LCOV - code coverage report
Current view: top level - drivers/gpu/drm/amd/amdgpu - atom.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 835 0.0 %
Date: 2022-12-09 01:23:36 Functions: 0 53 0.0 %

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

Generated by: LCOV version 1.14