1d38ceaf9SAlex Deucher /*
2d38ceaf9SAlex Deucher * Copyright 2008 Advanced Micro Devices, Inc.
3d38ceaf9SAlex Deucher *
4d38ceaf9SAlex Deucher * Permission is hereby granted, free of charge, to any person obtaining a
5d38ceaf9SAlex Deucher * copy of this software and associated documentation files (the "Software"),
6d38ceaf9SAlex Deucher * to deal in the Software without restriction, including without limitation
7d38ceaf9SAlex Deucher * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8d38ceaf9SAlex Deucher * and/or sell copies of the Software, and to permit persons to whom the
9d38ceaf9SAlex Deucher * Software is furnished to do so, subject to the following conditions:
10d38ceaf9SAlex Deucher *
11d38ceaf9SAlex Deucher * The above copyright notice and this permission notice shall be included in
12d38ceaf9SAlex Deucher * all copies or substantial portions of the Software.
13d38ceaf9SAlex Deucher *
14d38ceaf9SAlex Deucher * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15d38ceaf9SAlex Deucher * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16d38ceaf9SAlex Deucher * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17d38ceaf9SAlex Deucher * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18d38ceaf9SAlex Deucher * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19d38ceaf9SAlex Deucher * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20d38ceaf9SAlex Deucher * OTHER DEALINGS IN THE SOFTWARE.
21d38ceaf9SAlex Deucher *
22d38ceaf9SAlex Deucher * Author: Stanislaw Skowronek
23d38ceaf9SAlex Deucher */
24d38ceaf9SAlex Deucher
25d38ceaf9SAlex Deucher #include <linux/module.h>
26d38ceaf9SAlex Deucher #include <linux/sched.h>
27d38ceaf9SAlex Deucher #include <linux/slab.h>
28b8c75bd9SLucas De Marchi #include <linux/string_helpers.h>
29b8c75bd9SLucas De Marchi
30d38ceaf9SAlex Deucher #include <asm/unaligned.h>
31d38ceaf9SAlex Deucher
32e9eafcb5SSam Ravnborg #include <drm/drm_util.h>
33e9eafcb5SSam Ravnborg
34d38ceaf9SAlex Deucher #define ATOM_DEBUG
35d38ceaf9SAlex Deucher
3629b4c589SJiawei Gu #include "atomfirmware.h"
37d38ceaf9SAlex Deucher #include "atom.h"
38d38ceaf9SAlex Deucher #include "atom-names.h"
39d38ceaf9SAlex Deucher #include "atom-bits.h"
40d38ceaf9SAlex Deucher #include "amdgpu.h"
41d38ceaf9SAlex Deucher
42d38ceaf9SAlex Deucher #define ATOM_COND_ABOVE 0
43d38ceaf9SAlex Deucher #define ATOM_COND_ABOVEOREQUAL 1
44d38ceaf9SAlex Deucher #define ATOM_COND_ALWAYS 2
45d38ceaf9SAlex Deucher #define ATOM_COND_BELOW 3
46d38ceaf9SAlex Deucher #define ATOM_COND_BELOWOREQUAL 4
47d38ceaf9SAlex Deucher #define ATOM_COND_EQUAL 5
48d38ceaf9SAlex Deucher #define ATOM_COND_NOTEQUAL 6
49d38ceaf9SAlex Deucher
50d38ceaf9SAlex Deucher #define ATOM_PORT_ATI 0
51d38ceaf9SAlex Deucher #define ATOM_PORT_PCI 1
52d38ceaf9SAlex Deucher #define ATOM_PORT_SYSIO 2
53d38ceaf9SAlex Deucher
54d38ceaf9SAlex Deucher #define ATOM_UNIT_MICROSEC 0
55d38ceaf9SAlex Deucher #define ATOM_UNIT_MILLISEC 1
56d38ceaf9SAlex Deucher
57d38ceaf9SAlex Deucher #define PLL_INDEX 2
58d38ceaf9SAlex Deucher #define PLL_DATA 3
59d38ceaf9SAlex Deucher
609a785c7aSJohn Clements #define ATOM_CMD_TIMEOUT_SEC 20
619a785c7aSJohn Clements
62d38ceaf9SAlex Deucher typedef struct {
63d38ceaf9SAlex Deucher struct atom_context *ctx;
64d38ceaf9SAlex Deucher uint32_t *ps, *ws;
65d38ceaf9SAlex Deucher int ps_shift;
66d38ceaf9SAlex Deucher uint16_t start;
67d38ceaf9SAlex Deucher unsigned last_jump;
68d38ceaf9SAlex Deucher unsigned long last_jump_jiffies;
69d38ceaf9SAlex Deucher bool abort;
70d38ceaf9SAlex Deucher } atom_exec_context;
71d38ceaf9SAlex Deucher
7287fb7833SDeepak R Varma int amdgpu_atom_debug;
73d38ceaf9SAlex Deucher static int amdgpu_atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t *params);
74d38ceaf9SAlex Deucher int amdgpu_atom_execute_table(struct atom_context *ctx, int index, uint32_t *params);
75d38ceaf9SAlex Deucher
76d38ceaf9SAlex Deucher static uint32_t atom_arg_mask[8] =
77d38ceaf9SAlex Deucher { 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000,
78d38ceaf9SAlex Deucher 0xFF000000 };
79d38ceaf9SAlex Deucher static int atom_arg_shift[8] = { 0, 0, 8, 16, 0, 8, 16, 24 };
80d38ceaf9SAlex Deucher
81d38ceaf9SAlex Deucher static int atom_dst_to_src[8][4] = {
82d38ceaf9SAlex Deucher /* translate destination alignment field to the source alignment encoding */
83d38ceaf9SAlex Deucher {0, 0, 0, 0},
84d38ceaf9SAlex Deucher {1, 2, 3, 0},
85d38ceaf9SAlex Deucher {1, 2, 3, 0},
86d38ceaf9SAlex Deucher {1, 2, 3, 0},
87d38ceaf9SAlex Deucher {4, 5, 6, 7},
88d38ceaf9SAlex Deucher {4, 5, 6, 7},
89d38ceaf9SAlex Deucher {4, 5, 6, 7},
90d38ceaf9SAlex Deucher {4, 5, 6, 7},
91d38ceaf9SAlex Deucher };
92d38ceaf9SAlex Deucher static int atom_def_dst[8] = { 0, 0, 1, 2, 0, 1, 2, 3 };
93d38ceaf9SAlex Deucher
9487fb7833SDeepak R Varma static int debug_depth;
95d38ceaf9SAlex Deucher #ifdef ATOM_DEBUG
debug_print_spaces(int n)96d38ceaf9SAlex Deucher static void debug_print_spaces(int n)
97d38ceaf9SAlex Deucher {
98d38ceaf9SAlex Deucher while (n--)
99d38ceaf9SAlex Deucher printk(" ");
100d38ceaf9SAlex Deucher }
101d38ceaf9SAlex Deucher
102d38ceaf9SAlex Deucher #define DEBUG(...) do if (amdgpu_atom_debug) { printk(KERN_DEBUG __VA_ARGS__); } while (0)
103d38ceaf9SAlex Deucher #define SDEBUG(...) do if (amdgpu_atom_debug) { printk(KERN_DEBUG); debug_print_spaces(debug_depth); printk(__VA_ARGS__); } while (0)
104d38ceaf9SAlex Deucher #else
105d38ceaf9SAlex Deucher #define DEBUG(...) do { } while (0)
106d38ceaf9SAlex Deucher #define SDEBUG(...) do { } while (0)
107d38ceaf9SAlex Deucher #endif
108d38ceaf9SAlex Deucher
atom_iio_execute(struct atom_context * ctx,int base,uint32_t index,uint32_t data)109d38ceaf9SAlex Deucher static uint32_t atom_iio_execute(struct atom_context *ctx, int base,
110d38ceaf9SAlex Deucher uint32_t index, uint32_t data)
111d38ceaf9SAlex Deucher {
112d38ceaf9SAlex Deucher uint32_t temp = 0xCDCDCDCD;
113d38ceaf9SAlex Deucher
114d38ceaf9SAlex Deucher while (1)
115d38ceaf9SAlex Deucher switch (CU8(base)) {
116d38ceaf9SAlex Deucher case ATOM_IIO_NOP:
117d38ceaf9SAlex Deucher base++;
118d38ceaf9SAlex Deucher break;
119d38ceaf9SAlex Deucher case ATOM_IIO_READ:
120e99d2eaaSAlex Deucher temp = ctx->card->reg_read(ctx->card, CU16(base + 1));
121d38ceaf9SAlex Deucher base += 3;
122d38ceaf9SAlex Deucher break;
123d38ceaf9SAlex Deucher case ATOM_IIO_WRITE:
124e99d2eaaSAlex Deucher ctx->card->reg_write(ctx->card, CU16(base + 1), temp);
125d38ceaf9SAlex Deucher base += 3;
126d38ceaf9SAlex Deucher break;
127d38ceaf9SAlex Deucher case ATOM_IIO_CLEAR:
128d38ceaf9SAlex Deucher temp &=
129d38ceaf9SAlex Deucher ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
130d38ceaf9SAlex Deucher CU8(base + 2));
131d38ceaf9SAlex Deucher base += 3;
132d38ceaf9SAlex Deucher break;
133d38ceaf9SAlex Deucher case ATOM_IIO_SET:
134d38ceaf9SAlex Deucher temp |=
135d38ceaf9SAlex Deucher (0xFFFFFFFF >> (32 - CU8(base + 1))) << CU8(base +
136d38ceaf9SAlex Deucher 2);
137d38ceaf9SAlex Deucher base += 3;
138d38ceaf9SAlex Deucher break;
139d38ceaf9SAlex Deucher case ATOM_IIO_MOVE_INDEX:
140d38ceaf9SAlex Deucher temp &=
141d38ceaf9SAlex Deucher ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
142d38ceaf9SAlex Deucher CU8(base + 3));
143d38ceaf9SAlex Deucher temp |=
144d38ceaf9SAlex Deucher ((index >> CU8(base + 2)) &
145d38ceaf9SAlex Deucher (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base +
146d38ceaf9SAlex Deucher 3);
147d38ceaf9SAlex Deucher base += 4;
148d38ceaf9SAlex Deucher break;
149d38ceaf9SAlex Deucher case ATOM_IIO_MOVE_DATA:
150d38ceaf9SAlex Deucher temp &=
151d38ceaf9SAlex Deucher ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
152d38ceaf9SAlex Deucher CU8(base + 3));
153d38ceaf9SAlex Deucher temp |=
154d38ceaf9SAlex Deucher ((data >> CU8(base + 2)) &
155d38ceaf9SAlex Deucher (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base +
156d38ceaf9SAlex Deucher 3);
157d38ceaf9SAlex Deucher base += 4;
158d38ceaf9SAlex Deucher break;
159d38ceaf9SAlex Deucher case ATOM_IIO_MOVE_ATTR:
160d38ceaf9SAlex Deucher temp &=
161d38ceaf9SAlex Deucher ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
162d38ceaf9SAlex Deucher CU8(base + 3));
163d38ceaf9SAlex Deucher temp |=
164d38ceaf9SAlex Deucher ((ctx->
165d38ceaf9SAlex Deucher io_attr >> CU8(base + 2)) & (0xFFFFFFFF >> (32 -
166d38ceaf9SAlex Deucher CU8
167d38ceaf9SAlex Deucher (base
168d38ceaf9SAlex Deucher +
169d38ceaf9SAlex Deucher 1))))
170d38ceaf9SAlex Deucher << CU8(base + 3);
171d38ceaf9SAlex Deucher base += 4;
172d38ceaf9SAlex Deucher break;
173d38ceaf9SAlex Deucher case ATOM_IIO_END:
174d38ceaf9SAlex Deucher return temp;
175d38ceaf9SAlex Deucher default:
1767ca85295SJoe Perches pr_info("Unknown IIO opcode\n");
177d38ceaf9SAlex Deucher return 0;
178d38ceaf9SAlex Deucher }
179d38ceaf9SAlex Deucher }
180d38ceaf9SAlex Deucher
atom_get_src_int(atom_exec_context * ctx,uint8_t attr,int * ptr,uint32_t * saved,int print)181d38ceaf9SAlex Deucher static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr,
182d38ceaf9SAlex Deucher int *ptr, uint32_t *saved, int print)
183d38ceaf9SAlex Deucher {
184d38ceaf9SAlex Deucher uint32_t idx, val = 0xCDCDCDCD, align, arg;
185d38ceaf9SAlex Deucher struct atom_context *gctx = ctx->ctx;
186d38ceaf9SAlex Deucher arg = attr & 7;
187d38ceaf9SAlex Deucher align = (attr >> 3) & 7;
188d38ceaf9SAlex Deucher switch (arg) {
189d38ceaf9SAlex Deucher case ATOM_ARG_REG:
190d38ceaf9SAlex Deucher idx = U16(*ptr);
191d38ceaf9SAlex Deucher (*ptr) += 2;
192d38ceaf9SAlex Deucher if (print)
193d38ceaf9SAlex Deucher DEBUG("REG[0x%04X]", idx);
194d38ceaf9SAlex Deucher idx += gctx->reg_block;
195d38ceaf9SAlex Deucher switch (gctx->io_mode) {
196d38ceaf9SAlex Deucher case ATOM_IO_MM:
197d38ceaf9SAlex Deucher val = gctx->card->reg_read(gctx->card, idx);
198d38ceaf9SAlex Deucher break;
199d38ceaf9SAlex Deucher case ATOM_IO_PCI:
2007ca85295SJoe Perches pr_info("PCI registers are not implemented\n");
201d38ceaf9SAlex Deucher return 0;
202d38ceaf9SAlex Deucher case ATOM_IO_SYSIO:
2037ca85295SJoe Perches pr_info("SYSIO registers are not implemented\n");
204d38ceaf9SAlex Deucher return 0;
205d38ceaf9SAlex Deucher default:
206d38ceaf9SAlex Deucher if (!(gctx->io_mode & 0x80)) {
2077ca85295SJoe Perches pr_info("Bad IO mode\n");
208d38ceaf9SAlex Deucher return 0;
209d38ceaf9SAlex Deucher }
210d38ceaf9SAlex Deucher if (!gctx->iio[gctx->io_mode & 0x7F]) {
2117ca85295SJoe Perches pr_info("Undefined indirect IO read method %d\n",
212d38ceaf9SAlex Deucher gctx->io_mode & 0x7F);
213d38ceaf9SAlex Deucher return 0;
214d38ceaf9SAlex Deucher }
215d38ceaf9SAlex Deucher val =
216d38ceaf9SAlex Deucher atom_iio_execute(gctx,
217d38ceaf9SAlex Deucher gctx->iio[gctx->io_mode & 0x7F],
218d38ceaf9SAlex Deucher idx, 0);
219d38ceaf9SAlex Deucher }
220d38ceaf9SAlex Deucher break;
221d38ceaf9SAlex Deucher case ATOM_ARG_PS:
222d38ceaf9SAlex Deucher idx = U8(*ptr);
223d38ceaf9SAlex Deucher (*ptr)++;
224d38ceaf9SAlex Deucher /* get_unaligned_le32 avoids unaligned accesses from atombios
225d38ceaf9SAlex Deucher * tables, noticed on a DEC Alpha. */
226d38ceaf9SAlex Deucher val = get_unaligned_le32((u32 *)&ctx->ps[idx]);
227d38ceaf9SAlex Deucher if (print)
228d38ceaf9SAlex Deucher DEBUG("PS[0x%02X,0x%04X]", idx, val);
229d38ceaf9SAlex Deucher break;
230d38ceaf9SAlex Deucher case ATOM_ARG_WS:
231d38ceaf9SAlex Deucher idx = U8(*ptr);
232d38ceaf9SAlex Deucher (*ptr)++;
233d38ceaf9SAlex Deucher if (print)
234d38ceaf9SAlex Deucher DEBUG("WS[0x%02X]", idx);
235d38ceaf9SAlex Deucher switch (idx) {
236d38ceaf9SAlex Deucher case ATOM_WS_QUOTIENT:
237d38ceaf9SAlex Deucher val = gctx->divmul[0];
238d38ceaf9SAlex Deucher break;
239d38ceaf9SAlex Deucher case ATOM_WS_REMAINDER:
240d38ceaf9SAlex Deucher val = gctx->divmul[1];
241d38ceaf9SAlex Deucher break;
242d38ceaf9SAlex Deucher case ATOM_WS_DATAPTR:
243d38ceaf9SAlex Deucher val = gctx->data_block;
244d38ceaf9SAlex Deucher break;
245d38ceaf9SAlex Deucher case ATOM_WS_SHIFT:
246d38ceaf9SAlex Deucher val = gctx->shift;
247d38ceaf9SAlex Deucher break;
248d38ceaf9SAlex Deucher case ATOM_WS_OR_MASK:
249d38ceaf9SAlex Deucher val = 1 << gctx->shift;
250d38ceaf9SAlex Deucher break;
251d38ceaf9SAlex Deucher case ATOM_WS_AND_MASK:
252d38ceaf9SAlex Deucher val = ~(1 << gctx->shift);
253d38ceaf9SAlex Deucher break;
254d38ceaf9SAlex Deucher case ATOM_WS_FB_WINDOW:
255d38ceaf9SAlex Deucher val = gctx->fb_base;
256d38ceaf9SAlex Deucher break;
257d38ceaf9SAlex Deucher case ATOM_WS_ATTRIBUTES:
258d38ceaf9SAlex Deucher val = gctx->io_attr;
259d38ceaf9SAlex Deucher break;
260d38ceaf9SAlex Deucher case ATOM_WS_REGPTR:
261d38ceaf9SAlex Deucher val = gctx->reg_block;
262d38ceaf9SAlex Deucher break;
263d38ceaf9SAlex Deucher default:
264d38ceaf9SAlex Deucher val = ctx->ws[idx];
265d38ceaf9SAlex Deucher }
266d38ceaf9SAlex Deucher break;
267d38ceaf9SAlex Deucher case ATOM_ARG_ID:
268d38ceaf9SAlex Deucher idx = U16(*ptr);
269d38ceaf9SAlex Deucher (*ptr) += 2;
270d38ceaf9SAlex Deucher if (print) {
271d38ceaf9SAlex Deucher if (gctx->data_block)
272d38ceaf9SAlex Deucher DEBUG("ID[0x%04X+%04X]", idx, gctx->data_block);
273d38ceaf9SAlex Deucher else
274d38ceaf9SAlex Deucher DEBUG("ID[0x%04X]", idx);
275d38ceaf9SAlex Deucher }
276d38ceaf9SAlex Deucher val = U32(idx + gctx->data_block);
277d38ceaf9SAlex Deucher break;
278d38ceaf9SAlex Deucher case ATOM_ARG_FB:
279d38ceaf9SAlex Deucher idx = U8(*ptr);
280d38ceaf9SAlex Deucher (*ptr)++;
281d38ceaf9SAlex Deucher if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) {
282d38ceaf9SAlex Deucher DRM_ERROR("ATOM: fb read beyond scratch region: %d vs. %d\n",
283d38ceaf9SAlex Deucher gctx->fb_base + (idx * 4), gctx->scratch_size_bytes);
284d38ceaf9SAlex Deucher val = 0;
285d38ceaf9SAlex Deucher } else
286d38ceaf9SAlex Deucher val = gctx->scratch[(gctx->fb_base / 4) + idx];
287d38ceaf9SAlex Deucher if (print)
288d38ceaf9SAlex Deucher DEBUG("FB[0x%02X]", idx);
289d38ceaf9SAlex Deucher break;
290d38ceaf9SAlex Deucher case ATOM_ARG_IMM:
291d38ceaf9SAlex Deucher switch (align) {
292d38ceaf9SAlex Deucher case ATOM_SRC_DWORD:
293d38ceaf9SAlex Deucher val = U32(*ptr);
294d38ceaf9SAlex Deucher (*ptr) += 4;
295d38ceaf9SAlex Deucher if (print)
296d38ceaf9SAlex Deucher DEBUG("IMM 0x%08X\n", val);
297d38ceaf9SAlex Deucher return val;
298d38ceaf9SAlex Deucher case ATOM_SRC_WORD0:
299d38ceaf9SAlex Deucher case ATOM_SRC_WORD8:
300d38ceaf9SAlex Deucher case ATOM_SRC_WORD16:
301d38ceaf9SAlex Deucher val = U16(*ptr);
302d38ceaf9SAlex Deucher (*ptr) += 2;
303d38ceaf9SAlex Deucher if (print)
304d38ceaf9SAlex Deucher DEBUG("IMM 0x%04X\n", val);
305d38ceaf9SAlex Deucher return val;
306d38ceaf9SAlex Deucher case ATOM_SRC_BYTE0:
307d38ceaf9SAlex Deucher case ATOM_SRC_BYTE8:
308d38ceaf9SAlex Deucher case ATOM_SRC_BYTE16:
309d38ceaf9SAlex Deucher case ATOM_SRC_BYTE24:
310d38ceaf9SAlex Deucher val = U8(*ptr);
311d38ceaf9SAlex Deucher (*ptr)++;
312d38ceaf9SAlex Deucher if (print)
313d38ceaf9SAlex Deucher DEBUG("IMM 0x%02X\n", val);
314d38ceaf9SAlex Deucher return val;
315d38ceaf9SAlex Deucher }
316*bf13e50aSSrinivasan Shanmugam break;
317d38ceaf9SAlex Deucher case ATOM_ARG_PLL:
318d38ceaf9SAlex Deucher idx = U8(*ptr);
319d38ceaf9SAlex Deucher (*ptr)++;
320d38ceaf9SAlex Deucher if (print)
321d38ceaf9SAlex Deucher DEBUG("PLL[0x%02X]", idx);
322d38ceaf9SAlex Deucher val = gctx->card->pll_read(gctx->card, idx);
323d38ceaf9SAlex Deucher break;
324d38ceaf9SAlex Deucher case ATOM_ARG_MC:
325d38ceaf9SAlex Deucher idx = U8(*ptr);
326d38ceaf9SAlex Deucher (*ptr)++;
327d38ceaf9SAlex Deucher if (print)
328d38ceaf9SAlex Deucher DEBUG("MC[0x%02X]", idx);
329d38ceaf9SAlex Deucher val = gctx->card->mc_read(gctx->card, idx);
330d38ceaf9SAlex Deucher break;
331d38ceaf9SAlex Deucher }
332d38ceaf9SAlex Deucher if (saved)
333d38ceaf9SAlex Deucher *saved = val;
334d38ceaf9SAlex Deucher val &= atom_arg_mask[align];
335d38ceaf9SAlex Deucher val >>= atom_arg_shift[align];
336d38ceaf9SAlex Deucher if (print)
337d38ceaf9SAlex Deucher switch (align) {
338d38ceaf9SAlex Deucher case ATOM_SRC_DWORD:
339d38ceaf9SAlex Deucher DEBUG(".[31:0] -> 0x%08X\n", val);
340d38ceaf9SAlex Deucher break;
341d38ceaf9SAlex Deucher case ATOM_SRC_WORD0:
342d38ceaf9SAlex Deucher DEBUG(".[15:0] -> 0x%04X\n", val);
343d38ceaf9SAlex Deucher break;
344d38ceaf9SAlex Deucher case ATOM_SRC_WORD8:
345d38ceaf9SAlex Deucher DEBUG(".[23:8] -> 0x%04X\n", val);
346d38ceaf9SAlex Deucher break;
347d38ceaf9SAlex Deucher case ATOM_SRC_WORD16:
348d38ceaf9SAlex Deucher DEBUG(".[31:16] -> 0x%04X\n", val);
349d38ceaf9SAlex Deucher break;
350d38ceaf9SAlex Deucher case ATOM_SRC_BYTE0:
351d38ceaf9SAlex Deucher DEBUG(".[7:0] -> 0x%02X\n", val);
352d38ceaf9SAlex Deucher break;
353d38ceaf9SAlex Deucher case ATOM_SRC_BYTE8:
354d38ceaf9SAlex Deucher DEBUG(".[15:8] -> 0x%02X\n", val);
355d38ceaf9SAlex Deucher break;
356d38ceaf9SAlex Deucher case ATOM_SRC_BYTE16:
357d38ceaf9SAlex Deucher DEBUG(".[23:16] -> 0x%02X\n", val);
358d38ceaf9SAlex Deucher break;
359d38ceaf9SAlex Deucher case ATOM_SRC_BYTE24:
360d38ceaf9SAlex Deucher DEBUG(".[31:24] -> 0x%02X\n", val);
361d38ceaf9SAlex Deucher break;
362d38ceaf9SAlex Deucher }
363d38ceaf9SAlex Deucher return val;
364d38ceaf9SAlex Deucher }
365d38ceaf9SAlex Deucher
atom_skip_src_int(atom_exec_context * ctx,uint8_t attr,int * ptr)366d38ceaf9SAlex Deucher static void atom_skip_src_int(atom_exec_context *ctx, uint8_t attr, int *ptr)
367d38ceaf9SAlex Deucher {
368d38ceaf9SAlex Deucher uint32_t align = (attr >> 3) & 7, arg = attr & 7;
369d38ceaf9SAlex Deucher switch (arg) {
370d38ceaf9SAlex Deucher case ATOM_ARG_REG:
371d38ceaf9SAlex Deucher case ATOM_ARG_ID:
372d38ceaf9SAlex Deucher (*ptr) += 2;
373d38ceaf9SAlex Deucher break;
374d38ceaf9SAlex Deucher case ATOM_ARG_PLL:
375d38ceaf9SAlex Deucher case ATOM_ARG_MC:
376d38ceaf9SAlex Deucher case ATOM_ARG_PS:
377d38ceaf9SAlex Deucher case ATOM_ARG_WS:
378d38ceaf9SAlex Deucher case ATOM_ARG_FB:
379d38ceaf9SAlex Deucher (*ptr)++;
380d38ceaf9SAlex Deucher break;
381d38ceaf9SAlex Deucher case ATOM_ARG_IMM:
382d38ceaf9SAlex Deucher switch (align) {
383d38ceaf9SAlex Deucher case ATOM_SRC_DWORD:
384d38ceaf9SAlex Deucher (*ptr) += 4;
385d38ceaf9SAlex Deucher return;
386d38ceaf9SAlex Deucher case ATOM_SRC_WORD0:
387d38ceaf9SAlex Deucher case ATOM_SRC_WORD8:
388d38ceaf9SAlex Deucher case ATOM_SRC_WORD16:
389d38ceaf9SAlex Deucher (*ptr) += 2;
390d38ceaf9SAlex Deucher return;
391d38ceaf9SAlex Deucher case ATOM_SRC_BYTE0:
392d38ceaf9SAlex Deucher case ATOM_SRC_BYTE8:
393d38ceaf9SAlex Deucher case ATOM_SRC_BYTE16:
394d38ceaf9SAlex Deucher case ATOM_SRC_BYTE24:
395d38ceaf9SAlex Deucher (*ptr)++;
396d38ceaf9SAlex Deucher return;
397d38ceaf9SAlex Deucher }
398d38ceaf9SAlex Deucher return;
399d38ceaf9SAlex Deucher }
400d38ceaf9SAlex Deucher }
401d38ceaf9SAlex Deucher
atom_get_src(atom_exec_context * ctx,uint8_t attr,int * ptr)402d38ceaf9SAlex Deucher static uint32_t atom_get_src(atom_exec_context *ctx, uint8_t attr, int *ptr)
403d38ceaf9SAlex Deucher {
404d38ceaf9SAlex Deucher return atom_get_src_int(ctx, attr, ptr, NULL, 1);
405d38ceaf9SAlex Deucher }
406d38ceaf9SAlex Deucher
atom_get_src_direct(atom_exec_context * ctx,uint8_t align,int * ptr)407d38ceaf9SAlex Deucher static uint32_t atom_get_src_direct(atom_exec_context *ctx, uint8_t align, int *ptr)
408d38ceaf9SAlex Deucher {
409d38ceaf9SAlex Deucher uint32_t val = 0xCDCDCDCD;
410d38ceaf9SAlex Deucher
411d38ceaf9SAlex Deucher switch (align) {
412d38ceaf9SAlex Deucher case ATOM_SRC_DWORD:
413d38ceaf9SAlex Deucher val = U32(*ptr);
414d38ceaf9SAlex Deucher (*ptr) += 4;
415d38ceaf9SAlex Deucher break;
416d38ceaf9SAlex Deucher case ATOM_SRC_WORD0:
417d38ceaf9SAlex Deucher case ATOM_SRC_WORD8:
418d38ceaf9SAlex Deucher case ATOM_SRC_WORD16:
419d38ceaf9SAlex Deucher val = U16(*ptr);
420d38ceaf9SAlex Deucher (*ptr) += 2;
421d38ceaf9SAlex Deucher break;
422d38ceaf9SAlex Deucher case ATOM_SRC_BYTE0:
423d38ceaf9SAlex Deucher case ATOM_SRC_BYTE8:
424d38ceaf9SAlex Deucher case ATOM_SRC_BYTE16:
425d38ceaf9SAlex Deucher case ATOM_SRC_BYTE24:
426d38ceaf9SAlex Deucher val = U8(*ptr);
427d38ceaf9SAlex Deucher (*ptr)++;
428d38ceaf9SAlex Deucher break;
429d38ceaf9SAlex Deucher }
430d38ceaf9SAlex Deucher return val;
431d38ceaf9SAlex Deucher }
432d38ceaf9SAlex Deucher
atom_get_dst(atom_exec_context * ctx,int arg,uint8_t attr,int * ptr,uint32_t * saved,int print)433d38ceaf9SAlex Deucher static uint32_t atom_get_dst(atom_exec_context *ctx, int arg, uint8_t attr,
434d38ceaf9SAlex Deucher int *ptr, uint32_t *saved, int print)
435d38ceaf9SAlex Deucher {
436d38ceaf9SAlex Deucher return atom_get_src_int(ctx,
437d38ceaf9SAlex Deucher arg | atom_dst_to_src[(attr >> 3) &
438d38ceaf9SAlex Deucher 7][(attr >> 6) & 3] << 3,
439d38ceaf9SAlex Deucher ptr, saved, print);
440d38ceaf9SAlex Deucher }
441d38ceaf9SAlex Deucher
atom_skip_dst(atom_exec_context * ctx,int arg,uint8_t attr,int * ptr)442d38ceaf9SAlex Deucher static void atom_skip_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr)
443d38ceaf9SAlex Deucher {
444d38ceaf9SAlex Deucher atom_skip_src_int(ctx,
445d38ceaf9SAlex Deucher arg | atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) &
446d38ceaf9SAlex Deucher 3] << 3, ptr);
447d38ceaf9SAlex Deucher }
448d38ceaf9SAlex Deucher
atom_put_dst(atom_exec_context * ctx,int arg,uint8_t attr,int * ptr,uint32_t val,uint32_t saved)449d38ceaf9SAlex Deucher static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr,
450d38ceaf9SAlex Deucher int *ptr, uint32_t val, uint32_t saved)
451d38ceaf9SAlex Deucher {
452d38ceaf9SAlex Deucher uint32_t align =
453d38ceaf9SAlex Deucher atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3], old_val =
454d38ceaf9SAlex Deucher val, idx;
455d38ceaf9SAlex Deucher struct atom_context *gctx = ctx->ctx;
456d38ceaf9SAlex Deucher old_val &= atom_arg_mask[align] >> atom_arg_shift[align];
457d38ceaf9SAlex Deucher val <<= atom_arg_shift[align];
458d38ceaf9SAlex Deucher val &= atom_arg_mask[align];
459d38ceaf9SAlex Deucher saved &= ~atom_arg_mask[align];
460d38ceaf9SAlex Deucher val |= saved;
461d38ceaf9SAlex Deucher switch (arg) {
462d38ceaf9SAlex Deucher case ATOM_ARG_REG:
463d38ceaf9SAlex Deucher idx = U16(*ptr);
464d38ceaf9SAlex Deucher (*ptr) += 2;
465d38ceaf9SAlex Deucher DEBUG("REG[0x%04X]", idx);
466d38ceaf9SAlex Deucher idx += gctx->reg_block;
467d38ceaf9SAlex Deucher switch (gctx->io_mode) {
468d38ceaf9SAlex Deucher case ATOM_IO_MM:
469d38ceaf9SAlex Deucher if (idx == 0)
470d38ceaf9SAlex Deucher gctx->card->reg_write(gctx->card, idx,
471d38ceaf9SAlex Deucher val << 2);
472d38ceaf9SAlex Deucher else
473d38ceaf9SAlex Deucher gctx->card->reg_write(gctx->card, idx, val);
474d38ceaf9SAlex Deucher break;
475d38ceaf9SAlex Deucher case ATOM_IO_PCI:
4767ca85295SJoe Perches pr_info("PCI registers are not implemented\n");
477d38ceaf9SAlex Deucher return;
478d38ceaf9SAlex Deucher case ATOM_IO_SYSIO:
4797ca85295SJoe Perches pr_info("SYSIO registers are not implemented\n");
480d38ceaf9SAlex Deucher return;
481d38ceaf9SAlex Deucher default:
482d38ceaf9SAlex Deucher if (!(gctx->io_mode & 0x80)) {
4837ca85295SJoe Perches pr_info("Bad IO mode\n");
484d38ceaf9SAlex Deucher return;
485d38ceaf9SAlex Deucher }
486d38ceaf9SAlex Deucher if (!gctx->iio[gctx->io_mode & 0xFF]) {
4877ca85295SJoe Perches pr_info("Undefined indirect IO write method %d\n",
488d38ceaf9SAlex Deucher gctx->io_mode & 0x7F);
489d38ceaf9SAlex Deucher return;
490d38ceaf9SAlex Deucher }
491d38ceaf9SAlex Deucher atom_iio_execute(gctx, gctx->iio[gctx->io_mode & 0xFF],
492d38ceaf9SAlex Deucher idx, val);
493d38ceaf9SAlex Deucher }
494d38ceaf9SAlex Deucher break;
495d38ceaf9SAlex Deucher case ATOM_ARG_PS:
496d38ceaf9SAlex Deucher idx = U8(*ptr);
497d38ceaf9SAlex Deucher (*ptr)++;
498d38ceaf9SAlex Deucher DEBUG("PS[0x%02X]", idx);
499d38ceaf9SAlex Deucher ctx->ps[idx] = cpu_to_le32(val);
500d38ceaf9SAlex Deucher break;
501d38ceaf9SAlex Deucher case ATOM_ARG_WS:
502d38ceaf9SAlex Deucher idx = U8(*ptr);
503d38ceaf9SAlex Deucher (*ptr)++;
504d38ceaf9SAlex Deucher DEBUG("WS[0x%02X]", idx);
505d38ceaf9SAlex Deucher switch (idx) {
506d38ceaf9SAlex Deucher case ATOM_WS_QUOTIENT:
507d38ceaf9SAlex Deucher gctx->divmul[0] = val;
508d38ceaf9SAlex Deucher break;
509d38ceaf9SAlex Deucher case ATOM_WS_REMAINDER:
510d38ceaf9SAlex Deucher gctx->divmul[1] = val;
511d38ceaf9SAlex Deucher break;
512d38ceaf9SAlex Deucher case ATOM_WS_DATAPTR:
513d38ceaf9SAlex Deucher gctx->data_block = val;
514d38ceaf9SAlex Deucher break;
515d38ceaf9SAlex Deucher case ATOM_WS_SHIFT:
516d38ceaf9SAlex Deucher gctx->shift = val;
517d38ceaf9SAlex Deucher break;
518d38ceaf9SAlex Deucher case ATOM_WS_OR_MASK:
519d38ceaf9SAlex Deucher case ATOM_WS_AND_MASK:
520d38ceaf9SAlex Deucher break;
521d38ceaf9SAlex Deucher case ATOM_WS_FB_WINDOW:
522d38ceaf9SAlex Deucher gctx->fb_base = val;
523d38ceaf9SAlex Deucher break;
524d38ceaf9SAlex Deucher case ATOM_WS_ATTRIBUTES:
525d38ceaf9SAlex Deucher gctx->io_attr = val;
526d38ceaf9SAlex Deucher break;
527d38ceaf9SAlex Deucher case ATOM_WS_REGPTR:
528d38ceaf9SAlex Deucher gctx->reg_block = val;
529d38ceaf9SAlex Deucher break;
530d38ceaf9SAlex Deucher default:
531d38ceaf9SAlex Deucher ctx->ws[idx] = val;
532d38ceaf9SAlex Deucher }
533d38ceaf9SAlex Deucher break;
534d38ceaf9SAlex Deucher case ATOM_ARG_FB:
535d38ceaf9SAlex Deucher idx = U8(*ptr);
536d38ceaf9SAlex Deucher (*ptr)++;
537d38ceaf9SAlex Deucher if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) {
538d38ceaf9SAlex Deucher DRM_ERROR("ATOM: fb write beyond scratch region: %d vs. %d\n",
539d38ceaf9SAlex Deucher gctx->fb_base + (idx * 4), gctx->scratch_size_bytes);
540d38ceaf9SAlex Deucher } else
541d38ceaf9SAlex Deucher gctx->scratch[(gctx->fb_base / 4) + idx] = val;
542d38ceaf9SAlex Deucher DEBUG("FB[0x%02X]", idx);
543d38ceaf9SAlex Deucher break;
544d38ceaf9SAlex Deucher case ATOM_ARG_PLL:
545d38ceaf9SAlex Deucher idx = U8(*ptr);
546d38ceaf9SAlex Deucher (*ptr)++;
547d38ceaf9SAlex Deucher DEBUG("PLL[0x%02X]", idx);
548d38ceaf9SAlex Deucher gctx->card->pll_write(gctx->card, idx, val);
549d38ceaf9SAlex Deucher break;
550d38ceaf9SAlex Deucher case ATOM_ARG_MC:
551d38ceaf9SAlex Deucher idx = U8(*ptr);
552d38ceaf9SAlex Deucher (*ptr)++;
553d38ceaf9SAlex Deucher DEBUG("MC[0x%02X]", idx);
554d38ceaf9SAlex Deucher gctx->card->mc_write(gctx->card, idx, val);
555d38ceaf9SAlex Deucher return;
556d38ceaf9SAlex Deucher }
557d38ceaf9SAlex Deucher switch (align) {
558d38ceaf9SAlex Deucher case ATOM_SRC_DWORD:
559d38ceaf9SAlex Deucher DEBUG(".[31:0] <- 0x%08X\n", old_val);
560d38ceaf9SAlex Deucher break;
561d38ceaf9SAlex Deucher case ATOM_SRC_WORD0:
562d38ceaf9SAlex Deucher DEBUG(".[15:0] <- 0x%04X\n", old_val);
563d38ceaf9SAlex Deucher break;
564d38ceaf9SAlex Deucher case ATOM_SRC_WORD8:
565d38ceaf9SAlex Deucher DEBUG(".[23:8] <- 0x%04X\n", old_val);
566d38ceaf9SAlex Deucher break;
567d38ceaf9SAlex Deucher case ATOM_SRC_WORD16:
568d38ceaf9SAlex Deucher DEBUG(".[31:16] <- 0x%04X\n", old_val);
569d38ceaf9SAlex Deucher break;
570d38ceaf9SAlex Deucher case ATOM_SRC_BYTE0:
571d38ceaf9SAlex Deucher DEBUG(".[7:0] <- 0x%02X\n", old_val);
572d38ceaf9SAlex Deucher break;
573d38ceaf9SAlex Deucher case ATOM_SRC_BYTE8:
574d38ceaf9SAlex Deucher DEBUG(".[15:8] <- 0x%02X\n", old_val);
575d38ceaf9SAlex Deucher break;
576d38ceaf9SAlex Deucher case ATOM_SRC_BYTE16:
577d38ceaf9SAlex Deucher DEBUG(".[23:16] <- 0x%02X\n", old_val);
578d38ceaf9SAlex Deucher break;
579d38ceaf9SAlex Deucher case ATOM_SRC_BYTE24:
580d38ceaf9SAlex Deucher DEBUG(".[31:24] <- 0x%02X\n", old_val);
581d38ceaf9SAlex Deucher break;
582d38ceaf9SAlex Deucher }
583d38ceaf9SAlex Deucher }
584d38ceaf9SAlex Deucher
atom_op_add(atom_exec_context * ctx,int * ptr,int arg)585d38ceaf9SAlex Deucher static void atom_op_add(atom_exec_context *ctx, int *ptr, int arg)
586d38ceaf9SAlex Deucher {
587d38ceaf9SAlex Deucher uint8_t attr = U8((*ptr)++);
588d38ceaf9SAlex Deucher uint32_t dst, src, saved;
589d38ceaf9SAlex Deucher int dptr = *ptr;
590d38ceaf9SAlex Deucher SDEBUG(" dst: ");
591d38ceaf9SAlex Deucher dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
592d38ceaf9SAlex Deucher SDEBUG(" src: ");
593d38ceaf9SAlex Deucher src = atom_get_src(ctx, attr, ptr);
594d38ceaf9SAlex Deucher dst += src;
595d38ceaf9SAlex Deucher SDEBUG(" dst: ");
596d38ceaf9SAlex Deucher atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
597d38ceaf9SAlex Deucher }
598d38ceaf9SAlex Deucher
atom_op_and(atom_exec_context * ctx,int * ptr,int arg)599d38ceaf9SAlex Deucher static void atom_op_and(atom_exec_context *ctx, int *ptr, int arg)
600d38ceaf9SAlex Deucher {
601d38ceaf9SAlex Deucher uint8_t attr = U8((*ptr)++);
602d38ceaf9SAlex Deucher uint32_t dst, src, saved;
603d38ceaf9SAlex Deucher int dptr = *ptr;
604d38ceaf9SAlex Deucher SDEBUG(" dst: ");
605d38ceaf9SAlex Deucher dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
606d38ceaf9SAlex Deucher SDEBUG(" src: ");
607d38ceaf9SAlex Deucher src = atom_get_src(ctx, attr, ptr);
608d38ceaf9SAlex Deucher dst &= src;
609d38ceaf9SAlex Deucher SDEBUG(" dst: ");
610d38ceaf9SAlex Deucher atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
611d38ceaf9SAlex Deucher }
612d38ceaf9SAlex Deucher
atom_op_beep(atom_exec_context * ctx,int * ptr,int arg)613d38ceaf9SAlex Deucher static void atom_op_beep(atom_exec_context *ctx, int *ptr, int arg)
614d38ceaf9SAlex Deucher {
615d38ceaf9SAlex Deucher printk("ATOM BIOS beeped!\n");
616d38ceaf9SAlex Deucher }
617d38ceaf9SAlex Deucher
atom_op_calltable(atom_exec_context * ctx,int * ptr,int arg)618d38ceaf9SAlex Deucher static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg)
619d38ceaf9SAlex Deucher {
620d38ceaf9SAlex Deucher int idx = U8((*ptr)++);
621d38ceaf9SAlex Deucher int r = 0;
622d38ceaf9SAlex Deucher
623d38ceaf9SAlex Deucher if (idx < ATOM_TABLE_NAMES_CNT)
624d38ceaf9SAlex Deucher SDEBUG(" table: %d (%s)\n", idx, atom_table_names[idx]);
625d38ceaf9SAlex Deucher else
626d38ceaf9SAlex Deucher SDEBUG(" table: %d\n", idx);
627d38ceaf9SAlex Deucher if (U16(ctx->ctx->cmd_table + 4 + 2 * idx))
628d38ceaf9SAlex Deucher r = amdgpu_atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift);
629d38ceaf9SAlex Deucher if (r) {
630d38ceaf9SAlex Deucher ctx->abort = true;
631d38ceaf9SAlex Deucher }
632d38ceaf9SAlex Deucher }
633d38ceaf9SAlex Deucher
atom_op_clear(atom_exec_context * ctx,int * ptr,int arg)634d38ceaf9SAlex Deucher static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg)
635d38ceaf9SAlex Deucher {
636d38ceaf9SAlex Deucher uint8_t attr = U8((*ptr)++);
637d38ceaf9SAlex Deucher uint32_t saved;
638d38ceaf9SAlex Deucher int dptr = *ptr;
639d38ceaf9SAlex Deucher attr &= 0x38;
640d38ceaf9SAlex Deucher attr |= atom_def_dst[attr >> 3] << 6;
641d38ceaf9SAlex Deucher atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
642d38ceaf9SAlex Deucher SDEBUG(" dst: ");
643d38ceaf9SAlex Deucher atom_put_dst(ctx, arg, attr, &dptr, 0, saved);
644d38ceaf9SAlex Deucher }
645d38ceaf9SAlex Deucher
atom_op_compare(atom_exec_context * ctx,int * ptr,int arg)646d38ceaf9SAlex Deucher static void atom_op_compare(atom_exec_context *ctx, int *ptr, int arg)
647d38ceaf9SAlex Deucher {
648d38ceaf9SAlex Deucher uint8_t attr = U8((*ptr)++);
649d38ceaf9SAlex Deucher uint32_t dst, src;
650d38ceaf9SAlex Deucher SDEBUG(" src1: ");
651d38ceaf9SAlex Deucher dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
652d38ceaf9SAlex Deucher SDEBUG(" src2: ");
653d38ceaf9SAlex Deucher src = atom_get_src(ctx, attr, ptr);
654d38ceaf9SAlex Deucher ctx->ctx->cs_equal = (dst == src);
655d38ceaf9SAlex Deucher ctx->ctx->cs_above = (dst > src);
656d38ceaf9SAlex Deucher SDEBUG(" result: %s %s\n", ctx->ctx->cs_equal ? "EQ" : "NE",
657d38ceaf9SAlex Deucher ctx->ctx->cs_above ? "GT" : "LE");
658d38ceaf9SAlex Deucher }
659d38ceaf9SAlex Deucher
atom_op_delay(atom_exec_context * ctx,int * ptr,int arg)660d38ceaf9SAlex Deucher static void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg)
661d38ceaf9SAlex Deucher {
662d38ceaf9SAlex Deucher unsigned count = U8((*ptr)++);
663d38ceaf9SAlex Deucher SDEBUG(" count: %d\n", count);
664d38ceaf9SAlex Deucher if (arg == ATOM_UNIT_MICROSEC)
665d38ceaf9SAlex Deucher udelay(count);
666d38ceaf9SAlex Deucher else if (!drm_can_sleep())
667d38ceaf9SAlex Deucher mdelay(count);
668d38ceaf9SAlex Deucher else
669d38ceaf9SAlex Deucher msleep(count);
670d38ceaf9SAlex Deucher }
671d38ceaf9SAlex Deucher
atom_op_div(atom_exec_context * ctx,int * ptr,int arg)672d38ceaf9SAlex Deucher static void atom_op_div(atom_exec_context *ctx, int *ptr, int arg)
673d38ceaf9SAlex Deucher {
674d38ceaf9SAlex Deucher uint8_t attr = U8((*ptr)++);
675d38ceaf9SAlex Deucher uint32_t dst, src;
676d38ceaf9SAlex Deucher SDEBUG(" src1: ");
677d38ceaf9SAlex Deucher dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
678d38ceaf9SAlex Deucher SDEBUG(" src2: ");
679d38ceaf9SAlex Deucher src = atom_get_src(ctx, attr, ptr);
680d38ceaf9SAlex Deucher if (src != 0) {
681d38ceaf9SAlex Deucher ctx->ctx->divmul[0] = dst / src;
682d38ceaf9SAlex Deucher ctx->ctx->divmul[1] = dst % src;
683d38ceaf9SAlex Deucher } else {
684d38ceaf9SAlex Deucher ctx->ctx->divmul[0] = 0;
685d38ceaf9SAlex Deucher ctx->ctx->divmul[1] = 0;
686d38ceaf9SAlex Deucher }
687d38ceaf9SAlex Deucher }
688d38ceaf9SAlex Deucher
atom_op_div32(atom_exec_context * ctx,int * ptr,int arg)689c2fe16aaSAlex Deucher static void atom_op_div32(atom_exec_context *ctx, int *ptr, int arg)
690c2fe16aaSAlex Deucher {
691c2fe16aaSAlex Deucher uint64_t val64;
692c2fe16aaSAlex Deucher uint8_t attr = U8((*ptr)++);
693c2fe16aaSAlex Deucher uint32_t dst, src;
694c2fe16aaSAlex Deucher SDEBUG(" src1: ");
695c2fe16aaSAlex Deucher dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
696c2fe16aaSAlex Deucher SDEBUG(" src2: ");
697c2fe16aaSAlex Deucher src = atom_get_src(ctx, attr, ptr);
698c2fe16aaSAlex Deucher if (src != 0) {
699c2fe16aaSAlex Deucher val64 = dst;
700c2fe16aaSAlex Deucher val64 |= ((uint64_t)ctx->ctx->divmul[1]) << 32;
701c2fe16aaSAlex Deucher do_div(val64, src);
702c2fe16aaSAlex Deucher ctx->ctx->divmul[0] = lower_32_bits(val64);
703c2fe16aaSAlex Deucher ctx->ctx->divmul[1] = upper_32_bits(val64);
704c2fe16aaSAlex Deucher } else {
705c2fe16aaSAlex Deucher ctx->ctx->divmul[0] = 0;
706c2fe16aaSAlex Deucher ctx->ctx->divmul[1] = 0;
707c2fe16aaSAlex Deucher }
708c2fe16aaSAlex Deucher }
709c2fe16aaSAlex Deucher
atom_op_eot(atom_exec_context * ctx,int * ptr,int arg)710d38ceaf9SAlex Deucher static void atom_op_eot(atom_exec_context *ctx, int *ptr, int arg)
711d38ceaf9SAlex Deucher {
712d38ceaf9SAlex Deucher /* functionally, a nop */
713d38ceaf9SAlex Deucher }
714d38ceaf9SAlex Deucher
atom_op_jump(atom_exec_context * ctx,int * ptr,int arg)715d38ceaf9SAlex Deucher static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
716d38ceaf9SAlex Deucher {
717d38ceaf9SAlex Deucher int execute = 0, target = U16(*ptr);
718d38ceaf9SAlex Deucher unsigned long cjiffies;
719d38ceaf9SAlex Deucher
720d38ceaf9SAlex Deucher (*ptr) += 2;
721d38ceaf9SAlex Deucher switch (arg) {
722d38ceaf9SAlex Deucher case ATOM_COND_ABOVE:
723d38ceaf9SAlex Deucher execute = ctx->ctx->cs_above;
724d38ceaf9SAlex Deucher break;
725d38ceaf9SAlex Deucher case ATOM_COND_ABOVEOREQUAL:
726d38ceaf9SAlex Deucher execute = ctx->ctx->cs_above || ctx->ctx->cs_equal;
727d38ceaf9SAlex Deucher break;
728d38ceaf9SAlex Deucher case ATOM_COND_ALWAYS:
729d38ceaf9SAlex Deucher execute = 1;
730d38ceaf9SAlex Deucher break;
731d38ceaf9SAlex Deucher case ATOM_COND_BELOW:
732d38ceaf9SAlex Deucher execute = !(ctx->ctx->cs_above || ctx->ctx->cs_equal);
733d38ceaf9SAlex Deucher break;
734d38ceaf9SAlex Deucher case ATOM_COND_BELOWOREQUAL:
735d38ceaf9SAlex Deucher execute = !ctx->ctx->cs_above;
736d38ceaf9SAlex Deucher break;
737d38ceaf9SAlex Deucher case ATOM_COND_EQUAL:
738d38ceaf9SAlex Deucher execute = ctx->ctx->cs_equal;
739d38ceaf9SAlex Deucher break;
740d38ceaf9SAlex Deucher case ATOM_COND_NOTEQUAL:
741d38ceaf9SAlex Deucher execute = !ctx->ctx->cs_equal;
742d38ceaf9SAlex Deucher break;
743d38ceaf9SAlex Deucher }
744d38ceaf9SAlex Deucher if (arg != ATOM_COND_ALWAYS)
745b8c75bd9SLucas De Marchi SDEBUG(" taken: %s\n", str_yes_no(execute));
746d38ceaf9SAlex Deucher SDEBUG(" target: 0x%04X\n", target);
747d38ceaf9SAlex Deucher if (execute) {
748d38ceaf9SAlex Deucher if (ctx->last_jump == (ctx->start + target)) {
749d38ceaf9SAlex Deucher cjiffies = jiffies;
750d38ceaf9SAlex Deucher if (time_after(cjiffies, ctx->last_jump_jiffies)) {
751d38ceaf9SAlex Deucher cjiffies -= ctx->last_jump_jiffies;
7529a785c7aSJohn Clements if ((jiffies_to_msecs(cjiffies) > ATOM_CMD_TIMEOUT_SEC*1000)) {
7539a785c7aSJohn Clements DRM_ERROR("atombios stuck in loop for more than %dsecs aborting\n",
7549a785c7aSJohn Clements ATOM_CMD_TIMEOUT_SEC);
755d38ceaf9SAlex Deucher ctx->abort = true;
756d38ceaf9SAlex Deucher }
757d38ceaf9SAlex Deucher } else {
758d38ceaf9SAlex Deucher /* jiffies wrap around we will just wait a little longer */
759d38ceaf9SAlex Deucher ctx->last_jump_jiffies = jiffies;
760d38ceaf9SAlex Deucher }
761d38ceaf9SAlex Deucher } else {
762d38ceaf9SAlex Deucher ctx->last_jump = ctx->start + target;
763d38ceaf9SAlex Deucher ctx->last_jump_jiffies = jiffies;
764d38ceaf9SAlex Deucher }
765d38ceaf9SAlex Deucher *ptr = ctx->start + target;
766d38ceaf9SAlex Deucher }
767d38ceaf9SAlex Deucher }
768d38ceaf9SAlex Deucher
atom_op_mask(atom_exec_context * ctx,int * ptr,int arg)769d38ceaf9SAlex Deucher static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg)
770d38ceaf9SAlex Deucher {
771d38ceaf9SAlex Deucher uint8_t attr = U8((*ptr)++);
772d38ceaf9SAlex Deucher uint32_t dst, mask, src, saved;
773d38ceaf9SAlex Deucher int dptr = *ptr;
774d38ceaf9SAlex Deucher SDEBUG(" dst: ");
775d38ceaf9SAlex Deucher dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
776d38ceaf9SAlex Deucher mask = atom_get_src_direct(ctx, ((attr >> 3) & 7), ptr);
777d38ceaf9SAlex Deucher SDEBUG(" mask: 0x%08x", mask);
778d38ceaf9SAlex Deucher SDEBUG(" src: ");
779d38ceaf9SAlex Deucher src = atom_get_src(ctx, attr, ptr);
780d38ceaf9SAlex Deucher dst &= mask;
781d38ceaf9SAlex Deucher dst |= src;
782d38ceaf9SAlex Deucher SDEBUG(" dst: ");
783d38ceaf9SAlex Deucher atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
784d38ceaf9SAlex Deucher }
785d38ceaf9SAlex Deucher
atom_op_move(atom_exec_context * ctx,int * ptr,int arg)786d38ceaf9SAlex Deucher static void atom_op_move(atom_exec_context *ctx, int *ptr, int arg)
787d38ceaf9SAlex Deucher {
788d38ceaf9SAlex Deucher uint8_t attr = U8((*ptr)++);
789d38ceaf9SAlex Deucher uint32_t src, saved;
790d38ceaf9SAlex Deucher int dptr = *ptr;
791d38ceaf9SAlex Deucher if (((attr >> 3) & 7) != ATOM_SRC_DWORD)
792d38ceaf9SAlex Deucher atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
793d38ceaf9SAlex Deucher else {
794d38ceaf9SAlex Deucher atom_skip_dst(ctx, arg, attr, ptr);
795d38ceaf9SAlex Deucher saved = 0xCDCDCDCD;
796d38ceaf9SAlex Deucher }
797d38ceaf9SAlex Deucher SDEBUG(" src: ");
798d38ceaf9SAlex Deucher src = atom_get_src(ctx, attr, ptr);
799d38ceaf9SAlex Deucher SDEBUG(" dst: ");
800d38ceaf9SAlex Deucher atom_put_dst(ctx, arg, attr, &dptr, src, saved);
801d38ceaf9SAlex Deucher }
802d38ceaf9SAlex Deucher
atom_op_mul(atom_exec_context * ctx,int * ptr,int arg)803d38ceaf9SAlex Deucher static void atom_op_mul(atom_exec_context *ctx, int *ptr, int arg)
804d38ceaf9SAlex Deucher {
805d38ceaf9SAlex Deucher uint8_t attr = U8((*ptr)++);
806d38ceaf9SAlex Deucher uint32_t dst, src;
807d38ceaf9SAlex Deucher SDEBUG(" src1: ");
808d38ceaf9SAlex Deucher dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
809d38ceaf9SAlex Deucher SDEBUG(" src2: ");
810d38ceaf9SAlex Deucher src = atom_get_src(ctx, attr, ptr);
811d38ceaf9SAlex Deucher ctx->ctx->divmul[0] = dst * src;
812d38ceaf9SAlex Deucher }
813d38ceaf9SAlex Deucher
atom_op_mul32(atom_exec_context * ctx,int * ptr,int arg)814c9c14502SAlex Deucher static void atom_op_mul32(atom_exec_context *ctx, int *ptr, int arg)
815c9c14502SAlex Deucher {
816c9c14502SAlex Deucher uint64_t val64;
817c9c14502SAlex Deucher uint8_t attr = U8((*ptr)++);
818c9c14502SAlex Deucher uint32_t dst, src;
819c9c14502SAlex Deucher SDEBUG(" src1: ");
820c9c14502SAlex Deucher dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
821c9c14502SAlex Deucher SDEBUG(" src2: ");
822c9c14502SAlex Deucher src = atom_get_src(ctx, attr, ptr);
823c9c14502SAlex Deucher val64 = (uint64_t)dst * (uint64_t)src;
824c9c14502SAlex Deucher ctx->ctx->divmul[0] = lower_32_bits(val64);
825c9c14502SAlex Deucher ctx->ctx->divmul[1] = upper_32_bits(val64);
826c9c14502SAlex Deucher }
827c9c14502SAlex Deucher
atom_op_nop(atom_exec_context * ctx,int * ptr,int arg)828d38ceaf9SAlex Deucher static void atom_op_nop(atom_exec_context *ctx, int *ptr, int arg)
829d38ceaf9SAlex Deucher {
830d38ceaf9SAlex Deucher /* nothing */
831d38ceaf9SAlex Deucher }
832d38ceaf9SAlex Deucher
atom_op_or(atom_exec_context * ctx,int * ptr,int arg)833d38ceaf9SAlex Deucher static void atom_op_or(atom_exec_context *ctx, int *ptr, int arg)
834d38ceaf9SAlex Deucher {
835d38ceaf9SAlex Deucher uint8_t attr = U8((*ptr)++);
836d38ceaf9SAlex Deucher uint32_t dst, src, saved;
837d38ceaf9SAlex Deucher int dptr = *ptr;
838d38ceaf9SAlex Deucher SDEBUG(" dst: ");
839d38ceaf9SAlex Deucher dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
840d38ceaf9SAlex Deucher SDEBUG(" src: ");
841d38ceaf9SAlex Deucher src = atom_get_src(ctx, attr, ptr);
842d38ceaf9SAlex Deucher dst |= src;
843d38ceaf9SAlex Deucher SDEBUG(" dst: ");
844d38ceaf9SAlex Deucher atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
845d38ceaf9SAlex Deucher }
846d38ceaf9SAlex Deucher
atom_op_postcard(atom_exec_context * ctx,int * ptr,int arg)847d38ceaf9SAlex Deucher static void atom_op_postcard(atom_exec_context *ctx, int *ptr, int arg)
848d38ceaf9SAlex Deucher {
849d38ceaf9SAlex Deucher uint8_t val = U8((*ptr)++);
850d38ceaf9SAlex Deucher SDEBUG("POST card output: 0x%02X\n", val);
851d38ceaf9SAlex Deucher }
852d38ceaf9SAlex Deucher
atom_op_repeat(atom_exec_context * ctx,int * ptr,int arg)853d38ceaf9SAlex Deucher static void atom_op_repeat(atom_exec_context *ctx, int *ptr, int arg)
854d38ceaf9SAlex Deucher {
8557ca85295SJoe Perches pr_info("unimplemented!\n");
856d38ceaf9SAlex Deucher }
857d38ceaf9SAlex Deucher
atom_op_restorereg(atom_exec_context * ctx,int * ptr,int arg)858d38ceaf9SAlex Deucher static void atom_op_restorereg(atom_exec_context *ctx, int *ptr, int arg)
859d38ceaf9SAlex Deucher {
8607ca85295SJoe Perches pr_info("unimplemented!\n");
861d38ceaf9SAlex Deucher }
862d38ceaf9SAlex Deucher
atom_op_savereg(atom_exec_context * ctx,int * ptr,int arg)863d38ceaf9SAlex Deucher static void atom_op_savereg(atom_exec_context *ctx, int *ptr, int arg)
864d38ceaf9SAlex Deucher {
8657ca85295SJoe Perches pr_info("unimplemented!\n");
866d38ceaf9SAlex Deucher }
867d38ceaf9SAlex Deucher
atom_op_setdatablock(atom_exec_context * ctx,int * ptr,int arg)868d38ceaf9SAlex Deucher static void atom_op_setdatablock(atom_exec_context *ctx, int *ptr, int arg)
869d38ceaf9SAlex Deucher {
870d38ceaf9SAlex Deucher int idx = U8(*ptr);
871d38ceaf9SAlex Deucher (*ptr)++;
872d38ceaf9SAlex Deucher SDEBUG(" block: %d\n", idx);
873d38ceaf9SAlex Deucher if (!idx)
874d38ceaf9SAlex Deucher ctx->ctx->data_block = 0;
875d38ceaf9SAlex Deucher else if (idx == 255)
876d38ceaf9SAlex Deucher ctx->ctx->data_block = ctx->start;
877d38ceaf9SAlex Deucher else
878d38ceaf9SAlex Deucher ctx->ctx->data_block = U16(ctx->ctx->data_table + 4 + 2 * idx);
879d38ceaf9SAlex Deucher SDEBUG(" base: 0x%04X\n", ctx->ctx->data_block);
880d38ceaf9SAlex Deucher }
881d38ceaf9SAlex Deucher
atom_op_setfbbase(atom_exec_context * ctx,int * ptr,int arg)882d38ceaf9SAlex Deucher static void atom_op_setfbbase(atom_exec_context *ctx, int *ptr, int arg)
883d38ceaf9SAlex Deucher {
884d38ceaf9SAlex Deucher uint8_t attr = U8((*ptr)++);
885d38ceaf9SAlex Deucher SDEBUG(" fb_base: ");
886d38ceaf9SAlex Deucher ctx->ctx->fb_base = atom_get_src(ctx, attr, ptr);
887d38ceaf9SAlex Deucher }
888d38ceaf9SAlex Deucher
atom_op_setport(atom_exec_context * ctx,int * ptr,int arg)889d38ceaf9SAlex Deucher static void atom_op_setport(atom_exec_context *ctx, int *ptr, int arg)
890d38ceaf9SAlex Deucher {
891d38ceaf9SAlex Deucher int port;
892d38ceaf9SAlex Deucher switch (arg) {
893d38ceaf9SAlex Deucher case ATOM_PORT_ATI:
894d38ceaf9SAlex Deucher port = U16(*ptr);
895d38ceaf9SAlex Deucher if (port < ATOM_IO_NAMES_CNT)
896d38ceaf9SAlex Deucher SDEBUG(" port: %d (%s)\n", port, atom_io_names[port]);
897d38ceaf9SAlex Deucher else
898d38ceaf9SAlex Deucher SDEBUG(" port: %d\n", port);
899d38ceaf9SAlex Deucher if (!port)
900d38ceaf9SAlex Deucher ctx->ctx->io_mode = ATOM_IO_MM;
901d38ceaf9SAlex Deucher else
902d38ceaf9SAlex Deucher ctx->ctx->io_mode = ATOM_IO_IIO | port;
903d38ceaf9SAlex Deucher (*ptr) += 2;
904d38ceaf9SAlex Deucher break;
905d38ceaf9SAlex Deucher case ATOM_PORT_PCI:
906d38ceaf9SAlex Deucher ctx->ctx->io_mode = ATOM_IO_PCI;
907d38ceaf9SAlex Deucher (*ptr)++;
908d38ceaf9SAlex Deucher break;
909d38ceaf9SAlex Deucher case ATOM_PORT_SYSIO:
910d38ceaf9SAlex Deucher ctx->ctx->io_mode = ATOM_IO_SYSIO;
911d38ceaf9SAlex Deucher (*ptr)++;
912d38ceaf9SAlex Deucher break;
913d38ceaf9SAlex Deucher }
914d38ceaf9SAlex Deucher }
915d38ceaf9SAlex Deucher
atom_op_setregblock(atom_exec_context * ctx,int * ptr,int arg)916d38ceaf9SAlex Deucher static void atom_op_setregblock(atom_exec_context *ctx, int *ptr, int arg)
917d38ceaf9SAlex Deucher {
918d38ceaf9SAlex Deucher ctx->ctx->reg_block = U16(*ptr);
919d38ceaf9SAlex Deucher (*ptr) += 2;
920d38ceaf9SAlex Deucher SDEBUG(" base: 0x%04X\n", ctx->ctx->reg_block);
921d38ceaf9SAlex Deucher }
922d38ceaf9SAlex Deucher
atom_op_shift_left(atom_exec_context * ctx,int * ptr,int arg)923d38ceaf9SAlex Deucher static void atom_op_shift_left(atom_exec_context *ctx, int *ptr, int arg)
924d38ceaf9SAlex Deucher {
925d38ceaf9SAlex Deucher uint8_t attr = U8((*ptr)++), shift;
926d38ceaf9SAlex Deucher uint32_t saved, dst;
927d38ceaf9SAlex Deucher int dptr = *ptr;
928d38ceaf9SAlex Deucher attr &= 0x38;
929d38ceaf9SAlex Deucher attr |= atom_def_dst[attr >> 3] << 6;
930d38ceaf9SAlex Deucher SDEBUG(" dst: ");
931d38ceaf9SAlex Deucher dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
932d38ceaf9SAlex Deucher shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr);
933d38ceaf9SAlex Deucher SDEBUG(" shift: %d\n", shift);
934d38ceaf9SAlex Deucher dst <<= shift;
935d38ceaf9SAlex Deucher SDEBUG(" dst: ");
936d38ceaf9SAlex Deucher atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
937d38ceaf9SAlex Deucher }
938d38ceaf9SAlex Deucher
atom_op_shift_right(atom_exec_context * ctx,int * ptr,int arg)939d38ceaf9SAlex Deucher static void atom_op_shift_right(atom_exec_context *ctx, int *ptr, int arg)
940d38ceaf9SAlex Deucher {
941d38ceaf9SAlex Deucher uint8_t attr = U8((*ptr)++), shift;
942d38ceaf9SAlex Deucher uint32_t saved, dst;
943d38ceaf9SAlex Deucher int dptr = *ptr;
944d38ceaf9SAlex Deucher attr &= 0x38;
945d38ceaf9SAlex Deucher attr |= atom_def_dst[attr >> 3] << 6;
946d38ceaf9SAlex Deucher SDEBUG(" dst: ");
947d38ceaf9SAlex Deucher dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
948d38ceaf9SAlex Deucher shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr);
949d38ceaf9SAlex Deucher SDEBUG(" shift: %d\n", shift);
950d38ceaf9SAlex Deucher dst >>= shift;
951d38ceaf9SAlex Deucher SDEBUG(" dst: ");
952d38ceaf9SAlex Deucher atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
953d38ceaf9SAlex Deucher }
954d38ceaf9SAlex Deucher
atom_op_shl(atom_exec_context * ctx,int * ptr,int arg)955d38ceaf9SAlex Deucher static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg)
956d38ceaf9SAlex Deucher {
957d38ceaf9SAlex Deucher uint8_t attr = U8((*ptr)++), shift;
958d38ceaf9SAlex Deucher uint32_t saved, dst;
959d38ceaf9SAlex Deucher int dptr = *ptr;
960d38ceaf9SAlex Deucher uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3];
961d38ceaf9SAlex Deucher SDEBUG(" dst: ");
962d38ceaf9SAlex Deucher dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
963d38ceaf9SAlex Deucher /* op needs to full dst value */
964d38ceaf9SAlex Deucher dst = saved;
965d38ceaf9SAlex Deucher shift = atom_get_src(ctx, attr, ptr);
966d38ceaf9SAlex Deucher SDEBUG(" shift: %d\n", shift);
967d38ceaf9SAlex Deucher dst <<= shift;
968d38ceaf9SAlex Deucher dst &= atom_arg_mask[dst_align];
969d38ceaf9SAlex Deucher dst >>= atom_arg_shift[dst_align];
970d38ceaf9SAlex Deucher SDEBUG(" dst: ");
971d38ceaf9SAlex Deucher atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
972d38ceaf9SAlex Deucher }
973d38ceaf9SAlex Deucher
atom_op_shr(atom_exec_context * ctx,int * ptr,int arg)974d38ceaf9SAlex Deucher static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg)
975d38ceaf9SAlex Deucher {
976d38ceaf9SAlex Deucher uint8_t attr = U8((*ptr)++), shift;
977d38ceaf9SAlex Deucher uint32_t saved, dst;
978d38ceaf9SAlex Deucher int dptr = *ptr;
979d38ceaf9SAlex Deucher uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3];
980d38ceaf9SAlex Deucher SDEBUG(" dst: ");
981d38ceaf9SAlex Deucher dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
982d38ceaf9SAlex Deucher /* op needs to full dst value */
983d38ceaf9SAlex Deucher dst = saved;
984d38ceaf9SAlex Deucher shift = atom_get_src(ctx, attr, ptr);
985d38ceaf9SAlex Deucher SDEBUG(" shift: %d\n", shift);
986d38ceaf9SAlex Deucher dst >>= shift;
987d38ceaf9SAlex Deucher dst &= atom_arg_mask[dst_align];
988d38ceaf9SAlex Deucher dst >>= atom_arg_shift[dst_align];
989d38ceaf9SAlex Deucher SDEBUG(" dst: ");
990d38ceaf9SAlex Deucher atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
991d38ceaf9SAlex Deucher }
992d38ceaf9SAlex Deucher
atom_op_sub(atom_exec_context * ctx,int * ptr,int arg)993d38ceaf9SAlex Deucher static void atom_op_sub(atom_exec_context *ctx, int *ptr, int arg)
994d38ceaf9SAlex Deucher {
995d38ceaf9SAlex Deucher uint8_t attr = U8((*ptr)++);
996d38ceaf9SAlex Deucher uint32_t dst, src, saved;
997d38ceaf9SAlex Deucher int dptr = *ptr;
998d38ceaf9SAlex Deucher SDEBUG(" dst: ");
999d38ceaf9SAlex Deucher dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
1000d38ceaf9SAlex Deucher SDEBUG(" src: ");
1001d38ceaf9SAlex Deucher src = atom_get_src(ctx, attr, ptr);
1002d38ceaf9SAlex Deucher dst -= src;
1003d38ceaf9SAlex Deucher SDEBUG(" dst: ");
1004d38ceaf9SAlex Deucher atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
1005d38ceaf9SAlex Deucher }
1006d38ceaf9SAlex Deucher
atom_op_switch(atom_exec_context * ctx,int * ptr,int arg)1007d38ceaf9SAlex Deucher static void atom_op_switch(atom_exec_context *ctx, int *ptr, int arg)
1008d38ceaf9SAlex Deucher {
1009d38ceaf9SAlex Deucher uint8_t attr = U8((*ptr)++);
1010d38ceaf9SAlex Deucher uint32_t src, val, target;
1011d38ceaf9SAlex Deucher SDEBUG(" switch: ");
1012d38ceaf9SAlex Deucher src = atom_get_src(ctx, attr, ptr);
1013d38ceaf9SAlex Deucher while (U16(*ptr) != ATOM_CASE_END)
1014d38ceaf9SAlex Deucher if (U8(*ptr) == ATOM_CASE_MAGIC) {
1015d38ceaf9SAlex Deucher (*ptr)++;
1016d38ceaf9SAlex Deucher SDEBUG(" case: ");
1017d38ceaf9SAlex Deucher val =
1018d38ceaf9SAlex Deucher atom_get_src(ctx, (attr & 0x38) | ATOM_ARG_IMM,
1019d38ceaf9SAlex Deucher ptr);
1020d38ceaf9SAlex Deucher target = U16(*ptr);
1021d38ceaf9SAlex Deucher if (val == src) {
1022d38ceaf9SAlex Deucher SDEBUG(" target: %04X\n", target);
1023d38ceaf9SAlex Deucher *ptr = ctx->start + target;
1024d38ceaf9SAlex Deucher return;
1025d38ceaf9SAlex Deucher }
1026d38ceaf9SAlex Deucher (*ptr) += 2;
1027d38ceaf9SAlex Deucher } else {
10287ca85295SJoe Perches pr_info("Bad case\n");
1029d38ceaf9SAlex Deucher return;
1030d38ceaf9SAlex Deucher }
1031d38ceaf9SAlex Deucher (*ptr) += 2;
1032d38ceaf9SAlex Deucher }
1033d38ceaf9SAlex Deucher
atom_op_test(atom_exec_context * ctx,int * ptr,int arg)1034d38ceaf9SAlex Deucher static void atom_op_test(atom_exec_context *ctx, int *ptr, int arg)
1035d38ceaf9SAlex Deucher {
1036d38ceaf9SAlex Deucher uint8_t attr = U8((*ptr)++);
1037d38ceaf9SAlex Deucher uint32_t dst, src;
1038d38ceaf9SAlex Deucher SDEBUG(" src1: ");
1039d38ceaf9SAlex Deucher dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
1040d38ceaf9SAlex Deucher SDEBUG(" src2: ");
1041d38ceaf9SAlex Deucher src = atom_get_src(ctx, attr, ptr);
1042d38ceaf9SAlex Deucher ctx->ctx->cs_equal = ((dst & src) == 0);
1043d38ceaf9SAlex Deucher SDEBUG(" result: %s\n", ctx->ctx->cs_equal ? "EQ" : "NE");
1044d38ceaf9SAlex Deucher }
1045d38ceaf9SAlex Deucher
atom_op_xor(atom_exec_context * ctx,int * ptr,int arg)1046d38ceaf9SAlex Deucher static void atom_op_xor(atom_exec_context *ctx, int *ptr, int arg)
1047d38ceaf9SAlex Deucher {
1048d38ceaf9SAlex Deucher uint8_t attr = U8((*ptr)++);
1049d38ceaf9SAlex Deucher uint32_t dst, src, saved;
1050d38ceaf9SAlex Deucher int dptr = *ptr;
1051d38ceaf9SAlex Deucher SDEBUG(" dst: ");
1052d38ceaf9SAlex Deucher dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
1053d38ceaf9SAlex Deucher SDEBUG(" src: ");
1054d38ceaf9SAlex Deucher src = atom_get_src(ctx, attr, ptr);
1055d38ceaf9SAlex Deucher dst ^= src;
1056d38ceaf9SAlex Deucher SDEBUG(" dst: ");
1057d38ceaf9SAlex Deucher atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
1058d38ceaf9SAlex Deucher }
1059d38ceaf9SAlex Deucher
atom_op_debug(atom_exec_context * ctx,int * ptr,int arg)1060d38ceaf9SAlex Deucher static void atom_op_debug(atom_exec_context *ctx, int *ptr, int arg)
1061d38ceaf9SAlex Deucher {
1062f76097c0SAlex Deucher uint8_t val = U8((*ptr)++);
1063f76097c0SAlex Deucher SDEBUG("DEBUG output: 0x%02X\n", val);
1064d38ceaf9SAlex Deucher }
1065d38ceaf9SAlex Deucher
atom_op_processds(atom_exec_context * ctx,int * ptr,int arg)106655438419SAlex Deucher static void atom_op_processds(atom_exec_context *ctx, int *ptr, int arg)
106755438419SAlex Deucher {
106855438419SAlex Deucher uint16_t val = U16(*ptr);
106955438419SAlex Deucher (*ptr) += val + 2;
107055438419SAlex Deucher SDEBUG("PROCESSDS output: 0x%02X\n", val);
107155438419SAlex Deucher }
107255438419SAlex Deucher
1073d38ceaf9SAlex Deucher static struct {
1074d38ceaf9SAlex Deucher void (*func) (atom_exec_context *, int *, int);
1075d38ceaf9SAlex Deucher int arg;
1076d38ceaf9SAlex Deucher } opcode_table[ATOM_OP_CNT] = {
1077d38ceaf9SAlex Deucher {
1078d38ceaf9SAlex Deucher NULL, 0}, {
1079d38ceaf9SAlex Deucher atom_op_move, ATOM_ARG_REG}, {
1080d38ceaf9SAlex Deucher atom_op_move, ATOM_ARG_PS}, {
1081d38ceaf9SAlex Deucher atom_op_move, ATOM_ARG_WS}, {
1082d38ceaf9SAlex Deucher atom_op_move, ATOM_ARG_FB}, {
1083d38ceaf9SAlex Deucher atom_op_move, ATOM_ARG_PLL}, {
1084d38ceaf9SAlex Deucher atom_op_move, ATOM_ARG_MC}, {
1085d38ceaf9SAlex Deucher atom_op_and, ATOM_ARG_REG}, {
1086d38ceaf9SAlex Deucher atom_op_and, ATOM_ARG_PS}, {
1087d38ceaf9SAlex Deucher atom_op_and, ATOM_ARG_WS}, {
1088d38ceaf9SAlex Deucher atom_op_and, ATOM_ARG_FB}, {
1089d38ceaf9SAlex Deucher atom_op_and, ATOM_ARG_PLL}, {
1090d38ceaf9SAlex Deucher atom_op_and, ATOM_ARG_MC}, {
1091d38ceaf9SAlex Deucher atom_op_or, ATOM_ARG_REG}, {
1092d38ceaf9SAlex Deucher atom_op_or, ATOM_ARG_PS}, {
1093d38ceaf9SAlex Deucher atom_op_or, ATOM_ARG_WS}, {
1094d38ceaf9SAlex Deucher atom_op_or, ATOM_ARG_FB}, {
1095d38ceaf9SAlex Deucher atom_op_or, ATOM_ARG_PLL}, {
1096d38ceaf9SAlex Deucher atom_op_or, ATOM_ARG_MC}, {
1097d38ceaf9SAlex Deucher atom_op_shift_left, ATOM_ARG_REG}, {
1098d38ceaf9SAlex Deucher atom_op_shift_left, ATOM_ARG_PS}, {
1099d38ceaf9SAlex Deucher atom_op_shift_left, ATOM_ARG_WS}, {
1100d38ceaf9SAlex Deucher atom_op_shift_left, ATOM_ARG_FB}, {
1101d38ceaf9SAlex Deucher atom_op_shift_left, ATOM_ARG_PLL}, {
1102d38ceaf9SAlex Deucher atom_op_shift_left, ATOM_ARG_MC}, {
1103d38ceaf9SAlex Deucher atom_op_shift_right, ATOM_ARG_REG}, {
1104d38ceaf9SAlex Deucher atom_op_shift_right, ATOM_ARG_PS}, {
1105d38ceaf9SAlex Deucher atom_op_shift_right, ATOM_ARG_WS}, {
1106d38ceaf9SAlex Deucher atom_op_shift_right, ATOM_ARG_FB}, {
1107d38ceaf9SAlex Deucher atom_op_shift_right, ATOM_ARG_PLL}, {
1108d38ceaf9SAlex Deucher atom_op_shift_right, ATOM_ARG_MC}, {
1109d38ceaf9SAlex Deucher atom_op_mul, ATOM_ARG_REG}, {
1110d38ceaf9SAlex Deucher atom_op_mul, ATOM_ARG_PS}, {
1111d38ceaf9SAlex Deucher atom_op_mul, ATOM_ARG_WS}, {
1112d38ceaf9SAlex Deucher atom_op_mul, ATOM_ARG_FB}, {
1113d38ceaf9SAlex Deucher atom_op_mul, ATOM_ARG_PLL}, {
1114d38ceaf9SAlex Deucher atom_op_mul, ATOM_ARG_MC}, {
1115d38ceaf9SAlex Deucher atom_op_div, ATOM_ARG_REG}, {
1116d38ceaf9SAlex Deucher atom_op_div, ATOM_ARG_PS}, {
1117d38ceaf9SAlex Deucher atom_op_div, ATOM_ARG_WS}, {
1118d38ceaf9SAlex Deucher atom_op_div, ATOM_ARG_FB}, {
1119d38ceaf9SAlex Deucher atom_op_div, ATOM_ARG_PLL}, {
1120d38ceaf9SAlex Deucher atom_op_div, ATOM_ARG_MC}, {
1121d38ceaf9SAlex Deucher atom_op_add, ATOM_ARG_REG}, {
1122d38ceaf9SAlex Deucher atom_op_add, ATOM_ARG_PS}, {
1123d38ceaf9SAlex Deucher atom_op_add, ATOM_ARG_WS}, {
1124d38ceaf9SAlex Deucher atom_op_add, ATOM_ARG_FB}, {
1125d38ceaf9SAlex Deucher atom_op_add, ATOM_ARG_PLL}, {
1126d38ceaf9SAlex Deucher atom_op_add, ATOM_ARG_MC}, {
1127d38ceaf9SAlex Deucher atom_op_sub, ATOM_ARG_REG}, {
1128d38ceaf9SAlex Deucher atom_op_sub, ATOM_ARG_PS}, {
1129d38ceaf9SAlex Deucher atom_op_sub, ATOM_ARG_WS}, {
1130d38ceaf9SAlex Deucher atom_op_sub, ATOM_ARG_FB}, {
1131d38ceaf9SAlex Deucher atom_op_sub, ATOM_ARG_PLL}, {
1132d38ceaf9SAlex Deucher atom_op_sub, ATOM_ARG_MC}, {
1133d38ceaf9SAlex Deucher atom_op_setport, ATOM_PORT_ATI}, {
1134d38ceaf9SAlex Deucher atom_op_setport, ATOM_PORT_PCI}, {
1135d38ceaf9SAlex Deucher atom_op_setport, ATOM_PORT_SYSIO}, {
1136d38ceaf9SAlex Deucher atom_op_setregblock, 0}, {
1137d38ceaf9SAlex Deucher atom_op_setfbbase, 0}, {
1138d38ceaf9SAlex Deucher atom_op_compare, ATOM_ARG_REG}, {
1139d38ceaf9SAlex Deucher atom_op_compare, ATOM_ARG_PS}, {
1140d38ceaf9SAlex Deucher atom_op_compare, ATOM_ARG_WS}, {
1141d38ceaf9SAlex Deucher atom_op_compare, ATOM_ARG_FB}, {
1142d38ceaf9SAlex Deucher atom_op_compare, ATOM_ARG_PLL}, {
1143d38ceaf9SAlex Deucher atom_op_compare, ATOM_ARG_MC}, {
1144d38ceaf9SAlex Deucher atom_op_switch, 0}, {
1145d38ceaf9SAlex Deucher atom_op_jump, ATOM_COND_ALWAYS}, {
1146d38ceaf9SAlex Deucher atom_op_jump, ATOM_COND_EQUAL}, {
1147d38ceaf9SAlex Deucher atom_op_jump, ATOM_COND_BELOW}, {
1148d38ceaf9SAlex Deucher atom_op_jump, ATOM_COND_ABOVE}, {
1149d38ceaf9SAlex Deucher atom_op_jump, ATOM_COND_BELOWOREQUAL}, {
1150d38ceaf9SAlex Deucher atom_op_jump, ATOM_COND_ABOVEOREQUAL}, {
1151d38ceaf9SAlex Deucher atom_op_jump, ATOM_COND_NOTEQUAL}, {
1152d38ceaf9SAlex Deucher atom_op_test, ATOM_ARG_REG}, {
1153d38ceaf9SAlex Deucher atom_op_test, ATOM_ARG_PS}, {
1154d38ceaf9SAlex Deucher atom_op_test, ATOM_ARG_WS}, {
1155d38ceaf9SAlex Deucher atom_op_test, ATOM_ARG_FB}, {
1156d38ceaf9SAlex Deucher atom_op_test, ATOM_ARG_PLL}, {
1157d38ceaf9SAlex Deucher atom_op_test, ATOM_ARG_MC}, {
1158d38ceaf9SAlex Deucher atom_op_delay, ATOM_UNIT_MILLISEC}, {
1159d38ceaf9SAlex Deucher atom_op_delay, ATOM_UNIT_MICROSEC}, {
1160d38ceaf9SAlex Deucher atom_op_calltable, 0}, {
1161d38ceaf9SAlex Deucher atom_op_repeat, 0}, {
1162d38ceaf9SAlex Deucher atom_op_clear, ATOM_ARG_REG}, {
1163d38ceaf9SAlex Deucher atom_op_clear, ATOM_ARG_PS}, {
1164d38ceaf9SAlex Deucher atom_op_clear, ATOM_ARG_WS}, {
1165d38ceaf9SAlex Deucher atom_op_clear, ATOM_ARG_FB}, {
1166d38ceaf9SAlex Deucher atom_op_clear, ATOM_ARG_PLL}, {
1167d38ceaf9SAlex Deucher atom_op_clear, ATOM_ARG_MC}, {
1168d38ceaf9SAlex Deucher atom_op_nop, 0}, {
1169d38ceaf9SAlex Deucher atom_op_eot, 0}, {
1170d38ceaf9SAlex Deucher atom_op_mask, ATOM_ARG_REG}, {
1171d38ceaf9SAlex Deucher atom_op_mask, ATOM_ARG_PS}, {
1172d38ceaf9SAlex Deucher atom_op_mask, ATOM_ARG_WS}, {
1173d38ceaf9SAlex Deucher atom_op_mask, ATOM_ARG_FB}, {
1174d38ceaf9SAlex Deucher atom_op_mask, ATOM_ARG_PLL}, {
1175d38ceaf9SAlex Deucher atom_op_mask, ATOM_ARG_MC}, {
1176d38ceaf9SAlex Deucher atom_op_postcard, 0}, {
1177d38ceaf9SAlex Deucher atom_op_beep, 0}, {
1178d38ceaf9SAlex Deucher atom_op_savereg, 0}, {
1179d38ceaf9SAlex Deucher atom_op_restorereg, 0}, {
1180d38ceaf9SAlex Deucher atom_op_setdatablock, 0}, {
1181d38ceaf9SAlex Deucher atom_op_xor, ATOM_ARG_REG}, {
1182d38ceaf9SAlex Deucher atom_op_xor, ATOM_ARG_PS}, {
1183d38ceaf9SAlex Deucher atom_op_xor, ATOM_ARG_WS}, {
1184d38ceaf9SAlex Deucher atom_op_xor, ATOM_ARG_FB}, {
1185d38ceaf9SAlex Deucher atom_op_xor, ATOM_ARG_PLL}, {
1186d38ceaf9SAlex Deucher atom_op_xor, ATOM_ARG_MC}, {
1187d38ceaf9SAlex Deucher atom_op_shl, ATOM_ARG_REG}, {
1188d38ceaf9SAlex Deucher atom_op_shl, ATOM_ARG_PS}, {
1189d38ceaf9SAlex Deucher atom_op_shl, ATOM_ARG_WS}, {
1190d38ceaf9SAlex Deucher atom_op_shl, ATOM_ARG_FB}, {
1191d38ceaf9SAlex Deucher atom_op_shl, ATOM_ARG_PLL}, {
1192d38ceaf9SAlex Deucher atom_op_shl, ATOM_ARG_MC}, {
1193d38ceaf9SAlex Deucher atom_op_shr, ATOM_ARG_REG}, {
1194d38ceaf9SAlex Deucher atom_op_shr, ATOM_ARG_PS}, {
1195d38ceaf9SAlex Deucher atom_op_shr, ATOM_ARG_WS}, {
1196d38ceaf9SAlex Deucher atom_op_shr, ATOM_ARG_FB}, {
1197d38ceaf9SAlex Deucher atom_op_shr, ATOM_ARG_PLL}, {
1198d38ceaf9SAlex Deucher atom_op_shr, ATOM_ARG_MC}, {
119955438419SAlex Deucher atom_op_debug, 0}, {
1200c9c14502SAlex Deucher atom_op_processds, 0}, {
1201c9c14502SAlex Deucher atom_op_mul32, ATOM_ARG_PS}, {
1202c2fe16aaSAlex Deucher atom_op_mul32, ATOM_ARG_WS}, {
1203c2fe16aaSAlex Deucher atom_op_div32, ATOM_ARG_PS}, {
1204c2fe16aaSAlex Deucher atom_op_div32, ATOM_ARG_WS},
120555438419SAlex Deucher };
1206d38ceaf9SAlex Deucher
amdgpu_atom_execute_table_locked(struct atom_context * ctx,int index,uint32_t * params)1207d38ceaf9SAlex Deucher static int amdgpu_atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t *params)
1208d38ceaf9SAlex Deucher {
1209d38ceaf9SAlex Deucher int base = CU16(ctx->cmd_table + 4 + 2 * index);
1210d38ceaf9SAlex Deucher int len, ws, ps, ptr;
1211d38ceaf9SAlex Deucher unsigned char op;
1212d38ceaf9SAlex Deucher atom_exec_context ectx;
1213d38ceaf9SAlex Deucher int ret = 0;
1214d38ceaf9SAlex Deucher
1215d38ceaf9SAlex Deucher if (!base)
1216d38ceaf9SAlex Deucher return -EINVAL;
1217d38ceaf9SAlex Deucher
1218d38ceaf9SAlex Deucher len = CU16(base + ATOM_CT_SIZE_PTR);
1219d38ceaf9SAlex Deucher ws = CU8(base + ATOM_CT_WS_PTR);
1220d38ceaf9SAlex Deucher ps = CU8(base + ATOM_CT_PS_PTR) & ATOM_CT_PS_MASK;
1221d38ceaf9SAlex Deucher ptr = base + ATOM_CT_CODE_PTR;
1222d38ceaf9SAlex Deucher
1223d38ceaf9SAlex Deucher SDEBUG(">> execute %04X (len %d, WS %d, PS %d)\n", base, len, ws, ps);
1224d38ceaf9SAlex Deucher
1225d38ceaf9SAlex Deucher ectx.ctx = ctx;
1226d38ceaf9SAlex Deucher ectx.ps_shift = ps / 4;
1227d38ceaf9SAlex Deucher ectx.start = base;
1228d38ceaf9SAlex Deucher ectx.ps = params;
1229d38ceaf9SAlex Deucher ectx.abort = false;
1230d38ceaf9SAlex Deucher ectx.last_jump = 0;
1231d38ceaf9SAlex Deucher if (ws)
12326396bb22SKees Cook ectx.ws = kcalloc(4, ws, GFP_KERNEL);
1233d38ceaf9SAlex Deucher else
1234d38ceaf9SAlex Deucher ectx.ws = NULL;
1235d38ceaf9SAlex Deucher
1236d38ceaf9SAlex Deucher debug_depth++;
1237d38ceaf9SAlex Deucher while (1) {
1238d38ceaf9SAlex Deucher op = CU8(ptr++);
1239d38ceaf9SAlex Deucher if (op < ATOM_OP_NAMES_CNT)
1240d38ceaf9SAlex Deucher SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr - 1);
1241d38ceaf9SAlex Deucher else
1242d38ceaf9SAlex Deucher SDEBUG("[%d] @ 0x%04X\n", op, ptr - 1);
1243d38ceaf9SAlex Deucher if (ectx.abort) {
1244d38ceaf9SAlex Deucher DRM_ERROR("atombios stuck executing %04X (len %d, WS %d, PS %d) @ 0x%04X\n",
1245d38ceaf9SAlex Deucher base, len, ws, ps, ptr - 1);
1246d38ceaf9SAlex Deucher ret = -EINVAL;
1247d38ceaf9SAlex Deucher goto free;
1248d38ceaf9SAlex Deucher }
1249d38ceaf9SAlex Deucher
1250d38ceaf9SAlex Deucher if (op < ATOM_OP_CNT && op > 0)
1251d38ceaf9SAlex Deucher opcode_table[op].func(&ectx, &ptr,
1252d38ceaf9SAlex Deucher opcode_table[op].arg);
1253d38ceaf9SAlex Deucher else
1254d38ceaf9SAlex Deucher break;
1255d38ceaf9SAlex Deucher
1256d38ceaf9SAlex Deucher if (op == ATOM_OP_EOT)
1257d38ceaf9SAlex Deucher break;
1258d38ceaf9SAlex Deucher }
1259d38ceaf9SAlex Deucher debug_depth--;
1260d38ceaf9SAlex Deucher SDEBUG("<<\n");
1261d38ceaf9SAlex Deucher
1262d38ceaf9SAlex Deucher free:
1263d38ceaf9SAlex Deucher if (ws)
1264d38ceaf9SAlex Deucher kfree(ectx.ws);
1265d38ceaf9SAlex Deucher return ret;
1266d38ceaf9SAlex Deucher }
1267d38ceaf9SAlex Deucher
amdgpu_atom_execute_table(struct atom_context * ctx,int index,uint32_t * params)1268d38ceaf9SAlex Deucher int amdgpu_atom_execute_table(struct atom_context *ctx, int index, uint32_t *params)
1269d38ceaf9SAlex Deucher {
1270d38ceaf9SAlex Deucher int r;
1271d38ceaf9SAlex Deucher
1272d38ceaf9SAlex Deucher mutex_lock(&ctx->mutex);
1273d38ceaf9SAlex Deucher /* reset data block */
1274d38ceaf9SAlex Deucher ctx->data_block = 0;
1275d38ceaf9SAlex Deucher /* reset reg block */
1276d38ceaf9SAlex Deucher ctx->reg_block = 0;
1277d38ceaf9SAlex Deucher /* reset fb window */
1278d38ceaf9SAlex Deucher ctx->fb_base = 0;
1279d38ceaf9SAlex Deucher /* reset io mode */
1280d38ceaf9SAlex Deucher ctx->io_mode = ATOM_IO_MM;
1281d38ceaf9SAlex Deucher /* reset divmul */
1282d38ceaf9SAlex Deucher ctx->divmul[0] = 0;
1283d38ceaf9SAlex Deucher ctx->divmul[1] = 0;
1284d38ceaf9SAlex Deucher r = amdgpu_atom_execute_table_locked(ctx, index, params);
1285d38ceaf9SAlex Deucher mutex_unlock(&ctx->mutex);
1286d38ceaf9SAlex Deucher return r;
1287d38ceaf9SAlex Deucher }
1288d38ceaf9SAlex Deucher
1289d38ceaf9SAlex Deucher static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 };
1290d38ceaf9SAlex Deucher
atom_index_iio(struct atom_context * ctx,int base)1291d38ceaf9SAlex Deucher static void atom_index_iio(struct atom_context *ctx, int base)
1292d38ceaf9SAlex Deucher {
1293d38ceaf9SAlex Deucher ctx->iio = kzalloc(2 * 256, GFP_KERNEL);
1294d38ceaf9SAlex Deucher if (!ctx->iio)
1295d38ceaf9SAlex Deucher return;
1296d38ceaf9SAlex Deucher while (CU8(base) == ATOM_IIO_START) {
1297d38ceaf9SAlex Deucher ctx->iio[CU8(base + 1)] = base + 2;
1298d38ceaf9SAlex Deucher base += 2;
1299d38ceaf9SAlex Deucher while (CU8(base) != ATOM_IIO_END)
1300d38ceaf9SAlex Deucher base += atom_iio_len[CU8(base)];
1301d38ceaf9SAlex Deucher base += 3;
1302d38ceaf9SAlex Deucher }
1303d38ceaf9SAlex Deucher }
1304d38ceaf9SAlex Deucher
atom_get_vbios_name(struct atom_context * ctx)130529b4c589SJiawei Gu static void atom_get_vbios_name(struct atom_context *ctx)
130629b4c589SJiawei Gu {
130729b4c589SJiawei Gu unsigned char *p_rom;
130829b4c589SJiawei Gu unsigned char str_num;
130929b4c589SJiawei Gu unsigned short off_to_vbios_str;
131029b4c589SJiawei Gu unsigned char *c_ptr;
131129b4c589SJiawei Gu int name_size;
131229b4c589SJiawei Gu int i;
131329b4c589SJiawei Gu
131429b4c589SJiawei Gu const char *na = "--N/A--";
131529b4c589SJiawei Gu char *back;
131629b4c589SJiawei Gu
131729b4c589SJiawei Gu p_rom = ctx->bios;
131829b4c589SJiawei Gu
131929b4c589SJiawei Gu str_num = *(p_rom + OFFSET_TO_GET_ATOMBIOS_NUMBER_OF_STRINGS);
132029b4c589SJiawei Gu if (str_num != 0) {
132129b4c589SJiawei Gu off_to_vbios_str =
132229b4c589SJiawei Gu *(unsigned short *)(p_rom + OFFSET_TO_GET_ATOMBIOS_STRING_START);
132329b4c589SJiawei Gu
132429b4c589SJiawei Gu c_ptr = (unsigned char *)(p_rom + off_to_vbios_str);
132529b4c589SJiawei Gu } else {
132629b4c589SJiawei Gu /* do not know where to find name */
132729b4c589SJiawei Gu memcpy(ctx->name, na, 7);
132829b4c589SJiawei Gu ctx->name[7] = 0;
132929b4c589SJiawei Gu return;
133029b4c589SJiawei Gu }
133129b4c589SJiawei Gu
133229b4c589SJiawei Gu /*
133329b4c589SJiawei Gu * skip the atombios strings, usually 4
133429b4c589SJiawei Gu * 1st is P/N, 2nd is ASIC, 3rd is PCI type, 4th is Memory type
133529b4c589SJiawei Gu */
133629b4c589SJiawei Gu for (i = 0; i < str_num; i++) {
133729b4c589SJiawei Gu while (*c_ptr != 0)
133829b4c589SJiawei Gu c_ptr++;
133929b4c589SJiawei Gu c_ptr++;
134029b4c589SJiawei Gu }
134129b4c589SJiawei Gu
134229b4c589SJiawei Gu /* skip the following 2 chars: 0x0D 0x0A */
134329b4c589SJiawei Gu c_ptr += 2;
134429b4c589SJiawei Gu
134529b4c589SJiawei Gu name_size = strnlen(c_ptr, STRLEN_LONG - 1);
134629b4c589SJiawei Gu memcpy(ctx->name, c_ptr, name_size);
134729b4c589SJiawei Gu back = ctx->name + name_size;
134829b4c589SJiawei Gu while ((*--back) == ' ')
134929b4c589SJiawei Gu ;
135029b4c589SJiawei Gu *(back + 1) = '\0';
135129b4c589SJiawei Gu }
135229b4c589SJiawei Gu
atom_get_vbios_date(struct atom_context * ctx)135329b4c589SJiawei Gu static void atom_get_vbios_date(struct atom_context *ctx)
135429b4c589SJiawei Gu {
135529b4c589SJiawei Gu unsigned char *p_rom;
135629b4c589SJiawei Gu unsigned char *date_in_rom;
135729b4c589SJiawei Gu
135829b4c589SJiawei Gu p_rom = ctx->bios;
135929b4c589SJiawei Gu
136029b4c589SJiawei Gu date_in_rom = p_rom + OFFSET_TO_VBIOS_DATE;
136129b4c589SJiawei Gu
136229b4c589SJiawei Gu ctx->date[0] = '2';
136329b4c589SJiawei Gu ctx->date[1] = '0';
136429b4c589SJiawei Gu ctx->date[2] = date_in_rom[6];
136529b4c589SJiawei Gu ctx->date[3] = date_in_rom[7];
136629b4c589SJiawei Gu ctx->date[4] = '/';
136729b4c589SJiawei Gu ctx->date[5] = date_in_rom[0];
136829b4c589SJiawei Gu ctx->date[6] = date_in_rom[1];
136929b4c589SJiawei Gu ctx->date[7] = '/';
137029b4c589SJiawei Gu ctx->date[8] = date_in_rom[3];
137129b4c589SJiawei Gu ctx->date[9] = date_in_rom[4];
137229b4c589SJiawei Gu ctx->date[10] = ' ';
137329b4c589SJiawei Gu ctx->date[11] = date_in_rom[9];
137429b4c589SJiawei Gu ctx->date[12] = date_in_rom[10];
137529b4c589SJiawei Gu ctx->date[13] = date_in_rom[11];
137629b4c589SJiawei Gu ctx->date[14] = date_in_rom[12];
137729b4c589SJiawei Gu ctx->date[15] = date_in_rom[13];
137829b4c589SJiawei Gu ctx->date[16] = '\0';
137929b4c589SJiawei Gu }
138029b4c589SJiawei Gu
atom_find_str_in_rom(struct atom_context * ctx,char * str,int start,int end,int maxlen)138129b4c589SJiawei Gu static unsigned char *atom_find_str_in_rom(struct atom_context *ctx, char *str, int start,
138229b4c589SJiawei Gu int end, int maxlen)
138329b4c589SJiawei Gu {
138429b4c589SJiawei Gu unsigned long str_off;
138529b4c589SJiawei Gu unsigned char *p_rom;
138629b4c589SJiawei Gu unsigned short str_len;
138729b4c589SJiawei Gu
138829b4c589SJiawei Gu str_off = 0;
138929b4c589SJiawei Gu str_len = strnlen(str, maxlen);
139029b4c589SJiawei Gu p_rom = ctx->bios;
139129b4c589SJiawei Gu
139229b4c589SJiawei Gu for (; start <= end; ++start) {
139329b4c589SJiawei Gu for (str_off = 0; str_off < str_len; ++str_off) {
139429b4c589SJiawei Gu if (str[str_off] != *(p_rom + start + str_off))
139529b4c589SJiawei Gu break;
139629b4c589SJiawei Gu }
139729b4c589SJiawei Gu
139829b4c589SJiawei Gu if (str_off == str_len || str[str_off] == 0)
139929b4c589SJiawei Gu return p_rom + start;
140029b4c589SJiawei Gu }
140129b4c589SJiawei Gu return NULL;
140229b4c589SJiawei Gu }
140329b4c589SJiawei Gu
atom_get_vbios_pn(struct atom_context * ctx)140429b4c589SJiawei Gu static void atom_get_vbios_pn(struct atom_context *ctx)
140529b4c589SJiawei Gu {
140629b4c589SJiawei Gu unsigned char *p_rom;
140729b4c589SJiawei Gu unsigned short off_to_vbios_str;
140829b4c589SJiawei Gu unsigned char *vbios_str;
140929b4c589SJiawei Gu int count;
141029b4c589SJiawei Gu
141129b4c589SJiawei Gu off_to_vbios_str = 0;
141229b4c589SJiawei Gu p_rom = ctx->bios;
141329b4c589SJiawei Gu
141429b4c589SJiawei Gu if (*(p_rom + OFFSET_TO_GET_ATOMBIOS_NUMBER_OF_STRINGS) != 0) {
141529b4c589SJiawei Gu off_to_vbios_str =
141629b4c589SJiawei Gu *(unsigned short *)(p_rom + OFFSET_TO_GET_ATOMBIOS_STRING_START);
141729b4c589SJiawei Gu
141829b4c589SJiawei Gu vbios_str = (unsigned char *)(p_rom + off_to_vbios_str);
141929b4c589SJiawei Gu } else {
142029b4c589SJiawei Gu vbios_str = p_rom + OFFSET_TO_VBIOS_PART_NUMBER;
142129b4c589SJiawei Gu }
142229b4c589SJiawei Gu
142329b4c589SJiawei Gu if (*vbios_str == 0) {
142429b4c589SJiawei Gu vbios_str = atom_find_str_in_rom(ctx, BIOS_ATOM_PREFIX, 3, 1024, 64);
142529b4c589SJiawei Gu if (vbios_str == NULL)
142629b4c589SJiawei Gu vbios_str += sizeof(BIOS_ATOM_PREFIX) - 1;
142729b4c589SJiawei Gu }
142829b4c589SJiawei Gu if (vbios_str != NULL && *vbios_str == 0)
142929b4c589SJiawei Gu vbios_str++;
143029b4c589SJiawei Gu
143129b4c589SJiawei Gu if (vbios_str != NULL) {
143229b4c589SJiawei Gu count = 0;
143329b4c589SJiawei Gu while ((count < BIOS_STRING_LENGTH) && vbios_str[count] >= ' ' &&
143429b4c589SJiawei Gu vbios_str[count] <= 'z') {
143529b4c589SJiawei Gu ctx->vbios_pn[count] = vbios_str[count];
143629b4c589SJiawei Gu count++;
143729b4c589SJiawei Gu }
143829b4c589SJiawei Gu
143929b4c589SJiawei Gu ctx->vbios_pn[count] = 0;
144029b4c589SJiawei Gu }
1441adf64e21SMario Limonciello
1442adf64e21SMario Limonciello pr_info("ATOM BIOS: %s\n", ctx->vbios_pn);
144329b4c589SJiawei Gu }
144429b4c589SJiawei Gu
atom_get_vbios_version(struct atom_context * ctx)144529b4c589SJiawei Gu static void atom_get_vbios_version(struct atom_context *ctx)
144629b4c589SJiawei Gu {
144729b4c589SJiawei Gu unsigned char *vbios_ver;
144829b4c589SJiawei Gu
144929b4c589SJiawei Gu /* find anchor ATOMBIOSBK-AMD */
145029b4c589SJiawei Gu vbios_ver = atom_find_str_in_rom(ctx, BIOS_VERSION_PREFIX, 3, 1024, 64);
145129b4c589SJiawei Gu if (vbios_ver != NULL) {
145229b4c589SJiawei Gu /* skip ATOMBIOSBK-AMD VER */
145329b4c589SJiawei Gu vbios_ver += 18;
145429b4c589SJiawei Gu memcpy(ctx->vbios_ver_str, vbios_ver, STRLEN_NORMAL);
145529b4c589SJiawei Gu } else {
145629b4c589SJiawei Gu ctx->vbios_ver_str[0] = '\0';
145729b4c589SJiawei Gu }
145829b4c589SJiawei Gu }
145929b4c589SJiawei Gu
amdgpu_atom_parse(struct card_info * card,void * bios)1460d38ceaf9SAlex Deucher struct atom_context *amdgpu_atom_parse(struct card_info *card, void *bios)
1461d38ceaf9SAlex Deucher {
1462d38ceaf9SAlex Deucher int base;
1463d38ceaf9SAlex Deucher struct atom_context *ctx =
1464d38ceaf9SAlex Deucher kzalloc(sizeof(struct atom_context), GFP_KERNEL);
146529b4c589SJiawei Gu struct _ATOM_ROM_HEADER *atom_rom_header;
146629b4c589SJiawei Gu struct _ATOM_MASTER_DATA_TABLE *master_table;
146729b4c589SJiawei Gu struct _ATOM_FIRMWARE_INFO *atom_fw_info;
1468d38ceaf9SAlex Deucher
1469d38ceaf9SAlex Deucher if (!ctx)
1470d38ceaf9SAlex Deucher return NULL;
1471d38ceaf9SAlex Deucher
1472d38ceaf9SAlex Deucher ctx->card = card;
1473d38ceaf9SAlex Deucher ctx->bios = bios;
1474d38ceaf9SAlex Deucher
1475d38ceaf9SAlex Deucher if (CU16(0) != ATOM_BIOS_MAGIC) {
14767ca85295SJoe Perches pr_info("Invalid BIOS magic\n");
1477d38ceaf9SAlex Deucher kfree(ctx);
1478d38ceaf9SAlex Deucher return NULL;
1479d38ceaf9SAlex Deucher }
1480d38ceaf9SAlex Deucher if (strncmp
1481d38ceaf9SAlex Deucher (CSTR(ATOM_ATI_MAGIC_PTR), ATOM_ATI_MAGIC,
1482d38ceaf9SAlex Deucher strlen(ATOM_ATI_MAGIC))) {
14837ca85295SJoe Perches pr_info("Invalid ATI magic\n");
1484d38ceaf9SAlex Deucher kfree(ctx);
1485d38ceaf9SAlex Deucher return NULL;
1486d38ceaf9SAlex Deucher }
1487d38ceaf9SAlex Deucher
1488d38ceaf9SAlex Deucher base = CU16(ATOM_ROM_TABLE_PTR);
1489d38ceaf9SAlex Deucher if (strncmp
1490d38ceaf9SAlex Deucher (CSTR(base + ATOM_ROM_MAGIC_PTR), ATOM_ROM_MAGIC,
1491d38ceaf9SAlex Deucher strlen(ATOM_ROM_MAGIC))) {
14927ca85295SJoe Perches pr_info("Invalid ATOM magic\n");
1493d38ceaf9SAlex Deucher kfree(ctx);
1494d38ceaf9SAlex Deucher return NULL;
1495d38ceaf9SAlex Deucher }
1496d38ceaf9SAlex Deucher
1497d38ceaf9SAlex Deucher ctx->cmd_table = CU16(base + ATOM_ROM_CMD_PTR);
1498d38ceaf9SAlex Deucher ctx->data_table = CU16(base + ATOM_ROM_DATA_PTR);
1499d38ceaf9SAlex Deucher atom_index_iio(ctx, CU16(ctx->data_table + ATOM_DATA_IIO_PTR) + 4);
1500d38ceaf9SAlex Deucher if (!ctx->iio) {
1501d38ceaf9SAlex Deucher amdgpu_atom_destroy(ctx);
1502d38ceaf9SAlex Deucher return NULL;
1503d38ceaf9SAlex Deucher }
1504d38ceaf9SAlex Deucher
150529b4c589SJiawei Gu atom_rom_header = (struct _ATOM_ROM_HEADER *)CSTR(base);
150629b4c589SJiawei Gu if (atom_rom_header->usMasterDataTableOffset != 0) {
150729b4c589SJiawei Gu master_table = (struct _ATOM_MASTER_DATA_TABLE *)
150829b4c589SJiawei Gu CSTR(atom_rom_header->usMasterDataTableOffset);
150929b4c589SJiawei Gu if (master_table->ListOfDataTables.FirmwareInfo != 0) {
151029b4c589SJiawei Gu atom_fw_info = (struct _ATOM_FIRMWARE_INFO *)
151129b4c589SJiawei Gu CSTR(master_table->ListOfDataTables.FirmwareInfo);
151229b4c589SJiawei Gu ctx->version = atom_fw_info->ulFirmwareRevision;
151329b4c589SJiawei Gu }
151429b4c589SJiawei Gu }
151529b4c589SJiawei Gu
151629b4c589SJiawei Gu atom_get_vbios_name(ctx);
151729b4c589SJiawei Gu atom_get_vbios_pn(ctx);
151829b4c589SJiawei Gu atom_get_vbios_date(ctx);
151929b4c589SJiawei Gu atom_get_vbios_version(ctx);
1520d38ceaf9SAlex Deucher
1521d38ceaf9SAlex Deucher return ctx;
1522d38ceaf9SAlex Deucher }
1523d38ceaf9SAlex Deucher
amdgpu_atom_asic_init(struct atom_context * ctx)1524d38ceaf9SAlex Deucher int amdgpu_atom_asic_init(struct atom_context *ctx)
1525d38ceaf9SAlex Deucher {
1526d38ceaf9SAlex Deucher int hwi = CU16(ctx->data_table + ATOM_DATA_FWI_PTR);
1527d38ceaf9SAlex Deucher uint32_t ps[16];
1528d38ceaf9SAlex Deucher int ret;
1529d38ceaf9SAlex Deucher
1530d38ceaf9SAlex Deucher memset(ps, 0, 64);
1531d38ceaf9SAlex Deucher
1532d38ceaf9SAlex Deucher ps[0] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFSCLK_PTR));
1533d38ceaf9SAlex Deucher ps[1] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFMCLK_PTR));
1534d38ceaf9SAlex Deucher if (!ps[0] || !ps[1])
1535d38ceaf9SAlex Deucher return 1;
1536d38ceaf9SAlex Deucher
1537d38ceaf9SAlex Deucher if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT))
1538d38ceaf9SAlex Deucher return 1;
1539d38ceaf9SAlex Deucher ret = amdgpu_atom_execute_table(ctx, ATOM_CMD_INIT, ps);
1540d38ceaf9SAlex Deucher if (ret)
1541d38ceaf9SAlex Deucher return ret;
1542d38ceaf9SAlex Deucher
1543d38ceaf9SAlex Deucher memset(ps, 0, 64);
1544d38ceaf9SAlex Deucher
1545d38ceaf9SAlex Deucher return ret;
1546d38ceaf9SAlex Deucher }
1547d38ceaf9SAlex Deucher
amdgpu_atom_destroy(struct atom_context * ctx)1548d38ceaf9SAlex Deucher void amdgpu_atom_destroy(struct atom_context *ctx)
1549d38ceaf9SAlex Deucher {
1550d38ceaf9SAlex Deucher kfree(ctx->iio);
1551d38ceaf9SAlex Deucher kfree(ctx);
1552d38ceaf9SAlex Deucher }
1553d38ceaf9SAlex Deucher
amdgpu_atom_parse_data_header(struct atom_context * ctx,int index,uint16_t * size,uint8_t * frev,uint8_t * crev,uint16_t * data_start)1554d38ceaf9SAlex Deucher bool amdgpu_atom_parse_data_header(struct atom_context *ctx, int index,
1555d38ceaf9SAlex Deucher uint16_t *size, uint8_t *frev, uint8_t *crev,
1556d38ceaf9SAlex Deucher uint16_t *data_start)
1557d38ceaf9SAlex Deucher {
1558d38ceaf9SAlex Deucher int offset = index * 2 + 4;
1559d38ceaf9SAlex Deucher int idx = CU16(ctx->data_table + offset);
1560d38ceaf9SAlex Deucher u16 *mdt = (u16 *)(ctx->bios + ctx->data_table + 4);
1561d38ceaf9SAlex Deucher
1562d38ceaf9SAlex Deucher if (!mdt[index])
1563d38ceaf9SAlex Deucher return false;
1564d38ceaf9SAlex Deucher
1565d38ceaf9SAlex Deucher if (size)
1566d38ceaf9SAlex Deucher *size = CU16(idx);
1567d38ceaf9SAlex Deucher if (frev)
1568d38ceaf9SAlex Deucher *frev = CU8(idx + 2);
1569d38ceaf9SAlex Deucher if (crev)
1570d38ceaf9SAlex Deucher *crev = CU8(idx + 3);
1571d38ceaf9SAlex Deucher *data_start = idx;
1572d38ceaf9SAlex Deucher return true;
1573d38ceaf9SAlex Deucher }
1574d38ceaf9SAlex Deucher
amdgpu_atom_parse_cmd_header(struct atom_context * ctx,int index,uint8_t * frev,uint8_t * crev)1575d38ceaf9SAlex Deucher bool amdgpu_atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t *frev,
1576d38ceaf9SAlex Deucher uint8_t *crev)
1577d38ceaf9SAlex Deucher {
1578d38ceaf9SAlex Deucher int offset = index * 2 + 4;
1579d38ceaf9SAlex Deucher int idx = CU16(ctx->cmd_table + offset);
1580d38ceaf9SAlex Deucher u16 *mct = (u16 *)(ctx->bios + ctx->cmd_table + 4);
1581d38ceaf9SAlex Deucher
1582d38ceaf9SAlex Deucher if (!mct[index])
1583d38ceaf9SAlex Deucher return false;
1584d38ceaf9SAlex Deucher
1585d38ceaf9SAlex Deucher if (frev)
1586d38ceaf9SAlex Deucher *frev = CU8(idx + 2);
1587d38ceaf9SAlex Deucher if (crev)
1588d38ceaf9SAlex Deucher *crev = CU8(idx + 3);
1589d38ceaf9SAlex Deucher return true;
1590d38ceaf9SAlex Deucher }
1591d38ceaf9SAlex Deucher
1592