LCOV - code coverage report
Current view: top level - dev/pci/drm/radeon - atom.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 797 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 51 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13