Skip to content

Commit 8c9c70a

Browse files
committed
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: Eric Anholt <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected] Reviewed-by: Boris Brezillon <[email protected]> (v2) (cherry picked from commit af0c8c1)
1 parent abadb82 commit 8c9c70a

File tree

1 file changed

+30
-2
lines changed

1 file changed

+30
-2
lines changed

drivers/gpu/drm/vc4/vc4_dsi.c

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1486,6 +1486,27 @@ static void dsi_handle_error(struct vc4_dsi *dsi,
14861486
*ret = IRQ_HANDLED;
14871487
}
14881488

1489+
/*
1490+
* Initial handler for port 1 where we need the reg_dma workaround.
1491+
* The register DMA writes sleep, so we can't do it in the top half.
1492+
* Instead we use IRQF_ONESHOT so that the IRQ gets disabled in the
1493+
* parent interrupt contrller until our interrupt thread is done.
1494+
*/
1495+
static irqreturn_t vc4_dsi_irq_defer_to_thread_handler(int irq, void *data)
1496+
{
1497+
struct vc4_dsi *dsi = data;
1498+
u32 stat = DSI_PORT_READ(INT_STAT);
1499+
1500+
if (!stat)
1501+
return IRQ_NONE;
1502+
1503+
return IRQ_WAKE_THREAD;
1504+
}
1505+
1506+
/*
1507+
* Normal IRQ handler for port 0, or the threaded IRQ handler for port
1508+
* 1 where we need the reg_dma workaround.
1509+
*/
14891510
static irqreturn_t vc4_dsi_irq_handler(int irq, void *data)
14901511
{
14911512
struct vc4_dsi *dsi = data;
@@ -1669,8 +1690,15 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
16691690
/* Clear any existing interrupt state. */
16701691
DSI_PORT_WRITE(INT_STAT, DSI_PORT_READ(INT_STAT));
16711692

1672-
ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
1673-
vc4_dsi_irq_handler, 0, "vc4 dsi", dsi);
1693+
if (dsi->reg_dma_mem)
1694+
ret = devm_request_threaded_irq(dev, platform_get_irq(pdev, 0),
1695+
vc4_dsi_irq_defer_to_thread_handler,
1696+
vc4_dsi_irq_handler,
1697+
IRQF_ONESHOT,
1698+
"vc4 dsi", dsi);
1699+
else
1700+
ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
1701+
vc4_dsi_irq_handler, 0, "vc4 dsi", dsi);
16741702
if (ret) {
16751703
if (ret != -EPROBE_DEFER)
16761704
dev_err(dev, "Failed to get interrupt: %d\n", ret);

0 commit comments

Comments
 (0)