1 /* 2 * Copyright 2008 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Author: Stanislaw Skowronek 23 */ 24 25 /* Rewritten for the Haiku Operating System Radeon HD driver 26 * Author: 27 * Alexander von Gluck, kallisti5@unixzen.com 28 */ 29 30 31 #include <Debug.h> 32 33 #include "atom.h" 34 #include "atom-names.h" 35 #include "atom-bits.h" 36 37 38 /* AtomBIOS loop detection 39 * Number of seconds of identical jmp operations 40 * before detecting a fault. 41 */ 42 #define ATOM_OP_JMP_TIMEOUT 5 43 44 // *** Tracing 45 #undef TRACE 46 //#define TRACE_ATOM 47 #ifdef TRACE_ATOM 48 # define TRACE(x...) _sPrintf("radeon_hd: " x) 49 #else 50 # define TRACE(x...) ; 51 #endif 52 53 #define ERROR(x...) _sPrintf("radeon_hd: " x) 54 55 #define ATOM_COND_ABOVE 0 56 #define ATOM_COND_ABOVEOREQUAL 1 57 #define ATOM_COND_ALWAYS 2 58 #define ATOM_COND_BELOW 3 59 #define ATOM_COND_BELOWOREQUAL 4 60 #define ATOM_COND_EQUAL 5 61 #define ATOM_COND_NOTEQUAL 6 62 63 #define ATOM_PORT_ATI 0 64 #define ATOM_PORT_PCI 1 65 #define ATOM_PORT_SYSIO 2 66 67 #define ATOM_UNIT_MICROSEC 0 68 #define ATOM_UNIT_MILLISEC 1 69 70 #define PLL_INDEX 2 71 #define PLL_DATA 3 72 73 74 typedef struct { 75 atom_context *ctx; 76 77 uint32 *ps, *ws; 78 int ps_shift; 79 uint16 start; 80 uint16 lastJump; 81 uint32 lastJumpCount; 82 bigtime_t jumpStart; 83 bool abort; 84 } atom_exec_context; 85 86 int atom_debug = 0; 87 status_t atom_execute_table_locked(atom_context *ctx, 88 int index, uint32 *params); 89 status_t atom_execute_table(atom_context *ctx, int index, uint32 *params); 90 91 static uint32 atom_arg_mask[8] = {0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 92 0xFF, 0xFF00, 0xFF0000, 0xFF000000}; 93 static int atom_arg_shift[8] = {0, 0, 8, 16, 0, 8, 16, 24}; 94 static int atom_dst_to_src[8][4] = { 95 // translate destination alignment field to the source alignment encoding 96 { 0, 0, 0, 0 }, 97 { 1, 2, 3, 0 }, 98 { 1, 2, 3, 0 }, 99 { 1, 2, 3, 0 }, 100 { 4, 5, 6, 7 }, 101 { 4, 5, 6, 7 }, 102 { 4, 5, 6, 7 }, 103 { 4, 5, 6, 7 }, 104 }; 105 static int atom_def_dst[8] = { 0, 0, 1, 2, 0, 1, 2, 3 }; 106 107 static int debug_depth = 0; 108 109 static uint32 110 atom_iio_execute(atom_context *ctx, int base, uint32 index, uint32 data) 111 { 112 uint32 temp = 0xCDCDCDCD; 113 while (1) 114 switch(CU8(base)) { 115 case ATOM_IIO_NOP: 116 base++; 117 break; 118 case ATOM_IIO_READ: 119 temp = ctx->card->ioreg_read(CU16(base + 1)); 120 base += 3; 121 break; 122 case ATOM_IIO_WRITE: 123 (void)ctx->card->reg_read(CU16(base + 1)); 124 ctx->card->ioreg_write(CU16(base + 1), temp); 125 base += 3; 126 break; 127 case ATOM_IIO_CLEAR: 128 temp &= ~((0xFFFFFFFF >> (32 - CU8(base + 1))) << CU8(base + 2)); 129 base += 3; 130 break; 131 case ATOM_IIO_SET: 132 temp |= (0xFFFFFFFF >> (32 - CU8(base + 1))) << CU8(base + 2); 133 base += 3; 134 break; 135 case ATOM_IIO_MOVE_INDEX: 136 temp &= ~((0xFFFFFFFF >> (32 - CU8(base + 1))) << CU8(base + 3)); 137 temp |= ((index >> CU8(base + 2)) 138 & (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base + 3); 139 base += 4; 140 break; 141 case ATOM_IIO_MOVE_DATA: 142 temp &= ~((0xFFFFFFFF >> (32 - CU8(base + 1))) << CU8(base + 3)); 143 temp |= ((data >> CU8(base + 2)) 144 & (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base + 3); 145 base += 4; 146 break; 147 case ATOM_IIO_MOVE_ATTR: 148 temp &= ~((0xFFFFFFFF >> (32 - CU8(base + 1))) << CU8(base + 3)); 149 temp |= ((ctx->io_attr >> CU8(base + 2)) 150 & (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base + 3); 151 base += 4; 152 break; 153 case ATOM_IIO_END: 154 return temp; 155 default: 156 TRACE("%s: Unknown IIO opcode.\n", __func__); 157 return 0; 158 } 159 } 160 161 162 static uint32 163 atom_get_src_int(atom_exec_context *ctx, uint8 attr, int *ptr, 164 uint32 *saved, int print) 165 { 166 uint32 idx, val = 0xCDCDCDCD, align, arg; 167 atom_context *gctx = ctx->ctx; 168 arg = attr & 7; 169 align = (attr >> 3) & 7; 170 switch(arg) { 171 case ATOM_ARG_REG: 172 idx = U16(*ptr); 173 (*ptr)+=2; 174 idx += gctx->reg_block; 175 switch(gctx->io_mode) { 176 case ATOM_IO_MM: 177 val = gctx->card->reg_read(idx); 178 break; 179 case ATOM_IO_PCI: 180 TRACE("%s: PCI registers are not implemented.\n", __func__); 181 return 0; 182 case ATOM_IO_SYSIO: 183 TRACE("%s: SYSIO registers are not implemented.\n", 184 __func__); 185 return 0; 186 default: 187 if (!(gctx->io_mode & 0x80)) { 188 TRACE("%s: Bad IO mode.\n", __func__); 189 return 0; 190 } 191 if (!gctx->iio[gctx->io_mode & 0x7F]) { 192 TRACE("%s: Undefined indirect IO read method %d.\n", 193 __func__, gctx->io_mode & 0x7F); 194 return 0; 195 } 196 val = atom_iio_execute(gctx, 197 gctx->iio[gctx->io_mode & 0x7F], idx, 0); 198 } 199 break; 200 case ATOM_ARG_PS: 201 idx = U8(*ptr); 202 (*ptr)++; 203 val = B_LENDIAN_TO_HOST_INT32(ctx->ps[idx]); 204 // TODO : val = get_unaligned_le32((u32 *)&ctx->ps[idx]); 205 break; 206 case ATOM_ARG_WS: 207 idx = U8(*ptr); 208 (*ptr)++; 209 switch(idx) { 210 case ATOM_WS_QUOTIENT: 211 val = gctx->divmul[0]; 212 break; 213 case ATOM_WS_REMAINDER: 214 val = gctx->divmul[1]; 215 break; 216 case ATOM_WS_DATAPTR: 217 val = gctx->data_block; 218 break; 219 case ATOM_WS_SHIFT: 220 val = gctx->shift; 221 break; 222 case ATOM_WS_OR_MASK: 223 val = 1 << gctx->shift; 224 break; 225 case ATOM_WS_AND_MASK: 226 val = ~(1 << gctx->shift); 227 break; 228 case ATOM_WS_FB_WINDOW: 229 val = gctx->fb_base; 230 break; 231 case ATOM_WS_ATTRIBUTES: 232 val = gctx->io_attr; 233 break; 234 case ATOM_WS_REGPTR: 235 val = gctx->reg_block; 236 break; 237 default: 238 val = ctx->ws[idx]; 239 } 240 break; 241 case ATOM_ARG_ID: 242 idx = U16(*ptr); 243 (*ptr) += 2; 244 val = U32(idx + gctx->data_block); 245 break; 246 case ATOM_ARG_FB: 247 idx = U8(*ptr); 248 (*ptr)++; 249 val = gctx->scratch[((gctx->fb_base + idx) / 4)]; 250 if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) { 251 ERROR("%s: fb tried to read beyond scratch region!" 252 " %" B_PRIu32 " vs. %" B_PRIu32 "\n", __func__, 253 gctx->fb_base + (idx * 4), gctx->scratch_size_bytes); 254 val = 0; 255 } else 256 val = gctx->scratch[(gctx->fb_base / 4) + idx]; 257 break; 258 case ATOM_ARG_IMM: 259 switch(align) { 260 case ATOM_SRC_DWORD: 261 val = U32(*ptr); 262 (*ptr)+=4; 263 return val; 264 case ATOM_SRC_WORD0: 265 case ATOM_SRC_WORD8: 266 case ATOM_SRC_WORD16: 267 val = U16(*ptr); 268 (*ptr) += 2; 269 return val; 270 case ATOM_SRC_BYTE0: 271 case ATOM_SRC_BYTE8: 272 case ATOM_SRC_BYTE16: 273 case ATOM_SRC_BYTE24: 274 val = U8(*ptr); 275 (*ptr)++; 276 return val; 277 } 278 return 0; 279 case ATOM_ARG_PLL: 280 idx = U8(*ptr); 281 (*ptr)++; 282 val = gctx->card->pll_read(idx); 283 break; 284 case ATOM_ARG_MC: 285 idx = U8(*ptr); 286 (*ptr)++; 287 val = gctx->card->mc_read(idx); 288 return 0; 289 } 290 if (saved) 291 *saved = val; 292 val &= atom_arg_mask[align]; 293 val >>= atom_arg_shift[align]; 294 return val; 295 } 296 297 298 static void 299 atom_skip_src_int(atom_exec_context *ctx, uint8 attr, int *ptr) 300 { 301 uint32 align = (attr >> 3) & 7, arg = attr & 7; 302 switch(arg) { 303 case ATOM_ARG_REG: 304 case ATOM_ARG_ID: 305 (*ptr) += 2; 306 break; 307 case ATOM_ARG_PLL: 308 case ATOM_ARG_MC: 309 case ATOM_ARG_PS: 310 case ATOM_ARG_WS: 311 case ATOM_ARG_FB: 312 (*ptr)++; 313 break; 314 case ATOM_ARG_IMM: 315 switch(align) { 316 case ATOM_SRC_DWORD: 317 (*ptr) += 4; 318 return; 319 case ATOM_SRC_WORD0: 320 case ATOM_SRC_WORD8: 321 case ATOM_SRC_WORD16: 322 (*ptr) += 2; 323 return; 324 case ATOM_SRC_BYTE0: 325 case ATOM_SRC_BYTE8: 326 case ATOM_SRC_BYTE16: 327 case ATOM_SRC_BYTE24: 328 (*ptr)++; 329 return; 330 } 331 return; 332 } 333 } 334 335 336 static uint32 337 atom_get_src(atom_exec_context *ctx, uint8 attr, int *ptr) 338 { 339 return atom_get_src_int(ctx, attr, ptr, NULL, 1); 340 } 341 342 343 static uint32 344 atom_get_src_direct(atom_exec_context *ctx, uint8_t align, int *ptr) 345 { 346 uint32 val = 0xCDCDCDCD; 347 348 switch (align) { 349 case ATOM_SRC_DWORD: 350 val = U32(*ptr); 351 (*ptr) += 4; 352 break; 353 case ATOM_SRC_WORD0: 354 case ATOM_SRC_WORD8: 355 case ATOM_SRC_WORD16: 356 val = U16(*ptr); 357 (*ptr) += 2; 358 break; 359 case ATOM_SRC_BYTE0: 360 case ATOM_SRC_BYTE8: 361 case ATOM_SRC_BYTE16: 362 case ATOM_SRC_BYTE24: 363 val = U8(*ptr); 364 (*ptr)++; 365 break; 366 } 367 return val; 368 } 369 370 371 static uint32 372 atom_get_dst(atom_exec_context *ctx, int arg, uint8 attr, 373 int *ptr, uint32 *saved, int print) 374 { 375 return atom_get_src_int(ctx, 376 arg|atom_dst_to_src[(attr>>3)&7][(attr>>6)&3]<<3, ptr, saved, print); 377 } 378 379 380 static void 381 atom_skip_dst(atom_exec_context *ctx, int arg, uint8 attr, int *ptr) 382 { 383 atom_skip_src_int(ctx, 384 arg|atom_dst_to_src[(attr>>3)&7][(attr>>6)&3]<<3, ptr); 385 } 386 387 388 static void 389 atom_put_dst(atom_exec_context *ctx, int arg, uint8 attr, 390 int *ptr, uint32 val, uint32 saved) 391 { 392 uint32 align = atom_dst_to_src[(attr>>3)&7][(attr>>6)&3], 393 old_val = val, idx; 394 atom_context *gctx = ctx->ctx; 395 old_val &= atom_arg_mask[align] >> atom_arg_shift[align]; 396 val <<= atom_arg_shift[align]; 397 val &= atom_arg_mask[align]; 398 saved &= ~atom_arg_mask[align]; 399 val |= saved; 400 switch(arg) { 401 case ATOM_ARG_REG: 402 idx = U16(*ptr); 403 (*ptr) += 2; 404 idx += gctx->reg_block; 405 switch(gctx->io_mode) { 406 case ATOM_IO_MM: 407 if (idx == 0) 408 gctx->card->reg_write(idx, val << 2); 409 else 410 gctx->card->reg_write(idx, val); 411 break; 412 case ATOM_IO_PCI: 413 TRACE("%s: PCI registers are not implemented.\n", 414 __func__); 415 return; 416 case ATOM_IO_SYSIO: 417 TRACE("%s: SYSIO registers are not implemented.\n", 418 __func__); 419 return; 420 default: 421 if (!(gctx->io_mode & 0x80)) { 422 TRACE("%s: Bad IO mode.\n", __func__); 423 return; 424 } 425 if (!gctx->iio[gctx->io_mode & 0xFF]) { 426 TRACE("%s: Undefined indirect IO write method %d\n", 427 __func__, gctx->io_mode & 0x7F); 428 return; 429 } 430 atom_iio_execute(gctx, gctx->iio[gctx->io_mode&0xFF], 431 idx, val); 432 } 433 break; 434 case ATOM_ARG_PS: 435 idx = U8(*ptr); 436 (*ptr)++; 437 ctx->ps[idx] = B_HOST_TO_LENDIAN_INT32(val); 438 break; 439 case ATOM_ARG_WS: 440 idx = U8(*ptr); 441 (*ptr)++; 442 switch(idx) { 443 case ATOM_WS_QUOTIENT: 444 gctx->divmul[0] = val; 445 break; 446 case ATOM_WS_REMAINDER: 447 gctx->divmul[1] = val; 448 break; 449 case ATOM_WS_DATAPTR: 450 gctx->data_block = val; 451 break; 452 case ATOM_WS_SHIFT: 453 gctx->shift = val; 454 break; 455 case ATOM_WS_OR_MASK: 456 case ATOM_WS_AND_MASK: 457 break; 458 case ATOM_WS_FB_WINDOW: 459 gctx->fb_base = val; 460 break; 461 case ATOM_WS_ATTRIBUTES: 462 gctx->io_attr = val; 463 break; 464 case ATOM_WS_REGPTR: 465 gctx->reg_block = val; 466 break; 467 default: 468 ctx->ws[idx] = val; 469 } 470 break; 471 case ATOM_ARG_FB: 472 idx = U8(*ptr); 473 (*ptr)++; 474 if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) { 475 ERROR("%s: fb tried to write beyond scratch region! " 476 "%" B_PRIu32 " vs. %" B_PRIu32 "\n", __func__, 477 gctx->fb_base + (idx * 4), gctx->scratch_size_bytes); 478 } else 479 gctx->scratch[(gctx->fb_base / 4) + idx] = val; 480 break; 481 case ATOM_ARG_PLL: 482 idx = U8(*ptr); 483 (*ptr)++; 484 gctx->card->pll_write(idx, val); 485 break; 486 case ATOM_ARG_MC: 487 idx = U8(*ptr); 488 (*ptr)++; 489 gctx->card->mc_write(idx, val); 490 return; 491 } 492 } 493 494 495 static void 496 atom_op_add(atom_exec_context *ctx, int *ptr, int arg) 497 { 498 uint8 attr = U8((*ptr)++); 499 uint32 dst, src, saved; 500 int dptr = *ptr; 501 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 502 src = atom_get_src(ctx, attr, ptr); 503 #ifdef TRACE_ATOM 504 TRACE("%s: 0x%" B_PRIX32 " + 0x%" B_PRIX32 " is 0x%" B_PRIX32 "\n", 505 __func__, dst, src, dst + src); 506 #endif 507 dst += src; 508 atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 509 } 510 511 512 static void 513 atom_op_and(atom_exec_context *ctx, int *ptr, int arg) 514 { 515 uint8 attr = U8((*ptr)++); 516 uint32 dst, src, saved; 517 int dptr = *ptr; 518 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 519 src = atom_get_src(ctx, attr, ptr); 520 #ifdef TRACE_ATOM 521 TRACE("%s: 0x%" B_PRIX32 " & 0x%" B_PRIX32 " is 0x%" B_PRIX32 "\n", 522 __func__, src, dst, dst & src); 523 #endif 524 dst &= src; 525 atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 526 } 527 528 529 static void 530 atom_op_beep(atom_exec_context *ctx, int *ptr, int arg) 531 { 532 TRACE("%s: Quack!\n", __func__); 533 } 534 535 536 static void 537 atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg) 538 { 539 int idx = U8((*ptr)++); 540 status_t result = B_OK; 541 542 if (idx < ATOM_TABLE_NAMES_CNT) { 543 TRACE("%s: table: %s (%d)\n", __func__, atom_table_names[idx], idx); 544 } else { 545 ERROR("%s: table: unknown (%d)\n", __func__, idx); 546 } 547 548 if (U16(ctx->ctx->cmd_table + 4 + 2 * idx)) { 549 result = atom_execute_table_locked(ctx->ctx, 550 idx, ctx->ps + ctx->ps_shift); 551 } 552 553 if (result != B_OK) 554 ctx->abort = true; 555 } 556 557 558 static void 559 atom_op_clear(atom_exec_context *ctx, int *ptr, int arg) 560 { 561 uint8 attr = U8((*ptr)++); 562 uint32 saved; 563 int dptr = *ptr; 564 attr &= 0x38; 565 attr |= atom_def_dst[attr>>3]<<6; 566 atom_get_dst(ctx, arg, attr, ptr, &saved, 0); 567 TRACE("%s\n", __func__); 568 atom_put_dst(ctx, arg, attr, &dptr, 0, saved); 569 } 570 571 572 static void 573 atom_op_compare(atom_exec_context *ctx, int *ptr, int arg) 574 { 575 uint8 attr = U8((*ptr)++); 576 uint32 dst, src; 577 dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); 578 src = atom_get_src(ctx, attr, ptr); 579 ctx->ctx->cs_equal = (dst == src); 580 ctx->ctx->cs_above = (dst > src); 581 TRACE("%s: 0x%" B_PRIX32 " %s 0x%" B_PRIX32 "\n", __func__, 582 dst, ctx->ctx->cs_above ? ">" : "<=", src); 583 } 584 585 586 static void 587 atom_op_delay(atom_exec_context *ctx, int *ptr, int arg) 588 { 589 bigtime_t count = U8((*ptr)++); 590 if (arg == ATOM_UNIT_MICROSEC) { 591 TRACE("%s: %" B_PRId64 " microseconds\n", __func__, count); 592 // Microseconds 593 snooze(count); 594 } else { 595 TRACE("%s: %" B_PRId64 " milliseconds\n", __func__, count); 596 // Milliseconds 597 snooze(count * 1000); 598 } 599 } 600 601 602 static void 603 atom_op_div(atom_exec_context *ctx, int *ptr, int arg) 604 { 605 uint8 attr = U8((*ptr)++); 606 uint32 dst, src; 607 dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); 608 src = atom_get_src(ctx, attr, ptr); 609 if (src != 0) { 610 ctx->ctx->divmul[0] = dst / src; 611 ctx->ctx->divmul[1] = dst%src; 612 } else { 613 ctx->ctx->divmul[0] = 0; 614 ctx->ctx->divmul[1] = 0; 615 } 616 #ifdef ATOM_TRACE 617 TRACE("%s: 0x%" B_PRIX32 " / 0x%" B_PRIX32 " is 0x%" B_PRIX32 618 " remander 0x%" B_PRIX32 "\n", __func__, dst, src, 619 ctx->ctx->divmul[0], ctx->ctx->divmul[1]); 620 #endif 621 } 622 623 624 static void 625 atom_op_eot(atom_exec_context *ctx, int *ptr, int arg) 626 { 627 /* functionally, a nop */ 628 } 629 630 631 static void 632 atom_op_jump(atom_exec_context *ctx, int *ptr, int arg) 633 { 634 int execute = 0, target = U16(*ptr); 635 (*ptr) += 2; 636 switch(arg) { 637 case ATOM_COND_ABOVE: 638 execute = ctx->ctx->cs_above; 639 break; 640 case ATOM_COND_ABOVEOREQUAL: 641 execute = ctx->ctx->cs_above || ctx->ctx->cs_equal; 642 break; 643 case ATOM_COND_ALWAYS: 644 execute = 1; 645 break; 646 case ATOM_COND_BELOW: 647 execute = !(ctx->ctx->cs_above || ctx->ctx->cs_equal); 648 break; 649 case ATOM_COND_BELOWOREQUAL: 650 execute = !ctx->ctx->cs_above; 651 break; 652 case ATOM_COND_EQUAL: 653 execute = ctx->ctx->cs_equal; 654 break; 655 case ATOM_COND_NOTEQUAL: 656 execute = !ctx->ctx->cs_equal; 657 break; 658 } 659 TRACE("%s: execute jump: %s; target: 0x%04X\n", __func__, 660 execute? "yes" : "no", target); 661 662 if (execute) { 663 // Time based jmp timeout 664 if (ctx->lastJump == (ctx->start + target)) { 665 bigtime_t loopDuration = system_time() - ctx->jumpStart; 666 if (loopDuration > ATOM_OP_JMP_TIMEOUT * 1000000) { 667 ERROR("%s: Error: AtomBIOS stuck in loop for more then %d " 668 "seconds. (%" B_PRIu32 " identical jmp op's)\n", __func__, 669 ATOM_OP_JMP_TIMEOUT, ctx->lastJumpCount); 670 ctx->abort = true; 671 } else 672 ctx->lastJumpCount++; 673 } else { 674 ctx->jumpStart = system_time(); 675 ctx->lastJump = ctx->start + target; 676 ctx->lastJumpCount = 1; 677 } 678 *ptr = ctx->start + target; 679 } 680 } 681 682 683 static void 684 atom_op_mask(atom_exec_context *ctx, int *ptr, int arg) 685 { 686 uint8 attr = U8((*ptr)++); 687 uint32 dst, mask, src, saved; 688 int dptr = *ptr; 689 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 690 mask = atom_get_src_direct(ctx, ((attr >> 3) & 7), ptr); 691 src = atom_get_src(ctx, attr, ptr); 692 dst &= mask; 693 dst |= src; 694 TRACE("%s: src: 0x%" B_PRIX32 " mask 0x%" B_PRIX32 " is 0x%" B_PRIX32 "\n", 695 __func__, src, mask, dst); 696 atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 697 } 698 699 700 static void 701 atom_op_move(atom_exec_context *ctx, int *ptr, int arg) 702 { 703 uint8 attr = U8((*ptr)++); 704 uint32 src, saved; 705 int dptr = *ptr; 706 if (((attr >> 3) & 7) != ATOM_SRC_DWORD) 707 atom_get_dst(ctx, arg, attr, ptr, &saved, 0); 708 else { 709 atom_skip_dst(ctx, arg, attr, ptr); 710 saved = 0xCDCDCDCD; 711 } 712 src = atom_get_src(ctx, attr, ptr); 713 TRACE("%s: src: 0x%" B_PRIX32 "; saved: 0x%" B_PRIX32 "\n", 714 __func__, src, saved); 715 atom_put_dst(ctx, arg, attr, &dptr, src, saved); 716 } 717 718 719 static void 720 atom_op_mul(atom_exec_context *ctx, int *ptr, int arg) 721 { 722 uint8 attr = U8((*ptr)++); 723 uint32 dst, src; 724 dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); 725 src = atom_get_src(ctx, attr, ptr); 726 ctx->ctx->divmul[0] = dst * src; 727 TRACE("%s: 0x%" B_PRIX32 " * 0x%" B_PRIX32 " is 0x%" B_PRIX32 "\n", 728 __func__, dst, src, ctx->ctx->divmul[0]); 729 } 730 731 732 static void 733 atom_op_nop(atom_exec_context *ctx, int *ptr, int arg) 734 { 735 /* nothing */ 736 } 737 738 739 static void 740 atom_op_or(atom_exec_context *ctx, int *ptr, int arg) 741 { 742 uint8 attr = U8((*ptr)++); 743 uint32 dst, src, saved; 744 int dptr = *ptr; 745 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 746 src = atom_get_src(ctx, attr, ptr); 747 #ifdef ATOM_TRACE 748 TRACE("%s: 0x%" B_PRIX32 " | 0x%" B_PRIX32 " is 0x%" B_PRIX32 "\n", 749 __func__, dst, src, dst | src); 750 #endif 751 dst |= src; 752 atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 753 } 754 755 756 static void 757 atom_op_postcard(atom_exec_context *ctx, int *ptr, int arg) 758 { 759 #ifdef ATOM_TRACE 760 uint8 val = U8((*ptr)++); 761 TRACE("%s: POST card output: 0x%" B_PRIX8 "\n", __func__, val); 762 #endif 763 } 764 765 766 static void atom_op_repeat(atom_exec_context *ctx, int *ptr, int arg) 767 { 768 TRACE("%s: unimplemented!\n", __func__); 769 } 770 771 772 static void 773 atom_op_restorereg(atom_exec_context *ctx, int *ptr, int arg) 774 { 775 TRACE("%s: unimplemented!\n", __func__); 776 } 777 778 779 static void 780 atom_op_savereg(atom_exec_context *ctx, int *ptr, int arg) 781 { 782 TRACE("%s: unimplemented!\n", __func__); 783 } 784 785 786 static void 787 atom_op_setdatablock(atom_exec_context *ctx, int *ptr, int arg) 788 { 789 int idx = U8(*ptr); 790 (*ptr)++; 791 TRACE("%s: block: %d\n", __func__, idx); 792 if (!idx) 793 ctx->ctx->data_block = 0; 794 else if (idx == 255) 795 ctx->ctx->data_block = ctx->start; 796 else 797 ctx->ctx->data_block = U16(ctx->ctx->data_table + 4 + 2 * idx); 798 } 799 800 801 static void 802 atom_op_setfbbase(atom_exec_context *ctx, int *ptr, int arg) 803 { 804 uint8 attr = U8((*ptr)++); 805 ctx->ctx->fb_base = atom_get_src(ctx, attr, ptr); 806 TRACE("%s: fb_base: 0x%" B_PRIX32 "\n", __func__, ctx->ctx->fb_base); 807 } 808 809 810 static void 811 atom_op_setport(atom_exec_context *ctx, int *ptr, int arg) 812 { 813 int port; 814 switch(arg) { 815 case ATOM_PORT_ATI: 816 port = U16(*ptr); 817 if (port < ATOM_IO_NAMES_CNT) { 818 TRACE("%s: port: %d (%s)\n", __func__, 819 port, atom_io_names[port]); 820 } else 821 TRACE("%s: port: %d\n", __func__, port); 822 if (!port) 823 ctx->ctx->io_mode = ATOM_IO_MM; 824 else 825 ctx->ctx->io_mode = ATOM_IO_IIO | port; 826 (*ptr) += 2; 827 break; 828 case ATOM_PORT_PCI: 829 ctx->ctx->io_mode = ATOM_IO_PCI; 830 (*ptr)++; 831 break; 832 case ATOM_PORT_SYSIO: 833 ctx->ctx->io_mode = ATOM_IO_SYSIO; 834 (*ptr)++; 835 break; 836 } 837 } 838 839 840 static void 841 atom_op_setregblock(atom_exec_context *ctx, int *ptr, int arg) 842 { 843 ctx->ctx->reg_block = U16(*ptr); 844 (*ptr)+=2; 845 } 846 847 848 static void atom_op_shift_left(atom_exec_context *ctx, int *ptr, int arg) 849 { 850 uint8 attr = U8((*ptr)++), shift; 851 uint32 saved, dst; 852 int dptr = *ptr; 853 attr &= 0x38; 854 attr |= atom_def_dst[attr >> 3] << 6; 855 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 856 shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr); 857 #ifdef ATOM_TRACE 858 TRACE("%s: 0x%" B_PRIX32 " << %" B_PRId8 " is 0X%" B_PRIX32 "\n", 859 __func__, dst, shift, dst << shift); 860 #endif 861 dst <<= shift; 862 atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 863 } 864 865 866 static void atom_op_shift_right(atom_exec_context *ctx, int *ptr, int arg) 867 { 868 uint8 attr = U8((*ptr)++), shift; 869 uint32 saved, dst; 870 int dptr = *ptr; 871 attr &= 0x38; 872 attr |= atom_def_dst[attr >> 3] << 6; 873 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 874 shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr); 875 #ifdef ATOM_TRACE 876 TRACE("%s: 0x%" B_PRIX32 " >> %" B_PRId8 " is 0X%" B_PRIX32 "\n", 877 __func__, dst, shift, dst << shift); 878 #endif 879 dst >>= shift; 880 atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 881 } 882 883 884 static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg) 885 { 886 uint8 attr = U8((*ptr)++), shift; 887 uint32 saved, dst; 888 int dptr = *ptr; 889 uint32 dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3]; 890 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 891 /* op needs to full dst value */ 892 dst = saved; 893 shift = atom_get_src(ctx, attr, ptr); 894 #ifdef ATOM_TRACE 895 TRACE("%s: 0x%" B_PRIX32 " << %" B_PRId8 " is 0X%" B_PRIX32 "\n", 896 __func__, dst, shift, dst << shift); 897 #endif 898 dst <<= shift; 899 dst &= atom_arg_mask[dst_align]; 900 dst >>= atom_arg_shift[dst_align]; 901 atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 902 } 903 904 905 static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg) 906 { 907 uint8 attr = U8((*ptr)++), shift; 908 uint32 saved, dst; 909 int dptr = *ptr; 910 uint32 dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3]; 911 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 912 /* op needs to full dst value */ 913 dst = saved; 914 shift = atom_get_src(ctx, attr, ptr); 915 #ifdef ATOM_TRACE 916 TRACE("%s: 0x%" B_PRIX32 " >> %" B_PRId8 " is 0X%" B_PRIX32 "\n", 917 __func__, dst, shift, dst << shift); 918 #endif 919 dst >>= shift; 920 dst &= atom_arg_mask[dst_align]; 921 dst >>= atom_arg_shift[dst_align]; 922 atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 923 } 924 925 926 static void 927 atom_op_sub(atom_exec_context *ctx, int *ptr, int arg) 928 { 929 uint8 attr = U8((*ptr)++); 930 uint32 dst, src, saved; 931 int dptr = *ptr; 932 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 933 src = atom_get_src(ctx, attr, ptr); 934 #ifdef TRACE_ATOM 935 TRACE("%s: 0x%" B_PRIX32 " - 0x%" B_PRIX32 " is 0x%" B_PRIX32 "\n", 936 __func__, dst, src, dst - src); 937 #endif 938 dst -= src; 939 atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 940 } 941 942 943 static void 944 atom_op_switch(atom_exec_context *ctx, int *ptr, int arg) 945 { 946 uint8 attr = U8((*ptr)++); 947 uint32 src, val, target; 948 TRACE("%s: switch start\n", __func__); 949 src = atom_get_src(ctx, attr, ptr); 950 while (U16(*ptr) != ATOM_CASE_END) 951 if (U8(*ptr) == ATOM_CASE_MAGIC) { 952 (*ptr)++; 953 TRACE("%s: switch case\n", __func__); 954 val = atom_get_src(ctx, (attr & 0x38) | ATOM_ARG_IMM, ptr); 955 target = U16(*ptr); 956 if (val == src) { 957 *ptr = ctx->start + target; 958 return; 959 } 960 (*ptr) += 2; 961 } else { 962 TRACE("%s: ERROR bad case\n", __func__); 963 return; 964 } 965 (*ptr) += 2; 966 } 967 968 969 static void 970 atom_op_test(atom_exec_context *ctx, int *ptr, int arg) 971 { 972 uint8 attr = U8((*ptr)++); 973 uint32 dst, src; 974 dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); 975 src = atom_get_src(ctx, attr, ptr); 976 // logic is reversed 977 ctx->ctx->cs_equal = ((dst & src) == 0); 978 TRACE("%s: 0x%" B_PRIX32 " and 0x%" B_PRIX32 " are %s\n", __func__, 979 dst, src, ctx->ctx->cs_equal ? "NE" : "EQ"); 980 } 981 982 983 static void 984 atom_op_xor(atom_exec_context *ctx, int *ptr, int arg) 985 { 986 uint8 attr = U8((*ptr)++); 987 uint32 dst, src, saved; 988 int dptr = *ptr; 989 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 990 src = atom_get_src(ctx, attr, ptr); 991 #ifdef ATOM_TRACE 992 TRACE("%s: 0x%" B_PRIX32 " ^ 0X%" B_PRIX32 " is " B_PRIX32 "\n", 993 __func__, dst, src, dst ^ src); 994 #endif 995 dst ^= src; 996 atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 997 } 998 999 1000 static void 1001 atom_op_debug(atom_exec_context *ctx, int *ptr, int arg) 1002 { 1003 TRACE("%s: unimplemented!\n", __func__); 1004 } 1005 1006 1007 static struct { 1008 void (*func)(atom_exec_context *, int *, int); 1009 int arg; 1010 } opcode_table[ATOM_OP_CNT] = { 1011 { NULL, 0 }, 1012 { atom_op_move, ATOM_ARG_REG }, 1013 { atom_op_move, ATOM_ARG_PS }, 1014 { atom_op_move, ATOM_ARG_WS }, 1015 { atom_op_move, ATOM_ARG_FB }, 1016 { atom_op_move, ATOM_ARG_PLL }, 1017 { atom_op_move, ATOM_ARG_MC }, 1018 { atom_op_and, ATOM_ARG_REG }, 1019 { atom_op_and, ATOM_ARG_PS }, 1020 { atom_op_and, ATOM_ARG_WS }, 1021 { atom_op_and, ATOM_ARG_FB }, 1022 { atom_op_and, ATOM_ARG_PLL }, 1023 { atom_op_and, ATOM_ARG_MC }, 1024 { atom_op_or, ATOM_ARG_REG }, 1025 { atom_op_or, ATOM_ARG_PS }, 1026 { atom_op_or, ATOM_ARG_WS }, 1027 { atom_op_or, ATOM_ARG_FB }, 1028 { atom_op_or, ATOM_ARG_PLL }, 1029 { atom_op_or, ATOM_ARG_MC }, 1030 { atom_op_shift_left, ATOM_ARG_REG }, 1031 { atom_op_shift_left, ATOM_ARG_PS }, 1032 { atom_op_shift_left, ATOM_ARG_WS }, 1033 { atom_op_shift_left, ATOM_ARG_FB }, 1034 { atom_op_shift_left, ATOM_ARG_PLL }, 1035 { atom_op_shift_left, ATOM_ARG_MC }, 1036 { atom_op_shift_right, ATOM_ARG_REG }, 1037 { atom_op_shift_right, ATOM_ARG_PS }, 1038 { atom_op_shift_right, ATOM_ARG_WS }, 1039 { atom_op_shift_right, ATOM_ARG_FB }, 1040 { atom_op_shift_right, ATOM_ARG_PLL }, 1041 { atom_op_shift_right, ATOM_ARG_MC }, 1042 { atom_op_mul, ATOM_ARG_REG }, 1043 { atom_op_mul, ATOM_ARG_PS }, 1044 { atom_op_mul, ATOM_ARG_WS }, 1045 { atom_op_mul, ATOM_ARG_FB }, 1046 { atom_op_mul, ATOM_ARG_PLL }, 1047 { atom_op_mul, ATOM_ARG_MC }, 1048 { atom_op_div, ATOM_ARG_REG }, 1049 { atom_op_div, ATOM_ARG_PS }, 1050 { atom_op_div, ATOM_ARG_WS }, 1051 { atom_op_div, ATOM_ARG_FB }, 1052 { atom_op_div, ATOM_ARG_PLL }, 1053 { atom_op_div, ATOM_ARG_MC }, 1054 { atom_op_add, ATOM_ARG_REG }, 1055 { atom_op_add, ATOM_ARG_PS }, 1056 { atom_op_add, ATOM_ARG_WS }, 1057 { atom_op_add, ATOM_ARG_FB }, 1058 { atom_op_add, ATOM_ARG_PLL }, 1059 { atom_op_add, ATOM_ARG_MC }, 1060 { atom_op_sub, ATOM_ARG_REG }, 1061 { atom_op_sub, ATOM_ARG_PS }, 1062 { atom_op_sub, ATOM_ARG_WS }, 1063 { atom_op_sub, ATOM_ARG_FB }, 1064 { atom_op_sub, ATOM_ARG_PLL }, 1065 { atom_op_sub, ATOM_ARG_MC }, 1066 { atom_op_setport, ATOM_PORT_ATI }, 1067 { atom_op_setport, ATOM_PORT_PCI }, 1068 { atom_op_setport, ATOM_PORT_SYSIO }, 1069 { atom_op_setregblock, 0 }, 1070 { atom_op_setfbbase, 0 }, 1071 { atom_op_compare, ATOM_ARG_REG }, 1072 { atom_op_compare, ATOM_ARG_PS }, 1073 { atom_op_compare, ATOM_ARG_WS }, 1074 { atom_op_compare, ATOM_ARG_FB }, 1075 { atom_op_compare, ATOM_ARG_PLL }, 1076 { atom_op_compare, ATOM_ARG_MC }, 1077 { atom_op_switch, 0 }, 1078 { atom_op_jump, ATOM_COND_ALWAYS }, 1079 { atom_op_jump, ATOM_COND_EQUAL }, 1080 { atom_op_jump, ATOM_COND_BELOW }, 1081 { atom_op_jump, ATOM_COND_ABOVE }, 1082 { atom_op_jump, ATOM_COND_BELOWOREQUAL }, 1083 { atom_op_jump, ATOM_COND_ABOVEOREQUAL }, 1084 { atom_op_jump, ATOM_COND_NOTEQUAL }, 1085 { atom_op_test, ATOM_ARG_REG }, 1086 { atom_op_test, ATOM_ARG_PS }, 1087 { atom_op_test, ATOM_ARG_WS }, 1088 { atom_op_test, ATOM_ARG_FB }, 1089 { atom_op_test, ATOM_ARG_PLL }, 1090 { atom_op_test, ATOM_ARG_MC }, 1091 { atom_op_delay, ATOM_UNIT_MILLISEC }, 1092 { atom_op_delay, ATOM_UNIT_MICROSEC }, 1093 { atom_op_calltable, 0 }, 1094 { atom_op_repeat, 0 }, 1095 { atom_op_clear, ATOM_ARG_REG }, 1096 { atom_op_clear, ATOM_ARG_PS }, 1097 { atom_op_clear, ATOM_ARG_WS }, 1098 { atom_op_clear, ATOM_ARG_FB }, 1099 { atom_op_clear, ATOM_ARG_PLL }, 1100 { atom_op_clear, ATOM_ARG_MC }, 1101 { atom_op_nop, 0 }, 1102 { atom_op_eot, 0 }, 1103 { atom_op_mask, ATOM_ARG_REG }, 1104 { atom_op_mask, ATOM_ARG_PS }, 1105 { atom_op_mask, ATOM_ARG_WS }, 1106 { atom_op_mask, ATOM_ARG_FB }, 1107 { atom_op_mask, ATOM_ARG_PLL }, 1108 { atom_op_mask, ATOM_ARG_MC }, 1109 { atom_op_postcard, 0 }, 1110 { atom_op_beep, 0 }, 1111 { atom_op_savereg, 0 }, 1112 { atom_op_restorereg, 0 }, 1113 { atom_op_setdatablock, 0 }, 1114 { atom_op_xor, ATOM_ARG_REG }, 1115 { atom_op_xor, ATOM_ARG_PS }, 1116 { atom_op_xor, ATOM_ARG_WS }, 1117 { atom_op_xor, ATOM_ARG_FB }, 1118 { atom_op_xor, ATOM_ARG_PLL }, 1119 { atom_op_xor, ATOM_ARG_MC }, 1120 { atom_op_shl, ATOM_ARG_REG }, 1121 { atom_op_shl, ATOM_ARG_PS }, 1122 { atom_op_shl, ATOM_ARG_WS }, 1123 { atom_op_shl, ATOM_ARG_FB }, 1124 { atom_op_shl, ATOM_ARG_PLL }, 1125 { atom_op_shl, ATOM_ARG_MC }, 1126 { atom_op_shr, ATOM_ARG_REG }, 1127 { atom_op_shr, ATOM_ARG_PS }, 1128 { atom_op_shr, ATOM_ARG_WS }, 1129 { atom_op_shr, ATOM_ARG_FB }, 1130 { atom_op_shr, ATOM_ARG_PLL }, 1131 { atom_op_shr, ATOM_ARG_MC }, 1132 { atom_op_debug, 0 }, 1133 }; 1134 1135 1136 status_t 1137 atom_execute_table_locked(atom_context *ctx, int index, uint32 * params) 1138 { 1139 int base = CU16(ctx->cmd_table + 4 + 2 * index); 1140 int len, ws, ps, ptr; 1141 unsigned char op; 1142 atom_exec_context ectx; 1143 1144 if (!base) { 1145 ERROR("%s: BUG: Table called doesn't exist in AtomBIOS!\n", __func__); 1146 return B_ERROR; 1147 } 1148 1149 len = CU16(base + ATOM_CT_SIZE_PTR); 1150 ws = CU8(base + ATOM_CT_WS_PTR); 1151 ps = CU8(base + ATOM_CT_PS_PTR) & ATOM_CT_PS_MASK; 1152 ptr = base + ATOM_CT_CODE_PTR; 1153 1154 ectx.ctx = ctx; 1155 ectx.ps_shift = ps / 4; 1156 ectx.start = base; 1157 ectx.ps = params; 1158 ectx.abort = false; 1159 ectx.lastJump = 0; 1160 ectx.lastJumpCount = 0; 1161 ectx.jumpStart = 0; 1162 if (ws) 1163 ectx.ws = (uint32*)malloc(4 * ws); 1164 else 1165 ectx.ws = NULL; 1166 1167 debug_depth++; 1168 while (1) { 1169 op = CU8(ptr++); 1170 const char* operationName; 1171 1172 if (op < ATOM_OP_NAMES_CNT) 1173 operationName = atom_op_names[op]; 1174 else 1175 operationName = "UNKNOWN"; 1176 1177 TRACE("%s: %s @ 0x%" B_PRIX16 "\n", __func__, operationName, ptr - 1); 1178 1179 if (ectx.abort == true) { 1180 ERROR("%s: AtomBIOS parser aborted calling operation %s" 1181 " (0x%" B_PRIX8 ") @ 0x%" B_PRIX16 "\n", __func__, 1182 operationName, op, ptr - 1); 1183 free(ectx.ws); 1184 return B_ERROR; 1185 } 1186 1187 if (op < ATOM_OP_CNT && op > 0) 1188 opcode_table[op].func(&ectx, &ptr, opcode_table[op].arg); 1189 else 1190 break; 1191 1192 if (op == ATOM_OP_EOT) 1193 break; 1194 } 1195 debug_depth--; 1196 1197 free(ectx.ws); 1198 return B_OK; 1199 } 1200 1201 1202 status_t 1203 atom_execute_table(atom_context *ctx, int index, uint32 *params) 1204 { 1205 if (acquire_sem_etc(ctx->exec_sem, 1, B_RELATIVE_TIMEOUT, 5000000) 1206 != B_NO_ERROR) { 1207 ERROR("%s: Timeout to obtain semaphore!\n", __func__); 1208 return B_ERROR; 1209 } 1210 /* reset reg block */ 1211 ctx->reg_block = 0; 1212 /* reset fb window */ 1213 ctx->fb_base = 0; 1214 /* reset io mode */ 1215 ctx->io_mode = ATOM_IO_MM; 1216 status_t result = atom_execute_table_locked(ctx, index, params); 1217 if (result != B_OK) { 1218 const char* tableName; 1219 if (index < ATOM_TABLE_NAMES_CNT) 1220 tableName = atom_table_names[index]; 1221 else 1222 tableName = "Unknown"; 1223 1224 ERROR("%s: AtomBIOS parser was aborted in table %s (0x%" B_PRIX8 ")\n", 1225 __func__, tableName, index); 1226 } 1227 1228 release_sem(ctx->exec_sem); 1229 return result; 1230 } 1231 1232 1233 static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 }; 1234 1235 1236 static void 1237 atom_index_iio(atom_context *ctx, int base) 1238 { 1239 ctx->iio = (uint16*)malloc(2 * 256); 1240 while (CU8(base) == ATOM_IIO_START) { 1241 ctx->iio[CU8(base + 1)] = base + 2; 1242 base += 2; 1243 while (CU8(base) != ATOM_IIO_END) 1244 base += atom_iio_len[CU8(base)]; 1245 base += 3; 1246 } 1247 } 1248 1249 1250 atom_context* 1251 atom_parse(card_info *card, uint8 *bios) 1252 { 1253 atom_context *ctx = (atom_context*)malloc(sizeof(atom_context)); 1254 1255 if (ctx == NULL) { 1256 ERROR("%s: Error: No memory for atom_context mapping\n", __func__); 1257 return NULL; 1258 } 1259 1260 ctx->card = card; 1261 ctx->bios = bios; 1262 1263 if (CU16(0) != ATOM_BIOS_MAGIC) { 1264 ERROR("Invalid BIOS magic.\n"); 1265 free(ctx); 1266 return NULL; 1267 } 1268 if (strncmp(CSTR(ATOM_ATI_MAGIC_PTR), ATOM_ATI_MAGIC, 1269 strlen(ATOM_ATI_MAGIC))) { 1270 ERROR("Invalid ATI magic.\n"); 1271 free(ctx); 1272 return NULL; 1273 } 1274 1275 int base = CU16(ATOM_ROM_TABLE_PTR); 1276 if (strncmp(CSTR(base + ATOM_ROM_MAGIC_PTR), ATOM_ROM_MAGIC, 1277 strlen(ATOM_ROM_MAGIC))) { 1278 ERROR("Invalid ATOM magic.\n"); 1279 free(ctx); 1280 return NULL; 1281 } 1282 1283 ctx->cmd_table = CU16(base + ATOM_ROM_CMD_PTR); 1284 ctx->data_table = CU16(base + ATOM_ROM_DATA_PTR); 1285 atom_index_iio(ctx, CU16(ctx->data_table + ATOM_DATA_IIO_PTR) + 4); 1286 1287 char *str = CSTR(CU16(base + ATOM_ROM_MSG_PTR)); 1288 while (*str && ((*str == '\n') || (*str == '\r'))) 1289 str++; 1290 1291 int i; 1292 char name[512]; 1293 // Terminate bios string if not 0 terminated 1294 for (i = 0; i < 511; i++) { 1295 name[i] = str[i]; 1296 if (name[i] < '.' || name[i] > 'z') { 1297 name[i] = 0; 1298 break; 1299 } 1300 } 1301 1302 TRACE("ATOM BIOS: %s", name); 1303 1304 return ctx; 1305 } 1306 1307 1308 status_t 1309 atom_asic_init(atom_context *ctx) 1310 { 1311 int hwi = CU16(ctx->data_table + ATOM_DATA_FWI_PTR); 1312 uint32 ps[16]; 1313 memset(ps, 0, 64); 1314 1315 ps[0] = B_HOST_TO_LENDIAN_INT32(CU32(hwi + ATOM_FWI_DEFSCLK_PTR)); 1316 ps[1] = B_HOST_TO_LENDIAN_INT32(CU32(hwi + ATOM_FWI_DEFMCLK_PTR)); 1317 if (!ps[0] || !ps[1]) 1318 return B_ERROR; 1319 1320 if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT)) 1321 return B_ERROR; 1322 1323 return atom_execute_table(ctx, ATOM_CMD_INIT, ps); 1324 } 1325 1326 1327 void 1328 atom_destroy(atom_context *ctx) 1329 { 1330 if (ctx != NULL) { 1331 free(ctx->iio); 1332 free(ctx->scratch); 1333 delete_sem(ctx->exec_sem); 1334 } 1335 1336 free(ctx); 1337 } 1338 1339 1340 status_t 1341 atom_parse_data_header(atom_context *ctx, int index, uint16 *size, 1342 uint8 *frev, uint8 *crev, uint16 *data_start) 1343 { 1344 int offset = index * 2 + 4; 1345 int idx = CU16(ctx->data_table + offset); 1346 uint16 *mdt = (uint16 *)ctx->bios + ctx->data_table + 4; 1347 1348 if (!mdt[index]) 1349 return B_ERROR; 1350 1351 if (size) 1352 *size = CU16(idx); 1353 if (frev) 1354 *frev = CU8(idx + 2); 1355 if (crev) 1356 *crev = CU8(idx + 3); 1357 *data_start = idx; 1358 return B_OK; 1359 } 1360 1361 1362 status_t 1363 atom_parse_cmd_header(atom_context *ctx, int index, uint8 * frev, 1364 uint8 * crev) 1365 { 1366 int offset = index * 2 + 4; 1367 int idx = CU16(ctx->cmd_table + offset); 1368 uint16 *mct = (uint16 *)ctx->bios + ctx->cmd_table + 4; 1369 1370 if (!mct[index]) 1371 return B_ERROR; 1372 1373 if (frev) 1374 *frev = CU8(idx + 2); 1375 if (crev) 1376 *crev = CU8(idx + 3); 1377 return B_OK; 1378 } 1379 1380 1381 status_t 1382 atom_allocate_fb_scratch(atom_context *ctx) 1383 { 1384 int index = GetIndexIntoMasterTable(DATA, VRAM_UsageByFirmware); 1385 uint16 data_offset; 1386 int usage_bytes = 0; 1387 _ATOM_VRAM_USAGE_BY_FIRMWARE *firmware; 1388 1389 if (atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset) 1390 == B_OK) { 1391 firmware = (_ATOM_VRAM_USAGE_BY_FIRMWARE *)(ctx->bios + data_offset); 1392 1393 TRACE("Atom firmware requested 0x%" B_PRIX32 " %" B_PRIu16 "kb\n", 1394 firmware->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware, 1395 firmware->asFirmwareVramReserveInfo[0].usFirmwareUseInKb); 1396 1397 usage_bytes 1398 = firmware->asFirmwareVramReserveInfo[0].usFirmwareUseInKb * 1024; 1399 } 1400 ctx->scratch_size_bytes = 0; 1401 if (usage_bytes == 0) 1402 usage_bytes = 20 * 1024; 1403 /* allocate some scratch memory */ 1404 ctx->scratch = (uint32*)malloc(usage_bytes); 1405 if (!ctx->scratch) 1406 return B_NO_MEMORY; 1407 1408 ctx->scratch_size_bytes = usage_bytes; 1409 return B_OK; 1410 } 1411