aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2012-01-16 07:34:03 -0500
committerBen Skeggs <bskeggs@redhat.com>2012-03-13 03:07:00 -0400
commit03ddf04bdb9cc4cdf8edb231b78f031647498314 (patch)
tree198b81c5b8660bce756ec0087ae0970e309e6e4b /drivers/gpu
parent3d8a408c43828d586629204fe22134ae8f39b8be (diff)
drm/nouveau/pm: restructure bios table parsing
It turns out we need access to some additional information in various VBIOS tables to handle PFB memory timings correctly. Rather than hack in parsing of the new stuff in some kludgy way, I've restructured the VBIOS parsing to be more primitive, so we can use them in more flexible ways in the future. The perflvl->timing association code is disabled for the moment until it can be reworked. We don't use this stuff yet anyway, so no harm done. Signed-off-by: Ben Skeggs <bskeggs@redhat.com> Signed-off-by: Martin Peres <martin.peres@labri.fr>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_perf.c390
1 files changed, 217 insertions, 173 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_perf.c b/drivers/gpu/drm/nouveau/nouveau_perf.c
index 2ca26f39292a..ad990553d115 100644
--- a/drivers/gpu/drm/nouveau/nouveau_perf.c
+++ b/drivers/gpu/drm/nouveau/nouveau_perf.c
@@ -27,6 +27,178 @@
27#include "nouveau_drv.h" 27#include "nouveau_drv.h"
28#include "nouveau_pm.h" 28#include "nouveau_pm.h"
29 29
30static u8 *
31nouveau_perf_table(struct drm_device *dev, u8 *ver)
32{
33 struct drm_nouveau_private *dev_priv = dev->dev_private;
34 struct nvbios *bios = &dev_priv->vbios;
35 struct bit_entry P;
36
37 if (!bit_table(dev, 'P', &P) && P.version && P.version <= 2) {
38 u8 *perf = ROMPTR(dev, P.data[0]);
39 if (perf) {
40 *ver = perf[0];
41 return perf;
42 }
43 }
44
45 if (bios->type == NVBIOS_BMP) {
46 if (bios->data[bios->offset + 6] >= 0x25) {
47 u8 *perf = ROMPTR(dev, bios->data[bios->offset + 0x94]);
48 if (perf) {
49 *ver = perf[1];
50 return perf;
51 }
52 }
53 }
54
55 return NULL;
56}
57
58static u8 *
59nouveau_perf_entry(struct drm_device *dev, int idx,
60 u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
61{
62 u8 *perf = nouveau_perf_table(dev, ver);
63 if (perf) {
64 if (*ver >= 0x12 && *ver < 0x20 && idx < perf[2]) {
65 *hdr = perf[3];
66 *cnt = 0;
67 *len = 0;
68 return perf + perf[0] + idx * perf[3];
69 } else
70 if (*ver >= 0x20 && *ver < 0x40 && idx < perf[2]) {
71 *hdr = perf[3];
72 *cnt = perf[4];
73 *len = perf[5];
74 return perf + perf[1] + idx * (*hdr + (*cnt * *len));
75 } else
76 if (*ver >= 0x40 && *ver < 0x41 && idx < perf[5]) {
77 *hdr = perf[2];
78 *cnt = perf[4];
79 *len = perf[3];
80 return perf + perf[1] + idx * (*hdr + (*cnt * *len));
81 }
82 }
83 return NULL;
84}
85
86static u8 *
87nouveau_perf_rammap(struct drm_device *dev, u32 freq,
88 u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
89{
90 struct drm_nouveau_private *dev_priv = dev->dev_private;
91 struct bit_entry P;
92 u8 *perf, i;
93
94 if (!bit_table(dev, 'P', &P) && P.version == 2) {
95 u8 *rammap = ROMPTR(dev, P.data[4]);
96 if (rammap) {
97 u8 *ramcfg = rammap + rammap[1];
98
99 *ver = rammap[0];
100 *hdr = rammap[2];
101 *cnt = rammap[4];
102 *len = rammap[3];
103
104 freq /= 1000;
105 for (i = 0; i < rammap[5]; i++) {
106 if (freq >= ROM16(ramcfg[0]) &&
107 freq <= ROM16(ramcfg[2]))
108 return ramcfg;
109
110 ramcfg += *hdr + (*cnt * *len);
111 }
112 }
113
114 return NULL;
115 }
116
117 if (dev_priv->chipset == 0x49 ||
118 dev_priv->chipset == 0x4b)
119 freq /= 2;
120
121 while ((perf = nouveau_perf_entry(dev, i++, ver, hdr, cnt, len))) {
122 if (*ver >= 0x20 && *ver < 0x25) {
123 if (perf[0] != 0xff && freq <= ROM16(perf[11]) * 1000)
124 break;
125 } else
126 if (*ver >= 0x25 && *ver < 0x40) {
127 if (perf[0] != 0xff && freq <= ROM16(perf[12]) * 1000)
128 break;
129 }
130 }
131
132 if (perf) {
133 u8 *ramcfg = perf + *hdr;
134 *ver = 0x00;
135 *hdr = 0;
136 return ramcfg;
137 }
138
139 return NULL;
140}
141
142static u8 *
143nouveau_perf_ramcfg(struct drm_device *dev, u32 freq, u8 *ver, u8 *len)
144{
145 struct drm_nouveau_private *dev_priv = dev->dev_private;
146 struct nvbios *bios = &dev_priv->vbios;
147 u8 strap, hdr, cnt;
148 u8 *rammap;
149
150 strap = (nv_rd32(dev, 0x101000) & 0x0000003c) >> 2;
151 if (bios->ram_restrict_tbl_ptr)
152 strap = bios->data[bios->ram_restrict_tbl_ptr + strap];
153
154 rammap = nouveau_perf_rammap(dev, freq, ver, &hdr, &cnt, len);
155 if (rammap && strap < cnt)
156 return rammap + hdr + (strap * *len);
157
158 return NULL;
159}
160
161static u8 *
162nouveau_perf_timing(struct drm_device *dev, u32 freq, u8 *ver, u8 *len)
163{
164 struct drm_nouveau_private *dev_priv = dev->dev_private;
165 struct nvbios *bios = &dev_priv->vbios;
166 struct bit_entry P;
167 u8 *perf, *timing = NULL;
168 u8 i = 0, hdr, cnt;
169
170 if (bios->type == NVBIOS_BMP) {
171 while ((perf = nouveau_perf_entry(dev, i++, ver, &hdr, &cnt,
172 len)) && *ver == 0x15) {
173 if (freq <= ROM32(perf[5]) * 20) {
174 *ver = 0x00;
175 *len = 14;
176 return perf + 41;
177 }
178 }
179 return NULL;
180 }
181
182 if (!bit_table(dev, 'P', &P)) {
183 if (P.version == 1)
184 timing = ROMPTR(dev, P.data[4]);
185 else
186 if (P.version == 2)
187 timing = ROMPTR(dev, P.data[8]);
188 }
189
190 if (timing && timing[0] == 0x10) {
191 u8 *ramcfg = nouveau_perf_ramcfg(dev, freq, ver, len);
192 if (ramcfg && ramcfg[1] < timing[2]) {
193 *ver = timing[0];
194 *len = timing[3];
195 return timing + timing[1] + (ramcfg[1] * timing[3]);
196 }
197 }
198
199 return NULL;
200}
201
30static void 202static void
31legacy_perf_init(struct drm_device *dev) 203legacy_perf_init(struct drm_device *dev)
32{ 204{
@@ -72,74 +244,11 @@ legacy_perf_init(struct drm_device *dev)
72 pm->nr_perflvl = 1; 244 pm->nr_perflvl = 1;
73} 245}
74 246
75static struct nouveau_pm_memtiming *
76nouveau_perf_timing(struct drm_device *dev, struct bit_entry *P,
77 u16 memclk, u8 *entry, u8 recordlen, u8 entries)
78{
79 struct drm_nouveau_private *dev_priv = dev->dev_private;
80 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
81 struct nvbios *bios = &dev_priv->vbios;
82 u8 ramcfg;
83 int i;
84
85 /* perf v2 has a separate "timing map" table, we have to match
86 * the target memory clock to a specific entry, *then* use
87 * ramcfg to select the correct subentry
88 */
89 if (P->version == 2) {
90 u8 *tmap = ROMPTR(dev, P->data[4]);
91 if (!tmap) {
92 NV_DEBUG(dev, "no timing map pointer\n");
93 return NULL;
94 }
95
96 if (tmap[0] != 0x10) {
97 NV_WARN(dev, "timing map 0x%02x unknown\n", tmap[0]);
98 return NULL;
99 }
100
101 entry = tmap + tmap[1];
102 recordlen = tmap[2] + (tmap[4] * tmap[3]);
103 for (i = 0; i < tmap[5]; i++, entry += recordlen) {
104 if (memclk >= ROM16(entry[0]) &&
105 memclk <= ROM16(entry[2]))
106 break;
107 }
108
109 if (i == tmap[5]) {
110 NV_WARN(dev, "no match in timing map table\n");
111 return NULL;
112 }
113
114 entry += tmap[2];
115 recordlen = tmap[3];
116 entries = tmap[4];
117 }
118
119 ramcfg = (nv_rd32(dev, NV_PEXTDEV_BOOT_0) & 0x0000003c) >> 2;
120 if (bios->ram_restrict_tbl_ptr)
121 ramcfg = bios->data[bios->ram_restrict_tbl_ptr + ramcfg];
122
123 if (ramcfg >= entries) {
124 NV_WARN(dev, "ramcfg strap out of bounds!\n");
125 return NULL;
126 }
127
128 entry += ramcfg * recordlen;
129 if (entry[1] >= pm->memtimings.nr_timing) {
130 if (entry[1] != 0xff)
131 NV_WARN(dev, "timingset %d does not exist\n", entry[1]);
132 return NULL;
133 }
134
135 return &pm->memtimings.timing[entry[1]];
136}
137
138static void 247static void
139nouveau_perf_voltage(struct drm_device *dev, struct bit_entry *P, 248nouveau_perf_voltage(struct drm_device *dev, struct nouveau_pm_level *perflvl)
140 struct nouveau_pm_level *perflvl)
141{ 249{
142 struct drm_nouveau_private *dev_priv = dev->dev_private; 250 struct drm_nouveau_private *dev_priv = dev->dev_private;
251 struct bit_entry P;
143 u8 *vmap; 252 u8 *vmap;
144 int id; 253 int id;
145 254
@@ -158,13 +267,13 @@ nouveau_perf_voltage(struct drm_device *dev, struct bit_entry *P,
158 /* on newer ones, the perflvl stores an index into yet another 267 /* on newer ones, the perflvl stores an index into yet another
159 * vbios table containing a min/max voltage value for the perflvl 268 * vbios table containing a min/max voltage value for the perflvl
160 */ 269 */
161 if (P->version != 2 || P->length < 34) { 270 if (bit_table(dev, 'P', &P) || P.version != 2 || P.length < 34) {
162 NV_DEBUG(dev, "where's our volt map table ptr? %d %d\n", 271 NV_DEBUG(dev, "where's our volt map table ptr? %d %d\n",
163 P->version, P->length); 272 P.version, P.length);
164 return; 273 return;
165 } 274 }
166 275
167 vmap = ROMPTR(dev, P->data[32]); 276 vmap = ROMPTR(dev, P.data[32]);
168 if (!vmap) { 277 if (!vmap) {
169 NV_DEBUG(dev, "volt map table pointer invalid\n"); 278 NV_DEBUG(dev, "volt map table pointer invalid\n");
170 return; 279 return;
@@ -183,132 +292,66 @@ nouveau_perf_init(struct drm_device *dev)
183 struct drm_nouveau_private *dev_priv = dev->dev_private; 292 struct drm_nouveau_private *dev_priv = dev->dev_private;
184 struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 293 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
185 struct nvbios *bios = &dev_priv->vbios; 294 struct nvbios *bios = &dev_priv->vbios;
186 struct bit_entry P; 295 u8 *perf, ver, hdr, cnt, len;
187 struct nouveau_pm_memtimings *memtimings = &pm->memtimings; 296 int vid, i = -1;
188 struct nouveau_pm_tbl_header mt_hdr;
189 u8 version, headerlen, recordlen, entries;
190 u8 *perf, *entry;
191 int vid, i;
192
193 if (bios->type == NVBIOS_BIT) {
194 if (bit_table(dev, 'P', &P))
195 return;
196
197 if (P.version != 1 && P.version != 2) {
198 NV_WARN(dev, "unknown perf for BIT P %d\n", P.version);
199 return;
200 }
201
202 perf = ROMPTR(dev, P.data[0]);
203 version = perf[0];
204 headerlen = perf[1];
205 if (version < 0x40) {
206 recordlen = perf[3] + (perf[4] * perf[5]);
207 entries = perf[2];
208
209 pm->fan.pwm_divisor = ROM16(perf[6]);
210 } else {
211 recordlen = perf[2] + (perf[3] * perf[4]);
212 entries = perf[5];
213 }
214 } else {
215 if (bios->data[bios->offset + 6] < 0x25) {
216 legacy_perf_init(dev);
217 return;
218 }
219
220 perf = ROMPTR(dev, bios->data[bios->offset + 0x94]);
221 if (!perf) {
222 NV_DEBUG(dev, "perf table pointer invalid\n");
223 return;
224 }
225 297
226 version = perf[1]; 298 if (bios->type == NVBIOS_BMP && bios->data[bios->offset + 6] < 0x25) {
227 headerlen = perf[0]; 299 legacy_perf_init(dev);
228 recordlen = perf[3]; 300 return;
229 entries = perf[2];
230 }
231
232 if (entries > NOUVEAU_PM_MAX_LEVEL) {
233 NV_DEBUG(dev,
234 "perf table has too many entries - buggy vbios?\n");
235 entries = NOUVEAU_PM_MAX_LEVEL;
236 }
237
238 entry = perf + headerlen;
239
240 /* For version 0x15, initialize memtiming table */
241 if (version == 0x15) {
242 memtimings->timing = kcalloc(entries,
243 sizeof(*memtimings->timing),
244 GFP_KERNEL);
245 if (!memtimings->timing) {
246 NV_WARN(dev, "Could not allocate memtiming table\n");
247 return;
248 }
249
250 mt_hdr.entry_cnt = entries;
251 mt_hdr.entry_len = 14;
252 mt_hdr.version = version;
253 mt_hdr.header_len = 4;
254 } 301 }
255 302
256 for (i = 0; i < entries; i++) { 303 while ((perf = nouveau_perf_entry(dev, ++i, &ver, &hdr, &cnt, &len))) {
257 struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl]; 304 struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl];
258 305
259 perflvl->timing = NULL; 306 if (perf[0] == 0xff)
260
261 if (entry[0] == 0xff) {
262 entry += recordlen;
263 continue; 307 continue;
264 }
265 308
266 switch (version) { 309 switch (ver) {
267 case 0x12: 310 case 0x12:
268 case 0x13: 311 case 0x13:
269 case 0x15: 312 case 0x15:
270 perflvl->fanspeed = entry[55]; 313 perflvl->fanspeed = perf[55];
271 if (recordlen > 56) 314 if (hdr > 56)
272 perflvl->volt_min = entry[56]; 315 perflvl->volt_min = perf[56];
273 perflvl->core = ROM32(entry[1]) * 10; 316 perflvl->core = ROM32(perf[1]) * 10;
274 perflvl->memory = ROM32(entry[5]) * 20; 317 perflvl->memory = ROM32(perf[5]) * 20;
275 break; 318 break;
276 case 0x21: 319 case 0x21:
277 case 0x23: 320 case 0x23:
278 case 0x24: 321 case 0x24:
279 perflvl->fanspeed = entry[4]; 322 perflvl->fanspeed = perf[4];
280 perflvl->volt_min = entry[5]; 323 perflvl->volt_min = perf[5];
281 perflvl->shader = ROM16(entry[6]) * 1000; 324 perflvl->shader = ROM16(perf[6]) * 1000;
282 perflvl->core = perflvl->shader; 325 perflvl->core = perflvl->shader;
283 perflvl->core += (signed char)entry[8] * 1000; 326 perflvl->core += (signed char)perf[8] * 1000;
284 if (dev_priv->chipset == 0x49 || 327 if (dev_priv->chipset == 0x49 ||
285 dev_priv->chipset == 0x4b) 328 dev_priv->chipset == 0x4b)
286 perflvl->memory = ROM16(entry[11]) * 1000; 329 perflvl->memory = ROM16(perf[11]) * 1000;
287 else 330 else
288 perflvl->memory = ROM16(entry[11]) * 2000; 331 perflvl->memory = ROM16(perf[11]) * 2000;
289 break; 332 break;
290 case 0x25: 333 case 0x25:
291 perflvl->fanspeed = entry[4]; 334 perflvl->fanspeed = perf[4];
292 perflvl->volt_min = entry[5]; 335 perflvl->volt_min = perf[5];
293 perflvl->core = ROM16(entry[6]) * 1000; 336 perflvl->core = ROM16(perf[6]) * 1000;
294 perflvl->shader = ROM16(entry[10]) * 1000; 337 perflvl->shader = ROM16(perf[10]) * 1000;
295 perflvl->memory = ROM16(entry[12]) * 1000; 338 perflvl->memory = ROM16(perf[12]) * 1000;
296 break; 339 break;
297 case 0x30: 340 case 0x30:
298 perflvl->memscript = ROM16(entry[2]); 341 perflvl->memscript = ROM16(perf[2]);
299 case 0x35: 342 case 0x35:
300 perflvl->fanspeed = entry[6]; 343 perflvl->fanspeed = perf[6];
301 perflvl->volt_min = entry[7]; 344 perflvl->volt_min = perf[7];
302 perflvl->core = ROM16(entry[8]) * 1000; 345 perflvl->core = ROM16(perf[8]) * 1000;
303 perflvl->shader = ROM16(entry[10]) * 1000; 346 perflvl->shader = ROM16(perf[10]) * 1000;
304 perflvl->memory = ROM16(entry[12]) * 1000; 347 perflvl->memory = ROM16(perf[12]) * 1000;
305 perflvl->vdec = ROM16(entry[16]) * 1000; 348 perflvl->vdec = ROM16(perf[16]) * 1000;
306 perflvl->dom6 = ROM16(entry[20]) * 1000; 349 perflvl->dom6 = ROM16(perf[20]) * 1000;
307 break; 350 break;
308 case 0x40: 351 case 0x40:
309#define subent(n) ((ROM16(entry[perf[2] + ((n) * perf[3])]) & 0xfff) * 1000) 352#define subent(n) ((ROM16(perf[hdr + (n) * len]) & 0xfff) * 1000)
310 perflvl->fanspeed = 0; /*XXX*/ 353 perflvl->fanspeed = 0; /*XXX*/
311 perflvl->volt_min = entry[2]; 354 perflvl->volt_min = perf[2];
312 if (dev_priv->card_type == NV_50) { 355 if (dev_priv->card_type == NV_50) {
313 perflvl->core = subent(0); 356 perflvl->core = subent(0);
314 perflvl->shader = subent(1); 357 perflvl->shader = subent(1);
@@ -331,17 +374,17 @@ nouveau_perf_init(struct drm_device *dev)
331 } 374 }
332 375
333 /* make sure vid is valid */ 376 /* make sure vid is valid */
334 nouveau_perf_voltage(dev, &P, perflvl); 377 nouveau_perf_voltage(dev, perflvl);
335 if (pm->voltage.supported && perflvl->volt_min) { 378 if (pm->voltage.supported && perflvl->volt_min) {
336 vid = nouveau_volt_vid_lookup(dev, perflvl->volt_min); 379 vid = nouveau_volt_vid_lookup(dev, perflvl->volt_min);
337 if (vid < 0) { 380 if (vid < 0) {
338 NV_DEBUG(dev, "drop perflvl %d, bad vid\n", i); 381 NV_DEBUG(dev, "perflvl %d, bad vid\n", i);
339 entry += recordlen;
340 continue; 382 continue;
341 } 383 }
342 } 384 }
343 385
344 /* get the corresponding memory timings */ 386 /* get the corresponding memory timings */
387#if 0
345 if (version == 0x15) { 388 if (version == 0x15) {
346 memtimings->timing[i].id = i; 389 memtimings->timing[i].id = i;
347 nv30_mem_timing_entry(dev, &mt_hdr, 390 nv30_mem_timing_entry(dev, &mt_hdr,
@@ -356,13 +399,14 @@ nouveau_perf_init(struct drm_device *dev)
356 entry + perf[3], 399 entry + perf[3],
357 perf[5], perf[4]); 400 perf[5], perf[4]);
358 } 401 }
402#else
403 perflvl->timing = NULL;
404#endif
359 405
360 snprintf(perflvl->name, sizeof(perflvl->name), 406 snprintf(perflvl->name, sizeof(perflvl->name),
361 "performance_level_%d", i); 407 "performance_level_%d", i);
362 perflvl->id = i; 408 perflvl->id = i;
363 pm->nr_perflvl++; 409 pm->nr_perflvl++;
364
365 entry += recordlen;
366 } 410 }
367} 411}
368 412