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