From f92a8b6758bdc0f277c4f42aa7d736a205ac9ded Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 23 Nov 2009 18:40:40 -0500 Subject: [PATCH] drm/radeon/kms: handle dp sinks in atom encoder/transmitter tables Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_dp.c | 69 ++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_encoders.c | 41 +++++++++----- drivers/gpu/drm/radeon/radeon_mode.h | 2 + 3 files changed, 100 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index e761fefaacb1..76eb5c8a7016 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -33,6 +33,75 @@ #define DP_LINK_STATUS_SIZE 6 +/* move these to drm_dp_helper.c/h */ + +static const int dp_clocks[] = { + 54000, // 1 lane, 1.62 Ghz + 90000, // 1 lane, 2.70 Ghz + 108000, // 2 lane, 1.62 Ghz + 180000, // 2 lane, 2.70 Ghz + 216000, // 4 lane, 1.62 Ghz + 360000, // 4 lane, 2.70 Ghz +}; + +static const int num_dp_clocks = sizeof(dp_clocks) / sizeof(int); + +int dp_lanes_for_mode_clock(int max_link_bw, int mode_clock) +{ + int i; + + switch (max_link_bw) { + case DP_LINK_BW_1_62: + default: + for (i = 0; i < num_dp_clocks; i++) { + if (i % 2) + continue; + if (dp_clocks[i] > mode_clock) { + if (i < 2) + return 1; + else if (i < 4) + return 2; + else + return 4; + } + } + break; + case DP_LINK_BW_2_7: + for (i = 0; i < num_dp_clocks; i++) { + if (dp_clocks[i] > mode_clock) { + if (i < 2) + return 1; + else if (i < 4) + return 2; + else + return 4; + } + } + break; + } + + return 0; +} + +int dp_link_clock_for_mode_clock(int max_link_bw, int mode_clock) +{ + int i; + + switch (max_link_bw) { + case DP_LINK_BW_1_62: + default: + return 162000; + break; + case DP_LINK_BW_2_7: + for (i = 0; i < num_dp_clocks; i++) { + if (dp_clocks[i] > mode_clock) + return (i % 2) ? 270000 : 162000; + } + } + + return 0; +} + bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes, int num_bytes, u8 *read_byte, u8 read_buf_len, u8 delay) diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index b4e7abadbfb2..8f3d67b6032c 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -554,6 +554,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) { 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) @@ -583,10 +584,10 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) return ATOM_ENCODER_MODE_LVDS; break; case DRM_MODE_CONNECTOR_DisplayPort: - /*if (radeon_output->MonType == MT_DP) - return ATOM_ENCODER_MODE_DP; - else*/ - if (drm_detect_hdmi_monitor(radeon_connector->edid)) + 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)) return ATOM_ENCODER_MODE_HDMI; else return ATOM_ENCODER_MODE_DVI; @@ -715,7 +716,15 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action) } } - if (radeon_encoder->pixel_clock > 165000) + args.ucEncoderMode = atombios_get_encoder_mode(encoder); + + if (args.ucEncoderMode == ATOM_ENCODER_MODE_DP) { + if (dp_link_clock_for_mode_clock(dig_connector->dpcd[1], + radeon_encoder->pixel_clock) == 270000) + args.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; + args.ucLaneNum = dp_lanes_for_mode_clock(dig_connector->dpcd[1], + radeon_encoder->pixel_clock); + } else if (radeon_encoder->pixel_clock > 165000) args.ucLaneNum = 8; else args.ucLaneNum = 4; @@ -725,8 +734,6 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action) else args.ucConfig |= ATOM_ENCODER_CONFIG_LINKA; - args.ucEncoderMode = atombios_get_encoder_mode(encoder); - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } @@ -749,6 +756,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t 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) @@ -766,6 +774,9 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t 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)) @@ -790,14 +801,16 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t 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(dp_link_clock_for_mode_clock(dig_connector->dpcd[1], + radeon_encoder->pixel_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) @@ -818,7 +831,9 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t 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; } @@ -866,7 +881,9 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t else 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; } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 338d0af18510..b516401c151a 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -366,6 +366,8 @@ struct radeon_framebuffer { struct drm_gem_object *obj; }; +extern int dp_lanes_for_mode_clock(int max_link_bw, int mode_clock); +extern int dp_link_clock_for_mode_clock(int max_link_bw, int mode_clock); extern u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector); extern void radeon_dp_getdpcd(struct radeon_connector *radeon_connector); extern int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,