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