Subversion Repositories Kolibri OS

Rev

Rev 1120 | Rev 1313 | 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
 
1179 serge 25
#include 
26
#include 
1117 serge 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
 
52
typedef 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
 
60
int atom_debug = 0;
61
void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params);
62
 
63
static uint32_t atom_arg_mask[8] =
64
    { 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000,
65
0xFF000000 };
66
static int atom_arg_shift[8] = { 0, 0, 8, 16, 0, 8, 16, 24 };
67
 
68
static 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
};
79
static int atom_def_dst[8] = { 0, 0, 1, 2, 0, 1, 2, 3 };
80
 
81
static int debug_depth = 0;
82
#ifdef ATOM_DEBUG
83
static 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
 
96
static 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
 
167
static 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
 
345
static 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
 
381
static 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
 
386
static 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
 
395
static 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
 
402
static 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
 
534
static 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
 
548
static 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
 
562
static void atom_op_beep(atom_exec_context *ctx, int *ptr, int arg)
563
{
564
	printk("ATOM BIOS beeped!\n");
565
}
566
 
567
static 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
 
578
static 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
 
590
static 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
 
604
static 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);
1119 serge 608
    if (arg == ATOM_UNIT_MICROSEC)
609
       udelay(count);
610
    else
611
       mdelay(count);
1117 serge 612
}
613
 
614
static 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
 
631
static void atom_op_eot(atom_exec_context *ctx, int *ptr, int arg)
632
{
633
	/* functionally, a nop */
634
}
635
 
636
static 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
 
670
static 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
 
687
static 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
 
704
static 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
 
715
static void atom_op_nop(atom_exec_context *ctx, int *ptr, int arg)
716
{
717
	/* nothing */
718
}
719
 
720
static 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
 
734
static 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
 
740
static void atom_op_repeat(atom_exec_context *ctx, int *ptr, int arg)
741
{
742
	printk(KERN_INFO "unimplemented!\n");
743
}
744
 
745
static void atom_op_restorereg(atom_exec_context *ctx, int *ptr, int arg)
746
{
747
	printk(KERN_INFO "unimplemented!\n");
748
}
749
 
750
static void atom_op_savereg(atom_exec_context *ctx, int *ptr, int arg)
751
{
752
	printk(KERN_INFO "unimplemented!\n");
753
}
754
 
755
static 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
 
769
static 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
 
776
static 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
 
803
static 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
 
810
static 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
 
826
static 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
 
842
static 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
 
856
static 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
 
883
static 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
 
895
static 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
 
909
static void atom_op_debug(atom_exec_context *ctx, int *ptr, int arg)
910
{
911
	printk(KERN_INFO "unimplemented!\n");
912
}
913
 
914
static 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}, {
1040
atom_op_debug, 0},};
1041
 
1042
void 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
 
1094
static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 };
1095
 
1096
static 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
 
1108
struct 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
 
1162
int 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
 
1180
void atom_destroy(struct atom_context *ctx)
1181
{
1182
	if (ctx->iio)
1183
		kfree(ctx->iio);
1184
	kfree(ctx);
1185
}
1186
 
1187
void 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
 
1204
void 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
}