Unverified Commit bc5b815e authored by Dave Stevenson's avatar Dave Stevenson Committed by Maxime Ripard
Browse files

drm/vc4: dsi: Fix dsi0 interrupt support



DSI0 seemingly had very little or no testing as a load of
the register mappings were incorrect/missing, so host
transfers always timed out due to enabling/checking incorrect
bits in the interrupt enable and status registers.

Fixes: 4078f575 ("drm/vc4: Add DSI driver")
Signed-off-by: default avatarDave Stevenson <dave.stevenson@raspberrypi.com>
Link: https://lore.kernel.org/r/20220613144800.326124-16-maxime@cerno.tech


Signed-off-by: default avatarMaxime Ripard <maxime@cerno.tech>
parent 4d9273c9
Loading
Loading
Loading
Loading
+85 −26
Original line number Diff line number Diff line
@@ -183,6 +183,48 @@

#define DSI0_INT_STAT			0x24
#define DSI0_INT_EN			0x28
# define DSI0_INT_FIFO_ERR		BIT(25)
# define DSI0_INT_CMDC_DONE_MASK	VC4_MASK(24, 23)
# define DSI0_INT_CMDC_DONE_SHIFT	23
#  define DSI0_INT_CMDC_DONE_NO_REPEAT		1
#  define DSI0_INT_CMDC_DONE_REPEAT		3
# define DSI0_INT_PHY_DIR_RTF		BIT(22)
# define DSI0_INT_PHY_D1_ULPS		BIT(21)
# define DSI0_INT_PHY_D1_STOP		BIT(20)
# define DSI0_INT_PHY_RXLPDT		BIT(19)
# define DSI0_INT_PHY_RXTRIG		BIT(18)
# define DSI0_INT_PHY_D0_ULPS		BIT(17)
# define DSI0_INT_PHY_D0_LPDT		BIT(16)
# define DSI0_INT_PHY_D0_FTR		BIT(15)
# define DSI0_INT_PHY_D0_STOP		BIT(14)
/* Signaled when the clock lane enters the given state. */
# define DSI0_INT_PHY_CLK_ULPS		BIT(13)
# define DSI0_INT_PHY_CLK_HS		BIT(12)
# define DSI0_INT_PHY_CLK_FTR		BIT(11)
/* Signaled on timeouts */
# define DSI0_INT_PR_TO			BIT(10)
# define DSI0_INT_TA_TO			BIT(9)
# define DSI0_INT_LPRX_TO		BIT(8)
# define DSI0_INT_HSTX_TO		BIT(7)
/* Contention on a line when trying to drive the line low */
# define DSI0_INT_ERR_CONT_LP1		BIT(6)
# define DSI0_INT_ERR_CONT_LP0		BIT(5)
/* Control error: incorrect line state sequence on data lane 0. */
# define DSI0_INT_ERR_CONTROL		BIT(4)
# define DSI0_INT_ERR_SYNC_ESC		BIT(3)
# define DSI0_INT_RX2_PKT		BIT(2)
# define DSI0_INT_RX1_PKT		BIT(1)
# define DSI0_INT_CMD_PKT		BIT(0)

#define DSI0_INTERRUPTS_ALWAYS_ENABLED	(DSI0_INT_ERR_SYNC_ESC | \
					 DSI0_INT_ERR_CONTROL |	 \
					 DSI0_INT_ERR_CONT_LP0 | \
					 DSI0_INT_ERR_CONT_LP1 | \
					 DSI0_INT_HSTX_TO |	 \
					 DSI0_INT_LPRX_TO |	 \
					 DSI0_INT_TA_TO |	 \
					 DSI0_INT_PR_TO)

# define DSI1_INT_PHY_D3_ULPS		BIT(30)
# define DSI1_INT_PHY_D3_STOP		BIT(29)
# define DSI1_INT_PHY_D2_ULPS		BIT(28)
@@ -892,6 +934,9 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)

		DSI_PORT_WRITE(PHY_AFEC0, afec0);

		/* AFEC reset hold time */
		mdelay(1);

		DSI_PORT_WRITE(PHY_AFEC1,
			       VC4_SET_FIELD(6,  DSI0_PHY_AFEC1_IDR_DLANE1) |
			       VC4_SET_FIELD(6,  DSI0_PHY_AFEC1_IDR_DLANE0) |
@@ -1058,12 +1103,9 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
		DSI_PORT_WRITE(CTRL, DSI_PORT_READ(CTRL) | DSI1_CTRL_EN);

	/* Bring AFE out of reset. */
	if (dsi->variant->port == 0) {
	} else {
	DSI_PORT_WRITE(PHY_AFEC0,
		       DSI_PORT_READ(PHY_AFEC0) &
			       ~DSI1_PHY_AFEC0_RESET);
	}
		       ~DSI_PORT_BIT(PHY_AFEC0_RESET));

	vc4_dsi_ulps(dsi, false);

@@ -1182,7 +1224,21 @@ static ssize_t vc4_dsi_host_transfer(struct mipi_dsi_host *host,
	/* Enable the appropriate interrupt for the transfer completion. */
	dsi->xfer_result = 0;
	reinit_completion(&dsi->xfer_completion);
	DSI_PORT_WRITE(INT_STAT, DSI1_INT_TXPKT1_DONE | DSI1_INT_PHY_DIR_RTF);
	if (dsi->variant->port == 0) {
		DSI_PORT_WRITE(INT_STAT,
			       DSI0_INT_CMDC_DONE_MASK | DSI1_INT_PHY_DIR_RTF);
		if (msg->rx_len) {
			DSI_PORT_WRITE(INT_EN, (DSI0_INTERRUPTS_ALWAYS_ENABLED |
						DSI0_INT_PHY_DIR_RTF));
		} else {
			DSI_PORT_WRITE(INT_EN,
				       (DSI0_INTERRUPTS_ALWAYS_ENABLED |
					VC4_SET_FIELD(DSI0_INT_CMDC_DONE_NO_REPEAT,
						      DSI0_INT_CMDC_DONE)));
		}
	} else {
		DSI_PORT_WRITE(INT_STAT,
			       DSI1_INT_TXPKT1_DONE | DSI1_INT_PHY_DIR_RTF);
		if (msg->rx_len) {
			DSI_PORT_WRITE(INT_EN, (DSI1_INTERRUPTS_ALWAYS_ENABLED |
						DSI1_INT_PHY_DIR_RTF));
@@ -1190,6 +1246,7 @@ static ssize_t vc4_dsi_host_transfer(struct mipi_dsi_host *host,
			DSI_PORT_WRITE(INT_EN, (DSI1_INTERRUPTS_ALWAYS_ENABLED |
						DSI1_INT_TXPKT1_DONE));
		}
	}

	/* Send the packet. */
	DSI_PORT_WRITE(TXPKT1H, pkth);
@@ -1205,7 +1262,7 @@ static ssize_t vc4_dsi_host_transfer(struct mipi_dsi_host *host,
		ret = dsi->xfer_result;
	}

	DSI_PORT_WRITE(INT_EN, DSI1_INTERRUPTS_ALWAYS_ENABLED);
	DSI_PORT_WRITE(INT_EN, DSI_PORT_BIT(INTERRUPTS_ALWAYS_ENABLED));

	if (ret)
		goto reset_fifo_and_return;
@@ -1251,7 +1308,7 @@ static ssize_t vc4_dsi_host_transfer(struct mipi_dsi_host *host,
		       DSI_PORT_BIT(CTRL_RESET_FIFOS));

	DSI_PORT_WRITE(TXPKT1C, 0);
	DSI_PORT_WRITE(INT_EN, DSI1_INTERRUPTS_ALWAYS_ENABLED);
	DSI_PORT_WRITE(INT_EN, DSI_PORT_BIT(INTERRUPTS_ALWAYS_ENABLED));
	return ret;
}

@@ -1388,26 +1445,28 @@ static irqreturn_t vc4_dsi_irq_handler(int irq, void *data)
	DSI_PORT_WRITE(INT_STAT, stat);

	dsi_handle_error(dsi, &ret, stat,
			 DSI1_INT_ERR_SYNC_ESC, "LPDT sync");
			 DSI_PORT_BIT(INT_ERR_SYNC_ESC), "LPDT sync");
	dsi_handle_error(dsi, &ret, stat,
			 DSI1_INT_ERR_CONTROL, "data lane 0 sequence");
			 DSI_PORT_BIT(INT_ERR_CONTROL), "data lane 0 sequence");
	dsi_handle_error(dsi, &ret, stat,
			 DSI1_INT_ERR_CONT_LP0, "LP0 contention");
			 DSI_PORT_BIT(INT_ERR_CONT_LP0), "LP0 contention");
	dsi_handle_error(dsi, &ret, stat,
			 DSI1_INT_ERR_CONT_LP1, "LP1 contention");
			 DSI_PORT_BIT(INT_ERR_CONT_LP1), "LP1 contention");
	dsi_handle_error(dsi, &ret, stat,
			 DSI1_INT_HSTX_TO, "HSTX timeout");
			 DSI_PORT_BIT(INT_HSTX_TO), "HSTX timeout");
	dsi_handle_error(dsi, &ret, stat,
			 DSI1_INT_LPRX_TO, "LPRX timeout");
			 DSI_PORT_BIT(INT_LPRX_TO), "LPRX timeout");
	dsi_handle_error(dsi, &ret, stat,
			 DSI1_INT_TA_TO, "turnaround timeout");
			 DSI_PORT_BIT(INT_TA_TO), "turnaround timeout");
	dsi_handle_error(dsi, &ret, stat,
			 DSI1_INT_PR_TO, "peripheral reset timeout");
			 DSI_PORT_BIT(INT_PR_TO), "peripheral reset timeout");

	if (stat & (DSI1_INT_TXPKT1_DONE | DSI1_INT_PHY_DIR_RTF)) {
	if (stat & ((dsi->variant->port ? DSI1_INT_TXPKT1_DONE :
					  DSI0_INT_CMDC_DONE_MASK) |
		    DSI_PORT_BIT(INT_PHY_DIR_RTF))) {
		complete(&dsi->xfer_completion);
		ret = IRQ_HANDLED;
	} else if (stat & DSI1_INT_HSTX_TO) {
	} else if (stat & DSI_PORT_BIT(INT_HSTX_TO)) {
		complete(&dsi->xfer_completion);
		dsi->xfer_result = -ETIMEDOUT;
		ret = IRQ_HANDLED;