blob: 86f56dedf21c5370c26cc4b4be7a927be5e56e90 [file] [log] [blame]
Seppo Ingalsuo6a274832017-06-07 14:17:55 +03001/*
2 * Copyright (c) 2017, Intel Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the Intel Corporation nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
29 * Liam Girdwood <liam.r.girdwood@linux.intel.com>
30 * Keyon Jie <yang.jie@linux.intel.com>
31 */
32
33#include <stdint.h>
34#include <stddef.h>
35#include <errno.h>
36#include <reef/reef.h>
37#include <reef/lock.h>
38#include <reef/list.h>
39#include <reef/stream.h>
40#include <reef/alloc.h>
41#include <reef/work.h>
42#include <reef/clock.h>
43#include <reef/audio/component.h>
44#include <reef/audio/pipeline.h>
Liam Girdwood17641522017-06-09 17:27:02 +010045#include <uapi/ipc.h>
Seppo Ingalsuo6a274832017-06-07 14:17:55 +030046#include "src_core.h"
47
48#ifdef MODULE_TEST
49#include <stdio.h>
50#endif
51
52#define trace_src(__e) trace_event(TRACE_CLASS_SRC, __e)
53#define tracev_src(__e) tracev_event(TRACE_CLASS_SRC, __e)
54#define trace_src_error(__e) trace_error(TRACE_CLASS_SRC, __e)
55
56/* src component private data */
57struct comp_data {
58 struct polyphase_src src[PLATFORM_MAX_CHANNELS];
59 int32_t *delay_lines;
Liam Girdwood3488cce2017-08-10 11:59:08 +010060 uint32_t sink_rate;
61 uint32_t source_rate;
Seppo Ingalsuo54162292017-09-12 13:45:50 +030062 uint32_t period_bytes; /* sink period */
Seppo Ingalsuo887628a2017-09-14 16:00:05 +030063 int scratch_length; /* Buffer for stage1-stage2 */
64 int sign_extend_s24; /* Set if need to copy sign bit to b24..b31 */
Seppo Ingalsuo6a274832017-06-07 14:17:55 +030065 void (*src_func)(struct comp_dev *dev,
66 struct comp_buffer *source,
67 struct comp_buffer *sink,
68 uint32_t source_frames,
69 uint32_t sink_frames);
70};
71
72/* Common mute function for 2s and 1s SRC. This preserves the same
73 * buffer consume and produce pattern as normal operation.
74 */
75static void src_muted_s32(struct comp_buffer *source, struct comp_buffer *sink,
76 int blk_in, int blk_out, int nch, int source_frames)
77{
78
79 int i;
80 int32_t *src = (int32_t *) source->r_ptr;
81 int32_t *dest = (int32_t *) sink->w_ptr;
82 int32_t *end = (int32_t *) sink->end_addr;
83 int n_read = 0;
84 int n_max;
85 int n;
86 int n_written = 0;
87
88 for (i = 0; i < source_frames - blk_in + 1; i += blk_in) {
89 n_max = end - dest;
90 n = nch*blk_out;
91 if (n < n_max) {
92 bzero(dest, n * sizeof(int32_t));
93 dest += n;
94 } else {
95 /* Also case n_max == n is done here */
96 bzero(dest, n_max * sizeof(int32_t));
97 dest = (int32_t *) sink->addr;
98 bzero(dest, (n - n_max) * sizeof(int32_t));
99 dest += n - n_max;
100 }
101 n_read += nch*blk_in;
102 n_written += nch*blk_out;
103 }
104 source->r_ptr = src + n_read;
105 sink->w_ptr = dest;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300106}
107
108/* Fallback function to just output muted samples and advance
109 * pointers. Note that a buffer that is not having integer number of
110 * frames in a period will drift since there is no similar blk in/out
111 * check as for SRC.
112 */
113static void fallback_s32(struct comp_dev *dev,
114 struct comp_buffer *source,
115 struct comp_buffer *sink,
116 uint32_t source_frames,
117 uint32_t sink_frames)
118{
119
120 struct comp_data *cd = comp_get_drvdata(dev);
Liam Girdwood3488cce2017-08-10 11:59:08 +0100121 int nch = dev->params.channels;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300122 int blk_in = cd->src[0].blk_in;
123 int blk_out = cd->src[0].blk_out;
124
125 src_muted_s32(source, sink, blk_in, blk_out, nch, source_frames);
126
127}
128
129/* Normal 2 stage SRC */
130static void src_2s_s32_default(struct comp_dev *dev,
131 struct comp_buffer *source, struct comp_buffer *sink,
132 uint32_t source_frames, uint32_t sink_frames)
133{
134 int i, j;
135 struct polyphase_src *s;
136 struct comp_data *cd = comp_get_drvdata(dev);
137 int blk_in = cd->src[0].blk_in;
138 int blk_out = cd->src[0].blk_out;
139 int n_times1 = cd->src[0].stage1_times;
140 int n_times2 = cd->src[0].stage2_times;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100141 int nch = dev->params.channels;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300142 int32_t *dest = (int32_t *) sink->w_ptr;
143 int32_t *src = (int32_t *) source->r_ptr;
144 struct src_stage_prm s1, s2;
145 int n_read = 0;
146 int n_written = 0;
147
148 if (cd->src[0].mute) {
Liam Girdwood3488cce2017-08-10 11:59:08 +0100149 src_muted_s32(source, sink, blk_in, blk_out, nch, source_frames);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300150 return;
151 }
152
153 s1.times = n_times1;
154 s1.x_end_addr = source->end_addr;
Liam Girdwood44509242017-09-07 15:34:42 +0100155 s1.x_size = source->size;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300156 s1.x_inc = nch;
157 s1.y_end_addr = &cd->delay_lines[cd->scratch_length];
Seppo Ingalsuo887628a2017-09-14 16:00:05 +0300158 s1.y_size = cd->scratch_length * sizeof(int32_t);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300159 s1.y_inc = 1;
160
161 s2.times = n_times2;
162 s2.x_end_addr = &cd->delay_lines[cd->scratch_length];
Seppo Ingalsuo887628a2017-09-14 16:00:05 +0300163 s2.x_size = cd->scratch_length * sizeof(int32_t);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300164 s2.x_inc = 1;
165 s2.y_end_addr = sink->end_addr;
Liam Girdwood44509242017-09-07 15:34:42 +0100166 s2.y_size = sink->size;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300167 s2.y_inc = nch;
168
Seppo Ingalsuo6f27ab62017-06-12 11:31:15 +0300169 s1.x_rptr = src + nch - 1;
170 s2.y_wptr = dest + nch - 1;
171
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300172 for (j = 0; j < nch; j++) {
173 s = &cd->src[j]; /* Point to src[] for this channel */
174 s1.x_rptr = src++;
175 s2.y_wptr = dest++;
176 s1.state = &s->state1;
177 s1.stage = s->stage1;
178 s2.state = &s->state2;
179 s2.stage = s->stage2;
180
181 for (i = 0; i < source_frames - blk_in + 1; i += blk_in) {
182 /* Reset output to buffer start, read interleaved */
183 s1.y_wptr = cd->delay_lines;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300184 s2.x_rptr = cd->delay_lines;
Seppo Ingalsuo887628a2017-09-14 16:00:05 +0300185 if (cd->sign_extend_s24) {
186 src_polyphase_stage_cir_s24(&s1);
187 src_polyphase_stage_cir_s24(&s2);
188 } else {
189 src_polyphase_stage_cir(&s1);
190 src_polyphase_stage_cir(&s2);
191 }
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300192
193 n_read += blk_in;
194 n_written += blk_out;
195 }
196 }
197 source->r_ptr = s1.x_rptr - nch + 1;
198 sink->w_ptr = s2.y_wptr - nch + 1;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300199}
200
201/* 1 stage SRC for simple conversions */
202static void src_1s_s32_default(struct comp_dev *dev,
203 struct comp_buffer *source, struct comp_buffer *sink,
204 uint32_t source_frames, uint32_t sink_frames)
205{
206 int i, j;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300207 struct polyphase_src *s;
208
209 struct comp_data *cd = comp_get_drvdata(dev);
210 int blk_in = cd->src[0].blk_in;
211 int blk_out = cd->src[0].blk_out;
212 int n_times = cd->src[0].stage1_times;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100213 int nch = dev->params.channels;
Seppo Ingalsuo4a006912017-06-28 19:25:51 +0300214 int32_t *dest = (int32_t *) sink->w_ptr;
215 int32_t *src = (int32_t *) source->r_ptr;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300216 int n_read = 0;
217 int n_written = 0;
218 struct src_stage_prm s1;
219
220 if (cd->src[0].mute) {
Seppo Ingalsuo4a006912017-06-28 19:25:51 +0300221 src_muted_s32(source, sink, blk_in, blk_out, nch,
222 source_frames);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300223 return;
224 }
225
226 s1.times = n_times;
227 s1.x_end_addr = source->end_addr;
Liam Girdwood44509242017-09-07 15:34:42 +0100228 s1.x_size = source->size;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300229 s1.x_inc = nch;
230 s1.y_end_addr = sink->end_addr;
Liam Girdwood44509242017-09-07 15:34:42 +0100231 s1.y_size = sink->size;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300232 s1.y_inc = nch;
Seppo Ingalsuo6f27ab62017-06-12 11:31:15 +0300233 s1.x_rptr = src + nch - 1;
234 s1.y_wptr = dest + nch - 1;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300235
236 for (j = 0; j < nch; j++) {
237 s = &cd->src[j]; /* Point to src for this channel */
238 s1.x_rptr = src++;
239 s1.y_wptr = dest++;
240 s1.state = &s->state1;
241 s1.stage = s->stage1;
242
243 for (i = 0; i + blk_in - 1 < source_frames; i += blk_in) {
Seppo Ingalsuo887628a2017-09-14 16:00:05 +0300244 if (cd->sign_extend_s24)
245 src_polyphase_stage_cir_s24(&s1);
246 else
247 src_polyphase_stage_cir(&s1);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300248
249 n_read += blk_in;
250 n_written += blk_out;
251 }
252
253 }
254 source->r_ptr = s1.x_rptr - nch + 1;
255 sink->w_ptr = s1.y_wptr - nch + 1;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300256}
257
258static struct comp_dev *src_new(struct sof_ipc_comp *comp)
259{
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300260 struct comp_dev *dev;
Liam Girdwood960cf8e2017-06-12 11:38:07 +0100261 struct sof_ipc_comp_src *src;
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300262 struct sof_ipc_comp_src *ipc_src = (struct sof_ipc_comp_src *) comp;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300263 struct comp_data *cd;
Liam Girdwood960cf8e2017-06-12 11:38:07 +0100264 int i;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300265
Liam Girdwood3488cce2017-08-10 11:59:08 +0100266 trace_src("new");
Liam Girdwood960cf8e2017-06-12 11:38:07 +0100267
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100268 /* validate init data - either SRC sink or source rate must be set */
269 if (ipc_src->source_rate == 0 && ipc_src->sink_rate == 0) {
270 trace_src_error("sn1");
271 return NULL;
272 }
273
Liam Girdwood3488cce2017-08-10 11:59:08 +0100274 dev = rzalloc(RZONE_RUNTIME, RFLAGS_NONE,
Liam Girdwood17641522017-06-09 17:27:02 +0100275 COMP_SIZE(struct sof_ipc_comp_src));
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300276 if (dev == NULL)
277 return NULL;
278
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300279 src = (struct sof_ipc_comp_src *) &dev->comp;
Liam Girdwood960cf8e2017-06-12 11:38:07 +0100280 memcpy(src, ipc_src, sizeof(struct sof_ipc_comp_src));
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300281
Liam Girdwood3488cce2017-08-10 11:59:08 +0100282 cd = rzalloc(RZONE_RUNTIME, RFLAGS_NONE, sizeof(*cd));
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300283 if (cd == NULL) {
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300284 rfree(dev);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300285 return NULL;
286 }
287
288 comp_set_drvdata(dev, cd);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300289
290 cd->delay_lines = NULL;
291 cd->src_func = src_2s_s32_default;
292 for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
293 src_polyphase_reset(&cd->src[i]);
294
Liam Girdwoodbe41b682017-09-21 16:48:18 +0100295 dev->state = COMP_STATE_READY;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300296 return dev;
297}
298
299static void src_free(struct comp_dev *dev)
300{
301 struct comp_data *cd = comp_get_drvdata(dev);
302
Liam Girdwood3488cce2017-08-10 11:59:08 +0100303 trace_src("fre");
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300304
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300305 /* Free dynamically reserved buffers for SRC algorithm */
306 if (cd->delay_lines != NULL)
307 rfree(cd->delay_lines);
308
309 rfree(cd);
310 rfree(dev);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300311}
312
313/* set component audio stream parameters */
Liam Girdwood2cfaebe2017-08-21 17:13:52 +0100314static int src_params(struct comp_dev *dev)
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300315{
Liam Girdwood3488cce2017-08-10 11:59:08 +0100316 struct sof_ipc_stream_params *params = &dev->params;
317 struct sof_ipc_comp_src *src = COMP_GET_IPC(dev, sof_ipc_comp_src);
318 struct sof_ipc_comp_config *config = COMP_GET_CONFIG(dev);
319 struct comp_data *cd = comp_get_drvdata(dev);
Seppo Ingalsuo54162292017-09-12 13:45:50 +0300320 struct comp_buffer *sink, *source;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300321 struct src_alloc need;
322 size_t delay_lines_size;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100323 uint32_t source_rate, sink_rate;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300324 int32_t *buffer_start;
Seppo Ingalsuo849a5282017-09-22 16:08:44 +0300325 int n = 0, i, err, frames_is_for_source, nch, q;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300326
Liam Girdwood3488cce2017-08-10 11:59:08 +0100327 trace_src("par");
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300328
Seppo Ingalsuo887628a2017-09-14 16:00:05 +0300329 /* SRC supports S24_4LE and S32_LE formats */
330 switch (config->frame_fmt) {
331 case SOF_IPC_FRAME_S24_4LE:
332 cd->sign_extend_s24 = 1;
333 break;
334 case SOF_IPC_FRAME_S32_LE:
335 cd->sign_extend_s24 = 0;
336 break;
337 default:
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100338 trace_src_error("sr0");
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300339 return -EINVAL;
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100340 }
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300341
Liam Girdwood3488cce2017-08-10 11:59:08 +0100342 /* Calculate source and sink rates, one rate will come from IPC new
343 * and the other from params. */
344 if (src->source_rate == 0) {
345 /* params rate is source rate */
346 source_rate = params->rate;
347 sink_rate = src->sink_rate;
348 /* re-write our params with output rate for next component */
349 params->rate = sink_rate;
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300350 frames_is_for_source = 0;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100351 } else {
352 /* params rate is sink rate */
353 source_rate = src->source_rate;
354 sink_rate = params->rate;
355 /* re-write our params with output rate for next component */
356 params->rate = source_rate;
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300357 frames_is_for_source = 1;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100358 }
Seppo Ingalsuo4a006912017-06-28 19:25:51 +0300359
360 /* Allocate needed memory for delay lines */
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300361 err = src_buffer_lengths(&need, source_rate, sink_rate,
362 params->channels, dev->frames, frames_is_for_source);
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100363 if (err < 0) {
364 trace_src_error("sr1");
365 trace_value(source_rate);
366 trace_value(sink_rate);
367 trace_value(params->channels);
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300368 trace_value(dev->frames);
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100369 return err;
370 }
371
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300372 delay_lines_size = sizeof(int32_t) * need.total;
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100373 if (delay_lines_size == 0) {
374 trace_src_error("sr2");
375 return -EINVAL;
376 }
377
378 /* free any existing dalay lines. TODO reuse if same size */
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300379 if (cd->delay_lines != NULL)
380 rfree(cd->delay_lines);
381
Liam Girdwood22ce8062017-09-03 22:04:26 +0100382 cd->delay_lines = rballoc(RZONE_RUNTIME, RFLAGS_NONE, delay_lines_size);
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100383 if (cd->delay_lines == NULL) {
384 trace_src_error("sr3");
385 trace_value(delay_lines_size);
Liam Girdwood3488cce2017-08-10 11:59:08 +0100386 return -EINVAL;
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100387 }
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300388
389 /* Clear all delay lines here */
390 memset(cd->delay_lines, 0, delay_lines_size);
391 cd->scratch_length = need.scratch;
392 buffer_start = cd->delay_lines + need.scratch;
393
394 /* Initize SRC for actual sample rate */
Seppo Ingalsuo849a5282017-09-22 16:08:44 +0300395 nch = MIN(params->channels, PLATFORM_MAX_CHANNELS);
396 for (i = 0; i < nch; i++) {
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300397 n = src_polyphase_init(&cd->src[i], source_rate, sink_rate,
398 &need, buffer_start);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300399 buffer_start += need.single_src;
400 }
401
402 switch (n) {
403 case 1:
404 cd->src_func = src_1s_s32_default; /* Simpler 1 stage SRC */
405 break;
406 case 2:
407 cd->src_func = src_2s_s32_default; /* Default 2 stage SRC */
408 break;
409 default:
410 /* This is possibly due to missing coefficients for
411 * requested rates combination. Sink audio will be
412 * muted if copy() is run.
413 */
414 trace_src("SFa");
415 cd->src_func = fallback_s32;
Seppo Ingalsuo4a006912017-06-28 19:25:51 +0300416 return -EINVAL;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100417 break;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300418 }
419
Seppo Ingalsuo14d10a82017-09-22 16:08:47 +0300420 /* Calculate period size based on config. First make sure that
421 * frame_bytes is set.
422 */
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300423 dev->frame_bytes =
424 dev->params.sample_container_bytes * dev->params.channels;
Liam Girdwood44509242017-09-07 15:34:42 +0100425 cd->period_bytes = dev->frames * dev->frame_bytes;
426
Seppo Ingalsuo54162292017-09-12 13:45:50 +0300427 /* The downstream buffer must be at least length of blk_out plus
428 * dev->frames and an integer multiple of dev->frames. The
429 * buffer_set_size will return an error if the required length would
430 * be too long.
431 */
432 q = need.blk_out / dev->frames;
433 if (q * dev->frames < need.blk_out)
434 ++q;
435
436 if (q * dev->frames < need.blk_out + dev->frames)
437 ++q;
438
439 /* Configure downstream buffer */
440 sink = list_first_item(&dev->bsink_list, struct comp_buffer,
441 source_list);
442 err = buffer_set_size(sink, q * dev->frames * dev->frame_bytes);
Liam Girdwood44509242017-09-07 15:34:42 +0100443 if (err < 0) {
444 trace_src_error("eSz");
Seppo Ingalsuo887628a2017-09-14 16:00:05 +0300445 trace_value(sink->alloc_size);
446 trace_value(q * dev->frames * dev->frame_bytes);
Liam Girdwood44509242017-09-07 15:34:42 +0100447 return err;
448 }
449
450 buffer_reset_pos(sink);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300451
Seppo Ingalsuo54162292017-09-12 13:45:50 +0300452 /* Check that source buffer has sufficient size */
453 source = list_first_item(&dev->bsource_list, struct comp_buffer,
454 sink_list);
455 if (source->size < need.blk_in * dev->frame_bytes) {
456 trace_src_error("eSy");
457 return -EINVAL;
458 }
459
460
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300461 return 0;
462}
463
Liam Girdwood854b2e52017-09-02 23:14:02 +0100464static int src_ctrl_cmd(struct comp_dev *dev, struct sof_ipc_ctrl_data *cdata)
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300465{
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300466 struct comp_data *cd = comp_get_drvdata(dev);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300467 int i;
468
Liam Girdwood854b2e52017-09-02 23:14:02 +0100469 switch (cdata->cmd) {
470 case SOF_CTRL_CMD_MUTE:
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300471 trace_src("SMu");
472 for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
473 src_polyphase_mute(&cd->src[i]);
474
475 break;
Liam Girdwood854b2e52017-09-02 23:14:02 +0100476 case SOF_CTRL_CMD_UNMUTE:
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300477 trace_src("SUm");
478 for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
479 src_polyphase_unmute(&cd->src[i]);
480
481 break;
Liam Girdwood854b2e52017-09-02 23:14:02 +0100482 default:
483 trace_src_error("ec1");
484 return -EINVAL;
485 }
486
487 return 0;
488}
489
490/* used to pass standard and bespoke commands (with data) to component */
491static int src_cmd(struct comp_dev *dev, int cmd, void *data)
492{
493 struct sof_ipc_ctrl_data *cdata = data;
Ranjani Sridharan62004082017-09-06 22:01:40 +0100494 int ret = 0;
Liam Girdwood854b2e52017-09-02 23:14:02 +0100495
Liam Girdwoodbe41b682017-09-21 16:48:18 +0100496 trace_src("cmd");
497
498 ret = comp_set_state(dev, cmd);
499 if (ret < 0)
500 return ret;
Liam Girdwood854b2e52017-09-02 23:14:02 +0100501
502 switch (cmd) {
503 case COMP_CMD_SET_VALUE:
504 return src_ctrl_cmd(dev, cdata);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300505 default:
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300506 break;
507 }
508
Ranjani Sridharan62004082017-09-06 22:01:40 +0100509 return ret;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300510}
511
512/* copy and process stream data from source to sink buffers */
513static int src_copy(struct comp_dev *dev)
514{
515 struct comp_data *cd = comp_get_drvdata(dev);
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300516 struct comp_buffer *source, *sink;
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300517 int need_source, need_sink, blk_in, blk_out;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300518
519 trace_comp("SRC");
520
521 /* src component needs 1 source and 1 sink buffer */
522 source = list_first_item(&dev->bsource_list, struct comp_buffer,
523 sink_list);
524 sink = list_first_item(&dev->bsink_list, struct comp_buffer,
525 source_list);
526
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300527 /* Calculate needed amount of source buffer and sink buffer
528 * for one SRC run.
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300529 */
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300530 blk_in = src_polyphase_get_blk_in(&cd->src[0]);
531 blk_out = src_polyphase_get_blk_out(&cd->src[0]);
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300532 need_source = blk_in * dev->frame_bytes;
533 need_sink = blk_out * dev->frame_bytes;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300534
535 /* Run as many times as buffers allow */
536 while ((source->avail >= need_source) && (sink->free >= need_sink)) {
537 /* Run src */
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300538 cd->src_func(dev, source, sink, blk_in, blk_out);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300539
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300540 /* calc new free and available */
541 comp_update_buffer_consume(source, 0);
542 comp_update_buffer_produce(sink, 0);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300543 }
544
545 return 0;
546}
547
548static int src_prepare(struct comp_dev *dev)
549{
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300550 dev->state = COMP_STATE_PREPARE;
551 return 0;
552}
553
554static int src_preload(struct comp_dev *dev)
555{
Liam Girdwood3488cce2017-08-10 11:59:08 +0100556 return src_copy(dev);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300557}
558
559static int src_reset(struct comp_dev *dev)
560{
561 int i;
562 struct comp_data *cd = comp_get_drvdata(dev);
563
564 trace_src("SRe");
565
566 cd->src_func = src_2s_s32_default;
567 for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
568 src_polyphase_reset(&cd->src[i]);
569
Liam Girdwoodbe41b682017-09-21 16:48:18 +0100570 dev->state = COMP_STATE_READY;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300571 return 0;
572}
573
574struct comp_driver comp_src = {
575 .type = SOF_COMP_SRC,
Seppo Ingalsuo4a006912017-06-28 19:25:51 +0300576 .ops = {
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300577 .new = src_new,
578 .free = src_free,
579 .params = src_params,
580 .cmd = src_cmd,
581 .copy = src_copy,
582 .prepare = src_prepare,
583 .reset = src_reset,
584 .preload = src_preload,
585 },
586};
587
588void sys_comp_src_init(void)
589{
590 comp_register(&comp_src);
591}