aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nouveau_perf.c
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2011-06-09 02:57:07 -0400
committerBen Skeggs <bskeggs@redhat.com>2011-09-20 02:01:14 -0400
commit3b5565ddfd8fe71f6470a5d240a6bb50ba90d4ff (patch)
tree2ff079e372de919ebc486fad11e528391ac134fb /drivers/gpu/drm/nouveau/nouveau_perf.c
parenta31214ef3e6cf427afe76b54c67e11c92d2aaeb8 (diff)
drm/nouveau/pm: add support for parsing perflvl voltage on fermi chips
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_perf.c')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_perf.c58
1 files changed, 51 insertions, 7 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_perf.c b/drivers/gpu/drm/nouveau/nouveau_perf.c
index 117ce16f3580..18d1d995b53a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_perf.c
+++ b/drivers/gpu/drm/nouveau/nouveau_perf.c
@@ -134,6 +134,49 @@ nouveau_perf_timing(struct drm_device *dev, struct bit_entry *P,
134 return &pm->memtimings.timing[entry[1]]; 134 return &pm->memtimings.timing[entry[1]];
135} 135}
136 136
137static void
138nouveau_perf_voltage(struct drm_device *dev, struct bit_entry *P,
139 struct nouveau_pm_level *perflvl)
140{
141 struct drm_nouveau_private *dev_priv = dev->dev_private;
142 struct nvbios *bios = &dev_priv->vbios;
143 u8 *vmap;
144 int id;
145
146 id = perflvl->volt_min;
147 perflvl->volt_min = 0;
148
149 /* pre-fermi vbios stores the voltage level directly in the
150 * perflvl entry as a multiple of 10mV
151 */
152 if (dev_priv->card_type < NV_C0) {
153 perflvl->volt_min = id * 10000;
154 perflvl->volt_max = perflvl->volt_min;
155 return;
156 }
157
158 /* from fermi onwards, the perflvl stores an index into yet another
159 * vbios table containing a min/max voltage value for the perflvl
160 */
161 if (P->version != 2 || P->length < 34) {
162 NV_DEBUG(dev, "where's our volt map table ptr? %d %d\n",
163 P->version, P->length);
164 return;
165 }
166
167 vmap = ROMPTR(bios, P->data[32]);
168 if (!vmap) {
169 NV_DEBUG(dev, "volt map table pointer invalid\n");
170 return;
171 }
172
173 if (id < vmap[3]) {
174 vmap += vmap[1] + (vmap[2] * id);
175 perflvl->volt_min = ROM32(vmap[0]);
176 perflvl->volt_max = ROM32(vmap[4]);
177 }
178}
179
137void 180void
138nouveau_perf_init(struct drm_device *dev) 181nouveau_perf_init(struct drm_device *dev)
139{ 182{
@@ -204,7 +247,7 @@ nouveau_perf_init(struct drm_device *dev)
204 case 0x15: 247 case 0x15:
205 perflvl->fanspeed = entry[55]; 248 perflvl->fanspeed = entry[55];
206 if (recordlen > 56) 249 if (recordlen > 56)
207 perflvl->voltage = entry[56] * 10000; 250 perflvl->volt_min = entry[56];
208 perflvl->core = ROM32(entry[1]) * 10; 251 perflvl->core = ROM32(entry[1]) * 10;
209 perflvl->memory = ROM32(entry[5]) * 20; 252 perflvl->memory = ROM32(entry[5]) * 20;
210 break; 253 break;
@@ -212,7 +255,7 @@ nouveau_perf_init(struct drm_device *dev)
212 case 0x23: 255 case 0x23:
213 case 0x24: 256 case 0x24:
214 perflvl->fanspeed = entry[4]; 257 perflvl->fanspeed = entry[4];
215 perflvl->voltage = entry[5] * 10000; 258 perflvl->volt_min = entry[5];
216 perflvl->core = ROM16(entry[6]) * 1000; 259 perflvl->core = ROM16(entry[6]) * 1000;
217 260
218 if (dev_priv->chipset == 0x49 || 261 if (dev_priv->chipset == 0x49 ||
@@ -224,7 +267,7 @@ nouveau_perf_init(struct drm_device *dev)
224 break; 267 break;
225 case 0x25: 268 case 0x25:
226 perflvl->fanspeed = entry[4]; 269 perflvl->fanspeed = entry[4];
227 perflvl->voltage = entry[5] * 10000; 270 perflvl->volt_min = entry[5];
228 perflvl->core = ROM16(entry[6]) * 1000; 271 perflvl->core = ROM16(entry[6]) * 1000;
229 perflvl->shader = ROM16(entry[10]) * 1000; 272 perflvl->shader = ROM16(entry[10]) * 1000;
230 perflvl->memory = ROM16(entry[12]) * 1000; 273 perflvl->memory = ROM16(entry[12]) * 1000;
@@ -233,7 +276,7 @@ nouveau_perf_init(struct drm_device *dev)
233 perflvl->memscript = ROM16(entry[2]); 276 perflvl->memscript = ROM16(entry[2]);
234 case 0x35: 277 case 0x35:
235 perflvl->fanspeed = entry[6]; 278 perflvl->fanspeed = entry[6];
236 perflvl->voltage = entry[7] * 10000; 279 perflvl->volt_min = entry[7];
237 perflvl->core = ROM16(entry[8]) * 1000; 280 perflvl->core = ROM16(entry[8]) * 1000;
238 perflvl->shader = ROM16(entry[10]) * 1000; 281 perflvl->shader = ROM16(entry[10]) * 1000;
239 perflvl->memory = ROM16(entry[12]) * 1000; 282 perflvl->memory = ROM16(entry[12]) * 1000;
@@ -243,7 +286,7 @@ nouveau_perf_init(struct drm_device *dev)
243 case 0x40: 286 case 0x40:
244#define subent(n) entry[perf[2] + ((n) * perf[3])] 287#define subent(n) entry[perf[2] + ((n) * perf[3])]
245 perflvl->fanspeed = 0; /*XXX*/ 288 perflvl->fanspeed = 0; /*XXX*/
246 perflvl->voltage = entry[2] * 10000; 289 perflvl->volt_min = entry[2];
247 if (dev_priv->card_type == NV_50) { 290 if (dev_priv->card_type == NV_50) {
248 perflvl->core = ROM16(subent(0)) & 0xfff; 291 perflvl->core = ROM16(subent(0)) & 0xfff;
249 perflvl->shader = ROM16(subent(1)) & 0xfff; 292 perflvl->shader = ROM16(subent(1)) & 0xfff;
@@ -263,8 +306,9 @@ nouveau_perf_init(struct drm_device *dev)
263 } 306 }
264 307
265 /* make sure vid is valid */ 308 /* make sure vid is valid */
266 if (pm->voltage.supported && perflvl->voltage) { 309 nouveau_perf_voltage(dev, &P, perflvl);
267 vid = nouveau_volt_vid_lookup(dev, perflvl->voltage); 310 if (pm->voltage.supported && perflvl->volt_min) {
311 vid = nouveau_volt_vid_lookup(dev, perflvl->volt_min);
268 if (vid < 0) { 312 if (vid < 0) {
269 NV_DEBUG(dev, "drop perflvl %d, bad vid\n", i); 313 NV_DEBUG(dev, "drop perflvl %d, bad vid\n", i);
270 entry += recordlen; 314 entry += recordlen;