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 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 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 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 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 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 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 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 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 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 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 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 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