Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2008 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Author: Stanislaw Skowronek
0023  */
0024 
0025 #include <linux/module.h>
0026 #include <linux/sched.h>
0027 #include <linux/slab.h>
0028 #include <linux/string_helpers.h>
0029 
0030 #include <asm/unaligned.h>
0031 
0032 #include <drm/drm_device.h>
0033 #include <drm/drm_util.h>
0034 
0035 #define ATOM_DEBUG
0036 
0037 #include "atom.h"
0038 #include "atom-names.h"
0039 #include "atom-bits.h"
0040 #include "radeon.h"
0041 
0042 #define ATOM_COND_ABOVE     0
0043 #define ATOM_COND_ABOVEOREQUAL  1
0044 #define ATOM_COND_ALWAYS    2
0045 #define ATOM_COND_BELOW     3
0046 #define ATOM_COND_BELOWOREQUAL  4
0047 #define ATOM_COND_EQUAL     5
0048 #define ATOM_COND_NOTEQUAL  6
0049 
0050 #define ATOM_PORT_ATI   0
0051 #define ATOM_PORT_PCI   1
0052 #define ATOM_PORT_SYSIO 2
0053 
0054 #define ATOM_UNIT_MICROSEC  0
0055 #define ATOM_UNIT_MILLISEC  1
0056 
0057 #define PLL_INDEX   2
0058 #define PLL_DATA    3
0059 
0060 typedef struct {
0061     struct atom_context *ctx;
0062     uint32_t *ps, *ws;
0063     int ps_shift;
0064     uint16_t start;
0065     unsigned last_jump;
0066     unsigned long last_jump_jiffies;
0067     bool abort;
0068 } atom_exec_context;
0069 
0070 int atom_debug = 0;
0071 static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params);
0072 int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params);
0073 
0074 static uint32_t atom_arg_mask[8] = {
0075     0xFFFFFFFF, 0x0000FFFF, 0x00FFFF00, 0xFFFF0000,
0076     0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000
0077 };
0078 static int atom_arg_shift[8] = { 0, 0, 8, 16, 0, 8, 16, 24 };
0079 
0080 static int atom_dst_to_src[8][4] = {
0081     /* translate destination alignment field to the source alignment encoding */
0082     {0, 0, 0, 0},
0083     {1, 2, 3, 0},
0084     {1, 2, 3, 0},
0085     {1, 2, 3, 0},
0086     {4, 5, 6, 7},
0087     {4, 5, 6, 7},
0088     {4, 5, 6, 7},
0089     {4, 5, 6, 7},
0090 };
0091 static int atom_def_dst[8] = { 0, 0, 1, 2, 0, 1, 2, 3 };
0092 
0093 static int debug_depth = 0;
0094 #ifdef ATOM_DEBUG
0095 static void debug_print_spaces(int n)
0096 {
0097     while (n--)
0098         printk("   ");
0099 }
0100 
0101 #define DEBUG(...) do if (atom_debug) { printk(KERN_DEBUG __VA_ARGS__); } while (0)
0102 #define SDEBUG(...) do if (atom_debug) { printk(KERN_DEBUG); debug_print_spaces(debug_depth); printk(__VA_ARGS__); } while (0)
0103 #else
0104 #define DEBUG(...) do { } while (0)
0105 #define SDEBUG(...) do { } while (0)
0106 #endif
0107 
0108 static uint32_t atom_iio_execute(struct atom_context *ctx, int base,
0109                  uint32_t index, uint32_t data)
0110 {
0111     struct radeon_device *rdev = ctx->card->dev->dev_private;
0112     uint32_t temp = 0xCDCDCDCD;
0113 
0114     while (1)
0115         switch (CU8(base)) {
0116         case ATOM_IIO_NOP:
0117             base++;
0118             break;
0119         case ATOM_IIO_READ:
0120             temp = ctx->card->ioreg_read(ctx->card, CU16(base + 1));
0121             base += 3;
0122             break;
0123         case ATOM_IIO_WRITE:
0124             if (rdev->family == CHIP_RV515)
0125                 (void)ctx->card->ioreg_read(ctx->card, CU16(base + 1));
0126             ctx->card->ioreg_write(ctx->card, CU16(base + 1), temp);
0127             base += 3;
0128             break;
0129         case ATOM_IIO_CLEAR:
0130             temp &=
0131                 ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
0132                   CU8(base + 2));
0133             base += 3;
0134             break;
0135         case ATOM_IIO_SET:
0136             temp |=
0137                 (0xFFFFFFFF >> (32 - CU8(base + 1))) << CU8(base +
0138                                     2);
0139             base += 3;
0140             break;
0141         case ATOM_IIO_MOVE_INDEX:
0142             temp &=
0143                 ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
0144                   CU8(base + 3));
0145             temp |=
0146                 ((index >> CU8(base + 2)) &
0147                  (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base +
0148                                       3);
0149             base += 4;
0150             break;
0151         case ATOM_IIO_MOVE_DATA:
0152             temp &=
0153                 ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
0154                   CU8(base + 3));
0155             temp |=
0156                 ((data >> CU8(base + 2)) &
0157                  (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base +
0158                                       3);
0159             base += 4;
0160             break;
0161         case ATOM_IIO_MOVE_ATTR:
0162             temp &=
0163                 ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
0164                   CU8(base + 3));
0165             temp |=
0166                 ((ctx->
0167                   io_attr >> CU8(base + 2)) & (0xFFFFFFFF >> (32 -
0168                                       CU8
0169                                       (base
0170                                        +
0171                                        1))))
0172                 << CU8(base + 3);
0173             base += 4;
0174             break;
0175         case ATOM_IIO_END:
0176             return temp;
0177         default:
0178             pr_info("Unknown IIO opcode\n");
0179             return 0;
0180         }
0181 }
0182 
0183 static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr,
0184                  int *ptr, uint32_t *saved, int print)
0185 {
0186     uint32_t idx, val = 0xCDCDCDCD, align, arg;
0187     struct atom_context *gctx = ctx->ctx;
0188     arg = attr & 7;
0189     align = (attr >> 3) & 7;
0190     switch (arg) {
0191     case ATOM_ARG_REG:
0192         idx = U16(*ptr);
0193         (*ptr) += 2;
0194         if (print)
0195             DEBUG("REG[0x%04X]", idx);
0196         idx += gctx->reg_block;
0197         switch (gctx->io_mode) {
0198         case ATOM_IO_MM:
0199             val = gctx->card->reg_read(gctx->card, idx);
0200             break;
0201         case ATOM_IO_PCI:
0202             pr_info("PCI registers are not implemented\n");
0203             return 0;
0204         case ATOM_IO_SYSIO:
0205             pr_info("SYSIO registers are not implemented\n");
0206             return 0;
0207         default:
0208             if (!(gctx->io_mode & 0x80)) {
0209                 pr_info("Bad IO mode\n");
0210                 return 0;
0211             }
0212             if (!gctx->iio[gctx->io_mode & 0x7F]) {
0213                 pr_info("Undefined indirect IO read method %d\n",
0214                     gctx->io_mode & 0x7F);
0215                 return 0;
0216             }
0217             val =
0218                 atom_iio_execute(gctx,
0219                          gctx->iio[gctx->io_mode & 0x7F],
0220                          idx, 0);
0221         }
0222         break;
0223     case ATOM_ARG_PS:
0224         idx = U8(*ptr);
0225         (*ptr)++;
0226         /* get_unaligned_le32 avoids unaligned accesses from atombios
0227          * tables, noticed on a DEC Alpha. */
0228         val = get_unaligned_le32((u32 *)&ctx->ps[idx]);
0229         if (print)
0230             DEBUG("PS[0x%02X,0x%04X]", idx, val);
0231         break;
0232     case ATOM_ARG_WS:
0233         idx = U8(*ptr);
0234         (*ptr)++;
0235         if (print)
0236             DEBUG("WS[0x%02X]", idx);
0237         switch (idx) {
0238         case ATOM_WS_QUOTIENT:
0239             val = gctx->divmul[0];
0240             break;
0241         case ATOM_WS_REMAINDER:
0242             val = gctx->divmul[1];
0243             break;
0244         case ATOM_WS_DATAPTR:
0245             val = gctx->data_block;
0246             break;
0247         case ATOM_WS_SHIFT:
0248             val = gctx->shift;
0249             break;
0250         case ATOM_WS_OR_MASK:
0251             val = 1 << gctx->shift;
0252             break;
0253         case ATOM_WS_AND_MASK:
0254             val = ~(1 << gctx->shift);
0255             break;
0256         case ATOM_WS_FB_WINDOW:
0257             val = gctx->fb_base;
0258             break;
0259         case ATOM_WS_ATTRIBUTES:
0260             val = gctx->io_attr;
0261             break;
0262         case ATOM_WS_REGPTR:
0263             val = gctx->reg_block;
0264             break;
0265         default:
0266             val = ctx->ws[idx];
0267         }
0268         break;
0269     case ATOM_ARG_ID:
0270         idx = U16(*ptr);
0271         (*ptr) += 2;
0272         if (print) {
0273             if (gctx->data_block)
0274                 DEBUG("ID[0x%04X+%04X]", idx, gctx->data_block);
0275             else
0276                 DEBUG("ID[0x%04X]", idx);
0277         }
0278         val = U32(idx + gctx->data_block);
0279         break;
0280     case ATOM_ARG_FB:
0281         idx = U8(*ptr);
0282         (*ptr)++;
0283         if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) {
0284             DRM_ERROR("ATOM: fb read beyond scratch region: %d vs. %d\n",
0285                   gctx->fb_base + (idx * 4), gctx->scratch_size_bytes);
0286             val = 0;
0287         } else
0288             val = gctx->scratch[(gctx->fb_base / 4) + idx];
0289         if (print)
0290             DEBUG("FB[0x%02X]", idx);
0291         break;
0292     case ATOM_ARG_IMM:
0293         switch (align) {
0294         case ATOM_SRC_DWORD:
0295             val = U32(*ptr);
0296             (*ptr) += 4;
0297             if (print)
0298                 DEBUG("IMM 0x%08X\n", val);
0299             return val;
0300         case ATOM_SRC_WORD0:
0301         case ATOM_SRC_WORD8:
0302         case ATOM_SRC_WORD16:
0303             val = U16(*ptr);
0304             (*ptr) += 2;
0305             if (print)
0306                 DEBUG("IMM 0x%04X\n", val);
0307             return val;
0308         case ATOM_SRC_BYTE0:
0309         case ATOM_SRC_BYTE8:
0310         case ATOM_SRC_BYTE16:
0311         case ATOM_SRC_BYTE24:
0312             val = U8(*ptr);
0313             (*ptr)++;
0314             if (print)
0315                 DEBUG("IMM 0x%02X\n", val);
0316             return val;
0317         }
0318         return 0;
0319     case ATOM_ARG_PLL:
0320         idx = U8(*ptr);
0321         (*ptr)++;
0322         if (print)
0323             DEBUG("PLL[0x%02X]", idx);
0324         val = gctx->card->pll_read(gctx->card, idx);
0325         break;
0326     case ATOM_ARG_MC:
0327         idx = U8(*ptr);
0328         (*ptr)++;
0329         if (print)
0330             DEBUG("MC[0x%02X]", idx);
0331         val = gctx->card->mc_read(gctx->card, idx);
0332         break;
0333     }
0334     if (saved)
0335         *saved = val;
0336     val &= atom_arg_mask[align];
0337     val >>= atom_arg_shift[align];
0338     if (print)
0339         switch (align) {
0340         case ATOM_SRC_DWORD:
0341             DEBUG(".[31:0] -> 0x%08X\n", val);
0342             break;
0343         case ATOM_SRC_WORD0:
0344             DEBUG(".[15:0] -> 0x%04X\n", val);
0345             break;
0346         case ATOM_SRC_WORD8:
0347             DEBUG(".[23:8] -> 0x%04X\n", val);
0348             break;
0349         case ATOM_SRC_WORD16:
0350             DEBUG(".[31:16] -> 0x%04X\n", val);
0351             break;
0352         case ATOM_SRC_BYTE0:
0353             DEBUG(".[7:0] -> 0x%02X\n", val);
0354             break;
0355         case ATOM_SRC_BYTE8:
0356             DEBUG(".[15:8] -> 0x%02X\n", val);
0357             break;
0358         case ATOM_SRC_BYTE16:
0359             DEBUG(".[23:16] -> 0x%02X\n", val);
0360             break;
0361         case ATOM_SRC_BYTE24:
0362             DEBUG(".[31:24] -> 0x%02X\n", val);
0363             break;
0364         }
0365     return val;
0366 }
0367 
0368 static void atom_skip_src_int(atom_exec_context *ctx, uint8_t attr, int *ptr)
0369 {
0370     uint32_t align = (attr >> 3) & 7, arg = attr & 7;
0371     switch (arg) {
0372     case ATOM_ARG_REG:
0373     case ATOM_ARG_ID:
0374         (*ptr) += 2;
0375         break;
0376     case ATOM_ARG_PLL:
0377     case ATOM_ARG_MC:
0378     case ATOM_ARG_PS:
0379     case ATOM_ARG_WS:
0380     case ATOM_ARG_FB:
0381         (*ptr)++;
0382         break;
0383     case ATOM_ARG_IMM:
0384         switch (align) {
0385         case ATOM_SRC_DWORD:
0386             (*ptr) += 4;
0387             return;
0388         case ATOM_SRC_WORD0:
0389         case ATOM_SRC_WORD8:
0390         case ATOM_SRC_WORD16:
0391             (*ptr) += 2;
0392             return;
0393         case ATOM_SRC_BYTE0:
0394         case ATOM_SRC_BYTE8:
0395         case ATOM_SRC_BYTE16:
0396         case ATOM_SRC_BYTE24:
0397             (*ptr)++;
0398             return;
0399         }
0400         return;
0401     }
0402 }
0403 
0404 static uint32_t atom_get_src(atom_exec_context *ctx, uint8_t attr, int *ptr)
0405 {
0406     return atom_get_src_int(ctx, attr, ptr, NULL, 1);
0407 }
0408 
0409 static uint32_t atom_get_src_direct(atom_exec_context *ctx, uint8_t align, int *ptr)
0410 {
0411     uint32_t val = 0xCDCDCDCD;
0412 
0413     switch (align) {
0414     case ATOM_SRC_DWORD:
0415         val = U32(*ptr);
0416         (*ptr) += 4;
0417         break;
0418     case ATOM_SRC_WORD0:
0419     case ATOM_SRC_WORD8:
0420     case ATOM_SRC_WORD16:
0421         val = U16(*ptr);
0422         (*ptr) += 2;
0423         break;
0424     case ATOM_SRC_BYTE0:
0425     case ATOM_SRC_BYTE8:
0426     case ATOM_SRC_BYTE16:
0427     case ATOM_SRC_BYTE24:
0428         val = U8(*ptr);
0429         (*ptr)++;
0430         break;
0431     }
0432     return val;
0433 }
0434 
0435 static uint32_t atom_get_dst(atom_exec_context *ctx, int arg, uint8_t attr,
0436                  int *ptr, uint32_t *saved, int print)
0437 {
0438     return atom_get_src_int(ctx,
0439                 arg | atom_dst_to_src[(attr >> 3) &
0440                               7][(attr >> 6) & 3] << 3,
0441                 ptr, saved, print);
0442 }
0443 
0444 static void atom_skip_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr)
0445 {
0446     atom_skip_src_int(ctx,
0447               arg | atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) &
0448                                  3] << 3, ptr);
0449 }
0450 
0451 static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr,
0452              int *ptr, uint32_t val, uint32_t saved)
0453 {
0454     uint32_t align =
0455         atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3], old_val =
0456         val, idx;
0457     struct atom_context *gctx = ctx->ctx;
0458     old_val &= atom_arg_mask[align] >> atom_arg_shift[align];
0459     val <<= atom_arg_shift[align];
0460     val &= atom_arg_mask[align];
0461     saved &= ~atom_arg_mask[align];
0462     val |= saved;
0463     switch (arg) {
0464     case ATOM_ARG_REG:
0465         idx = U16(*ptr);
0466         (*ptr) += 2;
0467         DEBUG("REG[0x%04X]", idx);
0468         idx += gctx->reg_block;
0469         switch (gctx->io_mode) {
0470         case ATOM_IO_MM:
0471             if (idx == 0)
0472                 gctx->card->reg_write(gctx->card, idx,
0473                               val << 2);
0474             else
0475                 gctx->card->reg_write(gctx->card, idx, val);
0476             break;
0477         case ATOM_IO_PCI:
0478             pr_info("PCI registers are not implemented\n");
0479             return;
0480         case ATOM_IO_SYSIO:
0481             pr_info("SYSIO registers are not implemented\n");
0482             return;
0483         default:
0484             if (!(gctx->io_mode & 0x80)) {
0485                 pr_info("Bad IO mode\n");
0486                 return;
0487             }
0488             if (!gctx->iio[gctx->io_mode & 0xFF]) {
0489                 pr_info("Undefined indirect IO write method %d\n",
0490                     gctx->io_mode & 0x7F);
0491                 return;
0492             }
0493             atom_iio_execute(gctx, gctx->iio[gctx->io_mode & 0xFF],
0494                      idx, val);
0495         }
0496         break;
0497     case ATOM_ARG_PS:
0498         idx = U8(*ptr);
0499         (*ptr)++;
0500         DEBUG("PS[0x%02X]", idx);
0501         ctx->ps[idx] = cpu_to_le32(val);
0502         break;
0503     case ATOM_ARG_WS:
0504         idx = U8(*ptr);
0505         (*ptr)++;
0506         DEBUG("WS[0x%02X]", idx);
0507         switch (idx) {
0508         case ATOM_WS_QUOTIENT:
0509             gctx->divmul[0] = val;
0510             break;
0511         case ATOM_WS_REMAINDER:
0512             gctx->divmul[1] = val;
0513             break;
0514         case ATOM_WS_DATAPTR:
0515             gctx->data_block = val;
0516             break;
0517         case ATOM_WS_SHIFT:
0518             gctx->shift = val;
0519             break;
0520         case ATOM_WS_OR_MASK:
0521         case ATOM_WS_AND_MASK:
0522             break;
0523         case ATOM_WS_FB_WINDOW:
0524             gctx->fb_base = val;
0525             break;
0526         case ATOM_WS_ATTRIBUTES:
0527             gctx->io_attr = val;
0528             break;
0529         case ATOM_WS_REGPTR:
0530             gctx->reg_block = val;
0531             break;
0532         default:
0533             ctx->ws[idx] = val;
0534         }
0535         break;
0536     case ATOM_ARG_FB:
0537         idx = U8(*ptr);
0538         (*ptr)++;
0539         if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) {
0540             DRM_ERROR("ATOM: fb write beyond scratch region: %d vs. %d\n",
0541                   gctx->fb_base + (idx * 4), gctx->scratch_size_bytes);
0542         } else
0543             gctx->scratch[(gctx->fb_base / 4) + idx] = val;
0544         DEBUG("FB[0x%02X]", idx);
0545         break;
0546     case ATOM_ARG_PLL:
0547         idx = U8(*ptr);
0548         (*ptr)++;
0549         DEBUG("PLL[0x%02X]", idx);
0550         gctx->card->pll_write(gctx->card, idx, val);
0551         break;
0552     case ATOM_ARG_MC:
0553         idx = U8(*ptr);
0554         (*ptr)++;
0555         DEBUG("MC[0x%02X]", idx);
0556         gctx->card->mc_write(gctx->card, idx, val);
0557         return;
0558     }
0559     switch (align) {
0560     case ATOM_SRC_DWORD:
0561         DEBUG(".[31:0] <- 0x%08X\n", old_val);
0562         break;
0563     case ATOM_SRC_WORD0:
0564         DEBUG(".[15:0] <- 0x%04X\n", old_val);
0565         break;
0566     case ATOM_SRC_WORD8:
0567         DEBUG(".[23:8] <- 0x%04X\n", old_val);
0568         break;
0569     case ATOM_SRC_WORD16:
0570         DEBUG(".[31:16] <- 0x%04X\n", old_val);
0571         break;
0572     case ATOM_SRC_BYTE0:
0573         DEBUG(".[7:0] <- 0x%02X\n", old_val);
0574         break;
0575     case ATOM_SRC_BYTE8:
0576         DEBUG(".[15:8] <- 0x%02X\n", old_val);
0577         break;
0578     case ATOM_SRC_BYTE16:
0579         DEBUG(".[23:16] <- 0x%02X\n", old_val);
0580         break;
0581     case ATOM_SRC_BYTE24:
0582         DEBUG(".[31:24] <- 0x%02X\n", old_val);
0583         break;
0584     }
0585 }
0586 
0587 static void atom_op_add(atom_exec_context *ctx, int *ptr, int arg)
0588 {
0589     uint8_t attr = U8((*ptr)++);
0590     uint32_t dst, src, saved;
0591     int dptr = *ptr;
0592     SDEBUG("   dst: ");
0593     dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
0594     SDEBUG("   src: ");
0595     src = atom_get_src(ctx, attr, ptr);
0596     dst += src;
0597     SDEBUG("   dst: ");
0598     atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
0599 }
0600 
0601 static void atom_op_and(atom_exec_context *ctx, int *ptr, int arg)
0602 {
0603     uint8_t attr = U8((*ptr)++);
0604     uint32_t dst, src, saved;
0605     int dptr = *ptr;
0606     SDEBUG("   dst: ");
0607     dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
0608     SDEBUG("   src: ");
0609     src = atom_get_src(ctx, attr, ptr);
0610     dst &= src;
0611     SDEBUG("   dst: ");
0612     atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
0613 }
0614 
0615 static void atom_op_beep(atom_exec_context *ctx, int *ptr, int arg)
0616 {
0617     printk("ATOM BIOS beeped!\n");
0618 }
0619 
0620 static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg)
0621 {
0622     int idx = U8((*ptr)++);
0623     int r = 0;
0624 
0625     if (idx < ATOM_TABLE_NAMES_CNT)
0626         SDEBUG("   table: %d (%s)\n", idx, atom_table_names[idx]);
0627     else
0628         SDEBUG("   table: %d\n", idx);
0629     if (U16(ctx->ctx->cmd_table + 4 + 2 * idx))
0630         r = atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift);
0631     if (r) {
0632         ctx->abort = true;
0633     }
0634 }
0635 
0636 static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg)
0637 {
0638     uint8_t attr = U8((*ptr)++);
0639     uint32_t saved;
0640     int dptr = *ptr;
0641     attr &= 0x38;
0642     attr |= atom_def_dst[attr >> 3] << 6;
0643     atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
0644     SDEBUG("   dst: ");
0645     atom_put_dst(ctx, arg, attr, &dptr, 0, saved);
0646 }
0647 
0648 static void atom_op_compare(atom_exec_context *ctx, int *ptr, int arg)
0649 {
0650     uint8_t attr = U8((*ptr)++);
0651     uint32_t dst, src;
0652     SDEBUG("   src1: ");
0653     dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
0654     SDEBUG("   src2: ");
0655     src = atom_get_src(ctx, attr, ptr);
0656     ctx->ctx->cs_equal = (dst == src);
0657     ctx->ctx->cs_above = (dst > src);
0658     SDEBUG("   result: %s %s\n", ctx->ctx->cs_equal ? "EQ" : "NE",
0659            ctx->ctx->cs_above ? "GT" : "LE");
0660 }
0661 
0662 static void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg)
0663 {
0664     unsigned count = U8((*ptr)++);
0665     SDEBUG("   count: %d\n", count);
0666     if (arg == ATOM_UNIT_MICROSEC)
0667         udelay(count);
0668     else if (!drm_can_sleep())
0669         mdelay(count);
0670     else
0671         msleep(count);
0672 }
0673 
0674 static void atom_op_div(atom_exec_context *ctx, int *ptr, int arg)
0675 {
0676     uint8_t attr = U8((*ptr)++);
0677     uint32_t dst, src;
0678     SDEBUG("   src1: ");
0679     dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
0680     SDEBUG("   src2: ");
0681     src = atom_get_src(ctx, attr, ptr);
0682     if (src != 0) {
0683         ctx->ctx->divmul[0] = dst / src;
0684         ctx->ctx->divmul[1] = dst % src;
0685     } else {
0686         ctx->ctx->divmul[0] = 0;
0687         ctx->ctx->divmul[1] = 0;
0688     }
0689 }
0690 
0691 static void atom_op_eot(atom_exec_context *ctx, int *ptr, int arg)
0692 {
0693     /* functionally, a nop */
0694 }
0695 
0696 static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
0697 {
0698     int execute = 0, target = U16(*ptr);
0699     unsigned long cjiffies;
0700 
0701     (*ptr) += 2;
0702     switch (arg) {
0703     case ATOM_COND_ABOVE:
0704         execute = ctx->ctx->cs_above;
0705         break;
0706     case ATOM_COND_ABOVEOREQUAL:
0707         execute = ctx->ctx->cs_above || ctx->ctx->cs_equal;
0708         break;
0709     case ATOM_COND_ALWAYS:
0710         execute = 1;
0711         break;
0712     case ATOM_COND_BELOW:
0713         execute = !(ctx->ctx->cs_above || ctx->ctx->cs_equal);
0714         break;
0715     case ATOM_COND_BELOWOREQUAL:
0716         execute = !ctx->ctx->cs_above;
0717         break;
0718     case ATOM_COND_EQUAL:
0719         execute = ctx->ctx->cs_equal;
0720         break;
0721     case ATOM_COND_NOTEQUAL:
0722         execute = !ctx->ctx->cs_equal;
0723         break;
0724     }
0725     if (arg != ATOM_COND_ALWAYS)
0726         SDEBUG("   taken: %s\n", str_yes_no(execute));
0727     SDEBUG("   target: 0x%04X\n", target);
0728     if (execute) {
0729         if (ctx->last_jump == (ctx->start + target)) {
0730             cjiffies = jiffies;
0731             if (time_after(cjiffies, ctx->last_jump_jiffies)) {
0732                 cjiffies -= ctx->last_jump_jiffies;
0733                 if ((jiffies_to_msecs(cjiffies) > 5000)) {
0734                     DRM_ERROR("atombios stuck in loop for more than 5secs aborting\n");
0735                     ctx->abort = true;
0736                 }
0737             } else {
0738                 /* jiffies wrap around we will just wait a little longer */
0739                 ctx->last_jump_jiffies = jiffies;
0740             }
0741         } else {
0742             ctx->last_jump = ctx->start + target;
0743             ctx->last_jump_jiffies = jiffies;
0744         }
0745         *ptr = ctx->start + target;
0746     }
0747 }
0748 
0749 static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg)
0750 {
0751     uint8_t attr = U8((*ptr)++);
0752     uint32_t dst, mask, src, saved;
0753     int dptr = *ptr;
0754     SDEBUG("   dst: ");
0755     dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
0756     mask = atom_get_src_direct(ctx, ((attr >> 3) & 7), ptr);
0757     SDEBUG("   mask: 0x%08x", mask);
0758     SDEBUG("   src: ");
0759     src = atom_get_src(ctx, attr, ptr);
0760     dst &= mask;
0761     dst |= src;
0762     SDEBUG("   dst: ");
0763     atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
0764 }
0765 
0766 static void atom_op_move(atom_exec_context *ctx, int *ptr, int arg)
0767 {
0768     uint8_t attr = U8((*ptr)++);
0769     uint32_t src, saved;
0770     int dptr = *ptr;
0771     if (((attr >> 3) & 7) != ATOM_SRC_DWORD)
0772         atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
0773     else {
0774         atom_skip_dst(ctx, arg, attr, ptr);
0775         saved = 0xCDCDCDCD;
0776     }
0777     SDEBUG("   src: ");
0778     src = atom_get_src(ctx, attr, ptr);
0779     SDEBUG("   dst: ");
0780     atom_put_dst(ctx, arg, attr, &dptr, src, saved);
0781 }
0782 
0783 static void atom_op_mul(atom_exec_context *ctx, int *ptr, int arg)
0784 {
0785     uint8_t attr = U8((*ptr)++);
0786     uint32_t dst, src;
0787     SDEBUG("   src1: ");
0788     dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
0789     SDEBUG("   src2: ");
0790     src = atom_get_src(ctx, attr, ptr);
0791     ctx->ctx->divmul[0] = dst * src;
0792 }
0793 
0794 static void atom_op_nop(atom_exec_context *ctx, int *ptr, int arg)
0795 {
0796     /* nothing */
0797 }
0798 
0799 static void atom_op_or(atom_exec_context *ctx, int *ptr, int arg)
0800 {
0801     uint8_t attr = U8((*ptr)++);
0802     uint32_t dst, src, saved;
0803     int dptr = *ptr;
0804     SDEBUG("   dst: ");
0805     dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
0806     SDEBUG("   src: ");
0807     src = atom_get_src(ctx, attr, ptr);
0808     dst |= src;
0809     SDEBUG("   dst: ");
0810     atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
0811 }
0812 
0813 static void atom_op_postcard(atom_exec_context *ctx, int *ptr, int arg)
0814 {
0815     uint8_t val = U8((*ptr)++);
0816     SDEBUG("POST card output: 0x%02X\n", val);
0817 }
0818 
0819 static void atom_op_repeat(atom_exec_context *ctx, int *ptr, int arg)
0820 {
0821     pr_info("unimplemented!\n");
0822 }
0823 
0824 static void atom_op_restorereg(atom_exec_context *ctx, int *ptr, int arg)
0825 {
0826     pr_info("unimplemented!\n");
0827 }
0828 
0829 static void atom_op_savereg(atom_exec_context *ctx, int *ptr, int arg)
0830 {
0831     pr_info("unimplemented!\n");
0832 }
0833 
0834 static void atom_op_setdatablock(atom_exec_context *ctx, int *ptr, int arg)
0835 {
0836     int idx = U8(*ptr);
0837     (*ptr)++;
0838     SDEBUG("   block: %d\n", idx);
0839     if (!idx)
0840         ctx->ctx->data_block = 0;
0841     else if (idx == 255)
0842         ctx->ctx->data_block = ctx->start;
0843     else
0844         ctx->ctx->data_block = U16(ctx->ctx->data_table + 4 + 2 * idx);
0845     SDEBUG("   base: 0x%04X\n", ctx->ctx->data_block);
0846 }
0847 
0848 static void atom_op_setfbbase(atom_exec_context *ctx, int *ptr, int arg)
0849 {
0850     uint8_t attr = U8((*ptr)++);
0851     SDEBUG("   fb_base: ");
0852     ctx->ctx->fb_base = atom_get_src(ctx, attr, ptr);
0853 }
0854 
0855 static void atom_op_setport(atom_exec_context *ctx, int *ptr, int arg)
0856 {
0857     int port;
0858     switch (arg) {
0859     case ATOM_PORT_ATI:
0860         port = U16(*ptr);
0861         if (port < ATOM_IO_NAMES_CNT)
0862             SDEBUG("   port: %d (%s)\n", port, atom_io_names[port]);
0863         else
0864             SDEBUG("   port: %d\n", port);
0865         if (!port)
0866             ctx->ctx->io_mode = ATOM_IO_MM;
0867         else
0868             ctx->ctx->io_mode = ATOM_IO_IIO | port;
0869         (*ptr) += 2;
0870         break;
0871     case ATOM_PORT_PCI:
0872         ctx->ctx->io_mode = ATOM_IO_PCI;
0873         (*ptr)++;
0874         break;
0875     case ATOM_PORT_SYSIO:
0876         ctx->ctx->io_mode = ATOM_IO_SYSIO;
0877         (*ptr)++;
0878         break;
0879     }
0880 }
0881 
0882 static void atom_op_setregblock(atom_exec_context *ctx, int *ptr, int arg)
0883 {
0884     ctx->ctx->reg_block = U16(*ptr);
0885     (*ptr) += 2;
0886     SDEBUG("   base: 0x%04X\n", ctx->ctx->reg_block);
0887 }
0888 
0889 static void atom_op_shift_left(atom_exec_context *ctx, int *ptr, int arg)
0890 {
0891     uint8_t attr = U8((*ptr)++), shift;
0892     uint32_t saved, dst;
0893     int dptr = *ptr;
0894     attr &= 0x38;
0895     attr |= atom_def_dst[attr >> 3] << 6;
0896     SDEBUG("   dst: ");
0897     dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
0898     shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr);
0899     SDEBUG("   shift: %d\n", shift);
0900     dst <<= shift;
0901     SDEBUG("   dst: ");
0902     atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
0903 }
0904 
0905 static void atom_op_shift_right(atom_exec_context *ctx, int *ptr, int arg)
0906 {
0907     uint8_t attr = U8((*ptr)++), shift;
0908     uint32_t saved, dst;
0909     int dptr = *ptr;
0910     attr &= 0x38;
0911     attr |= atom_def_dst[attr >> 3] << 6;
0912     SDEBUG("   dst: ");
0913     dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
0914     shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr);
0915     SDEBUG("   shift: %d\n", shift);
0916     dst >>= shift;
0917     SDEBUG("   dst: ");
0918     atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
0919 }
0920 
0921 static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg)
0922 {
0923     uint8_t attr = U8((*ptr)++), shift;
0924     uint32_t saved, dst;
0925     int dptr = *ptr;
0926     uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3];
0927     SDEBUG("   dst: ");
0928     dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
0929     /* op needs to full dst value */
0930     dst = saved;
0931     shift = atom_get_src(ctx, attr, ptr);
0932     SDEBUG("   shift: %d\n", shift);
0933     dst <<= shift;
0934     dst &= atom_arg_mask[dst_align];
0935     dst >>= atom_arg_shift[dst_align];
0936     SDEBUG("   dst: ");
0937     atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
0938 }
0939 
0940 static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg)
0941 {
0942     uint8_t attr = U8((*ptr)++), shift;
0943     uint32_t saved, dst;
0944     int dptr = *ptr;
0945     uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3];
0946     SDEBUG("   dst: ");
0947     dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
0948     /* op needs to full dst value */
0949     dst = saved;
0950     shift = atom_get_src(ctx, attr, ptr);
0951     SDEBUG("   shift: %d\n", shift);
0952     dst >>= shift;
0953     dst &= atom_arg_mask[dst_align];
0954     dst >>= atom_arg_shift[dst_align];
0955     SDEBUG("   dst: ");
0956     atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
0957 }
0958 
0959 static void atom_op_sub(atom_exec_context *ctx, int *ptr, int arg)
0960 {
0961     uint8_t attr = U8((*ptr)++);
0962     uint32_t dst, src, saved;
0963     int dptr = *ptr;
0964     SDEBUG("   dst: ");
0965     dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
0966     SDEBUG("   src: ");
0967     src = atom_get_src(ctx, attr, ptr);
0968     dst -= src;
0969     SDEBUG("   dst: ");
0970     atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
0971 }
0972 
0973 static void atom_op_switch(atom_exec_context *ctx, int *ptr, int arg)
0974 {
0975     uint8_t attr = U8((*ptr)++);
0976     uint32_t src, val, target;
0977     SDEBUG("   switch: ");
0978     src = atom_get_src(ctx, attr, ptr);
0979     while (U16(*ptr) != ATOM_CASE_END)
0980         if (U8(*ptr) == ATOM_CASE_MAGIC) {
0981             (*ptr)++;
0982             SDEBUG("   case: ");
0983             val =
0984                 atom_get_src(ctx, (attr & 0x38) | ATOM_ARG_IMM,
0985                      ptr);
0986             target = U16(*ptr);
0987             if (val == src) {
0988                 SDEBUG("   target: %04X\n", target);
0989                 *ptr = ctx->start + target;
0990                 return;
0991             }
0992             (*ptr) += 2;
0993         } else {
0994             pr_info("Bad case\n");
0995             return;
0996         }
0997     (*ptr) += 2;
0998 }
0999 
1000 static void atom_op_test(atom_exec_context *ctx, int *ptr, int arg)
1001 {
1002     uint8_t attr = U8((*ptr)++);
1003     uint32_t dst, src;
1004     SDEBUG("   src1: ");
1005     dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
1006     SDEBUG("   src2: ");
1007     src = atom_get_src(ctx, attr, ptr);
1008     ctx->ctx->cs_equal = ((dst & src) == 0);
1009     SDEBUG("   result: %s\n", ctx->ctx->cs_equal ? "EQ" : "NE");
1010 }
1011 
1012 static void atom_op_xor(atom_exec_context *ctx, int *ptr, int arg)
1013 {
1014     uint8_t attr = U8((*ptr)++);
1015     uint32_t dst, src, saved;
1016     int dptr = *ptr;
1017     SDEBUG("   dst: ");
1018     dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
1019     SDEBUG("   src: ");
1020     src = atom_get_src(ctx, attr, ptr);
1021     dst ^= src;
1022     SDEBUG("   dst: ");
1023     atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
1024 }
1025 
1026 static void atom_op_debug(atom_exec_context *ctx, int *ptr, int arg)
1027 {
1028     pr_info("unimplemented!\n");
1029 }
1030 
1031 static struct {
1032     void (*func) (atom_exec_context *, int *, int);
1033     int arg;
1034 } opcode_table[ATOM_OP_CNT] = {
1035     {
1036     NULL, 0}, {
1037     atom_op_move, ATOM_ARG_REG}, {
1038     atom_op_move, ATOM_ARG_PS}, {
1039     atom_op_move, ATOM_ARG_WS}, {
1040     atom_op_move, ATOM_ARG_FB}, {
1041     atom_op_move, ATOM_ARG_PLL}, {
1042     atom_op_move, ATOM_ARG_MC}, {
1043     atom_op_and, ATOM_ARG_REG}, {
1044     atom_op_and, ATOM_ARG_PS}, {
1045     atom_op_and, ATOM_ARG_WS}, {
1046     atom_op_and, ATOM_ARG_FB}, {
1047     atom_op_and, ATOM_ARG_PLL}, {
1048     atom_op_and, ATOM_ARG_MC}, {
1049     atom_op_or, ATOM_ARG_REG}, {
1050     atom_op_or, ATOM_ARG_PS}, {
1051     atom_op_or, ATOM_ARG_WS}, {
1052     atom_op_or, ATOM_ARG_FB}, {
1053     atom_op_or, ATOM_ARG_PLL}, {
1054     atom_op_or, ATOM_ARG_MC}, {
1055     atom_op_shift_left, ATOM_ARG_REG}, {
1056     atom_op_shift_left, ATOM_ARG_PS}, {
1057     atom_op_shift_left, ATOM_ARG_WS}, {
1058     atom_op_shift_left, ATOM_ARG_FB}, {
1059     atom_op_shift_left, ATOM_ARG_PLL}, {
1060     atom_op_shift_left, ATOM_ARG_MC}, {
1061     atom_op_shift_right, ATOM_ARG_REG}, {
1062     atom_op_shift_right, ATOM_ARG_PS}, {
1063     atom_op_shift_right, ATOM_ARG_WS}, {
1064     atom_op_shift_right, ATOM_ARG_FB}, {
1065     atom_op_shift_right, ATOM_ARG_PLL}, {
1066     atom_op_shift_right, ATOM_ARG_MC}, {
1067     atom_op_mul, ATOM_ARG_REG}, {
1068     atom_op_mul, ATOM_ARG_PS}, {
1069     atom_op_mul, ATOM_ARG_WS}, {
1070     atom_op_mul, ATOM_ARG_FB}, {
1071     atom_op_mul, ATOM_ARG_PLL}, {
1072     atom_op_mul, ATOM_ARG_MC}, {
1073     atom_op_div, ATOM_ARG_REG}, {
1074     atom_op_div, ATOM_ARG_PS}, {
1075     atom_op_div, ATOM_ARG_WS}, {
1076     atom_op_div, ATOM_ARG_FB}, {
1077     atom_op_div, ATOM_ARG_PLL}, {
1078     atom_op_div, ATOM_ARG_MC}, {
1079     atom_op_add, ATOM_ARG_REG}, {
1080     atom_op_add, ATOM_ARG_PS}, {
1081     atom_op_add, ATOM_ARG_WS}, {
1082     atom_op_add, ATOM_ARG_FB}, {
1083     atom_op_add, ATOM_ARG_PLL}, {
1084     atom_op_add, ATOM_ARG_MC}, {
1085     atom_op_sub, ATOM_ARG_REG}, {
1086     atom_op_sub, ATOM_ARG_PS}, {
1087     atom_op_sub, ATOM_ARG_WS}, {
1088     atom_op_sub, ATOM_ARG_FB}, {
1089     atom_op_sub, ATOM_ARG_PLL}, {
1090     atom_op_sub, ATOM_ARG_MC}, {
1091     atom_op_setport, ATOM_PORT_ATI}, {
1092     atom_op_setport, ATOM_PORT_PCI}, {
1093     atom_op_setport, ATOM_PORT_SYSIO}, {
1094     atom_op_setregblock, 0}, {
1095     atom_op_setfbbase, 0}, {
1096     atom_op_compare, ATOM_ARG_REG}, {
1097     atom_op_compare, ATOM_ARG_PS}, {
1098     atom_op_compare, ATOM_ARG_WS}, {
1099     atom_op_compare, ATOM_ARG_FB}, {
1100     atom_op_compare, ATOM_ARG_PLL}, {
1101     atom_op_compare, ATOM_ARG_MC}, {
1102     atom_op_switch, 0}, {
1103     atom_op_jump, ATOM_COND_ALWAYS}, {
1104     atom_op_jump, ATOM_COND_EQUAL}, {
1105     atom_op_jump, ATOM_COND_BELOW}, {
1106     atom_op_jump, ATOM_COND_ABOVE}, {
1107     atom_op_jump, ATOM_COND_BELOWOREQUAL}, {
1108     atom_op_jump, ATOM_COND_ABOVEOREQUAL}, {
1109     atom_op_jump, ATOM_COND_NOTEQUAL}, {
1110     atom_op_test, ATOM_ARG_REG}, {
1111     atom_op_test, ATOM_ARG_PS}, {
1112     atom_op_test, ATOM_ARG_WS}, {
1113     atom_op_test, ATOM_ARG_FB}, {
1114     atom_op_test, ATOM_ARG_PLL}, {
1115     atom_op_test, ATOM_ARG_MC}, {
1116     atom_op_delay, ATOM_UNIT_MILLISEC}, {
1117     atom_op_delay, ATOM_UNIT_MICROSEC}, {
1118     atom_op_calltable, 0}, {
1119     atom_op_repeat, 0}, {
1120     atom_op_clear, ATOM_ARG_REG}, {
1121     atom_op_clear, ATOM_ARG_PS}, {
1122     atom_op_clear, ATOM_ARG_WS}, {
1123     atom_op_clear, ATOM_ARG_FB}, {
1124     atom_op_clear, ATOM_ARG_PLL}, {
1125     atom_op_clear, ATOM_ARG_MC}, {
1126     atom_op_nop, 0}, {
1127     atom_op_eot, 0}, {
1128     atom_op_mask, ATOM_ARG_REG}, {
1129     atom_op_mask, ATOM_ARG_PS}, {
1130     atom_op_mask, ATOM_ARG_WS}, {
1131     atom_op_mask, ATOM_ARG_FB}, {
1132     atom_op_mask, ATOM_ARG_PLL}, {
1133     atom_op_mask, ATOM_ARG_MC}, {
1134     atom_op_postcard, 0}, {
1135     atom_op_beep, 0}, {
1136     atom_op_savereg, 0}, {
1137     atom_op_restorereg, 0}, {
1138     atom_op_setdatablock, 0}, {
1139     atom_op_xor, ATOM_ARG_REG}, {
1140     atom_op_xor, ATOM_ARG_PS}, {
1141     atom_op_xor, ATOM_ARG_WS}, {
1142     atom_op_xor, ATOM_ARG_FB}, {
1143     atom_op_xor, ATOM_ARG_PLL}, {
1144     atom_op_xor, ATOM_ARG_MC}, {
1145     atom_op_shl, ATOM_ARG_REG}, {
1146     atom_op_shl, ATOM_ARG_PS}, {
1147     atom_op_shl, ATOM_ARG_WS}, {
1148     atom_op_shl, ATOM_ARG_FB}, {
1149     atom_op_shl, ATOM_ARG_PLL}, {
1150     atom_op_shl, ATOM_ARG_MC}, {
1151     atom_op_shr, ATOM_ARG_REG}, {
1152     atom_op_shr, ATOM_ARG_PS}, {
1153     atom_op_shr, ATOM_ARG_WS}, {
1154     atom_op_shr, ATOM_ARG_FB}, {
1155     atom_op_shr, ATOM_ARG_PLL}, {
1156     atom_op_shr, ATOM_ARG_MC}, {
1157 atom_op_debug, 0},};
1158 
1159 static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params)
1160 {
1161     int base = CU16(ctx->cmd_table + 4 + 2 * index);
1162     int len, ws, ps, ptr;
1163     unsigned char op;
1164     atom_exec_context ectx;
1165     int ret = 0;
1166 
1167     if (!base)
1168         return -EINVAL;
1169 
1170     len = CU16(base + ATOM_CT_SIZE_PTR);
1171     ws = CU8(base + ATOM_CT_WS_PTR);
1172     ps = CU8(base + ATOM_CT_PS_PTR) & ATOM_CT_PS_MASK;
1173     ptr = base + ATOM_CT_CODE_PTR;
1174 
1175     SDEBUG(">> execute %04X (len %d, WS %d, PS %d)\n", base, len, ws, ps);
1176 
1177     ectx.ctx = ctx;
1178     ectx.ps_shift = ps / 4;
1179     ectx.start = base;
1180     ectx.ps = params;
1181     ectx.abort = false;
1182     ectx.last_jump = 0;
1183     if (ws)
1184         ectx.ws = kcalloc(4, ws, GFP_KERNEL);
1185     else
1186         ectx.ws = NULL;
1187 
1188     debug_depth++;
1189     while (1) {
1190         op = CU8(ptr++);
1191         if (op < ATOM_OP_NAMES_CNT)
1192             SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr - 1);
1193         else
1194             SDEBUG("[%d] @ 0x%04X\n", op, ptr - 1);
1195         if (ectx.abort) {
1196             DRM_ERROR("atombios stuck executing %04X (len %d, WS %d, PS %d) @ 0x%04X\n",
1197                 base, len, ws, ps, ptr - 1);
1198             ret = -EINVAL;
1199             goto free;
1200         }
1201 
1202         if (op < ATOM_OP_CNT && op > 0)
1203             opcode_table[op].func(&ectx, &ptr,
1204                           opcode_table[op].arg);
1205         else
1206             break;
1207 
1208         if (op == ATOM_OP_EOT)
1209             break;
1210     }
1211     debug_depth--;
1212     SDEBUG("<<\n");
1213 
1214 free:
1215     kfree(ectx.ws);
1216     return ret;
1217 }
1218 
1219 int atom_execute_table_scratch_unlocked(struct atom_context *ctx, int index, uint32_t * params)
1220 {
1221     int r;
1222 
1223     mutex_lock(&ctx->mutex);
1224     /* reset data block */
1225     ctx->data_block = 0;
1226     /* reset reg block */
1227     ctx->reg_block = 0;
1228     /* reset fb window */
1229     ctx->fb_base = 0;
1230     /* reset io mode */
1231     ctx->io_mode = ATOM_IO_MM;
1232     /* reset divmul */
1233     ctx->divmul[0] = 0;
1234     ctx->divmul[1] = 0;
1235     r = atom_execute_table_locked(ctx, index, params);
1236     mutex_unlock(&ctx->mutex);
1237     return r;
1238 }
1239 
1240 int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
1241 {
1242     int r;
1243     mutex_lock(&ctx->scratch_mutex);
1244     r = atom_execute_table_scratch_unlocked(ctx, index, params);
1245     mutex_unlock(&ctx->scratch_mutex);
1246     return r;
1247 }
1248 
1249 static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 };
1250 
1251 static void atom_index_iio(struct atom_context *ctx, int base)
1252 {
1253     ctx->iio = kzalloc(2 * 256, GFP_KERNEL);
1254     if (!ctx->iio)
1255         return;
1256     while (CU8(base) == ATOM_IIO_START) {
1257         ctx->iio[CU8(base + 1)] = base + 2;
1258         base += 2;
1259         while (CU8(base) != ATOM_IIO_END)
1260             base += atom_iio_len[CU8(base)];
1261         base += 3;
1262     }
1263 }
1264 
1265 struct atom_context *atom_parse(struct card_info *card, void *bios)
1266 {
1267     int base;
1268     struct atom_context *ctx =
1269         kzalloc(sizeof(struct atom_context), GFP_KERNEL);
1270     char *str;
1271     char name[512];
1272     int i;
1273 
1274     if (!ctx)
1275         return NULL;
1276 
1277     ctx->card = card;
1278     ctx->bios = bios;
1279 
1280     if (CU16(0) != ATOM_BIOS_MAGIC) {
1281         pr_info("Invalid BIOS magic\n");
1282         kfree(ctx);
1283         return NULL;
1284     }
1285     if (strncmp
1286         (CSTR(ATOM_ATI_MAGIC_PTR), ATOM_ATI_MAGIC,
1287          strlen(ATOM_ATI_MAGIC))) {
1288         pr_info("Invalid ATI magic\n");
1289         kfree(ctx);
1290         return NULL;
1291     }
1292 
1293     base = CU16(ATOM_ROM_TABLE_PTR);
1294     if (strncmp
1295         (CSTR(base + ATOM_ROM_MAGIC_PTR), ATOM_ROM_MAGIC,
1296          strlen(ATOM_ROM_MAGIC))) {
1297         pr_info("Invalid ATOM magic\n");
1298         kfree(ctx);
1299         return NULL;
1300     }
1301 
1302     ctx->cmd_table = CU16(base + ATOM_ROM_CMD_PTR);
1303     ctx->data_table = CU16(base + ATOM_ROM_DATA_PTR);
1304     atom_index_iio(ctx, CU16(ctx->data_table + ATOM_DATA_IIO_PTR) + 4);
1305     if (!ctx->iio) {
1306         atom_destroy(ctx);
1307         return NULL;
1308     }
1309 
1310     str = CSTR(CU16(base + ATOM_ROM_MSG_PTR));
1311     while (*str && ((*str == '\n') || (*str == '\r')))
1312         str++;
1313     /* name string isn't always 0 terminated */
1314     for (i = 0; i < 511; i++) {
1315         name[i] = str[i];
1316         if (name[i] < '.' || name[i] > 'z') {
1317             name[i] = 0;
1318             break;
1319         }
1320     }
1321     pr_info("ATOM BIOS: %s\n", name);
1322 
1323     return ctx;
1324 }
1325 
1326 int atom_asic_init(struct atom_context *ctx)
1327 {
1328     struct radeon_device *rdev = ctx->card->dev->dev_private;
1329     int hwi = CU16(ctx->data_table + ATOM_DATA_FWI_PTR);
1330     uint32_t ps[16];
1331     int ret;
1332 
1333     memset(ps, 0, 64);
1334 
1335     ps[0] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFSCLK_PTR));
1336     ps[1] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFMCLK_PTR));
1337     if (!ps[0] || !ps[1])
1338         return 1;
1339 
1340     if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT))
1341         return 1;
1342     ret = atom_execute_table(ctx, ATOM_CMD_INIT, ps);
1343     if (ret)
1344         return ret;
1345 
1346     memset(ps, 0, 64);
1347 
1348     if (rdev->family < CHIP_R600) {
1349         if (CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_SPDFANCNTL))
1350             atom_execute_table(ctx, ATOM_CMD_SPDFANCNTL, ps);
1351     }
1352     return ret;
1353 }
1354 
1355 void atom_destroy(struct atom_context *ctx)
1356 {
1357     kfree(ctx->iio);
1358     kfree(ctx);
1359 }
1360 
1361 bool atom_parse_data_header(struct atom_context *ctx, int index,
1362                 uint16_t * size, uint8_t * frev, uint8_t * crev,
1363                 uint16_t * data_start)
1364 {
1365     int offset = index * 2 + 4;
1366     int idx = CU16(ctx->data_table + offset);
1367     u16 *mdt = (u16 *)(ctx->bios + ctx->data_table + 4);
1368 
1369     if (!mdt[index])
1370         return false;
1371 
1372     if (size)
1373         *size = CU16(idx);
1374     if (frev)
1375         *frev = CU8(idx + 2);
1376     if (crev)
1377         *crev = CU8(idx + 3);
1378     *data_start = idx;
1379     return true;
1380 }
1381 
1382 bool atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t * frev,
1383                uint8_t * crev)
1384 {
1385     int offset = index * 2 + 4;
1386     int idx = CU16(ctx->cmd_table + offset);
1387     u16 *mct = (u16 *)(ctx->bios + ctx->cmd_table + 4);
1388 
1389     if (!mct[index])
1390         return false;
1391 
1392     if (frev)
1393         *frev = CU8(idx + 2);
1394     if (crev)
1395         *crev = CU8(idx + 3);
1396     return true;
1397 }
1398 
1399 int atom_allocate_fb_scratch(struct atom_context *ctx)
1400 {
1401     int index = GetIndexIntoMasterTable(DATA, VRAM_UsageByFirmware);
1402     uint16_t data_offset;
1403     int usage_bytes = 0;
1404     struct _ATOM_VRAM_USAGE_BY_FIRMWARE *firmware_usage;
1405 
1406     if (atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset)) {
1407         firmware_usage = (struct _ATOM_VRAM_USAGE_BY_FIRMWARE *)(ctx->bios + data_offset);
1408 
1409         DRM_DEBUG("atom firmware requested %08x %dkb\n",
1410               le32_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware),
1411               le16_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb));
1412 
1413         usage_bytes = le16_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb) * 1024;
1414     }
1415     ctx->scratch_size_bytes = 0;
1416     if (usage_bytes == 0)
1417         usage_bytes = 20 * 1024;
1418     /* allocate some scratch memory */
1419     ctx->scratch = kzalloc(usage_bytes, GFP_KERNEL);
1420     if (!ctx->scratch)
1421         return -ENOMEM;
1422     ctx->scratch_size_bytes = usage_bytes;
1423     return 0;
1424 }