linux/drivers/gpu/drm/msm/edp/edp_aux.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
   4 */
   5
   6#include "edp.h"
   7#include "edp.xml.h"
   8
   9#define AUX_CMD_FIFO_LEN        144
  10#define AUX_CMD_NATIVE_MAX      16
  11#define AUX_CMD_I2C_MAX         128
  12
  13#define EDP_INTR_AUX_I2C_ERR    \
  14        (EDP_INTERRUPT_REG_1_WRONG_ADDR | EDP_INTERRUPT_REG_1_TIMEOUT | \
  15        EDP_INTERRUPT_REG_1_NACK_DEFER | EDP_INTERRUPT_REG_1_WRONG_DATA_CNT | \
  16        EDP_INTERRUPT_REG_1_I2C_NACK | EDP_INTERRUPT_REG_1_I2C_DEFER)
  17#define EDP_INTR_TRANS_STATUS   \
  18        (EDP_INTERRUPT_REG_1_AUX_I2C_DONE | EDP_INTR_AUX_I2C_ERR)
  19
  20struct edp_aux {
  21        void __iomem *base;
  22        bool msg_err;
  23
  24        struct completion msg_comp;
  25
  26        /* To prevent the message transaction routine from reentry. */
  27        struct mutex msg_mutex;
  28
  29        struct drm_dp_aux drm_aux;
  30};
  31#define to_edp_aux(x) container_of(x, struct edp_aux, drm_aux)
  32
  33static int edp_msg_fifo_tx(struct edp_aux *aux, struct drm_dp_aux_msg *msg)
  34{
  35        u32 data[4];
  36        u32 reg, len;
  37        bool native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
  38        bool read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
  39        u8 *msgdata = msg->buffer;
  40        int i;
  41
  42        if (read)
  43                len = 4;
  44        else
  45                len = msg->size + 4;
  46
  47        /*
  48         * cmd fifo only has depth of 144 bytes
  49         */
  50        if (len > AUX_CMD_FIFO_LEN)
  51                return -EINVAL;
  52
  53        /* Pack cmd and write to HW */
  54        data[0] = (msg->address >> 16) & 0xf;   /* addr[19:16] */
  55        if (read)
  56                data[0] |=  BIT(4);             /* R/W */
  57
  58        data[1] = (msg->address >> 8) & 0xff;   /* addr[15:8] */
  59        data[2] = msg->address & 0xff;          /* addr[7:0] */
  60        data[3] = (msg->size - 1) & 0xff;       /* len[7:0] */
  61
  62        for (i = 0; i < len; i++) {
  63                reg = (i < 4) ? data[i] : msgdata[i - 4];
  64                reg = EDP_AUX_DATA_DATA(reg); /* index = 0, write */
  65                if (i == 0)
  66                        reg |= EDP_AUX_DATA_INDEX_WRITE;
  67                edp_write(aux->base + REG_EDP_AUX_DATA, reg);
  68        }
  69
  70        reg = 0; /* Transaction number is always 1 */
  71        if (!native) /* i2c */
  72                reg |= EDP_AUX_TRANS_CTRL_I2C;
  73
  74        reg |= EDP_AUX_TRANS_CTRL_GO;
  75        edp_write(aux->base + REG_EDP_AUX_TRANS_CTRL, reg);
  76
  77        return 0;
  78}
  79
  80static int edp_msg_fifo_rx(struct edp_aux *aux, struct drm_dp_aux_msg *msg)
  81{
  82        u32 data;
  83        u8 *dp;
  84        int i;
  85        u32 len = msg->size;
  86
  87        edp_write(aux->base + REG_EDP_AUX_DATA,
  88                EDP_AUX_DATA_INDEX_WRITE | EDP_AUX_DATA_READ); /* index = 0 */
  89
  90        dp = msg->buffer;
  91
  92        /* discard first byte */
  93        data = edp_read(aux->base + REG_EDP_AUX_DATA);
  94        for (i = 0; i < len; i++) {
  95                data = edp_read(aux->base + REG_EDP_AUX_DATA);
  96                dp[i] = (u8)((data >> 8) & 0xff);
  97        }
  98
  99        return 0;
 100}
 101
 102/*
 103 * This function does the real job to process an AUX transaction.
 104 * It will call msm_edp_aux_ctrl() function to reset the AUX channel,
 105 * if the waiting is timeout.
 106 * The caller who triggers the transaction should avoid the
 107 * msm_edp_aux_ctrl() running concurrently in other threads, i.e.
 108 * start transaction only when AUX channel is fully enabled.
 109 */
 110static ssize_t edp_aux_transfer(struct drm_dp_aux *drm_aux,
 111                struct drm_dp_aux_msg *msg)
 112{
 113        struct edp_aux *aux = to_edp_aux(drm_aux);
 114        ssize_t ret;
 115        unsigned long time_left;
 116        bool native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
 117        bool read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
 118
 119        /* Ignore address only message */
 120        if ((msg->size == 0) || (msg->buffer == NULL)) {
 121                msg->reply = native ?
 122                        DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
 123                return msg->size;
 124        }
 125
 126        /* msg sanity check */
 127        if ((native && (msg->size > AUX_CMD_NATIVE_MAX)) ||
 128                (msg->size > AUX_CMD_I2C_MAX)) {
 129                pr_err("%s: invalid msg: size(%zu), request(%x)\n",
 130                        __func__, msg->size, msg->request);
 131                return -EINVAL;
 132        }
 133
 134        mutex_lock(&aux->msg_mutex);
 135
 136        aux->msg_err = false;
 137        reinit_completion(&aux->msg_comp);
 138
 139        ret = edp_msg_fifo_tx(aux, msg);
 140        if (ret < 0)
 141                goto unlock_exit;
 142
 143        DBG("wait_for_completion");
 144        time_left = wait_for_completion_timeout(&aux->msg_comp,
 145                                                msecs_to_jiffies(300));
 146        if (!time_left) {
 147                /*
 148                 * Clear GO and reset AUX channel
 149                 * to cancel the current transaction.
 150                 */
 151                edp_write(aux->base + REG_EDP_AUX_TRANS_CTRL, 0);
 152                msm_edp_aux_ctrl(aux, 1);
 153                pr_err("%s: aux timeout,\n", __func__);
 154                ret = -ETIMEDOUT;
 155                goto unlock_exit;
 156        }
 157        DBG("completion");
 158
 159        if (!aux->msg_err) {
 160                if (read) {
 161                        ret = edp_msg_fifo_rx(aux, msg);
 162                        if (ret < 0)
 163                                goto unlock_exit;
 164                }
 165
 166                msg->reply = native ?
 167                        DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
 168        } else {
 169                /* Reply defer to retry */
 170                msg->reply = native ?
 171                        DP_AUX_NATIVE_REPLY_DEFER : DP_AUX_I2C_REPLY_DEFER;
 172                /*
 173                 * The sleep time in caller is not long enough to make sure
 174                 * our H/W completes transactions. Add more defer time here.
 175                 */
 176                msleep(100);
 177        }
 178
 179        /* Return requested size for success or retry */
 180        ret = msg->size;
 181
 182unlock_exit:
 183        mutex_unlock(&aux->msg_mutex);
 184        return ret;
 185}
 186
 187void *msm_edp_aux_init(struct msm_edp *edp, void __iomem *regbase, struct drm_dp_aux **drm_aux)
 188{
 189        struct device *dev = &edp->pdev->dev;
 190        struct edp_aux *aux = NULL;
 191        int ret;
 192
 193        DBG("");
 194        aux = devm_kzalloc(dev, sizeof(*aux), GFP_KERNEL);
 195        if (!aux)
 196                return NULL;
 197
 198        aux->base = regbase;
 199        mutex_init(&aux->msg_mutex);
 200        init_completion(&aux->msg_comp);
 201
 202        aux->drm_aux.name = "msm_edp_aux";
 203        aux->drm_aux.dev = dev;
 204        aux->drm_aux.drm_dev = edp->dev;
 205        aux->drm_aux.transfer = edp_aux_transfer;
 206        ret = drm_dp_aux_register(&aux->drm_aux);
 207        if (ret) {
 208                pr_err("%s: failed to register drm aux: %d\n", __func__, ret);
 209                mutex_destroy(&aux->msg_mutex);
 210        }
 211
 212        if (drm_aux && aux)
 213                *drm_aux = &aux->drm_aux;
 214
 215        return aux;
 216}
 217
 218void msm_edp_aux_destroy(struct device *dev, struct edp_aux *aux)
 219{
 220        if (aux) {
 221                drm_dp_aux_unregister(&aux->drm_aux);
 222                mutex_destroy(&aux->msg_mutex);
 223        }
 224}
 225
 226irqreturn_t msm_edp_aux_irq(struct edp_aux *aux, u32 isr)
 227{
 228        if (isr & EDP_INTR_TRANS_STATUS) {
 229                DBG("isr=%x", isr);
 230                edp_write(aux->base + REG_EDP_AUX_TRANS_CTRL, 0);
 231
 232                if (isr & EDP_INTR_AUX_I2C_ERR)
 233                        aux->msg_err = true;
 234                else
 235                        aux->msg_err = false;
 236
 237                complete(&aux->msg_comp);
 238        }
 239
 240        return IRQ_HANDLED;
 241}
 242
 243void msm_edp_aux_ctrl(struct edp_aux *aux, int enable)
 244{
 245        u32 data;
 246
 247        DBG("enable=%d", enable);
 248        data = edp_read(aux->base + REG_EDP_AUX_CTRL);
 249
 250        if (enable) {
 251                data |= EDP_AUX_CTRL_RESET;
 252                edp_write(aux->base + REG_EDP_AUX_CTRL, data);
 253                /* Make sure full reset */
 254                wmb();
 255                usleep_range(500, 1000);
 256
 257                data &= ~EDP_AUX_CTRL_RESET;
 258                data |= EDP_AUX_CTRL_ENABLE;
 259                edp_write(aux->base + REG_EDP_AUX_CTRL, data);
 260        } else {
 261                data &= ~EDP_AUX_CTRL_ENABLE;
 262                edp_write(aux->base + REG_EDP_AUX_CTRL, data);
 263        }
 264}
 265
 266