2 * Copyright 2008 Advanced Micro Devices, Inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
22 * Author: Stanislaw Skowronek
25 #include <linux/module.h>
26 #include <linux/sched.h>
31 #include "atom-names.h"
32 #include "atom-bits.h"
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
42 #define ATOM_PORT_ATI 0
43 #define ATOM_PORT_PCI 1
44 #define ATOM_PORT_SYSIO 2
46 #define ATOM_UNIT_MICROSEC 0
47 #define ATOM_UNIT_MILLISEC 1
53 struct atom_context *ctx;
61 void atom_execute_table(struct atom_context *ctx, int index, uint32_t *params);
63 static uint32_t atom_arg_mask[8] = {0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000, 0xFF000000};
64 static int atom_arg_shift[8] = {0, 0, 8, 16, 0, 8, 16, 24};
65 static int atom_dst_to_src[8][4] = { // translate destination alignment field to the source alignment encoding
75 static int atom_def_dst[8] = { 0, 0, 1, 2, 0, 1, 2, 3 };
77 static int debug_depth = 0;
79 static void debug_print_spaces(int n)
84 #define DEBUG(...) do if(atom_debug) { printk(KERN_DEBUG __VA_ARGS__); } while(0)
85 #define SDEBUG(...) do if(atom_debug) { printk(KERN_DEBUG); debug_print_spaces(debug_depth); printk(__VA_ARGS__); } while(0)
87 #define DEBUG(...) do { } while(0)
88 #define SDEBUG(...) do { } while(0)
91 static uint32_t atom_iio_execute(struct atom_context *ctx, int base, uint32_t index, uint32_t data)
93 uint32_t temp = 0xCDCDCDCD;
100 temp = ctx->card->reg_read(ctx->card, CU16(base+1));
104 ctx->card->reg_write(ctx->card, CU16(base+1), temp);
108 temp &= ~((0xFFFFFFFF >> (32-CU8(base+1))) << CU8(base+2));
112 temp |= (0xFFFFFFFF >> (32-CU8(base+1))) << CU8(base+2);
115 case ATOM_IIO_MOVE_INDEX:
116 temp &= ~((0xFFFFFFFF >> (32-CU8(base+1))) << CU8(base+2));
117 temp |= ((index >> CU8(base+2)) & (0xFFFFFFFF >> (32-CU8(base+1)))) << CU8(base+3);
120 case ATOM_IIO_MOVE_DATA:
121 temp &= ~((0xFFFFFFFF >> (32-CU8(base+1))) << CU8(base+2));
122 temp |= ((data >> CU8(base+2)) & (0xFFFFFFFF >> (32-CU8(base+1)))) << CU8(base+3);
125 case ATOM_IIO_MOVE_ATTR:
126 temp &= ~((0xFFFFFFFF >> (32-CU8(base+1))) << CU8(base+2));
127 temp |= ((ctx->io_attr >> CU8(base+2)) & (0xFFFFFFFF >> (32-CU8(base+1)))) << CU8(base+3);
133 printk(KERN_INFO "Unknown IIO opcode.\n");
138 static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, int *ptr, uint32_t *saved, int print)
140 uint32_t idx, val = 0xCDCDCDCD, align, arg;
141 struct atom_context *gctx = ctx->ctx;
143 align = (attr >> 3) & 7;
149 DEBUG("REG[0x%04X]", idx);
150 idx += gctx->reg_block;
151 switch(gctx->io_mode) {
153 val = gctx->card->reg_read(gctx->card, idx);
156 printk(KERN_INFO "PCI registers are not implemented.\n");
159 printk(KERN_INFO "SYSIO registers are not implemented.\n");
162 if(!(gctx->io_mode&0x80)) {
163 printk(KERN_INFO "Bad IO mode.\n");
166 if(!gctx->iio[gctx->io_mode&0x7F]) {
167 printk(KERN_INFO "Undefined indirect IO read method %d.\n", gctx->io_mode&0x7F);
170 val = atom_iio_execute(gctx, gctx->iio[gctx->io_mode&0x7F], idx, 0);
178 DEBUG("PS[0x%02X,0x%04X]", idx, val);
184 DEBUG("WS[0x%02X]", idx);
186 case ATOM_WS_QUOTIENT:
187 val = gctx->divmul[0];
189 case ATOM_WS_REMAINDER:
190 val = gctx->divmul[1];
192 case ATOM_WS_DATAPTR:
193 val = gctx->data_block;
198 case ATOM_WS_OR_MASK:
199 val = 1<<gctx->shift;
201 case ATOM_WS_AND_MASK:
202 val = ~(1<<gctx->shift);
204 case ATOM_WS_FB_WINDOW:
207 case ATOM_WS_ATTRIBUTES:
219 DEBUG("ID[0x%04X+%04X]", idx, gctx->data_block);
221 DEBUG("ID[0x%04X]", idx);
223 val = U32(idx + gctx->data_block);
229 DEBUG("FB[0x%02X]", idx);
230 printk(KERN_INFO "FB access is not implemented.\n");
238 DEBUG("IMM 0x%08X\n", val);
242 case ATOM_SRC_WORD16:
246 DEBUG("IMM 0x%04X\n", val);
250 case ATOM_SRC_BYTE16:
251 case ATOM_SRC_BYTE24:
255 DEBUG("IMM 0x%02X\n", val);
263 DEBUG("PLL[0x%02X]", idx);
264 gctx->card->reg_write(gctx->card, PLL_INDEX, idx);
265 val = gctx->card->reg_read(gctx->card, PLL_DATA);
271 DEBUG("MC[0x%02X]", idx);
272 val = gctx->card->mc_read(gctx->card, idx);
277 val &= atom_arg_mask[align];
278 val >>= atom_arg_shift[align];
282 DEBUG(".[31:0] -> 0x%08X\n", val);
285 DEBUG(".[15:0] -> 0x%04X\n", val);
288 DEBUG(".[23:8] -> 0x%04X\n", val);
290 case ATOM_SRC_WORD16:
291 DEBUG(".[31:16] -> 0x%04X\n", val);
294 DEBUG(".[7:0] -> 0x%02X\n", val);
297 DEBUG(".[15:8] -> 0x%02X\n", val);
299 case ATOM_SRC_BYTE16:
300 DEBUG(".[23:16] -> 0x%02X\n", val);
302 case ATOM_SRC_BYTE24:
303 DEBUG(".[31:24] -> 0x%02X\n", val);
309 static void atom_skip_src_int(atom_exec_context *ctx, uint8_t attr, int *ptr)
311 uint32_t align = (attr >> 3) & 7, arg = attr & 7;
331 case ATOM_SRC_WORD16:
336 case ATOM_SRC_BYTE16:
337 case ATOM_SRC_BYTE24:
345 static uint32_t atom_get_src(atom_exec_context *ctx, uint8_t attr, int *ptr)
347 return atom_get_src_int(ctx, attr, ptr, NULL, 1);
350 static uint32_t atom_get_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr, uint32_t *saved, int print)
352 return atom_get_src_int(ctx, arg|atom_dst_to_src[(attr>>3)&7][(attr>>6)&3]<<3, ptr, saved, print);
355 static void atom_skip_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr)
357 atom_skip_src_int(ctx, arg|atom_dst_to_src[(attr>>3)&7][(attr>>6)&3]<<3, ptr);
360 static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr, uint32_t val, uint32_t saved)
362 uint32_t align = atom_dst_to_src[(attr>>3)&7][(attr>>6)&3], old_val = val, idx;
363 struct atom_context *gctx = ctx->ctx;
364 old_val &= atom_arg_mask[align] >> atom_arg_shift[align];
365 val <<= atom_arg_shift[align];
366 val &= atom_arg_mask[align];
367 saved &= ~atom_arg_mask[align];
373 DEBUG("REG[0x%04X]", idx);
374 idx += gctx->reg_block;
375 switch(gctx->io_mode) {
378 gctx->card->reg_write(gctx->card, idx, val<<2);
380 gctx->card->reg_write(gctx->card, idx, val);
383 printk(KERN_INFO "PCI registers are not implemented.\n");
386 printk(KERN_INFO "SYSIO registers are not implemented.\n");
389 if(!(gctx->io_mode&0x80)) {
390 printk(KERN_INFO "Bad IO mode.\n");
393 if(!gctx->iio[gctx->io_mode&0xFF]) {
394 printk(KERN_INFO "Undefined indirect IO write method %d.\n", gctx->io_mode&0x7F);
397 atom_iio_execute(gctx, gctx->iio[gctx->io_mode&0xFF], idx, val);
403 DEBUG("PS[0x%02X]", idx);
409 DEBUG("WS[0x%02X]", idx);
411 case ATOM_WS_QUOTIENT:
412 gctx->divmul[0] = val;
414 case ATOM_WS_REMAINDER:
415 gctx->divmul[1] = val;
417 case ATOM_WS_DATAPTR:
418 gctx->data_block = val;
423 case ATOM_WS_OR_MASK:
424 case ATOM_WS_AND_MASK:
426 case ATOM_WS_FB_WINDOW:
429 case ATOM_WS_ATTRIBUTES:
439 DEBUG("FB[0x%02X]", idx);
440 printk(KERN_INFO "FB access is not implemented.\n");
445 DEBUG("PLL[0x%02X]", idx);
446 gctx->card->reg_write(gctx->card, PLL_INDEX, idx);
447 gctx->card->reg_write(gctx->card, PLL_DATA, val);
452 DEBUG("MC[0x%02X]", idx);
453 gctx->card->mc_write(gctx->card, idx, val);
458 DEBUG(".[31:0] <- 0x%08X\n", old_val);
461 DEBUG(".[15:0] <- 0x%04X\n", old_val);
464 DEBUG(".[23:8] <- 0x%04X\n", old_val);
466 case ATOM_SRC_WORD16:
467 DEBUG(".[31:16] <- 0x%04X\n", old_val);
470 DEBUG(".[7:0] <- 0x%02X\n", old_val);
473 DEBUG(".[15:8] <- 0x%02X\n", old_val);
475 case ATOM_SRC_BYTE16:
476 DEBUG(".[23:16] <- 0x%02X\n", old_val);
478 case ATOM_SRC_BYTE24:
479 DEBUG(".[31:24] <- 0x%02X\n", old_val);
484 static void atom_op_add(atom_exec_context *ctx, int *ptr, int arg)
486 uint8_t attr = U8((*ptr)++);
487 uint32_t dst, src, saved;
490 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
492 src = atom_get_src(ctx, attr, ptr);
495 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
498 static void atom_op_and(atom_exec_context *ctx, int *ptr, int arg)
500 uint8_t attr = U8((*ptr)++);
501 uint32_t dst, src, saved;
504 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
506 src = atom_get_src(ctx, attr, ptr);
509 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
512 static void atom_op_beep(atom_exec_context *ctx, int *ptr, int arg)
514 printk("ATOM BIOS beeped!\n");
517 static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg)
519 int idx = U8((*ptr)++);
520 if(idx < ATOM_TABLE_NAMES_CNT)
521 SDEBUG(" table: %d (%s)\n", idx, atom_table_names[idx]);
523 SDEBUG(" table: %d\n", idx);
524 if(U16(ctx->ctx->cmd_table + 4 + 2*idx))
525 atom_execute_table(ctx->ctx, idx, ctx->ps+ctx->ps_shift);
528 static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg)
530 uint8_t attr = U8((*ptr)++);
534 attr |= atom_def_dst[attr>>3]<<6;
535 atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
537 atom_put_dst(ctx, arg, attr, &dptr, 0, saved);
540 static void atom_op_compare(atom_exec_context *ctx, int *ptr, int arg)
542 uint8_t attr = U8((*ptr)++);
545 dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
547 src = atom_get_src(ctx, attr, ptr);
548 ctx->ctx->cs_equal = (dst == src);
549 ctx->ctx->cs_above = (dst > src);
550 SDEBUG(" result: %s %s\n", ctx->ctx->cs_equal?"EQ":"NE", ctx->ctx->cs_above?"GT":"LE");
553 static void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg)
555 uint8_t count = U8((*ptr)++);
556 SDEBUG(" count: %d\n", count);
557 if(arg == ATOM_UNIT_MICROSEC)
558 schedule_timeout_uninterruptible(usecs_to_jiffies(count));
560 schedule_timeout_uninterruptible(msecs_to_jiffies(count));
563 static void atom_op_div(atom_exec_context *ctx, int *ptr, int arg)
565 uint8_t attr = U8((*ptr)++);
568 dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
570 src = atom_get_src(ctx, attr, ptr);
572 ctx->ctx->divmul[0] = dst/src;
573 ctx->ctx->divmul[1] = dst%src;
575 ctx->ctx->divmul[0] = 0;
576 ctx->ctx->divmul[1] = 0;
580 static void atom_op_eot(atom_exec_context *ctx, int *ptr, int arg)
582 /* functionally, a nop */
585 static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
587 int execute = 0, target = U16(*ptr);
590 case ATOM_COND_ABOVE:
591 execute = ctx->ctx->cs_above;
593 case ATOM_COND_ABOVEOREQUAL:
594 execute = ctx->ctx->cs_above || ctx->ctx->cs_equal;
596 case ATOM_COND_ALWAYS:
599 case ATOM_COND_BELOW:
600 execute = !(ctx->ctx->cs_above || ctx->ctx->cs_equal);
602 case ATOM_COND_BELOWOREQUAL:
603 execute = !ctx->ctx->cs_above;
605 case ATOM_COND_EQUAL:
606 execute = ctx->ctx->cs_equal;
608 case ATOM_COND_NOTEQUAL:
609 execute = !ctx->ctx->cs_equal;
612 if(arg != ATOM_COND_ALWAYS)
613 SDEBUG(" taken: %s\n", execute?"yes":"no");
614 SDEBUG(" target: 0x%04X\n", target);
616 *ptr = ctx->start+target;
619 static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg)
621 uint8_t attr = U8((*ptr)++);
622 uint32_t dst, src1, src2, saved;
625 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
627 src1 = atom_get_src(ctx, attr, ptr);
629 src2 = atom_get_src(ctx, attr, ptr);
633 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
636 static void atom_op_move(atom_exec_context *ctx, int *ptr, int arg)
638 uint8_t attr = U8((*ptr)++);
641 if(((attr>>3)&7) != ATOM_SRC_DWORD)
642 atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
644 atom_skip_dst(ctx, arg, attr, ptr);
648 src = atom_get_src(ctx, attr, ptr);
650 atom_put_dst(ctx, arg, attr, &dptr, src, saved);
653 static void atom_op_mul(atom_exec_context *ctx, int *ptr, int arg)
655 uint8_t attr = U8((*ptr)++);
658 dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
660 src = atom_get_src(ctx, attr, ptr);
661 ctx->ctx->divmul[0] = dst*src;
664 static void atom_op_nop(atom_exec_context *ctx, int *ptr, int arg)
669 static void atom_op_or(atom_exec_context *ctx, int *ptr, int arg)
671 uint8_t attr = U8((*ptr)++);
672 uint32_t dst, src, saved;
675 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
677 src = atom_get_src(ctx, attr, ptr);
680 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
683 static void atom_op_postcard(atom_exec_context *ctx, int *ptr, int arg)
685 uint8_t val = U8((*ptr)++);
686 SDEBUG("POST card output: 0x%02X\n", val);
689 static void atom_op_repeat(atom_exec_context *ctx, int *ptr, int arg)
691 printk(KERN_INFO "unimplemented!\n");
694 static void atom_op_restorereg(atom_exec_context *ctx, int *ptr, int arg)
696 printk(KERN_INFO "unimplemented!\n");
699 static void atom_op_savereg(atom_exec_context *ctx, int *ptr, int arg)
701 printk(KERN_INFO "unimplemented!\n");
704 static void atom_op_setdatablock(atom_exec_context *ctx, int *ptr, int arg)
708 SDEBUG(" block: %d\n", idx);
710 ctx->ctx->data_block = 0;
712 ctx->ctx->data_block = ctx->start;
714 ctx->ctx->data_block = U16(ctx->ctx->data_table + 4 + 2*idx);
715 SDEBUG(" base: 0x%04X\n", ctx->ctx->data_block);
718 static void atom_op_setfbbase(atom_exec_context *ctx, int *ptr, int arg)
720 uint8_t attr = U8((*ptr)++);
721 SDEBUG(" fb_base: ");
722 ctx->ctx->fb_base = atom_get_src(ctx, attr, ptr);
725 static void atom_op_setport(atom_exec_context *ctx, int *ptr, int arg)
731 if(port < ATOM_IO_NAMES_CNT)
732 SDEBUG(" port: %d (%s)\n", port, atom_io_names[port]);
734 SDEBUG(" port: %d\n", port);
736 ctx->ctx->io_mode = ATOM_IO_MM;
738 ctx->ctx->io_mode = ATOM_IO_IIO|port;
742 ctx->ctx->io_mode = ATOM_IO_PCI;
745 case ATOM_PORT_SYSIO:
746 ctx->ctx->io_mode = ATOM_IO_SYSIO;
752 static void atom_op_setregblock(atom_exec_context *ctx, int *ptr, int arg)
754 ctx->ctx->reg_block = U16(*ptr);
756 SDEBUG(" base: 0x%04X\n", ctx->ctx->reg_block);
759 static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg)
761 uint8_t attr = U8((*ptr)++), shift;
765 attr |= atom_def_dst[attr>>3]<<6;
767 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
768 shift = U8((*ptr)++);
769 SDEBUG(" shift: %d\n", shift);
772 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
775 static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg)
777 uint8_t attr = U8((*ptr)++), shift;
781 attr |= atom_def_dst[attr>>3]<<6;
783 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
784 shift = U8((*ptr)++);
785 SDEBUG(" shift: %d\n", shift);
788 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
791 static void atom_op_sub(atom_exec_context *ctx, int *ptr, int arg)
793 uint8_t attr = U8((*ptr)++);
794 uint32_t dst, src, saved;
797 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
799 src = atom_get_src(ctx, attr, ptr);
802 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
805 static void atom_op_switch(atom_exec_context *ctx, int *ptr, int arg)
807 uint8_t attr = U8((*ptr)++);
808 uint32_t src, val, target;
810 src = atom_get_src(ctx, attr, ptr);
811 while(U16(*ptr) != ATOM_CASE_END)
812 if(U8(*ptr) == ATOM_CASE_MAGIC) {
815 val = atom_get_src(ctx, (attr&0x38)|ATOM_ARG_IMM, ptr);
818 SDEBUG(" target: %04X\n", target);
819 *ptr = ctx->start+target;
824 printk(KERN_INFO "Bad case.\n");
830 static void atom_op_test(atom_exec_context *ctx, int *ptr, int arg)
832 uint8_t attr = U8((*ptr)++);
835 dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
837 src = atom_get_src(ctx, attr, ptr);
838 ctx->ctx->cs_equal = ((dst & src) == 0);
839 SDEBUG(" result: %s\n", ctx->ctx->cs_equal?"EQ":"NE");
842 static void atom_op_xor(atom_exec_context *ctx, int *ptr, int arg)
844 uint8_t attr = U8((*ptr)++);
845 uint32_t dst, src, saved;
848 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
850 src = atom_get_src(ctx, attr, ptr);
853 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
856 static void atom_op_debug(atom_exec_context *ctx, int *ptr, int arg)
858 printk(KERN_INFO "unimplemented!\n");
862 void (*func)(atom_exec_context *, int *, int);
864 } opcode_table[ATOM_OP_CNT] = {
866 { atom_op_move, ATOM_ARG_REG },
867 { atom_op_move, ATOM_ARG_PS },
868 { atom_op_move, ATOM_ARG_WS },
869 { atom_op_move, ATOM_ARG_FB },
870 { atom_op_move, ATOM_ARG_PLL },
871 { atom_op_move, ATOM_ARG_MC },
872 { atom_op_and, ATOM_ARG_REG },
873 { atom_op_and, ATOM_ARG_PS },
874 { atom_op_and, ATOM_ARG_WS },
875 { atom_op_and, ATOM_ARG_FB },
876 { atom_op_and, ATOM_ARG_PLL },
877 { atom_op_and, ATOM_ARG_MC },
878 { atom_op_or, ATOM_ARG_REG },
879 { atom_op_or, ATOM_ARG_PS },
880 { atom_op_or, ATOM_ARG_WS },
881 { atom_op_or, ATOM_ARG_FB },
882 { atom_op_or, ATOM_ARG_PLL },
883 { atom_op_or, ATOM_ARG_MC },
884 { atom_op_shl, ATOM_ARG_REG },
885 { atom_op_shl, ATOM_ARG_PS },
886 { atom_op_shl, ATOM_ARG_WS },
887 { atom_op_shl, ATOM_ARG_FB },
888 { atom_op_shl, ATOM_ARG_PLL },
889 { atom_op_shl, ATOM_ARG_MC },
890 { atom_op_shr, ATOM_ARG_REG },
891 { atom_op_shr, ATOM_ARG_PS },
892 { atom_op_shr, ATOM_ARG_WS },
893 { atom_op_shr, ATOM_ARG_FB },
894 { atom_op_shr, ATOM_ARG_PLL },
895 { atom_op_shr, ATOM_ARG_MC },
896 { atom_op_mul, ATOM_ARG_REG },
897 { atom_op_mul, ATOM_ARG_PS },
898 { atom_op_mul, ATOM_ARG_WS },
899 { atom_op_mul, ATOM_ARG_FB },
900 { atom_op_mul, ATOM_ARG_PLL },
901 { atom_op_mul, ATOM_ARG_MC },
902 { atom_op_div, ATOM_ARG_REG },
903 { atom_op_div, ATOM_ARG_PS },
904 { atom_op_div, ATOM_ARG_WS },
905 { atom_op_div, ATOM_ARG_FB },
906 { atom_op_div, ATOM_ARG_PLL },
907 { atom_op_div, ATOM_ARG_MC },
908 { atom_op_add, ATOM_ARG_REG },
909 { atom_op_add, ATOM_ARG_PS },
910 { atom_op_add, ATOM_ARG_WS },
911 { atom_op_add, ATOM_ARG_FB },
912 { atom_op_add, ATOM_ARG_PLL },
913 { atom_op_add, ATOM_ARG_MC },
914 { atom_op_sub, ATOM_ARG_REG },
915 { atom_op_sub, ATOM_ARG_PS },
916 { atom_op_sub, ATOM_ARG_WS },
917 { atom_op_sub, ATOM_ARG_FB },
918 { atom_op_sub, ATOM_ARG_PLL },
919 { atom_op_sub, ATOM_ARG_MC },
920 { atom_op_setport, ATOM_PORT_ATI },
921 { atom_op_setport, ATOM_PORT_PCI },
922 { atom_op_setport, ATOM_PORT_SYSIO },
923 { atom_op_setregblock, 0 },
924 { atom_op_setfbbase, 0 },
925 { atom_op_compare, ATOM_ARG_REG },
926 { atom_op_compare, ATOM_ARG_PS },
927 { atom_op_compare, ATOM_ARG_WS },
928 { atom_op_compare, ATOM_ARG_FB },
929 { atom_op_compare, ATOM_ARG_PLL },
930 { atom_op_compare, ATOM_ARG_MC },
931 { atom_op_switch, 0 },
932 { atom_op_jump, ATOM_COND_ALWAYS },
933 { atom_op_jump, ATOM_COND_EQUAL },
934 { atom_op_jump, ATOM_COND_BELOW },
935 { atom_op_jump, ATOM_COND_ABOVE },
936 { atom_op_jump, ATOM_COND_BELOWOREQUAL },
937 { atom_op_jump, ATOM_COND_ABOVEOREQUAL },
938 { atom_op_jump, ATOM_COND_NOTEQUAL },
939 { atom_op_test, ATOM_ARG_REG },
940 { atom_op_test, ATOM_ARG_PS },
941 { atom_op_test, ATOM_ARG_WS },
942 { atom_op_test, ATOM_ARG_FB },
943 { atom_op_test, ATOM_ARG_PLL },
944 { atom_op_test, ATOM_ARG_MC },
945 { atom_op_delay, ATOM_UNIT_MILLISEC },
946 { atom_op_delay, ATOM_UNIT_MICROSEC },
947 { atom_op_calltable, 0 },
948 { atom_op_repeat, 0 },
949 { atom_op_clear, ATOM_ARG_REG },
950 { atom_op_clear, ATOM_ARG_PS },
951 { atom_op_clear, ATOM_ARG_WS },
952 { atom_op_clear, ATOM_ARG_FB },
953 { atom_op_clear, ATOM_ARG_PLL },
954 { atom_op_clear, ATOM_ARG_MC },
957 { atom_op_mask, ATOM_ARG_REG },
958 { atom_op_mask, ATOM_ARG_PS },
959 { atom_op_mask, ATOM_ARG_WS },
960 { atom_op_mask, ATOM_ARG_FB },
961 { atom_op_mask, ATOM_ARG_PLL },
962 { atom_op_mask, ATOM_ARG_MC },
963 { atom_op_postcard, 0 },
965 { atom_op_savereg, 0 },
966 { atom_op_restorereg, 0 },
967 { atom_op_setdatablock, 0 },
968 { atom_op_xor, ATOM_ARG_REG },
969 { atom_op_xor, ATOM_ARG_PS },
970 { atom_op_xor, ATOM_ARG_WS },
971 { atom_op_xor, ATOM_ARG_FB },
972 { atom_op_xor, ATOM_ARG_PLL },
973 { atom_op_xor, ATOM_ARG_MC },
974 { atom_op_shl, ATOM_ARG_REG },
975 { atom_op_shl, ATOM_ARG_PS },
976 { atom_op_shl, ATOM_ARG_WS },
977 { atom_op_shl, ATOM_ARG_FB },
978 { atom_op_shl, ATOM_ARG_PLL },
979 { atom_op_shl, ATOM_ARG_MC },
980 { atom_op_shr, ATOM_ARG_REG },
981 { atom_op_shr, ATOM_ARG_PS },
982 { atom_op_shr, ATOM_ARG_WS },
983 { atom_op_shr, ATOM_ARG_FB },
984 { atom_op_shr, ATOM_ARG_PLL },
985 { atom_op_shr, ATOM_ARG_MC },
986 { atom_op_debug, 0 },
989 void atom_execute_table(struct atom_context *ctx, int index, uint32_t *params)
991 int base = CU16(ctx->cmd_table+4+2*index);
992 int len, ws, ps, ptr;
994 atom_exec_context ectx;
999 len = CU16(base+ATOM_CT_SIZE_PTR);
1000 ws = CU8(base+ATOM_CT_WS_PTR);
1001 ps = CU8(base+ATOM_CT_PS_PTR) & ATOM_CT_PS_MASK;
1002 ptr = base+ATOM_CT_CODE_PTR;
1004 SDEBUG(">> execute %04X (len %d, WS %d, PS %d)\n", base, len, ws, ps);
1006 /* reset reg block */
1009 ectx.ps_shift = ps/4;
1013 ectx.ws = kzalloc(4*ws, GFP_KERNEL);
1020 if(op<ATOM_OP_NAMES_CNT)
1021 SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr-1);
1023 SDEBUG("[%d] @ 0x%04X\n", op, ptr-1);
1025 if(op<ATOM_OP_CNT && op>0)
1026 opcode_table[op].func(&ectx, &ptr, opcode_table[op].arg);
1030 if(op == ATOM_OP_EOT)
1040 static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 };
1041 static void atom_index_iio(struct atom_context *ctx, int base)
1043 ctx->iio = kzalloc(2*256, GFP_KERNEL);
1044 while(CU8(base) == ATOM_IIO_START) {
1045 ctx->iio[CU8(base+1)] = base+2;
1047 while(CU8(base) != ATOM_IIO_END)
1048 base += atom_iio_len[CU8(base)];
1053 struct atom_context *atom_parse(struct card_info *card, void *bios)
1056 struct atom_context *ctx = kzalloc(sizeof(struct atom_context), GFP_KERNEL);
1062 if(CU16(0) != ATOM_BIOS_MAGIC) {
1063 printk(KERN_INFO "Invalid BIOS magic.\n");
1067 if(strncmp(CSTR(ATOM_ATI_MAGIC_PTR), ATOM_ATI_MAGIC, strlen(ATOM_ATI_MAGIC))) {
1068 printk(KERN_INFO "Invalid ATI magic.\n");
1073 base = CU16(ATOM_ROM_TABLE_PTR);
1074 if(strncmp(CSTR(base+ATOM_ROM_MAGIC_PTR), ATOM_ROM_MAGIC, strlen(ATOM_ROM_MAGIC))) {
1075 printk(KERN_INFO "Invalid ATOM magic.\n");
1080 ctx->cmd_table = CU16(base+ATOM_ROM_CMD_PTR);
1081 ctx->data_table = CU16(base+ATOM_ROM_DATA_PTR);
1082 atom_index_iio(ctx, CU16(ctx->data_table+ATOM_DATA_IIO_PTR)+4);
1084 str = CSTR(CU16(base+ATOM_ROM_MSG_PTR));
1085 while(*str && ((*str == '\n') || (*str == '\r')))
1087 printk(KERN_INFO "ATOM BIOS: %s", str);
1092 int atom_asic_init(struct atom_context *ctx)
1094 int hwi = CU16(ctx->data_table + ATOM_DATA_FWI_PTR);
1098 ps[0] = CU32(hwi + ATOM_FWI_DEFSCLK_PTR);
1099 ps[1] = CU32(hwi + ATOM_FWI_DEFMCLK_PTR);
1100 if(!ps[0] || !ps[1])
1103 if(!CU16(ctx->cmd_table+4+2*ATOM_CMD_INIT))
1105 atom_execute_table(ctx, ATOM_CMD_INIT, ps);
1110 void atom_destroy(struct atom_context *ctx)
1118 void atom_parse_data_header(struct atom_context *ctx, int index, uint16_t *size, uint8_t *frev, uint8_t *crev, uint16_t *data_start)
1120 int offset = index * 2 + 4;
1121 int idx = CU16(ctx->data_table + offset);
1126 *frev = CU8(idx + 2);
1128 *crev = CU8(idx + 3);
1133 void atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t *frev, uint8_t *crev)
1135 int offset = index * 2 + 4;
1136 int idx = CU16(ctx->cmd_table + offset);
1139 *frev = CU8(idx + 2);
1141 *crev = CU8(idx + 3);