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