From aee582de806c7008756df23aa444c8e7d58004a9 Mon Sep 17 00:00:00 2001
From: Ben Skeggs <bskeggs@redhat.com>
Date: Mon, 27 Sep 2010 10:13:23 +1000
Subject: [PATCH] drm/nouveau: run perflvl and M table scripts on mem clock
 change

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
---
 drivers/gpu/drm/nouveau/nouveau_drv.h  |  2 ++
 drivers/gpu/drm/nouveau/nouveau_perf.c |  1 +
 drivers/gpu/drm/nouveau/nv50_pm.c      | 22 ++++++++++++++++++++++
 3 files changed, 25 insertions(+)

diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 01ee63a70cc9..ef74d40d1bf1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -385,6 +385,8 @@ struct nouveau_pm_level {
 
 	u8 voltage;
 	u8 fanspeed;
+
+	u16 memscript;
 };
 
 struct nouveau_pm_temp_sensor_constants {
diff --git a/drivers/gpu/drm/nouveau/nouveau_perf.c b/drivers/gpu/drm/nouveau/nouveau_perf.c
index 6b641b69cb77..5a95be654123 100644
--- a/drivers/gpu/drm/nouveau/nouveau_perf.c
+++ b/drivers/gpu/drm/nouveau/nouveau_perf.c
@@ -160,6 +160,7 @@ nouveau_perf_init(struct drm_device *dev)
 			perflvl->memory = ROM16(entry[12]) * 1000;
 			break;
 		case 0x30:
+			perflvl->memscript = ROM16(entry[2]);
 		case 0x35:
 			perflvl->fanspeed = entry[6];
 			perflvl->voltage = entry[7];
diff --git a/drivers/gpu/drm/nouveau/nv50_pm.c b/drivers/gpu/drm/nouveau/nv50_pm.c
index eaf69c83ce92..2a9fabdf1b75 100644
--- a/drivers/gpu/drm/nouveau/nv50_pm.c
+++ b/drivers/gpu/drm/nouveau/nv50_pm.c
@@ -24,6 +24,7 @@
 
 #include "drmP.h"
 #include "nouveau_drv.h"
+#include "nouveau_bios.h"
 #include "nouveau_pm.h"
 
 /*XXX: boards using limits 0x40 need fixing, the register layout
@@ -33,6 +34,7 @@
  */
 
 struct nv50_pm_state {
+	struct nouveau_pm_level *perflvl;
 	struct pll_lims pll;
 	enum pll_types type;
 	int N, M, P;
@@ -77,6 +79,7 @@ nv50_pm_clock_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl,
 	if (!state)
 		return ERR_PTR(-ENOMEM);
 	state->type = id;
+	state->perflvl = perflvl;
 
 	ret = get_pll_limits(dev, id, &state->pll);
 	if (ret < 0) {
@@ -98,11 +101,30 @@ void
 nv50_pm_clock_set(struct drm_device *dev, void *pre_state)
 {
 	struct nv50_pm_state *state = pre_state;
+	struct nouveau_pm_level *perflvl = state->perflvl;
 	u32 reg = state->pll.reg, tmp;
+	struct bit_entry BIT_M;
+	u16 script;
 	int N = state->N;
 	int M = state->M;
 	int P = state->P;
 
+	if (state->type == PLL_MEMORY && perflvl->memscript &&
+	    bit_table(dev, 'M', &BIT_M) == 0 &&
+	    BIT_M.version == 1 && BIT_M.length >= 0x0b) {
+		script = ROM16(BIT_M.data[0x05]);
+		if (script)
+			nouveau_bios_run_init_table(dev, script, NULL);
+		script = ROM16(BIT_M.data[0x07]);
+		if (script)
+			nouveau_bios_run_init_table(dev, script, NULL);
+		script = ROM16(BIT_M.data[0x09]);
+		if (script)
+			nouveau_bios_run_init_table(dev, script, NULL);
+
+		nouveau_bios_run_init_table(dev, perflvl->memscript, NULL);
+	}
+
 	if (state->pll.vco2.maxfreq) {
 		if (state->type == PLL_MEMORY) {
 			nv_wr32(dev, 0x100210, 0);
-- 
GitLab