[Sound-open-firmware] [PATCH 1/4] pipeline: set up static buffers using platform macros.
Use period frames instead of period size in bytes. This makes the pipeline configuration less ambiguous and also allows for host, dai and internal frame sizes to be defined.
Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com --- src/audio/pipeline_static.c | 53 ++++++++++++++++------- src/platform/baytrail/include/platform/platform.h | 19 +++++--- 2 files changed, 51 insertions(+), 21 deletions(-)
diff --git a/src/audio/pipeline_static.c b/src/audio/pipeline_static.c index 51ced6c..cc80adf 100644 --- a/src/audio/pipeline_static.c +++ b/src/audio/pipeline_static.c @@ -46,7 +46,7 @@ #include <reef/audio/pipeline.h>
/* simple debug pipeline */ -#define DEBUG_PIPE 0 +#define DEBUG_PIPE 1
/* convenience component UUIDs and descriptors */ #define SPIPE_MIXER {COMP_TYPE_MIXER, 0, 0} @@ -63,16 +63,37 @@ .source_period = {.size = xosize, .number = xonum, .no_irq = xoirq},},}
/* Host facing buffer */ +#define HOST_PERIOD_SIZE \ + (PLAT_HOST_PERIOD_FRAMES * PLATFORM_HOST_FRAME_SIZE) +#define HOST_BUFFER_SIZE \ + (HOST_PERIOD_SIZE * PLAT_HOST_PERIODS) + #define SPIPE_HOST_BUF \ - SPIPE_BUFFER(PLAT_HOST_PERSIZE * PLAT_HOST_PERIODS, \ - PLAT_HOST_PERSIZE, PLAT_HOST_PERIODS, 0, \ - PLAT_HOST_PERSIZE, PLAT_HOST_PERIODS, 0) + SPIPE_BUFFER(HOST_BUFFER_SIZE, \ + HOST_PERIOD_SIZE, PLAT_HOST_PERIODS, 0, \ + HOST_PERIOD_SIZE, PLAT_HOST_PERIODS, 0)
/* Device facing buffer */ +#define DEV_PERIOD_SIZE \ + (PLAT_DAI_PERIOD_FRAMES * PLATFORM_DAI_FRAME_SIZE) +#define DEV_BUFFER_SIZE \ + (DEV_PERIOD_SIZE * PLAT_DAI_PERIODS) + #define SPIPE_DEV_BUF \ - SPIPE_BUFFER(PLAT_DEV_PERSIZE * PLAT_DEV_PERIODS, \ - PLAT_DEV_PERSIZE, PLAT_DEV_PERIODS, 0, \ - PLAT_DEV_PERSIZE, PLAT_DEV_PERIODS, 0) + SPIPE_BUFFER(DEV_BUFFER_SIZE, \ + DEV_PERIOD_SIZE, PLAT_DAI_PERIODS, 0, \ + DEV_PERIOD_SIZE, PLAT_DAI_PERIODS, 0) + +/* Internal buffer */ +#define INT_PERIOD_SIZE \ + (PLAT_INT_PERIOD_FRAMES * PLATFORM_INT_FRAME_SIZE) +#define INT_BUFFER_SIZE \ + (INT_PERIOD_SIZE * PLAT_INT_PERIODS) + +#define SPIPE_INT_BUF \ + SPIPE_BUFFER(INT_BUFFER_SIZE, \ + INT_PERIOD_SIZE, PLAT_INT_PERIODS, 0, \ + INT_PERIOD_SIZE, PLAT_INT_PERIODS, 0)
struct spipe_comp { uint32_t type; @@ -114,9 +135,9 @@ static struct spipe_comp pipe_capt_comps[] = { static struct spipe_buffer pipe_buffers[] = { SPIPE_HOST_BUF, /* B0 */ SPIPE_HOST_BUF, /* B1 */ - SPIPE_HOST_BUF, /* B2 */ - SPIPE_HOST_BUF, /* B3 */ - SPIPE_HOST_BUF, /* B4 */ + SPIPE_INT_BUF, /* B2 */ + SPIPE_INT_BUF, /* B3 */ + SPIPE_INT_BUF, /* B4 */ SPIPE_DEV_BUF, /* B5 */ SPIPE_DEV_BUF, /* B6 */ SPIPE_HOST_BUF, /* B7 */ @@ -127,9 +148,9 @@ static struct spipe_buffer pipe_buffers[] = { /* * One PCM to single SSP output. SSP port is set in platform.h * - * host PCM0(0) ---> volume(1) ---> SSPx(6) + * host PCM0(0) --B0--> volume(1) --B5--> SSPx(6) * - * host PCM0(9) <--- volume(8) <--- SSPx(7) + * host PCM0(9) <--B7-- volume(8) <--B6-- SSPx(7) */ static struct spipe_link pipe_play[] = { {&pipe_play_comps[0], &pipe_buffers[0], &pipe_play_comps[1]}, @@ -141,11 +162,11 @@ static struct spipe_link pipe_play[] = { /* * Two PCMs mixed into single SSP output. SSP port is set in platform.h * - * host PCM0(0) ---> volume(1) ---+ - * |mixer(4) --> volume(5) ---> SSPx(6) - * host PCM1(2) ---> volume(3) ---+ + * host PCM0(0) --B0--> volume(1) --B2--+ + * |--mixer(4) --B4--> volume(5) --B5--> SSPx(6) + * host PCM1(2) --B1--> volume(3) --B3--+ * - * host PCM0(9) <--- volume(8) <--- SSPx(7) + * host PCM0(9) <--B7-- volume(8) <--B6-- SSPx(7) */ static struct spipe_link pipe_play[] = { {&pipe_play_comps[0], &pipe_buffers[0], &pipe_play_comps[1]}, diff --git a/src/platform/baytrail/include/platform/platform.h b/src/platform/baytrail/include/platform/platform.h index 5e0c7a6..b1bfbf2 100644 --- a/src/platform/baytrail/include/platform/platform.h +++ b/src/platform/baytrail/include/platform/platform.h @@ -54,16 +54,25 @@ #define PLATFORM_MAX_CHANNELS 4 #define PLATFORM_MAX_STREAMS 5
+/* TODO: get this from IPC - 2 * 32 bit*/ +#define PLATFORM_INT_FRAME_SIZE 8 +/* TODO: get this from IPC - 2 * 16 bit*/ +#define PLATFORM_HOST_FRAME_SIZE 4 +/* TODO: get this from IPC - 2 * 24 (32) bit*/ +#define PLATFORM_DAI_FRAME_SIZE 8 + /* Platform Host DMA buffer config - these should align with DMA engine */ -#define PLAT_HOST_PERSIZE 192 /* must be multiple of DMA burst size */ +#define PLAT_HOST_PERIOD_FRAMES 48 /* 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 192 /* must be multiple of DMA+DEV burst size */ -#define PLAT_DEV_PERIODS 2 /* give enough latency for DMA refill */ +#define PLAT_DAI_PERIOD_FRAMES 48 /* must be multiple of DMA+DEV burst size */ +#define PLAT_DAI_PERIODS 2 /* give enough latency for DMA refill */ + +/* Platform internal buffer config - these should align with DMA engine */ +#define PLAT_INT_PERIOD_FRAMES 48 /* must be multiple of DMA+DEV burst size */ +#define PLAT_INT_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
The conversion should up/down convert only if source/sink is host or dai. Volume should be 32 bit at all other times
Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com --- src/audio/volume.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-)
diff --git a/src/audio/volume.c b/src/audio/volume.c index d797796..d457632 100644 --- a/src/audio/volume.c +++ b/src/audio/volume.c @@ -164,7 +164,7 @@ static void vol_s16_to_s24(struct comp_dev *dev, struct comp_buffer *sink, /* buffer sizes are always divisible by period frames */ for (i = 0; i < frames * 2; i += 2) { dest[i] = ((int32_t)src[i] * cd->volume[0]) >> 8; - dest[i + 1] = ((int32_t)src[i + 1] * cd->volume[0]) >> 8; + dest[i + 1] = ((int32_t)src[i + 1] * cd->volume[1]) >> 8; }
source->r_ptr = src + i; @@ -184,7 +184,7 @@ static void vol_s24_to_s16(struct comp_dev *dev, struct comp_buffer *sink, dest[i] = (int16_t)((((int32_t)src[i] >> 8) * cd->volume[0]) >> 16); dest[i + 1] = (int16_t)((((int32_t)src[i + 1] >> 8) * - cd->volume[0]) >> 16); + cd->volume[1]) >> 16); }
source->r_ptr = src + i; @@ -197,8 +197,8 @@ static const struct comp_func_map func_map[] = { {STREAM_FORMAT_S16_LE, STREAM_FORMAT_S32_LE, 2, vol_s16_to_s32}, {STREAM_FORMAT_S32_LE, STREAM_FORMAT_S16_LE, 2, vol_s32_to_s16}, {STREAM_FORMAT_S32_LE, STREAM_FORMAT_S32_LE, 2, vol_s32_to_s32}, - {STREAM_FORMAT_S16_LE, STREAM_FORMAT_S24_3LE, 2, vol_s16_to_s24}, - {STREAM_FORMAT_S24_3LE, STREAM_FORMAT_S16_LE, 2, vol_s24_to_s16}, + {STREAM_FORMAT_S16_LE, STREAM_FORMAT_S24_4LE, 2, vol_s16_to_s24}, + {STREAM_FORMAT_S24_4LE, STREAM_FORMAT_S16_LE, 2, vol_s24_to_s16}, };
static void vol_update(struct comp_data *cd, uint32_t chan) @@ -397,7 +397,7 @@ static int volume_copy(struct comp_dev *dev) { struct comp_data *cd = comp_get_drvdata(dev); struct comp_buffer *sink, *source; - uint32_t cframes = PIPELINE_LL_FRAMES; + uint32_t cframes = PLAT_INT_PERIOD_FRAMES;
trace_comp("Vol");
@@ -431,18 +431,32 @@ static int volume_prepare(struct comp_dev *dev) { struct comp_data *cd = comp_get_drvdata(dev); struct comp_buffer *sink, *source; + uint32_t source_format, sink_format; int i;
/* volume components will only ever have 1 source and 1 sink buffer */ source = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); sink = list_first_item(&dev->bsink_list, struct comp_buffer, source_list);
+ /* is source a host or DAI ? */ + if (source->source->is_host || source->source->is_dai) + source_format = source->params.pcm.format; + else + source_format = STREAM_FORMAT_S32_LE; + + /* TODO tmp hard coded for 24 bit - need fixed for capture*/ + /* is sink a host or DAI ? */ + if (sink->sink->is_host || sink->sink->is_dai) + sink_format = STREAM_FORMAT_S24_4LE;//sink->params.pcm.format; + else + sink_format = STREAM_FORMAT_S32_LE; + /* map the volume function for source and sink buffers */ for (i = 0; i < ARRAY_SIZE(func_map); i++) {
- if (source->params.pcm.format != func_map[i].source) + if (source_format != func_map[i].source) continue; - if (sink->params.pcm.format != func_map[i].sink) + if (sink_format != func_map[i].sink) continue; if (sink->params.channels != func_map[i].channels) continue;
Make the mixer compute two channels per loop iteration. This allows for easier vectorisation. The loop is also more efficient if we update or source/sink pointers after mixing has completed.
Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com --- src/audio/mixer.c | 50 +++++++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 23 deletions(-)
diff --git a/src/audio/mixer.c b/src/audio/mixer.c index b244f50..d08bc30 100644 --- a/src/audio/mixer.c +++ b/src/audio/mixer.c @@ -49,31 +49,35 @@ struct mixer_data {
/* mix n stream datas to 1 sink buffer */ static void mix_n(struct comp_dev *dev, struct comp_buffer *sink, - struct comp_buffer **sources, uint32_t count, uint32_t frames) + struct comp_buffer **sources, uint32_t num_sources, uint32_t frames) { - int16_t *src; - int16_t *dest = (int16_t*) sink->w_ptr; - int i, j, k; - int32_t val = 0; - - /* buffer sizes are always divisible by period frames */ - /* TODO: unroll this loop for further optimisation */ - for (i = 0; i < frames; i++) { - for (j = 0; j < sink->params.channels; j++) { - val = 0; - for (k = 0; k < count; k++) { - src = (int16_t*)sources[k]->r_ptr; - val += *src; - /* TODO: clamp when converting to int16_t */ - src++; - sources[k]->r_ptr = src; - } - *dest = (int16_t)(val >> (count >> 1)); /* average level */ - dest++; + int32_t *src, *dest = sink->w_ptr, val[2], count; + int i, j; + + count = frames * sink->params.channels; + + for (i = 0; i < count; i += 2) { + val[0] = 0; + val[1] = 0; + for (j = 0; j < num_sources; j++) { + src = sources[j]->r_ptr; + + /* TODO: clamp */ + val[0] += src[i]; + val[1] += src[i + 1]; } + + /* TODO: best place for attenuation ? */ + dest[i] = (val[0] >> (num_sources >> 1)); + dest[i + 1] = (val[1] >> (num_sources >> 1)); }
- sink->w_ptr = dest; + /* update R/W pointers */ + sink->w_ptr = dest + count; + for (j = 0; j < num_sources; j++) { + src = sources[j]->r_ptr; + sources[j]->r_ptr = src + count; + } }
static struct comp_dev *mixer_new(uint32_t type, uint32_t index, @@ -203,7 +207,7 @@ 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 = PIPELINE_LL_FRAMES; + uint32_t i = 0, cframes = PLAT_INT_PERIOD_FRAMES; struct list_item * blist;
trace_mixer("Mix"); @@ -222,7 +226,7 @@ static int mixer_copy(struct comp_dev *dev) md->mix_func(dev, sink, sources, i, cframes);
/* update buffer pointers for overflow */ - for(; i>0; i--) { + for(; i > 0; i--) { if (sources[i-1]->r_ptr >= sources[i-1]->end_addr) sources[i-1]->r_ptr = sources[i-1]->addr; comp_update_buffer(sources[i-1]);
It's better to express MCLK and BCLK as freqencies rather than as ratios.
Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com --- src/drivers/ssp.c | 4 +++- src/include/reef/dai.h | 3 +-- src/ipc/intel-ipc.c | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/src/drivers/ssp.c b/src/drivers/ssp.c index 9656104..c285af3 100644 --- a/src/drivers/ssp.c +++ b/src/drivers/ssp.c @@ -252,7 +252,9 @@ static inline int ssp_set_config(struct dai *dai, struct dai_config *dai_config) return -ENODEV; }
- sscr0 |= SSCR0_SCR(dai->config.mclk_fs / dai->config.bclk_fs - 1); + /* BCLK is generated from MCLK */ + sscr0 |= SSCR0_SCR(dai->config.mclk / dai->config.bclk - 1); + /* format */ switch (dai->config.format & DAI_FMT_FORMAT_MASK) { case DAI_FMT_I2S: diff --git a/src/include/reef/dai.h b/src/include/reef/dai.h index 5a29e85..cfcc428 100644 --- a/src/include/reef/dai.h +++ b/src/include/reef/dai.h @@ -103,8 +103,7 @@ struct dai_config { uint32_t frame_size; /* in BCLKs */ struct dai_slot_map tx_slot_map[DAI_NUM_SLOT_MAPS]; struct dai_slot_map rx_slot_map[DAI_NUM_SLOT_MAPS]; - uint32_t bclk_fs; /* ratio between frame size and BCLK */ - uint32_t mclk_fs; /* ratio between frame size and MCLK */ + uint32_t bclk; /* BCLK frequency in Hz */ uint32_t mclk; /* mclk frequency in Hz */ uint32_t clk_src; /* DAI specific clk source */ uint32_t lbm; /* loopback mode */ diff --git a/src/ipc/intel-ipc.c b/src/ipc/intel-ipc.c index cfe53c1..bfffaf6 100644 --- a/src/ipc/intel-ipc.c +++ b/src/ipc/intel-ipc.c @@ -565,9 +565,9 @@ static uint32_t ipc_device_set_formats(uint32_t header) dai_dev->dai_config.mclk = config_req.clock_frequency; dai_dev->dai_config.format = DAI_FMT_I2S | DAI_FMT_CONT | DAI_FMT_NB_NF | DAI_FMT_CBS_CFS; - dai_dev->dai_config.frame_size = 32; /* TODO 16bit stereo hard coded */ - dai_dev->dai_config.bclk_fs = 32; /* 32 BCLKs per frame - */ - dai_dev->dai_config.mclk_fs = 256; + dai_dev->dai_config.frame_size = 24; /* really sample size */ + dai_dev->dai_config.bclk = 2400000; + dai_dev->dai_config.mclk = 19200000; dai_dev->dai_config.clk_src = SSP_CLK_EXT;
comp_dai_config(dai_dev->dev.cd, &dai_dev->dai_config);
participants (1)
-
Liam Girdwood