11099013bSjsg /*
21099013bSjsg * Copyright 2008 Advanced Micro Devices, Inc.
31099013bSjsg *
41099013bSjsg * Permission is hereby granted, free of charge, to any person obtaining a
51099013bSjsg * copy of this software and associated documentation files (the "Software"),
61099013bSjsg * to deal in the Software without restriction, including without limitation
71099013bSjsg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
81099013bSjsg * and/or sell copies of the Software, and to permit persons to whom the
91099013bSjsg * Software is furnished to do so, subject to the following conditions:
101099013bSjsg *
111099013bSjsg * The above copyright notice and this permission notice shall be included in
121099013bSjsg * all copies or substantial portions of the Software.
131099013bSjsg *
141099013bSjsg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
151099013bSjsg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
161099013bSjsg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
171099013bSjsg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
181099013bSjsg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
191099013bSjsg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
201099013bSjsg * OTHER DEALINGS IN THE SOFTWARE.
211099013bSjsg *
221099013bSjsg * Author: Stanislaw Skowronek
231099013bSjsg */
241099013bSjsg
257f4dd379Sjsg #include <linux/module.h>
267f4dd379Sjsg #include <linux/sched.h>
277f4dd379Sjsg #include <linux/slab.h>
281bb76ff1Sjsg #include <linux/string_helpers.h>
29c349dbc7Sjsg
307f4dd379Sjsg #include <asm/unaligned.h>
317f4dd379Sjsg
32c349dbc7Sjsg #include <drm/drm_device.h>
33c349dbc7Sjsg #include <drm/drm_util.h>
34c349dbc7Sjsg
351099013bSjsg #define ATOM_DEBUG
361099013bSjsg
371099013bSjsg #include "atom.h"
381099013bSjsg #include "atom-names.h"
391099013bSjsg #include "atom-bits.h"
401099013bSjsg #include "radeon.h"
411099013bSjsg
421099013bSjsg #define ATOM_COND_ABOVE 0
431099013bSjsg #define ATOM_COND_ABOVEOREQUAL 1
441099013bSjsg #define ATOM_COND_ALWAYS 2
451099013bSjsg #define ATOM_COND_BELOW 3
461099013bSjsg #define ATOM_COND_BELOWOREQUAL 4
471099013bSjsg #define ATOM_COND_EQUAL 5
481099013bSjsg #define ATOM_COND_NOTEQUAL 6
491099013bSjsg
501099013bSjsg #define ATOM_PORT_ATI 0
511099013bSjsg #define ATOM_PORT_PCI 1
521099013bSjsg #define ATOM_PORT_SYSIO 2
531099013bSjsg
541099013bSjsg #define ATOM_UNIT_MICROSEC 0
551099013bSjsg #define ATOM_UNIT_MILLISEC 1
561099013bSjsg
571099013bSjsg #define PLL_INDEX 2
581099013bSjsg #define PLL_DATA 3
591099013bSjsg
601099013bSjsg typedef struct {
611099013bSjsg struct atom_context *ctx;
621099013bSjsg uint32_t *ps, *ws;
631099013bSjsg int ps_shift;
641099013bSjsg uint16_t start;
651099013bSjsg unsigned last_jump;
661099013bSjsg unsigned long last_jump_jiffies;
671099013bSjsg bool abort;
681099013bSjsg } atom_exec_context;
691099013bSjsg
701099013bSjsg int atom_debug = 0;
711099013bSjsg static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t *params);
721099013bSjsg int atom_execute_table(struct atom_context *ctx, int index, uint32_t *params);
731099013bSjsg
747f4dd379Sjsg static uint32_t atom_arg_mask[8] = {
757f4dd379Sjsg 0xFFFFFFFF, 0x0000FFFF, 0x00FFFF00, 0xFFFF0000,
767f4dd379Sjsg 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000
777f4dd379Sjsg };
781099013bSjsg static int atom_arg_shift[8] = { 0, 0, 8, 16, 0, 8, 16, 24 };
791099013bSjsg
801099013bSjsg static int atom_dst_to_src[8][4] = {
811099013bSjsg /* translate destination alignment field to the source alignment encoding */
821099013bSjsg {0, 0, 0, 0},
831099013bSjsg {1, 2, 3, 0},
841099013bSjsg {1, 2, 3, 0},
851099013bSjsg {1, 2, 3, 0},
861099013bSjsg {4, 5, 6, 7},
871099013bSjsg {4, 5, 6, 7},
881099013bSjsg {4, 5, 6, 7},
891099013bSjsg {4, 5, 6, 7},
901099013bSjsg };
911099013bSjsg static int atom_def_dst[8] = { 0, 0, 1, 2, 0, 1, 2, 3 };
921099013bSjsg
931099013bSjsg static int debug_depth = 0;
941099013bSjsg #ifdef ATOM_DEBUG
debug_print_spaces(int n)951099013bSjsg static void debug_print_spaces(int n)
961099013bSjsg {
971099013bSjsg while (n--)
98d765308cSjsg printk(" ");
991099013bSjsg }
1001099013bSjsg
101f5af14d6Sjsg #ifdef DEBUG
102f5af14d6Sjsg #undef DEBUG
103f5af14d6Sjsg #endif
104f5af14d6Sjsg
1057ccd5a2cSjsg #define DEBUG(...) do if (atom_debug) { printk(KERN_DEBUG __VA_ARGS__); } while (0)
1067ccd5a2cSjsg #define SDEBUG(...) do if (atom_debug) { printk(KERN_DEBUG); debug_print_spaces(debug_depth); printk(__VA_ARGS__); } while (0)
1071099013bSjsg #else
1081099013bSjsg #define DEBUG(...) do { } while (0)
1091099013bSjsg #define SDEBUG(...) do { } while (0)
1101099013bSjsg #endif
1111099013bSjsg
atom_iio_execute(struct atom_context * ctx,int base,uint32_t index,uint32_t data)1121099013bSjsg static uint32_t atom_iio_execute(struct atom_context *ctx, int base,
1131099013bSjsg uint32_t index, uint32_t data)
1141099013bSjsg {
1151099013bSjsg struct radeon_device *rdev = ctx->card->dev->dev_private;
1161099013bSjsg uint32_t temp = 0xCDCDCDCD;
1171099013bSjsg
1181099013bSjsg while (1)
1191099013bSjsg switch (CU8(base)) {
1201099013bSjsg case ATOM_IIO_NOP:
1211099013bSjsg base++;
1221099013bSjsg break;
1231099013bSjsg case ATOM_IIO_READ:
1241099013bSjsg temp = ctx->card->ioreg_read(ctx->card, CU16(base + 1));
1251099013bSjsg base += 3;
1261099013bSjsg break;
1271099013bSjsg case ATOM_IIO_WRITE:
1281099013bSjsg if (rdev->family == CHIP_RV515)
1291099013bSjsg (void)ctx->card->ioreg_read(ctx->card, CU16(base + 1));
1301099013bSjsg ctx->card->ioreg_write(ctx->card, CU16(base + 1), temp);
1311099013bSjsg base += 3;
1321099013bSjsg break;
1331099013bSjsg case ATOM_IIO_CLEAR:
1341099013bSjsg temp &=
1351099013bSjsg ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
1361099013bSjsg CU8(base + 2));
1371099013bSjsg base += 3;
1381099013bSjsg break;
1391099013bSjsg case ATOM_IIO_SET:
1401099013bSjsg temp |=
1411099013bSjsg (0xFFFFFFFF >> (32 - CU8(base + 1))) << CU8(base +
1421099013bSjsg 2);
1431099013bSjsg base += 3;
1441099013bSjsg break;
1451099013bSjsg case ATOM_IIO_MOVE_INDEX:
1461099013bSjsg temp &=
1471099013bSjsg ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
1481099013bSjsg CU8(base + 3));
1491099013bSjsg temp |=
1501099013bSjsg ((index >> CU8(base + 2)) &
1511099013bSjsg (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base +
1521099013bSjsg 3);
1531099013bSjsg base += 4;
1541099013bSjsg break;
1551099013bSjsg case ATOM_IIO_MOVE_DATA:
1561099013bSjsg temp &=
1571099013bSjsg ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
1581099013bSjsg CU8(base + 3));
1591099013bSjsg temp |=
1601099013bSjsg ((data >> CU8(base + 2)) &
1611099013bSjsg (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base +
1621099013bSjsg 3);
1631099013bSjsg base += 4;
1641099013bSjsg break;
1651099013bSjsg case ATOM_IIO_MOVE_ATTR:
1661099013bSjsg temp &=
1671099013bSjsg ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
1681099013bSjsg CU8(base + 3));
1691099013bSjsg temp |=
170*f005ef32Sjsg ((ctx->io_attr >> CU8(base + 2)) &
171*f005ef32Sjsg (0xFFFFFFFF >> (32 - CU8(base + 1)))) <<
172*f005ef32Sjsg CU8(base + 3);
1731099013bSjsg base += 4;
1741099013bSjsg break;
1751099013bSjsg case ATOM_IIO_END:
1761099013bSjsg return temp;
1771099013bSjsg default:
1787f4dd379Sjsg pr_info("Unknown IIO opcode\n");
1791099013bSjsg return 0;
1801099013bSjsg }
1811099013bSjsg }
1821099013bSjsg
atom_get_src_int(atom_exec_context * ctx,uint8_t attr,int * ptr,uint32_t * saved,int print)1831099013bSjsg static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr,
1841099013bSjsg int *ptr, uint32_t *saved, int print)
1851099013bSjsg {
1861099013bSjsg uint32_t idx, val = 0xCDCDCDCD, align, arg;
1871099013bSjsg struct atom_context *gctx = ctx->ctx;
1881099013bSjsg arg = attr & 7;
1891099013bSjsg align = (attr >> 3) & 7;
1901099013bSjsg switch (arg) {
1911099013bSjsg case ATOM_ARG_REG:
1921099013bSjsg idx = U16(*ptr);
1931099013bSjsg (*ptr) += 2;
1941099013bSjsg if (print)
1951099013bSjsg DEBUG("REG[0x%04X]", idx);
1961099013bSjsg idx += gctx->reg_block;
1971099013bSjsg switch (gctx->io_mode) {
1981099013bSjsg case ATOM_IO_MM:
1991099013bSjsg val = gctx->card->reg_read(gctx->card, idx);
2001099013bSjsg break;
2011099013bSjsg case ATOM_IO_PCI:
2027f4dd379Sjsg pr_info("PCI registers are not implemented\n");
2031099013bSjsg return 0;
2041099013bSjsg case ATOM_IO_SYSIO:
2057f4dd379Sjsg pr_info("SYSIO registers are not implemented\n");
2061099013bSjsg return 0;
2071099013bSjsg default:
2081099013bSjsg if (!(gctx->io_mode & 0x80)) {
2097f4dd379Sjsg pr_info("Bad IO mode\n");
2101099013bSjsg return 0;
2111099013bSjsg }
2121099013bSjsg if (!gctx->iio[gctx->io_mode & 0x7F]) {
2137f4dd379Sjsg pr_info("Undefined indirect IO read method %d\n",
2141099013bSjsg gctx->io_mode & 0x7F);
2151099013bSjsg return 0;
2161099013bSjsg }
2171099013bSjsg val =
2181099013bSjsg atom_iio_execute(gctx,
2191099013bSjsg gctx->iio[gctx->io_mode & 0x7F],
2201099013bSjsg idx, 0);
2211099013bSjsg }
2221099013bSjsg break;
2231099013bSjsg case ATOM_ARG_PS:
2241099013bSjsg idx = U8(*ptr);
2251099013bSjsg (*ptr)++;
2261099013bSjsg /* get_unaligned_le32 avoids unaligned accesses from atombios
2271099013bSjsg * tables, noticed on a DEC Alpha. */
2281099013bSjsg val = get_unaligned_le32((u32 *)&ctx->ps[idx]);
2291099013bSjsg if (print)
2301099013bSjsg DEBUG("PS[0x%02X,0x%04X]", idx, val);
2311099013bSjsg break;
2321099013bSjsg case ATOM_ARG_WS:
2331099013bSjsg idx = U8(*ptr);
2341099013bSjsg (*ptr)++;
2351099013bSjsg if (print)
2361099013bSjsg DEBUG("WS[0x%02X]", idx);
2371099013bSjsg switch (idx) {
2381099013bSjsg case ATOM_WS_QUOTIENT:
2391099013bSjsg val = gctx->divmul[0];
2401099013bSjsg break;
2411099013bSjsg case ATOM_WS_REMAINDER:
2421099013bSjsg val = gctx->divmul[1];
2431099013bSjsg break;
2441099013bSjsg case ATOM_WS_DATAPTR:
2451099013bSjsg val = gctx->data_block;
2461099013bSjsg break;
2471099013bSjsg case ATOM_WS_SHIFT:
2481099013bSjsg val = gctx->shift;
2491099013bSjsg break;
2501099013bSjsg case ATOM_WS_OR_MASK:
2511099013bSjsg val = 1 << gctx->shift;
2521099013bSjsg break;
2531099013bSjsg case ATOM_WS_AND_MASK:
2541099013bSjsg val = ~(1 << gctx->shift);
2551099013bSjsg break;
2561099013bSjsg case ATOM_WS_FB_WINDOW:
2571099013bSjsg val = gctx->fb_base;
2581099013bSjsg break;
2591099013bSjsg case ATOM_WS_ATTRIBUTES:
2601099013bSjsg val = gctx->io_attr;
2611099013bSjsg break;
2621099013bSjsg case ATOM_WS_REGPTR:
2631099013bSjsg val = gctx->reg_block;
2641099013bSjsg break;
2651099013bSjsg default:
2661099013bSjsg val = ctx->ws[idx];
2671099013bSjsg }
2681099013bSjsg break;
2691099013bSjsg case ATOM_ARG_ID:
2701099013bSjsg idx = U16(*ptr);
2711099013bSjsg (*ptr) += 2;
2721099013bSjsg if (print) {
2731099013bSjsg if (gctx->data_block)
2741099013bSjsg DEBUG("ID[0x%04X+%04X]", idx, gctx->data_block);
2751099013bSjsg else
2761099013bSjsg DEBUG("ID[0x%04X]", idx);
2771099013bSjsg }
2781099013bSjsg val = U32(idx + gctx->data_block);
2791099013bSjsg break;
2801099013bSjsg case ATOM_ARG_FB:
2811099013bSjsg idx = U8(*ptr);
2821099013bSjsg (*ptr)++;
2831099013bSjsg if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) {
2841099013bSjsg DRM_ERROR("ATOM: fb read beyond scratch region: %d vs. %d\n",
2851099013bSjsg gctx->fb_base + (idx * 4), gctx->scratch_size_bytes);
2861099013bSjsg val = 0;
2871099013bSjsg } else
2881099013bSjsg val = gctx->scratch[(gctx->fb_base / 4) + idx];
2891099013bSjsg if (print)
2901099013bSjsg DEBUG("FB[0x%02X]", idx);
2911099013bSjsg break;
2921099013bSjsg case ATOM_ARG_IMM:
2931099013bSjsg switch (align) {
2941099013bSjsg case ATOM_SRC_DWORD:
2951099013bSjsg val = U32(*ptr);
2961099013bSjsg (*ptr) += 4;
2971099013bSjsg if (print)
2981099013bSjsg DEBUG("IMM 0x%08X\n", val);
2991099013bSjsg return val;
3001099013bSjsg case ATOM_SRC_WORD0:
3011099013bSjsg case ATOM_SRC_WORD8:
3021099013bSjsg case ATOM_SRC_WORD16:
3031099013bSjsg val = U16(*ptr);
3041099013bSjsg (*ptr) += 2;
3051099013bSjsg if (print)
3061099013bSjsg DEBUG("IMM 0x%04X\n", val);
3071099013bSjsg return val;
3081099013bSjsg case ATOM_SRC_BYTE0:
3091099013bSjsg case ATOM_SRC_BYTE8:
3101099013bSjsg case ATOM_SRC_BYTE16:
3111099013bSjsg case ATOM_SRC_BYTE24:
3121099013bSjsg val = U8(*ptr);
3131099013bSjsg (*ptr)++;
3141099013bSjsg if (print)
3151099013bSjsg DEBUG("IMM 0x%02X\n", val);
3161099013bSjsg return val;
3171099013bSjsg }
3181099013bSjsg return 0;
3191099013bSjsg case ATOM_ARG_PLL:
3201099013bSjsg idx = U8(*ptr);
3211099013bSjsg (*ptr)++;
3221099013bSjsg if (print)
3231099013bSjsg DEBUG("PLL[0x%02X]", idx);
3241099013bSjsg val = gctx->card->pll_read(gctx->card, idx);
3251099013bSjsg break;
3261099013bSjsg case ATOM_ARG_MC:
3271099013bSjsg idx = U8(*ptr);
3281099013bSjsg (*ptr)++;
3291099013bSjsg if (print)
3301099013bSjsg DEBUG("MC[0x%02X]", idx);
3311099013bSjsg val = gctx->card->mc_read(gctx->card, idx);
3321099013bSjsg break;
3331099013bSjsg }
3341099013bSjsg if (saved)
3351099013bSjsg *saved = val;
3361099013bSjsg val &= atom_arg_mask[align];
3371099013bSjsg val >>= atom_arg_shift[align];
3381099013bSjsg if (print)
3391099013bSjsg switch (align) {
3401099013bSjsg case ATOM_SRC_DWORD:
3411099013bSjsg DEBUG(".[31:0] -> 0x%08X\n", val);
3421099013bSjsg break;
3431099013bSjsg case ATOM_SRC_WORD0:
3441099013bSjsg DEBUG(".[15:0] -> 0x%04X\n", val);
3451099013bSjsg break;
3461099013bSjsg case ATOM_SRC_WORD8:
3471099013bSjsg DEBUG(".[23:8] -> 0x%04X\n", val);
3481099013bSjsg break;
3491099013bSjsg case ATOM_SRC_WORD16:
3501099013bSjsg DEBUG(".[31:16] -> 0x%04X\n", val);
3511099013bSjsg break;
3521099013bSjsg case ATOM_SRC_BYTE0:
3531099013bSjsg DEBUG(".[7:0] -> 0x%02X\n", val);
3541099013bSjsg break;
3551099013bSjsg case ATOM_SRC_BYTE8:
3561099013bSjsg DEBUG(".[15:8] -> 0x%02X\n", val);
3571099013bSjsg break;
3581099013bSjsg case ATOM_SRC_BYTE16:
3591099013bSjsg DEBUG(".[23:16] -> 0x%02X\n", val);
3601099013bSjsg break;
3611099013bSjsg case ATOM_SRC_BYTE24:
3621099013bSjsg DEBUG(".[31:24] -> 0x%02X\n", val);
3631099013bSjsg break;
3641099013bSjsg }
3651099013bSjsg return val;
3661099013bSjsg }
3671099013bSjsg
atom_skip_src_int(atom_exec_context * ctx,uint8_t attr,int * ptr)3681099013bSjsg static void atom_skip_src_int(atom_exec_context *ctx, uint8_t attr, int *ptr)
3691099013bSjsg {
3701099013bSjsg uint32_t align = (attr >> 3) & 7, arg = attr & 7;
3711099013bSjsg switch (arg) {
3721099013bSjsg case ATOM_ARG_REG:
3731099013bSjsg case ATOM_ARG_ID:
3741099013bSjsg (*ptr) += 2;
3751099013bSjsg break;
3761099013bSjsg case ATOM_ARG_PLL:
3771099013bSjsg case ATOM_ARG_MC:
3781099013bSjsg case ATOM_ARG_PS:
3791099013bSjsg case ATOM_ARG_WS:
3801099013bSjsg case ATOM_ARG_FB:
3811099013bSjsg (*ptr)++;
3821099013bSjsg break;
3831099013bSjsg case ATOM_ARG_IMM:
3841099013bSjsg switch (align) {
3851099013bSjsg case ATOM_SRC_DWORD:
3861099013bSjsg (*ptr) += 4;
3871099013bSjsg return;
3881099013bSjsg case ATOM_SRC_WORD0:
3891099013bSjsg case ATOM_SRC_WORD8:
3901099013bSjsg case ATOM_SRC_WORD16:
3911099013bSjsg (*ptr) += 2;
3921099013bSjsg return;
3931099013bSjsg case ATOM_SRC_BYTE0:
3941099013bSjsg case ATOM_SRC_BYTE8:
3951099013bSjsg case ATOM_SRC_BYTE16:
3961099013bSjsg case ATOM_SRC_BYTE24:
3971099013bSjsg (*ptr)++;
3981099013bSjsg return;
3991099013bSjsg }
4001099013bSjsg return;
4011099013bSjsg }
4021099013bSjsg }
4031099013bSjsg
atom_get_src(atom_exec_context * ctx,uint8_t attr,int * ptr)4041099013bSjsg static uint32_t atom_get_src(atom_exec_context *ctx, uint8_t attr, int *ptr)
4051099013bSjsg {
4061099013bSjsg return atom_get_src_int(ctx, attr, ptr, NULL, 1);
4071099013bSjsg }
4081099013bSjsg
atom_get_src_direct(atom_exec_context * ctx,uint8_t align,int * ptr)4091099013bSjsg static uint32_t atom_get_src_direct(atom_exec_context *ctx, uint8_t align, int *ptr)
4101099013bSjsg {
4111099013bSjsg uint32_t val = 0xCDCDCDCD;
4121099013bSjsg
4131099013bSjsg switch (align) {
4141099013bSjsg case ATOM_SRC_DWORD:
4151099013bSjsg val = U32(*ptr);
4161099013bSjsg (*ptr) += 4;
4171099013bSjsg break;
4181099013bSjsg case ATOM_SRC_WORD0:
4191099013bSjsg case ATOM_SRC_WORD8:
4201099013bSjsg case ATOM_SRC_WORD16:
4211099013bSjsg val = U16(*ptr);
4221099013bSjsg (*ptr) += 2;
4231099013bSjsg break;
4241099013bSjsg case ATOM_SRC_BYTE0:
4251099013bSjsg case ATOM_SRC_BYTE8:
4261099013bSjsg case ATOM_SRC_BYTE16:
4271099013bSjsg case ATOM_SRC_BYTE24:
4281099013bSjsg val = U8(*ptr);
4291099013bSjsg (*ptr)++;
4301099013bSjsg break;
4311099013bSjsg }
4321099013bSjsg return val;
4331099013bSjsg }
4341099013bSjsg
atom_get_dst(atom_exec_context * ctx,int arg,uint8_t attr,int * ptr,uint32_t * saved,int print)4351099013bSjsg static uint32_t atom_get_dst(atom_exec_context *ctx, int arg, uint8_t attr,
4361099013bSjsg int *ptr, uint32_t *saved, int print)
4371099013bSjsg {
4381099013bSjsg return atom_get_src_int(ctx,
4391099013bSjsg arg | atom_dst_to_src[(attr >> 3) &
4401099013bSjsg 7][(attr >> 6) & 3] << 3,
4411099013bSjsg ptr, saved, print);
4421099013bSjsg }
4431099013bSjsg
atom_skip_dst(atom_exec_context * ctx,int arg,uint8_t attr,int * ptr)4441099013bSjsg static void atom_skip_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr)
4451099013bSjsg {
4461099013bSjsg atom_skip_src_int(ctx,
4471099013bSjsg arg | atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) &
4481099013bSjsg 3] << 3, ptr);
4491099013bSjsg }
4501099013bSjsg
atom_put_dst(atom_exec_context * ctx,int arg,uint8_t attr,int * ptr,uint32_t val,uint32_t saved)4511099013bSjsg static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr,
4521099013bSjsg int *ptr, uint32_t val, uint32_t saved)
4531099013bSjsg {
4541099013bSjsg uint32_t align =
4551099013bSjsg atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3], old_val =
4561099013bSjsg val, idx;
4571099013bSjsg struct atom_context *gctx = ctx->ctx;
4581099013bSjsg old_val &= atom_arg_mask[align] >> atom_arg_shift[align];
4591099013bSjsg val <<= atom_arg_shift[align];
4601099013bSjsg val &= atom_arg_mask[align];
4611099013bSjsg saved &= ~atom_arg_mask[align];
4621099013bSjsg val |= saved;
4631099013bSjsg switch (arg) {
4641099013bSjsg case ATOM_ARG_REG:
4651099013bSjsg idx = U16(*ptr);
4661099013bSjsg (*ptr) += 2;
4671099013bSjsg DEBUG("REG[0x%04X]", idx);
4681099013bSjsg idx += gctx->reg_block;
4691099013bSjsg switch (gctx->io_mode) {
4701099013bSjsg case ATOM_IO_MM:
4711099013bSjsg if (idx == 0)
4721099013bSjsg gctx->card->reg_write(gctx->card, idx,
4731099013bSjsg val << 2);
4741099013bSjsg else
4751099013bSjsg gctx->card->reg_write(gctx->card, idx, val);
4761099013bSjsg break;
4771099013bSjsg case ATOM_IO_PCI:
4787f4dd379Sjsg pr_info("PCI registers are not implemented\n");
4791099013bSjsg return;
4801099013bSjsg case ATOM_IO_SYSIO:
4817f4dd379Sjsg pr_info("SYSIO registers are not implemented\n");
4821099013bSjsg return;
4831099013bSjsg default:
4841099013bSjsg if (!(gctx->io_mode & 0x80)) {
4857f4dd379Sjsg pr_info("Bad IO mode\n");
4861099013bSjsg return;
4871099013bSjsg }
4881099013bSjsg if (!gctx->iio[gctx->io_mode & 0xFF]) {
4897f4dd379Sjsg pr_info("Undefined indirect IO write method %d\n",
4901099013bSjsg gctx->io_mode & 0x7F);
4911099013bSjsg return;
4921099013bSjsg }
4931099013bSjsg atom_iio_execute(gctx, gctx->iio[gctx->io_mode & 0xFF],
4941099013bSjsg idx, val);
4951099013bSjsg }
4961099013bSjsg break;
4971099013bSjsg case ATOM_ARG_PS:
4981099013bSjsg idx = U8(*ptr);
4991099013bSjsg (*ptr)++;
5001099013bSjsg DEBUG("PS[0x%02X]", idx);
5011099013bSjsg ctx->ps[idx] = cpu_to_le32(val);
5021099013bSjsg break;
5031099013bSjsg case ATOM_ARG_WS:
5041099013bSjsg idx = U8(*ptr);
5051099013bSjsg (*ptr)++;
5061099013bSjsg DEBUG("WS[0x%02X]", idx);
5071099013bSjsg switch (idx) {
5081099013bSjsg case ATOM_WS_QUOTIENT:
5091099013bSjsg gctx->divmul[0] = val;
5101099013bSjsg break;
5111099013bSjsg case ATOM_WS_REMAINDER:
5121099013bSjsg gctx->divmul[1] = val;
5131099013bSjsg break;
5141099013bSjsg case ATOM_WS_DATAPTR:
5151099013bSjsg gctx->data_block = val;
5161099013bSjsg break;
5171099013bSjsg case ATOM_WS_SHIFT:
5181099013bSjsg gctx->shift = val;
5191099013bSjsg break;
5201099013bSjsg case ATOM_WS_OR_MASK:
5211099013bSjsg case ATOM_WS_AND_MASK:
5221099013bSjsg break;
5231099013bSjsg case ATOM_WS_FB_WINDOW:
5241099013bSjsg gctx->fb_base = val;
5251099013bSjsg break;
5261099013bSjsg case ATOM_WS_ATTRIBUTES:
5271099013bSjsg gctx->io_attr = val;
5281099013bSjsg break;
5291099013bSjsg case ATOM_WS_REGPTR:
5301099013bSjsg gctx->reg_block = val;
5311099013bSjsg break;
5321099013bSjsg default:
5331099013bSjsg ctx->ws[idx] = val;
5341099013bSjsg }
5351099013bSjsg break;
5361099013bSjsg case ATOM_ARG_FB:
5371099013bSjsg idx = U8(*ptr);
5381099013bSjsg (*ptr)++;
5391099013bSjsg if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) {
5401099013bSjsg DRM_ERROR("ATOM: fb write beyond scratch region: %d vs. %d\n",
5411099013bSjsg gctx->fb_base + (idx * 4), gctx->scratch_size_bytes);
5421099013bSjsg } else
5431099013bSjsg gctx->scratch[(gctx->fb_base / 4) + idx] = val;
5441099013bSjsg DEBUG("FB[0x%02X]", idx);
5451099013bSjsg break;
5461099013bSjsg case ATOM_ARG_PLL:
5471099013bSjsg idx = U8(*ptr);
5481099013bSjsg (*ptr)++;
5491099013bSjsg DEBUG("PLL[0x%02X]", idx);
5501099013bSjsg gctx->card->pll_write(gctx->card, idx, val);
5511099013bSjsg break;
5521099013bSjsg case ATOM_ARG_MC:
5531099013bSjsg idx = U8(*ptr);
5541099013bSjsg (*ptr)++;
5551099013bSjsg DEBUG("MC[0x%02X]", idx);
5561099013bSjsg gctx->card->mc_write(gctx->card, idx, val);
5571099013bSjsg return;
5581099013bSjsg }
5591099013bSjsg switch (align) {
5601099013bSjsg case ATOM_SRC_DWORD:
5611099013bSjsg DEBUG(".[31:0] <- 0x%08X\n", old_val);
5621099013bSjsg break;
5631099013bSjsg case ATOM_SRC_WORD0:
5641099013bSjsg DEBUG(".[15:0] <- 0x%04X\n", old_val);
5651099013bSjsg break;
5661099013bSjsg case ATOM_SRC_WORD8:
5671099013bSjsg DEBUG(".[23:8] <- 0x%04X\n", old_val);
5681099013bSjsg break;
5691099013bSjsg case ATOM_SRC_WORD16:
5701099013bSjsg DEBUG(".[31:16] <- 0x%04X\n", old_val);
5711099013bSjsg break;
5721099013bSjsg case ATOM_SRC_BYTE0:
5731099013bSjsg DEBUG(".[7:0] <- 0x%02X\n", old_val);
5741099013bSjsg break;
5751099013bSjsg case ATOM_SRC_BYTE8:
5761099013bSjsg DEBUG(".[15:8] <- 0x%02X\n", old_val);
5771099013bSjsg break;
5781099013bSjsg case ATOM_SRC_BYTE16:
5791099013bSjsg DEBUG(".[23:16] <- 0x%02X\n", old_val);
5801099013bSjsg break;
5811099013bSjsg case ATOM_SRC_BYTE24:
5821099013bSjsg DEBUG(".[31:24] <- 0x%02X\n", old_val);
5831099013bSjsg break;
5841099013bSjsg }
5851099013bSjsg }
5861099013bSjsg
atom_op_add(atom_exec_context * ctx,int * ptr,int arg)5871099013bSjsg static void atom_op_add(atom_exec_context *ctx, int *ptr, int arg)
5881099013bSjsg {
5891099013bSjsg uint8_t attr = U8((*ptr)++);
5901099013bSjsg uint32_t dst, src, saved;
5911099013bSjsg int dptr = *ptr;
5921099013bSjsg SDEBUG(" dst: ");
5931099013bSjsg dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
5941099013bSjsg SDEBUG(" src: ");
5951099013bSjsg src = atom_get_src(ctx, attr, ptr);
5961099013bSjsg dst += src;
5971099013bSjsg SDEBUG(" dst: ");
5981099013bSjsg atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
5991099013bSjsg }
6001099013bSjsg
atom_op_and(atom_exec_context * ctx,int * ptr,int arg)6011099013bSjsg static void atom_op_and(atom_exec_context *ctx, int *ptr, int arg)
6021099013bSjsg {
6031099013bSjsg uint8_t attr = U8((*ptr)++);
6041099013bSjsg uint32_t dst, src, saved;
6051099013bSjsg int dptr = *ptr;
6061099013bSjsg SDEBUG(" dst: ");
6071099013bSjsg dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
6081099013bSjsg SDEBUG(" src: ");
6091099013bSjsg src = atom_get_src(ctx, attr, ptr);
6101099013bSjsg dst &= src;
6111099013bSjsg SDEBUG(" dst: ");
6121099013bSjsg atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
6131099013bSjsg }
6141099013bSjsg
atom_op_beep(atom_exec_context * ctx,int * ptr,int arg)6151099013bSjsg static void atom_op_beep(atom_exec_context *ctx, int *ptr, int arg)
6161099013bSjsg {
617d765308cSjsg printk("ATOM BIOS beeped!\n");
6181099013bSjsg }
6191099013bSjsg
atom_op_calltable(atom_exec_context * ctx,int * ptr,int arg)6201099013bSjsg static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg)
6211099013bSjsg {
6221099013bSjsg int idx = U8((*ptr)++);
6231099013bSjsg int r = 0;
6241099013bSjsg
6251099013bSjsg if (idx < ATOM_TABLE_NAMES_CNT)
6261099013bSjsg SDEBUG(" table: %d (%s)\n", idx, atom_table_names[idx]);
6271099013bSjsg else
6281099013bSjsg SDEBUG(" table: %d\n", idx);
6291099013bSjsg if (U16(ctx->ctx->cmd_table + 4 + 2 * idx))
6301099013bSjsg r = atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift);
6311099013bSjsg if (r) {
6321099013bSjsg ctx->abort = true;
6331099013bSjsg }
6341099013bSjsg }
6351099013bSjsg
atom_op_clear(atom_exec_context * ctx,int * ptr,int arg)6361099013bSjsg static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg)
6371099013bSjsg {
6381099013bSjsg uint8_t attr = U8((*ptr)++);
6391099013bSjsg uint32_t saved;
6401099013bSjsg int dptr = *ptr;
6411099013bSjsg attr &= 0x38;
6421099013bSjsg attr |= atom_def_dst[attr >> 3] << 6;
6431099013bSjsg atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
6441099013bSjsg SDEBUG(" dst: ");
6451099013bSjsg atom_put_dst(ctx, arg, attr, &dptr, 0, saved);
6461099013bSjsg }
6471099013bSjsg
atom_op_compare(atom_exec_context * ctx,int * ptr,int arg)6481099013bSjsg static void atom_op_compare(atom_exec_context *ctx, int *ptr, int arg)
6491099013bSjsg {
6501099013bSjsg uint8_t attr = U8((*ptr)++);
6511099013bSjsg uint32_t dst, src;
6521099013bSjsg SDEBUG(" src1: ");
6531099013bSjsg dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
6541099013bSjsg SDEBUG(" src2: ");
6551099013bSjsg src = atom_get_src(ctx, attr, ptr);
6561099013bSjsg ctx->ctx->cs_equal = (dst == src);
6571099013bSjsg ctx->ctx->cs_above = (dst > src);
6581099013bSjsg SDEBUG(" result: %s %s\n", ctx->ctx->cs_equal ? "EQ" : "NE",
6591099013bSjsg ctx->ctx->cs_above ? "GT" : "LE");
6601099013bSjsg }
6611099013bSjsg
atom_op_delay(atom_exec_context * ctx,int * ptr,int arg)6621099013bSjsg static void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg)
6631099013bSjsg {
6641099013bSjsg unsigned count = U8((*ptr)++);
6651099013bSjsg SDEBUG(" count: %d\n", count);
6661099013bSjsg if (arg == ATOM_UNIT_MICROSEC)
6671099013bSjsg udelay(count);
6681099013bSjsg else if (!drm_can_sleep())
6691099013bSjsg mdelay(count);
6701099013bSjsg else
671e1001332Skettenis drm_msleep(count);
6721099013bSjsg }
6731099013bSjsg
atom_op_div(atom_exec_context * ctx,int * ptr,int arg)6741099013bSjsg static void atom_op_div(atom_exec_context *ctx, int *ptr, int arg)
6751099013bSjsg {
6761099013bSjsg uint8_t attr = U8((*ptr)++);
6771099013bSjsg uint32_t dst, src;
6781099013bSjsg SDEBUG(" src1: ");
6791099013bSjsg dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
6801099013bSjsg SDEBUG(" src2: ");
6811099013bSjsg src = atom_get_src(ctx, attr, ptr);
6821099013bSjsg if (src != 0) {
6831099013bSjsg ctx->ctx->divmul[0] = dst / src;
6841099013bSjsg ctx->ctx->divmul[1] = dst % src;
6851099013bSjsg } else {
6861099013bSjsg ctx->ctx->divmul[0] = 0;
6871099013bSjsg ctx->ctx->divmul[1] = 0;
6881099013bSjsg }
6891099013bSjsg }
6901099013bSjsg
atom_op_eot(atom_exec_context * ctx,int * ptr,int arg)6911099013bSjsg static void atom_op_eot(atom_exec_context *ctx, int *ptr, int arg)
6921099013bSjsg {
6931099013bSjsg /* functionally, a nop */
6941099013bSjsg }
6951099013bSjsg
atom_op_jump(atom_exec_context * ctx,int * ptr,int arg)6961099013bSjsg static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
6971099013bSjsg {
6981099013bSjsg int execute = 0, target = U16(*ptr);
6991099013bSjsg unsigned long cjiffies;
7001099013bSjsg
7011099013bSjsg (*ptr) += 2;
7021099013bSjsg switch (arg) {
7031099013bSjsg case ATOM_COND_ABOVE:
7041099013bSjsg execute = ctx->ctx->cs_above;
7051099013bSjsg break;
7061099013bSjsg case ATOM_COND_ABOVEOREQUAL:
7071099013bSjsg execute = ctx->ctx->cs_above || ctx->ctx->cs_equal;
7081099013bSjsg break;
7091099013bSjsg case ATOM_COND_ALWAYS:
7101099013bSjsg execute = 1;
7111099013bSjsg break;
7121099013bSjsg case ATOM_COND_BELOW:
7131099013bSjsg execute = !(ctx->ctx->cs_above || ctx->ctx->cs_equal);
7141099013bSjsg break;
7151099013bSjsg case ATOM_COND_BELOWOREQUAL:
7161099013bSjsg execute = !ctx->ctx->cs_above;
7171099013bSjsg break;
7181099013bSjsg case ATOM_COND_EQUAL:
7191099013bSjsg execute = ctx->ctx->cs_equal;
7201099013bSjsg break;
7211099013bSjsg case ATOM_COND_NOTEQUAL:
7221099013bSjsg execute = !ctx->ctx->cs_equal;
7231099013bSjsg break;
7241099013bSjsg }
7251099013bSjsg if (arg != ATOM_COND_ALWAYS)
7261bb76ff1Sjsg SDEBUG(" taken: %s\n", str_yes_no(execute));
7271099013bSjsg SDEBUG(" target: 0x%04X\n", target);
7281099013bSjsg if (execute) {
7291099013bSjsg if (ctx->last_jump == (ctx->start + target)) {
730eab30e11Sjsg cjiffies = jiffies;
7311099013bSjsg if (time_after(cjiffies, ctx->last_jump_jiffies)) {
7321099013bSjsg cjiffies -= ctx->last_jump_jiffies;
7331099013bSjsg if ((jiffies_to_msecs(cjiffies) > 5000)) {
7341099013bSjsg DRM_ERROR("atombios stuck in loop for more than 5secs aborting\n");
7351099013bSjsg ctx->abort = true;
7361099013bSjsg }
7371099013bSjsg } else {
7381099013bSjsg /* jiffies wrap around we will just wait a little longer */
739eab30e11Sjsg ctx->last_jump_jiffies = jiffies;
7401099013bSjsg }
7411099013bSjsg } else {
7421099013bSjsg ctx->last_jump = ctx->start + target;
743eab30e11Sjsg ctx->last_jump_jiffies = jiffies;
7441099013bSjsg }
7451099013bSjsg *ptr = ctx->start + target;
7461099013bSjsg }
7471099013bSjsg }
7481099013bSjsg
atom_op_mask(atom_exec_context * ctx,int * ptr,int arg)7491099013bSjsg static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg)
7501099013bSjsg {
7511099013bSjsg uint8_t attr = U8((*ptr)++);
7521099013bSjsg uint32_t dst, mask, src, saved;
7531099013bSjsg int dptr = *ptr;
7541099013bSjsg SDEBUG(" dst: ");
7551099013bSjsg dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
7561099013bSjsg mask = atom_get_src_direct(ctx, ((attr >> 3) & 7), ptr);
7571099013bSjsg SDEBUG(" mask: 0x%08x", mask);
7581099013bSjsg SDEBUG(" src: ");
7591099013bSjsg src = atom_get_src(ctx, attr, ptr);
7601099013bSjsg dst &= mask;
7611099013bSjsg dst |= src;
7621099013bSjsg SDEBUG(" dst: ");
7631099013bSjsg atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
7641099013bSjsg }
7651099013bSjsg
atom_op_move(atom_exec_context * ctx,int * ptr,int arg)7661099013bSjsg static void atom_op_move(atom_exec_context *ctx, int *ptr, int arg)
7671099013bSjsg {
7681099013bSjsg uint8_t attr = U8((*ptr)++);
7691099013bSjsg uint32_t src, saved;
7701099013bSjsg int dptr = *ptr;
7711099013bSjsg if (((attr >> 3) & 7) != ATOM_SRC_DWORD)
7721099013bSjsg atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
7731099013bSjsg else {
7741099013bSjsg atom_skip_dst(ctx, arg, attr, ptr);
7751099013bSjsg saved = 0xCDCDCDCD;
7761099013bSjsg }
7771099013bSjsg SDEBUG(" src: ");
7781099013bSjsg src = atom_get_src(ctx, attr, ptr);
7791099013bSjsg SDEBUG(" dst: ");
7801099013bSjsg atom_put_dst(ctx, arg, attr, &dptr, src, saved);
7811099013bSjsg }
7821099013bSjsg
atom_op_mul(atom_exec_context * ctx,int * ptr,int arg)7831099013bSjsg static void atom_op_mul(atom_exec_context *ctx, int *ptr, int arg)
7841099013bSjsg {
7851099013bSjsg uint8_t attr = U8((*ptr)++);
7861099013bSjsg uint32_t dst, src;
7871099013bSjsg SDEBUG(" src1: ");
7881099013bSjsg dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
7891099013bSjsg SDEBUG(" src2: ");
7901099013bSjsg src = atom_get_src(ctx, attr, ptr);
7911099013bSjsg ctx->ctx->divmul[0] = dst * src;
7921099013bSjsg }
7931099013bSjsg
atom_op_nop(atom_exec_context * ctx,int * ptr,int arg)7941099013bSjsg static void atom_op_nop(atom_exec_context *ctx, int *ptr, int arg)
7951099013bSjsg {
7961099013bSjsg /* nothing */
7971099013bSjsg }
7981099013bSjsg
atom_op_or(atom_exec_context * ctx,int * ptr,int arg)7991099013bSjsg static void atom_op_or(atom_exec_context *ctx, int *ptr, int arg)
8001099013bSjsg {
8011099013bSjsg uint8_t attr = U8((*ptr)++);
8021099013bSjsg uint32_t dst, src, saved;
8031099013bSjsg int dptr = *ptr;
8041099013bSjsg SDEBUG(" dst: ");
8051099013bSjsg dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
8061099013bSjsg SDEBUG(" src: ");
8071099013bSjsg src = atom_get_src(ctx, attr, ptr);
8081099013bSjsg dst |= src;
8091099013bSjsg SDEBUG(" dst: ");
8101099013bSjsg atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
8111099013bSjsg }
8121099013bSjsg
atom_op_postcard(atom_exec_context * ctx,int * ptr,int arg)8131099013bSjsg static void atom_op_postcard(atom_exec_context *ctx, int *ptr, int arg)
8141099013bSjsg {
8151099013bSjsg uint8_t val = U8((*ptr)++);
8161099013bSjsg SDEBUG("POST card output: 0x%02X\n", val);
8171099013bSjsg }
8181099013bSjsg
atom_op_repeat(atom_exec_context * ctx,int * ptr,int arg)8191099013bSjsg static void atom_op_repeat(atom_exec_context *ctx, int *ptr, int arg)
8201099013bSjsg {
8217f4dd379Sjsg pr_info("unimplemented!\n");
8221099013bSjsg }
8231099013bSjsg
atom_op_restorereg(atom_exec_context * ctx,int * ptr,int arg)8241099013bSjsg static void atom_op_restorereg(atom_exec_context *ctx, int *ptr, int arg)
8251099013bSjsg {
8267f4dd379Sjsg pr_info("unimplemented!\n");
8271099013bSjsg }
8281099013bSjsg
atom_op_savereg(atom_exec_context * ctx,int * ptr,int arg)8291099013bSjsg static void atom_op_savereg(atom_exec_context *ctx, int *ptr, int arg)
8301099013bSjsg {
8317f4dd379Sjsg pr_info("unimplemented!\n");
8321099013bSjsg }
8331099013bSjsg
atom_op_setdatablock(atom_exec_context * ctx,int * ptr,int arg)8341099013bSjsg static void atom_op_setdatablock(atom_exec_context *ctx, int *ptr, int arg)
8351099013bSjsg {
8361099013bSjsg int idx = U8(*ptr);
8371099013bSjsg (*ptr)++;
8381099013bSjsg SDEBUG(" block: %d\n", idx);
8391099013bSjsg if (!idx)
8401099013bSjsg ctx->ctx->data_block = 0;
8411099013bSjsg else if (idx == 255)
8421099013bSjsg ctx->ctx->data_block = ctx->start;
8431099013bSjsg else
8441099013bSjsg ctx->ctx->data_block = U16(ctx->ctx->data_table + 4 + 2 * idx);
8451099013bSjsg SDEBUG(" base: 0x%04X\n", ctx->ctx->data_block);
8461099013bSjsg }
8471099013bSjsg
atom_op_setfbbase(atom_exec_context * ctx,int * ptr,int arg)8481099013bSjsg static void atom_op_setfbbase(atom_exec_context *ctx, int *ptr, int arg)
8491099013bSjsg {
8501099013bSjsg uint8_t attr = U8((*ptr)++);
8511099013bSjsg SDEBUG(" fb_base: ");
8521099013bSjsg ctx->ctx->fb_base = atom_get_src(ctx, attr, ptr);
8531099013bSjsg }
8541099013bSjsg
atom_op_setport(atom_exec_context * ctx,int * ptr,int arg)8551099013bSjsg static void atom_op_setport(atom_exec_context *ctx, int *ptr, int arg)
8561099013bSjsg {
8571099013bSjsg int port;
8581099013bSjsg switch (arg) {
8591099013bSjsg case ATOM_PORT_ATI:
8601099013bSjsg port = U16(*ptr);
8611099013bSjsg if (port < ATOM_IO_NAMES_CNT)
8621099013bSjsg SDEBUG(" port: %d (%s)\n", port, atom_io_names[port]);
8631099013bSjsg else
8641099013bSjsg SDEBUG(" port: %d\n", port);
8651099013bSjsg if (!port)
8661099013bSjsg ctx->ctx->io_mode = ATOM_IO_MM;
8671099013bSjsg else
8681099013bSjsg ctx->ctx->io_mode = ATOM_IO_IIO | port;
8691099013bSjsg (*ptr) += 2;
8701099013bSjsg break;
8711099013bSjsg case ATOM_PORT_PCI:
8721099013bSjsg ctx->ctx->io_mode = ATOM_IO_PCI;
8731099013bSjsg (*ptr)++;
8741099013bSjsg break;
8751099013bSjsg case ATOM_PORT_SYSIO:
8761099013bSjsg ctx->ctx->io_mode = ATOM_IO_SYSIO;
8771099013bSjsg (*ptr)++;
8781099013bSjsg break;
8791099013bSjsg }
8801099013bSjsg }
8811099013bSjsg
atom_op_setregblock(atom_exec_context * ctx,int * ptr,int arg)8821099013bSjsg static void atom_op_setregblock(atom_exec_context *ctx, int *ptr, int arg)
8831099013bSjsg {
8841099013bSjsg ctx->ctx->reg_block = U16(*ptr);
8851099013bSjsg (*ptr) += 2;
8861099013bSjsg SDEBUG(" base: 0x%04X\n", ctx->ctx->reg_block);
8871099013bSjsg }
8881099013bSjsg
atom_op_shift_left(atom_exec_context * ctx,int * ptr,int arg)8891099013bSjsg static void atom_op_shift_left(atom_exec_context *ctx, int *ptr, int arg)
8901099013bSjsg {
8911099013bSjsg uint8_t attr = U8((*ptr)++), shift;
8921099013bSjsg uint32_t saved, dst;
8931099013bSjsg int dptr = *ptr;
8941099013bSjsg attr &= 0x38;
8951099013bSjsg attr |= atom_def_dst[attr >> 3] << 6;
8961099013bSjsg SDEBUG(" dst: ");
8971099013bSjsg dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
8981099013bSjsg shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr);
8991099013bSjsg SDEBUG(" shift: %d\n", shift);
9001099013bSjsg dst <<= shift;
9011099013bSjsg SDEBUG(" dst: ");
9021099013bSjsg atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
9031099013bSjsg }
9041099013bSjsg
atom_op_shift_right(atom_exec_context * ctx,int * ptr,int arg)9051099013bSjsg static void atom_op_shift_right(atom_exec_context *ctx, int *ptr, int arg)
9061099013bSjsg {
9071099013bSjsg uint8_t attr = U8((*ptr)++), shift;
9081099013bSjsg uint32_t saved, dst;
9091099013bSjsg int dptr = *ptr;
9101099013bSjsg attr &= 0x38;
9111099013bSjsg attr |= atom_def_dst[attr >> 3] << 6;
9121099013bSjsg SDEBUG(" dst: ");
9131099013bSjsg dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
9141099013bSjsg shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr);
9151099013bSjsg SDEBUG(" shift: %d\n", shift);
9161099013bSjsg dst >>= shift;
9171099013bSjsg SDEBUG(" dst: ");
9181099013bSjsg atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
9191099013bSjsg }
9201099013bSjsg
atom_op_shl(atom_exec_context * ctx,int * ptr,int arg)9211099013bSjsg static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg)
9221099013bSjsg {
9231099013bSjsg uint8_t attr = U8((*ptr)++), shift;
9241099013bSjsg uint32_t saved, dst;
9251099013bSjsg int dptr = *ptr;
9261099013bSjsg uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3];
9271099013bSjsg SDEBUG(" dst: ");
9281099013bSjsg dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
9291099013bSjsg /* op needs to full dst value */
9301099013bSjsg dst = saved;
9311099013bSjsg shift = atom_get_src(ctx, attr, ptr);
9321099013bSjsg SDEBUG(" shift: %d\n", shift);
9331099013bSjsg dst <<= shift;
9341099013bSjsg dst &= atom_arg_mask[dst_align];
9351099013bSjsg dst >>= atom_arg_shift[dst_align];
9361099013bSjsg SDEBUG(" dst: ");
9371099013bSjsg atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
9381099013bSjsg }
9391099013bSjsg
atom_op_shr(atom_exec_context * ctx,int * ptr,int arg)9401099013bSjsg static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg)
9411099013bSjsg {
9421099013bSjsg uint8_t attr = U8((*ptr)++), shift;
9431099013bSjsg uint32_t saved, dst;
9441099013bSjsg int dptr = *ptr;
9451099013bSjsg uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3];
9461099013bSjsg SDEBUG(" dst: ");
9471099013bSjsg dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
9481099013bSjsg /* op needs to full dst value */
9491099013bSjsg dst = saved;
9501099013bSjsg shift = atom_get_src(ctx, attr, ptr);
9511099013bSjsg SDEBUG(" shift: %d\n", shift);
9521099013bSjsg dst >>= shift;
9531099013bSjsg dst &= atom_arg_mask[dst_align];
9541099013bSjsg dst >>= atom_arg_shift[dst_align];
9551099013bSjsg SDEBUG(" dst: ");
9561099013bSjsg atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
9571099013bSjsg }
9581099013bSjsg
atom_op_sub(atom_exec_context * ctx,int * ptr,int arg)9591099013bSjsg static void atom_op_sub(atom_exec_context *ctx, int *ptr, int arg)
9601099013bSjsg {
9611099013bSjsg uint8_t attr = U8((*ptr)++);
9621099013bSjsg uint32_t dst, src, saved;
9631099013bSjsg int dptr = *ptr;
9641099013bSjsg SDEBUG(" dst: ");
9651099013bSjsg dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
9661099013bSjsg SDEBUG(" src: ");
9671099013bSjsg src = atom_get_src(ctx, attr, ptr);
9681099013bSjsg dst -= src;
9691099013bSjsg SDEBUG(" dst: ");
9701099013bSjsg atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
9711099013bSjsg }
9721099013bSjsg
atom_op_switch(atom_exec_context * ctx,int * ptr,int arg)9731099013bSjsg static void atom_op_switch(atom_exec_context *ctx, int *ptr, int arg)
9741099013bSjsg {
9751099013bSjsg uint8_t attr = U8((*ptr)++);
9761099013bSjsg uint32_t src, val, target;
9771099013bSjsg SDEBUG(" switch: ");
9781099013bSjsg src = atom_get_src(ctx, attr, ptr);
9791099013bSjsg while (U16(*ptr) != ATOM_CASE_END)
9801099013bSjsg if (U8(*ptr) == ATOM_CASE_MAGIC) {
9811099013bSjsg (*ptr)++;
9821099013bSjsg SDEBUG(" case: ");
9831099013bSjsg val =
9841099013bSjsg atom_get_src(ctx, (attr & 0x38) | ATOM_ARG_IMM,
9851099013bSjsg ptr);
9861099013bSjsg target = U16(*ptr);
9871099013bSjsg if (val == src) {
9881099013bSjsg SDEBUG(" target: %04X\n", target);
9891099013bSjsg *ptr = ctx->start + target;
9901099013bSjsg return;
9911099013bSjsg }
9921099013bSjsg (*ptr) += 2;
9931099013bSjsg } else {
9947f4dd379Sjsg pr_info("Bad case\n");
9951099013bSjsg return;
9961099013bSjsg }
9971099013bSjsg (*ptr) += 2;
9981099013bSjsg }
9991099013bSjsg
atom_op_test(atom_exec_context * ctx,int * ptr,int arg)10001099013bSjsg static void atom_op_test(atom_exec_context *ctx, int *ptr, int arg)
10011099013bSjsg {
10021099013bSjsg uint8_t attr = U8((*ptr)++);
10031099013bSjsg uint32_t dst, src;
10041099013bSjsg SDEBUG(" src1: ");
10051099013bSjsg dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
10061099013bSjsg SDEBUG(" src2: ");
10071099013bSjsg src = atom_get_src(ctx, attr, ptr);
10081099013bSjsg ctx->ctx->cs_equal = ((dst & src) == 0);
10091099013bSjsg SDEBUG(" result: %s\n", ctx->ctx->cs_equal ? "EQ" : "NE");
10101099013bSjsg }
10111099013bSjsg
atom_op_xor(atom_exec_context * ctx,int * ptr,int arg)10121099013bSjsg static void atom_op_xor(atom_exec_context *ctx, int *ptr, int arg)
10131099013bSjsg {
10141099013bSjsg uint8_t attr = U8((*ptr)++);
10151099013bSjsg uint32_t dst, src, saved;
10161099013bSjsg int dptr = *ptr;
10171099013bSjsg SDEBUG(" dst: ");
10181099013bSjsg dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
10191099013bSjsg SDEBUG(" src: ");
10201099013bSjsg src = atom_get_src(ctx, attr, ptr);
10211099013bSjsg dst ^= src;
10221099013bSjsg SDEBUG(" dst: ");
10231099013bSjsg atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
10241099013bSjsg }
10251099013bSjsg
atom_op_debug(atom_exec_context * ctx,int * ptr,int arg)10261099013bSjsg static void atom_op_debug(atom_exec_context *ctx, int *ptr, int arg)
10271099013bSjsg {
10287f4dd379Sjsg pr_info("unimplemented!\n");
10291099013bSjsg }
10301099013bSjsg
10311099013bSjsg static struct {
10321099013bSjsg void (*func) (atom_exec_context *, int *, int);
10331099013bSjsg int arg;
10341099013bSjsg } opcode_table[ATOM_OP_CNT] = {
10351099013bSjsg {
10361099013bSjsg NULL, 0}, {
10371099013bSjsg atom_op_move, ATOM_ARG_REG}, {
10381099013bSjsg atom_op_move, ATOM_ARG_PS}, {
10391099013bSjsg atom_op_move, ATOM_ARG_WS}, {
10401099013bSjsg atom_op_move, ATOM_ARG_FB}, {
10411099013bSjsg atom_op_move, ATOM_ARG_PLL}, {
10421099013bSjsg atom_op_move, ATOM_ARG_MC}, {
10431099013bSjsg atom_op_and, ATOM_ARG_REG}, {
10441099013bSjsg atom_op_and, ATOM_ARG_PS}, {
10451099013bSjsg atom_op_and, ATOM_ARG_WS}, {
10461099013bSjsg atom_op_and, ATOM_ARG_FB}, {
10471099013bSjsg atom_op_and, ATOM_ARG_PLL}, {
10481099013bSjsg atom_op_and, ATOM_ARG_MC}, {
10491099013bSjsg atom_op_or, ATOM_ARG_REG}, {
10501099013bSjsg atom_op_or, ATOM_ARG_PS}, {
10511099013bSjsg atom_op_or, ATOM_ARG_WS}, {
10521099013bSjsg atom_op_or, ATOM_ARG_FB}, {
10531099013bSjsg atom_op_or, ATOM_ARG_PLL}, {
10541099013bSjsg atom_op_or, ATOM_ARG_MC}, {
10551099013bSjsg atom_op_shift_left, ATOM_ARG_REG}, {
10561099013bSjsg atom_op_shift_left, ATOM_ARG_PS}, {
10571099013bSjsg atom_op_shift_left, ATOM_ARG_WS}, {
10581099013bSjsg atom_op_shift_left, ATOM_ARG_FB}, {
10591099013bSjsg atom_op_shift_left, ATOM_ARG_PLL}, {
10601099013bSjsg atom_op_shift_left, ATOM_ARG_MC}, {
10611099013bSjsg atom_op_shift_right, ATOM_ARG_REG}, {
10621099013bSjsg atom_op_shift_right, ATOM_ARG_PS}, {
10631099013bSjsg atom_op_shift_right, ATOM_ARG_WS}, {
10641099013bSjsg atom_op_shift_right, ATOM_ARG_FB}, {
10651099013bSjsg atom_op_shift_right, ATOM_ARG_PLL}, {
10661099013bSjsg atom_op_shift_right, ATOM_ARG_MC}, {
10671099013bSjsg atom_op_mul, ATOM_ARG_REG}, {
10681099013bSjsg atom_op_mul, ATOM_ARG_PS}, {
10691099013bSjsg atom_op_mul, ATOM_ARG_WS}, {
10701099013bSjsg atom_op_mul, ATOM_ARG_FB}, {
10711099013bSjsg atom_op_mul, ATOM_ARG_PLL}, {
10721099013bSjsg atom_op_mul, ATOM_ARG_MC}, {
10731099013bSjsg atom_op_div, ATOM_ARG_REG}, {
10741099013bSjsg atom_op_div, ATOM_ARG_PS}, {
10751099013bSjsg atom_op_div, ATOM_ARG_WS}, {
10761099013bSjsg atom_op_div, ATOM_ARG_FB}, {
10771099013bSjsg atom_op_div, ATOM_ARG_PLL}, {
10781099013bSjsg atom_op_div, ATOM_ARG_MC}, {
10791099013bSjsg atom_op_add, ATOM_ARG_REG}, {
10801099013bSjsg atom_op_add, ATOM_ARG_PS}, {
10811099013bSjsg atom_op_add, ATOM_ARG_WS}, {
10821099013bSjsg atom_op_add, ATOM_ARG_FB}, {
10831099013bSjsg atom_op_add, ATOM_ARG_PLL}, {
10841099013bSjsg atom_op_add, ATOM_ARG_MC}, {
10851099013bSjsg atom_op_sub, ATOM_ARG_REG}, {
10861099013bSjsg atom_op_sub, ATOM_ARG_PS}, {
10871099013bSjsg atom_op_sub, ATOM_ARG_WS}, {
10881099013bSjsg atom_op_sub, ATOM_ARG_FB}, {
10891099013bSjsg atom_op_sub, ATOM_ARG_PLL}, {
10901099013bSjsg atom_op_sub, ATOM_ARG_MC}, {
10911099013bSjsg atom_op_setport, ATOM_PORT_ATI}, {
10921099013bSjsg atom_op_setport, ATOM_PORT_PCI}, {
10931099013bSjsg atom_op_setport, ATOM_PORT_SYSIO}, {
10941099013bSjsg atom_op_setregblock, 0}, {
10951099013bSjsg atom_op_setfbbase, 0}, {
10961099013bSjsg atom_op_compare, ATOM_ARG_REG}, {
10971099013bSjsg atom_op_compare, ATOM_ARG_PS}, {
10981099013bSjsg atom_op_compare, ATOM_ARG_WS}, {
10991099013bSjsg atom_op_compare, ATOM_ARG_FB}, {
11001099013bSjsg atom_op_compare, ATOM_ARG_PLL}, {
11011099013bSjsg atom_op_compare, ATOM_ARG_MC}, {
11021099013bSjsg atom_op_switch, 0}, {
11031099013bSjsg atom_op_jump, ATOM_COND_ALWAYS}, {
11041099013bSjsg atom_op_jump, ATOM_COND_EQUAL}, {
11051099013bSjsg atom_op_jump, ATOM_COND_BELOW}, {
11061099013bSjsg atom_op_jump, ATOM_COND_ABOVE}, {
11071099013bSjsg atom_op_jump, ATOM_COND_BELOWOREQUAL}, {
11081099013bSjsg atom_op_jump, ATOM_COND_ABOVEOREQUAL}, {
11091099013bSjsg atom_op_jump, ATOM_COND_NOTEQUAL}, {
11101099013bSjsg atom_op_test, ATOM_ARG_REG}, {
11111099013bSjsg atom_op_test, ATOM_ARG_PS}, {
11121099013bSjsg atom_op_test, ATOM_ARG_WS}, {
11131099013bSjsg atom_op_test, ATOM_ARG_FB}, {
11141099013bSjsg atom_op_test, ATOM_ARG_PLL}, {
11151099013bSjsg atom_op_test, ATOM_ARG_MC}, {
11161099013bSjsg atom_op_delay, ATOM_UNIT_MILLISEC}, {
11171099013bSjsg atom_op_delay, ATOM_UNIT_MICROSEC}, {
11181099013bSjsg atom_op_calltable, 0}, {
11191099013bSjsg atom_op_repeat, 0}, {
11201099013bSjsg atom_op_clear, ATOM_ARG_REG}, {
11211099013bSjsg atom_op_clear, ATOM_ARG_PS}, {
11221099013bSjsg atom_op_clear, ATOM_ARG_WS}, {
11231099013bSjsg atom_op_clear, ATOM_ARG_FB}, {
11241099013bSjsg atom_op_clear, ATOM_ARG_PLL}, {
11251099013bSjsg atom_op_clear, ATOM_ARG_MC}, {
11261099013bSjsg atom_op_nop, 0}, {
11271099013bSjsg atom_op_eot, 0}, {
11281099013bSjsg atom_op_mask, ATOM_ARG_REG}, {
11291099013bSjsg atom_op_mask, ATOM_ARG_PS}, {
11301099013bSjsg atom_op_mask, ATOM_ARG_WS}, {
11311099013bSjsg atom_op_mask, ATOM_ARG_FB}, {
11321099013bSjsg atom_op_mask, ATOM_ARG_PLL}, {
11331099013bSjsg atom_op_mask, ATOM_ARG_MC}, {
11341099013bSjsg atom_op_postcard, 0}, {
11351099013bSjsg atom_op_beep, 0}, {
11361099013bSjsg atom_op_savereg, 0}, {
11371099013bSjsg atom_op_restorereg, 0}, {
11381099013bSjsg atom_op_setdatablock, 0}, {
11391099013bSjsg atom_op_xor, ATOM_ARG_REG}, {
11401099013bSjsg atom_op_xor, ATOM_ARG_PS}, {
11411099013bSjsg atom_op_xor, ATOM_ARG_WS}, {
11421099013bSjsg atom_op_xor, ATOM_ARG_FB}, {
11431099013bSjsg atom_op_xor, ATOM_ARG_PLL}, {
11441099013bSjsg atom_op_xor, ATOM_ARG_MC}, {
11451099013bSjsg atom_op_shl, ATOM_ARG_REG}, {
11461099013bSjsg atom_op_shl, ATOM_ARG_PS}, {
11471099013bSjsg atom_op_shl, ATOM_ARG_WS}, {
11481099013bSjsg atom_op_shl, ATOM_ARG_FB}, {
11491099013bSjsg atom_op_shl, ATOM_ARG_PLL}, {
11501099013bSjsg atom_op_shl, ATOM_ARG_MC}, {
11511099013bSjsg atom_op_shr, ATOM_ARG_REG}, {
11521099013bSjsg atom_op_shr, ATOM_ARG_PS}, {
11531099013bSjsg atom_op_shr, ATOM_ARG_WS}, {
11541099013bSjsg atom_op_shr, ATOM_ARG_FB}, {
11551099013bSjsg atom_op_shr, ATOM_ARG_PLL}, {
11561099013bSjsg atom_op_shr, ATOM_ARG_MC}, {
11571099013bSjsg atom_op_debug, 0},};
11581099013bSjsg
atom_execute_table_locked(struct atom_context * ctx,int index,uint32_t * params)11591099013bSjsg static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t *params)
11601099013bSjsg {
11611099013bSjsg int base = CU16(ctx->cmd_table + 4 + 2 * index);
11621099013bSjsg int len, ws, ps, ptr;
11631099013bSjsg unsigned char op;
11641099013bSjsg atom_exec_context ectx;
11651099013bSjsg int ret = 0;
11661099013bSjsg
11671099013bSjsg if (!base)
11681099013bSjsg return -EINVAL;
11691099013bSjsg
11701099013bSjsg len = CU16(base + ATOM_CT_SIZE_PTR);
11711099013bSjsg ws = CU8(base + ATOM_CT_WS_PTR);
11721099013bSjsg ps = CU8(base + ATOM_CT_PS_PTR) & ATOM_CT_PS_MASK;
11731099013bSjsg ptr = base + ATOM_CT_CODE_PTR;
11741099013bSjsg
11751099013bSjsg SDEBUG(">> execute %04X (len %d, WS %d, PS %d)\n", base, len, ws, ps);
11761099013bSjsg
11771099013bSjsg ectx.ctx = ctx;
11781099013bSjsg ectx.ps_shift = ps / 4;
11791099013bSjsg ectx.start = base;
11801099013bSjsg ectx.ps = params;
11811099013bSjsg ectx.abort = false;
11821099013bSjsg ectx.last_jump = 0;
11831099013bSjsg if (ws)
11847f4dd379Sjsg ectx.ws = kcalloc(4, ws, GFP_KERNEL);
11851099013bSjsg else
11861099013bSjsg ectx.ws = NULL;
11871099013bSjsg
11881099013bSjsg debug_depth++;
11891099013bSjsg while (1) {
11901099013bSjsg op = CU8(ptr++);
11911099013bSjsg if (op < ATOM_OP_NAMES_CNT)
11921099013bSjsg SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr - 1);
11931099013bSjsg else
11941099013bSjsg SDEBUG("[%d] @ 0x%04X\n", op, ptr - 1);
11951099013bSjsg if (ectx.abort) {
11961099013bSjsg DRM_ERROR("atombios stuck executing %04X (len %d, WS %d, PS %d) @ 0x%04X\n",
11971099013bSjsg base, len, ws, ps, ptr - 1);
11981099013bSjsg ret = -EINVAL;
11991099013bSjsg goto free;
12001099013bSjsg }
12011099013bSjsg
12021099013bSjsg if (op < ATOM_OP_CNT && op > 0)
12031099013bSjsg opcode_table[op].func(&ectx, &ptr,
12041099013bSjsg opcode_table[op].arg);
12051099013bSjsg else
12061099013bSjsg break;
12071099013bSjsg
12081099013bSjsg if (op == ATOM_OP_EOT)
12091099013bSjsg break;
12101099013bSjsg }
12111099013bSjsg debug_depth--;
12121099013bSjsg SDEBUG("<<\n");
12131099013bSjsg
12141099013bSjsg free:
1215de5631a0Sjsg kfree(ectx.ws);
12161099013bSjsg return ret;
12171099013bSjsg }
12181099013bSjsg
atom_execute_table_scratch_unlocked(struct atom_context * ctx,int index,uint32_t * params)12197ccd5a2cSjsg int atom_execute_table_scratch_unlocked(struct atom_context *ctx, int index, uint32_t *params)
12201099013bSjsg {
12211099013bSjsg int r;
12221099013bSjsg
1223528273cbSjsg mutex_lock(&ctx->mutex);
12244d39cd64Sjsg /* reset data block */
12254d39cd64Sjsg ctx->data_block = 0;
12261099013bSjsg /* reset reg block */
12271099013bSjsg ctx->reg_block = 0;
12281099013bSjsg /* reset fb window */
12291099013bSjsg ctx->fb_base = 0;
12301099013bSjsg /* reset io mode */
12311099013bSjsg ctx->io_mode = ATOM_IO_MM;
12324d39cd64Sjsg /* reset divmul */
12334d39cd64Sjsg ctx->divmul[0] = 0;
12344d39cd64Sjsg ctx->divmul[1] = 0;
12351099013bSjsg r = atom_execute_table_locked(ctx, index, params);
1236528273cbSjsg mutex_unlock(&ctx->mutex);
12371099013bSjsg return r;
12381099013bSjsg }
12391099013bSjsg
atom_execute_table(struct atom_context * ctx,int index,uint32_t * params)12407ccd5a2cSjsg int atom_execute_table(struct atom_context *ctx, int index, uint32_t *params)
12417ccd5a2cSjsg {
12427ccd5a2cSjsg int r;
12437ccd5a2cSjsg mutex_lock(&ctx->scratch_mutex);
12447ccd5a2cSjsg r = atom_execute_table_scratch_unlocked(ctx, index, params);
12457ccd5a2cSjsg mutex_unlock(&ctx->scratch_mutex);
12467ccd5a2cSjsg return r;
12477ccd5a2cSjsg }
12487ccd5a2cSjsg
12491099013bSjsg static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 };
12501099013bSjsg
atom_index_iio(struct atom_context * ctx,int base)12511099013bSjsg static void atom_index_iio(struct atom_context *ctx, int base)
12521099013bSjsg {
1253de5631a0Sjsg ctx->iio = kzalloc(2 * 256, GFP_KERNEL);
12547ccd5a2cSjsg if (!ctx->iio)
12557ccd5a2cSjsg return;
12561099013bSjsg while (CU8(base) == ATOM_IIO_START) {
12571099013bSjsg ctx->iio[CU8(base + 1)] = base + 2;
12581099013bSjsg base += 2;
12591099013bSjsg while (CU8(base) != ATOM_IIO_END)
12601099013bSjsg base += atom_iio_len[CU8(base)];
12611099013bSjsg base += 3;
12621099013bSjsg }
12631099013bSjsg }
12641099013bSjsg
atom_parse(struct card_info * card,void * bios)12651099013bSjsg struct atom_context *atom_parse(struct card_info *card, void *bios)
12661099013bSjsg {
12671099013bSjsg int base;
12681099013bSjsg struct atom_context *ctx =
1269de5631a0Sjsg kzalloc(sizeof(struct atom_context), GFP_KERNEL);
12701099013bSjsg char *str;
12711099013bSjsg char name[512];
12721099013bSjsg int i;
12731099013bSjsg
12741099013bSjsg if (!ctx)
12751099013bSjsg return NULL;
12761099013bSjsg
12771099013bSjsg ctx->card = card;
12781099013bSjsg ctx->bios = bios;
12791099013bSjsg
12801099013bSjsg if (CU16(0) != ATOM_BIOS_MAGIC) {
12817f4dd379Sjsg pr_info("Invalid BIOS magic\n");
1282de5631a0Sjsg kfree(ctx);
12831099013bSjsg return NULL;
12841099013bSjsg }
12851099013bSjsg if (strncmp
12861099013bSjsg (CSTR(ATOM_ATI_MAGIC_PTR), ATOM_ATI_MAGIC,
12871099013bSjsg strlen(ATOM_ATI_MAGIC))) {
12887f4dd379Sjsg pr_info("Invalid ATI magic\n");
1289de5631a0Sjsg kfree(ctx);
12901099013bSjsg return NULL;
12911099013bSjsg }
12921099013bSjsg
12931099013bSjsg base = CU16(ATOM_ROM_TABLE_PTR);
12941099013bSjsg if (strncmp
12951099013bSjsg (CSTR(base + ATOM_ROM_MAGIC_PTR), ATOM_ROM_MAGIC,
12961099013bSjsg strlen(ATOM_ROM_MAGIC))) {
12977f4dd379Sjsg pr_info("Invalid ATOM magic\n");
1298de5631a0Sjsg kfree(ctx);
12991099013bSjsg return NULL;
13001099013bSjsg }
13011099013bSjsg
13021099013bSjsg ctx->cmd_table = CU16(base + ATOM_ROM_CMD_PTR);
13031099013bSjsg ctx->data_table = CU16(base + ATOM_ROM_DATA_PTR);
13041099013bSjsg atom_index_iio(ctx, CU16(ctx->data_table + ATOM_DATA_IIO_PTR) + 4);
13057ccd5a2cSjsg if (!ctx->iio) {
13067ccd5a2cSjsg atom_destroy(ctx);
13077ccd5a2cSjsg return NULL;
13087ccd5a2cSjsg }
13091099013bSjsg
13101099013bSjsg str = CSTR(CU16(base + ATOM_ROM_MSG_PTR));
13111099013bSjsg while (*str && ((*str == '\n') || (*str == '\r')))
13121099013bSjsg str++;
13131099013bSjsg /* name string isn't always 0 terminated */
13141099013bSjsg for (i = 0; i < 511; i++) {
13151099013bSjsg name[i] = str[i];
13161099013bSjsg if (name[i] < '.' || name[i] > 'z') {
13171099013bSjsg name[i] = 0;
13181099013bSjsg break;
13191099013bSjsg }
13201099013bSjsg }
13217f4dd379Sjsg pr_info("ATOM BIOS: %s\n", name);
13221099013bSjsg
13231099013bSjsg return ctx;
13241099013bSjsg }
13251099013bSjsg
atom_asic_init(struct atom_context * ctx)13261099013bSjsg int atom_asic_init(struct atom_context *ctx)
13271099013bSjsg {
13281099013bSjsg struct radeon_device *rdev = ctx->card->dev->dev_private;
13291099013bSjsg int hwi = CU16(ctx->data_table + ATOM_DATA_FWI_PTR);
13301099013bSjsg uint32_t ps[16];
13311099013bSjsg int ret;
13321099013bSjsg
13331099013bSjsg memset(ps, 0, 64);
13341099013bSjsg
13351099013bSjsg ps[0] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFSCLK_PTR));
13361099013bSjsg ps[1] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFMCLK_PTR));
13371099013bSjsg if (!ps[0] || !ps[1])
13381099013bSjsg return 1;
13391099013bSjsg
13401099013bSjsg if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT))
13411099013bSjsg return 1;
13421099013bSjsg ret = atom_execute_table(ctx, ATOM_CMD_INIT, ps);
13431099013bSjsg if (ret)
13441099013bSjsg return ret;
13451099013bSjsg
13461099013bSjsg memset(ps, 0, 64);
13471099013bSjsg
13481099013bSjsg if (rdev->family < CHIP_R600) {
13491099013bSjsg if (CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_SPDFANCNTL))
13501099013bSjsg atom_execute_table(ctx, ATOM_CMD_SPDFANCNTL, ps);
13511099013bSjsg }
13521099013bSjsg return ret;
13531099013bSjsg }
13541099013bSjsg
atom_destroy(struct atom_context * ctx)13551099013bSjsg void atom_destroy(struct atom_context *ctx)
13561099013bSjsg {
1357de5631a0Sjsg kfree(ctx->iio);
1358de5631a0Sjsg kfree(ctx);
13591099013bSjsg }
13601099013bSjsg
atom_parse_data_header(struct atom_context * ctx,int index,uint16_t * size,uint8_t * frev,uint8_t * crev,uint16_t * data_start)13611099013bSjsg bool atom_parse_data_header(struct atom_context *ctx, int index,
13621099013bSjsg uint16_t *size, uint8_t *frev, uint8_t *crev,
13631099013bSjsg uint16_t *data_start)
13641099013bSjsg {
13651099013bSjsg int offset = index * 2 + 4;
13661099013bSjsg int idx = CU16(ctx->data_table + offset);
13671099013bSjsg u16 *mdt = (u16 *)(ctx->bios + ctx->data_table + 4);
13681099013bSjsg
13691099013bSjsg if (!mdt[index])
13701099013bSjsg return false;
13711099013bSjsg
13721099013bSjsg if (size)
13731099013bSjsg *size = CU16(idx);
13741099013bSjsg if (frev)
13751099013bSjsg *frev = CU8(idx + 2);
13761099013bSjsg if (crev)
13771099013bSjsg *crev = CU8(idx + 3);
13781099013bSjsg *data_start = idx;
13791099013bSjsg return true;
13801099013bSjsg }
13811099013bSjsg
atom_parse_cmd_header(struct atom_context * ctx,int index,uint8_t * frev,uint8_t * crev)13821099013bSjsg bool atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t *frev,
13831099013bSjsg uint8_t *crev)
13841099013bSjsg {
13851099013bSjsg int offset = index * 2 + 4;
13861099013bSjsg int idx = CU16(ctx->cmd_table + offset);
13871099013bSjsg u16 *mct = (u16 *)(ctx->bios + ctx->cmd_table + 4);
13881099013bSjsg
13891099013bSjsg if (!mct[index])
13901099013bSjsg return false;
13911099013bSjsg
13921099013bSjsg if (frev)
13931099013bSjsg *frev = CU8(idx + 2);
13941099013bSjsg if (crev)
13951099013bSjsg *crev = CU8(idx + 3);
13961099013bSjsg return true;
13971099013bSjsg }
13981099013bSjsg
atom_allocate_fb_scratch(struct atom_context * ctx)13991099013bSjsg int atom_allocate_fb_scratch(struct atom_context *ctx)
14001099013bSjsg {
14011099013bSjsg int index = GetIndexIntoMasterTable(DATA, VRAM_UsageByFirmware);
14021099013bSjsg uint16_t data_offset;
14031099013bSjsg int usage_bytes = 0;
14041099013bSjsg struct _ATOM_VRAM_USAGE_BY_FIRMWARE *firmware_usage;
14051099013bSjsg
14061099013bSjsg if (atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset)) {
14071099013bSjsg firmware_usage = (struct _ATOM_VRAM_USAGE_BY_FIRMWARE *)(ctx->bios + data_offset);
14081099013bSjsg
14091099013bSjsg DRM_DEBUG("atom firmware requested %08x %dkb\n",
14101099013bSjsg le32_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware),
14111099013bSjsg le16_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb));
14121099013bSjsg
14131099013bSjsg usage_bytes = le16_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb) * 1024;
14141099013bSjsg }
14151099013bSjsg ctx->scratch_size_bytes = 0;
14161099013bSjsg if (usage_bytes == 0)
14171099013bSjsg usage_bytes = 20 * 1024;
14181099013bSjsg /* allocate some scratch memory */
1419de5631a0Sjsg ctx->scratch = kzalloc(usage_bytes, GFP_KERNEL);
14201099013bSjsg if (!ctx->scratch)
14211099013bSjsg return -ENOMEM;
14221099013bSjsg ctx->scratch_size_bytes = usage_bytes;
14231099013bSjsg return 0;
14241099013bSjsg }
1425