35,6 → 35,51 |
bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index, |
struct drm_display_mode *mode); |
|
static uint32_t radeon_encoder_clones(struct drm_encoder *encoder) |
{ |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
struct drm_encoder *clone_encoder; |
uint32_t index_mask = 0; |
int count; |
|
/* DIG routing gets problematic */ |
if (rdev->family >= CHIP_R600) |
return index_mask; |
/* LVDS/TV are too wacky */ |
if (radeon_encoder->devices & ATOM_DEVICE_LCD_SUPPORT) |
return index_mask; |
/* DVO requires 2x ppll clocks depending on tmds chip */ |
if (radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) |
return index_mask; |
|
count = -1; |
list_for_each_entry(clone_encoder, &dev->mode_config.encoder_list, head) { |
struct radeon_encoder *radeon_clone = to_radeon_encoder(clone_encoder); |
count++; |
|
if (clone_encoder == encoder) |
continue; |
if (radeon_clone->devices & (ATOM_DEVICE_LCD_SUPPORT)) |
continue; |
if (radeon_clone->devices & ATOM_DEVICE_DFP2_SUPPORT) |
continue; |
else |
index_mask |= (1 << count); |
} |
return index_mask; |
} |
|
void radeon_setup_encoder_clones(struct drm_device *dev) |
{ |
struct drm_encoder *encoder; |
|
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
encoder->possible_clones = radeon_encoder_clones(encoder); |
} |
} |
|
uint32_t |
radeon_get_encoder_id(struct drm_device *dev, uint32_t supported_device, uint8_t dac) |
{ |
163,29 → 208,6 |
return NULL; |
} |
|
/* used for both atom and legacy */ |
void radeon_rmx_mode_fixup(struct drm_encoder *encoder, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
{ |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct drm_display_mode *native_mode = &radeon_encoder->native_mode; |
|
if (mode->hdisplay < native_mode->hdisplay || |
mode->vdisplay < native_mode->vdisplay) { |
int mode_id = adjusted_mode->base.id; |
*adjusted_mode = *native_mode; |
if (!ASIC_IS_AVIVO(rdev)) { |
adjusted_mode->hdisplay = mode->hdisplay; |
adjusted_mode->vdisplay = mode->vdisplay; |
} |
adjusted_mode->base.id = mode_id; |
} |
} |
|
|
static bool radeon_atom_mode_fixup(struct drm_encoder *encoder, |
struct drm_display_mode *mode, |
struct drm_display_mode *adjusted_mode) |
198,14 → 220,24 |
radeon_encoder_set_active_device(encoder); |
drm_mode_set_crtcinfo(adjusted_mode, 0); |
|
if (radeon_encoder->rmx_type != RMX_OFF) |
radeon_rmx_mode_fixup(encoder, mode, adjusted_mode); |
|
/* hw bug */ |
if ((mode->flags & DRM_MODE_FLAG_INTERLACE) |
&& (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2))) |
adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2; |
|
/* get the native mode for LVDS */ |
if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) { |
struct drm_display_mode *native_mode = &radeon_encoder->native_mode; |
int mode_id = adjusted_mode->base.id; |
*adjusted_mode = *native_mode; |
if (!ASIC_IS_AVIVO(rdev)) { |
adjusted_mode->hdisplay = mode->hdisplay; |
adjusted_mode->vdisplay = mode->vdisplay; |
} |
adjusted_mode->base.id = mode_id; |
} |
|
/* get the native mode for TV */ |
if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) { |
struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv; |
if (tv_dac) { |
218,6 → 250,12 |
} |
} |
|
if (ASIC_IS_DCE3(rdev) && |
(radeon_encoder->active_device & (ATOM_DEVICE_DFP_SUPPORT))) { |
struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); |
radeon_dp_set_link_config(connector, mode); |
} |
|
return true; |
} |
|
392,7 → 430,7 |
LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 v2; |
}; |
|
static void |
void |
atombios_digital_setup(struct drm_encoder *encoder, int action) |
{ |
struct drm_device *dev = encoder->dev; |
522,6 → 560,7 |
{ |
struct drm_connector *connector; |
struct radeon_connector *radeon_connector; |
struct radeon_connector_atom_dig *radeon_dig_connector; |
|
connector = radeon_get_connector_for_encoder(encoder); |
if (!connector) |
551,10 → 590,10 |
return ATOM_ENCODER_MODE_LVDS; |
break; |
case DRM_MODE_CONNECTOR_DisplayPort: |
/*if (radeon_output->MonType == MT_DP) |
radeon_dig_connector = radeon_connector->con_priv; |
if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) |
return ATOM_ENCODER_MODE_DP; |
else*/ |
if (drm_detect_hdmi_monitor(radeon_connector->edid)) |
else if (drm_detect_hdmi_monitor(radeon_connector->edid)) |
return ATOM_ENCODER_MODE_HDMI; |
else |
return ATOM_ENCODER_MODE_DVI; |
573,6 → 612,30 |
} |
} |
|
/* |
* DIG Encoder/Transmitter Setup |
* |
* DCE 3.0/3.1 |
* - 2 DIG transmitter blocks. UNIPHY (links A and B) and LVTMA. |
* Supports up to 3 digital outputs |
* - 2 DIG encoder blocks. |
* DIG1 can drive UNIPHY link A or link B |
* DIG2 can drive UNIPHY link B or LVTMA |
* |
* DCE 3.2 |
* - 3 DIG transmitter blocks. UNIPHY0/1/2 (links A and B). |
* Supports up to 5 digital outputs |
* - 2 DIG encoder blocks. |
* DIG1/2 can drive UNIPHY0/1/2 link A or link B |
* |
* Routing |
* crtc -> dig encoder -> UNIPHY/LVTMA (1 or 2 links) |
* Examples: |
* crtc0 -> dig2 -> LVTMA links A+B -> TMDS/HDMI |
* crtc1 -> dig1 -> UNIPHY0 link B -> DP |
* crtc0 -> dig1 -> UNIPHY2 link A -> LVDS |
* crtc1 -> dig2 -> UNIPHY1 link B+A -> TMDS/HDMI |
*/ |
static void |
atombios_dig_encoder_setup(struct drm_encoder *encoder, int action) |
{ |
614,10 → 677,17 |
} else { |
switch (radeon_encoder->encoder_id) { |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: |
/* XXX doesn't really matter which dig encoder we pick as long as it's |
* not already in use |
*/ |
if (dig_connector->linkb) |
index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); |
else |
index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); |
num = 1; |
break; |
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: |
/* Only dig2 encoder can drive LVTMA */ |
index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); |
num = 2; |
break; |
652,19 → 722,22 |
} |
} |
|
if (radeon_encoder->pixel_clock > 165000) { |
args.ucConfig |= ATOM_ENCODER_CONFIG_LINKA_B; |
args.ucEncoderMode = atombios_get_encoder_mode(encoder); |
|
if (args.ucEncoderMode == ATOM_ENCODER_MODE_DP) { |
if (dig_connector->dp_clock == 270000) |
args.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; |
args.ucLaneNum = dig_connector->dp_lane_count; |
} else if (radeon_encoder->pixel_clock > 165000) |
args.ucLaneNum = 8; |
} else { |
else |
args.ucLaneNum = 4; |
|
if (dig_connector->linkb) |
args.ucConfig |= ATOM_ENCODER_CONFIG_LINKB; |
else |
args.ucConfig |= ATOM_ENCODER_CONFIG_LINKA; |
args.ucLaneNum = 4; |
} |
|
args.ucEncoderMode = atombios_get_encoder_mode(encoder); |
|
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
|
} |
674,8 → 747,8 |
DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2; |
}; |
|
static void |
atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action) |
void |
atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set) |
{ |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
687,6 → 760,7 |
struct drm_connector *connector; |
struct radeon_connector *radeon_connector; |
struct radeon_connector_atom_dig *dig_connector; |
bool is_dp = false; |
|
connector = radeon_get_connector_for_encoder(encoder); |
if (!connector) |
704,6 → 778,9 |
|
dig_connector = radeon_connector->con_priv; |
|
if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) |
is_dp = true; |
|
memset(&args, 0, sizeof(args)); |
|
if (ASIC_IS_DCE32(rdev)) |
724,17 → 801,23 |
args.v1.ucAction = action; |
if (action == ATOM_TRANSMITTER_ACTION_INIT) { |
args.v1.usInitInfo = radeon_connector->connector_object_id; |
} else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { |
args.v1.asMode.ucLaneSel = lane_num; |
args.v1.asMode.ucLaneSet = lane_set; |
} else { |
if (radeon_encoder->pixel_clock > 165000) |
if (is_dp) |
args.v1.usPixelClock = |
cpu_to_le16(dig_connector->dp_clock / 10); |
else if (radeon_encoder->pixel_clock > 165000) |
args.v1.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); |
else |
args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); |
} |
if (ASIC_IS_DCE32(rdev)) { |
if (radeon_encoder->pixel_clock > 165000) |
args.v2.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); |
if (dig->dig_block) |
args.v2.acConfig.ucEncoderSel = 1; |
if (dig_connector->linkb) |
args.v2.acConfig.ucLinkSel = 1; |
|
switch (radeon_encoder->encoder_id) { |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: |
751,7 → 834,9 |
break; |
} |
|
if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { |
if (is_dp) |
args.v2.acConfig.fCoherentMode = 1; |
else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { |
if (dig->coherent_mode) |
args.v2.acConfig.fCoherentMode = 1; |
} |
760,17 → 845,20 |
|
switch (radeon_encoder->encoder_id) { |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: |
/* XXX doesn't really matter which dig encoder we pick as long as it's |
* not already in use |
*/ |
if (dig_connector->linkb) |
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER; |
else |
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER; |
if (rdev->flags & RADEON_IS_IGP) { |
if (radeon_encoder->pixel_clock > 165000) { |
args.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK | |
ATOM_TRANSMITTER_CONFIG_LINKA_B); |
if (dig_connector->igp_lane_info & 0x3) |
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7; |
else if (dig_connector->igp_lane_info & 0xc) |
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15; |
} else { |
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA; |
if (dig_connector->igp_lane_info & 0x1) |
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3; |
else if (dig_connector->igp_lane_info & 0x2) |
780,35 → 868,25 |
else if (dig_connector->igp_lane_info & 0x8) |
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15; |
} |
} else { |
if (radeon_encoder->pixel_clock > 165000) |
args.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK | |
ATOM_TRANSMITTER_CONFIG_LINKA_B | |
ATOM_TRANSMITTER_CONFIG_LANE_0_7); |
else { |
if (dig_connector->linkb) |
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB | ATOM_TRANSMITTER_CONFIG_LANE_0_3; |
else |
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA | ATOM_TRANSMITTER_CONFIG_LANE_0_3; |
} |
} |
break; |
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: |
/* Only dig2 encoder can drive LVTMA */ |
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER; |
break; |
} |
|
if (radeon_encoder->pixel_clock > 165000) |
args.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK | |
ATOM_TRANSMITTER_CONFIG_LINKA_B | |
ATOM_TRANSMITTER_CONFIG_LANE_0_7); |
else { |
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_8LANE_LINK; |
|
if (dig_connector->linkb) |
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB | ATOM_TRANSMITTER_CONFIG_LANE_0_3; |
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB; |
else |
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA | ATOM_TRANSMITTER_CONFIG_LANE_0_3; |
} |
break; |
} |
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA; |
|
if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { |
if (is_dp) |
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; |
else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { |
if (dig->coherent_mode) |
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; |
} |
918,12 → 996,16 |
if (is_dig) { |
switch (mode) { |
case DRM_MODE_DPMS_ON: |
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE); |
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0); |
{ |
struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); |
dp_link_train(encoder, connector); |
} |
break; |
case DRM_MODE_DPMS_STANDBY: |
case DRM_MODE_DPMS_SUSPEND: |
case DRM_MODE_DPMS_OFF: |
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE); |
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0); |
break; |
} |
} else { |
1025,13 → 1107,33 |
args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; |
else |
args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; |
} else |
} else { |
struct drm_connector *connector; |
struct radeon_connector *radeon_connector; |
struct radeon_connector_atom_dig *dig_connector; |
|
connector = radeon_get_connector_for_encoder(encoder); |
if (!connector) |
return; |
radeon_connector = to_radeon_connector(connector); |
if (!radeon_connector->con_priv) |
return; |
dig_connector = radeon_connector->con_priv; |
|
/* XXX doesn't really matter which dig encoder we pick as long as it's |
* not already in use |
*/ |
if (dig_connector->linkb) |
args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; |
else |
args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; |
} |
break; |
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: |
args.v2.ucEncoderID = ASIC_INT_DVO_ENCODER_ID; |
break; |
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: |
/* Only dig2 encoder can drive LVTMA */ |
args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; |
break; |
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: |
1104,6 → 1206,8 |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); |
|
if (radeon_encoder->active_device & |
(ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) { |
if (radeon_encoder->enc_priv) { |
struct radeon_encoder_atom_dig *dig; |
|
1110,6 → 1214,7 |
dig = radeon_encoder->enc_priv; |
dig->dig_block = radeon_crtc->crtc_id; |
} |
} |
radeon_encoder->pixel_clock = adjusted_mode->clock; |
|
radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); |
1134,14 → 1239,14 |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: |
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: |
/* disable the encoder and transmitter */ |
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE); |
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); |
atombios_dig_encoder_setup(encoder, ATOM_DISABLE); |
|
/* setup and enable the encoder and transmitter */ |
atombios_dig_encoder_setup(encoder, ATOM_ENABLE); |
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT); |
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP); |
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE); |
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0); |
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0); |
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); |
break; |
case ENCODER_OBJECT_ID_INTERNAL_DDI: |
atombios_ddia_setup(encoder, ATOM_ENABLE); |
1354,7 → 1459,6 |
encoder->possible_crtcs = 0x1; |
else |
encoder->possible_crtcs = 0x3; |
encoder->possible_clones = 0; |
|
radeon_encoder->enc_priv = NULL; |
|