1 /* $NetBSD: radeonfb_bios.c,v 1.4 2010/11/03 00:49:02 macallan Exp $ */
2
3 /*-
4 * Copyright (c) 2006 Itronix Inc.
5 * All rights reserved.
6 *
7 * Written by Garrett D'Amore for Itronix Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
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.
20 *
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.
32 */
33
34 /*
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.
39 */
40
41 #include <sys/cdefs.h>
42 __KERNEL_RCSID(0, "$NetBSD: radeonfb_bios.c,v 1.4 2010/11/03 00:49:02 macallan Exp $");
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/device.h>
47 #include <sys/malloc.h>
48 #include <sys/bus.h>
49
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>
55
56 #include "opt_radeonfb.h"
57
58 #ifdef RADEONFB_BIOS_INIT
59
60 /*
61 * Globals for the entire BIOS.
62 */
63 #define ROM_HEADER_OFFSET 0x48
64 #define MAX_REVISION 0x10
65 #define SINGLE_TABLE_REVISION 0x09
66 #define MIN_OFFSET 0x60
67
68 /*
69 * Offsets of specific tables.
70 */
71 #define RAGE_REGS1_OFFSET 0x0c
72 #define RAGE_REGS2_OFFSET 0x4e
73 #define DYN_CLOCK_OFFSET 0x52
74 #define PLL_INIT_OFFSET 0x46
75 #define MEM_CONFIG_OFFSET 0x48
76
77 /*
78 * Values related to generic intialization tables.
79 */
80 #define TABLE_ENTRY_FLAG_MASK 0xe000
81 #define TABLE_ENTRY_INDEX_MASK 0x1fff
82 #define TABLE_ENTRY_COMMAND_MASK 0x00ff
83
84 #define TABLE_FLAG_WRITE_INDEXED 0x0000
85 #define TABLE_FLAG_WRITE_DIRECT 0x2000
86 #define TABLE_FLAG_MASK_INDEXED 0x4000
87 #define TABLE_FLAG_MASK_DIRECT 0x6000
88 #define TABLE_FLAG_DELAY 0x8000
89 #define TABLE_FLAG_SCOMMAND 0xa000
90
91 #define TABLE_SCOMMAND_WAIT_MC_BUSY_MASK 0x03
92 #define TABLE_SCOMMAND_WAIT_MEM_PWRUP_COMPLETE 0x08
93
94 /*
95 * PLL initialization block values.
96 */
97 #define PLL_FLAG_MASK 0xc0
98 #define PLL_INDEX_MASK 0x3f
99
100 #define PLL_FLAG_WRITE 0x00
101 #define PLL_FLAG_MASK_BYTE 0x40
102 #define PLL_FLAG_WAIT 0x80
103
104 #define PLL_WAIT_150MKS 1
105 #define PLL_WAIT_5MS 2
106 #define PLL_WAIT_MC_BUSY_MASK 3
107 #define PLL_WAIT_DLL_READY_MASK 4
108 #define PLL_WAIT_CHK_SET_CLK_PWRMGT_CNTL24 5
109
110
111 #ifdef RADEONFB_BIOS_DEBUG
112 #define DPRINTF(x) printf x
113 #else
114 #define DPRINTF(x)
115 #endif
116
117 struct rb_table;
118
119 static void rb_validate(struct radeonfb_softc *, struct rb_table *);
120 static uint16_t rb_find_asic_table(struct radeonfb_softc *, struct rb_table *);
121 static uint16_t rb_find_mem_reset_table(struct radeonfb_softc *,
122 struct rb_table *);
123 static uint16_t rb_find_short_mem_reset_table(struct radeonfb_softc *,
124 struct rb_table *);
125 static int rb_load_init_block(struct radeonfb_softc *, struct rb_table *);
126 static int rb_load_pll_block(struct radeonfb_softc *, struct rb_table *);
127 static int rb_reset_sdram(struct radeonfb_softc *, struct rb_table *);
128
129 static void rb_wait_mc_busy_mask(struct radeonfb_softc *, uint16_t);
130 static void rb_wait_mem_pwrup_complete(struct radeonfb_softc *, uint16_t);
131 static void rb_wait_dll_ready_mask(struct radeonfb_softc *, uint16_t);
132 static void rb_wait_chk_set_clk_pwrmgt_cntl24(struct radeonfb_softc *);
133
134 /*
135 * Generic structure describing the tables.
136 */
137 struct rb_table {
138 const unsigned char *name;
139 uint16_t offset;
140 struct rb_table *parent;
141
142 /* validate that the table looks sane */
143 void (*validate)(struct radeonfb_softc *, struct rb_table *);
144
145 /* find looks for the table relative to its "parent" */
146 uint16_t (*find)(struct radeonfb_softc *, struct rb_table *);
147 };
148
149 /*
150 * Instances of specific tables.
151 */
152 static struct rb_table rb_rage_regs1_table = {
153 "rage_regs_1", /* name */
154 RAGE_REGS1_OFFSET, /* offset */
155 NULL, /* parent */
156 rb_validate, /* validate */
157 NULL, /* find */
158 };
159
160 static struct rb_table rb_rage_regs2_table = {
161 "rage_regs_2", /* name */
162 RAGE_REGS2_OFFSET, /* offset */
163 NULL, /* parent */
164 rb_validate, /* validate */
165 NULL, /* find */
166 };
167
168 static struct rb_table rb_dyn_clock_table = {
169 "dyn_clock", /* name */
170 DYN_CLOCK_OFFSET, /* offset */
171 NULL, /* parent */
172 rb_validate, /* validate */
173 NULL, /* find */
174 };
175
176 static struct rb_table rb_pll_init_table = {
177 "pll_init", /* name */
178 PLL_INIT_OFFSET, /* offset */
179 NULL, /* parent */
180 rb_validate, /* validate */
181 NULL, /* find */
182 };
183
184 static struct rb_table rb_mem_config_table = {
185 "mem_config", /* name */
186 MEM_CONFIG_OFFSET, /* offset */
187 NULL, /* parent */
188 rb_validate, /* validate */
189 NULL, /* find */
190 };
191
192 static struct rb_table rb_mem_reset_table = {
193 "mem_reset", /* name */
194 0, /* offset */
195 &rb_mem_config_table, /* parent */
196 NULL, /* validate */
197 rb_find_mem_reset_table, /* find */
198 };
199
200 static struct rb_table rb_short_mem_reset_table = {
201 "short_mem_reset", /* name */
202 0, /* offset */
203 &rb_mem_config_table, /* parent */
204 NULL, /* validate */
205 rb_find_short_mem_reset_table, /* find */
206 };
207
208 static struct rb_table rb_rage_regs3_table = {
209 "rage_regs_3", /* name */
210 0, /* offset */
211 &rb_rage_regs2_table, /* parent */
212 NULL, /* validate */
213 rb_find_asic_table, /* find */
214 };
215
216 static struct rb_table rb_rage_regs4_table = {
217 "rage_regs_4", /* name */
218 0, /* offset */
219 &rb_rage_regs3_table, /* parent */
220 NULL, /* validate */
221 rb_find_asic_table, /* find */
222 };
223
224 static struct rb_table *rb_tables[] = {
225 &rb_rage_regs1_table,
226 &rb_rage_regs2_table,
227 &rb_dyn_clock_table,
228 &rb_pll_init_table,
229 &rb_mem_config_table,
230 &rb_mem_reset_table,
231 &rb_short_mem_reset_table,
232 &rb_rage_regs3_table,
233 &rb_rage_regs4_table,
234 NULL
235 };
236
237 void
rb_validate(struct radeonfb_softc * sc,struct rb_table * tp)238 rb_validate(struct radeonfb_softc *sc, struct rb_table *tp)
239 {
240 uint8_t rev;
241
242 rev = GETBIOS8(sc, tp->offset - 1);
243
244 if (rev > MAX_REVISION) {
245 DPRINTF(("%s: bad rev %x of %s\n", XNAME(sc), rev, tp->name));
246 tp->offset = 0;
247 return;
248 }
249
250 if (tp->offset < MIN_OFFSET) {
251 DPRINTF(("%s: wrong pointer to %s!\n", XNAME(sc), tp->name));
252 tp->offset = 0;
253 return;
254 }
255 }
256
257 uint16_t
rb_find_asic_table(struct radeonfb_softc * sc,struct rb_table * tp)258 rb_find_asic_table(struct radeonfb_softc *sc, struct rb_table *tp)
259 {
260 uint16_t offset;
261 uint8_t c;
262
263 if ((offset = tp->offset) != 0) {
264 while ((c = GETBIOS8(sc, offset + 1)) != 0) {
265 if (c & 0x40)
266 offset += 10;
267 else if (c & 0x80)
268 offset += 4;
269 else
270 offset += 6;
271 }
272 return offset + 2;
273 }
274 return 0;
275 }
276
277 uint16_t
rb_find_mem_reset_table(struct radeonfb_softc * sc,struct rb_table * tp)278 rb_find_mem_reset_table(struct radeonfb_softc *sc, struct rb_table *tp)
279 {
280 uint16_t offset;
281
282 if ((offset = tp->offset) != 0) {
283 while (GETBIOS8(sc, offset))
284 offset++;
285 offset++;
286 return offset + 2; /* skip table revision and mask */
287 }
288 return 0;
289 }
290
291 uint16_t
rb_find_short_mem_reset_table(struct radeonfb_softc * sc,struct rb_table * tp)292 rb_find_short_mem_reset_table(struct radeonfb_softc *sc, struct rb_table *tp)
293 {
294
295 if ((tp->offset != 0) && (GETBIOS8(sc, tp->offset - 2) <= 64))
296 return (tp->offset + GETBIOS8(sc, tp->offset - 3));
297
298 return 0;
299 }
300
301 /* helper commands */
302 void
rb_wait_mc_busy_mask(struct radeonfb_softc * sc,uint16_t count)303 rb_wait_mc_busy_mask(struct radeonfb_softc *sc, uint16_t count)
304 {
305 DPRINTF(("WAIT_MC_BUSY_MASK: %d ", count));
306 while (count--) {
307 if (!(radeonfb_getpll(sc, RADEON_CLK_PWRMGT_CNTL) &
308 RADEON_MC_BUSY_MASK))
309 break;
310 }
311 DPRINTF(("%d\n", count));
312 }
313
314 void
rb_wait_mem_pwrup_complete(struct radeonfb_softc * sc,uint16_t count)315 rb_wait_mem_pwrup_complete(struct radeonfb_softc *sc, uint16_t count)
316 {
317 DPRINTF(("WAIT_MEM_PWRUP_COMPLETE: %d ", count));
318 while (count--) {
319 if ((radeonfb_getindex(sc, RADEON_MEM_STR_CNTL) &
320 RADEON_MEM_PWRUP_COMPLETE) ==
321 RADEON_MEM_PWRUP_COMPLETE)
322 break;
323 }
324 DPRINTF(("%d\n", count));
325 }
326
327 void
rb_wait_dll_ready_mask(struct radeonfb_softc * sc,uint16_t count)328 rb_wait_dll_ready_mask(struct radeonfb_softc *sc, uint16_t count)
329 {
330 DPRINTF(("WAIT_DLL_READY_MASK: %d ", count));
331 while (count--) {
332 if (radeonfb_getpll(sc, RADEON_CLK_PWRMGT_CNTL) &
333 RADEON_DLL_READY_MASK)
334 break;
335 }
336 DPRINTF(("%d\n", count));
337 }
338
339 void
rb_wait_chk_set_clk_pwrmgt_cntl24(struct radeonfb_softc * sc)340 rb_wait_chk_set_clk_pwrmgt_cntl24(struct radeonfb_softc *sc)
341 {
342 uint32_t pmc;
343 DPRINTF(("WAIT CHK_SET_CLK_PWRMGT_CNTL24\n"));
344 pmc = radeonfb_getpll(sc, RADEON_CLK_PWRMGT_CNTL);
345
346 if (pmc & RADEON_CLK_PWRMGT_CNTL24) {
347 radeonfb_maskpll(sc, RADEON_MCLK_CNTL, 0xFFFF0000,
348 RADEON_SET_ALL_SRCS_TO_PCI);
349 delay(10000);
350 radeonfb_putpll(sc, RADEON_CLK_PWRMGT_CNTL,
351 pmc & ~RADEON_CLK_PWRMGT_CNTL24);
352 delay(10000);
353 }
354 }
355
356 /*
357 * Block initialization routines. These take action based on data in
358 * the tables.
359 */
360 int
rb_load_init_block(struct radeonfb_softc * sc,struct rb_table * tp)361 rb_load_init_block(struct radeonfb_softc *sc, struct rb_table *tp)
362 {
363 uint16_t offset;
364 uint16_t value;
365
366 if ((tp == NULL) || ((offset = tp->offset) == 0))
367 return 1;
368
369 DPRINTF(("%s: load_init_block processing %s\n", XNAME(sc), tp->name));
370 while ((value = GETBIOS16(sc, offset)) != 0) {
371 uint16_t flag = value & TABLE_ENTRY_FLAG_MASK;
372 uint16_t index = value & TABLE_ENTRY_INDEX_MASK;
373 uint8_t command = value & TABLE_ENTRY_COMMAND_MASK;
374 uint32_t ormask;
375 uint32_t andmask;
376 uint16_t count;
377
378 offset += 2;
379
380 switch (flag) {
381 case TABLE_FLAG_WRITE_INDEXED:
382 DPRINTF(("WRITE INDEXED: %x %x\n",
383 index, (uint32_t)GETBIOS32(sc, offset)));
384 radeonfb_putindex(sc, index, GETBIOS32(sc, offset));
385 offset += 4;
386 break;
387
388 case TABLE_FLAG_WRITE_DIRECT:
389 DPRINTF(("WRITE DIRECT: %x %x\n",
390 index, (uint32_t)GETBIOS32(sc, offset)));
391 radeonfb_put32(sc, index, GETBIOS32(sc, offset));
392 offset += 4;
393 break;
394
395 case TABLE_FLAG_MASK_INDEXED:
396 andmask = GETBIOS32(sc, offset);
397 offset += 4;
398 ormask = GETBIOS32(sc, offset);
399 offset += 4;
400 DPRINTF(("MASK INDEXED: %x %x %x\n",
401 index, andmask, ormask));
402 radeonfb_maskindex(sc, index, andmask, ormask);
403 break;
404
405 case TABLE_FLAG_MASK_DIRECT:
406 andmask = GETBIOS32(sc, offset);
407 offset += 4;
408 ormask = GETBIOS32(sc, offset);
409 offset += 4;
410 DPRINTF(("MASK DIRECT: %x %x %x\n",
411 index, andmask, ormask));
412 radeonfb_mask32(sc, index, andmask, ormask);
413 break;
414
415 case TABLE_FLAG_DELAY:
416 /* in the worst case, this would be 16msec */
417 count = GETBIOS16(sc, offset);
418 DPRINTF(("DELAY: %d\n", count));
419 delay(count);
420 offset += 2;
421 break;
422
423 case TABLE_FLAG_SCOMMAND:
424 DPRINTF(("SCOMMAND %x\n", command));
425 switch (command) {
426
427 case TABLE_SCOMMAND_WAIT_MC_BUSY_MASK:
428 count = GETBIOS16(sc, offset);
429 rb_wait_mc_busy_mask(sc, count);
430 break;
431
432 case TABLE_SCOMMAND_WAIT_MEM_PWRUP_COMPLETE:
433 count = GETBIOS16(sc, offset);
434 rb_wait_mem_pwrup_complete(sc, count);
435 break;
436
437 }
438 offset += 2;
439 break;
440 }
441 }
442 return 0;
443 }
444
445 int
rb_load_pll_block(struct radeonfb_softc * sc,struct rb_table * tp)446 rb_load_pll_block(struct radeonfb_softc *sc, struct rb_table *tp)
447 {
448 uint16_t offset;
449 uint8_t index;
450 uint8_t shift;
451 uint32_t andmask;
452 uint32_t ormask;
453
454 if ((tp == NULL) || ((offset = tp->offset) == 0))
455 return 1;
456
457 DPRINTF(("%s: load_pll_block processing %s\n", XNAME(sc), tp->name));
458 while ((index = GETBIOS8(sc, offset)) != 0) {
459 offset++;
460
461 switch (index & PLL_FLAG_MASK) {
462 case PLL_FLAG_WAIT:
463 switch (index & PLL_INDEX_MASK) {
464 case PLL_WAIT_150MKS:
465 delay(150);
466 break;
467 case PLL_WAIT_5MS:
468 /* perhaps this should be tsleep? */
469 delay(5000);
470 break;
471
472 case PLL_WAIT_MC_BUSY_MASK:
473 rb_wait_mc_busy_mask(sc, 1000);
474 break;
475
476 case PLL_WAIT_DLL_READY_MASK:
477 rb_wait_dll_ready_mask(sc, 1000);
478 break;
479
480 case PLL_WAIT_CHK_SET_CLK_PWRMGT_CNTL24:
481 rb_wait_chk_set_clk_pwrmgt_cntl24(sc);
482 break;
483 }
484 break;
485
486 case PLL_FLAG_MASK_BYTE:
487 shift = GETBIOS8(sc, offset) * 8;
488 offset++;
489
490 andmask =
491 (((uint32_t)GETBIOS8(sc, offset)) << shift) |
492 ~((uint32_t)0xff << shift);
493 offset++;
494
495 ormask = ((uint32_t)GETBIOS8(sc, offset)) << shift;
496 offset++;
497
498 DPRINTF(("PLL_MASK_BYTE %u %u %x %x\n", index,
499 shift, andmask, ormask));
500 radeonfb_maskpll(sc, index, andmask, ormask);
501 break;
502
503 case PLL_FLAG_WRITE:
504 DPRINTF(("PLL_WRITE %u %x\n", index,
505 GETBIOS32(sc, offset)));
506 radeonfb_putpll(sc, index, GETBIOS32(sc, offset));
507 offset += 4;
508 break;
509 }
510 }
511
512 return 0;
513 }
514
515 int
rb_reset_sdram(struct radeonfb_softc * sc,struct rb_table * tp)516 rb_reset_sdram(struct radeonfb_softc *sc, struct rb_table *tp)
517 {
518 uint16_t offset;
519 uint8_t index;
520
521 if ((tp == NULL) || ((offset = tp->offset) == 0))
522 return 1;
523
524 DPRINTF(("%s: reset_sdram processing %s\n", XNAME(sc), tp->name));
525
526 while ((index = GETBIOS8(sc, offset)) != 0xff) {
527 offset++;
528 if (index == 0x0f) {
529 rb_wait_mem_pwrup_complete(sc, 20000);
530 } else {
531 uint32_t ormask;
532
533 ormask = GETBIOS16(sc, offset);
534 offset += 2;
535
536 DPRINTF(("INDEX reg RADEON_MEM_SDRAM_MODE_REG %x %x\n",
537 RADEON_SDRAM_MODE_MASK, ormask));
538 radeonfb_maskindex(sc, RADEON_MEM_SDRAM_MODE_REG,
539 RADEON_SDRAM_MODE_MASK, ormask);
540
541 ormask = (uint32_t)index << 24;
542 DPRINTF(("INDEX reg RADEON_MEM_SDRAM_MODE_REG %x %x\n",
543 RADEON_B3MEM_RESET_MASK, ormask));
544 radeonfb_maskindex(sc, RADEON_MEM_SDRAM_MODE_REG,
545 RADEON_B3MEM_RESET_MASK, ormask);
546 }
547 }
548 return 0;
549 }
550
551 /*
552 * Master entry point to parse and act on table data.
553 */
554 int
radeonfb_bios_init(struct radeonfb_softc * sc)555 radeonfb_bios_init(struct radeonfb_softc *sc)
556 {
557 uint16_t revision;
558 uint16_t scratch;
559 int i;
560 struct rb_table *tp;
561
562 if (!sc->sc_biossz)
563 return 1;
564
565 scratch = GETBIOS16(sc, ROM_HEADER_OFFSET);
566 revision = GETBIOS8(sc, scratch);
567 DPRINTF(("%s: Bios Rev: %d\n", XNAME(sc), revision));
568
569
570 /* First parse pass -- locate tables */
571 for (i = 0; (tp = rb_tables[i]) != NULL; i++) {
572
573 DPRINTF(("%s: parsing table %s\n", XNAME(sc), tp->name));
574
575 if (tp->offset != 0) {
576 uint16_t temp, offset;
577
578 temp = GETBIOS16(sc, ROM_HEADER_OFFSET);
579 offset = GETBIOS16(sc, temp + tp->offset);
580 if (offset)
581 tp->offset = offset;
582
583 } else {
584 tp->offset = tp->find(sc, tp->parent);
585 }
586
587 if (tp->validate)
588 tp->validate(sc, tp);
589
590 if (revision > SINGLE_TABLE_REVISION)
591 break;
592 }
593
594 if (rb_rage_regs3_table.offset + 1 == rb_pll_init_table.offset) {
595 rb_rage_regs3_table.offset = 0;
596 rb_rage_regs4_table.offset = 0;
597 }
598
599 if (rb_rage_regs1_table.offset)
600 rb_load_init_block(sc, &rb_rage_regs1_table);
601
602 if (revision < SINGLE_TABLE_REVISION) {
603 if (rb_pll_init_table.offset)
604 rb_load_pll_block(sc, &rb_pll_init_table);
605 if (rb_rage_regs2_table.offset)
606 rb_load_init_block(sc, &rb_rage_regs2_table);
607 if (rb_rage_regs4_table.offset)
608 rb_load_init_block(sc, &rb_rage_regs4_table);
609 if (rb_mem_reset_table.offset)
610 rb_reset_sdram(sc, &rb_mem_reset_table);
611 if (rb_rage_regs3_table.offset)
612 rb_load_init_block(sc, &rb_rage_regs3_table);
613 if (rb_dyn_clock_table.offset)
614 rb_load_pll_block(sc, &rb_dyn_clock_table);
615 }
616
617 DPRINTF(("%s: BIOS parse done\n", XNAME(sc)));
618 return 0;
619 }
620
621 #endif
622