Subversion Repositories Kolibri OS

Rev

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