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:
Dave Airlie 2011-04-11 15:26:01 +10:00
commit d85023a3cd
10 changed files with 125 additions and 55 deletions

View File

@ -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;
} }

View File

@ -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 */

View File

@ -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;
} }

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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);
} }