Commit d394fb12 authored by Ben Skeggs's avatar Ben Skeggs

drm/nve0/fb/gddr5: not all memory partitions are created equal

As seen when comparing us vs nv on my GTX660.
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent dd95c8f7
...@@ -142,6 +142,7 @@ struct nouveau_ram { ...@@ -142,6 +142,7 @@ struct nouveau_ram {
} rammap, ramcfg, timing; } rammap, ramcfg, timing;
u32 freq; u32 freq;
u32 mr[16]; u32 mr[16];
u32 mr1_nuts;
}; };
#endif #endif
...@@ -26,11 +26,11 @@ ...@@ -26,11 +26,11 @@
#include "priv.h" #include "priv.h"
int int
nouveau_gddr5_calc(struct nouveau_ram *ram) nouveau_gddr5_calc(struct nouveau_ram *ram, bool nuts)
{ {
struct nouveau_bios *bios = nouveau_bios(ram); struct nouveau_bios *bios = nouveau_bios(ram);
int pd, lf, xd, vh, vr, vo; int pd, lf, xd, vh, vr, vo;
int WL, CL, WR, at, dt, ds; int WL, CL, WR, at[2], dt, ds;
int rq = ram->freq < 1000000; /* XXX */ int rq = ram->freq < 1000000; /* XXX */
switch (!!ram->ramcfg.data * ram->ramcfg.version) { switch (!!ram->ramcfg.data * ram->ramcfg.version) {
...@@ -51,7 +51,8 @@ nouveau_gddr5_calc(struct nouveau_ram *ram) ...@@ -51,7 +51,8 @@ nouveau_gddr5_calc(struct nouveau_ram *ram)
WL = (nv_ro16(bios, ram->timing.data + 0x04) & 0x0f80) >> 7; WL = (nv_ro16(bios, ram->timing.data + 0x04) & 0x0f80) >> 7;
CL = nv_ro08(bios, ram->timing.data + 0x04) & 0x1f; CL = nv_ro08(bios, ram->timing.data + 0x04) & 0x1f;
WR = nv_ro08(bios, ram->timing.data + 0x0a) & 0x7f; WR = nv_ro08(bios, ram->timing.data + 0x0a) & 0x7f;
at = (nv_ro08(bios, ram->timing.data + 0x2e) & 0xc0) >> 6; at[0] = (nv_ro08(bios, ram->timing.data + 0x2e) & 0xc0) >> 6;
at[1] = (nv_ro08(bios, ram->timing.data + 0x2e) & 0x30) >> 4;
dt = nv_ro08(bios, ram->timing.data + 0x2e) & 0x03; dt = nv_ro08(bios, ram->timing.data + 0x2e) & 0x03;
ds = nv_ro08(bios, ram->timing.data + 0x2f) & 0x03; ds = nv_ro08(bios, ram->timing.data + 0x2f) & 0x03;
break; break;
...@@ -71,10 +72,19 @@ nouveau_gddr5_calc(struct nouveau_ram *ram) ...@@ -71,10 +72,19 @@ nouveau_gddr5_calc(struct nouveau_ram *ram)
ram->mr[1] &= ~0x0bf; ram->mr[1] &= ~0x0bf;
ram->mr[1] |= (xd & 0x01) << 7; ram->mr[1] |= (xd & 0x01) << 7;
ram->mr[1] |= (at & 0x03) << 4; ram->mr[1] |= (at[0] & 0x03) << 4;
ram->mr[1] |= (dt & 0x03) << 2; ram->mr[1] |= (dt & 0x03) << 2;
ram->mr[1] |= (ds & 0x03) << 0; ram->mr[1] |= (ds & 0x03) << 0;
/* this seems wrong, alternate field used for the broadcast
* on nuts vs non-nuts configs.. meh, it matches for now.
*/
ram->mr1_nuts = ram->mr[1];
if (nuts) {
ram->mr[1] &= ~0x030;
ram->mr[1] |= (at[1] & 0x03) << 4;
}
ram->mr[3] &= ~0x020; ram->mr[3] &= ~0x020;
ram->mr[3] |= (rq & 0x01) << 5; ram->mr[3] |= (rq & 0x01) << 5;
......
...@@ -34,7 +34,7 @@ extern struct nouveau_oclass nvc0_ram_oclass; ...@@ -34,7 +34,7 @@ extern struct nouveau_oclass nvc0_ram_oclass;
extern struct nouveau_oclass nve0_ram_oclass; extern struct nouveau_oclass nve0_ram_oclass;
int nouveau_sddr3_calc(struct nouveau_ram *ram); int nouveau_sddr3_calc(struct nouveau_ram *ram);
int nouveau_gddr5_calc(struct nouveau_ram *ram); int nouveau_gddr5_calc(struct nouveau_ram *ram, bool nuts);
#define nouveau_fb_create(p,e,c,d) \ #define nouveau_fb_create(p,e,c,d) \
nouveau_fb_create_((p), (e), (c), sizeof(**d), (void **)d) nouveau_fb_create_((p), (e), (c), sizeof(**d), (void **)d)
......
...@@ -103,7 +103,9 @@ struct nve0_ramfuc { ...@@ -103,7 +103,9 @@ struct nve0_ramfuc {
struct ramfuc_reg r_mr[16]; /* MR0 - MR8, MR15 */ struct ramfuc_reg r_mr[16]; /* MR0 - MR8, MR15 */
struct ramfuc_reg r_0x62c000; struct ramfuc_reg r_0x62c000;
struct ramfuc_reg r_0x10f200; struct ramfuc_reg r_0x10f200;
struct ramfuc_reg r_0x10f210; struct ramfuc_reg r_0x10f210;
struct ramfuc_reg r_0x10f310; struct ramfuc_reg r_0x10f310;
struct ramfuc_reg r_0x10f314; struct ramfuc_reg r_0x10f314;
...@@ -123,6 +125,11 @@ struct nve0_ramfuc { ...@@ -123,6 +125,11 @@ struct nve0_ramfuc {
struct nve0_ram { struct nve0_ram {
struct nouveau_ram base; struct nouveau_ram base;
struct nve0_ramfuc fuc; struct nve0_ramfuc fuc;
u32 parts;
u32 pmask;
u32 pnuts;
int from; int from;
int mode; int mode;
int N1, fN1, M1, P1; int N1, fN1, M1, P1;
...@@ -136,16 +143,13 @@ static void ...@@ -136,16 +143,13 @@ static void
nve0_ram_train(struct nve0_ramfuc *fuc, u32 magic) nve0_ram_train(struct nve0_ramfuc *fuc, u32 magic)
{ {
struct nve0_ram *ram = container_of(fuc, typeof(*ram), fuc); struct nve0_ram *ram = container_of(fuc, typeof(*ram), fuc);
struct nouveau_fb *pfb = nouveau_fb(ram); u32 addr = 0x110974, i;
u32 part = nv_rd32(pfb, 0x022438), i;
u32 mask = nv_rd32(pfb, 0x022554);
u32 addr = 0x110974;
ram_mask(fuc, 0x10f910, 0xbc0e0000, magic); ram_mask(fuc, 0x10f910, 0xbc0e0000, magic);
ram_mask(fuc, 0x10f914, 0xbc0e0000, magic); ram_mask(fuc, 0x10f914, 0xbc0e0000, magic);
for (i = 0; (magic & 0x80000000) && i < part; addr += 0x1000, i++) { for (i = 0; (magic & 0x80000000) && i < ram->parts; addr += 0x1000, i++) {
if (mask & (1 << i)) if (ram->pmask & (1 << i))
continue; continue;
ram_wait(fuc, addr, 0x0000000f, 0x00000000, 500000); ram_wait(fuc, addr, 0x0000000f, 0x00000000, 500000);
} }
...@@ -222,6 +226,28 @@ r1373f4_fini(struct nve0_ramfuc *fuc, u32 ramcfg) ...@@ -222,6 +226,28 @@ r1373f4_fini(struct nve0_ramfuc *fuc, u32 ramcfg)
ram_mask(fuc, 0x10f800, 0x00000030, (v0 ^ v1) << 4); ram_mask(fuc, 0x10f800, 0x00000030, (v0 ^ v1) << 4);
} }
static void
nve0_ram_nuts(struct nve0_ram *ram, struct ramfuc_reg *reg,
u32 _mask, u32 _data, u32 _copy)
{
struct nve0_fb_priv *priv = (void *)nouveau_fb(ram);
struct ramfuc *fuc = &ram->fuc.base;
u32 addr = 0x110000 + (reg->addr[0] & 0xfff);
u32 mask = _mask | _copy;
u32 data = (_data & _mask) | (reg->data & _copy);
u32 i;
for (i = 0; i < 16; i++, addr += 0x1000) {
if (ram->pnuts & (1 << i)) {
u32 prev = nv_rd32(priv, addr);
u32 next = (prev & ~mask) | data;
nouveau_memx_wr32(fuc->memx, addr, next);
}
}
}
#define ram_nuts(s,r,m,d,c) \
nve0_ram_nuts((s), &(s)->fuc.r_##r, (m), (d), (c))
static int static int
nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq) nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
{ {
...@@ -233,14 +259,16 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq) ...@@ -233,14 +259,16 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
const u32 timing = ram->base.timing.data; const u32 timing = ram->base.timing.data;
int vc = !(nv_ro08(bios, ramcfg + 0x02) & 0x08); int vc = !(nv_ro08(bios, ramcfg + 0x02) & 0x08);
int mv = 1; /*XXX*/ int mv = 1; /*XXX*/
u32 mask, data; u32 mask, data, i;
ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000); ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000);
ram_wr32(fuc, 0x62c000, 0x0f0f0000); ram_wr32(fuc, 0x62c000, 0x0f0f0000);
/* MR1: turn termination on early, for some reason.. */ /* MR1: turn termination on early, for some reason.. */
if ((ram->base.mr[1] & 0x03c) != 0x030) if ((ram->base.mr[1] & 0x03c) != 0x030) {
ram_mask(fuc, mr[1], 0x03c, ram->base.mr[1] & 0x03c); ram_mask(fuc, mr[1], 0x03c, ram->base.mr[1] & 0x03c);
ram_nuts(ram, mr[1], 0x03c, ram->base.mr1_nuts & 0x03c, 0x000);
}
if (vc == 1 && ram_have(fuc, gpio2E)) { if (vc == 1 && ram_have(fuc, gpio2E)) {
u32 temp = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[1]); u32 temp = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[1]);
...@@ -546,6 +574,7 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq) ...@@ -546,6 +574,7 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
ram_wr32(fuc, 0x10f318, 0x00000001); /* NOP? */ ram_wr32(fuc, 0x10f318, 0x00000001); /* NOP? */
ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000); ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000);
ram_nsec(fuc, 1000); ram_nsec(fuc, 1000);
ram_nuts(ram, 0x10f200, 0x00808800, 0x00000000, 0x00808800);
data = ram_rd32(fuc, 0x10f978); data = ram_rd32(fuc, 0x10f978);
data &= ~0x00046144; data &= ~0x00046144;
...@@ -603,6 +632,7 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq) ...@@ -603,6 +632,7 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
else else
data = 0x00000000; data = 0x00000000;
ram_mask(fuc, 0x10f200, 0x00000800, data); ram_mask(fuc, 0x10f200, 0x00000800, data);
ram_nuts(ram, 0x10f200, 0x00808800, data, 0x00808800);
return 0; return 0;
} }
...@@ -980,7 +1010,7 @@ nve0_ram_calc(struct nouveau_fb *pfb, u32 freq) ...@@ -980,7 +1010,7 @@ nve0_ram_calc(struct nouveau_fb *pfb, u32 freq)
ret = nve0_ram_calc_sddr3(pfb, freq); ret = nve0_ram_calc_sddr3(pfb, freq);
break; break;
case NV_MEM_TYPE_GDDR5: case NV_MEM_TYPE_GDDR5:
ret = nouveau_gddr5_calc(&ram->base); ret = nouveau_gddr5_calc(&ram->base, ram->pnuts != 0);
if (ret == 0) if (ret == 0)
ret = nve0_ram_calc_gddr5(pfb, freq); ret = nve0_ram_calc_gddr5(pfb, freq);
break; break;
...@@ -1109,7 +1139,8 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -1109,7 +1139,8 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_gpio *gpio = nouveau_gpio(pfb); struct nouveau_gpio *gpio = nouveau_gpio(pfb);
struct dcb_gpio_func func; struct dcb_gpio_func func;
struct nve0_ram *ram; struct nve0_ram *ram;
int ret; int ret, i;
u32 tmp;
ret = nvc0_ram_create(parent, engine, oclass, &ram); ret = nvc0_ram_create(parent, engine, oclass, &ram);
*pobject = nv_object(ram); *pobject = nv_object(ram);
...@@ -1128,6 +1159,25 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -1128,6 +1159,25 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
break; break;
} }
/* calculate a mask of differently configured memory partitions,
* because, of course reclocking wasn't complicated enough
* already without having to treat some of them differently to
* the others....
*/
ram->parts = nv_rd32(pfb, 0x022438);
ram->pmask = nv_rd32(pfb, 0x022554);
ram->pnuts = 0;
for (i = 0, tmp = 0; i < ram->parts; i++) {
if (!(ram->pmask & (1 << i))) {
u32 cfg1 = nv_rd32(pfb, 0x110204 + (i * 0x1000));
if (tmp && tmp != cfg1) {
ram->pnuts |= (1 << i);
continue;
}
tmp = cfg1;
}
}
// parse bios data for both pll's // parse bios data for both pll's
ret = nvbios_pll_parse(bios, 0x0c, &ram->fuc.refpll); ret = nvbios_pll_parse(bios, 0x0c, &ram->fuc.refpll);
if (ret) { if (ret) {
......
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