summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/radeon.h2
-rw-r--r--src/radeon_driver.c23
-rw-r--r--src/radeon_macros.h3
-rw-r--r--src/radeon_pm.c105
-rw-r--r--src/radeon_reg.h23
5 files changed, 156 insertions, 0 deletions
diff --git a/src/radeon.h b/src/radeon.h
index 88de0e8f..3a9130cb 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -1060,9 +1060,11 @@ extern int RADEONMinBits(int val);
extern unsigned RADEONINMC(ScrnInfoPtr pScrn, int addr);
extern unsigned RADEONINPLL(ScrnInfoPtr pScrn, int addr);
extern unsigned RADEONINPCIE(ScrnInfoPtr pScrn, int addr);
+extern unsigned R600INPCIE_PORT(ScrnInfoPtr pScrn, int addr);
extern void RADEONOUTMC(ScrnInfoPtr pScrn, int addr, uint32_t data);
extern void RADEONOUTPLL(ScrnInfoPtr pScrn, int addr, uint32_t data);
extern void RADEONOUTPCIE(ScrnInfoPtr pScrn, int addr, uint32_t data);
+extern void R600OUTPCIE_PORT(ScrnInfoPtr pScrn, int addr, uint32_t data);
extern void RADEONPllErrataAfterData(RADEONInfoPtr info);
extern void RADEONPllErrataAfterIndex(RADEONInfoPtr info);
extern void RADEONWaitForVerticalSync(ScrnInfoPtr pScrn);
diff --git a/src/radeon_driver.c b/src/radeon_driver.c
index ac1a151e..7c758f86 100644
--- a/src/radeon_driver.c
+++ b/src/radeon_driver.c
@@ -690,6 +690,29 @@ void RADEONOUTPCIE(ScrnInfoPtr pScrn, int addr, uint32_t data)
OUTREG(RADEON_PCIE_DATA, data);
}
+/* Read PCIE PORT register */
+unsigned R600INPCIE_PORT(ScrnInfoPtr pScrn, int addr)
+{
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+ CARD32 data;
+
+ OUTREG(R600_PCIE_PORT_INDEX, addr & 0xff);
+ data = INREG(R600_PCIE_PORT_DATA);
+
+ return data;
+}
+
+/* Write PCIE PORT register */
+void R600OUTPCIE_PORT(ScrnInfoPtr pScrn, int addr, uint32_t data)
+{
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+
+ OUTREG(R600_PCIE_PORT_INDEX, ((addr) & 0xff));
+ OUTREG(R600_PCIE_PORT_DATA, data);
+}
+
static Bool radeon_get_mc_idle(ScrnInfoPtr pScrn)
{
RADEONInfoPtr info = RADEONPTR(pScrn);
diff --git a/src/radeon_macros.h b/src/radeon_macros.h
index 19307c83..8575884c 100644
--- a/src/radeon_macros.h
+++ b/src/radeon_macros.h
@@ -157,4 +157,7 @@ do { \
#define INPCIE(pScrn, addr) RADEONINPCIE(pScrn, addr)
#define OUTPCIE(pScrn, addr, val) RADEONOUTPCIE(pScrn, addr, val)
+#define INPCIE_P(pScrn, addr) R600INPCIE_PORT(pScrn, addr)
+#define OUTPCIE_P(pScrn, addr, val) R600OUTPCIE_PORT(pScrn, addr, val)
+
#endif
diff --git a/src/radeon_pm.c b/src/radeon_pm.c
index 86d739b2..d518998a 100644
--- a/src/radeon_pm.c
+++ b/src/radeon_pm.c
@@ -452,6 +452,105 @@ void RADEONForceSomeClocks(ScrnInfoPtr pScrn)
OUTPLL(pScrn, RADEON_SCLK_CNTL, tmp);
}
+static void
+RADEONSetPCIELanes(ScrnInfoPtr pScrn, int lanes)
+{
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+ uint32_t link_width_cntl, mask, target_reg;
+
+ if (info->IsIGP)
+ return;
+
+ RADEONWaitForIdleMMIO(pScrn);
+
+ switch (lanes) {
+ case 0:
+ mask = RADEON_PCIE_LC_LINK_WIDTH_X0;
+ break;
+ case 1:
+ mask = RADEON_PCIE_LC_LINK_WIDTH_X1;
+ break;
+ case 2:
+ mask = RADEON_PCIE_LC_LINK_WIDTH_X2;
+ break;
+ case 4:
+ mask = RADEON_PCIE_LC_LINK_WIDTH_X4;
+ break;
+ case 8:
+ mask = RADEON_PCIE_LC_LINK_WIDTH_X8;
+ break;
+ case 12:
+ mask = RADEON_PCIE_LC_LINK_WIDTH_X12;
+ break;
+ case 16:
+ default:
+ mask = RADEON_PCIE_LC_LINK_WIDTH_X16;
+ break;
+ }
+
+ if (info->ChipFamily >= CHIP_FAMILY_R600) {
+ link_width_cntl = INPCIE_P(pScrn, RADEON_PCIE_LC_LINK_WIDTH_CNTL);
+
+ if ((link_width_cntl & RADEON_PCIE_LC_LINK_WIDTH_RD_MASK) ==
+ (mask << RADEON_PCIE_LC_LINK_WIDTH_RD_SHIFT))
+ return;
+
+ link_width_cntl &= ~(RADEON_PCIE_LC_LINK_WIDTH_MASK |
+ RADEON_PCIE_LC_RECONFIG_NOW |
+ R600_PCIE_LC_RECONFIG_ARC_MISSING_ESCAPE |
+ R600_PCIE_LC_SHORT_RECONFIG_EN |
+ R600_PCIE_LC_RENEGOTIATE_EN);
+ link_width_cntl |= mask;
+
+#if 0
+ /* some northbridges can renegotiate the link rather than requiring
+ * a complete re-config.
+ * e.g., AMD 780/790 northbridges (pci ids: 0x5956, 0x5957, 0x5958, etc.)
+ */
+ if (northbridge can renegotiate)
+ link_width_cntl |= R600_PCIE_LC_RENEGOTIATE_EN;
+ else
+#endif
+ link_width_cntl |= R600_PCIE_LC_RECONFIG_ARC_MISSING_ESCAPE;
+
+ OUTPCIE_P(pScrn, RADEON_PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl);
+ OUTPCIE_P(pScrn, RADEON_PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl | RADEON_PCIE_LC_RECONFIG_NOW);
+
+ if (info->ChipFamily >= CHIP_FAMILY_RV770)
+ target_reg = R700_TARGET_AND_CURRENT_PROFILE_INDEX;
+ else
+ target_reg = R600_TARGET_AND_CURRENT_PROFILE_INDEX;
+
+ /* wait for lane set to complete */
+ link_width_cntl = INREG(target_reg);
+ while (link_width_cntl == 0xffffffff)
+ link_width_cntl = INREG(target_reg);
+
+ } else {
+ link_width_cntl = INPCIE(pScrn, RADEON_PCIE_LC_LINK_WIDTH_CNTL);
+
+ if ((link_width_cntl & RADEON_PCIE_LC_LINK_WIDTH_RD_MASK) ==
+ (mask << RADEON_PCIE_LC_LINK_WIDTH_RD_SHIFT))
+ return;
+
+ link_width_cntl &= ~(RADEON_PCIE_LC_LINK_WIDTH_MASK |
+ RADEON_PCIE_LC_RECONFIG_NOW |
+ RADEON_PCIE_LC_RECONFIG_LATER |
+ RADEON_PCIE_LC_SHORT_RECONFIG_EN);
+ link_width_cntl |= mask;
+ OUTPCIE(pScrn, RADEON_PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl);
+ OUTPCIE(pScrn, RADEON_PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl | RADEON_PCIE_LC_RECONFIG_NOW);
+
+ /* wait for lane set to complete */
+ link_width_cntl = INPCIE(pScrn, RADEON_PCIE_LC_LINK_WIDTH_CNTL);
+ while (link_width_cntl == 0xffffffff)
+ link_width_cntl = INPCIE(pScrn, RADEON_PCIE_LC_LINK_WIDTH_CNTL);
+
+ }
+
+}
+
void
RADEONSetClockGating(ScrnInfoPtr pScrn, Bool enable)
{
@@ -489,6 +588,9 @@ void RADEONStaticLowPowerMode(ScrnInfoPtr pScrn, Bool enable)
else
RADEONSetEngineClock(pScrn, sclk/2);
+ if (info->cardType == CARD_PCIE)
+ RADEONSetPCIELanes(pScrn, 1);
+
info->low_power_mode = TRUE;
} else {
if (info->IsAtomBios)
@@ -496,6 +598,9 @@ void RADEONStaticLowPowerMode(ScrnInfoPtr pScrn, Bool enable)
else
RADEONSetEngineClock(pScrn, sclk);
+ if (info->cardType == CARD_PCIE)
+ RADEONSetPCIELanes(pScrn, 16);
+
info->low_power_mode = FALSE;
}
diff --git a/src/radeon_reg.h b/src/radeon_reg.h
index e8af027f..e085353e 100644
--- a/src/radeon_reg.h
+++ b/src/radeon_reg.h
@@ -276,6 +276,29 @@
#define RADEON_PCIE_INDEX 0x0030
#define RADEON_PCIE_DATA 0x0034
+#define R600_PCIE_PORT_INDEX 0x0038
+#define R600_PCIE_PORT_DATA 0x003c
+/* PCIE_LC_LINK_WIDTH_CNTL is PCIE on r1xx-r5xx, PCIE_PORT on r6xx-r7xx */
+#define RADEON_PCIE_LC_LINK_WIDTH_CNTL 0xa2 /* PCIE */
+# define RADEON_PCIE_LC_LINK_WIDTH_SHIFT 0
+# define RADEON_PCIE_LC_LINK_WIDTH_MASK 0x7
+# define RADEON_PCIE_LC_LINK_WIDTH_X0 0
+# define RADEON_PCIE_LC_LINK_WIDTH_X1 1
+# define RADEON_PCIE_LC_LINK_WIDTH_X2 2
+# define RADEON_PCIE_LC_LINK_WIDTH_X4 3
+# define RADEON_PCIE_LC_LINK_WIDTH_X8 4
+# define RADEON_PCIE_LC_LINK_WIDTH_X12 5
+# define RADEON_PCIE_LC_LINK_WIDTH_X16 6
+# define RADEON_PCIE_LC_LINK_WIDTH_RD_SHIFT 4
+# define RADEON_PCIE_LC_LINK_WIDTH_RD_MASK 0x70
+# define R600_PCIE_LC_RECONFIG_ARC_MISSING_ESCAPE (1 << 7)
+# define RADEON_PCIE_LC_RECONFIG_NOW (1 << 8)
+# define RADEON_PCIE_LC_RECONFIG_LATER (1 << 9)
+# define RADEON_PCIE_LC_SHORT_RECONFIG_EN (1 << 10)
+# define R600_PCIE_LC_RENEGOTIATE_EN (1 << 10)
+# define R600_PCIE_LC_SHORT_RECONFIG_EN (1 << 11)
+#define R600_TARGET_AND_CURRENT_PROFILE_INDEX 0x70c
+#define R700_TARGET_AND_CURRENT_PROFILE_INDEX 0x66c
#define RADEON_CACHE_CNTL 0x1724
#define RADEON_CACHE_LINE 0x0f0c /* PCI */