1 // SPDX-License-Identifier: BSD-3-Clause
2 //
3 // Copyright(c) 2018 Intel Corporation. All rights reserved.
4
5 #include <stdint.h>
6 #include <stddef.h>
7 #include <time.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <rtos/string.h>
11 #include <math.h>
12 #include <rtos/sof.h>
13 #include <rtos/task.h>
14 #include <rtos/alloc.h>
15 #include <sof/lib/notifier.h>
16 #include <sof/ipc/driver.h>
17 #include <sof/ipc/topology.h>
18 #include <sof/lib/agent.h>
19 #include <sof/lib/dai.h>
20 #include <sof/lib/dma.h>
21 #include <sof/schedule/edf_schedule.h>
22 #include <sof/schedule/ll_schedule.h>
23 #include <sof/schedule/ll_schedule_domain.h>
24 #include <sof/schedule/schedule.h>
25 #include <rtos/wait.h>
26 #include <sof/audio/pipeline.h>
27 #include <sof/audio/component_ext.h>
28 #include "testbench/common_test.h"
29 #include "testbench/trace.h"
30 #include <tplg_parser/topology.h>
31
32 /* testbench helper functions for pipeline setup and trigger */
33
tb_setup(struct sof * sof,struct testbench_prm * tp)34 int tb_setup(struct sof *sof, struct testbench_prm *tp)
35 {
36 struct ll_schedule_domain domain = {0};
37
38 domain.next_tick = tp->tick_period_us;
39
40 /* init components */
41 sys_comp_init(sof);
42 sys_comp_file_init();
43 sys_comp_asrc_init();
44 sys_comp_crossover_init();
45 sys_comp_dcblock_init();
46 sys_comp_drc_init();
47 sys_comp_multiband_drc_init();
48 sys_comp_selector_init();
49 sys_comp_src_init();
50
51 /* Module adapter components */
52 sys_comp_module_demux_interface_init();
53 sys_comp_module_eq_fir_interface_init();
54 sys_comp_module_eq_iir_interface_init();
55 sys_comp_module_mux_interface_init();
56 sys_comp_module_tdfb_interface_init();
57 sys_comp_module_volume_interface_init();
58
59 /* other necessary initializations, todo: follow better SOF init */
60 pipeline_posn_init(sof);
61 init_system_notify(sof);
62
63 /* init IPC */
64 if (ipc_init(sof) < 0) {
65 fprintf(stderr, "error: IPC init\n");
66 return -EINVAL;
67 }
68
69 /* init LL scheduler */
70 if (scheduler_init_ll(&domain) < 0) {
71 fprintf(stderr, "error: edf scheduler init\n");
72 return -EINVAL;
73 }
74
75 /* init EDF scheduler */
76 if (scheduler_init_edf() < 0) {
77 fprintf(stderr, "error: edf scheduler init\n");
78 return -EINVAL;
79 }
80
81 debug_print("ipc and scheduler initialized\n");
82
83 return 0;
84 }
85
86 struct ipc_data {
87 struct ipc_data_host_buffer dh_buffer;
88 };
89
tb_free(struct sof * sof)90 void tb_free(struct sof *sof)
91 {
92 struct schedule_data *sch;
93 struct schedulers **schedulers;
94 struct list_item *slist, *_slist;
95 struct notify **notify = arch_notify_get();
96 struct ipc_data *iipc;
97
98 free(*notify);
99
100 /* free all scheduler data */
101 schedule_free(0);
102 schedulers = arch_schedulers_get();
103 list_for_item_safe(slist, _slist, &(*schedulers)->list) {
104 sch = container_of(slist, struct schedule_data, list);
105 free(sch);
106 }
107 free(*arch_schedulers_get());
108
109 /* free IPC data */
110 iipc = sof->ipc->private;
111 free(sof->ipc->comp_data);
112 free(iipc->dh_buffer.page_table);
113 free(iipc);
114 free(sof->ipc);
115 }
116
117 /* Get pipeline host component */
tb_get_pipeline_host(struct pipeline * p)118 static struct comp_dev *tb_get_pipeline_host(struct pipeline *p)
119 {
120 struct comp_dev *cd;
121
122 cd = p->source_comp;
123 if (cd->direction == SOF_IPC_STREAM_CAPTURE)
124 cd = p->sink_comp;
125
126 return cd;
127 }
128
129 /* set up pcm params, prepare and trigger pipeline */
tb_pipeline_start(struct ipc * ipc,struct pipeline * p)130 int tb_pipeline_start(struct ipc *ipc, struct pipeline *p)
131 {
132 struct comp_dev *cd;
133 int ret;
134
135 /* Get pipeline host component */
136 cd = tb_get_pipeline_host(p);
137
138 /* Component prepare */
139 ret = pipeline_prepare(p, cd);
140 if (ret < 0) {
141 fprintf(stderr, "error: Failed prepare pipeline command: %s\n",
142 strerror(ret));
143 return ret;
144 }
145
146 /* Start the pipeline */
147 ret = pipeline_trigger(cd->pipeline, cd, COMP_TRIGGER_PRE_START);
148 if (ret < 0) {
149 fprintf(stderr, "error: Failed to start pipeline command: %s\n",
150 strerror(ret));
151 return ret;
152 }
153
154 return ret;
155 }
156
157 /* set up pcm params, prepare and trigger pipeline */
tb_pipeline_stop(struct ipc * ipc,struct pipeline * p)158 int tb_pipeline_stop(struct ipc *ipc, struct pipeline *p)
159 {
160 struct comp_dev *cd;
161 int ret;
162
163 /* Get pipeline host component */
164 cd = tb_get_pipeline_host(p);
165
166 ret = pipeline_trigger(cd->pipeline, cd, COMP_TRIGGER_STOP);
167 if (ret < 0) {
168 fprintf(stderr, "error: Failed to stop pipeline command: %s\n",
169 strerror(ret));
170 }
171
172 return ret;
173 }
174
175 /* set up pcm params, prepare and trigger pipeline */
tb_pipeline_reset(struct ipc * ipc,struct pipeline * p)176 int tb_pipeline_reset(struct ipc *ipc, struct pipeline *p)
177 {
178 struct comp_dev *cd;
179 int ret;
180
181 /* Get pipeline host component */
182 cd = tb_get_pipeline_host(p);
183
184 ret = pipeline_reset(p, cd);
185 if (ret < 0)
186 fprintf(stderr, "error: pipeline reset\n");
187
188 return ret;
189 }
190
191 /* pipeline pcm params */
tb_pipeline_params(struct testbench_prm * tp,struct ipc * ipc,struct pipeline * p,struct tplg_context * ctx)192 int tb_pipeline_params(struct testbench_prm *tp, struct ipc *ipc, struct pipeline *p,
193 struct tplg_context *ctx)
194 {
195 struct ipc_comp_dev *pcm_dev;
196 struct comp_dev *cd;
197 struct sof_ipc_pcm_params params = {{0}};
198 char message[DEBUG_MSG_LEN];
199 int fs_period;
200 int period;
201 int ret = 0;
202
203 if (!p) {
204 fprintf(stderr, "error: pipeline is NULL\n");
205 return -EINVAL;
206 }
207
208 period = p->period;
209
210 /* Compute period from sample rates */
211 fs_period = (int)(0.9999 + tp->fs_in * period / 1e6);
212 sprintf(message, "period sample count %d\n", fs_period);
213 debug_print(message);
214
215 /* set pcm params */
216 params.comp_id = p->comp_id;
217 params.params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED;
218 params.params.frame_fmt = tp->frame_fmt;
219 params.params.rate = tp->fs_in;
220 params.params.channels = tp->channels_in;
221
222 switch (params.params.frame_fmt) {
223 case SOF_IPC_FRAME_S16_LE:
224 params.params.sample_container_bytes = 2;
225 params.params.sample_valid_bytes = 2;
226 break;
227 case SOF_IPC_FRAME_S24_4LE:
228 params.params.sample_container_bytes = 4;
229 params.params.sample_valid_bytes = 3;
230 break;
231 case SOF_IPC_FRAME_S32_LE:
232 params.params.sample_container_bytes = 4;
233 params.params.sample_valid_bytes = 4;
234 break;
235 default:
236 fprintf(stderr, "error: invalid frame format\n");
237 return -EINVAL;
238 }
239
240 params.params.host_period_bytes = fs_period * params.params.channels *
241 params.params.sample_container_bytes;
242
243 /* get scheduling component device for pipeline*/
244 pcm_dev = ipc_get_comp_by_id(ipc, p->sched_id);
245 if (!pcm_dev) {
246 fprintf(stderr, "error: ipc get comp\n");
247 return -EINVAL;
248 }
249
250 /* Get pipeline host component */
251 cd = tb_get_pipeline_host(p);
252
253 /* Set pipeline params direction from scheduling component */
254 params.params.direction = cd->direction;
255
256 printf("test params: rate %d channels %d format %d\n",
257 params.params.rate, params.params.channels,
258 params.params.frame_fmt);
259
260 /* pipeline params */
261 ret = pipeline_params(p, cd, ¶ms);
262 if (ret < 0)
263 fprintf(stderr, "error: pipeline_params\n");
264
265 return ret;
266 }
267
268 /* print debug messages */
debug_print(char * message)269 void debug_print(char *message)
270 {
271 if (debug)
272 printf("debug: %s", message);
273 }
274
275 /* enable trace in testbench */
tb_enable_trace(bool enable)276 void tb_enable_trace(bool enable)
277 {
278 test_bench_trace = enable;
279 if (enable)
280 debug_print("trace print enabled\n");
281 else
282 debug_print("trace print disabled\n");
283 }
284