Signed-off-by: Alex Deucher alexdeucher@gmail.com --- drivers/gpu/drm/radeon/r300.c | 5 +- drivers/gpu/drm/radeon/r600.c | 118 ++++++++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon.h | 8 ++ drivers/gpu/drm/radeon/radeon_asic.c | 14 ++-- drivers/gpu/drm/radeon/radeon_asic.h | 2 + drivers/gpu/drm/radeon/radeon_reg.h | 9 +++ 6 files changed, 145 insertions(+), 11 deletions(-)
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 23fee54..fae5e70 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -558,10 +558,7 @@ int rv370_get_pcie_lanes(struct radeon_device *rdev)
/* FIXME wait for idle */
- if (rdev->family < CHIP_R600) - link_width_cntl = RREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL); - else - link_width_cntl = RREG32_PCIE_P(RADEON_PCIE_LC_LINK_WIDTH_CNTL); + link_width_cntl = RREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL);
switch ((link_width_cntl & RADEON_PCIE_LC_LINK_WIDTH_RD_MASK) >> RADEON_PCIE_LC_LINK_WIDTH_RD_SHIFT) { case RADEON_PCIE_LC_LINK_WIDTH_X0: diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 279794c..60ad8c0 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -3531,3 +3531,121 @@ void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo) } else WREG32(R_005480_HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1); } + +void r600_set_pcie_lanes(struct radeon_device *rdev, int lanes) +{ + u32 link_width_cntl, mask, target_reg; + + if (rdev->flags & RADEON_IS_IGP) + return; + + if (!(rdev->flags & RADEON_IS_PCIE)) + return; + + /* x2 cards have a special sequence */ + if (ASIC_IS_X2(rdev)) + return; + + /* FIXME wait for idle */ + + 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; + } + + link_width_cntl = RREG32_PCIE_P(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; + + if (link_width_cntl & R600_PCIE_LC_UPCONFIGURE_DIS) + return; + + link_width_cntl &= ~(RADEON_PCIE_LC_LINK_WIDTH_MASK | + RADEON_PCIE_LC_RECONFIG_NOW | + R600_PCIE_LC_RENEGOTIATE_EN | + R600_PCIE_LC_RECONFIG_ARC_MISSING_ESCAPE); + link_width_cntl |= mask; + + WREG32_PCIE_P(RADEON_PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + + /* 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 (link_width_cntl & R600_PCIE_LC_RENEGOTIATION_SUPPORT) + link_width_cntl |= R600_PCIE_LC_RENEGOTIATE_EN | R600_PCIE_LC_UPCONFIGURE_SUPPORT; + else + link_width_cntl |= R600_PCIE_LC_RECONFIG_ARC_MISSING_ESCAPE; + + WREG32_PCIE_P(RADEON_PCIE_LC_LINK_WIDTH_CNTL, (link_width_cntl | + RADEON_PCIE_LC_RECONFIG_NOW)); + + if (rdev->family >= CHIP_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 = RREG32(target_reg); + while (link_width_cntl == 0xffffffff) + link_width_cntl = RREG32(target_reg); + +} + +int r600_get_pcie_lanes(struct radeon_device *rdev) +{ + u32 link_width_cntl; + + if (rdev->flags & RADEON_IS_IGP) + return 0; + + if (!(rdev->flags & RADEON_IS_PCIE)) + return 0; + + /* x2 cards have a special sequence */ + if (ASIC_IS_X2(rdev)) + return 0; + + /* FIXME wait for idle */ + + link_width_cntl = RREG32_PCIE_P(RADEON_PCIE_LC_LINK_WIDTH_CNTL); + + switch ((link_width_cntl & RADEON_PCIE_LC_LINK_WIDTH_RD_MASK) >> RADEON_PCIE_LC_LINK_WIDTH_RD_SHIFT) { + case RADEON_PCIE_LC_LINK_WIDTH_X0: + return 0; + case RADEON_PCIE_LC_LINK_WIDTH_X1: + return 1; + case RADEON_PCIE_LC_LINK_WIDTH_X2: + return 2; + case RADEON_PCIE_LC_LINK_WIDTH_X4: + return 4; + case RADEON_PCIE_LC_LINK_WIDTH_X8: + return 8; + case RADEON_PCIE_LC_LINK_WIDTH_X16: + default: + return 16; + } +} + diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index aff8080..e9fb64c 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1317,6 +1317,14 @@ void r100_pll_errata_after_index(struct radeon_device *rdev); (rdev->family == CHIP_RV410) || \ (rdev->family == CHIP_RS400) || \ (rdev->family == CHIP_RS480)) +#define ASIC_IS_X2(rdev) ((rdev->ddev->pdev->device == 0x9441) || \ + (rdev->ddev->pdev->device == 0x9443) || \ + (rdev->ddev->pdev->device == 0x944B) || \ + (rdev->ddev->pdev->device == 0x9506) || \ + (rdev->ddev->pdev->device == 0x9509) || \ + (rdev->ddev->pdev->device == 0x950F) || \ + (rdev->ddev->pdev->device == 0x689C) || \ + (rdev->ddev->pdev->device == 0x689D)) #define ASIC_IS_AVIVO(rdev) ((rdev->family >= CHIP_RS600)) #define ASIC_IS_DCE2(rdev) ((rdev->family == CHIP_RS600) || \ (rdev->family == CHIP_RS690) || \ diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 3d73fe4..53c6240 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -94,7 +94,7 @@ static void radeon_register_accessor_init(struct radeon_device *rdev) rdev->mc_rreg = &rs600_mc_rreg; rdev->mc_wreg = &rs600_mc_wreg; } - if ((rdev->family >= CHIP_R600) && (rdev->family <= CHIP_RV740)) { + if ((rdev->family >= CHIP_R600) && (rdev->family <= CHIP_HEMLOCK)) { rdev->pciep_rreg = &r600_pciep_rreg; rdev->pciep_wreg = &r600_pciep_wreg; } @@ -631,8 +631,8 @@ static struct radeon_asic r600_asic = { .set_engine_clock = &radeon_atom_set_engine_clock, .get_memory_clock = &radeon_atom_get_memory_clock, .set_memory_clock = &radeon_atom_set_memory_clock, - .get_pcie_lanes = &rv370_get_pcie_lanes, - .set_pcie_lanes = NULL, + .get_pcie_lanes = &r600_get_pcie_lanes, + .set_pcie_lanes = &r600_set_pcie_lanes, .set_clock_gating = NULL, .set_surface_reg = r600_set_surface_reg, .clear_surface_reg = r600_clear_surface_reg, @@ -725,8 +725,8 @@ static struct radeon_asic rv770_asic = { .set_engine_clock = &radeon_atom_set_engine_clock, .get_memory_clock = &radeon_atom_get_memory_clock, .set_memory_clock = &radeon_atom_set_memory_clock, - .get_pcie_lanes = &rv370_get_pcie_lanes, - .set_pcie_lanes = NULL, + .get_pcie_lanes = &r600_get_pcie_lanes, + .set_pcie_lanes = &r600_set_pcie_lanes, .set_clock_gating = &radeon_atom_set_clock_gating, .set_surface_reg = r600_set_surface_reg, .clear_surface_reg = r600_clear_surface_reg, @@ -772,8 +772,8 @@ static struct radeon_asic evergreen_asic = { .set_engine_clock = &radeon_atom_set_engine_clock, .get_memory_clock = &radeon_atom_get_memory_clock, .set_memory_clock = &radeon_atom_set_memory_clock, - .get_pcie_lanes = NULL, - .set_pcie_lanes = NULL, + .get_pcie_lanes = &r600_get_pcie_lanes, + .set_pcie_lanes = &r600_set_pcie_lanes, .set_clock_gating = NULL, .set_surface_reg = r600_set_surface_reg, .clear_surface_reg = r600_clear_surface_reg, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 4970eda..9ac71b8 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -284,6 +284,8 @@ extern void r600_pm_misc(struct radeon_device *rdev); extern void r600_pm_init_profile(struct radeon_device *rdev); extern void rs780_pm_init_profile(struct radeon_device *rdev); extern void r600_pm_get_dynpm_state(struct radeon_device *rdev); +extern void r600_set_pcie_lanes(struct radeon_device *rdev, int lanes); +extern int r600_get_pcie_lanes(struct radeon_device *rdev);
/* * rv770,rv730,rv710,rv740 diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h index 0a310b7..3369ce9 100644 --- a/drivers/gpu/drm/radeon/radeon_reg.h +++ b/drivers/gpu/drm/radeon/radeon_reg.h @@ -320,6 +320,15 @@ # 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_RECONFIG_ARC_MISSING_ESCAPE (1 << 7) +# define R600_PCIE_LC_RENEGOTIATION_SUPPORT (1 << 9) +# define R600_PCIE_LC_RENEGOTIATE_EN (1 << 10) +# define R600_PCIE_LC_SHORT_RECONFIG_EN (1 << 11) +# define R600_PCIE_LC_UPCONFIGURE_SUPPORT (1 << 12) +# define R600_PCIE_LC_UPCONFIGURE_DIS (1 << 13) + +#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 */
Supported on rv6xx/r7xx/evergreen. Cards come up in gen1 mode.
Signed-off-by: Alex Deucher alexdeucher@gmail.com --- drivers/gpu/drm/radeon/evergreen.c | 53 ++++++++++++++++++ drivers/gpu/drm/radeon/evergreend.h | 38 +++++++++++++ drivers/gpu/drm/radeon/r600.c | 102 +++++++++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/r600d.h | 39 +++++++++++++ drivers/gpu/drm/radeon/radeon.h | 2 + drivers/gpu/drm/radeon/rv770.c | 76 ++++++++++++++++++++++++++ drivers/gpu/drm/radeon/rv770d.h | 38 +++++++++++++ 7 files changed, 348 insertions(+), 0 deletions(-)
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index eaf4fba..11344c7 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -39,6 +39,7 @@
static void evergreen_gpu_init(struct radeon_device *rdev); void evergreen_fini(struct radeon_device *rdev); +static void evergreen_pcie_gen2_enable(struct radeon_device *rdev);
void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc) { @@ -2767,6 +2768,9 @@ static int evergreen_startup(struct radeon_device *rdev) { int r;
+ /* enable pcie gen2 link */ + evergreen_pcie_gen2_enable(rdev); + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { r = r600_init_microcode(rdev); if (r) { @@ -3049,3 +3053,52 @@ void evergreen_fini(struct radeon_device *rdev) rdev->bios = NULL; radeon_dummy_page_fini(rdev); } + +static void evergreen_pcie_gen2_enable(struct radeon_device *rdev) +{ + u32 link_width_cntl, speed_cntl; + + if (rdev->flags & RADEON_IS_IGP) + return; + + if (!(rdev->flags & RADEON_IS_PCIE)) + return; + + /* x2 cards have a special sequence */ + if (ASIC_IS_X2(rdev)) + return; + + speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL); + if ((speed_cntl & LC_OTHER_SIDE_EVER_SENT_GEN2) || + (speed_cntl & LC_OTHER_SIDE_SUPPORTS_GEN2)) { + + link_width_cntl = RREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL); + link_width_cntl &= ~LC_UPCONFIGURE_DIS; + WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + + speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL); + speed_cntl &= ~LC_TARGET_LINK_SPEED_OVERRIDE_EN; + WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl); + + speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL); + speed_cntl |= LC_CLR_FAILED_SPD_CHANGE_CNT; + WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl); + + speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL); + speed_cntl &= ~LC_CLR_FAILED_SPD_CHANGE_CNT; + WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl); + + speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL); + speed_cntl |= LC_GEN2_EN_STRAP; + WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl); + + } else { + link_width_cntl = RREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL); + /* XXX: only disable it if gen1 bridge vendor == 0x111d or 0x1106 */ + if (1) + link_width_cntl |= LC_UPCONFIGURE_DIS; + else + link_width_cntl &= ~LC_UPCONFIGURE_DIS; + WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + } +} diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 94140e1..b8da323 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -581,6 +581,44 @@ # define DC_HPDx_RX_INT_TIMER(x) ((x) << 16) # define DC_HPDx_EN (1 << 28)
+/* PCIE link stuff */ +#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_LINK_WIDTH_MASK 0x7 +# define LC_LINK_WIDTH_X0 0 +# define LC_LINK_WIDTH_X1 1 +# define LC_LINK_WIDTH_X2 2 +# define LC_LINK_WIDTH_X4 3 +# define LC_LINK_WIDTH_X8 4 +# define LC_LINK_WIDTH_X16 6 +# define LC_LINK_WIDTH_RD_SHIFT 4 +# define LC_LINK_WIDTH_RD_MASK 0x70 +# define LC_RECONFIG_ARC_MISSING_ESCAPE (1 << 7) +# define LC_RECONFIG_NOW (1 << 8) +# define LC_RENEGOTIATION_SUPPORT (1 << 9) +# define LC_RENEGOTIATE_EN (1 << 10) +# define LC_SHORT_RECONFIG_EN (1 << 11) +# define LC_UPCONFIGURE_SUPPORT (1 << 12) +# define LC_UPCONFIGURE_DIS (1 << 13) +#define PCIE_LC_SPEED_CNTL 0xa4 /* PCIE_P */ +# define LC_GEN2_EN_STRAP (1 << 0) +# define LC_TARGET_LINK_SPEED_OVERRIDE_EN (1 << 1) +# define LC_FORCE_EN_HW_SPEED_CHANGE (1 << 5) +# define LC_FORCE_DIS_HW_SPEED_CHANGE (1 << 6) +# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK (0x3 << 8) +# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT 3 +# define LC_CURRENT_DATA_RATE (1 << 11) +# define LC_VOLTAGE_TIMER_SEL_MASK (0xf << 14) +# define LC_CLR_FAILED_SPD_CHANGE_CNT (1 << 21) +# define LC_OTHER_SIDE_EVER_SENT_GEN2 (1 << 23) +# define LC_OTHER_SIDE_SUPPORTS_GEN2 (1 << 24) +#define MM_CFGREGS_CNTL 0x544c +# define MM_WR_TO_CFG_EN (1 << 3) +#define LINK_CNTL2 0x88 /* F0 */ +# define TARGET_LINK_SPEED_MASK (0xf << 0) +# define SELECTABLE_DEEMPHASIS (1 << 6) + /* * PM4 */ diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 60ad8c0..6b50716 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -94,6 +94,7 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev); void r600_gpu_init(struct radeon_device *rdev); void r600_fini(struct radeon_device *rdev); void r600_irq_disable(struct radeon_device *rdev); +static void r600_pcie_gen2_enable(struct radeon_device *rdev);
/* get temperature in millidegrees */ u32 rv6xx_get_temp(struct radeon_device *rdev) @@ -2379,6 +2380,9 @@ int r600_startup(struct radeon_device *rdev) { int r;
+ /* enable pcie gen2 link */ + r600_pcie_gen2_enable(rdev); + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { r = r600_init_microcode(rdev); if (r) { @@ -3649,3 +3653,101 @@ int r600_get_pcie_lanes(struct radeon_device *rdev) } }
+static void r600_pcie_gen2_enable(struct radeon_device *rdev) +{ + u32 link_width_cntl, lanes, speed_cntl, training_cntl, tmp; + u16 link_cntl2; + + if (rdev->flags & RADEON_IS_IGP) + return; + + if (!(rdev->flags & RADEON_IS_PCIE)) + return; + + /* x2 cards have a special sequence */ + if (ASIC_IS_X2(rdev)) + return; + + /* only RV6xx+ chips are supported */ + if (rdev->family <= CHIP_R600) + return; + + /* 55 nm r6xx asics */ + if ((rdev->family == CHIP_RV670) || + (rdev->family == CHIP_RV620) || + (rdev->family == CHIP_RV635)) { + /* advertise upconfig capability */ + link_width_cntl = RREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL); + link_width_cntl &= ~LC_UPCONFIGURE_DIS; + WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + link_width_cntl = RREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL); + if (link_width_cntl & LC_RENEGOTIATION_SUPPORT) { + lanes = (link_width_cntl & LC_LINK_WIDTH_RD_MASK) >> LC_LINK_WIDTH_RD_SHIFT; + link_width_cntl &= ~(LC_LINK_WIDTH_MASK | + LC_RECONFIG_ARC_MISSING_ESCAPE); + link_width_cntl |= lanes | LC_RECONFIG_NOW | LC_RENEGOTIATE_EN; + WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + } else { + link_width_cntl |= LC_UPCONFIGURE_DIS; + WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + } + } + + speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL); + if ((speed_cntl & LC_OTHER_SIDE_EVER_SENT_GEN2) && + (speed_cntl & LC_OTHER_SIDE_SUPPORTS_GEN2)) { + + /* 55 nm r6xx asics */ + if ((rdev->family == CHIP_RV670) || + (rdev->family == CHIP_RV620) || + (rdev->family == CHIP_RV635)) { + WREG32(MM_CFGREGS_CNTL, 0x8); + link_cntl2 = RREG32(0x4088); + WREG32(MM_CFGREGS_CNTL, 0); + /* not supported yet */ + if (link_cntl2 & SELECTABLE_DEEMPHASIS) + return; + } + + speed_cntl &= ~LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK; + speed_cntl |= (0x3 << LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT); + speed_cntl &= ~LC_VOLTAGE_TIMER_SEL_MASK; + speed_cntl &= ~LC_FORCE_DIS_HW_SPEED_CHANGE; + speed_cntl |= LC_FORCE_EN_HW_SPEED_CHANGE; + WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl); + + tmp = RREG32(0x541c); + WREG32(0x541c, tmp | 0x8); + WREG32(MM_CFGREGS_CNTL, MM_WR_TO_CFG_EN); + link_cntl2 = RREG16(0x4088); + link_cntl2 &= ~TARGET_LINK_SPEED_MASK; + link_cntl2 |= 0x2; + WREG16(0x4088, link_cntl2); + WREG32(MM_CFGREGS_CNTL, 0); + + if ((rdev->family == CHIP_RV670) || + (rdev->family == CHIP_RV620) || + (rdev->family == CHIP_RV635)) { + training_cntl = RREG32_PCIE_P(PCIE_LC_TRAINING_CNTL); + training_cntl &= ~LC_POINT_7_PLUS_EN; + WREG32_PCIE_P(PCIE_LC_TRAINING_CNTL, training_cntl); + } else { + speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL); + speed_cntl &= ~LC_TARGET_LINK_SPEED_OVERRIDE_EN; + WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl); + } + + speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL); + speed_cntl |= LC_GEN2_EN_STRAP; + WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl); + + } else { + link_width_cntl = RREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL); + /* XXX: only disable it if gen1 bridge vendor == 0x111d or 0x1106 */ + if (1) + link_width_cntl |= LC_UPCONFIGURE_DIS; + else + link_width_cntl &= ~LC_UPCONFIGURE_DIS; + WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + } +} diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index c89cfa8..a5d898b 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -737,6 +737,45 @@ # define DxGRPH_PFLIP_INT_MASK (1 << 0) # define DxGRPH_PFLIP_INT_TYPE (1 << 8)
+/* PCIE link stuff */ +#define PCIE_LC_TRAINING_CNTL 0xa1 /* PCIE_P */ +# define LC_POINT_7_PLUS_EN (1 << 6) +#define PCIE_LC_LINK_WIDTH_CNTL 0xa2 /* PCIE_P */ +# define LC_LINK_WIDTH_SHIFT 0 +# define LC_LINK_WIDTH_MASK 0x7 +# define LC_LINK_WIDTH_X0 0 +# define LC_LINK_WIDTH_X1 1 +# define LC_LINK_WIDTH_X2 2 +# define LC_LINK_WIDTH_X4 3 +# define LC_LINK_WIDTH_X8 4 +# define LC_LINK_WIDTH_X16 6 +# define LC_LINK_WIDTH_RD_SHIFT 4 +# define LC_LINK_WIDTH_RD_MASK 0x70 +# define LC_RECONFIG_ARC_MISSING_ESCAPE (1 << 7) +# define LC_RECONFIG_NOW (1 << 8) +# define LC_RENEGOTIATION_SUPPORT (1 << 9) +# define LC_RENEGOTIATE_EN (1 << 10) +# define LC_SHORT_RECONFIG_EN (1 << 11) +# define LC_UPCONFIGURE_SUPPORT (1 << 12) +# define LC_UPCONFIGURE_DIS (1 << 13) +#define PCIE_LC_SPEED_CNTL 0xa4 /* PCIE_P */ +# define LC_GEN2_EN_STRAP (1 << 0) +# define LC_TARGET_LINK_SPEED_OVERRIDE_EN (1 << 1) +# define LC_FORCE_EN_HW_SPEED_CHANGE (1 << 5) +# define LC_FORCE_DIS_HW_SPEED_CHANGE (1 << 6) +# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK (0x3 << 8) +# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT 3 +# define LC_CURRENT_DATA_RATE (1 << 11) +# define LC_VOLTAGE_TIMER_SEL_MASK (0xf << 14) +# define LC_CLR_FAILED_SPD_CHANGE_CNT (1 << 21) +# define LC_OTHER_SIDE_EVER_SENT_GEN2 (1 << 23) +# define LC_OTHER_SIDE_SUPPORTS_GEN2 (1 << 24) +#define MM_CFGREGS_CNTL 0x544c +# define MM_WR_TO_CFG_EN (1 << 3) +#define LINK_CNTL2 0x88 /* F0 */ +# define TARGET_LINK_SPEED_MASK (0xf << 0) +# define SELECTABLE_DEEMPHASIS (1 << 6) + /* * PM4 */ diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index e9fb64c..3e635c6 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1244,6 +1244,8 @@ static inline void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v) */ #define RREG8(reg) readb(((void __iomem *)rdev->rmmio) + (reg)) #define WREG8(reg, v) writeb(v, ((void __iomem *)rdev->rmmio) + (reg)) +#define RREG16(reg) readw(((void __iomem *)rdev->rmmio) + (reg)) +#define WREG16(reg, v) writew(v, ((void __iomem *)rdev->rmmio) + (reg)) #define RREG32(reg) r100_mm_rreg(rdev, (reg)) #define DREG32(reg) printk(KERN_INFO "REGISTER: " #reg " : 0x%08X\n", r100_mm_rreg(rdev, (reg))) #define WREG32(reg, v) r100_mm_wreg(rdev, (reg), (v)) diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 645aa1f..3a264aa 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -41,6 +41,7 @@
static void rv770_gpu_init(struct radeon_device *rdev); void rv770_fini(struct radeon_device *rdev); +static void rv770_pcie_gen2_enable(struct radeon_device *rdev);
u32 rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) { @@ -1124,6 +1125,9 @@ static int rv770_startup(struct radeon_device *rdev) { int r;
+ /* enable pcie gen2 link */ + rv770_pcie_gen2_enable(rdev); + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { r = r600_init_microcode(rdev); if (r) { @@ -1362,3 +1366,75 @@ void rv770_fini(struct radeon_device *rdev) rdev->bios = NULL; radeon_dummy_page_fini(rdev); } + +static void rv770_pcie_gen2_enable(struct radeon_device *rdev) +{ + u32 link_width_cntl, lanes, speed_cntl, tmp; + u16 link_cntl2; + + if (rdev->flags & RADEON_IS_IGP) + return; + + if (!(rdev->flags & RADEON_IS_PCIE)) + return; + + /* x2 cards have a special sequence */ + if (ASIC_IS_X2(rdev)) + return; + + /* advertise upconfig capability */ + link_width_cntl = RREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL); + link_width_cntl &= ~LC_UPCONFIGURE_DIS; + WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + link_width_cntl = RREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL); + if (link_width_cntl & LC_RENEGOTIATION_SUPPORT) { + lanes = (link_width_cntl & LC_LINK_WIDTH_RD_MASK) >> LC_LINK_WIDTH_RD_SHIFT; + link_width_cntl &= ~(LC_LINK_WIDTH_MASK | + LC_RECONFIG_ARC_MISSING_ESCAPE); + link_width_cntl |= lanes | LC_RECONFIG_NOW | + LC_RENEGOTIATE_EN | LC_UPCONFIGURE_SUPPORT; + WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + } else { + link_width_cntl |= LC_UPCONFIGURE_DIS; + WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + } + + speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL); + if ((speed_cntl & LC_OTHER_SIDE_EVER_SENT_GEN2) && + (speed_cntl & LC_OTHER_SIDE_SUPPORTS_GEN2)) { + + tmp = RREG32(0x541c); + WREG32(0x541c, tmp | 0x8); + WREG32(MM_CFGREGS_CNTL, MM_WR_TO_CFG_EN); + link_cntl2 = RREG16(0x4088); + link_cntl2 &= ~TARGET_LINK_SPEED_MASK; + link_cntl2 |= 0x2; + WREG16(0x4088, link_cntl2); + WREG32(MM_CFGREGS_CNTL, 0); + + speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL); + speed_cntl &= ~LC_TARGET_LINK_SPEED_OVERRIDE_EN; + WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl); + + speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL); + speed_cntl |= LC_CLR_FAILED_SPD_CHANGE_CNT; + WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl); + + speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL); + speed_cntl &= ~LC_CLR_FAILED_SPD_CHANGE_CNT; + WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl); + + speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL); + speed_cntl |= LC_GEN2_EN_STRAP; + WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl); + + } else { + link_width_cntl = RREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL); + /* XXX: only disable it if gen1 bridge vendor == 0x111d or 0x1106 */ + if (1) + link_width_cntl |= LC_UPCONFIGURE_DIS; + else + link_width_cntl &= ~LC_UPCONFIGURE_DIS; + WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + } +} diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h index fc77e1e..abc8cf5 100644 --- a/drivers/gpu/drm/radeon/rv770d.h +++ b/drivers/gpu/drm/radeon/rv770d.h @@ -360,4 +360,42 @@ #define D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH 0x691c #define D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH 0x611c
+/* PCIE link stuff */ +#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_LINK_WIDTH_MASK 0x7 +# define LC_LINK_WIDTH_X0 0 +# define LC_LINK_WIDTH_X1 1 +# define LC_LINK_WIDTH_X2 2 +# define LC_LINK_WIDTH_X4 3 +# define LC_LINK_WIDTH_X8 4 +# define LC_LINK_WIDTH_X16 6 +# define LC_LINK_WIDTH_RD_SHIFT 4 +# define LC_LINK_WIDTH_RD_MASK 0x70 +# define LC_RECONFIG_ARC_MISSING_ESCAPE (1 << 7) +# define LC_RECONFIG_NOW (1 << 8) +# define LC_RENEGOTIATION_SUPPORT (1 << 9) +# define LC_RENEGOTIATE_EN (1 << 10) +# define LC_SHORT_RECONFIG_EN (1 << 11) +# define LC_UPCONFIGURE_SUPPORT (1 << 12) +# define LC_UPCONFIGURE_DIS (1 << 13) +#define PCIE_LC_SPEED_CNTL 0xa4 /* PCIE_P */ +# define LC_GEN2_EN_STRAP (1 << 0) +# define LC_TARGET_LINK_SPEED_OVERRIDE_EN (1 << 1) +# define LC_FORCE_EN_HW_SPEED_CHANGE (1 << 5) +# define LC_FORCE_DIS_HW_SPEED_CHANGE (1 << 6) +# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK (0x3 << 8) +# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT 3 +# define LC_CURRENT_DATA_RATE (1 << 11) +# define LC_VOLTAGE_TIMER_SEL_MASK (0xf << 14) +# define LC_CLR_FAILED_SPD_CHANGE_CNT (1 << 21) +# define LC_OTHER_SIDE_EVER_SENT_GEN2 (1 << 23) +# define LC_OTHER_SIDE_SUPPORTS_GEN2 (1 << 24) +#define MM_CFGREGS_CNTL 0x544c +# define MM_WR_TO_CFG_EN (1 << 3) +#define LINK_CNTL2 0x88 /* F0 */ +# define TARGET_LINK_SPEED_MASK (0xf << 0) +# define SELECTABLE_DEEMPHASIS (1 << 6) + #endif
dri-devel@lists.freedesktop.org