aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2013-11-27 00:12:53 -0500
committerBen Skeggs <bskeggs@redhat.com>2014-01-22 22:38:49 -0500
commitd394fb12eca4cb9f42f922d7ae2bc8d7e1ed9272 (patch)
treef7fed4547942d1cab82e24fe964bde7def6d2bdf
parentdd95c8f782a053db361855298778a7d31de04a48 (diff)
drm/nve0/fb/gddr5: not all memory partitions are created equal
As seen when comparing us vs nv on my GTX660. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/fb.h1
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/gddr5.c18
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/priv.h2
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c70
4 files changed, 76 insertions, 15 deletions
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/fb.h b/drivers/gpu/drm/nouveau/core/include/subdev/fb.h
index d89dbdf39b0d..ef7795305fe6 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/fb.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/fb.h
@@ -142,6 +142,7 @@ struct nouveau_ram {
142 } rammap, ramcfg, timing; 142 } rammap, ramcfg, timing;
143 u32 freq; 143 u32 freq;
144 u32 mr[16]; 144 u32 mr[16];
145 u32 mr1_nuts;
145}; 146};
146 147
147#endif 148#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/gddr5.c b/drivers/gpu/drm/nouveau/core/subdev/fb/gddr5.c
index 012c1eab8467..409c74e6ed77 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/gddr5.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/gddr5.c
@@ -26,11 +26,11 @@
26#include "priv.h" 26#include "priv.h"
27 27
28int 28int
29nouveau_gddr5_calc(struct nouveau_ram *ram) 29nouveau_gddr5_calc(struct nouveau_ram *ram, bool nuts)
30{ 30{
31 struct nouveau_bios *bios = nouveau_bios(ram); 31 struct nouveau_bios *bios = nouveau_bios(ram);
32 int pd, lf, xd, vh, vr, vo; 32 int pd, lf, xd, vh, vr, vo;
33 int WL, CL, WR, at, dt, ds; 33 int WL, CL, WR, at[2], dt, ds;
34 int rq = ram->freq < 1000000; /* XXX */ 34 int rq = ram->freq < 1000000; /* XXX */
35 35
36 switch (!!ram->ramcfg.data * ram->ramcfg.version) { 36 switch (!!ram->ramcfg.data * ram->ramcfg.version) {
@@ -51,7 +51,8 @@ nouveau_gddr5_calc(struct nouveau_ram *ram)
51 WL = (nv_ro16(bios, ram->timing.data + 0x04) & 0x0f80) >> 7; 51 WL = (nv_ro16(bios, ram->timing.data + 0x04) & 0x0f80) >> 7;
52 CL = nv_ro08(bios, ram->timing.data + 0x04) & 0x1f; 52 CL = nv_ro08(bios, ram->timing.data + 0x04) & 0x1f;
53 WR = nv_ro08(bios, ram->timing.data + 0x0a) & 0x7f; 53 WR = nv_ro08(bios, ram->timing.data + 0x0a) & 0x7f;
54 at = (nv_ro08(bios, ram->timing.data + 0x2e) & 0xc0) >> 6; 54 at[0] = (nv_ro08(bios, ram->timing.data + 0x2e) & 0xc0) >> 6;
55 at[1] = (nv_ro08(bios, ram->timing.data + 0x2e) & 0x30) >> 4;
55 dt = nv_ro08(bios, ram->timing.data + 0x2e) & 0x03; 56 dt = nv_ro08(bios, ram->timing.data + 0x2e) & 0x03;
56 ds = nv_ro08(bios, ram->timing.data + 0x2f) & 0x03; 57 ds = nv_ro08(bios, ram->timing.data + 0x2f) & 0x03;
57 break; 58 break;
@@ -71,10 +72,19 @@ nouveau_gddr5_calc(struct nouveau_ram *ram)
71 72
72 ram->mr[1] &= ~0x0bf; 73 ram->mr[1] &= ~0x0bf;
73 ram->mr[1] |= (xd & 0x01) << 7; 74 ram->mr[1] |= (xd & 0x01) << 7;
74 ram->mr[1] |= (at & 0x03) << 4; 75 ram->mr[1] |= (at[0] & 0x03) << 4;
75 ram->mr[1] |= (dt & 0x03) << 2; 76 ram->mr[1] |= (dt & 0x03) << 2;
76 ram->mr[1] |= (ds & 0x03) << 0; 77 ram->mr[1] |= (ds & 0x03) << 0;
77 78
79 /* this seems wrong, alternate field used for the broadcast
80 * on nuts vs non-nuts configs.. meh, it matches for now.
81 */
82 ram->mr1_nuts = ram->mr[1];
83 if (nuts) {
84 ram->mr[1] &= ~0x030;
85 ram->mr[1] |= (at[1] & 0x03) << 4;
86 }
87
78 ram->mr[3] &= ~0x020; 88 ram->mr[3] &= ~0x020;
79 ram->mr[3] |= (rq & 0x01) << 5; 89 ram->mr[3] |= (rq & 0x01) << 5;
80 90
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h b/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
index 493125214e88..edaf95dee612 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
@@ -34,7 +34,7 @@ extern struct nouveau_oclass nvc0_ram_oclass;
34extern struct nouveau_oclass nve0_ram_oclass; 34extern struct nouveau_oclass nve0_ram_oclass;
35 35
36int nouveau_sddr3_calc(struct nouveau_ram *ram); 36int nouveau_sddr3_calc(struct nouveau_ram *ram);
37int nouveau_gddr5_calc(struct nouveau_ram *ram); 37int nouveau_gddr5_calc(struct nouveau_ram *ram, bool nuts);
38 38
39#define nouveau_fb_create(p,e,c,d) \ 39#define nouveau_fb_create(p,e,c,d) \
40 nouveau_fb_create_((p), (e), (c), sizeof(**d), (void **)d) 40 nouveau_fb_create_((p), (e), (c), sizeof(**d), (void **)d)
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c
index c7d2fee947cd..62230c2d8236 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c
@@ -103,7 +103,9 @@ struct nve0_ramfuc {
103 struct ramfuc_reg r_mr[16]; /* MR0 - MR8, MR15 */ 103 struct ramfuc_reg r_mr[16]; /* MR0 - MR8, MR15 */
104 104
105 struct ramfuc_reg r_0x62c000; 105 struct ramfuc_reg r_0x62c000;
106
106 struct ramfuc_reg r_0x10f200; 107 struct ramfuc_reg r_0x10f200;
108
107 struct ramfuc_reg r_0x10f210; 109 struct ramfuc_reg r_0x10f210;
108 struct ramfuc_reg r_0x10f310; 110 struct ramfuc_reg r_0x10f310;
109 struct ramfuc_reg r_0x10f314; 111 struct ramfuc_reg r_0x10f314;
@@ -123,6 +125,11 @@ struct nve0_ramfuc {
123struct nve0_ram { 125struct nve0_ram {
124 struct nouveau_ram base; 126 struct nouveau_ram base;
125 struct nve0_ramfuc fuc; 127 struct nve0_ramfuc fuc;
128
129 u32 parts;
130 u32 pmask;
131 u32 pnuts;
132
126 int from; 133 int from;
127 int mode; 134 int mode;
128 int N1, fN1, M1, P1; 135 int N1, fN1, M1, P1;
@@ -136,16 +143,13 @@ static void
136nve0_ram_train(struct nve0_ramfuc *fuc, u32 magic) 143nve0_ram_train(struct nve0_ramfuc *fuc, u32 magic)
137{ 144{
138 struct nve0_ram *ram = container_of(fuc, typeof(*ram), fuc); 145 struct nve0_ram *ram = container_of(fuc, typeof(*ram), fuc);
139 struct nouveau_fb *pfb = nouveau_fb(ram); 146 u32 addr = 0x110974, i;
140 u32 part = nv_rd32(pfb, 0x022438), i;
141 u32 mask = nv_rd32(pfb, 0x022554);
142 u32 addr = 0x110974;
143 147
144 ram_mask(fuc, 0x10f910, 0xbc0e0000, magic); 148 ram_mask(fuc, 0x10f910, 0xbc0e0000, magic);
145 ram_mask(fuc, 0x10f914, 0xbc0e0000, magic); 149 ram_mask(fuc, 0x10f914, 0xbc0e0000, magic);
146 150
147 for (i = 0; (magic & 0x80000000) && i < part; addr += 0x1000, i++) { 151 for (i = 0; (magic & 0x80000000) && i < ram->parts; addr += 0x1000, i++) {
148 if (mask & (1 << i)) 152 if (ram->pmask & (1 << i))
149 continue; 153 continue;
150 ram_wait(fuc, addr, 0x0000000f, 0x00000000, 500000); 154 ram_wait(fuc, addr, 0x0000000f, 0x00000000, 500000);
151 } 155 }
@@ -222,6 +226,28 @@ r1373f4_fini(struct nve0_ramfuc *fuc, u32 ramcfg)
222 ram_mask(fuc, 0x10f800, 0x00000030, (v0 ^ v1) << 4); 226 ram_mask(fuc, 0x10f800, 0x00000030, (v0 ^ v1) << 4);
223} 227}
224 228
229static void
230nve0_ram_nuts(struct nve0_ram *ram, struct ramfuc_reg *reg,
231 u32 _mask, u32 _data, u32 _copy)
232{
233 struct nve0_fb_priv *priv = (void *)nouveau_fb(ram);
234 struct ramfuc *fuc = &ram->fuc.base;
235 u32 addr = 0x110000 + (reg->addr[0] & 0xfff);
236 u32 mask = _mask | _copy;
237 u32 data = (_data & _mask) | (reg->data & _copy);
238 u32 i;
239
240 for (i = 0; i < 16; i++, addr += 0x1000) {
241 if (ram->pnuts & (1 << i)) {
242 u32 prev = nv_rd32(priv, addr);
243 u32 next = (prev & ~mask) | data;
244 nouveau_memx_wr32(fuc->memx, addr, next);
245 }
246 }
247}
248#define ram_nuts(s,r,m,d,c) \
249 nve0_ram_nuts((s), &(s)->fuc.r_##r, (m), (d), (c))
250
225static int 251static int
226nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq) 252nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
227{ 253{
@@ -233,14 +259,16 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
233 const u32 timing = ram->base.timing.data; 259 const u32 timing = ram->base.timing.data;
234 int vc = !(nv_ro08(bios, ramcfg + 0x02) & 0x08); 260 int vc = !(nv_ro08(bios, ramcfg + 0x02) & 0x08);
235 int mv = 1; /*XXX*/ 261 int mv = 1; /*XXX*/
236 u32 mask, data; 262 u32 mask, data, i;
237 263
238 ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000); 264 ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000);
239 ram_wr32(fuc, 0x62c000, 0x0f0f0000); 265 ram_wr32(fuc, 0x62c000, 0x0f0f0000);
240 266
241 /* MR1: turn termination on early, for some reason.. */ 267 /* MR1: turn termination on early, for some reason.. */
242 if ((ram->base.mr[1] & 0x03c) != 0x030) 268 if ((ram->base.mr[1] & 0x03c) != 0x030) {
243 ram_mask(fuc, mr[1], 0x03c, ram->base.mr[1] & 0x03c); 269 ram_mask(fuc, mr[1], 0x03c, ram->base.mr[1] & 0x03c);
270 ram_nuts(ram, mr[1], 0x03c, ram->base.mr1_nuts & 0x03c, 0x000);
271 }
244 272
245 if (vc == 1 && ram_have(fuc, gpio2E)) { 273 if (vc == 1 && ram_have(fuc, gpio2E)) {
246 u32 temp = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[1]); 274 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 ram_wr32(fuc, 0x10f318, 0x00000001); /* NOP? */ 574 ram_wr32(fuc, 0x10f318, 0x00000001); /* NOP? */
547 ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000); 575 ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000);
548 ram_nsec(fuc, 1000); 576 ram_nsec(fuc, 1000);
577 ram_nuts(ram, 0x10f200, 0x00808800, 0x00000000, 0x00808800);
549 578
550 data = ram_rd32(fuc, 0x10f978); 579 data = ram_rd32(fuc, 0x10f978);
551 data &= ~0x00046144; 580 data &= ~0x00046144;
@@ -603,6 +632,7 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
603 else 632 else
604 data = 0x00000000; 633 data = 0x00000000;
605 ram_mask(fuc, 0x10f200, 0x00000800, data); 634 ram_mask(fuc, 0x10f200, 0x00000800, data);
635 ram_nuts(ram, 0x10f200, 0x00808800, data, 0x00808800);
606 return 0; 636 return 0;
607} 637}
608 638
@@ -980,7 +1010,7 @@ nve0_ram_calc(struct nouveau_fb *pfb, u32 freq)
980 ret = nve0_ram_calc_sddr3(pfb, freq); 1010 ret = nve0_ram_calc_sddr3(pfb, freq);
981 break; 1011 break;
982 case NV_MEM_TYPE_GDDR5: 1012 case NV_MEM_TYPE_GDDR5:
983 ret = nouveau_gddr5_calc(&ram->base); 1013 ret = nouveau_gddr5_calc(&ram->base, ram->pnuts != 0);
984 if (ret == 0) 1014 if (ret == 0)
985 ret = nve0_ram_calc_gddr5(pfb, freq); 1015 ret = nve0_ram_calc_gddr5(pfb, freq);
986 break; 1016 break;
@@ -1109,7 +1139,8 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
1109 struct nouveau_gpio *gpio = nouveau_gpio(pfb); 1139 struct nouveau_gpio *gpio = nouveau_gpio(pfb);
1110 struct dcb_gpio_func func; 1140 struct dcb_gpio_func func;
1111 struct nve0_ram *ram; 1141 struct nve0_ram *ram;
1112 int ret; 1142 int ret, i;
1143 u32 tmp;
1113 1144
1114 ret = nvc0_ram_create(parent, engine, oclass, &ram); 1145 ret = nvc0_ram_create(parent, engine, oclass, &ram);
1115 *pobject = nv_object(ram); 1146 *pobject = nv_object(ram);
@@ -1128,6 +1159,25 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
1128 break; 1159 break;
1129 } 1160 }
1130 1161
1162 /* calculate a mask of differently configured memory partitions,
1163 * because, of course reclocking wasn't complicated enough
1164 * already without having to treat some of them differently to
1165 * the others....
1166 */
1167 ram->parts = nv_rd32(pfb, 0x022438);
1168 ram->pmask = nv_rd32(pfb, 0x022554);
1169 ram->pnuts = 0;
1170 for (i = 0, tmp = 0; i < ram->parts; i++) {
1171 if (!(ram->pmask & (1 << i))) {
1172 u32 cfg1 = nv_rd32(pfb, 0x110204 + (i * 0x1000));
1173 if (tmp && tmp != cfg1) {
1174 ram->pnuts |= (1 << i);
1175 continue;
1176 }
1177 tmp = cfg1;
1178 }
1179 }
1180
1131 // parse bios data for both pll's 1181 // parse bios data for both pll's
1132 ret = nvbios_pll_parse(bios, 0x0c, &ram->fuc.refpll); 1182 ret = nvbios_pll_parse(bios, 0x0c, &ram->fuc.refpll);
1133 if (ret) { 1183 if (ret) {