Merge branch 'master' into export-slabh
[kernel.git] / drivers / gpu / drm / radeon / atom.c
1 /*
2  * Copyright 2008 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Author: Stanislaw Skowronek
23  */
24
25 #include <linux/module.h>
26 #include <linux/sched.h>
27 #include <linux/slab.h>
28 #include <asm/unaligned.h>
29
30 #define ATOM_DEBUG
31
32 #include "atom.h"
33 #include "atom-names.h"
34 #include "atom-bits.h"
35
36 #define ATOM_COND_ABOVE         0
37 #define ATOM_COND_ABOVEOREQUAL  1
38 #define ATOM_COND_ALWAYS        2
39 #define ATOM_COND_BELOW         3
40 #define ATOM_COND_BELOWOREQUAL  4
41 #define ATOM_COND_EQUAL         5
42 #define ATOM_COND_NOTEQUAL      6
43
44 #define ATOM_PORT_ATI   0
45 #define ATOM_PORT_PCI   1
46 #define ATOM_PORT_SYSIO 2
47
48 #define ATOM_UNIT_MICROSEC      0
49 #define ATOM_UNIT_MILLISEC      1
50
51 #define PLL_INDEX       2
52 #define PLL_DATA        3
53
54 typedef struct {
55         struct atom_context *ctx;
56         uint32_t *ps, *ws;
57         int ps_shift;
58         uint16_t start;
59         unsigned last_jump;
60         unsigned long last_jump_jiffies;
61         bool abort;
62 } atom_exec_context;
63
64 int atom_debug = 0;
65 static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params);
66 int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params);
67
68 static uint32_t atom_arg_mask[8] =
69     { 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000,
70 0xFF000000 };
71 static int atom_arg_shift[8] = { 0, 0, 8, 16, 0, 8, 16, 24 };
72
73 static int atom_dst_to_src[8][4] = {
74         /* translate destination alignment field to the source alignment encoding */
75         {0, 0, 0, 0},
76         {1, 2, 3, 0},
77         {1, 2, 3, 0},
78         {1, 2, 3, 0},
79         {4, 5, 6, 7},
80         {4, 5, 6, 7},
81         {4, 5, 6, 7},
82         {4, 5, 6, 7},
83 };
84 static int atom_def_dst[8] = { 0, 0, 1, 2, 0, 1, 2, 3 };
85
86 static int debug_depth = 0;
87 #ifdef ATOM_DEBUG
88 static void debug_print_spaces(int n)
89 {
90         while (n--)
91                 printk("   ");
92 }
93
94 #define DEBUG(...) do if (atom_debug) { printk(KERN_DEBUG __VA_ARGS__); } while (0)
95 #define SDEBUG(...) do if (atom_debug) { printk(KERN_DEBUG); debug_print_spaces(debug_depth); printk(__VA_ARGS__); } while (0)
96 #else
97 #define DEBUG(...) do { } while (0)
98 #define SDEBUG(...) do { } while (0)
99 #endif
100
101 static uint32_t atom_iio_execute(struct atom_context *ctx, int base,
102                                  uint32_t index, uint32_t data)
103 {
104         uint32_t temp = 0xCDCDCDCD;
105         while (1)
106                 switch (CU8(base)) {
107                 case ATOM_IIO_NOP:
108                         base++;
109                         break;
110                 case ATOM_IIO_READ:
111                         temp = ctx->card->reg_read(ctx->card, CU16(base + 1));
112                         base += 3;
113                         break;
114                 case ATOM_IIO_WRITE:
115                         (void)ctx->card->reg_read(ctx->card, CU16(base + 1));
116                         ctx->card->reg_write(ctx->card, CU16(base + 1), temp);
117                         base += 3;
118                         break;
119                 case ATOM_IIO_CLEAR:
120                         temp &=
121                             ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
122                               CU8(base + 2));
123                         base += 3;
124                         break;
125                 case ATOM_IIO_SET:
126                         temp |=
127                             (0xFFFFFFFF >> (32 - CU8(base + 1))) << CU8(base +
128                                                                         2);
129                         base += 3;
130                         break;
131                 case ATOM_IIO_MOVE_INDEX:
132                         temp &=
133                             ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
134                               CU8(base + 2));
135                         temp |=
136                             ((index >> CU8(base + 2)) &
137                              (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base +
138                                                                           3);
139                         base += 4;
140                         break;
141                 case ATOM_IIO_MOVE_DATA:
142                         temp &=
143                             ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
144                               CU8(base + 2));
145                         temp |=
146                             ((data >> CU8(base + 2)) &
147                              (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base +
148                                                                           3);
149                         base += 4;
150                         break;
151                 case ATOM_IIO_MOVE_ATTR:
152                         temp &=
153                             ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
154                               CU8(base + 2));
155                         temp |=
156                             ((ctx->
157                               io_attr >> CU8(base + 2)) & (0xFFFFFFFF >> (32 -
158                                                                           CU8
159                                                                           (base
160                                                                            +
161                                                                            1))))
162                             << CU8(base + 3);
163                         base += 4;
164                         break;
165                 case ATOM_IIO_END:
166                         return temp;
167                 default:
168                         printk(KERN_INFO "Unknown IIO opcode.\n");
169                         return 0;
170                 }
171 }
172
173 static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr,
174                                  int *ptr, uint32_t *saved, int print)
175 {
176         uint32_t idx, val = 0xCDCDCDCD, align, arg;
177         struct atom_context *gctx = ctx->ctx;
178         arg = attr & 7;
179         align = (attr >> 3) & 7;
180         switch (arg) {
181         case ATOM_ARG_REG:
182                 idx = U16(*ptr);
183                 (*ptr) += 2;
184                 if (print)
185                         DEBUG("REG[0x%04X]", idx);
186                 idx += gctx->reg_block;
187                 switch (gctx->io_mode) {
188                 case ATOM_IO_MM:
189                         val = gctx->card->reg_read(gctx->card, idx);
190                         break;
191                 case ATOM_IO_PCI:
192                         printk(KERN_INFO
193                                "PCI registers are not implemented.\n");
194                         return 0;
195                 case ATOM_IO_SYSIO:
196                         printk(KERN_INFO
197                                "SYSIO registers are not implemented.\n");
198                         return 0;
199                 default:
200                         if (!(gctx->io_mode & 0x80)) {
201                                 printk(KERN_INFO "Bad IO mode.\n");
202                                 return 0;
203                         }
204                         if (!gctx->iio[gctx->io_mode & 0x7F]) {
205                                 printk(KERN_INFO
206                                        "Undefined indirect IO read method %d.\n",
207                                        gctx->io_mode & 0x7F);
208                                 return 0;
209                         }
210                         val =
211                             atom_iio_execute(gctx,
212                                              gctx->iio[gctx->io_mode & 0x7F],
213                                              idx, 0);
214                 }
215                 break;
216         case ATOM_ARG_PS:
217                 idx = U8(*ptr);
218                 (*ptr)++;
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]);
222                 if (print)
223                         DEBUG("PS[0x%02X,0x%04X]", idx, val);
224                 break;
225         case ATOM_ARG_WS:
226                 idx = U8(*ptr);
227                 (*ptr)++;
228                 if (print)
229                         DEBUG("WS[0x%02X]", idx);
230                 switch (idx) {
231                 case ATOM_WS_QUOTIENT:
232                         val = gctx->divmul[0];
233                         break;
234                 case ATOM_WS_REMAINDER:
235                         val = gctx->divmul[1];
236                         break;
237                 case ATOM_WS_DATAPTR:
238                         val = gctx->data_block;
239                         break;
240                 case ATOM_WS_SHIFT:
241                         val = gctx->shift;
242                         break;
243                 case ATOM_WS_OR_MASK:
244                         val = 1 << gctx->shift;
245                         break;
246                 case ATOM_WS_AND_MASK:
247                         val = ~(1 << gctx->shift);
248                         break;
249                 case ATOM_WS_FB_WINDOW:
250                         val = gctx->fb_base;
251                         break;
252                 case ATOM_WS_ATTRIBUTES:
253                         val = gctx->io_attr;
254                         break;
255                 case ATOM_WS_REGPTR:
256                         val = gctx->reg_block;
257                         break;
258                 default:
259                         val = ctx->ws[idx];
260                 }
261                 break;
262         case ATOM_ARG_ID:
263                 idx = U16(*ptr);
264                 (*ptr) += 2;
265                 if (print) {
266                         if (gctx->data_block)
267                                 DEBUG("ID[0x%04X+%04X]", idx, gctx->data_block);
268                         else
269                                 DEBUG("ID[0x%04X]", idx);
270                 }
271                 val = U32(idx + gctx->data_block);
272                 break;
273         case ATOM_ARG_FB:
274                 idx = U8(*ptr);
275                 (*ptr)++;
276                 val = gctx->scratch[((gctx->fb_base + idx) / 4)];
277                 if (print)
278                         DEBUG("FB[0x%02X]", idx);
279                 break;
280         case ATOM_ARG_IMM:
281                 switch (align) {
282                 case ATOM_SRC_DWORD:
283                         val = U32(*ptr);
284                         (*ptr) += 4;
285                         if (print)
286                                 DEBUG("IMM 0x%08X\n", val);
287                         return val;
288                 case ATOM_SRC_WORD0:
289                 case ATOM_SRC_WORD8:
290                 case ATOM_SRC_WORD16:
291                         val = U16(*ptr);
292                         (*ptr) += 2;
293                         if (print)
294                                 DEBUG("IMM 0x%04X\n", val);
295                         return val;
296                 case ATOM_SRC_BYTE0:
297                 case ATOM_SRC_BYTE8:
298                 case ATOM_SRC_BYTE16:
299                 case ATOM_SRC_BYTE24:
300                         val = U8(*ptr);
301                         (*ptr)++;
302                         if (print)
303                                 DEBUG("IMM 0x%02X\n", val);
304                         return val;
305                 }
306                 return 0;
307         case ATOM_ARG_PLL:
308                 idx = U8(*ptr);
309                 (*ptr)++;
310                 if (print)
311                         DEBUG("PLL[0x%02X]", idx);
312                 val = gctx->card->pll_read(gctx->card, idx);
313                 break;
314         case ATOM_ARG_MC:
315                 idx = U8(*ptr);
316                 (*ptr)++;
317                 if (print)
318                         DEBUG("MC[0x%02X]", idx);
319                 val = gctx->card->mc_read(gctx->card, idx);
320                 break;
321         }
322         if (saved)
323                 *saved = val;
324         val &= atom_arg_mask[align];
325         val >>= atom_arg_shift[align];
326         if (print)
327                 switch (align) {
328                 case ATOM_SRC_DWORD:
329                         DEBUG(".[31:0] -> 0x%08X\n", val);
330                         break;
331                 case ATOM_SRC_WORD0:
332                         DEBUG(".[15:0] -> 0x%04X\n", val);
333                         break;
334                 case ATOM_SRC_WORD8:
335                         DEBUG(".[23:8] -> 0x%04X\n", val);
336                         break;
337                 case ATOM_SRC_WORD16:
338                         DEBUG(".[31:16] -> 0x%04X\n", val);
339                         break;
340                 case ATOM_SRC_BYTE0:
341                         DEBUG(".[7:0] -> 0x%02X\n", val);
342                         break;
343                 case ATOM_SRC_BYTE8:
344                         DEBUG(".[15:8] -> 0x%02X\n", val);
345                         break;
346                 case ATOM_SRC_BYTE16:
347                         DEBUG(".[23:16] -> 0x%02X\n", val);
348                         break;
349                 case ATOM_SRC_BYTE24:
350                         DEBUG(".[31:24] -> 0x%02X\n", val);
351                         break;
352                 }
353         return val;
354 }
355
356 static void atom_skip_src_int(atom_exec_context *ctx, uint8_t attr, int *ptr)
357 {
358         uint32_t align = (attr >> 3) & 7, arg = attr & 7;
359         switch (arg) {
360         case ATOM_ARG_REG:
361         case ATOM_ARG_ID:
362                 (*ptr) += 2;
363                 break;
364         case ATOM_ARG_PLL:
365         case ATOM_ARG_MC:
366         case ATOM_ARG_PS:
367         case ATOM_ARG_WS:
368         case ATOM_ARG_FB:
369                 (*ptr)++;
370                 break;
371         case ATOM_ARG_IMM:
372                 switch (align) {
373                 case ATOM_SRC_DWORD:
374                         (*ptr) += 4;
375                         return;
376                 case ATOM_SRC_WORD0:
377                 case ATOM_SRC_WORD8:
378                 case ATOM_SRC_WORD16:
379                         (*ptr) += 2;
380                         return;
381                 case ATOM_SRC_BYTE0:
382                 case ATOM_SRC_BYTE8:
383                 case ATOM_SRC_BYTE16:
384                 case ATOM_SRC_BYTE24:
385                         (*ptr)++;
386                         return;
387                 }
388                 return;
389         }
390 }
391
392 static uint32_t atom_get_src(atom_exec_context *ctx, uint8_t attr, int *ptr)
393 {
394         return atom_get_src_int(ctx, attr, ptr, NULL, 1);
395 }
396
397 static 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
423 static uint32_t atom_get_dst(atom_exec_context *ctx, int arg, uint8_t attr,
424                              int *ptr, uint32_t *saved, int print)
425 {
426         return atom_get_src_int(ctx,
427                                 arg | atom_dst_to_src[(attr >> 3) &
428                                                       7][(attr >> 6) & 3] << 3,
429                                 ptr, saved, print);
430 }
431
432 static void atom_skip_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr)
433 {
434         atom_skip_src_int(ctx,
435                           arg | atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) &
436                                                                  3] << 3, ptr);
437 }
438
439 static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr,
440                          int *ptr, uint32_t val, uint32_t saved)
441 {
442         uint32_t align =
443             atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3], old_val =
444             val, idx;
445         struct atom_context *gctx = ctx->ctx;
446         old_val &= atom_arg_mask[align] >> atom_arg_shift[align];
447         val <<= atom_arg_shift[align];
448         val &= atom_arg_mask[align];
449         saved &= ~atom_arg_mask[align];
450         val |= saved;
451         switch (arg) {
452         case ATOM_ARG_REG:
453                 idx = U16(*ptr);
454                 (*ptr) += 2;
455                 DEBUG("REG[0x%04X]", idx);
456                 idx += gctx->reg_block;
457                 switch (gctx->io_mode) {
458                 case ATOM_IO_MM:
459                         if (idx == 0)
460                                 gctx->card->reg_write(gctx->card, idx,
461                                                       val << 2);
462                         else
463                                 gctx->card->reg_write(gctx->card, idx, val);
464                         break;
465                 case ATOM_IO_PCI:
466                         printk(KERN_INFO
467                                "PCI registers are not implemented.\n");
468                         return;
469                 case ATOM_IO_SYSIO:
470                         printk(KERN_INFO
471                                "SYSIO registers are not implemented.\n");
472                         return;
473                 default:
474                         if (!(gctx->io_mode & 0x80)) {
475                                 printk(KERN_INFO "Bad IO mode.\n");
476                                 return;
477                         }
478                         if (!gctx->iio[gctx->io_mode & 0xFF]) {
479                                 printk(KERN_INFO
480                                        "Undefined indirect IO write method %d.\n",
481                                        gctx->io_mode & 0x7F);
482                                 return;
483                         }
484                         atom_iio_execute(gctx, gctx->iio[gctx->io_mode & 0xFF],
485                                          idx, val);
486                 }
487                 break;
488         case ATOM_ARG_PS:
489                 idx = U8(*ptr);
490                 (*ptr)++;
491                 DEBUG("PS[0x%02X]", idx);
492                 ctx->ps[idx] = cpu_to_le32(val);
493                 break;
494         case ATOM_ARG_WS:
495                 idx = U8(*ptr);
496                 (*ptr)++;
497                 DEBUG("WS[0x%02X]", idx);
498                 switch (idx) {
499                 case ATOM_WS_QUOTIENT:
500                         gctx->divmul[0] = val;
501                         break;
502                 case ATOM_WS_REMAINDER:
503                         gctx->divmul[1] = val;
504                         break;
505                 case ATOM_WS_DATAPTR:
506                         gctx->data_block = val;
507                         break;
508                 case ATOM_WS_SHIFT:
509                         gctx->shift = val;
510                         break;
511                 case ATOM_WS_OR_MASK:
512                 case ATOM_WS_AND_MASK:
513                         break;
514                 case ATOM_WS_FB_WINDOW:
515                         gctx->fb_base = val;
516                         break;
517                 case ATOM_WS_ATTRIBUTES:
518                         gctx->io_attr = val;
519                         break;
520                 case ATOM_WS_REGPTR:
521                         gctx->reg_block = val;
522                         break;
523                 default:
524                         ctx->ws[idx] = val;
525                 }
526                 break;
527         case ATOM_ARG_FB:
528                 idx = U8(*ptr);
529                 (*ptr)++;
530                 gctx->scratch[((gctx->fb_base + idx) / 4)] = val;
531                 DEBUG("FB[0x%02X]", idx);
532                 break;
533         case ATOM_ARG_PLL:
534                 idx = U8(*ptr);
535                 (*ptr)++;
536                 DEBUG("PLL[0x%02X]", idx);
537                 gctx->card->pll_write(gctx->card, idx, val);
538                 break;
539         case ATOM_ARG_MC:
540                 idx = U8(*ptr);
541                 (*ptr)++;
542                 DEBUG("MC[0x%02X]", idx);
543                 gctx->card->mc_write(gctx->card, idx, val);
544                 return;
545         }
546         switch (align) {
547         case ATOM_SRC_DWORD:
548                 DEBUG(".[31:0] <- 0x%08X\n", old_val);
549                 break;
550         case ATOM_SRC_WORD0:
551                 DEBUG(".[15:0] <- 0x%04X\n", old_val);
552                 break;
553         case ATOM_SRC_WORD8:
554                 DEBUG(".[23:8] <- 0x%04X\n", old_val);
555                 break;
556         case ATOM_SRC_WORD16:
557                 DEBUG(".[31:16] <- 0x%04X\n", old_val);
558                 break;
559         case ATOM_SRC_BYTE0:
560                 DEBUG(".[7:0] <- 0x%02X\n", old_val);
561                 break;
562         case ATOM_SRC_BYTE8:
563                 DEBUG(".[15:8] <- 0x%02X\n", old_val);
564                 break;
565         case ATOM_SRC_BYTE16:
566                 DEBUG(".[23:16] <- 0x%02X\n", old_val);
567                 break;
568         case ATOM_SRC_BYTE24:
569                 DEBUG(".[31:24] <- 0x%02X\n", old_val);
570                 break;
571         }
572 }
573
574 static void atom_op_add(atom_exec_context *ctx, int *ptr, int arg)
575 {
576         uint8_t attr = U8((*ptr)++);
577         uint32_t dst, src, saved;
578         int dptr = *ptr;
579         SDEBUG("   dst: ");
580         dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
581         SDEBUG("   src: ");
582         src = atom_get_src(ctx, attr, ptr);
583         dst += src;
584         SDEBUG("   dst: ");
585         atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
586 }
587
588 static void atom_op_and(atom_exec_context *ctx, int *ptr, int arg)
589 {
590         uint8_t attr = U8((*ptr)++);
591         uint32_t dst, src, saved;
592         int dptr = *ptr;
593         SDEBUG("   dst: ");
594         dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
595         SDEBUG("   src: ");
596         src = atom_get_src(ctx, attr, ptr);
597         dst &= src;
598         SDEBUG("   dst: ");
599         atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
600 }
601
602 static void atom_op_beep(atom_exec_context *ctx, int *ptr, int arg)
603 {
604         printk("ATOM BIOS beeped!\n");
605 }
606
607 static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg)
608 {
609         int idx = U8((*ptr)++);
610         int r = 0;
611
612         if (idx < ATOM_TABLE_NAMES_CNT)
613                 SDEBUG("   table: %d (%s)\n", idx, atom_table_names[idx]);
614         else
615                 SDEBUG("   table: %d\n", idx);
616         if (U16(ctx->ctx->cmd_table + 4 + 2 * idx))
617                 r = atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift);
618         if (r) {
619                 ctx->abort = true;
620         }
621 }
622
623 static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg)
624 {
625         uint8_t attr = U8((*ptr)++);
626         uint32_t saved;
627         int dptr = *ptr;
628         attr &= 0x38;
629         attr |= atom_def_dst[attr >> 3] << 6;
630         atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
631         SDEBUG("   dst: ");
632         atom_put_dst(ctx, arg, attr, &dptr, 0, saved);
633 }
634
635 static void atom_op_compare(atom_exec_context *ctx, int *ptr, int arg)
636 {
637         uint8_t attr = U8((*ptr)++);
638         uint32_t dst, src;
639         SDEBUG("   src1: ");
640         dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
641         SDEBUG("   src2: ");
642         src = atom_get_src(ctx, attr, ptr);
643         ctx->ctx->cs_equal = (dst == src);
644         ctx->ctx->cs_above = (dst > src);
645         SDEBUG("   result: %s %s\n", ctx->ctx->cs_equal ? "EQ" : "NE",
646                ctx->ctx->cs_above ? "GT" : "LE");
647 }
648
649 static void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg)
650 {
651         uint8_t count = U8((*ptr)++);
652         SDEBUG("   count: %d\n", count);
653         if (arg == ATOM_UNIT_MICROSEC)
654                 udelay(count);
655         else
656                 schedule_timeout_uninterruptible(msecs_to_jiffies(count));
657 }
658
659 static void atom_op_div(atom_exec_context *ctx, int *ptr, int arg)
660 {
661         uint8_t attr = U8((*ptr)++);
662         uint32_t dst, src;
663         SDEBUG("   src1: ");
664         dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
665         SDEBUG("   src2: ");
666         src = atom_get_src(ctx, attr, ptr);
667         if (src != 0) {
668                 ctx->ctx->divmul[0] = dst / src;
669                 ctx->ctx->divmul[1] = dst % src;
670         } else {
671                 ctx->ctx->divmul[0] = 0;
672                 ctx->ctx->divmul[1] = 0;
673         }
674 }
675
676 static void atom_op_eot(atom_exec_context *ctx, int *ptr, int arg)
677 {
678         /* functionally, a nop */
679 }
680
681 static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
682 {
683         int execute = 0, target = U16(*ptr);
684         unsigned long cjiffies;
685
686         (*ptr) += 2;
687         switch (arg) {
688         case ATOM_COND_ABOVE:
689                 execute = ctx->ctx->cs_above;
690                 break;
691         case ATOM_COND_ABOVEOREQUAL:
692                 execute = ctx->ctx->cs_above || ctx->ctx->cs_equal;
693                 break;
694         case ATOM_COND_ALWAYS:
695                 execute = 1;
696                 break;
697         case ATOM_COND_BELOW:
698                 execute = !(ctx->ctx->cs_above || ctx->ctx->cs_equal);
699                 break;
700         case ATOM_COND_BELOWOREQUAL:
701                 execute = !ctx->ctx->cs_above;
702                 break;
703         case ATOM_COND_EQUAL:
704                 execute = ctx->ctx->cs_equal;
705                 break;
706         case ATOM_COND_NOTEQUAL:
707                 execute = !ctx->ctx->cs_equal;
708                 break;
709         }
710         if (arg != ATOM_COND_ALWAYS)
711                 SDEBUG("   taken: %s\n", execute ? "yes" : "no");
712         SDEBUG("   target: 0x%04X\n", target);
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                 }
730                 *ptr = ctx->start + target;
731         }
732 }
733
734 static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg)
735 {
736         uint8_t attr = U8((*ptr)++);
737         uint32_t dst, src1, src2, saved;
738         int dptr = *ptr;
739         SDEBUG("   dst: ");
740         dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
741         SDEBUG("   src1: ");
742         src1 = atom_get_src_direct(ctx, ((attr >> 3) & 7), ptr);
743         SDEBUG("   src2: ");
744         src2 = atom_get_src(ctx, attr, ptr);
745         dst &= src1;
746         dst |= src2;
747         SDEBUG("   dst: ");
748         atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
749 }
750
751 static void atom_op_move(atom_exec_context *ctx, int *ptr, int arg)
752 {
753         uint8_t attr = U8((*ptr)++);
754         uint32_t src, saved;
755         int dptr = *ptr;
756         if (((attr >> 3) & 7) != ATOM_SRC_DWORD)
757                 atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
758         else {
759                 atom_skip_dst(ctx, arg, attr, ptr);
760                 saved = 0xCDCDCDCD;
761         }
762         SDEBUG("   src: ");
763         src = atom_get_src(ctx, attr, ptr);
764         SDEBUG("   dst: ");
765         atom_put_dst(ctx, arg, attr, &dptr, src, saved);
766 }
767
768 static void atom_op_mul(atom_exec_context *ctx, int *ptr, int arg)
769 {
770         uint8_t attr = U8((*ptr)++);
771         uint32_t dst, src;
772         SDEBUG("   src1: ");
773         dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
774         SDEBUG("   src2: ");
775         src = atom_get_src(ctx, attr, ptr);
776         ctx->ctx->divmul[0] = dst * src;
777 }
778
779 static void atom_op_nop(atom_exec_context *ctx, int *ptr, int arg)
780 {
781         /* nothing */
782 }
783
784 static void atom_op_or(atom_exec_context *ctx, int *ptr, int arg)
785 {
786         uint8_t attr = U8((*ptr)++);
787         uint32_t dst, src, saved;
788         int dptr = *ptr;
789         SDEBUG("   dst: ");
790         dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
791         SDEBUG("   src: ");
792         src = atom_get_src(ctx, attr, ptr);
793         dst |= src;
794         SDEBUG("   dst: ");
795         atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
796 }
797
798 static void atom_op_postcard(atom_exec_context *ctx, int *ptr, int arg)
799 {
800         uint8_t val = U8((*ptr)++);
801         SDEBUG("POST card output: 0x%02X\n", val);
802 }
803
804 static void atom_op_repeat(atom_exec_context *ctx, int *ptr, int arg)
805 {
806         printk(KERN_INFO "unimplemented!\n");
807 }
808
809 static void atom_op_restorereg(atom_exec_context *ctx, int *ptr, int arg)
810 {
811         printk(KERN_INFO "unimplemented!\n");
812 }
813
814 static void atom_op_savereg(atom_exec_context *ctx, int *ptr, int arg)
815 {
816         printk(KERN_INFO "unimplemented!\n");
817 }
818
819 static void atom_op_setdatablock(atom_exec_context *ctx, int *ptr, int arg)
820 {
821         int idx = U8(*ptr);
822         (*ptr)++;
823         SDEBUG("   block: %d\n", idx);
824         if (!idx)
825                 ctx->ctx->data_block = 0;
826         else if (idx == 255)
827                 ctx->ctx->data_block = ctx->start;
828         else
829                 ctx->ctx->data_block = U16(ctx->ctx->data_table + 4 + 2 * idx);
830         SDEBUG("   base: 0x%04X\n", ctx->ctx->data_block);
831 }
832
833 static void atom_op_setfbbase(atom_exec_context *ctx, int *ptr, int arg)
834 {
835         uint8_t attr = U8((*ptr)++);
836         SDEBUG("   fb_base: ");
837         ctx->ctx->fb_base = atom_get_src(ctx, attr, ptr);
838 }
839
840 static void atom_op_setport(atom_exec_context *ctx, int *ptr, int arg)
841 {
842         int port;
843         switch (arg) {
844         case ATOM_PORT_ATI:
845                 port = U16(*ptr);
846                 if (port < ATOM_IO_NAMES_CNT)
847                         SDEBUG("   port: %d (%s)\n", port, atom_io_names[port]);
848                 else
849                         SDEBUG("   port: %d\n", port);
850                 if (!port)
851                         ctx->ctx->io_mode = ATOM_IO_MM;
852                 else
853                         ctx->ctx->io_mode = ATOM_IO_IIO | port;
854                 (*ptr) += 2;
855                 break;
856         case ATOM_PORT_PCI:
857                 ctx->ctx->io_mode = ATOM_IO_PCI;
858                 (*ptr)++;
859                 break;
860         case ATOM_PORT_SYSIO:
861                 ctx->ctx->io_mode = ATOM_IO_SYSIO;
862                 (*ptr)++;
863                 break;
864         }
865 }
866
867 static void atom_op_setregblock(atom_exec_context *ctx, int *ptr, int arg)
868 {
869         ctx->ctx->reg_block = U16(*ptr);
870         (*ptr) += 2;
871         SDEBUG("   base: 0x%04X\n", ctx->ctx->reg_block);
872 }
873
874 static void atom_op_shift_left(atom_exec_context *ctx, int *ptr, int arg)
875 {
876         uint8_t attr = U8((*ptr)++), shift;
877         uint32_t saved, dst;
878         int dptr = *ptr;
879         attr &= 0x38;
880         attr |= atom_def_dst[attr >> 3] << 6;
881         SDEBUG("   dst: ");
882         dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
883         shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr);
884         SDEBUG("   shift: %d\n", shift);
885         dst <<= shift;
886         SDEBUG("   dst: ");
887         atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
888 }
889
890 static void atom_op_shift_right(atom_exec_context *ctx, int *ptr, int arg)
891 {
892         uint8_t attr = U8((*ptr)++), shift;
893         uint32_t saved, dst;
894         int dptr = *ptr;
895         attr &= 0x38;
896         attr |= atom_def_dst[attr >> 3] << 6;
897         SDEBUG("   dst: ");
898         dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
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
906 static 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         SDEBUG("   dst: ");
912         dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
913         shift = atom_get_src(ctx, attr, ptr);
914         SDEBUG("   shift: %d\n", shift);
915         dst <<= shift;
916         SDEBUG("   dst: ");
917         atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
918 }
919
920 static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg)
921 {
922         uint8_t attr = U8((*ptr)++), shift;
923         uint32_t saved, dst;
924         int dptr = *ptr;
925         SDEBUG("   dst: ");
926         dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
927         shift = atom_get_src(ctx, attr, ptr);
928         SDEBUG("   shift: %d\n", shift);
929         dst >>= shift;
930         SDEBUG("   dst: ");
931         atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
932 }
933
934 static void atom_op_sub(atom_exec_context *ctx, int *ptr, int arg)
935 {
936         uint8_t attr = U8((*ptr)++);
937         uint32_t dst, src, saved;
938         int dptr = *ptr;
939         SDEBUG("   dst: ");
940         dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
941         SDEBUG("   src: ");
942         src = atom_get_src(ctx, attr, ptr);
943         dst -= src;
944         SDEBUG("   dst: ");
945         atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
946 }
947
948 static void atom_op_switch(atom_exec_context *ctx, int *ptr, int arg)
949 {
950         uint8_t attr = U8((*ptr)++);
951         uint32_t src, val, target;
952         SDEBUG("   switch: ");
953         src = atom_get_src(ctx, attr, ptr);
954         while (U16(*ptr) != ATOM_CASE_END)
955                 if (U8(*ptr) == ATOM_CASE_MAGIC) {
956                         (*ptr)++;
957                         SDEBUG("   case: ");
958                         val =
959                             atom_get_src(ctx, (attr & 0x38) | ATOM_ARG_IMM,
960                                          ptr);
961                         target = U16(*ptr);
962                         if (val == src) {
963                                 SDEBUG("   target: %04X\n", target);
964                                 *ptr = ctx->start + target;
965                                 return;
966                         }
967                         (*ptr) += 2;
968                 } else {
969                         printk(KERN_INFO "Bad case.\n");
970                         return;
971                 }
972         (*ptr) += 2;
973 }
974
975 static void atom_op_test(atom_exec_context *ctx, int *ptr, int arg)
976 {
977         uint8_t attr = U8((*ptr)++);
978         uint32_t dst, src;
979         SDEBUG("   src1: ");
980         dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
981         SDEBUG("   src2: ");
982         src = atom_get_src(ctx, attr, ptr);
983         ctx->ctx->cs_equal = ((dst & src) == 0);
984         SDEBUG("   result: %s\n", ctx->ctx->cs_equal ? "EQ" : "NE");
985 }
986
987 static void atom_op_xor(atom_exec_context *ctx, int *ptr, int arg)
988 {
989         uint8_t attr = U8((*ptr)++);
990         uint32_t dst, src, saved;
991         int dptr = *ptr;
992         SDEBUG("   dst: ");
993         dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
994         SDEBUG("   src: ");
995         src = atom_get_src(ctx, attr, ptr);
996         dst ^= src;
997         SDEBUG("   dst: ");
998         atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
999 }
1000
1001 static void atom_op_debug(atom_exec_context *ctx, int *ptr, int arg)
1002 {
1003         printk(KERN_INFO "unimplemented!\n");
1004 }
1005
1006 static struct {
1007         void (*func) (atom_exec_context *, int *, int);
1008         int arg;
1009 } opcode_table[ATOM_OP_CNT] = {
1010         {
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 static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params)
1135 {
1136         int base = CU16(ctx->cmd_table + 4 + 2 * index);
1137         int len, ws, ps, ptr;
1138         unsigned char op;
1139         atom_exec_context ectx;
1140
1141         if (!base)
1142                 return -EINVAL;
1143
1144         len = CU16(base + ATOM_CT_SIZE_PTR);
1145         ws = CU8(base + ATOM_CT_WS_PTR);
1146         ps = CU8(base + ATOM_CT_PS_PTR) & ATOM_CT_PS_MASK;
1147         ptr = base + ATOM_CT_CODE_PTR;
1148
1149         SDEBUG(">> execute %04X (len %d, WS %d, PS %d)\n", base, len, ws, ps);
1150
1151         ectx.ctx = ctx;
1152         ectx.ps_shift = ps / 4;
1153         ectx.start = base;
1154         ectx.ps = params;
1155         ectx.abort = false;
1156         ectx.last_jump = 0;
1157         if (ws)
1158                 ectx.ws = kzalloc(4 * ws, GFP_KERNEL);
1159         else
1160                 ectx.ws = NULL;
1161
1162         debug_depth++;
1163         while (1) {
1164                 op = CU8(ptr++);
1165                 if (op < ATOM_OP_NAMES_CNT)
1166                         SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr - 1);
1167                 else
1168                         SDEBUG("[%d] @ 0x%04X\n", op, ptr - 1);
1169                 if (ectx.abort) {
1170                         DRM_ERROR("atombios stuck executing %04X (len %d, WS %d, PS %d) @ 0x%04X\n",
1171                                 base, len, ws, ps, ptr - 1);
1172                         return -EINVAL;
1173                 }
1174
1175                 if (op < ATOM_OP_CNT && op > 0)
1176                         opcode_table[op].func(&ectx, &ptr,
1177                                               opcode_table[op].arg);
1178                 else
1179                         break;
1180
1181                 if (op == ATOM_OP_EOT)
1182                         break;
1183         }
1184         debug_depth--;
1185         SDEBUG("<<\n");
1186
1187         if (ws)
1188                 kfree(ectx.ws);
1189         return 0;
1190 }
1191
1192 int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
1193 {
1194         int r;
1195
1196         mutex_lock(&ctx->mutex);
1197         /* reset reg block */
1198         ctx->reg_block = 0;
1199         /* reset fb window */
1200         ctx->fb_base = 0;
1201         /* reset io mode */
1202         ctx->io_mode = ATOM_IO_MM;
1203         r = atom_execute_table_locked(ctx, index, params);
1204         mutex_unlock(&ctx->mutex);
1205         return r;
1206 }
1207
1208 static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 };
1209
1210 static void atom_index_iio(struct atom_context *ctx, int base)
1211 {
1212         ctx->iio = kzalloc(2 * 256, GFP_KERNEL);
1213         while (CU8(base) == ATOM_IIO_START) {
1214                 ctx->iio[CU8(base + 1)] = base + 2;
1215                 base += 2;
1216                 while (CU8(base) != ATOM_IIO_END)
1217                         base += atom_iio_len[CU8(base)];
1218                 base += 3;
1219         }
1220 }
1221
1222 struct atom_context *atom_parse(struct card_info *card, void *bios)
1223 {
1224         int base;
1225         struct atom_context *ctx =
1226             kzalloc(sizeof(struct atom_context), GFP_KERNEL);
1227         char *str;
1228         char name[512];
1229         int i;
1230
1231         ctx->card = card;
1232         ctx->bios = bios;
1233
1234         if (CU16(0) != ATOM_BIOS_MAGIC) {
1235                 printk(KERN_INFO "Invalid BIOS magic.\n");
1236                 kfree(ctx);
1237                 return NULL;
1238         }
1239         if (strncmp
1240             (CSTR(ATOM_ATI_MAGIC_PTR), ATOM_ATI_MAGIC,
1241              strlen(ATOM_ATI_MAGIC))) {
1242                 printk(KERN_INFO "Invalid ATI magic.\n");
1243                 kfree(ctx);
1244                 return NULL;
1245         }
1246
1247         base = CU16(ATOM_ROM_TABLE_PTR);
1248         if (strncmp
1249             (CSTR(base + ATOM_ROM_MAGIC_PTR), ATOM_ROM_MAGIC,
1250              strlen(ATOM_ROM_MAGIC))) {
1251                 printk(KERN_INFO "Invalid ATOM magic.\n");
1252                 kfree(ctx);
1253                 return NULL;
1254         }
1255
1256         ctx->cmd_table = CU16(base + ATOM_ROM_CMD_PTR);
1257         ctx->data_table = CU16(base + ATOM_ROM_DATA_PTR);
1258         atom_index_iio(ctx, CU16(ctx->data_table + ATOM_DATA_IIO_PTR) + 4);
1259
1260         str = CSTR(CU16(base + ATOM_ROM_MSG_PTR));
1261         while (*str && ((*str == '\n') || (*str == '\r')))
1262                 str++;
1263         /* name string isn't always 0 terminated */
1264         for (i = 0; i < 511; i++) {
1265                 name[i] = str[i];
1266                 if (name[i] < '.' || name[i] > 'z') {
1267                         name[i] = 0;
1268                         break;
1269                 }
1270         }
1271         printk(KERN_INFO "ATOM BIOS: %s\n", name);
1272
1273         return ctx;
1274 }
1275
1276 int atom_asic_init(struct atom_context *ctx)
1277 {
1278         int hwi = CU16(ctx->data_table + ATOM_DATA_FWI_PTR);
1279         uint32_t ps[16];
1280         memset(ps, 0, 64);
1281
1282         ps[0] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFSCLK_PTR));
1283         ps[1] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFMCLK_PTR));
1284         if (!ps[0] || !ps[1])
1285                 return 1;
1286
1287         if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT))
1288                 return 1;
1289         return atom_execute_table(ctx, ATOM_CMD_INIT, ps);
1290 }
1291
1292 void atom_destroy(struct atom_context *ctx)
1293 {
1294         if (ctx->iio)
1295                 kfree(ctx->iio);
1296         kfree(ctx);
1297 }
1298
1299 bool atom_parse_data_header(struct atom_context *ctx, int index,
1300                             uint16_t * size, uint8_t * frev, uint8_t * crev,
1301                             uint16_t * data_start)
1302 {
1303         int offset = index * 2 + 4;
1304         int idx = CU16(ctx->data_table + offset);
1305         u16 *mdt = (u16 *)(ctx->bios + ctx->data_table + 4);
1306
1307         if (!mdt[index])
1308                 return false;
1309
1310         if (size)
1311                 *size = CU16(idx);
1312         if (frev)
1313                 *frev = CU8(idx + 2);
1314         if (crev)
1315                 *crev = CU8(idx + 3);
1316         *data_start = idx;
1317         return true;
1318 }
1319
1320 bool atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t * frev,
1321                            uint8_t * crev)
1322 {
1323         int offset = index * 2 + 4;
1324         int idx = CU16(ctx->cmd_table + offset);
1325         u16 *mct = (u16 *)(ctx->bios + ctx->cmd_table + 4);
1326
1327         if (!mct[index])
1328                 return false;
1329
1330         if (frev)
1331                 *frev = CU8(idx + 2);
1332         if (crev)
1333                 *crev = CU8(idx + 3);
1334         return true;
1335 }
1336
1337 int atom_allocate_fb_scratch(struct atom_context *ctx)
1338 {
1339         int index = GetIndexIntoMasterTable(DATA, VRAM_UsageByFirmware);
1340         uint16_t data_offset;
1341         int usage_bytes = 0;
1342         struct _ATOM_VRAM_USAGE_BY_FIRMWARE *firmware_usage;
1343
1344         if (atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset)) {
1345                 firmware_usage = (struct _ATOM_VRAM_USAGE_BY_FIRMWARE *)(ctx->bios + data_offset);
1346
1347                 DRM_DEBUG("atom firmware requested %08x %dkb\n",
1348                           firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware,
1349                           firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb);
1350
1351                 usage_bytes = firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb * 1024;
1352         }
1353         if (usage_bytes == 0)
1354                 usage_bytes = 20 * 1024;
1355         /* allocate some scratch memory */
1356         ctx->scratch = kzalloc(usage_bytes, GFP_KERNEL);
1357         if (!ctx->scratch)
1358                 return -ENOMEM;
1359         return 0;
1360 }