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