xref: /linux/drivers/gpu/drm/amd/amdgpu/atom.c (revision 570f7e331f5febb30f1384817463c7e42b65ca7d)
1 /*
2  * Copyright 2008 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Author: Stanislaw Skowronek
23  */
24 
25 #include <linux/module.h>
26 #include <linux/sched.h>
27 #include <linux/slab.h>
28 #include <linux/string_helpers.h>
29 
30 #include <linux/unaligned.h>
31 
32 #include <drm/drm_util.h>
33 
34 #define ATOM_DEBUG
35 
36 #include "atomfirmware.h"
37 #include "atom.h"
38 #include "atom-names.h"
39 #include "atom-bits.h"
40 #include "amdgpu.h"
41 
42 #define ATOM_COND_ABOVE		0
43 #define ATOM_COND_ABOVEOREQUAL	1
44 #define ATOM_COND_ALWAYS	2
45 #define ATOM_COND_BELOW		3
46 #define ATOM_COND_BELOWOREQUAL	4
47 #define ATOM_COND_EQUAL		5
48 #define ATOM_COND_NOTEQUAL	6
49 
50 #define ATOM_PORT_ATI	0
51 #define ATOM_PORT_PCI	1
52 #define ATOM_PORT_SYSIO	2
53 
54 #define ATOM_UNIT_MICROSEC	0
55 #define ATOM_UNIT_MILLISEC	1
56 
57 #define PLL_INDEX	2
58 #define PLL_DATA	3
59 
60 #define ATOM_CMD_TIMEOUT_SEC	20
61 
62 /* Limit ATOM command table recursion (calltable) to avoid kernel stack overflow. */
63 #define ATOM_EXECUTE_MAX_DEPTH	32
64 
65 typedef struct {
66 	struct atom_context *ctx;
67 	uint32_t *ps, *ws;
68 	int ps_size, ws_size;
69 	int ps_shift;
70 	uint16_t start;
71 	unsigned last_jump;
72 	unsigned long last_jump_jiffies;
73 	bool abort;
74 } atom_exec_context;
75 
76 int amdgpu_atom_debug;
77 static int amdgpu_atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t *params, int params_size);
78 int amdgpu_atom_execute_table(struct atom_context *ctx, int index, uint32_t *params, int params_size);
79 
80 static uint32_t atom_arg_mask[8] =
81 	{ 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000,
82 	  0xFF000000 };
83 static int atom_arg_shift[8] = { 0, 0, 8, 16, 0, 8, 16, 24 };
84 
85 static int atom_dst_to_src[8][4] = {
86 	/* translate destination alignment field to the source alignment encoding */
87 	{0, 0, 0, 0},
88 	{1, 2, 3, 0},
89 	{1, 2, 3, 0},
90 	{1, 2, 3, 0},
91 	{4, 5, 6, 7},
92 	{4, 5, 6, 7},
93 	{4, 5, 6, 7},
94 	{4, 5, 6, 7},
95 };
96 static int atom_def_dst[8] = { 0, 0, 1, 2, 0, 1, 2, 3 };
97 
98 static int debug_depth;
99 #ifdef ATOM_DEBUG
100 static void debug_print_spaces(int n)
101 {
102 	while (n--)
103 		printk("   ");
104 }
105 
106 #define DEBUG(...) do if (amdgpu_atom_debug) { printk(KERN_DEBUG __VA_ARGS__); } while (0)
107 #define SDEBUG(...) do if (amdgpu_atom_debug) { printk(KERN_DEBUG); debug_print_spaces(debug_depth); printk(__VA_ARGS__); } while (0)
108 #else
109 #define DEBUG(...) do { } while (0)
110 #define SDEBUG(...) do { } while (0)
111 #endif
112 
113 static uint32_t atom_iio_execute(struct atom_context *ctx, int base,
114 				 uint32_t index, uint32_t data)
115 {
116 	uint32_t temp = 0xCDCDCDCD;
117 	int start = base;
118 
119 	/* IIO opcodes read up to base+3; keep within the BIOS image */
120 	while (base + 3 < ctx->bios_size)
121 		switch (CU8(base)) {
122 		case ATOM_IIO_NOP:
123 			base++;
124 			break;
125 		case ATOM_IIO_READ:
126 			temp = ctx->card->reg_read(ctx->card, CU16(base + 1));
127 			base += 3;
128 			break;
129 		case ATOM_IIO_WRITE:
130 			ctx->card->reg_write(ctx->card, CU16(base + 1), temp);
131 			base += 3;
132 			break;
133 		case ATOM_IIO_CLEAR:
134 			temp &=
135 			    ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
136 			      CU8(base + 2));
137 			base += 3;
138 			break;
139 		case ATOM_IIO_SET:
140 			temp |=
141 			    (0xFFFFFFFF >> (32 - CU8(base + 1))) << CU8(base +
142 									2);
143 			base += 3;
144 			break;
145 		case ATOM_IIO_MOVE_INDEX:
146 			temp &=
147 			    ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
148 			      CU8(base + 3));
149 			temp |=
150 			    ((index >> CU8(base + 2)) &
151 			     (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base +
152 									  3);
153 			base += 4;
154 			break;
155 		case ATOM_IIO_MOVE_DATA:
156 			temp &=
157 			    ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
158 			      CU8(base + 3));
159 			temp |=
160 			    ((data >> CU8(base + 2)) &
161 			     (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base +
162 									  3);
163 			base += 4;
164 			break;
165 		case ATOM_IIO_MOVE_ATTR:
166 			temp &=
167 			    ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
168 			      CU8(base + 3));
169 			temp |=
170 			    ((ctx->
171 			      io_attr >> CU8(base + 2)) & (0xFFFFFFFF >> (32 -
172 									  CU8
173 									  (base
174 									   +
175 									   1))))
176 			    << CU8(base + 3);
177 			base += 4;
178 			break;
179 		case ATOM_IIO_END:
180 			return temp;
181 		default:
182 			pr_info("Unknown IIO opcode\n");
183 			return 0;
184 		}
185 
186 	pr_info("IIO method starting at offset %d runs past BIOS image\n", start);
187 	return 0;
188 }
189 
190 static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr,
191 				 int *ptr, uint32_t *saved, int print)
192 {
193 	uint32_t idx, val = 0xCDCDCDCD, align, arg;
194 	struct atom_context *gctx = ctx->ctx;
195 	arg = attr & 7;
196 	align = (attr >> 3) & 7;
197 	switch (arg) {
198 	case ATOM_ARG_REG:
199 		idx = U16(*ptr);
200 		(*ptr) += 2;
201 		if (print)
202 			DEBUG("REG[0x%04X]", idx);
203 		idx += gctx->reg_block;
204 		switch (gctx->io_mode) {
205 		case ATOM_IO_MM:
206 			val = gctx->card->reg_read(gctx->card, idx);
207 			break;
208 		case ATOM_IO_PCI:
209 			pr_info("PCI registers are not implemented\n");
210 			return 0;
211 		case ATOM_IO_SYSIO:
212 			pr_info("SYSIO registers are not implemented\n");
213 			return 0;
214 		default:
215 			if (!(gctx->io_mode & 0x80)) {
216 				pr_info("Bad IO mode\n");
217 				return 0;
218 			}
219 			if (!gctx->iio[gctx->io_mode & 0x7F]) {
220 				pr_info("Undefined indirect IO read method %d\n",
221 					gctx->io_mode & 0x7F);
222 				return 0;
223 			}
224 			val =
225 			    atom_iio_execute(gctx,
226 					     gctx->iio[gctx->io_mode & 0x7F],
227 					     idx, 0);
228 		}
229 		break;
230 	case ATOM_ARG_PS:
231 		idx = U8(*ptr);
232 		(*ptr)++;
233 		/* get_unaligned_le32 avoids unaligned accesses from atombios
234 		 * tables, noticed on a DEC Alpha. */
235 		if (idx < ctx->ps_size)
236 			val = get_unaligned_le32((u32 *)&ctx->ps[idx]);
237 		else
238 			pr_info("PS index out of range: %i > %i\n", idx, ctx->ps_size);
239 		if (print)
240 			DEBUG("PS[0x%02X,0x%04X]", idx, val);
241 		break;
242 	case ATOM_ARG_WS:
243 		idx = U8(*ptr);
244 		(*ptr)++;
245 		if (print)
246 			DEBUG("WS[0x%02X]", idx);
247 		switch (idx) {
248 		case ATOM_WS_QUOTIENT:
249 			val = gctx->divmul[0];
250 			break;
251 		case ATOM_WS_REMAINDER:
252 			val = gctx->divmul[1];
253 			break;
254 		case ATOM_WS_DATAPTR:
255 			val = gctx->data_block;
256 			break;
257 		case ATOM_WS_SHIFT:
258 			val = gctx->shift;
259 			break;
260 		case ATOM_WS_OR_MASK:
261 			val = 1 << gctx->shift;
262 			break;
263 		case ATOM_WS_AND_MASK:
264 			val = ~(1 << gctx->shift);
265 			break;
266 		case ATOM_WS_FB_WINDOW:
267 			val = gctx->fb_base;
268 			break;
269 		case ATOM_WS_ATTRIBUTES:
270 			val = gctx->io_attr;
271 			break;
272 		case ATOM_WS_REGPTR:
273 			val = gctx->reg_block;
274 			break;
275 		default:
276 			if (idx < ctx->ws_size)
277 				val = ctx->ws[idx];
278 			else
279 				pr_info("WS index out of range: %i > %i\n", idx, ctx->ws_size);
280 		}
281 		break;
282 	case ATOM_ARG_ID:
283 		idx = U16(*ptr);
284 		(*ptr) += 2;
285 		if (print) {
286 			if (gctx->data_block)
287 				DEBUG("ID[0x%04X+%04X]", idx, gctx->data_block);
288 			else
289 				DEBUG("ID[0x%04X]", idx);
290 		}
291 		val = U32(idx + gctx->data_block);
292 		break;
293 	case ATOM_ARG_FB:
294 		idx = U8(*ptr);
295 		(*ptr)++;
296 		if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) {
297 			DRM_ERROR("ATOM: fb read beyond scratch region: %d vs. %d\n",
298 				  gctx->fb_base + (idx * 4), gctx->scratch_size_bytes);
299 			val = 0;
300 		} else
301 			val = gctx->scratch[(gctx->fb_base / 4) + idx];
302 		if (print)
303 			DEBUG("FB[0x%02X]", idx);
304 		break;
305 	case ATOM_ARG_IMM:
306 		switch (align) {
307 		case ATOM_SRC_DWORD:
308 			val = U32(*ptr);
309 			(*ptr) += 4;
310 			if (print)
311 				DEBUG("IMM 0x%08X\n", val);
312 			break;
313 		case ATOM_SRC_WORD0:
314 		case ATOM_SRC_WORD8:
315 		case ATOM_SRC_WORD16:
316 			val = U16(*ptr);
317 			(*ptr) += 2;
318 			if (print)
319 				DEBUG("IMM 0x%04X\n", val);
320 			break;
321 		case ATOM_SRC_BYTE0:
322 		case ATOM_SRC_BYTE8:
323 		case ATOM_SRC_BYTE16:
324 		case ATOM_SRC_BYTE24:
325 			val = U8(*ptr);
326 			(*ptr)++;
327 			if (print)
328 				DEBUG("IMM 0x%02X\n", val);
329 			break;
330 		}
331 		return val;
332 	case ATOM_ARG_PLL:
333 		idx = U8(*ptr);
334 		(*ptr)++;
335 		if (print)
336 			DEBUG("PLL[0x%02X]", idx);
337 		val = gctx->card->pll_read(gctx->card, idx);
338 		break;
339 	case ATOM_ARG_MC:
340 		idx = U8(*ptr);
341 		(*ptr)++;
342 		if (print)
343 			DEBUG("MC[0x%02X]", idx);
344 		val = gctx->card->mc_read(gctx->card, idx);
345 		break;
346 	}
347 	if (saved)
348 		*saved = val;
349 	val &= atom_arg_mask[align];
350 	val >>= atom_arg_shift[align];
351 	if (print)
352 		switch (align) {
353 		case ATOM_SRC_DWORD:
354 			DEBUG(".[31:0] -> 0x%08X\n", val);
355 			break;
356 		case ATOM_SRC_WORD0:
357 			DEBUG(".[15:0] -> 0x%04X\n", val);
358 			break;
359 		case ATOM_SRC_WORD8:
360 			DEBUG(".[23:8] -> 0x%04X\n", val);
361 			break;
362 		case ATOM_SRC_WORD16:
363 			DEBUG(".[31:16] -> 0x%04X\n", val);
364 			break;
365 		case ATOM_SRC_BYTE0:
366 			DEBUG(".[7:0] -> 0x%02X\n", val);
367 			break;
368 		case ATOM_SRC_BYTE8:
369 			DEBUG(".[15:8] -> 0x%02X\n", val);
370 			break;
371 		case ATOM_SRC_BYTE16:
372 			DEBUG(".[23:16] -> 0x%02X\n", val);
373 			break;
374 		case ATOM_SRC_BYTE24:
375 			DEBUG(".[31:24] -> 0x%02X\n", val);
376 			break;
377 		}
378 	return val;
379 }
380 
381 static void atom_skip_src_int(atom_exec_context *ctx, uint8_t attr, int *ptr)
382 {
383 	uint32_t align = (attr >> 3) & 7, arg = attr & 7;
384 	switch (arg) {
385 	case ATOM_ARG_REG:
386 	case ATOM_ARG_ID:
387 		(*ptr) += 2;
388 		break;
389 	case ATOM_ARG_PLL:
390 	case ATOM_ARG_MC:
391 	case ATOM_ARG_PS:
392 	case ATOM_ARG_WS:
393 	case ATOM_ARG_FB:
394 		(*ptr)++;
395 		break;
396 	case ATOM_ARG_IMM:
397 		switch (align) {
398 		case ATOM_SRC_DWORD:
399 			(*ptr) += 4;
400 			return;
401 		case ATOM_SRC_WORD0:
402 		case ATOM_SRC_WORD8:
403 		case ATOM_SRC_WORD16:
404 			(*ptr) += 2;
405 			return;
406 		case ATOM_SRC_BYTE0:
407 		case ATOM_SRC_BYTE8:
408 		case ATOM_SRC_BYTE16:
409 		case ATOM_SRC_BYTE24:
410 			(*ptr)++;
411 			return;
412 		}
413 	}
414 }
415 
416 static uint32_t atom_get_src(atom_exec_context *ctx, uint8_t attr, int *ptr)
417 {
418 	return atom_get_src_int(ctx, attr, ptr, NULL, 1);
419 }
420 
421 static uint32_t atom_get_src_direct(atom_exec_context *ctx, uint8_t align, int *ptr)
422 {
423 	uint32_t val = 0xCDCDCDCD;
424 
425 	switch (align) {
426 	case ATOM_SRC_DWORD:
427 		val = U32(*ptr);
428 		(*ptr) += 4;
429 		break;
430 	case ATOM_SRC_WORD0:
431 	case ATOM_SRC_WORD8:
432 	case ATOM_SRC_WORD16:
433 		val = U16(*ptr);
434 		(*ptr) += 2;
435 		break;
436 	case ATOM_SRC_BYTE0:
437 	case ATOM_SRC_BYTE8:
438 	case ATOM_SRC_BYTE16:
439 	case ATOM_SRC_BYTE24:
440 		val = U8(*ptr);
441 		(*ptr)++;
442 		break;
443 	}
444 	return val;
445 }
446 
447 static uint32_t atom_get_dst(atom_exec_context *ctx, int arg, uint8_t attr,
448 			     int *ptr, uint32_t *saved, int print)
449 {
450 	return atom_get_src_int(ctx,
451 				arg | atom_dst_to_src[(attr >> 3) &
452 						      7][(attr >> 6) & 3] << 3,
453 				ptr, saved, print);
454 }
455 
456 static void atom_skip_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr)
457 {
458 	atom_skip_src_int(ctx,
459 			  arg | atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) &
460 								 3] << 3, ptr);
461 }
462 
463 static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr,
464 			 int *ptr, uint32_t val, uint32_t saved)
465 {
466 	uint32_t align =
467 	    atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3], old_val =
468 	    val, idx;
469 	struct atom_context *gctx = ctx->ctx;
470 	old_val &= atom_arg_mask[align] >> atom_arg_shift[align];
471 	val <<= atom_arg_shift[align];
472 	val &= atom_arg_mask[align];
473 	saved &= ~atom_arg_mask[align];
474 	val |= saved;
475 	switch (arg) {
476 	case ATOM_ARG_REG:
477 		idx = U16(*ptr);
478 		(*ptr) += 2;
479 		DEBUG("REG[0x%04X]", idx);
480 		idx += gctx->reg_block;
481 		switch (gctx->io_mode) {
482 		case ATOM_IO_MM:
483 			if (idx == 0)
484 				gctx->card->reg_write(gctx->card, idx,
485 						      val << 2);
486 			else
487 				gctx->card->reg_write(gctx->card, idx, val);
488 			break;
489 		case ATOM_IO_PCI:
490 			pr_info("PCI registers are not implemented\n");
491 			return;
492 		case ATOM_IO_SYSIO:
493 			pr_info("SYSIO registers are not implemented\n");
494 			return;
495 		default:
496 			if (!(gctx->io_mode & 0x80)) {
497 				pr_info("Bad IO mode\n");
498 				return;
499 			}
500 			if (!gctx->iio[gctx->io_mode & 0xFF]) {
501 				pr_info("Undefined indirect IO write method %d\n",
502 					gctx->io_mode & 0x7F);
503 				return;
504 			}
505 			atom_iio_execute(gctx, gctx->iio[gctx->io_mode & 0xFF],
506 					 idx, val);
507 		}
508 		break;
509 	case ATOM_ARG_PS:
510 		idx = U8(*ptr);
511 		(*ptr)++;
512 		DEBUG("PS[0x%02X]", idx);
513 		if (idx >= ctx->ps_size) {
514 			pr_info("PS index out of range: %i > %i\n", idx, ctx->ps_size);
515 			return;
516 		}
517 		ctx->ps[idx] = cpu_to_le32(val);
518 		break;
519 	case ATOM_ARG_WS:
520 		idx = U8(*ptr);
521 		(*ptr)++;
522 		DEBUG("WS[0x%02X]", idx);
523 		switch (idx) {
524 		case ATOM_WS_QUOTIENT:
525 			gctx->divmul[0] = val;
526 			break;
527 		case ATOM_WS_REMAINDER:
528 			gctx->divmul[1] = val;
529 			break;
530 		case ATOM_WS_DATAPTR:
531 			gctx->data_block = val;
532 			break;
533 		case ATOM_WS_SHIFT:
534 			gctx->shift = val;
535 			break;
536 		case ATOM_WS_OR_MASK:
537 		case ATOM_WS_AND_MASK:
538 			break;
539 		case ATOM_WS_FB_WINDOW:
540 			gctx->fb_base = val;
541 			break;
542 		case ATOM_WS_ATTRIBUTES:
543 			gctx->io_attr = val;
544 			break;
545 		case ATOM_WS_REGPTR:
546 			gctx->reg_block = val;
547 			break;
548 		default:
549 			if (idx >= ctx->ws_size) {
550 				pr_info("WS index out of range: %i > %i\n", idx, ctx->ws_size);
551 				return;
552 			}
553 			ctx->ws[idx] = val;
554 		}
555 		break;
556 	case ATOM_ARG_FB:
557 		idx = U8(*ptr);
558 		(*ptr)++;
559 		if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) {
560 			DRM_ERROR("ATOM: fb write beyond scratch region: %d vs. %d\n",
561 				  gctx->fb_base + (idx * 4), gctx->scratch_size_bytes);
562 		} else
563 			gctx->scratch[(gctx->fb_base / 4) + idx] = val;
564 		DEBUG("FB[0x%02X]", idx);
565 		break;
566 	case ATOM_ARG_PLL:
567 		idx = U8(*ptr);
568 		(*ptr)++;
569 		DEBUG("PLL[0x%02X]", idx);
570 		gctx->card->pll_write(gctx->card, idx, val);
571 		break;
572 	case ATOM_ARG_MC:
573 		idx = U8(*ptr);
574 		(*ptr)++;
575 		DEBUG("MC[0x%02X]", idx);
576 		gctx->card->mc_write(gctx->card, idx, val);
577 		return;
578 	}
579 	switch (align) {
580 	case ATOM_SRC_DWORD:
581 		DEBUG(".[31:0] <- 0x%08X\n", old_val);
582 		break;
583 	case ATOM_SRC_WORD0:
584 		DEBUG(".[15:0] <- 0x%04X\n", old_val);
585 		break;
586 	case ATOM_SRC_WORD8:
587 		DEBUG(".[23:8] <- 0x%04X\n", old_val);
588 		break;
589 	case ATOM_SRC_WORD16:
590 		DEBUG(".[31:16] <- 0x%04X\n", old_val);
591 		break;
592 	case ATOM_SRC_BYTE0:
593 		DEBUG(".[7:0] <- 0x%02X\n", old_val);
594 		break;
595 	case ATOM_SRC_BYTE8:
596 		DEBUG(".[15:8] <- 0x%02X\n", old_val);
597 		break;
598 	case ATOM_SRC_BYTE16:
599 		DEBUG(".[23:16] <- 0x%02X\n", old_val);
600 		break;
601 	case ATOM_SRC_BYTE24:
602 		DEBUG(".[31:24] <- 0x%02X\n", old_val);
603 		break;
604 	}
605 }
606 
607 static void atom_op_add(atom_exec_context *ctx, int *ptr, int arg)
608 {
609 	uint8_t attr = U8((*ptr)++);
610 	uint32_t dst, src, saved;
611 	int dptr = *ptr;
612 	SDEBUG("   dst: ");
613 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
614 	SDEBUG("   src: ");
615 	src = atom_get_src(ctx, attr, ptr);
616 	dst += src;
617 	SDEBUG("   dst: ");
618 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
619 }
620 
621 static void atom_op_and(atom_exec_context *ctx, int *ptr, int arg)
622 {
623 	uint8_t attr = U8((*ptr)++);
624 	uint32_t dst, src, saved;
625 	int dptr = *ptr;
626 	SDEBUG("   dst: ");
627 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
628 	SDEBUG("   src: ");
629 	src = atom_get_src(ctx, attr, ptr);
630 	dst &= src;
631 	SDEBUG("   dst: ");
632 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
633 }
634 
635 static void atom_op_beep(atom_exec_context *ctx, int *ptr, int arg)
636 {
637 	printk("ATOM BIOS beeped!\n");
638 }
639 
640 static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg)
641 {
642 	int idx = U8((*ptr)++);
643 	int r = 0;
644 
645 	if (idx < ATOM_TABLE_NAMES_CNT)
646 		SDEBUG("   table: %d (%s)\n", idx, atom_table_names[idx]);
647 	else
648 		SDEBUG("   table: %d\n", idx);
649 	if (U16(ctx->ctx->cmd_table + 4 + 2 * idx))
650 		r = amdgpu_atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift, ctx->ps_size - ctx->ps_shift);
651 	if (r) {
652 		ctx->abort = true;
653 	}
654 }
655 
656 static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg)
657 {
658 	uint8_t attr = U8((*ptr)++);
659 	uint32_t saved;
660 	int dptr = *ptr;
661 	attr &= 0x38;
662 	attr |= atom_def_dst[attr >> 3] << 6;
663 	atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
664 	SDEBUG("   dst: ");
665 	atom_put_dst(ctx, arg, attr, &dptr, 0, saved);
666 }
667 
668 static void atom_op_compare(atom_exec_context *ctx, int *ptr, int arg)
669 {
670 	uint8_t attr = U8((*ptr)++);
671 	uint32_t dst, src;
672 	SDEBUG("   src1: ");
673 	dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
674 	SDEBUG("   src2: ");
675 	src = atom_get_src(ctx, attr, ptr);
676 	ctx->ctx->cs_equal = (dst == src);
677 	ctx->ctx->cs_above = (dst > src);
678 	SDEBUG("   result: %s %s\n", ctx->ctx->cs_equal ? "EQ" : "NE",
679 	       ctx->ctx->cs_above ? "GT" : "LE");
680 }
681 
682 static void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg)
683 {
684 	unsigned count = U8((*ptr)++);
685 	SDEBUG("   count: %d\n", count);
686 	if (arg == ATOM_UNIT_MICROSEC)
687 		udelay(count);
688 	else if (!drm_can_sleep())
689 		mdelay(count);
690 	else
691 		msleep(count);
692 }
693 
694 static void atom_op_div(atom_exec_context *ctx, int *ptr, int arg)
695 {
696 	uint8_t attr = U8((*ptr)++);
697 	uint32_t dst, src;
698 	SDEBUG("   src1: ");
699 	dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
700 	SDEBUG("   src2: ");
701 	src = atom_get_src(ctx, attr, ptr);
702 	if (src != 0) {
703 		ctx->ctx->divmul[0] = dst / src;
704 		ctx->ctx->divmul[1] = dst % src;
705 	} else {
706 		ctx->ctx->divmul[0] = 0;
707 		ctx->ctx->divmul[1] = 0;
708 	}
709 }
710 
711 static void atom_op_div32(atom_exec_context *ctx, int *ptr, int arg)
712 {
713 	uint64_t val64;
714 	uint8_t attr = U8((*ptr)++);
715 	uint32_t dst, src;
716 	SDEBUG("   src1: ");
717 	dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
718 	SDEBUG("   src2: ");
719 	src = atom_get_src(ctx, attr, ptr);
720 	if (src != 0) {
721 		val64 = dst;
722 		val64 |= ((uint64_t)ctx->ctx->divmul[1]) << 32;
723 		do_div(val64, src);
724 		ctx->ctx->divmul[0] = lower_32_bits(val64);
725 		ctx->ctx->divmul[1] = upper_32_bits(val64);
726 	} else {
727 		ctx->ctx->divmul[0] = 0;
728 		ctx->ctx->divmul[1] = 0;
729 	}
730 }
731 
732 static void atom_op_eot(atom_exec_context *ctx, int *ptr, int arg)
733 {
734 	/* functionally, a nop */
735 }
736 
737 static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
738 {
739 	int execute = 0, target = U16(*ptr);
740 	unsigned long cjiffies;
741 
742 	(*ptr) += 2;
743 	switch (arg) {
744 	case ATOM_COND_ABOVE:
745 		execute = ctx->ctx->cs_above;
746 		break;
747 	case ATOM_COND_ABOVEOREQUAL:
748 		execute = ctx->ctx->cs_above || ctx->ctx->cs_equal;
749 		break;
750 	case ATOM_COND_ALWAYS:
751 		execute = 1;
752 		break;
753 	case ATOM_COND_BELOW:
754 		execute = !(ctx->ctx->cs_above || ctx->ctx->cs_equal);
755 		break;
756 	case ATOM_COND_BELOWOREQUAL:
757 		execute = !ctx->ctx->cs_above;
758 		break;
759 	case ATOM_COND_EQUAL:
760 		execute = ctx->ctx->cs_equal;
761 		break;
762 	case ATOM_COND_NOTEQUAL:
763 		execute = !ctx->ctx->cs_equal;
764 		break;
765 	}
766 	if (arg != ATOM_COND_ALWAYS)
767 		SDEBUG("   taken: %s\n", str_yes_no(execute));
768 	SDEBUG("   target: 0x%04X\n", target);
769 	if (execute) {
770 		if (ctx->last_jump == (ctx->start + target)) {
771 			cjiffies = jiffies;
772 			if (time_after(cjiffies, ctx->last_jump_jiffies)) {
773 				cjiffies -= ctx->last_jump_jiffies;
774 				if ((jiffies_to_msecs(cjiffies) > ATOM_CMD_TIMEOUT_SEC*1000)) {
775 					DRM_ERROR("atombios stuck in loop for more than %dsecs aborting\n",
776 						  ATOM_CMD_TIMEOUT_SEC);
777 					ctx->abort = true;
778 				}
779 			} else {
780 				/* jiffies wrap around we will just wait a little longer */
781 				ctx->last_jump_jiffies = jiffies;
782 			}
783 		} else {
784 			ctx->last_jump = ctx->start + target;
785 			ctx->last_jump_jiffies = jiffies;
786 		}
787 		*ptr = ctx->start + target;
788 	}
789 }
790 
791 static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg)
792 {
793 	uint8_t attr = U8((*ptr)++);
794 	uint32_t dst, mask, src, saved;
795 	int dptr = *ptr;
796 	SDEBUG("   dst: ");
797 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
798 	mask = atom_get_src_direct(ctx, ((attr >> 3) & 7), ptr);
799 	SDEBUG("   mask: 0x%08x", mask);
800 	SDEBUG("   src: ");
801 	src = atom_get_src(ctx, attr, ptr);
802 	dst &= mask;
803 	dst |= src;
804 	SDEBUG("   dst: ");
805 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
806 }
807 
808 static void atom_op_move(atom_exec_context *ctx, int *ptr, int arg)
809 {
810 	uint8_t attr = U8((*ptr)++);
811 	uint32_t src, saved;
812 	int dptr = *ptr;
813 	if (((attr >> 3) & 7) != ATOM_SRC_DWORD)
814 		atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
815 	else {
816 		atom_skip_dst(ctx, arg, attr, ptr);
817 		saved = 0xCDCDCDCD;
818 	}
819 	SDEBUG("   src: ");
820 	src = atom_get_src(ctx, attr, ptr);
821 	SDEBUG("   dst: ");
822 	atom_put_dst(ctx, arg, attr, &dptr, src, saved);
823 }
824 
825 static void atom_op_mul(atom_exec_context *ctx, int *ptr, int arg)
826 {
827 	uint8_t attr = U8((*ptr)++);
828 	uint32_t dst, src;
829 	SDEBUG("   src1: ");
830 	dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
831 	SDEBUG("   src2: ");
832 	src = atom_get_src(ctx, attr, ptr);
833 	ctx->ctx->divmul[0] = dst * src;
834 }
835 
836 static void atom_op_mul32(atom_exec_context *ctx, int *ptr, int arg)
837 {
838 	uint64_t val64;
839 	uint8_t attr = U8((*ptr)++);
840 	uint32_t dst, src;
841 	SDEBUG("   src1: ");
842 	dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
843 	SDEBUG("   src2: ");
844 	src = atom_get_src(ctx, attr, ptr);
845 	val64 = (uint64_t)dst * (uint64_t)src;
846 	ctx->ctx->divmul[0] = lower_32_bits(val64);
847 	ctx->ctx->divmul[1] = upper_32_bits(val64);
848 }
849 
850 static void atom_op_nop(atom_exec_context *ctx, int *ptr, int arg)
851 {
852 	/* nothing */
853 }
854 
855 static void atom_op_or(atom_exec_context *ctx, int *ptr, int arg)
856 {
857 	uint8_t attr = U8((*ptr)++);
858 	uint32_t dst, src, saved;
859 	int dptr = *ptr;
860 	SDEBUG("   dst: ");
861 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
862 	SDEBUG("   src: ");
863 	src = atom_get_src(ctx, attr, ptr);
864 	dst |= src;
865 	SDEBUG("   dst: ");
866 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
867 }
868 
869 static void atom_op_postcard(atom_exec_context *ctx, int *ptr, int arg)
870 {
871 	uint8_t val = U8((*ptr)++);
872 	SDEBUG("POST card output: 0x%02X\n", val);
873 }
874 
875 static void atom_op_repeat(atom_exec_context *ctx, int *ptr, int arg)
876 {
877 	pr_info("unimplemented!\n");
878 }
879 
880 static void atom_op_restorereg(atom_exec_context *ctx, int *ptr, int arg)
881 {
882 	pr_info("unimplemented!\n");
883 }
884 
885 static void atom_op_savereg(atom_exec_context *ctx, int *ptr, int arg)
886 {
887 	pr_info("unimplemented!\n");
888 }
889 
890 static void atom_op_setdatablock(atom_exec_context *ctx, int *ptr, int arg)
891 {
892 	int idx = U8(*ptr);
893 	(*ptr)++;
894 	SDEBUG("   block: %d\n", idx);
895 	if (!idx)
896 		ctx->ctx->data_block = 0;
897 	else if (idx == 255)
898 		ctx->ctx->data_block = ctx->start;
899 	else
900 		ctx->ctx->data_block = U16(ctx->ctx->data_table + 4 + 2 * idx);
901 	SDEBUG("   base: 0x%04X\n", ctx->ctx->data_block);
902 }
903 
904 static void atom_op_setfbbase(atom_exec_context *ctx, int *ptr, int arg)
905 {
906 	uint8_t attr = U8((*ptr)++);
907 	SDEBUG("   fb_base: ");
908 	ctx->ctx->fb_base = atom_get_src(ctx, attr, ptr);
909 }
910 
911 static void atom_op_setport(atom_exec_context *ctx, int *ptr, int arg)
912 {
913 	int port;
914 	switch (arg) {
915 	case ATOM_PORT_ATI:
916 		port = U16(*ptr);
917 		if (port < ATOM_IO_NAMES_CNT)
918 			SDEBUG("   port: %d (%s)\n", port, atom_io_names[port]);
919 		else
920 			SDEBUG("   port: %d\n", port);
921 		if (!port)
922 			ctx->ctx->io_mode = ATOM_IO_MM;
923 		else
924 			ctx->ctx->io_mode = ATOM_IO_IIO | port;
925 		(*ptr) += 2;
926 		break;
927 	case ATOM_PORT_PCI:
928 		ctx->ctx->io_mode = ATOM_IO_PCI;
929 		(*ptr)++;
930 		break;
931 	case ATOM_PORT_SYSIO:
932 		ctx->ctx->io_mode = ATOM_IO_SYSIO;
933 		(*ptr)++;
934 		break;
935 	}
936 }
937 
938 static void atom_op_setregblock(atom_exec_context *ctx, int *ptr, int arg)
939 {
940 	ctx->ctx->reg_block = U16(*ptr);
941 	(*ptr) += 2;
942 	SDEBUG("   base: 0x%04X\n", ctx->ctx->reg_block);
943 }
944 
945 static void atom_op_shift_left(atom_exec_context *ctx, int *ptr, int arg)
946 {
947 	uint8_t attr = U8((*ptr)++), shift;
948 	uint32_t saved, dst;
949 	int dptr = *ptr;
950 	attr &= 0x38;
951 	attr |= atom_def_dst[attr >> 3] << 6;
952 	SDEBUG("   dst: ");
953 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
954 	shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr);
955 	SDEBUG("   shift: %d\n", shift);
956 	dst <<= shift;
957 	SDEBUG("   dst: ");
958 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
959 }
960 
961 static void atom_op_shift_right(atom_exec_context *ctx, int *ptr, int arg)
962 {
963 	uint8_t attr = U8((*ptr)++), shift;
964 	uint32_t saved, dst;
965 	int dptr = *ptr;
966 	attr &= 0x38;
967 	attr |= atom_def_dst[attr >> 3] << 6;
968 	SDEBUG("   dst: ");
969 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
970 	shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr);
971 	SDEBUG("   shift: %d\n", shift);
972 	dst >>= shift;
973 	SDEBUG("   dst: ");
974 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
975 }
976 
977 static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg)
978 {
979 	uint8_t attr = U8((*ptr)++), shift;
980 	uint32_t saved, dst;
981 	int dptr = *ptr;
982 	uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3];
983 	SDEBUG("   dst: ");
984 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
985 	/* op needs to full dst value */
986 	dst = saved;
987 	shift = atom_get_src(ctx, attr, ptr);
988 	SDEBUG("   shift: %d\n", shift);
989 	dst <<= shift;
990 	dst &= atom_arg_mask[dst_align];
991 	dst >>= atom_arg_shift[dst_align];
992 	SDEBUG("   dst: ");
993 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
994 }
995 
996 static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg)
997 {
998 	uint8_t attr = U8((*ptr)++), shift;
999 	uint32_t saved, dst;
1000 	int dptr = *ptr;
1001 	uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3];
1002 	SDEBUG("   dst: ");
1003 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
1004 	/* op needs to full dst value */
1005 	dst = saved;
1006 	shift = atom_get_src(ctx, attr, ptr);
1007 	SDEBUG("   shift: %d\n", shift);
1008 	dst >>= shift;
1009 	dst &= atom_arg_mask[dst_align];
1010 	dst >>= atom_arg_shift[dst_align];
1011 	SDEBUG("   dst: ");
1012 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
1013 }
1014 
1015 static void atom_op_sub(atom_exec_context *ctx, int *ptr, int arg)
1016 {
1017 	uint8_t attr = U8((*ptr)++);
1018 	uint32_t dst, src, saved;
1019 	int dptr = *ptr;
1020 	SDEBUG("   dst: ");
1021 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
1022 	SDEBUG("   src: ");
1023 	src = atom_get_src(ctx, attr, ptr);
1024 	dst -= src;
1025 	SDEBUG("   dst: ");
1026 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
1027 }
1028 
1029 static void atom_op_switch(atom_exec_context *ctx, int *ptr, int arg)
1030 {
1031 	uint8_t attr = U8((*ptr)++);
1032 	uint32_t src, val, target;
1033 	SDEBUG("   switch: ");
1034 	src = atom_get_src(ctx, attr, ptr);
1035 	while (U16(*ptr) != ATOM_CASE_END)
1036 		if (U8(*ptr) == ATOM_CASE_MAGIC) {
1037 			(*ptr)++;
1038 			SDEBUG("   case: ");
1039 			val =
1040 			    atom_get_src(ctx, (attr & 0x38) | ATOM_ARG_IMM,
1041 					 ptr);
1042 			target = U16(*ptr);
1043 			if (val == src) {
1044 				SDEBUG("   target: %04X\n", target);
1045 				*ptr = ctx->start + target;
1046 				return;
1047 			}
1048 			(*ptr) += 2;
1049 		} else {
1050 			pr_info("Bad case\n");
1051 			return;
1052 		}
1053 	(*ptr) += 2;
1054 }
1055 
1056 static void atom_op_test(atom_exec_context *ctx, int *ptr, int arg)
1057 {
1058 	uint8_t attr = U8((*ptr)++);
1059 	uint32_t dst, src;
1060 	SDEBUG("   src1: ");
1061 	dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
1062 	SDEBUG("   src2: ");
1063 	src = atom_get_src(ctx, attr, ptr);
1064 	ctx->ctx->cs_equal = ((dst & src) == 0);
1065 	SDEBUG("   result: %s\n", ctx->ctx->cs_equal ? "EQ" : "NE");
1066 }
1067 
1068 static void atom_op_xor(atom_exec_context *ctx, int *ptr, int arg)
1069 {
1070 	uint8_t attr = U8((*ptr)++);
1071 	uint32_t dst, src, saved;
1072 	int dptr = *ptr;
1073 	SDEBUG("   dst: ");
1074 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
1075 	SDEBUG("   src: ");
1076 	src = atom_get_src(ctx, attr, ptr);
1077 	dst ^= src;
1078 	SDEBUG("   dst: ");
1079 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
1080 }
1081 
1082 static void atom_op_debug(atom_exec_context *ctx, int *ptr, int arg)
1083 {
1084 	uint8_t val = U8((*ptr)++);
1085 	SDEBUG("DEBUG output: 0x%02X\n", val);
1086 }
1087 
1088 static void atom_op_processds(atom_exec_context *ctx, int *ptr, int arg)
1089 {
1090 	uint16_t val = U16(*ptr);
1091 	(*ptr) += val + 2;
1092 	SDEBUG("PROCESSDS output: 0x%02X\n", val);
1093 }
1094 
1095 static struct {
1096 	void (*func) (atom_exec_context *, int *, int);
1097 	int arg;
1098 } opcode_table[ATOM_OP_CNT] = {
1099 	{
1100 	NULL, 0}, {
1101 	atom_op_move, ATOM_ARG_REG}, {
1102 	atom_op_move, ATOM_ARG_PS}, {
1103 	atom_op_move, ATOM_ARG_WS}, {
1104 	atom_op_move, ATOM_ARG_FB}, {
1105 	atom_op_move, ATOM_ARG_PLL}, {
1106 	atom_op_move, ATOM_ARG_MC}, {
1107 	atom_op_and, ATOM_ARG_REG}, {
1108 	atom_op_and, ATOM_ARG_PS}, {
1109 	atom_op_and, ATOM_ARG_WS}, {
1110 	atom_op_and, ATOM_ARG_FB}, {
1111 	atom_op_and, ATOM_ARG_PLL}, {
1112 	atom_op_and, ATOM_ARG_MC}, {
1113 	atom_op_or, ATOM_ARG_REG}, {
1114 	atom_op_or, ATOM_ARG_PS}, {
1115 	atom_op_or, ATOM_ARG_WS}, {
1116 	atom_op_or, ATOM_ARG_FB}, {
1117 	atom_op_or, ATOM_ARG_PLL}, {
1118 	atom_op_or, ATOM_ARG_MC}, {
1119 	atom_op_shift_left, ATOM_ARG_REG}, {
1120 	atom_op_shift_left, ATOM_ARG_PS}, {
1121 	atom_op_shift_left, ATOM_ARG_WS}, {
1122 	atom_op_shift_left, ATOM_ARG_FB}, {
1123 	atom_op_shift_left, ATOM_ARG_PLL}, {
1124 	atom_op_shift_left, ATOM_ARG_MC}, {
1125 	atom_op_shift_right, ATOM_ARG_REG}, {
1126 	atom_op_shift_right, ATOM_ARG_PS}, {
1127 	atom_op_shift_right, ATOM_ARG_WS}, {
1128 	atom_op_shift_right, ATOM_ARG_FB}, {
1129 	atom_op_shift_right, ATOM_ARG_PLL}, {
1130 	atom_op_shift_right, ATOM_ARG_MC}, {
1131 	atom_op_mul, ATOM_ARG_REG}, {
1132 	atom_op_mul, ATOM_ARG_PS}, {
1133 	atom_op_mul, ATOM_ARG_WS}, {
1134 	atom_op_mul, ATOM_ARG_FB}, {
1135 	atom_op_mul, ATOM_ARG_PLL}, {
1136 	atom_op_mul, ATOM_ARG_MC}, {
1137 	atom_op_div, ATOM_ARG_REG}, {
1138 	atom_op_div, ATOM_ARG_PS}, {
1139 	atom_op_div, ATOM_ARG_WS}, {
1140 	atom_op_div, ATOM_ARG_FB}, {
1141 	atom_op_div, ATOM_ARG_PLL}, {
1142 	atom_op_div, ATOM_ARG_MC}, {
1143 	atom_op_add, ATOM_ARG_REG}, {
1144 	atom_op_add, ATOM_ARG_PS}, {
1145 	atom_op_add, ATOM_ARG_WS}, {
1146 	atom_op_add, ATOM_ARG_FB}, {
1147 	atom_op_add, ATOM_ARG_PLL}, {
1148 	atom_op_add, ATOM_ARG_MC}, {
1149 	atom_op_sub, ATOM_ARG_REG}, {
1150 	atom_op_sub, ATOM_ARG_PS}, {
1151 	atom_op_sub, ATOM_ARG_WS}, {
1152 	atom_op_sub, ATOM_ARG_FB}, {
1153 	atom_op_sub, ATOM_ARG_PLL}, {
1154 	atom_op_sub, ATOM_ARG_MC}, {
1155 	atom_op_setport, ATOM_PORT_ATI}, {
1156 	atom_op_setport, ATOM_PORT_PCI}, {
1157 	atom_op_setport, ATOM_PORT_SYSIO}, {
1158 	atom_op_setregblock, 0}, {
1159 	atom_op_setfbbase, 0}, {
1160 	atom_op_compare, ATOM_ARG_REG}, {
1161 	atom_op_compare, ATOM_ARG_PS}, {
1162 	atom_op_compare, ATOM_ARG_WS}, {
1163 	atom_op_compare, ATOM_ARG_FB}, {
1164 	atom_op_compare, ATOM_ARG_PLL}, {
1165 	atom_op_compare, ATOM_ARG_MC}, {
1166 	atom_op_switch, 0}, {
1167 	atom_op_jump, ATOM_COND_ALWAYS}, {
1168 	atom_op_jump, ATOM_COND_EQUAL}, {
1169 	atom_op_jump, ATOM_COND_BELOW}, {
1170 	atom_op_jump, ATOM_COND_ABOVE}, {
1171 	atom_op_jump, ATOM_COND_BELOWOREQUAL}, {
1172 	atom_op_jump, ATOM_COND_ABOVEOREQUAL}, {
1173 	atom_op_jump, ATOM_COND_NOTEQUAL}, {
1174 	atom_op_test, ATOM_ARG_REG}, {
1175 	atom_op_test, ATOM_ARG_PS}, {
1176 	atom_op_test, ATOM_ARG_WS}, {
1177 	atom_op_test, ATOM_ARG_FB}, {
1178 	atom_op_test, ATOM_ARG_PLL}, {
1179 	atom_op_test, ATOM_ARG_MC}, {
1180 	atom_op_delay, ATOM_UNIT_MILLISEC}, {
1181 	atom_op_delay, ATOM_UNIT_MICROSEC}, {
1182 	atom_op_calltable, 0}, {
1183 	atom_op_repeat, 0}, {
1184 	atom_op_clear, ATOM_ARG_REG}, {
1185 	atom_op_clear, ATOM_ARG_PS}, {
1186 	atom_op_clear, ATOM_ARG_WS}, {
1187 	atom_op_clear, ATOM_ARG_FB}, {
1188 	atom_op_clear, ATOM_ARG_PLL}, {
1189 	atom_op_clear, ATOM_ARG_MC}, {
1190 	atom_op_nop, 0}, {
1191 	atom_op_eot, 0}, {
1192 	atom_op_mask, ATOM_ARG_REG}, {
1193 	atom_op_mask, ATOM_ARG_PS}, {
1194 	atom_op_mask, ATOM_ARG_WS}, {
1195 	atom_op_mask, ATOM_ARG_FB}, {
1196 	atom_op_mask, ATOM_ARG_PLL}, {
1197 	atom_op_mask, ATOM_ARG_MC}, {
1198 	atom_op_postcard, 0}, {
1199 	atom_op_beep, 0}, {
1200 	atom_op_savereg, 0}, {
1201 	atom_op_restorereg, 0}, {
1202 	atom_op_setdatablock, 0}, {
1203 	atom_op_xor, ATOM_ARG_REG}, {
1204 	atom_op_xor, ATOM_ARG_PS}, {
1205 	atom_op_xor, ATOM_ARG_WS}, {
1206 	atom_op_xor, ATOM_ARG_FB}, {
1207 	atom_op_xor, ATOM_ARG_PLL}, {
1208 	atom_op_xor, ATOM_ARG_MC}, {
1209 	atom_op_shl, ATOM_ARG_REG}, {
1210 	atom_op_shl, ATOM_ARG_PS}, {
1211 	atom_op_shl, ATOM_ARG_WS}, {
1212 	atom_op_shl, ATOM_ARG_FB}, {
1213 	atom_op_shl, ATOM_ARG_PLL}, {
1214 	atom_op_shl, ATOM_ARG_MC}, {
1215 	atom_op_shr, ATOM_ARG_REG}, {
1216 	atom_op_shr, ATOM_ARG_PS}, {
1217 	atom_op_shr, ATOM_ARG_WS}, {
1218 	atom_op_shr, ATOM_ARG_FB}, {
1219 	atom_op_shr, ATOM_ARG_PLL}, {
1220 	atom_op_shr, ATOM_ARG_MC}, {
1221 	atom_op_debug, 0}, {
1222 	atom_op_processds, 0}, {
1223 	atom_op_mul32, ATOM_ARG_PS}, {
1224 	atom_op_mul32, ATOM_ARG_WS}, {
1225 	atom_op_div32, ATOM_ARG_PS}, {
1226 	atom_op_div32, ATOM_ARG_WS},
1227 };
1228 
1229 static int amdgpu_atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t *params, int params_size)
1230 {
1231 	int base = CU16(ctx->cmd_table + 4 + 2 * index);
1232 	int len, ws, ps, ptr;
1233 	unsigned char op;
1234 	atom_exec_context ectx;
1235 	int ret = 0;
1236 
1237 	if (!base)
1238 		return -EINVAL;
1239 
1240 	if (ctx->execute_depth >= ATOM_EXECUTE_MAX_DEPTH) {
1241 		DRM_ERROR("atombios command table nesting exceeded limit (%u)\n",
1242 			  ATOM_EXECUTE_MAX_DEPTH);
1243 		return -ELOOP;
1244 	}
1245 	ctx->execute_depth++;
1246 
1247 	len = CU16(base + ATOM_CT_SIZE_PTR);
1248 	ws = CU8(base + ATOM_CT_WS_PTR);
1249 	ps = CU8(base + ATOM_CT_PS_PTR) & ATOM_CT_PS_MASK;
1250 	ptr = base + ATOM_CT_CODE_PTR;
1251 
1252 	SDEBUG(">> execute %04X (len %d, WS %d, PS %d)\n", base, len, ws, ps);
1253 
1254 	ectx.ctx = ctx;
1255 	ectx.ps_shift = ps / 4;
1256 	ectx.start = base;
1257 	ectx.ps = params;
1258 	ectx.ps_size = params_size;
1259 	ectx.abort = false;
1260 	ectx.last_jump = 0;
1261 	ectx.last_jump_jiffies = 0;
1262 	if (ws) {
1263 		ectx.ws = kcalloc(4, ws, GFP_KERNEL);
1264 		if (!ectx.ws) {
1265 			ret = -ENOMEM;
1266 			goto free;
1267 		}
1268 		ectx.ws_size = ws;
1269 	} else {
1270 		ectx.ws = NULL;
1271 		ectx.ws_size = 0;
1272 	}
1273 
1274 	debug_depth++;
1275 	while (1) {
1276 		op = CU8(ptr++);
1277 		if (op < ATOM_OP_NAMES_CNT)
1278 			SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr - 1);
1279 		else
1280 			SDEBUG("[%d] @ 0x%04X\n", op, ptr - 1);
1281 		if (ectx.abort) {
1282 			DRM_ERROR("atombios stuck executing %04X (len %d, WS %d, PS %d) @ 0x%04X\n",
1283 				base, len, ws, ps, ptr - 1);
1284 			ret = -EINVAL;
1285 			goto free;
1286 		}
1287 
1288 		if (op < ATOM_OP_CNT && op > 0)
1289 			opcode_table[op].func(&ectx, &ptr,
1290 					      opcode_table[op].arg);
1291 		else
1292 			break;
1293 
1294 		if (op == ATOM_OP_EOT)
1295 			break;
1296 	}
1297 	debug_depth--;
1298 	SDEBUG("<<\n");
1299 
1300 free:
1301 	if (ws)
1302 		kfree(ectx.ws);
1303 	ctx->execute_depth--;
1304 	return ret;
1305 }
1306 
1307 int amdgpu_atom_execute_table(struct atom_context *ctx, int index, uint32_t *params, int params_size)
1308 {
1309 	int r;
1310 
1311 	mutex_lock(&ctx->mutex);
1312 	/* reset data block */
1313 	ctx->data_block = 0;
1314 	/* reset reg block */
1315 	ctx->reg_block = 0;
1316 	/* reset fb window */
1317 	ctx->fb_base = 0;
1318 	/* reset io mode */
1319 	ctx->io_mode = ATOM_IO_MM;
1320 	/* reset divmul */
1321 	ctx->divmul[0] = 0;
1322 	ctx->divmul[1] = 0;
1323 	r = amdgpu_atom_execute_table_locked(ctx, index, params, params_size);
1324 	mutex_unlock(&ctx->mutex);
1325 	return r;
1326 }
1327 
1328 static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 };
1329 
1330 static void atom_index_iio(struct atom_context *ctx, int base)
1331 {
1332 	ctx->iio = kzalloc(2 * 256, GFP_KERNEL);
1333 	if (!ctx->iio)
1334 		return;
1335 	while (base + 1 < ctx->bios_size && CU8(base) == ATOM_IIO_START) {
1336 		uint8_t index = CU8(base + 1);
1337 		int start = base + 2;
1338 		base += 2;
1339 		while (base < ctx->bios_size && CU8(base) != ATOM_IIO_END) {
1340 			uint8_t op = CU8(base);
1341 
1342 			/*
1343 			 * Unknown opcode: its length is unknown so the byte
1344 			 * stream cannot be resynced reliably.
1345 			 */
1346 			if (op >= ARRAY_SIZE(atom_iio_len))
1347 				return;
1348 			base += atom_iio_len[op];
1349 		}
1350 		if (base >= ctx->bios_size)
1351 			return;
1352 		/* Only index well-formed methods, others stay 0 */
1353 		ctx->iio[index] = start;
1354 		base += 3;
1355 	}
1356 }
1357 
1358 static void atom_get_vbios_name(struct atom_context *ctx)
1359 {
1360 	unsigned char *p_rom;
1361 	unsigned char *p_end;
1362 	unsigned char str_num;
1363 	unsigned short off_to_vbios_str;
1364 	unsigned char *c_ptr;
1365 	int name_size;
1366 	int i;
1367 
1368 	const char *na = "--N/A--";
1369 	char *back;
1370 
1371 	p_rom = ctx->bios;
1372 	p_end = p_rom + ctx->bios_size;
1373 
1374 	if (p_rom + OFFSET_TO_GET_ATOMBIOS_STRING_START + 1 >= p_end)
1375 		goto no_name;
1376 
1377 	str_num = *(p_rom + OFFSET_TO_GET_ATOMBIOS_NUMBER_OF_STRINGS);
1378 	if (!str_num)
1379 		goto no_name;
1380 
1381 	off_to_vbios_str =
1382 		*(unsigned short *)(p_rom + OFFSET_TO_GET_ATOMBIOS_STRING_START);
1383 
1384 	c_ptr = (unsigned char *)(p_rom + off_to_vbios_str);
1385 	if (c_ptr >= p_end)
1386 		goto no_name;
1387 
1388 	/*
1389 	 * skip the atombios strings, usually 4
1390 	 * 1st is P/N, 2nd is ASIC, 3rd is PCI type, 4th is Memory type
1391 	 */
1392 	for (i = 0; i < str_num; i++) {
1393 		while (c_ptr < p_end && *c_ptr != 0)
1394 			c_ptr++;
1395 		c_ptr++;
1396 	}
1397 
1398 	/* skip the following 2 chars: 0x0D 0x0A */
1399 	c_ptr += 2;
1400 	if (c_ptr >= p_end)
1401 		goto no_name;
1402 
1403 	name_size = strnlen(c_ptr, min(STRLEN_LONG - 1, (int)(p_end - c_ptr)));
1404 	memcpy(ctx->name, c_ptr, name_size);
1405 	back = ctx->name + name_size;
1406 	while ((*--back) == ' ')
1407 		;
1408 	*(back + 1) = '\0';
1409 	return;
1410 
1411 no_name:
1412 	/* do not know where to find name */
1413 	strscpy(ctx->name, na, sizeof(ctx->name));
1414 }
1415 
1416 static void atom_get_vbios_date(struct atom_context *ctx)
1417 {
1418 	unsigned char *p_rom;
1419 	unsigned char *date_in_rom;
1420 
1421 	p_rom = ctx->bios;
1422 
1423 	date_in_rom = p_rom + OFFSET_TO_VBIOS_DATE;
1424 
1425 	ctx->date[0] = '2';
1426 	ctx->date[1] = '0';
1427 	ctx->date[2] = date_in_rom[6];
1428 	ctx->date[3] = date_in_rom[7];
1429 	ctx->date[4] = '/';
1430 	ctx->date[5] = date_in_rom[0];
1431 	ctx->date[6] = date_in_rom[1];
1432 	ctx->date[7] = '/';
1433 	ctx->date[8] = date_in_rom[3];
1434 	ctx->date[9] = date_in_rom[4];
1435 	ctx->date[10] = ' ';
1436 	ctx->date[11] = date_in_rom[9];
1437 	ctx->date[12] = date_in_rom[10];
1438 	ctx->date[13] = date_in_rom[11];
1439 	ctx->date[14] = date_in_rom[12];
1440 	ctx->date[15] = date_in_rom[13];
1441 	ctx->date[16] = '\0';
1442 }
1443 
1444 static unsigned char *atom_find_str_in_rom(struct atom_context *ctx, char *str, int start,
1445 					   int end, int maxlen)
1446 {
1447 	unsigned long str_off;
1448 	unsigned char *p_rom;
1449 	unsigned short str_len;
1450 
1451 	str_off = 0;
1452 	str_len = strnlen(str, maxlen);
1453 	p_rom = ctx->bios;
1454 
1455 	for (; start <= end; ++start) {
1456 		for (str_off = 0; str_off < str_len; ++str_off) {
1457 			if (str[str_off] != *(p_rom + start + str_off))
1458 				break;
1459 		}
1460 
1461 		if (str_off == str_len || str[str_off] == 0)
1462 			return p_rom + start;
1463 	}
1464 	return NULL;
1465 }
1466 
1467 static void atom_get_vbios_pn(struct atom_context *ctx)
1468 {
1469 	unsigned char *p_rom;
1470 	unsigned short off_to_vbios_str;
1471 	unsigned char *vbios_str;
1472 	int count;
1473 
1474 	off_to_vbios_str = 0;
1475 	p_rom = ctx->bios;
1476 
1477 	if (*(p_rom + OFFSET_TO_GET_ATOMBIOS_NUMBER_OF_STRINGS) != 0) {
1478 		off_to_vbios_str =
1479 			*(unsigned short *)(p_rom + OFFSET_TO_GET_ATOMBIOS_STRING_START);
1480 
1481 		vbios_str = (unsigned char *)(p_rom + off_to_vbios_str);
1482 	} else {
1483 		vbios_str = p_rom + OFFSET_TO_VBIOS_PART_NUMBER;
1484 	}
1485 
1486 	if (*vbios_str == 0) {
1487 		vbios_str = atom_find_str_in_rom(ctx, BIOS_ATOM_PREFIX, 3, 1024, 64);
1488 		if (vbios_str == NULL)
1489 			vbios_str += sizeof(BIOS_ATOM_PREFIX) - 1;
1490 	}
1491 	OPTIMIZER_HIDE_VAR(vbios_str);
1492 	if (vbios_str != NULL && *vbios_str == 0)
1493 		vbios_str++;
1494 
1495 	if (vbios_str != NULL) {
1496 		count = 0;
1497 		while ((count < BIOS_STRING_LENGTH) && vbios_str[count] >= ' ' &&
1498 		       vbios_str[count] <= 'z') {
1499 			ctx->vbios_pn[count] = vbios_str[count];
1500 			count++;
1501 		}
1502 
1503 		ctx->vbios_pn[count] = 0;
1504 	}
1505 }
1506 
1507 static void atom_get_vbios_version(struct atom_context *ctx)
1508 {
1509 	unsigned short start = 3, end;
1510 	unsigned char *vbios_ver;
1511 	unsigned char *p_rom;
1512 
1513 	p_rom = ctx->bios;
1514 	/* Search from strings offset if it's present */
1515 	start = *(unsigned short *)(p_rom +
1516 				    OFFSET_TO_GET_ATOMBIOS_STRING_START);
1517 
1518 	/* Search till atom rom header start point */
1519 	end = *(unsigned short *)(p_rom + OFFSET_TO_ATOM_ROM_HEADER_POINTER);
1520 
1521 	/* Use hardcoded offsets, if the offsets are not populated */
1522 	if (end <= start) {
1523 		start = 3;
1524 		end = 1024;
1525 	}
1526 
1527 	/* find anchor ATOMBIOSBK-AMD */
1528 	vbios_ver =
1529 		atom_find_str_in_rom(ctx, BIOS_VERSION_PREFIX, start, end, 64);
1530 	if (vbios_ver != NULL) {
1531 		/* skip ATOMBIOSBK-AMD VER */
1532 		vbios_ver += 18;
1533 		memcpy(ctx->vbios_ver_str, vbios_ver, STRLEN_NORMAL);
1534 	} else {
1535 		ctx->vbios_ver_str[0] = '\0';
1536 	}
1537 }
1538 
1539 static void atom_get_vbios_build(struct atom_context *ctx)
1540 {
1541 	unsigned char *atom_rom_hdr;
1542 	unsigned char *str;
1543 	uint16_t base, len;
1544 
1545 	base = CU16(ATOM_ROM_TABLE_PTR);
1546 	atom_rom_hdr = CSTR(base);
1547 
1548 	str = CSTR(CU16(base + ATOM_ROM_CFG_PTR));
1549 	/* Skip config string */
1550 	while (str < atom_rom_hdr && *str++)
1551 		;
1552 	/* Skip change list string */
1553 	while (str < atom_rom_hdr && *str++)
1554 		;
1555 
1556 	len = min(atom_rom_hdr - str, STRLEN_NORMAL);
1557 	if (len)
1558 		strscpy(ctx->build_num, str, len);
1559 }
1560 
1561 static inline void atom_print_vbios_info(struct atom_context *ctx)
1562 {
1563 	char vbios_info[256];
1564 	int off = 0;
1565 
1566 	if (ctx->vbios_pn[0])
1567 		off += scnprintf(vbios_info + off, sizeof(vbios_info) - off,
1568 				 "%s", ctx->vbios_pn);
1569 	if (ctx->build_num[0])
1570 		off += scnprintf(vbios_info + off, sizeof(vbios_info) - off,
1571 				 "%sbuild: %s", off ? ", " : "",
1572 				 ctx->build_num);
1573 	if (ctx->vbios_ver_str[0])
1574 		off += scnprintf(vbios_info + off, sizeof(vbios_info) - off,
1575 				 "%sver: %s", off ? ", " : "",
1576 				 ctx->vbios_ver_str);
1577 	if (ctx->date[0])
1578 		off += scnprintf(vbios_info + off, sizeof(vbios_info) - off,
1579 				 "%s%.10s", off ? ", " : "",
1580 				 ctx->date);
1581 	if (off)
1582 		drm_info(ctx->card->dev, "ATOM BIOS: %s\n", vbios_info);
1583 }
1584 
1585 struct atom_context *amdgpu_atom_parse(struct card_info *card, void *bios, uint32_t bios_size)
1586 {
1587 	int base;
1588 	struct atom_context *ctx =
1589 	    kzalloc_obj(struct atom_context);
1590 	struct _ATOM_ROM_HEADER *atom_rom_header;
1591 	struct _ATOM_MASTER_DATA_TABLE *master_table;
1592 	struct _ATOM_FIRMWARE_INFO *atom_fw_info;
1593 
1594 	if (!ctx)
1595 		return NULL;
1596 
1597 	ctx->card = card;
1598 	ctx->bios = bios;
1599 	ctx->bios_size = bios_size;
1600 
1601 	if (CU16(0) != ATOM_BIOS_MAGIC) {
1602 		pr_info("Invalid BIOS magic\n");
1603 		kfree(ctx);
1604 		return NULL;
1605 	}
1606 	if (strncmp
1607 	    (CSTR(ATOM_ATI_MAGIC_PTR), ATOM_ATI_MAGIC,
1608 	     strlen(ATOM_ATI_MAGIC))) {
1609 		pr_info("Invalid ATI magic\n");
1610 		kfree(ctx);
1611 		return NULL;
1612 	}
1613 
1614 	base = CU16(ATOM_ROM_TABLE_PTR);
1615 	if (strncmp
1616 	    (CSTR(base + ATOM_ROM_MAGIC_PTR), ATOM_ROM_MAGIC,
1617 	     strlen(ATOM_ROM_MAGIC))) {
1618 		pr_info("Invalid ATOM magic\n");
1619 		kfree(ctx);
1620 		return NULL;
1621 	}
1622 
1623 	ctx->cmd_table = CU16(base + ATOM_ROM_CMD_PTR);
1624 	ctx->data_table = CU16(base + ATOM_ROM_DATA_PTR);
1625 	atom_index_iio(ctx, CU16(ctx->data_table + ATOM_DATA_IIO_PTR) + 4);
1626 	if (!ctx->iio) {
1627 		amdgpu_atom_destroy(ctx);
1628 		return NULL;
1629 	}
1630 
1631 	atom_rom_header = (struct _ATOM_ROM_HEADER *)CSTR(base);
1632 	if (atom_rom_header->usMasterDataTableOffset != 0) {
1633 		master_table = (struct _ATOM_MASTER_DATA_TABLE *)
1634 				CSTR(atom_rom_header->usMasterDataTableOffset);
1635 		if (master_table->ListOfDataTables.FirmwareInfo != 0) {
1636 			atom_fw_info = (struct _ATOM_FIRMWARE_INFO *)
1637 					CSTR(master_table->ListOfDataTables.FirmwareInfo);
1638 			ctx->version = atom_fw_info->ulFirmwareRevision;
1639 		}
1640 	}
1641 
1642 	atom_get_vbios_name(ctx);
1643 	atom_get_vbios_pn(ctx);
1644 	atom_get_vbios_date(ctx);
1645 	atom_get_vbios_version(ctx);
1646 	atom_get_vbios_build(ctx);
1647 
1648 	atom_print_vbios_info(ctx);
1649 
1650 	return ctx;
1651 }
1652 
1653 int amdgpu_atom_asic_init(struct atom_context *ctx)
1654 {
1655 	int hwi = CU16(ctx->data_table + ATOM_DATA_FWI_PTR);
1656 	uint32_t ps[16];
1657 	int ret;
1658 
1659 	memset(ps, 0, 64);
1660 
1661 	ps[0] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFSCLK_PTR));
1662 	ps[1] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFMCLK_PTR));
1663 	if (!ps[0] || !ps[1])
1664 		return 1;
1665 
1666 	if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT))
1667 		return 1;
1668 	ret = amdgpu_atom_execute_table(ctx, ATOM_CMD_INIT, ps, 16);
1669 	if (ret)
1670 		return ret;
1671 
1672 	memset(ps, 0, 64);
1673 
1674 	return ret;
1675 }
1676 
1677 void amdgpu_atom_destroy(struct atom_context *ctx)
1678 {
1679 	kfree(ctx->iio);
1680 	kfree(ctx);
1681 }
1682 
1683 bool amdgpu_atom_parse_data_header(struct atom_context *ctx, int index,
1684 			    uint16_t *size, uint8_t *frev, uint8_t *crev,
1685 			    uint16_t *data_start)
1686 {
1687 	int offset = index * 2 + 4;
1688 	int idx = CU16(ctx->data_table + offset);
1689 	u16 *mdt = (u16 *)(ctx->bios + ctx->data_table + 4);
1690 
1691 	if (!mdt[index])
1692 		return false;
1693 
1694 	if (size)
1695 		*size = CU16(idx);
1696 	if (frev)
1697 		*frev = CU8(idx + 2);
1698 	if (crev)
1699 		*crev = CU8(idx + 3);
1700 	*data_start = idx;
1701 	return true;
1702 }
1703 
1704 bool amdgpu_atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t *frev,
1705 			   uint8_t *crev)
1706 {
1707 	int offset = index * 2 + 4;
1708 	int idx = CU16(ctx->cmd_table + offset);
1709 	u16 *mct = (u16 *)(ctx->bios + ctx->cmd_table + 4);
1710 
1711 	if (!mct[index])
1712 		return false;
1713 
1714 	if (frev)
1715 		*frev = CU8(idx + 2);
1716 	if (crev)
1717 		*crev = CU8(idx + 3);
1718 	return true;
1719 }
1720 
1721