linux/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c
<<
>>
Prefs
   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
  35#define CTX \
  36        aux110->base.ctx
  37#define REG(reg_name)\
  38        (aux110->regs->reg_name)
  39
  40#define DC_LOGGER \
  41        engine->ctx->logger
  42
  43#include "reg_helper.h"
  44
  45#undef FN
  46#define FN(reg_name, field_name) \
  47        aux110->shift->field_name, aux110->mask->field_name
  48
  49#define FROM_AUX_ENGINE(ptr) \
  50        container_of((ptr), struct aux_engine_dce110, base)
  51
  52#define FROM_ENGINE(ptr) \
  53        FROM_AUX_ENGINE(container_of((ptr), struct dce_aux, base))
  54
  55#define FROM_AUX_ENGINE_ENGINE(ptr) \
  56        container_of((ptr), struct dce_aux, base)
  57enum {
  58        AUX_INVALID_REPLY_RETRY_COUNTER = 1,
  59        AUX_TIMED_OUT_RETRY_COUNTER = 2,
  60        AUX_DEFER_RETRY_COUNTER = 6
  61};
  62
  63#define TIME_OUT_INCREMENT        1016
  64#define TIME_OUT_MULTIPLIER_8     8
  65#define TIME_OUT_MULTIPLIER_16    16
  66#define TIME_OUT_MULTIPLIER_32    32
  67#define TIME_OUT_MULTIPLIER_64    64
  68#define MAX_TIMEOUT_LENGTH        127
  69#define DEFAULT_AUX_ENGINE_MULT   0
  70#define DEFAULT_AUX_ENGINE_LENGTH 69
  71
  72static void release_engine(
  73        struct dce_aux *engine)
  74{
  75        struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
  76
  77        dal_ddc_close(engine->ddc);
  78
  79        engine->ddc = NULL;
  80
  81        REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_DONE_USING_AUX_REG, 1);
  82}
  83
  84#define SW_CAN_ACCESS_AUX 1
  85#define DMCU_CAN_ACCESS_AUX 2
  86
  87static bool is_engine_available(
  88        struct dce_aux *engine)
  89{
  90        struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
  91
  92        uint32_t value = REG_READ(AUX_ARB_CONTROL);
  93        uint32_t field = get_reg_field_value(
  94                        value,
  95                        AUX_ARB_CONTROL,
  96                        AUX_REG_RW_CNTL_STATUS);
  97
  98        return (field != DMCU_CAN_ACCESS_AUX);
  99}
 100static bool acquire_engine(
 101        struct dce_aux *engine)
 102{
 103        struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
 104
 105        uint32_t value = REG_READ(AUX_ARB_CONTROL);
 106        uint32_t field = get_reg_field_value(
 107                        value,
 108                        AUX_ARB_CONTROL,
 109                        AUX_REG_RW_CNTL_STATUS);
 110        if (field == DMCU_CAN_ACCESS_AUX)
 111                return false;
 112        /* enable AUX before request SW to access AUX */
 113        value = REG_READ(AUX_CONTROL);
 114        field = get_reg_field_value(value,
 115                                AUX_CONTROL,
 116                                AUX_EN);
 117
 118        if (field == 0) {
 119                set_reg_field_value(
 120                                value,
 121                                1,
 122                                AUX_CONTROL,
 123                                AUX_EN);
 124
 125                if (REG(AUX_RESET_MASK)) {
 126                        /*DP_AUX block as part of the enable sequence*/
 127                        set_reg_field_value(
 128                                value,
 129                                1,
 130                                AUX_CONTROL,
 131                                AUX_RESET);
 132                }
 133
 134                REG_WRITE(AUX_CONTROL, value);
 135
 136                if (REG(AUX_RESET_MASK)) {
 137                        /*poll HW to make sure reset it done*/
 138
 139                        REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 1,
 140                                        1, 11);
 141
 142                        set_reg_field_value(
 143                                value,
 144                                0,
 145                                AUX_CONTROL,
 146                                AUX_RESET);
 147
 148                        REG_WRITE(AUX_CONTROL, value);
 149
 150                        REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 0,
 151                                        1, 11);
 152                }
 153        } /*if (field)*/
 154
 155        /* request SW to access AUX */
 156        REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_USE_AUX_REG_REQ, 1);
 157
 158        value = REG_READ(AUX_ARB_CONTROL);
 159        field = get_reg_field_value(
 160                        value,
 161                        AUX_ARB_CONTROL,
 162                        AUX_REG_RW_CNTL_STATUS);
 163
 164        return (field == SW_CAN_ACCESS_AUX);
 165}
 166
 167#define COMPOSE_AUX_SW_DATA_16_20(command, address) \
 168        ((command) | ((0xF0000 & (address)) >> 16))
 169
 170#define COMPOSE_AUX_SW_DATA_8_15(address) \
 171        ((0xFF00 & (address)) >> 8)
 172
 173#define COMPOSE_AUX_SW_DATA_0_7(address) \
 174        (0xFF & (address))
 175
 176static void submit_channel_request(
 177        struct dce_aux *engine,
 178        struct aux_request_transaction_data *request)
 179{
 180        struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
 181        uint32_t value;
 182        uint32_t length;
 183
 184        bool is_write =
 185                ((request->type == AUX_TRANSACTION_TYPE_DP) &&
 186                 (request->action == I2CAUX_TRANSACTION_ACTION_DP_WRITE)) ||
 187                ((request->type == AUX_TRANSACTION_TYPE_I2C) &&
 188                ((request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) ||
 189                 (request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT)));
 190        if (REG(AUXN_IMPCAL)) {
 191                /* clear_aux_error */
 192                REG_UPDATE_SEQ_2(AUXN_IMPCAL,
 193                                AUXN_CALOUT_ERROR_AK, 1,
 194                                AUXN_CALOUT_ERROR_AK, 0);
 195
 196                REG_UPDATE_SEQ_2(AUXP_IMPCAL,
 197                                AUXP_CALOUT_ERROR_AK, 1,
 198                                AUXP_CALOUT_ERROR_AK, 0);
 199
 200                /* force_default_calibrate */
 201                REG_UPDATE_SEQ_2(AUXN_IMPCAL,
 202                                AUXN_IMPCAL_ENABLE, 1,
 203                                AUXN_IMPCAL_OVERRIDE_ENABLE, 0);
 204
 205                /* bug? why AUXN update EN and OVERRIDE_EN 1 by 1 while AUX P toggles OVERRIDE? */
 206
 207                REG_UPDATE_SEQ_2(AUXP_IMPCAL,
 208                                AUXP_IMPCAL_OVERRIDE_ENABLE, 1,
 209                                AUXP_IMPCAL_OVERRIDE_ENABLE, 0);
 210        }
 211
 212        REG_UPDATE(AUX_INTERRUPT_CONTROL, AUX_SW_DONE_ACK, 1);
 213
 214        REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 0,
 215                                10, aux110->polling_timeout_period/10);
 216
 217        /* set the delay and the number of bytes to write */
 218
 219        /* The length include
 220         * the 4 bit header and the 20 bit address
 221         * (that is 3 byte).
 222         * If the requested length is non zero this means
 223         * an addition byte specifying the length is required.
 224         */
 225
 226        length = request->length ? 4 : 3;
 227        if (is_write)
 228                length += request->length;
 229
 230        REG_UPDATE_2(AUX_SW_CONTROL,
 231                        AUX_SW_START_DELAY, request->delay,
 232                        AUX_SW_WR_BYTES, length);
 233
 234        /* program action and address and payload data (if 'is_write') */
 235        value = REG_UPDATE_4(AUX_SW_DATA,
 236                        AUX_SW_INDEX, 0,
 237                        AUX_SW_DATA_RW, 0,
 238                        AUX_SW_AUTOINCREMENT_DISABLE, 1,
 239                        AUX_SW_DATA, COMPOSE_AUX_SW_DATA_16_20(request->action, request->address));
 240
 241        value = REG_SET_2(AUX_SW_DATA, value,
 242                        AUX_SW_AUTOINCREMENT_DISABLE, 0,
 243                        AUX_SW_DATA, COMPOSE_AUX_SW_DATA_8_15(request->address));
 244
 245        value = REG_SET(AUX_SW_DATA, value,
 246                        AUX_SW_DATA, COMPOSE_AUX_SW_DATA_0_7(request->address));
 247
 248        if (request->length) {
 249                value = REG_SET(AUX_SW_DATA, value,
 250                                AUX_SW_DATA, request->length - 1);
 251        }
 252
 253        if (is_write) {
 254                /* Load the HW buffer with the Data to be sent.
 255                 * This is relevant for write operation.
 256                 * For read, the data recived data will be
 257                 * processed in process_channel_reply().
 258                 */
 259                uint32_t i = 0;
 260
 261                while (i < request->length) {
 262                        value = REG_SET(AUX_SW_DATA, value,
 263                                        AUX_SW_DATA, request->data[i]);
 264
 265                        ++i;
 266                }
 267        }
 268
 269        REG_UPDATE(AUX_SW_CONTROL, AUX_SW_GO, 1);
 270        EVENT_LOG_AUX_REQ(engine->ddc->pin_data->en, EVENT_LOG_AUX_ORIGIN_NATIVE,
 271                                        request->action, request->address, request->length, request->data);
 272}
 273
 274static int read_channel_reply(struct dce_aux *engine, uint32_t size,
 275                              uint8_t *buffer, uint8_t *reply_result,
 276                              uint32_t *sw_status)
 277{
 278        struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
 279        uint32_t bytes_replied;
 280        uint32_t reply_result_32;
 281
 282        *sw_status = REG_GET(AUX_SW_STATUS, AUX_SW_REPLY_BYTE_COUNT,
 283                             &bytes_replied);
 284
 285        /* In case HPD is LOW, exit AUX transaction */
 286        if ((*sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
 287                return -1;
 288
 289        /* Need at least the status byte */
 290        if (!bytes_replied)
 291                return -1;
 292
 293        REG_UPDATE_SEQ_3(AUX_SW_DATA,
 294                          AUX_SW_INDEX, 0,
 295                          AUX_SW_AUTOINCREMENT_DISABLE, 1,
 296                          AUX_SW_DATA_RW, 1);
 297
 298        REG_GET(AUX_SW_DATA, AUX_SW_DATA, &reply_result_32);
 299        reply_result_32 = reply_result_32 >> 4;
 300        if (reply_result != NULL)
 301                *reply_result = (uint8_t)reply_result_32;
 302
 303        if (reply_result_32 == 0) { /* ACK */
 304                uint32_t i = 0;
 305
 306                /* First byte was already used to get the command status */
 307                --bytes_replied;
 308
 309                /* Do not overflow buffer */
 310                if (bytes_replied > size)
 311                        return -1;
 312
 313                while (i < bytes_replied) {
 314                        uint32_t aux_sw_data_val;
 315
 316                        REG_GET(AUX_SW_DATA, AUX_SW_DATA, &aux_sw_data_val);
 317                        buffer[i] = aux_sw_data_val;
 318                        ++i;
 319                }
 320
 321                return i;
 322        }
 323
 324        return 0;
 325}
 326
 327static enum aux_channel_operation_result get_channel_status(
 328        struct dce_aux *engine,
 329        uint8_t *returned_bytes)
 330{
 331        struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
 332
 333        uint32_t value;
 334
 335        if (returned_bytes == NULL) {
 336                /*caller pass NULL pointer*/
 337                ASSERT_CRITICAL(false);
 338                return AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN;
 339        }
 340        *returned_bytes = 0;
 341
 342        /* poll to make sure that SW_DONE is asserted */
 343        REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 1,
 344                                10, aux110->polling_timeout_period/10);
 345
 346        value = REG_READ(AUX_SW_STATUS);
 347        /* in case HPD is LOW, exit AUX transaction */
 348        if ((value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
 349                return AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON;
 350
 351        /* Note that the following bits are set in 'status.bits'
 352         * during CTS 4.2.1.2 (FW 3.3.1):
 353         * AUX_SW_RX_MIN_COUNT_VIOL, AUX_SW_RX_INVALID_STOP,
 354         * AUX_SW_RX_RECV_NO_DET, AUX_SW_RX_RECV_INVALID_H.
 355         *
 356         * AUX_SW_RX_MIN_COUNT_VIOL is an internal,
 357         * HW debugging bit and should be ignored.
 358         */
 359        if (value & AUX_SW_STATUS__AUX_SW_DONE_MASK) {
 360                if ((value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_STATE_MASK) ||
 361                        (value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_MASK))
 362                        return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
 363
 364                else if ((value & AUX_SW_STATUS__AUX_SW_RX_INVALID_STOP_MASK) ||
 365                        (value & AUX_SW_STATUS__AUX_SW_RX_RECV_NO_DET_MASK) ||
 366                        (value &
 367                                AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_H_MASK) ||
 368                        (value & AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_L_MASK))
 369                        return AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
 370
 371                *returned_bytes = get_reg_field_value(value,
 372                                AUX_SW_STATUS,
 373                                AUX_SW_REPLY_BYTE_COUNT);
 374
 375                if (*returned_bytes == 0)
 376                        return
 377                        AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
 378                else {
 379                        *returned_bytes -= 1;
 380                        return AUX_CHANNEL_OPERATION_SUCCEEDED;
 381                }
 382        } else {
 383                /*time_elapsed >= aux_engine->timeout_period
 384                 *  AUX_SW_STATUS__AUX_SW_HPD_DISCON = at this point
 385                 */
 386                ASSERT_CRITICAL(false);
 387                return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
 388        }
 389}
 390
 391enum i2caux_engine_type get_engine_type(
 392                const struct dce_aux *engine)
 393{
 394        return I2CAUX_ENGINE_TYPE_AUX;
 395}
 396
 397static bool acquire(
 398        struct dce_aux *engine,
 399        struct ddc *ddc)
 400{
 401        enum gpio_result result;
 402
 403        if ((engine == NULL) || !is_engine_available(engine))
 404                return false;
 405
 406        result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
 407                GPIO_DDC_CONFIG_TYPE_MODE_AUX);
 408
 409        if (result != GPIO_RESULT_OK)
 410                return false;
 411
 412        if (!acquire_engine(engine)) {
 413                dal_ddc_close(ddc);
 414                return false;
 415        }
 416
 417        engine->ddc = ddc;
 418
 419        return true;
 420}
 421
 422void dce110_engine_destroy(struct dce_aux **engine)
 423{
 424
 425        struct aux_engine_dce110 *engine110 = FROM_AUX_ENGINE(*engine);
 426
 427        kfree(engine110);
 428        *engine = NULL;
 429
 430}
 431
 432static uint32_t dce_aux_configure_timeout(struct ddc_service *ddc,
 433                uint32_t timeout_in_us)
 434{
 435        uint32_t multiplier = 0;
 436        uint32_t length = 0;
 437        uint32_t prev_length = 0;
 438        uint32_t prev_mult = 0;
 439        uint32_t prev_timeout_val = 0;
 440        struct ddc *ddc_pin = ddc->ddc_pin;
 441        struct dce_aux *aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en];
 442        struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(aux_engine);
 443
 444        /* 1-Update polling timeout period */
 445        aux110->polling_timeout_period = timeout_in_us * SW_AUX_TIMEOUT_PERIOD_MULTIPLIER;
 446
 447        /* 2-Update aux timeout period length and multiplier */
 448        if (timeout_in_us == 0) {
 449                multiplier = DEFAULT_AUX_ENGINE_MULT;
 450                length = DEFAULT_AUX_ENGINE_LENGTH;
 451        } else if (timeout_in_us <= TIME_OUT_INCREMENT) {
 452                multiplier = 0;
 453                length = timeout_in_us/TIME_OUT_MULTIPLIER_8;
 454                if (timeout_in_us % TIME_OUT_MULTIPLIER_8 != 0)
 455                        length++;
 456        } else if (timeout_in_us <= 2 * TIME_OUT_INCREMENT) {
 457                multiplier = 1;
 458                length = timeout_in_us/TIME_OUT_MULTIPLIER_16;
 459                if (timeout_in_us % TIME_OUT_MULTIPLIER_16 != 0)
 460                        length++;
 461        } else if (timeout_in_us <= 4 * TIME_OUT_INCREMENT) {
 462                multiplier = 2;
 463                length = timeout_in_us/TIME_OUT_MULTIPLIER_32;
 464                if (timeout_in_us % TIME_OUT_MULTIPLIER_32 != 0)
 465                        length++;
 466        } else if (timeout_in_us > 4 * TIME_OUT_INCREMENT) {
 467                multiplier = 3;
 468                length = timeout_in_us/TIME_OUT_MULTIPLIER_64;
 469                if (timeout_in_us % TIME_OUT_MULTIPLIER_64 != 0)
 470                        length++;
 471        }
 472
 473        length = (length < MAX_TIMEOUT_LENGTH) ? length : MAX_TIMEOUT_LENGTH;
 474
 475        REG_GET_2(AUX_DPHY_RX_CONTROL1, AUX_RX_TIMEOUT_LEN, &prev_length, AUX_RX_TIMEOUT_LEN_MUL, &prev_mult);
 476
 477        switch (prev_mult) {
 478        case 0:
 479                prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_8;
 480                break;
 481        case 1:
 482                prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_16;
 483                break;
 484        case 2:
 485                prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_32;
 486                break;
 487        case 3:
 488                prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_64;
 489                break;
 490        default:
 491                prev_timeout_val = DEFAULT_AUX_ENGINE_LENGTH * TIME_OUT_MULTIPLIER_8;
 492                break;
 493        }
 494
 495        REG_UPDATE_SEQ_2(AUX_DPHY_RX_CONTROL1, AUX_RX_TIMEOUT_LEN, length, AUX_RX_TIMEOUT_LEN_MUL, multiplier);
 496
 497        return prev_timeout_val;
 498}
 499
 500static struct dce_aux_funcs aux_functions = {
 501        .configure_timeout = NULL,
 502        .destroy = NULL,
 503};
 504
 505struct dce_aux *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_engine110,
 506                struct dc_context *ctx,
 507                uint32_t inst,
 508                uint32_t timeout_period,
 509                const struct dce110_aux_registers *regs,
 510                const struct dce110_aux_registers_mask *mask,
 511                const struct dce110_aux_registers_shift *shift,
 512                bool is_ext_aux_timeout_configurable)
 513{
 514        aux_engine110->base.ddc = NULL;
 515        aux_engine110->base.ctx = ctx;
 516        aux_engine110->base.delay = 0;
 517        aux_engine110->base.max_defer_write_retry = 0;
 518        aux_engine110->base.inst = inst;
 519        aux_engine110->polling_timeout_period = timeout_period;
 520        aux_engine110->regs = regs;
 521
 522        aux_engine110->mask = mask;
 523        aux_engine110->shift = shift;
 524        aux_engine110->base.funcs = &aux_functions;
 525        if (is_ext_aux_timeout_configurable)
 526                aux_engine110->base.funcs->configure_timeout = &dce_aux_configure_timeout;
 527
 528        return &aux_engine110->base;
 529}
 530
 531static enum i2caux_transaction_action i2caux_action_from_payload(struct aux_payload *payload)
 532{
 533        if (payload->i2c_over_aux) {
 534                if (payload->write) {
 535                        if (payload->mot)
 536                                return I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT;
 537                        return I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
 538                }
 539                if (payload->mot)
 540                        return I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT;
 541                return I2CAUX_TRANSACTION_ACTION_I2C_READ;
 542        }
 543        if (payload->write)
 544                return I2CAUX_TRANSACTION_ACTION_DP_WRITE;
 545        return I2CAUX_TRANSACTION_ACTION_DP_READ;
 546}
 547
 548int dce_aux_transfer_raw(struct ddc_service *ddc,
 549                struct aux_payload *payload,
 550                enum aux_channel_operation_result *operation_result)
 551{
 552        struct ddc *ddc_pin = ddc->ddc_pin;
 553        struct dce_aux *aux_engine;
 554        struct aux_request_transaction_data aux_req;
 555        struct aux_reply_transaction_data aux_rep;
 556        uint8_t returned_bytes = 0;
 557        int res = -1;
 558        uint32_t status;
 559
 560        memset(&aux_req, 0, sizeof(aux_req));
 561        memset(&aux_rep, 0, sizeof(aux_rep));
 562
 563        aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en];
 564        if (!acquire(aux_engine, ddc_pin)) {
 565                *operation_result = AUX_CHANNEL_OPERATION_FAILED_ENGINE_ACQUIRE;
 566                return -1;
 567        }
 568
 569        if (payload->i2c_over_aux)
 570                aux_req.type = AUX_TRANSACTION_TYPE_I2C;
 571        else
 572                aux_req.type = AUX_TRANSACTION_TYPE_DP;
 573
 574        aux_req.action = i2caux_action_from_payload(payload);
 575
 576        aux_req.address = payload->address;
 577        aux_req.delay = 0;
 578        aux_req.length = payload->length;
 579        aux_req.data = payload->data;
 580
 581        submit_channel_request(aux_engine, &aux_req);
 582        *operation_result = get_channel_status(aux_engine, &returned_bytes);
 583
 584        if (*operation_result == AUX_CHANNEL_OPERATION_SUCCEEDED) {
 585                int bytes_replied = 0;
 586                bytes_replied = read_channel_reply(aux_engine, payload->length,
 587                                         payload->data, payload->reply,
 588                                         &status);
 589                EVENT_LOG_AUX_REP(aux_engine->ddc->pin_data->en,
 590                                        EVENT_LOG_AUX_ORIGIN_NATIVE, *payload->reply,
 591                                        bytes_replied, payload->data);
 592                res = returned_bytes;
 593        } else {
 594                res = -1;
 595        }
 596
 597        release_engine(aux_engine);
 598        return res;
 599}
 600
 601#define AUX_MAX_RETRIES 7
 602#define AUX_MAX_DEFER_RETRIES 7
 603#define AUX_MAX_I2C_DEFER_RETRIES 7
 604#define AUX_MAX_INVALID_REPLY_RETRIES 2
 605#define AUX_MAX_TIMEOUT_RETRIES 3
 606
 607bool dce_aux_transfer_with_retries(struct ddc_service *ddc,
 608                struct aux_payload *payload)
 609{
 610        int i, ret = 0;
 611        uint8_t reply;
 612        bool payload_reply = true;
 613        enum aux_channel_operation_result operation_result;
 614        bool retry_on_defer = false;
 615
 616        int aux_ack_retries = 0,
 617                aux_defer_retries = 0,
 618                aux_i2c_defer_retries = 0,
 619                aux_timeout_retries = 0,
 620                aux_invalid_reply_retries = 0;
 621
 622        if (!payload->reply) {
 623                payload_reply = false;
 624                payload->reply = &reply;
 625        }
 626
 627        for (i = 0; i < AUX_MAX_RETRIES; i++) {
 628                ret = dce_aux_transfer_raw(ddc, payload, &operation_result);
 629                switch (operation_result) {
 630                case AUX_CHANNEL_OPERATION_SUCCEEDED:
 631                        aux_timeout_retries = 0;
 632                        aux_invalid_reply_retries = 0;
 633
 634                        switch (*payload->reply) {
 635                        case AUX_TRANSACTION_REPLY_AUX_ACK:
 636                                if (!payload->write && payload->length != ret) {
 637                                        if (++aux_ack_retries >= AUX_MAX_RETRIES)
 638                                                goto fail;
 639                                        else
 640                                                udelay(300);
 641                                } else
 642                                        return true;
 643                        break;
 644
 645                        case AUX_TRANSACTION_REPLY_AUX_DEFER:
 646                        case AUX_TRANSACTION_REPLY_I2C_OVER_AUX_DEFER:
 647                                retry_on_defer = true;
 648                                fallthrough;
 649                        case AUX_TRANSACTION_REPLY_I2C_OVER_AUX_NACK:
 650                                if (++aux_defer_retries >= AUX_MAX_DEFER_RETRIES) {
 651                                        goto fail;
 652                                } else {
 653                                        if ((*payload->reply == AUX_TRANSACTION_REPLY_AUX_DEFER) ||
 654                                                (*payload->reply == AUX_TRANSACTION_REPLY_I2C_OVER_AUX_DEFER)) {
 655                                                if (payload->defer_delay > 0)
 656                                                        msleep(payload->defer_delay);
 657                                        }
 658                                }
 659                                break;
 660
 661                        case AUX_TRANSACTION_REPLY_I2C_DEFER:
 662                                aux_defer_retries = 0;
 663                                if (++aux_i2c_defer_retries >= AUX_MAX_I2C_DEFER_RETRIES)
 664                                        goto fail;
 665                                break;
 666
 667                        case AUX_TRANSACTION_REPLY_AUX_NACK:
 668                        case AUX_TRANSACTION_REPLY_HPD_DISCON:
 669                        default:
 670                                goto fail;
 671                        }
 672                        break;
 673
 674                case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
 675                        if (++aux_invalid_reply_retries >= AUX_MAX_INVALID_REPLY_RETRIES)
 676                                goto fail;
 677                        else
 678                                udelay(400);
 679                        break;
 680
 681                case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
 682                        // Check whether a DEFER had occurred before the timeout.
 683                        // If so, treat timeout as a DEFER.
 684                        if (retry_on_defer) {
 685                                if (++aux_defer_retries >= AUX_MAX_DEFER_RETRIES)
 686                                        goto fail;
 687                                else if (payload->defer_delay > 0)
 688                                        msleep(payload->defer_delay);
 689                        } else {
 690                                if (++aux_timeout_retries >= AUX_MAX_TIMEOUT_RETRIES)
 691                                        goto fail;
 692                                else {
 693                                        /*
 694                                         * DP 1.4, 2.8.2:  AUX Transaction Response/Reply Timeouts
 695                                         * According to the DP spec there should be 3 retries total
 696                                         * with a 400us wait inbetween each. Hardware already waits
 697                                         * for 550us therefore no wait is required here.
 698                                         */
 699                                }
 700                        }
 701                        break;
 702
 703                case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
 704                case AUX_CHANNEL_OPERATION_FAILED_ENGINE_ACQUIRE:
 705                case AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN:
 706                default:
 707                        goto fail;
 708                }
 709        }
 710
 711fail:
 712        if (!payload_reply)
 713                payload->reply = NULL;
 714        return false;
 715}
 716