Hi,
Please merge this patch, it helps a lot when it comes to safe
re-clocking. It isn't perfect yet but it will satisfy most users.
Cheers,
Martin
From 58605d78ec7a576502a8f46953f6e2f0092eb180 Mon Sep 17 00:00:00 2001
From: Martin Peres martin.pe...@ensi-bourges.fr
Date: Thu, 28 Oct 2010 20:27:08 +0200
Subject: [PATCH] Pause the card before reclocking
Signed-off-by: Martin Peres martin.pe...@ensi-bourges.fr
---
drivers/gpu/drm/nouveau/nouveau_drv.h | 10 ++
drivers/gpu/drm/nouveau/nouveau_pm.c| 50 +-
drivers/gpu/drm/nouveau/nouveau_reg.h |3 ++
drivers/gpu/drm/nouveau/nouveau_state.c | 35 +-
drivers/gpu/drm/nouveau/nv50_fifo.c | 18 +++
drivers/gpu/drm/nouveau/nv50_graph.c| 46
6 files changed, 159 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index fc162c2..6f3b81b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -338,6 +338,9 @@ struct nouveau_fifo_engine {
int (*load_context)(struct nouveau_channel *);
int (*unload_context)(struct drm_device *);
void (*tlb_flush)(struct drm_device *dev);
+
+ int (*pause)(struct drm_device *);
+ void (*unpause)(struct drm_device *);
};
struct nouveau_pgraph_engine {
@@ -361,6 +364,9 @@ struct nouveau_pgraph_engine {
void (*tlb_flush)(struct drm_device *dev);
void (*set_tile_region)(struct drm_device *dev, int i);
+
+ int (*pause)(struct drm_device *);
+ void (*unpause)(struct drm_device *);
};
struct nouveau_display_engine {
@@ -1076,6 +1082,8 @@ extern void nv50_fifo_destroy_context(struct nouveau_channel *);
extern int nv50_fifo_load_context(struct nouveau_channel *);
extern int nv50_fifo_unload_context(struct drm_device *);
extern void nv50_fifo_tlb_flush(struct drm_device *dev);
+extern int nv50_fifo_pause(struct drm_device *);
+extern void nv50_fifo_unpause(struct drm_device *);
/* nvc0_fifo.c */
extern int nvc0_fifo_init(struct drm_device *);
@@ -1148,6 +1156,8 @@ extern void nv50_graph_context_switch(struct drm_device *);
extern int nv50_grctx_init(struct nouveau_grctx *);
extern void nv50_graph_tlb_flush(struct drm_device *dev);
extern void nv86_graph_tlb_flush(struct drm_device *dev);
+extern int nv50_graph_pause(struct drm_device *dev);
+extern void nv50_graph_unpause(struct drm_device *dev);
/* nvc0_graph.c */
extern int nvc0_graph_init(struct drm_device *);
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c
index 8ef1d5b..bc7c70e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_pm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.c
@@ -59,6 +59,7 @@ nouveau_pm_perflvl_set(struct drm_device *dev, struct nouveau_pm_level *perflvl)
{
struct drm_nouveau_private *dev_priv = dev-dev_private;
struct nouveau_pm_engine *pm = dev_priv-engine.pm;
+ uint32_t status;
int ret;
if (perflvl == pm-cur)
@@ -72,13 +73,58 @@ nouveau_pm_perflvl_set(struct drm_device *dev, struct nouveau_pm_level *perflvl)
}
}
+ /* TODO: Wait for vblank */
+
+ /* Disable interrupts */
+ nv_wr32(dev, 0x140, 0);
+
+ /* Pause the engines, if possible */
+ if (dev_priv-engine.fifo.pause(dev)) {
+ ret = -EIO;
+ goto out;
+ }
+ if (dev_priv-engine.graph.pause(dev)) {
+ ret = -EIO;
+ goto out;
+ }
+
+ /* Disable the PFIFO cache pulling */
+ status = nv_rd32(dev, 0x003250);
+ nv_wr32(dev, 0x003250, status0xfffe);
+
+ /* Disable the PFIFO cache dma push */
+ status = nv_rd32(dev, 0x003220);
+ nv_wr32(dev, 0x003220, status0xfffe);
+
+ /* Change the clocks */
nouveau_pm_clock_set(dev, perflvl, PLL_CORE, perflvl-core);
nouveau_pm_clock_set(dev, perflvl, PLL_SHADER, perflvl-shader);
nouveau_pm_clock_set(dev, perflvl, PLL_MEMORY, perflvl-memory);
nouveau_pm_clock_set(dev, perflvl, PLL_UNK05, perflvl-unk05);
+ /* Wait for PLLs to stabilize */
+ udelay(100);
+
pm-cur = perflvl;
- return 0;
+ ret = 0;
+
+out:
+ /* Re-enable the PFIFO cache dma push */
+ status = nv_rd32(dev, 0x003220);
+ nv_wr32(dev, 0x003220, status|0x1);
+
+ /* Re-enable the PFIFO cache pulling */
+ status = nv_rd32(dev, 0x003250);
+ nv_wr32(dev, 0x003250, status|0x1);
+
+ /* Un-pause the engines */
+ dev_priv-engine.fifo.unpause(dev);
+ dev_priv-engine.graph.unpause(dev);
+
+ /* Re-enable interrupts */
+ nv_wr32(dev, 0x140, 1);
+
+ return ret;
}
static int
@@ -112,7 +158,7 @@ nouveau_pm_profile_set(struct drm_device *dev, const char *profile)
return -EINVAL;
}
- NV_INFO(dev, setting performance level: %s\n, profile);
+ NV_INFO(dev, setting performance level: %s, profile);
return nouveau_pm_perflvl_set(dev, perflvl);
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h
index b6384d3..951c268 100644
--- a/drivers/gpu/drm/nouveau/nouveau_reg.h
+++ b/drivers/gpu/drm/nouveau/nouveau_reg.h
@@ -700,8 +700,11 @@
#define