Merge remote branch 'nouveau/drm-nouveau-fixes' of /ssd/git/drm-nouveau-next into drm-fixes
* 'nouveau/drm-nouveau-fixes' of /ssd/git/drm-nouveau-next: drm/nvc0: improve vm flush function drm/nv50-nvc0: remove some code that doesn't belong here drm/nv50: use "nv86" tlb flush method on everything except 0x50/0xac drm/nouveau: quirk for XFX GT-240X-YA drm/nv50-nvc0: work around an evo channel hang that some people see drm/nouveau: implement init table opcode 0x5c drm/nouveau: fix oops on unload with disabled LVDS panel nv30: Fix parsing of perf table drm/nouveau: correct memtiming table parsing for nv4x
This commit is contained in:
commit
d85023a3cd
|
@ -269,7 +269,7 @@ struct init_tbl_entry {
|
||||||
int (*handler)(struct nvbios *, uint16_t, struct init_exec *);
|
int (*handler)(struct nvbios *, uint16_t, struct init_exec *);
|
||||||
};
|
};
|
||||||
|
|
||||||
static int parse_init_table(struct nvbios *, unsigned int, struct init_exec *);
|
static int parse_init_table(struct nvbios *, uint16_t, struct init_exec *);
|
||||||
|
|
||||||
#define MACRO_INDEX_SIZE 2
|
#define MACRO_INDEX_SIZE 2
|
||||||
#define MACRO_SIZE 8
|
#define MACRO_SIZE 8
|
||||||
|
@ -2010,6 +2010,27 @@ init_sub_direct(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
init_jump(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* INIT_JUMP opcode: 0x5C ('\')
|
||||||
|
*
|
||||||
|
* offset (8 bit): opcode
|
||||||
|
* offset + 1 (16 bit): offset (in bios)
|
||||||
|
*
|
||||||
|
* Continue execution of init table from 'offset'
|
||||||
|
*/
|
||||||
|
|
||||||
|
uint16_t jmp_offset = ROM16(bios->data[offset + 1]);
|
||||||
|
|
||||||
|
if (!iexec->execute)
|
||||||
|
return 3;
|
||||||
|
|
||||||
|
BIOSLOG(bios, "0x%04X: Jump to 0x%04X\n", offset, jmp_offset);
|
||||||
|
return jmp_offset - offset;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
init_i2c_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
|
init_i2c_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
|
||||||
{
|
{
|
||||||
|
@ -3659,6 +3680,7 @@ static struct init_tbl_entry itbl_entry[] = {
|
||||||
{ "INIT_ZM_REG_SEQUENCE" , 0x58, init_zm_reg_sequence },
|
{ "INIT_ZM_REG_SEQUENCE" , 0x58, init_zm_reg_sequence },
|
||||||
/* INIT_INDIRECT_REG (0x5A, 7, 0, 0) removed due to no example of use */
|
/* INIT_INDIRECT_REG (0x5A, 7, 0, 0) removed due to no example of use */
|
||||||
{ "INIT_SUB_DIRECT" , 0x5B, init_sub_direct },
|
{ "INIT_SUB_DIRECT" , 0x5B, init_sub_direct },
|
||||||
|
{ "INIT_JUMP" , 0x5C, init_jump },
|
||||||
{ "INIT_I2C_IF" , 0x5E, init_i2c_if },
|
{ "INIT_I2C_IF" , 0x5E, init_i2c_if },
|
||||||
{ "INIT_COPY_NV_REG" , 0x5F, init_copy_nv_reg },
|
{ "INIT_COPY_NV_REG" , 0x5F, init_copy_nv_reg },
|
||||||
{ "INIT_ZM_INDEX_IO" , 0x62, init_zm_index_io },
|
{ "INIT_ZM_INDEX_IO" , 0x62, init_zm_index_io },
|
||||||
|
@ -3700,8 +3722,7 @@ static struct init_tbl_entry itbl_entry[] = {
|
||||||
#define MAX_TABLE_OPS 1000
|
#define MAX_TABLE_OPS 1000
|
||||||
|
|
||||||
static int
|
static int
|
||||||
parse_init_table(struct nvbios *bios, unsigned int offset,
|
parse_init_table(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
|
||||||
struct init_exec *iexec)
|
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Parses all commands in an init table.
|
* Parses all commands in an init table.
|
||||||
|
@ -6333,6 +6354,32 @@ apply_dcb_encoder_quirks(struct drm_device *dev, int idx, u32 *conn, u32 *conf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* XFX GT-240X-YA
|
||||||
|
*
|
||||||
|
* So many things wrong here, replace the entire encoder table..
|
||||||
|
*/
|
||||||
|
if (nv_match_device(dev, 0x0ca3, 0x1682, 0x3003)) {
|
||||||
|
if (idx == 0) {
|
||||||
|
*conn = 0x02001300; /* VGA, connector 1 */
|
||||||
|
*conf = 0x00000028;
|
||||||
|
} else
|
||||||
|
if (idx == 1) {
|
||||||
|
*conn = 0x01010312; /* DVI, connector 0 */
|
||||||
|
*conf = 0x00020030;
|
||||||
|
} else
|
||||||
|
if (idx == 2) {
|
||||||
|
*conn = 0x01010310; /* VGA, connector 0 */
|
||||||
|
*conf = 0x00000028;
|
||||||
|
} else
|
||||||
|
if (idx == 3) {
|
||||||
|
*conn = 0x02022362; /* HDMI, connector 2 */
|
||||||
|
*conf = 0x00020010;
|
||||||
|
} else {
|
||||||
|
*conn = 0x0000000e; /* EOL */
|
||||||
|
*conf = 0x00000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1190,7 +1190,7 @@ extern int nv50_graph_load_context(struct nouveau_channel *);
|
||||||
extern int nv50_graph_unload_context(struct drm_device *);
|
extern int nv50_graph_unload_context(struct drm_device *);
|
||||||
extern int nv50_grctx_init(struct nouveau_grctx *);
|
extern int nv50_grctx_init(struct nouveau_grctx *);
|
||||||
extern void nv50_graph_tlb_flush(struct drm_device *dev);
|
extern void nv50_graph_tlb_flush(struct drm_device *dev);
|
||||||
extern void nv86_graph_tlb_flush(struct drm_device *dev);
|
extern void nv84_graph_tlb_flush(struct drm_device *dev);
|
||||||
extern struct nouveau_enum nv50_data_error_names[];
|
extern struct nouveau_enum nv50_data_error_names[];
|
||||||
|
|
||||||
/* nvc0_graph.c */
|
/* nvc0_graph.c */
|
||||||
|
|
|
@ -552,6 +552,7 @@ nouveau_mem_timing_init(struct drm_device *dev)
|
||||||
u8 tRC; /* Byte 9 */
|
u8 tRC; /* Byte 9 */
|
||||||
u8 tUNK_10, tUNK_11, tUNK_12, tUNK_13, tUNK_14;
|
u8 tUNK_10, tUNK_11, tUNK_12, tUNK_13, tUNK_14;
|
||||||
u8 tUNK_18, tUNK_19, tUNK_20, tUNK_21;
|
u8 tUNK_18, tUNK_19, tUNK_20, tUNK_21;
|
||||||
|
u8 magic_number = 0; /* Yeah... sorry*/
|
||||||
u8 *mem = NULL, *entry;
|
u8 *mem = NULL, *entry;
|
||||||
int i, recordlen, entries;
|
int i, recordlen, entries;
|
||||||
|
|
||||||
|
@ -596,6 +597,12 @@ nouveau_mem_timing_init(struct drm_device *dev)
|
||||||
if (!memtimings->timing)
|
if (!memtimings->timing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* Get "some number" from the timing reg for NV_40
|
||||||
|
* Used in calculations later */
|
||||||
|
if(dev_priv->card_type == NV_40) {
|
||||||
|
magic_number = (nv_rd32(dev,0x100228) & 0x0f000000) >> 24;
|
||||||
|
}
|
||||||
|
|
||||||
entry = mem + mem[1];
|
entry = mem + mem[1];
|
||||||
for (i = 0; i < entries; i++, entry += recordlen) {
|
for (i = 0; i < entries; i++, entry += recordlen) {
|
||||||
struct nouveau_pm_memtiming *timing = &pm->memtimings.timing[i];
|
struct nouveau_pm_memtiming *timing = &pm->memtimings.timing[i];
|
||||||
|
@ -635,36 +642,51 @@ nouveau_mem_timing_init(struct drm_device *dev)
|
||||||
|
|
||||||
/* XXX: I don't trust the -1's and +1's... they must come
|
/* XXX: I don't trust the -1's and +1's... they must come
|
||||||
* from somewhere! */
|
* from somewhere! */
|
||||||
timing->reg_100224 = ((tUNK_0 + tUNK_19 + 1) << 24 |
|
timing->reg_100224 = (tUNK_0 + tUNK_19 + 1 + magic_number) << 24 |
|
||||||
tUNK_18 << 16 |
|
tUNK_18 << 16 |
|
||||||
(tUNK_1 + tUNK_19 + 1) << 8 |
|
(tUNK_1 + tUNK_19 + 1 + magic_number) << 8;
|
||||||
(tUNK_2 - 1));
|
if(dev_priv->chipset == 0xa8) {
|
||||||
|
timing->reg_100224 |= (tUNK_2 - 1);
|
||||||
|
} else {
|
||||||
|
timing->reg_100224 |= (tUNK_2 + 2 - magic_number);
|
||||||
|
}
|
||||||
|
|
||||||
timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10);
|
timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10);
|
||||||
if(recordlen > 19) {
|
if(dev_priv->chipset >= 0xa3 && dev_priv->chipset < 0xaa) {
|
||||||
timing->reg_100228 += (tUNK_19 - 1) << 24;
|
timing->reg_100228 |= (tUNK_19 - 1) << 24;
|
||||||
}/* I cannot back-up this else-statement right now
|
}
|
||||||
else {
|
|
||||||
timing->reg_100228 += tUNK_12 << 24;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/* XXX: reg_10022c */
|
if(dev_priv->card_type == NV_40) {
|
||||||
timing->reg_10022c = tUNK_2 - 1;
|
/* NV40: don't know what the rest of the regs are..
|
||||||
|
* And don't need to know either */
|
||||||
|
timing->reg_100228 |= 0x20200000 | magic_number << 24;
|
||||||
|
} else if(dev_priv->card_type >= NV_50) {
|
||||||
|
/* XXX: reg_10022c */
|
||||||
|
timing->reg_10022c = tUNK_2 - 1;
|
||||||
|
|
||||||
timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 |
|
timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 |
|
||||||
tUNK_13 << 8 | tUNK_13);
|
tUNK_13 << 8 | tUNK_13);
|
||||||
|
|
||||||
/* XXX: +6? */
|
timing->reg_100234 = (tRAS << 24 | tRC);
|
||||||
timing->reg_100234 = (tRAS << 24 | (tUNK_19 + 6) << 8 | tRC);
|
timing->reg_100234 += max(tUNK_10,tUNK_11) << 16;
|
||||||
timing->reg_100234 += max(tUNK_10,tUNK_11) << 16;
|
|
||||||
|
|
||||||
/* XXX; reg_100238, reg_10023c
|
if(dev_priv->chipset < 0xa3) {
|
||||||
* reg: 0x00??????
|
timing->reg_100234 |= (tUNK_2 + 2) << 8;
|
||||||
* reg_10023c:
|
} else {
|
||||||
* 0 for pre-NV50 cards
|
/* XXX: +6? */
|
||||||
* 0x????0202 for NV50+ cards (empirical evidence) */
|
timing->reg_100234 |= (tUNK_19 + 6) << 8;
|
||||||
if(dev_priv->card_type >= NV_50) {
|
}
|
||||||
|
|
||||||
|
/* XXX; reg_100238, reg_10023c
|
||||||
|
* reg_100238: 0x00??????
|
||||||
|
* reg_10023c: 0x!!??0202 for NV50+ cards (empirical evidence) */
|
||||||
timing->reg_10023c = 0x202;
|
timing->reg_10023c = 0x202;
|
||||||
|
if(dev_priv->chipset < 0xa3) {
|
||||||
|
timing->reg_10023c |= 0x4000000 | (tUNK_2 - 1) << 16;
|
||||||
|
} else {
|
||||||
|
/* currently unknown
|
||||||
|
* 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i,
|
NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i,
|
||||||
|
@ -675,7 +697,7 @@ nouveau_mem_timing_init(struct drm_device *dev)
|
||||||
timing->reg_100238, timing->reg_10023c);
|
timing->reg_100238, timing->reg_10023c);
|
||||||
}
|
}
|
||||||
|
|
||||||
memtimings->nr_timing = entries;
|
memtimings->nr_timing = entries;
|
||||||
memtimings->supported = true;
|
memtimings->supported = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -134,7 +134,7 @@ nouveau_perf_init(struct drm_device *dev)
|
||||||
case 0x13:
|
case 0x13:
|
||||||
case 0x15:
|
case 0x15:
|
||||||
perflvl->fanspeed = entry[55];
|
perflvl->fanspeed = entry[55];
|
||||||
perflvl->voltage = entry[56];
|
perflvl->voltage = (recordlen > 56) ? entry[56] : 0;
|
||||||
perflvl->core = ROM32(entry[1]) * 10;
|
perflvl->core = ROM32(entry[1]) * 10;
|
||||||
perflvl->memory = ROM32(entry[5]) * 20;
|
perflvl->memory = ROM32(entry[5]) * 20;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -376,15 +376,11 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
|
||||||
engine->graph.destroy_context = nv50_graph_destroy_context;
|
engine->graph.destroy_context = nv50_graph_destroy_context;
|
||||||
engine->graph.load_context = nv50_graph_load_context;
|
engine->graph.load_context = nv50_graph_load_context;
|
||||||
engine->graph.unload_context = nv50_graph_unload_context;
|
engine->graph.unload_context = nv50_graph_unload_context;
|
||||||
if (dev_priv->chipset != 0x86)
|
if (dev_priv->chipset == 0x50 ||
|
||||||
|
dev_priv->chipset == 0xac)
|
||||||
engine->graph.tlb_flush = nv50_graph_tlb_flush;
|
engine->graph.tlb_flush = nv50_graph_tlb_flush;
|
||||||
else {
|
else
|
||||||
/* from what i can see nvidia do this on every
|
engine->graph.tlb_flush = nv84_graph_tlb_flush;
|
||||||
* pre-NVA3 board except NVAC, but, we've only
|
|
||||||
* ever seen problems on NV86
|
|
||||||
*/
|
|
||||||
engine->graph.tlb_flush = nv86_graph_tlb_flush;
|
|
||||||
}
|
|
||||||
engine->fifo.channels = 128;
|
engine->fifo.channels = 128;
|
||||||
engine->fifo.init = nv50_fifo_init;
|
engine->fifo.init = nv50_fifo_init;
|
||||||
engine->fifo.takedown = nv50_fifo_takedown;
|
engine->fifo.takedown = nv50_fifo_takedown;
|
||||||
|
|
|
@ -581,12 +581,13 @@ static void nv04_dfp_restore(struct drm_encoder *encoder)
|
||||||
int head = nv_encoder->restore.head;
|
int head = nv_encoder->restore.head;
|
||||||
|
|
||||||
if (nv_encoder->dcb->type == OUTPUT_LVDS) {
|
if (nv_encoder->dcb->type == OUTPUT_LVDS) {
|
||||||
struct drm_display_mode *native_mode = nouveau_encoder_connector_get(nv_encoder)->native_mode;
|
struct nouveau_connector *connector =
|
||||||
if (native_mode)
|
nouveau_encoder_connector_get(nv_encoder);
|
||||||
call_lvds_script(dev, nv_encoder->dcb, head, LVDS_PANEL_ON,
|
|
||||||
native_mode->clock);
|
if (connector && connector->native_mode)
|
||||||
else
|
call_lvds_script(dev, nv_encoder->dcb, head,
|
||||||
NV_ERROR(dev, "Not restoring LVDS without native mode\n");
|
LVDS_PANEL_ON,
|
||||||
|
connector->native_mode->clock);
|
||||||
|
|
||||||
} else if (nv_encoder->dcb->type == OUTPUT_TMDS) {
|
} else if (nv_encoder->dcb->type == OUTPUT_TMDS) {
|
||||||
int clock = nouveau_hw_pllvals_to_clk
|
int clock = nouveau_hw_pllvals_to_clk
|
||||||
|
|
|
@ -469,9 +469,6 @@ nv50_crtc_wait_complete(struct drm_crtc *crtc)
|
||||||
|
|
||||||
start = ptimer->read(dev);
|
start = ptimer->read(dev);
|
||||||
do {
|
do {
|
||||||
nv_wr32(dev, 0x61002c, 0x370);
|
|
||||||
nv_wr32(dev, 0x000140, 1);
|
|
||||||
|
|
||||||
if (nv_ro32(disp->ntfy, 0x000))
|
if (nv_ro32(disp->ntfy, 0x000))
|
||||||
return 0;
|
return 0;
|
||||||
} while (ptimer->read(dev) - start < 2000000000ULL);
|
} while (ptimer->read(dev) - start < 2000000000ULL);
|
||||||
|
|
|
@ -186,6 +186,7 @@ nv50_evo_channel_init(struct nouveau_channel *evo)
|
||||||
nv_mask(dev, 0x610028, 0x00000000, 0x00010001 << id);
|
nv_mask(dev, 0x610028, 0x00000000, 0x00010001 << id);
|
||||||
|
|
||||||
evo->dma.max = (4096/4) - 2;
|
evo->dma.max = (4096/4) - 2;
|
||||||
|
evo->dma.max &= ~7;
|
||||||
evo->dma.put = 0;
|
evo->dma.put = 0;
|
||||||
evo->dma.cur = evo->dma.put;
|
evo->dma.cur = evo->dma.put;
|
||||||
evo->dma.free = evo->dma.max - evo->dma.cur;
|
evo->dma.free = evo->dma.max - evo->dma.cur;
|
||||||
|
|
|
@ -503,7 +503,7 @@ nv50_graph_tlb_flush(struct drm_device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nv86_graph_tlb_flush(struct drm_device *dev)
|
nv84_graph_tlb_flush(struct drm_device *dev)
|
||||||
{
|
{
|
||||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||||
struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
|
struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
|
||||||
|
|
|
@ -104,20 +104,26 @@ nvc0_vm_flush(struct nouveau_vm *vm)
|
||||||
struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
|
struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
|
||||||
struct drm_device *dev = vm->dev;
|
struct drm_device *dev = vm->dev;
|
||||||
struct nouveau_vm_pgd *vpgd;
|
struct nouveau_vm_pgd *vpgd;
|
||||||
u32 r100c80, engine;
|
u32 engine = (dev_priv->chan_vm == vm) ? 1 : 5;
|
||||||
|
|
||||||
pinstmem->flush(vm->dev);
|
pinstmem->flush(vm->dev);
|
||||||
|
|
||||||
if (vm == dev_priv->chan_vm)
|
spin_lock(&dev_priv->ramin_lock);
|
||||||
engine = 1;
|
|
||||||
else
|
|
||||||
engine = 5;
|
|
||||||
|
|
||||||
list_for_each_entry(vpgd, &vm->pgd_list, head) {
|
list_for_each_entry(vpgd, &vm->pgd_list, head) {
|
||||||
r100c80 = nv_rd32(dev, 0x100c80);
|
/* looks like maybe a "free flush slots" counter, the
|
||||||
|
* faster you write to 0x100cbc to more it decreases
|
||||||
|
*/
|
||||||
|
if (!nv_wait_ne(dev, 0x100c80, 0x00ff0000, 0x00000000)) {
|
||||||
|
NV_ERROR(dev, "vm timeout 0: 0x%08x %d\n",
|
||||||
|
nv_rd32(dev, 0x100c80), engine);
|
||||||
|
}
|
||||||
nv_wr32(dev, 0x100cb8, vpgd->obj->vinst >> 8);
|
nv_wr32(dev, 0x100cb8, vpgd->obj->vinst >> 8);
|
||||||
nv_wr32(dev, 0x100cbc, 0x80000000 | engine);
|
nv_wr32(dev, 0x100cbc, 0x80000000 | engine);
|
||||||
if (!nv_wait(dev, 0x100c80, 0xffffffff, r100c80))
|
/* wait for flush to be queued? */
|
||||||
NV_ERROR(dev, "vm flush timeout eng %d\n", engine);
|
if (!nv_wait(dev, 0x100c80, 0x00008000, 0x00008000)) {
|
||||||
|
NV_ERROR(dev, "vm timeout 1: 0x%08x %d\n",
|
||||||
|
nv_rd32(dev, 0x100c80), engine);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
spin_unlock(&dev_priv->ramin_lock);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue