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 <asm/unaligned.h>
29 
30 #define ATOM_DEBUG
31 
32 #include "atom.h"
33 #include "atom-names.h"
34 #include "atom-bits.h"
35 #include "radeon.h"
36 
37 #define ATOM_COND_ABOVE		0
38 #define ATOM_COND_ABOVEOREQUAL	1
39 #define ATOM_COND_ALWAYS	2
40 #define ATOM_COND_BELOW		3
41 #define ATOM_COND_BELOWOREQUAL	4
42 #define ATOM_COND_EQUAL		5
43 #define ATOM_COND_NOTEQUAL	6
44 
45 #define ATOM_PORT_ATI	0
46 #define ATOM_PORT_PCI	1
47 #define ATOM_PORT_SYSIO	2
48 
49 #define ATOM_UNIT_MICROSEC	0
50 #define ATOM_UNIT_MILLISEC	1
51 
52 #define PLL_INDEX	2
53 #define PLL_DATA	3
54 
55 typedef struct {
56 	struct atom_context *ctx;
57 	uint32_t *ps, *ws;
58 	int ps_shift;
59 	uint16_t start;
60 	unsigned last_jump;
61 	unsigned long last_jump_jiffies;
62 	bool abort;
63 } atom_exec_context;
64 
65 int atom_debug = 0;
66 static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params);
67 int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params);
68 
69 static uint32_t atom_arg_mask[8] =
70     { 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000,
71 0xFF000000 };
72 static int atom_arg_shift[8] = { 0, 0, 8, 16, 0, 8, 16, 24 };
73 
74 static int atom_dst_to_src[8][4] = {
75 	/* translate destination alignment field to the source alignment encoding */
76 	{0, 0, 0, 0},
77 	{1, 2, 3, 0},
78 	{1, 2, 3, 0},
79 	{1, 2, 3, 0},
80 	{4, 5, 6, 7},
81 	{4, 5, 6, 7},
82 	{4, 5, 6, 7},
83 	{4, 5, 6, 7},
84 };
85 static int atom_def_dst[8] = { 0, 0, 1, 2, 0, 1, 2, 3 };
86 
87 static int debug_depth = 0;
88 #ifdef ATOM_DEBUG
debug_print_spaces(int n)89 static void debug_print_spaces(int n)
90 {
91 	while (n--)
92 		printk("   ");
93 }
94 
95 #define DEBUG(...) do if (atom_debug) { printk(KERN_DEBUG __VA_ARGS__); } while (0)
96 #define SDEBUG(...) do if (atom_debug) { printk(KERN_DEBUG); debug_print_spaces(debug_depth); printk(__VA_ARGS__); } while (0)
97 #else
98 #define DEBUG(...) do { } while (0)
99 #define SDEBUG(...) do { } while (0)
100 #endif
101 
atom_iio_execute(struct atom_context * ctx,int base,uint32_t index,uint32_t data)102 static uint32_t atom_iio_execute(struct atom_context *ctx, int base,
103 				 uint32_t index, uint32_t data)
104 {
105 	struct radeon_device *rdev = ctx->card->dev->dev_private;
106 	uint32_t temp = 0xCDCDCDCD;
107 
108 	while (1)
109 		switch (CU8(base)) {
110 		case ATOM_IIO_NOP:
111 			base++;
112 			break;
113 		case ATOM_IIO_READ:
114 			temp = ctx->card->ioreg_read(ctx->card, CU16(base + 1));
115 			base += 3;
116 			break;
117 		case ATOM_IIO_WRITE:
118 			if (rdev->family == CHIP_RV515)
119 				(void)ctx->card->ioreg_read(ctx->card, CU16(base + 1));
120 			ctx->card->ioreg_write(ctx->card, CU16(base + 1), temp);
121 			base += 3;
122 			break;
123 		case ATOM_IIO_CLEAR:
124 			temp &=
125 			    ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
126 			      CU8(base + 2));
127 			base += 3;
128 			break;
129 		case ATOM_IIO_SET:
130 			temp |=
131 			    (0xFFFFFFFF >> (32 - CU8(base + 1))) << CU8(base +
132 									2);
133 			base += 3;
134 			break;
135 		case ATOM_IIO_MOVE_INDEX:
136 			temp &=
137 			    ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
138 			      CU8(base + 3));
139 			temp |=
140 			    ((index >> CU8(base + 2)) &
141 			     (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base +
142 									  3);
143 			base += 4;
144 			break;
145 		case ATOM_IIO_MOVE_DATA:
146 			temp &=
147 			    ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
148 			      CU8(base + 3));
149 			temp |=
150 			    ((data >> CU8(base + 2)) &
151 			     (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base +
152 									  3);
153 			base += 4;
154 			break;
155 		case ATOM_IIO_MOVE_ATTR:
156 			temp &=
157 			    ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
158 			      CU8(base + 3));
159 			temp |=
160 			    ((ctx->
161 			      io_attr >> CU8(base + 2)) & (0xFFFFFFFF >> (32 -
162 									  CU8
163 									  (base
164 									   +
165 									   1))))
166 			    << CU8(base + 3);
167 			base += 4;
168 			break;
169 		case ATOM_IIO_END:
170 			return temp;
171 		default:
172 			printk(KERN_INFO "Unknown IIO opcode.\n");
173 			return 0;
174 		}
175 }
176 
atom_get_src_int(atom_exec_context * ctx,uint8_t attr,int * ptr,uint32_t * saved,int print)177 static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr,
178 				 int *ptr, uint32_t *saved, int print)
179 {
180 	uint32_t idx, val = 0xCDCDCDCD, align, arg;
181 	struct atom_context *gctx = ctx->ctx;
182 	arg = attr & 7;
183 	align = (attr >> 3) & 7;
184 	switch (arg) {
185 	case ATOM_ARG_REG:
186 		idx = U16(*ptr);
187 		(*ptr) += 2;
188 		if (print)
189 			DEBUG("REG[0x%04X]", idx);
190 		idx += gctx->reg_block;
191 		switch (gctx->io_mode) {
192 		case ATOM_IO_MM:
193 			val = gctx->card->reg_read(gctx->card, idx);
194 			break;
195 		case ATOM_IO_PCI:
196 			printk(KERN_INFO
197 			       "PCI registers are not implemented.\n");
198 			return 0;
199 		case ATOM_IO_SYSIO:
200 			printk(KERN_INFO
201 			       "SYSIO registers are not implemented.\n");
202 			return 0;
203 		default:
204 			if (!(gctx->io_mode & 0x80)) {
205 				printk(KERN_INFO "Bad IO mode.\n");
206 				return 0;
207 			}
208 			if (!gctx->iio[gctx->io_mode & 0x7F]) {
209 				printk(KERN_INFO
210 				       "Undefined indirect IO read method %d.\n",
211 				       gctx->io_mode & 0x7F);
212 				return 0;
213 			}
214 			val =
215 			    atom_iio_execute(gctx,
216 					     gctx->iio[gctx->io_mode & 0x7F],
217 					     idx, 0);
218 		}
219 		break;
220 	case ATOM_ARG_PS:
221 		idx = U8(*ptr);
222 		(*ptr)++;
223 		/* get_unaligned_le32 avoids unaligned accesses from atombios
224 		 * tables, noticed on a DEC Alpha. */
225 		val = get_unaligned_le32((u32 *)&ctx->ps[idx]);
226 		if (print)
227 			DEBUG("PS[0x%02X,0x%04X]", idx, val);
228 		break;
229 	case ATOM_ARG_WS:
230 		idx = U8(*ptr);
231 		(*ptr)++;
232 		if (print)
233 			DEBUG("WS[0x%02X]", idx);
234 		switch (idx) {
235 		case ATOM_WS_QUOTIENT:
236 			val = gctx->divmul[0];
237 			break;
238 		case ATOM_WS_REMAINDER:
239 			val = gctx->divmul[1];
240 			break;
241 		case ATOM_WS_DATAPTR:
242 			val = gctx->data_block;
243 			break;
244 		case ATOM_WS_SHIFT:
245 			val = gctx->shift;
246 			break;
247 		case ATOM_WS_OR_MASK:
248 			val = 1 << gctx->shift;
249 			break;
250 		case ATOM_WS_AND_MASK:
251 			val = ~(1 << gctx->shift);
252 			break;
253 		case ATOM_WS_FB_WINDOW:
254 			val = gctx->fb_base;
255 			break;
256 		case ATOM_WS_ATTRIBUTES:
257 			val = gctx->io_attr;
258 			break;
259 		case ATOM_WS_REGPTR:
260 			val = gctx->reg_block;
261 			break;
262 		default:
263 			val = ctx->ws[idx];
264 		}
265 		break;
266 	case ATOM_ARG_ID:
267 		idx = U16(*ptr);
268 		(*ptr) += 2;
269 		if (print) {
270 			if (gctx->data_block)
271 				DEBUG("ID[0x%04X+%04X]", idx, gctx->data_block);
272 			else
273 				DEBUG("ID[0x%04X]", idx);
274 		}
275 		val = U32(idx + gctx->data_block);
276 		break;
277 	case ATOM_ARG_FB:
278 		idx = U8(*ptr);
279 		(*ptr)++;
280 		val = gctx->scratch[((gctx->fb_base + idx) / 4)];
281 		if (print)
282 			DEBUG("FB[0x%02X]", idx);
283 		break;
284 	case ATOM_ARG_IMM:
285 		switch (align) {
286 		case ATOM_SRC_DWORD:
287 			val = U32(*ptr);
288 			(*ptr) += 4;
289 			if (print)
290 				DEBUG("IMM 0x%08X\n", val);
291 			return val;
292 		case ATOM_SRC_WORD0:
293 		case ATOM_SRC_WORD8:
294 		case ATOM_SRC_WORD16:
295 			val = U16(*ptr);
296 			(*ptr) += 2;
297 			if (print)
298 				DEBUG("IMM 0x%04X\n", val);
299 			return val;
300 		case ATOM_SRC_BYTE0:
301 		case ATOM_SRC_BYTE8:
302 		case ATOM_SRC_BYTE16:
303 		case ATOM_SRC_BYTE24:
304 			val = U8(*ptr);
305 			(*ptr)++;
306 			if (print)
307 				DEBUG("IMM 0x%02X\n", val);
308 			return val;
309 		}
310 		return 0;
311 	case ATOM_ARG_PLL:
312 		idx = U8(*ptr);
313 		(*ptr)++;
314 		if (print)
315 			DEBUG("PLL[0x%02X]", idx);
316 		val = gctx->card->pll_read(gctx->card, idx);
317 		break;
318 	case ATOM_ARG_MC:
319 		idx = U8(*ptr);
320 		(*ptr)++;
321 		if (print)
322 			DEBUG("MC[0x%02X]", idx);
323 		val = gctx->card->mc_read(gctx->card, idx);
324 		break;
325 	}
326 	if (saved)
327 		*saved = val;
328 	val &= atom_arg_mask[align];
329 	val >>= atom_arg_shift[align];
330 	if (print)
331 		switch (align) {
332 		case ATOM_SRC_DWORD:
333 			DEBUG(".[31:0] -> 0x%08X\n", val);
334 			break;
335 		case ATOM_SRC_WORD0:
336 			DEBUG(".[15:0] -> 0x%04X\n", val);
337 			break;
338 		case ATOM_SRC_WORD8:
339 			DEBUG(".[23:8] -> 0x%04X\n", val);
340 			break;
341 		case ATOM_SRC_WORD16:
342 			DEBUG(".[31:16] -> 0x%04X\n", val);
343 			break;
344 		case ATOM_SRC_BYTE0:
345 			DEBUG(".[7:0] -> 0x%02X\n", val);
346 			break;
347 		case ATOM_SRC_BYTE8:
348 			DEBUG(".[15:8] -> 0x%02X\n", val);
349 			break;
350 		case ATOM_SRC_BYTE16:
351 			DEBUG(".[23:16] -> 0x%02X\n", val);
352 			break;
353 		case ATOM_SRC_BYTE24:
354 			DEBUG(".[31:24] -> 0x%02X\n", val);
355 			break;
356 		}
357 	return val;
358 }
359 
atom_skip_src_int(atom_exec_context * ctx,uint8_t attr,int * ptr)360 static void atom_skip_src_int(atom_exec_context *ctx, uint8_t attr, int *ptr)
361 {
362 	uint32_t align = (attr >> 3) & 7, arg = attr & 7;
363 	switch (arg) {
364 	case ATOM_ARG_REG:
365 	case ATOM_ARG_ID:
366 		(*ptr) += 2;
367 		break;
368 	case ATOM_ARG_PLL:
369 	case ATOM_ARG_MC:
370 	case ATOM_ARG_PS:
371 	case ATOM_ARG_WS:
372 	case ATOM_ARG_FB:
373 		(*ptr)++;
374 		break;
375 	case ATOM_ARG_IMM:
376 		switch (align) {
377 		case ATOM_SRC_DWORD:
378 			(*ptr) += 4;
379 			return;
380 		case ATOM_SRC_WORD0:
381 		case ATOM_SRC_WORD8:
382 		case ATOM_SRC_WORD16:
383 			(*ptr) += 2;
384 			return;
385 		case ATOM_SRC_BYTE0:
386 		case ATOM_SRC_BYTE8:
387 		case ATOM_SRC_BYTE16:
388 		case ATOM_SRC_BYTE24:
389 			(*ptr)++;
390 			return;
391 		}
392 		return;
393 	}
394 }
395 
atom_get_src(atom_exec_context * ctx,uint8_t attr,int * ptr)396 static uint32_t atom_get_src(atom_exec_context *ctx, uint8_t attr, int *ptr)
397 {
398 	return atom_get_src_int(ctx, attr, ptr, NULL, 1);
399 }
400 
atom_get_src_direct(atom_exec_context * ctx,uint8_t align,int * ptr)401 static uint32_t atom_get_src_direct(atom_exec_context *ctx, uint8_t align, int *ptr)
402 {
403 	uint32_t val = 0xCDCDCDCD;
404 
405 	switch (align) {
406 	case ATOM_SRC_DWORD:
407 		val = U32(*ptr);
408 		(*ptr) += 4;
409 		break;
410 	case ATOM_SRC_WORD0:
411 	case ATOM_SRC_WORD8:
412 	case ATOM_SRC_WORD16:
413 		val = U16(*ptr);
414 		(*ptr) += 2;
415 		break;
416 	case ATOM_SRC_BYTE0:
417 	case ATOM_SRC_BYTE8:
418 	case ATOM_SRC_BYTE16:
419 	case ATOM_SRC_BYTE24:
420 		val = U8(*ptr);
421 		(*ptr)++;
422 		break;
423 	}
424 	return val;
425 }
426 
atom_get_dst(atom_exec_context * ctx,int arg,uint8_t attr,int * ptr,uint32_t * saved,int print)427 static uint32_t atom_get_dst(atom_exec_context *ctx, int arg, uint8_t attr,
428 			     int *ptr, uint32_t *saved, int print)
429 {
430 	return atom_get_src_int(ctx,
431 				arg | atom_dst_to_src[(attr >> 3) &
432 						      7][(attr >> 6) & 3] << 3,
433 				ptr, saved, print);
434 }
435 
atom_skip_dst(atom_exec_context * ctx,int arg,uint8_t attr,int * ptr)436 static void atom_skip_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr)
437 {
438 	atom_skip_src_int(ctx,
439 			  arg | atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) &
440 								 3] << 3, ptr);
441 }
442 
atom_put_dst(atom_exec_context * ctx,int arg,uint8_t attr,int * ptr,uint32_t val,uint32_t saved)443 static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr,
444 			 int *ptr, uint32_t val, uint32_t saved)
445 {
446 	uint32_t align =
447 	    atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3], old_val =
448 	    val, idx;
449 	struct atom_context *gctx = ctx->ctx;
450 	old_val &= atom_arg_mask[align] >> atom_arg_shift[align];
451 	val <<= atom_arg_shift[align];
452 	val &= atom_arg_mask[align];
453 	saved &= ~atom_arg_mask[align];
454 	val |= saved;
455 	switch (arg) {
456 	case ATOM_ARG_REG:
457 		idx = U16(*ptr);
458 		(*ptr) += 2;
459 		DEBUG("REG[0x%04X]", idx);
460 		idx += gctx->reg_block;
461 		switch (gctx->io_mode) {
462 		case ATOM_IO_MM:
463 			if (idx == 0)
464 				gctx->card->reg_write(gctx->card, idx,
465 						      val << 2);
466 			else
467 				gctx->card->reg_write(gctx->card, idx, val);
468 			break;
469 		case ATOM_IO_PCI:
470 			printk(KERN_INFO
471 			       "PCI registers are not implemented.\n");
472 			return;
473 		case ATOM_IO_SYSIO:
474 			printk(KERN_INFO
475 			       "SYSIO registers are not implemented.\n");
476 			return;
477 		default:
478 			if (!(gctx->io_mode & 0x80)) {
479 				printk(KERN_INFO "Bad IO mode.\n");
480 				return;
481 			}
482 			if (!gctx->iio[gctx->io_mode & 0xFF]) {
483 				printk(KERN_INFO
484 				       "Undefined indirect IO write method %d.\n",
485 				       gctx->io_mode & 0x7F);
486 				return;
487 			}
488 			atom_iio_execute(gctx, gctx->iio[gctx->io_mode & 0xFF],
489 					 idx, val);
490 		}
491 		break;
492 	case ATOM_ARG_PS:
493 		idx = U8(*ptr);
494 		(*ptr)++;
495 		DEBUG("PS[0x%02X]", idx);
496 		ctx->ps[idx] = cpu_to_le32(val);
497 		break;
498 	case ATOM_ARG_WS:
499 		idx = U8(*ptr);
500 		(*ptr)++;
501 		DEBUG("WS[0x%02X]", idx);
502 		switch (idx) {
503 		case ATOM_WS_QUOTIENT:
504 			gctx->divmul[0] = val;
505 			break;
506 		case ATOM_WS_REMAINDER:
507 			gctx->divmul[1] = val;
508 			break;
509 		case ATOM_WS_DATAPTR:
510 			gctx->data_block = val;
511 			break;
512 		case ATOM_WS_SHIFT:
513 			gctx->shift = val;
514 			break;
515 		case ATOM_WS_OR_MASK:
516 		case ATOM_WS_AND_MASK:
517 			break;
518 		case ATOM_WS_FB_WINDOW:
519 			gctx->fb_base = val;
520 			break;
521 		case ATOM_WS_ATTRIBUTES:
522 			gctx->io_attr = val;
523 			break;
524 		case ATOM_WS_REGPTR:
525 			gctx->reg_block = val;
526 			break;
527 		default:
528 			ctx->ws[idx] = val;
529 		}
530 		break;
531 	case ATOM_ARG_FB:
532 		idx = U8(*ptr);
533 		(*ptr)++;
534 		gctx->scratch[((gctx->fb_base + idx) / 4)] = val;
535 		DEBUG("FB[0x%02X]", idx);
536 		break;
537 	case ATOM_ARG_PLL:
538 		idx = U8(*ptr);
539 		(*ptr)++;
540 		DEBUG("PLL[0x%02X]", idx);
541 		gctx->card->pll_write(gctx->card, idx, val);
542 		break;
543 	case ATOM_ARG_MC:
544 		idx = U8(*ptr);
545 		(*ptr)++;
546 		DEBUG("MC[0x%02X]", idx);
547 		gctx->card->mc_write(gctx->card, idx, val);
548 		return;
549 	}
550 	switch (align) {
551 	case ATOM_SRC_DWORD:
552 		DEBUG(".[31:0] <- 0x%08X\n", old_val);
553 		break;
554 	case ATOM_SRC_WORD0:
555 		DEBUG(".[15:0] <- 0x%04X\n", old_val);
556 		break;
557 	case ATOM_SRC_WORD8:
558 		DEBUG(".[23:8] <- 0x%04X\n", old_val);
559 		break;
560 	case ATOM_SRC_WORD16:
561 		DEBUG(".[31:16] <- 0x%04X\n", old_val);
562 		break;
563 	case ATOM_SRC_BYTE0:
564 		DEBUG(".[7:0] <- 0x%02X\n", old_val);
565 		break;
566 	case ATOM_SRC_BYTE8:
567 		DEBUG(".[15:8] <- 0x%02X\n", old_val);
568 		break;
569 	case ATOM_SRC_BYTE16:
570 		DEBUG(".[23:16] <- 0x%02X\n", old_val);
571 		break;
572 	case ATOM_SRC_BYTE24:
573 		DEBUG(".[31:24] <- 0x%02X\n", old_val);
574 		break;
575 	}
576 }
577 
atom_op_add(atom_exec_context * ctx,int * ptr,int arg)578 static void atom_op_add(atom_exec_context *ctx, int *ptr, int arg)
579 {
580 	uint8_t attr = U8((*ptr)++);
581 	uint32_t dst, src, saved;
582 	int dptr = *ptr;
583 	SDEBUG("   dst: ");
584 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
585 	SDEBUG("   src: ");
586 	src = atom_get_src(ctx, attr, ptr);
587 	dst += src;
588 	SDEBUG("   dst: ");
589 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
590 }
591 
atom_op_and(atom_exec_context * ctx,int * ptr,int arg)592 static void atom_op_and(atom_exec_context *ctx, int *ptr, int arg)
593 {
594 	uint8_t attr = U8((*ptr)++);
595 	uint32_t dst, src, saved;
596 	int dptr = *ptr;
597 	SDEBUG("   dst: ");
598 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
599 	SDEBUG("   src: ");
600 	src = atom_get_src(ctx, attr, ptr);
601 	dst &= src;
602 	SDEBUG("   dst: ");
603 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
604 }
605 
atom_op_beep(atom_exec_context * ctx,int * ptr,int arg)606 static void atom_op_beep(atom_exec_context *ctx, int *ptr, int arg)
607 {
608 	printk("ATOM BIOS beeped!\n");
609 }
610 
atom_op_calltable(atom_exec_context * ctx,int * ptr,int arg)611 static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg)
612 {
613 	int idx = U8((*ptr)++);
614 	int r = 0;
615 
616 	if (idx < ATOM_TABLE_NAMES_CNT)
617 		SDEBUG("   table: %d (%s)\n", idx, atom_table_names[idx]);
618 	else
619 		SDEBUG("   table: %d\n", idx);
620 	if (U16(ctx->ctx->cmd_table + 4 + 2 * idx))
621 		r = atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift);
622 	if (r) {
623 		ctx->abort = true;
624 	}
625 }
626 
atom_op_clear(atom_exec_context * ctx,int * ptr,int arg)627 static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg)
628 {
629 	uint8_t attr = U8((*ptr)++);
630 	uint32_t saved;
631 	int dptr = *ptr;
632 	attr &= 0x38;
633 	attr |= atom_def_dst[attr >> 3] << 6;
634 	atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
635 	SDEBUG("   dst: ");
636 	atom_put_dst(ctx, arg, attr, &dptr, 0, saved);
637 }
638 
atom_op_compare(atom_exec_context * ctx,int * ptr,int arg)639 static void atom_op_compare(atom_exec_context *ctx, int *ptr, int arg)
640 {
641 	uint8_t attr = U8((*ptr)++);
642 	uint32_t dst, src;
643 	SDEBUG("   src1: ");
644 	dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
645 	SDEBUG("   src2: ");
646 	src = atom_get_src(ctx, attr, ptr);
647 	ctx->ctx->cs_equal = (dst == src);
648 	ctx->ctx->cs_above = (dst > src);
649 	SDEBUG("   result: %s %s\n", ctx->ctx->cs_equal ? "EQ" : "NE",
650 	       ctx->ctx->cs_above ? "GT" : "LE");
651 }
652 
atom_op_delay(atom_exec_context * ctx,int * ptr,int arg)653 static void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg)
654 {
655 	uint8_t count = U8((*ptr)++);
656 	SDEBUG("   count: %d\n", count);
657 	if (arg == ATOM_UNIT_MICROSEC)
658 		udelay(count);
659 	else
660 		schedule_timeout_uninterruptible(msecs_to_jiffies(count));
661 }
662 
atom_op_div(atom_exec_context * ctx,int * ptr,int arg)663 static void atom_op_div(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 	if (src != 0) {
672 		ctx->ctx->divmul[0] = dst / src;
673 		ctx->ctx->divmul[1] = dst % src;
674 	} else {
675 		ctx->ctx->divmul[0] = 0;
676 		ctx->ctx->divmul[1] = 0;
677 	}
678 }
679 
atom_op_eot(atom_exec_context * ctx,int * ptr,int arg)680 static void atom_op_eot(atom_exec_context *ctx, int *ptr, int arg)
681 {
682 	/* functionally, a nop */
683 }
684 
atom_op_jump(atom_exec_context * ctx,int * ptr,int arg)685 static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
686 {
687 	int execute = 0, target = U16(*ptr);
688 	unsigned long cjiffies;
689 
690 	(*ptr) += 2;
691 	switch (arg) {
692 	case ATOM_COND_ABOVE:
693 		execute = ctx->ctx->cs_above;
694 		break;
695 	case ATOM_COND_ABOVEOREQUAL:
696 		execute = ctx->ctx->cs_above || ctx->ctx->cs_equal;
697 		break;
698 	case ATOM_COND_ALWAYS:
699 		execute = 1;
700 		break;
701 	case ATOM_COND_BELOW:
702 		execute = !(ctx->ctx->cs_above || ctx->ctx->cs_equal);
703 		break;
704 	case ATOM_COND_BELOWOREQUAL:
705 		execute = !ctx->ctx->cs_above;
706 		break;
707 	case ATOM_COND_EQUAL:
708 		execute = ctx->ctx->cs_equal;
709 		break;
710 	case ATOM_COND_NOTEQUAL:
711 		execute = !ctx->ctx->cs_equal;
712 		break;
713 	}
714 	if (arg != ATOM_COND_ALWAYS)
715 		SDEBUG("   taken: %s\n", execute ? "yes" : "no");
716 	SDEBUG("   target: 0x%04X\n", target);
717 	if (execute) {
718 		if (ctx->last_jump == (ctx->start + target)) {
719 			cjiffies = jiffies;
720 			if (time_after(cjiffies, ctx->last_jump_jiffies)) {
721 				cjiffies -= ctx->last_jump_jiffies;
722 				if ((jiffies_to_msecs(cjiffies) > 5000)) {
723 					DRM_ERROR("atombios stuck in loop for more than 5secs aborting\n");
724 					ctx->abort = true;
725 				}
726 			} else {
727 				/* jiffies wrap around we will just wait a little longer */
728 				ctx->last_jump_jiffies = jiffies;
729 			}
730 		} else {
731 			ctx->last_jump = ctx->start + target;
732 			ctx->last_jump_jiffies = jiffies;
733 		}
734 		*ptr = ctx->start + target;
735 	}
736 }
737 
atom_op_mask(atom_exec_context * ctx,int * ptr,int arg)738 static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg)
739 {
740 	uint8_t attr = U8((*ptr)++);
741 	uint32_t dst, mask, src, saved;
742 	int dptr = *ptr;
743 	SDEBUG("   dst: ");
744 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
745 	mask = atom_get_src_direct(ctx, ((attr >> 3) & 7), ptr);
746 	SDEBUG("   mask: 0x%08x", mask);
747 	SDEBUG("   src: ");
748 	src = atom_get_src(ctx, attr, ptr);
749 	dst &= mask;
750 	dst |= src;
751 	SDEBUG("   dst: ");
752 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
753 }
754 
atom_op_move(atom_exec_context * ctx,int * ptr,int arg)755 static void atom_op_move(atom_exec_context *ctx, int *ptr, int arg)
756 {
757 	uint8_t attr = U8((*ptr)++);
758 	uint32_t src, saved;
759 	int dptr = *ptr;
760 	if (((attr >> 3) & 7) != ATOM_SRC_DWORD)
761 		atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
762 	else {
763 		atom_skip_dst(ctx, arg, attr, ptr);
764 		saved = 0xCDCDCDCD;
765 	}
766 	SDEBUG("   src: ");
767 	src = atom_get_src(ctx, attr, ptr);
768 	SDEBUG("   dst: ");
769 	atom_put_dst(ctx, arg, attr, &dptr, src, saved);
770 }
771 
atom_op_mul(atom_exec_context * ctx,int * ptr,int arg)772 static void atom_op_mul(atom_exec_context *ctx, int *ptr, int arg)
773 {
774 	uint8_t attr = U8((*ptr)++);
775 	uint32_t dst, src;
776 	SDEBUG("   src1: ");
777 	dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
778 	SDEBUG("   src2: ");
779 	src = atom_get_src(ctx, attr, ptr);
780 	ctx->ctx->divmul[0] = dst * src;
781 }
782 
atom_op_nop(atom_exec_context * ctx,int * ptr,int arg)783 static void atom_op_nop(atom_exec_context *ctx, int *ptr, int arg)
784 {
785 	/* nothing */
786 }
787 
atom_op_or(atom_exec_context * ctx,int * ptr,int arg)788 static void atom_op_or(atom_exec_context *ctx, int *ptr, int arg)
789 {
790 	uint8_t attr = U8((*ptr)++);
791 	uint32_t dst, src, saved;
792 	int dptr = *ptr;
793 	SDEBUG("   dst: ");
794 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
795 	SDEBUG("   src: ");
796 	src = atom_get_src(ctx, attr, ptr);
797 	dst |= src;
798 	SDEBUG("   dst: ");
799 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
800 }
801 
atom_op_postcard(atom_exec_context * ctx,int * ptr,int arg)802 static void atom_op_postcard(atom_exec_context *ctx, int *ptr, int arg)
803 {
804 	uint8_t val = U8((*ptr)++);
805 	SDEBUG("POST card output: 0x%02X\n", val);
806 }
807 
atom_op_repeat(atom_exec_context * ctx,int * ptr,int arg)808 static void atom_op_repeat(atom_exec_context *ctx, int *ptr, int arg)
809 {
810 	printk(KERN_INFO "unimplemented!\n");
811 }
812 
atom_op_restorereg(atom_exec_context * ctx,int * ptr,int arg)813 static void atom_op_restorereg(atom_exec_context *ctx, int *ptr, int arg)
814 {
815 	printk(KERN_INFO "unimplemented!\n");
816 }
817 
atom_op_savereg(atom_exec_context * ctx,int * ptr,int arg)818 static void atom_op_savereg(atom_exec_context *ctx, int *ptr, int arg)
819 {
820 	printk(KERN_INFO "unimplemented!\n");
821 }
822 
atom_op_setdatablock(atom_exec_context * ctx,int * ptr,int arg)823 static void atom_op_setdatablock(atom_exec_context *ctx, int *ptr, int arg)
824 {
825 	int idx = U8(*ptr);
826 	(*ptr)++;
827 	SDEBUG("   block: %d\n", idx);
828 	if (!idx)
829 		ctx->ctx->data_block = 0;
830 	else if (idx == 255)
831 		ctx->ctx->data_block = ctx->start;
832 	else
833 		ctx->ctx->data_block = U16(ctx->ctx->data_table + 4 + 2 * idx);
834 	SDEBUG("   base: 0x%04X\n", ctx->ctx->data_block);
835 }
836 
atom_op_setfbbase(atom_exec_context * ctx,int * ptr,int arg)837 static void atom_op_setfbbase(atom_exec_context *ctx, int *ptr, int arg)
838 {
839 	uint8_t attr = U8((*ptr)++);
840 	SDEBUG("   fb_base: ");
841 	ctx->ctx->fb_base = atom_get_src(ctx, attr, ptr);
842 }
843 
atom_op_setport(atom_exec_context * ctx,int * ptr,int arg)844 static void atom_op_setport(atom_exec_context *ctx, int *ptr, int arg)
845 {
846 	int port;
847 	switch (arg) {
848 	case ATOM_PORT_ATI:
849 		port = U16(*ptr);
850 		if (port < ATOM_IO_NAMES_CNT)
851 			SDEBUG("   port: %d (%s)\n", port, atom_io_names[port]);
852 		else
853 			SDEBUG("   port: %d\n", port);
854 		if (!port)
855 			ctx->ctx->io_mode = ATOM_IO_MM;
856 		else
857 			ctx->ctx->io_mode = ATOM_IO_IIO | port;
858 		(*ptr) += 2;
859 		break;
860 	case ATOM_PORT_PCI:
861 		ctx->ctx->io_mode = ATOM_IO_PCI;
862 		(*ptr)++;
863 		break;
864 	case ATOM_PORT_SYSIO:
865 		ctx->ctx->io_mode = ATOM_IO_SYSIO;
866 		(*ptr)++;
867 		break;
868 	}
869 }
870 
atom_op_setregblock(atom_exec_context * ctx,int * ptr,int arg)871 static void atom_op_setregblock(atom_exec_context *ctx, int *ptr, int arg)
872 {
873 	ctx->ctx->reg_block = U16(*ptr);
874 	(*ptr) += 2;
875 	SDEBUG("   base: 0x%04X\n", ctx->ctx->reg_block);
876 }
877 
atom_op_shift_left(atom_exec_context * ctx,int * ptr,int arg)878 static void atom_op_shift_left(atom_exec_context *ctx, int *ptr, int arg)
879 {
880 	uint8_t attr = U8((*ptr)++), shift;
881 	uint32_t saved, dst;
882 	int dptr = *ptr;
883 	attr &= 0x38;
884 	attr |= atom_def_dst[attr >> 3] << 6;
885 	SDEBUG("   dst: ");
886 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
887 	shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr);
888 	SDEBUG("   shift: %d\n", shift);
889 	dst <<= shift;
890 	SDEBUG("   dst: ");
891 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
892 }
893 
atom_op_shift_right(atom_exec_context * ctx,int * ptr,int arg)894 static void atom_op_shift_right(atom_exec_context *ctx, int *ptr, int arg)
895 {
896 	uint8_t attr = U8((*ptr)++), shift;
897 	uint32_t saved, dst;
898 	int dptr = *ptr;
899 	attr &= 0x38;
900 	attr |= atom_def_dst[attr >> 3] << 6;
901 	SDEBUG("   dst: ");
902 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
903 	shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr);
904 	SDEBUG("   shift: %d\n", shift);
905 	dst >>= shift;
906 	SDEBUG("   dst: ");
907 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
908 }
909 
atom_op_shl(atom_exec_context * ctx,int * ptr,int arg)910 static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg)
911 {
912 	uint8_t attr = U8((*ptr)++), shift;
913 	uint32_t saved, dst;
914 	int dptr = *ptr;
915 	uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3];
916 	SDEBUG("   dst: ");
917 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
918 	/* op needs to full dst value */
919 	dst = saved;
920 	shift = atom_get_src(ctx, attr, ptr);
921 	SDEBUG("   shift: %d\n", shift);
922 	dst <<= shift;
923 	dst &= atom_arg_mask[dst_align];
924 	dst >>= atom_arg_shift[dst_align];
925 	SDEBUG("   dst: ");
926 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
927 }
928 
atom_op_shr(atom_exec_context * ctx,int * ptr,int arg)929 static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg)
930 {
931 	uint8_t attr = U8((*ptr)++), shift;
932 	uint32_t saved, dst;
933 	int dptr = *ptr;
934 	uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3];
935 	SDEBUG("   dst: ");
936 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
937 	/* op needs to full dst value */
938 	dst = saved;
939 	shift = atom_get_src(ctx, attr, ptr);
940 	SDEBUG("   shift: %d\n", shift);
941 	dst >>= shift;
942 	dst &= atom_arg_mask[dst_align];
943 	dst >>= atom_arg_shift[dst_align];
944 	SDEBUG("   dst: ");
945 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
946 }
947 
atom_op_sub(atom_exec_context * ctx,int * ptr,int arg)948 static void atom_op_sub(atom_exec_context *ctx, int *ptr, int arg)
949 {
950 	uint8_t attr = U8((*ptr)++);
951 	uint32_t dst, src, saved;
952 	int dptr = *ptr;
953 	SDEBUG("   dst: ");
954 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
955 	SDEBUG("   src: ");
956 	src = atom_get_src(ctx, attr, ptr);
957 	dst -= src;
958 	SDEBUG("   dst: ");
959 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
960 }
961 
atom_op_switch(atom_exec_context * ctx,int * ptr,int arg)962 static void atom_op_switch(atom_exec_context *ctx, int *ptr, int arg)
963 {
964 	uint8_t attr = U8((*ptr)++);
965 	uint32_t src, val, target;
966 	SDEBUG("   switch: ");
967 	src = atom_get_src(ctx, attr, ptr);
968 	while (U16(*ptr) != ATOM_CASE_END)
969 		if (U8(*ptr) == ATOM_CASE_MAGIC) {
970 			(*ptr)++;
971 			SDEBUG("   case: ");
972 			val =
973 			    atom_get_src(ctx, (attr & 0x38) | ATOM_ARG_IMM,
974 					 ptr);
975 			target = U16(*ptr);
976 			if (val == src) {
977 				SDEBUG("   target: %04X\n", target);
978 				*ptr = ctx->start + target;
979 				return;
980 			}
981 			(*ptr) += 2;
982 		} else {
983 			printk(KERN_INFO "Bad case.\n");
984 			return;
985 		}
986 	(*ptr) += 2;
987 }
988 
atom_op_test(atom_exec_context * ctx,int * ptr,int arg)989 static void atom_op_test(atom_exec_context *ctx, int *ptr, int arg)
990 {
991 	uint8_t attr = U8((*ptr)++);
992 	uint32_t dst, src;
993 	SDEBUG("   src1: ");
994 	dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
995 	SDEBUG("   src2: ");
996 	src = atom_get_src(ctx, attr, ptr);
997 	ctx->ctx->cs_equal = ((dst & src) == 0);
998 	SDEBUG("   result: %s\n", ctx->ctx->cs_equal ? "EQ" : "NE");
999 }
1000 
atom_op_xor(atom_exec_context * ctx,int * ptr,int arg)1001 static void atom_op_xor(atom_exec_context *ctx, int *ptr, int arg)
1002 {
1003 	uint8_t attr = U8((*ptr)++);
1004 	uint32_t dst, src, saved;
1005 	int dptr = *ptr;
1006 	SDEBUG("   dst: ");
1007 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
1008 	SDEBUG("   src: ");
1009 	src = atom_get_src(ctx, attr, ptr);
1010 	dst ^= src;
1011 	SDEBUG("   dst: ");
1012 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
1013 }
1014 
atom_op_debug(atom_exec_context * ctx,int * ptr,int arg)1015 static void atom_op_debug(atom_exec_context *ctx, int *ptr, int arg)
1016 {
1017 	printk(KERN_INFO "unimplemented!\n");
1018 }
1019 
1020 static struct {
1021 	void (*func) (atom_exec_context *, int *, int);
1022 	int arg;
1023 } opcode_table[ATOM_OP_CNT] = {
1024 	{
1025 	NULL, 0}, {
1026 	atom_op_move, ATOM_ARG_REG}, {
1027 	atom_op_move, ATOM_ARG_PS}, {
1028 	atom_op_move, ATOM_ARG_WS}, {
1029 	atom_op_move, ATOM_ARG_FB}, {
1030 	atom_op_move, ATOM_ARG_PLL}, {
1031 	atom_op_move, ATOM_ARG_MC}, {
1032 	atom_op_and, ATOM_ARG_REG}, {
1033 	atom_op_and, ATOM_ARG_PS}, {
1034 	atom_op_and, ATOM_ARG_WS}, {
1035 	atom_op_and, ATOM_ARG_FB}, {
1036 	atom_op_and, ATOM_ARG_PLL}, {
1037 	atom_op_and, ATOM_ARG_MC}, {
1038 	atom_op_or, ATOM_ARG_REG}, {
1039 	atom_op_or, ATOM_ARG_PS}, {
1040 	atom_op_or, ATOM_ARG_WS}, {
1041 	atom_op_or, ATOM_ARG_FB}, {
1042 	atom_op_or, ATOM_ARG_PLL}, {
1043 	atom_op_or, ATOM_ARG_MC}, {
1044 	atom_op_shift_left, ATOM_ARG_REG}, {
1045 	atom_op_shift_left, ATOM_ARG_PS}, {
1046 	atom_op_shift_left, ATOM_ARG_WS}, {
1047 	atom_op_shift_left, ATOM_ARG_FB}, {
1048 	atom_op_shift_left, ATOM_ARG_PLL}, {
1049 	atom_op_shift_left, ATOM_ARG_MC}, {
1050 	atom_op_shift_right, ATOM_ARG_REG}, {
1051 	atom_op_shift_right, ATOM_ARG_PS}, {
1052 	atom_op_shift_right, ATOM_ARG_WS}, {
1053 	atom_op_shift_right, ATOM_ARG_FB}, {
1054 	atom_op_shift_right, ATOM_ARG_PLL}, {
1055 	atom_op_shift_right, ATOM_ARG_MC}, {
1056 	atom_op_mul, ATOM_ARG_REG}, {
1057 	atom_op_mul, ATOM_ARG_PS}, {
1058 	atom_op_mul, ATOM_ARG_WS}, {
1059 	atom_op_mul, ATOM_ARG_FB}, {
1060 	atom_op_mul, ATOM_ARG_PLL}, {
1061 	atom_op_mul, ATOM_ARG_MC}, {
1062 	atom_op_div, ATOM_ARG_REG}, {
1063 	atom_op_div, ATOM_ARG_PS}, {
1064 	atom_op_div, ATOM_ARG_WS}, {
1065 	atom_op_div, ATOM_ARG_FB}, {
1066 	atom_op_div, ATOM_ARG_PLL}, {
1067 	atom_op_div, ATOM_ARG_MC}, {
1068 	atom_op_add, ATOM_ARG_REG}, {
1069 	atom_op_add, ATOM_ARG_PS}, {
1070 	atom_op_add, ATOM_ARG_WS}, {
1071 	atom_op_add, ATOM_ARG_FB}, {
1072 	atom_op_add, ATOM_ARG_PLL}, {
1073 	atom_op_add, ATOM_ARG_MC}, {
1074 	atom_op_sub, ATOM_ARG_REG}, {
1075 	atom_op_sub, ATOM_ARG_PS}, {
1076 	atom_op_sub, ATOM_ARG_WS}, {
1077 	atom_op_sub, ATOM_ARG_FB}, {
1078 	atom_op_sub, ATOM_ARG_PLL}, {
1079 	atom_op_sub, ATOM_ARG_MC}, {
1080 	atom_op_setport, ATOM_PORT_ATI}, {
1081 	atom_op_setport, ATOM_PORT_PCI}, {
1082 	atom_op_setport, ATOM_PORT_SYSIO}, {
1083 	atom_op_setregblock, 0}, {
1084 	atom_op_setfbbase, 0}, {
1085 	atom_op_compare, ATOM_ARG_REG}, {
1086 	atom_op_compare, ATOM_ARG_PS}, {
1087 	atom_op_compare, ATOM_ARG_WS}, {
1088 	atom_op_compare, ATOM_ARG_FB}, {
1089 	atom_op_compare, ATOM_ARG_PLL}, {
1090 	atom_op_compare, ATOM_ARG_MC}, {
1091 	atom_op_switch, 0}, {
1092 	atom_op_jump, ATOM_COND_ALWAYS}, {
1093 	atom_op_jump, ATOM_COND_EQUAL}, {
1094 	atom_op_jump, ATOM_COND_BELOW}, {
1095 	atom_op_jump, ATOM_COND_ABOVE}, {
1096 	atom_op_jump, ATOM_COND_BELOWOREQUAL}, {
1097 	atom_op_jump, ATOM_COND_ABOVEOREQUAL}, {
1098 	atom_op_jump, ATOM_COND_NOTEQUAL}, {
1099 	atom_op_test, ATOM_ARG_REG}, {
1100 	atom_op_test, ATOM_ARG_PS}, {
1101 	atom_op_test, ATOM_ARG_WS}, {
1102 	atom_op_test, ATOM_ARG_FB}, {
1103 	atom_op_test, ATOM_ARG_PLL}, {
1104 	atom_op_test, ATOM_ARG_MC}, {
1105 	atom_op_delay, ATOM_UNIT_MILLISEC}, {
1106 	atom_op_delay, ATOM_UNIT_MICROSEC}, {
1107 	atom_op_calltable, 0}, {
1108 	atom_op_repeat, 0}, {
1109 	atom_op_clear, ATOM_ARG_REG}, {
1110 	atom_op_clear, ATOM_ARG_PS}, {
1111 	atom_op_clear, ATOM_ARG_WS}, {
1112 	atom_op_clear, ATOM_ARG_FB}, {
1113 	atom_op_clear, ATOM_ARG_PLL}, {
1114 	atom_op_clear, ATOM_ARG_MC}, {
1115 	atom_op_nop, 0}, {
1116 	atom_op_eot, 0}, {
1117 	atom_op_mask, ATOM_ARG_REG}, {
1118 	atom_op_mask, ATOM_ARG_PS}, {
1119 	atom_op_mask, ATOM_ARG_WS}, {
1120 	atom_op_mask, ATOM_ARG_FB}, {
1121 	atom_op_mask, ATOM_ARG_PLL}, {
1122 	atom_op_mask, ATOM_ARG_MC}, {
1123 	atom_op_postcard, 0}, {
1124 	atom_op_beep, 0}, {
1125 	atom_op_savereg, 0}, {
1126 	atom_op_restorereg, 0}, {
1127 	atom_op_setdatablock, 0}, {
1128 	atom_op_xor, ATOM_ARG_REG}, {
1129 	atom_op_xor, ATOM_ARG_PS}, {
1130 	atom_op_xor, ATOM_ARG_WS}, {
1131 	atom_op_xor, ATOM_ARG_FB}, {
1132 	atom_op_xor, ATOM_ARG_PLL}, {
1133 	atom_op_xor, ATOM_ARG_MC}, {
1134 	atom_op_shl, ATOM_ARG_REG}, {
1135 	atom_op_shl, ATOM_ARG_PS}, {
1136 	atom_op_shl, ATOM_ARG_WS}, {
1137 	atom_op_shl, ATOM_ARG_FB}, {
1138 	atom_op_shl, ATOM_ARG_PLL}, {
1139 	atom_op_shl, ATOM_ARG_MC}, {
1140 	atom_op_shr, ATOM_ARG_REG}, {
1141 	atom_op_shr, ATOM_ARG_PS}, {
1142 	atom_op_shr, ATOM_ARG_WS}, {
1143 	atom_op_shr, ATOM_ARG_FB}, {
1144 	atom_op_shr, ATOM_ARG_PLL}, {
1145 	atom_op_shr, ATOM_ARG_MC}, {
1146 atom_op_debug, 0},};
1147 
atom_execute_table_locked(struct atom_context * ctx,int index,uint32_t * params)1148 static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params)
1149 {
1150 	int base = CU16(ctx->cmd_table + 4 + 2 * index);
1151 	int len, ws, ps, ptr;
1152 	unsigned char op;
1153 	atom_exec_context ectx;
1154 	int ret = 0;
1155 
1156 	if (!base)
1157 		return -EINVAL;
1158 
1159 	len = CU16(base + ATOM_CT_SIZE_PTR);
1160 	ws = CU8(base + ATOM_CT_WS_PTR);
1161 	ps = CU8(base + ATOM_CT_PS_PTR) & ATOM_CT_PS_MASK;
1162 	ptr = base + ATOM_CT_CODE_PTR;
1163 
1164 	SDEBUG(">> execute %04X (len %d, WS %d, PS %d)\n", base, len, ws, ps);
1165 
1166 	ectx.ctx = ctx;
1167 	ectx.ps_shift = ps / 4;
1168 	ectx.start = base;
1169 	ectx.ps = params;
1170 	ectx.abort = false;
1171 	ectx.last_jump = 0;
1172 	if (ws)
1173 		ectx.ws = kzalloc(4 * ws, GFP_KERNEL);
1174 	else
1175 		ectx.ws = NULL;
1176 
1177 	debug_depth++;
1178 	while (1) {
1179 		op = CU8(ptr++);
1180 		if (op < ATOM_OP_NAMES_CNT)
1181 			SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr - 1);
1182 		else
1183 			SDEBUG("[%d] @ 0x%04X\n", op, ptr - 1);
1184 		if (ectx.abort) {
1185 			DRM_ERROR("atombios stuck executing %04X (len %d, WS %d, PS %d) @ 0x%04X\n",
1186 				base, len, ws, ps, ptr - 1);
1187 			ret = -EINVAL;
1188 			goto free;
1189 		}
1190 
1191 		if (op < ATOM_OP_CNT && op > 0)
1192 			opcode_table[op].func(&ectx, &ptr,
1193 					      opcode_table[op].arg);
1194 		else
1195 			break;
1196 
1197 		if (op == ATOM_OP_EOT)
1198 			break;
1199 	}
1200 	debug_depth--;
1201 	SDEBUG("<<\n");
1202 
1203 free:
1204 	if (ws)
1205 		kfree(ectx.ws);
1206 	return ret;
1207 }
1208 
atom_execute_table(struct atom_context * ctx,int index,uint32_t * params)1209 int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
1210 {
1211 	int r;
1212 
1213 	mutex_lock(&ctx->mutex);
1214 	/* reset reg block */
1215 	ctx->reg_block = 0;
1216 	/* reset fb window */
1217 	ctx->fb_base = 0;
1218 	/* reset io mode */
1219 	ctx->io_mode = ATOM_IO_MM;
1220 	r = atom_execute_table_locked(ctx, index, params);
1221 	mutex_unlock(&ctx->mutex);
1222 	return r;
1223 }
1224 
1225 static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 };
1226 
atom_index_iio(struct atom_context * ctx,int base)1227 static void atom_index_iio(struct atom_context *ctx, int base)
1228 {
1229 	ctx->iio = kzalloc(2 * 256, GFP_KERNEL);
1230 	while (CU8(base) == ATOM_IIO_START) {
1231 		ctx->iio[CU8(base + 1)] = base + 2;
1232 		base += 2;
1233 		while (CU8(base) != ATOM_IIO_END)
1234 			base += atom_iio_len[CU8(base)];
1235 		base += 3;
1236 	}
1237 }
1238 
atom_parse(struct card_info * card,void * bios)1239 struct atom_context *atom_parse(struct card_info *card, void *bios)
1240 {
1241 	int base;
1242 	struct atom_context *ctx =
1243 	    kzalloc(sizeof(struct atom_context), GFP_KERNEL);
1244 	char *str;
1245 	char name[512];
1246 	int i;
1247 
1248 	ctx->card = card;
1249 	ctx->bios = bios;
1250 
1251 	if (CU16(0) != ATOM_BIOS_MAGIC) {
1252 		printk(KERN_INFO "Invalid BIOS magic.\n");
1253 		kfree(ctx);
1254 		return NULL;
1255 	}
1256 	if (strncmp
1257 	    (CSTR(ATOM_ATI_MAGIC_PTR), ATOM_ATI_MAGIC,
1258 	     strlen(ATOM_ATI_MAGIC))) {
1259 		printk(KERN_INFO "Invalid ATI magic.\n");
1260 		kfree(ctx);
1261 		return NULL;
1262 	}
1263 
1264 	base = CU16(ATOM_ROM_TABLE_PTR);
1265 	if (strncmp
1266 	    (CSTR(base + ATOM_ROM_MAGIC_PTR), ATOM_ROM_MAGIC,
1267 	     strlen(ATOM_ROM_MAGIC))) {
1268 		printk(KERN_INFO "Invalid ATOM magic.\n");
1269 		kfree(ctx);
1270 		return NULL;
1271 	}
1272 
1273 	ctx->cmd_table = CU16(base + ATOM_ROM_CMD_PTR);
1274 	ctx->data_table = CU16(base + ATOM_ROM_DATA_PTR);
1275 	atom_index_iio(ctx, CU16(ctx->data_table + ATOM_DATA_IIO_PTR) + 4);
1276 
1277 	str = CSTR(CU16(base + ATOM_ROM_MSG_PTR));
1278 	while (*str && ((*str == '\n') || (*str == '\r')))
1279 		str++;
1280 	/* name string isn't always 0 terminated */
1281 	for (i = 0; i < 511; i++) {
1282 		name[i] = str[i];
1283 		if (name[i] < '.' || name[i] > 'z') {
1284 			name[i] = 0;
1285 			break;
1286 		}
1287 	}
1288 	printk(KERN_INFO "ATOM BIOS: %s\n", name);
1289 
1290 	return ctx;
1291 }
1292 
atom_asic_init(struct atom_context * ctx)1293 int atom_asic_init(struct atom_context *ctx)
1294 {
1295 	int hwi = CU16(ctx->data_table + ATOM_DATA_FWI_PTR);
1296 	uint32_t ps[16];
1297 	memset(ps, 0, 64);
1298 
1299 	ps[0] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFSCLK_PTR));
1300 	ps[1] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFMCLK_PTR));
1301 	if (!ps[0] || !ps[1])
1302 		return 1;
1303 
1304 	if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT))
1305 		return 1;
1306 	return atom_execute_table(ctx, ATOM_CMD_INIT, ps);
1307 }
1308 
atom_destroy(struct atom_context * ctx)1309 void atom_destroy(struct atom_context *ctx)
1310 {
1311 	if (ctx->iio)
1312 		kfree(ctx->iio);
1313 	kfree(ctx);
1314 }
1315 
atom_parse_data_header(struct atom_context * ctx,int index,uint16_t * size,uint8_t * frev,uint8_t * crev,uint16_t * data_start)1316 bool atom_parse_data_header(struct atom_context *ctx, int index,
1317 			    uint16_t * size, uint8_t * frev, uint8_t * crev,
1318 			    uint16_t * data_start)
1319 {
1320 	int offset = index * 2 + 4;
1321 	int idx = CU16(ctx->data_table + offset);
1322 	u16 *mdt = (u16 *)(ctx->bios + ctx->data_table + 4);
1323 
1324 	if (!mdt[index])
1325 		return false;
1326 
1327 	if (size)
1328 		*size = CU16(idx);
1329 	if (frev)
1330 		*frev = CU8(idx + 2);
1331 	if (crev)
1332 		*crev = CU8(idx + 3);
1333 	*data_start = idx;
1334 	return true;
1335 }
1336 
atom_parse_cmd_header(struct atom_context * ctx,int index,uint8_t * frev,uint8_t * crev)1337 bool atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t * frev,
1338 			   uint8_t * crev)
1339 {
1340 	int offset = index * 2 + 4;
1341 	int idx = CU16(ctx->cmd_table + offset);
1342 	u16 *mct = (u16 *)(ctx->bios + ctx->cmd_table + 4);
1343 
1344 	if (!mct[index])
1345 		return false;
1346 
1347 	if (frev)
1348 		*frev = CU8(idx + 2);
1349 	if (crev)
1350 		*crev = CU8(idx + 3);
1351 	return true;
1352 }
1353 
atom_allocate_fb_scratch(struct atom_context * ctx)1354 int atom_allocate_fb_scratch(struct atom_context *ctx)
1355 {
1356 	int index = GetIndexIntoMasterTable(DATA, VRAM_UsageByFirmware);
1357 	uint16_t data_offset;
1358 	int usage_bytes = 0;
1359 	struct _ATOM_VRAM_USAGE_BY_FIRMWARE *firmware_usage;
1360 
1361 	if (atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset)) {
1362 		firmware_usage = (struct _ATOM_VRAM_USAGE_BY_FIRMWARE *)(ctx->bios + data_offset);
1363 
1364 		DRM_DEBUG("atom firmware requested %08x %dkb\n",
1365 			  firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware,
1366 			  firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb);
1367 
1368 		usage_bytes = firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb * 1024;
1369 	}
1370 	if (usage_bytes == 0)
1371 		usage_bytes = 20 * 1024;
1372 	/* allocate some scratch memory */
1373 	ctx->scratch = kzalloc(usage_bytes, GFP_KERNEL);
1374 	if (!ctx->scratch)
1375 		return -ENOMEM;
1376 	return 0;
1377 }
1378