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 * Keyon Jie <yang.jie@linux.intel.com>
7 */
8
9 /**
10 * \file include/sof/audio/component_ext.h
11 * \brief Component API for Infrastructure
12 * \author Liam Girdwood <liam.r.girdwood@linux.intel.com>
13 * \author Keyon Jie <yang.jie@linux.intel.com>
14 */
15
16 #ifndef __SOF_AUDIO_COMPONENT_INT_H__
17 #define __SOF_AUDIO_COMPONENT_INT_H__
18
19 #include <sof/audio/component.h>
20 #include <rtos/idc.h>
21 #include <sof/list.h>
22 #include <ipc/topology.h>
23 #include <kernel/abi.h>
24 #include <stdbool.h>
25
26 /** \addtogroup component_api_helpers Component Mgmt API
27 * @{
28 */
29
30 /** \brief Holds list of registered components' drivers */
31 struct comp_driver_list {
32 struct list_item list; /**< list of component drivers */
33 struct k_spinlock lock; /**< list lock */
34 };
35
36 /** \brief Retrieves the component device buffer list. */
37 #define comp_buffer_list(comp, dir) \
38 ((dir) == PPL_DIR_DOWNSTREAM ? &(comp)->bsink_list : \
39 &(comp)->bsource_list)
40
41 /** See comp_ops::new */
42 #if CONFIG_IPC_MAJOR_3
43 struct comp_dev *comp_new(struct sof_ipc_comp *comp);
44 #elif CONFIG_IPC_MAJOR_4
45 struct comp_dev *comp_new_ipc4(struct ipc4_module_init_instance *module_init);
46 #endif
47
48 /** See comp_ops::free */
comp_free(struct comp_dev * dev)49 static inline void comp_free(struct comp_dev *dev)
50 {
51 assert(dev->drv->ops.free);
52
53 /* free task if shared component or DP task*/
54 if ((dev->is_shared || dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) &&
55 dev->task) {
56 schedule_task_free(dev->task);
57 rfree(dev->task);
58 }
59
60 dev->drv->ops.free(dev);
61 }
62
63 /**
64 * Parameter init for component on other core.
65 * @param dev Component device.
66 * @param params Parameters to be set.
67 * @return 0 if succeeded, error code otherwise.
68 */
comp_params_remote(struct comp_dev * dev,struct sof_ipc_stream_params * params)69 static inline int comp_params_remote(struct comp_dev *dev,
70 struct sof_ipc_stream_params *params)
71 {
72 struct idc_msg msg = { IDC_MSG_PARAMS, IDC_MSG_PARAMS_EXT(dev->ipc_config.id),
73 dev->ipc_config.core, sizeof(*params), params, };
74
75 return idc_send_msg(&msg, IDC_BLOCKING);
76 }
77
78 /** See comp_ops::params */
comp_params(struct comp_dev * dev,struct sof_ipc_stream_params * params)79 static inline int comp_params(struct comp_dev *dev,
80 struct sof_ipc_stream_params *params)
81 {
82 int ret = 0;
83
84 if (dev->is_shared && !cpu_is_me(dev->ipc_config.core)) {
85 ret = comp_params_remote(dev, params);
86 } else {
87 if (dev->drv->ops.params) {
88 ret = dev->drv->ops.params(dev, params);
89 } else {
90 /* not defined, run the default handler */
91 ret = comp_verify_params(dev, 0, params);
92
93 /* BugLink: https://github.com/zephyrproject-rtos/zephyr/issues/43786
94 * TODO: Remove this once the bug gets fixed.
95 */
96 #ifndef __ZEPHYR__
97 if (ret < 0)
98 comp_err(dev, "pcm params verification failed");
99 #endif
100 }
101 }
102
103 return ret;
104 }
105
106 /** See comp_ops::dai_get_hw_params */
comp_dai_get_hw_params(struct comp_dev * dev,struct sof_ipc_stream_params * params,int dir)107 static inline int comp_dai_get_hw_params(struct comp_dev *dev,
108 struct sof_ipc_stream_params *params,
109 int dir)
110 {
111 if (dev->drv->ops.dai_get_hw_params)
112 return dev->drv->ops.dai_get_hw_params(dev, params, dir);
113
114 return -EINVAL;
115 }
116
117 /** See comp_ops::cmd */
comp_cmd(struct comp_dev * dev,int cmd,void * data,int max_data_size)118 static inline int comp_cmd(struct comp_dev *dev, int cmd, void *data,
119 int max_data_size)
120 {
121 LOG_MODULE_DECLARE(component, CONFIG_SOF_LOG_LEVEL);
122
123 struct sof_ipc_ctrl_data *cdata = ASSUME_ALIGNED(data, 4);
124
125 if (cmd == COMP_CMD_SET_DATA &&
126 (cdata->data->magic != SOF_ABI_MAGIC ||
127 SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi))) {
128 comp_err(dev, "comp_cmd(): invalid version, data->magic = %u, data->abi = %u",
129 cdata->data->magic, cdata->data->abi);
130 return -EINVAL;
131 }
132
133 if (dev->drv->ops.cmd)
134 return dev->drv->ops.cmd(dev, cmd, data, max_data_size);
135
136 return -EINVAL;
137 }
138
139 /**
140 * Runs comp_ops::trigger on the core the target component is assigned to.
141 */
comp_trigger_remote(struct comp_dev * dev,int cmd)142 static inline int comp_trigger_remote(struct comp_dev *dev, int cmd)
143 {
144 struct idc_msg msg = { IDC_MSG_TRIGGER,
145 IDC_MSG_TRIGGER_EXT(dev->ipc_config.id), dev->ipc_config.core, sizeof(cmd),
146 &cmd, };
147
148 return idc_send_msg(&msg, IDC_BLOCKING);
149 }
150
comp_trigger_local(struct comp_dev * dev,int cmd)151 static inline int comp_trigger_local(struct comp_dev *dev, int cmd)
152 {
153 int ret;
154
155 ret = dev->drv->ops.trigger(dev, cmd);
156
157 /* start a thread in case of shared component or DP scheduling */
158 if (dev->task) {
159 /* schedule or cancel task */
160 switch (cmd) {
161 case COMP_TRIGGER_START:
162 case COMP_TRIGGER_RELEASE:
163 schedule_task(dev->task, 0, dev->period);
164 break;
165 case COMP_TRIGGER_XRUN:
166 case COMP_TRIGGER_PAUSE:
167 case COMP_TRIGGER_STOP:
168 schedule_task_cancel(dev->task);
169 break;
170 }
171 }
172
173 return ret;
174 }
175
176 /** See comp_ops::trigger */
comp_trigger(struct comp_dev * dev,int cmd)177 static inline int comp_trigger(struct comp_dev *dev, int cmd)
178 {
179 int ret;
180 assert(dev->drv->ops.trigger);
181
182 if (dev->is_shared && !cpu_is_me(dev->ipc_config.core))
183 ret = comp_trigger_remote(dev, cmd);
184 else
185 ret = comp_trigger_local(dev, cmd);
186
187 return ret;
188 }
189
190 /** Runs comp_ops::prepare on the target component's core */
comp_prepare_remote(struct comp_dev * dev)191 static inline int comp_prepare_remote(struct comp_dev *dev)
192 {
193 struct idc_msg msg = { IDC_MSG_PREPARE,
194 IDC_MSG_PREPARE_EXT(dev->ipc_config.id), dev->ipc_config.core, };
195
196 return idc_send_msg(&msg, IDC_BLOCKING);
197 }
198
199 /** See comp_ops::prepare */
comp_prepare(struct comp_dev * dev)200 static inline int comp_prepare(struct comp_dev *dev)
201 {
202 if (dev->drv->ops.prepare)
203 return (dev->is_shared && !cpu_is_me(dev->ipc_config.core)) ?
204 comp_prepare_remote(dev) : dev->drv->ops.prepare(dev);
205
206 return 0;
207 }
208
209 int comp_copy(struct comp_dev *dev);
210
211
212 /** See comp_ops::get_attribute */
comp_get_attribute(struct comp_dev * dev,uint32_t type,void * value)213 static inline int comp_get_attribute(struct comp_dev *dev, uint32_t type,
214 void *value)
215 {
216 if (dev->drv->ops.get_attribute)
217 return dev->drv->ops.get_attribute(dev, type, value);
218
219 return 0;
220 }
221
222 /** See comp_ops::set_attribute */
comp_set_attribute(struct comp_dev * dev,uint32_t type,void * value)223 static inline int comp_set_attribute(struct comp_dev *dev, uint32_t type,
224 void *value)
225 {
226 if (dev->drv->ops.set_attribute)
227 return dev->drv->ops.set_attribute(dev, type, value);
228
229 return 0;
230 }
231
232 /** Runs comp_ops::reset on the target component's core */
comp_reset_remote(struct comp_dev * dev)233 static inline int comp_reset_remote(struct comp_dev *dev)
234 {
235 struct idc_msg msg = { IDC_MSG_RESET,
236 IDC_MSG_RESET_EXT(dev->ipc_config.id), dev->ipc_config.core, };
237
238 return idc_send_msg(&msg, IDC_BLOCKING);
239 }
240
241 /**
242 * Component reset and free runtime resources.
243 * @param dev Component device.
244 * @return 0 if succeeded, error code otherwise.
245 */
comp_reset(struct comp_dev * dev)246 static inline int comp_reset(struct comp_dev *dev)
247 {
248 if (dev->drv->ops.reset)
249 return (dev->is_shared && !cpu_is_me(dev->ipc_config.core)) ?
250 comp_reset_remote(dev) : dev->drv->ops.reset(dev);
251
252 return 0;
253 }
254
255 /** See comp_ops::dai_config */
comp_dai_config(struct comp_dev * dev,struct ipc_config_dai * config,const void * spec_config)256 static inline int comp_dai_config(struct comp_dev *dev, struct ipc_config_dai *config,
257 const void *spec_config)
258 {
259 if (dev->drv->ops.dai_config)
260 return dev->drv->ops.dai_config(dev, config, spec_config);
261
262 return 0;
263 }
264
265 /** See comp_ops::position */
comp_position(struct comp_dev * dev,struct sof_ipc_stream_posn * posn)266 static inline int comp_position(struct comp_dev *dev,
267 struct sof_ipc_stream_posn *posn)
268 {
269 if (dev->drv->ops.position)
270 return dev->drv->ops.position(dev, posn);
271
272 return 0;
273 }
274
275 /**
276 * Allocates and initializes audio component list.
277 * To be called once at boot time.
278 */
279 void sys_comp_init(struct sof *sof);
280
281 /**
282 * Checks if two component devices belong to the same parent pipeline.
283 * @param current Component device.
284 * @param previous Another component device.
285 * @return 1 if children of the same pipeline, 0 otherwise.
286 */
comp_is_single_pipeline(struct comp_dev * current,struct comp_dev * previous)287 static inline int comp_is_single_pipeline(struct comp_dev *current,
288 struct comp_dev *previous)
289 {
290 return dev_comp_pipe_id(current) == dev_comp_pipe_id(previous);
291 }
292
293 /**
294 * Checks if component device is active.
295 * @param current Component device.
296 * @return 1 if active, 0 otherwise.
297 */
comp_is_active(struct comp_dev * current)298 static inline int comp_is_active(struct comp_dev *current)
299 {
300 return current->state == COMP_STATE_ACTIVE;
301 }
302
303 /**
304 * Returns component state based on requested command.
305 * @param cmd Request command.
306 * @return Component state.
307 */
comp_get_requested_state(int cmd)308 static inline int comp_get_requested_state(int cmd)
309 {
310 int state = COMP_STATE_INIT;
311
312 switch (cmd) {
313 case COMP_TRIGGER_START:
314 case COMP_TRIGGER_RELEASE:
315 state = COMP_STATE_ACTIVE;
316 break;
317 case COMP_TRIGGER_PREPARE:
318 case COMP_TRIGGER_STOP:
319 state = COMP_STATE_PREPARE;
320 break;
321 case COMP_TRIGGER_PAUSE:
322 state = COMP_STATE_PAUSED;
323 break;
324 case COMP_TRIGGER_XRUN:
325 case COMP_TRIGGER_RESET:
326 state = COMP_STATE_READY;
327 break;
328 case COMP_TRIGGER_PRE_START:
329 case COMP_TRIGGER_PRE_RELEASE:
330 state = COMP_STATE_PRE_ACTIVE;
331 break;
332 }
333
334 return state;
335 }
336
337 /**
338 * \brief Returns endpoint type of given component.
339 * @param dev Component device
340 * @return Endpoint type, one of comp_endpoint_type.
341 */
comp_get_endpoint_type(struct comp_dev * dev)342 static inline int comp_get_endpoint_type(struct comp_dev *dev)
343 {
344 switch (dev_comp_type(dev)) {
345 case SOF_COMP_HOST:
346 return COMP_ENDPOINT_HOST;
347 case SOF_COMP_DAI:
348 return COMP_ENDPOINT_DAI;
349 default:
350 return COMP_ENDPOINT_NODE;
351 }
352 }
353
354 #if CONFIG_IPC_MAJOR_4
355 #include <ipc4/copier.h>
comp_get_dai(struct comp_dev * parent,int index)356 static inline struct comp_dev *comp_get_dai(struct comp_dev *parent, int index)
357 {
358 struct copier_data *cd = comp_get_drvdata(parent);
359
360 if (index >= ARRAY_SIZE(cd->endpoint))
361 return NULL;
362
363 return cd->endpoint[index];
364 }
365 #elif CONFIG_IPC_MAJOR_3
comp_get_dai(struct comp_dev * parent,int index)366 static inline struct comp_dev *comp_get_dai(struct comp_dev *parent, int index)
367 {
368 return parent;
369 }
370 #else
371 #error Unknown IPC major version
372 #endif
373
374 /**
375 * Called to check whether component schedules its pipeline.
376 * @param dev Component device.
377 * @return True if this is scheduling component, false otherwise.
378 */
comp_is_scheduling_source(struct comp_dev * dev)379 static inline bool comp_is_scheduling_source(struct comp_dev *dev)
380 {
381 return dev == dev->pipeline->sched_comp;
382 }
383
384 /**
385 * Called to mark component as shared between cores
386 * @param dev Component device.
387 */
comp_make_shared(struct comp_dev * dev)388 static inline void comp_make_shared(struct comp_dev *dev)
389 {
390 dev->is_shared = true;
391 }
392
comp_drivers_get(void)393 static inline struct comp_driver_list *comp_drivers_get(void)
394 {
395 return sof_get()->comp_drivers;
396 }
397
comp_bind(struct comp_dev * dev,void * data)398 static inline int comp_bind(struct comp_dev *dev, void *data)
399 {
400 int ret = 0;
401
402 if (dev->drv->ops.bind)
403 ret = dev->drv->ops.bind(dev, data);
404
405 return ret;
406 }
407
comp_unbind(struct comp_dev * dev,void * data)408 static inline int comp_unbind(struct comp_dev *dev, void *data)
409 {
410 int ret = 0;
411
412 if (dev->drv->ops.unbind)
413 ret = dev->drv->ops.unbind(dev, data);
414
415 return ret;
416 }
417
comp_get_total_data_processed(struct comp_dev * dev,uint32_t stream_no,bool input)418 static inline uint64_t comp_get_total_data_processed(struct comp_dev *dev, uint32_t stream_no,
419 bool input)
420 {
421 uint64_t ret = 0;
422
423 if (dev->drv->ops.get_total_data_processed)
424 ret = dev->drv->ops.get_total_data_processed(dev, stream_no, input);
425
426 return ret;
427 }
428
429 /** @}*/
430
431 #endif /* __SOF_AUDIO_COMPONENT_INT_H__ */
432