blob: 5f77bf0adf1d10ff519acd6e79e290de1cdd64c7 [file] [log] [blame]
Hai Liab5b0102015-01-07 18:47:44 -05001/*
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 */
118ssize_t edp_aux_transfer(struct drm_dp_aux *drm_aux, struct drm_dp_aux_msg *msg)
119{
120 struct edp_aux *aux = to_edp_aux(drm_aux);
121 ssize_t ret;
Nicholas Mc Guire9f68ef92015-04-04 04:39:07 +0200122 unsigned long time_left;
Hai Liab5b0102015-01-07 18:47:44 -0500123 bool native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
124 bool read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
125
126 /* Ignore address only message */
127 if ((msg->size == 0) || (msg->buffer == NULL)) {
128 msg->reply = native ?
129 DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
130 return msg->size;
131 }
132
133 /* msg sanity check */
134 if ((native && (msg->size > AUX_CMD_NATIVE_MAX)) ||
135 (msg->size > AUX_CMD_I2C_MAX)) {
Thierry Redingfc99f972015-04-09 16:39:51 +0200136 pr_err("%s: invalid msg: size(%zu), request(%x)\n",
Hai Liab5b0102015-01-07 18:47:44 -0500137 __func__, msg->size, msg->request);
138 return -EINVAL;
139 }
140
141 mutex_lock(&aux->msg_mutex);
142
143 aux->msg_err = false;
144 reinit_completion(&aux->msg_comp);
145
146 ret = edp_msg_fifo_tx(aux, msg);
147 if (ret < 0)
148 goto unlock_exit;
149
150 DBG("wait_for_completion");
Nicholas Mc Guire9f68ef92015-04-04 04:39:07 +0200151 time_left = wait_for_completion_timeout(&aux->msg_comp, 300);
152 if (!time_left) {
Hai Liab5b0102015-01-07 18:47:44 -0500153 /*
154 * Clear GO and reset AUX channel
155 * to cancel the current transaction.
156 */
157 edp_write(aux->base + REG_EDP_AUX_TRANS_CTRL, 0);
158 msm_edp_aux_ctrl(aux, 1);
Nicholas Mc Guire9f68ef92015-04-04 04:39:07 +0200159 pr_err("%s: aux timeout, %lu\n", __func__, time_left);
160 ret = -ETIMEDOUT;
Hai Liab5b0102015-01-07 18:47:44 -0500161 goto unlock_exit;
162 }
163 DBG("completion");
164
165 if (!aux->msg_err) {
166 if (read) {
167 ret = edp_msg_fifo_rx(aux, msg);
168 if (ret < 0)
169 goto unlock_exit;
170 }
171
172 msg->reply = native ?
173 DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
174 } else {
175 /* Reply defer to retry */
176 msg->reply = native ?
177 DP_AUX_NATIVE_REPLY_DEFER : DP_AUX_I2C_REPLY_DEFER;
178 /*
179 * The sleep time in caller is not long enough to make sure
180 * our H/W completes transactions. Add more defer time here.
181 */
182 msleep(100);
183 }
184
185 /* Return requested size for success or retry */
186 ret = msg->size;
187
188unlock_exit:
189 mutex_unlock(&aux->msg_mutex);
190 return ret;
191}
192
193void *msm_edp_aux_init(struct device *dev, void __iomem *regbase,
194 struct drm_dp_aux **drm_aux)
195{
196 struct edp_aux *aux = NULL;
197 int ret;
198
199 DBG("");
200 aux = devm_kzalloc(dev, sizeof(*aux), GFP_KERNEL);
201 if (!aux)
202 return NULL;
203
204 aux->base = regbase;
205 mutex_init(&aux->msg_mutex);
206 init_completion(&aux->msg_comp);
207
208 aux->drm_aux.name = "msm_edp_aux";
209 aux->drm_aux.dev = dev;
210 aux->drm_aux.transfer = edp_aux_transfer;
211 ret = drm_dp_aux_register(&aux->drm_aux);
212 if (ret) {
213 pr_err("%s: failed to register drm aux: %d\n", __func__, ret);
214 mutex_destroy(&aux->msg_mutex);
215 }
216
217 if (drm_aux && aux)
218 *drm_aux = &aux->drm_aux;
219
220 return aux;
221}
222
223void msm_edp_aux_destroy(struct device *dev, struct edp_aux *aux)
224{
225 if (aux) {
226 drm_dp_aux_unregister(&aux->drm_aux);
227 mutex_destroy(&aux->msg_mutex);
228 }
229}
230
231irqreturn_t msm_edp_aux_irq(struct edp_aux *aux, u32 isr)
232{
233 if (isr & EDP_INTR_TRANS_STATUS) {
234 DBG("isr=%x", isr);
235 edp_write(aux->base + REG_EDP_AUX_TRANS_CTRL, 0);
236
237 if (isr & EDP_INTR_AUX_I2C_ERR)
238 aux->msg_err = true;
239 else
240 aux->msg_err = false;
241
242 complete(&aux->msg_comp);
243 }
244
245 return IRQ_HANDLED;
246}
247
248void msm_edp_aux_ctrl(struct edp_aux *aux, int enable)
249{
250 u32 data;
251
252 DBG("enable=%d", enable);
253 data = edp_read(aux->base + REG_EDP_AUX_CTRL);
254
255 if (enable) {
256 data |= EDP_AUX_CTRL_RESET;
257 edp_write(aux->base + REG_EDP_AUX_CTRL, data);
258 /* Make sure full reset */
259 wmb();
260 usleep_range(500, 1000);
261
262 data &= ~EDP_AUX_CTRL_RESET;
263 data |= EDP_AUX_CTRL_ENABLE;
264 edp_write(aux->base + REG_EDP_AUX_CTRL, data);
265 } else {
266 data &= ~EDP_AUX_CTRL_ENABLE;
267 edp_write(aux->base + REG_EDP_AUX_CTRL, data);
268 }
269}
270