/* * Copyright 2007-8 Advanced Micro Devices, Inc. * Copyright 2008 Red Hat Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: Dave Airlie * Alex Deucher * Jerome Glisse
*/
switch (msg->request & ~DP_AUX_I2C_MOT) { case DP_AUX_NATIVE_WRITE: case DP_AUX_I2C_WRITE: /* tx_size needs to be 4 even for bare address packets since the atom * table needs the info in tx_buf[3].
*/
tx_size = HEADER_SIZE + msg->size; if (msg->size == 0)
tx_buf[3] |= BARE_ADDRESS_SIZE << 4; else
tx_buf[3] |= tx_size << 4;
memcpy(tx_buf + HEADER_SIZE, msg->buffer, msg->size);
ret = amdgpu_atombios_dp_process_aux_ch(chan,
tx_buf, tx_size, NULL, 0, delay, &ack); if (ret >= 0) /* Return payload size. */
ret = msg->size; break; case DP_AUX_NATIVE_READ: case DP_AUX_I2C_READ: /* tx_size needs to be 4 even for bare address packets since the atom * table needs the info in tx_buf[3].
*/
tx_size = HEADER_SIZE; if (msg->size == 0)
tx_buf[3] |= BARE_ADDRESS_SIZE << 4; else
tx_buf[3] |= tx_size << 4;
ret = amdgpu_atombios_dp_process_aux_ch(chan,
tx_buf, tx_size, msg->buffer, msg->size, delay, &ack); break; default:
ret = -EINVAL; break;
}
staticvoid amdgpu_atombios_dp_get_adjust_train(const u8 link_status[DP_LINK_STATUS_SIZE], int lane_count,
u8 train_set[4])
{
u8 v = 0;
u8 p = 0; int lane;
for (lane = 0; lane < lane_count; lane++) {
u8 this_v = drm_dp_get_adjust_request_voltage(link_status, lane);
u8 this_p = drm_dp_get_adjust_request_pre_emphasis(link_status, lane);
DRM_DEBUG_KMS("requested signal parameters: lane %d voltage %s pre_emph %s\n",
lane,
voltage_names[this_v >> DP_TRAIN_VOLTAGE_SWING_SHIFT],
pre_emph_names[this_p >> DP_TRAIN_PRE_EMPHASIS_SHIFT]);
if (this_v > v)
v = this_v; if (this_p > p)
p = this_p;
}
if (v >= DP_VOLTAGE_MAX)
v |= DP_TRAIN_MAX_SWING_REACHED;
if (p >= DP_PRE_EMPHASIS_MAX)
p |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
DRM_DEBUG_KMS("using signal parameters: voltage %s pre_emph %s\n",
voltage_names[(v & DP_TRAIN_VOLTAGE_SWING_MASK) >> DP_TRAIN_VOLTAGE_SWING_SHIFT],
pre_emph_names[(p & DP_TRAIN_PRE_EMPHASIS_MASK) >> DP_TRAIN_PRE_EMPHASIS_SHIFT]);
for (lane = 0; lane < 4; lane++)
train_set[lane] = v | p;
}
/* convert bits per color to bits per pixel */ /* get bpc from the EDID */ staticunsigned amdgpu_atombios_dp_convert_bpc_to_bpp(int bpc)
{ if (bpc == 0) return 24; else return bpc * 3;
}
staticvoid
amdgpu_atombios_dp_update_vs_emph(struct amdgpu_atombios_dp_link_train_info *dp_info)
{ /* set the initial vs/emph on the source */
amdgpu_atombios_encoder_setup_dig_transmitter(dp_info->encoder,
ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH,
0, dp_info->train_set[0]); /* sets all lanes at once */
/* set the vs/emph on the sink */
drm_dp_dpcd_write(dp_info->aux, DP_TRAINING_LANE0_SET,
dp_info->train_set, dp_info->dp_lane_count);
}
staticvoid
amdgpu_atombios_dp_set_tp(struct amdgpu_atombios_dp_link_train_info *dp_info, int tp)
{ int rtp = 0;
/* set training pattern on the source */ switch (tp) { case DP_TRAINING_PATTERN_1:
rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1; break; case DP_TRAINING_PATTERN_2:
rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2; break; case DP_TRAINING_PATTERN_3:
rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN3; break;
}
amdgpu_atombios_encoder_setup_dig_encoder(dp_info->encoder, rtp, 0);
/* enable training pattern on the sink */
drm_dp_dpcd_writeb(dp_info->aux, DP_TRAINING_PATTERN_SET, tp);
}
/* power up the sink */
amdgpu_atombios_dp_set_rx_power_state(dp_info->connector, DP_SET_POWER_D0);
/* possibly enable downspread on the sink */ if (dp_info->dpcd[3] & 0x1)
drm_dp_dpcd_writeb(dp_info->aux,
DP_DOWNSPREAD_CTRL, DP_SPREAD_AMP_0_5); else
drm_dp_dpcd_writeb(dp_info->aux,
DP_DOWNSPREAD_CTRL, 0);
if (dig->panel_mode == DP_PANEL_MODE_INTERNAL_DP2_MODE)
drm_dp_dpcd_writeb(dp_info->aux, DP_EDP_CONFIGURATION_SET, 1);
/* set the lane count on the sink */
tmp = dp_info->dp_lane_count; if (drm_dp_enhanced_frame_cap(dp_info->dpcd))
tmp |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
drm_dp_dpcd_writeb(dp_info->aux, DP_LANE_COUNT_SET, tmp);
/* set the link rate on the sink */
tmp = drm_dp_link_rate_to_bw_code(dp_info->dp_clock);
drm_dp_dpcd_writeb(dp_info->aux, DP_LINK_BW_SET, tmp);
/* start training on the source */
amdgpu_atombios_encoder_setup_dig_encoder(dp_info->encoder,
ATOM_ENCODER_CMD_DP_LINK_TRAINING_START, 0);
/* disable the training pattern on the sink */
drm_dp_dpcd_writeb(dp_info->aux,
DP_TRAINING_PATTERN_SET,
DP_TRAINING_PATTERN_DISABLE);
/* disable the training pattern on the sink */
drm_dp_dpcd_writeb(dp_info->aux,
DP_TRAINING_PATTERN_SET,
DP_TRAINING_PATTERN_DISABLE);
/* disable the training pattern on the source */
amdgpu_atombios_encoder_setup_dig_encoder(dp_info->encoder,
ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE, 0);
/* clock recovery loop */
clock_recovery = false;
dp_info->tries = 0;
voltage = 0xff; while (1) {
drm_dp_link_train_clock_recovery_delay(dp_info->aux, dp_info->dpcd);
if (drm_dp_dpcd_read_link_status(dp_info->aux,
dp_info->link_status) < 0) {
DRM_ERROR("displayport link status failed\n"); break;
}
if (drm_dp_clock_recovery_ok(dp_info->link_status, dp_info->dp_lane_count)) {
clock_recovery = true; break;
}
for (i = 0; i < dp_info->dp_lane_count; i++) { if ((dp_info->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0) break;
} if (i == dp_info->dp_lane_count) {
DRM_ERROR("clock recovery reached max voltage\n"); break;
}
voltage = dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
/* Compute new train_set as requested by sink */
amdgpu_atombios_dp_get_adjust_train(dp_info->link_status, dp_info->dp_lane_count,
dp_info->train_set);
if (drm_dp_dpcd_read_link_status(dp_info->aux,
dp_info->link_status) < 0) {
DRM_ERROR("displayport link status failed\n"); break;
}
if (drm_dp_channel_eq_ok(dp_info->link_status, dp_info->dp_lane_count)) {
channel_eq = true; break;
}
/* Try 5 times */ if (dp_info->tries > 5) {
DRM_ERROR("channel eq failed: 5 tries\n"); break;
}
/* Compute new train_set as requested by sink */
amdgpu_atombios_dp_get_adjust_train(dp_info->link_status, dp_info->dp_lane_count,
dp_info->train_set);
if (amdgpu_atombios_dp_link_train_init(&dp_info)) goto done; if (amdgpu_atombios_dp_link_train_cr(&dp_info)) goto done; if (amdgpu_atombios_dp_link_train_ce(&dp_info)) goto done;
done: if (amdgpu_atombios_dp_link_train_finish(&dp_info)) return;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.2 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.