aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/atom.c
diff options
context:
space:
mode:
authorAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
committerAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
commitada47b5fe13d89735805b566185f4885f5a3f750 (patch)
tree644b88f8a71896307d71438e9b3af49126ffb22b /drivers/gpu/drm/radeon/atom.c
parent43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff)
parent3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff)
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/gpu/drm/radeon/atom.c')
-rw-r--r--drivers/gpu/drm/radeon/atom.c233
1 files changed, 195 insertions, 38 deletions
diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c
index d67c42555ab9..1d569830ed99 100644
--- a/drivers/gpu/drm/radeon/atom.c
+++ b/drivers/gpu/drm/radeon/atom.c
@@ -24,6 +24,8 @@
24 24
25#include <linux/module.h> 25#include <linux/module.h>
26#include <linux/sched.h> 26#include <linux/sched.h>
27#include <linux/slab.h>
28#include <asm/unaligned.h>
27 29
28#define ATOM_DEBUG 30#define ATOM_DEBUG
29 31
@@ -51,14 +53,17 @@
51 53
52typedef struct { 54typedef struct {
53 struct atom_context *ctx; 55 struct atom_context *ctx;
54
55 uint32_t *ps, *ws; 56 uint32_t *ps, *ws;
56 int ps_shift; 57 int ps_shift;
57 uint16_t start; 58 uint16_t start;
59 unsigned last_jump;
60 unsigned long last_jump_jiffies;
61 bool abort;
58} atom_exec_context; 62} atom_exec_context;
59 63
60int atom_debug = 0; 64int atom_debug = 0;
61void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params); 65static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params);
66int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params);
62 67
63static uint32_t atom_arg_mask[8] = 68static uint32_t atom_arg_mask[8] =
64 { 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000, 69 { 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000,
@@ -211,7 +216,9 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr,
211 case ATOM_ARG_PS: 216 case ATOM_ARG_PS:
212 idx = U8(*ptr); 217 idx = U8(*ptr);
213 (*ptr)++; 218 (*ptr)++;
214 val = le32_to_cpu(ctx->ps[idx]); 219 /* get_unaligned_le32 avoids unaligned accesses from atombios
220 * tables, noticed on a DEC Alpha. */
221 val = get_unaligned_le32((u32 *)&ctx->ps[idx]);
215 if (print) 222 if (print)
216 DEBUG("PS[0x%02X,0x%04X]", idx, val); 223 DEBUG("PS[0x%02X,0x%04X]", idx, val);
217 break; 224 break;
@@ -245,6 +252,9 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr,
245 case ATOM_WS_ATTRIBUTES: 252 case ATOM_WS_ATTRIBUTES:
246 val = gctx->io_attr; 253 val = gctx->io_attr;
247 break; 254 break;
255 case ATOM_WS_REGPTR:
256 val = gctx->reg_block;
257 break;
248 default: 258 default:
249 val = ctx->ws[idx]; 259 val = ctx->ws[idx];
250 } 260 }
@@ -263,10 +273,10 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr,
263 case ATOM_ARG_FB: 273 case ATOM_ARG_FB:
264 idx = U8(*ptr); 274 idx = U8(*ptr);
265 (*ptr)++; 275 (*ptr)++;
276 val = gctx->scratch[((gctx->fb_base + idx) / 4)];
266 if (print) 277 if (print)
267 DEBUG("FB[0x%02X]", idx); 278 DEBUG("FB[0x%02X]", idx);
268 printk(KERN_INFO "FB access is not implemented.\n"); 279 break;
269 return 0;
270 case ATOM_ARG_IMM: 280 case ATOM_ARG_IMM:
271 switch (align) { 281 switch (align) {
272 case ATOM_SRC_DWORD: 282 case ATOM_SRC_DWORD:
@@ -384,6 +394,32 @@ static uint32_t atom_get_src(atom_exec_context *ctx, uint8_t attr, int *ptr)
384 return atom_get_src_int(ctx, attr, ptr, NULL, 1); 394 return atom_get_src_int(ctx, attr, ptr, NULL, 1);
385} 395}
386 396
397static uint32_t atom_get_src_direct(atom_exec_context *ctx, uint8_t align, int *ptr)
398{
399 uint32_t val = 0xCDCDCDCD;
400
401 switch (align) {
402 case ATOM_SRC_DWORD:
403 val = U32(*ptr);
404 (*ptr) += 4;
405 break;
406 case ATOM_SRC_WORD0:
407 case ATOM_SRC_WORD8:
408 case ATOM_SRC_WORD16:
409 val = U16(*ptr);
410 (*ptr) += 2;
411 break;
412 case ATOM_SRC_BYTE0:
413 case ATOM_SRC_BYTE8:
414 case ATOM_SRC_BYTE16:
415 case ATOM_SRC_BYTE24:
416 val = U8(*ptr);
417 (*ptr)++;
418 break;
419 }
420 return val;
421}
422
387static uint32_t atom_get_dst(atom_exec_context *ctx, int arg, uint8_t attr, 423static uint32_t atom_get_dst(atom_exec_context *ctx, int arg, uint8_t attr,
388 int *ptr, uint32_t *saved, int print) 424 int *ptr, uint32_t *saved, int print)
389{ 425{
@@ -481,6 +517,9 @@ static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr,
481 case ATOM_WS_ATTRIBUTES: 517 case ATOM_WS_ATTRIBUTES:
482 gctx->io_attr = val; 518 gctx->io_attr = val;
483 break; 519 break;
520 case ATOM_WS_REGPTR:
521 gctx->reg_block = val;
522 break;
484 default: 523 default:
485 ctx->ws[idx] = val; 524 ctx->ws[idx] = val;
486 } 525 }
@@ -488,9 +527,9 @@ static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr,
488 case ATOM_ARG_FB: 527 case ATOM_ARG_FB:
489 idx = U8(*ptr); 528 idx = U8(*ptr);
490 (*ptr)++; 529 (*ptr)++;
530 gctx->scratch[((gctx->fb_base + idx) / 4)] = val;
491 DEBUG("FB[0x%02X]", idx); 531 DEBUG("FB[0x%02X]", idx);
492 printk(KERN_INFO "FB access is not implemented.\n"); 532 break;
493 return;
494 case ATOM_ARG_PLL: 533 case ATOM_ARG_PLL:
495 idx = U8(*ptr); 534 idx = U8(*ptr);
496 (*ptr)++; 535 (*ptr)++;
@@ -568,12 +607,17 @@ static void atom_op_beep(atom_exec_context *ctx, int *ptr, int arg)
568static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg) 607static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg)
569{ 608{
570 int idx = U8((*ptr)++); 609 int idx = U8((*ptr)++);
610 int r = 0;
611
571 if (idx < ATOM_TABLE_NAMES_CNT) 612 if (idx < ATOM_TABLE_NAMES_CNT)
572 SDEBUG(" table: %d (%s)\n", idx, atom_table_names[idx]); 613 SDEBUG(" table: %d (%s)\n", idx, atom_table_names[idx]);
573 else 614 else
574 SDEBUG(" table: %d\n", idx); 615 SDEBUG(" table: %d\n", idx);
575 if (U16(ctx->ctx->cmd_table + 4 + 2 * idx)) 616 if (U16(ctx->ctx->cmd_table + 4 + 2 * idx))
576 atom_execute_table(ctx->ctx, idx, ctx->ps + ctx->ps_shift); 617 r = atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift);
618 if (r) {
619 ctx->abort = true;
620 }
577} 621}
578 622
579static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg) 623static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg)
@@ -607,7 +651,7 @@ static void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg)
607 uint8_t count = U8((*ptr)++); 651 uint8_t count = U8((*ptr)++);
608 SDEBUG(" count: %d\n", count); 652 SDEBUG(" count: %d\n", count);
609 if (arg == ATOM_UNIT_MICROSEC) 653 if (arg == ATOM_UNIT_MICROSEC)
610 schedule_timeout_uninterruptible(usecs_to_jiffies(count)); 654 udelay(count);
611 else 655 else
612 schedule_timeout_uninterruptible(msecs_to_jiffies(count)); 656 schedule_timeout_uninterruptible(msecs_to_jiffies(count));
613} 657}
@@ -637,6 +681,8 @@ static void atom_op_eot(atom_exec_context *ctx, int *ptr, int arg)
637static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg) 681static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
638{ 682{
639 int execute = 0, target = U16(*ptr); 683 int execute = 0, target = U16(*ptr);
684 unsigned long cjiffies;
685
640 (*ptr) += 2; 686 (*ptr) += 2;
641 switch (arg) { 687 switch (arg) {
642 case ATOM_COND_ABOVE: 688 case ATOM_COND_ABOVE:
@@ -664,8 +710,25 @@ static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
664 if (arg != ATOM_COND_ALWAYS) 710 if (arg != ATOM_COND_ALWAYS)
665 SDEBUG(" taken: %s\n", execute ? "yes" : "no"); 711 SDEBUG(" taken: %s\n", execute ? "yes" : "no");
666 SDEBUG(" target: 0x%04X\n", target); 712 SDEBUG(" target: 0x%04X\n", target);
667 if (execute) 713 if (execute) {
714 if (ctx->last_jump == (ctx->start + target)) {
715 cjiffies = jiffies;
716 if (time_after(cjiffies, ctx->last_jump_jiffies)) {
717 cjiffies -= ctx->last_jump_jiffies;
718 if ((jiffies_to_msecs(cjiffies) > 1000)) {
719 DRM_ERROR("atombios stuck in loop for more than 1sec aborting\n");
720 ctx->abort = true;
721 }
722 } else {
723 /* jiffies wrap around we will just wait a little longer */
724 ctx->last_jump_jiffies = jiffies;
725 }
726 } else {
727 ctx->last_jump = ctx->start + target;
728 ctx->last_jump_jiffies = jiffies;
729 }
668 *ptr = ctx->start + target; 730 *ptr = ctx->start + target;
731 }
669} 732}
670 733
671static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg) 734static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg)
@@ -676,7 +739,7 @@ static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg)
676 SDEBUG(" dst: "); 739 SDEBUG(" dst: ");
677 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 740 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
678 SDEBUG(" src1: "); 741 SDEBUG(" src1: ");
679 src1 = atom_get_src(ctx, attr, ptr); 742 src1 = atom_get_src_direct(ctx, ((attr >> 3) & 7), ptr);
680 SDEBUG(" src2: "); 743 SDEBUG(" src2: ");
681 src2 = atom_get_src(ctx, attr, ptr); 744 src2 = atom_get_src(ctx, attr, ptr);
682 dst &= src1; 745 dst &= src1;
@@ -808,7 +871,7 @@ static void atom_op_setregblock(atom_exec_context *ctx, int *ptr, int arg)
808 SDEBUG(" base: 0x%04X\n", ctx->ctx->reg_block); 871 SDEBUG(" base: 0x%04X\n", ctx->ctx->reg_block);
809} 872}
810 873
811static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg) 874static void atom_op_shift_left(atom_exec_context *ctx, int *ptr, int arg)
812{ 875{
813 uint8_t attr = U8((*ptr)++), shift; 876 uint8_t attr = U8((*ptr)++), shift;
814 uint32_t saved, dst; 877 uint32_t saved, dst;
@@ -817,14 +880,14 @@ static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg)
817 attr |= atom_def_dst[attr >> 3] << 6; 880 attr |= atom_def_dst[attr >> 3] << 6;
818 SDEBUG(" dst: "); 881 SDEBUG(" dst: ");
819 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 882 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
820 shift = U8((*ptr)++); 883 shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr);
821 SDEBUG(" shift: %d\n", shift); 884 SDEBUG(" shift: %d\n", shift);
822 dst <<= shift; 885 dst <<= shift;
823 SDEBUG(" dst: "); 886 SDEBUG(" dst: ");
824 atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 887 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
825} 888}
826 889
827static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg) 890static void atom_op_shift_right(atom_exec_context *ctx, int *ptr, int arg)
828{ 891{
829 uint8_t attr = U8((*ptr)++), shift; 892 uint8_t attr = U8((*ptr)++), shift;
830 uint32_t saved, dst; 893 uint32_t saved, dst;
@@ -833,9 +896,47 @@ static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg)
833 attr |= atom_def_dst[attr >> 3] << 6; 896 attr |= atom_def_dst[attr >> 3] << 6;
834 SDEBUG(" dst: "); 897 SDEBUG(" dst: ");
835 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 898 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
836 shift = U8((*ptr)++); 899 shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr);
900 SDEBUG(" shift: %d\n", shift);
901 dst >>= shift;
902 SDEBUG(" dst: ");
903 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
904}
905
906static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg)
907{
908 uint8_t attr = U8((*ptr)++), shift;
909 uint32_t saved, dst;
910 int dptr = *ptr;
911 uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3];
912 SDEBUG(" dst: ");
913 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
914 /* op needs to full dst value */
915 dst = saved;
916 shift = atom_get_src(ctx, attr, ptr);
917 SDEBUG(" shift: %d\n", shift);
918 dst <<= shift;
919 dst &= atom_arg_mask[dst_align];
920 dst >>= atom_arg_shift[dst_align];
921 SDEBUG(" dst: ");
922 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
923}
924
925static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg)
926{
927 uint8_t attr = U8((*ptr)++), shift;
928 uint32_t saved, dst;
929 int dptr = *ptr;
930 uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3];
931 SDEBUG(" dst: ");
932 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
933 /* op needs to full dst value */
934 dst = saved;
935 shift = atom_get_src(ctx, attr, ptr);
837 SDEBUG(" shift: %d\n", shift); 936 SDEBUG(" shift: %d\n", shift);
838 dst >>= shift; 937 dst >>= shift;
938 dst &= atom_arg_mask[dst_align];
939 dst >>= atom_arg_shift[dst_align];
839 SDEBUG(" dst: "); 940 SDEBUG(" dst: ");
840 atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 941 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
841} 942}
@@ -936,18 +1037,18 @@ static struct {
936 atom_op_or, ATOM_ARG_FB}, { 1037 atom_op_or, ATOM_ARG_FB}, {
937 atom_op_or, ATOM_ARG_PLL}, { 1038 atom_op_or, ATOM_ARG_PLL}, {
938 atom_op_or, ATOM_ARG_MC}, { 1039 atom_op_or, ATOM_ARG_MC}, {
939 atom_op_shl, ATOM_ARG_REG}, { 1040 atom_op_shift_left, ATOM_ARG_REG}, {
940 atom_op_shl, ATOM_ARG_PS}, { 1041 atom_op_shift_left, ATOM_ARG_PS}, {
941 atom_op_shl, ATOM_ARG_WS}, { 1042 atom_op_shift_left, ATOM_ARG_WS}, {
942 atom_op_shl, ATOM_ARG_FB}, { 1043 atom_op_shift_left, ATOM_ARG_FB}, {
943 atom_op_shl, ATOM_ARG_PLL}, { 1044 atom_op_shift_left, ATOM_ARG_PLL}, {
944 atom_op_shl, ATOM_ARG_MC}, { 1045 atom_op_shift_left, ATOM_ARG_MC}, {
945 atom_op_shr, ATOM_ARG_REG}, { 1046 atom_op_shift_right, ATOM_ARG_REG}, {
946 atom_op_shr, ATOM_ARG_PS}, { 1047 atom_op_shift_right, ATOM_ARG_PS}, {
947 atom_op_shr, ATOM_ARG_WS}, { 1048 atom_op_shift_right, ATOM_ARG_WS}, {
948 atom_op_shr, ATOM_ARG_FB}, { 1049 atom_op_shift_right, ATOM_ARG_FB}, {
949 atom_op_shr, ATOM_ARG_PLL}, { 1050 atom_op_shift_right, ATOM_ARG_PLL}, {
950 atom_op_shr, ATOM_ARG_MC}, { 1051 atom_op_shift_right, ATOM_ARG_MC}, {
951 atom_op_mul, ATOM_ARG_REG}, { 1052 atom_op_mul, ATOM_ARG_REG}, {
952 atom_op_mul, ATOM_ARG_PS}, { 1053 atom_op_mul, ATOM_ARG_PS}, {
953 atom_op_mul, ATOM_ARG_WS}, { 1054 atom_op_mul, ATOM_ARG_WS}, {
@@ -1040,15 +1141,16 @@ static struct {
1040 atom_op_shr, ATOM_ARG_MC}, { 1141 atom_op_shr, ATOM_ARG_MC}, {
1041atom_op_debug, 0},}; 1142atom_op_debug, 0},};
1042 1143
1043void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params) 1144static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params)
1044{ 1145{
1045 int base = CU16(ctx->cmd_table + 4 + 2 * index); 1146 int base = CU16(ctx->cmd_table + 4 + 2 * index);
1046 int len, ws, ps, ptr; 1147 int len, ws, ps, ptr;
1047 unsigned char op; 1148 unsigned char op;
1048 atom_exec_context ectx; 1149 atom_exec_context ectx;
1150 int ret = 0;
1049 1151
1050 if (!base) 1152 if (!base)
1051 return; 1153 return -EINVAL;
1052 1154
1053 len = CU16(base + ATOM_CT_SIZE_PTR); 1155 len = CU16(base + ATOM_CT_SIZE_PTR);
1054 ws = CU8(base + ATOM_CT_WS_PTR); 1156 ws = CU8(base + ATOM_CT_WS_PTR);
@@ -1057,12 +1159,12 @@ void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
1057 1159
1058 SDEBUG(">> execute %04X (len %d, WS %d, PS %d)\n", base, len, ws, ps); 1160 SDEBUG(">> execute %04X (len %d, WS %d, PS %d)\n", base, len, ws, ps);
1059 1161
1060 /* reset reg block */
1061 ctx->reg_block = 0;
1062 ectx.ctx = ctx; 1162 ectx.ctx = ctx;
1063 ectx.ps_shift = ps / 4; 1163 ectx.ps_shift = ps / 4;
1064 ectx.start = base; 1164 ectx.start = base;
1065 ectx.ps = params; 1165 ectx.ps = params;
1166 ectx.abort = false;
1167 ectx.last_jump = 0;
1066 if (ws) 1168 if (ws)
1067 ectx.ws = kzalloc(4 * ws, GFP_KERNEL); 1169 ectx.ws = kzalloc(4 * ws, GFP_KERNEL);
1068 else 1170 else
@@ -1075,6 +1177,12 @@ void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
1075 SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr - 1); 1177 SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr - 1);
1076 else 1178 else
1077 SDEBUG("[%d] @ 0x%04X\n", op, ptr - 1); 1179 SDEBUG("[%d] @ 0x%04X\n", op, ptr - 1);
1180 if (ectx.abort) {
1181 DRM_ERROR("atombios stuck executing %04X (len %d, WS %d, PS %d) @ 0x%04X\n",
1182 base, len, ws, ps, ptr - 1);
1183 ret = -EINVAL;
1184 goto free;
1185 }
1078 1186
1079 if (op < ATOM_OP_CNT && op > 0) 1187 if (op < ATOM_OP_CNT && op > 0)
1080 opcode_table[op].func(&ectx, &ptr, 1188 opcode_table[op].func(&ectx, &ptr,
@@ -1088,8 +1196,26 @@ void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
1088 debug_depth--; 1196 debug_depth--;
1089 SDEBUG("<<\n"); 1197 SDEBUG("<<\n");
1090 1198
1199free:
1091 if (ws) 1200 if (ws)
1092 kfree(ectx.ws); 1201 kfree(ectx.ws);
1202 return ret;
1203}
1204
1205int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
1206{
1207 int r;
1208
1209 mutex_lock(&ctx->mutex);
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 r = atom_execute_table_locked(ctx, index, params);
1217 mutex_unlock(&ctx->mutex);
1218 return r;
1093} 1219}
1094 1220
1095static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 }; 1221static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 };
@@ -1173,9 +1299,7 @@ int atom_asic_init(struct atom_context *ctx)
1173 1299
1174 if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT)) 1300 if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT))
1175 return 1; 1301 return 1;
1176 atom_execute_table(ctx, ATOM_CMD_INIT, ps); 1302 return atom_execute_table(ctx, ATOM_CMD_INIT, ps);
1177
1178 return 0;
1179} 1303}
1180 1304
1181void atom_destroy(struct atom_context *ctx) 1305void atom_destroy(struct atom_context *ctx)
@@ -1185,12 +1309,16 @@ void atom_destroy(struct atom_context *ctx)
1185 kfree(ctx); 1309 kfree(ctx);
1186} 1310}
1187 1311
1188void atom_parse_data_header(struct atom_context *ctx, int index, 1312bool atom_parse_data_header(struct atom_context *ctx, int index,
1189 uint16_t * size, uint8_t * frev, uint8_t * crev, 1313 uint16_t * size, uint8_t * frev, uint8_t * crev,
1190 uint16_t * data_start) 1314 uint16_t * data_start)
1191{ 1315{
1192 int offset = index * 2 + 4; 1316 int offset = index * 2 + 4;
1193 int idx = CU16(ctx->data_table + offset); 1317 int idx = CU16(ctx->data_table + offset);
1318 u16 *mdt = (u16 *)(ctx->bios + ctx->data_table + 4);
1319
1320 if (!mdt[index])
1321 return false;
1194 1322
1195 if (size) 1323 if (size)
1196 *size = CU16(idx); 1324 *size = CU16(idx);
@@ -1199,18 +1327,47 @@ void atom_parse_data_header(struct atom_context *ctx, int index,
1199 if (crev) 1327 if (crev)
1200 *crev = CU8(idx + 3); 1328 *crev = CU8(idx + 3);
1201 *data_start = idx; 1329 *data_start = idx;
1202 return; 1330 return true;
1203} 1331}
1204 1332
1205void atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t * frev, 1333bool atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t * frev,
1206 uint8_t * crev) 1334 uint8_t * crev)
1207{ 1335{
1208 int offset = index * 2 + 4; 1336 int offset = index * 2 + 4;
1209 int idx = CU16(ctx->cmd_table + offset); 1337 int idx = CU16(ctx->cmd_table + offset);
1338 u16 *mct = (u16 *)(ctx->bios + ctx->cmd_table + 4);
1339
1340 if (!mct[index])
1341 return false;
1210 1342
1211 if (frev) 1343 if (frev)
1212 *frev = CU8(idx + 2); 1344 *frev = CU8(idx + 2);
1213 if (crev) 1345 if (crev)
1214 *crev = CU8(idx + 3); 1346 *crev = CU8(idx + 3);
1215 return; 1347 return true;
1348}
1349
1350int atom_allocate_fb_scratch(struct atom_context *ctx)
1351{
1352 int index = GetIndexIntoMasterTable(DATA, VRAM_UsageByFirmware);
1353 uint16_t data_offset;
1354 int usage_bytes = 0;
1355 struct _ATOM_VRAM_USAGE_BY_FIRMWARE *firmware_usage;
1356
1357 if (atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset)) {
1358 firmware_usage = (struct _ATOM_VRAM_USAGE_BY_FIRMWARE *)(ctx->bios + data_offset);
1359
1360 DRM_DEBUG("atom firmware requested %08x %dkb\n",
1361 firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware,
1362 firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb);
1363
1364 usage_bytes = firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb * 1024;
1365 }
1366 if (usage_bytes == 0)
1367 usage_bytes = 20 * 1024;
1368 /* allocate some scratch memory */
1369 ctx->scratch = kzalloc(usage_bytes, GFP_KERNEL);
1370 if (!ctx->scratch)
1371 return -ENOMEM;
1372 return 0;
1216} 1373}