Browse Source

drm/radeon: add support for ASPM on evergreen asics

Enables PCIE ASPM (Active State Power Management) on
evergreen-cayman asics.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Alex Deucher 12 years ago
parent
commit
f52382d73e
3 changed files with 198 additions and 1 deletions
  1. 150 0
      drivers/gpu/drm/radeon/evergreen.c
  2. 45 1
      drivers/gpu/drm/radeon/evergreend.h
  3. 3 0
      drivers/gpu/drm/radeon/ni.c

+ 150 - 0
drivers/gpu/drm/radeon/evergreen.c

@@ -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);
+}

+ 45 - 1
drivers/gpu/drm/radeon/evergreend.h

@@ -1323,7 +1323,48 @@
 #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
@@ -1343,6 +1384,9 @@
 #       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)

+ 3 - 0
drivers/gpu/drm/radeon/ni.c

@@ -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) {