/* * Copyright 2012-15 Advanced Micro Devices, 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: AMD *
*/
uint32_t value = REG_READ(AUX_ARB_CONTROL);
uint32_t field = get_reg_field_value(
value,
AUX_ARB_CONTROL,
AUX_REG_RW_CNTL_STATUS); if (field == DMCU_CAN_ACCESS_AUX) returnfalse; /* enable AUX before request SW to access AUX */
value = REG_READ(AUX_CONTROL);
field = get_reg_field_value(value,
AUX_CONTROL,
AUX_EN);
if (field == 0) {
set_reg_field_value(
value,
1,
AUX_CONTROL,
AUX_EN);
if (REG(AUX_RESET_MASK)) { /*DP_AUX block as part of the enable sequence*/
set_reg_field_value(
value,
1,
AUX_CONTROL,
AUX_RESET);
}
REG_WRITE(AUX_CONTROL, value);
if (REG(AUX_RESET_MASK)) { /*poll HW to make sure reset it done*/
/* set the delay and the number of bytes to write */
/* The length include * the 4 bit header and the 20 bit address * (that is 3 byte). * If the requested length is non zero this means * an addition byte specifying the length is required.
*/
/* program action and address and payload data (if 'is_write') */
value = REG_UPDATE_4(AUX_SW_DATA,
AUX_SW_INDEX, 0,
AUX_SW_DATA_RW, 0,
AUX_SW_AUTOINCREMENT_DISABLE, 1,
AUX_SW_DATA, COMPOSE_AUX_SW_DATA_16_20(request->action, request->address));
value = REG_SET_2(AUX_SW_DATA, value,
AUX_SW_AUTOINCREMENT_DISABLE, 0,
AUX_SW_DATA, COMPOSE_AUX_SW_DATA_8_15(request->address));
value = REG_SET(AUX_SW_DATA, value,
AUX_SW_DATA, COMPOSE_AUX_SW_DATA_0_7(request->address));
if (request->length) {
value = REG_SET(AUX_SW_DATA, value,
AUX_SW_DATA, request->length - 1);
}
if (is_write) { /* Load the HW buffer with the Data to be sent. * This is relevant for write operation. * For read, the data recived data will be * processed in process_channel_reply().
*/
uint32_t i = 0;
while (i < request->length) {
value = REG_SET(AUX_SW_DATA, value,
AUX_SW_DATA, request->data[i]);
/* poll to make sure that SW_DONE is asserted */
REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 1,
10, aux110->polling_timeout_period/10);
value = REG_READ(AUX_SW_STATUS); /* in case HPD is LOW, exit AUX transaction */ if ((value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) return AUX_RET_ERROR_HPD_DISCON;
/* Note that the following bits are set in 'status.bits' * during CTS 4.2.1.2 (FW 3.3.1): * AUX_SW_RX_MIN_COUNT_VIOL, AUX_SW_RX_INVALID_STOP, * AUX_SW_RX_RECV_NO_DET, AUX_SW_RX_RECV_INVALID_H. * * AUX_SW_RX_MIN_COUNT_VIOL is an internal, * HW debugging bit and should be ignored.
*/ if (value & AUX_SW_STATUS__AUX_SW_DONE_MASK) { if ((value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_STATE_MASK) ||
(value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_MASK)) return AUX_RET_ERROR_TIMEOUT;
if (ddc_pin) {
aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en];
aux110 = FROM_AUX_ENGINE(aux_engine);
}
if (!payload->reply) {
payload_reply = false;
payload->reply = &reply;
}
for (i = 0; i < AUX_MAX_RETRIES; i++) {
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
LOG_FLAG_I2cAux_DceAux, "dce_aux_transfer_with_retries: link_index=%u: START: retry %d of %d: address=0x%04x length=%u write=%d mot=%d",
ddc && ddc->link ? ddc->link->link_index : UINT_MAX,
i + 1,
(int)AUX_MAX_RETRIES,
payload->address,
payload->length,
(unsignedint) payload->write,
(unsignedint) payload->mot); if (payload->write)
dce_aux_log_payload(" write", payload->data, payload->length, 16);
/* Check whether aux to be processed via dmub or dcn directly */ if (ddc->ctx->dc->debug.enable_dmub_aux_for_legacy_ddc
|| ddc->ddc_pin == NULL) {
ret = dce_aux_transfer_dmub_raw(ddc, payload, &operation_result);
} else {
ret = dce_aux_transfer_raw(ddc, payload, &operation_result);
}
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
LOG_FLAG_I2cAux_DceAux, "dce_aux_transfer_with_retries: link_index=%u: END: retry %d of %d: address=0x%04x length=%u write=%d mot=%d: ret=%d operation_result=%d payload->reply=%u",
ddc && ddc->link ? ddc->link->link_index : UINT_MAX,
i + 1,
(int)AUX_MAX_RETRIES,
payload->address,
payload->length,
(unsignedint) payload->write,
(unsignedint) payload->mot,
ret,
(int)operation_result,
(unsignedint) *payload->reply); if (!payload->write)
dce_aux_log_payload(" read", payload->data, ret > 0 ? ret : 0, 16);
switch (*payload->reply) { case AUX_TRANSACTION_REPLY_AUX_ACK:
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
LOG_FLAG_I2cAux_DceAux, "dce_aux_transfer_with_retries: AUX_RET_SUCCESS: AUX_TRANSACTION_REPLY_AUX_ACK"); if (!payload->write && payload->length != ret) { if (++aux_ack_retries >= AUX_MAX_RETRIES) {
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
LOG_FLAG_Error_I2cAux, "dce_aux_transfer_with_retries: FAILURE: aux_ack_retries=%d >= AUX_MAX_RETRIES=%d",
aux_defer_retries,
AUX_MAX_RETRIES); goto fail;
} else
udelay(300);
} elseif (payload->write && ret > 0) { /* sink requested more time to complete the write via AUX_ACKM */ if (++aux_ack_m_retries >= AUX_MAX_RETRIES) {
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
LOG_FLAG_Error_I2cAux, "dce_aux_transfer_with_retries: FAILURE: aux_ack_m_retries=%d >= AUX_MAX_RETRIES=%d",
aux_ack_m_retries,
AUX_MAX_RETRIES); goto fail;
}
/* retry reading the write status until complete * NOTE: payload is modified here
*/
payload->write = false;
payload->write_status_update = true;
payload->length = 0;
udelay(300);
} else returntrue; break;
case AUX_TRANSACTION_REPLY_AUX_DEFER:
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
LOG_FLAG_I2cAux_DceAux, "dce_aux_transfer_with_retries: AUX_RET_SUCCESS: AUX_TRANSACTION_REPLY_AUX_DEFER");
/* polling_timeout_period is in us */ if (aux110)
defer_time_in_ms += aux110->polling_timeout_period / 1000; else
defer_time_in_ms += AUX_DEFER_DELAY_FOR_DPIA;
++aux_defer_retries;
fallthrough; case AUX_TRANSACTION_REPLY_I2C_OVER_AUX_DEFER: if (*payload->reply == AUX_TRANSACTION_REPLY_I2C_OVER_AUX_DEFER)
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
LOG_FLAG_I2cAux_DceAux, "dce_aux_transfer_with_retries: AUX_RET_SUCCESS: AUX_TRANSACTION_REPLY_I2C_OVER_AUX_DEFER");
case AUX_RET_ERROR_TIMEOUT:
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
LOG_FLAG_I2cAux_DceAux, "dce_aux_transfer_with_retries: AUX_RET_ERROR_TIMEOUT"); // Check whether a DEFER had occurred before the timeout. // If so, treat timeout as a DEFER. if (retry_on_defer) { if (++aux_defer_retries >= AUX_MIN_DEFER_RETRIES) {
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
LOG_FLAG_Error_I2cAux, "dce_aux_transfer_with_retries: FAILURE: aux_defer_retries=%d >= AUX_MIN_DEFER_RETRIES=%d",
aux_defer_retries,
AUX_MIN_DEFER_RETRIES); goto fail;
} elseif (payload->defer_delay > 0) {
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
LOG_FLAG_I2cAux_DceAux, "dce_aux_transfer_with_retries: payload->defer_delay=%u",
payload->defer_delay);
msleep(payload->defer_delay);
}
} else { if (++aux_timeout_retries >= AUX_MAX_TIMEOUT_RETRIES) {
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
LOG_FLAG_Error_I2cAux, "dce_aux_transfer_with_retries: FAILURE: aux_timeout_retries=%d >= AUX_MAX_TIMEOUT_RETRIES=%d",
aux_timeout_retries,
AUX_MAX_TIMEOUT_RETRIES); goto fail;
} else { /* * DP 1.4, 2.8.2: AUX Transaction Response/Reply Timeouts * According to the DP spec there should be 3 retries total * with a 400us wait inbetween each. Hardware already waits * for 550us therefore no wait is required here.
*/
}
} break;
case AUX_RET_ERROR_HPD_DISCON: case AUX_RET_ERROR_ENGINE_ACQUIRE: case AUX_RET_ERROR_UNKNOWN: default: goto fail;
}
}
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.