diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2011-06-09 16:57:07 +1000 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2011-09-20 16:01:14 +1000 |
commit | 3b5565ddfd8fe71f6470a5d240a6bb50ba90d4ff (patch) | |
tree | 2ff079e372de919ebc486fad11e528391ac134fb /drivers/gpu/drm/nouveau/nouveau_perf.c | |
parent | a31214ef3e6cf427afe76b54c67e11c92d2aaeb8 (diff) | |
download | blackbird-op-linux-3b5565ddfd8fe71f6470a5d240a6bb50ba90d4ff.tar.gz blackbird-op-linux-3b5565ddfd8fe71f6470a5d240a6bb50ba90d4ff.zip |
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, return &pm->memtimings.timing[entry[1]]; } +static void +nouveau_perf_voltage(struct drm_device *dev, struct bit_entry *P, + struct nouveau_pm_level *perflvl) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nvbios *bios = &dev_priv->vbios; + u8 *vmap; + int id; + + id = perflvl->volt_min; + perflvl->volt_min = 0; + + /* pre-fermi vbios stores the voltage level directly in the + * perflvl entry as a multiple of 10mV + */ + if (dev_priv->card_type < NV_C0) { + perflvl->volt_min = id * 10000; + perflvl->volt_max = perflvl->volt_min; + return; + } + + /* from fermi onwards, the perflvl stores an index into yet another + * vbios table containing a min/max voltage value for the perflvl + */ + if (P->version != 2 || P->length < 34) { + NV_DEBUG(dev, "where's our volt map table ptr? %d %d\n", + P->version, P->length); + return; + } + + vmap = ROMPTR(bios, P->data[32]); + if (!vmap) { + NV_DEBUG(dev, "volt map table pointer invalid\n"); + return; + } + + if (id < vmap[3]) { + vmap += vmap[1] + (vmap[2] * id); + perflvl->volt_min = ROM32(vmap[0]); + perflvl->volt_max = ROM32(vmap[4]); + } +} + void nouveau_perf_init(struct drm_device *dev) { @@ -204,7 +247,7 @@ nouveau_perf_init(struct drm_device *dev) case 0x15: perflvl->fanspeed = entry[55]; if (recordlen > 56) - perflvl->voltage = entry[56] * 10000; + perflvl->volt_min = entry[56]; perflvl->core = ROM32(entry[1]) * 10; perflvl->memory = ROM32(entry[5]) * 20; break; @@ -212,7 +255,7 @@ nouveau_perf_init(struct drm_device *dev) case 0x23: case 0x24: perflvl->fanspeed = entry[4]; - perflvl->voltage = entry[5] * 10000; + perflvl->volt_min = entry[5]; perflvl->core = ROM16(entry[6]) * 1000; if (dev_priv->chipset == 0x49 || @@ -224,7 +267,7 @@ nouveau_perf_init(struct drm_device *dev) break; case 0x25: perflvl->fanspeed = entry[4]; - perflvl->voltage = entry[5] * 10000; + perflvl->volt_min = entry[5]; perflvl->core = ROM16(entry[6]) * 1000; perflvl->shader = ROM16(entry[10]) * 1000; perflvl->memory = ROM16(entry[12]) * 1000; @@ -233,7 +276,7 @@ nouveau_perf_init(struct drm_device *dev) perflvl->memscript = ROM16(entry[2]); case 0x35: perflvl->fanspeed = entry[6]; - perflvl->voltage = entry[7] * 10000; + perflvl->volt_min = entry[7]; perflvl->core = ROM16(entry[8]) * 1000; perflvl->shader = ROM16(entry[10]) * 1000; perflvl->memory = ROM16(entry[12]) * 1000; @@ -243,7 +286,7 @@ nouveau_perf_init(struct drm_device *dev) case 0x40: #define subent(n) entry[perf[2] + ((n) * perf[3])] perflvl->fanspeed = 0; /*XXX*/ - perflvl->voltage = entry[2] * 10000; + perflvl->volt_min = entry[2]; if (dev_priv->card_type == NV_50) { perflvl->core = ROM16(subent(0)) & 0xfff; perflvl->shader = ROM16(subent(1)) & 0xfff; @@ -263,8 +306,9 @@ nouveau_perf_init(struct drm_device *dev) } /* make sure vid is valid */ - if (pm->voltage.supported && perflvl->voltage) { - vid = nouveau_volt_vid_lookup(dev, perflvl->voltage); + nouveau_perf_voltage(dev, &P, perflvl); + if (pm->voltage.supported && perflvl->volt_min) { + vid = nouveau_volt_vid_lookup(dev, perflvl->volt_min); if (vid < 0) { NV_DEBUG(dev, "drop perflvl %d, bad vid\n", i); entry += recordlen; |