diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2011-06-09 02:57:07 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2011-09-20 02:01:14 -0400 |
commit | 3b5565ddfd8fe71f6470a5d240a6bb50ba90d4ff (patch) | |
tree | 2ff079e372de919ebc486fad11e528391ac134fb /drivers/gpu/drm/nouveau | |
parent | a31214ef3e6cf427afe76b54c67e11c92d2aaeb8 (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.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_perf.c | 58 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_pm.c | 24 |
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 | ||
137 | static void | ||
138 | nouveau_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 | |||
137 | void | 180 | void |
138 | nouveau_perf_init(struct drm_device *dev) | 181 | nouveau_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) | |||
156 | static void | 158 | static void |
157 | nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len) | 159 | nouveau_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) |