xref: /openbmc/linux/drivers/gpu/drm/amd/amdgpu/atom.c (revision bf13e50a)
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