diff options
-rw-r--r-- | src/radeon.h | 2 | ||||
-rw-r--r-- | src/radeon_driver.c | 23 | ||||
-rw-r--r-- | src/radeon_macros.h | 3 | ||||
-rw-r--r-- | src/radeon_pm.c | 105 | ||||
-rw-r--r-- | src/radeon_reg.h | 23 |
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 */ |