Sound-open-firmware
Threads by month
- ----- 2024 -----
- 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
- 1495 discussions
---
src/audio/Makefile.am | 2 +
src/audio/eq_iir.c | 496 +++++++++++++++++++++++++++++++++++++
src/audio/eq_iir.h | 83 +++++++
src/audio/iir.c | 161 ++++++++++++
src/audio/iir.h | 75 ++++++
src/include/reef/audio/component.h | 3 +
src/include/reef/trace.h | 1 +
src/include/uapi/ipc.h | 10 +
src/tasks/audio.c | 1 +
9 files changed, 832 insertions(+)
create mode 100644 src/audio/eq_iir.c
create mode 100644 src/audio/eq_iir.h
create mode 100644 src/audio/iir.c
create mode 100644 src/audio/iir.h
diff --git a/src/audio/Makefile.am b/src/audio/Makefile.am
index 1da6757..285422e 100644
--- a/src/audio/Makefile.am
+++ b/src/audio/Makefile.am
@@ -1,6 +1,8 @@
noinst_LIBRARIES = libaudio.a
libaudio_a_SOURCES = \
+ eq_iir.c \
+ iir.c \
eq_fir.c \
fir.c \
tone.c \
diff --git a/src/audio/eq_iir.c b/src/audio/eq_iir.c
new file mode 100644
index 0000000..96570b2
--- /dev/null
+++ b/src/audio/eq_iir.c
@@ -0,0 +1,496 @@
+/*
+ * Copyright (c) 2017, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Intel Corporation nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Seppo Ingalsuo <seppo.ingalsuo(a)linux.intel.com>
+ * Liam Girdwood <liam.r.girdwood(a)linux.intel.com>
+ * Keyon Jie <yang.jie(a)linux.intel.com>
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <errno.h>
+#include <reef/reef.h>
+#include <reef/lock.h>
+#include <reef/list.h>
+#include <reef/stream.h>
+#include <reef/alloc.h>
+#include <reef/work.h>
+#include <reef/clock.h>
+#include <reef/audio/component.h>
+#include <reef/audio/pipeline.h>
+#include <reef/audio/format.h>
+#include "eq_iir.h"
+#include "iir.h"
+
+#ifdef MODULE_TEST
+#include <stdio.h>
+#endif
+
+#define trace_eq_iir(__e) trace_event(TRACE_CLASS_EQ_IIR, __e)
+#define tracev_eq_iir(__e) tracev_event(TRACE_CLASS_EQ_IIR, __e)
+#define trace_eq_iir_error(__e) trace_error(TRACE_CLASS_EQ_IIR, __e)
+
+/* src component private data */
+struct comp_data {
+ struct eq_iir_configuration *config;
+ struct iir_state_df2t iir[PLATFORM_MAX_CHANNELS];
+ void (*eq_iir_func)(struct comp_dev *dev,
+ struct comp_buffer *source,
+ struct comp_buffer *sink,
+ uint32_t frames);
+};
+
+/*
+ * EQ IIR algorithm code
+ */
+
+static void eq_iir_s32_default(struct comp_dev *dev,
+ struct comp_buffer *source, struct comp_buffer *sink, uint32_t frames)
+{
+
+ int ch, n, n_wrap_src, n_wrap_snk, n_wrap_min;
+ int32_t *src = (int32_t *) source->r_ptr;
+ int32_t *snk = (int32_t *) sink->w_ptr;
+ int nch = source->params.pcm->channels;
+ int32_t *x = src + nch - 1;
+ int32_t *y = snk + nch - 1;
+ struct comp_data *cd = comp_get_drvdata(dev);
+
+
+ for (ch = 0; ch < nch; ch++) {
+ n = frames * nch;
+ x = src++;
+ y = snk++;
+ while (n > 0) {
+ n_wrap_src = (int32_t *) source->end_addr - x;
+ n_wrap_snk = (int32_t *) sink->end_addr - y;
+ n_wrap_min = (n_wrap_src < n_wrap_snk) ?
+ n_wrap_src : n_wrap_snk;
+ if (n < n_wrap_min) {
+ /* No circular wrap need */
+ while (n > 0) {
+ *y = iir_df2t(&cd->iir[ch], *x);
+ x += nch;
+ y += nch;
+ n -= nch;
+ }
+ } else {
+ /* Wrap in n_wrap_min/nch samples */
+ while (n_wrap_min > 0) {
+ *y = iir_df2t(&cd->iir[ch], *x);
+ x += nch;
+ y += nch;
+ n_wrap_min -= nch;
+ n -= nch;
+ }
+ /* Check both source and destination for wrap */
+ if (x > (int32_t *) source->end_addr)
+ x = (int32_t *)
+ ((size_t) x - source->alloc_size);
+ if (snk > (int32_t *) sink->end_addr)
+ y = (int32_t *)
+ ((size_t) y - sink->alloc_size);
+ }
+ }
+
+ }
+ source->r_ptr = x - nch + 1; /* After previous loop the x and y */
+ sink->w_ptr = y - nch + 1; /* point to one frame -1. */
+
+ comp_wrap_source_r_ptr_circular(source);
+ comp_wrap_sink_w_ptr_circular(sink);
+ comp_update_source_free_avail(source, frames * nch);
+ comp_update_sink_free_avail(sink, frames * nch);
+}
+
+static void eq_iir_free_parameters(struct eq_iir_configuration **config)
+{
+ if (*config != NULL)
+ rfree(*config);
+
+ *config = NULL;
+}
+
+static void eq_iir_free_delaylines(struct iir_state_df2t *iir)
+{
+ int i = 0;
+ int64_t *delay = NULL; /* TODO should not need to know the type */
+
+ /* 1st active EQ delay line data is at beginning of the single
+ * allocated buffer
+ */
+ for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) {
+ if ((iir[i].delay != NULL) && (delay == NULL))
+ delay = iir[i].delay;
+
+ /* Point all delays to NULL to avoid duplicated free later */
+ iir[i].delay = NULL;
+ }
+
+ if (delay != NULL)
+ rfree(delay);
+
+}
+
+static int eq_iir_setup(struct iir_state_df2t iir[],
+ struct eq_iir_configuration *config, int nch)
+{
+ int i, j, idx, resp;
+ size_t s;
+ size_t size_sum = 0;
+ int64_t *iir_delay; /* TODO should not need to know the type */
+ int response_index[PLATFORM_MAX_CHANNELS];
+
+ if (nch > PLATFORM_MAX_CHANNELS)
+ return -EINVAL;
+
+ /* Free existing IIR channels data if it was allocated */
+ eq_iir_free_delaylines(iir);
+
+ /* Collect index of respose start positions in all_coefficients[] */
+ j = 0;
+ for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) {
+ if (i < config->number_of_responses_defined) {
+ response_index[i] = j;
+ j += NHEADER_DF2T
+ + NBIQUAD_DF2T * config->all_coefficients[j];
+ } else {
+ response_index[i] = 0;
+ }
+ }
+
+ /* Initialize 1st phase */
+ for (i = 0; i < nch; i++) {
+ resp = config->assign_response[i];
+ if (resp < 0) {
+ /* Initialize EQ channel to bypass */
+ iir_reset_df2t(&iir[i]);
+ } else {
+ /* Initialize EQ coefficients */
+ idx = response_index[resp];
+ s = iir_init_coef_df2t(&iir[i],
+ &config->all_coefficients[idx]);
+ if (s > 0)
+ size_sum += s;
+ else
+ return -EINVAL;
+ }
+
+ }
+
+ /* Allocate all IIR channels data in a big chunk and clear it */
+ iir_delay = rmalloc(RZONE_RUNTIME, RFLAGS_NONE, size_sum);
+ if (iir_delay == NULL)
+ return -EINVAL;
+
+ memset(iir_delay, 0, size_sum);
+
+ /* Initialize 2nd phase to set EQ delay lines pointers */
+ for (i = 0; i < nch; i++) {
+ resp = config->assign_response[i];
+ if (resp >= 0) {
+ idx = response_index[resp];
+ iir_init_delay_df2t(&iir[i], &iir_delay);
+ }
+
+ }
+
+ return 0;
+}
+
+static int eq_iir_switch_response(struct iir_state_df2t iir[],
+ struct eq_iir_configuration *config, struct eq_iir_update *update,
+ int nch)
+{
+ int i;
+
+ /* Copy assign response from update and re-initilize EQ */
+ if (config == NULL)
+ return -EINVAL;
+
+ for (i = 0; i < config->stream_max_channels; i++) {
+ if (i < update->stream_max_channels)
+ config->assign_response[i] = update->assign_response[i];
+ }
+
+ eq_iir_setup(iir, config, nch);
+
+ return 0;
+}
+
+/*
+ * End of EQ setup code. Next the standard component methods.
+ */
+
+static struct comp_dev *eq_iir_new(struct sof_ipc_comp *comp)
+{
+ int i;
+ //struct comp_buffer *sink;
+ //struct comp_buffer *source;
+ struct comp_dev *dev;
+ struct comp_data *cd;
+
+ trace_eq_iir("ENw");
+ dev = rmalloc(RZONE_RUNTIME, RFLAGS_NONE, sizeof(*dev));
+ if (dev == NULL)
+ return NULL;
+
+ //memcpy(&dev->comp, comp, sizeof(struct sof_ipc_comp_eq_iir));
+
+ cd = rmalloc(RZONE_RUNTIME, RFLAGS_NONE, sizeof(*cd));
+ if (cd == NULL) {
+ rfree(dev);
+ return NULL;
+ }
+
+ comp_set_drvdata(dev, cd);
+
+ cd->eq_iir_func = eq_iir_s32_default;
+ cd->config = NULL;
+ for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
+ iir_reset_df2t(&cd->iir[i]);
+
+ return dev;
+}
+
+static void eq_iir_free(struct comp_dev *dev)
+{
+ struct comp_data *cd = comp_get_drvdata(dev);
+
+ trace_eq_iir("EFr");
+
+ eq_iir_free_delaylines(cd->iir);
+ eq_iir_free_parameters(&cd->config);
+
+ rfree(cd);
+ rfree(dev);
+}
+
+/* set component audio stream parameters */
+static int eq_iir_params(struct comp_dev *dev, struct stream_params *params)
+{
+
+ trace_eq_iir("EPa");
+
+ /* EQ supports only S32_LE PCM format */
+ if ((params->type != STREAM_TYPE_PCM)
+ || (params->pcm->frame_fmt != SOF_IPC_FRAME_S32_LE))
+ return -EINVAL;
+
+ /* don't do any data transformation */
+ comp_set_sink_params(dev, params);
+
+ return 0;
+}
+
+/* used to pass standard and bespoke commands (with data) to component */
+static int eq_iir_cmd(struct comp_dev *dev, int cmd, void *data)
+{
+ trace_eq_iir("ECm");
+ struct comp_data *cd = comp_get_drvdata(dev);
+ struct comp_buffer *source = list_first_item(&dev->bsource_list,
+ struct comp_buffer, sink_list);
+ struct sof_ipc_eq_iir_switch *assign;
+ struct sof_ipc_eq_iir_blob *blob;
+ int i;
+ size_t bs;
+ switch (cmd) {
+ case COMP_CMD_EQ_IIR_SWITCH:
+ trace_eq_iir("EFx");
+ assign = (struct sof_ipc_eq_iir_switch *) data;
+ eq_iir_switch_response(cd->iir, cd->config,
+ (struct eq_iir_update *) assign->data,
+ source->params.pcm->channels);
+ break;
+ case COMP_CMD_EQ_IIR_CONFIG:
+ trace_eq_iir("EFc");
+ /* Check and free old config */
+ eq_iir_free_parameters(&cd->config);
+
+ /* Copy new config, need to decode data to know the size */
+ blob = (struct sof_ipc_eq_iir_blob *) data;
+ bs = blob->hdr.size - sizeof(struct sof_ipc_hdr);
+ if (bs > EQ_IIR_MAX_BLOB_SIZE)
+ return -EINVAL;
+
+ /* Allocate and make a copy of the blob and setup IIR */
+ cd->config = rmalloc(RZONE_RUNTIME, RFLAGS_NONE, bs);
+ if (cd->config != NULL)
+ memcpy(cd->config, blob->data, bs);
+
+ eq_iir_setup(cd->iir, cd->config, source->params.pcm->channels);
+ break;
+ case COMP_CMD_MUTE:
+ trace_eq_iir("EFm");
+ for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
+ iir_mute_df2t(&cd->iir[i]);
+
+ break;
+ case COMP_CMD_UNMUTE:
+ trace_eq_iir("EFu");
+ for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
+ iir_unmute_df2t(&cd->iir[i]);
+
+ break;
+ case COMP_CMD_START:
+ trace_eq_iir("EFs");
+ dev->state = COMP_STATE_RUNNING;
+ break;
+ case COMP_CMD_STOP:
+ trace_eq_iir("ESp");
+ if (dev->state == COMP_STATE_RUNNING ||
+ dev->state == COMP_STATE_DRAINING ||
+ dev->state == COMP_STATE_PAUSED) {
+ comp_buffer_reset(dev);
+ dev->state = COMP_STATE_SETUP;
+ }
+ break;
+ case COMP_CMD_PAUSE:
+ trace_eq_iir("EPe");
+ /* only support pausing for running */
+ if (dev->state == COMP_STATE_RUNNING)
+ dev->state = COMP_STATE_PAUSED;
+
+ break;
+ case COMP_CMD_RELEASE:
+ trace_eq_iir("ERl");
+ dev->state = COMP_STATE_RUNNING;
+ break;
+ default:
+ trace_eq_iir("EDf");
+ break;
+ }
+
+ return 0;
+}
+
+/* copy and process stream data from source to sink buffers */
+static int eq_iir_copy(struct comp_dev *dev)
+{
+ struct comp_data *cd = comp_get_drvdata(dev);
+ struct comp_buffer *source;
+ struct comp_buffer *sink;
+ int frames;
+ int need_source, need_sink;
+
+ trace_comp("EqI");
+
+ /* src component needs 1 source and 1 sink buffer */
+ source = list_first_item(&dev->bsource_list, struct comp_buffer,
+ sink_list);
+ sink = list_first_item(&dev->bsink_list, struct comp_buffer,
+ source_list);
+
+ /* Check that source has enough frames available and that sink has
+ * enough frames free.
+ */
+ //frames = source->params.period_frames;
+ //need_source = frames * source->params.frame_size;
+ //need_sink = frames * sink->params.frame_size;
+ frames = source->params.pcm->period_count;
+ need_source = frames * source->params.pcm->frame_size;
+ need_sink = frames * sink->params.pcm->frame_size;
+
+ /* Run EQ if buffers have enough room */
+ if ((source->avail >= need_source) && (sink->free >= need_sink))
+ cd->eq_iir_func(dev, source, sink, frames);
+
+ return 0;
+}
+
+static int eq_iir_prepare(struct comp_dev *dev)
+{
+ struct comp_data *cd = comp_get_drvdata(dev);
+ struct comp_buffer *source;
+
+ trace_eq_iir("EPp");
+
+ cd->eq_iir_func = eq_iir_s32_default;
+
+ /* Initialize EQ */
+ if (cd->config == NULL)
+ return -EINVAL;
+
+ source = list_first_item(&dev->bsource_list, struct comp_buffer,
+ sink_list);
+ if (eq_iir_setup(cd->iir, cd->config, source->params.pcm->channels) < 0)
+ return -EINVAL;
+
+ //dev->preload = PLAT_INT_PERIODS;
+ dev->state = COMP_STATE_PREPARE;
+ return 0;
+}
+
+static int eq_iir_preload(struct comp_dev *dev)
+{
+ //int i;
+
+ trace_eq_iir("EPl");
+
+ //for (i = 0; i < dev->preload; i++)
+ // eq_iir_copy(dev);
+
+ return 0;
+}
+
+static int eq_iir_reset(struct comp_dev *dev)
+{
+ int i;
+ struct comp_data *cd = comp_get_drvdata(dev);
+
+ trace_eq_iir("ERe");
+
+ eq_iir_free_delaylines(cd->iir);
+ eq_iir_free_parameters(&cd->config);
+
+ cd->eq_iir_func = eq_iir_s32_default;
+ for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
+ iir_reset_df2t(&cd->iir[i]);
+
+ dev->state = COMP_STATE_INIT;
+ return 0;
+}
+
+struct comp_driver comp_eq_iir = {
+ .type = SOF_COMP_EQ_IIR,
+ .ops =
+ {
+ .new = eq_iir_new,
+ .free = eq_iir_free,
+ .params = eq_iir_params,
+ .cmd = eq_iir_cmd,
+ .copy = eq_iir_copy,
+ .prepare = eq_iir_prepare,
+ .reset = eq_iir_reset,
+ .preload = eq_iir_preload,
+ },
+};
+
+void sys_comp_eq_iir_init(void)
+{
+ comp_register(&comp_eq_iir);
+}
diff --git a/src/audio/eq_iir.h b/src/audio/eq_iir.h
new file mode 100644
index 0000000..43c666d
--- /dev/null
+++ b/src/audio/eq_iir.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Intel Corporation nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Seppo Ingalsuo <seppo.ingalsuo(a)linux.intel.com>
+ * Liam Girdwood <liam.r.girdwood(a)linux.intel.com>
+ * Keyon Jie <yang.jie(a)linux.intel.com>
+ */
+
+#ifndef EQ_IIR_H
+#define EQ_IIR_H
+
+
+
+/* eq_iir_configuration
+ * uint32_t platform max channels
+ * uint32_t number_of_responses_defined
+ * 0=no responses, 1=one response defined, 2=two responses defined, etc.
+ * uint32_t assign_response[PLATFORM_MAX_CHANNELS]
+ * -1 = not defined, 0 = use first response, 1 = use 2nd response, etc.
+ * E.g. {0, 0, 0, 0, -1, -1, -1, -1} would apply to channels 0-3 the
+ * same first defined response and leave channels 4-7 unequalized.
+ * all_coefficients[]
+ * <1st EQ>
+ * uint32_t num_biquads
+ * uint32_t num_biquads_in_series
+ * <1st biquad>
+ * int32_t coef_a2 Q2.30 format
+ * int32_t coef_a1 Q2.30 format
+ * int32_t coef_b2 Q2.30 format
+ * int32_t coef_b1 Q2.30 format
+ * int32_t coef_b0 Q2.30 format
+ * int32_t output_shift number of shifts right, shift left is negative
+ * int32_t output_gain Q2.14 format
+ * <2nd biquad>
+ * ...
+ * <2nd EQ>
+ *
+ * Note: A flat response biquad can be made with a section set to
+ * b0 = 1.0, gain = 1.0, and other parameters set to 0
+ * {0, 0, 0, 0, 1073741824, 0, 16484}
+ */
+
+#define EQ_IIR_MAX_BLOB_SIZE 1024
+
+#define NHEADER_EQ_IIR_BLOB 2 /* Blob is two words plus asssigns plus coef */
+
+struct eq_iir_configuration {
+ int32_t stream_max_channels;
+ int32_t number_of_responses_defined;
+ int32_t assign_response[PLATFORM_MAX_CHANNELS];
+ int32_t all_coefficients[];
+};
+
+struct eq_iir_update {
+ int32_t stream_max_channels;
+ int32_t assign_response[PLATFORM_MAX_CHANNELS];
+};
+
+#endif
diff --git a/src/audio/iir.c b/src/audio/iir.c
new file mode 100644
index 0000000..a713cdf
--- /dev/null
+++ b/src/audio/iir.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2017, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Intel Corporation nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Seppo Ingalsuo <seppo.ingalsuo(a)linux.intel.com>
+ * Liam Girdwood <liam.r.girdwood(a)linux.intel.com>
+ * Keyon Jie <yang.jie(a)linux.intel.com>
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <errno.h>
+
+#ifdef MODULE_TEST
+#include <stdio.h>
+#endif
+
+#include <reef/audio/format.h>
+#include "iir.h"
+
+/*
+ * Direct form II transposed second order filter block (biquad)
+ *
+ * +----+ +---+ +-------+
+ * X(z) ---o--->| b0 |---> + -------------o--->| g |--->| shift |---> Y(z)
+ * | +----+ ^ | +---+ +-------+
+ * | | |
+ * | +------+ |
+ * | | z^-1 | |
+ * | +------+ |
+ * | ^ |
+ * | +----+ | +----+ |
+ * o--->| b1 |---> + <---| a1 |---o
+ * | +----+ ^ +----+ |
+ * | | |
+ * | +------+ |
+ * | | z^-1 | |
+ * | +------+ |
+ * | ^ |
+ * | +----+ | +----+ |
+ * o--->| b2 |---> + <---| a2 |---+
+ * +----+ +----+
+ *
+ */
+
+/* Series DF2T IIR */
+
+/* 32 bit data, 32 bit coefficients and 64 bit state variables */
+
+int32_t iir_df2t(struct iir_state_df2t *iir, int32_t x)
+{
+ int32_t in, tmp;
+ int64_t acc;
+ int32_t out = 0;
+ int i, j;
+ int d = 0; /* Index to delays */
+ int c = 2; /* Index to coefficient a2 */
+
+ /* Coefficients order in coef[] is {a2, a1, b2, b1, b0, shift, gain} */
+ in = x;
+ for (j = 0; j < iir->biquads; j += iir->biquads_in_series) {
+ for (i = 0; i < iir->biquads_in_series; i++) {
+ /* Compute output: Delay is Q3.61
+ * Q2.30 x Q1.31 -> Q3.61
+ * Shift Q3.61 to Q3.31 with rounding
+ */
+ acc = ((int64_t) iir->coef[c + 4]) * in + iir->delay[d];
+ tmp = (int32_t) Q_SHIFT_RND(acc, 61, 31);
+
+ /* Compute 1st delay */
+ acc = iir->delay[d + 1];
+ acc += ((int64_t) iir->coef[c + 3]) * in; /* Coef b1 */
+ acc += ((int64_t) iir->coef[c + 1]) * tmp; /* Coef a1 */
+ iir->delay[d] = acc;
+
+ /* Compute 2nd delay */
+ acc = ((int64_t) iir->coef[c + 2]) * in; /* Coef b2 */
+ acc += ((int64_t) iir->coef[c]) * tmp; /* Coef a2 */
+ iir->delay[d + 1] = acc;
+
+ /* Gain, output shift, prepare for next biquad
+ * Q2.14 x Q1.31 -> Q3.45, shift too Q3.31 and saturate
+ */
+ acc = ((int64_t) iir->coef[c + 6]) * tmp; /* Gain */
+ acc = Q_SHIFT_RND(acc, 45 + iir->coef[c + 5], 31);
+ in = sat_int32(acc);
+ c += 7; /* Next coefficients section */
+ d += 2; /* Next biquad delays */
+ }
+ /* Output of previous section is in variable in */
+ out = sat_int32((int64_t) out + in);
+ }
+ return out;
+}
+
+size_t iir_init_coef_df2t(struct iir_state_df2t *iir, int32_t config[])
+{
+ iir->mute = 0;
+ iir->biquads = (int) config[0];
+ iir->biquads_in_series = (int) config[1];
+ iir->coef = &config[0]; /* TODO: Could change this to config[2] */
+ iir->delay = NULL;
+
+ if ((iir->biquads > IIR_DF2T_BIQUADS_MAX) || (iir->biquads < 1)) {
+ iir_reset_df2t(iir);
+ return -EINVAL;
+ }
+
+ return 2 * iir->biquads * sizeof(int64_t); /* Needed delay line size */
+}
+
+void iir_init_delay_df2t(struct iir_state_df2t *iir, int64_t **delay)
+{
+ iir->delay = *delay; /* Delay line of this IIR */
+ *delay += 2 * iir->biquads; /* Point to next IIR delay line start */
+
+}
+
+void iir_mute_df2t(struct iir_state_df2t *iir)
+{
+ iir->mute = 1;
+}
+
+void iir_unmute_df2t(struct iir_state_df2t *iir)
+{
+ iir->mute = 0;
+}
+
+void iir_reset_df2t(struct iir_state_df2t *iir)
+{
+ iir->mute = 1;
+ iir->biquads = 0;
+ iir->biquads_in_series = 0;
+ iir->coef = NULL;
+ /* Note: May need to know the beginning of dynamic allocation after so
+ * omitting setting iir->delay to NULL.
+ */
+}
diff --git a/src/audio/iir.h b/src/audio/iir.h
new file mode 100644
index 0000000..0de275a
--- /dev/null
+++ b/src/audio/iir.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Intel Corporation nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Seppo Ingalsuo <seppo.ingalsuo(a)linux.intel.com>
+ * Liam Girdwood <liam.r.girdwood(a)linux.intel.com>
+ * Keyon Jie <yang.jie(a)linux.intel.com>
+ */
+
+/* A full 22th order equalizer with 11 biquads cover octave bands 1-11 in
+ * in the 0 - 20 kHz bandwidth.
+ */
+#define IIR_DF2T_BIQUADS_MAX 11
+
+struct iir_state_df2t {
+ int mute; /* Set to 1 to mute EQ output, 0 otherwise */
+ int biquads; /* Number of IIR 2nd order sections total */
+ int biquads_in_series; /* Number of IIR 2nd order sections in series*/
+ int32_t *coef; /* Pointer to IIR coefficients */
+ int64_t *delay; /* Pointer to IIR delay line */
+};
+
+#define NHEADER_DF2T 2
+
+struct iir_header_df2t {
+ int32_t num_sections;
+ int32_t num_sections_in_series;
+};
+
+#define NBIQUAD_DF2T 7
+
+struct iir_biquad_df2t {
+ int32_t a2; /* Q2.30 */
+ int32_t a1; /* Q2.30 */
+ int32_t b2; /* Q2.30 */
+ int32_t b1; /* Q2.30 */
+ int32_t b0; /* Q2.30 */
+ int32_t output_shift; /* Number of right shifts */
+ int32_t output_gain; /* Q2.14 */
+};
+
+int32_t iir_df2t(struct iir_state_df2t *iir, int32_t x);
+
+size_t iir_init_coef_df2t(struct iir_state_df2t *iir, int32_t config[]);
+
+void iir_init_delay_df2t(struct iir_state_df2t *iir, int64_t **delay);
+
+void iir_mute_df2t(struct iir_state_df2t *iir);
+
+void iir_unmute_df2t(struct iir_state_df2t *iir);
+
+void iir_reset_df2t(struct iir_state_df2t *iir);
diff --git a/src/include/reef/audio/component.h b/src/include/reef/audio/component.h
index 7de47c2..7e28dfc 100644
--- a/src/include/reef/audio/component.h
+++ b/src/include/reef/audio/component.h
@@ -78,6 +78,8 @@
#define COMP_CMD_TONE 106 /* Tone generator amplitude and frequency */
#define COMP_CMD_EQ_FIR_CONFIG 107 /* Configuration data for FIR EQ */
#define COMP_CMD_EQ_FIR_SWITCH 108 /* Update request for FIR EQ */
+#define COMP_CMD_EQ_IIR_CONFIG 109 /* Configuration data for IIR EQ */
+#define COMP_CMD_EQ_IIR_SWITCH 110 /* Response update request for IIR EQ */
/* MMAP IPC status */
#define COMP_CMD_IPC_MMAP_RPOS 200 /* host read position */
@@ -263,6 +265,7 @@ void sys_comp_switch_init(void);
void sys_comp_volume_init(void);
void sys_comp_src_init(void);
void sys_comp_tone_init(void);
+void sys_comp_eq_iir_init(void);
void sys_comp_eq_fir_init(void);
diff --git a/src/include/reef/trace.h b/src/include/reef/trace.h
index ff41caf..00dbb5b 100644
--- a/src/include/reef/trace.h
+++ b/src/include/reef/trace.h
@@ -85,6 +85,7 @@
#define TRACE_CLASS_SRC (17 << 24)
#define TRACE_CLASS_TONE (18 << 24)
#define TRACE_CLASS_EQ_FIR (19 << 24)
+#define TRACE_CLASS_EQ_IIR (20 << 24)
/* move to config.h */
#define TRACE 1
diff --git a/src/include/uapi/ipc.h b/src/include/uapi/ipc.h
index 3bb6f61..20048b6 100644
--- a/src/include/uapi/ipc.h
+++ b/src/include/uapi/ipc.h
@@ -680,10 +680,20 @@ struct sof_ipc_eq_fir_blob {
int32_t data[];
} __attribute__((packed));
+struct sof_ipc_eq_iir_blob {
+ struct sof_ipc_hdr hdr;
+ struct sof_ipc_host_buffer buffer;
+ int32_t data[];
+} __attribute__((packed));
+
struct sof_ipc_eq_fir_switch {
struct sof_ipc_hdr hdr;
int32_t data[];
} __attribute__((packed));
+struct sof_ipc_eq_iir_switch {
+ struct sof_ipc_hdr hdr;
+ int32_t data[];
+} __attribute__((packed));
#endif
diff --git a/src/tasks/audio.c b/src/tasks/audio.c
index c420fb1..123b964 100644
--- a/src/tasks/audio.c
+++ b/src/tasks/audio.c
@@ -65,6 +65,7 @@ int do_task(struct reef *reef)
sys_comp_volume_init();
sys_comp_src_init();
sys_comp_tone_init();
+ sys_comp_eq_iir_init();
sys_comp_eq_fir_init();
#if 0
--
2.11.0
1
0
07 Jun '17
---
src/audio/Makefile.am | 2 +
src/audio/eq_fir.c | 487 +++++++++++++++++++++++++++++++++++++
src/audio/eq_fir.h | 70 ++++++
src/audio/fir.c | 92 +++++++
src/audio/fir.h | 130 ++++++++++
src/include/reef/audio/component.h | 3 +
src/include/reef/trace.h | 1 +
src/include/uapi/ipc.h | 12 +
src/tasks/audio.c | 1 +
9 files changed, 798 insertions(+)
create mode 100644 src/audio/eq_fir.c
create mode 100644 src/audio/eq_fir.h
create mode 100644 src/audio/fir.c
create mode 100644 src/audio/fir.h
diff --git a/src/audio/Makefile.am b/src/audio/Makefile.am
index 6f0381a..1da6757 100644
--- a/src/audio/Makefile.am
+++ b/src/audio/Makefile.am
@@ -1,6 +1,8 @@
noinst_LIBRARIES = libaudio.a
libaudio_a_SOURCES = \
+ eq_fir.c \
+ fir.c \
tone.c \
src.c \
src_core.c \
diff --git a/src/audio/eq_fir.c b/src/audio/eq_fir.c
new file mode 100644
index 0000000..6c8f1fb
--- /dev/null
+++ b/src/audio/eq_fir.c
@@ -0,0 +1,487 @@
+/*
+ * Copyright (c) 2017, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Intel Corporation nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Seppo Ingalsuo <seppo.ingalsuo(a)linux.intel.com>
+ * Liam Girdwood <liam.r.girdwood(a)linux.intel.com>
+ * Keyon Jie <yang.jie(a)linux.intel.com>
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <errno.h>
+#include <reef/reef.h>
+#include <reef/lock.h>
+#include <reef/list.h>
+#include <reef/stream.h>
+#include <reef/alloc.h>
+#include <reef/work.h>
+#include <reef/clock.h>
+#include <reef/audio/component.h>
+#include <reef/audio/pipeline.h>
+#include <reef/audio/format.h>
+#include "fir.h"
+#include "eq_fir.h"
+
+#ifdef MODULE_TEST
+#include <stdio.h>
+#endif
+
+#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)
+
+/* src component private data */
+struct comp_data {
+ struct eq_fir_configuration *config;
+ struct fir_state_32x16 fir[PLATFORM_MAX_CHANNELS];
+ void (*eq_fir_func)(struct comp_dev *dev,
+ struct comp_buffer *source,
+ struct comp_buffer *sink,
+ uint32_t frames);
+};
+
+/*
+ * EQ FIR algorithm code
+ */
+
+static void eq_fir_s32_default(struct comp_dev *dev,
+ struct comp_buffer *source, struct comp_buffer *sink, uint32_t frames)
+{
+
+ int ch, n, n_wrap_src, n_wrap_snk, n_wrap_min;
+ int32_t *src = (int32_t *) source->r_ptr;
+ int32_t *snk = (int32_t *) sink->w_ptr;
+ int nch = source->params.pcm->channels;
+ int32_t *x = src + nch - 1;
+ int32_t *y = snk + nch - 1;
+ struct comp_data *cd = comp_get_drvdata(dev);
+
+ for (ch = 0; ch < nch; ch++) {
+ n = frames * nch;
+ x = src++;
+ y = snk++;
+ while (n > 0) {
+ n_wrap_src = (int32_t *) source->end_addr - x;
+ n_wrap_snk = (int32_t *) sink->end_addr - y;
+ n_wrap_min = (n_wrap_src < n_wrap_snk) ?
+ n_wrap_src : n_wrap_snk;
+ if (n < n_wrap_min) {
+ /* No circular wrap need */
+ while (n > 0) {
+ *y = fir_32x16(&cd->fir[ch], *x);
+ x += nch;
+ y += nch;
+ n -= nch;
+ }
+ } else {
+ /* Wrap in n_wrap_min/nch samples */
+ while (n_wrap_min > 0) {
+ *y = fir_32x16(&cd->fir[ch], *x);
+ x += nch;
+ y += nch;
+ n_wrap_min -= nch;
+ n -= nch;
+ }
+ /* Check both source and destination for wrap */
+ if (x > (int32_t *) source->end_addr)
+ x = (int32_t *)
+ ((size_t) x - source->alloc_size);
+ if (snk > (int32_t *) sink->end_addr)
+ y = (int32_t *)
+ ((size_t) y - sink->alloc_size);
+ }
+ }
+
+ }
+ source->r_ptr = x - nch + 1; /* After previous loop the x and y */
+ sink->w_ptr = y - nch + 1; /* point to one frame -1. */
+
+ comp_wrap_source_r_ptr_circular(source);
+ comp_wrap_sink_w_ptr_circular(sink);
+ comp_update_source_free_avail(source, frames * nch);
+ comp_update_sink_free_avail(sink, frames * nch);
+}
+
+static void eq_fir_free_parameters(struct eq_fir_configuration **config)
+{
+ if (*config != NULL)
+ rfree(*config);
+
+ *config = NULL;
+}
+
+static void eq_fir_free_delaylines(struct fir_state_32x16 fir[])
+{
+ int i = 0;
+ int32_t *data = NULL;
+
+ /* 1st active EQ data is at beginning of the single allocated buffer */
+ for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) {
+ if ((fir[i].delay != NULL) && (data == NULL))
+ data = fir[i].delay;
+
+ /* Set all to NULL to avoid duplicated free later */
+ fir[i].delay = NULL;
+ }
+
+ if (data != NULL)
+ rbfree(data);
+
+}
+
+static int eq_fir_setup(struct fir_state_32x16 fir[],
+ struct eq_fir_configuration *config, int nch)
+{
+ int i, j, idx, length, resp;
+ int32_t *fir_data;
+ int response_index[PLATFORM_MAX_CHANNELS];
+ int length_sum = 0;
+
+ if (nch > PLATFORM_MAX_CHANNELS)
+ return -EINVAL;
+
+ /* Collect index of respose start positions in all_coefficients[] */
+ j = 0;
+ for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) {
+ if (i < config->number_of_responses_defined) {
+ response_index[i] = j;
+ j += 3 + config->all_coefficients[j];
+ } else {
+ response_index[i] = 0;
+ }
+ }
+
+ /* Initialize 1st phase */
+ for (i = 0; i < nch; i++) {
+ resp = config->assign_response[i];
+ if (resp < 0) {
+ /* Initialize EQ channel to bypass */
+ fir_reset(&fir[i]);
+ } else {
+ /* Initialize EQ coefficients */
+ idx = response_index[resp];
+ length = fir_init_coef(&fir[i],
+ &config->all_coefficients[idx]);
+ if (length > 0)
+ length_sum += length;
+ }
+
+ }
+ /* Free existing FIR channels data if it was allocated */
+ eq_fir_free_delaylines(fir);
+
+ /* Allocate all FIR channels data in a big chunk and clear it */
+ fir_data = rballoc(RZONE_SYS, RFLAGS_NONE,
+ length_sum * sizeof(int32_t));
+ if (fir_data == NULL)
+ return -EINVAL;
+
+ memset(fir_data, 0, length_sum * sizeof(int32_t));
+
+ /* Initialize 2nd phase to set EQ delay lines pointers */
+ for (i = 0; i < nch; i++) {
+ resp = config->assign_response[i];
+ if (resp >= 0) {
+ idx = response_index[resp];
+ fir_init_delay(&fir[i], &config->all_coefficients[idx],
+ &fir_data);
+ }
+
+ }
+
+ return 0;
+}
+
+static int eq_fir_switch_response(struct fir_state_32x16 fir[],
+ struct eq_fir_configuration *config, struct eq_fir_update *update,
+ int nch)
+{
+ int i;
+
+ /* Copy assign response from update and re-initilize EQ */
+ if (config == NULL)
+ return -EINVAL;
+
+ for (i = 0; i < config->stream_max_channels; i++) {
+ if (i < update->stream_max_channels)
+ config->assign_response[i] = update->assign_response[i];
+ }
+
+ eq_fir_setup(fir, config, nch);
+
+ return 0;
+}
+
+/*
+ * End of algorithm code. Next the standard component methods.
+ */
+
+static struct comp_dev *eq_fir_new(struct sof_ipc_comp *comp)
+{
+ int i;
+ //struct comp_buffer *sink;
+ //struct comp_buffer *source;
+ struct comp_dev *dev;
+ struct comp_data *cd;
+
+ trace_src("ENw");
+ dev = rmalloc(RZONE_RUNTIME, RFLAGS_NONE, sizeof(*dev));
+ if (dev == NULL)
+ return NULL;
+
+ //memcpy(&dev->comp, comp, sizeof(struct sof_ipc_comp_eq_fir));
+
+ cd = rmalloc(RZONE_RUNTIME, RFLAGS_NONE, sizeof(*cd));
+ if (cd == NULL) {
+ rfree(dev);
+ return NULL;
+ }
+
+ comp_set_drvdata(dev, cd);
+
+ cd->eq_fir_func = eq_fir_s32_default;
+ cd->config = NULL;
+ for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
+ fir_reset(&cd->fir[i]);
+
+ return dev;
+}
+
+static void eq_fir_free(struct comp_dev *dev)
+{
+ struct comp_data *cd = comp_get_drvdata(dev);
+
+ trace_src("EFr");
+
+ eq_fir_free_delaylines(cd->fir);
+ eq_fir_free_parameters(&cd->config);
+
+ rfree(cd);
+ rfree(dev);
+}
+
+/* set component audio stream parameters */
+static int eq_fir_params(struct comp_dev *dev, struct stream_params *params)
+{
+
+ trace_src("EPa");
+
+ /* EQ supports only S32_LE PCM format */
+ if ((params->type != STREAM_TYPE_PCM)
+ || (params->pcm->frame_fmt != SOF_IPC_FRAME_S32_LE))
+ return -EINVAL;
+
+ /* don't do any data transformation */
+ comp_set_sink_params(dev, params);
+
+ return 0;
+}
+
+/* used to pass standard and bespoke commands (with data) to component */
+static int eq_fir_cmd(struct comp_dev *dev, int cmd, void *data)
+{
+ trace_src("ECm");
+ struct comp_data *cd = comp_get_drvdata(dev);
+ struct comp_buffer *source = list_first_item(&dev->bsource_list,
+ struct comp_buffer, sink_list);
+ struct sof_ipc_eq_fir_blob *blob;
+ struct sof_ipc_eq_fir_switch *assign;
+
+ int i;
+ size_t bs;
+
+ switch (cmd) {
+ case COMP_CMD_EQ_FIR_SWITCH:
+ trace_src("EFx");
+ assign = (struct sof_ipc_eq_fir_switch *) data;
+ eq_fir_switch_response(cd->fir, cd->config,
+ (struct eq_fir_update *) assign->data,
+ source->params.pcm->channels);
+ break;
+ case COMP_CMD_EQ_FIR_CONFIG:
+ trace_src("EFc");
+ /* Check and free old config */
+ eq_fir_free_parameters(&cd->config);
+
+ /* Copy new config, need to decode data to know the size */
+ blob = (struct sof_ipc_eq_fir_blob *) data;
+ bs = blob->hdr.size - sizeof(struct sof_ipc_hdr);
+ if (bs > EQ_FIR_MAX_BLOB_SIZE)
+ return -EINVAL;
+
+ cd->config = rmalloc(RZONE_RUNTIME, RFLAGS_NONE, bs);
+ if (cd->config != NULL)
+ memcpy(cd->config, blob->data, bs);
+
+ eq_fir_setup(cd->fir, cd->config, source->params.pcm->channels);
+ break;
+ case COMP_CMD_MUTE:
+ trace_src("EFm");
+ for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
+ fir_mute(&cd->fir[i]);
+
+ break;
+ case COMP_CMD_UNMUTE:
+ trace_src("EFu");
+ for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
+ fir_unmute(&cd->fir[i]);
+
+ break;
+ case COMP_CMD_START:
+ trace_src("EFs");
+ dev->state = COMP_STATE_RUNNING;
+ break;
+ case COMP_CMD_STOP:
+ trace_src("ESp");
+ if (dev->state == COMP_STATE_RUNNING ||
+ dev->state == COMP_STATE_DRAINING ||
+ dev->state == COMP_STATE_PAUSED) {
+ comp_buffer_reset(dev);
+ dev->state = COMP_STATE_SETUP;
+ }
+ break;
+ case COMP_CMD_PAUSE:
+ trace_src("EPe");
+ /* only support pausing for running */
+ if (dev->state == COMP_STATE_RUNNING)
+ dev->state = COMP_STATE_PAUSED;
+
+ break;
+ case COMP_CMD_RELEASE:
+ trace_src("ERl");
+ dev->state = COMP_STATE_RUNNING;
+ break;
+ default:
+ trace_src("EDf");
+ break;
+ }
+
+ return 0;
+}
+
+/* copy and process stream data from source to sink buffers */
+static int eq_fir_copy(struct comp_dev *dev)
+{
+ struct comp_data *sd = comp_get_drvdata(dev);
+ struct comp_buffer *source;
+ struct comp_buffer *sink;
+ int frames;
+ int need_source, need_sink;
+
+ trace_comp("EqF");
+
+ /* src component needs 1 source and 1 sink buffer */
+ source = list_first_item(&dev->bsource_list, struct comp_buffer,
+ sink_list);
+ sink = list_first_item(&dev->bsink_list, struct comp_buffer,
+ source_list);
+
+ /* Check that source has enough frames available and sink enough
+ * frames free.
+ */
+ frames = source->params.pcm->period_count;
+ need_source = frames * source->params.pcm->frame_size;
+ need_sink = frames * sink->params.pcm->frame_size;
+
+ /* Run EQ if buffers have enough room */
+ if ((source->avail >= need_source) && (sink->free >= need_sink))
+ sd->eq_fir_func(dev, source, sink, frames);
+
+ return 0;
+}
+
+static int eq_fir_prepare(struct comp_dev *dev)
+{
+ struct comp_data *cd = comp_get_drvdata(dev);
+ struct comp_buffer *source;
+
+ trace_src("EPp");
+
+ cd->eq_fir_func = eq_fir_s32_default;
+
+ /* Initialize EQ */
+ if (cd->config == NULL)
+ return -EINVAL;
+
+ source = list_first_item(&dev->bsource_list, struct comp_buffer,
+ sink_list);
+ if (eq_fir_setup(cd->fir, cd->config, source->params.pcm->channels) < 0)
+ return -EINVAL;
+
+ //dev->preload = PLAT_INT_PERIODS;
+ dev->state = COMP_STATE_PREPARE;
+ return 0;
+}
+
+static int eq_fir_preload(struct comp_dev *dev)
+{
+ //int i;
+
+ trace_src("EPl");
+ //for (i = 0; i < dev->preload; i++)
+ // eq_fir_copy(dev);
+
+ return 0;
+}
+
+static int eq_fir_reset(struct comp_dev *dev)
+{
+ int i;
+ struct comp_data *cd = comp_get_drvdata(dev);
+
+ trace_src("ERe");
+
+ eq_fir_free_delaylines(cd->fir);
+ eq_fir_free_parameters(&cd->config);
+
+ cd->eq_fir_func = eq_fir_s32_default;
+ for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
+ fir_reset(&cd->fir[i]);
+
+ dev->state = COMP_STATE_INIT;
+ return 0;
+}
+
+struct comp_driver comp_eq_fir = {
+ .type = SOF_COMP_EQ_FIR,
+ .ops =
+ {
+ .new = eq_fir_new,
+ .free = eq_fir_free,
+ .params = eq_fir_params,
+ .cmd = eq_fir_cmd,
+ .copy = eq_fir_copy,
+ .prepare = eq_fir_prepare,
+ .reset = eq_fir_reset,
+ .preload = eq_fir_preload,
+ },
+};
+
+void sys_comp_eq_fir_init(void)
+{
+ comp_register(&comp_eq_fir);
+}
diff --git a/src/audio/eq_fir.h b/src/audio/eq_fir.h
new file mode 100644
index 0000000..22af4af
--- /dev/null
+++ b/src/audio/eq_fir.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2017, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Intel Corporation nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Seppo Ingalsuo <seppo.ingalsuo(a)linux.intel.com>
+ * Liam Girdwood <liam.r.girdwood(a)linux.intel.com>
+ * Keyon Jie <yang.jie(a)linux.intel.com>
+ */
+
+#ifndef EQ_FIR_H
+#define EQ_FIR_H
+
+
+/*
+ * eq_fir_configuration data structure contains this information
+ * stream max channels
+ * number_of_responses_defined
+ * 0=no respones, 1=one response defined, 2=two responses defined, etc.
+ * assign_response[STREAM_MAX_CHANNELS]
+ * -1 = not defined, 0 = use first response, 1 = use 2nd response, etc.
+ * E.g. {0, 0, 0, 0, -1, -1, -1, -1} would apply to channels 0-3 the
+ * same first defined response and leave channels 4-7 unequalized.
+ * all_coefficients[]
+ * Repeated data { filter_length, input_shift, output_shift, h[] }
+ * where vector h has filter_length number of coefficients.
+ * Coefficients in h[] are in Q1.15 format. 16384 = 0.5. The shifts
+ * are number of right shifts.
+ */
+
+#define NHEADER_EQ_FIR_BLOB 2 /* Header is two words plus assigns plus coef */
+
+#define EQ_FIR_MAX_BLOB_SIZE 4096 /* Max size allowed for blob */
+
+struct eq_fir_configuration {
+ uint16_t stream_max_channels;
+ uint16_t number_of_responses_defined;
+ uint16_t assign_response[PLATFORM_MAX_CHANNELS];
+ int16_t all_coefficients[];
+};
+
+struct eq_fir_update {
+ uint16_t stream_max_channels;
+ uint16_t assign_response[PLATFORM_MAX_CHANNELS];
+
+};
+
+#endif
diff --git a/src/audio/fir.c b/src/audio/fir.c
new file mode 100644
index 0000000..beb7e72
--- /dev/null
+++ b/src/audio/fir.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2017, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Intel Corporation nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Seppo Ingalsuo <seppo.ingalsuo(a)linux.intel.com>
+ * Liam Girdwood <liam.r.girdwood(a)linux.intel.com>
+ * Keyon Jie <yang.jie(a)linux.intel.com>
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <errno.h>
+
+#ifdef MODULE_TEST
+#include <stdio.h>
+#endif
+
+#include <reef/audio/format.h>
+#include "fir.h"
+
+#ifdef MODULE_TEST
+#include <stdio.h>
+#endif
+
+/*
+ * EQ FIR algorithm code
+ */
+
+void fir_reset(struct fir_state_32x16 *fir)
+{
+ fir->mute = 1;
+ fir->rwi = 0;
+ fir->length = 0;
+ fir->delay_size = 0;
+ fir->in_shift = 0;
+ fir->out_shift = 0;
+ fir->coef = NULL;
+ /* There may need to know the beginning of dynamic allocation after
+ * reset so omitting setting also fir->delay to NULL.
+ */
+}
+
+int fir_init_coef(struct fir_state_32x16 *fir, int16_t config[])
+{
+ struct fir_coef_32x16 *setup;
+
+ setup = (struct fir_coef_32x16 *) config;
+ fir->mute = 0;
+ fir->rwi = 0;
+ fir->length = (int) setup->length;
+ fir->in_shift = (int) setup->in_shift;
+ fir->out_shift = (int) setup->out_shift;
+ fir->coef = &setup->coef;
+ fir->delay = NULL;
+ fir->delay_size = 0;
+
+ if ((fir->length > MAX_FIR_LENGTH) || (fir->length < 1))
+ return -EINVAL;
+
+ return fir->length;
+}
+
+void fir_init_delay(struct fir_state_32x16 *fir, int16_t config[],
+ int32_t **data)
+{
+ fir->delay = *data;
+ fir->delay_size = fir->length;
+ *data += fir->delay_size; /* Point to next delay line start */
+}
diff --git a/src/audio/fir.h b/src/audio/fir.h
new file mode 100644
index 0000000..7044a22
--- /dev/null
+++ b/src/audio/fir.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2017, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Intel Corporation nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Seppo Ingalsuo <seppo.ingalsuo(a)linux.intel.com>
+ * Liam Girdwood <liam.r.girdwood(a)linux.intel.com>
+ * Keyon Jie <yang.jie(a)linux.intel.com>
+ */
+
+#include <reef/audio/format.h>
+
+#define MAX_FIR_LENGTH 192
+
+#define NHEADER_FIR_COEF_32x16 3
+
+struct fir_coef_32x16 {
+ int16_t length; /* Number of FIR taps */
+ int16_t in_shift; /* Amount of right shifts at input */
+ int16_t out_shift; /* Amount of right shifts at output */
+ int16_t coef; /* FIR coefficients */
+};
+
+struct fir_state_32x16 {
+ int mute; /* Set to 1 to mute EQ output, 0 otherwise */
+ int rwi; /* Circular read and write index */
+ int length; /* Number of FIR taps */
+ int delay_size; /* Actual delay lentgh, must be >= length */
+ int in_shift; /* Amount of right shifts at input */
+ int out_shift; /* Amount of right shifts at output */
+ int16_t *coef; /* Pointer to FIR coefficients */
+ int32_t *delay; /* Pointer to FIR delay line */
+};
+
+void fir_reset(struct fir_state_32x16 *fir);
+
+int fir_init_coef(struct fir_state_32x16 *fir, int16_t config[]);
+
+void fir_init_delay(struct fir_state_32x16 *fir, int16_t config[],
+ int32_t **data);
+
+/* The next trivial functions are inlined */
+
+static inline void fir_mute(struct fir_state_32x16 *fir)
+{
+ fir->mute = 1;
+}
+
+static inline void fir_unmute(struct fir_state_32x16 *fir)
+{
+ fir->mute = 0;
+}
+
+/* The next functions are inlined to optmize execution speed */
+
+static inline void fir_part_32x16(int64_t *y, int taps, const int16_t c[],
+ int *ic, int32_t d[], int *id)
+{
+ int n;
+
+ /* Data is Q8.24, coef is Q1.15, product is Q9.39 */
+ for (n = 0; n < taps; n++) {
+ *y += (int64_t) c[*ic] * d[*id];
+ (*ic)++;
+ (*id)--;
+ }
+}
+
+static inline int32_t fir_32x16(struct fir_state_32x16 *fir, int32_t x)
+{
+ int64_t y = 0;
+ int n1;
+ int n2;
+ int i = 0; /* Start from 1st tap */
+ int tmp_ri;
+
+ /* Write sample to delay */
+ fir->delay[fir->rwi] = x >> fir->in_shift;
+
+ /* Start FIR calculation. Calculate first number of taps possible to
+ * calculate before circular wrap need.
+ */
+ n1 = fir->rwi + 1;
+ tmp_ri = (fir->rwi)++; /* Point to newest sample and advance read index */
+ if (fir->rwi == fir->delay_size)
+ fir->rwi = 0;
+
+ if (n1 > fir->length) {
+ /* No need to un-wrap fir read index, make sure ri
+ * is >= 0 after FIR computation */
+ fir_part_32x16(&y, fir->length, fir->coef, &i, fir->delay, &tmp_ri);
+ } else {
+ n2 = fir->length - n1;
+ /* Part 1, loop n1 times, fir_ri becomes -1 */
+ fir_part_32x16(&y, n1, fir->coef, &i, fir->delay, &tmp_ri);
+
+ /* Part 2, unwrap fir_ri, continue rest of filter */
+ tmp_ri = fir->delay_size - 1;
+ fir_part_32x16(&y, n2, fir->coef, &i, fir->delay, &tmp_ri);
+ }
+ /* Q9.39 -> Q9.24, saturate to Q8.24 */
+ y = sat_int32(y >> (15 + fir->out_shift));
+
+ if (fir->mute)
+ return 0;
+ else
+ return(int32_t) y;
+}
diff --git a/src/include/reef/audio/component.h b/src/include/reef/audio/component.h
index e4f4f8f..7de47c2 100644
--- a/src/include/reef/audio/component.h
+++ b/src/include/reef/audio/component.h
@@ -76,6 +76,8 @@
#define COMP_CMD_LOOPBACK 105
#define COMP_CMD_TONE 106 /* Tone generator amplitude and frequency */
+#define COMP_CMD_EQ_FIR_CONFIG 107 /* Configuration data for FIR EQ */
+#define COMP_CMD_EQ_FIR_SWITCH 108 /* Update request for FIR EQ */
/* MMAP IPC status */
#define COMP_CMD_IPC_MMAP_RPOS 200 /* host read position */
@@ -263,6 +265,7 @@ void sys_comp_src_init(void);
void sys_comp_tone_init(void);
+void sys_comp_eq_fir_init(void);
static inline void comp_set_endpoint(struct comp_dev *dev)
{
diff --git a/src/include/reef/trace.h b/src/include/reef/trace.h
index 04b8d5d..ff41caf 100644
--- a/src/include/reef/trace.h
+++ b/src/include/reef/trace.h
@@ -84,6 +84,7 @@
#define TRACE_CLASS_MUX (16 << 24)
#define TRACE_CLASS_SRC (17 << 24)
#define TRACE_CLASS_TONE (18 << 24)
+#define TRACE_CLASS_EQ_FIR (19 << 24)
/* move to config.h */
#define TRACE 1
diff --git a/src/include/uapi/ipc.h b/src/include/uapi/ipc.h
index 7b0fd96..3bb6f61 100644
--- a/src/include/uapi/ipc.h
+++ b/src/include/uapi/ipc.h
@@ -673,5 +673,17 @@ struct sof_ipc_window {
uint32_t num_windows;
struct sof_ipc_window_elem window[0];
} __attribute__((packed));
+/* IPC to pass configuration blobs to equalizers and re-assign responses */
+struct sof_ipc_eq_fir_blob {
+ struct sof_ipc_hdr hdr;
+ struct sof_ipc_host_buffer buffer;
+ int32_t data[];
+} __attribute__((packed));
+
+struct sof_ipc_eq_fir_switch {
+ struct sof_ipc_hdr hdr;
+ int32_t data[];
+} __attribute__((packed));
+
#endif
diff --git a/src/tasks/audio.c b/src/tasks/audio.c
index 8dc42ce..c420fb1 100644
--- a/src/tasks/audio.c
+++ b/src/tasks/audio.c
@@ -65,6 +65,7 @@ int do_task(struct reef *reef)
sys_comp_volume_init();
sys_comp_src_init();
sys_comp_tone_init();
+ sys_comp_eq_fir_init();
#if 0
/* init static pipeline */
--
2.11.0
1
0
07 Jun '17
---
src/audio/Makefile.am | 1 +
src/audio/tone.c | 576 +++++++++++++++++++++++++++++++++++
src/audio/tone.h | 54 ++++
src/include/reef/audio/component.h | 2 +
src/include/reef/math/trig.h | 44 +++
src/include/reef/trace.h | 1 +
src/include/uapi/ipc.h | 8 +
src/math/trig.c | 595 +++++++++++++++++++++++++++++++++++++
src/tasks/audio.c | 1 +
9 files changed, 1282 insertions(+)
create mode 100644 src/audio/tone.c
create mode 100644 src/audio/tone.h
create mode 100644 src/include/reef/math/trig.h
create mode 100644 src/math/trig.c
diff --git a/src/audio/Makefile.am b/src/audio/Makefile.am
index 235e785..6f0381a 100644
--- a/src/audio/Makefile.am
+++ b/src/audio/Makefile.am
@@ -1,6 +1,7 @@
noinst_LIBRARIES = libaudio.a
libaudio_a_SOURCES = \
+ tone.c \
src.c \
src_core.c \
mixer.c \
diff --git a/src/audio/tone.c b/src/audio/tone.c
new file mode 100644
index 0000000..f305c03
--- /dev/null
+++ b/src/audio/tone.c
@@ -0,0 +1,576 @@
+/*
+ * Copyright (c) 2016, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Intel Corporation nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Seppo Ingalsuo <seppo.ingalsuo(a)linux.intel.com>
+ * Liam Girdwood <liam.r.girdwood(a)linux.intel.com>
+ * Keyon Jie <yang.jie(a)linux.intel.com>
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <errno.h>
+#include <reef/reef.h>
+#include <reef/lock.h>
+#include <reef/list.h>
+#include <reef/stream.h>
+#include <reef/alloc.h>
+#include <reef/work.h>
+#include <reef/clock.h>
+#include <reef/audio/component.h>
+#include <reef/audio/format.h>
+#include <reef/audio/pipeline.h>
+#include <reef/math/trig.h>
+#include "tone.h"
+
+#ifdef MODULE_TEST
+#include <stdio.h>
+#endif
+
+#define trace_tone(__e) trace_event(TRACE_CLASS_TONE, __e)
+#define tracev_tone(__e) tracev_event(TRACE_CLASS_TONE, __e)
+#define trace_tone_error(__e) trace_error(TRACE_CLASS_TONE, __e)
+
+#define TONE_NUM_FS 13 /* Table size for 8-192 kHz range */
+#define TONE_AMPLITUDE_DEFAULT 2147484 /* -60 dB from full scale */
+#define TONE_FREQUENCY_DEFAULT 16334848 /* 997 in Q18.14 */
+
+static int32_t tonegen(struct tone_state *sg);
+static void tonegen_control(struct tone_state *sg);
+static void tonegen_update_f(struct tone_state *sg, int32_t f);
+
+
+/* 2*pi/Fs lookup tables in Q1.31 for each Fs */
+static const int32_t tone_fs_list[TONE_NUM_FS] = {
+ 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000,
+ 64000, 88200, 96000, 176400, 192000
+};
+static const int32_t tone_pi2_div_fs[TONE_NUM_FS] = {
+ 1686630, 1223858, 843315, 611929, 562210, 421657, 305965,
+ 281105, 210829, 152982, 140552, 76491, 70276
+};
+
+/* tone component private data */
+
+/* TODO: Remove *source when internal endpoint is possible */
+struct comp_data {
+ struct tone_state sg;
+ void (*tone_func)(struct comp_dev *dev, struct comp_buffer *sink,
+ struct comp_buffer *source, uint32_t frames);
+
+};
+
+/*
+ * Tone generator algorithm code
+ */
+
+static void tone_s32_default(struct comp_dev *dev, struct comp_buffer *sink,
+ struct comp_buffer *source, uint32_t frames)
+{
+ struct comp_data *cd = comp_get_drvdata(dev);
+ int32_t sine_sample;
+ int32_t *dest = (int32_t*) sink->w_ptr;
+ int i, n, n_wrap_dest;
+ int nch = sink->params.pcm->channels;
+
+ n = frames * nch;
+ while (n > 0) {
+ n_wrap_dest = (int32_t *) sink->end_addr - dest;
+ if (n < n_wrap_dest) {
+ /* No circular wrap need */
+ while (n > 0) {
+ /* Update period count for sweeps, etc. */
+ tonegen_control(&cd->sg);
+ /* Calculate mono sine wave sample and then
+ * duplicate to channels.
+ */
+ sine_sample = tonegen(&cd->sg);
+ n -= nch;
+ for (i = 0; i < nch; i++) {
+ *dest = sine_sample;
+ dest++;
+ }
+ }
+ } else {
+ /* Process until wrap */
+ while (n_wrap_dest > 0) {
+ tonegen_control(&cd->sg);
+ sine_sample = tonegen(&cd->sg);
+ n -= nch;
+ n_wrap_dest -= nch;
+ for (i = 0; i < nch; i++) {
+ *dest = sine_sample;
+ dest++;
+ }
+ }
+ /* No need to check if past end_addr,
+ * it is so just subtract buffer size.
+ */
+ dest = (int32_t *) ((size_t) dest - sink->alloc_size);
+ }
+ }
+ sink->w_ptr = dest;
+ comp_update_sink_free_avail(sink, frames * nch);
+}
+
+static int32_t tonegen(struct tone_state *sg)
+{
+ int64_t sine, w;
+
+ /* 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);
+
+ /* Next point */
+ w = (int64_t) sg->w + sg->w_step;
+ sg->w = (w > PI_MUL2_Q4_28)
+ ? (int32_t) (w - PI_MUL2_Q4_28) : (int32_t) w;
+
+ if (sg->mute)
+ return 0;
+ else
+ return(int32_t) sine; /* Q1.31 no saturation need */
+}
+
+static void tonegen_control(struct tone_state *sg)
+{
+ int64_t a, p;
+
+ /* Count samples, 125 us blocks */
+ sg->sample_count++;
+ if (sg->sample_count < sg->samples_in_block)
+ return;
+
+ sg->sample_count = 0;
+ if (sg->block_count < INT32_MAXVALUE)
+ sg->block_count++;
+
+ /* Fadein ramp during tone */
+ if (sg->block_count < sg->tone_length) {
+ if (sg->a == 0)
+ sg->w = 0; /* Reset phase to have less clicky ramp */
+
+ if (sg->a > sg->a_target) {
+ a = (int64_t) sg->a - sg->ramp_step;
+ if (a < sg->a_target)
+ a = sg->a_target;
+
+ } else {
+ a = (int64_t) sg->a + sg->ramp_step;
+ if (a > sg->a_target)
+ a = sg->a_target;
+ }
+ sg->a = (int32_t) a;
+ }
+
+ /* Fadeout ramp after tone*/
+ if (sg->block_count > sg->tone_length) {
+ a = (int64_t) sg->a - sg->ramp_step;
+ if (a < 0)
+ a = 0;
+
+ sg->a = (int32_t) a;
+ }
+
+ /* New repeated tone, update for frequency or amplitude sweep */
+ if ((sg->block_count > sg->tone_period)
+ && (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 = (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);
+ tonegen_update_f(sg, (int32_t) p); /* No saturation */
+ }
+ sg->repeat_count++;
+ }
+}
+
+static inline void tonegen_set_a(struct tone_state *sg, int32_t a)
+{
+ sg->a_target = a;
+}
+
+static inline void tonegen_set_f(struct tone_state *sg, int32_t f)
+{
+ sg->f = f;
+}
+
+/* Tone sweep parameters description:
+ * fc - Multiplication factor for frequency as Q2.30 for logarithmic change
+ * ac - Multiplication factor for amplitude as Q2.30 for logarithmic change
+ * l - Tone length in samples, this is the active length of tone
+ * p - Tone period in samples, this is the length including the pause after beep
+ * r - Repeated number of beeps
+ */
+
+static void tonegen_set_sweep(struct tone_state *sg, int32_t fc, int32_t ac,
+ uint32_t l, uint32_t p, uint32_t r)
+{
+ sg->repeats = r;
+
+ /* Zeros as defaults make a nicer API without need to remember
+ * the neutral settings for sweep and repeat parameters.
+ */
+ sg->freq_coef = (fc > 0) ? fc : ONE_Q2_30; /* Set freq mult to 1.0 */
+ sg->ampl_coef = (ac > 0) ? ac : ONE_Q2_30; /* Set ampl mult to 1.0 */
+ sg->tone_length = (l > 0) ? l : INT32_MAXVALUE; /* Count rate 125 us */
+ sg->tone_period = (p > 0) ? p : INT32_MAXVALUE; /* Count rate 125 us */
+}
+
+/* Tone ramp parameters:
+ * step - Value that is added or subtracted to amplitude. A zero or negative
+ * number disables the ramp and amplitude is immediately modified to
+ * final value.
+ */
+
+static inline void tonegen_set_linramp(struct tone_state *sg, int32_t step)
+{
+ sg->ramp_step = (step > 0) ? step : INT32_MAXVALUE;
+}
+
+static inline int32_t tonegen_get_f(struct tone_state *sg)
+{
+ return sg->f;
+}
+
+static inline int32_t tonegen_get_a(struct tone_state *sg)
+{
+ return sg->a_target;
+}
+
+static inline void tonegen_mute(struct tone_state *sg)
+{
+ sg->mute = 1;
+}
+
+static inline void tonegen_unmute(struct tone_state *sg)
+{
+ sg->mute = 0;
+}
+
+static void tonegen_update_f(struct tone_state *sg, int32_t f)
+{
+ int64_t w_tmp;
+ int64_t f_max;
+
+ /* Calculate Fs/2, fs is Q32.0, f is Q16.16 */
+ 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 */
+ w_tmp = (w_tmp > PI_Q4_28) ? PI_Q4_28 : w_tmp; /* Limit to pi Q4.28 */
+ sg->w_step = (int32_t) w_tmp;
+
+#ifdef MODULE_TEST
+ printf("Fs=%d, f_max=%d, f_new=%.3f\n",
+ sg->fs, (int32_t) (f_max >> 16), sg->f / 65536.0);
+#endif
+}
+
+static void tonegen_reset(struct tone_state *sg)
+{
+ sg->mute = 1;
+ sg->a = 0;
+ sg->a_target = TONE_AMPLITUDE_DEFAULT;
+ sg->c = 0;
+ sg->f = TONE_FREQUENCY_DEFAULT;
+ sg->w = 0;
+ sg->w_step = 0;
+
+ sg->block_count = 0;
+ sg->repeat_count = 0;
+ sg->repeats = 0;
+ sg->sample_count = 0;
+ sg->samples_in_block = 0;
+
+ /* Continuous tone */
+ sg->freq_coef = ONE_Q2_30; /* Set freq multiplier to 1.0 */
+ sg->ampl_coef = ONE_Q2_30; /* Set ampl multiplier to 1.0 */
+ sg->tone_length = INT32_MAXVALUE;
+ sg->tone_period = INT32_MAXVALUE;
+ sg->ramp_step = ONE_Q1_31; /* Set lin ramp modification to max */
+}
+
+static int tonegen_init(struct tone_state *sg, int32_t fs, int32_t f, int32_t a)
+{
+ int idx, i;
+
+ sg->a_target = a;
+ sg->a = (sg->ramp_step > sg->a_target) ? sg->a_target : sg->ramp_step;
+
+ idx = -1;
+ sg->mute = 1;
+ sg->fs = 0;
+
+ /* Find index of current sample rate and then get from lookup table the
+ * corresponding 2*pi/Fs value.
+ */
+ for (i = 0; i < TONE_NUM_FS; i++) {
+ if (fs == tone_fs_list[i])
+ idx = i;
+ }
+
+ if (idx < 0) {
+ sg->w_step = 0;
+ return -EINVAL;
+ }
+
+ sg->fs = fs;
+ sg->c = tone_pi2_div_fs[idx]; /* Store 2*pi/Fs */
+ sg->mute = 0;
+ 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);
+
+ return 0;
+}
+
+/*
+ * End of algorithm code. Next the standard component methods.
+ */
+
+static struct comp_dev *tone_new(struct sof_ipc_comp *comp)
+{
+ struct comp_dev *dev;
+ struct comp_data *cd;
+
+ trace_tone("TNw");
+ dev = rmalloc(RZONE_RUNTIME, RFLAGS_NONE, sizeof(*dev));
+ if (dev == NULL)
+ return NULL;
+
+ //memcpy(&dev->comp, comp, sizeof(struct sof_ipc_comp_tone));
+
+
+ cd = rmalloc(RZONE_RUNTIME, RFLAGS_NONE, sizeof(*cd));
+ if (cd == NULL) {
+ rfree(dev);
+ return NULL;
+ }
+
+ comp_set_drvdata(dev, cd);
+
+
+ tonegen_reset(&cd->sg);
+
+ return dev;
+}
+
+static void tone_free(struct comp_dev *dev)
+{
+ struct tone_data *td = comp_get_drvdata(dev);
+
+ trace_tone("TFr");
+
+ rfree(td);
+ rfree(dev);
+}
+
+/* set component audio stream parameters */
+static int tone_params(struct comp_dev *dev, struct stream_params *params)
+{
+ trace_tone("TPa");
+
+ /* Tone generator supports only S32_LE PCM format */
+ if ((params->type != STREAM_TYPE_PCM)
+ || (params->pcm->frame_fmt != SOF_IPC_FRAME_S32_LE))
+ return -EINVAL;
+
+ /* Don't do any data transformation */
+ comp_set_sink_params(dev, params);
+
+ return 0;
+}
+
+/* used to pass standard and bespoke commands (with data) to component */
+static int tone_cmd(struct comp_dev *dev, int cmd, void *data)
+{
+ struct comp_data *cd = comp_get_drvdata(dev);
+ struct sof_ipc_comp_tone *cv;
+ trace_tone("TCm");
+
+ switch (cmd) {
+ case COMP_CMD_TONE:
+ trace_tone("Tto");
+ cv = (struct sof_ipc_comp_tone *) data;
+ /* Ignore channels while tone implementation is mono */
+ tonegen_set_f(&cd->sg, cv->frequency);
+ tonegen_set_a(&cd->sg, cv->amplitude);
+ tonegen_set_sweep(&cd->sg, cv->freq_mult, cv->ampl_mult,
+ cv->length, cv->period, cv->repeats);
+ tonegen_set_linramp(&cd->sg, cv->ramp_step);
+ break;
+ case COMP_CMD_VOLUME:
+ trace_tone("TVo");
+ break;
+ case COMP_CMD_MUTE:
+ trace_tone("TMu");
+ tonegen_mute(&cd->sg);
+ break;
+ case COMP_CMD_UNMUTE:
+ trace_tone("TUm");
+ tonegen_unmute(&cd->sg);
+ break;
+ case COMP_CMD_START:
+ trace_tone("TSt");
+ dev->state = COMP_STATE_RUNNING;
+ break;
+ case COMP_CMD_STOP:
+ trace_tone("TSp");
+ if (dev->state == COMP_STATE_RUNNING ||
+ dev->state == COMP_STATE_DRAINING ||
+ dev->state == COMP_STATE_PAUSED) {
+ comp_buffer_reset(dev);
+ dev->state = COMP_STATE_SETUP;
+ }
+ break;
+ case COMP_CMD_PAUSE:
+ trace_tone("TPe");
+ /* only support pausing for running */
+ if (dev->state == COMP_STATE_RUNNING)
+ dev->state = COMP_STATE_PAUSED;
+
+ break;
+ case COMP_CMD_RELEASE:
+ trace_tone("TRl");
+ dev->state = COMP_STATE_RUNNING;
+ break;
+ default:
+ trace_tone("TDf");
+
+ break;
+ }
+
+ return 0;
+}
+
+/* copy and process stream data from source to sink buffers */
+static int tone_copy(struct comp_dev *dev)
+{
+ int need_sink;
+ struct comp_buffer *sink;
+ struct comp_buffer *source = NULL;
+ struct comp_data *cd = comp_get_drvdata(dev);
+ uint32_t cframes;
+
+ trace_comp("Ton");
+
+ /* tone component sink buffer */
+ sink = list_first_item(&dev->bsink_list, struct comp_buffer,
+ source_list);
+ cframes = sink->params.pcm->period_count;
+
+ /* Test that sink has enough free frames. Then run once to maintain
+ * low latency and steady load for tones.
+ */
+ need_sink = cframes * sink->params.pcm->frame_size;
+ if (sink->free >= need_sink) {
+
+ /* create tone */
+ cd->tone_func(dev, sink, source, cframes);
+ }
+
+ return 0;
+}
+
+static int tone_prepare(struct comp_dev *dev)
+{
+ int32_t f, a;
+ struct comp_buffer *sink;
+ struct comp_data *cd = comp_get_drvdata(dev);
+
+ trace_tone("TPp");
+
+ sink = list_first_item(&dev->bsink_list, struct comp_buffer,
+ source_list);
+ trace_value(sink->params.pcm->channels);
+ trace_value(sink->params.pcm->rate);
+
+ cd->tone_func = tone_s32_default;
+ f = tonegen_get_f(&cd->sg);
+ a = tonegen_get_a(&cd->sg);
+ if (tonegen_init(&cd->sg, sink->params.pcm->rate, f, a) < 0)
+ return -EINVAL;
+
+ //dev->preload = PLAT_INT_PERIODS;
+ dev->state = COMP_STATE_PREPARE;
+
+ return 0;
+}
+
+static int tone_preload(struct comp_dev *dev)
+{
+ //int i;
+ trace_tone("TPl");
+
+ //for (i = 0; i < dev->preload; i++)
+ // tone_copy(dev);
+
+ return 0;
+}
+
+static int tone_reset(struct comp_dev *dev)
+{
+
+ struct comp_data *cd = comp_get_drvdata(dev);
+
+ trace_tone("TRe");
+
+ /* Initialize with the defaults */
+ tonegen_reset(&cd->sg);
+
+ dev->state = COMP_STATE_INIT;
+
+ return 0;
+}
+
+struct comp_driver comp_tone = {
+ .type = SOF_COMP_TONE,
+ .ops =
+ {
+ .new = tone_new,
+ .free = tone_free,
+ .params = tone_params,
+ .cmd = tone_cmd,
+ .copy = tone_copy,
+ .prepare = tone_prepare,
+ .reset = tone_reset,
+ .preload = tone_preload,
+ },
+};
+
+void sys_comp_tone_init(void)
+{
+ comp_register(&comp_tone);
+}
diff --git a/src/audio/tone.h b/src/audio/tone.h
new file mode 100644
index 0000000..37830db
--- /dev/null
+++ b/src/audio/tone.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Intel Corporation nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Seppo Ingalsuo <seppo.ingalsuo(a)linux.intel.com>
+ * Liam Girdwood <liam.r.girdwood(a)linux.intel.com>
+ * Keyon Jie <yang.jie(a)linux.intel.com>
+ */
+
+
+struct tone_state {
+ int mute;
+ int32_t a; /* Current amplitude Q1.31 */
+ int32_t a_target; /* Target amplitude Q1.31 */
+ int32_t ampl_coef; /* Amplitude multiplier Q2.30 */
+ int32_t c; /* Coefficient 2*pi/Fs Q1.31 */
+ int32_t f; /* Frequency Q18.14 */
+ int32_t freq_coef; /* Frequency multiplier Q2.30 */
+ int32_t fs; /* Sample rate in Hertz Q32.0 */
+ int32_t ramp_step; /* Amplitude ramp step Q1.31 */
+ int32_t w; /* Angle radians Q4.28 */
+ int32_t w_step; /* Angle step Q4.28 */
+ uint32_t block_count;
+ uint32_t repeat_count;
+ uint32_t repeats; /* Number of repeats for tone (sweep steps) */
+ uint32_t sample_count;
+ uint32_t samples_in_block; /* Samples in 125 us block */
+ uint32_t tone_length; /* Active length in 125 us blocks */
+ uint32_t tone_period; /* Active + idle time in 125 us blocks */
+};
+
diff --git a/src/include/reef/audio/component.h b/src/include/reef/audio/component.h
index a37aa51..e4f4f8f 100644
--- a/src/include/reef/audio/component.h
+++ b/src/include/reef/audio/component.h
@@ -75,6 +75,7 @@
#define COMP_CMD_SRC 104
#define COMP_CMD_LOOPBACK 105
+#define COMP_CMD_TONE 106 /* Tone generator amplitude and frequency */
/* MMAP IPC status */
#define COMP_CMD_IPC_MMAP_RPOS 200 /* host read position */
@@ -259,6 +260,7 @@ void sys_comp_mux_init(void);
void sys_comp_switch_init(void);
void sys_comp_volume_init(void);
void sys_comp_src_init(void);
+void sys_comp_tone_init(void);
diff --git a/src/include/reef/math/trig.h b/src/include/reef/math/trig.h
new file mode 100644
index 0000000..b75f229
--- /dev/null
+++ b/src/include/reef/math/trig.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Intel Corporation nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Seppo Ingalsuo <seppo.ingalsuo(a)linux.intel.com>
+ * Liam Girdwood <liam.r.girdwood(a)linux.intel.com>
+ * Keyon Jie <yang.jie(a)linux.intel.com>
+ */
+
+#ifndef TRIG_H
+#define TRIG_H
+
+#define PI_DIV2_Q4_28 421657428
+#define PI_Q4_28 843314857
+#define PI_MUL2_Q4_28 1686629713
+
+int32_t sin_fixed(int32_t w); /* Input is Q4.28, output is Q1.31 */
+
+#endif
+
+
diff --git a/src/include/reef/trace.h b/src/include/reef/trace.h
index eb3fdd2..04b8d5d 100644
--- a/src/include/reef/trace.h
+++ b/src/include/reef/trace.h
@@ -83,6 +83,7 @@
#define TRACE_CLASS_SWITCH (15 << 24)
#define TRACE_CLASS_MUX (16 << 24)
#define TRACE_CLASS_SRC (17 << 24)
+#define TRACE_CLASS_TONE (18 << 24)
/* move to config.h */
#define TRACE 1
diff --git a/src/include/uapi/ipc.h b/src/include/uapi/ipc.h
index fc5a88b..7b0fd96 100644
--- a/src/include/uapi/ipc.h
+++ b/src/include/uapi/ipc.h
@@ -505,6 +505,14 @@ struct sof_ipc_comp_mux {
struct sof_ipc_comp_tone {
struct sof_ipc_comp comp;
struct sof_ipc_pcm_comp pcm;
+ int32_t frequency;
+ int32_t amplitude;
+ int32_t freq_mult;
+ int32_t ampl_mult;
+ int32_t length;
+ int32_t period;
+ int32_t repeats;
+ int32_t ramp_step;
} __attribute__((packed));
/* frees components, buffers and pipelines
diff --git a/src/math/trig.c b/src/math/trig.c
new file mode 100644
index 0000000..a58e1f4
--- /dev/null
+++ b/src/math/trig.c
@@ -0,0 +1,595 @@
+/*
+ * Copyright (c) 2016, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Intel Corporation nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Seppo Ingalsuo <seppo.ingalsuo(a)linux.intel.com>
+ * Liam Girdwood <liam.r.girdwood(a)linux.intel.com>
+ * Keyon Jie <yang.jie(a)linux.intel.com>
+ */
+
+#include <stdint.h>
+#include <reef/audio/format.h>
+
+
+#define SINE_C_Q20 341782638 /* 2*SINE_NQUART/pi in Q12.20 */
+#define SINE_NQUART 512 /* Must be 2^N */
+#define SINE_TABLE_SIZE (SINE_NQUART+1)
+
+/* An 1/4 period of sine wave as Q1.31 */
+const int32_t sine_table[SINE_TABLE_SIZE] = {
+ 0,
+ 6588387,
+ 13176712,
+ 19764913,
+ 26352928,
+ 32940695,
+ 39528151,
+ 46115236,
+ 52701887,
+ 59288042,
+ 65873638,
+ 72458615,
+ 79042909,
+ 85626460,
+ 92209205,
+ 98791081,
+ 105372028,
+ 111951983,
+ 118530885,
+ 125108670,
+ 131685278,
+ 138260647,
+ 144834714,
+ 151407418,
+ 157978697,
+ 164548489,
+ 171116732,
+ 177683365,
+ 184248325,
+ 190811551,
+ 197372981,
+ 203932553,
+ 210490206,
+ 217045877,
+ 223599506,
+ 230151030,
+ 236700388,
+ 243247517,
+ 249792358,
+ 256334847,
+ 262874923,
+ 269412525,
+ 275947592,
+ 282480061,
+ 289009871,
+ 295536961,
+ 302061269,
+ 308582734,
+ 315101294,
+ 321616889,
+ 328129457,
+ 334638936,
+ 341145265,
+ 347648383,
+ 354148229,
+ 360644742,
+ 367137860,
+ 373627523,
+ 380113669,
+ 386596237,
+ 393075166,
+ 399550396,
+ 406021864,
+ 412489512,
+ 418953276,
+ 425413098,
+ 431868915,
+ 438320667,
+ 444768293,
+ 451211734,
+ 457650927,
+ 464085813,
+ 470516330,
+ 476942419,
+ 483364019,
+ 489781069,
+ 496193509,
+ 502601279,
+ 509004318,
+ 515402566,
+ 521795963,
+ 528184448,
+ 534567963,
+ 540946445,
+ 547319836,
+ 553688076,
+ 560051103,
+ 566408860,
+ 572761285,
+ 579108319,
+ 585449903,
+ 591785976,
+ 598116478,
+ 604441351,
+ 610760535,
+ 617073970,
+ 623381597,
+ 629683357,
+ 635979190,
+ 642269036,
+ 648552837,
+ 654830534,
+ 661102068,
+ 667367379,
+ 673626408,
+ 679879097,
+ 686125386,
+ 692365218,
+ 698598533,
+ 704825272,
+ 711045377,
+ 717258790,
+ 723465451,
+ 729665303,
+ 735858287,
+ 742044345,
+ 748223418,
+ 754395449,
+ 760560379,
+ 766718151,
+ 772868706,
+ 779011986,
+ 785147934,
+ 791276492,
+ 797397602,
+ 803511207,
+ 809617248,
+ 815715670,
+ 821806413,
+ 827889421,
+ 833964637,
+ 840032003,
+ 846091463,
+ 852142959,
+ 858186434,
+ 864221832,
+ 870249095,
+ 876268167,
+ 882278991,
+ 888281511,
+ 894275670,
+ 900261412,
+ 906238681,
+ 912207419,
+ 918167571,
+ 924119082,
+ 930061894,
+ 935995952,
+ 941921200,
+ 947837582,
+ 953745043,
+ 959643527,
+ 965532978,
+ 971413341,
+ 977284561,
+ 983146583,
+ 988999351,
+ 994842809,
+ 1000676905,
+ 1006501581,
+ 1012316784,
+ 1018122458,
+ 1023918549,
+ 1029705003,
+ 1035481765,
+ 1041248781,
+ 1047005996,
+ 1052753356,
+ 1058490807,
+ 1064218296,
+ 1069935767,
+ 1075643168,
+ 1081340445,
+ 1087027543,
+ 1092704410,
+ 1098370992,
+ 1104027236,
+ 1109673088,
+ 1115308496,
+ 1120933406,
+ 1126547765,
+ 1132151521,
+ 1137744620,
+ 1143327011,
+ 1148898640,
+ 1154459455,
+ 1160009404,
+ 1165548435,
+ 1171076495,
+ 1176593532,
+ 1182099495,
+ 1187594332,
+ 1193077990,
+ 1198550419,
+ 1204011566,
+ 1209461381,
+ 1214899812,
+ 1220326808,
+ 1225742318,
+ 1231146290,
+ 1236538675,
+ 1241919421,
+ 1247288477,
+ 1252645793,
+ 1257991319,
+ 1263325005,
+ 1268646799,
+ 1273956652,
+ 1279254515,
+ 1284540337,
+ 1289814068,
+ 1295075658,
+ 1300325059,
+ 1305562221,
+ 1310787095,
+ 1315999631,
+ 1321199780,
+ 1326387493,
+ 1331562722,
+ 1336725418,
+ 1341875532,
+ 1347013016,
+ 1352137822,
+ 1357249900,
+ 1362349204,
+ 1367435684,
+ 1372509294,
+ 1377569985,
+ 1382617710,
+ 1387652421,
+ 1392674071,
+ 1397682613,
+ 1402677999,
+ 1407660183,
+ 1412629117,
+ 1417584755,
+ 1422527050,
+ 1427455956,
+ 1432371426,
+ 1437273414,
+ 1442161874,
+ 1447036759,
+ 1451898025,
+ 1456745625,
+ 1461579513,
+ 1466399644,
+ 1471205973,
+ 1475998455,
+ 1480777044,
+ 1485541695,
+ 1490292364,
+ 1495029005,
+ 1499751575,
+ 1504460029,
+ 1509154322,
+ 1513834410,
+ 1518500249,
+ 1523151796,
+ 1527789006,
+ 1532411836,
+ 1537020243,
+ 1541614182,
+ 1546193612,
+ 1550758488,
+ 1555308767,
+ 1559844407,
+ 1564365366,
+ 1568871600,
+ 1573363067,
+ 1577839726,
+ 1582301533,
+ 1586748446,
+ 1591180425,
+ 1595597427,
+ 1599999410,
+ 1604386334,
+ 1608758157,
+ 1613114837,
+ 1617456334,
+ 1621782607,
+ 1626093615,
+ 1630389318,
+ 1634669675,
+ 1638934646,
+ 1643184190,
+ 1647418268,
+ 1651636840,
+ 1655839867,
+ 1660027308,
+ 1664199124,
+ 1668355276,
+ 1672495724,
+ 1676620431,
+ 1680729357,
+ 1684822463,
+ 1688899710,
+ 1692961061,
+ 1697006478,
+ 1701035921,
+ 1705049354,
+ 1709046738,
+ 1713028036,
+ 1716993211,
+ 1720942224,
+ 1724875039,
+ 1728791619,
+ 1732691927,
+ 1736575926,
+ 1740443580,
+ 1744294852,
+ 1748129706,
+ 1751948106,
+ 1755750016,
+ 1759535401,
+ 1763304223,
+ 1767056449,
+ 1770792043,
+ 1774510970,
+ 1778213194,
+ 1781898680,
+ 1785567395,
+ 1789219304,
+ 1792854372,
+ 1796472564,
+ 1800073848,
+ 1803658188,
+ 1807225552,
+ 1810775906,
+ 1814309215,
+ 1817825448,
+ 1821324571,
+ 1824806551,
+ 1828271355,
+ 1831718951,
+ 1835149305,
+ 1838562387,
+ 1841958164,
+ 1845336603,
+ 1848697673,
+ 1852041343,
+ 1855367580,
+ 1858676354,
+ 1861967633,
+ 1865241387,
+ 1868497585,
+ 1871736195,
+ 1874957188,
+ 1878160534,
+ 1881346201,
+ 1884514160,
+ 1887664382,
+ 1890796836,
+ 1893911493,
+ 1897008324,
+ 1900087300,
+ 1903148391,
+ 1906191569,
+ 1909216806,
+ 1912224072,
+ 1915213339,
+ 1918184580,
+ 1921137766,
+ 1924072870,
+ 1926989863,
+ 1929888719,
+ 1932769410,
+ 1935631909,
+ 1938476189,
+ 1941302224,
+ 1944109986,
+ 1946899450,
+ 1949670588,
+ 1952423376,
+ 1955157787,
+ 1957873795,
+ 1960571374,
+ 1963250500,
+ 1965911147,
+ 1968553291,
+ 1971176905,
+ 1973781966,
+ 1976368449,
+ 1978936330,
+ 1981485584,
+ 1984016188,
+ 1986528117,
+ 1989021349,
+ 1991495859,
+ 1993951624,
+ 1996388621,
+ 1998806828,
+ 2001206221,
+ 2003586778,
+ 2005948477,
+ 2008291295,
+ 2010615209,
+ 2012920200,
+ 2015206244,
+ 2017473320,
+ 2019721407,
+ 2021950483,
+ 2024160528,
+ 2026351521,
+ 2028523441,
+ 2030676268,
+ 2032809981,
+ 2034924561,
+ 2037019987,
+ 2039096240,
+ 2041153301,
+ 2043191149,
+ 2045209766,
+ 2047209132,
+ 2049189230,
+ 2051150040,
+ 2053091543,
+ 2055013722,
+ 2056916559,
+ 2058800035,
+ 2060664132,
+ 2062508835,
+ 2064334123,
+ 2066139982,
+ 2067926393,
+ 2069693341,
+ 2071440807,
+ 2073168776,
+ 2074877232,
+ 2076566159,
+ 2078235539,
+ 2079885359,
+ 2081515602,
+ 2083126253,
+ 2084717297,
+ 2086288719,
+ 2087840504,
+ 2089372637,
+ 2090885104,
+ 2092377891,
+ 2093850984,
+ 2095304369,
+ 2096738031,
+ 2098151959,
+ 2099546138,
+ 2100920555,
+ 2102275198,
+ 2103610053,
+ 2104925108,
+ 2106220351,
+ 2107495769,
+ 2108751351,
+ 2109987084,
+ 2111202958,
+ 2112398959,
+ 2113575079,
+ 2114731304,
+ 2115867625,
+ 2116984030,
+ 2118080510,
+ 2119157053,
+ 2120213650,
+ 2121250291,
+ 2122266966,
+ 2123263665,
+ 2124240379,
+ 2125197099,
+ 2126133816,
+ 2127050521,
+ 2127947205,
+ 2128823861,
+ 2129680479,
+ 2130517051,
+ 2131333571,
+ 2132130029,
+ 2132906419,
+ 2133662733,
+ 2134398965,
+ 2135115106,
+ 2135811152,
+ 2136487094,
+ 2137142926,
+ 2137778643,
+ 2138394239,
+ 2138989707,
+ 2139565042,
+ 2140120239,
+ 2140655292,
+ 2141170196,
+ 2141664947,
+ 2142139540,
+ 2142593970,
+ 2143028233,
+ 2143442325,
+ 2143836243,
+ 2144209981,
+ 2144563538,
+ 2144896909,
+ 2145210091,
+ 2145503082,
+ 2145775879,
+ 2146028479,
+ 2146260880,
+ 2146473079,
+ 2146665075,
+ 2146836865,
+ 2146988449,
+ 2147119824,
+ 2147230990,
+ 2147321945,
+ 2147392689,
+ 2147443221,
+ 2147473541,
+ 2147483647
+};
+
+/* Sine lookup table read */
+static inline int32_t sine_lookup(int idx) {
+ int32_t s;
+ int i1;
+
+ i1 = idx & (2 * SINE_NQUART - 1);
+ if (i1 > SINE_NQUART)
+ i1 = 2 * SINE_NQUART - i1;
+
+ if (idx > 2 * SINE_NQUART)
+ s = -sine_table[i1];
+ else
+ s = sine_table[i1];
+
+ return (s);
+}
+
+/* Compute fixed point sine with table lookup and interpolation */
+int32_t sin_fixed(int32_t w) {
+ int idx;
+ int32_t frac, s0, s1, delta;
+ int64_t sine, idx_tmp;
+
+ /* Q4.28 x Q12.20 -> Q16.48 */
+ idx_tmp = (int64_t) w * SINE_C_Q20;
+ idx = (int) (idx_tmp >> 48); /* Shift to Q0 */
+ idx_tmp = idx_tmp >> 17; /* Shift to Q16.31 */
+ idx_tmp = idx_tmp - (idx << 31); /* Get fraction */
+ frac = (int32_t) idx_tmp; /* Q1.31 */
+ s0 = sine_lookup(idx); /* Q1.31 */
+ s1 = sine_lookup(idx + 1); /* Q1.31 */
+ 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 */
+ return (int32_t) sine;
+}
+
diff --git a/src/tasks/audio.c b/src/tasks/audio.c
index ed99806..8dc42ce 100644
--- a/src/tasks/audio.c
+++ b/src/tasks/audio.c
@@ -64,6 +64,7 @@ int do_task(struct reef *reef)
sys_comp_switch_init();
sys_comp_volume_init();
sys_comp_src_init();
+ sys_comp_tone_init();
#if 0
/* init static pipeline */
--
2.11.0
1
0
[Sound-open-firmware] [PATCH] cache: Add cache management API to writeback/invalidate regions
by Liam Girdwood 07 Jun '17
by Liam Girdwood 07 Jun '17
07 Jun '17
Add an API to allow drivers to writeback or invalidate cache contents.
This is useful where the DSP firmware runs from cache and needs to
writeback/buffer prior to DMA or other peripheral usage.
Signed-off-by: Liam Girdwood <liam.r.girdwood(a)linux.intel.com>
---
src/audio/dai.c | 7 +++++++
src/audio/host.c | 7 +++++++
src/include/reef/mailbox.h | 9 +++++++--
src/lib/trace.c | 4 ++++
4 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/src/audio/dai.c b/src/audio/dai.c
index 8be8776..d02e365 100644
--- a/src/audio/dai.c
+++ b/src/audio/dai.c
@@ -43,6 +43,7 @@
#include <reef/audio/component.h>
#include <reef/audio/pipeline.h>
#include <platform/dma.h>
+#include <arch/cache.h>
#define DAI_PLAYBACK_STREAM 0
#define DAI_CAPTURE_STREAM 1
@@ -94,6 +95,9 @@ static void dai_dma_cb(void *data, uint32_t type, struct dma_sg_elem *next)
dd->dai_pos_blks += dma_buffer->ipc_buffer.size;
}
+ /* writeback buffer contents from cache */
+ dcache_writeback_region(dma_buffer->r_ptr, dev->period_bytes);
+
#if 0
// TODO: move this to new trace mechanism
trace_value((uint32_t)(dma_buffer->r_ptr - dma_buffer->addr));
@@ -111,6 +115,9 @@ static void dai_dma_cb(void *data, uint32_t type, struct dma_sg_elem *next)
dma_buffer = list_first_item(&dev->bsink_list,
struct comp_buffer, source_list);
+ /* invalidate buffer contents */
+ dcache_writeback_region(dma_buffer->w_ptr, dev->period_bytes);
+
dma_buffer->w_ptr += dev->period_bytes;
/* check for end of buffer */
diff --git a/src/audio/host.c b/src/audio/host.c
index 51ece99..9f81a1c 100644
--- a/src/audio/host.c
+++ b/src/audio/host.c
@@ -44,6 +44,7 @@
#include <reef/audio/component.h>
#include <reef/audio/pipeline.h>
#include <platform/dma.h>
+#include <arch/cache.h>
#include <uapi/ipc.h>
#define trace_host(__e) trace_event(TRACE_CLASS_HOST, __e)
@@ -127,6 +128,9 @@ static void host_dma_cb(void *data, uint32_t type, struct dma_sg_elem *next)
if (hd->params.pcm->direction == SOF_IPC_STREAM_PLAYBACK) {
dma_buffer->w_ptr += local_elem->size;
+ /* invalidate audio data */
+ dcache_invalidate_region(dma_buffer->w_ptr, local_elem->size);
+
if (dma_buffer->w_ptr >= dma_buffer->end_addr)
dma_buffer->w_ptr = dma_buffer->addr;
#if 0
@@ -144,6 +148,9 @@ static void host_dma_cb(void *data, uint32_t type, struct dma_sg_elem *next)
trace_value((uint32_t)(hd->dma_buffer->r_ptr - hd->dma_buffer->addr));
#endif
+ /* writeback audio data */
+ dcache_writeback_region(dma_buffer->r_ptr, local_elem->size);
+
/* recalc available buffer space */
comp_update_buffer_consume(hd->dma_buffer);
}
diff --git a/src/include/reef/mailbox.h b/src/include/reef/mailbox.h
index d3a7bf6..44366e4 100644
--- a/src/include/reef/mailbox.h
+++ b/src/include/reef/mailbox.h
@@ -32,6 +32,7 @@
#define __INCLUDE_MAILBOX__
#include <platform/mailbox.h>
+#include <arch/cache.h>
#include <stdint.h>
/* almost 1k should be enough for everyone ..... */
@@ -62,15 +63,19 @@
MAILBOX_DEBUG_SIZE
#define mailbox_outbox_write(dest, src, bytes) \
- rmemcpy((void*)(MAILBOX_OUTBOX_BASE + dest), src, bytes);
+ rmemcpy((void*)(MAILBOX_OUTBOX_BASE + dest), src, bytes); \
+ dcache_writeback_region((void*)(MAILBOX_OUTBOX_BASE + dest), bytes);
#define mailbox_outbox_read(dest, src, bytes) \
+ dcache_invalidate_region((void*)(MAILBOX_OUTBOX_BASE + src), bytes); \
rmemcpy(dest, (void*)(MAILBOX_OUTBOX_BASE + src), bytes);
#define mailbox_inbox_write(dest, src, bytes) \
- rmemcpy((void*)(MAILBOX_INBOX_BASE + dest), src, bytes);
+ rmemcpy((void*)(MAILBOX_INBOX_BASE + dest), src, bytes); \
+ dcache_writeback_region((void*)(MAILBOX_INBOX_BASE + dest), bytes);
#define mailbox_inbox_read(dest, src, bytes) \
+ dcache_invalidate_region((void*)(MAILBOX_INBOX_BASE + src), bytes); \
rmemcpy(dest, (void*)(MAILBOX_INBOX_BASE + src), bytes);
#endif
diff --git a/src/lib/trace.c b/src/lib/trace.c
index 278a59b..79d026e 100644
--- a/src/lib/trace.c
+++ b/src/lib/trace.c
@@ -29,6 +29,7 @@
*/
#include <reef/trace.h>
+#include <arch/cache.h>
#include <stdint.h>
/* trace position */
@@ -47,6 +48,9 @@ void _trace_event(uint32_t event)
t[0] = platform_timer_get(0);
t[1] = event;
+ /* writeback trace data */
+ dcache_writeback_region((void*)t, sizeof(uint32_t) * 2);
+
trace_pos += (sizeof(uint32_t) << 1);
if (trace_pos >= MAILBOX_TRACE_SIZE)
trace_pos = 0;
--
2.11.0
1
0
[Sound-open-firmware] [PATCH] drivers: dw-dma: move register macros into platform specific header.
by Liam Girdwood 06 Jun '17
by Liam Girdwood 06 Jun '17
06 Jun '17
Clean up the DW-DMA rsgisters so that it can be more easily integrated
into other platforms.
Signed-off-by: Liam Girdwood <liam.r.girdwood(a)linux.intel.com>
---
src/drivers/dw-dma.c | 106 ++++++++++++++++++---------
src/platform/baytrail/include/platform/dma.h | 26 +++++++
2 files changed, 99 insertions(+), 33 deletions(-)
diff --git a/src/drivers/dw-dma.c b/src/drivers/dw-dma.c
index 16f59d1..e851e54 100644
--- a/src/drivers/dw-dma.c
+++ b/src/drivers/dw-dma.c
@@ -62,6 +62,7 @@
#include <errno.h>
#include <stdint.h>
#include <string.h>
+#include <config.h>
/* channel registers */
#define DW_MAX_CHAN 8
@@ -108,20 +109,16 @@
#define DW_INTR_STATUS 0x0360
#define DW_DMA_CFG 0x0398
#define DW_DMA_CHAN_EN 0x03A0
-#define DW_FIFO_PART0_LO 0x0400
-#define DW_FIFO_PART0_HI 0x0404
-#define DW_FIFO_PART1_LO 0x0408
-#define DW_FIFO_PART1_HI 0x040C
-#define DW_CH_SAI_ERR 0x0410
/* channel bits */
#define INT_MASK(chan) (0x100 << chan)
#define INT_UNMASK(chan) (0x101 << chan)
+#define INT_MASK_ALL 0xFF00
+#define INT_UNMASK_ALL 0xFFFF
#define CHAN_ENABLE(chan) (0x101 << chan)
#define CHAN_DISABLE(chan) (0x100 << chan)
#define DW_CFG_CH_SUSPEND 0x100
-#define DW_CFG_CH_DRAIN 0x400
#define DW_CFG_CH_FIFO_EMPTY 0x200
/* CTL_LO */
@@ -136,8 +133,6 @@
#define DW_CTLL_SRC_FIX (2 << 9)
#define DW_CTLL_DST_MSIZE(x) (x << 11)
#define DW_CTLL_SRC_MSIZE(x) (x << 14)
-#define DW_CTLL_S_GATH_EN (1 << 17)
-#define DW_CTLL_D_SCAT_EN (1 << 18)
#define DW_CTLL_FC(x) (x << 20)
#define DW_CTLL_FC_M2M (0 << 20)
#define DW_CTLL_FC_M2P (1 << 20)
@@ -150,16 +145,6 @@
#define DW_CTLL_RELOAD_SRC (1 << 30)
#define DW_CTLL_RELOAD_DST (1 << 31)
-/* CTL_HI */
-#define DW_CTLH_DONE 0x00020000
-#define DW_CTLH_BLOCK_TS_MASK 0x0001ffff
-#define DW_CTLH_CLASS(x) (x << 29)
-#define DW_CTLH_WEIGHT(x) (x << 18)
-
-/* CFG_HI */
-#define DW_CFGH_SRC_PER(x) (x << 0)
-#define DW_CFGH_DST_PER(x) (x << 4)
-
/* tracing */
#define trace_dma(__e) trace_event(TRACE_CLASS_DMA, __e)
#define trace_dma_error(__e) trace_error(TRACE_CLASS_DMA, __e)
@@ -168,6 +153,9 @@
/* HW Linked list support currently disabled - needs debug for missing IRQs !!! */
#define DW_USE_HW_LLI 0
+/* number of tries to wait for reset */
+#define DW_DMA_CFG_TRIES 10000
+
/* data for each DMA channel */
struct dma_chan_data {
uint32_t status;
@@ -264,7 +252,7 @@ static void dw_dma_channel_put_unlocked(struct dma *dma, int channel)
return;
}
-
+#ifdef DW_CFG_CH_DRAIN /* have drain feature */
if (p->chan[channel].status == DMA_STATUS_PAUSED) {
dw_update_bits(dma, DW_CFG_LOW(channel),
@@ -276,6 +264,7 @@ static void dw_dma_channel_put_unlocked(struct dma *dma, int channel)
work_schedule_default(&p->chan[channel].work, 100);
return;
}
+#endif
/* mask block, transfer and error interrupts for channel */
dw_write(dma, DW_MASK_TFR, INT_MASK(channel));
@@ -456,8 +445,11 @@ static uint32_t dw_dma_fifo_work(void *data, uint32_t udelay)
/* clear suspend */
dw_update_bits(dma, DW_CFG_LOW(cd->channel),
+#ifdef DW_CFG_CH_DRAIN /* have drain feature */
DW_CFG_CH_SUSPEND | DW_CFG_CH_DRAIN, 0);
-
+#else
+ DW_CFG_CH_SUSPEND, 0);
+#endif
cd->status = DMA_STATUS_IDLE;
goto out;
}
@@ -470,8 +462,11 @@ static uint32_t dw_dma_fifo_work(void *data, uint32_t udelay)
/* clear suspend */
dw_update_bits(dma, DW_CFG_LOW(cd->channel),
+#ifdef DW_CFG_CH_DRAIN /* have drain feature */
DW_CFG_CH_SUSPEND | DW_CFG_CH_DRAIN, 0);
-
+#else
+ DW_CFG_CH_SUSPEND, 0);
+#endif
/* do we need to free it ? */
if (cd->status == DMA_STATUS_CLOSING)
dw_dma_channel_put_unlocked(dma, cd->channel);
@@ -512,15 +507,17 @@ static int dw_dma_stop(struct dma *dma, int channel, int drain)
}
/* suspend and drain */
+ bits = DW_CFG_CH_SUSPEND;
+ p->chan[channel].drain_count = 3;
+ p->chan[channel].status = DMA_STATUS_STOPPING;
+
+#ifdef DW_CFG_CH_DRAIN /* have drain feature, then may drain */
if (drain) {
- bits = DW_CFG_CH_SUSPEND | DW_CFG_CH_DRAIN;
+ bits |= DW_CFG_CH_DRAIN;
p->chan[channel].drain_count = 14;
p->chan[channel].status = DMA_STATUS_DRAINING;
- } else {
- bits = DW_CFG_CH_SUSPEND;
- p->chan[channel].drain_count = 3;
- p->chan[channel].status = DMA_STATUS_STOPPING;
}
+#endif
dw_update_bits(dma, DW_CFG_LOW(channel), bits, bits);
schedule = 1;
@@ -568,8 +565,8 @@ static int dw_dma_set_config(struct dma *dma, int channel,
/* default channel config */
p->chan[channel].direction = config->direction;
- p->chan[channel].cfg_lo = 0x00000003;
- p->chan[channel].cfg_hi = 0x0;
+ p->chan[channel].cfg_lo = DW_CFG_LOW_DEF;
+ p->chan[channel].cfg_hi = DW_CFG_HIGH_DEF;
/* get number of SG elems */
list_for_item(plist, &config->elem_list)
@@ -666,9 +663,19 @@ static int dw_dma_set_config(struct dma *dma, int channel,
break;
}
+ if (sg_elem->size > DW_CTLH_BLOCK_TS_MASK) {
+ trace_dma_error("eDS");
+ return -EINVAL;
+ }
/* set transfer size of element */
+#if defined CONFIG_BAYTRAIL || defined CONFIG_CHERRYTRAIL
lli_desc->ctrl_hi = DW_CTLH_CLASS(p->class) |
(sg_elem->size & DW_CTLH_BLOCK_TS_MASK);
+#else
+ /* for the unit is transaction--TR_WIDTH. */
+ lli_desc->ctrl_hi = (sg_elem->size / (1 << (lli_desc->ctrl_lo >> 4 & 0x7)))
+ & DW_CTLH_BLOCK_TS_MASK;
+#endif
/* set next descriptor in list */
lli_desc->llp = (uint32_t)(lli_desc + 1);
@@ -768,8 +775,14 @@ static inline void dw_dma_chan_reload_next(struct dma *dma, int channel,
dw_write(dma, DW_DAR(channel), next->dest);
/* set transfer size of element */
+#if defined CONFIG_BAYTRAIL || defined CONFIG_CHERRYTRAIL
lli->ctrl_hi = DW_CTLH_CLASS(p->class) |
(next->size & DW_CTLH_BLOCK_TS_MASK);
+#else
+ /* for the unit is transaction--TR_WIDTH. */
+ lli->ctrl_hi = (next->size / (1 << (lli->ctrl_lo >> 4 & 0x7)))
+ & DW_CTLH_BLOCK_TS_MASK;
+#endif
/* program CTLn */
dw_write(dma, DW_CTRL_LOW(channel), lli->ctrl_lo);
@@ -872,16 +885,38 @@ static void dw_dma_setup(struct dma *dma)
struct dw_drv_plat_data *dp = dma->plat_data.drv_plat_data;
int i;
+ /* we cannot config DMAC if DMAC has been already enabled by host */
+ if (dw_read(dma, DW_DMA_CFG) != 0)
+ dw_write(dma, DW_DMA_CFG, 0x0);
+
+ /* now check that it's 0 */
+ for (i = DW_DMA_CFG_TRIES; i > 0; i--) {
+ if (dw_read(dma, DW_DMA_CFG) == 0)
+ goto found;
+ }
+ trace_dma_error("eDs");
+ return;
+
+found:
+ for (i = 0; i < DW_MAX_CHAN; i++)
+ dw_read(dma, DW_DMA_CHAN_EN);
+
+#ifdef HAVE_HDDA
+ /* enable HDDA before DMAC */
+ shim_write(SHIM_HMDC, SHIM_HMDC_HDDA_ALLCH);
+#endif
+
/* enable the DMA controller */
dw_write(dma, DW_DMA_CFG, 1);
/* mask all interrupts for all 8 channels */
- dw_write(dma, DW_MASK_TFR, 0x0000ff00);
- dw_write(dma, DW_MASK_BLOCK, 0x0000ff00);
- dw_write(dma, DW_MASK_SRC_TRAN, 0x0000ff00);
- dw_write(dma, DW_MASK_DST_TRAN, 0x0000ff00);
- dw_write(dma, DW_MASK_ERR, 0x0000ff00);
+ dw_write(dma, DW_MASK_TFR, INT_MASK_ALL);
+ dw_write(dma, DW_MASK_BLOCK, INT_MASK_ALL);
+ dw_write(dma, DW_MASK_SRC_TRAN, INT_MASK_ALL);
+ dw_write(dma, DW_MASK_DST_TRAN, INT_MASK_ALL);
+ dw_write(dma, DW_MASK_ERR, INT_MASK_ALL);
+#ifdef DW_FIFO_PARTITION
/* TODO: we cannot config DMA FIFOs if DMAC has been already */
/* allocate FIFO partitions, 128 bytes for each ch */
dw_write(dma, DW_FIFO_PART1_LO, 0x100080);
@@ -889,10 +924,15 @@ static void dw_dma_setup(struct dma *dma)
dw_write(dma, DW_FIFO_PART0_HI, 0x100080);
dw_write(dma, DW_FIFO_PART0_LO, 0x100080 | (1 << 26));
dw_write(dma, DW_FIFO_PART0_LO, 0x100080);
+#endif
/* set channel priorities */
for (i = 0; i < DW_MAX_CHAN; i++) {
+#if defined CONFIG_BAYTRAIL || defined CONFIG_CHERRYTRAIL
dw_write(dma, DW_CTRL_HIGH(i), DW_CTLH_CLASS(dp->chan[i].class));
+#else
+ dw_write(dma, DW_CFG_LOW(i), DW_CFG_CLASS(dp->chan[i].class));
+#endif
}
}
diff --git a/src/platform/baytrail/include/platform/dma.h b/src/platform/baytrail/include/platform/dma.h
index eec501a..5f5c52a 100644
--- a/src/platform/baytrail/include/platform/dma.h
+++ b/src/platform/baytrail/include/platform/dma.h
@@ -38,6 +38,32 @@
#define DMA_ID_DMAC1 1
#define DMA_ID_DMAC2 2
+/* baytrail specific registers */
+/* CTL_LO */
+#define DW_CTLL_S_GATH_EN (1 << 17)
+#define DW_CTLL_D_SCAT_EN (1 << 18)
+/* CTL_HI */
+#define DW_CTLH_DONE 0x00020000
+#define DW_CTLH_BLOCK_TS_MASK 0x0001ffff
+#define DW_CTLH_CLASS(x) (x << 29)
+#define DW_CTLH_WEIGHT(x) (x << 18)
+/* CFG_LO */
+#define DW_CFG_CH_DRAIN 0x400
+/* CFG_HI */
+#define DW_CFGH_SRC_PER(x) (x << 0)
+#define DW_CFGH_DST_PER(x) (x << 4)
+/* FIFO Partition */
+#define DW_FIFO_PARTITION
+#define DW_FIFO_PART0_LO 0x0400
+#define DW_FIFO_PART0_HI 0x0404
+#define DW_FIFO_PART1_LO 0x0408
+#define DW_FIFO_PART1_HI 0x040C
+#define DW_CH_SAI_ERR 0x0410
+
+/* default initial setup register values */
+#define DW_CFG_LOW_DEF 0x00000003
+#define DW_CFG_HIGH_DEF 0x0
+
#define DMA_HANDSHAKE_SSP0_RX 0
#define DMA_HANDSHAKE_SSP0_TX 1
#define DMA_HANDSHAKE_SSP1_RX 2
--
2.11.0
1
4
[Sound-open-firmware] [PATCH] trace: add more detailed trace vales for init
by Liam Girdwood 06 Jun '17
by Liam Girdwood 06 Jun '17
06 Jun '17
Signed-off-by: Liam Girdwood <liam.r.girdwood(a)linux.intel.com>
---
src/include/reef/trace.h | 9 ++++++++-
src/init/init.c | 3 ++-
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/src/include/reef/trace.h b/src/include/reef/trace.h
index 76908f5..cb861e0 100644
--- a/src/include/reef/trace.h
+++ b/src/include/reef/trace.h
@@ -48,7 +48,10 @@
/* system specific codes */
#define TRACE_BOOT_SYS_WORK (TRACE_BOOT_SYS + 0x100)
-#define TRACE_BOOT_SYS_CPU_FREQ (TRACE_BOOT_SYS + 0x101)
+#define TRACE_BOOT_SYS_CPU_FREQ (TRACE_BOOT_SYS + 0x200)
+#define TRACE_BOOT_SYS_HEAP (TRACE_BOOT_SYS + 0x300)
+#define TRACE_BOOT_SYS_NOTE (TRACE_BOOT_SYS + 0x400)
+#define TRACE_BOOT_SYS_SCHED (TRACE_BOOT_SYS + 0x500)
/* platform/device specific codes */
#define TRACE_BOOT_PLATFORM_MBOX (TRACE_BOOT_PLATFORM + 0x100)
@@ -75,6 +78,10 @@
#define TRACE_CLASS_LOCK (10 << 24)
#define TRACE_CLASS_MEM (11 << 24)
#define TRACE_CLASS_MIXER (12 << 24)
+#define TRACE_CLASS_BUFFER (13 << 24)
+#define TRACE_CLASS_VOLUME (14 << 24)
+#define TRACE_CLASS_SWITCH (15 << 24)
+#define TRACE_CLASS_MUX (16 << 24)
/* move to config.h */
#define TRACE 1
diff --git a/src/init/init.c b/src/init/init.c
index 1a6b11c..31d727e 100644
--- a/src/init/init.c
+++ b/src/init/init.c
@@ -55,10 +55,11 @@ int main(int argc, char *argv[])
trace_point(TRACE_BOOT_ARCH);
/* initialise system services */
+ trace_point(TRACE_BOOT_SYS_HEAP);
init_heap();
init_system_notify();
- trace_point(TRACE_BOOT_SYS);
+ trace_point(TRACE_BOOT_SYS_NOTE);
/* init the platform */
err = platform_init();
--
2.11.0
1
2
[Sound-open-firmware] [PATCH] build: fix generation of commit ID and build number
by Liam Girdwood 06 Jun '17
by Liam Girdwood 06 Jun '17
06 Jun '17
Signed-off-by: Liam Girdwood <liam.r.girdwood(a)linux.intel.com>
---
.gitignore | 2 ++
Makefile.am | 5 ++++-
configure.ac | 2 +-
git-version.sh | 16 ++++++++++++++--
src/ipc/intel-ipc.c | 3 +--
5 files changed, 22 insertions(+), 6 deletions(-)
diff --git a/.gitignore b/.gitignore
index 9223f60..c8a8ab0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,8 @@
*.man
.version
.tarball-version
+*.x
+.build
Makefile
Makefile.in
diff --git a/Makefile.am b/Makefile.am
index c47580e..362e2bd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -17,10 +17,13 @@ export PLATFORM_INCDIR = \
BUILT_SOURCES = $(top_srcdir)/src/include/version.h
-$(top_srcdir)/src/include/version.h:
+$(top_srcdir)/src/include/version.h: Makefile
./git-version.sh
dist-hook:
./git-version.sh
cat .version > $(distdir)/.tarball-version
cat .version > $(distdir)/.version
+
+all-local:
+ rm -f $(top_srcdir)/src/include/version.h
diff --git a/configure.ac b/configure.ac
index 7c1acf4..f085a73 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
AC_PREREQ([2.69])
-AC_INIT([Reef],[m4_esyscmd(./git-version.sh)],[sound-open-firmware(a)alsa-project.org])
+AC_INIT([Reef],[m4_esyscmd(./git-version.sh), m4_esyscmd(rm -f .build)],[sound-open-firmware(a)alsa-project.org])
AC_CONFIG_SRCDIR([src/init/init.c])
AC_CONFIG_HEADERS([src/include/config.h])
AC_CONFIG_MACRO_DIRS([m4])
diff --git a/git-version.sh b/git-version.sh
index f8f1e58..c6beb40 100755
--- a/git-version.sh
+++ b/git-version.sh
@@ -1,10 +1,22 @@
# version for configure
-echo -n `git describe --abbrev=4`
+# echo -n `git describe --abbrev=4`
# version for make dist
git describe --abbrev=4 > .version
git describe --abbrev=4 > .tarball-version
# git commit for IPC
-echo "#define REEF_BUILD \"`git describe --abbrev=4 | cut -d- -f3`\"" > src/include/version.h
+echo "#define REEF_TAG \"`git describe --abbrev=4 | cut -d- -f3`\"" > src/include/version.h
+
+# build counter
+if [ -e .build ]; then
+ num=$((`cat .build` + 1))
+else
+ num=0
+fi
+
+# save and insert build counter
+echo $num > .build
+echo "#define REEF_BUILD $num" >> src/include/version.h
+
diff --git a/src/ipc/intel-ipc.c b/src/ipc/intel-ipc.c
index 7db4179..e0ab4f7 100644
--- a/src/ipc/intel-ipc.c
+++ b/src/ipc/intel-ipc.c
@@ -120,11 +120,10 @@ static inline uint32_t msg_get_stage_type(uint32_t msg)
/* TODO: add build count */
static const struct ipc_intel_ipc_fw_version fw_version = {
- .build = 0,
+ .build = REEF_BUILD,
.minor = REEF_MINOR,
.major = REEF_MAJOR,
.type = 0,
- .fw_build_hash = REEF_BUILD,
.fw_log_providers_hash = 0,
};
--
2.11.0
1
4
[Sound-open-firmware] [PATCH] work: enable/disable workq timer following each timer_set/clear()
by Keyon Jie 16 Mar '17
by Keyon Jie 16 Mar '17
16 Mar '17
We need enable/disable workq timer also after each calling to
set/clear timer, but not only CPU frequency change, so merge
them into work_set/clear_timer().
Signed-off-by: Keyon Jie <yang.jie(a)linux.intel.com>
---
src/lib/work.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/lib/work.c b/src/lib/work.c
index 55a6f90..7da6f68 100644
--- a/src/lib/work.c
+++ b/src/lib/work.c
@@ -75,11 +75,13 @@ static struct work_queue *queue_;
static inline void work_set_timer(struct work_queue *queue, uint32_t ticks)
{
queue->ts->timer_set(&queue->ts->timer, ticks);
+ timer_enable(&queue->ts->timer);
}
static inline void work_clear_timer(struct work_queue *queue)
{
queue->ts->timer_clear(&queue->ts->timer);
+ timer_disable(&queue->ts->timer);
}
static inline uint32_t work_get_timer(struct work_queue *queue)
@@ -308,10 +310,8 @@ static void work_notify(int message, void *data, void *event_data)
queue->ticks_per_usec * PLATFORM_WORKQ_WINDOW;
queue_recalc_timers(queue, clk_data);
queue_reschedule(queue);
- timer_enable(&queue->ts->timer);
} else if (message == CLOCK_NOTIFY_PRE) {
/* CPU frequency update pending */
- timer_disable(&queue->ts->timer);
}
spin_unlock_irq(&queue->lock, flags);
--
2.7.4
2
1
16 Mar '17
Add default clk type SSP_CLK_DEFAULT and the handle for it
Signed-off-by: Keyon Jie <yang.jie(a)linux.intel.com>
---
src/drivers/ssp.c | 2 ++
src/include/reef/ssp.h | 1 +
2 files changed, 3 insertions(+)
diff --git a/src/drivers/ssp.c b/src/drivers/ssp.c
index b22e06d..c0d4ef3 100644
--- a/src/drivers/ssp.c
+++ b/src/drivers/ssp.c
@@ -101,6 +101,8 @@ static inline int ssp_set_config(struct dai *dai, struct dai_config *dai_config)
case DAI_FMT_CBS_CFM:
sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR | SSCR1_SCFR;
break;
+ case SSP_CLK_DEFAULT:
+ break;
default:
return -EINVAL;
}
diff --git a/src/include/reef/ssp.h b/src/include/reef/ssp.h
index b1c1afd..b1f370b 100644
--- a/src/include/reef/ssp.h
+++ b/src/include/reef/ssp.h
@@ -42,6 +42,7 @@
#define SSP_CLK_NET_PLL 1
#define SSP_CLK_EXT 2
#define SSP_CLK_NET 3
+#define SSP_CLK_DEFAULT 4
/* SSP register offsets */
#define SSCR0 0x00
--
2.7.4
2
1
16 Mar '17
Signed-off-by: Keyon Jie <yang.jie(a)linux.intel.com>
---
src/lib/work.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/lib/work.c b/src/lib/work.c
index f93da31..8062ca5 100644
--- a/src/lib/work.c
+++ b/src/lib/work.c
@@ -300,7 +300,7 @@ static void work_notify(int message, void *data, void *event_data)
spin_lock_irq(&queue->lock, flags);
- /* we need to re-caclulate timer when CPU freqency changes */
+ /* we need to re-caclulate timer when CPU frequency changes */
if (message == CLOCK_NOTIFY_POST) {
/* CPU frequency update complete */
@@ -336,7 +336,7 @@ void work_schedule(struct work_queue *queue, struct work *w, uint32_t timeout)
goto out;
}
- /* convert timeout microsecs to CPU clock ticks */
+ /* convert timeout micro seconds to CPU clock ticks */
w->timeout = queue->ticks_per_usec * timeout + work_get_timer(queue);
/* insert work into list */
--
2.7.4
2
1