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