27,6 → 27,7 |
#include <drm/drm_crtc_helper.h> |
#include <drm/radeon_drm.h> |
#include "radeon.h" |
#include "radeon_audio.h" |
#include "atom.h" |
#include <linux/backlight.h> |
|
236,6 → 237,7 |
backlight_update_status(bd); |
|
DRM_INFO("radeon atom DIG backlight initialized\n"); |
rdev->mode_info.bl_encoder = radeon_encoder; |
|
return; |
|
309,7 → 311,7 |
adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2; |
|
/* get the native mode for scaling */ |
if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT|ATOM_DEVICE_DFP_SUPPORT)) { |
if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) { |
radeon_panel_mode_fixup(encoder, adjusted_mode); |
} else if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) { |
struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv; |
664,11 → 666,21 |
int |
atombios_get_encoder_mode(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_connector *connector; |
struct radeon_connector *radeon_connector; |
struct radeon_connector_atom_dig *dig_connector; |
struct radeon_encoder_atom_dig *dig_enc; |
|
if (radeon_encoder_is_digital(encoder)) { |
dig_enc = radeon_encoder->enc_priv; |
if (dig_enc->active_mst_links) |
return ATOM_ENCODER_MODE_DP_MST; |
} |
if (radeon_encoder->is_mst_encoder || radeon_encoder->offset) |
return ATOM_ENCODER_MODE_DP_MST; |
/* dp bridges are always DP */ |
if (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE) |
return ATOM_ENCODER_MODE_DP; |
728,6 → 740,10 |
dig_connector = radeon_connector->con_priv; |
if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || |
(dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) { |
if (radeon_audio != 0 && |
drm_detect_monitor_audio(radeon_connector_edid(connector)) && |
ASIC_IS_DCE4(rdev) && !ASIC_IS_DCE5(rdev)) |
return ATOM_ENCODER_MODE_DP_AUDIO; |
return ATOM_ENCODER_MODE_DP; |
} else if (radeon_audio != 0) { |
if (radeon_connector->audio == RADEON_AUDIO_ENABLE) |
742,6 → 758,10 |
} |
break; |
case DRM_MODE_CONNECTOR_eDP: |
if (radeon_audio != 0 && |
drm_detect_monitor_audio(radeon_connector_edid(connector)) && |
ASIC_IS_DCE4(rdev) && !ASIC_IS_DCE5(rdev)) |
return ATOM_ENCODER_MODE_DP_AUDIO; |
return ATOM_ENCODER_MODE_DP; |
case DRM_MODE_CONNECTOR_DVIA: |
case DRM_MODE_CONNECTOR_VGA: |
812,7 → 832,7 |
}; |
|
void |
atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode) |
atombios_dig_encoder_setup2(struct drm_encoder *encoder, int action, int panel_mode, int enc_override) |
{ |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
909,6 → 929,9 |
|
if (ENCODER_MODE_IS_DP(args.v3.ucEncoderMode) && (dp_clock == 270000)) |
args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ; |
if (enc_override != -1) |
args.v3.acConfig.ucDigSel = enc_override; |
else |
args.v3.acConfig.ucDigSel = dig->dig_encoder; |
args.v3.ucBitPerColor = radeon_atom_get_bpc(encoder); |
break; |
937,6 → 960,10 |
else |
args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_1_62GHZ; |
} |
|
if (enc_override != -1) |
args.v4.acConfig.ucDigSel = enc_override; |
else |
args.v4.acConfig.ucDigSel = dig->dig_encoder; |
args.v4.ucBitPerColor = radeon_atom_get_bpc(encoder); |
if (hpd_id == RADEON_HPD_NONE) |
958,6 → 985,12 |
|
} |
|
void |
atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode) |
{ |
atombios_dig_encoder_setup2(encoder, action, panel_mode, -1); |
} |
|
union dig_transmitter_control { |
DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1; |
DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2; |
967,7 → 1000,7 |
}; |
|
void |
atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set) |
atombios_dig_transmitter_setup2(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set, int fe) |
{ |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
1317,7 → 1350,7 |
args.v5.asConfig.ucHPDSel = 0; |
else |
args.v5.asConfig.ucHPDSel = hpd_id + 1; |
args.v5.ucDigEncoderSel = 1 << dig_encoder; |
args.v5.ucDigEncoderSel = (fe != -1) ? (1 << fe) : (1 << dig_encoder); |
args.v5.ucDPLaneSet = lane_set; |
break; |
default: |
1333,6 → 1366,12 |
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
} |
|
void |
atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set) |
{ |
atombios_dig_transmitter_setup2(encoder, action, lane_num, lane_set, -1); |
} |
|
bool |
atombios_set_edp_panel_power(struct drm_connector *connector, int action) |
{ |
1586,9 → 1625,15 |
} else |
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { |
if (rdev->mode_info.bl_encoder) { |
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; |
|
atombios_set_backlight_level(radeon_encoder, dig->backlight_level); |
} else { |
args.ucAction = ATOM_LCD_BLON; |
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
} |
} |
break; |
case DRM_MODE_DPMS_STANDBY: |
case DRM_MODE_DPMS_SUSPEND: |
1667,9 → 1712,13 |
if (ASIC_IS_DCE4(rdev)) |
atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0); |
} |
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) |
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { |
if (rdev->mode_info.bl_encoder) |
atombios_set_backlight_level(radeon_encoder, dig->backlight_level); |
else |
atombios_dig_transmitter_setup(encoder, |
ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0); |
} |
if (ext_encoder) |
atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); |
break; |
1676,6 → 1725,11 |
case DRM_MODE_DPMS_STANDBY: |
case DRM_MODE_DPMS_SUSPEND: |
case DRM_MODE_DPMS_OFF: |
|
/* don't power off encoders with active MST links */ |
if (dig->active_mst_links) |
return; |
|
if (ASIC_IS_DCE4(rdev)) { |
if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) |
atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0); |
1718,10 → 1772,17 |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
int encoder_mode = atombios_get_encoder_mode(encoder); |
|
DRM_DEBUG_KMS("encoder dpms %d to mode %d, devices %08x, active_devices %08x\n", |
radeon_encoder->encoder_id, mode, radeon_encoder->devices, |
radeon_encoder->active_device); |
|
if ((radeon_audio != 0) && |
((encoder_mode == ATOM_ENCODER_MODE_HDMI) || |
ENCODER_MODE_IS_DP(encoder_mode))) |
radeon_audio_dpms(encoder, mode); |
|
switch (radeon_encoder->encoder_id) { |
case ENCODER_OBJECT_ID_INTERNAL_TMDS1: |
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: |
1935,6 → 1996,53 |
radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); |
} |
|
void |
atombios_set_mst_encoder_crtc_source(struct drm_encoder *encoder, int fe) |
{ |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); |
int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source); |
uint8_t frev, crev; |
union crtc_source_param args; |
|
memset(&args, 0, sizeof(args)); |
|
if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) |
return; |
|
if (frev != 1 && crev != 2) |
DRM_ERROR("Unknown table for MST %d, %d\n", frev, crev); |
|
args.v2.ucCRTC = radeon_crtc->crtc_id; |
args.v2.ucEncodeMode = ATOM_ENCODER_MODE_DP_MST; |
|
switch (fe) { |
case 0: |
args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; |
break; |
case 1: |
args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; |
break; |
case 2: |
args.v2.ucEncoderID = ASIC_INT_DIG3_ENCODER_ID; |
break; |
case 3: |
args.v2.ucEncoderID = ASIC_INT_DIG4_ENCODER_ID; |
break; |
case 4: |
args.v2.ucEncoderID = ASIC_INT_DIG5_ENCODER_ID; |
break; |
case 5: |
args.v2.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID; |
break; |
case 6: |
args.v2.ucEncoderID = ASIC_INT_DIG7_ENCODER_ID; |
break; |
} |
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
} |
|
static void |
atombios_apply_encoder_quirks(struct drm_encoder *encoder, |
struct drm_display_mode *mode) |
1983,8 → 2091,15 |
} |
} |
|
static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder) |
void radeon_atom_release_dig_encoder(struct radeon_device *rdev, int enc_idx) |
{ |
if (enc_idx < 0) |
return; |
rdev->mode_info.active_encoders &= ~(1 << enc_idx); |
} |
|
int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder, int fe_idx) |
{ |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); |
1992,32 → 2107,38 |
struct drm_encoder *test_encoder; |
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; |
uint32_t dig_enc_in_use = 0; |
int enc_idx = -1; |
|
if (fe_idx >= 0) { |
enc_idx = fe_idx; |
goto assigned; |
} |
if (ASIC_IS_DCE6(rdev)) { |
/* DCE6 */ |
switch (radeon_encoder->encoder_id) { |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: |
if (dig->linkb) |
return 1; |
enc_idx = 1; |
else |
return 0; |
enc_idx = 0; |
break; |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: |
if (dig->linkb) |
return 3; |
enc_idx = 3; |
else |
return 2; |
enc_idx = 2; |
break; |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: |
if (dig->linkb) |
return 5; |
enc_idx = 5; |
else |
return 4; |
enc_idx = 4; |
break; |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: |
return 6; |
enc_idx = 6; |
break; |
} |
goto assigned; |
} else if (ASIC_IS_DCE4(rdev)) { |
/* DCE4/5 */ |
if (ASIC_IS_DCE41(rdev) && !ASIC_IS_DCE61(rdev)) { |
2024,39 → 2145,41 |
/* ontario follows DCE4 */ |
if (rdev->family == CHIP_PALM) { |
if (dig->linkb) |
return 1; |
enc_idx = 1; |
else |
return 0; |
enc_idx = 0; |
} else |
/* llano follows DCE3.2 */ |
return radeon_crtc->crtc_id; |
enc_idx = radeon_crtc->crtc_id; |
} else { |
switch (radeon_encoder->encoder_id) { |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: |
if (dig->linkb) |
return 1; |
enc_idx = 1; |
else |
return 0; |
enc_idx = 0; |
break; |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: |
if (dig->linkb) |
return 3; |
enc_idx = 3; |
else |
return 2; |
enc_idx = 2; |
break; |
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: |
if (dig->linkb) |
return 5; |
enc_idx = 5; |
else |
return 4; |
enc_idx = 4; |
break; |
} |
} |
goto assigned; |
} |
|
/* on DCE32 and encoder can driver any block so just crtc id */ |
if (ASIC_IS_DCE32(rdev)) { |
return radeon_crtc->crtc_id; |
enc_idx = radeon_crtc->crtc_id; |
goto assigned; |
} |
|
/* on DCE3 - LVTMA can only be driven by DIGB */ |
2084,7 → 2207,18 |
if (!(dig_enc_in_use & 1)) |
return 0; |
return 1; |
|
assigned: |
if (enc_idx == -1) { |
DRM_ERROR("Got encoder index incorrect - returning 0\n"); |
return 0; |
} |
if (rdev->mode_info.active_encoders & (1 << enc_idx)) { |
DRM_ERROR("chosen encoder in use %d\n", enc_idx); |
} |
rdev->mode_info.active_encoders |= (1 << enc_idx); |
return enc_idx; |
} |
|
/* This only needs to be called once at startup */ |
void |
2123,6 → 2257,8 |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); |
int encoder_mode; |
|
radeon_encoder->pixel_clock = adjusted_mode->clock; |
|
2171,13 → 2307,12 |
|
atombios_apply_encoder_quirks(encoder, adjusted_mode); |
|
if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) { |
if (rdev->asic->display.hdmi_enable) |
radeon_hdmi_enable(rdev, encoder, true); |
if (rdev->asic->display.hdmi_setmode) |
radeon_hdmi_setmode(rdev, encoder, adjusted_mode); |
encoder_mode = atombios_get_encoder_mode(encoder); |
if (connector && (radeon_audio != 0) && |
((encoder_mode == ATOM_ENCODER_MODE_HDMI) || |
ENCODER_MODE_IS_DP(encoder_mode))) |
radeon_audio_mode_set(encoder, adjusted_mode); |
} |
} |
|
static bool |
atombios_dac_load_detect(struct drm_encoder *encoder, struct drm_connector *connector) |
2340,7 → 2475,9 |
ENCODER_OBJECT_ID_NONE)) { |
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; |
if (dig) { |
dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder); |
if (dig->dig_encoder >= 0) |
radeon_atom_release_dig_encoder(rdev, dig->dig_encoder); |
dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder, -1); |
if (radeon_encoder->active_device & ATOM_DEVICE_DFP_SUPPORT) { |
if (rdev->family >= CHIP_R600) |
dig->afmt = rdev->mode_info.afmt[dig->dig_encoder]; |
2446,9 → 2583,13 |
if (rdev->asic->display.hdmi_enable) |
radeon_hdmi_enable(rdev, encoder, false); |
} |
if (atombios_get_encoder_mode(encoder) != ATOM_ENCODER_MODE_DP_MST) { |
dig = radeon_encoder->enc_priv; |
radeon_atom_release_dig_encoder(rdev, dig->dig_encoder); |
dig->dig_encoder = -1; |
radeon_encoder->active_device = 0; |
} |
} else |
radeon_encoder->active_device = 0; |
} |
|