diff mbox

[3/4] radeon: Reclock r520 memory by hand

Message ID 1269284260-12224-3-git-send-email-mjg@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Matthew Garrett March 22, 2010, 6:57 p.m. UTC
None
diff mbox

Patch

diff --git a/drivers/gpu/drm/radeon/r500_reg.h b/drivers/gpu/drm/radeon/r500_reg.h
index 0cf2ad2..b3e798f 100644
--- a/drivers/gpu/drm/radeon/r500_reg.h
+++ b/drivers/gpu/drm/radeon/r500_reg.h
@@ -258,7 +258,7 @@ 
 #define		R520_MC_AGP_TOP_SHIFT		16
 #define R520_MC_AGP_BASE		0x06
 #define R520_MC_AGP_BASE_2		0x07
-
+#define R520_MC_ARB_RATIO_CLK_SEQ	0x16
 
 #define AVIVO_MC_INDEX						0x0070
 #define R520_MC_STATUS 0x00
@@ -279,6 +279,8 @@ 
 #	define R520_MEM_NUM_CHANNELS_SHIFT  24
 #	define R520_MC_CHANNEL_SIZE  (1 << 23)
 
+#define AVIVO_SPLL_FUNC_CNTL			       0x0000 /* PLL */
+#define AVIVO_MPLL_FUNC_CNTL			       0x0004 /* PLL */
 #define AVIVO_CP_DYN_CNTL                              0x000f /* PLL */
 #       define AVIVO_CP_FORCEON                        (1 << 0)
 #define AVIVO_E2_DYN_CNTL                              0x0011 /* PLL */
diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c
index 870111e..fda7c11 100644
--- a/drivers/gpu/drm/radeon/r520.c
+++ b/drivers/gpu/drm/radeon/r520.c
@@ -26,6 +26,8 @@ 
  *          Jerome Glisse
  */
 #include "drmP.h"
+#include "radeon_drm.h"
+#include "radeon_drv.h"
 #include "radeon.h"
 #include "radeon_asic.h"
 #include "atom.h"
@@ -127,6 +129,8 @@  void r520_mc_init(struct radeon_device *rdev)
 	radeon_vram_location(rdev, &rdev->mc, 0);
 	if (!(rdev->flags & RADEON_IS_AGP))
 		radeon_gtt_location(rdev, &rdev->mc);
+	rdev->clock.fbdiv =
+		(RADEON_READ_PLL(rdev->ddev, AVIVO_MPLL_FUNC_CNTL) & 0x1fe0) >> 5;
 	radeon_update_bandwidth_info(rdev);
 }
 
@@ -303,3 +307,38 @@  int r520_init(struct radeon_device *rdev)
 	}
 	return 0;
 }
+
+void r520_set_memory_clock(struct radeon_device *rdev, uint32_t mem_clock)
+{
+	int mpll, spll, hclk, sclk, fbdiv, index, factor;
+	struct drm_radeon_private *dev_priv = rdev->ddev->dev_private;
+
+	mpll = RADEON_READ_PLL(rdev->ddev, AVIVO_MPLL_FUNC_CNTL);
+	fbdiv = (mpll & 0x1fe0) >> 5;
+
+	/* Set new fbdiv */
+	factor = rdev->clock.default_mclk / mem_clock;
+	fbdiv = rdev->clock.fbdiv / factor;
+
+	mpll &= ~0x1fe0;
+	mpll |= ((fbdiv << 5) | (1 << 24));
+	mpll &= ~(1 << 25);
+
+	spll = RADEON_READ_PLL(rdev->ddev, AVIVO_SPLL_FUNC_CNTL);
+
+	hclk = fbdiv << 5;
+	hclk += 0x20;
+	hclk *= 8;
+
+	sclk = spll * 0x1fe0;
+	sclk += 0x20;
+	sclk *= 6;
+	sclk = sclk >> 5;
+
+	index = hclk/sclk;
+
+	R500_WRITE_MCIND(R520_MC_ARB_RATIO_CLK_SEQ,
+			 rdev->pm.mc_arb_init_values[index]);
+	RADEON_WRITE_PLL(AVIVO_MPLL_FUNC_CNTL, mpll);
+	radeon_atom_initialize_memory_controller(rdev);
+}
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index ac403e4..d706974 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -163,6 +163,7 @@  struct radeon_clock {
 	uint32_t default_sclk;
 	uint32_t default_dispclk;
 	uint32_t dp_extclk;
+	uint32_t fbdiv;
 };
 
 /*
@@ -728,6 +729,7 @@  struct radeon_pm {
 	u32                     current_sclk;
 	u32                     current_mclk;
 	u32			new_mclk;
+	u32			*mc_arb_init_values;
 	struct radeon_i2c_chan *i2c_bus;
 	/* r6xx+ only */
 	u32 low_simd_mask;
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index 1df1e89..80487e0 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -529,7 +529,7 @@  static struct radeon_asic r520_asic = {
 	.get_engine_clock = &radeon_atom_get_engine_clock,
 	.set_engine_clock = &radeon_atom_set_engine_clock,
 	.get_memory_clock = &radeon_atom_get_memory_clock,
-	.set_memory_clock = &radeon_atom_set_memory_clock,
+	.set_memory_clock = &r520_set_memory_clock,
 	.get_pcie_lanes = &rv370_get_pcie_lanes,
 	.set_pcie_lanes = &rv370_set_pcie_lanes,
 	.set_clock_gating = &radeon_atom_set_clock_gating,
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 7de4947..51ddb60 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -36,10 +36,12 @@  void radeon_legacy_set_engine_clock(struct radeon_device *rdev, uint32_t eng_clo
 uint32_t radeon_legacy_get_memory_clock(struct radeon_device *rdev);
 void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable);
 
+void radeon_atom_get_mc_arb_info(struct radeon_device *rdev);
 uint32_t radeon_atom_get_engine_clock(struct radeon_device *rdev);
 void radeon_atom_set_engine_clock(struct radeon_device *rdev, uint32_t eng_clock);
 uint32_t radeon_atom_get_memory_clock(struct radeon_device *rdev);
 void radeon_atom_set_memory_clock(struct radeon_device *rdev, uint32_t mem_clock);
+void radeon_atom_initialize_memory_controller(struct radeon_device *rdev);
 void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable);
 
 /*
@@ -232,6 +234,7 @@  int rv515_suspend(struct radeon_device *rdev);
  */
 int r520_init(struct radeon_device *rdev);
 int r520_resume(struct radeon_device *rdev);
+void r520_set_memory_clock(struct radeon_device *rdev, uint32_t mem_clock);
 
 /*
  * r600,rv610,rv630,rv620,rv635,rv670,rs780,rs880
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index 0af81b7..5b964e2 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -1901,6 +1901,19 @@  void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable)
 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 }
 
+void radeon_atom_get_mc_arb_info(struct radeon_device *rdev)
+{
+	int index = GetIndexIntoMasterTable(DATA, MC_InitParameter);
+	u16 size, data_offset;
+	struct atom_context *ctx = rdev->mode_info.atom_context;
+
+	if (atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) {
+		rdev->pm.mc_arb_init_values = kmalloc(size*sizeof(u32), GFP_KERNEL);
+		memcpy(rdev->pm.mc_arb_init_values, ctx->bios + data_offset,
+		       size * sizeof(u32));
+	}
+}
+
 uint32_t radeon_atom_get_engine_clock(struct radeon_device *rdev)
 {
 	GET_ENGINE_CLOCK_PS_ALLOCATION args;
@@ -1944,6 +1957,14 @@  void radeon_atom_set_memory_clock(struct radeon_device *rdev,
 	atom_execute_table_atomic(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 }
 
+void radeon_atom_initialize_memory_controller(struct radeon_device *rdev)
+{
+	int index = GetIndexIntoMasterTable(COMMAND, MemoryDeviceInit);
+	MEMORY_PLLINIT_PS_ALLOCATION args;
+
+	atom_execute_table_atomic(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
 void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev)
 {
 	struct radeon_device *rdev = dev->dev_private;
diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c
index dc6eba6..d22e832 100644
--- a/drivers/gpu/drm/radeon/radeon_cp.c
+++ b/drivers/gpu/drm/radeon/radeon_cp.c
@@ -292,7 +292,7 @@  void radeon_enable_bm(struct drm_radeon_private *dev_priv)
 	} /* PCIE cards appears to not need this */
 }
 
-static int RADEON_READ_PLL(struct drm_device * dev, int addr)
+int RADEON_READ_PLL(struct drm_device *dev, int addr)
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 
diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h
index ec55f2b..43fd3b9 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.h
+++ b/drivers/gpu/drm/radeon/radeon_drv.h
@@ -1859,6 +1859,7 @@  do {									\
 #define RADEON_READ8(reg)	DRM_READ8(  dev_priv->mmio, (reg) )
 #define RADEON_WRITE8(reg,val)	DRM_WRITE8( dev_priv->mmio, (reg), (val) )
 
+int RADEON_READ_PLL(struct drm_device *dev, int addr);
 #define RADEON_WRITE_PLL(addr, val)					\
 do {									\
 	RADEON_WRITE8(RADEON_CLOCK_CNTL_INDEX,				\
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 3f4beef..745475f 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -23,6 +23,7 @@ 
 #include "drmP.h"
 #include "radeon.h"
 #include "avivod.h"
+#include "radeon_asic.h"
 
 #define RADEON_IDLE_LOOP_MS 100
 #define RADEON_RECLOCK_DELAY_MS 200
@@ -100,10 +101,12 @@  int radeon_pm_init(struct radeon_device *rdev)
 	rdev->pm.can_downclock = true;
 
 	if (rdev->bios) {
-		if (rdev->is_atom_bios)
+		if (rdev->is_atom_bios) {
 			radeon_atombios_get_power_modes(rdev);
-		else
+			radeon_atom_get_mc_arb_info(rdev);
+		} else {
 			radeon_combios_get_power_modes(rdev);
+		}
 		radeon_print_power_mode_info(rdev);
 	}
 
@@ -131,6 +134,7 @@  void radeon_pm_fini(struct radeon_device *rdev)
 		/* reset default clocks */
 		rdev->pm.state = PM_STATE_DISABLED;
 		rdev->pm.planned_action = PM_ACTION_DEFAULT;
+		kfree(rdev->pm.mc_arb_init_values);
 		radeon_pm_set_clocks(rdev);
 	}