156,6 → 156,26 |
return ret; |
} |
|
static inline bool radeon_encoder_is_digital(struct drm_encoder *encoder) |
{ |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
switch (radeon_encoder->encoder_id) { |
case ENCODER_OBJECT_ID_INTERNAL_LVDS: |
case ENCODER_OBJECT_ID_INTERNAL_TMDS1: |
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: |
case ENCODER_OBJECT_ID_INTERNAL_LVTM1: |
case ENCODER_OBJECT_ID_INTERNAL_DVO1: |
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: |
case ENCODER_OBJECT_ID_INTERNAL_DDI: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: |
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: |
return true; |
default: |
return false; |
} |
} |
void |
radeon_link_encoder_connector(struct drm_device *dev) |
{ |
202,7 → 222,7 |
|
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
radeon_connector = to_radeon_connector(connector); |
if (radeon_encoder->devices & radeon_connector->devices) |
if (radeon_encoder->active_device & radeon_connector->devices) |
return connector; |
} |
return NULL; |
233,6 → 253,8 |
if (!ASIC_IS_AVIVO(rdev)) { |
adjusted_mode->hdisplay = mode->hdisplay; |
adjusted_mode->vdisplay = mode->vdisplay; |
adjusted_mode->crtc_hdisplay = mode->hdisplay; |
adjusted_mode->crtc_vdisplay = mode->vdisplay; |
} |
adjusted_mode->base.id = mode_id; |
} |
438,6 → 460,7 |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
union lvds_encoder_control args; |
int index = 0; |
int hdmi_detected = 0; |
uint8_t frev, crev; |
struct radeon_encoder_atom_dig *dig; |
struct drm_connector *connector; |
458,6 → 481,9 |
if (!radeon_connector->con_priv) |
return; |
|
if (drm_detect_hdmi_monitor(radeon_connector->edid)) |
hdmi_detected = 1; |
|
dig_connector = radeon_connector->con_priv; |
|
memset(&args, 0, sizeof(args)); |
487,13 → 513,13 |
case 1: |
args.v1.ucMisc = 0; |
args.v1.ucAction = action; |
if (drm_detect_hdmi_monitor(radeon_connector->edid)) |
if (hdmi_detected) |
args.v1.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; |
args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); |
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { |
if (dig->lvds_misc & (1 << 0)) |
if (dig->lvds_misc & ATOM_PANEL_MISC_DUAL) |
args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; |
if (dig->lvds_misc & (1 << 1)) |
if (dig->lvds_misc & ATOM_PANEL_MISC_888RGB) |
args.v1.ucMisc |= (1 << 1); |
} else { |
if (dig_connector->linkb) |
512,7 → 538,7 |
if (dig->coherent_mode) |
args.v2.ucMisc |= PANEL_ENCODER_MISC_COHERENT; |
} |
if (drm_detect_hdmi_monitor(radeon_connector->edid)) |
if (hdmi_detected) |
args.v2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; |
args.v2.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); |
args.v2.ucTruncate = 0; |
520,18 → 546,18 |
args.v2.ucTemporal = 0; |
args.v2.ucFRC = 0; |
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { |
if (dig->lvds_misc & (1 << 0)) |
if (dig->lvds_misc & ATOM_PANEL_MISC_DUAL) |
args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL; |
if (dig->lvds_misc & (1 << 5)) { |
if (dig->lvds_misc & ATOM_PANEL_MISC_SPATIAL) { |
args.v2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN; |
if (dig->lvds_misc & (1 << 1)) |
if (dig->lvds_misc & ATOM_PANEL_MISC_888RGB) |
args.v2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH; |
} |
if (dig->lvds_misc & (1 << 6)) { |
if (dig->lvds_misc & ATOM_PANEL_MISC_TEMPORAL) { |
args.v2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN; |
if (dig->lvds_misc & (1 << 1)) |
if (dig->lvds_misc & ATOM_PANEL_MISC_888RGB) |
args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH; |
if (((dig->lvds_misc >> 2) & 0x3) == 2) |
if (((dig->lvds_misc >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT) & 0x3) == 2) |
args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4; |
} |
} else { |
552,7 → 578,7 |
} |
|
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
|
r600_hdmi_enable(encoder, hdmi_detected); |
} |
|
int |
590,8 → 616,10 |
return ATOM_ENCODER_MODE_LVDS; |
break; |
case DRM_MODE_CONNECTOR_DisplayPort: |
case DRM_MODE_CONNECTOR_eDP: |
radeon_dig_connector = radeon_connector->con_priv; |
if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) |
if ((radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || |
(radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) |
return ATOM_ENCODER_MODE_DP; |
else if (drm_detect_hdmi_monitor(radeon_connector->edid)) |
return ATOM_ENCODER_MODE_HDMI; |
598,13 → 626,13 |
else |
return ATOM_ENCODER_MODE_DVI; |
break; |
case CONNECTOR_DVI_A: |
case CONNECTOR_VGA: |
case DRM_MODE_CONNECTOR_DVIA: |
case DRM_MODE_CONNECTOR_VGA: |
return ATOM_ENCODER_MODE_CRT; |
break; |
case CONNECTOR_STV: |
case CONNECTOR_CTV: |
case CONNECTOR_DIN: |
case DRM_MODE_CONNECTOR_Composite: |
case DRM_MODE_CONNECTOR_SVIDEO: |
case DRM_MODE_CONNECTOR_9PinDIN: |
/* fix me */ |
return ATOM_ENCODER_MODE_TV; |
/*return ATOM_ENCODER_MODE_CV;*/ |
668,31 → 696,11 |
|
memset(&args, 0, sizeof(args)); |
|
if (ASIC_IS_DCE32(rdev)) { |
if (dig->dig_block) |
if (dig->dig_encoder) |
index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); |
else |
index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); |
num = dig->dig_block + 1; |
} 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; |
} |
} |
num = dig->dig_encoder + 1; |
|
atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev); |
|
814,7 → 822,7 |
args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); |
} |
if (ASIC_IS_DCE32(rdev)) { |
if (dig->dig_block) |
if (dig->dig_encoder == 1) |
args.v2.acConfig.ucEncoderSel = 1; |
if (dig_connector->linkb) |
args.v2.acConfig.ucLinkSel = 1; |
841,17 → 849,16 |
args.v2.acConfig.fCoherentMode = 1; |
} |
} else { |
|
args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL; |
|
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) |
if (dig->dig_encoder) |
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER; |
else |
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER; |
|
switch (radeon_encoder->encoder_id) { |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: |
if (rdev->flags & RADEON_IS_IGP) { |
if (radeon_encoder->pixel_clock > 165000) { |
if (dig_connector->igp_lane_info & 0x3) |
870,10 → 877,6 |
} |
} |
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) |
893,7 → 896,6 |
} |
|
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
|
} |
|
static void |
1039,6 → 1041,7 |
union crtc_sourc_param args; |
int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source); |
uint8_t frev, crev; |
struct radeon_encoder_atom_dig *dig; |
|
memset(&args, 0, sizeof(args)); |
|
1102,40 → 1105,16 |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: |
if (ASIC_IS_DCE32(rdev)) { |
if (radeon_crtc->crtc_id) |
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: |
dig = radeon_encoder->enc_priv; |
if (dig->dig_encoder) |
args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; |
else |
args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; |
} 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: |
if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) |
args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; |
1162,7 → 1141,6 |
} |
|
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
|
} |
|
static void |
1196,6 → 1174,47 |
} |
} |
|
static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder) |
{ |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
struct drm_encoder *test_encoder; |
struct radeon_encoder_atom_dig *dig; |
uint32_t dig_enc_in_use = 0; |
/* on DCE32 and encoder can driver any block so just crtc id */ |
if (ASIC_IS_DCE32(rdev)) { |
return radeon_crtc->crtc_id; |
} |
|
/* on DCE3 - LVTMA can only be driven by DIGB */ |
list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { |
struct radeon_encoder *radeon_test_encoder; |
|
if (encoder == test_encoder) |
continue; |
|
if (!radeon_encoder_is_digital(test_encoder)) |
continue; |
|
radeon_test_encoder = to_radeon_encoder(test_encoder); |
dig = radeon_test_encoder->enc_priv; |
|
if (dig->dig_encoder >= 0) |
dig_enc_in_use |= (1 << dig->dig_encoder); |
} |
|
if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA) { |
if (dig_enc_in_use & 0x2) |
DRM_ERROR("LVDS required digital encoder 2 but it was in use - stealing\n"); |
return 1; |
} |
if (!(dig_enc_in_use & 1)) |
return 0; |
return 1; |
} |
|
static void |
radeon_atom_encoder_mode_set(struct drm_encoder *encoder, |
struct drm_display_mode *mode, |
1208,13 → 1227,10 |
|
if (radeon_encoder->active_device & |
(ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) { |
if (radeon_encoder->enc_priv) { |
struct radeon_encoder_atom_dig *dig; |
|
dig = radeon_encoder->enc_priv; |
dig->dig_block = radeon_crtc->crtc_id; |
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; |
if (dig) |
dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder); |
} |
} |
radeon_encoder->pixel_clock = adjusted_mode->clock; |
|
radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); |
1265,6 → 1281,8 |
break; |
} |
atombios_apply_encoder_quirks(encoder, adjusted_mode); |
|
r600_hdmi_setmode(encoder, adjusted_mode); |
} |
|
static bool |
1371,7 → 1389,13 |
static void radeon_atom_encoder_disable(struct drm_encoder *encoder) |
{ |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
struct radeon_encoder_atom_dig *dig; |
radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); |
|
if (radeon_encoder_is_digital(encoder)) { |
dig = radeon_encoder->enc_priv; |
dig->dig_encoder = -1; |
} |
radeon_encoder->active_device = 0; |
} |
|
1428,6 → 1452,7 |
|
/* coherent mode by default */ |
dig->coherent_mode = true; |
dig->dig_encoder = -1; |
|
return dig; |
} |
1510,4 → 1535,6 |
drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); |
break; |
} |
|
r600_hdmi_init(encoder); |
} |