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