blob: f25255c5215f1ebb95d216d7f5229500a280b930 [file] [log] [blame]
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301/*
Meng Wangb6afa8c2017-11-30 17:55:05 +08002 * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303 * Author: Brian Swetland <swetland@google.com>
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 */
15#include <linux/fs.h>
16#include <linux/mutex.h>
17#include <linux/wait.h>
18#include <linux/miscdevice.h>
19#include <linux/uaccess.h>
20#include <linux/sched.h>
21#include <linux/dma-mapping.h>
22#include <linux/miscdevice.h>
23#include <linux/delay.h>
24#include <linux/slab.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053025
26#include <linux/debugfs.h>
27#include <linux/time.h>
28#include <linux/atomic.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053029#include <linux/mm.h>
30
31#include <asm/ioctls.h>
32
33#include <linux/memory.h>
34
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053035#include <sound/compress_params.h>
36
Laxminath Kasam605b42f2017-08-01 22:02:15 +053037#include <dsp/msm_audio_ion.h>
38#include <dsp/apr_audio-v2.h>
39#include <dsp/audio_cal_utils.h>
40#include <dsp/q6asm-v2.h>
41#include <dsp/q6audio-v2.h>
42#include "adsp_err.h"
43
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053044#define TRUE 0x01
45#define FALSE 0x00
46#define SESSION_MAX 8
47
48enum {
49 ASM_TOPOLOGY_CAL = 0,
50 ASM_CUSTOM_TOP_CAL,
51 ASM_AUDSTRM_CAL,
52 ASM_RTAC_APR_CAL,
53 ASM_MAX_CAL_TYPES
54};
55
56union asm_token_struct {
57 struct {
58 u8 stream_id;
59 u8 session_id;
60 u8 buf_index;
61 u8 flags;
62 } _token;
63 u32 token;
64} __packed;
65
66
67enum {
68 ASM_DIRECTION_OFFSET,
69 ASM_CMD_NO_WAIT_OFFSET,
70 /*
71 * Offset is limited to 7 because flags is stored in u8
72 * field in asm_token_structure defined above. The offset
73 * starts from 0.
74 */
75 ASM_MAX_OFFSET = 7,
76};
77
78enum {
79 WAIT_CMD,
80 NO_WAIT_CMD
81};
82
83#define ASM_SET_BIT(n, x) (n |= 1 << x)
84#define ASM_TEST_BIT(n, x) ((n >> x) & 1)
85
86/* TODO, combine them together */
87static DEFINE_MUTEX(session_lock);
88struct asm_mmap {
89 atomic_t ref_cnt;
90 void *apr;
91};
92
93static struct asm_mmap this_mmap;
Meng Wang9730cdd2017-09-26 12:48:31 +080094
95struct audio_session {
96 struct audio_client *ac;
97 spinlock_t session_lock;
98};
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053099/* session id: 0 reserved */
Meng Wang9730cdd2017-09-26 12:48:31 +0800100static struct audio_session session[ASM_ACTIVE_STREAMS_ALLOWED + 1];
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530101
102struct asm_buffer_node {
103 struct list_head list;
104 phys_addr_t buf_phys_addr;
105 uint32_t mmap_hdl;
106};
107static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv);
108static int32_t q6asm_callback(struct apr_client_data *data, void *priv);
109static void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
110 uint32_t pkt_size, uint32_t cmd_flg);
111static void q6asm_add_hdr_custom_topology(struct audio_client *ac,
112 struct apr_hdr *hdr,
113 uint32_t pkt_size);
114static void q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
115 uint32_t pkt_size, uint32_t cmd_flg);
116static int q6asm_memory_map_regions(struct audio_client *ac, int dir,
117 uint32_t bufsz, uint32_t bufcnt,
118 bool is_contiguous);
119static int q6asm_memory_unmap_regions(struct audio_client *ac, int dir);
120static void q6asm_reset_buf_state(struct audio_client *ac);
121
122static int q6asm_map_channels(u8 *channel_mapping, uint32_t channels,
123 bool use_back_flavor);
124void *q6asm_mmap_apr_reg(void);
125
126static int q6asm_is_valid_session(struct apr_client_data *data, void *priv);
127static int q6asm_get_asm_topology_cal(void);
128static int q6asm_get_asm_app_type_cal(void);
129
130/* for ASM custom topology */
131static struct cal_type_data *cal_data[ASM_MAX_CAL_TYPES];
132static struct audio_buffer common_buf[2];
133static struct audio_client common_client;
134static int set_custom_topology;
135static int topology_map_handle;
136
137struct generic_get_data_ {
138 int valid;
139 int is_inband;
140 int size_in_ints;
141 int ints[];
142};
143static struct generic_get_data_ *generic_get_data;
144
145#ifdef CONFIG_DEBUG_FS
146#define OUT_BUFFER_SIZE 56
147#define IN_BUFFER_SIZE 24
148
149static struct timeval out_cold_tv;
150static struct timeval out_warm_tv;
151static struct timeval out_cont_tv;
152static struct timeval in_cont_tv;
153static long out_enable_flag;
154static long in_enable_flag;
155static struct dentry *out_dentry;
156static struct dentry *in_dentry;
157static int in_cont_index;
158/*This var is used to keep track of first write done for cold output latency */
159static int out_cold_index;
160static char *out_buffer;
161static char *in_buffer;
162
163static uint32_t adsp_reg_event_opcode[] = {
164 ASM_STREAM_CMD_REGISTER_PP_EVENTS,
165 ASM_STREAM_CMD_REGISTER_ENCDEC_EVENTS,
166 ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE };
167
168static uint32_t adsp_raise_event_opcode[] = {
169 ASM_STREAM_PP_EVENT,
170 ASM_STREAM_CMD_ENCDEC_EVENTS,
171 ASM_IEC_61937_MEDIA_FMT_EVENT };
172
173static int is_adsp_reg_event(uint32_t cmd)
174{
175 int i;
176
177 for (i = 0; i < ARRAY_SIZE(adsp_reg_event_opcode); i++) {
178 if (cmd == adsp_reg_event_opcode[i])
179 return i;
180 }
181 return -EINVAL;
182}
183
184static int is_adsp_raise_event(uint32_t cmd)
185{
186 int i;
187
188 for (i = 0; i < ARRAY_SIZE(adsp_raise_event_opcode); i++) {
189 if (cmd == adsp_raise_event_opcode[i])
190 return i;
191 }
192 return -EINVAL;
193}
194
195static inline void q6asm_set_flag_in_token(union asm_token_struct *asm_token,
196 int flag, int flag_offset)
197{
198 if (flag)
199 ASM_SET_BIT(asm_token->_token.flags, flag_offset);
200}
201
202static inline int q6asm_get_flag_from_token(union asm_token_struct *asm_token,
203 int flag_offset)
204{
205 return ASM_TEST_BIT(asm_token->_token.flags, flag_offset);
206}
207
208static inline void q6asm_update_token(u32 *token, u8 session_id, u8 stream_id,
209 u8 buf_index, u8 dir, u8 nowait_flag)
210{
211 union asm_token_struct asm_token;
212
213 asm_token.token = 0;
214 asm_token._token.session_id = session_id;
215 asm_token._token.stream_id = stream_id;
216 asm_token._token.buf_index = buf_index;
217 q6asm_set_flag_in_token(&asm_token, dir, ASM_DIRECTION_OFFSET);
218 q6asm_set_flag_in_token(&asm_token, nowait_flag,
219 ASM_CMD_NO_WAIT_OFFSET);
220 *token = asm_token.token;
221}
222
223static inline uint32_t q6asm_get_pcm_format_id(uint32_t media_format_block_ver)
224{
225 uint32_t pcm_format_id;
226
227 switch (media_format_block_ver) {
228 case PCM_MEDIA_FORMAT_V4:
229 pcm_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V4;
230 break;
231 case PCM_MEDIA_FORMAT_V3:
232 pcm_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3;
233 break;
234 case PCM_MEDIA_FORMAT_V2:
235 default:
236 pcm_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
237 break;
238 }
239 return pcm_format_id;
240}
241
242/*
243 * q6asm_get_buf_index_from_token:
244 * Retrieve buffer index from token.
245 *
246 * @token: token value sent to ASM service on q6.
247 * Returns buffer index in the read/write commands.
248 */
249uint8_t q6asm_get_buf_index_from_token(uint32_t token)
250{
251 union asm_token_struct asm_token;
252
253 asm_token.token = token;
254 return asm_token._token.buf_index;
255}
256EXPORT_SYMBOL(q6asm_get_buf_index_from_token);
257
258/*
259 * q6asm_get_stream_id_from_token:
260 * Retrieve stream id from token.
261 *
262 * @token: token value sent to ASM service on q6.
263 * Returns stream id.
264 */
265uint8_t q6asm_get_stream_id_from_token(uint32_t token)
266{
267 union asm_token_struct asm_token;
268
269 asm_token.token = token;
270 return asm_token._token.stream_id;
271}
272EXPORT_SYMBOL(q6asm_get_stream_id_from_token);
273
274static int audio_output_latency_dbgfs_open(struct inode *inode,
275 struct file *file)
276{
277 file->private_data = inode->i_private;
278 return 0;
279}
280static ssize_t audio_output_latency_dbgfs_read(struct file *file,
281 char __user *buf, size_t count, loff_t *ppos)
282{
283 if (out_buffer == NULL) {
284 pr_err("%s: out_buffer is null\n", __func__);
285 return 0;
286 }
287 snprintf(out_buffer, OUT_BUFFER_SIZE, "%ld,%ld,%ld,%ld,%ld,%ld,",
288 out_cold_tv.tv_sec, out_cold_tv.tv_usec, out_warm_tv.tv_sec,
289 out_warm_tv.tv_usec, out_cont_tv.tv_sec, out_cont_tv.tv_usec);
290 return simple_read_from_buffer(buf, OUT_BUFFER_SIZE, ppos,
291 out_buffer, OUT_BUFFER_SIZE);
292}
293static ssize_t audio_output_latency_dbgfs_write(struct file *file,
294 const char __user *buf, size_t count, loff_t *ppos)
295{
296 char *temp;
297
298 if (count > 2*sizeof(char)) {
299 pr_err("%s: err count is more %zd\n", __func__, count);
300 return -EINVAL;
301 }
302 temp = kmalloc(2*sizeof(char), GFP_KERNEL);
303
304 out_cold_index = 0;
305
306 if (temp) {
307 if (copy_from_user(temp, buf, 2*sizeof(char))) {
308 pr_err("%s: copy from user failed for size %zd\n",
309 __func__, 2*sizeof(char));
310 kfree(temp);
311 return -EFAULT;
312 }
313 if (!kstrtol(temp, 10, &out_enable_flag)) {
314 kfree(temp);
315 return count;
316 }
317 kfree(temp);
318 }
319 return -EINVAL;
320}
321static const struct file_operations audio_output_latency_debug_fops = {
322 .open = audio_output_latency_dbgfs_open,
323 .read = audio_output_latency_dbgfs_read,
324 .write = audio_output_latency_dbgfs_write
325};
326static int audio_input_latency_dbgfs_open(struct inode *inode,
327 struct file *file)
328{
329 file->private_data = inode->i_private;
330 return 0;
331}
332static ssize_t audio_input_latency_dbgfs_read(struct file *file,
333 char __user *buf, size_t count, loff_t *ppos)
334{
335 if (in_buffer == NULL) {
336 pr_err("%s: in_buffer is null\n", __func__);
337 return 0;
338 }
339 snprintf(in_buffer, IN_BUFFER_SIZE, "%ld,%ld,",
340 in_cont_tv.tv_sec, in_cont_tv.tv_usec);
341 return simple_read_from_buffer(buf, IN_BUFFER_SIZE, ppos,
342 in_buffer, IN_BUFFER_SIZE);
343}
344static ssize_t audio_input_latency_dbgfs_write(struct file *file,
345 const char __user *buf, size_t count, loff_t *ppos)
346{
347 char *temp;
348
349 if (count > 2*sizeof(char)) {
350 pr_err("%s: err count is more %zd\n", __func__, count);
351 return -EINVAL;
352 }
353 temp = kmalloc(2*sizeof(char), GFP_KERNEL);
354
355 if (temp) {
356 if (copy_from_user(temp, buf, 2*sizeof(char))) {
357 pr_err("%s: copy from user failed for size %zd\n",
358 __func__, 2*sizeof(char));
359 kfree(temp);
360 return -EFAULT;
361 }
362 if (!kstrtol(temp, 10, &in_enable_flag)) {
363 kfree(temp);
364 return count;
365 }
366 kfree(temp);
367 }
368 return -EINVAL;
369}
370static const struct file_operations audio_input_latency_debug_fops = {
371 .open = audio_input_latency_dbgfs_open,
372 .read = audio_input_latency_dbgfs_read,
373 .write = audio_input_latency_dbgfs_write
374};
375
376static void config_debug_fs_write_cb(void)
377{
378 if (out_enable_flag) {
379 /* For first Write done log the time and reset
380 * out_cold_index
381 */
382 if (out_cold_index != 1) {
383 do_gettimeofday(&out_cold_tv);
384 pr_debug("COLD: apr_send_pkt at %ld sec %ld microsec\n",
385 out_cold_tv.tv_sec,
386 out_cold_tv.tv_usec);
387 out_cold_index = 1;
388 }
389 pr_debug("%s: out_enable_flag %ld\n",
390 __func__, out_enable_flag);
391 }
392}
393static void config_debug_fs_read_cb(void)
394{
395 if (in_enable_flag) {
396 /* when in_cont_index == 7, DSP would be
397 * writing into the 8th 512 byte buffer and this
398 * timestamp is tapped here.Once done it then writes
399 * to 9th 512 byte buffer.These two buffers(8th, 9th)
400 * reach the test application in 5th iteration and that
401 * timestamp is tapped at user level. The difference
402 * of these two timestamps gives us the time between
403 * the time at which dsp started filling the sample
404 * required and when it reached the test application.
405 * Hence continuous input latency
406 */
407 if (in_cont_index == 7) {
408 do_gettimeofday(&in_cont_tv);
409 pr_info("%s: read buffer at %ld sec %ld microsec\n",
410 __func__,
411 in_cont_tv.tv_sec, in_cont_tv.tv_usec);
412 }
413 in_cont_index++;
414 }
415}
416
417static void config_debug_fs_reset_index(void)
418{
419 in_cont_index = 0;
420}
421
422static void config_debug_fs_run(void)
423{
424 if (out_enable_flag) {
425 do_gettimeofday(&out_cold_tv);
426 pr_debug("%s: COLD apr_send_pkt at %ld sec %ld microsec\n",
427 __func__, out_cold_tv.tv_sec, out_cold_tv.tv_usec);
428 }
429}
430
431static void config_debug_fs_write(struct audio_buffer *ab)
432{
433 if (out_enable_flag) {
434 char zero_pattern[2] = {0x00, 0x00};
435 /* If First two byte is non zero and last two byte
436 * is zero then it is warm output pattern
437 */
438 if ((strcmp(((char *)ab->data), zero_pattern)) &&
439 (!strcmp(((char *)ab->data + 2), zero_pattern))) {
440 do_gettimeofday(&out_warm_tv);
441 pr_debug("%s: WARM:apr_send_pkt at %ld sec %ld microsec\n",
442 __func__,
443 out_warm_tv.tv_sec,
444 out_warm_tv.tv_usec);
445 pr_debug("%s: Warm Pattern Matched\n", __func__);
446 }
447 /* If First two byte is zero and last two byte is
448 * non zero then it is cont output pattern
449 */
450 else if ((!strcmp(((char *)ab->data), zero_pattern))
451 && (strcmp(((char *)ab->data + 2), zero_pattern))) {
452 do_gettimeofday(&out_cont_tv);
453 pr_debug("%s: CONT:apr_send_pkt at %ld sec %ld microsec\n",
454 __func__,
455 out_cont_tv.tv_sec,
456 out_cont_tv.tv_usec);
457 pr_debug("%s: Cont Pattern Matched\n", __func__);
458 }
459 }
460}
461static void config_debug_fs_init(void)
462{
463 out_buffer = kzalloc(OUT_BUFFER_SIZE, GFP_KERNEL);
464 if (out_buffer == NULL)
465 goto outbuf_fail;
466
467 in_buffer = kzalloc(IN_BUFFER_SIZE, GFP_KERNEL);
468 if (in_buffer == NULL)
469 goto inbuf_fail;
470
471 out_dentry = debugfs_create_file("audio_out_latency_measurement_node",
472 0664,
473 NULL, NULL, &audio_output_latency_debug_fops);
474 if (IS_ERR(out_dentry)) {
475 pr_err("%s: debugfs_create_file failed\n", __func__);
476 goto file_fail;
477 }
478 in_dentry = debugfs_create_file("audio_in_latency_measurement_node",
479 0664,
480 NULL, NULL, &audio_input_latency_debug_fops);
481 if (IS_ERR(in_dentry)) {
482 pr_err("%s: debugfs_create_file failed\n", __func__);
483 goto file_fail;
484 }
485 return;
486file_fail:
487 kfree(in_buffer);
488inbuf_fail:
489 kfree(out_buffer);
490outbuf_fail:
491 in_buffer = NULL;
492 out_buffer = NULL;
493}
494#else
495static void config_debug_fs_write(struct audio_buffer *ab)
496{
497}
498static void config_debug_fs_run(void)
499{
500}
501static void config_debug_fs_reset_index(void)
502{
503}
504static void config_debug_fs_read_cb(void)
505{
506}
507static void config_debug_fs_write_cb(void)
508{
509}
510static void config_debug_fs_init(void)
511{
512}
513#endif
514
515int q6asm_mmap_apr_dereg(void)
516{
517 int c;
518
519 c = atomic_sub_return(1, &this_mmap.ref_cnt);
520 if (c == 0) {
521 apr_deregister(this_mmap.apr);
522 common_client.mmap_apr = NULL;
523 pr_debug("%s: APR De-Register common port\n", __func__);
524 } else if (c < 0) {
525 pr_err("%s: APR Common Port Already Closed %d\n",
526 __func__, c);
527 atomic_set(&this_mmap.ref_cnt, 0);
528 }
529
530 return 0;
531}
532
533static int q6asm_session_alloc(struct audio_client *ac)
534{
535 int n;
536
537 for (n = 1; n <= ASM_ACTIVE_STREAMS_ALLOWED; n++) {
Meng Wang9730cdd2017-09-26 12:48:31 +0800538 if (!(session[n].ac)) {
539 session[n].ac = ac;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530540 return n;
541 }
542 }
543 pr_err("%s: session not available\n", __func__);
544 return -ENOMEM;
545}
546
Meng Wang9730cdd2017-09-26 12:48:31 +0800547static int q6asm_get_session_id_from_audio_client(struct audio_client *ac)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530548{
549 int n;
550
551 for (n = 1; n <= ASM_ACTIVE_STREAMS_ALLOWED; n++) {
Meng Wang9730cdd2017-09-26 12:48:31 +0800552 if (session[n].ac == ac)
553 return n;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530554 }
555 return 0;
556}
557
Meng Wang9730cdd2017-09-26 12:48:31 +0800558static bool q6asm_is_valid_audio_client(struct audio_client *ac)
559{
560 return q6asm_get_session_id_from_audio_client(ac) ? 1 : 0;
561}
562
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530563static void q6asm_session_free(struct audio_client *ac)
564{
Meng Wang9730cdd2017-09-26 12:48:31 +0800565 int session_id;
Meng Wangb6afa8c2017-11-30 17:55:05 +0800566 unsigned long flags;
Meng Wang9730cdd2017-09-26 12:48:31 +0800567
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530568 pr_debug("%s: sessionid[%d]\n", __func__, ac->session);
Meng Wang9730cdd2017-09-26 12:48:31 +0800569 session_id = ac->session;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530570 rtac_remove_popp_from_adm_devices(ac->session);
Meng Wangb6afa8c2017-11-30 17:55:05 +0800571 spin_lock_irqsave(&(session[session_id].session_lock), flags);
Meng Wang9730cdd2017-09-26 12:48:31 +0800572 session[ac->session].ac = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530573 ac->session = 0;
574 ac->perf_mode = LEGACY_PCM_MODE;
575 ac->fptr_cache_ops = NULL;
Meng Wang9730cdd2017-09-26 12:48:31 +0800576 ac->cb = NULL;
577 ac->priv = NULL;
578 kfree(ac);
579 ac = NULL;
Meng Wangb6afa8c2017-11-30 17:55:05 +0800580 spin_unlock_irqrestore(&(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530581}
582
583static uint32_t q6asm_get_next_buf(struct audio_client *ac,
584 uint32_t curr_buf, uint32_t max_buf_cnt)
585{
586 dev_vdbg(ac->dev, "%s: curr_buf = %d, max_buf_cnt = %d\n",
587 __func__, curr_buf, max_buf_cnt);
588 curr_buf += 1;
589 return (curr_buf >= max_buf_cnt) ? 0 : curr_buf;
590}
591
592static int q6asm_map_cal_memory(int32_t cal_type,
593 struct cal_block_data *cal_block)
594{
595 int result = 0;
596 struct asm_buffer_node *buf_node = NULL;
597 struct list_head *ptr, *next;
598
599 if (cal_block == NULL) {
600 pr_err("%s: cal_block is NULL!\n",
601 __func__);
602 goto done;
603 }
604
605 if (cal_block->cal_data.paddr == 0) {
606 pr_debug("%s: No address to map!\n",
607 __func__);
608 goto done;
609 }
610
611 common_client.mmap_apr = q6asm_mmap_apr_reg();
612 if (common_client.mmap_apr == NULL) {
613 pr_err("%s: q6asm_mmap_apr_reg failed\n",
614 __func__);
615 result = -EPERM;
616 goto done;
617 }
618 common_client.apr = common_client.mmap_apr;
619 if (cal_block->map_data.map_size == 0) {
620 pr_debug("%s: map size is 0!\n",
621 __func__);
622 goto done;
623 }
624
625 /* Use second asm buf to map memory */
626 if (common_client.port[IN].buf == NULL) {
627 pr_err("%s: common buf is NULL\n",
628 __func__);
629 result = -EINVAL;
630 goto done;
631 }
632
633 common_client.port[IN].buf->phys = cal_block->cal_data.paddr;
634
635 result = q6asm_memory_map_regions(&common_client,
636 IN, cal_block->map_data.map_size, 1, 1);
637 if (result < 0) {
638 pr_err("%s: mmap did not work! size = %zd result %d\n",
639 __func__,
640 cal_block->map_data.map_size, result);
641 pr_debug("%s: mmap did not work! addr = 0x%pK, size = %zd\n",
642 __func__,
643 &cal_block->cal_data.paddr,
644 cal_block->map_data.map_size);
645 goto done;
646 }
647
648 list_for_each_safe(ptr, next,
649 &common_client.port[IN].mem_map_handle) {
650 buf_node = list_entry(ptr, struct asm_buffer_node,
651 list);
652 if (buf_node->buf_phys_addr == cal_block->cal_data.paddr) {
653 cal_block->map_data.q6map_handle = buf_node->mmap_hdl;
654 break;
655 }
656 }
657done:
658 return result;
659}
660
661static int remap_cal_data(int32_t cal_type, struct cal_block_data *cal_block)
662{
663 int ret = 0;
664
665 if (cal_block->map_data.ion_client == NULL) {
666 pr_err("%s: No ION allocation for cal type %d!\n",
667 __func__, cal_type);
668 ret = -EINVAL;
669 goto done;
670 }
671
672 if ((cal_block->map_data.map_size > 0) &&
673 (cal_block->map_data.q6map_handle == 0)) {
674
675 ret = q6asm_map_cal_memory(cal_type, cal_block);
676 if (ret < 0) {
677 pr_err("%s: mmap did not work! size = %zd ret %d\n",
678 __func__, cal_block->map_data.map_size, ret);
679 goto done;
680 }
681 }
682done:
683 return ret;
684}
685
686static int q6asm_unmap_cal_memory(int32_t cal_type,
687 struct cal_block_data *cal_block)
688{
689 int result = 0;
690 int result2 = 0;
691
692 if (cal_block == NULL) {
693 pr_err("%s: cal_block is NULL!\n",
694 __func__);
695 result = -EINVAL;
696 goto done;
697 }
698
699 if (cal_block->map_data.q6map_handle == 0) {
700 pr_debug("%s: No address to unmap!\n",
701 __func__);
702 result = -EINVAL;
703 goto done;
704 }
705
706 if (common_client.mmap_apr == NULL) {
707 common_client.mmap_apr = q6asm_mmap_apr_reg();
708 if (common_client.mmap_apr == NULL) {
709 pr_err("%s: q6asm_mmap_apr_reg failed\n",
710 __func__);
711 result = -EPERM;
712 goto done;
713 }
714 }
715
716 result2 = q6asm_memory_unmap_regions(&common_client, IN);
717 if (result2 < 0) {
718 pr_err("%s: unmap failed, err %d\n",
719 __func__, result2);
720 result = result2;
721 }
722
723 cal_block->map_data.q6map_handle = 0;
724done:
725 return result;
726}
727
728int q6asm_unmap_cal_data(int cal_type, struct cal_block_data *cal_block)
729{
730 int ret = 0;
731
732 if ((cal_block->map_data.map_size > 0) &&
733 (cal_block->map_data.q6map_handle != 0)) {
734
735 ret = q6asm_unmap_cal_memory(cal_type, cal_block);
736 if (ret < 0) {
737 pr_err("%s: unmap did not work! size = %zd ret %d\n",
738 __func__, cal_block->map_data.map_size, ret);
739 goto done;
740 }
741 }
742done:
743 return ret;
744}
745
746int send_asm_custom_topology(struct audio_client *ac)
747{
748 struct cal_block_data *cal_block = NULL;
749 struct cmd_set_topologies asm_top;
750 int result = 0;
751 int result1 = 0;
752
753 if (cal_data[ASM_CUSTOM_TOP_CAL] == NULL)
754 goto done;
755
756 mutex_lock(&cal_data[ASM_CUSTOM_TOP_CAL]->lock);
757 if (!set_custom_topology)
758 goto unlock;
759 set_custom_topology = 0;
760
761 cal_block = cal_utils_get_only_cal_block(cal_data[ASM_CUSTOM_TOP_CAL]);
762 if (cal_block == NULL)
763 goto unlock;
764
765 if (cal_block->cal_data.size == 0) {
766 pr_debug("%s: No cal to send!\n", __func__);
767 goto unlock;
768 }
769
770 pr_debug("%s: Sending cal_index %d\n", __func__, ASM_CUSTOM_TOP_CAL);
771
772 result = remap_cal_data(ASM_CUST_TOPOLOGY_CAL_TYPE, cal_block);
773 if (result) {
774 pr_err("%s: Remap_cal_data failed for cal %d!\n",
775 __func__, ASM_CUSTOM_TOP_CAL);
776 goto unlock;
777 }
778
779 q6asm_add_hdr_custom_topology(ac, &asm_top.hdr, sizeof(asm_top));
780 atomic_set(&ac->mem_state, -1);
781 asm_top.hdr.opcode = ASM_CMD_ADD_TOPOLOGIES;
782 asm_top.payload_addr_lsw = lower_32_bits(cal_block->cal_data.paddr);
783 asm_top.payload_addr_msw = msm_audio_populate_upper_32_bits(
784 cal_block->cal_data.paddr);
785 asm_top.mem_map_handle = cal_block->map_data.q6map_handle;
786 asm_top.payload_size = cal_block->cal_data.size;
787
788 pr_debug("%s: Sending ASM_CMD_ADD_TOPOLOGIES payload = %pK, size = %d, map handle = 0x%x\n",
789 __func__, &cal_block->cal_data.paddr,
790 asm_top.payload_size, asm_top.mem_map_handle);
791
792 result = apr_send_pkt(ac->apr, (uint32_t *) &asm_top);
793 if (result < 0) {
794 pr_err("%s: Set topologies failed result %d\n",
795 __func__, result);
796 pr_debug("%s: Set topologies failed payload = 0x%pK\n",
797 __func__, &cal_block->cal_data.paddr);
798 goto unmap;
799
800 }
801
802 result = wait_event_timeout(ac->mem_wait,
803 (atomic_read(&ac->mem_state) >= 0), 5*HZ);
804 if (!result) {
805 pr_err("%s: Set topologies failed timeout\n", __func__);
806 pr_debug("%s: Set topologies failed after timedout payload = 0x%pK\n",
807 __func__, &cal_block->cal_data.paddr);
808 result = -ETIMEDOUT;
809 goto unmap;
810 }
811 if (atomic_read(&ac->mem_state) > 0) {
812 pr_err("%s: DSP returned error[%s]\n",
813 __func__, adsp_err_get_err_str(
814 atomic_read(&ac->mem_state)));
815 result = adsp_err_get_lnx_err_code(
816 atomic_read(&ac->mem_state));
817 goto unmap;
818 }
819
820unmap:
821 result1 = q6asm_unmap_cal_memory(ASM_CUST_TOPOLOGY_CAL_TYPE,
822 cal_block);
823 if (result1 < 0) {
824 result = result1;
825 pr_debug("%s: unmap cal failed! %d\n", __func__, result);
826 }
827unlock:
828 mutex_unlock(&cal_data[ASM_CUSTOM_TOP_CAL]->lock);
829done:
830 return result;
831}
832
833int q6asm_map_rtac_block(struct rtac_cal_block_data *cal_block)
834{
835 int result = 0;
836 struct asm_buffer_node *buf_node = NULL;
837 struct list_head *ptr, *next;
838
839 pr_debug("%s:\n", __func__);
840
841 if (cal_block == NULL) {
842 pr_err("%s: cal_block is NULL!\n",
843 __func__);
844 result = -EINVAL;
845 goto done;
846 }
847
848 if (cal_block->cal_data.paddr == 0) {
849 pr_debug("%s: No address to map!\n",
850 __func__);
851 result = -EINVAL;
852 goto done;
853 }
854
855 if (common_client.mmap_apr == NULL) {
856 common_client.mmap_apr = q6asm_mmap_apr_reg();
857 if (common_client.mmap_apr == NULL) {
858 pr_err("%s: q6asm_mmap_apr_reg failed\n",
859 __func__);
860 result = -EPERM;
861 goto done;
862 }
863 }
864
865 if (cal_block->map_data.map_size == 0) {
866 pr_debug("%s: map size is 0!\n",
867 __func__);
868 result = -EINVAL;
869 goto done;
870 }
871
872 /* Use second asm buf to map memory */
873 if (common_client.port[OUT].buf == NULL) {
874 pr_err("%s: common buf is NULL\n",
875 __func__);
876 result = -EINVAL;
877 goto done;
878 }
879
880 common_client.port[OUT].buf->phys = cal_block->cal_data.paddr;
881
882 result = q6asm_memory_map_regions(&common_client,
883 OUT, cal_block->map_data.map_size, 1, 1);
884 if (result < 0) {
885 pr_err("%s: mmap did not work! size = %d result %d\n",
886 __func__,
887 cal_block->map_data.map_size, result);
888 pr_debug("%s: mmap did not work! addr = 0x%pK, size = %d\n",
889 __func__,
890 &cal_block->cal_data.paddr,
891 cal_block->map_data.map_size);
892 goto done;
893 }
894
895 list_for_each_safe(ptr, next,
896 &common_client.port[OUT].mem_map_handle) {
897 buf_node = list_entry(ptr, struct asm_buffer_node,
898 list);
899 if (buf_node->buf_phys_addr == cal_block->cal_data.paddr) {
900 cal_block->map_data.map_handle = buf_node->mmap_hdl;
901 break;
902 }
903 }
904done:
905 return result;
906}
907
908int q6asm_unmap_rtac_block(uint32_t *mem_map_handle)
909{
910 int result = 0;
911 int result2 = 0;
912
913 pr_debug("%s:\n", __func__);
914
915 if (mem_map_handle == NULL) {
916 pr_debug("%s: Map handle is NULL, nothing to unmap\n",
917 __func__);
918 goto done;
919 }
920
921 if (*mem_map_handle == 0) {
922 pr_debug("%s: Map handle is 0, nothing to unmap\n",
923 __func__);
924 goto done;
925 }
926
927 if (common_client.mmap_apr == NULL) {
928 common_client.mmap_apr = q6asm_mmap_apr_reg();
929 if (common_client.mmap_apr == NULL) {
930 pr_err("%s: q6asm_mmap_apr_reg failed\n",
931 __func__);
932 result = -EPERM;
933 goto done;
934 }
935 }
936
937
938 result2 = q6asm_memory_unmap_regions(&common_client, OUT);
939 if (result2 < 0) {
940 pr_err("%s: unmap failed, err %d\n",
941 __func__, result2);
942 result = result2;
943 } else {
944 mem_map_handle = 0;
945 }
946
947 result2 = q6asm_mmap_apr_dereg();
948 if (result2 < 0) {
949 pr_err("%s: q6asm_mmap_apr_dereg failed, err %d\n",
950 __func__, result2);
951 result = result2;
952 }
953done:
954 return result;
955}
956
957int q6asm_audio_client_buf_free(unsigned int dir,
958 struct audio_client *ac)
959{
960 struct audio_port_data *port;
961 int cnt = 0;
962 int rc = 0;
963
964 pr_debug("%s: Session id %d\n", __func__, ac->session);
965 mutex_lock(&ac->cmd_lock);
966 if (ac->io_mode & SYNC_IO_MODE) {
967 port = &ac->port[dir];
968 if (!port->buf) {
969 pr_err("%s: buf NULL\n", __func__);
970 mutex_unlock(&ac->cmd_lock);
971 return 0;
972 }
973 cnt = port->max_buf_cnt - 1;
974
975 if (cnt >= 0) {
976 rc = q6asm_memory_unmap_regions(ac, dir);
977 if (rc < 0)
978 pr_err("%s: Memory_unmap_regions failed %d\n",
979 __func__, rc);
980 }
981
982 while (cnt >= 0) {
983 if (port->buf[cnt].data) {
984 if (!rc || atomic_read(&ac->reset))
985 msm_audio_ion_free(
986 port->buf[cnt].client,
987 port->buf[cnt].handle);
988
989 port->buf[cnt].client = NULL;
990 port->buf[cnt].handle = NULL;
991 port->buf[cnt].data = NULL;
992 port->buf[cnt].phys = 0;
993 --(port->max_buf_cnt);
994 }
995 --cnt;
996 }
997 kfree(port->buf);
998 port->buf = NULL;
999 }
1000 mutex_unlock(&ac->cmd_lock);
1001 return 0;
1002}
1003
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301004/**
1005 * q6asm_audio_client_buf_free_contiguous -
1006 * frees the memory buffers for ASM
1007 *
1008 * @dir: RX or TX direction
1009 * @ac: audio client handle
1010 *
1011 * Returns 0 on success or error on failure
1012 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301013int q6asm_audio_client_buf_free_contiguous(unsigned int dir,
1014 struct audio_client *ac)
1015{
1016 struct audio_port_data *port;
1017 int cnt = 0;
1018 int rc = 0;
1019
1020 pr_debug("%s: Session id %d\n", __func__, ac->session);
1021 mutex_lock(&ac->cmd_lock);
1022 port = &ac->port[dir];
1023 if (!port->buf) {
1024 mutex_unlock(&ac->cmd_lock);
1025 return 0;
1026 }
1027 cnt = port->max_buf_cnt - 1;
1028
1029 if (cnt >= 0) {
1030 rc = q6asm_memory_unmap(ac, port->buf[0].phys, dir);
1031 if (rc < 0)
1032 pr_err("%s: Memory_unmap_regions failed %d\n",
1033 __func__, rc);
1034 }
1035
1036 if (port->buf[0].data) {
1037 pr_debug("%s: data[%pK]phys[%pK][%pK] , client[%pK] handle[%pK]\n",
1038 __func__,
1039 port->buf[0].data,
1040 &port->buf[0].phys,
1041 &port->buf[0].phys,
1042 port->buf[0].client,
1043 port->buf[0].handle);
1044 if (!rc || atomic_read(&ac->reset))
1045 msm_audio_ion_free(port->buf[0].client,
1046 port->buf[0].handle);
1047 port->buf[0].client = NULL;
1048 port->buf[0].handle = NULL;
1049 }
1050
1051 while (cnt >= 0) {
1052 port->buf[cnt].data = NULL;
1053 port->buf[cnt].phys = 0;
1054 cnt--;
1055 }
1056 port->max_buf_cnt = 0;
1057 kfree(port->buf);
1058 port->buf = NULL;
1059 mutex_unlock(&ac->cmd_lock);
1060 return 0;
1061}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301062EXPORT_SYMBOL(q6asm_audio_client_buf_free_contiguous);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301063
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301064/**
1065 * q6asm_audio_client_free -
1066 * frees the audio client for ASM
1067 *
1068 * @ac: audio client handle
1069 *
1070 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301071void q6asm_audio_client_free(struct audio_client *ac)
1072{
1073 int loopcnt;
1074 struct audio_port_data *port;
1075
1076 if (!ac) {
1077 pr_err("%s: ac %pK\n", __func__, ac);
1078 return;
1079 }
1080 if (!ac->session) {
1081 pr_err("%s: ac session invalid\n", __func__);
1082 return;
1083 }
1084
1085 mutex_lock(&session_lock);
1086
1087 pr_debug("%s: Session id %d\n", __func__, ac->session);
1088 if (ac->io_mode & SYNC_IO_MODE) {
1089 for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
1090 port = &ac->port[loopcnt];
1091 if (!port->buf)
1092 continue;
1093 pr_debug("%s: loopcnt = %d\n",
1094 __func__, loopcnt);
1095 q6asm_audio_client_buf_free(loopcnt, ac);
1096 }
1097 }
1098
1099 rtac_set_asm_handle(ac->session, NULL);
1100 apr_deregister(ac->apr2);
1101 apr_deregister(ac->apr);
1102 q6asm_mmap_apr_dereg();
1103 ac->apr2 = NULL;
1104 ac->apr = NULL;
1105 ac->mmap_apr = NULL;
1106 q6asm_session_free(ac);
1107
1108 pr_debug("%s: APR De-Register\n", __func__);
1109
1110/*done:*/
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301111 mutex_unlock(&session_lock);
1112}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301113EXPORT_SYMBOL(q6asm_audio_client_free);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301114
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301115/**
1116 * q6asm_set_io_mode -
1117 * Update IO mode for ASM
1118 *
1119 * @ac: audio client handle
1120 * @mode1: IO mode to update
1121 *
1122 * Returns 0 on success or error on failure
1123 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301124int q6asm_set_io_mode(struct audio_client *ac, uint32_t mode1)
1125{
1126 uint32_t mode;
1127 int ret = 0;
1128
1129 if (ac == NULL) {
1130 pr_err("%s: APR handle NULL\n", __func__);
1131 return -EINVAL;
1132 }
1133
1134 ac->io_mode &= 0xFF00;
1135 mode = (mode1 & 0xF);
1136
1137 pr_debug("%s: ac->mode after anding with FF00:0x%x,\n",
1138 __func__, ac->io_mode);
1139
1140 if ((mode == ASYNC_IO_MODE) || (mode == SYNC_IO_MODE)) {
1141 ac->io_mode |= mode1;
1142 pr_debug("%s: Set Mode to 0x%x\n", __func__, ac->io_mode);
1143 } else {
1144 pr_err("%s: Not an valid IO Mode:%d\n", __func__, ac->io_mode);
1145 ret = -EINVAL;
1146 }
1147
1148 return ret;
1149}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301150EXPORT_SYMBOL(q6asm_set_io_mode);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301151
1152void *q6asm_mmap_apr_reg(void)
1153{
1154 if ((atomic_read(&this_mmap.ref_cnt) == 0) ||
1155 (this_mmap.apr == NULL)) {
1156 this_mmap.apr = apr_register("ADSP", "ASM",
1157 (apr_fn)q6asm_srvc_callback,
1158 0x0FFFFFFFF, &this_mmap);
1159 if (this_mmap.apr == NULL) {
1160 pr_debug("%s: Unable to register APR ASM common port\n",
1161 __func__);
1162 goto fail;
1163 }
1164 }
1165 atomic_inc(&this_mmap.ref_cnt);
1166
1167 return this_mmap.apr;
1168fail:
1169 return NULL;
1170}
1171
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301172/**
1173 * q6asm_send_stream_cmd -
1174 * command to send for ASM stream
1175 *
1176 * @ac: audio client handle
1177 * @data: event data
1178 *
1179 * Returns 0 on success or error on failure
1180 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301181int q6asm_send_stream_cmd(struct audio_client *ac,
1182 struct msm_adsp_event_data *data)
1183{
1184 char *asm_params = NULL;
1185 struct apr_hdr hdr;
1186 int sz, rc;
1187
1188 if (!data || !ac) {
1189 pr_err("%s: %s is NULL\n", __func__,
1190 (!data) ? "data" : "ac");
1191 rc = -EINVAL;
1192 goto done;
1193 }
1194
1195 if (data->event_type >= ARRAY_SIZE(adsp_reg_event_opcode)) {
1196 pr_err("%s: event %u out of boundary of array size of (%lu)\n",
1197 __func__, data->event_type,
1198 (long)ARRAY_SIZE(adsp_reg_event_opcode));
1199 rc = -EINVAL;
1200 goto done;
1201 }
1202
1203 sz = sizeof(struct apr_hdr) + data->payload_len;
1204 asm_params = kzalloc(sz, GFP_KERNEL);
1205 if (!asm_params) {
1206 rc = -ENOMEM;
1207 goto done;
1208 }
1209
1210 q6asm_add_hdr_async(ac, &hdr, sz, TRUE);
1211 atomic_set(&ac->cmd_state_pp, -1);
1212 hdr.opcode = adsp_reg_event_opcode[data->event_type];
1213 memcpy(asm_params, &hdr, sizeof(struct apr_hdr));
1214 memcpy(asm_params + sizeof(struct apr_hdr),
1215 data->payload, data->payload_len);
1216 rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params);
1217 if (rc < 0) {
1218 pr_err("%s: stream event cmd apr pkt failed\n", __func__);
1219 rc = -EINVAL;
1220 goto fail_send_param;
1221 }
1222
1223 rc = wait_event_timeout(ac->cmd_wait,
1224 (atomic_read(&ac->cmd_state_pp) >= 0), 1 * HZ);
1225 if (!rc) {
1226 pr_err("%s: timeout for stream event cmd resp\n", __func__);
1227 rc = -ETIMEDOUT;
1228 goto fail_send_param;
1229 }
1230
1231 if (atomic_read(&ac->cmd_state_pp) > 0) {
1232 pr_err("%s: DSP returned error[%s] for stream event cmd\n",
1233 __func__, adsp_err_get_err_str(
1234 atomic_read(&ac->cmd_state_pp)));
1235 rc = adsp_err_get_lnx_err_code(
1236 atomic_read(&ac->cmd_state_pp));
1237 goto fail_send_param;
1238 }
1239
1240 rc = 0;
1241fail_send_param:
1242 kfree(asm_params);
1243done:
1244 return rc;
1245}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301246EXPORT_SYMBOL(q6asm_send_stream_cmd);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301247
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301248/**
1249 * q6asm_audio_client_alloc -
1250 * Alloc audio client for ASM
1251 *
1252 * @cb: callback fn
1253 * @priv: private data
1254 *
1255 * Returns ac pointer on success or NULL on failure
1256 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301257struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv)
1258{
1259 struct audio_client *ac;
1260 int n;
1261 int lcnt = 0;
1262 int rc = 0;
1263
1264 ac = kzalloc(sizeof(struct audio_client), GFP_KERNEL);
1265 if (!ac)
1266 return NULL;
1267
1268 mutex_lock(&session_lock);
1269 n = q6asm_session_alloc(ac);
1270 if (n <= 0) {
1271 pr_err("%s: ASM Session alloc fail n=%d\n", __func__, n);
1272 mutex_unlock(&session_lock);
Meng Wang9730cdd2017-09-26 12:48:31 +08001273 kfree(ac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301274 goto fail_session;
1275 }
1276 ac->session = n;
1277 ac->cb = cb;
1278 ac->path_delay = UINT_MAX;
1279 ac->priv = priv;
1280 ac->io_mode = SYNC_IO_MODE;
1281 ac->perf_mode = LEGACY_PCM_MODE;
1282 ac->fptr_cache_ops = NULL;
1283 /* DSP expects stream id from 1 */
1284 ac->stream_id = 1;
1285 ac->apr = apr_register("ADSP", "ASM",
1286 (apr_fn)q6asm_callback,
1287 ((ac->session) << 8 | 0x0001),
1288 ac);
1289
1290 if (ac->apr == NULL) {
1291 pr_err("%s: Registration with APR failed\n", __func__);
1292 mutex_unlock(&session_lock);
1293 goto fail_apr1;
1294 }
1295 ac->apr2 = apr_register("ADSP", "ASM",
1296 (apr_fn)q6asm_callback,
1297 ((ac->session) << 8 | 0x0002),
1298 ac);
1299
1300 if (ac->apr2 == NULL) {
1301 pr_err("%s: Registration with APR-2 failed\n", __func__);
1302 mutex_unlock(&session_lock);
1303 goto fail_apr2;
1304 }
1305
1306 rtac_set_asm_handle(n, ac->apr);
1307
1308 pr_debug("%s: Registering the common port with APR\n", __func__);
1309 ac->mmap_apr = q6asm_mmap_apr_reg();
1310 if (ac->mmap_apr == NULL) {
1311 mutex_unlock(&session_lock);
1312 goto fail_mmap;
1313 }
1314
1315 init_waitqueue_head(&ac->cmd_wait);
1316 init_waitqueue_head(&ac->time_wait);
1317 init_waitqueue_head(&ac->mem_wait);
1318 atomic_set(&ac->time_flag, 1);
1319 atomic_set(&ac->reset, 0);
1320 INIT_LIST_HEAD(&ac->port[0].mem_map_handle);
1321 INIT_LIST_HEAD(&ac->port[1].mem_map_handle);
1322 pr_debug("%s: mem_map_handle list init'ed\n", __func__);
1323 mutex_init(&ac->cmd_lock);
1324 for (lcnt = 0; lcnt <= OUT; lcnt++) {
1325 mutex_init(&ac->port[lcnt].lock);
1326 spin_lock_init(&ac->port[lcnt].dsp_lock);
1327 }
1328 atomic_set(&ac->cmd_state, 0);
1329 atomic_set(&ac->cmd_state_pp, 0);
1330 atomic_set(&ac->mem_state, 0);
1331
1332 rc = send_asm_custom_topology(ac);
1333 if (rc < 0) {
1334 mutex_unlock(&session_lock);
1335 goto fail_mmap;
1336 }
1337
1338 pr_debug("%s: session[%d]\n", __func__, ac->session);
1339
1340 mutex_unlock(&session_lock);
1341
1342 return ac;
1343fail_mmap:
1344 apr_deregister(ac->apr2);
1345fail_apr2:
1346 apr_deregister(ac->apr);
1347fail_apr1:
1348 q6asm_session_free(ac);
1349fail_session:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301350 return NULL;
1351}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301352EXPORT_SYMBOL(q6asm_audio_client_alloc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301353
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301354/**
1355 * q6asm_get_audio_client -
1356 * Retrieve audio client for ASM
1357 *
1358 * @session_id: ASM session id
1359 *
1360 * Returns valid pointer on success or NULL on failure
1361 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301362struct audio_client *q6asm_get_audio_client(int session_id)
1363{
1364 if (session_id == ASM_CONTROL_SESSION)
1365 return &common_client;
1366
1367 if ((session_id <= 0) || (session_id > ASM_ACTIVE_STREAMS_ALLOWED)) {
1368 pr_err("%s: invalid session: %d\n", __func__, session_id);
1369 goto err;
1370 }
1371
Meng Wang9730cdd2017-09-26 12:48:31 +08001372 if (!(session[session_id].ac)) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301373 pr_err("%s: session not active: %d\n", __func__, session_id);
1374 goto err;
1375 }
Meng Wang9730cdd2017-09-26 12:48:31 +08001376 return session[session_id].ac;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301377err:
1378 return NULL;
1379}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301380EXPORT_SYMBOL(q6asm_get_audio_client);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301381
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301382/**
1383 * q6asm_audio_client_buf_alloc -
1384 * Allocs memory from ION for ASM
1385 *
1386 * @dir: RX or TX direction
1387 * @ac: Audio client handle
1388 * @bufsz: size of each buffer
1389 * @bufcnt: number of buffers to alloc
1390 *
1391 * Returns 0 on success or error on failure
1392 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301393int q6asm_audio_client_buf_alloc(unsigned int dir,
1394 struct audio_client *ac,
1395 unsigned int bufsz,
1396 uint32_t bufcnt)
1397{
1398 int cnt = 0;
1399 int rc = 0;
1400 struct audio_buffer *buf;
1401 size_t len;
1402
1403 if (!(ac) || !(bufsz) || ((dir != IN) && (dir != OUT))) {
1404 pr_err("%s: ac %pK bufsz %d dir %d\n", __func__, ac, bufsz,
1405 dir);
1406 return -EINVAL;
1407 }
1408
1409 pr_debug("%s: session[%d]bufsz[%d]bufcnt[%d]\n", __func__, ac->session,
1410 bufsz, bufcnt);
1411
1412 if (ac->session <= 0 || ac->session > 8) {
1413 pr_err("%s: Session ID is invalid, session = %d\n", __func__,
1414 ac->session);
1415 goto fail;
1416 }
1417
1418 if (ac->io_mode & SYNC_IO_MODE) {
1419 if (ac->port[dir].buf) {
1420 pr_debug("%s: buffer already allocated\n", __func__);
1421 return 0;
1422 }
1423 mutex_lock(&ac->cmd_lock);
1424 if (bufcnt > (U32_MAX/sizeof(struct audio_buffer))) {
1425 pr_err("%s: Buffer size overflows", __func__);
1426 mutex_unlock(&ac->cmd_lock);
1427 goto fail;
1428 }
1429 buf = kzalloc(((sizeof(struct audio_buffer))*bufcnt),
1430 GFP_KERNEL);
1431
1432 if (!buf) {
1433 mutex_unlock(&ac->cmd_lock);
1434 goto fail;
1435 }
1436
1437 ac->port[dir].buf = buf;
1438
1439 while (cnt < bufcnt) {
1440 if (bufsz > 0) {
1441 if (!buf[cnt].data) {
1442 rc = msm_audio_ion_alloc("asm_client",
1443 &buf[cnt].client, &buf[cnt].handle,
1444 bufsz,
1445 (ion_phys_addr_t *)&buf[cnt].phys,
1446 &len,
1447 &buf[cnt].data);
1448 if (rc) {
1449 pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n",
1450 __func__, rc);
1451 mutex_unlock(&ac->cmd_lock);
1452 goto fail;
1453 }
1454
1455 buf[cnt].used = 1;
1456 buf[cnt].size = bufsz;
1457 buf[cnt].actual_size = bufsz;
1458 pr_debug("%s: data[%pK]phys[%pK][%pK]\n",
1459 __func__,
1460 buf[cnt].data,
1461 &buf[cnt].phys,
1462 &buf[cnt].phys);
1463 cnt++;
1464 }
1465 }
1466 }
1467 ac->port[dir].max_buf_cnt = cnt;
1468
1469 mutex_unlock(&ac->cmd_lock);
1470 rc = q6asm_memory_map_regions(ac, dir, bufsz, cnt, 0);
1471 if (rc < 0) {
1472 pr_err("%s: CMD Memory_map_regions failed %d for size %d\n",
1473 __func__, rc, bufsz);
1474 goto fail;
1475 }
1476 }
1477 return 0;
1478fail:
1479 q6asm_audio_client_buf_free(dir, ac);
1480 return -EINVAL;
1481}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301482EXPORT_SYMBOL(q6asm_audio_client_buf_alloc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301483
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301484/**
1485 * q6asm_audio_client_buf_alloc_contiguous -
1486 * Alloc contiguous memory from ION for ASM
1487 *
1488 * @dir: RX or TX direction
1489 * @ac: Audio client handle
1490 * @bufsz: size of each buffer
1491 * @bufcnt: number of buffers to alloc
1492 *
1493 * Returns 0 on success or error on failure
1494 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301495int q6asm_audio_client_buf_alloc_contiguous(unsigned int dir,
1496 struct audio_client *ac,
1497 unsigned int bufsz,
1498 unsigned int bufcnt)
1499{
1500 int cnt = 0;
1501 int rc = 0;
1502 struct audio_buffer *buf;
1503 size_t len;
1504 int bytes_to_alloc;
1505
1506 if (!(ac) || ((dir != IN) && (dir != OUT))) {
1507 pr_err("%s: ac %pK dir %d\n", __func__, ac, dir);
1508 return -EINVAL;
1509 }
1510
1511 pr_debug("%s: session[%d]bufsz[%d]bufcnt[%d]\n",
1512 __func__, ac->session,
1513 bufsz, bufcnt);
1514
1515 if (ac->session <= 0 || ac->session > 8) {
1516 pr_err("%s: Session ID is invalid, session = %d\n", __func__,
1517 ac->session);
1518 goto fail;
1519 }
1520
1521 if (ac->port[dir].buf) {
1522 pr_err("%s: buffer already allocated\n", __func__);
1523 return 0;
1524 }
1525 mutex_lock(&ac->cmd_lock);
1526 buf = kzalloc(((sizeof(struct audio_buffer))*bufcnt),
1527 GFP_KERNEL);
1528
1529 if (!buf) {
1530 pr_err("%s: buffer allocation failed\n", __func__);
1531 mutex_unlock(&ac->cmd_lock);
1532 goto fail;
1533 }
1534
1535 ac->port[dir].buf = buf;
1536
1537 /* check for integer overflow */
1538 if ((bufcnt > 0) && ((INT_MAX / bufcnt) < bufsz)) {
1539 pr_err("%s: integer overflow\n", __func__);
1540 mutex_unlock(&ac->cmd_lock);
1541 goto fail;
1542 }
1543 bytes_to_alloc = bufsz * bufcnt;
1544
1545 /* The size to allocate should be multiple of 4K bytes */
1546 bytes_to_alloc = PAGE_ALIGN(bytes_to_alloc);
1547
1548 rc = msm_audio_ion_alloc("asm_client", &buf[0].client, &buf[0].handle,
1549 bytes_to_alloc,
1550 (ion_phys_addr_t *)&buf[0].phys, &len,
1551 &buf[0].data);
1552 if (rc) {
1553 pr_err("%s: Audio ION alloc is failed, rc = %d\n",
1554 __func__, rc);
1555 mutex_unlock(&ac->cmd_lock);
1556 goto fail;
1557 }
1558
1559 buf[0].used = dir ^ 1;
1560 buf[0].size = bufsz;
1561 buf[0].actual_size = bufsz;
1562 cnt = 1;
1563 while (cnt < bufcnt) {
1564 if (bufsz > 0) {
1565 buf[cnt].data = buf[0].data + (cnt * bufsz);
1566 buf[cnt].phys = buf[0].phys + (cnt * bufsz);
1567 if (!buf[cnt].data) {
1568 pr_err("%s: Buf alloc failed\n",
1569 __func__);
1570 mutex_unlock(&ac->cmd_lock);
1571 goto fail;
1572 }
1573 buf[cnt].used = dir ^ 1;
1574 buf[cnt].size = bufsz;
1575 buf[cnt].actual_size = bufsz;
1576 pr_debug("%s: data[%pK]phys[%pK][%pK]\n",
1577 __func__,
1578 buf[cnt].data,
1579 &buf[cnt].phys,
1580 &buf[cnt].phys);
1581 }
1582 cnt++;
1583 }
1584 ac->port[dir].max_buf_cnt = cnt;
1585 mutex_unlock(&ac->cmd_lock);
1586 rc = q6asm_memory_map_regions(ac, dir, bufsz, cnt, 1);
1587 if (rc < 0) {
1588 pr_err("%s: CMD Memory_map_regions failed %d for size %d\n",
1589 __func__, rc, bufsz);
1590 goto fail;
1591 }
1592 return 0;
1593fail:
1594 q6asm_audio_client_buf_free_contiguous(dir, ac);
1595 return -EINVAL;
1596}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301597EXPORT_SYMBOL(q6asm_audio_client_buf_alloc_contiguous);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301598
1599static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv)
1600{
1601 uint32_t dir = 0;
1602 uint32_t i = IN;
1603 uint32_t *payload;
1604 unsigned long dsp_flags;
Meng Wangb6afa8c2017-11-30 17:55:05 +08001605 unsigned long flags = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301606 struct asm_buffer_node *buf_node = NULL;
1607 struct list_head *ptr, *next;
1608 union asm_token_struct asm_token;
1609
1610 struct audio_client *ac = NULL;
1611 struct audio_port_data *port;
1612
Meng Wang9730cdd2017-09-26 12:48:31 +08001613 int session_id;
1614
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301615 if (!data) {
1616 pr_err("%s: Invalid CB\n", __func__);
1617 return 0;
1618 }
1619
1620 payload = data->payload;
1621
1622 if (data->opcode == RESET_EVENTS) {
1623 pr_debug("%s: Reset event is received: %d %d apr[%pK]\n",
1624 __func__,
1625 data->reset_event,
1626 data->reset_proc,
1627 this_mmap.apr);
1628 atomic_set(&this_mmap.ref_cnt, 0);
1629 apr_reset(this_mmap.apr);
1630 this_mmap.apr = NULL;
1631 for (; i <= OUT; i++) {
1632 list_for_each_safe(ptr, next,
1633 &common_client.port[i].mem_map_handle) {
1634 buf_node = list_entry(ptr,
1635 struct asm_buffer_node,
1636 list);
1637 if (buf_node->buf_phys_addr ==
1638 common_client.port[i].buf->phys) {
1639 list_del(&buf_node->list);
1640 kfree(buf_node);
1641 }
1642 }
1643 pr_debug("%s: Clearing custom topology\n", __func__);
1644 }
1645
1646 cal_utils_clear_cal_block_q6maps(ASM_MAX_CAL_TYPES, cal_data);
1647 common_client.mmap_apr = NULL;
1648 mutex_lock(&cal_data[ASM_CUSTOM_TOP_CAL]->lock);
1649 set_custom_topology = 1;
1650 mutex_unlock(&cal_data[ASM_CUSTOM_TOP_CAL]->lock);
1651 topology_map_handle = 0;
1652 rtac_clear_mapping(ASM_RTAC_CAL);
1653 return 0;
1654 }
1655 asm_token.token = data->token;
Meng Wang9730cdd2017-09-26 12:48:31 +08001656 session_id = asm_token._token.session_id;
1657
1658 if ((session_id > 0 && session_id <= ASM_ACTIVE_STREAMS_ALLOWED))
Meng Wangb6afa8c2017-11-30 17:55:05 +08001659 spin_lock_irqsave(&(session[session_id].session_lock), flags);
Meng Wang9730cdd2017-09-26 12:48:31 +08001660
1661 ac = q6asm_get_audio_client(session_id);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301662 dir = q6asm_get_flag_from_token(&asm_token, ASM_DIRECTION_OFFSET);
1663
1664 if (!ac) {
1665 pr_debug("%s: session[%d] already freed\n",
Meng Wang9730cdd2017-09-26 12:48:31 +08001666 __func__, session_id);
1667 if ((session_id > 0 &&
1668 session_id <= ASM_ACTIVE_STREAMS_ALLOWED))
Meng Wangb6afa8c2017-11-30 17:55:05 +08001669 spin_unlock_irqrestore(
1670 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301671 return 0;
1672 }
1673
1674 if (data->payload_size > sizeof(int)) {
1675 pr_debug("%s:ptr0[0x%x]ptr1[0x%x]opcode[0x%x] token[0x%x]payload_s[%d] src[%d] dest[%d]sid[%d]dir[%d]\n",
1676 __func__, payload[0], payload[1], data->opcode,
1677 data->token, data->payload_size, data->src_port,
1678 data->dest_port, asm_token._token.session_id, dir);
1679 pr_debug("%s:Payload = [0x%x] status[0x%x]\n",
1680 __func__, payload[0], payload[1]);
1681 } else if (data->payload_size == sizeof(int)) {
1682 pr_debug("%s:ptr0[0x%x]opcode[0x%x] token[0x%x]payload_s[%d] src[%d] dest[%d]sid[%d]dir[%d]\n",
1683 __func__, payload[0], data->opcode,
1684 data->token, data->payload_size, data->src_port,
1685 data->dest_port, asm_token._token.session_id, dir);
1686 pr_debug("%s:Payload = [0x%x]\n",
1687 __func__, payload[0]);
1688 }
1689
1690 if (data->opcode == APR_BASIC_RSP_RESULT) {
1691 switch (payload[0]) {
1692 case ASM_CMD_SHARED_MEM_MAP_REGIONS:
1693 case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:
1694 case ASM_CMD_ADD_TOPOLOGIES:
1695 if (payload[1] != 0) {
1696 pr_err("%s: cmd = 0x%x returned error = 0x%x sid:%d\n",
1697 __func__, payload[0], payload[1],
1698 asm_token._token.session_id);
1699 if (payload[0] ==
1700 ASM_CMD_SHARED_MEM_UNMAP_REGIONS)
1701 atomic_set(&ac->unmap_cb_success, 0);
1702
1703 atomic_set(&ac->mem_state, payload[1]);
1704 wake_up(&ac->mem_wait);
1705 } else {
1706 if (payload[0] ==
1707 ASM_CMD_SHARED_MEM_UNMAP_REGIONS)
1708 atomic_set(&ac->unmap_cb_success, 1);
1709 }
1710
1711 if (atomic_cmpxchg(&ac->mem_state, -1, 0) == -1)
1712 wake_up(&ac->mem_wait);
1713 dev_vdbg(ac->dev, "%s: Payload = [0x%x] status[0x%x]\n",
1714 __func__, payload[0], payload[1]);
1715 break;
1716 default:
1717 pr_debug("%s: command[0x%x] not expecting rsp\n",
1718 __func__, payload[0]);
1719 break;
1720 }
Meng Wang9730cdd2017-09-26 12:48:31 +08001721 if ((session_id > 0 &&
1722 session_id <= ASM_ACTIVE_STREAMS_ALLOWED))
Meng Wangb6afa8c2017-11-30 17:55:05 +08001723 spin_unlock_irqrestore(
1724 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301725 return 0;
1726 }
1727
1728 port = &ac->port[dir];
1729
1730 switch (data->opcode) {
1731 case ASM_CMDRSP_SHARED_MEM_MAP_REGIONS:{
1732 pr_debug("%s:PL#0[0x%x] dir=0x%x s_id=0x%x\n",
1733 __func__, payload[0], dir, asm_token._token.session_id);
1734 spin_lock_irqsave(&port->dsp_lock, dsp_flags);
1735 if (atomic_cmpxchg(&ac->mem_state, -1, 0) == -1) {
1736 ac->port[dir].tmp_hdl = payload[0];
1737 wake_up(&ac->mem_wait);
1738 }
1739 spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
1740 break;
1741 }
1742 case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:{
1743 pr_debug("%s: PL#0[0x%x]PL#1 [0x%x]\n",
1744 __func__, payload[0], payload[1]);
1745 spin_lock_irqsave(&port->dsp_lock, dsp_flags);
1746 if (atomic_cmpxchg(&ac->mem_state, -1, 0) == -1)
1747 wake_up(&ac->mem_wait);
1748 spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
1749
1750 break;
1751 }
1752 default:
1753 pr_debug("%s: command[0x%x]success [0x%x]\n",
1754 __func__, payload[0], payload[1]);
1755 }
1756 if (ac->cb)
1757 ac->cb(data->opcode, data->token,
1758 data->payload, ac->priv);
Meng Wang9730cdd2017-09-26 12:48:31 +08001759 if ((session_id > 0 && session_id <= ASM_ACTIVE_STREAMS_ALLOWED))
Meng Wangb6afa8c2017-11-30 17:55:05 +08001760 spin_unlock_irqrestore(
1761 &(session[session_id].session_lock), flags);
Meng Wang9730cdd2017-09-26 12:48:31 +08001762
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301763 return 0;
1764}
1765
1766static void q6asm_process_mtmx_get_param_rsp(struct audio_client *ac,
1767 struct asm_mtmx_strtr_get_params_cmdrsp *cmdrsp)
1768{
1769 struct asm_session_mtmx_strtr_param_session_time_v3_t *time;
1770
1771 if (cmdrsp->err_code) {
1772 dev_err_ratelimited(ac->dev,
1773 "%s: err=%x, mod_id=%x, param_id=%x\n",
1774 __func__, cmdrsp->err_code,
1775 cmdrsp->param_info.module_id,
1776 cmdrsp->param_info.param_id);
1777 return;
1778 }
1779 dev_dbg_ratelimited(ac->dev,
1780 "%s: mod_id=%x, param_id=%x\n", __func__,
1781 cmdrsp->param_info.module_id,
1782 cmdrsp->param_info.param_id);
1783
1784 switch (cmdrsp->param_info.module_id) {
1785 case ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC:
1786 switch (cmdrsp->param_info.param_id) {
1787 case ASM_SESSION_MTMX_STRTR_PARAM_SESSION_TIME_V3:
1788 time = &cmdrsp->param_data.session_time;
1789 dev_vdbg(ac->dev, "%s: GET_TIME_V3, time_lsw=%x, time_msw=%x\n",
1790 __func__, time->session_time_lsw,
1791 time->session_time_msw);
1792 ac->time_stamp = (uint64_t)(((uint64_t)
1793 time->session_time_msw << 32) |
1794 time->session_time_lsw);
1795 if (time->flags &
1796 ASM_SESSION_MTMX_STRTR_PARAM_STIME_TSTMP_FLG_BMASK)
1797 dev_warn_ratelimited(ac->dev,
1798 "%s: recv inval tstmp\n",
1799 __func__);
1800 if (atomic_cmpxchg(&ac->time_flag, 1, 0))
1801 wake_up(&ac->time_wait);
1802
1803 break;
1804 default:
1805 dev_err(ac->dev, "%s: unexpected param_id %x\n",
1806 __func__, cmdrsp->param_info.param_id);
1807 break;
1808 }
1809 break;
1810 default:
1811 dev_err(ac->dev, "%s: unexpected mod_id %x\n", __func__,
1812 cmdrsp->param_info.module_id);
1813 break;
1814 }
1815}
1816
1817static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
1818{
1819 int i = 0;
1820 struct audio_client *ac = (struct audio_client *)priv;
1821 unsigned long dsp_flags;
1822 uint32_t *payload;
1823 uint32_t wakeup_flag = 1;
1824 int32_t ret = 0;
1825 union asm_token_struct asm_token;
1826 uint8_t buf_index;
1827 struct msm_adsp_event_data *pp_event_package = NULL;
1828 uint32_t payload_size = 0;
Meng Wangb6afa8c2017-11-30 17:55:05 +08001829 unsigned long flags;
Meng Wang9730cdd2017-09-26 12:48:31 +08001830 int session_id;
1831
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301832 if (ac == NULL) {
1833 pr_err("%s: ac NULL\n", __func__);
1834 return -EINVAL;
1835 }
1836 if (data == NULL) {
1837 pr_err("%s: data NULL\n", __func__);
1838 return -EINVAL;
1839 }
Meng Wang9730cdd2017-09-26 12:48:31 +08001840
1841 session_id = q6asm_get_session_id_from_audio_client(ac);
1842 if (session_id <= 0 || session_id > ASM_ACTIVE_STREAMS_ALLOWED) {
1843 pr_err("%s: Session ID is invalid, session = %d\n", __func__,
1844 session_id);
1845 return -EINVAL;
1846 }
Meng Wangb6afa8c2017-11-30 17:55:05 +08001847 spin_lock_irqsave(&(session[session_id].session_lock), flags);
Meng Wang9730cdd2017-09-26 12:48:31 +08001848
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301849 if (!q6asm_is_valid_audio_client(ac)) {
1850 pr_err("%s: audio client pointer is invalid, ac = %pK\n",
1851 __func__, ac);
Meng Wangb6afa8c2017-11-30 17:55:05 +08001852 spin_unlock_irqrestore(
1853 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301854 return -EINVAL;
1855 }
1856
1857 payload = data->payload;
1858 asm_token.token = data->token;
1859 if (q6asm_get_flag_from_token(&asm_token, ASM_CMD_NO_WAIT_OFFSET)) {
1860 pr_debug("%s: No wait command opcode[0x%x] cmd_opcode:%x\n",
1861 __func__, data->opcode, payload ? payload[0] : 0);
1862 wakeup_flag = 0;
1863 }
1864
1865 if (data->opcode == RESET_EVENTS) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301866 atomic_set(&ac->reset, 1);
1867 if (ac->apr == NULL) {
1868 ac->apr = ac->apr2;
1869 ac->apr2 = NULL;
1870 }
1871 pr_debug("%s: Reset event is received: %d %d apr[%pK]\n",
1872 __func__,
1873 data->reset_event, data->reset_proc, ac->apr);
1874 if (ac->cb)
1875 ac->cb(data->opcode, data->token,
1876 (uint32_t *)data->payload, ac->priv);
1877 apr_reset(ac->apr);
1878 ac->apr = NULL;
1879 atomic_set(&ac->time_flag, 0);
1880 atomic_set(&ac->cmd_state, 0);
1881 atomic_set(&ac->mem_state, 0);
1882 atomic_set(&ac->cmd_state_pp, 0);
1883 wake_up(&ac->time_wait);
1884 wake_up(&ac->cmd_wait);
1885 wake_up(&ac->mem_wait);
Meng Wangb6afa8c2017-11-30 17:55:05 +08001886 spin_unlock_irqrestore(
1887 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301888 return 0;
1889 }
1890
1891 dev_vdbg(ac->dev, "%s: session[%d]opcode[0x%x] token[0x%x]payload_size[%d] src[%d] dest[%d]\n",
1892 __func__,
1893 ac->session, data->opcode,
1894 data->token, data->payload_size, data->src_port,
1895 data->dest_port);
1896 if ((data->opcode != ASM_DATA_EVENT_RENDERED_EOS) &&
1897 (data->opcode != ASM_DATA_EVENT_EOS) &&
1898 (data->opcode != ASM_SESSION_EVENT_RX_UNDERFLOW)) {
1899 if (payload == NULL) {
1900 pr_err("%s: payload is null\n", __func__);
Meng Wangb6afa8c2017-11-30 17:55:05 +08001901 spin_unlock_irqrestore(
1902 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301903 return -EINVAL;
1904 }
1905 dev_vdbg(ac->dev, "%s: Payload = [0x%x] status[0x%x] opcode 0x%x\n",
1906 __func__, payload[0], payload[1], data->opcode);
1907 }
1908 if (data->opcode == APR_BASIC_RSP_RESULT) {
1909 switch (payload[0]) {
1910 case ASM_STREAM_CMD_SET_PP_PARAMS_V2:
1911 if (rtac_make_asm_callback(ac->session, payload,
1912 data->payload_size))
1913 break;
1914 case ASM_SESSION_CMD_PAUSE:
1915 case ASM_SESSION_CMD_SUSPEND:
1916 case ASM_DATA_CMD_EOS:
1917 case ASM_STREAM_CMD_CLOSE:
1918 case ASM_STREAM_CMD_FLUSH:
1919 case ASM_SESSION_CMD_RUN_V2:
1920 case ASM_SESSION_CMD_REGISTER_FORX_OVERFLOW_EVENTS:
1921 case ASM_STREAM_CMD_FLUSH_READBUFS:
1922 pr_debug("%s: session %d opcode 0x%x token 0x%x Payload = [0x%x] src %d dest %d\n",
1923 __func__, ac->session, data->opcode, data->token,
1924 payload[0], data->src_port, data->dest_port);
1925 ret = q6asm_is_valid_session(data, priv);
1926 if (ret != 0) {
1927 pr_err("%s: session invalid %d\n", __func__, ret);
Meng Wangb6afa8c2017-11-30 17:55:05 +08001928 spin_unlock_irqrestore(
1929 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301930 return ret;
1931 }
1932 case ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2:
1933 case ASM_STREAM_CMD_OPEN_READ_V3:
1934 case ASM_STREAM_CMD_OPEN_WRITE_V3:
1935 case ASM_STREAM_CMD_OPEN_PULL_MODE_WRITE:
1936 case ASM_STREAM_CMD_OPEN_PUSH_MODE_READ:
1937 case ASM_STREAM_CMD_OPEN_READWRITE_V2:
1938 case ASM_STREAM_CMD_OPEN_LOOPBACK_V2:
1939 case ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK:
1940 case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
1941 case ASM_DATA_CMD_IEC_60958_MEDIA_FMT:
1942 case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
1943 case ASM_STREAM_CMD_SET_ENCDEC_PARAM_V2:
1944 case ASM_STREAM_CMD_REGISTER_ENCDEC_EVENTS:
1945 case ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE:
1946 case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE:
1947 case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE:
1948 case ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS:
1949 case ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED:
1950 pr_debug("%s: session %d opcode 0x%x token 0x%x Payload = [0x%x] stat 0x%x src %d dest %d\n",
1951 __func__, ac->session,
1952 data->opcode, data->token,
1953 payload[0], payload[1],
1954 data->src_port, data->dest_port);
1955 if (payload[1] != 0) {
1956 pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
1957 __func__, payload[0], payload[1]);
1958 if (wakeup_flag) {
1959 if ((is_adsp_reg_event(payload[0]) >= 0)
1960 || (payload[0] ==
1961 ASM_STREAM_CMD_SET_PP_PARAMS_V2))
1962 atomic_set(&ac->cmd_state_pp,
1963 payload[1]);
1964 else
1965 atomic_set(&ac->cmd_state,
1966 payload[1]);
1967 wake_up(&ac->cmd_wait);
1968 }
Meng Wangb6afa8c2017-11-30 17:55:05 +08001969 spin_unlock_irqrestore(
1970 &(session[session_id].session_lock),
1971 flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301972 return 0;
1973 }
1974 if ((is_adsp_reg_event(payload[0]) >= 0) ||
1975 (payload[0] == ASM_STREAM_CMD_SET_PP_PARAMS_V2)) {
1976 if (atomic_read(&ac->cmd_state_pp) &&
1977 wakeup_flag) {
1978 atomic_set(&ac->cmd_state_pp, 0);
1979 wake_up(&ac->cmd_wait);
1980 }
1981 } else {
1982 if (atomic_read(&ac->cmd_state) &&
1983 wakeup_flag) {
1984 atomic_set(&ac->cmd_state, 0);
1985 wake_up(&ac->cmd_wait);
1986 }
1987 }
1988 if (ac->cb)
1989 ac->cb(data->opcode, data->token,
1990 (uint32_t *)data->payload, ac->priv);
1991 break;
1992 case ASM_CMD_ADD_TOPOLOGIES:
1993 pr_debug("%s:Payload = [0x%x]stat[0x%x]\n",
1994 __func__, payload[0], payload[1]);
1995 if (payload[1] != 0) {
1996 pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
1997 __func__, payload[0], payload[1]);
1998 if (wakeup_flag) {
1999 atomic_set(&ac->mem_state, payload[1]);
2000 wake_up(&ac->mem_wait);
2001 }
Meng Wangb6afa8c2017-11-30 17:55:05 +08002002 spin_unlock_irqrestore(
2003 &(session[session_id].session_lock),
2004 flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302005 return 0;
2006 }
2007 if (atomic_read(&ac->mem_state) && wakeup_flag) {
2008 atomic_set(&ac->mem_state, 0);
2009 wake_up(&ac->mem_wait);
2010 }
2011 if (ac->cb)
2012 ac->cb(data->opcode, data->token,
2013 (uint32_t *)data->payload, ac->priv);
2014 break;
2015 case ASM_DATA_EVENT_WATERMARK: {
2016 pr_debug("%s: Watermark opcode[0x%x] status[0x%x]",
2017 __func__, payload[0], payload[1]);
2018 break;
2019 }
2020 case ASM_STREAM_CMD_GET_PP_PARAMS_V2:
2021 pr_debug("%s: ASM_STREAM_CMD_GET_PP_PARAMS_V2 session %d opcode 0x%x token 0x%x src %d dest %d\n",
2022 __func__, ac->session,
2023 data->opcode, data->token,
2024 data->src_port, data->dest_port);
2025 /* Should only come here if there is an APR */
2026 /* error or malformed APR packet. Otherwise */
2027 /* response will be returned as */
2028 /* ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2 */
2029 if (payload[1] != 0) {
2030 pr_err("%s: ASM get param error = %d, resuming\n",
2031 __func__, payload[1]);
2032 rtac_make_asm_callback(ac->session, payload,
2033 data->payload_size);
2034 }
2035 break;
2036 case ASM_STREAM_CMD_REGISTER_PP_EVENTS:
2037 pr_debug("%s: ASM_STREAM_CMD_REGISTER_PP_EVENTS session %d opcode 0x%x token 0x%x src %d dest %d\n",
2038 __func__, ac->session,
2039 data->opcode, data->token,
2040 data->src_port, data->dest_port);
2041 if (payload[1] != 0)
2042 pr_err("%s: ASM get param error = %d, resuming\n",
2043 __func__, payload[1]);
2044 atomic_set(&ac->cmd_state_pp, payload[1]);
2045 wake_up(&ac->cmd_wait);
2046 break;
2047 default:
2048 pr_debug("%s: command[0x%x] not expecting rsp\n",
2049 __func__, payload[0]);
2050 break;
2051 }
Meng Wang9730cdd2017-09-26 12:48:31 +08002052
Meng Wangb6afa8c2017-11-30 17:55:05 +08002053 spin_unlock_irqrestore(
2054 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302055 return 0;
2056 }
2057
2058 switch (data->opcode) {
2059 case ASM_DATA_EVENT_WRITE_DONE_V2:{
2060 struct audio_port_data *port = &ac->port[IN];
2061
2062 dev_vdbg(ac->dev, "%s: Rxed opcode[0x%x] status[0x%x] token[%d]",
2063 __func__, payload[0], payload[1],
2064 data->token);
2065 if (ac->io_mode & SYNC_IO_MODE) {
2066 if (port->buf == NULL) {
2067 pr_err("%s: Unexpected Write Done\n",
2068 __func__);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002069 spin_unlock_irqrestore(
2070 &(session[session_id].session_lock),
2071 flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302072 return -EINVAL;
2073 }
2074 spin_lock_irqsave(&port->dsp_lock, dsp_flags);
2075 buf_index = asm_token._token.buf_index;
2076 if (lower_32_bits(port->buf[buf_index].phys) !=
2077 payload[0] ||
2078 msm_audio_populate_upper_32_bits(
2079 port->buf[buf_index].phys) != payload[1]) {
2080 pr_debug("%s: Expected addr %pK\n",
2081 __func__, &port->buf[buf_index].phys);
2082 pr_err("%s: rxedl[0x%x] rxedu [0x%x]\n",
2083 __func__, payload[0], payload[1]);
2084 spin_unlock_irqrestore(&port->dsp_lock,
2085 dsp_flags);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002086 spin_unlock_irqrestore(
2087 &(session[session_id].session_lock),
2088 flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302089 return -EINVAL;
2090 }
2091 port->buf[buf_index].used = 1;
2092 spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
2093
2094 config_debug_fs_write_cb();
2095
2096 for (i = 0; i < port->max_buf_cnt; i++)
2097 dev_vdbg(ac->dev, "%s %d\n",
2098 __func__, port->buf[i].used);
2099
2100 }
2101 break;
2102 }
2103 case ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2:
2104 pr_debug("%s: ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2 session %d opcode 0x%x token 0x%x src %d dest %d\n",
2105 __func__, ac->session, data->opcode,
2106 data->token,
2107 data->src_port, data->dest_port);
2108 if (payload[0] != 0) {
2109 pr_err("%s: ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2 returned error = 0x%x\n",
2110 __func__, payload[0]);
2111 } else if (generic_get_data) {
2112 generic_get_data->valid = 1;
2113 if (generic_get_data->is_inband) {
2114 pr_debug("%s: payload[1] = 0x%x, payload[2]=0x%x, payload[3]=0x%x\n",
2115 __func__, payload[1], payload[2], payload[3]);
2116 generic_get_data->size_in_ints = payload[3]>>2;
2117 for (i = 0; i < payload[3]>>2; i++) {
2118 generic_get_data->ints[i] =
2119 payload[4+i];
2120 pr_debug("%s: ASM callback val %i = %i\n",
2121 __func__, i, payload[4+i]);
2122 }
2123 pr_debug("%s: callback size in ints = %i\n",
2124 __func__,
2125 generic_get_data->size_in_ints);
2126 }
2127 if (atomic_read(&ac->cmd_state) && wakeup_flag) {
2128 atomic_set(&ac->cmd_state, 0);
2129 wake_up(&ac->cmd_wait);
2130 }
2131 break;
2132 }
2133 rtac_make_asm_callback(ac->session, payload,
2134 data->payload_size);
2135 break;
2136 case ASM_DATA_EVENT_READ_DONE_V2:{
2137
2138 struct audio_port_data *port = &ac->port[OUT];
2139
2140 config_debug_fs_read_cb();
2141
2142 dev_vdbg(ac->dev, "%s: ReadDone: status=%d buff_add=0x%x act_size=%d offset=%d\n",
2143 __func__, payload[READDONE_IDX_STATUS],
2144 payload[READDONE_IDX_BUFADD_LSW],
2145 payload[READDONE_IDX_SIZE],
2146 payload[READDONE_IDX_OFFSET]);
2147
2148 dev_vdbg(ac->dev, "%s: ReadDone:msw_ts=%d lsw_ts=%d memmap_hdl=0x%x flags=%d id=%d num=%d\n",
2149 __func__, payload[READDONE_IDX_MSW_TS],
2150 payload[READDONE_IDX_LSW_TS],
2151 payload[READDONE_IDX_MEMMAP_HDL],
2152 payload[READDONE_IDX_FLAGS],
2153 payload[READDONE_IDX_SEQ_ID],
2154 payload[READDONE_IDX_NUMFRAMES]);
2155
2156 if (ac->io_mode & SYNC_IO_MODE) {
2157 if (port->buf == NULL) {
2158 pr_err("%s: Unexpected Write Done\n", __func__);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002159 spin_unlock_irqrestore(
2160 &(session[session_id].session_lock),
2161 flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302162 return -EINVAL;
2163 }
2164 spin_lock_irqsave(&port->dsp_lock, dsp_flags);
2165 buf_index = asm_token._token.buf_index;
2166 port->buf[buf_index].used = 0;
2167 if (lower_32_bits(port->buf[buf_index].phys) !=
2168 payload[READDONE_IDX_BUFADD_LSW] ||
2169 msm_audio_populate_upper_32_bits(
2170 port->buf[buf_index].phys) !=
2171 payload[READDONE_IDX_BUFADD_MSW]) {
2172 dev_vdbg(ac->dev, "%s: Expected addr %pK\n",
2173 __func__, &port->buf[buf_index].phys);
2174 pr_err("%s: rxedl[0x%x] rxedu[0x%x]\n",
2175 __func__,
2176 payload[READDONE_IDX_BUFADD_LSW],
2177 payload[READDONE_IDX_BUFADD_MSW]);
2178 spin_unlock_irqrestore(&port->dsp_lock,
2179 dsp_flags);
2180 break;
2181 }
2182 port->buf[buf_index].actual_size =
2183 payload[READDONE_IDX_SIZE];
2184 spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
2185 }
2186 break;
2187 }
2188 case ASM_DATA_EVENT_EOS:
2189 case ASM_DATA_EVENT_RENDERED_EOS:
2190 pr_debug("%s: EOS ACK received: rxed session %d opcode 0x%x token 0x%x src %d dest %d\n",
2191 __func__, ac->session,
2192 data->opcode, data->token,
2193 data->src_port, data->dest_port);
2194 break;
2195 case ASM_SESSION_EVENTX_OVERFLOW:
2196 pr_debug("%s: ASM_SESSION_EVENTX_OVERFLOW session %d opcode 0x%x token 0x%x src %d dest %d\n",
2197 __func__, ac->session,
2198 data->opcode, data->token,
2199 data->src_port, data->dest_port);
2200 break;
2201 case ASM_SESSION_EVENT_RX_UNDERFLOW:
2202 pr_debug("%s: ASM_SESSION_EVENT_RX_UNDERFLOW session %d opcode 0x%x token 0x%x src %d dest %d\n",
2203 __func__, ac->session,
2204 data->opcode, data->token,
2205 data->src_port, data->dest_port);
2206 break;
2207 case ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3:
2208 dev_vdbg(ac->dev, "%s: ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3, payload[0] = %d, payload[1] = %d, payload[2] = %d\n",
2209 __func__,
2210 payload[0], payload[1], payload[2]);
2211 ac->time_stamp = (uint64_t)(((uint64_t)payload[2] << 32) |
2212 payload[1]);
2213 if (atomic_cmpxchg(&ac->time_flag, 1, 0))
2214 wake_up(&ac->time_wait);
2215 break;
2216 case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
2217 case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY:
2218 pr_debug("%s: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY session %d opcode 0x%x token 0x%x src %d dest %d\n",
2219 __func__, ac->session,
2220 data->opcode, data->token,
2221 data->src_port, data->dest_port);
2222 pr_debug("%s: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, payload[0] = %d, payload[1] = %d, payload[2] = %d, payload[3] = %d\n",
2223 __func__,
2224 payload[0], payload[1], payload[2],
2225 payload[3]);
2226 break;
2227 case ASM_SESSION_CMDRSP_GET_MTMX_STRTR_PARAMS_V2:
2228 q6asm_process_mtmx_get_param_rsp(ac, (void *) payload);
2229 break;
2230 case ASM_STREAM_PP_EVENT:
2231 case ASM_STREAM_CMD_ENCDEC_EVENTS:
2232 case ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE:
2233 pr_debug("%s: ASM_STREAM_EVENT payload[0][0x%x] payload[1][0x%x]",
2234 __func__, payload[0], payload[1]);
2235 i = is_adsp_raise_event(data->opcode);
Meng Wang9730cdd2017-09-26 12:48:31 +08002236 if (i < 0) {
Meng Wangb6afa8c2017-11-30 17:55:05 +08002237 spin_unlock_irqrestore(
2238 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302239 return 0;
Meng Wang9730cdd2017-09-26 12:48:31 +08002240 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302241
2242 /* repack payload for asm_stream_pp_event
2243 * package is composed of event type + size + actual payload
2244 */
2245 payload_size = data->payload_size;
2246 pp_event_package = kzalloc(payload_size
2247 + sizeof(struct msm_adsp_event_data),
2248 GFP_ATOMIC);
Meng Wang9730cdd2017-09-26 12:48:31 +08002249 if (!pp_event_package) {
Meng Wangb6afa8c2017-11-30 17:55:05 +08002250 spin_unlock_irqrestore(
2251 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302252 return -ENOMEM;
Meng Wang9730cdd2017-09-26 12:48:31 +08002253 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302254
2255 pp_event_package->event_type = i;
2256 pp_event_package->payload_len = payload_size;
2257 memcpy((void *)pp_event_package->payload,
2258 data->payload, payload_size);
2259 ac->cb(data->opcode, data->token,
2260 (void *)pp_event_package, ac->priv);
2261 kfree(pp_event_package);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002262 spin_unlock_irqrestore(
2263 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302264 return 0;
2265 case ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2:
2266 pr_debug("%s: ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2 sesion %d status 0x%x msw %u lsw %u\n",
2267 __func__, ac->session, payload[0], payload[2],
2268 payload[1]);
2269 wake_up(&ac->cmd_wait);
2270 break;
2271 case ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2:
2272 pr_debug("%s: ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2 session %d status 0x%x msw %u lsw %u\n",
2273 __func__, ac->session, payload[0], payload[2],
2274 payload[1]);
2275 if (payload[0] == 0) {
2276 atomic_set(&ac->cmd_state, 0);
2277 /* ignore msw, as a delay that large shouldn't happen */
2278 ac->path_delay = payload[1];
2279 } else {
2280 atomic_set(&ac->cmd_state, payload[0]);
2281 ac->path_delay = UINT_MAX;
2282 }
2283 wake_up(&ac->cmd_wait);
2284 break;
2285 }
2286 if (ac->cb)
2287 ac->cb(data->opcode, data->token,
2288 data->payload, ac->priv);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002289 spin_unlock_irqrestore(
2290 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302291 return 0;
2292}
2293
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302294/**
2295 * q6asm_is_cpu_buf_avail -
2296 * retrieve next CPU buf avail
2297 *
2298 * @dir: RX or TX direction
2299 * @ac: Audio client handle
2300 * @size: size pointer to be updated with size of buffer
2301 * @index: index pointer to be updated with
2302 * CPU buffer index available
2303 *
2304 * Returns buffer pointer on success or NULL on failure
2305 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302306void *q6asm_is_cpu_buf_avail(int dir, struct audio_client *ac, uint32_t *size,
2307 uint32_t *index)
2308{
2309 void *data;
2310 unsigned char idx;
2311 struct audio_port_data *port;
2312
2313 if (!ac || ((dir != IN) && (dir != OUT))) {
2314 pr_err("%s: ac %pK dir %d\n", __func__, ac, dir);
2315 return NULL;
2316 }
2317
2318 if (ac->io_mode & SYNC_IO_MODE) {
2319 port = &ac->port[dir];
2320
2321 mutex_lock(&port->lock);
2322 idx = port->cpu_buf;
2323 if (port->buf == NULL) {
2324 pr_err("%s: Buffer pointer null\n", __func__);
2325 mutex_unlock(&port->lock);
2326 return NULL;
2327 }
2328 /* dir 0: used = 0 means buf in use
2329 * dir 1: used = 1 means buf in use
2330 */
2331 if (port->buf[idx].used == dir) {
2332 /* To make it more robust, we could loop and get the
2333 * next avail buf, its risky though
2334 */
2335 pr_err("%s: Next buf idx[0x%x] not available, dir[%d]\n",
2336 __func__, idx, dir);
2337 mutex_unlock(&port->lock);
2338 return NULL;
2339 }
2340 *size = port->buf[idx].actual_size;
2341 *index = port->cpu_buf;
2342 data = port->buf[idx].data;
2343 dev_vdbg(ac->dev, "%s: session[%d]index[%d] data[%pK]size[%d]\n",
2344 __func__,
2345 ac->session,
2346 port->cpu_buf,
2347 data, *size);
2348 /* By default increase the cpu_buf cnt
2349 * user accesses this function,increase cpu
2350 * buf(to avoid another api)
2351 */
2352 port->buf[idx].used = dir;
2353 port->cpu_buf = q6asm_get_next_buf(ac, port->cpu_buf,
2354 port->max_buf_cnt);
2355 mutex_unlock(&port->lock);
2356 return data;
2357 }
2358 return NULL;
2359}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302360EXPORT_SYMBOL(q6asm_is_cpu_buf_avail);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302361
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302362/**
2363 * q6asm_cpu_buf_release -
2364 * releases cpu buffer for ASM
2365 *
2366 * @dir: RX or TX direction
2367 * @ac: Audio client handle
2368 *
2369 * Returns 0 on success or error on failure
2370 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302371int q6asm_cpu_buf_release(int dir, struct audio_client *ac)
2372{
2373 struct audio_port_data *port;
2374 int ret = 0;
2375 int idx;
2376
2377 if (!ac || ((dir != IN) && (dir != OUT))) {
2378 pr_err("%s: ac %pK dir %d\n", __func__, ac, dir);
2379 ret = -EINVAL;
2380 goto exit;
2381 }
2382
2383 if (ac->io_mode & SYNC_IO_MODE) {
2384 port = &ac->port[dir];
2385 mutex_lock(&port->lock);
2386 idx = port->cpu_buf;
2387 if (port->cpu_buf == 0) {
2388 port->cpu_buf = port->max_buf_cnt - 1;
2389 } else if (port->cpu_buf < port->max_buf_cnt) {
2390 port->cpu_buf = port->cpu_buf - 1;
2391 } else {
2392 pr_err("%s: buffer index(%d) out of range\n",
2393 __func__, port->cpu_buf);
2394 ret = -EINVAL;
2395 mutex_unlock(&port->lock);
2396 goto exit;
2397 }
2398 port->buf[port->cpu_buf].used = dir ^ 1;
2399 mutex_unlock(&port->lock);
2400 }
2401exit:
2402 return ret;
2403}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302404EXPORT_SYMBOL(q6asm_cpu_buf_release);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302405
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302406/**
2407 * q6asm_is_cpu_buf_avail_nolock -
2408 * retrieve next CPU buf avail without lock acquire
2409 *
2410 * @dir: RX or TX direction
2411 * @ac: Audio client handle
2412 * @size: size pointer to be updated with size of buffer
2413 * @index: index pointer to be updated with
2414 * CPU buffer index available
2415 *
2416 * Returns buffer pointer on success or NULL on failure
2417 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302418void *q6asm_is_cpu_buf_avail_nolock(int dir, struct audio_client *ac,
2419 uint32_t *size, uint32_t *index)
2420{
2421 void *data;
2422 unsigned char idx;
2423 struct audio_port_data *port;
2424
2425 if (!ac || ((dir != IN) && (dir != OUT))) {
2426 pr_err("%s: ac %pK dir %d\n", __func__, ac, dir);
2427 return NULL;
2428 }
2429
2430 port = &ac->port[dir];
2431
2432 idx = port->cpu_buf;
2433 if (port->buf == NULL) {
2434 pr_err("%s: Buffer pointer null\n", __func__);
2435 return NULL;
2436 }
2437 /*
2438 * dir 0: used = 0 means buf in use
2439 * dir 1: used = 1 means buf in use
2440 */
2441 if (port->buf[idx].used == dir) {
2442 /*
2443 * To make it more robust, we could loop and get the
2444 * next avail buf, its risky though
2445 */
2446 pr_err("%s: Next buf idx[0x%x] not available, dir[%d]\n",
2447 __func__, idx, dir);
2448 return NULL;
2449 }
2450 *size = port->buf[idx].actual_size;
2451 *index = port->cpu_buf;
2452 data = port->buf[idx].data;
2453 dev_vdbg(ac->dev, "%s: session[%d]index[%d] data[%pK]size[%d]\n",
2454 __func__, ac->session, port->cpu_buf,
2455 data, *size);
2456 /*
2457 * By default increase the cpu_buf cnt
2458 * user accesses this function,increase cpu
2459 * buf(to avoid another api)
2460 */
2461 port->buf[idx].used = dir;
2462 port->cpu_buf = q6asm_get_next_buf(ac, port->cpu_buf,
2463 port->max_buf_cnt);
2464 return data;
2465}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302466EXPORT_SYMBOL(q6asm_is_cpu_buf_avail_nolock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302467
2468int q6asm_is_dsp_buf_avail(int dir, struct audio_client *ac)
2469{
2470 int ret = -1;
2471 struct audio_port_data *port;
2472 uint32_t idx;
2473
2474 if (!ac || (dir != OUT)) {
2475 pr_err("%s: ac %pK dir %d\n", __func__, ac, dir);
2476 return ret;
2477 }
2478
2479 if (ac->io_mode & SYNC_IO_MODE) {
2480 port = &ac->port[dir];
2481
2482 mutex_lock(&port->lock);
2483 idx = port->dsp_buf;
2484
2485 if (port->buf[idx].used == (dir ^ 1)) {
2486 /* To make it more robust, we could loop and get the
2487 * next avail buf, its risky though
2488 */
2489 pr_err("%s: Next buf idx[0x%x] not available, dir[%d]\n",
2490 __func__, idx, dir);
2491 mutex_unlock(&port->lock);
2492 return ret;
2493 }
2494 dev_vdbg(ac->dev, "%s: session[%d]dsp_buf=%d cpu_buf=%d\n",
2495 __func__,
2496 ac->session, port->dsp_buf, port->cpu_buf);
2497 ret = ((port->dsp_buf != port->cpu_buf) ? 0 : -1);
2498 mutex_unlock(&port->lock);
2499 }
2500 return ret;
2501}
2502
2503static void __q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
2504 uint32_t pkt_size, uint32_t cmd_flg, uint32_t stream_id)
2505{
Meng Wangb6afa8c2017-11-30 17:55:05 +08002506 unsigned long flags;
2507
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302508 dev_vdbg(ac->dev, "%s: pkt_size=%d cmd_flg=%d session=%d stream_id=%d\n",
2509 __func__, pkt_size, cmd_flg, ac->session, stream_id);
2510 mutex_lock(&ac->cmd_lock);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002511 spin_lock_irqsave(&(session[ac->session].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302512 if (ac->apr == NULL) {
2513 pr_err("%s: AC APR handle NULL", __func__);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002514 spin_unlock_irqrestore(
2515 &(session[ac->session].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302516 mutex_unlock(&ac->cmd_lock);
2517 return;
2518 }
2519
2520 hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
2521 APR_HDR_LEN(sizeof(struct apr_hdr)),
2522 APR_PKT_VER);
2523 hdr->src_svc = ((struct apr_svc *)ac->apr)->id;
2524 hdr->src_domain = APR_DOMAIN_APPS;
2525 hdr->dest_svc = APR_SVC_ASM;
2526 hdr->dest_domain = APR_DOMAIN_ADSP;
2527 hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id);
2528 hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id);
2529 if (cmd_flg)
2530 q6asm_update_token(&hdr->token,
2531 ac->session,
2532 0, /* Stream ID is NA */
2533 0, /* Buffer index is NA */
2534 0, /* Direction flag is NA */
2535 WAIT_CMD);
2536
2537 hdr->pkt_size = pkt_size;
Meng Wangb6afa8c2017-11-30 17:55:05 +08002538 spin_unlock_irqrestore(
2539 &(session[ac->session].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302540 mutex_unlock(&ac->cmd_lock);
2541}
2542
2543static void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
2544 uint32_t pkt_size, uint32_t cmd_flg)
2545{
2546 __q6asm_add_hdr(ac, hdr, pkt_size, cmd_flg, ac->stream_id);
2547}
2548
2549static void q6asm_stream_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
2550 uint32_t pkt_size, uint32_t cmd_flg, int32_t stream_id)
2551{
2552 __q6asm_add_hdr(ac, hdr, pkt_size, cmd_flg, stream_id);
2553}
2554
2555static void __q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
2556 uint32_t pkt_size, uint32_t cmd_flg,
2557 uint32_t stream_id, u8 no_wait_flag)
2558{
2559 dev_vdbg(ac->dev, "%s: pkt_size = %d, cmd_flg = %d, session = %d stream_id=%d\n",
2560 __func__, pkt_size, cmd_flg, ac->session, stream_id);
2561 hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
2562 APR_HDR_LEN(sizeof(struct apr_hdr)),
2563 APR_PKT_VER);
2564 if (ac->apr == NULL) {
2565 pr_err("%s: AC APR is NULL", __func__);
2566 return;
2567 }
2568 hdr->src_svc = ((struct apr_svc *)ac->apr)->id;
2569 hdr->src_domain = APR_DOMAIN_APPS;
2570 hdr->dest_svc = APR_SVC_ASM;
2571 hdr->dest_domain = APR_DOMAIN_ADSP;
2572 hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id);
2573 hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id);
2574 if (cmd_flg) {
2575 q6asm_update_token(&hdr->token,
2576 ac->session,
2577 0, /* Stream ID is NA */
2578 0, /* Buffer index is NA */
2579 0, /* Direction flag is NA */
2580 no_wait_flag);
2581
2582 }
2583 hdr->pkt_size = pkt_size;
2584}
2585
2586static void q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
2587 uint32_t pkt_size, uint32_t cmd_flg)
2588{
2589 __q6asm_add_hdr_async(ac, hdr, pkt_size, cmd_flg,
2590 ac->stream_id, WAIT_CMD);
2591}
2592
2593static void q6asm_stream_add_hdr_async(struct audio_client *ac,
2594 struct apr_hdr *hdr, uint32_t pkt_size,
2595 uint32_t cmd_flg, int32_t stream_id)
2596{
2597 __q6asm_add_hdr_async(ac, hdr, pkt_size, cmd_flg,
2598 stream_id, NO_WAIT_CMD);
2599}
2600
2601static void q6asm_add_hdr_custom_topology(struct audio_client *ac,
2602 struct apr_hdr *hdr,
2603 uint32_t pkt_size)
2604{
2605 pr_debug("%s: pkt_size=%d session=%d\n",
2606 __func__, pkt_size, ac->session);
2607 if (ac->apr == NULL) {
2608 pr_err("%s: AC APR handle NULL\n", __func__);
2609 return;
2610 }
2611
2612 mutex_lock(&ac->cmd_lock);
2613 hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
2614 APR_HDR_LEN(sizeof(struct apr_hdr)),
2615 APR_PKT_VER);
2616 hdr->src_svc = ((struct apr_svc *)ac->apr)->id;
2617 hdr->src_domain = APR_DOMAIN_APPS;
2618 hdr->dest_svc = APR_SVC_ASM;
2619 hdr->dest_domain = APR_DOMAIN_ADSP;
2620 hdr->src_port = ((ac->session << 8) & 0xFF00) | 0x01;
2621 hdr->dest_port = 0;
2622 q6asm_update_token(&hdr->token,
2623 ac->session,
2624 0, /* Stream ID is NA */
2625 0, /* Buffer index is NA */
2626 0, /* Direction flag is NA */
2627 WAIT_CMD);
2628 hdr->pkt_size = pkt_size;
2629 mutex_unlock(&ac->cmd_lock);
2630}
2631
2632static void q6asm_add_mmaphdr(struct audio_client *ac, struct apr_hdr *hdr,
2633 u32 pkt_size, int dir)
2634{
2635 pr_debug("%s: pkt size=%d\n",
2636 __func__, pkt_size);
2637 hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
2638 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
2639 hdr->src_port = 0;
2640 hdr->dest_port = 0;
2641 q6asm_update_token(&hdr->token,
2642 ac->session,
2643 0, /* Stream ID is NA */
2644 0, /* Buffer index is NA */
2645 dir,
2646 WAIT_CMD);
2647 hdr->pkt_size = pkt_size;
2648}
2649
2650static int __q6asm_open_read(struct audio_client *ac,
2651 uint32_t format, uint16_t bits_per_sample,
2652 uint32_t pcm_format_block_ver,
2653 bool ts_mode)
2654{
2655 int rc = 0x00;
2656 struct asm_stream_cmd_open_read_v3 open;
2657
2658 config_debug_fs_reset_index();
2659
2660 if (ac == NULL) {
2661 pr_err("%s: APR handle NULL\n", __func__);
2662 return -EINVAL;
2663 }
2664 if (ac->apr == NULL) {
2665 pr_err("%s: AC APR handle NULL\n", __func__);
2666 return -EINVAL;
2667 }
2668 pr_debug("%s: session[%d]\n", __func__, ac->session);
2669
2670 q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
2671 atomic_set(&ac->cmd_state, -1);
2672 open.hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V3;
2673 /* Stream prio : High, provide meta info with encoded frames */
2674 open.src_endpointype = ASM_END_POINT_DEVICE_MATRIX;
2675
2676 open.preprocopo_id = q6asm_get_asm_topology_cal();
2677 open.bits_per_sample = bits_per_sample;
2678 open.mode_flags = 0x0;
2679
2680 ac->topology = open.preprocopo_id;
2681 ac->app_type = q6asm_get_asm_app_type_cal();
2682 if (ac->perf_mode == LOW_LATENCY_PCM_MODE) {
2683 open.mode_flags |= ASM_LOW_LATENCY_TX_STREAM_SESSION <<
2684 ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
2685 } else {
2686 open.mode_flags |= ASM_LEGACY_STREAM_SESSION <<
2687 ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
2688 }
2689
2690 switch (format) {
2691 case FORMAT_LINEAR_PCM:
2692 open.mode_flags |= 0x00;
2693 open.enc_cfg_id = q6asm_get_pcm_format_id(pcm_format_block_ver);
2694 if (ts_mode)
2695 open.mode_flags |= ABSOLUTE_TIMESTAMP_ENABLE;
2696 break;
2697 case FORMAT_MPEG4_AAC:
2698 open.mode_flags |= BUFFER_META_ENABLE;
2699 open.enc_cfg_id = ASM_MEDIA_FMT_AAC_V2;
2700 break;
2701 case FORMAT_G711_ALAW_FS:
2702 open.mode_flags |= BUFFER_META_ENABLE;
2703 open.enc_cfg_id = ASM_MEDIA_FMT_G711_ALAW_FS;
2704 break;
2705 case FORMAT_G711_MLAW_FS:
2706 open.mode_flags |= BUFFER_META_ENABLE;
2707 open.enc_cfg_id = ASM_MEDIA_FMT_G711_MLAW_FS;
2708 break;
2709 case FORMAT_V13K:
2710 open.mode_flags |= BUFFER_META_ENABLE;
2711 open.enc_cfg_id = ASM_MEDIA_FMT_V13K_FS;
2712 break;
2713 case FORMAT_EVRC:
2714 open.mode_flags |= BUFFER_META_ENABLE;
2715 open.enc_cfg_id = ASM_MEDIA_FMT_EVRC_FS;
2716 break;
2717 case FORMAT_AMRNB:
2718 open.mode_flags |= BUFFER_META_ENABLE;
2719 open.enc_cfg_id = ASM_MEDIA_FMT_AMRNB_FS;
2720 break;
2721 case FORMAT_AMRWB:
2722 open.mode_flags |= BUFFER_META_ENABLE;
2723 open.enc_cfg_id = ASM_MEDIA_FMT_AMRWB_FS;
2724 break;
2725 default:
2726 pr_err("%s: Invalid format 0x%x\n",
2727 __func__, format);
2728 rc = -EINVAL;
2729 goto fail_cmd;
2730 }
2731 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
2732 if (rc < 0) {
2733 pr_err("%s: open failed op[0x%x]rc[%d]\n",
2734 __func__, open.hdr.opcode, rc);
2735 rc = -EINVAL;
2736 goto fail_cmd;
2737 }
2738 rc = wait_event_timeout(ac->cmd_wait,
2739 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
2740 if (!rc) {
2741 pr_err("%s: timeout. waited for open read\n",
2742 __func__);
2743 rc = -ETIMEDOUT;
2744 goto fail_cmd;
2745 }
2746 if (atomic_read(&ac->cmd_state) > 0) {
2747 pr_err("%s: DSP returned error[%s]\n",
2748 __func__, adsp_err_get_err_str(
2749 atomic_read(&ac->cmd_state)));
2750 rc = adsp_err_get_lnx_err_code(
2751 atomic_read(&ac->cmd_state));
2752 goto fail_cmd;
2753 }
2754
2755 ac->io_mode |= TUN_READ_IO_MODE;
2756
2757 return 0;
2758fail_cmd:
2759 return rc;
2760}
2761
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302762/**
2763 * q6asm_open_read -
2764 * command to open ASM in read mode
2765 *
2766 * @ac: Audio client handle
2767 * @format: capture format for ASM
2768 *
2769 * Returns 0 on success or error on failure
2770 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302771int q6asm_open_read(struct audio_client *ac,
2772 uint32_t format)
2773{
2774 return __q6asm_open_read(ac, format, 16,
2775 PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/,
2776 false/*ts_mode*/);
2777}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302778EXPORT_SYMBOL(q6asm_open_read);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302779
2780int q6asm_open_read_v2(struct audio_client *ac, uint32_t format,
2781 uint16_t bits_per_sample)
2782{
2783 return __q6asm_open_read(ac, format, bits_per_sample,
2784 PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/,
2785 false/*ts_mode*/);
2786}
2787
2788/*
2789 * asm_open_read_v3 - Opens audio capture session
2790 *
2791 * @ac: Client session handle
2792 * @format: encoder format
2793 * @bits_per_sample: bit width of capture session
2794 */
2795int q6asm_open_read_v3(struct audio_client *ac, uint32_t format,
2796 uint16_t bits_per_sample)
2797{
2798 return __q6asm_open_read(ac, format, bits_per_sample,
2799 PCM_MEDIA_FORMAT_V3/*media fmt block ver*/,
2800 false/*ts_mode*/);
2801}
2802EXPORT_SYMBOL(q6asm_open_read_v3);
2803
2804/*
2805 * asm_open_read_v4 - Opens audio capture session
2806 *
2807 * @ac: Client session handle
2808 * @format: encoder format
2809 * @bits_per_sample: bit width of capture session
2810 * @ts_mode: timestamp mode
2811 */
2812int q6asm_open_read_v4(struct audio_client *ac, uint32_t format,
2813 uint16_t bits_per_sample, bool ts_mode)
2814{
2815 return __q6asm_open_read(ac, format, bits_per_sample,
2816 PCM_MEDIA_FORMAT_V4 /*media fmt block ver*/,
2817 ts_mode);
2818}
2819EXPORT_SYMBOL(q6asm_open_read_v4);
2820
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302821/**
2822 * q6asm_open_write_compressed -
2823 * command to open ASM in compressed write mode
2824 *
2825 * @ac: Audio client handle
2826 * @format: playback format for ASM
2827 * @passthrough_flag: flag to indicate passthrough option
2828 *
2829 * Returns 0 on success or error on failure
2830 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302831int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format,
2832 uint32_t passthrough_flag)
2833{
2834 int rc = 0;
2835 struct asm_stream_cmd_open_write_compressed open;
2836
2837 if (ac == NULL) {
2838 pr_err("%s: ac[%pK] NULL\n", __func__, ac);
2839 rc = -EINVAL;
2840 goto fail_cmd;
2841 }
2842
2843 if (ac->apr == NULL) {
2844 pr_err("%s: APR handle[%pK] NULL\n", __func__, ac->apr);
2845 rc = -EINVAL;
2846 goto fail_cmd;
2847 }
2848 pr_debug("%s: session[%d] wr_format[0x%x]", __func__, ac->session,
2849 format);
2850
2851 q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
2852 open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED;
2853 atomic_set(&ac->cmd_state, -1);
2854
2855 switch (format) {
2856 case FORMAT_AC3:
2857 open.fmt_id = ASM_MEDIA_FMT_AC3;
2858 break;
2859 case FORMAT_EAC3:
2860 open.fmt_id = ASM_MEDIA_FMT_EAC3;
2861 break;
2862 case FORMAT_DTS:
2863 open.fmt_id = ASM_MEDIA_FMT_DTS;
2864 break;
2865 case FORMAT_DSD:
2866 open.fmt_id = ASM_MEDIA_FMT_DSD;
2867 break;
2868 case FORMAT_GEN_COMPR:
2869 open.fmt_id = ASM_MEDIA_FMT_GENERIC_COMPRESSED;
2870 break;
2871 case FORMAT_TRUEHD:
2872 open.fmt_id = ASM_MEDIA_FMT_TRUEHD;
2873 break;
2874 case FORMAT_IEC61937:
2875 open.fmt_id = ASM_MEDIA_FMT_IEC;
2876 break;
2877 default:
2878 pr_err("%s: Invalid format[%d]\n", __func__, format);
2879 rc = -EINVAL;
2880 goto fail_cmd;
2881 }
2882 /* Below flag indicates the DSP that Compressed audio input
2883 * stream is not IEC 61937 or IEC 60958 packetizied
2884 */
2885 if (passthrough_flag == COMPRESSED_PASSTHROUGH ||
2886 passthrough_flag == COMPRESSED_PASSTHROUGH_DSD ||
2887 passthrough_flag == COMPRESSED_PASSTHROUGH_GEN) {
2888 open.flags = 0x0;
2889 pr_debug("%s: Flag 0 COMPRESSED_PASSTHROUGH\n", __func__);
2890 } else if (passthrough_flag == COMPRESSED_PASSTHROUGH_CONVERT) {
2891 open.flags = 0x8;
2892 pr_debug("%s: Flag 8 - COMPRESSED_PASSTHROUGH_CONVERT\n",
2893 __func__);
2894 } else if (passthrough_flag == COMPRESSED_PASSTHROUGH_IEC61937) {
2895 open.flags = 0x1;
2896 pr_debug("%s: Flag 1 - COMPRESSED_PASSTHROUGH_IEC61937\n",
2897 __func__);
2898 } else {
2899 pr_err("%s: Invalid passthrough type[%d]\n",
2900 __func__, passthrough_flag);
2901 rc = -EINVAL;
2902 goto fail_cmd;
2903 }
2904 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
2905 if (rc < 0) {
2906 pr_err("%s: open failed op[0x%x]rc[%d]\n",
2907 __func__, open.hdr.opcode, rc);
2908 rc = -EINVAL;
2909 goto fail_cmd;
2910 }
2911 rc = wait_event_timeout(ac->cmd_wait,
2912 (atomic_read(&ac->cmd_state) >= 0), 1*HZ);
2913 if (!rc) {
2914 pr_err("%s: timeout. waited for OPEN_WRITE_COMPR rc[%d]\n",
2915 __func__, rc);
2916 rc = -ETIMEDOUT;
2917 goto fail_cmd;
2918 }
2919
2920 if (atomic_read(&ac->cmd_state) > 0) {
2921 pr_err("%s: DSP returned error[%s]\n",
2922 __func__, adsp_err_get_err_str(
2923 atomic_read(&ac->cmd_state)));
2924 rc = adsp_err_get_lnx_err_code(
2925 atomic_read(&ac->cmd_state));
2926 goto fail_cmd;
2927 }
2928
2929 return 0;
2930
2931fail_cmd:
2932 return rc;
2933}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302934EXPORT_SYMBOL(q6asm_open_write_compressed);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302935
2936static int __q6asm_open_write(struct audio_client *ac, uint32_t format,
2937 uint16_t bits_per_sample, uint32_t stream_id,
2938 bool is_gapless_mode,
2939 uint32_t pcm_format_block_ver)
2940{
2941 int rc = 0x00;
2942 struct asm_stream_cmd_open_write_v3 open;
2943
2944 if (ac == NULL) {
2945 pr_err("%s: APR handle NULL\n", __func__);
2946 return -EINVAL;
2947 }
2948 if (ac->apr == NULL) {
2949 pr_err("%s: AC APR handle NULL\n", __func__);
2950 return -EINVAL;
2951 }
2952
2953 dev_vdbg(ac->dev, "%s: session[%d] wr_format[0x%x]\n",
2954 __func__, ac->session, format);
2955
2956 q6asm_stream_add_hdr(ac, &open.hdr, sizeof(open), TRUE, stream_id);
2957 atomic_set(&ac->cmd_state, -1);
2958 /*
2959 * Updated the token field with stream/session for compressed playback
2960 * Platform driver must know the the stream with which the command is
2961 * associated
2962 */
2963 if (ac->io_mode & COMPRESSED_STREAM_IO)
2964 q6asm_update_token(&open.hdr.token,
2965 ac->session,
2966 stream_id,
2967 0, /* Buffer index is NA */
2968 0, /* Direction flag is NA */
2969 WAIT_CMD);
2970
2971 dev_vdbg(ac->dev, "%s: token = 0x%x, stream_id %d, session 0x%x\n",
2972 __func__, open.hdr.token, stream_id, ac->session);
2973 open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
2974 open.mode_flags = 0x00;
2975 if (ac->perf_mode == ULL_POST_PROCESSING_PCM_MODE)
2976 open.mode_flags |= ASM_ULL_POST_PROCESSING_STREAM_SESSION;
2977 else if (ac->perf_mode == ULTRA_LOW_LATENCY_PCM_MODE)
2978 open.mode_flags |= ASM_ULTRA_LOW_LATENCY_STREAM_SESSION;
2979 else if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
2980 open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION;
2981 else {
2982 open.mode_flags |= ASM_LEGACY_STREAM_SESSION;
2983 if (is_gapless_mode)
2984 open.mode_flags |= 1 << ASM_SHIFT_GAPLESS_MODE_FLAG;
2985 }
2986
2987 /* source endpoint : matrix */
2988 open.sink_endpointype = ASM_END_POINT_DEVICE_MATRIX;
2989 open.bits_per_sample = bits_per_sample;
2990
2991 open.postprocopo_id = q6asm_get_asm_topology_cal();
2992 if (ac->perf_mode != LEGACY_PCM_MODE)
2993 open.postprocopo_id = ASM_STREAM_POSTPROCOPO_ID_NONE;
2994
2995 pr_debug("%s: perf_mode %d asm_topology 0x%x bps %d\n", __func__,
2996 ac->perf_mode, open.postprocopo_id, open.bits_per_sample);
2997
2998 /*
2999 * For Gapless playback it will use the same session for next stream,
3000 * So use the same topology
3001 */
3002 if (!ac->topology) {
3003 ac->topology = open.postprocopo_id;
3004 ac->app_type = q6asm_get_asm_app_type_cal();
3005 }
3006 switch (format) {
3007 case FORMAT_LINEAR_PCM:
3008 open.dec_fmt_id = q6asm_get_pcm_format_id(pcm_format_block_ver);
3009 break;
3010 case FORMAT_MPEG4_AAC:
3011 open.dec_fmt_id = ASM_MEDIA_FMT_AAC_V2;
3012 break;
3013 case FORMAT_MPEG4_MULTI_AAC:
3014 open.dec_fmt_id = ASM_MEDIA_FMT_AAC_V2;
3015 break;
3016 case FORMAT_WMA_V9:
3017 open.dec_fmt_id = ASM_MEDIA_FMT_WMA_V9_V2;
3018 break;
3019 case FORMAT_WMA_V10PRO:
3020 open.dec_fmt_id = ASM_MEDIA_FMT_WMA_V10PRO_V2;
3021 break;
3022 case FORMAT_MP3:
3023 open.dec_fmt_id = ASM_MEDIA_FMT_MP3;
3024 break;
3025 case FORMAT_AC3:
3026 open.dec_fmt_id = ASM_MEDIA_FMT_AC3;
3027 break;
3028 case FORMAT_EAC3:
3029 open.dec_fmt_id = ASM_MEDIA_FMT_EAC3;
3030 break;
3031 case FORMAT_MP2:
3032 open.dec_fmt_id = ASM_MEDIA_FMT_MP2;
3033 break;
3034 case FORMAT_FLAC:
3035 open.dec_fmt_id = ASM_MEDIA_FMT_FLAC;
3036 break;
3037 case FORMAT_ALAC:
3038 open.dec_fmt_id = ASM_MEDIA_FMT_ALAC;
3039 break;
3040 case FORMAT_VORBIS:
3041 open.dec_fmt_id = ASM_MEDIA_FMT_VORBIS;
3042 break;
3043 case FORMAT_APE:
3044 open.dec_fmt_id = ASM_MEDIA_FMT_APE;
3045 break;
3046 case FORMAT_DSD:
3047 open.dec_fmt_id = ASM_MEDIA_FMT_DSD;
3048 break;
3049 case FORMAT_APTX:
3050 open.dec_fmt_id = ASM_MEDIA_FMT_APTX;
3051 break;
3052 case FORMAT_GEN_COMPR:
3053 open.dec_fmt_id = ASM_MEDIA_FMT_GENERIC_COMPRESSED;
3054 break;
3055 default:
3056 pr_err("%s: Invalid format 0x%x\n", __func__, format);
3057 rc = -EINVAL;
3058 goto fail_cmd;
3059 }
3060 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
3061 if (rc < 0) {
3062 pr_err("%s: open failed op[0x%x]rc[%d]\n",
3063 __func__, open.hdr.opcode, rc);
3064 rc = -EINVAL;
3065 goto fail_cmd;
3066 }
3067 rc = wait_event_timeout(ac->cmd_wait,
3068 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
3069 if (!rc) {
3070 pr_err("%s: timeout. waited for open write\n", __func__);
3071 rc = -ETIMEDOUT;
3072 goto fail_cmd;
3073 }
3074 if (atomic_read(&ac->cmd_state) > 0) {
3075 pr_err("%s: DSP returned error[%s]\n",
3076 __func__, adsp_err_get_err_str(
3077 atomic_read(&ac->cmd_state)));
3078 rc = adsp_err_get_lnx_err_code(
3079 atomic_read(&ac->cmd_state));
3080 goto fail_cmd;
3081 }
3082 ac->io_mode |= TUN_WRITE_IO_MODE;
3083
3084 return 0;
3085fail_cmd:
3086 return rc;
3087}
3088
3089int q6asm_open_write(struct audio_client *ac, uint32_t format)
3090{
3091 return __q6asm_open_write(ac, format, 16, ac->stream_id,
3092 false /*gapless*/,
3093 PCM_MEDIA_FORMAT_V2 /*pcm_format_block_ver*/);
3094}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303095EXPORT_SYMBOL(q6asm_open_write);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303096
3097int q6asm_open_write_v2(struct audio_client *ac, uint32_t format,
3098 uint16_t bits_per_sample)
3099{
3100 return __q6asm_open_write(ac, format, bits_per_sample,
3101 ac->stream_id, false /*gapless*/,
3102 PCM_MEDIA_FORMAT_V2 /*pcm_format_block_ver*/);
3103}
3104
3105/*
3106 * q6asm_open_write_v3 - Opens audio playback session
3107 *
3108 * @ac: Client session handle
3109 * @format: decoder format
3110 * @bits_per_sample: bit width of playback session
3111 */
3112int q6asm_open_write_v3(struct audio_client *ac, uint32_t format,
3113 uint16_t bits_per_sample)
3114{
3115 return __q6asm_open_write(ac, format, bits_per_sample,
3116 ac->stream_id, false /*gapless*/,
3117 PCM_MEDIA_FORMAT_V3 /*pcm_format_block_ver*/);
3118}
3119EXPORT_SYMBOL(q6asm_open_write_v3);
3120
3121/*
3122 * q6asm_open_write_v4 - Opens audio playback session
3123 *
3124 * @ac: Client session handle
3125 * @format: decoder format
3126 * @bits_per_sample: bit width of playback session
3127 */
3128int q6asm_open_write_v4(struct audio_client *ac, uint32_t format,
3129 uint16_t bits_per_sample)
3130{
3131 return __q6asm_open_write(ac, format, bits_per_sample,
3132 ac->stream_id, false /*gapless*/,
3133 PCM_MEDIA_FORMAT_V4 /*pcm_format_block_ver*/);
3134}
3135EXPORT_SYMBOL(q6asm_open_write_v4);
3136
3137int q6asm_stream_open_write_v2(struct audio_client *ac, uint32_t format,
3138 uint16_t bits_per_sample, int32_t stream_id,
3139 bool is_gapless_mode)
3140{
3141 return __q6asm_open_write(ac, format, bits_per_sample,
3142 stream_id, is_gapless_mode,
3143 PCM_MEDIA_FORMAT_V2 /*pcm_format_block_ver*/);
3144}
3145
3146/*
3147 * q6asm_stream_open_write_v3 - Creates audio stream for playback
3148 *
3149 * @ac: Client session handle
3150 * @format: asm playback format
3151 * @bits_per_sample: bit width of requested stream
3152 * @stream_id: stream id of stream to be associated with this session
3153 * @is_gapless_mode: true if gapless mode needs to be enabled
3154 */
3155int q6asm_stream_open_write_v3(struct audio_client *ac, uint32_t format,
3156 uint16_t bits_per_sample, int32_t stream_id,
3157 bool is_gapless_mode)
3158{
3159 return __q6asm_open_write(ac, format, bits_per_sample,
3160 stream_id, is_gapless_mode,
3161 PCM_MEDIA_FORMAT_V3 /*pcm_format_block_ver*/);
3162}
3163EXPORT_SYMBOL(q6asm_stream_open_write_v3);
3164
3165/*
3166 * q6asm_stream_open_write_v4 - Creates audio stream for playback
3167 *
3168 * @ac: Client session handle
3169 * @format: asm playback format
3170 * @bits_per_sample: bit width of requested stream
3171 * @stream_id: stream id of stream to be associated with this session
3172 * @is_gapless_mode: true if gapless mode needs to be enabled
3173 */
3174int q6asm_stream_open_write_v4(struct audio_client *ac, uint32_t format,
3175 uint16_t bits_per_sample, int32_t stream_id,
3176 bool is_gapless_mode)
3177{
3178 return __q6asm_open_write(ac, format, bits_per_sample,
3179 stream_id, is_gapless_mode,
3180 PCM_MEDIA_FORMAT_V4 /*pcm_format_block_ver*/);
3181}
3182EXPORT_SYMBOL(q6asm_stream_open_write_v4);
3183
3184static int __q6asm_open_read_write(struct audio_client *ac, uint32_t rd_format,
3185 uint32_t wr_format, bool is_meta_data_mode,
3186 uint32_t bits_per_sample,
3187 bool overwrite_topology, int topology)
3188{
3189 int rc = 0x00;
3190 struct asm_stream_cmd_open_readwrite_v2 open;
3191
3192 if (ac == NULL) {
3193 pr_err("%s: APR handle NULL\n", __func__);
3194 return -EINVAL;
3195 }
3196 if (ac->apr == NULL) {
3197 pr_err("%s: AC APR handle NULL\n", __func__);
3198 return -EINVAL;
3199 }
3200 pr_debug("%s: session[%d]\n", __func__, ac->session);
3201 pr_debug("%s: wr_format[0x%x]rd_format[0x%x]\n",
3202 __func__, wr_format, rd_format);
3203
3204 ac->io_mode |= NT_MODE;
3205 q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
3206 atomic_set(&ac->cmd_state, -1);
3207 open.hdr.opcode = ASM_STREAM_CMD_OPEN_READWRITE_V2;
3208
3209 open.mode_flags = is_meta_data_mode ? BUFFER_META_ENABLE : 0;
3210 open.bits_per_sample = bits_per_sample;
3211 /* source endpoint : matrix */
3212 open.postprocopo_id = q6asm_get_asm_topology_cal();
3213
3214 open.postprocopo_id = overwrite_topology ?
3215 topology : open.postprocopo_id;
3216 ac->topology = open.postprocopo_id;
3217 ac->app_type = q6asm_get_asm_app_type_cal();
3218
3219
3220 switch (wr_format) {
3221 case FORMAT_LINEAR_PCM:
3222 case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
3223 open.dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
3224 break;
3225 case FORMAT_MPEG4_AAC:
3226 open.dec_fmt_id = ASM_MEDIA_FMT_AAC_V2;
3227 break;
3228 case FORMAT_MPEG4_MULTI_AAC:
3229 open.dec_fmt_id = ASM_MEDIA_FMT_AAC_V2;
3230 break;
3231 case FORMAT_WMA_V9:
3232 open.dec_fmt_id = ASM_MEDIA_FMT_WMA_V9_V2;
3233 break;
3234 case FORMAT_WMA_V10PRO:
3235 open.dec_fmt_id = ASM_MEDIA_FMT_WMA_V10PRO_V2;
3236 break;
3237 case FORMAT_AMRNB:
3238 open.dec_fmt_id = ASM_MEDIA_FMT_AMRNB_FS;
3239 break;
3240 case FORMAT_AMRWB:
3241 open.dec_fmt_id = ASM_MEDIA_FMT_AMRWB_FS;
3242 break;
3243 case FORMAT_AMR_WB_PLUS:
3244 open.dec_fmt_id = ASM_MEDIA_FMT_AMR_WB_PLUS_V2;
3245 break;
3246 case FORMAT_V13K:
3247 open.dec_fmt_id = ASM_MEDIA_FMT_V13K_FS;
3248 break;
3249 case FORMAT_EVRC:
3250 open.dec_fmt_id = ASM_MEDIA_FMT_EVRC_FS;
3251 break;
3252 case FORMAT_EVRCB:
3253 open.dec_fmt_id = ASM_MEDIA_FMT_EVRCB_FS;
3254 break;
3255 case FORMAT_EVRCWB:
3256 open.dec_fmt_id = ASM_MEDIA_FMT_EVRCWB_FS;
3257 break;
3258 case FORMAT_MP3:
3259 open.dec_fmt_id = ASM_MEDIA_FMT_MP3;
3260 break;
3261 case FORMAT_ALAC:
3262 open.dec_fmt_id = ASM_MEDIA_FMT_ALAC;
3263 break;
3264 case FORMAT_APE:
3265 open.dec_fmt_id = ASM_MEDIA_FMT_APE;
3266 break;
3267 case FORMAT_DSD:
3268 open.dec_fmt_id = ASM_MEDIA_FMT_DSD;
3269 break;
3270 case FORMAT_G711_ALAW_FS:
3271 open.dec_fmt_id = ASM_MEDIA_FMT_G711_ALAW_FS;
3272 break;
3273 case FORMAT_G711_MLAW_FS:
3274 open.dec_fmt_id = ASM_MEDIA_FMT_G711_MLAW_FS;
3275 break;
3276 default:
3277 pr_err("%s: Invalid format 0x%x\n",
3278 __func__, wr_format);
3279 rc = -EINVAL;
3280 goto fail_cmd;
3281 }
3282
3283 switch (rd_format) {
3284 case FORMAT_LINEAR_PCM:
3285 case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
3286 open.enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
3287 break;
3288 case FORMAT_MPEG4_AAC:
3289 open.enc_cfg_id = ASM_MEDIA_FMT_AAC_V2;
3290 break;
3291 case FORMAT_G711_ALAW_FS:
3292 open.enc_cfg_id = ASM_MEDIA_FMT_G711_ALAW_FS;
3293 break;
3294 case FORMAT_G711_MLAW_FS:
3295 open.enc_cfg_id = ASM_MEDIA_FMT_G711_MLAW_FS;
3296 break;
3297 case FORMAT_V13K:
3298 open.enc_cfg_id = ASM_MEDIA_FMT_V13K_FS;
3299 break;
3300 case FORMAT_EVRC:
3301 open.enc_cfg_id = ASM_MEDIA_FMT_EVRC_FS;
3302 break;
3303 case FORMAT_AMRNB:
3304 open.enc_cfg_id = ASM_MEDIA_FMT_AMRNB_FS;
3305 break;
3306 case FORMAT_AMRWB:
3307 open.enc_cfg_id = ASM_MEDIA_FMT_AMRWB_FS;
3308 break;
3309 case FORMAT_ALAC:
3310 open.enc_cfg_id = ASM_MEDIA_FMT_ALAC;
3311 break;
3312 case FORMAT_APE:
3313 open.enc_cfg_id = ASM_MEDIA_FMT_APE;
3314 break;
3315 default:
3316 pr_err("%s: Invalid format 0x%x\n",
3317 __func__, rd_format);
3318 rc = -EINVAL;
3319 goto fail_cmd;
3320 }
3321 dev_vdbg(ac->dev, "%s: rdformat[0x%x]wrformat[0x%x]\n", __func__,
3322 open.enc_cfg_id, open.dec_fmt_id);
3323
3324 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
3325 if (rc < 0) {
3326 pr_err("%s: open failed op[0x%x]rc[%d]\n",
3327 __func__, open.hdr.opcode, rc);
3328 rc = -EINVAL;
3329 goto fail_cmd;
3330 }
3331 rc = wait_event_timeout(ac->cmd_wait,
3332 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
3333 if (!rc) {
3334 pr_err("%s: timeout. waited for open read-write\n",
3335 __func__);
3336 rc = -ETIMEDOUT;
3337 goto fail_cmd;
3338 }
3339 if (atomic_read(&ac->cmd_state) > 0) {
3340 pr_err("%s: DSP returned error[%s]\n",
3341 __func__, adsp_err_get_err_str(
3342 atomic_read(&ac->cmd_state)));
3343 rc = adsp_err_get_lnx_err_code(
3344 atomic_read(&ac->cmd_state));
3345 goto fail_cmd;
3346 }
3347
3348 return 0;
3349fail_cmd:
3350 return rc;
3351}
3352
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303353/**
3354 * q6asm_open_read_write -
3355 * command to open ASM in read/write mode
3356 *
3357 * @ac: Audio client handle
3358 * @rd_format: capture format for ASM
3359 * @wr_format: playback format for ASM
3360 *
3361 * Returns 0 on success or error on failure
3362 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303363int q6asm_open_read_write(struct audio_client *ac, uint32_t rd_format,
3364 uint32_t wr_format)
3365{
3366 return __q6asm_open_read_write(ac, rd_format, wr_format,
3367 true/*meta data mode*/,
3368 16 /*bits_per_sample*/,
3369 false /*overwrite_topology*/, 0);
3370}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303371EXPORT_SYMBOL(q6asm_open_read_write);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303372
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303373/**
3374 * q6asm_open_read_write_v2 -
3375 * command to open ASM in bi-directional read/write mode
3376 *
3377 * @ac: Audio client handle
3378 * @rd_format: capture format for ASM
3379 * @wr_format: playback format for ASM
3380 * @is_meta_data_mode: mode to indicate if meta data present
3381 * @bits_per_sample: number of bits per sample
3382 * @overwrite_topology: topology to be overwritten flag
3383 * @topology: Topology for ASM
3384 *
3385 * Returns 0 on success or error on failure
3386 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303387int q6asm_open_read_write_v2(struct audio_client *ac, uint32_t rd_format,
3388 uint32_t wr_format, bool is_meta_data_mode,
3389 uint32_t bits_per_sample, bool overwrite_topology,
3390 int topology)
3391{
3392 return __q6asm_open_read_write(ac, rd_format, wr_format,
3393 is_meta_data_mode, bits_per_sample,
3394 overwrite_topology, topology);
3395}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303396EXPORT_SYMBOL(q6asm_open_read_write_v2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303397
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303398/**
3399 * q6asm_open_loopback_v2 -
3400 * command to open ASM in loopback mode
3401 *
3402 * @ac: Audio client handle
3403 * @bits_per_sample: number of bits per sample
3404 *
3405 * Returns 0 on success or error on failure
3406 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303407int q6asm_open_loopback_v2(struct audio_client *ac, uint16_t bits_per_sample)
3408{
3409 int rc = 0x00;
3410
3411 if (ac == NULL) {
3412 pr_err("%s: APR handle NULL\n", __func__);
3413 return -EINVAL;
3414 }
3415 if (ac->apr == NULL) {
3416 pr_err("%s: AC APR handle NULL\n", __func__);
3417 return -EINVAL;
3418 }
3419 pr_debug("%s: session[%d]\n", __func__, ac->session);
3420
3421 if (ac->perf_mode == LOW_LATENCY_PCM_MODE) {
3422 struct asm_stream_cmd_open_transcode_loopback_t open;
3423
3424 q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
3425 atomic_set(&ac->cmd_state, -1);
3426 open.hdr.opcode = ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK;
3427
3428 open.mode_flags = 0;
3429 open.src_endpoint_type = 0;
3430 open.sink_endpoint_type = 0;
3431 open.src_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
3432 open.sink_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
3433 /* source endpoint : matrix */
3434 open.audproc_topo_id = q6asm_get_asm_topology_cal();
3435
3436 ac->app_type = q6asm_get_asm_app_type_cal();
3437 if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
3438 open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION;
3439 else
3440 open.mode_flags |= ASM_LEGACY_STREAM_SESSION;
3441 ac->topology = open.audproc_topo_id;
3442 open.bits_per_sample = bits_per_sample;
3443 open.reserved = 0;
3444 pr_debug("%s: opening a transcode_loopback with mode_flags =[%d] session[%d]\n",
3445 __func__, open.mode_flags, ac->session);
3446
3447 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
3448 if (rc < 0) {
3449 pr_err("%s: open failed op[0x%x]rc[%d]\n",
3450 __func__, open.hdr.opcode, rc);
3451 rc = -EINVAL;
3452 goto fail_cmd;
3453 }
3454 } else {/*if(ac->perf_mode == LEGACY_PCM_MODE)*/
3455 struct asm_stream_cmd_open_loopback_v2 open;
3456
3457 q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
3458 atomic_set(&ac->cmd_state, -1);
3459 open.hdr.opcode = ASM_STREAM_CMD_OPEN_LOOPBACK_V2;
3460
3461 open.mode_flags = 0;
3462 open.src_endpointype = 0;
3463 open.sink_endpointype = 0;
3464 /* source endpoint : matrix */
3465 open.postprocopo_id = q6asm_get_asm_topology_cal();
3466
3467 ac->app_type = q6asm_get_asm_app_type_cal();
3468 ac->topology = open.postprocopo_id;
3469 open.bits_per_sample = bits_per_sample;
3470 open.reserved = 0;
3471 pr_debug("%s: opening a loopback_v2 with mode_flags =[%d] session[%d]\n",
3472 __func__, open.mode_flags, ac->session);
3473
3474 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
3475 if (rc < 0) {
3476 pr_err("%s: open failed op[0x%x]rc[%d]\n",
3477 __func__, open.hdr.opcode, rc);
3478 rc = -EINVAL;
3479 goto fail_cmd;
3480 }
3481 }
3482 rc = wait_event_timeout(ac->cmd_wait,
3483 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
3484 if (!rc) {
3485 pr_err("%s: timeout. waited for open_loopback\n",
3486 __func__);
3487 rc = -ETIMEDOUT;
3488 goto fail_cmd;
3489 }
3490 if (atomic_read(&ac->cmd_state) > 0) {
3491 pr_err("%s: DSP returned error[%s]\n",
3492 __func__, adsp_err_get_err_str(
3493 atomic_read(&ac->cmd_state)));
3494 rc = adsp_err_get_lnx_err_code(
3495 atomic_read(&ac->cmd_state));
3496 goto fail_cmd;
3497 }
3498
3499 return 0;
3500fail_cmd:
3501 return rc;
3502}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303503EXPORT_SYMBOL(q6asm_open_loopback_v2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303504
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303505/**
3506 * q6asm_open_transcode_loopback -
3507 * command to open ASM in transcode loopback mode
3508 *
3509 * @ac: Audio client handle
3510 * @bits_per_sample: number of bits per sample
3511 * @source_format: Format of clip
3512 * @sink_format: end device supported format
3513 *
3514 * Returns 0 on success or error on failure
3515 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303516int q6asm_open_transcode_loopback(struct audio_client *ac,
3517 uint16_t bits_per_sample,
3518 uint32_t source_format, uint32_t sink_format)
3519{
3520 int rc = 0x00;
3521 struct asm_stream_cmd_open_transcode_loopback_t open;
3522
3523 if (ac == NULL) {
3524 pr_err("%s: APR handle NULL\n", __func__);
3525 return -EINVAL;
3526 }
3527 if (ac->apr == NULL) {
3528 pr_err("%s: AC APR handle NULL\n", __func__);
3529 return -EINVAL;
3530 }
3531
3532 pr_debug("%s: session[%d]\n", __func__, ac->session);
3533
3534 q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
3535 atomic_set(&ac->cmd_state, -1);
3536 open.hdr.opcode = ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK;
3537
3538 open.mode_flags = 0;
3539 open.src_endpoint_type = 0;
3540 open.sink_endpoint_type = 0;
3541 switch (source_format) {
3542 case FORMAT_LINEAR_PCM:
3543 case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
3544 open.src_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3;
3545 break;
3546 case FORMAT_AC3:
3547 open.src_format_id = ASM_MEDIA_FMT_AC3;
3548 break;
3549 case FORMAT_EAC3:
3550 open.src_format_id = ASM_MEDIA_FMT_EAC3;
3551 break;
3552 default:
3553 pr_err("%s: Unsupported src fmt [%d]\n",
3554 __func__, source_format);
3555 return -EINVAL;
3556 }
3557 switch (sink_format) {
3558 case FORMAT_LINEAR_PCM:
3559 case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
3560 open.sink_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3;
3561 break;
3562 default:
3563 pr_err("%s: Unsupported sink fmt [%d]\n",
3564 __func__, sink_format);
3565 return -EINVAL;
3566 }
3567
3568 /* source endpoint : matrix */
3569 open.audproc_topo_id = q6asm_get_asm_topology_cal();
3570
3571 ac->app_type = q6asm_get_asm_app_type_cal();
3572 if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
3573 open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION;
3574 else
3575 open.mode_flags |= ASM_LEGACY_STREAM_SESSION;
3576 ac->topology = open.audproc_topo_id;
3577 open.bits_per_sample = bits_per_sample;
3578 open.reserved = 0;
3579 pr_debug("%s: opening a transcode_loopback with mode_flags =[%d] session[%d]\n",
3580 __func__, open.mode_flags, ac->session);
3581
3582 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
3583 if (rc < 0) {
3584 pr_err("%s: open failed op[0x%x]rc[%d]\n",
3585 __func__, open.hdr.opcode, rc);
3586 rc = -EINVAL;
3587 goto fail_cmd;
3588 }
3589 rc = wait_event_timeout(ac->cmd_wait,
3590 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
3591 if (!rc) {
3592 pr_err("%s: timeout. waited for open_transcode_loopback\n",
3593 __func__);
3594 rc = -ETIMEDOUT;
3595 goto fail_cmd;
3596 }
3597 if (atomic_read(&ac->cmd_state) > 0) {
3598 pr_err("%s: DSP returned error[%s]\n",
3599 __func__, adsp_err_get_err_str(
3600 atomic_read(&ac->cmd_state)));
3601 rc = adsp_err_get_lnx_err_code(
3602 atomic_read(&ac->cmd_state));
3603 goto fail_cmd;
3604 }
3605
3606 return 0;
3607fail_cmd:
3608 return rc;
3609}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303610EXPORT_SYMBOL(q6asm_open_transcode_loopback);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303611
3612static
3613int q6asm_set_shared_circ_buff(struct audio_client *ac,
3614 struct asm_stream_cmd_open_shared_io *open,
3615 int bufsz, int bufcnt,
3616 int dir)
3617{
3618 struct audio_buffer *buf_circ;
3619 int bytes_to_alloc, rc;
3620 size_t len;
3621
Aditya Bavanaria8aea172017-09-13 11:37:53 +05303622 mutex_lock(&ac->cmd_lock);
3623
3624 if (ac->port[dir].buf) {
3625 pr_err("%s: Buffer already allocated\n", __func__);
3626 rc = -EINVAL;
Aditya Bavanaria8aea172017-09-13 11:37:53 +05303627 goto done;
3628 }
3629
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303630 buf_circ = kzalloc(sizeof(struct audio_buffer), GFP_KERNEL);
3631
3632 if (!buf_circ) {
3633 rc = -ENOMEM;
3634 goto done;
3635 }
3636
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303637 bytes_to_alloc = bufsz * bufcnt;
3638 bytes_to_alloc = PAGE_ALIGN(bytes_to_alloc);
3639
3640 rc = msm_audio_ion_alloc("audio_client", &buf_circ->client,
3641 &buf_circ->handle, bytes_to_alloc,
3642 (ion_phys_addr_t *)&buf_circ->phys,
3643 &len, &buf_circ->data);
3644
3645 if (rc) {
3646 pr_err("%s: Audio ION alloc is failed, rc = %d\n", __func__,
3647 rc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303648 kfree(buf_circ);
3649 goto done;
3650 }
3651
Aditya Bavanaria8aea172017-09-13 11:37:53 +05303652 ac->port[dir].buf = buf_circ;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303653 buf_circ->used = dir ^ 1;
3654 buf_circ->size = bytes_to_alloc;
3655 buf_circ->actual_size = bytes_to_alloc;
3656 memset(buf_circ->data, 0, buf_circ->actual_size);
3657
3658 ac->port[dir].max_buf_cnt = 1;
3659
3660 open->shared_circ_buf_mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
3661 open->shared_circ_buf_num_regions = 1;
3662 open->shared_circ_buf_property_flag = 0x00;
3663 open->shared_circ_buf_start_phy_addr_lsw =
3664 lower_32_bits(buf_circ->phys);
3665 open->shared_circ_buf_start_phy_addr_msw =
3666 msm_audio_populate_upper_32_bits(buf_circ->phys);
3667 open->shared_circ_buf_size = bufsz * bufcnt;
3668
3669 open->map_region_circ_buf.shm_addr_lsw = lower_32_bits(buf_circ->phys);
3670 open->map_region_circ_buf.shm_addr_msw =
3671 msm_audio_populate_upper_32_bits(buf_circ->phys);
3672 open->map_region_circ_buf.mem_size_bytes = bytes_to_alloc;
3673
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303674done:
Xiaoyu Yef423ab12017-11-22 11:38:29 -08003675 mutex_unlock(&ac->cmd_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303676 return rc;
3677}
3678
3679
3680static
3681int q6asm_set_shared_pos_buff(struct audio_client *ac,
3682 struct asm_stream_cmd_open_shared_io *open,
3683 int dir)
3684{
3685 struct audio_buffer *buf_pos = &ac->shared_pos_buf;
3686 int rc;
3687 size_t len;
3688 int bytes_to_alloc = sizeof(struct asm_shared_position_buffer);
3689
3690 mutex_lock(&ac->cmd_lock);
3691
3692 bytes_to_alloc = PAGE_ALIGN(bytes_to_alloc);
3693
3694 rc = msm_audio_ion_alloc("audio_client", &buf_pos->client,
3695 &buf_pos->handle, bytes_to_alloc,
3696 (ion_phys_addr_t *)&buf_pos->phys, &len,
3697 &buf_pos->data);
3698
3699 if (rc) {
3700 pr_err("%s: Audio pos buf ION alloc is failed, rc = %d\n",
3701 __func__, rc);
3702 goto done;
3703 }
3704
3705 buf_pos->used = dir ^ 1;
3706 buf_pos->size = bytes_to_alloc;
3707 buf_pos->actual_size = bytes_to_alloc;
3708
3709 open->shared_pos_buf_mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
3710 open->shared_pos_buf_num_regions = 1;
3711 open->shared_pos_buf_property_flag = 0x00;
3712 open->shared_pos_buf_phy_addr_lsw = lower_32_bits(buf_pos->phys);
3713 open->shared_pos_buf_phy_addr_msw =
3714 msm_audio_populate_upper_32_bits(buf_pos->phys);
3715
3716 open->map_region_pos_buf.shm_addr_lsw = lower_32_bits(buf_pos->phys);
3717 open->map_region_pos_buf.shm_addr_msw =
3718 msm_audio_populate_upper_32_bits(buf_pos->phys);
3719 open->map_region_pos_buf.mem_size_bytes = bytes_to_alloc;
3720
3721done:
3722 mutex_unlock(&ac->cmd_lock);
3723 return rc;
3724}
3725
3726/*
3727 * q6asm_open_shared_io: Open an ASM session for pull mode (playback)
3728 * or push mode (capture).
3729 * parameters
3730 * config - session parameters (channels, bits_per_sample, sr)
3731 * dir - stream direction (IN for playback, OUT for capture)
3732 * returns 0 if successful, error code otherwise
3733 */
3734int q6asm_open_shared_io(struct audio_client *ac,
3735 struct shared_io_config *config,
3736 int dir)
3737{
3738 struct asm_stream_cmd_open_shared_io *open;
3739 u8 *channel_mapping;
3740 int i, size_of_open, num_watermarks, bufsz, bufcnt, rc, flags = 0;
3741
3742 if (!ac || !config)
3743 return -EINVAL;
3744
3745 bufsz = config->bufsz;
3746 bufcnt = config->bufcnt;
3747 num_watermarks = 0;
3748
3749 ac->config = *config;
3750
3751 if (ac->session <= 0 || ac->session > SESSION_MAX) {
3752 pr_err("%s: Session %d is out of bounds\n",
3753 __func__, ac->session);
3754 return -EINVAL;
3755 }
3756
3757 size_of_open = sizeof(struct asm_stream_cmd_open_shared_io) +
3758 (sizeof(struct asm_shared_watermark_level) * num_watermarks);
3759
3760 open = kzalloc(PAGE_ALIGN(size_of_open), GFP_KERNEL);
3761 if (!open)
3762 return -ENOMEM;
3763
3764 q6asm_stream_add_hdr(ac, &open->hdr, size_of_open, TRUE,
3765 ac->stream_id);
3766
3767 atomic_set(&ac->cmd_state, 1);
3768
3769 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x, perf %d\n",
3770 __func__, open->hdr.token, ac->stream_id, ac->session,
3771 ac->perf_mode);
3772
3773 open->hdr.opcode =
3774 dir == IN ? ASM_STREAM_CMD_OPEN_PULL_MODE_WRITE :
3775 ASM_STREAM_CMD_OPEN_PUSH_MODE_READ;
3776
3777 pr_debug("%s perf_mode %d\n", __func__, ac->perf_mode);
3778 if (dir == IN)
3779 if (ac->perf_mode == ULL_POST_PROCESSING_PCM_MODE)
3780 flags = 4 << ASM_SHIFT_STREAM_PERF_FLAG_PULL_MODE_WRITE;
3781 else if (ac->perf_mode == ULTRA_LOW_LATENCY_PCM_MODE)
3782 flags = 2 << ASM_SHIFT_STREAM_PERF_FLAG_PULL_MODE_WRITE;
3783 else if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
3784 flags = 1 << ASM_SHIFT_STREAM_PERF_FLAG_PULL_MODE_WRITE;
3785 else
3786 pr_err("Invalid perf mode for pull write\n");
3787 else
3788 if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
3789 flags = ASM_LOW_LATENCY_TX_STREAM_SESSION <<
3790 ASM_SHIFT_STREAM_PERF_FLAG_PUSH_MODE_READ;
3791 else
3792 pr_err("Invalid perf mode for push read\n");
3793
3794 if (flags == 0) {
3795 pr_err("%s: Invalid mode[%d]\n", __func__,
3796 ac->perf_mode);
3797 kfree(open);
3798 return -EINVAL;
3799
3800 }
3801
3802 pr_debug("open.mode_flags = 0x%x\n", flags);
3803 open->mode_flags = flags;
3804 open->endpoint_type = ASM_END_POINT_DEVICE_MATRIX;
3805 open->topo_bits_per_sample = config->bits_per_sample;
3806
3807 open->topo_id = q6asm_get_asm_topology_cal();
3808
3809 if (config->format == FORMAT_LINEAR_PCM)
3810 open->fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3;
3811 else {
3812 pr_err("%s: Invalid format[%d]\n", __func__, config->format);
3813 rc = -EINVAL;
3814 goto done;
3815 }
3816
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303817 rc = q6asm_set_shared_circ_buff(ac, open, bufsz, bufcnt, dir);
3818
3819 if (rc)
3820 goto done;
3821
3822 ac->port[dir].tmp_hdl = 0;
3823
3824 rc = q6asm_set_shared_pos_buff(ac, open, dir);
3825
3826 if (rc)
3827 goto done;
3828
3829 /* asm_multi_channel_pcm_fmt_blk_v3 */
3830 open->fmt.num_channels = config->channels;
3831 open->fmt.bits_per_sample = config->bits_per_sample;
3832 open->fmt.sample_rate = config->rate;
3833 open->fmt.is_signed = 1;
3834 open->fmt.sample_word_size = config->sample_word_size;
3835
3836 channel_mapping = open->fmt.channel_mapping;
3837
3838 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
3839
3840 rc = q6asm_map_channels(channel_mapping, config->channels, false);
3841 if (rc) {
3842 pr_err("%s: Map channels failed, ret: %d\n", __func__, rc);
3843 goto done;
3844 }
3845
3846 open->num_watermark_levels = num_watermarks;
3847 for (i = 0; i < num_watermarks; i++) {
3848 open->watermark[i].watermark_level_bytes = i *
3849 ((bufsz * bufcnt) / num_watermarks);
3850 pr_debug("%s: Watermark level set for %i\n",
3851 __func__,
3852 open->watermark[i].watermark_level_bytes);
3853 }
3854
3855 rc = apr_send_pkt(ac->apr, (uint32_t *) open);
3856 if (rc < 0) {
3857 pr_err("%s: Open failed op[0x%x]rc[%d]\n",
3858 __func__, open->hdr.opcode, rc);
3859 goto done;
3860 }
3861
3862 pr_debug("%s: sent open apr pkt\n", __func__);
3863 rc = wait_event_timeout(ac->cmd_wait,
3864 (atomic_read(&ac->cmd_state) <= 0), 5*HZ);
3865 if (!rc) {
3866 pr_err("%s: Timeout. Waited for open write apr pkt rc[%d]\n",
3867 __func__, rc);
3868 rc = -ETIMEDOUT;
3869 goto done;
3870 }
3871
3872 if (atomic_read(&ac->cmd_state) < 0) {
3873 pr_err("%s: DSP returned error [%d]\n", __func__,
3874 atomic_read(&ac->cmd_state));
3875 rc = -EINVAL;
3876 goto done;
3877 }
3878
3879 ac->io_mode |= TUN_WRITE_IO_MODE;
3880 rc = 0;
3881done:
3882 kfree(open);
3883 return rc;
3884}
3885EXPORT_SYMBOL(q6asm_open_shared_io);
3886
3887/*
3888 * q6asm_shared_io_buf: Returns handle to the shared circular buffer being
3889 * used for pull/push mode.
3890 * parameters
3891 * dir - used to identify input/output port
3892 * returns buffer handle
3893 */
3894struct audio_buffer *q6asm_shared_io_buf(struct audio_client *ac,
3895 int dir)
3896{
3897 struct audio_port_data *port;
3898
3899 if (!ac) {
3900 pr_err("%s: ac is null\n", __func__);
3901 return NULL;
3902 }
3903 port = &ac->port[dir];
3904 return port->buf;
3905}
3906EXPORT_SYMBOL(q6asm_shared_io_buf);
3907
3908/*
3909 * q6asm_shared_io_free: Frees memory allocated for a pull/push session
3910 * parameters
3911 * dir - port direction
3912 * returns 0 if successful, error otherwise
3913 */
3914int q6asm_shared_io_free(struct audio_client *ac, int dir)
3915{
3916 struct audio_port_data *port;
3917
3918 if (!ac) {
3919 pr_err("%s: audio client is null\n", __func__);
3920 return -EINVAL;
3921 }
3922 port = &ac->port[dir];
3923 mutex_lock(&ac->cmd_lock);
3924 if (port->buf && port->buf->data) {
3925 msm_audio_ion_free(port->buf->client, port->buf->handle);
3926 port->buf->client = NULL;
3927 port->buf->handle = NULL;
3928 port->max_buf_cnt = 0;
3929 kfree(port->buf);
3930 port->buf = NULL;
3931 }
3932 if (ac->shared_pos_buf.data) {
3933 msm_audio_ion_free(ac->shared_pos_buf.client,
3934 ac->shared_pos_buf.handle);
3935 ac->shared_pos_buf.client = NULL;
3936 ac->shared_pos_buf.handle = NULL;
3937 }
3938 mutex_unlock(&ac->cmd_lock);
3939 return 0;
3940}
3941EXPORT_SYMBOL(q6asm_shared_io_free);
3942
3943/*
3944 * q6asm_get_shared_pos: Returns current read index/write index as observed
3945 * by the DSP. Note that this is an offset and iterates from [0,BUF_SIZE - 1]
3946 * parameters - (all output)
3947 * read_index - offset
3948 * wall_clk_msw1 - ADSP wallclock msw
3949 * wall_clk_lsw1 - ADSP wallclock lsw
3950 * returns 0 if successful, -EAGAIN if DSP failed to update after some
3951 * retries
3952 */
3953int q6asm_get_shared_pos(struct audio_client *ac, uint32_t *read_index,
3954 uint32_t *wall_clk_msw1, uint32_t *wall_clk_lsw1)
3955{
3956 struct asm_shared_position_buffer *pos_buf;
3957 uint32_t frame_cnt1, frame_cnt2;
3958 int i, j;
3959
3960 if (!ac) {
3961 pr_err("%s: audio client is null\n", __func__);
3962 return -EINVAL;
3963 }
3964
3965 pos_buf = ac->shared_pos_buf.data;
3966
3967 /* always try to get the latest update in the shared pos buffer */
3968 for (i = 0; i < 2; i++) {
3969 /* retry until there is an update from DSP */
3970 for (j = 0; j < 5; j++) {
3971 frame_cnt1 = pos_buf->frame_counter;
3972 if (frame_cnt1 != 0)
3973 break;
3974 }
3975
3976 *wall_clk_msw1 = pos_buf->wall_clock_us_msw;
3977 *wall_clk_lsw1 = pos_buf->wall_clock_us_lsw;
3978 *read_index = pos_buf->index;
3979 frame_cnt2 = pos_buf->frame_counter;
3980
3981 if (frame_cnt1 != frame_cnt2)
3982 continue;
3983 return 0;
3984 }
3985 pr_err("%s out of tries trying to get a good read, try again\n",
3986 __func__);
3987 return -EAGAIN;
3988}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303989EXPORT_SYMBOL(q6asm_get_shared_pos);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303990
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303991/**
3992 * q6asm_run -
3993 * command to set ASM to run state
3994 *
3995 * @ac: Audio client handle
3996 * @flags: Flags for session
3997 * @msw_ts: upper 32bits timestamp
3998 * @lsw_ts: lower 32bits timestamp
3999 *
4000 * Returns 0 on success or error on failure
4001 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304002int q6asm_run(struct audio_client *ac, uint32_t flags,
4003 uint32_t msw_ts, uint32_t lsw_ts)
4004{
4005 struct asm_session_cmd_run_v2 run;
4006 int rc;
4007
4008 if (ac == NULL) {
4009 pr_err("%s: APR handle NULL\n", __func__);
4010 return -EINVAL;
4011 }
4012 if (ac->apr == NULL) {
4013 pr_err("%s: AC APR handle NULL\n", __func__);
4014 return -EINVAL;
4015 }
4016 pr_debug("%s: session[%d]\n", __func__, ac->session);
4017
4018 q6asm_add_hdr(ac, &run.hdr, sizeof(run), TRUE);
4019 atomic_set(&ac->cmd_state, -1);
4020
4021 run.hdr.opcode = ASM_SESSION_CMD_RUN_V2;
4022 run.flags = flags;
4023 run.time_lsw = lsw_ts;
4024 run.time_msw = msw_ts;
4025
4026 config_debug_fs_run();
4027
4028 rc = apr_send_pkt(ac->apr, (uint32_t *) &run);
4029 if (rc < 0) {
4030 pr_err("%s: Commmand run failed[%d]",
4031 __func__, rc);
4032 rc = -EINVAL;
4033 goto fail_cmd;
4034 }
4035
4036 rc = wait_event_timeout(ac->cmd_wait,
4037 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4038 if (!rc) {
4039 pr_err("%s: timeout. waited for run success",
4040 __func__);
4041 rc = -ETIMEDOUT;
4042 goto fail_cmd;
4043 }
4044 if (atomic_read(&ac->cmd_state) > 0) {
4045 pr_err("%s: DSP returned error[%s]\n",
4046 __func__, adsp_err_get_err_str(
4047 atomic_read(&ac->cmd_state)));
4048 rc = adsp_err_get_lnx_err_code(
4049 atomic_read(&ac->cmd_state));
4050 goto fail_cmd;
4051 }
4052
4053 return 0;
4054fail_cmd:
4055 return rc;
4056}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304057EXPORT_SYMBOL(q6asm_run);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304058
4059static int __q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
4060 uint32_t msw_ts, uint32_t lsw_ts, uint32_t stream_id)
4061{
4062 struct asm_session_cmd_run_v2 run;
4063 int rc;
4064
4065 if (ac == NULL) {
4066 pr_err("%s: APR handle NULL\n", __func__);
4067 return -EINVAL;
4068 }
4069 if (ac->apr == NULL) {
4070 pr_err("%s: AC APR handle NULL\n", __func__);
4071 return -EINVAL;
4072 }
4073 pr_debug("%s: session[%d]\n", __func__, ac->session);
4074
4075 q6asm_stream_add_hdr_async(ac, &run.hdr, sizeof(run), TRUE, stream_id);
4076 atomic_set(&ac->cmd_state, 1);
4077 run.hdr.opcode = ASM_SESSION_CMD_RUN_V2;
4078 run.flags = flags;
4079 run.time_lsw = lsw_ts;
4080 run.time_msw = msw_ts;
4081
4082 rc = apr_send_pkt(ac->apr, (uint32_t *) &run);
4083 if (rc < 0) {
4084 pr_err("%s: Commmand run failed[%d]", __func__, rc);
4085 return -EINVAL;
4086 }
4087 return 0;
4088}
4089
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304090/**
4091 * q6asm_run_nowait -
4092 * command to set ASM to run state with no wait for ack
4093 *
4094 * @ac: Audio client handle
4095 * @flags: Flags for session
4096 * @msw_ts: upper 32bits timestamp
4097 * @lsw_ts: lower 32bits timestamp
4098 *
4099 * Returns 0 on success or error on failure
4100 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304101int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
4102 uint32_t msw_ts, uint32_t lsw_ts)
4103{
4104 return __q6asm_run_nowait(ac, flags, msw_ts, lsw_ts, ac->stream_id);
4105}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304106EXPORT_SYMBOL(q6asm_run_nowait);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304107
4108int q6asm_stream_run_nowait(struct audio_client *ac, uint32_t flags,
4109 uint32_t msw_ts, uint32_t lsw_ts, uint32_t stream_id)
4110{
4111 return __q6asm_run_nowait(ac, flags, msw_ts, lsw_ts, stream_id);
4112}
4113
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304114/**
4115 * q6asm_enc_cfg_blk_aac -
4116 * command to set encode cfg block for aac
4117 *
4118 * @ac: Audio client handle
4119 * @frames_per_buf: number of frames per buffer
4120 * @sample_rate: Sample rate
4121 * @channels: number of ASM channels
4122 * @bit_rate: Bit rate info
4123 * @mode: mode of AAC stream encode
4124 * @format: aac format flag
4125 *
4126 * Returns 0 on success or error on failure
4127 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304128int q6asm_enc_cfg_blk_aac(struct audio_client *ac,
4129 uint32_t frames_per_buf,
4130 uint32_t sample_rate, uint32_t channels,
4131 uint32_t bit_rate, uint32_t mode, uint32_t format)
4132{
4133 struct asm_aac_enc_cfg_v2 enc_cfg;
4134 int rc = 0;
4135
4136 pr_debug("%s: session[%d]frames[%d]SR[%d]ch[%d]bitrate[%d]mode[%d] format[%d]\n",
4137 __func__, ac->session, frames_per_buf,
4138 sample_rate, channels, bit_rate, mode, format);
4139
4140 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
4141 atomic_set(&ac->cmd_state, -1);
4142
4143 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4144 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
4145 enc_cfg.encdec.param_size = sizeof(struct asm_aac_enc_cfg_v2) -
4146 sizeof(struct asm_stream_cmd_set_encdec_param);
4147 enc_cfg.encblk.frames_per_buf = frames_per_buf;
4148 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
4149 sizeof(struct asm_enc_cfg_blk_param_v2);
4150 enc_cfg.bit_rate = bit_rate;
4151 enc_cfg.enc_mode = mode;
4152 enc_cfg.aac_fmt_flag = format;
4153 enc_cfg.channel_cfg = channels;
4154 enc_cfg.sample_rate = sample_rate;
4155
4156 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
4157 if (rc < 0) {
4158 pr_err("%s: Comamnd %d failed %d\n",
4159 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
4160 rc = -EINVAL;
4161 goto fail_cmd;
4162 }
4163 rc = wait_event_timeout(ac->cmd_wait,
4164 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4165 if (!rc) {
4166 pr_err("%s: timeout. waited for FORMAT_UPDATE\n",
4167 __func__);
4168 rc = -ETIMEDOUT;
4169 goto fail_cmd;
4170 }
4171 if (atomic_read(&ac->cmd_state) > 0) {
4172 pr_err("%s: DSP returned error[%s]\n",
4173 __func__, adsp_err_get_err_str(
4174 atomic_read(&ac->cmd_state)));
4175 rc = adsp_err_get_lnx_err_code(
4176 atomic_read(&ac->cmd_state));
4177 goto fail_cmd;
4178 }
4179 return 0;
4180fail_cmd:
4181 return rc;
4182}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304183EXPORT_SYMBOL(q6asm_enc_cfg_blk_aac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304184
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304185/**
4186 * q6asm_enc_cfg_blk_g711 -
4187 * command to set encode cfg block for g711
4188 *
4189 * @ac: Audio client handle
4190 * @frames_per_buf: number of frames per buffer
4191 * @sample_rate: Sample rate
4192 *
4193 * Returns 0 on success or error on failure
4194 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304195int q6asm_enc_cfg_blk_g711(struct audio_client *ac,
4196 uint32_t frames_per_buf,
4197 uint32_t sample_rate)
4198{
4199 struct asm_g711_enc_cfg_v2 enc_cfg;
4200 int rc = 0;
4201
4202 pr_debug("%s: session[%d]frames[%d]SR[%d]\n",
4203 __func__, ac->session, frames_per_buf,
4204 sample_rate);
4205
4206 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
4207 atomic_set(&ac->cmd_state, -1);
4208
4209 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4210 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
4211 enc_cfg.encdec.param_size = sizeof(struct asm_g711_enc_cfg_v2) -
4212 sizeof(struct asm_stream_cmd_set_encdec_param);
4213 enc_cfg.encblk.frames_per_buf = frames_per_buf;
4214 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
4215 sizeof(struct asm_enc_cfg_blk_param_v2);
4216 enc_cfg.sample_rate = sample_rate;
4217
4218 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
4219 if (rc < 0) {
4220 pr_err("%s: Comamnd %d failed %d\n",
4221 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
4222 rc = -EINVAL;
4223 goto fail_cmd;
4224 }
4225 rc = wait_event_timeout(ac->cmd_wait,
4226 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4227 if (!rc) {
4228 pr_err("%s: timeout. waited for FORMAT_UPDATE\n",
4229 __func__);
4230 rc = -ETIMEDOUT;
4231 goto fail_cmd;
4232 }
4233 if (atomic_read(&ac->cmd_state) > 0) {
4234 pr_err("%s: DSP returned error[%s]\n",
4235 __func__, adsp_err_get_err_str(
4236 atomic_read(&ac->cmd_state)));
4237 rc = adsp_err_get_lnx_err_code(
4238 atomic_read(&ac->cmd_state));
4239 goto fail_cmd;
4240 }
4241 return 0;
4242fail_cmd:
4243 return rc;
4244}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304245EXPORT_SYMBOL(q6asm_enc_cfg_blk_g711);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304246
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304247/**
4248 * q6asm_set_encdec_chan_map -
4249 * command to set encdec channel map
4250 *
4251 * @ac: Audio client handle
4252 * @channels: number of channels
4253 *
4254 * Returns 0 on success or error on failure
4255 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304256int q6asm_set_encdec_chan_map(struct audio_client *ac,
4257 uint32_t num_channels)
4258{
4259 struct asm_dec_out_chan_map_param chan_map;
4260 u8 *channel_mapping;
4261 int rc = 0;
4262
4263 pr_debug("%s: Session %d, num_channels = %d\n",
4264 __func__, ac->session, num_channels);
4265 q6asm_add_hdr(ac, &chan_map.hdr, sizeof(chan_map), TRUE);
4266 atomic_set(&ac->cmd_state, -1);
4267 chan_map.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4268 chan_map.encdec.param_id = ASM_PARAM_ID_DEC_OUTPUT_CHAN_MAP;
4269 chan_map.encdec.param_size = sizeof(struct asm_dec_out_chan_map_param) -
4270 (sizeof(struct apr_hdr) +
4271 sizeof(struct asm_stream_cmd_set_encdec_param));
4272 chan_map.num_channels = num_channels;
4273 channel_mapping = chan_map.channel_mapping;
4274 memset(channel_mapping, PCM_CHANNEL_NULL, MAX_CHAN_MAP_CHANNELS);
4275
4276 if (q6asm_map_channels(channel_mapping, num_channels, false)) {
4277 pr_err("%s: map channels failed %d\n", __func__, num_channels);
4278 return -EINVAL;
4279 }
4280
4281 rc = apr_send_pkt(ac->apr, (uint32_t *) &chan_map);
4282 if (rc < 0) {
4283 pr_err("%s: Command opcode[0x%x]paramid[0x%x] failed %d\n",
4284 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM,
4285 ASM_PARAM_ID_DEC_OUTPUT_CHAN_MAP, rc);
4286 goto fail_cmd;
4287 }
4288 rc = wait_event_timeout(ac->cmd_wait,
4289 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4290 if (!rc) {
4291 pr_err("%s: timeout opcode[0x%x]\n", __func__,
4292 chan_map.hdr.opcode);
4293 rc = -ETIMEDOUT;
4294 goto fail_cmd;
4295 }
4296 if (atomic_read(&ac->cmd_state) > 0) {
4297 pr_err("%s: DSP returned error[%s]\n",
4298 __func__, adsp_err_get_err_str(
4299 atomic_read(&ac->cmd_state)));
4300 rc = adsp_err_get_lnx_err_code(
4301 atomic_read(&ac->cmd_state));
4302 goto fail_cmd;
4303 }
4304 return 0;
4305fail_cmd:
4306 return rc;
4307}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304308EXPORT_SYMBOL(q6asm_set_encdec_chan_map);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304309
4310/*
4311 * q6asm_enc_cfg_blk_pcm_v4 - sends encoder configuration parameters
4312 *
4313 * @ac: Client session handle
4314 * @rate: sample rate
4315 * @channels: number of channels
4316 * @bits_per_sample: bit width of encoder session
4317 * @use_default_chmap: true if default channel map to be used
4318 * @use_back_flavor: to configure back left and right channel
4319 * @channel_map: input channel map
4320 * @sample_word_size: Size in bits of the word that holds a sample of a channel
4321 * @endianness: endianness of the pcm data
4322 * @mode: Mode to provide additional info about the pcm input data
4323 */
4324int q6asm_enc_cfg_blk_pcm_v4(struct audio_client *ac,
4325 uint32_t rate, uint32_t channels,
4326 uint16_t bits_per_sample, bool use_default_chmap,
4327 bool use_back_flavor, u8 *channel_map,
4328 uint16_t sample_word_size, uint16_t endianness,
4329 uint16_t mode)
4330{
4331 struct asm_multi_channel_pcm_enc_cfg_v4 enc_cfg;
4332 struct asm_enc_cfg_blk_param_v2 enc_fg_blk;
4333 u8 *channel_mapping;
4334 u32 frames_per_buf = 0;
4335 int rc;
4336
4337 if (!use_default_chmap && (channel_map == NULL)) {
4338 pr_err("%s: No valid chan map and can't use default\n",
4339 __func__);
4340 rc = -EINVAL;
4341 goto fail_cmd;
4342 }
4343
4344 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
4345 ac->session, rate, channels,
4346 bits_per_sample, sample_word_size);
4347
4348 memset(&enc_cfg, 0, sizeof(enc_cfg));
4349 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
4350 atomic_set(&ac->cmd_state, -1);
4351 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4352 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
4353 enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
4354 sizeof(enc_cfg.encdec);
4355 enc_cfg.encblk.frames_per_buf = frames_per_buf;
4356 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
4357 sizeof(enc_fg_blk);
4358 enc_cfg.num_channels = channels;
4359 enc_cfg.bits_per_sample = bits_per_sample;
4360 enc_cfg.sample_rate = rate;
4361 enc_cfg.is_signed = 1;
4362 enc_cfg.sample_word_size = sample_word_size;
4363 enc_cfg.endianness = endianness;
4364 enc_cfg.mode = mode;
4365 channel_mapping = enc_cfg.channel_mapping;
4366
4367 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
4368
4369 if (use_default_chmap) {
4370 pr_debug("%s: setting default channel map for %d channels",
4371 __func__, channels);
4372 if (q6asm_map_channels(channel_mapping, channels,
4373 use_back_flavor)) {
4374 pr_err("%s: map channels failed %d\n",
4375 __func__, channels);
4376 rc = -EINVAL;
4377 goto fail_cmd;
4378 }
4379 } else {
4380 pr_debug("%s: Using pre-defined channel map", __func__);
4381 memcpy(channel_mapping, channel_map,
4382 PCM_FORMAT_MAX_NUM_CHANNEL);
4383 }
4384
4385 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
4386 if (rc < 0) {
4387 pr_err("%s: Command open failed %d\n", __func__, rc);
4388 goto fail_cmd;
4389 }
4390 rc = wait_event_timeout(ac->cmd_wait,
4391 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4392 if (!rc) {
4393 pr_err("%s: timeout opcode[0x%x]\n",
4394 __func__, enc_cfg.hdr.opcode);
4395 rc = -ETIMEDOUT;
4396 goto fail_cmd;
4397 }
4398 if (atomic_read(&ac->cmd_state) > 0) {
4399 pr_err("%s: DSP returned error[%s]\n",
4400 __func__, adsp_err_get_err_str(
4401 atomic_read(&ac->cmd_state)));
4402 rc = adsp_err_get_lnx_err_code(
4403 atomic_read(&ac->cmd_state));
4404 goto fail_cmd;
4405 }
4406 return 0;
4407fail_cmd:
4408 return rc;
4409}
4410EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_v4);
4411
4412/*
4413 * q6asm_enc_cfg_blk_pcm_v3 - sends encoder configuration parameters
4414 *
4415 * @ac: Client session handle
4416 * @rate: sample rate
4417 * @channels: number of channels
4418 * @bits_per_sample: bit width of encoder session
4419 * @use_default_chmap: true if default channel map to be used
4420 * @use_back_flavor: to configure back left and right channel
4421 * @channel_map: input channel map
4422 * @sample_word_size: Size in bits of the word that holds a sample of a channel
4423 */
4424int q6asm_enc_cfg_blk_pcm_v3(struct audio_client *ac,
4425 uint32_t rate, uint32_t channels,
4426 uint16_t bits_per_sample, bool use_default_chmap,
4427 bool use_back_flavor, u8 *channel_map,
4428 uint16_t sample_word_size)
4429{
4430 struct asm_multi_channel_pcm_enc_cfg_v3 enc_cfg;
4431 struct asm_enc_cfg_blk_param_v2 enc_fg_blk;
4432 u8 *channel_mapping;
4433 u32 frames_per_buf = 0;
4434 int rc;
4435
4436 if (!use_default_chmap && (channel_map == NULL)) {
4437 pr_err("%s: No valid chan map and can't use default\n",
4438 __func__);
4439 rc = -EINVAL;
4440 goto fail_cmd;
4441 }
4442
4443 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
4444 ac->session, rate, channels,
4445 bits_per_sample, sample_word_size);
4446
4447 memset(&enc_cfg, 0, sizeof(enc_cfg));
4448 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
4449 atomic_set(&ac->cmd_state, -1);
4450 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4451 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
4452 enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
4453 sizeof(enc_cfg.encdec);
4454 enc_cfg.encblk.frames_per_buf = frames_per_buf;
4455 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
4456 sizeof(enc_fg_blk);
4457 enc_cfg.num_channels = channels;
4458 enc_cfg.bits_per_sample = bits_per_sample;
4459 enc_cfg.sample_rate = rate;
4460 enc_cfg.is_signed = 1;
4461 enc_cfg.sample_word_size = sample_word_size;
4462 channel_mapping = enc_cfg.channel_mapping;
4463
4464 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
4465
4466 if (use_default_chmap) {
4467 pr_debug("%s: setting default channel map for %d channels",
4468 __func__, channels);
4469 if (q6asm_map_channels(channel_mapping, channels,
4470 use_back_flavor)) {
4471 pr_err("%s: map channels failed %d\n",
4472 __func__, channels);
4473 rc = -EINVAL;
4474 goto fail_cmd;
4475 }
4476 } else {
4477 pr_debug("%s: Using pre-defined channel map", __func__);
4478 memcpy(channel_mapping, channel_map,
4479 PCM_FORMAT_MAX_NUM_CHANNEL);
4480 }
4481
4482 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
4483 if (rc < 0) {
4484 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
4485 goto fail_cmd;
4486 }
4487 rc = wait_event_timeout(ac->cmd_wait,
4488 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4489 if (!rc) {
4490 pr_err("%s: timeout opcode[0x%x]\n",
4491 __func__, enc_cfg.hdr.opcode);
4492 rc = -ETIMEDOUT;
4493 goto fail_cmd;
4494 }
4495 if (atomic_read(&ac->cmd_state) > 0) {
4496 pr_err("%s: DSP returned error[%s]\n",
4497 __func__, adsp_err_get_err_str(
4498 atomic_read(&ac->cmd_state)));
4499 rc = adsp_err_get_lnx_err_code(
4500 atomic_read(&ac->cmd_state));
4501 goto fail_cmd;
4502 }
4503 return 0;
4504fail_cmd:
4505 return rc;
4506}
4507EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_v3);
4508
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304509/**
4510 * q6asm_enc_cfg_blk_pcm_v2 -
4511 * command to set encode config block for pcm_v2
4512 *
4513 * @ac: Audio client handle
4514 * @rate: sample rate
4515 * @channels: number of channels
4516 * @bits_per_sample: number of bits per sample
4517 * @use_default_chmap: Flag indicating to use default ch_map or not
4518 * @use_back_flavor: back flavor flag
4519 * @channel_map: Custom channel map settings
4520 *
4521 * Returns 0 on success or error on failure
4522 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304523int q6asm_enc_cfg_blk_pcm_v2(struct audio_client *ac,
4524 uint32_t rate, uint32_t channels, uint16_t bits_per_sample,
4525 bool use_default_chmap, bool use_back_flavor, u8 *channel_map)
4526{
4527 struct asm_multi_channel_pcm_enc_cfg_v2 enc_cfg;
4528 u8 *channel_mapping;
4529 u32 frames_per_buf = 0;
4530
4531 int rc = 0;
4532
4533 if (!use_default_chmap && (channel_map == NULL)) {
4534 pr_err("%s: No valid chan map and can't use default\n",
4535 __func__);
4536 return -EINVAL;
4537 }
4538
4539 pr_debug("%s: Session %d, rate = %d, channels = %d\n", __func__,
4540 ac->session, rate, channels);
4541
4542 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
4543 atomic_set(&ac->cmd_state, -1);
4544 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4545 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
4546 enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
4547 sizeof(enc_cfg.encdec);
4548 enc_cfg.encblk.frames_per_buf = frames_per_buf;
4549 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
4550 sizeof(struct asm_enc_cfg_blk_param_v2);
4551
4552 enc_cfg.num_channels = channels;
4553 enc_cfg.bits_per_sample = bits_per_sample;
4554 enc_cfg.sample_rate = rate;
4555 enc_cfg.is_signed = 1;
4556 channel_mapping = enc_cfg.channel_mapping;
4557
4558 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
4559
4560 if (use_default_chmap) {
4561 pr_debug("%s: setting default channel map for %d channels",
4562 __func__, channels);
4563 if (q6asm_map_channels(channel_mapping, channels,
4564 use_back_flavor)) {
4565 pr_err("%s: map channels failed %d\n",
4566 __func__, channels);
4567 return -EINVAL;
4568 }
4569 } else {
4570 pr_debug("%s: Using pre-defined channel map", __func__);
4571 memcpy(channel_mapping, channel_map,
4572 PCM_FORMAT_MAX_NUM_CHANNEL);
4573 }
4574
4575 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
4576 if (rc < 0) {
4577 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
4578 rc = -EINVAL;
4579 goto fail_cmd;
4580 }
4581 rc = wait_event_timeout(ac->cmd_wait,
4582 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4583 if (!rc) {
4584 pr_err("%s: timeout opcode[0x%x]\n",
4585 __func__, enc_cfg.hdr.opcode);
4586 rc = -ETIMEDOUT;
4587 goto fail_cmd;
4588 }
4589 if (atomic_read(&ac->cmd_state) > 0) {
4590 pr_err("%s: DSP returned error[%s]\n",
4591 __func__, adsp_err_get_err_str(
4592 atomic_read(&ac->cmd_state)));
4593 rc = adsp_err_get_lnx_err_code(
4594 atomic_read(&ac->cmd_state));
4595 goto fail_cmd;
4596 }
4597 return 0;
4598fail_cmd:
4599 return rc;
4600}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304601EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_v2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304602
4603static int __q6asm_enc_cfg_blk_pcm_v4(struct audio_client *ac,
4604 uint32_t rate, uint32_t channels,
4605 uint16_t bits_per_sample,
4606 uint16_t sample_word_size,
4607 uint16_t endianness,
4608 uint16_t mode)
4609{
4610 return q6asm_enc_cfg_blk_pcm_v4(ac, rate, channels,
4611 bits_per_sample, true, false, NULL,
4612 sample_word_size, endianness, mode);
4613}
4614
4615static int __q6asm_enc_cfg_blk_pcm_v3(struct audio_client *ac,
4616 uint32_t rate, uint32_t channels,
4617 uint16_t bits_per_sample,
4618 uint16_t sample_word_size)
4619{
4620 return q6asm_enc_cfg_blk_pcm_v3(ac, rate, channels,
4621 bits_per_sample, true, false, NULL,
4622 sample_word_size);
4623}
4624
4625static int __q6asm_enc_cfg_blk_pcm(struct audio_client *ac,
4626 uint32_t rate, uint32_t channels, uint16_t bits_per_sample)
4627{
4628 return q6asm_enc_cfg_blk_pcm_v2(ac, rate, channels,
4629 bits_per_sample, true, false, NULL);
4630}
4631
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304632/**
4633 * q6asm_enc_cfg_blk_pcm -
4634 * command to set encode config block for pcm
4635 *
4636 * @ac: Audio client handle
4637 * @rate: sample rate
4638 * @channels: number of channels
4639 *
4640 * Returns 0 on success or error on failure
4641 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304642int q6asm_enc_cfg_blk_pcm(struct audio_client *ac,
4643 uint32_t rate, uint32_t channels)
4644{
4645 return __q6asm_enc_cfg_blk_pcm(ac, rate, channels, 16);
4646}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304647EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304648
4649int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
4650 uint32_t rate, uint32_t channels, uint16_t bits_per_sample)
4651{
4652 return __q6asm_enc_cfg_blk_pcm(ac, rate, channels, bits_per_sample);
4653}
4654
4655/*
4656 * q6asm_enc_cfg_blk_pcm_format_support_v3 - sends encoder configuration
4657 * parameters
4658 *
4659 * @ac: Client session handle
4660 * @rate: sample rate
4661 * @channels: number of channels
4662 * @bits_per_sample: bit width of encoder session
4663 * @sample_word_size: Size in bits of the word that holds a sample of a channel
4664 */
4665int q6asm_enc_cfg_blk_pcm_format_support_v3(struct audio_client *ac,
4666 uint32_t rate, uint32_t channels,
4667 uint16_t bits_per_sample,
4668 uint16_t sample_word_size)
4669{
4670 return __q6asm_enc_cfg_blk_pcm_v3(ac, rate, channels,
4671 bits_per_sample, sample_word_size);
4672}
4673EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_format_support_v3);
4674
4675/*
4676 * q6asm_enc_cfg_blk_pcm_format_support_v4 - sends encoder configuration
4677 * parameters
4678 *
4679 * @ac: Client session handle
4680 * @rate: sample rate
4681 * @channels: number of channels
4682 * @bits_per_sample: bit width of encoder session
4683 * @sample_word_size: Size in bits of the word that holds a sample of a channel
4684 * @endianness: endianness of the pcm data
4685 * @mode: Mode to provide additional info about the pcm input data
4686 */
4687int q6asm_enc_cfg_blk_pcm_format_support_v4(struct audio_client *ac,
4688 uint32_t rate, uint32_t channels,
4689 uint16_t bits_per_sample,
4690 uint16_t sample_word_size,
4691 uint16_t endianness,
4692 uint16_t mode)
4693{
4694 return __q6asm_enc_cfg_blk_pcm_v4(ac, rate, channels,
4695 bits_per_sample, sample_word_size,
4696 endianness, mode);
4697}
4698EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_format_support_v4);
4699
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304700/**
4701 * q6asm_enc_cfg_blk_pcm_native -
4702 * command to set encode config block for pcm_native
4703 *
4704 * @ac: Audio client handle
4705 * @rate: sample rate
4706 * @channels: number of channels
4707 *
4708 * Returns 0 on success or error on failure
4709 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304710int q6asm_enc_cfg_blk_pcm_native(struct audio_client *ac,
4711 uint32_t rate, uint32_t channels)
4712{
4713 struct asm_multi_channel_pcm_enc_cfg_v2 enc_cfg;
4714 u8 *channel_mapping;
4715 u32 frames_per_buf = 0;
4716
4717 int rc = 0;
4718
4719 pr_debug("%s: Session %d, rate = %d, channels = %d\n", __func__,
4720 ac->session, rate, channels);
4721
4722 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
4723 atomic_set(&ac->cmd_state, -1);
4724 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4725 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
4726 enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
4727 sizeof(enc_cfg.encdec);
4728 enc_cfg.encblk.frames_per_buf = frames_per_buf;
4729 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
4730 sizeof(struct asm_enc_cfg_blk_param_v2);
4731
4732 enc_cfg.num_channels = 0;/*channels;*/
4733 enc_cfg.bits_per_sample = 16;
4734 enc_cfg.sample_rate = 0;/*rate;*/
4735 enc_cfg.is_signed = 1;
4736 channel_mapping = enc_cfg.channel_mapping;
4737
4738
4739 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
4740
4741 if (q6asm_map_channels(channel_mapping, channels, false)) {
4742 pr_err("%s: map channels failed %d\n", __func__, channels);
4743 return -EINVAL;
4744 }
4745
4746 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
4747 if (rc < 0) {
4748 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
4749 rc = -EINVAL;
4750 goto fail_cmd;
4751 }
4752 rc = wait_event_timeout(ac->cmd_wait,
4753 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4754 if (!rc) {
4755 pr_err("%s: timeout opcode[0x%x]\n",
4756 __func__, enc_cfg.hdr.opcode);
4757 rc = -ETIMEDOUT;
4758 goto fail_cmd;
4759 }
4760 if (atomic_read(&ac->cmd_state) > 0) {
4761 pr_err("%s: DSP returned error[%s]\n",
4762 __func__, adsp_err_get_err_str(
4763 atomic_read(&ac->cmd_state)));
4764 rc = adsp_err_get_lnx_err_code(
4765 atomic_read(&ac->cmd_state));
4766 goto fail_cmd;
4767 }
4768 return 0;
4769fail_cmd:
4770 return rc;
4771}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304772EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_native);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304773
4774static int q6asm_map_channels(u8 *channel_mapping, uint32_t channels,
4775 bool use_back_flavor)
4776{
4777 u8 *lchannel_mapping;
4778
4779 lchannel_mapping = channel_mapping;
4780 pr_debug("%s: channels passed: %d\n", __func__, channels);
4781 if (channels == 1) {
4782 lchannel_mapping[0] = PCM_CHANNEL_FC;
4783 } else if (channels == 2) {
4784 lchannel_mapping[0] = PCM_CHANNEL_FL;
4785 lchannel_mapping[1] = PCM_CHANNEL_FR;
4786 } else if (channels == 3) {
4787 lchannel_mapping[0] = PCM_CHANNEL_FL;
4788 lchannel_mapping[1] = PCM_CHANNEL_FR;
4789 lchannel_mapping[2] = PCM_CHANNEL_FC;
4790 } else if (channels == 4) {
4791 lchannel_mapping[0] = PCM_CHANNEL_FL;
4792 lchannel_mapping[1] = PCM_CHANNEL_FR;
4793 lchannel_mapping[2] = use_back_flavor ?
4794 PCM_CHANNEL_LB : PCM_CHANNEL_LS;
4795 lchannel_mapping[3] = use_back_flavor ?
4796 PCM_CHANNEL_RB : PCM_CHANNEL_RS;
4797 } else if (channels == 5) {
4798 lchannel_mapping[0] = PCM_CHANNEL_FL;
4799 lchannel_mapping[1] = PCM_CHANNEL_FR;
4800 lchannel_mapping[2] = PCM_CHANNEL_FC;
4801 lchannel_mapping[3] = use_back_flavor ?
4802 PCM_CHANNEL_LB : PCM_CHANNEL_LS;
4803 lchannel_mapping[4] = use_back_flavor ?
4804 PCM_CHANNEL_RB : PCM_CHANNEL_RS;
4805 } else if (channels == 6) {
4806 lchannel_mapping[0] = PCM_CHANNEL_FL;
4807 lchannel_mapping[1] = PCM_CHANNEL_FR;
4808 lchannel_mapping[2] = PCM_CHANNEL_FC;
4809 lchannel_mapping[3] = PCM_CHANNEL_LFE;
4810 lchannel_mapping[4] = use_back_flavor ?
4811 PCM_CHANNEL_LB : PCM_CHANNEL_LS;
4812 lchannel_mapping[5] = use_back_flavor ?
4813 PCM_CHANNEL_RB : PCM_CHANNEL_RS;
4814 } else if (channels == 7) {
4815 /*
4816 * Configured for 5.1 channel mapping + 1 channel for debug
4817 * Can be customized based on DSP.
4818 */
4819 lchannel_mapping[0] = PCM_CHANNEL_FL;
4820 lchannel_mapping[1] = PCM_CHANNEL_FR;
4821 lchannel_mapping[2] = PCM_CHANNEL_FC;
4822 lchannel_mapping[3] = PCM_CHANNEL_LFE;
4823 lchannel_mapping[4] = use_back_flavor ?
4824 PCM_CHANNEL_LB : PCM_CHANNEL_LS;
4825 lchannel_mapping[5] = use_back_flavor ?
4826 PCM_CHANNEL_RB : PCM_CHANNEL_RS;
4827 lchannel_mapping[6] = PCM_CHANNEL_CS;
4828 } else if (channels == 8) {
4829 lchannel_mapping[0] = PCM_CHANNEL_FL;
4830 lchannel_mapping[1] = PCM_CHANNEL_FR;
4831 lchannel_mapping[2] = PCM_CHANNEL_FC;
4832 lchannel_mapping[3] = PCM_CHANNEL_LFE;
4833 lchannel_mapping[4] = PCM_CHANNEL_LB;
4834 lchannel_mapping[5] = PCM_CHANNEL_RB;
4835 lchannel_mapping[6] = PCM_CHANNEL_LS;
4836 lchannel_mapping[7] = PCM_CHANNEL_RS;
4837 } else {
4838 pr_err("%s: ERROR.unsupported num_ch = %u\n",
4839 __func__, channels);
4840 return -EINVAL;
4841 }
4842 return 0;
4843}
4844
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304845/**
4846 * q6asm_enable_sbrps -
4847 * command to enable sbrps for ASM
4848 *
4849 * @ac: Audio client handle
4850 * @sbr_ps_enable: flag for sbr_ps enable or disable
4851 *
4852 * Returns 0 on success or error on failure
4853 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304854int q6asm_enable_sbrps(struct audio_client *ac,
4855 uint32_t sbr_ps_enable)
4856{
4857 struct asm_aac_sbr_ps_flag_param sbrps;
4858 u32 frames_per_buf = 0;
4859
4860 int rc = 0;
4861
4862 pr_debug("%s: Session %d\n", __func__, ac->session);
4863
4864 q6asm_add_hdr(ac, &sbrps.hdr, sizeof(sbrps), TRUE);
4865 atomic_set(&ac->cmd_state, -1);
4866
4867 sbrps.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4868 sbrps.encdec.param_id = ASM_PARAM_ID_AAC_SBR_PS_FLAG;
4869 sbrps.encdec.param_size = sizeof(struct asm_aac_sbr_ps_flag_param) -
4870 sizeof(struct asm_stream_cmd_set_encdec_param);
4871 sbrps.encblk.frames_per_buf = frames_per_buf;
4872 sbrps.encblk.enc_cfg_blk_size = sbrps.encdec.param_size -
4873 sizeof(struct asm_enc_cfg_blk_param_v2);
4874
4875 sbrps.sbr_ps_flag = sbr_ps_enable;
4876
4877 rc = apr_send_pkt(ac->apr, (uint32_t *) &sbrps);
4878 if (rc < 0) {
4879 pr_err("%s: Command opcode[0x%x]paramid[0x%x] failed %d\n",
4880 __func__,
4881 ASM_STREAM_CMD_SET_ENCDEC_PARAM,
4882 ASM_PARAM_ID_AAC_SBR_PS_FLAG, rc);
4883 rc = -EINVAL;
4884 goto fail_cmd;
4885 }
4886 rc = wait_event_timeout(ac->cmd_wait,
4887 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4888 if (!rc) {
4889 pr_err("%s: timeout opcode[0x%x] ", __func__, sbrps.hdr.opcode);
4890 rc = -ETIMEDOUT;
4891 goto fail_cmd;
4892 }
4893 if (atomic_read(&ac->cmd_state) > 0) {
4894 pr_err("%s: DSP returned error[%s]\n",
4895 __func__, adsp_err_get_err_str(
4896 atomic_read(&ac->cmd_state)));
4897 rc = adsp_err_get_lnx_err_code(
4898 atomic_read(&ac->cmd_state));
4899 goto fail_cmd;
4900 }
4901 return 0;
4902fail_cmd:
4903 return rc;
4904}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304905EXPORT_SYMBOL(q6asm_enable_sbrps);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304906
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304907/**
4908 * q6asm_cfg_dual_mono_aac -
4909 * command to set config for dual mono aac
4910 *
4911 * @ac: Audio client handle
4912 * @sce_left: left sce val
4913 * @sce_right: right sce val
4914 *
4915 * Returns 0 on success or error on failure
4916 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304917int q6asm_cfg_dual_mono_aac(struct audio_client *ac,
4918 uint16_t sce_left, uint16_t sce_right)
4919{
4920 struct asm_aac_dual_mono_mapping_param dual_mono;
4921
4922 int rc = 0;
4923
4924 pr_debug("%s: Session %d, sce_left = %d, sce_right = %d\n",
4925 __func__, ac->session, sce_left, sce_right);
4926
4927 q6asm_add_hdr(ac, &dual_mono.hdr, sizeof(dual_mono), TRUE);
4928 atomic_set(&ac->cmd_state, -1);
4929
4930 dual_mono.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4931 dual_mono.encdec.param_id = ASM_PARAM_ID_AAC_DUAL_MONO_MAPPING;
4932 dual_mono.encdec.param_size = sizeof(dual_mono.left_channel_sce) +
4933 sizeof(dual_mono.right_channel_sce);
4934 dual_mono.left_channel_sce = sce_left;
4935 dual_mono.right_channel_sce = sce_right;
4936
4937 rc = apr_send_pkt(ac->apr, (uint32_t *) &dual_mono);
4938 if (rc < 0) {
4939 pr_err("%s: Command opcode[0x%x]paramid[0x%x] failed %d\n",
4940 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM,
4941 ASM_PARAM_ID_AAC_DUAL_MONO_MAPPING, rc);
4942 rc = -EINVAL;
4943 goto fail_cmd;
4944 }
4945 rc = wait_event_timeout(ac->cmd_wait,
4946 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4947 if (!rc) {
4948 pr_err("%s: timeout opcode[0x%x]\n", __func__,
4949 dual_mono.hdr.opcode);
4950 rc = -ETIMEDOUT;
4951 goto fail_cmd;
4952 }
4953 if (atomic_read(&ac->cmd_state) > 0) {
4954 pr_err("%s: DSP returned error[%s]\n",
4955 __func__, adsp_err_get_err_str(
4956 atomic_read(&ac->cmd_state)));
4957 rc = adsp_err_get_lnx_err_code(
4958 atomic_read(&ac->cmd_state));
4959 goto fail_cmd;
4960 }
4961 return 0;
4962fail_cmd:
4963 return rc;
4964}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304965EXPORT_SYMBOL(q6asm_cfg_dual_mono_aac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304966
4967/* Support for selecting stereo mixing coefficients for B family not done */
4968int q6asm_cfg_aac_sel_mix_coef(struct audio_client *ac, uint32_t mix_coeff)
4969{
4970 struct asm_aac_stereo_mix_coeff_selection_param_v2 aac_mix_coeff;
4971 int rc = 0;
4972
4973 q6asm_add_hdr(ac, &aac_mix_coeff.hdr, sizeof(aac_mix_coeff), TRUE);
4974 atomic_set(&ac->cmd_state, -1);
4975 aac_mix_coeff.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4976 aac_mix_coeff.param_id =
4977 ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG_V2;
4978 aac_mix_coeff.param_size =
4979 sizeof(struct asm_aac_stereo_mix_coeff_selection_param_v2);
4980 aac_mix_coeff.aac_stereo_mix_coeff_flag = mix_coeff;
4981 pr_debug("%s: mix_coeff = %u\n", __func__, mix_coeff);
4982 rc = apr_send_pkt(ac->apr, (uint32_t *) &aac_mix_coeff);
4983 if (rc < 0) {
4984 pr_err("%s: Command opcode[0x%x]paramid[0x%x] failed %d\n",
4985 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM,
4986 ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG_V2,
4987 rc);
4988 rc = -EINVAL;
4989 goto fail_cmd;
4990 }
4991 rc = wait_event_timeout(ac->cmd_wait,
4992 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4993 if (!rc) {
4994 pr_err("%s: timeout opcode[0x%x]\n",
4995 __func__, aac_mix_coeff.hdr.opcode);
4996 rc = -ETIMEDOUT;
4997 goto fail_cmd;
4998 }
4999 if (atomic_read(&ac->cmd_state) > 0) {
5000 pr_err("%s: DSP returned error[%s]\n",
5001 __func__, adsp_err_get_err_str(
5002 atomic_read(&ac->cmd_state)));
5003 rc = adsp_err_get_lnx_err_code(
5004 atomic_read(&ac->cmd_state));
5005 goto fail_cmd;
5006 }
5007 return 0;
5008fail_cmd:
5009 return rc;
5010}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305011EXPORT_SYMBOL(q6asm_cfg_aac_sel_mix_coef);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305012
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305013/**
5014 * q6asm_enc_cfg_blk_qcelp -
5015 * command to set encode config block for QCELP
5016 *
5017 * @ac: Audio client handle
5018 * @frames_per_buf: Number of frames per buffer
5019 * @min_rate: Minimum Enc rate
5020 * @max_rate: Maximum Enc rate
5021 * reduced_rate_level: Reduced rate level
5022 * @rate_modulation_cmd: rate modulation command
5023 *
5024 * Returns 0 on success or error on failure
5025 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305026int q6asm_enc_cfg_blk_qcelp(struct audio_client *ac, uint32_t frames_per_buf,
5027 uint16_t min_rate, uint16_t max_rate,
5028 uint16_t reduced_rate_level, uint16_t rate_modulation_cmd)
5029{
5030 struct asm_v13k_enc_cfg enc_cfg;
5031 int rc = 0;
5032
5033 pr_debug("%s: session[%d]frames[%d]min_rate[0x%4x]max_rate[0x%4x] reduced_rate_level[0x%4x]rate_modulation_cmd[0x%4x]\n",
5034 __func__,
5035 ac->session, frames_per_buf, min_rate, max_rate,
5036 reduced_rate_level, rate_modulation_cmd);
5037
5038 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
5039 atomic_set(&ac->cmd_state, -1);
5040 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
5041 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
5042 enc_cfg.encdec.param_size = sizeof(struct asm_v13k_enc_cfg) -
5043 sizeof(struct asm_stream_cmd_set_encdec_param);
5044 enc_cfg.encblk.frames_per_buf = frames_per_buf;
5045 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
5046 sizeof(struct asm_enc_cfg_blk_param_v2);
5047
5048 enc_cfg.min_rate = min_rate;
5049 enc_cfg.max_rate = max_rate;
5050 enc_cfg.reduced_rate_cmd = reduced_rate_level;
5051 enc_cfg.rate_mod_cmd = rate_modulation_cmd;
5052
5053 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
5054 if (rc < 0) {
5055 pr_err("%s: Comamnd %d failed %d\n",
5056 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
5057 rc = -EINVAL;
5058 goto fail_cmd;
5059 }
5060 rc = wait_event_timeout(ac->cmd_wait,
5061 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5062 if (!rc) {
5063 pr_err("%s: timeout. waited for setencdec v13k resp\n",
5064 __func__);
5065 rc = -ETIMEDOUT;
5066 goto fail_cmd;
5067 }
5068 if (atomic_read(&ac->cmd_state) > 0) {
5069 pr_err("%s: DSP returned error[%s]\n",
5070 __func__, adsp_err_get_err_str(
5071 atomic_read(&ac->cmd_state)));
5072 rc = adsp_err_get_lnx_err_code(
5073 atomic_read(&ac->cmd_state));
5074 goto fail_cmd;
5075 }
5076 return 0;
5077fail_cmd:
5078 return rc;
5079}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305080EXPORT_SYMBOL(q6asm_enc_cfg_blk_qcelp);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305081
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305082/**
5083 * q6asm_enc_cfg_blk_evrc -
5084 * command to set encode config block for EVRC
5085 *
5086 * @ac: Audio client handle
5087 * @frames_per_buf: Number of frames per buffer
5088 * @min_rate: Minimum Enc rate
5089 * @max_rate: Maximum Enc rate
5090 * @rate_modulation_cmd: rate modulation command
5091 *
5092 * Returns 0 on success or error on failure
5093 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305094int q6asm_enc_cfg_blk_evrc(struct audio_client *ac, uint32_t frames_per_buf,
5095 uint16_t min_rate, uint16_t max_rate,
5096 uint16_t rate_modulation_cmd)
5097{
5098 struct asm_evrc_enc_cfg enc_cfg;
5099 int rc = 0;
5100
5101 pr_debug("%s: session[%d]frames[%d]min_rate[0x%4x]max_rate[0x%4x] rate_modulation_cmd[0x%4x]\n",
5102 __func__, ac->session,
5103 frames_per_buf, min_rate, max_rate, rate_modulation_cmd);
5104
5105 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
5106 atomic_set(&ac->cmd_state, -1);
5107 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
5108 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
5109 enc_cfg.encdec.param_size = sizeof(struct asm_evrc_enc_cfg) -
5110 sizeof(struct asm_stream_cmd_set_encdec_param);
5111 enc_cfg.encblk.frames_per_buf = frames_per_buf;
5112 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
5113 sizeof(struct asm_enc_cfg_blk_param_v2);
5114
5115 enc_cfg.min_rate = min_rate;
5116 enc_cfg.max_rate = max_rate;
5117 enc_cfg.rate_mod_cmd = rate_modulation_cmd;
5118 enc_cfg.reserved = 0;
5119
5120 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
5121 if (rc < 0) {
5122 pr_err("%s: Comamnd %d failed %d\n",
5123 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
5124 rc = -EINVAL;
5125 goto fail_cmd;
5126 }
5127 rc = wait_event_timeout(ac->cmd_wait,
5128 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5129 if (!rc) {
5130 pr_err("%s: timeout. waited for encdec evrc\n", __func__);
5131 rc = -ETIMEDOUT;
5132 goto fail_cmd;
5133 }
5134 if (atomic_read(&ac->cmd_state) > 0) {
5135 pr_err("%s: DSP returned error[%s]\n",
5136 __func__, adsp_err_get_err_str(
5137 atomic_read(&ac->cmd_state)));
5138 rc = adsp_err_get_lnx_err_code(
5139 atomic_read(&ac->cmd_state));
5140 goto fail_cmd;
5141 }
5142 return 0;
5143fail_cmd:
5144 return rc;
5145}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305146EXPORT_SYMBOL(q6asm_enc_cfg_blk_evrc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305147
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305148/**
5149 * q6asm_enc_cfg_blk_amrnb -
5150 * command to set encode config block for AMRNB
5151 *
5152 * @ac: Audio client handle
5153 * @frames_per_buf: Number of frames per buffer
5154 * @band_mode: Band mode used
5155 * @dtx_enable: DTX en flag
5156 *
5157 * Returns 0 on success or error on failure
5158 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305159int q6asm_enc_cfg_blk_amrnb(struct audio_client *ac, uint32_t frames_per_buf,
5160 uint16_t band_mode, uint16_t dtx_enable)
5161{
5162 struct asm_amrnb_enc_cfg enc_cfg;
5163 int rc = 0;
5164
5165 pr_debug("%s: session[%d]frames[%d]band_mode[0x%4x]dtx_enable[0x%4x]\n",
5166 __func__, ac->session, frames_per_buf, band_mode, dtx_enable);
5167
5168 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
5169 atomic_set(&ac->cmd_state, -1);
5170 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
5171 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
5172 enc_cfg.encdec.param_size = sizeof(struct asm_amrnb_enc_cfg) -
5173 sizeof(struct asm_stream_cmd_set_encdec_param);
5174 enc_cfg.encblk.frames_per_buf = frames_per_buf;
5175 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
5176 sizeof(struct asm_enc_cfg_blk_param_v2);
5177
5178 enc_cfg.enc_mode = band_mode;
5179 enc_cfg.dtx_mode = dtx_enable;
5180
5181 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
5182 if (rc < 0) {
5183 pr_err("%s: Comamnd %d failed %d\n",
5184 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
5185 rc = -EINVAL;
5186 goto fail_cmd;
5187 }
5188 rc = wait_event_timeout(ac->cmd_wait,
5189 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5190 if (!rc) {
5191 pr_err("%s: timeout. waited for set encdec amrnb\n", __func__);
5192 rc = -ETIMEDOUT;
5193 goto fail_cmd;
5194 }
5195 if (atomic_read(&ac->cmd_state) > 0) {
5196 pr_err("%s: DSP returned error[%s]\n",
5197 __func__, adsp_err_get_err_str(
5198 atomic_read(&ac->cmd_state)));
5199 rc = adsp_err_get_lnx_err_code(
5200 atomic_read(&ac->cmd_state));
5201 goto fail_cmd;
5202 }
5203 return 0;
5204fail_cmd:
5205 return rc;
5206}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305207EXPORT_SYMBOL(q6asm_enc_cfg_blk_amrnb);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305208
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305209/**
5210 * q6asm_enc_cfg_blk_amrwb -
5211 * command to set encode config block for AMRWB
5212 *
5213 * @ac: Audio client handle
5214 * @frames_per_buf: Number of frames per buffer
5215 * @band_mode: Band mode used
5216 * @dtx_enable: DTX en flag
5217 *
5218 * Returns 0 on success or error on failure
5219 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305220int q6asm_enc_cfg_blk_amrwb(struct audio_client *ac, uint32_t frames_per_buf,
5221 uint16_t band_mode, uint16_t dtx_enable)
5222{
5223 struct asm_amrwb_enc_cfg enc_cfg;
5224 int rc = 0;
5225
5226 pr_debug("%s: session[%d]frames[%d]band_mode[0x%4x]dtx_enable[0x%4x]\n",
5227 __func__, ac->session, frames_per_buf, band_mode, dtx_enable);
5228
5229 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
5230 atomic_set(&ac->cmd_state, -1);
5231 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
5232 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
5233 enc_cfg.encdec.param_size = sizeof(struct asm_amrwb_enc_cfg) -
5234 sizeof(struct asm_stream_cmd_set_encdec_param);
5235 enc_cfg.encblk.frames_per_buf = frames_per_buf;
5236 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
5237 sizeof(struct asm_enc_cfg_blk_param_v2);
5238
5239 enc_cfg.enc_mode = band_mode;
5240 enc_cfg.dtx_mode = dtx_enable;
5241
5242 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
5243 if (rc < 0) {
5244 pr_err("%s: Comamnd %d failed %d\n",
5245 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
5246 rc = -EINVAL;
5247 goto fail_cmd;
5248 }
5249 rc = wait_event_timeout(ac->cmd_wait,
5250 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5251 if (!rc) {
5252 pr_err("%s: timeout. waited for FORMAT_UPDATE\n", __func__);
5253 rc = -ETIMEDOUT;
5254 goto fail_cmd;
5255 }
5256 if (atomic_read(&ac->cmd_state) > 0) {
5257 pr_err("%s: DSP returned error[%s]\n",
5258 __func__, adsp_err_get_err_str(
5259 atomic_read(&ac->cmd_state)));
5260 rc = adsp_err_get_lnx_err_code(
5261 atomic_read(&ac->cmd_state));
5262 goto fail_cmd;
5263 }
5264 return 0;
5265fail_cmd:
5266 return rc;
5267}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305268EXPORT_SYMBOL(q6asm_enc_cfg_blk_amrwb);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305269
5270
5271static int __q6asm_media_format_block_pcm(struct audio_client *ac,
5272 uint32_t rate, uint32_t channels,
5273 uint16_t bits_per_sample, int stream_id,
5274 bool use_default_chmap, char *channel_map)
5275{
5276 struct asm_multi_channel_pcm_fmt_blk_v2 fmt;
5277 u8 *channel_mapping;
5278 int rc = 0;
5279
5280 pr_debug("%s: session[%d]rate[%d]ch[%d]\n", __func__, ac->session, rate,
5281 channels);
5282
5283 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
5284 atomic_set(&ac->cmd_state, -1);
5285 /*
5286 * Updated the token field with stream/session for compressed playback
5287 * Platform driver must know the the stream with which the command is
5288 * associated
5289 */
5290 if (ac->io_mode & COMPRESSED_STREAM_IO)
5291 q6asm_update_token(&fmt.hdr.token,
5292 ac->session,
5293 stream_id,
5294 0, /* Buffer index is NA */
5295 0, /* Direction flag is NA */
5296 WAIT_CMD);
5297
5298 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
5299 __func__, fmt.hdr.token, stream_id, ac->session);
5300
5301 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
5302 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
5303 sizeof(fmt.fmt_blk);
5304 fmt.num_channels = channels;
5305 fmt.bits_per_sample = bits_per_sample;
5306 fmt.sample_rate = rate;
5307 fmt.is_signed = 1;
5308
5309 channel_mapping = fmt.channel_mapping;
5310
5311 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
5312
5313 if (use_default_chmap) {
5314 if (q6asm_map_channels(channel_mapping, channels, false)) {
5315 pr_err("%s: map channels failed %d\n",
5316 __func__, channels);
5317 return -EINVAL;
5318 }
5319 } else {
5320 memcpy(channel_mapping, channel_map,
5321 PCM_FORMAT_MAX_NUM_CHANNEL);
5322 }
5323
5324 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
5325 if (rc < 0) {
5326 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
5327 rc = -EINVAL;
5328 goto fail_cmd;
5329 }
5330 rc = wait_event_timeout(ac->cmd_wait,
5331 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5332 if (!rc) {
5333 pr_err("%s: timeout. waited for format update\n", __func__);
5334 rc = -ETIMEDOUT;
5335 goto fail_cmd;
5336 }
5337 if (atomic_read(&ac->cmd_state) > 0) {
5338 pr_err("%s: DSP returned error[%s]\n",
5339 __func__, adsp_err_get_err_str(
5340 atomic_read(&ac->cmd_state)));
5341 rc = adsp_err_get_lnx_err_code(
5342 atomic_read(&ac->cmd_state));
5343 goto fail_cmd;
5344 }
5345 return 0;
5346fail_cmd:
5347 return rc;
5348}
5349
5350static int __q6asm_media_format_block_pcm_v3(struct audio_client *ac,
5351 uint32_t rate, uint32_t channels,
5352 uint16_t bits_per_sample,
5353 int stream_id,
5354 bool use_default_chmap,
5355 char *channel_map,
5356 uint16_t sample_word_size)
5357{
5358 struct asm_multi_channel_pcm_fmt_blk_param_v3 fmt;
5359 u8 *channel_mapping;
5360 int rc;
5361
5362 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
5363 ac->session, rate, channels,
5364 bits_per_sample, sample_word_size);
5365
5366 memset(&fmt, 0, sizeof(fmt));
5367 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
5368 atomic_set(&ac->cmd_state, -1);
5369 /*
5370 * Updated the token field with stream/session for compressed playback
5371 * Platform driver must know the the stream with which the command is
5372 * associated
5373 */
5374 if (ac->io_mode & COMPRESSED_STREAM_IO)
5375 fmt.hdr.token = ((ac->session << 8) & 0xFFFF00) |
5376 (stream_id & 0xFF);
5377
5378 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
5379 __func__, fmt.hdr.token, stream_id, ac->session);
5380
5381 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
5382 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
5383 sizeof(fmt.fmt_blk);
5384 fmt.param.num_channels = channels;
5385 fmt.param.bits_per_sample = bits_per_sample;
5386 fmt.param.sample_rate = rate;
5387 fmt.param.is_signed = 1;
5388 fmt.param.sample_word_size = sample_word_size;
5389 channel_mapping = fmt.param.channel_mapping;
5390
5391 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
5392
5393 if (use_default_chmap) {
5394 if (q6asm_map_channels(channel_mapping, channels, false)) {
5395 pr_err("%s: map channels failed %d\n",
5396 __func__, channels);
5397 rc = -EINVAL;
5398 goto fail_cmd;
5399 }
5400 } else {
5401 memcpy(channel_mapping, channel_map,
5402 PCM_FORMAT_MAX_NUM_CHANNEL);
5403 }
5404
5405 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
5406 if (rc < 0) {
5407 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
5408 rc = -EINVAL;
5409 goto fail_cmd;
5410 }
5411 rc = wait_event_timeout(ac->cmd_wait,
5412 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5413 if (!rc) {
5414 pr_err("%s: timeout. waited for format update\n", __func__);
5415 rc = -ETIMEDOUT;
5416 goto fail_cmd;
5417 }
5418 if (atomic_read(&ac->cmd_state) > 0) {
5419 pr_err("%s: DSP returned error[%s]\n",
5420 __func__, adsp_err_get_err_str(
5421 atomic_read(&ac->cmd_state)));
5422 rc = adsp_err_get_lnx_err_code(
5423 atomic_read(&ac->cmd_state));
5424 goto fail_cmd;
5425 }
5426 return 0;
5427fail_cmd:
5428 return rc;
5429}
5430
5431static int __q6asm_media_format_block_pcm_v4(struct audio_client *ac,
5432 uint32_t rate, uint32_t channels,
5433 uint16_t bits_per_sample,
5434 int stream_id,
5435 bool use_default_chmap,
5436 char *channel_map,
5437 uint16_t sample_word_size,
5438 uint16_t endianness,
5439 uint16_t mode)
5440{
5441 struct asm_multi_channel_pcm_fmt_blk_param_v4 fmt;
5442 u8 *channel_mapping;
5443 int rc;
5444
5445 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
5446 ac->session, rate, channels,
5447 bits_per_sample, sample_word_size);
5448
5449 memset(&fmt, 0, sizeof(fmt));
5450 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
5451 atomic_set(&ac->cmd_state, -1);
5452 /*
5453 * Updated the token field with stream/session for compressed playback
5454 * Platform driver must know the the stream with which the command is
5455 * associated
5456 */
5457 if (ac->io_mode & COMPRESSED_STREAM_IO)
5458 fmt.hdr.token = ((ac->session << 8) & 0xFFFF00) |
5459 (stream_id & 0xFF);
5460
5461 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
5462 __func__, fmt.hdr.token, stream_id, ac->session);
5463
5464 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
5465 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
5466 sizeof(fmt.fmt_blk);
5467 fmt.param.num_channels = channels;
5468 fmt.param.bits_per_sample = bits_per_sample;
5469 fmt.param.sample_rate = rate;
5470 fmt.param.is_signed = 1;
5471 fmt.param.sample_word_size = sample_word_size;
5472 fmt.param.endianness = endianness;
5473 fmt.param.mode = mode;
5474 channel_mapping = fmt.param.channel_mapping;
5475
5476 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
5477
5478 if (use_default_chmap) {
5479 if (q6asm_map_channels(channel_mapping, channels, false)) {
5480 pr_err("%s: map channels failed %d\n",
5481 __func__, channels);
5482 rc = -EINVAL;
5483 goto fail_cmd;
5484 }
5485 } else {
5486 memcpy(channel_mapping, channel_map,
5487 PCM_FORMAT_MAX_NUM_CHANNEL);
5488 }
5489
5490 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
5491 if (rc < 0) {
5492 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
5493 rc = -EINVAL;
5494 goto fail_cmd;
5495 }
5496 rc = wait_event_timeout(ac->cmd_wait,
5497 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5498 if (!rc) {
5499 pr_err("%s: timeout. waited for format update\n", __func__);
5500 rc = -ETIMEDOUT;
5501 goto fail_cmd;
5502 }
5503 if (atomic_read(&ac->cmd_state) > 0) {
5504 pr_err("%s: DSP returned error[%s]\n",
5505 __func__, adsp_err_get_err_str(
5506 atomic_read(&ac->cmd_state)));
5507 rc = adsp_err_get_lnx_err_code(
5508 atomic_read(&ac->cmd_state));
5509 goto fail_cmd;
5510 }
5511 return 0;
5512fail_cmd:
5513 return rc;
5514}
5515
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305516/**
5517 * q6asm_media_format_block_pcm -
5518 * command to set mediafmt block for PCM on ASM stream
5519 *
5520 * @ac: Audio client handle
5521 * @rate: sample rate
5522 * @channels: number of ASM channels
5523 *
5524 * Returns 0 on success or error on failure
5525 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305526int q6asm_media_format_block_pcm(struct audio_client *ac,
5527 uint32_t rate, uint32_t channels)
5528{
5529 return __q6asm_media_format_block_pcm(ac, rate,
5530 channels, 16, ac->stream_id,
5531 true, NULL);
5532}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305533EXPORT_SYMBOL(q6asm_media_format_block_pcm);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305534
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305535/**
5536 * q6asm_media_format_block_pcm_format_support -
5537 * command to set mediafmt block for PCM format support
5538 *
5539 * @ac: Audio client handle
5540 * @rate: sample rate
5541 * @channels: number of ASM channels
5542 * @bits_per_sample: number of bits per sample
5543 *
5544 * Returns 0 on success or error on failure
5545 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305546int q6asm_media_format_block_pcm_format_support(struct audio_client *ac,
5547 uint32_t rate, uint32_t channels,
5548 uint16_t bits_per_sample)
5549{
5550 return __q6asm_media_format_block_pcm(ac, rate,
5551 channels, bits_per_sample, ac->stream_id,
5552 true, NULL);
5553}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305554EXPORT_SYMBOL(q6asm_media_format_block_pcm_format_support);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305555
5556int q6asm_media_format_block_pcm_format_support_v2(struct audio_client *ac,
5557 uint32_t rate, uint32_t channels,
5558 uint16_t bits_per_sample, int stream_id,
5559 bool use_default_chmap, char *channel_map)
5560{
5561 if (!use_default_chmap && (channel_map == NULL)) {
5562 pr_err("%s: No valid chan map and can't use default\n",
5563 __func__);
5564 return -EINVAL;
5565 }
5566 return __q6asm_media_format_block_pcm(ac, rate,
5567 channels, bits_per_sample, stream_id,
5568 use_default_chmap, channel_map);
5569}
5570
5571/*
5572 * q6asm_media_format_block_pcm_format_support_v3- sends pcm decoder
5573 * configuration parameters
5574 *
5575 * @ac: Client session handle
5576 * @rate: sample rate
5577 * @channels: number of channels
5578 * @bits_per_sample: bit width of encoder session
5579 * @stream_id: stream id of stream to be associated with this session
5580 * @use_default_chmap: true if default channel map to be used
5581 * @channel_map: input channel map
5582 * @sample_word_size: Size in bits of the word that holds a sample of a channel
5583 */
5584int q6asm_media_format_block_pcm_format_support_v3(struct audio_client *ac,
5585 uint32_t rate,
5586 uint32_t channels,
5587 uint16_t bits_per_sample,
5588 int stream_id,
5589 bool use_default_chmap,
5590 char *channel_map,
5591 uint16_t sample_word_size)
5592{
5593 if (!use_default_chmap && (channel_map == NULL)) {
5594 pr_err("%s: No valid chan map and can't use default\n",
5595 __func__);
5596 return -EINVAL;
5597 }
5598 return __q6asm_media_format_block_pcm_v3(ac, rate,
5599 channels, bits_per_sample, stream_id,
5600 use_default_chmap, channel_map,
5601 sample_word_size);
5602
5603}
5604EXPORT_SYMBOL(q6asm_media_format_block_pcm_format_support_v3);
5605
5606/*
5607 * q6asm_media_format_block_pcm_format_support_v4- sends pcm decoder
5608 * configuration parameters
5609 *
5610 * @ac: Client session handle
5611 * @rate: sample rate
5612 * @channels: number of channels
5613 * @bits_per_sample: bit width of encoder session
5614 * @stream_id: stream id of stream to be associated with this session
5615 * @use_default_chmap: true if default channel map to be used
5616 * @channel_map: input channel map
5617 * @sample_word_size: Size in bits of the word that holds a sample of a channel
5618 * @endianness: endianness of the pcm data
5619 * @mode: Mode to provide additional info about the pcm input data
5620 */
5621int q6asm_media_format_block_pcm_format_support_v4(struct audio_client *ac,
5622 uint32_t rate,
5623 uint32_t channels,
5624 uint16_t bits_per_sample,
5625 int stream_id,
5626 bool use_default_chmap,
5627 char *channel_map,
5628 uint16_t sample_word_size,
5629 uint16_t endianness,
5630 uint16_t mode)
5631{
5632 if (!use_default_chmap && (channel_map == NULL)) {
5633 pr_err("%s: No valid chan map and can't use default\n",
5634 __func__);
5635 return -EINVAL;
5636 }
5637 return __q6asm_media_format_block_pcm_v4(ac, rate,
5638 channels, bits_per_sample, stream_id,
5639 use_default_chmap, channel_map,
5640 sample_word_size, endianness,
5641 mode);
5642
5643}
5644EXPORT_SYMBOL(q6asm_media_format_block_pcm_format_support_v4);
5645
5646
5647static int __q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
5648 uint32_t rate, uint32_t channels,
5649 bool use_default_chmap, char *channel_map,
5650 uint16_t bits_per_sample)
5651{
5652 struct asm_multi_channel_pcm_fmt_blk_v2 fmt;
5653 u8 *channel_mapping;
5654 int rc = 0;
5655
5656 pr_debug("%s: session[%d]rate[%d]ch[%d]\n", __func__, ac->session, rate,
5657 channels);
5658
5659 q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
5660 atomic_set(&ac->cmd_state, -1);
5661
5662 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
5663 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
5664 sizeof(fmt.fmt_blk);
5665 fmt.num_channels = channels;
5666 fmt.bits_per_sample = bits_per_sample;
5667 fmt.sample_rate = rate;
5668 fmt.is_signed = 1;
5669
5670 channel_mapping = fmt.channel_mapping;
5671
5672 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
5673
5674 if (use_default_chmap) {
5675 if (q6asm_map_channels(channel_mapping, channels, false)) {
5676 pr_err("%s: map channels failed %d\n",
5677 __func__, channels);
5678 return -EINVAL;
5679 }
5680 } else {
5681 memcpy(channel_mapping, channel_map,
5682 PCM_FORMAT_MAX_NUM_CHANNEL);
5683 }
5684
5685 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
5686 if (rc < 0) {
5687 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
5688 rc = -EINVAL;
5689 goto fail_cmd;
5690 }
5691 rc = wait_event_timeout(ac->cmd_wait,
5692 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5693 if (!rc) {
5694 pr_err("%s: timeout. waited for format update\n", __func__);
5695 rc = -ETIMEDOUT;
5696 goto fail_cmd;
5697 }
5698 if (atomic_read(&ac->cmd_state) > 0) {
5699 pr_err("%s: DSP returned error[%s]\n",
5700 __func__, adsp_err_get_err_str(
5701 atomic_read(&ac->cmd_state)));
5702 rc = adsp_err_get_lnx_err_code(
5703 atomic_read(&ac->cmd_state));
5704 goto fail_cmd;
5705 }
5706 return 0;
5707fail_cmd:
5708 return rc;
5709}
5710
5711static int __q6asm_media_format_block_multi_ch_pcm_v3(struct audio_client *ac,
5712 uint32_t rate,
5713 uint32_t channels,
5714 bool use_default_chmap,
5715 char *channel_map,
5716 uint16_t bits_per_sample,
5717 uint16_t sample_word_size)
5718{
5719 struct asm_multi_channel_pcm_fmt_blk_param_v3 fmt;
5720 u8 *channel_mapping;
5721 int rc;
5722
5723 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
5724 ac->session, rate, channels,
5725 bits_per_sample, sample_word_size);
5726
5727 memset(&fmt, 0, sizeof(fmt));
5728 q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
5729 atomic_set(&ac->cmd_state, -1);
5730
5731 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
5732 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
5733 sizeof(fmt.fmt_blk);
5734 fmt.param.num_channels = channels;
5735 fmt.param.bits_per_sample = bits_per_sample;
5736 fmt.param.sample_rate = rate;
5737 fmt.param.is_signed = 1;
5738 fmt.param.sample_word_size = sample_word_size;
5739 channel_mapping = fmt.param.channel_mapping;
5740
5741 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
5742
5743 if (use_default_chmap) {
5744 if (q6asm_map_channels(channel_mapping, channels, false)) {
5745 pr_err("%s: map channels failed %d\n",
5746 __func__, channels);
5747 rc = -EINVAL;
5748 goto fail_cmd;
5749 }
5750 } else {
5751 memcpy(channel_mapping, channel_map,
5752 PCM_FORMAT_MAX_NUM_CHANNEL);
5753 }
5754
5755 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
5756 if (rc < 0) {
5757 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
5758 goto fail_cmd;
5759 }
5760 rc = wait_event_timeout(ac->cmd_wait,
5761 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5762 if (!rc) {
5763 pr_err("%s: timeout. waited for format update\n", __func__);
5764 rc = -ETIMEDOUT;
5765 goto fail_cmd;
5766 }
5767 if (atomic_read(&ac->cmd_state) > 0) {
5768 pr_err("%s: DSP returned error[%s]\n",
5769 __func__, adsp_err_get_err_str(
5770 atomic_read(&ac->cmd_state)));
5771 rc = adsp_err_get_lnx_err_code(
5772 atomic_read(&ac->cmd_state));
5773 goto fail_cmd;
5774 }
5775 return 0;
5776fail_cmd:
5777 return rc;
5778}
5779
5780static int __q6asm_media_format_block_multi_ch_pcm_v4(struct audio_client *ac,
5781 uint32_t rate,
5782 uint32_t channels,
5783 bool use_default_chmap,
5784 char *channel_map,
5785 uint16_t bits_per_sample,
5786 uint16_t sample_word_size,
5787 uint16_t endianness,
5788 uint16_t mode)
5789{
5790 struct asm_multi_channel_pcm_fmt_blk_param_v4 fmt;
5791 u8 *channel_mapping;
5792 int rc;
5793
5794 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
5795 ac->session, rate, channels,
5796 bits_per_sample, sample_word_size);
5797
5798 memset(&fmt, 0, sizeof(fmt));
5799 q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
5800 atomic_set(&ac->cmd_state, -1);
5801
5802 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
5803 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
5804 sizeof(fmt.fmt_blk);
5805 fmt.param.num_channels = channels;
5806 fmt.param.bits_per_sample = bits_per_sample;
5807 fmt.param.sample_rate = rate;
5808 fmt.param.is_signed = 1;
5809 fmt.param.sample_word_size = sample_word_size;
5810 fmt.param.endianness = endianness;
5811 fmt.param.mode = mode;
5812 channel_mapping = fmt.param.channel_mapping;
5813
5814 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
5815
5816 if (use_default_chmap) {
5817 if (q6asm_map_channels(channel_mapping, channels, false)) {
5818 pr_err("%s: map channels failed %d\n",
5819 __func__, channels);
5820 rc = -EINVAL;
5821 goto fail_cmd;
5822 }
5823 } else {
5824 memcpy(channel_mapping, channel_map,
5825 PCM_FORMAT_MAX_NUM_CHANNEL);
5826 }
5827
5828 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
5829 if (rc < 0) {
5830 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
5831 goto fail_cmd;
5832 }
5833 rc = wait_event_timeout(ac->cmd_wait,
5834 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5835 if (!rc) {
5836 pr_err("%s: timeout. waited for format update\n", __func__);
5837 rc = -ETIMEDOUT;
5838 goto fail_cmd;
5839 }
5840 if (atomic_read(&ac->cmd_state) > 0) {
5841 pr_err("%s: DSP returned error[%s]\n",
5842 __func__, adsp_err_get_err_str(
5843 atomic_read(&ac->cmd_state)));
5844 rc = adsp_err_get_lnx_err_code(
5845 atomic_read(&ac->cmd_state));
5846 goto fail_cmd;
5847 }
5848 return 0;
5849fail_cmd:
5850 return rc;
5851}
5852
5853int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
5854 uint32_t rate, uint32_t channels,
5855 bool use_default_chmap, char *channel_map)
5856{
5857 return __q6asm_media_format_block_multi_ch_pcm(ac, rate,
5858 channels, use_default_chmap, channel_map, 16);
5859}
5860
5861int q6asm_media_format_block_multi_ch_pcm_v2(
5862 struct audio_client *ac,
5863 uint32_t rate, uint32_t channels,
5864 bool use_default_chmap, char *channel_map,
5865 uint16_t bits_per_sample)
5866{
5867 return __q6asm_media_format_block_multi_ch_pcm(ac, rate,
5868 channels, use_default_chmap, channel_map,
5869 bits_per_sample);
5870}
5871
5872/*
5873 * q6asm_media_format_block_multi_ch_pcm_v3 - sends pcm decoder configuration
5874 * parameters
5875 *
5876 * @ac: Client session handle
5877 * @rate: sample rate
5878 * @channels: number of channels
5879 * @bits_per_sample: bit width of encoder session
5880 * @use_default_chmap: true if default channel map to be used
5881 * @channel_map: input channel map
5882 * @sample_word_size: Size in bits of the word that holds a sample of a channel
5883 */
5884int q6asm_media_format_block_multi_ch_pcm_v3(struct audio_client *ac,
5885 uint32_t rate, uint32_t channels,
5886 bool use_default_chmap,
5887 char *channel_map,
5888 uint16_t bits_per_sample,
5889 uint16_t sample_word_size)
5890{
5891 return __q6asm_media_format_block_multi_ch_pcm_v3(ac, rate, channels,
5892 use_default_chmap,
5893 channel_map,
5894 bits_per_sample,
5895 sample_word_size);
5896}
5897EXPORT_SYMBOL(q6asm_media_format_block_multi_ch_pcm_v3);
5898
5899/*
5900 * q6asm_media_format_block_multi_ch_pcm_v4 - sends pcm decoder configuration
5901 * parameters
5902 *
5903 * @ac: Client session handle
5904 * @rate: sample rate
5905 * @channels: number of channels
5906 * @bits_per_sample: bit width of encoder session
5907 * @use_default_chmap: true if default channel map to be used
5908 * @channel_map: input channel map
5909 * @sample_word_size: Size in bits of the word that holds a sample of a channel
5910 * @endianness: endianness of the pcm data
5911 * @mode: Mode to provide additional info about the pcm input data
5912 */
5913int q6asm_media_format_block_multi_ch_pcm_v4(struct audio_client *ac,
5914 uint32_t rate, uint32_t channels,
5915 bool use_default_chmap,
5916 char *channel_map,
5917 uint16_t bits_per_sample,
5918 uint16_t sample_word_size,
5919 uint16_t endianness,
5920 uint16_t mode)
5921{
5922 return __q6asm_media_format_block_multi_ch_pcm_v4(ac, rate, channels,
5923 use_default_chmap,
5924 channel_map,
5925 bits_per_sample,
5926 sample_word_size,
5927 endianness,
5928 mode);
5929}
5930EXPORT_SYMBOL(q6asm_media_format_block_multi_ch_pcm_v4);
5931
5932/*
5933 * q6asm_media_format_block_gen_compr - set up generic compress format params
5934 *
5935 * @ac: Client session handle
5936 * @rate: sample rate
5937 * @channels: number of channels
5938 * @use_default_chmap: true if default channel map to be used
5939 * @channel_map: input channel map
5940 * @bits_per_sample: bit width of gen compress stream
5941 */
5942int q6asm_media_format_block_gen_compr(struct audio_client *ac,
5943 uint32_t rate, uint32_t channels,
5944 bool use_default_chmap, char *channel_map,
5945 uint16_t bits_per_sample)
5946{
5947 struct asm_generic_compressed_fmt_blk_t fmt;
5948 u8 *channel_mapping;
5949 int rc = 0;
5950
5951 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]\n",
5952 __func__, ac->session, rate,
5953 channels, bits_per_sample);
5954
5955 memset(&fmt, 0, sizeof(fmt));
5956 q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
5957
5958 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
5959 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
5960 sizeof(fmt.fmt_blk);
5961 fmt.num_channels = channels;
5962 fmt.bits_per_sample = bits_per_sample;
5963 fmt.sampling_rate = rate;
5964
5965 channel_mapping = fmt.channel_mapping;
5966
5967 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
5968
5969 if (use_default_chmap) {
5970 if (q6asm_map_channels(channel_mapping, channels, false)) {
5971 pr_err("%s: map channels failed %d\n",
5972 __func__, channels);
5973 return -EINVAL;
5974 }
5975 } else {
5976 memcpy(channel_mapping, channel_map,
5977 PCM_FORMAT_MAX_NUM_CHANNEL);
5978 }
5979
5980 atomic_set(&ac->cmd_state, -1);
5981 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
5982 if (rc < 0) {
5983 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
5984 rc = -EINVAL;
5985 goto fail_cmd;
5986 }
5987 rc = wait_event_timeout(ac->cmd_wait,
5988 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5989 if (!rc) {
5990 pr_err("%s: timeout. waited for format update\n", __func__);
5991 rc = -ETIMEDOUT;
5992 goto fail_cmd;
5993 }
5994
5995 if (atomic_read(&ac->cmd_state) > 0) {
5996 pr_err("%s: DSP returned error[%s]\n",
5997 __func__, adsp_err_get_err_str(
5998 atomic_read(&ac->cmd_state)));
5999 rc = adsp_err_get_lnx_err_code(
6000 atomic_read(&ac->cmd_state));
6001 }
6002 return 0;
6003fail_cmd:
6004 return rc;
6005}
6006EXPORT_SYMBOL(q6asm_media_format_block_gen_compr);
6007
6008
6009/*
6010 * q6asm_media_format_block_iec - set up IEC61937 (compressed) or IEC60958
6011 * (pcm) format params. Both audio standards
6012 * use the same format and are used for
6013 * HDMI or SPDIF.
6014 *
6015 * @ac: Client session handle
6016 * @rate: sample rate
6017 * @channels: number of channels
6018 */
6019int q6asm_media_format_block_iec(struct audio_client *ac,
6020 uint32_t rate, uint32_t channels)
6021{
6022 struct asm_iec_compressed_fmt_blk_t fmt;
6023 int rc = 0;
6024
6025 pr_debug("%s: session[%d]rate[%d]ch[%d]\n",
6026 __func__, ac->session, rate,
6027 channels);
6028
6029 memset(&fmt, 0, sizeof(fmt));
6030 q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
6031
6032 fmt.hdr.opcode = ASM_DATA_CMD_IEC_60958_MEDIA_FMT;
6033 fmt.num_channels = channels;
6034 fmt.sampling_rate = rate;
6035
6036 atomic_set(&ac->cmd_state, -1);
6037 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6038 if (rc < 0) {
6039 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
6040 rc = -EINVAL;
6041 goto fail_cmd;
6042 }
6043 rc = wait_event_timeout(ac->cmd_wait,
6044 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6045 if (!rc) {
6046 pr_err("%s: timeout. waited for format update\n", __func__);
6047 rc = -ETIMEDOUT;
6048 goto fail_cmd;
6049 }
6050
6051 if (atomic_read(&ac->cmd_state) > 0) {
6052 pr_err("%s: DSP returned error[%s]\n",
6053 __func__, adsp_err_get_err_str(
6054 atomic_read(&ac->cmd_state)));
6055 rc = adsp_err_get_lnx_err_code(
6056 atomic_read(&ac->cmd_state));
6057 }
6058 return 0;
6059fail_cmd:
6060 return rc;
6061}
6062EXPORT_SYMBOL(q6asm_media_format_block_iec);
6063
6064static int __q6asm_media_format_block_multi_aac(struct audio_client *ac,
6065 struct asm_aac_cfg *cfg, int stream_id)
6066{
6067 struct asm_aac_fmt_blk_v2 fmt;
6068 int rc = 0;
6069
6070 pr_debug("%s: session[%d]rate[%d]ch[%d]\n", __func__, ac->session,
6071 cfg->sample_rate, cfg->ch_cfg);
6072
6073 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6074 atomic_set(&ac->cmd_state, -1);
6075 /*
6076 * Updated the token field with stream/session for compressed playback
6077 * Platform driver must know the the stream with which the command is
6078 * associated
6079 */
6080 if (ac->io_mode & COMPRESSED_STREAM_IO)
6081 q6asm_update_token(&fmt.hdr.token,
6082 ac->session,
6083 stream_id,
6084 0, /* Buffer index is NA */
6085 0, /* Direction flag is NA */
6086 WAIT_CMD);
6087
6088 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
6089 __func__, fmt.hdr.token, stream_id, ac->session);
6090 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6091 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6092 sizeof(fmt.fmt_blk);
6093 fmt.aac_fmt_flag = cfg->format;
6094 fmt.audio_objype = cfg->aot;
6095 /* If zero, PCE is assumed to be available in bitstream*/
6096 fmt.total_size_of_PCE_bits = 0;
6097 fmt.channel_config = cfg->ch_cfg;
6098 fmt.sample_rate = cfg->sample_rate;
6099
6100 pr_debug("%s: format=0x%x cfg_size=%d aac-cfg=0x%x aot=%d ch=%d sr=%d\n",
6101 __func__, fmt.aac_fmt_flag, fmt.fmt_blk.fmt_blk_size,
6102 fmt.aac_fmt_flag,
6103 fmt.audio_objype,
6104 fmt.channel_config,
6105 fmt.sample_rate);
6106 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6107 if (rc < 0) {
6108 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
6109 rc = -EINVAL;
6110 goto fail_cmd;
6111 }
6112 rc = wait_event_timeout(ac->cmd_wait,
6113 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6114 if (!rc) {
6115 pr_err("%s: timeout. waited for FORMAT_UPDATE\n", __func__);
6116 rc = -ETIMEDOUT;
6117 goto fail_cmd;
6118 }
6119 if (atomic_read(&ac->cmd_state) > 0) {
6120 pr_err("%s: DSP returned error[%s]\n",
6121 __func__, adsp_err_get_err_str(
6122 atomic_read(&ac->cmd_state)));
6123 rc = adsp_err_get_lnx_err_code(
6124 atomic_read(&ac->cmd_state));
6125 goto fail_cmd;
6126 }
6127 return 0;
6128fail_cmd:
6129 return rc;
6130}
6131
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306132/**
6133 * q6asm_media_format_block_multi_aac -
6134 * command to set mediafmt block for multi_aac on ASM stream
6135 *
6136 * @ac: Audio client handle
6137 * @cfg: multi_aac config
6138 *
6139 * Returns 0 on success or error on failure
6140 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306141int q6asm_media_format_block_multi_aac(struct audio_client *ac,
6142 struct asm_aac_cfg *cfg)
6143{
6144 return __q6asm_media_format_block_multi_aac(ac, cfg, ac->stream_id);
6145}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306146EXPORT_SYMBOL(q6asm_media_format_block_multi_aac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306147
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306148/**
6149 * q6asm_media_format_block_aac -
6150 * command to set mediafmt block for aac on ASM
6151 *
6152 * @ac: Audio client handle
6153 * @cfg: aac config
6154 *
6155 * Returns 0 on success or error on failure
6156 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306157int q6asm_media_format_block_aac(struct audio_client *ac,
6158 struct asm_aac_cfg *cfg)
6159{
6160 return __q6asm_media_format_block_multi_aac(ac, cfg, ac->stream_id);
6161}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306162EXPORT_SYMBOL(q6asm_media_format_block_aac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306163
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306164/**
6165 * q6asm_stream_media_format_block_aac -
6166 * command to set mediafmt block for aac on ASM stream
6167 *
6168 * @ac: Audio client handle
6169 * @cfg: aac config
6170 * @stream_id: stream ID info
6171 *
6172 * Returns 0 on success or error on failure
6173 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306174int q6asm_stream_media_format_block_aac(struct audio_client *ac,
6175 struct asm_aac_cfg *cfg, int stream_id)
6176{
6177 return __q6asm_media_format_block_multi_aac(ac, cfg, stream_id);
6178}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306179EXPORT_SYMBOL(q6asm_stream_media_format_block_aac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306180
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306181/**
6182 * q6asm_media_format_block_wma -
6183 * command to set mediafmt block for wma on ASM stream
6184 *
6185 * @ac: Audio client handle
6186 * @cfg: wma config
6187 * @stream_id: stream ID info
6188 *
6189 * Returns 0 on success or error on failure
6190 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306191int q6asm_media_format_block_wma(struct audio_client *ac,
6192 void *cfg, int stream_id)
6193{
6194 struct asm_wmastdv9_fmt_blk_v2 fmt;
6195 struct asm_wma_cfg *wma_cfg = (struct asm_wma_cfg *)cfg;
6196 int rc = 0;
6197
6198 pr_debug("session[%d]format_tag[0x%4x] rate[%d] ch[0x%4x] bps[%d], balign[0x%4x], bit_sample[0x%4x], ch_msk[%d], enc_opt[0x%4x]\n",
6199 ac->session, wma_cfg->format_tag, wma_cfg->sample_rate,
6200 wma_cfg->ch_cfg, wma_cfg->avg_bytes_per_sec,
6201 wma_cfg->block_align, wma_cfg->valid_bits_per_sample,
6202 wma_cfg->ch_mask, wma_cfg->encode_opt);
6203
6204 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6205 atomic_set(&ac->cmd_state, -1);
6206
6207 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6208 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6209 sizeof(fmt.fmtblk);
6210 fmt.fmtag = wma_cfg->format_tag;
6211 fmt.num_channels = wma_cfg->ch_cfg;
6212 fmt.sample_rate = wma_cfg->sample_rate;
6213 fmt.avg_bytes_per_sec = wma_cfg->avg_bytes_per_sec;
6214 fmt.blk_align = wma_cfg->block_align;
6215 fmt.bits_per_sample =
6216 wma_cfg->valid_bits_per_sample;
6217 fmt.channel_mask = wma_cfg->ch_mask;
6218 fmt.enc_options = wma_cfg->encode_opt;
6219
6220 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6221 if (rc < 0) {
6222 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
6223 rc = -EINVAL;
6224 goto fail_cmd;
6225 }
6226 rc = wait_event_timeout(ac->cmd_wait,
6227 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6228 if (!rc) {
6229 pr_err("%s: timeout. waited for FORMAT_UPDATE\n", __func__);
6230 rc = -ETIMEDOUT;
6231 goto fail_cmd;
6232 }
6233 if (atomic_read(&ac->cmd_state) > 0) {
6234 pr_err("%s: DSP returned error[%s]\n",
6235 __func__, adsp_err_get_err_str(
6236 atomic_read(&ac->cmd_state)));
6237 rc = adsp_err_get_lnx_err_code(
6238 atomic_read(&ac->cmd_state));
6239 goto fail_cmd;
6240 }
6241 return 0;
6242fail_cmd:
6243 return rc;
6244}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306245EXPORT_SYMBOL(q6asm_media_format_block_wma);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306246
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306247/**
6248 * q6asm_media_format_block_wmapro -
6249 * command to set mediafmt block for wmapro on ASM stream
6250 *
6251 * @ac: Audio client handle
6252 * @cfg: wmapro config
6253 * @stream_id: stream ID info
6254 *
6255 * Returns 0 on success or error on failure
6256 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306257int q6asm_media_format_block_wmapro(struct audio_client *ac,
6258 void *cfg, int stream_id)
6259{
6260 struct asm_wmaprov10_fmt_blk_v2 fmt;
6261 struct asm_wmapro_cfg *wmapro_cfg = (struct asm_wmapro_cfg *)cfg;
6262 int rc = 0;
6263
6264 pr_debug("%s: session[%d]format_tag[0x%4x] rate[%d] ch[0x%4x] bps[%d], balign[0x%4x], bit_sample[0x%4x], ch_msk[%d], enc_opt[0x%4x], adv_enc_opt[0x%4x], adv_enc_opt2[0x%8x]\n",
6265 __func__,
6266 ac->session, wmapro_cfg->format_tag, wmapro_cfg->sample_rate,
6267 wmapro_cfg->ch_cfg, wmapro_cfg->avg_bytes_per_sec,
6268 wmapro_cfg->block_align, wmapro_cfg->valid_bits_per_sample,
6269 wmapro_cfg->ch_mask, wmapro_cfg->encode_opt,
6270 wmapro_cfg->adv_encode_opt, wmapro_cfg->adv_encode_opt2);
6271
6272 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6273 atomic_set(&ac->cmd_state, -1);
6274
6275 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6276 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6277 sizeof(fmt.fmtblk);
6278
6279 fmt.fmtag = wmapro_cfg->format_tag;
6280 fmt.num_channels = wmapro_cfg->ch_cfg;
6281 fmt.sample_rate = wmapro_cfg->sample_rate;
6282 fmt.avg_bytes_per_sec =
6283 wmapro_cfg->avg_bytes_per_sec;
6284 fmt.blk_align = wmapro_cfg->block_align;
6285 fmt.bits_per_sample = wmapro_cfg->valid_bits_per_sample;
6286 fmt.channel_mask = wmapro_cfg->ch_mask;
6287 fmt.enc_options = wmapro_cfg->encode_opt;
6288 fmt.usAdvancedEncodeOpt = wmapro_cfg->adv_encode_opt;
6289 fmt.advanced_enc_options2 = wmapro_cfg->adv_encode_opt2;
6290
6291 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6292 if (rc < 0) {
6293 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
6294 rc = -EINVAL;
6295 goto fail_cmd;
6296 }
6297 rc = wait_event_timeout(ac->cmd_wait,
6298 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6299 if (!rc) {
6300 pr_err("%s: timeout. waited for FORMAT_UPDATE\n", __func__);
6301 rc = -ETIMEDOUT;
6302 goto fail_cmd;
6303 }
6304 if (atomic_read(&ac->cmd_state) > 0) {
6305 pr_err("%s: DSP returned error[%s]\n",
6306 __func__, adsp_err_get_err_str(
6307 atomic_read(&ac->cmd_state)));
6308 rc = adsp_err_get_lnx_err_code(
6309 atomic_read(&ac->cmd_state));
6310 goto fail_cmd;
6311 }
6312 return 0;
6313fail_cmd:
6314 return rc;
6315}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306316EXPORT_SYMBOL(q6asm_media_format_block_wmapro);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306317
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306318/**
6319 * q6asm_media_format_block_amrwbplus -
6320 * command to set mediafmt block for amrwbplus on ASM stream
6321 *
6322 * @ac: Audio client handle
6323 * @cfg: amrwbplus config
6324 * @stream_id: stream ID info
6325 *
6326 * Returns 0 on success or error on failure
6327 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306328int q6asm_media_format_block_amrwbplus(struct audio_client *ac,
6329 struct asm_amrwbplus_cfg *cfg)
6330{
6331 struct asm_amrwbplus_fmt_blk_v2 fmt;
6332 int rc = 0;
6333
6334 pr_debug("%s: session[%d]band-mode[%d]frame-fmt[%d]ch[%d]\n",
6335 __func__,
6336 ac->session,
6337 cfg->amr_band_mode,
6338 cfg->amr_frame_fmt,
6339 cfg->num_channels);
6340
6341 q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
6342 atomic_set(&ac->cmd_state, -1);
6343
6344 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6345 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6346 sizeof(fmt.fmtblk);
6347 fmt.amr_frame_fmt = cfg->amr_frame_fmt;
6348
6349 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6350 if (rc < 0) {
6351 pr_err("%s: Comamnd media format update failed.. %d\n",
6352 __func__, rc);
6353 rc = -EINVAL;
6354 goto fail_cmd;
6355 }
6356 rc = wait_event_timeout(ac->cmd_wait,
6357 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6358 if (!rc) {
6359 pr_err("%s: timeout. waited for FORMAT_UPDATE\n", __func__);
6360 rc = -ETIMEDOUT;
6361 goto fail_cmd;
6362 }
6363 if (atomic_read(&ac->cmd_state) > 0) {
6364 pr_err("%s: DSP returned error[%s]\n",
6365 __func__, adsp_err_get_err_str(
6366 atomic_read(&ac->cmd_state)));
6367 rc = adsp_err_get_lnx_err_code(
6368 atomic_read(&ac->cmd_state));
6369 goto fail_cmd;
6370 }
6371 return 0;
6372fail_cmd:
6373 return rc;
6374}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306375EXPORT_SYMBOL(q6asm_media_format_block_amrwbplus);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306376
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306377/**
6378 * q6asm_stream_media_format_block_flac -
6379 * command to set mediafmt block for flac on ASM stream
6380 *
6381 * @ac: Audio client handle
6382 * @cfg: FLAC config
6383 * @stream_id: stream ID info
6384 *
6385 * Returns 0 on success or error on failure
6386 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306387int q6asm_stream_media_format_block_flac(struct audio_client *ac,
6388 struct asm_flac_cfg *cfg, int stream_id)
6389{
6390 struct asm_flac_fmt_blk_v2 fmt;
6391 int rc = 0;
6392
6393 pr_debug("%s :session[%d] rate[%d] ch[%d] size[%d] stream_id[%d]\n",
6394 __func__, ac->session, cfg->sample_rate, cfg->ch_cfg,
6395 cfg->sample_size, stream_id);
6396
6397 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6398 atomic_set(&ac->cmd_state, -1);
6399
6400 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6401 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6402 sizeof(fmt.fmtblk);
6403
6404 fmt.is_stream_info_present = cfg->stream_info_present;
6405 fmt.num_channels = cfg->ch_cfg;
6406 fmt.min_blk_size = cfg->min_blk_size;
6407 fmt.max_blk_size = cfg->max_blk_size;
6408 fmt.sample_rate = cfg->sample_rate;
6409 fmt.min_frame_size = cfg->min_frame_size;
6410 fmt.max_frame_size = cfg->max_frame_size;
6411 fmt.sample_size = cfg->sample_size;
6412
6413 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6414 if (rc < 0) {
6415 pr_err("%s :Comamnd media format update failed %d\n",
6416 __func__, rc);
6417 goto fail_cmd;
6418 }
6419 rc = wait_event_timeout(ac->cmd_wait,
6420 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6421 if (!rc) {
6422 pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
6423 rc = -ETIMEDOUT;
6424 goto fail_cmd;
6425 }
6426
6427 if (atomic_read(&ac->cmd_state) > 0) {
6428 pr_err("%s: DSP returned error[%s]\n",
6429 __func__, adsp_err_get_err_str(
6430 atomic_read(&ac->cmd_state)));
6431 rc = adsp_err_get_lnx_err_code(
6432 atomic_read(&ac->cmd_state));
6433 goto fail_cmd;
6434 }
6435 return 0;
6436fail_cmd:
6437 return rc;
6438}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306439EXPORT_SYMBOL(q6asm_stream_media_format_block_flac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306440
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306441/**
6442 * q6asm_media_format_block_alac -
6443 * command to set mediafmt block for alac on ASM stream
6444 *
6445 * @ac: Audio client handle
6446 * @cfg: ALAC config
6447 * @stream_id: stream ID info
6448 *
6449 * Returns 0 on success or error on failure
6450 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306451int q6asm_media_format_block_alac(struct audio_client *ac,
6452 struct asm_alac_cfg *cfg, int stream_id)
6453{
6454 struct asm_alac_fmt_blk_v2 fmt;
6455 int rc = 0;
6456
6457 pr_debug("%s :session[%d]rate[%d]ch[%d]\n", __func__,
6458 ac->session, cfg->sample_rate, cfg->num_channels);
6459
6460 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6461 atomic_set(&ac->cmd_state, -1);
6462
6463 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6464 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6465 sizeof(fmt.fmtblk);
6466
6467 fmt.frame_length = cfg->frame_length;
6468 fmt.compatible_version = cfg->compatible_version;
6469 fmt.bit_depth = cfg->bit_depth;
6470 fmt.pb = cfg->pb;
6471 fmt.mb = cfg->mb;
6472 fmt.kb = cfg->kb;
6473 fmt.num_channels = cfg->num_channels;
6474 fmt.max_run = cfg->max_run;
6475 fmt.max_frame_bytes = cfg->max_frame_bytes;
6476 fmt.avg_bit_rate = cfg->avg_bit_rate;
6477 fmt.sample_rate = cfg->sample_rate;
6478 fmt.channel_layout_tag = cfg->channel_layout_tag;
6479
6480 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6481 if (rc < 0) {
6482 pr_err("%s :Comamnd media format update failed %d\n",
6483 __func__, rc);
6484 goto fail_cmd;
6485 }
6486 rc = wait_event_timeout(ac->cmd_wait,
6487 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6488 if (!rc) {
6489 pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
6490 rc = -ETIMEDOUT;
6491 goto fail_cmd;
6492 }
6493
6494 if (atomic_read(&ac->cmd_state) > 0) {
6495 pr_err("%s: DSP returned error[%s]\n",
6496 __func__, adsp_err_get_err_str(
6497 atomic_read(&ac->cmd_state)));
6498 rc = adsp_err_get_lnx_err_code(
6499 atomic_read(&ac->cmd_state));
6500 goto fail_cmd;
6501 }
6502 return 0;
6503fail_cmd:
6504 return rc;
6505}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306506EXPORT_SYMBOL(q6asm_media_format_block_alac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306507
6508/*
6509 * q6asm_media_format_block_g711 - sends g711 decoder configuration
6510 * parameters
6511 * @ac: Client session handle
6512 * @cfg: Audio stream manager configuration parameters
6513 * @stream_id: Stream id
6514 */
6515int q6asm_media_format_block_g711(struct audio_client *ac,
6516 struct asm_g711_dec_cfg *cfg, int stream_id)
6517{
6518 struct asm_g711_dec_fmt_blk_v2 fmt;
6519 int rc = 0;
6520
6521 if (!ac) {
6522 pr_err("%s: audio client is null\n", __func__);
6523 return -EINVAL;
6524 }
6525 if (!cfg) {
6526 pr_err("%s: Invalid ASM config\n", __func__);
6527 return -EINVAL;
6528 }
6529
6530 if (stream_id <= 0) {
6531 pr_err("%s: Invalid stream id\n", __func__);
6532 return -EINVAL;
6533 }
6534
6535 pr_debug("%s :session[%d]rate[%d]\n", __func__,
6536 ac->session, cfg->sample_rate);
6537
6538 memset(&fmt, 0, sizeof(struct asm_g711_dec_fmt_blk_v2));
6539
6540 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6541 atomic_set(&ac->cmd_state, -1);
6542
6543 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6544 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6545 sizeof(fmt.fmtblk);
6546
6547 fmt.sample_rate = cfg->sample_rate;
6548
6549 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6550 if (rc < 0) {
6551 pr_err("%s :Command media format update failed %d\n",
6552 __func__, rc);
6553 goto fail_cmd;
6554 }
6555 rc = wait_event_timeout(ac->cmd_wait,
6556 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6557 if (!rc) {
6558 pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
6559 rc = -ETIMEDOUT;
6560 goto fail_cmd;
6561 }
6562
6563 if (atomic_read(&ac->cmd_state) > 0) {
6564 pr_err("%s: DSP returned error[%s]\n",
6565 __func__, adsp_err_get_err_str(
6566 atomic_read(&ac->cmd_state)));
6567 rc = adsp_err_get_lnx_err_code(
6568 atomic_read(&ac->cmd_state));
6569 goto fail_cmd;
6570 }
6571 return 0;
6572fail_cmd:
6573 return rc;
6574}
6575EXPORT_SYMBOL(q6asm_media_format_block_g711);
6576
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306577/**
6578 * q6asm_stream_media_format_block_vorbis -
6579 * command to set mediafmt block for vorbis on ASM stream
6580 *
6581 * @ac: Audio client handle
6582 * @cfg: vorbis config
6583 * @stream_id: stream ID info
6584 *
6585 * Returns 0 on success or error on failure
6586 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306587int q6asm_stream_media_format_block_vorbis(struct audio_client *ac,
6588 struct asm_vorbis_cfg *cfg, int stream_id)
6589{
6590 struct asm_vorbis_fmt_blk_v2 fmt;
6591 int rc = 0;
6592
6593 pr_debug("%s :session[%d] bit_stream_fmt[%d] stream_id[%d]\n",
6594 __func__, ac->session, cfg->bit_stream_fmt, stream_id);
6595
6596 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6597 atomic_set(&ac->cmd_state, -1);
6598
6599 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6600 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6601 sizeof(fmt.fmtblk);
6602
6603 fmt.bit_stream_fmt = cfg->bit_stream_fmt;
6604
6605 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6606 if (rc < 0) {
6607 pr_err("%s :Comamnd media format update failed %d\n",
6608 __func__, rc);
6609 goto fail_cmd;
6610 }
6611 rc = wait_event_timeout(ac->cmd_wait,
6612 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6613 if (!rc) {
6614 pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
6615 rc = -ETIMEDOUT;
6616 goto fail_cmd;
6617 }
6618
6619 if (atomic_read(&ac->cmd_state) > 0) {
6620 pr_err("%s: DSP returned error[%s]\n",
6621 __func__, adsp_err_get_err_str(
6622 atomic_read(&ac->cmd_state)));
6623 rc = adsp_err_get_lnx_err_code(
6624 atomic_read(&ac->cmd_state));
6625 goto fail_cmd;
6626 }
6627 return 0;
6628fail_cmd:
6629 return rc;
6630}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306631EXPORT_SYMBOL(q6asm_stream_media_format_block_vorbis);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306632
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306633/**
6634 * q6asm_media_format_block_ape -
6635 * command to set mediafmt block for APE on ASM stream
6636 *
6637 * @ac: Audio client handle
6638 * @cfg: APE config
6639 * @stream_id: stream ID info
6640 *
6641 * Returns 0 on success or error on failure
6642 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306643int q6asm_media_format_block_ape(struct audio_client *ac,
6644 struct asm_ape_cfg *cfg, int stream_id)
6645{
6646 struct asm_ape_fmt_blk_v2 fmt;
6647 int rc = 0;
6648
6649 pr_debug("%s :session[%d]rate[%d]ch[%d]\n", __func__,
6650 ac->session, cfg->sample_rate, cfg->num_channels);
6651
6652 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6653 atomic_set(&ac->cmd_state, -1);
6654
6655 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6656 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6657 sizeof(fmt.fmtblk);
6658
6659 fmt.compatible_version = cfg->compatible_version;
6660 fmt.compression_level = cfg->compression_level;
6661 fmt.format_flags = cfg->format_flags;
6662 fmt.blocks_per_frame = cfg->blocks_per_frame;
6663 fmt.final_frame_blocks = cfg->final_frame_blocks;
6664 fmt.total_frames = cfg->total_frames;
6665 fmt.bits_per_sample = cfg->bits_per_sample;
6666 fmt.num_channels = cfg->num_channels;
6667 fmt.sample_rate = cfg->sample_rate;
6668 fmt.seek_table_present = cfg->seek_table_present;
6669
6670 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6671 if (rc < 0) {
6672 pr_err("%s :Comamnd media format update failed %d\n",
6673 __func__, rc);
6674 goto fail_cmd;
6675 }
6676 rc = wait_event_timeout(ac->cmd_wait,
6677 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6678 if (!rc) {
6679 pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
6680 rc = -ETIMEDOUT;
6681 goto fail_cmd;
6682 }
6683
6684 if (atomic_read(&ac->cmd_state) > 0) {
6685 pr_err("%s: DSP returned error[%s]\n",
6686 __func__, adsp_err_get_err_str(
6687 atomic_read(&ac->cmd_state)));
6688 rc = adsp_err_get_lnx_err_code(
6689 atomic_read(&ac->cmd_state));
6690 goto fail_cmd;
6691 }
6692 return 0;
6693fail_cmd:
6694 return rc;
6695}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306696EXPORT_SYMBOL(q6asm_media_format_block_ape);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306697
6698/*
6699 * q6asm_media_format_block_dsd- Sends DSD Decoder
6700 * configuration parameters
6701 *
6702 * @ac: Client session handle
6703 * @cfg: DSD Media Format Configuration.
6704 * @stream_id: stream id of stream to be associated with this session
6705 *
6706 * Return 0 on success or negative error code on failure
6707 */
6708int q6asm_media_format_block_dsd(struct audio_client *ac,
6709 struct asm_dsd_cfg *cfg, int stream_id)
6710{
6711 struct asm_dsd_fmt_blk_v2 fmt;
6712 int rc;
6713
6714 pr_debug("%s: session[%d] data_rate[%d] ch[%d]\n", __func__,
6715 ac->session, cfg->dsd_data_rate, cfg->num_channels);
6716
6717 memset(&fmt, 0, sizeof(fmt));
6718 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6719
6720 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6721 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6722 sizeof(fmt.fmtblk);
6723
6724 fmt.num_version = cfg->num_version;
6725 fmt.is_bitwise_big_endian = cfg->is_bitwise_big_endian;
6726 fmt.dsd_channel_block_size = cfg->dsd_channel_block_size;
6727 fmt.num_channels = cfg->num_channels;
6728 fmt.dsd_data_rate = cfg->dsd_data_rate;
6729 atomic_set(&ac->cmd_state, -1);
6730 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6731 if (rc < 0) {
6732 pr_err("%s: Command DSD media format update failed, err: %d\n",
6733 __func__, rc);
6734 goto done;
6735 }
6736 rc = wait_event_timeout(ac->cmd_wait,
6737 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6738 if (!rc) {
6739 pr_err("%s: timeout. waited for DSD FORMAT_UPDATE\n", __func__);
6740 rc = -ETIMEDOUT;
6741 goto done;
6742 }
6743
6744 if (atomic_read(&ac->cmd_state) > 0) {
6745 pr_err("%s: DSP returned error[%s]\n",
6746 __func__, adsp_err_get_err_str(
6747 atomic_read(&ac->cmd_state)));
6748 rc = adsp_err_get_lnx_err_code(
6749 atomic_read(&ac->cmd_state));
6750 goto done;
6751 }
6752 return 0;
6753done:
6754 return rc;
6755}
6756EXPORT_SYMBOL(q6asm_media_format_block_dsd);
6757
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306758/**
6759 * q6asm_stream_media_format_block_aptx_dec -
6760 * command to set mediafmt block for APTX dec on ASM stream
6761 *
6762 * @ac: Audio client handle
6763 * @srate: sample rate
6764 * @stream_id: stream ID info
6765 *
6766 * Returns 0 on success or error on failure
6767 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306768int q6asm_stream_media_format_block_aptx_dec(struct audio_client *ac,
6769 uint32_t srate, int stream_id)
6770{
6771 struct asm_aptx_dec_fmt_blk_v2 aptx_fmt;
6772 int rc = 0;
6773
6774 if (!ac->session) {
6775 pr_err("%s: ac session invalid\n", __func__);
6776 rc = -EINVAL;
6777 goto fail_cmd;
6778 }
6779 pr_debug("%s :session[%d] rate[%d] stream_id[%d]\n",
6780 __func__, ac->session, srate, stream_id);
6781
6782 q6asm_stream_add_hdr(ac, &aptx_fmt.hdr, sizeof(aptx_fmt), TRUE,
6783 stream_id);
6784 atomic_set(&ac->cmd_state, -1);
6785
6786 aptx_fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6787 aptx_fmt.fmtblk.fmt_blk_size = sizeof(aptx_fmt) - sizeof(aptx_fmt.hdr) -
6788 sizeof(aptx_fmt.fmtblk);
6789
6790 aptx_fmt.sample_rate = srate;
6791
6792 rc = apr_send_pkt(ac->apr, (uint32_t *) &aptx_fmt);
6793 if (rc < 0) {
6794 pr_err("%s :Comamnd media format update failed %d\n",
6795 __func__, rc);
6796 goto fail_cmd;
6797 }
6798 rc = wait_event_timeout(ac->cmd_wait,
6799 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6800 if (!rc) {
6801 pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
6802 rc = -ETIMEDOUT;
6803 goto fail_cmd;
6804 }
6805
6806 if (atomic_read(&ac->cmd_state) > 0) {
6807 pr_err("%s: DSP returned error[%s]\n",
6808 __func__, adsp_err_get_err_str(
6809 atomic_read(&ac->cmd_state)));
6810 rc = adsp_err_get_lnx_err_code(
6811 atomic_read(&ac->cmd_state));
6812 goto fail_cmd;
6813 }
6814 rc = 0;
6815fail_cmd:
6816 return rc;
6817}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306818EXPORT_SYMBOL(q6asm_stream_media_format_block_aptx_dec);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306819
6820static int __q6asm_ds1_set_endp_params(struct audio_client *ac, int param_id,
6821 int param_value, int stream_id)
6822{
6823 struct asm_dec_ddp_endp_param_v2 ddp_cfg;
6824 int rc = 0;
6825
6826 pr_debug("%s: session[%d] stream[%d],param_id[%d]param_value[%d]",
6827 __func__, ac->session, stream_id, param_id, param_value);
6828
6829 q6asm_stream_add_hdr(ac, &ddp_cfg.hdr, sizeof(ddp_cfg), TRUE,
6830 stream_id);
6831 atomic_set(&ac->cmd_state, -1);
6832 /*
6833 * Updated the token field with stream/session for compressed playback
6834 * Platform driver must know the stream with which the command is
6835 * associated
6836 */
6837 if (ac->io_mode & COMPRESSED_STREAM_IO)
6838 q6asm_update_token(&ddp_cfg.hdr.token,
6839 ac->session,
6840 stream_id,
6841 0, /* Buffer index is NA */
6842 0, /* Direction flag is NA */
6843 WAIT_CMD);
6844 ddp_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
6845 ddp_cfg.encdec.param_id = param_id;
6846 ddp_cfg.encdec.param_size = sizeof(struct asm_dec_ddp_endp_param_v2) -
6847 (sizeof(struct apr_hdr) +
6848 sizeof(struct asm_stream_cmd_set_encdec_param));
6849 ddp_cfg.endp_param_value = param_value;
6850 rc = apr_send_pkt(ac->apr, (uint32_t *) &ddp_cfg);
6851 if (rc < 0) {
6852 pr_err("%s: Command opcode[0x%x] failed %d\n",
6853 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
6854 goto fail_cmd;
6855 }
6856 rc = wait_event_timeout(ac->cmd_wait,
6857 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6858 if (!rc) {
6859 pr_err("%s: timeout opcode[0x%x]\n", __func__,
6860 ddp_cfg.hdr.opcode);
6861 rc = -ETIMEDOUT;
6862 goto fail_cmd;
6863 }
6864 if (atomic_read(&ac->cmd_state) > 0) {
6865 pr_err("%s: DSP returned error[%s]\n",
6866 __func__, adsp_err_get_err_str(
6867 atomic_read(&ac->cmd_state)));
6868 rc = adsp_err_get_lnx_err_code(
6869 atomic_read(&ac->cmd_state));
6870 goto fail_cmd;
6871 }
6872 return 0;
6873fail_cmd:
6874 return rc;
6875}
6876
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306877/**
6878 * q6asm_ds1_set_endp_params -
6879 * command to set DS1 params for ASM
6880 *
6881 * @ac: Audio client handle
6882 * @param_id: param id
6883 * @param_value: value of param
6884 *
6885 * Returns 0 on success or error on failure
6886 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306887int q6asm_ds1_set_endp_params(struct audio_client *ac,
6888 int param_id, int param_value)
6889{
6890 return __q6asm_ds1_set_endp_params(ac, param_id, param_value,
6891 ac->stream_id);
6892}
6893
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306894/**
6895 * q6asm_ds1_set_stream_endp_params -
6896 * command to set DS1 params for ASM stream
6897 *
6898 * @ac: Audio client handle
6899 * @param_id: param id
6900 * @param_value: value of param
6901 * @stream_id: stream ID info
6902 *
6903 * Returns 0 on success or error on failure
6904 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306905int q6asm_ds1_set_stream_endp_params(struct audio_client *ac,
6906 int param_id, int param_value,
6907 int stream_id)
6908{
6909 return __q6asm_ds1_set_endp_params(ac, param_id, param_value,
6910 stream_id);
6911}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306912EXPORT_SYMBOL(q6asm_ds1_set_stream_endp_params);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306913
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306914/**
6915 * q6asm_memory_map -
6916 * command to send memory map for ASM
6917 *
6918 * @ac: Audio client handle
6919 * @buf_add: buffer address to map
6920 * @dir: RX or TX session
6921 * @bufsz: size of each buffer
6922 * @bufcnt: buffer count
6923 *
6924 * Returns 0 on success or error on failure
6925 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306926int q6asm_memory_map(struct audio_client *ac, phys_addr_t buf_add, int dir,
6927 uint32_t bufsz, uint32_t bufcnt)
6928{
6929 struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
6930 struct avs_shared_map_region_payload *mregions = NULL;
6931 struct audio_port_data *port = NULL;
6932 void *mmap_region_cmd = NULL;
6933 void *payload = NULL;
6934 struct asm_buffer_node *buffer_node = NULL;
6935 int rc = 0;
6936 int cmd_size = 0;
6937
6938 if (!ac) {
6939 pr_err("%s: APR handle NULL\n", __func__);
6940 return -EINVAL;
6941 }
6942 if (ac->mmap_apr == NULL) {
6943 pr_err("%s: mmap APR handle NULL\n", __func__);
6944 return -EINVAL;
6945 }
6946 pr_debug("%s: Session[%d]\n", __func__, ac->session);
6947
6948 buffer_node = kmalloc(sizeof(struct asm_buffer_node), GFP_KERNEL);
6949 if (!buffer_node)
6950 return -ENOMEM;
6951
6952 cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions)
6953 + sizeof(struct avs_shared_map_region_payload) * bufcnt;
6954
6955 mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
6956 if (mmap_region_cmd == NULL) {
6957 rc = -EINVAL;
6958 kfree(buffer_node);
6959 return rc;
6960 }
6961 mmap_regions = (struct avs_cmd_shared_mem_map_regions *)
6962 mmap_region_cmd;
6963 q6asm_add_mmaphdr(ac, &mmap_regions->hdr, cmd_size, dir);
6964 atomic_set(&ac->mem_state, -1);
6965 mmap_regions->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS;
6966 mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
6967 mmap_regions->num_regions = bufcnt & 0x00ff;
6968 mmap_regions->property_flag = 0x00;
6969 payload = ((u8 *) mmap_region_cmd +
6970 sizeof(struct avs_cmd_shared_mem_map_regions));
6971 mregions = (struct avs_shared_map_region_payload *)payload;
6972
6973 ac->port[dir].tmp_hdl = 0;
6974 port = &ac->port[dir];
6975 pr_debug("%s: buf_add 0x%pK, bufsz: %d\n", __func__,
6976 &buf_add, bufsz);
6977 mregions->shm_addr_lsw = lower_32_bits(buf_add);
6978 mregions->shm_addr_msw = msm_audio_populate_upper_32_bits(buf_add);
6979 mregions->mem_size_bytes = bufsz;
6980 ++mregions;
6981
6982 rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) mmap_region_cmd);
6983 if (rc < 0) {
6984 pr_err("%s: mmap op[0x%x]rc[%d]\n", __func__,
6985 mmap_regions->hdr.opcode, rc);
6986 rc = -EINVAL;
6987 kfree(buffer_node);
6988 goto fail_cmd;
6989 }
6990
6991 rc = wait_event_timeout(ac->mem_wait,
6992 (atomic_read(&ac->mem_state) >= 0 &&
6993 ac->port[dir].tmp_hdl), 5*HZ);
6994 if (!rc) {
6995 pr_err("%s: timeout. waited for memory_map\n", __func__);
6996 rc = -ETIMEDOUT;
6997 kfree(buffer_node);
6998 goto fail_cmd;
6999 }
7000 if (atomic_read(&ac->mem_state) > 0) {
7001 pr_err("%s: DSP returned error[%s] for memory_map\n",
7002 __func__, adsp_err_get_err_str(
7003 atomic_read(&ac->mem_state)));
7004 rc = adsp_err_get_lnx_err_code(
7005 atomic_read(&ac->mem_state));
7006 kfree(buffer_node);
7007 goto fail_cmd;
7008 }
7009 buffer_node->buf_phys_addr = buf_add;
7010 buffer_node->mmap_hdl = ac->port[dir].tmp_hdl;
7011 list_add_tail(&buffer_node->list, &ac->port[dir].mem_map_handle);
7012 ac->port[dir].tmp_hdl = 0;
7013 rc = 0;
7014
7015fail_cmd:
7016 kfree(mmap_region_cmd);
7017 return rc;
7018}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307019EXPORT_SYMBOL(q6asm_memory_map);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307020
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307021/**
7022 * q6asm_memory_unmap -
7023 * command to send memory unmap for ASM
7024 *
7025 * @ac: Audio client handle
7026 * @buf_add: buffer address to unmap
7027 * @dir: RX or TX session
7028 *
7029 * Returns 0 on success or error on failure
7030 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307031int q6asm_memory_unmap(struct audio_client *ac, phys_addr_t buf_add, int dir)
7032{
7033 struct avs_cmd_shared_mem_unmap_regions mem_unmap;
7034 struct asm_buffer_node *buf_node = NULL;
7035 struct list_head *ptr, *next;
7036
7037 int rc = 0;
7038
7039 if (!ac) {
7040 pr_err("%s: APR handle NULL\n", __func__);
7041 return -EINVAL;
7042 }
7043 if (this_mmap.apr == NULL) {
7044 pr_err("%s: APR handle NULL\n", __func__);
7045 return -EINVAL;
7046 }
7047 pr_debug("%s: Session[%d]\n", __func__, ac->session);
7048
7049 q6asm_add_mmaphdr(ac, &mem_unmap.hdr,
7050 sizeof(struct avs_cmd_shared_mem_unmap_regions),
7051 dir);
7052 atomic_set(&ac->mem_state, -1);
7053 mem_unmap.hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS;
7054 mem_unmap.mem_map_handle = 0;
7055 list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
7056 buf_node = list_entry(ptr, struct asm_buffer_node,
7057 list);
7058 if (buf_node->buf_phys_addr == buf_add) {
7059 pr_debug("%s: Found the element\n", __func__);
7060 mem_unmap.mem_map_handle = buf_node->mmap_hdl;
7061 break;
7062 }
7063 }
7064 pr_debug("%s: mem_unmap-mem_map_handle: 0x%x\n",
7065 __func__, mem_unmap.mem_map_handle);
7066
7067 if (mem_unmap.mem_map_handle == 0) {
7068 pr_err("%s: Do not send null mem handle to DSP\n", __func__);
7069 rc = 0;
7070 goto fail_cmd;
7071 }
7072 rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) &mem_unmap);
7073 if (rc < 0) {
7074 pr_err("%s: mem_unmap op[0x%x]rc[%d]\n", __func__,
7075 mem_unmap.hdr.opcode, rc);
7076 rc = -EINVAL;
7077 goto fail_cmd;
7078 }
7079
7080 rc = wait_event_timeout(ac->mem_wait,
7081 (atomic_read(&ac->mem_state) >= 0), 5 * HZ);
7082 if (!rc) {
7083 pr_err("%s: timeout. waited for memory_unmap of handle 0x%x\n",
7084 __func__, mem_unmap.mem_map_handle);
7085 rc = -ETIMEDOUT;
7086 goto fail_cmd;
7087 } else if (atomic_read(&ac->mem_state) > 0) {
7088 pr_err("%s DSP returned error [%s] map handle 0x%x\n",
7089 __func__, adsp_err_get_err_str(
7090 atomic_read(&ac->mem_state)),
7091 mem_unmap.mem_map_handle);
7092 rc = adsp_err_get_lnx_err_code(
7093 atomic_read(&ac->mem_state));
7094 goto fail_cmd;
7095 } else if (atomic_read(&ac->unmap_cb_success) == 0) {
7096 pr_err("%s: Error in mem unmap callback of handle 0x%x\n",
7097 __func__, mem_unmap.mem_map_handle);
7098 rc = -EINVAL;
7099 goto fail_cmd;
7100 }
7101
7102 rc = 0;
7103fail_cmd:
7104 list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
7105 buf_node = list_entry(ptr, struct asm_buffer_node,
7106 list);
7107 if (buf_node->buf_phys_addr == buf_add) {
7108 list_del(&buf_node->list);
7109 kfree(buf_node);
7110 break;
7111 }
7112 }
7113 return rc;
7114}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307115EXPORT_SYMBOL(q6asm_memory_unmap);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307116
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307117/**
7118 * q6asm_memory_map_regions -
7119 * command to send memory map regions for ASM
7120 *
7121 * @ac: Audio client handle
7122 * @dir: RX or TX session
7123 * @bufsz: size of each buffer
7124 * @bufcnt: buffer count
7125 * @is_contiguous: alloc contiguous mem or not
7126 *
7127 * Returns 0 on success or error on failure
7128 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307129static int q6asm_memory_map_regions(struct audio_client *ac, int dir,
7130 uint32_t bufsz, uint32_t bufcnt,
7131 bool is_contiguous)
7132{
7133 struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
7134 struct avs_shared_map_region_payload *mregions = NULL;
7135 struct audio_port_data *port = NULL;
7136 struct audio_buffer *ab = NULL;
7137 void *mmap_region_cmd = NULL;
7138 void *payload = NULL;
7139 struct asm_buffer_node *buffer_node = NULL;
7140 int rc = 0;
7141 int i = 0;
7142 uint32_t cmd_size = 0;
7143 uint32_t bufcnt_t;
7144 uint32_t bufsz_t;
7145
7146 if (!ac) {
7147 pr_err("%s: APR handle NULL\n", __func__);
7148 return -EINVAL;
7149 }
7150 if (ac->mmap_apr == NULL) {
7151 pr_err("%s: mmap APR handle NULL\n", __func__);
7152 return -EINVAL;
7153 }
7154 pr_debug("%s: Session[%d]\n", __func__, ac->session);
7155
7156 bufcnt_t = (is_contiguous) ? 1 : bufcnt;
7157 bufsz_t = (is_contiguous) ? (bufsz * bufcnt) : bufsz;
7158
7159 if (is_contiguous) {
7160 /* The size to memory map should be multiple of 4K bytes */
7161 bufsz_t = PAGE_ALIGN(bufsz_t);
7162 }
7163
7164 if (bufcnt_t > (UINT_MAX
7165 - sizeof(struct avs_cmd_shared_mem_map_regions))
7166 / sizeof(struct avs_shared_map_region_payload)) {
7167 pr_err("%s: Unsigned Integer Overflow. bufcnt_t = %u\n",
7168 __func__, bufcnt_t);
7169 return -EINVAL;
7170 }
7171
7172 cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions)
7173 + (sizeof(struct avs_shared_map_region_payload)
7174 * bufcnt_t);
7175
7176
7177 if (bufcnt > (UINT_MAX / sizeof(struct asm_buffer_node))) {
7178 pr_err("%s: Unsigned Integer Overflow. bufcnt = %u\n",
7179 __func__, bufcnt);
7180 return -EINVAL;
7181 }
7182
7183 buffer_node = kzalloc(sizeof(struct asm_buffer_node) * bufcnt,
7184 GFP_KERNEL);
7185 if (!buffer_node)
7186 return -ENOMEM;
7187
7188 mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
7189 if (mmap_region_cmd == NULL) {
7190 rc = -EINVAL;
7191 kfree(buffer_node);
7192 return rc;
7193 }
7194 mmap_regions = (struct avs_cmd_shared_mem_map_regions *)
7195 mmap_region_cmd;
7196 q6asm_add_mmaphdr(ac, &mmap_regions->hdr, cmd_size, dir);
7197 atomic_set(&ac->mem_state, -1);
7198 pr_debug("%s: mmap_region=0x%pK token=0x%x\n", __func__,
7199 mmap_regions, ((ac->session << 8) | dir));
7200
7201 mmap_regions->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS;
7202 mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
7203 mmap_regions->num_regions = bufcnt_t; /*bufcnt & 0x00ff; */
7204 mmap_regions->property_flag = 0x00;
7205 pr_debug("%s: map_regions->nregions = %d\n", __func__,
7206 mmap_regions->num_regions);
7207 payload = ((u8 *) mmap_region_cmd +
7208 sizeof(struct avs_cmd_shared_mem_map_regions));
7209 mregions = (struct avs_shared_map_region_payload *)payload;
7210
7211 ac->port[dir].tmp_hdl = 0;
7212 port = &ac->port[dir];
7213 for (i = 0; i < bufcnt_t; i++) {
7214 ab = &port->buf[i];
7215 mregions->shm_addr_lsw = lower_32_bits(ab->phys);
7216 mregions->shm_addr_msw =
7217 msm_audio_populate_upper_32_bits(ab->phys);
7218 mregions->mem_size_bytes = bufsz_t;
7219 ++mregions;
7220 }
7221
7222 rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) mmap_region_cmd);
7223 if (rc < 0) {
7224 pr_err("%s: mmap_regions op[0x%x]rc[%d]\n", __func__,
7225 mmap_regions->hdr.opcode, rc);
7226 rc = -EINVAL;
7227 kfree(buffer_node);
7228 goto fail_cmd;
7229 }
7230
7231 rc = wait_event_timeout(ac->mem_wait,
7232 (atomic_read(&ac->mem_state) >= 0)
7233 , 5*HZ);
7234 if (!rc) {
7235 pr_err("%s: timeout. waited for memory_map\n", __func__);
7236 rc = -ETIMEDOUT;
7237 kfree(buffer_node);
7238 goto fail_cmd;
7239 }
7240 if (atomic_read(&ac->mem_state) > 0) {
7241 pr_err("%s DSP returned error for memory_map [%s]\n",
7242 __func__, adsp_err_get_err_str(
7243 atomic_read(&ac->mem_state)));
7244 rc = adsp_err_get_lnx_err_code(
7245 atomic_read(&ac->mem_state));
7246 kfree(buffer_node);
7247 goto fail_cmd;
7248 }
7249 mutex_lock(&ac->cmd_lock);
7250
7251 for (i = 0; i < bufcnt; i++) {
7252 ab = &port->buf[i];
7253 buffer_node[i].buf_phys_addr = ab->phys;
7254 buffer_node[i].mmap_hdl = ac->port[dir].tmp_hdl;
7255 list_add_tail(&buffer_node[i].list,
7256 &ac->port[dir].mem_map_handle);
7257 pr_debug("%s: i=%d, bufadd[i] = 0x%pK, maphdl[i] = 0x%x\n",
7258 __func__, i, &buffer_node[i].buf_phys_addr,
7259 buffer_node[i].mmap_hdl);
7260 }
7261 ac->port[dir].tmp_hdl = 0;
7262 mutex_unlock(&ac->cmd_lock);
7263 rc = 0;
7264fail_cmd:
7265 kfree(mmap_region_cmd);
7266 return rc;
7267}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307268EXPORT_SYMBOL(q6asm_memory_map_regions);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307269
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307270/**
7271 * q6asm_memory_unmap_regions -
7272 * command to send memory unmap regions for ASM
7273 *
7274 * @ac: Audio client handle
7275 * @dir: RX or TX session
7276 *
7277 * Returns 0 on success or error on failure
7278 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307279static int q6asm_memory_unmap_regions(struct audio_client *ac, int dir)
7280{
7281 struct avs_cmd_shared_mem_unmap_regions mem_unmap;
7282 struct audio_port_data *port = NULL;
7283 struct asm_buffer_node *buf_node = NULL;
7284 struct list_head *ptr, *next;
7285 phys_addr_t buf_add;
7286 int rc = 0;
7287 int cmd_size = 0;
7288
7289 if (!ac) {
7290 pr_err("%s: APR handle NULL\n", __func__);
7291 return -EINVAL;
7292 }
7293 if (ac->mmap_apr == NULL) {
7294 pr_err("%s: mmap APR handle NULL\n", __func__);
7295 return -EINVAL;
7296 }
7297 pr_debug("%s: Session[%d]\n", __func__, ac->session);
7298
7299 cmd_size = sizeof(struct avs_cmd_shared_mem_unmap_regions);
7300 q6asm_add_mmaphdr(ac, &mem_unmap.hdr, cmd_size, dir);
7301 atomic_set(&ac->mem_state, -1);
7302 port = &ac->port[dir];
7303 buf_add = port->buf->phys;
7304 mem_unmap.hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS;
7305 mem_unmap.mem_map_handle = 0;
7306 list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
7307 buf_node = list_entry(ptr, struct asm_buffer_node,
7308 list);
7309 if (buf_node->buf_phys_addr == buf_add) {
7310 pr_debug("%s: Found the element\n", __func__);
7311 mem_unmap.mem_map_handle = buf_node->mmap_hdl;
7312 break;
7313 }
7314 }
7315
7316 pr_debug("%s: mem_unmap-mem_map_handle: 0x%x\n",
7317 __func__, mem_unmap.mem_map_handle);
7318
7319 if (mem_unmap.mem_map_handle == 0) {
7320 pr_err("%s: Do not send null mem handle to DSP\n", __func__);
7321 rc = 0;
7322 goto fail_cmd;
7323 }
7324 rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) &mem_unmap);
7325 if (rc < 0) {
7326 pr_err("mmap_regions op[0x%x]rc[%d]\n",
7327 mem_unmap.hdr.opcode, rc);
7328 goto fail_cmd;
7329 }
7330
7331 rc = wait_event_timeout(ac->mem_wait,
7332 (atomic_read(&ac->mem_state) >= 0), 5*HZ);
7333 if (!rc) {
7334 pr_err("%s: timeout. waited for memory_unmap of handle 0x%x\n",
7335 __func__, mem_unmap.mem_map_handle);
7336 rc = -ETIMEDOUT;
7337 goto fail_cmd;
7338 } else if (atomic_read(&ac->mem_state) > 0) {
7339 pr_err("%s: DSP returned error[%s]\n",
7340 __func__, adsp_err_get_err_str(
7341 atomic_read(&ac->mem_state)));
7342 rc = adsp_err_get_lnx_err_code(
7343 atomic_read(&ac->mem_state));
7344 goto fail_cmd;
7345 } else if (atomic_read(&ac->unmap_cb_success) == 0) {
7346 pr_err("%s: Error in mem unmap callback of handle 0x%x\n",
7347 __func__, mem_unmap.mem_map_handle);
7348 rc = -EINVAL;
7349 goto fail_cmd;
7350 }
7351 rc = 0;
7352
7353fail_cmd:
7354 list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
7355 buf_node = list_entry(ptr, struct asm_buffer_node,
7356 list);
7357 if (buf_node->buf_phys_addr == buf_add) {
7358 list_del(&buf_node->list);
7359 kfree(buf_node);
7360 break;
7361 }
7362 }
7363 return rc;
7364}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307365EXPORT_SYMBOL(q6asm_memory_unmap_regions);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307366
7367int q6asm_set_lrgain(struct audio_client *ac, int left_gain, int right_gain)
7368{
7369 struct asm_volume_ctrl_multichannel_gain multi_ch_gain;
7370 int sz = 0;
7371 int rc = 0;
7372
7373 if (ac == NULL) {
7374 pr_err("%s: APR handle NULL\n", __func__);
7375 rc = -EINVAL;
7376 goto fail_cmd;
7377 }
7378 if (ac->apr == NULL) {
7379 pr_err("%s: AC APR handle NULL\n", __func__);
7380 rc = -EINVAL;
7381 goto fail_cmd;
7382 }
7383
7384 memset(&multi_ch_gain, 0, sizeof(multi_ch_gain));
7385 sz = sizeof(struct asm_volume_ctrl_multichannel_gain);
7386 q6asm_add_hdr_async(ac, &multi_ch_gain.hdr, sz, TRUE);
7387 atomic_set(&ac->cmd_state_pp, -1);
7388 multi_ch_gain.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
7389 multi_ch_gain.param.data_payload_addr_lsw = 0;
7390 multi_ch_gain.param.data_payload_addr_msw = 0;
7391 multi_ch_gain.param.mem_map_handle = 0;
7392 multi_ch_gain.param.data_payload_size = sizeof(multi_ch_gain) -
7393 sizeof(multi_ch_gain.hdr) - sizeof(multi_ch_gain.param);
7394 multi_ch_gain.data.module_id = ASM_MODULE_ID_VOL_CTRL;
7395 multi_ch_gain.data.param_id = ASM_PARAM_ID_MULTICHANNEL_GAIN;
7396 multi_ch_gain.data.param_size = multi_ch_gain.param.data_payload_size -
7397 sizeof(multi_ch_gain.data);
7398 multi_ch_gain.data.reserved = 0;
7399 multi_ch_gain.gain_data[0].channeltype = PCM_CHANNEL_FL;
7400 multi_ch_gain.gain_data[0].gain = left_gain << 15;
7401 multi_ch_gain.gain_data[1].channeltype = PCM_CHANNEL_FR;
7402 multi_ch_gain.gain_data[1].gain = right_gain << 15;
7403 multi_ch_gain.num_channels = 2;
7404 rc = apr_send_pkt(ac->apr, (uint32_t *) &multi_ch_gain);
7405 if (rc < 0) {
7406 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
7407 __func__, multi_ch_gain.data.param_id, rc);
7408 rc = -EINVAL;
7409 goto fail_cmd;
7410 }
7411
7412 rc = wait_event_timeout(ac->cmd_wait,
7413 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
7414 if (!rc) {
7415 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
7416 multi_ch_gain.data.param_id);
7417 rc = -ETIMEDOUT;
7418 goto fail_cmd;
7419 }
7420 if (atomic_read(&ac->cmd_state_pp) > 0) {
7421 pr_err("%s: DSP returned error[%s] , set-params paramid[0x%x]\n",
7422 __func__, adsp_err_get_err_str(
7423 atomic_read(&ac->cmd_state_pp)),
7424 multi_ch_gain.data.param_id);
7425 rc = adsp_err_get_lnx_err_code(
7426 atomic_read(&ac->cmd_state_pp));
7427 goto fail_cmd;
7428 }
7429 rc = 0;
7430fail_cmd:
7431 return rc;
7432}
7433
7434/*
7435 * q6asm_set_multich_gain: set multiple channel gains on an ASM session
7436 * @ac: audio client handle
7437 * @channels: number of channels caller intends to set gains
7438 * @gains: list of gains of audio channels
7439 * @ch_map: list of channel mapping. Only valid if use_default is false
7440 * @use_default: flag to indicate whether to use default mapping
7441 */
7442int q6asm_set_multich_gain(struct audio_client *ac, uint32_t channels,
7443 uint32_t *gains, uint8_t *ch_map, bool use_default)
7444{
7445 struct asm_volume_ctrl_multichannel_gain multich_gain;
7446 int sz = 0;
7447 int rc = 0;
7448 int i;
7449 u8 default_chmap[VOLUME_CONTROL_MAX_CHANNELS];
7450
7451 if (ac == NULL) {
7452 pr_err("%s: ac is NULL\n", __func__);
7453 rc = -EINVAL;
7454 goto done;
7455 }
7456 if (ac->apr == NULL) {
7457 dev_err(ac->dev, "%s: AC APR handle NULL\n", __func__);
7458 rc = -EINVAL;
7459 goto done;
7460 }
7461 if (gains == NULL) {
7462 dev_err(ac->dev, "%s: gain_list is NULL\n", __func__);
7463 rc = -EINVAL;
7464 goto done;
7465 }
7466 if (channels > VOLUME_CONTROL_MAX_CHANNELS) {
7467 dev_err(ac->dev, "%s: Invalid channel count %d\n",
7468 __func__, channels);
7469 rc = -EINVAL;
7470 goto done;
7471 }
7472 if (!use_default && ch_map == NULL) {
7473 dev_err(ac->dev, "%s: NULL channel map\n", __func__);
7474 rc = -EINVAL;
7475 goto done;
7476 }
7477
7478 memset(&multich_gain, 0, sizeof(multich_gain));
7479 sz = sizeof(struct asm_volume_ctrl_multichannel_gain);
7480 q6asm_add_hdr_async(ac, &multich_gain.hdr, sz, TRUE);
7481 atomic_set(&ac->cmd_state_pp, -1);
7482 multich_gain.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
7483 multich_gain.param.data_payload_addr_lsw = 0;
7484 multich_gain.param.data_payload_addr_msw = 0;
7485 multich_gain.param.mem_map_handle = 0;
7486 multich_gain.param.data_payload_size = sizeof(multich_gain) -
7487 sizeof(multich_gain.hdr) - sizeof(multich_gain.param);
7488 multich_gain.data.module_id = ASM_MODULE_ID_VOL_CTRL;
7489 multich_gain.data.param_id = ASM_PARAM_ID_MULTICHANNEL_GAIN;
7490 multich_gain.data.param_size = multich_gain.param.data_payload_size -
7491 sizeof(multich_gain.data);
7492 multich_gain.data.reserved = 0;
7493
7494 if (use_default) {
7495 rc = q6asm_map_channels(default_chmap, channels, false);
7496 if (rc < 0)
7497 goto done;
7498 for (i = 0; i < channels; i++) {
7499 multich_gain.gain_data[i].channeltype =
7500 default_chmap[i];
7501 multich_gain.gain_data[i].gain = gains[i] << 15;
7502 }
7503 } else {
7504 for (i = 0; i < channels; i++) {
7505 multich_gain.gain_data[i].channeltype = ch_map[i];
7506 multich_gain.gain_data[i].gain = gains[i] << 15;
7507 }
7508 }
7509 multich_gain.num_channels = channels;
7510
7511 rc = apr_send_pkt(ac->apr, (uint32_t *) &multich_gain);
7512 if (rc < 0) {
7513 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
7514 __func__, multich_gain.data.param_id, rc);
7515 goto done;
7516 }
7517
7518 rc = wait_event_timeout(ac->cmd_wait,
7519 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
7520 if (!rc) {
7521 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
7522 multich_gain.data.param_id);
7523 rc = -EINVAL;
7524 goto done;
7525 }
7526 if (atomic_read(&ac->cmd_state_pp) > 0) {
7527 pr_err("%s: DSP returned error[%d] , set-params paramid[0x%x]\n",
7528 __func__, atomic_read(&ac->cmd_state_pp),
7529 multich_gain.data.param_id);
7530 rc = -EINVAL;
7531 goto done;
7532 }
7533 rc = 0;
7534done:
7535 return rc;
7536}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307537EXPORT_SYMBOL(q6asm_set_multich_gain);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307538
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307539/**
7540 * q6asm_set_mute -
7541 * command to set mute for ASM
7542 *
7543 * @ac: Audio client handle
7544 * @muteflag: mute value
7545 *
7546 * Returns 0 on success or error on failure
7547 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307548int q6asm_set_mute(struct audio_client *ac, int muteflag)
7549{
7550 struct asm_volume_ctrl_mute_config mute;
7551 int sz = 0;
7552 int rc = 0;
7553
7554 if (ac == NULL) {
7555 pr_err("%s: APR handle NULL\n", __func__);
7556 rc = -EINVAL;
7557 goto fail_cmd;
7558 }
7559 if (ac->apr == NULL) {
7560 pr_err("%s: AC APR handle NULL\n", __func__);
7561 rc = -EINVAL;
7562 goto fail_cmd;
7563 }
7564
7565 sz = sizeof(struct asm_volume_ctrl_mute_config);
7566 q6asm_add_hdr_async(ac, &mute.hdr, sz, TRUE);
7567 atomic_set(&ac->cmd_state_pp, -1);
7568 mute.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
7569 mute.param.data_payload_addr_lsw = 0;
7570 mute.param.data_payload_addr_msw = 0;
7571 mute.param.mem_map_handle = 0;
7572 mute.param.data_payload_size = sizeof(mute) -
7573 sizeof(mute.hdr) - sizeof(mute.param);
7574 mute.data.module_id = ASM_MODULE_ID_VOL_CTRL;
7575 mute.data.param_id = ASM_PARAM_ID_VOL_CTRL_MUTE_CONFIG;
7576 mute.data.param_size = mute.param.data_payload_size - sizeof(mute.data);
7577 mute.data.reserved = 0;
7578 mute.mute_flag = muteflag;
7579
7580 rc = apr_send_pkt(ac->apr, (uint32_t *) &mute);
7581 if (rc < 0) {
7582 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
7583 __func__, mute.data.param_id, rc);
7584 rc = -EINVAL;
7585 goto fail_cmd;
7586 }
7587
7588 rc = wait_event_timeout(ac->cmd_wait,
7589 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
7590 if (!rc) {
7591 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
7592 mute.data.param_id);
7593 rc = -ETIMEDOUT;
7594 goto fail_cmd;
7595 }
7596 if (atomic_read(&ac->cmd_state_pp) > 0) {
7597 pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
7598 __func__, adsp_err_get_err_str(
7599 atomic_read(&ac->cmd_state_pp)),
7600 mute.data.param_id);
7601 rc = adsp_err_get_lnx_err_code(
7602 atomic_read(&ac->cmd_state_pp));
7603 goto fail_cmd;
7604 }
7605 rc = 0;
7606fail_cmd:
7607 return rc;
7608}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307609EXPORT_SYMBOL(q6asm_set_mute);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307610
7611static int __q6asm_set_volume(struct audio_client *ac, int volume, int instance)
7612{
7613 struct asm_volume_ctrl_master_gain vol;
7614 int sz = 0;
7615 int rc = 0;
7616 int module_id;
7617
7618 if (ac == NULL) {
7619 pr_err("%s: APR handle NULL\n", __func__);
7620 rc = -EINVAL;
7621 goto fail_cmd;
7622 }
7623 if (ac->apr == NULL) {
7624 pr_err("%s: AC APR handle NULL\n", __func__);
7625 rc = -EINVAL;
7626 goto fail_cmd;
7627 }
7628
7629 switch (instance) {
7630 case SOFT_VOLUME_INSTANCE_2:
7631 module_id = ASM_MODULE_ID_VOL_CTRL2;
7632 break;
7633 case SOFT_VOLUME_INSTANCE_1:
7634 default:
7635 module_id = ASM_MODULE_ID_VOL_CTRL;
7636 break;
7637 }
7638
7639 sz = sizeof(struct asm_volume_ctrl_master_gain);
7640 q6asm_add_hdr_async(ac, &vol.hdr, sz, TRUE);
7641 atomic_set(&ac->cmd_state_pp, -1);
7642 vol.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
7643 vol.param.data_payload_addr_lsw = 0;
7644 vol.param.data_payload_addr_msw = 0;
7645 vol.param.mem_map_handle = 0;
7646 vol.param.data_payload_size = sizeof(vol) -
7647 sizeof(vol.hdr) - sizeof(vol.param);
7648 vol.data.module_id = module_id;
7649 vol.data.param_id = ASM_PARAM_ID_VOL_CTRL_MASTER_GAIN;
7650 vol.data.param_size = vol.param.data_payload_size - sizeof(vol.data);
7651 vol.data.reserved = 0;
7652 vol.master_gain = volume;
7653
7654 rc = apr_send_pkt(ac->apr, (uint32_t *) &vol);
7655 if (rc < 0) {
7656 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
7657 __func__, vol.data.param_id, rc);
7658 rc = -EINVAL;
7659 goto fail_cmd;
7660 }
7661
7662 rc = wait_event_timeout(ac->cmd_wait,
7663 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
7664 if (!rc) {
7665 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
7666 vol.data.param_id);
7667 rc = -ETIMEDOUT;
7668 goto fail_cmd;
7669 }
7670 if (atomic_read(&ac->cmd_state_pp) > 0) {
7671 pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
7672 __func__, adsp_err_get_err_str(
7673 atomic_read(&ac->cmd_state_pp)),
7674 vol.data.param_id);
7675 rc = adsp_err_get_lnx_err_code(
7676 atomic_read(&ac->cmd_state_pp));
7677 goto fail_cmd;
7678 }
7679
7680 rc = 0;
7681fail_cmd:
7682 return rc;
7683}
7684
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307685/**
7686 * q6asm_set_volume -
7687 * command to set volume for ASM
7688 *
7689 * @ac: Audio client handle
7690 * @volume: volume level
7691 *
7692 * Returns 0 on success or error on failure
7693 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307694int q6asm_set_volume(struct audio_client *ac, int volume)
7695{
7696 return __q6asm_set_volume(ac, volume, SOFT_VOLUME_INSTANCE_1);
7697}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307698EXPORT_SYMBOL(q6asm_set_volume);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307699
7700int q6asm_set_volume_v2(struct audio_client *ac, int volume, int instance)
7701{
7702 return __q6asm_set_volume(ac, volume, instance);
7703}
7704
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307705/**
7706 * q6asm_set_aptx_dec_bt_addr -
7707 * command to aptx decoder BT addr for ASM
7708 *
7709 * @ac: Audio client handle
7710 * @cfg: APTX decoder bt addr config
7711 *
7712 * Returns 0 on success or error on failure
7713 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307714int q6asm_set_aptx_dec_bt_addr(struct audio_client *ac,
7715 struct aptx_dec_bt_addr_cfg *cfg)
7716{
7717 struct aptx_dec_bt_dev_addr paylod;
7718 int sz = 0;
7719 int rc = 0;
7720
7721 pr_debug("%s: BT addr nap %d, uap %d, lap %d\n", __func__, cfg->nap,
7722 cfg->uap, cfg->lap);
7723
7724 if (ac == NULL) {
7725 pr_err("%s: AC handle NULL\n", __func__);
7726 rc = -EINVAL;
7727 goto fail_cmd;
7728 }
7729 if (ac->apr == NULL) {
7730 pr_err("%s: AC APR handle NULL\n", __func__);
7731 rc = -EINVAL;
7732 goto fail_cmd;
7733 }
7734
7735 sz = sizeof(struct aptx_dec_bt_dev_addr);
7736 q6asm_add_hdr_async(ac, &paylod.hdr, sz, TRUE);
7737 atomic_set(&ac->cmd_state, -1);
7738 paylod.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
7739 paylod.encdec.param_id = APTX_DECODER_BT_ADDRESS;
7740 paylod.encdec.param_size = sz - sizeof(paylod.hdr)
7741 - sizeof(paylod.encdec);
7742 paylod.bt_addr_cfg.lap = cfg->lap;
7743 paylod.bt_addr_cfg.uap = cfg->uap;
7744 paylod.bt_addr_cfg.nap = cfg->nap;
7745
7746 rc = apr_send_pkt(ac->apr, (uint32_t *) &paylod);
7747 if (rc < 0) {
7748 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
7749 __func__, paylod.encdec.param_id, rc);
7750 rc = -EINVAL;
7751 goto fail_cmd;
7752 }
7753
7754 rc = wait_event_timeout(ac->cmd_wait,
7755 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
7756 if (!rc) {
7757 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
7758 paylod.encdec.param_id);
7759 rc = -ETIMEDOUT;
7760 goto fail_cmd;
7761 }
7762 if (atomic_read(&ac->cmd_state) > 0) {
7763 pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
7764 __func__, adsp_err_get_err_str(
7765 atomic_read(&ac->cmd_state)),
7766 paylod.encdec.param_id);
7767 rc = adsp_err_get_lnx_err_code(
7768 atomic_read(&ac->cmd_state));
7769 goto fail_cmd;
7770 }
7771 pr_debug("%s: set BT addr is success\n", __func__);
7772 rc = 0;
7773fail_cmd:
7774 return rc;
7775}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307776EXPORT_SYMBOL(q6asm_set_aptx_dec_bt_addr);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307777
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307778/**
7779 * q6asm_send_ion_fd -
7780 * command to send ION memory map for ASM
7781 *
7782 * @ac: Audio client handle
7783 * @fd: ION file desc
7784 *
7785 * Returns 0 on success or error on failure
7786 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307787int q6asm_send_ion_fd(struct audio_client *ac, int fd)
7788{
7789 struct ion_client *client;
7790 struct ion_handle *handle;
7791 ion_phys_addr_t paddr;
7792 size_t pa_len = 0;
7793 void *vaddr;
7794 int ret;
7795 int sz = 0;
7796 struct avs_rtic_shared_mem_addr shm;
7797
7798 if (ac == NULL) {
7799 pr_err("%s: APR handle NULL\n", __func__);
7800 ret = -EINVAL;
7801 goto fail_cmd;
7802 }
7803 if (ac->apr == NULL) {
7804 pr_err("%s: AC APR handle NULL\n", __func__);
7805 ret = -EINVAL;
7806 goto fail_cmd;
7807 }
7808
7809 ret = msm_audio_ion_import("audio_mem_client",
7810 &client,
7811 &handle,
7812 fd,
7813 NULL,
7814 0,
7815 &paddr,
7816 &pa_len,
7817 &vaddr);
7818 if (ret) {
7819 pr_err("%s: audio ION import failed, rc = %d\n",
7820 __func__, ret);
7821 ret = -ENOMEM;
7822 goto fail_cmd;
7823 }
7824 /* get payload length */
7825 sz = sizeof(struct avs_rtic_shared_mem_addr);
7826 q6asm_add_hdr_async(ac, &shm.hdr, sz, TRUE);
7827 atomic_set(&ac->cmd_state, -1);
7828 shm.shm_buf_addr_lsw = lower_32_bits(paddr);
7829 shm.shm_buf_addr_msw = msm_audio_populate_upper_32_bits(paddr);
7830 shm.buf_size = pa_len;
7831 shm.shm_buf_num_regions = 1;
7832 shm.shm_buf_mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
7833 shm.shm_buf_flag = 0x00;
7834 shm.encdec.param_id = AVS_PARAM_ID_RTIC_SHARED_MEMORY_ADDR;
7835 shm.encdec.param_size = sizeof(struct avs_rtic_shared_mem_addr) -
7836 sizeof(struct apr_hdr) -
7837 sizeof(struct asm_stream_cmd_set_encdec_param_v2);
7838 shm.encdec.service_id = OUT;
7839 shm.encdec.reserved = 0;
7840 shm.map_region.shm_addr_lsw = shm.shm_buf_addr_lsw;
7841 shm.map_region.shm_addr_msw = shm.shm_buf_addr_msw;
7842 shm.map_region.mem_size_bytes = pa_len;
7843 shm.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM_V2;
7844 ret = apr_send_pkt(ac->apr, (uint32_t *) &shm);
7845 if (ret < 0) {
7846 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
7847 __func__, shm.encdec.param_id, ret);
7848 ret = -EINVAL;
7849 goto fail_cmd;
7850 }
7851
7852 ret = wait_event_timeout(ac->cmd_wait,
7853 (atomic_read(&ac->cmd_state) >= 0), 1*HZ);
7854 if (!ret) {
7855 pr_err("%s: timeout, shm.encdec paramid[0x%x]\n", __func__,
7856 shm.encdec.param_id);
7857 ret = -ETIMEDOUT;
7858 goto fail_cmd;
7859 }
7860 if (atomic_read(&ac->cmd_state) > 0) {
7861 pr_err("%s: DSP returned error[%s] shm.encdec paramid[0x%x]\n",
7862 __func__,
7863 adsp_err_get_err_str(atomic_read(&ac->cmd_state)),
7864 shm.encdec.param_id);
7865 ret = adsp_err_get_lnx_err_code(atomic_read(&ac->cmd_state));
7866 goto fail_cmd;
7867 }
7868 ret = 0;
7869fail_cmd:
7870 return ret;
7871}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307872EXPORT_SYMBOL(q6asm_send_ion_fd);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307873
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307874/**
7875 * q6asm_send_rtic_event_ack -
7876 * command to send RTIC event ack
7877 *
7878 * @ac: Audio client handle
7879 * @param: params for event ack
7880 * @params_length: length of params
7881 *
7882 * Returns 0 on success or error on failure
7883 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307884int q6asm_send_rtic_event_ack(struct audio_client *ac,
7885 void *param, uint32_t params_length)
7886{
7887 char *asm_params = NULL;
7888 int sz, rc;
7889 struct avs_param_rtic_event_ack ack;
7890
7891 if (!param || !ac) {
7892 pr_err("%s: %s is NULL\n", __func__,
7893 (!param) ? "param" : "ac");
7894 rc = -EINVAL;
7895 goto done;
7896 }
7897
7898 sz = sizeof(struct avs_param_rtic_event_ack) + params_length;
7899 asm_params = kzalloc(sz, GFP_KERNEL);
7900 if (!asm_params) {
7901 rc = -ENOMEM;
7902 goto done;
7903 }
7904
7905 q6asm_add_hdr_async(ac, &ack.hdr,
7906 sizeof(struct avs_param_rtic_event_ack) +
7907 params_length, TRUE);
7908 atomic_set(&ac->cmd_state, -1);
7909 ack.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM_V2;
7910 ack.encdec.param_id = AVS_PARAM_ID_RTIC_EVENT_ACK;
7911 ack.encdec.param_size = params_length;
7912 ack.encdec.reserved = 0;
7913 ack.encdec.service_id = OUT;
7914 memcpy(asm_params, &ack, sizeof(struct avs_param_rtic_event_ack));
7915 memcpy(asm_params + sizeof(struct avs_param_rtic_event_ack),
7916 param, params_length);
7917 rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params);
7918 if (rc < 0) {
7919 pr_err("%s: apr pkt failed for rtic event ack\n", __func__);
7920 rc = -EINVAL;
7921 goto fail_send_param;
7922 }
7923
7924 rc = wait_event_timeout(ac->cmd_wait,
7925 (atomic_read(&ac->cmd_state) >= 0), 1 * HZ);
7926 if (!rc) {
7927 pr_err("%s: timeout for rtic event ack cmd\n", __func__);
7928 rc = -ETIMEDOUT;
7929 goto fail_send_param;
7930 }
7931
7932 if (atomic_read(&ac->cmd_state) > 0) {
7933 pr_err("%s: DSP returned error[%s] for rtic event ack cmd\n",
7934 __func__, adsp_err_get_err_str(
7935 atomic_read(&ac->cmd_state)));
7936 rc = adsp_err_get_lnx_err_code(
7937 atomic_read(&ac->cmd_state));
7938 goto fail_send_param;
7939 }
7940 rc = 0;
7941
7942fail_send_param:
7943 kfree(asm_params);
7944done:
7945 return rc;
7946}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307947EXPORT_SYMBOL(q6asm_send_rtic_event_ack);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307948
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307949/**
7950 * q6asm_set_softpause -
7951 * command to set pause for ASM
7952 *
7953 * @ac: Audio client handle
7954 * @pause_param: params for pause
7955 *
7956 * Returns 0 on success or error on failure
7957 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307958int q6asm_set_softpause(struct audio_client *ac,
7959 struct asm_softpause_params *pause_param)
7960{
7961 struct asm_soft_pause_params softpause;
7962 int sz = 0;
7963 int rc = 0;
7964
7965 if (ac == NULL) {
7966 pr_err("%s: APR handle NULL\n", __func__);
7967 rc = -EINVAL;
7968 goto fail_cmd;
7969 }
7970 if (ac->apr == NULL) {
7971 pr_err("%s: AC APR handle NULL\n", __func__);
7972 rc = -EINVAL;
7973 goto fail_cmd;
7974 }
7975
7976 sz = sizeof(struct asm_soft_pause_params);
7977 q6asm_add_hdr_async(ac, &softpause.hdr, sz, TRUE);
7978 atomic_set(&ac->cmd_state_pp, -1);
7979 softpause.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
7980
7981 softpause.param.data_payload_addr_lsw = 0;
7982 softpause.param.data_payload_addr_msw = 0;
7983 softpause.param.mem_map_handle = 0;
7984 softpause.param.data_payload_size = sizeof(softpause) -
7985 sizeof(softpause.hdr) - sizeof(softpause.param);
7986 softpause.data.module_id = ASM_MODULE_ID_VOL_CTRL;
7987 softpause.data.param_id = ASM_PARAM_ID_SOFT_PAUSE_PARAMETERS;
7988 softpause.data.param_size = softpause.param.data_payload_size -
7989 sizeof(softpause.data);
7990 softpause.data.reserved = 0;
7991 softpause.enable_flag = pause_param->enable;
7992 softpause.period = pause_param->period;
7993 softpause.step = pause_param->step;
7994 softpause.ramping_curve = pause_param->rampingcurve;
7995
7996 rc = apr_send_pkt(ac->apr, (uint32_t *) &softpause);
7997 if (rc < 0) {
7998 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
7999 __func__, softpause.data.param_id, rc);
8000 rc = -EINVAL;
8001 goto fail_cmd;
8002 }
8003
8004 rc = wait_event_timeout(ac->cmd_wait,
8005 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
8006 if (!rc) {
8007 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
8008 softpause.data.param_id);
8009 rc = -ETIMEDOUT;
8010 goto fail_cmd;
8011 }
8012 if (atomic_read(&ac->cmd_state_pp) > 0) {
8013 pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
8014 __func__, adsp_err_get_err_str(
8015 atomic_read(&ac->cmd_state_pp)),
8016 softpause.data.param_id);
8017 rc = adsp_err_get_lnx_err_code(
8018 atomic_read(&ac->cmd_state_pp));
8019 goto fail_cmd;
8020 }
8021 rc = 0;
8022fail_cmd:
8023 return rc;
8024}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308025EXPORT_SYMBOL(q6asm_set_softpause);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308026
8027static int __q6asm_set_softvolume(struct audio_client *ac,
8028 struct asm_softvolume_params *softvol_param,
8029 int instance)
8030{
8031 struct asm_soft_step_volume_params softvol;
8032 int sz = 0;
8033 int rc = 0;
8034 int module_id;
8035
8036 if (ac == NULL) {
8037 pr_err("%s: APR handle NULL\n", __func__);
8038 rc = -EINVAL;
8039 goto fail_cmd;
8040 }
8041 if (ac->apr == NULL) {
8042 pr_err("%s: AC APR handle NULL\n", __func__);
8043 rc = -EINVAL;
8044 goto fail_cmd;
8045 }
8046
8047 switch (instance) {
8048 case SOFT_VOLUME_INSTANCE_2:
8049 module_id = ASM_MODULE_ID_VOL_CTRL2;
8050 break;
8051 case SOFT_VOLUME_INSTANCE_1:
8052 default:
8053 module_id = ASM_MODULE_ID_VOL_CTRL;
8054 break;
8055 }
8056
8057 sz = sizeof(struct asm_soft_step_volume_params);
8058 q6asm_add_hdr_async(ac, &softvol.hdr, sz, TRUE);
8059 atomic_set(&ac->cmd_state_pp, -1);
8060 softvol.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
8061 softvol.param.data_payload_addr_lsw = 0;
8062 softvol.param.data_payload_addr_msw = 0;
8063 softvol.param.mem_map_handle = 0;
8064 softvol.param.data_payload_size = sizeof(softvol) -
8065 sizeof(softvol.hdr) - sizeof(softvol.param);
8066 softvol.data.module_id = module_id;
8067 softvol.data.param_id = ASM_PARAM_ID_SOFT_VOL_STEPPING_PARAMETERS;
8068 softvol.data.param_size = softvol.param.data_payload_size -
8069 sizeof(softvol.data);
8070 softvol.data.reserved = 0;
8071 softvol.period = softvol_param->period;
8072 softvol.step = softvol_param->step;
8073 softvol.ramping_curve = softvol_param->rampingcurve;
8074
8075 rc = apr_send_pkt(ac->apr, (uint32_t *) &softvol);
8076 if (rc < 0) {
8077 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
8078 __func__, softvol.data.param_id, rc);
8079 rc = -EINVAL;
8080 goto fail_cmd;
8081 }
8082
8083 rc = wait_event_timeout(ac->cmd_wait,
8084 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
8085 if (!rc) {
8086 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
8087 softvol.data.param_id);
8088 rc = -ETIMEDOUT;
8089 goto fail_cmd;
8090 }
8091 if (atomic_read(&ac->cmd_state_pp) > 0) {
8092 pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
8093 __func__, adsp_err_get_err_str(
8094 atomic_read(&ac->cmd_state_pp)),
8095 softvol.data.param_id);
8096 rc = adsp_err_get_lnx_err_code(
8097 atomic_read(&ac->cmd_state_pp));
8098 goto fail_cmd;
8099 }
8100 rc = 0;
8101fail_cmd:
8102 return rc;
8103}
8104
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308105/**
8106 * q6asm_set_softvolume -
8107 * command to set softvolume for ASM
8108 *
8109 * @ac: Audio client handle
8110 * @softvol_param: params for softvol
8111 *
8112 * Returns 0 on success or error on failure
8113 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308114int q6asm_set_softvolume(struct audio_client *ac,
8115 struct asm_softvolume_params *softvol_param)
8116{
8117 return __q6asm_set_softvolume(ac, softvol_param,
8118 SOFT_VOLUME_INSTANCE_1);
8119}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308120EXPORT_SYMBOL(q6asm_set_softvolume);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308121
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308122/**
8123 * q6asm_set_softvolume_v2 -
8124 * command to set softvolume V2 for ASM
8125 *
8126 * @ac: Audio client handle
8127 * @softvol_param: params for softvol
8128 * @instance: instance to apply softvol
8129 *
8130 * Returns 0 on success or error on failure
8131 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308132int q6asm_set_softvolume_v2(struct audio_client *ac,
8133 struct asm_softvolume_params *softvol_param,
8134 int instance)
8135{
8136 return __q6asm_set_softvolume(ac, softvol_param, instance);
8137}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308138EXPORT_SYMBOL(q6asm_set_softvolume_v2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308139
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308140/**
8141 * q6asm_equalizer -
8142 * command to set equalizer for ASM
8143 *
8144 * @ac: Audio client handle
8145 * @eq_p: Equalizer params
8146 *
8147 * Returns 0 on success or error on failure
8148 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308149int q6asm_equalizer(struct audio_client *ac, void *eq_p)
8150{
8151 struct asm_eq_params eq;
8152 struct msm_audio_eq_stream_config *eq_params = NULL;
8153 int i = 0;
8154 int sz = 0;
8155 int rc = 0;
8156
8157 if (ac == NULL) {
8158 pr_err("%s: APR handle NULL\n", __func__);
8159 rc = -EINVAL;
8160 goto fail_cmd;
8161 }
8162 if (ac->apr == NULL) {
8163 pr_err("%s: AC APR handle NULL\n", __func__);
8164 rc = -EINVAL;
8165 goto fail_cmd;
8166 }
8167
8168 if (eq_p == NULL) {
8169 pr_err("%s: [%d]: Invalid Eq param\n", __func__, ac->session);
8170 rc = -EINVAL;
8171 goto fail_cmd;
8172 }
8173 sz = sizeof(struct asm_eq_params);
8174 eq_params = (struct msm_audio_eq_stream_config *) eq_p;
8175 q6asm_add_hdr(ac, &eq.hdr, sz, TRUE);
8176 atomic_set(&ac->cmd_state_pp, -1);
8177
8178 eq.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
8179 eq.param.data_payload_addr_lsw = 0;
8180 eq.param.data_payload_addr_msw = 0;
8181 eq.param.mem_map_handle = 0;
8182 eq.param.data_payload_size = sizeof(eq) -
8183 sizeof(eq.hdr) - sizeof(eq.param);
8184 eq.data.module_id = ASM_MODULE_ID_EQUALIZER;
8185 eq.data.param_id = ASM_PARAM_ID_EQUALIZER_PARAMETERS;
8186 eq.data.param_size = eq.param.data_payload_size - sizeof(eq.data);
8187 eq.enable_flag = eq_params->enable;
8188 eq.num_bands = eq_params->num_bands;
8189
8190 pr_debug("%s: enable:%d numbands:%d\n", __func__, eq_params->enable,
8191 eq_params->num_bands);
8192 for (i = 0; i < eq_params->num_bands; i++) {
8193 eq.eq_bands[i].band_idx =
8194 eq_params->eq_bands[i].band_idx;
8195 eq.eq_bands[i].filterype =
8196 eq_params->eq_bands[i].filter_type;
8197 eq.eq_bands[i].center_freq_hz =
8198 eq_params->eq_bands[i].center_freq_hz;
8199 eq.eq_bands[i].filter_gain =
8200 eq_params->eq_bands[i].filter_gain;
8201 eq.eq_bands[i].q_factor =
8202 eq_params->eq_bands[i].q_factor;
8203 pr_debug("%s: filter_type:%u bandnum:%d\n", __func__,
8204 eq_params->eq_bands[i].filter_type, i);
8205 pr_debug("%s: center_freq_hz:%u bandnum:%d\n", __func__,
8206 eq_params->eq_bands[i].center_freq_hz, i);
8207 pr_debug("%s: filter_gain:%d bandnum:%d\n", __func__,
8208 eq_params->eq_bands[i].filter_gain, i);
8209 pr_debug("%s: q_factor:%d bandnum:%d\n", __func__,
8210 eq_params->eq_bands[i].q_factor, i);
8211 }
8212 rc = apr_send_pkt(ac->apr, (uint32_t *)&eq);
8213 if (rc < 0) {
8214 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
8215 __func__, eq.data.param_id, rc);
8216 rc = -EINVAL;
8217 goto fail_cmd;
8218 }
8219
8220 rc = wait_event_timeout(ac->cmd_wait,
8221 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
8222 if (!rc) {
8223 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
8224 eq.data.param_id);
8225 rc = -ETIMEDOUT;
8226 goto fail_cmd;
8227 }
8228 if (atomic_read(&ac->cmd_state_pp) > 0) {
8229 pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
8230 __func__, adsp_err_get_err_str(
8231 atomic_read(&ac->cmd_state_pp)),
8232 eq.data.param_id);
8233 rc = adsp_err_get_lnx_err_code(
8234 atomic_read(&ac->cmd_state_pp));
8235 goto fail_cmd;
8236 }
8237 rc = 0;
8238fail_cmd:
8239 return rc;
8240}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308241EXPORT_SYMBOL(q6asm_equalizer);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308242
8243static int __q6asm_read(struct audio_client *ac, bool is_custom_len_reqd,
8244 int len)
8245{
8246 struct asm_data_cmd_read_v2 read;
8247 struct asm_buffer_node *buf_node = NULL;
8248 struct list_head *ptr, *next;
8249 struct audio_buffer *ab;
8250 int dsp_buf;
8251 struct audio_port_data *port;
8252 int rc;
8253
8254 if (ac == NULL) {
8255 pr_err("%s: APR handle NULL\n", __func__);
8256 return -EINVAL;
8257 }
8258 if (ac->apr == NULL) {
8259 pr_err("%s: AC APR handle NULL\n", __func__);
8260 return -EINVAL;
8261 }
8262
8263 if (ac->io_mode & SYNC_IO_MODE) {
8264 port = &ac->port[OUT];
8265
8266 q6asm_add_hdr(ac, &read.hdr, sizeof(read), FALSE);
8267
8268 mutex_lock(&port->lock);
8269
8270 dsp_buf = port->dsp_buf;
8271 if (port->buf == NULL) {
8272 pr_err("%s: buf is NULL\n", __func__);
8273 mutex_unlock(&port->lock);
8274 return -EINVAL;
8275 }
8276 ab = &port->buf[dsp_buf];
8277
8278 dev_vdbg(ac->dev, "%s: session[%d]dsp-buf[%d][%pK]cpu_buf[%d][%pK]\n",
8279 __func__,
8280 ac->session,
8281 dsp_buf,
8282 port->buf[dsp_buf].data,
8283 port->cpu_buf,
8284 &port->buf[port->cpu_buf].phys);
8285
8286 read.hdr.opcode = ASM_DATA_CMD_READ_V2;
8287 read.buf_addr_lsw = lower_32_bits(ab->phys);
8288 read.buf_addr_msw = msm_audio_populate_upper_32_bits(ab->phys);
8289
8290 list_for_each_safe(ptr, next, &ac->port[OUT].mem_map_handle) {
8291 buf_node = list_entry(ptr, struct asm_buffer_node,
8292 list);
8293 if (buf_node->buf_phys_addr == ab->phys)
8294 read.mem_map_handle = buf_node->mmap_hdl;
8295 }
8296 dev_vdbg(ac->dev, "memory_map handle in q6asm_read: [%0x]:",
8297 read.mem_map_handle);
8298 read.buf_size = is_custom_len_reqd ? len : ab->size;
8299 read.seq_id = port->dsp_buf;
8300 q6asm_update_token(&read.hdr.token,
8301 0, /* Session ID is NA */
8302 0, /* Stream ID is NA */
8303 port->dsp_buf,
8304 0, /* Direction flag is NA */
8305 WAIT_CMD);
8306 port->dsp_buf = q6asm_get_next_buf(ac, port->dsp_buf,
8307 port->max_buf_cnt);
8308 mutex_unlock(&port->lock);
8309 dev_vdbg(ac->dev, "%s: buf add[%pK] token[0x%x] uid[%d]\n",
8310 __func__, &ab->phys, read.hdr.token,
8311 read.seq_id);
8312 rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
8313 if (rc < 0) {
8314 pr_err("%s: read op[0x%x]rc[%d]\n",
8315 __func__, read.hdr.opcode, rc);
8316 goto fail_cmd;
8317 }
8318 return 0;
8319 }
8320fail_cmd:
8321 return -EINVAL;
8322}
8323
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308324/**
8325 * q6asm_read -
8326 * command to read buffer data from DSP
8327 *
8328 * @ac: Audio client handle
8329 *
8330 * Returns 0 on success or error on failure
8331 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308332int q6asm_read(struct audio_client *ac)
8333{
8334 return __q6asm_read(ac, false/*is_custom_len_reqd*/, 0);
8335}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308336EXPORT_SYMBOL(q6asm_read);
8337
8338
8339/**
8340 * q6asm_read_v2 -
8341 * command to read buffer data from DSP
8342 *
8343 * @ac: Audio client handle
8344 * @len: buffer size to read
8345 *
8346 * Returns 0 on success or error on failure
8347 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308348int q6asm_read_v2(struct audio_client *ac, uint32_t len)
8349{
8350 return __q6asm_read(ac, true /*is_custom_len_reqd*/, len);
8351}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308352EXPORT_SYMBOL(q6asm_read_v2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308353
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308354/**
8355 * q6asm_read_nolock -
8356 * command to read buffer data from DSP
8357 * with no wait for ack.
8358 *
8359 * @ac: Audio client handle
8360 *
8361 * Returns 0 on success or error on failure
8362 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308363int q6asm_read_nolock(struct audio_client *ac)
8364{
8365 struct asm_data_cmd_read_v2 read;
8366 struct asm_buffer_node *buf_node = NULL;
8367 struct list_head *ptr, *next;
8368 struct audio_buffer *ab;
8369 int dsp_buf;
8370 struct audio_port_data *port;
8371 int rc;
8372
8373 if (ac == NULL) {
8374 pr_err("%s: APR handle NULL\n", __func__);
8375 return -EINVAL;
8376 }
8377 if (ac->apr == NULL) {
8378 pr_err("%s: AC APR handle NULL\n", __func__);
8379 return -EINVAL;
8380 }
8381
8382 if (ac->io_mode & SYNC_IO_MODE) {
8383 port = &ac->port[OUT];
8384
8385 q6asm_add_hdr_async(ac, &read.hdr, sizeof(read), FALSE);
8386
8387
8388 dsp_buf = port->dsp_buf;
8389 ab = &port->buf[dsp_buf];
8390
8391 dev_vdbg(ac->dev, "%s: session[%d]dsp-buf[%d][%pK]cpu_buf[%d][%pK]\n",
8392 __func__,
8393 ac->session,
8394 dsp_buf,
8395 port->buf[dsp_buf].data,
8396 port->cpu_buf,
8397 &port->buf[port->cpu_buf].phys);
8398
8399 read.hdr.opcode = ASM_DATA_CMD_READ_V2;
8400 read.buf_addr_lsw = lower_32_bits(ab->phys);
8401 read.buf_addr_msw = msm_audio_populate_upper_32_bits(ab->phys);
8402 read.buf_size = ab->size;
8403 read.seq_id = port->dsp_buf;
8404 q6asm_update_token(&read.hdr.token,
8405 0, /* Session ID is NA */
8406 0, /* Stream ID is NA */
8407 port->dsp_buf,
8408 0, /* Direction flag is NA */
8409 WAIT_CMD);
8410
8411 list_for_each_safe(ptr, next, &ac->port[OUT].mem_map_handle) {
8412 buf_node = list_entry(ptr, struct asm_buffer_node,
8413 list);
8414 if (buf_node->buf_phys_addr == ab->phys) {
8415 read.mem_map_handle = buf_node->mmap_hdl;
8416 break;
8417 }
8418 }
8419
8420 port->dsp_buf = q6asm_get_next_buf(ac, port->dsp_buf,
8421 port->max_buf_cnt);
8422 dev_vdbg(ac->dev, "%s: buf add[%pK] token[0x%x] uid[%d]\n",
8423 __func__, &ab->phys, read.hdr.token,
8424 read.seq_id);
8425 rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
8426 if (rc < 0) {
8427 pr_err("%s: read op[0x%x]rc[%d]\n",
8428 __func__, read.hdr.opcode, rc);
8429 goto fail_cmd;
8430 }
8431 return 0;
8432 }
8433fail_cmd:
8434 return -EINVAL;
8435}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308436EXPORT_SYMBOL(q6asm_read_nolock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308437
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308438/**
8439 * q6asm_async_write -
8440 * command to write DSP buffer
8441 *
8442 * @ac: Audio client handle
8443 * @param: params for async write
8444 *
8445 * Returns 0 on success or error on failure
8446 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308447int q6asm_async_write(struct audio_client *ac,
8448 struct audio_aio_write_param *param)
8449{
8450 int rc = 0;
8451 struct asm_data_cmd_write_v2 write;
8452 struct asm_buffer_node *buf_node = NULL;
8453 struct list_head *ptr, *next;
8454 struct audio_buffer *ab;
8455 struct audio_port_data *port;
8456 phys_addr_t lbuf_phys_addr;
8457 u32 liomode;
8458 u32 io_compressed;
8459 u32 io_compressed_stream;
8460
8461 if (ac == NULL) {
8462 pr_err("%s: APR handle NULL\n", __func__);
8463 return -EINVAL;
8464 }
8465 if (ac->apr == NULL) {
8466 pr_err("%s: AC APR handle NULL\n", __func__);
8467 return -EINVAL;
8468 }
8469
8470 q6asm_stream_add_hdr_async(
8471 ac, &write.hdr, sizeof(write), TRUE, ac->stream_id);
8472 port = &ac->port[IN];
8473 ab = &port->buf[port->dsp_buf];
8474
8475 /* Pass session id as token for AIO scheme */
8476 write.hdr.token = param->uid;
8477 write.hdr.opcode = ASM_DATA_CMD_WRITE_V2;
8478 write.buf_addr_lsw = lower_32_bits(param->paddr);
8479 write.buf_addr_msw = msm_audio_populate_upper_32_bits(param->paddr);
8480 write.buf_size = param->len;
8481 write.timestamp_msw = param->msw_ts;
8482 write.timestamp_lsw = param->lsw_ts;
8483 liomode = (ASYNC_IO_MODE | NT_MODE);
8484 io_compressed = (ASYNC_IO_MODE | COMPRESSED_IO);
8485 io_compressed_stream = (ASYNC_IO_MODE | COMPRESSED_STREAM_IO);
8486
8487 if (ac->io_mode == liomode)
8488 lbuf_phys_addr = (param->paddr - 32);
8489 else if (ac->io_mode == io_compressed ||
8490 ac->io_mode == io_compressed_stream)
8491 lbuf_phys_addr = (param->paddr - param->metadata_len);
8492 else {
8493 if (param->flags & SET_TIMESTAMP)
8494 lbuf_phys_addr = param->paddr -
8495 sizeof(struct snd_codec_metadata);
8496 else
8497 lbuf_phys_addr = param->paddr;
8498 }
8499 dev_vdbg(ac->dev, "%s: token[0x%x], buf_addr[%pK], buf_size[0x%x], ts_msw[0x%x], ts_lsw[0x%x], lbuf_phys_addr: 0x[%pK]\n",
8500 __func__,
8501 write.hdr.token, &param->paddr,
8502 write.buf_size, write.timestamp_msw,
8503 write.timestamp_lsw, &lbuf_phys_addr);
8504
8505 /* Use 0xFF00 for disabling timestamps */
8506 if (param->flags == 0xFF00)
8507 write.flags = (0x00000000 | (param->flags & 0x800000FF));
8508 else
8509 write.flags = (0x80000000 | param->flags);
8510 write.flags |= param->last_buffer << ASM_SHIFT_LAST_BUFFER_FLAG;
8511 write.seq_id = param->uid;
8512 list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
8513 buf_node = list_entry(ptr, struct asm_buffer_node,
8514 list);
8515 if (buf_node->buf_phys_addr == lbuf_phys_addr) {
8516 write.mem_map_handle = buf_node->mmap_hdl;
8517 break;
8518 }
8519 }
8520
8521 rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
8522 if (rc < 0) {
8523 pr_err("%s: write op[0x%x]rc[%d]\n", __func__,
8524 write.hdr.opcode, rc);
8525 goto fail_cmd;
8526 }
8527 return 0;
8528fail_cmd:
8529 return -EINVAL;
8530}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308531EXPORT_SYMBOL(q6asm_async_write);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308532
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308533/**
8534 * q6asm_async_read -
8535 * command to read DSP buffer
8536 *
8537 * @ac: Audio client handle
8538 * @param: params for async read
8539 *
8540 * Returns 0 on success or error on failure
8541 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308542int q6asm_async_read(struct audio_client *ac,
8543 struct audio_aio_read_param *param)
8544{
8545 int rc = 0;
8546 struct asm_data_cmd_read_v2 read;
8547 struct asm_buffer_node *buf_node = NULL;
8548 struct list_head *ptr, *next;
8549 phys_addr_t lbuf_phys_addr;
8550 u32 liomode;
8551 u32 io_compressed;
8552 int dir = 0;
8553
8554 if (ac == NULL) {
8555 pr_err("%s: APR handle NULL\n", __func__);
8556 return -EINVAL;
8557 }
8558 if (ac->apr == NULL) {
8559 pr_err("%s: AC APR handle NULL\n", __func__);
8560 return -EINVAL;
8561 }
8562
8563 q6asm_add_hdr_async(ac, &read.hdr, sizeof(read), FALSE);
8564
8565 /* Pass session id as token for AIO scheme */
8566 read.hdr.token = param->uid;
8567 read.hdr.opcode = ASM_DATA_CMD_READ_V2;
8568 read.buf_addr_lsw = lower_32_bits(param->paddr);
8569 read.buf_addr_msw = msm_audio_populate_upper_32_bits(param->paddr);
8570 read.buf_size = param->len;
8571 read.seq_id = param->uid;
8572 liomode = (NT_MODE | ASYNC_IO_MODE);
8573 io_compressed = (ASYNC_IO_MODE | COMPRESSED_IO);
8574 if (ac->io_mode == liomode) {
8575 lbuf_phys_addr = (param->paddr - 32);
8576 /*legacy wma driver case*/
8577 dir = IN;
8578 } else if (ac->io_mode == io_compressed) {
8579 lbuf_phys_addr = (param->paddr - 64);
8580 dir = OUT;
8581 } else {
8582 if (param->flags & COMPRESSED_TIMESTAMP_FLAG)
8583 lbuf_phys_addr = param->paddr -
8584 sizeof(struct snd_codec_metadata);
8585 else
8586 lbuf_phys_addr = param->paddr;
8587 dir = OUT;
8588 }
8589
8590 list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
8591 buf_node = list_entry(ptr, struct asm_buffer_node,
8592 list);
8593 if (buf_node->buf_phys_addr == lbuf_phys_addr) {
8594 read.mem_map_handle = buf_node->mmap_hdl;
8595 break;
8596 }
8597 }
8598
8599 rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
8600 if (rc < 0) {
8601 pr_err("%s: read op[0x%x]rc[%d]\n", __func__,
8602 read.hdr.opcode, rc);
8603 goto fail_cmd;
8604 }
8605 return 0;
8606fail_cmd:
8607 return -EINVAL;
8608}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308609EXPORT_SYMBOL(q6asm_async_read);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308610
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308611/**
8612 * q6asm_write -
8613 * command to write buffer data to DSP
8614 *
8615 * @ac: Audio client handle
8616 * @len: buffer size
8617 * @msw_ts: upper 32bits of timestamp
8618 * @lsw_ts: lower 32bits of timestamp
8619 * @flags: Flags for timestamp mode
8620 *
8621 * Returns 0 on success or error on failure
8622 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308623int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
8624 uint32_t lsw_ts, uint32_t flags)
8625{
8626 int rc = 0;
8627 struct asm_data_cmd_write_v2 write;
8628 struct asm_buffer_node *buf_node = NULL;
8629 struct audio_port_data *port;
8630 struct audio_buffer *ab;
8631 int dsp_buf = 0;
8632
8633 if (ac == NULL) {
8634 pr_err("%s: APR handle NULL\n", __func__);
8635 return -EINVAL;
8636 }
8637 if (ac->apr == NULL) {
8638 pr_err("%s: AC APR handle NULL\n", __func__);
8639 return -EINVAL;
8640 }
8641
8642 dev_vdbg(ac->dev, "%s: session[%d] len=%d\n",
8643 __func__, ac->session, len);
8644 if (ac->io_mode & SYNC_IO_MODE) {
8645 port = &ac->port[IN];
8646
8647 q6asm_add_hdr(ac, &write.hdr, sizeof(write),
8648 FALSE);
8649 mutex_lock(&port->lock);
8650
8651 dsp_buf = port->dsp_buf;
8652 ab = &port->buf[dsp_buf];
8653
8654 q6asm_update_token(&write.hdr.token,
8655 0, /* Session ID is NA */
8656 0, /* Stream ID is NA */
8657 port->dsp_buf,
8658 0, /* Direction flag is NA */
8659 NO_WAIT_CMD);
8660 write.hdr.opcode = ASM_DATA_CMD_WRITE_V2;
8661 write.buf_addr_lsw = lower_32_bits(ab->phys);
8662 write.buf_addr_msw = msm_audio_populate_upper_32_bits(ab->phys);
8663 write.buf_size = len;
8664 write.seq_id = port->dsp_buf;
8665 write.timestamp_lsw = lsw_ts;
8666 write.timestamp_msw = msw_ts;
8667 /* Use 0xFF00 for disabling timestamps */
8668 if (flags == 0xFF00)
8669 write.flags = (0x00000000 | (flags & 0x800000FF));
8670 else
8671 write.flags = (0x80000000 | flags);
8672 port->dsp_buf = q6asm_get_next_buf(ac, port->dsp_buf,
8673 port->max_buf_cnt);
8674 buf_node = list_first_entry(&ac->port[IN].mem_map_handle,
8675 struct asm_buffer_node,
8676 list);
8677 write.mem_map_handle = buf_node->mmap_hdl;
8678
8679 dev_vdbg(ac->dev, "%s: ab->phys[%pK]bufadd[0x%x] token[0x%x]buf_id[0x%x]buf_size[0x%x]mmaphdl[0x%x]"
8680 , __func__,
8681 &ab->phys,
8682 write.buf_addr_lsw,
8683 write.hdr.token,
8684 write.seq_id,
8685 write.buf_size,
8686 write.mem_map_handle);
8687 mutex_unlock(&port->lock);
8688
8689 config_debug_fs_write(ab);
8690
8691 rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
8692 if (rc < 0) {
8693 pr_err("%s: write op[0x%x]rc[%d]\n",
8694 __func__, write.hdr.opcode, rc);
8695 goto fail_cmd;
8696 }
8697 return 0;
8698 }
8699fail_cmd:
8700 return -EINVAL;
8701}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308702EXPORT_SYMBOL(q6asm_write);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308703
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308704/**
8705 * q6asm_write_nolock -
8706 * command to write buffer data to DSP
8707 * with no wait for ack.
8708 *
8709 * @ac: Audio client handle
8710 * @len: buffer size
8711 * @msw_ts: upper 32bits of timestamp
8712 * @lsw_ts: lower 32bits of timestamp
8713 * @flags: Flags for timestamp mode
8714 *
8715 * Returns 0 on success or error on failure
8716 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308717int q6asm_write_nolock(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
8718 uint32_t lsw_ts, uint32_t flags)
8719{
8720 int rc = 0;
8721 struct asm_data_cmd_write_v2 write;
8722 struct asm_buffer_node *buf_node = NULL;
8723 struct audio_port_data *port;
8724 struct audio_buffer *ab;
8725 int dsp_buf = 0;
8726
8727 if (ac == NULL) {
8728 pr_err("%s: APR handle NULL\n", __func__);
8729 return -EINVAL;
8730 }
8731 if (ac->apr == NULL) {
8732 pr_err("%s: AC APR handle NULL\n", __func__);
8733 return -EINVAL;
8734 }
8735
8736 dev_vdbg(ac->dev, "%s: session[%d] len=%d\n",
8737 __func__, ac->session, len);
8738 if (ac->io_mode & SYNC_IO_MODE) {
8739 port = &ac->port[IN];
8740
8741 q6asm_add_hdr_async(ac, &write.hdr, sizeof(write),
8742 FALSE);
8743
8744 dsp_buf = port->dsp_buf;
8745 ab = &port->buf[dsp_buf];
8746
8747 q6asm_update_token(&write.hdr.token,
8748 0, /* Session ID is NA */
8749 0, /* Stream ID is NA */
8750 port->dsp_buf,
8751 0, /* Direction flag is NA */
8752 NO_WAIT_CMD);
8753
8754 write.hdr.opcode = ASM_DATA_CMD_WRITE_V2;
8755 write.buf_addr_lsw = lower_32_bits(ab->phys);
8756 write.buf_addr_msw = msm_audio_populate_upper_32_bits(ab->phys);
8757 write.buf_size = len;
8758 write.seq_id = port->dsp_buf;
8759 write.timestamp_lsw = lsw_ts;
8760 write.timestamp_msw = msw_ts;
8761 buf_node = list_first_entry(&ac->port[IN].mem_map_handle,
8762 struct asm_buffer_node,
8763 list);
8764 write.mem_map_handle = buf_node->mmap_hdl;
8765 /* Use 0xFF00 for disabling timestamps */
8766 if (flags == 0xFF00)
8767 write.flags = (0x00000000 | (flags & 0x800000FF));
8768 else
8769 write.flags = (0x80000000 | flags);
8770 port->dsp_buf = q6asm_get_next_buf(ac, port->dsp_buf,
8771 port->max_buf_cnt);
8772
8773 dev_vdbg(ac->dev, "%s: ab->phys[%pK]bufadd[0x%x]token[0x%x] buf_id[0x%x]buf_size[0x%x]mmaphdl[0x%x]"
8774 , __func__,
8775 &ab->phys,
8776 write.buf_addr_lsw,
8777 write.hdr.token,
8778 write.seq_id,
8779 write.buf_size,
8780 write.mem_map_handle);
8781
8782 rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
8783 if (rc < 0) {
8784 pr_err("%s: write op[0x%x]rc[%d]\n",
8785 __func__, write.hdr.opcode, rc);
8786 goto fail_cmd;
8787 }
8788 return 0;
8789 }
8790fail_cmd:
8791 return -EINVAL;
8792}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308793EXPORT_SYMBOL(q6asm_write_nolock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308794
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308795/**
8796 * q6asm_get_session_time -
8797 * command to retrieve timestamp info
8798 *
8799 * @ac: Audio client handle
8800 * @tstamp: pointer to fill with timestamp info
8801 *
8802 * Returns 0 on success or error on failure
8803 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308804int q6asm_get_session_time(struct audio_client *ac, uint64_t *tstamp)
8805{
8806 struct asm_mtmx_strtr_get_params mtmx_params;
8807 int rc;
8808
8809 if (ac == NULL) {
8810 pr_err("%s: APR handle NULL\n", __func__);
8811 return -EINVAL;
8812 }
8813 if (ac->apr == NULL) {
8814 pr_err("%s: AC APR handle NULL\n", __func__);
8815 return -EINVAL;
8816 }
8817 if (tstamp == NULL) {
8818 pr_err("%s: tstamp NULL\n", __func__);
8819 return -EINVAL;
8820 }
8821
8822 q6asm_add_hdr(ac, &mtmx_params.hdr, sizeof(mtmx_params), TRUE);
8823 mtmx_params.hdr.opcode = ASM_SESSION_CMD_GET_MTMX_STRTR_PARAMS_V2;
8824 mtmx_params.param_info.data_payload_addr_lsw = 0;
8825 mtmx_params.param_info.data_payload_addr_msw = 0;
8826 mtmx_params.param_info.mem_map_handle = 0;
8827 mtmx_params.param_info.direction = (ac->io_mode & TUN_READ_IO_MODE
8828 ? 1 : 0);
8829 mtmx_params.param_info.module_id =
8830 ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
8831 mtmx_params.param_info.param_id =
8832 ASM_SESSION_MTMX_STRTR_PARAM_SESSION_TIME_V3;
8833 mtmx_params.param_info.param_max_size =
8834 sizeof(struct asm_stream_param_data_v2) +
8835 sizeof(struct asm_session_mtmx_strtr_param_session_time_v3_t);
8836 atomic_set(&ac->time_flag, 1);
8837
8838 dev_vdbg(ac->dev, "%s: session[%d]opcode[0x%x]\n", __func__,
8839 ac->session, mtmx_params.hdr.opcode);
8840 rc = apr_send_pkt(ac->apr, (uint32_t *) &mtmx_params);
8841 if (rc < 0) {
8842 pr_err("%s: Commmand 0x%x failed %d\n", __func__,
8843 mtmx_params.hdr.opcode, rc);
8844 goto fail_cmd;
8845 }
8846 rc = wait_event_timeout(ac->time_wait,
8847 (atomic_read(&ac->time_flag) == 0), 5*HZ);
8848 if (!rc) {
8849 pr_err("%s: timeout in getting session time from DSP\n",
8850 __func__);
8851 goto fail_cmd;
8852 }
8853
8854 *tstamp = ac->time_stamp;
8855 return 0;
8856
8857fail_cmd:
8858 return -EINVAL;
8859}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308860EXPORT_SYMBOL(q6asm_get_session_time);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308861
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308862/**
8863 * q6asm_get_session_time_legacy -
8864 * command to retrieve timestamp info
8865 *
8866 * @ac: Audio client handle
8867 * @tstamp: pointer to fill with timestamp info
8868 *
8869 * Returns 0 on success or error on failure
8870 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308871int q6asm_get_session_time_legacy(struct audio_client *ac, uint64_t *tstamp)
8872{
8873 struct apr_hdr hdr;
8874 int rc;
8875
8876 if (ac == NULL) {
8877 pr_err("%s: APR handle NULL\n", __func__);
8878 return -EINVAL;
8879 }
8880 if (ac->apr == NULL) {
8881 pr_err("%s: AC APR handle NULL\n", __func__);
8882 return -EINVAL;
8883 }
8884 if (tstamp == NULL) {
8885 pr_err("%s: tstamp NULL\n", __func__);
8886 return -EINVAL;
8887 }
8888
8889 q6asm_add_hdr(ac, &hdr, sizeof(hdr), TRUE);
8890 hdr.opcode = ASM_SESSION_CMD_GET_SESSIONTIME_V3;
8891 atomic_set(&ac->time_flag, 1);
8892
8893 dev_vdbg(ac->dev, "%s: session[%d]opcode[0x%x]\n", __func__,
8894 ac->session,
8895 hdr.opcode);
8896 rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
8897 if (rc < 0) {
8898 pr_err("%s: Commmand 0x%x failed %d\n",
8899 __func__, hdr.opcode, rc);
8900 goto fail_cmd;
8901 }
8902 rc = wait_event_timeout(ac->time_wait,
8903 (atomic_read(&ac->time_flag) == 0), 5*HZ);
8904 if (!rc) {
8905 pr_err("%s: timeout in getting session time from DSP\n",
8906 __func__);
8907 goto fail_cmd;
8908 }
8909
8910 *tstamp = ac->time_stamp;
8911 return 0;
8912
8913fail_cmd:
8914 return -EINVAL;
8915}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308916EXPORT_SYMBOL(q6asm_get_session_time_legacy);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308917
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308918/**
8919 * q6asm_send_audio_effects_params -
8920 * command to send audio effects params
8921 *
8922 * @ac: Audio client handle
8923 * @params: audio effects params
8924 * @params_length: size of params
8925 *
8926 * Returns 0 on success or error on failure
8927 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308928int q6asm_send_audio_effects_params(struct audio_client *ac, char *params,
8929 uint32_t params_length)
8930{
8931 char *asm_params = NULL;
8932 struct apr_hdr hdr;
8933 struct asm_stream_cmd_set_pp_params_v2 payload_params;
8934 int sz, rc;
8935
8936 pr_debug("%s:\n", __func__);
8937 if (!ac) {
8938 pr_err("%s: APR handle NULL\n", __func__);
8939 return -EINVAL;
8940 }
8941 if (ac->apr == NULL) {
8942 pr_err("%s: AC APR handle NULL\n", __func__);
8943 return -EINVAL;
8944 }
8945 if (params == NULL) {
8946 pr_err("%s: params NULL\n", __func__);
8947 return -EINVAL;
8948 }
8949 sz = sizeof(struct apr_hdr) +
8950 sizeof(struct asm_stream_cmd_set_pp_params_v2) +
8951 params_length;
8952 asm_params = kzalloc(sz, GFP_KERNEL);
8953 if (!asm_params) {
8954 pr_err("%s, asm params memory alloc failed", __func__);
8955 return -ENOMEM;
8956 }
8957 q6asm_add_hdr_async(ac, &hdr, (sizeof(struct apr_hdr) +
8958 sizeof(struct asm_stream_cmd_set_pp_params_v2) +
8959 params_length), TRUE);
8960 atomic_set(&ac->cmd_state_pp, -1);
8961 hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
8962 payload_params.data_payload_addr_lsw = 0;
8963 payload_params.data_payload_addr_msw = 0;
8964 payload_params.mem_map_handle = 0;
8965 payload_params.data_payload_size = params_length;
8966 memcpy(((u8 *)asm_params), &hdr, sizeof(struct apr_hdr));
8967 memcpy(((u8 *)asm_params + sizeof(struct apr_hdr)), &payload_params,
8968 sizeof(struct asm_stream_cmd_set_pp_params_v2));
8969 memcpy(((u8 *)asm_params + sizeof(struct apr_hdr) +
8970 sizeof(struct asm_stream_cmd_set_pp_params_v2)),
8971 params, params_length);
8972 rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params);
8973 if (rc < 0) {
8974 pr_err("%s: audio effects set-params send failed\n", __func__);
8975 rc = -EINVAL;
8976 goto fail_send_param;
8977 }
8978 rc = wait_event_timeout(ac->cmd_wait,
8979 (atomic_read(&ac->cmd_state_pp) >= 0), 1*HZ);
8980 if (!rc) {
8981 pr_err("%s: timeout, audio effects set-params\n", __func__);
8982 rc = -ETIMEDOUT;
8983 goto fail_send_param;
8984 }
8985 if (atomic_read(&ac->cmd_state_pp) > 0) {
8986 pr_err("%s: DSP returned error[%s] set-params\n",
8987 __func__, adsp_err_get_err_str(
8988 atomic_read(&ac->cmd_state_pp)));
8989 rc = adsp_err_get_lnx_err_code(
8990 atomic_read(&ac->cmd_state_pp));
8991 goto fail_send_param;
8992 }
8993
8994 rc = 0;
8995fail_send_param:
8996 kfree(asm_params);
8997 return rc;
8998}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308999EXPORT_SYMBOL(q6asm_send_audio_effects_params);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309000
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309001/**
9002 * q6asm_send_mtmx_strtr_window -
9003 * command to send matrix for window params
9004 *
9005 * @ac: Audio client handle
9006 * @window_param: window params
9007 * @param_id: param id for window
9008 *
9009 * Returns 0 on success or error on failure
9010 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309011int q6asm_send_mtmx_strtr_window(struct audio_client *ac,
9012 struct asm_session_mtmx_strtr_param_window_v2_t *window_param,
9013 uint32_t param_id)
9014{
9015 struct asm_mtmx_strtr_params matrix;
9016 int sz = 0;
9017 int rc = 0;
9018
9019 pr_debug("%s: Window lsw is %d, window msw is %d\n", __func__,
9020 window_param->window_lsw, window_param->window_msw);
9021
9022 if (!ac) {
9023 pr_err("%s: audio client handle is NULL\n", __func__);
9024 rc = -EINVAL;
9025 goto fail_cmd;
9026 }
9027
9028 if (ac->apr == NULL) {
9029 pr_err("%s: ac->apr is NULL", __func__);
9030 rc = -EINVAL;
9031 goto fail_cmd;
9032 }
9033
9034 sz = sizeof(struct asm_mtmx_strtr_params);
9035 q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE);
9036 atomic_set(&ac->cmd_state, -1);
9037 matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2;
9038
9039 matrix.param.data_payload_addr_lsw = 0;
9040 matrix.param.data_payload_addr_msw = 0;
9041 matrix.param.mem_map_handle = 0;
9042 matrix.param.data_payload_size =
9043 sizeof(struct asm_stream_param_data_v2) +
9044 sizeof(struct asm_session_mtmx_strtr_param_window_v2_t);
9045 matrix.param.direction = 0; /* RX */
9046 matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
9047 matrix.data.param_id = param_id;
9048 matrix.data.param_size =
9049 sizeof(struct asm_session_mtmx_strtr_param_window_v2_t);
9050 matrix.data.reserved = 0;
9051 memcpy(&(matrix.config.window_param),
9052 window_param,
9053 sizeof(struct asm_session_mtmx_strtr_param_window_v2_t));
9054
9055 rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix);
9056 if (rc < 0) {
9057 pr_err("%s: Render window start send failed paramid [0x%x]\n",
9058 __func__, matrix.data.param_id);
9059 rc = -EINVAL;
9060 goto fail_cmd;
9061 }
9062
9063 rc = wait_event_timeout(ac->cmd_wait,
9064 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
9065 if (!rc) {
9066 pr_err("%s: timeout, Render window start paramid[0x%x]\n",
9067 __func__, matrix.data.param_id);
9068 rc = -ETIMEDOUT;
9069 goto fail_cmd;
9070 }
9071
9072 if (atomic_read(&ac->cmd_state) > 0) {
9073 pr_err("%s: DSP returned error[%s]\n",
9074 __func__, adsp_err_get_err_str(
9075 atomic_read(&ac->cmd_state)));
9076 rc = adsp_err_get_lnx_err_code(
9077 atomic_read(&ac->cmd_state));
9078 goto fail_cmd;
9079 }
9080 rc = 0;
9081fail_cmd:
9082 return rc;
9083}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309084EXPORT_SYMBOL(q6asm_send_mtmx_strtr_window);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309085
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309086/**
9087 * q6asm_send_mtmx_strtr_render_mode -
9088 * command to send matrix for render mode
9089 *
9090 * @ac: Audio client handle
9091 * @render_mode: rendering mode
9092 *
9093 * Returns 0 on success or error on failure
9094 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309095int q6asm_send_mtmx_strtr_render_mode(struct audio_client *ac,
9096 uint32_t render_mode)
9097{
9098 struct asm_mtmx_strtr_params matrix;
9099 struct asm_session_mtmx_strtr_param_render_mode_t render_param;
9100 int sz = 0;
9101 int rc = 0;
9102
9103 pr_debug("%s: render mode is %d\n", __func__, render_mode);
9104
9105 if (!ac) {
9106 pr_err("%s: audio client handle is NULL\n", __func__);
9107 rc = -EINVAL;
9108 goto exit;
9109 }
9110
9111 if (ac->apr == NULL) {
9112 pr_err("%s: ac->apr is NULL\n", __func__);
9113 rc = -EINVAL;
9114 goto exit;
9115 }
9116
9117 if ((render_mode != ASM_SESSION_MTMX_STRTR_PARAM_RENDER_DEFAULT) &&
9118 (render_mode != ASM_SESSION_MTMX_STRTR_PARAM_RENDER_LOCAL_STC)) {
9119 pr_err("%s: Invalid render mode %d\n", __func__, render_mode);
9120 rc = -EINVAL;
9121 goto exit;
9122 }
9123
9124 memset(&render_param, 0,
9125 sizeof(struct asm_session_mtmx_strtr_param_render_mode_t));
9126 render_param.flags = render_mode;
9127
9128 memset(&matrix, 0, sizeof(struct asm_mtmx_strtr_params));
9129 sz = sizeof(struct asm_mtmx_strtr_params);
9130 q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE);
9131 atomic_set(&ac->cmd_state, -1);
9132 matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2;
9133
9134 matrix.param.data_payload_addr_lsw = 0;
9135 matrix.param.data_payload_addr_msw = 0;
9136 matrix.param.mem_map_handle = 0;
9137 matrix.param.data_payload_size =
9138 sizeof(struct asm_stream_param_data_v2) +
9139 sizeof(struct asm_session_mtmx_strtr_param_render_mode_t);
9140 matrix.param.direction = 0; /* RX */
9141 matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
9142 matrix.data.param_id = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_MODE_CMD;
9143 matrix.data.param_size =
9144 sizeof(struct asm_session_mtmx_strtr_param_render_mode_t);
9145 matrix.data.reserved = 0;
9146 memcpy(&(matrix.config.render_param),
9147 &render_param,
9148 sizeof(struct asm_session_mtmx_strtr_param_render_mode_t));
9149
9150 rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix);
9151 if (rc < 0) {
9152 pr_err("%s: Render mode send failed paramid [0x%x]\n",
9153 __func__, matrix.data.param_id);
9154 rc = -EINVAL;
9155 goto exit;
9156 }
9157
9158 rc = wait_event_timeout(ac->cmd_wait,
9159 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
9160 if (!rc) {
9161 pr_err("%s: timeout, Render mode send paramid [0x%x]\n",
9162 __func__, matrix.data.param_id);
9163 rc = -ETIMEDOUT;
9164 goto exit;
9165 }
9166
9167 if (atomic_read(&ac->cmd_state) > 0) {
9168 pr_err("%s: DSP returned error[%s]\n",
9169 __func__, adsp_err_get_err_str(
9170 atomic_read(&ac->cmd_state)));
9171 rc = adsp_err_get_lnx_err_code(
9172 atomic_read(&ac->cmd_state));
9173 goto exit;
9174 }
9175 rc = 0;
9176exit:
9177 return rc;
9178}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309179EXPORT_SYMBOL(q6asm_send_mtmx_strtr_render_mode);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309180
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309181/**
9182 * q6asm_send_mtmx_strtr_clk_rec_mode -
9183 * command to send matrix for clock rec
9184 *
9185 * @ac: Audio client handle
9186 * @clk_rec_mode: mode for clock rec
9187 *
9188 * Returns 0 on success or error on failure
9189 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309190int q6asm_send_mtmx_strtr_clk_rec_mode(struct audio_client *ac,
9191 uint32_t clk_rec_mode)
9192{
9193 struct asm_mtmx_strtr_params matrix;
9194 struct asm_session_mtmx_strtr_param_clk_rec_t clk_rec_param;
9195 int sz = 0;
9196 int rc = 0;
9197
9198 pr_debug("%s: clk rec mode is %d\n", __func__, clk_rec_mode);
9199
9200 if (!ac) {
9201 pr_err("%s: audio client handle is NULL\n", __func__);
9202 rc = -EINVAL;
9203 goto exit;
9204 }
9205
9206 if (ac->apr == NULL) {
9207 pr_err("%s: ac->apr is NULL\n", __func__);
9208 rc = -EINVAL;
9209 goto exit;
9210 }
9211
9212 if ((clk_rec_mode != ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_NONE) &&
9213 (clk_rec_mode != ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_AUTO)) {
9214 pr_err("%s: Invalid clk rec mode %d\n", __func__, clk_rec_mode);
9215 rc = -EINVAL;
9216 goto exit;
9217 }
9218
9219 memset(&clk_rec_param, 0,
9220 sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t));
9221 clk_rec_param.flags = clk_rec_mode;
9222
9223 memset(&matrix, 0, sizeof(struct asm_mtmx_strtr_params));
9224 sz = sizeof(struct asm_mtmx_strtr_params);
9225 q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE);
9226 atomic_set(&ac->cmd_state, -1);
9227 matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2;
9228
9229 matrix.param.data_payload_addr_lsw = 0;
9230 matrix.param.data_payload_addr_msw = 0;
9231 matrix.param.mem_map_handle = 0;
9232 matrix.param.data_payload_size =
9233 sizeof(struct asm_stream_param_data_v2) +
9234 sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t);
9235 matrix.param.direction = 0; /* RX */
9236 matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
9237 matrix.data.param_id = ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_CMD;
9238 matrix.data.param_size =
9239 sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t);
9240 matrix.data.reserved = 0;
9241 memcpy(&(matrix.config.clk_rec_param),
9242 &clk_rec_param,
9243 sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t));
9244
9245 rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix);
9246 if (rc < 0) {
9247 pr_err("%s: clk rec mode send failed paramid [0x%x]\n",
9248 __func__, matrix.data.param_id);
9249 rc = -EINVAL;
9250 goto exit;
9251 }
9252
9253 rc = wait_event_timeout(ac->cmd_wait,
9254 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
9255 if (!rc) {
9256 pr_err("%s: timeout, clk rec mode send paramid [0x%x]\n",
9257 __func__, matrix.data.param_id);
9258 rc = -ETIMEDOUT;
9259 goto exit;
9260 }
9261
9262 if (atomic_read(&ac->cmd_state) > 0) {
9263 pr_err("%s: DSP returned error[%s]\n",
9264 __func__, adsp_err_get_err_str(
9265 atomic_read(&ac->cmd_state)));
9266 rc = adsp_err_get_lnx_err_code(
9267 atomic_read(&ac->cmd_state));
9268 goto exit;
9269 }
9270 rc = 0;
9271exit:
9272 return rc;
9273}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309274EXPORT_SYMBOL(q6asm_send_mtmx_strtr_clk_rec_mode);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309275
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309276/**
9277 * q6asm_send_mtmx_strtr_enable_adjust_session_clock -
9278 * command to send matrix for adjust time
9279 *
9280 * @ac: Audio client handle
9281 * @enable: flag to adjust time or not
9282 *
9283 * Returns 0 on success or error on failure
9284 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309285int q6asm_send_mtmx_strtr_enable_adjust_session_clock(struct audio_client *ac,
9286 bool enable)
9287{
9288 struct asm_mtmx_strtr_params matrix;
9289 struct asm_session_mtmx_param_adjust_session_time_ctl_t adjust_time;
9290 int sz = 0;
9291 int rc = 0;
9292
9293 pr_debug("%s: adjust session enable %d\n", __func__, enable);
9294
9295 if (!ac) {
9296 pr_err("%s: audio client handle is NULL\n", __func__);
9297 rc = -EINVAL;
9298 goto exit;
9299 }
9300
9301 if (ac->apr == NULL) {
9302 pr_err("%s: ac->apr is NULL\n", __func__);
9303 rc = -EINVAL;
9304 goto exit;
9305 }
9306
9307 adjust_time.enable = enable;
9308 memset(&matrix, 0, sizeof(struct asm_mtmx_strtr_params));
9309 sz = sizeof(struct asm_mtmx_strtr_params);
9310 q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE);
9311 atomic_set(&ac->cmd_state, -1);
9312 matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2;
9313
9314 matrix.param.data_payload_addr_lsw = 0;
9315 matrix.param.data_payload_addr_msw = 0;
9316 matrix.param.mem_map_handle = 0;
9317 matrix.param.data_payload_size =
9318 sizeof(struct asm_stream_param_data_v2) +
9319 sizeof(struct asm_session_mtmx_param_adjust_session_time_ctl_t);
9320 matrix.param.direction = 0; /* RX */
9321 matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
9322 matrix.data.param_id = ASM_SESSION_MTMX_PARAM_ADJUST_SESSION_TIME_CTL;
9323 matrix.data.param_size =
9324 sizeof(struct asm_session_mtmx_param_adjust_session_time_ctl_t);
9325 matrix.data.reserved = 0;
9326 matrix.config.adj_time_param.enable = adjust_time.enable;
9327
9328 rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix);
9329 if (rc < 0) {
9330 pr_err("%s: enable adjust session failed failed paramid [0x%x]\n",
9331 __func__, matrix.data.param_id);
9332 rc = -EINVAL;
9333 goto exit;
9334 }
9335
9336 rc = wait_event_timeout(ac->cmd_wait,
9337 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
9338 if (!rc) {
9339 pr_err("%s: enable adjust session failed failed paramid [0x%x]\n",
9340 __func__, matrix.data.param_id);
9341 rc = -ETIMEDOUT;
9342 goto exit;
9343 }
9344
9345 if (atomic_read(&ac->cmd_state) > 0) {
9346 pr_err("%s: DSP returned error[%s]\n",
9347 __func__, adsp_err_get_err_str(
9348 atomic_read(&ac->cmd_state)));
9349 rc = adsp_err_get_lnx_err_code(
9350 atomic_read(&ac->cmd_state));
9351 goto exit;
9352 }
9353 rc = 0;
9354exit:
9355 return rc;
9356}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309357EXPORT_SYMBOL(q6asm_send_mtmx_strtr_enable_adjust_session_clock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309358
9359
9360static int __q6asm_cmd(struct audio_client *ac, int cmd, uint32_t stream_id)
9361{
9362 struct apr_hdr hdr;
9363 int rc;
9364 atomic_t *state;
9365 int cnt = 0;
9366
9367 if (!ac) {
9368 pr_err("%s: APR handle NULL\n", __func__);
9369 return -EINVAL;
9370 }
9371 if (ac->apr == NULL) {
9372 pr_err("%s: AC APR handle NULL\n", __func__);
9373 return -EINVAL;
9374 }
9375 q6asm_stream_add_hdr(ac, &hdr, sizeof(hdr), TRUE, stream_id);
9376 atomic_set(&ac->cmd_state, -1);
9377 /*
9378 * Updated the token field with stream/session for compressed playback
9379 * Platform driver must know the the stream with which the command is
9380 * associated
9381 */
9382 if (ac->io_mode & COMPRESSED_STREAM_IO)
9383 q6asm_update_token(&hdr.token,
9384 ac->session,
9385 stream_id,
9386 0, /* Buffer index is NA */
9387 0, /* Direction flag is NA */
9388 WAIT_CMD);
9389 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
9390 __func__, hdr.token, stream_id, ac->session);
9391 switch (cmd) {
9392 case CMD_PAUSE:
9393 pr_debug("%s: CMD_PAUSE\n", __func__);
9394 hdr.opcode = ASM_SESSION_CMD_PAUSE;
9395 state = &ac->cmd_state;
9396 break;
9397 case CMD_SUSPEND:
9398 pr_debug("%s: CMD_SUSPEND\n", __func__);
9399 hdr.opcode = ASM_SESSION_CMD_SUSPEND;
9400 state = &ac->cmd_state;
9401 break;
9402 case CMD_FLUSH:
9403 pr_debug("%s: CMD_FLUSH\n", __func__);
9404 hdr.opcode = ASM_STREAM_CMD_FLUSH;
9405 state = &ac->cmd_state;
9406 break;
9407 case CMD_OUT_FLUSH:
9408 pr_debug("%s: CMD_OUT_FLUSH\n", __func__);
9409 hdr.opcode = ASM_STREAM_CMD_FLUSH_READBUFS;
9410 state = &ac->cmd_state;
9411 break;
9412 case CMD_EOS:
9413 pr_debug("%s: CMD_EOS\n", __func__);
9414 hdr.opcode = ASM_DATA_CMD_EOS;
9415 atomic_set(&ac->cmd_state, 0);
9416 state = &ac->cmd_state;
9417 break;
9418 case CMD_CLOSE:
9419 pr_debug("%s: CMD_CLOSE\n", __func__);
9420 hdr.opcode = ASM_STREAM_CMD_CLOSE;
9421 state = &ac->cmd_state;
9422 break;
9423 default:
9424 pr_err("%s: Invalid format[%d]\n", __func__, cmd);
9425 rc = -EINVAL;
9426 goto fail_cmd;
9427 }
9428 pr_debug("%s: session[%d]opcode[0x%x]\n", __func__,
9429 ac->session,
9430 hdr.opcode);
9431 rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
9432 if (rc < 0) {
9433 pr_err("%s: Commmand 0x%x failed %d\n",
9434 __func__, hdr.opcode, rc);
9435 rc = -EINVAL;
9436 goto fail_cmd;
9437 }
9438 rc = wait_event_timeout(ac->cmd_wait, (atomic_read(state) >= 0), 5*HZ);
9439 if (!rc) {
9440 pr_err("%s: timeout. waited for response opcode[0x%x]\n",
9441 __func__, hdr.opcode);
9442 rc = -ETIMEDOUT;
9443 goto fail_cmd;
9444 }
9445 if (atomic_read(state) > 0) {
9446 pr_err("%s: DSP returned error[%s] opcode %d\n",
9447 __func__, adsp_err_get_err_str(
9448 atomic_read(state)),
9449 hdr.opcode);
9450 rc = adsp_err_get_lnx_err_code(atomic_read(state));
9451 goto fail_cmd;
9452 }
9453
9454 if (cmd == CMD_FLUSH)
9455 q6asm_reset_buf_state(ac);
9456 if (cmd == CMD_CLOSE) {
9457 /* check if DSP return all buffers */
9458 if (ac->port[IN].buf) {
9459 for (cnt = 0; cnt < ac->port[IN].max_buf_cnt;
9460 cnt++) {
9461 if (ac->port[IN].buf[cnt].used == IN) {
9462 dev_vdbg(ac->dev, "Write Buf[%d] not returned\n",
9463 cnt);
9464 }
9465 }
9466 }
9467 if (ac->port[OUT].buf) {
9468 for (cnt = 0; cnt < ac->port[OUT].max_buf_cnt; cnt++) {
9469 if (ac->port[OUT].buf[cnt].used == OUT) {
9470 dev_vdbg(ac->dev, "Read Buf[%d] not returned\n",
9471 cnt);
9472 }
9473 }
9474 }
9475 }
9476 return 0;
9477fail_cmd:
9478 return rc;
9479}
9480
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309481/**
9482 * q6asm_cmd -
9483 * Function used to send commands for
9484 * ASM with wait for ack.
9485 *
9486 * @ac: Audio client handle
9487 * @cmd: command to send
9488 *
9489 * Returns 0 on success or error on failure
9490 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309491int q6asm_cmd(struct audio_client *ac, int cmd)
9492{
9493 return __q6asm_cmd(ac, cmd, ac->stream_id);
9494}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309495EXPORT_SYMBOL(q6asm_cmd);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309496
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309497/**
9498 * q6asm_stream_cmd -
9499 * Function used to send commands for
9500 * ASM stream with wait for ack.
9501 *
9502 * @ac: Audio client handle
9503 * @cmd: command to send
9504 * @stream_id: Stream ID
9505 *
9506 * Returns 0 on success or error on failure
9507 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309508int q6asm_stream_cmd(struct audio_client *ac, int cmd, uint32_t stream_id)
9509{
9510 return __q6asm_cmd(ac, cmd, stream_id);
9511}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309512EXPORT_SYMBOL(q6asm_stream_cmd);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309513
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309514/**
9515 * q6asm_cmd_nowait -
9516 * Function used to send commands for
9517 * ASM stream without wait for ack.
9518 *
9519 * @ac: Audio client handle
9520 * @cmd: command to send
9521 * @stream_id: Stream ID
9522 *
9523 * Returns 0 on success or error on failure
9524 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309525static int __q6asm_cmd_nowait(struct audio_client *ac, int cmd,
9526 uint32_t stream_id)
9527{
9528 struct apr_hdr hdr;
9529 int rc;
9530
9531 if (!ac) {
9532 pr_err("%s: APR handle NULL\n", __func__);
9533 return -EINVAL;
9534 }
9535 if (ac->apr == NULL) {
9536 pr_err("%s: AC APR handle NULL\n", __func__);
9537 return -EINVAL;
9538 }
9539 q6asm_stream_add_hdr_async(ac, &hdr, sizeof(hdr), TRUE, stream_id);
9540 atomic_set(&ac->cmd_state, 1);
9541 /*
9542 * Updated the token field with stream/session for compressed playback
9543 * Platform driver must know the the stream with which the command is
9544 * associated
9545 */
9546 if (ac->io_mode & COMPRESSED_STREAM_IO)
9547 q6asm_update_token(&hdr.token,
9548 ac->session,
9549 stream_id,
9550 0, /* Buffer index is NA */
9551 0, /* Direction flag is NA */
9552 NO_WAIT_CMD);
9553
9554 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
9555 __func__, hdr.token, stream_id, ac->session);
9556 switch (cmd) {
9557 case CMD_PAUSE:
9558 pr_debug("%s: CMD_PAUSE\n", __func__);
9559 hdr.opcode = ASM_SESSION_CMD_PAUSE;
9560 break;
9561 case CMD_EOS:
9562 pr_debug("%s: CMD_EOS\n", __func__);
9563 hdr.opcode = ASM_DATA_CMD_EOS;
9564 break;
9565 case CMD_CLOSE:
9566 pr_debug("%s: CMD_CLOSE\n", __func__);
9567 hdr.opcode = ASM_STREAM_CMD_CLOSE;
9568 break;
9569 default:
9570 pr_err("%s: Invalid format[%d]\n", __func__, cmd);
9571 goto fail_cmd;
9572 }
9573 pr_debug("%s: session[%d]opcode[0x%x]\n", __func__,
9574 ac->session,
9575 hdr.opcode);
9576
9577 rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
9578 if (rc < 0) {
9579 pr_err("%s: Commmand 0x%x failed %d\n",
9580 __func__, hdr.opcode, rc);
9581 goto fail_cmd;
9582 }
9583 return 0;
9584fail_cmd:
9585 return -EINVAL;
9586}
9587
9588int q6asm_cmd_nowait(struct audio_client *ac, int cmd)
9589{
9590 pr_debug("%s: stream_id: %d\n", __func__, ac->stream_id);
9591 return __q6asm_cmd_nowait(ac, cmd, ac->stream_id);
9592}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309593EXPORT_SYMBOL(q6asm_cmd_nowait);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309594
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309595/**
9596 * q6asm_stream_cmd_nowait -
9597 * Function used to send commands for
9598 * ASM stream without wait for ack.
9599 *
9600 * @ac: Audio client handle
9601 * @cmd: command to send
9602 * @stream_id: Stream ID
9603 *
9604 * Returns 0 on success or error on failure
9605 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309606int q6asm_stream_cmd_nowait(struct audio_client *ac, int cmd,
9607 uint32_t stream_id)
9608{
9609 pr_debug("%s: stream_id: %d\n", __func__, stream_id);
9610 return __q6asm_cmd_nowait(ac, cmd, stream_id);
9611}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309612EXPORT_SYMBOL(q6asm_stream_cmd_nowait);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309613
9614int __q6asm_send_meta_data(struct audio_client *ac, uint32_t stream_id,
9615 uint32_t initial_samples, uint32_t trailing_samples)
9616{
9617 struct asm_data_cmd_remove_silence silence;
9618 int rc = 0;
9619
9620 if (!ac) {
9621 pr_err("%s: APR handle NULL\n", __func__);
9622 return -EINVAL;
9623 }
9624 if (ac->apr == NULL) {
9625 pr_err("%s: AC APR handle NULL\n", __func__);
9626 return -EINVAL;
9627 }
9628 pr_debug("%s: session[%d]\n", __func__, ac->session);
9629 q6asm_stream_add_hdr_async(ac, &silence.hdr, sizeof(silence), TRUE,
9630 stream_id);
9631
9632 /*
9633 * Updated the token field with stream/session for compressed playback
9634 * Platform driver must know the the stream with which the command is
9635 * associated
9636 */
9637 if (ac->io_mode & COMPRESSED_STREAM_IO)
9638 q6asm_update_token(&silence.hdr.token,
9639 ac->session,
9640 stream_id,
9641 0, /* Buffer index is NA */
9642 0, /* Direction flag is NA */
9643 NO_WAIT_CMD);
9644 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
9645 __func__, silence.hdr.token, stream_id, ac->session);
9646
9647 silence.hdr.opcode = ASM_DATA_CMD_REMOVE_INITIAL_SILENCE;
9648 silence.num_samples_to_remove = initial_samples;
9649
9650 rc = apr_send_pkt(ac->apr, (uint32_t *) &silence);
9651 if (rc < 0) {
9652 pr_err("%s: Commmand silence failed[%d]", __func__, rc);
9653
9654 goto fail_cmd;
9655 }
9656
9657 silence.hdr.opcode = ASM_DATA_CMD_REMOVE_TRAILING_SILENCE;
9658 silence.num_samples_to_remove = trailing_samples;
9659
9660
9661 rc = apr_send_pkt(ac->apr, (uint32_t *) &silence);
9662 if (rc < 0) {
9663 pr_err("%s: Commmand silence failed[%d]", __func__, rc);
9664 goto fail_cmd;
9665 }
9666
9667 return 0;
9668fail_cmd:
9669 return -EINVAL;
9670}
9671
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309672/**
9673 * q6asm_stream_send_meta_data -
9674 * command to send meta data for stream
9675 *
9676 * @ac: Audio client handle
9677 * @stream_id: Stream ID
9678 * @initial_samples: Initial samples of stream
9679 * @trailing_samples: Trailing samples of stream
9680 *
9681 * Returns 0 on success or error on failure
9682 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309683int q6asm_stream_send_meta_data(struct audio_client *ac, uint32_t stream_id,
9684 uint32_t initial_samples, uint32_t trailing_samples)
9685{
9686 return __q6asm_send_meta_data(ac, stream_id, initial_samples,
9687 trailing_samples);
9688}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309689EXPORT_SYMBOL(q6asm_stream_send_meta_data);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309690
9691int q6asm_send_meta_data(struct audio_client *ac, uint32_t initial_samples,
9692 uint32_t trailing_samples)
9693{
9694 return __q6asm_send_meta_data(ac, ac->stream_id, initial_samples,
9695 trailing_samples);
9696}
9697
9698static void q6asm_reset_buf_state(struct audio_client *ac)
9699{
9700 int cnt = 0;
9701 int loopcnt = 0;
9702 int used;
9703 struct audio_port_data *port = NULL;
9704
9705 if (ac->io_mode & SYNC_IO_MODE) {
9706 used = (ac->io_mode & TUN_WRITE_IO_MODE ? 1 : 0);
9707 mutex_lock(&ac->cmd_lock);
9708 for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
9709 port = &ac->port[loopcnt];
9710 cnt = port->max_buf_cnt - 1;
9711 port->dsp_buf = 0;
9712 port->cpu_buf = 0;
9713 while (cnt >= 0) {
9714 if (!port->buf)
9715 continue;
9716 port->buf[cnt].used = used;
9717 cnt--;
9718 }
9719 }
9720 mutex_unlock(&ac->cmd_lock);
9721 }
9722}
9723
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309724/**
9725 * q6asm_reg_tx_overflow -
9726 * command to register for TX overflow events
9727 *
9728 * @ac: Audio client handle
9729 * @enable: flag to enable or disable events
9730 *
9731 * Returns 0 on success or error on failure
9732 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309733int q6asm_reg_tx_overflow(struct audio_client *ac, uint16_t enable)
9734{
9735 struct asm_session_cmd_regx_overflow tx_overflow;
9736 int rc;
9737
9738 if (!ac) {
9739 pr_err("%s: APR handle NULL\n", __func__);
9740 return -EINVAL;
9741 }
9742 if (ac->apr == NULL) {
9743 pr_err("%s: AC APR handle NULL\n", __func__);
9744 return -EINVAL;
9745 }
9746 pr_debug("%s: session[%d]enable[%d]\n", __func__,
9747 ac->session, enable);
9748 q6asm_add_hdr(ac, &tx_overflow.hdr, sizeof(tx_overflow), TRUE);
9749 atomic_set(&ac->cmd_state, -1);
9750
9751 tx_overflow.hdr.opcode =
9752 ASM_SESSION_CMD_REGISTER_FORX_OVERFLOW_EVENTS;
9753 /* tx overflow event: enable */
9754 tx_overflow.enable_flag = enable;
9755
9756 rc = apr_send_pkt(ac->apr, (uint32_t *) &tx_overflow);
9757 if (rc < 0) {
9758 pr_err("%s: tx overflow op[0x%x]rc[%d]\n",
9759 __func__, tx_overflow.hdr.opcode, rc);
9760 rc = -EINVAL;
9761 goto fail_cmd;
9762 }
9763 rc = wait_event_timeout(ac->cmd_wait,
9764 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
9765 if (!rc) {
9766 pr_err("%s: timeout. waited for tx overflow\n", __func__);
9767 rc = -ETIMEDOUT;
9768 goto fail_cmd;
9769 }
9770 if (atomic_read(&ac->cmd_state) > 0) {
9771 pr_err("%s: DSP returned error[%s]\n",
9772 __func__, adsp_err_get_err_str(
9773 atomic_read(&ac->cmd_state)));
9774 rc = adsp_err_get_lnx_err_code(
9775 atomic_read(&ac->cmd_state));
9776 goto fail_cmd;
9777 }
9778
9779 return 0;
9780fail_cmd:
9781 return rc;
9782}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309783EXPORT_SYMBOL(q6asm_reg_tx_overflow);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309784
9785int q6asm_reg_rx_underflow(struct audio_client *ac, uint16_t enable)
9786{
9787 struct asm_session_cmd_rgstr_rx_underflow rx_underflow;
9788 int rc;
9789
9790 if (!ac) {
9791 pr_err("%s: AC APR handle NULL\n", __func__);
9792 return -EINVAL;
9793 }
9794 if (ac->apr == NULL) {
9795 pr_err("%s: APR handle NULL\n", __func__);
9796 return -EINVAL;
9797 }
9798 pr_debug("%s: session[%d]enable[%d]\n", __func__,
9799 ac->session, enable);
9800 q6asm_add_hdr_async(ac, &rx_underflow.hdr, sizeof(rx_underflow), FALSE);
9801
9802 rx_underflow.hdr.opcode =
9803 ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS;
9804 /* tx overflow event: enable */
9805 rx_underflow.enable_flag = enable;
9806
9807 rc = apr_send_pkt(ac->apr, (uint32_t *) &rx_underflow);
9808 if (rc < 0) {
9809 pr_err("%s: tx overflow op[0x%x]rc[%d]\n",
9810 __func__, rx_underflow.hdr.opcode, rc);
9811 goto fail_cmd;
9812 }
9813 return 0;
9814fail_cmd:
9815 return -EINVAL;
9816}
9817
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309818/**
9819 * q6asm_adjust_session_clock -
9820 * command to adjust session clock
9821 *
9822 * @ac: Audio client handle
9823 * @adjust_time_lsw: lower 32bits
9824 * @adjust_time_msw: upper 32bits
9825 *
9826 * Returns 0 on success or error on failure
9827 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309828int q6asm_adjust_session_clock(struct audio_client *ac,
9829 uint32_t adjust_time_lsw,
9830 uint32_t adjust_time_msw)
9831{
9832 int rc = 0;
9833 int sz = 0;
9834 struct asm_session_cmd_adjust_session_clock_v2 adjust_clock;
9835
9836 pr_debug("%s: adjust_time_lsw is %x, adjust_time_msw is %x\n", __func__,
9837 adjust_time_lsw, adjust_time_msw);
9838
9839 if (!ac) {
9840 pr_err("%s: audio client handle is NULL\n", __func__);
9841 rc = -EINVAL;
9842 goto fail_cmd;
9843 }
9844
9845 if (ac->apr == NULL) {
9846 pr_err("%s: ac->apr is NULL", __func__);
9847 rc = -EINVAL;
9848 goto fail_cmd;
9849 }
9850
9851 sz = sizeof(struct asm_session_cmd_adjust_session_clock_v2);
9852 q6asm_add_hdr(ac, &adjust_clock.hdr, sz, TRUE);
9853 atomic_set(&ac->cmd_state, -1);
9854 adjust_clock.hdr.opcode = ASM_SESSION_CMD_ADJUST_SESSION_CLOCK_V2;
9855
9856 adjust_clock.adjustime_lsw = adjust_time_lsw;
9857 adjust_clock.adjustime_msw = adjust_time_msw;
9858
9859
9860 rc = apr_send_pkt(ac->apr, (uint32_t *) &adjust_clock);
9861 if (rc < 0) {
9862 pr_err("%s: adjust_clock send failed paramid [0x%x]\n",
9863 __func__, adjust_clock.hdr.opcode);
9864 rc = -EINVAL;
9865 goto fail_cmd;
9866 }
9867
9868 rc = wait_event_timeout(ac->cmd_wait,
9869 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
9870 if (!rc) {
9871 pr_err("%s: timeout, adjust_clock paramid[0x%x]\n",
9872 __func__, adjust_clock.hdr.opcode);
9873 rc = -ETIMEDOUT;
9874 goto fail_cmd;
9875 }
9876
9877 if (atomic_read(&ac->cmd_state) > 0) {
9878 pr_err("%s: DSP returned error[%s]\n",
9879 __func__, adsp_err_get_err_str(
9880 atomic_read(&ac->cmd_state)));
9881 rc = adsp_err_get_lnx_err_code(
9882 atomic_read(&ac->cmd_state));
9883 goto fail_cmd;
9884 }
9885 rc = 0;
9886fail_cmd:
9887 return rc;
9888}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309889EXPORT_SYMBOL(q6asm_adjust_session_clock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309890
9891/*
9892 * q6asm_get_path_delay() - get the path delay for an audio session
9893 * @ac: audio client handle
9894 *
9895 * Retrieves the current audio DSP path delay for the given audio session.
9896 *
9897 * Return: 0 on success, error code otherwise
9898 */
9899int q6asm_get_path_delay(struct audio_client *ac)
9900{
9901 int rc = 0;
9902 struct apr_hdr hdr;
9903
9904 if (!ac || ac->apr == NULL) {
9905 pr_err("%s: invalid audio client\n", __func__);
9906 return -EINVAL;
9907 }
9908
9909 hdr.opcode = ASM_SESSION_CMD_GET_PATH_DELAY_V2;
9910 q6asm_add_hdr(ac, &hdr, sizeof(hdr), TRUE);
9911 atomic_set(&ac->cmd_state, -1);
9912
9913 rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
9914 if (rc < 0) {
9915 pr_err("%s: Commmand 0x%x failed %d\n", __func__,
9916 hdr.opcode, rc);
9917 return rc;
9918 }
9919
9920 rc = wait_event_timeout(ac->cmd_wait,
9921 (atomic_read(&ac->cmd_state) >= 0), 5 * HZ);
9922 if (!rc) {
9923 pr_err("%s: timeout. waited for response opcode[0x%x]\n",
9924 __func__, hdr.opcode);
9925 return -ETIMEDOUT;
9926 }
9927
9928 if (atomic_read(&ac->cmd_state) > 0) {
9929 pr_err("%s: DSP returned error[%s]\n",
9930 __func__, adsp_err_get_err_str(
9931 atomic_read(&ac->cmd_state)));
9932 rc = adsp_err_get_lnx_err_code(
9933 atomic_read(&ac->cmd_state));
9934 return rc;
9935 }
9936
9937 return 0;
9938}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309939EXPORT_SYMBOL(q6asm_get_path_delay);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309940
9941int q6asm_get_apr_service_id(int session_id)
9942{
9943 pr_debug("%s:\n", __func__);
9944
9945 if (session_id <= 0 || session_id > ASM_ACTIVE_STREAMS_ALLOWED) {
9946 pr_err("%s: invalid session_id = %d\n", __func__, session_id);
9947 return -EINVAL;
9948 }
9949
Meng Wang9730cdd2017-09-26 12:48:31 +08009950 return ((struct apr_svc *)(session[session_id].ac)->apr)->id;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309951}
9952
9953int q6asm_get_asm_topology(int session_id)
9954{
9955 int topology = -EINVAL;
9956
9957 if (session_id <= 0 || session_id > ASM_ACTIVE_STREAMS_ALLOWED) {
9958 pr_err("%s: invalid session_id = %d\n", __func__, session_id);
9959 goto done;
9960 }
Meng Wang9730cdd2017-09-26 12:48:31 +08009961 if (session[session_id].ac == NULL) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309962 pr_err("%s: session not created for session id = %d\n",
9963 __func__, session_id);
9964 goto done;
9965 }
Meng Wang9730cdd2017-09-26 12:48:31 +08009966 topology = (session[session_id].ac)->topology;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309967done:
9968 return topology;
9969}
9970
9971int q6asm_get_asm_app_type(int session_id)
9972{
9973 int app_type = -EINVAL;
9974
9975 if (session_id <= 0 || session_id > ASM_ACTIVE_STREAMS_ALLOWED) {
9976 pr_err("%s: invalid session_id = %d\n", __func__, session_id);
9977 goto done;
9978 }
Meng Wang9730cdd2017-09-26 12:48:31 +08009979 if (session[session_id].ac == NULL) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309980 pr_err("%s: session not created for session id = %d\n",
9981 __func__, session_id);
9982 goto done;
9983 }
Meng Wang9730cdd2017-09-26 12:48:31 +08009984 app_type = (session[session_id].ac)->app_type;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309985done:
9986 return app_type;
9987}
9988
9989static int q6asm_get_asm_topology_cal(void)
9990{
9991 int topology = DEFAULT_POPP_TOPOLOGY;
9992 struct cal_block_data *cal_block = NULL;
9993
9994 if (cal_data[ASM_TOPOLOGY_CAL] == NULL)
9995 goto done;
9996
9997 mutex_lock(&cal_data[ASM_TOPOLOGY_CAL]->lock);
9998 cal_block = cal_utils_get_only_cal_block(cal_data[ASM_TOPOLOGY_CAL]);
9999 if (cal_block == NULL)
10000 goto unlock;
10001
10002 topology = ((struct audio_cal_info_asm_top *)
10003 cal_block->cal_info)->topology;
10004unlock:
10005 mutex_unlock(&cal_data[ASM_TOPOLOGY_CAL]->lock);
10006done:
10007 pr_debug("%s: Using topology %d\n", __func__, topology);
10008 return topology;
10009}
10010
10011static int q6asm_get_asm_app_type_cal(void)
10012{
10013 int app_type = DEFAULT_APP_TYPE;
10014 struct cal_block_data *cal_block = NULL;
10015
10016 if (cal_data[ASM_TOPOLOGY_CAL] == NULL)
10017 goto done;
10018
10019 mutex_lock(&cal_data[ASM_TOPOLOGY_CAL]->lock);
10020 cal_block = cal_utils_get_only_cal_block(cal_data[ASM_TOPOLOGY_CAL]);
10021 if (cal_block == NULL)
10022 goto unlock;
10023
10024 app_type = ((struct audio_cal_info_asm_top *)
10025 cal_block->cal_info)->app_type;
10026
10027 if (app_type == 0)
10028 app_type = DEFAULT_APP_TYPE;
10029unlock:
10030 mutex_unlock(&cal_data[ASM_TOPOLOGY_CAL]->lock);
10031done:
10032 pr_debug("%s: Using app_type %d\n", __func__, app_type);
10033 return app_type;
10034}
10035
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010036/**
10037 * q6asm_send_cal -
10038 * command to send ASM calibration
10039 *
10040 * @ac: Audio client handle
10041 *
10042 * Returns 0 on success or error on failure
10043 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010044int q6asm_send_cal(struct audio_client *ac)
10045{
10046 struct cal_block_data *cal_block = NULL;
10047 struct apr_hdr hdr;
10048 char *asm_params = NULL;
10049 struct asm_stream_cmd_set_pp_params_v2 payload_params;
10050 int sz, rc = -EINVAL;
10051
10052 pr_debug("%s:\n", __func__);
10053
10054 if (!ac) {
10055 pr_err("%s: APR handle NULL\n", __func__);
10056 goto done;
10057 }
10058 if (ac->apr == NULL) {
10059 pr_err("%s: AC APR handle NULL\n", __func__);
10060 goto done;
10061 }
10062 if (ac->io_mode & NT_MODE) {
10063 pr_debug("%s: called for NT MODE, exiting\n", __func__);
10064 goto done;
10065 }
10066
10067 if (cal_data[ASM_AUDSTRM_CAL] == NULL)
10068 goto done;
10069
10070 if (ac->perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) {
10071 rc = 0; /* no cal is required, not error case */
10072 goto done;
10073 }
10074
10075 mutex_lock(&cal_data[ASM_AUDSTRM_CAL]->lock);
10076 cal_block = cal_utils_get_only_cal_block(cal_data[ASM_AUDSTRM_CAL]);
10077 if (cal_block == NULL) {
10078 pr_err("%s: cal_block is NULL\n",
10079 __func__);
10080 goto unlock;
10081 }
10082
10083 if (cal_block->cal_data.size == 0) {
10084 rc = 0; /* not error case */
10085 pr_debug("%s: cal_data.size is 0, don't send cal data\n",
10086 __func__);
10087 goto unlock;
10088 }
10089
10090 rc = remap_cal_data(ASM_AUDSTRM_CAL_TYPE, cal_block);
10091 if (rc) {
10092 pr_err("%s: Remap_cal_data failed for cal %d!\n",
10093 __func__, ASM_AUDSTRM_CAL);
10094 goto unlock;
10095 }
10096
10097 sz = sizeof(struct apr_hdr) +
10098 sizeof(struct asm_stream_cmd_set_pp_params_v2);
10099 asm_params = kzalloc(sz, GFP_KERNEL);
10100 if (!asm_params) {
10101 pr_err("%s, asm params memory alloc failed", __func__);
10102 rc = -ENOMEM;
10103 goto unlock;
10104 }
10105
10106 /* asm_stream_cmd_set_pp_params_v2 has no APR header in it */
10107 q6asm_add_hdr_async(ac, &hdr, (sizeof(struct apr_hdr) +
10108 sizeof(struct asm_stream_cmd_set_pp_params_v2)), TRUE);
10109
10110 atomic_set(&ac->cmd_state_pp, -1);
10111 hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
10112 payload_params.data_payload_addr_lsw =
10113 lower_32_bits(cal_block->cal_data.paddr);
10114 payload_params.data_payload_addr_msw =
10115 msm_audio_populate_upper_32_bits(
10116 cal_block->cal_data.paddr);
10117 payload_params.mem_map_handle = cal_block->map_data.q6map_handle;
10118 payload_params.data_payload_size = cal_block->cal_data.size;
10119 memcpy(((u8 *)asm_params), &hdr, sizeof(struct apr_hdr));
10120 memcpy(((u8 *)asm_params + sizeof(struct apr_hdr)), &payload_params,
10121 sizeof(struct asm_stream_cmd_set_pp_params_v2));
10122
10123 pr_debug("%s: phyaddr lsw = %x msw = %x, maphdl = %x calsize = %d\n",
10124 __func__, payload_params.data_payload_addr_lsw,
10125 payload_params.data_payload_addr_msw,
10126 payload_params.mem_map_handle,
10127 payload_params.data_payload_size);
10128
10129 rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params);
10130 if (rc < 0) {
10131 pr_err("%s: audio audstrm cal send failed\n", __func__);
10132 rc = -EINVAL;
10133 goto free;
10134 }
10135 rc = wait_event_timeout(ac->cmd_wait,
10136 (atomic_read(&ac->cmd_state_pp) >= 0), 5 * HZ);
10137 if (!rc) {
10138 pr_err("%s: timeout, audio audstrm cal send\n", __func__);
10139 rc = -ETIMEDOUT;
10140 goto free;
10141 }
10142 if (atomic_read(&ac->cmd_state_pp) > 0) {
10143 pr_err("%s: DSP returned error[%d] audio audstrm cal send\n",
10144 __func__, atomic_read(&ac->cmd_state_pp));
10145 rc = -EINVAL;
10146 goto free;
10147 }
10148
10149 rc = 0;
10150
10151free:
10152 kfree(asm_params);
10153unlock:
10154 mutex_unlock(&cal_data[ASM_AUDSTRM_CAL]->lock);
10155done:
10156 return rc;
10157}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010158EXPORT_SYMBOL(q6asm_send_cal);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010159
10160static int get_cal_type_index(int32_t cal_type)
10161{
10162 int ret = -EINVAL;
10163
10164 switch (cal_type) {
10165 case ASM_TOPOLOGY_CAL_TYPE:
10166 ret = ASM_TOPOLOGY_CAL;
10167 break;
10168 case ASM_CUST_TOPOLOGY_CAL_TYPE:
10169 ret = ASM_CUSTOM_TOP_CAL;
10170 break;
10171 case ASM_AUDSTRM_CAL_TYPE:
10172 ret = ASM_AUDSTRM_CAL;
10173 break;
10174 case ASM_RTAC_APR_CAL_TYPE:
10175 ret = ASM_RTAC_APR_CAL;
10176 break;
10177 default:
10178 pr_err("%s: invalid cal type %d!\n", __func__, cal_type);
10179 }
10180 return ret;
10181}
10182
10183static int q6asm_alloc_cal(int32_t cal_type,
10184 size_t data_size, void *data)
10185{
10186 int ret = 0;
10187 int cal_index;
10188
10189 pr_debug("%s:\n", __func__);
10190
10191 cal_index = get_cal_type_index(cal_type);
10192 if (cal_index < 0) {
10193 pr_err("%s: could not get cal index %d!\n",
10194 __func__, cal_index);
10195 ret = -EINVAL;
10196 goto done;
10197 }
10198
10199 ret = cal_utils_alloc_cal(data_size, data,
10200 cal_data[cal_index], 0, NULL);
10201 if (ret < 0) {
10202 pr_err("%s: cal_utils_alloc_block failed, ret = %d, cal type = %d!\n",
10203 __func__, ret, cal_type);
10204 ret = -EINVAL;
10205 goto done;
10206 }
10207done:
10208 return ret;
10209}
10210
10211static int q6asm_dealloc_cal(int32_t cal_type,
10212 size_t data_size, void *data)
10213{
10214 int ret = 0;
10215 int cal_index;
10216
10217 pr_debug("%s:\n", __func__);
10218
10219 cal_index = get_cal_type_index(cal_type);
10220 if (cal_index < 0) {
10221 pr_err("%s: could not get cal index %d!\n",
10222 __func__, cal_index);
10223 ret = -EINVAL;
10224 goto done;
10225 }
10226
10227 ret = cal_utils_dealloc_cal(data_size, data,
10228 cal_data[cal_index]);
10229 if (ret < 0) {
10230 pr_err("%s: cal_utils_dealloc_block failed, ret = %d, cal type = %d!\n",
10231 __func__, ret, cal_type);
10232 ret = -EINVAL;
10233 goto done;
10234 }
10235done:
10236 return ret;
10237}
10238
10239static int q6asm_set_cal(int32_t cal_type,
10240 size_t data_size, void *data)
10241{
10242 int ret = 0;
10243 int cal_index;
10244
10245 pr_debug("%s:\n", __func__);
10246
10247 cal_index = get_cal_type_index(cal_type);
10248 if (cal_index < 0) {
10249 pr_err("%s: could not get cal index %d!\n",
10250 __func__, cal_index);
10251 ret = -EINVAL;
10252 goto done;
10253 }
10254
10255 ret = cal_utils_set_cal(data_size, data,
10256 cal_data[cal_index], 0, NULL);
10257 if (ret < 0) {
10258 pr_err("%s: cal_utils_set_cal failed, ret = %d, cal type = %d!\n",
10259 __func__, ret, cal_type);
10260 ret = -EINVAL;
10261 goto done;
10262 }
10263
10264 if (cal_index == ASM_CUSTOM_TOP_CAL) {
10265 mutex_lock(&cal_data[ASM_CUSTOM_TOP_CAL]->lock);
10266 set_custom_topology = 1;
10267 mutex_unlock(&cal_data[ASM_CUSTOM_TOP_CAL]->lock);
10268 }
10269done:
10270 return ret;
10271}
10272
10273static void q6asm_delete_cal_data(void)
10274{
10275 pr_debug("%s:\n", __func__);
10276 cal_utils_destroy_cal_types(ASM_MAX_CAL_TYPES, cal_data);
10277}
10278
10279static int q6asm_init_cal_data(void)
10280{
10281 int ret = 0;
10282 struct cal_type_info cal_type_info[] = {
10283 {{ASM_TOPOLOGY_CAL_TYPE,
10284 {NULL, NULL, NULL,
10285 q6asm_set_cal, NULL, NULL} },
10286 {NULL, NULL, cal_utils_match_buf_num} },
10287
10288 {{ASM_CUST_TOPOLOGY_CAL_TYPE,
10289 {q6asm_alloc_cal, q6asm_dealloc_cal, NULL,
10290 q6asm_set_cal, NULL, NULL} },
10291 {NULL, q6asm_unmap_cal_memory, cal_utils_match_buf_num} },
10292
10293 {{ASM_AUDSTRM_CAL_TYPE,
10294 {q6asm_alloc_cal, q6asm_dealloc_cal, NULL,
10295 q6asm_set_cal, NULL, NULL} },
10296 {NULL, q6asm_unmap_cal_memory, cal_utils_match_buf_num} },
10297
10298 {{ASM_RTAC_APR_CAL_TYPE,
10299 {NULL, NULL, NULL, NULL, NULL, NULL} },
10300 {NULL, NULL, cal_utils_match_buf_num} }
10301 };
10302 pr_debug("%s\n", __func__);
10303
10304 ret = cal_utils_create_cal_types(ASM_MAX_CAL_TYPES, cal_data,
10305 cal_type_info);
10306 if (ret < 0) {
10307 pr_err("%s: could not create cal type! %d\n",
10308 __func__, ret);
10309 ret = -EINVAL;
10310 goto err;
10311 }
10312
10313 return ret;
10314err:
10315 q6asm_delete_cal_data();
10316 return ret;
10317}
10318
10319static int q6asm_is_valid_session(struct apr_client_data *data, void *priv)
10320{
10321 struct audio_client *ac = (struct audio_client *)priv;
10322 union asm_token_struct asm_token;
10323
10324 asm_token.token = data->token;
10325 if (asm_token._token.session_id != ac->session) {
10326 pr_err("%s: Invalid session[%d] rxed expected[%d]",
10327 __func__, asm_token._token.session_id, ac->session);
10328 return -EINVAL;
10329 }
10330 return 0;
10331}
10332
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010333int __init q6asm_init(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010334{
10335 int lcnt, ret;
10336
10337 pr_debug("%s:\n", __func__);
10338
Meng Wang9730cdd2017-09-26 12:48:31 +080010339 memset(session, 0, sizeof(struct audio_session) *
10340 (ASM_ACTIVE_STREAMS_ALLOWED + 1));
10341 for (lcnt = 0; lcnt <= ASM_ACTIVE_STREAMS_ALLOWED; lcnt++)
10342 spin_lock_init(&(session[lcnt].session_lock));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010343 set_custom_topology = 1;
10344
10345 /*setup common client used for cal mem map */
10346 common_client.session = ASM_CONTROL_SESSION;
10347 common_client.port[0].buf = &common_buf[0];
10348 common_client.port[1].buf = &common_buf[1];
10349 init_waitqueue_head(&common_client.cmd_wait);
10350 init_waitqueue_head(&common_client.time_wait);
10351 init_waitqueue_head(&common_client.mem_wait);
10352 atomic_set(&common_client.time_flag, 1);
10353 INIT_LIST_HEAD(&common_client.port[0].mem_map_handle);
10354 INIT_LIST_HEAD(&common_client.port[1].mem_map_handle);
10355 mutex_init(&common_client.cmd_lock);
10356 for (lcnt = 0; lcnt <= OUT; lcnt++) {
10357 mutex_init(&common_client.port[lcnt].lock);
10358 spin_lock_init(&common_client.port[lcnt].dsp_lock);
10359 }
10360 atomic_set(&common_client.cmd_state, 0);
10361 atomic_set(&common_client.mem_state, 0);
10362
10363 ret = q6asm_init_cal_data();
10364 if (ret)
10365 pr_err("%s: could not init cal data! ret %d\n",
10366 __func__, ret);
10367
10368 config_debug_fs_init();
10369
10370 return 0;
10371}
10372
Asish Bhattacharya5faacb32017-12-04 17:23:15 +053010373void q6asm_exit(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010374{
10375 q6asm_delete_cal_data();
10376}