1254885Sdumbbell/* 2254885Sdumbbell * Copyright 2008 Advanced Micro Devices, Inc. 3254885Sdumbbell * 4254885Sdumbbell * Permission is hereby granted, free of charge, to any person obtaining a 5254885Sdumbbell * copy of this software and associated documentation files (the "Software"), 6254885Sdumbbell * to deal in the Software without restriction, including without limitation 7254885Sdumbbell * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8254885Sdumbbell * and/or sell copies of the Software, and to permit persons to whom the 9254885Sdumbbell * Software is furnished to do so, subject to the following conditions: 10254885Sdumbbell * 11254885Sdumbbell * The above copyright notice and this permission notice shall be included in 12254885Sdumbbell * all copies or substantial portions of the Software. 13254885Sdumbbell * 14254885Sdumbbell * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15254885Sdumbbell * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16254885Sdumbbell * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17254885Sdumbbell * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18254885Sdumbbell * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19254885Sdumbbell * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20254885Sdumbbell * OTHER DEALINGS IN THE SOFTWARE. 21254885Sdumbbell * 22254885Sdumbbell * Author: Stanislaw Skowronek 23254885Sdumbbell */ 24254885Sdumbbell 25254885Sdumbbell#include <sys/cdefs.h> 26254885Sdumbbell__FBSDID("$FreeBSD$"); 27254885Sdumbbell 28254885Sdumbbell#define ATOM_DEBUG 29254885Sdumbbell 30254885Sdumbbell#include "atom.h" 31254885Sdumbbell#include "atom-names.h" 32254885Sdumbbell#include "atom-bits.h" 33254885Sdumbbell#include "radeon.h" 34254885Sdumbbell 35254885Sdumbbell#define ATOM_COND_ABOVE 0 36254885Sdumbbell#define ATOM_COND_ABOVEOREQUAL 1 37254885Sdumbbell#define ATOM_COND_ALWAYS 2 38254885Sdumbbell#define ATOM_COND_BELOW 3 39254885Sdumbbell#define ATOM_COND_BELOWOREQUAL 4 40254885Sdumbbell#define ATOM_COND_EQUAL 5 41254885Sdumbbell#define ATOM_COND_NOTEQUAL 6 42254885Sdumbbell 43254885Sdumbbell#define ATOM_PORT_ATI 0 44254885Sdumbbell#define ATOM_PORT_PCI 1 45254885Sdumbbell#define ATOM_PORT_SYSIO 2 46254885Sdumbbell 47254885Sdumbbell#define ATOM_UNIT_MICROSEC 0 48254885Sdumbbell#define ATOM_UNIT_MILLISEC 1 49254885Sdumbbell 50254885Sdumbbell#define PLL_INDEX 2 51254885Sdumbbell#define PLL_DATA 3 52254885Sdumbbell 53254885Sdumbbelltypedef struct { 54254885Sdumbbell struct atom_context *ctx; 55254885Sdumbbell uint32_t *ps, *ws; 56254885Sdumbbell int ps_shift; 57254885Sdumbbell uint16_t start; 58254885Sdumbbell unsigned last_jump; 59254885Sdumbbell unsigned long last_jump_jiffies; 60254885Sdumbbell bool abort; 61254885Sdumbbell} atom_exec_context; 62254885Sdumbbell 63254885Sdumbbellint atom_debug = 0; 64254885Sdumbbellstatic int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params); 65254885Sdumbbell 66254885Sdumbbellstatic uint32_t atom_arg_mask[8] = 67254885Sdumbbell { 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000, 68254885Sdumbbell0xFF000000 }; 69254885Sdumbbellstatic int atom_arg_shift[8] = { 0, 0, 8, 16, 0, 8, 16, 24 }; 70254885Sdumbbell 71254885Sdumbbellstatic int atom_dst_to_src[8][4] = { 72254885Sdumbbell /* translate destination alignment field to the source alignment encoding */ 73254885Sdumbbell {0, 0, 0, 0}, 74254885Sdumbbell {1, 2, 3, 0}, 75254885Sdumbbell {1, 2, 3, 0}, 76254885Sdumbbell {1, 2, 3, 0}, 77254885Sdumbbell {4, 5, 6, 7}, 78254885Sdumbbell {4, 5, 6, 7}, 79254885Sdumbbell {4, 5, 6, 7}, 80254885Sdumbbell {4, 5, 6, 7}, 81254885Sdumbbell}; 82254885Sdumbbellstatic int atom_def_dst[8] = { 0, 0, 1, 2, 0, 1, 2, 3 }; 83254885Sdumbbell 84254885Sdumbbellstatic int debug_depth = 0; 85254885Sdumbbell#ifdef ATOM_DEBUG 86254885Sdumbbellstatic void debug_print_spaces(int n) 87254885Sdumbbell{ 88254885Sdumbbell while (n--) 89254885Sdumbbell printf(" "); 90254885Sdumbbell} 91254885Sdumbbell 92254894Sdumbbell#define ATOM_DEBUG_PRINT(...) do if (atom_debug) { printf(__FILE__ __VA_ARGS__); } while (0) 93254894Sdumbbell#define ATOM_SDEBUG_PRINT(...) do if (atom_debug) { printf(__FILE__); debug_print_spaces(debug_depth); printf(__VA_ARGS__); } while (0) 94254885Sdumbbell#else 95254894Sdumbbell#define ATOM_DEBUG_PRINT(...) do { } while (0) 96254894Sdumbbell#define ATOM_SDEBUG_PRINT(...) do { } while (0) 97254885Sdumbbell#endif 98254885Sdumbbell 99254885Sdumbbellstatic uint32_t atom_iio_execute(struct atom_context *ctx, int base, 100254885Sdumbbell uint32_t index, uint32_t data) 101254885Sdumbbell{ 102254885Sdumbbell struct radeon_device *rdev = ctx->card->dev->dev_private; 103254885Sdumbbell uint32_t temp = 0xCDCDCDCD; 104254885Sdumbbell 105254885Sdumbbell while (1) 106254885Sdumbbell switch (CU8(base)) { 107254885Sdumbbell case ATOM_IIO_NOP: 108254885Sdumbbell base++; 109254885Sdumbbell break; 110254885Sdumbbell case ATOM_IIO_READ: 111254885Sdumbbell temp = ctx->card->ioreg_read(ctx->card, CU16(base + 1)); 112254885Sdumbbell base += 3; 113254885Sdumbbell break; 114254885Sdumbbell case ATOM_IIO_WRITE: 115254885Sdumbbell if (rdev->family == CHIP_RV515) 116254885Sdumbbell (void)ctx->card->ioreg_read(ctx->card, CU16(base + 1)); 117254885Sdumbbell ctx->card->ioreg_write(ctx->card, CU16(base + 1), temp); 118254885Sdumbbell base += 3; 119254885Sdumbbell break; 120254885Sdumbbell case ATOM_IIO_CLEAR: 121254885Sdumbbell temp &= 122254885Sdumbbell ~((0xFFFFFFFF >> (32 - CU8(base + 1))) << 123254885Sdumbbell CU8(base + 2)); 124254885Sdumbbell base += 3; 125254885Sdumbbell break; 126254885Sdumbbell case ATOM_IIO_SET: 127254885Sdumbbell temp |= 128254885Sdumbbell (0xFFFFFFFF >> (32 - CU8(base + 1))) << CU8(base + 129254885Sdumbbell 2); 130254885Sdumbbell base += 3; 131254885Sdumbbell break; 132254885Sdumbbell case ATOM_IIO_MOVE_INDEX: 133254885Sdumbbell temp &= 134254885Sdumbbell ~((0xFFFFFFFF >> (32 - CU8(base + 1))) << 135254885Sdumbbell CU8(base + 3)); 136254885Sdumbbell temp |= 137254885Sdumbbell ((index >> CU8(base + 2)) & 138254885Sdumbbell (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base + 139254885Sdumbbell 3); 140254885Sdumbbell base += 4; 141254885Sdumbbell break; 142254885Sdumbbell case ATOM_IIO_MOVE_DATA: 143254885Sdumbbell temp &= 144254885Sdumbbell ~((0xFFFFFFFF >> (32 - CU8(base + 1))) << 145254885Sdumbbell CU8(base + 3)); 146254885Sdumbbell temp |= 147254885Sdumbbell ((data >> CU8(base + 2)) & 148254885Sdumbbell (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base + 149254885Sdumbbell 3); 150254885Sdumbbell base += 4; 151254885Sdumbbell break; 152254885Sdumbbell case ATOM_IIO_MOVE_ATTR: 153254885Sdumbbell temp &= 154254885Sdumbbell ~((0xFFFFFFFF >> (32 - CU8(base + 1))) << 155254885Sdumbbell CU8(base + 3)); 156254885Sdumbbell temp |= 157254885Sdumbbell ((ctx-> 158254885Sdumbbell io_attr >> CU8(base + 2)) & (0xFFFFFFFF >> (32 - 159254885Sdumbbell CU8 160254885Sdumbbell (base 161254885Sdumbbell + 162254885Sdumbbell 1)))) 163254885Sdumbbell << CU8(base + 3); 164254885Sdumbbell base += 4; 165254885Sdumbbell break; 166254885Sdumbbell case ATOM_IIO_END: 167254885Sdumbbell return temp; 168254885Sdumbbell default: 169254885Sdumbbell DRM_INFO("Unknown IIO opcode.\n"); 170254885Sdumbbell return 0; 171254885Sdumbbell } 172254885Sdumbbell} 173254885Sdumbbell 174254885Sdumbbellstatic uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, 175254885Sdumbbell int *ptr, uint32_t *saved, int print) 176254885Sdumbbell{ 177254885Sdumbbell uint32_t idx, val = 0xCDCDCDCD, align, arg; 178254885Sdumbbell struct atom_context *gctx = ctx->ctx; 179254885Sdumbbell arg = attr & 7; 180254885Sdumbbell align = (attr >> 3) & 7; 181254885Sdumbbell switch (arg) { 182254885Sdumbbell case ATOM_ARG_REG: 183254885Sdumbbell idx = U16(*ptr); 184254885Sdumbbell (*ptr) += 2; 185254885Sdumbbell if (print) 186254894Sdumbbell ATOM_DEBUG_PRINT("REG[0x%04X]", idx); 187254885Sdumbbell idx += gctx->reg_block; 188254885Sdumbbell switch (gctx->io_mode) { 189254885Sdumbbell case ATOM_IO_MM: 190254885Sdumbbell val = gctx->card->reg_read(gctx->card, idx); 191254885Sdumbbell break; 192254885Sdumbbell case ATOM_IO_PCI: 193254885Sdumbbell DRM_INFO( 194254885Sdumbbell "PCI registers are not implemented.\n"); 195254885Sdumbbell return 0; 196254885Sdumbbell case ATOM_IO_SYSIO: 197254885Sdumbbell DRM_INFO( 198254885Sdumbbell "SYSIO registers are not implemented.\n"); 199254885Sdumbbell return 0; 200254885Sdumbbell default: 201254885Sdumbbell if (!(gctx->io_mode & 0x80)) { 202254885Sdumbbell DRM_INFO("Bad IO mode.\n"); 203254885Sdumbbell return 0; 204254885Sdumbbell } 205254885Sdumbbell if (!gctx->iio[gctx->io_mode & 0x7F]) { 206254885Sdumbbell DRM_INFO( 207254885Sdumbbell "Undefined indirect IO read method %d.\n", 208254885Sdumbbell gctx->io_mode & 0x7F); 209254885Sdumbbell return 0; 210254885Sdumbbell } 211254885Sdumbbell val = 212254885Sdumbbell atom_iio_execute(gctx, 213254885Sdumbbell gctx->iio[gctx->io_mode & 0x7F], 214254885Sdumbbell idx, 0); 215254885Sdumbbell } 216254885Sdumbbell break; 217254885Sdumbbell case ATOM_ARG_PS: 218254885Sdumbbell idx = U8(*ptr); 219254885Sdumbbell (*ptr)++; 220254885Sdumbbell /* get_unaligned_le32 avoids unaligned accesses from atombios 221254885Sdumbbell * tables, noticed on a DEC Alpha. */ 222254885Sdumbbell val = get_unaligned_le32((u32 *)&ctx->ps[idx]); 223254885Sdumbbell if (print) 224254894Sdumbbell ATOM_DEBUG_PRINT("PS[0x%02X,0x%04X]", idx, val); 225254885Sdumbbell break; 226254885Sdumbbell case ATOM_ARG_WS: 227254885Sdumbbell idx = U8(*ptr); 228254885Sdumbbell (*ptr)++; 229254885Sdumbbell if (print) 230254894Sdumbbell ATOM_DEBUG_PRINT("WS[0x%02X]", idx); 231254885Sdumbbell switch (idx) { 232254885Sdumbbell case ATOM_WS_QUOTIENT: 233254885Sdumbbell val = gctx->divmul[0]; 234254885Sdumbbell break; 235254885Sdumbbell case ATOM_WS_REMAINDER: 236254885Sdumbbell val = gctx->divmul[1]; 237254885Sdumbbell break; 238254885Sdumbbell case ATOM_WS_DATAPTR: 239254885Sdumbbell val = gctx->data_block; 240254885Sdumbbell break; 241254885Sdumbbell case ATOM_WS_SHIFT: 242254885Sdumbbell val = gctx->shift; 243254885Sdumbbell break; 244254885Sdumbbell case ATOM_WS_OR_MASK: 245254885Sdumbbell val = 1 << gctx->shift; 246254885Sdumbbell break; 247254885Sdumbbell case ATOM_WS_AND_MASK: 248254885Sdumbbell val = ~(1 << gctx->shift); 249254885Sdumbbell break; 250254885Sdumbbell case ATOM_WS_FB_WINDOW: 251254885Sdumbbell val = gctx->fb_base; 252254885Sdumbbell break; 253254885Sdumbbell case ATOM_WS_ATTRIBUTES: 254254885Sdumbbell val = gctx->io_attr; 255254885Sdumbbell break; 256254885Sdumbbell case ATOM_WS_REGPTR: 257254885Sdumbbell val = gctx->reg_block; 258254885Sdumbbell break; 259254885Sdumbbell default: 260254885Sdumbbell val = ctx->ws[idx]; 261254885Sdumbbell } 262254885Sdumbbell break; 263254885Sdumbbell case ATOM_ARG_ID: 264254885Sdumbbell idx = U16(*ptr); 265254885Sdumbbell (*ptr) += 2; 266254885Sdumbbell if (print) { 267254885Sdumbbell if (gctx->data_block) 268254894Sdumbbell ATOM_DEBUG_PRINT("ID[0x%04X+%04X]", idx, gctx->data_block); 269254885Sdumbbell else 270254894Sdumbbell ATOM_DEBUG_PRINT("ID[0x%04X]", idx); 271254885Sdumbbell } 272254885Sdumbbell val = U32(idx + gctx->data_block); 273254885Sdumbbell break; 274254885Sdumbbell case ATOM_ARG_FB: 275254885Sdumbbell idx = U8(*ptr); 276254885Sdumbbell (*ptr)++; 277254885Sdumbbell if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) { 278254885Sdumbbell DRM_ERROR("ATOM: fb read beyond scratch region: %d vs. %d\n", 279254885Sdumbbell gctx->fb_base + (idx * 4), gctx->scratch_size_bytes); 280254885Sdumbbell val = 0; 281254885Sdumbbell } else 282254885Sdumbbell val = gctx->scratch[(gctx->fb_base / 4) + idx]; 283254885Sdumbbell if (print) 284254894Sdumbbell ATOM_DEBUG_PRINT("FB[0x%02X]", idx); 285254885Sdumbbell break; 286254885Sdumbbell case ATOM_ARG_IMM: 287254885Sdumbbell switch (align) { 288254885Sdumbbell case ATOM_SRC_DWORD: 289254885Sdumbbell val = U32(*ptr); 290254885Sdumbbell (*ptr) += 4; 291254885Sdumbbell if (print) 292254894Sdumbbell ATOM_DEBUG_PRINT("IMM 0x%08X\n", val); 293254885Sdumbbell return val; 294254885Sdumbbell case ATOM_SRC_WORD0: 295254885Sdumbbell case ATOM_SRC_WORD8: 296254885Sdumbbell case ATOM_SRC_WORD16: 297254885Sdumbbell val = U16(*ptr); 298254885Sdumbbell (*ptr) += 2; 299254885Sdumbbell if (print) 300254894Sdumbbell ATOM_DEBUG_PRINT("IMM 0x%04X\n", val); 301254885Sdumbbell return val; 302254885Sdumbbell case ATOM_SRC_BYTE0: 303254885Sdumbbell case ATOM_SRC_BYTE8: 304254885Sdumbbell case ATOM_SRC_BYTE16: 305254885Sdumbbell case ATOM_SRC_BYTE24: 306254885Sdumbbell val = U8(*ptr); 307254885Sdumbbell (*ptr)++; 308254885Sdumbbell if (print) 309254894Sdumbbell ATOM_DEBUG_PRINT("IMM 0x%02X\n", val); 310254885Sdumbbell return val; 311254885Sdumbbell } 312254885Sdumbbell return 0; 313254885Sdumbbell case ATOM_ARG_PLL: 314254885Sdumbbell idx = U8(*ptr); 315254885Sdumbbell (*ptr)++; 316254885Sdumbbell if (print) 317254894Sdumbbell ATOM_DEBUG_PRINT("PLL[0x%02X]", idx); 318254885Sdumbbell val = gctx->card->pll_read(gctx->card, idx); 319254885Sdumbbell break; 320254885Sdumbbell case ATOM_ARG_MC: 321254885Sdumbbell idx = U8(*ptr); 322254885Sdumbbell (*ptr)++; 323254885Sdumbbell if (print) 324254894Sdumbbell ATOM_DEBUG_PRINT("MC[0x%02X]", idx); 325254885Sdumbbell val = gctx->card->mc_read(gctx->card, idx); 326254885Sdumbbell break; 327254885Sdumbbell } 328254885Sdumbbell if (saved) 329254885Sdumbbell *saved = val; 330254885Sdumbbell val &= atom_arg_mask[align]; 331254885Sdumbbell val >>= atom_arg_shift[align]; 332254885Sdumbbell if (print) 333254885Sdumbbell switch (align) { 334254885Sdumbbell case ATOM_SRC_DWORD: 335254894Sdumbbell ATOM_DEBUG_PRINT(".[31:0] -> 0x%08X\n", val); 336254885Sdumbbell break; 337254885Sdumbbell case ATOM_SRC_WORD0: 338254894Sdumbbell ATOM_DEBUG_PRINT(".[15:0] -> 0x%04X\n", val); 339254885Sdumbbell break; 340254885Sdumbbell case ATOM_SRC_WORD8: 341254894Sdumbbell ATOM_DEBUG_PRINT(".[23:8] -> 0x%04X\n", val); 342254885Sdumbbell break; 343254885Sdumbbell case ATOM_SRC_WORD16: 344254894Sdumbbell ATOM_DEBUG_PRINT(".[31:16] -> 0x%04X\n", val); 345254885Sdumbbell break; 346254885Sdumbbell case ATOM_SRC_BYTE0: 347254894Sdumbbell ATOM_DEBUG_PRINT(".[7:0] -> 0x%02X\n", val); 348254885Sdumbbell break; 349254885Sdumbbell case ATOM_SRC_BYTE8: 350254894Sdumbbell ATOM_DEBUG_PRINT(".[15:8] -> 0x%02X\n", val); 351254885Sdumbbell break; 352254885Sdumbbell case ATOM_SRC_BYTE16: 353254894Sdumbbell ATOM_DEBUG_PRINT(".[23:16] -> 0x%02X\n", val); 354254885Sdumbbell break; 355254885Sdumbbell case ATOM_SRC_BYTE24: 356254894Sdumbbell ATOM_DEBUG_PRINT(".[31:24] -> 0x%02X\n", val); 357254885Sdumbbell break; 358254885Sdumbbell } 359254885Sdumbbell return val; 360254885Sdumbbell} 361254885Sdumbbell 362254885Sdumbbellstatic void atom_skip_src_int(atom_exec_context *ctx, uint8_t attr, int *ptr) 363254885Sdumbbell{ 364254885Sdumbbell uint32_t align = (attr >> 3) & 7, arg = attr & 7; 365254885Sdumbbell switch (arg) { 366254885Sdumbbell case ATOM_ARG_REG: 367254885Sdumbbell case ATOM_ARG_ID: 368254885Sdumbbell (*ptr) += 2; 369254885Sdumbbell break; 370254885Sdumbbell case ATOM_ARG_PLL: 371254885Sdumbbell case ATOM_ARG_MC: 372254885Sdumbbell case ATOM_ARG_PS: 373254885Sdumbbell case ATOM_ARG_WS: 374254885Sdumbbell case ATOM_ARG_FB: 375254885Sdumbbell (*ptr)++; 376254885Sdumbbell break; 377254885Sdumbbell case ATOM_ARG_IMM: 378254885Sdumbbell switch (align) { 379254885Sdumbbell case ATOM_SRC_DWORD: 380254885Sdumbbell (*ptr) += 4; 381254885Sdumbbell return; 382254885Sdumbbell case ATOM_SRC_WORD0: 383254885Sdumbbell case ATOM_SRC_WORD8: 384254885Sdumbbell case ATOM_SRC_WORD16: 385254885Sdumbbell (*ptr) += 2; 386254885Sdumbbell return; 387254885Sdumbbell case ATOM_SRC_BYTE0: 388254885Sdumbbell case ATOM_SRC_BYTE8: 389254885Sdumbbell case ATOM_SRC_BYTE16: 390254885Sdumbbell case ATOM_SRC_BYTE24: 391254885Sdumbbell (*ptr)++; 392254885Sdumbbell return; 393254885Sdumbbell } 394254885Sdumbbell return; 395254885Sdumbbell } 396254885Sdumbbell} 397254885Sdumbbell 398254885Sdumbbellstatic uint32_t atom_get_src(atom_exec_context *ctx, uint8_t attr, int *ptr) 399254885Sdumbbell{ 400254885Sdumbbell return atom_get_src_int(ctx, attr, ptr, NULL, 1); 401254885Sdumbbell} 402254885Sdumbbell 403254885Sdumbbellstatic uint32_t atom_get_src_direct(atom_exec_context *ctx, uint8_t align, int *ptr) 404254885Sdumbbell{ 405254885Sdumbbell uint32_t val = 0xCDCDCDCD; 406254885Sdumbbell 407254885Sdumbbell switch (align) { 408254885Sdumbbell case ATOM_SRC_DWORD: 409254885Sdumbbell val = U32(*ptr); 410254885Sdumbbell (*ptr) += 4; 411254885Sdumbbell break; 412254885Sdumbbell case ATOM_SRC_WORD0: 413254885Sdumbbell case ATOM_SRC_WORD8: 414254885Sdumbbell case ATOM_SRC_WORD16: 415254885Sdumbbell val = U16(*ptr); 416254885Sdumbbell (*ptr) += 2; 417254885Sdumbbell break; 418254885Sdumbbell case ATOM_SRC_BYTE0: 419254885Sdumbbell case ATOM_SRC_BYTE8: 420254885Sdumbbell case ATOM_SRC_BYTE16: 421254885Sdumbbell case ATOM_SRC_BYTE24: 422254885Sdumbbell val = U8(*ptr); 423254885Sdumbbell (*ptr)++; 424254885Sdumbbell break; 425254885Sdumbbell } 426254885Sdumbbell return val; 427254885Sdumbbell} 428254885Sdumbbell 429254885Sdumbbellstatic uint32_t atom_get_dst(atom_exec_context *ctx, int arg, uint8_t attr, 430254885Sdumbbell int *ptr, uint32_t *saved, int print) 431254885Sdumbbell{ 432254885Sdumbbell return atom_get_src_int(ctx, 433254885Sdumbbell arg | atom_dst_to_src[(attr >> 3) & 434254885Sdumbbell 7][(attr >> 6) & 3] << 3, 435254885Sdumbbell ptr, saved, print); 436254885Sdumbbell} 437254885Sdumbbell 438254885Sdumbbellstatic void atom_skip_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr) 439254885Sdumbbell{ 440254885Sdumbbell atom_skip_src_int(ctx, 441254885Sdumbbell arg | atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 442254885Sdumbbell 3] << 3, ptr); 443254885Sdumbbell} 444254885Sdumbbell 445254885Sdumbbellstatic void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr, 446254885Sdumbbell int *ptr, uint32_t val, uint32_t saved) 447254885Sdumbbell{ 448254885Sdumbbell uint32_t align = 449254885Sdumbbell atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3], old_val = 450254885Sdumbbell val, idx; 451254885Sdumbbell struct atom_context *gctx = ctx->ctx; 452254885Sdumbbell old_val &= atom_arg_mask[align] >> atom_arg_shift[align]; 453254885Sdumbbell val <<= atom_arg_shift[align]; 454254885Sdumbbell val &= atom_arg_mask[align]; 455254885Sdumbbell saved &= ~atom_arg_mask[align]; 456254885Sdumbbell val |= saved; 457254885Sdumbbell switch (arg) { 458254885Sdumbbell case ATOM_ARG_REG: 459254885Sdumbbell idx = U16(*ptr); 460254885Sdumbbell (*ptr) += 2; 461254894Sdumbbell ATOM_DEBUG_PRINT("REG[0x%04X]", idx); 462254885Sdumbbell idx += gctx->reg_block; 463254885Sdumbbell switch (gctx->io_mode) { 464254885Sdumbbell case ATOM_IO_MM: 465254885Sdumbbell if (idx == 0) 466254885Sdumbbell gctx->card->reg_write(gctx->card, idx, 467254885Sdumbbell val << 2); 468254885Sdumbbell else 469254885Sdumbbell gctx->card->reg_write(gctx->card, idx, val); 470254885Sdumbbell break; 471254885Sdumbbell case ATOM_IO_PCI: 472254885Sdumbbell DRM_INFO( 473254885Sdumbbell "PCI registers are not implemented.\n"); 474254885Sdumbbell return; 475254885Sdumbbell case ATOM_IO_SYSIO: 476254885Sdumbbell DRM_INFO( 477254885Sdumbbell "SYSIO registers are not implemented.\n"); 478254885Sdumbbell return; 479254885Sdumbbell default: 480254885Sdumbbell if (!(gctx->io_mode & 0x80)) { 481254885Sdumbbell DRM_INFO("Bad IO mode.\n"); 482254885Sdumbbell return; 483254885Sdumbbell } 484254885Sdumbbell if (!gctx->iio[gctx->io_mode & 0xFF]) { 485254885Sdumbbell DRM_INFO( 486254885Sdumbbell "Undefined indirect IO write method %d.\n", 487254885Sdumbbell gctx->io_mode & 0x7F); 488254885Sdumbbell return; 489254885Sdumbbell } 490254885Sdumbbell atom_iio_execute(gctx, gctx->iio[gctx->io_mode & 0xFF], 491254885Sdumbbell idx, val); 492254885Sdumbbell } 493254885Sdumbbell break; 494254885Sdumbbell case ATOM_ARG_PS: 495254885Sdumbbell idx = U8(*ptr); 496254885Sdumbbell (*ptr)++; 497254894Sdumbbell ATOM_DEBUG_PRINT("PS[0x%02X]", idx); 498254885Sdumbbell ctx->ps[idx] = cpu_to_le32(val); 499254885Sdumbbell break; 500254885Sdumbbell case ATOM_ARG_WS: 501254885Sdumbbell idx = U8(*ptr); 502254885Sdumbbell (*ptr)++; 503254894Sdumbbell ATOM_DEBUG_PRINT("WS[0x%02X]", idx); 504254885Sdumbbell switch (idx) { 505254885Sdumbbell case ATOM_WS_QUOTIENT: 506254885Sdumbbell gctx->divmul[0] = val; 507254885Sdumbbell break; 508254885Sdumbbell case ATOM_WS_REMAINDER: 509254885Sdumbbell gctx->divmul[1] = val; 510254885Sdumbbell break; 511254885Sdumbbell case ATOM_WS_DATAPTR: 512254885Sdumbbell gctx->data_block = val; 513254885Sdumbbell break; 514254885Sdumbbell case ATOM_WS_SHIFT: 515254885Sdumbbell gctx->shift = val; 516254885Sdumbbell break; 517254885Sdumbbell case ATOM_WS_OR_MASK: 518254885Sdumbbell case ATOM_WS_AND_MASK: 519254885Sdumbbell break; 520254885Sdumbbell case ATOM_WS_FB_WINDOW: 521254885Sdumbbell gctx->fb_base = val; 522254885Sdumbbell break; 523254885Sdumbbell case ATOM_WS_ATTRIBUTES: 524254885Sdumbbell gctx->io_attr = val; 525254885Sdumbbell break; 526254885Sdumbbell case ATOM_WS_REGPTR: 527254885Sdumbbell gctx->reg_block = val; 528254885Sdumbbell break; 529254885Sdumbbell default: 530254885Sdumbbell ctx->ws[idx] = val; 531254885Sdumbbell } 532254885Sdumbbell break; 533254885Sdumbbell case ATOM_ARG_FB: 534254885Sdumbbell idx = U8(*ptr); 535254885Sdumbbell (*ptr)++; 536254885Sdumbbell if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) { 537254885Sdumbbell DRM_ERROR("ATOM: fb write beyond scratch region: %d vs. %d\n", 538254885Sdumbbell gctx->fb_base + (idx * 4), gctx->scratch_size_bytes); 539254885Sdumbbell } else 540254885Sdumbbell gctx->scratch[(gctx->fb_base / 4) + idx] = val; 541254894Sdumbbell ATOM_DEBUG_PRINT("FB[0x%02X]", idx); 542254885Sdumbbell break; 543254885Sdumbbell case ATOM_ARG_PLL: 544254885Sdumbbell idx = U8(*ptr); 545254885Sdumbbell (*ptr)++; 546254894Sdumbbell ATOM_DEBUG_PRINT("PLL[0x%02X]", idx); 547254885Sdumbbell gctx->card->pll_write(gctx->card, idx, val); 548254885Sdumbbell break; 549254885Sdumbbell case ATOM_ARG_MC: 550254885Sdumbbell idx = U8(*ptr); 551254885Sdumbbell (*ptr)++; 552254894Sdumbbell ATOM_DEBUG_PRINT("MC[0x%02X]", idx); 553254885Sdumbbell gctx->card->mc_write(gctx->card, idx, val); 554254885Sdumbbell return; 555254885Sdumbbell } 556254885Sdumbbell switch (align) { 557254885Sdumbbell case ATOM_SRC_DWORD: 558254894Sdumbbell ATOM_DEBUG_PRINT(".[31:0] <- 0x%08X\n", old_val); 559254885Sdumbbell break; 560254885Sdumbbell case ATOM_SRC_WORD0: 561254894Sdumbbell ATOM_DEBUG_PRINT(".[15:0] <- 0x%04X\n", old_val); 562254885Sdumbbell break; 563254885Sdumbbell case ATOM_SRC_WORD8: 564254894Sdumbbell ATOM_DEBUG_PRINT(".[23:8] <- 0x%04X\n", old_val); 565254885Sdumbbell break; 566254885Sdumbbell case ATOM_SRC_WORD16: 567254894Sdumbbell ATOM_DEBUG_PRINT(".[31:16] <- 0x%04X\n", old_val); 568254885Sdumbbell break; 569254885Sdumbbell case ATOM_SRC_BYTE0: 570254894Sdumbbell ATOM_DEBUG_PRINT(".[7:0] <- 0x%02X\n", old_val); 571254885Sdumbbell break; 572254885Sdumbbell case ATOM_SRC_BYTE8: 573254894Sdumbbell ATOM_DEBUG_PRINT(".[15:8] <- 0x%02X\n", old_val); 574254885Sdumbbell break; 575254885Sdumbbell case ATOM_SRC_BYTE16: 576254894Sdumbbell ATOM_DEBUG_PRINT(".[23:16] <- 0x%02X\n", old_val); 577254885Sdumbbell break; 578254885Sdumbbell case ATOM_SRC_BYTE24: 579254894Sdumbbell ATOM_DEBUG_PRINT(".[31:24] <- 0x%02X\n", old_val); 580254885Sdumbbell break; 581254885Sdumbbell } 582254885Sdumbbell} 583254885Sdumbbell 584254885Sdumbbellstatic void atom_op_add(atom_exec_context *ctx, int *ptr, int arg) 585254885Sdumbbell{ 586254885Sdumbbell uint8_t attr = U8((*ptr)++); 587254885Sdumbbell uint32_t dst, src, saved; 588254885Sdumbbell int dptr = *ptr; 589254894Sdumbbell ATOM_SDEBUG_PRINT(" dst: "); 590254885Sdumbbell dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 591254894Sdumbbell ATOM_SDEBUG_PRINT(" src: "); 592254885Sdumbbell src = atom_get_src(ctx, attr, ptr); 593254885Sdumbbell dst += src; 594254894Sdumbbell ATOM_SDEBUG_PRINT(" dst: "); 595254885Sdumbbell atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 596254885Sdumbbell} 597254885Sdumbbell 598254885Sdumbbellstatic void atom_op_and(atom_exec_context *ctx, int *ptr, int arg) 599254885Sdumbbell{ 600254885Sdumbbell uint8_t attr = U8((*ptr)++); 601254885Sdumbbell uint32_t dst, src, saved; 602254885Sdumbbell int dptr = *ptr; 603254894Sdumbbell ATOM_SDEBUG_PRINT(" dst: "); 604254885Sdumbbell dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 605254894Sdumbbell ATOM_SDEBUG_PRINT(" src: "); 606254885Sdumbbell src = atom_get_src(ctx, attr, ptr); 607254885Sdumbbell dst &= src; 608254894Sdumbbell ATOM_SDEBUG_PRINT(" dst: "); 609254885Sdumbbell atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 610254885Sdumbbell} 611254885Sdumbbell 612254885Sdumbbellstatic void atom_op_beep(atom_exec_context *ctx, int *ptr, int arg) 613254885Sdumbbell{ 614254885Sdumbbell DRM_INFO("ATOM BIOS beeped!\n"); 615254885Sdumbbell} 616254885Sdumbbell 617254885Sdumbbellstatic void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg) 618254885Sdumbbell{ 619254885Sdumbbell int idx = U8((*ptr)++); 620254885Sdumbbell int r = 0; 621254885Sdumbbell 622254885Sdumbbell if (idx < ATOM_TABLE_NAMES_CNT) 623254894Sdumbbell ATOM_SDEBUG_PRINT(" table: %d (%s)\n", idx, atom_table_names[idx]); 624254885Sdumbbell else 625254894Sdumbbell ATOM_SDEBUG_PRINT(" table: %d\n", idx); 626254885Sdumbbell if (U16(ctx->ctx->cmd_table + 4 + 2 * idx)) 627254885Sdumbbell r = atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift); 628254885Sdumbbell if (r) { 629254885Sdumbbell ctx->abort = true; 630254885Sdumbbell } 631254885Sdumbbell} 632254885Sdumbbell 633254885Sdumbbellstatic void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg) 634254885Sdumbbell{ 635254885Sdumbbell uint8_t attr = U8((*ptr)++); 636254885Sdumbbell uint32_t saved; 637254885Sdumbbell int dptr = *ptr; 638254885Sdumbbell attr &= 0x38; 639254885Sdumbbell attr |= atom_def_dst[attr >> 3] << 6; 640254885Sdumbbell atom_get_dst(ctx, arg, attr, ptr, &saved, 0); 641254894Sdumbbell ATOM_SDEBUG_PRINT(" dst: "); 642254885Sdumbbell atom_put_dst(ctx, arg, attr, &dptr, 0, saved); 643254885Sdumbbell} 644254885Sdumbbell 645254885Sdumbbellstatic void atom_op_compare(atom_exec_context *ctx, int *ptr, int arg) 646254885Sdumbbell{ 647254885Sdumbbell uint8_t attr = U8((*ptr)++); 648254885Sdumbbell uint32_t dst, src; 649254894Sdumbbell ATOM_SDEBUG_PRINT(" src1: "); 650254885Sdumbbell dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); 651254894Sdumbbell ATOM_SDEBUG_PRINT(" src2: "); 652254885Sdumbbell src = atom_get_src(ctx, attr, ptr); 653254885Sdumbbell ctx->ctx->cs_equal = (dst == src); 654254885Sdumbbell ctx->ctx->cs_above = (dst > src); 655254894Sdumbbell ATOM_SDEBUG_PRINT(" result: %s %s\n", ctx->ctx->cs_equal ? "EQ" : "NE", 656254885Sdumbbell ctx->ctx->cs_above ? "GT" : "LE"); 657254885Sdumbbell} 658254885Sdumbbell 659254885Sdumbbellstatic void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg) 660254885Sdumbbell{ 661254885Sdumbbell unsigned count = U8((*ptr)++); 662254894Sdumbbell ATOM_SDEBUG_PRINT(" count: %d\n", count); 663254885Sdumbbell if (arg == ATOM_UNIT_MICROSEC) 664254885Sdumbbell DRM_UDELAY(count); 665254885Sdumbbell else if (!drm_can_sleep()) 666254885Sdumbbell DRM_MDELAY(count); 667254885Sdumbbell else 668254885Sdumbbell DRM_MSLEEP(count); 669254885Sdumbbell} 670254885Sdumbbell 671254885Sdumbbellstatic void atom_op_div(atom_exec_context *ctx, int *ptr, int arg) 672254885Sdumbbell{ 673254885Sdumbbell uint8_t attr = U8((*ptr)++); 674254885Sdumbbell uint32_t dst, src; 675254894Sdumbbell ATOM_SDEBUG_PRINT(" src1: "); 676254885Sdumbbell dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); 677254894Sdumbbell ATOM_SDEBUG_PRINT(" src2: "); 678254885Sdumbbell src = atom_get_src(ctx, attr, ptr); 679254885Sdumbbell if (src != 0) { 680254885Sdumbbell ctx->ctx->divmul[0] = dst / src; 681254885Sdumbbell ctx->ctx->divmul[1] = dst % src; 682254885Sdumbbell } else { 683254885Sdumbbell ctx->ctx->divmul[0] = 0; 684254885Sdumbbell ctx->ctx->divmul[1] = 0; 685254885Sdumbbell } 686254885Sdumbbell} 687254885Sdumbbell 688254885Sdumbbellstatic void atom_op_eot(atom_exec_context *ctx, int *ptr, int arg) 689254885Sdumbbell{ 690254885Sdumbbell /* functionally, a nop */ 691254885Sdumbbell} 692254885Sdumbbell 693254885Sdumbbellstatic void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg) 694254885Sdumbbell{ 695254885Sdumbbell int execute = 0, target = U16(*ptr); 696254885Sdumbbell unsigned long cjiffies; 697254885Sdumbbell 698254885Sdumbbell (*ptr) += 2; 699254885Sdumbbell switch (arg) { 700254885Sdumbbell case ATOM_COND_ABOVE: 701254885Sdumbbell execute = ctx->ctx->cs_above; 702254885Sdumbbell break; 703254885Sdumbbell case ATOM_COND_ABOVEOREQUAL: 704254885Sdumbbell execute = ctx->ctx->cs_above || ctx->ctx->cs_equal; 705254885Sdumbbell break; 706254885Sdumbbell case ATOM_COND_ALWAYS: 707254885Sdumbbell execute = 1; 708254885Sdumbbell break; 709254885Sdumbbell case ATOM_COND_BELOW: 710254885Sdumbbell execute = !(ctx->ctx->cs_above || ctx->ctx->cs_equal); 711254885Sdumbbell break; 712254885Sdumbbell case ATOM_COND_BELOWOREQUAL: 713254885Sdumbbell execute = !ctx->ctx->cs_above; 714254885Sdumbbell break; 715254885Sdumbbell case ATOM_COND_EQUAL: 716254885Sdumbbell execute = ctx->ctx->cs_equal; 717254885Sdumbbell break; 718254885Sdumbbell case ATOM_COND_NOTEQUAL: 719254885Sdumbbell execute = !ctx->ctx->cs_equal; 720254885Sdumbbell break; 721254885Sdumbbell } 722254885Sdumbbell if (arg != ATOM_COND_ALWAYS) 723254894Sdumbbell ATOM_SDEBUG_PRINT(" taken: %s\n", execute ? "yes" : "no"); 724254894Sdumbbell ATOM_SDEBUG_PRINT(" target: 0x%04X\n", target); 725254885Sdumbbell if (execute) { 726254885Sdumbbell if (ctx->last_jump == (ctx->start + target)) { 727254885Sdumbbell cjiffies = jiffies; 728254885Sdumbbell if (time_after(cjiffies, ctx->last_jump_jiffies)) { 729254885Sdumbbell cjiffies -= ctx->last_jump_jiffies; 730254885Sdumbbell if ((jiffies_to_msecs(cjiffies) > 5000)) { 731254885Sdumbbell DRM_ERROR("atombios stuck in loop for more than 5secs aborting\n"); 732254885Sdumbbell ctx->abort = true; 733254885Sdumbbell } 734254885Sdumbbell } else { 735254885Sdumbbell /* jiffies wrap around we will just wait a little longer */ 736254885Sdumbbell ctx->last_jump_jiffies = jiffies; 737254885Sdumbbell } 738254885Sdumbbell } else { 739254885Sdumbbell ctx->last_jump = ctx->start + target; 740254885Sdumbbell ctx->last_jump_jiffies = jiffies; 741254885Sdumbbell } 742254885Sdumbbell *ptr = ctx->start + target; 743254885Sdumbbell } 744254885Sdumbbell} 745254885Sdumbbell 746254885Sdumbbellstatic void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg) 747254885Sdumbbell{ 748254885Sdumbbell uint8_t attr = U8((*ptr)++); 749254885Sdumbbell uint32_t dst, mask, src, saved; 750254885Sdumbbell int dptr = *ptr; 751254894Sdumbbell ATOM_SDEBUG_PRINT(" dst: "); 752254885Sdumbbell dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 753254885Sdumbbell mask = atom_get_src_direct(ctx, ((attr >> 3) & 7), ptr); 754254894Sdumbbell ATOM_SDEBUG_PRINT(" mask: 0x%08x", mask); 755254894Sdumbbell ATOM_SDEBUG_PRINT(" src: "); 756254885Sdumbbell src = atom_get_src(ctx, attr, ptr); 757254885Sdumbbell dst &= mask; 758254885Sdumbbell dst |= src; 759254894Sdumbbell ATOM_SDEBUG_PRINT(" dst: "); 760254885Sdumbbell atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 761254885Sdumbbell} 762254885Sdumbbell 763254885Sdumbbellstatic void atom_op_move(atom_exec_context *ctx, int *ptr, int arg) 764254885Sdumbbell{ 765254885Sdumbbell uint8_t attr = U8((*ptr)++); 766254885Sdumbbell uint32_t src, saved; 767254885Sdumbbell int dptr = *ptr; 768254885Sdumbbell if (((attr >> 3) & 7) != ATOM_SRC_DWORD) 769254885Sdumbbell atom_get_dst(ctx, arg, attr, ptr, &saved, 0); 770254885Sdumbbell else { 771254885Sdumbbell atom_skip_dst(ctx, arg, attr, ptr); 772254885Sdumbbell saved = 0xCDCDCDCD; 773254885Sdumbbell } 774254894Sdumbbell ATOM_SDEBUG_PRINT(" src: "); 775254885Sdumbbell src = atom_get_src(ctx, attr, ptr); 776254894Sdumbbell ATOM_SDEBUG_PRINT(" dst: "); 777254885Sdumbbell atom_put_dst(ctx, arg, attr, &dptr, src, saved); 778254885Sdumbbell} 779254885Sdumbbell 780254885Sdumbbellstatic void atom_op_mul(atom_exec_context *ctx, int *ptr, int arg) 781254885Sdumbbell{ 782254885Sdumbbell uint8_t attr = U8((*ptr)++); 783254885Sdumbbell uint32_t dst, src; 784254894Sdumbbell ATOM_SDEBUG_PRINT(" src1: "); 785254885Sdumbbell dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); 786254894Sdumbbell ATOM_SDEBUG_PRINT(" src2: "); 787254885Sdumbbell src = atom_get_src(ctx, attr, ptr); 788254885Sdumbbell ctx->ctx->divmul[0] = dst * src; 789254885Sdumbbell} 790254885Sdumbbell 791254885Sdumbbellstatic void atom_op_nop(atom_exec_context *ctx, int *ptr, int arg) 792254885Sdumbbell{ 793254885Sdumbbell /* nothing */ 794254885Sdumbbell} 795254885Sdumbbell 796254885Sdumbbellstatic void atom_op_or(atom_exec_context *ctx, int *ptr, int arg) 797254885Sdumbbell{ 798254885Sdumbbell uint8_t attr = U8((*ptr)++); 799254885Sdumbbell uint32_t dst, src, saved; 800254885Sdumbbell int dptr = *ptr; 801254894Sdumbbell ATOM_SDEBUG_PRINT(" dst: "); 802254885Sdumbbell dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 803254894Sdumbbell ATOM_SDEBUG_PRINT(" src: "); 804254885Sdumbbell src = atom_get_src(ctx, attr, ptr); 805254885Sdumbbell dst |= src; 806254894Sdumbbell ATOM_SDEBUG_PRINT(" dst: "); 807254885Sdumbbell atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 808254885Sdumbbell} 809254885Sdumbbell 810254885Sdumbbellstatic void atom_op_postcard(atom_exec_context *ctx, int *ptr, int arg) 811254885Sdumbbell{ 812254885Sdumbbell uint8_t val = U8((*ptr)++); 813254894Sdumbbell ATOM_SDEBUG_PRINT("POST card output: 0x%02X\n", val); 814254885Sdumbbell} 815254885Sdumbbell 816254885Sdumbbellstatic void atom_op_repeat(atom_exec_context *ctx, int *ptr, int arg) 817254885Sdumbbell{ 818254885Sdumbbell DRM_INFO("unimplemented!\n"); 819254885Sdumbbell} 820254885Sdumbbell 821254885Sdumbbellstatic void atom_op_restorereg(atom_exec_context *ctx, int *ptr, int arg) 822254885Sdumbbell{ 823254885Sdumbbell DRM_INFO("unimplemented!\n"); 824254885Sdumbbell} 825254885Sdumbbell 826254885Sdumbbellstatic void atom_op_savereg(atom_exec_context *ctx, int *ptr, int arg) 827254885Sdumbbell{ 828254885Sdumbbell DRM_INFO("unimplemented!\n"); 829254885Sdumbbell} 830254885Sdumbbell 831254885Sdumbbellstatic void atom_op_setdatablock(atom_exec_context *ctx, int *ptr, int arg) 832254885Sdumbbell{ 833254885Sdumbbell int idx = U8(*ptr); 834254885Sdumbbell (*ptr)++; 835254894Sdumbbell ATOM_SDEBUG_PRINT(" block: %d\n", idx); 836254885Sdumbbell if (!idx) 837254885Sdumbbell ctx->ctx->data_block = 0; 838254885Sdumbbell else if (idx == 255) 839254885Sdumbbell ctx->ctx->data_block = ctx->start; 840254885Sdumbbell else 841254885Sdumbbell ctx->ctx->data_block = U16(ctx->ctx->data_table + 4 + 2 * idx); 842254894Sdumbbell ATOM_SDEBUG_PRINT(" base: 0x%04X\n", ctx->ctx->data_block); 843254885Sdumbbell} 844254885Sdumbbell 845254885Sdumbbellstatic void atom_op_setfbbase(atom_exec_context *ctx, int *ptr, int arg) 846254885Sdumbbell{ 847254885Sdumbbell uint8_t attr = U8((*ptr)++); 848254894Sdumbbell ATOM_SDEBUG_PRINT(" fb_base: "); 849254885Sdumbbell ctx->ctx->fb_base = atom_get_src(ctx, attr, ptr); 850254885Sdumbbell} 851254885Sdumbbell 852254885Sdumbbellstatic void atom_op_setport(atom_exec_context *ctx, int *ptr, int arg) 853254885Sdumbbell{ 854254885Sdumbbell int port; 855254885Sdumbbell switch (arg) { 856254885Sdumbbell case ATOM_PORT_ATI: 857254885Sdumbbell port = U16(*ptr); 858254885Sdumbbell if (port < ATOM_IO_NAMES_CNT) 859254894Sdumbbell ATOM_SDEBUG_PRINT(" port: %d (%s)\n", port, atom_io_names[port]); 860254885Sdumbbell else 861254894Sdumbbell ATOM_SDEBUG_PRINT(" port: %d\n", port); 862254885Sdumbbell if (!port) 863254885Sdumbbell ctx->ctx->io_mode = ATOM_IO_MM; 864254885Sdumbbell else 865254885Sdumbbell ctx->ctx->io_mode = ATOM_IO_IIO | port; 866254885Sdumbbell (*ptr) += 2; 867254885Sdumbbell break; 868254885Sdumbbell case ATOM_PORT_PCI: 869254885Sdumbbell ctx->ctx->io_mode = ATOM_IO_PCI; 870254885Sdumbbell (*ptr)++; 871254885Sdumbbell break; 872254885Sdumbbell case ATOM_PORT_SYSIO: 873254885Sdumbbell ctx->ctx->io_mode = ATOM_IO_SYSIO; 874254885Sdumbbell (*ptr)++; 875254885Sdumbbell break; 876254885Sdumbbell } 877254885Sdumbbell} 878254885Sdumbbell 879254885Sdumbbellstatic void atom_op_setregblock(atom_exec_context *ctx, int *ptr, int arg) 880254885Sdumbbell{ 881254885Sdumbbell ctx->ctx->reg_block = U16(*ptr); 882254885Sdumbbell (*ptr) += 2; 883254894Sdumbbell ATOM_SDEBUG_PRINT(" base: 0x%04X\n", ctx->ctx->reg_block); 884254885Sdumbbell} 885254885Sdumbbell 886254885Sdumbbellstatic void atom_op_shift_left(atom_exec_context *ctx, int *ptr, int arg) 887254885Sdumbbell{ 888254885Sdumbbell uint8_t attr = U8((*ptr)++), shift; 889254885Sdumbbell uint32_t saved, dst; 890254885Sdumbbell int dptr = *ptr; 891254885Sdumbbell attr &= 0x38; 892254885Sdumbbell attr |= atom_def_dst[attr >> 3] << 6; 893254894Sdumbbell ATOM_SDEBUG_PRINT(" dst: "); 894254885Sdumbbell dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 895254885Sdumbbell shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr); 896254894Sdumbbell ATOM_SDEBUG_PRINT(" shift: %d\n", shift); 897254885Sdumbbell dst <<= shift; 898254894Sdumbbell ATOM_SDEBUG_PRINT(" dst: "); 899254885Sdumbbell atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 900254885Sdumbbell} 901254885Sdumbbell 902254885Sdumbbellstatic void atom_op_shift_right(atom_exec_context *ctx, int *ptr, int arg) 903254885Sdumbbell{ 904254885Sdumbbell uint8_t attr = U8((*ptr)++), shift; 905254885Sdumbbell uint32_t saved, dst; 906254885Sdumbbell int dptr = *ptr; 907254885Sdumbbell attr &= 0x38; 908254885Sdumbbell attr |= atom_def_dst[attr >> 3] << 6; 909254894Sdumbbell ATOM_SDEBUG_PRINT(" dst: "); 910254885Sdumbbell dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 911254885Sdumbbell shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr); 912254894Sdumbbell ATOM_SDEBUG_PRINT(" shift: %d\n", shift); 913254885Sdumbbell dst >>= shift; 914254894Sdumbbell ATOM_SDEBUG_PRINT(" dst: "); 915254885Sdumbbell atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 916254885Sdumbbell} 917254885Sdumbbell 918254885Sdumbbellstatic void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg) 919254885Sdumbbell{ 920254885Sdumbbell uint8_t attr = U8((*ptr)++), shift; 921254885Sdumbbell uint32_t saved, dst; 922254885Sdumbbell int dptr = *ptr; 923254885Sdumbbell uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3]; 924254894Sdumbbell ATOM_SDEBUG_PRINT(" dst: "); 925254885Sdumbbell dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 926254885Sdumbbell /* op needs to full dst value */ 927254885Sdumbbell dst = saved; 928254885Sdumbbell shift = atom_get_src(ctx, attr, ptr); 929254894Sdumbbell ATOM_SDEBUG_PRINT(" shift: %d\n", shift); 930254885Sdumbbell dst <<= shift; 931254885Sdumbbell dst &= atom_arg_mask[dst_align]; 932254885Sdumbbell dst >>= atom_arg_shift[dst_align]; 933254894Sdumbbell ATOM_SDEBUG_PRINT(" dst: "); 934254885Sdumbbell atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 935254885Sdumbbell} 936254885Sdumbbell 937254885Sdumbbellstatic void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg) 938254885Sdumbbell{ 939254885Sdumbbell uint8_t attr = U8((*ptr)++), shift; 940254885Sdumbbell uint32_t saved, dst; 941254885Sdumbbell int dptr = *ptr; 942254885Sdumbbell uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3]; 943254894Sdumbbell ATOM_SDEBUG_PRINT(" dst: "); 944254885Sdumbbell dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 945254885Sdumbbell /* op needs to full dst value */ 946254885Sdumbbell dst = saved; 947254885Sdumbbell shift = atom_get_src(ctx, attr, ptr); 948254894Sdumbbell ATOM_SDEBUG_PRINT(" shift: %d\n", shift); 949254885Sdumbbell dst >>= shift; 950254885Sdumbbell dst &= atom_arg_mask[dst_align]; 951254885Sdumbbell dst >>= atom_arg_shift[dst_align]; 952254894Sdumbbell ATOM_SDEBUG_PRINT(" dst: "); 953254885Sdumbbell atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 954254885Sdumbbell} 955254885Sdumbbell 956254885Sdumbbellstatic void atom_op_sub(atom_exec_context *ctx, int *ptr, int arg) 957254885Sdumbbell{ 958254885Sdumbbell uint8_t attr = U8((*ptr)++); 959254885Sdumbbell uint32_t dst, src, saved; 960254885Sdumbbell int dptr = *ptr; 961254894Sdumbbell ATOM_SDEBUG_PRINT(" dst: "); 962254885Sdumbbell dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 963254894Sdumbbell ATOM_SDEBUG_PRINT(" src: "); 964254885Sdumbbell src = atom_get_src(ctx, attr, ptr); 965254885Sdumbbell dst -= src; 966254894Sdumbbell ATOM_SDEBUG_PRINT(" dst: "); 967254885Sdumbbell atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 968254885Sdumbbell} 969254885Sdumbbell 970254885Sdumbbellstatic void atom_op_switch(atom_exec_context *ctx, int *ptr, int arg) 971254885Sdumbbell{ 972254885Sdumbbell uint8_t attr = U8((*ptr)++); 973254885Sdumbbell uint32_t src, val, target; 974254894Sdumbbell ATOM_SDEBUG_PRINT(" switch: "); 975254885Sdumbbell src = atom_get_src(ctx, attr, ptr); 976254885Sdumbbell while (U16(*ptr) != ATOM_CASE_END) 977254885Sdumbbell if (U8(*ptr) == ATOM_CASE_MAGIC) { 978254885Sdumbbell (*ptr)++; 979254894Sdumbbell ATOM_SDEBUG_PRINT(" case: "); 980254885Sdumbbell val = 981254885Sdumbbell atom_get_src(ctx, (attr & 0x38) | ATOM_ARG_IMM, 982254885Sdumbbell ptr); 983254885Sdumbbell target = U16(*ptr); 984254885Sdumbbell if (val == src) { 985254894Sdumbbell ATOM_SDEBUG_PRINT(" target: %04X\n", target); 986254885Sdumbbell *ptr = ctx->start + target; 987254885Sdumbbell return; 988254885Sdumbbell } 989254885Sdumbbell (*ptr) += 2; 990254885Sdumbbell } else { 991254885Sdumbbell DRM_INFO("Bad case.\n"); 992254885Sdumbbell return; 993254885Sdumbbell } 994254885Sdumbbell (*ptr) += 2; 995254885Sdumbbell} 996254885Sdumbbell 997254885Sdumbbellstatic void atom_op_test(atom_exec_context *ctx, int *ptr, int arg) 998254885Sdumbbell{ 999254885Sdumbbell uint8_t attr = U8((*ptr)++); 1000254885Sdumbbell uint32_t dst, src; 1001254894Sdumbbell ATOM_SDEBUG_PRINT(" src1: "); 1002254885Sdumbbell dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); 1003254894Sdumbbell ATOM_SDEBUG_PRINT(" src2: "); 1004254885Sdumbbell src = atom_get_src(ctx, attr, ptr); 1005254885Sdumbbell ctx->ctx->cs_equal = ((dst & src) == 0); 1006254894Sdumbbell ATOM_SDEBUG_PRINT(" result: %s\n", ctx->ctx->cs_equal ? "EQ" : "NE"); 1007254885Sdumbbell} 1008254885Sdumbbell 1009254885Sdumbbellstatic void atom_op_xor(atom_exec_context *ctx, int *ptr, int arg) 1010254885Sdumbbell{ 1011254885Sdumbbell uint8_t attr = U8((*ptr)++); 1012254885Sdumbbell uint32_t dst, src, saved; 1013254885Sdumbbell int dptr = *ptr; 1014254894Sdumbbell ATOM_SDEBUG_PRINT(" dst: "); 1015254885Sdumbbell dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 1016254894Sdumbbell ATOM_SDEBUG_PRINT(" src: "); 1017254885Sdumbbell src = atom_get_src(ctx, attr, ptr); 1018254885Sdumbbell dst ^= src; 1019254894Sdumbbell ATOM_SDEBUG_PRINT(" dst: "); 1020254885Sdumbbell atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 1021254885Sdumbbell} 1022254885Sdumbbell 1023254885Sdumbbellstatic void atom_op_debug(atom_exec_context *ctx, int *ptr, int arg) 1024254885Sdumbbell{ 1025254885Sdumbbell DRM_INFO("unimplemented!\n"); 1026254885Sdumbbell} 1027254885Sdumbbell 1028254885Sdumbbellstatic struct { 1029254885Sdumbbell void (*func) (atom_exec_context *, int *, int); 1030254885Sdumbbell int arg; 1031254885Sdumbbell} opcode_table[ATOM_OP_CNT] = { 1032254885Sdumbbell { 1033254885Sdumbbell NULL, 0}, { 1034254885Sdumbbell atom_op_move, ATOM_ARG_REG}, { 1035254885Sdumbbell atom_op_move, ATOM_ARG_PS}, { 1036254885Sdumbbell atom_op_move, ATOM_ARG_WS}, { 1037254885Sdumbbell atom_op_move, ATOM_ARG_FB}, { 1038254885Sdumbbell atom_op_move, ATOM_ARG_PLL}, { 1039254885Sdumbbell atom_op_move, ATOM_ARG_MC}, { 1040254885Sdumbbell atom_op_and, ATOM_ARG_REG}, { 1041254885Sdumbbell atom_op_and, ATOM_ARG_PS}, { 1042254885Sdumbbell atom_op_and, ATOM_ARG_WS}, { 1043254885Sdumbbell atom_op_and, ATOM_ARG_FB}, { 1044254885Sdumbbell atom_op_and, ATOM_ARG_PLL}, { 1045254885Sdumbbell atom_op_and, ATOM_ARG_MC}, { 1046254885Sdumbbell atom_op_or, ATOM_ARG_REG}, { 1047254885Sdumbbell atom_op_or, ATOM_ARG_PS}, { 1048254885Sdumbbell atom_op_or, ATOM_ARG_WS}, { 1049254885Sdumbbell atom_op_or, ATOM_ARG_FB}, { 1050254885Sdumbbell atom_op_or, ATOM_ARG_PLL}, { 1051254885Sdumbbell atom_op_or, ATOM_ARG_MC}, { 1052254885Sdumbbell atom_op_shift_left, ATOM_ARG_REG}, { 1053254885Sdumbbell atom_op_shift_left, ATOM_ARG_PS}, { 1054254885Sdumbbell atom_op_shift_left, ATOM_ARG_WS}, { 1055254885Sdumbbell atom_op_shift_left, ATOM_ARG_FB}, { 1056254885Sdumbbell atom_op_shift_left, ATOM_ARG_PLL}, { 1057254885Sdumbbell atom_op_shift_left, ATOM_ARG_MC}, { 1058254885Sdumbbell atom_op_shift_right, ATOM_ARG_REG}, { 1059254885Sdumbbell atom_op_shift_right, ATOM_ARG_PS}, { 1060254885Sdumbbell atom_op_shift_right, ATOM_ARG_WS}, { 1061254885Sdumbbell atom_op_shift_right, ATOM_ARG_FB}, { 1062254885Sdumbbell atom_op_shift_right, ATOM_ARG_PLL}, { 1063254885Sdumbbell atom_op_shift_right, ATOM_ARG_MC}, { 1064254885Sdumbbell atom_op_mul, ATOM_ARG_REG}, { 1065254885Sdumbbell atom_op_mul, ATOM_ARG_PS}, { 1066254885Sdumbbell atom_op_mul, ATOM_ARG_WS}, { 1067254885Sdumbbell atom_op_mul, ATOM_ARG_FB}, { 1068254885Sdumbbell atom_op_mul, ATOM_ARG_PLL}, { 1069254885Sdumbbell atom_op_mul, ATOM_ARG_MC}, { 1070254885Sdumbbell atom_op_div, ATOM_ARG_REG}, { 1071254885Sdumbbell atom_op_div, ATOM_ARG_PS}, { 1072254885Sdumbbell atom_op_div, ATOM_ARG_WS}, { 1073254885Sdumbbell atom_op_div, ATOM_ARG_FB}, { 1074254885Sdumbbell atom_op_div, ATOM_ARG_PLL}, { 1075254885Sdumbbell atom_op_div, ATOM_ARG_MC}, { 1076254885Sdumbbell atom_op_add, ATOM_ARG_REG}, { 1077254885Sdumbbell atom_op_add, ATOM_ARG_PS}, { 1078254885Sdumbbell atom_op_add, ATOM_ARG_WS}, { 1079254885Sdumbbell atom_op_add, ATOM_ARG_FB}, { 1080254885Sdumbbell atom_op_add, ATOM_ARG_PLL}, { 1081254885Sdumbbell atom_op_add, ATOM_ARG_MC}, { 1082254885Sdumbbell atom_op_sub, ATOM_ARG_REG}, { 1083254885Sdumbbell atom_op_sub, ATOM_ARG_PS}, { 1084254885Sdumbbell atom_op_sub, ATOM_ARG_WS}, { 1085254885Sdumbbell atom_op_sub, ATOM_ARG_FB}, { 1086254885Sdumbbell atom_op_sub, ATOM_ARG_PLL}, { 1087254885Sdumbbell atom_op_sub, ATOM_ARG_MC}, { 1088254885Sdumbbell atom_op_setport, ATOM_PORT_ATI}, { 1089254885Sdumbbell atom_op_setport, ATOM_PORT_PCI}, { 1090254885Sdumbbell atom_op_setport, ATOM_PORT_SYSIO}, { 1091254885Sdumbbell atom_op_setregblock, 0}, { 1092254885Sdumbbell atom_op_setfbbase, 0}, { 1093254885Sdumbbell atom_op_compare, ATOM_ARG_REG}, { 1094254885Sdumbbell atom_op_compare, ATOM_ARG_PS}, { 1095254885Sdumbbell atom_op_compare, ATOM_ARG_WS}, { 1096254885Sdumbbell atom_op_compare, ATOM_ARG_FB}, { 1097254885Sdumbbell atom_op_compare, ATOM_ARG_PLL}, { 1098254885Sdumbbell atom_op_compare, ATOM_ARG_MC}, { 1099254885Sdumbbell atom_op_switch, 0}, { 1100254885Sdumbbell atom_op_jump, ATOM_COND_ALWAYS}, { 1101254885Sdumbbell atom_op_jump, ATOM_COND_EQUAL}, { 1102254885Sdumbbell atom_op_jump, ATOM_COND_BELOW}, { 1103254885Sdumbbell atom_op_jump, ATOM_COND_ABOVE}, { 1104254885Sdumbbell atom_op_jump, ATOM_COND_BELOWOREQUAL}, { 1105254885Sdumbbell atom_op_jump, ATOM_COND_ABOVEOREQUAL}, { 1106254885Sdumbbell atom_op_jump, ATOM_COND_NOTEQUAL}, { 1107254885Sdumbbell atom_op_test, ATOM_ARG_REG}, { 1108254885Sdumbbell atom_op_test, ATOM_ARG_PS}, { 1109254885Sdumbbell atom_op_test, ATOM_ARG_WS}, { 1110254885Sdumbbell atom_op_test, ATOM_ARG_FB}, { 1111254885Sdumbbell atom_op_test, ATOM_ARG_PLL}, { 1112254885Sdumbbell atom_op_test, ATOM_ARG_MC}, { 1113254885Sdumbbell atom_op_delay, ATOM_UNIT_MILLISEC}, { 1114254885Sdumbbell atom_op_delay, ATOM_UNIT_MICROSEC}, { 1115254885Sdumbbell atom_op_calltable, 0}, { 1116254885Sdumbbell atom_op_repeat, 0}, { 1117254885Sdumbbell atom_op_clear, ATOM_ARG_REG}, { 1118254885Sdumbbell atom_op_clear, ATOM_ARG_PS}, { 1119254885Sdumbbell atom_op_clear, ATOM_ARG_WS}, { 1120254885Sdumbbell atom_op_clear, ATOM_ARG_FB}, { 1121254885Sdumbbell atom_op_clear, ATOM_ARG_PLL}, { 1122254885Sdumbbell atom_op_clear, ATOM_ARG_MC}, { 1123254885Sdumbbell atom_op_nop, 0}, { 1124254885Sdumbbell atom_op_eot, 0}, { 1125254885Sdumbbell atom_op_mask, ATOM_ARG_REG}, { 1126254885Sdumbbell atom_op_mask, ATOM_ARG_PS}, { 1127254885Sdumbbell atom_op_mask, ATOM_ARG_WS}, { 1128254885Sdumbbell atom_op_mask, ATOM_ARG_FB}, { 1129254885Sdumbbell atom_op_mask, ATOM_ARG_PLL}, { 1130254885Sdumbbell atom_op_mask, ATOM_ARG_MC}, { 1131254885Sdumbbell atom_op_postcard, 0}, { 1132254885Sdumbbell atom_op_beep, 0}, { 1133254885Sdumbbell atom_op_savereg, 0}, { 1134254885Sdumbbell atom_op_restorereg, 0}, { 1135254885Sdumbbell atom_op_setdatablock, 0}, { 1136254885Sdumbbell atom_op_xor, ATOM_ARG_REG}, { 1137254885Sdumbbell atom_op_xor, ATOM_ARG_PS}, { 1138254885Sdumbbell atom_op_xor, ATOM_ARG_WS}, { 1139254885Sdumbbell atom_op_xor, ATOM_ARG_FB}, { 1140254885Sdumbbell atom_op_xor, ATOM_ARG_PLL}, { 1141254885Sdumbbell atom_op_xor, ATOM_ARG_MC}, { 1142254885Sdumbbell atom_op_shl, ATOM_ARG_REG}, { 1143254885Sdumbbell atom_op_shl, ATOM_ARG_PS}, { 1144254885Sdumbbell atom_op_shl, ATOM_ARG_WS}, { 1145254885Sdumbbell atom_op_shl, ATOM_ARG_FB}, { 1146254885Sdumbbell atom_op_shl, ATOM_ARG_PLL}, { 1147254885Sdumbbell atom_op_shl, ATOM_ARG_MC}, { 1148254885Sdumbbell atom_op_shr, ATOM_ARG_REG}, { 1149254885Sdumbbell atom_op_shr, ATOM_ARG_PS}, { 1150254885Sdumbbell atom_op_shr, ATOM_ARG_WS}, { 1151254885Sdumbbell atom_op_shr, ATOM_ARG_FB}, { 1152254885Sdumbbell atom_op_shr, ATOM_ARG_PLL}, { 1153254885Sdumbbell atom_op_shr, ATOM_ARG_MC}, { 1154254885Sdumbbellatom_op_debug, 0},}; 1155254885Sdumbbell 1156254885Sdumbbellstatic int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params) 1157254885Sdumbbell{ 1158254885Sdumbbell int base = CU16(ctx->cmd_table + 4 + 2 * index); 1159254885Sdumbbell int len, ws, ps, ptr; 1160254885Sdumbbell unsigned char op; 1161254885Sdumbbell atom_exec_context ectx; 1162254885Sdumbbell int ret = 0; 1163254885Sdumbbell 1164254885Sdumbbell if (!base) 1165254885Sdumbbell return -EINVAL; 1166254885Sdumbbell 1167254885Sdumbbell len = CU16(base + ATOM_CT_SIZE_PTR); 1168254885Sdumbbell ws = CU8(base + ATOM_CT_WS_PTR); 1169254885Sdumbbell ps = CU8(base + ATOM_CT_PS_PTR) & ATOM_CT_PS_MASK; 1170254885Sdumbbell ptr = base + ATOM_CT_CODE_PTR; 1171254885Sdumbbell 1172254894Sdumbbell ATOM_SDEBUG_PRINT(">> execute %04X (len %d, WS %d, PS %d)\n", base, len, ws, ps); 1173254885Sdumbbell 1174254885Sdumbbell ectx.ctx = ctx; 1175254885Sdumbbell ectx.ps_shift = ps / 4; 1176254885Sdumbbell ectx.start = base; 1177254885Sdumbbell ectx.ps = params; 1178254885Sdumbbell ectx.abort = false; 1179254885Sdumbbell ectx.last_jump = 0; 1180254885Sdumbbell if (ws) 1181254885Sdumbbell ectx.ws = malloc(4 * ws, DRM_MEM_DRIVER, M_ZERO | M_WAITOK); 1182254885Sdumbbell else 1183254885Sdumbbell ectx.ws = NULL; 1184254885Sdumbbell 1185254885Sdumbbell debug_depth++; 1186254885Sdumbbell while (1) { 1187254885Sdumbbell op = CU8(ptr++); 1188254885Sdumbbell if (op < ATOM_OP_NAMES_CNT) 1189254894Sdumbbell ATOM_SDEBUG_PRINT("%s @ 0x%04X\n", atom_op_names[op], ptr - 1); 1190254885Sdumbbell else 1191254894Sdumbbell ATOM_SDEBUG_PRINT("[%d] @ 0x%04X\n", op, ptr - 1); 1192254885Sdumbbell if (ectx.abort) { 1193254885Sdumbbell DRM_ERROR("atombios stuck executing %04X (len %d, WS %d, PS %d) @ 0x%04X\n", 1194254885Sdumbbell base, len, ws, ps, ptr - 1); 1195254885Sdumbbell ret = -EINVAL; 1196254885Sdumbbell goto free; 1197254885Sdumbbell } 1198254885Sdumbbell 1199254885Sdumbbell if (op < ATOM_OP_CNT && op > 0) 1200254885Sdumbbell opcode_table[op].func(&ectx, &ptr, 1201254885Sdumbbell opcode_table[op].arg); 1202254885Sdumbbell else 1203254885Sdumbbell break; 1204254885Sdumbbell 1205254885Sdumbbell if (op == ATOM_OP_EOT) 1206254885Sdumbbell break; 1207254885Sdumbbell } 1208254885Sdumbbell debug_depth--; 1209254894Sdumbbell ATOM_SDEBUG_PRINT("<<\n"); 1210254885Sdumbbell 1211254885Sdumbbellfree: 1212254885Sdumbbell if (ws) 1213254885Sdumbbell free(ectx.ws, DRM_MEM_DRIVER); 1214254885Sdumbbell return ret; 1215254885Sdumbbell} 1216254885Sdumbbell 1217254885Sdumbbellint atom_execute_table(struct atom_context *ctx, int index, uint32_t * params) 1218254885Sdumbbell{ 1219254885Sdumbbell int r; 1220254885Sdumbbell 1221254885Sdumbbell sx_xlock(&ctx->mutex); 1222254885Sdumbbell /* reset reg block */ 1223254885Sdumbbell ctx->reg_block = 0; 1224254885Sdumbbell /* reset fb window */ 1225254885Sdumbbell ctx->fb_base = 0; 1226254885Sdumbbell /* reset io mode */ 1227254885Sdumbbell ctx->io_mode = ATOM_IO_MM; 1228254885Sdumbbell r = atom_execute_table_locked(ctx, index, params); 1229254885Sdumbbell sx_xunlock(&ctx->mutex); 1230254885Sdumbbell return r; 1231254885Sdumbbell} 1232254885Sdumbbell 1233254885Sdumbbellstatic int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 }; 1234254885Sdumbbell 1235254885Sdumbbellstatic void atom_index_iio(struct atom_context *ctx, int base) 1236254885Sdumbbell{ 1237254885Sdumbbell ctx->iio = malloc(2 * 256, DRM_MEM_DRIVER, M_ZERO | M_WAITOK); 1238254885Sdumbbell while (CU8(base) == ATOM_IIO_START) { 1239254885Sdumbbell ctx->iio[CU8(base + 1)] = base + 2; 1240254885Sdumbbell base += 2; 1241254885Sdumbbell while (CU8(base) != ATOM_IIO_END) 1242254885Sdumbbell base += atom_iio_len[CU8(base)]; 1243254885Sdumbbell base += 3; 1244254885Sdumbbell } 1245254885Sdumbbell} 1246254885Sdumbbell 1247254885Sdumbbellstruct atom_context *atom_parse(struct card_info *card, void *bios) 1248254885Sdumbbell{ 1249254885Sdumbbell int base; 1250254885Sdumbbell struct atom_context *ctx = 1251254885Sdumbbell malloc(sizeof(struct atom_context), DRM_MEM_DRIVER, M_ZERO | M_WAITOK); 1252254885Sdumbbell char *str; 1253254885Sdumbbell char name[512]; 1254254885Sdumbbell int i; 1255254885Sdumbbell 1256254885Sdumbbell if (!ctx) 1257254885Sdumbbell return NULL; 1258254885Sdumbbell 1259254885Sdumbbell ctx->card = card; 1260254885Sdumbbell ctx->bios = bios; 1261254885Sdumbbell 1262254885Sdumbbell if (CU16(0) != ATOM_BIOS_MAGIC) { 1263254885Sdumbbell DRM_INFO("Invalid BIOS magic.\n"); 1264254885Sdumbbell free(ctx, DRM_MEM_DRIVER); 1265254885Sdumbbell return NULL; 1266254885Sdumbbell } 1267254885Sdumbbell if (strncmp 1268254885Sdumbbell (CSTR(ATOM_ATI_MAGIC_PTR), ATOM_ATI_MAGIC, 1269254885Sdumbbell strlen(ATOM_ATI_MAGIC))) { 1270254885Sdumbbell DRM_INFO("Invalid ATI magic.\n"); 1271254885Sdumbbell free(ctx, DRM_MEM_DRIVER); 1272254885Sdumbbell return NULL; 1273254885Sdumbbell } 1274254885Sdumbbell 1275254885Sdumbbell base = CU16(ATOM_ROM_TABLE_PTR); 1276254885Sdumbbell if (strncmp 1277254885Sdumbbell (CSTR(base + ATOM_ROM_MAGIC_PTR), ATOM_ROM_MAGIC, 1278254885Sdumbbell strlen(ATOM_ROM_MAGIC))) { 1279254885Sdumbbell DRM_INFO("Invalid ATOM magic.\n"); 1280254885Sdumbbell free(ctx, DRM_MEM_DRIVER); 1281254885Sdumbbell return NULL; 1282254885Sdumbbell } 1283254885Sdumbbell 1284254885Sdumbbell ctx->cmd_table = CU16(base + ATOM_ROM_CMD_PTR); 1285254885Sdumbbell ctx->data_table = CU16(base + ATOM_ROM_DATA_PTR); 1286254885Sdumbbell atom_index_iio(ctx, CU16(ctx->data_table + ATOM_DATA_IIO_PTR) + 4); 1287254885Sdumbbell 1288254885Sdumbbell str = CSTR(CU16(base + ATOM_ROM_MSG_PTR)); 1289254885Sdumbbell while (*str && ((*str == '\n') || (*str == '\r'))) 1290254885Sdumbbell str++; 1291254885Sdumbbell /* name string isn't always 0 terminated */ 1292254885Sdumbbell for (i = 0; i < 511; i++) { 1293254885Sdumbbell name[i] = str[i]; 1294254885Sdumbbell if (name[i] < '.' || name[i] > 'z') { 1295254885Sdumbbell name[i] = 0; 1296254885Sdumbbell break; 1297254885Sdumbbell } 1298254885Sdumbbell } 1299254885Sdumbbell DRM_INFO("ATOM BIOS: %s\n", name); 1300254885Sdumbbell 1301254885Sdumbbell return ctx; 1302254885Sdumbbell} 1303254885Sdumbbell 1304254885Sdumbbellint atom_asic_init(struct atom_context *ctx) 1305254885Sdumbbell{ 1306254885Sdumbbell struct radeon_device *rdev = ctx->card->dev->dev_private; 1307254885Sdumbbell int hwi = CU16(ctx->data_table + ATOM_DATA_FWI_PTR); 1308254885Sdumbbell uint32_t ps[16]; 1309254885Sdumbbell int ret; 1310254885Sdumbbell 1311254885Sdumbbell memset(ps, 0, 64); 1312254885Sdumbbell 1313254885Sdumbbell ps[0] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFSCLK_PTR)); 1314254885Sdumbbell ps[1] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFMCLK_PTR)); 1315254885Sdumbbell if (!ps[0] || !ps[1]) 1316254885Sdumbbell return 1; 1317254885Sdumbbell 1318254885Sdumbbell if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT)) 1319254885Sdumbbell return 1; 1320254885Sdumbbell ret = atom_execute_table(ctx, ATOM_CMD_INIT, ps); 1321254885Sdumbbell if (ret) 1322254885Sdumbbell return ret; 1323254885Sdumbbell 1324254885Sdumbbell memset(ps, 0, 64); 1325254885Sdumbbell 1326254885Sdumbbell if (rdev->family < CHIP_R600) { 1327254885Sdumbbell if (CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_SPDFANCNTL)) 1328254885Sdumbbell atom_execute_table(ctx, ATOM_CMD_SPDFANCNTL, ps); 1329254885Sdumbbell } 1330254885Sdumbbell return ret; 1331254885Sdumbbell} 1332254885Sdumbbell 1333254885Sdumbbellvoid atom_destroy(struct atom_context *ctx) 1334254885Sdumbbell{ 1335254885Sdumbbell if (ctx->iio) 1336254885Sdumbbell free(ctx->iio, DRM_MEM_DRIVER); 1337254885Sdumbbell free(ctx, DRM_MEM_DRIVER); 1338254885Sdumbbell} 1339254885Sdumbbell 1340254885Sdumbbellbool atom_parse_data_header(struct atom_context *ctx, int index, 1341254885Sdumbbell uint16_t * size, uint8_t * frev, uint8_t * crev, 1342254885Sdumbbell uint16_t * data_start) 1343254885Sdumbbell{ 1344254885Sdumbbell int offset = index * 2 + 4; 1345254885Sdumbbell int idx = CU16(ctx->data_table + offset); 1346254885Sdumbbell u16 *mdt = (u16 *)((char *)ctx->bios + ctx->data_table + 4); 1347254885Sdumbbell 1348254885Sdumbbell if (!mdt[index]) 1349254885Sdumbbell return false; 1350254885Sdumbbell 1351254885Sdumbbell if (size) 1352254885Sdumbbell *size = CU16(idx); 1353254885Sdumbbell if (frev) 1354254885Sdumbbell *frev = CU8(idx + 2); 1355254885Sdumbbell if (crev) 1356254885Sdumbbell *crev = CU8(idx + 3); 1357254885Sdumbbell *data_start = idx; 1358254885Sdumbbell return true; 1359254885Sdumbbell} 1360254885Sdumbbell 1361254885Sdumbbellbool atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t * frev, 1362254885Sdumbbell uint8_t * crev) 1363254885Sdumbbell{ 1364254885Sdumbbell int offset = index * 2 + 4; 1365254885Sdumbbell int idx = CU16(ctx->cmd_table + offset); 1366254885Sdumbbell u16 *mct = (u16 *)((char *)ctx->bios + ctx->cmd_table + 4); 1367254885Sdumbbell 1368254885Sdumbbell if (!mct[index]) 1369254885Sdumbbell return false; 1370254885Sdumbbell 1371254885Sdumbbell if (frev) 1372254885Sdumbbell *frev = CU8(idx + 2); 1373254885Sdumbbell if (crev) 1374254885Sdumbbell *crev = CU8(idx + 3); 1375254885Sdumbbell return true; 1376254885Sdumbbell} 1377254885Sdumbbell 1378254885Sdumbbellint atom_allocate_fb_scratch(struct atom_context *ctx) 1379254885Sdumbbell{ 1380254885Sdumbbell int index = GetIndexIntoMasterTable(DATA, VRAM_UsageByFirmware); 1381254885Sdumbbell uint16_t data_offset; 1382254885Sdumbbell int usage_bytes = 0; 1383254885Sdumbbell struct _ATOM_VRAM_USAGE_BY_FIRMWARE *firmware_usage; 1384254885Sdumbbell 1385254885Sdumbbell if (atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset)) { 1386254885Sdumbbell firmware_usage = (struct _ATOM_VRAM_USAGE_BY_FIRMWARE *)((char *)ctx->bios + data_offset); 1387254885Sdumbbell 1388254885Sdumbbell DRM_DEBUG("atom firmware requested %08x %dkb\n", 1389254885Sdumbbell firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware, 1390254885Sdumbbell firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb); 1391254885Sdumbbell 1392254885Sdumbbell usage_bytes = firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb * 1024; 1393254885Sdumbbell } 1394254885Sdumbbell ctx->scratch_size_bytes = 0; 1395254885Sdumbbell if (usage_bytes == 0) 1396254885Sdumbbell usage_bytes = 20 * 1024; 1397254885Sdumbbell /* allocate some scratch memory */ 1398254885Sdumbbell ctx->scratch = malloc(usage_bytes, DRM_MEM_DRIVER, M_ZERO | M_WAITOK); 1399254885Sdumbbell if (!ctx->scratch) 1400254885Sdumbbell return -ENOMEM; 1401254885Sdumbbell ctx->scratch_size_bytes = usage_bytes; 1402254885Sdumbbell return 0; 1403254885Sdumbbell} 1404