Sound-open-firmware
Threads by month
- ----- 2025 -----
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- 4 participants
- 1538 discussions

[Sound-open-firmware] [PATCH] Volume, FIR EQ, IIR EQ, tone: Fix SOF_CTRL_CMD_SWITCH polarity
by Seppo Ingalsuo 30 Oct '17
by Seppo Ingalsuo 30 Oct '17
30 Oct '17
This patch inverts the use of switch value. A non-zero value
unmutes the audio path.
Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo(a)linux.intel.com>
---
src/audio/eq_fir.c | 11 +++++++----
src/audio/eq_iir.c | 9 +++++----
src/audio/tone.c | 9 +++++----
src/audio/volume.c | 6 +++---
4 files changed, 20 insertions(+), 15 deletions(-)
diff --git a/src/audio/eq_fir.c b/src/audio/eq_fir.c
index 9056808..8babed3 100644
--- a/src/audio/eq_fir.c
+++ b/src/audio/eq_fir.c
@@ -33,6 +33,7 @@
#include <stdint.h>
#include <stddef.h>
#include <errno.h>
+#include <stdbool.h>
#include <reef/reef.h>
#include <reef/lock.h>
#include <reef/list.h>
@@ -330,21 +331,23 @@ static int fir_cmd_set_value(struct comp_dev *dev, struct sof_ipc_ctrl_data *cda
struct comp_data *cd = comp_get_drvdata(dev);
int j;
uint32_t ch;
+ bool val;
if (cdata->cmd == SOF_CTRL_CMD_SWITCH) {
trace_eq("mst");
for (j = 0; j < cdata->num_elems; j++) {
ch = cdata->chanv[j].channel;
+ val = cdata->chanv[j].value;
tracev_value(ch);
- tracev_value(cdata->chanv[j].value);
+ tracev_value(val);
if (ch >= PLATFORM_MAX_CHANNELS) {
trace_eq_error("che");
return -EINVAL;
}
- if (cdata->chanv[j].value > 0)
- fir_mute(&cd->fir[ch]);
- else
+ if (val)
fir_unmute(&cd->fir[ch]);
+ else
+ fir_mute(&cd->fir[ch]);
}
} else {
trace_eq_error("ste");
diff --git a/src/audio/eq_iir.c b/src/audio/eq_iir.c
index d3a8fa3..88382fe 100644
--- a/src/audio/eq_iir.c
+++ b/src/audio/eq_iir.c
@@ -33,6 +33,7 @@
#include <stdint.h>
#include <stddef.h>
#include <errno.h>
+#include <stdbool.h>
#include <reef/reef.h>
#include <reef/lock.h>
#include <reef/list.h>
@@ -331,7 +332,7 @@ static int iir_cmd_set_value(struct comp_dev *dev, struct sof_ipc_ctrl_data *cda
struct comp_data *cd = comp_get_drvdata(dev);
int j;
uint32_t ch;
- uint32_t val;
+ bool val;
if (cdata->cmd == SOF_CTRL_CMD_SWITCH) {
trace_eq_iir("mst");
@@ -344,10 +345,10 @@ static int iir_cmd_set_value(struct comp_dev *dev, struct sof_ipc_ctrl_data *cda
trace_eq_iir_error("che");
return -EINVAL;
}
- if (val > 0)
- iir_mute_df2t(&cd->iir[ch]);
- else
+ if (val)
iir_unmute_df2t(&cd->iir[ch]);
+ else
+ iir_mute_df2t(&cd->iir[ch]);
}
} else {
trace_eq_iir_error("ste");
diff --git a/src/audio/tone.c b/src/audio/tone.c
index d565c17..3eb08e9 100644
--- a/src/audio/tone.c
+++ b/src/audio/tone.c
@@ -33,6 +33,7 @@
#include <stdint.h>
#include <stddef.h>
#include <errno.h>
+#include <stdbool.h>
#include <reef/reef.h>
#include <reef/lock.h>
#include <reef/list.h>
@@ -466,7 +467,7 @@ static int tone_cmd_set_value(struct comp_dev *dev, struct sof_ipc_ctrl_data *cd
struct comp_data *cd = comp_get_drvdata(dev);
int j;
uint32_t ch;
- uint32_t val;
+ bool val;
if (cdata->cmd == SOF_CTRL_CMD_SWITCH) {
trace_tone("mst");
@@ -479,10 +480,10 @@ static int tone_cmd_set_value(struct comp_dev *dev, struct sof_ipc_ctrl_data *cd
trace_tone_error("che");
return -EINVAL;
}
- if (val > 0)
- tonegen_mute(&cd->sg[ch]);
- else
+ if (val)
tonegen_unmute(&cd->sg[ch]);
+ else
+ tonegen_mute(&cd->sg[ch]);
}
} else {
diff --git a/src/audio/volume.c b/src/audio/volume.c
index 28d3225..f52ab46 100644
--- a/src/audio/volume.c
+++ b/src/audio/volume.c
@@ -468,10 +468,10 @@ static int volume_ctrl_set_cmd(struct comp_dev *dev, struct sof_ipc_ctrl_data *c
tracev_value(cdata->chanv[j].channel);
tracev_value(cdata->chanv[j].value);
if (cdata->chanv[j].channel == cd->chan[i]) {
- if (cdata->chanv[j].value > 0)
- volume_set_chan_mute(dev, i);
- else
+ if (cdata->chanv[j].value)
volume_set_chan_unmute(dev, i);
+ else
+ volume_set_chan_mute(dev, i);
}
}
}
--
2.11.0
2
1

[Sound-open-firmware] [PATCH 1/5] IPC: Add new enum commands and an index into control data struct
by Seppo Ingalsuo 24 Oct '17
by Seppo Ingalsuo 24 Oct '17
24 Oct '17
This patch adds to struct sof_ipc_ctrl_data three new commands
SOF_CTRL_CMD_ENUM, SOF_CTRL_CMD_SWITCH, and SOF_CTRL_CMD_BINARY. In
addition an index parameter is added to address various features or
registers.
Commands SOF_CTRL_CMD_ROUTE, SOF_CTRL_CMD_SRC, SOF_CTRL_CMD_LOOPBACK,
SOF_CTRL_CMD_EQ_SWITCH, SOF_CTRL_CMD_EQ_CONFIG, SOF_CTRL_CMD_MUTE, and
SOF_CTRL_CMD_UNMUTE are removed.
Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo(a)linux.intel.com>
---
src/include/uapi/ipc.h | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/src/include/uapi/ipc.h b/src/include/uapi/ipc.h
index 281e77a..5658b9a 100644
--- a/src/include/uapi/ipc.h
+++ b/src/include/uapi/ipc.h
@@ -437,25 +437,23 @@ struct sof_ipc_stream_posn {
/* control data type and direction */
enum sof_ipc_ctrl_type {
+ /* per channel data - uses struct sof_ipc_ctrl_value_chan */
SOF_CTRL_TYPE_VALUE_CHAN_GET = 0,
SOF_CTRL_TYPE_VALUE_CHAN_SET,
+ /* per component data - uses struct sof_ipc_ctrl_value_comp */
SOF_CTRL_TYPE_VALUE_COMP_GET,
SOF_CTRL_TYPE_VALUE_COMP_SET,
+ /* bespoke data - struct struct sof_abi_hdr */
SOF_CTRL_TYPE_DATA_GET,
SOF_CTRL_TYPE_DATA_SET,
};
/* control command type */
enum sof_ipc_ctrl_cmd {
- SOF_CTRL_CMD_VOLUME = 0,
- SOF_CTRL_CMD_ROUTE,
- SOF_CTRL_CMD_SRC,
- SOF_CTRL_CMD_LOOPBACK,
- SOF_CTRL_CMD_EQ_SWITCH,
- SOF_CTRL_CMD_EQ_CONFIG,
- /* Mute is similar to volume, but maps better onto ALSA switch controls */
- SOF_CTRL_CMD_MUTE,
- SOF_CTRL_CMD_UNMUTE,
+ SOF_CTRL_CMD_VOLUME = 0, /* maps to ALSA volume style controls */
+ SOF_CTRL_CMD_ENUM, /* maps to ALSA enum style controls */
+ SOF_CTRL_CMD_SWITCH, /* maps to ALSA switch style controls */
+ SOF_CTRL_CMD_BINARY, /* maps to ALSA binary style controls */
};
/* generic channel mapped value data */
@@ -481,6 +479,7 @@ struct sof_ipc_ctrl_data {
/* control access and data type */
enum sof_ipc_ctrl_type type;
enum sof_ipc_ctrl_cmd cmd;
+ uint32_t index; /* control index for comps > 1 control */
/* control data - can either be appended or DMAed from host */
struct sof_ipc_host_buffer buffer;
@@ -497,7 +496,6 @@ struct sof_ipc_ctrl_data {
};
} __attribute__((packed));
-
/*
* Component
*/
--
2.11.0
2
10

[Sound-open-firmware] [PATCH V2] SRC: Use a multi-channel FIR core to optimize speed plus other cleanup
by Seppo Ingalsuo 20 Oct '17
by Seppo Ingalsuo 20 Oct '17
20 Oct '17
This patch changes the sample rate conversion processing to use a single
multi-channel filter instead of per channel called mono filter instances.
The filter output is now rounded with 1/2 LSB add. The polyphase filter
input input block sizes are multiplied in SRC initialization to reach
near to or exacly the period length to reduce polyphase filter call
overhead.
The polyphase filter is now called via function pointer for more
flexibility with audio data formats. Currently S32_LE and S24_4LE are
supported.
Code cleanup includes removal of redundant variables and some debug
print code.
Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo(a)linux.intel.com>
---
src/audio/src.c | 200 +++++++++++------------
src/audio/src_core.c | 448 +++++++++++++++++++++++++++------------------------
src/audio/src_core.h | 42 +----
3 files changed, 329 insertions(+), 361 deletions(-)
diff --git a/src/audio/src.c b/src/audio/src.c
index 4c4bc6e..9fe81d3 100644
--- a/src/audio/src.c
+++ b/src/audio/src.c
@@ -55,7 +55,7 @@
/* src component private data */
struct comp_data {
- struct polyphase_src src[PLATFORM_MAX_CHANNELS];
+ struct polyphase_src src;
struct src_param param;
int32_t *delay_lines;
uint32_t sink_rate;
@@ -63,16 +63,16 @@ struct comp_data {
int32_t *sbuf_w_ptr;
int32_t *sbuf_r_ptr;
int sbuf_avail;
- int sign_extend_s24; /* Set if need to copy sign bit to b24..b31 */
void (* src_func)(struct comp_dev *dev,
struct comp_buffer *source,
struct comp_buffer *sink,
size_t *consumed,
size_t *produced);
+ void (* polyphase_func)(struct src_stage_prm *s);
};
/* Fallback function */
-static void fallback_s32(struct comp_dev *dev, struct comp_buffer *source,
+static void src_fallback(struct comp_dev *dev, struct comp_buffer *source,
struct comp_buffer *sink, size_t *bytes_read, size_t *bytes_written)
{
*bytes_read = 0;
@@ -84,101 +84,110 @@ static void src_2s_s32_default(struct comp_dev *dev,
struct comp_buffer *source, struct comp_buffer *sink,
size_t *bytes_read, size_t *bytes_written)
{
- struct polyphase_src *s;
struct src_stage_prm s1;
struct src_stage_prm s2;
- int j;
+ int s1_blk_in;
+ int s1_blk_out;
+ int s2_blk_in;
+ int s2_blk_out;
struct comp_data *cd = comp_get_drvdata(dev);
int32_t *dest = (int32_t *) sink->w_ptr;
int32_t *src = (int32_t *) source->r_ptr;
- int32_t *sbuf_addr = cd->delay_lines;
int32_t *sbuf_end_addr = &cd->delay_lines[cd->param.sbuf_length];
int32_t sbuf_size = cd->param.sbuf_length * sizeof(int32_t);
- const int nch = dev->params.channels;
- const int s1_blk_in = cd->src[0].stage1->blk_in * nch;
- const int s1_blk_out = cd->src[0].stage1->blk_out * nch;
- const int s2_blk_in = cd->src[0].stage2->blk_in * nch;
- const int s2_blk_out = cd->src[0].stage2->blk_out * nch;
+ int nch = dev->params.channels;
int sbuf_free = cd->param.sbuf_length - cd->sbuf_avail;
- int source_check = (source->avail >> 2) - s1_blk_in; /* for int32_t */
- int sink_check = (sink->free >> 2) - s2_blk_out; /* For int32_t */
int n_read = 0;
int n_written = 0;
int n1 = 0;
int n2 = 0;
+ int avail_b = source->avail;
+ int free_b = sink->free;
+ int sz = sizeof(int32_t);
- s1.times = 1;
s1.x_end_addr = source->end_addr;
s1.x_size = source->size;
- s1.x_inc = nch;
s1.y_end_addr = sbuf_end_addr;
s1.y_size = sbuf_size;
- s1.y_inc = nch;
+ s1.state = &cd->src.state1;
+ s1.stage = cd->src.stage1;
+ s1.x_rptr = src;
+ s1.y_wptr = cd->sbuf_w_ptr;
+ s1.nch = nch;
- s2.times = 1;
s2.x_end_addr = sbuf_end_addr;
s2.x_size = sbuf_size;
- s2.x_inc = nch;
s2.y_end_addr = sink->end_addr;
s2.y_size = sink->size;
- s2.y_inc = nch;
+ s2.state = &cd->src.state2;
+ s2.stage = cd->src.stage2;
+ s2.x_rptr = cd->sbuf_r_ptr;
+ s2.y_wptr = dest;
+ s2.nch = nch;
+
- /* 1st stage runs once a long multiplied length block.
- * The stage buffer much be large enough to fit one s1 output block
- * plus one s2 input block plus jitter in s2 consumption.
+ /* Test if 1st stage can be run with default block length to reach
+ * the period length or just under it.
*/
- while ((n1 < cd->param.stage1_times_max)
- && (n_read <= source_check)
- && (sbuf_free >= s1_blk_out)) {
- for (j = 0; j < nch; j++) {
- s = &cd->src[j]; /* Point to src[] for this channel */
- s1.x_rptr = src++;
- s1.y_wptr = cd->sbuf_w_ptr++;
- src_circ_inc_wrap(&src, source->end_addr, source->size);
- src_circ_inc_wrap(&cd->sbuf_w_ptr, sbuf_end_addr, sbuf_size);
- s1.state = &s->state1;
- s1.stage = s->stage1;
- if (cd->sign_extend_s24)
- src_polyphase_stage_cir_s24(&s1);
- else
- src_polyphase_stage_cir(&s1);
-
- }
+ s1.times = cd->param.stage1_times;
+ s1_blk_in = s1.times * cd->src.stage1->blk_in * nch;
+ s1_blk_out = s1.times * cd->src.stage1->blk_out * nch;
+ if ((avail_b >= s1_blk_in * sz) && (sbuf_free >= s1_blk_out)) {
+ cd->polyphase_func(&s1);
+
+ cd->sbuf_w_ptr = s1.y_wptr;
+ cd->sbuf_avail += s1_blk_out;
n_read += s1_blk_in;
+ avail_b -= s1_blk_in * sz;
+ sbuf_free -= s1_blk_out;
+ n1 = s1.times;
+ }
+
+ /* Run one block at time the remaining data for 1st stage. */
+ s1.times = 1;
+ s1_blk_in = cd->src.stage1->blk_in * nch;
+ s1_blk_out = cd->src.stage1->blk_out * nch;
+ while ((n1 < cd->param.stage1_times_max) && (avail_b >= s1_blk_in * sz)
+ && (sbuf_free >= s1_blk_out)) {
+ cd->polyphase_func(&s1);
+
+ cd->sbuf_w_ptr = s1.y_wptr;
cd->sbuf_avail += s1_blk_out;
+ n_read += s1_blk_in;
+ avail_b -= s1_blk_in * sz;
sbuf_free -= s1_blk_out;
- src = s1.x_rptr - nch + 1;
- cd->sbuf_w_ptr = s1.y_wptr - nch + 1;
- src_circ_dec_wrap(&src, source->addr, source->size);
- src_circ_dec_wrap(&cd->sbuf_w_ptr, sbuf_addr, sbuf_size);
- n1++;
+ n1 += s1.times;
+ }
+
+ /* Test if 2nd stage can be run with default block length. */
+ s2.times = cd->param.stage2_times;
+ s2_blk_in = s2.times * cd->src.stage2->blk_in * nch;
+ s2_blk_out = s2.times * cd->src.stage2->blk_out * nch;
+ if ((cd->sbuf_avail >= s2_blk_in) && (free_b >= s2_blk_out * sz)) {
+ cd->polyphase_func(&s2);
+
+ cd->sbuf_r_ptr = s2.x_rptr;
+ cd->sbuf_avail -= s2_blk_in;
+ free_b -= s2_blk_out * sz;
+ n_written += s2_blk_out;
+ n2 = s2.times;
}
- /* 2nd stage runs as many min size blocks as buffers allow */
+
+ /* Run one block at time the remaining 2nd stage output */
+ s2.times = 1;
+ s2_blk_in = cd->src.stage2->blk_in * nch;
+ s2_blk_out = cd->src.stage2->blk_out * nch;
while ((n2 < cd->param.stage2_times_max)
&& (cd->sbuf_avail >= s2_blk_in)
- && (n_written <= sink_check)) {
- for (j = 0; j < nch; j++) {
- s2.x_rptr = cd->sbuf_r_ptr++;
- s2.y_wptr = dest++;
- src_circ_inc_wrap(&cd->sbuf_r_ptr, sbuf_end_addr, sbuf_size);
- src_circ_inc_wrap(&dest, sink->end_addr, sink->size);
- s = &cd->src[j]; /* Point to src[] for this channel */
- s2.state = &s->state2;
- s2.stage = s->stage2;
- if (cd->sign_extend_s24)
- src_polyphase_stage_cir_s24(&s2);
- else
- src_polyphase_stage_cir(&s2);
-
- }
- cd->sbuf_r_ptr = s2.x_rptr - nch + 1;
- dest = s2.y_wptr - nch + 1;
- src_circ_dec_wrap(&cd->sbuf_r_ptr, sbuf_addr, sbuf_size);
- src_circ_dec_wrap(&dest, sink->addr, sink->size);
- n_written += s2_blk_out;
+ && (free_b >= s2_blk_out * sz)) {
+ cd->polyphase_func(&s2);
+
+ cd->sbuf_r_ptr = s2.x_rptr;
cd->sbuf_avail -= s2_blk_in;
- n2++;
+ free_b -= s2_blk_out * sz;
+ n_written += s2_blk_out;
+ n2 += s2.times;
}
*bytes_read = sizeof(int32_t) * n_read;
*bytes_written = sizeof(int32_t) * n_written;
@@ -189,42 +198,27 @@ static void src_1s_s32_default(struct comp_dev *dev,
struct comp_buffer *source, struct comp_buffer *sink,
size_t *bytes_read, size_t *bytes_written)
{
- struct polyphase_src *s;
struct src_stage_prm s1;
- int j;
struct comp_data *cd = comp_get_drvdata(dev);
- int32_t *dest = (int32_t *) sink->w_ptr;
- int32_t *src = (int32_t *) source->r_ptr;
int nch = dev->params.channels;
int n_read = 0;
int n_written = 0;
s1.times = cd->param.stage1_times;
+ s1.x_rptr = (int32_t *) source->r_ptr;
s1.x_end_addr = source->end_addr;
s1.x_size = source->size;
- s1.x_inc = nch;
+ s1.y_wptr = (int32_t *) sink->w_ptr;
s1.y_end_addr = sink->end_addr;
s1.y_size = sink->size;
- s1.y_inc = nch;
- s1.x_rptr = src + nch - 1;
- s1.y_wptr = dest + nch - 1;
-
- for (j = 0; j < nch; j++) {
- s = &cd->src[j]; /* Point to src for this channel */
- s1.x_rptr = src++;
- s1.y_wptr = dest++;
- src_circ_inc_wrap(&src, source->end_addr, source->size);
- src_circ_inc_wrap(&dest, sink->end_addr, sink->size);
- s1.state = &s->state1;
- s1.stage = s->stage1;
- if (cd->sign_extend_s24)
- src_polyphase_stage_cir_s24(&s1);
- else
- src_polyphase_stage_cir(&s1);
-
- n_read += cd->param.blk_in;
- n_written += cd->param.blk_out;
- }
+ s1.state = &cd->src.state1;
+ s1.stage = cd->src.stage1;
+ s1.nch = dev->params.channels;
+
+ cd->polyphase_func(&s1);
+
+ n_read += nch * cd->param.blk_in;
+ n_written += nch * cd->param.blk_out;
*bytes_read = n_read * sizeof(int32_t);
*bytes_written = n_written * sizeof(int32_t);
}
@@ -271,7 +265,6 @@ static struct comp_dev *src_new(struct sof_ipc_comp *comp)
struct sof_ipc_comp_src *src;
struct sof_ipc_comp_src *ipc_src = (struct sof_ipc_comp_src *) comp;
struct comp_data *cd;
- int i;
trace_src("new");
@@ -299,8 +292,8 @@ static struct comp_dev *src_new(struct sof_ipc_comp *comp)
cd->delay_lines = NULL;
cd->src_func = src_2s_s32_default;
- for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
- src_polyphase_reset(&cd->src[i]);
+ cd->polyphase_func = src_polyphase_stage_cir;
+ src_polyphase_reset(&cd->src);
dev->state = COMP_STATE_READY;
return dev;
@@ -334,10 +327,8 @@ static int src_params(struct comp_dev *dev)
uint32_t sink_rate;
int32_t *buffer_start;
int n = 0;
- int i;
int err;
int frames_is_for_source;
- int nch;
int q;
trace_src("par");
@@ -345,10 +336,10 @@ static int src_params(struct comp_dev *dev)
/* SRC supports S24_4LE and S32_LE formats */
switch (config->frame_fmt) {
case SOF_IPC_FRAME_S24_4LE:
- cd->sign_extend_s24 = 1;
+ cd->polyphase_func = src_polyphase_stage_cir_s24;
break;
case SOF_IPC_FRAME_S32_LE:
- cd->sign_extend_s24 = 0;
+ cd->polyphase_func = src_polyphase_stage_cir;
break;
default:
trace_src_error("sr0");
@@ -407,11 +398,7 @@ static int src_params(struct comp_dev *dev)
buffer_start = cd->delay_lines + cd->param.sbuf_length;
/* Initize SRC for actual sample rate */
- nch = MIN(params->channels, PLATFORM_MAX_CHANNELS);
- for (i = 0; i < nch; i++) {
- n = src_polyphase_init(&cd->src[i], &cd->param, buffer_start);
- buffer_start += cd->param.single_src;
- }
+ n = src_polyphase_init(&cd->src, &cd->param, buffer_start);
/* Reset stage buffer */
cd->sbuf_r_ptr = cd->delay_lines;
@@ -434,7 +421,7 @@ static int src_params(struct comp_dev *dev)
* muted if copy() is run.
*/
trace_src("SFa");
- cd->src_func = fallback_s32;
+ cd->src_func = src_fallback;
return -EINVAL;
break;
}
@@ -532,7 +519,6 @@ static int src_copy(struct comp_dev *dev)
/* Run SRC function if buffers avail and free allow */
if (((int) source->avail >= need_source) && ((int) sink->free >= need_sink)) {
- /* Run src */
cd->src_func(dev, source, sink, &consumed, &produced);
/* Calc new free and available if data was processed. These
@@ -561,14 +547,12 @@ static int src_preload(struct comp_dev *dev)
static int src_reset(struct comp_dev *dev)
{
- int i;
struct comp_data *cd = comp_get_drvdata(dev);
trace_src("SRe");
cd->src_func = src_2s_s32_default;
- for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
- src_polyphase_reset(&cd->src[i]);
+ src_polyphase_reset(&cd->src);
comp_set_state(dev, COMP_CMD_RESET);
return 0;
diff --git a/src/audio/src_core.c b/src/audio/src_core.c
index 4ee2efd..080256c 100644
--- a/src/audio/src_core.c
+++ b/src/audio/src_core.c
@@ -45,12 +45,20 @@
#include "src_core.h"
#include "src_config.h"
+#define trace_src(__e) trace_event(TRACE_CLASS_SRC, __e)
+#define tracev_src(__e) tracev_event(TRACE_CLASS_SRC, __e)
+#define trace_src_error(__e) trace_error(TRACE_CLASS_SRC, __e)
+
/* TODO: These should be defined somewhere else. */
#define SOF_RATES_LENGTH 15
int sof_rates[SOF_RATES_LENGTH] = {8000, 11025, 12000, 16000, 18900,
22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000, 176400,
192000};
+/* The FIR maximum lenghts are per channel so need to multiply them */
+#define MAX_FIR_DELAY_SIZE_XNCH (PLATFORM_MAX_CHANNELS * MAX_FIR_DELAY_SIZE)
+#define MAX_OUT_DELAY_SIZE_XNCH (PLATFORM_MAX_CHANNELS * MAX_OUT_DELAY_SIZE)
+
/* Calculate ceil() for integer division */
int src_ceil_divide(int a, int b)
{
@@ -131,6 +139,13 @@ int src_buffer_lengths(struct src_param *a, int fs_in, int fs_out, int nch,
int num;
int frames2;
+ if (nch > PLATFORM_MAX_CHANNELS) {
+ trace_src_error("che");
+ tracev_value(nch);
+ return -EINVAL;
+ }
+
+ a->nch = nch;
a->idx_in = src_find_fs(src_in_fs, NUM_IN_FS, fs_in);
a->idx_out = src_find_fs(src_out_fs, NUM_OUT_FS, fs_out);
@@ -146,8 +161,8 @@ int src_buffer_lengths(struct src_param *a, int fs_in, int fs_out, int nch,
stage1 = src_table1[a->idx_out][a->idx_in];
stage2 = src_table2[a->idx_out][a->idx_in];
- a->fir_s1 = src_fir_delay_length(stage1);
- a->out_s1 = src_out_delay_length(stage1);
+ a->fir_s1 = nch * src_fir_delay_length(stage1);
+ a->out_s1 = nch * src_out_delay_length(stage1);
/* Find out how many additional times the SRC can be executed
while having block size less or equal to max_frames.
@@ -191,8 +206,8 @@ int src_buffer_lengths(struct src_param *a, int fs_in, int fs_out, int nch,
a->stage2_times_max = 0;
a->sbuf_length = 0;
} else {
- a->fir_s2 = src_fir_delay_length(stage2);
- a->out_s2 = src_out_delay_length(stage2);
+ a->fir_s2 = nch * src_fir_delay_length(stage2);
+ a->out_s2 = nch * src_out_delay_length(stage2);
/* 2x is an empirically tested length. Since the sink buffer
* capability to receive samples varies a shorter stage 2 output
* block will create a peak in internal buffer usage.
@@ -200,8 +215,8 @@ int src_buffer_lengths(struct src_param *a, int fs_in, int fs_out, int nch,
a->sbuf_length = 2 * nch * stage1->blk_out * a->stage1_times_max;
}
- a->single_src = a->fir_s1 + a->fir_s2 + a->out_s1 + a->out_s2;
- a->total = a->sbuf_length + nch * a->single_src;
+ a->src_multich = a->fir_s1 + a->fir_s2 + a->out_s1 + a->out_s2;
+ a->total = a->sbuf_length + a->src_multich;
return 0;
}
@@ -212,8 +227,6 @@ static void src_state_reset(struct src_state *state)
state->fir_delay_size = 0;
state->out_delay_size = 0;
state->fir_wi = 0;
- state->fir_ri = 0;
- state->out_wi = 0;
state->out_ri = 0;
}
@@ -229,17 +242,8 @@ static int init_stages(
src->number_of_stages = n;
src->stage1 = stage1;
src->stage2 = stage2;
- src->blk_in = p->blk_in;
- src->blk_out = p->blk_out;
- if (n == 1) {
- src->stage1_times = p->stage1_times;
- src->stage2_times = 0;
- if (stage1->blk_out == 0)
- return -EINVAL;
- } else {
- src->stage1_times = p->stage1_times;
- src->stage2_times = p->stage2_times;
- }
+ if ((n == 1) && (stage1->blk_out == 0))
+ return -EINVAL;
/* Delay line sizes */
src->state1.fir_delay_size = p->fir_s1;
@@ -262,10 +266,10 @@ static int init_stages(
}
/* Check the sizes are less than MAX */
- if ((src->state1.fir_delay_size > MAX_FIR_DELAY_SIZE)
- || (src->state1.out_delay_size > MAX_OUT_DELAY_SIZE)
- || (src->state2.fir_delay_size > MAX_FIR_DELAY_SIZE)
- || (src->state2.out_delay_size > MAX_OUT_DELAY_SIZE)) {
+ if ((src->state1.fir_delay_size > MAX_FIR_DELAY_SIZE_XNCH)
+ || (src->state1.out_delay_size > MAX_OUT_DELAY_SIZE_XNCH)
+ || (src->state2.fir_delay_size > MAX_FIR_DELAY_SIZE_XNCH)
+ || (src->state2.out_delay_size > MAX_OUT_DELAY_SIZE_XNCH)) {
src->state1.fir_delay = NULL;
src->state1.out_delay = NULL;
src->state2.fir_delay = NULL;
@@ -279,12 +283,7 @@ static int init_stages(
void src_polyphase_reset(struct polyphase_src *src)
{
- src->mute = 0;
src->number_of_stages = 0;
- src->blk_in = 0;
- src->blk_out = 0;
- src->stage1_times = 0;
- src->stage2_times = 0;
src->stage1 = NULL;
src->stage2 = NULL;
src_state_reset(&src->state1);
@@ -294,14 +293,12 @@ void src_polyphase_reset(struct polyphase_src *src)
int src_polyphase_init(struct polyphase_src *src, struct src_param *p,
int32_t *delay_lines_start)
{
- int n_stages;
- int ret;
struct src_stage *stage1;
struct src_stage *stage2;
+ int n_stages;
+ int ret;
if ((p->idx_in < 0) || (p->idx_out < 0)) {
- src->blk_in = p->blk_in;
- src->blk_out = p->blk_out;
return -EINVAL;
}
@@ -335,109 +332,157 @@ int src_polyphase_init(struct polyphase_src *src, struct src_param *p,
#if SRC_SHORT == 1
/* Calculate a FIR filter part that does not need circular modification */
-static inline void fir_part(int64_t *y, int ntaps, const int16_t c[], int *ic,
- int32_t d[], int *id)
+
+static inline void fir_part(int64_t y[], int *id, int *ic,
+ const int32_t data[], const int16_t coef[], int nch_x_taps, int nch)
{
+ int64_t tap0;
+ int64_t tap1;
int n;
int64_t a = 0;
+ int64_t b = 0;
+ int c = *ic;
+ int d = *id;
+ int d_end = d - nch_x_taps;
/* Data is Q1.31, coef is Q1.15, product is Q2.46 */
- for (n = 0; n < (ntaps >> 1); n++) {
- a += (int64_t) c[*ic] * d[*id]
- + (int64_t) c[*ic + 1] * d[*id - 1];
- *ic += 2;
- *id -= 2;
+ if (nch == 2) {
+ for (n = 0; n < (nch_x_taps >> 2); n++) {
+ tap0 = coef[c++];
+ tap1 = coef[c++];
+ b += data[d--] * tap0;
+ a += data[d--] * tap0;
+ b += data[d--] * tap1;
+ a += data[d--] * tap1;
+ }
+ if (d > d_end) {
+ tap0 = coef[c++];
+ b += data[d--] * tap0;
+ a += data[d--] * tap0;
+ }
+ y[1] += b;
+ y[0] += a;
+ } else {
+ while (d > d_end) {
+ tap0 = coef[c++];
+ for (n = nch - 1; n >= 0; n--)
+ y[n] += data[d--] * tap0;
+ }
}
- if (ntaps & 1)
- a += (int64_t) c[(*ic)++] * d[(*id)--];
-
- *y += a;
+ *ic = c;
+ *id = d;
}
+
#else
-/* Calculate a FIR filter part that does not need circular modification */
-static inline void fir_part(int64_t *y, int ntaps, const int32_t c[], int *ic,
- int32_t d[], int *id)
+static inline void fir_part(int64_t y[], int *id, int *ic,
+ const int32_t data[], const int32_t coef[], int nch_x_taps, int nch)
{
+ int64_t tap0;
+ int64_t tap1;
int n;
int64_t a = 0;
-
- /* Data is Q8.24, coef is Q1.23, product is Q9.47 */
- for (n = 0; n < (ntaps >> 1); n++) {
- a += (int64_t) c[*ic] * d[*id]
- + (int64_t) c[*ic + 1] * d[*id - 1];
- *ic += 2;
- *id -= 2;
+ int64_t b = 0;
+ int c = *ic;
+ int d = *id;
+ int d_end = d - nch_x_taps;
+
+ /* Data is Q1.31, coef is Q1.23, product is Q2.54 */
+ if (nch == 2) {
+ for (n = 0; n < (nch_x_taps >> 2); n++) {
+ tap0 = coef[c++];
+ tap1 = coef[c++];
+ b += data[d--] * tap0;
+ a += data[d--] * tap0;
+ b += data[d--] * tap1;
+ a += data[d--] * tap1;
+ }
+ if (d > d_end) {
+ tap0 = coef[c++];
+ b += data[d--] * tap0;
+ a += data[d--] * tap0;
+ }
+ y[1] += b;
+ y[0] += a;
+ } else {
+ while (d > d_end) {
+ tap0 = coef[c++];
+ for (n = nch - 1; n >= 0; n--)
+ y[n] += data[d--] * tap0;
+ }
}
- if (ntaps & 1)
- a += (int64_t) c[(*ic)++] * d[(*id)--];
-
- *y += a;
+ *ic = c;
+ *id = d;
}
+
#endif
#if SRC_SHORT == 1
-static inline int32_t fir_filter(
- struct src_state *fir, const int16_t coefs[],
- int *coefi, int filter_length, int shift)
+static void fir_filter(int ri0, int *ci, int wi0, int32_t in_delay[],
+ int32_t out_delay[], const int16_t coefs[], int dsm1, int taps,
+ int shift, int nch)
{
- int64_t y = 0;
- int n1;
int n2;
-
- n1 = fir->fir_ri + 1;
- if (n1 > filter_length) {
- /* No need to un-wrap fir read index, make sure fir_fi
- * is ge 0 after FIR computation.
- */
- fir_part(&y, filter_length, coefs, coefi, fir->fir_delay,
- &fir->fir_ri);
+ int i;
+ int64_t y[PLATFORM_MAX_CHANNELS];
+ int ri = ri0;
+ int wi = wi0;
+ int n1 = ri0 + 1; /* Convert to number of sequential frames */
+ int qshift = 15 + shift; /* Q2.46 -> Q2.31 */
+ int32_t rnd = 1 << (qshift - 1); /* Half LSB */
+ int nch_x_taps = nch * taps;
+
+ /* Initialize to half LSB for rounding */
+ for (i = 0; i < nch; i++)
+ y[i] = rnd;
+
+ if (n1 >= nch_x_taps) {
+ fir_part(y, &ri, ci, in_delay, coefs, nch_x_taps, nch);
} else {
- n2 = filter_length - n1;
- /* Part 1, loop n1 times, fir_ri becomes -1 */
- fir_part(&y, n1, coefs, coefi, fir->fir_delay, &fir->fir_ri);
-
- /* Part 2, unwrap fir_ri, continue rest of filter */
- fir->fir_ri = fir->fir_delay_size - 1;
- fir_part(&y, n2, coefs, coefi, fir->fir_delay, &fir->fir_ri);
+ n2 = nch_x_taps - n1;
+ fir_part(y, &ri, ci, in_delay, coefs, n1, nch);
+ ri = dsm1;
+ fir_part(y, &ri, ci, in_delay, coefs, n2, nch);
}
- /* Q2.46 -> Q2.31, saturate to Q1.31 */
- y = y >> (15 + shift);
- return(int32_t) sat_int32(y);
+ for (i = 0; i < nch; i++)
+ out_delay[wi++] = sat_int32(y[i] >> qshift);
}
#else
-static inline int32_t fir_filter(
- struct src_state *fir, const int32_t coefs[],
- int *coefi, int filter_length, int shift)
+static void fir_filter(int ri0, int *ci, int wi0, int32_t in_delay[],
+ int32_t out_delay[], const int32_t coefs[], int dsm1, int taps,
+ int shift, int nch)
{
- int64_t y = 0;
- int n1;
int n2;
-
- n1 = fir->fir_ri + 1;
- if (n1 > filter_length) {
- /* No need to un-wrap fir read index, make sure fir_fi
- * is ge 0 after FIR computation.
- */
- fir_part(&y, filter_length, coefs, coefi, fir->fir_delay,
- &fir->fir_ri);
+ int i;
+ int64_t y[PLATFORM_MAX_CHANNELS];
+ int ri = ri0;
+ int wi = wi0;
+ int n1 = ri0 + 1; /* Convert to number of sequential frames */
+ int qshift = 23 + shift; /* Q2.54 -> Q2.31 */
+ int32_t rnd = 1 << (qshift - 1); /* Half LSB */
+ int nch_x_taps = nch * taps;
+
+ /* Initialize to half LSB for rounding */
+ for (i = 0; i < nch; i++)
+ y[i] = rnd;
+
+ if (n1 >= nch_x_taps) {
+ fir_part(y, &ri, ci, in_delay, coefs, nch_x_taps, nch);
} else {
- n2 = filter_length - n1;
- /* Part 1, loop n1 times, fir_ri becomes -1 */
- fir_part(&y, n1, coefs, coefi, fir->fir_delay, &fir->fir_ri);
-
- /* Part 2, unwrap fir_ri, continue rest of filter */
- fir->fir_ri = fir->fir_delay_size - 1;
- fir_part(&y, n2, coefs, coefi, fir->fir_delay, &fir->fir_ri);
+ n2 = nch_x_taps - n1;
+ fir_part(y, &ri, ci, in_delay, coefs, n1, nch);
+ ri = dsm1;
+ fir_part(y, &ri, ci, in_delay, coefs, n2, nch);
}
- /* Q9.47 -> Q9.24, saturate to Q8.24 */
- y = y >> (23 + shift);
- return(int32_t) sat_int32(y);
+ for (i = 0; i < nch; i++)
+ out_delay[wi++] = sat_int32(y[i] >> qshift);
+
}
+
#endif
void src_polyphase_stage_cir(struct src_stage_prm * s)
@@ -447,29 +492,42 @@ void src_polyphase_stage_cir(struct src_stage_prm * s)
int n;
int m;
int f;
- int c;
- int r;
+ int ci;
+ int ri;
int n_wrap_fir;
int n_wrap_buf;
int n_wrap_min;
int n_min;
- int32_t z;
+ int wi;
+ const void *coef = cfg->coefs;
+ int32_t *in_delay = fir->fir_delay;
+ int32_t *out_delay = fir->out_delay;
+ int dsm1 = fir->fir_delay_size - 1;
+ int shift = cfg->shift;
+ int nch = s->nch;
+ int rewind = -nch * (cfg->blk_in
+ + (cfg->num_of_subfilters - 1) * cfg->idm) + nch - 1;
+ int nch_x_idm = cfg->idm * nch;
+ int nch_x_odm = cfg->odm * nch;
+ size_t sz = sizeof(int32_t);
+ int blk_in_bytes = nch * cfg->blk_in * sz;
+ int blk_out_bytes = nch * cfg->num_of_subfilters * sz;
+
for (n = 0; n < s->times; n++) {
/* Input data */
- m = s->x_inc * cfg->blk_in;
+ m = blk_in_bytes;
while (m > 0) {
- n_wrap_fir = (fir->fir_delay_size - fir->fir_wi)
- * s->x_inc;
+ n_wrap_fir = (fir->fir_delay_size - fir->fir_wi) * sz;
n_wrap_buf = s->x_end_addr - s->x_rptr;
n_wrap_min = (n_wrap_fir < n_wrap_buf)
? n_wrap_fir : n_wrap_buf;
n_min = (m < n_wrap_min) ? m : n_wrap_min;
while (n_min > 0) {
fir->fir_delay[fir->fir_wi++] = *s->x_rptr;
- s->x_rptr += s->x_inc;
- n_min -= s->x_inc;
- m -= s->x_inc;
+ s->x_rptr++;
+ n_min -= sz;
+ m -= sz;
}
/* Check for wrap */
src_circ_inc_wrap(&s->x_rptr, s->x_end_addr, s->x_size);
@@ -478,41 +536,38 @@ void src_polyphase_stage_cir(struct src_stage_prm * s)
}
/* Filter */
- c = 0;
- r = fir->fir_wi - cfg->blk_in
- - (cfg->num_of_subfilters - 1) * cfg->idm;
- if (r < 0)
- r += fir->fir_delay_size;
+ ci = 0; /* Reset to 1st coefficient */
+ ri = fir->fir_wi + rewind; /* Newest data for last subfilter */
+ if (ri < 0)
+ ri += fir->fir_delay_size;
- fir->out_wi = fir->out_ri;
+ wi = fir->out_ri;
for (f = 0; f < cfg->num_of_subfilters; f++) {
- fir->fir_ri = r;
- z = fir_filter(fir, cfg->coefs, &c,
- cfg->subfilter_length, cfg->shift);
- r += cfg->idm;
- if (r >= fir->fir_delay_size)
- r -= fir->fir_delay_size;
-
- fir->out_delay[fir->out_wi] = z;
- fir->out_wi += cfg->odm;
- if (fir->out_wi >= fir->out_delay_size)
- fir->out_wi -= fir->out_delay_size;
+ fir_filter(ri, &ci, wi, in_delay, out_delay, coef,
+ dsm1, cfg->subfilter_length, shift, nch);
+
+ wi += nch_x_odm;
+ if (wi >= fir->out_delay_size)
+ wi -= fir->out_delay_size;
+
+ ri += nch_x_idm; /* Next sub-filter start */
+ if (ri >= fir->fir_delay_size)
+ ri -= fir->fir_delay_size;
}
/* Output */
- m = s->y_inc * cfg->num_of_subfilters;
+ m = blk_out_bytes;
while (m > 0) {
- n_wrap_fir = (fir->out_delay_size - fir->out_ri)
- * s->y_inc;
+ n_wrap_fir = (fir->out_delay_size - fir->out_ri) * sz;
n_wrap_buf = s->y_end_addr - s->y_wptr;
n_wrap_min = (n_wrap_fir < n_wrap_buf)
? n_wrap_fir : n_wrap_buf;
n_min = (m < n_wrap_min) ? m : n_wrap_min;
while (n_min > 0) {
*s->y_wptr = fir->out_delay[fir->out_ri++];
- s->y_wptr += s->y_inc;
- n_min -= s->y_inc;
- m -= s->y_inc;
+ s->y_wptr++;
+ n_min -= sz;
+ m -= sz;
}
/* Check wrap */
src_circ_inc_wrap(&s->y_wptr, s->y_end_addr, s->y_size);
@@ -522,38 +577,48 @@ void src_polyphase_stage_cir(struct src_stage_prm * s)
}
}
-void src_polyphase_stage_cir_s24(struct src_stage_prm * s)
+void src_polyphase_stage_cir_s24(struct src_stage_prm *s)
{
struct src_state *fir = s->state;
struct src_stage *cfg = s->stage;
int n;
int m;
int f;
- int c;
- int r;
+ int ci;
+ int ri;
int n_wrap_fir;
int n_wrap_buf;
int n_wrap_min;
int n_min;
- int32_t z;
- int32_t se;
+ int wi;
+ const void *coef = cfg->coefs;
+ int32_t *in_delay = fir->fir_delay;
+ int32_t *out_delay = fir->out_delay;
+ int dsm1 = fir->fir_delay_size - 1;
+ int shift = cfg->shift;
+ int nch = s->nch;
+ int rewind = -nch * (cfg->blk_in
+ + (cfg->num_of_subfilters - 1) * cfg->idm) + nch - 1;
+ int nch_x_idm = cfg->idm * nch;
+ int nch_x_odm = cfg->odm * nch;
+ size_t sz = sizeof(int32_t);
+ int blk_in_bytes = nch * cfg->blk_in * sz;
+ int blk_out_bytes = nch * cfg->num_of_subfilters * sz;
for (n = 0; n < s->times; n++) {
/* Input data */
- m = s->x_inc * cfg->blk_in;
+ m = blk_in_bytes;
while (m > 0) {
- n_wrap_fir = (fir->fir_delay_size - fir->fir_wi)
- * s->x_inc;
+ n_wrap_fir = (fir->fir_delay_size - fir->fir_wi) * sz;
n_wrap_buf = s->x_end_addr - s->x_rptr;
n_wrap_min = (n_wrap_fir < n_wrap_buf)
? n_wrap_fir : n_wrap_buf;
n_min = (m < n_wrap_min) ? m : n_wrap_min;
while (n_min > 0) {
- se = *s->x_rptr << 8;
- fir->fir_delay[fir->fir_wi++] = se >> 8;
- s->x_rptr += s->x_inc;
- n_min -= s->x_inc;
- m -= s->x_inc;
+ fir->fir_delay[fir->fir_wi++] = *s->x_rptr << 8;
+ s->x_rptr++;
+ n_min -= sz;
+ m -= sz;
}
/* Check for wrap */
src_circ_inc_wrap(&s->x_rptr, s->x_end_addr, s->x_size);
@@ -562,41 +627,38 @@ void src_polyphase_stage_cir_s24(struct src_stage_prm * s)
}
/* Filter */
- c = 0;
- r = fir->fir_wi - cfg->blk_in
- - (cfg->num_of_subfilters - 1) * cfg->idm;
- if (r < 0)
- r += fir->fir_delay_size;
+ ci = 0; /* Reset to 1st coefficient */
+ ri = fir->fir_wi + rewind; /* Newest data for last subfilter */
+ if (ri < 0)
+ ri += fir->fir_delay_size;
- fir->out_wi = fir->out_ri;
+ wi = fir->out_ri;
for (f = 0; f < cfg->num_of_subfilters; f++) {
- fir->fir_ri = r;
- z = fir_filter(fir, cfg->coefs, &c,
- cfg->subfilter_length, cfg->shift);
- r += cfg->idm;
- if (r >= fir->fir_delay_size)
- r -= fir->fir_delay_size;
-
- fir->out_delay[fir->out_wi] = z;
- fir->out_wi += cfg->odm;
- if (fir->out_wi >= fir->out_delay_size)
- fir->out_wi -= fir->out_delay_size;
+ fir_filter(ri, &ci, wi, in_delay, out_delay, coef,
+ dsm1, cfg->subfilter_length, shift, nch);
+
+ wi += nch_x_odm;
+ if (wi >= fir->out_delay_size)
+ wi -= fir->out_delay_size;
+
+ ri += nch_x_idm; /* Next sub-filter start */
+ if (ri >= fir->fir_delay_size)
+ ri -= fir->fir_delay_size;
}
/* Output */
- m = s->y_inc * cfg->num_of_subfilters;
+ m = blk_out_bytes;
while (m > 0) {
- n_wrap_fir = (fir->out_delay_size - fir->out_ri)
- * s->y_inc;
+ n_wrap_fir = (fir->out_delay_size - fir->out_ri) * sz;
n_wrap_buf = s->y_end_addr - s->y_wptr;
n_wrap_min = (n_wrap_fir < n_wrap_buf)
? n_wrap_fir : n_wrap_buf;
n_min = (m < n_wrap_min) ? m : n_wrap_min;
while (n_min > 0) {
- *s->y_wptr = fir->out_delay[fir->out_ri++];
- s->y_wptr += s->y_inc;
- n_min -= s->y_inc;
- m -= s->y_inc;
+ *s->y_wptr = fir->out_delay[fir->out_ri++] >> 8;
+ s->y_wptr++;
+ n_min -= sz;
+ m -= sz;
}
/* Check wrap */
src_circ_inc_wrap(&s->y_wptr, s->y_end_addr, s->y_size);
@@ -604,47 +666,5 @@ void src_polyphase_stage_cir_s24(struct src_stage_prm * s)
fir->out_ri = 0;
}
}
-}
-
-#ifdef MODULE_TEST
-
-void src_print_info(struct polyphase_src * src)
-{
-
- int n1;
- int n2;
-
- n1 = src->stage1->filter_length;
- n2 = src->stage2->filter_length;
- printf("SRC stages %d\n", src->number_of_stages);
- printf("SRC input blk %d\n", src->blk_in);
- printf("SRC output blk %d\n", src->blk_out);
- printf("SRC stage1 %d times\n", src->stage1_times);
- printf("SRC stage2 %d times\n", src->stage2_times);
-
- printf("SRC1 filter length %d\n", n1);
- printf("SRC1 subfilter length %d\n", src->stage1->subfilter_length);
- printf("SRC1 number of subfilters %d\n",
- src->stage1->num_of_subfilters);
- printf("SRC1 idm %d\n", src->stage1->idm);
- printf("SRC1 odm %d\n", src->stage1->odm);
- printf("SRC1 input blk %d\n", src->stage1->blk_in);
- printf("SRC1 output blk %d\n", src->stage1->blk_out);
- printf("SRC1 halfband %d\n", src->stage1->halfband);
- printf("SRC1 FIR delay %d\n", src->state1.fir_delay_size);
- printf("SRC1 out delay %d\n", src->state1.out_delay_size);
-
- printf("SRC2 filter length %d\n", n2);
- printf("SRC2 subfilter length %d\n", src->stage2->subfilter_length);
- printf("SRC2 number of subfilters %d\n",
- src->stage2->num_of_subfilters);
- printf("SRC2 idm %d\n", src->stage2->idm);
- printf("SRC2 odm %d\n", src->stage2->odm);
- printf("SRC2 input blk %d\n", src->stage2->blk_in);
- printf("SRC2 output blk %d\n", src->stage2->blk_out);
- printf("SRC2 halfband %d\n", src->stage2->halfband);
- printf("SRC2 FIR delay %d\n", src->state2.fir_delay_size);
- printf("SRC2 out delay %d\n", src->state2.out_delay_size);
}
-#endif
diff --git a/src/audio/src_core.h b/src/audio/src_core.h
index 3859e6f..3ea6028 100644
--- a/src/audio/src_core.h
+++ b/src/audio/src_core.h
@@ -41,7 +41,7 @@ struct src_param {
int out_s1;
int out_s2;
int sbuf_length;
- int single_src;
+ int src_multich;
int total;
int blk_in;
int blk_out;
@@ -51,6 +51,7 @@ struct src_param {
int stage2_times_max;
int idx_in;
int idx_out;
+ int nch;
};
struct src_stage {
@@ -70,20 +71,13 @@ struct src_state {
int fir_delay_size;
int out_delay_size;
int fir_wi;
- int fir_ri;
- int out_wi;
int out_ri;
int32_t *fir_delay;
int32_t *out_delay;
};
struct polyphase_src {
- int mute;
int number_of_stages;
- int blk_in;
- int blk_out;
- int stage1_times;
- int stage2_times;
struct src_stage *stage1;
struct src_stage *stage2;
struct src_state state1;
@@ -91,15 +85,14 @@ struct polyphase_src {
};
struct src_stage_prm {
+ int nch;
int times;
int32_t *x_rptr;
int32_t *x_end_addr;
size_t x_size;
- int x_inc;
int32_t *y_wptr;
int32_t *y_end_addr;
size_t y_size;
- int y_inc;
struct src_state *state;
struct src_stage *stage;
};
@@ -116,31 +109,6 @@ static inline void src_circ_dec_wrap(int32_t **ptr, int32_t *addr, size_t size)
*ptr = (int32_t *) ((size_t) * ptr + size);
}
-static inline void src_polyphase_mute(struct polyphase_src *src)
-{
- src->mute = 1;
-}
-
-static inline void src_polyphase_unmute(struct polyphase_src *src)
-{
- src->mute = 0;
-}
-
-static inline int src_polyphase_getmute(struct polyphase_src *src)
-{
- return src->mute;
-}
-
-static inline int src_polyphase_get_blk_in(struct polyphase_src *src)
-{
- return src->blk_in;
-}
-
-static inline int src_polyphase_get_blk_out(struct polyphase_src *src)
-{
- return src->blk_out;
-}
-
void src_polyphase_reset(struct polyphase_src *src);
int src_polyphase_init(struct polyphase_src *src, struct src_param *p,
@@ -162,8 +130,4 @@ int32_t src_output_rates(void);
int src_ceil_divide(int a, int b);
-#ifdef MODULE_TEST
-void src_print_info(struct polyphase_src *src);
-#endif
-
#endif
--
2.11.0
1
0

[Sound-open-firmware] [PATCH 2/2] Move DMA tracing intialization calling.
by yan.wangï¼ linux.intel.com 20 Oct '17
by yan.wangï¼ linux.intel.com 20 Oct '17
20 Oct '17
From: Yan Wang <yan.wang(a)linux.intel.com>
Move it from ipc handler into platform_init().
Signed-off-by: Yan Wang <yan.wang(a)linux.intel.com>
---
src/ipc/intel-ipc.c | 7 -------
src/platform/baytrail/platform.c | 4 ++++
2 files changed, 4 insertions(+), 7 deletions(-)
diff --git a/src/ipc/intel-ipc.c b/src/ipc/intel-ipc.c
index f6d88ef..902e5a6 100644
--- a/src/ipc/intel-ipc.c
+++ b/src/ipc/intel-ipc.c
@@ -583,13 +583,6 @@ static int ipc_dma_trace_config(uint32_t header)
trace_ipc_error("DA1");
- /* Initialize DMA for Trace*/
- err = dma_trace_init(&_ipc->dmat);
- if (err < 0) {
- trace_ipc_error("eIP");
- goto error;
- }
-
/* use DMA to read in compressed page table ringbuffer from host */
err = get_page_descriptors(iipc, ¶ms->buffer);
if (err < 0) {
diff --git a/src/platform/baytrail/platform.c b/src/platform/baytrail/platform.c
index b701196..61596bb 100644
--- a/src/platform/baytrail/platform.c
+++ b/src/platform/baytrail/platform.c
@@ -46,6 +46,7 @@
#include <reef/clock.h>
#include <reef/ipc.h>
#include <reef/trace.h>
+#include <reef/dma-trace.h>
#include <reef/audio/component.h>
#include <config.h>
#include <string.h>
@@ -296,6 +297,9 @@ int platform_init(struct reef *reef)
trace_point(TRACE_BOOT_PLATFORM_IPC);
ipc_init(reef);
+ /* Initialize DMA for Trace*/
+ dma_trace_init(&reef->ipc->dmat);
+
/* init DMACs */
trace_point(TRACE_BOOT_PLATFORM_DMA);
dmac0 = dma_get(DMA_ID_DMAC0);
--
2.7.4
1
0

[Sound-open-firmware] [PATCH 1/2] Move DMA tracing implementaion from src/audio to src/lib.
by yan.wangï¼ linux.intel.com 20 Oct '17
by yan.wangï¼ linux.intel.com 20 Oct '17
20 Oct '17
From: Yan Wang <yan.wang(a)linux.intel.com>
1. Move source and header file.
2. Change src/lib/Makefile.am and src/audio/Makefile.am.
3. Chnage header file path.
Signed-off-by: Yan Wang <yan.wang(a)linux.intel.com>
---
src/audio/Makefile.am | 1 -
src/include/reef/{audio => }/dma-trace.h | 0
src/include/reef/ipc.h | 2 +-
src/lib/Makefile.am | 1 +
src/{audio => lib}/dma-trace.c | 3 +--
src/lib/trace.c | 2 +-
6 files changed, 4 insertions(+), 5 deletions(-)
rename src/include/reef/{audio => }/dma-trace.h (100%)
rename src/{audio => lib}/dma-trace.c (98%)
diff --git a/src/audio/Makefile.am b/src/audio/Makefile.am
index 7ffe01f..285422e 100644
--- a/src/audio/Makefile.am
+++ b/src/audio/Makefile.am
@@ -17,7 +17,6 @@ libaudio_a_SOURCES = \
pipeline.c \
pipeline_static.c \
component.c \
- dma-trace.c \
buffer.c
libaudio_a_CFLAGS = \
diff --git a/src/include/reef/audio/dma-trace.h b/src/include/reef/dma-trace.h
similarity index 100%
rename from src/include/reef/audio/dma-trace.h
rename to src/include/reef/dma-trace.h
diff --git a/src/include/reef/ipc.h b/src/include/reef/ipc.h
index a552626..472aca8 100644
--- a/src/include/reef/ipc.h
+++ b/src/include/reef/ipc.h
@@ -40,7 +40,7 @@
#include <uapi/ipc.h>
#include <reef/audio/pipeline.h>
#include <reef/audio/component.h>
-#include <reef/audio/dma-trace.h>
+#include <reef/dma-trace.h>
struct reef;
struct dai_config;
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index acdbd85..b4521df 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -6,6 +6,7 @@ libcore_a_SOURCES = \
work.c \
notifier.c \
trace.c \
+ dma-trace.c \
schedule.c
libcore_a_CFLAGS = \
diff --git a/src/audio/dma-trace.c b/src/lib/dma-trace.c
similarity index 98%
rename from src/audio/dma-trace.c
rename to src/lib/dma-trace.c
index b0267fa..5885037 100644
--- a/src/audio/dma-trace.c
+++ b/src/lib/dma-trace.c
@@ -29,7 +29,7 @@
*/
#include <reef/trace.h>
-#include <reef/audio/dma-trace.h>
+#include <reef/dma-trace.h>
#include <reef/ipc.h>
#include <reef/reef.h>
#include <reef/alloc.h>
@@ -172,7 +172,6 @@ int dma_trace_enable(struct dma_trace_data *d)
return -ENODEV;
}
- /* TODO: fix crash when enabled */
d->enabled = 1;
work_schedule_default(&d->dmat_work, DMA_TRACE_US);
return 0;
diff --git a/src/lib/trace.c b/src/lib/trace.c
index c0abf7c..eec93b5 100644
--- a/src/lib/trace.c
+++ b/src/lib/trace.c
@@ -34,7 +34,7 @@
#include <arch/cache.h>
#include <platform/timer.h>
#include <reef/lock.h>
-#include <reef/audio/dma-trace.h>
+#include <reef/dma-trace.h>
#include <stdint.h>
struct trace {
--
2.7.4
1
0

[Sound-open-firmware] [PATCH v5] volume: fix for DC offset and handling of sign extension for 24-bit samples
by Ranjani Sridharan 20 Oct '17
by Ranjani Sridharan 20 Oct '17
20 Oct '17
This patch fixes the DC offsets introduced in the volume component
due to shifts and handles sign extension for 24-bit input samples
Signed-off-by: Ranjani Sridharan <ranjani.sridharan(a)linux.intel.com>
---
src/audio/tone.c | 19 +++++++----
src/audio/volume.c | 71 +++++++++++++++++++++++++++--------------
src/include/reef/audio/format.h | 50 ++++++++++++++++++++++-------
src/math/trig.c | 3 +-
4 files changed, 99 insertions(+), 44 deletions(-)
diff --git a/src/audio/tone.c b/src/audio/tone.c
index 0baf247..1fde455 100644
--- a/src/audio/tone.c
+++ b/src/audio/tone.c
@@ -149,7 +149,9 @@ static int32_t tonegen(struct tone_state *sg)
/* sg->w is angle in Q4.28 radians format, sin() returns Q1.31 */
/* sg->a is amplitude as Q1.31 */
- sine = q_mults_32x32(sin_fixed(sg->w), sg->a, 31, 31, 31);
+ sine =
+ q_mults_32x32(sin_fixed(sg->w), sg->a,
+ Q_SHIFT_BITS_64(31, 31, 31));
/* Next point */
w = (int64_t) sg->w + sg->w_step;
@@ -208,15 +210,16 @@ static void tonegen_control(struct tone_state *sg)
&& (sg->repeat_count + 1 < sg->repeats)) {
sg->block_count = 0;
if (sg->ampl_coef > 0) {
- sg->a_target = sat_int32(q_multsr_32x32(
- sg->a_target,
- sg->ampl_coef, 31, 30, 31));
+ sg->a_target =
+ sat_int32(q_multsr_32x32(sg->a_target,
+ sg->ampl_coef, Q_SHIFT_BITS_64(31, 30, 31)));
sg->a = (sg->ramp_step > sg->a_target)
? sg->a_target : sg->ramp_step;
}
if (sg->freq_coef > 0) {
/* f is Q16.16, freq_coef is Q2.30 */
- p = q_multsr_32x32(sg->f, sg->freq_coef, 16, 30, 16);
+ p = q_multsr_32x32(sg->f, sg->freq_coef,
+ Q_SHIFT_BITS_64(16, 30, 16));
tonegen_update_f(sg, (int32_t) p); /* No saturation */
}
sg->repeat_count++;
@@ -297,7 +300,8 @@ static void tonegen_update_f(struct tone_state *sg, int32_t f)
f_max = Q_SHIFT_LEFT((int64_t) sg->fs, 0, 16 - 1);
f_max = (f_max > INT32_MAXVALUE) ? INT32_MAXVALUE : f_max;
sg->f = (f > f_max) ? f_max : f;
- w_tmp = q_multsr_32x32(sg->f, sg->c, 16, 31, 28); /* Q16 x Q31 -> Q28 */
+ /* Q16 x Q31 -> Q28 */
+ w_tmp = q_multsr_32x32(sg->f, sg->c, Q_SHIFT_BITS_64(16, 31, 28));
w_tmp = (w_tmp > PI_Q4_28) ? PI_Q4_28 : w_tmp; /* Limit to pi Q4.28 */
sg->w_step = (int32_t) w_tmp;
@@ -362,7 +366,8 @@ static int tonegen_init(struct tone_state *sg, int32_t fs, int32_t f, int32_t a)
tonegen_update_f(sg, f);
/* 125us as Q1.31 is 268435, calculate fs * 125e-6 in Q31.0 */
- sg->samples_in_block = (int32_t) q_multsr_32x32(fs, 268435, 0, 31, 0);
+ sg->samples_in_block =
+ (int32_t) q_multsr_32x32(fs, 268435, Q_SHIFT_BITS_64(0, 31, 0));
return 0;
}
diff --git a/src/audio/volume.c b/src/audio/volume.c
index 472aab9..137be3c 100644
--- a/src/audio/volume.c
+++ b/src/audio/volume.c
@@ -99,8 +99,8 @@ static void vol_s16_to_s32(struct comp_dev *dev, struct comp_buffer *sink,
int32_t *dest = (int32_t *) sink->w_ptr;
int32_t i;
-
/* buffer sizes are always divisible by period frames */
+ /* Samples are Q1.15 --> Q1.31 and volume is Q1.16 */
for (i = 0; i < frames * 2; i += 2) {
dest[i] = (int32_t)src[i] * cd->volume[0];
dest[i + 1] = (int32_t)src[i + 1] * cd->volume[1];
@@ -117,9 +117,12 @@ static void vol_s32_to_s16(struct comp_dev *dev, struct comp_buffer *sink,
int32_t i;
/* buffer sizes are always divisible by period frames */
+ /* Samples are Q1.31 --> Q1.15 and volume is Q1.16 */
for (i = 0; i < frames * 2; i += 2) {
- dest[i] = (((int32_t)src[i] >> 16) * cd->volume[0]) >> 16;
- dest[i + 1] = (((int32_t)src[i + 1] >> 16) * cd->volume[1]) >> 16;
+ dest[i] = (int16_t)q_multsr_sat_32x32(
+ src[i], cd->volume[0], Q_SHIFT_BITS_64(31, 16, 15));
+ dest[i + 1] = (int16_t)q_multsr_sat_32x32(
+ src[i + 1], cd->volume[1], Q_SHIFT_BITS_64(31, 16, 15));
}
}
@@ -133,9 +136,12 @@ static void vol_s32_to_s32(struct comp_dev *dev, struct comp_buffer *sink,
int32_t i;
/* buffer sizes are always divisible by period frames */
+ /* Samples are Q1.31 --> Q1.31 and volume is Q1.16 */
for (i = 0; i < frames * 2; i += 2) {
- dest[i] = ((int64_t)src[i] * cd->volume[0]) >> 16;
- dest[i + 1] = ((int64_t)src[i + 1] * cd->volume[1]) >> 16;
+ dest[i] = q_multsr_sat_32x32(
+ src[i], cd->volume[0], Q_SHIFT_BITS_64(31, 16, 31));
+ dest[i + 1] = q_multsr_sat_32x32(
+ src[i + 1], cd->volume[1], Q_SHIFT_BITS_64(31, 16, 31));
}
}
@@ -149,9 +155,12 @@ static void vol_s16_to_s16(struct comp_dev *dev, struct comp_buffer *sink,
int32_t i;
/* buffer sizes are always divisible by period frames */
+ /* Samples are Q1.15 --> Q1.15 and volume is Q1.16 */
for (i = 0; i < frames * 2; i += 2) {
- dest[i] = ((int32_t)src[i] * cd->volume[0]) >> 16;
- dest[i + 1] = ((int32_t)src[i + 1] * cd->volume[1]) >> 16;
+ dest[i] = q_multsr_sat_16x16(
+ src[i], cd->volume[0], Q_SHIFT_BITS_32(15, 16, 15));
+ dest[i + 1] = q_multsr_sat_16x16(
+ src[i + 1], cd->volume[1], Q_SHIFT_BITS_32(15, 16, 15));
}
}
@@ -165,9 +174,12 @@ static void vol_s16_to_s24(struct comp_dev *dev, struct comp_buffer *sink,
int32_t i;
/* buffer sizes are always divisible by period frames */
+ /* Samples are Q1.15 and volume is Q1.16 */
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[1]) >> 8;
+ dest[i] = q_multsr_sat_32x32(
+ src[i], cd->volume[0], Q_SHIFT_BITS_64(15, 16, 23));
+ dest[i + 1] = q_multsr_sat_32x32(
+ src[i], cd->volume[0], Q_SHIFT_BITS_64(15, 16, 23));
}
}
@@ -181,11 +193,14 @@ static void vol_s24_to_s16(struct comp_dev *dev, struct comp_buffer *sink,
int32_t i;
/* buffer sizes are always divisible by period frames */
+ /* Samples are Q1.23 --> Q1.15 and volume is Q1.16 */
for (i = 0; i < frames * 2; i += 2) {
- 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[1]) >> 16);
+ dest[i] = (int16_t)q_multsr_sat_32x32(
+ sign_extend_s24(src[i]), cd->volume[0],
+ Q_SHIFT_BITS_64(23, 16, 15));
+ dest[i + 1] = (int16_t)q_multsr_sat_32x32(
+ sign_extend_s24(src[i + 1]), cd->volume[1],
+ Q_SHIFT_BITS_64(23, 16, 15));
}
}
@@ -199,9 +214,12 @@ static void vol_s32_to_s24(struct comp_dev *dev, struct comp_buffer *sink,
int32_t i;
/* buffer sizes are always divisible by period frames */
+ /* Samples are Q1.31 --> Q1.23 and volume is Q1.16 */
for (i = 0; i < frames * 2; i += 2) {
- dest[i] = ((int64_t)src[i] * cd->volume[0]) >> 24;
- dest[i + 1] = ((int64_t)src[i + 1] * cd->volume[1]) >> 24;
+ dest[i] = q_multsr_sat_32x32(
+ src[i], cd->volume[0], Q_SHIFT_BITS_64(31, 16, 23));
+ dest[i + 1] = q_multsr_sat_32x32(
+ src[i + 1], cd->volume[1], Q_SHIFT_BITS_64(31, 16, 23));
}
}
@@ -215,11 +233,14 @@ static void vol_s24_to_s32(struct comp_dev *dev, struct comp_buffer *sink,
int32_t i;
/* buffer sizes are always divisible by period frames */
+ /* Samples are Q1.23 --> Q1.31 and volume is Q1.16 */
for (i = 0; i < frames * 2; i += 2) {
- dest[i] = (int32_t)(((int64_t)src[i] *
- cd->volume[0]) >> 8);
- dest[i + 1] = (int32_t)(((int64_t)src[i + 1] *
- cd->volume[1]) >> 8);
+ dest[i] = q_multsr_sat_32x32(
+ sign_extend_s24(src[i]), cd->volume[0],
+ Q_SHIFT_BITS_64(23, 16, 31));
+ dest[i + 1] = q_multsr_sat_32x32(
+ sign_extend_s24(src[i + 1]), cd->volume[1],
+ Q_SHIFT_BITS_64(23, 16, 31));
}
}
@@ -234,12 +255,14 @@ static void vol_s24_to_s24(struct comp_dev *dev, struct comp_buffer *sink,
int32_t *dest = (int32_t*) sink->w_ptr;
/* buffer sizes are always divisible by period frames */
- /* Samples are Q1.23 and volume is Q1.16 */
+ /* Samples are Q1.23 --> Q1.23 and volume is Q1.16 */
for (i = 0; i < frames * 2; i += 2) {
- dest[i] = (int32_t)(Q_MULTS_32X32(
- (int64_t)src[i], cd->volume[0], 23, 16, 23));
- dest[i + 1] = (int32_t)(Q_MULTS_32X32(
- (int64_t)src[i+1], cd->volume[1], 23, 16, 23));
+ dest[i] = q_multsr_sat_32x32(
+ sign_extend_s24(src[i]), cd->volume[0],
+ Q_SHIFT_BITS_64(23, 16, 23));
+ dest[i + 1] = q_multsr_sat_32x32(
+ sign_extend_s24(src[i + 1]), cd->volume[1],
+ Q_SHIFT_BITS_64(23, 16, 23));
}
}
diff --git a/src/include/reef/audio/format.h b/src/include/reef/audio/format.h
index 945a968..b9263f1 100644
--- a/src/include/reef/audio/format.h
+++ b/src/include/reef/audio/format.h
@@ -56,6 +56,18 @@
#define MINUS_80DB_Q1_31 214748 /* 10^(-80/20) */
#define MINUS_90DB_Q1_31 67909 /* 10^(-90/20) */
+/* Compute the number of shifts
+ * This will result in a compiler overflow error if shift bits are out of
+ * range as INT64_MAX/MIN is greater than 32 bit Q shift parameter
+ */
+#define Q_SHIFT_BITS_64(qx, qy, qz) \
+ ((qx + qy - qz) <= 63 ? (((qx + qy - qz) >= 0) ? \
+ (qx + qy - qz) : INT64_MIN) : INT64_MAX)
+
+#define Q_SHIFT_BITS_32(qx, qy, qz) \
+ ((qx + qy - qz) <= 31 ? (((qx + qy - qz) >= 0) ? \
+ (qx + qy - qz) : INT32_MIN) : INT32_MAX)
+
/* Convert a float number to fractional Qnx.ny format. Note that there is no
* check for nx+ny number of bits to fit the word length of int.
*/
@@ -82,28 +94,24 @@
#define SATP_INT32(x) (((x) > INT32_MAXVALUE) ? INT32_MAXVALUE : (x))
#define SATM_INT32(x) (((x) < INT32_MINVALUE) ? INT32_MINVALUE : (x))
-static inline int64_t q_mults_32x32(int32_t x, int32_t y,
- const int qx, const int qy, const int qp)
+static inline int64_t q_mults_32x32(int32_t x, int32_t y, const int shift_bits)
{
- return ((int64_t)x * y) >> (qx+qy-qp);
+ return ((int64_t)x * y) >> shift_bits;
}
-static inline int64_t q_multsr_32x32(int32_t x, int32_t y,
- const int qx, const int qy, const int qp)
+static inline int64_t q_multsr_32x32(int32_t x, int32_t y, const int shift_bits)
{
- return ((((int64_t)x * y) >> (qx+qy-qp-1)) + 1) >> 1;
+ return ((((int64_t)x * y) >> (shift_bits - 1)) + 1) >> 1;
}
-static inline int32_t q_mults_16x16(int16_t x, int16_t y,
- const int qx, const int qy, const int qp)
+static inline int32_t q_mults_16x16(int16_t x, int32_t y, const int shift_bits)
{
- return ((int32_t)x * y) >> (qx+qy-qp);
+ return ((int32_t)x * y) >> shift_bits;
}
-static inline int16_t q_multsr_16x16(int16_t x, int16_t y,
- const int qx, const int qy, const int qp)
+static inline int16_t q_multsr_16x16(int16_t x, int32_t y, const int shift_bits)
{
- return ((((int32_t)x * y) >> (qx+qy-qp-1)) + 1) >> 1;
+ return ((((int32_t)x * y) >> (shift_bits - 1)) + 1) >> 1;
}
/* Saturation inline functions */
@@ -147,4 +155,22 @@ static inline int16_t sat_int16(int32_t x)
return (int16_t)x;
}
+/* Fractional multiplication with shift and saturation */
+static inline int32_t q_multsr_sat_32x32(int32_t x, int32_t y,
+ const int shift_bits)
+{
+ return sat_int32(((((int64_t)x * y) >> (shift_bits - 1)) + 1) >> 1);
+}
+
+static inline int16_t q_multsr_sat_16x16(int16_t x, int32_t y,
+ const int shift_bits)
+{
+ return sat_int16(((((int32_t)x * y) >> (shift_bits - 1)) + 1) >> 1);
+}
+
+static inline int32_t sign_extend_s24(int32_t x)
+{
+ return (x << 8) >> 8;
+}
+
#endif
diff --git a/src/math/trig.c b/src/math/trig.c
index 79eb480..70593e4 100644
--- a/src/math/trig.c
+++ b/src/math/trig.c
@@ -594,6 +594,7 @@ int32_t sin_fixed(int32_t w) {
delta = s1 - s0; /* Q1.31 */
//sine = (int64_t) frac*delta; /* Q1.31 x Q1.31 -> Q2.62 */
//sine = (sine >> 31) + s0; /* Q2.31 */
- sine = s0 + q_mults_32x32(frac, delta, 31, 31, 31); /* All Q1.31 */
+ /* All Q1.31 */
+ sine = s0 + q_mults_32x32(frac, delta, Q_SHIFT_BITS_64(31, 31, 31));
return (int32_t) sine;
}
--
2.11.0
2
1

[Sound-open-firmware] [PATCH 1/2] comp: remove unused list in struct component.
by Liam Girdwood 20 Oct '17
by Liam Girdwood 20 Oct '17
20 Oct '17
Not used so remove.
Signed-off-by: Liam Girdwood <liam.r.girdwood(a)linux.intel.com>
---
src/include/reef/audio/component.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/include/reef/audio/component.h b/src/include/reef/audio/component.h
index db5f35b..8f5a508 100644
--- a/src/include/reef/audio/component.h
+++ b/src/include/reef/audio/component.h
@@ -186,7 +186,6 @@ struct comp_dev {
struct comp_driver *drv;
/* lists */
- struct list_item list; /* list in components */
struct list_item bsource_list; /* list of source buffers */
struct list_item bsink_list; /* list of sink buffers */
--
2.11.0
1
0
Update trace to align with FW and use 64bit data size.
Signed-off-by: Liam Girdwood <liam.r.girdwood(a)linux.intel.com>
---
rmbox/rmbox.c | 21 +++++++++++++++------
1 file changed, 15 insertions(+), 6 deletions(-)
diff --git a/rmbox/rmbox.c b/rmbox/rmbox.c
index 9313f4b..b872694 100644
--- a/rmbox/rmbox.c
+++ b/rmbox/rmbox.c
@@ -129,16 +129,28 @@ static void show_trace(uint64_t val, uint64_t addr, uint64_t *timestamp, double
/* 64-bit timestamp */
us = to_usecs(val, clk);
- printf("[%6.6f]\tdelta [%6.6f]\t",
+ /* empty data ? */
+ if (val == 0) {
+ *timestamp = 0;
+ return;
+ }
+
+ /* detect wrap around */
+ if (fdelta < 1000.0 * 1000.0 * 1000.0)
+ printf("0x%lx [%6.6f]\tdelta [%6.6f]\t", addr,
us / 1000000.0 , fdelta / 1000000.0);
+ else
+ printf("0x%lx [%6.6f]\tdelta [********]\t", addr,
+ us / 1000000.0);
*timestamp = val;
return;
- }
+ } else if (*timestamp == 0)
+ return;
/* check for printable values - otherwise it's a value */
if (!isprint((char)(val >> 16)) || !isprint((char)(val >> 8)) || !isprint((char)val)) {
- printf("value 0x%8.8x\n", (uint32_t)val);
+ printf("value 0x%16.16lx\n", val);
return;
}
@@ -237,9 +249,6 @@ trace:
tmp[TRACE_BLOCK_SIZE - i - 1] = c;
}
- if (val == 0)
- break;
-
show_trace(val, addr, ×tamp, clk);
if (out_fd) {
--
1.9.1
1
0

[Sound-open-firmware] [PATCH] SRC: Use a multi-channel FIR core to optimize speed plus other cleanup
by Seppo Ingalsuo 19 Oct '17
by Seppo Ingalsuo 19 Oct '17
19 Oct '17
This patch changes the sample rate conversion processing to use a single
multi-channel filter instead of per channel called mono filter instances.
The filter output is now rounded with 1/2 LSB add. The polyphase filter
input input block sizes are multiplied in SRC initialization to reach
near to or exacly the period length to reduce polyphase filter call
overhead.
The polyphase filter is now called via function pointer for more
flexibility with audio data formats. Currently S32_LE and S24_4LE are
supported.
Code cleanup includes removal of redundant variables and some debug
print code.
Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo(a)linux.intel.com>
---
src/audio/src.c | 198 ++++++++++-------------
src/audio/src_core.c | 447 ++++++++++++++++++++++++++-------------------------
src/audio/src_core.h | 42 +----
3 files changed, 323 insertions(+), 364 deletions(-)
diff --git a/src/audio/src.c b/src/audio/src.c
index 4c4bc6e..854cb82 100644
--- a/src/audio/src.c
+++ b/src/audio/src.c
@@ -55,7 +55,7 @@
/* src component private data */
struct comp_data {
- struct polyphase_src src[PLATFORM_MAX_CHANNELS];
+ struct polyphase_src src;
struct src_param param;
int32_t *delay_lines;
uint32_t sink_rate;
@@ -63,16 +63,16 @@ struct comp_data {
int32_t *sbuf_w_ptr;
int32_t *sbuf_r_ptr;
int sbuf_avail;
- int sign_extend_s24; /* Set if need to copy sign bit to b24..b31 */
void (* src_func)(struct comp_dev *dev,
struct comp_buffer *source,
struct comp_buffer *sink,
size_t *consumed,
size_t *produced);
+ void (* polyphase_func)(struct src_stage_prm *s);
};
/* Fallback function */
-static void fallback_s32(struct comp_dev *dev, struct comp_buffer *source,
+static void src_fallback(struct comp_dev *dev, struct comp_buffer *source,
struct comp_buffer *sink, size_t *bytes_read, size_t *bytes_written)
{
*bytes_read = 0;
@@ -84,101 +84,105 @@ static void src_2s_s32_default(struct comp_dev *dev,
struct comp_buffer *source, struct comp_buffer *sink,
size_t *bytes_read, size_t *bytes_written)
{
- struct polyphase_src *s;
struct src_stage_prm s1;
struct src_stage_prm s2;
- int j;
+ int s1_blk_in;
+ int s1_blk_out;
+ int s2_blk_in;
+ int s2_blk_out;
struct comp_data *cd = comp_get_drvdata(dev);
int32_t *dest = (int32_t *) sink->w_ptr;
int32_t *src = (int32_t *) source->r_ptr;
- int32_t *sbuf_addr = cd->delay_lines;
int32_t *sbuf_end_addr = &cd->delay_lines[cd->param.sbuf_length];
int32_t sbuf_size = cd->param.sbuf_length * sizeof(int32_t);
- const int nch = dev->params.channels;
- const int s1_blk_in = cd->src[0].stage1->blk_in * nch;
- const int s1_blk_out = cd->src[0].stage1->blk_out * nch;
- const int s2_blk_in = cd->src[0].stage2->blk_in * nch;
- const int s2_blk_out = cd->src[0].stage2->blk_out * nch;
+ int nch = dev->params.channels;
int sbuf_free = cd->param.sbuf_length - cd->sbuf_avail;
- int source_check = (source->avail >> 2) - s1_blk_in; /* for int32_t */
- int sink_check = (sink->free >> 2) - s2_blk_out; /* For int32_t */
int n_read = 0;
int n_written = 0;
int n1 = 0;
int n2 = 0;
+ int avail = source->avail >> 2; /* For int32_t */
+ int free = sink->free >> 2; /* For int32_t */
- s1.times = 1;
s1.x_end_addr = source->end_addr;
s1.x_size = source->size;
- s1.x_inc = nch;
s1.y_end_addr = sbuf_end_addr;
s1.y_size = sbuf_size;
- s1.y_inc = nch;
+ s1.state = &cd->src.state1;
+ s1.stage = cd->src.stage1;
+ s1.x_rptr = src;
+ s1.y_wptr = cd->sbuf_w_ptr;
+ s1.nch = nch;
- s2.times = 1;
s2.x_end_addr = sbuf_end_addr;
s2.x_size = sbuf_size;
- s2.x_inc = nch;
s2.y_end_addr = sink->end_addr;
s2.y_size = sink->size;
- s2.y_inc = nch;
+ s2.state = &cd->src.state2;
+ s2.stage = cd->src.stage2;
+ s2.x_rptr = cd->sbuf_r_ptr;
+ s2.y_wptr = dest;
+ s2.nch = nch;
+
- /* 1st stage runs once a long multiplied length block.
- * The stage buffer much be large enough to fit one s1 output block
- * plus one s2 input block plus jitter in s2 consumption.
+ /* Test if 1st stage can be run with default block length to reach
+ * the period length or just under it.
*/
- while ((n1 < cd->param.stage1_times_max)
- && (n_read <= source_check)
- && (sbuf_free >= s1_blk_out)) {
- for (j = 0; j < nch; j++) {
- s = &cd->src[j]; /* Point to src[] for this channel */
- s1.x_rptr = src++;
- s1.y_wptr = cd->sbuf_w_ptr++;
- src_circ_inc_wrap(&src, source->end_addr, source->size);
- src_circ_inc_wrap(&cd->sbuf_w_ptr, sbuf_end_addr, sbuf_size);
- s1.state = &s->state1;
- s1.stage = s->stage1;
- if (cd->sign_extend_s24)
- src_polyphase_stage_cir_s24(&s1);
- else
- src_polyphase_stage_cir(&s1);
-
- }
+ s1.times = cd->param.stage1_times;
+ s1_blk_in = s1.times * cd->src.stage1->blk_in * nch;
+ s1_blk_out = s1.times * cd->src.stage1->blk_out * nch;
+ if ((avail >= s1_blk_in) && (sbuf_free >= s1_blk_out)) {
+ cd->polyphase_func(&s1);
+ cd->sbuf_w_ptr = s1.y_wptr;
+ cd->sbuf_avail += s1_blk_out;
n_read += s1_blk_in;
+ avail -= s1_blk_in;
+ sbuf_free -= s1_blk_out;
+ n1 = s1.times;
+ }
+
+ /* Run one block at time the remaining data for 1st stage. */
+ s1.times = 1;
+ s1_blk_in = cd->src.stage1->blk_in * nch;
+ s1_blk_out = cd->src.stage1->blk_out * nch;
+ while ((n1 < cd->param.stage1_times_max) && (avail >= s1_blk_in)
+ && (sbuf_free >= s1_blk_out)) {
+ cd->polyphase_func(&s1);
+ cd->sbuf_w_ptr = s1.y_wptr;
cd->sbuf_avail += s1_blk_out;
+ n_read += s1_blk_in;
+ avail -= s1_blk_in;
sbuf_free -= s1_blk_out;
- src = s1.x_rptr - nch + 1;
- cd->sbuf_w_ptr = s1.y_wptr - nch + 1;
- src_circ_dec_wrap(&src, source->addr, source->size);
- src_circ_dec_wrap(&cd->sbuf_w_ptr, sbuf_addr, sbuf_size);
- n1++;
+ n1 += s1.times;
+ }
+
+ /* Test if 2nd stage can be run with default block length. */
+ s2.times = cd->param.stage2_times;
+ s2_blk_in = s2.times * cd->src.stage2->blk_in * nch;
+ s2_blk_out = s2.times * cd->src.stage2->blk_out * nch;
+ if ((cd->sbuf_avail >= s2_blk_in) && (free >= s2_blk_out)) {
+ cd->polyphase_func(&s2);
+ cd->sbuf_r_ptr = s2.x_rptr;
+ cd->sbuf_avail -= s2_blk_in;
+ free -= s2_blk_out;
+ n_written += s2_blk_out;
+ n2 = s2.times;
}
- /* 2nd stage runs as many min size blocks as buffers allow */
+
+ /* Run one block at time the remaining 2nd stage output */
+ s2.times = 1;
+ s2_blk_in = cd->src.stage2->blk_in * nch;
+ s2_blk_out = cd->src.stage2->blk_out * nch;
while ((n2 < cd->param.stage2_times_max)
&& (cd->sbuf_avail >= s2_blk_in)
- && (n_written <= sink_check)) {
- for (j = 0; j < nch; j++) {
- s2.x_rptr = cd->sbuf_r_ptr++;
- s2.y_wptr = dest++;
- src_circ_inc_wrap(&cd->sbuf_r_ptr, sbuf_end_addr, sbuf_size);
- src_circ_inc_wrap(&dest, sink->end_addr, sink->size);
- s = &cd->src[j]; /* Point to src[] for this channel */
- s2.state = &s->state2;
- s2.stage = s->stage2;
- if (cd->sign_extend_s24)
- src_polyphase_stage_cir_s24(&s2);
- else
- src_polyphase_stage_cir(&s2);
-
- }
- cd->sbuf_r_ptr = s2.x_rptr - nch + 1;
- dest = s2.y_wptr - nch + 1;
- src_circ_dec_wrap(&cd->sbuf_r_ptr, sbuf_addr, sbuf_size);
- src_circ_dec_wrap(&dest, sink->addr, sink->size);
- n_written += s2_blk_out;
+ && (free >= s2_blk_out)) {
+ cd->polyphase_func(&s2);
+ cd->sbuf_r_ptr = s2.x_rptr;
cd->sbuf_avail -= s2_blk_in;
- n2++;
+ free -= s2_blk_out;
+ n_written += s2_blk_out;
+ n2 += s2.times;
}
*bytes_read = sizeof(int32_t) * n_read;
*bytes_written = sizeof(int32_t) * n_written;
@@ -189,42 +193,27 @@ static void src_1s_s32_default(struct comp_dev *dev,
struct comp_buffer *source, struct comp_buffer *sink,
size_t *bytes_read, size_t *bytes_written)
{
- struct polyphase_src *s;
struct src_stage_prm s1;
- int j;
struct comp_data *cd = comp_get_drvdata(dev);
- int32_t *dest = (int32_t *) sink->w_ptr;
- int32_t *src = (int32_t *) source->r_ptr;
int nch = dev->params.channels;
int n_read = 0;
int n_written = 0;
s1.times = cd->param.stage1_times;
+ s1.x_rptr = (int32_t *) source->r_ptr;
s1.x_end_addr = source->end_addr;
s1.x_size = source->size;
- s1.x_inc = nch;
+ s1.y_wptr = (int32_t *) sink->w_ptr;
s1.y_end_addr = sink->end_addr;
s1.y_size = sink->size;
- s1.y_inc = nch;
- s1.x_rptr = src + nch - 1;
- s1.y_wptr = dest + nch - 1;
-
- for (j = 0; j < nch; j++) {
- s = &cd->src[j]; /* Point to src for this channel */
- s1.x_rptr = src++;
- s1.y_wptr = dest++;
- src_circ_inc_wrap(&src, source->end_addr, source->size);
- src_circ_inc_wrap(&dest, sink->end_addr, sink->size);
- s1.state = &s->state1;
- s1.stage = s->stage1;
- if (cd->sign_extend_s24)
- src_polyphase_stage_cir_s24(&s1);
- else
- src_polyphase_stage_cir(&s1);
-
- n_read += cd->param.blk_in;
- n_written += cd->param.blk_out;
- }
+ s1.state = &cd->src.state1;
+ s1.stage = cd->src.stage1;
+ s1.nch = dev->params.channels;
+
+ cd->polyphase_func(&s1);
+
+ n_read += nch * cd->param.blk_in;
+ n_written += nch * cd->param.blk_out;
*bytes_read = n_read * sizeof(int32_t);
*bytes_written = n_written * sizeof(int32_t);
}
@@ -271,7 +260,6 @@ static struct comp_dev *src_new(struct sof_ipc_comp *comp)
struct sof_ipc_comp_src *src;
struct sof_ipc_comp_src *ipc_src = (struct sof_ipc_comp_src *) comp;
struct comp_data *cd;
- int i;
trace_src("new");
@@ -299,8 +287,8 @@ static struct comp_dev *src_new(struct sof_ipc_comp *comp)
cd->delay_lines = NULL;
cd->src_func = src_2s_s32_default;
- for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
- src_polyphase_reset(&cd->src[i]);
+ cd->polyphase_func = src_polyphase_stage_cir;
+ src_polyphase_reset(&cd->src);
dev->state = COMP_STATE_READY;
return dev;
@@ -334,10 +322,8 @@ static int src_params(struct comp_dev *dev)
uint32_t sink_rate;
int32_t *buffer_start;
int n = 0;
- int i;
int err;
int frames_is_for_source;
- int nch;
int q;
trace_src("par");
@@ -345,10 +331,10 @@ static int src_params(struct comp_dev *dev)
/* SRC supports S24_4LE and S32_LE formats */
switch (config->frame_fmt) {
case SOF_IPC_FRAME_S24_4LE:
- cd->sign_extend_s24 = 1;
+ cd->polyphase_func = src_polyphase_stage_cir_s24;
break;
case SOF_IPC_FRAME_S32_LE:
- cd->sign_extend_s24 = 0;
+ cd->polyphase_func = src_polyphase_stage_cir;
break;
default:
trace_src_error("sr0");
@@ -407,11 +393,7 @@ static int src_params(struct comp_dev *dev)
buffer_start = cd->delay_lines + cd->param.sbuf_length;
/* Initize SRC for actual sample rate */
- nch = MIN(params->channels, PLATFORM_MAX_CHANNELS);
- for (i = 0; i < nch; i++) {
- n = src_polyphase_init(&cd->src[i], &cd->param, buffer_start);
- buffer_start += cd->param.single_src;
- }
+ n = src_polyphase_init(&cd->src, &cd->param, buffer_start);
/* Reset stage buffer */
cd->sbuf_r_ptr = cd->delay_lines;
@@ -434,7 +416,7 @@ static int src_params(struct comp_dev *dev)
* muted if copy() is run.
*/
trace_src("SFa");
- cd->src_func = fallback_s32;
+ cd->src_func = src_fallback;
return -EINVAL;
break;
}
@@ -532,7 +514,6 @@ static int src_copy(struct comp_dev *dev)
/* Run SRC function if buffers avail and free allow */
if (((int) source->avail >= need_source) && ((int) sink->free >= need_sink)) {
- /* Run src */
cd->src_func(dev, source, sink, &consumed, &produced);
/* Calc new free and available if data was processed. These
@@ -561,14 +542,12 @@ static int src_preload(struct comp_dev *dev)
static int src_reset(struct comp_dev *dev)
{
- int i;
struct comp_data *cd = comp_get_drvdata(dev);
trace_src("SRe");
cd->src_func = src_2s_s32_default;
- for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
- src_polyphase_reset(&cd->src[i]);
+ src_polyphase_reset(&cd->src);
comp_set_state(dev, COMP_CMD_RESET);
return 0;
@@ -576,7 +555,8 @@ static int src_reset(struct comp_dev *dev)
struct comp_driver comp_src = {
.type = SOF_COMP_SRC,
- .ops = {
+ .ops =
+ {
.new = src_new,
.free = src_free,
.params = src_params,
diff --git a/src/audio/src_core.c b/src/audio/src_core.c
index 4ee2efd..0d8cc17 100644
--- a/src/audio/src_core.c
+++ b/src/audio/src_core.c
@@ -51,6 +51,10 @@ int sof_rates[SOF_RATES_LENGTH] = {8000, 11025, 12000, 16000, 18900,
22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000, 176400,
192000};
+/* The FIR maximum lenghts are per channel so need to multiply them */
+#define MAX_FIR_DELAY_SIZE_XNCH (PLATFORM_MAX_CHANNELS * MAX_FIR_DELAY_SIZE)
+#define MAX_OUT_DELAY_SIZE_XNCH (PLATFORM_MAX_CHANNELS * MAX_OUT_DELAY_SIZE)
+
/* Calculate ceil() for integer division */
int src_ceil_divide(int a, int b)
{
@@ -131,6 +135,10 @@ int src_buffer_lengths(struct src_param *a, int fs_in, int fs_out, int nch,
int num;
int frames2;
+ if (nch > PLATFORM_MAX_CHANNELS)
+ return -EINVAL;
+
+ a->nch = nch;
a->idx_in = src_find_fs(src_in_fs, NUM_IN_FS, fs_in);
a->idx_out = src_find_fs(src_out_fs, NUM_OUT_FS, fs_out);
@@ -146,8 +154,8 @@ int src_buffer_lengths(struct src_param *a, int fs_in, int fs_out, int nch,
stage1 = src_table1[a->idx_out][a->idx_in];
stage2 = src_table2[a->idx_out][a->idx_in];
- a->fir_s1 = src_fir_delay_length(stage1);
- a->out_s1 = src_out_delay_length(stage1);
+ a->fir_s1 = nch * src_fir_delay_length(stage1);
+ a->out_s1 = nch * src_out_delay_length(stage1);
/* Find out how many additional times the SRC can be executed
while having block size less or equal to max_frames.
@@ -191,8 +199,8 @@ int src_buffer_lengths(struct src_param *a, int fs_in, int fs_out, int nch,
a->stage2_times_max = 0;
a->sbuf_length = 0;
} else {
- a->fir_s2 = src_fir_delay_length(stage2);
- a->out_s2 = src_out_delay_length(stage2);
+ a->fir_s2 = nch * src_fir_delay_length(stage2);
+ a->out_s2 = nch * src_out_delay_length(stage2);
/* 2x is an empirically tested length. Since the sink buffer
* capability to receive samples varies a shorter stage 2 output
* block will create a peak in internal buffer usage.
@@ -200,8 +208,8 @@ int src_buffer_lengths(struct src_param *a, int fs_in, int fs_out, int nch,
a->sbuf_length = 2 * nch * stage1->blk_out * a->stage1_times_max;
}
- a->single_src = a->fir_s1 + a->fir_s2 + a->out_s1 + a->out_s2;
- a->total = a->sbuf_length + nch * a->single_src;
+ a->src_multich = a->fir_s1 + a->fir_s2 + a->out_s1 + a->out_s2;
+ a->total = a->sbuf_length + a->src_multich;
return 0;
}
@@ -212,8 +220,6 @@ static void src_state_reset(struct src_state *state)
state->fir_delay_size = 0;
state->out_delay_size = 0;
state->fir_wi = 0;
- state->fir_ri = 0;
- state->out_wi = 0;
state->out_ri = 0;
}
@@ -229,17 +235,8 @@ static int init_stages(
src->number_of_stages = n;
src->stage1 = stage1;
src->stage2 = stage2;
- src->blk_in = p->blk_in;
- src->blk_out = p->blk_out;
- if (n == 1) {
- src->stage1_times = p->stage1_times;
- src->stage2_times = 0;
- if (stage1->blk_out == 0)
- return -EINVAL;
- } else {
- src->stage1_times = p->stage1_times;
- src->stage2_times = p->stage2_times;
- }
+ if ((n == 1) && (stage1->blk_out == 0))
+ return -EINVAL;
/* Delay line sizes */
src->state1.fir_delay_size = p->fir_s1;
@@ -262,10 +259,10 @@ static int init_stages(
}
/* Check the sizes are less than MAX */
- if ((src->state1.fir_delay_size > MAX_FIR_DELAY_SIZE)
- || (src->state1.out_delay_size > MAX_OUT_DELAY_SIZE)
- || (src->state2.fir_delay_size > MAX_FIR_DELAY_SIZE)
- || (src->state2.out_delay_size > MAX_OUT_DELAY_SIZE)) {
+ if ((src->state1.fir_delay_size > MAX_FIR_DELAY_SIZE_XNCH)
+ || (src->state1.out_delay_size > MAX_OUT_DELAY_SIZE_XNCH)
+ || (src->state2.fir_delay_size > MAX_FIR_DELAY_SIZE_XNCH)
+ || (src->state2.out_delay_size > MAX_OUT_DELAY_SIZE_XNCH)) {
src->state1.fir_delay = NULL;
src->state1.out_delay = NULL;
src->state2.fir_delay = NULL;
@@ -279,12 +276,7 @@ static int init_stages(
void src_polyphase_reset(struct polyphase_src *src)
{
- src->mute = 0;
src->number_of_stages = 0;
- src->blk_in = 0;
- src->blk_out = 0;
- src->stage1_times = 0;
- src->stage2_times = 0;
src->stage1 = NULL;
src->stage2 = NULL;
src_state_reset(&src->state1);
@@ -300,8 +292,6 @@ int src_polyphase_init(struct polyphase_src *src, struct src_param *p,
struct src_stage *stage2;
if ((p->idx_in < 0) || (p->idx_out < 0)) {
- src->blk_in = p->blk_in;
- src->blk_out = p->blk_out;
return -EINVAL;
}
@@ -335,141 +325,203 @@ int src_polyphase_init(struct polyphase_src *src, struct src_param *p,
#if SRC_SHORT == 1
/* Calculate a FIR filter part that does not need circular modification */
-static inline void fir_part(int64_t *y, int ntaps, const int16_t c[], int *ic,
- int32_t d[], int *id)
+
+static inline void fir_part(int64_t y[], int *id, int *ic,
+ const int32_t data[], const int16_t coef[], int nch_x_taps, int nch)
{
+ int64_t tap0;
+ int64_t tap1;
int n;
int64_t a = 0;
+ int64_t b = 0;
+ int c = *ic;
+ int d = *id;
+ int d_end = d - nch_x_taps;
/* Data is Q1.31, coef is Q1.15, product is Q2.46 */
- for (n = 0; n < (ntaps >> 1); n++) {
- a += (int64_t) c[*ic] * d[*id]
- + (int64_t) c[*ic + 1] * d[*id - 1];
- *ic += 2;
- *id -= 2;
+ if (nch == 2) {
+ for (n = 0; n < (nch_x_taps >> 2); n++) {
+ tap0 = coef[c++];
+ tap1 = coef[c++];
+ b += data[d--] * tap0;
+ a += data[d--] * tap0;
+ b += data[d--] * tap1;
+ a += data[d--] * tap1;
+ }
+ if (d > d_end) {
+ tap0 = coef[c++];
+ b += data[d--] * tap0;
+ a += data[d--] * tap0;
+ }
+ y[1] += b;
+ y[0] += a;
+ } else {
+ while (d > d_end) {
+ tap0 = coef[c++];
+ for (n = nch - 1; n >= 0; n--)
+ y[n] += data[d--] * tap0;
+ }
}
- if (ntaps & 1)
- a += (int64_t) c[(*ic)++] * d[(*id)--];
-
- *y += a;
+ *ic = c;
+ *id = d;
}
+
#else
-/* Calculate a FIR filter part that does not need circular modification */
-static inline void fir_part(int64_t *y, int ntaps, const int32_t c[], int *ic,
- int32_t d[], int *id)
+static inline void fir_part(int64_t y[], int *id, int *ic,
+ const int32_t data[], const int32_t coef[], int nch_x_taps, int nch)
{
+ int64_t tap0;
+ int64_t tap1;
int n;
int64_t a = 0;
-
- /* Data is Q8.24, coef is Q1.23, product is Q9.47 */
- for (n = 0; n < (ntaps >> 1); n++) {
- a += (int64_t) c[*ic] * d[*id]
- + (int64_t) c[*ic + 1] * d[*id - 1];
- *ic += 2;
- *id -= 2;
+ int64_t b = 0;
+ int c = *ic;
+ int d = *id;
+ int d_end = d - nch_x_taps;
+
+ /* Data is Q1.31, coef is Q1.23, product is Q2.54 */
+ if (nch == 2) {
+ for (n = 0; n < (nch_x_taps >> 2); n++) {
+ tap0 = coef[c++];
+ tap1 = coef[c++];
+ b += data[d--] * tap0;
+ a += data[d--] * tap0;
+ b += data[d--] * tap1;
+ a += data[d--] * tap1;
+ }
+ if (d > d_end) {
+ tap0 = coef[c++];
+ b += data[d--] * tap0;
+ a += data[d--] * tap0;
+ }
+ y[1] += b;
+ y[0] += a;
+ } else {
+ while (d > d_end) {
+ tap0 = coef[c++];
+ for (n = nch - 1; n >= 0; n--)
+ y[n] += data[d--] * tap0;
+ }
}
- if (ntaps & 1)
- a += (int64_t) c[(*ic)++] * d[(*id)--];
-
- *y += a;
+ *ic = c;
+ *id = d;
}
+
#endif
#if SRC_SHORT == 1
-static inline int32_t fir_filter(
- struct src_state *fir, const int16_t coefs[],
- int *coefi, int filter_length, int shift)
+static void fir_filter(int ri0, int *ci, int wi0, int32_t in_delay[],
+ int32_t out_delay[], const int16_t coefs[], int dsm1, int taps,
+ int shift, int nch)
{
- int64_t y = 0;
- int n1;
int n2;
-
- n1 = fir->fir_ri + 1;
- if (n1 > filter_length) {
- /* No need to un-wrap fir read index, make sure fir_fi
- * is ge 0 after FIR computation.
- */
- fir_part(&y, filter_length, coefs, coefi, fir->fir_delay,
- &fir->fir_ri);
+ int i;
+ int64_t y[PLATFORM_MAX_CHANNELS];
+ int ri = ri0;
+ int wi = wi0;
+ int n1 = ri0 + 1; /* Convert to number of sequential frames */
+ int qshift = 15 + shift; /* Q2.46 -> Q2.31 */
+ int32_t rnd = 1 << (qshift - 1); /* Half LSB */
+ int nch_x_taps = nch * taps;
+
+ /* Initialize to half LSB for rounding */
+ for (i = 0; i < nch; i++)
+ y[i] = rnd;
+
+ if (n1 >= nch_x_taps) {
+ fir_part(y, &ri, ci, in_delay, coefs, nch_x_taps, nch);
} else {
- n2 = filter_length - n1;
- /* Part 1, loop n1 times, fir_ri becomes -1 */
- fir_part(&y, n1, coefs, coefi, fir->fir_delay, &fir->fir_ri);
-
- /* Part 2, unwrap fir_ri, continue rest of filter */
- fir->fir_ri = fir->fir_delay_size - 1;
- fir_part(&y, n2, coefs, coefi, fir->fir_delay, &fir->fir_ri);
+ n2 = nch_x_taps - n1;
+ fir_part(y, &ri, ci, in_delay, coefs, n1, nch);
+ ri = dsm1;
+ fir_part(y, &ri, ci, in_delay, coefs, n2, nch);
}
- /* Q2.46 -> Q2.31, saturate to Q1.31 */
- y = y >> (15 + shift);
- return(int32_t) sat_int32(y);
+ for (i = 0; i < nch; i++)
+ out_delay[wi++] = sat_int32(y[i] >> qshift);
}
#else
-static inline int32_t fir_filter(
- struct src_state *fir, const int32_t coefs[],
- int *coefi, int filter_length, int shift)
+static void fir_filter(int ri0, int *ci, int wi0, int32_t in_delay[],
+ int32_t out_delay[], const int32_t coefs[], int dsm1, int taps,
+ int shift, int nch)
{
- int64_t y = 0;
- int n1;
int n2;
-
- n1 = fir->fir_ri + 1;
- if (n1 > filter_length) {
- /* No need to un-wrap fir read index, make sure fir_fi
- * is ge 0 after FIR computation.
- */
- fir_part(&y, filter_length, coefs, coefi, fir->fir_delay,
- &fir->fir_ri);
+ int i;
+ int64_t y[PLATFORM_MAX_CHANNELS];
+ int ri = ri0;
+ int wi = wi0;
+ int n1 = ri0 + 1; /* Convert to number of sequential frames */
+ int qshift = 23 + shift; /* Q2.54 -> Q2.31 */
+ int32_t rnd = 1 << (qshift - 1); /* Half LSB */
+ int nch_x_taps = nch * taps;
+
+ /* Initialize to half LSB for rounding */
+ for (i = 0; i < nch; i++)
+ y[i] = rnd;
+
+ if (n1 >= nch_x_taps) {
+ fir_part(y, &ri, ci, in_delay, coefs, nch_x_taps, nch);
} else {
- n2 = filter_length - n1;
- /* Part 1, loop n1 times, fir_ri becomes -1 */
- fir_part(&y, n1, coefs, coefi, fir->fir_delay, &fir->fir_ri);
-
- /* Part 2, unwrap fir_ri, continue rest of filter */
- fir->fir_ri = fir->fir_delay_size - 1;
- fir_part(&y, n2, coefs, coefi, fir->fir_delay, &fir->fir_ri);
+ n2 = nch_x_taps - n1;
+ fir_part(y, &ri, ci, in_delay, coefs, n1, nch);
+ ri = dsm1;
+ fir_part(y, &ri, ci, in_delay, coefs, n2, nch);
}
- /* Q9.47 -> Q9.24, saturate to Q8.24 */
- y = y >> (23 + shift);
- return(int32_t) sat_int32(y);
+ for (i = 0; i < nch; i++)
+ out_delay[wi++] = sat_int32(y[i] >> qshift);
+
}
+
#endif
void src_polyphase_stage_cir(struct src_stage_prm * s)
{
- struct src_state *fir = s->state;
- struct src_stage *cfg = s->stage;
int n;
int m;
int f;
- int c;
- int r;
+ int ci;
+ int ri;
int n_wrap_fir;
int n_wrap_buf;
int n_wrap_min;
int n_min;
- int32_t z;
+ int wi;
+
+ struct src_state *fir = s->state;
+ struct src_stage *cfg = s->stage;
+ const void *coef = cfg->coefs;
+ int32_t *in_delay = fir->fir_delay;
+ int32_t *out_delay = fir->out_delay;
+ int dsm1 = fir->fir_delay_size - 1;
+ int shift = cfg->shift;
+ int nch = s->nch;
+ int rewind = -nch * (cfg->blk_in
+ + (cfg->num_of_subfilters - 1) * cfg->idm) + nch - 1;
+ int nch_x_idm = cfg->idm * nch;
+ int nch_x_odm = cfg->odm * nch;
+ size_t sz = sizeof(int32_t);
+ int blk_in_bytes = nch * cfg->blk_in * sz;
+ int blk_out_bytes = nch * cfg->num_of_subfilters * sz;
+
for (n = 0; n < s->times; n++) {
/* Input data */
- m = s->x_inc * cfg->blk_in;
+ m = blk_in_bytes;
while (m > 0) {
- n_wrap_fir = (fir->fir_delay_size - fir->fir_wi)
- * s->x_inc;
+ n_wrap_fir = (fir->fir_delay_size - fir->fir_wi) * sz;
n_wrap_buf = s->x_end_addr - s->x_rptr;
n_wrap_min = (n_wrap_fir < n_wrap_buf)
? n_wrap_fir : n_wrap_buf;
n_min = (m < n_wrap_min) ? m : n_wrap_min;
while (n_min > 0) {
fir->fir_delay[fir->fir_wi++] = *s->x_rptr;
- s->x_rptr += s->x_inc;
- n_min -= s->x_inc;
- m -= s->x_inc;
+ s->x_rptr++;
+ n_min -= sz;
+ m -= sz;
}
/* Check for wrap */
src_circ_inc_wrap(&s->x_rptr, s->x_end_addr, s->x_size);
@@ -478,41 +530,38 @@ void src_polyphase_stage_cir(struct src_stage_prm * s)
}
/* Filter */
- c = 0;
- r = fir->fir_wi - cfg->blk_in
- - (cfg->num_of_subfilters - 1) * cfg->idm;
- if (r < 0)
- r += fir->fir_delay_size;
+ ci = 0; /* Reset to 1st coefficient */
+ ri = fir->fir_wi + rewind; /* Newest data for last subfilter */
+ if (ri < 0)
+ ri += fir->fir_delay_size;
- fir->out_wi = fir->out_ri;
+ wi = fir->out_ri;
for (f = 0; f < cfg->num_of_subfilters; f++) {
- fir->fir_ri = r;
- z = fir_filter(fir, cfg->coefs, &c,
- cfg->subfilter_length, cfg->shift);
- r += cfg->idm;
- if (r >= fir->fir_delay_size)
- r -= fir->fir_delay_size;
-
- fir->out_delay[fir->out_wi] = z;
- fir->out_wi += cfg->odm;
- if (fir->out_wi >= fir->out_delay_size)
- fir->out_wi -= fir->out_delay_size;
+ fir_filter(ri, &ci, wi, in_delay, out_delay, coef,
+ dsm1, cfg->subfilter_length, shift, nch);
+
+ wi += nch_x_odm;
+ if (wi >= fir->out_delay_size)
+ wi -= fir->out_delay_size;
+
+ ri += nch_x_idm; /* Next sub-filter start */
+ if (ri >= fir->fir_delay_size)
+ ri -= fir->fir_delay_size;
}
/* Output */
- m = s->y_inc * cfg->num_of_subfilters;
+ m = blk_out_bytes;
while (m > 0) {
- n_wrap_fir = (fir->out_delay_size - fir->out_ri)
- * s->y_inc;
+ n_wrap_fir = (fir->out_delay_size - fir->out_ri) * sz;
n_wrap_buf = s->y_end_addr - s->y_wptr;
n_wrap_min = (n_wrap_fir < n_wrap_buf)
? n_wrap_fir : n_wrap_buf;
n_min = (m < n_wrap_min) ? m : n_wrap_min;
while (n_min > 0) {
*s->y_wptr = fir->out_delay[fir->out_ri++];
- s->y_wptr += s->y_inc;
- n_min -= s->y_inc;
- m -= s->y_inc;
+ s->y_wptr++;
+ n_min -= sz;
+ m -= sz;
}
/* Check wrap */
src_circ_inc_wrap(&s->y_wptr, s->y_end_addr, s->y_size);
@@ -522,38 +571,49 @@ void src_polyphase_stage_cir(struct src_stage_prm * s)
}
}
-void src_polyphase_stage_cir_s24(struct src_stage_prm * s)
+void src_polyphase_stage_cir_s24(struct src_stage_prm *s)
{
- struct src_state *fir = s->state;
- struct src_stage *cfg = s->stage;
int n;
int m;
int f;
- int c;
- int r;
+ int ci;
+ int ri;
int n_wrap_fir;
int n_wrap_buf;
int n_wrap_min;
int n_min;
- int32_t z;
- int32_t se;
+ int wi;
+
+ struct src_state *fir = s->state;
+ struct src_stage *cfg = s->stage;
+ const void *coef = cfg->coefs;
+ int32_t *in_delay = fir->fir_delay;
+ int32_t *out_delay = fir->out_delay;
+ int dsm1 = fir->fir_delay_size - 1;
+ int shift = cfg->shift;
+ int nch = s->nch;
+ int rewind = -nch * (cfg->blk_in
+ + (cfg->num_of_subfilters - 1) * cfg->idm) + nch - 1;
+ int nch_x_idm = cfg->idm * nch;
+ int nch_x_odm = cfg->odm * nch;
+ size_t sz = sizeof(int32_t);
+ int blk_in_bytes = nch * cfg->blk_in * sz;
+ int blk_out_bytes = nch * cfg->num_of_subfilters * sz;
for (n = 0; n < s->times; n++) {
/* Input data */
- m = s->x_inc * cfg->blk_in;
+ m = blk_in_bytes;
while (m > 0) {
- n_wrap_fir = (fir->fir_delay_size - fir->fir_wi)
- * s->x_inc;
+ n_wrap_fir = (fir->fir_delay_size - fir->fir_wi) * sz;
n_wrap_buf = s->x_end_addr - s->x_rptr;
n_wrap_min = (n_wrap_fir < n_wrap_buf)
? n_wrap_fir : n_wrap_buf;
n_min = (m < n_wrap_min) ? m : n_wrap_min;
while (n_min > 0) {
- se = *s->x_rptr << 8;
- fir->fir_delay[fir->fir_wi++] = se >> 8;
- s->x_rptr += s->x_inc;
- n_min -= s->x_inc;
- m -= s->x_inc;
+ fir->fir_delay[fir->fir_wi++] = *s->x_rptr << 8;
+ s->x_rptr++;
+ n_min -= sz;
+ m -= sz;
}
/* Check for wrap */
src_circ_inc_wrap(&s->x_rptr, s->x_end_addr, s->x_size);
@@ -562,41 +622,38 @@ void src_polyphase_stage_cir_s24(struct src_stage_prm * s)
}
/* Filter */
- c = 0;
- r = fir->fir_wi - cfg->blk_in
- - (cfg->num_of_subfilters - 1) * cfg->idm;
- if (r < 0)
- r += fir->fir_delay_size;
+ ci = 0; /* Reset to 1st coefficient */
+ ri = fir->fir_wi + rewind; /* Newest data for last subfilter */
+ if (ri < 0)
+ ri += fir->fir_delay_size;
- fir->out_wi = fir->out_ri;
+ wi = fir->out_ri;
for (f = 0; f < cfg->num_of_subfilters; f++) {
- fir->fir_ri = r;
- z = fir_filter(fir, cfg->coefs, &c,
- cfg->subfilter_length, cfg->shift);
- r += cfg->idm;
- if (r >= fir->fir_delay_size)
- r -= fir->fir_delay_size;
-
- fir->out_delay[fir->out_wi] = z;
- fir->out_wi += cfg->odm;
- if (fir->out_wi >= fir->out_delay_size)
- fir->out_wi -= fir->out_delay_size;
+ fir_filter(ri, &ci, wi, in_delay, out_delay, coef,
+ dsm1, cfg->subfilter_length, shift, nch);
+
+ wi += nch_x_odm;
+ if (wi >= fir->out_delay_size)
+ wi -= fir->out_delay_size;
+
+ ri += nch_x_idm; /* Next sub-filter start */
+ if (ri >= fir->fir_delay_size)
+ ri -= fir->fir_delay_size;
}
/* Output */
- m = s->y_inc * cfg->num_of_subfilters;
+ m = blk_out_bytes;
while (m > 0) {
- n_wrap_fir = (fir->out_delay_size - fir->out_ri)
- * s->y_inc;
+ n_wrap_fir = (fir->out_delay_size - fir->out_ri) * sz;
n_wrap_buf = s->y_end_addr - s->y_wptr;
n_wrap_min = (n_wrap_fir < n_wrap_buf)
? n_wrap_fir : n_wrap_buf;
n_min = (m < n_wrap_min) ? m : n_wrap_min;
while (n_min > 0) {
- *s->y_wptr = fir->out_delay[fir->out_ri++];
- s->y_wptr += s->y_inc;
- n_min -= s->y_inc;
- m -= s->y_inc;
+ *s->y_wptr = fir->out_delay[fir->out_ri++] >> 8;
+ s->y_wptr++;
+ n_min -= sz;
+ m -= sz;
}
/* Check wrap */
src_circ_inc_wrap(&s->y_wptr, s->y_end_addr, s->y_size);
@@ -604,47 +661,5 @@ void src_polyphase_stage_cir_s24(struct src_stage_prm * s)
fir->out_ri = 0;
}
}
-}
-
-#ifdef MODULE_TEST
-
-void src_print_info(struct polyphase_src * src)
-{
-
- int n1;
- int n2;
-
- n1 = src->stage1->filter_length;
- n2 = src->stage2->filter_length;
- printf("SRC stages %d\n", src->number_of_stages);
- printf("SRC input blk %d\n", src->blk_in);
- printf("SRC output blk %d\n", src->blk_out);
- printf("SRC stage1 %d times\n", src->stage1_times);
- printf("SRC stage2 %d times\n", src->stage2_times);
-
- printf("SRC1 filter length %d\n", n1);
- printf("SRC1 subfilter length %d\n", src->stage1->subfilter_length);
- printf("SRC1 number of subfilters %d\n",
- src->stage1->num_of_subfilters);
- printf("SRC1 idm %d\n", src->stage1->idm);
- printf("SRC1 odm %d\n", src->stage1->odm);
- printf("SRC1 input blk %d\n", src->stage1->blk_in);
- printf("SRC1 output blk %d\n", src->stage1->blk_out);
- printf("SRC1 halfband %d\n", src->stage1->halfband);
- printf("SRC1 FIR delay %d\n", src->state1.fir_delay_size);
- printf("SRC1 out delay %d\n", src->state1.out_delay_size);
-
- printf("SRC2 filter length %d\n", n2);
- printf("SRC2 subfilter length %d\n", src->stage2->subfilter_length);
- printf("SRC2 number of subfilters %d\n",
- src->stage2->num_of_subfilters);
- printf("SRC2 idm %d\n", src->stage2->idm);
- printf("SRC2 odm %d\n", src->stage2->odm);
- printf("SRC2 input blk %d\n", src->stage2->blk_in);
- printf("SRC2 output blk %d\n", src->stage2->blk_out);
- printf("SRC2 halfband %d\n", src->stage2->halfband);
- printf("SRC2 FIR delay %d\n", src->state2.fir_delay_size);
- printf("SRC2 out delay %d\n", src->state2.out_delay_size);
}
-#endif
diff --git a/src/audio/src_core.h b/src/audio/src_core.h
index 3859e6f..3ea6028 100644
--- a/src/audio/src_core.h
+++ b/src/audio/src_core.h
@@ -41,7 +41,7 @@ struct src_param {
int out_s1;
int out_s2;
int sbuf_length;
- int single_src;
+ int src_multich;
int total;
int blk_in;
int blk_out;
@@ -51,6 +51,7 @@ struct src_param {
int stage2_times_max;
int idx_in;
int idx_out;
+ int nch;
};
struct src_stage {
@@ -70,20 +71,13 @@ struct src_state {
int fir_delay_size;
int out_delay_size;
int fir_wi;
- int fir_ri;
- int out_wi;
int out_ri;
int32_t *fir_delay;
int32_t *out_delay;
};
struct polyphase_src {
- int mute;
int number_of_stages;
- int blk_in;
- int blk_out;
- int stage1_times;
- int stage2_times;
struct src_stage *stage1;
struct src_stage *stage2;
struct src_state state1;
@@ -91,15 +85,14 @@ struct polyphase_src {
};
struct src_stage_prm {
+ int nch;
int times;
int32_t *x_rptr;
int32_t *x_end_addr;
size_t x_size;
- int x_inc;
int32_t *y_wptr;
int32_t *y_end_addr;
size_t y_size;
- int y_inc;
struct src_state *state;
struct src_stage *stage;
};
@@ -116,31 +109,6 @@ static inline void src_circ_dec_wrap(int32_t **ptr, int32_t *addr, size_t size)
*ptr = (int32_t *) ((size_t) * ptr + size);
}
-static inline void src_polyphase_mute(struct polyphase_src *src)
-{
- src->mute = 1;
-}
-
-static inline void src_polyphase_unmute(struct polyphase_src *src)
-{
- src->mute = 0;
-}
-
-static inline int src_polyphase_getmute(struct polyphase_src *src)
-{
- return src->mute;
-}
-
-static inline int src_polyphase_get_blk_in(struct polyphase_src *src)
-{
- return src->blk_in;
-}
-
-static inline int src_polyphase_get_blk_out(struct polyphase_src *src)
-{
- return src->blk_out;
-}
-
void src_polyphase_reset(struct polyphase_src *src);
int src_polyphase_init(struct polyphase_src *src, struct src_param *p,
@@ -162,8 +130,4 @@ int32_t src_output_rates(void);
int src_ceil_divide(int a, int b);
-#ifdef MODULE_TEST
-void src_print_info(struct polyphase_src *src);
-#endif
-
#endif
--
2.11.0
2
1

[Sound-open-firmware] [PATCH] trace: dma: Add atomic and nowait DMA tracing support.
by Liam Girdwood 19 Oct '17
by Liam Girdwood 19 Oct '17
19 Oct '17
Add support for DMA trace to run in atomic and IRQ contexts. Currently
DMA trace would sleep between DMA copies and enter atomic state when
inserting new tarce data into the trace buffer.
This patch adds new DMA _nowait() APIs that dont sleep and _atomic() APIs
for trace logging that can be safely called in atomic context.
Signed-off-by: Liam Girdwood <liam.r.girdwood(a)linux.intel.com>
---
src/audio/dma-trace.c | 144 ++++++++++++++++++++--------------
src/include/reef/audio/dma-trace.h | 1 +
src/include/reef/dma.h | 4 +
src/include/reef/trace.h | 12 +++
src/ipc/dma-copy.c | 157 ++++++++++++++++++++++++++++++++++---
src/lib/trace.c | 56 ++++++++++++-
6 files changed, 301 insertions(+), 73 deletions(-)
diff --git a/src/audio/dma-trace.c b/src/audio/dma-trace.c
index 9704733..b0267fa 100644
--- a/src/audio/dma-trace.c
+++ b/src/audio/dma-trace.c
@@ -47,9 +47,7 @@ static uint64_t trace_work(void *data, uint64_t delay)
struct dma_trace_buf *buffer = &d->dmatb;
struct dma_sg_config *config = &d->config;
unsigned long flags;
- int32_t offset = 0;
uint32_t avail = buffer->avail;
- uint32_t bytes_copied = 0;
uint32_t size;
uint32_t hsize;
uint32_t lsize;
@@ -58,53 +56,51 @@ static uint64_t trace_work(void *data, uint64_t delay)
if (avail == 0)
return DMA_TRACE_US;
+ /* make sure we dont write more than buffer */
+ if (avail > DMA_TRACE_LOCAL_SIZE)
+ avail = DMA_TRACE_LOCAL_SIZE;
+
/* copy to host in sections if we wrap */
- while (avail > 0) {
-
- lsize = hsize = avail;
-
- /* host buffer wrap ? */
- if (d->host_offset + buffer->avail > d->host_size)
- hsize = d->host_offset + buffer->avail - d->host_size;
-
- /* local buffer wrap ? */
- if (buffer->r_ptr > buffer->w_ptr)
- lsize = buffer->end_addr - buffer->r_ptr;
-
- /* get smallest size */
- if (hsize < lsize)
- size = hsize;
- else
- size = lsize;
-
- /* writeback trace data */
- dcache_writeback_region((void*)buffer->r_ptr, size);
-
- /* copy this section to host */
- offset = dma_copy_to_host(&d->dc, config, d->host_offset,
- buffer->r_ptr, size);
- if (offset < 0) {
- trace_buffer_error("ebb");
- goto out;
- }
-
- /* update host pointer and check for wrap */
- d->host_offset += size;
- if (d->host_offset + size >= d->host_size)
- d->host_offset = 0;
-
- /* update local pointer and check for wrap */
- buffer->r_ptr += size;
- if (buffer->r_ptr >= buffer->end_addr)
- buffer->r_ptr = buffer->addr;
-
- avail -= size;
- bytes_copied += size;
+ lsize = hsize = avail;
+
+ /* host buffer wrap ? */
+ if (d->host_offset + avail > d->host_size)
+ hsize = d->host_size - d->host_offset;
+
+ /* local buffer wrap ? */
+ if (buffer->r_ptr + avail > buffer->end_addr)
+ lsize = buffer->end_addr - buffer->r_ptr;
+
+ /* get smallest size */
+ if (hsize < lsize)
+ size = hsize;
+ else
+ size = lsize;
+
+ /* writeback trace data */
+ dcache_writeback_region((void*)buffer->r_ptr, size);
+
+ /* copy this section to host */
+ size = dma_copy_to_host_nowait(&d->dc, config, d->host_offset,
+ buffer->r_ptr, size);
+ if (size < 0) {
+ trace_buffer_error("ebb");
+ goto out;
}
+ /* update host pointer and check for wrap */
+ d->host_offset += size;
+ if (d->host_offset + size >= d->host_size)
+ d->host_offset = 0;
+
+ /* update local pointer and check for wrap */
+ buffer->r_ptr += size;
+ if (buffer->r_ptr >= buffer->end_addr)
+ buffer->r_ptr = buffer->addr;
+
out:
spin_lock_irq(&d->lock, flags);
- buffer->avail -= bytes_copied;
+ buffer->avail -= size;
spin_unlock_irq(&d->lock, flags);
/* reschedule the trace copying work */
@@ -172,32 +168,28 @@ int dma_trace_enable(struct dma_trace_data *d)
{
/* validate DMA context */
if (d->dc.dmac == NULL || d->dc.chan < 0) {
- trace_buffer_error("eem");
+ trace_error_atomic(TRACE_CLASS_BUFFER, "eem");
return -ENODEV;
}
/* TODO: fix crash when enabled */
- //d->enabled = 1;
+ d->enabled = 1;
work_schedule_default(&d->dmat_work, DMA_TRACE_US);
return 0;
}
-void dtrace_event(const char *e, uint32_t length)
+static void dtrace_add_event(const char *e, uint32_t length)
{
- struct dma_trace_buf *buffer = NULL;
- int margin = 0;
- unsigned long flags;
+ struct dma_trace_buf *buffer = &trace_data->dmatb;
+ int margin;
- if (trace_data == NULL || length == 0)
- return;
+ margin = buffer->end_addr - buffer->w_ptr;
- buffer = &trace_data->dmatb;
- if (buffer == NULL)
+ /* validate */
+ if (margin <= 0) {
+ trace_buffer_error("emm");
return;
-
- spin_lock_irq(&trace_data->lock, flags);
-
- margin = buffer->end_addr - buffer->w_ptr;
+ }
/* check for buffer wrap */
if (margin > length) {
@@ -216,9 +208,45 @@ void dtrace_event(const char *e, uint32_t length)
}
buffer->avail += length;
+}
+
+void dtrace_event(const char *e, uint32_t length)
+{
+ struct dma_trace_buf *buffer = NULL;
+ unsigned long flags;
+
+ if (trace_data == NULL || length == 0)
+ return;
+
+ if (!trace_data->enabled)
+ return;
+
+ buffer = &trace_data->dmatb;
+ if (buffer == NULL)
+ return;
+
+ spin_lock_irq(&trace_data->lock, flags);
+ dtrace_add_event(e, length);
spin_unlock_irq(&trace_data->lock, flags);
/* schedule copy now if buffer > 50% full */
if (trace_data->enabled && buffer->avail >= (DMA_TRACE_LOCAL_SIZE / 2))
work_reschedule_default(&trace_data->dmat_work, 100);
}
+
+void dtrace_event_atomic(const char *e, uint32_t length)
+{
+ struct dma_trace_buf *buffer = NULL;
+
+ if (trace_data == NULL || length == 0)
+ return;
+
+ if (!trace_data->enabled)
+ return;
+
+ buffer = &trace_data->dmatb;
+ if (buffer == NULL)
+ return;
+
+ dtrace_add_event(e, length);
+}
diff --git a/src/include/reef/audio/dma-trace.h b/src/include/reef/audio/dma-trace.h
index 83db484..12d0956 100644
--- a/src/include/reef/audio/dma-trace.h
+++ b/src/include/reef/audio/dma-trace.h
@@ -69,5 +69,6 @@ int dma_trace_host_buffer(struct dma_trace_data *d, struct dma_sg_elem *elem,
int dma_trace_enable(struct dma_trace_data *d);
void dtrace_event(const char *e, uint32_t size);
+void dtrace_event_atomic(const char *e, uint32_t length);
#endif
diff --git a/src/include/reef/dma.h b/src/include/reef/dma.h
index 33d1c9a..8dd4adf 100644
--- a/src/include/reef/dma.h
+++ b/src/include/reef/dma.h
@@ -249,9 +249,13 @@ static inline void dma_copy_free(struct dma_copy *dc)
/* DMA copy data from host to DSP */
int dma_copy_from_host(struct dma_copy *dc, struct dma_sg_config *host_sg,
int32_t host_offset, void *local_ptr, int32_t size);
+int dma_copy_from_host_nowait(struct dma_copy *dc, struct dma_sg_config *host_sg,
+ int32_t host_offset, void *local_ptr, int32_t size);
/* DMA copy data from DSP to host */
int dma_copy_to_host(struct dma_copy *dc, struct dma_sg_config *host_sg,
int32_t host_offset, void *local_ptr, int32_t size);
+int dma_copy_to_host_nowait(struct dma_copy *dc, struct dma_sg_config *host_sg,
+ int32_t host_offset, void *local_ptr, int32_t size);
#endif
diff --git a/src/include/reef/trace.h b/src/include/reef/trace.h
index cdd8158..17dff5c 100644
--- a/src/include/reef/trace.h
+++ b/src/include/reef/trace.h
@@ -95,6 +95,8 @@
void _trace_event(uint32_t event);
void _trace_error(uint32_t event);
+void _trace_event_atomic(uint32_t event);
+void _trace_error_atomic(uint32_t event);
void trace_off(void);
void trace_init(struct reef * reef);
@@ -102,8 +104,11 @@ void trace_init(struct reef * reef);
#define trace_event(__c, __e) \
_trace_event(__c | (__e[0] << 16) | (__e[1] <<8) | __e[2])
+#define trace_event_atomic(__c, __e) \
+ _trace_event_atomic(__c | (__e[0] << 16) | (__e[1] <<8) | __e[2])
#define trace_value(x) _trace_event(x)
+#define trace_value_atomic(x) _trace_event_atomic(x)
#define trace_point(x) platform_trace_point(x)
@@ -111,17 +116,24 @@ void trace_init(struct reef * reef);
#if TRACEV
#define tracev_event(__c, __e) trace_event(__c, __e)
#define tracev_value(x) _trace_event(x)
+#define tracev_event_atomic(__c, __e) trace_event_atomic(__c, __e)
+#define tracev_value_atomic(x) _trace_event_atomic(x)
#else
#define tracev_event(__c, __e)
#define tracev_value(x)
+#define tracev_event_atomic(__c, __e)
+#define tracev_value_atomic(x)
#endif
/* error tracing */
#if TRACEE
#define trace_error(__c, __e) \
_trace_error(__c | (__e[0] << 16) | (__e[1] <<8) | __e[2])
+#define trace_error_atomic(__c, __e) \
+ _trace_error_atomic(__c | (__e[0] << 16) | (__e[1] <<8) | __e[2])
#else
#define trace_error(__c, __e)
+#define trace_error_atomic(__c, __e)
#endif
#else
diff --git a/src/ipc/dma-copy.c b/src/ipc/dma-copy.c
index 75dd3bd..5c9ff97 100644
--- a/src/ipc/dma-copy.c
+++ b/src/ipc/dma-copy.c
@@ -75,8 +75,14 @@ static void dma_complete(void *data, uint32_t type, struct dma_sg_elem *next)
if (type == DMA_IRQ_TYPE_LLIST)
wait_completed(comp);
+
+ next->size = DMA_RELOAD_END;
}
+/* Copy DSP memory to host memory.
+ * copies DSP memory to host in PAGE_SIZE or smaller blocks and waits/sleeps
+ * between blocks. Cant be used in IRQ context.
+ */
int dma_copy_to_host(struct dma_copy *dc, struct dma_sg_config *host_sg,
int32_t host_offset, void *local_ptr, int32_t size)
{
@@ -85,6 +91,7 @@ int dma_copy_to_host(struct dma_copy *dc, struct dma_sg_config *host_sg,
struct dma_sg_elem local_sg_elem;
int32_t err;
int32_t offset = host_offset;
+ int32_t bytes_copied = 0;
if (size <= 0)
return 0;
@@ -104,7 +111,11 @@ int dma_copy_to_host(struct dma_copy *dc, struct dma_sg_config *host_sg,
/* configure local DMA elem */
local_sg_elem.dest = host_sg_elem->dest + offset;
local_sg_elem.src = (uint32_t)local_ptr;
- local_sg_elem.size = HOST_PAGE_SIZE - offset;
+ if (size >= HOST_PAGE_SIZE - offset)
+ local_sg_elem.size = HOST_PAGE_SIZE - offset;
+ else
+ local_sg_elem.size = size;
+
list_item_prepend(&local_sg_elem.list, &config.elem_list);
/* transfer max PAGE size at a time to SG buffer */
@@ -112,8 +123,13 @@ int dma_copy_to_host(struct dma_copy *dc, struct dma_sg_config *host_sg,
/* start the DMA */
wait_init(&dc->complete);
- dma_set_config(dc->dmac, dc->chan, &config);
- dma_start(dc->dmac, dc->chan);
+ err = dma_set_config(dc->dmac, dc->chan, &config);
+ if (err < 0)
+ return err;
+
+ err = dma_start(dc->dmac, dc->chan);
+ if (err < 0)
+ return err;
/* wait for DMA to complete */
err = wait_for_completion_timeout(&dc->complete);
@@ -127,12 +143,15 @@ int dma_copy_to_host(struct dma_copy *dc, struct dma_sg_config *host_sg,
host_offset += local_sg_elem.size;
/* next dest host address is in next host elem */
+
host_sg_elem = list_next_item(host_sg_elem, list);
local_sg_elem.dest = host_sg_elem->dest;
/* local address is continuous */
local_sg_elem.src = (uint32_t)local_ptr + local_sg_elem.size;
+ bytes_copied += local_sg_elem.size;
+
/* do we have less than 1 PAGE to copy ? */
if (size >= HOST_PAGE_SIZE)
local_sg_elem.size = HOST_PAGE_SIZE;
@@ -140,10 +159,65 @@ int dma_copy_to_host(struct dma_copy *dc, struct dma_sg_config *host_sg,
local_sg_elem.size = size;
}
- /* new host offset in SG buffer */
- return host_offset;
+ /* bytes copied */
+ return bytes_copied;
+}
+
+/* Copy DSP memory to host memory.
+ * Copies DSP memory to host in a single PAGE_SIZE or smaller block. Does not
+ * waits/sleeps and can be used in IRQ context.
+ */
+int dma_copy_to_host_nowait(struct dma_copy *dc, struct dma_sg_config *host_sg,
+ int32_t host_offset, void *local_ptr, int32_t size)
+{
+ struct dma_sg_config config;
+ struct dma_sg_elem *host_sg_elem;
+ struct dma_sg_elem local_sg_elem;
+ int32_t err;
+ int32_t offset = host_offset;
+
+ if (size <= 0)
+ return 0;
+
+ /* find host element with host_offset */
+ host_sg_elem = sg_get_elem_at(host_sg, &offset);
+ if (host_sg_elem == NULL)
+ return -EINVAL;
+
+ /* set up DMA configuration */
+ config.direction = DMA_DIR_LMEM_TO_HMEM;
+ config.src_width = sizeof(uint32_t);
+ config.dest_width = sizeof(uint32_t);
+ config.cyclic = 0;
+ list_init(&config.elem_list);
+
+ /* configure local DMA elem */
+ local_sg_elem.dest = host_sg_elem->dest + offset;
+ local_sg_elem.src = (uint32_t)local_ptr;
+ if (size >= HOST_PAGE_SIZE - offset)
+ local_sg_elem.size = HOST_PAGE_SIZE - offset;
+ else
+ local_sg_elem.size = size;
+
+ list_item_prepend(&local_sg_elem.list, &config.elem_list);
+
+ /* start the DMA */
+ err = dma_set_config(dc->dmac, dc->chan, &config);
+ if (err < 0)
+ return err;
+
+ err = dma_start(dc->dmac, dc->chan);
+ if (err < 0)
+ return err;
+
+ /* bytes copied */
+ return local_sg_elem.size;
}
+/* Copy host memory to DSP memory.
+ * Copies host memory to host in PAGE_SIZE or smaller blocks and waits/sleeps
+ * between blocks. Cant be used in IRQ context.
+ */
int dma_copy_from_host(struct dma_copy *dc, struct dma_sg_config *host_sg,
int32_t host_offset, void *local_ptr, int32_t size)
{
@@ -152,6 +226,7 @@ int dma_copy_from_host(struct dma_copy *dc, struct dma_sg_config *host_sg,
struct dma_sg_elem local_sg_elem;
int32_t err;
int32_t offset = host_offset;
+ int32_t bytes_copied = 0;
if (size <= 0)
return 0;
@@ -171,7 +246,10 @@ int dma_copy_from_host(struct dma_copy *dc, struct dma_sg_config *host_sg,
/* configure local DMA elem */
local_sg_elem.dest = (uint32_t)local_ptr;
local_sg_elem.src = host_sg_elem->src + offset;
- local_sg_elem.size = HOST_PAGE_SIZE - offset;
+ if (size >= HOST_PAGE_SIZE - offset)
+ local_sg_elem.size = HOST_PAGE_SIZE - offset;
+ else
+ local_sg_elem.size = size;
list_item_prepend(&local_sg_elem.list, &config.elem_list);
/* transfer max PAGE size at a time to SG buffer */
@@ -179,9 +257,14 @@ int dma_copy_from_host(struct dma_copy *dc, struct dma_sg_config *host_sg,
/* start the DMA */
wait_init(&dc->complete);
- dma_set_config(dc->dmac, dc->chan, &config);
- dma_start(dc->dmac, dc->chan);
-
+ err = dma_set_config(dc->dmac, dc->chan, &config);
+ if (err < 0)
+ return err;
+
+ err = dma_start(dc->dmac, dc->chan);
+ if (err < 0)
+ return err;
+
/* wait for DMA to complete */
err = wait_for_completion_timeout(&dc->complete);
if (err < 0) {
@@ -200,6 +283,8 @@ int dma_copy_from_host(struct dma_copy *dc, struct dma_sg_config *host_sg,
/* local address is continuous */
local_sg_elem.dest = (uint32_t)local_ptr + local_sg_elem.size;
+ bytes_copied += local_sg_elem.size;
+
/* do we have less than 1 PAGE to copy ? */
if (size >= HOST_PAGE_SIZE)
local_sg_elem.size = HOST_PAGE_SIZE;
@@ -207,8 +292,58 @@ int dma_copy_from_host(struct dma_copy *dc, struct dma_sg_config *host_sg,
local_sg_elem.size = size;
}
- /* new host offset in SG buffer */
- return host_offset;
+ /* bytes copied */
+ return bytes_copied;
+}
+
+/* Copy host memory to DSP memory.
+ * Copies host memory to DSP in a single PAGE_SIZE or smaller block. Does not
+ * waits/sleeps and can be used in IRQ context.
+ */
+int dma_copy_from_host_nowait(struct dma_copy *dc, struct dma_sg_config *host_sg,
+ int32_t host_offset, void *local_ptr, int32_t size)
+{
+ struct dma_sg_config config;
+ struct dma_sg_elem *host_sg_elem;
+ struct dma_sg_elem local_sg_elem;
+ int32_t err;
+ int32_t offset = host_offset;
+
+ if (size <= 0)
+ return 0;
+
+ /* find host element with host_offset */
+ host_sg_elem = sg_get_elem_at(host_sg, &offset);
+ if (host_sg_elem == NULL)
+ return -EINVAL;
+
+ /* set up DMA configuration */
+ config.direction = DMA_DIR_HMEM_TO_LMEM;
+ config.src_width = sizeof(uint32_t);
+ config.dest_width = sizeof(uint32_t);
+ config.cyclic = 0;
+ list_init(&config.elem_list);
+
+ /* configure local DMA elem */
+ local_sg_elem.dest = (uint32_t)local_ptr;
+ local_sg_elem.src = host_sg_elem->src + offset;
+ if (size >= HOST_PAGE_SIZE - offset)
+ local_sg_elem.size = HOST_PAGE_SIZE - offset;
+ else
+ local_sg_elem.size = size;
+ list_item_prepend(&local_sg_elem.list, &config.elem_list);
+
+ /* start the DMA */
+ err = dma_set_config(dc->dmac, dc->chan, &config);
+ if (err < 0)
+ return err;
+
+ err = dma_start(dc->dmac, dc->chan);
+ if (err < 0)
+ return err;
+
+ /* bytes copied */
+ return local_sg_elem.size;
}
int dma_copy_new(struct dma_copy *dc, int dmac)
diff --git a/src/lib/trace.c b/src/lib/trace.c
index 6f707c3..c0abf7c 100644
--- a/src/lib/trace.c
+++ b/src/lib/trace.c
@@ -49,30 +49,66 @@ void _trace_error(uint32_t event)
{
unsigned long flags;
volatile uint64_t *t;
+ uint64_t dt[2];
+ uint64_t time;
if (!trace.enable)
return;
+ time = platform_timer_get(platform_timer);
+
/* save event to DMA tracing buffer */
- _trace_event(event);
+ dt[0] = time;
+ dt[1] = event;
+ dtrace_event((const char*)dt, sizeof(uint64_t) * 2);
/* send event by mail box too. */
spin_lock_irq(&trace.lock, flags);
/* write timestamp and event to trace buffer */
t = (volatile uint64_t*)(MAILBOX_TRACE_BASE + trace.pos);
- t[0] = platform_timer_get(platform_timer);
+ trace.pos += (sizeof(uint64_t) << 1);
+
+ if (trace.pos > MAILBOX_TRACE_SIZE - sizeof(uint64_t) * 2)
+ trace.pos = 0;
+
+ spin_unlock_irq(&trace.lock, flags);
+
+ t[0] = time;
t[1] = event;
/* writeback trace data */
dcache_writeback_region((void*)t, sizeof(uint64_t) * 2);
+}
+
+void _trace_error_atomic(uint32_t event)
+{
+ volatile uint64_t *t;
+ uint64_t dt[2];
+ uint64_t time;
+
+ if (!trace.enable)
+ return;
+
+ time = platform_timer_get(platform_timer);
+
+ /* save event to DMA tracing buffer */
+ dt[0] = time;
+ dt[1] = event;
+ dtrace_event_atomic((const char*)dt, sizeof(uint64_t) * 2);
+ /* write timestamp and event to trace buffer */
+ t = (volatile uint64_t*)(MAILBOX_TRACE_BASE + trace.pos);
trace.pos += (sizeof(uint64_t) << 1);
if (trace.pos > MAILBOX_TRACE_SIZE - sizeof(uint64_t) * 2)
trace.pos = 0;
- spin_unlock_irq(&trace.lock, flags);
+ t[0] = time;
+ t[1] = event;
+
+ /* writeback trace data */
+ dcache_writeback_region((void*)t, sizeof(uint64_t) * 2);
}
void _trace_event(uint32_t event)
@@ -87,10 +123,22 @@ void _trace_event(uint32_t event)
dtrace_event((const char*)dt, sizeof(uint64_t) * 2);
}
+void _trace_event_atomic(uint32_t event)
+{
+ uint64_t dt[2];
+
+ if (!trace.enable)
+ return;
+
+ dt[0] = platform_timer_get(platform_timer);
+ dt[1] = event;
+ dtrace_event_atomic((const char*)dt, sizeof(uint64_t) * 2);
+}
+
void trace_off(void)
{
trace.enable = 0;
-};
+}
void trace_init(struct reef *reef)
{
--
2.11.0
1
5