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 "dm_services.h"
  27#include "dce_aux.h"
  28#include "dce/dce_11_0_sh_mask.h"
  29
  30#define CTX \
  31        aux110->base.ctx
  32#define REG(reg_name)\
  33        (aux110->regs->reg_name)
  34
  35#define DC_LOGGER \
  36        engine->ctx->logger
  37
  38#include "reg_helper.h"
  39
  40#define FROM_AUX_ENGINE(ptr) \
  41        container_of((ptr), struct aux_engine_dce110, base)
  42
  43#define FROM_ENGINE(ptr) \
  44        FROM_AUX_ENGINE(container_of((ptr), struct aux_engine, base))
  45
  46#define FROM_AUX_ENGINE_ENGINE(ptr) \
  47        container_of((ptr), struct aux_engine, base)
  48enum {
  49        AUX_INVALID_REPLY_RETRY_COUNTER = 1,
  50        AUX_TIMED_OUT_RETRY_COUNTER = 2,
  51        AUX_DEFER_RETRY_COUNTER = 6
  52};
  53static void release_engine(
  54        struct aux_engine *engine)
  55{
  56        struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
  57
  58        dal_ddc_close(engine->ddc);
  59
  60        engine->ddc = NULL;
  61
  62        REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_DONE_USING_AUX_REG, 1);
  63}
  64
  65#define SW_CAN_ACCESS_AUX 1
  66#define DMCU_CAN_ACCESS_AUX 2
  67
  68static bool is_engine_available(
  69        struct aux_engine *engine)
  70{
  71        struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
  72
  73        uint32_t value = REG_READ(AUX_ARB_CONTROL);
  74        uint32_t field = get_reg_field_value(
  75                        value,
  76                        AUX_ARB_CONTROL,
  77                        AUX_REG_RW_CNTL_STATUS);
  78
  79        return (field != DMCU_CAN_ACCESS_AUX);
  80}
  81static bool acquire_engine(
  82        struct aux_engine *engine)
  83{
  84        struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
  85
  86        uint32_t value = REG_READ(AUX_ARB_CONTROL);
  87        uint32_t field = get_reg_field_value(
  88                        value,
  89                        AUX_ARB_CONTROL,
  90                        AUX_REG_RW_CNTL_STATUS);
  91        if (field == DMCU_CAN_ACCESS_AUX)
  92                return false;
  93        /* enable AUX before request SW to access AUX */
  94        value = REG_READ(AUX_CONTROL);
  95        field = get_reg_field_value(value,
  96                                AUX_CONTROL,
  97                                AUX_EN);
  98
  99        if (field == 0) {
 100                set_reg_field_value(
 101                                value,
 102                                1,
 103                                AUX_CONTROL,
 104                                AUX_EN);
 105
 106                if (REG(AUX_RESET_MASK)) {
 107                        /*DP_AUX block as part of the enable sequence*/
 108                        set_reg_field_value(
 109                                value,
 110                                1,
 111                                AUX_CONTROL,
 112                                AUX_RESET);
 113                }
 114
 115                REG_WRITE(AUX_CONTROL, value);
 116
 117                if (REG(AUX_RESET_MASK)) {
 118                        /*poll HW to make sure reset it done*/
 119
 120                        REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 1,
 121                                        1, 11);
 122
 123                        set_reg_field_value(
 124                                value,
 125                                0,
 126                                AUX_CONTROL,
 127                                AUX_RESET);
 128
 129                        REG_WRITE(AUX_CONTROL, value);
 130
 131                        REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 0,
 132                                        1, 11);
 133                }
 134        } /*if (field)*/
 135
 136        /* request SW to access AUX */
 137        REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_USE_AUX_REG_REQ, 1);
 138
 139        value = REG_READ(AUX_ARB_CONTROL);
 140        field = get_reg_field_value(
 141                        value,
 142                        AUX_ARB_CONTROL,
 143                        AUX_REG_RW_CNTL_STATUS);
 144
 145        return (field == SW_CAN_ACCESS_AUX);
 146}
 147
 148#define COMPOSE_AUX_SW_DATA_16_20(command, address) \
 149        ((command) | ((0xF0000 & (address)) >> 16))
 150
 151#define COMPOSE_AUX_SW_DATA_8_15(address) \
 152        ((0xFF00 & (address)) >> 8)
 153
 154#define COMPOSE_AUX_SW_DATA_0_7(address) \
 155        (0xFF & (address))
 156
 157static void submit_channel_request(
 158        struct aux_engine *engine,
 159        struct aux_request_transaction_data *request)
 160{
 161        struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
 162        uint32_t value;
 163        uint32_t length;
 164
 165        bool is_write =
 166                ((request->type == AUX_TRANSACTION_TYPE_DP) &&
 167                 (request->action == I2CAUX_TRANSACTION_ACTION_DP_WRITE)) ||
 168                ((request->type == AUX_TRANSACTION_TYPE_I2C) &&
 169                ((request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) ||
 170                 (request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT)));
 171        if (REG(AUXN_IMPCAL)) {
 172                /* clear_aux_error */
 173                REG_UPDATE_SEQ(AUXN_IMPCAL, AUXN_CALOUT_ERROR_AK,
 174                                1,
 175                                0);
 176
 177                REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_CALOUT_ERROR_AK,
 178                                1,
 179                                0);
 180
 181                /* force_default_calibrate */
 182                REG_UPDATE_1BY1_2(AUXN_IMPCAL,
 183                                AUXN_IMPCAL_ENABLE, 1,
 184                                AUXN_IMPCAL_OVERRIDE_ENABLE, 0);
 185
 186                /* bug? why AUXN update EN and OVERRIDE_EN 1 by 1 while AUX P toggles OVERRIDE? */
 187
 188                REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_IMPCAL_OVERRIDE_ENABLE,
 189                                1,
 190                                0);
 191        }
 192        /* set the delay and the number of bytes to write */
 193
 194        /* The length include
 195         * the 4 bit header and the 20 bit address
 196         * (that is 3 byte).
 197         * If the requested length is non zero this means
 198         * an addition byte specifying the length is required.
 199         */
 200
 201        length = request->length ? 4 : 3;
 202        if (is_write)
 203                length += request->length;
 204
 205        REG_UPDATE_2(AUX_SW_CONTROL,
 206                        AUX_SW_START_DELAY, request->delay,
 207                        AUX_SW_WR_BYTES, length);
 208
 209        /* program action and address and payload data (if 'is_write') */
 210        value = REG_UPDATE_4(AUX_SW_DATA,
 211                        AUX_SW_INDEX, 0,
 212                        AUX_SW_DATA_RW, 0,
 213                        AUX_SW_AUTOINCREMENT_DISABLE, 1,
 214                        AUX_SW_DATA, COMPOSE_AUX_SW_DATA_16_20(request->action, request->address));
 215
 216        value = REG_SET_2(AUX_SW_DATA, value,
 217                        AUX_SW_AUTOINCREMENT_DISABLE, 0,
 218                        AUX_SW_DATA, COMPOSE_AUX_SW_DATA_8_15(request->address));
 219
 220        value = REG_SET(AUX_SW_DATA, value,
 221                        AUX_SW_DATA, COMPOSE_AUX_SW_DATA_0_7(request->address));
 222
 223        if (request->length) {
 224                value = REG_SET(AUX_SW_DATA, value,
 225                                AUX_SW_DATA, request->length - 1);
 226        }
 227
 228        if (is_write) {
 229                /* Load the HW buffer with the Data to be sent.
 230                 * This is relevant for write operation.
 231                 * For read, the data recived data will be
 232                 * processed in process_channel_reply().
 233                 */
 234                uint32_t i = 0;
 235
 236                while (i < request->length) {
 237                        value = REG_SET(AUX_SW_DATA, value,
 238                                        AUX_SW_DATA, request->data[i]);
 239
 240                        ++i;
 241                }
 242        }
 243
 244        REG_UPDATE(AUX_INTERRUPT_CONTROL, AUX_SW_DONE_ACK, 1);
 245        REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 0,
 246                                10, aux110->timeout_period/10);
 247        REG_UPDATE(AUX_SW_CONTROL, AUX_SW_GO, 1);
 248}
 249
 250static int read_channel_reply(struct aux_engine *engine, uint32_t size,
 251                              uint8_t *buffer, uint8_t *reply_result,
 252                              uint32_t *sw_status)
 253{
 254        struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
 255        uint32_t bytes_replied;
 256        uint32_t reply_result_32;
 257
 258        *sw_status = REG_GET(AUX_SW_STATUS, AUX_SW_REPLY_BYTE_COUNT,
 259                             &bytes_replied);
 260
 261        /* In case HPD is LOW, exit AUX transaction */
 262        if ((*sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
 263                return -1;
 264
 265        /* Need at least the status byte */
 266        if (!bytes_replied)
 267                return -1;
 268
 269        REG_UPDATE_1BY1_3(AUX_SW_DATA,
 270                          AUX_SW_INDEX, 0,
 271                          AUX_SW_AUTOINCREMENT_DISABLE, 1,
 272                          AUX_SW_DATA_RW, 1);
 273
 274        REG_GET(AUX_SW_DATA, AUX_SW_DATA, &reply_result_32);
 275        reply_result_32 = reply_result_32 >> 4;
 276        *reply_result = (uint8_t)reply_result_32;
 277
 278        if (reply_result_32 == 0) { /* ACK */
 279                uint32_t i = 0;
 280
 281                /* First byte was already used to get the command status */
 282                --bytes_replied;
 283
 284                /* Do not overflow buffer */
 285                if (bytes_replied > size)
 286                        return -1;
 287
 288                while (i < bytes_replied) {
 289                        uint32_t aux_sw_data_val;
 290
 291                        REG_GET(AUX_SW_DATA, AUX_SW_DATA, &aux_sw_data_val);
 292                        buffer[i] = aux_sw_data_val;
 293                        ++i;
 294                }
 295
 296                return i;
 297        }
 298
 299        return 0;
 300}
 301
 302static void process_channel_reply(
 303        struct aux_engine *engine,
 304        struct aux_reply_transaction_data *reply)
 305{
 306        int bytes_replied;
 307        uint8_t reply_result;
 308        uint32_t sw_status;
 309
 310        bytes_replied = read_channel_reply(engine, reply->length, reply->data,
 311                                           &reply_result, &sw_status);
 312
 313        /* in case HPD is LOW, exit AUX transaction */
 314        if ((sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
 315                reply->status = AUX_TRANSACTION_REPLY_HPD_DISCON;
 316                return;
 317        }
 318
 319        if (bytes_replied < 0) {
 320                /* Need to handle an error case...
 321                 * Hopefully, upper layer function won't call this function if
 322                 * the number of bytes in the reply was 0, because there was
 323                 * surely an error that was asserted that should have been
 324                 * handled for hot plug case, this could happens
 325                 */
 326                if (!(sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
 327                        reply->status = AUX_TRANSACTION_REPLY_INVALID;
 328                        ASSERT_CRITICAL(false);
 329                        return;
 330                }
 331        } else {
 332
 333                switch (reply_result) {
 334                case 0: /* ACK */
 335                        reply->status = AUX_TRANSACTION_REPLY_AUX_ACK;
 336                break;
 337                case 1: /* NACK */
 338                        reply->status = AUX_TRANSACTION_REPLY_AUX_NACK;
 339                break;
 340                case 2: /* DEFER */
 341                        reply->status = AUX_TRANSACTION_REPLY_AUX_DEFER;
 342                break;
 343                case 4: /* AUX ACK / I2C NACK */
 344                        reply->status = AUX_TRANSACTION_REPLY_I2C_NACK;
 345                break;
 346                case 8: /* AUX ACK / I2C DEFER */
 347                        reply->status = AUX_TRANSACTION_REPLY_I2C_DEFER;
 348                break;
 349                default:
 350                        reply->status = AUX_TRANSACTION_REPLY_INVALID;
 351                }
 352        }
 353}
 354
 355static enum aux_channel_operation_result get_channel_status(
 356        struct aux_engine *engine,
 357        uint8_t *returned_bytes)
 358{
 359        struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
 360
 361        uint32_t value;
 362
 363        if (returned_bytes == NULL) {
 364                /*caller pass NULL pointer*/
 365                ASSERT_CRITICAL(false);
 366                return AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN;
 367        }
 368        *returned_bytes = 0;
 369
 370        /* poll to make sure that SW_DONE is asserted */
 371        value = REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 1,
 372                                10, aux110->timeout_period/10);
 373
 374        /* in case HPD is LOW, exit AUX transaction */
 375        if ((value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
 376                return AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON;
 377
 378        /* Note that the following bits are set in 'status.bits'
 379         * during CTS 4.2.1.2 (FW 3.3.1):
 380         * AUX_SW_RX_MIN_COUNT_VIOL, AUX_SW_RX_INVALID_STOP,
 381         * AUX_SW_RX_RECV_NO_DET, AUX_SW_RX_RECV_INVALID_H.
 382         *
 383         * AUX_SW_RX_MIN_COUNT_VIOL is an internal,
 384         * HW debugging bit and should be ignored.
 385         */
 386        if (value & AUX_SW_STATUS__AUX_SW_DONE_MASK) {
 387                if ((value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_STATE_MASK) ||
 388                        (value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_MASK))
 389                        return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
 390
 391                else if ((value & AUX_SW_STATUS__AUX_SW_RX_INVALID_STOP_MASK) ||
 392                        (value & AUX_SW_STATUS__AUX_SW_RX_RECV_NO_DET_MASK) ||
 393                        (value &
 394                                AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_H_MASK) ||
 395                        (value & AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_L_MASK))
 396                        return AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
 397
 398                *returned_bytes = get_reg_field_value(value,
 399                                AUX_SW_STATUS,
 400                                AUX_SW_REPLY_BYTE_COUNT);
 401
 402                if (*returned_bytes == 0)
 403                        return
 404                        AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
 405                else {
 406                        *returned_bytes -= 1;
 407                        return AUX_CHANNEL_OPERATION_SUCCEEDED;
 408                }
 409        } else {
 410                /*time_elapsed >= aux_engine->timeout_period
 411                 *  AUX_SW_STATUS__AUX_SW_HPD_DISCON = at this point
 412                 */
 413                ASSERT_CRITICAL(false);
 414                return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
 415        }
 416}
 417static void process_read_reply(
 418        struct aux_engine *engine,
 419        struct read_command_context *ctx)
 420{
 421        engine->funcs->process_channel_reply(engine, &ctx->reply);
 422
 423        switch (ctx->reply.status) {
 424        case AUX_TRANSACTION_REPLY_AUX_ACK:
 425                ctx->defer_retry_aux = 0;
 426                if (ctx->returned_byte > ctx->current_read_length) {
 427                        ctx->status =
 428                                I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
 429                        ctx->operation_succeeded = false;
 430                } else if (ctx->returned_byte < ctx->current_read_length) {
 431                        ctx->current_read_length -= ctx->returned_byte;
 432
 433                        ctx->offset += ctx->returned_byte;
 434
 435                        ++ctx->invalid_reply_retry_aux_on_ack;
 436
 437                        if (ctx->invalid_reply_retry_aux_on_ack >
 438                                AUX_INVALID_REPLY_RETRY_COUNTER) {
 439                                ctx->status =
 440                                I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
 441                                ctx->operation_succeeded = false;
 442                        }
 443                } else {
 444                        ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
 445                        ctx->transaction_complete = true;
 446                        ctx->operation_succeeded = true;
 447                }
 448        break;
 449        case AUX_TRANSACTION_REPLY_AUX_NACK:
 450                ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
 451                ctx->operation_succeeded = false;
 452        break;
 453        case AUX_TRANSACTION_REPLY_AUX_DEFER:
 454                ++ctx->defer_retry_aux;
 455
 456                if (ctx->defer_retry_aux > AUX_DEFER_RETRY_COUNTER) {
 457                        ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
 458                        ctx->operation_succeeded = false;
 459                }
 460        break;
 461        case AUX_TRANSACTION_REPLY_I2C_DEFER:
 462                ctx->defer_retry_aux = 0;
 463
 464                ++ctx->defer_retry_i2c;
 465
 466                if (ctx->defer_retry_i2c > AUX_DEFER_RETRY_COUNTER) {
 467                        ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
 468                        ctx->operation_succeeded = false;
 469                }
 470        break;
 471        case AUX_TRANSACTION_REPLY_HPD_DISCON:
 472                ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
 473                ctx->operation_succeeded = false;
 474        break;
 475        default:
 476                ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
 477                ctx->operation_succeeded = false;
 478        }
 479}
 480static void process_read_request(
 481        struct aux_engine *engine,
 482        struct read_command_context *ctx)
 483{
 484        enum aux_channel_operation_result operation_result;
 485
 486        engine->funcs->submit_channel_request(engine, &ctx->request);
 487
 488        operation_result = engine->funcs->get_channel_status(
 489                engine, &ctx->returned_byte);
 490
 491        switch (operation_result) {
 492        case AUX_CHANNEL_OPERATION_SUCCEEDED:
 493                if (ctx->returned_byte > ctx->current_read_length) {
 494                        ctx->status =
 495                                I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
 496                        ctx->operation_succeeded = false;
 497                } else {
 498                        ctx->timed_out_retry_aux = 0;
 499                        ctx->invalid_reply_retry_aux = 0;
 500
 501                        ctx->reply.length = ctx->returned_byte;
 502                        ctx->reply.data = ctx->buffer;
 503
 504                        process_read_reply(engine, ctx);
 505                }
 506        break;
 507        case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
 508                ++ctx->invalid_reply_retry_aux;
 509
 510                if (ctx->invalid_reply_retry_aux >
 511                        AUX_INVALID_REPLY_RETRY_COUNTER) {
 512                        ctx->status =
 513                                I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
 514                        ctx->operation_succeeded = false;
 515                } else
 516                        udelay(400);
 517        break;
 518        case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
 519                ++ctx->timed_out_retry_aux;
 520
 521                if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) {
 522                        ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
 523                        ctx->operation_succeeded = false;
 524                } else {
 525                        /* DP 1.2a, table 2-58:
 526                         * "S3: AUX Request CMD PENDING:
 527                         * retry 3 times, with 400usec wait on each"
 528                         * The HW timeout is set to 550usec,
 529                         * so we should not wait here
 530                         */
 531                }
 532        break;
 533        case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
 534                ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
 535                ctx->operation_succeeded = false;
 536        break;
 537        default:
 538                ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
 539                ctx->operation_succeeded = false;
 540        }
 541}
 542static bool read_command(
 543        struct aux_engine *engine,
 544        struct i2caux_transaction_request *request,
 545        bool middle_of_transaction)
 546{
 547        struct read_command_context ctx;
 548
 549        ctx.buffer = request->payload.data;
 550        ctx.current_read_length = request->payload.length;
 551        ctx.offset = 0;
 552        ctx.timed_out_retry_aux = 0;
 553        ctx.invalid_reply_retry_aux = 0;
 554        ctx.defer_retry_aux = 0;
 555        ctx.defer_retry_i2c = 0;
 556        ctx.invalid_reply_retry_aux_on_ack = 0;
 557        ctx.transaction_complete = false;
 558        ctx.operation_succeeded = true;
 559
 560        if (request->payload.address_space ==
 561                I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
 562                ctx.request.type = AUX_TRANSACTION_TYPE_DP;
 563                ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_READ;
 564                ctx.request.address = request->payload.address;
 565        } else if (request->payload.address_space ==
 566                I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) {
 567                ctx.request.type = AUX_TRANSACTION_TYPE_I2C;
 568                ctx.request.action = middle_of_transaction ?
 569                        I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT :
 570                        I2CAUX_TRANSACTION_ACTION_I2C_READ;
 571                ctx.request.address = request->payload.address >> 1;
 572        } else {
 573                /* in DAL2, there was no return in such case */
 574                BREAK_TO_DEBUGGER();
 575                return false;
 576        }
 577
 578        ctx.request.delay = 0;
 579
 580        do {
 581                memset(ctx.buffer + ctx.offset, 0, ctx.current_read_length);
 582
 583                ctx.request.data = ctx.buffer + ctx.offset;
 584                ctx.request.length = ctx.current_read_length;
 585
 586                process_read_request(engine, &ctx);
 587
 588                request->status = ctx.status;
 589
 590                if (ctx.operation_succeeded && !ctx.transaction_complete)
 591                        if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C)
 592                                msleep(engine->delay);
 593        } while (ctx.operation_succeeded && !ctx.transaction_complete);
 594
 595        if (request->payload.address_space ==
 596                I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
 597                DC_LOG_I2C_AUX("READ: addr:0x%x  value:0x%x Result:%d",
 598                                request->payload.address,
 599                                request->payload.data[0],
 600                                ctx.operation_succeeded);
 601        }
 602
 603        return ctx.operation_succeeded;
 604}
 605
 606static void process_write_reply(
 607        struct aux_engine *engine,
 608        struct write_command_context *ctx)
 609{
 610        engine->funcs->process_channel_reply(engine, &ctx->reply);
 611
 612        switch (ctx->reply.status) {
 613        case AUX_TRANSACTION_REPLY_AUX_ACK:
 614                ctx->operation_succeeded = true;
 615
 616                if (ctx->returned_byte) {
 617                        ctx->request.action = ctx->mot ?
 618                        I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
 619                        I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
 620
 621                        ctx->current_write_length = 0;
 622
 623                        ++ctx->ack_m_retry;
 624
 625                        if (ctx->ack_m_retry > AUX_DEFER_RETRY_COUNTER) {
 626                                ctx->status =
 627                                I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
 628                                ctx->operation_succeeded = false;
 629                        } else
 630                                udelay(300);
 631                } else {
 632                        ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
 633                        ctx->defer_retry_aux = 0;
 634                        ctx->ack_m_retry = 0;
 635                        ctx->transaction_complete = true;
 636                }
 637        break;
 638        case AUX_TRANSACTION_REPLY_AUX_NACK:
 639                ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
 640                ctx->operation_succeeded = false;
 641        break;
 642        case AUX_TRANSACTION_REPLY_AUX_DEFER:
 643                ++ctx->defer_retry_aux;
 644
 645                if (ctx->defer_retry_aux > ctx->max_defer_retry) {
 646                        ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
 647                        ctx->operation_succeeded = false;
 648                }
 649        break;
 650        case AUX_TRANSACTION_REPLY_I2C_DEFER:
 651                ctx->defer_retry_aux = 0;
 652                ctx->current_write_length = 0;
 653
 654                ctx->request.action = ctx->mot ?
 655                        I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
 656                        I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
 657
 658                ++ctx->defer_retry_i2c;
 659
 660                if (ctx->defer_retry_i2c > ctx->max_defer_retry) {
 661                        ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
 662                        ctx->operation_succeeded = false;
 663                }
 664        break;
 665        case AUX_TRANSACTION_REPLY_HPD_DISCON:
 666                ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
 667                ctx->operation_succeeded = false;
 668        break;
 669        default:
 670                ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
 671                ctx->operation_succeeded = false;
 672        }
 673}
 674static void process_write_request(
 675        struct aux_engine *engine,
 676        struct write_command_context *ctx)
 677{
 678        enum aux_channel_operation_result operation_result;
 679
 680        engine->funcs->submit_channel_request(engine, &ctx->request);
 681
 682        operation_result = engine->funcs->get_channel_status(
 683                engine, &ctx->returned_byte);
 684
 685        switch (operation_result) {
 686        case AUX_CHANNEL_OPERATION_SUCCEEDED:
 687                ctx->timed_out_retry_aux = 0;
 688                ctx->invalid_reply_retry_aux = 0;
 689
 690                ctx->reply.length = ctx->returned_byte;
 691                ctx->reply.data = ctx->reply_data;
 692
 693                process_write_reply(engine, ctx);
 694        break;
 695        case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
 696                ++ctx->invalid_reply_retry_aux;
 697
 698                if (ctx->invalid_reply_retry_aux >
 699                        AUX_INVALID_REPLY_RETRY_COUNTER) {
 700                        ctx->status =
 701                                I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
 702                        ctx->operation_succeeded = false;
 703                } else
 704                        udelay(400);
 705        break;
 706        case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
 707                ++ctx->timed_out_retry_aux;
 708
 709                if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) {
 710                        ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
 711                        ctx->operation_succeeded = false;
 712                } else {
 713                        /* DP 1.2a, table 2-58:
 714                         * "S3: AUX Request CMD PENDING:
 715                         * retry 3 times, with 400usec wait on each"
 716                         * The HW timeout is set to 550usec,
 717                         * so we should not wait here
 718                         */
 719                }
 720        break;
 721        case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
 722                ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
 723                ctx->operation_succeeded = false;
 724        break;
 725        default:
 726                ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
 727                ctx->operation_succeeded = false;
 728        }
 729}
 730static bool write_command(
 731        struct aux_engine *engine,
 732        struct i2caux_transaction_request *request,
 733        bool middle_of_transaction)
 734{
 735        struct write_command_context ctx;
 736
 737        ctx.mot = middle_of_transaction;
 738        ctx.buffer = request->payload.data;
 739        ctx.current_write_length = request->payload.length;
 740        ctx.timed_out_retry_aux = 0;
 741        ctx.invalid_reply_retry_aux = 0;
 742        ctx.defer_retry_aux = 0;
 743        ctx.defer_retry_i2c = 0;
 744        ctx.ack_m_retry = 0;
 745        ctx.transaction_complete = false;
 746        ctx.operation_succeeded = true;
 747
 748        if (request->payload.address_space ==
 749                I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
 750                ctx.request.type = AUX_TRANSACTION_TYPE_DP;
 751                ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_WRITE;
 752                ctx.request.address = request->payload.address;
 753        } else if (request->payload.address_space ==
 754                I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) {
 755                ctx.request.type = AUX_TRANSACTION_TYPE_I2C;
 756                ctx.request.action = middle_of_transaction ?
 757                        I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT :
 758                        I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
 759                ctx.request.address = request->payload.address >> 1;
 760        } else {
 761                /* in DAL2, there was no return in such case */
 762                BREAK_TO_DEBUGGER();
 763                return false;
 764        }
 765
 766        ctx.request.delay = 0;
 767
 768        ctx.max_defer_retry =
 769                (engine->max_defer_write_retry > AUX_DEFER_RETRY_COUNTER) ?
 770                        engine->max_defer_write_retry : AUX_DEFER_RETRY_COUNTER;
 771
 772        do {
 773                ctx.request.data = ctx.buffer;
 774                ctx.request.length = ctx.current_write_length;
 775
 776                process_write_request(engine, &ctx);
 777
 778                request->status = ctx.status;
 779
 780                if (ctx.operation_succeeded && !ctx.transaction_complete)
 781                        if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C)
 782                                msleep(engine->delay);
 783        } while (ctx.operation_succeeded && !ctx.transaction_complete);
 784
 785        if (request->payload.address_space ==
 786                I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
 787                DC_LOG_I2C_AUX("WRITE: addr:0x%x  value:0x%x Result:%d",
 788                                request->payload.address,
 789                                request->payload.data[0],
 790                                ctx.operation_succeeded);
 791        }
 792
 793        return ctx.operation_succeeded;
 794}
 795static bool end_of_transaction_command(
 796        struct aux_engine *engine,
 797        struct i2caux_transaction_request *request)
 798{
 799        struct i2caux_transaction_request dummy_request;
 800        uint8_t dummy_data;
 801
 802        /* [tcheng] We only need to send the stop (read with MOT = 0)
 803         * for I2C-over-Aux, not native AUX
 804         */
 805
 806        if (request->payload.address_space !=
 807                I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C)
 808                return false;
 809
 810        dummy_request.operation = request->operation;
 811        dummy_request.payload.address_space = request->payload.address_space;
 812        dummy_request.payload.address = request->payload.address;
 813
 814        /*
 815         * Add a dummy byte due to some receiver quirk
 816         * where one byte is sent along with MOT = 0.
 817         * Ideally this should be 0.
 818         */
 819
 820        dummy_request.payload.length = 0;
 821        dummy_request.payload.data = &dummy_data;
 822
 823        if (request->operation == I2CAUX_TRANSACTION_READ)
 824                return read_command(engine, &dummy_request, false);
 825        else
 826                return write_command(engine, &dummy_request, false);
 827
 828        /* according Syed, it does not need now DoDummyMOT */
 829}
 830static bool submit_request(
 831        struct aux_engine *engine,
 832        struct i2caux_transaction_request *request,
 833        bool middle_of_transaction)
 834{
 835
 836        bool result;
 837        bool mot_used = true;
 838
 839        switch (request->operation) {
 840        case I2CAUX_TRANSACTION_READ:
 841                result = read_command(engine, request, mot_used);
 842        break;
 843        case I2CAUX_TRANSACTION_WRITE:
 844                result = write_command(engine, request, mot_used);
 845        break;
 846        default:
 847                result = false;
 848        }
 849
 850        /* [tcheng]
 851         * need to send stop for the last transaction to free up the AUX
 852         * if the above command fails, this would be the last transaction
 853         */
 854
 855        if (!middle_of_transaction || !result)
 856                end_of_transaction_command(engine, request);
 857
 858        /* mask AUX interrupt */
 859
 860        return result;
 861}
 862enum i2caux_engine_type get_engine_type(
 863                const struct aux_engine *engine)
 864{
 865        return I2CAUX_ENGINE_TYPE_AUX;
 866}
 867
 868static bool acquire(
 869        struct aux_engine *engine,
 870        struct ddc *ddc)
 871{
 872
 873        enum gpio_result result;
 874
 875        if (engine->funcs->is_engine_available) {
 876                /*check whether SW could use the engine*/
 877                if (!engine->funcs->is_engine_available(engine))
 878                        return false;
 879        }
 880
 881        result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
 882                GPIO_DDC_CONFIG_TYPE_MODE_AUX);
 883
 884        if (result != GPIO_RESULT_OK)
 885                return false;
 886
 887        if (!engine->funcs->acquire_engine(engine)) {
 888                dal_ddc_close(ddc);
 889                return false;
 890        }
 891
 892        engine->ddc = ddc;
 893
 894        return true;
 895}
 896
 897static const struct aux_engine_funcs aux_engine_funcs = {
 898        .acquire_engine = acquire_engine,
 899        .submit_channel_request = submit_channel_request,
 900        .process_channel_reply = process_channel_reply,
 901        .read_channel_reply = read_channel_reply,
 902        .get_channel_status = get_channel_status,
 903        .is_engine_available = is_engine_available,
 904        .release_engine = release_engine,
 905        .destroy_engine = dce110_engine_destroy,
 906        .submit_request = submit_request,
 907        .get_engine_type = get_engine_type,
 908        .acquire = acquire,
 909};
 910
 911void dce110_engine_destroy(struct aux_engine **engine)
 912{
 913
 914        struct aux_engine_dce110 *engine110 = FROM_AUX_ENGINE(*engine);
 915
 916        kfree(engine110);
 917        *engine = NULL;
 918
 919}
 920struct aux_engine *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_engine110,
 921                struct dc_context *ctx,
 922                uint32_t inst,
 923                uint32_t timeout_period,
 924                const struct dce110_aux_registers *regs)
 925{
 926        aux_engine110->base.ddc = NULL;
 927        aux_engine110->base.ctx = ctx;
 928        aux_engine110->base.delay = 0;
 929        aux_engine110->base.max_defer_write_retry = 0;
 930        aux_engine110->base.funcs = &aux_engine_funcs;
 931        aux_engine110->base.inst = inst;
 932        aux_engine110->timeout_period = timeout_period;
 933        aux_engine110->regs = regs;
 934
 935        return &aux_engine110->base;
 936}
 937
 938