diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2013-11-27 00:12:53 -0500 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2014-01-22 22:38:49 -0500 |
commit | d394fb12eca4cb9f42f922d7ae2bc8d7e1ed9272 (patch) | |
tree | f7fed4547942d1cab82e24fe964bde7def6d2bdf | |
parent | dd95c8f782a053db361855298778a7d31de04a48 (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.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/fb/gddr5.c | 18 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/fb/priv.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c | 70 |
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 | ||
28 | int | 28 | int |
29 | nouveau_gddr5_calc(struct nouveau_ram *ram) | 29 | nouveau_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; | |||
34 | extern struct nouveau_oclass nve0_ram_oclass; | 34 | extern struct nouveau_oclass nve0_ram_oclass; |
35 | 35 | ||
36 | int nouveau_sddr3_calc(struct nouveau_ram *ram); | 36 | int nouveau_sddr3_calc(struct nouveau_ram *ram); |
37 | int nouveau_gddr5_calc(struct nouveau_ram *ram); | 37 | int 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 { | |||
123 | struct nve0_ram { | 125 | struct 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 | |||
136 | nve0_ram_train(struct nve0_ramfuc *fuc, u32 magic) | 143 | nve0_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 | ||
229 | static void | ||
230 | nve0_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 | |||
225 | static int | 251 | static int |
226 | nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq) | 252 | nve0_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) { |