File Index
Files and directories
Sign in
FILE

dp_aux.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/msm/dp/dp_aux.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
  4 */
  5
  6#include <linux/delay.h>
  7#include <linux/iopoll.h>
  8#include <linux/phy/phy.h>
  9#include <drm/drm_print.h>
 10
 11#include "dp_reg.h"
 12#include "dp_aux.h"
 13
 14enum msm_dp_aux_err {
 15	DP_AUX_ERR_NONE,
 16	DP_AUX_ERR_ADDR,
 17	DP_AUX_ERR_TOUT,
 18	DP_AUX_ERR_NACK,
 19	DP_AUX_ERR_DEFER,
 20	DP_AUX_ERR_NACK_DEFER,
 21	DP_AUX_ERR_PHY,
 22};
 23
 24struct msm_dp_aux_private {
 25	struct device *dev;
 26	void __iomem *aux_base;
 27
 28	struct phy *phy;
 29
 30	struct mutex mutex;
 31	struct completion comp;
 32
 33	enum msm_dp_aux_err aux_error_num;
 34	u32 retry_cnt;
 35	bool cmd_busy;
 36	bool native;
 37	bool read;
 38	bool no_send_addr;
 39	bool no_send_stop;
 40	bool initted;
 41	bool is_edp;
 42	bool enable_xfers;
 43	u32 offset;
 44	u32 segment;
 45
 46	struct drm_dp_aux msm_dp_aux;
 47};
 48
 49static inline u32 msm_dp_read_aux(struct msm_dp_aux_private *aux, u32 offset)
 50{
 51	return readl_relaxed(aux->aux_base + offset);
 52}
 53
 54static inline void msm_dp_write_aux(struct msm_dp_aux_private *aux,
 55				u32 offset, u32 data)
 56{
 57	/*
 58	 * To make sure aux reg writes happens before any other operation,
 59	 * this function uses writel() instread of writel_relaxed()
 60	 */
 61	writel(data, aux->aux_base + offset);
 62}
 63
 64static void msm_dp_aux_clear_hw_interrupts(struct msm_dp_aux_private *aux)
 65{
 66	msm_dp_read_aux(aux, REG_DP_PHY_AUX_INTERRUPT_STATUS);
 67	msm_dp_write_aux(aux, REG_DP_PHY_AUX_INTERRUPT_CLEAR, 0x1f);
 68	msm_dp_write_aux(aux, REG_DP_PHY_AUX_INTERRUPT_CLEAR, 0x9f);
 69	msm_dp_write_aux(aux, REG_DP_PHY_AUX_INTERRUPT_CLEAR, 0);
 70}
 71
 72/*
 73 * NOTE: resetting AUX controller will also clear any pending HPD related interrupts
 74 */
 75static void msm_dp_aux_reset(struct msm_dp_aux_private *aux)
 76{
 77	u32 aux_ctrl;
 78
 79	aux_ctrl = msm_dp_read_aux(aux, REG_DP_AUX_CTRL);
 80
 81	aux_ctrl |= DP_AUX_CTRL_RESET;
 82	msm_dp_write_aux(aux, REG_DP_AUX_CTRL, aux_ctrl);
 83	usleep_range(1000, 1100); /* h/w recommended delay */
 84
 85	aux_ctrl &= ~DP_AUX_CTRL_RESET;
 86	msm_dp_write_aux(aux, REG_DP_AUX_CTRL, aux_ctrl);
 87}
 88
 89static void msm_dp_aux_enable(struct msm_dp_aux_private *aux)
 90{
 91	u32 aux_ctrl;
 92
 93	aux_ctrl = msm_dp_read_aux(aux, REG_DP_AUX_CTRL);
 94
 95	msm_dp_write_aux(aux, REG_DP_TIMEOUT_COUNT, 0xffff);
 96	msm_dp_write_aux(aux, REG_DP_AUX_LIMITS, 0xffff);
 97
 98	aux_ctrl |= DP_AUX_CTRL_ENABLE;
 99	msm_dp_write_aux(aux, REG_DP_AUX_CTRL, aux_ctrl);
100}
101
102static void msm_dp_aux_disable(struct msm_dp_aux_private *aux)
103{
104	u32 aux_ctrl;
105
106	aux_ctrl = msm_dp_read_aux(aux, REG_DP_AUX_CTRL);
107	aux_ctrl &= ~DP_AUX_CTRL_ENABLE;
108	msm_dp_write_aux(aux, REG_DP_AUX_CTRL, aux_ctrl);
109}
110
111static int msm_dp_aux_wait_for_hpd_connect_state(struct msm_dp_aux_private *aux,
112					     unsigned long wait_us)
113{
114	u32 state;
115
116	/* poll for hpd connected status every 2ms and timeout after wait_us */
117	return readl_poll_timeout(aux->aux_base +
118				  REG_DP_DP_HPD_INT_STATUS,
119				  state, state & DP_DP_HPD_STATE_STATUS_CONNECTED,
120				  min(wait_us, 2000), wait_us);
121}
122
123#define MAX_AUX_RETRIES			5
124
125static ssize_t msm_dp_aux_write(struct msm_dp_aux_private *aux,
126			struct drm_dp_aux_msg *msg)
127{
128	u8 data[4];
129	u32 reg;
130	ssize_t len;
131	u8 *msgdata = msg->buffer;
132	int const AUX_CMD_FIFO_LEN = 128;
133	int i = 0;
134
135	if (aux->read)
136		len = 0;
137	else
138		len = msg->size;
139
140	/*
141	 * cmd fifo only has depth of 144 bytes
142	 * limit buf length to 128 bytes here
143	 */
144	if (len > AUX_CMD_FIFO_LEN - 4) {
145		DRM_ERROR("buf size greater than allowed size of 128 bytes\n");
146		return -EINVAL;
147	}
148
149	/* Pack cmd and write to HW */
150	data[0] = (msg->address >> 16) & 0xf;	/* addr[19:16] */
151	if (aux->read)
152		data[0] |=  BIT(4);		/* R/W */
153
154	data[1] = msg->address >> 8;		/* addr[15:8] */
155	data[2] = msg->address;			/* addr[7:0] */
156	data[3] = msg->size - 1;		/* len[7:0] */
157
158	for (i = 0; i < len + 4; i++) {
159		reg = (i < 4) ? data[i] : msgdata[i - 4];
160		reg <<= DP_AUX_DATA_OFFSET;
161		reg &= DP_AUX_DATA_MASK;
162		reg |= DP_AUX_DATA_WRITE;
163		/* index = 0, write */
164		if (i == 0)
165			reg |= DP_AUX_DATA_INDEX_WRITE;
166		msm_dp_write_aux(aux, REG_DP_AUX_DATA, reg);
167	}
168
169	msm_dp_write_aux(aux, REG_DP_AUX_TRANS_CTRL, 0);
170	msm_dp_aux_clear_hw_interrupts(aux);
171
172	reg = 0; /* Transaction number == 1 */
173	if (!aux->native) { /* i2c */
174		reg |= DP_AUX_TRANS_CTRL_I2C;
175
176		if (aux->no_send_addr)
177			reg |= DP_AUX_TRANS_CTRL_NO_SEND_ADDR;
178
179		if (aux->no_send_stop)
180			reg |= DP_AUX_TRANS_CTRL_NO_SEND_STOP;
181	}
182
183	reg |= DP_AUX_TRANS_CTRL_GO;
184	msm_dp_write_aux(aux, REG_DP_AUX_TRANS_CTRL, reg);
185
186	return len;
187}
188
189static ssize_t msm_dp_aux_cmd_fifo_tx(struct msm_dp_aux_private *aux,
190			      struct drm_dp_aux_msg *msg)
191{
192	ssize_t ret;
193	unsigned long time_left;
194
195	reinit_completion(&aux->comp);
196
197	ret = msm_dp_aux_write(aux, msg);
198	if (ret < 0)
199		return ret;
200
201	time_left = wait_for_completion_timeout(&aux->comp,
202						msecs_to_jiffies(250));
203	if (!time_left)
204		return -ETIMEDOUT;
205
206	return ret;
207}
208
209static ssize_t msm_dp_aux_cmd_fifo_rx(struct msm_dp_aux_private *aux,
210		struct drm_dp_aux_msg *msg)
211{
212	u32 data;
213	u8 *dp;
214	u32 i, actual_i;
215	u32 len = msg->size;
216
217	data = msm_dp_read_aux(aux, REG_DP_AUX_TRANS_CTRL);
218	data &= ~DP_AUX_TRANS_CTRL_GO;
219	msm_dp_write_aux(aux, REG_DP_AUX_TRANS_CTRL, data);
220
221	data = DP_AUX_DATA_INDEX_WRITE; /* INDEX_WRITE */
222	data |= DP_AUX_DATA_READ;  /* read */
223
224	msm_dp_write_aux(aux, REG_DP_AUX_DATA, data);
225
226	dp = msg->buffer;
227
228	/* discard first byte */
229	data = msm_dp_read_aux(aux, REG_DP_AUX_DATA);
230
231	for (i = 0; i < len; i++) {
232		data = msm_dp_read_aux(aux, REG_DP_AUX_DATA);
233		*dp++ = (u8)((data >> DP_AUX_DATA_OFFSET) & 0xff);
234
235		actual_i = (data >> DP_AUX_DATA_INDEX_OFFSET) & 0xFF;
236		if (i != actual_i)
237			break;
238	}
239
240	return i;
241}
242
243static void msm_dp_aux_update_offset_and_segment(struct msm_dp_aux_private *aux,
244					     struct drm_dp_aux_msg *input_msg)
245{
246	u32 edid_address = 0x50;
247	u32 segment_address = 0x30;
248	bool i2c_read = input_msg->request &
249		(DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
250	u8 *data;
251
252	if (aux->native || i2c_read || ((input_msg->address != edid_address) &&
253		(input_msg->address != segment_address)))
254		return;
255
256
257	data = input_msg->buffer;
258	if (input_msg->address == segment_address)
259		aux->segment = *data;
260	else
261		aux->offset = *data;
262}
263
264/**
265 * msm_dp_aux_transfer_helper() - helper function for EDID read transactions
266 *
267 * @aux: DP AUX private structure
268 * @input_msg: input message from DRM upstream APIs
269 * @send_seg: send the segment to sink
270 *
271 * return: void
272 *
273 * This helper function is used to fix EDID reads for non-compliant
274 * sinks that do not handle the i2c middle-of-transaction flag correctly.
275 */
276static void msm_dp_aux_transfer_helper(struct msm_dp_aux_private *aux,
277				   struct drm_dp_aux_msg *input_msg,
278				   bool send_seg)
279{
280	struct drm_dp_aux_msg helper_msg;
281	u32 message_size = 0x10;
282	u32 segment_address = 0x30;
283	u32 const edid_block_length = 0x80;
284	bool i2c_mot = input_msg->request & DP_AUX_I2C_MOT;
285	bool i2c_read = input_msg->request &
286		(DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
287
288	if (!i2c_mot || !i2c_read || (input_msg->size == 0))
289		return;
290
291	/*
292	 * Sending the segment value and EDID offset will be performed
293	 * from the DRM upstream EDID driver for each block. Avoid
294	 * duplicate AUX transactions related to this while reading the
295	 * first 16 bytes of each block.
296	 */
297	if (!(aux->offset % edid_block_length) || !send_seg)
298		goto end;
299
300	aux->read = false;
301	aux->cmd_busy = true;
302	aux->no_send_addr = true;
303	aux->no_send_stop = true;
304
305	/*
306	 * Send the segment address for every i2c read in which the
307	 * middle-of-tranaction flag is set. This is required to support EDID
308	 * reads of more than 2 blocks as the segment address is reset to 0
309	 * since we are overriding the middle-of-transaction flag for read
310	 * transactions.
311	 */
312
313	if (aux->segment) {
314		memset(&helper_msg, 0, sizeof(helper_msg));
315		helper_msg.address = segment_address;
316		helper_msg.buffer = &aux->segment;
317		helper_msg.size = 1;
318		msm_dp_aux_cmd_fifo_tx(aux, &helper_msg);
319	}
320
321	/*
322	 * Send the offset address for every i2c read in which the
323	 * middle-of-transaction flag is set. This will ensure that the sink
324	 * will update its read pointer and return the correct portion of the
325	 * EDID buffer in the subsequent i2c read trasntion triggered in the
326	 * native AUX transfer function.
327	 */
328	memset(&helper_msg, 0, sizeof(helper_msg));
329	helper_msg.address = input_msg->address;
330	helper_msg.buffer = &aux->offset;
331	helper_msg.size = 1;
332	msm_dp_aux_cmd_fifo_tx(aux, &helper_msg);
333
334end:
335	aux->offset += message_size;
336	if (aux->offset == 0x80 || aux->offset == 0x100)
337		aux->segment = 0x0; /* reset segment at end of block */
338}
339
340/*
341 * This function does the real job to process an AUX transaction.
342 * It will call aux_reset() function to reset the AUX channel,
343 * if the waiting is timeout.
344 */
345static ssize_t msm_dp_aux_transfer(struct drm_dp_aux *msm_dp_aux,
346			       struct drm_dp_aux_msg *msg)
347{
348	ssize_t ret;
349	int const aux_cmd_native_max = 16;
350	int const aux_cmd_i2c_max = 128;
351	struct msm_dp_aux_private *aux;
352
353	aux = container_of(msm_dp_aux, struct msm_dp_aux_private, msm_dp_aux);
354
355	aux->native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
356
357	/* Ignore address only message */
358	if (msg->size == 0 || !msg->buffer) {
359		msg->reply = aux->native ?
360			DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
361		return msg->size;
362	}
363
364	/* msg sanity check */
365	if ((aux->native && msg->size > aux_cmd_native_max) ||
366	    msg->size > aux_cmd_i2c_max) {
367		DRM_ERROR("%s: invalid msg: size(%zu), request(%x)\n",
368			__func__, msg->size, msg->request);
369		return -EINVAL;
370	}
371
372	ret = pm_runtime_resume_and_get(msm_dp_aux->dev);
373	if (ret)
374		return  ret;
375
376	mutex_lock(&aux->mutex);
377	if (!aux->initted) {
378		ret = -EIO;
379		goto exit;
380	}
381
382	/*
383	 * If we're using DP and an external display isn't connected then the
384	 * transfer won't succeed. Return right away. If we don't do this we
385	 * can end up with long timeouts if someone tries to access the DP AUX
386	 * character device when no DP device is connected.
387	 */
388	if (!aux->is_edp && !aux->enable_xfers) {
389		ret = -ENXIO;
390		goto exit;
391	}
392
393	msm_dp_aux_update_offset_and_segment(aux, msg);
394	msm_dp_aux_transfer_helper(aux, msg, true);
395
396	aux->read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
397	aux->cmd_busy = true;
398
399	if (aux->read) {
400		aux->no_send_addr = true;
401		aux->no_send_stop = false;
402	} else {
403		aux->no_send_addr = true;
404		aux->no_send_stop = true;
405	}
406
407	ret = msm_dp_aux_cmd_fifo_tx(aux, msg);
408	if (ret < 0) {
409		if (aux->native) {
410			aux->retry_cnt++;
411			if (!(aux->retry_cnt % MAX_AUX_RETRIES))
412				phy_calibrate(aux->phy);
413		}
414		/* reset aux if link is in connected state */
415		if (msm_dp_aux_is_link_connected(msm_dp_aux))
416			msm_dp_aux_reset(aux);
417	} else {
418		aux->retry_cnt = 0;
419		switch (aux->aux_error_num) {
420		case DP_AUX_ERR_NONE:
421			if (aux->read)
422				ret = msm_dp_aux_cmd_fifo_rx(aux, msg);
423			msg->reply = aux->native ? DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
424			break;
425		case DP_AUX_ERR_DEFER:
426			msg->reply = aux->native ? DP_AUX_NATIVE_REPLY_DEFER : DP_AUX_I2C_REPLY_DEFER;
427			break;
428		case DP_AUX_ERR_PHY:
429		case DP_AUX_ERR_ADDR:
430		case DP_AUX_ERR_NACK:
431		case DP_AUX_ERR_NACK_DEFER:
432			msg->reply = aux->native ? DP_AUX_NATIVE_REPLY_NACK : DP_AUX_I2C_REPLY_NACK;
433			break;
434		case DP_AUX_ERR_TOUT:
435			ret = -ETIMEDOUT;
436			break;
437		}
438	}
439
440	aux->cmd_busy = false;
441
442exit:
443	mutex_unlock(&aux->mutex);
444	pm_runtime_put_sync(msm_dp_aux->dev);
445
446	return ret;
447}
448
449irqreturn_t msm_dp_aux_isr(struct drm_dp_aux *msm_dp_aux, u32 isr)
450{
451	struct msm_dp_aux_private *aux;
452
453	if (!msm_dp_aux) {
454		DRM_ERROR("invalid input\n");
455		return IRQ_NONE;
456	}
457
458	aux = container_of(msm_dp_aux, struct msm_dp_aux_private, msm_dp_aux);
459
460	if (!aux->cmd_busy) {
461		DRM_ERROR("Unexpected DP AUX IRQ %#010x when not busy\n", isr);
462		return IRQ_NONE;
463	}
464
465	/*
466	 * The logic below assumes only one error bit is set (other than "done"
467	 * which can apparently be set at the same time as some of the other
468	 * bits). Warn if more than one get set so we know we need to improve
469	 * the logic.
470	 */
471	if (hweight32(isr & ~DP_INTR_AUX_XFER_DONE) > 1)
472		DRM_WARN("Some DP AUX interrupts unhandled: %#010x\n", isr);
473
474	if (isr & DP_INTR_AUX_ERROR) {
475		aux->aux_error_num = DP_AUX_ERR_PHY;
476		msm_dp_aux_clear_hw_interrupts(aux);
477	} else if (isr & DP_INTR_NACK_DEFER) {
478		aux->aux_error_num = DP_AUX_ERR_NACK_DEFER;
479	} else if (isr & DP_INTR_WRONG_ADDR) {
480		aux->aux_error_num = DP_AUX_ERR_ADDR;
481	} else if (isr & DP_INTR_TIMEOUT) {
482		aux->aux_error_num = DP_AUX_ERR_TOUT;
483	} else if (!aux->native && (isr & DP_INTR_I2C_NACK)) {
484		aux->aux_error_num = DP_AUX_ERR_NACK;
485	} else if (!aux->native && (isr & DP_INTR_I2C_DEFER)) {
486		if (isr & DP_INTR_AUX_XFER_DONE)
487			aux->aux_error_num = DP_AUX_ERR_NACK;
488		else
489			aux->aux_error_num = DP_AUX_ERR_DEFER;
490	} else if (isr & DP_INTR_AUX_XFER_DONE) {
491		aux->aux_error_num = DP_AUX_ERR_NONE;
492	} else {
493		DRM_WARN("Unexpected interrupt: %#010x\n", isr);
494		return IRQ_NONE;
495	}
496
497	complete(&aux->comp);
498
499	return IRQ_HANDLED;
500}
501
502void msm_dp_aux_enable_xfers(struct drm_dp_aux *msm_dp_aux, bool enabled)
503{
504	struct msm_dp_aux_private *aux;
505
506	aux = container_of(msm_dp_aux, struct msm_dp_aux_private, msm_dp_aux);
507	aux->enable_xfers = enabled;
508}
509
510void msm_dp_aux_reconfig(struct drm_dp_aux *msm_dp_aux)
511{
512	struct msm_dp_aux_private *aux;
513
514	aux = container_of(msm_dp_aux, struct msm_dp_aux_private, msm_dp_aux);
515
516	phy_calibrate(aux->phy);
517	msm_dp_aux_reset(aux);
518}
519
520void msm_dp_aux_init(struct drm_dp_aux *msm_dp_aux)
521{
522	struct msm_dp_aux_private *aux;
523
524	if (!msm_dp_aux) {
525		DRM_ERROR("invalid input\n");
526		return;
527	}
528
529	aux = container_of(msm_dp_aux, struct msm_dp_aux_private, msm_dp_aux);
530
531	mutex_lock(&aux->mutex);
532
533	msm_dp_aux_enable(aux);
534	aux->retry_cnt = 0;
535	aux->initted = true;
536
537	mutex_unlock(&aux->mutex);
538}
539
540void msm_dp_aux_deinit(struct drm_dp_aux *msm_dp_aux)
541{
542	struct msm_dp_aux_private *aux;
543
544	aux = container_of(msm_dp_aux, struct msm_dp_aux_private, msm_dp_aux);
545
546	mutex_lock(&aux->mutex);
547
548	aux->initted = false;
549	msm_dp_aux_disable(aux);
550
551	mutex_unlock(&aux->mutex);
552}
553
554int msm_dp_aux_register(struct drm_dp_aux *msm_dp_aux)
555{
556	int ret;
557
558	if (!msm_dp_aux) {
559		DRM_ERROR("invalid input\n");
560		return -EINVAL;
561	}
562
563	ret = drm_dp_aux_register(msm_dp_aux);
564	if (ret) {
565		DRM_ERROR("%s: failed to register drm aux: %d\n", __func__,
566				ret);
567		return ret;
568	}
569
570	return 0;
571}
572
573void msm_dp_aux_unregister(struct drm_dp_aux *msm_dp_aux)
574{
575	drm_dp_aux_unregister(msm_dp_aux);
576}
577
578static int msm_dp_wait_hpd_asserted(struct drm_dp_aux *msm_dp_aux,
579				 unsigned long wait_us)
580{
581	int ret;
582	struct msm_dp_aux_private *aux;
583
584	aux = container_of(msm_dp_aux, struct msm_dp_aux_private, msm_dp_aux);
585
586	ret = pm_runtime_resume_and_get(aux->dev);
587	if (ret)
588		return ret;
589
590	ret = msm_dp_aux_wait_for_hpd_connect_state(aux, wait_us);
591	pm_runtime_put_sync(aux->dev);
592
593	return ret;
594}
595
596void msm_dp_aux_hpd_enable(struct drm_dp_aux *msm_dp_aux)
597{
598	struct msm_dp_aux_private *aux =
599		container_of(msm_dp_aux, struct msm_dp_aux_private, msm_dp_aux);
600	u32 reg;
601
602	/* Configure REFTIMER and enable it */
603	reg = msm_dp_read_aux(aux, REG_DP_DP_HPD_REFTIMER);
604	reg |= DP_DP_HPD_REFTIMER_ENABLE;
605	msm_dp_write_aux(aux, REG_DP_DP_HPD_REFTIMER, reg);
606
607	/* Enable HPD */
608	msm_dp_write_aux(aux, REG_DP_DP_HPD_CTRL, DP_DP_HPD_CTRL_HPD_EN);
609}
610
611void msm_dp_aux_hpd_disable(struct drm_dp_aux *msm_dp_aux)
612{
613	struct msm_dp_aux_private *aux =
614		container_of(msm_dp_aux, struct msm_dp_aux_private, msm_dp_aux);
615	u32 reg;
616
617	reg = msm_dp_read_aux(aux, REG_DP_DP_HPD_REFTIMER);
618	reg &= ~DP_DP_HPD_REFTIMER_ENABLE;
619	msm_dp_write_aux(aux, REG_DP_DP_HPD_REFTIMER, reg);
620
621	msm_dp_write_aux(aux, REG_DP_DP_HPD_CTRL, 0);
622}
623
624void msm_dp_aux_hpd_intr_enable(struct drm_dp_aux *msm_dp_aux)
625{
626	struct msm_dp_aux_private *aux =
627		container_of(msm_dp_aux, struct msm_dp_aux_private, msm_dp_aux);
628	u32 reg;
629
630	reg = msm_dp_read_aux(aux, REG_DP_DP_HPD_INT_MASK);
631	reg |= DP_DP_HPD_INT_MASK;
632	msm_dp_write_aux(aux, REG_DP_DP_HPD_INT_MASK,
633		     reg & DP_DP_HPD_INT_MASK);
634}
635
636void msm_dp_aux_hpd_intr_disable(struct drm_dp_aux *msm_dp_aux)
637{
638	struct msm_dp_aux_private *aux =
639		container_of(msm_dp_aux, struct msm_dp_aux_private, msm_dp_aux);
640	u32 reg;
641
642	reg = msm_dp_read_aux(aux, REG_DP_DP_HPD_INT_MASK);
643	reg &= ~DP_DP_HPD_INT_MASK;
644	msm_dp_write_aux(aux, REG_DP_DP_HPD_INT_MASK,
645		     reg & DP_DP_HPD_INT_MASK);
646}
647
648u32 msm_dp_aux_get_hpd_intr_status(struct drm_dp_aux *msm_dp_aux)
649{
650	struct msm_dp_aux_private *aux =
651		container_of(msm_dp_aux, struct msm_dp_aux_private, msm_dp_aux);
652	int isr, mask;
653
654	isr = msm_dp_read_aux(aux, REG_DP_DP_HPD_INT_STATUS);
655	msm_dp_write_aux(aux, REG_DP_DP_HPD_INT_ACK,
656				 (isr & DP_DP_HPD_INT_MASK));
657	mask = msm_dp_read_aux(aux, REG_DP_DP_HPD_INT_MASK);
658
659	/*
660	 * We only want to return interrupts that are unmasked to the caller.
661	 * However, the interrupt status field also contains other
662	 * informational bits about the HPD state status, so we only mask
663	 * out the part of the register that tells us about which interrupts
664	 * are pending.
665	 */
666	return isr & (mask | ~DP_DP_HPD_INT_MASK);
667}
668
669u32 msm_dp_aux_is_link_connected(struct drm_dp_aux *msm_dp_aux)
670{
671	struct msm_dp_aux_private *aux =
672		container_of(msm_dp_aux, struct msm_dp_aux_private, msm_dp_aux);
673	u32 status;
674
675	status = msm_dp_read_aux(aux, REG_DP_DP_HPD_INT_STATUS);
676	status >>= DP_DP_HPD_STATE_STATUS_BITS_SHIFT;
677	status &= DP_DP_HPD_STATE_STATUS_BITS_MASK;
678
679	return status;
680}
681
682struct drm_dp_aux *msm_dp_aux_get(struct device *dev,
683			      struct phy *phy,
684			      bool is_edp,
685			      void __iomem *aux_base)
686{
687	struct msm_dp_aux_private *aux;
688
689	aux = devm_kzalloc(dev, sizeof(*aux), GFP_KERNEL);
690	if (!aux)
691		return ERR_PTR(-ENOMEM);
692
693	init_completion(&aux->comp);
694	aux->cmd_busy = false;
695	aux->is_edp = is_edp;
696	mutex_init(&aux->mutex);
697
698	aux->dev = dev;
699	aux->phy = phy;
700	aux->retry_cnt = 0;
701	aux->aux_base = aux_base;
702
703	/*
704	 * Use the drm_dp_aux_init() to use the aux adapter
705	 * before registering AUX with the DRM device so that
706	 * msm eDP panel can be detected by generic_dep_panel_probe().
707	 */
708	aux->msm_dp_aux.name = "dpu_dp_aux";
709	aux->msm_dp_aux.dev = dev;
710	aux->msm_dp_aux.transfer = msm_dp_aux_transfer;
711	aux->msm_dp_aux.wait_hpd_asserted = msm_dp_wait_hpd_asserted;
712	drm_dp_aux_init(&aux->msm_dp_aux);
713
714	return &aux->msm_dp_aux;
715}
716
717void msm_dp_aux_put(struct drm_dp_aux *msm_dp_aux)
718{
719	struct msm_dp_aux_private *aux;
720
721	if (!msm_dp_aux)
722		return;
723
724	aux = container_of(msm_dp_aux, struct msm_dp_aux_private, msm_dp_aux);
725
726	mutex_destroy(&aux->mutex);
727
728	devm_kfree(aux->dev, aux);
729}
~/ Read-only file preview.