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