Path: blob/master/drivers/gpu/drm/radeon/atombios_dp.c
15113 views
/*1* Copyright 2007-8 Advanced Micro Devices, Inc.2* Copyright 2008 Red Hat Inc.3*4* Permission is hereby granted, free of charge, to any person obtaining a5* copy of this software and associated documentation files (the "Software"),6* to deal in the Software without restriction, including without limitation7* the rights to use, copy, modify, merge, publish, distribute, sublicense,8* and/or sell copies of the Software, and to permit persons to whom the9* Software is furnished to do so, subject to the following conditions:10*11* The above copyright notice and this permission notice shall be included in12* all copies or substantial portions of the Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR18* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,19* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR20* OTHER DEALINGS IN THE SOFTWARE.21*22* Authors: Dave Airlie23* Alex Deucher24*/25#include "drmP.h"26#include "radeon_drm.h"27#include "radeon.h"2829#include "atom.h"30#include "atom-bits.h"31#include "drm_dp_helper.h"3233/* move these to drm_dp_helper.c/h */34#define DP_LINK_CONFIGURATION_SIZE 935#define DP_LINK_STATUS_SIZE 636#define DP_DPCD_SIZE 83738static char *voltage_names[] = {39"0.4V", "0.6V", "0.8V", "1.2V"40};41static char *pre_emph_names[] = {42"0dB", "3.5dB", "6dB", "9.5dB"43};4445/***** radeon AUX functions *****/46union aux_channel_transaction {47PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1;48PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2;49};5051static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,52u8 *send, int send_bytes,53u8 *recv, int recv_size,54u8 delay, u8 *ack)55{56struct drm_device *dev = chan->dev;57struct radeon_device *rdev = dev->dev_private;58union aux_channel_transaction args;59int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction);60unsigned char *base;61int recv_bytes;6263memset(&args, 0, sizeof(args));6465base = (unsigned char *)rdev->mode_info.atom_context->scratch;6667memcpy(base, send, send_bytes);6869args.v1.lpAuxRequest = 0;70args.v1.lpDataOut = 16;71args.v1.ucDataOutLen = 0;72args.v1.ucChannelID = chan->rec.i2c_id;73args.v1.ucDelay = delay / 10;74if (ASIC_IS_DCE4(rdev))75args.v2.ucHPD_ID = chan->rec.hpd;7677atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);7879*ack = args.v1.ucReplyStatus;8081/* timeout */82if (args.v1.ucReplyStatus == 1) {83DRM_DEBUG_KMS("dp_aux_ch timeout\n");84return -ETIMEDOUT;85}8687/* flags not zero */88if (args.v1.ucReplyStatus == 2) {89DRM_DEBUG_KMS("dp_aux_ch flags not zero\n");90return -EBUSY;91}9293/* error */94if (args.v1.ucReplyStatus == 3) {95DRM_DEBUG_KMS("dp_aux_ch error\n");96return -EIO;97}9899recv_bytes = args.v1.ucDataOutLen;100if (recv_bytes > recv_size)101recv_bytes = recv_size;102103if (recv && recv_size)104memcpy(recv, base + 16, recv_bytes);105106return recv_bytes;107}108109static int radeon_dp_aux_native_write(struct radeon_connector *radeon_connector,110u16 address, u8 *send, u8 send_bytes, u8 delay)111{112struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;113int ret;114u8 msg[20];115int msg_bytes = send_bytes + 4;116u8 ack;117118if (send_bytes > 16)119return -1;120121msg[0] = address;122msg[1] = address >> 8;123msg[2] = AUX_NATIVE_WRITE << 4;124msg[3] = (msg_bytes << 4) | (send_bytes - 1);125memcpy(&msg[4], send, send_bytes);126127while (1) {128ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus,129msg, msg_bytes, NULL, 0, delay, &ack);130if (ret < 0)131return ret;132if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)133break;134else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)135udelay(400);136else137return -EIO;138}139140return send_bytes;141}142143static int radeon_dp_aux_native_read(struct radeon_connector *radeon_connector,144u16 address, u8 *recv, int recv_bytes, u8 delay)145{146struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;147u8 msg[4];148int msg_bytes = 4;149u8 ack;150int ret;151152msg[0] = address;153msg[1] = address >> 8;154msg[2] = AUX_NATIVE_READ << 4;155msg[3] = (msg_bytes << 4) | (recv_bytes - 1);156157while (1) {158ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus,159msg, msg_bytes, recv, recv_bytes, delay, &ack);160if (ret == 0)161return -EPROTO;162if (ret < 0)163return ret;164if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)165return ret;166else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)167udelay(400);168else169return -EIO;170}171}172173static void radeon_write_dpcd_reg(struct radeon_connector *radeon_connector,174u16 reg, u8 val)175{176radeon_dp_aux_native_write(radeon_connector, reg, &val, 1, 0);177}178179static u8 radeon_read_dpcd_reg(struct radeon_connector *radeon_connector,180u16 reg)181{182u8 val = 0;183184radeon_dp_aux_native_read(radeon_connector, reg, &val, 1, 0);185186return val;187}188189int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,190u8 write_byte, u8 *read_byte)191{192struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;193struct radeon_i2c_chan *auxch = (struct radeon_i2c_chan *)adapter;194u16 address = algo_data->address;195u8 msg[5];196u8 reply[2];197unsigned retry;198int msg_bytes;199int reply_bytes = 1;200int ret;201u8 ack;202203/* Set up the command byte */204if (mode & MODE_I2C_READ)205msg[2] = AUX_I2C_READ << 4;206else207msg[2] = AUX_I2C_WRITE << 4;208209if (!(mode & MODE_I2C_STOP))210msg[2] |= AUX_I2C_MOT << 4;211212msg[0] = address;213msg[1] = address >> 8;214215switch (mode) {216case MODE_I2C_WRITE:217msg_bytes = 5;218msg[3] = msg_bytes << 4;219msg[4] = write_byte;220break;221case MODE_I2C_READ:222msg_bytes = 4;223msg[3] = msg_bytes << 4;224break;225default:226msg_bytes = 4;227msg[3] = 3 << 4;228break;229}230231for (retry = 0; retry < 4; retry++) {232ret = radeon_process_aux_ch(auxch,233msg, msg_bytes, reply, reply_bytes, 0, &ack);234if (ret < 0) {235DRM_DEBUG_KMS("aux_ch failed %d\n", ret);236return ret;237}238239switch (ack & AUX_NATIVE_REPLY_MASK) {240case AUX_NATIVE_REPLY_ACK:241/* I2C-over-AUX Reply field is only valid242* when paired with AUX ACK.243*/244break;245case AUX_NATIVE_REPLY_NACK:246DRM_DEBUG_KMS("aux_ch native nack\n");247return -EREMOTEIO;248case AUX_NATIVE_REPLY_DEFER:249DRM_DEBUG_KMS("aux_ch native defer\n");250udelay(400);251continue;252default:253DRM_ERROR("aux_ch invalid native reply 0x%02x\n", ack);254return -EREMOTEIO;255}256257switch (ack & AUX_I2C_REPLY_MASK) {258case AUX_I2C_REPLY_ACK:259if (mode == MODE_I2C_READ)260*read_byte = reply[0];261return ret;262case AUX_I2C_REPLY_NACK:263DRM_DEBUG_KMS("aux_i2c nack\n");264return -EREMOTEIO;265case AUX_I2C_REPLY_DEFER:266DRM_DEBUG_KMS("aux_i2c defer\n");267udelay(400);268break;269default:270DRM_ERROR("aux_i2c invalid reply 0x%02x\n", ack);271return -EREMOTEIO;272}273}274275DRM_ERROR("aux i2c too many retries, giving up\n");276return -EREMOTEIO;277}278279/***** general DP utility functions *****/280281static u8 dp_link_status(u8 link_status[DP_LINK_STATUS_SIZE], int r)282{283return link_status[r - DP_LANE0_1_STATUS];284}285286static u8 dp_get_lane_status(u8 link_status[DP_LINK_STATUS_SIZE],287int lane)288{289int i = DP_LANE0_1_STATUS + (lane >> 1);290int s = (lane & 1) * 4;291u8 l = dp_link_status(link_status, i);292return (l >> s) & 0xf;293}294295static bool dp_clock_recovery_ok(u8 link_status[DP_LINK_STATUS_SIZE],296int lane_count)297{298int lane;299u8 lane_status;300301for (lane = 0; lane < lane_count; lane++) {302lane_status = dp_get_lane_status(link_status, lane);303if ((lane_status & DP_LANE_CR_DONE) == 0)304return false;305}306return true;307}308309static bool dp_channel_eq_ok(u8 link_status[DP_LINK_STATUS_SIZE],310int lane_count)311{312u8 lane_align;313u8 lane_status;314int lane;315316lane_align = dp_link_status(link_status,317DP_LANE_ALIGN_STATUS_UPDATED);318if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0)319return false;320for (lane = 0; lane < lane_count; lane++) {321lane_status = dp_get_lane_status(link_status, lane);322if ((lane_status & DP_CHANNEL_EQ_BITS) != DP_CHANNEL_EQ_BITS)323return false;324}325return true;326}327328static u8 dp_get_adjust_request_voltage(u8 link_status[DP_LINK_STATUS_SIZE],329int lane)330331{332int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);333int s = ((lane & 1) ?334DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT :335DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT);336u8 l = dp_link_status(link_status, i);337338return ((l >> s) & 0x3) << DP_TRAIN_VOLTAGE_SWING_SHIFT;339}340341static u8 dp_get_adjust_request_pre_emphasis(u8 link_status[DP_LINK_STATUS_SIZE],342int lane)343{344int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);345int s = ((lane & 1) ?346DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT :347DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT);348u8 l = dp_link_status(link_status, i);349350return ((l >> s) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT;351}352353#define DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_1200354#define DP_PRE_EMPHASIS_MAX DP_TRAIN_PRE_EMPHASIS_9_5355356static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE],357int lane_count,358u8 train_set[4])359{360u8 v = 0;361u8 p = 0;362int lane;363364for (lane = 0; lane < lane_count; lane++) {365u8 this_v = dp_get_adjust_request_voltage(link_status, lane);366u8 this_p = dp_get_adjust_request_pre_emphasis(link_status, lane);367368DRM_DEBUG_KMS("requested signal parameters: lane %d voltage %s pre_emph %s\n",369lane,370voltage_names[this_v >> DP_TRAIN_VOLTAGE_SWING_SHIFT],371pre_emph_names[this_p >> DP_TRAIN_PRE_EMPHASIS_SHIFT]);372373if (this_v > v)374v = this_v;375if (this_p > p)376p = this_p;377}378379if (v >= DP_VOLTAGE_MAX)380v |= DP_TRAIN_MAX_SWING_REACHED;381382if (p >= DP_PRE_EMPHASIS_MAX)383p |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;384385DRM_DEBUG_KMS("using signal parameters: voltage %s pre_emph %s\n",386voltage_names[(v & DP_TRAIN_VOLTAGE_SWING_MASK) >> DP_TRAIN_VOLTAGE_SWING_SHIFT],387pre_emph_names[(p & DP_TRAIN_PRE_EMPHASIS_MASK) >> DP_TRAIN_PRE_EMPHASIS_SHIFT]);388389for (lane = 0; lane < 4; lane++)390train_set[lane] = v | p;391}392393/* convert bits per color to bits per pixel */394/* get bpc from the EDID */395static int convert_bpc_to_bpp(int bpc)396{397if (bpc == 0)398return 24;399else400return bpc * 3;401}402403/* get the max pix clock supported by the link rate and lane num */404static int dp_get_max_dp_pix_clock(int link_rate,405int lane_num,406int bpp)407{408return (link_rate * lane_num * 8) / bpp;409}410411static int dp_get_max_link_rate(u8 dpcd[DP_DPCD_SIZE])412{413switch (dpcd[DP_MAX_LINK_RATE]) {414case DP_LINK_BW_1_62:415default:416return 162000;417case DP_LINK_BW_2_7:418return 270000;419case DP_LINK_BW_5_4:420return 540000;421}422}423424static u8 dp_get_max_lane_number(u8 dpcd[DP_DPCD_SIZE])425{426return dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK;427}428429static u8 dp_get_dp_link_rate_coded(int link_rate)430{431switch (link_rate) {432case 162000:433default:434return DP_LINK_BW_1_62;435case 270000:436return DP_LINK_BW_2_7;437case 540000:438return DP_LINK_BW_5_4;439}440}441442/***** radeon specific DP functions *****/443444/* First get the min lane# when low rate is used according to pixel clock445* (prefer low rate), second check max lane# supported by DP panel,446* if the max lane# < low rate lane# then use max lane# instead.447*/448static int radeon_dp_get_dp_lane_number(struct drm_connector *connector,449u8 dpcd[DP_DPCD_SIZE],450int pix_clock)451{452int bpp = convert_bpc_to_bpp(connector->display_info.bpc);453int max_link_rate = dp_get_max_link_rate(dpcd);454int max_lane_num = dp_get_max_lane_number(dpcd);455int lane_num;456int max_dp_pix_clock;457458for (lane_num = 1; lane_num < max_lane_num; lane_num <<= 1) {459max_dp_pix_clock = dp_get_max_dp_pix_clock(max_link_rate, lane_num, bpp);460if (pix_clock <= max_dp_pix_clock)461break;462}463464return lane_num;465}466467static int radeon_dp_get_dp_link_clock(struct drm_connector *connector,468u8 dpcd[DP_DPCD_SIZE],469int pix_clock)470{471int bpp = convert_bpc_to_bpp(connector->display_info.bpc);472int lane_num, max_pix_clock;473474if (radeon_connector_encoder_is_dp_bridge(connector))475return 270000;476477lane_num = radeon_dp_get_dp_lane_number(connector, dpcd, pix_clock);478max_pix_clock = dp_get_max_dp_pix_clock(162000, lane_num, bpp);479if (pix_clock <= max_pix_clock)480return 162000;481max_pix_clock = dp_get_max_dp_pix_clock(270000, lane_num, bpp);482if (pix_clock <= max_pix_clock)483return 270000;484if (radeon_connector_is_dp12_capable(connector)) {485max_pix_clock = dp_get_max_dp_pix_clock(540000, lane_num, bpp);486if (pix_clock <= max_pix_clock)487return 540000;488}489490return dp_get_max_link_rate(dpcd);491}492493static u8 radeon_dp_encoder_service(struct radeon_device *rdev,494int action, int dp_clock,495u8 ucconfig, u8 lane_num)496{497DP_ENCODER_SERVICE_PARAMETERS args;498int index = GetIndexIntoMasterTable(COMMAND, DPEncoderService);499500memset(&args, 0, sizeof(args));501args.ucLinkClock = dp_clock / 10;502args.ucConfig = ucconfig;503args.ucAction = action;504args.ucLaneNum = lane_num;505args.ucStatus = 0;506507atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);508return args.ucStatus;509}510511u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector)512{513struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;514struct drm_device *dev = radeon_connector->base.dev;515struct radeon_device *rdev = dev->dev_private;516517return radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_GET_SINK_TYPE, 0,518dig_connector->dp_i2c_bus->rec.i2c_id, 0);519}520521bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector)522{523struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;524u8 msg[25];525int ret, i;526527ret = radeon_dp_aux_native_read(radeon_connector, DP_DPCD_REV, msg, 8, 0);528if (ret > 0) {529memcpy(dig_connector->dpcd, msg, 8);530DRM_DEBUG_KMS("DPCD: ");531for (i = 0; i < 8; i++)532DRM_DEBUG_KMS("%02x ", msg[i]);533DRM_DEBUG_KMS("\n");534return true;535}536dig_connector->dpcd[0] = 0;537return false;538}539540static void radeon_dp_set_panel_mode(struct drm_encoder *encoder,541struct drm_connector *connector)542{543struct drm_device *dev = encoder->dev;544struct radeon_device *rdev = dev->dev_private;545int panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE;546547if (!ASIC_IS_DCE4(rdev))548return;549550if (radeon_connector_encoder_is_dp_bridge(connector))551panel_mode = DP_PANEL_MODE_INTERNAL_DP1_MODE;552553atombios_dig_encoder_setup(encoder,554ATOM_ENCODER_CMD_SETUP_PANEL_MODE,555panel_mode);556}557558void radeon_dp_set_link_config(struct drm_connector *connector,559struct drm_display_mode *mode)560{561struct radeon_connector *radeon_connector = to_radeon_connector(connector);562struct radeon_connector_atom_dig *dig_connector;563564if (!radeon_connector->con_priv)565return;566dig_connector = radeon_connector->con_priv;567568if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||569(dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {570dig_connector->dp_clock =571radeon_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);572dig_connector->dp_lane_count =573radeon_dp_get_dp_lane_number(connector, dig_connector->dpcd, mode->clock);574}575}576577int radeon_dp_mode_valid_helper(struct drm_connector *connector,578struct drm_display_mode *mode)579{580struct radeon_connector *radeon_connector = to_radeon_connector(connector);581struct radeon_connector_atom_dig *dig_connector;582int dp_clock;583584if (!radeon_connector->con_priv)585return MODE_CLOCK_HIGH;586dig_connector = radeon_connector->con_priv;587588dp_clock =589radeon_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);590591if ((dp_clock == 540000) &&592(!radeon_connector_is_dp12_capable(connector)))593return MODE_CLOCK_HIGH;594595return MODE_OK;596}597598static bool radeon_dp_get_link_status(struct radeon_connector *radeon_connector,599u8 link_status[DP_LINK_STATUS_SIZE])600{601int ret;602ret = radeon_dp_aux_native_read(radeon_connector, DP_LANE0_1_STATUS,603link_status, DP_LINK_STATUS_SIZE, 100);604if (ret <= 0) {605DRM_ERROR("displayport link status failed\n");606return false;607}608609DRM_DEBUG_KMS("link status %02x %02x %02x %02x %02x %02x\n",610link_status[0], link_status[1], link_status[2],611link_status[3], link_status[4], link_status[5]);612return true;613}614615struct radeon_dp_link_train_info {616struct radeon_device *rdev;617struct drm_encoder *encoder;618struct drm_connector *connector;619struct radeon_connector *radeon_connector;620int enc_id;621int dp_clock;622int dp_lane_count;623int rd_interval;624bool tp3_supported;625u8 dpcd[8];626u8 train_set[4];627u8 link_status[DP_LINK_STATUS_SIZE];628u8 tries;629};630631static void radeon_dp_update_vs_emph(struct radeon_dp_link_train_info *dp_info)632{633/* set the initial vs/emph on the source */634atombios_dig_transmitter_setup(dp_info->encoder,635ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH,6360, dp_info->train_set[0]); /* sets all lanes at once */637638/* set the vs/emph on the sink */639radeon_dp_aux_native_write(dp_info->radeon_connector, DP_TRAINING_LANE0_SET,640dp_info->train_set, dp_info->dp_lane_count, 0);641}642643static void radeon_dp_set_tp(struct radeon_dp_link_train_info *dp_info, int tp)644{645int rtp = 0;646647/* set training pattern on the source */648if (ASIC_IS_DCE4(dp_info->rdev)) {649switch (tp) {650case DP_TRAINING_PATTERN_1:651rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1;652break;653case DP_TRAINING_PATTERN_2:654rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2;655break;656case DP_TRAINING_PATTERN_3:657rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN3;658break;659}660atombios_dig_encoder_setup(dp_info->encoder, rtp, 0);661} else {662switch (tp) {663case DP_TRAINING_PATTERN_1:664rtp = 0;665break;666case DP_TRAINING_PATTERN_2:667rtp = 1;668break;669}670radeon_dp_encoder_service(dp_info->rdev, ATOM_DP_ACTION_TRAINING_PATTERN_SEL,671dp_info->dp_clock, dp_info->enc_id, rtp);672}673674/* enable training pattern on the sink */675radeon_write_dpcd_reg(dp_info->radeon_connector, DP_TRAINING_PATTERN_SET, tp);676}677678static int radeon_dp_link_train_init(struct radeon_dp_link_train_info *dp_info)679{680u8 tmp;681682/* power up the sink */683if (dp_info->dpcd[0] >= 0x11)684radeon_write_dpcd_reg(dp_info->radeon_connector,685DP_SET_POWER, DP_SET_POWER_D0);686687/* possibly enable downspread on the sink */688if (dp_info->dpcd[3] & 0x1)689radeon_write_dpcd_reg(dp_info->radeon_connector,690DP_DOWNSPREAD_CTRL, DP_SPREAD_AMP_0_5);691else692radeon_write_dpcd_reg(dp_info->radeon_connector,693DP_DOWNSPREAD_CTRL, 0);694695radeon_dp_set_panel_mode(dp_info->encoder, dp_info->connector);696697/* set the lane count on the sink */698tmp = dp_info->dp_lane_count;699if (dp_info->dpcd[0] >= 0x11)700tmp |= DP_LANE_COUNT_ENHANCED_FRAME_EN;701radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LANE_COUNT_SET, tmp);702703/* set the link rate on the sink */704tmp = dp_get_dp_link_rate_coded(dp_info->dp_clock);705radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LINK_BW_SET, tmp);706707/* start training on the source */708if (ASIC_IS_DCE4(dp_info->rdev))709atombios_dig_encoder_setup(dp_info->encoder,710ATOM_ENCODER_CMD_DP_LINK_TRAINING_START, 0);711else712radeon_dp_encoder_service(dp_info->rdev, ATOM_DP_ACTION_TRAINING_START,713dp_info->dp_clock, dp_info->enc_id, 0);714715/* disable the training pattern on the sink */716radeon_write_dpcd_reg(dp_info->radeon_connector,717DP_TRAINING_PATTERN_SET,718DP_TRAINING_PATTERN_DISABLE);719720return 0;721}722723static int radeon_dp_link_train_finish(struct radeon_dp_link_train_info *dp_info)724{725udelay(400);726727/* disable the training pattern on the sink */728radeon_write_dpcd_reg(dp_info->radeon_connector,729DP_TRAINING_PATTERN_SET,730DP_TRAINING_PATTERN_DISABLE);731732/* disable the training pattern on the source */733if (ASIC_IS_DCE4(dp_info->rdev))734atombios_dig_encoder_setup(dp_info->encoder,735ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE, 0);736else737radeon_dp_encoder_service(dp_info->rdev, ATOM_DP_ACTION_TRAINING_COMPLETE,738dp_info->dp_clock, dp_info->enc_id, 0);739740return 0;741}742743static int radeon_dp_link_train_cr(struct radeon_dp_link_train_info *dp_info)744{745bool clock_recovery;746u8 voltage;747int i;748749radeon_dp_set_tp(dp_info, DP_TRAINING_PATTERN_1);750memset(dp_info->train_set, 0, 4);751radeon_dp_update_vs_emph(dp_info);752753udelay(400);754755/* clock recovery loop */756clock_recovery = false;757dp_info->tries = 0;758voltage = 0xff;759while (1) {760if (dp_info->rd_interval == 0)761udelay(100);762else763mdelay(dp_info->rd_interval * 4);764765if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status))766break;767768if (dp_clock_recovery_ok(dp_info->link_status, dp_info->dp_lane_count)) {769clock_recovery = true;770break;771}772773for (i = 0; i < dp_info->dp_lane_count; i++) {774if ((dp_info->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)775break;776}777if (i == dp_info->dp_lane_count) {778DRM_ERROR("clock recovery reached max voltage\n");779break;780}781782if ((dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {783++dp_info->tries;784if (dp_info->tries == 5) {785DRM_ERROR("clock recovery tried 5 times\n");786break;787}788} else789dp_info->tries = 0;790791voltage = dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;792793/* Compute new train_set as requested by sink */794dp_get_adjust_train(dp_info->link_status, dp_info->dp_lane_count, dp_info->train_set);795796radeon_dp_update_vs_emph(dp_info);797}798if (!clock_recovery) {799DRM_ERROR("clock recovery failed\n");800return -1;801} else {802DRM_DEBUG_KMS("clock recovery at voltage %d pre-emphasis %d\n",803dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,804(dp_info->train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK) >>805DP_TRAIN_PRE_EMPHASIS_SHIFT);806return 0;807}808}809810static int radeon_dp_link_train_ce(struct radeon_dp_link_train_info *dp_info)811{812bool channel_eq;813814if (dp_info->tp3_supported)815radeon_dp_set_tp(dp_info, DP_TRAINING_PATTERN_3);816else817radeon_dp_set_tp(dp_info, DP_TRAINING_PATTERN_2);818819/* channel equalization loop */820dp_info->tries = 0;821channel_eq = false;822while (1) {823if (dp_info->rd_interval == 0)824udelay(400);825else826mdelay(dp_info->rd_interval * 4);827828if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status))829break;830831if (dp_channel_eq_ok(dp_info->link_status, dp_info->dp_lane_count)) {832channel_eq = true;833break;834}835836/* Try 5 times */837if (dp_info->tries > 5) {838DRM_ERROR("channel eq failed: 5 tries\n");839break;840}841842/* Compute new train_set as requested by sink */843dp_get_adjust_train(dp_info->link_status, dp_info->dp_lane_count, dp_info->train_set);844845radeon_dp_update_vs_emph(dp_info);846dp_info->tries++;847}848849if (!channel_eq) {850DRM_ERROR("channel eq failed\n");851return -1;852} else {853DRM_DEBUG_KMS("channel eq at voltage %d pre-emphasis %d\n",854dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,855(dp_info->train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK)856>> DP_TRAIN_PRE_EMPHASIS_SHIFT);857return 0;858}859}860861void radeon_dp_link_train(struct drm_encoder *encoder,862struct drm_connector *connector)863{864struct drm_device *dev = encoder->dev;865struct radeon_device *rdev = dev->dev_private;866struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);867struct radeon_encoder_atom_dig *dig;868struct radeon_connector *radeon_connector;869struct radeon_connector_atom_dig *dig_connector;870struct radeon_dp_link_train_info dp_info;871u8 tmp;872873if (!radeon_encoder->enc_priv)874return;875dig = radeon_encoder->enc_priv;876877radeon_connector = to_radeon_connector(connector);878if (!radeon_connector->con_priv)879return;880dig_connector = radeon_connector->con_priv;881882if ((dig_connector->dp_sink_type != CONNECTOR_OBJECT_ID_DISPLAYPORT) &&883(dig_connector->dp_sink_type != CONNECTOR_OBJECT_ID_eDP))884return;885886dp_info.enc_id = 0;887if (dig->dig_encoder)888dp_info.enc_id |= ATOM_DP_CONFIG_DIG2_ENCODER;889else890dp_info.enc_id |= ATOM_DP_CONFIG_DIG1_ENCODER;891if (dig->linkb)892dp_info.enc_id |= ATOM_DP_CONFIG_LINK_B;893else894dp_info.enc_id |= ATOM_DP_CONFIG_LINK_A;895896dp_info.rd_interval = radeon_read_dpcd_reg(radeon_connector, DP_TRAINING_AUX_RD_INTERVAL);897tmp = radeon_read_dpcd_reg(radeon_connector, DP_MAX_LANE_COUNT);898if (ASIC_IS_DCE5(rdev) && (tmp & DP_TPS3_SUPPORTED))899dp_info.tp3_supported = true;900else901dp_info.tp3_supported = false;902903memcpy(dp_info.dpcd, dig_connector->dpcd, 8);904dp_info.rdev = rdev;905dp_info.encoder = encoder;906dp_info.connector = connector;907dp_info.radeon_connector = radeon_connector;908dp_info.dp_lane_count = dig_connector->dp_lane_count;909dp_info.dp_clock = dig_connector->dp_clock;910911if (radeon_dp_link_train_init(&dp_info))912goto done;913if (radeon_dp_link_train_cr(&dp_info))914goto done;915if (radeon_dp_link_train_ce(&dp_info))916goto done;917done:918if (radeon_dp_link_train_finish(&dp_info))919return;920}921922923