The first patch should allow the generation of correct memtimings (r100240 put aside) on the nv40-nv98.a1 interval. The second one is associating the memtimings with the performance levels. Please comment on it or push it
Martin Peres
2011-Mar-29 00:18 UTC
[Nouveau] [PATCH 1/2] PM: NV50-NV98.a1 correct/implement many additional memtimings Nearly consistent with envytools. Added stepping to drm_nouveau_private to make sure newer NV98 (105M) is zero rather than incorrect.
From: Roy Spliet <r.spliet at student.tudelft.nl> --- drivers/gpu/drm/nouveau/nouveau_drv.h | 2 + drivers/gpu/drm/nouveau/nouveau_mem.c | 42 +++++++++++++++++++++--------- drivers/gpu/drm/nouveau/nouveau_state.c | 2 + 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 383093e..aca960e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -466,6 +466,7 @@ struct nouveau_pm_memtiming { u32 reg_100234; u32 reg_100238; u32 reg_10023c; + u32 reg_100240; }; struct nouveau_pm_memtimings { @@ -637,6 +638,7 @@ struct drm_nouveau_private { enum nouveau_card_type card_type; /* exact chipset, derived from NV_PMC_BOOT_0 */ int chipset; + int stepping; int flags; void __iomem *mmio; diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 405f990..3636529 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -597,9 +597,9 @@ nouveau_mem_timing_init(struct drm_device *dev) if (!memtimings->timing) return; - /* Get "some number" from the timing reg for NV_40 + /* Get "some number" from the timing reg for NV_40 and NV_50 * Used in calculations later */ - if (dev_priv->card_type == NV_40) { + if (dev_priv->card_type >= NV_40 && dev_priv->chipset < 0x98) { magic_number = (nv_rd32(dev, 0x100228) & 0x0f000000) >> 24; } @@ -643,7 +643,7 @@ nouveau_mem_timing_init(struct drm_device *dev) /* XXX: I don't trust the -1's and +1's... they must come * from somewhere! */ timing->reg_100224 = (tUNK_0 + tUNK_19 + 1 + magic_number) << 24 | - tUNK_18 << 16 | + max(tUNK_18, (u8) 1) << 16 | (tUNK_1 + tUNK_19 + 1 + magic_number) << 8; if (dev_priv->chipset == 0xa8) { timing->reg_100224 |= (tUNK_2 - 1); @@ -654,15 +654,25 @@ nouveau_mem_timing_init(struct drm_device *dev) timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10); if (dev_priv->chipset >= 0xa3 && dev_priv->chipset < 0xaa) { timing->reg_100228 |= (tUNK_19 - 1) << 24; - } + } else { + timing->reg_100228 |= magic_number << 24; + } if (dev_priv->card_type == NV_40) { /* 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; + timing->reg_100228 |= 0x20200000; } else if (dev_priv->card_type >= NV_50) { - /* XXX: reg_10022c */ - timing->reg_10022c = tUNK_2 - 1; + if(dev_priv->chipset < 0x98 || + (dev_priv->chipset == 0x98 && dev_priv->stepping <= 0xa1)) { + timing->reg_10022c = (0x14 + tUNK_2) << 24 | + 0x16 << 16 | + (tUNK_2 - 1) << 8 | + (tUNK_2 - 1); + } else { + /* XXX: reg_10022c for recentish cards */ + timing->reg_10022c = tUNK_2 - 1; + } timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 | tUNK_13 << 8 | tUNK_13); @@ -670,23 +680,27 @@ nouveau_mem_timing_init(struct drm_device *dev) timing->reg_100234 = (tRAS << 24 | tRC); timing->reg_100234 += max(tUNK_10, tUNK_11) << 16; - if (dev_priv->chipset < 0xa3) { + if (dev_priv->chipset < 0x98 || + (dev_priv->chipset == 0x98 && dev_priv->stepping <= 0xa1)) { timing->reg_100234 |= (tUNK_2 + 2) << 8; } else { /* XXX: +6? */ timing->reg_100234 |= (tUNK_19 + 6) << 8; } - /* XXX; reg_100238, reg_10023c - * reg_100238: 0x00?????? - * reg_10023c: 0x!!??0202 for NV50+ cards (empirical evidence) */ + /* XXX; reg_100238 + * reg_100238: 0x00?????? */ timing->reg_10023c = 0x202; - if (dev_priv->chipset < 0xa3) { + if (dev_priv->chipset < 0x98 || + (dev_priv->chipset == 0x98 && dev_priv->stepping <= 0xa1)) { timing->reg_10023c |= 0x4000000 | (tUNK_2 - 1) << 16; } else { - /* currently unknown + /* XXX: reg_10023c + * currently unknown * 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */ } + + /* XXX: reg_100240? */ } NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i, @@ -695,6 +709,8 @@ nouveau_mem_timing_init(struct drm_device *dev) NV_DEBUG(dev, " 230: %08x %08x %08x %08x\n", timing->reg_100230, timing->reg_100234, timing->reg_100238, timing->reg_10023c); + NV_DEBUG(dev, " 240: %08x\n", + timing->reg_100240); } memtimings->nr_timing = entries; diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index e162514..d8297c0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -922,11 +922,13 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) /* Time to determine the card architecture */ reg0 = nv_rd32(dev, NV03_PMC_BOOT_0); + dev_priv->stepping = 0; /* XXX: add stepping for pre-NV10? */ /* We're dealing with >=NV10 */ if ((reg0 & 0x0f000000) > 0) { /* Bit 27-20 contain the architecture in hex */ dev_priv->chipset = (reg0 & 0xff00000) >> 20; + dev_priv->stepping = (reg0 & 0xff); /* NV04 or NV05 */ } else if ((reg0 & 0xff00fff0) == 0x20004000) { if (reg0 & 0x00f00000) -- 1.7.4.1
Martin Peres
2011-Mar-29 00:18 UTC
[Nouveau] [PATCH 2/2] Associate memtimings with performance levels
Signed-off-by: Martin Peres <martin.peres at ensi-bourges.fr> --- drivers/gpu/drm/nouveau/nouveau_drv.h | 26 ++++++++++++++------------ drivers/gpu/drm/nouveau/nouveau_mem.c | 1 + drivers/gpu/drm/nouveau/nouveau_perf.c | 25 +++++++++++++++++++++++++ drivers/gpu/drm/nouveau/nouveau_pm.c | 14 +++++++++----- 4 files changed, 49 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index aca960e..0d23671 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -426,6 +426,19 @@ struct nouveau_pm_voltage { int nr_level; }; +struct nouveau_pm_memtiming { + int id; + u32 reg_100220; + u32 reg_100224; + u32 reg_100228; + u32 reg_10022c; + u32 reg_100230; + u32 reg_100234; + u32 reg_100238; + u32 reg_10023c; + u32 reg_100240; +}; + #define NOUVEAU_PM_MAX_LEVEL 8 struct nouveau_pm_level { struct device_attribute dev_attr; @@ -441,6 +454,7 @@ struct nouveau_pm_level { u8 fanspeed; u16 memscript; + struct nouveau_pm_memtiming *timing; }; struct nouveau_pm_temp_sensor_constants { @@ -457,18 +471,6 @@ struct nouveau_pm_threshold_temp { s16 fan_boost; }; -struct nouveau_pm_memtiming { - u32 reg_100220; - u32 reg_100224; - u32 reg_100228; - u32 reg_10022c; - u32 reg_100230; - u32 reg_100234; - u32 reg_100238; - u32 reg_10023c; - u32 reg_100240; -}; - struct nouveau_pm_memtimings { bool supported; struct nouveau_pm_memtiming *timing; diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 3636529..45b315c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -702,6 +702,7 @@ nouveau_mem_timing_init(struct drm_device *dev) /* XXX: reg_100240? */ } + timing->id = i; NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i, timing->reg_100220, timing->reg_100224, diff --git a/drivers/gpu/drm/nouveau/nouveau_perf.c b/drivers/gpu/drm/nouveau/nouveau_perf.c index 670e3cb..904d680 100644 --- a/drivers/gpu/drm/nouveau/nouveau_perf.c +++ b/drivers/gpu/drm/nouveau/nouveau_perf.c @@ -82,6 +82,7 @@ nouveau_perf_init(struct drm_device *dev) u8 version, headerlen, recordlen, entries; u8 *perf, *entry; int vid, i; + uint8_t timing_entry = (nv_rd32(dev, NV_PEXTDEV_BOOT_0) & 0x1c) >> 2; if (bios->type == NVBIOS_BIT) { if (bit_table(dev, 'P', &P)) @@ -124,6 +125,8 @@ nouveau_perf_init(struct drm_device *dev) for (i = 0; i < entries; i++) { struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl]; + perflvl->timing = NULL; + if (entry[0] == 0xff) { entry += recordlen; continue; @@ -190,6 +193,28 @@ nouveau_perf_init(struct drm_device *dev) } } + /* get the corresponding memory timings */ + if (pm->memtimings.supported) { + uint8_t timing_id = 0xff; + + if (version > 0x15 && version < 0x40 && + timing_entry < perf[4]) { + uint16_t extra_data; + extra_data = perf[3] + (timing_entry * perf[5]); + + timing_id = entry[extra_data + 1]; + } else if (version == 0x40 && timing_entry < perf[4]) { + uint16_t extra_data; + extra_data = perf[2] + (timing_entry * perf[3]); + + timing_id = entry[extra_data + 1]; + } + + if (pm->memtimings.nr_timing > timing_id) + perflvl->timing + &pm->memtimings.timing[timing_id]; + } + snprintf(perflvl->name, sizeof(perflvl->name), "performance_level_%d", i); perflvl->id = i; diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c index 0b1caeb..4e51404 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.c +++ b/drivers/gpu/drm/nouveau/nouveau_pm.c @@ -156,7 +156,7 @@ nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) static void nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len) { - char c[16], s[16], v[16], f[16]; + char c[16], s[16], v[16], f[16], t[16]; c[0] = '\0'; if (perflvl->core) @@ -174,8 +174,12 @@ nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len) if (perflvl->fanspeed) snprintf(f, sizeof(f), " fanspeed %d%%", perflvl->fanspeed); - snprintf(ptr, len, "memory %dMHz%s%s%s%s\n", perflvl->memory / 1000, - c, s, v, f); + t[0] = '\0'; + if (perflvl->timing) + snprintf(t, sizeof(t), " timing %d", perflvl->timing->id); + + snprintf(ptr, len, "memory %dMHz%s%s%s%s%s\n", perflvl->memory / 1000, + c, s, v, f, t); } static ssize_t @@ -476,10 +480,10 @@ nouveau_pm_init(struct drm_device *dev) char info[256]; int ret, i; + nouveau_mem_timing_init(dev); nouveau_volt_init(dev); nouveau_perf_init(dev); nouveau_temp_init(dev); - nouveau_mem_timing_init(dev); NV_INFO(dev, "%d available performance level(s)\n", pm->nr_perflvl); for (i = 0; i < pm->nr_perflvl; i++) { @@ -525,10 +529,10 @@ nouveau_pm_fini(struct drm_device *dev) if (pm->cur != &pm->boot) nouveau_pm_perflvl_set(dev, &pm->boot); - nouveau_mem_timing_fini(dev); nouveau_temp_fini(dev); nouveau_perf_fini(dev); nouveau_volt_fini(dev); + nouveau_mem_timing_fini(dev); #ifdef CONFIG_ACPI unregister_acpi_notifier(&pm->acpi_nb); -- 1.7.4.1