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 <m...@redhat.com>
---
 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


------------------------------------------------------------------------------
Download Intel&#174; Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
--
_______________________________________________
Dri-devel mailing list
Dri-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dri-devel

Reply via email to