drm/radeon: add support for ASPM on evergreen asics
authorAlex Deucher <alexander.deucher@amd.com>
Fri, 15 Feb 2013 16:02:50 +0000 (11:02 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Thu, 27 Jun 2013 23:16:27 +0000 (19:16 -0400)
Enables PCIE ASPM (Active State Power Management) on
evergreen-cayman asics.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreend.h
drivers/gpu/drm/radeon/ni.c

index d0aef76121d5fbdcc58b626f78996191bb60a4ca..c6bbf621649893774f411965f09a72d7591d550d 100644 (file)
@@ -136,6 +136,7 @@ static u32 sumo_rlc_save_restore_register_list_size = ARRAY_SIZE(sumo_rlc_save_r
 static void evergreen_gpu_init(struct radeon_device *rdev);
 void evergreen_fini(struct radeon_device *rdev);
 void evergreen_pcie_gen2_enable(struct radeon_device *rdev);
+void evergreen_program_aspm(struct radeon_device *rdev);
 extern void cayman_cp_int_cntl_setup(struct radeon_device *rdev,
                                     int ring, u32 cp_int_cntl);
 
@@ -5071,6 +5072,8 @@ static int evergreen_startup(struct radeon_device *rdev)
 
        /* enable pcie gen2 link */
        evergreen_pcie_gen2_enable(rdev);
+       /* enable aspm */
+       evergreen_program_aspm(rdev);
 
        if (ASIC_IS_DCE5(rdev)) {
                if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) {
@@ -5468,3 +5471,150 @@ void evergreen_pcie_gen2_enable(struct radeon_device *rdev)
                WREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl);
        }
 }
+
+void evergreen_program_aspm(struct radeon_device *rdev)
+{
+       u32 data, orig;
+       u32 pcie_lc_cntl, pcie_lc_cntl_old;
+       bool disable_l0s, disable_l1 = false, disable_plloff_in_l1 = false;
+       /* fusion_platform = true
+        * if the system is a fusion system
+        * (APU or DGPU in a fusion system).
+        * todo: check if the system is a fusion platform.
+        */
+       bool fusion_platform = false;
+
+       if (!(rdev->flags & RADEON_IS_PCIE))
+               return;
+
+       switch (rdev->family) {
+       case CHIP_CYPRESS:
+       case CHIP_HEMLOCK:
+       case CHIP_JUNIPER:
+       case CHIP_REDWOOD:
+       case CHIP_CEDAR:
+       case CHIP_SUMO:
+       case CHIP_SUMO2:
+       case CHIP_PALM:
+       case CHIP_ARUBA:
+               disable_l0s = true;
+               break;
+       default:
+               disable_l0s = false;
+               break;
+       }
+
+       if (rdev->flags & RADEON_IS_IGP)
+               fusion_platform = true; /* XXX also dGPUs in a fusion system */
+
+       data = orig = RREG32_PIF_PHY0(PB0_PIF_PAIRING);
+       if (fusion_platform)
+               data &= ~MULTI_PIF;
+       else
+               data |= MULTI_PIF;
+       if (data != orig)
+               WREG32_PIF_PHY0(PB0_PIF_PAIRING, data);
+
+       data = orig = RREG32_PIF_PHY1(PB1_PIF_PAIRING);
+       if (fusion_platform)
+               data &= ~MULTI_PIF;
+       else
+               data |= MULTI_PIF;
+       if (data != orig)
+               WREG32_PIF_PHY1(PB1_PIF_PAIRING, data);
+
+       pcie_lc_cntl = pcie_lc_cntl_old = RREG32_PCIE_PORT(PCIE_LC_CNTL);
+       pcie_lc_cntl &= ~(LC_L0S_INACTIVITY_MASK | LC_L1_INACTIVITY_MASK);
+       if (!disable_l0s) {
+               if (rdev->family >= CHIP_BARTS)
+                       pcie_lc_cntl |= LC_L0S_INACTIVITY(7);
+               else
+                       pcie_lc_cntl |= LC_L0S_INACTIVITY(3);
+       }
+
+       if (!disable_l1) {
+               if (rdev->family >= CHIP_BARTS)
+                       pcie_lc_cntl |= LC_L1_INACTIVITY(7);
+               else
+                       pcie_lc_cntl |= LC_L1_INACTIVITY(8);
+
+               if (!disable_plloff_in_l1) {
+                       data = orig = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_0);
+                       data &= ~(PLL_POWER_STATE_IN_OFF_0_MASK | PLL_POWER_STATE_IN_TXS2_0_MASK);
+                       data |= PLL_POWER_STATE_IN_OFF_0(7) | PLL_POWER_STATE_IN_TXS2_0(7);
+                       if (data != orig)
+                               WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_0, data);
+
+                       data = orig = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_1);
+                       data &= ~(PLL_POWER_STATE_IN_OFF_1_MASK | PLL_POWER_STATE_IN_TXS2_1_MASK);
+                       data |= PLL_POWER_STATE_IN_OFF_1(7) | PLL_POWER_STATE_IN_TXS2_1(7);
+                       if (data != orig)
+                               WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_1, data);
+
+                       data = orig = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_0);
+                       data &= ~(PLL_POWER_STATE_IN_OFF_0_MASK | PLL_POWER_STATE_IN_TXS2_0_MASK);
+                       data |= PLL_POWER_STATE_IN_OFF_0(7) | PLL_POWER_STATE_IN_TXS2_0(7);
+                       if (data != orig)
+                               WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_0, data);
+
+                       data = orig = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_1);
+                       data &= ~(PLL_POWER_STATE_IN_OFF_1_MASK | PLL_POWER_STATE_IN_TXS2_1_MASK);
+                       data |= PLL_POWER_STATE_IN_OFF_1(7) | PLL_POWER_STATE_IN_TXS2_1(7);
+                       if (data != orig)
+                               WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_1, data);
+
+                       if (rdev->family >= CHIP_BARTS) {
+                               data = orig = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_0);
+                               data &= ~PLL_RAMP_UP_TIME_0_MASK;
+                               data |= PLL_RAMP_UP_TIME_0(4);
+                               if (data != orig)
+                                       WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_0, data);
+
+                               data = orig = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_1);
+                               data &= ~PLL_RAMP_UP_TIME_1_MASK;
+                               data |= PLL_RAMP_UP_TIME_1(4);
+                               if (data != orig)
+                                       WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_1, data);
+
+                               data = orig = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_0);
+                               data &= ~PLL_RAMP_UP_TIME_0_MASK;
+                               data |= PLL_RAMP_UP_TIME_0(4);
+                               if (data != orig)
+                                       WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_0, data);
+
+                               data = orig = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_1);
+                               data &= ~PLL_RAMP_UP_TIME_1_MASK;
+                               data |= PLL_RAMP_UP_TIME_1(4);
+                               if (data != orig)
+                                       WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_1, data);
+                       }
+
+                       data = orig = RREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL);
+                       data &= ~LC_DYN_LANES_PWR_STATE_MASK;
+                       data |= LC_DYN_LANES_PWR_STATE(3);
+                       if (data != orig)
+                               WREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL, data);
+
+                       if (rdev->family >= CHIP_BARTS) {
+                               data = orig = RREG32_PIF_PHY0(PB0_PIF_CNTL);
+                               data &= ~LS2_EXIT_TIME_MASK;
+                               data |= LS2_EXIT_TIME(1);
+                               if (data != orig)
+                                       WREG32_PIF_PHY0(PB0_PIF_CNTL, data);
+
+                               data = orig = RREG32_PIF_PHY1(PB1_PIF_CNTL);
+                               data &= ~LS2_EXIT_TIME_MASK;
+                               data |= LS2_EXIT_TIME(1);
+                               if (data != orig)
+                                       WREG32_PIF_PHY1(PB1_PIF_CNTL, data);
+                       }
+               }
+       }
+
+       /* evergreen parts only */
+       if (rdev->family < CHIP_BARTS)
+               pcie_lc_cntl |= LC_PMI_TO_L1_DIS;
+
+       if (pcie_lc_cntl != pcie_lc_cntl_old)
+               WREG32_PCIE_PORT(PCIE_LC_CNTL, pcie_lc_cntl);
+}
index 35e61539b5f8573559bbb42e46cda34da351000e..c0df1cac9485693c8c7fbdc2cd3a52f377e880ae 100644 (file)
 #define        DMA_PACKET_CONSTANT_FILL                0xd
 #define        DMA_PACKET_NOP                          0xf
 
-/* PCIE link stuff */
+/* PIF PHY0 indirect regs */
+#define PB0_PIF_CNTL                                      0x10
+#       define LS2_EXIT_TIME(x)                           ((x) << 17)
+#       define LS2_EXIT_TIME_MASK                         (0x7 << 17)
+#       define LS2_EXIT_TIME_SHIFT                        17
+#define PB0_PIF_PAIRING                                   0x11
+#       define MULTI_PIF                                  (1 << 25)
+#define PB0_PIF_PWRDOWN_0                                 0x12
+#       define PLL_POWER_STATE_IN_TXS2_0(x)               ((x) << 7)
+#       define PLL_POWER_STATE_IN_TXS2_0_MASK             (0x7 << 7)
+#       define PLL_POWER_STATE_IN_TXS2_0_SHIFT            7
+#       define PLL_POWER_STATE_IN_OFF_0(x)                ((x) << 10)
+#       define PLL_POWER_STATE_IN_OFF_0_MASK              (0x7 << 10)
+#       define PLL_POWER_STATE_IN_OFF_0_SHIFT             10
+#       define PLL_RAMP_UP_TIME_0(x)                      ((x) << 24)
+#       define PLL_RAMP_UP_TIME_0_MASK                    (0x7 << 24)
+#       define PLL_RAMP_UP_TIME_0_SHIFT                   24
+#define PB0_PIF_PWRDOWN_1                                 0x13
+#       define PLL_POWER_STATE_IN_TXS2_1(x)               ((x) << 7)
+#       define PLL_POWER_STATE_IN_TXS2_1_MASK             (0x7 << 7)
+#       define PLL_POWER_STATE_IN_TXS2_1_SHIFT            7
+#       define PLL_POWER_STATE_IN_OFF_1(x)                ((x) << 10)
+#       define PLL_POWER_STATE_IN_OFF_1_MASK              (0x7 << 10)
+#       define PLL_POWER_STATE_IN_OFF_1_SHIFT             10
+#       define PLL_RAMP_UP_TIME_1(x)                      ((x) << 24)
+#       define PLL_RAMP_UP_TIME_1_MASK                    (0x7 << 24)
+#       define PLL_RAMP_UP_TIME_1_SHIFT                   24
+/* PIF PHY1 indirect regs */
+#define PB1_PIF_CNTL                                      0x10
+#define PB1_PIF_PAIRING                                   0x11
+#define PB1_PIF_PWRDOWN_0                                 0x12
+#define PB1_PIF_PWRDOWN_1                                 0x13
+/* PCIE PORT indirect regs */
+#define PCIE_LC_CNTL                                      0xa0
+#       define LC_L0S_INACTIVITY(x)                       ((x) << 8)
+#       define LC_L0S_INACTIVITY_MASK                     (0xf << 8)
+#       define LC_L0S_INACTIVITY_SHIFT                    8
+#       define LC_L1_INACTIVITY(x)                        ((x) << 12)
+#       define LC_L1_INACTIVITY_MASK                      (0xf << 12)
+#       define LC_L1_INACTIVITY_SHIFT                     12
+#       define LC_PMI_TO_L1_DIS                           (1 << 16)
+#       define LC_ASPM_TO_L1_DIS                          (1 << 24)
 #define PCIE_LC_TRAINING_CNTL                             0xa1 /* PCIE_P */
 #define PCIE_LC_LINK_WIDTH_CNTL                           0xa2 /* PCIE_P */
 #       define LC_LINK_WIDTH_SHIFT                        0
 #       define LC_SHORT_RECONFIG_EN                       (1 << 11)
 #       define LC_UPCONFIGURE_SUPPORT                     (1 << 12)
 #       define LC_UPCONFIGURE_DIS                         (1 << 13)
+#       define LC_DYN_LANES_PWR_STATE(x)                  ((x) << 21)
+#       define LC_DYN_LANES_PWR_STATE_MASK                (0x3 << 21)
+#       define LC_DYN_LANES_PWR_STATE_SHIFT               21
 #define PCIE_LC_SPEED_CNTL                                0xa4 /* PCIE_P */
 #       define LC_GEN2_EN_STRAP                           (1 << 0)
 #       define LC_TARGET_LINK_SPEED_OVERRIDE_EN           (1 << 1)
index ad65143232c002586cdb4cbe2c0e258cb0539e65..cafc3bd78a384927415bd7808d7da6afacefd8eb 100644 (file)
@@ -173,6 +173,7 @@ extern void evergreen_irq_suspend(struct radeon_device *rdev);
 extern int evergreen_mc_init(struct radeon_device *rdev);
 extern void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev);
 extern void evergreen_pcie_gen2_enable(struct radeon_device *rdev);
+extern void evergreen_program_aspm(struct radeon_device *rdev);
 extern void sumo_rlc_fini(struct radeon_device *rdev);
 extern int sumo_rlc_init(struct radeon_device *rdev);
 
@@ -2076,6 +2077,8 @@ static int cayman_startup(struct radeon_device *rdev)
 
        /* enable pcie gen2 link */
        evergreen_pcie_gen2_enable(rdev);
+       /* enable aspm */
+       evergreen_program_aspm(rdev);
 
        if (rdev->flags & RADEON_IS_IGP) {
                if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) {