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