Skip to content

Commit

Permalink
dmaengine: ti: omap-dma: Block PM if SDMA is busy to fix audio
Browse files Browse the repository at this point in the history
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: 4c74ecf ("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>
  • Loading branch information
tmlind authored and vinodkoul committed Nov 10, 2020
1 parent 96d5d88 commit 29a25b9
Showing 1 changed file with 24 additions and 13 deletions.
37 changes: 24 additions & 13 deletions drivers/dma/ti/omap-dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -1522,29 +1522,38 @@ static void omap_dma_free(struct omap_dmadev *od)
}
}

/* Currently used by omap2 & 3 to block deeper SoC idle states */
static bool omap_dma_busy(struct omap_dmadev *od)
{
struct omap_chan *c;
int lch = -1;

while (1) {
lch = find_next_bit(od->lch_bitmap, od->lch_count, lch + 1);
if (lch >= od->lch_count)
break;
c = od->lch_map[lch];
if (!c)
continue;
if (omap_dma_chan_read(c, CCR) & CCR_ENABLE)
return true;
}

return false;
}

/* Currently only used for omap2. For omap1, also a check for lcd_dma is needed */
static int omap_dma_busy_notifier(struct notifier_block *nb,
unsigned long cmd, void *v)
{
struct omap_dmadev *od;
struct omap_chan *c;
int lch = -1;

od = container_of(nb, struct omap_dmadev, nb);

switch (cmd) {
case CPU_CLUSTER_PM_ENTER:
while (1) {
lch = find_next_bit(od->lch_bitmap, od->lch_count,
lch + 1);
if (lch >= od->lch_count)
break;
c = od->lch_map[lch];
if (!c)
continue;
if (omap_dma_chan_read(c, CCR) & CCR_ENABLE)
return NOTIFY_BAD;
}
if (omap_dma_busy(od))
return NOTIFY_BAD;
break;
case CPU_CLUSTER_PM_ENTER_FAILED:
case CPU_CLUSTER_PM_EXIT:
Expand Down Expand Up @@ -1595,6 +1604,8 @@ static int omap_dma_context_notifier(struct notifier_block *nb,

switch (cmd) {
case CPU_CLUSTER_PM_ENTER:
if (omap_dma_busy(od))
return NOTIFY_BAD;
omap_dma_context_save(od);
break;
case CPU_CLUSTER_PM_ENTER_FAILED:
Expand Down

0 comments on commit 29a25b9

Please sign in to comment.