Subversion Repositories Kolibri OS

Rev

Rev 1119 | Go to most recent revision | Details | Last modification | View Log | RSS feed

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