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