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