24,6 → 24,7 |
|
#include <linux/module.h> |
#include <linux/sched.h> |
#include <linux/slab.h> |
#include <asm/unaligned.h> |
|
#define ATOM_DEBUG |
31,6 → 32,7 |
#include "atom.h" |
#include "atom-names.h" |
#include "atom-bits.h" |
#include "radeon.h" |
|
#define ATOM_COND_ABOVE 0 |
#define ATOM_COND_ABOVEOREQUAL 1 |
52,15 → 54,17 |
|
typedef struct { |
struct atom_context *ctx; |
|
uint32_t *ps, *ws; |
int ps_shift; |
uint16_t start; |
unsigned last_jump; |
unsigned long last_jump_jiffies; |
bool abort; |
} atom_exec_context; |
|
int atom_debug = 0; |
static void atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params); |
void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params); |
static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params); |
int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params); |
|
static uint32_t atom_arg_mask[8] = |
{ 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000, |
98,7 → 102,9 |
static uint32_t atom_iio_execute(struct atom_context *ctx, int base, |
uint32_t index, uint32_t data) |
{ |
struct radeon_device *rdev = ctx->card->dev->dev_private; |
uint32_t temp = 0xCDCDCDCD; |
|
while (1) |
switch (CU8(base)) { |
case ATOM_IIO_NOP: |
105,12 → 111,13 |
base++; |
break; |
case ATOM_IIO_READ: |
temp = ctx->card->reg_read(ctx->card, CU16(base + 1)); |
temp = ctx->card->ioreg_read(ctx->card, CU16(base + 1)); |
base += 3; |
break; |
case ATOM_IIO_WRITE: |
(void)ctx->card->reg_read(ctx->card, CU16(base + 1)); |
ctx->card->reg_write(ctx->card, CU16(base + 1), temp); |
if (rdev->family == CHIP_RV515) |
(void)ctx->card->ioreg_read(ctx->card, CU16(base + 1)); |
ctx->card->ioreg_write(ctx->card, CU16(base + 1), temp); |
base += 3; |
break; |
case ATOM_IIO_CLEAR: |
128,7 → 135,7 |
case ATOM_IIO_MOVE_INDEX: |
temp &= |
~((0xFFFFFFFF >> (32 - CU8(base + 1))) << |
CU8(base + 2)); |
CU8(base + 3)); |
temp |= |
((index >> CU8(base + 2)) & |
(0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base + |
138,7 → 145,7 |
case ATOM_IIO_MOVE_DATA: |
temp &= |
~((0xFFFFFFFF >> (32 - CU8(base + 1))) << |
CU8(base + 2)); |
CU8(base + 3)); |
temp |= |
((data >> CU8(base + 2)) & |
(0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base + |
148,7 → 155,7 |
case ATOM_IIO_MOVE_ATTR: |
temp &= |
~((0xFFFFFFFF >> (32 - CU8(base + 1))) << |
CU8(base + 2)); |
CU8(base + 3)); |
temp |= |
((ctx-> |
io_attr >> CU8(base + 2)) & (0xFFFFFFFF >> (32 - |
604,12 → 611,17 |
static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg) |
{ |
int idx = U8((*ptr)++); |
int r = 0; |
|
if (idx < ATOM_TABLE_NAMES_CNT) |
SDEBUG(" table: %d (%s)\n", idx, atom_table_names[idx]); |
else |
SDEBUG(" table: %d\n", idx); |
if (U16(ctx->ctx->cmd_table + 4 + 2 * idx)) |
atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift); |
r = atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift); |
if (r) { |
ctx->abort = true; |
} |
} |
|
static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg) |
640,12 → 652,12 |
|
static void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg) |
{ |
uint8_t count = U8((*ptr)++); |
unsigned count = U8((*ptr)++); |
SDEBUG(" count: %d\n", count); |
if (arg == ATOM_UNIT_MICROSEC) |
udelay(count); |
else |
mdelay(count); |
msleep(count); |
} |
|
static void atom_op_div(atom_exec_context *ctx, int *ptr, int arg) |
673,6 → 685,8 |
static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg) |
{ |
int execute = 0, target = U16(*ptr); |
unsigned long cjiffies; |
|
(*ptr) += 2; |
switch (arg) { |
case ATOM_COND_ABOVE: |
707,16 → 721,16 |
static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg) |
{ |
uint8_t attr = U8((*ptr)++); |
uint32_t dst, src1, src2, saved; |
uint32_t dst, mask, src, saved; |
int dptr = *ptr; |
SDEBUG(" dst: "); |
dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); |
SDEBUG(" src1: "); |
src1 = atom_get_src_direct(ctx, ((attr >> 3) & 7), ptr); |
SDEBUG(" src2: "); |
src2 = atom_get_src(ctx, attr, ptr); |
dst &= src1; |
dst |= src2; |
mask = atom_get_src_direct(ctx, ((attr >> 3) & 7), ptr); |
SDEBUG(" mask: 0x%08x", mask); |
SDEBUG(" src: "); |
src = atom_get_src(ctx, attr, ptr); |
dst &= mask; |
dst |= src; |
SDEBUG(" dst: "); |
atom_put_dst(ctx, arg, attr, &dptr, dst, saved); |
} |
881,11 → 895,16 |
uint8_t attr = U8((*ptr)++), shift; |
uint32_t saved, dst; |
int dptr = *ptr; |
uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3]; |
SDEBUG(" dst: "); |
dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); |
/* op needs to full dst value */ |
dst = saved; |
shift = atom_get_src(ctx, attr, ptr); |
SDEBUG(" shift: %d\n", shift); |
dst <<= shift; |
dst &= atom_arg_mask[dst_align]; |
dst >>= atom_arg_shift[dst_align]; |
SDEBUG(" dst: "); |
atom_put_dst(ctx, arg, attr, &dptr, dst, saved); |
} |
895,11 → 914,16 |
uint8_t attr = U8((*ptr)++), shift; |
uint32_t saved, dst; |
int dptr = *ptr; |
uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3]; |
SDEBUG(" dst: "); |
dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); |
/* op needs to full dst value */ |
dst = saved; |
shift = atom_get_src(ctx, attr, ptr); |
SDEBUG(" shift: %d\n", shift); |
dst >>= shift; |
dst &= atom_arg_mask[dst_align]; |
dst >>= atom_arg_shift[dst_align]; |
SDEBUG(" dst: "); |
atom_put_dst(ctx, arg, attr, &dptr, dst, saved); |
} |
1104,15 → 1128,16 |
atom_op_shr, ATOM_ARG_MC}, { |
atom_op_debug, 0},}; |
|
static void atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params) |
static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params) |
{ |
int base = CU16(ctx->cmd_table + 4 + 2 * index); |
int len, ws, ps, ptr; |
unsigned char op; |
atom_exec_context ectx; |
int ret = 0; |
|
if (!base) |
return; |
return -EINVAL; |
|
len = CU16(base + ATOM_CT_SIZE_PTR); |
ws = CU8(base + ATOM_CT_WS_PTR); |
1125,6 → 1150,8 |
ectx.ps_shift = ps / 4; |
ectx.start = base; |
ectx.ps = params; |
ectx.abort = false; |
ectx.last_jump = 0; |
if (ws) |
ectx.ws = kzalloc(4 * ws, GFP_KERNEL); |
else |
1137,6 → 1164,12 |
SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr - 1); |
else |
SDEBUG("[%d] @ 0x%04X\n", op, ptr - 1); |
if (ectx.abort) { |
DRM_ERROR("atombios stuck executing %04X (len %d, WS %d, PS %d) @ 0x%04X\n", |
base, len, ws, ps, ptr - 1); |
ret = -EINVAL; |
goto free; |
} |
|
if (op < ATOM_OP_CNT && op > 0) |
opcode_table[op].func(&ectx, &ptr, |
1150,12 → 1183,16 |
debug_depth--; |
SDEBUG("<<\n"); |
|
free: |
if (ws) |
kfree(ectx.ws); |
return ret; |
} |
|
void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params) |
int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params) |
{ |
int r; |
|
mutex_lock(&ctx->mutex); |
/* reset reg block */ |
ctx->reg_block = 0; |
1163,8 → 1200,9 |
ctx->fb_base = 0; |
/* reset io mode */ |
ctx->io_mode = ATOM_IO_MM; |
atom_execute_table_locked(ctx, index, params); |
r = atom_execute_table_locked(ctx, index, params); |
mutex_unlock(&ctx->mutex); |
return r; |
} |
|
static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 }; |
1248,9 → 1286,7 |
|
if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT)) |
return 1; |
atom_execute_table(ctx, ATOM_CMD_INIT, ps); |
|
return 0; |
return atom_execute_table(ctx, ATOM_CMD_INIT, ps); |
} |
|
void atom_destroy(struct atom_context *ctx) |
1260,13 → 1296,17 |
kfree(ctx); |
} |
|
void atom_parse_data_header(struct atom_context *ctx, int index, |
bool atom_parse_data_header(struct atom_context *ctx, int index, |
uint16_t * size, uint8_t * frev, uint8_t * crev, |
uint16_t * data_start) |
{ |
int offset = index * 2 + 4; |
int idx = CU16(ctx->data_table + offset); |
u16 *mdt = (u16 *)(ctx->bios + ctx->data_table + 4); |
|
if (!mdt[index]) |
return false; |
|
if (size) |
*size = CU16(idx); |
if (frev) |
1274,20 → 1314,24 |
if (crev) |
*crev = CU8(idx + 3); |
*data_start = idx; |
return; |
return true; |
} |
|
void atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t * frev, |
bool atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t * frev, |
uint8_t * crev) |
{ |
int offset = index * 2 + 4; |
int idx = CU16(ctx->cmd_table + offset); |
u16 *mct = (u16 *)(ctx->bios + ctx->cmd_table + 4); |
|
if (!mct[index]) |
return false; |
|
if (frev) |
*frev = CU8(idx + 2); |
if (crev) |
*crev = CU8(idx + 3); |
return; |
return true; |
} |
|
int atom_allocate_fb_scratch(struct atom_context *ctx) |
1294,11 → 1338,10 |
{ |
int index = GetIndexIntoMasterTable(DATA, VRAM_UsageByFirmware); |
uint16_t data_offset; |
int usage_bytes; |
int usage_bytes = 0; |
struct _ATOM_VRAM_USAGE_BY_FIRMWARE *firmware_usage; |
|
atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset); |
|
if (atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset)) { |
firmware_usage = (struct _ATOM_VRAM_USAGE_BY_FIRMWARE *)(ctx->bios + data_offset); |
|
DRM_DEBUG("atom firmware requested %08x %dkb\n", |
1306,6 → 1349,7 |
firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb); |
|
usage_bytes = firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb * 1024; |
} |
if (usage_bytes == 0) |
usage_bytes = 20 * 1024; |
/* allocate some scratch memory */ |