1fb4d8502Sjsg /*
2fb4d8502Sjsg * Copyright 2008 Advanced Micro Devices, Inc.
3fb4d8502Sjsg *
4fb4d8502Sjsg * Permission is hereby granted, free of charge, to any person obtaining a
5fb4d8502Sjsg * copy of this software and associated documentation files (the "Software"),
6fb4d8502Sjsg * to deal in the Software without restriction, including without limitation
7fb4d8502Sjsg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8fb4d8502Sjsg * and/or sell copies of the Software, and to permit persons to whom the
9fb4d8502Sjsg * Software is furnished to do so, subject to the following conditions:
10fb4d8502Sjsg *
11fb4d8502Sjsg * The above copyright notice and this permission notice shall be included in
12fb4d8502Sjsg * all copies or substantial portions of the Software.
13fb4d8502Sjsg *
14fb4d8502Sjsg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15fb4d8502Sjsg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16fb4d8502Sjsg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17fb4d8502Sjsg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18fb4d8502Sjsg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19fb4d8502Sjsg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20fb4d8502Sjsg * OTHER DEALINGS IN THE SOFTWARE.
21fb4d8502Sjsg *
22fb4d8502Sjsg * Author: Stanislaw Skowronek
23fb4d8502Sjsg */
24fb4d8502Sjsg
25fb4d8502Sjsg #include <linux/module.h>
26fb4d8502Sjsg #include <linux/sched.h>
27fb4d8502Sjsg #include <linux/slab.h>
281bb76ff1Sjsg #include <linux/string_helpers.h>
291bb76ff1Sjsg
30fb4d8502Sjsg #include <asm/unaligned.h>
31fb4d8502Sjsg
32c349dbc7Sjsg #include <drm/drm_util.h>
33c349dbc7Sjsg
34fb4d8502Sjsg #define ATOM_DEBUG
35fb4d8502Sjsg
365ca02815Sjsg #include "atomfirmware.h"
37fb4d8502Sjsg #include "atom.h"
38fb4d8502Sjsg #include "atom-names.h"
39fb4d8502Sjsg #include "atom-bits.h"
40fb4d8502Sjsg #include "amdgpu.h"
41fb4d8502Sjsg
42fb4d8502Sjsg #define ATOM_COND_ABOVE 0
43fb4d8502Sjsg #define ATOM_COND_ABOVEOREQUAL 1
44fb4d8502Sjsg #define ATOM_COND_ALWAYS 2
45fb4d8502Sjsg #define ATOM_COND_BELOW 3
46fb4d8502Sjsg #define ATOM_COND_BELOWOREQUAL 4
47fb4d8502Sjsg #define ATOM_COND_EQUAL 5
48fb4d8502Sjsg #define ATOM_COND_NOTEQUAL 6
49fb4d8502Sjsg
50fb4d8502Sjsg #define ATOM_PORT_ATI 0
51fb4d8502Sjsg #define ATOM_PORT_PCI 1
52fb4d8502Sjsg #define ATOM_PORT_SYSIO 2
53fb4d8502Sjsg
54fb4d8502Sjsg #define ATOM_UNIT_MICROSEC 0
55fb4d8502Sjsg #define ATOM_UNIT_MILLISEC 1
56fb4d8502Sjsg
57fb4d8502Sjsg #define PLL_INDEX 2
58fb4d8502Sjsg #define PLL_DATA 3
59fb4d8502Sjsg
60ad8b1aafSjsg #define ATOM_CMD_TIMEOUT_SEC 20
61ad8b1aafSjsg
62fb4d8502Sjsg typedef struct {
63fb4d8502Sjsg struct atom_context *ctx;
64fb4d8502Sjsg uint32_t *ps, *ws;
65fb4d8502Sjsg int ps_shift;
66fb4d8502Sjsg uint16_t start;
67fb4d8502Sjsg unsigned last_jump;
68fb4d8502Sjsg unsigned long last_jump_jiffies;
69fb4d8502Sjsg bool abort;
70fb4d8502Sjsg } atom_exec_context;
71fb4d8502Sjsg
725ca02815Sjsg int amdgpu_atom_debug;
73fb4d8502Sjsg static int amdgpu_atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t *params);
74fb4d8502Sjsg int amdgpu_atom_execute_table(struct atom_context *ctx, int index, uint32_t *params);
75fb4d8502Sjsg
76fb4d8502Sjsg static uint32_t atom_arg_mask[8] =
77fb4d8502Sjsg { 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000,
78fb4d8502Sjsg 0xFF000000 };
79fb4d8502Sjsg static int atom_arg_shift[8] = { 0, 0, 8, 16, 0, 8, 16, 24 };
80fb4d8502Sjsg
81fb4d8502Sjsg static int atom_dst_to_src[8][4] = {
82fb4d8502Sjsg /* translate destination alignment field to the source alignment encoding */
83fb4d8502Sjsg {0, 0, 0, 0},
84fb4d8502Sjsg {1, 2, 3, 0},
85fb4d8502Sjsg {1, 2, 3, 0},
86fb4d8502Sjsg {1, 2, 3, 0},
87fb4d8502Sjsg {4, 5, 6, 7},
88fb4d8502Sjsg {4, 5, 6, 7},
89fb4d8502Sjsg {4, 5, 6, 7},
90fb4d8502Sjsg {4, 5, 6, 7},
91fb4d8502Sjsg };
92fb4d8502Sjsg static int atom_def_dst[8] = { 0, 0, 1, 2, 0, 1, 2, 3 };
93fb4d8502Sjsg
945ca02815Sjsg static int debug_depth;
95fb4d8502Sjsg #ifdef ATOM_DEBUG
debug_print_spaces(int n)96fb4d8502Sjsg static void debug_print_spaces(int n)
97fb4d8502Sjsg {
98fb4d8502Sjsg while (n--)
99fb4d8502Sjsg printk(" ");
100fb4d8502Sjsg }
101fb4d8502Sjsg
102f5af14d6Sjsg #ifdef DEBUG
103f5af14d6Sjsg #undef DEBUG
104f5af14d6Sjsg #endif
105f5af14d6Sjsg
106fb4d8502Sjsg #define DEBUG(...) do if (amdgpu_atom_debug) { printk(KERN_DEBUG __VA_ARGS__); } while (0)
107fb4d8502Sjsg #define SDEBUG(...) do if (amdgpu_atom_debug) { printk(KERN_DEBUG); debug_print_spaces(debug_depth); printk(__VA_ARGS__); } while (0)
108fb4d8502Sjsg #else
109fb4d8502Sjsg #define DEBUG(...) do { } while (0)
110fb4d8502Sjsg #define SDEBUG(...) do { } while (0)
111fb4d8502Sjsg #endif
112fb4d8502Sjsg
atom_iio_execute(struct atom_context * ctx,int base,uint32_t index,uint32_t data)113fb4d8502Sjsg static uint32_t atom_iio_execute(struct atom_context *ctx, int base,
114fb4d8502Sjsg uint32_t index, uint32_t data)
115fb4d8502Sjsg {
116fb4d8502Sjsg uint32_t temp = 0xCDCDCDCD;
117fb4d8502Sjsg
118fb4d8502Sjsg while (1)
119fb4d8502Sjsg switch (CU8(base)) {
120fb4d8502Sjsg case ATOM_IIO_NOP:
121fb4d8502Sjsg base++;
122fb4d8502Sjsg break;
123fb4d8502Sjsg case ATOM_IIO_READ:
1245ca02815Sjsg temp = ctx->card->reg_read(ctx->card, CU16(base + 1));
125fb4d8502Sjsg base += 3;
126fb4d8502Sjsg break;
127fb4d8502Sjsg case ATOM_IIO_WRITE:
1285ca02815Sjsg ctx->card->reg_write(ctx->card, CU16(base + 1), temp);
129fb4d8502Sjsg base += 3;
130fb4d8502Sjsg break;
131fb4d8502Sjsg case ATOM_IIO_CLEAR:
132fb4d8502Sjsg temp &=
133fb4d8502Sjsg ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
134fb4d8502Sjsg CU8(base + 2));
135fb4d8502Sjsg base += 3;
136fb4d8502Sjsg break;
137fb4d8502Sjsg case ATOM_IIO_SET:
138fb4d8502Sjsg temp |=
139fb4d8502Sjsg (0xFFFFFFFF >> (32 - CU8(base + 1))) << CU8(base +
140fb4d8502Sjsg 2);
141fb4d8502Sjsg base += 3;
142fb4d8502Sjsg break;
143fb4d8502Sjsg case ATOM_IIO_MOVE_INDEX:
144fb4d8502Sjsg temp &=
145fb4d8502Sjsg ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
146fb4d8502Sjsg CU8(base + 3));
147fb4d8502Sjsg temp |=
148fb4d8502Sjsg ((index >> CU8(base + 2)) &
149fb4d8502Sjsg (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base +
150fb4d8502Sjsg 3);
151fb4d8502Sjsg base += 4;
152fb4d8502Sjsg break;
153fb4d8502Sjsg case ATOM_IIO_MOVE_DATA:
154fb4d8502Sjsg temp &=
155fb4d8502Sjsg ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
156fb4d8502Sjsg CU8(base + 3));
157fb4d8502Sjsg temp |=
158fb4d8502Sjsg ((data >> CU8(base + 2)) &
159fb4d8502Sjsg (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base +
160fb4d8502Sjsg 3);
161fb4d8502Sjsg base += 4;
162fb4d8502Sjsg break;
163fb4d8502Sjsg case ATOM_IIO_MOVE_ATTR:
164fb4d8502Sjsg temp &=
165fb4d8502Sjsg ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
166fb4d8502Sjsg CU8(base + 3));
167fb4d8502Sjsg temp |=
168fb4d8502Sjsg ((ctx->
169fb4d8502Sjsg io_attr >> CU8(base + 2)) & (0xFFFFFFFF >> (32 -
170fb4d8502Sjsg CU8
171fb4d8502Sjsg (base
172fb4d8502Sjsg +
173fb4d8502Sjsg 1))))
174fb4d8502Sjsg << CU8(base + 3);
175fb4d8502Sjsg base += 4;
176fb4d8502Sjsg break;
177fb4d8502Sjsg case ATOM_IIO_END:
178fb4d8502Sjsg return temp;
179fb4d8502Sjsg default:
180fb4d8502Sjsg pr_info("Unknown IIO opcode\n");
181fb4d8502Sjsg return 0;
182fb4d8502Sjsg }
183fb4d8502Sjsg }
184fb4d8502Sjsg
atom_get_src_int(atom_exec_context * ctx,uint8_t attr,int * ptr,uint32_t * saved,int print)185fb4d8502Sjsg static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr,
186fb4d8502Sjsg int *ptr, uint32_t *saved, int print)
187fb4d8502Sjsg {
188fb4d8502Sjsg uint32_t idx, val = 0xCDCDCDCD, align, arg;
189fb4d8502Sjsg struct atom_context *gctx = ctx->ctx;
190fb4d8502Sjsg arg = attr & 7;
191fb4d8502Sjsg align = (attr >> 3) & 7;
192fb4d8502Sjsg switch (arg) {
193fb4d8502Sjsg case ATOM_ARG_REG:
194fb4d8502Sjsg idx = U16(*ptr);
195fb4d8502Sjsg (*ptr) += 2;
196fb4d8502Sjsg if (print)
197fb4d8502Sjsg DEBUG("REG[0x%04X]", idx);
198fb4d8502Sjsg idx += gctx->reg_block;
199fb4d8502Sjsg switch (gctx->io_mode) {
200fb4d8502Sjsg case ATOM_IO_MM:
201fb4d8502Sjsg val = gctx->card->reg_read(gctx->card, idx);
202fb4d8502Sjsg break;
203fb4d8502Sjsg case ATOM_IO_PCI:
204fb4d8502Sjsg pr_info("PCI registers are not implemented\n");
205fb4d8502Sjsg return 0;
206fb4d8502Sjsg case ATOM_IO_SYSIO:
207fb4d8502Sjsg pr_info("SYSIO registers are not implemented\n");
208fb4d8502Sjsg return 0;
209fb4d8502Sjsg default:
210fb4d8502Sjsg if (!(gctx->io_mode & 0x80)) {
211fb4d8502Sjsg pr_info("Bad IO mode\n");
212fb4d8502Sjsg return 0;
213fb4d8502Sjsg }
214fb4d8502Sjsg if (!gctx->iio[gctx->io_mode & 0x7F]) {
215fb4d8502Sjsg pr_info("Undefined indirect IO read method %d\n",
216fb4d8502Sjsg gctx->io_mode & 0x7F);
217fb4d8502Sjsg return 0;
218fb4d8502Sjsg }
219fb4d8502Sjsg val =
220fb4d8502Sjsg atom_iio_execute(gctx,
221fb4d8502Sjsg gctx->iio[gctx->io_mode & 0x7F],
222fb4d8502Sjsg idx, 0);
223fb4d8502Sjsg }
224fb4d8502Sjsg break;
225fb4d8502Sjsg case ATOM_ARG_PS:
226fb4d8502Sjsg idx = U8(*ptr);
227fb4d8502Sjsg (*ptr)++;
228fb4d8502Sjsg /* get_unaligned_le32 avoids unaligned accesses from atombios
229fb4d8502Sjsg * tables, noticed on a DEC Alpha. */
230fb4d8502Sjsg val = get_unaligned_le32((u32 *)&ctx->ps[idx]);
231fb4d8502Sjsg if (print)
232fb4d8502Sjsg DEBUG("PS[0x%02X,0x%04X]", idx, val);
233fb4d8502Sjsg break;
234fb4d8502Sjsg case ATOM_ARG_WS:
235fb4d8502Sjsg idx = U8(*ptr);
236fb4d8502Sjsg (*ptr)++;
237fb4d8502Sjsg if (print)
238fb4d8502Sjsg DEBUG("WS[0x%02X]", idx);
239fb4d8502Sjsg switch (idx) {
240fb4d8502Sjsg case ATOM_WS_QUOTIENT:
241fb4d8502Sjsg val = gctx->divmul[0];
242fb4d8502Sjsg break;
243fb4d8502Sjsg case ATOM_WS_REMAINDER:
244fb4d8502Sjsg val = gctx->divmul[1];
245fb4d8502Sjsg break;
246fb4d8502Sjsg case ATOM_WS_DATAPTR:
247fb4d8502Sjsg val = gctx->data_block;
248fb4d8502Sjsg break;
249fb4d8502Sjsg case ATOM_WS_SHIFT:
250fb4d8502Sjsg val = gctx->shift;
251fb4d8502Sjsg break;
252fb4d8502Sjsg case ATOM_WS_OR_MASK:
253fb4d8502Sjsg val = 1 << gctx->shift;
254fb4d8502Sjsg break;
255fb4d8502Sjsg case ATOM_WS_AND_MASK:
256fb4d8502Sjsg val = ~(1 << gctx->shift);
257fb4d8502Sjsg break;
258fb4d8502Sjsg case ATOM_WS_FB_WINDOW:
259fb4d8502Sjsg val = gctx->fb_base;
260fb4d8502Sjsg break;
261fb4d8502Sjsg case ATOM_WS_ATTRIBUTES:
262fb4d8502Sjsg val = gctx->io_attr;
263fb4d8502Sjsg break;
264fb4d8502Sjsg case ATOM_WS_REGPTR:
265fb4d8502Sjsg val = gctx->reg_block;
266fb4d8502Sjsg break;
267fb4d8502Sjsg default:
268fb4d8502Sjsg val = ctx->ws[idx];
269fb4d8502Sjsg }
270fb4d8502Sjsg break;
271fb4d8502Sjsg case ATOM_ARG_ID:
272fb4d8502Sjsg idx = U16(*ptr);
273fb4d8502Sjsg (*ptr) += 2;
274fb4d8502Sjsg if (print) {
275fb4d8502Sjsg if (gctx->data_block)
276fb4d8502Sjsg DEBUG("ID[0x%04X+%04X]", idx, gctx->data_block);
277fb4d8502Sjsg else
278fb4d8502Sjsg DEBUG("ID[0x%04X]", idx);
279fb4d8502Sjsg }
280fb4d8502Sjsg val = U32(idx + gctx->data_block);
281fb4d8502Sjsg break;
282fb4d8502Sjsg case ATOM_ARG_FB:
283fb4d8502Sjsg idx = U8(*ptr);
284fb4d8502Sjsg (*ptr)++;
285fb4d8502Sjsg if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) {
286fb4d8502Sjsg DRM_ERROR("ATOM: fb read beyond scratch region: %d vs. %d\n",
287fb4d8502Sjsg gctx->fb_base + (idx * 4), gctx->scratch_size_bytes);
288fb4d8502Sjsg val = 0;
289fb4d8502Sjsg } else
290fb4d8502Sjsg val = gctx->scratch[(gctx->fb_base / 4) + idx];
291fb4d8502Sjsg if (print)
292fb4d8502Sjsg DEBUG("FB[0x%02X]", idx);
293fb4d8502Sjsg break;
294fb4d8502Sjsg case ATOM_ARG_IMM:
295fb4d8502Sjsg switch (align) {
296fb4d8502Sjsg case ATOM_SRC_DWORD:
297fb4d8502Sjsg val = U32(*ptr);
298fb4d8502Sjsg (*ptr) += 4;
299fb4d8502Sjsg if (print)
300fb4d8502Sjsg DEBUG("IMM 0x%08X\n", val);
301fb4d8502Sjsg return val;
302fb4d8502Sjsg case ATOM_SRC_WORD0:
303fb4d8502Sjsg case ATOM_SRC_WORD8:
304fb4d8502Sjsg case ATOM_SRC_WORD16:
305fb4d8502Sjsg val = U16(*ptr);
306fb4d8502Sjsg (*ptr) += 2;
307fb4d8502Sjsg if (print)
308fb4d8502Sjsg DEBUG("IMM 0x%04X\n", val);
309fb4d8502Sjsg return val;
310fb4d8502Sjsg case ATOM_SRC_BYTE0:
311fb4d8502Sjsg case ATOM_SRC_BYTE8:
312fb4d8502Sjsg case ATOM_SRC_BYTE16:
313fb4d8502Sjsg case ATOM_SRC_BYTE24:
314fb4d8502Sjsg val = U8(*ptr);
315fb4d8502Sjsg (*ptr)++;
316fb4d8502Sjsg if (print)
317fb4d8502Sjsg DEBUG("IMM 0x%02X\n", val);
318fb4d8502Sjsg return val;
319fb4d8502Sjsg }
320*7c7baa3fSjsg break;
321fb4d8502Sjsg case ATOM_ARG_PLL:
322fb4d8502Sjsg idx = U8(*ptr);
323fb4d8502Sjsg (*ptr)++;
324fb4d8502Sjsg if (print)
325fb4d8502Sjsg DEBUG("PLL[0x%02X]", idx);
326fb4d8502Sjsg val = gctx->card->pll_read(gctx->card, idx);
327fb4d8502Sjsg break;
328fb4d8502Sjsg case ATOM_ARG_MC:
329fb4d8502Sjsg idx = U8(*ptr);
330fb4d8502Sjsg (*ptr)++;
331fb4d8502Sjsg if (print)
332fb4d8502Sjsg DEBUG("MC[0x%02X]", idx);
333fb4d8502Sjsg val = gctx->card->mc_read(gctx->card, idx);
334fb4d8502Sjsg break;
335fb4d8502Sjsg }
336fb4d8502Sjsg if (saved)
337fb4d8502Sjsg *saved = val;
338fb4d8502Sjsg val &= atom_arg_mask[align];
339fb4d8502Sjsg val >>= atom_arg_shift[align];
340fb4d8502Sjsg if (print)
341fb4d8502Sjsg switch (align) {
342fb4d8502Sjsg case ATOM_SRC_DWORD:
343fb4d8502Sjsg DEBUG(".[31:0] -> 0x%08X\n", val);
344fb4d8502Sjsg break;
345fb4d8502Sjsg case ATOM_SRC_WORD0:
346fb4d8502Sjsg DEBUG(".[15:0] -> 0x%04X\n", val);
347fb4d8502Sjsg break;
348fb4d8502Sjsg case ATOM_SRC_WORD8:
349fb4d8502Sjsg DEBUG(".[23:8] -> 0x%04X\n", val);
350fb4d8502Sjsg break;
351fb4d8502Sjsg case ATOM_SRC_WORD16:
352fb4d8502Sjsg DEBUG(".[31:16] -> 0x%04X\n", val);
353fb4d8502Sjsg break;
354fb4d8502Sjsg case ATOM_SRC_BYTE0:
355fb4d8502Sjsg DEBUG(".[7:0] -> 0x%02X\n", val);
356fb4d8502Sjsg break;
357fb4d8502Sjsg case ATOM_SRC_BYTE8:
358fb4d8502Sjsg DEBUG(".[15:8] -> 0x%02X\n", val);
359fb4d8502Sjsg break;
360fb4d8502Sjsg case ATOM_SRC_BYTE16:
361fb4d8502Sjsg DEBUG(".[23:16] -> 0x%02X\n", val);
362fb4d8502Sjsg break;
363fb4d8502Sjsg case ATOM_SRC_BYTE24:
364fb4d8502Sjsg DEBUG(".[31:24] -> 0x%02X\n", val);
365fb4d8502Sjsg break;
366fb4d8502Sjsg }
367fb4d8502Sjsg return val;
368fb4d8502Sjsg }
369fb4d8502Sjsg
atom_skip_src_int(atom_exec_context * ctx,uint8_t attr,int * ptr)370fb4d8502Sjsg static void atom_skip_src_int(atom_exec_context *ctx, uint8_t attr, int *ptr)
371fb4d8502Sjsg {
372fb4d8502Sjsg uint32_t align = (attr >> 3) & 7, arg = attr & 7;
373fb4d8502Sjsg switch (arg) {
374fb4d8502Sjsg case ATOM_ARG_REG:
375fb4d8502Sjsg case ATOM_ARG_ID:
376fb4d8502Sjsg (*ptr) += 2;
377fb4d8502Sjsg break;
378fb4d8502Sjsg case ATOM_ARG_PLL:
379fb4d8502Sjsg case ATOM_ARG_MC:
380fb4d8502Sjsg case ATOM_ARG_PS:
381fb4d8502Sjsg case ATOM_ARG_WS:
382fb4d8502Sjsg case ATOM_ARG_FB:
383fb4d8502Sjsg (*ptr)++;
384fb4d8502Sjsg break;
385fb4d8502Sjsg case ATOM_ARG_IMM:
386fb4d8502Sjsg switch (align) {
387fb4d8502Sjsg case ATOM_SRC_DWORD:
388fb4d8502Sjsg (*ptr) += 4;
389fb4d8502Sjsg return;
390fb4d8502Sjsg case ATOM_SRC_WORD0:
391fb4d8502Sjsg case ATOM_SRC_WORD8:
392fb4d8502Sjsg case ATOM_SRC_WORD16:
393fb4d8502Sjsg (*ptr) += 2;
394fb4d8502Sjsg return;
395fb4d8502Sjsg case ATOM_SRC_BYTE0:
396fb4d8502Sjsg case ATOM_SRC_BYTE8:
397fb4d8502Sjsg case ATOM_SRC_BYTE16:
398fb4d8502Sjsg case ATOM_SRC_BYTE24:
399fb4d8502Sjsg (*ptr)++;
400fb4d8502Sjsg return;
401fb4d8502Sjsg }
402fb4d8502Sjsg return;
403fb4d8502Sjsg }
404fb4d8502Sjsg }
405fb4d8502Sjsg
atom_get_src(atom_exec_context * ctx,uint8_t attr,int * ptr)406fb4d8502Sjsg static uint32_t atom_get_src(atom_exec_context *ctx, uint8_t attr, int *ptr)
407fb4d8502Sjsg {
408fb4d8502Sjsg return atom_get_src_int(ctx, attr, ptr, NULL, 1);
409fb4d8502Sjsg }
410fb4d8502Sjsg
atom_get_src_direct(atom_exec_context * ctx,uint8_t align,int * ptr)411fb4d8502Sjsg static uint32_t atom_get_src_direct(atom_exec_context *ctx, uint8_t align, int *ptr)
412fb4d8502Sjsg {
413fb4d8502Sjsg uint32_t val = 0xCDCDCDCD;
414fb4d8502Sjsg
415fb4d8502Sjsg switch (align) {
416fb4d8502Sjsg case ATOM_SRC_DWORD:
417fb4d8502Sjsg val = U32(*ptr);
418fb4d8502Sjsg (*ptr) += 4;
419fb4d8502Sjsg break;
420fb4d8502Sjsg case ATOM_SRC_WORD0:
421fb4d8502Sjsg case ATOM_SRC_WORD8:
422fb4d8502Sjsg case ATOM_SRC_WORD16:
423fb4d8502Sjsg val = U16(*ptr);
424fb4d8502Sjsg (*ptr) += 2;
425fb4d8502Sjsg break;
426fb4d8502Sjsg case ATOM_SRC_BYTE0:
427fb4d8502Sjsg case ATOM_SRC_BYTE8:
428fb4d8502Sjsg case ATOM_SRC_BYTE16:
429fb4d8502Sjsg case ATOM_SRC_BYTE24:
430fb4d8502Sjsg val = U8(*ptr);
431fb4d8502Sjsg (*ptr)++;
432fb4d8502Sjsg break;
433fb4d8502Sjsg }
434fb4d8502Sjsg return val;
435fb4d8502Sjsg }
436fb4d8502Sjsg
atom_get_dst(atom_exec_context * ctx,int arg,uint8_t attr,int * ptr,uint32_t * saved,int print)437fb4d8502Sjsg static uint32_t atom_get_dst(atom_exec_context *ctx, int arg, uint8_t attr,
438fb4d8502Sjsg int *ptr, uint32_t *saved, int print)
439fb4d8502Sjsg {
440fb4d8502Sjsg return atom_get_src_int(ctx,
441fb4d8502Sjsg arg | atom_dst_to_src[(attr >> 3) &
442fb4d8502Sjsg 7][(attr >> 6) & 3] << 3,
443fb4d8502Sjsg ptr, saved, print);
444fb4d8502Sjsg }
445fb4d8502Sjsg
atom_skip_dst(atom_exec_context * ctx,int arg,uint8_t attr,int * ptr)446fb4d8502Sjsg static void atom_skip_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr)
447fb4d8502Sjsg {
448fb4d8502Sjsg atom_skip_src_int(ctx,
449fb4d8502Sjsg arg | atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) &
450fb4d8502Sjsg 3] << 3, ptr);
451fb4d8502Sjsg }
452fb4d8502Sjsg
atom_put_dst(atom_exec_context * ctx,int arg,uint8_t attr,int * ptr,uint32_t val,uint32_t saved)453fb4d8502Sjsg static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr,
454fb4d8502Sjsg int *ptr, uint32_t val, uint32_t saved)
455fb4d8502Sjsg {
456fb4d8502Sjsg uint32_t align =
457fb4d8502Sjsg atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3], old_val =
458fb4d8502Sjsg val, idx;
459fb4d8502Sjsg struct atom_context *gctx = ctx->ctx;
460fb4d8502Sjsg old_val &= atom_arg_mask[align] >> atom_arg_shift[align];
461fb4d8502Sjsg val <<= atom_arg_shift[align];
462fb4d8502Sjsg val &= atom_arg_mask[align];
463fb4d8502Sjsg saved &= ~atom_arg_mask[align];
464fb4d8502Sjsg val |= saved;
465fb4d8502Sjsg switch (arg) {
466fb4d8502Sjsg case ATOM_ARG_REG:
467fb4d8502Sjsg idx = U16(*ptr);
468fb4d8502Sjsg (*ptr) += 2;
469fb4d8502Sjsg DEBUG("REG[0x%04X]", idx);
470fb4d8502Sjsg idx += gctx->reg_block;
471fb4d8502Sjsg switch (gctx->io_mode) {
472fb4d8502Sjsg case ATOM_IO_MM:
473fb4d8502Sjsg if (idx == 0)
474fb4d8502Sjsg gctx->card->reg_write(gctx->card, idx,
475fb4d8502Sjsg val << 2);
476fb4d8502Sjsg else
477fb4d8502Sjsg gctx->card->reg_write(gctx->card, idx, val);
478fb4d8502Sjsg break;
479fb4d8502Sjsg case ATOM_IO_PCI:
480fb4d8502Sjsg pr_info("PCI registers are not implemented\n");
481fb4d8502Sjsg return;
482fb4d8502Sjsg case ATOM_IO_SYSIO:
483fb4d8502Sjsg pr_info("SYSIO registers are not implemented\n");
484fb4d8502Sjsg return;
485fb4d8502Sjsg default:
486fb4d8502Sjsg if (!(gctx->io_mode & 0x80)) {
487fb4d8502Sjsg pr_info("Bad IO mode\n");
488fb4d8502Sjsg return;
489fb4d8502Sjsg }
490fb4d8502Sjsg if (!gctx->iio[gctx->io_mode & 0xFF]) {
491fb4d8502Sjsg pr_info("Undefined indirect IO write method %d\n",
492fb4d8502Sjsg gctx->io_mode & 0x7F);
493fb4d8502Sjsg return;
494fb4d8502Sjsg }
495fb4d8502Sjsg atom_iio_execute(gctx, gctx->iio[gctx->io_mode & 0xFF],
496fb4d8502Sjsg idx, val);
497fb4d8502Sjsg }
498fb4d8502Sjsg break;
499fb4d8502Sjsg case ATOM_ARG_PS:
500fb4d8502Sjsg idx = U8(*ptr);
501fb4d8502Sjsg (*ptr)++;
502fb4d8502Sjsg DEBUG("PS[0x%02X]", idx);
503fb4d8502Sjsg ctx->ps[idx] = cpu_to_le32(val);
504fb4d8502Sjsg break;
505fb4d8502Sjsg case ATOM_ARG_WS:
506fb4d8502Sjsg idx = U8(*ptr);
507fb4d8502Sjsg (*ptr)++;
508fb4d8502Sjsg DEBUG("WS[0x%02X]", idx);
509fb4d8502Sjsg switch (idx) {
510fb4d8502Sjsg case ATOM_WS_QUOTIENT:
511fb4d8502Sjsg gctx->divmul[0] = val;
512fb4d8502Sjsg break;
513fb4d8502Sjsg case ATOM_WS_REMAINDER:
514fb4d8502Sjsg gctx->divmul[1] = val;
515fb4d8502Sjsg break;
516fb4d8502Sjsg case ATOM_WS_DATAPTR:
517fb4d8502Sjsg gctx->data_block = val;
518fb4d8502Sjsg break;
519fb4d8502Sjsg case ATOM_WS_SHIFT:
520fb4d8502Sjsg gctx->shift = val;
521fb4d8502Sjsg break;
522fb4d8502Sjsg case ATOM_WS_OR_MASK:
523fb4d8502Sjsg case ATOM_WS_AND_MASK:
524fb4d8502Sjsg break;
525fb4d8502Sjsg case ATOM_WS_FB_WINDOW:
526fb4d8502Sjsg gctx->fb_base = val;
527fb4d8502Sjsg break;
528fb4d8502Sjsg case ATOM_WS_ATTRIBUTES:
529fb4d8502Sjsg gctx->io_attr = val;
530fb4d8502Sjsg break;
531fb4d8502Sjsg case ATOM_WS_REGPTR:
532fb4d8502Sjsg gctx->reg_block = val;
533fb4d8502Sjsg break;
534fb4d8502Sjsg default:
535fb4d8502Sjsg ctx->ws[idx] = val;
536fb4d8502Sjsg }
537fb4d8502Sjsg break;
538fb4d8502Sjsg case ATOM_ARG_FB:
539fb4d8502Sjsg idx = U8(*ptr);
540fb4d8502Sjsg (*ptr)++;
541fb4d8502Sjsg if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) {
542fb4d8502Sjsg DRM_ERROR("ATOM: fb write beyond scratch region: %d vs. %d\n",
543fb4d8502Sjsg gctx->fb_base + (idx * 4), gctx->scratch_size_bytes);
544fb4d8502Sjsg } else
545fb4d8502Sjsg gctx->scratch[(gctx->fb_base / 4) + idx] = val;
546fb4d8502Sjsg DEBUG("FB[0x%02X]", idx);
547fb4d8502Sjsg break;
548fb4d8502Sjsg case ATOM_ARG_PLL:
549fb4d8502Sjsg idx = U8(*ptr);
550fb4d8502Sjsg (*ptr)++;
551fb4d8502Sjsg DEBUG("PLL[0x%02X]", idx);
552fb4d8502Sjsg gctx->card->pll_write(gctx->card, idx, val);
553fb4d8502Sjsg break;
554fb4d8502Sjsg case ATOM_ARG_MC:
555fb4d8502Sjsg idx = U8(*ptr);
556fb4d8502Sjsg (*ptr)++;
557fb4d8502Sjsg DEBUG("MC[0x%02X]", idx);
558fb4d8502Sjsg gctx->card->mc_write(gctx->card, idx, val);
559fb4d8502Sjsg return;
560fb4d8502Sjsg }
561fb4d8502Sjsg switch (align) {
562fb4d8502Sjsg case ATOM_SRC_DWORD:
563fb4d8502Sjsg DEBUG(".[31:0] <- 0x%08X\n", old_val);
564fb4d8502Sjsg break;
565fb4d8502Sjsg case ATOM_SRC_WORD0:
566fb4d8502Sjsg DEBUG(".[15:0] <- 0x%04X\n", old_val);
567fb4d8502Sjsg break;
568fb4d8502Sjsg case ATOM_SRC_WORD8:
569fb4d8502Sjsg DEBUG(".[23:8] <- 0x%04X\n", old_val);
570fb4d8502Sjsg break;
571fb4d8502Sjsg case ATOM_SRC_WORD16:
572fb4d8502Sjsg DEBUG(".[31:16] <- 0x%04X\n", old_val);
573fb4d8502Sjsg break;
574fb4d8502Sjsg case ATOM_SRC_BYTE0:
575fb4d8502Sjsg DEBUG(".[7:0] <- 0x%02X\n", old_val);
576fb4d8502Sjsg break;
577fb4d8502Sjsg case ATOM_SRC_BYTE8:
578fb4d8502Sjsg DEBUG(".[15:8] <- 0x%02X\n", old_val);
579fb4d8502Sjsg break;
580fb4d8502Sjsg case ATOM_SRC_BYTE16:
581fb4d8502Sjsg DEBUG(".[23:16] <- 0x%02X\n", old_val);
582fb4d8502Sjsg break;
583fb4d8502Sjsg case ATOM_SRC_BYTE24:
584fb4d8502Sjsg DEBUG(".[31:24] <- 0x%02X\n", old_val);
585fb4d8502Sjsg break;
586fb4d8502Sjsg }
587fb4d8502Sjsg }
588fb4d8502Sjsg
atom_op_add(atom_exec_context * ctx,int * ptr,int arg)589fb4d8502Sjsg static void atom_op_add(atom_exec_context *ctx, int *ptr, int arg)
590fb4d8502Sjsg {
591fb4d8502Sjsg uint8_t attr = U8((*ptr)++);
592fb4d8502Sjsg uint32_t dst, src, saved;
593fb4d8502Sjsg int dptr = *ptr;
594fb4d8502Sjsg SDEBUG(" dst: ");
595fb4d8502Sjsg dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
596fb4d8502Sjsg SDEBUG(" src: ");
597fb4d8502Sjsg src = atom_get_src(ctx, attr, ptr);
598fb4d8502Sjsg dst += src;
599fb4d8502Sjsg SDEBUG(" dst: ");
600fb4d8502Sjsg atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
601fb4d8502Sjsg }
602fb4d8502Sjsg
atom_op_and(atom_exec_context * ctx,int * ptr,int arg)603fb4d8502Sjsg static void atom_op_and(atom_exec_context *ctx, int *ptr, int arg)
604fb4d8502Sjsg {
605fb4d8502Sjsg uint8_t attr = U8((*ptr)++);
606fb4d8502Sjsg uint32_t dst, src, saved;
607fb4d8502Sjsg int dptr = *ptr;
608fb4d8502Sjsg SDEBUG(" dst: ");
609fb4d8502Sjsg dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
610fb4d8502Sjsg SDEBUG(" src: ");
611fb4d8502Sjsg src = atom_get_src(ctx, attr, ptr);
612fb4d8502Sjsg dst &= src;
613fb4d8502Sjsg SDEBUG(" dst: ");
614fb4d8502Sjsg atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
615fb4d8502Sjsg }
616fb4d8502Sjsg
atom_op_beep(atom_exec_context * ctx,int * ptr,int arg)617fb4d8502Sjsg static void atom_op_beep(atom_exec_context *ctx, int *ptr, int arg)
618fb4d8502Sjsg {
619fb4d8502Sjsg printk("ATOM BIOS beeped!\n");
620fb4d8502Sjsg }
621fb4d8502Sjsg
atom_op_calltable(atom_exec_context * ctx,int * ptr,int arg)622fb4d8502Sjsg static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg)
623fb4d8502Sjsg {
624fb4d8502Sjsg int idx = U8((*ptr)++);
625fb4d8502Sjsg int r = 0;
626fb4d8502Sjsg
627fb4d8502Sjsg if (idx < ATOM_TABLE_NAMES_CNT)
628fb4d8502Sjsg SDEBUG(" table: %d (%s)\n", idx, atom_table_names[idx]);
629fb4d8502Sjsg else
630fb4d8502Sjsg SDEBUG(" table: %d\n", idx);
631fb4d8502Sjsg if (U16(ctx->ctx->cmd_table + 4 + 2 * idx))
632fb4d8502Sjsg r = amdgpu_atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift);
633fb4d8502Sjsg if (r) {
634fb4d8502Sjsg ctx->abort = true;
635fb4d8502Sjsg }
636fb4d8502Sjsg }
637fb4d8502Sjsg
atom_op_clear(atom_exec_context * ctx,int * ptr,int arg)638fb4d8502Sjsg static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg)
639fb4d8502Sjsg {
640fb4d8502Sjsg uint8_t attr = U8((*ptr)++);
641fb4d8502Sjsg uint32_t saved;
642fb4d8502Sjsg int dptr = *ptr;
643fb4d8502Sjsg attr &= 0x38;
644fb4d8502Sjsg attr |= atom_def_dst[attr >> 3] << 6;
645fb4d8502Sjsg atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
646fb4d8502Sjsg SDEBUG(" dst: ");
647fb4d8502Sjsg atom_put_dst(ctx, arg, attr, &dptr, 0, saved);
648fb4d8502Sjsg }
649fb4d8502Sjsg
atom_op_compare(atom_exec_context * ctx,int * ptr,int arg)650fb4d8502Sjsg static void atom_op_compare(atom_exec_context *ctx, int *ptr, int arg)
651fb4d8502Sjsg {
652fb4d8502Sjsg uint8_t attr = U8((*ptr)++);
653fb4d8502Sjsg uint32_t dst, src;
654fb4d8502Sjsg SDEBUG(" src1: ");
655fb4d8502Sjsg dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
656fb4d8502Sjsg SDEBUG(" src2: ");
657fb4d8502Sjsg src = atom_get_src(ctx, attr, ptr);
658fb4d8502Sjsg ctx->ctx->cs_equal = (dst == src);
659fb4d8502Sjsg ctx->ctx->cs_above = (dst > src);
660fb4d8502Sjsg SDEBUG(" result: %s %s\n", ctx->ctx->cs_equal ? "EQ" : "NE",
661fb4d8502Sjsg ctx->ctx->cs_above ? "GT" : "LE");
662fb4d8502Sjsg }
663fb4d8502Sjsg
atom_op_delay(atom_exec_context * ctx,int * ptr,int arg)664fb4d8502Sjsg static void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg)
665fb4d8502Sjsg {
666fb4d8502Sjsg unsigned count = U8((*ptr)++);
667fb4d8502Sjsg SDEBUG(" count: %d\n", count);
668fb4d8502Sjsg if (arg == ATOM_UNIT_MICROSEC)
669fb4d8502Sjsg udelay(count);
670fb4d8502Sjsg else if (!drm_can_sleep())
671fb4d8502Sjsg mdelay(count);
672fb4d8502Sjsg else
673fb4d8502Sjsg drm_msleep(count);
674fb4d8502Sjsg }
675fb4d8502Sjsg
atom_op_div(atom_exec_context * ctx,int * ptr,int arg)676fb4d8502Sjsg static void atom_op_div(atom_exec_context *ctx, int *ptr, int arg)
677fb4d8502Sjsg {
678fb4d8502Sjsg uint8_t attr = U8((*ptr)++);
679fb4d8502Sjsg uint32_t dst, src;
680fb4d8502Sjsg SDEBUG(" src1: ");
681fb4d8502Sjsg dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
682fb4d8502Sjsg SDEBUG(" src2: ");
683fb4d8502Sjsg src = atom_get_src(ctx, attr, ptr);
684fb4d8502Sjsg if (src != 0) {
685fb4d8502Sjsg ctx->ctx->divmul[0] = dst / src;
686fb4d8502Sjsg ctx->ctx->divmul[1] = dst % src;
687fb4d8502Sjsg } else {
688fb4d8502Sjsg ctx->ctx->divmul[0] = 0;
689fb4d8502Sjsg ctx->ctx->divmul[1] = 0;
690fb4d8502Sjsg }
691fb4d8502Sjsg }
692fb4d8502Sjsg
atom_op_div32(atom_exec_context * ctx,int * ptr,int arg)693fb4d8502Sjsg static void atom_op_div32(atom_exec_context *ctx, int *ptr, int arg)
694fb4d8502Sjsg {
695fb4d8502Sjsg uint64_t val64;
696fb4d8502Sjsg uint8_t attr = U8((*ptr)++);
697fb4d8502Sjsg uint32_t dst, src;
698fb4d8502Sjsg SDEBUG(" src1: ");
699fb4d8502Sjsg dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
700fb4d8502Sjsg SDEBUG(" src2: ");
701fb4d8502Sjsg src = atom_get_src(ctx, attr, ptr);
702fb4d8502Sjsg if (src != 0) {
703fb4d8502Sjsg val64 = dst;
704fb4d8502Sjsg val64 |= ((uint64_t)ctx->ctx->divmul[1]) << 32;
705fb4d8502Sjsg do_div(val64, src);
706fb4d8502Sjsg ctx->ctx->divmul[0] = lower_32_bits(val64);
707fb4d8502Sjsg ctx->ctx->divmul[1] = upper_32_bits(val64);
708fb4d8502Sjsg } else {
709fb4d8502Sjsg ctx->ctx->divmul[0] = 0;
710fb4d8502Sjsg ctx->ctx->divmul[1] = 0;
711fb4d8502Sjsg }
712fb4d8502Sjsg }
713fb4d8502Sjsg
atom_op_eot(atom_exec_context * ctx,int * ptr,int arg)714fb4d8502Sjsg static void atom_op_eot(atom_exec_context *ctx, int *ptr, int arg)
715fb4d8502Sjsg {
716fb4d8502Sjsg /* functionally, a nop */
717fb4d8502Sjsg }
718fb4d8502Sjsg
atom_op_jump(atom_exec_context * ctx,int * ptr,int arg)719fb4d8502Sjsg static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
720fb4d8502Sjsg {
721fb4d8502Sjsg int execute = 0, target = U16(*ptr);
722fb4d8502Sjsg unsigned long cjiffies;
723fb4d8502Sjsg
724fb4d8502Sjsg (*ptr) += 2;
725fb4d8502Sjsg switch (arg) {
726fb4d8502Sjsg case ATOM_COND_ABOVE:
727fb4d8502Sjsg execute = ctx->ctx->cs_above;
728fb4d8502Sjsg break;
729fb4d8502Sjsg case ATOM_COND_ABOVEOREQUAL:
730fb4d8502Sjsg execute = ctx->ctx->cs_above || ctx->ctx->cs_equal;
731fb4d8502Sjsg break;
732fb4d8502Sjsg case ATOM_COND_ALWAYS:
733fb4d8502Sjsg execute = 1;
734fb4d8502Sjsg break;
735fb4d8502Sjsg case ATOM_COND_BELOW:
736fb4d8502Sjsg execute = !(ctx->ctx->cs_above || ctx->ctx->cs_equal);
737fb4d8502Sjsg break;
738fb4d8502Sjsg case ATOM_COND_BELOWOREQUAL:
739fb4d8502Sjsg execute = !ctx->ctx->cs_above;
740fb4d8502Sjsg break;
741fb4d8502Sjsg case ATOM_COND_EQUAL:
742fb4d8502Sjsg execute = ctx->ctx->cs_equal;
743fb4d8502Sjsg break;
744fb4d8502Sjsg case ATOM_COND_NOTEQUAL:
745fb4d8502Sjsg execute = !ctx->ctx->cs_equal;
746fb4d8502Sjsg break;
747fb4d8502Sjsg }
748fb4d8502Sjsg if (arg != ATOM_COND_ALWAYS)
7491bb76ff1Sjsg SDEBUG(" taken: %s\n", str_yes_no(execute));
750fb4d8502Sjsg SDEBUG(" target: 0x%04X\n", target);
751fb4d8502Sjsg if (execute) {
752fb4d8502Sjsg if (ctx->last_jump == (ctx->start + target)) {
753fb4d8502Sjsg cjiffies = jiffies;
754fb4d8502Sjsg if (time_after(cjiffies, ctx->last_jump_jiffies)) {
755fb4d8502Sjsg cjiffies -= ctx->last_jump_jiffies;
756ad8b1aafSjsg if ((jiffies_to_msecs(cjiffies) > ATOM_CMD_TIMEOUT_SEC*1000)) {
757ad8b1aafSjsg DRM_ERROR("atombios stuck in loop for more than %dsecs aborting\n",
758ad8b1aafSjsg ATOM_CMD_TIMEOUT_SEC);
759fb4d8502Sjsg ctx->abort = true;
760fb4d8502Sjsg }
761fb4d8502Sjsg } else {
762fb4d8502Sjsg /* jiffies wrap around we will just wait a little longer */
763fb4d8502Sjsg ctx->last_jump_jiffies = jiffies;
764fb4d8502Sjsg }
765fb4d8502Sjsg } else {
766fb4d8502Sjsg ctx->last_jump = ctx->start + target;
767fb4d8502Sjsg ctx->last_jump_jiffies = jiffies;
768fb4d8502Sjsg }
769fb4d8502Sjsg *ptr = ctx->start + target;
770fb4d8502Sjsg }
771fb4d8502Sjsg }
772fb4d8502Sjsg
atom_op_mask(atom_exec_context * ctx,int * ptr,int arg)773fb4d8502Sjsg static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg)
774fb4d8502Sjsg {
775fb4d8502Sjsg uint8_t attr = U8((*ptr)++);
776fb4d8502Sjsg uint32_t dst, mask, src, saved;
777fb4d8502Sjsg int dptr = *ptr;
778fb4d8502Sjsg SDEBUG(" dst: ");
779fb4d8502Sjsg dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
780fb4d8502Sjsg mask = atom_get_src_direct(ctx, ((attr >> 3) & 7), ptr);
781fb4d8502Sjsg SDEBUG(" mask: 0x%08x", mask);
782fb4d8502Sjsg SDEBUG(" src: ");
783fb4d8502Sjsg src = atom_get_src(ctx, attr, ptr);
784fb4d8502Sjsg dst &= mask;
785fb4d8502Sjsg dst |= src;
786fb4d8502Sjsg SDEBUG(" dst: ");
787fb4d8502Sjsg atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
788fb4d8502Sjsg }
789fb4d8502Sjsg
atom_op_move(atom_exec_context * ctx,int * ptr,int arg)790fb4d8502Sjsg static void atom_op_move(atom_exec_context *ctx, int *ptr, int arg)
791fb4d8502Sjsg {
792fb4d8502Sjsg uint8_t attr = U8((*ptr)++);
793fb4d8502Sjsg uint32_t src, saved;
794fb4d8502Sjsg int dptr = *ptr;
795fb4d8502Sjsg if (((attr >> 3) & 7) != ATOM_SRC_DWORD)
796fb4d8502Sjsg atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
797fb4d8502Sjsg else {
798fb4d8502Sjsg atom_skip_dst(ctx, arg, attr, ptr);
799fb4d8502Sjsg saved = 0xCDCDCDCD;
800fb4d8502Sjsg }
801fb4d8502Sjsg SDEBUG(" src: ");
802fb4d8502Sjsg src = atom_get_src(ctx, attr, ptr);
803fb4d8502Sjsg SDEBUG(" dst: ");
804fb4d8502Sjsg atom_put_dst(ctx, arg, attr, &dptr, src, saved);
805fb4d8502Sjsg }
806fb4d8502Sjsg
atom_op_mul(atom_exec_context * ctx,int * ptr,int arg)807fb4d8502Sjsg static void atom_op_mul(atom_exec_context *ctx, int *ptr, int arg)
808fb4d8502Sjsg {
809fb4d8502Sjsg uint8_t attr = U8((*ptr)++);
810fb4d8502Sjsg uint32_t dst, src;
811fb4d8502Sjsg SDEBUG(" src1: ");
812fb4d8502Sjsg dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
813fb4d8502Sjsg SDEBUG(" src2: ");
814fb4d8502Sjsg src = atom_get_src(ctx, attr, ptr);
815fb4d8502Sjsg ctx->ctx->divmul[0] = dst * src;
816fb4d8502Sjsg }
817fb4d8502Sjsg
atom_op_mul32(atom_exec_context * ctx,int * ptr,int arg)818fb4d8502Sjsg static void atom_op_mul32(atom_exec_context *ctx, int *ptr, int arg)
819fb4d8502Sjsg {
820fb4d8502Sjsg uint64_t val64;
821fb4d8502Sjsg uint8_t attr = U8((*ptr)++);
822fb4d8502Sjsg uint32_t dst, src;
823fb4d8502Sjsg SDEBUG(" src1: ");
824fb4d8502Sjsg dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
825fb4d8502Sjsg SDEBUG(" src2: ");
826fb4d8502Sjsg src = atom_get_src(ctx, attr, ptr);
827fb4d8502Sjsg val64 = (uint64_t)dst * (uint64_t)src;
828fb4d8502Sjsg ctx->ctx->divmul[0] = lower_32_bits(val64);
829fb4d8502Sjsg ctx->ctx->divmul[1] = upper_32_bits(val64);
830fb4d8502Sjsg }
831fb4d8502Sjsg
atom_op_nop(atom_exec_context * ctx,int * ptr,int arg)832fb4d8502Sjsg static void atom_op_nop(atom_exec_context *ctx, int *ptr, int arg)
833fb4d8502Sjsg {
834fb4d8502Sjsg /* nothing */
835fb4d8502Sjsg }
836fb4d8502Sjsg
atom_op_or(atom_exec_context * ctx,int * ptr,int arg)837fb4d8502Sjsg static void atom_op_or(atom_exec_context *ctx, int *ptr, int arg)
838fb4d8502Sjsg {
839fb4d8502Sjsg uint8_t attr = U8((*ptr)++);
840fb4d8502Sjsg uint32_t dst, src, saved;
841fb4d8502Sjsg int dptr = *ptr;
842fb4d8502Sjsg SDEBUG(" dst: ");
843fb4d8502Sjsg dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
844fb4d8502Sjsg SDEBUG(" src: ");
845fb4d8502Sjsg src = atom_get_src(ctx, attr, ptr);
846fb4d8502Sjsg dst |= src;
847fb4d8502Sjsg SDEBUG(" dst: ");
848fb4d8502Sjsg atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
849fb4d8502Sjsg }
850fb4d8502Sjsg
atom_op_postcard(atom_exec_context * ctx,int * ptr,int arg)851fb4d8502Sjsg static void atom_op_postcard(atom_exec_context *ctx, int *ptr, int arg)
852fb4d8502Sjsg {
853fb4d8502Sjsg uint8_t val = U8((*ptr)++);
854fb4d8502Sjsg SDEBUG("POST card output: 0x%02X\n", val);
855fb4d8502Sjsg }
856fb4d8502Sjsg
atom_op_repeat(atom_exec_context * ctx,int * ptr,int arg)857fb4d8502Sjsg static void atom_op_repeat(atom_exec_context *ctx, int *ptr, int arg)
858fb4d8502Sjsg {
859fb4d8502Sjsg pr_info("unimplemented!\n");
860fb4d8502Sjsg }
861fb4d8502Sjsg
atom_op_restorereg(atom_exec_context * ctx,int * ptr,int arg)862fb4d8502Sjsg static void atom_op_restorereg(atom_exec_context *ctx, int *ptr, int arg)
863fb4d8502Sjsg {
864fb4d8502Sjsg pr_info("unimplemented!\n");
865fb4d8502Sjsg }
866fb4d8502Sjsg
atom_op_savereg(atom_exec_context * ctx,int * ptr,int arg)867fb4d8502Sjsg static void atom_op_savereg(atom_exec_context *ctx, int *ptr, int arg)
868fb4d8502Sjsg {
869fb4d8502Sjsg pr_info("unimplemented!\n");
870fb4d8502Sjsg }
871fb4d8502Sjsg
atom_op_setdatablock(atom_exec_context * ctx,int * ptr,int arg)872fb4d8502Sjsg static void atom_op_setdatablock(atom_exec_context *ctx, int *ptr, int arg)
873fb4d8502Sjsg {
874fb4d8502Sjsg int idx = U8(*ptr);
875fb4d8502Sjsg (*ptr)++;
876fb4d8502Sjsg SDEBUG(" block: %d\n", idx);
877fb4d8502Sjsg if (!idx)
878fb4d8502Sjsg ctx->ctx->data_block = 0;
879fb4d8502Sjsg else if (idx == 255)
880fb4d8502Sjsg ctx->ctx->data_block = ctx->start;
881fb4d8502Sjsg else
882fb4d8502Sjsg ctx->ctx->data_block = U16(ctx->ctx->data_table + 4 + 2 * idx);
883fb4d8502Sjsg SDEBUG(" base: 0x%04X\n", ctx->ctx->data_block);
884fb4d8502Sjsg }
885fb4d8502Sjsg
atom_op_setfbbase(atom_exec_context * ctx,int * ptr,int arg)886fb4d8502Sjsg static void atom_op_setfbbase(atom_exec_context *ctx, int *ptr, int arg)
887fb4d8502Sjsg {
888fb4d8502Sjsg uint8_t attr = U8((*ptr)++);
889fb4d8502Sjsg SDEBUG(" fb_base: ");
890fb4d8502Sjsg ctx->ctx->fb_base = atom_get_src(ctx, attr, ptr);
891fb4d8502Sjsg }
892fb4d8502Sjsg
atom_op_setport(atom_exec_context * ctx,int * ptr,int arg)893fb4d8502Sjsg static void atom_op_setport(atom_exec_context *ctx, int *ptr, int arg)
894fb4d8502Sjsg {
895fb4d8502Sjsg int port;
896fb4d8502Sjsg switch (arg) {
897fb4d8502Sjsg case ATOM_PORT_ATI:
898fb4d8502Sjsg port = U16(*ptr);
899fb4d8502Sjsg if (port < ATOM_IO_NAMES_CNT)
900fb4d8502Sjsg SDEBUG(" port: %d (%s)\n", port, atom_io_names[port]);
901fb4d8502Sjsg else
902fb4d8502Sjsg SDEBUG(" port: %d\n", port);
903fb4d8502Sjsg if (!port)
904fb4d8502Sjsg ctx->ctx->io_mode = ATOM_IO_MM;
905fb4d8502Sjsg else
906fb4d8502Sjsg ctx->ctx->io_mode = ATOM_IO_IIO | port;
907fb4d8502Sjsg (*ptr) += 2;
908fb4d8502Sjsg break;
909fb4d8502Sjsg case ATOM_PORT_PCI:
910fb4d8502Sjsg ctx->ctx->io_mode = ATOM_IO_PCI;
911fb4d8502Sjsg (*ptr)++;
912fb4d8502Sjsg break;
913fb4d8502Sjsg case ATOM_PORT_SYSIO:
914fb4d8502Sjsg ctx->ctx->io_mode = ATOM_IO_SYSIO;
915fb4d8502Sjsg (*ptr)++;
916fb4d8502Sjsg break;
917fb4d8502Sjsg }
918fb4d8502Sjsg }
919fb4d8502Sjsg
atom_op_setregblock(atom_exec_context * ctx,int * ptr,int arg)920fb4d8502Sjsg static void atom_op_setregblock(atom_exec_context *ctx, int *ptr, int arg)
921fb4d8502Sjsg {
922fb4d8502Sjsg ctx->ctx->reg_block = U16(*ptr);
923fb4d8502Sjsg (*ptr) += 2;
924fb4d8502Sjsg SDEBUG(" base: 0x%04X\n", ctx->ctx->reg_block);
925fb4d8502Sjsg }
926fb4d8502Sjsg
atom_op_shift_left(atom_exec_context * ctx,int * ptr,int arg)927fb4d8502Sjsg static void atom_op_shift_left(atom_exec_context *ctx, int *ptr, int arg)
928fb4d8502Sjsg {
929fb4d8502Sjsg uint8_t attr = U8((*ptr)++), shift;
930fb4d8502Sjsg uint32_t saved, dst;
931fb4d8502Sjsg int dptr = *ptr;
932fb4d8502Sjsg attr &= 0x38;
933fb4d8502Sjsg attr |= atom_def_dst[attr >> 3] << 6;
934fb4d8502Sjsg SDEBUG(" dst: ");
935fb4d8502Sjsg dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
936fb4d8502Sjsg shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr);
937fb4d8502Sjsg SDEBUG(" shift: %d\n", shift);
938fb4d8502Sjsg dst <<= shift;
939fb4d8502Sjsg SDEBUG(" dst: ");
940fb4d8502Sjsg atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
941fb4d8502Sjsg }
942fb4d8502Sjsg
atom_op_shift_right(atom_exec_context * ctx,int * ptr,int arg)943fb4d8502Sjsg static void atom_op_shift_right(atom_exec_context *ctx, int *ptr, int arg)
944fb4d8502Sjsg {
945fb4d8502Sjsg uint8_t attr = U8((*ptr)++), shift;
946fb4d8502Sjsg uint32_t saved, dst;
947fb4d8502Sjsg int dptr = *ptr;
948fb4d8502Sjsg attr &= 0x38;
949fb4d8502Sjsg attr |= atom_def_dst[attr >> 3] << 6;
950fb4d8502Sjsg SDEBUG(" dst: ");
951fb4d8502Sjsg dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
952fb4d8502Sjsg shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr);
953fb4d8502Sjsg SDEBUG(" shift: %d\n", shift);
954fb4d8502Sjsg dst >>= shift;
955fb4d8502Sjsg SDEBUG(" dst: ");
956fb4d8502Sjsg atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
957fb4d8502Sjsg }
958fb4d8502Sjsg
atom_op_shl(atom_exec_context * ctx,int * ptr,int arg)959fb4d8502Sjsg static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg)
960fb4d8502Sjsg {
961fb4d8502Sjsg uint8_t attr = U8((*ptr)++), shift;
962fb4d8502Sjsg uint32_t saved, dst;
963fb4d8502Sjsg int dptr = *ptr;
964fb4d8502Sjsg uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3];
965fb4d8502Sjsg SDEBUG(" dst: ");
966fb4d8502Sjsg dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
967fb4d8502Sjsg /* op needs to full dst value */
968fb4d8502Sjsg dst = saved;
969fb4d8502Sjsg shift = atom_get_src(ctx, attr, ptr);
970fb4d8502Sjsg SDEBUG(" shift: %d\n", shift);
971fb4d8502Sjsg dst <<= shift;
972fb4d8502Sjsg dst &= atom_arg_mask[dst_align];
973fb4d8502Sjsg dst >>= atom_arg_shift[dst_align];
974fb4d8502Sjsg SDEBUG(" dst: ");
975fb4d8502Sjsg atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
976fb4d8502Sjsg }
977fb4d8502Sjsg
atom_op_shr(atom_exec_context * ctx,int * ptr,int arg)978fb4d8502Sjsg static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg)
979fb4d8502Sjsg {
980fb4d8502Sjsg uint8_t attr = U8((*ptr)++), shift;
981fb4d8502Sjsg uint32_t saved, dst;
982fb4d8502Sjsg int dptr = *ptr;
983fb4d8502Sjsg uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3];
984fb4d8502Sjsg SDEBUG(" dst: ");
985fb4d8502Sjsg dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
986fb4d8502Sjsg /* op needs to full dst value */
987fb4d8502Sjsg dst = saved;
988fb4d8502Sjsg shift = atom_get_src(ctx, attr, ptr);
989fb4d8502Sjsg SDEBUG(" shift: %d\n", shift);
990fb4d8502Sjsg dst >>= shift;
991fb4d8502Sjsg dst &= atom_arg_mask[dst_align];
992fb4d8502Sjsg dst >>= atom_arg_shift[dst_align];
993fb4d8502Sjsg SDEBUG(" dst: ");
994fb4d8502Sjsg atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
995fb4d8502Sjsg }
996fb4d8502Sjsg
atom_op_sub(atom_exec_context * ctx,int * ptr,int arg)997fb4d8502Sjsg static void atom_op_sub(atom_exec_context *ctx, int *ptr, int arg)
998fb4d8502Sjsg {
999fb4d8502Sjsg uint8_t attr = U8((*ptr)++);
1000fb4d8502Sjsg uint32_t dst, src, saved;
1001fb4d8502Sjsg int dptr = *ptr;
1002fb4d8502Sjsg SDEBUG(" dst: ");
1003fb4d8502Sjsg dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
1004fb4d8502Sjsg SDEBUG(" src: ");
1005fb4d8502Sjsg src = atom_get_src(ctx, attr, ptr);
1006fb4d8502Sjsg dst -= src;
1007fb4d8502Sjsg SDEBUG(" dst: ");
1008fb4d8502Sjsg atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
1009fb4d8502Sjsg }
1010fb4d8502Sjsg
atom_op_switch(atom_exec_context * ctx,int * ptr,int arg)1011fb4d8502Sjsg static void atom_op_switch(atom_exec_context *ctx, int *ptr, int arg)
1012fb4d8502Sjsg {
1013fb4d8502Sjsg uint8_t attr = U8((*ptr)++);
1014fb4d8502Sjsg uint32_t src, val, target;
1015fb4d8502Sjsg SDEBUG(" switch: ");
1016fb4d8502Sjsg src = atom_get_src(ctx, attr, ptr);
1017fb4d8502Sjsg while (U16(*ptr) != ATOM_CASE_END)
1018fb4d8502Sjsg if (U8(*ptr) == ATOM_CASE_MAGIC) {
1019fb4d8502Sjsg (*ptr)++;
1020fb4d8502Sjsg SDEBUG(" case: ");
1021fb4d8502Sjsg val =
1022fb4d8502Sjsg atom_get_src(ctx, (attr & 0x38) | ATOM_ARG_IMM,
1023fb4d8502Sjsg ptr);
1024fb4d8502Sjsg target = U16(*ptr);
1025fb4d8502Sjsg if (val == src) {
1026fb4d8502Sjsg SDEBUG(" target: %04X\n", target);
1027fb4d8502Sjsg *ptr = ctx->start + target;
1028fb4d8502Sjsg return;
1029fb4d8502Sjsg }
1030fb4d8502Sjsg (*ptr) += 2;
1031fb4d8502Sjsg } else {
1032fb4d8502Sjsg pr_info("Bad case\n");
1033fb4d8502Sjsg return;
1034fb4d8502Sjsg }
1035fb4d8502Sjsg (*ptr) += 2;
1036fb4d8502Sjsg }
1037fb4d8502Sjsg
atom_op_test(atom_exec_context * ctx,int * ptr,int arg)1038fb4d8502Sjsg static void atom_op_test(atom_exec_context *ctx, int *ptr, int arg)
1039fb4d8502Sjsg {
1040fb4d8502Sjsg uint8_t attr = U8((*ptr)++);
1041fb4d8502Sjsg uint32_t dst, src;
1042fb4d8502Sjsg SDEBUG(" src1: ");
1043fb4d8502Sjsg dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
1044fb4d8502Sjsg SDEBUG(" src2: ");
1045fb4d8502Sjsg src = atom_get_src(ctx, attr, ptr);
1046fb4d8502Sjsg ctx->ctx->cs_equal = ((dst & src) == 0);
1047fb4d8502Sjsg SDEBUG(" result: %s\n", ctx->ctx->cs_equal ? "EQ" : "NE");
1048fb4d8502Sjsg }
1049fb4d8502Sjsg
atom_op_xor(atom_exec_context * ctx,int * ptr,int arg)1050fb4d8502Sjsg static void atom_op_xor(atom_exec_context *ctx, int *ptr, int arg)
1051fb4d8502Sjsg {
1052fb4d8502Sjsg uint8_t attr = U8((*ptr)++);
1053fb4d8502Sjsg uint32_t dst, src, saved;
1054fb4d8502Sjsg int dptr = *ptr;
1055fb4d8502Sjsg SDEBUG(" dst: ");
1056fb4d8502Sjsg dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
1057fb4d8502Sjsg SDEBUG(" src: ");
1058fb4d8502Sjsg src = atom_get_src(ctx, attr, ptr);
1059fb4d8502Sjsg dst ^= src;
1060fb4d8502Sjsg SDEBUG(" dst: ");
1061fb4d8502Sjsg atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
1062fb4d8502Sjsg }
1063fb4d8502Sjsg
atom_op_debug(atom_exec_context * ctx,int * ptr,int arg)1064fb4d8502Sjsg static void atom_op_debug(atom_exec_context *ctx, int *ptr, int arg)
1065fb4d8502Sjsg {
1066fb4d8502Sjsg uint8_t val = U8((*ptr)++);
1067fb4d8502Sjsg SDEBUG("DEBUG output: 0x%02X\n", val);
1068fb4d8502Sjsg }
1069fb4d8502Sjsg
atom_op_processds(atom_exec_context * ctx,int * ptr,int arg)1070fb4d8502Sjsg static void atom_op_processds(atom_exec_context *ctx, int *ptr, int arg)
1071fb4d8502Sjsg {
1072fb4d8502Sjsg uint16_t val = U16(*ptr);
1073fb4d8502Sjsg (*ptr) += val + 2;
1074fb4d8502Sjsg SDEBUG("PROCESSDS output: 0x%02X\n", val);
1075fb4d8502Sjsg }
1076fb4d8502Sjsg
1077fb4d8502Sjsg static struct {
1078fb4d8502Sjsg void (*func) (atom_exec_context *, int *, int);
1079fb4d8502Sjsg int arg;
1080fb4d8502Sjsg } opcode_table[ATOM_OP_CNT] = {
1081fb4d8502Sjsg {
1082fb4d8502Sjsg NULL, 0}, {
1083fb4d8502Sjsg atom_op_move, ATOM_ARG_REG}, {
1084fb4d8502Sjsg atom_op_move, ATOM_ARG_PS}, {
1085fb4d8502Sjsg atom_op_move, ATOM_ARG_WS}, {
1086fb4d8502Sjsg atom_op_move, ATOM_ARG_FB}, {
1087fb4d8502Sjsg atom_op_move, ATOM_ARG_PLL}, {
1088fb4d8502Sjsg atom_op_move, ATOM_ARG_MC}, {
1089fb4d8502Sjsg atom_op_and, ATOM_ARG_REG}, {
1090fb4d8502Sjsg atom_op_and, ATOM_ARG_PS}, {
1091fb4d8502Sjsg atom_op_and, ATOM_ARG_WS}, {
1092fb4d8502Sjsg atom_op_and, ATOM_ARG_FB}, {
1093fb4d8502Sjsg atom_op_and, ATOM_ARG_PLL}, {
1094fb4d8502Sjsg atom_op_and, ATOM_ARG_MC}, {
1095fb4d8502Sjsg atom_op_or, ATOM_ARG_REG}, {
1096fb4d8502Sjsg atom_op_or, ATOM_ARG_PS}, {
1097fb4d8502Sjsg atom_op_or, ATOM_ARG_WS}, {
1098fb4d8502Sjsg atom_op_or, ATOM_ARG_FB}, {
1099fb4d8502Sjsg atom_op_or, ATOM_ARG_PLL}, {
1100fb4d8502Sjsg atom_op_or, ATOM_ARG_MC}, {
1101fb4d8502Sjsg atom_op_shift_left, ATOM_ARG_REG}, {
1102fb4d8502Sjsg atom_op_shift_left, ATOM_ARG_PS}, {
1103fb4d8502Sjsg atom_op_shift_left, ATOM_ARG_WS}, {
1104fb4d8502Sjsg atom_op_shift_left, ATOM_ARG_FB}, {
1105fb4d8502Sjsg atom_op_shift_left, ATOM_ARG_PLL}, {
1106fb4d8502Sjsg atom_op_shift_left, ATOM_ARG_MC}, {
1107fb4d8502Sjsg atom_op_shift_right, ATOM_ARG_REG}, {
1108fb4d8502Sjsg atom_op_shift_right, ATOM_ARG_PS}, {
1109fb4d8502Sjsg atom_op_shift_right, ATOM_ARG_WS}, {
1110fb4d8502Sjsg atom_op_shift_right, ATOM_ARG_FB}, {
1111fb4d8502Sjsg atom_op_shift_right, ATOM_ARG_PLL}, {
1112fb4d8502Sjsg atom_op_shift_right, ATOM_ARG_MC}, {
1113fb4d8502Sjsg atom_op_mul, ATOM_ARG_REG}, {
1114fb4d8502Sjsg atom_op_mul, ATOM_ARG_PS}, {
1115fb4d8502Sjsg atom_op_mul, ATOM_ARG_WS}, {
1116fb4d8502Sjsg atom_op_mul, ATOM_ARG_FB}, {
1117fb4d8502Sjsg atom_op_mul, ATOM_ARG_PLL}, {
1118fb4d8502Sjsg atom_op_mul, ATOM_ARG_MC}, {
1119fb4d8502Sjsg atom_op_div, ATOM_ARG_REG}, {
1120fb4d8502Sjsg atom_op_div, ATOM_ARG_PS}, {
1121fb4d8502Sjsg atom_op_div, ATOM_ARG_WS}, {
1122fb4d8502Sjsg atom_op_div, ATOM_ARG_FB}, {
1123fb4d8502Sjsg atom_op_div, ATOM_ARG_PLL}, {
1124fb4d8502Sjsg atom_op_div, ATOM_ARG_MC}, {
1125fb4d8502Sjsg atom_op_add, ATOM_ARG_REG}, {
1126fb4d8502Sjsg atom_op_add, ATOM_ARG_PS}, {
1127fb4d8502Sjsg atom_op_add, ATOM_ARG_WS}, {
1128fb4d8502Sjsg atom_op_add, ATOM_ARG_FB}, {
1129fb4d8502Sjsg atom_op_add, ATOM_ARG_PLL}, {
1130fb4d8502Sjsg atom_op_add, ATOM_ARG_MC}, {
1131fb4d8502Sjsg atom_op_sub, ATOM_ARG_REG}, {
1132fb4d8502Sjsg atom_op_sub, ATOM_ARG_PS}, {
1133fb4d8502Sjsg atom_op_sub, ATOM_ARG_WS}, {
1134fb4d8502Sjsg atom_op_sub, ATOM_ARG_FB}, {
1135fb4d8502Sjsg atom_op_sub, ATOM_ARG_PLL}, {
1136fb4d8502Sjsg atom_op_sub, ATOM_ARG_MC}, {
1137fb4d8502Sjsg atom_op_setport, ATOM_PORT_ATI}, {
1138fb4d8502Sjsg atom_op_setport, ATOM_PORT_PCI}, {
1139fb4d8502Sjsg atom_op_setport, ATOM_PORT_SYSIO}, {
1140fb4d8502Sjsg atom_op_setregblock, 0}, {
1141fb4d8502Sjsg atom_op_setfbbase, 0}, {
1142fb4d8502Sjsg atom_op_compare, ATOM_ARG_REG}, {
1143fb4d8502Sjsg atom_op_compare, ATOM_ARG_PS}, {
1144fb4d8502Sjsg atom_op_compare, ATOM_ARG_WS}, {
1145fb4d8502Sjsg atom_op_compare, ATOM_ARG_FB}, {
1146fb4d8502Sjsg atom_op_compare, ATOM_ARG_PLL}, {
1147fb4d8502Sjsg atom_op_compare, ATOM_ARG_MC}, {
1148fb4d8502Sjsg atom_op_switch, 0}, {
1149fb4d8502Sjsg atom_op_jump, ATOM_COND_ALWAYS}, {
1150fb4d8502Sjsg atom_op_jump, ATOM_COND_EQUAL}, {
1151fb4d8502Sjsg atom_op_jump, ATOM_COND_BELOW}, {
1152fb4d8502Sjsg atom_op_jump, ATOM_COND_ABOVE}, {
1153fb4d8502Sjsg atom_op_jump, ATOM_COND_BELOWOREQUAL}, {
1154fb4d8502Sjsg atom_op_jump, ATOM_COND_ABOVEOREQUAL}, {
1155fb4d8502Sjsg atom_op_jump, ATOM_COND_NOTEQUAL}, {
1156fb4d8502Sjsg atom_op_test, ATOM_ARG_REG}, {
1157fb4d8502Sjsg atom_op_test, ATOM_ARG_PS}, {
1158fb4d8502Sjsg atom_op_test, ATOM_ARG_WS}, {
1159fb4d8502Sjsg atom_op_test, ATOM_ARG_FB}, {
1160fb4d8502Sjsg atom_op_test, ATOM_ARG_PLL}, {
1161fb4d8502Sjsg atom_op_test, ATOM_ARG_MC}, {
1162fb4d8502Sjsg atom_op_delay, ATOM_UNIT_MILLISEC}, {
1163fb4d8502Sjsg atom_op_delay, ATOM_UNIT_MICROSEC}, {
1164fb4d8502Sjsg atom_op_calltable, 0}, {
1165fb4d8502Sjsg atom_op_repeat, 0}, {
1166fb4d8502Sjsg atom_op_clear, ATOM_ARG_REG}, {
1167fb4d8502Sjsg atom_op_clear, ATOM_ARG_PS}, {
1168fb4d8502Sjsg atom_op_clear, ATOM_ARG_WS}, {
1169fb4d8502Sjsg atom_op_clear, ATOM_ARG_FB}, {
1170fb4d8502Sjsg atom_op_clear, ATOM_ARG_PLL}, {
1171fb4d8502Sjsg atom_op_clear, ATOM_ARG_MC}, {
1172fb4d8502Sjsg atom_op_nop, 0}, {
1173fb4d8502Sjsg atom_op_eot, 0}, {
1174fb4d8502Sjsg atom_op_mask, ATOM_ARG_REG}, {
1175fb4d8502Sjsg atom_op_mask, ATOM_ARG_PS}, {
1176fb4d8502Sjsg atom_op_mask, ATOM_ARG_WS}, {
1177fb4d8502Sjsg atom_op_mask, ATOM_ARG_FB}, {
1178fb4d8502Sjsg atom_op_mask, ATOM_ARG_PLL}, {
1179fb4d8502Sjsg atom_op_mask, ATOM_ARG_MC}, {
1180fb4d8502Sjsg atom_op_postcard, 0}, {
1181fb4d8502Sjsg atom_op_beep, 0}, {
1182fb4d8502Sjsg atom_op_savereg, 0}, {
1183fb4d8502Sjsg atom_op_restorereg, 0}, {
1184fb4d8502Sjsg atom_op_setdatablock, 0}, {
1185fb4d8502Sjsg atom_op_xor, ATOM_ARG_REG}, {
1186fb4d8502Sjsg atom_op_xor, ATOM_ARG_PS}, {
1187fb4d8502Sjsg atom_op_xor, ATOM_ARG_WS}, {
1188fb4d8502Sjsg atom_op_xor, ATOM_ARG_FB}, {
1189fb4d8502Sjsg atom_op_xor, ATOM_ARG_PLL}, {
1190fb4d8502Sjsg atom_op_xor, ATOM_ARG_MC}, {
1191fb4d8502Sjsg atom_op_shl, ATOM_ARG_REG}, {
1192fb4d8502Sjsg atom_op_shl, ATOM_ARG_PS}, {
1193fb4d8502Sjsg atom_op_shl, ATOM_ARG_WS}, {
1194fb4d8502Sjsg atom_op_shl, ATOM_ARG_FB}, {
1195fb4d8502Sjsg atom_op_shl, ATOM_ARG_PLL}, {
1196fb4d8502Sjsg atom_op_shl, ATOM_ARG_MC}, {
1197fb4d8502Sjsg atom_op_shr, ATOM_ARG_REG}, {
1198fb4d8502Sjsg atom_op_shr, ATOM_ARG_PS}, {
1199fb4d8502Sjsg atom_op_shr, ATOM_ARG_WS}, {
1200fb4d8502Sjsg atom_op_shr, ATOM_ARG_FB}, {
1201fb4d8502Sjsg atom_op_shr, ATOM_ARG_PLL}, {
1202fb4d8502Sjsg atom_op_shr, ATOM_ARG_MC}, {
1203fb4d8502Sjsg atom_op_debug, 0}, {
1204fb4d8502Sjsg atom_op_processds, 0}, {
1205fb4d8502Sjsg atom_op_mul32, ATOM_ARG_PS}, {
1206fb4d8502Sjsg atom_op_mul32, ATOM_ARG_WS}, {
1207fb4d8502Sjsg atom_op_div32, ATOM_ARG_PS}, {
1208fb4d8502Sjsg atom_op_div32, ATOM_ARG_WS},
1209fb4d8502Sjsg };
1210fb4d8502Sjsg
amdgpu_atom_execute_table_locked(struct atom_context * ctx,int index,uint32_t * params)1211fb4d8502Sjsg static int amdgpu_atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t *params)
1212fb4d8502Sjsg {
1213fb4d8502Sjsg int base = CU16(ctx->cmd_table + 4 + 2 * index);
1214fb4d8502Sjsg int len, ws, ps, ptr;
1215fb4d8502Sjsg unsigned char op;
1216fb4d8502Sjsg atom_exec_context ectx;
1217fb4d8502Sjsg int ret = 0;
1218fb4d8502Sjsg
1219fb4d8502Sjsg if (!base)
1220fb4d8502Sjsg return -EINVAL;
1221fb4d8502Sjsg
1222fb4d8502Sjsg len = CU16(base + ATOM_CT_SIZE_PTR);
1223fb4d8502Sjsg ws = CU8(base + ATOM_CT_WS_PTR);
1224fb4d8502Sjsg ps = CU8(base + ATOM_CT_PS_PTR) & ATOM_CT_PS_MASK;
1225fb4d8502Sjsg ptr = base + ATOM_CT_CODE_PTR;
1226fb4d8502Sjsg
1227fb4d8502Sjsg SDEBUG(">> execute %04X (len %d, WS %d, PS %d)\n", base, len, ws, ps);
1228fb4d8502Sjsg
1229fb4d8502Sjsg ectx.ctx = ctx;
1230fb4d8502Sjsg ectx.ps_shift = ps / 4;
1231fb4d8502Sjsg ectx.start = base;
1232fb4d8502Sjsg ectx.ps = params;
1233fb4d8502Sjsg ectx.abort = false;
1234fb4d8502Sjsg ectx.last_jump = 0;
1235fb4d8502Sjsg if (ws)
1236fb4d8502Sjsg ectx.ws = kcalloc(4, ws, GFP_KERNEL);
1237fb4d8502Sjsg else
1238fb4d8502Sjsg ectx.ws = NULL;
1239fb4d8502Sjsg
1240fb4d8502Sjsg debug_depth++;
1241fb4d8502Sjsg while (1) {
1242fb4d8502Sjsg op = CU8(ptr++);
1243fb4d8502Sjsg if (op < ATOM_OP_NAMES_CNT)
1244fb4d8502Sjsg SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr - 1);
1245fb4d8502Sjsg else
1246fb4d8502Sjsg SDEBUG("[%d] @ 0x%04X\n", op, ptr - 1);
1247fb4d8502Sjsg if (ectx.abort) {
1248fb4d8502Sjsg DRM_ERROR("atombios stuck executing %04X (len %d, WS %d, PS %d) @ 0x%04X\n",
1249fb4d8502Sjsg base, len, ws, ps, ptr - 1);
1250fb4d8502Sjsg ret = -EINVAL;
1251fb4d8502Sjsg goto free;
1252fb4d8502Sjsg }
1253fb4d8502Sjsg
1254fb4d8502Sjsg if (op < ATOM_OP_CNT && op > 0)
1255fb4d8502Sjsg opcode_table[op].func(&ectx, &ptr,
1256fb4d8502Sjsg opcode_table[op].arg);
1257fb4d8502Sjsg else
1258fb4d8502Sjsg break;
1259fb4d8502Sjsg
1260fb4d8502Sjsg if (op == ATOM_OP_EOT)
1261fb4d8502Sjsg break;
1262fb4d8502Sjsg }
1263fb4d8502Sjsg debug_depth--;
1264fb4d8502Sjsg SDEBUG("<<\n");
1265fb4d8502Sjsg
1266fb4d8502Sjsg free:
1267fb4d8502Sjsg if (ws)
1268fb4d8502Sjsg kfree(ectx.ws);
1269fb4d8502Sjsg return ret;
1270fb4d8502Sjsg }
1271fb4d8502Sjsg
amdgpu_atom_execute_table(struct atom_context * ctx,int index,uint32_t * params)1272fb4d8502Sjsg int amdgpu_atom_execute_table(struct atom_context *ctx, int index, uint32_t *params)
1273fb4d8502Sjsg {
1274fb4d8502Sjsg int r;
1275fb4d8502Sjsg
1276fb4d8502Sjsg mutex_lock(&ctx->mutex);
1277fb4d8502Sjsg /* reset data block */
1278fb4d8502Sjsg ctx->data_block = 0;
1279fb4d8502Sjsg /* reset reg block */
1280fb4d8502Sjsg ctx->reg_block = 0;
1281fb4d8502Sjsg /* reset fb window */
1282fb4d8502Sjsg ctx->fb_base = 0;
1283fb4d8502Sjsg /* reset io mode */
1284fb4d8502Sjsg ctx->io_mode = ATOM_IO_MM;
1285fb4d8502Sjsg /* reset divmul */
1286fb4d8502Sjsg ctx->divmul[0] = 0;
1287fb4d8502Sjsg ctx->divmul[1] = 0;
1288fb4d8502Sjsg r = amdgpu_atom_execute_table_locked(ctx, index, params);
1289fb4d8502Sjsg mutex_unlock(&ctx->mutex);
1290fb4d8502Sjsg return r;
1291fb4d8502Sjsg }
1292fb4d8502Sjsg
1293fb4d8502Sjsg static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 };
1294fb4d8502Sjsg
atom_index_iio(struct atom_context * ctx,int base)1295fb4d8502Sjsg static void atom_index_iio(struct atom_context *ctx, int base)
1296fb4d8502Sjsg {
1297fb4d8502Sjsg ctx->iio = kzalloc(2 * 256, GFP_KERNEL);
1298fb4d8502Sjsg if (!ctx->iio)
1299fb4d8502Sjsg return;
1300fb4d8502Sjsg while (CU8(base) == ATOM_IIO_START) {
1301fb4d8502Sjsg ctx->iio[CU8(base + 1)] = base + 2;
1302fb4d8502Sjsg base += 2;
1303fb4d8502Sjsg while (CU8(base) != ATOM_IIO_END)
1304fb4d8502Sjsg base += atom_iio_len[CU8(base)];
1305fb4d8502Sjsg base += 3;
1306fb4d8502Sjsg }
1307fb4d8502Sjsg }
1308fb4d8502Sjsg
atom_get_vbios_name(struct atom_context * ctx)13095ca02815Sjsg static void atom_get_vbios_name(struct atom_context *ctx)
13105ca02815Sjsg {
13115ca02815Sjsg unsigned char *p_rom;
13125ca02815Sjsg unsigned char str_num;
13135ca02815Sjsg unsigned short off_to_vbios_str;
13145ca02815Sjsg unsigned char *c_ptr;
13155ca02815Sjsg int name_size;
13165ca02815Sjsg int i;
13175ca02815Sjsg
13185ca02815Sjsg const char *na = "--N/A--";
13195ca02815Sjsg char *back;
13205ca02815Sjsg
13215ca02815Sjsg p_rom = ctx->bios;
13225ca02815Sjsg
13235ca02815Sjsg str_num = *(p_rom + OFFSET_TO_GET_ATOMBIOS_NUMBER_OF_STRINGS);
13245ca02815Sjsg if (str_num != 0) {
13255ca02815Sjsg off_to_vbios_str =
13265ca02815Sjsg *(unsigned short *)(p_rom + OFFSET_TO_GET_ATOMBIOS_STRING_START);
13275ca02815Sjsg
13285ca02815Sjsg c_ptr = (unsigned char *)(p_rom + off_to_vbios_str);
13295ca02815Sjsg } else {
13305ca02815Sjsg /* do not know where to find name */
13315ca02815Sjsg memcpy(ctx->name, na, 7);
13325ca02815Sjsg ctx->name[7] = 0;
13335ca02815Sjsg return;
13345ca02815Sjsg }
13355ca02815Sjsg
13365ca02815Sjsg /*
13375ca02815Sjsg * skip the atombios strings, usually 4
13385ca02815Sjsg * 1st is P/N, 2nd is ASIC, 3rd is PCI type, 4th is Memory type
13395ca02815Sjsg */
13405ca02815Sjsg for (i = 0; i < str_num; i++) {
13415ca02815Sjsg while (*c_ptr != 0)
13425ca02815Sjsg c_ptr++;
13435ca02815Sjsg c_ptr++;
13445ca02815Sjsg }
13455ca02815Sjsg
13465ca02815Sjsg /* skip the following 2 chars: 0x0D 0x0A */
13475ca02815Sjsg c_ptr += 2;
13485ca02815Sjsg
13495ca02815Sjsg name_size = strnlen(c_ptr, STRLEN_LONG - 1);
13505ca02815Sjsg memcpy(ctx->name, c_ptr, name_size);
13515ca02815Sjsg back = ctx->name + name_size;
13525ca02815Sjsg while ((*--back) == ' ')
13535ca02815Sjsg ;
13545ca02815Sjsg *(back + 1) = '\0';
13555ca02815Sjsg }
13565ca02815Sjsg
atom_get_vbios_date(struct atom_context * ctx)13575ca02815Sjsg static void atom_get_vbios_date(struct atom_context *ctx)
13585ca02815Sjsg {
13595ca02815Sjsg unsigned char *p_rom;
13605ca02815Sjsg unsigned char *date_in_rom;
13615ca02815Sjsg
13625ca02815Sjsg p_rom = ctx->bios;
13635ca02815Sjsg
13645ca02815Sjsg date_in_rom = p_rom + OFFSET_TO_VBIOS_DATE;
13655ca02815Sjsg
13665ca02815Sjsg ctx->date[0] = '2';
13675ca02815Sjsg ctx->date[1] = '0';
13685ca02815Sjsg ctx->date[2] = date_in_rom[6];
13695ca02815Sjsg ctx->date[3] = date_in_rom[7];
13705ca02815Sjsg ctx->date[4] = '/';
13715ca02815Sjsg ctx->date[5] = date_in_rom[0];
13725ca02815Sjsg ctx->date[6] = date_in_rom[1];
13735ca02815Sjsg ctx->date[7] = '/';
13745ca02815Sjsg ctx->date[8] = date_in_rom[3];
13755ca02815Sjsg ctx->date[9] = date_in_rom[4];
13765ca02815Sjsg ctx->date[10] = ' ';
13775ca02815Sjsg ctx->date[11] = date_in_rom[9];
13785ca02815Sjsg ctx->date[12] = date_in_rom[10];
13795ca02815Sjsg ctx->date[13] = date_in_rom[11];
13805ca02815Sjsg ctx->date[14] = date_in_rom[12];
13815ca02815Sjsg ctx->date[15] = date_in_rom[13];
13825ca02815Sjsg ctx->date[16] = '\0';
13835ca02815Sjsg }
13845ca02815Sjsg
atom_find_str_in_rom(struct atom_context * ctx,char * str,int start,int end,int maxlen)13855ca02815Sjsg static unsigned char *atom_find_str_in_rom(struct atom_context *ctx, char *str, int start,
13865ca02815Sjsg int end, int maxlen)
13875ca02815Sjsg {
13885ca02815Sjsg unsigned long str_off;
13895ca02815Sjsg unsigned char *p_rom;
13905ca02815Sjsg unsigned short str_len;
13915ca02815Sjsg
13925ca02815Sjsg str_off = 0;
13935ca02815Sjsg str_len = strnlen(str, maxlen);
13945ca02815Sjsg p_rom = ctx->bios;
13955ca02815Sjsg
13965ca02815Sjsg for (; start <= end; ++start) {
13975ca02815Sjsg for (str_off = 0; str_off < str_len; ++str_off) {
13985ca02815Sjsg if (str[str_off] != *(p_rom + start + str_off))
13995ca02815Sjsg break;
14005ca02815Sjsg }
14015ca02815Sjsg
14025ca02815Sjsg if (str_off == str_len || str[str_off] == 0)
14035ca02815Sjsg return p_rom + start;
14045ca02815Sjsg }
14055ca02815Sjsg return NULL;
14065ca02815Sjsg }
14075ca02815Sjsg
atom_get_vbios_pn(struct atom_context * ctx)14085ca02815Sjsg static void atom_get_vbios_pn(struct atom_context *ctx)
14095ca02815Sjsg {
14105ca02815Sjsg unsigned char *p_rom;
14115ca02815Sjsg unsigned short off_to_vbios_str;
14125ca02815Sjsg unsigned char *vbios_str;
14135ca02815Sjsg int count;
14145ca02815Sjsg
14155ca02815Sjsg off_to_vbios_str = 0;
14165ca02815Sjsg p_rom = ctx->bios;
14175ca02815Sjsg
14185ca02815Sjsg if (*(p_rom + OFFSET_TO_GET_ATOMBIOS_NUMBER_OF_STRINGS) != 0) {
14195ca02815Sjsg off_to_vbios_str =
14205ca02815Sjsg *(unsigned short *)(p_rom + OFFSET_TO_GET_ATOMBIOS_STRING_START);
14215ca02815Sjsg
14225ca02815Sjsg vbios_str = (unsigned char *)(p_rom + off_to_vbios_str);
14235ca02815Sjsg } else {
14245ca02815Sjsg vbios_str = p_rom + OFFSET_TO_VBIOS_PART_NUMBER;
14255ca02815Sjsg }
14265ca02815Sjsg
14275ca02815Sjsg if (*vbios_str == 0) {
14285ca02815Sjsg vbios_str = atom_find_str_in_rom(ctx, BIOS_ATOM_PREFIX, 3, 1024, 64);
14295ca02815Sjsg if (vbios_str == NULL)
14305ca02815Sjsg vbios_str += sizeof(BIOS_ATOM_PREFIX) - 1;
14315ca02815Sjsg }
14325ca02815Sjsg if (vbios_str != NULL && *vbios_str == 0)
14335ca02815Sjsg vbios_str++;
14345ca02815Sjsg
14355ca02815Sjsg if (vbios_str != NULL) {
14365ca02815Sjsg count = 0;
14375ca02815Sjsg while ((count < BIOS_STRING_LENGTH) && vbios_str[count] >= ' ' &&
14385ca02815Sjsg vbios_str[count] <= 'z') {
14395ca02815Sjsg ctx->vbios_pn[count] = vbios_str[count];
14405ca02815Sjsg count++;
14415ca02815Sjsg }
14425ca02815Sjsg
14435ca02815Sjsg ctx->vbios_pn[count] = 0;
14445ca02815Sjsg }
1445f005ef32Sjsg
1446f005ef32Sjsg pr_info("ATOM BIOS: %s\n", ctx->vbios_pn);
14475ca02815Sjsg }
14485ca02815Sjsg
atom_get_vbios_version(struct atom_context * ctx)14495ca02815Sjsg static void atom_get_vbios_version(struct atom_context *ctx)
14505ca02815Sjsg {
14515ca02815Sjsg unsigned char *vbios_ver;
14525ca02815Sjsg
14535ca02815Sjsg /* find anchor ATOMBIOSBK-AMD */
14545ca02815Sjsg vbios_ver = atom_find_str_in_rom(ctx, BIOS_VERSION_PREFIX, 3, 1024, 64);
14555ca02815Sjsg if (vbios_ver != NULL) {
14565ca02815Sjsg /* skip ATOMBIOSBK-AMD VER */
14575ca02815Sjsg vbios_ver += 18;
14585ca02815Sjsg memcpy(ctx->vbios_ver_str, vbios_ver, STRLEN_NORMAL);
14595ca02815Sjsg } else {
14605ca02815Sjsg ctx->vbios_ver_str[0] = '\0';
14615ca02815Sjsg }
14625ca02815Sjsg }
14635ca02815Sjsg
amdgpu_atom_parse(struct card_info * card,void * bios)1464fb4d8502Sjsg struct atom_context *amdgpu_atom_parse(struct card_info *card, void *bios)
1465fb4d8502Sjsg {
1466fb4d8502Sjsg int base;
1467fb4d8502Sjsg struct atom_context *ctx =
1468fb4d8502Sjsg kzalloc(sizeof(struct atom_context), GFP_KERNEL);
14695ca02815Sjsg struct _ATOM_ROM_HEADER *atom_rom_header;
14705ca02815Sjsg struct _ATOM_MASTER_DATA_TABLE *master_table;
14715ca02815Sjsg struct _ATOM_FIRMWARE_INFO *atom_fw_info;
1472fb4d8502Sjsg
1473fb4d8502Sjsg if (!ctx)
1474fb4d8502Sjsg return NULL;
1475fb4d8502Sjsg
1476fb4d8502Sjsg ctx->card = card;
1477fb4d8502Sjsg ctx->bios = bios;
1478fb4d8502Sjsg
1479fb4d8502Sjsg if (CU16(0) != ATOM_BIOS_MAGIC) {
1480fb4d8502Sjsg pr_info("Invalid BIOS magic\n");
1481fb4d8502Sjsg kfree(ctx);
1482fb4d8502Sjsg return NULL;
1483fb4d8502Sjsg }
1484fb4d8502Sjsg if (strncmp
1485fb4d8502Sjsg (CSTR(ATOM_ATI_MAGIC_PTR), ATOM_ATI_MAGIC,
1486fb4d8502Sjsg strlen(ATOM_ATI_MAGIC))) {
1487fb4d8502Sjsg pr_info("Invalid ATI magic\n");
1488fb4d8502Sjsg kfree(ctx);
1489fb4d8502Sjsg return NULL;
1490fb4d8502Sjsg }
1491fb4d8502Sjsg
1492fb4d8502Sjsg base = CU16(ATOM_ROM_TABLE_PTR);
1493fb4d8502Sjsg if (strncmp
1494fb4d8502Sjsg (CSTR(base + ATOM_ROM_MAGIC_PTR), ATOM_ROM_MAGIC,
1495fb4d8502Sjsg strlen(ATOM_ROM_MAGIC))) {
1496fb4d8502Sjsg pr_info("Invalid ATOM magic\n");
1497fb4d8502Sjsg kfree(ctx);
1498fb4d8502Sjsg return NULL;
1499fb4d8502Sjsg }
1500fb4d8502Sjsg
1501fb4d8502Sjsg ctx->cmd_table = CU16(base + ATOM_ROM_CMD_PTR);
1502fb4d8502Sjsg ctx->data_table = CU16(base + ATOM_ROM_DATA_PTR);
1503fb4d8502Sjsg atom_index_iio(ctx, CU16(ctx->data_table + ATOM_DATA_IIO_PTR) + 4);
1504fb4d8502Sjsg if (!ctx->iio) {
1505fb4d8502Sjsg amdgpu_atom_destroy(ctx);
1506fb4d8502Sjsg return NULL;
1507fb4d8502Sjsg }
1508fb4d8502Sjsg
15095ca02815Sjsg atom_rom_header = (struct _ATOM_ROM_HEADER *)CSTR(base);
15105ca02815Sjsg if (atom_rom_header->usMasterDataTableOffset != 0) {
15115ca02815Sjsg master_table = (struct _ATOM_MASTER_DATA_TABLE *)
15125ca02815Sjsg CSTR(atom_rom_header->usMasterDataTableOffset);
15135ca02815Sjsg if (master_table->ListOfDataTables.FirmwareInfo != 0) {
15145ca02815Sjsg atom_fw_info = (struct _ATOM_FIRMWARE_INFO *)
15155ca02815Sjsg CSTR(master_table->ListOfDataTables.FirmwareInfo);
15165ca02815Sjsg ctx->version = atom_fw_info->ulFirmwareRevision;
15175ca02815Sjsg }
15185ca02815Sjsg }
15195ca02815Sjsg
15205ca02815Sjsg atom_get_vbios_name(ctx);
15215ca02815Sjsg atom_get_vbios_pn(ctx);
15225ca02815Sjsg atom_get_vbios_date(ctx);
15235ca02815Sjsg atom_get_vbios_version(ctx);
1524fb4d8502Sjsg
1525fb4d8502Sjsg return ctx;
1526fb4d8502Sjsg }
1527fb4d8502Sjsg
amdgpu_atom_asic_init(struct atom_context * ctx)1528fb4d8502Sjsg int amdgpu_atom_asic_init(struct atom_context *ctx)
1529fb4d8502Sjsg {
1530fb4d8502Sjsg int hwi = CU16(ctx->data_table + ATOM_DATA_FWI_PTR);
1531fb4d8502Sjsg uint32_t ps[16];
1532fb4d8502Sjsg int ret;
1533fb4d8502Sjsg
1534fb4d8502Sjsg memset(ps, 0, 64);
1535fb4d8502Sjsg
1536fb4d8502Sjsg ps[0] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFSCLK_PTR));
1537fb4d8502Sjsg ps[1] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFMCLK_PTR));
1538fb4d8502Sjsg if (!ps[0] || !ps[1])
1539fb4d8502Sjsg return 1;
1540fb4d8502Sjsg
1541fb4d8502Sjsg if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT))
1542fb4d8502Sjsg return 1;
1543fb4d8502Sjsg ret = amdgpu_atom_execute_table(ctx, ATOM_CMD_INIT, ps);
1544fb4d8502Sjsg if (ret)
1545fb4d8502Sjsg return ret;
1546fb4d8502Sjsg
1547fb4d8502Sjsg memset(ps, 0, 64);
1548fb4d8502Sjsg
1549fb4d8502Sjsg return ret;
1550fb4d8502Sjsg }
1551fb4d8502Sjsg
amdgpu_atom_destroy(struct atom_context * ctx)1552fb4d8502Sjsg void amdgpu_atom_destroy(struct atom_context *ctx)
1553fb4d8502Sjsg {
1554fb4d8502Sjsg kfree(ctx->iio);
1555fb4d8502Sjsg kfree(ctx);
1556fb4d8502Sjsg }
1557fb4d8502Sjsg
amdgpu_atom_parse_data_header(struct atom_context * ctx,int index,uint16_t * size,uint8_t * frev,uint8_t * crev,uint16_t * data_start)1558fb4d8502Sjsg bool amdgpu_atom_parse_data_header(struct atom_context *ctx, int index,
1559fb4d8502Sjsg uint16_t *size, uint8_t *frev, uint8_t *crev,
1560fb4d8502Sjsg uint16_t *data_start)
1561fb4d8502Sjsg {
1562fb4d8502Sjsg int offset = index * 2 + 4;
1563fb4d8502Sjsg int idx = CU16(ctx->data_table + offset);
1564fb4d8502Sjsg u16 *mdt = (u16 *)(ctx->bios + ctx->data_table + 4);
1565fb4d8502Sjsg
1566fb4d8502Sjsg if (!mdt[index])
1567fb4d8502Sjsg return false;
1568fb4d8502Sjsg
1569fb4d8502Sjsg if (size)
1570fb4d8502Sjsg *size = CU16(idx);
1571fb4d8502Sjsg if (frev)
1572fb4d8502Sjsg *frev = CU8(idx + 2);
1573fb4d8502Sjsg if (crev)
1574fb4d8502Sjsg *crev = CU8(idx + 3);
1575fb4d8502Sjsg *data_start = idx;
1576fb4d8502Sjsg return true;
1577fb4d8502Sjsg }
1578fb4d8502Sjsg
amdgpu_atom_parse_cmd_header(struct atom_context * ctx,int index,uint8_t * frev,uint8_t * crev)1579fb4d8502Sjsg bool amdgpu_atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t *frev,
1580fb4d8502Sjsg uint8_t *crev)
1581fb4d8502Sjsg {
1582fb4d8502Sjsg int offset = index * 2 + 4;
1583fb4d8502Sjsg int idx = CU16(ctx->cmd_table + offset);
1584fb4d8502Sjsg u16 *mct = (u16 *)(ctx->bios + ctx->cmd_table + 4);
1585fb4d8502Sjsg
1586fb4d8502Sjsg if (!mct[index])
1587fb4d8502Sjsg return false;
1588fb4d8502Sjsg
1589fb4d8502Sjsg if (frev)
1590fb4d8502Sjsg *frev = CU8(idx + 2);
1591fb4d8502Sjsg if (crev)
1592fb4d8502Sjsg *crev = CU8(idx + 3);
1593fb4d8502Sjsg return true;
1594fb4d8502Sjsg }
1595fb4d8502Sjsg
1596