xref: /linux-6.15/drivers/gpu/drm/amd/amdgpu/atom.c (revision 5f60d5f6)
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 
30*5f60d5f6SAl Viro #include <linux/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;
654630d503SAlexander Richards 	int ps_size, ws_size;
66d38ceaf9SAlex Deucher 	int ps_shift;
67d38ceaf9SAlex Deucher 	uint16_t start;
68d38ceaf9SAlex Deucher 	unsigned last_jump;
69d38ceaf9SAlex Deucher 	unsigned long last_jump_jiffies;
70d38ceaf9SAlex Deucher 	bool abort;
71d38ceaf9SAlex Deucher } atom_exec_context;
72d38ceaf9SAlex Deucher 
7387fb7833SDeepak R Varma int amdgpu_atom_debug;
744630d503SAlexander Richards static int amdgpu_atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t *params, int params_size);
754630d503SAlexander Richards int amdgpu_atom_execute_table(struct atom_context *ctx, int index, uint32_t *params, int params_size);
76d38ceaf9SAlex Deucher 
77d38ceaf9SAlex Deucher static uint32_t atom_arg_mask[8] =
78d38ceaf9SAlex Deucher 	{ 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000,
79d38ceaf9SAlex Deucher 	  0xFF000000 };
80d38ceaf9SAlex Deucher static int atom_arg_shift[8] = { 0, 0, 8, 16, 0, 8, 16, 24 };
81d38ceaf9SAlex Deucher 
82d38ceaf9SAlex Deucher static int atom_dst_to_src[8][4] = {
83d38ceaf9SAlex Deucher 	/* translate destination alignment field to the source alignment encoding */
84d38ceaf9SAlex Deucher 	{0, 0, 0, 0},
85d38ceaf9SAlex Deucher 	{1, 2, 3, 0},
86d38ceaf9SAlex Deucher 	{1, 2, 3, 0},
87d38ceaf9SAlex Deucher 	{1, 2, 3, 0},
88d38ceaf9SAlex Deucher 	{4, 5, 6, 7},
89d38ceaf9SAlex Deucher 	{4, 5, 6, 7},
90d38ceaf9SAlex Deucher 	{4, 5, 6, 7},
91d38ceaf9SAlex Deucher 	{4, 5, 6, 7},
92d38ceaf9SAlex Deucher };
93d38ceaf9SAlex Deucher static int atom_def_dst[8] = { 0, 0, 1, 2, 0, 1, 2, 3 };
94d38ceaf9SAlex Deucher 
9587fb7833SDeepak R Varma static int debug_depth;
96d38ceaf9SAlex Deucher #ifdef ATOM_DEBUG
debug_print_spaces(int n)97d38ceaf9SAlex Deucher static void debug_print_spaces(int n)
98d38ceaf9SAlex Deucher {
99d38ceaf9SAlex Deucher 	while (n--)
100d38ceaf9SAlex Deucher 		printk("   ");
101d38ceaf9SAlex Deucher }
102d38ceaf9SAlex Deucher 
103d38ceaf9SAlex Deucher #define DEBUG(...) do if (amdgpu_atom_debug) { printk(KERN_DEBUG __VA_ARGS__); } while (0)
104d38ceaf9SAlex Deucher #define SDEBUG(...) do if (amdgpu_atom_debug) { printk(KERN_DEBUG); debug_print_spaces(debug_depth); printk(__VA_ARGS__); } while (0)
105d38ceaf9SAlex Deucher #else
106d38ceaf9SAlex Deucher #define DEBUG(...) do { } while (0)
107d38ceaf9SAlex Deucher #define SDEBUG(...) do { } while (0)
108d38ceaf9SAlex Deucher #endif
109d38ceaf9SAlex Deucher 
atom_iio_execute(struct atom_context * ctx,int base,uint32_t index,uint32_t data)110d38ceaf9SAlex Deucher static uint32_t atom_iio_execute(struct atom_context *ctx, int base,
111d38ceaf9SAlex Deucher 				 uint32_t index, uint32_t data)
112d38ceaf9SAlex Deucher {
113d38ceaf9SAlex Deucher 	uint32_t temp = 0xCDCDCDCD;
114d38ceaf9SAlex Deucher 
115d38ceaf9SAlex Deucher 	while (1)
116d38ceaf9SAlex Deucher 		switch (CU8(base)) {
117d38ceaf9SAlex Deucher 		case ATOM_IIO_NOP:
118d38ceaf9SAlex Deucher 			base++;
119d38ceaf9SAlex Deucher 			break;
120d38ceaf9SAlex Deucher 		case ATOM_IIO_READ:
121e99d2eaaSAlex Deucher 			temp = ctx->card->reg_read(ctx->card, CU16(base + 1));
122d38ceaf9SAlex Deucher 			base += 3;
123d38ceaf9SAlex Deucher 			break;
124d38ceaf9SAlex Deucher 		case ATOM_IIO_WRITE:
125e99d2eaaSAlex Deucher 			ctx->card->reg_write(ctx->card, CU16(base + 1), temp);
126d38ceaf9SAlex Deucher 			base += 3;
127d38ceaf9SAlex Deucher 			break;
128d38ceaf9SAlex Deucher 		case ATOM_IIO_CLEAR:
129d38ceaf9SAlex Deucher 			temp &=
130d38ceaf9SAlex Deucher 			    ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
131d38ceaf9SAlex Deucher 			      CU8(base + 2));
132d38ceaf9SAlex Deucher 			base += 3;
133d38ceaf9SAlex Deucher 			break;
134d38ceaf9SAlex Deucher 		case ATOM_IIO_SET:
135d38ceaf9SAlex Deucher 			temp |=
136d38ceaf9SAlex Deucher 			    (0xFFFFFFFF >> (32 - CU8(base + 1))) << CU8(base +
137d38ceaf9SAlex Deucher 									2);
138d38ceaf9SAlex Deucher 			base += 3;
139d38ceaf9SAlex Deucher 			break;
140d38ceaf9SAlex Deucher 		case ATOM_IIO_MOVE_INDEX:
141d38ceaf9SAlex Deucher 			temp &=
142d38ceaf9SAlex Deucher 			    ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
143d38ceaf9SAlex Deucher 			      CU8(base + 3));
144d38ceaf9SAlex Deucher 			temp |=
145d38ceaf9SAlex Deucher 			    ((index >> CU8(base + 2)) &
146d38ceaf9SAlex Deucher 			     (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base +
147d38ceaf9SAlex Deucher 									  3);
148d38ceaf9SAlex Deucher 			base += 4;
149d38ceaf9SAlex Deucher 			break;
150d38ceaf9SAlex Deucher 		case ATOM_IIO_MOVE_DATA:
151d38ceaf9SAlex Deucher 			temp &=
152d38ceaf9SAlex Deucher 			    ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
153d38ceaf9SAlex Deucher 			      CU8(base + 3));
154d38ceaf9SAlex Deucher 			temp |=
155d38ceaf9SAlex Deucher 			    ((data >> CU8(base + 2)) &
156d38ceaf9SAlex Deucher 			     (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base +
157d38ceaf9SAlex Deucher 									  3);
158d38ceaf9SAlex Deucher 			base += 4;
159d38ceaf9SAlex Deucher 			break;
160d38ceaf9SAlex Deucher 		case ATOM_IIO_MOVE_ATTR:
161d38ceaf9SAlex Deucher 			temp &=
162d38ceaf9SAlex Deucher 			    ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
163d38ceaf9SAlex Deucher 			      CU8(base + 3));
164d38ceaf9SAlex Deucher 			temp |=
165d38ceaf9SAlex Deucher 			    ((ctx->
166d38ceaf9SAlex Deucher 			      io_attr >> CU8(base + 2)) & (0xFFFFFFFF >> (32 -
167d38ceaf9SAlex Deucher 									  CU8
168d38ceaf9SAlex Deucher 									  (base
169d38ceaf9SAlex Deucher 									   +
170d38ceaf9SAlex Deucher 									   1))))
171d38ceaf9SAlex Deucher 			    << CU8(base + 3);
172d38ceaf9SAlex Deucher 			base += 4;
173d38ceaf9SAlex Deucher 			break;
174d38ceaf9SAlex Deucher 		case ATOM_IIO_END:
175d38ceaf9SAlex Deucher 			return temp;
176d38ceaf9SAlex Deucher 		default:
1777ca85295SJoe Perches 			pr_info("Unknown IIO opcode\n");
178d38ceaf9SAlex Deucher 			return 0;
179d38ceaf9SAlex Deucher 		}
180d38ceaf9SAlex Deucher }
181d38ceaf9SAlex Deucher 
atom_get_src_int(atom_exec_context * ctx,uint8_t attr,int * ptr,uint32_t * saved,int print)182d38ceaf9SAlex Deucher static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr,
183d38ceaf9SAlex Deucher 				 int *ptr, uint32_t *saved, int print)
184d38ceaf9SAlex Deucher {
185d38ceaf9SAlex Deucher 	uint32_t idx, val = 0xCDCDCDCD, align, arg;
186d38ceaf9SAlex Deucher 	struct atom_context *gctx = ctx->ctx;
187d38ceaf9SAlex Deucher 	arg = attr & 7;
188d38ceaf9SAlex Deucher 	align = (attr >> 3) & 7;
189d38ceaf9SAlex Deucher 	switch (arg) {
190d38ceaf9SAlex Deucher 	case ATOM_ARG_REG:
191d38ceaf9SAlex Deucher 		idx = U16(*ptr);
192d38ceaf9SAlex Deucher 		(*ptr) += 2;
193d38ceaf9SAlex Deucher 		if (print)
194d38ceaf9SAlex Deucher 			DEBUG("REG[0x%04X]", idx);
195d38ceaf9SAlex Deucher 		idx += gctx->reg_block;
196d38ceaf9SAlex Deucher 		switch (gctx->io_mode) {
197d38ceaf9SAlex Deucher 		case ATOM_IO_MM:
198d38ceaf9SAlex Deucher 			val = gctx->card->reg_read(gctx->card, idx);
199d38ceaf9SAlex Deucher 			break;
200d38ceaf9SAlex Deucher 		case ATOM_IO_PCI:
2017ca85295SJoe Perches 			pr_info("PCI registers are not implemented\n");
202d38ceaf9SAlex Deucher 			return 0;
203d38ceaf9SAlex Deucher 		case ATOM_IO_SYSIO:
2047ca85295SJoe Perches 			pr_info("SYSIO registers are not implemented\n");
205d38ceaf9SAlex Deucher 			return 0;
206d38ceaf9SAlex Deucher 		default:
207d38ceaf9SAlex Deucher 			if (!(gctx->io_mode & 0x80)) {
2087ca85295SJoe Perches 				pr_info("Bad IO mode\n");
209d38ceaf9SAlex Deucher 				return 0;
210d38ceaf9SAlex Deucher 			}
211d38ceaf9SAlex Deucher 			if (!gctx->iio[gctx->io_mode & 0x7F]) {
2127ca85295SJoe Perches 				pr_info("Undefined indirect IO read method %d\n",
213d38ceaf9SAlex Deucher 					gctx->io_mode & 0x7F);
214d38ceaf9SAlex Deucher 				return 0;
215d38ceaf9SAlex Deucher 			}
216d38ceaf9SAlex Deucher 			val =
217d38ceaf9SAlex Deucher 			    atom_iio_execute(gctx,
218d38ceaf9SAlex Deucher 					     gctx->iio[gctx->io_mode & 0x7F],
219d38ceaf9SAlex Deucher 					     idx, 0);
220d38ceaf9SAlex Deucher 		}
221d38ceaf9SAlex Deucher 		break;
222d38ceaf9SAlex Deucher 	case ATOM_ARG_PS:
223d38ceaf9SAlex Deucher 		idx = U8(*ptr);
224d38ceaf9SAlex Deucher 		(*ptr)++;
225d38ceaf9SAlex Deucher 		/* get_unaligned_le32 avoids unaligned accesses from atombios
226d38ceaf9SAlex Deucher 		 * tables, noticed on a DEC Alpha. */
2274630d503SAlexander Richards 		if (idx < ctx->ps_size)
228d38ceaf9SAlex Deucher 			val = get_unaligned_le32((u32 *)&ctx->ps[idx]);
2294630d503SAlexander Richards 		else
2304630d503SAlexander Richards 			pr_info("PS index out of range: %i > %i\n", idx, ctx->ps_size);
231d38ceaf9SAlex Deucher 		if (print)
232d38ceaf9SAlex Deucher 			DEBUG("PS[0x%02X,0x%04X]", idx, val);
233d38ceaf9SAlex Deucher 		break;
234d38ceaf9SAlex Deucher 	case ATOM_ARG_WS:
235d38ceaf9SAlex Deucher 		idx = U8(*ptr);
236d38ceaf9SAlex Deucher 		(*ptr)++;
237d38ceaf9SAlex Deucher 		if (print)
238d38ceaf9SAlex Deucher 			DEBUG("WS[0x%02X]", idx);
239d38ceaf9SAlex Deucher 		switch (idx) {
240d38ceaf9SAlex Deucher 		case ATOM_WS_QUOTIENT:
241d38ceaf9SAlex Deucher 			val = gctx->divmul[0];
242d38ceaf9SAlex Deucher 			break;
243d38ceaf9SAlex Deucher 		case ATOM_WS_REMAINDER:
244d38ceaf9SAlex Deucher 			val = gctx->divmul[1];
245d38ceaf9SAlex Deucher 			break;
246d38ceaf9SAlex Deucher 		case ATOM_WS_DATAPTR:
247d38ceaf9SAlex Deucher 			val = gctx->data_block;
248d38ceaf9SAlex Deucher 			break;
249d38ceaf9SAlex Deucher 		case ATOM_WS_SHIFT:
250d38ceaf9SAlex Deucher 			val = gctx->shift;
251d38ceaf9SAlex Deucher 			break;
252d38ceaf9SAlex Deucher 		case ATOM_WS_OR_MASK:
253d38ceaf9SAlex Deucher 			val = 1 << gctx->shift;
254d38ceaf9SAlex Deucher 			break;
255d38ceaf9SAlex Deucher 		case ATOM_WS_AND_MASK:
256d38ceaf9SAlex Deucher 			val = ~(1 << gctx->shift);
257d38ceaf9SAlex Deucher 			break;
258d38ceaf9SAlex Deucher 		case ATOM_WS_FB_WINDOW:
259d38ceaf9SAlex Deucher 			val = gctx->fb_base;
260d38ceaf9SAlex Deucher 			break;
261d38ceaf9SAlex Deucher 		case ATOM_WS_ATTRIBUTES:
262d38ceaf9SAlex Deucher 			val = gctx->io_attr;
263d38ceaf9SAlex Deucher 			break;
264d38ceaf9SAlex Deucher 		case ATOM_WS_REGPTR:
265d38ceaf9SAlex Deucher 			val = gctx->reg_block;
266d38ceaf9SAlex Deucher 			break;
267d38ceaf9SAlex Deucher 		default:
2684630d503SAlexander Richards 			if (idx < ctx->ws_size)
269d38ceaf9SAlex Deucher 				val = ctx->ws[idx];
2704630d503SAlexander Richards 			else
2714630d503SAlexander Richards 				pr_info("WS index out of range: %i > %i\n", idx, ctx->ws_size);
272d38ceaf9SAlex Deucher 		}
273d38ceaf9SAlex Deucher 		break;
274d38ceaf9SAlex Deucher 	case ATOM_ARG_ID:
275d38ceaf9SAlex Deucher 		idx = U16(*ptr);
276d38ceaf9SAlex Deucher 		(*ptr) += 2;
277d38ceaf9SAlex Deucher 		if (print) {
278d38ceaf9SAlex Deucher 			if (gctx->data_block)
279d38ceaf9SAlex Deucher 				DEBUG("ID[0x%04X+%04X]", idx, gctx->data_block);
280d38ceaf9SAlex Deucher 			else
281d38ceaf9SAlex Deucher 				DEBUG("ID[0x%04X]", idx);
282d38ceaf9SAlex Deucher 		}
283d38ceaf9SAlex Deucher 		val = U32(idx + gctx->data_block);
284d38ceaf9SAlex Deucher 		break;
285d38ceaf9SAlex Deucher 	case ATOM_ARG_FB:
286d38ceaf9SAlex Deucher 		idx = U8(*ptr);
287d38ceaf9SAlex Deucher 		(*ptr)++;
288d38ceaf9SAlex Deucher 		if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) {
289d38ceaf9SAlex Deucher 			DRM_ERROR("ATOM: fb read beyond scratch region: %d vs. %d\n",
290d38ceaf9SAlex Deucher 				  gctx->fb_base + (idx * 4), gctx->scratch_size_bytes);
291d38ceaf9SAlex Deucher 			val = 0;
292d38ceaf9SAlex Deucher 		} else
293d38ceaf9SAlex Deucher 			val = gctx->scratch[(gctx->fb_base / 4) + idx];
294d38ceaf9SAlex Deucher 		if (print)
295d38ceaf9SAlex Deucher 			DEBUG("FB[0x%02X]", idx);
296d38ceaf9SAlex Deucher 		break;
297d38ceaf9SAlex Deucher 	case ATOM_ARG_IMM:
298d38ceaf9SAlex Deucher 		switch (align) {
299d38ceaf9SAlex Deucher 		case ATOM_SRC_DWORD:
300d38ceaf9SAlex Deucher 			val = U32(*ptr);
301d38ceaf9SAlex Deucher 			(*ptr) += 4;
302d38ceaf9SAlex Deucher 			if (print)
303d38ceaf9SAlex Deucher 				DEBUG("IMM 0x%08X\n", val);
30427b500b7SJesse Zhang 			break;
305d38ceaf9SAlex Deucher 		case ATOM_SRC_WORD0:
306d38ceaf9SAlex Deucher 		case ATOM_SRC_WORD8:
307d38ceaf9SAlex Deucher 		case ATOM_SRC_WORD16:
308d38ceaf9SAlex Deucher 			val = U16(*ptr);
309d38ceaf9SAlex Deucher 			(*ptr) += 2;
310d38ceaf9SAlex Deucher 			if (print)
311d38ceaf9SAlex Deucher 				DEBUG("IMM 0x%04X\n", val);
31227b500b7SJesse Zhang 			break;
313d38ceaf9SAlex Deucher 		case ATOM_SRC_BYTE0:
314d38ceaf9SAlex Deucher 		case ATOM_SRC_BYTE8:
315d38ceaf9SAlex Deucher 		case ATOM_SRC_BYTE16:
316d38ceaf9SAlex Deucher 		case ATOM_SRC_BYTE24:
317d38ceaf9SAlex Deucher 			val = U8(*ptr);
318d38ceaf9SAlex Deucher 			(*ptr)++;
319d38ceaf9SAlex Deucher 			if (print)
320d38ceaf9SAlex Deucher 				DEBUG("IMM 0x%02X\n", val);
3217cf1ad2fSSrinivasan Shanmugam 			break;
32227b500b7SJesse Zhang 		}
32327b500b7SJesse Zhang 		return val;
324d38ceaf9SAlex Deucher 	case ATOM_ARG_PLL:
325d38ceaf9SAlex Deucher 		idx = U8(*ptr);
326d38ceaf9SAlex Deucher 		(*ptr)++;
327d38ceaf9SAlex Deucher 		if (print)
328d38ceaf9SAlex Deucher 			DEBUG("PLL[0x%02X]", idx);
329d38ceaf9SAlex Deucher 		val = gctx->card->pll_read(gctx->card, idx);
330d38ceaf9SAlex Deucher 		break;
331d38ceaf9SAlex Deucher 	case ATOM_ARG_MC:
332d38ceaf9SAlex Deucher 		idx = U8(*ptr);
333d38ceaf9SAlex Deucher 		(*ptr)++;
334d38ceaf9SAlex Deucher 		if (print)
335d38ceaf9SAlex Deucher 			DEBUG("MC[0x%02X]", idx);
336d38ceaf9SAlex Deucher 		val = gctx->card->mc_read(gctx->card, idx);
337d38ceaf9SAlex Deucher 		break;
338d38ceaf9SAlex Deucher 	}
339d38ceaf9SAlex Deucher 	if (saved)
340d38ceaf9SAlex Deucher 		*saved = val;
341d38ceaf9SAlex Deucher 	val &= atom_arg_mask[align];
342d38ceaf9SAlex Deucher 	val >>= atom_arg_shift[align];
343d38ceaf9SAlex Deucher 	if (print)
344d38ceaf9SAlex Deucher 		switch (align) {
345d38ceaf9SAlex Deucher 		case ATOM_SRC_DWORD:
346d38ceaf9SAlex Deucher 			DEBUG(".[31:0] -> 0x%08X\n", val);
347d38ceaf9SAlex Deucher 			break;
348d38ceaf9SAlex Deucher 		case ATOM_SRC_WORD0:
349d38ceaf9SAlex Deucher 			DEBUG(".[15:0] -> 0x%04X\n", val);
350d38ceaf9SAlex Deucher 			break;
351d38ceaf9SAlex Deucher 		case ATOM_SRC_WORD8:
352d38ceaf9SAlex Deucher 			DEBUG(".[23:8] -> 0x%04X\n", val);
353d38ceaf9SAlex Deucher 			break;
354d38ceaf9SAlex Deucher 		case ATOM_SRC_WORD16:
355d38ceaf9SAlex Deucher 			DEBUG(".[31:16] -> 0x%04X\n", val);
356d38ceaf9SAlex Deucher 			break;
357d38ceaf9SAlex Deucher 		case ATOM_SRC_BYTE0:
358d38ceaf9SAlex Deucher 			DEBUG(".[7:0] -> 0x%02X\n", val);
359d38ceaf9SAlex Deucher 			break;
360d38ceaf9SAlex Deucher 		case ATOM_SRC_BYTE8:
361d38ceaf9SAlex Deucher 			DEBUG(".[15:8] -> 0x%02X\n", val);
362d38ceaf9SAlex Deucher 			break;
363d38ceaf9SAlex Deucher 		case ATOM_SRC_BYTE16:
364d38ceaf9SAlex Deucher 			DEBUG(".[23:16] -> 0x%02X\n", val);
365d38ceaf9SAlex Deucher 			break;
366d38ceaf9SAlex Deucher 		case ATOM_SRC_BYTE24:
367d38ceaf9SAlex Deucher 			DEBUG(".[31:24] -> 0x%02X\n", val);
368d38ceaf9SAlex Deucher 			break;
369d38ceaf9SAlex Deucher 		}
370d38ceaf9SAlex Deucher 	return val;
371d38ceaf9SAlex Deucher }
372d38ceaf9SAlex Deucher 
atom_skip_src_int(atom_exec_context * ctx,uint8_t attr,int * ptr)373d38ceaf9SAlex Deucher static void atom_skip_src_int(atom_exec_context *ctx, uint8_t attr, int *ptr)
374d38ceaf9SAlex Deucher {
375d38ceaf9SAlex Deucher 	uint32_t align = (attr >> 3) & 7, arg = attr & 7;
376d38ceaf9SAlex Deucher 	switch (arg) {
377d38ceaf9SAlex Deucher 	case ATOM_ARG_REG:
378d38ceaf9SAlex Deucher 	case ATOM_ARG_ID:
379d38ceaf9SAlex Deucher 		(*ptr) += 2;
380d38ceaf9SAlex Deucher 		break;
381d38ceaf9SAlex Deucher 	case ATOM_ARG_PLL:
382d38ceaf9SAlex Deucher 	case ATOM_ARG_MC:
383d38ceaf9SAlex Deucher 	case ATOM_ARG_PS:
384d38ceaf9SAlex Deucher 	case ATOM_ARG_WS:
385d38ceaf9SAlex Deucher 	case ATOM_ARG_FB:
386d38ceaf9SAlex Deucher 		(*ptr)++;
387d38ceaf9SAlex Deucher 		break;
388d38ceaf9SAlex Deucher 	case ATOM_ARG_IMM:
389d38ceaf9SAlex Deucher 		switch (align) {
390d38ceaf9SAlex Deucher 		case ATOM_SRC_DWORD:
391d38ceaf9SAlex Deucher 			(*ptr) += 4;
392d38ceaf9SAlex Deucher 			return;
393d38ceaf9SAlex Deucher 		case ATOM_SRC_WORD0:
394d38ceaf9SAlex Deucher 		case ATOM_SRC_WORD8:
395d38ceaf9SAlex Deucher 		case ATOM_SRC_WORD16:
396d38ceaf9SAlex Deucher 			(*ptr) += 2;
397d38ceaf9SAlex Deucher 			return;
398d38ceaf9SAlex Deucher 		case ATOM_SRC_BYTE0:
399d38ceaf9SAlex Deucher 		case ATOM_SRC_BYTE8:
400d38ceaf9SAlex Deucher 		case ATOM_SRC_BYTE16:
401d38ceaf9SAlex Deucher 		case ATOM_SRC_BYTE24:
402d38ceaf9SAlex Deucher 			(*ptr)++;
403d38ceaf9SAlex Deucher 			return;
404d38ceaf9SAlex Deucher 		}
405d38ceaf9SAlex Deucher 	}
406d38ceaf9SAlex Deucher }
407d38ceaf9SAlex Deucher 
atom_get_src(atom_exec_context * ctx,uint8_t attr,int * ptr)408d38ceaf9SAlex Deucher static uint32_t atom_get_src(atom_exec_context *ctx, uint8_t attr, int *ptr)
409d38ceaf9SAlex Deucher {
410d38ceaf9SAlex Deucher 	return atom_get_src_int(ctx, attr, ptr, NULL, 1);
411d38ceaf9SAlex Deucher }
412d38ceaf9SAlex Deucher 
atom_get_src_direct(atom_exec_context * ctx,uint8_t align,int * ptr)413d38ceaf9SAlex Deucher static uint32_t atom_get_src_direct(atom_exec_context *ctx, uint8_t align, int *ptr)
414d38ceaf9SAlex Deucher {
415d38ceaf9SAlex Deucher 	uint32_t val = 0xCDCDCDCD;
416d38ceaf9SAlex Deucher 
417d38ceaf9SAlex Deucher 	switch (align) {
418d38ceaf9SAlex Deucher 	case ATOM_SRC_DWORD:
419d38ceaf9SAlex Deucher 		val = U32(*ptr);
420d38ceaf9SAlex Deucher 		(*ptr) += 4;
421d38ceaf9SAlex Deucher 		break;
422d38ceaf9SAlex Deucher 	case ATOM_SRC_WORD0:
423d38ceaf9SAlex Deucher 	case ATOM_SRC_WORD8:
424d38ceaf9SAlex Deucher 	case ATOM_SRC_WORD16:
425d38ceaf9SAlex Deucher 		val = U16(*ptr);
426d38ceaf9SAlex Deucher 		(*ptr) += 2;
427d38ceaf9SAlex Deucher 		break;
428d38ceaf9SAlex Deucher 	case ATOM_SRC_BYTE0:
429d38ceaf9SAlex Deucher 	case ATOM_SRC_BYTE8:
430d38ceaf9SAlex Deucher 	case ATOM_SRC_BYTE16:
431d38ceaf9SAlex Deucher 	case ATOM_SRC_BYTE24:
432d38ceaf9SAlex Deucher 		val = U8(*ptr);
433d38ceaf9SAlex Deucher 		(*ptr)++;
434d38ceaf9SAlex Deucher 		break;
435d38ceaf9SAlex Deucher 	}
436d38ceaf9SAlex Deucher 	return val;
437d38ceaf9SAlex Deucher }
438d38ceaf9SAlex Deucher 
atom_get_dst(atom_exec_context * ctx,int arg,uint8_t attr,int * ptr,uint32_t * saved,int print)439d38ceaf9SAlex Deucher static uint32_t atom_get_dst(atom_exec_context *ctx, int arg, uint8_t attr,
440d38ceaf9SAlex Deucher 			     int *ptr, uint32_t *saved, int print)
441d38ceaf9SAlex Deucher {
442d38ceaf9SAlex Deucher 	return atom_get_src_int(ctx,
443d38ceaf9SAlex Deucher 				arg | atom_dst_to_src[(attr >> 3) &
444d38ceaf9SAlex Deucher 						      7][(attr >> 6) & 3] << 3,
445d38ceaf9SAlex Deucher 				ptr, saved, print);
446d38ceaf9SAlex Deucher }
447d38ceaf9SAlex Deucher 
atom_skip_dst(atom_exec_context * ctx,int arg,uint8_t attr,int * ptr)448d38ceaf9SAlex Deucher static void atom_skip_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr)
449d38ceaf9SAlex Deucher {
450d38ceaf9SAlex Deucher 	atom_skip_src_int(ctx,
451d38ceaf9SAlex Deucher 			  arg | atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) &
452d38ceaf9SAlex Deucher 								 3] << 3, ptr);
453d38ceaf9SAlex Deucher }
454d38ceaf9SAlex Deucher 
atom_put_dst(atom_exec_context * ctx,int arg,uint8_t attr,int * ptr,uint32_t val,uint32_t saved)455d38ceaf9SAlex Deucher static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr,
456d38ceaf9SAlex Deucher 			 int *ptr, uint32_t val, uint32_t saved)
457d38ceaf9SAlex Deucher {
458d38ceaf9SAlex Deucher 	uint32_t align =
459d38ceaf9SAlex Deucher 	    atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3], old_val =
460d38ceaf9SAlex Deucher 	    val, idx;
461d38ceaf9SAlex Deucher 	struct atom_context *gctx = ctx->ctx;
462d38ceaf9SAlex Deucher 	old_val &= atom_arg_mask[align] >> atom_arg_shift[align];
463d38ceaf9SAlex Deucher 	val <<= atom_arg_shift[align];
464d38ceaf9SAlex Deucher 	val &= atom_arg_mask[align];
465d38ceaf9SAlex Deucher 	saved &= ~atom_arg_mask[align];
466d38ceaf9SAlex Deucher 	val |= saved;
467d38ceaf9SAlex Deucher 	switch (arg) {
468d38ceaf9SAlex Deucher 	case ATOM_ARG_REG:
469d38ceaf9SAlex Deucher 		idx = U16(*ptr);
470d38ceaf9SAlex Deucher 		(*ptr) += 2;
471d38ceaf9SAlex Deucher 		DEBUG("REG[0x%04X]", idx);
472d38ceaf9SAlex Deucher 		idx += gctx->reg_block;
473d38ceaf9SAlex Deucher 		switch (gctx->io_mode) {
474d38ceaf9SAlex Deucher 		case ATOM_IO_MM:
475d38ceaf9SAlex Deucher 			if (idx == 0)
476d38ceaf9SAlex Deucher 				gctx->card->reg_write(gctx->card, idx,
477d38ceaf9SAlex Deucher 						      val << 2);
478d38ceaf9SAlex Deucher 			else
479d38ceaf9SAlex Deucher 				gctx->card->reg_write(gctx->card, idx, val);
480d38ceaf9SAlex Deucher 			break;
481d38ceaf9SAlex Deucher 		case ATOM_IO_PCI:
4827ca85295SJoe Perches 			pr_info("PCI registers are not implemented\n");
483d38ceaf9SAlex Deucher 			return;
484d38ceaf9SAlex Deucher 		case ATOM_IO_SYSIO:
4857ca85295SJoe Perches 			pr_info("SYSIO registers are not implemented\n");
486d38ceaf9SAlex Deucher 			return;
487d38ceaf9SAlex Deucher 		default:
488d38ceaf9SAlex Deucher 			if (!(gctx->io_mode & 0x80)) {
4897ca85295SJoe Perches 				pr_info("Bad IO mode\n");
490d38ceaf9SAlex Deucher 				return;
491d38ceaf9SAlex Deucher 			}
492d38ceaf9SAlex Deucher 			if (!gctx->iio[gctx->io_mode & 0xFF]) {
4937ca85295SJoe Perches 				pr_info("Undefined indirect IO write method %d\n",
494d38ceaf9SAlex Deucher 					gctx->io_mode & 0x7F);
495d38ceaf9SAlex Deucher 				return;
496d38ceaf9SAlex Deucher 			}
497d38ceaf9SAlex Deucher 			atom_iio_execute(gctx, gctx->iio[gctx->io_mode & 0xFF],
498d38ceaf9SAlex Deucher 					 idx, val);
499d38ceaf9SAlex Deucher 		}
500d38ceaf9SAlex Deucher 		break;
501d38ceaf9SAlex Deucher 	case ATOM_ARG_PS:
502d38ceaf9SAlex Deucher 		idx = U8(*ptr);
503d38ceaf9SAlex Deucher 		(*ptr)++;
504d38ceaf9SAlex Deucher 		DEBUG("PS[0x%02X]", idx);
5054630d503SAlexander Richards 		if (idx >= ctx->ps_size) {
5064630d503SAlexander Richards 			pr_info("PS index out of range: %i > %i\n", idx, ctx->ps_size);
5074630d503SAlexander Richards 			return;
5084630d503SAlexander Richards 		}
509d38ceaf9SAlex Deucher 		ctx->ps[idx] = cpu_to_le32(val);
510d38ceaf9SAlex Deucher 		break;
511d38ceaf9SAlex Deucher 	case ATOM_ARG_WS:
512d38ceaf9SAlex Deucher 		idx = U8(*ptr);
513d38ceaf9SAlex Deucher 		(*ptr)++;
514d38ceaf9SAlex Deucher 		DEBUG("WS[0x%02X]", idx);
515d38ceaf9SAlex Deucher 		switch (idx) {
516d38ceaf9SAlex Deucher 		case ATOM_WS_QUOTIENT:
517d38ceaf9SAlex Deucher 			gctx->divmul[0] = val;
518d38ceaf9SAlex Deucher 			break;
519d38ceaf9SAlex Deucher 		case ATOM_WS_REMAINDER:
520d38ceaf9SAlex Deucher 			gctx->divmul[1] = val;
521d38ceaf9SAlex Deucher 			break;
522d38ceaf9SAlex Deucher 		case ATOM_WS_DATAPTR:
523d38ceaf9SAlex Deucher 			gctx->data_block = val;
524d38ceaf9SAlex Deucher 			break;
525d38ceaf9SAlex Deucher 		case ATOM_WS_SHIFT:
526d38ceaf9SAlex Deucher 			gctx->shift = val;
527d38ceaf9SAlex Deucher 			break;
528d38ceaf9SAlex Deucher 		case ATOM_WS_OR_MASK:
529d38ceaf9SAlex Deucher 		case ATOM_WS_AND_MASK:
530d38ceaf9SAlex Deucher 			break;
531d38ceaf9SAlex Deucher 		case ATOM_WS_FB_WINDOW:
532d38ceaf9SAlex Deucher 			gctx->fb_base = val;
533d38ceaf9SAlex Deucher 			break;
534d38ceaf9SAlex Deucher 		case ATOM_WS_ATTRIBUTES:
535d38ceaf9SAlex Deucher 			gctx->io_attr = val;
536d38ceaf9SAlex Deucher 			break;
537d38ceaf9SAlex Deucher 		case ATOM_WS_REGPTR:
538d38ceaf9SAlex Deucher 			gctx->reg_block = val;
539d38ceaf9SAlex Deucher 			break;
540d38ceaf9SAlex Deucher 		default:
5414630d503SAlexander Richards 			if (idx >= ctx->ws_size) {
5424630d503SAlexander Richards 				pr_info("WS index out of range: %i > %i\n", idx, ctx->ws_size);
5434630d503SAlexander Richards 				return;
5444630d503SAlexander Richards 			}
545d38ceaf9SAlex Deucher 			ctx->ws[idx] = val;
546d38ceaf9SAlex Deucher 		}
547d38ceaf9SAlex Deucher 		break;
548d38ceaf9SAlex Deucher 	case ATOM_ARG_FB:
549d38ceaf9SAlex Deucher 		idx = U8(*ptr);
550d38ceaf9SAlex Deucher 		(*ptr)++;
551d38ceaf9SAlex Deucher 		if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) {
552d38ceaf9SAlex Deucher 			DRM_ERROR("ATOM: fb write beyond scratch region: %d vs. %d\n",
553d38ceaf9SAlex Deucher 				  gctx->fb_base + (idx * 4), gctx->scratch_size_bytes);
554d38ceaf9SAlex Deucher 		} else
555d38ceaf9SAlex Deucher 			gctx->scratch[(gctx->fb_base / 4) + idx] = val;
556d38ceaf9SAlex Deucher 		DEBUG("FB[0x%02X]", idx);
557d38ceaf9SAlex Deucher 		break;
558d38ceaf9SAlex Deucher 	case ATOM_ARG_PLL:
559d38ceaf9SAlex Deucher 		idx = U8(*ptr);
560d38ceaf9SAlex Deucher 		(*ptr)++;
561d38ceaf9SAlex Deucher 		DEBUG("PLL[0x%02X]", idx);
562d38ceaf9SAlex Deucher 		gctx->card->pll_write(gctx->card, idx, val);
563d38ceaf9SAlex Deucher 		break;
564d38ceaf9SAlex Deucher 	case ATOM_ARG_MC:
565d38ceaf9SAlex Deucher 		idx = U8(*ptr);
566d38ceaf9SAlex Deucher 		(*ptr)++;
567d38ceaf9SAlex Deucher 		DEBUG("MC[0x%02X]", idx);
568d38ceaf9SAlex Deucher 		gctx->card->mc_write(gctx->card, idx, val);
569d38ceaf9SAlex Deucher 		return;
570d38ceaf9SAlex Deucher 	}
571d38ceaf9SAlex Deucher 	switch (align) {
572d38ceaf9SAlex Deucher 	case ATOM_SRC_DWORD:
573d38ceaf9SAlex Deucher 		DEBUG(".[31:0] <- 0x%08X\n", old_val);
574d38ceaf9SAlex Deucher 		break;
575d38ceaf9SAlex Deucher 	case ATOM_SRC_WORD0:
576d38ceaf9SAlex Deucher 		DEBUG(".[15:0] <- 0x%04X\n", old_val);
577d38ceaf9SAlex Deucher 		break;
578d38ceaf9SAlex Deucher 	case ATOM_SRC_WORD8:
579d38ceaf9SAlex Deucher 		DEBUG(".[23:8] <- 0x%04X\n", old_val);
580d38ceaf9SAlex Deucher 		break;
581d38ceaf9SAlex Deucher 	case ATOM_SRC_WORD16:
582d38ceaf9SAlex Deucher 		DEBUG(".[31:16] <- 0x%04X\n", old_val);
583d38ceaf9SAlex Deucher 		break;
584d38ceaf9SAlex Deucher 	case ATOM_SRC_BYTE0:
585d38ceaf9SAlex Deucher 		DEBUG(".[7:0] <- 0x%02X\n", old_val);
586d38ceaf9SAlex Deucher 		break;
587d38ceaf9SAlex Deucher 	case ATOM_SRC_BYTE8:
588d38ceaf9SAlex Deucher 		DEBUG(".[15:8] <- 0x%02X\n", old_val);
589d38ceaf9SAlex Deucher 		break;
590d38ceaf9SAlex Deucher 	case ATOM_SRC_BYTE16:
591d38ceaf9SAlex Deucher 		DEBUG(".[23:16] <- 0x%02X\n", old_val);
592d38ceaf9SAlex Deucher 		break;
593d38ceaf9SAlex Deucher 	case ATOM_SRC_BYTE24:
594d38ceaf9SAlex Deucher 		DEBUG(".[31:24] <- 0x%02X\n", old_val);
595d38ceaf9SAlex Deucher 		break;
596d38ceaf9SAlex Deucher 	}
597d38ceaf9SAlex Deucher }
598d38ceaf9SAlex Deucher 
atom_op_add(atom_exec_context * ctx,int * ptr,int arg)599d38ceaf9SAlex Deucher static void atom_op_add(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_and(atom_exec_context * ctx,int * ptr,int arg)613d38ceaf9SAlex Deucher static void atom_op_and(atom_exec_context *ctx, int *ptr, int arg)
614d38ceaf9SAlex Deucher {
615d38ceaf9SAlex Deucher 	uint8_t attr = U8((*ptr)++);
616d38ceaf9SAlex Deucher 	uint32_t dst, src, saved;
617d38ceaf9SAlex Deucher 	int dptr = *ptr;
618d38ceaf9SAlex Deucher 	SDEBUG("   dst: ");
619d38ceaf9SAlex Deucher 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
620d38ceaf9SAlex Deucher 	SDEBUG("   src: ");
621d38ceaf9SAlex Deucher 	src = atom_get_src(ctx, attr, ptr);
622d38ceaf9SAlex Deucher 	dst &= src;
623d38ceaf9SAlex Deucher 	SDEBUG("   dst: ");
624d38ceaf9SAlex Deucher 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
625d38ceaf9SAlex Deucher }
626d38ceaf9SAlex Deucher 
atom_op_beep(atom_exec_context * ctx,int * ptr,int arg)627d38ceaf9SAlex Deucher static void atom_op_beep(atom_exec_context *ctx, int *ptr, int arg)
628d38ceaf9SAlex Deucher {
629d38ceaf9SAlex Deucher 	printk("ATOM BIOS beeped!\n");
630d38ceaf9SAlex Deucher }
631d38ceaf9SAlex Deucher 
atom_op_calltable(atom_exec_context * ctx,int * ptr,int arg)632d38ceaf9SAlex Deucher static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg)
633d38ceaf9SAlex Deucher {
634d38ceaf9SAlex Deucher 	int idx = U8((*ptr)++);
635d38ceaf9SAlex Deucher 	int r = 0;
636d38ceaf9SAlex Deucher 
637d38ceaf9SAlex Deucher 	if (idx < ATOM_TABLE_NAMES_CNT)
638d38ceaf9SAlex Deucher 		SDEBUG("   table: %d (%s)\n", idx, atom_table_names[idx]);
639d38ceaf9SAlex Deucher 	else
640d38ceaf9SAlex Deucher 		SDEBUG("   table: %d\n", idx);
641d38ceaf9SAlex Deucher 	if (U16(ctx->ctx->cmd_table + 4 + 2 * idx))
6424630d503SAlexander Richards 		r = amdgpu_atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift, ctx->ps_size - ctx->ps_shift);
643d38ceaf9SAlex Deucher 	if (r) {
644d38ceaf9SAlex Deucher 		ctx->abort = true;
645d38ceaf9SAlex Deucher 	}
646d38ceaf9SAlex Deucher }
647d38ceaf9SAlex Deucher 
atom_op_clear(atom_exec_context * ctx,int * ptr,int arg)648d38ceaf9SAlex Deucher static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg)
649d38ceaf9SAlex Deucher {
650d38ceaf9SAlex Deucher 	uint8_t attr = U8((*ptr)++);
651d38ceaf9SAlex Deucher 	uint32_t saved;
652d38ceaf9SAlex Deucher 	int dptr = *ptr;
653d38ceaf9SAlex Deucher 	attr &= 0x38;
654d38ceaf9SAlex Deucher 	attr |= atom_def_dst[attr >> 3] << 6;
655d38ceaf9SAlex Deucher 	atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
656d38ceaf9SAlex Deucher 	SDEBUG("   dst: ");
657d38ceaf9SAlex Deucher 	atom_put_dst(ctx, arg, attr, &dptr, 0, saved);
658d38ceaf9SAlex Deucher }
659d38ceaf9SAlex Deucher 
atom_op_compare(atom_exec_context * ctx,int * ptr,int arg)660d38ceaf9SAlex Deucher static void atom_op_compare(atom_exec_context *ctx, int *ptr, int arg)
661d38ceaf9SAlex Deucher {
662d38ceaf9SAlex Deucher 	uint8_t attr = U8((*ptr)++);
663d38ceaf9SAlex Deucher 	uint32_t dst, src;
664d38ceaf9SAlex Deucher 	SDEBUG("   src1: ");
665d38ceaf9SAlex Deucher 	dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
666d38ceaf9SAlex Deucher 	SDEBUG("   src2: ");
667d38ceaf9SAlex Deucher 	src = atom_get_src(ctx, attr, ptr);
668d38ceaf9SAlex Deucher 	ctx->ctx->cs_equal = (dst == src);
669d38ceaf9SAlex Deucher 	ctx->ctx->cs_above = (dst > src);
670d38ceaf9SAlex Deucher 	SDEBUG("   result: %s %s\n", ctx->ctx->cs_equal ? "EQ" : "NE",
671d38ceaf9SAlex Deucher 	       ctx->ctx->cs_above ? "GT" : "LE");
672d38ceaf9SAlex Deucher }
673d38ceaf9SAlex Deucher 
atom_op_delay(atom_exec_context * ctx,int * ptr,int arg)674d38ceaf9SAlex Deucher static void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg)
675d38ceaf9SAlex Deucher {
676d38ceaf9SAlex Deucher 	unsigned count = U8((*ptr)++);
677d38ceaf9SAlex Deucher 	SDEBUG("   count: %d\n", count);
678d38ceaf9SAlex Deucher 	if (arg == ATOM_UNIT_MICROSEC)
679d38ceaf9SAlex Deucher 		udelay(count);
680d38ceaf9SAlex Deucher 	else if (!drm_can_sleep())
681d38ceaf9SAlex Deucher 		mdelay(count);
682d38ceaf9SAlex Deucher 	else
683d38ceaf9SAlex Deucher 		msleep(count);
684d38ceaf9SAlex Deucher }
685d38ceaf9SAlex Deucher 
atom_op_div(atom_exec_context * ctx,int * ptr,int arg)686d38ceaf9SAlex Deucher static void atom_op_div(atom_exec_context *ctx, int *ptr, int arg)
687d38ceaf9SAlex Deucher {
688d38ceaf9SAlex Deucher 	uint8_t attr = U8((*ptr)++);
689d38ceaf9SAlex Deucher 	uint32_t dst, src;
690d38ceaf9SAlex Deucher 	SDEBUG("   src1: ");
691d38ceaf9SAlex Deucher 	dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
692d38ceaf9SAlex Deucher 	SDEBUG("   src2: ");
693d38ceaf9SAlex Deucher 	src = atom_get_src(ctx, attr, ptr);
694d38ceaf9SAlex Deucher 	if (src != 0) {
695d38ceaf9SAlex Deucher 		ctx->ctx->divmul[0] = dst / src;
696d38ceaf9SAlex Deucher 		ctx->ctx->divmul[1] = dst % src;
697d38ceaf9SAlex Deucher 	} else {
698d38ceaf9SAlex Deucher 		ctx->ctx->divmul[0] = 0;
699d38ceaf9SAlex Deucher 		ctx->ctx->divmul[1] = 0;
700d38ceaf9SAlex Deucher 	}
701d38ceaf9SAlex Deucher }
702d38ceaf9SAlex Deucher 
atom_op_div32(atom_exec_context * ctx,int * ptr,int arg)703c2fe16aaSAlex Deucher static void atom_op_div32(atom_exec_context *ctx, int *ptr, int arg)
704c2fe16aaSAlex Deucher {
705c2fe16aaSAlex Deucher 	uint64_t val64;
706c2fe16aaSAlex Deucher 	uint8_t attr = U8((*ptr)++);
707c2fe16aaSAlex Deucher 	uint32_t dst, src;
708c2fe16aaSAlex Deucher 	SDEBUG("   src1: ");
709c2fe16aaSAlex Deucher 	dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
710c2fe16aaSAlex Deucher 	SDEBUG("   src2: ");
711c2fe16aaSAlex Deucher 	src = atom_get_src(ctx, attr, ptr);
712c2fe16aaSAlex Deucher 	if (src != 0) {
713c2fe16aaSAlex Deucher 		val64 = dst;
714c2fe16aaSAlex Deucher 		val64 |= ((uint64_t)ctx->ctx->divmul[1]) << 32;
715c2fe16aaSAlex Deucher 		do_div(val64, src);
716c2fe16aaSAlex Deucher 		ctx->ctx->divmul[0] = lower_32_bits(val64);
717c2fe16aaSAlex Deucher 		ctx->ctx->divmul[1] = upper_32_bits(val64);
718c2fe16aaSAlex Deucher 	} else {
719c2fe16aaSAlex Deucher 		ctx->ctx->divmul[0] = 0;
720c2fe16aaSAlex Deucher 		ctx->ctx->divmul[1] = 0;
721c2fe16aaSAlex Deucher 	}
722c2fe16aaSAlex Deucher }
723c2fe16aaSAlex Deucher 
atom_op_eot(atom_exec_context * ctx,int * ptr,int arg)724d38ceaf9SAlex Deucher static void atom_op_eot(atom_exec_context *ctx, int *ptr, int arg)
725d38ceaf9SAlex Deucher {
726d38ceaf9SAlex Deucher 	/* functionally, a nop */
727d38ceaf9SAlex Deucher }
728d38ceaf9SAlex Deucher 
atom_op_jump(atom_exec_context * ctx,int * ptr,int arg)729d38ceaf9SAlex Deucher static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
730d38ceaf9SAlex Deucher {
731d38ceaf9SAlex Deucher 	int execute = 0, target = U16(*ptr);
732d38ceaf9SAlex Deucher 	unsigned long cjiffies;
733d38ceaf9SAlex Deucher 
734d38ceaf9SAlex Deucher 	(*ptr) += 2;
735d38ceaf9SAlex Deucher 	switch (arg) {
736d38ceaf9SAlex Deucher 	case ATOM_COND_ABOVE:
737d38ceaf9SAlex Deucher 		execute = ctx->ctx->cs_above;
738d38ceaf9SAlex Deucher 		break;
739d38ceaf9SAlex Deucher 	case ATOM_COND_ABOVEOREQUAL:
740d38ceaf9SAlex Deucher 		execute = ctx->ctx->cs_above || ctx->ctx->cs_equal;
741d38ceaf9SAlex Deucher 		break;
742d38ceaf9SAlex Deucher 	case ATOM_COND_ALWAYS:
743d38ceaf9SAlex Deucher 		execute = 1;
744d38ceaf9SAlex Deucher 		break;
745d38ceaf9SAlex Deucher 	case ATOM_COND_BELOW:
746d38ceaf9SAlex Deucher 		execute = !(ctx->ctx->cs_above || ctx->ctx->cs_equal);
747d38ceaf9SAlex Deucher 		break;
748d38ceaf9SAlex Deucher 	case ATOM_COND_BELOWOREQUAL:
749d38ceaf9SAlex Deucher 		execute = !ctx->ctx->cs_above;
750d38ceaf9SAlex Deucher 		break;
751d38ceaf9SAlex Deucher 	case ATOM_COND_EQUAL:
752d38ceaf9SAlex Deucher 		execute = ctx->ctx->cs_equal;
753d38ceaf9SAlex Deucher 		break;
754d38ceaf9SAlex Deucher 	case ATOM_COND_NOTEQUAL:
755d38ceaf9SAlex Deucher 		execute = !ctx->ctx->cs_equal;
756d38ceaf9SAlex Deucher 		break;
757d38ceaf9SAlex Deucher 	}
758d38ceaf9SAlex Deucher 	if (arg != ATOM_COND_ALWAYS)
759b8c75bd9SLucas De Marchi 		SDEBUG("   taken: %s\n", str_yes_no(execute));
760d38ceaf9SAlex Deucher 	SDEBUG("   target: 0x%04X\n", target);
761d38ceaf9SAlex Deucher 	if (execute) {
762d38ceaf9SAlex Deucher 		if (ctx->last_jump == (ctx->start + target)) {
763d38ceaf9SAlex Deucher 			cjiffies = jiffies;
764d38ceaf9SAlex Deucher 			if (time_after(cjiffies, ctx->last_jump_jiffies)) {
765d38ceaf9SAlex Deucher 				cjiffies -= ctx->last_jump_jiffies;
7669a785c7aSJohn Clements 				if ((jiffies_to_msecs(cjiffies) > ATOM_CMD_TIMEOUT_SEC*1000)) {
7679a785c7aSJohn Clements 					DRM_ERROR("atombios stuck in loop for more than %dsecs aborting\n",
7689a785c7aSJohn Clements 						  ATOM_CMD_TIMEOUT_SEC);
769d38ceaf9SAlex Deucher 					ctx->abort = true;
770d38ceaf9SAlex Deucher 				}
771d38ceaf9SAlex Deucher 			} else {
772d38ceaf9SAlex Deucher 				/* jiffies wrap around we will just wait a little longer */
773d38ceaf9SAlex Deucher 				ctx->last_jump_jiffies = jiffies;
774d38ceaf9SAlex Deucher 			}
775d38ceaf9SAlex Deucher 		} else {
776d38ceaf9SAlex Deucher 			ctx->last_jump = ctx->start + target;
777d38ceaf9SAlex Deucher 			ctx->last_jump_jiffies = jiffies;
778d38ceaf9SAlex Deucher 		}
779d38ceaf9SAlex Deucher 		*ptr = ctx->start + target;
780d38ceaf9SAlex Deucher 	}
781d38ceaf9SAlex Deucher }
782d38ceaf9SAlex Deucher 
atom_op_mask(atom_exec_context * ctx,int * ptr,int arg)783d38ceaf9SAlex Deucher static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg)
784d38ceaf9SAlex Deucher {
785d38ceaf9SAlex Deucher 	uint8_t attr = U8((*ptr)++);
786d38ceaf9SAlex Deucher 	uint32_t dst, mask, src, saved;
787d38ceaf9SAlex Deucher 	int dptr = *ptr;
788d38ceaf9SAlex Deucher 	SDEBUG("   dst: ");
789d38ceaf9SAlex Deucher 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
790d38ceaf9SAlex Deucher 	mask = atom_get_src_direct(ctx, ((attr >> 3) & 7), ptr);
791d38ceaf9SAlex Deucher 	SDEBUG("   mask: 0x%08x", mask);
792d38ceaf9SAlex Deucher 	SDEBUG("   src: ");
793d38ceaf9SAlex Deucher 	src = atom_get_src(ctx, attr, ptr);
794d38ceaf9SAlex Deucher 	dst &= mask;
795d38ceaf9SAlex Deucher 	dst |= src;
796d38ceaf9SAlex Deucher 	SDEBUG("   dst: ");
797d38ceaf9SAlex Deucher 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
798d38ceaf9SAlex Deucher }
799d38ceaf9SAlex Deucher 
atom_op_move(atom_exec_context * ctx,int * ptr,int arg)800d38ceaf9SAlex Deucher static void atom_op_move(atom_exec_context *ctx, int *ptr, int arg)
801d38ceaf9SAlex Deucher {
802d38ceaf9SAlex Deucher 	uint8_t attr = U8((*ptr)++);
803d38ceaf9SAlex Deucher 	uint32_t src, saved;
804d38ceaf9SAlex Deucher 	int dptr = *ptr;
805d38ceaf9SAlex Deucher 	if (((attr >> 3) & 7) != ATOM_SRC_DWORD)
806d38ceaf9SAlex Deucher 		atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
807d38ceaf9SAlex Deucher 	else {
808d38ceaf9SAlex Deucher 		atom_skip_dst(ctx, arg, attr, ptr);
809d38ceaf9SAlex Deucher 		saved = 0xCDCDCDCD;
810d38ceaf9SAlex Deucher 	}
811d38ceaf9SAlex Deucher 	SDEBUG("   src: ");
812d38ceaf9SAlex Deucher 	src = atom_get_src(ctx, attr, ptr);
813d38ceaf9SAlex Deucher 	SDEBUG("   dst: ");
814d38ceaf9SAlex Deucher 	atom_put_dst(ctx, arg, attr, &dptr, src, saved);
815d38ceaf9SAlex Deucher }
816d38ceaf9SAlex Deucher 
atom_op_mul(atom_exec_context * ctx,int * ptr,int arg)817d38ceaf9SAlex Deucher static void atom_op_mul(atom_exec_context *ctx, int *ptr, int arg)
818d38ceaf9SAlex Deucher {
819d38ceaf9SAlex Deucher 	uint8_t attr = U8((*ptr)++);
820d38ceaf9SAlex Deucher 	uint32_t dst, src;
821d38ceaf9SAlex Deucher 	SDEBUG("   src1: ");
822d38ceaf9SAlex Deucher 	dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
823d38ceaf9SAlex Deucher 	SDEBUG("   src2: ");
824d38ceaf9SAlex Deucher 	src = atom_get_src(ctx, attr, ptr);
825d38ceaf9SAlex Deucher 	ctx->ctx->divmul[0] = dst * src;
826d38ceaf9SAlex Deucher }
827d38ceaf9SAlex Deucher 
atom_op_mul32(atom_exec_context * ctx,int * ptr,int arg)828c9c14502SAlex Deucher static void atom_op_mul32(atom_exec_context *ctx, int *ptr, int arg)
829c9c14502SAlex Deucher {
830c9c14502SAlex Deucher 	uint64_t val64;
831c9c14502SAlex Deucher 	uint8_t attr = U8((*ptr)++);
832c9c14502SAlex Deucher 	uint32_t dst, src;
833c9c14502SAlex Deucher 	SDEBUG("   src1: ");
834c9c14502SAlex Deucher 	dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
835c9c14502SAlex Deucher 	SDEBUG("   src2: ");
836c9c14502SAlex Deucher 	src = atom_get_src(ctx, attr, ptr);
837c9c14502SAlex Deucher 	val64 = (uint64_t)dst * (uint64_t)src;
838c9c14502SAlex Deucher 	ctx->ctx->divmul[0] = lower_32_bits(val64);
839c9c14502SAlex Deucher 	ctx->ctx->divmul[1] = upper_32_bits(val64);
840c9c14502SAlex Deucher }
841c9c14502SAlex Deucher 
atom_op_nop(atom_exec_context * ctx,int * ptr,int arg)842d38ceaf9SAlex Deucher static void atom_op_nop(atom_exec_context *ctx, int *ptr, int arg)
843d38ceaf9SAlex Deucher {
844d38ceaf9SAlex Deucher 	/* nothing */
845d38ceaf9SAlex Deucher }
846d38ceaf9SAlex Deucher 
atom_op_or(atom_exec_context * ctx,int * ptr,int arg)847d38ceaf9SAlex Deucher static void atom_op_or(atom_exec_context *ctx, int *ptr, int arg)
848d38ceaf9SAlex Deucher {
849d38ceaf9SAlex Deucher 	uint8_t attr = U8((*ptr)++);
850d38ceaf9SAlex Deucher 	uint32_t dst, src, saved;
851d38ceaf9SAlex Deucher 	int dptr = *ptr;
852d38ceaf9SAlex Deucher 	SDEBUG("   dst: ");
853d38ceaf9SAlex Deucher 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
854d38ceaf9SAlex Deucher 	SDEBUG("   src: ");
855d38ceaf9SAlex Deucher 	src = atom_get_src(ctx, attr, ptr);
856d38ceaf9SAlex Deucher 	dst |= src;
857d38ceaf9SAlex Deucher 	SDEBUG("   dst: ");
858d38ceaf9SAlex Deucher 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
859d38ceaf9SAlex Deucher }
860d38ceaf9SAlex Deucher 
atom_op_postcard(atom_exec_context * ctx,int * ptr,int arg)861d38ceaf9SAlex Deucher static void atom_op_postcard(atom_exec_context *ctx, int *ptr, int arg)
862d38ceaf9SAlex Deucher {
863d38ceaf9SAlex Deucher 	uint8_t val = U8((*ptr)++);
864d38ceaf9SAlex Deucher 	SDEBUG("POST card output: 0x%02X\n", val);
865d38ceaf9SAlex Deucher }
866d38ceaf9SAlex Deucher 
atom_op_repeat(atom_exec_context * ctx,int * ptr,int arg)867d38ceaf9SAlex Deucher static void atom_op_repeat(atom_exec_context *ctx, int *ptr, int arg)
868d38ceaf9SAlex Deucher {
8697ca85295SJoe Perches 	pr_info("unimplemented!\n");
870d38ceaf9SAlex Deucher }
871d38ceaf9SAlex Deucher 
atom_op_restorereg(atom_exec_context * ctx,int * ptr,int arg)872d38ceaf9SAlex Deucher static void atom_op_restorereg(atom_exec_context *ctx, int *ptr, int arg)
873d38ceaf9SAlex Deucher {
8747ca85295SJoe Perches 	pr_info("unimplemented!\n");
875d38ceaf9SAlex Deucher }
876d38ceaf9SAlex Deucher 
atom_op_savereg(atom_exec_context * ctx,int * ptr,int arg)877d38ceaf9SAlex Deucher static void atom_op_savereg(atom_exec_context *ctx, int *ptr, int arg)
878d38ceaf9SAlex Deucher {
8797ca85295SJoe Perches 	pr_info("unimplemented!\n");
880d38ceaf9SAlex Deucher }
881d38ceaf9SAlex Deucher 
atom_op_setdatablock(atom_exec_context * ctx,int * ptr,int arg)882d38ceaf9SAlex Deucher static void atom_op_setdatablock(atom_exec_context *ctx, int *ptr, int arg)
883d38ceaf9SAlex Deucher {
884d38ceaf9SAlex Deucher 	int idx = U8(*ptr);
885d38ceaf9SAlex Deucher 	(*ptr)++;
886d38ceaf9SAlex Deucher 	SDEBUG("   block: %d\n", idx);
887d38ceaf9SAlex Deucher 	if (!idx)
888d38ceaf9SAlex Deucher 		ctx->ctx->data_block = 0;
889d38ceaf9SAlex Deucher 	else if (idx == 255)
890d38ceaf9SAlex Deucher 		ctx->ctx->data_block = ctx->start;
891d38ceaf9SAlex Deucher 	else
892d38ceaf9SAlex Deucher 		ctx->ctx->data_block = U16(ctx->ctx->data_table + 4 + 2 * idx);
893d38ceaf9SAlex Deucher 	SDEBUG("   base: 0x%04X\n", ctx->ctx->data_block);
894d38ceaf9SAlex Deucher }
895d38ceaf9SAlex Deucher 
atom_op_setfbbase(atom_exec_context * ctx,int * ptr,int arg)896d38ceaf9SAlex Deucher static void atom_op_setfbbase(atom_exec_context *ctx, int *ptr, int arg)
897d38ceaf9SAlex Deucher {
898d38ceaf9SAlex Deucher 	uint8_t attr = U8((*ptr)++);
899d38ceaf9SAlex Deucher 	SDEBUG("   fb_base: ");
900d38ceaf9SAlex Deucher 	ctx->ctx->fb_base = atom_get_src(ctx, attr, ptr);
901d38ceaf9SAlex Deucher }
902d38ceaf9SAlex Deucher 
atom_op_setport(atom_exec_context * ctx,int * ptr,int arg)903d38ceaf9SAlex Deucher static void atom_op_setport(atom_exec_context *ctx, int *ptr, int arg)
904d38ceaf9SAlex Deucher {
905d38ceaf9SAlex Deucher 	int port;
906d38ceaf9SAlex Deucher 	switch (arg) {
907d38ceaf9SAlex Deucher 	case ATOM_PORT_ATI:
908d38ceaf9SAlex Deucher 		port = U16(*ptr);
909d38ceaf9SAlex Deucher 		if (port < ATOM_IO_NAMES_CNT)
910d38ceaf9SAlex Deucher 			SDEBUG("   port: %d (%s)\n", port, atom_io_names[port]);
911d38ceaf9SAlex Deucher 		else
912d38ceaf9SAlex Deucher 			SDEBUG("   port: %d\n", port);
913d38ceaf9SAlex Deucher 		if (!port)
914d38ceaf9SAlex Deucher 			ctx->ctx->io_mode = ATOM_IO_MM;
915d38ceaf9SAlex Deucher 		else
916d38ceaf9SAlex Deucher 			ctx->ctx->io_mode = ATOM_IO_IIO | port;
917d38ceaf9SAlex Deucher 		(*ptr) += 2;
918d38ceaf9SAlex Deucher 		break;
919d38ceaf9SAlex Deucher 	case ATOM_PORT_PCI:
920d38ceaf9SAlex Deucher 		ctx->ctx->io_mode = ATOM_IO_PCI;
921d38ceaf9SAlex Deucher 		(*ptr)++;
922d38ceaf9SAlex Deucher 		break;
923d38ceaf9SAlex Deucher 	case ATOM_PORT_SYSIO:
924d38ceaf9SAlex Deucher 		ctx->ctx->io_mode = ATOM_IO_SYSIO;
925d38ceaf9SAlex Deucher 		(*ptr)++;
926d38ceaf9SAlex Deucher 		break;
927d38ceaf9SAlex Deucher 	}
928d38ceaf9SAlex Deucher }
929d38ceaf9SAlex Deucher 
atom_op_setregblock(atom_exec_context * ctx,int * ptr,int arg)930d38ceaf9SAlex Deucher static void atom_op_setregblock(atom_exec_context *ctx, int *ptr, int arg)
931d38ceaf9SAlex Deucher {
932d38ceaf9SAlex Deucher 	ctx->ctx->reg_block = U16(*ptr);
933d38ceaf9SAlex Deucher 	(*ptr) += 2;
934d38ceaf9SAlex Deucher 	SDEBUG("   base: 0x%04X\n", ctx->ctx->reg_block);
935d38ceaf9SAlex Deucher }
936d38ceaf9SAlex Deucher 
atom_op_shift_left(atom_exec_context * ctx,int * ptr,int arg)937d38ceaf9SAlex Deucher static void atom_op_shift_left(atom_exec_context *ctx, int *ptr, int arg)
938d38ceaf9SAlex Deucher {
939d38ceaf9SAlex Deucher 	uint8_t attr = U8((*ptr)++), shift;
940d38ceaf9SAlex Deucher 	uint32_t saved, dst;
941d38ceaf9SAlex Deucher 	int dptr = *ptr;
942d38ceaf9SAlex Deucher 	attr &= 0x38;
943d38ceaf9SAlex Deucher 	attr |= atom_def_dst[attr >> 3] << 6;
944d38ceaf9SAlex Deucher 	SDEBUG("   dst: ");
945d38ceaf9SAlex Deucher 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
946d38ceaf9SAlex Deucher 	shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr);
947d38ceaf9SAlex Deucher 	SDEBUG("   shift: %d\n", shift);
948d38ceaf9SAlex Deucher 	dst <<= shift;
949d38ceaf9SAlex Deucher 	SDEBUG("   dst: ");
950d38ceaf9SAlex Deucher 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
951d38ceaf9SAlex Deucher }
952d38ceaf9SAlex Deucher 
atom_op_shift_right(atom_exec_context * ctx,int * ptr,int arg)953d38ceaf9SAlex Deucher static void atom_op_shift_right(atom_exec_context *ctx, int *ptr, int arg)
954d38ceaf9SAlex Deucher {
955d38ceaf9SAlex Deucher 	uint8_t attr = U8((*ptr)++), shift;
956d38ceaf9SAlex Deucher 	uint32_t saved, dst;
957d38ceaf9SAlex Deucher 	int dptr = *ptr;
958d38ceaf9SAlex Deucher 	attr &= 0x38;
959d38ceaf9SAlex Deucher 	attr |= atom_def_dst[attr >> 3] << 6;
960d38ceaf9SAlex Deucher 	SDEBUG("   dst: ");
961d38ceaf9SAlex Deucher 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
962d38ceaf9SAlex Deucher 	shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr);
963d38ceaf9SAlex Deucher 	SDEBUG("   shift: %d\n", shift);
964d38ceaf9SAlex Deucher 	dst >>= shift;
965d38ceaf9SAlex Deucher 	SDEBUG("   dst: ");
966d38ceaf9SAlex Deucher 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
967d38ceaf9SAlex Deucher }
968d38ceaf9SAlex Deucher 
atom_op_shl(atom_exec_context * ctx,int * ptr,int arg)969d38ceaf9SAlex Deucher static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg)
970d38ceaf9SAlex Deucher {
971d38ceaf9SAlex Deucher 	uint8_t attr = U8((*ptr)++), shift;
972d38ceaf9SAlex Deucher 	uint32_t saved, dst;
973d38ceaf9SAlex Deucher 	int dptr = *ptr;
974d38ceaf9SAlex Deucher 	uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3];
975d38ceaf9SAlex Deucher 	SDEBUG("   dst: ");
976d38ceaf9SAlex Deucher 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
977d38ceaf9SAlex Deucher 	/* op needs to full dst value */
978d38ceaf9SAlex Deucher 	dst = saved;
979d38ceaf9SAlex Deucher 	shift = atom_get_src(ctx, attr, ptr);
980d38ceaf9SAlex Deucher 	SDEBUG("   shift: %d\n", shift);
981d38ceaf9SAlex Deucher 	dst <<= shift;
982d38ceaf9SAlex Deucher 	dst &= atom_arg_mask[dst_align];
983d38ceaf9SAlex Deucher 	dst >>= atom_arg_shift[dst_align];
984d38ceaf9SAlex Deucher 	SDEBUG("   dst: ");
985d38ceaf9SAlex Deucher 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
986d38ceaf9SAlex Deucher }
987d38ceaf9SAlex Deucher 
atom_op_shr(atom_exec_context * ctx,int * ptr,int arg)988d38ceaf9SAlex Deucher static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg)
989d38ceaf9SAlex Deucher {
990d38ceaf9SAlex Deucher 	uint8_t attr = U8((*ptr)++), shift;
991d38ceaf9SAlex Deucher 	uint32_t saved, dst;
992d38ceaf9SAlex Deucher 	int dptr = *ptr;
993d38ceaf9SAlex Deucher 	uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3];
994d38ceaf9SAlex Deucher 	SDEBUG("   dst: ");
995d38ceaf9SAlex Deucher 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
996d38ceaf9SAlex Deucher 	/* op needs to full dst value */
997d38ceaf9SAlex Deucher 	dst = saved;
998d38ceaf9SAlex Deucher 	shift = atom_get_src(ctx, attr, ptr);
999d38ceaf9SAlex Deucher 	SDEBUG("   shift: %d\n", shift);
1000d38ceaf9SAlex Deucher 	dst >>= shift;
1001d38ceaf9SAlex Deucher 	dst &= atom_arg_mask[dst_align];
1002d38ceaf9SAlex Deucher 	dst >>= atom_arg_shift[dst_align];
1003d38ceaf9SAlex Deucher 	SDEBUG("   dst: ");
1004d38ceaf9SAlex Deucher 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
1005d38ceaf9SAlex Deucher }
1006d38ceaf9SAlex Deucher 
atom_op_sub(atom_exec_context * ctx,int * ptr,int arg)1007d38ceaf9SAlex Deucher static void atom_op_sub(atom_exec_context *ctx, int *ptr, int arg)
1008d38ceaf9SAlex Deucher {
1009d38ceaf9SAlex Deucher 	uint8_t attr = U8((*ptr)++);
1010d38ceaf9SAlex Deucher 	uint32_t dst, src, saved;
1011d38ceaf9SAlex Deucher 	int dptr = *ptr;
1012d38ceaf9SAlex Deucher 	SDEBUG("   dst: ");
1013d38ceaf9SAlex Deucher 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
1014d38ceaf9SAlex Deucher 	SDEBUG("   src: ");
1015d38ceaf9SAlex Deucher 	src = atom_get_src(ctx, attr, ptr);
1016d38ceaf9SAlex Deucher 	dst -= src;
1017d38ceaf9SAlex Deucher 	SDEBUG("   dst: ");
1018d38ceaf9SAlex Deucher 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
1019d38ceaf9SAlex Deucher }
1020d38ceaf9SAlex Deucher 
atom_op_switch(atom_exec_context * ctx,int * ptr,int arg)1021d38ceaf9SAlex Deucher static void atom_op_switch(atom_exec_context *ctx, int *ptr, int arg)
1022d38ceaf9SAlex Deucher {
1023d38ceaf9SAlex Deucher 	uint8_t attr = U8((*ptr)++);
1024d38ceaf9SAlex Deucher 	uint32_t src, val, target;
1025d38ceaf9SAlex Deucher 	SDEBUG("   switch: ");
1026d38ceaf9SAlex Deucher 	src = atom_get_src(ctx, attr, ptr);
1027d38ceaf9SAlex Deucher 	while (U16(*ptr) != ATOM_CASE_END)
1028d38ceaf9SAlex Deucher 		if (U8(*ptr) == ATOM_CASE_MAGIC) {
1029d38ceaf9SAlex Deucher 			(*ptr)++;
1030d38ceaf9SAlex Deucher 			SDEBUG("   case: ");
1031d38ceaf9SAlex Deucher 			val =
1032d38ceaf9SAlex Deucher 			    atom_get_src(ctx, (attr & 0x38) | ATOM_ARG_IMM,
1033d38ceaf9SAlex Deucher 					 ptr);
1034d38ceaf9SAlex Deucher 			target = U16(*ptr);
1035d38ceaf9SAlex Deucher 			if (val == src) {
1036d38ceaf9SAlex Deucher 				SDEBUG("   target: %04X\n", target);
1037d38ceaf9SAlex Deucher 				*ptr = ctx->start + target;
1038d38ceaf9SAlex Deucher 				return;
1039d38ceaf9SAlex Deucher 			}
1040d38ceaf9SAlex Deucher 			(*ptr) += 2;
1041d38ceaf9SAlex Deucher 		} else {
10427ca85295SJoe Perches 			pr_info("Bad case\n");
1043d38ceaf9SAlex Deucher 			return;
1044d38ceaf9SAlex Deucher 		}
1045d38ceaf9SAlex Deucher 	(*ptr) += 2;
1046d38ceaf9SAlex Deucher }
1047d38ceaf9SAlex Deucher 
atom_op_test(atom_exec_context * ctx,int * ptr,int arg)1048d38ceaf9SAlex Deucher static void atom_op_test(atom_exec_context *ctx, int *ptr, int arg)
1049d38ceaf9SAlex Deucher {
1050d38ceaf9SAlex Deucher 	uint8_t attr = U8((*ptr)++);
1051d38ceaf9SAlex Deucher 	uint32_t dst, src;
1052d38ceaf9SAlex Deucher 	SDEBUG("   src1: ");
1053d38ceaf9SAlex Deucher 	dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
1054d38ceaf9SAlex Deucher 	SDEBUG("   src2: ");
1055d38ceaf9SAlex Deucher 	src = atom_get_src(ctx, attr, ptr);
1056d38ceaf9SAlex Deucher 	ctx->ctx->cs_equal = ((dst & src) == 0);
1057d38ceaf9SAlex Deucher 	SDEBUG("   result: %s\n", ctx->ctx->cs_equal ? "EQ" : "NE");
1058d38ceaf9SAlex Deucher }
1059d38ceaf9SAlex Deucher 
atom_op_xor(atom_exec_context * ctx,int * ptr,int arg)1060d38ceaf9SAlex Deucher static void atom_op_xor(atom_exec_context *ctx, int *ptr, int arg)
1061d38ceaf9SAlex Deucher {
1062d38ceaf9SAlex Deucher 	uint8_t attr = U8((*ptr)++);
1063d38ceaf9SAlex Deucher 	uint32_t dst, src, saved;
1064d38ceaf9SAlex Deucher 	int dptr = *ptr;
1065d38ceaf9SAlex Deucher 	SDEBUG("   dst: ");
1066d38ceaf9SAlex Deucher 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
1067d38ceaf9SAlex Deucher 	SDEBUG("   src: ");
1068d38ceaf9SAlex Deucher 	src = atom_get_src(ctx, attr, ptr);
1069d38ceaf9SAlex Deucher 	dst ^= src;
1070d38ceaf9SAlex Deucher 	SDEBUG("   dst: ");
1071d38ceaf9SAlex Deucher 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
1072d38ceaf9SAlex Deucher }
1073d38ceaf9SAlex Deucher 
atom_op_debug(atom_exec_context * ctx,int * ptr,int arg)1074d38ceaf9SAlex Deucher static void atom_op_debug(atom_exec_context *ctx, int *ptr, int arg)
1075d38ceaf9SAlex Deucher {
1076f76097c0SAlex Deucher 	uint8_t val = U8((*ptr)++);
1077f76097c0SAlex Deucher 	SDEBUG("DEBUG output: 0x%02X\n", val);
1078d38ceaf9SAlex Deucher }
1079d38ceaf9SAlex Deucher 
atom_op_processds(atom_exec_context * ctx,int * ptr,int arg)108055438419SAlex Deucher static void atom_op_processds(atom_exec_context *ctx, int *ptr, int arg)
108155438419SAlex Deucher {
108255438419SAlex Deucher 	uint16_t val = U16(*ptr);
108355438419SAlex Deucher 	(*ptr) += val + 2;
108455438419SAlex Deucher 	SDEBUG("PROCESSDS output: 0x%02X\n", val);
108555438419SAlex Deucher }
108655438419SAlex Deucher 
1087d38ceaf9SAlex Deucher static struct {
1088d38ceaf9SAlex Deucher 	void (*func) (atom_exec_context *, int *, int);
1089d38ceaf9SAlex Deucher 	int arg;
1090d38ceaf9SAlex Deucher } opcode_table[ATOM_OP_CNT] = {
1091d38ceaf9SAlex Deucher 	{
1092d38ceaf9SAlex Deucher 	NULL, 0}, {
1093d38ceaf9SAlex Deucher 	atom_op_move, ATOM_ARG_REG}, {
1094d38ceaf9SAlex Deucher 	atom_op_move, ATOM_ARG_PS}, {
1095d38ceaf9SAlex Deucher 	atom_op_move, ATOM_ARG_WS}, {
1096d38ceaf9SAlex Deucher 	atom_op_move, ATOM_ARG_FB}, {
1097d38ceaf9SAlex Deucher 	atom_op_move, ATOM_ARG_PLL}, {
1098d38ceaf9SAlex Deucher 	atom_op_move, ATOM_ARG_MC}, {
1099d38ceaf9SAlex Deucher 	atom_op_and, ATOM_ARG_REG}, {
1100d38ceaf9SAlex Deucher 	atom_op_and, ATOM_ARG_PS}, {
1101d38ceaf9SAlex Deucher 	atom_op_and, ATOM_ARG_WS}, {
1102d38ceaf9SAlex Deucher 	atom_op_and, ATOM_ARG_FB}, {
1103d38ceaf9SAlex Deucher 	atom_op_and, ATOM_ARG_PLL}, {
1104d38ceaf9SAlex Deucher 	atom_op_and, ATOM_ARG_MC}, {
1105d38ceaf9SAlex Deucher 	atom_op_or, ATOM_ARG_REG}, {
1106d38ceaf9SAlex Deucher 	atom_op_or, ATOM_ARG_PS}, {
1107d38ceaf9SAlex Deucher 	atom_op_or, ATOM_ARG_WS}, {
1108d38ceaf9SAlex Deucher 	atom_op_or, ATOM_ARG_FB}, {
1109d38ceaf9SAlex Deucher 	atom_op_or, ATOM_ARG_PLL}, {
1110d38ceaf9SAlex Deucher 	atom_op_or, ATOM_ARG_MC}, {
1111d38ceaf9SAlex Deucher 	atom_op_shift_left, ATOM_ARG_REG}, {
1112d38ceaf9SAlex Deucher 	atom_op_shift_left, ATOM_ARG_PS}, {
1113d38ceaf9SAlex Deucher 	atom_op_shift_left, ATOM_ARG_WS}, {
1114d38ceaf9SAlex Deucher 	atom_op_shift_left, ATOM_ARG_FB}, {
1115d38ceaf9SAlex Deucher 	atom_op_shift_left, ATOM_ARG_PLL}, {
1116d38ceaf9SAlex Deucher 	atom_op_shift_left, ATOM_ARG_MC}, {
1117d38ceaf9SAlex Deucher 	atom_op_shift_right, ATOM_ARG_REG}, {
1118d38ceaf9SAlex Deucher 	atom_op_shift_right, ATOM_ARG_PS}, {
1119d38ceaf9SAlex Deucher 	atom_op_shift_right, ATOM_ARG_WS}, {
1120d38ceaf9SAlex Deucher 	atom_op_shift_right, ATOM_ARG_FB}, {
1121d38ceaf9SAlex Deucher 	atom_op_shift_right, ATOM_ARG_PLL}, {
1122d38ceaf9SAlex Deucher 	atom_op_shift_right, ATOM_ARG_MC}, {
1123d38ceaf9SAlex Deucher 	atom_op_mul, ATOM_ARG_REG}, {
1124d38ceaf9SAlex Deucher 	atom_op_mul, ATOM_ARG_PS}, {
1125d38ceaf9SAlex Deucher 	atom_op_mul, ATOM_ARG_WS}, {
1126d38ceaf9SAlex Deucher 	atom_op_mul, ATOM_ARG_FB}, {
1127d38ceaf9SAlex Deucher 	atom_op_mul, ATOM_ARG_PLL}, {
1128d38ceaf9SAlex Deucher 	atom_op_mul, ATOM_ARG_MC}, {
1129d38ceaf9SAlex Deucher 	atom_op_div, ATOM_ARG_REG}, {
1130d38ceaf9SAlex Deucher 	atom_op_div, ATOM_ARG_PS}, {
1131d38ceaf9SAlex Deucher 	atom_op_div, ATOM_ARG_WS}, {
1132d38ceaf9SAlex Deucher 	atom_op_div, ATOM_ARG_FB}, {
1133d38ceaf9SAlex Deucher 	atom_op_div, ATOM_ARG_PLL}, {
1134d38ceaf9SAlex Deucher 	atom_op_div, ATOM_ARG_MC}, {
1135d38ceaf9SAlex Deucher 	atom_op_add, ATOM_ARG_REG}, {
1136d38ceaf9SAlex Deucher 	atom_op_add, ATOM_ARG_PS}, {
1137d38ceaf9SAlex Deucher 	atom_op_add, ATOM_ARG_WS}, {
1138d38ceaf9SAlex Deucher 	atom_op_add, ATOM_ARG_FB}, {
1139d38ceaf9SAlex Deucher 	atom_op_add, ATOM_ARG_PLL}, {
1140d38ceaf9SAlex Deucher 	atom_op_add, ATOM_ARG_MC}, {
1141d38ceaf9SAlex Deucher 	atom_op_sub, ATOM_ARG_REG}, {
1142d38ceaf9SAlex Deucher 	atom_op_sub, ATOM_ARG_PS}, {
1143d38ceaf9SAlex Deucher 	atom_op_sub, ATOM_ARG_WS}, {
1144d38ceaf9SAlex Deucher 	atom_op_sub, ATOM_ARG_FB}, {
1145d38ceaf9SAlex Deucher 	atom_op_sub, ATOM_ARG_PLL}, {
1146d38ceaf9SAlex Deucher 	atom_op_sub, ATOM_ARG_MC}, {
1147d38ceaf9SAlex Deucher 	atom_op_setport, ATOM_PORT_ATI}, {
1148d38ceaf9SAlex Deucher 	atom_op_setport, ATOM_PORT_PCI}, {
1149d38ceaf9SAlex Deucher 	atom_op_setport, ATOM_PORT_SYSIO}, {
1150d38ceaf9SAlex Deucher 	atom_op_setregblock, 0}, {
1151d38ceaf9SAlex Deucher 	atom_op_setfbbase, 0}, {
1152d38ceaf9SAlex Deucher 	atom_op_compare, ATOM_ARG_REG}, {
1153d38ceaf9SAlex Deucher 	atom_op_compare, ATOM_ARG_PS}, {
1154d38ceaf9SAlex Deucher 	atom_op_compare, ATOM_ARG_WS}, {
1155d38ceaf9SAlex Deucher 	atom_op_compare, ATOM_ARG_FB}, {
1156d38ceaf9SAlex Deucher 	atom_op_compare, ATOM_ARG_PLL}, {
1157d38ceaf9SAlex Deucher 	atom_op_compare, ATOM_ARG_MC}, {
1158d38ceaf9SAlex Deucher 	atom_op_switch, 0}, {
1159d38ceaf9SAlex Deucher 	atom_op_jump, ATOM_COND_ALWAYS}, {
1160d38ceaf9SAlex Deucher 	atom_op_jump, ATOM_COND_EQUAL}, {
1161d38ceaf9SAlex Deucher 	atom_op_jump, ATOM_COND_BELOW}, {
1162d38ceaf9SAlex Deucher 	atom_op_jump, ATOM_COND_ABOVE}, {
1163d38ceaf9SAlex Deucher 	atom_op_jump, ATOM_COND_BELOWOREQUAL}, {
1164d38ceaf9SAlex Deucher 	atom_op_jump, ATOM_COND_ABOVEOREQUAL}, {
1165d38ceaf9SAlex Deucher 	atom_op_jump, ATOM_COND_NOTEQUAL}, {
1166d38ceaf9SAlex Deucher 	atom_op_test, ATOM_ARG_REG}, {
1167d38ceaf9SAlex Deucher 	atom_op_test, ATOM_ARG_PS}, {
1168d38ceaf9SAlex Deucher 	atom_op_test, ATOM_ARG_WS}, {
1169d38ceaf9SAlex Deucher 	atom_op_test, ATOM_ARG_FB}, {
1170d38ceaf9SAlex Deucher 	atom_op_test, ATOM_ARG_PLL}, {
1171d38ceaf9SAlex Deucher 	atom_op_test, ATOM_ARG_MC}, {
1172d38ceaf9SAlex Deucher 	atom_op_delay, ATOM_UNIT_MILLISEC}, {
1173d38ceaf9SAlex Deucher 	atom_op_delay, ATOM_UNIT_MICROSEC}, {
1174d38ceaf9SAlex Deucher 	atom_op_calltable, 0}, {
1175d38ceaf9SAlex Deucher 	atom_op_repeat, 0}, {
1176d38ceaf9SAlex Deucher 	atom_op_clear, ATOM_ARG_REG}, {
1177d38ceaf9SAlex Deucher 	atom_op_clear, ATOM_ARG_PS}, {
1178d38ceaf9SAlex Deucher 	atom_op_clear, ATOM_ARG_WS}, {
1179d38ceaf9SAlex Deucher 	atom_op_clear, ATOM_ARG_FB}, {
1180d38ceaf9SAlex Deucher 	atom_op_clear, ATOM_ARG_PLL}, {
1181d38ceaf9SAlex Deucher 	atom_op_clear, ATOM_ARG_MC}, {
1182d38ceaf9SAlex Deucher 	atom_op_nop, 0}, {
1183d38ceaf9SAlex Deucher 	atom_op_eot, 0}, {
1184d38ceaf9SAlex Deucher 	atom_op_mask, ATOM_ARG_REG}, {
1185d38ceaf9SAlex Deucher 	atom_op_mask, ATOM_ARG_PS}, {
1186d38ceaf9SAlex Deucher 	atom_op_mask, ATOM_ARG_WS}, {
1187d38ceaf9SAlex Deucher 	atom_op_mask, ATOM_ARG_FB}, {
1188d38ceaf9SAlex Deucher 	atom_op_mask, ATOM_ARG_PLL}, {
1189d38ceaf9SAlex Deucher 	atom_op_mask, ATOM_ARG_MC}, {
1190d38ceaf9SAlex Deucher 	atom_op_postcard, 0}, {
1191d38ceaf9SAlex Deucher 	atom_op_beep, 0}, {
1192d38ceaf9SAlex Deucher 	atom_op_savereg, 0}, {
1193d38ceaf9SAlex Deucher 	atom_op_restorereg, 0}, {
1194d38ceaf9SAlex Deucher 	atom_op_setdatablock, 0}, {
1195d38ceaf9SAlex Deucher 	atom_op_xor, ATOM_ARG_REG}, {
1196d38ceaf9SAlex Deucher 	atom_op_xor, ATOM_ARG_PS}, {
1197d38ceaf9SAlex Deucher 	atom_op_xor, ATOM_ARG_WS}, {
1198d38ceaf9SAlex Deucher 	atom_op_xor, ATOM_ARG_FB}, {
1199d38ceaf9SAlex Deucher 	atom_op_xor, ATOM_ARG_PLL}, {
1200d38ceaf9SAlex Deucher 	atom_op_xor, ATOM_ARG_MC}, {
1201d38ceaf9SAlex Deucher 	atom_op_shl, ATOM_ARG_REG}, {
1202d38ceaf9SAlex Deucher 	atom_op_shl, ATOM_ARG_PS}, {
1203d38ceaf9SAlex Deucher 	atom_op_shl, ATOM_ARG_WS}, {
1204d38ceaf9SAlex Deucher 	atom_op_shl, ATOM_ARG_FB}, {
1205d38ceaf9SAlex Deucher 	atom_op_shl, ATOM_ARG_PLL}, {
1206d38ceaf9SAlex Deucher 	atom_op_shl, ATOM_ARG_MC}, {
1207d38ceaf9SAlex Deucher 	atom_op_shr, ATOM_ARG_REG}, {
1208d38ceaf9SAlex Deucher 	atom_op_shr, ATOM_ARG_PS}, {
1209d38ceaf9SAlex Deucher 	atom_op_shr, ATOM_ARG_WS}, {
1210d38ceaf9SAlex Deucher 	atom_op_shr, ATOM_ARG_FB}, {
1211d38ceaf9SAlex Deucher 	atom_op_shr, ATOM_ARG_PLL}, {
1212d38ceaf9SAlex Deucher 	atom_op_shr, ATOM_ARG_MC}, {
121355438419SAlex Deucher 	atom_op_debug, 0}, {
1214c9c14502SAlex Deucher 	atom_op_processds, 0}, {
1215c9c14502SAlex Deucher 	atom_op_mul32, ATOM_ARG_PS}, {
1216c2fe16aaSAlex Deucher 	atom_op_mul32, ATOM_ARG_WS}, {
1217c2fe16aaSAlex Deucher 	atom_op_div32, ATOM_ARG_PS}, {
1218c2fe16aaSAlex Deucher 	atom_op_div32, ATOM_ARG_WS},
121955438419SAlex Deucher };
1220d38ceaf9SAlex Deucher 
amdgpu_atom_execute_table_locked(struct atom_context * ctx,int index,uint32_t * params,int params_size)12214630d503SAlexander Richards static int amdgpu_atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t *params, int params_size)
1222d38ceaf9SAlex Deucher {
1223d38ceaf9SAlex Deucher 	int base = CU16(ctx->cmd_table + 4 + 2 * index);
1224d38ceaf9SAlex Deucher 	int len, ws, ps, ptr;
1225d38ceaf9SAlex Deucher 	unsigned char op;
1226d38ceaf9SAlex Deucher 	atom_exec_context ectx;
1227d38ceaf9SAlex Deucher 	int ret = 0;
1228d38ceaf9SAlex Deucher 
1229d38ceaf9SAlex Deucher 	if (!base)
1230d38ceaf9SAlex Deucher 		return -EINVAL;
1231d38ceaf9SAlex Deucher 
1232d38ceaf9SAlex Deucher 	len = CU16(base + ATOM_CT_SIZE_PTR);
1233d38ceaf9SAlex Deucher 	ws = CU8(base + ATOM_CT_WS_PTR);
1234d38ceaf9SAlex Deucher 	ps = CU8(base + ATOM_CT_PS_PTR) & ATOM_CT_PS_MASK;
1235d38ceaf9SAlex Deucher 	ptr = base + ATOM_CT_CODE_PTR;
1236d38ceaf9SAlex Deucher 
1237d38ceaf9SAlex Deucher 	SDEBUG(">> execute %04X (len %d, WS %d, PS %d)\n", base, len, ws, ps);
1238d38ceaf9SAlex Deucher 
1239d38ceaf9SAlex Deucher 	ectx.ctx = ctx;
1240d38ceaf9SAlex Deucher 	ectx.ps_shift = ps / 4;
1241d38ceaf9SAlex Deucher 	ectx.start = base;
1242d38ceaf9SAlex Deucher 	ectx.ps = params;
12434630d503SAlexander Richards 	ectx.ps_size = params_size;
1244d38ceaf9SAlex Deucher 	ectx.abort = false;
1245d38ceaf9SAlex Deucher 	ectx.last_jump = 0;
12467bfd16d0SJesse Zhang 	ectx.last_jump_jiffies = 0;
12474630d503SAlexander Richards 	if (ws) {
12486396bb22SKees Cook 		ectx.ws = kcalloc(4, ws, GFP_KERNEL);
12494630d503SAlexander Richards 		ectx.ws_size = ws;
12504630d503SAlexander Richards 	} else {
1251d38ceaf9SAlex Deucher 		ectx.ws = NULL;
12524630d503SAlexander Richards 		ectx.ws_size = 0;
12534630d503SAlexander Richards 	}
1254d38ceaf9SAlex Deucher 
1255d38ceaf9SAlex Deucher 	debug_depth++;
1256d38ceaf9SAlex Deucher 	while (1) {
1257d38ceaf9SAlex Deucher 		op = CU8(ptr++);
1258d38ceaf9SAlex Deucher 		if (op < ATOM_OP_NAMES_CNT)
1259d38ceaf9SAlex Deucher 			SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr - 1);
1260d38ceaf9SAlex Deucher 		else
1261d38ceaf9SAlex Deucher 			SDEBUG("[%d] @ 0x%04X\n", op, ptr - 1);
1262d38ceaf9SAlex Deucher 		if (ectx.abort) {
1263d38ceaf9SAlex Deucher 			DRM_ERROR("atombios stuck executing %04X (len %d, WS %d, PS %d) @ 0x%04X\n",
1264d38ceaf9SAlex Deucher 				base, len, ws, ps, ptr - 1);
1265d38ceaf9SAlex Deucher 			ret = -EINVAL;
1266d38ceaf9SAlex Deucher 			goto free;
1267d38ceaf9SAlex Deucher 		}
1268d38ceaf9SAlex Deucher 
1269d38ceaf9SAlex Deucher 		if (op < ATOM_OP_CNT && op > 0)
1270d38ceaf9SAlex Deucher 			opcode_table[op].func(&ectx, &ptr,
1271d38ceaf9SAlex Deucher 					      opcode_table[op].arg);
1272d38ceaf9SAlex Deucher 		else
1273d38ceaf9SAlex Deucher 			break;
1274d38ceaf9SAlex Deucher 
1275d38ceaf9SAlex Deucher 		if (op == ATOM_OP_EOT)
1276d38ceaf9SAlex Deucher 			break;
1277d38ceaf9SAlex Deucher 	}
1278d38ceaf9SAlex Deucher 	debug_depth--;
1279d38ceaf9SAlex Deucher 	SDEBUG("<<\n");
1280d38ceaf9SAlex Deucher 
1281d38ceaf9SAlex Deucher free:
1282d38ceaf9SAlex Deucher 	if (ws)
1283d38ceaf9SAlex Deucher 		kfree(ectx.ws);
1284d38ceaf9SAlex Deucher 	return ret;
1285d38ceaf9SAlex Deucher }
1286d38ceaf9SAlex Deucher 
amdgpu_atom_execute_table(struct atom_context * ctx,int index,uint32_t * params,int params_size)12874630d503SAlexander Richards int amdgpu_atom_execute_table(struct atom_context *ctx, int index, uint32_t *params, int params_size)
1288d38ceaf9SAlex Deucher {
1289d38ceaf9SAlex Deucher 	int r;
1290d38ceaf9SAlex Deucher 
1291d38ceaf9SAlex Deucher 	mutex_lock(&ctx->mutex);
1292d38ceaf9SAlex Deucher 	/* reset data block */
1293d38ceaf9SAlex Deucher 	ctx->data_block = 0;
1294d38ceaf9SAlex Deucher 	/* reset reg block */
1295d38ceaf9SAlex Deucher 	ctx->reg_block = 0;
1296d38ceaf9SAlex Deucher 	/* reset fb window */
1297d38ceaf9SAlex Deucher 	ctx->fb_base = 0;
1298d38ceaf9SAlex Deucher 	/* reset io mode */
1299d38ceaf9SAlex Deucher 	ctx->io_mode = ATOM_IO_MM;
1300d38ceaf9SAlex Deucher 	/* reset divmul */
1301d38ceaf9SAlex Deucher 	ctx->divmul[0] = 0;
1302d38ceaf9SAlex Deucher 	ctx->divmul[1] = 0;
13034630d503SAlexander Richards 	r = amdgpu_atom_execute_table_locked(ctx, index, params, params_size);
1304d38ceaf9SAlex Deucher 	mutex_unlock(&ctx->mutex);
1305d38ceaf9SAlex Deucher 	return r;
1306d38ceaf9SAlex Deucher }
1307d38ceaf9SAlex Deucher 
1308d38ceaf9SAlex Deucher static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 };
1309d38ceaf9SAlex Deucher 
atom_index_iio(struct atom_context * ctx,int base)1310d38ceaf9SAlex Deucher static void atom_index_iio(struct atom_context *ctx, int base)
1311d38ceaf9SAlex Deucher {
1312d38ceaf9SAlex Deucher 	ctx->iio = kzalloc(2 * 256, GFP_KERNEL);
1313d38ceaf9SAlex Deucher 	if (!ctx->iio)
1314d38ceaf9SAlex Deucher 		return;
1315d38ceaf9SAlex Deucher 	while (CU8(base) == ATOM_IIO_START) {
1316d38ceaf9SAlex Deucher 		ctx->iio[CU8(base + 1)] = base + 2;
1317d38ceaf9SAlex Deucher 		base += 2;
1318d38ceaf9SAlex Deucher 		while (CU8(base) != ATOM_IIO_END)
1319d38ceaf9SAlex Deucher 			base += atom_iio_len[CU8(base)];
1320d38ceaf9SAlex Deucher 		base += 3;
1321d38ceaf9SAlex Deucher 	}
1322d38ceaf9SAlex Deucher }
1323d38ceaf9SAlex Deucher 
atom_get_vbios_name(struct atom_context * ctx)132429b4c589SJiawei Gu static void atom_get_vbios_name(struct atom_context *ctx)
132529b4c589SJiawei Gu {
132629b4c589SJiawei Gu 	unsigned char *p_rom;
132729b4c589SJiawei Gu 	unsigned char str_num;
132829b4c589SJiawei Gu 	unsigned short off_to_vbios_str;
132929b4c589SJiawei Gu 	unsigned char *c_ptr;
133029b4c589SJiawei Gu 	int name_size;
133129b4c589SJiawei Gu 	int i;
133229b4c589SJiawei Gu 
133329b4c589SJiawei Gu 	const char *na = "--N/A--";
133429b4c589SJiawei Gu 	char *back;
133529b4c589SJiawei Gu 
133629b4c589SJiawei Gu 	p_rom = ctx->bios;
133729b4c589SJiawei Gu 
133829b4c589SJiawei Gu 	str_num = *(p_rom + OFFSET_TO_GET_ATOMBIOS_NUMBER_OF_STRINGS);
133929b4c589SJiawei Gu 	if (str_num != 0) {
134029b4c589SJiawei Gu 		off_to_vbios_str =
134129b4c589SJiawei Gu 			*(unsigned short *)(p_rom + OFFSET_TO_GET_ATOMBIOS_STRING_START);
134229b4c589SJiawei Gu 
134329b4c589SJiawei Gu 		c_ptr = (unsigned char *)(p_rom + off_to_vbios_str);
134429b4c589SJiawei Gu 	} else {
134529b4c589SJiawei Gu 		/* do not know where to find name */
134629b4c589SJiawei Gu 		memcpy(ctx->name, na, 7);
134729b4c589SJiawei Gu 		ctx->name[7] = 0;
134829b4c589SJiawei Gu 		return;
134929b4c589SJiawei Gu 	}
135029b4c589SJiawei Gu 
135129b4c589SJiawei Gu 	/*
135229b4c589SJiawei Gu 	 * skip the atombios strings, usually 4
135329b4c589SJiawei Gu 	 * 1st is P/N, 2nd is ASIC, 3rd is PCI type, 4th is Memory type
135429b4c589SJiawei Gu 	 */
135529b4c589SJiawei Gu 	for (i = 0; i < str_num; i++) {
135629b4c589SJiawei Gu 		while (*c_ptr != 0)
135729b4c589SJiawei Gu 			c_ptr++;
135829b4c589SJiawei Gu 		c_ptr++;
135929b4c589SJiawei Gu 	}
136029b4c589SJiawei Gu 
136129b4c589SJiawei Gu 	/* skip the following 2 chars: 0x0D 0x0A */
136229b4c589SJiawei Gu 	c_ptr += 2;
136329b4c589SJiawei Gu 
136429b4c589SJiawei Gu 	name_size = strnlen(c_ptr, STRLEN_LONG - 1);
136529b4c589SJiawei Gu 	memcpy(ctx->name, c_ptr, name_size);
136629b4c589SJiawei Gu 	back = ctx->name + name_size;
136729b4c589SJiawei Gu 	while ((*--back) == ' ')
136829b4c589SJiawei Gu 		;
136929b4c589SJiawei Gu 	*(back + 1) = '\0';
137029b4c589SJiawei Gu }
137129b4c589SJiawei Gu 
atom_get_vbios_date(struct atom_context * ctx)137229b4c589SJiawei Gu static void atom_get_vbios_date(struct atom_context *ctx)
137329b4c589SJiawei Gu {
137429b4c589SJiawei Gu 	unsigned char *p_rom;
137529b4c589SJiawei Gu 	unsigned char *date_in_rom;
137629b4c589SJiawei Gu 
137729b4c589SJiawei Gu 	p_rom = ctx->bios;
137829b4c589SJiawei Gu 
137929b4c589SJiawei Gu 	date_in_rom = p_rom + OFFSET_TO_VBIOS_DATE;
138029b4c589SJiawei Gu 
138129b4c589SJiawei Gu 	ctx->date[0] = '2';
138229b4c589SJiawei Gu 	ctx->date[1] = '0';
138329b4c589SJiawei Gu 	ctx->date[2] = date_in_rom[6];
138429b4c589SJiawei Gu 	ctx->date[3] = date_in_rom[7];
138529b4c589SJiawei Gu 	ctx->date[4] = '/';
138629b4c589SJiawei Gu 	ctx->date[5] = date_in_rom[0];
138729b4c589SJiawei Gu 	ctx->date[6] = date_in_rom[1];
138829b4c589SJiawei Gu 	ctx->date[7] = '/';
138929b4c589SJiawei Gu 	ctx->date[8] = date_in_rom[3];
139029b4c589SJiawei Gu 	ctx->date[9] = date_in_rom[4];
139129b4c589SJiawei Gu 	ctx->date[10] = ' ';
139229b4c589SJiawei Gu 	ctx->date[11] = date_in_rom[9];
139329b4c589SJiawei Gu 	ctx->date[12] = date_in_rom[10];
139429b4c589SJiawei Gu 	ctx->date[13] = date_in_rom[11];
139529b4c589SJiawei Gu 	ctx->date[14] = date_in_rom[12];
139629b4c589SJiawei Gu 	ctx->date[15] = date_in_rom[13];
139729b4c589SJiawei Gu 	ctx->date[16] = '\0';
139829b4c589SJiawei Gu }
139929b4c589SJiawei Gu 
atom_find_str_in_rom(struct atom_context * ctx,char * str,int start,int end,int maxlen)140029b4c589SJiawei Gu static unsigned char *atom_find_str_in_rom(struct atom_context *ctx, char *str, int start,
140129b4c589SJiawei Gu 					   int end, int maxlen)
140229b4c589SJiawei Gu {
140329b4c589SJiawei Gu 	unsigned long str_off;
140429b4c589SJiawei Gu 	unsigned char *p_rom;
140529b4c589SJiawei Gu 	unsigned short str_len;
140629b4c589SJiawei Gu 
140729b4c589SJiawei Gu 	str_off = 0;
140829b4c589SJiawei Gu 	str_len = strnlen(str, maxlen);
140929b4c589SJiawei Gu 	p_rom = ctx->bios;
141029b4c589SJiawei Gu 
141129b4c589SJiawei Gu 	for (; start <= end; ++start) {
141229b4c589SJiawei Gu 		for (str_off = 0; str_off < str_len; ++str_off) {
141329b4c589SJiawei Gu 			if (str[str_off] != *(p_rom + start + str_off))
141429b4c589SJiawei Gu 				break;
141529b4c589SJiawei Gu 		}
141629b4c589SJiawei Gu 
141729b4c589SJiawei Gu 		if (str_off == str_len || str[str_off] == 0)
141829b4c589SJiawei Gu 			return p_rom + start;
141929b4c589SJiawei Gu 	}
142029b4c589SJiawei Gu 	return NULL;
142129b4c589SJiawei Gu }
142229b4c589SJiawei Gu 
atom_get_vbios_pn(struct atom_context * ctx)142329b4c589SJiawei Gu static void atom_get_vbios_pn(struct atom_context *ctx)
142429b4c589SJiawei Gu {
142529b4c589SJiawei Gu 	unsigned char *p_rom;
142629b4c589SJiawei Gu 	unsigned short off_to_vbios_str;
142729b4c589SJiawei Gu 	unsigned char *vbios_str;
142829b4c589SJiawei Gu 	int count;
142929b4c589SJiawei Gu 
143029b4c589SJiawei Gu 	off_to_vbios_str = 0;
143129b4c589SJiawei Gu 	p_rom = ctx->bios;
143229b4c589SJiawei Gu 
143329b4c589SJiawei Gu 	if (*(p_rom + OFFSET_TO_GET_ATOMBIOS_NUMBER_OF_STRINGS) != 0) {
143429b4c589SJiawei Gu 		off_to_vbios_str =
143529b4c589SJiawei Gu 			*(unsigned short *)(p_rom + OFFSET_TO_GET_ATOMBIOS_STRING_START);
143629b4c589SJiawei Gu 
143729b4c589SJiawei Gu 		vbios_str = (unsigned char *)(p_rom + off_to_vbios_str);
143829b4c589SJiawei Gu 	} else {
143929b4c589SJiawei Gu 		vbios_str = p_rom + OFFSET_TO_VBIOS_PART_NUMBER;
144029b4c589SJiawei Gu 	}
144129b4c589SJiawei Gu 
144229b4c589SJiawei Gu 	if (*vbios_str == 0) {
144329b4c589SJiawei Gu 		vbios_str = atom_find_str_in_rom(ctx, BIOS_ATOM_PREFIX, 3, 1024, 64);
144429b4c589SJiawei Gu 		if (vbios_str == NULL)
144529b4c589SJiawei Gu 			vbios_str += sizeof(BIOS_ATOM_PREFIX) - 1;
144629b4c589SJiawei Gu 	}
144729b4c589SJiawei Gu 	if (vbios_str != NULL && *vbios_str == 0)
144829b4c589SJiawei Gu 		vbios_str++;
144929b4c589SJiawei Gu 
145029b4c589SJiawei Gu 	if (vbios_str != NULL) {
145129b4c589SJiawei Gu 		count = 0;
145229b4c589SJiawei Gu 		while ((count < BIOS_STRING_LENGTH) && vbios_str[count] >= ' ' &&
145329b4c589SJiawei Gu 		       vbios_str[count] <= 'z') {
145429b4c589SJiawei Gu 			ctx->vbios_pn[count] = vbios_str[count];
145529b4c589SJiawei Gu 			count++;
145629b4c589SJiawei Gu 		}
145729b4c589SJiawei Gu 
145829b4c589SJiawei Gu 		ctx->vbios_pn[count] = 0;
145929b4c589SJiawei Gu 	}
1460adf64e21SMario Limonciello 
1461adf64e21SMario Limonciello 	pr_info("ATOM BIOS: %s\n", ctx->vbios_pn);
146229b4c589SJiawei Gu }
146329b4c589SJiawei Gu 
atom_get_vbios_version(struct atom_context * ctx)146429b4c589SJiawei Gu static void atom_get_vbios_version(struct atom_context *ctx)
146529b4c589SJiawei Gu {
146624f60ddcSLijo Lazar 	unsigned short start = 3, end;
146729b4c589SJiawei Gu 	unsigned char *vbios_ver;
146824f60ddcSLijo Lazar 	unsigned char *p_rom;
146924f60ddcSLijo Lazar 
147024f60ddcSLijo Lazar 	p_rom = ctx->bios;
147124f60ddcSLijo Lazar 	/* Search from strings offset if it's present */
147224f60ddcSLijo Lazar 	start = *(unsigned short *)(p_rom +
147324f60ddcSLijo Lazar 				    OFFSET_TO_GET_ATOMBIOS_STRING_START);
147424f60ddcSLijo Lazar 
147524f60ddcSLijo Lazar 	/* Search till atom rom header start point */
147624f60ddcSLijo Lazar 	end = *(unsigned short *)(p_rom + OFFSET_TO_ATOM_ROM_HEADER_POINTER);
147724f60ddcSLijo Lazar 
147824f60ddcSLijo Lazar 	/* Use hardcoded offsets, if the offsets are not populated */
147924f60ddcSLijo Lazar 	if (end <= start) {
148024f60ddcSLijo Lazar 		start = 3;
148124f60ddcSLijo Lazar 		end = 1024;
148224f60ddcSLijo Lazar 	}
148329b4c589SJiawei Gu 
148429b4c589SJiawei Gu 	/* find anchor ATOMBIOSBK-AMD */
148524f60ddcSLijo Lazar 	vbios_ver =
148624f60ddcSLijo Lazar 		atom_find_str_in_rom(ctx, BIOS_VERSION_PREFIX, start, end, 64);
148729b4c589SJiawei Gu 	if (vbios_ver != NULL) {
148829b4c589SJiawei Gu 		/* skip ATOMBIOSBK-AMD VER */
148929b4c589SJiawei Gu 		vbios_ver += 18;
149029b4c589SJiawei Gu 		memcpy(ctx->vbios_ver_str, vbios_ver, STRLEN_NORMAL);
149129b4c589SJiawei Gu 	} else {
149229b4c589SJiawei Gu 		ctx->vbios_ver_str[0] = '\0';
149329b4c589SJiawei Gu 	}
149429b4c589SJiawei Gu }
149529b4c589SJiawei Gu 
amdgpu_atom_parse(struct card_info * card,void * bios)1496d38ceaf9SAlex Deucher struct atom_context *amdgpu_atom_parse(struct card_info *card, void *bios)
1497d38ceaf9SAlex Deucher {
1498d38ceaf9SAlex Deucher 	int base;
1499d38ceaf9SAlex Deucher 	struct atom_context *ctx =
1500d38ceaf9SAlex Deucher 	    kzalloc(sizeof(struct atom_context), GFP_KERNEL);
150129b4c589SJiawei Gu 	struct _ATOM_ROM_HEADER *atom_rom_header;
150229b4c589SJiawei Gu 	struct _ATOM_MASTER_DATA_TABLE *master_table;
150329b4c589SJiawei Gu 	struct _ATOM_FIRMWARE_INFO *atom_fw_info;
1504d38ceaf9SAlex Deucher 
1505d38ceaf9SAlex Deucher 	if (!ctx)
1506d38ceaf9SAlex Deucher 		return NULL;
1507d38ceaf9SAlex Deucher 
1508d38ceaf9SAlex Deucher 	ctx->card = card;
1509d38ceaf9SAlex Deucher 	ctx->bios = bios;
1510d38ceaf9SAlex Deucher 
1511d38ceaf9SAlex Deucher 	if (CU16(0) != ATOM_BIOS_MAGIC) {
15127ca85295SJoe Perches 		pr_info("Invalid BIOS magic\n");
1513d38ceaf9SAlex Deucher 		kfree(ctx);
1514d38ceaf9SAlex Deucher 		return NULL;
1515d38ceaf9SAlex Deucher 	}
1516d38ceaf9SAlex Deucher 	if (strncmp
1517d38ceaf9SAlex Deucher 	    (CSTR(ATOM_ATI_MAGIC_PTR), ATOM_ATI_MAGIC,
1518d38ceaf9SAlex Deucher 	     strlen(ATOM_ATI_MAGIC))) {
15197ca85295SJoe Perches 		pr_info("Invalid ATI magic\n");
1520d38ceaf9SAlex Deucher 		kfree(ctx);
1521d38ceaf9SAlex Deucher 		return NULL;
1522d38ceaf9SAlex Deucher 	}
1523d38ceaf9SAlex Deucher 
1524d38ceaf9SAlex Deucher 	base = CU16(ATOM_ROM_TABLE_PTR);
1525d38ceaf9SAlex Deucher 	if (strncmp
1526d38ceaf9SAlex Deucher 	    (CSTR(base + ATOM_ROM_MAGIC_PTR), ATOM_ROM_MAGIC,
1527d38ceaf9SAlex Deucher 	     strlen(ATOM_ROM_MAGIC))) {
15287ca85295SJoe Perches 		pr_info("Invalid ATOM magic\n");
1529d38ceaf9SAlex Deucher 		kfree(ctx);
1530d38ceaf9SAlex Deucher 		return NULL;
1531d38ceaf9SAlex Deucher 	}
1532d38ceaf9SAlex Deucher 
1533d38ceaf9SAlex Deucher 	ctx->cmd_table = CU16(base + ATOM_ROM_CMD_PTR);
1534d38ceaf9SAlex Deucher 	ctx->data_table = CU16(base + ATOM_ROM_DATA_PTR);
1535d38ceaf9SAlex Deucher 	atom_index_iio(ctx, CU16(ctx->data_table + ATOM_DATA_IIO_PTR) + 4);
1536d38ceaf9SAlex Deucher 	if (!ctx->iio) {
1537d38ceaf9SAlex Deucher 		amdgpu_atom_destroy(ctx);
1538d38ceaf9SAlex Deucher 		return NULL;
1539d38ceaf9SAlex Deucher 	}
1540d38ceaf9SAlex Deucher 
154129b4c589SJiawei Gu 	atom_rom_header = (struct _ATOM_ROM_HEADER *)CSTR(base);
154229b4c589SJiawei Gu 	if (atom_rom_header->usMasterDataTableOffset != 0) {
154329b4c589SJiawei Gu 		master_table = (struct _ATOM_MASTER_DATA_TABLE *)
154429b4c589SJiawei Gu 				CSTR(atom_rom_header->usMasterDataTableOffset);
154529b4c589SJiawei Gu 		if (master_table->ListOfDataTables.FirmwareInfo != 0) {
154629b4c589SJiawei Gu 			atom_fw_info = (struct _ATOM_FIRMWARE_INFO *)
154729b4c589SJiawei Gu 					CSTR(master_table->ListOfDataTables.FirmwareInfo);
154829b4c589SJiawei Gu 			ctx->version = atom_fw_info->ulFirmwareRevision;
154929b4c589SJiawei Gu 		}
155029b4c589SJiawei Gu 	}
155129b4c589SJiawei Gu 
155229b4c589SJiawei Gu 	atom_get_vbios_name(ctx);
155329b4c589SJiawei Gu 	atom_get_vbios_pn(ctx);
155429b4c589SJiawei Gu 	atom_get_vbios_date(ctx);
155529b4c589SJiawei Gu 	atom_get_vbios_version(ctx);
1556d38ceaf9SAlex Deucher 
1557d38ceaf9SAlex Deucher 	return ctx;
1558d38ceaf9SAlex Deucher }
1559d38ceaf9SAlex Deucher 
amdgpu_atom_asic_init(struct atom_context * ctx)1560d38ceaf9SAlex Deucher int amdgpu_atom_asic_init(struct atom_context *ctx)
1561d38ceaf9SAlex Deucher {
1562d38ceaf9SAlex Deucher 	int hwi = CU16(ctx->data_table + ATOM_DATA_FWI_PTR);
1563d38ceaf9SAlex Deucher 	uint32_t ps[16];
1564d38ceaf9SAlex Deucher 	int ret;
1565d38ceaf9SAlex Deucher 
1566d38ceaf9SAlex Deucher 	memset(ps, 0, 64);
1567d38ceaf9SAlex Deucher 
1568d38ceaf9SAlex Deucher 	ps[0] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFSCLK_PTR));
1569d38ceaf9SAlex Deucher 	ps[1] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFMCLK_PTR));
1570d38ceaf9SAlex Deucher 	if (!ps[0] || !ps[1])
1571d38ceaf9SAlex Deucher 		return 1;
1572d38ceaf9SAlex Deucher 
1573d38ceaf9SAlex Deucher 	if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT))
1574d38ceaf9SAlex Deucher 		return 1;
15754630d503SAlexander Richards 	ret = amdgpu_atom_execute_table(ctx, ATOM_CMD_INIT, ps, 16);
1576d38ceaf9SAlex Deucher 	if (ret)
1577d38ceaf9SAlex Deucher 		return ret;
1578d38ceaf9SAlex Deucher 
1579d38ceaf9SAlex Deucher 	memset(ps, 0, 64);
1580d38ceaf9SAlex Deucher 
1581d38ceaf9SAlex Deucher 	return ret;
1582d38ceaf9SAlex Deucher }
1583d38ceaf9SAlex Deucher 
amdgpu_atom_destroy(struct atom_context * ctx)1584d38ceaf9SAlex Deucher void amdgpu_atom_destroy(struct atom_context *ctx)
1585d38ceaf9SAlex Deucher {
1586d38ceaf9SAlex Deucher 	kfree(ctx->iio);
1587d38ceaf9SAlex Deucher 	kfree(ctx);
1588d38ceaf9SAlex Deucher }
1589d38ceaf9SAlex 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)1590d38ceaf9SAlex Deucher bool amdgpu_atom_parse_data_header(struct atom_context *ctx, int index,
1591d38ceaf9SAlex Deucher 			    uint16_t *size, uint8_t *frev, uint8_t *crev,
1592d38ceaf9SAlex Deucher 			    uint16_t *data_start)
1593d38ceaf9SAlex Deucher {
1594d38ceaf9SAlex Deucher 	int offset = index * 2 + 4;
1595d38ceaf9SAlex Deucher 	int idx = CU16(ctx->data_table + offset);
1596d38ceaf9SAlex Deucher 	u16 *mdt = (u16 *)(ctx->bios + ctx->data_table + 4);
1597d38ceaf9SAlex Deucher 
1598d38ceaf9SAlex Deucher 	if (!mdt[index])
1599d38ceaf9SAlex Deucher 		return false;
1600d38ceaf9SAlex Deucher 
1601d38ceaf9SAlex Deucher 	if (size)
1602d38ceaf9SAlex Deucher 		*size = CU16(idx);
1603d38ceaf9SAlex Deucher 	if (frev)
1604d38ceaf9SAlex Deucher 		*frev = CU8(idx + 2);
1605d38ceaf9SAlex Deucher 	if (crev)
1606d38ceaf9SAlex Deucher 		*crev = CU8(idx + 3);
1607d38ceaf9SAlex Deucher 	*data_start = idx;
1608d38ceaf9SAlex Deucher 	return true;
1609d38ceaf9SAlex Deucher }
1610d38ceaf9SAlex Deucher 
amdgpu_atom_parse_cmd_header(struct atom_context * ctx,int index,uint8_t * frev,uint8_t * crev)1611d38ceaf9SAlex Deucher bool amdgpu_atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t *frev,
1612d38ceaf9SAlex Deucher 			   uint8_t *crev)
1613d38ceaf9SAlex Deucher {
1614d38ceaf9SAlex Deucher 	int offset = index * 2 + 4;
1615d38ceaf9SAlex Deucher 	int idx = CU16(ctx->cmd_table + offset);
1616d38ceaf9SAlex Deucher 	u16 *mct = (u16 *)(ctx->bios + ctx->cmd_table + 4);
1617d38ceaf9SAlex Deucher 
1618d38ceaf9SAlex Deucher 	if (!mct[index])
1619d38ceaf9SAlex Deucher 		return false;
1620d38ceaf9SAlex Deucher 
1621d38ceaf9SAlex Deucher 	if (frev)
1622d38ceaf9SAlex Deucher 		*frev = CU8(idx + 2);
1623d38ceaf9SAlex Deucher 	if (crev)
1624d38ceaf9SAlex Deucher 		*crev = CU8(idx + 3);
1625d38ceaf9SAlex Deucher 	return true;
1626d38ceaf9SAlex Deucher }
1627d38ceaf9SAlex Deucher 
1628