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