1 // SPDX-License-Identifier: BSD-3-Clause
2 //
3 // Copyright(c) 2016 Intel Corporation. All rights reserved.
4 //
5 // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
6
7 #include <sof/audio/component_ext.h>
8 #include <sof/common.h>
9 #include <rtos/panic.h>
10 #include <rtos/interrupt.h>
11 #include <sof/ipc/msg.h>
12 #include <rtos/alloc.h>
13 #include <rtos/cache.h>
14 #include <sof/lib/memory.h>
15 #include <sof/list.h>
16 #include <rtos/sof.h>
17 #include <rtos/string.h>
18 #include <ipc/topology.h>
19 #include <errno.h>
20 #include <stdbool.h>
21 #include <stddef.h>
22 #include <stdint.h>
23
24 #if defined(__XCC__)
25 #include <xtensa/config/core-isa.h>
26 #if XCHAL_HAVE_HIFI3 || XCHAL_HAVE_HIFI4
27 #define STREAMCOPY_HIFI3
28 #endif
29 #endif
30
31 LOG_MODULE_REGISTER(component, CONFIG_SOF_LOG_LEVEL);
32
33 static SHARED_DATA struct comp_driver_list cd;
34
35 /* 7c42ce8b-0108-43d0-9137-56d660478c5f */
36 DECLARE_SOF_UUID("component", comp_uuid, 0x7c42ce8b, 0x0108, 0x43d0,
37 0x91, 0x37, 0x56, 0xd6, 0x60, 0x47, 0x8c, 0x5f);
38
39 DECLARE_TR_CTX(comp_tr, SOF_UUID(comp_uuid), LOG_LEVEL_INFO);
40
comp_register(struct comp_driver_info * drv)41 int comp_register(struct comp_driver_info *drv)
42 {
43 struct comp_driver_list *drivers = comp_drivers_get();
44 k_spinlock_key_t key;
45
46 key = k_spin_lock(&drivers->lock);
47 list_item_prepend(&drv->list, &drivers->list);
48 k_spin_unlock(&drivers->lock, key);
49
50 return 0;
51 }
52
comp_unregister(struct comp_driver_info * drv)53 void comp_unregister(struct comp_driver_info *drv)
54 {
55 struct comp_driver_list *drivers = comp_drivers_get();
56 k_spinlock_key_t key;
57
58 key = k_spin_lock(&drivers->lock);
59 list_item_del(&drv->list);
60 k_spin_unlock(&drivers->lock, key);
61 }
62
63 /* NOTE: Keep the component state diagram up to date:
64 * sof-docs/developer_guides/firmware/components/images/comp-dev-states.pu
65 */
66
comp_set_state(struct comp_dev * dev,int cmd)67 int comp_set_state(struct comp_dev *dev, int cmd)
68 {
69 int requested_state = comp_get_requested_state(cmd);
70
71 if (dev->state == requested_state) {
72 comp_info(dev, "comp_set_state(), state already set to %u",
73 dev->state);
74 #ifdef CONFIG_IPC_MAJOR_4
75 return 0;
76 #else
77 return COMP_STATUS_STATE_ALREADY_SET;
78 #endif
79 }
80
81 switch (cmd) {
82 case COMP_TRIGGER_START:
83 if (dev->state != COMP_STATE_PRE_ACTIVE) {
84 comp_err(dev, "comp_set_state(): wrong state = %u, COMP_TRIGGER_START",
85 dev->state);
86 return -EINVAL;
87 }
88 break;
89 case COMP_TRIGGER_RELEASE:
90 if (dev->state != COMP_STATE_PRE_ACTIVE) {
91 comp_err(dev, "comp_set_state(): wrong state = %u, COMP_TRIGGER_RELEASE",
92 dev->state);
93 return -EINVAL;
94 }
95 break;
96 case COMP_TRIGGER_STOP:
97 if (dev->state != COMP_STATE_ACTIVE &&
98 dev->state != COMP_STATE_PAUSED) {
99 comp_err(dev, "comp_set_state(): wrong state = %u, COMP_TRIGGER_STOP",
100 dev->state);
101 return -EINVAL;
102 }
103 break;
104 case COMP_TRIGGER_PAUSE:
105 /* only support pausing for running */
106 if (dev->state != COMP_STATE_ACTIVE) {
107 comp_err(dev, "comp_set_state(): wrong state = %u, COMP_TRIGGER_PAUSE",
108 dev->state);
109 return -EINVAL;
110 }
111 break;
112 case COMP_TRIGGER_RESET:
113 /* reset always succeeds */
114 if (dev->state == COMP_STATE_ACTIVE)
115 comp_err(dev, "comp_set_state(): wrong state = %u, COMP_TRIGGER_RESET",
116 dev->state);
117 else if (dev->state == COMP_STATE_PAUSED)
118 comp_info(dev, "comp_set_state(): state = %u, COMP_TRIGGER_RESET",
119 dev->state);
120 break;
121 case COMP_TRIGGER_PREPARE:
122 if (dev->state != COMP_STATE_READY) {
123 comp_err(dev, "comp_set_state(): wrong state = %u, COMP_TRIGGER_PREPARE",
124 dev->state);
125 return -EINVAL;
126 }
127 break;
128 case COMP_TRIGGER_PRE_START:
129 if (dev->state != COMP_STATE_PREPARE) {
130 comp_err(dev,
131 "comp_set_state(): wrong state = %u, COMP_TRIGGER_PRE_START",
132 dev->state);
133 return -EINVAL;
134 }
135 break;
136 case COMP_TRIGGER_PRE_RELEASE:
137 if (dev->state != COMP_STATE_PAUSED) {
138 comp_err(dev,
139 "comp_set_state(): wrong state = %u, COMP_TRIGGER_PRE_RELEASE",
140 dev->state);
141 return -EINVAL;
142 }
143 break;
144 default:
145 return 0;
146 }
147
148 dev->state = requested_state;
149
150 return 0;
151 }
152
sys_comp_init(struct sof * sof)153 void sys_comp_init(struct sof *sof)
154 {
155 sof->comp_drivers = platform_shared_get(&cd, sizeof(cd));
156
157 list_init(&sof->comp_drivers->list);
158 k_spinlock_init(&sof->comp_drivers->lock);
159 }
160
comp_get_copy_limits(struct comp_buffer __sparse_cache * source,struct comp_buffer __sparse_cache * sink,struct comp_copy_limits * cl)161 void comp_get_copy_limits(struct comp_buffer __sparse_cache *source,
162 struct comp_buffer __sparse_cache *sink,
163 struct comp_copy_limits *cl)
164 {
165 cl->frames = audio_stream_avail_frames(&source->stream, &sink->stream);
166 cl->source_frame_bytes = audio_stream_frame_bytes(&source->stream);
167 cl->sink_frame_bytes = audio_stream_frame_bytes(&sink->stream);
168 cl->source_bytes = cl->frames * cl->source_frame_bytes;
169 cl->sink_bytes = cl->frames * cl->sink_frame_bytes;
170 }
171
comp_get_copy_limits_frame_aligned(const struct comp_buffer __sparse_cache * source,const struct comp_buffer __sparse_cache * sink,struct comp_copy_limits * cl)172 void comp_get_copy_limits_frame_aligned(const struct comp_buffer __sparse_cache *source,
173 const struct comp_buffer __sparse_cache *sink,
174 struct comp_copy_limits *cl)
175 {
176 cl->frames = audio_stream_avail_frames_aligned(&source->stream, &sink->stream);
177 cl->source_frame_bytes = audio_stream_frame_bytes(&source->stream);
178 cl->sink_frame_bytes = audio_stream_frame_bytes(&sink->stream);
179 cl->source_bytes = cl->frames * cl->source_frame_bytes;
180 cl->sink_bytes = cl->frames * cl->sink_frame_bytes;
181 }
182
183 #ifdef STREAMCOPY_HIFI3
184
audio_stream_copy(const struct audio_stream __sparse_cache * source,uint32_t ioffset,struct audio_stream __sparse_cache * sink,uint32_t ooffset,uint32_t samples)185 int audio_stream_copy(const struct audio_stream __sparse_cache *source, uint32_t ioffset,
186 struct audio_stream __sparse_cache *sink, uint32_t ooffset, uint32_t samples)
187 {
188 int ssize = audio_stream_sample_bytes(source); /* src fmt == sink fmt */
189 ae_int16x4 *src = (ae_int16x4 *)((int8_t *)source->r_ptr + ioffset * ssize);
190 ae_int16x4 *dst = (ae_int16x4 *)((int8_t *)sink->w_ptr + ooffset * ssize);
191 int shorts = samples * ssize >> 1;
192 int shorts_src;
193 int shorts_dst;
194 int shorts_copied;
195 int left, m, i;
196 ae_int16x4 in_sample = AE_ZERO16();
197 ae_valign inu = AE_ZALIGN64();
198 ae_valign outu = AE_ZALIGN64();
199
200 /* copy with 16bit as the minimum unit since the minimum sample size is 16 bit*/
201 while (shorts) {
202 src = audio_stream_wrap(source, src);
203 dst = audio_stream_wrap(sink, dst);
204 shorts_src = audio_stream_samples_without_wrap_s16(source, src);
205 shorts_dst = audio_stream_samples_without_wrap_s16(sink, dst);
206 shorts_copied = AE_MIN_32_signed(shorts_src, shorts_dst);
207 shorts_copied = AE_MIN_32_signed(shorts, shorts_copied);
208 m = shorts_copied >> 2;
209 left = shorts_copied & 0x03;
210 inu = AE_LA64_PP(src);
211 /* copy 4 * 16bit(8 bytes)per loop */
212 for (i = 0; i < m; i++) {
213 AE_LA16X4_IP(in_sample, inu, src);
214 AE_SA16X4_IP(in_sample, outu, dst);
215 }
216 AE_SA64POS_FP(outu, dst);
217
218 /* process the left bits that less than 4 * 16 */
219 for (i = 0; i < left ; i++) {
220 AE_L16_IP(in_sample, (ae_int16 *)src, sizeof(ae_int16));
221 AE_S16_0_IP(in_sample, (ae_int16 *)dst, sizeof(ae_int16));
222 }
223 shorts -= shorts_copied;
224 }
225 return samples;
226 }
227
228 #else
229
audio_stream_copy(const struct audio_stream __sparse_cache * source,uint32_t ioffset,struct audio_stream __sparse_cache * sink,uint32_t ooffset,uint32_t samples)230 int audio_stream_copy(const struct audio_stream __sparse_cache *source, uint32_t ioffset,
231 struct audio_stream __sparse_cache *sink, uint32_t ooffset, uint32_t samples)
232 {
233 int ssize = audio_stream_sample_bytes(source); /* src fmt == sink fmt */
234 uint8_t *src = audio_stream_wrap(source, (uint8_t *)source->r_ptr + ioffset * ssize);
235 uint8_t *snk = audio_stream_wrap(sink, (uint8_t *)sink->w_ptr + ooffset * ssize);
236 size_t bytes = samples * ssize;
237 size_t bytes_src;
238 size_t bytes_snk;
239 size_t bytes_copied;
240
241 while (bytes) {
242 bytes_src = audio_stream_bytes_without_wrap(source, src);
243 bytes_snk = audio_stream_bytes_without_wrap(sink, snk);
244 bytes_copied = MIN(bytes_src, bytes_snk);
245 bytes_copied = MIN(bytes, bytes_copied);
246 memcpy(snk, src, bytes_copied);
247 bytes -= bytes_copied;
248 src = audio_stream_wrap(source, src + bytes_copied);
249 snk = audio_stream_wrap(sink, snk + bytes_copied);
250 }
251
252 return samples;
253 }
254
255 #endif
256
audio_stream_copy_from_linear(const void * linear_source,int ioffset,struct audio_stream __sparse_cache * sink,int ooffset,unsigned int samples)257 void audio_stream_copy_from_linear(const void *linear_source, int ioffset,
258 struct audio_stream __sparse_cache *sink, int ooffset,
259 unsigned int samples)
260 {
261 int ssize = audio_stream_sample_bytes(sink); /* src fmt == sink fmt */
262 uint8_t *src = (uint8_t *)linear_source + ioffset * ssize;
263 uint8_t *snk = audio_stream_wrap(sink, (uint8_t *)sink->w_ptr + ooffset * ssize);
264 size_t bytes = samples * ssize;
265 size_t bytes_snk;
266 size_t bytes_copied;
267
268 while (bytes) {
269 bytes_snk = audio_stream_bytes_without_wrap(sink, snk);
270 bytes_copied = MIN(bytes, bytes_snk);
271 memcpy(snk, src, bytes_copied);
272 bytes -= bytes_copied;
273 src += bytes_copied;
274 snk = audio_stream_wrap(sink, snk + bytes_copied);
275 }
276 }
277
audio_stream_copy_to_linear(const struct audio_stream __sparse_cache * source,int ioffset,void * linear_sink,int ooffset,unsigned int samples)278 void audio_stream_copy_to_linear(const struct audio_stream __sparse_cache *source, int ioffset,
279 void *linear_sink, int ooffset, unsigned int samples)
280 {
281 int ssize = audio_stream_sample_bytes(source); /* src fmt == sink fmt */
282 uint8_t *src = audio_stream_wrap(source, (uint8_t *)source->r_ptr + ioffset * ssize);
283 uint8_t *snk = (uint8_t *)linear_sink + ooffset * ssize;
284 size_t bytes = samples * ssize;
285 size_t bytes_src;
286 size_t bytes_copied;
287
288 while (bytes) {
289 bytes_src = audio_stream_bytes_without_wrap(source, src);
290 bytes_copied = MIN(bytes, bytes_src);
291 memcpy(snk, src, bytes_copied);
292 bytes -= bytes_copied;
293 src = audio_stream_wrap(source, src + bytes_copied);
294 snk += bytes_copied;
295 }
296 }
297
298 /** See comp_ops::copy */
comp_copy(struct comp_dev * dev)299 int comp_copy(struct comp_dev *dev)
300 {
301 int ret = 0;
302
303 assert(dev->drv->ops.copy);
304
305 /* copy only if we are the owner of the LL component */
306 if (dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_LL &&
307 cpu_is_me(dev->ipc_config.core)) {
308 #if CONFIG_PERFORMANCE_COUNTERS
309 perf_cnt_init(&dev->pcd);
310 #endif
311
312 ret = dev->drv->ops.copy(dev);
313
314 #if CONFIG_PERFORMANCE_COUNTERS
315 perf_cnt_stamp(&dev->pcd, perf_trace_null, dev);
316 perf_cnt_average(&dev->pcd, comp_perf_avg_info, dev);
317 #endif
318 }
319
320 return ret;
321 }
322