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);
273 printk(KERN_INFO "MC registers are not implemented.\n");
278 val &= atom_arg_mask[align];
279 val >>= atom_arg_shift[align];
283 DEBUG(".[31:0] -> 0x%08X\n", val);
286 DEBUG(".[15:0] -> 0x%04X\n", val);
289 DEBUG(".[23:8] -> 0x%04X\n", val);
291 case ATOM_SRC_WORD16:
292 DEBUG(".[31:16] -> 0x%04X\n", val);
295 DEBUG(".[7:0] -> 0x%02X\n", val);
298 DEBUG(".[15:8] -> 0x%02X\n", val);
300 case ATOM_SRC_BYTE16:
301 DEBUG(".[23:16] -> 0x%02X\n", val);
303 case ATOM_SRC_BYTE24:
304 DEBUG(".[31:24] -> 0x%02X\n", val);
310 static void atom_skip_src_int(atom_exec_context *ctx, uint8_t attr, int *ptr)
312 uint32_t align = (attr >> 3) & 7, arg = attr & 7;
332 case ATOM_SRC_WORD16:
337 case ATOM_SRC_BYTE16:
338 case ATOM_SRC_BYTE24:
346 static uint32_t atom_get_src(atom_exec_context *ctx, uint8_t attr, int *ptr)
348 return atom_get_src_int(ctx, attr, ptr, NULL, 1);
351 static uint32_t atom_get_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr, uint32_t *saved, int print)
353 return atom_get_src_int(ctx, arg|atom_dst_to_src[(attr>>3)&7][(attr>>6)&3]<<3, ptr, saved, print);
356 static void atom_skip_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr)
358 atom_skip_src_int(ctx, arg|atom_dst_to_src[(attr>>3)&7][(attr>>6)&3]<<3, ptr);
361 static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr, uint32_t val, uint32_t saved)
363 uint32_t align = atom_dst_to_src[(attr>>3)&7][(attr>>6)&3], old_val = val, idx;
364 struct atom_context *gctx = ctx->ctx;
365 old_val &= atom_arg_mask[align] >> atom_arg_shift[align];
366 val <<= atom_arg_shift[align];
367 val &= atom_arg_mask[align];
368 saved &= ~atom_arg_mask[align];
374 DEBUG("REG[0x%04X]", idx);
375 idx += gctx->reg_block;
376 switch(gctx->io_mode) {
379 gctx->card->reg_write(gctx->card, idx, val<<2);
381 gctx->card->reg_write(gctx->card, idx, val);
384 printk(KERN_INFO "PCI registers are not implemented.\n");
387 printk(KERN_INFO "SYSIO registers are not implemented.\n");
390 if(!(gctx->io_mode&0x80)) {
391 printk(KERN_INFO "Bad IO mode.\n");
394 if(!gctx->iio[gctx->io_mode&0xFF]) {
395 printk(KERN_INFO "Undefined indirect IO write method %d.\n", gctx->io_mode&0x7F);
398 atom_iio_execute(gctx, gctx->iio[gctx->io_mode&0xFF], idx, val);
404 DEBUG("PS[0x%02X]", idx);
410 DEBUG("WS[0x%02X]", idx);
412 case ATOM_WS_QUOTIENT:
413 gctx->divmul[0] = val;
415 case ATOM_WS_REMAINDER:
416 gctx->divmul[1] = val;
418 case ATOM_WS_DATAPTR:
419 gctx->data_block = val;
424 case ATOM_WS_OR_MASK:
425 case ATOM_WS_AND_MASK:
427 case ATOM_WS_FB_WINDOW:
430 case ATOM_WS_ATTRIBUTES:
440 DEBUG("FB[0x%02X]", idx);
441 printk(KERN_INFO "FB access is not implemented.\n");
446 DEBUG("PLL[0x%02X]", idx);
447 gctx->card->reg_write(gctx->card, PLL_INDEX, idx);
448 gctx->card->reg_write(gctx->card, PLL_DATA, val);
453 DEBUG("MC[0x%02X]", idx);
454 gctx->card->mc_write(gctx->card, idx, val);
455 printk(KERN_INFO "MC registers are not implemented.\n");
460 DEBUG(".[31:0] <- 0x%08X\n", old_val);
463 DEBUG(".[15:0] <- 0x%04X\n", old_val);
466 DEBUG(".[23:8] <- 0x%04X\n", old_val);
468 case ATOM_SRC_WORD16:
469 DEBUG(".[31:16] <- 0x%04X\n", old_val);
472 DEBUG(".[7:0] <- 0x%02X\n", old_val);
475 DEBUG(".[15:8] <- 0x%02X\n", old_val);
477 case ATOM_SRC_BYTE16:
478 DEBUG(".[23:16] <- 0x%02X\n", old_val);
480 case ATOM_SRC_BYTE24:
481 DEBUG(".[31:24] <- 0x%02X\n", old_val);
486 static void atom_op_add(atom_exec_context *ctx, int *ptr, int arg)
488 uint8_t attr = U8((*ptr)++);
489 uint32_t dst, src, saved;
492 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
494 src = atom_get_src(ctx, attr, ptr);
497 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
500 static void atom_op_and(atom_exec_context *ctx, int *ptr, int arg)
502 uint8_t attr = U8((*ptr)++);
503 uint32_t dst, src, saved;
506 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
508 src = atom_get_src(ctx, attr, ptr);
511 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
514 static void atom_op_beep(atom_exec_context *ctx, int *ptr, int arg)
516 printk("ATOM BIOS beeped!\n");
519 static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg)
521 int idx = U8((*ptr)++);
522 if(idx < ATOM_TABLE_NAMES_CNT)
523 SDEBUG(" table: %d (%s)\n", idx, atom_table_names[idx]);
525 SDEBUG(" table: %d\n", idx);
526 if(U16(ctx->ctx->cmd_table + 4 + 2*idx))
527 atom_execute_table(ctx->ctx, idx, ctx->ps+ctx->ps_shift);
530 static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg)
532 uint8_t attr = U8((*ptr)++);
536 attr |= atom_def_dst[attr>>3]<<6;
537 atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
539 atom_put_dst(ctx, arg, attr, &dptr, 0, saved);
542 static void atom_op_compare(atom_exec_context *ctx, int *ptr, int arg)
544 uint8_t attr = U8((*ptr)++);
547 dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
549 src = atom_get_src(ctx, attr, ptr);
550 ctx->ctx->cs_equal = (dst == src);
551 ctx->ctx->cs_above = (dst > src);
552 SDEBUG(" result: %s %s\n", ctx->ctx->cs_equal?"EQ":"NE", ctx->ctx->cs_above?"GT":"LE");
555 static void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg)
557 uint8_t count = U8((*ptr)++);
558 SDEBUG(" count: %d\n", count);
559 if(arg == ATOM_UNIT_MICROSEC)
560 schedule_timeout_uninterruptible(usecs_to_jiffies(count));
562 schedule_timeout_uninterruptible(msecs_to_jiffies(count));
565 static void atom_op_div(atom_exec_context *ctx, int *ptr, int arg)
567 uint8_t attr = U8((*ptr)++);
570 dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
572 src = atom_get_src(ctx, attr, ptr);
574 ctx->ctx->divmul[0] = dst/src;
575 ctx->ctx->divmul[1] = dst%src;
577 ctx->ctx->divmul[0] = 0;
578 ctx->ctx->divmul[1] = 0;
582 static void atom_op_eot(atom_exec_context *ctx, int *ptr, int arg)
584 /* functionally, a nop */
587 static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
589 int execute = 0, target = U16(*ptr);
592 case ATOM_COND_ABOVE:
593 execute = ctx->ctx->cs_above;
595 case ATOM_COND_ABOVEOREQUAL:
596 execute = ctx->ctx->cs_above || ctx->ctx->cs_equal;
598 case ATOM_COND_ALWAYS:
601 case ATOM_COND_BELOW:
602 execute = !(ctx->ctx->cs_above || ctx->ctx->cs_equal);
604 case ATOM_COND_BELOWOREQUAL:
605 execute = !ctx->ctx->cs_above;
607 case ATOM_COND_EQUAL:
608 execute = ctx->ctx->cs_equal;
610 case ATOM_COND_NOTEQUAL:
611 execute = !ctx->ctx->cs_equal;
614 if(arg != ATOM_COND_ALWAYS)
615 SDEBUG(" taken: %s\n", execute?"yes":"no");
616 SDEBUG(" target: 0x%04X\n", target);
618 *ptr = ctx->start+target;
621 static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg)
623 uint8_t attr = U8((*ptr)++);
624 uint32_t dst, src1, src2, saved;
627 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
629 src1 = atom_get_src(ctx, attr, ptr);
631 src2 = atom_get_src(ctx, attr, ptr);
635 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
638 static void atom_op_move(atom_exec_context *ctx, int *ptr, int arg)
640 uint8_t attr = U8((*ptr)++);
643 if(((attr>>3)&7) != ATOM_SRC_DWORD)
644 atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
646 atom_skip_dst(ctx, arg, attr, ptr);
650 src = atom_get_src(ctx, attr, ptr);
652 atom_put_dst(ctx, arg, attr, &dptr, src, saved);
655 static void atom_op_mul(atom_exec_context *ctx, int *ptr, int arg)
657 uint8_t attr = U8((*ptr)++);
660 dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
662 src = atom_get_src(ctx, attr, ptr);
663 ctx->ctx->divmul[0] = dst*src;
666 static void atom_op_nop(atom_exec_context *ctx, int *ptr, int arg)
671 static void atom_op_or(atom_exec_context *ctx, int *ptr, int arg)
673 uint8_t attr = U8((*ptr)++);
674 uint32_t dst, src, saved;
677 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
679 src = atom_get_src(ctx, attr, ptr);
682 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
685 static void atom_op_postcard(atom_exec_context *ctx, int *ptr, int arg)
687 uint8_t val = U8((*ptr)++);
688 SDEBUG("POST card output: 0x%02X\n", val);
691 static void atom_op_repeat(atom_exec_context *ctx, int *ptr, int arg)
693 printk(KERN_INFO "unimplemented!\n");
696 static void atom_op_restorereg(atom_exec_context *ctx, int *ptr, int arg)
698 printk(KERN_INFO "unimplemented!\n");
701 static void atom_op_savereg(atom_exec_context *ctx, int *ptr, int arg)
703 printk(KERN_INFO "unimplemented!\n");
706 static void atom_op_setdatablock(atom_exec_context *ctx, int *ptr, int arg)
710 SDEBUG(" block: %d\n", idx);
712 ctx->ctx->data_block = 0;
714 ctx->ctx->data_block = ctx->start;
716 ctx->ctx->data_block = U16(ctx->ctx->data_table + 4 + 2*idx);
717 SDEBUG(" base: 0x%04X\n", ctx->ctx->data_block);
720 static void atom_op_setfbbase(atom_exec_context *ctx, int *ptr, int arg)
722 uint8_t attr = U8((*ptr)++);
723 SDEBUG(" fb_base: ");
724 ctx->ctx->fb_base = atom_get_src(ctx, attr, ptr);
727 static void atom_op_setport(atom_exec_context *ctx, int *ptr, int arg)
733 if(port < ATOM_IO_NAMES_CNT)
734 SDEBUG(" port: %d (%s)\n", port, atom_io_names[port]);
736 SDEBUG(" port: %d\n", port);
738 ctx->ctx->io_mode = ATOM_IO_MM;
740 ctx->ctx->io_mode = ATOM_IO_IIO|port;
744 ctx->ctx->io_mode = ATOM_IO_PCI;
747 case ATOM_PORT_SYSIO:
748 ctx->ctx->io_mode = ATOM_IO_SYSIO;
754 static void atom_op_setregblock(atom_exec_context *ctx, int *ptr, int arg)
756 ctx->ctx->reg_block = U16(*ptr);
758 SDEBUG(" base: 0x%04X\n", ctx->ctx->reg_block);
761 static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg)
763 uint8_t attr = U8((*ptr)++), shift;
767 attr |= atom_def_dst[attr>>3]<<6;
769 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
770 shift = U8((*ptr)++);
771 SDEBUG(" shift: %d\n", shift);
774 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
777 static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg)
779 uint8_t attr = U8((*ptr)++), shift;
783 attr |= atom_def_dst[attr>>3]<<6;
785 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
786 shift = U8((*ptr)++);
787 SDEBUG(" shift: %d\n", shift);
790 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
793 static void atom_op_sub(atom_exec_context *ctx, int *ptr, int arg)
795 uint8_t attr = U8((*ptr)++);
796 uint32_t dst, src, saved;
799 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
801 src = atom_get_src(ctx, attr, ptr);
804 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
807 static void atom_op_switch(atom_exec_context *ctx, int *ptr, int arg)
809 uint8_t attr = U8((*ptr)++);
810 uint32_t src, val, target;
812 src = atom_get_src(ctx, attr, ptr);
813 while(U16(*ptr) != ATOM_CASE_END)
814 if(U8(*ptr) == ATOM_CASE_MAGIC) {
817 val = atom_get_src(ctx, (attr&0x38)|ATOM_ARG_IMM, ptr);
820 SDEBUG(" target: %04X\n", target);
821 *ptr = ctx->start+target;
826 printk(KERN_INFO "Bad case.\n");
832 static void atom_op_test(atom_exec_context *ctx, int *ptr, int arg)
834 uint8_t attr = U8((*ptr)++);
837 dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
839 src = atom_get_src(ctx, attr, ptr);
840 ctx->ctx->cs_equal = ((dst & src) == 0);
841 SDEBUG(" result: %s\n", ctx->ctx->cs_equal?"EQ":"NE");
844 static void atom_op_xor(atom_exec_context *ctx, int *ptr, int arg)
846 uint8_t attr = U8((*ptr)++);
847 uint32_t dst, src, saved;
850 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
852 src = atom_get_src(ctx, attr, ptr);
855 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
858 static void atom_op_debug(atom_exec_context *ctx, int *ptr, int arg)
860 printk(KERN_INFO "unimplemented!\n");
864 void (*func)(atom_exec_context *, int *, int);
866 } opcode_table[ATOM_OP_CNT] = {
868 { atom_op_move, ATOM_ARG_REG },
869 { atom_op_move, ATOM_ARG_PS },
870 { atom_op_move, ATOM_ARG_WS },
871 { atom_op_move, ATOM_ARG_FB },
872 { atom_op_move, ATOM_ARG_PLL },
873 { atom_op_move, ATOM_ARG_MC },
874 { atom_op_and, ATOM_ARG_REG },
875 { atom_op_and, ATOM_ARG_PS },
876 { atom_op_and, ATOM_ARG_WS },
877 { atom_op_and, ATOM_ARG_FB },
878 { atom_op_and, ATOM_ARG_PLL },
879 { atom_op_and, ATOM_ARG_MC },
880 { atom_op_or, ATOM_ARG_REG },
881 { atom_op_or, ATOM_ARG_PS },
882 { atom_op_or, ATOM_ARG_WS },
883 { atom_op_or, ATOM_ARG_FB },
884 { atom_op_or, ATOM_ARG_PLL },
885 { atom_op_or, ATOM_ARG_MC },
886 { atom_op_shl, ATOM_ARG_REG },
887 { atom_op_shl, ATOM_ARG_PS },
888 { atom_op_shl, ATOM_ARG_WS },
889 { atom_op_shl, ATOM_ARG_FB },
890 { atom_op_shl, ATOM_ARG_PLL },
891 { atom_op_shl, ATOM_ARG_MC },
892 { atom_op_shr, ATOM_ARG_REG },
893 { atom_op_shr, ATOM_ARG_PS },
894 { atom_op_shr, ATOM_ARG_WS },
895 { atom_op_shr, ATOM_ARG_FB },
896 { atom_op_shr, ATOM_ARG_PLL },
897 { atom_op_shr, ATOM_ARG_MC },
898 { atom_op_mul, ATOM_ARG_REG },
899 { atom_op_mul, ATOM_ARG_PS },
900 { atom_op_mul, ATOM_ARG_WS },
901 { atom_op_mul, ATOM_ARG_FB },
902 { atom_op_mul, ATOM_ARG_PLL },
903 { atom_op_mul, ATOM_ARG_MC },
904 { atom_op_div, ATOM_ARG_REG },
905 { atom_op_div, ATOM_ARG_PS },
906 { atom_op_div, ATOM_ARG_WS },
907 { atom_op_div, ATOM_ARG_FB },
908 { atom_op_div, ATOM_ARG_PLL },
909 { atom_op_div, ATOM_ARG_MC },
910 { atom_op_add, ATOM_ARG_REG },
911 { atom_op_add, ATOM_ARG_PS },
912 { atom_op_add, ATOM_ARG_WS },
913 { atom_op_add, ATOM_ARG_FB },
914 { atom_op_add, ATOM_ARG_PLL },
915 { atom_op_add, ATOM_ARG_MC },
916 { atom_op_sub, ATOM_ARG_REG },
917 { atom_op_sub, ATOM_ARG_PS },
918 { atom_op_sub, ATOM_ARG_WS },
919 { atom_op_sub, ATOM_ARG_FB },
920 { atom_op_sub, ATOM_ARG_PLL },
921 { atom_op_sub, ATOM_ARG_MC },
922 { atom_op_setport, ATOM_PORT_ATI },
923 { atom_op_setport, ATOM_PORT_PCI },
924 { atom_op_setport, ATOM_PORT_SYSIO },
925 { atom_op_setregblock, 0 },
926 { atom_op_setfbbase, 0 },
927 { atom_op_compare, ATOM_ARG_REG },
928 { atom_op_compare, ATOM_ARG_PS },
929 { atom_op_compare, ATOM_ARG_WS },
930 { atom_op_compare, ATOM_ARG_FB },
931 { atom_op_compare, ATOM_ARG_PLL },
932 { atom_op_compare, ATOM_ARG_MC },
933 { atom_op_switch, 0 },
934 { atom_op_jump, ATOM_COND_ALWAYS },
935 { atom_op_jump, ATOM_COND_EQUAL },
936 { atom_op_jump, ATOM_COND_BELOW },
937 { atom_op_jump, ATOM_COND_ABOVE },
938 { atom_op_jump, ATOM_COND_BELOWOREQUAL },
939 { atom_op_jump, ATOM_COND_ABOVEOREQUAL },
940 { atom_op_jump, ATOM_COND_NOTEQUAL },
941 { atom_op_test, ATOM_ARG_REG },
942 { atom_op_test, ATOM_ARG_PS },
943 { atom_op_test, ATOM_ARG_WS },
944 { atom_op_test, ATOM_ARG_FB },
945 { atom_op_test, ATOM_ARG_PLL },
946 { atom_op_test, ATOM_ARG_MC },
947 { atom_op_delay, ATOM_UNIT_MILLISEC },
948 { atom_op_delay, ATOM_UNIT_MICROSEC },
949 { atom_op_calltable, 0 },
950 { atom_op_repeat, 0 },
951 { atom_op_clear, ATOM_ARG_REG },
952 { atom_op_clear, ATOM_ARG_PS },
953 { atom_op_clear, ATOM_ARG_WS },
954 { atom_op_clear, ATOM_ARG_FB },
955 { atom_op_clear, ATOM_ARG_PLL },
956 { atom_op_clear, ATOM_ARG_MC },
959 { atom_op_mask, ATOM_ARG_REG },
960 { atom_op_mask, ATOM_ARG_PS },
961 { atom_op_mask, ATOM_ARG_WS },
962 { atom_op_mask, ATOM_ARG_FB },
963 { atom_op_mask, ATOM_ARG_PLL },
964 { atom_op_mask, ATOM_ARG_MC },
965 { atom_op_postcard, 0 },
967 { atom_op_savereg, 0 },
968 { atom_op_restorereg, 0 },
969 { atom_op_setdatablock, 0 },
970 { atom_op_xor, ATOM_ARG_REG },
971 { atom_op_xor, ATOM_ARG_PS },
972 { atom_op_xor, ATOM_ARG_WS },
973 { atom_op_xor, ATOM_ARG_FB },
974 { atom_op_xor, ATOM_ARG_PLL },
975 { atom_op_xor, ATOM_ARG_MC },
976 { atom_op_shl, ATOM_ARG_REG },
977 { atom_op_shl, ATOM_ARG_PS },
978 { atom_op_shl, ATOM_ARG_WS },
979 { atom_op_shl, ATOM_ARG_FB },
980 { atom_op_shl, ATOM_ARG_PLL },
981 { atom_op_shl, ATOM_ARG_MC },
982 { atom_op_shr, ATOM_ARG_REG },
983 { atom_op_shr, ATOM_ARG_PS },
984 { atom_op_shr, ATOM_ARG_WS },
985 { atom_op_shr, ATOM_ARG_FB },
986 { atom_op_shr, ATOM_ARG_PLL },
987 { atom_op_shr, ATOM_ARG_MC },
988 { atom_op_debug, 0 },
991 void atom_execute_table(struct atom_context *ctx, int index, uint32_t *params)
993 int base = CU16(ctx->cmd_table+4+2*index);
994 int len, ws, ps, ptr;
996 atom_exec_context ectx;
1001 len = CU16(base+ATOM_CT_SIZE_PTR);
1002 ws = CU8(base+ATOM_CT_WS_PTR);
1003 ps = CU8(base+ATOM_CT_PS_PTR) & ATOM_CT_PS_MASK;
1004 ptr = base+ATOM_CT_CODE_PTR;
1006 SDEBUG(">> execute %04X (len %d, WS %d, PS %d)\n", base, len, ws, ps);
1008 /* reset reg block */
1011 ectx.ps_shift = ps/4;
1015 ectx.ws = kzalloc(4*ws, GFP_KERNEL);
1022 if(op<ATOM_OP_NAMES_CNT)
1023 SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr-1);
1025 SDEBUG("[%d] @ 0x%04X\n", op, ptr-1);
1027 if(op<ATOM_OP_CNT && op>0)
1028 opcode_table[op].func(&ectx, &ptr, opcode_table[op].arg);
1032 if(op == ATOM_OP_EOT)
1042 static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 };
1043 static void atom_index_iio(struct atom_context *ctx, int base)
1045 ctx->iio = kzalloc(2*256, GFP_KERNEL);
1046 while(CU8(base) == ATOM_IIO_START) {
1047 ctx->iio[CU8(base+1)] = base+2;
1049 while(CU8(base) != ATOM_IIO_END)
1050 base += atom_iio_len[CU8(base)];
1055 struct atom_context *atom_parse(struct card_info *card, void *bios)
1058 struct atom_context *ctx = kzalloc(sizeof(struct atom_context), GFP_KERNEL);
1064 if(CU16(0) != ATOM_BIOS_MAGIC) {
1065 printk(KERN_INFO "Invalid BIOS magic.\n");
1069 if(strncmp(CSTR(ATOM_ATI_MAGIC_PTR), ATOM_ATI_MAGIC, strlen(ATOM_ATI_MAGIC))) {
1070 printk(KERN_INFO "Invalid ATI magic.\n");
1075 base = CU16(ATOM_ROM_TABLE_PTR);
1076 if(strncmp(CSTR(base+ATOM_ROM_MAGIC_PTR), ATOM_ROM_MAGIC, strlen(ATOM_ROM_MAGIC))) {
1077 printk(KERN_INFO "Invalid ATOM magic.\n");
1082 ctx->cmd_table = CU16(base+ATOM_ROM_CMD_PTR);
1083 ctx->data_table = CU16(base+ATOM_ROM_DATA_PTR);
1084 atom_index_iio(ctx, CU16(ctx->data_table+ATOM_DATA_IIO_PTR)+4);
1086 str = CSTR(CU16(base+ATOM_ROM_MSG_PTR));
1087 while(*str && ((*str == '\n') || (*str == '\r')))
1089 printk(KERN_INFO "ATOM BIOS: %s", str);
1094 int atom_asic_init(struct atom_context *ctx)
1096 int hwi = CU16(ctx->data_table + ATOM_DATA_FWI_PTR);
1100 ps[0] = CU32(hwi + ATOM_FWI_DEFSCLK_PTR);
1101 ps[1] = CU32(hwi + ATOM_FWI_DEFMCLK_PTR);
1102 if(!ps[0] || !ps[1])
1105 if(!CU16(ctx->cmd_table+4+2*ATOM_CMD_INIT))
1107 atom_execute_table(ctx, ATOM_CMD_INIT, ps);
1112 void atom_destroy(struct atom_context *ctx)
1120 void atom_parse_data_header(struct atom_context *ctx, int index, uint16_t *size, uint8_t *frev, uint8_t *crev, uint16_t *data_start)
1122 int offset = index * 2 + 4;
1123 int idx = CU16(ctx->data_table + offset);
1128 *frev = CU8(idx + 2);
1130 *crev = CU8(idx + 3);
1135 void atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t *frev, uint8_t *crev)
1137 int offset = index * 2 + 4;
1138 int idx = CU16(ctx->cmd_table + offset);
1141 *frev = CU8(idx + 2);
1143 *crev = CU8(idx + 3);