diff --git a/src/audio/dai.c b/src/audio/dai.c index abb30efe9e76..a649520d1693 100644 --- a/src/audio/dai.c +++ b/src/audio/dai.c @@ -456,6 +456,7 @@ static int dai_params(struct comp_dev *dev) static int dai_prepare(struct comp_dev *dev) { struct dai_data *dd = comp_get_drvdata(dev); + struct dma_sg_config *config = &dd->config; int ret = 0; trace_dai_with_ids(dev, "dai_prepare()"); @@ -477,7 +478,9 @@ static int dai_prepare(struct comp_dev *dev) /* write back buffer contents from cache */ dcache_writeback_region(dd->dma_buffer->addr, dd->dma_buffer->size); - dd->cb_type = 0; + /* set default callback type if irq disabled */ + if (config->irq_disabled) + dd->cb_type = DMA_CB_TYPE_BLOCK; /* dma reconfig not required if XRUN handling */ if (dd->xrun) { @@ -615,7 +618,8 @@ static int dai_copy(struct comp_dev *dev) dev->params.direction); platform_dai_wallclock(dev, &dd->wallclock); - return ret; + /* let's not copy further */ + return 1; } /* get data sizes from DMA */ diff --git a/src/audio/pipeline.c b/src/audio/pipeline.c index e88b5423743d..08d72742a871 100644 --- a/src/audio/pipeline.c +++ b/src/audio/pipeline.c @@ -353,8 +353,11 @@ int pipeline_prepare(struct pipeline *p, struct comp_dev *dev) goto out; } - /* pipeline preload needed only for playback streams */ - p->preload = dev->params.direction == SOF_IPC_STREAM_PLAYBACK; + /* pipeline preload needed only for playback streams and capture + * streams scheduled with timer + */ + p->preload = dev->params.direction == SOF_IPC_STREAM_PLAYBACK || + pipeline_is_timer_driven(p); p->status = COMP_STATE_PREPARE; out: @@ -424,12 +427,12 @@ static void pipeline_comp_trigger_sched_comp(struct pipeline *p, case COMP_TRIGGER_START: p->xrun_bytes = 0; - /* playback pipelines need scheduled now, capture pipelines are - * scheduled once their initial DMA period is filled by the DAI - * or in resume process + /* playback pipelines need to be scheduled now, + * capture pipelines are scheduled only for + * timer driven scheduling */ if (comp->params.direction == SOF_IPC_STREAM_PLAYBACK || - p->status == COMP_STATE_PAUSED) { + pipeline_is_timer_driven(p)) { /* schedule initial pipeline fill when next idle */ pipeline_schedule_copy_idle(p); } @@ -596,7 +599,7 @@ static int pipeline_comp_copy(struct comp_dev *current, void *data, int dir) /* copy to downstream immediately */ if (dir == PPL_DIR_DOWNSTREAM) { err = comp_copy(current); - if (err < 0) + if (err < 0 || err > 0) return err; } diff --git a/src/drivers/dw/dma.c b/src/drivers/dw/dma.c index edc11f8df2df..29a7a501e147 100644 --- a/src/drivers/dw/dma.c +++ b/src/drivers/dw/dma.c @@ -267,6 +267,9 @@ /* number of tries to wait for reset */ #define DW_DMA_CFG_TRIES 10000 +/* min number of elems for config with irq disabled */ +#define DW_DMA_CFG_NO_IRQ_MIN_ELEMS 3 + /* linked list item address */ #define DW_DMA_LLI_ADDRESS(lli, dir) \ (((dir) == DMA_DIR_MEM_TO_DEV) ? ((lli)->sar) : ((lli)->dar)) @@ -797,6 +800,16 @@ static int dw_dma_set_config(struct dma *dma, int channel, goto out; } + if (config->irq_disabled && + config->elem_array.count < DW_DMA_CFG_NO_IRQ_MIN_ELEMS) { + trace_dwdma_error("dw-dma: %d channel %d not enough elems " + "for config with irq disabled", + dma->plat_data.id, channel, + config->elem_array.count); + ret = -EINVAL; + goto out; + } + /* do we need to realloc descriptors */ if (config->elem_array.count != chan->desc_count) {