/* Atom needs data in little endian format so swap as appropriate when copying *datatoorfromatom.Notethatatomoperatesondwunits. * *Useto_le=truewhensendingdatatoatomandprovideatleast *ALIGN(num_bytes,4)bytesinthedstbuffer. * *Useto_le=falsewhenreceivingdatafromatomandprovideALIGN(num_bytes,4) *byesinthesrcbuffer.
*/ void radeon_atom_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le)
{ #ifdef __BIG_ENDIAN
u32 src_tmp[5], dst_tmp[5]; int i;
u8 align_num_bytes = ALIGN(num_bytes, 4);
if (to_le) {
memcpy(src_tmp, src, num_bytes); for (i = 0; i < align_num_bytes / 4; i++)
dst_tmp[i] = cpu_to_le32(src_tmp[i]);
memcpy(dst, dst_tmp, align_num_bytes);
} else {
memcpy(src_tmp, src, align_num_bytes); for (i = 0; i < align_num_bytes / 4; i++)
dst_tmp[i] = le32_to_cpu(src_tmp[i]);
memcpy(dst, dst_tmp, num_bytes);
} #else
memcpy(dst, src, num_bytes); #endif
}
union aux_channel_transaction {
PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1;
PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2;
};
staticint radeon_process_aux_ch(struct radeon_i2c_chan *chan,
u8 *send, int send_bytes,
u8 *recv, int recv_size,
u8 delay, u8 *ack)
{ struct drm_device *dev = chan->dev; struct radeon_device *rdev = dev->dev_private; union aux_channel_transaction args; int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction); unsignedchar *base; int recv_bytes; int r = 0;
switch (msg->request & ~DP_AUX_I2C_MOT) { case DP_AUX_NATIVE_WRITE: case DP_AUX_I2C_WRITE: case DP_AUX_I2C_WRITE_STATUS_UPDATE: /* The atom implementation only supports writes with a max payload of *12bytessinceituses4bitsforthetotalcount(header+payload) *intheparameterspace.Theatominterfacesupports16byte *payloadsforreads.Thehwitselfsupportsupto16bytesofpayload.
*/ if (WARN_ON_ONCE(msg->size > 12)) return -E2BIG; /* tx_size needs to be 4 even for bare address packets since the atom *tableneedstheinfointx_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 = radeon_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 *tableneedstheinfointx_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 = radeon_process_aux_ch(chan,
tx_buf, tx_size, msg->buffer, msg->size, delay, &ack); break; default:
ret = -EINVAL; break;
}
staticvoid 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 */ staticint convert_bpc_to_bpp(int bpc)
{ if (bpc == 0) return24; else return bpc * 3;
}
staticvoid radeon_dp_update_vs_emph(struct radeon_dp_link_train_info *dp_info)
{ /* set the initial vs/emph on the source */
atombios_dig_transmitter_setup(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 radeon_dp_set_tp(struct radeon_dp_link_train_info *dp_info, int tp)
{ int rtp = 0;
/* set training pattern on the source */ if (ASIC_IS_DCE4(dp_info->rdev) || !dp_info->use_dpencoder) { 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;
}
atombios_dig_encoder_setup(dp_info->encoder, rtp, 0);
} else { switch (tp) { case DP_TRAINING_PATTERN_1:
rtp = 0; break; case DP_TRAINING_PATTERN_2:
rtp = 1; break;
}
radeon_dp_encoder_service(dp_info->rdev, ATOM_DP_ACTION_TRAINING_PATTERN_SEL,
dp_info->dp_clock, dp_info->enc_id, rtp);
}
/* enable training pattern on the sink */
drm_dp_dpcd_writeb(dp_info->aux, DP_TRAINING_PATTERN_SET, tp);
}
/* power up the sink */
radeon_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 */ if (ASIC_IS_DCE4(dp_info->rdev) || !dp_info->use_dpencoder)
atombios_dig_encoder_setup(dp_info->encoder,
ATOM_ENCODER_CMD_DP_LINK_TRAINING_START, 0); else
radeon_dp_encoder_service(dp_info->rdev, ATOM_DP_ACTION_TRAINING_START,
dp_info->dp_clock, dp_info->enc_id, 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 */ if (ASIC_IS_DCE4(dp_info->rdev) || !dp_info->use_dpencoder)
atombios_dig_encoder_setup(dp_info->encoder,
ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE, 0); else
radeon_dp_encoder_service(dp_info->rdev, ATOM_DP_ACTION_TRAINING_COMPLETE,
dp_info->dp_clock, dp_info->enc_id, 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;
}
if (radeon_dp_link_train_init(&dp_info)) goto done; if (radeon_dp_link_train_cr(&dp_info)) goto done; if (radeon_dp_link_train_ce(&dp_info)) goto done;
done: if (radeon_dp_link_train_finish(&dp_info)) return;
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.57 Sekunden
(vorverarbeitet am 2026-09-28)
¤
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.