summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_pm.h7
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c24
-rw-r--r--drivers/gpu/drm/nouveau/nv04_pm.c109
3 files changed, 91 insertions, 49 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.h b/drivers/gpu/drm/nouveau/nouveau_pm.h
index 06df411ca5f..663088d3042 100644
--- a/drivers/gpu/drm/nouveau/nouveau_pm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.h
@@ -47,10 +47,9 @@ void nouveau_mem_timing_init(struct drm_device *);
void nouveau_mem_timing_fini(struct drm_device *);
/* nv04_pm.c */
-int nv04_pm_clock_get(struct drm_device *, u32 id);
-void *nv04_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *,
- u32 id, int khz);
-void nv04_pm_clock_set(struct drm_device *, void *);
+int nv04_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *);
+void *nv04_pm_clocks_pre(struct drm_device *, struct nouveau_pm_level *);
+int nv04_pm_clocks_set(struct drm_device *, void *);
/* nv40_pm.c */
int nv40_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *);
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index 6b4aaec648b..3e3798f7f36 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -87,9 +87,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->gpio.get = NULL;
engine->gpio.set = NULL;
engine->gpio.irq_enable = NULL;
- engine->pm.clock_get = nv04_pm_clock_get;
- engine->pm.clock_pre = nv04_pm_clock_pre;
- engine->pm.clock_set = nv04_pm_clock_set;
+ engine->pm.clocks_get = nv04_pm_clocks_get;
+ engine->pm.clocks_pre = nv04_pm_clocks_pre;
+ engine->pm.clocks_set = nv04_pm_clocks_set;
engine->vram.init = nouveau_mem_detect;
engine->vram.takedown = nouveau_stub_takedown;
engine->vram.flags_valid = nouveau_mem_flags_valid;
@@ -136,9 +136,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->gpio.get = nv10_gpio_get;
engine->gpio.set = nv10_gpio_set;
engine->gpio.irq_enable = NULL;
- engine->pm.clock_get = nv04_pm_clock_get;
- engine->pm.clock_pre = nv04_pm_clock_pre;
- engine->pm.clock_set = nv04_pm_clock_set;
+ engine->pm.clocks_get = nv04_pm_clocks_get;
+ engine->pm.clocks_pre = nv04_pm_clocks_pre;
+ engine->pm.clocks_set = nv04_pm_clocks_set;
engine->vram.init = nouveau_mem_detect;
engine->vram.takedown = nouveau_stub_takedown;
engine->vram.flags_valid = nouveau_mem_flags_valid;
@@ -185,9 +185,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->gpio.get = nv10_gpio_get;
engine->gpio.set = nv10_gpio_set;
engine->gpio.irq_enable = NULL;
- engine->pm.clock_get = nv04_pm_clock_get;
- engine->pm.clock_pre = nv04_pm_clock_pre;
- engine->pm.clock_set = nv04_pm_clock_set;
+ engine->pm.clocks_get = nv04_pm_clocks_get;
+ engine->pm.clocks_pre = nv04_pm_clocks_pre;
+ engine->pm.clocks_set = nv04_pm_clocks_set;
engine->vram.init = nouveau_mem_detect;
engine->vram.takedown = nouveau_stub_takedown;
engine->vram.flags_valid = nouveau_mem_flags_valid;
@@ -234,9 +234,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->gpio.get = nv10_gpio_get;
engine->gpio.set = nv10_gpio_set;
engine->gpio.irq_enable = NULL;
- engine->pm.clock_get = nv04_pm_clock_get;
- engine->pm.clock_pre = nv04_pm_clock_pre;
- engine->pm.clock_set = nv04_pm_clock_set;
+ engine->pm.clocks_get = nv04_pm_clocks_get;
+ engine->pm.clocks_pre = nv04_pm_clocks_pre;
+ engine->pm.clocks_set = nv04_pm_clocks_set;
engine->pm.voltage_get = nouveau_voltage_gpio_get;
engine->pm.voltage_set = nouveau_voltage_gpio_set;
engine->vram.init = nouveau_mem_detect;
diff --git a/drivers/gpu/drm/nouveau/nv04_pm.c b/drivers/gpu/drm/nouveau/nv04_pm.c
index 9ae92a87b8c..6e7589918fa 100644
--- a/drivers/gpu/drm/nouveau/nv04_pm.c
+++ b/drivers/gpu/drm/nouveau/nv04_pm.c
@@ -27,68 +27,111 @@
#include "nouveau_hw.h"
#include "nouveau_pm.h"
-struct nv04_pm_state {
+int
+nv04_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
+{
+ int ret;
+
+ ret = nouveau_hw_get_clock(dev, PLL_CORE);
+ if (ret < 0)
+ return ret;
+ perflvl->core = ret;
+
+ ret = nouveau_hw_get_clock(dev, PLL_MEMORY);
+ if (ret < 0)
+ return ret;
+ perflvl->memory = ret;
+
+ return 0;
+}
+
+struct nv04_pm_clock {
struct pll_lims pll;
struct nouveau_pll_vals calc;
};
-int
-nv04_pm_clock_get(struct drm_device *dev, u32 id)
+struct nv04_pm_state {
+ struct nv04_pm_clock core;
+ struct nv04_pm_clock memory;
+};
+
+static int
+calc_pll(struct drm_device *dev, u32 id, int khz, struct nv04_pm_clock *clk)
{
- return nouveau_hw_get_clock(dev, id);
+ int ret;
+
+ ret = get_pll_limits(dev, id, &clk->pll);
+ if (ret)
+ return ret;
+
+ ret = nouveau_calc_pll_mnp(dev, &clk->pll, khz, &clk->calc);
+ if (!ret)
+ return -EINVAL;
+
+ return 0;
}
void *
-nv04_pm_clock_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl,
- u32 id, int khz)
+nv04_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl)
{
- struct nv04_pm_state *state;
+ struct nv04_pm_state *info;
int ret;
- state = kzalloc(sizeof(*state), GFP_KERNEL);
- if (!state)
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
return ERR_PTR(-ENOMEM);
- ret = get_pll_limits(dev, id, &state->pll);
- if (ret) {
- kfree(state);
- return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
- }
+ ret = calc_pll(dev, PLL_CORE, perflvl->core, &info->core);
+ if (ret)
+ goto error;
- ret = nouveau_calc_pll_mnp(dev, &state->pll, khz, &state->calc);
- if (!ret) {
- kfree(state);
- return ERR_PTR(-EINVAL);
+ if (perflvl->memory) {
+ ret = calc_pll(dev, PLL_MEMORY, perflvl->memory, &info->memory);
+ if (ret)
+ goto error;
}
- return state;
+ return info;
+error:
+ kfree(info);
+ return ERR_PTR(ret);
}
-void
-nv04_pm_clock_set(struct drm_device *dev, void *pre_state)
+static void
+prog_pll(struct drm_device *dev, struct nv04_pm_clock *clk)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
- struct nv04_pm_state *state = pre_state;
- u32 reg = state->pll.reg;
+ u32 reg = clk->pll.reg;
/* thank the insane nouveau_hw_setpll() interface for this */
if (dev_priv->card_type >= NV_40)
reg += 4;
- nouveau_hw_setpll(dev, reg, &state->calc);
+ nouveau_hw_setpll(dev, reg, &clk->calc);
+}
+
+int
+nv04_pm_clocks_set(struct drm_device *dev, void *pre_state)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
+ struct nv04_pm_state *state = pre_state;
+
+ prog_pll(dev, &state->core);
- if (dev_priv->card_type < NV_30 && reg == NV_PRAMDAC_MPLL_COEFF) {
- if (dev_priv->card_type == NV_20)
- nv_mask(dev, 0x1002c4, 0, 1 << 20);
+ if (state->memory.pll.reg) {
+ prog_pll(dev, &state->memory);
+ if (dev_priv->card_type < NV_30) {
+ if (dev_priv->card_type == NV_20)
+ nv_mask(dev, 0x1002c4, 0, 1 << 20);
- /* Reset the DLLs */
- nv_mask(dev, 0x1002c0, 0, 1 << 8);
+ /* Reset the DLLs */
+ nv_mask(dev, 0x1002c0, 0, 1 << 8);
+ }
}
- if (reg == NV_PRAMDAC_NVPLL_COEFF)
- ptimer->init(dev);
+ ptimer->init(dev);
kfree(state);
+ return 0;
}
-