OSDN Git Service

drm/radeon/kms/atom: use get_unaligned_le32() for ctx->ps
[armadillo-ux/linux-2.6-armadillo.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                 schedule_timeout_uninterruptible(usecs_to_jiffies(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         attr &= 0x38;
885         attr |= atom_def_dst[attr >> 3] << 6;
886         SDEBUG("   dst: ");
887         dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
888         shift = atom_get_src(ctx, attr, ptr);
889         SDEBUG("   shift: %d\n", shift);
890         dst <<= shift;
891         SDEBUG("   dst: ");
892         atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
893 }
894
895 static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg)
896 {
897         uint8_t attr = U8((*ptr)++), shift;
898         uint32_t saved, dst;
899         int dptr = *ptr;
900         attr &= 0x38;
901         attr |= atom_def_dst[attr >> 3] << 6;
902         SDEBUG("   dst: ");
903         dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
904         shift = atom_get_src(ctx, attr, ptr);
905         SDEBUG("   shift: %d\n", shift);
906         dst >>= shift;
907         SDEBUG("   dst: ");
908         atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
909 }
910
911 static void atom_op_sub(atom_exec_context *ctx, int *ptr, int arg)
912 {
913         uint8_t attr = U8((*ptr)++);
914         uint32_t dst, src, saved;
915         int dptr = *ptr;
916         SDEBUG("   dst: ");
917         dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
918         SDEBUG("   src: ");
919         src = atom_get_src(ctx, attr, ptr);
920         dst -= src;
921         SDEBUG("   dst: ");
922         atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
923 }
924
925 static void atom_op_switch(atom_exec_context *ctx, int *ptr, int arg)
926 {
927         uint8_t attr = U8((*ptr)++);
928         uint32_t src, val, target;
929         SDEBUG("   switch: ");
930         src = atom_get_src(ctx, attr, ptr);
931         while (U16(*ptr) != ATOM_CASE_END)
932                 if (U8(*ptr) == ATOM_CASE_MAGIC) {
933                         (*ptr)++;
934                         SDEBUG("   case: ");
935                         val =
936                             atom_get_src(ctx, (attr & 0x38) | ATOM_ARG_IMM,
937                                          ptr);
938                         target = U16(*ptr);
939                         if (val == src) {
940                                 SDEBUG("   target: %04X\n", target);
941                                 *ptr = ctx->start + target;
942                                 return;
943                         }
944                         (*ptr) += 2;
945                 } else {
946                         printk(KERN_INFO "Bad case.\n");
947                         return;
948                 }
949         (*ptr) += 2;
950 }
951
952 static void atom_op_test(atom_exec_context *ctx, int *ptr, int arg)
953 {
954         uint8_t attr = U8((*ptr)++);
955         uint32_t dst, src;
956         SDEBUG("   src1: ");
957         dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
958         SDEBUG("   src2: ");
959         src = atom_get_src(ctx, attr, ptr);
960         ctx->ctx->cs_equal = ((dst & src) == 0);
961         SDEBUG("   result: %s\n", ctx->ctx->cs_equal ? "EQ" : "NE");
962 }
963
964 static void atom_op_xor(atom_exec_context *ctx, int *ptr, int arg)
965 {
966         uint8_t attr = U8((*ptr)++);
967         uint32_t dst, src, saved;
968         int dptr = *ptr;
969         SDEBUG("   dst: ");
970         dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
971         SDEBUG("   src: ");
972         src = atom_get_src(ctx, attr, ptr);
973         dst ^= src;
974         SDEBUG("   dst: ");
975         atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
976 }
977
978 static void atom_op_debug(atom_exec_context *ctx, int *ptr, int arg)
979 {
980         printk(KERN_INFO "unimplemented!\n");
981 }
982
983 static struct {
984         void (*func) (atom_exec_context *, int *, int);
985         int arg;
986 } opcode_table[ATOM_OP_CNT] = {
987         {
988         NULL, 0}, {
989         atom_op_move, ATOM_ARG_REG}, {
990         atom_op_move, ATOM_ARG_PS}, {
991         atom_op_move, ATOM_ARG_WS}, {
992         atom_op_move, ATOM_ARG_FB}, {
993         atom_op_move, ATOM_ARG_PLL}, {
994         atom_op_move, ATOM_ARG_MC}, {
995         atom_op_and, ATOM_ARG_REG}, {
996         atom_op_and, ATOM_ARG_PS}, {
997         atom_op_and, ATOM_ARG_WS}, {
998         atom_op_and, ATOM_ARG_FB}, {
999         atom_op_and, ATOM_ARG_PLL}, {
1000         atom_op_and, ATOM_ARG_MC}, {
1001         atom_op_or, ATOM_ARG_REG}, {
1002         atom_op_or, ATOM_ARG_PS}, {
1003         atom_op_or, ATOM_ARG_WS}, {
1004         atom_op_or, ATOM_ARG_FB}, {
1005         atom_op_or, ATOM_ARG_PLL}, {
1006         atom_op_or, ATOM_ARG_MC}, {
1007         atom_op_shift_left, ATOM_ARG_REG}, {
1008         atom_op_shift_left, ATOM_ARG_PS}, {
1009         atom_op_shift_left, ATOM_ARG_WS}, {
1010         atom_op_shift_left, ATOM_ARG_FB}, {
1011         atom_op_shift_left, ATOM_ARG_PLL}, {
1012         atom_op_shift_left, ATOM_ARG_MC}, {
1013         atom_op_shift_right, ATOM_ARG_REG}, {
1014         atom_op_shift_right, ATOM_ARG_PS}, {
1015         atom_op_shift_right, ATOM_ARG_WS}, {
1016         atom_op_shift_right, ATOM_ARG_FB}, {
1017         atom_op_shift_right, ATOM_ARG_PLL}, {
1018         atom_op_shift_right, ATOM_ARG_MC}, {
1019         atom_op_mul, ATOM_ARG_REG}, {
1020         atom_op_mul, ATOM_ARG_PS}, {
1021         atom_op_mul, ATOM_ARG_WS}, {
1022         atom_op_mul, ATOM_ARG_FB}, {
1023         atom_op_mul, ATOM_ARG_PLL}, {
1024         atom_op_mul, ATOM_ARG_MC}, {
1025         atom_op_div, ATOM_ARG_REG}, {
1026         atom_op_div, ATOM_ARG_PS}, {
1027         atom_op_div, ATOM_ARG_WS}, {
1028         atom_op_div, ATOM_ARG_FB}, {
1029         atom_op_div, ATOM_ARG_PLL}, {
1030         atom_op_div, ATOM_ARG_MC}, {
1031         atom_op_add, ATOM_ARG_REG}, {
1032         atom_op_add, ATOM_ARG_PS}, {
1033         atom_op_add, ATOM_ARG_WS}, {
1034         atom_op_add, ATOM_ARG_FB}, {
1035         atom_op_add, ATOM_ARG_PLL}, {
1036         atom_op_add, ATOM_ARG_MC}, {
1037         atom_op_sub, ATOM_ARG_REG}, {
1038         atom_op_sub, ATOM_ARG_PS}, {
1039         atom_op_sub, ATOM_ARG_WS}, {
1040         atom_op_sub, ATOM_ARG_FB}, {
1041         atom_op_sub, ATOM_ARG_PLL}, {
1042         atom_op_sub, ATOM_ARG_MC}, {
1043         atom_op_setport, ATOM_PORT_ATI}, {
1044         atom_op_setport, ATOM_PORT_PCI}, {
1045         atom_op_setport, ATOM_PORT_SYSIO}, {
1046         atom_op_setregblock, 0}, {
1047         atom_op_setfbbase, 0}, {
1048         atom_op_compare, ATOM_ARG_REG}, {
1049         atom_op_compare, ATOM_ARG_PS}, {
1050         atom_op_compare, ATOM_ARG_WS}, {
1051         atom_op_compare, ATOM_ARG_FB}, {
1052         atom_op_compare, ATOM_ARG_PLL}, {
1053         atom_op_compare, ATOM_ARG_MC}, {
1054         atom_op_switch, 0}, {
1055         atom_op_jump, ATOM_COND_ALWAYS}, {
1056         atom_op_jump, ATOM_COND_EQUAL}, {
1057         atom_op_jump, ATOM_COND_BELOW}, {
1058         atom_op_jump, ATOM_COND_ABOVE}, {
1059         atom_op_jump, ATOM_COND_BELOWOREQUAL}, {
1060         atom_op_jump, ATOM_COND_ABOVEOREQUAL}, {
1061         atom_op_jump, ATOM_COND_NOTEQUAL}, {
1062         atom_op_test, ATOM_ARG_REG}, {
1063         atom_op_test, ATOM_ARG_PS}, {
1064         atom_op_test, ATOM_ARG_WS}, {
1065         atom_op_test, ATOM_ARG_FB}, {
1066         atom_op_test, ATOM_ARG_PLL}, {
1067         atom_op_test, ATOM_ARG_MC}, {
1068         atom_op_delay, ATOM_UNIT_MILLISEC}, {
1069         atom_op_delay, ATOM_UNIT_MICROSEC}, {
1070         atom_op_calltable, 0}, {
1071         atom_op_repeat, 0}, {
1072         atom_op_clear, ATOM_ARG_REG}, {
1073         atom_op_clear, ATOM_ARG_PS}, {
1074         atom_op_clear, ATOM_ARG_WS}, {
1075         atom_op_clear, ATOM_ARG_FB}, {
1076         atom_op_clear, ATOM_ARG_PLL}, {
1077         atom_op_clear, ATOM_ARG_MC}, {
1078         atom_op_nop, 0}, {
1079         atom_op_eot, 0}, {
1080         atom_op_mask, ATOM_ARG_REG}, {
1081         atom_op_mask, ATOM_ARG_PS}, {
1082         atom_op_mask, ATOM_ARG_WS}, {
1083         atom_op_mask, ATOM_ARG_FB}, {
1084         atom_op_mask, ATOM_ARG_PLL}, {
1085         atom_op_mask, ATOM_ARG_MC}, {
1086         atom_op_postcard, 0}, {
1087         atom_op_beep, 0}, {
1088         atom_op_savereg, 0}, {
1089         atom_op_restorereg, 0}, {
1090         atom_op_setdatablock, 0}, {
1091         atom_op_xor, ATOM_ARG_REG}, {
1092         atom_op_xor, ATOM_ARG_PS}, {
1093         atom_op_xor, ATOM_ARG_WS}, {
1094         atom_op_xor, ATOM_ARG_FB}, {
1095         atom_op_xor, ATOM_ARG_PLL}, {
1096         atom_op_xor, ATOM_ARG_MC}, {
1097         atom_op_shl, ATOM_ARG_REG}, {
1098         atom_op_shl, ATOM_ARG_PS}, {
1099         atom_op_shl, ATOM_ARG_WS}, {
1100         atom_op_shl, ATOM_ARG_FB}, {
1101         atom_op_shl, ATOM_ARG_PLL}, {
1102         atom_op_shl, ATOM_ARG_MC}, {
1103         atom_op_shr, ATOM_ARG_REG}, {
1104         atom_op_shr, ATOM_ARG_PS}, {
1105         atom_op_shr, ATOM_ARG_WS}, {
1106         atom_op_shr, ATOM_ARG_FB}, {
1107         atom_op_shr, ATOM_ARG_PLL}, {
1108         atom_op_shr, ATOM_ARG_MC}, {
1109 atom_op_debug, 0},};
1110
1111 static void atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params)
1112 {
1113         int base = CU16(ctx->cmd_table + 4 + 2 * index);
1114         int len, ws, ps, ptr;
1115         unsigned char op;
1116         atom_exec_context ectx;
1117
1118         if (!base)
1119                 return;
1120
1121         len = CU16(base + ATOM_CT_SIZE_PTR);
1122         ws = CU8(base + ATOM_CT_WS_PTR);
1123         ps = CU8(base + ATOM_CT_PS_PTR) & ATOM_CT_PS_MASK;
1124         ptr = base + ATOM_CT_CODE_PTR;
1125
1126         SDEBUG(">> execute %04X (len %d, WS %d, PS %d)\n", base, len, ws, ps);
1127
1128         ectx.ctx = ctx;
1129         ectx.ps_shift = ps / 4;
1130         ectx.start = base;
1131         ectx.ps = params;
1132         if (ws)
1133                 ectx.ws = kzalloc(4 * ws, GFP_KERNEL);
1134         else
1135                 ectx.ws = NULL;
1136
1137         debug_depth++;
1138         while (1) {
1139                 op = CU8(ptr++);
1140                 if (op < ATOM_OP_NAMES_CNT)
1141                         SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr - 1);
1142                 else
1143                         SDEBUG("[%d] @ 0x%04X\n", op, ptr - 1);
1144
1145                 if (op < ATOM_OP_CNT && op > 0)
1146                         opcode_table[op].func(&ectx, &ptr,
1147                                               opcode_table[op].arg);
1148                 else
1149                         break;
1150
1151                 if (op == ATOM_OP_EOT)
1152                         break;
1153         }
1154         debug_depth--;
1155         SDEBUG("<<\n");
1156
1157         if (ws)
1158                 kfree(ectx.ws);
1159 }
1160
1161 void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
1162 {
1163         mutex_lock(&ctx->mutex);
1164         /* reset reg block */
1165         ctx->reg_block = 0;
1166         /* reset fb window */
1167         ctx->fb_base = 0;
1168         /* reset io mode */
1169         ctx->io_mode = ATOM_IO_MM;
1170         atom_execute_table_locked(ctx, index, params);
1171         mutex_unlock(&ctx->mutex);
1172 }
1173
1174 static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 };
1175
1176 static void atom_index_iio(struct atom_context *ctx, int base)
1177 {
1178         ctx->iio = kzalloc(2 * 256, GFP_KERNEL);
1179         while (CU8(base) == ATOM_IIO_START) {
1180                 ctx->iio[CU8(base + 1)] = base + 2;
1181                 base += 2;
1182                 while (CU8(base) != ATOM_IIO_END)
1183                         base += atom_iio_len[CU8(base)];
1184                 base += 3;
1185         }
1186 }
1187
1188 struct atom_context *atom_parse(struct card_info *card, void *bios)
1189 {
1190         int base;
1191         struct atom_context *ctx =
1192             kzalloc(sizeof(struct atom_context), GFP_KERNEL);
1193         char *str;
1194         char name[512];
1195         int i;
1196
1197         ctx->card = card;
1198         ctx->bios = bios;
1199
1200         if (CU16(0) != ATOM_BIOS_MAGIC) {
1201                 printk(KERN_INFO "Invalid BIOS magic.\n");
1202                 kfree(ctx);
1203                 return NULL;
1204         }
1205         if (strncmp
1206             (CSTR(ATOM_ATI_MAGIC_PTR), ATOM_ATI_MAGIC,
1207              strlen(ATOM_ATI_MAGIC))) {
1208                 printk(KERN_INFO "Invalid ATI magic.\n");
1209                 kfree(ctx);
1210                 return NULL;
1211         }
1212
1213         base = CU16(ATOM_ROM_TABLE_PTR);
1214         if (strncmp
1215             (CSTR(base + ATOM_ROM_MAGIC_PTR), ATOM_ROM_MAGIC,
1216              strlen(ATOM_ROM_MAGIC))) {
1217                 printk(KERN_INFO "Invalid ATOM magic.\n");
1218                 kfree(ctx);
1219                 return NULL;
1220         }
1221
1222         ctx->cmd_table = CU16(base + ATOM_ROM_CMD_PTR);
1223         ctx->data_table = CU16(base + ATOM_ROM_DATA_PTR);
1224         atom_index_iio(ctx, CU16(ctx->data_table + ATOM_DATA_IIO_PTR) + 4);
1225
1226         str = CSTR(CU16(base + ATOM_ROM_MSG_PTR));
1227         while (*str && ((*str == '\n') || (*str == '\r')))
1228                 str++;
1229         /* name string isn't always 0 terminated */
1230         for (i = 0; i < 511; i++) {
1231                 name[i] = str[i];
1232                 if (name[i] < '.' || name[i] > 'z') {
1233                         name[i] = 0;
1234                         break;
1235                 }
1236         }
1237         printk(KERN_INFO "ATOM BIOS: %s\n", name);
1238
1239         return ctx;
1240 }
1241
1242 int atom_asic_init(struct atom_context *ctx)
1243 {
1244         int hwi = CU16(ctx->data_table + ATOM_DATA_FWI_PTR);
1245         uint32_t ps[16];
1246         memset(ps, 0, 64);
1247
1248         ps[0] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFSCLK_PTR));
1249         ps[1] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFMCLK_PTR));
1250         if (!ps[0] || !ps[1])
1251                 return 1;
1252
1253         if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT))
1254                 return 1;
1255         atom_execute_table(ctx, ATOM_CMD_INIT, ps);
1256
1257         return 0;
1258 }
1259
1260 void atom_destroy(struct atom_context *ctx)
1261 {
1262         if (ctx->iio)
1263                 kfree(ctx->iio);
1264         kfree(ctx);
1265 }
1266
1267 void atom_parse_data_header(struct atom_context *ctx, int index,
1268                             uint16_t * size, uint8_t * frev, uint8_t * crev,
1269                             uint16_t * data_start)
1270 {
1271         int offset = index * 2 + 4;
1272         int idx = CU16(ctx->data_table + offset);
1273
1274         if (size)
1275                 *size = CU16(idx);
1276         if (frev)
1277                 *frev = CU8(idx + 2);
1278         if (crev)
1279                 *crev = CU8(idx + 3);
1280         *data_start = idx;
1281         return;
1282 }
1283
1284 void atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t * frev,
1285                            uint8_t * crev)
1286 {
1287         int offset = index * 2 + 4;
1288         int idx = CU16(ctx->cmd_table + offset);
1289
1290         if (frev)
1291                 *frev = CU8(idx + 2);
1292         if (crev)
1293                 *crev = CU8(idx + 3);
1294         return;
1295 }
1296
1297 int atom_allocate_fb_scratch(struct atom_context *ctx)
1298 {
1299         int index = GetIndexIntoMasterTable(DATA, VRAM_UsageByFirmware);
1300         uint16_t data_offset;
1301         int usage_bytes;
1302         struct _ATOM_VRAM_USAGE_BY_FIRMWARE *firmware_usage;
1303
1304         atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset);
1305
1306         firmware_usage = (struct _ATOM_VRAM_USAGE_BY_FIRMWARE *)(ctx->bios + data_offset);
1307
1308         DRM_DEBUG("atom firmware requested %08x %dkb\n",
1309                   firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware,
1310                   firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb);
1311
1312         usage_bytes = firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb * 1024;
1313         if (usage_bytes == 0)
1314                 usage_bytes = 20 * 1024;
1315         /* allocate some scratch memory */
1316         ctx->scratch = kzalloc(usage_bytes, GFP_KERNEL);
1317         if (!ctx->scratch)
1318                 return -ENOMEM;
1319         return 0;
1320 }