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