linux/drivers/gpu/drm/msm/dp/dp_aux.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
   4 */
   5
   6#include <linux/delay.h>
   7#include <drm/drm_print.h>
   8
   9#include "dp_reg.h"
  10#include "dp_aux.h"
  11
  12enum msm_dp_aux_err {
  13        DP_AUX_ERR_NONE,
  14        DP_AUX_ERR_ADDR,
  15        DP_AUX_ERR_TOUT,
  16        DP_AUX_ERR_NACK,
  17        DP_AUX_ERR_DEFER,
  18        DP_AUX_ERR_NACK_DEFER,
  19        DP_AUX_ERR_PHY,
  20};
  21
  22struct dp_aux_private {
  23        struct device *dev;
  24        struct dp_catalog *catalog;
  25
  26        struct mutex mutex;
  27        struct completion comp;
  28
  29        enum msm_dp_aux_err aux_error_num;
  30        u32 retry_cnt;
  31        bool cmd_busy;
  32        bool native;
  33        bool read;
  34        bool no_send_addr;
  35        bool no_send_stop;
  36        bool initted;
  37        u32 offset;
  38        u32 segment;
  39
  40        struct drm_dp_aux dp_aux;
  41};
  42
  43#define MAX_AUX_RETRIES                 5
  44
  45static ssize_t dp_aux_write(struct dp_aux_private *aux,
  46                        struct drm_dp_aux_msg *msg)
  47{
  48        u8 data[4];
  49        u32 reg;
  50        ssize_t len;
  51        u8 *msgdata = msg->buffer;
  52        int const AUX_CMD_FIFO_LEN = 128;
  53        int i = 0;
  54
  55        if (aux->read)
  56                len = 0;
  57        else
  58                len = msg->size;
  59
  60        /*
  61         * cmd fifo only has depth of 144 bytes
  62         * limit buf length to 128 bytes here
  63         */
  64        if (len > AUX_CMD_FIFO_LEN - 4) {
  65                DRM_ERROR("buf size greater than allowed size of 128 bytes\n");
  66                return -EINVAL;
  67        }
  68
  69        /* Pack cmd and write to HW */
  70        data[0] = (msg->address >> 16) & 0xf;   /* addr[19:16] */
  71        if (aux->read)
  72                data[0] |=  BIT(4);             /* R/W */
  73
  74        data[1] = msg->address >> 8;            /* addr[15:8] */
  75        data[2] = msg->address;                 /* addr[7:0] */
  76        data[3] = msg->size - 1;                /* len[7:0] */
  77
  78        for (i = 0; i < len + 4; i++) {
  79                reg = (i < 4) ? data[i] : msgdata[i - 4];
  80                reg <<= DP_AUX_DATA_OFFSET;
  81                reg &= DP_AUX_DATA_MASK;
  82                reg |= DP_AUX_DATA_WRITE;
  83                /* index = 0, write */
  84                if (i == 0)
  85                        reg |= DP_AUX_DATA_INDEX_WRITE;
  86                aux->catalog->aux_data = reg;
  87                dp_catalog_aux_write_data(aux->catalog);
  88        }
  89
  90        dp_catalog_aux_clear_trans(aux->catalog, false);
  91        dp_catalog_aux_clear_hw_interrupts(aux->catalog);
  92
  93        reg = 0; /* Transaction number == 1 */
  94        if (!aux->native) { /* i2c */
  95                reg |= DP_AUX_TRANS_CTRL_I2C;
  96
  97                if (aux->no_send_addr)
  98                        reg |= DP_AUX_TRANS_CTRL_NO_SEND_ADDR;
  99
 100                if (aux->no_send_stop)
 101                        reg |= DP_AUX_TRANS_CTRL_NO_SEND_STOP;
 102        }
 103
 104        reg |= DP_AUX_TRANS_CTRL_GO;
 105        aux->catalog->aux_data = reg;
 106        dp_catalog_aux_write_trans(aux->catalog);
 107
 108        return len;
 109}
 110
 111static ssize_t dp_aux_cmd_fifo_tx(struct dp_aux_private *aux,
 112                              struct drm_dp_aux_msg *msg)
 113{
 114        ssize_t ret;
 115        unsigned long time_left;
 116
 117        reinit_completion(&aux->comp);
 118
 119        ret = dp_aux_write(aux, msg);
 120        if (ret < 0)
 121                return ret;
 122
 123        time_left = wait_for_completion_timeout(&aux->comp,
 124                                                msecs_to_jiffies(250));
 125        if (!time_left)
 126                return -ETIMEDOUT;
 127
 128        return ret;
 129}
 130
 131static ssize_t dp_aux_cmd_fifo_rx(struct dp_aux_private *aux,
 132                struct drm_dp_aux_msg *msg)
 133{
 134        u32 data;
 135        u8 *dp;
 136        u32 i, actual_i;
 137        u32 len = msg->size;
 138
 139        dp_catalog_aux_clear_trans(aux->catalog, true);
 140
 141        data = DP_AUX_DATA_INDEX_WRITE; /* INDEX_WRITE */
 142        data |= DP_AUX_DATA_READ;  /* read */
 143
 144        aux->catalog->aux_data = data;
 145        dp_catalog_aux_write_data(aux->catalog);
 146
 147        dp = msg->buffer;
 148
 149        /* discard first byte */
 150        data = dp_catalog_aux_read_data(aux->catalog);
 151
 152        for (i = 0; i < len; i++) {
 153                data = dp_catalog_aux_read_data(aux->catalog);
 154                *dp++ = (u8)((data >> DP_AUX_DATA_OFFSET) & 0xff);
 155
 156                actual_i = (data >> DP_AUX_DATA_INDEX_OFFSET) & 0xFF;
 157                if (i != actual_i)
 158                        break;
 159        }
 160
 161        return i;
 162}
 163
 164static void dp_aux_native_handler(struct dp_aux_private *aux, u32 isr)
 165{
 166        if (isr & DP_INTR_AUX_I2C_DONE)
 167                aux->aux_error_num = DP_AUX_ERR_NONE;
 168        else if (isr & DP_INTR_WRONG_ADDR)
 169                aux->aux_error_num = DP_AUX_ERR_ADDR;
 170        else if (isr & DP_INTR_TIMEOUT)
 171                aux->aux_error_num = DP_AUX_ERR_TOUT;
 172        if (isr & DP_INTR_NACK_DEFER)
 173                aux->aux_error_num = DP_AUX_ERR_NACK;
 174        if (isr & DP_INTR_AUX_ERROR) {
 175                aux->aux_error_num = DP_AUX_ERR_PHY;
 176                dp_catalog_aux_clear_hw_interrupts(aux->catalog);
 177        }
 178}
 179
 180static void dp_aux_i2c_handler(struct dp_aux_private *aux, u32 isr)
 181{
 182        if (isr & DP_INTR_AUX_I2C_DONE) {
 183                if (isr & (DP_INTR_I2C_NACK | DP_INTR_I2C_DEFER))
 184                        aux->aux_error_num = DP_AUX_ERR_NACK;
 185                else
 186                        aux->aux_error_num = DP_AUX_ERR_NONE;
 187        } else {
 188                if (isr & DP_INTR_WRONG_ADDR)
 189                        aux->aux_error_num = DP_AUX_ERR_ADDR;
 190                else if (isr & DP_INTR_TIMEOUT)
 191                        aux->aux_error_num = DP_AUX_ERR_TOUT;
 192                if (isr & DP_INTR_NACK_DEFER)
 193                        aux->aux_error_num = DP_AUX_ERR_NACK_DEFER;
 194                if (isr & DP_INTR_I2C_NACK)
 195                        aux->aux_error_num = DP_AUX_ERR_NACK;
 196                if (isr & DP_INTR_I2C_DEFER)
 197                        aux->aux_error_num = DP_AUX_ERR_DEFER;
 198                if (isr & DP_INTR_AUX_ERROR) {
 199                        aux->aux_error_num = DP_AUX_ERR_PHY;
 200                        dp_catalog_aux_clear_hw_interrupts(aux->catalog);
 201                }
 202        }
 203}
 204
 205static void dp_aux_update_offset_and_segment(struct dp_aux_private *aux,
 206                                             struct drm_dp_aux_msg *input_msg)
 207{
 208        u32 edid_address = 0x50;
 209        u32 segment_address = 0x30;
 210        bool i2c_read = input_msg->request &
 211                (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
 212        u8 *data;
 213
 214        if (aux->native || i2c_read || ((input_msg->address != edid_address) &&
 215                (input_msg->address != segment_address)))
 216                return;
 217
 218
 219        data = input_msg->buffer;
 220        if (input_msg->address == segment_address)
 221                aux->segment = *data;
 222        else
 223                aux->offset = *data;
 224}
 225
 226/**
 227 * dp_aux_transfer_helper() - helper function for EDID read transactions
 228 *
 229 * @aux: DP AUX private structure
 230 * @input_msg: input message from DRM upstream APIs
 231 * @send_seg: send the segment to sink
 232 *
 233 * return: void
 234 *
 235 * This helper function is used to fix EDID reads for non-compliant
 236 * sinks that do not handle the i2c middle-of-transaction flag correctly.
 237 */
 238static void dp_aux_transfer_helper(struct dp_aux_private *aux,
 239                                   struct drm_dp_aux_msg *input_msg,
 240                                   bool send_seg)
 241{
 242        struct drm_dp_aux_msg helper_msg;
 243        u32 message_size = 0x10;
 244        u32 segment_address = 0x30;
 245        u32 const edid_block_length = 0x80;
 246        bool i2c_mot = input_msg->request & DP_AUX_I2C_MOT;
 247        bool i2c_read = input_msg->request &
 248                (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
 249
 250        if (!i2c_mot || !i2c_read || (input_msg->size == 0))
 251                return;
 252
 253        /*
 254         * Sending the segment value and EDID offset will be performed
 255         * from the DRM upstream EDID driver for each block. Avoid
 256         * duplicate AUX transactions related to this while reading the
 257         * first 16 bytes of each block.
 258         */
 259        if (!(aux->offset % edid_block_length) || !send_seg)
 260                goto end;
 261
 262        aux->read = false;
 263        aux->cmd_busy = true;
 264        aux->no_send_addr = true;
 265        aux->no_send_stop = true;
 266
 267        /*
 268         * Send the segment address for every i2c read in which the
 269         * middle-of-tranaction flag is set. This is required to support EDID
 270         * reads of more than 2 blocks as the segment address is reset to 0
 271         * since we are overriding the middle-of-transaction flag for read
 272         * transactions.
 273         */
 274
 275        if (aux->segment) {
 276                memset(&helper_msg, 0, sizeof(helper_msg));
 277                helper_msg.address = segment_address;
 278                helper_msg.buffer = &aux->segment;
 279                helper_msg.size = 1;
 280                dp_aux_cmd_fifo_tx(aux, &helper_msg);
 281        }
 282
 283        /*
 284         * Send the offset address for every i2c read in which the
 285         * middle-of-transaction flag is set. This will ensure that the sink
 286         * will update its read pointer and return the correct portion of the
 287         * EDID buffer in the subsequent i2c read trasntion triggered in the
 288         * native AUX transfer function.
 289         */
 290        memset(&helper_msg, 0, sizeof(helper_msg));
 291        helper_msg.address = input_msg->address;
 292        helper_msg.buffer = &aux->offset;
 293        helper_msg.size = 1;
 294        dp_aux_cmd_fifo_tx(aux, &helper_msg);
 295
 296end:
 297        aux->offset += message_size;
 298        if (aux->offset == 0x80 || aux->offset == 0x100)
 299                aux->segment = 0x0; /* reset segment at end of block */
 300}
 301
 302/*
 303 * This function does the real job to process an AUX transaction.
 304 * It will call aux_reset() function to reset the AUX channel,
 305 * if the waiting is timeout.
 306 */
 307static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux,
 308                               struct drm_dp_aux_msg *msg)
 309{
 310        ssize_t ret;
 311        int const aux_cmd_native_max = 16;
 312        int const aux_cmd_i2c_max = 128;
 313        struct dp_aux_private *aux;
 314
 315        aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
 316
 317        aux->native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
 318
 319        /* Ignore address only message */
 320        if (msg->size == 0 || !msg->buffer) {
 321                msg->reply = aux->native ?
 322                        DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
 323                return msg->size;
 324        }
 325
 326        /* msg sanity check */
 327        if ((aux->native && msg->size > aux_cmd_native_max) ||
 328            msg->size > aux_cmd_i2c_max) {
 329                DRM_ERROR("%s: invalid msg: size(%zu), request(%x)\n",
 330                        __func__, msg->size, msg->request);
 331                return -EINVAL;
 332        }
 333
 334        mutex_lock(&aux->mutex);
 335        if (!aux->initted) {
 336                ret = -EIO;
 337                goto exit;
 338        }
 339
 340        dp_aux_update_offset_and_segment(aux, msg);
 341        dp_aux_transfer_helper(aux, msg, true);
 342
 343        aux->read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
 344        aux->cmd_busy = true;
 345
 346        if (aux->read) {
 347                aux->no_send_addr = true;
 348                aux->no_send_stop = false;
 349        } else {
 350                aux->no_send_addr = true;
 351                aux->no_send_stop = true;
 352        }
 353
 354        ret = dp_aux_cmd_fifo_tx(aux, msg);
 355        if (ret < 0) {
 356                if (aux->native) {
 357                        aux->retry_cnt++;
 358                        if (!(aux->retry_cnt % MAX_AUX_RETRIES))
 359                                dp_catalog_aux_update_cfg(aux->catalog);
 360                }
 361                /* reset aux if link is in connected state */
 362                if (dp_catalog_link_is_connected(aux->catalog))
 363                        dp_catalog_aux_reset(aux->catalog);
 364        } else {
 365                aux->retry_cnt = 0;
 366                switch (aux->aux_error_num) {
 367                case DP_AUX_ERR_NONE:
 368                        if (aux->read)
 369                                ret = dp_aux_cmd_fifo_rx(aux, msg);
 370                        msg->reply = aux->native ? DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
 371                        break;
 372                case DP_AUX_ERR_DEFER:
 373                        msg->reply = aux->native ? DP_AUX_NATIVE_REPLY_DEFER : DP_AUX_I2C_REPLY_DEFER;
 374                        break;
 375                case DP_AUX_ERR_PHY:
 376                case DP_AUX_ERR_ADDR:
 377                case DP_AUX_ERR_NACK:
 378                case DP_AUX_ERR_NACK_DEFER:
 379                        msg->reply = aux->native ? DP_AUX_NATIVE_REPLY_NACK : DP_AUX_I2C_REPLY_NACK;
 380                        break;
 381                case DP_AUX_ERR_TOUT:
 382                        ret = -ETIMEDOUT;
 383                        break;
 384                }
 385        }
 386
 387        aux->cmd_busy = false;
 388
 389exit:
 390        mutex_unlock(&aux->mutex);
 391
 392        return ret;
 393}
 394
 395void dp_aux_isr(struct drm_dp_aux *dp_aux)
 396{
 397        u32 isr;
 398        struct dp_aux_private *aux;
 399
 400        if (!dp_aux) {
 401                DRM_ERROR("invalid input\n");
 402                return;
 403        }
 404
 405        aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
 406
 407        isr = dp_catalog_aux_get_irq(aux->catalog);
 408
 409        if (!aux->cmd_busy)
 410                return;
 411
 412        if (aux->native)
 413                dp_aux_native_handler(aux, isr);
 414        else
 415                dp_aux_i2c_handler(aux, isr);
 416
 417        complete(&aux->comp);
 418}
 419
 420void dp_aux_reconfig(struct drm_dp_aux *dp_aux)
 421{
 422        struct dp_aux_private *aux;
 423
 424        aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
 425
 426        dp_catalog_aux_update_cfg(aux->catalog);
 427        dp_catalog_aux_reset(aux->catalog);
 428}
 429
 430void dp_aux_init(struct drm_dp_aux *dp_aux)
 431{
 432        struct dp_aux_private *aux;
 433
 434        if (!dp_aux) {
 435                DRM_ERROR("invalid input\n");
 436                return;
 437        }
 438
 439        aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
 440
 441        mutex_lock(&aux->mutex);
 442
 443        dp_catalog_aux_enable(aux->catalog, true);
 444        aux->retry_cnt = 0;
 445        aux->initted = true;
 446
 447        mutex_unlock(&aux->mutex);
 448}
 449
 450void dp_aux_deinit(struct drm_dp_aux *dp_aux)
 451{
 452        struct dp_aux_private *aux;
 453
 454        aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
 455
 456        mutex_lock(&aux->mutex);
 457
 458        aux->initted = false;
 459        dp_catalog_aux_enable(aux->catalog, false);
 460
 461        mutex_unlock(&aux->mutex);
 462}
 463
 464int dp_aux_register(struct drm_dp_aux *dp_aux)
 465{
 466        struct dp_aux_private *aux;
 467        int ret;
 468
 469        if (!dp_aux) {
 470                DRM_ERROR("invalid input\n");
 471                return -EINVAL;
 472        }
 473
 474        aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
 475
 476        aux->dp_aux.name = "dpu_dp_aux";
 477        aux->dp_aux.dev = aux->dev;
 478        aux->dp_aux.transfer = dp_aux_transfer;
 479        ret = drm_dp_aux_register(&aux->dp_aux);
 480        if (ret) {
 481                DRM_ERROR("%s: failed to register drm aux: %d\n", __func__,
 482                                ret);
 483                return ret;
 484        }
 485
 486        return 0;
 487}
 488
 489void dp_aux_unregister(struct drm_dp_aux *dp_aux)
 490{
 491        drm_dp_aux_unregister(dp_aux);
 492}
 493
 494struct drm_dp_aux *dp_aux_get(struct device *dev, struct dp_catalog *catalog)
 495{
 496        struct dp_aux_private *aux;
 497
 498        if (!catalog) {
 499                DRM_ERROR("invalid input\n");
 500                return ERR_PTR(-ENODEV);
 501        }
 502
 503        aux = devm_kzalloc(dev, sizeof(*aux), GFP_KERNEL);
 504        if (!aux)
 505                return ERR_PTR(-ENOMEM);
 506
 507        init_completion(&aux->comp);
 508        aux->cmd_busy = false;
 509        mutex_init(&aux->mutex);
 510
 511        aux->dev = dev;
 512        aux->catalog = catalog;
 513        aux->retry_cnt = 0;
 514
 515        return &aux->dp_aux;
 516}
 517
 518void dp_aux_put(struct drm_dp_aux *dp_aux)
 519{
 520        struct dp_aux_private *aux;
 521
 522        if (!dp_aux)
 523                return;
 524
 525        aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
 526
 527        mutex_destroy(&aux->mutex);
 528
 529        devm_kfree(aux->dev, aux);
 530}
 531