cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

atom.c (35383B)


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