Commit 50066f81 authored by Roy Spliet's avatar Roy Spliet Committed by Ben Skeggs

drm/nouveau: improve memtiming table parsing

Improves the parsing of the memory timing table on NV50-NV98revA1 chipsets.

Added stepping to drm_nouveau_private to make sure newer NV98 (105M) is
zero rather than incorrect.
Signed-off-by: default avatarRoy Spliet <r.spliet@student.tudelft.nl>
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 7795bee0
...@@ -466,6 +466,7 @@ struct nouveau_pm_memtiming { ...@@ -466,6 +466,7 @@ struct nouveau_pm_memtiming {
u32 reg_100234; u32 reg_100234;
u32 reg_100238; u32 reg_100238;
u32 reg_10023c; u32 reg_10023c;
u32 reg_100240;
}; };
struct nouveau_pm_memtimings { struct nouveau_pm_memtimings {
...@@ -637,6 +638,7 @@ struct drm_nouveau_private { ...@@ -637,6 +638,7 @@ struct drm_nouveau_private {
enum nouveau_card_type card_type; enum nouveau_card_type card_type;
/* exact chipset, derived from NV_PMC_BOOT_0 */ /* exact chipset, derived from NV_PMC_BOOT_0 */
int chipset; int chipset;
int stepping;
int flags; int flags;
void __iomem *mmio; void __iomem *mmio;
......
...@@ -597,9 +597,9 @@ nouveau_mem_timing_init(struct drm_device *dev) ...@@ -597,9 +597,9 @@ 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 /* Get "some number" from the timing reg for NV_40 and NV_50
* Used in calculations later */ * 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; magic_number = (nv_rd32(dev, 0x100228) & 0x0f000000) >> 24;
} }
...@@ -643,7 +643,7 @@ nouveau_mem_timing_init(struct drm_device *dev) ...@@ -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 /* 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 + magic_number) << 24 | 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; (tUNK_1 + tUNK_19 + 1 + magic_number) << 8;
if (dev_priv->chipset == 0xa8) { if (dev_priv->chipset == 0xa8) {
timing->reg_100224 |= (tUNK_2 - 1); timing->reg_100224 |= (tUNK_2 - 1);
...@@ -652,17 +652,27 @@ nouveau_mem_timing_init(struct drm_device *dev) ...@@ -652,17 +652,27 @@ nouveau_mem_timing_init(struct drm_device *dev)
} }
timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10); timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10);
if (dev_priv->chipset >= 0xa3 && dev_priv->chipset < 0xaa) { if (dev_priv->chipset >= 0xa3 && dev_priv->chipset < 0xaa)
timing->reg_100228 |= (tUNK_19 - 1) << 24; timing->reg_100228 |= (tUNK_19 - 1) << 24;
} else
timing->reg_100228 |= magic_number << 24;
if (dev_priv->card_type == NV_40) { if (dev_priv->card_type == NV_40) {
/* NV40: don't know what the rest of the regs are.. /* NV40: don't know what the rest of the regs are..
* And don't need to know either */ * 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) { } else if (dev_priv->card_type >= NV_50) {
/* XXX: reg_10022c */ 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_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);
...@@ -670,23 +680,29 @@ nouveau_mem_timing_init(struct drm_device *dev) ...@@ -670,23 +680,29 @@ nouveau_mem_timing_init(struct drm_device *dev)
timing->reg_100234 = (tRAS << 24 | tRC); timing->reg_100234 = (tRAS << 24 | tRC);
timing->reg_100234 += max(tUNK_10, tUNK_11) << 16; 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; timing->reg_100234 |= (tUNK_2 + 2) << 8;
} else { } else {
/* XXX: +6? */ /* XXX: +6? */
timing->reg_100234 |= (tUNK_19 + 6) << 8; timing->reg_100234 |= (tUNK_19 + 6) << 8;
} }
/* XXX; reg_100238, reg_10023c /* XXX; reg_100238
* reg_100238: 0x00?????? * 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) { if (dev_priv->chipset < 0x98 ||
(dev_priv->chipset == 0x98 &&
dev_priv->stepping <= 0xa1)) {
timing->reg_10023c |= 0x4000000 | (tUNK_2 - 1) << 16; timing->reg_10023c |= 0x4000000 | (tUNK_2 - 1) << 16;
} else { } else {
/* currently unknown /* XXX: reg_10023c
* currently unknown
* 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */ * 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */
} }
/* XXX: reg_100240? */
} }
NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i, NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i,
...@@ -695,6 +711,7 @@ nouveau_mem_timing_init(struct drm_device *dev) ...@@ -695,6 +711,7 @@ nouveau_mem_timing_init(struct drm_device *dev)
NV_DEBUG(dev, " 230: %08x %08x %08x %08x\n", NV_DEBUG(dev, " 230: %08x %08x %08x %08x\n",
timing->reg_100230, timing->reg_100234, timing->reg_100230, timing->reg_100234,
timing->reg_100238, timing->reg_10023c); timing->reg_100238, timing->reg_10023c);
NV_DEBUG(dev, " 240: %08x\n", timing->reg_100240);
} }
memtimings->nr_timing = entries; memtimings->nr_timing = entries;
......
...@@ -913,11 +913,13 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) ...@@ -913,11 +913,13 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
/* Time to determine the card architecture */ /* Time to determine the card architecture */
reg0 = nv_rd32(dev, NV03_PMC_BOOT_0); reg0 = nv_rd32(dev, NV03_PMC_BOOT_0);
dev_priv->stepping = 0; /* XXX: add stepping for pre-NV10? */
/* We're dealing with >=NV10 */ /* We're dealing with >=NV10 */
if ((reg0 & 0x0f000000) > 0) { if ((reg0 & 0x0f000000) > 0) {
/* Bit 27-20 contain the architecture in hex */ /* Bit 27-20 contain the architecture in hex */
dev_priv->chipset = (reg0 & 0xff00000) >> 20; dev_priv->chipset = (reg0 & 0xff00000) >> 20;
dev_priv->stepping = (reg0 & 0xff);
/* NV04 or NV05 */ /* NV04 or NV05 */
} else if ((reg0 & 0xff00fff0) == 0x20004000) { } else if ((reg0 & 0xff00fff0) == 0x20004000) {
if (reg0 & 0x00f00000) if (reg0 & 0x00f00000)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment