From e4750c39be6314e924627a6a49b8a0d47f6323d6 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 16 Mar 2010 15:31:25 -0400 Subject: [PATCH] drm/radeon/kms/pm: enable pcie lane change support Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/r100.c | 14 +++++ drivers/gpu/drm/radeon/r300.c | 81 +++++++++++++++++++++++------ drivers/gpu/drm/radeon/r600.c | 16 ++++++- drivers/gpu/drm/radeon/radeon_asic.c | 5 +- drivers/gpu/drm/radeon/radeon_atombios.c | 5 +-- drivers/gpu/drm/radeon/radeon_combios.c | 5 +-- drivers/gpu/drm/radeon/radeon_reg.h | 6 ++ 7 files changed, 104 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 56f3303..b035eb5 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -162,6 +162,20 @@ void r100_set_power_state(struct radeon_device *rdev) mclk = rdev->clock.default_mclk; /* set pcie lanes */ + if ((rdev->flags & RADEON_IS_PCIE) && + !(rdev->flags & RADEON_IS_IGP) && + rdev->asic->set_pcie_lanes && + (rdev->pm.power_state[rdev->pm.requested_power_state_index]. + non_clock_info.pcie_lanes != + rdev->pm.power_state[rdev->pm.current_power_state_index]. + non_clock_info.pcie_lanes)) { + radeon_set_pcie_lanes(rdev, + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + non_clock_info.pcie_lanes); + DRM_INFO("Setting: p: %d\n", + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + non_clock_info.pcie_lanes); + } /* TODO */ /* set voltage */ diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 6a0b550..298a586 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -495,7 +495,7 @@ void r300_mc_init(struct radeon_device *rdev) void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes) { - uint32_t link_width_cntl, mask; + uint32_t link_width_cntl, mask, target_reg; if (rdev->flags & RADEON_IS_IGP) return; @@ -503,6 +503,15 @@ void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes) if (!(rdev->flags & RADEON_IS_PCIE)) return; + /* don't change lanes on multi-gpu cards for now */ + if ((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)) + return; + /* FIXME wait for idle */ switch (lanes) { @@ -530,26 +539,64 @@ void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes) break; } - link_width_cntl = RREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL); + if (rdev->family >= CHIP_R600) { + 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 & 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; + + /* 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 */ + link_width_cntl |= R600_PCIE_LC_RECONFIG_ARC_MISSING_ESCAPE; + + WREG32_PCIE_P(RADEON_PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + 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); - 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; - WREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); - WREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL, (link_width_cntl | - RADEON_PCIE_LC_RECONFIG_NOW)); - - /* wait for lane set to complete */ - link_width_cntl = RREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL); - while (link_width_cntl == 0xffffffff) + } else { link_width_cntl = RREG32_PCIE(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; + WREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + WREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL, (link_width_cntl | + RADEON_PCIE_LC_RECONFIG_NOW)); + + /* wait for lane set to complete */ + link_width_cntl = RREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL); + while (link_width_cntl == 0xffffffff) + link_width_cntl = RREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL); + } } int rv370_get_pcie_lanes(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 7e1233f..b569627 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -252,7 +252,21 @@ void r600_set_power_state(struct radeon_device *rdev) mclk = rdev->clock.default_mclk; /* set pcie lanes */ - /* TODO */ + /* set pcie lanes */ + if ((rdev->flags & RADEON_IS_PCIE) && + !(rdev->flags & RADEON_IS_IGP) && + rdev->asic->set_pcie_lanes && + (rdev->pm.power_state[rdev->pm.requested_power_state_index]. + non_clock_info.pcie_lanes != + rdev->pm.power_state[rdev->pm.current_power_state_index]. + non_clock_info.pcie_lanes)) { + radeon_set_pcie_lanes(rdev, + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + non_clock_info.pcie_lanes); + DRM_INFO("Setting: p: %d\n", + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + non_clock_info.pcie_lanes); + } /* set voltage */ /* TODO */ diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 91e3373..1df1e89 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -572,7 +572,7 @@ static struct radeon_asic r600_asic = { .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, + .set_pcie_lanes = &rv370_set_pcie_lanes, .set_clock_gating = NULL, .set_surface_reg = r600_set_surface_reg, .clear_surface_reg = r600_clear_surface_reg, @@ -654,7 +654,7 @@ static struct radeon_asic rv770_asic = { .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, + .set_pcie_lanes = &rv370_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, @@ -694,6 +694,7 @@ 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, .set_clock_gating = NULL, .set_surface_reg = r600_set_surface_reg, diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index bcee679..4998b24 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1850,10 +1850,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[0]; rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; - if (rdev->asic->get_pcie_lanes) - rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = radeon_get_pcie_lanes(rdev); - else - rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = 16; + rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = 16; rdev->pm.default_power_state_index = state_index; rdev->pm.power_state[state_index].flags = 0; state_index++; diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 4e23132..ee92615 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -2447,10 +2447,7 @@ default_mode: rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk; rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[0]; rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; - if (rdev->asic->get_pcie_lanes) - rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = radeon_get_pcie_lanes(rdev); - else - rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = 16; + rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = 16; rdev->pm.power_state[state_index].flags = 0; rdev->pm.default_power_state_index = state_index; rdev->pm.num_power_states = state_index + 1; diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h index 1776e05..87dc5b4 100644 --- a/drivers/gpu/drm/radeon/radeon_reg.h +++ b/drivers/gpu/drm/radeon/radeon_reg.h @@ -305,6 +305,7 @@ /* #define RADEON_PCIE_INDEX 0x0030 */ /* #define RADEON_PCIE_DATA 0x0034 */ +/* 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 @@ -317,9 +318,14 @@ # 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 */ -- 1.5.6.3