From: Matthew G. <mj...@re...> - 2010-03-22 18:58:05
|
The r520 atom tables sleep for long enough that it's impossible to reclock memory during an interrupt. Implement this by hand instead in order to avoid the delay. Signed-off-by: Matthew Garrett <mj...@re...> --- drivers/gpu/drm/radeon/r500_reg.h | 4 ++- drivers/gpu/drm/radeon/r520.c | 39 ++++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon.h | 2 + drivers/gpu/drm/radeon/radeon_asic.c | 2 +- drivers/gpu/drm/radeon/radeon_asic.h | 3 ++ drivers/gpu/drm/radeon/radeon_atombios.c | 21 ++++++++++++++++ drivers/gpu/drm/radeon/radeon_cp.c | 2 +- drivers/gpu/drm/radeon/radeon_drv.h | 1 + drivers/gpu/drm/radeon/radeon_pm.c | 8 ++++- 9 files changed, 77 insertions(+), 5 deletions(-) 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); } -- 1.6.5.2 |