Linux Audio

Check our new training course

Linux kernel drivers training

May 6-19, 2025
Register
Loading...
Note: File does not exist in v3.1.
  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
 20struct 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
 33static 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
 80static 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 */
110static 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
182unlock_exit:
183	mutex_unlock(&aux->msg_mutex);
184	return ret;
185}
186
187void *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
218void 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
226irqreturn_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
243void 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