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