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