xref: /openbmc/linux/sound/soc/qcom/qdsp6/q6asm.c (revision 14474950)
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
3 // Copyright (c) 2018, Linaro Limited
4 
5 #include <linux/mutex.h>
6 #include <linux/wait.h>
7 #include <linux/module.h>
8 #include <linux/soc/qcom/apr.h>
9 #include <linux/device.h>
10 #include <linux/of_platform.h>
11 #include <linux/spinlock.h>
12 #include <linux/kref.h>
13 #include <linux/of.h>
14 #include <uapi/sound/asound.h>
15 #include <uapi/sound/compress_params.h>
16 #include <linux/delay.h>
17 #include <linux/slab.h>
18 #include <linux/mm.h>
19 #include "q6asm.h"
20 #include "q6core.h"
21 #include "q6dsp-errno.h"
22 #include "q6dsp-common.h"
23 
24 #define ASM_STREAM_CMD_CLOSE			0x00010BCD
25 #define ASM_STREAM_CMD_FLUSH			0x00010BCE
26 #define ASM_SESSION_CMD_PAUSE			0x00010BD3
27 #define ASM_DATA_CMD_EOS			0x00010BDB
28 #define ASM_DATA_EVENT_RENDERED_EOS		0x00010C1C
29 #define ASM_NULL_POPP_TOPOLOGY			0x00010C68
30 #define ASM_STREAM_CMD_FLUSH_READBUFS		0x00010C09
31 #define ASM_STREAM_CMD_SET_ENCDEC_PARAM		0x00010C10
32 #define ASM_STREAM_POSTPROC_TOPO_ID_NONE	0x00010C68
33 #define ASM_CMD_SHARED_MEM_MAP_REGIONS		0x00010D92
34 #define ASM_CMDRSP_SHARED_MEM_MAP_REGIONS	0x00010D93
35 #define ASM_CMD_SHARED_MEM_UNMAP_REGIONS	0x00010D94
36 #define ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2	0x00010D98
37 #define ASM_DATA_EVENT_WRITE_DONE_V2		0x00010D99
38 #define ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2	0x00010DA3
39 #define ASM_SESSION_CMD_RUN_V2			0x00010DAA
40 #define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2	0x00010DA5
41 #define ASM_MEDIA_FMT_MP3			0x00010BE9
42 #define ASM_MEDIA_FMT_FLAC			0x00010C16
43 #define ASM_MEDIA_FMT_WMA_V9			0x00010DA8
44 #define ASM_MEDIA_FMT_WMA_V10			0x00010DA7
45 #define ASM_DATA_CMD_WRITE_V2			0x00010DAB
46 #define ASM_DATA_CMD_READ_V2			0x00010DAC
47 #define ASM_SESSION_CMD_SUSPEND			0x00010DEC
48 #define ASM_STREAM_CMD_OPEN_WRITE_V3		0x00010DB3
49 #define ASM_STREAM_CMD_OPEN_READ_V3                 0x00010DB4
50 #define ASM_DATA_EVENT_READ_DONE_V2 0x00010D9A
51 #define ASM_STREAM_CMD_OPEN_READWRITE_V2        0x00010D8D
52 #define ASM_MEDIA_FMT_ALAC			0x00012f31
53 #define ASM_MEDIA_FMT_APE			0x00012f32
54 
55 
56 #define ASM_LEGACY_STREAM_SESSION	0
57 /* Bit shift for the stream_perf_mode subfield. */
58 #define ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ              29
59 #define ASM_END_POINT_DEVICE_MATRIX	0
60 #define ASM_DEFAULT_APP_TYPE		0
61 #define ASM_SYNC_IO_MODE		0x0001
62 #define ASM_ASYNC_IO_MODE		0x0002
63 #define ASM_TUN_READ_IO_MODE		0x0004	/* tunnel read write mode */
64 #define ASM_TUN_WRITE_IO_MODE		0x0008	/* tunnel read write mode */
65 #define ASM_SHIFT_GAPLESS_MODE_FLAG	31
66 #define ADSP_MEMORY_MAP_SHMEM8_4K_POOL	3
67 
68 struct avs_cmd_shared_mem_map_regions {
69 	u16 mem_pool_id;
70 	u16 num_regions;
71 	u32 property_flag;
72 } __packed;
73 
74 struct avs_shared_map_region_payload {
75 	u32 shm_addr_lsw;
76 	u32 shm_addr_msw;
77 	u32 mem_size_bytes;
78 } __packed;
79 
80 struct avs_cmd_shared_mem_unmap_regions {
81 	u32 mem_map_handle;
82 } __packed;
83 
84 struct asm_data_cmd_media_fmt_update_v2 {
85 	u32 fmt_blk_size;
86 } __packed;
87 
88 struct asm_multi_channel_pcm_fmt_blk_v2 {
89 	struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
90 	u16 num_channels;
91 	u16 bits_per_sample;
92 	u32 sample_rate;
93 	u16 is_signed;
94 	u16 reserved;
95 	u8 channel_mapping[PCM_MAX_NUM_CHANNEL];
96 } __packed;
97 
98 struct asm_flac_fmt_blk_v2 {
99 	struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
100 	u16 is_stream_info_present;
101 	u16 num_channels;
102 	u16 min_blk_size;
103 	u16 max_blk_size;
104 	u16 md5_sum[8];
105 	u32 sample_rate;
106 	u32 min_frame_size;
107 	u32 max_frame_size;
108 	u16 sample_size;
109 	u16 reserved;
110 } __packed;
111 
112 struct asm_wmastdv9_fmt_blk_v2 {
113 	struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
114 	u16          fmtag;
115 	u16          num_channels;
116 	u32          sample_rate;
117 	u32          bytes_per_sec;
118 	u16          blk_align;
119 	u16          bits_per_sample;
120 	u32          channel_mask;
121 	u16          enc_options;
122 	u16          reserved;
123 } __packed;
124 
125 struct asm_wmaprov10_fmt_blk_v2 {
126 	struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
127 	u16          fmtag;
128 	u16          num_channels;
129 	u32          sample_rate;
130 	u32          bytes_per_sec;
131 	u16          blk_align;
132 	u16          bits_per_sample;
133 	u32          channel_mask;
134 	u16          enc_options;
135 	u16          advanced_enc_options1;
136 	u32          advanced_enc_options2;
137 } __packed;
138 
139 struct asm_alac_fmt_blk_v2 {
140 	struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
141 	u32 frame_length;
142 	u8 compatible_version;
143 	u8 bit_depth;
144 	u8 pb;
145 	u8 mb;
146 	u8 kb;
147 	u8 num_channels;
148 	u16 max_run;
149 	u32 max_frame_bytes;
150 	u32 avg_bit_rate;
151 	u32 sample_rate;
152 	u32 channel_layout_tag;
153 } __packed;
154 
155 struct asm_ape_fmt_blk_v2 {
156 	struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
157 	u16 compatible_version;
158 	u16 compression_level;
159 	u32 format_flags;
160 	u32 blocks_per_frame;
161 	u32 final_frame_blocks;
162 	u32 total_frames;
163 	u16 bits_per_sample;
164 	u16 num_channels;
165 	u32 sample_rate;
166 	u32 seek_table_present;
167 } __packed;
168 
169 struct asm_stream_cmd_set_encdec_param {
170 	u32                  param_id;
171 	u32                  param_size;
172 } __packed;
173 
174 struct asm_enc_cfg_blk_param_v2 {
175 	u32                  frames_per_buf;
176 	u32                  enc_cfg_blk_size;
177 } __packed;
178 
179 struct asm_multi_channel_pcm_enc_cfg_v2 {
180 	struct asm_stream_cmd_set_encdec_param  encdec;
181 	struct asm_enc_cfg_blk_param_v2	encblk;
182 	uint16_t  num_channels;
183 	uint16_t  bits_per_sample;
184 	uint32_t  sample_rate;
185 	uint16_t  is_signed;
186 	uint16_t  reserved;
187 	uint8_t   channel_mapping[8];
188 } __packed;
189 
190 struct asm_data_cmd_read_v2 {
191 	u32                  buf_addr_lsw;
192 	u32                  buf_addr_msw;
193 	u32                  mem_map_handle;
194 	u32                  buf_size;
195 	u32                  seq_id;
196 } __packed;
197 
198 struct asm_data_cmd_read_v2_done {
199 	u32	status;
200 	u32	buf_addr_lsw;
201 	u32	buf_addr_msw;
202 };
203 
204 struct asm_stream_cmd_open_read_v3 {
205 	u32                    mode_flags;
206 	u32                    src_endpointype;
207 	u32                    preprocopo_id;
208 	u32                    enc_cfg_id;
209 	u16                    bits_per_sample;
210 	u16                    reserved;
211 } __packed;
212 
213 struct asm_data_cmd_write_v2 {
214 	u32 buf_addr_lsw;
215 	u32 buf_addr_msw;
216 	u32 mem_map_handle;
217 	u32 buf_size;
218 	u32 seq_id;
219 	u32 timestamp_lsw;
220 	u32 timestamp_msw;
221 	u32 flags;
222 } __packed;
223 
224 struct asm_stream_cmd_open_write_v3 {
225 	uint32_t mode_flags;
226 	uint16_t sink_endpointype;
227 	uint16_t bits_per_sample;
228 	uint32_t postprocopo_id;
229 	uint32_t dec_fmt_id;
230 } __packed;
231 
232 struct asm_session_cmd_run_v2 {
233 	u32 flags;
234 	u32 time_lsw;
235 	u32 time_msw;
236 } __packed;
237 
238 struct audio_buffer {
239 	phys_addr_t phys;
240 	uint32_t size;		/* size of buffer */
241 };
242 
243 struct audio_port_data {
244 	struct audio_buffer *buf;
245 	uint32_t num_periods;
246 	uint32_t dsp_buf;
247 	uint32_t mem_map_handle;
248 };
249 
250 struct q6asm {
251 	struct apr_device *adev;
252 	struct device *dev;
253 	struct q6core_svc_api_info ainfo;
254 	wait_queue_head_t mem_wait;
255 	spinlock_t slock;
256 	struct audio_client *session[MAX_SESSIONS + 1];
257 };
258 
259 struct audio_client {
260 	int session;
261 	q6asm_cb cb;
262 	void *priv;
263 	uint32_t io_mode;
264 	struct apr_device *adev;
265 	struct mutex cmd_lock;
266 	spinlock_t lock;
267 	struct kref refcount;
268 	/* idx:1 out port, 0: in port */
269 	struct audio_port_data port[2];
270 	wait_queue_head_t cmd_wait;
271 	struct aprv2_ibasic_rsp_result_t result;
272 	int perf_mode;
273 	int stream_id;
274 	struct q6asm *q6asm;
275 	struct device *dev;
276 };
277 
278 static inline void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
279 				 uint32_t pkt_size, bool cmd_flg,
280 				 uint32_t stream_id)
281 {
282 	hdr->hdr_field = APR_SEQ_CMD_HDR_FIELD;
283 	hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id);
284 	hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id);
285 	hdr->pkt_size = pkt_size;
286 	if (cmd_flg)
287 		hdr->token = ac->session;
288 }
289 
290 static int q6asm_apr_send_session_pkt(struct q6asm *a, struct audio_client *ac,
291 				      struct apr_pkt *pkt, uint32_t rsp_opcode)
292 {
293 	struct apr_hdr *hdr = &pkt->hdr;
294 	int rc;
295 
296 	mutex_lock(&ac->cmd_lock);
297 	ac->result.opcode = 0;
298 	ac->result.status = 0;
299 	rc = apr_send_pkt(a->adev, pkt);
300 	if (rc < 0)
301 		goto err;
302 
303 	if (rsp_opcode)
304 		rc = wait_event_timeout(a->mem_wait,
305 					(ac->result.opcode == hdr->opcode) ||
306 					(ac->result.opcode == rsp_opcode),
307 					5 * HZ);
308 	else
309 		rc = wait_event_timeout(a->mem_wait,
310 					(ac->result.opcode == hdr->opcode),
311 					5 * HZ);
312 
313 	if (!rc) {
314 		dev_err(a->dev, "CMD timeout\n");
315 		rc = -ETIMEDOUT;
316 	} else if (ac->result.status > 0) {
317 		dev_err(a->dev, "DSP returned error[%x]\n",
318 			ac->result.status);
319 		rc = -EINVAL;
320 	}
321 
322 err:
323 	mutex_unlock(&ac->cmd_lock);
324 	return rc;
325 }
326 
327 static int __q6asm_memory_unmap(struct audio_client *ac,
328 				phys_addr_t buf_add, int dir)
329 {
330 	struct avs_cmd_shared_mem_unmap_regions *mem_unmap;
331 	struct q6asm *a = dev_get_drvdata(ac->dev->parent);
332 	struct apr_pkt *pkt;
333 	int rc, pkt_size;
334 	void *p;
335 
336 	if (ac->port[dir].mem_map_handle == 0) {
337 		dev_err(ac->dev, "invalid mem handle\n");
338 		return -EINVAL;
339 	}
340 
341 	pkt_size = APR_HDR_SIZE + sizeof(*mem_unmap);
342 	p = kzalloc(pkt_size, GFP_KERNEL);
343 	if (!p)
344 		return -ENOMEM;
345 
346 	pkt = p;
347 	mem_unmap = p + APR_HDR_SIZE;
348 
349 	pkt->hdr.hdr_field = APR_SEQ_CMD_HDR_FIELD;
350 	pkt->hdr.src_port = 0;
351 	pkt->hdr.dest_port = 0;
352 	pkt->hdr.pkt_size = pkt_size;
353 	pkt->hdr.token = ((ac->session << 8) | dir);
354 
355 	pkt->hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS;
356 	mem_unmap->mem_map_handle = ac->port[dir].mem_map_handle;
357 
358 	rc = q6asm_apr_send_session_pkt(a, ac, pkt, 0);
359 	if (rc < 0) {
360 		kfree(pkt);
361 		return rc;
362 	}
363 
364 	ac->port[dir].mem_map_handle = 0;
365 
366 	kfree(pkt);
367 	return 0;
368 }
369 
370 
371 static void q6asm_audio_client_free_buf(struct audio_client *ac,
372 					struct audio_port_data *port)
373 {
374 	unsigned long flags;
375 
376 	spin_lock_irqsave(&ac->lock, flags);
377 	port->num_periods = 0;
378 	kfree(port->buf);
379 	port->buf = NULL;
380 	spin_unlock_irqrestore(&ac->lock, flags);
381 }
382 
383 /**
384  * q6asm_unmap_memory_regions() - unmap memory regions in the dsp.
385  *
386  * @dir: direction of audio stream
387  * @ac: audio client instanace
388  *
389  * Return: Will be an negative value on failure or zero on success
390  */
391 int q6asm_unmap_memory_regions(unsigned int dir, struct audio_client *ac)
392 {
393 	struct audio_port_data *port;
394 	int cnt = 0;
395 	int rc = 0;
396 
397 	port = &ac->port[dir];
398 	if (!port->buf) {
399 		rc = -EINVAL;
400 		goto err;
401 	}
402 
403 	cnt = port->num_periods - 1;
404 	if (cnt >= 0) {
405 		rc = __q6asm_memory_unmap(ac, port->buf[dir].phys, dir);
406 		if (rc < 0) {
407 			dev_err(ac->dev, "%s: Memory_unmap_regions failed %d\n",
408 				__func__, rc);
409 			goto err;
410 		}
411 	}
412 
413 	q6asm_audio_client_free_buf(ac, port);
414 
415 err:
416 	return rc;
417 }
418 EXPORT_SYMBOL_GPL(q6asm_unmap_memory_regions);
419 
420 static int __q6asm_memory_map_regions(struct audio_client *ac, int dir,
421 				      size_t period_sz, unsigned int periods,
422 				      bool is_contiguous)
423 {
424 	struct avs_cmd_shared_mem_map_regions *cmd = NULL;
425 	struct avs_shared_map_region_payload *mregions = NULL;
426 	struct q6asm *a = dev_get_drvdata(ac->dev->parent);
427 	struct audio_port_data *port = NULL;
428 	struct audio_buffer *ab = NULL;
429 	struct apr_pkt *pkt;
430 	void *p;
431 	unsigned long flags;
432 	uint32_t num_regions, buf_sz;
433 	int rc, i, pkt_size;
434 
435 	if (is_contiguous) {
436 		num_regions = 1;
437 		buf_sz = period_sz * periods;
438 	} else {
439 		buf_sz = period_sz;
440 		num_regions = periods;
441 	}
442 
443 	/* DSP expects size should be aligned to 4K */
444 	buf_sz = ALIGN(buf_sz, 4096);
445 
446 	pkt_size = APR_HDR_SIZE + sizeof(*cmd) +
447 		   (sizeof(*mregions) * num_regions);
448 
449 	p = kzalloc(pkt_size, GFP_KERNEL);
450 	if (!p)
451 		return -ENOMEM;
452 
453 	pkt = p;
454 	cmd = p + APR_HDR_SIZE;
455 	mregions = p + APR_HDR_SIZE +  sizeof(*cmd);
456 
457 	pkt->hdr.hdr_field = APR_SEQ_CMD_HDR_FIELD;
458 	pkt->hdr.src_port = 0;
459 	pkt->hdr.dest_port = 0;
460 	pkt->hdr.pkt_size = pkt_size;
461 	pkt->hdr.token = ((ac->session << 8) | dir);
462 	pkt->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS;
463 
464 	cmd->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
465 	cmd->num_regions = num_regions;
466 	cmd->property_flag = 0x00;
467 
468 	spin_lock_irqsave(&ac->lock, flags);
469 	port = &ac->port[dir];
470 
471 	for (i = 0; i < num_regions; i++) {
472 		ab = &port->buf[i];
473 		mregions->shm_addr_lsw = lower_32_bits(ab->phys);
474 		mregions->shm_addr_msw = upper_32_bits(ab->phys);
475 		mregions->mem_size_bytes = buf_sz;
476 		++mregions;
477 	}
478 	spin_unlock_irqrestore(&ac->lock, flags);
479 
480 	rc = q6asm_apr_send_session_pkt(a, ac, pkt,
481 					ASM_CMDRSP_SHARED_MEM_MAP_REGIONS);
482 
483 	kfree(pkt);
484 
485 	return rc;
486 }
487 
488 /**
489  * q6asm_map_memory_regions() - map memory regions in the dsp.
490  *
491  * @dir: direction of audio stream
492  * @ac: audio client instanace
493  * @phys: physcial address that needs mapping.
494  * @period_sz: audio period size
495  * @periods: number of periods
496  *
497  * Return: Will be an negative value on failure or zero on success
498  */
499 int q6asm_map_memory_regions(unsigned int dir, struct audio_client *ac,
500 			     phys_addr_t phys,
501 			     size_t period_sz, unsigned int periods)
502 {
503 	struct audio_buffer *buf;
504 	unsigned long flags;
505 	int cnt;
506 	int rc;
507 
508 	spin_lock_irqsave(&ac->lock, flags);
509 	if (ac->port[dir].buf) {
510 		dev_err(ac->dev, "Buffer already allocated\n");
511 		spin_unlock_irqrestore(&ac->lock, flags);
512 		return 0;
513 	}
514 
515 	buf = kzalloc(((sizeof(struct audio_buffer)) * periods), GFP_ATOMIC);
516 	if (!buf) {
517 		spin_unlock_irqrestore(&ac->lock, flags);
518 		return -ENOMEM;
519 	}
520 
521 
522 	ac->port[dir].buf = buf;
523 
524 	buf[0].phys = phys;
525 	buf[0].size = period_sz;
526 
527 	for (cnt = 1; cnt < periods; cnt++) {
528 		if (period_sz > 0) {
529 			buf[cnt].phys = buf[0].phys + (cnt * period_sz);
530 			buf[cnt].size = period_sz;
531 		}
532 	}
533 	ac->port[dir].num_periods = periods;
534 
535 	spin_unlock_irqrestore(&ac->lock, flags);
536 
537 	rc = __q6asm_memory_map_regions(ac, dir, period_sz, periods, 1);
538 	if (rc < 0) {
539 		dev_err(ac->dev, "Memory_map_regions failed\n");
540 		q6asm_audio_client_free_buf(ac, &ac->port[dir]);
541 	}
542 
543 	return rc;
544 }
545 EXPORT_SYMBOL_GPL(q6asm_map_memory_regions);
546 
547 static void q6asm_audio_client_release(struct kref *ref)
548 {
549 	struct audio_client *ac;
550 	struct q6asm *a;
551 	unsigned long flags;
552 
553 	ac = container_of(ref, struct audio_client, refcount);
554 	a = ac->q6asm;
555 
556 	spin_lock_irqsave(&a->slock, flags);
557 	a->session[ac->session] = NULL;
558 	spin_unlock_irqrestore(&a->slock, flags);
559 
560 	kfree(ac);
561 }
562 
563 /**
564  * q6asm_audio_client_free() - Freee allocated audio client
565  *
566  * @ac: audio client to free
567  */
568 void q6asm_audio_client_free(struct audio_client *ac)
569 {
570 	kref_put(&ac->refcount, q6asm_audio_client_release);
571 }
572 EXPORT_SYMBOL_GPL(q6asm_audio_client_free);
573 
574 static struct audio_client *q6asm_get_audio_client(struct q6asm *a,
575 						   int session_id)
576 {
577 	struct audio_client *ac = NULL;
578 	unsigned long flags;
579 
580 	spin_lock_irqsave(&a->slock, flags);
581 	if ((session_id <= 0) || (session_id > MAX_SESSIONS)) {
582 		dev_err(a->dev, "invalid session: %d\n", session_id);
583 		goto err;
584 	}
585 
586 	/* check for valid session */
587 	if (!a->session[session_id])
588 		goto err;
589 	else if (a->session[session_id]->session != session_id)
590 		goto err;
591 
592 	ac = a->session[session_id];
593 	kref_get(&ac->refcount);
594 err:
595 	spin_unlock_irqrestore(&a->slock, flags);
596 	return ac;
597 }
598 
599 static int32_t q6asm_stream_callback(struct apr_device *adev,
600 				     struct apr_resp_pkt *data,
601 				     int session_id)
602 {
603 	struct q6asm *q6asm = dev_get_drvdata(&adev->dev);
604 	struct aprv2_ibasic_rsp_result_t *result;
605 	struct apr_hdr *hdr = &data->hdr;
606 	struct audio_port_data *port;
607 	struct audio_client *ac;
608 	uint32_t client_event = 0;
609 	int ret = 0;
610 
611 	ac = q6asm_get_audio_client(q6asm, session_id);
612 	if (!ac)/* Audio client might already be freed by now */
613 		return 0;
614 
615 	result = data->payload;
616 
617 	switch (hdr->opcode) {
618 	case APR_BASIC_RSP_RESULT:
619 		switch (result->opcode) {
620 		case ASM_SESSION_CMD_PAUSE:
621 			client_event = ASM_CLIENT_EVENT_CMD_PAUSE_DONE;
622 			break;
623 		case ASM_SESSION_CMD_SUSPEND:
624 			client_event = ASM_CLIENT_EVENT_CMD_SUSPEND_DONE;
625 			break;
626 		case ASM_STREAM_CMD_FLUSH:
627 			client_event = ASM_CLIENT_EVENT_CMD_FLUSH_DONE;
628 			break;
629 		case ASM_SESSION_CMD_RUN_V2:
630 			client_event = ASM_CLIENT_EVENT_CMD_RUN_DONE;
631 			break;
632 		case ASM_STREAM_CMD_CLOSE:
633 			client_event = ASM_CLIENT_EVENT_CMD_CLOSE_DONE;
634 			break;
635 		case ASM_STREAM_CMD_FLUSH_READBUFS:
636 			client_event = ASM_CLIENT_EVENT_CMD_OUT_FLUSH_DONE;
637 			break;
638 		case ASM_STREAM_CMD_OPEN_WRITE_V3:
639 		case ASM_STREAM_CMD_OPEN_READ_V3:
640 		case ASM_STREAM_CMD_OPEN_READWRITE_V2:
641 		case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
642 		case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
643 			if (result->status != 0) {
644 				dev_err(ac->dev,
645 					"cmd = 0x%x returned error = 0x%x\n",
646 					result->opcode, result->status);
647 				ac->result = *result;
648 				wake_up(&ac->cmd_wait);
649 				ret = 0;
650 				goto done;
651 			}
652 			break;
653 		default:
654 			dev_err(ac->dev, "command[0x%x] not expecting rsp\n",
655 				result->opcode);
656 			break;
657 		}
658 
659 		ac->result = *result;
660 		wake_up(&ac->cmd_wait);
661 
662 		if (ac->cb)
663 			ac->cb(client_event, hdr->token,
664 			       data->payload, ac->priv);
665 
666 		ret = 0;
667 		goto done;
668 
669 	case ASM_DATA_EVENT_WRITE_DONE_V2:
670 		client_event = ASM_CLIENT_EVENT_DATA_WRITE_DONE;
671 		if (ac->io_mode & ASM_SYNC_IO_MODE) {
672 			phys_addr_t phys;
673 			unsigned long flags;
674 
675 			spin_lock_irqsave(&ac->lock, flags);
676 
677 			port =  &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
678 
679 			if (!port->buf) {
680 				spin_unlock_irqrestore(&ac->lock, flags);
681 				ret = 0;
682 				goto done;
683 			}
684 
685 			phys = port->buf[hdr->token].phys;
686 
687 			if (lower_32_bits(phys) != result->opcode ||
688 			    upper_32_bits(phys) != result->status) {
689 				dev_err(ac->dev, "Expected addr %pa\n",
690 					&port->buf[hdr->token].phys);
691 				spin_unlock_irqrestore(&ac->lock, flags);
692 				ret = -EINVAL;
693 				goto done;
694 			}
695 			spin_unlock_irqrestore(&ac->lock, flags);
696 		}
697 		break;
698 	case ASM_DATA_EVENT_READ_DONE_V2:
699 		client_event = ASM_CLIENT_EVENT_DATA_READ_DONE;
700 		if (ac->io_mode & ASM_SYNC_IO_MODE) {
701 			struct asm_data_cmd_read_v2_done *done = data->payload;
702 			unsigned long flags;
703 			phys_addr_t phys;
704 
705 			spin_lock_irqsave(&ac->lock, flags);
706 			port =  &ac->port[SNDRV_PCM_STREAM_CAPTURE];
707 			if (!port->buf) {
708 				spin_unlock_irqrestore(&ac->lock, flags);
709 				ret = 0;
710 				goto done;
711 			}
712 
713 			phys = port->buf[hdr->token].phys;
714 
715 			if (upper_32_bits(phys) != done->buf_addr_msw ||
716 			    lower_32_bits(phys) != done->buf_addr_lsw) {
717 				dev_err(ac->dev, "Expected addr %pa %08x-%08x\n",
718 					&port->buf[hdr->token].phys,
719 					done->buf_addr_lsw,
720 					done->buf_addr_msw);
721 				spin_unlock_irqrestore(&ac->lock, flags);
722 				ret = -EINVAL;
723 				goto done;
724 			}
725 			spin_unlock_irqrestore(&ac->lock, flags);
726 		}
727 
728 		break;
729 	case ASM_DATA_EVENT_RENDERED_EOS:
730 		client_event = ASM_CLIENT_EVENT_CMD_EOS_DONE;
731 		break;
732 	}
733 
734 	if (ac->cb)
735 		ac->cb(client_event, hdr->token, data->payload, ac->priv);
736 
737 done:
738 	kref_put(&ac->refcount, q6asm_audio_client_release);
739 	return ret;
740 }
741 
742 static int q6asm_srvc_callback(struct apr_device *adev,
743 			       struct apr_resp_pkt *data)
744 {
745 	struct q6asm *q6asm = dev_get_drvdata(&adev->dev);
746 	struct aprv2_ibasic_rsp_result_t *result;
747 	struct audio_port_data *port;
748 	struct audio_client *ac = NULL;
749 	struct apr_hdr *hdr = &data->hdr;
750 	struct q6asm *a;
751 	uint32_t sid = 0;
752 	uint32_t dir = 0;
753 	int session_id;
754 
755 	session_id = (hdr->dest_port >> 8) & 0xFF;
756 	if (session_id)
757 		return q6asm_stream_callback(adev, data, session_id);
758 
759 	sid = (hdr->token >> 8) & 0x0F;
760 	ac = q6asm_get_audio_client(q6asm, sid);
761 	if (!ac) {
762 		dev_err(&adev->dev, "Audio Client not active\n");
763 		return 0;
764 	}
765 
766 	a = dev_get_drvdata(ac->dev->parent);
767 	dir = (hdr->token & 0x0F);
768 	port = &ac->port[dir];
769 	result = data->payload;
770 
771 	switch (hdr->opcode) {
772 	case APR_BASIC_RSP_RESULT:
773 		switch (result->opcode) {
774 		case ASM_CMD_SHARED_MEM_MAP_REGIONS:
775 		case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:
776 			ac->result = *result;
777 			wake_up(&a->mem_wait);
778 			break;
779 		default:
780 			dev_err(&adev->dev, "command[0x%x] not expecting rsp\n",
781 				 result->opcode);
782 			break;
783 		}
784 		goto done;
785 	case ASM_CMDRSP_SHARED_MEM_MAP_REGIONS:
786 		ac->result.status = 0;
787 		ac->result.opcode = hdr->opcode;
788 		port->mem_map_handle = result->opcode;
789 		wake_up(&a->mem_wait);
790 		break;
791 	case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:
792 		ac->result.opcode = hdr->opcode;
793 		ac->result.status = 0;
794 		port->mem_map_handle = 0;
795 		wake_up(&a->mem_wait);
796 		break;
797 	default:
798 		dev_dbg(&adev->dev, "command[0x%x]success [0x%x]\n",
799 			result->opcode, result->status);
800 		break;
801 	}
802 
803 	if (ac->cb)
804 		ac->cb(hdr->opcode, hdr->token, data->payload, ac->priv);
805 
806 done:
807 	kref_put(&ac->refcount, q6asm_audio_client_release);
808 
809 	return 0;
810 }
811 
812 /**
813  * q6asm_get_session_id() - get session id for audio client
814  *
815  * @c: audio client pointer
816  *
817  * Return: Will be an session id of the audio client.
818  */
819 int q6asm_get_session_id(struct audio_client *c)
820 {
821 	return c->session;
822 }
823 EXPORT_SYMBOL_GPL(q6asm_get_session_id);
824 
825 /**
826  * q6asm_audio_client_alloc() - Allocate a new audio client
827  *
828  * @dev: Pointer to asm child device.
829  * @cb: event callback.
830  * @priv: private data associated with this client.
831  * @stream_id: stream id
832  * @perf_mode: performace mode for this client
833  *
834  * Return: Will be an error pointer on error or a valid audio client
835  * on success.
836  */
837 struct audio_client *q6asm_audio_client_alloc(struct device *dev, q6asm_cb cb,
838 					      void *priv, int stream_id,
839 					      int perf_mode)
840 {
841 	struct q6asm *a = dev_get_drvdata(dev->parent);
842 	struct audio_client *ac;
843 	unsigned long flags;
844 
845 	ac = q6asm_get_audio_client(a, stream_id + 1);
846 	if (ac) {
847 		dev_err(dev, "Audio Client already active\n");
848 		return ac;
849 	}
850 
851 	ac = kzalloc(sizeof(*ac), GFP_KERNEL);
852 	if (!ac)
853 		return ERR_PTR(-ENOMEM);
854 
855 	spin_lock_irqsave(&a->slock, flags);
856 	a->session[stream_id + 1] = ac;
857 	spin_unlock_irqrestore(&a->slock, flags);
858 	ac->session = stream_id + 1;
859 	ac->cb = cb;
860 	ac->dev = dev;
861 	ac->q6asm = a;
862 	ac->priv = priv;
863 	ac->io_mode = ASM_SYNC_IO_MODE;
864 	ac->perf_mode = perf_mode;
865 	/* DSP expects stream id from 1 */
866 	ac->stream_id = 1;
867 	ac->adev = a->adev;
868 	kref_init(&ac->refcount);
869 
870 	init_waitqueue_head(&ac->cmd_wait);
871 	mutex_init(&ac->cmd_lock);
872 	spin_lock_init(&ac->lock);
873 
874 	return ac;
875 }
876 EXPORT_SYMBOL_GPL(q6asm_audio_client_alloc);
877 
878 static int q6asm_ac_send_cmd_sync(struct audio_client *ac, struct apr_pkt *pkt)
879 {
880 	struct apr_hdr *hdr = &pkt->hdr;
881 	int rc;
882 
883 	mutex_lock(&ac->cmd_lock);
884 	ac->result.opcode = 0;
885 	ac->result.status = 0;
886 
887 	rc = apr_send_pkt(ac->adev, pkt);
888 	if (rc < 0)
889 		goto err;
890 
891 	rc = wait_event_timeout(ac->cmd_wait,
892 				(ac->result.opcode == hdr->opcode), 5 * HZ);
893 	if (!rc) {
894 		dev_err(ac->dev, "CMD timeout\n");
895 		rc =  -ETIMEDOUT;
896 		goto err;
897 	}
898 
899 	if (ac->result.status > 0) {
900 		dev_err(ac->dev, "DSP returned error[%x]\n",
901 			ac->result.status);
902 		rc = -EINVAL;
903 	} else {
904 		rc = 0;
905 	}
906 
907 
908 err:
909 	mutex_unlock(&ac->cmd_lock);
910 	return rc;
911 }
912 
913 /**
914  * q6asm_open_write() - Open audio client for writing
915  *
916  * @ac: audio client pointer
917  * @format: audio sample format
918  * @bits_per_sample: bits per sample
919  *
920  * Return: Will be an negative value on error or zero on success
921  */
922 int q6asm_open_write(struct audio_client *ac, uint32_t format,
923 		     u32 codec_profile, uint16_t bits_per_sample)
924 {
925 	struct asm_stream_cmd_open_write_v3 *open;
926 	struct apr_pkt *pkt;
927 	void *p;
928 	int rc, pkt_size;
929 
930 	pkt_size = APR_HDR_SIZE + sizeof(*open);
931 
932 	p = kzalloc(pkt_size, GFP_KERNEL);
933 	if (!p)
934 		return -ENOMEM;
935 
936 	pkt = p;
937 	open = p + APR_HDR_SIZE;
938 	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
939 
940 	pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
941 	open->mode_flags = 0x00;
942 	open->mode_flags |= ASM_LEGACY_STREAM_SESSION;
943 
944 	/* source endpoint : matrix */
945 	open->sink_endpointype = ASM_END_POINT_DEVICE_MATRIX;
946 	open->bits_per_sample = bits_per_sample;
947 	open->postprocopo_id = ASM_NULL_POPP_TOPOLOGY;
948 
949 	switch (format) {
950 	case SND_AUDIOCODEC_MP3:
951 		open->dec_fmt_id = ASM_MEDIA_FMT_MP3;
952 		break;
953 	case FORMAT_LINEAR_PCM:
954 		open->dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
955 		break;
956 	case SND_AUDIOCODEC_FLAC:
957 		open->dec_fmt_id = ASM_MEDIA_FMT_FLAC;
958 		break;
959 	case SND_AUDIOCODEC_WMA:
960 		switch (codec_profile) {
961 		case SND_AUDIOPROFILE_WMA9:
962 			open->dec_fmt_id = ASM_MEDIA_FMT_WMA_V9;
963 			break;
964 		case SND_AUDIOPROFILE_WMA10:
965 		case SND_AUDIOPROFILE_WMA9_PRO:
966 		case SND_AUDIOPROFILE_WMA9_LOSSLESS:
967 		case SND_AUDIOPROFILE_WMA10_LOSSLESS:
968 			open->dec_fmt_id = ASM_MEDIA_FMT_WMA_V10;
969 			break;
970 		default:
971 			dev_err(ac->dev, "Invalid codec profile 0x%x\n",
972 				codec_profile);
973 			rc = -EINVAL;
974 			goto err;
975 		}
976 		break;
977 	case SND_AUDIOCODEC_ALAC:
978 		open->dec_fmt_id = ASM_MEDIA_FMT_ALAC;
979 		break;
980 	case SND_AUDIOCODEC_APE:
981 		open->dec_fmt_id = ASM_MEDIA_FMT_APE;
982 		break;
983 	default:
984 		dev_err(ac->dev, "Invalid format 0x%x\n", format);
985 		rc = -EINVAL;
986 		goto err;
987 	}
988 
989 	rc = q6asm_ac_send_cmd_sync(ac, pkt);
990 	if (rc < 0)
991 		goto err;
992 
993 	ac->io_mode |= ASM_TUN_WRITE_IO_MODE;
994 
995 err:
996 	kfree(pkt);
997 	return rc;
998 }
999 EXPORT_SYMBOL_GPL(q6asm_open_write);
1000 
1001 static int __q6asm_run(struct audio_client *ac, uint32_t flags,
1002 	      uint32_t msw_ts, uint32_t lsw_ts, bool wait)
1003 {
1004 	struct asm_session_cmd_run_v2 *run;
1005 	struct apr_pkt *pkt;
1006 	int pkt_size, rc;
1007 	void *p;
1008 
1009 	pkt_size = APR_HDR_SIZE + sizeof(*run);
1010 	p = kzalloc(pkt_size, GFP_ATOMIC);
1011 	if (!p)
1012 		return -ENOMEM;
1013 
1014 	pkt = p;
1015 	run = p + APR_HDR_SIZE;
1016 
1017 	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
1018 
1019 	pkt->hdr.opcode = ASM_SESSION_CMD_RUN_V2;
1020 	run->flags = flags;
1021 	run->time_lsw = lsw_ts;
1022 	run->time_msw = msw_ts;
1023 	if (wait) {
1024 		rc = q6asm_ac_send_cmd_sync(ac, pkt);
1025 	} else {
1026 		rc = apr_send_pkt(ac->adev, pkt);
1027 		if (rc == pkt_size)
1028 			rc = 0;
1029 	}
1030 
1031 	kfree(pkt);
1032 	return rc;
1033 }
1034 
1035 /**
1036  * q6asm_run() - start the audio client
1037  *
1038  * @ac: audio client pointer
1039  * @flags: flags associated with write
1040  * @msw_ts: timestamp msw
1041  * @lsw_ts: timestamp lsw
1042  *
1043  * Return: Will be an negative value on error or zero on success
1044  */
1045 int q6asm_run(struct audio_client *ac, uint32_t flags,
1046 	      uint32_t msw_ts, uint32_t lsw_ts)
1047 {
1048 	return __q6asm_run(ac, flags, msw_ts, lsw_ts, true);
1049 }
1050 EXPORT_SYMBOL_GPL(q6asm_run);
1051 
1052 /**
1053  * q6asm_run_nowait() - start the audio client withou blocking
1054  *
1055  * @ac: audio client pointer
1056  * @flags: flags associated with write
1057  * @msw_ts: timestamp msw
1058  * @lsw_ts: timestamp lsw
1059  *
1060  * Return: Will be an negative value on error or zero on success
1061  */
1062 int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
1063 	      uint32_t msw_ts, uint32_t lsw_ts)
1064 {
1065 	return __q6asm_run(ac, flags, msw_ts, lsw_ts, false);
1066 }
1067 EXPORT_SYMBOL_GPL(q6asm_run_nowait);
1068 
1069 /**
1070  * q6asm_media_format_block_multi_ch_pcm() - setup pcm configuration
1071  *
1072  * @ac: audio client pointer
1073  * @rate: audio sample rate
1074  * @channels: number of audio channels.
1075  * @channel_map: channel map pointer
1076  * @bits_per_sample: bits per sample
1077  *
1078  * Return: Will be an negative value on error or zero on success
1079  */
1080 int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
1081 					  uint32_t rate, uint32_t channels,
1082 					  u8 channel_map[PCM_MAX_NUM_CHANNEL],
1083 					  uint16_t bits_per_sample)
1084 {
1085 	struct asm_multi_channel_pcm_fmt_blk_v2 *fmt;
1086 	struct apr_pkt *pkt;
1087 	u8 *channel_mapping;
1088 	void *p;
1089 	int rc, pkt_size;
1090 
1091 	pkt_size = APR_HDR_SIZE + sizeof(*fmt);
1092 	p = kzalloc(pkt_size, GFP_KERNEL);
1093 	if (!p)
1094 		return -ENOMEM;
1095 
1096 	pkt = p;
1097 	fmt = p + APR_HDR_SIZE;
1098 
1099 	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
1100 
1101 	pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
1102 	fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
1103 	fmt->num_channels = channels;
1104 	fmt->bits_per_sample = bits_per_sample;
1105 	fmt->sample_rate = rate;
1106 	fmt->is_signed = 1;
1107 
1108 	channel_mapping = fmt->channel_mapping;
1109 
1110 	if (channel_map) {
1111 		memcpy(channel_mapping, channel_map, PCM_MAX_NUM_CHANNEL);
1112 	} else {
1113 		if (q6dsp_map_channels(channel_mapping, channels)) {
1114 			dev_err(ac->dev, " map channels failed %d\n", channels);
1115 			rc = -EINVAL;
1116 			goto err;
1117 		}
1118 	}
1119 
1120 	rc = q6asm_ac_send_cmd_sync(ac, pkt);
1121 
1122 err:
1123 	kfree(pkt);
1124 	return rc;
1125 }
1126 EXPORT_SYMBOL_GPL(q6asm_media_format_block_multi_ch_pcm);
1127 
1128 
1129 int q6asm_stream_media_format_block_flac(struct audio_client *ac,
1130 					 struct q6asm_flac_cfg *cfg)
1131 {
1132 	struct asm_flac_fmt_blk_v2 *fmt;
1133 	struct apr_pkt *pkt;
1134 	void *p;
1135 	int rc, pkt_size;
1136 
1137 	pkt_size = APR_HDR_SIZE + sizeof(*fmt);
1138 	p = kzalloc(pkt_size, GFP_KERNEL);
1139 	if (!p)
1140 		return -ENOMEM;
1141 
1142 	pkt = p;
1143 	fmt = p + APR_HDR_SIZE;
1144 
1145 	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
1146 
1147 	pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
1148 	fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
1149 	fmt->is_stream_info_present = cfg->stream_info_present;
1150 	fmt->num_channels = cfg->ch_cfg;
1151 	fmt->min_blk_size = cfg->min_blk_size;
1152 	fmt->max_blk_size = cfg->max_blk_size;
1153 	fmt->sample_rate = cfg->sample_rate;
1154 	fmt->min_frame_size = cfg->min_frame_size;
1155 	fmt->max_frame_size = cfg->max_frame_size;
1156 	fmt->sample_size = cfg->sample_size;
1157 
1158 	rc = q6asm_ac_send_cmd_sync(ac, pkt);
1159 	kfree(pkt);
1160 
1161 	return rc;
1162 }
1163 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_flac);
1164 
1165 int q6asm_stream_media_format_block_wma_v9(struct audio_client *ac,
1166 					   struct q6asm_wma_cfg *cfg)
1167 {
1168 	struct asm_wmastdv9_fmt_blk_v2 *fmt;
1169 	struct apr_pkt *pkt;
1170 	void *p;
1171 	int rc, pkt_size;
1172 
1173 	pkt_size = APR_HDR_SIZE + sizeof(*fmt);
1174 	p = kzalloc(pkt_size, GFP_KERNEL);
1175 	if (!p)
1176 		return -ENOMEM;
1177 
1178 	pkt = p;
1179 	fmt = p + APR_HDR_SIZE;
1180 
1181 	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
1182 
1183 	pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
1184 	fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
1185 	fmt->fmtag = cfg->fmtag;
1186 	fmt->num_channels = cfg->num_channels;
1187 	fmt->sample_rate = cfg->sample_rate;
1188 	fmt->bytes_per_sec = cfg->bytes_per_sec;
1189 	fmt->blk_align = cfg->block_align;
1190 	fmt->bits_per_sample = cfg->bits_per_sample;
1191 	fmt->channel_mask = cfg->channel_mask;
1192 	fmt->enc_options = cfg->enc_options;
1193 	fmt->reserved = 0;
1194 
1195 	rc = q6asm_ac_send_cmd_sync(ac, pkt);
1196 	kfree(pkt);
1197 
1198 	return rc;
1199 }
1200 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_wma_v9);
1201 
1202 int q6asm_stream_media_format_block_wma_v10(struct audio_client *ac,
1203 					    struct q6asm_wma_cfg *cfg)
1204 {
1205 	struct asm_wmaprov10_fmt_blk_v2 *fmt;
1206 	struct apr_pkt *pkt;
1207 	void *p;
1208 	int rc, pkt_size;
1209 
1210 	pkt_size = APR_HDR_SIZE + sizeof(*fmt);
1211 	p = kzalloc(pkt_size, GFP_KERNEL);
1212 	if (!p)
1213 		return -ENOMEM;
1214 
1215 	pkt = p;
1216 	fmt = p + APR_HDR_SIZE;
1217 
1218 	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
1219 
1220 	pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
1221 	fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
1222 	fmt->fmtag = cfg->fmtag;
1223 	fmt->num_channels = cfg->num_channels;
1224 	fmt->sample_rate = cfg->sample_rate;
1225 	fmt->bytes_per_sec = cfg->bytes_per_sec;
1226 	fmt->blk_align = cfg->block_align;
1227 	fmt->bits_per_sample = cfg->bits_per_sample;
1228 	fmt->channel_mask = cfg->channel_mask;
1229 	fmt->enc_options = cfg->enc_options;
1230 	fmt->advanced_enc_options1 = cfg->adv_enc_options;
1231 	fmt->advanced_enc_options2 = cfg->adv_enc_options2;
1232 
1233 	rc = q6asm_ac_send_cmd_sync(ac, pkt);
1234 	kfree(pkt);
1235 
1236 	return rc;
1237 }
1238 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_wma_v10);
1239 
1240 int q6asm_stream_media_format_block_alac(struct audio_client *ac,
1241 					 struct q6asm_alac_cfg *cfg)
1242 {
1243 	struct asm_alac_fmt_blk_v2 *fmt;
1244 	struct apr_pkt *pkt;
1245 	void *p;
1246 	int rc, pkt_size;
1247 
1248 	pkt_size = APR_HDR_SIZE + sizeof(*fmt);
1249 	p = kzalloc(pkt_size, GFP_KERNEL);
1250 	if (!p)
1251 		return -ENOMEM;
1252 
1253 	pkt = p;
1254 	fmt = p + APR_HDR_SIZE;
1255 
1256 	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
1257 
1258 	pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
1259 	fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
1260 
1261 	fmt->frame_length = cfg->frame_length;
1262 	fmt->compatible_version = cfg->compatible_version;
1263 	fmt->bit_depth =  cfg->bit_depth;
1264 	fmt->num_channels = cfg->num_channels;
1265 	fmt->max_run = cfg->max_run;
1266 	fmt->max_frame_bytes = cfg->max_frame_bytes;
1267 	fmt->avg_bit_rate = cfg->avg_bit_rate;
1268 	fmt->sample_rate = cfg->sample_rate;
1269 	fmt->channel_layout_tag = cfg->channel_layout_tag;
1270 	fmt->pb = cfg->pb;
1271 	fmt->mb = cfg->mb;
1272 	fmt->kb = cfg->kb;
1273 
1274 	rc = q6asm_ac_send_cmd_sync(ac, pkt);
1275 	kfree(pkt);
1276 
1277 	return rc;
1278 }
1279 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_alac);
1280 
1281 int q6asm_stream_media_format_block_ape(struct audio_client *ac,
1282 					struct q6asm_ape_cfg *cfg)
1283 {
1284 	struct asm_ape_fmt_blk_v2 *fmt;
1285 	struct apr_pkt *pkt;
1286 	void *p;
1287 	int rc, pkt_size;
1288 
1289 	pkt_size = APR_HDR_SIZE + sizeof(*fmt);
1290 	p = kzalloc(pkt_size, GFP_KERNEL);
1291 	if (!p)
1292 		return -ENOMEM;
1293 
1294 	pkt = p;
1295 	fmt = p + APR_HDR_SIZE;
1296 
1297 	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
1298 
1299 	pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
1300 	fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
1301 
1302 	fmt->compatible_version = cfg->compatible_version;
1303 	fmt->compression_level = cfg->compression_level;
1304 	fmt->format_flags = cfg->format_flags;
1305 	fmt->blocks_per_frame = cfg->blocks_per_frame;
1306 	fmt->final_frame_blocks = cfg->final_frame_blocks;
1307 	fmt->total_frames = cfg->total_frames;
1308 	fmt->bits_per_sample = cfg->bits_per_sample;
1309 	fmt->num_channels = cfg->num_channels;
1310 	fmt->sample_rate = cfg->sample_rate;
1311 	fmt->seek_table_present = cfg->seek_table_present;
1312 
1313 	rc = q6asm_ac_send_cmd_sync(ac, pkt);
1314 	kfree(pkt);
1315 
1316 	return rc;
1317 }
1318 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_ape);
1319 
1320 /**
1321  * q6asm_enc_cfg_blk_pcm_format_support() - setup pcm configuration for capture
1322  *
1323  * @ac: audio client pointer
1324  * @rate: audio sample rate
1325  * @channels: number of audio channels.
1326  * @bits_per_sample: bits per sample
1327  *
1328  * Return: Will be an negative value on error or zero on success
1329  */
1330 int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
1331 		uint32_t rate, uint32_t channels, uint16_t bits_per_sample)
1332 {
1333 	struct asm_multi_channel_pcm_enc_cfg_v2  *enc_cfg;
1334 	struct apr_pkt *pkt;
1335 	u8 *channel_mapping;
1336 	u32 frames_per_buf = 0;
1337 	int pkt_size, rc;
1338 	void *p;
1339 
1340 	pkt_size = APR_HDR_SIZE + sizeof(*enc_cfg);
1341 	p = kzalloc(pkt_size, GFP_KERNEL);
1342 	if (!p)
1343 		return -ENOMEM;
1344 
1345 	pkt = p;
1346 	enc_cfg = p + APR_HDR_SIZE;
1347 	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
1348 
1349 	pkt->hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
1350 	enc_cfg->encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
1351 	enc_cfg->encdec.param_size = sizeof(*enc_cfg) - sizeof(enc_cfg->encdec);
1352 	enc_cfg->encblk.frames_per_buf = frames_per_buf;
1353 	enc_cfg->encblk.enc_cfg_blk_size  = enc_cfg->encdec.param_size -
1354 					sizeof(struct asm_enc_cfg_blk_param_v2);
1355 
1356 	enc_cfg->num_channels = channels;
1357 	enc_cfg->bits_per_sample = bits_per_sample;
1358 	enc_cfg->sample_rate = rate;
1359 	enc_cfg->is_signed = 1;
1360 	channel_mapping = enc_cfg->channel_mapping;
1361 
1362 	if (q6dsp_map_channels(channel_mapping, channels)) {
1363 		rc = -EINVAL;
1364 		goto err;
1365 	}
1366 
1367 	rc = q6asm_ac_send_cmd_sync(ac, pkt);
1368 err:
1369 	kfree(pkt);
1370 	return rc;
1371 }
1372 EXPORT_SYMBOL_GPL(q6asm_enc_cfg_blk_pcm_format_support);
1373 
1374 
1375 /**
1376  * q6asm_read() - read data of period size from audio client
1377  *
1378  * @ac: audio client pointer
1379  *
1380  * Return: Will be an negative value on error or zero on success
1381  */
1382 int q6asm_read(struct audio_client *ac)
1383 {
1384 	struct asm_data_cmd_read_v2 *read;
1385 	struct audio_port_data *port;
1386 	struct audio_buffer *ab;
1387 	struct apr_pkt *pkt;
1388 	unsigned long flags;
1389 	int pkt_size;
1390 	int rc = 0;
1391 	void *p;
1392 
1393 	pkt_size = APR_HDR_SIZE + sizeof(*read);
1394 	p = kzalloc(pkt_size, GFP_ATOMIC);
1395 	if (!p)
1396 		return -ENOMEM;
1397 
1398 	pkt = p;
1399 	read = p + APR_HDR_SIZE;
1400 
1401 	spin_lock_irqsave(&ac->lock, flags);
1402 	port = &ac->port[SNDRV_PCM_STREAM_CAPTURE];
1403 	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, ac->stream_id);
1404 	ab = &port->buf[port->dsp_buf];
1405 	pkt->hdr.opcode = ASM_DATA_CMD_READ_V2;
1406 	read->buf_addr_lsw = lower_32_bits(ab->phys);
1407 	read->buf_addr_msw = upper_32_bits(ab->phys);
1408 	read->mem_map_handle = port->mem_map_handle;
1409 
1410 	read->buf_size = ab->size;
1411 	read->seq_id = port->dsp_buf;
1412 	pkt->hdr.token = port->dsp_buf;
1413 
1414 	port->dsp_buf++;
1415 
1416 	if (port->dsp_buf >= port->num_periods)
1417 		port->dsp_buf = 0;
1418 
1419 	spin_unlock_irqrestore(&ac->lock, flags);
1420 	rc = apr_send_pkt(ac->adev, pkt);
1421 	if (rc == pkt_size)
1422 		rc = 0;
1423 	else
1424 		pr_err("read op[0x%x]rc[%d]\n", pkt->hdr.opcode, rc);
1425 
1426 	kfree(pkt);
1427 	return rc;
1428 }
1429 EXPORT_SYMBOL_GPL(q6asm_read);
1430 
1431 static int __q6asm_open_read(struct audio_client *ac,
1432 		uint32_t format, uint16_t bits_per_sample)
1433 {
1434 	struct asm_stream_cmd_open_read_v3 *open;
1435 	struct apr_pkt *pkt;
1436 	int pkt_size, rc;
1437 	void *p;
1438 
1439 	pkt_size = APR_HDR_SIZE + sizeof(*open);
1440 	p = kzalloc(pkt_size, GFP_KERNEL);
1441 	if (!p)
1442 		return -ENOMEM;
1443 
1444 	pkt = p;
1445 	open = p + APR_HDR_SIZE;
1446 
1447 	q6asm_add_hdr(ac, &pkt->hdr,  pkt_size, true, ac->stream_id);
1448 	pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V3;
1449 	/* Stream prio : High, provide meta info with encoded frames */
1450 	open->src_endpointype = ASM_END_POINT_DEVICE_MATRIX;
1451 
1452 	open->preprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE;
1453 	open->bits_per_sample = bits_per_sample;
1454 	open->mode_flags = 0x0;
1455 
1456 	open->mode_flags |= ASM_LEGACY_STREAM_SESSION <<
1457 				ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
1458 
1459 	switch (format) {
1460 	case FORMAT_LINEAR_PCM:
1461 		open->mode_flags |= 0x00;
1462 		open->enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
1463 		break;
1464 	default:
1465 		pr_err("Invalid format[%d]\n", format);
1466 	}
1467 
1468 	rc = q6asm_ac_send_cmd_sync(ac, pkt);
1469 
1470 	kfree(pkt);
1471 	return rc;
1472 }
1473 
1474 /**
1475  * q6asm_open_read() - Open audio client for reading
1476  *
1477  * @ac: audio client pointer
1478  * @format: audio sample format
1479  * @bits_per_sample: bits per sample
1480  *
1481  * Return: Will be an negative value on error or zero on success
1482  */
1483 int q6asm_open_read(struct audio_client *ac, uint32_t format,
1484 			uint16_t bits_per_sample)
1485 {
1486 	return __q6asm_open_read(ac, format, bits_per_sample);
1487 }
1488 EXPORT_SYMBOL_GPL(q6asm_open_read);
1489 
1490 /**
1491  * q6asm_write_async() - non blocking write
1492  *
1493  * @ac: audio client pointer
1494  * @len: length in bytes
1495  * @msw_ts: timestamp msw
1496  * @lsw_ts: timestamp lsw
1497  * @wflags: flags associated with write
1498  *
1499  * Return: Will be an negative value on error or zero on success
1500  */
1501 int q6asm_write_async(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
1502 		       uint32_t lsw_ts, uint32_t wflags)
1503 {
1504 	struct asm_data_cmd_write_v2 *write;
1505 	struct audio_port_data *port;
1506 	struct audio_buffer *ab;
1507 	unsigned long flags;
1508 	struct apr_pkt *pkt;
1509 	int pkt_size;
1510 	int rc = 0;
1511 	void *p;
1512 
1513 	pkt_size = APR_HDR_SIZE + sizeof(*write);
1514 	p = kzalloc(pkt_size, GFP_ATOMIC);
1515 	if (!p)
1516 		return -ENOMEM;
1517 
1518 	pkt = p;
1519 	write = p + APR_HDR_SIZE;
1520 
1521 	spin_lock_irqsave(&ac->lock, flags);
1522 	port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
1523 	q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, ac->stream_id);
1524 
1525 	ab = &port->buf[port->dsp_buf];
1526 	pkt->hdr.token = port->dsp_buf;
1527 	pkt->hdr.opcode = ASM_DATA_CMD_WRITE_V2;
1528 	write->buf_addr_lsw = lower_32_bits(ab->phys);
1529 	write->buf_addr_msw = upper_32_bits(ab->phys);
1530 	write->buf_size = len;
1531 	write->seq_id = port->dsp_buf;
1532 	write->timestamp_lsw = lsw_ts;
1533 	write->timestamp_msw = msw_ts;
1534 	write->mem_map_handle =
1535 	    ac->port[SNDRV_PCM_STREAM_PLAYBACK].mem_map_handle;
1536 
1537 	if (wflags == NO_TIMESTAMP)
1538 		write->flags = (wflags & 0x800000FF);
1539 	else
1540 		write->flags = (0x80000000 | wflags);
1541 
1542 	port->dsp_buf++;
1543 
1544 	if (port->dsp_buf >= port->num_periods)
1545 		port->dsp_buf = 0;
1546 
1547 	spin_unlock_irqrestore(&ac->lock, flags);
1548 	rc = apr_send_pkt(ac->adev, pkt);
1549 	if (rc == pkt_size)
1550 		rc = 0;
1551 
1552 	kfree(pkt);
1553 	return rc;
1554 }
1555 EXPORT_SYMBOL_GPL(q6asm_write_async);
1556 
1557 static void q6asm_reset_buf_state(struct audio_client *ac)
1558 {
1559 	struct audio_port_data *port = NULL;
1560 	unsigned long flags;
1561 
1562 	spin_lock_irqsave(&ac->lock, flags);
1563 	port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
1564 	port->dsp_buf = 0;
1565 	port = &ac->port[SNDRV_PCM_STREAM_CAPTURE];
1566 	port->dsp_buf = 0;
1567 	spin_unlock_irqrestore(&ac->lock, flags);
1568 }
1569 
1570 static int __q6asm_cmd(struct audio_client *ac, int cmd, bool wait)
1571 {
1572 	int stream_id = ac->stream_id;
1573 	struct apr_pkt pkt;
1574 	int rc;
1575 
1576 	q6asm_add_hdr(ac, &pkt.hdr, APR_HDR_SIZE, true, stream_id);
1577 
1578 	switch (cmd) {
1579 	case CMD_PAUSE:
1580 		pkt.hdr.opcode = ASM_SESSION_CMD_PAUSE;
1581 		break;
1582 	case CMD_SUSPEND:
1583 		pkt.hdr.opcode = ASM_SESSION_CMD_SUSPEND;
1584 		break;
1585 	case CMD_FLUSH:
1586 		pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH;
1587 		break;
1588 	case CMD_OUT_FLUSH:
1589 		pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH_READBUFS;
1590 		break;
1591 	case CMD_EOS:
1592 		pkt.hdr.opcode = ASM_DATA_CMD_EOS;
1593 		break;
1594 	case CMD_CLOSE:
1595 		pkt.hdr.opcode = ASM_STREAM_CMD_CLOSE;
1596 		break;
1597 	default:
1598 		return -EINVAL;
1599 	}
1600 
1601 	if (wait)
1602 		rc = q6asm_ac_send_cmd_sync(ac, &pkt);
1603 	else
1604 		return apr_send_pkt(ac->adev, &pkt);
1605 
1606 	if (rc < 0)
1607 		return rc;
1608 
1609 	if (cmd == CMD_FLUSH)
1610 		q6asm_reset_buf_state(ac);
1611 
1612 	return 0;
1613 }
1614 
1615 /**
1616  * q6asm_cmd() - run cmd on audio client
1617  *
1618  * @ac: audio client pointer
1619  * @cmd: command to run on audio client.
1620  *
1621  * Return: Will be an negative value on error or zero on success
1622  */
1623 int q6asm_cmd(struct audio_client *ac, int cmd)
1624 {
1625 	return __q6asm_cmd(ac, cmd, true);
1626 }
1627 EXPORT_SYMBOL_GPL(q6asm_cmd);
1628 
1629 /**
1630  * q6asm_cmd_nowait() - non blocking, run cmd on audio client
1631  *
1632  * @ac: audio client pointer
1633  * @cmd: command to run on audio client.
1634  *
1635  * Return: Will be an negative value on error or zero on success
1636  */
1637 int q6asm_cmd_nowait(struct audio_client *ac, int cmd)
1638 {
1639 	return __q6asm_cmd(ac, cmd, false);
1640 }
1641 EXPORT_SYMBOL_GPL(q6asm_cmd_nowait);
1642 
1643 static int q6asm_probe(struct apr_device *adev)
1644 {
1645 	struct device *dev = &adev->dev;
1646 	struct q6asm *q6asm;
1647 
1648 	q6asm = devm_kzalloc(dev, sizeof(*q6asm), GFP_KERNEL);
1649 	if (!q6asm)
1650 		return -ENOMEM;
1651 
1652 	q6core_get_svc_api_info(adev->svc_id, &q6asm->ainfo);
1653 
1654 	q6asm->dev = dev;
1655 	q6asm->adev = adev;
1656 	init_waitqueue_head(&q6asm->mem_wait);
1657 	spin_lock_init(&q6asm->slock);
1658 	dev_set_drvdata(dev, q6asm);
1659 
1660 	return of_platform_populate(dev->of_node, NULL, NULL, dev);
1661 }
1662 
1663 static int q6asm_remove(struct apr_device *adev)
1664 {
1665 	of_platform_depopulate(&adev->dev);
1666 
1667 	return 0;
1668 }
1669 static const struct of_device_id q6asm_device_id[]  = {
1670 	{ .compatible = "qcom,q6asm" },
1671 	{},
1672 };
1673 MODULE_DEVICE_TABLE(of, q6asm_device_id);
1674 
1675 static struct apr_driver qcom_q6asm_driver = {
1676 	.probe = q6asm_probe,
1677 	.remove = q6asm_remove,
1678 	.callback = q6asm_srvc_callback,
1679 	.driver = {
1680 		.name = "qcom-q6asm",
1681 		.of_match_table = of_match_ptr(q6asm_device_id),
1682 	},
1683 };
1684 
1685 module_apr_driver(qcom_q6asm_driver);
1686 MODULE_DESCRIPTION("Q6 Audio Stream Manager driver");
1687 MODULE_LICENSE("GPL v2");
1688