83,26 → 83,20 |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
ENABLE_SCALER_PS_ALLOCATION args; |
int index = GetIndexIntoMasterTable(COMMAND, EnableScaler); |
|
struct radeon_encoder *radeon_encoder = |
to_radeon_encoder(radeon_crtc->encoder); |
/* fixme - fill in enc_priv for atom dac */ |
enum radeon_tv_std tv_std = TV_STD_NTSC; |
bool is_tv = false, is_cv = false; |
struct drm_encoder *encoder; |
|
if (!ASIC_IS_AVIVO(rdev) && radeon_crtc->crtc_id) |
return; |
|
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
/* find tv std */ |
if (encoder->crtc == crtc) { |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) { |
struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv; |
tv_std = tv_dac->tv_std; |
is_tv = true; |
} |
} |
} |
|
memset(&args, 0, sizeof(args)); |
|
231,6 → 225,22 |
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
} |
|
static void atombios_powergate_crtc(struct drm_crtc *crtc, int state) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating); |
ENABLE_DISP_POWER_GATING_PARAMETERS_V2_1 args; |
|
memset(&args, 0, sizeof(args)); |
|
args.ucDispPipeId = radeon_crtc->crtc_id; |
args.ucEnable = state; |
|
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
} |
|
void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) |
{ |
struct drm_device *dev = crtc->dev; |
242,8 → 252,10 |
radeon_crtc->enabled = true; |
/* adjust pm to dpms changes BEFORE enabling crtcs */ |
radeon_pm_compute_clocks(rdev); |
if (ASIC_IS_DCE6(rdev) && !radeon_crtc->in_mode_set) |
atombios_powergate_crtc(crtc, ATOM_DISABLE); |
atombios_enable_crtc(crtc, ATOM_ENABLE); |
if (ASIC_IS_DCE3(rdev)) |
if (ASIC_IS_DCE3(rdev) && !ASIC_IS_DCE6(rdev)) |
atombios_enable_crtc_memreq(crtc, ATOM_ENABLE); |
atombios_blank_crtc(crtc, ATOM_DISABLE); |
drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); |
255,10 → 267,12 |
drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id); |
if (radeon_crtc->enabled) |
atombios_blank_crtc(crtc, ATOM_ENABLE); |
if (ASIC_IS_DCE3(rdev)) |
if (ASIC_IS_DCE3(rdev) && !ASIC_IS_DCE6(rdev)) |
atombios_enable_crtc_memreq(crtc, ATOM_DISABLE); |
atombios_enable_crtc(crtc, ATOM_DISABLE); |
radeon_crtc->enabled = false; |
if (ASIC_IS_DCE6(rdev) && !radeon_crtc->in_mode_set) |
atombios_powergate_crtc(crtc, ATOM_ENABLE); |
/* adjust pm to dpms changes AFTER disabling crtcs */ |
radeon_pm_compute_clocks(rdev); |
break; |
355,15 → 369,12 |
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
} |
|
static void atombios_disable_ss(struct drm_crtc *crtc) |
static void atombios_disable_ss(struct radeon_device *rdev, int pll_id) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
u32 ss_cntl; |
|
if (ASIC_IS_DCE4(rdev)) { |
switch (radeon_crtc->pll_id) { |
switch (pll_id) { |
case ATOM_PPLL1: |
ss_cntl = RREG32(EVERGREEN_P1PLL_SS_CNTL); |
ss_cntl &= ~EVERGREEN_PxPLL_SS_EN; |
379,7 → 390,7 |
return; |
} |
} else if (ASIC_IS_AVIVO(rdev)) { |
switch (radeon_crtc->pll_id) { |
switch (pll_id) { |
case ATOM_PPLL1: |
ss_cntl = RREG32(AVIVO_P1PLL_INT_SS_CNTL); |
ss_cntl &= ~1; |
406,16 → 417,31 |
ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 v3; |
}; |
|
static void atombios_crtc_program_ss(struct drm_crtc *crtc, |
static void atombios_crtc_program_ss(struct radeon_device *rdev, |
int enable, |
int pll_id, |
int crtc_id, |
struct radeon_atom_ss *ss) |
{ |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
unsigned i; |
int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL); |
union atom_enable_ss args; |
|
if (!enable) { |
for (i = 0; i < rdev->num_crtc; i++) { |
if (rdev->mode_info.crtcs[i] && |
rdev->mode_info.crtcs[i]->enabled && |
i != crtc_id && |
pll_id == rdev->mode_info.crtcs[i]->pll_id) { |
/* one other crtc is using this pll don't turn |
* off spread spectrum as it might turn off |
* display on active crtc |
*/ |
return; |
} |
} |
} |
|
memset(&args, 0, sizeof(args)); |
|
if (ASIC_IS_DCE5(rdev)) { |
424,24 → 450,20 |
switch (pll_id) { |
case ATOM_PPLL1: |
args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL; |
args.v3.usSpreadSpectrumAmount = cpu_to_le16(ss->amount); |
args.v3.usSpreadSpectrumStep = cpu_to_le16(ss->step); |
break; |
case ATOM_PPLL2: |
args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL; |
args.v3.usSpreadSpectrumAmount = cpu_to_le16(ss->amount); |
args.v3.usSpreadSpectrumStep = cpu_to_le16(ss->step); |
break; |
case ATOM_DCPLL: |
args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL; |
args.v3.usSpreadSpectrumAmount = cpu_to_le16(0); |
args.v3.usSpreadSpectrumStep = cpu_to_le16(0); |
break; |
case ATOM_PPLL_INVALID: |
return; |
} |
args.v3.usSpreadSpectrumAmount = cpu_to_le16(ss->amount); |
args.v3.usSpreadSpectrumStep = cpu_to_le16(ss->step); |
args.v3.ucEnable = enable; |
if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK)) |
if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK) || ASIC_IS_DCE61(rdev)) |
args.v3.ucEnable = ATOM_DISABLE; |
} else if (ASIC_IS_DCE4(rdev)) { |
args.v2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); |
449,24 → 471,20 |
switch (pll_id) { |
case ATOM_PPLL1: |
args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P1PLL; |
args.v2.usSpreadSpectrumAmount = cpu_to_le16(ss->amount); |
args.v2.usSpreadSpectrumStep = cpu_to_le16(ss->step); |
break; |
case ATOM_PPLL2: |
args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P2PLL; |
args.v2.usSpreadSpectrumAmount = cpu_to_le16(ss->amount); |
args.v2.usSpreadSpectrumStep = cpu_to_le16(ss->step); |
break; |
case ATOM_DCPLL: |
args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_DCPLL; |
args.v2.usSpreadSpectrumAmount = cpu_to_le16(0); |
args.v2.usSpreadSpectrumStep = cpu_to_le16(0); |
break; |
case ATOM_PPLL_INVALID: |
return; |
} |
args.v2.usSpreadSpectrumAmount = cpu_to_le16(ss->amount); |
args.v2.usSpreadSpectrumStep = cpu_to_le16(ss->step); |
args.v2.ucEnable = enable; |
if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK)) |
if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK) || ASIC_IS_DCE41(rdev)) |
args.v2.ucEnable = ATOM_DISABLE; |
} else if (ASIC_IS_DCE3(rdev)) { |
args.v1.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); |
479,7 → 497,7 |
} else if (ASIC_IS_AVIVO(rdev)) { |
if ((enable == ATOM_DISABLE) || (ss->percentage == 0) || |
(ss->type & ATOM_EXTERNAL_SS_MASK)) { |
atombios_disable_ss(crtc); |
atombios_disable_ss(rdev, pll_id); |
return; |
} |
args.lvds_ss_2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); |
491,7 → 509,7 |
} else { |
if ((enable == ATOM_DISABLE) || (ss->percentage == 0) || |
(ss->type & ATOM_EXTERNAL_SS_MASK)) { |
atombios_disable_ss(crtc); |
atombios_disable_ss(rdev, pll_id); |
return; |
} |
args.lvds_ss.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); |
509,56 → 527,51 |
}; |
|
static u32 atombios_adjust_pll(struct drm_crtc *crtc, |
struct drm_display_mode *mode, |
struct radeon_pll *pll, |
bool ss_enabled, |
struct radeon_atom_ss *ss) |
struct drm_display_mode *mode) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct drm_encoder *encoder = NULL; |
struct radeon_encoder *radeon_encoder = NULL; |
struct drm_connector *connector = NULL; |
struct drm_encoder *encoder = radeon_crtc->encoder; |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); |
u32 adjusted_clock = mode->clock; |
int encoder_mode = 0; |
int encoder_mode = atombios_get_encoder_mode(encoder); |
u32 dp_clock = mode->clock; |
int bpc = 8; |
int bpc = radeon_get_monitor_bpc(connector); |
bool is_duallink = radeon_dig_monitor_is_duallink(encoder, mode->clock); |
|
/* reset the pll flags */ |
pll->flags = 0; |
radeon_crtc->pll_flags = 0; |
|
if (ASIC_IS_AVIVO(rdev)) { |
if ((rdev->family == CHIP_RS600) || |
(rdev->family == CHIP_RS690) || |
(rdev->family == CHIP_RS740)) |
pll->flags |= (/*RADEON_PLL_USE_FRAC_FB_DIV |*/ |
radeon_crtc->pll_flags |= (/*RADEON_PLL_USE_FRAC_FB_DIV |*/ |
RADEON_PLL_PREFER_CLOSEST_LOWER); |
|
if (ASIC_IS_DCE32(rdev) && mode->clock > 200000) /* range limits??? */ |
pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; |
radeon_crtc->pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; |
else |
pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; |
radeon_crtc->pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; |
|
if (rdev->family < CHIP_RV770) |
pll->flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP; |
radeon_crtc->pll_flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP; |
/* use frac fb div on APUs */ |
if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev)) |
radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; |
} else { |
pll->flags |= RADEON_PLL_LEGACY; |
radeon_crtc->pll_flags |= RADEON_PLL_LEGACY; |
|
if (mode->clock > 200000) /* range limits??? */ |
pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; |
radeon_crtc->pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; |
else |
pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; |
radeon_crtc->pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; |
} |
|
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
if (encoder->crtc == crtc) { |
radeon_encoder = to_radeon_encoder(encoder); |
connector = radeon_get_connector_for_encoder(encoder); |
if (connector) |
bpc = connector->display_info.bpc; |
encoder_mode = atombios_get_encoder_mode(encoder); |
if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) || |
radeon_encoder_is_dp_bridge(encoder)) { |
(radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)) { |
if (connector) { |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
struct radeon_connector_atom_dig *dig_connector = |
570,12 → 583,12 |
|
/* use recommended ref_div for ss */ |
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { |
if (ss_enabled) { |
if (ss->refdiv) { |
pll->flags |= RADEON_PLL_USE_REF_DIV; |
pll->reference_div = ss->refdiv; |
if (radeon_crtc->ss_enabled) { |
if (radeon_crtc->ss.refdiv) { |
radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV; |
radeon_crtc->pll_reference_div = radeon_crtc->ss.refdiv; |
if (ASIC_IS_AVIVO(rdev)) |
pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV; |
radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; |
} |
} |
} |
585,18 → 598,15 |
if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1) |
adjusted_clock = mode->clock * 2; |
if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) |
pll->flags |= RADEON_PLL_PREFER_CLOSEST_LOWER; |
radeon_crtc->pll_flags |= RADEON_PLL_PREFER_CLOSEST_LOWER; |
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) |
pll->flags |= RADEON_PLL_IS_LCD; |
radeon_crtc->pll_flags |= RADEON_PLL_IS_LCD; |
} else { |
if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) |
pll->flags |= RADEON_PLL_NO_ODD_POST_DIV; |
radeon_crtc->pll_flags |= RADEON_PLL_NO_ODD_POST_DIV; |
if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) |
pll->flags |= RADEON_PLL_USE_REF_DIV; |
radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV; |
} |
break; |
} |
} |
|
/* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock |
* accordingly based on the encoder/transmitter to work around |
622,7 → 632,7 |
args.v1.usPixelClock = cpu_to_le16(mode->clock / 10); |
args.v1.ucTransmitterID = radeon_encoder->encoder_id; |
args.v1.ucEncodeMode = encoder_mode; |
if (ss_enabled && ss->percentage) |
if (radeon_crtc->ss_enabled && radeon_crtc->ss.percentage) |
args.v1.ucConfig |= |
ADJUST_DISPLAY_CONFIG_SS_ENABLE; |
|
635,47 → 645,32 |
args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id; |
args.v3.sInput.ucEncodeMode = encoder_mode; |
args.v3.sInput.ucDispPllConfig = 0; |
if (ss_enabled && ss->percentage) |
if (radeon_crtc->ss_enabled && radeon_crtc->ss.percentage) |
args.v3.sInput.ucDispPllConfig |= |
DISPPLL_CONFIG_SS_ENABLE; |
if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT) || |
radeon_encoder_is_dp_bridge(encoder)) { |
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; |
if (encoder_mode == ATOM_ENCODER_MODE_DP) { |
if (ENCODER_MODE_IS_DP(encoder_mode)) { |
args.v3.sInput.ucDispPllConfig |= |
DISPPLL_CONFIG_COHERENT_MODE; |
/* 16200 or 27000 */ |
args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); |
} else { |
if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { |
} else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { |
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; |
if (encoder_mode == ATOM_ENCODER_MODE_HDMI) |
/* deep color support */ |
args.v3.sInput.usPixelClock = |
cpu_to_le16((mode->clock * bpc / 8) / 10); |
} |
if (dig->coherent_mode) |
args.v3.sInput.ucDispPllConfig |= |
DISPPLL_CONFIG_COHERENT_MODE; |
if (mode->clock > 165000) |
if (is_duallink) |
args.v3.sInput.ucDispPllConfig |= |
DISPPLL_CONFIG_DUAL_LINK; |
} |
} else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { |
if (encoder_mode == ATOM_ENCODER_MODE_DP) { |
args.v3.sInput.ucDispPllConfig |= |
DISPPLL_CONFIG_COHERENT_MODE; |
/* 16200 or 27000 */ |
args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); |
} else if (encoder_mode != ATOM_ENCODER_MODE_LVDS) { |
if (mode->clock > 165000) |
args.v3.sInput.ucDispPllConfig |= |
DISPPLL_CONFIG_DUAL_LINK; |
} |
} |
if (radeon_encoder_is_dp_bridge(encoder)) { |
struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder); |
struct radeon_encoder *ext_radeon_encoder = to_radeon_encoder(ext_encoder); |
args.v3.sInput.ucExtTransmitterID = ext_radeon_encoder->encoder_id; |
} else |
if (radeon_encoder_get_dp_bridge_encoder_id(encoder) != |
ENCODER_OBJECT_ID_NONE) |
args.v3.sInput.ucExtTransmitterID = |
radeon_encoder_get_dp_bridge_encoder_id(encoder); |
else |
args.v3.sInput.ucExtTransmitterID = 0; |
|
atom_execute_table(rdev->mode_info.atom_context, |
682,14 → 677,14 |
index, (uint32_t *)&args); |
adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10; |
if (args.v3.sOutput.ucRefDiv) { |
pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV; |
pll->flags |= RADEON_PLL_USE_REF_DIV; |
pll->reference_div = args.v3.sOutput.ucRefDiv; |
radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; |
radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV; |
radeon_crtc->pll_reference_div = args.v3.sOutput.ucRefDiv; |
} |
if (args.v3.sOutput.ucPostDiv) { |
pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV; |
pll->flags |= RADEON_PLL_USE_POST_DIV; |
pll->post_div = args.v3.sOutput.ucPostDiv; |
radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; |
radeon_crtc->pll_flags |= RADEON_PLL_USE_POST_DIV; |
radeon_crtc->pll_post_div = args.v3.sOutput.ucPostDiv; |
} |
break; |
default: |
717,11 → 712,9 |
/* on DCE5, make sure the voltage is high enough to support the |
* required disp clk. |
*/ |
static void atombios_crtc_set_dcpll(struct drm_crtc *crtc, |
static void atombios_crtc_set_disp_eng_pll(struct radeon_device *rdev, |
u32 dispclk) |
{ |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
u8 frev, crev; |
int index; |
union set_pixel_clock args; |
749,6 → 742,11 |
* SetPixelClock provides the dividers |
*/ |
args.v6.ulDispEngClkFreq = cpu_to_le32(dispclk); |
if (ASIC_IS_DCE61(rdev)) |
args.v6.ucPpll = ATOM_EXT_PLL1; |
else if (ASIC_IS_DCE6(rdev)) |
args.v6.ucPpll = ATOM_PPLL0; |
else |
args.v6.ucPpll = ATOM_DCPLL; |
break; |
default: |
821,7 → 819,10 |
args.v3.ucFracFbDiv = frac_fb_div; |
args.v3.ucPostDiv = post_div; |
args.v3.ucPpll = pll_id; |
args.v3.ucMiscInfo = (pll_id << 2); |
if (crtc_id == ATOM_CRTC2) |
args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC2; |
else |
args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC1; |
if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) |
args.v3.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC; |
args.v3.ucTransmitterId = encoder_id; |
891,103 → 892,84 |
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
} |
|
static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) |
static bool atombios_crtc_prepare_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct drm_encoder *encoder = NULL; |
struct radeon_encoder *radeon_encoder = NULL; |
u32 pll_clock = mode->clock; |
u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; |
struct radeon_pll *pll; |
u32 adjusted_clock; |
int encoder_mode = 0; |
struct radeon_atom_ss ss; |
bool ss_enabled = false; |
int bpc = 8; |
struct radeon_encoder *radeon_encoder = |
to_radeon_encoder(radeon_crtc->encoder); |
int encoder_mode = atombios_get_encoder_mode(radeon_crtc->encoder); |
|
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
if (encoder->crtc == crtc) { |
radeon_encoder = to_radeon_encoder(encoder); |
encoder_mode = atombios_get_encoder_mode(encoder); |
break; |
} |
} |
radeon_crtc->bpc = 8; |
radeon_crtc->ss_enabled = false; |
|
if (!radeon_encoder) |
return; |
|
switch (radeon_crtc->pll_id) { |
case ATOM_PPLL1: |
pll = &rdev->clock.p1pll; |
break; |
case ATOM_PPLL2: |
pll = &rdev->clock.p2pll; |
break; |
case ATOM_DCPLL: |
case ATOM_PPLL_INVALID: |
default: |
pll = &rdev->clock.dcpll; |
break; |
} |
|
if (radeon_encoder->active_device & |
(ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) { |
if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) || |
(radeon_encoder_get_dp_bridge_encoder_id(radeon_crtc->encoder) != ENCODER_OBJECT_ID_NONE)) { |
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; |
struct drm_connector *connector = |
radeon_get_connector_for_encoder(encoder); |
radeon_get_connector_for_encoder(radeon_crtc->encoder); |
struct radeon_connector *radeon_connector = |
to_radeon_connector(connector); |
struct radeon_connector_atom_dig *dig_connector = |
radeon_connector->con_priv; |
int dp_clock; |
bpc = connector->display_info.bpc; |
radeon_crtc->bpc = radeon_get_monitor_bpc(connector); |
|
switch (encoder_mode) { |
case ATOM_ENCODER_MODE_DP_MST: |
case ATOM_ENCODER_MODE_DP: |
/* DP/eDP */ |
dp_clock = dig_connector->dp_clock / 10; |
if (ASIC_IS_DCE4(rdev)) |
ss_enabled = |
radeon_atombios_get_asic_ss_info(rdev, &ss, |
radeon_crtc->ss_enabled = |
radeon_atombios_get_asic_ss_info(rdev, &radeon_crtc->ss, |
ASIC_INTERNAL_SS_ON_DP, |
dp_clock); |
else { |
if (dp_clock == 16200) { |
ss_enabled = |
radeon_atombios_get_ppll_ss_info(rdev, &ss, |
radeon_crtc->ss_enabled = |
radeon_atombios_get_ppll_ss_info(rdev, |
&radeon_crtc->ss, |
ATOM_DP_SS_ID2); |
if (!ss_enabled) |
ss_enabled = |
radeon_atombios_get_ppll_ss_info(rdev, &ss, |
if (!radeon_crtc->ss_enabled) |
radeon_crtc->ss_enabled = |
radeon_atombios_get_ppll_ss_info(rdev, |
&radeon_crtc->ss, |
ATOM_DP_SS_ID1); |
} else |
ss_enabled = |
radeon_atombios_get_ppll_ss_info(rdev, &ss, |
radeon_crtc->ss_enabled = |
radeon_atombios_get_ppll_ss_info(rdev, |
&radeon_crtc->ss, |
ATOM_DP_SS_ID1); |
} |
break; |
case ATOM_ENCODER_MODE_LVDS: |
if (ASIC_IS_DCE4(rdev)) |
ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &ss, |
radeon_crtc->ss_enabled = |
radeon_atombios_get_asic_ss_info(rdev, |
&radeon_crtc->ss, |
dig->lcd_ss_id, |
mode->clock / 10); |
else |
ss_enabled = radeon_atombios_get_ppll_ss_info(rdev, &ss, |
radeon_crtc->ss_enabled = |
radeon_atombios_get_ppll_ss_info(rdev, |
&radeon_crtc->ss, |
dig->lcd_ss_id); |
break; |
case ATOM_ENCODER_MODE_DVI: |
if (ASIC_IS_DCE4(rdev)) |
ss_enabled = |
radeon_atombios_get_asic_ss_info(rdev, &ss, |
radeon_crtc->ss_enabled = |
radeon_atombios_get_asic_ss_info(rdev, |
&radeon_crtc->ss, |
ASIC_INTERNAL_SS_ON_TMDS, |
mode->clock / 10); |
break; |
case ATOM_ENCODER_MODE_HDMI: |
if (ASIC_IS_DCE4(rdev)) |
ss_enabled = |
radeon_atombios_get_asic_ss_info(rdev, &ss, |
radeon_crtc->ss_enabled = |
radeon_atombios_get_asic_ss_info(rdev, |
&radeon_crtc->ss, |
ASIC_INTERNAL_SS_ON_HDMI, |
mode->clock / 10); |
break; |
997,43 → 979,80 |
} |
|
/* adjust pixel clock as needed */ |
adjusted_clock = atombios_adjust_pll(crtc, mode, pll, ss_enabled, &ss); |
radeon_crtc->adjusted_clock = atombios_adjust_pll(crtc, mode); |
|
return true; |
} |
|
static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_encoder *radeon_encoder = |
to_radeon_encoder(radeon_crtc->encoder); |
u32 pll_clock = mode->clock; |
u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; |
struct radeon_pll *pll; |
int encoder_mode = atombios_get_encoder_mode(radeon_crtc->encoder); |
|
switch (radeon_crtc->pll_id) { |
case ATOM_PPLL1: |
pll = &rdev->clock.p1pll; |
break; |
case ATOM_PPLL2: |
pll = &rdev->clock.p2pll; |
break; |
case ATOM_DCPLL: |
case ATOM_PPLL_INVALID: |
default: |
pll = &rdev->clock.dcpll; |
break; |
} |
|
/* update pll params */ |
pll->flags = radeon_crtc->pll_flags; |
pll->reference_div = radeon_crtc->pll_reference_div; |
pll->post_div = radeon_crtc->pll_post_div; |
|
if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) |
/* TV seems to prefer the legacy algo on some boards */ |
radeon_compute_pll_legacy(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, |
&ref_div, &post_div); |
radeon_compute_pll_legacy(pll, radeon_crtc->adjusted_clock, &pll_clock, |
&fb_div, &frac_fb_div, &ref_div, &post_div); |
else if (ASIC_IS_AVIVO(rdev)) |
radeon_compute_pll_avivo(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, |
&ref_div, &post_div); |
radeon_compute_pll_avivo(pll, radeon_crtc->adjusted_clock, &pll_clock, |
&fb_div, &frac_fb_div, &ref_div, &post_div); |
else |
radeon_compute_pll_legacy(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, |
&ref_div, &post_div); |
radeon_compute_pll_legacy(pll, radeon_crtc->adjusted_clock, &pll_clock, |
&fb_div, &frac_fb_div, &ref_div, &post_div); |
|
atombios_crtc_program_ss(crtc, ATOM_DISABLE, radeon_crtc->pll_id, &ss); |
atombios_crtc_program_ss(rdev, ATOM_DISABLE, radeon_crtc->pll_id, |
radeon_crtc->crtc_id, &radeon_crtc->ss); |
|
atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, |
encoder_mode, radeon_encoder->encoder_id, mode->clock, |
ref_div, fb_div, frac_fb_div, post_div, bpc, ss_enabled, &ss); |
ref_div, fb_div, frac_fb_div, post_div, |
radeon_crtc->bpc, radeon_crtc->ss_enabled, &radeon_crtc->ss); |
|
if (ss_enabled) { |
if (radeon_crtc->ss_enabled) { |
/* calculate ss amount and step size */ |
if (ASIC_IS_DCE4(rdev)) { |
u32 step_size; |
u32 amount = (((fb_div * 10) + frac_fb_div) * ss.percentage) / 10000; |
ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK; |
ss.amount |= ((amount - (amount / 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) & |
u32 amount = (((fb_div * 10) + frac_fb_div) * radeon_crtc->ss.percentage) / 10000; |
radeon_crtc->ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK; |
radeon_crtc->ss.amount |= ((amount - (amount / 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) & |
ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK; |
if (ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD) |
step_size = (4 * amount * ref_div * (ss.rate * 2048)) / |
if (radeon_crtc->ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD) |
step_size = (4 * amount * ref_div * (radeon_crtc->ss.rate * 2048)) / |
(125 * 25 * pll->reference_freq / 100); |
else |
step_size = (2 * amount * ref_div * (ss.rate * 2048)) / |
step_size = (2 * amount * ref_div * (radeon_crtc->ss.rate * 2048)) / |
(125 * 25 * pll->reference_freq / 100); |
ss.step = step_size; |
radeon_crtc->ss.step = step_size; |
} |
|
atombios_crtc_program_ss(crtc, ATOM_ENABLE, radeon_crtc->pll_id, &ss); |
atombios_crtc_program_ss(rdev, ATOM_ENABLE, radeon_crtc->pll_id, |
radeon_crtc->crtc_id, &radeon_crtc->ss); |
} |
} |
|
1050,6 → 1069,7 |
struct radeon_bo *rbo; |
uint64_t fb_location; |
uint32_t fb_format, fb_pitch_pixels, tiling_flags; |
unsigned bankw, bankh, mtaspect, tile_split; |
u32 fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE); |
u32 tmp, viewport_w, viewport_h; |
int r; |
1121,11 → 1141,43 |
return -EINVAL; |
} |
|
if (tiling_flags & RADEON_TILING_MACRO) |
if (tiling_flags & RADEON_TILING_MACRO) { |
if (rdev->family >= CHIP_TAHITI) |
tmp = rdev->config.si.tile_config; |
else if (rdev->family >= CHIP_CAYMAN) |
tmp = rdev->config.cayman.tile_config; |
else |
tmp = rdev->config.evergreen.tile_config; |
|
switch ((tmp & 0xf0) >> 4) { |
case 0: /* 4 banks */ |
fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_4_BANK); |
break; |
case 1: /* 8 banks */ |
default: |
fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_8_BANK); |
break; |
case 2: /* 16 banks */ |
fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_16_BANK); |
break; |
} |
|
fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1); |
else if (tiling_flags & RADEON_TILING_MICRO) |
|
evergreen_tiling_fields(tiling_flags, &bankw, &bankh, &mtaspect, &tile_split); |
fb_format |= EVERGREEN_GRPH_TILE_SPLIT(tile_split); |
fb_format |= EVERGREEN_GRPH_BANK_WIDTH(bankw); |
fb_format |= EVERGREEN_GRPH_BANK_HEIGHT(bankh); |
fb_format |= EVERGREEN_GRPH_MACRO_TILE_ASPECT(mtaspect); |
} else if (tiling_flags & RADEON_TILING_MICRO) |
fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1); |
|
if ((rdev->family == CHIP_TAHITI) || |
(rdev->family == CHIP_PITCAIRN)) |
fb_format |= SI_GRPH_PIPE_CONFIG(SI_ADDR_SURF_P8_32x32_8x16); |
else if (rdev->family == CHIP_VERDE) |
fb_format |= SI_GRPH_PIPE_CONFIG(SI_ADDR_SURF_P4_8x16); |
|
switch (radeon_crtc->crtc_id) { |
case 0: |
WREG32(AVIVO_D1VGA_CONTROL, 0); |
1167,12 → 1219,12 |
WREG32(EVERGREEN_GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width); |
WREG32(EVERGREEN_GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height); |
|
fb_pitch_pixels = target_fb->pitch / (target_fb->bits_per_pixel / 8); |
fb_pitch_pixels = target_fb->pitches[0] / (target_fb->bits_per_pixel / 8); |
WREG32(EVERGREEN_GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); |
WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1); |
|
WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, |
crtc->mode.vdisplay); |
target_fb->height); |
x &= ~3; |
y &= ~1; |
WREG32(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset, |
1336,12 → 1388,12 |
WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width); |
WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height); |
|
fb_pitch_pixels = target_fb->pitch / (target_fb->bits_per_pixel / 8); |
fb_pitch_pixels = target_fb->pitches[0] / (target_fb->bits_per_pixel / 8); |
WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); |
WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1); |
|
WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, |
crtc->mode.vdisplay); |
target_fb->height); |
x &= ~3; |
y &= ~1; |
WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset, |
1429,54 → 1481,273 |
} |
} |
|
/** |
* radeon_get_pll_use_mask - look up a mask of which pplls are in use |
* |
* @crtc: drm crtc |
* |
* Returns the mask of which PPLLs (Pixel PLLs) are in use. |
*/ |
static u32 radeon_get_pll_use_mask(struct drm_crtc *crtc) |
{ |
struct drm_device *dev = crtc->dev; |
struct drm_crtc *test_crtc; |
struct radeon_crtc *test_radeon_crtc; |
u32 pll_in_use = 0; |
|
list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { |
if (crtc == test_crtc) |
continue; |
|
test_radeon_crtc = to_radeon_crtc(test_crtc); |
if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID) |
pll_in_use |= (1 << test_radeon_crtc->pll_id); |
} |
return pll_in_use; |
} |
|
/** |
* radeon_get_shared_dp_ppll - return the PPLL used by another crtc for DP |
* |
* @crtc: drm crtc |
* |
* Returns the PPLL (Pixel PLL) used by another crtc/encoder which is |
* also in DP mode. For DP, a single PPLL can be used for all DP |
* crtcs/encoders. |
*/ |
static int radeon_get_shared_dp_ppll(struct drm_crtc *crtc) |
{ |
struct drm_device *dev = crtc->dev; |
struct drm_crtc *test_crtc; |
struct radeon_crtc *test_radeon_crtc; |
|
list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { |
if (crtc == test_crtc) |
continue; |
test_radeon_crtc = to_radeon_crtc(test_crtc); |
if (test_radeon_crtc->encoder && |
ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_radeon_crtc->encoder))) { |
/* for DP use the same PLL for all */ |
if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID) |
return test_radeon_crtc->pll_id; |
} |
} |
return ATOM_PPLL_INVALID; |
} |
|
/** |
* radeon_get_shared_nondp_ppll - return the PPLL used by another non-DP crtc |
* |
* @crtc: drm crtc |
* @encoder: drm encoder |
* |
* Returns the PPLL (Pixel PLL) used by another non-DP crtc/encoder which can |
* be shared (i.e., same clock). |
*/ |
static int radeon_get_shared_nondp_ppll(struct drm_crtc *crtc) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
struct drm_device *dev = crtc->dev; |
struct drm_crtc *test_crtc; |
struct radeon_crtc *test_radeon_crtc; |
u32 adjusted_clock, test_adjusted_clock; |
|
adjusted_clock = radeon_crtc->adjusted_clock; |
|
if (adjusted_clock == 0) |
return ATOM_PPLL_INVALID; |
|
list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { |
if (crtc == test_crtc) |
continue; |
test_radeon_crtc = to_radeon_crtc(test_crtc); |
if (test_radeon_crtc->encoder && |
!ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_radeon_crtc->encoder))) { |
/* check if we are already driving this connector with another crtc */ |
if (test_radeon_crtc->connector == radeon_crtc->connector) { |
/* if we are, return that pll */ |
if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID) |
return test_radeon_crtc->pll_id; |
} |
/* for non-DP check the clock */ |
test_adjusted_clock = test_radeon_crtc->adjusted_clock; |
if ((crtc->mode.clock == test_crtc->mode.clock) && |
(adjusted_clock == test_adjusted_clock) && |
(radeon_crtc->ss_enabled == test_radeon_crtc->ss_enabled) && |
(test_radeon_crtc->pll_id != ATOM_PPLL_INVALID)) |
return test_radeon_crtc->pll_id; |
} |
} |
return ATOM_PPLL_INVALID; |
} |
|
/** |
* radeon_atom_pick_pll - Allocate a PPLL for use by the crtc. |
* |
* @crtc: drm crtc |
* |
* Returns the PPLL (Pixel PLL) to be used by the crtc. For DP monitors |
* a single PPLL can be used for all DP crtcs/encoders. For non-DP |
* monitors a dedicated PPLL must be used. If a particular board has |
* an external DP PLL, return ATOM_PPLL_INVALID to skip PLL programming |
* as there is no need to program the PLL itself. If we are not able to |
* allocate a PLL, return ATOM_PPLL_INVALID to skip PLL programming to |
* avoid messing up an existing monitor. |
* |
* Asic specific PLL information |
* |
* DCE 6.1 |
* - PPLL2 is only available to UNIPHYA (both DP and non-DP) |
* - PPLL0, PPLL1 are available for UNIPHYB/C/D/E/F (both DP and non-DP) |
* |
* DCE 6.0 |
* - PPLL0 is available to all UNIPHY (DP only) |
* - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC |
* |
* DCE 5.0 |
* - DCPLL is available to all UNIPHY (DP only) |
* - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC |
* |
* DCE 3.0/4.0/4.1 |
* - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC |
* |
*/ |
static int radeon_atom_pick_pll(struct drm_crtc *crtc) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct drm_encoder *test_encoder; |
struct drm_crtc *test_crtc; |
uint32_t pll_in_use = 0; |
struct radeon_encoder *radeon_encoder = |
to_radeon_encoder(radeon_crtc->encoder); |
u32 pll_in_use; |
int pll; |
|
if (ASIC_IS_DCE4(rdev)) { |
list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { |
if (test_encoder->crtc && (test_encoder->crtc == crtc)) { |
if (ASIC_IS_DCE61(rdev)) { |
struct radeon_encoder_atom_dig *dig = |
radeon_encoder->enc_priv; |
|
if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY) && |
(dig->linkb == false)) |
/* UNIPHY A uses PPLL2 */ |
return ATOM_PPLL2; |
else if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { |
/* UNIPHY B/C/D/E/F */ |
if (rdev->clock.dp_extclk) |
/* skip PPLL programming if using ext clock */ |
return ATOM_PPLL_INVALID; |
else { |
/* use the same PPLL for all DP monitors */ |
pll = radeon_get_shared_dp_ppll(crtc); |
if (pll != ATOM_PPLL_INVALID) |
return pll; |
} |
} else { |
/* use the same PPLL for all monitors with the same clock */ |
pll = radeon_get_shared_nondp_ppll(crtc); |
if (pll != ATOM_PPLL_INVALID) |
return pll; |
} |
/* UNIPHY B/C/D/E/F */ |
pll_in_use = radeon_get_pll_use_mask(crtc); |
if (!(pll_in_use & (1 << ATOM_PPLL0))) |
return ATOM_PPLL0; |
if (!(pll_in_use & (1 << ATOM_PPLL1))) |
return ATOM_PPLL1; |
DRM_ERROR("unable to allocate a PPLL\n"); |
return ATOM_PPLL_INVALID; |
} else if (ASIC_IS_DCE4(rdev)) { |
/* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock, |
* depending on the asic: |
* DCE4: PPLL or ext clock |
* DCE5: DCPLL or ext clock |
* DCE5: PPLL, DCPLL, or ext clock |
* DCE6: PPLL, PPLL0, or ext clock |
* |
* Setting ATOM_PPLL_INVALID will cause SetPixelClock to skip |
* PPLL/DCPLL programming and only program the DP DTO for the |
* crtc virtual pixel clock. |
*/ |
if (atombios_get_encoder_mode(test_encoder) == ATOM_ENCODER_MODE_DP) { |
if (ASIC_IS_DCE5(rdev) || rdev->clock.dp_extclk) |
if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { |
if (rdev->clock.dp_extclk) |
/* skip PPLL programming if using ext clock */ |
return ATOM_PPLL_INVALID; |
else if (ASIC_IS_DCE6(rdev)) |
/* use PPLL0 for all DP */ |
return ATOM_PPLL0; |
else if (ASIC_IS_DCE5(rdev)) |
/* use DCPLL for all DP */ |
return ATOM_DCPLL; |
else { |
/* use the same PPLL for all DP monitors */ |
pll = radeon_get_shared_dp_ppll(crtc); |
if (pll != ATOM_PPLL_INVALID) |
return pll; |
} |
} else { |
/* use the same PPLL for all monitors with the same clock */ |
pll = radeon_get_shared_nondp_ppll(crtc); |
if (pll != ATOM_PPLL_INVALID) |
return pll; |
} |
/* all other cases */ |
pll_in_use = radeon_get_pll_use_mask(crtc); |
if (!(pll_in_use & (1 << ATOM_PPLL1))) |
return ATOM_PPLL1; |
if (!(pll_in_use & (1 << ATOM_PPLL2))) |
return ATOM_PPLL2; |
DRM_ERROR("unable to allocate a PPLL\n"); |
return ATOM_PPLL_INVALID; |
} else { |
if (ASIC_IS_AVIVO(rdev)) { |
/* in DP mode, the DP ref clock can come from either PPLL |
* depending on the asic: |
* DCE3: PPLL1 or PPLL2 |
*/ |
if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { |
/* use the same PPLL for all DP monitors */ |
pll = radeon_get_shared_dp_ppll(crtc); |
if (pll != ATOM_PPLL_INVALID) |
return pll; |
} else { |
/* use the same PPLL for all monitors with the same clock */ |
pll = radeon_get_shared_nondp_ppll(crtc); |
if (pll != ATOM_PPLL_INVALID) |
return pll; |
} |
|
/* otherwise, pick one of the plls */ |
list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { |
struct radeon_crtc *radeon_test_crtc; |
|
if (crtc == test_crtc) |
continue; |
|
radeon_test_crtc = to_radeon_crtc(test_crtc); |
if ((radeon_test_crtc->pll_id >= ATOM_PPLL1) && |
(radeon_test_crtc->pll_id <= ATOM_PPLL2)) |
pll_in_use |= (1 << radeon_test_crtc->pll_id); |
} |
if (!(pll_in_use & 1)) |
/* all other cases */ |
pll_in_use = radeon_get_pll_use_mask(crtc); |
if (!(pll_in_use & (1 << ATOM_PPLL1))) |
return ATOM_PPLL1; |
if (!(pll_in_use & (1 << ATOM_PPLL2))) |
return ATOM_PPLL2; |
} else |
DRM_ERROR("unable to allocate a PPLL\n"); |
return ATOM_PPLL_INVALID; |
} else { |
/* on pre-R5xx asics, the crtc to pll mapping is hardcoded */ |
return radeon_crtc->crtc_id; |
} |
} |
} |
|
void radeon_atom_disp_eng_pll_init(struct radeon_device *rdev) |
{ |
/* always set DCPLL */ |
if (ASIC_IS_DCE6(rdev)) |
atombios_crtc_set_disp_eng_pll(rdev, rdev->clock.default_dispclk); |
else if (ASIC_IS_DCE4(rdev)) { |
struct radeon_atom_ss ss; |
bool ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &ss, |
ASIC_INTERNAL_SS_ON_DCPLL, |
rdev->clock.default_dispclk); |
if (ss_enabled) |
atombios_crtc_program_ss(rdev, ATOM_DISABLE, ATOM_DCPLL, -1, &ss); |
/* XXX: DCE5, make sure voltage, dispclk is high enough */ |
atombios_crtc_set_disp_eng_pll(rdev, rdev->clock.default_dispclk); |
if (ss_enabled) |
atombios_crtc_program_ss(rdev, ATOM_ENABLE, ATOM_DCPLL, -1, &ss); |
} |
|
} |
|
int atombios_crtc_mode_set(struct drm_crtc *crtc, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode, |
1485,32 → 1756,14 |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct drm_encoder *encoder; |
struct radeon_encoder *radeon_encoder = |
to_radeon_encoder(radeon_crtc->encoder); |
bool is_tvcv = false; |
|
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
/* find tv std */ |
if (encoder->crtc == crtc) { |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
if (radeon_encoder->active_device & |
(ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) |
is_tvcv = true; |
} |
} |
|
/* always set DCPLL */ |
if (ASIC_IS_DCE4(rdev)) { |
struct radeon_atom_ss ss; |
bool ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &ss, |
ASIC_INTERNAL_SS_ON_DCPLL, |
rdev->clock.default_dispclk); |
if (ss_enabled) |
atombios_crtc_program_ss(crtc, ATOM_DISABLE, ATOM_DCPLL, &ss); |
/* XXX: DCE5, make sure voltage, dispclk is high enough */ |
atombios_crtc_set_dcpll(crtc, rdev->clock.default_dispclk); |
if (ss_enabled) |
atombios_crtc_program_ss(crtc, ATOM_ENABLE, ATOM_DCPLL, &ss); |
} |
atombios_crtc_set_pll(crtc, adjusted_mode); |
|
if (ASIC_IS_DCE4(rdev)) |
1533,17 → 1786,37 |
} |
|
static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, |
struct drm_display_mode *mode, |
const struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct drm_encoder *encoder; |
|
/* adjust pm to upcoming mode change */ |
radeon_pm_compute_clocks(rdev); |
|
/* assign the encoder to the radeon crtc to avoid repeated lookups later */ |
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
if (encoder->crtc == crtc) { |
radeon_crtc->encoder = encoder; |
radeon_crtc->connector = radeon_get_connector_for_encoder(encoder); |
break; |
} |
} |
if ((radeon_crtc->encoder == NULL) || (radeon_crtc->connector == NULL)) { |
radeon_crtc->encoder = NULL; |
radeon_crtc->connector = NULL; |
return false; |
} |
if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) |
return false; |
if (!atombios_crtc_prepare_pll(crtc, adjusted_mode)) |
return false; |
/* pick pll */ |
radeon_crtc->pll_id = radeon_atom_pick_pll(crtc); |
/* if we can't get a PPLL for a non-DP encoder, fail */ |
if ((radeon_crtc->pll_id == ATOM_PPLL_INVALID) && |
!ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) |
return false; |
|
return true; |
} |
|
1550,10 → 1823,15 |
static void atombios_crtc_prepare(struct drm_crtc *crtc) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
|
/* pick pll */ |
radeon_crtc->pll_id = radeon_atom_pick_pll(crtc); |
radeon_crtc->in_mode_set = true; |
|
/* disable crtc pair power gating before programming */ |
if (ASIC_IS_DCE6(rdev)) |
atombios_powergate_crtc(crtc, ATOM_DISABLE); |
|
atombios_lock_crtc(crtc, ATOM_ENABLE); |
atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); |
} |
1560,17 → 1838,35 |
|
static void atombios_crtc_commit(struct drm_crtc *crtc) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
|
atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON); |
atombios_lock_crtc(crtc, ATOM_DISABLE); |
radeon_crtc->in_mode_set = false; |
} |
|
static void atombios_crtc_disable(struct drm_crtc *crtc) |
{ |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
struct drm_device *dev = crtc->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_atom_ss ss; |
int i; |
|
atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); |
|
for (i = 0; i < rdev->num_crtc; i++) { |
if (rdev->mode_info.crtcs[i] && |
rdev->mode_info.crtcs[i]->enabled && |
i != radeon_crtc->crtc_id && |
radeon_crtc->pll_id == rdev->mode_info.crtcs[i]->pll_id) { |
/* one other crtc is using this pll don't turn |
* off the pll |
*/ |
goto done; |
} |
} |
|
switch (radeon_crtc->pll_id) { |
case ATOM_PPLL1: |
case ATOM_PPLL2: |
1578,10 → 1874,20 |
atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, |
0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss); |
break; |
case ATOM_PPLL0: |
/* disable the ppll */ |
if (ASIC_IS_DCE61(rdev)) |
atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, |
0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss); |
break; |
default: |
break; |
} |
radeon_crtc->pll_id = -1; |
done: |
radeon_crtc->pll_id = ATOM_PPLL_INVALID; |
radeon_crtc->adjusted_clock = 0; |
radeon_crtc->encoder = NULL; |
radeon_crtc->connector = NULL; |
} |
|
static const struct drm_crtc_helper_funcs atombios_helper_funcs = { |
1630,6 → 1936,9 |
else |
radeon_crtc->crtc_offset = 0; |
} |
radeon_crtc->pll_id = -1; |
radeon_crtc->pll_id = ATOM_PPLL_INVALID; |
radeon_crtc->adjusted_clock = 0; |
radeon_crtc->encoder = NULL; |
radeon_crtc->connector = NULL; |
drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); |
} |