xref: /openbmc/linux/sound/soc/intel/atom/sst/sst_stream.c (revision 04301bf5)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  *  sst_stream.c - Intel SST Driver for audio engine
4  *
5  *  Copyright (C) 2008-14 Intel Corp
6  *  Authors:	Vinod Koul <vinod.koul@intel.com>
7  *		Harsha Priya <priya.harsha@intel.com>
8  *		Dharageswari R <dharageswari.r@intel.com>
9  *		KP Jeeja <jeeja.kp@intel.com>
10  *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11  *
12  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
13  */
14 #include <linux/pci.h>
15 #include <linux/firmware.h>
16 #include <linux/sched.h>
17 #include <linux/delay.h>
18 #include <linux/pm_runtime.h>
19 #include <sound/core.h>
20 #include <sound/pcm.h>
21 #include <sound/soc.h>
22 #include <sound/compress_driver.h>
23 #include <asm/platform_sst_audio.h>
24 #include "../sst-mfld-platform.h"
25 #include "sst.h"
26 #include "../../common/sst-dsp.h"
27 
28 int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params)
29 {
30 	struct snd_pcm_params *pcm_params;
31 	struct snd_sst_params *str_params;
32 	struct snd_sst_tstamp fw_tstamp;
33 	struct stream_info *str_info;
34 	int i, num_ch, str_id;
35 
36 	dev_dbg(sst_drv_ctx->dev, "Enter\n");
37 
38 	str_params = (struct snd_sst_params *)params;
39 	str_id = str_params->stream_id;
40 	str_info = get_stream_info(sst_drv_ctx, str_id);
41 	if (!str_info)
42 		return -EINVAL;
43 
44 	memset(&str_info->alloc_param, 0, sizeof(str_info->alloc_param));
45 	str_info->alloc_param.operation = str_params->ops;
46 	str_info->alloc_param.codec_type = str_params->codec;
47 	str_info->alloc_param.sg_count = str_params->aparams.sg_count;
48 	str_info->alloc_param.ring_buf_info[0].addr =
49 		str_params->aparams.ring_buf_info[0].addr;
50 	str_info->alloc_param.ring_buf_info[0].size =
51 		str_params->aparams.ring_buf_info[0].size;
52 	str_info->alloc_param.frag_size = str_params->aparams.frag_size;
53 
54 	memcpy(&str_info->alloc_param.codec_params, &str_params->sparams,
55 			sizeof(struct snd_sst_stream_params));
56 
57 	/*
58 	 * fill channel map params for multichannel support.
59 	 * Ideally channel map should be received from upper layers
60 	 * for multichannel support.
61 	 * Currently hardcoding as per FW reqm.
62 	 */
63 	num_ch = sst_get_num_channel(str_params);
64 	pcm_params = &str_info->alloc_param.codec_params.uc.pcm_params;
65 	for (i = 0; i < 8; i++) {
66 		if (i < num_ch)
67 			pcm_params->channel_map[i] = i;
68 		else
69 			pcm_params->channel_map[i] = 0xff;
70 	}
71 
72 	sst_drv_ctx->streams[str_id].status = STREAM_INIT;
73 	sst_drv_ctx->streams[str_id].prev = STREAM_UN_INIT;
74 	sst_drv_ctx->streams[str_id].pipe_id = str_params->device_type;
75 	sst_drv_ctx->streams[str_id].task_id = str_params->task;
76 	sst_drv_ctx->streams[str_id].num_ch = num_ch;
77 
78 	if (sst_drv_ctx->info.lpe_viewpt_rqd)
79 		str_info->alloc_param.ts = sst_drv_ctx->info.mailbox_start +
80 			sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp));
81 	else
82 		str_info->alloc_param.ts = sst_drv_ctx->mailbox_add +
83 			sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp));
84 
85 	dev_dbg(sst_drv_ctx->dev, "alloc tstamp location = 0x%x\n",
86 			str_info->alloc_param.ts);
87 	dev_dbg(sst_drv_ctx->dev, "assigned pipe id 0x%x to task %d\n",
88 			str_info->pipe_id, str_info->task_id);
89 
90 	return sst_realloc_stream(sst_drv_ctx, str_id);
91 }
92 
93 /**
94  * sst_realloc_stream - Send msg for (re-)allocating a stream using the
95  * @sst_drv_ctx: intel_sst_drv context pointer
96  * @str_id: stream ID
97  *
98  * Send a msg for (re-)allocating a stream using the parameters previously
99  * passed to sst_alloc_stream_mrfld() for the same stream ID.
100  * Return: 0 or negative errno value.
101  */
102 int sst_realloc_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
103 {
104 	struct snd_sst_alloc_response *response;
105 	struct stream_info *str_info;
106 	void *data = NULL;
107 	int ret;
108 
109 	str_info = get_stream_info(sst_drv_ctx, str_id);
110 	if (!str_info)
111 		return -EINVAL;
112 
113 	dev_dbg(sst_drv_ctx->dev, "Alloc for str %d pipe %#x\n",
114 		str_id, str_info->pipe_id);
115 
116 	ret = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
117 			IPC_IA_ALLOC_STREAM_MRFLD, str_info->pipe_id,
118 			sizeof(str_info->alloc_param), &str_info->alloc_param,
119 			&data, true, true, false, true);
120 
121 	if (ret < 0) {
122 		dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret);
123 		/* alloc failed, so reset the state to uninit */
124 		str_info->status = STREAM_UN_INIT;
125 		str_id = ret;
126 	} else if (data) {
127 		response = (struct snd_sst_alloc_response *)data;
128 		ret = response->str_type.result;
129 		if (!ret)
130 			goto out;
131 		dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret);
132 		if (ret == SST_ERR_STREAM_IN_USE) {
133 			dev_err(sst_drv_ctx->dev,
134 				"FW not in clean state, send free for:%d\n", str_id);
135 			sst_free_stream(sst_drv_ctx, str_id);
136 		}
137 		str_id = -ret;
138 	}
139 out:
140 	kfree(data);
141 	return str_id;
142 }
143 
144 /**
145  * sst_start_stream - Send msg for a starting stream
146  * @sst_drv_ctx: intel_sst_drv context pointer
147  * @str_id: stream ID
148  *
149  * This function is called by any function which wants to start
150  * a stream.
151  */
152 int sst_start_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
153 {
154 	int retval = 0;
155 	struct stream_info *str_info;
156 	u16 data = 0;
157 
158 	dev_dbg(sst_drv_ctx->dev, "sst_start_stream for %d\n", str_id);
159 	str_info = get_stream_info(sst_drv_ctx, str_id);
160 	if (!str_info)
161 		return -EINVAL;
162 	if (str_info->status != STREAM_RUNNING)
163 		return -EBADRQC;
164 
165 	retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id,
166 			IPC_CMD, IPC_IA_START_STREAM_MRFLD, str_info->pipe_id,
167 			sizeof(u16), &data, NULL, true, true, true, false);
168 
169 	return retval;
170 }
171 
172 int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx,
173 		struct snd_sst_bytes_v2 *bytes)
174 {	struct ipc_post *msg = NULL;
175 	u32 length;
176 	int pvt_id, ret = 0;
177 	struct sst_block *block = NULL;
178 
179 	dev_dbg(sst_drv_ctx->dev,
180 		"type:%u ipc_msg:%u block:%u task_id:%u pipe: %#x length:%#x\n",
181 		bytes->type, bytes->ipc_msg, bytes->block, bytes->task_id,
182 		bytes->pipe_id, bytes->len);
183 
184 	if (sst_create_ipc_msg(&msg, true))
185 		return -ENOMEM;
186 
187 	pvt_id = sst_assign_pvt_id(sst_drv_ctx);
188 	sst_fill_header_mrfld(&msg->mrfld_header, bytes->ipc_msg,
189 			bytes->task_id, 1, pvt_id);
190 	msg->mrfld_header.p.header_high.part.res_rqd = bytes->block;
191 	length = bytes->len;
192 	msg->mrfld_header.p.header_low_payload = length;
193 	dev_dbg(sst_drv_ctx->dev, "length is %d\n", length);
194 	memcpy(msg->mailbox_data, &bytes->bytes, bytes->len);
195 	if (bytes->block) {
196 		block = sst_create_block(sst_drv_ctx, bytes->ipc_msg, pvt_id);
197 		if (block == NULL) {
198 			kfree(msg);
199 			ret = -ENOMEM;
200 			goto out;
201 		}
202 	}
203 
204 	sst_add_to_dispatch_list_and_post(sst_drv_ctx, msg);
205 	dev_dbg(sst_drv_ctx->dev, "msg->mrfld_header.p.header_low_payload:%d",
206 			msg->mrfld_header.p.header_low_payload);
207 
208 	if (bytes->block) {
209 		ret = sst_wait_timeout(sst_drv_ctx, block);
210 		if (ret) {
211 			dev_err(sst_drv_ctx->dev, "fw returned err %d\n", ret);
212 			sst_free_block(sst_drv_ctx, block);
213 			goto out;
214 		}
215 	}
216 	if (bytes->type == SND_SST_BYTES_GET) {
217 		/*
218 		 * copy the reply and send back
219 		 * we need to update only sz and payload
220 		 */
221 		if (bytes->block) {
222 			unsigned char *r = block->data;
223 
224 			dev_dbg(sst_drv_ctx->dev, "read back %d bytes",
225 					bytes->len);
226 			memcpy(bytes->bytes, r, bytes->len);
227 		}
228 	}
229 	if (bytes->block)
230 		sst_free_block(sst_drv_ctx, block);
231 out:
232 	test_and_clear_bit(pvt_id, &sst_drv_ctx->pvt_id);
233 	return ret;
234 }
235 
236 /**
237  * sst_pause_stream - Send msg for a pausing stream
238  * @sst_drv_ctx: intel_sst_drv context pointer
239  * @str_id: stream ID
240  *
241  * This function is called by any function which wants to pause
242  * an already running stream.
243  */
244 int sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
245 {
246 	int retval = 0;
247 	struct stream_info *str_info;
248 
249 	dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_pause_stream for %d\n", str_id);
250 	str_info = get_stream_info(sst_drv_ctx, str_id);
251 	if (!str_info)
252 		return -EINVAL;
253 	if (str_info->status == STREAM_PAUSED)
254 		return 0;
255 	if (str_info->status == STREAM_RUNNING ||
256 		str_info->status == STREAM_INIT) {
257 		if (str_info->prev == STREAM_UN_INIT)
258 			return -EBADRQC;
259 
260 		retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
261 				IPC_IA_PAUSE_STREAM_MRFLD, str_info->pipe_id,
262 				0, NULL, NULL, true, true, false, true);
263 
264 		if (retval == 0) {
265 			str_info->prev = str_info->status;
266 			str_info->status = STREAM_PAUSED;
267 		} else if (retval == -SST_ERR_INVALID_STREAM_ID) {
268 			retval = -EINVAL;
269 			mutex_lock(&sst_drv_ctx->sst_lock);
270 			sst_clean_stream(str_info);
271 			mutex_unlock(&sst_drv_ctx->sst_lock);
272 		}
273 	} else {
274 		retval = -EBADRQC;
275 		dev_dbg(sst_drv_ctx->dev, "SST DBG:BADRQC for stream\n");
276 	}
277 
278 	return retval;
279 }
280 
281 /**
282  * sst_resume_stream - Send msg for resuming stream
283  * @sst_drv_ctx: intel_sst_drv context pointer
284  * @str_id: stream ID
285  *
286  * This function is called by any function which wants to resume
287  * an already paused stream.
288  */
289 int sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
290 {
291 	int retval = 0;
292 	struct stream_info *str_info;
293 
294 	dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_resume_stream for %d\n", str_id);
295 	str_info = get_stream_info(sst_drv_ctx, str_id);
296 	if (!str_info)
297 		return -EINVAL;
298 	if (str_info->status == STREAM_RUNNING)
299 		return 0;
300 
301 	if (str_info->resume_status == STREAM_PAUSED &&
302 	    str_info->resume_prev == STREAM_RUNNING) {
303 		/*
304 		 * Stream was running before suspend and re-created on resume,
305 		 * start it to get back to running state.
306 		 */
307 		dev_dbg(sst_drv_ctx->dev, "restart recreated stream after resume\n");
308 		str_info->status = STREAM_RUNNING;
309 		str_info->prev = STREAM_PAUSED;
310 		retval = sst_start_stream(sst_drv_ctx, str_id);
311 		str_info->resume_status = STREAM_UN_INIT;
312 	} else if (str_info->resume_status == STREAM_PAUSED &&
313 		   str_info->resume_prev == STREAM_INIT) {
314 		/*
315 		 * Stream was idle before suspend and re-created on resume,
316 		 * keep it as is.
317 		 */
318 		dev_dbg(sst_drv_ctx->dev, "leaving recreated stream idle after resume\n");
319 		str_info->status = STREAM_INIT;
320 		str_info->prev = STREAM_PAUSED;
321 		str_info->resume_status = STREAM_UN_INIT;
322 	} else if (str_info->status == STREAM_PAUSED) {
323 		retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id,
324 				IPC_CMD, IPC_IA_RESUME_STREAM_MRFLD,
325 				str_info->pipe_id, 0, NULL, NULL,
326 				true, true, false, true);
327 
328 		if (!retval) {
329 			if (str_info->prev == STREAM_RUNNING)
330 				str_info->status = STREAM_RUNNING;
331 			else
332 				str_info->status = STREAM_INIT;
333 			str_info->prev = STREAM_PAUSED;
334 		} else if (retval == -SST_ERR_INVALID_STREAM_ID) {
335 			retval = -EINVAL;
336 			mutex_lock(&sst_drv_ctx->sst_lock);
337 			sst_clean_stream(str_info);
338 			mutex_unlock(&sst_drv_ctx->sst_lock);
339 		}
340 	} else {
341 		retval = -EBADRQC;
342 		dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream\n");
343 	}
344 
345 	return retval;
346 }
347 
348 
349 /**
350  * sst_drop_stream - Send msg for stopping stream
351  * @sst_drv_ctx: intel_sst_drv context pointer
352  * @str_id: stream ID
353  *
354  * This function is called by any function which wants to stop
355  * a stream.
356  */
357 int sst_drop_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
358 {
359 	int retval = 0;
360 	struct stream_info *str_info;
361 
362 	dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_drop_stream for %d\n", str_id);
363 	str_info = get_stream_info(sst_drv_ctx, str_id);
364 	if (!str_info)
365 		return -EINVAL;
366 
367 	if (str_info->status != STREAM_UN_INIT) {
368 		str_info->prev = STREAM_UN_INIT;
369 		str_info->status = STREAM_INIT;
370 		str_info->cumm_bytes = 0;
371 		retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id,
372 				IPC_CMD, IPC_IA_DROP_STREAM_MRFLD,
373 				str_info->pipe_id, 0, NULL, NULL,
374 				true, true, true, false);
375 	} else {
376 		retval = -EBADRQC;
377 		dev_dbg(sst_drv_ctx->dev, "BADQRC for stream, state %x\n",
378 				str_info->status);
379 	}
380 	return retval;
381 }
382 
383 /**
384  * sst_drain_stream - Send msg for draining stream
385  * @sst_drv_ctx: intel_sst_drv context pointer
386  * @str_id: stream ID
387  * @partial_drain: boolean indicating if a gapless transition is taking place
388  *
389  * This function is called by any function which wants to drain
390  * a stream.
391  */
392 int sst_drain_stream(struct intel_sst_drv *sst_drv_ctx,
393 			int str_id, bool partial_drain)
394 {
395 	int retval = 0;
396 	struct stream_info *str_info;
397 
398 	dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_drain_stream for %d\n", str_id);
399 	str_info = get_stream_info(sst_drv_ctx, str_id);
400 	if (!str_info)
401 		return -EINVAL;
402 	if (str_info->status != STREAM_RUNNING &&
403 		str_info->status != STREAM_INIT &&
404 		str_info->status != STREAM_PAUSED) {
405 			dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream = %d\n",
406 				       str_info->status);
407 			return -EBADRQC;
408 	}
409 
410 	retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
411 			IPC_IA_DRAIN_STREAM_MRFLD, str_info->pipe_id,
412 			sizeof(u8), &partial_drain, NULL, true, true, false, false);
413 	/*
414 	 * with new non blocked drain implementation in core we dont need to
415 	 * wait for respsonse, and need to only invoke callback for drain
416 	 * complete
417 	 */
418 
419 	return retval;
420 }
421 
422 /**
423  * sst_free_stream - Frees a stream
424  * @sst_drv_ctx: intel_sst_drv context pointer
425  * @str_id: stream ID
426  *
427  * This function is called by any function which wants to free
428  * a stream.
429  */
430 int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
431 {
432 	int retval = 0;
433 	struct stream_info *str_info;
434 
435 	dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_free_stream for %d\n", str_id);
436 
437 	mutex_lock(&sst_drv_ctx->sst_lock);
438 	if (sst_drv_ctx->sst_state == SST_RESET) {
439 		mutex_unlock(&sst_drv_ctx->sst_lock);
440 		return -ENODEV;
441 	}
442 	mutex_unlock(&sst_drv_ctx->sst_lock);
443 	str_info = get_stream_info(sst_drv_ctx, str_id);
444 	if (!str_info)
445 		return -EINVAL;
446 
447 	mutex_lock(&str_info->lock);
448 	if (str_info->status != STREAM_UN_INIT) {
449 		str_info->prev =  str_info->status;
450 		str_info->status = STREAM_UN_INIT;
451 		mutex_unlock(&str_info->lock);
452 
453 		dev_dbg(sst_drv_ctx->dev, "Free for str %d pipe %#x\n",
454 				str_id, str_info->pipe_id);
455 		retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
456 				IPC_IA_FREE_STREAM_MRFLD, str_info->pipe_id, 0,
457 				NULL, NULL, true, true, false, true);
458 
459 		dev_dbg(sst_drv_ctx->dev, "sst: wait for free returned %d\n",
460 				retval);
461 		mutex_lock(&sst_drv_ctx->sst_lock);
462 		sst_clean_stream(str_info);
463 		mutex_unlock(&sst_drv_ctx->sst_lock);
464 		dev_dbg(sst_drv_ctx->dev, "SST DBG:Stream freed\n");
465 	} else {
466 		mutex_unlock(&str_info->lock);
467 		retval = -EBADRQC;
468 		dev_dbg(sst_drv_ctx->dev, "SST DBG:BADQRC for stream\n");
469 	}
470 
471 	return retval;
472 }
473