aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/atom.c
diff options
context:
space:
mode:
authorJerome Glisse <jglisse@redhat.com>2009-06-05 08:42:42 -0400
committerDave Airlie <airlied@redhat.com>2009-06-14 22:01:53 -0400
commit771fe6b912fca54f03e8a72eb63058b582775362 (patch)
tree58aa5469ba8058c2b564d50807395ad6cd7bd7e4 /drivers/gpu/drm/radeon/atom.c
parentba4e7d973dd09b66912ac4c0856add8b0703a997 (diff)
drm/radeon: introduce kernel modesetting for radeon hardware
Add kernel modesetting support to radeon driver, use the ttm memory manager to manage memory and DRM/GEM to provide userspace API. In order to avoid backward compatibility issue and to allow clean design and code the radeon kernel modesetting use different code path than old radeon/drm driver. When kernel modesetting is enabled the IOCTL of radeon/drm driver are considered as invalid and an error message is printed in the log and they return failure. KMS enabled userspace will use new API to talk with the radeon/drm driver. The new API provide functions to create/destroy/share/mmap buffer object which are then managed by the kernel memory manager (here TTM). In order to submit command to the GPU the userspace provide a buffer holding the command stream, along this buffer userspace have to provide a list of buffer object used by the command stream. The kernel radeon driver will then place buffer in GPU accessible memory and will update command stream to reflect the position of the different buffers. The kernel will also perform security check on command stream provided by the user, we want to catch and forbid any illegal use of the GPU such as DMA into random system memory or into memory not owned by the process supplying the command stream. This part of the code is still incomplete and this why we propose that patch as a staging driver addition, future security might forbid current experimental userspace to run. This code support the following hardware : R1XX,R2XX,R3XX,R4XX,R5XX (radeon up to X1950). Works is underway to provide support for R6XX, R7XX and newer hardware (radeon from HD2XXX to HD4XXX). Authors: Jerome Glisse <jglisse@redhat.com> Dave Airlie <airlied@redhat.com> Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Jerome Glisse <jglisse@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/atom.c')
-rw-r--r--drivers/gpu/drm/radeon/atom.c1215
1 files changed, 1215 insertions, 0 deletions
diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c
new file mode 100644
index 000000000000..901befe03da2
--- /dev/null
+++ b/drivers/gpu/drm/radeon/atom.c
@@ -0,0 +1,1215 @@
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
28#define ATOM_DEBUG
29
30#include "atom.h"
31#include "atom-names.h"
32#include "atom-bits.h"
33
34#define ATOM_COND_ABOVE 0
35#define ATOM_COND_ABOVEOREQUAL 1
36#define ATOM_COND_ALWAYS 2
37#define ATOM_COND_BELOW 3
38#define ATOM_COND_BELOWOREQUAL 4
39#define ATOM_COND_EQUAL 5
40#define ATOM_COND_NOTEQUAL 6
41
42#define ATOM_PORT_ATI 0
43#define ATOM_PORT_PCI 1
44#define ATOM_PORT_SYSIO 2
45
46#define ATOM_UNIT_MICROSEC 0
47#define ATOM_UNIT_MILLISEC 1
48
49#define PLL_INDEX 2
50#define PLL_DATA 3
51
52typedef struct {
53 struct atom_context *ctx;
54
55 uint32_t *ps, *ws;
56 int ps_shift;
57 uint16_t start;
58} atom_exec_context;
59
60int atom_debug = 0;
61void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params);
62
63static uint32_t atom_arg_mask[8] =
64 { 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000,
650xFF000000 };
66static int atom_arg_shift[8] = { 0, 0, 8, 16, 0, 8, 16, 24 };
67
68static int atom_dst_to_src[8][4] = {
69 /* translate destination alignment field to the source alignment encoding */
70 {0, 0, 0, 0},
71 {1, 2, 3, 0},
72 {1, 2, 3, 0},
73 {1, 2, 3, 0},
74 {4, 5, 6, 7},
75 {4, 5, 6, 7},
76 {4, 5, 6, 7},
77 {4, 5, 6, 7},
78};
79static int atom_def_dst[8] = { 0, 0, 1, 2, 0, 1, 2, 3 };
80
81static int debug_depth = 0;
82#ifdef ATOM_DEBUG
83static void debug_print_spaces(int n)
84{
85 while (n--)
86 printk(" ");
87}
88
89#define DEBUG(...) do if (atom_debug) { printk(KERN_DEBUG __VA_ARGS__); } while (0)
90#define SDEBUG(...) do if (atom_debug) { printk(KERN_DEBUG); debug_print_spaces(debug_depth); printk(__VA_ARGS__); } while (0)
91#else
92#define DEBUG(...) do { } while (0)
93#define SDEBUG(...) do { } while (0)
94#endif
95
96static uint32_t atom_iio_execute(struct atom_context *ctx, int base,
97 uint32_t index, uint32_t data)
98{
99 uint32_t temp = 0xCDCDCDCD;
100 while (1)
101 switch (CU8(base)) {
102 case ATOM_IIO_NOP:
103 base++;
104 break;
105 case ATOM_IIO_READ:
106 temp = ctx->card->reg_read(ctx->card, CU16(base + 1));
107 base += 3;
108 break;
109 case ATOM_IIO_WRITE:
110 ctx->card->reg_write(ctx->card, CU16(base + 1), temp);
111 base += 3;
112 break;
113 case ATOM_IIO_CLEAR:
114 temp &=
115 ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
116 CU8(base + 2));
117 base += 3;
118 break;
119 case ATOM_IIO_SET:
120 temp |=
121 (0xFFFFFFFF >> (32 - CU8(base + 1))) << CU8(base +
122 2);
123 base += 3;
124 break;
125 case ATOM_IIO_MOVE_INDEX:
126 temp &=
127 ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
128 CU8(base + 2));
129 temp |=
130 ((index >> CU8(base + 2)) &
131 (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base +
132 3);
133 base += 4;
134 break;
135 case ATOM_IIO_MOVE_DATA:
136 temp &=
137 ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
138 CU8(base + 2));
139 temp |=
140 ((data >> CU8(base + 2)) &
141 (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base +
142 3);
143 base += 4;
144 break;
145 case ATOM_IIO_MOVE_ATTR:
146 temp &=
147 ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
148 CU8(base + 2));
149 temp |=
150 ((ctx->
151 io_attr >> CU8(base + 2)) & (0xFFFFFFFF >> (32 -
152 CU8
153 (base
154 +
155 1))))
156 << CU8(base + 3);
157 base += 4;
158 break;
159 case ATOM_IIO_END:
160 return temp;
161 default:
162 printk(KERN_INFO "Unknown IIO opcode.\n");
163 return 0;
164 }
165}
166
167static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr,
168 int *ptr, uint32_t *saved, int print)
169{
170 uint32_t idx, val = 0xCDCDCDCD, align, arg;
171 struct atom_context *gctx = ctx->ctx;
172 arg = attr & 7;
173 align = (attr >> 3) & 7;
174 switch (arg) {
175 case ATOM_ARG_REG:
176 idx = U16(*ptr);
177 (*ptr) += 2;
178 if (print)
179 DEBUG("REG[0x%04X]", idx);
180 idx += gctx->reg_block;
181 switch (gctx->io_mode) {
182 case ATOM_IO_MM:
183 val = gctx->card->reg_read(gctx->card, idx);
184 break;
185 case ATOM_IO_PCI:
186 printk(KERN_INFO
187 "PCI registers are not implemented.\n");
188 return 0;
189 case ATOM_IO_SYSIO:
190 printk(KERN_INFO
191 "SYSIO registers are not implemented.\n");
192 return 0;
193 default:
194 if (!(gctx->io_mode & 0x80)) {
195 printk(KERN_INFO "Bad IO mode.\n");
196 return 0;
197 }
198 if (!gctx->iio[gctx->io_mode & 0x7F]) {
199 printk(KERN_INFO
200 "Undefined indirect IO read method %d.\n",
201 gctx->io_mode & 0x7F);
202 return 0;
203 }
204 val =
205 atom_iio_execute(gctx,
206 gctx->iio[gctx->io_mode & 0x7F],
207 idx, 0);
208 }
209 break;
210 case ATOM_ARG_PS:
211 idx = U8(*ptr);
212 (*ptr)++;
213 val = le32_to_cpu(ctx->ps[idx]);
214 if (print)
215 DEBUG("PS[0x%02X,0x%04X]", idx, val);
216 break;
217 case ATOM_ARG_WS:
218 idx = U8(*ptr);
219 (*ptr)++;
220 if (print)
221 DEBUG("WS[0x%02X]", idx);
222 switch (idx) {
223 case ATOM_WS_QUOTIENT:
224 val = gctx->divmul[0];
225 break;
226 case ATOM_WS_REMAINDER:
227 val = gctx->divmul[1];
228 break;
229 case ATOM_WS_DATAPTR:
230 val = gctx->data_block;
231 break;
232 case ATOM_WS_SHIFT:
233 val = gctx->shift;
234 break;
235 case ATOM_WS_OR_MASK:
236 val = 1 << gctx->shift;
237 break;
238 case ATOM_WS_AND_MASK:
239 val = ~(1 << gctx->shift);
240 break;
241 case ATOM_WS_FB_WINDOW:
242 val = gctx->fb_base;
243 break;
244 case ATOM_WS_ATTRIBUTES:
245 val = gctx->io_attr;
246 break;
247 default:
248 val = ctx->ws[idx];
249 }
250 break;
251 case ATOM_ARG_ID:
252 idx = U16(*ptr);
253 (*ptr) += 2;
254 if (print) {
255 if (gctx->data_block)
256 DEBUG("ID[0x%04X+%04X]", idx, gctx->data_block);
257 else
258 DEBUG("ID[0x%04X]", idx);
259 }
260 val = U32(idx + gctx->data_block);
261 break;
262 case ATOM_ARG_FB:
263 idx = U8(*ptr);
264 (*ptr)++;
265 if (print)
266 DEBUG("FB[0x%02X]", idx);
267 printk(KERN_INFO "FB access is not implemented.\n");
268 return 0;
269 case ATOM_ARG_IMM:
270 switch (align) {
271 case ATOM_SRC_DWORD:
272 val = U32(*ptr);
273 (*ptr) += 4;
274 if (print)
275 DEBUG("IMM 0x%08X\n", val);
276 return val;
277 case ATOM_SRC_WORD0:
278 case ATOM_SRC_WORD8:
279 case ATOM_SRC_WORD16:
280 val = U16(*ptr);
281 (*ptr) += 2;
282 if (print)
283 DEBUG("IMM 0x%04X\n", val);
284 return val;
285 case ATOM_SRC_BYTE0:
286 case ATOM_SRC_BYTE8:
287 case ATOM_SRC_BYTE16:
288 case ATOM_SRC_BYTE24:
289 val = U8(*ptr);
290 (*ptr)++;
291 if (print)
292 DEBUG("IMM 0x%02X\n", val);
293 return val;
294 }
295 return 0;
296 case ATOM_ARG_PLL:
297 idx = U8(*ptr);
298 (*ptr)++;
299 if (print)
300 DEBUG("PLL[0x%02X]", idx);
301 val = gctx->card->pll_read(gctx->card, idx);
302 break;
303 case ATOM_ARG_MC:
304 idx = U8(*ptr);
305 (*ptr)++;
306 if (print)
307 DEBUG("MC[0x%02X]", idx);
308 val = gctx->card->mc_read(gctx->card, idx);
309 break;
310 }
311 if (saved)
312 *saved = val;
313 val &= atom_arg_mask[align];
314 val >>= atom_arg_shift[align];
315 if (print)
316 switch (align) {
317 case ATOM_SRC_DWORD:
318 DEBUG(".[31:0] -> 0x%08X\n", val);
319 break;
320 case ATOM_SRC_WORD0:
321 DEBUG(".[15:0] -> 0x%04X\n", val);
322 break;
323 case ATOM_SRC_WORD8:
324 DEBUG(".[23:8] -> 0x%04X\n", val);
325 break;
326 case ATOM_SRC_WORD16:
327 DEBUG(".[31:16] -> 0x%04X\n", val);
328 break;
329 case ATOM_SRC_BYTE0:
330 DEBUG(".[7:0] -> 0x%02X\n", val);
331 break;
332 case ATOM_SRC_BYTE8:
333 DEBUG(".[15:8] -> 0x%02X\n", val);
334 break;
335 case ATOM_SRC_BYTE16:
336 DEBUG(".[23:16] -> 0x%02X\n", val);
337 break;
338 case ATOM_SRC_BYTE24:
339 DEBUG(".[31:24] -> 0x%02X\n", val);
340 break;
341 }
342 return val;
343}
344
345static void atom_skip_src_int(atom_exec_context *ctx, uint8_t attr, int *ptr)
346{
347 uint32_t align = (attr >> 3) & 7, arg = attr & 7;
348 switch (arg) {
349 case ATOM_ARG_REG:
350 case ATOM_ARG_ID:
351 (*ptr) += 2;
352 break;
353 case ATOM_ARG_PLL:
354 case ATOM_ARG_MC:
355 case ATOM_ARG_PS:
356 case ATOM_ARG_WS:
357 case ATOM_ARG_FB:
358 (*ptr)++;
359 break;
360 case ATOM_ARG_IMM:
361 switch (align) {
362 case ATOM_SRC_DWORD:
363 (*ptr) += 4;
364 return;
365 case ATOM_SRC_WORD0:
366 case ATOM_SRC_WORD8:
367 case ATOM_SRC_WORD16:
368 (*ptr) += 2;
369 return;
370 case ATOM_SRC_BYTE0:
371 case ATOM_SRC_BYTE8:
372 case ATOM_SRC_BYTE16:
373 case ATOM_SRC_BYTE24:
374 (*ptr)++;
375 return;
376 }
377 return;
378 }
379}
380
381static uint32_t atom_get_src(atom_exec_context *ctx, uint8_t attr, int *ptr)
382{
383 return atom_get_src_int(ctx, attr, ptr, NULL, 1);
384}
385
386static uint32_t atom_get_dst(atom_exec_context *ctx, int arg, uint8_t attr,
387 int *ptr, uint32_t *saved, int print)
388{
389 return atom_get_src_int(ctx,
390 arg | atom_dst_to_src[(attr >> 3) &
391 7][(attr >> 6) & 3] << 3,
392 ptr, saved, print);
393}
394
395static void atom_skip_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr)
396{
397 atom_skip_src_int(ctx,
398 arg | atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) &
399 3] << 3, ptr);
400}
401
402static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr,
403 int *ptr, uint32_t val, uint32_t saved)
404{
405 uint32_t align =
406 atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3], old_val =
407 val, idx;
408 struct atom_context *gctx = ctx->ctx;
409 old_val &= atom_arg_mask[align] >> atom_arg_shift[align];
410 val <<= atom_arg_shift[align];
411 val &= atom_arg_mask[align];
412 saved &= ~atom_arg_mask[align];
413 val |= saved;
414 switch (arg) {
415 case ATOM_ARG_REG:
416 idx = U16(*ptr);
417 (*ptr) += 2;
418 DEBUG("REG[0x%04X]", idx);
419 idx += gctx->reg_block;
420 switch (gctx->io_mode) {
421 case ATOM_IO_MM:
422 if (idx == 0)
423 gctx->card->reg_write(gctx->card, idx,
424 val << 2);
425 else
426 gctx->card->reg_write(gctx->card, idx, val);
427 break;
428 case ATOM_IO_PCI:
429 printk(KERN_INFO
430 "PCI registers are not implemented.\n");
431 return;
432 case ATOM_IO_SYSIO:
433 printk(KERN_INFO
434 "SYSIO registers are not implemented.\n");
435 return;
436 default:
437 if (!(gctx->io_mode & 0x80)) {
438 printk(KERN_INFO "Bad IO mode.\n");
439 return;
440 }
441 if (!gctx->iio[gctx->io_mode & 0xFF]) {
442 printk(KERN_INFO
443 "Undefined indirect IO write method %d.\n",
444 gctx->io_mode & 0x7F);
445 return;
446 }
447 atom_iio_execute(gctx, gctx->iio[gctx->io_mode & 0xFF],
448 idx, val);
449 }
450 break;
451 case ATOM_ARG_PS:
452 idx = U8(*ptr);
453 (*ptr)++;
454 DEBUG("PS[0x%02X]", idx);
455 ctx->ps[idx] = cpu_to_le32(val);
456 break;
457 case ATOM_ARG_WS:
458 idx = U8(*ptr);
459 (*ptr)++;
460 DEBUG("WS[0x%02X]", idx);
461 switch (idx) {
462 case ATOM_WS_QUOTIENT:
463 gctx->divmul[0] = val;
464 break;
465 case ATOM_WS_REMAINDER:
466 gctx->divmul[1] = val;
467 break;
468 case ATOM_WS_DATAPTR:
469 gctx->data_block = val;
470 break;
471 case ATOM_WS_SHIFT:
472 gctx->shift = val;
473 break;
474 case ATOM_WS_OR_MASK:
475 case ATOM_WS_AND_MASK:
476 break;
477 case ATOM_WS_FB_WINDOW:
478 gctx->fb_base = val;
479 break;
480 case ATOM_WS_ATTRIBUTES:
481 gctx->io_attr = val;
482 break;
483 default:
484 ctx->ws[idx] = val;
485 }
486 break;
487 case ATOM_ARG_FB:
488 idx = U8(*ptr);
489 (*ptr)++;
490 DEBUG("FB[0x%02X]", idx);
491 printk(KERN_INFO "FB access is not implemented.\n");
492 return;
493 case ATOM_ARG_PLL:
494 idx = U8(*ptr);
495 (*ptr)++;
496 DEBUG("PLL[0x%02X]", idx);
497 gctx->card->pll_write(gctx->card, idx, val);
498 break;
499 case ATOM_ARG_MC:
500 idx = U8(*ptr);
501 (*ptr)++;
502 DEBUG("MC[0x%02X]", idx);
503 gctx->card->mc_write(gctx->card, idx, val);
504 return;
505 }
506 switch (align) {
507 case ATOM_SRC_DWORD:
508 DEBUG(".[31:0] <- 0x%08X\n", old_val);
509 break;
510 case ATOM_SRC_WORD0:
511 DEBUG(".[15:0] <- 0x%04X\n", old_val);
512 break;
513 case ATOM_SRC_WORD8:
514 DEBUG(".[23:8] <- 0x%04X\n", old_val);
515 break;
516 case ATOM_SRC_WORD16:
517 DEBUG(".[31:16] <- 0x%04X\n", old_val);
518 break;
519 case ATOM_SRC_BYTE0:
520 DEBUG(".[7:0] <- 0x%02X\n", old_val);
521 break;
522 case ATOM_SRC_BYTE8:
523 DEBUG(".[15:8] <- 0x%02X\n", old_val);
524 break;
525 case ATOM_SRC_BYTE16:
526 DEBUG(".[23:16] <- 0x%02X\n", old_val);
527 break;
528 case ATOM_SRC_BYTE24:
529 DEBUG(".[31:24] <- 0x%02X\n", old_val);
530 break;
531 }
532}
533
534static void atom_op_add(atom_exec_context *ctx, int *ptr, int arg)
535{
536 uint8_t attr = U8((*ptr)++);
537 uint32_t dst, src, saved;
538 int dptr = *ptr;
539 SDEBUG(" dst: ");
540 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
541 SDEBUG(" src: ");
542 src = atom_get_src(ctx, attr, ptr);
543 dst += src;
544 SDEBUG(" dst: ");
545 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
546}
547
548static void atom_op_and(atom_exec_context *ctx, int *ptr, int arg)
549{
550 uint8_t attr = U8((*ptr)++);
551 uint32_t dst, src, saved;
552 int dptr = *ptr;
553 SDEBUG(" dst: ");
554 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
555 SDEBUG(" src: ");
556 src = atom_get_src(ctx, attr, ptr);
557 dst &= src;
558 SDEBUG(" dst: ");
559 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
560}
561
562static void atom_op_beep(atom_exec_context *ctx, int *ptr, int arg)
563{
564 printk("ATOM BIOS beeped!\n");
565}
566
567static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg)
568{
569 int idx = U8((*ptr)++);
570 if (idx < ATOM_TABLE_NAMES_CNT)
571 SDEBUG(" table: %d (%s)\n", idx, atom_table_names[idx]);
572 else
573 SDEBUG(" table: %d\n", idx);
574 if (U16(ctx->ctx->cmd_table + 4 + 2 * idx))
575 atom_execute_table(ctx->ctx, idx, ctx->ps + ctx->ps_shift);
576}
577
578static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg)
579{
580 uint8_t attr = U8((*ptr)++);
581 uint32_t saved;
582 int dptr = *ptr;
583 attr &= 0x38;
584 attr |= atom_def_dst[attr >> 3] << 6;
585 atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
586 SDEBUG(" dst: ");
587 atom_put_dst(ctx, arg, attr, &dptr, 0, saved);
588}
589
590static void atom_op_compare(atom_exec_context *ctx, int *ptr, int arg)
591{
592 uint8_t attr = U8((*ptr)++);
593 uint32_t dst, src;
594 SDEBUG(" src1: ");
595 dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
596 SDEBUG(" src2: ");
597 src = atom_get_src(ctx, attr, ptr);
598 ctx->ctx->cs_equal = (dst == src);
599 ctx->ctx->cs_above = (dst > src);
600 SDEBUG(" result: %s %s\n", ctx->ctx->cs_equal ? "EQ" : "NE",
601 ctx->ctx->cs_above ? "GT" : "LE");
602}
603
604static void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg)
605{
606 uint8_t count = U8((*ptr)++);
607 SDEBUG(" count: %d\n", count);
608 if (arg == ATOM_UNIT_MICROSEC)
609 schedule_timeout_uninterruptible(usecs_to_jiffies(count));
610 else
611 schedule_timeout_uninterruptible(msecs_to_jiffies(count));
612}
613
614static void atom_op_div(atom_exec_context *ctx, int *ptr, int arg)
615{
616 uint8_t attr = U8((*ptr)++);
617 uint32_t dst, src;
618 SDEBUG(" src1: ");
619 dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
620 SDEBUG(" src2: ");
621 src = atom_get_src(ctx, attr, ptr);
622 if (src != 0) {
623 ctx->ctx->divmul[0] = dst / src;
624 ctx->ctx->divmul[1] = dst % src;
625 } else {
626 ctx->ctx->divmul[0] = 0;
627 ctx->ctx->divmul[1] = 0;
628 }
629}
630
631static void atom_op_eot(atom_exec_context *ctx, int *ptr, int arg)
632{
633 /* functionally, a nop */
634}
635
636static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
637{
638 int execute = 0, target = U16(*ptr);
639 (*ptr) += 2;
640 switch (arg) {
641 case ATOM_COND_ABOVE:
642 execute = ctx->ctx->cs_above;
643 break;
644 case ATOM_COND_ABOVEOREQUAL:
645 execute = ctx->ctx->cs_above || ctx->ctx->cs_equal;
646 break;
647 case ATOM_COND_ALWAYS:
648 execute = 1;
649 break;
650 case ATOM_COND_BELOW:
651 execute = !(ctx->ctx->cs_above || ctx->ctx->cs_equal);
652 break;
653 case ATOM_COND_BELOWOREQUAL:
654 execute = !ctx->ctx->cs_above;
655 break;
656 case ATOM_COND_EQUAL:
657 execute = ctx->ctx->cs_equal;
658 break;
659 case ATOM_COND_NOTEQUAL:
660 execute = !ctx->ctx->cs_equal;
661 break;
662 }
663 if (arg != ATOM_COND_ALWAYS)
664 SDEBUG(" taken: %s\n", execute ? "yes" : "no");
665 SDEBUG(" target: 0x%04X\n", target);
666 if (execute)
667 *ptr = ctx->start + target;
668}
669
670static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg)
671{
672 uint8_t attr = U8((*ptr)++);
673 uint32_t dst, src1, src2, saved;
674 int dptr = *ptr;
675 SDEBUG(" dst: ");
676 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
677 SDEBUG(" src1: ");
678 src1 = atom_get_src(ctx, attr, ptr);
679 SDEBUG(" src2: ");
680 src2 = atom_get_src(ctx, attr, ptr);
681 dst &= src1;
682 dst |= src2;
683 SDEBUG(" dst: ");
684 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
685}
686
687static void atom_op_move(atom_exec_context *ctx, int *ptr, int arg)
688{
689 uint8_t attr = U8((*ptr)++);
690 uint32_t src, saved;
691 int dptr = *ptr;
692 if (((attr >> 3) & 7) != ATOM_SRC_DWORD)
693 atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
694 else {
695 atom_skip_dst(ctx, arg, attr, ptr);
696 saved = 0xCDCDCDCD;
697 }
698 SDEBUG(" src: ");
699 src = atom_get_src(ctx, attr, ptr);
700 SDEBUG(" dst: ");
701 atom_put_dst(ctx, arg, attr, &dptr, src, saved);
702}
703
704static void atom_op_mul(atom_exec_context *ctx, int *ptr, int arg)
705{
706 uint8_t attr = U8((*ptr)++);
707 uint32_t dst, src;
708 SDEBUG(" src1: ");
709 dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
710 SDEBUG(" src2: ");
711 src = atom_get_src(ctx, attr, ptr);
712 ctx->ctx->divmul[0] = dst * src;
713}
714
715static void atom_op_nop(atom_exec_context *ctx, int *ptr, int arg)
716{
717 /* nothing */
718}
719
720static void atom_op_or(atom_exec_context *ctx, int *ptr, int arg)
721{
722 uint8_t attr = U8((*ptr)++);
723 uint32_t dst, src, saved;
724 int dptr = *ptr;
725 SDEBUG(" dst: ");
726 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
727 SDEBUG(" src: ");
728 src = atom_get_src(ctx, attr, ptr);
729 dst |= src;
730 SDEBUG(" dst: ");
731 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
732}
733
734static void atom_op_postcard(atom_exec_context *ctx, int *ptr, int arg)
735{
736 uint8_t val = U8((*ptr)++);
737 SDEBUG("POST card output: 0x%02X\n", val);
738}
739
740static void atom_op_repeat(atom_exec_context *ctx, int *ptr, int arg)
741{
742 printk(KERN_INFO "unimplemented!\n");
743}
744
745static void atom_op_restorereg(atom_exec_context *ctx, int *ptr, int arg)
746{
747 printk(KERN_INFO "unimplemented!\n");
748}
749
750static void atom_op_savereg(atom_exec_context *ctx, int *ptr, int arg)
751{
752 printk(KERN_INFO "unimplemented!\n");
753}
754
755static void atom_op_setdatablock(atom_exec_context *ctx, int *ptr, int arg)
756{
757 int idx = U8(*ptr);
758 (*ptr)++;
759 SDEBUG(" block: %d\n", idx);
760 if (!idx)
761 ctx->ctx->data_block = 0;
762 else if (idx == 255)
763 ctx->ctx->data_block = ctx->start;
764 else
765 ctx->ctx->data_block = U16(ctx->ctx->data_table + 4 + 2 * idx);
766 SDEBUG(" base: 0x%04X\n", ctx->ctx->data_block);
767}
768
769static void atom_op_setfbbase(atom_exec_context *ctx, int *ptr, int arg)
770{
771 uint8_t attr = U8((*ptr)++);
772 SDEBUG(" fb_base: ");
773 ctx->ctx->fb_base = atom_get_src(ctx, attr, ptr);
774}
775
776static void atom_op_setport(atom_exec_context *ctx, int *ptr, int arg)
777{
778 int port;
779 switch (arg) {
780 case ATOM_PORT_ATI:
781 port = U16(*ptr);
782 if (port < ATOM_IO_NAMES_CNT)
783 SDEBUG(" port: %d (%s)\n", port, atom_io_names[port]);
784 else
785 SDEBUG(" port: %d\n", port);
786 if (!port)
787 ctx->ctx->io_mode = ATOM_IO_MM;
788 else
789 ctx->ctx->io_mode = ATOM_IO_IIO | port;
790 (*ptr) += 2;
791 break;
792 case ATOM_PORT_PCI:
793 ctx->ctx->io_mode = ATOM_IO_PCI;
794 (*ptr)++;
795 break;
796 case ATOM_PORT_SYSIO:
797 ctx->ctx->io_mode = ATOM_IO_SYSIO;
798 (*ptr)++;
799 break;
800 }
801}
802
803static void atom_op_setregblock(atom_exec_context *ctx, int *ptr, int arg)
804{
805 ctx->ctx->reg_block = U16(*ptr);
806 (*ptr) += 2;
807 SDEBUG(" base: 0x%04X\n", ctx->ctx->reg_block);
808}
809
810static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg)
811{
812 uint8_t attr = U8((*ptr)++), shift;
813 uint32_t saved, dst;
814 int dptr = *ptr;
815 attr &= 0x38;
816 attr |= atom_def_dst[attr >> 3] << 6;
817 SDEBUG(" dst: ");
818 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
819 shift = U8((*ptr)++);
820 SDEBUG(" shift: %d\n", shift);
821 dst <<= shift;
822 SDEBUG(" dst: ");
823 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
824}
825
826static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg)
827{
828 uint8_t attr = U8((*ptr)++), shift;
829 uint32_t saved, dst;
830 int dptr = *ptr;
831 attr &= 0x38;
832 attr |= atom_def_dst[attr >> 3] << 6;
833 SDEBUG(" dst: ");
834 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
835 shift = U8((*ptr)++);
836 SDEBUG(" shift: %d\n", shift);
837 dst >>= shift;
838 SDEBUG(" dst: ");
839 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
840}
841
842static void atom_op_sub(atom_exec_context *ctx, int *ptr, int arg)
843{
844 uint8_t attr = U8((*ptr)++);
845 uint32_t dst, src, saved;
846 int dptr = *ptr;
847 SDEBUG(" dst: ");
848 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
849 SDEBUG(" src: ");
850 src = atom_get_src(ctx, attr, ptr);
851 dst -= src;
852 SDEBUG(" dst: ");
853 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
854}
855
856static void atom_op_switch(atom_exec_context *ctx, int *ptr, int arg)
857{
858 uint8_t attr = U8((*ptr)++);
859 uint32_t src, val, target;
860 SDEBUG(" switch: ");
861 src = atom_get_src(ctx, attr, ptr);
862 while (U16(*ptr) != ATOM_CASE_END)
863 if (U8(*ptr) == ATOM_CASE_MAGIC) {
864 (*ptr)++;
865 SDEBUG(" case: ");
866 val =
867 atom_get_src(ctx, (attr & 0x38) | ATOM_ARG_IMM,
868 ptr);
869 target = U16(*ptr);
870 if (val == src) {
871 SDEBUG(" target: %04X\n", target);
872 *ptr = ctx->start + target;
873 return;
874 }
875 (*ptr) += 2;
876 } else {
877 printk(KERN_INFO "Bad case.\n");
878 return;
879 }
880 (*ptr) += 2;
881}
882
883static void atom_op_test(atom_exec_context *ctx, int *ptr, int arg)
884{
885 uint8_t attr = U8((*ptr)++);
886 uint32_t dst, src;
887 SDEBUG(" src1: ");
888 dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
889 SDEBUG(" src2: ");
890 src = atom_get_src(ctx, attr, ptr);
891 ctx->ctx->cs_equal = ((dst & src) == 0);
892 SDEBUG(" result: %s\n", ctx->ctx->cs_equal ? "EQ" : "NE");
893}
894
895static void atom_op_xor(atom_exec_context *ctx, int *ptr, int arg)
896{
897 uint8_t attr = U8((*ptr)++);
898 uint32_t dst, src, saved;
899 int dptr = *ptr;
900 SDEBUG(" dst: ");
901 dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
902 SDEBUG(" src: ");
903 src = atom_get_src(ctx, attr, ptr);
904 dst ^= src;
905 SDEBUG(" dst: ");
906 atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
907}
908
909static void atom_op_debug(atom_exec_context *ctx, int *ptr, int arg)
910{
911 printk(KERN_INFO "unimplemented!\n");
912}
913
914static struct {
915 void (*func) (atom_exec_context *, int *, int);
916 int arg;
917} opcode_table[ATOM_OP_CNT] = {
918 {
919 NULL, 0}, {
920 atom_op_move, ATOM_ARG_REG}, {
921 atom_op_move, ATOM_ARG_PS}, {
922 atom_op_move, ATOM_ARG_WS}, {
923 atom_op_move, ATOM_ARG_FB}, {
924 atom_op_move, ATOM_ARG_PLL}, {
925 atom_op_move, ATOM_ARG_MC}, {
926 atom_op_and, ATOM_ARG_REG}, {
927 atom_op_and, ATOM_ARG_PS}, {
928 atom_op_and, ATOM_ARG_WS}, {
929 atom_op_and, ATOM_ARG_FB}, {
930 atom_op_and, ATOM_ARG_PLL}, {
931 atom_op_and, ATOM_ARG_MC}, {
932 atom_op_or, ATOM_ARG_REG}, {
933 atom_op_or, ATOM_ARG_PS}, {
934 atom_op_or, ATOM_ARG_WS}, {
935 atom_op_or, ATOM_ARG_FB}, {
936 atom_op_or, ATOM_ARG_PLL}, {
937 atom_op_or, ATOM_ARG_MC}, {
938 atom_op_shl, ATOM_ARG_REG}, {
939 atom_op_shl, ATOM_ARG_PS}, {
940 atom_op_shl, ATOM_ARG_WS}, {
941 atom_op_shl, ATOM_ARG_FB}, {
942 atom_op_shl, ATOM_ARG_PLL}, {
943 atom_op_shl, ATOM_ARG_MC}, {
944 atom_op_shr, ATOM_ARG_REG}, {
945 atom_op_shr, ATOM_ARG_PS}, {
946 atom_op_shr, ATOM_ARG_WS}, {
947 atom_op_shr, ATOM_ARG_FB}, {
948 atom_op_shr, ATOM_ARG_PLL}, {
949 atom_op_shr, ATOM_ARG_MC}, {
950 atom_op_mul, ATOM_ARG_REG}, {
951 atom_op_mul, ATOM_ARG_PS}, {
952 atom_op_mul, ATOM_ARG_WS}, {
953 atom_op_mul, ATOM_ARG_FB}, {
954 atom_op_mul, ATOM_ARG_PLL}, {
955 atom_op_mul, ATOM_ARG_MC}, {
956 atom_op_div, ATOM_ARG_REG}, {
957 atom_op_div, ATOM_ARG_PS}, {
958 atom_op_div, ATOM_ARG_WS}, {
959 atom_op_div, ATOM_ARG_FB}, {
960 atom_op_div, ATOM_ARG_PLL}, {
961 atom_op_div, ATOM_ARG_MC}, {
962 atom_op_add, ATOM_ARG_REG}, {
963 atom_op_add, ATOM_ARG_PS}, {
964 atom_op_add, ATOM_ARG_WS}, {
965 atom_op_add, ATOM_ARG_FB}, {
966 atom_op_add, ATOM_ARG_PLL}, {
967 atom_op_add, ATOM_ARG_MC}, {
968 atom_op_sub, ATOM_ARG_REG}, {
969 atom_op_sub, ATOM_ARG_PS}, {
970 atom_op_sub, ATOM_ARG_WS}, {
971 atom_op_sub, ATOM_ARG_FB}, {
972 atom_op_sub, ATOM_ARG_PLL}, {
973 atom_op_sub, ATOM_ARG_MC}, {
974 atom_op_setport, ATOM_PORT_ATI}, {
975 atom_op_setport, ATOM_PORT_PCI}, {
976 atom_op_setport, ATOM_PORT_SYSIO}, {
977 atom_op_setregblock, 0}, {
978 atom_op_setfbbase, 0}, {
979 atom_op_compare, ATOM_ARG_REG}, {
980 atom_op_compare, ATOM_ARG_PS}, {
981 atom_op_compare, ATOM_ARG_WS}, {
982 atom_op_compare, ATOM_ARG_FB}, {
983 atom_op_compare, ATOM_ARG_PLL}, {
984 atom_op_compare, ATOM_ARG_MC}, {
985 atom_op_switch, 0}, {
986 atom_op_jump, ATOM_COND_ALWAYS}, {
987 atom_op_jump, ATOM_COND_EQUAL}, {
988 atom_op_jump, ATOM_COND_BELOW}, {
989 atom_op_jump, ATOM_COND_ABOVE}, {
990 atom_op_jump, ATOM_COND_BELOWOREQUAL}, {
991 atom_op_jump, ATOM_COND_ABOVEOREQUAL}, {
992 atom_op_jump, ATOM_COND_NOTEQUAL}, {
993 atom_op_test, ATOM_ARG_REG}, {
994 atom_op_test, ATOM_ARG_PS}, {
995 atom_op_test, ATOM_ARG_WS}, {
996 atom_op_test, ATOM_ARG_FB}, {
997 atom_op_test, ATOM_ARG_PLL}, {
998 atom_op_test, ATOM_ARG_MC}, {
999 atom_op_delay, ATOM_UNIT_MILLISEC}, {
1000 atom_op_delay, ATOM_UNIT_MICROSEC}, {
1001 atom_op_calltable, 0}, {
1002 atom_op_repeat, 0}, {
1003 atom_op_clear, ATOM_ARG_REG}, {
1004 atom_op_clear, ATOM_ARG_PS}, {
1005 atom_op_clear, ATOM_ARG_WS}, {
1006 atom_op_clear, ATOM_ARG_FB}, {
1007 atom_op_clear, ATOM_ARG_PLL}, {
1008 atom_op_clear, ATOM_ARG_MC}, {
1009 atom_op_nop, 0}, {
1010 atom_op_eot, 0}, {
1011 atom_op_mask, ATOM_ARG_REG}, {
1012 atom_op_mask, ATOM_ARG_PS}, {
1013 atom_op_mask, ATOM_ARG_WS}, {
1014 atom_op_mask, ATOM_ARG_FB}, {
1015 atom_op_mask, ATOM_ARG_PLL}, {
1016 atom_op_mask, ATOM_ARG_MC}, {
1017 atom_op_postcard, 0}, {
1018 atom_op_beep, 0}, {
1019 atom_op_savereg, 0}, {
1020 atom_op_restorereg, 0}, {
1021 atom_op_setdatablock, 0}, {
1022 atom_op_xor, ATOM_ARG_REG}, {
1023 atom_op_xor, ATOM_ARG_PS}, {
1024 atom_op_xor, ATOM_ARG_WS}, {
1025 atom_op_xor, ATOM_ARG_FB}, {
1026 atom_op_xor, ATOM_ARG_PLL}, {
1027 atom_op_xor, ATOM_ARG_MC}, {
1028 atom_op_shl, ATOM_ARG_REG}, {
1029 atom_op_shl, ATOM_ARG_PS}, {
1030 atom_op_shl, ATOM_ARG_WS}, {
1031 atom_op_shl, ATOM_ARG_FB}, {
1032 atom_op_shl, ATOM_ARG_PLL}, {
1033 atom_op_shl, ATOM_ARG_MC}, {
1034 atom_op_shr, ATOM_ARG_REG}, {
1035 atom_op_shr, ATOM_ARG_PS}, {
1036 atom_op_shr, ATOM_ARG_WS}, {
1037 atom_op_shr, ATOM_ARG_FB}, {
1038 atom_op_shr, ATOM_ARG_PLL}, {
1039 atom_op_shr, ATOM_ARG_MC}, {
1040atom_op_debug, 0},};
1041
1042void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
1043{
1044 int base = CU16(ctx->cmd_table + 4 + 2 * index);
1045 int len, ws, ps, ptr;
1046 unsigned char op;
1047 atom_exec_context ectx;
1048
1049 if (!base)
1050 return;
1051
1052 len = CU16(base + ATOM_CT_SIZE_PTR);
1053 ws = CU8(base + ATOM_CT_WS_PTR);
1054 ps = CU8(base + ATOM_CT_PS_PTR) & ATOM_CT_PS_MASK;
1055 ptr = base + ATOM_CT_CODE_PTR;
1056
1057 SDEBUG(">> execute %04X (len %d, WS %d, PS %d)\n", base, len, ws, ps);
1058
1059 /* reset reg block */
1060 ctx->reg_block = 0;
1061 ectx.ctx = ctx;
1062 ectx.ps_shift = ps / 4;
1063 ectx.start = base;
1064 ectx.ps = params;
1065 if (ws)
1066 ectx.ws = kzalloc(4 * ws, GFP_KERNEL);
1067 else
1068 ectx.ws = NULL;
1069
1070 debug_depth++;
1071 while (1) {
1072 op = CU8(ptr++);
1073 if (op < ATOM_OP_NAMES_CNT)
1074 SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr - 1);
1075 else
1076 SDEBUG("[%d] @ 0x%04X\n", op, ptr - 1);
1077
1078 if (op < ATOM_OP_CNT && op > 0)
1079 opcode_table[op].func(&ectx, &ptr,
1080 opcode_table[op].arg);
1081 else
1082 break;
1083
1084 if (op == ATOM_OP_EOT)
1085 break;
1086 }
1087 debug_depth--;
1088 SDEBUG("<<\n");
1089
1090 if (ws)
1091 kfree(ectx.ws);
1092}
1093
1094static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 };
1095
1096static void atom_index_iio(struct atom_context *ctx, int base)
1097{
1098 ctx->iio = kzalloc(2 * 256, GFP_KERNEL);
1099 while (CU8(base) == ATOM_IIO_START) {
1100 ctx->iio[CU8(base + 1)] = base + 2;
1101 base += 2;
1102 while (CU8(base) != ATOM_IIO_END)
1103 base += atom_iio_len[CU8(base)];
1104 base += 3;
1105 }
1106}
1107
1108struct atom_context *atom_parse(struct card_info *card, void *bios)
1109{
1110 int base;
1111 struct atom_context *ctx =
1112 kzalloc(sizeof(struct atom_context), GFP_KERNEL);
1113 char *str;
1114 char name[512];
1115 int i;
1116
1117 ctx->card = card;
1118 ctx->bios = bios;
1119
1120 if (CU16(0) != ATOM_BIOS_MAGIC) {
1121 printk(KERN_INFO "Invalid BIOS magic.\n");
1122 kfree(ctx);
1123 return NULL;
1124 }
1125 if (strncmp
1126 (CSTR(ATOM_ATI_MAGIC_PTR), ATOM_ATI_MAGIC,
1127 strlen(ATOM_ATI_MAGIC))) {
1128 printk(KERN_INFO "Invalid ATI magic.\n");
1129 kfree(ctx);
1130 return NULL;
1131 }
1132
1133 base = CU16(ATOM_ROM_TABLE_PTR);
1134 if (strncmp
1135 (CSTR(base + ATOM_ROM_MAGIC_PTR), ATOM_ROM_MAGIC,
1136 strlen(ATOM_ROM_MAGIC))) {
1137 printk(KERN_INFO "Invalid ATOM magic.\n");
1138 kfree(ctx);
1139 return NULL;
1140 }
1141
1142 ctx->cmd_table = CU16(base + ATOM_ROM_CMD_PTR);
1143 ctx->data_table = CU16(base + ATOM_ROM_DATA_PTR);
1144 atom_index_iio(ctx, CU16(ctx->data_table + ATOM_DATA_IIO_PTR) + 4);
1145
1146 str = CSTR(CU16(base + ATOM_ROM_MSG_PTR));
1147 while (*str && ((*str == '\n') || (*str == '\r')))
1148 str++;
1149 /* name string isn't always 0 terminated */
1150 for (i = 0; i < 511; i++) {
1151 name[i] = str[i];
1152 if (name[i] < '.' || name[i] > 'z') {
1153 name[i] = 0;
1154 break;
1155 }
1156 }
1157 printk(KERN_INFO "ATOM BIOS: %s\n", name);
1158
1159 return ctx;
1160}
1161
1162int atom_asic_init(struct atom_context *ctx)
1163{
1164 int hwi = CU16(ctx->data_table + ATOM_DATA_FWI_PTR);
1165 uint32_t ps[16];
1166 memset(ps, 0, 64);
1167
1168 ps[0] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFSCLK_PTR));
1169 ps[1] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFMCLK_PTR));
1170 if (!ps[0] || !ps[1])
1171 return 1;
1172
1173 if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT))
1174 return 1;
1175 atom_execute_table(ctx, ATOM_CMD_INIT, ps);
1176
1177 return 0;
1178}
1179
1180void atom_destroy(struct atom_context *ctx)
1181{
1182 if (ctx->iio)
1183 kfree(ctx->iio);
1184 kfree(ctx);
1185}
1186
1187void atom_parse_data_header(struct atom_context *ctx, int index,
1188 uint16_t * size, uint8_t * frev, uint8_t * crev,
1189 uint16_t * data_start)
1190{
1191 int offset = index * 2 + 4;
1192 int idx = CU16(ctx->data_table + offset);
1193
1194 if (size)
1195 *size = CU16(idx);
1196 if (frev)
1197 *frev = CU8(idx + 2);
1198 if (crev)
1199 *crev = CU8(idx + 3);
1200 *data_start = idx;
1201 return;
1202}
1203
1204void atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t * frev,
1205 uint8_t * crev)
1206{
1207 int offset = index * 2 + 4;
1208 int idx = CU16(ctx->cmd_table + offset);
1209
1210 if (frev)
1211 *frev = CU8(idx + 2);
1212 if (crev)
1213 *crev = CU8(idx + 3);
1214 return;
1215}