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