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