aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau
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
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')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_perf.c58
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_pm.c24
3 files changed, 69 insertions, 16 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 39d6bb313bab..84a19a5fc553 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -451,7 +451,8 @@ struct nouveau_pm_level {
451 u32 unk05; 451 u32 unk05;
452 u32 unk0a; 452 u32 unk0a;
453 453
454 u32 voltage; /* microvolts */ 454 u32 volt_min; /* microvolts */
455 u32 volt_max;
455 u8 fanspeed; 456 u8 fanspeed;
456 457
457 u16 memscript; 458 u16 memscript;
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;
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c
index f5703ef68518..cab576b2f15e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_pm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.c
@@ -64,11 +64,11 @@ nouveau_pm_perflvl_set(struct drm_device *dev, struct nouveau_pm_level *perflvl)
64 if (perflvl == pm->cur) 64 if (perflvl == pm->cur)
65 return 0; 65 return 0;
66 66
67 if (pm->voltage.supported && pm->voltage_set && perflvl->voltage) { 67 if (pm->voltage.supported && pm->voltage_set && perflvl->volt_min) {
68 ret = pm->voltage_set(dev, perflvl->voltage); 68 ret = pm->voltage_set(dev, perflvl->volt_min);
69 if (ret) { 69 if (ret) {
70 NV_ERROR(dev, "voltage_set %d failed: %d\n", 70 NV_ERROR(dev, "voltage_set %d failed: %d\n",
71 perflvl->voltage, ret); 71 perflvl->volt_min, ret);
72 } 72 }
73 } 73 }
74 74
@@ -146,8 +146,10 @@ nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
146 146
147 if (pm->voltage.supported && pm->voltage_get) { 147 if (pm->voltage.supported && pm->voltage_get) {
148 ret = pm->voltage_get(dev); 148 ret = pm->voltage_get(dev);
149 if (ret > 0) 149 if (ret > 0) {
150 perflvl->voltage = ret; 150 perflvl->volt_min = ret;
151 perflvl->volt_max = ret;
152 }
151 } 153 }
152 154
153 return 0; 155 return 0;
@@ -156,7 +158,7 @@ nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
156static void 158static void
157nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len) 159nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len)
158{ 160{
159 char c[16], s[16], v[16], f[16], t[16]; 161 char c[16], s[16], v[32], f[16], t[16];
160 162
161 c[0] = '\0'; 163 c[0] = '\0';
162 if (perflvl->core) 164 if (perflvl->core)
@@ -167,8 +169,14 @@ nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len)
167 snprintf(s, sizeof(s), " shader %dMHz", perflvl->shader / 1000); 169 snprintf(s, sizeof(s), " shader %dMHz", perflvl->shader / 1000);
168 170
169 v[0] = '\0'; 171 v[0] = '\0';
170 if (perflvl->voltage) 172 if (perflvl->volt_min && perflvl->volt_min != perflvl->volt_max) {
171 snprintf(v, sizeof(v), " voltage %dmV", perflvl->voltage / 1000); 173 snprintf(v, sizeof(v), " voltage %dmV-%dmV",
174 perflvl->volt_min / 1000, perflvl->volt_max / 1000);
175 } else
176 if (perflvl->volt_min) {
177 snprintf(v, sizeof(v), " voltage %dmV",
178 perflvl->volt_min / 1000);
179 }
172 180
173 f[0] = '\0'; 181 f[0] = '\0';
174 if (perflvl->fanspeed) 182 if (perflvl->fanspeed)