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