]> Git Repo - linux.git/blob - drivers/gpu/drm/msm/edp/edp_aux.c
Merge tag 'linux-kselftest-next-5.14-rc1' of git://git.kernel.org/pub/scm/linux/kerne...
[linux.git] / drivers / gpu / drm / msm / edp / edp_aux.c
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
20 struct 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
33 static 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
80 static 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  */
110 static 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
182 unlock_exit:
183         mutex_unlock(&aux->msg_mutex);
184         return ret;
185 }
186
187 void *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
218 void 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
226 irqreturn_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
243 void 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
This page took 0.051024 seconds and 4 git commands to generate.