dce_aux.c (28512B)
1/* 2 * Copyright 2012-15 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * 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 OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: AMD 23 * 24 */ 25 26#include <linux/delay.h> 27#include <linux/slab.h> 28 29#include "dm_services.h" 30#include "core_types.h" 31#include "dce_aux.h" 32#include "dce/dce_11_0_sh_mask.h" 33#include "dm_event_log.h" 34#include "dm_helpers.h" 35#include "dmub/inc/dmub_cmd.h" 36 37#define CTX \ 38 aux110->base.ctx 39#define REG(reg_name)\ 40 (aux110->regs->reg_name) 41 42#define DC_LOGGER \ 43 engine->ctx->logger 44 45#define DC_TRACE_LEVEL_MESSAGE(...) do { } while (0) 46#define IS_DC_I2CAUX_LOGGING_ENABLED() (false) 47#define LOG_FLAG_Error_I2cAux LOG_ERROR 48#define LOG_FLAG_I2cAux_DceAux LOG_I2C_AUX 49 50#include "reg_helper.h" 51 52#undef FN 53#define FN(reg_name, field_name) \ 54 aux110->shift->field_name, aux110->mask->field_name 55 56#define FROM_AUX_ENGINE(ptr) \ 57 container_of((ptr), struct aux_engine_dce110, base) 58 59#define FROM_ENGINE(ptr) \ 60 FROM_AUX_ENGINE(container_of((ptr), struct dce_aux, base)) 61 62#define FROM_AUX_ENGINE_ENGINE(ptr) \ 63 container_of((ptr), struct dce_aux, base) 64enum { 65 AUX_INVALID_REPLY_RETRY_COUNTER = 1, 66 AUX_TIMED_OUT_RETRY_COUNTER = 2, 67 AUX_DEFER_RETRY_COUNTER = 6 68}; 69 70#define TIME_OUT_INCREMENT 1016 71#define TIME_OUT_MULTIPLIER_8 8 72#define TIME_OUT_MULTIPLIER_16 16 73#define TIME_OUT_MULTIPLIER_32 32 74#define TIME_OUT_MULTIPLIER_64 64 75#define MAX_TIMEOUT_LENGTH 127 76#define DEFAULT_AUX_ENGINE_MULT 0 77#define DEFAULT_AUX_ENGINE_LENGTH 69 78 79#define DC_TRACE_LEVEL_MESSAGE(...) do { } while (0) 80 81static void release_engine( 82 struct dce_aux *engine) 83{ 84 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); 85 86 dal_ddc_close(engine->ddc); 87 88 engine->ddc = NULL; 89 90 REG_UPDATE_2(AUX_ARB_CONTROL, AUX_SW_DONE_USING_AUX_REG, 1, 91 AUX_SW_USE_AUX_REG_REQ, 0); 92} 93 94#define SW_CAN_ACCESS_AUX 1 95#define DMCU_CAN_ACCESS_AUX 2 96 97static bool is_engine_available( 98 struct dce_aux *engine) 99{ 100 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); 101 102 uint32_t value = REG_READ(AUX_ARB_CONTROL); 103 uint32_t field = get_reg_field_value( 104 value, 105 AUX_ARB_CONTROL, 106 AUX_REG_RW_CNTL_STATUS); 107 108 return (field != DMCU_CAN_ACCESS_AUX); 109} 110static bool acquire_engine( 111 struct dce_aux *engine) 112{ 113 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); 114 115 uint32_t value = REG_READ(AUX_ARB_CONTROL); 116 uint32_t field = get_reg_field_value( 117 value, 118 AUX_ARB_CONTROL, 119 AUX_REG_RW_CNTL_STATUS); 120 if (field == DMCU_CAN_ACCESS_AUX) 121 return false; 122 /* enable AUX before request SW to access AUX */ 123 value = REG_READ(AUX_CONTROL); 124 field = get_reg_field_value(value, 125 AUX_CONTROL, 126 AUX_EN); 127 128 if (field == 0) { 129 set_reg_field_value( 130 value, 131 1, 132 AUX_CONTROL, 133 AUX_EN); 134 135 if (REG(AUX_RESET_MASK)) { 136 /*DP_AUX block as part of the enable sequence*/ 137 set_reg_field_value( 138 value, 139 1, 140 AUX_CONTROL, 141 AUX_RESET); 142 } 143 144 REG_WRITE(AUX_CONTROL, value); 145 146 if (REG(AUX_RESET_MASK)) { 147 /*poll HW to make sure reset it done*/ 148 149 REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 1, 150 1, 11); 151 152 set_reg_field_value( 153 value, 154 0, 155 AUX_CONTROL, 156 AUX_RESET); 157 158 REG_WRITE(AUX_CONTROL, value); 159 160 REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 0, 161 1, 11); 162 } 163 } /*if (field)*/ 164 165 /* request SW to access AUX */ 166 REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_USE_AUX_REG_REQ, 1); 167 168 value = REG_READ(AUX_ARB_CONTROL); 169 field = get_reg_field_value( 170 value, 171 AUX_ARB_CONTROL, 172 AUX_REG_RW_CNTL_STATUS); 173 174 return (field == SW_CAN_ACCESS_AUX); 175} 176 177#define COMPOSE_AUX_SW_DATA_16_20(command, address) \ 178 ((command) | ((0xF0000 & (address)) >> 16)) 179 180#define COMPOSE_AUX_SW_DATA_8_15(address) \ 181 ((0xFF00 & (address)) >> 8) 182 183#define COMPOSE_AUX_SW_DATA_0_7(address) \ 184 (0xFF & (address)) 185 186static void submit_channel_request( 187 struct dce_aux *engine, 188 struct aux_request_transaction_data *request) 189{ 190 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); 191 uint32_t value; 192 uint32_t length; 193 194 bool is_write = 195 ((request->type == AUX_TRANSACTION_TYPE_DP) && 196 (request->action == I2CAUX_TRANSACTION_ACTION_DP_WRITE)) || 197 ((request->type == AUX_TRANSACTION_TYPE_I2C) && 198 ((request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) || 199 (request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT))); 200 if (REG(AUXN_IMPCAL)) { 201 /* clear_aux_error */ 202 REG_UPDATE_SEQ_2(AUXN_IMPCAL, 203 AUXN_CALOUT_ERROR_AK, 1, 204 AUXN_CALOUT_ERROR_AK, 0); 205 206 REG_UPDATE_SEQ_2(AUXP_IMPCAL, 207 AUXP_CALOUT_ERROR_AK, 1, 208 AUXP_CALOUT_ERROR_AK, 0); 209 210 /* force_default_calibrate */ 211 REG_UPDATE_SEQ_2(AUXN_IMPCAL, 212 AUXN_IMPCAL_ENABLE, 1, 213 AUXN_IMPCAL_OVERRIDE_ENABLE, 0); 214 215 /* bug? why AUXN update EN and OVERRIDE_EN 1 by 1 while AUX P toggles OVERRIDE? */ 216 217 REG_UPDATE_SEQ_2(AUXP_IMPCAL, 218 AUXP_IMPCAL_OVERRIDE_ENABLE, 1, 219 AUXP_IMPCAL_OVERRIDE_ENABLE, 0); 220 } 221 222 REG_UPDATE(AUX_INTERRUPT_CONTROL, AUX_SW_DONE_ACK, 1); 223 224 REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 0, 225 10, aux110->polling_timeout_period/10); 226 227 /* set the delay and the number of bytes to write */ 228 229 /* The length include 230 * the 4 bit header and the 20 bit address 231 * (that is 3 byte). 232 * If the requested length is non zero this means 233 * an addition byte specifying the length is required. 234 */ 235 236 length = request->length ? 4 : 3; 237 if (is_write) 238 length += request->length; 239 240 REG_UPDATE_2(AUX_SW_CONTROL, 241 AUX_SW_START_DELAY, request->delay, 242 AUX_SW_WR_BYTES, length); 243 244 /* program action and address and payload data (if 'is_write') */ 245 value = REG_UPDATE_4(AUX_SW_DATA, 246 AUX_SW_INDEX, 0, 247 AUX_SW_DATA_RW, 0, 248 AUX_SW_AUTOINCREMENT_DISABLE, 1, 249 AUX_SW_DATA, COMPOSE_AUX_SW_DATA_16_20(request->action, request->address)); 250 251 value = REG_SET_2(AUX_SW_DATA, value, 252 AUX_SW_AUTOINCREMENT_DISABLE, 0, 253 AUX_SW_DATA, COMPOSE_AUX_SW_DATA_8_15(request->address)); 254 255 value = REG_SET(AUX_SW_DATA, value, 256 AUX_SW_DATA, COMPOSE_AUX_SW_DATA_0_7(request->address)); 257 258 if (request->length) { 259 value = REG_SET(AUX_SW_DATA, value, 260 AUX_SW_DATA, request->length - 1); 261 } 262 263 if (is_write) { 264 /* Load the HW buffer with the Data to be sent. 265 * This is relevant for write operation. 266 * For read, the data recived data will be 267 * processed in process_channel_reply(). 268 */ 269 uint32_t i = 0; 270 271 while (i < request->length) { 272 value = REG_SET(AUX_SW_DATA, value, 273 AUX_SW_DATA, request->data[i]); 274 275 ++i; 276 } 277 } 278 279 REG_UPDATE(AUX_SW_CONTROL, AUX_SW_GO, 1); 280 EVENT_LOG_AUX_REQ(engine->ddc->pin_data->en, EVENT_LOG_AUX_ORIGIN_NATIVE, 281 request->action, request->address, request->length, request->data); 282} 283 284static int read_channel_reply(struct dce_aux *engine, uint32_t size, 285 uint8_t *buffer, uint8_t *reply_result, 286 uint32_t *sw_status) 287{ 288 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); 289 uint32_t bytes_replied; 290 uint32_t reply_result_32; 291 292 *sw_status = REG_GET(AUX_SW_STATUS, AUX_SW_REPLY_BYTE_COUNT, 293 &bytes_replied); 294 295 /* In case HPD is LOW, exit AUX transaction */ 296 if ((*sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) 297 return -1; 298 299 /* Need at least the status byte */ 300 if (!bytes_replied) 301 return -1; 302 303 REG_UPDATE_SEQ_3(AUX_SW_DATA, 304 AUX_SW_INDEX, 0, 305 AUX_SW_AUTOINCREMENT_DISABLE, 1, 306 AUX_SW_DATA_RW, 1); 307 308 REG_GET(AUX_SW_DATA, AUX_SW_DATA, &reply_result_32); 309 reply_result_32 = reply_result_32 >> 4; 310 if (reply_result != NULL) 311 *reply_result = (uint8_t)reply_result_32; 312 313 if (reply_result_32 == 0) { /* ACK */ 314 uint32_t i = 0; 315 316 /* First byte was already used to get the command status */ 317 --bytes_replied; 318 319 /* Do not overflow buffer */ 320 if (bytes_replied > size) 321 return -1; 322 323 while (i < bytes_replied) { 324 uint32_t aux_sw_data_val; 325 326 REG_GET(AUX_SW_DATA, AUX_SW_DATA, &aux_sw_data_val); 327 buffer[i] = aux_sw_data_val; 328 ++i; 329 } 330 331 return i; 332 } 333 334 return 0; 335} 336 337static enum aux_return_code_type get_channel_status( 338 struct dce_aux *engine, 339 uint8_t *returned_bytes) 340{ 341 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); 342 343 uint32_t value; 344 345 if (returned_bytes == NULL) { 346 /*caller pass NULL pointer*/ 347 ASSERT_CRITICAL(false); 348 return AUX_RET_ERROR_UNKNOWN; 349 } 350 *returned_bytes = 0; 351 352 /* poll to make sure that SW_DONE is asserted */ 353 REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 1, 354 10, aux110->polling_timeout_period/10); 355 356 value = REG_READ(AUX_SW_STATUS); 357 /* in case HPD is LOW, exit AUX transaction */ 358 if ((value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) 359 return AUX_RET_ERROR_HPD_DISCON; 360 361 /* Note that the following bits are set in 'status.bits' 362 * during CTS 4.2.1.2 (FW 3.3.1): 363 * AUX_SW_RX_MIN_COUNT_VIOL, AUX_SW_RX_INVALID_STOP, 364 * AUX_SW_RX_RECV_NO_DET, AUX_SW_RX_RECV_INVALID_H. 365 * 366 * AUX_SW_RX_MIN_COUNT_VIOL is an internal, 367 * HW debugging bit and should be ignored. 368 */ 369 if (value & AUX_SW_STATUS__AUX_SW_DONE_MASK) { 370 if ((value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_STATE_MASK) || 371 (value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_MASK)) 372 return AUX_RET_ERROR_TIMEOUT; 373 374 else if ((value & AUX_SW_STATUS__AUX_SW_RX_INVALID_STOP_MASK) || 375 (value & AUX_SW_STATUS__AUX_SW_RX_RECV_NO_DET_MASK) || 376 (value & 377 AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_H_MASK) || 378 (value & AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_L_MASK)) 379 return AUX_RET_ERROR_INVALID_REPLY; 380 381 *returned_bytes = get_reg_field_value(value, 382 AUX_SW_STATUS, 383 AUX_SW_REPLY_BYTE_COUNT); 384 385 if (*returned_bytes == 0) 386 return 387 AUX_RET_ERROR_INVALID_REPLY; 388 else { 389 *returned_bytes -= 1; 390 return AUX_RET_SUCCESS; 391 } 392 } else { 393 /*time_elapsed >= aux_engine->timeout_period 394 * AUX_SW_STATUS__AUX_SW_HPD_DISCON = at this point 395 */ 396 ASSERT_CRITICAL(false); 397 return AUX_RET_ERROR_TIMEOUT; 398 } 399} 400 401static bool acquire( 402 struct dce_aux *engine, 403 struct ddc *ddc) 404{ 405 enum gpio_result result; 406 407 if ((engine == NULL) || !is_engine_available(engine)) 408 return false; 409 410 result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE, 411 GPIO_DDC_CONFIG_TYPE_MODE_AUX); 412 413 if (result != GPIO_RESULT_OK) 414 return false; 415 416 if (!acquire_engine(engine)) { 417 engine->ddc = ddc; 418 release_engine(engine); 419 return false; 420 } 421 422 engine->ddc = ddc; 423 424 return true; 425} 426 427void dce110_engine_destroy(struct dce_aux **engine) 428{ 429 430 struct aux_engine_dce110 *engine110 = FROM_AUX_ENGINE(*engine); 431 432 kfree(engine110); 433 *engine = NULL; 434 435} 436 437static uint32_t dce_aux_configure_timeout(struct ddc_service *ddc, 438 uint32_t timeout_in_us) 439{ 440 uint32_t multiplier = 0; 441 uint32_t length = 0; 442 uint32_t prev_length = 0; 443 uint32_t prev_mult = 0; 444 uint32_t prev_timeout_val = 0; 445 struct ddc *ddc_pin = ddc->ddc_pin; 446 struct dce_aux *aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]; 447 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(aux_engine); 448 449 /* 1-Update polling timeout period */ 450 aux110->polling_timeout_period = timeout_in_us * SW_AUX_TIMEOUT_PERIOD_MULTIPLIER; 451 452 /* 2-Update aux timeout period length and multiplier */ 453 if (timeout_in_us == 0) { 454 multiplier = DEFAULT_AUX_ENGINE_MULT; 455 length = DEFAULT_AUX_ENGINE_LENGTH; 456 } else if (timeout_in_us <= TIME_OUT_INCREMENT) { 457 multiplier = 0; 458 length = timeout_in_us/TIME_OUT_MULTIPLIER_8; 459 if (timeout_in_us % TIME_OUT_MULTIPLIER_8 != 0) 460 length++; 461 } else if (timeout_in_us <= 2 * TIME_OUT_INCREMENT) { 462 multiplier = 1; 463 length = timeout_in_us/TIME_OUT_MULTIPLIER_16; 464 if (timeout_in_us % TIME_OUT_MULTIPLIER_16 != 0) 465 length++; 466 } else if (timeout_in_us <= 4 * TIME_OUT_INCREMENT) { 467 multiplier = 2; 468 length = timeout_in_us/TIME_OUT_MULTIPLIER_32; 469 if (timeout_in_us % TIME_OUT_MULTIPLIER_32 != 0) 470 length++; 471 } else if (timeout_in_us > 4 * TIME_OUT_INCREMENT) { 472 multiplier = 3; 473 length = timeout_in_us/TIME_OUT_MULTIPLIER_64; 474 if (timeout_in_us % TIME_OUT_MULTIPLIER_64 != 0) 475 length++; 476 } 477 478 length = (length < MAX_TIMEOUT_LENGTH) ? length : MAX_TIMEOUT_LENGTH; 479 480 REG_GET_2(AUX_DPHY_RX_CONTROL1, AUX_RX_TIMEOUT_LEN, &prev_length, AUX_RX_TIMEOUT_LEN_MUL, &prev_mult); 481 482 switch (prev_mult) { 483 case 0: 484 prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_8; 485 break; 486 case 1: 487 prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_16; 488 break; 489 case 2: 490 prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_32; 491 break; 492 case 3: 493 prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_64; 494 break; 495 default: 496 prev_timeout_val = DEFAULT_AUX_ENGINE_LENGTH * TIME_OUT_MULTIPLIER_8; 497 break; 498 } 499 500 REG_UPDATE_SEQ_2(AUX_DPHY_RX_CONTROL1, AUX_RX_TIMEOUT_LEN, length, AUX_RX_TIMEOUT_LEN_MUL, multiplier); 501 502 return prev_timeout_val; 503} 504 505static struct dce_aux_funcs aux_functions = { 506 .configure_timeout = NULL, 507 .destroy = NULL, 508}; 509 510struct dce_aux *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_engine110, 511 struct dc_context *ctx, 512 uint32_t inst, 513 uint32_t timeout_period, 514 const struct dce110_aux_registers *regs, 515 const struct dce110_aux_registers_mask *mask, 516 const struct dce110_aux_registers_shift *shift, 517 bool is_ext_aux_timeout_configurable) 518{ 519 aux_engine110->base.ddc = NULL; 520 aux_engine110->base.ctx = ctx; 521 aux_engine110->base.delay = 0; 522 aux_engine110->base.max_defer_write_retry = 0; 523 aux_engine110->base.inst = inst; 524 aux_engine110->polling_timeout_period = timeout_period; 525 aux_engine110->regs = regs; 526 527 aux_engine110->mask = mask; 528 aux_engine110->shift = shift; 529 aux_engine110->base.funcs = &aux_functions; 530 if (is_ext_aux_timeout_configurable) 531 aux_engine110->base.funcs->configure_timeout = &dce_aux_configure_timeout; 532 533 return &aux_engine110->base; 534} 535 536static enum i2caux_transaction_action i2caux_action_from_payload(struct aux_payload *payload) 537{ 538 if (payload->i2c_over_aux) { 539 if (payload->write_status_update) { 540 if (payload->mot) 541 return I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT; 542 else 543 return I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST; 544 } 545 if (payload->write) { 546 if (payload->mot) 547 return I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT; 548 else 549 return I2CAUX_TRANSACTION_ACTION_I2C_WRITE; 550 } 551 if (payload->mot) 552 return I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT; 553 554 return I2CAUX_TRANSACTION_ACTION_I2C_READ; 555 } 556 if (payload->write) 557 return I2CAUX_TRANSACTION_ACTION_DP_WRITE; 558 559 return I2CAUX_TRANSACTION_ACTION_DP_READ; 560} 561 562int dce_aux_transfer_raw(struct ddc_service *ddc, 563 struct aux_payload *payload, 564 enum aux_return_code_type *operation_result) 565{ 566 struct ddc *ddc_pin = ddc->ddc_pin; 567 struct dce_aux *aux_engine; 568 struct aux_request_transaction_data aux_req; 569 uint8_t returned_bytes = 0; 570 int res = -1; 571 uint32_t status; 572 573 memset(&aux_req, 0, sizeof(aux_req)); 574 575 aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]; 576 if (!acquire(aux_engine, ddc_pin)) { 577 *operation_result = AUX_RET_ERROR_ENGINE_ACQUIRE; 578 return -1; 579 } 580 581 if (payload->i2c_over_aux) 582 aux_req.type = AUX_TRANSACTION_TYPE_I2C; 583 else 584 aux_req.type = AUX_TRANSACTION_TYPE_DP; 585 586 aux_req.action = i2caux_action_from_payload(payload); 587 588 aux_req.address = payload->address; 589 aux_req.delay = 0; 590 aux_req.length = payload->length; 591 aux_req.data = payload->data; 592 593 submit_channel_request(aux_engine, &aux_req); 594 *operation_result = get_channel_status(aux_engine, &returned_bytes); 595 596 if (*operation_result == AUX_RET_SUCCESS) { 597 int __maybe_unused bytes_replied = 0; 598 599 bytes_replied = read_channel_reply(aux_engine, payload->length, 600 payload->data, payload->reply, 601 &status); 602 EVENT_LOG_AUX_REP(aux_engine->ddc->pin_data->en, 603 EVENT_LOG_AUX_ORIGIN_NATIVE, *payload->reply, 604 bytes_replied, payload->data); 605 res = returned_bytes; 606 } else { 607 res = -1; 608 } 609 610 release_engine(aux_engine); 611 return res; 612} 613 614int dce_aux_transfer_dmub_raw(struct ddc_service *ddc, 615 struct aux_payload *payload, 616 enum aux_return_code_type *operation_result) 617{ 618 struct ddc *ddc_pin = ddc->ddc_pin; 619 620 if (ddc_pin != NULL) { 621 struct dce_aux *aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]; 622 /* XXX: Workaround to configure ddc channels for aux transactions */ 623 if (!acquire(aux_engine, ddc_pin)) { 624 *operation_result = AUX_RET_ERROR_ENGINE_ACQUIRE; 625 return -1; 626 } 627 release_engine(aux_engine); 628 } 629 630 return dm_helper_dmub_aux_transfer_sync(ddc->ctx, ddc->link, payload, operation_result); 631} 632 633#define AUX_MAX_RETRIES 7 634#define AUX_MIN_DEFER_RETRIES 7 635#define AUX_MAX_DEFER_TIMEOUT_MS 50 636#define AUX_MAX_I2C_DEFER_RETRIES 7 637#define AUX_MAX_INVALID_REPLY_RETRIES 2 638#define AUX_MAX_TIMEOUT_RETRIES 3 639#define AUX_DEFER_DELAY_FOR_DPIA 4 /*ms*/ 640 641static void dce_aux_log_payload(const char *payload_name, 642 unsigned char *payload, uint32_t length, uint32_t max_length_to_log) 643{ 644 if (!IS_DC_I2CAUX_LOGGING_ENABLED()) 645 return; 646 647 if (payload && length) { 648 char hex_str[128] = {0}; 649 char *hex_str_ptr = &hex_str[0]; 650 uint32_t hex_str_remaining = sizeof(hex_str); 651 unsigned char *payload_ptr = payload; 652 unsigned char *payload_max_to_log_ptr = payload_ptr + min(max_length_to_log, length); 653 unsigned int count; 654 char *padding = ""; 655 656 while (payload_ptr < payload_max_to_log_ptr) { 657 count = snprintf_count(hex_str_ptr, hex_str_remaining, "%s%02X", padding, *payload_ptr); 658 padding = " "; 659 hex_str_remaining -= count; 660 hex_str_ptr += count; 661 payload_ptr++; 662 } 663 664 count = snprintf_count(hex_str_ptr, hex_str_remaining, " "); 665 hex_str_remaining -= count; 666 hex_str_ptr += count; 667 668 payload_ptr = payload; 669 while (payload_ptr < payload_max_to_log_ptr) { 670 count = snprintf_count(hex_str_ptr, hex_str_remaining, "%c", 671 *payload_ptr >= ' ' ? *payload_ptr : '.'); 672 hex_str_remaining -= count; 673 hex_str_ptr += count; 674 payload_ptr++; 675 } 676 677 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_VERBOSE, 678 LOG_FLAG_I2cAux_DceAux, 679 "dce_aux_log_payload: %s: length=%u: data: %s%s", 680 payload_name, 681 length, 682 hex_str, 683 (length > max_length_to_log ? " (...)" : " ")); 684 } else { 685 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_VERBOSE, 686 LOG_FLAG_I2cAux_DceAux, 687 "dce_aux_log_payload: %s: length=%u: data: <empty payload>", 688 payload_name, 689 length); 690 } 691} 692 693bool dce_aux_transfer_with_retries(struct ddc_service *ddc, 694 struct aux_payload *payload) 695{ 696 int i, ret = 0; 697 uint8_t reply; 698 bool payload_reply = true; 699 enum aux_return_code_type operation_result; 700 bool retry_on_defer = false; 701 struct ddc *ddc_pin = ddc->ddc_pin; 702 struct dce_aux *aux_engine = NULL; 703 struct aux_engine_dce110 *aux110 = NULL; 704 uint32_t defer_time_in_ms = 0; 705 706 int aux_ack_retries = 0, 707 aux_defer_retries = 0, 708 aux_i2c_defer_retries = 0, 709 aux_timeout_retries = 0, 710 aux_invalid_reply_retries = 0, 711 aux_ack_m_retries = 0; 712 713 if (ddc_pin) { 714 aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]; 715 aux110 = FROM_AUX_ENGINE(aux_engine); 716 } 717 718 if (!payload->reply) { 719 payload_reply = false; 720 payload->reply = &reply; 721 } 722 723 for (i = 0; i < AUX_MAX_RETRIES; i++) { 724 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION, 725 LOG_FLAG_I2cAux_DceAux, 726 "dce_aux_transfer_with_retries: link_index=%u: START: retry %d of %d: address=0x%04x length=%u write=%d mot=%d", 727 ddc && ddc->link ? ddc->link->link_index : UINT_MAX, 728 i + 1, 729 (int)AUX_MAX_RETRIES, 730 payload->address, 731 payload->length, 732 (unsigned int) payload->write, 733 (unsigned int) payload->mot); 734 if (payload->write) 735 dce_aux_log_payload(" write", payload->data, payload->length, 16); 736 ret = dce_aux_transfer_raw(ddc, payload, &operation_result); 737 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION, 738 LOG_FLAG_I2cAux_DceAux, 739 "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", 740 ddc && ddc->link ? ddc->link->link_index : UINT_MAX, 741 i + 1, 742 (int)AUX_MAX_RETRIES, 743 payload->address, 744 payload->length, 745 (unsigned int) payload->write, 746 (unsigned int) payload->mot, 747 ret, 748 (int)operation_result, 749 (unsigned int) *payload->reply); 750 if (!payload->write) 751 dce_aux_log_payload(" read", payload->data, ret > 0 ? ret : 0, 16); 752 753 switch (operation_result) { 754 case AUX_RET_SUCCESS: 755 aux_timeout_retries = 0; 756 aux_invalid_reply_retries = 0; 757 758 switch (*payload->reply) { 759 case AUX_TRANSACTION_REPLY_AUX_ACK: 760 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION, 761 LOG_FLAG_I2cAux_DceAux, 762 "dce_aux_transfer_with_retries: AUX_RET_SUCCESS: AUX_TRANSACTION_REPLY_AUX_ACK"); 763 if (!payload->write && payload->length != ret) { 764 if (++aux_ack_retries >= AUX_MAX_RETRIES) { 765 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 766 LOG_FLAG_Error_I2cAux, 767 "dce_aux_transfer_with_retries: FAILURE: aux_ack_retries=%d >= AUX_MAX_RETRIES=%d", 768 aux_defer_retries, 769 AUX_MAX_RETRIES); 770 goto fail; 771 } else 772 udelay(300); 773 } else if (payload->write && ret > 0) { 774 /* sink requested more time to complete the write via AUX_ACKM */ 775 if (++aux_ack_m_retries >= AUX_MAX_RETRIES) { 776 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 777 LOG_FLAG_Error_I2cAux, 778 "dce_aux_transfer_with_retries: FAILURE: aux_ack_m_retries=%d >= AUX_MAX_RETRIES=%d", 779 aux_ack_m_retries, 780 AUX_MAX_RETRIES); 781 goto fail; 782 } 783 784 /* retry reading the write status until complete 785 * NOTE: payload is modified here 786 */ 787 payload->write = false; 788 payload->write_status_update = true; 789 payload->length = 0; 790 udelay(300); 791 792 } else 793 return true; 794 break; 795 796 case AUX_TRANSACTION_REPLY_AUX_DEFER: 797 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION, 798 LOG_FLAG_I2cAux_DceAux, 799 "dce_aux_transfer_with_retries: AUX_RET_SUCCESS: AUX_TRANSACTION_REPLY_AUX_DEFER"); 800 801 /* polling_timeout_period is in us */ 802 if (aux110) 803 defer_time_in_ms += aux110->polling_timeout_period / 1000; 804 else 805 defer_time_in_ms += AUX_DEFER_DELAY_FOR_DPIA; 806 ++aux_defer_retries; 807 fallthrough; 808 case AUX_TRANSACTION_REPLY_I2C_OVER_AUX_DEFER: 809 if (*payload->reply == AUX_TRANSACTION_REPLY_I2C_OVER_AUX_DEFER) 810 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION, 811 LOG_FLAG_I2cAux_DceAux, 812 "dce_aux_transfer_with_retries: AUX_RET_SUCCESS: AUX_TRANSACTION_REPLY_I2C_OVER_AUX_DEFER"); 813 814 retry_on_defer = true; 815 fallthrough; 816 case AUX_TRANSACTION_REPLY_I2C_OVER_AUX_NACK: 817 if (*payload->reply == AUX_TRANSACTION_REPLY_I2C_OVER_AUX_NACK) 818 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION, 819 LOG_FLAG_I2cAux_DceAux, 820 "dce_aux_transfer_with_retries: AUX_RET_SUCCESS: AUX_TRANSACTION_REPLY_I2C_OVER_AUX_NACK"); 821 822 if (aux_defer_retries >= AUX_MIN_DEFER_RETRIES 823 && defer_time_in_ms >= AUX_MAX_DEFER_TIMEOUT_MS) { 824 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 825 LOG_FLAG_Error_I2cAux, 826 "dce_aux_transfer_with_retries: FAILURE: aux_defer_retries=%d >= AUX_MIN_DEFER_RETRIES=%d && defer_time_in_ms=%d >= AUX_MAX_DEFER_TIMEOUT_MS=%d", 827 aux_defer_retries, 828 AUX_MIN_DEFER_RETRIES, 829 defer_time_in_ms, 830 AUX_MAX_DEFER_TIMEOUT_MS); 831 goto fail; 832 } else { 833 if ((*payload->reply == AUX_TRANSACTION_REPLY_AUX_DEFER) || 834 (*payload->reply == AUX_TRANSACTION_REPLY_I2C_OVER_AUX_DEFER)) { 835 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION, 836 LOG_FLAG_I2cAux_DceAux, 837 "dce_aux_transfer_with_retries: payload->defer_delay=%u", 838 payload->defer_delay); 839 if (payload->defer_delay > 1) { 840 msleep(payload->defer_delay); 841 defer_time_in_ms += payload->defer_delay; 842 } else if (payload->defer_delay <= 1) { 843 udelay(payload->defer_delay * 1000); 844 defer_time_in_ms += payload->defer_delay; 845 } 846 } 847 } 848 break; 849 850 case AUX_TRANSACTION_REPLY_I2C_DEFER: 851 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION, 852 LOG_FLAG_I2cAux_DceAux, 853 "dce_aux_transfer_with_retries: AUX_RET_SUCCESS: AUX_TRANSACTION_REPLY_I2C_DEFER"); 854 855 aux_defer_retries = 0; 856 if (++aux_i2c_defer_retries >= AUX_MAX_I2C_DEFER_RETRIES) { 857 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 858 LOG_FLAG_Error_I2cAux, 859 "dce_aux_transfer_with_retries: FAILURE: aux_i2c_defer_retries=%d >= AUX_MAX_I2C_DEFER_RETRIES=%d", 860 aux_i2c_defer_retries, 861 AUX_MAX_I2C_DEFER_RETRIES); 862 goto fail; 863 } 864 break; 865 866 case AUX_TRANSACTION_REPLY_AUX_NACK: 867 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION, 868 LOG_FLAG_I2cAux_DceAux, 869 "dce_aux_transfer_with_retries: AUX_RET_SUCCESS: AUX_TRANSACTION_REPLY_AUX_NACK"); 870 goto fail; 871 872 case AUX_TRANSACTION_REPLY_HPD_DISCON: 873 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION, 874 LOG_FLAG_I2cAux_DceAux, 875 "dce_aux_transfer_with_retries: AUX_RET_SUCCESS: AUX_TRANSACTION_REPLY_HPD_DISCON"); 876 goto fail; 877 878 default: 879 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 880 LOG_FLAG_Error_I2cAux, 881 "dce_aux_transfer_with_retries: AUX_RET_SUCCESS: FAILURE: AUX_TRANSACTION_REPLY_* unknown, default case. Reply: %d", *payload->reply); 882 goto fail; 883 } 884 break; 885 886 case AUX_RET_ERROR_INVALID_REPLY: 887 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION, 888 LOG_FLAG_I2cAux_DceAux, 889 "dce_aux_transfer_with_retries: AUX_RET_ERROR_INVALID_REPLY"); 890 if (++aux_invalid_reply_retries >= AUX_MAX_INVALID_REPLY_RETRIES) { 891 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 892 LOG_FLAG_Error_I2cAux, 893 "dce_aux_transfer_with_retries: FAILURE: aux_invalid_reply_retries=%d >= AUX_MAX_INVALID_REPLY_RETRIES=%d", 894 aux_invalid_reply_retries, 895 AUX_MAX_INVALID_REPLY_RETRIES); 896 goto fail; 897 } else 898 udelay(400); 899 break; 900 901 case AUX_RET_ERROR_TIMEOUT: 902 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION, 903 LOG_FLAG_I2cAux_DceAux, 904 "dce_aux_transfer_with_retries: AUX_RET_ERROR_TIMEOUT"); 905 // Check whether a DEFER had occurred before the timeout. 906 // If so, treat timeout as a DEFER. 907 if (retry_on_defer) { 908 if (++aux_defer_retries >= AUX_MIN_DEFER_RETRIES) { 909 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 910 LOG_FLAG_Error_I2cAux, 911 "dce_aux_transfer_with_retries: FAILURE: aux_defer_retries=%d >= AUX_MIN_DEFER_RETRIES=%d", 912 aux_defer_retries, 913 AUX_MIN_DEFER_RETRIES); 914 goto fail; 915 } else if (payload->defer_delay > 0) { 916 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION, 917 LOG_FLAG_I2cAux_DceAux, 918 "dce_aux_transfer_with_retries: payload->defer_delay=%u", 919 payload->defer_delay); 920 msleep(payload->defer_delay); 921 } 922 } else { 923 if (++aux_timeout_retries >= AUX_MAX_TIMEOUT_RETRIES) { 924 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 925 LOG_FLAG_Error_I2cAux, 926 "dce_aux_transfer_with_retries: FAILURE: aux_timeout_retries=%d >= AUX_MAX_TIMEOUT_RETRIES=%d", 927 aux_timeout_retries, 928 AUX_MAX_TIMEOUT_RETRIES); 929 goto fail; 930 } else { 931 /* 932 * DP 1.4, 2.8.2: AUX Transaction Response/Reply Timeouts 933 * According to the DP spec there should be 3 retries total 934 * with a 400us wait inbetween each. Hardware already waits 935 * for 550us therefore no wait is required here. 936 */ 937 } 938 } 939 break; 940 941 case AUX_RET_ERROR_HPD_DISCON: 942 case AUX_RET_ERROR_ENGINE_ACQUIRE: 943 case AUX_RET_ERROR_UNKNOWN: 944 default: 945 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION, 946 LOG_FLAG_I2cAux_DceAux, 947 "dce_aux_transfer_with_retries: Failure: operation_result=%d", 948 (int)operation_result); 949 goto fail; 950 } 951 } 952 953fail: 954 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 955 LOG_FLAG_Error_I2cAux, 956 "dce_aux_transfer_with_retries: FAILURE"); 957 if (!payload_reply) 958 payload->reply = NULL; 959 960 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 961 WPP_BIT_FLAG_DC_ERROR, 962 "AUX transaction failed. Result: %d", 963 operation_result); 964 965 return false; 966}