diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2012-01-25 01:02:58 -0500 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2012-05-24 02:31:14 -0400 |
commit | 65115bb05a9380a256907ae307135248ac1c29b4 (patch) | |
tree | a7a37c77e2c3007e6038d97d4eb5b02416e9bc5e /drivers/gpu/drm/nouveau | |
parent | 074e747a6d371192419fb5abeabb9686d0cf24a5 (diff) |
drm/nva3/pm: hook up to ram reclocking helper
This gets us a start on memory timings.
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau')
-rw-r--r-- | drivers/gpu/drm/nouveau/nva3_pm.c | 122 |
1 files changed, 110 insertions, 12 deletions
diff --git a/drivers/gpu/drm/nouveau/nva3_pm.c b/drivers/gpu/drm/nouveau/nva3_pm.c index 0f93c54de80c..3d397845dca9 100644 --- a/drivers/gpu/drm/nouveau/nva3_pm.c +++ b/drivers/gpu/drm/nouveau/nva3_pm.c | |||
@@ -235,6 +235,7 @@ nva3_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) | |||
235 | } | 235 | } |
236 | 236 | ||
237 | struct nva3_pm_state { | 237 | struct nva3_pm_state { |
238 | struct nouveau_pm_level *perflvl; | ||
238 | struct creg nclk; | 239 | struct creg nclk; |
239 | struct creg sclk; | 240 | struct creg sclk; |
240 | struct creg mclk; | 241 | struct creg mclk; |
@@ -272,6 +273,7 @@ nva3_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl) | |||
272 | if (ret < 0) | 273 | if (ret < 0) |
273 | goto out; | 274 | goto out; |
274 | 275 | ||
276 | info->perflvl = perflvl; | ||
275 | out: | 277 | out: |
276 | if (ret < 0) { | 278 | if (ret < 0) { |
277 | kfree(info); | 279 | kfree(info); |
@@ -292,6 +294,112 @@ nva3_pm_grcp_idle(void *data) | |||
292 | return false; | 294 | return false; |
293 | } | 295 | } |
294 | 296 | ||
297 | static void | ||
298 | mclk_precharge(struct nouveau_mem_exec_func *exec) | ||
299 | { | ||
300 | nv_wr32(exec->dev, 0x1002d4, 0x00000001); | ||
301 | } | ||
302 | |||
303 | static void | ||
304 | mclk_refresh(struct nouveau_mem_exec_func *exec) | ||
305 | { | ||
306 | nv_wr32(exec->dev, 0x1002d0, 0x00000001); | ||
307 | } | ||
308 | |||
309 | static void | ||
310 | mclk_refresh_auto(struct nouveau_mem_exec_func *exec, bool enable) | ||
311 | { | ||
312 | nv_wr32(exec->dev, 0x100210, enable ? 0x80000000 : 0x00000000); | ||
313 | } | ||
314 | |||
315 | static void | ||
316 | mclk_refresh_self(struct nouveau_mem_exec_func *exec, bool enable) | ||
317 | { | ||
318 | nv_wr32(exec->dev, 0x1002dc, enable ? 0x00000001 : 0x00000000); | ||
319 | } | ||
320 | |||
321 | static void | ||
322 | mclk_wait(struct nouveau_mem_exec_func *exec, u32 nsec) | ||
323 | { | ||
324 | udelay((nsec + 500) / 1000); | ||
325 | } | ||
326 | |||
327 | static u32 | ||
328 | mclk_mrg(struct nouveau_mem_exec_func *exec, int mr) | ||
329 | { | ||
330 | if (mr <= 1) | ||
331 | return nv_rd32(exec->dev, 0x1002c0 + ((mr - 0) * 4)); | ||
332 | if (mr <= 3) | ||
333 | return nv_rd32(exec->dev, 0x1002e0 + ((mr - 2) * 4)); | ||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | static void | ||
338 | mclk_mrs(struct nouveau_mem_exec_func *exec, int mr, u32 data) | ||
339 | { | ||
340 | struct drm_nouveau_private *dev_priv = exec->dev->dev_private; | ||
341 | |||
342 | if (mr <= 1) { | ||
343 | if (dev_priv->vram_rank_B) | ||
344 | nv_wr32(exec->dev, 0x1002c8 + ((mr - 0) * 4), data); | ||
345 | nv_wr32(exec->dev, 0x1002c0 + ((mr - 0) * 4), data); | ||
346 | } else | ||
347 | if (mr <= 3) { | ||
348 | if (dev_priv->vram_rank_B) | ||
349 | nv_wr32(exec->dev, 0x1002e8 + ((mr - 2) * 4), data); | ||
350 | nv_wr32(exec->dev, 0x1002e0 + ((mr - 2) * 4), data); | ||
351 | } | ||
352 | } | ||
353 | |||
354 | static void | ||
355 | mclk_clock_set(struct nouveau_mem_exec_func *exec) | ||
356 | { | ||
357 | struct nva3_pm_state *info = exec->priv; | ||
358 | struct drm_device *dev = exec->dev; | ||
359 | |||
360 | nv_wr32(dev, 0x004018, 0x00001000); | ||
361 | |||
362 | prog_pll(dev, 0x02, 0x004000, &info->mclk); | ||
363 | |||
364 | if (nv_rd32(dev, 0x4000) & 0x00000008) | ||
365 | nv_wr32(dev, 0x004018, 0x1000d000); | ||
366 | else | ||
367 | nv_wr32(dev, 0x004018, 0x10005000); | ||
368 | } | ||
369 | |||
370 | static void | ||
371 | mclk_timing_set(struct nouveau_mem_exec_func *exec) | ||
372 | { | ||
373 | struct nva3_pm_state *info = exec->priv; | ||
374 | struct nouveau_pm_level *perflvl = info->perflvl; | ||
375 | int i; | ||
376 | |||
377 | for (i = 0; i < 9; i++) | ||
378 | nv_wr32(exec->dev, 0x100220 + (i * 4), perflvl->timing.reg[i]); | ||
379 | } | ||
380 | |||
381 | static void | ||
382 | prog_mem(struct drm_device *dev, struct nva3_pm_state *info) | ||
383 | { | ||
384 | struct nouveau_mem_exec_func exec = { | ||
385 | .dev = dev, | ||
386 | .precharge = mclk_precharge, | ||
387 | .refresh = mclk_refresh, | ||
388 | .refresh_auto = mclk_refresh_auto, | ||
389 | .refresh_self = mclk_refresh_self, | ||
390 | .wait = mclk_wait, | ||
391 | .mrg = mclk_mrg, | ||
392 | .mrs = mclk_mrs, | ||
393 | .clock_set = mclk_clock_set, | ||
394 | .timing_set = mclk_timing_set, | ||
395 | .priv = info | ||
396 | }; | ||
397 | |||
398 | nv_wr32(dev, 0x611200, 0x00003300); | ||
399 | nouveau_mem_exec(&exec, info->perflvl); | ||
400 | nv_wr32(dev, 0x611200, 0x00003330); | ||
401 | } | ||
402 | |||
295 | int | 403 | int |
296 | nva3_pm_clocks_set(struct drm_device *dev, void *pre_state) | 404 | nva3_pm_clocks_set(struct drm_device *dev, void *pre_state) |
297 | { | 405 | { |
@@ -321,18 +429,8 @@ nva3_pm_clocks_set(struct drm_device *dev, void *pre_state) | |||
321 | prog_clk(dev, 0x20, &info->unka0); | 429 | prog_clk(dev, 0x20, &info->unka0); |
322 | prog_clk(dev, 0x21, &info->vdec); | 430 | prog_clk(dev, 0x21, &info->vdec); |
323 | 431 | ||
324 | if (info->mclk.clk || info->mclk.pll) { | 432 | if (info->mclk.clk || info->mclk.pll) |
325 | nv_wr32(dev, 0x100210, 0); | 433 | prog_mem(dev, info); |
326 | nv_wr32(dev, 0x1002dc, 1); | ||
327 | nv_wr32(dev, 0x004018, 0x00001000); | ||
328 | prog_pll(dev, 0x02, 0x004000, &info->mclk); | ||
329 | if (nv_rd32(dev, 0x4000) & 0x00000008) | ||
330 | nv_wr32(dev, 0x004018, 0x1000d000); | ||
331 | else | ||
332 | nv_wr32(dev, 0x004018, 0x10005000); | ||
333 | nv_wr32(dev, 0x1002dc, 0); | ||
334 | nv_wr32(dev, 0x100210, 0x80000000); | ||
335 | } | ||
336 | 434 | ||
337 | ret = 0; | 435 | ret = 0; |
338 | 436 | ||