Hi,
I'm still working on getting the reclocking work done right. There are
several parts I identify:
- Pausing PFIFO (with its caches), pause PGRAPH and wait for idle
- Stop some PLL (I guess it is more, physically disconnect them from the
engines) using the 0xc040 register.
- reclock memory
- reclock the other engines
- Make sure the display doesn't blow up
Depending on the cards, I have completed all of the steps or none.
Anyway, pausing PFIFO and PGRAPH works well on all the card I tested and
so, I would like it to be pushed.
I have a new theory upon the PLL_SUPERVISOR(0xc040) that I want to test.
When I'm done with this, I'll put together a patch for it and continue
on the other steps.
Please provide me with some feedback on the patch or push it if nothing
bothers you.
Martin
PS: I'm quite busy at the moment, I'll write an in-depth mail when I've
verified my theories and got proper support on other cards than the nv86
ones.
From f7ad98f4a857dd4b1892712d15f93c13eb0669e3 Mon Sep 17 00:00:00 2001
From: Martin Peres martin.pe...@ensi-bourges.fr
Date: Mon, 10 Jan 2011 00:44:05 +0100
Subject: [PATCH] Pause PFIFO and PGRAPH before reclocking
Signed-off-by: Martin Peres martin.pe...@ensi-bourges.fr
---
drivers/gpu/drm/nouveau/nouveau_drv.h | 15 +++
drivers/gpu/drm/nouveau/nouveau_pm.c| 32 ++-
drivers/gpu/drm/nouveau/nouveau_reg.h |3 +
drivers/gpu/drm/nouveau/nouveau_state.c | 51 +++-
drivers/gpu/drm/nouveau/nv04_fifo.c | 16 +++
drivers/gpu/drm/nouveau/nv50_fifo.c | 20 +
drivers/gpu/drm/nouveau/nv50_graph.c| 66 +++
7 files changed, 200 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 6d749b7..b0c52c7 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -359,6 +359,12 @@ 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 *);
+
+ int (*cache_pause)(struct drm_device *);
+ void (*cache_unpause)(struct drm_device *);
};
struct nouveau_pgraph_engine {
@@ -383,6 +389,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 {
@@ -1094,6 +1103,8 @@ extern void nv04_fifo_destroy_context(struct nouveau_channel *);
extern int nv04_fifo_load_context(struct nouveau_channel *);
extern int nv04_fifo_unload_context(struct drm_device *);
extern void nv04_fifo_isr(struct drm_device *);
+extern void nv04_fifo_cache_pause(struct drm_device *dev);
+extern void nv04_fifo_cache_unpause(struct drm_device *dev);
/* nv10_fifo.c */
extern int nv10_fifo_init(struct drm_device *);
@@ -1117,6 +1128,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 *);
@@ -1189,6 +1202,8 @@ extern int nv50_graph_unload_context(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);
extern struct nouveau_enum nv50_data_error_names[];
/* nvc0_graph.c */
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c
index fb846a3..233deec 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;
+ unsigned long flags;
int ret;
if (perflvl == pm-cur)
@@ -72,13 +73,42 @@ nouveau_pm_perflvl_set(struct drm_device *dev, struct nouveau_pm_level *perflvl)
}
}
+ /* Do not allow the card to allocate/destroy a
+ * new channel while reclocking.
+ */
+ spin_lock_irqsave(dev_priv-context_switch_lock, flags);
+
+ /* Pause the engines, if possible */
+ if (dev_priv-engine.fifo.pause(dev)) {
+ ret = -EIO;
+ goto out;
+ }
+ dev_priv-engine.fifo.cache_pause(dev);
+ if (dev_priv-engine.graph.pause(dev)) {
+ ret = -EIO;
+ goto out;
+ }
+
nouveau_pm_clock_set(dev, perflvl, PLL_CORE, perflvl-core);