• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
28 struct 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 
edp_msg_fifo_tx(struct edp_aux * aux,struct drm_dp_aux_msg * msg)41 static 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 
edp_msg_fifo_rx(struct edp_aux * aux,struct drm_dp_aux_msg * msg)88 static 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  */
edp_aux_transfer(struct drm_dp_aux * drm_aux,struct drm_dp_aux_msg * msg)118 static 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 
190 unlock_exit:
191 	mutex_unlock(&aux->msg_mutex);
192 	return ret;
193 }
194 
msm_edp_aux_init(struct device * dev,void __iomem * regbase,struct drm_dp_aux ** drm_aux)195 void *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 
msm_edp_aux_destroy(struct device * dev,struct edp_aux * aux)225 void 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 
msm_edp_aux_irq(struct edp_aux * aux,u32 isr)233 irqreturn_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 
msm_edp_aux_ctrl(struct edp_aux * aux,int enable)250 void 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