aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2017-10-13 20:12:55 -0400
committerEric Anholt <eric@anholt.net>2017-10-19 16:20:09 -0400
commitaf0c8c10564aac5b6d67308129ec09c4ad5db476 (patch)
tree39407dbc8d0c72b2b190dbfa64822a4038e16e1d
parentb9f19259b84dc648f207a46f3581d15eeaedf4b6 (diff)
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 <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)
-rw-r--r--drivers/gpu/drm/vc4/vc4_dsi.c32
1 files changed, 30 insertions, 2 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
index 554605af344e..94085f8bcd68 100644
--- a/drivers/gpu/drm/vc4/vc4_dsi.c
+++ b/drivers/gpu/drm/vc4/vc4_dsi.c
@@ -1360,6 +1360,27 @@ static void dsi_handle_error(struct vc4_dsi *dsi,
1360 *ret = IRQ_HANDLED; 1360 *ret = IRQ_HANDLED;
1361} 1361}
1362 1362
1363/*
1364 * Initial handler for port 1 where we need the reg_dma workaround.
1365 * The register DMA writes sleep, so we can't do it in the top half.
1366 * Instead we use IRQF_ONESHOT so that the IRQ gets disabled in the
1367 * parent interrupt contrller until our interrupt thread is done.
1368 */
1369static irqreturn_t vc4_dsi_irq_defer_to_thread_handler(int irq, void *data)
1370{
1371 struct vc4_dsi *dsi = data;
1372 u32 stat = DSI_PORT_READ(INT_STAT);
1373
1374 if (!stat)
1375 return IRQ_NONE;
1376
1377 return IRQ_WAKE_THREAD;
1378}
1379
1380/*
1381 * Normal IRQ handler for port 0, or the threaded IRQ handler for port
1382 * 1 where we need the reg_dma workaround.
1383 */
1363static irqreturn_t vc4_dsi_irq_handler(int irq, void *data) 1384static irqreturn_t vc4_dsi_irq_handler(int irq, void *data)
1364{ 1385{
1365 struct vc4_dsi *dsi = data; 1386 struct vc4_dsi *dsi = data;
@@ -1539,8 +1560,15 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
1539 /* Clear any existing interrupt state. */ 1560 /* Clear any existing interrupt state. */
1540 DSI_PORT_WRITE(INT_STAT, DSI_PORT_READ(INT_STAT)); 1561 DSI_PORT_WRITE(INT_STAT, DSI_PORT_READ(INT_STAT));
1541 1562
1542 ret = devm_request_irq(dev, platform_get_irq(pdev, 0), 1563 if (dsi->reg_dma_mem)
1543 vc4_dsi_irq_handler, 0, "vc4 dsi", dsi); 1564 ret = devm_request_threaded_irq(dev, platform_get_irq(pdev, 0),
1565 vc4_dsi_irq_defer_to_thread_handler,
1566 vc4_dsi_irq_handler,
1567 IRQF_ONESHOT,
1568 "vc4 dsi", dsi);
1569 else
1570 ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
1571 vc4_dsi_irq_handler, 0, "vc4 dsi", dsi);
1544 if (ret) { 1572 if (ret) {
1545 if (ret != -EPROBE_DEFER) 1573 if (ret != -EPROBE_DEFER)
1546 dev_err(dev, "Failed to get interrupt: %d\n", ret); 1574 dev_err(dev, "Failed to get interrupt: %d\n", ret);