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/nouveau_perf.c | |
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/nouveau_perf.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_perf.c | 58 |
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 | ||
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; |