Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dmaengine: ti: omap-dma: Block PM if SDMA is busy to fix audio

We now use cpu_pm for saving and restoring device context for deeper SoC
idle states. But for omap3, we must also block idle if SDMA is busy.

If we don't block idle when SDMA is busy, we eventually end up saving and
restoring SDMA register state on PER domain idle while SDMA is active and
that causes at least audio playback to fail.

Fixes: 4c74ecf79227 ("dmaengine: ti: omap-dma: Add device tree match data and use it for cpu_pm")
Reported-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Tested-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
Acked-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
Link: https://lore.kernel.org/r/20201109154013.11950-1-tony@atomide.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Tony Lindgren and committed by
Vinod Koul
29a25b92 96d5d884

+24 -13
+24 -13
drivers/dma/ti/omap-dma.c
··· 1522 1522 } 1523 1523 } 1524 1524 1525 + /* Currently used by omap2 & 3 to block deeper SoC idle states */ 1526 + static bool omap_dma_busy(struct omap_dmadev *od) 1527 + { 1528 + struct omap_chan *c; 1529 + int lch = -1; 1530 + 1531 + while (1) { 1532 + lch = find_next_bit(od->lch_bitmap, od->lch_count, lch + 1); 1533 + if (lch >= od->lch_count) 1534 + break; 1535 + c = od->lch_map[lch]; 1536 + if (!c) 1537 + continue; 1538 + if (omap_dma_chan_read(c, CCR) & CCR_ENABLE) 1539 + return true; 1540 + } 1541 + 1542 + return false; 1543 + } 1544 + 1525 1545 /* Currently only used for omap2. For omap1, also a check for lcd_dma is needed */ 1526 1546 static int omap_dma_busy_notifier(struct notifier_block *nb, 1527 1547 unsigned long cmd, void *v) 1528 1548 { 1529 1549 struct omap_dmadev *od; 1530 - struct omap_chan *c; 1531 - int lch = -1; 1532 1550 1533 1551 od = container_of(nb, struct omap_dmadev, nb); 1534 1552 1535 1553 switch (cmd) { 1536 1554 case CPU_CLUSTER_PM_ENTER: 1537 - while (1) { 1538 - lch = find_next_bit(od->lch_bitmap, od->lch_count, 1539 - lch + 1); 1540 - if (lch >= od->lch_count) 1541 - break; 1542 - c = od->lch_map[lch]; 1543 - if (!c) 1544 - continue; 1545 - if (omap_dma_chan_read(c, CCR) & CCR_ENABLE) 1546 - return NOTIFY_BAD; 1547 - } 1555 + if (omap_dma_busy(od)) 1556 + return NOTIFY_BAD; 1548 1557 break; 1549 1558 case CPU_CLUSTER_PM_ENTER_FAILED: 1550 1559 case CPU_CLUSTER_PM_EXIT: ··· 1604 1595 1605 1596 switch (cmd) { 1606 1597 case CPU_CLUSTER_PM_ENTER: 1598 + if (omap_dma_busy(od)) 1599 + return NOTIFY_BAD; 1607 1600 omap_dma_context_save(od); 1608 1601 break; 1609 1602 case CPU_CLUSTER_PM_ENTER_FAILED: