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 <sof/debug/panic.h>
10 #include <sof/drivers/interrupt.h>
11 #include <sof/ipc/msg.h>
12 #include <sof/lib/alloc.h>
13 #include <sof/lib/cache.h>
14 #include <sof/lib/memory.h>
15 #include <sof/list.h>
16 #include <sof/sof.h>
17 #include <sof/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 static SHARED_DATA struct comp_driver_list cd;
25 
26 /* 7c42ce8b-0108-43d0-9137-56d660478c5f */
27 DECLARE_SOF_UUID("component", comp_uuid, 0x7c42ce8b, 0x0108, 0x43d0,
28 		 0x91, 0x37, 0x56, 0xd6, 0x60, 0x47, 0x8c, 0x5f);
29 
30 DECLARE_TR_CTX(comp_tr, SOF_UUID(comp_uuid), LOG_LEVEL_INFO);
31 
comp_register(struct comp_driver_info * drv)32 int comp_register(struct comp_driver_info *drv)
33 {
34 	struct comp_driver_list *drivers = comp_drivers_get();
35 
36 	spin_lock(&drivers->lock);
37 	list_item_prepend(&drv->list, &drivers->list);
38 	spin_unlock(&drivers->lock);
39 
40 	return 0;
41 }
42 
comp_unregister(struct comp_driver_info * drv)43 void comp_unregister(struct comp_driver_info *drv)
44 {
45 	struct comp_driver_list *drivers = comp_drivers_get();
46 
47 	spin_lock(&drivers->lock);
48 	list_item_del(&drv->list);
49 	spin_unlock(&drivers->lock);
50 }
51 
52 /* NOTE: Keep the component state diagram up to date:
53  * sof-docs/developer_guides/firmware/components/images/comp-dev-states.pu
54  */
55 
comp_set_state(struct comp_dev * dev,int cmd)56 int comp_set_state(struct comp_dev *dev, int cmd)
57 {
58 	int requested_state = comp_get_requested_state(cmd);
59 	int ret = 0;
60 
61 	if (dev->state == requested_state) {
62 		comp_info(dev, "comp_set_state(), state already set to %u",
63 			  dev->state);
64 		return COMP_STATUS_STATE_ALREADY_SET;
65 	}
66 
67 	switch (cmd) {
68 	case COMP_TRIGGER_START:
69 		if (dev->state == COMP_STATE_PREPARE) {
70 			dev->state = COMP_STATE_ACTIVE;
71 		} else {
72 			comp_err(dev, "comp_set_state(): wrong state = %u, COMP_TRIGGER_START",
73 				 dev->state);
74 			ret = -EINVAL;
75 		}
76 		break;
77 	case COMP_TRIGGER_RELEASE:
78 		if (dev->state == COMP_STATE_PAUSED) {
79 			dev->state = COMP_STATE_ACTIVE;
80 		} else {
81 			comp_err(dev, "comp_set_state(): wrong state = %u, COMP_TRIGGER_RELEASE",
82 				 dev->state);
83 			ret = -EINVAL;
84 		}
85 		break;
86 	case COMP_TRIGGER_STOP:
87 		if (dev->state == COMP_STATE_ACTIVE ||
88 		    dev->state == COMP_STATE_PAUSED) {
89 			dev->state = COMP_STATE_PREPARE;
90 		} else {
91 			comp_err(dev, "comp_set_state(): wrong state = %u, COMP_TRIGGER_STOP",
92 				 dev->state);
93 			ret = -EINVAL;
94 		}
95 		break;
96 	case COMP_TRIGGER_PAUSE:
97 		/* only support pausing for running */
98 		if (dev->state == COMP_STATE_ACTIVE) {
99 			dev->state = COMP_STATE_PAUSED;
100 		} else {
101 			comp_err(dev, "comp_set_state(): wrong state = %u, COMP_TRIGGER_PAUSE",
102 				 dev->state);
103 			ret = -EINVAL;
104 		}
105 		break;
106 	case COMP_TRIGGER_RESET:
107 		/* reset always succeeds */
108 		if (dev->state == COMP_STATE_ACTIVE ||
109 		    dev->state == COMP_STATE_PAUSED) {
110 			comp_err(dev, "comp_set_state(): wrong state = %u, COMP_TRIGGER_RESET",
111 				 dev->state);
112 			ret = 0;
113 		}
114 		dev->state = COMP_STATE_READY;
115 		break;
116 	case COMP_TRIGGER_PREPARE:
117 		if (dev->state == COMP_STATE_READY) {
118 			dev->state = COMP_STATE_PREPARE;
119 		} else {
120 			comp_err(dev, "comp_set_state(): wrong state = %u, COMP_TRIGGER_PREPARE",
121 				 dev->state);
122 			ret = -EINVAL;
123 		}
124 		break;
125 	default:
126 		break;
127 	}
128 
129 	comp_writeback(dev);
130 
131 	return ret;
132 }
133 
sys_comp_init(struct sof * sof)134 void sys_comp_init(struct sof *sof)
135 {
136 	sof->comp_drivers = platform_shared_get(&cd, sizeof(cd));
137 
138 	list_init(&sof->comp_drivers->list);
139 	spinlock_init(&sof->comp_drivers->lock);
140 }
141 
comp_get_copy_limits(struct comp_buffer * source,struct comp_buffer * sink,struct comp_copy_limits * cl)142 void comp_get_copy_limits(struct comp_buffer *source, struct comp_buffer *sink,
143 			  struct comp_copy_limits *cl)
144 {
145 	cl->frames = audio_stream_avail_frames(&source->stream, &sink->stream);
146 	cl->source_frame_bytes = audio_stream_frame_bytes(&source->stream);
147 	cl->sink_frame_bytes = audio_stream_frame_bytes(&sink->stream);
148 	cl->source_bytes = cl->frames * cl->source_frame_bytes;
149 	cl->sink_bytes = cl->frames * cl->sink_frame_bytes;
150 }
151 
152 /** \brief Struct handler for large component configs */
153 struct comp_data_blob_handler {
154 	struct comp_dev *dev;	/**< audio component device */
155 	uint32_t data_size;	/**< size of component's data blob */
156 	void *data;		/**< pointer to data blob */
157 	void *data_new;		/**< pointer to new data blob */
158 	bool data_ready;	/**< set when data blob is fully received */
159 	uint32_t data_pos;	/**< indicates a data position in data
160 				  *  sending/receiving process
161 				  */
162 };
163 
comp_free_data_blob(struct comp_data_blob_handler * blob_handler)164 static void comp_free_data_blob(struct comp_data_blob_handler *blob_handler)
165 {
166 	assert(blob_handler);
167 
168 	if (!blob_handler->data)
169 		return;
170 
171 	rfree(blob_handler->data);
172 	rfree(blob_handler->data_new);
173 	blob_handler->data = NULL;
174 	blob_handler->data_new = NULL;
175 	blob_handler->data_size = 0;
176 }
177 
comp_get_data_blob(struct comp_data_blob_handler * blob_handler,size_t * size,uint32_t * crc)178 void *comp_get_data_blob(struct comp_data_blob_handler *blob_handler,
179 			 size_t *size, uint32_t *crc)
180 {
181 	assert(blob_handler);
182 
183 	comp_dbg(blob_handler->dev, "comp_get_data_blob()");
184 
185 	if (size)
186 		*size = 0;
187 
188 	/* Function returns new data blob if available */
189 	if (comp_is_new_data_blob_available(blob_handler)) {
190 		comp_dbg(blob_handler->dev, "comp_get_data_blob(): new data available");
191 
192 		/* Free "old" data blob and set data to data_new pointer */
193 		rfree(blob_handler->data);
194 		blob_handler->data = blob_handler->data_new;
195 		blob_handler->data_new = NULL;
196 		blob_handler->data_ready = false;
197 	}
198 
199 	/* If data is available we calculate crc32 when crc pointer is given */
200 	if (blob_handler->data) {
201 		if (crc)
202 			*crc = crc32(0, blob_handler->data,
203 				     blob_handler->data_size);
204 	} else {
205 		/* If blob_handler->data is equal to NULL and there is no new
206 		 * data blob it means that component hasn't got any config yet.
207 		 * Function returns NULL in that case.
208 		 */
209 		comp_warn(blob_handler->dev, "comp_get_data_blob(): blob_handler->data is not set.");
210 	}
211 
212 	if (size)
213 		*size = blob_handler->data_size;
214 
215 	return blob_handler->data;
216 }
217 
comp_is_new_data_blob_available(struct comp_data_blob_handler * blob_handler)218 bool comp_is_new_data_blob_available(struct comp_data_blob_handler
219 					*blob_handler)
220 {
221 	assert(blob_handler);
222 
223 	comp_dbg(blob_handler->dev, "comp_is_new_data_blob_available()");
224 
225 	/* New data blob is available when new data blob is allocated (data_new
226 	 * is not NULL) nd component received all required chunks of data
227 	 * (data_ready is set to TRUE)
228 	 */
229 	if (blob_handler->data_new && blob_handler->data_ready)
230 		return true;
231 
232 	return false;
233 }
234 
comp_init_data_blob(struct comp_data_blob_handler * blob_handler,uint32_t size,void * init_data)235 int comp_init_data_blob(struct comp_data_blob_handler *blob_handler,
236 			uint32_t size, void *init_data)
237 {
238 	int ret;
239 
240 	assert(blob_handler);
241 
242 	comp_free_data_blob(blob_handler);
243 
244 	if (!size)
245 		return 0;
246 
247 	/* Data blob allocation */
248 	blob_handler->data = rballoc(0, SOF_MEM_CAPS_RAM, size);
249 	if (!blob_handler->data) {
250 		comp_err(blob_handler->dev, "comp_init_data_blob(): model->data rballoc failed");
251 		return -ENOMEM;
252 	}
253 
254 	/* If init_data is given, data will be initialized with it. In other
255 	 * case, data will be set to zero.
256 	 */
257 	if (init_data) {
258 		ret = memcpy_s(blob_handler->data, size, init_data, size);
259 		assert(!ret);
260 	} else {
261 		bzero(blob_handler->data, size);
262 	}
263 
264 	blob_handler->data_new = NULL;
265 	blob_handler->data_size = size;
266 	blob_handler->data_ready = true;
267 
268 	return 0;
269 }
270 
comp_data_blob_set_cmd(struct comp_data_blob_handler * blob_handler,struct sof_ipc_ctrl_data * cdata)271 int comp_data_blob_set_cmd(struct comp_data_blob_handler *blob_handler,
272 			   struct sof_ipc_ctrl_data *cdata)
273 {
274 	int ret = 0;
275 
276 	assert(blob_handler);
277 
278 	comp_dbg(blob_handler->dev, "comp_data_blob_set_cmd() msg_index = %d, num_elems = %d, remaining = %d ",
279 		 cdata->msg_index, cdata->num_elems,
280 		 cdata->elems_remaining);
281 
282 	/* Check that there is no work-in-progress previous request */
283 	if (blob_handler->data_new && cdata->msg_index == 0) {
284 		comp_err(blob_handler->dev, "comp_data_blob_set_cmd(), busy with previous request");
285 		return -EBUSY;
286 	}
287 
288 	/* in case when the current package is the first, we should allocate
289 	 * memory for whole model data
290 	 */
291 	if (!cdata->msg_index) {
292 		/* in case when required model size is equal to zero we do not
293 		 * allocate memory and should just return 0.
294 		 *
295 		 * Set cmd with cdata->data->size equal to 0 is possible in
296 		 * following situation:
297 		 * 1. At first boot and topology parsing stage, the driver will
298 		 * read all initial values of DSP kcontrols via IPC. Driver send
299 		 * get_model() cmd to components. If we do not initialize
300 		 * component earlier driver will get "model" with size 0.
301 		 * 2. When resuming from runtime suspended, the driver will
302 		 * restore all pipelines and kcontrols, for the tlv binary
303 		 * kcontrols, it will call the set_model() with the cached value
304 		 * and size (0 if it is not updated by any actual end user
305 		 * sof-ctl settings) - basically driver will send set_model()
306 		 * command with size equal to 0.
307 		 */
308 		if (!cdata->data->size)
309 			return 0;
310 
311 		blob_handler->data_new = rballoc(0, SOF_MEM_CAPS_RAM,
312 						 cdata->data->size);
313 		if (!blob_handler->data_new) {
314 			comp_err(blob_handler->dev, "comp_data_blob_set_cmd(): blob_handler->data_new allocation failed.");
315 			return -ENOMEM;
316 		}
317 
318 		blob_handler->data_size = cdata->data->size;
319 		blob_handler->data_ready = false;
320 		blob_handler->data_pos = 0;
321 	}
322 
323 	/* return an error in case when we do not have allocated memory for
324 	 * model data
325 	 */
326 	if (!blob_handler->data_new) {
327 		comp_err(blob_handler->dev, "comp_data_blob_set_cmd(): buffer not allocated");
328 		return -ENOMEM;
329 	}
330 
331 	ret = memcpy_s((char *)blob_handler->data_new + blob_handler->data_pos,
332 		       blob_handler->data_size - blob_handler->data_pos,
333 		       cdata->data->data, cdata->num_elems);
334 	assert(!ret);
335 
336 	blob_handler->data_pos += cdata->num_elems;
337 
338 	if (!cdata->elems_remaining) {
339 		comp_dbg(blob_handler->dev, "comp_data_blob_set_cmd(): final package received");
340 
341 		/* The new configuration is OK to be applied */
342 		blob_handler->data_ready = true;
343 
344 		/* If component state is READY we can omit old
345 		 * configuration immediately. When in playback/capture
346 		 * the new configuration presence is checked in copy().
347 		 */
348 		if (blob_handler->dev->state ==  COMP_STATE_READY) {
349 			rfree(blob_handler->data);
350 			blob_handler->data = NULL;
351 		}
352 
353 		/* If there is no existing configuration the received
354 		 * can be set to current immediately. It will be
355 		 * applied in prepare() when streaming starts.
356 		 */
357 		if (!blob_handler->data) {
358 			blob_handler->data = blob_handler->data_new;
359 			blob_handler->data_new = NULL;
360 		}
361 	}
362 
363 	return 0;
364 }
365 
comp_data_blob_get_cmd(struct comp_data_blob_handler * blob_handler,struct sof_ipc_ctrl_data * cdata,int size)366 int comp_data_blob_get_cmd(struct comp_data_blob_handler *blob_handler,
367 			   struct sof_ipc_ctrl_data *cdata, int size)
368 {
369 	int ret = 0;
370 
371 	assert(blob_handler);
372 
373 	comp_dbg(blob_handler->dev, "comp_data_blob_get_cmd() msg_index = %d, num_elems = %d, remaining = %d ",
374 		 cdata->msg_index, cdata->num_elems,
375 		 cdata->elems_remaining);
376 
377 	/* Copy back to user space */
378 	if (blob_handler->data) {
379 		/* reset data_pos variable in case of copying first element */
380 		if (!cdata->msg_index) {
381 			blob_handler->data_pos = 0;
382 			comp_dbg(blob_handler->dev, "comp_data_blob_get_cmd() model data_size = 0x%x",
383 				 blob_handler->data_size);
384 		}
385 
386 		/* return an error in case of mismatch between num_elems and
387 		 * required size
388 		 */
389 		if (cdata->num_elems > size) {
390 			comp_err(blob_handler->dev, "comp_data_blob_get_cmd(): invalid cdata->num_elems %d",
391 				 cdata->num_elems);
392 			return -EINVAL;
393 		}
394 
395 		/* copy required size of data */
396 		ret = memcpy_s(cdata->data->data, size,
397 			       (char *)blob_handler->data + blob_handler->data_pos,
398 			       cdata->num_elems);
399 		assert(!ret);
400 
401 		cdata->data->abi = SOF_ABI_VERSION;
402 		cdata->data->size = blob_handler->data_size;
403 		blob_handler->data_pos += cdata->num_elems;
404 	} else {
405 		comp_warn(blob_handler->dev, "comp_data_blob_get_cmd(): model->data not allocated yet.");
406 		cdata->data->abi = SOF_ABI_VERSION;
407 		cdata->data->size = 0;
408 	}
409 
410 	return ret;
411 }
412 
comp_data_blob_handler_new(struct comp_dev * dev)413 struct comp_data_blob_handler *comp_data_blob_handler_new(struct comp_dev *dev)
414 {
415 	struct comp_data_blob_handler *handler;
416 
417 	comp_dbg(dev, "comp_data_blob_handler_new()");
418 
419 	handler = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM,
420 			  sizeof(struct comp_data_blob_handler));
421 
422 	if (handler)
423 		handler->dev = dev;
424 
425 	return handler;
426 }
427 
comp_data_blob_handler_free(struct comp_data_blob_handler * blob_handler)428 void comp_data_blob_handler_free(struct comp_data_blob_handler *blob_handler)
429 {
430 	if (!blob_handler)
431 		return;
432 
433 	comp_free_data_blob(blob_handler);
434 
435 	rfree(blob_handler);
436 }
437 
comp_make_shared(struct comp_dev * dev)438 struct comp_dev *comp_make_shared(struct comp_dev *dev)
439 {
440 	struct list_item *old_bsource_list = &dev->bsource_list;
441 	struct list_item *old_bsink_list = &dev->bsink_list;
442 
443 	/* flush cache to share */
444 	dcache_writeback_region(dev, dev->size);
445 
446 	dev = platform_shared_get(dev, dev->size);
447 
448 	/* re-link lists with the new heads addresses, init would cut
449 	 * links to existing items, local already connected buffers
450 	 */
451 	list_relink(&dev->bsource_list, old_bsource_list);
452 	list_relink(&dev->bsink_list, old_bsink_list);
453 	dev->is_shared = true;
454 
455 	return dev;
456 }
457