1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#include <linux/pci.h>
23#include <linux/firmware.h>
24#include <linux/sched.h>
25#include <linux/delay.h>
26#include <linux/pm_runtime.h>
27#include <sound/core.h>
28#include <sound/pcm.h>
29#include <sound/soc.h>
30#include <sound/compress_driver.h>
31#include <asm/platform_sst_audio.h>
32#include "../sst-mfld-platform.h"
33#include "sst.h"
34#include "../../common/sst-dsp.h"
35
36int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params)
37{
38 struct snd_sst_alloc_mrfld alloc_param;
39 struct snd_sst_params *str_params;
40 struct snd_sst_tstamp fw_tstamp;
41 struct stream_info *str_info;
42 struct snd_sst_alloc_response *response;
43 unsigned int str_id, pipe_id, task_id;
44 int i, num_ch, ret = 0;
45 void *data = NULL;
46
47 dev_dbg(sst_drv_ctx->dev, "Enter\n");
48 BUG_ON(!params);
49
50 str_params = (struct snd_sst_params *)params;
51 memset(&alloc_param, 0, sizeof(alloc_param));
52 alloc_param.operation = str_params->ops;
53 alloc_param.codec_type = str_params->codec;
54 alloc_param.sg_count = str_params->aparams.sg_count;
55 alloc_param.ring_buf_info[0].addr =
56 str_params->aparams.ring_buf_info[0].addr;
57 alloc_param.ring_buf_info[0].size =
58 str_params->aparams.ring_buf_info[0].size;
59 alloc_param.frag_size = str_params->aparams.frag_size;
60
61 memcpy(&alloc_param.codec_params, &str_params->sparams,
62 sizeof(struct snd_sst_stream_params));
63
64
65
66
67
68
69
70 num_ch = sst_get_num_channel(str_params);
71 for (i = 0; i < 8; i++) {
72 if (i < num_ch)
73 alloc_param.codec_params.uc.pcm_params.channel_map[i] = i;
74 else
75 alloc_param.codec_params.uc.pcm_params.channel_map[i] = 0xFF;
76 }
77
78 str_id = str_params->stream_id;
79 str_info = get_stream_info(sst_drv_ctx, str_id);
80 if (str_info == NULL) {
81 dev_err(sst_drv_ctx->dev, "get stream info returned null\n");
82 return -EINVAL;
83 }
84
85 pipe_id = str_params->device_type;
86 task_id = str_params->task;
87 sst_drv_ctx->streams[str_id].pipe_id = pipe_id;
88 sst_drv_ctx->streams[str_id].task_id = task_id;
89 sst_drv_ctx->streams[str_id].num_ch = num_ch;
90
91 if (sst_drv_ctx->info.lpe_viewpt_rqd)
92 alloc_param.ts = sst_drv_ctx->info.mailbox_start +
93 sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp));
94 else
95 alloc_param.ts = sst_drv_ctx->mailbox_add +
96 sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp));
97
98 dev_dbg(sst_drv_ctx->dev, "alloc tstamp location = 0x%x\n",
99 alloc_param.ts);
100 dev_dbg(sst_drv_ctx->dev, "assigned pipe id 0x%x to task %d\n",
101 pipe_id, task_id);
102
103
104 sst_init_stream(&sst_drv_ctx->streams[str_id], alloc_param.codec_type,
105 str_id, alloc_param.operation, 0);
106
107 dev_dbg(sst_drv_ctx->dev, "Alloc for str %d pipe %#x\n",
108 str_id, pipe_id);
109 ret = sst_prepare_and_post_msg(sst_drv_ctx, task_id, IPC_CMD,
110 IPC_IA_ALLOC_STREAM_MRFLD, pipe_id, sizeof(alloc_param),
111 &alloc_param, &data, true, true, false, true);
112
113 if (ret < 0) {
114 dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret);
115
116 str_info->status = STREAM_UN_INIT;
117 str_id = ret;
118 } else if (data) {
119 response = (struct snd_sst_alloc_response *)data;
120 ret = response->str_type.result;
121 if (!ret)
122 goto out;
123 dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret);
124 if (ret == SST_ERR_STREAM_IN_USE) {
125 dev_err(sst_drv_ctx->dev,
126 "FW not in clean state, send free for:%d\n", str_id);
127 sst_free_stream(sst_drv_ctx, str_id);
128 }
129 str_id = -ret;
130 }
131out:
132 kfree(data);
133 return str_id;
134}
135
136
137
138
139
140
141
142
143int sst_start_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
144{
145 int retval = 0;
146 struct stream_info *str_info;
147 u16 data = 0;
148
149 dev_dbg(sst_drv_ctx->dev, "sst_start_stream for %d\n", str_id);
150 str_info = get_stream_info(sst_drv_ctx, str_id);
151 if (!str_info)
152 return -EINVAL;
153 if (str_info->status != STREAM_RUNNING)
154 return -EBADRQC;
155
156 retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id,
157 IPC_CMD, IPC_IA_START_STREAM_MRFLD, str_info->pipe_id,
158 sizeof(u16), &data, NULL, true, true, true, false);
159
160 return retval;
161}
162
163int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx,
164 struct snd_sst_bytes_v2 *bytes)
165{ struct ipc_post *msg = NULL;
166 u32 length;
167 int pvt_id, ret = 0;
168 struct sst_block *block = NULL;
169
170 dev_dbg(sst_drv_ctx->dev,
171 "type:%u ipc_msg:%u block:%u task_id:%u pipe: %#x length:%#x\n",
172 bytes->type, bytes->ipc_msg, bytes->block, bytes->task_id,
173 bytes->pipe_id, bytes->len);
174
175 if (sst_create_ipc_msg(&msg, true))
176 return -ENOMEM;
177
178 pvt_id = sst_assign_pvt_id(sst_drv_ctx);
179 sst_fill_header_mrfld(&msg->mrfld_header, bytes->ipc_msg,
180 bytes->task_id, 1, pvt_id);
181 msg->mrfld_header.p.header_high.part.res_rqd = bytes->block;
182 length = bytes->len;
183 msg->mrfld_header.p.header_low_payload = length;
184 dev_dbg(sst_drv_ctx->dev, "length is %d\n", length);
185 memcpy(msg->mailbox_data, &bytes->bytes, bytes->len);
186 if (bytes->block) {
187 block = sst_create_block(sst_drv_ctx, bytes->ipc_msg, pvt_id);
188 if (block == NULL) {
189 kfree(msg);
190 ret = -ENOMEM;
191 goto out;
192 }
193 }
194
195 sst_add_to_dispatch_list_and_post(sst_drv_ctx, msg);
196 dev_dbg(sst_drv_ctx->dev, "msg->mrfld_header.p.header_low_payload:%d",
197 msg->mrfld_header.p.header_low_payload);
198
199 if (bytes->block) {
200 ret = sst_wait_timeout(sst_drv_ctx, block);
201 if (ret) {
202 dev_err(sst_drv_ctx->dev, "fw returned err %d\n", ret);
203 sst_free_block(sst_drv_ctx, block);
204 goto out;
205 }
206 }
207 if (bytes->type == SND_SST_BYTES_GET) {
208
209
210
211
212 if (bytes->block) {
213 unsigned char *r = block->data;
214
215 dev_dbg(sst_drv_ctx->dev, "read back %d bytes",
216 bytes->len);
217 memcpy(bytes->bytes, r, bytes->len);
218 }
219 }
220 if (bytes->block)
221 sst_free_block(sst_drv_ctx, block);
222out:
223 test_and_clear_bit(pvt_id, &sst_drv_ctx->pvt_id);
224 return 0;
225}
226
227
228
229
230
231
232
233
234int sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
235{
236 int retval = 0;
237 struct stream_info *str_info;
238
239 dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_pause_stream for %d\n", str_id);
240 str_info = get_stream_info(sst_drv_ctx, str_id);
241 if (!str_info)
242 return -EINVAL;
243 if (str_info->status == STREAM_PAUSED)
244 return 0;
245 if (str_info->status == STREAM_RUNNING ||
246 str_info->status == STREAM_INIT) {
247 if (str_info->prev == STREAM_UN_INIT)
248 return -EBADRQC;
249
250 retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
251 IPC_IA_PAUSE_STREAM_MRFLD, str_info->pipe_id,
252 0, NULL, NULL, true, true, false, true);
253
254 if (retval == 0) {
255 str_info->prev = str_info->status;
256 str_info->status = STREAM_PAUSED;
257 } else if (retval == SST_ERR_INVALID_STREAM_ID) {
258 retval = -EINVAL;
259 mutex_lock(&sst_drv_ctx->sst_lock);
260 sst_clean_stream(str_info);
261 mutex_unlock(&sst_drv_ctx->sst_lock);
262 }
263 } else {
264 retval = -EBADRQC;
265 dev_dbg(sst_drv_ctx->dev, "SST DBG:BADRQC for stream\n ");
266 }
267
268 return retval;
269}
270
271
272
273
274
275
276
277
278int sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
279{
280 int retval = 0;
281 struct stream_info *str_info;
282
283 dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_resume_stream for %d\n", str_id);
284 str_info = get_stream_info(sst_drv_ctx, str_id);
285 if (!str_info)
286 return -EINVAL;
287 if (str_info->status == STREAM_RUNNING)
288 return 0;
289 if (str_info->status == STREAM_PAUSED) {
290 retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id,
291 IPC_CMD, IPC_IA_RESUME_STREAM_MRFLD,
292 str_info->pipe_id, 0, NULL, NULL,
293 true, true, false, true);
294
295 if (!retval) {
296 if (str_info->prev == STREAM_RUNNING)
297 str_info->status = STREAM_RUNNING;
298 else
299 str_info->status = STREAM_INIT;
300 str_info->prev = STREAM_PAUSED;
301 } else if (retval == -SST_ERR_INVALID_STREAM_ID) {
302 retval = -EINVAL;
303 mutex_lock(&sst_drv_ctx->sst_lock);
304 sst_clean_stream(str_info);
305 mutex_unlock(&sst_drv_ctx->sst_lock);
306 }
307 } else {
308 retval = -EBADRQC;
309 dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream\n");
310 }
311
312 return retval;
313}
314
315
316
317
318
319
320
321
322
323int sst_drop_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
324{
325 int retval = 0;
326 struct stream_info *str_info;
327
328 dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_drop_stream for %d\n", str_id);
329 str_info = get_stream_info(sst_drv_ctx, str_id);
330 if (!str_info)
331 return -EINVAL;
332
333 if (str_info->status != STREAM_UN_INIT) {
334 str_info->prev = STREAM_UN_INIT;
335 str_info->status = STREAM_INIT;
336 str_info->cumm_bytes = 0;
337 retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id,
338 IPC_CMD, IPC_IA_DROP_STREAM_MRFLD,
339 str_info->pipe_id, 0, NULL, NULL,
340 true, true, true, false);
341 } else {
342 retval = -EBADRQC;
343 dev_dbg(sst_drv_ctx->dev, "BADQRC for stream, state %x\n",
344 str_info->status);
345 }
346 return retval;
347}
348
349
350
351
352
353
354
355
356int sst_drain_stream(struct intel_sst_drv *sst_drv_ctx,
357 int str_id, bool partial_drain)
358{
359 int retval = 0;
360 struct stream_info *str_info;
361
362 dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_drain_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 if (str_info->status != STREAM_RUNNING &&
367 str_info->status != STREAM_INIT &&
368 str_info->status != STREAM_PAUSED) {
369 dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream = %d\n",
370 str_info->status);
371 return -EBADRQC;
372 }
373
374 retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
375 IPC_IA_DRAIN_STREAM_MRFLD, str_info->pipe_id,
376 sizeof(u8), &partial_drain, NULL, true, true, false, false);
377
378
379
380
381
382
383 return retval;
384}
385
386
387
388
389
390
391
392
393int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
394{
395 int retval = 0;
396 struct stream_info *str_info;
397
398 dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_free_stream for %d\n", str_id);
399
400 mutex_lock(&sst_drv_ctx->sst_lock);
401 if (sst_drv_ctx->sst_state == SST_RESET) {
402 mutex_unlock(&sst_drv_ctx->sst_lock);
403 return -ENODEV;
404 }
405 mutex_unlock(&sst_drv_ctx->sst_lock);
406 str_info = get_stream_info(sst_drv_ctx, str_id);
407 if (!str_info)
408 return -EINVAL;
409
410 mutex_lock(&str_info->lock);
411 if (str_info->status != STREAM_UN_INIT) {
412 str_info->prev = str_info->status;
413 str_info->status = STREAM_UN_INIT;
414 mutex_unlock(&str_info->lock);
415
416 dev_dbg(sst_drv_ctx->dev, "Free for str %d pipe %#x\n",
417 str_id, str_info->pipe_id);
418 retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
419 IPC_IA_FREE_STREAM_MRFLD, str_info->pipe_id, 0,
420 NULL, NULL, true, true, false, true);
421
422 dev_dbg(sst_drv_ctx->dev, "sst: wait for free returned %d\n",
423 retval);
424 mutex_lock(&sst_drv_ctx->sst_lock);
425 sst_clean_stream(str_info);
426 mutex_unlock(&sst_drv_ctx->sst_lock);
427 dev_dbg(sst_drv_ctx->dev, "SST DBG:Stream freed\n");
428 } else {
429 mutex_unlock(&str_info->lock);
430 retval = -EBADRQC;
431 dev_dbg(sst_drv_ctx->dev, "SST DBG:BADQRC for stream\n");
432 }
433
434 return retval;
435}
436