diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2011-10-25 19:11:02 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2011-12-21 04:01:24 -0500 |
commit | f3fbaf34e2b1459eab248c5f0180928e7861120b (patch) | |
tree | bd5bc90f52df47630e67dfd90e707500a88f3634 /drivers/gpu | |
parent | d4cca9e1fccb9f7804ddfbbc2aebff7be23faa1e (diff) |
drm/nv50/pm: rewrite clock management, and switch to the new pm hooks
This area is horrifically complicated on these chipsets, and it's likely we
will need at least a few more tweaks yet.
Oh yes, and it's completely disabled on IGPs for the moment. From traces,
things look potentially different there yet again. Sigh...
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drv.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_perf.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_pm.h | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_state.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_pm.c | 658 |
5 files changed, 576 insertions, 97 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 067bda411a21..95892ce9b59c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h | |||
@@ -493,6 +493,7 @@ struct nouveau_pm_level { | |||
493 | u32 copy; | 493 | u32 copy; |
494 | u32 daemon; | 494 | u32 daemon; |
495 | u32 vdec; | 495 | u32 vdec; |
496 | u32 dom6; | ||
496 | u32 unka0; /* nva3:nvc0 */ | 497 | u32 unka0; /* nva3:nvc0 */ |
497 | u32 hub01; /* nvc0- */ | 498 | u32 hub01; /* nvc0- */ |
498 | u32 hub06; /* nvc0- */ | 499 | u32 hub06; /* nvc0- */ |
diff --git a/drivers/gpu/drm/nouveau/nouveau_perf.c b/drivers/gpu/drm/nouveau/nouveau_perf.c index da584e3a8f6a..6d49bdbf93d0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_perf.c +++ b/drivers/gpu/drm/nouveau/nouveau_perf.c | |||
@@ -302,6 +302,7 @@ nouveau_perf_init(struct drm_device *dev) | |||
302 | perflvl->shader = ROM16(entry[10]) * 1000; | 302 | perflvl->shader = ROM16(entry[10]) * 1000; |
303 | perflvl->memory = ROM16(entry[12]) * 1000; | 303 | perflvl->memory = ROM16(entry[12]) * 1000; |
304 | perflvl->vdec = ROM16(entry[16]) * 1000; | 304 | perflvl->vdec = ROM16(entry[16]) * 1000; |
305 | perflvl->dom6 = ROM16(entry[20]) * 1000; | ||
305 | break; | 306 | break; |
306 | case 0x40: | 307 | case 0x40: |
307 | #define subent(n) (ROM16(entry[perf[2] + ((n) * perf[3])]) & 0xfff) * 1000 | 308 | #define subent(n) (ROM16(entry[perf[2] + ((n) * perf[3])]) & 0xfff) * 1000 |
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.h b/drivers/gpu/drm/nouveau/nouveau_pm.h index 41050feb5b90..06df411ca5fe 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.h +++ b/drivers/gpu/drm/nouveau/nouveau_pm.h | |||
@@ -60,10 +60,9 @@ int nv40_pm_pwm_get(struct drm_device *, struct dcb_gpio_entry *, u32*, u32*); | |||
60 | int nv40_pm_pwm_set(struct drm_device *, struct dcb_gpio_entry *, u32, u32); | 60 | int nv40_pm_pwm_set(struct drm_device *, struct dcb_gpio_entry *, u32, u32); |
61 | 61 | ||
62 | /* nv50_pm.c */ | 62 | /* nv50_pm.c */ |
63 | int nv50_pm_clock_get(struct drm_device *, u32 id); | 63 | int nv50_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *); |
64 | void *nv50_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *, | 64 | void *nv50_pm_clocks_pre(struct drm_device *, struct nouveau_pm_level *); |
65 | u32 id, int khz); | 65 | int nv50_pm_clocks_set(struct drm_device *, void *); |
66 | void nv50_pm_clock_set(struct drm_device *, void *); | ||
67 | int nv50_pm_pwm_get(struct drm_device *, struct dcb_gpio_entry *, u32*, u32*); | 66 | int nv50_pm_pwm_get(struct drm_device *, struct dcb_gpio_entry *, u32*, u32*); |
68 | int nv50_pm_pwm_set(struct drm_device *, struct dcb_gpio_entry *, u32, u32); | 67 | int nv50_pm_pwm_set(struct drm_device *, struct dcb_gpio_entry *, u32, u32); |
69 | 68 | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 31bca1dca85d..6b4aaec648b9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c | |||
@@ -356,9 +356,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) | |||
356 | case 0xaa: | 356 | case 0xaa: |
357 | case 0xac: | 357 | case 0xac: |
358 | case 0x50: | 358 | case 0x50: |
359 | engine->pm.clock_get = nv50_pm_clock_get; | 359 | engine->pm.clocks_get = nv50_pm_clocks_get; |
360 | engine->pm.clock_pre = nv50_pm_clock_pre; | 360 | engine->pm.clocks_pre = nv50_pm_clocks_pre; |
361 | engine->pm.clock_set = nv50_pm_clock_set; | 361 | engine->pm.clocks_set = nv50_pm_clocks_set; |
362 | break; | 362 | break; |
363 | default: | 363 | default: |
364 | engine->pm.clocks_get = nva3_pm_clocks_get; | 364 | engine->pm.clocks_get = nva3_pm_clocks_get; |
diff --git a/drivers/gpu/drm/nouveau/nv50_pm.c b/drivers/gpu/drm/nouveau/nv50_pm.c index 8a56880e4e71..bf9fd95c81c0 100644 --- a/drivers/gpu/drm/nouveau/nv50_pm.c +++ b/drivers/gpu/drm/nouveau/nv50_pm.c | |||
@@ -25,123 +25,601 @@ | |||
25 | #include "drmP.h" | 25 | #include "drmP.h" |
26 | #include "nouveau_drv.h" | 26 | #include "nouveau_drv.h" |
27 | #include "nouveau_bios.h" | 27 | #include "nouveau_bios.h" |
28 | #include "nouveau_hw.h" | ||
28 | #include "nouveau_pm.h" | 29 | #include "nouveau_pm.h" |
29 | 30 | ||
30 | struct nv50_pm_state { | 31 | enum clk_src { |
31 | struct nouveau_pm_level *perflvl; | 32 | clk_src_crystal, |
32 | struct pll_lims pll; | 33 | clk_src_href, |
33 | enum pll_types type; | 34 | clk_src_hclk, |
34 | int N, M, P; | 35 | clk_src_hclkm3, |
36 | clk_src_hclkm3d2, | ||
37 | clk_src_host, | ||
38 | clk_src_nvclk, | ||
39 | clk_src_sclk, | ||
40 | clk_src_mclk, | ||
41 | clk_src_vdec, | ||
42 | clk_src_dom6 | ||
35 | }; | 43 | }; |
36 | 44 | ||
45 | static u32 read_clk(struct drm_device *, enum clk_src); | ||
46 | |||
47 | static u32 | ||
48 | read_div(struct drm_device *dev) | ||
49 | { | ||
50 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
51 | |||
52 | switch (dev_priv->chipset) { | ||
53 | case 0x50: /* it exists, but only has bit 31, not the dividers.. */ | ||
54 | case 0x84: | ||
55 | case 0x86: | ||
56 | case 0x98: | ||
57 | case 0xa0: | ||
58 | return nv_rd32(dev, 0x004700); | ||
59 | case 0x92: | ||
60 | case 0x94: | ||
61 | case 0x96: | ||
62 | return nv_rd32(dev, 0x004800); | ||
63 | default: | ||
64 | return 0x00000000; | ||
65 | } | ||
66 | } | ||
67 | |||
68 | static u32 | ||
69 | read_pll_ref(struct drm_device *dev, u32 base) | ||
70 | { | ||
71 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
72 | u32 coef, ref = read_clk(dev, clk_src_crystal); | ||
73 | u32 rsel = nv_rd32(dev, 0x00e18c); | ||
74 | int P, N, M, id; | ||
75 | |||
76 | switch (dev_priv->chipset) { | ||
77 | case 0x50: | ||
78 | case 0xa0: | ||
79 | switch (base) { | ||
80 | case 0x4020: | ||
81 | case 0x4028: id = !!(rsel & 0x00000004); break; | ||
82 | case 0x4008: id = !!(rsel & 0x00000008); break; | ||
83 | case 0x4030: id = 0; break; | ||
84 | default: | ||
85 | NV_ERROR(dev, "ref: bad pll 0x%06x\n", base); | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | coef = nv_rd32(dev, 0x00e81c + (id * 0x0c)); | ||
90 | ref *= (coef & 0x01000000) ? 2 : 4; | ||
91 | P = (coef & 0x00070000) >> 16; | ||
92 | N = ((coef & 0x0000ff00) >> 8) + 1; | ||
93 | M = ((coef & 0x000000ff) >> 0) + 1; | ||
94 | break; | ||
95 | case 0x84: | ||
96 | case 0x86: | ||
97 | case 0x92: | ||
98 | coef = nv_rd32(dev, 0x00e81c); | ||
99 | P = (coef & 0x00070000) >> 16; | ||
100 | N = (coef & 0x0000ff00) >> 8; | ||
101 | M = (coef & 0x000000ff) >> 0; | ||
102 | break; | ||
103 | case 0x94: | ||
104 | case 0x96: | ||
105 | case 0x98: | ||
106 | rsel = nv_rd32(dev, 0x00c050); | ||
107 | switch (base) { | ||
108 | case 0x4020: rsel = (rsel & 0x00000003) >> 0; break; | ||
109 | case 0x4008: rsel = (rsel & 0x0000000c) >> 2; break; | ||
110 | case 0x4028: rsel = (rsel & 0x00001800) >> 11; break; | ||
111 | case 0x4030: rsel = 3; break; | ||
112 | default: | ||
113 | NV_ERROR(dev, "ref: bad pll 0x%06x\n", base); | ||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | switch (rsel) { | ||
118 | case 0: id = 1; break; | ||
119 | case 1: return read_clk(dev, clk_src_crystal); | ||
120 | case 2: return read_clk(dev, clk_src_href); | ||
121 | case 3: id = 0; break; | ||
122 | } | ||
123 | |||
124 | coef = nv_rd32(dev, 0x00e81c + (id * 0x28)); | ||
125 | P = (nv_rd32(dev, 0x00e824 + (id * 0x28)) >> 16) & 7; | ||
126 | P += (coef & 0x00070000) >> 16; | ||
127 | N = (coef & 0x0000ff00) >> 8; | ||
128 | M = (coef & 0x000000ff) >> 0; | ||
129 | break; | ||
130 | default: | ||
131 | BUG_ON(1); | ||
132 | } | ||
133 | |||
134 | if (M) | ||
135 | return (ref * N / M) >> P; | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | static u32 | ||
140 | read_pll(struct drm_device *dev, u32 base) | ||
141 | { | ||
142 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
143 | u32 mast = nv_rd32(dev, 0x00c040); | ||
144 | u32 src = 0, ref = 0, clk = 0; | ||
145 | u32 ctrl, coef; | ||
146 | int N1, N2, M1, M2; | ||
147 | |||
148 | switch (base) { | ||
149 | case 0x004028: | ||
150 | if (mast & 0x00100000) { | ||
151 | /* wtf, appears to only disable post-divider on nva0 */ | ||
152 | if (dev_priv->chipset != 0xa0) | ||
153 | return read_clk(dev, clk_src_dom6); | ||
154 | } | ||
155 | src = !!(mast & 0x00200000); | ||
156 | break; | ||
157 | case 0x004020: | ||
158 | src = !!(mast & 0x00400000); | ||
159 | break; | ||
160 | case 0x004008: | ||
161 | src = !!(mast & 0x00010000); | ||
162 | break; | ||
163 | case 0x004030: | ||
164 | src = !!(mast & 0x02000000); | ||
165 | break; | ||
166 | case 0x00e810: | ||
167 | ref = read_clk(dev, clk_src_crystal); | ||
168 | break; | ||
169 | default: | ||
170 | NV_ERROR(dev, "bad pll 0x%06x\n", base); | ||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | if (ref == 0) { | ||
175 | if (src) | ||
176 | ref = read_clk(dev, clk_src_href); | ||
177 | else | ||
178 | ref = read_pll_ref(dev, base); | ||
179 | } | ||
180 | |||
181 | ctrl = nv_rd32(dev, base + 0); | ||
182 | coef = nv_rd32(dev, base + 4); | ||
183 | |||
184 | N2 = (coef & 0xff000000) >> 24; | ||
185 | M2 = (coef & 0x00ff0000) >> 16; | ||
186 | N1 = (coef & 0x0000ff00) >> 8; | ||
187 | M1 = (coef & 0x000000ff); | ||
188 | if ((ctrl & 0x80000000) && M1) { | ||
189 | clk = ref * N1 / M1; | ||
190 | if ((ctrl & 0x40000100) == 0x40000000) { | ||
191 | if (M2) | ||
192 | clk = clk * N2 / M2; | ||
193 | else | ||
194 | clk = 0; | ||
195 | } | ||
196 | } | ||
197 | |||
198 | return clk; | ||
199 | } | ||
200 | |||
201 | static u32 | ||
202 | read_clk(struct drm_device *dev, enum clk_src src) | ||
203 | { | ||
204 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
205 | u32 mast = nv_rd32(dev, 0x00c040); | ||
206 | u32 P = 0; | ||
207 | |||
208 | switch (src) { | ||
209 | case clk_src_crystal: | ||
210 | return dev_priv->crystal; | ||
211 | case clk_src_href: | ||
212 | return 100000; /* PCIE reference clock */ | ||
213 | case clk_src_hclk: | ||
214 | return read_clk(dev, clk_src_href) * 27778 / 10000; | ||
215 | case clk_src_hclkm3: | ||
216 | return read_clk(dev, clk_src_hclk) * 3; | ||
217 | case clk_src_hclkm3d2: | ||
218 | return read_clk(dev, clk_src_hclk) * 3 / 2; | ||
219 | case clk_src_host: | ||
220 | switch (mast & 0x30000000) { | ||
221 | case 0x00000000: return read_clk(dev, clk_src_href); | ||
222 | case 0x10000000: break; | ||
223 | case 0x20000000: /* !0x50 */ | ||
224 | case 0x30000000: return read_clk(dev, clk_src_hclk); | ||
225 | } | ||
226 | break; | ||
227 | case clk_src_nvclk: | ||
228 | if (!(mast & 0x00100000)) | ||
229 | P = (nv_rd32(dev, 0x004028) & 0x00070000) >> 16; | ||
230 | switch (mast & 0x00000003) { | ||
231 | case 0x00000000: return read_clk(dev, clk_src_crystal) >> P; | ||
232 | case 0x00000001: return read_clk(dev, clk_src_dom6); | ||
233 | case 0x00000002: return read_pll(dev, 0x004020) >> P; | ||
234 | case 0x00000003: return read_pll(dev, 0x004028) >> P; | ||
235 | } | ||
236 | break; | ||
237 | case clk_src_sclk: | ||
238 | P = (nv_rd32(dev, 0x004020) & 0x00070000) >> 16; | ||
239 | switch (mast & 0x00000030) { | ||
240 | case 0x00000000: | ||
241 | if (mast & 0x00000080) | ||
242 | return read_clk(dev, clk_src_host) >> P; | ||
243 | return read_clk(dev, clk_src_crystal) >> P; | ||
244 | case 0x00000010: break; | ||
245 | case 0x00000020: return read_pll(dev, 0x004028) >> P; | ||
246 | case 0x00000030: return read_pll(dev, 0x004020) >> P; | ||
247 | } | ||
248 | break; | ||
249 | case clk_src_mclk: | ||
250 | P = (nv_rd32(dev, 0x004008) & 0x00070000) >> 16; | ||
251 | if (nv_rd32(dev, 0x004008) & 0x00000200) { | ||
252 | switch (mast & 0x0000c000) { | ||
253 | case 0x00000000: | ||
254 | return read_clk(dev, clk_src_crystal) >> P; | ||
255 | case 0x00008000: | ||
256 | case 0x0000c000: | ||
257 | return read_clk(dev, clk_src_href) >> P; | ||
258 | } | ||
259 | } else { | ||
260 | return read_pll(dev, 0x004008) >> P; | ||
261 | } | ||
262 | break; | ||
263 | case clk_src_vdec: | ||
264 | P = (read_div(dev) & 0x00000700) >> 8; | ||
265 | switch (dev_priv->chipset) { | ||
266 | case 0x84: | ||
267 | case 0x86: | ||
268 | case 0x92: | ||
269 | case 0x94: | ||
270 | case 0x96: | ||
271 | case 0xa0: | ||
272 | switch (mast & 0x00000c00) { | ||
273 | case 0x00000000: | ||
274 | if (dev_priv->chipset == 0xa0) /* wtf?? */ | ||
275 | return read_clk(dev, clk_src_nvclk) >> P; | ||
276 | return read_clk(dev, clk_src_crystal) >> P; | ||
277 | case 0x00000400: | ||
278 | return 0; | ||
279 | case 0x00000800: | ||
280 | if (mast & 0x01000000) | ||
281 | return read_pll(dev, 0x004028) >> P; | ||
282 | return read_pll(dev, 0x004030) >> P; | ||
283 | case 0x00000c00: | ||
284 | return read_clk(dev, clk_src_nvclk) >> P; | ||
285 | } | ||
286 | break; | ||
287 | case 0x98: | ||
288 | switch (mast & 0x00000c00) { | ||
289 | case 0x00000000: | ||
290 | return read_clk(dev, clk_src_nvclk) >> P; | ||
291 | case 0x00000400: | ||
292 | return 0; | ||
293 | case 0x00000800: | ||
294 | return read_clk(dev, clk_src_hclkm3d2) >> P; | ||
295 | case 0x00000c00: | ||
296 | return read_pll(dev, clk_src_mclk) >> P; | ||
297 | } | ||
298 | break; | ||
299 | } | ||
300 | break; | ||
301 | case clk_src_dom6: | ||
302 | switch (dev_priv->chipset) { | ||
303 | case 0x50: | ||
304 | case 0xa0: | ||
305 | return read_pll(dev, 0x00e810) >> 2; | ||
306 | case 0x84: | ||
307 | case 0x86: | ||
308 | case 0x92: | ||
309 | case 0x94: | ||
310 | case 0x96: | ||
311 | case 0x98: | ||
312 | P = (read_div(dev) & 0x00000007) >> 0; | ||
313 | switch (mast & 0x0c000000) { | ||
314 | case 0x00000000: return read_clk(dev, clk_src_href); | ||
315 | case 0x04000000: break; | ||
316 | case 0x08000000: return read_clk(dev, clk_src_hclk); | ||
317 | case 0x0c000000: | ||
318 | return read_clk(dev, clk_src_hclkm3) >> P; | ||
319 | } | ||
320 | break; | ||
321 | default: | ||
322 | break; | ||
323 | } | ||
324 | default: | ||
325 | break; | ||
326 | } | ||
327 | |||
328 | NV_DEBUG(dev, "unknown clock source %d 0x%08x\n", src, mast); | ||
329 | return 0; | ||
330 | } | ||
331 | |||
37 | int | 332 | int |
38 | nv50_pm_clock_get(struct drm_device *dev, u32 id) | 333 | nv50_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) |
39 | { | 334 | { |
40 | struct pll_lims pll; | 335 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
41 | int P, N, M, ret; | 336 | if (dev_priv->chipset == 0xaa || |
42 | u32 reg0, reg1; | 337 | dev_priv->chipset == 0xac) |
338 | return 0; | ||
339 | |||
340 | perflvl->core = read_clk(dev, clk_src_nvclk); | ||
341 | perflvl->shader = read_clk(dev, clk_src_sclk); | ||
342 | perflvl->memory = read_clk(dev, clk_src_mclk); | ||
343 | if (dev_priv->chipset != 0x50) { | ||
344 | perflvl->vdec = read_clk(dev, clk_src_vdec); | ||
345 | perflvl->dom6 = read_clk(dev, clk_src_dom6); | ||
346 | } | ||
43 | 347 | ||
44 | ret = get_pll_limits(dev, id, &pll); | 348 | return 0; |
349 | } | ||
350 | |||
351 | struct nv50_pm_state { | ||
352 | u32 emast; | ||
353 | u32 nctrl; | ||
354 | u32 ncoef; | ||
355 | u32 sctrl; | ||
356 | u32 scoef; | ||
357 | |||
358 | u32 amast; | ||
359 | u32 pdivs; | ||
360 | |||
361 | u32 mscript; | ||
362 | u32 mctrl; | ||
363 | u32 mcoef; | ||
364 | }; | ||
365 | |||
366 | static u32 | ||
367 | calc_pll(struct drm_device *dev, u32 reg, struct pll_lims *pll, | ||
368 | u32 clk, int *N1, int *M1, int *log2P) | ||
369 | { | ||
370 | struct nouveau_pll_vals coef; | ||
371 | int ret; | ||
372 | |||
373 | ret = get_pll_limits(dev, reg, pll); | ||
45 | if (ret) | 374 | if (ret) |
46 | return ret; | 375 | return 0; |
376 | |||
377 | pll->vco2.maxfreq = 0; | ||
378 | pll->refclk = read_pll_ref(dev, reg); | ||
379 | if (!pll->refclk) | ||
380 | return 0; | ||
381 | |||
382 | ret = nouveau_calc_pll_mnp(dev, pll, clk, &coef); | ||
383 | if (ret == 0) | ||
384 | return 0; | ||
47 | 385 | ||
48 | reg0 = nv_rd32(dev, pll.reg + 0); | 386 | *N1 = coef.N1; |
49 | reg1 = nv_rd32(dev, pll.reg + 4); | 387 | *M1 = coef.M1; |
50 | 388 | *log2P = coef.log2P; | |
51 | if ((reg0 & 0x80000000) == 0) { | 389 | return ret; |
52 | if (id == PLL_SHADER) { | 390 | } |
53 | NV_DEBUG(dev, "Shader PLL is disabled. " | 391 | |
54 | "Shader clock is twice the core\n"); | 392 | static inline u32 |
55 | ret = nv50_pm_clock_get(dev, PLL_CORE); | 393 | calc_div(u32 src, u32 target, int *div) |
56 | if (ret > 0) | 394 | { |
57 | return ret << 1; | 395 | u32 clk0 = src, clk1 = src; |
58 | } else if (id == PLL_MEMORY) { | 396 | for (*div = 0; *div <= 7; (*div)++) { |
59 | NV_DEBUG(dev, "Memory PLL is disabled. " | 397 | if (clk0 <= target) { |
60 | "Memory clock is equal to the ref_clk\n"); | 398 | clk1 = clk0 << (*div ? 1 : 0); |
61 | return pll.refclk; | 399 | break; |
62 | } | 400 | } |
401 | clk0 >>= 1; | ||
63 | } | 402 | } |
64 | 403 | ||
65 | P = (reg0 & 0x00070000) >> 16; | 404 | if (target - clk0 <= clk1 - target) |
66 | N = (reg1 & 0x0000ff00) >> 8; | 405 | return clk0; |
67 | M = (reg1 & 0x000000ff); | 406 | (*div)--; |
407 | return clk1; | ||
408 | } | ||
68 | 409 | ||
69 | return ((pll.refclk * N / M) >> P); | 410 | static inline u32 |
411 | clk_same(u32 a, u32 b) | ||
412 | { | ||
413 | return ((a / 1000) == (b / 1000)); | ||
70 | } | 414 | } |
71 | 415 | ||
72 | void * | 416 | void * |
73 | nv50_pm_clock_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl, | 417 | nv50_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl) |
74 | u32 id, int khz) | ||
75 | { | 418 | { |
76 | struct nv50_pm_state *state; | 419 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
77 | int dummy, ret; | 420 | struct nv50_pm_state *info; |
421 | struct pll_lims pll; | ||
422 | int ret = -EINVAL; | ||
423 | int N, M, P1, P2; | ||
424 | u32 clk, out; | ||
425 | |||
426 | if (dev_priv->chipset == 0xaa || | ||
427 | dev_priv->chipset == 0xac) | ||
428 | return ERR_PTR(-ENODEV); | ||
78 | 429 | ||
79 | state = kzalloc(sizeof(*state), GFP_KERNEL); | 430 | info = kmalloc(sizeof(*info), GFP_KERNEL); |
80 | if (!state) | 431 | if (!info) |
81 | return ERR_PTR(-ENOMEM); | 432 | return ERR_PTR(-ENOMEM); |
82 | state->type = id; | ||
83 | state->perflvl = perflvl; | ||
84 | 433 | ||
85 | ret = get_pll_limits(dev, id, &state->pll); | 434 | /* core: for the moment at least, always use nvpll */ |
86 | if (ret < 0) { | 435 | clk = calc_pll(dev, 0x4028, &pll, perflvl->core, &N, &M, &P1); |
87 | kfree(state); | 436 | if (clk == 0) |
88 | return (ret == -ENOENT) ? NULL : ERR_PTR(ret); | 437 | goto error; |
438 | |||
439 | info->emast = 0x00000003; | ||
440 | info->nctrl = 0x80000000 | (P1 << 19) | (P1 << 16); | ||
441 | info->ncoef = (N << 8) | M; | ||
442 | |||
443 | /* shader: tie to nvclk if possible, otherwise use spll. have to be | ||
444 | * very careful that the shader clock is at least twice the core, or | ||
445 | * some chipsets will be very unhappy. i expect most or all of these | ||
446 | * cases will be handled by tying to nvclk, but it's possible there's | ||
447 | * corners | ||
448 | */ | ||
449 | if (P1-- && perflvl->shader == (perflvl->core << 1)) { | ||
450 | info->emast |= 0x00000020; | ||
451 | info->sctrl = 0x00000000 | (P1 << 19) | (P1 << 16); | ||
452 | info->scoef = nv_rd32(dev, 0x004024); | ||
453 | } else { | ||
454 | clk = calc_pll(dev, 0x4020, &pll, perflvl->shader, &N, &M, &P1); | ||
455 | if (clk == 0) | ||
456 | goto error; | ||
457 | |||
458 | info->emast |= 0x00000030; | ||
459 | info->sctrl = 0x80000000 | (P1 << 19) | (P1 << 16); | ||
460 | info->scoef = (N << 8) | M; | ||
89 | } | 461 | } |
90 | 462 | ||
91 | ret = nv50_calc_pll(dev, &state->pll, khz, &state->N, &state->M, | 463 | /* memory: use pcie refclock if possible, otherwise use mpll */ |
92 | &dummy, &dummy, &state->P); | 464 | info->mscript = perflvl->memscript; |
93 | if (ret < 0) { | 465 | if (clk_same(perflvl->memory, read_clk(dev, clk_src_href))) { |
94 | kfree(state); | 466 | info->mctrl = nv_rd32(dev, 0x4008) | 0x00000200; |
95 | return ERR_PTR(ret); | 467 | info->mcoef = nv_rd32(dev, 0x400c); |
468 | } else | ||
469 | if (perflvl->memory) { | ||
470 | clk = calc_pll(dev, 0x4008, &pll, perflvl->memory, | ||
471 | &N, &M, &P1); | ||
472 | if (clk == 0) | ||
473 | goto error; | ||
474 | |||
475 | info->mctrl = 0x80000000 | (P1 << 22) | (P1 << 16); | ||
476 | info->mctrl |= pll.log2p_bias << 19; | ||
477 | info->mcoef = (N << 8) | M; | ||
478 | } else { | ||
479 | info->mctrl = 0x00000000; | ||
96 | } | 480 | } |
97 | 481 | ||
98 | return state; | 482 | /* vdec: avoid modifying xpll until we know exactly how the other |
483 | * clock domains work, i suspect at least some of them can also be | ||
484 | * tied to xpll... | ||
485 | */ | ||
486 | info->amast = info->pdivs = 0; | ||
487 | if (perflvl->vdec) { | ||
488 | /* see how close we can get using nvclk as a source */ | ||
489 | clk = calc_div(perflvl->core, perflvl->vdec, &P1); | ||
490 | |||
491 | /* see how close we can get using xpll/hclk as a source */ | ||
492 | if (dev_priv->chipset != 0x98) | ||
493 | out = read_pll(dev, 0x004030); | ||
494 | else | ||
495 | out = read_clk(dev, clk_src_hclkm3d2); | ||
496 | out = calc_div(out, perflvl->vdec, &P2); | ||
497 | |||
498 | /* select whichever gets us closest */ | ||
499 | if (abs((int)perflvl->vdec - clk) <= | ||
500 | abs((int)perflvl->vdec - out)) { | ||
501 | if (dev_priv->chipset != 0x98) | ||
502 | info->amast |= 0x00000c00; | ||
503 | else | ||
504 | info->amast |= 0x00000000; | ||
505 | info->pdivs |= P1 << 8; | ||
506 | } else { | ||
507 | info->amast |= 0x00000800; | ||
508 | info->pdivs |= P2 << 8; | ||
509 | } | ||
510 | } | ||
511 | |||
512 | /* dom6: nfi what this is, but we're limited to various combinations | ||
513 | * of the host clock frequency | ||
514 | */ | ||
515 | if (clk_same(perflvl->dom6, read_clk(dev, clk_src_href))) { | ||
516 | info->amast |= 0x00000000; | ||
517 | info->pdivs |= read_div(dev) & 0x00000007; | ||
518 | } else | ||
519 | if (clk_same(perflvl->dom6, read_clk(dev, clk_src_hclk))) { | ||
520 | info->amast |= 0x08000000; | ||
521 | info->pdivs |= read_div(dev) & 0x00000007; | ||
522 | } else | ||
523 | if (perflvl->dom6) { | ||
524 | clk = read_clk(dev, clk_src_hclk) * 3; | ||
525 | clk = calc_div(clk, perflvl->dom6, &P1); | ||
526 | |||
527 | info->amast |= 0x0c000000; | ||
528 | info->pdivs |= P1; | ||
529 | } | ||
530 | |||
531 | |||
532 | return info; | ||
533 | error: | ||
534 | kfree(info); | ||
535 | return ERR_PTR(ret); | ||
99 | } | 536 | } |
100 | 537 | ||
101 | void | 538 | int |
102 | nv50_pm_clock_set(struct drm_device *dev, void *pre_state) | 539 | nv50_pm_clocks_set(struct drm_device *dev, void *data) |
103 | { | 540 | { |
104 | struct nv50_pm_state *state = pre_state; | 541 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
105 | struct nouveau_pm_level *perflvl = state->perflvl; | 542 | struct nv50_pm_state *info = data; |
106 | u32 reg = state->pll.reg, tmp; | 543 | struct bit_entry M; |
107 | struct bit_entry BIT_M; | 544 | int ret = 0; |
108 | u16 script; | 545 | |
109 | int N = state->N; | 546 | /* halt and idle execution engines */ |
110 | int M = state->M; | 547 | nv_mask(dev, 0x002504, 0x00000001, 0x00000001); |
111 | int P = state->P; | 548 | if (!nv_wait(dev, 0x002504, 0x00000010, 0x00000010)) |
112 | 549 | goto error; | |
113 | if (state->type == PLL_MEMORY && perflvl->memscript && | 550 | |
114 | bit_table(dev, 'M', &BIT_M) == 0 && | 551 | /* reclock vdec/dom6 */ |
115 | BIT_M.version == 1 && BIT_M.length >= 0x0b) { | 552 | nv_mask(dev, 0x00c040, 0x00000c00, 0x00000000); |
116 | script = ROM16(BIT_M.data[0x05]); | 553 | switch (dev_priv->chipset) { |
117 | if (script) | 554 | case 0x92: |
118 | nouveau_bios_run_init_table(dev, script, NULL, -1); | 555 | case 0x94: |
119 | script = ROM16(BIT_M.data[0x07]); | 556 | case 0x96: |
120 | if (script) | 557 | nv_mask(dev, 0x004800, 0x00000707, info->pdivs); |
121 | nouveau_bios_run_init_table(dev, script, NULL, -1); | 558 | break; |
122 | script = ROM16(BIT_M.data[0x09]); | 559 | default: |
123 | if (script) | 560 | nv_mask(dev, 0x004700, 0x00000707, info->pdivs); |
124 | nouveau_bios_run_init_table(dev, script, NULL, -1); | 561 | break; |
125 | 562 | } | |
126 | nouveau_bios_run_init_table(dev, perflvl->memscript, NULL, -1); | 563 | nv_mask(dev, 0x00c040, 0x0c000c00, info->amast); |
127 | } | 564 | |
128 | 565 | /* core/shader: switch core to dom6, shader to hclk */ | |
129 | if (state->type == PLL_MEMORY) { | 566 | if (dev_priv->chipset == 0x50) |
130 | nv_wr32(dev, 0x100210, 0); | 567 | nv_mask(dev, 0x00c040, 0x001000b0, 0x00100080); /* grrr! */ |
131 | nv_wr32(dev, 0x1002dc, 1); | 568 | else |
132 | } | 569 | nv_mask(dev, 0x00c040, 0x000000b3, 0x00000081); |
133 | 570 | nv_mask(dev, 0x004020, 0xc03f0100, info->sctrl); | |
134 | tmp = nv_rd32(dev, reg + 0) & 0xfff8ffff; | 571 | nv_wr32(dev, 0x004024, info->scoef); |
135 | tmp |= 0x80000000 | (P << 16); | 572 | nv_mask(dev, 0x004028, 0xc03f0100, info->nctrl); |
136 | nv_wr32(dev, reg + 0, tmp); | 573 | nv_wr32(dev, 0x00402c, info->ncoef); |
137 | nv_wr32(dev, reg + 4, (N << 8) | M); | 574 | nv_mask(dev, 0x00c040, 0x00100033, info->emast); |
138 | 575 | ||
139 | if (state->type == PLL_MEMORY) { | 576 | /* memory */ |
140 | nv_wr32(dev, 0x1002dc, 0); | 577 | if (!info->mctrl) |
141 | nv_wr32(dev, 0x100210, 0x80000000); | 578 | goto resume; |
142 | } | 579 | |
143 | 580 | /* execute some scripts that do ??? from the vbios.. */ | |
144 | kfree(state); | 581 | if (!bit_table(dev, 'M', &M) && M.version == 1) { |
582 | if (M.length >= 6) | ||
583 | nouveau_bios_init_exec(dev, ROM16(M.data[5])); | ||
584 | if (M.length >= 8) | ||
585 | nouveau_bios_init_exec(dev, ROM16(M.data[7])); | ||
586 | if (M.length >= 10) | ||
587 | nouveau_bios_init_exec(dev, ROM16(M.data[9])); | ||
588 | nouveau_bios_init_exec(dev, info->mscript); | ||
589 | } | ||
590 | |||
591 | /* disable display */ | ||
592 | nv_wr32(dev, 0x611200, 0x00003300); | ||
593 | udelay(100); | ||
594 | |||
595 | /* prepare ram for reclocking */ | ||
596 | nv_wr32(dev, 0x1002d4, 0x00000001); /* precharge */ | ||
597 | nv_wr32(dev, 0x1002d0, 0x00000001); /* refresh */ | ||
598 | nv_wr32(dev, 0x1002d0, 0x00000001); /* refresh */ | ||
599 | nv_mask(dev, 0x100210, 0x80000000, 0x00000000); /* no auto-refresh */ | ||
600 | nv_wr32(dev, 0x1002dc, 0x00000001); /* enable self-refresh */ | ||
601 | |||
602 | /* modify mpll */ | ||
603 | nv_mask(dev, 0x00c040, 0x0000c000, 0x0000c000); | ||
604 | nv_mask(dev, 0x004008, 0x81ff0200, 0x00000200 | info->mctrl); | ||
605 | nv_wr32(dev, 0x00400c, info->mcoef); | ||
606 | udelay(100); | ||
607 | nv_mask(dev, 0x004008, 0x81ff0200, info->mctrl); | ||
608 | |||
609 | /* re-enable normal operation of memory controller */ | ||
610 | nv_wr32(dev, 0x1002dc, 0x00000000); | ||
611 | nv_mask(dev, 0x100210, 0x80000000, 0x80000000); | ||
612 | udelay(100); | ||
613 | |||
614 | /* re-enable display */ | ||
615 | nv_wr32(dev, 0x611200, 0x00003330); | ||
616 | |||
617 | goto resume; | ||
618 | error: | ||
619 | ret = -EBUSY; | ||
620 | resume: | ||
621 | nv_mask(dev, 0x002504, 0x00000001, 0x00000000); | ||
622 | return ret; | ||
145 | } | 623 | } |
146 | 624 | ||
147 | static int | 625 | static int |