Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit af0c8c10 authored by Eric Anholt's avatar Eric Anholt
Browse files

drm/vc4: Fix sleeps during the IRQ handler for DSI transactions.



VC4's DSI1 has a bug where the AXI connection is broken for 32-bit
writes from the CPU, so we use the DMA engine to DMA 32-bit values
into registers instead.  That sleeps, so we can't do it from the top
half.

As a solution, use an interrupt thread so that all our writes happen
when sleeping is is allowed.

v2: Use IRQF_ONESHOT (suggested by Boris)
v3: Style nitpicks.

Signed-off-by: default avatarEric Anholt <eric@anholt.net>
Link: https://patchwork.freedesktop.org/patch/msgid/20171014001255.32005-1-eric@anholt.net
Reviewed-by: Boris Brezillon <boris.brezillon@free-electrons.com> (v2)
parent b9f19259
Loading
Loading
Loading
Loading
+30 −2
Original line number Diff line number Diff line
@@ -1360,6 +1360,27 @@ static void dsi_handle_error(struct vc4_dsi *dsi,
	*ret = IRQ_HANDLED;
}

/*
 * Initial handler for port 1 where we need the reg_dma workaround.
 * The register DMA writes sleep, so we can't do it in the top half.
 * Instead we use IRQF_ONESHOT so that the IRQ gets disabled in the
 * parent interrupt contrller until our interrupt thread is done.
 */
static irqreturn_t vc4_dsi_irq_defer_to_thread_handler(int irq, void *data)
{
	struct vc4_dsi *dsi = data;
	u32 stat = DSI_PORT_READ(INT_STAT);

	if (!stat)
		return IRQ_NONE;

	return IRQ_WAKE_THREAD;
}

/*
 * Normal IRQ handler for port 0, or the threaded IRQ handler for port
 * 1 where we need the reg_dma workaround.
 */
static irqreturn_t vc4_dsi_irq_handler(int irq, void *data)
{
	struct vc4_dsi *dsi = data;
@@ -1539,6 +1560,13 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
	/* Clear any existing interrupt state. */
	DSI_PORT_WRITE(INT_STAT, DSI_PORT_READ(INT_STAT));

	if (dsi->reg_dma_mem)
		ret = devm_request_threaded_irq(dev, platform_get_irq(pdev, 0),
						vc4_dsi_irq_defer_to_thread_handler,
						vc4_dsi_irq_handler,
						IRQF_ONESHOT,
						"vc4 dsi", dsi);
	else
		ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
				       vc4_dsi_irq_handler, 0, "vc4 dsi", dsi);
	if (ret) {