1 /* $NetBSD: radeonfb_bios.c,v 1.2 2007/10/19 12:00:55 ad Exp $ */
4 * Copyright (c) 2006 Itronix Inc.
7 * Written by Garrett D'Amore for Itronix Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The name of Itronix Inc. may not be used to endorse
18 * or promote products derived from this software without specific
19 * prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28 * ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
35 * ATI Technologies Inc. ("ATI") has not assisted in the creation of, and
36 * does not endorse, this software. ATI will not be responsible or liable
37 * for any actual or alleged damage or loss caused by or in connection with
38 * the use of or reliance on this software.
41 #include <sys/cdefs.h>
42 __KERNEL_RCSID(0, "$NetBSD: radeonfb_bios.c,v 1.2 2007/10/19 12:00:55 ad Exp $");
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/device.h>
47 #include <sys/malloc.h>
50 #include <dev/pci/pcidevs.h>
51 #include <dev/pci/pcireg.h>
52 #include <dev/pci/pcivar.h>
53 #include <dev/pci/radeonfbreg.h>
54 #include <dev/pci/radeonfbvar.h>
56 #ifdef RADEON_BIOS_INIT
59 * Globals for the entire BIOS.
61 #define ROM_HEADER_OFFSET 0x48
62 #define MAX_REVISION 0x10
63 #define SINGLE_TABLE_REVISION 0x09
64 #define MIN_OFFSET 0x60
67 * Offsets of specific tables.
69 #define RAGE_REGS1_OFFSET 0x0c
70 #define RAGE_REGS2_OFFSET 0x4e
71 #define DYN_CLOCK_OFFSET 0x52
72 #define PLL_INIT_OFFSET 0x46
73 #define MEM_CONFIG_OFFSET 0x48
76 * Values related to generic intialization tables.
78 #define TABLE_ENTRY_FLAG_MASK 0xe000
79 #define TABLE_ENTRY_INDEX_MASK 0x1fff
80 #define TABLE_ENTRY_COMMAND_MASK 0x00ff
82 #define TABLE_FLAG_WRITE_INDEXED 0x0000
83 #define TABLE_FLAG_WRITE_DIRECT 0x2000
84 #define TABLE_FLAG_MASK_INDEXED 0x4000
85 #define TABLE_FLAG_MASK_DIRECT 0x6000
86 #define TABLE_FLAG_DELAY 0x8000
87 #define TABLE_FLAG_SCOMMAND 0xa000
89 #define TABLE_SCOMMAND_WAIT_MC_BUSY_MASK 0x03
90 #define TABLE_SCOMMAND_WAIT_MEM_PWRUP_COMPLETE 0x08
93 * PLL initialization block values.
95 #define PLL_FLAG_MASK 0xc0
96 #define PLL_INDEX_MASK 0x3f
98 #define PLL_FLAG_WRITE 0x00
99 #define PLL_FLAG_MASK_BYTE 0x40
100 #define PLL_FLAG_WAIT 0x80
102 #define PLL_WAIT_150MKS 1
103 #define PLL_WAIT_5MS 2
104 #define PLL_WAIT_MC_BUSY_MASK 3
105 #define PLL_WAIT_DLL_READY_MASK 4
106 #define PLL_WAIT_CHK_SET_CLK_PWRMGT_CNTL24 5
109 #ifdef RADEON_BIOS_DEBUG
110 #define DPRINTF(x) printf x
117 static void rb_validate(struct radeonfb_softc
*, struct rb_table
*);
118 static uint16_t rb_find_asic_table(struct radeonfb_softc
*, struct rb_table
*);
119 static uint16_t rb_find_mem_reset_table(struct radeonfb_softc
*,
121 static uint16_t rb_find_short_mem_reset_table(struct radeonfb_softc
*,
123 static int rb_load_init_block(struct radeonfb_softc
*, struct rb_table
*);
124 static int rb_load_pll_block(struct radeonfb_softc
*, struct rb_table
*);
125 static int rb_reset_sdram(struct radeonfb_softc
*, struct rb_table
*);
127 static void rb_wait_mc_busy_mask(struct radeonfb_softc
*, uint16_t);
128 static void rb_wait_mem_pwrup_complete(struct radeonfb_softc
*, uint16_t);
129 static void rb_wait_dll_ready_mask(struct radeonfb_softc
*, uint16_t);
130 static void rb_wait_chk_set_clk_pwrmgt_cntl24(struct radeonfb_softc
*);
133 * Generic structure describing the tables.
136 const unsigned char *name
;
138 struct rb_table
*parent
;
140 /* validate that the table looks sane */
141 void (*validate
)(struct radeonfb_softc
*, struct rb_table
*);
143 /* find looks for the table relative to its "parent" */
144 uint16_t (*find
)(struct radeonfb_softc
*, struct rb_table
*);
148 * Instances of specific tables.
150 static struct rb_table rb_rage_regs1_table
= {
151 "rage_regs_1", /* name */
152 RAGE_REGS1_OFFSET
, /* offset */
154 rb_validate
, /* validate */
158 static struct rb_table rb_rage_regs2_table
= {
159 "rage_regs_2", /* name */
160 RAGE_REGS2_OFFSET
, /* offset */
162 rb_validate
, /* validate */
166 static struct rb_table rb_dyn_clock_table
= {
167 "dyn_clock", /* name */
168 DYN_CLOCK_OFFSET
, /* offset */
170 rb_validate
, /* validate */
174 static struct rb_table rb_pll_init_table
= {
175 "pll_init", /* name */
176 PLL_INIT_OFFSET
, /* offset */
178 rb_validate
, /* validate */
182 static struct rb_table rb_mem_config_table
= {
183 "mem_config", /* name */
184 MEM_CONFIG_OFFSET
, /* offset */
186 rb_validate
, /* validate */
190 static struct rb_table rb_mem_reset_table
= {
191 "mem_reset", /* name */
193 &rb_mem_config_table
, /* parent */
195 rb_find_mem_reset_table
, /* find */
198 static struct rb_table rb_short_mem_reset_table
= {
199 "short_mem_reset", /* name */
201 &rb_mem_config_table
, /* parent */
203 rb_find_short_mem_reset_table
, /* find */
206 static struct rb_table rb_rage_regs3_table
= {
207 "rage_regs_3", /* name */
209 &rb_rage_regs2_table
, /* parent */
211 rb_find_asic_table
, /* find */
214 static struct rb_table rb_rage_regs4_table
= {
215 "rage_regs_4", /* name */
217 &rb_rage_regs3_table
, /* parent */
219 rb_find_asic_table
, /* find */
222 static struct rb_table
*rb_tables
[] = {
223 &rb_rage_regs1_table
,
224 &rb_rage_regs2_table
,
227 &rb_mem_config_table
,
229 &rb_short_mem_reset_table
,
230 &rb_rage_regs3_table
,
231 &rb_rage_regs4_table
,
236 rb_validate(struct radeonfb_softc
*sc
, struct rb_table
*tp
)
240 rev
= GETBIOS8(sc
, tp
->offset
- 1);
242 if (rev
> MAX_REVISION
) {
243 DPRINTF(("%s: bad rev %x of %s\n", XNAME(sc
), rev
, tp
->name
));
248 if (tp
->offset
< MIN_OFFSET
) {
249 DPRINTF(("%s: wrong pointer to %s!\n", XNAME(sc
), tp
->name
));
256 rb_find_asic_table(struct radeonfb_softc
*sc
, struct rb_table
*tp
)
261 if ((offset
= tp
->offset
) != 0) {
262 while ((c
= GETBIOS8(sc
, offset
+ 1)) != 0) {
276 rb_find_mem_reset_table(struct radeonfb_softc
*sc
, struct rb_table
*tp
)
280 if ((offset
= tp
->offset
) != 0) {
281 while (GETBIOS8(sc
, offset
))
284 return offset
+ 2; /* skip table revision and mask */
290 rb_find_short_mem_reset_table(struct radeonfb_softc
*sc
, struct rb_table
*tp
)
293 if ((tp
->offset
!= 0) && (GETBIOS8(sc
, tp
->offset
- 2) <= 64))
294 return (tp
->offset
+ GETBIOS8(sc
, tp
->offset
- 3));
299 /* helper commands */
301 rb_wait_mc_busy_mask(struct radeonfb_softc
*sc
, uint16_t count
)
303 DPRINTF(("WAIT_MC_BUSY_MASK: %d ", count
));
305 if (!(radeonfb_getpll(sc
, RADEON_CLK_PWRMGT_CNTL
) &
306 RADEON_MC_BUSY_MASK
))
309 DPRINTF(("%d\n", count
));
313 rb_wait_mem_pwrup_complete(struct radeonfb_softc
*sc
, uint16_t count
)
315 DPRINTF(("WAIT_MEM_PWRUP_COMPLETE: %d ", count
));
317 if ((radeonfb_getindex(sc
, RADEON_MEM_STR_CNTL
) &
318 RADEON_MEM_PWRUP_COMPLETE
) ==
319 RADEON_MEM_PWRUP_COMPLETE
)
322 DPRINTF(("%d\n", count
));
326 rb_wait_dll_ready_mask(struct radeonfb_softc
*sc
, uint16_t count
)
328 DPRINTF(("WAIT_DLL_READY_MASK: %d ", count
));
330 if (radeonfb_getpll(sc
, RADEON_CLK_PWRMGT_CNTL
) &
331 RADEON_DLL_READY_MASK
)
334 DPRINTF(("%d\n", count
));
338 rb_wait_chk_set_clk_pwrmgt_cntl24(struct radeonfb_softc
*sc
)
341 DPRINTF(("WAIT CHK_SET_CLK_PWRMGT_CNTL24\n"));
342 pmc
= radeonfb_getpll(sc
, RADEON_CLK_PWRMGT_CNTL
);
344 if (pmc
& RADEON_CLK_PWRMGT_CNTL24
) {
345 radeonfb_maskpll(sc
, RADEON_MCLK_CNTL
, 0xFFFF0000,
346 RADEON_SET_ALL_SRCS_TO_PCI
);
348 radeonfb_putpll(sc
, RADEON_CLK_PWRMGT_CNTL
,
349 pmc
& ~RADEON_CLK_PWRMGT_CNTL24
);
355 * Block initialization routines. These take action based on data in
359 rb_load_init_block(struct radeonfb_softc
*sc
, struct rb_table
*tp
)
364 if ((tp
== NULL
) || ((offset
= tp
->offset
) == 0))
367 DPRINTF(("%s: load_init_block processing %s\n", XNAME(sc
), tp
->name
));
368 while ((value
= GETBIOS16(sc
, offset
)) != 0) {
369 uint16_t flag
= value
& TABLE_ENTRY_FLAG_MASK
;
370 uint16_t index
= value
& TABLE_ENTRY_INDEX_MASK
;
371 uint8_t command
= value
& TABLE_ENTRY_COMMAND_MASK
;
379 case TABLE_FLAG_WRITE_INDEXED
:
380 DPRINTF(("WRITE INDEXED: %x %x\n",
381 index
, (uint32_t)GETBIOS32(sc
, offset
)));
382 radeonfb_putindex(sc
, index
, GETBIOS32(sc
, offset
));
386 case TABLE_FLAG_WRITE_DIRECT
:
387 DPRINTF(("WRITE DIRECT: %x %x\n",
388 index
, (uint32_t)GETBIOS32(sc
, offset
)));
389 radeonfb_put32(sc
, index
, GETBIOS32(sc
, offset
));
393 case TABLE_FLAG_MASK_INDEXED
:
394 andmask
= GETBIOS32(sc
, offset
);
396 ormask
= GETBIOS32(sc
, offset
);
398 DPRINTF(("MASK INDEXED: %x %x %x\n",
399 index
, andmask
, ormask
));
400 radeonfb_maskindex(sc
, index
, andmask
, ormask
);
403 case TABLE_FLAG_MASK_DIRECT
:
404 andmask
= GETBIOS32(sc
, offset
);
406 ormask
= GETBIOS32(sc
, offset
);
408 DPRINTF(("MASK DIRECT: %x %x %x\n",
409 index
, andmask
, ormask
));
410 radeonfb_mask32(sc
, index
, andmask
, ormask
);
413 case TABLE_FLAG_DELAY
:
414 /* in the worst case, this would be 16msec */
415 count
= GETBIOS16(sc
, offset
);
416 DPRINTF(("DELAY: %d\n", count
));
421 case TABLE_FLAG_SCOMMAND
:
422 DPRINTF(("SCOMMAND %x\n", command
));
425 case TABLE_SCOMMAND_WAIT_MC_BUSY_MASK
:
426 count
= GETBIOS16(sc
, offset
);
427 rb_wait_mc_busy_mask(sc
, count
);
430 case TABLE_SCOMMAND_WAIT_MEM_PWRUP_COMPLETE
:
431 count
= GETBIOS16(sc
, offset
);
432 rb_wait_mem_pwrup_complete(sc
, count
);
444 rb_load_pll_block(struct radeonfb_softc
*sc
, struct rb_table
*tp
)
452 if ((tp
== NULL
) || ((offset
= tp
->offset
) == 0))
455 DPRINTF(("%s: load_pll_block processing %s\n", XNAME(sc
), tp
->name
));
456 while ((index
= GETBIOS8(sc
, offset
)) != 0) {
459 switch (index
& PLL_FLAG_MASK
) {
461 switch (index
& PLL_INDEX_MASK
) {
462 case PLL_WAIT_150MKS
:
466 /* perhaps this should be tsleep? */
470 case PLL_WAIT_MC_BUSY_MASK
:
471 rb_wait_mc_busy_mask(sc
, 1000);
474 case PLL_WAIT_DLL_READY_MASK
:
475 rb_wait_dll_ready_mask(sc
, 1000);
478 case PLL_WAIT_CHK_SET_CLK_PWRMGT_CNTL24
:
479 rb_wait_chk_set_clk_pwrmgt_cntl24(sc
);
484 case PLL_FLAG_MASK_BYTE
:
485 shift
= GETBIOS8(sc
, offset
) * 8;
489 (((uint32_t)GETBIOS8(sc
, offset
)) << shift
) |
490 ~((uint32_t)0xff << shift
);
493 ormask
= ((uint32_t)GETBIOS8(sc
, offset
)) << shift
;
496 DPRINTF(("PLL_MASK_BYTE %u %u %x %x\n", index
,
497 shift
, andmask
, ormask
));
498 radeonfb_maskpll(sc
, index
, andmask
, ormask
);
502 DPRINTF(("PLL_WRITE %u %x\n", index
,
503 GETBIOS32(sc
, offset
)));
504 radeonfb_putpll(sc
, index
, GETBIOS32(sc
, offset
));
514 rb_reset_sdram(struct radeonfb_softc
*sc
, struct rb_table
*tp
)
519 if ((tp
== NULL
) || ((offset
= tp
->offset
) == 0))
522 DPRINTF(("%s: reset_sdram processing %s\n", XNAME(sc
), tp
->name
));
524 while ((index
= GETBIOS8(sc
, offset
)) != 0xff) {
527 rb_wait_mem_pwrup_complete(sc
, 20000);
531 ormask
= GETBIOS16(sc
, offset
);
534 DPRINTF(("INDEX reg RADEON_MEM_SDRAM_MODE_REG %x %x\n",
535 RADEON_SDRAM_MODE_MASK
, ormask
));
536 radeonfb_maskindex(sc
, RADEON_MEM_SDRAM_MODE_REG
,
537 RADEON_SDRAM_MODE_MASK
, ormask
);
539 ormask
= (uint32_t)index
<< 24;
540 DPRINTF(("INDEX reg RADEON_MEM_SDRAM_MODE_REG %x %x\n",
541 RADEON_B3MEM_RESET_MASK
, ormask
));
542 radeonfb_maskindex(sc
, RADEON_MEM_SDRAM_MODE_REG
,
543 RADEON_B3MEM_RESET_MASK
, ormask
);
550 * Master entry point to parse and act on table data.
553 radeonfb_bios_init(struct radeonfb_softc
*sc
)
563 scratch
= GETBIOS16(sc
, ROM_HEADER_OFFSET
);
564 revision
= GETBIOS8(sc
, scratch
);
565 DPRINTF(("%s: Bios Rev: %d\n", XNAME(sc
), revision
));
568 /* First parse pass -- locate tables */
569 for (i
= 0; (tp
= rb_tables
[i
]) != NULL
; i
++) {
571 DPRINTF(("%s: parsing table %s\n", XNAME(sc
), tp
->name
));
573 if (tp
->offset
!= 0) {
574 uint16_t temp
, offset
;
576 temp
= GETBIOS16(sc
, ROM_HEADER_OFFSET
);
577 offset
= GETBIOS16(sc
, temp
+ tp
->offset
);
582 tp
->offset
= tp
->find(sc
, tp
->parent
);
586 tp
->validate(sc
, tp
);
588 if (revision
> SINGLE_TABLE_REVISION
)
592 if (rb_rage_regs3_table
.offset
+ 1 == rb_pll_init_table
.offset
) {
593 rb_rage_regs3_table
.offset
= 0;
594 rb_rage_regs4_table
.offset
= 0;
597 if (rb_rage_regs1_table
.offset
)
598 rb_load_init_block(sc
, &rb_rage_regs1_table
);
600 if (revision
< SINGLE_TABLE_REVISION
) {
601 if (rb_pll_init_table
.offset
)
602 rb_load_pll_block(sc
, &rb_pll_init_table
);
603 if (rb_rage_regs2_table
.offset
)
604 rb_load_init_block(sc
, &rb_rage_regs2_table
);
605 if (rb_rage_regs4_table
.offset
)
606 rb_load_init_block(sc
, &rb_rage_regs4_table
);
607 if (rb_mem_reset_table
.offset
)
608 rb_reset_sdram(sc
, &rb_mem_reset_table
);
609 if (rb_rage_regs3_table
.offset
)
610 rb_load_init_block(sc
, &rb_rage_regs3_table
);
611 if (rb_dyn_clock_table
.offset
)
612 rb_load_pll_block(sc
, &rb_dyn_clock_table
);
615 DPRINTF(("%s: BIOS parse done\n", XNAME(sc
)));