drm/nouveau/pm: add initial NV3x/NVCx memtiming support, improve other cards
NV30: Create framework for memtm NV50: Improve reg creation, NV50: Use P.version instead of card codename/stepping, NVC0: Initial memtiming code for Fermi, Renamed regs for consistency, Overall redesign to improve readability, Avoid kfree on null-pointer Signed-off-by: Roy Spliet <r.spliet@student.tudelft.nl>
This commit is contained in:
parent
1cb70b30e4
commit
9a78248876
|
@ -429,17 +429,43 @@ struct nouveau_pm_voltage {
|
||||||
|
|
||||||
struct nouveau_pm_memtiming {
|
struct nouveau_pm_memtiming {
|
||||||
int id;
|
int id;
|
||||||
u32 reg_100220;
|
u32 reg_0; /* 0x10f290 on Fermi, 0x100220 for older */
|
||||||
u32 reg_100224;
|
u32 reg_1;
|
||||||
u32 reg_100228;
|
u32 reg_2;
|
||||||
u32 reg_10022c;
|
u32 reg_3;
|
||||||
u32 reg_100230;
|
u32 reg_4;
|
||||||
u32 reg_100234;
|
u32 reg_5;
|
||||||
u32 reg_100238;
|
u32 reg_6;
|
||||||
u32 reg_10023c;
|
u32 reg_7;
|
||||||
u32 reg_100240;
|
u32 reg_8;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct nouveau_pm_tbl_header{
|
||||||
|
u8 version;
|
||||||
|
u8 header_len;
|
||||||
|
u8 entry_cnt;
|
||||||
|
u8 entry_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nouveau_pm_tbl_entry{
|
||||||
|
u8 tUNK_0, tUNK_1, tUNK_2;
|
||||||
|
u8 tRP; /* Byte 3 */
|
||||||
|
u8 empty_4;
|
||||||
|
u8 tRAS; /* Byte 5 */
|
||||||
|
u8 empty_6;
|
||||||
|
u8 tRFC; /* Byte 7 */
|
||||||
|
u8 empty_8;
|
||||||
|
u8 tRC; /* Byte 9 */
|
||||||
|
u8 tUNK_10, tUNK_11, tUNK_12, tUNK_13, tUNK_14;
|
||||||
|
u8 empty_15,empty_16,empty_17;
|
||||||
|
u8 tUNK_18, tUNK_19, tUNK_20, tUNK_21;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* nouveau_mem.c */
|
||||||
|
void nv30_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
|
||||||
|
struct nouveau_pm_tbl_entry *e, uint8_t magic_number,
|
||||||
|
struct nouveau_pm_memtiming *timing);
|
||||||
|
|
||||||
#define NOUVEAU_PM_MAX_LEVEL 8
|
#define NOUVEAU_PM_MAX_LEVEL 8
|
||||||
struct nouveau_pm_level {
|
struct nouveau_pm_level {
|
||||||
struct device_attribute dev_attr;
|
struct device_attribute dev_attr;
|
||||||
|
@ -648,7 +674,6 @@ 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;
|
||||||
|
|
|
@ -502,35 +502,146 @@ nouveau_mem_gart_init(struct drm_device *dev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* XXX: For now a dummy. More samples required, possibly even a card
|
||||||
|
* Called from nouveau_perf.c */
|
||||||
|
void nv30_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
|
||||||
|
struct nouveau_pm_tbl_entry *e, uint8_t magic_number,
|
||||||
|
struct nouveau_pm_memtiming *timing) {
|
||||||
|
|
||||||
|
NV_DEBUG(dev,"Timing entry format unknown, please contact nouveau developers");
|
||||||
|
}
|
||||||
|
|
||||||
|
void nv40_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
|
||||||
|
struct nouveau_pm_tbl_entry *e, uint8_t magic_number,
|
||||||
|
struct nouveau_pm_memtiming *timing) {
|
||||||
|
|
||||||
|
timing->reg_0 = (e->tRC << 24 | e->tRFC << 16 | e->tRAS << 8 | e->tRP);
|
||||||
|
|
||||||
|
/* XXX: I don't trust the -1's and +1's... they must come
|
||||||
|
* from somewhere! */
|
||||||
|
timing->reg_1 = (e->tUNK_0 + 2 + magic_number) << 24 |
|
||||||
|
1 << 16 |
|
||||||
|
(e->tUNK_1 + 2 + magic_number) << 8 |
|
||||||
|
(e->tUNK_2 + 2 - magic_number);
|
||||||
|
timing->reg_2 = (magic_number << 24 | e->tUNK_12 << 16 | e->tUNK_11 << 8 | e->tUNK_10);
|
||||||
|
timing->reg_2 |= 0x20200000;
|
||||||
|
|
||||||
|
NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x\n", timing->id,
|
||||||
|
timing->reg_0, timing->reg_1,timing->reg_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nv50_mem_timing_entry(struct drm_device *dev, struct bit_entry *P, struct nouveau_pm_tbl_header *hdr,
|
||||||
|
struct nouveau_pm_tbl_entry *e, uint8_t magic_number,struct nouveau_pm_memtiming *timing) {
|
||||||
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||||
|
|
||||||
|
uint8_t unk18 = 1,
|
||||||
|
unk19 = 1,
|
||||||
|
unk20 = 0,
|
||||||
|
unk21 = 0;
|
||||||
|
|
||||||
|
switch (min(hdr->entry_len, (u8) 22)) {
|
||||||
|
case 22:
|
||||||
|
unk21 = e->tUNK_21;
|
||||||
|
case 21:
|
||||||
|
unk20 = e->tUNK_20;
|
||||||
|
case 20:
|
||||||
|
unk19 = e->tUNK_19;
|
||||||
|
case 19:
|
||||||
|
unk18 = e->tUNK_18;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
timing->reg_0 = (e->tRC << 24 | e->tRFC << 16 | e->tRAS << 8 | e->tRP);
|
||||||
|
|
||||||
|
/* XXX: I don't trust the -1's and +1's... they must come
|
||||||
|
* from somewhere! */
|
||||||
|
timing->reg_1 = (e->tUNK_0 + unk19 + 1 + magic_number) << 24 |
|
||||||
|
max(unk18, (u8) 1) << 16 |
|
||||||
|
(e->tUNK_1 + unk19 + 1 + magic_number) << 8;
|
||||||
|
if (dev_priv->chipset == 0xa8) {
|
||||||
|
timing->reg_1 |= (e->tUNK_2 - 1);
|
||||||
|
} else {
|
||||||
|
timing->reg_1 |= (e->tUNK_2 + 2 - magic_number);
|
||||||
|
}
|
||||||
|
timing->reg_2 = (e->tUNK_12 << 16 | e->tUNK_11 << 8 | e->tUNK_10);
|
||||||
|
|
||||||
|
timing->reg_5 = (e->tRAS << 24 | e->tRC);
|
||||||
|
timing->reg_5 += max(e->tUNK_10, e->tUNK_11) << 16;
|
||||||
|
|
||||||
|
if (P->version == 1) {
|
||||||
|
timing->reg_2 |= magic_number << 24;
|
||||||
|
timing->reg_3 = (0x14 + e->tUNK_2) << 24 |
|
||||||
|
0x16 << 16 |
|
||||||
|
(e->tUNK_2 - 1) << 8 |
|
||||||
|
(e->tUNK_2 - 1);
|
||||||
|
timing->reg_4 = (nv_rd32(dev,0x10022c) & 0xffff0000) | e->tUNK_13 << 8 | e->tUNK_13;
|
||||||
|
timing->reg_5 |= (e->tUNK_2 + 2) << 8;
|
||||||
|
timing->reg_7 = 0x4000202 | (e->tUNK_2 - 1) << 16;
|
||||||
|
} else {
|
||||||
|
timing->reg_2 |= (unk19 - 1) << 24;
|
||||||
|
/* XXX: reg_10022c for recentish cards pretty much unknown*/
|
||||||
|
timing->reg_3 = e->tUNK_2 - 1;
|
||||||
|
timing->reg_4 = (unk20 << 24 | unk21 << 16 |
|
||||||
|
e->tUNK_13 << 8 | e->tUNK_13);
|
||||||
|
/* XXX: +6? */
|
||||||
|
timing->reg_5 |= (unk19 + 6) << 8;
|
||||||
|
|
||||||
|
/* XXX: reg_10023c currently unknown
|
||||||
|
* 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */
|
||||||
|
timing->reg_7 = 0x202;
|
||||||
|
}
|
||||||
|
|
||||||
|
NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", timing->id,
|
||||||
|
timing->reg_0, timing->reg_1,
|
||||||
|
timing->reg_2, timing->reg_3);
|
||||||
|
NV_DEBUG(dev, " 230: %08x %08x %08x %08x\n",
|
||||||
|
timing->reg_4, timing->reg_5,
|
||||||
|
timing->reg_6, timing->reg_7);
|
||||||
|
NV_DEBUG(dev, " 240: %08x\n", timing->reg_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nvc0_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
|
||||||
|
struct nouveau_pm_tbl_entry *e, struct nouveau_pm_memtiming *timing) {
|
||||||
|
timing->reg_0 = (e->tRC << 24 | (e->tRFC & 0x7f) << 17 | e->tRAS << 8 | e->tRP);
|
||||||
|
timing->reg_1 = (nv_rd32(dev,0x10f294) & 0xff000000) | (e->tUNK_11&0x0f) << 20 | (e->tUNK_19 << 7) | (e->tUNK_2 & 0x0f);
|
||||||
|
timing->reg_2 = (nv_rd32(dev,0x10f298) & 0xff0000ff) | e->tUNK_0 << 16 | e->tUNK_1 << 8;
|
||||||
|
timing->reg_3 = e->tUNK_20 << 9 | e->tUNK_13;
|
||||||
|
timing->reg_4 = (nv_rd32(dev,0x10f2a0) & 0xfff000ff) | e->tUNK_12 << 15;
|
||||||
|
NV_DEBUG(dev, "Entry %d: 290: %08x %08x %08x %08x\n", timing->id,
|
||||||
|
timing->reg_0, timing->reg_1,
|
||||||
|
timing->reg_2, timing->reg_3);
|
||||||
|
NV_DEBUG(dev, " 2a0: %08x %08x %08x %08x\n",
|
||||||
|
timing->reg_4, timing->reg_5,
|
||||||
|
timing->reg_6, timing->reg_7);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes the Memory Timing BIOS table, stores generated
|
||||||
|
* register values
|
||||||
|
* @pre init scripts were run, memtiming regs are initialized
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
nouveau_mem_timing_init(struct drm_device *dev)
|
nouveau_mem_timing_init(struct drm_device *dev)
|
||||||
{
|
{
|
||||||
/* cards < NVC0 only */
|
|
||||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||||
struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
|
struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
|
||||||
struct nouveau_pm_memtimings *memtimings = &pm->memtimings;
|
struct nouveau_pm_memtimings *memtimings = &pm->memtimings;
|
||||||
struct nvbios *bios = &dev_priv->vbios;
|
struct nvbios *bios = &dev_priv->vbios;
|
||||||
struct bit_entry P;
|
struct bit_entry P;
|
||||||
u8 tUNK_0, tUNK_1, tUNK_2;
|
struct nouveau_pm_tbl_header *hdr = NULL;
|
||||||
u8 tRP; /* Byte 3 */
|
uint8_t magic_number;
|
||||||
u8 tRAS; /* Byte 5 */
|
u8 *entry;
|
||||||
u8 tRFC; /* Byte 7 */
|
int i;
|
||||||
u8 tRC; /* Byte 9 */
|
|
||||||
u8 tUNK_10, tUNK_11, tUNK_12, tUNK_13, tUNK_14;
|
|
||||||
u8 tUNK_18, tUNK_19, tUNK_20, tUNK_21;
|
|
||||||
u8 magic_number = 0; /* Yeah... sorry*/
|
|
||||||
u8 *mem = NULL, *entry;
|
|
||||||
int i, recordlen, entries;
|
|
||||||
|
|
||||||
if (bios->type == NVBIOS_BIT) {
|
if (bios->type == NVBIOS_BIT) {
|
||||||
if (bit_table(dev, 'P', &P))
|
if (bit_table(dev, 'P', &P))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (P.version == 1)
|
if (P.version == 1)
|
||||||
mem = ROMPTR(bios, P.data[4]);
|
hdr = (struct nouveau_pm_tbl_header *) ROMPTR(bios, P.data[4]);
|
||||||
else
|
else
|
||||||
if (P.version == 2)
|
if (P.version == 2)
|
||||||
mem = ROMPTR(bios, P.data[8]);
|
hdr = (struct nouveau_pm_tbl_header *) ROMPTR(bios, P.data[8]);
|
||||||
else {
|
else {
|
||||||
NV_WARN(dev, "unknown mem for BIT P %d\n", P.version);
|
NV_WARN(dev, "unknown mem for BIT P %d\n", P.version);
|
||||||
}
|
}
|
||||||
|
@ -539,150 +650,54 @@ nouveau_mem_timing_init(struct drm_device *dev)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mem) {
|
if (!hdr) {
|
||||||
NV_DEBUG(dev, "memory timing table pointer invalid\n");
|
NV_DEBUG(dev, "memory timing table pointer invalid\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mem[0] != 0x10) {
|
if (hdr->version != 0x10) {
|
||||||
NV_WARN(dev, "memory timing table 0x%02x unknown\n", mem[0]);
|
NV_WARN(dev, "memory timing table 0x%02x unknown\n", hdr->version);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* validate record length */
|
/* validate record length */
|
||||||
entries = mem[2];
|
if (hdr->entry_len < 15) {
|
||||||
recordlen = mem[3];
|
NV_ERROR(dev, "mem timing table length unknown: %d\n", hdr->entry_len);
|
||||||
if (recordlen < 15) {
|
|
||||||
NV_ERROR(dev, "mem timing table length unknown: %d\n", mem[3]);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parse vbios entries into common format */
|
/* parse vbios entries into common format */
|
||||||
memtimings->timing =
|
memtimings->timing =
|
||||||
kcalloc(entries, sizeof(*memtimings->timing), GFP_KERNEL);
|
kcalloc(hdr->entry_cnt, sizeof(*memtimings->timing), GFP_KERNEL);
|
||||||
if (!memtimings->timing)
|
if (!memtimings->timing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Get "some number" from the timing reg for NV_40 and NV_50
|
/* Get "some number" from the timing reg for NV_40 and NV_50
|
||||||
* Used in calculations later */
|
* Used in calculations later... source unknown */
|
||||||
if (dev_priv->card_type >= NV_40 && dev_priv->chipset < 0x98) {
|
magic_number = 0;
|
||||||
|
if (P.version == 1) {
|
||||||
magic_number = (nv_rd32(dev, 0x100228) & 0x0f000000) >> 24;
|
magic_number = (nv_rd32(dev, 0x100228) & 0x0f000000) >> 24;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = mem + mem[1];
|
entry = (u8*) hdr + hdr->header_len;
|
||||||
for (i = 0; i < entries; i++, entry += recordlen) {
|
for (i = 0; i < hdr->entry_cnt; i++, entry += hdr->entry_len) {
|
||||||
struct nouveau_pm_memtiming *timing = &pm->memtimings.timing[i];
|
struct nouveau_pm_memtiming *timing = &pm->memtimings.timing[i];
|
||||||
if (entry[0] == 0)
|
if (entry[0] == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
tUNK_18 = 1;
|
|
||||||
tUNK_19 = 1;
|
|
||||||
tUNK_20 = 0;
|
|
||||||
tUNK_21 = 0;
|
|
||||||
switch (min(recordlen, 22)) {
|
|
||||||
case 22:
|
|
||||||
tUNK_21 = entry[21];
|
|
||||||
case 21:
|
|
||||||
tUNK_20 = entry[20];
|
|
||||||
case 20:
|
|
||||||
tUNK_19 = entry[19];
|
|
||||||
case 19:
|
|
||||||
tUNK_18 = entry[18];
|
|
||||||
default:
|
|
||||||
tUNK_0 = entry[0];
|
|
||||||
tUNK_1 = entry[1];
|
|
||||||
tUNK_2 = entry[2];
|
|
||||||
tRP = entry[3];
|
|
||||||
tRAS = entry[5];
|
|
||||||
tRFC = entry[7];
|
|
||||||
tRC = entry[9];
|
|
||||||
tUNK_10 = entry[10];
|
|
||||||
tUNK_11 = entry[11];
|
|
||||||
tUNK_12 = entry[12];
|
|
||||||
tUNK_13 = entry[13];
|
|
||||||
tUNK_14 = entry[14];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
timing->reg_100220 = (tRC << 24 | tRFC << 16 | tRAS << 8 | tRP);
|
|
||||||
|
|
||||||
/* 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 |
|
|
||||||
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);
|
|
||||||
} else {
|
|
||||||
timing->reg_100224 |= (tUNK_2 + 2 - magic_number);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
} else if (dev_priv->card_type >= NV_50) {
|
|
||||||
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);
|
|
||||||
|
|
||||||
timing->reg_100234 = (tRAS << 24 | tRC);
|
|
||||||
timing->reg_100234 += max(tUNK_10, tUNK_11) << 16;
|
|
||||||
|
|
||||||
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_100238: 0x00?????? */
|
|
||||||
timing->reg_10023c = 0x202;
|
|
||||||
if (dev_priv->chipset < 0x98 ||
|
|
||||||
(dev_priv->chipset == 0x98 &&
|
|
||||||
dev_priv->stepping <= 0xa1)) {
|
|
||||||
timing->reg_10023c |= 0x4000000 | (tUNK_2 - 1) << 16;
|
|
||||||
} else {
|
|
||||||
/* XXX: reg_10023c
|
|
||||||
* currently unknown
|
|
||||||
* 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* XXX: reg_100240? */
|
|
||||||
}
|
|
||||||
timing->id = i;
|
timing->id = i;
|
||||||
|
|
||||||
NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i,
|
if(dev_priv->card_type <= NV_40) {
|
||||||
timing->reg_100220, timing->reg_100224,
|
nv40_mem_timing_entry(dev,hdr,(struct nouveau_pm_tbl_entry*) entry,magic_number,&pm->memtimings.timing[i]);
|
||||||
timing->reg_100228, timing->reg_10022c);
|
} else if(dev_priv->card_type == NV_50){
|
||||||
NV_DEBUG(dev, " 230: %08x %08x %08x %08x\n",
|
nv50_mem_timing_entry(dev,&P,hdr,(struct nouveau_pm_tbl_entry*) entry,magic_number,&pm->memtimings.timing[i]);
|
||||||
timing->reg_100230, timing->reg_100234,
|
} else if(dev_priv->card_type == NV_C0) {
|
||||||
timing->reg_100238, timing->reg_10023c);
|
nvc0_mem_timing_entry(dev,hdr,(struct nouveau_pm_tbl_entry*) entry,&pm->memtimings.timing[i]);
|
||||||
NV_DEBUG(dev, " 240: %08x\n", timing->reg_100240);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memtimings->nr_timing = entries;
|
memtimings->nr_timing = hdr->entry_cnt;
|
||||||
memtimings->supported = (dev_priv->chipset <= 0x98);
|
memtimings->supported = P.version == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -691,7 +706,10 @@ nouveau_mem_timing_fini(struct drm_device *dev)
|
||||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||||
struct nouveau_pm_memtimings *mem = &dev_priv->engine.pm.memtimings;
|
struct nouveau_pm_memtimings *mem = &dev_priv->engine.pm.memtimings;
|
||||||
|
|
||||||
kfree(mem->timing);
|
if(mem->timing) {
|
||||||
|
kfree(mem->timing);
|
||||||
|
mem->timing = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|
|
@ -185,6 +185,8 @@ nouveau_perf_init(struct drm_device *dev)
|
||||||
struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
|
struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
|
||||||
struct nvbios *bios = &dev_priv->vbios;
|
struct nvbios *bios = &dev_priv->vbios;
|
||||||
struct bit_entry P;
|
struct bit_entry P;
|
||||||
|
struct nouveau_pm_memtimings *memtimings = &pm->memtimings;
|
||||||
|
struct nouveau_pm_tbl_header mt_hdr;
|
||||||
u8 version, headerlen, recordlen, entries;
|
u8 version, headerlen, recordlen, entries;
|
||||||
u8 *perf, *entry;
|
u8 *perf, *entry;
|
||||||
int vid, i;
|
int vid, i;
|
||||||
|
@ -232,6 +234,22 @@ nouveau_perf_init(struct drm_device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = perf + headerlen;
|
entry = perf + headerlen;
|
||||||
|
|
||||||
|
/* For version 0x15, initialize memtiming table */
|
||||||
|
if(version == 0x15) {
|
||||||
|
memtimings->timing =
|
||||||
|
kcalloc(entries, sizeof(*memtimings->timing), GFP_KERNEL);
|
||||||
|
if(!memtimings) {
|
||||||
|
NV_WARN(dev,"Could not allocate memtiming table\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mt_hdr.entry_cnt = entries;
|
||||||
|
mt_hdr.entry_len = 14;
|
||||||
|
mt_hdr.version = version;
|
||||||
|
mt_hdr.header_len = 4;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < entries; i++) {
|
for (i = 0; i < entries; i++) {
|
||||||
struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl];
|
struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl];
|
||||||
|
|
||||||
|
@ -321,7 +339,11 @@ nouveau_perf_init(struct drm_device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get the corresponding memory timings */
|
/* get the corresponding memory timings */
|
||||||
if (version > 0x15) {
|
if (version == 0x15) {
|
||||||
|
memtimings->timing[i].id = i;
|
||||||
|
nv30_mem_timing_entry(dev,&mt_hdr,(struct nouveau_pm_tbl_entry*) &entry[41],0,&memtimings->timing[i]);
|
||||||
|
perflvl->timing = &memtimings->timing[i];
|
||||||
|
} else if (version > 0x15) {
|
||||||
/* last 3 args are for < 0x40, ignored for >= 0x40 */
|
/* last 3 args are for < 0x40, ignored for >= 0x40 */
|
||||||
perflvl->timing =
|
perflvl->timing =
|
||||||
nouveau_perf_timing(dev, &P,
|
nouveau_perf_timing(dev, &P,
|
||||||
|
|
|
@ -1028,13 +1028,11 @@ 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)
|
||||||
|
|
Loading…
Reference in New Issue