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