[Sound-open-firmware] [PATCH] dma: Add support for callback DMA reload.
Add support to immediately reload the DMA during a DMA transfer completion callback. This allows components to respond quickly to any physical DMA copy updates i.e. period split over two non continuous physical host pages.
Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com --- src/audio/dai.c | 2 +- src/drivers/dw-dma.c | 53 ++++++++++++++++++++++++++++++++------ src/include/reef/audio/component.h | 3 ++- src/include/reef/dma.h | 5 ++-- src/ipc/intel-ipc.c | 2 +- 5 files changed, 52 insertions(+), 13 deletions(-)
diff --git a/src/audio/dai.c b/src/audio/dai.c index afa1be1..7bbde08 100644 --- a/src/audio/dai.c +++ b/src/audio/dai.c @@ -68,7 +68,7 @@ struct dai_data { };
/* this is called by DMA driver every time descriptor has completed */ -static void dai_dma_cb(void *data, uint32_t type) +static void dai_dma_cb(void *data, uint32_t type, struct dma_sg_elem *next) { struct comp_dev *dev = (struct comp_dev *)data; struct dai_data *dd = comp_get_drvdata(dev); diff --git a/src/drivers/dw-dma.c b/src/drivers/dw-dma.c index 8834ca3..ecd152d 100644 --- a/src/drivers/dw-dma.c +++ b/src/drivers/dw-dma.c @@ -184,7 +184,7 @@ struct dma_chan_data {
struct work work;
- void (*cb)(void *data, uint32_t type); /* client callback function */ + void (*cb)(void *data, uint32_t type, struct dma_sg_elem *next); /* client callback function */ void *cb_data; /* client callback data */ int cb_type; /* callback type */ }; @@ -195,7 +195,9 @@ struct dma_pdata { uint32_t class; /* channel class - set for controller atm */ };
-static inline void dw_dma_chan_reload(struct dma *dma, int channel); +static inline void dw_dma_chan_reload_lli(struct dma *dma, int channel); +static inline void dw_dma_chan_reload_next(struct dma *dma, int channel, + struct dma_sg_elem *next);
static inline void dw_write(struct dma *dma, uint32_t reg, uint32_t value) { @@ -385,6 +387,7 @@ out: static int dw_dma_release(struct dma *dma, int channel) { struct dma_pdata *p = dma_get_drvdata(dma); + struct dma_sg_elem next; uint32_t flags;
spin_lock_irq(&dma->lock, flags); @@ -393,8 +396,8 @@ static int dw_dma_release(struct dma *dma, int channel)
if (p->chan[channel].status == DMA_STATUS_PAUSED) { if (p->chan[channel].cb && p->chan[channel].cb_type & DMA_IRQ_TYPE_LLIST) - p->chan[channel].cb(p->chan[channel].cb_data, DMA_IRQ_TYPE_LLIST); - dw_dma_chan_reload(dma, channel); + p->chan[channel].cb(p->chan[channel].cb_data, DMA_IRQ_TYPE_LLIST, &next); + dw_dma_chan_reload_lli(dma, channel); }
/* resume and reload DMA */ @@ -711,7 +714,8 @@ static int dw_dma_pm_context_store(struct dma *dma) }
static void dw_dma_set_cb(struct dma *dma, int channel, int type, - void (*cb)(void *data, uint32_t type), void *data) + void (*cb)(void *data, uint32_t type, struct dma_sg_elem *next), + void *data) { struct dma_pdata *p = dma_get_drvdata(dma); uint32_t flags; @@ -723,7 +727,8 @@ static void dw_dma_set_cb(struct dma *dma, int channel, int type, spin_unlock_irq(&dma->lock, flags); }
-static inline void dw_dma_chan_reload(struct dma *dma, int channel) +/* reload using LLI data */ +static inline void dw_dma_chan_reload_lli(struct dma *dma, int channel) { struct dma_pdata *p = dma_get_drvdata(dma); struct dw_lli2 *lli = p->chan[channel].lli_current; @@ -754,11 +759,39 @@ static inline void dw_dma_chan_reload(struct dma *dma, int channel) dw_write(dma, DW_DMA_CHAN_EN, CHAN_ENABLE(channel)); }
+/* reload using callback data */ +static inline void dw_dma_chan_reload_next(struct dma *dma, int channel, + struct dma_sg_elem *next) +{ + struct dma_pdata *p = dma_get_drvdata(dma); + struct dw_lli2 *lli = p->chan[channel].lli_current; + + /* channel needs started from scratch, so write SARn, DARn */ + dw_write(dma, DW_SAR(channel), next->src); + dw_write(dma, DW_DAR(channel), next->dest); + + /* set transfer size of element */ + lli->ctrl_hi = DW_CTLH_CLASS(p->class) | + (next->size & DW_CTLH_BLOCK_TS_MASK); + + /* program CTLn */ + dw_write(dma, DW_CTRL_LOW(channel), lli->ctrl_lo); + dw_write(dma, DW_CTRL_HIGH(channel), lli->ctrl_hi); + + /* program CFGn */ + dw_write(dma, DW_CFG_LOW(channel), p->chan[channel].cfg_lo); + dw_write(dma, DW_CFG_HIGH(channel), p->chan[channel].cfg_hi); + + /* enable the channel */ + dw_write(dma, DW_DMA_CHAN_EN, CHAN_ENABLE(channel)); +} + /* this will probably be called at the end of every period copied */ static void dw_dma_irq_handler(void *data) { struct dma *dma = (struct dma *)data; struct dma_pdata *p = dma_get_drvdata(dma); + struct dma_sg_elem next; uint32_t status_tfr = 0, status_block = 0, status_err = 0, status_intr; uint32_t mask, pmask; int i; @@ -806,12 +839,16 @@ static void dw_dma_irq_handler(void *data) continue; }
+ next.size = 0; if (p->chan[i].cb) p->chan[i].cb(p->chan[i].cb_data, - DMA_IRQ_TYPE_LLIST); + DMA_IRQ_TYPE_LLIST, &next);
/* check for reload channel */ - dw_dma_chan_reload(dma, i); + if (next.size > 0) + dw_dma_chan_reload_next(dma, i, &next); + else + dw_dma_chan_reload_lli(dma, i); } #if DW_USE_HW_LLI /* end of a LLI block */ diff --git a/src/include/reef/audio/component.h b/src/include/reef/audio/component.h index 61afa5a..850165b 100644 --- a/src/include/reef/audio/component.h +++ b/src/include/reef/audio/component.h @@ -161,7 +161,8 @@ struct comp_ops { int (*copy)(struct comp_dev *dev);
/* host buffer config */ - int (*host_buffer)(struct comp_dev *dev, struct dma_sg_elem *elem); + int (*host_buffer)(struct comp_dev *dev, struct dma_sg_elem *elem, + uint32_t host_size); };
diff --git a/src/include/reef/dma.h b/src/include/reef/dma.h index b9e8a45..6de2ede 100644 --- a/src/include/reef/dma.h +++ b/src/include/reef/dma.h @@ -104,7 +104,8 @@ struct dma_ops { struct dma_sg_config *config);
void (*set_cb)(struct dma *dma, int channel, int type, - void (*cb)(void *data, uint32_t type), void *data); + void (*cb)(void *data, uint32_t type, struct dma_sg_elem *next), + void *data);
int (*pm_context_restore)(struct dma *dma); int (*pm_context_store)(struct dma *dma); @@ -162,7 +163,7 @@ static inline void dma_channel_put(struct dma *dma, int channel) }
static inline void dma_set_cb(struct dma *dma, int channel, int type, - void (*cb)(void *data, uint32_t type), void *data) + void (*cb)(void *data, uint32_t type, struct dma_sg_elem *next), void *data) { dma->ops->set_cb(dma, channel, type, cb, data); } diff --git a/src/ipc/intel-ipc.c b/src/ipc/intel-ipc.c index 7aa24f3..d735f26 100644 --- a/src/ipc/intel-ipc.c +++ b/src/ipc/intel-ipc.c @@ -143,7 +143,7 @@ static uint32_t ipc_fw_caps(uint32_t header) return IPC_INTEL_GLB_REPLY_SUCCESS; }
-static void dma_complete(void *data, uint32_t type) +static void dma_complete(void *data, uint32_t type, struct dma_sg_elem *next) { struct intel_ipc_data *iipc = (struct intel_ipc_data *)data;
The host buffer may not be a multiple of host PHY page size, so provide so pass this value as part of our host buffer init.
Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com --- src/audio/host.c | 5 +++-- src/audio/pipeline.c | 4 ++-- src/include/reef/audio/component.h | 4 ++-- src/include/reef/audio/pipeline.h | 2 +- src/ipc/intel-ipc.c | 3 ++- 5 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/src/audio/host.c b/src/audio/host.c index e76fe81..521380a 100644 --- a/src/audio/host.c +++ b/src/audio/host.c @@ -473,7 +473,8 @@ static int host_cmd(struct comp_dev *dev, int cmd, void *data) return ret; }
-static int host_buffer(struct comp_dev *dev, struct dma_sg_elem *elem) +static int host_buffer(struct comp_dev *dev, struct dma_sg_elem *elem, + uint32_t host_size) { struct host_data *hd = comp_get_drvdata(dev); struct dma_sg_elem *e; @@ -484,7 +485,7 @@ static int host_buffer(struct comp_dev *dev, struct dma_sg_elem *elem) return -ENOMEM;
*e = *elem; - hd->host_size += e->size; + hd->host_size = host_size;
list_item_append(&e->list, &hd->host.elem_list); return 0; diff --git a/src/audio/pipeline.c b/src/audio/pipeline.c index f42fa15..0026048 100644 --- a/src/audio/pipeline.c +++ b/src/audio/pipeline.c @@ -553,11 +553,11 @@ int pipeline_reset(struct pipeline *p, struct comp_dev *host)
/* TODO: remove ?? configure pipelines host DMA buffer */ int pipeline_host_buffer(struct pipeline *p, struct comp_dev *host, - struct dma_sg_elem *elem) + struct dma_sg_elem *elem, uint32_t host_size) { trace_pipe("PBr");
- return comp_host_buffer(host, elem); + return comp_host_buffer(host, elem, host_size); }
/* copy audio data from DAI buffer to host PCM buffer via pipeline */ diff --git a/src/include/reef/audio/component.h b/src/include/reef/audio/component.h index 850165b..fbd29e4 100644 --- a/src/include/reef/audio/component.h +++ b/src/include/reef/audio/component.h @@ -254,10 +254,10 @@ static inline int comp_params(struct comp_dev *dev, * mandatory for host components, optional for the others. */ static inline int comp_host_buffer(struct comp_dev *dev, - struct dma_sg_elem *elem) + struct dma_sg_elem *elem, uint32_t host_size) { if (dev->drv->ops.host_buffer) - return dev->drv->ops.host_buffer(dev, elem); + return dev->drv->ops.host_buffer(dev, elem, host_size); return 0; }
diff --git a/src/include/reef/audio/pipeline.h b/src/include/reef/audio/pipeline.h index f0f77fa..26c1dd6 100644 --- a/src/include/reef/audio/pipeline.h +++ b/src/include/reef/audio/pipeline.h @@ -89,7 +89,7 @@ int pipeline_params(struct pipeline *p, struct comp_dev *cd,
/* pipeline parameters */ int pipeline_host_buffer(struct pipeline *p, struct comp_dev *cd, - struct dma_sg_elem *elem); + struct dma_sg_elem *elem, uint32_t host_size);
/* prepare the pipeline for usage */ int pipeline_prepare(struct pipeline *p, struct comp_dev *cd); diff --git a/src/ipc/intel-ipc.c b/src/ipc/intel-ipc.c index d735f26..b7ecbba 100644 --- a/src/ipc/intel-ipc.c +++ b/src/ipc/intel-ipc.c @@ -244,7 +244,8 @@ static int parse_page_descriptors(struct intel_ipc_data *iipc, else elem.dest = phy_addr;
- err = pipeline_host_buffer(pipeline_static, host, &elem); + err = pipeline_host_buffer(pipeline_static, host, &elem, + req->ringinfo.ring_size); if (err < 0) { trace_ipc_error("ePb"); return err;
This will be different for each platform so use the platform tiemout.
Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com --- src/audio/host.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/audio/host.c b/src/audio/host.c index 521380a..d544924 100644 --- a/src/audio/host.c +++ b/src/audio/host.c @@ -364,8 +364,8 @@ static int host_preload(struct comp_dev *dev) dma_set_config(hd->dma, hd->chan, &hd->config); dma_start(hd->dma, hd->chan);
- /* wait 1 msecs for DMA to finish */ - hd->complete.timeout = 100; + /* wait for DMA to finish */ + hd->complete.timeout = PLATFORM_DMA_TIMEOUT; ret = wait_for_completion_timeout(&hd->complete); if (ret < 0) { trace_comp_error("eHp");
Host buffers are not guaranteed to be continuous physical pages or a factor of the DSP period size. Add support for non continuous host buffers of any size.
Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com --- src/audio/host.c | 196 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 169 insertions(+), 27 deletions(-)
diff --git a/src/audio/host.c b/src/audio/host.c index d544924..f339bc2 100644 --- a/src/audio/host.c +++ b/src/audio/host.c @@ -76,6 +76,8 @@ struct host_data { /* pointers set during params to host or local above */ struct hc_buf *source; struct hc_buf *sink; + uint32_t split_remaining; + uint32_t next_inc;
/* stream info */ struct stream_params params; @@ -95,10 +97,17 @@ static inline struct dma_sg_elem *next_buffer(struct hc_buf *hc) return elem; }
-/* this is called by DMA driver every time descriptor has completed */ -static void host_dma_cb(void *data, uint32_t type) +/* + * Host period copy to DSP DMA completion. This is called when DMA completes + * its current transfer from host to DSP. The host memory is not guaranteed + * to be continuous and also not guaranteed to have a period/buffer size that + * is a multiple of the DSP period size. This means we must check we do not + * overflow host period/buffer/page boundaries on each transfer and split the + * DMA transfer if we do overflow. + */ +static void host_dma_cb_playback(struct comp_dev *dev, + struct dma_sg_elem *next) { - struct comp_dev *dev = (struct comp_dev *)data; struct host_data *hd = comp_get_drvdata(dev); struct dma_sg_elem *local_elem, *source_elem, *sink_elem; struct comp_buffer *dma_buffer; @@ -106,6 +115,63 @@ static void host_dma_cb(void *data, uint32_t type) local_elem = list_first_item(&hd->config.elem_list, struct dma_sg_elem, list);
+ trace_host("Cpp"); + + /* are we dealing with a split transfer */ + if (hd->split_remaining) { + + /* update local elem */ + local_elem->dest += local_elem->size; + source_elem = next_buffer(hd->source); + hd->source->current_end = source_elem->src + source_elem->size; + local_elem->src = source_elem->src; + + /* set up next elem */ + local_elem->size = hd->split_remaining; + hd->next_inc = hd->split_remaining; + hd->split_remaining = 0; + + } else { + /* destination is always DSP period size */ + sink_elem = next_buffer(hd->sink); + + local_elem->dest = sink_elem->dest; + local_elem->size = hd->period->size; + local_elem->src += hd->next_inc; + hd->next_inc = hd->period->size; + + /* are we at end of elem */ + if (local_elem->src == hd->source->current_end) { + + /* end of elem, so use next */ + source_elem = next_buffer(hd->source); + hd->source->current_end = source_elem->src + source_elem->size; + local_elem->src = source_elem->src; + + } else if (local_elem->src + hd->period->size > hd->source->current_end) { + + /* split copy - split transaction into 2 copies */ + local_elem->size = hd->source->current_end - local_elem->src; + hd->split_remaining = hd->period->size - local_elem->size; + + next->src = local_elem->src; + next->dest = local_elem->dest; + next->size = local_elem->size; + return; + } + } + + /* update buffer positions */ + dma_buffer = hd->dma_buffer; + + dma_buffer->w_ptr += hd->period->size; + + if (dma_buffer->w_ptr >= dma_buffer->end_addr) + dma_buffer->w_ptr = dma_buffer->addr; +#if 0 + trace_value((uint32_t)(hd->dma_buffer->w_ptr - hd->dma_buffer->addr)); +#endif + /* new local period, update host buffer position blks */ hd->host_pos_blks += hd->period->size;
@@ -115,45 +181,103 @@ static void host_dma_cb(void *data, uint32_t type) if (hd->host_pos) *hd->host_pos = hd->host_pos_blks;
- /* update source buffer elem and check for overflow */ - local_elem->src += hd->period->size; - if (local_elem->src >= hd->source->current_end) { + /* recalc available buffer space */ + comp_update_buffer(hd->dma_buffer);
- /* move onto next host side elem */ - source_elem = next_buffer(hd->source); - hd->source->current_end = source_elem->src + source_elem->size; - local_elem->src = source_elem->src; + /* send IPC message to driver if needed */ + hd->host_period_pos += hd->period->size; + if (hd->host_period_pos >= hd->host_period_bytes) { + hd->host_period_pos = 0; + ipc_stream_send_notification(dev, &hd->cp); }
- /* update sink buffer elem and check for overflow */ - local_elem->dest += hd->period->size; - if (local_elem->dest >= hd->sink->current_end) { + /* let any waiters know we have completed */ + wait_completed(&hd->complete); +} + +/* + * DSP period copy to host DMA completion. This is called when DMA completes + * its current transfer from DSP to host. The host memory is not guaranteed + * to be continuous and also not guaranteed to have a period/buffer size that + * is a multiple of the DSP period size. This means we must check we do not + * overflow host period/buffer/page boundaries on each transfer and split the + * DMA transfer if we do overflow. + */ +static void host_dma_cb_capture(struct comp_dev *dev, + struct dma_sg_elem *next) +{ + struct host_data *hd = comp_get_drvdata(dev); + struct dma_sg_elem *local_elem, *source_elem, *sink_elem; + struct comp_buffer *dma_buffer; + + local_elem = list_first_item(&hd->config.elem_list, + struct dma_sg_elem, list); + + trace_host("Cpc"); + + /* are we dealing with a split transfer */ + if (hd->split_remaining) {
- /* move onto next host side elem */ + /* update local elem */ + local_elem->src += local_elem->size; sink_elem = next_buffer(hd->sink); hd->sink->current_end = sink_elem->dest + sink_elem->size; local_elem->dest = sink_elem->dest; + + /* set up next elem */ + local_elem->size = hd->split_remaining; + hd->next_inc = hd->split_remaining; + hd->split_remaining = 0; + + } else { + /* source is always DSP period size */ + source_elem = next_buffer(hd->source); + + local_elem->src = source_elem->src; + local_elem->size = hd->period->size; + local_elem->dest += hd->next_inc; + hd->next_inc = hd->period->size; + + /* are we at end of elem */ + if (local_elem->dest == hd->sink->current_end) { + + /* end of elem, so use next */ + sink_elem = next_buffer(hd->sink); + hd->sink->current_end = sink_elem->dest + sink_elem->size; + local_elem->dest = sink_elem->dest; + + } else if (local_elem->dest + hd->period->size > hd->sink->current_end) { + + /* split copy - split transaction into 2 copies */ + local_elem->size = hd->sink->current_end - local_elem->dest; + hd->split_remaining = hd->period->size - local_elem->size; + + next->src = local_elem->src; + next->dest = local_elem->dest; + next->size = local_elem->size; + return; + } }
/* update buffer positions */ dma_buffer = hd->dma_buffer; - if (hd->params.direction == STREAM_DIRECTION_PLAYBACK) { - dma_buffer->w_ptr += hd->period->size; + hd->dma_buffer->r_ptr += hd->period->size;
- if (dma_buffer->w_ptr >= dma_buffer->end_addr) - dma_buffer->w_ptr = dma_buffer->addr; + if (dma_buffer->r_ptr >= dma_buffer->end_addr) + dma_buffer->r_ptr = dma_buffer->addr; #if 0 - trace_value((uint32_t)(hd->dma_buffer->w_ptr - hd->dma_buffer->addr)); + trace_value((uint32_t)(hd->dma_buffer->r_ptr - hd->dma_buffer->addr)); #endif - } else { - hd->dma_buffer->r_ptr += hd->period->size;
- if (dma_buffer->r_ptr >= dma_buffer->end_addr) - dma_buffer->r_ptr = dma_buffer->addr; -#if 0 - trace_value((uint32_t)(hd->dma_buffer->r_ptr - hd->dma_buffer->addr)); -#endif - } + + /* new local period, update host buffer position blks */ + hd->host_pos_blks += hd->period->size; + + /* buffer overlap ? */ + if (hd->host_pos_blks >= hd->host_size) + hd->host_pos_blks = 0; + if (hd->host_pos) + *hd->host_pos = hd->host_pos_blks;
/* recalc available buffer space */ comp_update_buffer(hd->dma_buffer); @@ -169,6 +293,19 @@ static void host_dma_cb(void *data, uint32_t type) wait_completed(&hd->complete); }
+/* this is called by DMA driver every time descriptor has completed */ +static void host_dma_cb(void *data, uint32_t type, struct dma_sg_elem *next) +{ + + struct comp_dev *dev = (struct comp_dev *)data; + struct host_data *hd = comp_get_drvdata(dev); + + if (hd->params.direction == STREAM_DIRECTION_PLAYBACK) + host_dma_cb_playback(dev, next); + else + host_dma_cb_capture(dev, next); +} + static struct comp_dev *host_new(uint32_t type, uint32_t index, uint32_t direction) { @@ -203,6 +340,7 @@ static struct comp_dev *host_new(uint32_t type, uint32_t index, hd->host_pos = NULL; hd->source = NULL; hd->sink = NULL; + hd->split_remaining = 0;
/* init buffer elems */ list_init(&hd->config.elem_list); @@ -347,6 +485,7 @@ static int host_params(struct comp_dev *dev, struct stream_params *params) local_elem->dest = sink_elem->dest; local_elem->size = hd->period->size; local_elem->src = source_elem->src; + hd->next_inc = hd->period->size; return 0; }
@@ -401,6 +540,8 @@ static int host_prepare(struct comp_dev *dev) hd->host_period_pos = 0; hd->host_period_bytes = hd->params.period_frames * hd->params.frame_size; + hd->split_remaining = 0; +
if (hd->params.direction == STREAM_DIRECTION_PLAYBACK) host_preload(dev); @@ -533,6 +674,7 @@ static int host_copy(struct comp_dev *dev) if (dev->state != COMP_STATE_RUNNING) return 0;
+ trace_host("CpS"); dma_set_config(hd->dma, hd->chan, &hd->config); dma_start(hd->dma, hd->chan);
Make sure any interrupt handler can run after a panic.
Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com --- src/include/reef/debug.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/src/include/reef/debug.h b/src/include/reef/debug.h index 4fa6999..2bee8e6 100644 --- a/src/include/reef/debug.h +++ b/src/include/reef/debug.h @@ -122,6 +122,7 @@ /* panic and stop executing any more code */ #define panic(_p) \ do { \ + interrupt_global_disable(); \ dbg_val(0xdead0000 | _p) \ platform_panic(_p); \ while(1) {}; \
Make it less ambiguous.
Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com --- src/drivers/dw-dma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/drivers/dw-dma.c b/src/drivers/dw-dma.c index ecd152d..9de766b 100644 --- a/src/drivers/dw-dma.c +++ b/src/drivers/dw-dma.c @@ -831,8 +831,8 @@ static void dw_dma_irq_handler(void *data) mask = 0x1 << i;
/* end of a transfer */ - if (status_tfr & mask && - p->chan[i].cb_type & DMA_IRQ_TYPE_LLIST) { + if ((status_tfr & mask) && + (p->chan[i].cb_type & DMA_IRQ_TYPE_LLIST)) {
if (p->chan[i].status == DMA_STATUS_PAUSING) { p->chan[i].status = DMA_STATUS_PAUSED;
Change tick from 1.3ms to 1ms to improve latency.
Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com --- src/audio/mixer.c | 4 +++- src/audio/volume.c | 4 +++- src/platform/baytrail/include/platform/platform.h | 7 +++++-- 3 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/src/audio/mixer.c b/src/audio/mixer.c index e48b545..b244f50 100644 --- a/src/audio/mixer.c +++ b/src/audio/mixer.c @@ -203,9 +203,11 @@ static int mixer_copy(struct comp_dev *dev) { struct mixer_data *md = comp_get_drvdata(dev); struct comp_buffer *sink, *sources[5], *source; - uint32_t i = 0, cframes = 64; + uint32_t i = 0, cframes = PIPELINE_LL_FRAMES; struct list_item * blist;
+ trace_mixer("Mix"); + /* calculate the highest status between input streams */ list_for_item(blist, &dev->bsource_list) { source = container_of(blist, struct comp_buffer, sink_list); diff --git a/src/audio/volume.c b/src/audio/volume.c index f5528cd..23db6a5 100644 --- a/src/audio/volume.c +++ b/src/audio/volume.c @@ -376,7 +376,9 @@ static int volume_copy(struct comp_dev *dev) { struct comp_data *cd = comp_get_drvdata(dev); struct comp_buffer *sink, *source; - uint32_t cframes = 64; + uint32_t cframes = PIPELINE_LL_FRAMES; + + trace_comp("Vol");
/* volume components will only ever have 1 source and 1 sink buffer */ source = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); diff --git a/src/platform/baytrail/include/platform/platform.h b/src/platform/baytrail/include/platform/platform.h index 38fcc26..b58a3c0 100644 --- a/src/platform/baytrail/include/platform/platform.h +++ b/src/platform/baytrail/include/platform/platform.h @@ -55,13 +55,16 @@ #define PLATFORM_MAX_STREAMS 5
/* Platform Host DMA buffer config - these should align with DMA engine */ -#define PLAT_HOST_PERSIZE 256 /* must be multiple of DMA burst size */ +#define PLAT_HOST_PERSIZE 192 /* must be multiple of DMA burst size */ #define PLAT_HOST_PERIODS 2 /* give enough latency for DMA refill */
/* Platform Dev DMA buffer config - these should align with DMA engine */ -#define PLAT_DEV_PERSIZE 256 /* must be multiple of DMA+DEV burst size */ +#define PLAT_DEV_PERSIZE 192 /* must be multiple of DMA+DEV burst size */ #define PLAT_DEV_PERIODS 2 /* give enough latency for DMA refill */
+/* Pipeline low latency frames per copy - TODO should come from config */ +#define PIPELINE_LL_FRAMES 48 + /* DMA channel drain timeout in microseconds */ #define PLATFORM_DMA_TIMEOUT 1333
Add a simple static pipeline that can be used for debug
Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com --- src/audio/pipeline_static.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
diff --git a/src/audio/pipeline_static.c b/src/audio/pipeline_static.c index 1bbc5b7..51ced6c 100644 --- a/src/audio/pipeline_static.c +++ b/src/audio/pipeline_static.c @@ -45,6 +45,9 @@ #include <reef/audio/component.h> #include <reef/audio/pipeline.h>
+/* simple debug pipeline */ +#define DEBUG_PIPE 0 + /* convenience component UUIDs and descriptors */ #define SPIPE_MIXER {COMP_TYPE_MIXER, 0, 0} #define SPIPE_MUX {COMP_TYPE_MUX, 0, 0} @@ -119,6 +122,22 @@ static struct spipe_buffer pipe_buffers[] = { SPIPE_HOST_BUF, /* B7 */ };
+#if DEBUG_PIPE + +/* + * One PCM to single SSP output. SSP port is set in platform.h + * + * host PCM0(0) ---> volume(1) ---> SSPx(6) + * + * host PCM0(9) <--- volume(8) <--- SSPx(7) + */ +static struct spipe_link pipe_play[] = { + {&pipe_play_comps[0], &pipe_buffers[0], &pipe_play_comps[1]}, + {&pipe_play_comps[1], &pipe_buffers[5], &pipe_play_comps[6]}, +}; + +#else + /* * Two PCMs mixed into single SSP output. SSP port is set in platform.h * @@ -137,6 +156,8 @@ static struct spipe_link pipe_play[] = { {&pipe_play_comps[5], &pipe_buffers[5], &pipe_play_comps[6]}, };
+#endif + static struct spipe_link pipe_capture[] = { {&pipe_capt_comps[0], &pipe_buffers[6], &pipe_capt_comps[1]}, {&pipe_capt_comps[1], &pipe_buffers[7], &pipe_capt_comps[2]},
participants (1)
-
Liam Girdwood