@@ -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 */
@@ -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);
+}
@@ -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;
@@ -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,
@@ -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
@@ -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;
@@ -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;
@@ -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, \
@@ -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);
}