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 "drmP.h"
26 
27 #include "nouveau_drv.h"
28 #include "nouveau_pm.h"
29 
30 static u8 *
nouveau_perf_table(struct drm_device * dev,u8 * ver)31 nouveau_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 
58 static u8 *
nouveau_perf_entry(struct drm_device * dev,int idx,u8 * ver,u8 * hdr,u8 * cnt,u8 * len)59 nouveau_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 
86 static u8 *
nouveau_perf_rammap(struct drm_device * dev,u32 freq,u8 * ver,u8 * hdr,u8 * cnt,u8 * len)87 nouveau_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 = 0;
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 
142 u8 *
nouveau_perf_ramcfg(struct drm_device * dev,u32 freq,u8 * ver,u8 * len)143 nouveau_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 
161 u8 *
nouveau_perf_timing(struct drm_device * dev,u32 freq,u8 * ver,u8 * len)162 nouveau_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 
202 static void
legacy_perf_init(struct drm_device * dev)203 legacy_perf_init(struct drm_device *dev)
204 {
205 	struct drm_nouveau_private *dev_priv = dev->dev_private;
206 	struct nvbios *bios = &dev_priv->vbios;
207 	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
208 	char *perf, *entry, *bmp = &bios->data[bios->offset];
209 	int headerlen, use_straps;
210 
211 	if (bmp[5] < 0x5 || bmp[6] < 0x14) {
212 		NV_DEBUG(dev, "BMP version too old for perf\n");
213 		return;
214 	}
215 
216 	perf = ROMPTR(dev, bmp[0x73]);
217 	if (!perf) {
218 		NV_DEBUG(dev, "No memclock table pointer found.\n");
219 		return;
220 	}
221 
222 	switch (perf[0]) {
223 	case 0x12:
224 	case 0x14:
225 	case 0x18:
226 		use_straps = 0;
227 		headerlen = 1;
228 		break;
229 	case 0x01:
230 		use_straps = perf[1] & 1;
231 		headerlen = (use_straps ? 8 : 2);
232 		break;
233 	default:
234 		NV_WARN(dev, "Unknown memclock table version %x.\n", perf[0]);
235 		return;
236 	}
237 
238 	entry = perf + headerlen;
239 	if (use_straps)
240 		entry += (nv_rd32(dev, NV_PEXTDEV_BOOT_0) & 0x3c) >> 1;
241 
242 	sprintf(pm->perflvl[0].name, "performance_level_0");
243 	pm->perflvl[0].memory = ROM16(entry[0]) * 20;
244 	pm->nr_perflvl = 1;
245 }
246 
247 static void
nouveau_perf_voltage(struct drm_device * dev,struct nouveau_pm_level * perflvl)248 nouveau_perf_voltage(struct drm_device *dev, struct nouveau_pm_level *perflvl)
249 {
250 	struct drm_nouveau_private *dev_priv = dev->dev_private;
251 	struct bit_entry P;
252 	u8 *vmap;
253 	int id;
254 
255 	id = perflvl->volt_min;
256 	perflvl->volt_min = 0;
257 
258 	/* boards using voltage table version <0x40 store the voltage
259 	 * level directly in the perflvl entry as a multiple of 10mV
260 	 */
261 	if (dev_priv->engine.pm.voltage.version < 0x40) {
262 		perflvl->volt_min = id * 10000;
263 		perflvl->volt_max = perflvl->volt_min;
264 		return;
265 	}
266 
267 	/* on newer ones, the perflvl stores an index into yet another
268 	 * vbios table containing a min/max voltage value for the perflvl
269 	 */
270 	if (bit_table(dev, 'P', &P) || P.version != 2 || P.length < 34) {
271 		NV_DEBUG(dev, "where's our volt map table ptr? %d %d\n",
272 			 P.version, P.length);
273 		return;
274 	}
275 
276 	vmap = ROMPTR(dev, P.data[32]);
277 	if (!vmap) {
278 		NV_DEBUG(dev, "volt map table pointer invalid\n");
279 		return;
280 	}
281 
282 	if (id < vmap[3]) {
283 		vmap += vmap[1] + (vmap[2] * id);
284 		perflvl->volt_min = ROM32(vmap[0]);
285 		perflvl->volt_max = ROM32(vmap[4]);
286 	}
287 }
288 
289 void
nouveau_perf_init(struct drm_device * dev)290 nouveau_perf_init(struct drm_device *dev)
291 {
292 	struct drm_nouveau_private *dev_priv = dev->dev_private;
293 	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
294 	struct nvbios *bios = &dev_priv->vbios;
295 	u8 *perf, ver, hdr, cnt, len;
296 	int ret, vid, i = -1;
297 
298 	if (bios->type == NVBIOS_BMP && bios->data[bios->offset + 6] < 0x25) {
299 		legacy_perf_init(dev);
300 		return;
301 	}
302 
303 	perf = nouveau_perf_table(dev, &ver);
304 	if (ver >= 0x20 && ver < 0x40)
305 		pm->fan.pwm_divisor = ROM16(perf[6]);
306 
307 	while ((perf = nouveau_perf_entry(dev, ++i, &ver, &hdr, &cnt, &len))) {
308 		struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl];
309 
310 		if (perf[0] == 0xff)
311 			continue;
312 
313 		switch (ver) {
314 		case 0x12:
315 		case 0x13:
316 		case 0x15:
317 			perflvl->fanspeed = perf[55];
318 			if (hdr > 56)
319 				perflvl->volt_min = perf[56];
320 			perflvl->core = ROM32(perf[1]) * 10;
321 			perflvl->memory = ROM32(perf[5]) * 20;
322 			break;
323 		case 0x21:
324 		case 0x23:
325 		case 0x24:
326 			perflvl->fanspeed = perf[4];
327 			perflvl->volt_min = perf[5];
328 			perflvl->shader = ROM16(perf[6]) * 1000;
329 			perflvl->core = perflvl->shader;
330 			perflvl->core += (signed char)perf[8] * 1000;
331 			if (dev_priv->chipset == 0x49 ||
332 			    dev_priv->chipset == 0x4b)
333 				perflvl->memory = ROM16(perf[11]) * 1000;
334 			else
335 				perflvl->memory = ROM16(perf[11]) * 2000;
336 			break;
337 		case 0x25:
338 			perflvl->fanspeed = perf[4];
339 			perflvl->volt_min = perf[5];
340 			perflvl->core = ROM16(perf[6]) * 1000;
341 			perflvl->shader = ROM16(perf[10]) * 1000;
342 			perflvl->memory = ROM16(perf[12]) * 1000;
343 			break;
344 		case 0x30:
345 			perflvl->memscript = ROM16(perf[2]);
346 		case 0x35:
347 			perflvl->fanspeed = perf[6];
348 			perflvl->volt_min = perf[7];
349 			perflvl->core = ROM16(perf[8]) * 1000;
350 			perflvl->shader = ROM16(perf[10]) * 1000;
351 			perflvl->memory = ROM16(perf[12]) * 1000;
352 			perflvl->vdec = ROM16(perf[16]) * 1000;
353 			perflvl->dom6 = ROM16(perf[20]) * 1000;
354 			break;
355 		case 0x40:
356 #define subent(n) ((ROM16(perf[hdr + (n) * len]) & 0xfff) * 1000)
357 			perflvl->fanspeed = 0; /*XXX*/
358 			perflvl->volt_min = perf[2];
359 			if (dev_priv->card_type == NV_50) {
360 				perflvl->core   = subent(0);
361 				perflvl->shader = subent(1);
362 				perflvl->memory = subent(2);
363 				perflvl->vdec   = subent(3);
364 				perflvl->unka0  = subent(4);
365 			} else {
366 				perflvl->hub06  = subent(0);
367 				perflvl->hub01  = subent(1);
368 				perflvl->copy   = subent(2);
369 				perflvl->shader = subent(3);
370 				perflvl->rop    = subent(4);
371 				perflvl->memory = subent(5);
372 				perflvl->vdec   = subent(6);
373 				perflvl->daemon = subent(10);
374 				perflvl->hub07  = subent(11);
375 				perflvl->core   = perflvl->shader / 2;
376 			}
377 			break;
378 		}
379 
380 		/* make sure vid is valid */
381 		nouveau_perf_voltage(dev, perflvl);
382 		if (pm->voltage.supported && perflvl->volt_min) {
383 			vid = nouveau_volt_vid_lookup(dev, perflvl->volt_min);
384 			if (vid < 0) {
385 				NV_DEBUG(dev, "perflvl %d, bad vid\n", i);
386 				continue;
387 			}
388 		}
389 
390 		/* get the corresponding memory timings */
391 		ret = nouveau_mem_timing_calc(dev, perflvl->memory,
392 					          &perflvl->timing);
393 		if (ret) {
394 			NV_DEBUG(dev, "perflvl %d, bad timing: %d\n", i, ret);
395 			continue;
396 		}
397 
398 		snprintf(perflvl->name, sizeof(perflvl->name),
399 			 "performance_level_%d", i);
400 		perflvl->id = i;
401 
402 		snprintf(perflvl->profile.name, sizeof(perflvl->profile.name),
403 			 "%d", perflvl->id);
404 		perflvl->profile.func = &nouveau_pm_static_profile_func;
405 		list_add_tail(&perflvl->profile.head, &pm->profiles);
406 
407 
408 		pm->nr_perflvl++;
409 	}
410 }
411 
412 void
nouveau_perf_fini(struct drm_device * dev)413 nouveau_perf_fini(struct drm_device *dev)
414 {
415 }
416