• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2010 Red Hat Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Authors: Ben Skeggs
23  */
24 
25 #include <drm/drmP.h>
26 
27 #include "nouveau_drm.h"
28 #include "nouveau_reg.h"
29 #include "nouveau_pm.h"
30 
31 static u8 *
nouveau_perf_table(struct drm_device * dev,u8 * ver)32 nouveau_perf_table(struct drm_device *dev, u8 *ver)
33 {
34 	struct nouveau_drm *drm = nouveau_drm(dev);
35 	struct nvbios *bios = &drm->vbios;
36 	struct bit_entry P;
37 
38 	if (!bit_table(dev, 'P', &P) && P.version && P.version <= 2) {
39 		u8 *perf = ROMPTR(dev, P.data[0]);
40 		if (perf) {
41 			*ver = perf[0];
42 			return perf;
43 		}
44 	}
45 
46 	if (bios->type == NVBIOS_BMP) {
47 		if (bios->data[bios->offset + 6] >= 0x25) {
48 			u8 *perf = ROMPTR(dev, bios->data[bios->offset + 0x94]);
49 			if (perf) {
50 				*ver = perf[1];
51 				return perf;
52 			}
53 		}
54 	}
55 
56 	return NULL;
57 }
58 
59 static u8 *
nouveau_perf_entry(struct drm_device * dev,int idx,u8 * ver,u8 * hdr,u8 * cnt,u8 * len)60 nouveau_perf_entry(struct drm_device *dev, int idx,
61 		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
62 {
63 	u8 *perf = nouveau_perf_table(dev, ver);
64 	if (perf) {
65 		if (*ver >= 0x12 && *ver < 0x20 && idx < perf[2]) {
66 			*hdr = perf[3];
67 			*cnt = 0;
68 			*len = 0;
69 			return perf + perf[0] + idx * perf[3];
70 		} else
71 		if (*ver >= 0x20 && *ver < 0x40 && idx < perf[2]) {
72 			*hdr = perf[3];
73 			*cnt = perf[4];
74 			*len = perf[5];
75 			return perf + perf[1] + idx * (*hdr + (*cnt * *len));
76 		} else
77 		if (*ver >= 0x40 && *ver < 0x41 && idx < perf[5]) {
78 			*hdr = perf[2];
79 			*cnt = perf[4];
80 			*len = perf[3];
81 			return perf + perf[1] + idx * (*hdr + (*cnt * *len));
82 		}
83 	}
84 	return NULL;
85 }
86 
87 u8 *
nouveau_perf_rammap(struct drm_device * dev,u32 freq,u8 * ver,u8 * hdr,u8 * cnt,u8 * len)88 nouveau_perf_rammap(struct drm_device *dev, u32 freq,
89 		    u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
90 {
91 	struct nouveau_drm *drm = nouveau_drm(dev);
92 	struct bit_entry P;
93 	u8 *perf, i = 0;
94 
95 	if (!bit_table(dev, 'P', &P) && P.version == 2) {
96 		u8 *rammap = ROMPTR(dev, P.data[4]);
97 		if (rammap) {
98 			u8 *ramcfg = rammap + rammap[1];
99 
100 			*ver = rammap[0];
101 			*hdr = rammap[2];
102 			*cnt = rammap[4];
103 			*len = rammap[3];
104 
105 			freq /= 1000;
106 			for (i = 0; i < rammap[5]; i++) {
107 				if (freq >= ROM16(ramcfg[0]) &&
108 				    freq <= ROM16(ramcfg[2]))
109 					return ramcfg;
110 
111 				ramcfg += *hdr + (*cnt * *len);
112 			}
113 		}
114 
115 		return NULL;
116 	}
117 
118 	if (nv_device(drm->device)->chipset == 0x49 ||
119 	    nv_device(drm->device)->chipset == 0x4b)
120 		freq /= 2;
121 
122 	while ((perf = nouveau_perf_entry(dev, i++, ver, hdr, cnt, len))) {
123 		if (*ver >= 0x20 && *ver < 0x25) {
124 			if (perf[0] != 0xff && freq <= ROM16(perf[11]) * 1000)
125 				break;
126 		} else
127 		if (*ver >= 0x25 && *ver < 0x40) {
128 			if (perf[0] != 0xff && freq <= ROM16(perf[12]) * 1000)
129 				break;
130 		}
131 	}
132 
133 	if (perf) {
134 		u8 *ramcfg = perf + *hdr;
135 		*ver = 0x00;
136 		*hdr = 0;
137 		return ramcfg;
138 	}
139 
140 	return NULL;
141 }
142 
143 u8 *
nouveau_perf_ramcfg(struct drm_device * dev,u32 freq,u8 * ver,u8 * len)144 nouveau_perf_ramcfg(struct drm_device *dev, u32 freq, u8 *ver, u8 *len)
145 {
146 	struct nouveau_device *device = nouveau_dev(dev);
147 	struct nouveau_drm *drm = nouveau_drm(dev);
148 	struct nvbios *bios = &drm->vbios;
149 	u8 strap, hdr, cnt;
150 	u8 *rammap;
151 
152 	strap = (nv_rd32(device, 0x101000) & 0x0000003c) >> 2;
153 	if (bios->ram_restrict_tbl_ptr)
154 		strap = bios->data[bios->ram_restrict_tbl_ptr + strap];
155 
156 	rammap = nouveau_perf_rammap(dev, freq, ver, &hdr, &cnt, len);
157 	if (rammap && strap < cnt)
158 		return rammap + hdr + (strap * *len);
159 
160 	return NULL;
161 }
162 
163 u8 *
nouveau_perf_timing(struct drm_device * dev,u32 freq,u8 * ver,u8 * len)164 nouveau_perf_timing(struct drm_device *dev, u32 freq, u8 *ver, u8 *len)
165 {
166 	struct nouveau_drm *drm = nouveau_drm(dev);
167 	struct nvbios *bios = &drm->vbios;
168 	struct bit_entry P;
169 	u8 *perf, *timing = NULL;
170 	u8 i = 0, hdr, cnt;
171 
172 	if (bios->type == NVBIOS_BMP) {
173 		while ((perf = nouveau_perf_entry(dev, i++, ver, &hdr, &cnt,
174 						  len)) && *ver == 0x15) {
175 			if (freq <= ROM32(perf[5]) * 20) {
176 				*ver = 0x00;
177 				*len = 14;
178 				return perf + 41;
179 			}
180 		}
181 		return NULL;
182 	}
183 
184 	if (!bit_table(dev, 'P', &P)) {
185 		if (P.version == 1)
186 			timing = ROMPTR(dev, P.data[4]);
187 		else
188 		if (P.version == 2)
189 			timing = ROMPTR(dev, P.data[8]);
190 	}
191 
192 	if (timing && timing[0] == 0x10) {
193 		u8 *ramcfg = nouveau_perf_ramcfg(dev, freq, ver, len);
194 		if (ramcfg && ramcfg[1] < timing[2]) {
195 			*ver = timing[0];
196 			*len = timing[3];
197 			return timing + timing[1] + (ramcfg[1] * timing[3]);
198 		}
199 	}
200 
201 	return NULL;
202 }
203 
204 static void
legacy_perf_init(struct drm_device * dev)205 legacy_perf_init(struct drm_device *dev)
206 {
207 	struct nouveau_device *device = nouveau_dev(dev);
208 	struct nouveau_drm *drm = nouveau_drm(dev);
209 	struct nvbios *bios = &drm->vbios;
210 	struct nouveau_pm *pm = nouveau_pm(dev);
211 	char *perf, *entry, *bmp = &bios->data[bios->offset];
212 	int headerlen, use_straps;
213 
214 	if (bmp[5] < 0x5 || bmp[6] < 0x14) {
215 		NV_DEBUG(drm, "BMP version too old for perf\n");
216 		return;
217 	}
218 
219 	perf = ROMPTR(dev, bmp[0x73]);
220 	if (!perf) {
221 		NV_DEBUG(drm, "No memclock table pointer found.\n");
222 		return;
223 	}
224 
225 	switch (perf[0]) {
226 	case 0x12:
227 	case 0x14:
228 	case 0x18:
229 		use_straps = 0;
230 		headerlen = 1;
231 		break;
232 	case 0x01:
233 		use_straps = perf[1] & 1;
234 		headerlen = (use_straps ? 8 : 2);
235 		break;
236 	default:
237 		NV_WARN(drm, "Unknown memclock table version %x.\n", perf[0]);
238 		return;
239 	}
240 
241 	entry = perf + headerlen;
242 	if (use_straps)
243 		entry += (nv_rd32(device, NV_PEXTDEV_BOOT_0) & 0x3c) >> 1;
244 
245 	sprintf(pm->perflvl[0].name, "performance_level_0");
246 	pm->perflvl[0].memory = ROM16(entry[0]) * 20;
247 	pm->nr_perflvl = 1;
248 }
249 
250 static void
nouveau_perf_voltage(struct drm_device * dev,struct nouveau_pm_level * perflvl)251 nouveau_perf_voltage(struct drm_device *dev, struct nouveau_pm_level *perflvl)
252 {
253 	struct nouveau_drm *drm = nouveau_drm(dev);
254 	struct bit_entry P;
255 	u8 *vmap;
256 	int id;
257 
258 	id = perflvl->volt_min;
259 	perflvl->volt_min = 0;
260 
261 	/* boards using voltage table version <0x40 store the voltage
262 	 * level directly in the perflvl entry as a multiple of 10mV
263 	 */
264 	if (drm->pm->voltage.version < 0x40) {
265 		perflvl->volt_min = id * 10000;
266 		perflvl->volt_max = perflvl->volt_min;
267 		return;
268 	}
269 
270 	/* on newer ones, the perflvl stores an index into yet another
271 	 * vbios table containing a min/max voltage value for the perflvl
272 	 */
273 	if (bit_table(dev, 'P', &P) || P.version != 2 || P.length < 34) {
274 		NV_DEBUG(drm, "where's our volt map table ptr? %d %d\n",
275 			 P.version, P.length);
276 		return;
277 	}
278 
279 	vmap = ROMPTR(dev, P.data[32]);
280 	if (!vmap) {
281 		NV_DEBUG(drm, "volt map table pointer invalid\n");
282 		return;
283 	}
284 
285 	if (id < vmap[3]) {
286 		vmap += vmap[1] + (vmap[2] * id);
287 		perflvl->volt_min = ROM32(vmap[0]);
288 		perflvl->volt_max = ROM32(vmap[4]);
289 	}
290 }
291 
292 void
nouveau_perf_init(struct drm_device * dev)293 nouveau_perf_init(struct drm_device *dev)
294 {
295 	struct nouveau_drm *drm = nouveau_drm(dev);
296 	struct nouveau_pm *pm = nouveau_pm(dev);
297 	struct nvbios *bios = &drm->vbios;
298 	u8 *perf, ver, hdr, cnt, len;
299 	int ret, vid, i = -1;
300 
301 	if (bios->type == NVBIOS_BMP && bios->data[bios->offset + 6] < 0x25) {
302 		legacy_perf_init(dev);
303 		return;
304 	}
305 
306 	perf = nouveau_perf_table(dev, &ver);
307 
308 	while ((perf = nouveau_perf_entry(dev, ++i, &ver, &hdr, &cnt, &len))) {
309 		struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl];
310 
311 		if (perf[0] == 0xff)
312 			continue;
313 
314 		switch (ver) {
315 		case 0x12:
316 		case 0x13:
317 		case 0x15:
318 			perflvl->fanspeed = perf[55];
319 			if (hdr > 56)
320 				perflvl->volt_min = perf[56];
321 			perflvl->core = ROM32(perf[1]) * 10;
322 			perflvl->memory = ROM32(perf[5]) * 20;
323 			break;
324 		case 0x21:
325 		case 0x23:
326 		case 0x24:
327 			perflvl->fanspeed = perf[4];
328 			perflvl->volt_min = perf[5];
329 			perflvl->shader = ROM16(perf[6]) * 1000;
330 			perflvl->core = perflvl->shader;
331 			perflvl->core += (signed char)perf[8] * 1000;
332 			if (nv_device(drm->device)->chipset == 0x49 ||
333 			    nv_device(drm->device)->chipset == 0x4b)
334 				perflvl->memory = ROM16(perf[11]) * 1000;
335 			else
336 				perflvl->memory = ROM16(perf[11]) * 2000;
337 			break;
338 		case 0x25:
339 			perflvl->fanspeed = perf[4];
340 			perflvl->volt_min = perf[5];
341 			perflvl->core = ROM16(perf[6]) * 1000;
342 			perflvl->shader = ROM16(perf[10]) * 1000;
343 			perflvl->memory = ROM16(perf[12]) * 1000;
344 			break;
345 		case 0x30:
346 			perflvl->memscript = ROM16(perf[2]);
347 		case 0x35:
348 			perflvl->fanspeed = perf[6];
349 			perflvl->volt_min = perf[7];
350 			perflvl->core = ROM16(perf[8]) * 1000;
351 			perflvl->shader = ROM16(perf[10]) * 1000;
352 			perflvl->memory = ROM16(perf[12]) * 1000;
353 			perflvl->vdec = ROM16(perf[16]) * 1000;
354 			perflvl->dom6 = ROM16(perf[20]) * 1000;
355 			break;
356 		case 0x40:
357 #define subent(n) ((ROM16(perf[hdr + (n) * len]) & 0xfff) * 1000)
358 			perflvl->fanspeed = 0; /*XXX*/
359 			perflvl->volt_min = perf[2];
360 			if (nv_device(drm->device)->card_type == NV_50) {
361 				perflvl->core   = subent(0);
362 				perflvl->shader = subent(1);
363 				perflvl->memory = subent(2);
364 				perflvl->vdec   = subent(3);
365 				perflvl->unka0  = subent(4);
366 			} else {
367 				perflvl->hub06  = subent(0);
368 				perflvl->hub01  = subent(1);
369 				perflvl->copy   = subent(2);
370 				perflvl->shader = subent(3);
371 				perflvl->rop    = subent(4);
372 				perflvl->memory = subent(5);
373 				perflvl->vdec   = subent(6);
374 				perflvl->daemon = subent(10);
375 				perflvl->hub07  = subent(11);
376 				perflvl->core   = perflvl->shader / 2;
377 			}
378 			break;
379 		}
380 
381 		/* make sure vid is valid */
382 		nouveau_perf_voltage(dev, perflvl);
383 		if (pm->voltage.supported && perflvl->volt_min) {
384 			vid = nouveau_volt_vid_lookup(dev, perflvl->volt_min);
385 			if (vid < 0) {
386 				NV_DEBUG(drm, "perflvl %d, bad vid\n", i);
387 				continue;
388 			}
389 		}
390 
391 		/* get the corresponding memory timings */
392 		ret = nouveau_mem_timing_calc(dev, perflvl->memory,
393 					          &perflvl->timing);
394 		if (ret) {
395 			NV_DEBUG(drm, "perflvl %d, bad timing: %d\n", i, ret);
396 			continue;
397 		}
398 
399 		snprintf(perflvl->name, sizeof(perflvl->name),
400 			 "performance_level_%d", i);
401 		perflvl->id = i;
402 
403 		snprintf(perflvl->profile.name, sizeof(perflvl->profile.name),
404 			 "%d", perflvl->id);
405 		perflvl->profile.func = &nouveau_pm_static_profile_func;
406 		list_add_tail(&perflvl->profile.head, &pm->profiles);
407 
408 
409 		pm->nr_perflvl++;
410 	}
411 }
412 
413 void
nouveau_perf_fini(struct drm_device * dev)414 nouveau_perf_fini(struct drm_device *dev)
415 {
416 }
417