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