diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2011-04-19 21:31:04 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2011-05-15 20:50:33 -0400 |
commit | fcfc768806f2ed8ad56d9fd3f0c6af1cdb5e10e2 (patch) | |
tree | c60348c1e70107d7dacfe7c48c8960de9a2aa0c8 /drivers | |
parent | e614b2e7ca9f9946cede13b34c950b92af6fa7ef (diff) |
drm/nva3: support for memory timing map table
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_perf.c | 81 |
1 files changed, 67 insertions, 14 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_perf.c b/drivers/gpu/drm/nouveau/nouveau_perf.c index 5b87e68b00ae..92431a07d9bc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_perf.c +++ b/drivers/gpu/drm/nouveau/nouveau_perf.c | |||
@@ -72,6 +72,66 @@ legacy_perf_init(struct drm_device *dev) | |||
72 | pm->nr_perflvl = 1; | 72 | pm->nr_perflvl = 1; |
73 | } | 73 | } |
74 | 74 | ||
75 | static struct nouveau_pm_memtiming * | ||
76 | nouveau_perf_timing(struct drm_device *dev, struct bit_entry *P, | ||
77 | u16 memclk, u8 *entry, u8 recordlen, u8 entries) | ||
78 | { | ||
79 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
80 | struct nouveau_pm_engine *pm = &dev_priv->engine.pm; | ||
81 | struct nvbios *bios = &dev_priv->vbios; | ||
82 | u8 ramcfg; | ||
83 | int i; | ||
84 | |||
85 | /* perf v2 has a separate "timing map" table, we have to match | ||
86 | * the target memory clock to a specific entry, *then* use | ||
87 | * ramcfg to select the correct subentry | ||
88 | */ | ||
89 | if (P->version == 2) { | ||
90 | u8 *tmap = ROMPTR(bios, P->data[4]); | ||
91 | if (!tmap) { | ||
92 | NV_DEBUG(dev, "no timing map pointer\n"); | ||
93 | return NULL; | ||
94 | } | ||
95 | |||
96 | if (tmap[0] != 0x10) { | ||
97 | NV_WARN(dev, "timing map 0x%02x unknown\n", tmap[0]); | ||
98 | return NULL; | ||
99 | } | ||
100 | |||
101 | entry = tmap + tmap[1]; | ||
102 | recordlen = tmap[2] + (tmap[4] * tmap[3]); | ||
103 | for (i = 0; i < tmap[5]; i++, entry += recordlen) { | ||
104 | if (memclk >= ROM16(entry[0]) && | ||
105 | memclk <= ROM16(entry[2])) | ||
106 | break; | ||
107 | } | ||
108 | |||
109 | if (i == tmap[5]) { | ||
110 | NV_WARN(dev, "no match in timing map table\n"); | ||
111 | return NULL; | ||
112 | } | ||
113 | |||
114 | entry += tmap[2]; | ||
115 | recordlen = tmap[3]; | ||
116 | entries = tmap[4]; | ||
117 | } | ||
118 | |||
119 | ramcfg = nv_rd32(dev, NV_PEXTDEV_BOOT_0) & 0x0000003c; | ||
120 | ramcfg >>= 2; | ||
121 | if (ramcfg >= entries) { | ||
122 | NV_WARN(dev, "ramcfg strap out of bounds!\n"); | ||
123 | return NULL; | ||
124 | } | ||
125 | |||
126 | entry += ramcfg * recordlen; | ||
127 | if (entry[1] >= pm->memtimings.nr_timing) { | ||
128 | NV_WARN(dev, "timingset %d does not exist\n", entry[1]); | ||
129 | return NULL; | ||
130 | } | ||
131 | |||
132 | return &pm->memtimings.timing[entry[1]]; | ||
133 | } | ||
134 | |||
75 | void | 135 | void |
76 | nouveau_perf_init(struct drm_device *dev) | 136 | nouveau_perf_init(struct drm_device *dev) |
77 | { | 137 | { |
@@ -82,7 +142,6 @@ nouveau_perf_init(struct drm_device *dev) | |||
82 | u8 version, headerlen, recordlen, entries; | 142 | u8 version, headerlen, recordlen, entries; |
83 | u8 *perf, *entry; | 143 | u8 *perf, *entry; |
84 | int vid, i; | 144 | int vid, i; |
85 | u8 ramcfg = (nv_rd32(dev, NV_PEXTDEV_BOOT_0) & 0x3c) >> 2; | ||
86 | 145 | ||
87 | if (bios->type == NVBIOS_BIT) { | 146 | if (bios->type == NVBIOS_BIT) { |
88 | if (bit_table(dev, 'P', &P)) | 147 | if (bit_table(dev, 'P', &P)) |
@@ -194,19 +253,13 @@ nouveau_perf_init(struct drm_device *dev) | |||
194 | } | 253 | } |
195 | 254 | ||
196 | /* get the corresponding memory timings */ | 255 | /* get the corresponding memory timings */ |
197 | if (pm->memtimings.supported) { | 256 | if (pm->memtimings.supported && version > 0x15) { |
198 | u8 timing_id = 0xff; | 257 | /* last 3 args are for < 0x40, ignored for >= 0x40 */ |
199 | u16 extra_data; | 258 | perflvl->timing = |
200 | 259 | nouveau_perf_timing(dev, &P, | |
201 | if (version > 0x15 && version < 0x40 && | 260 | perflvl->memory / 1000, |
202 | ramcfg < perf[4]) { | 261 | entry + perf[3], |
203 | extra_data = perf[3] + (ramcfg * perf[5]); | 262 | perf[5], perf[4]); |
204 | timing_id = entry[extra_data + 1]; | ||
205 | } | ||
206 | |||
207 | if (pm->memtimings.nr_timing > timing_id) | ||
208 | perflvl->timing = | ||
209 | &pm->memtimings.timing[timing_id]; | ||
210 | } | 263 | } |
211 | 264 | ||
212 | snprintf(perflvl->name, sizeof(perflvl->name), | 265 | snprintf(perflvl->name, sizeof(perflvl->name), |