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 <sof/drivers/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 spinlock_t 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 struct comp_dev *comp_new(struct sof_ipc_comp *comp);
43
44 /** See comp_ops::free */
comp_free(struct comp_dev * dev)45 static inline void comp_free(struct comp_dev *dev)
46 {
47 assert(dev->drv->ops.free);
48
49 /* free task if shared component */
50 if (dev->is_shared && dev->task) {
51 schedule_task_free(dev->task);
52 rfree(dev->task);
53 }
54
55 dev->drv->ops.free(dev);
56 }
57
58 /**
59 * Commits component's memory if it's shared.
60 * @param dev Component device.
61 */
comp_shared_commit(struct comp_dev * dev)62 static inline void comp_shared_commit(struct comp_dev *dev)
63 {
64 }
65
66 /**
67 * Parameter init for component on other core.
68 * @param dev Component device.
69 * @param params Parameters to be set.
70 * @return 0 if succeeded, error code otherwise.
71 */
comp_params_remote(struct comp_dev * dev,struct sof_ipc_stream_params * params)72 static inline int comp_params_remote(struct comp_dev *dev,
73 struct sof_ipc_stream_params *params)
74 {
75 struct idc_msg msg = { IDC_MSG_PARAMS, IDC_MSG_PARAMS_EXT(dev->ipc_config.id),
76 dev->ipc_config.core, sizeof(*params), params, };
77
78 return idc_send_msg(&msg, IDC_BLOCKING);
79 }
80
81 /** See comp_ops::params */
comp_params(struct comp_dev * dev,struct sof_ipc_stream_params * params)82 static inline int comp_params(struct comp_dev *dev,
83 struct sof_ipc_stream_params *params)
84 {
85 int ret = 0;
86
87 if (dev->is_shared && !cpu_is_me(dev->ipc_config.core)) {
88 ret = comp_params_remote(dev, params);
89 } else {
90 if (dev->drv->ops.params) {
91 ret = dev->drv->ops.params(dev, params);
92 } else {
93 /* not defined, run the default handler */
94 ret = comp_verify_params(dev, 0, params);
95 if (ret < 0)
96 comp_err(dev, "pcm params verification failed");
97 }
98 }
99
100 comp_shared_commit(dev);
101
102 return ret;
103 }
104
105 /** See comp_ops::dai_get_hw_params */
comp_dai_get_hw_params(struct comp_dev * dev,struct sof_ipc_stream_params * params,int dir)106 static inline int comp_dai_get_hw_params(struct comp_dev *dev,
107 struct sof_ipc_stream_params *params,
108 int dir)
109 {
110 int ret = -EINVAL;
111
112 if (dev->drv->ops.dai_get_hw_params)
113 ret = dev->drv->ops.dai_get_hw_params(dev, params, dir);
114
115 comp_shared_commit(dev);
116
117 return ret;
118 }
119
120 /** See comp_ops::cmd */
comp_cmd(struct comp_dev * dev,int cmd,void * data,int max_data_size)121 static inline int comp_cmd(struct comp_dev *dev, int cmd, void *data,
122 int max_data_size)
123 {
124 struct sof_ipc_ctrl_data *cdata = ASSUME_ALIGNED(data, 4);
125 int ret = -EINVAL;
126
127 if (cmd == COMP_CMD_SET_DATA &&
128 (cdata->data->magic != SOF_ABI_MAGIC ||
129 SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi))) {
130 comp_err(dev, "comp_cmd(): invalid version, data->magic = %u, data->abi = %u",
131 cdata->data->magic, cdata->data->abi);
132 goto out;
133 }
134
135 if (dev->drv->ops.cmd)
136 ret = dev->drv->ops.cmd(dev, cmd, data, max_data_size);
137
138 out:
139 comp_shared_commit(dev);
140
141 return ret;
142 }
143
144 /**
145 * Runs comp_ops::trigger on the core the target component is assigned to.
146 */
comp_trigger_remote(struct comp_dev * dev,int cmd)147 static inline int comp_trigger_remote(struct comp_dev *dev, int cmd)
148 {
149 struct idc_msg msg = { IDC_MSG_TRIGGER,
150 IDC_MSG_TRIGGER_EXT(dev->ipc_config.id), dev->ipc_config.core, sizeof(cmd),
151 &cmd, };
152
153 return idc_send_msg(&msg, IDC_BLOCKING);
154 }
155
156 /** See comp_ops::trigger */
comp_trigger(struct comp_dev * dev,int cmd)157 static inline int comp_trigger(struct comp_dev *dev, int cmd)
158 {
159 int ret = 0;
160
161 assert(dev->drv->ops.trigger);
162
163 ret = (dev->is_shared && !cpu_is_me(dev->ipc_config.core)) ?
164 comp_trigger_remote(dev, cmd) : dev->drv->ops.trigger(dev, cmd);
165
166 comp_shared_commit(dev);
167
168 return ret;
169 }
170
171 /** Runs comp_ops::prepare on the target component's core */
comp_prepare_remote(struct comp_dev * dev)172 static inline int comp_prepare_remote(struct comp_dev *dev)
173 {
174 struct idc_msg msg = { IDC_MSG_PREPARE,
175 IDC_MSG_PREPARE_EXT(dev->ipc_config.id), dev->ipc_config.core, };
176
177 return idc_send_msg(&msg, IDC_BLOCKING);
178 }
179
180 /** See comp_ops::prepare */
comp_prepare(struct comp_dev * dev)181 static inline int comp_prepare(struct comp_dev *dev)
182 {
183 int ret = 0;
184
185 if (dev->drv->ops.prepare)
186 ret = (dev->is_shared && !cpu_is_me(dev->ipc_config.core)) ?
187 comp_prepare_remote(dev) : dev->drv->ops.prepare(dev);
188
189 comp_shared_commit(dev);
190
191 return ret;
192 }
193
194 /** See comp_ops::copy */
comp_copy(struct comp_dev * dev)195 static inline int comp_copy(struct comp_dev *dev)
196 {
197 int ret = 0;
198
199 assert(dev->drv->ops.copy);
200
201 /* copy only if we are the owner of the component */
202 if (cpu_is_me(dev->ipc_config.core)) {
203 perf_cnt_init(&dev->pcd);
204 ret = dev->drv->ops.copy(dev);
205 perf_cnt_stamp(&dev->pcd, comp_perf_info, dev);
206 }
207 comp_shared_commit(dev);
208
209 return ret;
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 int ret = 0;
217
218 if (dev->drv->ops.get_attribute)
219 ret = dev->drv->ops.get_attribute(dev, type, value);
220
221 comp_shared_commit(dev);
222
223 return ret;
224 }
225
226 /** See comp_ops::set_attribute */
comp_set_attribute(struct comp_dev * dev,uint32_t type,void * value)227 static inline int comp_set_attribute(struct comp_dev *dev, uint32_t type,
228 void *value)
229 {
230 int ret = 0;
231
232 if (dev->drv->ops.set_attribute)
233 ret = dev->drv->ops.set_attribute(dev, type, value);
234
235 comp_shared_commit(dev);
236
237 return ret;
238 }
239
240 /** Runs comp_ops::reset on the target component's core */
comp_reset_remote(struct comp_dev * dev)241 static inline int comp_reset_remote(struct comp_dev *dev)
242 {
243 struct idc_msg msg = { IDC_MSG_RESET,
244 IDC_MSG_RESET_EXT(dev->ipc_config.id), dev->ipc_config.core, };
245
246 return idc_send_msg(&msg, IDC_BLOCKING);
247 }
248
249 /**
250 * Component reset and free runtime resources.
251 * @param dev Component device.
252 * @return 0 if succeeded, error code otherwise.
253 */
comp_reset(struct comp_dev * dev)254 static inline int comp_reset(struct comp_dev *dev)
255 {
256 int ret = 0;
257
258 if (dev->drv->ops.reset)
259 ret = (dev->is_shared && !cpu_is_me(dev->ipc_config.core)) ?
260 comp_reset_remote(dev) : dev->drv->ops.reset(dev);
261
262 comp_shared_commit(dev);
263
264 return ret;
265 }
266
267 /** See comp_ops::dai_config */
comp_dai_config(struct comp_dev * dev,struct ipc_config_dai * config,void * spec_config)268 static inline int comp_dai_config(struct comp_dev *dev, struct ipc_config_dai *config,
269 void *spec_config)
270 {
271 int ret = 0;
272
273 if (dev->drv->ops.dai_config)
274 ret = dev->drv->ops.dai_config(dev, config, spec_config);
275
276 comp_shared_commit(dev);
277
278 return ret;
279 }
280
281 /** See comp_ops::position */
comp_position(struct comp_dev * dev,struct sof_ipc_stream_posn * posn)282 static inline int comp_position(struct comp_dev *dev,
283 struct sof_ipc_stream_posn *posn)
284 {
285 int ret = 0;
286
287 if (dev->drv->ops.position)
288 ret = dev->drv->ops.position(dev, posn);
289
290 comp_shared_commit(dev);
291
292 return ret;
293 }
294
295 /**
296 * Allocates and initializes audio component list.
297 * To be called once at boot time.
298 */
299 void sys_comp_init(struct sof *sof);
300
301 /**
302 * Checks if two component devices belong to the same parent pipeline.
303 * @param current Component device.
304 * @param previous Another component device.
305 * @return 1 if children of the same pipeline, 0 otherwise.
306 */
comp_is_single_pipeline(struct comp_dev * current,struct comp_dev * previous)307 static inline int comp_is_single_pipeline(struct comp_dev *current,
308 struct comp_dev *previous)
309 {
310 return dev_comp_pipe_id(current) == dev_comp_pipe_id(previous);
311 }
312
313 /**
314 * Checks if component device is active.
315 * @param current Component device.
316 * @return 1 if active, 0 otherwise.
317 */
comp_is_active(struct comp_dev * current)318 static inline int comp_is_active(struct comp_dev *current)
319 {
320 return current->state == COMP_STATE_ACTIVE;
321 }
322
323 /**
324 * Returns component state based on requested command.
325 * @param cmd Request command.
326 * @return Component state.
327 */
comp_get_requested_state(int cmd)328 static inline int comp_get_requested_state(int cmd)
329 {
330 int state = COMP_STATE_INIT;
331
332 switch (cmd) {
333 case COMP_TRIGGER_START:
334 case COMP_TRIGGER_RELEASE:
335 state = COMP_STATE_ACTIVE;
336 break;
337 case COMP_TRIGGER_PREPARE:
338 case COMP_TRIGGER_STOP:
339 state = COMP_STATE_PREPARE;
340 break;
341 case COMP_TRIGGER_PAUSE:
342 state = COMP_STATE_PAUSED;
343 break;
344 case COMP_TRIGGER_XRUN:
345 case COMP_TRIGGER_RESET:
346 state = COMP_STATE_READY;
347 break;
348 default:
349 break;
350 }
351
352 return state;
353 }
354
355 /**
356 * \brief Returns endpoint type of given component.
357 * @param dev Component device
358 * @return Endpoint type, one of comp_endpoint_type.
359 */
comp_get_endpoint_type(struct comp_dev * dev)360 static inline int comp_get_endpoint_type(struct comp_dev *dev)
361 {
362 switch (dev_comp_type(dev)) {
363 case SOF_COMP_HOST:
364 return COMP_ENDPOINT_HOST;
365 case SOF_COMP_DAI:
366 return COMP_ENDPOINT_DAI;
367 default:
368 return COMP_ENDPOINT_NODE;
369 }
370 }
371
372 /**
373 * Called to check whether component schedules its pipeline.
374 * @param dev Component device.
375 * @return True if this is scheduling component, false otherwise.
376 */
comp_is_scheduling_source(struct comp_dev * dev)377 static inline bool comp_is_scheduling_source(struct comp_dev *dev)
378 {
379 return dev == dev->pipeline->sched_comp;
380 }
381
382 /**
383 * Called to reallocate component in shared memory.
384 * @param dev Component device.
385 * @return Pointer to reallocated component device.
386 */
387 struct comp_dev *comp_make_shared(struct comp_dev *dev);
388
comp_drivers_get(void)389 static inline struct comp_driver_list *comp_drivers_get(void)
390 {
391 return sof_get()->comp_drivers;
392 }
393
comp_bind(struct comp_dev * dev,void * data)394 static inline int comp_bind(struct comp_dev *dev, void *data)
395 {
396 int ret = 0;
397
398 if (dev->drv->ops.bind)
399 ret = dev->drv->ops.bind(dev, data);
400
401 comp_shared_commit(dev);
402
403 return ret;
404 }
405
comp_unbind(struct comp_dev * dev,void * data)406 static inline int comp_unbind(struct comp_dev *dev, void *data)
407 {
408 int ret = 0;
409
410 if (dev->drv->ops.unbind)
411 ret = dev->drv->ops.unbind(dev, data);
412
413 comp_shared_commit(dev);
414
415 return ret;
416 }
417
418 /** @}*/
419
420 #endif /* __SOF_AUDIO_COMPONENT_INT_H__ */
421