blob: 80aa2a6bbdb75dbb47f22a0bd9612c0bd05a67a4 [file] [log] [blame]
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301/*
Sidipotu Ashok5c6855b2019-01-08 15:58:37 +05302 * Copyright (c) 2012-2019, 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>
Dhanalakshmi Siddaniff8d0d92019-12-05 15:20:23 +053042#include <dsp/q6core.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053043#include "adsp_err.h"
44
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053045#define TRUE 0x01
46#define FALSE 0x00
47#define SESSION_MAX 8
48
49enum {
50 ASM_TOPOLOGY_CAL = 0,
51 ASM_CUSTOM_TOP_CAL,
52 ASM_AUDSTRM_CAL,
53 ASM_RTAC_APR_CAL,
54 ASM_MAX_CAL_TYPES
55};
56
57union asm_token_struct {
58 struct {
59 u8 stream_id;
60 u8 session_id;
61 u8 buf_index;
62 u8 flags;
63 } _token;
64 u32 token;
65} __packed;
66
67
68enum {
69 ASM_DIRECTION_OFFSET,
70 ASM_CMD_NO_WAIT_OFFSET,
71 /*
72 * Offset is limited to 7 because flags is stored in u8
73 * field in asm_token_structure defined above. The offset
74 * starts from 0.
75 */
76 ASM_MAX_OFFSET = 7,
77};
78
79enum {
80 WAIT_CMD,
81 NO_WAIT_CMD
82};
83
84#define ASM_SET_BIT(n, x) (n |= 1 << x)
85#define ASM_TEST_BIT(n, x) ((n >> x) & 1)
86
87/* TODO, combine them together */
88static DEFINE_MUTEX(session_lock);
89struct asm_mmap {
90 atomic_t ref_cnt;
91 void *apr;
92};
93
94static struct asm_mmap this_mmap;
Meng Wang9730cdd2017-09-26 12:48:31 +080095
96struct audio_session {
97 struct audio_client *ac;
98 spinlock_t session_lock;
Xiaojun Sanga4648082018-04-27 14:57:33 +080099 struct mutex mutex_lock_per_session;
Meng Wang9730cdd2017-09-26 12:48:31 +0800100};
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530101/* session id: 0 reserved */
Meng Wang9730cdd2017-09-26 12:48:31 +0800102static struct audio_session session[ASM_ACTIVE_STREAMS_ALLOWED + 1];
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530103
104struct asm_buffer_node {
105 struct list_head list;
106 phys_addr_t buf_phys_addr;
107 uint32_t mmap_hdl;
108};
109static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv);
110static int32_t q6asm_callback(struct apr_client_data *data, void *priv);
111static void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
112 uint32_t pkt_size, uint32_t cmd_flg);
113static void q6asm_add_hdr_custom_topology(struct audio_client *ac,
114 struct apr_hdr *hdr,
115 uint32_t pkt_size);
116static void q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
117 uint32_t pkt_size, uint32_t cmd_flg);
118static int q6asm_memory_map_regions(struct audio_client *ac, int dir,
119 uint32_t bufsz, uint32_t bufcnt,
120 bool is_contiguous);
121static int q6asm_memory_unmap_regions(struct audio_client *ac, int dir);
122static void q6asm_reset_buf_state(struct audio_client *ac);
123
124static int q6asm_map_channels(u8 *channel_mapping, uint32_t channels,
125 bool use_back_flavor);
126void *q6asm_mmap_apr_reg(void);
127
128static int q6asm_is_valid_session(struct apr_client_data *data, void *priv);
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -0700129static int q6asm_get_asm_topology_apptype(struct q6asm_cal_info *cal_info);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530130
131/* for ASM custom topology */
132static struct cal_type_data *cal_data[ASM_MAX_CAL_TYPES];
133static struct audio_buffer common_buf[2];
134static struct audio_client common_client;
135static int set_custom_topology;
136static int topology_map_handle;
137
138struct generic_get_data_ {
139 int valid;
140 int is_inband;
141 int size_in_ints;
142 int ints[];
143};
144static struct generic_get_data_ *generic_get_data;
145
146#ifdef CONFIG_DEBUG_FS
147#define OUT_BUFFER_SIZE 56
148#define IN_BUFFER_SIZE 24
149
150static struct timeval out_cold_tv;
151static struct timeval out_warm_tv;
152static struct timeval out_cont_tv;
153static struct timeval in_cont_tv;
154static long out_enable_flag;
155static long in_enable_flag;
156static struct dentry *out_dentry;
157static struct dentry *in_dentry;
158static int in_cont_index;
159/*This var is used to keep track of first write done for cold output latency */
160static int out_cold_index;
161static char *out_buffer;
162static char *in_buffer;
163
164static uint32_t adsp_reg_event_opcode[] = {
165 ASM_STREAM_CMD_REGISTER_PP_EVENTS,
166 ASM_STREAM_CMD_REGISTER_ENCDEC_EVENTS,
167 ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE };
168
169static uint32_t adsp_raise_event_opcode[] = {
170 ASM_STREAM_PP_EVENT,
171 ASM_STREAM_CMD_ENCDEC_EVENTS,
172 ASM_IEC_61937_MEDIA_FMT_EVENT };
173
174static int is_adsp_reg_event(uint32_t cmd)
175{
176 int i;
177
178 for (i = 0; i < ARRAY_SIZE(adsp_reg_event_opcode); i++) {
179 if (cmd == adsp_reg_event_opcode[i])
180 return i;
181 }
182 return -EINVAL;
183}
184
185static int is_adsp_raise_event(uint32_t cmd)
186{
187 int i;
188
189 for (i = 0; i < ARRAY_SIZE(adsp_raise_event_opcode); i++) {
190 if (cmd == adsp_raise_event_opcode[i])
191 return i;
192 }
193 return -EINVAL;
194}
195
196static inline void q6asm_set_flag_in_token(union asm_token_struct *asm_token,
197 int flag, int flag_offset)
198{
199 if (flag)
200 ASM_SET_BIT(asm_token->_token.flags, flag_offset);
201}
202
203static inline int q6asm_get_flag_from_token(union asm_token_struct *asm_token,
204 int flag_offset)
205{
206 return ASM_TEST_BIT(asm_token->_token.flags, flag_offset);
207}
208
209static inline void q6asm_update_token(u32 *token, u8 session_id, u8 stream_id,
210 u8 buf_index, u8 dir, u8 nowait_flag)
211{
212 union asm_token_struct asm_token;
213
214 asm_token.token = 0;
215 asm_token._token.session_id = session_id;
216 asm_token._token.stream_id = stream_id;
217 asm_token._token.buf_index = buf_index;
218 q6asm_set_flag_in_token(&asm_token, dir, ASM_DIRECTION_OFFSET);
219 q6asm_set_flag_in_token(&asm_token, nowait_flag,
220 ASM_CMD_NO_WAIT_OFFSET);
221 *token = asm_token.token;
222}
223
224static inline uint32_t q6asm_get_pcm_format_id(uint32_t media_format_block_ver)
225{
226 uint32_t pcm_format_id;
227
228 switch (media_format_block_ver) {
Dhanalakshmi Siddaniff8d0d92019-12-05 15:20:23 +0530229 case PCM_MEDIA_FORMAT_V5:
230 pcm_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V5;
231 break;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530232 case PCM_MEDIA_FORMAT_V4:
233 pcm_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V4;
234 break;
235 case PCM_MEDIA_FORMAT_V3:
236 pcm_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3;
237 break;
238 case PCM_MEDIA_FORMAT_V2:
239 default:
240 pcm_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
241 break;
242 }
243 return pcm_format_id;
244}
245
246/*
247 * q6asm_get_buf_index_from_token:
248 * Retrieve buffer index from token.
249 *
250 * @token: token value sent to ASM service on q6.
251 * Returns buffer index in the read/write commands.
252 */
253uint8_t q6asm_get_buf_index_from_token(uint32_t token)
254{
255 union asm_token_struct asm_token;
256
257 asm_token.token = token;
258 return asm_token._token.buf_index;
259}
260EXPORT_SYMBOL(q6asm_get_buf_index_from_token);
261
262/*
263 * q6asm_get_stream_id_from_token:
264 * Retrieve stream id from token.
265 *
266 * @token: token value sent to ASM service on q6.
267 * Returns stream id.
268 */
269uint8_t q6asm_get_stream_id_from_token(uint32_t token)
270{
271 union asm_token_struct asm_token;
272
273 asm_token.token = token;
274 return asm_token._token.stream_id;
275}
276EXPORT_SYMBOL(q6asm_get_stream_id_from_token);
277
278static int audio_output_latency_dbgfs_open(struct inode *inode,
279 struct file *file)
280{
281 file->private_data = inode->i_private;
282 return 0;
283}
284static ssize_t audio_output_latency_dbgfs_read(struct file *file,
285 char __user *buf, size_t count, loff_t *ppos)
286{
287 if (out_buffer == NULL) {
288 pr_err("%s: out_buffer is null\n", __func__);
289 return 0;
290 }
Karthikeyan Mani1dfff342018-02-15 17:46:25 -0800291 if (count < OUT_BUFFER_SIZE) {
292 pr_err("%s: read size %d exceeds buf size %zd\n", __func__,
293 OUT_BUFFER_SIZE, count);
294 return 0;
295 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530296 snprintf(out_buffer, OUT_BUFFER_SIZE, "%ld,%ld,%ld,%ld,%ld,%ld,",
297 out_cold_tv.tv_sec, out_cold_tv.tv_usec, out_warm_tv.tv_sec,
298 out_warm_tv.tv_usec, out_cont_tv.tv_sec, out_cont_tv.tv_usec);
299 return simple_read_from_buffer(buf, OUT_BUFFER_SIZE, ppos,
300 out_buffer, OUT_BUFFER_SIZE);
301}
302static ssize_t audio_output_latency_dbgfs_write(struct file *file,
303 const char __user *buf, size_t count, loff_t *ppos)
304{
305 char *temp;
306
307 if (count > 2*sizeof(char)) {
308 pr_err("%s: err count is more %zd\n", __func__, count);
309 return -EINVAL;
310 }
311 temp = kmalloc(2*sizeof(char), GFP_KERNEL);
312
313 out_cold_index = 0;
314
315 if (temp) {
316 if (copy_from_user(temp, buf, 2*sizeof(char))) {
317 pr_err("%s: copy from user failed for size %zd\n",
318 __func__, 2*sizeof(char));
319 kfree(temp);
320 return -EFAULT;
321 }
322 if (!kstrtol(temp, 10, &out_enable_flag)) {
323 kfree(temp);
324 return count;
325 }
326 kfree(temp);
327 }
328 return -EINVAL;
329}
330static const struct file_operations audio_output_latency_debug_fops = {
331 .open = audio_output_latency_dbgfs_open,
332 .read = audio_output_latency_dbgfs_read,
333 .write = audio_output_latency_dbgfs_write
334};
335static int audio_input_latency_dbgfs_open(struct inode *inode,
336 struct file *file)
337{
338 file->private_data = inode->i_private;
339 return 0;
340}
341static ssize_t audio_input_latency_dbgfs_read(struct file *file,
342 char __user *buf, size_t count, loff_t *ppos)
343{
344 if (in_buffer == NULL) {
345 pr_err("%s: in_buffer is null\n", __func__);
346 return 0;
347 }
Karthikeyan Mani1dfff342018-02-15 17:46:25 -0800348 if (count < IN_BUFFER_SIZE) {
349 pr_err("%s: read size %d exceeds buf size %zd\n", __func__,
350 IN_BUFFER_SIZE, count);
351 return 0;
352 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530353 snprintf(in_buffer, IN_BUFFER_SIZE, "%ld,%ld,",
354 in_cont_tv.tv_sec, in_cont_tv.tv_usec);
355 return simple_read_from_buffer(buf, IN_BUFFER_SIZE, ppos,
356 in_buffer, IN_BUFFER_SIZE);
357}
358static ssize_t audio_input_latency_dbgfs_write(struct file *file,
359 const char __user *buf, size_t count, loff_t *ppos)
360{
361 char *temp;
362
363 if (count > 2*sizeof(char)) {
364 pr_err("%s: err count is more %zd\n", __func__, count);
365 return -EINVAL;
366 }
367 temp = kmalloc(2*sizeof(char), GFP_KERNEL);
368
369 if (temp) {
370 if (copy_from_user(temp, buf, 2*sizeof(char))) {
371 pr_err("%s: copy from user failed for size %zd\n",
372 __func__, 2*sizeof(char));
373 kfree(temp);
374 return -EFAULT;
375 }
376 if (!kstrtol(temp, 10, &in_enable_flag)) {
377 kfree(temp);
378 return count;
379 }
380 kfree(temp);
381 }
382 return -EINVAL;
383}
384static const struct file_operations audio_input_latency_debug_fops = {
385 .open = audio_input_latency_dbgfs_open,
386 .read = audio_input_latency_dbgfs_read,
387 .write = audio_input_latency_dbgfs_write
388};
389
390static void config_debug_fs_write_cb(void)
391{
392 if (out_enable_flag) {
393 /* For first Write done log the time and reset
394 * out_cold_index
395 */
396 if (out_cold_index != 1) {
397 do_gettimeofday(&out_cold_tv);
398 pr_debug("COLD: apr_send_pkt at %ld sec %ld microsec\n",
399 out_cold_tv.tv_sec,
400 out_cold_tv.tv_usec);
401 out_cold_index = 1;
402 }
403 pr_debug("%s: out_enable_flag %ld\n",
404 __func__, out_enable_flag);
405 }
406}
407static void config_debug_fs_read_cb(void)
408{
409 if (in_enable_flag) {
410 /* when in_cont_index == 7, DSP would be
411 * writing into the 8th 512 byte buffer and this
412 * timestamp is tapped here.Once done it then writes
413 * to 9th 512 byte buffer.These two buffers(8th, 9th)
414 * reach the test application in 5th iteration and that
415 * timestamp is tapped at user level. The difference
416 * of these two timestamps gives us the time between
417 * the time at which dsp started filling the sample
418 * required and when it reached the test application.
419 * Hence continuous input latency
420 */
421 if (in_cont_index == 7) {
422 do_gettimeofday(&in_cont_tv);
423 pr_info("%s: read buffer at %ld sec %ld microsec\n",
424 __func__,
425 in_cont_tv.tv_sec, in_cont_tv.tv_usec);
426 }
427 in_cont_index++;
428 }
429}
430
431static void config_debug_fs_reset_index(void)
432{
433 in_cont_index = 0;
434}
435
436static void config_debug_fs_run(void)
437{
438 if (out_enable_flag) {
439 do_gettimeofday(&out_cold_tv);
440 pr_debug("%s: COLD apr_send_pkt at %ld sec %ld microsec\n",
441 __func__, out_cold_tv.tv_sec, out_cold_tv.tv_usec);
442 }
443}
444
445static void config_debug_fs_write(struct audio_buffer *ab)
446{
447 if (out_enable_flag) {
448 char zero_pattern[2] = {0x00, 0x00};
449 /* If First two byte is non zero and last two byte
450 * is zero then it is warm output pattern
451 */
452 if ((strcmp(((char *)ab->data), zero_pattern)) &&
453 (!strcmp(((char *)ab->data + 2), zero_pattern))) {
454 do_gettimeofday(&out_warm_tv);
455 pr_debug("%s: WARM:apr_send_pkt at %ld sec %ld microsec\n",
456 __func__,
457 out_warm_tv.tv_sec,
458 out_warm_tv.tv_usec);
459 pr_debug("%s: Warm Pattern Matched\n", __func__);
460 }
461 /* If First two byte is zero and last two byte is
462 * non zero then it is cont output pattern
463 */
464 else if ((!strcmp(((char *)ab->data), zero_pattern))
465 && (strcmp(((char *)ab->data + 2), zero_pattern))) {
466 do_gettimeofday(&out_cont_tv);
467 pr_debug("%s: CONT:apr_send_pkt at %ld sec %ld microsec\n",
468 __func__,
469 out_cont_tv.tv_sec,
470 out_cont_tv.tv_usec);
471 pr_debug("%s: Cont Pattern Matched\n", __func__);
472 }
473 }
474}
475static void config_debug_fs_init(void)
476{
477 out_buffer = kzalloc(OUT_BUFFER_SIZE, GFP_KERNEL);
478 if (out_buffer == NULL)
479 goto outbuf_fail;
480
481 in_buffer = kzalloc(IN_BUFFER_SIZE, GFP_KERNEL);
482 if (in_buffer == NULL)
483 goto inbuf_fail;
484
485 out_dentry = debugfs_create_file("audio_out_latency_measurement_node",
486 0664,
487 NULL, NULL, &audio_output_latency_debug_fops);
488 if (IS_ERR(out_dentry)) {
489 pr_err("%s: debugfs_create_file failed\n", __func__);
490 goto file_fail;
491 }
492 in_dentry = debugfs_create_file("audio_in_latency_measurement_node",
493 0664,
494 NULL, NULL, &audio_input_latency_debug_fops);
495 if (IS_ERR(in_dentry)) {
496 pr_err("%s: debugfs_create_file failed\n", __func__);
497 goto file_fail;
498 }
499 return;
500file_fail:
501 kfree(in_buffer);
502inbuf_fail:
503 kfree(out_buffer);
504outbuf_fail:
505 in_buffer = NULL;
506 out_buffer = NULL;
507}
508#else
509static void config_debug_fs_write(struct audio_buffer *ab)
510{
511}
512static void config_debug_fs_run(void)
513{
514}
515static void config_debug_fs_reset_index(void)
516{
517}
518static void config_debug_fs_read_cb(void)
519{
520}
521static void config_debug_fs_write_cb(void)
522{
523}
524static void config_debug_fs_init(void)
525{
526}
527#endif
528
529int q6asm_mmap_apr_dereg(void)
530{
531 int c;
532
533 c = atomic_sub_return(1, &this_mmap.ref_cnt);
534 if (c == 0) {
535 apr_deregister(this_mmap.apr);
536 common_client.mmap_apr = NULL;
537 pr_debug("%s: APR De-Register common port\n", __func__);
538 } else if (c < 0) {
539 pr_err("%s: APR Common Port Already Closed %d\n",
540 __func__, c);
541 atomic_set(&this_mmap.ref_cnt, 0);
542 }
543
544 return 0;
545}
546
547static int q6asm_session_alloc(struct audio_client *ac)
548{
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)) {
553 session[n].ac = ac;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530554 return n;
555 }
556 }
557 pr_err("%s: session not available\n", __func__);
558 return -ENOMEM;
559}
560
Meng Wang9730cdd2017-09-26 12:48:31 +0800561static int q6asm_get_session_id_from_audio_client(struct audio_client *ac)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530562{
563 int n;
564
565 for (n = 1; n <= ASM_ACTIVE_STREAMS_ALLOWED; n++) {
Meng Wang9730cdd2017-09-26 12:48:31 +0800566 if (session[n].ac == ac)
567 return n;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530568 }
Xiaojun Sanga4648082018-04-27 14:57:33 +0800569 pr_debug("%s: cannot find matching audio client. ac = %pK\n",
570 __func__, ac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530571 return 0;
572}
573
Meng Wang9730cdd2017-09-26 12:48:31 +0800574static bool q6asm_is_valid_audio_client(struct audio_client *ac)
575{
576 return q6asm_get_session_id_from_audio_client(ac) ? 1 : 0;
577}
578
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530579static void q6asm_session_free(struct audio_client *ac)
580{
Meng Wang9730cdd2017-09-26 12:48:31 +0800581 int session_id;
Vignesh Kulothungan023a5322018-06-21 11:13:29 -0700582 unsigned long flags = 0;
Meng Wang9730cdd2017-09-26 12:48:31 +0800583
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530584 pr_debug("%s: sessionid[%d]\n", __func__, ac->session);
Meng Wang9730cdd2017-09-26 12:48:31 +0800585 session_id = ac->session;
Xiaojun Sanga4648082018-04-27 14:57:33 +0800586 mutex_lock(&session[session_id].mutex_lock_per_session);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530587 rtac_remove_popp_from_adm_devices(ac->session);
Meng Wangb6afa8c2017-11-30 17:55:05 +0800588 spin_lock_irqsave(&(session[session_id].session_lock), flags);
Meng Wang9730cdd2017-09-26 12:48:31 +0800589 session[ac->session].ac = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530590 ac->session = 0;
591 ac->perf_mode = LEGACY_PCM_MODE;
592 ac->fptr_cache_ops = NULL;
Meng Wang9730cdd2017-09-26 12:48:31 +0800593 ac->cb = NULL;
594 ac->priv = NULL;
595 kfree(ac);
596 ac = NULL;
Meng Wangb6afa8c2017-11-30 17:55:05 +0800597 spin_unlock_irqrestore(&(session[session_id].session_lock), flags);
Xiaojun Sanga4648082018-04-27 14:57:33 +0800598 mutex_unlock(&session[session_id].mutex_lock_per_session);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530599}
600
601static uint32_t q6asm_get_next_buf(struct audio_client *ac,
602 uint32_t curr_buf, uint32_t max_buf_cnt)
603{
604 dev_vdbg(ac->dev, "%s: curr_buf = %d, max_buf_cnt = %d\n",
605 __func__, curr_buf, max_buf_cnt);
606 curr_buf += 1;
607 return (curr_buf >= max_buf_cnt) ? 0 : curr_buf;
608}
609
610static int q6asm_map_cal_memory(int32_t cal_type,
611 struct cal_block_data *cal_block)
612{
613 int result = 0;
614 struct asm_buffer_node *buf_node = NULL;
615 struct list_head *ptr, *next;
616
617 if (cal_block == NULL) {
618 pr_err("%s: cal_block is NULL!\n",
619 __func__);
620 goto done;
621 }
622
623 if (cal_block->cal_data.paddr == 0) {
624 pr_debug("%s: No address to map!\n",
625 __func__);
626 goto done;
627 }
628
629 common_client.mmap_apr = q6asm_mmap_apr_reg();
630 if (common_client.mmap_apr == NULL) {
631 pr_err("%s: q6asm_mmap_apr_reg failed\n",
632 __func__);
633 result = -EPERM;
634 goto done;
635 }
636 common_client.apr = common_client.mmap_apr;
637 if (cal_block->map_data.map_size == 0) {
638 pr_debug("%s: map size is 0!\n",
639 __func__);
640 goto done;
641 }
642
643 /* Use second asm buf to map memory */
644 if (common_client.port[IN].buf == NULL) {
645 pr_err("%s: common buf is NULL\n",
646 __func__);
647 result = -EINVAL;
648 goto done;
649 }
650
651 common_client.port[IN].buf->phys = cal_block->cal_data.paddr;
652
653 result = q6asm_memory_map_regions(&common_client,
654 IN, cal_block->map_data.map_size, 1, 1);
655 if (result < 0) {
656 pr_err("%s: mmap did not work! size = %zd result %d\n",
657 __func__,
658 cal_block->map_data.map_size, result);
659 pr_debug("%s: mmap did not work! addr = 0x%pK, size = %zd\n",
660 __func__,
661 &cal_block->cal_data.paddr,
662 cal_block->map_data.map_size);
663 goto done;
664 }
665
666 list_for_each_safe(ptr, next,
667 &common_client.port[IN].mem_map_handle) {
668 buf_node = list_entry(ptr, struct asm_buffer_node,
669 list);
670 if (buf_node->buf_phys_addr == cal_block->cal_data.paddr) {
671 cal_block->map_data.q6map_handle = buf_node->mmap_hdl;
672 break;
673 }
674 }
675done:
676 return result;
677}
678
679static int remap_cal_data(int32_t cal_type, struct cal_block_data *cal_block)
680{
681 int ret = 0;
682
683 if (cal_block->map_data.ion_client == NULL) {
684 pr_err("%s: No ION allocation for cal type %d!\n",
685 __func__, cal_type);
686 ret = -EINVAL;
687 goto done;
688 }
689
690 if ((cal_block->map_data.map_size > 0) &&
691 (cal_block->map_data.q6map_handle == 0)) {
692
693 ret = q6asm_map_cal_memory(cal_type, cal_block);
694 if (ret < 0) {
695 pr_err("%s: mmap did not work! size = %zd ret %d\n",
696 __func__, cal_block->map_data.map_size, ret);
697 goto done;
698 }
699 }
700done:
701 return ret;
702}
703
704static int q6asm_unmap_cal_memory(int32_t cal_type,
705 struct cal_block_data *cal_block)
706{
707 int result = 0;
708 int result2 = 0;
709
710 if (cal_block == NULL) {
711 pr_err("%s: cal_block is NULL!\n",
712 __func__);
713 result = -EINVAL;
714 goto done;
715 }
716
717 if (cal_block->map_data.q6map_handle == 0) {
718 pr_debug("%s: No address to unmap!\n",
719 __func__);
720 result = -EINVAL;
721 goto done;
722 }
723
724 if (common_client.mmap_apr == NULL) {
725 common_client.mmap_apr = q6asm_mmap_apr_reg();
726 if (common_client.mmap_apr == NULL) {
727 pr_err("%s: q6asm_mmap_apr_reg failed\n",
728 __func__);
729 result = -EPERM;
730 goto done;
731 }
732 }
733
734 result2 = q6asm_memory_unmap_regions(&common_client, IN);
735 if (result2 < 0) {
736 pr_err("%s: unmap failed, err %d\n",
737 __func__, result2);
738 result = result2;
739 }
740
741 cal_block->map_data.q6map_handle = 0;
742done:
743 return result;
744}
745
746int q6asm_unmap_cal_data(int cal_type, struct cal_block_data *cal_block)
747{
748 int ret = 0;
749
750 if ((cal_block->map_data.map_size > 0) &&
751 (cal_block->map_data.q6map_handle != 0)) {
752
753 ret = q6asm_unmap_cal_memory(cal_type, cal_block);
754 if (ret < 0) {
755 pr_err("%s: unmap did not work! size = %zd ret %d\n",
756 __func__, cal_block->map_data.map_size, ret);
757 goto done;
758 }
759 }
760done:
761 return ret;
762}
763
764int send_asm_custom_topology(struct audio_client *ac)
765{
766 struct cal_block_data *cal_block = NULL;
767 struct cmd_set_topologies asm_top;
768 int result = 0;
769 int result1 = 0;
770
771 if (cal_data[ASM_CUSTOM_TOP_CAL] == NULL)
772 goto done;
773
774 mutex_lock(&cal_data[ASM_CUSTOM_TOP_CAL]->lock);
775 if (!set_custom_topology)
776 goto unlock;
777 set_custom_topology = 0;
778
779 cal_block = cal_utils_get_only_cal_block(cal_data[ASM_CUSTOM_TOP_CAL]);
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -0700780 if (cal_block == NULL || cal_utils_is_cal_stale(cal_block))
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530781 goto unlock;
782
783 if (cal_block->cal_data.size == 0) {
784 pr_debug("%s: No cal to send!\n", __func__);
785 goto unlock;
786 }
787
788 pr_debug("%s: Sending cal_index %d\n", __func__, ASM_CUSTOM_TOP_CAL);
789
790 result = remap_cal_data(ASM_CUST_TOPOLOGY_CAL_TYPE, cal_block);
791 if (result) {
792 pr_err("%s: Remap_cal_data failed for cal %d!\n",
793 __func__, ASM_CUSTOM_TOP_CAL);
794 goto unlock;
795 }
796
797 q6asm_add_hdr_custom_topology(ac, &asm_top.hdr, sizeof(asm_top));
798 atomic_set(&ac->mem_state, -1);
799 asm_top.hdr.opcode = ASM_CMD_ADD_TOPOLOGIES;
800 asm_top.payload_addr_lsw = lower_32_bits(cal_block->cal_data.paddr);
801 asm_top.payload_addr_msw = msm_audio_populate_upper_32_bits(
802 cal_block->cal_data.paddr);
803 asm_top.mem_map_handle = cal_block->map_data.q6map_handle;
804 asm_top.payload_size = cal_block->cal_data.size;
805
806 pr_debug("%s: Sending ASM_CMD_ADD_TOPOLOGIES payload = %pK, size = %d, map handle = 0x%x\n",
807 __func__, &cal_block->cal_data.paddr,
808 asm_top.payload_size, asm_top.mem_map_handle);
809
810 result = apr_send_pkt(ac->apr, (uint32_t *) &asm_top);
811 if (result < 0) {
812 pr_err("%s: Set topologies failed result %d\n",
813 __func__, result);
814 pr_debug("%s: Set topologies failed payload = 0x%pK\n",
815 __func__, &cal_block->cal_data.paddr);
816 goto unmap;
817
818 }
819
820 result = wait_event_timeout(ac->mem_wait,
821 (atomic_read(&ac->mem_state) >= 0), 5*HZ);
822 if (!result) {
823 pr_err("%s: Set topologies failed timeout\n", __func__);
824 pr_debug("%s: Set topologies failed after timedout payload = 0x%pK\n",
825 __func__, &cal_block->cal_data.paddr);
826 result = -ETIMEDOUT;
827 goto unmap;
828 }
829 if (atomic_read(&ac->mem_state) > 0) {
830 pr_err("%s: DSP returned error[%s]\n",
831 __func__, adsp_err_get_err_str(
832 atomic_read(&ac->mem_state)));
833 result = adsp_err_get_lnx_err_code(
834 atomic_read(&ac->mem_state));
835 goto unmap;
836 }
837
838unmap:
839 result1 = q6asm_unmap_cal_memory(ASM_CUST_TOPOLOGY_CAL_TYPE,
840 cal_block);
841 if (result1 < 0) {
842 result = result1;
843 pr_debug("%s: unmap cal failed! %d\n", __func__, result);
844 }
845unlock:
846 mutex_unlock(&cal_data[ASM_CUSTOM_TOP_CAL]->lock);
847done:
848 return result;
849}
850
851int q6asm_map_rtac_block(struct rtac_cal_block_data *cal_block)
852{
853 int result = 0;
854 struct asm_buffer_node *buf_node = NULL;
855 struct list_head *ptr, *next;
856
857 pr_debug("%s:\n", __func__);
858
859 if (cal_block == NULL) {
860 pr_err("%s: cal_block is NULL!\n",
861 __func__);
862 result = -EINVAL;
863 goto done;
864 }
865
866 if (cal_block->cal_data.paddr == 0) {
867 pr_debug("%s: No address to map!\n",
868 __func__);
869 result = -EINVAL;
870 goto done;
871 }
872
873 if (common_client.mmap_apr == NULL) {
874 common_client.mmap_apr = q6asm_mmap_apr_reg();
875 if (common_client.mmap_apr == NULL) {
876 pr_err("%s: q6asm_mmap_apr_reg failed\n",
877 __func__);
878 result = -EPERM;
879 goto done;
880 }
881 }
882
883 if (cal_block->map_data.map_size == 0) {
884 pr_debug("%s: map size is 0!\n",
885 __func__);
886 result = -EINVAL;
887 goto done;
888 }
889
890 /* Use second asm buf to map memory */
891 if (common_client.port[OUT].buf == NULL) {
892 pr_err("%s: common buf is NULL\n",
893 __func__);
894 result = -EINVAL;
895 goto done;
896 }
897
898 common_client.port[OUT].buf->phys = cal_block->cal_data.paddr;
899
900 result = q6asm_memory_map_regions(&common_client,
901 OUT, cal_block->map_data.map_size, 1, 1);
902 if (result < 0) {
903 pr_err("%s: mmap did not work! size = %d result %d\n",
904 __func__,
905 cal_block->map_data.map_size, result);
906 pr_debug("%s: mmap did not work! addr = 0x%pK, size = %d\n",
907 __func__,
908 &cal_block->cal_data.paddr,
909 cal_block->map_data.map_size);
910 goto done;
911 }
912
913 list_for_each_safe(ptr, next,
914 &common_client.port[OUT].mem_map_handle) {
915 buf_node = list_entry(ptr, struct asm_buffer_node,
916 list);
917 if (buf_node->buf_phys_addr == cal_block->cal_data.paddr) {
918 cal_block->map_data.map_handle = buf_node->mmap_hdl;
919 break;
920 }
921 }
922done:
923 return result;
924}
925
926int q6asm_unmap_rtac_block(uint32_t *mem_map_handle)
927{
928 int result = 0;
929 int result2 = 0;
930
931 pr_debug("%s:\n", __func__);
932
933 if (mem_map_handle == NULL) {
934 pr_debug("%s: Map handle is NULL, nothing to unmap\n",
935 __func__);
936 goto done;
937 }
938
939 if (*mem_map_handle == 0) {
940 pr_debug("%s: Map handle is 0, nothing to unmap\n",
941 __func__);
942 goto done;
943 }
944
945 if (common_client.mmap_apr == NULL) {
946 common_client.mmap_apr = q6asm_mmap_apr_reg();
947 if (common_client.mmap_apr == NULL) {
948 pr_err("%s: q6asm_mmap_apr_reg failed\n",
949 __func__);
950 result = -EPERM;
951 goto done;
952 }
953 }
954
955
956 result2 = q6asm_memory_unmap_regions(&common_client, OUT);
957 if (result2 < 0) {
958 pr_err("%s: unmap failed, err %d\n",
959 __func__, result2);
960 result = result2;
961 } else {
Aditya Bavanari271b0c92018-06-18 11:59:09 +0530962 *mem_map_handle = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530963 }
964
965 result2 = q6asm_mmap_apr_dereg();
966 if (result2 < 0) {
967 pr_err("%s: q6asm_mmap_apr_dereg failed, err %d\n",
968 __func__, result2);
969 result = result2;
970 }
971done:
972 return result;
973}
974
975int q6asm_audio_client_buf_free(unsigned int dir,
976 struct audio_client *ac)
977{
978 struct audio_port_data *port;
979 int cnt = 0;
980 int rc = 0;
981
982 pr_debug("%s: Session id %d\n", __func__, ac->session);
983 mutex_lock(&ac->cmd_lock);
984 if (ac->io_mode & SYNC_IO_MODE) {
985 port = &ac->port[dir];
986 if (!port->buf) {
987 pr_err("%s: buf NULL\n", __func__);
988 mutex_unlock(&ac->cmd_lock);
989 return 0;
990 }
991 cnt = port->max_buf_cnt - 1;
992
993 if (cnt >= 0) {
994 rc = q6asm_memory_unmap_regions(ac, dir);
995 if (rc < 0)
996 pr_err("%s: Memory_unmap_regions failed %d\n",
997 __func__, rc);
998 }
999
1000 while (cnt >= 0) {
1001 if (port->buf[cnt].data) {
1002 if (!rc || atomic_read(&ac->reset))
1003 msm_audio_ion_free(
1004 port->buf[cnt].client,
1005 port->buf[cnt].handle);
1006
1007 port->buf[cnt].client = NULL;
1008 port->buf[cnt].handle = NULL;
1009 port->buf[cnt].data = NULL;
1010 port->buf[cnt].phys = 0;
1011 --(port->max_buf_cnt);
1012 }
1013 --cnt;
1014 }
1015 kfree(port->buf);
1016 port->buf = NULL;
1017 }
1018 mutex_unlock(&ac->cmd_lock);
1019 return 0;
1020}
1021
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301022/**
1023 * q6asm_audio_client_buf_free_contiguous -
1024 * frees the memory buffers for ASM
1025 *
1026 * @dir: RX or TX direction
1027 * @ac: audio client handle
1028 *
1029 * Returns 0 on success or error on failure
1030 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301031int q6asm_audio_client_buf_free_contiguous(unsigned int dir,
1032 struct audio_client *ac)
1033{
1034 struct audio_port_data *port;
1035 int cnt = 0;
1036 int rc = 0;
1037
1038 pr_debug("%s: Session id %d\n", __func__, ac->session);
1039 mutex_lock(&ac->cmd_lock);
1040 port = &ac->port[dir];
1041 if (!port->buf) {
1042 mutex_unlock(&ac->cmd_lock);
1043 return 0;
1044 }
1045 cnt = port->max_buf_cnt - 1;
1046
1047 if (cnt >= 0) {
1048 rc = q6asm_memory_unmap(ac, port->buf[0].phys, dir);
1049 if (rc < 0)
1050 pr_err("%s: Memory_unmap_regions failed %d\n",
1051 __func__, rc);
1052 }
1053
1054 if (port->buf[0].data) {
1055 pr_debug("%s: data[%pK]phys[%pK][%pK] , client[%pK] handle[%pK]\n",
1056 __func__,
1057 port->buf[0].data,
1058 &port->buf[0].phys,
1059 &port->buf[0].phys,
1060 port->buf[0].client,
1061 port->buf[0].handle);
1062 if (!rc || atomic_read(&ac->reset))
1063 msm_audio_ion_free(port->buf[0].client,
1064 port->buf[0].handle);
1065 port->buf[0].client = NULL;
1066 port->buf[0].handle = NULL;
1067 }
1068
1069 while (cnt >= 0) {
1070 port->buf[cnt].data = NULL;
1071 port->buf[cnt].phys = 0;
1072 cnt--;
1073 }
1074 port->max_buf_cnt = 0;
1075 kfree(port->buf);
1076 port->buf = NULL;
1077 mutex_unlock(&ac->cmd_lock);
1078 return 0;
1079}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301080EXPORT_SYMBOL(q6asm_audio_client_buf_free_contiguous);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301081
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301082/**
1083 * q6asm_audio_client_free -
1084 * frees the audio client for ASM
1085 *
1086 * @ac: audio client handle
1087 *
1088 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301089void q6asm_audio_client_free(struct audio_client *ac)
1090{
1091 int loopcnt;
1092 struct audio_port_data *port;
1093
1094 if (!ac) {
1095 pr_err("%s: ac %pK\n", __func__, ac);
1096 return;
1097 }
1098 if (!ac->session) {
1099 pr_err("%s: ac session invalid\n", __func__);
1100 return;
1101 }
1102
1103 mutex_lock(&session_lock);
1104
1105 pr_debug("%s: Session id %d\n", __func__, ac->session);
1106 if (ac->io_mode & SYNC_IO_MODE) {
1107 for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
1108 port = &ac->port[loopcnt];
1109 if (!port->buf)
1110 continue;
1111 pr_debug("%s: loopcnt = %d\n",
1112 __func__, loopcnt);
1113 q6asm_audio_client_buf_free(loopcnt, ac);
1114 }
1115 }
1116
1117 rtac_set_asm_handle(ac->session, NULL);
1118 apr_deregister(ac->apr2);
1119 apr_deregister(ac->apr);
1120 q6asm_mmap_apr_dereg();
1121 ac->apr2 = NULL;
1122 ac->apr = NULL;
1123 ac->mmap_apr = NULL;
1124 q6asm_session_free(ac);
1125
1126 pr_debug("%s: APR De-Register\n", __func__);
1127
1128/*done:*/
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301129 mutex_unlock(&session_lock);
1130}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301131EXPORT_SYMBOL(q6asm_audio_client_free);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301132
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301133/**
1134 * q6asm_set_io_mode -
1135 * Update IO mode for ASM
1136 *
1137 * @ac: audio client handle
1138 * @mode1: IO mode to update
1139 *
1140 * Returns 0 on success or error on failure
1141 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301142int q6asm_set_io_mode(struct audio_client *ac, uint32_t mode1)
1143{
1144 uint32_t mode;
1145 int ret = 0;
1146
1147 if (ac == NULL) {
1148 pr_err("%s: APR handle NULL\n", __func__);
1149 return -EINVAL;
1150 }
1151
1152 ac->io_mode &= 0xFF00;
1153 mode = (mode1 & 0xF);
1154
1155 pr_debug("%s: ac->mode after anding with FF00:0x%x,\n",
1156 __func__, ac->io_mode);
1157
1158 if ((mode == ASYNC_IO_MODE) || (mode == SYNC_IO_MODE)) {
1159 ac->io_mode |= mode1;
1160 pr_debug("%s: Set Mode to 0x%x\n", __func__, ac->io_mode);
1161 } else {
1162 pr_err("%s: Not an valid IO Mode:%d\n", __func__, ac->io_mode);
1163 ret = -EINVAL;
1164 }
1165
1166 return ret;
1167}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301168EXPORT_SYMBOL(q6asm_set_io_mode);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301169
1170void *q6asm_mmap_apr_reg(void)
1171{
1172 if ((atomic_read(&this_mmap.ref_cnt) == 0) ||
1173 (this_mmap.apr == NULL)) {
1174 this_mmap.apr = apr_register("ADSP", "ASM",
1175 (apr_fn)q6asm_srvc_callback,
1176 0x0FFFFFFFF, &this_mmap);
1177 if (this_mmap.apr == NULL) {
1178 pr_debug("%s: Unable to register APR ASM common port\n",
1179 __func__);
1180 goto fail;
1181 }
1182 }
1183 atomic_inc(&this_mmap.ref_cnt);
1184
1185 return this_mmap.apr;
1186fail:
1187 return NULL;
1188}
1189
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301190/**
1191 * q6asm_send_stream_cmd -
1192 * command to send for ASM stream
1193 *
1194 * @ac: audio client handle
1195 * @data: event data
1196 *
1197 * Returns 0 on success or error on failure
1198 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301199int q6asm_send_stream_cmd(struct audio_client *ac,
1200 struct msm_adsp_event_data *data)
1201{
1202 char *asm_params = NULL;
1203 struct apr_hdr hdr;
Xiaojun Sanga4648082018-04-27 14:57:33 +08001204 int rc, session_id = 0;
Aditya Bavanari2e3341d2018-02-23 12:58:57 +05301205 uint32_t sz = 0;
1206 uint64_t actual_sz = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301207
1208 if (!data || !ac) {
1209 pr_err("%s: %s is NULL\n", __func__,
1210 (!data) ? "data" : "ac");
1211 rc = -EINVAL;
1212 goto done;
1213 }
1214
Xiaojun Sanga4648082018-04-27 14:57:33 +08001215 session_id = q6asm_get_session_id_from_audio_client(ac);
1216 if (!session_id) {
1217 rc = -EINVAL;
1218 goto done;
1219 }
1220
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301221 if (data->event_type >= ARRAY_SIZE(adsp_reg_event_opcode)) {
1222 pr_err("%s: event %u out of boundary of array size of (%lu)\n",
1223 __func__, data->event_type,
1224 (long)ARRAY_SIZE(adsp_reg_event_opcode));
1225 rc = -EINVAL;
1226 goto done;
1227 }
1228
Aditya Bavanari2e3341d2018-02-23 12:58:57 +05301229 actual_sz = sizeof(struct apr_hdr) + data->payload_len;
1230 if (actual_sz > U32_MAX) {
1231 pr_err("%s: payload size 0x%X exceeds limit\n",
1232 __func__, data->payload_len);
1233 rc = -EINVAL;
1234 goto done;
1235 }
1236
1237 sz = (uint32_t)actual_sz;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301238 asm_params = kzalloc(sz, GFP_KERNEL);
1239 if (!asm_params) {
1240 rc = -ENOMEM;
1241 goto done;
1242 }
1243
Xiaojun Sanga4648082018-04-27 14:57:33 +08001244 mutex_lock(&session[session_id].mutex_lock_per_session);
1245 if (!q6asm_is_valid_audio_client(ac)) {
1246 rc = -EINVAL;
1247 goto fail_send_param;
1248 }
1249
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301250 q6asm_add_hdr_async(ac, &hdr, sz, TRUE);
1251 atomic_set(&ac->cmd_state_pp, -1);
1252 hdr.opcode = adsp_reg_event_opcode[data->event_type];
1253 memcpy(asm_params, &hdr, sizeof(struct apr_hdr));
1254 memcpy(asm_params + sizeof(struct apr_hdr),
1255 data->payload, data->payload_len);
1256 rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params);
1257 if (rc < 0) {
1258 pr_err("%s: stream event cmd apr pkt failed\n", __func__);
1259 rc = -EINVAL;
1260 goto fail_send_param;
1261 }
1262
1263 rc = wait_event_timeout(ac->cmd_wait,
1264 (atomic_read(&ac->cmd_state_pp) >= 0), 1 * HZ);
1265 if (!rc) {
1266 pr_err("%s: timeout for stream event cmd resp\n", __func__);
1267 rc = -ETIMEDOUT;
1268 goto fail_send_param;
1269 }
1270
1271 if (atomic_read(&ac->cmd_state_pp) > 0) {
1272 pr_err("%s: DSP returned error[%s] for stream event cmd\n",
1273 __func__, adsp_err_get_err_str(
1274 atomic_read(&ac->cmd_state_pp)));
1275 rc = adsp_err_get_lnx_err_code(
1276 atomic_read(&ac->cmd_state_pp));
1277 goto fail_send_param;
1278 }
1279
1280 rc = 0;
1281fail_send_param:
Xiaojun Sanga4648082018-04-27 14:57:33 +08001282 mutex_unlock(&session[session_id].mutex_lock_per_session);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301283 kfree(asm_params);
1284done:
1285 return rc;
1286}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301287EXPORT_SYMBOL(q6asm_send_stream_cmd);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301288
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301289/**
1290 * q6asm_audio_client_alloc -
1291 * Alloc audio client for ASM
1292 *
1293 * @cb: callback fn
1294 * @priv: private data
1295 *
1296 * Returns ac pointer on success or NULL on failure
1297 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301298struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv)
1299{
1300 struct audio_client *ac;
1301 int n;
1302 int lcnt = 0;
1303 int rc = 0;
1304
1305 ac = kzalloc(sizeof(struct audio_client), GFP_KERNEL);
1306 if (!ac)
1307 return NULL;
1308
1309 mutex_lock(&session_lock);
1310 n = q6asm_session_alloc(ac);
1311 if (n <= 0) {
1312 pr_err("%s: ASM Session alloc fail n=%d\n", __func__, n);
1313 mutex_unlock(&session_lock);
Meng Wang9730cdd2017-09-26 12:48:31 +08001314 kfree(ac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301315 goto fail_session;
1316 }
1317 ac->session = n;
1318 ac->cb = cb;
1319 ac->path_delay = UINT_MAX;
1320 ac->priv = priv;
1321 ac->io_mode = SYNC_IO_MODE;
1322 ac->perf_mode = LEGACY_PCM_MODE;
1323 ac->fptr_cache_ops = NULL;
1324 /* DSP expects stream id from 1 */
1325 ac->stream_id = 1;
1326 ac->apr = apr_register("ADSP", "ASM",
1327 (apr_fn)q6asm_callback,
1328 ((ac->session) << 8 | 0x0001),
1329 ac);
1330
1331 if (ac->apr == NULL) {
1332 pr_err("%s: Registration with APR failed\n", __func__);
1333 mutex_unlock(&session_lock);
1334 goto fail_apr1;
1335 }
1336 ac->apr2 = apr_register("ADSP", "ASM",
1337 (apr_fn)q6asm_callback,
1338 ((ac->session) << 8 | 0x0002),
1339 ac);
1340
1341 if (ac->apr2 == NULL) {
1342 pr_err("%s: Registration with APR-2 failed\n", __func__);
1343 mutex_unlock(&session_lock);
1344 goto fail_apr2;
1345 }
1346
1347 rtac_set_asm_handle(n, ac->apr);
1348
1349 pr_debug("%s: Registering the common port with APR\n", __func__);
1350 ac->mmap_apr = q6asm_mmap_apr_reg();
1351 if (ac->mmap_apr == NULL) {
1352 mutex_unlock(&session_lock);
1353 goto fail_mmap;
1354 }
1355
1356 init_waitqueue_head(&ac->cmd_wait);
1357 init_waitqueue_head(&ac->time_wait);
1358 init_waitqueue_head(&ac->mem_wait);
1359 atomic_set(&ac->time_flag, 1);
1360 atomic_set(&ac->reset, 0);
1361 INIT_LIST_HEAD(&ac->port[0].mem_map_handle);
1362 INIT_LIST_HEAD(&ac->port[1].mem_map_handle);
1363 pr_debug("%s: mem_map_handle list init'ed\n", __func__);
1364 mutex_init(&ac->cmd_lock);
1365 for (lcnt = 0; lcnt <= OUT; lcnt++) {
1366 mutex_init(&ac->port[lcnt].lock);
1367 spin_lock_init(&ac->port[lcnt].dsp_lock);
1368 }
1369 atomic_set(&ac->cmd_state, 0);
1370 atomic_set(&ac->cmd_state_pp, 0);
1371 atomic_set(&ac->mem_state, 0);
1372
1373 rc = send_asm_custom_topology(ac);
1374 if (rc < 0) {
1375 mutex_unlock(&session_lock);
1376 goto fail_mmap;
1377 }
1378
1379 pr_debug("%s: session[%d]\n", __func__, ac->session);
1380
1381 mutex_unlock(&session_lock);
1382
1383 return ac;
1384fail_mmap:
1385 apr_deregister(ac->apr2);
1386fail_apr2:
1387 apr_deregister(ac->apr);
1388fail_apr1:
1389 q6asm_session_free(ac);
1390fail_session:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301391 return NULL;
1392}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301393EXPORT_SYMBOL(q6asm_audio_client_alloc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301394
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301395/**
1396 * q6asm_get_audio_client -
1397 * Retrieve audio client for ASM
1398 *
1399 * @session_id: ASM session id
1400 *
1401 * Returns valid pointer on success or NULL on failure
1402 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301403struct audio_client *q6asm_get_audio_client(int session_id)
1404{
1405 if (session_id == ASM_CONTROL_SESSION)
1406 return &common_client;
1407
1408 if ((session_id <= 0) || (session_id > ASM_ACTIVE_STREAMS_ALLOWED)) {
1409 pr_err("%s: invalid session: %d\n", __func__, session_id);
1410 goto err;
1411 }
1412
Meng Wang9730cdd2017-09-26 12:48:31 +08001413 if (!(session[session_id].ac)) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301414 pr_err("%s: session not active: %d\n", __func__, session_id);
1415 goto err;
1416 }
Meng Wang9730cdd2017-09-26 12:48:31 +08001417 return session[session_id].ac;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301418err:
1419 return NULL;
1420}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301421EXPORT_SYMBOL(q6asm_get_audio_client);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301422
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301423/**
1424 * q6asm_audio_client_buf_alloc -
1425 * Allocs memory from ION for ASM
1426 *
1427 * @dir: RX or TX direction
1428 * @ac: Audio client handle
1429 * @bufsz: size of each buffer
1430 * @bufcnt: number of buffers to alloc
1431 *
1432 * Returns 0 on success or error on failure
1433 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301434int q6asm_audio_client_buf_alloc(unsigned int dir,
1435 struct audio_client *ac,
1436 unsigned int bufsz,
1437 uint32_t bufcnt)
1438{
1439 int cnt = 0;
1440 int rc = 0;
1441 struct audio_buffer *buf;
1442 size_t len;
1443
1444 if (!(ac) || !(bufsz) || ((dir != IN) && (dir != OUT))) {
1445 pr_err("%s: ac %pK bufsz %d dir %d\n", __func__, ac, bufsz,
1446 dir);
1447 return -EINVAL;
1448 }
1449
1450 pr_debug("%s: session[%d]bufsz[%d]bufcnt[%d]\n", __func__, ac->session,
1451 bufsz, bufcnt);
1452
1453 if (ac->session <= 0 || ac->session > 8) {
1454 pr_err("%s: Session ID is invalid, session = %d\n", __func__,
1455 ac->session);
1456 goto fail;
1457 }
1458
1459 if (ac->io_mode & SYNC_IO_MODE) {
1460 if (ac->port[dir].buf) {
1461 pr_debug("%s: buffer already allocated\n", __func__);
1462 return 0;
1463 }
1464 mutex_lock(&ac->cmd_lock);
1465 if (bufcnt > (U32_MAX/sizeof(struct audio_buffer))) {
1466 pr_err("%s: Buffer size overflows", __func__);
1467 mutex_unlock(&ac->cmd_lock);
1468 goto fail;
1469 }
1470 buf = kzalloc(((sizeof(struct audio_buffer))*bufcnt),
1471 GFP_KERNEL);
1472
1473 if (!buf) {
1474 mutex_unlock(&ac->cmd_lock);
1475 goto fail;
1476 }
1477
1478 ac->port[dir].buf = buf;
1479
1480 while (cnt < bufcnt) {
1481 if (bufsz > 0) {
1482 if (!buf[cnt].data) {
1483 rc = msm_audio_ion_alloc("asm_client",
1484 &buf[cnt].client, &buf[cnt].handle,
1485 bufsz,
1486 (ion_phys_addr_t *)&buf[cnt].phys,
1487 &len,
1488 &buf[cnt].data);
1489 if (rc) {
1490 pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n",
1491 __func__, rc);
1492 mutex_unlock(&ac->cmd_lock);
1493 goto fail;
1494 }
1495
1496 buf[cnt].used = 1;
1497 buf[cnt].size = bufsz;
1498 buf[cnt].actual_size = bufsz;
1499 pr_debug("%s: data[%pK]phys[%pK][%pK]\n",
1500 __func__,
1501 buf[cnt].data,
1502 &buf[cnt].phys,
1503 &buf[cnt].phys);
1504 cnt++;
1505 }
1506 }
1507 }
1508 ac->port[dir].max_buf_cnt = cnt;
1509
1510 mutex_unlock(&ac->cmd_lock);
1511 rc = q6asm_memory_map_regions(ac, dir, bufsz, cnt, 0);
1512 if (rc < 0) {
1513 pr_err("%s: CMD Memory_map_regions failed %d for size %d\n",
1514 __func__, rc, bufsz);
1515 goto fail;
1516 }
1517 }
1518 return 0;
1519fail:
1520 q6asm_audio_client_buf_free(dir, ac);
1521 return -EINVAL;
1522}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301523EXPORT_SYMBOL(q6asm_audio_client_buf_alloc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301524
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301525/**
1526 * q6asm_audio_client_buf_alloc_contiguous -
1527 * Alloc contiguous memory from ION for ASM
1528 *
1529 * @dir: RX or TX direction
1530 * @ac: Audio client handle
1531 * @bufsz: size of each buffer
1532 * @bufcnt: number of buffers to alloc
1533 *
1534 * Returns 0 on success or error on failure
1535 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301536int q6asm_audio_client_buf_alloc_contiguous(unsigned int dir,
1537 struct audio_client *ac,
1538 unsigned int bufsz,
1539 unsigned int bufcnt)
1540{
1541 int cnt = 0;
1542 int rc = 0;
1543 struct audio_buffer *buf;
1544 size_t len;
1545 int bytes_to_alloc;
1546
1547 if (!(ac) || ((dir != IN) && (dir != OUT))) {
1548 pr_err("%s: ac %pK dir %d\n", __func__, ac, dir);
1549 return -EINVAL;
1550 }
1551
1552 pr_debug("%s: session[%d]bufsz[%d]bufcnt[%d]\n",
1553 __func__, ac->session,
1554 bufsz, bufcnt);
1555
1556 if (ac->session <= 0 || ac->session > 8) {
1557 pr_err("%s: Session ID is invalid, session = %d\n", __func__,
1558 ac->session);
1559 goto fail;
1560 }
1561
1562 if (ac->port[dir].buf) {
1563 pr_err("%s: buffer already allocated\n", __func__);
1564 return 0;
1565 }
Soumya Managoli70a195a2018-09-05 11:02:56 +05301566
1567 if (bufcnt == 0) {
1568 pr_err("%s: invalid buffer count\n", __func__);
1569 return -EINVAL;
1570 }
1571
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301572 mutex_lock(&ac->cmd_lock);
1573 buf = kzalloc(((sizeof(struct audio_buffer))*bufcnt),
1574 GFP_KERNEL);
1575
1576 if (!buf) {
1577 pr_err("%s: buffer allocation failed\n", __func__);
1578 mutex_unlock(&ac->cmd_lock);
1579 goto fail;
1580 }
1581
1582 ac->port[dir].buf = buf;
1583
1584 /* check for integer overflow */
1585 if ((bufcnt > 0) && ((INT_MAX / bufcnt) < bufsz)) {
1586 pr_err("%s: integer overflow\n", __func__);
1587 mutex_unlock(&ac->cmd_lock);
1588 goto fail;
1589 }
1590 bytes_to_alloc = bufsz * bufcnt;
1591
1592 /* The size to allocate should be multiple of 4K bytes */
1593 bytes_to_alloc = PAGE_ALIGN(bytes_to_alloc);
1594
1595 rc = msm_audio_ion_alloc("asm_client", &buf[0].client, &buf[0].handle,
1596 bytes_to_alloc,
1597 (ion_phys_addr_t *)&buf[0].phys, &len,
1598 &buf[0].data);
1599 if (rc) {
1600 pr_err("%s: Audio ION alloc is failed, rc = %d\n",
1601 __func__, rc);
1602 mutex_unlock(&ac->cmd_lock);
1603 goto fail;
1604 }
1605
1606 buf[0].used = dir ^ 1;
1607 buf[0].size = bufsz;
1608 buf[0].actual_size = bufsz;
1609 cnt = 1;
1610 while (cnt < bufcnt) {
1611 if (bufsz > 0) {
1612 buf[cnt].data = buf[0].data + (cnt * bufsz);
1613 buf[cnt].phys = buf[0].phys + (cnt * bufsz);
1614 if (!buf[cnt].data) {
1615 pr_err("%s: Buf alloc failed\n",
1616 __func__);
1617 mutex_unlock(&ac->cmd_lock);
1618 goto fail;
1619 }
1620 buf[cnt].used = dir ^ 1;
1621 buf[cnt].size = bufsz;
1622 buf[cnt].actual_size = bufsz;
1623 pr_debug("%s: data[%pK]phys[%pK][%pK]\n",
1624 __func__,
1625 buf[cnt].data,
1626 &buf[cnt].phys,
1627 &buf[cnt].phys);
1628 }
1629 cnt++;
1630 }
1631 ac->port[dir].max_buf_cnt = cnt;
1632 mutex_unlock(&ac->cmd_lock);
1633 rc = q6asm_memory_map_regions(ac, dir, bufsz, cnt, 1);
1634 if (rc < 0) {
1635 pr_err("%s: CMD Memory_map_regions failed %d for size %d\n",
1636 __func__, rc, bufsz);
1637 goto fail;
1638 }
1639 return 0;
1640fail:
1641 q6asm_audio_client_buf_free_contiguous(dir, ac);
1642 return -EINVAL;
1643}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301644EXPORT_SYMBOL(q6asm_audio_client_buf_alloc_contiguous);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301645
1646static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv)
1647{
1648 uint32_t dir = 0;
1649 uint32_t i = IN;
1650 uint32_t *payload;
Vignesh Kulothungan023a5322018-06-21 11:13:29 -07001651 unsigned long dsp_flags = 0;
Meng Wangb6afa8c2017-11-30 17:55:05 +08001652 unsigned long flags = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301653 struct asm_buffer_node *buf_node = NULL;
1654 struct list_head *ptr, *next;
1655 union asm_token_struct asm_token;
1656
1657 struct audio_client *ac = NULL;
1658 struct audio_port_data *port;
1659
Meng Wang9730cdd2017-09-26 12:48:31 +08001660 int session_id;
1661
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301662 if (!data) {
1663 pr_err("%s: Invalid CB\n", __func__);
1664 return 0;
1665 }
1666
1667 payload = data->payload;
1668
1669 if (data->opcode == RESET_EVENTS) {
1670 pr_debug("%s: Reset event is received: %d %d apr[%pK]\n",
1671 __func__,
1672 data->reset_event,
1673 data->reset_proc,
1674 this_mmap.apr);
1675 atomic_set(&this_mmap.ref_cnt, 0);
1676 apr_reset(this_mmap.apr);
1677 this_mmap.apr = NULL;
1678 for (; i <= OUT; i++) {
1679 list_for_each_safe(ptr, next,
1680 &common_client.port[i].mem_map_handle) {
1681 buf_node = list_entry(ptr,
1682 struct asm_buffer_node,
1683 list);
1684 if (buf_node->buf_phys_addr ==
1685 common_client.port[i].buf->phys) {
1686 list_del(&buf_node->list);
1687 kfree(buf_node);
1688 }
1689 }
1690 pr_debug("%s: Clearing custom topology\n", __func__);
1691 }
1692
1693 cal_utils_clear_cal_block_q6maps(ASM_MAX_CAL_TYPES, cal_data);
1694 common_client.mmap_apr = NULL;
1695 mutex_lock(&cal_data[ASM_CUSTOM_TOP_CAL]->lock);
1696 set_custom_topology = 1;
1697 mutex_unlock(&cal_data[ASM_CUSTOM_TOP_CAL]->lock);
1698 topology_map_handle = 0;
1699 rtac_clear_mapping(ASM_RTAC_CAL);
1700 return 0;
1701 }
1702 asm_token.token = data->token;
Meng Wang9730cdd2017-09-26 12:48:31 +08001703 session_id = asm_token._token.session_id;
1704
1705 if ((session_id > 0 && session_id <= ASM_ACTIVE_STREAMS_ALLOWED))
Meng Wangb6afa8c2017-11-30 17:55:05 +08001706 spin_lock_irqsave(&(session[session_id].session_lock), flags);
Meng Wang9730cdd2017-09-26 12:48:31 +08001707
1708 ac = q6asm_get_audio_client(session_id);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301709 dir = q6asm_get_flag_from_token(&asm_token, ASM_DIRECTION_OFFSET);
1710
1711 if (!ac) {
1712 pr_debug("%s: session[%d] already freed\n",
Meng Wang9730cdd2017-09-26 12:48:31 +08001713 __func__, session_id);
1714 if ((session_id > 0 &&
1715 session_id <= ASM_ACTIVE_STREAMS_ALLOWED))
Meng Wangb6afa8c2017-11-30 17:55:05 +08001716 spin_unlock_irqrestore(
1717 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301718 return 0;
1719 }
1720
Xiaojun Sang55ee5692019-02-15 16:26:16 +08001721 if (data->payload_size >= 2 * sizeof(uint32_t)) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301722 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",
1723 __func__, payload[0], payload[1], data->opcode,
1724 data->token, data->payload_size, data->src_port,
1725 data->dest_port, asm_token._token.session_id, dir);
1726 pr_debug("%s:Payload = [0x%x] status[0x%x]\n",
1727 __func__, payload[0], payload[1]);
Xiaojun Sang55ee5692019-02-15 16:26:16 +08001728 } else if (data->payload_size == sizeof(uint32_t)) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301729 pr_debug("%s:ptr0[0x%x]opcode[0x%x] token[0x%x]payload_s[%d] src[%d] dest[%d]sid[%d]dir[%d]\n",
1730 __func__, payload[0], data->opcode,
1731 data->token, data->payload_size, data->src_port,
1732 data->dest_port, asm_token._token.session_id, dir);
1733 pr_debug("%s:Payload = [0x%x]\n",
1734 __func__, payload[0]);
1735 }
1736
1737 if (data->opcode == APR_BASIC_RSP_RESULT) {
1738 switch (payload[0]) {
1739 case ASM_CMD_SHARED_MEM_MAP_REGIONS:
1740 case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:
1741 case ASM_CMD_ADD_TOPOLOGIES:
Xiaojun Sang55ee5692019-02-15 16:26:16 +08001742 if (data->payload_size >=
1743 2 * sizeof(uint32_t)
1744 && payload[1] != 0) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301745 pr_err("%s: cmd = 0x%x returned error = 0x%x sid:%d\n",
1746 __func__, payload[0], payload[1],
1747 asm_token._token.session_id);
1748 if (payload[0] ==
1749 ASM_CMD_SHARED_MEM_UNMAP_REGIONS)
1750 atomic_set(&ac->unmap_cb_success, 0);
1751
1752 atomic_set(&ac->mem_state, payload[1]);
1753 wake_up(&ac->mem_wait);
1754 } else {
1755 if (payload[0] ==
1756 ASM_CMD_SHARED_MEM_UNMAP_REGIONS)
1757 atomic_set(&ac->unmap_cb_success, 1);
1758 }
1759
1760 if (atomic_cmpxchg(&ac->mem_state, -1, 0) == -1)
1761 wake_up(&ac->mem_wait);
Xiaojun Sang55ee5692019-02-15 16:26:16 +08001762 if (data->payload_size >= 2 * sizeof(uint32_t))
1763 dev_vdbg(ac->dev, "%s: Payload = [0x%x] status[0x%x]\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301764 __func__, payload[0], payload[1]);
Xiaojun Sang55ee5692019-02-15 16:26:16 +08001765 else
1766 dev_vdbg(ac->dev, "%s: Payload size of %d is less than expected.\n",
1767 __func__, data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301768 break;
1769 default:
1770 pr_debug("%s: command[0x%x] not expecting rsp\n",
1771 __func__, payload[0]);
1772 break;
1773 }
Meng Wang9730cdd2017-09-26 12:48:31 +08001774 if ((session_id > 0 &&
1775 session_id <= ASM_ACTIVE_STREAMS_ALLOWED))
Meng Wangb6afa8c2017-11-30 17:55:05 +08001776 spin_unlock_irqrestore(
1777 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301778 return 0;
1779 }
1780
Soumya Managoli5ae26ba2019-11-06 15:37:08 +05301781 if (dir != IN && dir != OUT) {
1782 pr_err("%s: Invalid audio port index: %d\n", __func__, dir);
1783 if ((session_id > 0 && session_id <= SESSION_MAX))
1784 spin_unlock_irqrestore(
1785 &(session[session_id].session_lock), flags);
1786 return 0;
1787 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301788 port = &ac->port[dir];
1789
1790 switch (data->opcode) {
1791 case ASM_CMDRSP_SHARED_MEM_MAP_REGIONS:{
1792 pr_debug("%s:PL#0[0x%x] dir=0x%x s_id=0x%x\n",
1793 __func__, payload[0], dir, asm_token._token.session_id);
1794 spin_lock_irqsave(&port->dsp_lock, dsp_flags);
1795 if (atomic_cmpxchg(&ac->mem_state, -1, 0) == -1) {
1796 ac->port[dir].tmp_hdl = payload[0];
1797 wake_up(&ac->mem_wait);
1798 }
1799 spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
1800 break;
1801 }
1802 case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:{
Xiaojun Sang55ee5692019-02-15 16:26:16 +08001803 if (data->payload_size >= 2 * sizeof(uint32_t))
1804 pr_debug("%s: PL#0[0x%x]PL#1 [0x%x]\n",
1805 __func__, payload[0], payload[1]);
1806 else
1807 pr_debug("%s: Payload size of %d is less than expected.\n",
1808 __func__, data->payload_size);
1809
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301810 spin_lock_irqsave(&port->dsp_lock, dsp_flags);
1811 if (atomic_cmpxchg(&ac->mem_state, -1, 0) == -1)
1812 wake_up(&ac->mem_wait);
1813 spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
1814
1815 break;
1816 }
1817 default:
Xiaojun Sang55ee5692019-02-15 16:26:16 +08001818 if (data->payload_size >= 2 * sizeof(uint32_t))
1819 pr_debug("%s: command[0x%x]success [0x%x]\n",
1820 __func__, payload[0], payload[1]);
1821 else
1822 pr_debug("%s: Payload size of %d is less than expected.\n",
1823 __func__, data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301824 }
1825 if (ac->cb)
1826 ac->cb(data->opcode, data->token,
1827 data->payload, ac->priv);
Meng Wang9730cdd2017-09-26 12:48:31 +08001828 if ((session_id > 0 && session_id <= ASM_ACTIVE_STREAMS_ALLOWED))
Meng Wangb6afa8c2017-11-30 17:55:05 +08001829 spin_unlock_irqrestore(
1830 &(session[session_id].session_lock), flags);
Meng Wang9730cdd2017-09-26 12:48:31 +08001831
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301832 return 0;
1833}
1834
1835static void q6asm_process_mtmx_get_param_rsp(struct audio_client *ac,
1836 struct asm_mtmx_strtr_get_params_cmdrsp *cmdrsp)
1837{
1838 struct asm_session_mtmx_strtr_param_session_time_v3_t *time;
1839
1840 if (cmdrsp->err_code) {
1841 dev_err_ratelimited(ac->dev,
1842 "%s: err=%x, mod_id=%x, param_id=%x\n",
1843 __func__, cmdrsp->err_code,
1844 cmdrsp->param_info.module_id,
1845 cmdrsp->param_info.param_id);
1846 return;
1847 }
1848 dev_dbg_ratelimited(ac->dev,
1849 "%s: mod_id=%x, param_id=%x\n", __func__,
1850 cmdrsp->param_info.module_id,
1851 cmdrsp->param_info.param_id);
1852
1853 switch (cmdrsp->param_info.module_id) {
1854 case ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC:
1855 switch (cmdrsp->param_info.param_id) {
1856 case ASM_SESSION_MTMX_STRTR_PARAM_SESSION_TIME_V3:
1857 time = &cmdrsp->param_data.session_time;
1858 dev_vdbg(ac->dev, "%s: GET_TIME_V3, time_lsw=%x, time_msw=%x\n",
1859 __func__, time->session_time_lsw,
1860 time->session_time_msw);
1861 ac->time_stamp = (uint64_t)(((uint64_t)
1862 time->session_time_msw << 32) |
1863 time->session_time_lsw);
1864 if (time->flags &
1865 ASM_SESSION_MTMX_STRTR_PARAM_STIME_TSTMP_FLG_BMASK)
1866 dev_warn_ratelimited(ac->dev,
1867 "%s: recv inval tstmp\n",
1868 __func__);
1869 if (atomic_cmpxchg(&ac->time_flag, 1, 0))
1870 wake_up(&ac->time_wait);
1871
1872 break;
1873 default:
1874 dev_err(ac->dev, "%s: unexpected param_id %x\n",
1875 __func__, cmdrsp->param_info.param_id);
1876 break;
1877 }
1878 break;
1879 default:
1880 dev_err(ac->dev, "%s: unexpected mod_id %x\n", __func__,
1881 cmdrsp->param_info.module_id);
1882 break;
1883 }
1884}
1885
1886static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
1887{
1888 int i = 0;
1889 struct audio_client *ac = (struct audio_client *)priv;
Vignesh Kulothungan023a5322018-06-21 11:13:29 -07001890 unsigned long dsp_flags = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301891 uint32_t *payload;
1892 uint32_t wakeup_flag = 1;
1893 int32_t ret = 0;
1894 union asm_token_struct asm_token;
1895 uint8_t buf_index;
1896 struct msm_adsp_event_data *pp_event_package = NULL;
1897 uint32_t payload_size = 0;
Vignesh Kulothungan023a5322018-06-21 11:13:29 -07001898 unsigned long flags = 0;
Meng Wang9730cdd2017-09-26 12:48:31 +08001899 int session_id;
1900
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301901 if (ac == NULL) {
1902 pr_err("%s: ac NULL\n", __func__);
1903 return -EINVAL;
1904 }
1905 if (data == NULL) {
1906 pr_err("%s: data NULL\n", __func__);
1907 return -EINVAL;
1908 }
Meng Wang9730cdd2017-09-26 12:48:31 +08001909
1910 session_id = q6asm_get_session_id_from_audio_client(ac);
1911 if (session_id <= 0 || session_id > ASM_ACTIVE_STREAMS_ALLOWED) {
1912 pr_err("%s: Session ID is invalid, session = %d\n", __func__,
1913 session_id);
1914 return -EINVAL;
1915 }
Meng Wangb6afa8c2017-11-30 17:55:05 +08001916 spin_lock_irqsave(&(session[session_id].session_lock), flags);
Meng Wang9730cdd2017-09-26 12:48:31 +08001917
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301918 if (!q6asm_is_valid_audio_client(ac)) {
1919 pr_err("%s: audio client pointer is invalid, ac = %pK\n",
1920 __func__, ac);
Meng Wangb6afa8c2017-11-30 17:55:05 +08001921 spin_unlock_irqrestore(
1922 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301923 return -EINVAL;
1924 }
1925
1926 payload = data->payload;
1927 asm_token.token = data->token;
1928 if (q6asm_get_flag_from_token(&asm_token, ASM_CMD_NO_WAIT_OFFSET)) {
1929 pr_debug("%s: No wait command opcode[0x%x] cmd_opcode:%x\n",
1930 __func__, data->opcode, payload ? payload[0] : 0);
1931 wakeup_flag = 0;
1932 }
1933
1934 if (data->opcode == RESET_EVENTS) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301935 atomic_set(&ac->reset, 1);
1936 if (ac->apr == NULL) {
1937 ac->apr = ac->apr2;
1938 ac->apr2 = NULL;
1939 }
1940 pr_debug("%s: Reset event is received: %d %d apr[%pK]\n",
1941 __func__,
1942 data->reset_event, data->reset_proc, ac->apr);
1943 if (ac->cb)
1944 ac->cb(data->opcode, data->token,
1945 (uint32_t *)data->payload, ac->priv);
1946 apr_reset(ac->apr);
1947 ac->apr = NULL;
1948 atomic_set(&ac->time_flag, 0);
1949 atomic_set(&ac->cmd_state, 0);
1950 atomic_set(&ac->mem_state, 0);
1951 atomic_set(&ac->cmd_state_pp, 0);
1952 wake_up(&ac->time_wait);
1953 wake_up(&ac->cmd_wait);
1954 wake_up(&ac->mem_wait);
Meng Wangb6afa8c2017-11-30 17:55:05 +08001955 spin_unlock_irqrestore(
1956 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301957 return 0;
1958 }
1959
1960 dev_vdbg(ac->dev, "%s: session[%d]opcode[0x%x] token[0x%x]payload_size[%d] src[%d] dest[%d]\n",
1961 __func__,
1962 ac->session, data->opcode,
1963 data->token, data->payload_size, data->src_port,
1964 data->dest_port);
1965 if ((data->opcode != ASM_DATA_EVENT_RENDERED_EOS) &&
1966 (data->opcode != ASM_DATA_EVENT_EOS) &&
Vignesh Kulothunganb79df2f2019-01-22 10:31:21 -08001967 (data->opcode != ASM_SESSION_EVENTX_OVERFLOW) &&
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301968 (data->opcode != ASM_SESSION_EVENT_RX_UNDERFLOW)) {
1969 if (payload == NULL) {
1970 pr_err("%s: payload is null\n", __func__);
Meng Wangb6afa8c2017-11-30 17:55:05 +08001971 spin_unlock_irqrestore(
1972 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301973 return -EINVAL;
1974 }
Xiaojun Sang55ee5692019-02-15 16:26:16 +08001975 if (data->payload_size >=
1976 2 * sizeof(uint32_t))
1977 dev_vdbg(ac->dev, "%s: Payload = [0x%x] status[0x%x] opcode 0x%x\n",
1978 __func__, payload[0], payload[1], data->opcode);
1979 else
1980 dev_vdbg(ac->dev, "%s: Payload size of %d is less than expected.\n",
1981 __func__, data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301982 }
1983 if (data->opcode == APR_BASIC_RSP_RESULT) {
1984 switch (payload[0]) {
1985 case ASM_STREAM_CMD_SET_PP_PARAMS_V2:
1986 if (rtac_make_asm_callback(ac->session, payload,
1987 data->payload_size))
1988 break;
1989 case ASM_SESSION_CMD_PAUSE:
1990 case ASM_SESSION_CMD_SUSPEND:
1991 case ASM_DATA_CMD_EOS:
1992 case ASM_STREAM_CMD_CLOSE:
1993 case ASM_STREAM_CMD_FLUSH:
1994 case ASM_SESSION_CMD_RUN_V2:
1995 case ASM_SESSION_CMD_REGISTER_FORX_OVERFLOW_EVENTS:
1996 case ASM_STREAM_CMD_FLUSH_READBUFS:
1997 pr_debug("%s: session %d opcode 0x%x token 0x%x Payload = [0x%x] src %d dest %d\n",
1998 __func__, ac->session, data->opcode, data->token,
1999 payload[0], data->src_port, data->dest_port);
2000 ret = q6asm_is_valid_session(data, priv);
2001 if (ret != 0) {
2002 pr_err("%s: session invalid %d\n", __func__, ret);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002003 spin_unlock_irqrestore(
2004 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302005 return ret;
2006 }
2007 case ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2:
2008 case ASM_STREAM_CMD_OPEN_READ_V3:
2009 case ASM_STREAM_CMD_OPEN_WRITE_V3:
2010 case ASM_STREAM_CMD_OPEN_PULL_MODE_WRITE:
2011 case ASM_STREAM_CMD_OPEN_PUSH_MODE_READ:
2012 case ASM_STREAM_CMD_OPEN_READWRITE_V2:
2013 case ASM_STREAM_CMD_OPEN_LOOPBACK_V2:
2014 case ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK:
2015 case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
2016 case ASM_DATA_CMD_IEC_60958_MEDIA_FMT:
2017 case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
2018 case ASM_STREAM_CMD_SET_ENCDEC_PARAM_V2:
2019 case ASM_STREAM_CMD_REGISTER_ENCDEC_EVENTS:
2020 case ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE:
2021 case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE:
2022 case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE:
2023 case ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS:
2024 case ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED:
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002025 if (data->payload_size >=
2026 2 * sizeof(uint32_t) &&
2027 payload[1] != 0) {
2028 pr_debug("%s: session %d opcode 0x%x token 0x%x Payload = [0x%x] stat 0x%x src %d dest %d\n",
2029 __func__, ac->session,
2030 data->opcode, data->token,
2031 payload[0], payload[1],
2032 data->src_port, data->dest_port);
2033 pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302034 __func__, payload[0], payload[1]);
2035 if (wakeup_flag) {
2036 if ((is_adsp_reg_event(payload[0]) >= 0)
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002037 || (payload[0] ==
2038 ASM_STREAM_CMD_SET_PP_PARAMS_V2))
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302039 atomic_set(&ac->cmd_state_pp,
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002040 payload[1]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302041 else
2042 atomic_set(&ac->cmd_state,
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002043 payload[1]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302044 wake_up(&ac->cmd_wait);
2045 }
Meng Wangb6afa8c2017-11-30 17:55:05 +08002046 spin_unlock_irqrestore(
2047 &(session[session_id].session_lock),
2048 flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302049 return 0;
2050 }
2051 if ((is_adsp_reg_event(payload[0]) >= 0) ||
2052 (payload[0] == ASM_STREAM_CMD_SET_PP_PARAMS_V2)) {
2053 if (atomic_read(&ac->cmd_state_pp) &&
2054 wakeup_flag) {
2055 atomic_set(&ac->cmd_state_pp, 0);
2056 wake_up(&ac->cmd_wait);
2057 }
2058 } else {
2059 if (atomic_read(&ac->cmd_state) &&
2060 wakeup_flag) {
2061 atomic_set(&ac->cmd_state, 0);
2062 wake_up(&ac->cmd_wait);
2063 }
2064 }
2065 if (ac->cb)
2066 ac->cb(data->opcode, data->token,
2067 (uint32_t *)data->payload, ac->priv);
2068 break;
2069 case ASM_CMD_ADD_TOPOLOGIES:
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002070 if (data->payload_size >=
2071 2 * sizeof(uint32_t) &&
2072 payload[1] != 0) {
2073 pr_debug("%s:Payload = [0x%x]stat[0x%x]\n",
2074 __func__, payload[0], payload[1]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302075 pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
2076 __func__, payload[0], payload[1]);
2077 if (wakeup_flag) {
2078 atomic_set(&ac->mem_state, payload[1]);
2079 wake_up(&ac->mem_wait);
2080 }
Meng Wangb6afa8c2017-11-30 17:55:05 +08002081 spin_unlock_irqrestore(
2082 &(session[session_id].session_lock),
2083 flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302084 return 0;
2085 }
2086 if (atomic_read(&ac->mem_state) && wakeup_flag) {
2087 atomic_set(&ac->mem_state, 0);
2088 wake_up(&ac->mem_wait);
2089 }
2090 if (ac->cb)
2091 ac->cb(data->opcode, data->token,
2092 (uint32_t *)data->payload, ac->priv);
2093 break;
2094 case ASM_DATA_EVENT_WATERMARK: {
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002095 if (data->payload_size >= 2 * sizeof(uint32_t))
2096 pr_debug("%s: Watermark opcode[0x%x] status[0x%x]",
2097 __func__, payload[0], payload[1]);
2098 else
2099 pr_err("%s: payload size of %x is less than expected.\n",
2100 __func__, data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302101 break;
2102 }
2103 case ASM_STREAM_CMD_GET_PP_PARAMS_V2:
2104 pr_debug("%s: ASM_STREAM_CMD_GET_PP_PARAMS_V2 session %d opcode 0x%x token 0x%x src %d dest %d\n",
2105 __func__, ac->session,
2106 data->opcode, data->token,
2107 data->src_port, data->dest_port);
2108 /* Should only come here if there is an APR */
2109 /* error or malformed APR packet. Otherwise */
2110 /* response will be returned as */
2111 /* ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2 */
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002112 if (data->payload_size >= 2 * sizeof(uint32_t)) {
2113 if (payload[1] != 0) {
2114 pr_err("%s: ASM get param error = %d, resuming\n",
2115 __func__, payload[1]);
2116 rtac_make_asm_callback(ac->session,
2117 payload,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302118 data->payload_size);
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002119 }
2120 } else {
2121 pr_err("%s: payload size of %x is less than expected.\n",
2122 __func__, data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302123 }
2124 break;
2125 case ASM_STREAM_CMD_REGISTER_PP_EVENTS:
2126 pr_debug("%s: ASM_STREAM_CMD_REGISTER_PP_EVENTS session %d opcode 0x%x token 0x%x src %d dest %d\n",
2127 __func__, ac->session,
2128 data->opcode, data->token,
2129 data->src_port, data->dest_port);
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002130 if (data->payload_size >= 2 * sizeof(uint32_t)) {
2131 if (payload[1] != 0)
2132 pr_err("%s: ASM get param error = %d, resuming\n",
2133 __func__, payload[1]);
2134 atomic_set(&ac->cmd_state_pp, payload[1]);
2135 wake_up(&ac->cmd_wait);
2136 } else {
2137 pr_err("%s: payload size of %x is less than expected.\n",
2138 __func__, data->payload_size);
2139 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302140 break;
2141 default:
2142 pr_debug("%s: command[0x%x] not expecting rsp\n",
2143 __func__, payload[0]);
2144 break;
2145 }
Meng Wang9730cdd2017-09-26 12:48:31 +08002146
Meng Wangb6afa8c2017-11-30 17:55:05 +08002147 spin_unlock_irqrestore(
2148 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302149 return 0;
2150 }
2151
2152 switch (data->opcode) {
2153 case ASM_DATA_EVENT_WRITE_DONE_V2:{
2154 struct audio_port_data *port = &ac->port[IN];
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002155 if (data->payload_size >= 2 * sizeof(uint32_t))
2156 dev_vdbg(ac->dev, "%s: Rxed opcode[0x%x] status[0x%x] token[%d]",
2157 __func__, payload[0], payload[1],
2158 data->token);
2159 else
2160 dev_err(ac->dev, "%s: payload size of %x is less than expected.\n",
2161 __func__, data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302162 if (ac->io_mode & SYNC_IO_MODE) {
2163 if (port->buf == NULL) {
2164 pr_err("%s: Unexpected Write Done\n",
2165 __func__);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002166 spin_unlock_irqrestore(
2167 &(session[session_id].session_lock),
2168 flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302169 return -EINVAL;
2170 }
2171 spin_lock_irqsave(&port->dsp_lock, dsp_flags);
2172 buf_index = asm_token._token.buf_index;
Vignesh Kulothunganb79df2f2019-01-22 10:31:21 -08002173 if (buf_index < 0 || buf_index >= port->max_buf_cnt) {
2174 pr_debug("%s: Invalid buffer index %u\n",
2175 __func__, buf_index);
2176 spin_unlock_irqrestore(&port->dsp_lock,
2177 dsp_flags);
2178 spin_unlock_irqrestore(
2179 &(session[session_id].session_lock),
2180 flags);
2181 return -EINVAL;
2182 }
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002183 if (data->payload_size >= 2 * sizeof(uint32_t) &&
2184 (lower_32_bits(port->buf[buf_index].phys) !=
2185 payload[0] ||
2186 msm_audio_populate_upper_32_bits(
2187 port->buf[buf_index].phys) !=
2188 payload[1])) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302189 pr_debug("%s: Expected addr %pK\n",
2190 __func__, &port->buf[buf_index].phys);
2191 pr_err("%s: rxedl[0x%x] rxedu [0x%x]\n",
2192 __func__, payload[0], payload[1]);
2193 spin_unlock_irqrestore(&port->dsp_lock,
2194 dsp_flags);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002195 spin_unlock_irqrestore(
2196 &(session[session_id].session_lock),
2197 flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302198 return -EINVAL;
2199 }
2200 port->buf[buf_index].used = 1;
2201 spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
2202
2203 config_debug_fs_write_cb();
2204
2205 for (i = 0; i < port->max_buf_cnt; i++)
2206 dev_vdbg(ac->dev, "%s %d\n",
2207 __func__, port->buf[i].used);
2208
2209 }
2210 break;
2211 }
2212 case ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2:
2213 pr_debug("%s: ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2 session %d opcode 0x%x token 0x%x src %d dest %d\n",
2214 __func__, ac->session, data->opcode,
2215 data->token,
2216 data->src_port, data->dest_port);
2217 if (payload[0] != 0) {
2218 pr_err("%s: ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2 returned error = 0x%x\n",
2219 __func__, payload[0]);
2220 } else if (generic_get_data) {
2221 generic_get_data->valid = 1;
2222 if (generic_get_data->is_inband) {
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002223 if (data->payload_size >= 4 * sizeof(uint32_t))
2224 pr_debug("%s: payload[1] = 0x%x, payload[2]=0x%x, payload[3]=0x%x\n",
2225 __func__, payload[1],
2226 payload[2], payload[3]);
2227 else
2228 pr_err("%s: payload size of %x is less than expected.\n",
2229 __func__,
2230 data->payload_size);
2231
2232 if (data->payload_size >=
2233 (4 + (payload[3]>>2))
2234 * sizeof(uint32_t)) {
2235 generic_get_data->size_in_ints =
2236 payload[3]>>2;
2237 for (i = 0; i < payload[3]>>2; i++) {
2238 generic_get_data->ints[i] =
2239 payload[4+i];
2240 pr_debug("%s: ASM callback val %i = %i\n",
2241 __func__, i,
2242 payload[4+i]);
2243 }
2244 } else {
2245 pr_err("%s: payload size of %x is less than expected.\n",
2246 __func__,
2247 data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302248 }
2249 pr_debug("%s: callback size in ints = %i\n",
2250 __func__,
2251 generic_get_data->size_in_ints);
2252 }
2253 if (atomic_read(&ac->cmd_state) && wakeup_flag) {
2254 atomic_set(&ac->cmd_state, 0);
2255 wake_up(&ac->cmd_wait);
2256 }
2257 break;
2258 }
2259 rtac_make_asm_callback(ac->session, payload,
2260 data->payload_size);
2261 break;
2262 case ASM_DATA_EVENT_READ_DONE_V2:{
2263
2264 struct audio_port_data *port = &ac->port[OUT];
2265
2266 config_debug_fs_read_cb();
2267
2268 dev_vdbg(ac->dev, "%s: ReadDone: status=%d buff_add=0x%x act_size=%d offset=%d\n",
2269 __func__, payload[READDONE_IDX_STATUS],
2270 payload[READDONE_IDX_BUFADD_LSW],
2271 payload[READDONE_IDX_SIZE],
2272 payload[READDONE_IDX_OFFSET]);
2273
2274 dev_vdbg(ac->dev, "%s: ReadDone:msw_ts=%d lsw_ts=%d memmap_hdl=0x%x flags=%d id=%d num=%d\n",
2275 __func__, payload[READDONE_IDX_MSW_TS],
2276 payload[READDONE_IDX_LSW_TS],
2277 payload[READDONE_IDX_MEMMAP_HDL],
2278 payload[READDONE_IDX_FLAGS],
2279 payload[READDONE_IDX_SEQ_ID],
2280 payload[READDONE_IDX_NUMFRAMES]);
2281
2282 if (ac->io_mode & SYNC_IO_MODE) {
2283 if (port->buf == NULL) {
2284 pr_err("%s: Unexpected Write Done\n", __func__);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002285 spin_unlock_irqrestore(
2286 &(session[session_id].session_lock),
2287 flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302288 return -EINVAL;
2289 }
2290 spin_lock_irqsave(&port->dsp_lock, dsp_flags);
2291 buf_index = asm_token._token.buf_index;
Vignesh Kulothunganb79df2f2019-01-22 10:31:21 -08002292 if (buf_index < 0 || buf_index >= port->max_buf_cnt) {
2293 pr_debug("%s: Invalid buffer index %u\n",
2294 __func__, buf_index);
2295 spin_unlock_irqrestore(&port->dsp_lock,
2296 dsp_flags);
2297 spin_unlock_irqrestore(
2298 &(session[session_id].session_lock),
2299 flags);
2300 return -EINVAL;
2301 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302302 port->buf[buf_index].used = 0;
2303 if (lower_32_bits(port->buf[buf_index].phys) !=
2304 payload[READDONE_IDX_BUFADD_LSW] ||
2305 msm_audio_populate_upper_32_bits(
2306 port->buf[buf_index].phys) !=
2307 payload[READDONE_IDX_BUFADD_MSW]) {
2308 dev_vdbg(ac->dev, "%s: Expected addr %pK\n",
2309 __func__, &port->buf[buf_index].phys);
2310 pr_err("%s: rxedl[0x%x] rxedu[0x%x]\n",
2311 __func__,
2312 payload[READDONE_IDX_BUFADD_LSW],
2313 payload[READDONE_IDX_BUFADD_MSW]);
2314 spin_unlock_irqrestore(&port->dsp_lock,
2315 dsp_flags);
2316 break;
2317 }
2318 port->buf[buf_index].actual_size =
2319 payload[READDONE_IDX_SIZE];
2320 spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
2321 }
2322 break;
2323 }
2324 case ASM_DATA_EVENT_EOS:
2325 case ASM_DATA_EVENT_RENDERED_EOS:
2326 pr_debug("%s: EOS ACK received: rxed session %d opcode 0x%x token 0x%x src %d dest %d\n",
2327 __func__, ac->session,
2328 data->opcode, data->token,
2329 data->src_port, data->dest_port);
2330 break;
2331 case ASM_SESSION_EVENTX_OVERFLOW:
2332 pr_debug("%s: ASM_SESSION_EVENTX_OVERFLOW session %d opcode 0x%x token 0x%x src %d dest %d\n",
2333 __func__, ac->session,
2334 data->opcode, data->token,
2335 data->src_port, data->dest_port);
2336 break;
2337 case ASM_SESSION_EVENT_RX_UNDERFLOW:
2338 pr_debug("%s: ASM_SESSION_EVENT_RX_UNDERFLOW session %d opcode 0x%x token 0x%x src %d dest %d\n",
2339 __func__, ac->session,
2340 data->opcode, data->token,
2341 data->src_port, data->dest_port);
2342 break;
2343 case ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3:
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002344 if (data->payload_size >= 3 * sizeof(uint32_t)) {
2345 dev_vdbg(ac->dev, "%s: ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3, payload[0] = %d, payload[1] = %d, payload[2] = %d\n",
2346 __func__,
2347 payload[0], payload[1], payload[2]);
2348 ac->time_stamp =
2349 (uint64_t)(((uint64_t)payload[2] << 32) |
2350 payload[1]);
2351 } else {
2352 dev_err(ac->dev, "%s: payload size of %x is less than expected.n",
2353 __func__, data->payload_size);
2354 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302355 if (atomic_cmpxchg(&ac->time_flag, 1, 0))
2356 wake_up(&ac->time_wait);
2357 break;
2358 case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
2359 case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY:
2360 pr_debug("%s: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY session %d opcode 0x%x token 0x%x src %d dest %d\n",
2361 __func__, ac->session,
2362 data->opcode, data->token,
2363 data->src_port, data->dest_port);
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002364 if (data->payload_size >= 4 * sizeof(uint32_t))
2365 pr_debug("%s: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, payload[0] = %d, payload[1] = %d, payload[2] = %d, payload[3] = %d\n",
2366 __func__,
2367 payload[0], payload[1], payload[2],
2368 payload[3]);
2369 else
2370 pr_debug("%s: payload size of %x is less than expected.\n",
2371 __func__, data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302372 break;
2373 case ASM_SESSION_CMDRSP_GET_MTMX_STRTR_PARAMS_V2:
2374 q6asm_process_mtmx_get_param_rsp(ac, (void *) payload);
2375 break;
2376 case ASM_STREAM_PP_EVENT:
2377 case ASM_STREAM_CMD_ENCDEC_EVENTS:
2378 case ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE:
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002379 if (data->payload_size >= 2 * sizeof(uint32_t))
2380 pr_debug("%s: ASM_STREAM_EVENT payload[0][0x%x] payload[1][0x%x]",
2381 __func__, payload[0], payload[1]);
2382 else
2383 pr_debug("%s: payload size of %x is less than expected.\n",
2384 __func__, data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302385 i = is_adsp_raise_event(data->opcode);
Meng Wang9730cdd2017-09-26 12:48:31 +08002386 if (i < 0) {
Meng Wangb6afa8c2017-11-30 17:55:05 +08002387 spin_unlock_irqrestore(
2388 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302389 return 0;
Meng Wang9730cdd2017-09-26 12:48:31 +08002390 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302391
2392 /* repack payload for asm_stream_pp_event
2393 * package is composed of event type + size + actual payload
2394 */
2395 payload_size = data->payload_size;
Xiaojun Sangae3d8862018-03-23 08:57:33 +08002396 if (payload_size > UINT_MAX
2397 - sizeof(struct msm_adsp_event_data)) {
2398 pr_err("%s: payload size = %d exceeds limit.\n",
2399 __func__, payload_size);
2400 spin_unlock(&(session[session_id].session_lock));
2401 return -EINVAL;
2402 }
2403
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302404 pp_event_package = kzalloc(payload_size
2405 + sizeof(struct msm_adsp_event_data),
2406 GFP_ATOMIC);
Meng Wang9730cdd2017-09-26 12:48:31 +08002407 if (!pp_event_package) {
Meng Wangb6afa8c2017-11-30 17:55:05 +08002408 spin_unlock_irqrestore(
2409 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302410 return -ENOMEM;
Meng Wang9730cdd2017-09-26 12:48:31 +08002411 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302412
2413 pp_event_package->event_type = i;
2414 pp_event_package->payload_len = payload_size;
2415 memcpy((void *)pp_event_package->payload,
2416 data->payload, payload_size);
2417 ac->cb(data->opcode, data->token,
2418 (void *)pp_event_package, ac->priv);
2419 kfree(pp_event_package);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002420 spin_unlock_irqrestore(
2421 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302422 return 0;
2423 case ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2:
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002424 if (data->payload_size >= 3 * sizeof(uint32_t))
2425 pr_debug("%s: ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2 sesion %d status 0x%x msw %u lsw %u\n",
2426 __func__, ac->session, payload[0], payload[2],
2427 payload[1]);
2428 else
2429 pr_err("%s: payload size of %x is less than expected.\n",
2430 __func__, data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302431 wake_up(&ac->cmd_wait);
2432 break;
2433 case ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2:
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002434 if (data->payload_size >= 3 * sizeof(uint32_t))
2435 pr_debug("%s: ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2 session %d status 0x%x msw %u lsw %u\n",
2436 __func__, ac->session,
2437 payload[0], payload[2],
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302438 payload[1]);
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002439 else
2440 pr_err("%s: payload size of %x is less than expected.\n",
2441 __func__, data->payload_size);
2442 if (data->payload_size >= 2 * sizeof(uint32_t) &&
2443 payload[0] == 0) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302444 atomic_set(&ac->cmd_state, 0);
2445 /* ignore msw, as a delay that large shouldn't happen */
2446 ac->path_delay = payload[1];
2447 } else {
2448 atomic_set(&ac->cmd_state, payload[0]);
2449 ac->path_delay = UINT_MAX;
2450 }
2451 wake_up(&ac->cmd_wait);
2452 break;
2453 }
2454 if (ac->cb)
2455 ac->cb(data->opcode, data->token,
2456 data->payload, ac->priv);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002457 spin_unlock_irqrestore(
2458 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302459 return 0;
2460}
2461
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302462/**
2463 * q6asm_is_cpu_buf_avail -
2464 * retrieve next CPU buf avail
2465 *
2466 * @dir: RX or TX direction
2467 * @ac: Audio client handle
2468 * @size: size pointer to be updated with size of buffer
2469 * @index: index pointer to be updated with
2470 * CPU buffer index available
2471 *
2472 * Returns buffer pointer on success or NULL on failure
2473 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302474void *q6asm_is_cpu_buf_avail(int dir, struct audio_client *ac, uint32_t *size,
2475 uint32_t *index)
2476{
2477 void *data;
2478 unsigned char idx;
2479 struct audio_port_data *port;
2480
2481 if (!ac || ((dir != IN) && (dir != OUT))) {
2482 pr_err("%s: ac %pK dir %d\n", __func__, ac, dir);
2483 return NULL;
2484 }
2485
2486 if (ac->io_mode & SYNC_IO_MODE) {
2487 port = &ac->port[dir];
2488
2489 mutex_lock(&port->lock);
2490 idx = port->cpu_buf;
2491 if (port->buf == NULL) {
2492 pr_err("%s: Buffer pointer null\n", __func__);
2493 mutex_unlock(&port->lock);
2494 return NULL;
2495 }
2496 /* dir 0: used = 0 means buf in use
2497 * dir 1: used = 1 means buf in use
2498 */
2499 if (port->buf[idx].used == dir) {
2500 /* To make it more robust, we could loop and get the
2501 * next avail buf, its risky though
2502 */
2503 pr_err("%s: Next buf idx[0x%x] not available, dir[%d]\n",
2504 __func__, idx, dir);
2505 mutex_unlock(&port->lock);
2506 return NULL;
2507 }
2508 *size = port->buf[idx].actual_size;
2509 *index = port->cpu_buf;
2510 data = port->buf[idx].data;
2511 dev_vdbg(ac->dev, "%s: session[%d]index[%d] data[%pK]size[%d]\n",
2512 __func__,
2513 ac->session,
2514 port->cpu_buf,
2515 data, *size);
2516 /* By default increase the cpu_buf cnt
2517 * user accesses this function,increase cpu
2518 * buf(to avoid another api)
2519 */
2520 port->buf[idx].used = dir;
2521 port->cpu_buf = q6asm_get_next_buf(ac, port->cpu_buf,
2522 port->max_buf_cnt);
2523 mutex_unlock(&port->lock);
2524 return data;
2525 }
2526 return NULL;
2527}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302528EXPORT_SYMBOL(q6asm_is_cpu_buf_avail);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302529
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302530/**
2531 * q6asm_cpu_buf_release -
2532 * releases cpu buffer for ASM
2533 *
2534 * @dir: RX or TX direction
2535 * @ac: Audio client handle
2536 *
2537 * Returns 0 on success or error on failure
2538 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302539int q6asm_cpu_buf_release(int dir, struct audio_client *ac)
2540{
2541 struct audio_port_data *port;
2542 int ret = 0;
2543 int idx;
2544
2545 if (!ac || ((dir != IN) && (dir != OUT))) {
2546 pr_err("%s: ac %pK dir %d\n", __func__, ac, dir);
2547 ret = -EINVAL;
2548 goto exit;
2549 }
2550
2551 if (ac->io_mode & SYNC_IO_MODE) {
2552 port = &ac->port[dir];
2553 mutex_lock(&port->lock);
2554 idx = port->cpu_buf;
2555 if (port->cpu_buf == 0) {
2556 port->cpu_buf = port->max_buf_cnt - 1;
2557 } else if (port->cpu_buf < port->max_buf_cnt) {
2558 port->cpu_buf = port->cpu_buf - 1;
2559 } else {
2560 pr_err("%s: buffer index(%d) out of range\n",
2561 __func__, port->cpu_buf);
2562 ret = -EINVAL;
2563 mutex_unlock(&port->lock);
2564 goto exit;
2565 }
2566 port->buf[port->cpu_buf].used = dir ^ 1;
2567 mutex_unlock(&port->lock);
2568 }
2569exit:
2570 return ret;
2571}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302572EXPORT_SYMBOL(q6asm_cpu_buf_release);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302573
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302574/**
2575 * q6asm_is_cpu_buf_avail_nolock -
2576 * retrieve next CPU buf avail without lock acquire
2577 *
2578 * @dir: RX or TX direction
2579 * @ac: Audio client handle
2580 * @size: size pointer to be updated with size of buffer
2581 * @index: index pointer to be updated with
2582 * CPU buffer index available
2583 *
2584 * Returns buffer pointer on success or NULL on failure
2585 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302586void *q6asm_is_cpu_buf_avail_nolock(int dir, struct audio_client *ac,
2587 uint32_t *size, uint32_t *index)
2588{
2589 void *data;
2590 unsigned char idx;
2591 struct audio_port_data *port;
2592
2593 if (!ac || ((dir != IN) && (dir != OUT))) {
2594 pr_err("%s: ac %pK dir %d\n", __func__, ac, dir);
2595 return NULL;
2596 }
2597
2598 port = &ac->port[dir];
2599
2600 idx = port->cpu_buf;
2601 if (port->buf == NULL) {
2602 pr_err("%s: Buffer pointer null\n", __func__);
2603 return NULL;
2604 }
2605 /*
2606 * dir 0: used = 0 means buf in use
2607 * dir 1: used = 1 means buf in use
2608 */
2609 if (port->buf[idx].used == dir) {
2610 /*
2611 * To make it more robust, we could loop and get the
2612 * next avail buf, its risky though
2613 */
2614 pr_err("%s: Next buf idx[0x%x] not available, dir[%d]\n",
2615 __func__, idx, dir);
2616 return NULL;
2617 }
2618 *size = port->buf[idx].actual_size;
2619 *index = port->cpu_buf;
2620 data = port->buf[idx].data;
2621 dev_vdbg(ac->dev, "%s: session[%d]index[%d] data[%pK]size[%d]\n",
2622 __func__, ac->session, port->cpu_buf,
2623 data, *size);
2624 /*
2625 * By default increase the cpu_buf cnt
2626 * user accesses this function,increase cpu
2627 * buf(to avoid another api)
2628 */
2629 port->buf[idx].used = dir;
2630 port->cpu_buf = q6asm_get_next_buf(ac, port->cpu_buf,
2631 port->max_buf_cnt);
2632 return data;
2633}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302634EXPORT_SYMBOL(q6asm_is_cpu_buf_avail_nolock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302635
2636int q6asm_is_dsp_buf_avail(int dir, struct audio_client *ac)
2637{
2638 int ret = -1;
2639 struct audio_port_data *port;
2640 uint32_t idx;
2641
2642 if (!ac || (dir != OUT)) {
2643 pr_err("%s: ac %pK dir %d\n", __func__, ac, dir);
2644 return ret;
2645 }
2646
2647 if (ac->io_mode & SYNC_IO_MODE) {
2648 port = &ac->port[dir];
2649
2650 mutex_lock(&port->lock);
2651 idx = port->dsp_buf;
2652
2653 if (port->buf[idx].used == (dir ^ 1)) {
2654 /* To make it more robust, we could loop and get the
2655 * next avail buf, its risky though
2656 */
2657 pr_err("%s: Next buf idx[0x%x] not available, dir[%d]\n",
2658 __func__, idx, dir);
2659 mutex_unlock(&port->lock);
2660 return ret;
2661 }
2662 dev_vdbg(ac->dev, "%s: session[%d]dsp_buf=%d cpu_buf=%d\n",
2663 __func__,
2664 ac->session, port->dsp_buf, port->cpu_buf);
2665 ret = ((port->dsp_buf != port->cpu_buf) ? 0 : -1);
2666 mutex_unlock(&port->lock);
2667 }
2668 return ret;
2669}
2670
2671static void __q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
2672 uint32_t pkt_size, uint32_t cmd_flg, uint32_t stream_id)
2673{
Vignesh Kulothungan023a5322018-06-21 11:13:29 -07002674 unsigned long flags = 0;
Meng Wangb6afa8c2017-11-30 17:55:05 +08002675
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302676 dev_vdbg(ac->dev, "%s: pkt_size=%d cmd_flg=%d session=%d stream_id=%d\n",
2677 __func__, pkt_size, cmd_flg, ac->session, stream_id);
2678 mutex_lock(&ac->cmd_lock);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002679 spin_lock_irqsave(&(session[ac->session].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302680 if (ac->apr == NULL) {
2681 pr_err("%s: AC APR handle NULL", __func__);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002682 spin_unlock_irqrestore(
2683 &(session[ac->session].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302684 mutex_unlock(&ac->cmd_lock);
2685 return;
2686 }
2687
2688 hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
2689 APR_HDR_LEN(sizeof(struct apr_hdr)),
2690 APR_PKT_VER);
2691 hdr->src_svc = ((struct apr_svc *)ac->apr)->id;
2692 hdr->src_domain = APR_DOMAIN_APPS;
2693 hdr->dest_svc = APR_SVC_ASM;
2694 hdr->dest_domain = APR_DOMAIN_ADSP;
2695 hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id);
2696 hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id);
2697 if (cmd_flg)
2698 q6asm_update_token(&hdr->token,
2699 ac->session,
2700 0, /* Stream ID is NA */
2701 0, /* Buffer index is NA */
2702 0, /* Direction flag is NA */
2703 WAIT_CMD);
2704
2705 hdr->pkt_size = pkt_size;
Meng Wangb6afa8c2017-11-30 17:55:05 +08002706 spin_unlock_irqrestore(
2707 &(session[ac->session].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302708 mutex_unlock(&ac->cmd_lock);
2709}
2710
2711static void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
2712 uint32_t pkt_size, uint32_t cmd_flg)
2713{
2714 __q6asm_add_hdr(ac, hdr, pkt_size, cmd_flg, ac->stream_id);
2715}
2716
2717static void q6asm_stream_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
2718 uint32_t pkt_size, uint32_t cmd_flg, int32_t stream_id)
2719{
2720 __q6asm_add_hdr(ac, hdr, pkt_size, cmd_flg, stream_id);
2721}
2722
2723static void __q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
2724 uint32_t pkt_size, uint32_t cmd_flg,
2725 uint32_t stream_id, u8 no_wait_flag)
2726{
2727 dev_vdbg(ac->dev, "%s: pkt_size = %d, cmd_flg = %d, session = %d stream_id=%d\n",
2728 __func__, pkt_size, cmd_flg, ac->session, stream_id);
2729 hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
2730 APR_HDR_LEN(sizeof(struct apr_hdr)),
2731 APR_PKT_VER);
2732 if (ac->apr == NULL) {
2733 pr_err("%s: AC APR is NULL", __func__);
2734 return;
2735 }
2736 hdr->src_svc = ((struct apr_svc *)ac->apr)->id;
2737 hdr->src_domain = APR_DOMAIN_APPS;
2738 hdr->dest_svc = APR_SVC_ASM;
2739 hdr->dest_domain = APR_DOMAIN_ADSP;
2740 hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id);
2741 hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id);
2742 if (cmd_flg) {
2743 q6asm_update_token(&hdr->token,
2744 ac->session,
2745 0, /* Stream ID is NA */
2746 0, /* Buffer index is NA */
2747 0, /* Direction flag is NA */
2748 no_wait_flag);
2749
2750 }
2751 hdr->pkt_size = pkt_size;
2752}
2753
2754static void q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
2755 uint32_t pkt_size, uint32_t cmd_flg)
2756{
2757 __q6asm_add_hdr_async(ac, hdr, pkt_size, cmd_flg,
2758 ac->stream_id, WAIT_CMD);
2759}
2760
2761static void q6asm_stream_add_hdr_async(struct audio_client *ac,
2762 struct apr_hdr *hdr, uint32_t pkt_size,
2763 uint32_t cmd_flg, int32_t stream_id)
2764{
2765 __q6asm_add_hdr_async(ac, hdr, pkt_size, cmd_flg,
2766 stream_id, NO_WAIT_CMD);
2767}
2768
2769static void q6asm_add_hdr_custom_topology(struct audio_client *ac,
2770 struct apr_hdr *hdr,
2771 uint32_t pkt_size)
2772{
2773 pr_debug("%s: pkt_size=%d session=%d\n",
2774 __func__, pkt_size, ac->session);
2775 if (ac->apr == NULL) {
2776 pr_err("%s: AC APR handle NULL\n", __func__);
2777 return;
2778 }
2779
2780 mutex_lock(&ac->cmd_lock);
2781 hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
2782 APR_HDR_LEN(sizeof(struct apr_hdr)),
2783 APR_PKT_VER);
2784 hdr->src_svc = ((struct apr_svc *)ac->apr)->id;
2785 hdr->src_domain = APR_DOMAIN_APPS;
2786 hdr->dest_svc = APR_SVC_ASM;
2787 hdr->dest_domain = APR_DOMAIN_ADSP;
2788 hdr->src_port = ((ac->session << 8) & 0xFF00) | 0x01;
2789 hdr->dest_port = 0;
2790 q6asm_update_token(&hdr->token,
2791 ac->session,
2792 0, /* Stream ID is NA */
2793 0, /* Buffer index is NA */
2794 0, /* Direction flag is NA */
2795 WAIT_CMD);
2796 hdr->pkt_size = pkt_size;
2797 mutex_unlock(&ac->cmd_lock);
2798}
2799
2800static void q6asm_add_mmaphdr(struct audio_client *ac, struct apr_hdr *hdr,
2801 u32 pkt_size, int dir)
2802{
2803 pr_debug("%s: pkt size=%d\n",
2804 __func__, pkt_size);
2805 hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
2806 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
2807 hdr->src_port = 0;
2808 hdr->dest_port = 0;
2809 q6asm_update_token(&hdr->token,
2810 ac->session,
2811 0, /* Stream ID is NA */
2812 0, /* Buffer index is NA */
2813 dir,
2814 WAIT_CMD);
2815 hdr->pkt_size = pkt_size;
2816}
2817
2818static int __q6asm_open_read(struct audio_client *ac,
2819 uint32_t format, uint16_t bits_per_sample,
2820 uint32_t pcm_format_block_ver,
2821 bool ts_mode)
2822{
2823 int rc = 0x00;
2824 struct asm_stream_cmd_open_read_v3 open;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07002825 struct q6asm_cal_info cal_info;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302826
2827 config_debug_fs_reset_index();
2828
2829 if (ac == NULL) {
2830 pr_err("%s: APR handle NULL\n", __func__);
2831 return -EINVAL;
2832 }
2833 if (ac->apr == NULL) {
2834 pr_err("%s: AC APR handle NULL\n", __func__);
2835 return -EINVAL;
2836 }
2837 pr_debug("%s: session[%d]\n", __func__, ac->session);
2838
2839 q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
2840 atomic_set(&ac->cmd_state, -1);
2841 open.hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V3;
2842 /* Stream prio : High, provide meta info with encoded frames */
2843 open.src_endpointype = ASM_END_POINT_DEVICE_MATRIX;
2844
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07002845 rc = q6asm_get_asm_topology_apptype(&cal_info);
2846 open.preprocopo_id = cal_info.topology_id;
2847
2848
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302849 open.bits_per_sample = bits_per_sample;
2850 open.mode_flags = 0x0;
2851
2852 ac->topology = open.preprocopo_id;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07002853 ac->app_type = cal_info.app_type;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302854 if (ac->perf_mode == LOW_LATENCY_PCM_MODE) {
2855 open.mode_flags |= ASM_LOW_LATENCY_TX_STREAM_SESSION <<
2856 ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
2857 } else {
2858 open.mode_flags |= ASM_LEGACY_STREAM_SESSION <<
2859 ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
2860 }
2861
2862 switch (format) {
2863 case FORMAT_LINEAR_PCM:
2864 open.mode_flags |= 0x00;
2865 open.enc_cfg_id = q6asm_get_pcm_format_id(pcm_format_block_ver);
2866 if (ts_mode)
2867 open.mode_flags |= ABSOLUTE_TIMESTAMP_ENABLE;
2868 break;
2869 case FORMAT_MPEG4_AAC:
2870 open.mode_flags |= BUFFER_META_ENABLE;
2871 open.enc_cfg_id = ASM_MEDIA_FMT_AAC_V2;
2872 break;
2873 case FORMAT_G711_ALAW_FS:
2874 open.mode_flags |= BUFFER_META_ENABLE;
2875 open.enc_cfg_id = ASM_MEDIA_FMT_G711_ALAW_FS;
2876 break;
2877 case FORMAT_G711_MLAW_FS:
2878 open.mode_flags |= BUFFER_META_ENABLE;
2879 open.enc_cfg_id = ASM_MEDIA_FMT_G711_MLAW_FS;
2880 break;
2881 case FORMAT_V13K:
2882 open.mode_flags |= BUFFER_META_ENABLE;
2883 open.enc_cfg_id = ASM_MEDIA_FMT_V13K_FS;
2884 break;
2885 case FORMAT_EVRC:
2886 open.mode_flags |= BUFFER_META_ENABLE;
2887 open.enc_cfg_id = ASM_MEDIA_FMT_EVRC_FS;
2888 break;
2889 case FORMAT_AMRNB:
2890 open.mode_flags |= BUFFER_META_ENABLE;
2891 open.enc_cfg_id = ASM_MEDIA_FMT_AMRNB_FS;
2892 break;
2893 case FORMAT_AMRWB:
2894 open.mode_flags |= BUFFER_META_ENABLE;
2895 open.enc_cfg_id = ASM_MEDIA_FMT_AMRWB_FS;
2896 break;
2897 default:
2898 pr_err("%s: Invalid format 0x%x\n",
2899 __func__, format);
2900 rc = -EINVAL;
2901 goto fail_cmd;
2902 }
2903 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
2904 if (rc < 0) {
2905 pr_err("%s: open failed op[0x%x]rc[%d]\n",
2906 __func__, open.hdr.opcode, rc);
2907 rc = -EINVAL;
2908 goto fail_cmd;
2909 }
2910 rc = wait_event_timeout(ac->cmd_wait,
2911 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
2912 if (!rc) {
2913 pr_err("%s: timeout. waited for open read\n",
2914 __func__);
2915 rc = -ETIMEDOUT;
2916 goto fail_cmd;
2917 }
2918 if (atomic_read(&ac->cmd_state) > 0) {
2919 pr_err("%s: DSP returned error[%s]\n",
2920 __func__, adsp_err_get_err_str(
2921 atomic_read(&ac->cmd_state)));
2922 rc = adsp_err_get_lnx_err_code(
2923 atomic_read(&ac->cmd_state));
2924 goto fail_cmd;
2925 }
2926
2927 ac->io_mode |= TUN_READ_IO_MODE;
2928
2929 return 0;
2930fail_cmd:
2931 return rc;
2932}
2933
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302934/**
2935 * q6asm_open_read -
2936 * command to open ASM in read mode
2937 *
2938 * @ac: Audio client handle
2939 * @format: capture format for ASM
2940 *
2941 * Returns 0 on success or error on failure
2942 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302943int q6asm_open_read(struct audio_client *ac,
2944 uint32_t format)
2945{
2946 return __q6asm_open_read(ac, format, 16,
2947 PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/,
2948 false/*ts_mode*/);
2949}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302950EXPORT_SYMBOL(q6asm_open_read);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302951
2952int q6asm_open_read_v2(struct audio_client *ac, uint32_t format,
2953 uint16_t bits_per_sample)
2954{
2955 return __q6asm_open_read(ac, format, bits_per_sample,
2956 PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/,
2957 false/*ts_mode*/);
2958}
2959
2960/*
2961 * asm_open_read_v3 - Opens audio capture session
2962 *
2963 * @ac: Client session handle
2964 * @format: encoder format
2965 * @bits_per_sample: bit width of capture session
2966 */
2967int q6asm_open_read_v3(struct audio_client *ac, uint32_t format,
2968 uint16_t bits_per_sample)
2969{
2970 return __q6asm_open_read(ac, format, bits_per_sample,
2971 PCM_MEDIA_FORMAT_V3/*media fmt block ver*/,
2972 false/*ts_mode*/);
2973}
2974EXPORT_SYMBOL(q6asm_open_read_v3);
2975
2976/*
2977 * asm_open_read_v4 - Opens audio capture session
2978 *
2979 * @ac: Client session handle
2980 * @format: encoder format
2981 * @bits_per_sample: bit width of capture session
2982 * @ts_mode: timestamp mode
2983 */
2984int q6asm_open_read_v4(struct audio_client *ac, uint32_t format,
2985 uint16_t bits_per_sample, bool ts_mode)
2986{
2987 return __q6asm_open_read(ac, format, bits_per_sample,
2988 PCM_MEDIA_FORMAT_V4 /*media fmt block ver*/,
2989 ts_mode);
2990}
2991EXPORT_SYMBOL(q6asm_open_read_v4);
2992
Dhanalakshmi Siddaniff8d0d92019-12-05 15:20:23 +05302993
2994/*
2995 * asm_open_read_v5 - Opens audio capture session
2996 *
2997 * @ac: Client session handle
2998 * @format: encoder format
2999 * @bits_per_sample: bit width of capture session
3000 * @ts_mode: timestamp mode
3001 */
3002int q6asm_open_read_v5(struct audio_client *ac, uint32_t format,
3003 uint16_t bits_per_sample, bool ts_mode,
3004 uint32_t enc_cfg_id)
3005{
3006 return __q6asm_open_read(ac, format, bits_per_sample,
3007 PCM_MEDIA_FORMAT_V5 /*media fmt block ver*/,
3008 ts_mode);
3009}
3010EXPORT_SYMBOL(q6asm_open_read_v5);
3011
3012
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303013/**
3014 * q6asm_open_write_compressed -
3015 * command to open ASM in compressed write mode
3016 *
3017 * @ac: Audio client handle
3018 * @format: playback format for ASM
3019 * @passthrough_flag: flag to indicate passthrough option
3020 *
3021 * Returns 0 on success or error on failure
3022 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303023int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format,
3024 uint32_t passthrough_flag)
3025{
3026 int rc = 0;
3027 struct asm_stream_cmd_open_write_compressed open;
3028
3029 if (ac == NULL) {
3030 pr_err("%s: ac[%pK] NULL\n", __func__, ac);
3031 rc = -EINVAL;
3032 goto fail_cmd;
3033 }
3034
3035 if (ac->apr == NULL) {
3036 pr_err("%s: APR handle[%pK] NULL\n", __func__, ac->apr);
3037 rc = -EINVAL;
3038 goto fail_cmd;
3039 }
3040 pr_debug("%s: session[%d] wr_format[0x%x]", __func__, ac->session,
3041 format);
3042
3043 q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
3044 open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED;
3045 atomic_set(&ac->cmd_state, -1);
3046
3047 switch (format) {
3048 case FORMAT_AC3:
3049 open.fmt_id = ASM_MEDIA_FMT_AC3;
3050 break;
3051 case FORMAT_EAC3:
3052 open.fmt_id = ASM_MEDIA_FMT_EAC3;
3053 break;
3054 case FORMAT_DTS:
3055 open.fmt_id = ASM_MEDIA_FMT_DTS;
3056 break;
3057 case FORMAT_DSD:
3058 open.fmt_id = ASM_MEDIA_FMT_DSD;
3059 break;
3060 case FORMAT_GEN_COMPR:
3061 open.fmt_id = ASM_MEDIA_FMT_GENERIC_COMPRESSED;
3062 break;
3063 case FORMAT_TRUEHD:
3064 open.fmt_id = ASM_MEDIA_FMT_TRUEHD;
3065 break;
3066 case FORMAT_IEC61937:
3067 open.fmt_id = ASM_MEDIA_FMT_IEC;
3068 break;
3069 default:
3070 pr_err("%s: Invalid format[%d]\n", __func__, format);
3071 rc = -EINVAL;
3072 goto fail_cmd;
3073 }
3074 /* Below flag indicates the DSP that Compressed audio input
3075 * stream is not IEC 61937 or IEC 60958 packetizied
3076 */
3077 if (passthrough_flag == COMPRESSED_PASSTHROUGH ||
3078 passthrough_flag == COMPRESSED_PASSTHROUGH_DSD ||
3079 passthrough_flag == COMPRESSED_PASSTHROUGH_GEN) {
3080 open.flags = 0x0;
3081 pr_debug("%s: Flag 0 COMPRESSED_PASSTHROUGH\n", __func__);
3082 } else if (passthrough_flag == COMPRESSED_PASSTHROUGH_CONVERT) {
3083 open.flags = 0x8;
3084 pr_debug("%s: Flag 8 - COMPRESSED_PASSTHROUGH_CONVERT\n",
3085 __func__);
3086 } else if (passthrough_flag == COMPRESSED_PASSTHROUGH_IEC61937) {
3087 open.flags = 0x1;
3088 pr_debug("%s: Flag 1 - COMPRESSED_PASSTHROUGH_IEC61937\n",
3089 __func__);
3090 } else {
3091 pr_err("%s: Invalid passthrough type[%d]\n",
3092 __func__, passthrough_flag);
3093 rc = -EINVAL;
3094 goto fail_cmd;
3095 }
3096 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
3097 if (rc < 0) {
3098 pr_err("%s: open failed op[0x%x]rc[%d]\n",
3099 __func__, open.hdr.opcode, rc);
3100 rc = -EINVAL;
3101 goto fail_cmd;
3102 }
3103 rc = wait_event_timeout(ac->cmd_wait,
3104 (atomic_read(&ac->cmd_state) >= 0), 1*HZ);
3105 if (!rc) {
3106 pr_err("%s: timeout. waited for OPEN_WRITE_COMPR rc[%d]\n",
3107 __func__, rc);
3108 rc = -ETIMEDOUT;
3109 goto fail_cmd;
3110 }
3111
3112 if (atomic_read(&ac->cmd_state) > 0) {
3113 pr_err("%s: DSP returned error[%s]\n",
3114 __func__, adsp_err_get_err_str(
3115 atomic_read(&ac->cmd_state)));
3116 rc = adsp_err_get_lnx_err_code(
3117 atomic_read(&ac->cmd_state));
3118 goto fail_cmd;
3119 }
3120
3121 return 0;
3122
3123fail_cmd:
3124 return rc;
3125}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303126EXPORT_SYMBOL(q6asm_open_write_compressed);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303127
3128static int __q6asm_open_write(struct audio_client *ac, uint32_t format,
3129 uint16_t bits_per_sample, uint32_t stream_id,
3130 bool is_gapless_mode,
3131 uint32_t pcm_format_block_ver)
3132{
3133 int rc = 0x00;
3134 struct asm_stream_cmd_open_write_v3 open;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003135 struct q6asm_cal_info cal_info;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303136
3137 if (ac == NULL) {
3138 pr_err("%s: APR handle NULL\n", __func__);
3139 return -EINVAL;
3140 }
3141 if (ac->apr == NULL) {
3142 pr_err("%s: AC APR handle NULL\n", __func__);
3143 return -EINVAL;
3144 }
3145
3146 dev_vdbg(ac->dev, "%s: session[%d] wr_format[0x%x]\n",
3147 __func__, ac->session, format);
3148
3149 q6asm_stream_add_hdr(ac, &open.hdr, sizeof(open), TRUE, stream_id);
3150 atomic_set(&ac->cmd_state, -1);
3151 /*
3152 * Updated the token field with stream/session for compressed playback
3153 * Platform driver must know the the stream with which the command is
3154 * associated
3155 */
3156 if (ac->io_mode & COMPRESSED_STREAM_IO)
3157 q6asm_update_token(&open.hdr.token,
3158 ac->session,
3159 stream_id,
3160 0, /* Buffer index is NA */
3161 0, /* Direction flag is NA */
3162 WAIT_CMD);
3163
3164 dev_vdbg(ac->dev, "%s: token = 0x%x, stream_id %d, session 0x%x\n",
3165 __func__, open.hdr.token, stream_id, ac->session);
3166 open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
3167 open.mode_flags = 0x00;
3168 if (ac->perf_mode == ULL_POST_PROCESSING_PCM_MODE)
3169 open.mode_flags |= ASM_ULL_POST_PROCESSING_STREAM_SESSION;
3170 else if (ac->perf_mode == ULTRA_LOW_LATENCY_PCM_MODE)
3171 open.mode_flags |= ASM_ULTRA_LOW_LATENCY_STREAM_SESSION;
3172 else if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
3173 open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION;
3174 else {
3175 open.mode_flags |= ASM_LEGACY_STREAM_SESSION;
3176 if (is_gapless_mode)
3177 open.mode_flags |= 1 << ASM_SHIFT_GAPLESS_MODE_FLAG;
3178 }
3179
3180 /* source endpoint : matrix */
3181 open.sink_endpointype = ASM_END_POINT_DEVICE_MATRIX;
3182 open.bits_per_sample = bits_per_sample;
3183
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003184 rc = q6asm_get_asm_topology_apptype(&cal_info);
3185 open.postprocopo_id = cal_info.topology_id;
3186
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303187 if (ac->perf_mode != LEGACY_PCM_MODE)
3188 open.postprocopo_id = ASM_STREAM_POSTPROCOPO_ID_NONE;
3189
3190 pr_debug("%s: perf_mode %d asm_topology 0x%x bps %d\n", __func__,
3191 ac->perf_mode, open.postprocopo_id, open.bits_per_sample);
3192
3193 /*
3194 * For Gapless playback it will use the same session for next stream,
3195 * So use the same topology
3196 */
3197 if (!ac->topology) {
3198 ac->topology = open.postprocopo_id;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003199 ac->app_type = cal_info.app_type;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303200 }
3201 switch (format) {
3202 case FORMAT_LINEAR_PCM:
3203 open.dec_fmt_id = q6asm_get_pcm_format_id(pcm_format_block_ver);
3204 break;
3205 case FORMAT_MPEG4_AAC:
3206 open.dec_fmt_id = ASM_MEDIA_FMT_AAC_V2;
3207 break;
3208 case FORMAT_MPEG4_MULTI_AAC:
3209 open.dec_fmt_id = ASM_MEDIA_FMT_AAC_V2;
3210 break;
3211 case FORMAT_WMA_V9:
3212 open.dec_fmt_id = ASM_MEDIA_FMT_WMA_V9_V2;
3213 break;
3214 case FORMAT_WMA_V10PRO:
3215 open.dec_fmt_id = ASM_MEDIA_FMT_WMA_V10PRO_V2;
3216 break;
3217 case FORMAT_MP3:
3218 open.dec_fmt_id = ASM_MEDIA_FMT_MP3;
3219 break;
3220 case FORMAT_AC3:
3221 open.dec_fmt_id = ASM_MEDIA_FMT_AC3;
3222 break;
3223 case FORMAT_EAC3:
3224 open.dec_fmt_id = ASM_MEDIA_FMT_EAC3;
3225 break;
3226 case FORMAT_MP2:
3227 open.dec_fmt_id = ASM_MEDIA_FMT_MP2;
3228 break;
3229 case FORMAT_FLAC:
3230 open.dec_fmt_id = ASM_MEDIA_FMT_FLAC;
3231 break;
3232 case FORMAT_ALAC:
3233 open.dec_fmt_id = ASM_MEDIA_FMT_ALAC;
3234 break;
3235 case FORMAT_VORBIS:
3236 open.dec_fmt_id = ASM_MEDIA_FMT_VORBIS;
3237 break;
3238 case FORMAT_APE:
3239 open.dec_fmt_id = ASM_MEDIA_FMT_APE;
3240 break;
3241 case FORMAT_DSD:
3242 open.dec_fmt_id = ASM_MEDIA_FMT_DSD;
3243 break;
3244 case FORMAT_APTX:
3245 open.dec_fmt_id = ASM_MEDIA_FMT_APTX;
3246 break;
3247 case FORMAT_GEN_COMPR:
3248 open.dec_fmt_id = ASM_MEDIA_FMT_GENERIC_COMPRESSED;
3249 break;
3250 default:
3251 pr_err("%s: Invalid format 0x%x\n", __func__, format);
3252 rc = -EINVAL;
3253 goto fail_cmd;
3254 }
3255 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
3256 if (rc < 0) {
3257 pr_err("%s: open failed op[0x%x]rc[%d]\n",
3258 __func__, open.hdr.opcode, rc);
3259 rc = -EINVAL;
3260 goto fail_cmd;
3261 }
3262 rc = wait_event_timeout(ac->cmd_wait,
3263 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
3264 if (!rc) {
3265 pr_err("%s: timeout. waited for open write\n", __func__);
3266 rc = -ETIMEDOUT;
3267 goto fail_cmd;
3268 }
3269 if (atomic_read(&ac->cmd_state) > 0) {
3270 pr_err("%s: DSP returned error[%s]\n",
3271 __func__, adsp_err_get_err_str(
3272 atomic_read(&ac->cmd_state)));
3273 rc = adsp_err_get_lnx_err_code(
3274 atomic_read(&ac->cmd_state));
3275 goto fail_cmd;
3276 }
3277 ac->io_mode |= TUN_WRITE_IO_MODE;
3278
3279 return 0;
3280fail_cmd:
3281 return rc;
3282}
3283
3284int q6asm_open_write(struct audio_client *ac, uint32_t format)
3285{
3286 return __q6asm_open_write(ac, format, 16, ac->stream_id,
3287 false /*gapless*/,
3288 PCM_MEDIA_FORMAT_V2 /*pcm_format_block_ver*/);
3289}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303290EXPORT_SYMBOL(q6asm_open_write);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303291
3292int q6asm_open_write_v2(struct audio_client *ac, uint32_t format,
3293 uint16_t bits_per_sample)
3294{
3295 return __q6asm_open_write(ac, format, bits_per_sample,
3296 ac->stream_id, false /*gapless*/,
3297 PCM_MEDIA_FORMAT_V2 /*pcm_format_block_ver*/);
3298}
3299
3300/*
3301 * q6asm_open_write_v3 - Opens audio playback session
3302 *
3303 * @ac: Client session handle
3304 * @format: decoder format
3305 * @bits_per_sample: bit width of playback session
3306 */
3307int q6asm_open_write_v3(struct audio_client *ac, uint32_t format,
3308 uint16_t bits_per_sample)
3309{
3310 return __q6asm_open_write(ac, format, bits_per_sample,
3311 ac->stream_id, false /*gapless*/,
3312 PCM_MEDIA_FORMAT_V3 /*pcm_format_block_ver*/);
3313}
3314EXPORT_SYMBOL(q6asm_open_write_v3);
3315
3316/*
3317 * q6asm_open_write_v4 - Opens audio playback session
3318 *
3319 * @ac: Client session handle
3320 * @format: decoder format
3321 * @bits_per_sample: bit width of playback session
3322 */
3323int q6asm_open_write_v4(struct audio_client *ac, uint32_t format,
3324 uint16_t bits_per_sample)
3325{
3326 return __q6asm_open_write(ac, format, bits_per_sample,
3327 ac->stream_id, false /*gapless*/,
3328 PCM_MEDIA_FORMAT_V4 /*pcm_format_block_ver*/);
3329}
3330EXPORT_SYMBOL(q6asm_open_write_v4);
3331
3332int q6asm_stream_open_write_v2(struct audio_client *ac, uint32_t format,
3333 uint16_t bits_per_sample, int32_t stream_id,
3334 bool is_gapless_mode)
3335{
3336 return __q6asm_open_write(ac, format, bits_per_sample,
3337 stream_id, is_gapless_mode,
3338 PCM_MEDIA_FORMAT_V2 /*pcm_format_block_ver*/);
3339}
3340
3341/*
3342 * q6asm_stream_open_write_v3 - Creates audio stream for playback
3343 *
3344 * @ac: Client session handle
3345 * @format: asm playback format
3346 * @bits_per_sample: bit width of requested stream
3347 * @stream_id: stream id of stream to be associated with this session
3348 * @is_gapless_mode: true if gapless mode needs to be enabled
3349 */
3350int q6asm_stream_open_write_v3(struct audio_client *ac, uint32_t format,
3351 uint16_t bits_per_sample, int32_t stream_id,
3352 bool is_gapless_mode)
3353{
3354 return __q6asm_open_write(ac, format, bits_per_sample,
3355 stream_id, is_gapless_mode,
3356 PCM_MEDIA_FORMAT_V3 /*pcm_format_block_ver*/);
3357}
3358EXPORT_SYMBOL(q6asm_stream_open_write_v3);
3359
3360/*
Dhanalakshmi Siddaniff8d0d92019-12-05 15:20:23 +05303361 * q6asm_open_write_v5 - Opens audio playback session
3362 *
3363 * @ac: Client session handle
3364 * @format: decoder format
3365 * @bits_per_sample: bit width of playback session
3366 */
3367int q6asm_open_write_v5(struct audio_client *ac, uint32_t format,
3368 uint16_t bits_per_sample)
3369{
3370 return __q6asm_open_write(ac, format, bits_per_sample,
3371 ac->stream_id, false /*gapless*/,
3372 PCM_MEDIA_FORMAT_V5 /*pcm_format_block_ver*/);
3373}
3374EXPORT_SYMBOL(q6asm_open_write_v5);
3375
3376
3377/*
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303378 * q6asm_stream_open_write_v4 - Creates audio stream for playback
3379 *
3380 * @ac: Client session handle
3381 * @format: asm playback format
3382 * @bits_per_sample: bit width of requested stream
3383 * @stream_id: stream id of stream to be associated with this session
3384 * @is_gapless_mode: true if gapless mode needs to be enabled
3385 */
3386int q6asm_stream_open_write_v4(struct audio_client *ac, uint32_t format,
3387 uint16_t bits_per_sample, int32_t stream_id,
3388 bool is_gapless_mode)
3389{
3390 return __q6asm_open_write(ac, format, bits_per_sample,
3391 stream_id, is_gapless_mode,
3392 PCM_MEDIA_FORMAT_V4 /*pcm_format_block_ver*/);
3393}
3394EXPORT_SYMBOL(q6asm_stream_open_write_v4);
3395
Dhanalakshmi Siddaniff8d0d92019-12-05 15:20:23 +05303396/*
3397 * q6asm_stream_open_write_v5 - Creates audio stream for playback
3398 *
3399 * @ac: Client session handle
3400 * @format: asm playback format
3401 * @bits_per_sample: bit width of requested stream
3402 * @stream_id: stream id of stream to be associated with this session
3403 * @is_gapless_mode: true if gapless mode needs to be enabled
3404 */
3405int q6asm_stream_open_write_v5(struct audio_client *ac, uint32_t format,
3406 uint16_t bits_per_sample, int32_t stream_id,
3407 bool is_gapless_mode)
3408{
3409 return __q6asm_open_write(ac, format, bits_per_sample,
3410 stream_id, is_gapless_mode,
3411 PCM_MEDIA_FORMAT_V5 /*pcm_format_block_ver*/);
3412}
3413EXPORT_SYMBOL(q6asm_stream_open_write_v5);
3414
3415
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303416static int __q6asm_open_read_write(struct audio_client *ac, uint32_t rd_format,
3417 uint32_t wr_format, bool is_meta_data_mode,
3418 uint32_t bits_per_sample,
3419 bool overwrite_topology, int topology)
3420{
3421 int rc = 0x00;
3422 struct asm_stream_cmd_open_readwrite_v2 open;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003423 struct q6asm_cal_info cal_info;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303424
3425 if (ac == NULL) {
3426 pr_err("%s: APR handle NULL\n", __func__);
3427 return -EINVAL;
3428 }
3429 if (ac->apr == NULL) {
3430 pr_err("%s: AC APR handle NULL\n", __func__);
3431 return -EINVAL;
3432 }
3433 pr_debug("%s: session[%d]\n", __func__, ac->session);
3434 pr_debug("%s: wr_format[0x%x]rd_format[0x%x]\n",
3435 __func__, wr_format, rd_format);
3436
3437 ac->io_mode |= NT_MODE;
3438 q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
3439 atomic_set(&ac->cmd_state, -1);
3440 open.hdr.opcode = ASM_STREAM_CMD_OPEN_READWRITE_V2;
3441
3442 open.mode_flags = is_meta_data_mode ? BUFFER_META_ENABLE : 0;
3443 open.bits_per_sample = bits_per_sample;
3444 /* source endpoint : matrix */
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003445 rc = q6asm_get_asm_topology_apptype(&cal_info);
3446 open.postprocopo_id = cal_info.topology_id;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303447
3448 open.postprocopo_id = overwrite_topology ?
3449 topology : open.postprocopo_id;
3450 ac->topology = open.postprocopo_id;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003451 ac->app_type = cal_info.app_type;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303452
3453
3454 switch (wr_format) {
3455 case FORMAT_LINEAR_PCM:
3456 case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
3457 open.dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
3458 break;
3459 case FORMAT_MPEG4_AAC:
3460 open.dec_fmt_id = ASM_MEDIA_FMT_AAC_V2;
3461 break;
3462 case FORMAT_MPEG4_MULTI_AAC:
3463 open.dec_fmt_id = ASM_MEDIA_FMT_AAC_V2;
3464 break;
3465 case FORMAT_WMA_V9:
3466 open.dec_fmt_id = ASM_MEDIA_FMT_WMA_V9_V2;
3467 break;
3468 case FORMAT_WMA_V10PRO:
3469 open.dec_fmt_id = ASM_MEDIA_FMT_WMA_V10PRO_V2;
3470 break;
3471 case FORMAT_AMRNB:
3472 open.dec_fmt_id = ASM_MEDIA_FMT_AMRNB_FS;
3473 break;
3474 case FORMAT_AMRWB:
3475 open.dec_fmt_id = ASM_MEDIA_FMT_AMRWB_FS;
3476 break;
3477 case FORMAT_AMR_WB_PLUS:
3478 open.dec_fmt_id = ASM_MEDIA_FMT_AMR_WB_PLUS_V2;
3479 break;
3480 case FORMAT_V13K:
3481 open.dec_fmt_id = ASM_MEDIA_FMT_V13K_FS;
3482 break;
3483 case FORMAT_EVRC:
3484 open.dec_fmt_id = ASM_MEDIA_FMT_EVRC_FS;
3485 break;
3486 case FORMAT_EVRCB:
3487 open.dec_fmt_id = ASM_MEDIA_FMT_EVRCB_FS;
3488 break;
3489 case FORMAT_EVRCWB:
3490 open.dec_fmt_id = ASM_MEDIA_FMT_EVRCWB_FS;
3491 break;
3492 case FORMAT_MP3:
3493 open.dec_fmt_id = ASM_MEDIA_FMT_MP3;
3494 break;
3495 case FORMAT_ALAC:
3496 open.dec_fmt_id = ASM_MEDIA_FMT_ALAC;
3497 break;
3498 case FORMAT_APE:
3499 open.dec_fmt_id = ASM_MEDIA_FMT_APE;
3500 break;
3501 case FORMAT_DSD:
3502 open.dec_fmt_id = ASM_MEDIA_FMT_DSD;
3503 break;
3504 case FORMAT_G711_ALAW_FS:
3505 open.dec_fmt_id = ASM_MEDIA_FMT_G711_ALAW_FS;
3506 break;
3507 case FORMAT_G711_MLAW_FS:
3508 open.dec_fmt_id = ASM_MEDIA_FMT_G711_MLAW_FS;
3509 break;
3510 default:
3511 pr_err("%s: Invalid format 0x%x\n",
3512 __func__, wr_format);
3513 rc = -EINVAL;
3514 goto fail_cmd;
3515 }
3516
3517 switch (rd_format) {
3518 case FORMAT_LINEAR_PCM:
3519 case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
3520 open.enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
3521 break;
3522 case FORMAT_MPEG4_AAC:
3523 open.enc_cfg_id = ASM_MEDIA_FMT_AAC_V2;
3524 break;
3525 case FORMAT_G711_ALAW_FS:
3526 open.enc_cfg_id = ASM_MEDIA_FMT_G711_ALAW_FS;
3527 break;
3528 case FORMAT_G711_MLAW_FS:
3529 open.enc_cfg_id = ASM_MEDIA_FMT_G711_MLAW_FS;
3530 break;
3531 case FORMAT_V13K:
3532 open.enc_cfg_id = ASM_MEDIA_FMT_V13K_FS;
3533 break;
3534 case FORMAT_EVRC:
3535 open.enc_cfg_id = ASM_MEDIA_FMT_EVRC_FS;
3536 break;
3537 case FORMAT_AMRNB:
3538 open.enc_cfg_id = ASM_MEDIA_FMT_AMRNB_FS;
3539 break;
3540 case FORMAT_AMRWB:
3541 open.enc_cfg_id = ASM_MEDIA_FMT_AMRWB_FS;
3542 break;
3543 case FORMAT_ALAC:
3544 open.enc_cfg_id = ASM_MEDIA_FMT_ALAC;
3545 break;
3546 case FORMAT_APE:
3547 open.enc_cfg_id = ASM_MEDIA_FMT_APE;
3548 break;
3549 default:
3550 pr_err("%s: Invalid format 0x%x\n",
3551 __func__, rd_format);
3552 rc = -EINVAL;
3553 goto fail_cmd;
3554 }
3555 dev_vdbg(ac->dev, "%s: rdformat[0x%x]wrformat[0x%x]\n", __func__,
3556 open.enc_cfg_id, open.dec_fmt_id);
3557
3558 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
3559 if (rc < 0) {
3560 pr_err("%s: open failed op[0x%x]rc[%d]\n",
3561 __func__, open.hdr.opcode, rc);
3562 rc = -EINVAL;
3563 goto fail_cmd;
3564 }
3565 rc = wait_event_timeout(ac->cmd_wait,
3566 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
3567 if (!rc) {
3568 pr_err("%s: timeout. waited for open read-write\n",
3569 __func__);
3570 rc = -ETIMEDOUT;
3571 goto fail_cmd;
3572 }
3573 if (atomic_read(&ac->cmd_state) > 0) {
3574 pr_err("%s: DSP returned error[%s]\n",
3575 __func__, adsp_err_get_err_str(
3576 atomic_read(&ac->cmd_state)));
3577 rc = adsp_err_get_lnx_err_code(
3578 atomic_read(&ac->cmd_state));
3579 goto fail_cmd;
3580 }
3581
3582 return 0;
3583fail_cmd:
3584 return rc;
3585}
3586
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303587/**
3588 * q6asm_open_read_write -
3589 * command to open ASM in read/write mode
3590 *
3591 * @ac: Audio client handle
3592 * @rd_format: capture format for ASM
3593 * @wr_format: playback format for ASM
3594 *
3595 * Returns 0 on success or error on failure
3596 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303597int q6asm_open_read_write(struct audio_client *ac, uint32_t rd_format,
3598 uint32_t wr_format)
3599{
3600 return __q6asm_open_read_write(ac, rd_format, wr_format,
3601 true/*meta data mode*/,
3602 16 /*bits_per_sample*/,
3603 false /*overwrite_topology*/, 0);
3604}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303605EXPORT_SYMBOL(q6asm_open_read_write);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303606
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303607/**
3608 * q6asm_open_read_write_v2 -
3609 * command to open ASM in bi-directional read/write mode
3610 *
3611 * @ac: Audio client handle
3612 * @rd_format: capture format for ASM
3613 * @wr_format: playback format for ASM
3614 * @is_meta_data_mode: mode to indicate if meta data present
3615 * @bits_per_sample: number of bits per sample
3616 * @overwrite_topology: topology to be overwritten flag
3617 * @topology: Topology for ASM
3618 *
3619 * Returns 0 on success or error on failure
3620 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303621int q6asm_open_read_write_v2(struct audio_client *ac, uint32_t rd_format,
3622 uint32_t wr_format, bool is_meta_data_mode,
3623 uint32_t bits_per_sample, bool overwrite_topology,
3624 int topology)
3625{
3626 return __q6asm_open_read_write(ac, rd_format, wr_format,
3627 is_meta_data_mode, bits_per_sample,
3628 overwrite_topology, topology);
3629}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303630EXPORT_SYMBOL(q6asm_open_read_write_v2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303631
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303632/**
3633 * q6asm_open_loopback_v2 -
3634 * command to open ASM in loopback mode
3635 *
3636 * @ac: Audio client handle
3637 * @bits_per_sample: number of bits per sample
3638 *
3639 * Returns 0 on success or error on failure
3640 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303641int q6asm_open_loopback_v2(struct audio_client *ac, uint16_t bits_per_sample)
3642{
3643 int rc = 0x00;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003644 struct q6asm_cal_info cal_info;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303645
3646 if (ac == NULL) {
3647 pr_err("%s: APR handle NULL\n", __func__);
3648 return -EINVAL;
3649 }
3650 if (ac->apr == NULL) {
3651 pr_err("%s: AC APR handle NULL\n", __func__);
3652 return -EINVAL;
3653 }
3654 pr_debug("%s: session[%d]\n", __func__, ac->session);
3655
3656 if (ac->perf_mode == LOW_LATENCY_PCM_MODE) {
3657 struct asm_stream_cmd_open_transcode_loopback_t open;
3658
3659 q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
3660 atomic_set(&ac->cmd_state, -1);
3661 open.hdr.opcode = ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK;
3662
3663 open.mode_flags = 0;
3664 open.src_endpoint_type = 0;
3665 open.sink_endpoint_type = 0;
3666 open.src_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
3667 open.sink_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
3668 /* source endpoint : matrix */
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003669 rc = q6asm_get_asm_topology_apptype(&cal_info);
3670 open.audproc_topo_id = cal_info.topology_id;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303671
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003672 ac->app_type = cal_info.app_type;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303673 if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
3674 open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION;
3675 else
3676 open.mode_flags |= ASM_LEGACY_STREAM_SESSION;
3677 ac->topology = open.audproc_topo_id;
3678 open.bits_per_sample = bits_per_sample;
3679 open.reserved = 0;
3680 pr_debug("%s: opening a transcode_loopback with mode_flags =[%d] session[%d]\n",
3681 __func__, open.mode_flags, ac->session);
3682
3683 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
3684 if (rc < 0) {
3685 pr_err("%s: open failed op[0x%x]rc[%d]\n",
3686 __func__, open.hdr.opcode, rc);
3687 rc = -EINVAL;
3688 goto fail_cmd;
3689 }
3690 } else {/*if(ac->perf_mode == LEGACY_PCM_MODE)*/
3691 struct asm_stream_cmd_open_loopback_v2 open;
3692
3693 q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
3694 atomic_set(&ac->cmd_state, -1);
3695 open.hdr.opcode = ASM_STREAM_CMD_OPEN_LOOPBACK_V2;
3696
3697 open.mode_flags = 0;
3698 open.src_endpointype = 0;
3699 open.sink_endpointype = 0;
3700 /* source endpoint : matrix */
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003701 rc = q6asm_get_asm_topology_apptype(&cal_info);
3702 open.postprocopo_id = cal_info.topology_id;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303703
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003704 ac->app_type = cal_info.app_type;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303705 ac->topology = open.postprocopo_id;
3706 open.bits_per_sample = bits_per_sample;
3707 open.reserved = 0;
3708 pr_debug("%s: opening a loopback_v2 with mode_flags =[%d] session[%d]\n",
3709 __func__, open.mode_flags, ac->session);
3710
3711 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
3712 if (rc < 0) {
3713 pr_err("%s: open failed op[0x%x]rc[%d]\n",
3714 __func__, open.hdr.opcode, rc);
3715 rc = -EINVAL;
3716 goto fail_cmd;
3717 }
3718 }
3719 rc = wait_event_timeout(ac->cmd_wait,
3720 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
3721 if (!rc) {
3722 pr_err("%s: timeout. waited for open_loopback\n",
3723 __func__);
3724 rc = -ETIMEDOUT;
3725 goto fail_cmd;
3726 }
3727 if (atomic_read(&ac->cmd_state) > 0) {
3728 pr_err("%s: DSP returned error[%s]\n",
3729 __func__, adsp_err_get_err_str(
3730 atomic_read(&ac->cmd_state)));
3731 rc = adsp_err_get_lnx_err_code(
3732 atomic_read(&ac->cmd_state));
3733 goto fail_cmd;
3734 }
3735
3736 return 0;
3737fail_cmd:
3738 return rc;
3739}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303740EXPORT_SYMBOL(q6asm_open_loopback_v2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303741
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303742/**
3743 * q6asm_open_transcode_loopback -
3744 * command to open ASM in transcode loopback mode
3745 *
3746 * @ac: Audio client handle
3747 * @bits_per_sample: number of bits per sample
3748 * @source_format: Format of clip
3749 * @sink_format: end device supported format
3750 *
3751 * Returns 0 on success or error on failure
3752 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303753int q6asm_open_transcode_loopback(struct audio_client *ac,
3754 uint16_t bits_per_sample,
3755 uint32_t source_format, uint32_t sink_format)
3756{
3757 int rc = 0x00;
3758 struct asm_stream_cmd_open_transcode_loopback_t open;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003759 struct q6asm_cal_info cal_info;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303760
3761 if (ac == NULL) {
3762 pr_err("%s: APR handle NULL\n", __func__);
3763 return -EINVAL;
3764 }
3765 if (ac->apr == NULL) {
3766 pr_err("%s: AC APR handle NULL\n", __func__);
3767 return -EINVAL;
3768 }
3769
3770 pr_debug("%s: session[%d]\n", __func__, ac->session);
3771
3772 q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
3773 atomic_set(&ac->cmd_state, -1);
3774 open.hdr.opcode = ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK;
3775
3776 open.mode_flags = 0;
3777 open.src_endpoint_type = 0;
3778 open.sink_endpoint_type = 0;
3779 switch (source_format) {
3780 case FORMAT_LINEAR_PCM:
3781 case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
3782 open.src_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3;
3783 break;
3784 case FORMAT_AC3:
3785 open.src_format_id = ASM_MEDIA_FMT_AC3;
3786 break;
3787 case FORMAT_EAC3:
3788 open.src_format_id = ASM_MEDIA_FMT_EAC3;
3789 break;
3790 default:
3791 pr_err("%s: Unsupported src fmt [%d]\n",
3792 __func__, source_format);
3793 return -EINVAL;
3794 }
3795 switch (sink_format) {
3796 case FORMAT_LINEAR_PCM:
3797 case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
3798 open.sink_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3;
3799 break;
3800 default:
3801 pr_err("%s: Unsupported sink fmt [%d]\n",
3802 __func__, sink_format);
3803 return -EINVAL;
3804 }
3805
3806 /* source endpoint : matrix */
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003807 rc = q6asm_get_asm_topology_apptype(&cal_info);
3808 open.audproc_topo_id = cal_info.topology_id;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303809
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003810
3811 ac->app_type = cal_info.app_type;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303812 if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
3813 open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION;
3814 else
3815 open.mode_flags |= ASM_LEGACY_STREAM_SESSION;
3816 ac->topology = open.audproc_topo_id;
3817 open.bits_per_sample = bits_per_sample;
3818 open.reserved = 0;
3819 pr_debug("%s: opening a transcode_loopback with mode_flags =[%d] session[%d]\n",
3820 __func__, open.mode_flags, ac->session);
3821
3822 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
3823 if (rc < 0) {
3824 pr_err("%s: open failed op[0x%x]rc[%d]\n",
3825 __func__, open.hdr.opcode, rc);
3826 rc = -EINVAL;
3827 goto fail_cmd;
3828 }
3829 rc = wait_event_timeout(ac->cmd_wait,
3830 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
3831 if (!rc) {
3832 pr_err("%s: timeout. waited for open_transcode_loopback\n",
3833 __func__);
3834 rc = -ETIMEDOUT;
3835 goto fail_cmd;
3836 }
3837 if (atomic_read(&ac->cmd_state) > 0) {
3838 pr_err("%s: DSP returned error[%s]\n",
3839 __func__, adsp_err_get_err_str(
3840 atomic_read(&ac->cmd_state)));
3841 rc = adsp_err_get_lnx_err_code(
3842 atomic_read(&ac->cmd_state));
3843 goto fail_cmd;
3844 }
3845
3846 return 0;
3847fail_cmd:
3848 return rc;
3849}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303850EXPORT_SYMBOL(q6asm_open_transcode_loopback);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303851
3852static
3853int q6asm_set_shared_circ_buff(struct audio_client *ac,
3854 struct asm_stream_cmd_open_shared_io *open,
3855 int bufsz, int bufcnt,
3856 int dir)
3857{
3858 struct audio_buffer *buf_circ;
3859 int bytes_to_alloc, rc;
3860 size_t len;
3861
Aditya Bavanaria8aea172017-09-13 11:37:53 +05303862 mutex_lock(&ac->cmd_lock);
3863
3864 if (ac->port[dir].buf) {
3865 pr_err("%s: Buffer already allocated\n", __func__);
3866 rc = -EINVAL;
Aditya Bavanaria8aea172017-09-13 11:37:53 +05303867 goto done;
3868 }
3869
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303870 buf_circ = kzalloc(sizeof(struct audio_buffer), GFP_KERNEL);
3871
3872 if (!buf_circ) {
3873 rc = -ENOMEM;
3874 goto done;
3875 }
3876
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303877 bytes_to_alloc = bufsz * bufcnt;
3878 bytes_to_alloc = PAGE_ALIGN(bytes_to_alloc);
3879
3880 rc = msm_audio_ion_alloc("audio_client", &buf_circ->client,
3881 &buf_circ->handle, bytes_to_alloc,
3882 (ion_phys_addr_t *)&buf_circ->phys,
3883 &len, &buf_circ->data);
3884
3885 if (rc) {
3886 pr_err("%s: Audio ION alloc is failed, rc = %d\n", __func__,
3887 rc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303888 kfree(buf_circ);
3889 goto done;
3890 }
3891
Aditya Bavanaria8aea172017-09-13 11:37:53 +05303892 ac->port[dir].buf = buf_circ;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303893 buf_circ->used = dir ^ 1;
3894 buf_circ->size = bytes_to_alloc;
3895 buf_circ->actual_size = bytes_to_alloc;
3896 memset(buf_circ->data, 0, buf_circ->actual_size);
3897
3898 ac->port[dir].max_buf_cnt = 1;
3899
3900 open->shared_circ_buf_mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
3901 open->shared_circ_buf_num_regions = 1;
3902 open->shared_circ_buf_property_flag = 0x00;
3903 open->shared_circ_buf_start_phy_addr_lsw =
3904 lower_32_bits(buf_circ->phys);
3905 open->shared_circ_buf_start_phy_addr_msw =
3906 msm_audio_populate_upper_32_bits(buf_circ->phys);
3907 open->shared_circ_buf_size = bufsz * bufcnt;
3908
3909 open->map_region_circ_buf.shm_addr_lsw = lower_32_bits(buf_circ->phys);
3910 open->map_region_circ_buf.shm_addr_msw =
3911 msm_audio_populate_upper_32_bits(buf_circ->phys);
3912 open->map_region_circ_buf.mem_size_bytes = bytes_to_alloc;
3913
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303914done:
Xiaoyu Yef423ab12017-11-22 11:38:29 -08003915 mutex_unlock(&ac->cmd_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303916 return rc;
3917}
3918
3919
3920static
3921int q6asm_set_shared_pos_buff(struct audio_client *ac,
3922 struct asm_stream_cmd_open_shared_io *open,
3923 int dir)
3924{
3925 struct audio_buffer *buf_pos = &ac->shared_pos_buf;
3926 int rc;
3927 size_t len;
3928 int bytes_to_alloc = sizeof(struct asm_shared_position_buffer);
3929
3930 mutex_lock(&ac->cmd_lock);
3931
3932 bytes_to_alloc = PAGE_ALIGN(bytes_to_alloc);
3933
3934 rc = msm_audio_ion_alloc("audio_client", &buf_pos->client,
3935 &buf_pos->handle, bytes_to_alloc,
3936 (ion_phys_addr_t *)&buf_pos->phys, &len,
3937 &buf_pos->data);
3938
3939 if (rc) {
3940 pr_err("%s: Audio pos buf ION alloc is failed, rc = %d\n",
3941 __func__, rc);
3942 goto done;
3943 }
3944
3945 buf_pos->used = dir ^ 1;
3946 buf_pos->size = bytes_to_alloc;
3947 buf_pos->actual_size = bytes_to_alloc;
3948
3949 open->shared_pos_buf_mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
3950 open->shared_pos_buf_num_regions = 1;
3951 open->shared_pos_buf_property_flag = 0x00;
3952 open->shared_pos_buf_phy_addr_lsw = lower_32_bits(buf_pos->phys);
3953 open->shared_pos_buf_phy_addr_msw =
3954 msm_audio_populate_upper_32_bits(buf_pos->phys);
3955
3956 open->map_region_pos_buf.shm_addr_lsw = lower_32_bits(buf_pos->phys);
3957 open->map_region_pos_buf.shm_addr_msw =
3958 msm_audio_populate_upper_32_bits(buf_pos->phys);
3959 open->map_region_pos_buf.mem_size_bytes = bytes_to_alloc;
3960
3961done:
3962 mutex_unlock(&ac->cmd_lock);
3963 return rc;
3964}
3965
3966/*
3967 * q6asm_open_shared_io: Open an ASM session for pull mode (playback)
3968 * or push mode (capture).
3969 * parameters
3970 * config - session parameters (channels, bits_per_sample, sr)
3971 * dir - stream direction (IN for playback, OUT for capture)
3972 * returns 0 if successful, error code otherwise
3973 */
3974int q6asm_open_shared_io(struct audio_client *ac,
3975 struct shared_io_config *config,
3976 int dir)
3977{
3978 struct asm_stream_cmd_open_shared_io *open;
3979 u8 *channel_mapping;
3980 int i, size_of_open, num_watermarks, bufsz, bufcnt, rc, flags = 0;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003981 struct q6asm_cal_info cal_info;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303982
3983 if (!ac || !config)
3984 return -EINVAL;
3985
Rohit kumar6a14cfb2019-02-04 11:22:49 +05303986 if (config->channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
3987 pr_err("%s: Invalid channel count %d\n", __func__,
3988 config->channels);
3989 return -EINVAL;
3990 }
3991
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303992 bufsz = config->bufsz;
3993 bufcnt = config->bufcnt;
3994 num_watermarks = 0;
3995
3996 ac->config = *config;
3997
3998 if (ac->session <= 0 || ac->session > SESSION_MAX) {
3999 pr_err("%s: Session %d is out of bounds\n",
4000 __func__, ac->session);
4001 return -EINVAL;
4002 }
4003
4004 size_of_open = sizeof(struct asm_stream_cmd_open_shared_io) +
4005 (sizeof(struct asm_shared_watermark_level) * num_watermarks);
4006
4007 open = kzalloc(PAGE_ALIGN(size_of_open), GFP_KERNEL);
4008 if (!open)
4009 return -ENOMEM;
4010
4011 q6asm_stream_add_hdr(ac, &open->hdr, size_of_open, TRUE,
4012 ac->stream_id);
4013
4014 atomic_set(&ac->cmd_state, 1);
4015
4016 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x, perf %d\n",
4017 __func__, open->hdr.token, ac->stream_id, ac->session,
4018 ac->perf_mode);
4019
4020 open->hdr.opcode =
4021 dir == IN ? ASM_STREAM_CMD_OPEN_PULL_MODE_WRITE :
4022 ASM_STREAM_CMD_OPEN_PUSH_MODE_READ;
4023
4024 pr_debug("%s perf_mode %d\n", __func__, ac->perf_mode);
4025 if (dir == IN)
4026 if (ac->perf_mode == ULL_POST_PROCESSING_PCM_MODE)
4027 flags = 4 << ASM_SHIFT_STREAM_PERF_FLAG_PULL_MODE_WRITE;
4028 else if (ac->perf_mode == ULTRA_LOW_LATENCY_PCM_MODE)
4029 flags = 2 << ASM_SHIFT_STREAM_PERF_FLAG_PULL_MODE_WRITE;
4030 else if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
4031 flags = 1 << ASM_SHIFT_STREAM_PERF_FLAG_PULL_MODE_WRITE;
4032 else
4033 pr_err("Invalid perf mode for pull write\n");
4034 else
4035 if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
4036 flags = ASM_LOW_LATENCY_TX_STREAM_SESSION <<
4037 ASM_SHIFT_STREAM_PERF_FLAG_PUSH_MODE_READ;
4038 else
4039 pr_err("Invalid perf mode for push read\n");
4040
4041 if (flags == 0) {
4042 pr_err("%s: Invalid mode[%d]\n", __func__,
4043 ac->perf_mode);
4044 kfree(open);
4045 return -EINVAL;
4046
4047 }
4048
4049 pr_debug("open.mode_flags = 0x%x\n", flags);
4050 open->mode_flags = flags;
4051 open->endpoint_type = ASM_END_POINT_DEVICE_MATRIX;
4052 open->topo_bits_per_sample = config->bits_per_sample;
4053
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07004054 rc = q6asm_get_asm_topology_apptype(&cal_info);
4055 open->topo_id = cal_info.topology_id;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304056
4057 if (config->format == FORMAT_LINEAR_PCM)
4058 open->fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3;
4059 else {
4060 pr_err("%s: Invalid format[%d]\n", __func__, config->format);
4061 rc = -EINVAL;
4062 goto done;
4063 }
4064
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304065 rc = q6asm_set_shared_circ_buff(ac, open, bufsz, bufcnt, dir);
4066
4067 if (rc)
4068 goto done;
4069
4070 ac->port[dir].tmp_hdl = 0;
4071
4072 rc = q6asm_set_shared_pos_buff(ac, open, dir);
4073
4074 if (rc)
4075 goto done;
4076
4077 /* asm_multi_channel_pcm_fmt_blk_v3 */
4078 open->fmt.num_channels = config->channels;
4079 open->fmt.bits_per_sample = config->bits_per_sample;
4080 open->fmt.sample_rate = config->rate;
4081 open->fmt.is_signed = 1;
4082 open->fmt.sample_word_size = config->sample_word_size;
4083
4084 channel_mapping = open->fmt.channel_mapping;
4085
4086 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
4087
4088 rc = q6asm_map_channels(channel_mapping, config->channels, false);
4089 if (rc) {
4090 pr_err("%s: Map channels failed, ret: %d\n", __func__, rc);
4091 goto done;
4092 }
4093
4094 open->num_watermark_levels = num_watermarks;
4095 for (i = 0; i < num_watermarks; i++) {
4096 open->watermark[i].watermark_level_bytes = i *
4097 ((bufsz * bufcnt) / num_watermarks);
4098 pr_debug("%s: Watermark level set for %i\n",
4099 __func__,
4100 open->watermark[i].watermark_level_bytes);
4101 }
4102
4103 rc = apr_send_pkt(ac->apr, (uint32_t *) open);
4104 if (rc < 0) {
4105 pr_err("%s: Open failed op[0x%x]rc[%d]\n",
4106 __func__, open->hdr.opcode, rc);
4107 goto done;
4108 }
4109
4110 pr_debug("%s: sent open apr pkt\n", __func__);
4111 rc = wait_event_timeout(ac->cmd_wait,
4112 (atomic_read(&ac->cmd_state) <= 0), 5*HZ);
4113 if (!rc) {
4114 pr_err("%s: Timeout. Waited for open write apr pkt rc[%d]\n",
4115 __func__, rc);
4116 rc = -ETIMEDOUT;
4117 goto done;
4118 }
4119
4120 if (atomic_read(&ac->cmd_state) < 0) {
4121 pr_err("%s: DSP returned error [%d]\n", __func__,
4122 atomic_read(&ac->cmd_state));
4123 rc = -EINVAL;
4124 goto done;
4125 }
4126
4127 ac->io_mode |= TUN_WRITE_IO_MODE;
4128 rc = 0;
4129done:
4130 kfree(open);
4131 return rc;
4132}
4133EXPORT_SYMBOL(q6asm_open_shared_io);
4134
4135/*
4136 * q6asm_shared_io_buf: Returns handle to the shared circular buffer being
4137 * used for pull/push mode.
4138 * parameters
4139 * dir - used to identify input/output port
4140 * returns buffer handle
4141 */
4142struct audio_buffer *q6asm_shared_io_buf(struct audio_client *ac,
4143 int dir)
4144{
4145 struct audio_port_data *port;
4146
4147 if (!ac) {
4148 pr_err("%s: ac is null\n", __func__);
4149 return NULL;
4150 }
4151 port = &ac->port[dir];
4152 return port->buf;
4153}
4154EXPORT_SYMBOL(q6asm_shared_io_buf);
4155
4156/*
4157 * q6asm_shared_io_free: Frees memory allocated for a pull/push session
4158 * parameters
4159 * dir - port direction
4160 * returns 0 if successful, error otherwise
4161 */
4162int q6asm_shared_io_free(struct audio_client *ac, int dir)
4163{
4164 struct audio_port_data *port;
4165
4166 if (!ac) {
4167 pr_err("%s: audio client is null\n", __func__);
4168 return -EINVAL;
4169 }
4170 port = &ac->port[dir];
4171 mutex_lock(&ac->cmd_lock);
4172 if (port->buf && port->buf->data) {
4173 msm_audio_ion_free(port->buf->client, port->buf->handle);
4174 port->buf->client = NULL;
4175 port->buf->handle = NULL;
4176 port->max_buf_cnt = 0;
4177 kfree(port->buf);
4178 port->buf = NULL;
4179 }
4180 if (ac->shared_pos_buf.data) {
4181 msm_audio_ion_free(ac->shared_pos_buf.client,
4182 ac->shared_pos_buf.handle);
4183 ac->shared_pos_buf.client = NULL;
4184 ac->shared_pos_buf.handle = NULL;
4185 }
4186 mutex_unlock(&ac->cmd_lock);
4187 return 0;
4188}
4189EXPORT_SYMBOL(q6asm_shared_io_free);
4190
4191/*
4192 * q6asm_get_shared_pos: Returns current read index/write index as observed
4193 * by the DSP. Note that this is an offset and iterates from [0,BUF_SIZE - 1]
4194 * parameters - (all output)
4195 * read_index - offset
4196 * wall_clk_msw1 - ADSP wallclock msw
4197 * wall_clk_lsw1 - ADSP wallclock lsw
4198 * returns 0 if successful, -EAGAIN if DSP failed to update after some
4199 * retries
4200 */
4201int q6asm_get_shared_pos(struct audio_client *ac, uint32_t *read_index,
4202 uint32_t *wall_clk_msw1, uint32_t *wall_clk_lsw1)
4203{
4204 struct asm_shared_position_buffer *pos_buf;
4205 uint32_t frame_cnt1, frame_cnt2;
4206 int i, j;
4207
4208 if (!ac) {
4209 pr_err("%s: audio client is null\n", __func__);
4210 return -EINVAL;
4211 }
4212
4213 pos_buf = ac->shared_pos_buf.data;
4214
4215 /* always try to get the latest update in the shared pos buffer */
4216 for (i = 0; i < 2; i++) {
4217 /* retry until there is an update from DSP */
4218 for (j = 0; j < 5; j++) {
4219 frame_cnt1 = pos_buf->frame_counter;
4220 if (frame_cnt1 != 0)
4221 break;
4222 }
4223
4224 *wall_clk_msw1 = pos_buf->wall_clock_us_msw;
4225 *wall_clk_lsw1 = pos_buf->wall_clock_us_lsw;
4226 *read_index = pos_buf->index;
4227 frame_cnt2 = pos_buf->frame_counter;
4228
4229 if (frame_cnt1 != frame_cnt2)
4230 continue;
4231 return 0;
4232 }
4233 pr_err("%s out of tries trying to get a good read, try again\n",
4234 __func__);
4235 return -EAGAIN;
4236}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304237EXPORT_SYMBOL(q6asm_get_shared_pos);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304238
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304239/**
4240 * q6asm_run -
4241 * command to set ASM to run state
4242 *
4243 * @ac: Audio client handle
4244 * @flags: Flags for session
4245 * @msw_ts: upper 32bits timestamp
4246 * @lsw_ts: lower 32bits timestamp
4247 *
4248 * Returns 0 on success or error on failure
4249 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304250int q6asm_run(struct audio_client *ac, uint32_t flags,
4251 uint32_t msw_ts, uint32_t lsw_ts)
4252{
4253 struct asm_session_cmd_run_v2 run;
4254 int rc;
4255
4256 if (ac == NULL) {
4257 pr_err("%s: APR handle NULL\n", __func__);
4258 return -EINVAL;
4259 }
4260 if (ac->apr == NULL) {
4261 pr_err("%s: AC APR handle NULL\n", __func__);
4262 return -EINVAL;
4263 }
4264 pr_debug("%s: session[%d]\n", __func__, ac->session);
4265
4266 q6asm_add_hdr(ac, &run.hdr, sizeof(run), TRUE);
4267 atomic_set(&ac->cmd_state, -1);
4268
4269 run.hdr.opcode = ASM_SESSION_CMD_RUN_V2;
4270 run.flags = flags;
4271 run.time_lsw = lsw_ts;
4272 run.time_msw = msw_ts;
4273
4274 config_debug_fs_run();
4275
4276 rc = apr_send_pkt(ac->apr, (uint32_t *) &run);
4277 if (rc < 0) {
4278 pr_err("%s: Commmand run failed[%d]",
4279 __func__, rc);
4280 rc = -EINVAL;
4281 goto fail_cmd;
4282 }
4283
4284 rc = wait_event_timeout(ac->cmd_wait,
4285 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4286 if (!rc) {
4287 pr_err("%s: timeout. waited for run success",
4288 __func__);
4289 rc = -ETIMEDOUT;
4290 goto fail_cmd;
4291 }
4292 if (atomic_read(&ac->cmd_state) > 0) {
4293 pr_err("%s: DSP returned error[%s]\n",
4294 __func__, adsp_err_get_err_str(
4295 atomic_read(&ac->cmd_state)));
4296 rc = adsp_err_get_lnx_err_code(
4297 atomic_read(&ac->cmd_state));
4298 goto fail_cmd;
4299 }
4300
4301 return 0;
4302fail_cmd:
4303 return rc;
4304}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304305EXPORT_SYMBOL(q6asm_run);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304306
4307static int __q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
4308 uint32_t msw_ts, uint32_t lsw_ts, uint32_t stream_id)
4309{
4310 struct asm_session_cmd_run_v2 run;
4311 int rc;
4312
4313 if (ac == NULL) {
4314 pr_err("%s: APR handle NULL\n", __func__);
4315 return -EINVAL;
4316 }
4317 if (ac->apr == NULL) {
4318 pr_err("%s: AC APR handle NULL\n", __func__);
4319 return -EINVAL;
4320 }
4321 pr_debug("%s: session[%d]\n", __func__, ac->session);
4322
4323 q6asm_stream_add_hdr_async(ac, &run.hdr, sizeof(run), TRUE, stream_id);
4324 atomic_set(&ac->cmd_state, 1);
4325 run.hdr.opcode = ASM_SESSION_CMD_RUN_V2;
4326 run.flags = flags;
4327 run.time_lsw = lsw_ts;
4328 run.time_msw = msw_ts;
4329
4330 rc = apr_send_pkt(ac->apr, (uint32_t *) &run);
4331 if (rc < 0) {
4332 pr_err("%s: Commmand run failed[%d]", __func__, rc);
4333 return -EINVAL;
4334 }
4335 return 0;
4336}
4337
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304338/**
4339 * q6asm_run_nowait -
4340 * command to set ASM to run state with no wait for ack
4341 *
4342 * @ac: Audio client handle
4343 * @flags: Flags for session
4344 * @msw_ts: upper 32bits timestamp
4345 * @lsw_ts: lower 32bits timestamp
4346 *
4347 * Returns 0 on success or error on failure
4348 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304349int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
4350 uint32_t msw_ts, uint32_t lsw_ts)
4351{
4352 return __q6asm_run_nowait(ac, flags, msw_ts, lsw_ts, ac->stream_id);
4353}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304354EXPORT_SYMBOL(q6asm_run_nowait);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304355
4356int q6asm_stream_run_nowait(struct audio_client *ac, uint32_t flags,
4357 uint32_t msw_ts, uint32_t lsw_ts, uint32_t stream_id)
4358{
4359 return __q6asm_run_nowait(ac, flags, msw_ts, lsw_ts, stream_id);
4360}
4361
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304362/**
4363 * q6asm_enc_cfg_blk_aac -
4364 * command to set encode cfg block for aac
4365 *
4366 * @ac: Audio client handle
4367 * @frames_per_buf: number of frames per buffer
4368 * @sample_rate: Sample rate
4369 * @channels: number of ASM channels
4370 * @bit_rate: Bit rate info
4371 * @mode: mode of AAC stream encode
4372 * @format: aac format flag
4373 *
4374 * Returns 0 on success or error on failure
4375 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304376int q6asm_enc_cfg_blk_aac(struct audio_client *ac,
4377 uint32_t frames_per_buf,
4378 uint32_t sample_rate, uint32_t channels,
4379 uint32_t bit_rate, uint32_t mode, uint32_t format)
4380{
4381 struct asm_aac_enc_cfg_v2 enc_cfg;
4382 int rc = 0;
4383
4384 pr_debug("%s: session[%d]frames[%d]SR[%d]ch[%d]bitrate[%d]mode[%d] format[%d]\n",
4385 __func__, ac->session, frames_per_buf,
4386 sample_rate, channels, bit_rate, mode, format);
4387
4388 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
4389 atomic_set(&ac->cmd_state, -1);
4390
4391 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4392 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
4393 enc_cfg.encdec.param_size = sizeof(struct asm_aac_enc_cfg_v2) -
4394 sizeof(struct asm_stream_cmd_set_encdec_param);
4395 enc_cfg.encblk.frames_per_buf = frames_per_buf;
4396 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
4397 sizeof(struct asm_enc_cfg_blk_param_v2);
4398 enc_cfg.bit_rate = bit_rate;
4399 enc_cfg.enc_mode = mode;
4400 enc_cfg.aac_fmt_flag = format;
4401 enc_cfg.channel_cfg = channels;
4402 enc_cfg.sample_rate = sample_rate;
4403
4404 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
4405 if (rc < 0) {
4406 pr_err("%s: Comamnd %d failed %d\n",
4407 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
4408 rc = -EINVAL;
4409 goto fail_cmd;
4410 }
4411 rc = wait_event_timeout(ac->cmd_wait,
4412 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4413 if (!rc) {
4414 pr_err("%s: timeout. waited for FORMAT_UPDATE\n",
4415 __func__);
4416 rc = -ETIMEDOUT;
4417 goto fail_cmd;
4418 }
4419 if (atomic_read(&ac->cmd_state) > 0) {
4420 pr_err("%s: DSP returned error[%s]\n",
4421 __func__, adsp_err_get_err_str(
4422 atomic_read(&ac->cmd_state)));
4423 rc = adsp_err_get_lnx_err_code(
4424 atomic_read(&ac->cmd_state));
4425 goto fail_cmd;
4426 }
4427 return 0;
4428fail_cmd:
4429 return rc;
4430}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304431EXPORT_SYMBOL(q6asm_enc_cfg_blk_aac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304432
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304433/**
4434 * q6asm_enc_cfg_blk_g711 -
4435 * command to set encode cfg block for g711
4436 *
4437 * @ac: Audio client handle
4438 * @frames_per_buf: number of frames per buffer
4439 * @sample_rate: Sample rate
4440 *
4441 * Returns 0 on success or error on failure
4442 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304443int q6asm_enc_cfg_blk_g711(struct audio_client *ac,
4444 uint32_t frames_per_buf,
4445 uint32_t sample_rate)
4446{
4447 struct asm_g711_enc_cfg_v2 enc_cfg;
4448 int rc = 0;
4449
4450 pr_debug("%s: session[%d]frames[%d]SR[%d]\n",
4451 __func__, ac->session, frames_per_buf,
4452 sample_rate);
4453
4454 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
4455 atomic_set(&ac->cmd_state, -1);
4456
4457 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4458 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
4459 enc_cfg.encdec.param_size = sizeof(struct asm_g711_enc_cfg_v2) -
4460 sizeof(struct asm_stream_cmd_set_encdec_param);
4461 enc_cfg.encblk.frames_per_buf = frames_per_buf;
4462 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
4463 sizeof(struct asm_enc_cfg_blk_param_v2);
4464 enc_cfg.sample_rate = sample_rate;
4465
4466 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
4467 if (rc < 0) {
4468 pr_err("%s: Comamnd %d failed %d\n",
4469 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
4470 rc = -EINVAL;
4471 goto fail_cmd;
4472 }
4473 rc = wait_event_timeout(ac->cmd_wait,
4474 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4475 if (!rc) {
4476 pr_err("%s: timeout. waited for FORMAT_UPDATE\n",
4477 __func__);
4478 rc = -ETIMEDOUT;
4479 goto fail_cmd;
4480 }
4481 if (atomic_read(&ac->cmd_state) > 0) {
4482 pr_err("%s: DSP returned error[%s]\n",
4483 __func__, adsp_err_get_err_str(
4484 atomic_read(&ac->cmd_state)));
4485 rc = adsp_err_get_lnx_err_code(
4486 atomic_read(&ac->cmd_state));
4487 goto fail_cmd;
4488 }
4489 return 0;
4490fail_cmd:
4491 return rc;
4492}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304493EXPORT_SYMBOL(q6asm_enc_cfg_blk_g711);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304494
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304495/**
4496 * q6asm_set_encdec_chan_map -
4497 * command to set encdec channel map
4498 *
4499 * @ac: Audio client handle
4500 * @channels: number of channels
4501 *
4502 * Returns 0 on success or error on failure
4503 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304504int q6asm_set_encdec_chan_map(struct audio_client *ac,
4505 uint32_t num_channels)
4506{
4507 struct asm_dec_out_chan_map_param chan_map;
4508 u8 *channel_mapping;
4509 int rc = 0;
4510
Rohit kumar6a14cfb2019-02-04 11:22:49 +05304511 if (num_channels > MAX_CHAN_MAP_CHANNELS) {
4512 pr_err("%s: Invalid channel count %d\n", __func__,
4513 num_channels);
4514 return -EINVAL;
4515 }
4516
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304517 pr_debug("%s: Session %d, num_channels = %d\n",
4518 __func__, ac->session, num_channels);
4519 q6asm_add_hdr(ac, &chan_map.hdr, sizeof(chan_map), TRUE);
4520 atomic_set(&ac->cmd_state, -1);
4521 chan_map.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4522 chan_map.encdec.param_id = ASM_PARAM_ID_DEC_OUTPUT_CHAN_MAP;
4523 chan_map.encdec.param_size = sizeof(struct asm_dec_out_chan_map_param) -
4524 (sizeof(struct apr_hdr) +
4525 sizeof(struct asm_stream_cmd_set_encdec_param));
4526 chan_map.num_channels = num_channels;
4527 channel_mapping = chan_map.channel_mapping;
4528 memset(channel_mapping, PCM_CHANNEL_NULL, MAX_CHAN_MAP_CHANNELS);
4529
4530 if (q6asm_map_channels(channel_mapping, num_channels, false)) {
4531 pr_err("%s: map channels failed %d\n", __func__, num_channels);
4532 return -EINVAL;
4533 }
4534
4535 rc = apr_send_pkt(ac->apr, (uint32_t *) &chan_map);
4536 if (rc < 0) {
4537 pr_err("%s: Command opcode[0x%x]paramid[0x%x] failed %d\n",
4538 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM,
4539 ASM_PARAM_ID_DEC_OUTPUT_CHAN_MAP, rc);
4540 goto fail_cmd;
4541 }
4542 rc = wait_event_timeout(ac->cmd_wait,
4543 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4544 if (!rc) {
4545 pr_err("%s: timeout opcode[0x%x]\n", __func__,
4546 chan_map.hdr.opcode);
4547 rc = -ETIMEDOUT;
4548 goto fail_cmd;
4549 }
4550 if (atomic_read(&ac->cmd_state) > 0) {
4551 pr_err("%s: DSP returned error[%s]\n",
4552 __func__, adsp_err_get_err_str(
4553 atomic_read(&ac->cmd_state)));
4554 rc = adsp_err_get_lnx_err_code(
4555 atomic_read(&ac->cmd_state));
4556 goto fail_cmd;
4557 }
4558 return 0;
4559fail_cmd:
4560 return rc;
4561}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304562EXPORT_SYMBOL(q6asm_set_encdec_chan_map);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304563
4564/*
Dhanalakshmi Siddaniff8d0d92019-12-05 15:20:23 +05304565 * q6asm_enc_cfg_blk_pcm_v5 - sends encoder configuration parameters
4566 *
4567 * @ac: Client session handle
4568 * @rate: sample rate
4569 * @channels: number of channels
4570 * @bits_per_sample: bit width of encoder session
4571 * @use_default_chmap: true if default channel map to be used
4572 * @use_back_flavor: to configure back left and right channel
4573 * @channel_map: input channel map
4574 * @sample_word_size: Size in bits of the word that holds a sample of a channel
4575 * @endianness: endianness of the pcm data
4576 * @mode: Mode to provide additional info about the pcm input data
4577 */
4578static int q6asm_enc_cfg_blk_pcm_v5(struct audio_client *ac,
4579 uint32_t rate, uint32_t channels,
4580 uint16_t bits_per_sample, bool use_default_chmap,
4581 bool use_back_flavor, u8 *channel_map,
4582 uint16_t sample_word_size, uint16_t endianness,
4583 uint16_t mode)
4584{
4585 struct asm_multi_channel_pcm_enc_cfg_v5 enc_cfg;
4586 struct asm_enc_cfg_blk_param_v2 enc_fg_blk;
4587 u8 *channel_mapping;
4588 u32 frames_per_buf = 0;
4589 int rc;
4590
4591 if (!use_default_chmap && (channel_map == NULL)) {
4592 pr_err("%s: No valid chan map and can't use default\n",
4593 __func__);
4594 rc = -EINVAL;
4595 goto fail_cmd;
4596 }
4597
4598 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
4599 pr_err("%s: Invalid channel count %d\n", __func__, channels);
4600 rc = -EINVAL;
4601 goto fail_cmd;
4602 }
4603
4604 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
4605 ac->session, rate, channels,
4606 bits_per_sample, sample_word_size);
4607
4608 memset(&enc_cfg, 0, sizeof(enc_cfg));
4609 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
4610 atomic_set(&ac->cmd_state, -1);
4611 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4612 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
4613 enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
4614 sizeof(enc_cfg.encdec);
4615 enc_cfg.encblk.frames_per_buf = frames_per_buf;
4616 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
4617 sizeof(enc_fg_blk);
4618 enc_cfg.num_channels = channels;
4619 enc_cfg.bits_per_sample = bits_per_sample;
4620 enc_cfg.sample_rate = rate;
4621 enc_cfg.is_signed = 1;
4622 enc_cfg.sample_word_size = sample_word_size;
4623 enc_cfg.endianness = endianness;
4624 enc_cfg.mode = mode;
4625 channel_mapping = enc_cfg.channel_mapping;
4626
4627 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL_V8);
4628
4629 if (use_default_chmap) {
4630 pr_debug("%s: setting default channel map for %d channels",
4631 __func__, channels);
4632 if (q6asm_map_channels(channel_mapping, channels,
4633 use_back_flavor)) {
4634 pr_err("%s: map channels failed %d\n",
4635 __func__, channels);
4636 rc = -EINVAL;
4637 goto fail_cmd;
4638 }
4639 } else {
4640 pr_debug("%s: Using pre-defined channel map", __func__);
4641 memcpy(channel_mapping, channel_map,
4642 PCM_FORMAT_MAX_NUM_CHANNEL_V8);
4643 }
4644
4645 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
4646 if (rc < 0) {
4647 pr_err("%s: Command open failed %d\n", __func__, rc);
4648 goto fail_cmd;
4649 }
4650 rc = wait_event_timeout(ac->cmd_wait,
4651 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4652 if (!rc) {
4653 pr_err("%s: timeout opcode[0x%x]\n",
4654 __func__, enc_cfg.hdr.opcode);
4655 rc = -ETIMEDOUT;
4656 goto fail_cmd;
4657 }
4658 if (atomic_read(&ac->cmd_state) > 0) {
4659 pr_err("%s: DSP returned error[%s]\n",
4660 __func__, adsp_err_get_err_str(
4661 atomic_read(&ac->cmd_state)));
4662 rc = adsp_err_get_lnx_err_code(
4663 atomic_read(&ac->cmd_state));
4664 goto fail_cmd;
4665 }
4666 return 0;
4667fail_cmd:
4668 return rc;
4669}
4670EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_v5);
4671
4672/*
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304673 * q6asm_enc_cfg_blk_pcm_v4 - sends encoder configuration parameters
4674 *
4675 * @ac: Client session handle
4676 * @rate: sample rate
4677 * @channels: number of channels
4678 * @bits_per_sample: bit width of encoder session
4679 * @use_default_chmap: true if default channel map to be used
4680 * @use_back_flavor: to configure back left and right channel
4681 * @channel_map: input channel map
4682 * @sample_word_size: Size in bits of the word that holds a sample of a channel
4683 * @endianness: endianness of the pcm data
4684 * @mode: Mode to provide additional info about the pcm input data
4685 */
4686int q6asm_enc_cfg_blk_pcm_v4(struct audio_client *ac,
4687 uint32_t rate, uint32_t channels,
4688 uint16_t bits_per_sample, bool use_default_chmap,
4689 bool use_back_flavor, u8 *channel_map,
4690 uint16_t sample_word_size, uint16_t endianness,
4691 uint16_t mode)
4692{
4693 struct asm_multi_channel_pcm_enc_cfg_v4 enc_cfg;
4694 struct asm_enc_cfg_blk_param_v2 enc_fg_blk;
4695 u8 *channel_mapping;
4696 u32 frames_per_buf = 0;
4697 int rc;
4698
4699 if (!use_default_chmap && (channel_map == NULL)) {
4700 pr_err("%s: No valid chan map and can't use default\n",
4701 __func__);
4702 rc = -EINVAL;
4703 goto fail_cmd;
4704 }
4705
Rohit kumar6a14cfb2019-02-04 11:22:49 +05304706 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
4707 pr_err("%s: Invalid channel count %d\n", __func__, channels);
4708 rc = -EINVAL;
4709 goto fail_cmd;
4710 }
4711
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304712 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
4713 ac->session, rate, channels,
4714 bits_per_sample, sample_word_size);
4715
4716 memset(&enc_cfg, 0, sizeof(enc_cfg));
4717 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
4718 atomic_set(&ac->cmd_state, -1);
4719 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4720 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
4721 enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
4722 sizeof(enc_cfg.encdec);
4723 enc_cfg.encblk.frames_per_buf = frames_per_buf;
4724 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
4725 sizeof(enc_fg_blk);
4726 enc_cfg.num_channels = channels;
4727 enc_cfg.bits_per_sample = bits_per_sample;
4728 enc_cfg.sample_rate = rate;
4729 enc_cfg.is_signed = 1;
4730 enc_cfg.sample_word_size = sample_word_size;
4731 enc_cfg.endianness = endianness;
4732 enc_cfg.mode = mode;
4733 channel_mapping = enc_cfg.channel_mapping;
4734
4735 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
4736
4737 if (use_default_chmap) {
4738 pr_debug("%s: setting default channel map for %d channels",
4739 __func__, channels);
4740 if (q6asm_map_channels(channel_mapping, channels,
4741 use_back_flavor)) {
4742 pr_err("%s: map channels failed %d\n",
4743 __func__, channels);
4744 rc = -EINVAL;
4745 goto fail_cmd;
4746 }
4747 } else {
4748 pr_debug("%s: Using pre-defined channel map", __func__);
4749 memcpy(channel_mapping, channel_map,
4750 PCM_FORMAT_MAX_NUM_CHANNEL);
4751 }
4752
4753 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
4754 if (rc < 0) {
4755 pr_err("%s: Command open failed %d\n", __func__, rc);
4756 goto fail_cmd;
4757 }
4758 rc = wait_event_timeout(ac->cmd_wait,
4759 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4760 if (!rc) {
4761 pr_err("%s: timeout opcode[0x%x]\n",
4762 __func__, enc_cfg.hdr.opcode);
4763 rc = -ETIMEDOUT;
4764 goto fail_cmd;
4765 }
4766 if (atomic_read(&ac->cmd_state) > 0) {
4767 pr_err("%s: DSP returned error[%s]\n",
4768 __func__, adsp_err_get_err_str(
4769 atomic_read(&ac->cmd_state)));
4770 rc = adsp_err_get_lnx_err_code(
4771 atomic_read(&ac->cmd_state));
4772 goto fail_cmd;
4773 }
4774 return 0;
4775fail_cmd:
4776 return rc;
4777}
4778EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_v4);
4779
4780/*
4781 * q6asm_enc_cfg_blk_pcm_v3 - sends encoder configuration parameters
4782 *
4783 * @ac: Client session handle
4784 * @rate: sample rate
4785 * @channels: number of channels
4786 * @bits_per_sample: bit width of encoder session
4787 * @use_default_chmap: true if default channel map to be used
4788 * @use_back_flavor: to configure back left and right channel
4789 * @channel_map: input channel map
4790 * @sample_word_size: Size in bits of the word that holds a sample of a channel
4791 */
4792int q6asm_enc_cfg_blk_pcm_v3(struct audio_client *ac,
4793 uint32_t rate, uint32_t channels,
4794 uint16_t bits_per_sample, bool use_default_chmap,
4795 bool use_back_flavor, u8 *channel_map,
4796 uint16_t sample_word_size)
4797{
4798 struct asm_multi_channel_pcm_enc_cfg_v3 enc_cfg;
4799 struct asm_enc_cfg_blk_param_v2 enc_fg_blk;
4800 u8 *channel_mapping;
4801 u32 frames_per_buf = 0;
4802 int rc;
4803
4804 if (!use_default_chmap && (channel_map == NULL)) {
4805 pr_err("%s: No valid chan map and can't use default\n",
4806 __func__);
4807 rc = -EINVAL;
4808 goto fail_cmd;
4809 }
4810
Rohit kumar6a14cfb2019-02-04 11:22:49 +05304811 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
4812 pr_err("%s: Invalid channel count %d\n", __func__, channels);
4813 rc = -EINVAL;
4814 goto fail_cmd;
4815 }
4816
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304817 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
4818 ac->session, rate, channels,
4819 bits_per_sample, sample_word_size);
4820
4821 memset(&enc_cfg, 0, sizeof(enc_cfg));
4822 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
4823 atomic_set(&ac->cmd_state, -1);
4824 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4825 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
4826 enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
4827 sizeof(enc_cfg.encdec);
4828 enc_cfg.encblk.frames_per_buf = frames_per_buf;
4829 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
4830 sizeof(enc_fg_blk);
4831 enc_cfg.num_channels = channels;
4832 enc_cfg.bits_per_sample = bits_per_sample;
4833 enc_cfg.sample_rate = rate;
4834 enc_cfg.is_signed = 1;
4835 enc_cfg.sample_word_size = sample_word_size;
4836 channel_mapping = enc_cfg.channel_mapping;
4837
4838 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
4839
4840 if (use_default_chmap) {
4841 pr_debug("%s: setting default channel map for %d channels",
4842 __func__, channels);
4843 if (q6asm_map_channels(channel_mapping, channels,
4844 use_back_flavor)) {
4845 pr_err("%s: map channels failed %d\n",
4846 __func__, channels);
4847 rc = -EINVAL;
4848 goto fail_cmd;
4849 }
4850 } else {
4851 pr_debug("%s: Using pre-defined channel map", __func__);
4852 memcpy(channel_mapping, channel_map,
4853 PCM_FORMAT_MAX_NUM_CHANNEL);
4854 }
4855
4856 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
4857 if (rc < 0) {
4858 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
4859 goto fail_cmd;
4860 }
4861 rc = wait_event_timeout(ac->cmd_wait,
4862 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4863 if (!rc) {
4864 pr_err("%s: timeout opcode[0x%x]\n",
4865 __func__, enc_cfg.hdr.opcode);
4866 rc = -ETIMEDOUT;
4867 goto fail_cmd;
4868 }
4869 if (atomic_read(&ac->cmd_state) > 0) {
4870 pr_err("%s: DSP returned error[%s]\n",
4871 __func__, adsp_err_get_err_str(
4872 atomic_read(&ac->cmd_state)));
4873 rc = adsp_err_get_lnx_err_code(
4874 atomic_read(&ac->cmd_state));
4875 goto fail_cmd;
4876 }
4877 return 0;
4878fail_cmd:
4879 return rc;
4880}
4881EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_v3);
4882
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304883/**
4884 * q6asm_enc_cfg_blk_pcm_v2 -
4885 * command to set encode config block for pcm_v2
4886 *
4887 * @ac: Audio client handle
4888 * @rate: sample rate
4889 * @channels: number of channels
4890 * @bits_per_sample: number of bits per sample
4891 * @use_default_chmap: Flag indicating to use default ch_map or not
4892 * @use_back_flavor: back flavor flag
4893 * @channel_map: Custom channel map settings
4894 *
4895 * Returns 0 on success or error on failure
4896 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304897int q6asm_enc_cfg_blk_pcm_v2(struct audio_client *ac,
4898 uint32_t rate, uint32_t channels, uint16_t bits_per_sample,
4899 bool use_default_chmap, bool use_back_flavor, u8 *channel_map)
4900{
4901 struct asm_multi_channel_pcm_enc_cfg_v2 enc_cfg;
4902 u8 *channel_mapping;
4903 u32 frames_per_buf = 0;
4904
4905 int rc = 0;
4906
4907 if (!use_default_chmap && (channel_map == NULL)) {
4908 pr_err("%s: No valid chan map and can't use default\n",
4909 __func__);
4910 return -EINVAL;
4911 }
4912
Rohit kumar6a14cfb2019-02-04 11:22:49 +05304913 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
4914 pr_err("%s: Invalid channel count %d\n", __func__, channels);
4915 return -EINVAL;
4916 }
4917
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304918 pr_debug("%s: Session %d, rate = %d, channels = %d\n", __func__,
4919 ac->session, rate, channels);
4920
4921 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
4922 atomic_set(&ac->cmd_state, -1);
4923 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4924 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
4925 enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
4926 sizeof(enc_cfg.encdec);
4927 enc_cfg.encblk.frames_per_buf = frames_per_buf;
4928 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
4929 sizeof(struct asm_enc_cfg_blk_param_v2);
4930
4931 enc_cfg.num_channels = channels;
4932 enc_cfg.bits_per_sample = bits_per_sample;
4933 enc_cfg.sample_rate = rate;
4934 enc_cfg.is_signed = 1;
4935 channel_mapping = enc_cfg.channel_mapping;
4936
4937 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
4938
4939 if (use_default_chmap) {
4940 pr_debug("%s: setting default channel map for %d channels",
4941 __func__, channels);
4942 if (q6asm_map_channels(channel_mapping, channels,
4943 use_back_flavor)) {
4944 pr_err("%s: map channels failed %d\n",
4945 __func__, channels);
4946 return -EINVAL;
4947 }
4948 } else {
4949 pr_debug("%s: Using pre-defined channel map", __func__);
4950 memcpy(channel_mapping, channel_map,
4951 PCM_FORMAT_MAX_NUM_CHANNEL);
4952 }
4953
4954 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
4955 if (rc < 0) {
4956 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
4957 rc = -EINVAL;
4958 goto fail_cmd;
4959 }
4960 rc = wait_event_timeout(ac->cmd_wait,
4961 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4962 if (!rc) {
4963 pr_err("%s: timeout opcode[0x%x]\n",
4964 __func__, enc_cfg.hdr.opcode);
4965 rc = -ETIMEDOUT;
4966 goto fail_cmd;
4967 }
4968 if (atomic_read(&ac->cmd_state) > 0) {
4969 pr_err("%s: DSP returned error[%s]\n",
4970 __func__, adsp_err_get_err_str(
4971 atomic_read(&ac->cmd_state)));
4972 rc = adsp_err_get_lnx_err_code(
4973 atomic_read(&ac->cmd_state));
4974 goto fail_cmd;
4975 }
4976 return 0;
4977fail_cmd:
4978 return rc;
4979}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304980EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_v2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304981
Dhanalakshmi Siddaniff8d0d92019-12-05 15:20:23 +05304982static int __q6asm_enc_cfg_blk_pcm_v5(struct audio_client *ac,
4983 uint32_t rate, uint32_t channels,
4984 uint16_t bits_per_sample,
4985 uint16_t sample_word_size,
4986 uint16_t endianness,
4987 uint16_t mode)
4988{
4989 return q6asm_enc_cfg_blk_pcm_v5(ac, rate, channels,
4990 bits_per_sample, true, false, NULL,
4991 sample_word_size, endianness, mode);
4992}
4993
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304994static int __q6asm_enc_cfg_blk_pcm_v4(struct audio_client *ac,
4995 uint32_t rate, uint32_t channels,
4996 uint16_t bits_per_sample,
4997 uint16_t sample_word_size,
4998 uint16_t endianness,
4999 uint16_t mode)
5000{
5001 return q6asm_enc_cfg_blk_pcm_v4(ac, rate, channels,
5002 bits_per_sample, true, false, NULL,
5003 sample_word_size, endianness, mode);
5004}
5005
5006static int __q6asm_enc_cfg_blk_pcm_v3(struct audio_client *ac,
5007 uint32_t rate, uint32_t channels,
5008 uint16_t bits_per_sample,
5009 uint16_t sample_word_size)
5010{
5011 return q6asm_enc_cfg_blk_pcm_v3(ac, rate, channels,
5012 bits_per_sample, true, false, NULL,
5013 sample_word_size);
5014}
5015
5016static int __q6asm_enc_cfg_blk_pcm(struct audio_client *ac,
5017 uint32_t rate, uint32_t channels, uint16_t bits_per_sample)
5018{
5019 return q6asm_enc_cfg_blk_pcm_v2(ac, rate, channels,
5020 bits_per_sample, true, false, NULL);
5021}
5022
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305023/**
5024 * q6asm_enc_cfg_blk_pcm -
5025 * command to set encode config block for pcm
5026 *
5027 * @ac: Audio client handle
5028 * @rate: sample rate
5029 * @channels: number of channels
5030 *
5031 * Returns 0 on success or error on failure
5032 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305033int q6asm_enc_cfg_blk_pcm(struct audio_client *ac,
5034 uint32_t rate, uint32_t channels)
5035{
5036 return __q6asm_enc_cfg_blk_pcm(ac, rate, channels, 16);
5037}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305038EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305039
5040int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
5041 uint32_t rate, uint32_t channels, uint16_t bits_per_sample)
5042{
5043 return __q6asm_enc_cfg_blk_pcm(ac, rate, channels, bits_per_sample);
5044}
5045
5046/*
5047 * q6asm_enc_cfg_blk_pcm_format_support_v3 - sends encoder configuration
5048 * parameters
5049 *
5050 * @ac: Client session handle
5051 * @rate: sample rate
5052 * @channels: number of channels
5053 * @bits_per_sample: bit width of encoder session
5054 * @sample_word_size: Size in bits of the word that holds a sample of a channel
5055 */
5056int q6asm_enc_cfg_blk_pcm_format_support_v3(struct audio_client *ac,
5057 uint32_t rate, uint32_t channels,
5058 uint16_t bits_per_sample,
5059 uint16_t sample_word_size)
5060{
5061 return __q6asm_enc_cfg_blk_pcm_v3(ac, rate, channels,
5062 bits_per_sample, sample_word_size);
5063}
5064EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_format_support_v3);
5065
5066/*
5067 * q6asm_enc_cfg_blk_pcm_format_support_v4 - sends encoder configuration
5068 * parameters
5069 *
5070 * @ac: Client session handle
5071 * @rate: sample rate
5072 * @channels: number of channels
5073 * @bits_per_sample: bit width of encoder session
5074 * @sample_word_size: Size in bits of the word that holds a sample of a channel
5075 * @endianness: endianness of the pcm data
5076 * @mode: Mode to provide additional info about the pcm input data
5077 */
5078int q6asm_enc_cfg_blk_pcm_format_support_v4(struct audio_client *ac,
5079 uint32_t rate, uint32_t channels,
5080 uint16_t bits_per_sample,
5081 uint16_t sample_word_size,
5082 uint16_t endianness,
5083 uint16_t mode)
5084{
5085 return __q6asm_enc_cfg_blk_pcm_v4(ac, rate, channels,
5086 bits_per_sample, sample_word_size,
5087 endianness, mode);
5088}
5089EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_format_support_v4);
5090
Dhanalakshmi Siddaniff8d0d92019-12-05 15:20:23 +05305091/*
5092 * q6asm_enc_cfg_blk_pcm_format_support_v5 - sends encoder configuration
5093 * parameters
5094 *
5095 * @ac: Client session handle
5096 * @rate: sample rate
5097 * @channels: number of channels
5098 * @bits_per_sample: bit width of encoder session
5099 * @sample_word_size: Size in bits of the word that holds a sample of a channel
5100 * @endianness: endianness of the pcm data
5101 * @mode: Mode to provide additional info about the pcm input data
5102 */
5103int q6asm_enc_cfg_blk_pcm_format_support_v5(struct audio_client *ac,
5104 uint32_t rate, uint32_t channels,
5105 uint16_t bits_per_sample,
5106 uint16_t sample_word_size,
5107 uint16_t endianness,
5108 uint16_t mode)
5109{
5110 return __q6asm_enc_cfg_blk_pcm_v5(ac, rate, channels,
5111 bits_per_sample, sample_word_size,
5112 endianness, mode);
5113}
5114
5115EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_format_support_v5);
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305116/**
5117 * q6asm_enc_cfg_blk_pcm_native -
5118 * command to set encode config block for pcm_native
5119 *
5120 * @ac: Audio client handle
5121 * @rate: sample rate
5122 * @channels: number of channels
5123 *
5124 * Returns 0 on success or error on failure
5125 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305126int q6asm_enc_cfg_blk_pcm_native(struct audio_client *ac,
5127 uint32_t rate, uint32_t channels)
5128{
5129 struct asm_multi_channel_pcm_enc_cfg_v2 enc_cfg;
5130 u8 *channel_mapping;
5131 u32 frames_per_buf = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305132 int rc = 0;
5133
Rohit kumar6a14cfb2019-02-04 11:22:49 +05305134 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
5135 pr_err("%s: Invalid channel count %d\n", __func__, channels);
5136 return -EINVAL;
5137 }
5138
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305139 pr_debug("%s: Session %d, rate = %d, channels = %d\n", __func__,
5140 ac->session, rate, channels);
5141
5142 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
5143 atomic_set(&ac->cmd_state, -1);
5144 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
5145 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
5146 enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
5147 sizeof(enc_cfg.encdec);
5148 enc_cfg.encblk.frames_per_buf = frames_per_buf;
5149 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
5150 sizeof(struct asm_enc_cfg_blk_param_v2);
5151
5152 enc_cfg.num_channels = 0;/*channels;*/
5153 enc_cfg.bits_per_sample = 16;
5154 enc_cfg.sample_rate = 0;/*rate;*/
5155 enc_cfg.is_signed = 1;
5156 channel_mapping = enc_cfg.channel_mapping;
5157
5158
5159 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
5160
5161 if (q6asm_map_channels(channel_mapping, channels, false)) {
5162 pr_err("%s: map channels failed %d\n", __func__, channels);
5163 return -EINVAL;
5164 }
5165
5166 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
5167 if (rc < 0) {
5168 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
5169 rc = -EINVAL;
5170 goto fail_cmd;
5171 }
5172 rc = wait_event_timeout(ac->cmd_wait,
5173 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5174 if (!rc) {
5175 pr_err("%s: timeout opcode[0x%x]\n",
5176 __func__, enc_cfg.hdr.opcode);
5177 rc = -ETIMEDOUT;
5178 goto fail_cmd;
5179 }
5180 if (atomic_read(&ac->cmd_state) > 0) {
5181 pr_err("%s: DSP returned error[%s]\n",
5182 __func__, adsp_err_get_err_str(
5183 atomic_read(&ac->cmd_state)));
5184 rc = adsp_err_get_lnx_err_code(
5185 atomic_read(&ac->cmd_state));
5186 goto fail_cmd;
5187 }
5188 return 0;
5189fail_cmd:
5190 return rc;
5191}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305192EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_native);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305193
5194static int q6asm_map_channels(u8 *channel_mapping, uint32_t channels,
5195 bool use_back_flavor)
5196{
5197 u8 *lchannel_mapping;
5198
5199 lchannel_mapping = channel_mapping;
5200 pr_debug("%s: channels passed: %d\n", __func__, channels);
5201 if (channels == 1) {
5202 lchannel_mapping[0] = PCM_CHANNEL_FC;
5203 } else if (channels == 2) {
5204 lchannel_mapping[0] = PCM_CHANNEL_FL;
5205 lchannel_mapping[1] = PCM_CHANNEL_FR;
5206 } else if (channels == 3) {
5207 lchannel_mapping[0] = PCM_CHANNEL_FL;
5208 lchannel_mapping[1] = PCM_CHANNEL_FR;
5209 lchannel_mapping[2] = PCM_CHANNEL_FC;
5210 } else if (channels == 4) {
5211 lchannel_mapping[0] = PCM_CHANNEL_FL;
5212 lchannel_mapping[1] = PCM_CHANNEL_FR;
5213 lchannel_mapping[2] = use_back_flavor ?
5214 PCM_CHANNEL_LB : PCM_CHANNEL_LS;
5215 lchannel_mapping[3] = use_back_flavor ?
5216 PCM_CHANNEL_RB : PCM_CHANNEL_RS;
5217 } else if (channels == 5) {
5218 lchannel_mapping[0] = PCM_CHANNEL_FL;
5219 lchannel_mapping[1] = PCM_CHANNEL_FR;
5220 lchannel_mapping[2] = PCM_CHANNEL_FC;
5221 lchannel_mapping[3] = use_back_flavor ?
5222 PCM_CHANNEL_LB : PCM_CHANNEL_LS;
5223 lchannel_mapping[4] = use_back_flavor ?
5224 PCM_CHANNEL_RB : PCM_CHANNEL_RS;
5225 } else if (channels == 6) {
5226 lchannel_mapping[0] = PCM_CHANNEL_FL;
5227 lchannel_mapping[1] = PCM_CHANNEL_FR;
5228 lchannel_mapping[2] = PCM_CHANNEL_FC;
5229 lchannel_mapping[3] = PCM_CHANNEL_LFE;
5230 lchannel_mapping[4] = use_back_flavor ?
5231 PCM_CHANNEL_LB : PCM_CHANNEL_LS;
5232 lchannel_mapping[5] = use_back_flavor ?
5233 PCM_CHANNEL_RB : PCM_CHANNEL_RS;
5234 } else if (channels == 7) {
5235 /*
5236 * Configured for 5.1 channel mapping + 1 channel for debug
5237 * Can be customized based on DSP.
5238 */
5239 lchannel_mapping[0] = PCM_CHANNEL_FL;
5240 lchannel_mapping[1] = PCM_CHANNEL_FR;
5241 lchannel_mapping[2] = PCM_CHANNEL_FC;
5242 lchannel_mapping[3] = PCM_CHANNEL_LFE;
5243 lchannel_mapping[4] = use_back_flavor ?
5244 PCM_CHANNEL_LB : PCM_CHANNEL_LS;
5245 lchannel_mapping[5] = use_back_flavor ?
5246 PCM_CHANNEL_RB : PCM_CHANNEL_RS;
5247 lchannel_mapping[6] = PCM_CHANNEL_CS;
5248 } else if (channels == 8) {
5249 lchannel_mapping[0] = PCM_CHANNEL_FL;
5250 lchannel_mapping[1] = PCM_CHANNEL_FR;
5251 lchannel_mapping[2] = PCM_CHANNEL_FC;
5252 lchannel_mapping[3] = PCM_CHANNEL_LFE;
5253 lchannel_mapping[4] = PCM_CHANNEL_LB;
5254 lchannel_mapping[5] = PCM_CHANNEL_RB;
5255 lchannel_mapping[6] = PCM_CHANNEL_LS;
5256 lchannel_mapping[7] = PCM_CHANNEL_RS;
Dhanalakshmi Siddaniff8d0d92019-12-05 15:20:23 +05305257 } else if (channels == 12) {
5258 /*
5259 * Configured for 7.1.4 channel mapping
5260 * Todo: Needs to be checked
5261 */
5262 lchannel_mapping[0] = PCM_CHANNEL_FL;
5263 lchannel_mapping[1] = PCM_CHANNEL_FR;
5264 lchannel_mapping[2] = PCM_CHANNEL_FC;
5265 lchannel_mapping[3] = PCM_CHANNEL_LFE;
5266 lchannel_mapping[4] = PCM_CHANNEL_LB;
5267 lchannel_mapping[5] = PCM_CHANNEL_RB;
5268 lchannel_mapping[6] = PCM_CHANNEL_LS;
5269 lchannel_mapping[7] = PCM_CHANNEL_RS;
5270 lchannel_mapping[8] = PCM_CHANNEL_TFL;
5271 lchannel_mapping[9] = PCM_CHANNEL_TFR;
5272 lchannel_mapping[10] = PCM_CHANNEL_TSL;
5273 lchannel_mapping[11] = PCM_CHANNEL_TSR;
5274 } else if (channels == 16) {
5275 /*
5276 * Configured for 7.1.8 channel mapping
5277 * Todo: Needs to be checked
5278 */
5279 lchannel_mapping[0] = PCM_CHANNEL_FL;
5280 lchannel_mapping[1] = PCM_CHANNEL_FR;
5281 lchannel_mapping[2] = PCM_CHANNEL_FC;
5282 lchannel_mapping[3] = PCM_CHANNEL_LFE;
5283 lchannel_mapping[4] = PCM_CHANNEL_LB;
5284 lchannel_mapping[5] = PCM_CHANNEL_RB;
5285 lchannel_mapping[6] = PCM_CHANNEL_LS;
5286 lchannel_mapping[7] = PCM_CHANNEL_RS;
5287 lchannel_mapping[8] = PCM_CHANNEL_TFL;
5288 lchannel_mapping[9] = PCM_CHANNEL_TFR;
5289 lchannel_mapping[10] = PCM_CHANNEL_TSL;
5290 lchannel_mapping[11] = PCM_CHANNEL_TSR;
5291 lchannel_mapping[12] = PCM_CHANNEL_FLC;
5292 lchannel_mapping[13] = PCM_CHANNEL_FRC;
5293 lchannel_mapping[14] = PCM_CHANNEL_RLC;
5294 lchannel_mapping[15] = PCM_CHANNEL_RRC;
Cong Tang76c7e642019-02-26 15:08:55 +08005295 } else if (channels == 32) {
5296 lchannel_mapping[0] = PCM_CHANNEL_FL;
5297 lchannel_mapping[1] = PCM_CHANNEL_FR;
5298 lchannel_mapping[2] = PCM_CHANNEL_LFE;
5299 lchannel_mapping[3] = PCM_CHANNEL_FC;
5300 lchannel_mapping[4] = PCM_CHANNEL_LS;
5301 lchannel_mapping[5] = PCM_CHANNEL_RS;
5302 lchannel_mapping[6] = PCM_CHANNEL_LB;
5303 lchannel_mapping[7] = PCM_CHANNEL_RB;
5304 lchannel_mapping[8] = PCM_CHANNEL_CS;
5305 lchannel_mapping[9] = PCM_CHANNELS;
5306 lchannel_mapping[10] = PCM_CHANNEL_CVH;
5307 lchannel_mapping[11] = PCM_CHANNEL_MS;
5308 lchannel_mapping[12] = PCM_CHANNEL_FLC;
5309 lchannel_mapping[13] = PCM_CHANNEL_FRC;
5310 lchannel_mapping[14] = PCM_CHANNEL_RLC;
5311 lchannel_mapping[15] = PCM_CHANNEL_RRC;
5312 lchannel_mapping[16] = PCM_CHANNEL_LFE2;
5313 lchannel_mapping[17] = PCM_CHANNEL_SL;
5314 lchannel_mapping[18] = PCM_CHANNEL_SR;
5315 lchannel_mapping[19] = PCM_CHANNEL_TFL;
5316 lchannel_mapping[20] = PCM_CHANNEL_TFR;
5317 lchannel_mapping[21] = PCM_CHANNEL_TC;
5318 lchannel_mapping[22] = PCM_CHANNEL_TBL;
5319 lchannel_mapping[23] = PCM_CHANNEL_TBR;
5320 lchannel_mapping[24] = PCM_CHANNEL_TSL;
5321 lchannel_mapping[25] = PCM_CHANNEL_TSR;
5322 lchannel_mapping[26] = PCM_CHANNEL_TBC;
5323 lchannel_mapping[27] = PCM_CHANNEL_BFC;
5324 lchannel_mapping[28] = PCM_CHANNEL_BFL;
5325 lchannel_mapping[29] = PCM_CHANNEL_BFR;
5326 lchannel_mapping[30] = PCM_CHANNEL_LW;
5327 lchannel_mapping[31] = PCM_CHANNEL_RW;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305328 } else {
5329 pr_err("%s: ERROR.unsupported num_ch = %u\n",
5330 __func__, channels);
5331 return -EINVAL;
5332 }
5333 return 0;
5334}
5335
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305336/**
5337 * q6asm_enable_sbrps -
5338 * command to enable sbrps for ASM
5339 *
5340 * @ac: Audio client handle
5341 * @sbr_ps_enable: flag for sbr_ps enable or disable
5342 *
5343 * Returns 0 on success or error on failure
5344 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305345int q6asm_enable_sbrps(struct audio_client *ac,
5346 uint32_t sbr_ps_enable)
5347{
5348 struct asm_aac_sbr_ps_flag_param sbrps;
5349 u32 frames_per_buf = 0;
5350
5351 int rc = 0;
5352
5353 pr_debug("%s: Session %d\n", __func__, ac->session);
5354
5355 q6asm_add_hdr(ac, &sbrps.hdr, sizeof(sbrps), TRUE);
5356 atomic_set(&ac->cmd_state, -1);
5357
5358 sbrps.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
5359 sbrps.encdec.param_id = ASM_PARAM_ID_AAC_SBR_PS_FLAG;
5360 sbrps.encdec.param_size = sizeof(struct asm_aac_sbr_ps_flag_param) -
5361 sizeof(struct asm_stream_cmd_set_encdec_param);
5362 sbrps.encblk.frames_per_buf = frames_per_buf;
5363 sbrps.encblk.enc_cfg_blk_size = sbrps.encdec.param_size -
5364 sizeof(struct asm_enc_cfg_blk_param_v2);
5365
5366 sbrps.sbr_ps_flag = sbr_ps_enable;
5367
5368 rc = apr_send_pkt(ac->apr, (uint32_t *) &sbrps);
5369 if (rc < 0) {
5370 pr_err("%s: Command opcode[0x%x]paramid[0x%x] failed %d\n",
5371 __func__,
5372 ASM_STREAM_CMD_SET_ENCDEC_PARAM,
5373 ASM_PARAM_ID_AAC_SBR_PS_FLAG, rc);
5374 rc = -EINVAL;
5375 goto fail_cmd;
5376 }
5377 rc = wait_event_timeout(ac->cmd_wait,
5378 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5379 if (!rc) {
5380 pr_err("%s: timeout opcode[0x%x] ", __func__, sbrps.hdr.opcode);
5381 rc = -ETIMEDOUT;
5382 goto fail_cmd;
5383 }
5384 if (atomic_read(&ac->cmd_state) > 0) {
5385 pr_err("%s: DSP returned error[%s]\n",
5386 __func__, adsp_err_get_err_str(
5387 atomic_read(&ac->cmd_state)));
5388 rc = adsp_err_get_lnx_err_code(
5389 atomic_read(&ac->cmd_state));
5390 goto fail_cmd;
5391 }
5392 return 0;
5393fail_cmd:
5394 return rc;
5395}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305396EXPORT_SYMBOL(q6asm_enable_sbrps);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305397
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305398/**
5399 * q6asm_cfg_dual_mono_aac -
5400 * command to set config for dual mono aac
5401 *
5402 * @ac: Audio client handle
5403 * @sce_left: left sce val
5404 * @sce_right: right sce val
5405 *
5406 * Returns 0 on success or error on failure
5407 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305408int q6asm_cfg_dual_mono_aac(struct audio_client *ac,
5409 uint16_t sce_left, uint16_t sce_right)
5410{
5411 struct asm_aac_dual_mono_mapping_param dual_mono;
5412
5413 int rc = 0;
5414
5415 pr_debug("%s: Session %d, sce_left = %d, sce_right = %d\n",
5416 __func__, ac->session, sce_left, sce_right);
5417
5418 q6asm_add_hdr(ac, &dual_mono.hdr, sizeof(dual_mono), TRUE);
5419 atomic_set(&ac->cmd_state, -1);
5420
5421 dual_mono.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
5422 dual_mono.encdec.param_id = ASM_PARAM_ID_AAC_DUAL_MONO_MAPPING;
5423 dual_mono.encdec.param_size = sizeof(dual_mono.left_channel_sce) +
5424 sizeof(dual_mono.right_channel_sce);
5425 dual_mono.left_channel_sce = sce_left;
5426 dual_mono.right_channel_sce = sce_right;
5427
5428 rc = apr_send_pkt(ac->apr, (uint32_t *) &dual_mono);
5429 if (rc < 0) {
5430 pr_err("%s: Command opcode[0x%x]paramid[0x%x] failed %d\n",
5431 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM,
5432 ASM_PARAM_ID_AAC_DUAL_MONO_MAPPING, rc);
5433 rc = -EINVAL;
5434 goto fail_cmd;
5435 }
5436 rc = wait_event_timeout(ac->cmd_wait,
5437 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5438 if (!rc) {
5439 pr_err("%s: timeout opcode[0x%x]\n", __func__,
5440 dual_mono.hdr.opcode);
5441 rc = -ETIMEDOUT;
5442 goto fail_cmd;
5443 }
5444 if (atomic_read(&ac->cmd_state) > 0) {
5445 pr_err("%s: DSP returned error[%s]\n",
5446 __func__, adsp_err_get_err_str(
5447 atomic_read(&ac->cmd_state)));
5448 rc = adsp_err_get_lnx_err_code(
5449 atomic_read(&ac->cmd_state));
5450 goto fail_cmd;
5451 }
5452 return 0;
5453fail_cmd:
5454 return rc;
5455}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305456EXPORT_SYMBOL(q6asm_cfg_dual_mono_aac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305457
5458/* Support for selecting stereo mixing coefficients for B family not done */
5459int q6asm_cfg_aac_sel_mix_coef(struct audio_client *ac, uint32_t mix_coeff)
5460{
5461 struct asm_aac_stereo_mix_coeff_selection_param_v2 aac_mix_coeff;
5462 int rc = 0;
5463
5464 q6asm_add_hdr(ac, &aac_mix_coeff.hdr, sizeof(aac_mix_coeff), TRUE);
5465 atomic_set(&ac->cmd_state, -1);
5466 aac_mix_coeff.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
5467 aac_mix_coeff.param_id =
5468 ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG_V2;
5469 aac_mix_coeff.param_size =
5470 sizeof(struct asm_aac_stereo_mix_coeff_selection_param_v2);
5471 aac_mix_coeff.aac_stereo_mix_coeff_flag = mix_coeff;
5472 pr_debug("%s: mix_coeff = %u\n", __func__, mix_coeff);
5473 rc = apr_send_pkt(ac->apr, (uint32_t *) &aac_mix_coeff);
5474 if (rc < 0) {
5475 pr_err("%s: Command opcode[0x%x]paramid[0x%x] failed %d\n",
5476 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM,
5477 ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG_V2,
5478 rc);
5479 rc = -EINVAL;
5480 goto fail_cmd;
5481 }
5482 rc = wait_event_timeout(ac->cmd_wait,
5483 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5484 if (!rc) {
5485 pr_err("%s: timeout opcode[0x%x]\n",
5486 __func__, aac_mix_coeff.hdr.opcode);
5487 rc = -ETIMEDOUT;
5488 goto fail_cmd;
5489 }
5490 if (atomic_read(&ac->cmd_state) > 0) {
5491 pr_err("%s: DSP returned error[%s]\n",
5492 __func__, adsp_err_get_err_str(
5493 atomic_read(&ac->cmd_state)));
5494 rc = adsp_err_get_lnx_err_code(
5495 atomic_read(&ac->cmd_state));
5496 goto fail_cmd;
5497 }
5498 return 0;
5499fail_cmd:
5500 return rc;
5501}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305502EXPORT_SYMBOL(q6asm_cfg_aac_sel_mix_coef);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305503
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305504/**
5505 * q6asm_enc_cfg_blk_qcelp -
5506 * command to set encode config block for QCELP
5507 *
5508 * @ac: Audio client handle
5509 * @frames_per_buf: Number of frames per buffer
5510 * @min_rate: Minimum Enc rate
5511 * @max_rate: Maximum Enc rate
5512 * reduced_rate_level: Reduced rate level
5513 * @rate_modulation_cmd: rate modulation command
5514 *
5515 * Returns 0 on success or error on failure
5516 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305517int q6asm_enc_cfg_blk_qcelp(struct audio_client *ac, uint32_t frames_per_buf,
5518 uint16_t min_rate, uint16_t max_rate,
5519 uint16_t reduced_rate_level, uint16_t rate_modulation_cmd)
5520{
5521 struct asm_v13k_enc_cfg enc_cfg;
5522 int rc = 0;
5523
5524 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",
5525 __func__,
5526 ac->session, frames_per_buf, min_rate, max_rate,
5527 reduced_rate_level, rate_modulation_cmd);
5528
5529 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
5530 atomic_set(&ac->cmd_state, -1);
5531 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
5532 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
5533 enc_cfg.encdec.param_size = sizeof(struct asm_v13k_enc_cfg) -
5534 sizeof(struct asm_stream_cmd_set_encdec_param);
5535 enc_cfg.encblk.frames_per_buf = frames_per_buf;
5536 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
5537 sizeof(struct asm_enc_cfg_blk_param_v2);
5538
5539 enc_cfg.min_rate = min_rate;
5540 enc_cfg.max_rate = max_rate;
5541 enc_cfg.reduced_rate_cmd = reduced_rate_level;
5542 enc_cfg.rate_mod_cmd = rate_modulation_cmd;
5543
5544 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
5545 if (rc < 0) {
5546 pr_err("%s: Comamnd %d failed %d\n",
5547 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
5548 rc = -EINVAL;
5549 goto fail_cmd;
5550 }
5551 rc = wait_event_timeout(ac->cmd_wait,
5552 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5553 if (!rc) {
5554 pr_err("%s: timeout. waited for setencdec v13k resp\n",
5555 __func__);
5556 rc = -ETIMEDOUT;
5557 goto fail_cmd;
5558 }
5559 if (atomic_read(&ac->cmd_state) > 0) {
5560 pr_err("%s: DSP returned error[%s]\n",
5561 __func__, adsp_err_get_err_str(
5562 atomic_read(&ac->cmd_state)));
5563 rc = adsp_err_get_lnx_err_code(
5564 atomic_read(&ac->cmd_state));
5565 goto fail_cmd;
5566 }
5567 return 0;
5568fail_cmd:
5569 return rc;
5570}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305571EXPORT_SYMBOL(q6asm_enc_cfg_blk_qcelp);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305572
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305573/**
5574 * q6asm_enc_cfg_blk_evrc -
5575 * command to set encode config block for EVRC
5576 *
5577 * @ac: Audio client handle
5578 * @frames_per_buf: Number of frames per buffer
5579 * @min_rate: Minimum Enc rate
5580 * @max_rate: Maximum Enc rate
5581 * @rate_modulation_cmd: rate modulation command
5582 *
5583 * Returns 0 on success or error on failure
5584 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305585int q6asm_enc_cfg_blk_evrc(struct audio_client *ac, uint32_t frames_per_buf,
5586 uint16_t min_rate, uint16_t max_rate,
5587 uint16_t rate_modulation_cmd)
5588{
5589 struct asm_evrc_enc_cfg enc_cfg;
5590 int rc = 0;
5591
5592 pr_debug("%s: session[%d]frames[%d]min_rate[0x%4x]max_rate[0x%4x] rate_modulation_cmd[0x%4x]\n",
5593 __func__, ac->session,
5594 frames_per_buf, min_rate, max_rate, rate_modulation_cmd);
5595
5596 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
5597 atomic_set(&ac->cmd_state, -1);
5598 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
5599 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
5600 enc_cfg.encdec.param_size = sizeof(struct asm_evrc_enc_cfg) -
5601 sizeof(struct asm_stream_cmd_set_encdec_param);
5602 enc_cfg.encblk.frames_per_buf = frames_per_buf;
5603 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
5604 sizeof(struct asm_enc_cfg_blk_param_v2);
5605
5606 enc_cfg.min_rate = min_rate;
5607 enc_cfg.max_rate = max_rate;
5608 enc_cfg.rate_mod_cmd = rate_modulation_cmd;
5609 enc_cfg.reserved = 0;
5610
5611 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
5612 if (rc < 0) {
5613 pr_err("%s: Comamnd %d failed %d\n",
5614 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
5615 rc = -EINVAL;
5616 goto fail_cmd;
5617 }
5618 rc = wait_event_timeout(ac->cmd_wait,
5619 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5620 if (!rc) {
5621 pr_err("%s: timeout. waited for encdec evrc\n", __func__);
5622 rc = -ETIMEDOUT;
5623 goto fail_cmd;
5624 }
5625 if (atomic_read(&ac->cmd_state) > 0) {
5626 pr_err("%s: DSP returned error[%s]\n",
5627 __func__, adsp_err_get_err_str(
5628 atomic_read(&ac->cmd_state)));
5629 rc = adsp_err_get_lnx_err_code(
5630 atomic_read(&ac->cmd_state));
5631 goto fail_cmd;
5632 }
5633 return 0;
5634fail_cmd:
5635 return rc;
5636}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305637EXPORT_SYMBOL(q6asm_enc_cfg_blk_evrc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305638
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305639/**
5640 * q6asm_enc_cfg_blk_amrnb -
5641 * command to set encode config block for AMRNB
5642 *
5643 * @ac: Audio client handle
5644 * @frames_per_buf: Number of frames per buffer
5645 * @band_mode: Band mode used
5646 * @dtx_enable: DTX en flag
5647 *
5648 * Returns 0 on success or error on failure
5649 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305650int q6asm_enc_cfg_blk_amrnb(struct audio_client *ac, uint32_t frames_per_buf,
5651 uint16_t band_mode, uint16_t dtx_enable)
5652{
5653 struct asm_amrnb_enc_cfg enc_cfg;
5654 int rc = 0;
5655
5656 pr_debug("%s: session[%d]frames[%d]band_mode[0x%4x]dtx_enable[0x%4x]\n",
5657 __func__, ac->session, frames_per_buf, band_mode, dtx_enable);
5658
5659 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
5660 atomic_set(&ac->cmd_state, -1);
5661 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
5662 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
5663 enc_cfg.encdec.param_size = sizeof(struct asm_amrnb_enc_cfg) -
5664 sizeof(struct asm_stream_cmd_set_encdec_param);
5665 enc_cfg.encblk.frames_per_buf = frames_per_buf;
5666 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
5667 sizeof(struct asm_enc_cfg_blk_param_v2);
5668
5669 enc_cfg.enc_mode = band_mode;
5670 enc_cfg.dtx_mode = dtx_enable;
5671
5672 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
5673 if (rc < 0) {
5674 pr_err("%s: Comamnd %d failed %d\n",
5675 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
5676 rc = -EINVAL;
5677 goto fail_cmd;
5678 }
5679 rc = wait_event_timeout(ac->cmd_wait,
5680 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5681 if (!rc) {
5682 pr_err("%s: timeout. waited for set encdec amrnb\n", __func__);
5683 rc = -ETIMEDOUT;
5684 goto fail_cmd;
5685 }
5686 if (atomic_read(&ac->cmd_state) > 0) {
5687 pr_err("%s: DSP returned error[%s]\n",
5688 __func__, adsp_err_get_err_str(
5689 atomic_read(&ac->cmd_state)));
5690 rc = adsp_err_get_lnx_err_code(
5691 atomic_read(&ac->cmd_state));
5692 goto fail_cmd;
5693 }
5694 return 0;
5695fail_cmd:
5696 return rc;
5697}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305698EXPORT_SYMBOL(q6asm_enc_cfg_blk_amrnb);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305699
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305700/**
5701 * q6asm_enc_cfg_blk_amrwb -
5702 * command to set encode config block for AMRWB
5703 *
5704 * @ac: Audio client handle
5705 * @frames_per_buf: Number of frames per buffer
5706 * @band_mode: Band mode used
5707 * @dtx_enable: DTX en flag
5708 *
5709 * Returns 0 on success or error on failure
5710 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305711int q6asm_enc_cfg_blk_amrwb(struct audio_client *ac, uint32_t frames_per_buf,
5712 uint16_t band_mode, uint16_t dtx_enable)
5713{
5714 struct asm_amrwb_enc_cfg enc_cfg;
5715 int rc = 0;
5716
5717 pr_debug("%s: session[%d]frames[%d]band_mode[0x%4x]dtx_enable[0x%4x]\n",
5718 __func__, ac->session, frames_per_buf, band_mode, dtx_enable);
5719
5720 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
5721 atomic_set(&ac->cmd_state, -1);
5722 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
5723 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
5724 enc_cfg.encdec.param_size = sizeof(struct asm_amrwb_enc_cfg) -
5725 sizeof(struct asm_stream_cmd_set_encdec_param);
5726 enc_cfg.encblk.frames_per_buf = frames_per_buf;
5727 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
5728 sizeof(struct asm_enc_cfg_blk_param_v2);
5729
5730 enc_cfg.enc_mode = band_mode;
5731 enc_cfg.dtx_mode = dtx_enable;
5732
5733 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
5734 if (rc < 0) {
5735 pr_err("%s: Comamnd %d failed %d\n",
5736 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
5737 rc = -EINVAL;
5738 goto fail_cmd;
5739 }
5740 rc = wait_event_timeout(ac->cmd_wait,
5741 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5742 if (!rc) {
5743 pr_err("%s: timeout. waited for FORMAT_UPDATE\n", __func__);
5744 rc = -ETIMEDOUT;
5745 goto fail_cmd;
5746 }
5747 if (atomic_read(&ac->cmd_state) > 0) {
5748 pr_err("%s: DSP returned error[%s]\n",
5749 __func__, adsp_err_get_err_str(
5750 atomic_read(&ac->cmd_state)));
5751 rc = adsp_err_get_lnx_err_code(
5752 atomic_read(&ac->cmd_state));
5753 goto fail_cmd;
5754 }
5755 return 0;
5756fail_cmd:
5757 return rc;
5758}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305759EXPORT_SYMBOL(q6asm_enc_cfg_blk_amrwb);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305760
5761
5762static int __q6asm_media_format_block_pcm(struct audio_client *ac,
5763 uint32_t rate, uint32_t channels,
5764 uint16_t bits_per_sample, int stream_id,
5765 bool use_default_chmap, char *channel_map)
5766{
5767 struct asm_multi_channel_pcm_fmt_blk_v2 fmt;
5768 u8 *channel_mapping;
5769 int rc = 0;
5770
Rohit kumar6a14cfb2019-02-04 11:22:49 +05305771 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
5772 pr_err("%s: Invalid channel count %d\n", __func__, channels);
5773 return -EINVAL;
5774 }
5775
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305776 pr_debug("%s: session[%d]rate[%d]ch[%d]\n", __func__, ac->session, rate,
5777 channels);
5778
5779 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
5780 atomic_set(&ac->cmd_state, -1);
5781 /*
5782 * Updated the token field with stream/session for compressed playback
5783 * Platform driver must know the the stream with which the command is
5784 * associated
5785 */
5786 if (ac->io_mode & COMPRESSED_STREAM_IO)
5787 q6asm_update_token(&fmt.hdr.token,
5788 ac->session,
5789 stream_id,
5790 0, /* Buffer index is NA */
5791 0, /* Direction flag is NA */
5792 WAIT_CMD);
5793
5794 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
5795 __func__, fmt.hdr.token, stream_id, ac->session);
5796
5797 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
5798 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
5799 sizeof(fmt.fmt_blk);
5800 fmt.num_channels = channels;
5801 fmt.bits_per_sample = bits_per_sample;
5802 fmt.sample_rate = rate;
5803 fmt.is_signed = 1;
5804
5805 channel_mapping = fmt.channel_mapping;
5806
5807 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
5808
5809 if (use_default_chmap) {
5810 if (q6asm_map_channels(channel_mapping, channels, false)) {
5811 pr_err("%s: map channels failed %d\n",
5812 __func__, channels);
5813 return -EINVAL;
5814 }
5815 } else {
5816 memcpy(channel_mapping, channel_map,
5817 PCM_FORMAT_MAX_NUM_CHANNEL);
5818 }
5819
5820 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
5821 if (rc < 0) {
5822 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
5823 rc = -EINVAL;
5824 goto fail_cmd;
5825 }
5826 rc = wait_event_timeout(ac->cmd_wait,
5827 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5828 if (!rc) {
5829 pr_err("%s: timeout. waited for format update\n", __func__);
5830 rc = -ETIMEDOUT;
5831 goto fail_cmd;
5832 }
5833 if (atomic_read(&ac->cmd_state) > 0) {
5834 pr_err("%s: DSP returned error[%s]\n",
5835 __func__, adsp_err_get_err_str(
5836 atomic_read(&ac->cmd_state)));
5837 rc = adsp_err_get_lnx_err_code(
5838 atomic_read(&ac->cmd_state));
5839 goto fail_cmd;
5840 }
5841 return 0;
5842fail_cmd:
5843 return rc;
5844}
5845
5846static int __q6asm_media_format_block_pcm_v3(struct audio_client *ac,
5847 uint32_t rate, uint32_t channels,
5848 uint16_t bits_per_sample,
5849 int stream_id,
5850 bool use_default_chmap,
5851 char *channel_map,
5852 uint16_t sample_word_size)
5853{
5854 struct asm_multi_channel_pcm_fmt_blk_param_v3 fmt;
5855 u8 *channel_mapping;
5856 int rc;
5857
Rohit kumar6a14cfb2019-02-04 11:22:49 +05305858 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
5859 pr_err("%s: Invalid channel count %d\n", __func__, channels);
5860 return -EINVAL;
5861 }
5862
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305863 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
5864 ac->session, rate, channels,
5865 bits_per_sample, sample_word_size);
5866
5867 memset(&fmt, 0, sizeof(fmt));
5868 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
5869 atomic_set(&ac->cmd_state, -1);
5870 /*
5871 * Updated the token field with stream/session for compressed playback
5872 * Platform driver must know the the stream with which the command is
5873 * associated
5874 */
5875 if (ac->io_mode & COMPRESSED_STREAM_IO)
5876 fmt.hdr.token = ((ac->session << 8) & 0xFFFF00) |
5877 (stream_id & 0xFF);
5878
5879 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
5880 __func__, fmt.hdr.token, stream_id, ac->session);
5881
5882 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
5883 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
5884 sizeof(fmt.fmt_blk);
5885 fmt.param.num_channels = channels;
5886 fmt.param.bits_per_sample = bits_per_sample;
5887 fmt.param.sample_rate = rate;
5888 fmt.param.is_signed = 1;
5889 fmt.param.sample_word_size = sample_word_size;
5890 channel_mapping = fmt.param.channel_mapping;
5891
5892 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
5893
5894 if (use_default_chmap) {
5895 if (q6asm_map_channels(channel_mapping, channels, false)) {
5896 pr_err("%s: map channels failed %d\n",
5897 __func__, channels);
5898 rc = -EINVAL;
5899 goto fail_cmd;
5900 }
5901 } else {
5902 memcpy(channel_mapping, channel_map,
5903 PCM_FORMAT_MAX_NUM_CHANNEL);
5904 }
5905
5906 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
5907 if (rc < 0) {
5908 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
5909 rc = -EINVAL;
5910 goto fail_cmd;
5911 }
5912 rc = wait_event_timeout(ac->cmd_wait,
5913 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5914 if (!rc) {
5915 pr_err("%s: timeout. waited for format update\n", __func__);
5916 rc = -ETIMEDOUT;
5917 goto fail_cmd;
5918 }
5919 if (atomic_read(&ac->cmd_state) > 0) {
5920 pr_err("%s: DSP returned error[%s]\n",
5921 __func__, adsp_err_get_err_str(
5922 atomic_read(&ac->cmd_state)));
5923 rc = adsp_err_get_lnx_err_code(
5924 atomic_read(&ac->cmd_state));
5925 goto fail_cmd;
5926 }
5927 return 0;
5928fail_cmd:
5929 return rc;
5930}
5931
5932static int __q6asm_media_format_block_pcm_v4(struct audio_client *ac,
5933 uint32_t rate, uint32_t channels,
5934 uint16_t bits_per_sample,
5935 int stream_id,
5936 bool use_default_chmap,
5937 char *channel_map,
5938 uint16_t sample_word_size,
5939 uint16_t endianness,
5940 uint16_t mode)
5941{
5942 struct asm_multi_channel_pcm_fmt_blk_param_v4 fmt;
5943 u8 *channel_mapping;
5944 int rc;
5945
Rohit kumar6a14cfb2019-02-04 11:22:49 +05305946 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
5947 pr_err("%s: Invalid channel count %d\n", __func__, channels);
5948 return -EINVAL;
5949 }
5950
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305951 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
5952 ac->session, rate, channels,
5953 bits_per_sample, sample_word_size);
5954
5955 memset(&fmt, 0, sizeof(fmt));
5956 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
5957 atomic_set(&ac->cmd_state, -1);
5958 /*
5959 * Updated the token field with stream/session for compressed playback
5960 * Platform driver must know the the stream with which the command is
5961 * associated
5962 */
5963 if (ac->io_mode & COMPRESSED_STREAM_IO)
5964 fmt.hdr.token = ((ac->session << 8) & 0xFFFF00) |
5965 (stream_id & 0xFF);
5966
5967 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
5968 __func__, fmt.hdr.token, stream_id, ac->session);
5969
5970 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
5971 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
5972 sizeof(fmt.fmt_blk);
5973 fmt.param.num_channels = channels;
5974 fmt.param.bits_per_sample = bits_per_sample;
5975 fmt.param.sample_rate = rate;
5976 fmt.param.is_signed = 1;
5977 fmt.param.sample_word_size = sample_word_size;
5978 fmt.param.endianness = endianness;
5979 fmt.param.mode = mode;
5980 channel_mapping = fmt.param.channel_mapping;
5981
5982 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
5983
5984 if (use_default_chmap) {
5985 if (q6asm_map_channels(channel_mapping, channels, false)) {
5986 pr_err("%s: map channels failed %d\n",
5987 __func__, channels);
5988 rc = -EINVAL;
5989 goto fail_cmd;
5990 }
5991 } else {
5992 memcpy(channel_mapping, channel_map,
5993 PCM_FORMAT_MAX_NUM_CHANNEL);
5994 }
5995
5996 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
5997 if (rc < 0) {
5998 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
5999 rc = -EINVAL;
6000 goto fail_cmd;
6001 }
6002 rc = wait_event_timeout(ac->cmd_wait,
6003 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6004 if (!rc) {
6005 pr_err("%s: timeout. waited for format update\n", __func__);
6006 rc = -ETIMEDOUT;
6007 goto fail_cmd;
6008 }
6009 if (atomic_read(&ac->cmd_state) > 0) {
6010 pr_err("%s: DSP returned error[%s]\n",
6011 __func__, adsp_err_get_err_str(
6012 atomic_read(&ac->cmd_state)));
6013 rc = adsp_err_get_lnx_err_code(
6014 atomic_read(&ac->cmd_state));
6015 goto fail_cmd;
6016 }
6017 return 0;
6018fail_cmd:
6019 return rc;
6020}
6021
Dhanalakshmi Siddaniff8d0d92019-12-05 15:20:23 +05306022static int __q6asm_media_format_block_pcm_v5(struct audio_client *ac,
6023 uint32_t rate, uint32_t channels,
6024 uint16_t bits_per_sample,
6025 int stream_id,
6026 bool use_default_chmap,
6027 char *channel_map,
6028 uint16_t sample_word_size,
6029 uint16_t endianness,
6030 uint16_t mode)
6031{
6032 struct asm_multi_channel_pcm_fmt_blk_param_v5 fmt;
6033 u8 *channel_mapping;
6034 int rc;
6035
6036 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
6037 pr_err("%s: Invalid channel count %d\n", __func__, channels);
6038 return -EINVAL;
6039 }
6040
6041 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
6042 ac->session, rate, channels,
6043 bits_per_sample, sample_word_size);
6044
6045 memset(&fmt, 0, sizeof(fmt));
6046 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6047 atomic_set(&ac->cmd_state, -1);
6048 /*
6049 * Updated the token field with stream/session for compressed playback
6050 * Platform driver must know the the stream with which the command is
6051 * associated
6052 */
6053 if (ac->io_mode & COMPRESSED_STREAM_IO)
6054 fmt.hdr.token = ((ac->session << 8) & 0xFFFF00) |
6055 (stream_id & 0xFF);
6056
6057 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
6058 __func__, fmt.hdr.token, stream_id, ac->session);
6059
6060 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6061 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6062 sizeof(fmt.fmt_blk);
6063 fmt.param.num_channels = (uint16_t) channels & 0xFFFF;
6064 fmt.param.bits_per_sample = bits_per_sample;
6065 fmt.param.sample_rate = rate;
6066 fmt.param.is_signed = 1;
6067 fmt.param.sample_word_size = sample_word_size;
6068 fmt.param.endianness = endianness;
6069 fmt.param.mode = mode;
6070 channel_mapping = fmt.param.channel_mapping;
6071
6072 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL_V8);
6073
6074 if (use_default_chmap) {
6075 if (q6asm_map_channels(channel_mapping, fmt.param.num_channels, false)) {
6076 pr_err("%s: map channels failed %d\n",
6077 __func__, channels);
6078 rc = -EINVAL;
6079 goto fail_cmd;
6080 }
6081 } else {
6082 memcpy(channel_mapping, channel_map,
6083 PCM_FORMAT_MAX_NUM_CHANNEL_V8);
6084 }
6085
6086 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6087 if (rc < 0) {
6088 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
6089 rc = -EINVAL;
6090 goto fail_cmd;
6091 }
6092 rc = wait_event_timeout(ac->cmd_wait,
6093 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6094 if (!rc) {
6095 pr_err("%s: timeout. waited for format update\n", __func__);
6096 rc = -ETIMEDOUT;
6097 goto fail_cmd;
6098 }
6099 if (atomic_read(&ac->cmd_state) > 0) {
6100 pr_err("%s: DSP returned error[%s]\n",
6101 __func__, adsp_err_get_err_str(
6102 atomic_read(&ac->cmd_state)));
6103 rc = adsp_err_get_lnx_err_code(
6104 atomic_read(&ac->cmd_state));
6105 goto fail_cmd;
6106 }
6107 return 0;
6108fail_cmd:
6109 return rc;
6110}
6111
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306112/**
6113 * q6asm_media_format_block_pcm -
6114 * command to set mediafmt block for PCM on ASM stream
6115 *
6116 * @ac: Audio client handle
6117 * @rate: sample rate
6118 * @channels: number of ASM channels
6119 *
6120 * Returns 0 on success or error on failure
6121 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306122int q6asm_media_format_block_pcm(struct audio_client *ac,
6123 uint32_t rate, uint32_t channels)
6124{
6125 return __q6asm_media_format_block_pcm(ac, rate,
6126 channels, 16, ac->stream_id,
6127 true, NULL);
6128}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306129EXPORT_SYMBOL(q6asm_media_format_block_pcm);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306130
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306131/**
6132 * q6asm_media_format_block_pcm_format_support -
6133 * command to set mediafmt block for PCM format support
6134 *
6135 * @ac: Audio client handle
6136 * @rate: sample rate
6137 * @channels: number of ASM channels
6138 * @bits_per_sample: number of bits per sample
6139 *
6140 * Returns 0 on success or error on failure
6141 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306142int q6asm_media_format_block_pcm_format_support(struct audio_client *ac,
6143 uint32_t rate, uint32_t channels,
6144 uint16_t bits_per_sample)
6145{
6146 return __q6asm_media_format_block_pcm(ac, rate,
6147 channels, bits_per_sample, ac->stream_id,
6148 true, NULL);
6149}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306150EXPORT_SYMBOL(q6asm_media_format_block_pcm_format_support);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306151
6152int q6asm_media_format_block_pcm_format_support_v2(struct audio_client *ac,
6153 uint32_t rate, uint32_t channels,
6154 uint16_t bits_per_sample, int stream_id,
6155 bool use_default_chmap, char *channel_map)
6156{
6157 if (!use_default_chmap && (channel_map == NULL)) {
6158 pr_err("%s: No valid chan map and can't use default\n",
6159 __func__);
6160 return -EINVAL;
6161 }
6162 return __q6asm_media_format_block_pcm(ac, rate,
6163 channels, bits_per_sample, stream_id,
6164 use_default_chmap, channel_map);
6165}
6166
6167/*
6168 * q6asm_media_format_block_pcm_format_support_v3- sends pcm decoder
6169 * configuration parameters
6170 *
6171 * @ac: Client session handle
6172 * @rate: sample rate
6173 * @channels: number of channels
6174 * @bits_per_sample: bit width of encoder session
6175 * @stream_id: stream id of stream to be associated with this session
6176 * @use_default_chmap: true if default channel map to be used
6177 * @channel_map: input channel map
6178 * @sample_word_size: Size in bits of the word that holds a sample of a channel
6179 */
6180int q6asm_media_format_block_pcm_format_support_v3(struct audio_client *ac,
6181 uint32_t rate,
6182 uint32_t channels,
6183 uint16_t bits_per_sample,
6184 int stream_id,
6185 bool use_default_chmap,
6186 char *channel_map,
6187 uint16_t sample_word_size)
6188{
6189 if (!use_default_chmap && (channel_map == NULL)) {
6190 pr_err("%s: No valid chan map and can't use default\n",
6191 __func__);
6192 return -EINVAL;
6193 }
6194 return __q6asm_media_format_block_pcm_v3(ac, rate,
6195 channels, bits_per_sample, stream_id,
6196 use_default_chmap, channel_map,
6197 sample_word_size);
6198
6199}
6200EXPORT_SYMBOL(q6asm_media_format_block_pcm_format_support_v3);
6201
6202/*
6203 * q6asm_media_format_block_pcm_format_support_v4- sends pcm decoder
6204 * configuration parameters
6205 *
6206 * @ac: Client session handle
6207 * @rate: sample rate
6208 * @channels: number of channels
6209 * @bits_per_sample: bit width of encoder session
6210 * @stream_id: stream id of stream to be associated with this session
6211 * @use_default_chmap: true if default channel map to be used
6212 * @channel_map: input channel map
6213 * @sample_word_size: Size in bits of the word that holds a sample of a channel
6214 * @endianness: endianness of the pcm data
6215 * @mode: Mode to provide additional info about the pcm input data
6216 */
6217int q6asm_media_format_block_pcm_format_support_v4(struct audio_client *ac,
6218 uint32_t rate,
6219 uint32_t channels,
6220 uint16_t bits_per_sample,
6221 int stream_id,
6222 bool use_default_chmap,
6223 char *channel_map,
6224 uint16_t sample_word_size,
6225 uint16_t endianness,
6226 uint16_t mode)
6227{
6228 if (!use_default_chmap && (channel_map == NULL)) {
6229 pr_err("%s: No valid chan map and can't use default\n",
6230 __func__);
6231 return -EINVAL;
6232 }
6233 return __q6asm_media_format_block_pcm_v4(ac, rate,
6234 channels, bits_per_sample, stream_id,
6235 use_default_chmap, channel_map,
6236 sample_word_size, endianness,
6237 mode);
6238
6239}
6240EXPORT_SYMBOL(q6asm_media_format_block_pcm_format_support_v4);
6241
6242
Dhanalakshmi Siddaniff8d0d92019-12-05 15:20:23 +05306243/*
6244 * q6asm_media_format_block_pcm_format_support_v5- sends pcm decoder
6245 * configuration parameters
6246 *
6247 * @ac: Client session handle
6248 * @rate: sample rate
6249 * @channels: number of channels
6250 * @bits_per_sample: bit width of encoder session
6251 * @stream_id: stream id of stream to be associated with this session
6252 * @use_default_chmap: true if default channel map to be used
6253 * @channel_map: input channel map
6254 * @sample_word_size: Size in bits of the word that holds a sample of a channel
6255 * @endianness: endianness of the pcm data
6256 * @mode: Mode to provide additional info about the pcm input data
6257 */
6258int q6asm_media_format_block_pcm_format_support_v5(struct audio_client *ac,
6259 uint32_t rate,
6260 uint32_t channels,
6261 uint16_t bits_per_sample,
6262 int stream_id,
6263 bool use_default_chmap,
6264 char *channel_map,
6265 uint16_t sample_word_size,
6266 uint16_t endianness,
6267 uint16_t mode)
6268{
6269 if (!use_default_chmap && (channel_map == NULL)) {
6270 pr_err("%s: No valid chan map and can't use default\n",
6271 __func__);
6272 return -EINVAL;
6273 }
6274 return __q6asm_media_format_block_pcm_v5(ac, rate,
6275 channels, bits_per_sample, stream_id,
6276 use_default_chmap, channel_map,
6277 sample_word_size, endianness,
6278 mode);
6279
6280}
6281EXPORT_SYMBOL(q6asm_media_format_block_pcm_format_support_v5);
6282
6283
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306284static int __q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
6285 uint32_t rate, uint32_t channels,
6286 bool use_default_chmap, char *channel_map,
6287 uint16_t bits_per_sample)
6288{
6289 struct asm_multi_channel_pcm_fmt_blk_v2 fmt;
6290 u8 *channel_mapping;
6291 int rc = 0;
6292
Rohit kumar6a14cfb2019-02-04 11:22:49 +05306293 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
6294 pr_err("%s: Invalid channel count %d\n", __func__, channels);
6295 return -EINVAL;
6296 }
6297
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306298 pr_debug("%s: session[%d]rate[%d]ch[%d]\n", __func__, ac->session, rate,
6299 channels);
6300
6301 q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
6302 atomic_set(&ac->cmd_state, -1);
6303
6304 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6305 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6306 sizeof(fmt.fmt_blk);
6307 fmt.num_channels = channels;
6308 fmt.bits_per_sample = bits_per_sample;
6309 fmt.sample_rate = rate;
6310 fmt.is_signed = 1;
6311
6312 channel_mapping = fmt.channel_mapping;
6313
6314 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
6315
6316 if (use_default_chmap) {
6317 if (q6asm_map_channels(channel_mapping, channels, false)) {
6318 pr_err("%s: map channels failed %d\n",
6319 __func__, channels);
6320 return -EINVAL;
6321 }
6322 } else {
6323 memcpy(channel_mapping, channel_map,
6324 PCM_FORMAT_MAX_NUM_CHANNEL);
6325 }
6326
6327 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6328 if (rc < 0) {
6329 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
6330 rc = -EINVAL;
6331 goto fail_cmd;
6332 }
6333 rc = wait_event_timeout(ac->cmd_wait,
6334 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6335 if (!rc) {
6336 pr_err("%s: timeout. waited for format update\n", __func__);
6337 rc = -ETIMEDOUT;
6338 goto fail_cmd;
6339 }
6340 if (atomic_read(&ac->cmd_state) > 0) {
6341 pr_err("%s: DSP returned error[%s]\n",
6342 __func__, adsp_err_get_err_str(
6343 atomic_read(&ac->cmd_state)));
6344 rc = adsp_err_get_lnx_err_code(
6345 atomic_read(&ac->cmd_state));
6346 goto fail_cmd;
6347 }
6348 return 0;
6349fail_cmd:
6350 return rc;
6351}
6352
6353static int __q6asm_media_format_block_multi_ch_pcm_v3(struct audio_client *ac,
6354 uint32_t rate,
6355 uint32_t channels,
6356 bool use_default_chmap,
6357 char *channel_map,
6358 uint16_t bits_per_sample,
6359 uint16_t sample_word_size)
6360{
6361 struct asm_multi_channel_pcm_fmt_blk_param_v3 fmt;
6362 u8 *channel_mapping;
6363 int rc;
6364
Rohit kumar6a14cfb2019-02-04 11:22:49 +05306365 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
6366 pr_err("%s: Invalid channel count %d\n", __func__, channels);
6367 return -EINVAL;
6368 }
6369
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306370 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
6371 ac->session, rate, channels,
6372 bits_per_sample, sample_word_size);
6373
6374 memset(&fmt, 0, sizeof(fmt));
6375 q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
6376 atomic_set(&ac->cmd_state, -1);
6377
6378 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6379 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6380 sizeof(fmt.fmt_blk);
6381 fmt.param.num_channels = channels;
6382 fmt.param.bits_per_sample = bits_per_sample;
6383 fmt.param.sample_rate = rate;
6384 fmt.param.is_signed = 1;
6385 fmt.param.sample_word_size = sample_word_size;
6386 channel_mapping = fmt.param.channel_mapping;
6387
6388 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
6389
6390 if (use_default_chmap) {
6391 if (q6asm_map_channels(channel_mapping, channels, false)) {
6392 pr_err("%s: map channels failed %d\n",
6393 __func__, channels);
6394 rc = -EINVAL;
6395 goto fail_cmd;
6396 }
6397 } else {
6398 memcpy(channel_mapping, channel_map,
6399 PCM_FORMAT_MAX_NUM_CHANNEL);
6400 }
6401
6402 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6403 if (rc < 0) {
6404 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
6405 goto fail_cmd;
6406 }
6407 rc = wait_event_timeout(ac->cmd_wait,
6408 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6409 if (!rc) {
6410 pr_err("%s: timeout. waited for format update\n", __func__);
6411 rc = -ETIMEDOUT;
6412 goto fail_cmd;
6413 }
6414 if (atomic_read(&ac->cmd_state) > 0) {
6415 pr_err("%s: DSP returned error[%s]\n",
6416 __func__, adsp_err_get_err_str(
6417 atomic_read(&ac->cmd_state)));
6418 rc = adsp_err_get_lnx_err_code(
6419 atomic_read(&ac->cmd_state));
6420 goto fail_cmd;
6421 }
6422 return 0;
6423fail_cmd:
6424 return rc;
6425}
6426
6427static int __q6asm_media_format_block_multi_ch_pcm_v4(struct audio_client *ac,
6428 uint32_t rate,
6429 uint32_t channels,
6430 bool use_default_chmap,
6431 char *channel_map,
6432 uint16_t bits_per_sample,
6433 uint16_t sample_word_size,
6434 uint16_t endianness,
6435 uint16_t mode)
6436{
6437 struct asm_multi_channel_pcm_fmt_blk_param_v4 fmt;
6438 u8 *channel_mapping;
6439 int rc;
6440
Rohit kumar6a14cfb2019-02-04 11:22:49 +05306441 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
6442 pr_err("%s: Invalid channel count %d\n", __func__, channels);
6443 return -EINVAL;
6444 }
6445
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306446 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
6447 ac->session, rate, channels,
6448 bits_per_sample, sample_word_size);
6449
6450 memset(&fmt, 0, sizeof(fmt));
6451 q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
6452 atomic_set(&ac->cmd_state, -1);
6453
6454 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6455 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6456 sizeof(fmt.fmt_blk);
6457 fmt.param.num_channels = channels;
6458 fmt.param.bits_per_sample = bits_per_sample;
6459 fmt.param.sample_rate = rate;
6460 fmt.param.is_signed = 1;
6461 fmt.param.sample_word_size = sample_word_size;
6462 fmt.param.endianness = endianness;
6463 fmt.param.mode = mode;
6464 channel_mapping = fmt.param.channel_mapping;
6465
6466 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
6467
6468 if (use_default_chmap) {
6469 if (q6asm_map_channels(channel_mapping, channels, false)) {
6470 pr_err("%s: map channels failed %d\n",
6471 __func__, channels);
6472 rc = -EINVAL;
6473 goto fail_cmd;
6474 }
6475 } else {
6476 memcpy(channel_mapping, channel_map,
6477 PCM_FORMAT_MAX_NUM_CHANNEL);
6478 }
6479
6480 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6481 if (rc < 0) {
6482 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
6483 goto fail_cmd;
6484 }
6485 rc = wait_event_timeout(ac->cmd_wait,
6486 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6487 if (!rc) {
6488 pr_err("%s: timeout. waited for format update\n", __func__);
6489 rc = -ETIMEDOUT;
6490 goto fail_cmd;
6491 }
6492 if (atomic_read(&ac->cmd_state) > 0) {
6493 pr_err("%s: DSP returned error[%s]\n",
6494 __func__, adsp_err_get_err_str(
6495 atomic_read(&ac->cmd_state)));
6496 rc = adsp_err_get_lnx_err_code(
6497 atomic_read(&ac->cmd_state));
6498 goto fail_cmd;
6499 }
6500 return 0;
6501fail_cmd:
6502 return rc;
6503}
6504
Dhanalakshmi Siddaniff8d0d92019-12-05 15:20:23 +05306505static int __q6asm_media_format_block_multi_ch_pcm_v5(struct audio_client *ac,
6506 uint32_t rate,
6507 uint32_t channels,
6508 bool use_default_chmap,
6509 char *channel_map,
6510 uint16_t bits_per_sample,
6511 uint16_t sample_word_size,
6512 uint16_t endianness,
6513 uint16_t mode)
6514{
6515 struct asm_multi_channel_pcm_fmt_blk_param_v5 fmt;
6516 u8 *channel_mapping;
6517 int rc;
6518
6519 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL_V8) {
6520 pr_err("%s: Invalid channel count %d\n", __func__, channels);
6521 return -EINVAL;
6522 }
6523
6524 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
6525 ac->session, rate, channels,
6526 bits_per_sample, sample_word_size);
6527
6528 memset(&fmt, 0, sizeof(fmt));
6529 q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
6530 atomic_set(&ac->cmd_state, -1);
6531
6532 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6533 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6534 sizeof(fmt.fmt_blk);
6535 fmt.param.num_channels = channels;
6536 fmt.param.bits_per_sample = bits_per_sample;
6537 fmt.param.sample_rate = rate;
6538 fmt.param.is_signed = 1;
6539 fmt.param.sample_word_size = sample_word_size;
6540 fmt.param.endianness = endianness;
6541 fmt.param.mode = mode;
6542 channel_mapping = fmt.param.channel_mapping;
6543
6544 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL_V8);
6545
6546 if (use_default_chmap) {
6547 if (q6asm_map_channels(channel_mapping, channels, false)) {
6548 pr_err("%s: map channels failed %d\n",
6549 __func__, channels);
6550 rc = -EINVAL;
6551 goto fail_cmd;
6552 }
6553 } else {
6554 memcpy(channel_mapping, channel_map,
6555 PCM_FORMAT_MAX_NUM_CHANNEL_V8);
6556 }
6557
6558 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6559 if (rc < 0) {
6560 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
6561 goto fail_cmd;
6562 }
6563 rc = wait_event_timeout(ac->cmd_wait,
6564 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6565 if (!rc) {
6566 pr_err("%s: timeout. waited for format update\n", __func__);
6567 rc = -ETIMEDOUT;
6568 goto fail_cmd;
6569 }
6570 if (atomic_read(&ac->cmd_state) > 0) {
6571 pr_err("%s: DSP returned error[%s]\n",
6572 __func__, adsp_err_get_err_str(
6573 atomic_read(&ac->cmd_state)));
6574 rc = adsp_err_get_lnx_err_code(
6575 atomic_read(&ac->cmd_state));
6576 goto fail_cmd;
6577 }
6578 return 0;
6579fail_cmd:
6580 return rc;
6581}
6582
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306583int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
6584 uint32_t rate, uint32_t channels,
6585 bool use_default_chmap, char *channel_map)
6586{
6587 return __q6asm_media_format_block_multi_ch_pcm(ac, rate,
6588 channels, use_default_chmap, channel_map, 16);
6589}
6590
6591int q6asm_media_format_block_multi_ch_pcm_v2(
6592 struct audio_client *ac,
6593 uint32_t rate, uint32_t channels,
6594 bool use_default_chmap, char *channel_map,
6595 uint16_t bits_per_sample)
6596{
6597 return __q6asm_media_format_block_multi_ch_pcm(ac, rate,
6598 channels, use_default_chmap, channel_map,
6599 bits_per_sample);
6600}
6601
6602/*
6603 * q6asm_media_format_block_multi_ch_pcm_v3 - sends pcm decoder configuration
6604 * parameters
6605 *
6606 * @ac: Client session handle
6607 * @rate: sample rate
6608 * @channels: number of channels
6609 * @bits_per_sample: bit width of encoder session
6610 * @use_default_chmap: true if default channel map to be used
6611 * @channel_map: input channel map
6612 * @sample_word_size: Size in bits of the word that holds a sample of a channel
6613 */
6614int q6asm_media_format_block_multi_ch_pcm_v3(struct audio_client *ac,
6615 uint32_t rate, uint32_t channels,
6616 bool use_default_chmap,
6617 char *channel_map,
6618 uint16_t bits_per_sample,
6619 uint16_t sample_word_size)
6620{
6621 return __q6asm_media_format_block_multi_ch_pcm_v3(ac, rate, channels,
6622 use_default_chmap,
6623 channel_map,
6624 bits_per_sample,
6625 sample_word_size);
6626}
6627EXPORT_SYMBOL(q6asm_media_format_block_multi_ch_pcm_v3);
6628
6629/*
6630 * q6asm_media_format_block_multi_ch_pcm_v4 - sends pcm decoder configuration
6631 * parameters
6632 *
6633 * @ac: Client session handle
6634 * @rate: sample rate
6635 * @channels: number of channels
6636 * @bits_per_sample: bit width of encoder session
6637 * @use_default_chmap: true if default channel map to be used
6638 * @channel_map: input channel map
6639 * @sample_word_size: Size in bits of the word that holds a sample of a channel
6640 * @endianness: endianness of the pcm data
6641 * @mode: Mode to provide additional info about the pcm input data
6642 */
6643int q6asm_media_format_block_multi_ch_pcm_v4(struct audio_client *ac,
6644 uint32_t rate, uint32_t channels,
6645 bool use_default_chmap,
6646 char *channel_map,
6647 uint16_t bits_per_sample,
6648 uint16_t sample_word_size,
6649 uint16_t endianness,
6650 uint16_t mode)
6651{
6652 return __q6asm_media_format_block_multi_ch_pcm_v4(ac, rate, channels,
6653 use_default_chmap,
6654 channel_map,
6655 bits_per_sample,
6656 sample_word_size,
6657 endianness,
6658 mode);
6659}
6660EXPORT_SYMBOL(q6asm_media_format_block_multi_ch_pcm_v4);
6661
Dhanalakshmi Siddaniff8d0d92019-12-05 15:20:23 +05306662
6663/*
6664 * q6asm_media_format_block_multi_ch_pcm_v5 - sends pcm decoder configuration
6665 * parameters
6666 *
6667 * @ac: Client session handle
6668 * @rate: sample rate
6669 * @channels: number of channels
6670 * @bits_per_sample: bit width of encoder session
6671 * @use_default_chmap: true if default channel map to be used
6672 * @channel_map: input channel map
6673 * @sample_word_size: Size in bits of the word that holds a sample of a channel
6674 * @endianness: endianness of the pcm data
6675 * @mode: Mode to provide additional info about the pcm input data
6676 */
6677int q6asm_media_format_block_multi_ch_pcm_v5(struct audio_client *ac,
6678 uint32_t rate, uint32_t channels,
6679 bool use_default_chmap,
6680 char *channel_map,
6681 uint16_t bits_per_sample,
6682 uint16_t sample_word_size,
6683 uint16_t endianness,
6684 uint16_t mode)
6685{
6686 return __q6asm_media_format_block_multi_ch_pcm_v5(ac, rate, channels,
6687 use_default_chmap,
6688 channel_map,
6689 bits_per_sample,
6690 sample_word_size,
6691 endianness,
6692 mode);
6693}
6694EXPORT_SYMBOL(q6asm_media_format_block_multi_ch_pcm_v5);
6695
6696
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306697/*
6698 * q6asm_media_format_block_gen_compr - set up generic compress format params
6699 *
6700 * @ac: Client session handle
6701 * @rate: sample rate
6702 * @channels: number of channels
6703 * @use_default_chmap: true if default channel map to be used
6704 * @channel_map: input channel map
6705 * @bits_per_sample: bit width of gen compress stream
6706 */
6707int q6asm_media_format_block_gen_compr(struct audio_client *ac,
6708 uint32_t rate, uint32_t channels,
6709 bool use_default_chmap, char *channel_map,
6710 uint16_t bits_per_sample)
6711{
6712 struct asm_generic_compressed_fmt_blk_t fmt;
6713 u8 *channel_mapping;
6714 int rc = 0;
6715
Rohit kumar6a14cfb2019-02-04 11:22:49 +05306716 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
6717 pr_err("%s: Invalid channel count %d\n", __func__, channels);
6718 return -EINVAL;
6719 }
6720
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306721 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]\n",
6722 __func__, ac->session, rate,
6723 channels, bits_per_sample);
6724
6725 memset(&fmt, 0, sizeof(fmt));
6726 q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
6727
6728 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6729 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6730 sizeof(fmt.fmt_blk);
6731 fmt.num_channels = channels;
6732 fmt.bits_per_sample = bits_per_sample;
6733 fmt.sampling_rate = rate;
6734
6735 channel_mapping = fmt.channel_mapping;
6736
6737 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
6738
6739 if (use_default_chmap) {
6740 if (q6asm_map_channels(channel_mapping, channels, false)) {
6741 pr_err("%s: map channels failed %d\n",
6742 __func__, channels);
6743 return -EINVAL;
6744 }
6745 } else {
6746 memcpy(channel_mapping, channel_map,
6747 PCM_FORMAT_MAX_NUM_CHANNEL);
6748 }
6749
6750 atomic_set(&ac->cmd_state, -1);
6751 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6752 if (rc < 0) {
6753 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
6754 rc = -EINVAL;
6755 goto fail_cmd;
6756 }
6757 rc = wait_event_timeout(ac->cmd_wait,
6758 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6759 if (!rc) {
6760 pr_err("%s: timeout. waited for format update\n", __func__);
6761 rc = -ETIMEDOUT;
6762 goto fail_cmd;
6763 }
6764
6765 if (atomic_read(&ac->cmd_state) > 0) {
6766 pr_err("%s: DSP returned error[%s]\n",
6767 __func__, adsp_err_get_err_str(
6768 atomic_read(&ac->cmd_state)));
6769 rc = adsp_err_get_lnx_err_code(
6770 atomic_read(&ac->cmd_state));
6771 }
6772 return 0;
6773fail_cmd:
6774 return rc;
6775}
6776EXPORT_SYMBOL(q6asm_media_format_block_gen_compr);
6777
6778
6779/*
6780 * q6asm_media_format_block_iec - set up IEC61937 (compressed) or IEC60958
6781 * (pcm) format params. Both audio standards
6782 * use the same format and are used for
6783 * HDMI or SPDIF.
6784 *
6785 * @ac: Client session handle
6786 * @rate: sample rate
6787 * @channels: number of channels
6788 */
6789int q6asm_media_format_block_iec(struct audio_client *ac,
6790 uint32_t rate, uint32_t channels)
6791{
6792 struct asm_iec_compressed_fmt_blk_t fmt;
6793 int rc = 0;
6794
6795 pr_debug("%s: session[%d]rate[%d]ch[%d]\n",
6796 __func__, ac->session, rate,
6797 channels);
6798
6799 memset(&fmt, 0, sizeof(fmt));
6800 q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
6801
6802 fmt.hdr.opcode = ASM_DATA_CMD_IEC_60958_MEDIA_FMT;
6803 fmt.num_channels = channels;
6804 fmt.sampling_rate = rate;
6805
6806 atomic_set(&ac->cmd_state, -1);
6807 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6808 if (rc < 0) {
6809 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
6810 rc = -EINVAL;
6811 goto fail_cmd;
6812 }
6813 rc = wait_event_timeout(ac->cmd_wait,
6814 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6815 if (!rc) {
6816 pr_err("%s: timeout. waited for format update\n", __func__);
6817 rc = -ETIMEDOUT;
6818 goto fail_cmd;
6819 }
6820
6821 if (atomic_read(&ac->cmd_state) > 0) {
6822 pr_err("%s: DSP returned error[%s]\n",
6823 __func__, adsp_err_get_err_str(
6824 atomic_read(&ac->cmd_state)));
6825 rc = adsp_err_get_lnx_err_code(
6826 atomic_read(&ac->cmd_state));
6827 }
6828 return 0;
6829fail_cmd:
6830 return rc;
6831}
6832EXPORT_SYMBOL(q6asm_media_format_block_iec);
6833
6834static int __q6asm_media_format_block_multi_aac(struct audio_client *ac,
6835 struct asm_aac_cfg *cfg, int stream_id)
6836{
6837 struct asm_aac_fmt_blk_v2 fmt;
6838 int rc = 0;
6839
6840 pr_debug("%s: session[%d]rate[%d]ch[%d]\n", __func__, ac->session,
6841 cfg->sample_rate, cfg->ch_cfg);
6842
6843 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6844 atomic_set(&ac->cmd_state, -1);
6845 /*
6846 * Updated the token field with stream/session for compressed playback
6847 * Platform driver must know the the stream with which the command is
6848 * associated
6849 */
6850 if (ac->io_mode & COMPRESSED_STREAM_IO)
6851 q6asm_update_token(&fmt.hdr.token,
6852 ac->session,
6853 stream_id,
6854 0, /* Buffer index is NA */
6855 0, /* Direction flag is NA */
6856 WAIT_CMD);
6857
6858 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
6859 __func__, fmt.hdr.token, stream_id, ac->session);
6860 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6861 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6862 sizeof(fmt.fmt_blk);
6863 fmt.aac_fmt_flag = cfg->format;
6864 fmt.audio_objype = cfg->aot;
6865 /* If zero, PCE is assumed to be available in bitstream*/
6866 fmt.total_size_of_PCE_bits = 0;
6867 fmt.channel_config = cfg->ch_cfg;
6868 fmt.sample_rate = cfg->sample_rate;
6869
6870 pr_debug("%s: format=0x%x cfg_size=%d aac-cfg=0x%x aot=%d ch=%d sr=%d\n",
6871 __func__, fmt.aac_fmt_flag, fmt.fmt_blk.fmt_blk_size,
6872 fmt.aac_fmt_flag,
6873 fmt.audio_objype,
6874 fmt.channel_config,
6875 fmt.sample_rate);
6876 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6877 if (rc < 0) {
6878 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
6879 rc = -EINVAL;
6880 goto fail_cmd;
6881 }
6882 rc = wait_event_timeout(ac->cmd_wait,
6883 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6884 if (!rc) {
6885 pr_err("%s: timeout. waited for FORMAT_UPDATE\n", __func__);
6886 rc = -ETIMEDOUT;
6887 goto fail_cmd;
6888 }
6889 if (atomic_read(&ac->cmd_state) > 0) {
6890 pr_err("%s: DSP returned error[%s]\n",
6891 __func__, adsp_err_get_err_str(
6892 atomic_read(&ac->cmd_state)));
6893 rc = adsp_err_get_lnx_err_code(
6894 atomic_read(&ac->cmd_state));
6895 goto fail_cmd;
6896 }
6897 return 0;
6898fail_cmd:
6899 return rc;
6900}
6901
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306902/**
6903 * q6asm_media_format_block_multi_aac -
6904 * command to set mediafmt block for multi_aac on ASM stream
6905 *
6906 * @ac: Audio client handle
6907 * @cfg: multi_aac config
6908 *
6909 * Returns 0 on success or error on failure
6910 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306911int q6asm_media_format_block_multi_aac(struct audio_client *ac,
6912 struct asm_aac_cfg *cfg)
6913{
6914 return __q6asm_media_format_block_multi_aac(ac, cfg, ac->stream_id);
6915}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306916EXPORT_SYMBOL(q6asm_media_format_block_multi_aac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306917
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306918/**
6919 * q6asm_media_format_block_aac -
6920 * command to set mediafmt block for aac on ASM
6921 *
6922 * @ac: Audio client handle
6923 * @cfg: aac config
6924 *
6925 * Returns 0 on success or error on failure
6926 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306927int q6asm_media_format_block_aac(struct audio_client *ac,
6928 struct asm_aac_cfg *cfg)
6929{
6930 return __q6asm_media_format_block_multi_aac(ac, cfg, ac->stream_id);
6931}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306932EXPORT_SYMBOL(q6asm_media_format_block_aac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306933
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306934/**
6935 * q6asm_stream_media_format_block_aac -
6936 * command to set mediafmt block for aac on ASM stream
6937 *
6938 * @ac: Audio client handle
6939 * @cfg: aac config
6940 * @stream_id: stream ID info
6941 *
6942 * Returns 0 on success or error on failure
6943 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306944int q6asm_stream_media_format_block_aac(struct audio_client *ac,
6945 struct asm_aac_cfg *cfg, int stream_id)
6946{
6947 return __q6asm_media_format_block_multi_aac(ac, cfg, stream_id);
6948}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306949EXPORT_SYMBOL(q6asm_stream_media_format_block_aac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306950
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306951/**
6952 * q6asm_media_format_block_wma -
6953 * command to set mediafmt block for wma on ASM stream
6954 *
6955 * @ac: Audio client handle
6956 * @cfg: wma config
6957 * @stream_id: stream ID info
6958 *
6959 * Returns 0 on success or error on failure
6960 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306961int q6asm_media_format_block_wma(struct audio_client *ac,
6962 void *cfg, int stream_id)
6963{
6964 struct asm_wmastdv9_fmt_blk_v2 fmt;
6965 struct asm_wma_cfg *wma_cfg = (struct asm_wma_cfg *)cfg;
6966 int rc = 0;
6967
6968 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",
6969 ac->session, wma_cfg->format_tag, wma_cfg->sample_rate,
6970 wma_cfg->ch_cfg, wma_cfg->avg_bytes_per_sec,
6971 wma_cfg->block_align, wma_cfg->valid_bits_per_sample,
6972 wma_cfg->ch_mask, wma_cfg->encode_opt);
6973
6974 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6975 atomic_set(&ac->cmd_state, -1);
6976
6977 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6978 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6979 sizeof(fmt.fmtblk);
6980 fmt.fmtag = wma_cfg->format_tag;
6981 fmt.num_channels = wma_cfg->ch_cfg;
6982 fmt.sample_rate = wma_cfg->sample_rate;
6983 fmt.avg_bytes_per_sec = wma_cfg->avg_bytes_per_sec;
6984 fmt.blk_align = wma_cfg->block_align;
6985 fmt.bits_per_sample =
6986 wma_cfg->valid_bits_per_sample;
6987 fmt.channel_mask = wma_cfg->ch_mask;
6988 fmt.enc_options = wma_cfg->encode_opt;
6989
6990 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6991 if (rc < 0) {
6992 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
6993 rc = -EINVAL;
6994 goto fail_cmd;
6995 }
6996 rc = wait_event_timeout(ac->cmd_wait,
6997 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6998 if (!rc) {
6999 pr_err("%s: timeout. waited for FORMAT_UPDATE\n", __func__);
7000 rc = -ETIMEDOUT;
7001 goto fail_cmd;
7002 }
7003 if (atomic_read(&ac->cmd_state) > 0) {
7004 pr_err("%s: DSP returned error[%s]\n",
7005 __func__, adsp_err_get_err_str(
7006 atomic_read(&ac->cmd_state)));
7007 rc = adsp_err_get_lnx_err_code(
7008 atomic_read(&ac->cmd_state));
7009 goto fail_cmd;
7010 }
7011 return 0;
7012fail_cmd:
7013 return rc;
7014}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307015EXPORT_SYMBOL(q6asm_media_format_block_wma);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307016
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307017/**
7018 * q6asm_media_format_block_wmapro -
7019 * command to set mediafmt block for wmapro on ASM stream
7020 *
7021 * @ac: Audio client handle
7022 * @cfg: wmapro config
7023 * @stream_id: stream ID info
7024 *
7025 * Returns 0 on success or error on failure
7026 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307027int q6asm_media_format_block_wmapro(struct audio_client *ac,
7028 void *cfg, int stream_id)
7029{
7030 struct asm_wmaprov10_fmt_blk_v2 fmt;
7031 struct asm_wmapro_cfg *wmapro_cfg = (struct asm_wmapro_cfg *)cfg;
7032 int rc = 0;
7033
7034 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",
7035 __func__,
7036 ac->session, wmapro_cfg->format_tag, wmapro_cfg->sample_rate,
7037 wmapro_cfg->ch_cfg, wmapro_cfg->avg_bytes_per_sec,
7038 wmapro_cfg->block_align, wmapro_cfg->valid_bits_per_sample,
7039 wmapro_cfg->ch_mask, wmapro_cfg->encode_opt,
7040 wmapro_cfg->adv_encode_opt, wmapro_cfg->adv_encode_opt2);
7041
7042 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
7043 atomic_set(&ac->cmd_state, -1);
7044
7045 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
7046 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
7047 sizeof(fmt.fmtblk);
7048
7049 fmt.fmtag = wmapro_cfg->format_tag;
7050 fmt.num_channels = wmapro_cfg->ch_cfg;
7051 fmt.sample_rate = wmapro_cfg->sample_rate;
7052 fmt.avg_bytes_per_sec =
7053 wmapro_cfg->avg_bytes_per_sec;
7054 fmt.blk_align = wmapro_cfg->block_align;
7055 fmt.bits_per_sample = wmapro_cfg->valid_bits_per_sample;
7056 fmt.channel_mask = wmapro_cfg->ch_mask;
7057 fmt.enc_options = wmapro_cfg->encode_opt;
7058 fmt.usAdvancedEncodeOpt = wmapro_cfg->adv_encode_opt;
7059 fmt.advanced_enc_options2 = wmapro_cfg->adv_encode_opt2;
7060
7061 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
7062 if (rc < 0) {
7063 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
7064 rc = -EINVAL;
7065 goto fail_cmd;
7066 }
7067 rc = wait_event_timeout(ac->cmd_wait,
7068 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
7069 if (!rc) {
7070 pr_err("%s: timeout. waited for FORMAT_UPDATE\n", __func__);
7071 rc = -ETIMEDOUT;
7072 goto fail_cmd;
7073 }
7074 if (atomic_read(&ac->cmd_state) > 0) {
7075 pr_err("%s: DSP returned error[%s]\n",
7076 __func__, adsp_err_get_err_str(
7077 atomic_read(&ac->cmd_state)));
7078 rc = adsp_err_get_lnx_err_code(
7079 atomic_read(&ac->cmd_state));
7080 goto fail_cmd;
7081 }
7082 return 0;
7083fail_cmd:
7084 return rc;
7085}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307086EXPORT_SYMBOL(q6asm_media_format_block_wmapro);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307087
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307088/**
7089 * q6asm_media_format_block_amrwbplus -
7090 * command to set mediafmt block for amrwbplus on ASM stream
7091 *
7092 * @ac: Audio client handle
7093 * @cfg: amrwbplus config
7094 * @stream_id: stream ID info
7095 *
7096 * Returns 0 on success or error on failure
7097 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307098int q6asm_media_format_block_amrwbplus(struct audio_client *ac,
7099 struct asm_amrwbplus_cfg *cfg)
7100{
7101 struct asm_amrwbplus_fmt_blk_v2 fmt;
7102 int rc = 0;
7103
7104 pr_debug("%s: session[%d]band-mode[%d]frame-fmt[%d]ch[%d]\n",
7105 __func__,
7106 ac->session,
7107 cfg->amr_band_mode,
7108 cfg->amr_frame_fmt,
7109 cfg->num_channels);
7110
7111 q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
7112 atomic_set(&ac->cmd_state, -1);
7113
7114 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
7115 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
7116 sizeof(fmt.fmtblk);
7117 fmt.amr_frame_fmt = cfg->amr_frame_fmt;
7118
7119 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
7120 if (rc < 0) {
7121 pr_err("%s: Comamnd media format update failed.. %d\n",
7122 __func__, rc);
7123 rc = -EINVAL;
7124 goto fail_cmd;
7125 }
7126 rc = wait_event_timeout(ac->cmd_wait,
7127 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
7128 if (!rc) {
7129 pr_err("%s: timeout. waited for FORMAT_UPDATE\n", __func__);
7130 rc = -ETIMEDOUT;
7131 goto fail_cmd;
7132 }
7133 if (atomic_read(&ac->cmd_state) > 0) {
7134 pr_err("%s: DSP returned error[%s]\n",
7135 __func__, adsp_err_get_err_str(
7136 atomic_read(&ac->cmd_state)));
7137 rc = adsp_err_get_lnx_err_code(
7138 atomic_read(&ac->cmd_state));
7139 goto fail_cmd;
7140 }
7141 return 0;
7142fail_cmd:
7143 return rc;
7144}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307145EXPORT_SYMBOL(q6asm_media_format_block_amrwbplus);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307146
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307147/**
7148 * q6asm_stream_media_format_block_flac -
7149 * command to set mediafmt block for flac on ASM stream
7150 *
7151 * @ac: Audio client handle
7152 * @cfg: FLAC config
7153 * @stream_id: stream ID info
7154 *
7155 * Returns 0 on success or error on failure
7156 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307157int q6asm_stream_media_format_block_flac(struct audio_client *ac,
7158 struct asm_flac_cfg *cfg, int stream_id)
7159{
7160 struct asm_flac_fmt_blk_v2 fmt;
7161 int rc = 0;
7162
7163 pr_debug("%s :session[%d] rate[%d] ch[%d] size[%d] stream_id[%d]\n",
7164 __func__, ac->session, cfg->sample_rate, cfg->ch_cfg,
7165 cfg->sample_size, stream_id);
7166
7167 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
7168 atomic_set(&ac->cmd_state, -1);
7169
7170 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
7171 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
7172 sizeof(fmt.fmtblk);
7173
7174 fmt.is_stream_info_present = cfg->stream_info_present;
7175 fmt.num_channels = cfg->ch_cfg;
7176 fmt.min_blk_size = cfg->min_blk_size;
7177 fmt.max_blk_size = cfg->max_blk_size;
7178 fmt.sample_rate = cfg->sample_rate;
7179 fmt.min_frame_size = cfg->min_frame_size;
7180 fmt.max_frame_size = cfg->max_frame_size;
7181 fmt.sample_size = cfg->sample_size;
7182
7183 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
7184 if (rc < 0) {
7185 pr_err("%s :Comamnd media format update failed %d\n",
7186 __func__, rc);
7187 goto fail_cmd;
7188 }
7189 rc = wait_event_timeout(ac->cmd_wait,
7190 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
7191 if (!rc) {
7192 pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
7193 rc = -ETIMEDOUT;
7194 goto fail_cmd;
7195 }
7196
7197 if (atomic_read(&ac->cmd_state) > 0) {
7198 pr_err("%s: DSP returned error[%s]\n",
7199 __func__, adsp_err_get_err_str(
7200 atomic_read(&ac->cmd_state)));
7201 rc = adsp_err_get_lnx_err_code(
7202 atomic_read(&ac->cmd_state));
7203 goto fail_cmd;
7204 }
7205 return 0;
7206fail_cmd:
7207 return rc;
7208}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307209EXPORT_SYMBOL(q6asm_stream_media_format_block_flac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307210
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307211/**
7212 * q6asm_media_format_block_alac -
7213 * command to set mediafmt block for alac on ASM stream
7214 *
7215 * @ac: Audio client handle
7216 * @cfg: ALAC config
7217 * @stream_id: stream ID info
7218 *
7219 * Returns 0 on success or error on failure
7220 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307221int q6asm_media_format_block_alac(struct audio_client *ac,
7222 struct asm_alac_cfg *cfg, int stream_id)
7223{
7224 struct asm_alac_fmt_blk_v2 fmt;
7225 int rc = 0;
7226
7227 pr_debug("%s :session[%d]rate[%d]ch[%d]\n", __func__,
7228 ac->session, cfg->sample_rate, cfg->num_channels);
7229
7230 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
7231 atomic_set(&ac->cmd_state, -1);
7232
7233 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
7234 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
7235 sizeof(fmt.fmtblk);
7236
7237 fmt.frame_length = cfg->frame_length;
7238 fmt.compatible_version = cfg->compatible_version;
7239 fmt.bit_depth = cfg->bit_depth;
7240 fmt.pb = cfg->pb;
7241 fmt.mb = cfg->mb;
7242 fmt.kb = cfg->kb;
7243 fmt.num_channels = cfg->num_channels;
7244 fmt.max_run = cfg->max_run;
7245 fmt.max_frame_bytes = cfg->max_frame_bytes;
7246 fmt.avg_bit_rate = cfg->avg_bit_rate;
7247 fmt.sample_rate = cfg->sample_rate;
7248 fmt.channel_layout_tag = cfg->channel_layout_tag;
7249
7250 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
7251 if (rc < 0) {
7252 pr_err("%s :Comamnd media format update failed %d\n",
7253 __func__, rc);
7254 goto fail_cmd;
7255 }
7256 rc = wait_event_timeout(ac->cmd_wait,
7257 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
7258 if (!rc) {
7259 pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
7260 rc = -ETIMEDOUT;
7261 goto fail_cmd;
7262 }
7263
7264 if (atomic_read(&ac->cmd_state) > 0) {
7265 pr_err("%s: DSP returned error[%s]\n",
7266 __func__, adsp_err_get_err_str(
7267 atomic_read(&ac->cmd_state)));
7268 rc = adsp_err_get_lnx_err_code(
7269 atomic_read(&ac->cmd_state));
7270 goto fail_cmd;
7271 }
7272 return 0;
7273fail_cmd:
7274 return rc;
7275}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307276EXPORT_SYMBOL(q6asm_media_format_block_alac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307277
7278/*
7279 * q6asm_media_format_block_g711 - sends g711 decoder configuration
7280 * parameters
7281 * @ac: Client session handle
7282 * @cfg: Audio stream manager configuration parameters
7283 * @stream_id: Stream id
7284 */
7285int q6asm_media_format_block_g711(struct audio_client *ac,
7286 struct asm_g711_dec_cfg *cfg, int stream_id)
7287{
7288 struct asm_g711_dec_fmt_blk_v2 fmt;
7289 int rc = 0;
7290
7291 if (!ac) {
7292 pr_err("%s: audio client is null\n", __func__);
7293 return -EINVAL;
7294 }
7295 if (!cfg) {
7296 pr_err("%s: Invalid ASM config\n", __func__);
7297 return -EINVAL;
7298 }
7299
7300 if (stream_id <= 0) {
7301 pr_err("%s: Invalid stream id\n", __func__);
7302 return -EINVAL;
7303 }
7304
7305 pr_debug("%s :session[%d]rate[%d]\n", __func__,
7306 ac->session, cfg->sample_rate);
7307
7308 memset(&fmt, 0, sizeof(struct asm_g711_dec_fmt_blk_v2));
7309
7310 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
7311 atomic_set(&ac->cmd_state, -1);
7312
7313 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
7314 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
7315 sizeof(fmt.fmtblk);
7316
7317 fmt.sample_rate = cfg->sample_rate;
7318
7319 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
7320 if (rc < 0) {
7321 pr_err("%s :Command media format update failed %d\n",
7322 __func__, rc);
7323 goto fail_cmd;
7324 }
7325 rc = wait_event_timeout(ac->cmd_wait,
7326 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
7327 if (!rc) {
7328 pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
7329 rc = -ETIMEDOUT;
7330 goto fail_cmd;
7331 }
7332
7333 if (atomic_read(&ac->cmd_state) > 0) {
7334 pr_err("%s: DSP returned error[%s]\n",
7335 __func__, adsp_err_get_err_str(
7336 atomic_read(&ac->cmd_state)));
7337 rc = adsp_err_get_lnx_err_code(
7338 atomic_read(&ac->cmd_state));
7339 goto fail_cmd;
7340 }
7341 return 0;
7342fail_cmd:
7343 return rc;
7344}
7345EXPORT_SYMBOL(q6asm_media_format_block_g711);
7346
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307347/**
7348 * q6asm_stream_media_format_block_vorbis -
7349 * command to set mediafmt block for vorbis on ASM stream
7350 *
7351 * @ac: Audio client handle
7352 * @cfg: vorbis config
7353 * @stream_id: stream ID info
7354 *
7355 * Returns 0 on success or error on failure
7356 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307357int q6asm_stream_media_format_block_vorbis(struct audio_client *ac,
7358 struct asm_vorbis_cfg *cfg, int stream_id)
7359{
7360 struct asm_vorbis_fmt_blk_v2 fmt;
7361 int rc = 0;
7362
7363 pr_debug("%s :session[%d] bit_stream_fmt[%d] stream_id[%d]\n",
7364 __func__, ac->session, cfg->bit_stream_fmt, stream_id);
7365
7366 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
7367 atomic_set(&ac->cmd_state, -1);
7368
7369 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
7370 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
7371 sizeof(fmt.fmtblk);
7372
7373 fmt.bit_stream_fmt = cfg->bit_stream_fmt;
7374
7375 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
7376 if (rc < 0) {
7377 pr_err("%s :Comamnd media format update failed %d\n",
7378 __func__, rc);
7379 goto fail_cmd;
7380 }
7381 rc = wait_event_timeout(ac->cmd_wait,
7382 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
7383 if (!rc) {
7384 pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
7385 rc = -ETIMEDOUT;
7386 goto fail_cmd;
7387 }
7388
7389 if (atomic_read(&ac->cmd_state) > 0) {
7390 pr_err("%s: DSP returned error[%s]\n",
7391 __func__, adsp_err_get_err_str(
7392 atomic_read(&ac->cmd_state)));
7393 rc = adsp_err_get_lnx_err_code(
7394 atomic_read(&ac->cmd_state));
7395 goto fail_cmd;
7396 }
7397 return 0;
7398fail_cmd:
7399 return rc;
7400}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307401EXPORT_SYMBOL(q6asm_stream_media_format_block_vorbis);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307402
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307403/**
7404 * q6asm_media_format_block_ape -
7405 * command to set mediafmt block for APE on ASM stream
7406 *
7407 * @ac: Audio client handle
7408 * @cfg: APE config
7409 * @stream_id: stream ID info
7410 *
7411 * Returns 0 on success or error on failure
7412 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307413int q6asm_media_format_block_ape(struct audio_client *ac,
7414 struct asm_ape_cfg *cfg, int stream_id)
7415{
7416 struct asm_ape_fmt_blk_v2 fmt;
7417 int rc = 0;
7418
7419 pr_debug("%s :session[%d]rate[%d]ch[%d]\n", __func__,
7420 ac->session, cfg->sample_rate, cfg->num_channels);
7421
7422 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
7423 atomic_set(&ac->cmd_state, -1);
7424
7425 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
7426 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
7427 sizeof(fmt.fmtblk);
7428
7429 fmt.compatible_version = cfg->compatible_version;
7430 fmt.compression_level = cfg->compression_level;
7431 fmt.format_flags = cfg->format_flags;
7432 fmt.blocks_per_frame = cfg->blocks_per_frame;
7433 fmt.final_frame_blocks = cfg->final_frame_blocks;
7434 fmt.total_frames = cfg->total_frames;
7435 fmt.bits_per_sample = cfg->bits_per_sample;
7436 fmt.num_channels = cfg->num_channels;
7437 fmt.sample_rate = cfg->sample_rate;
7438 fmt.seek_table_present = cfg->seek_table_present;
7439
7440 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
7441 if (rc < 0) {
7442 pr_err("%s :Comamnd media format update failed %d\n",
7443 __func__, rc);
7444 goto fail_cmd;
7445 }
7446 rc = wait_event_timeout(ac->cmd_wait,
7447 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
7448 if (!rc) {
7449 pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
7450 rc = -ETIMEDOUT;
7451 goto fail_cmd;
7452 }
7453
7454 if (atomic_read(&ac->cmd_state) > 0) {
7455 pr_err("%s: DSP returned error[%s]\n",
7456 __func__, adsp_err_get_err_str(
7457 atomic_read(&ac->cmd_state)));
7458 rc = adsp_err_get_lnx_err_code(
7459 atomic_read(&ac->cmd_state));
7460 goto fail_cmd;
7461 }
7462 return 0;
7463fail_cmd:
7464 return rc;
7465}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307466EXPORT_SYMBOL(q6asm_media_format_block_ape);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307467
7468/*
7469 * q6asm_media_format_block_dsd- Sends DSD Decoder
7470 * configuration parameters
7471 *
7472 * @ac: Client session handle
7473 * @cfg: DSD Media Format Configuration.
7474 * @stream_id: stream id of stream to be associated with this session
7475 *
7476 * Return 0 on success or negative error code on failure
7477 */
7478int q6asm_media_format_block_dsd(struct audio_client *ac,
7479 struct asm_dsd_cfg *cfg, int stream_id)
7480{
7481 struct asm_dsd_fmt_blk_v2 fmt;
7482 int rc;
7483
7484 pr_debug("%s: session[%d] data_rate[%d] ch[%d]\n", __func__,
7485 ac->session, cfg->dsd_data_rate, cfg->num_channels);
7486
7487 memset(&fmt, 0, sizeof(fmt));
7488 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
7489
7490 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
7491 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
7492 sizeof(fmt.fmtblk);
7493
7494 fmt.num_version = cfg->num_version;
7495 fmt.is_bitwise_big_endian = cfg->is_bitwise_big_endian;
7496 fmt.dsd_channel_block_size = cfg->dsd_channel_block_size;
7497 fmt.num_channels = cfg->num_channels;
7498 fmt.dsd_data_rate = cfg->dsd_data_rate;
7499 atomic_set(&ac->cmd_state, -1);
7500 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
7501 if (rc < 0) {
7502 pr_err("%s: Command DSD media format update failed, err: %d\n",
7503 __func__, rc);
7504 goto done;
7505 }
7506 rc = wait_event_timeout(ac->cmd_wait,
7507 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
7508 if (!rc) {
7509 pr_err("%s: timeout. waited for DSD FORMAT_UPDATE\n", __func__);
7510 rc = -ETIMEDOUT;
7511 goto done;
7512 }
7513
7514 if (atomic_read(&ac->cmd_state) > 0) {
7515 pr_err("%s: DSP returned error[%s]\n",
7516 __func__, adsp_err_get_err_str(
7517 atomic_read(&ac->cmd_state)));
7518 rc = adsp_err_get_lnx_err_code(
7519 atomic_read(&ac->cmd_state));
7520 goto done;
7521 }
7522 return 0;
7523done:
7524 return rc;
7525}
7526EXPORT_SYMBOL(q6asm_media_format_block_dsd);
7527
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307528/**
7529 * q6asm_stream_media_format_block_aptx_dec -
7530 * command to set mediafmt block for APTX dec on ASM stream
7531 *
7532 * @ac: Audio client handle
7533 * @srate: sample rate
7534 * @stream_id: stream ID info
7535 *
7536 * Returns 0 on success or error on failure
7537 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307538int q6asm_stream_media_format_block_aptx_dec(struct audio_client *ac,
7539 uint32_t srate, int stream_id)
7540{
7541 struct asm_aptx_dec_fmt_blk_v2 aptx_fmt;
7542 int rc = 0;
7543
7544 if (!ac->session) {
7545 pr_err("%s: ac session invalid\n", __func__);
7546 rc = -EINVAL;
7547 goto fail_cmd;
7548 }
7549 pr_debug("%s :session[%d] rate[%d] stream_id[%d]\n",
7550 __func__, ac->session, srate, stream_id);
7551
7552 q6asm_stream_add_hdr(ac, &aptx_fmt.hdr, sizeof(aptx_fmt), TRUE,
7553 stream_id);
7554 atomic_set(&ac->cmd_state, -1);
7555
7556 aptx_fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
7557 aptx_fmt.fmtblk.fmt_blk_size = sizeof(aptx_fmt) - sizeof(aptx_fmt.hdr) -
7558 sizeof(aptx_fmt.fmtblk);
7559
7560 aptx_fmt.sample_rate = srate;
7561
7562 rc = apr_send_pkt(ac->apr, (uint32_t *) &aptx_fmt);
7563 if (rc < 0) {
7564 pr_err("%s :Comamnd media format update failed %d\n",
7565 __func__, rc);
7566 goto fail_cmd;
7567 }
7568 rc = wait_event_timeout(ac->cmd_wait,
7569 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
7570 if (!rc) {
7571 pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
7572 rc = -ETIMEDOUT;
7573 goto fail_cmd;
7574 }
7575
7576 if (atomic_read(&ac->cmd_state) > 0) {
7577 pr_err("%s: DSP returned error[%s]\n",
7578 __func__, adsp_err_get_err_str(
7579 atomic_read(&ac->cmd_state)));
7580 rc = adsp_err_get_lnx_err_code(
7581 atomic_read(&ac->cmd_state));
7582 goto fail_cmd;
7583 }
7584 rc = 0;
7585fail_cmd:
7586 return rc;
7587}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307588EXPORT_SYMBOL(q6asm_stream_media_format_block_aptx_dec);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307589
7590static int __q6asm_ds1_set_endp_params(struct audio_client *ac, int param_id,
7591 int param_value, int stream_id)
7592{
7593 struct asm_dec_ddp_endp_param_v2 ddp_cfg;
7594 int rc = 0;
7595
7596 pr_debug("%s: session[%d] stream[%d],param_id[%d]param_value[%d]",
7597 __func__, ac->session, stream_id, param_id, param_value);
7598
7599 q6asm_stream_add_hdr(ac, &ddp_cfg.hdr, sizeof(ddp_cfg), TRUE,
7600 stream_id);
7601 atomic_set(&ac->cmd_state, -1);
7602 /*
7603 * Updated the token field with stream/session for compressed playback
7604 * Platform driver must know the stream with which the command is
7605 * associated
7606 */
7607 if (ac->io_mode & COMPRESSED_STREAM_IO)
7608 q6asm_update_token(&ddp_cfg.hdr.token,
7609 ac->session,
7610 stream_id,
7611 0, /* Buffer index is NA */
7612 0, /* Direction flag is NA */
7613 WAIT_CMD);
7614 ddp_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
7615 ddp_cfg.encdec.param_id = param_id;
7616 ddp_cfg.encdec.param_size = sizeof(struct asm_dec_ddp_endp_param_v2) -
7617 (sizeof(struct apr_hdr) +
7618 sizeof(struct asm_stream_cmd_set_encdec_param));
7619 ddp_cfg.endp_param_value = param_value;
7620 rc = apr_send_pkt(ac->apr, (uint32_t *) &ddp_cfg);
7621 if (rc < 0) {
7622 pr_err("%s: Command opcode[0x%x] failed %d\n",
7623 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
7624 goto fail_cmd;
7625 }
7626 rc = wait_event_timeout(ac->cmd_wait,
7627 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
7628 if (!rc) {
7629 pr_err("%s: timeout opcode[0x%x]\n", __func__,
7630 ddp_cfg.hdr.opcode);
7631 rc = -ETIMEDOUT;
7632 goto fail_cmd;
7633 }
7634 if (atomic_read(&ac->cmd_state) > 0) {
7635 pr_err("%s: DSP returned error[%s]\n",
7636 __func__, adsp_err_get_err_str(
7637 atomic_read(&ac->cmd_state)));
7638 rc = adsp_err_get_lnx_err_code(
7639 atomic_read(&ac->cmd_state));
7640 goto fail_cmd;
7641 }
7642 return 0;
7643fail_cmd:
7644 return rc;
7645}
7646
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307647/**
7648 * q6asm_ds1_set_endp_params -
7649 * command to set DS1 params for ASM
7650 *
7651 * @ac: Audio client handle
7652 * @param_id: param id
7653 * @param_value: value of param
7654 *
7655 * Returns 0 on success or error on failure
7656 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307657int q6asm_ds1_set_endp_params(struct audio_client *ac,
7658 int param_id, int param_value)
7659{
7660 return __q6asm_ds1_set_endp_params(ac, param_id, param_value,
7661 ac->stream_id);
7662}
7663
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307664/**
7665 * q6asm_ds1_set_stream_endp_params -
7666 * command to set DS1 params for ASM stream
7667 *
7668 * @ac: Audio client handle
7669 * @param_id: param id
7670 * @param_value: value of param
7671 * @stream_id: stream ID info
7672 *
7673 * Returns 0 on success or error on failure
7674 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307675int q6asm_ds1_set_stream_endp_params(struct audio_client *ac,
7676 int param_id, int param_value,
7677 int stream_id)
7678{
7679 return __q6asm_ds1_set_endp_params(ac, param_id, param_value,
7680 stream_id);
7681}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307682EXPORT_SYMBOL(q6asm_ds1_set_stream_endp_params);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307683
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307684/**
7685 * q6asm_memory_map -
7686 * command to send memory map for ASM
7687 *
7688 * @ac: Audio client handle
7689 * @buf_add: buffer address to map
7690 * @dir: RX or TX session
7691 * @bufsz: size of each buffer
7692 * @bufcnt: buffer count
7693 *
7694 * Returns 0 on success or error on failure
7695 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307696int q6asm_memory_map(struct audio_client *ac, phys_addr_t buf_add, int dir,
7697 uint32_t bufsz, uint32_t bufcnt)
7698{
7699 struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
7700 struct avs_shared_map_region_payload *mregions = NULL;
7701 struct audio_port_data *port = NULL;
7702 void *mmap_region_cmd = NULL;
7703 void *payload = NULL;
7704 struct asm_buffer_node *buffer_node = NULL;
7705 int rc = 0;
7706 int cmd_size = 0;
7707
7708 if (!ac) {
7709 pr_err("%s: APR handle NULL\n", __func__);
7710 return -EINVAL;
7711 }
7712 if (ac->mmap_apr == NULL) {
7713 pr_err("%s: mmap APR handle NULL\n", __func__);
7714 return -EINVAL;
7715 }
7716 pr_debug("%s: Session[%d]\n", __func__, ac->session);
7717
7718 buffer_node = kmalloc(sizeof(struct asm_buffer_node), GFP_KERNEL);
7719 if (!buffer_node)
7720 return -ENOMEM;
7721
7722 cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions)
7723 + sizeof(struct avs_shared_map_region_payload) * bufcnt;
7724
7725 mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
7726 if (mmap_region_cmd == NULL) {
7727 rc = -EINVAL;
7728 kfree(buffer_node);
7729 return rc;
7730 }
7731 mmap_regions = (struct avs_cmd_shared_mem_map_regions *)
7732 mmap_region_cmd;
7733 q6asm_add_mmaphdr(ac, &mmap_regions->hdr, cmd_size, dir);
7734 atomic_set(&ac->mem_state, -1);
7735 mmap_regions->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS;
7736 mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
7737 mmap_regions->num_regions = bufcnt & 0x00ff;
7738 mmap_regions->property_flag = 0x00;
7739 payload = ((u8 *) mmap_region_cmd +
7740 sizeof(struct avs_cmd_shared_mem_map_regions));
7741 mregions = (struct avs_shared_map_region_payload *)payload;
7742
7743 ac->port[dir].tmp_hdl = 0;
7744 port = &ac->port[dir];
7745 pr_debug("%s: buf_add 0x%pK, bufsz: %d\n", __func__,
7746 &buf_add, bufsz);
7747 mregions->shm_addr_lsw = lower_32_bits(buf_add);
7748 mregions->shm_addr_msw = msm_audio_populate_upper_32_bits(buf_add);
7749 mregions->mem_size_bytes = bufsz;
7750 ++mregions;
7751
7752 rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) mmap_region_cmd);
7753 if (rc < 0) {
7754 pr_err("%s: mmap op[0x%x]rc[%d]\n", __func__,
7755 mmap_regions->hdr.opcode, rc);
7756 rc = -EINVAL;
7757 kfree(buffer_node);
7758 goto fail_cmd;
7759 }
7760
7761 rc = wait_event_timeout(ac->mem_wait,
7762 (atomic_read(&ac->mem_state) >= 0 &&
7763 ac->port[dir].tmp_hdl), 5*HZ);
7764 if (!rc) {
7765 pr_err("%s: timeout. waited for memory_map\n", __func__);
7766 rc = -ETIMEDOUT;
7767 kfree(buffer_node);
7768 goto fail_cmd;
7769 }
7770 if (atomic_read(&ac->mem_state) > 0) {
7771 pr_err("%s: DSP returned error[%s] for memory_map\n",
7772 __func__, adsp_err_get_err_str(
7773 atomic_read(&ac->mem_state)));
7774 rc = adsp_err_get_lnx_err_code(
7775 atomic_read(&ac->mem_state));
7776 kfree(buffer_node);
7777 goto fail_cmd;
7778 }
7779 buffer_node->buf_phys_addr = buf_add;
7780 buffer_node->mmap_hdl = ac->port[dir].tmp_hdl;
7781 list_add_tail(&buffer_node->list, &ac->port[dir].mem_map_handle);
7782 ac->port[dir].tmp_hdl = 0;
7783 rc = 0;
7784
7785fail_cmd:
7786 kfree(mmap_region_cmd);
7787 return rc;
7788}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307789EXPORT_SYMBOL(q6asm_memory_map);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307790
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307791/**
7792 * q6asm_memory_unmap -
7793 * command to send memory unmap for ASM
7794 *
7795 * @ac: Audio client handle
7796 * @buf_add: buffer address to unmap
7797 * @dir: RX or TX session
7798 *
7799 * Returns 0 on success or error on failure
7800 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307801int q6asm_memory_unmap(struct audio_client *ac, phys_addr_t buf_add, int dir)
7802{
7803 struct avs_cmd_shared_mem_unmap_regions mem_unmap;
7804 struct asm_buffer_node *buf_node = NULL;
7805 struct list_head *ptr, *next;
7806
7807 int rc = 0;
7808
7809 if (!ac) {
7810 pr_err("%s: APR handle NULL\n", __func__);
7811 return -EINVAL;
7812 }
7813 if (this_mmap.apr == NULL) {
7814 pr_err("%s: APR handle NULL\n", __func__);
7815 return -EINVAL;
7816 }
7817 pr_debug("%s: Session[%d]\n", __func__, ac->session);
7818
7819 q6asm_add_mmaphdr(ac, &mem_unmap.hdr,
7820 sizeof(struct avs_cmd_shared_mem_unmap_regions),
7821 dir);
7822 atomic_set(&ac->mem_state, -1);
7823 mem_unmap.hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS;
7824 mem_unmap.mem_map_handle = 0;
7825 list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
7826 buf_node = list_entry(ptr, struct asm_buffer_node,
7827 list);
7828 if (buf_node->buf_phys_addr == buf_add) {
7829 pr_debug("%s: Found the element\n", __func__);
7830 mem_unmap.mem_map_handle = buf_node->mmap_hdl;
7831 break;
7832 }
7833 }
7834 pr_debug("%s: mem_unmap-mem_map_handle: 0x%x\n",
7835 __func__, mem_unmap.mem_map_handle);
7836
7837 if (mem_unmap.mem_map_handle == 0) {
7838 pr_err("%s: Do not send null mem handle to DSP\n", __func__);
7839 rc = 0;
7840 goto fail_cmd;
7841 }
7842 rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) &mem_unmap);
7843 if (rc < 0) {
7844 pr_err("%s: mem_unmap op[0x%x]rc[%d]\n", __func__,
7845 mem_unmap.hdr.opcode, rc);
7846 rc = -EINVAL;
7847 goto fail_cmd;
7848 }
7849
7850 rc = wait_event_timeout(ac->mem_wait,
7851 (atomic_read(&ac->mem_state) >= 0), 5 * HZ);
7852 if (!rc) {
7853 pr_err("%s: timeout. waited for memory_unmap of handle 0x%x\n",
7854 __func__, mem_unmap.mem_map_handle);
7855 rc = -ETIMEDOUT;
7856 goto fail_cmd;
7857 } else if (atomic_read(&ac->mem_state) > 0) {
7858 pr_err("%s DSP returned error [%s] map handle 0x%x\n",
7859 __func__, adsp_err_get_err_str(
7860 atomic_read(&ac->mem_state)),
7861 mem_unmap.mem_map_handle);
7862 rc = adsp_err_get_lnx_err_code(
7863 atomic_read(&ac->mem_state));
7864 goto fail_cmd;
7865 } else if (atomic_read(&ac->unmap_cb_success) == 0) {
7866 pr_err("%s: Error in mem unmap callback of handle 0x%x\n",
7867 __func__, mem_unmap.mem_map_handle);
7868 rc = -EINVAL;
7869 goto fail_cmd;
7870 }
7871
7872 rc = 0;
7873fail_cmd:
7874 list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
7875 buf_node = list_entry(ptr, struct asm_buffer_node,
7876 list);
7877 if (buf_node->buf_phys_addr == buf_add) {
7878 list_del(&buf_node->list);
7879 kfree(buf_node);
7880 break;
7881 }
7882 }
7883 return rc;
7884}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307885EXPORT_SYMBOL(q6asm_memory_unmap);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307886
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307887/**
7888 * q6asm_memory_map_regions -
7889 * command to send memory map regions for ASM
7890 *
7891 * @ac: Audio client handle
7892 * @dir: RX or TX session
7893 * @bufsz: size of each buffer
7894 * @bufcnt: buffer count
7895 * @is_contiguous: alloc contiguous mem or not
7896 *
7897 * Returns 0 on success or error on failure
7898 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307899static int q6asm_memory_map_regions(struct audio_client *ac, int dir,
7900 uint32_t bufsz, uint32_t bufcnt,
7901 bool is_contiguous)
7902{
7903 struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
7904 struct avs_shared_map_region_payload *mregions = NULL;
7905 struct audio_port_data *port = NULL;
7906 struct audio_buffer *ab = NULL;
7907 void *mmap_region_cmd = NULL;
7908 void *payload = NULL;
7909 struct asm_buffer_node *buffer_node = NULL;
7910 int rc = 0;
7911 int i = 0;
7912 uint32_t cmd_size = 0;
7913 uint32_t bufcnt_t;
7914 uint32_t bufsz_t;
7915
7916 if (!ac) {
7917 pr_err("%s: APR handle NULL\n", __func__);
7918 return -EINVAL;
7919 }
7920 if (ac->mmap_apr == NULL) {
7921 pr_err("%s: mmap APR handle NULL\n", __func__);
7922 return -EINVAL;
7923 }
7924 pr_debug("%s: Session[%d]\n", __func__, ac->session);
7925
7926 bufcnt_t = (is_contiguous) ? 1 : bufcnt;
7927 bufsz_t = (is_contiguous) ? (bufsz * bufcnt) : bufsz;
7928
7929 if (is_contiguous) {
7930 /* The size to memory map should be multiple of 4K bytes */
7931 bufsz_t = PAGE_ALIGN(bufsz_t);
7932 }
7933
7934 if (bufcnt_t > (UINT_MAX
7935 - sizeof(struct avs_cmd_shared_mem_map_regions))
7936 / sizeof(struct avs_shared_map_region_payload)) {
7937 pr_err("%s: Unsigned Integer Overflow. bufcnt_t = %u\n",
7938 __func__, bufcnt_t);
7939 return -EINVAL;
7940 }
7941
7942 cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions)
7943 + (sizeof(struct avs_shared_map_region_payload)
7944 * bufcnt_t);
7945
7946
7947 if (bufcnt > (UINT_MAX / sizeof(struct asm_buffer_node))) {
7948 pr_err("%s: Unsigned Integer Overflow. bufcnt = %u\n",
7949 __func__, bufcnt);
7950 return -EINVAL;
7951 }
7952
7953 buffer_node = kzalloc(sizeof(struct asm_buffer_node) * bufcnt,
7954 GFP_KERNEL);
7955 if (!buffer_node)
7956 return -ENOMEM;
7957
7958 mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
7959 if (mmap_region_cmd == NULL) {
7960 rc = -EINVAL;
7961 kfree(buffer_node);
7962 return rc;
7963 }
7964 mmap_regions = (struct avs_cmd_shared_mem_map_regions *)
7965 mmap_region_cmd;
7966 q6asm_add_mmaphdr(ac, &mmap_regions->hdr, cmd_size, dir);
7967 atomic_set(&ac->mem_state, -1);
7968 pr_debug("%s: mmap_region=0x%pK token=0x%x\n", __func__,
7969 mmap_regions, ((ac->session << 8) | dir));
7970
7971 mmap_regions->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS;
7972 mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
7973 mmap_regions->num_regions = bufcnt_t; /*bufcnt & 0x00ff; */
7974 mmap_regions->property_flag = 0x00;
7975 pr_debug("%s: map_regions->nregions = %d\n", __func__,
7976 mmap_regions->num_regions);
7977 payload = ((u8 *) mmap_region_cmd +
7978 sizeof(struct avs_cmd_shared_mem_map_regions));
7979 mregions = (struct avs_shared_map_region_payload *)payload;
7980
7981 ac->port[dir].tmp_hdl = 0;
7982 port = &ac->port[dir];
7983 for (i = 0; i < bufcnt_t; i++) {
7984 ab = &port->buf[i];
7985 mregions->shm_addr_lsw = lower_32_bits(ab->phys);
7986 mregions->shm_addr_msw =
7987 msm_audio_populate_upper_32_bits(ab->phys);
7988 mregions->mem_size_bytes = bufsz_t;
7989 ++mregions;
7990 }
7991
7992 rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) mmap_region_cmd);
7993 if (rc < 0) {
7994 pr_err("%s: mmap_regions op[0x%x]rc[%d]\n", __func__,
7995 mmap_regions->hdr.opcode, rc);
7996 rc = -EINVAL;
7997 kfree(buffer_node);
7998 goto fail_cmd;
7999 }
8000
8001 rc = wait_event_timeout(ac->mem_wait,
Meng Wang56d55952018-02-27 11:16:32 +08008002 (atomic_read(&ac->mem_state) >= 0 &&
8003 ac->port[dir].tmp_hdl), 5*HZ);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308004 if (!rc) {
8005 pr_err("%s: timeout. waited for memory_map\n", __func__);
8006 rc = -ETIMEDOUT;
8007 kfree(buffer_node);
8008 goto fail_cmd;
8009 }
8010 if (atomic_read(&ac->mem_state) > 0) {
8011 pr_err("%s DSP returned error for memory_map [%s]\n",
8012 __func__, adsp_err_get_err_str(
8013 atomic_read(&ac->mem_state)));
8014 rc = adsp_err_get_lnx_err_code(
8015 atomic_read(&ac->mem_state));
8016 kfree(buffer_node);
8017 goto fail_cmd;
8018 }
8019 mutex_lock(&ac->cmd_lock);
8020
8021 for (i = 0; i < bufcnt; i++) {
8022 ab = &port->buf[i];
8023 buffer_node[i].buf_phys_addr = ab->phys;
8024 buffer_node[i].mmap_hdl = ac->port[dir].tmp_hdl;
8025 list_add_tail(&buffer_node[i].list,
8026 &ac->port[dir].mem_map_handle);
8027 pr_debug("%s: i=%d, bufadd[i] = 0x%pK, maphdl[i] = 0x%x\n",
8028 __func__, i, &buffer_node[i].buf_phys_addr,
8029 buffer_node[i].mmap_hdl);
8030 }
8031 ac->port[dir].tmp_hdl = 0;
8032 mutex_unlock(&ac->cmd_lock);
8033 rc = 0;
8034fail_cmd:
8035 kfree(mmap_region_cmd);
8036 return rc;
8037}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308038EXPORT_SYMBOL(q6asm_memory_map_regions);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308039
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308040/**
8041 * q6asm_memory_unmap_regions -
8042 * command to send memory unmap regions for ASM
8043 *
8044 * @ac: Audio client handle
8045 * @dir: RX or TX session
8046 *
8047 * Returns 0 on success or error on failure
8048 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308049static int q6asm_memory_unmap_regions(struct audio_client *ac, int dir)
8050{
8051 struct avs_cmd_shared_mem_unmap_regions mem_unmap;
8052 struct audio_port_data *port = NULL;
8053 struct asm_buffer_node *buf_node = NULL;
8054 struct list_head *ptr, *next;
8055 phys_addr_t buf_add;
8056 int rc = 0;
8057 int cmd_size = 0;
8058
8059 if (!ac) {
8060 pr_err("%s: APR handle NULL\n", __func__);
8061 return -EINVAL;
8062 }
8063 if (ac->mmap_apr == NULL) {
8064 pr_err("%s: mmap APR handle NULL\n", __func__);
8065 return -EINVAL;
8066 }
8067 pr_debug("%s: Session[%d]\n", __func__, ac->session);
8068
8069 cmd_size = sizeof(struct avs_cmd_shared_mem_unmap_regions);
8070 q6asm_add_mmaphdr(ac, &mem_unmap.hdr, cmd_size, dir);
8071 atomic_set(&ac->mem_state, -1);
8072 port = &ac->port[dir];
8073 buf_add = port->buf->phys;
8074 mem_unmap.hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS;
8075 mem_unmap.mem_map_handle = 0;
8076 list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
8077 buf_node = list_entry(ptr, struct asm_buffer_node,
8078 list);
8079 if (buf_node->buf_phys_addr == buf_add) {
8080 pr_debug("%s: Found the element\n", __func__);
8081 mem_unmap.mem_map_handle = buf_node->mmap_hdl;
8082 break;
8083 }
8084 }
8085
8086 pr_debug("%s: mem_unmap-mem_map_handle: 0x%x\n",
8087 __func__, mem_unmap.mem_map_handle);
8088
8089 if (mem_unmap.mem_map_handle == 0) {
8090 pr_err("%s: Do not send null mem handle to DSP\n", __func__);
8091 rc = 0;
8092 goto fail_cmd;
8093 }
8094 rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) &mem_unmap);
8095 if (rc < 0) {
8096 pr_err("mmap_regions op[0x%x]rc[%d]\n",
8097 mem_unmap.hdr.opcode, rc);
8098 goto fail_cmd;
8099 }
8100
8101 rc = wait_event_timeout(ac->mem_wait,
8102 (atomic_read(&ac->mem_state) >= 0), 5*HZ);
8103 if (!rc) {
8104 pr_err("%s: timeout. waited for memory_unmap of handle 0x%x\n",
8105 __func__, mem_unmap.mem_map_handle);
8106 rc = -ETIMEDOUT;
8107 goto fail_cmd;
8108 } else if (atomic_read(&ac->mem_state) > 0) {
8109 pr_err("%s: DSP returned error[%s]\n",
8110 __func__, adsp_err_get_err_str(
8111 atomic_read(&ac->mem_state)));
8112 rc = adsp_err_get_lnx_err_code(
8113 atomic_read(&ac->mem_state));
8114 goto fail_cmd;
8115 } else if (atomic_read(&ac->unmap_cb_success) == 0) {
8116 pr_err("%s: Error in mem unmap callback of handle 0x%x\n",
8117 __func__, mem_unmap.mem_map_handle);
8118 rc = -EINVAL;
8119 goto fail_cmd;
8120 }
8121 rc = 0;
8122
8123fail_cmd:
8124 list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
8125 buf_node = list_entry(ptr, struct asm_buffer_node,
8126 list);
8127 if (buf_node->buf_phys_addr == buf_add) {
8128 list_del(&buf_node->list);
8129 kfree(buf_node);
8130 break;
8131 }
8132 }
8133 return rc;
8134}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308135EXPORT_SYMBOL(q6asm_memory_unmap_regions);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308136
8137int q6asm_set_lrgain(struct audio_client *ac, int left_gain, int right_gain)
8138{
8139 struct asm_volume_ctrl_multichannel_gain multi_ch_gain;
8140 int sz = 0;
8141 int rc = 0;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008142 int session_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308143
8144 if (ac == NULL) {
8145 pr_err("%s: APR handle NULL\n", __func__);
8146 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008147 goto done;
8148 }
8149
8150 session_id = q6asm_get_session_id_from_audio_client(ac);
8151 if (!session_id) {
8152 rc = -EINVAL;
8153 goto done;
8154 }
8155
8156 mutex_lock(&session[session_id].mutex_lock_per_session);
8157 if (!q6asm_is_valid_audio_client(ac)) {
8158 rc = -EINVAL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308159 goto fail_cmd;
8160 }
Xiaojun Sanga4648082018-04-27 14:57:33 +08008161
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308162 if (ac->apr == NULL) {
8163 pr_err("%s: AC APR handle NULL\n", __func__);
8164 rc = -EINVAL;
8165 goto fail_cmd;
8166 }
8167
8168 memset(&multi_ch_gain, 0, sizeof(multi_ch_gain));
8169 sz = sizeof(struct asm_volume_ctrl_multichannel_gain);
8170 q6asm_add_hdr_async(ac, &multi_ch_gain.hdr, sz, TRUE);
8171 atomic_set(&ac->cmd_state_pp, -1);
8172 multi_ch_gain.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
8173 multi_ch_gain.param.data_payload_addr_lsw = 0;
8174 multi_ch_gain.param.data_payload_addr_msw = 0;
8175 multi_ch_gain.param.mem_map_handle = 0;
8176 multi_ch_gain.param.data_payload_size = sizeof(multi_ch_gain) -
8177 sizeof(multi_ch_gain.hdr) - sizeof(multi_ch_gain.param);
8178 multi_ch_gain.data.module_id = ASM_MODULE_ID_VOL_CTRL;
8179 multi_ch_gain.data.param_id = ASM_PARAM_ID_MULTICHANNEL_GAIN;
8180 multi_ch_gain.data.param_size = multi_ch_gain.param.data_payload_size -
8181 sizeof(multi_ch_gain.data);
8182 multi_ch_gain.data.reserved = 0;
8183 multi_ch_gain.gain_data[0].channeltype = PCM_CHANNEL_FL;
8184 multi_ch_gain.gain_data[0].gain = left_gain << 15;
8185 multi_ch_gain.gain_data[1].channeltype = PCM_CHANNEL_FR;
8186 multi_ch_gain.gain_data[1].gain = right_gain << 15;
8187 multi_ch_gain.num_channels = 2;
8188 rc = apr_send_pkt(ac->apr, (uint32_t *) &multi_ch_gain);
8189 if (rc < 0) {
8190 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
8191 __func__, multi_ch_gain.data.param_id, rc);
8192 rc = -EINVAL;
8193 goto fail_cmd;
8194 }
8195
8196 rc = wait_event_timeout(ac->cmd_wait,
8197 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
8198 if (!rc) {
8199 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
8200 multi_ch_gain.data.param_id);
8201 rc = -ETIMEDOUT;
8202 goto fail_cmd;
8203 }
8204 if (atomic_read(&ac->cmd_state_pp) > 0) {
8205 pr_err("%s: DSP returned error[%s] , set-params paramid[0x%x]\n",
8206 __func__, adsp_err_get_err_str(
8207 atomic_read(&ac->cmd_state_pp)),
8208 multi_ch_gain.data.param_id);
8209 rc = adsp_err_get_lnx_err_code(
8210 atomic_read(&ac->cmd_state_pp));
8211 goto fail_cmd;
8212 }
8213 rc = 0;
8214fail_cmd:
Xiaojun Sanga4648082018-04-27 14:57:33 +08008215 mutex_unlock(&session[session_id].mutex_lock_per_session);
8216done:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308217 return rc;
8218}
8219
8220/*
8221 * q6asm_set_multich_gain: set multiple channel gains on an ASM session
8222 * @ac: audio client handle
8223 * @channels: number of channels caller intends to set gains
8224 * @gains: list of gains of audio channels
8225 * @ch_map: list of channel mapping. Only valid if use_default is false
8226 * @use_default: flag to indicate whether to use default mapping
8227 */
8228int q6asm_set_multich_gain(struct audio_client *ac, uint32_t channels,
8229 uint32_t *gains, uint8_t *ch_map, bool use_default)
8230{
8231 struct asm_volume_ctrl_multichannel_gain multich_gain;
8232 int sz = 0;
8233 int rc = 0;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008234 int i, session_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308235 u8 default_chmap[VOLUME_CONTROL_MAX_CHANNELS];
8236
8237 if (ac == NULL) {
8238 pr_err("%s: ac is NULL\n", __func__);
8239 rc = -EINVAL;
8240 goto done;
8241 }
Xiaojun Sanga4648082018-04-27 14:57:33 +08008242
8243 session_id = q6asm_get_session_id_from_audio_client(ac);
8244 if (!session_id) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308245 rc = -EINVAL;
8246 goto done;
8247 }
8248
8249 memset(&multich_gain, 0, sizeof(multich_gain));
8250 sz = sizeof(struct asm_volume_ctrl_multichannel_gain);
Xiaojun Sanga4648082018-04-27 14:57:33 +08008251 mutex_lock(&session[session_id].mutex_lock_per_session);
8252 if (!q6asm_is_valid_audio_client(ac)) {
8253 rc = -EINVAL;
8254 goto fail_cmd;
8255 }
8256
8257 if (ac->apr == NULL) {
8258 dev_err(ac->dev, "%s: AC APR handle NULL\n", __func__);
8259 rc = -EINVAL;
8260 goto fail_cmd;
8261 }
8262
8263 if (gains == NULL) {
8264 dev_err(ac->dev, "%s: gain_list is NULL\n", __func__);
8265 rc = -EINVAL;
8266 goto fail_cmd;
8267 }
8268 if (channels > VOLUME_CONTROL_MAX_CHANNELS) {
8269 dev_err(ac->dev, "%s: Invalid channel count %d\n",
8270 __func__, channels);
8271 rc = -EINVAL;
8272 goto fail_cmd;
8273 }
8274 if (!use_default && ch_map == NULL) {
8275 dev_err(ac->dev, "%s: NULL channel map\n", __func__);
8276 rc = -EINVAL;
8277 goto fail_cmd;
8278 }
8279
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308280 q6asm_add_hdr_async(ac, &multich_gain.hdr, sz, TRUE);
8281 atomic_set(&ac->cmd_state_pp, -1);
8282 multich_gain.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
8283 multich_gain.param.data_payload_addr_lsw = 0;
8284 multich_gain.param.data_payload_addr_msw = 0;
8285 multich_gain.param.mem_map_handle = 0;
8286 multich_gain.param.data_payload_size = sizeof(multich_gain) -
8287 sizeof(multich_gain.hdr) - sizeof(multich_gain.param);
8288 multich_gain.data.module_id = ASM_MODULE_ID_VOL_CTRL;
8289 multich_gain.data.param_id = ASM_PARAM_ID_MULTICHANNEL_GAIN;
8290 multich_gain.data.param_size = multich_gain.param.data_payload_size -
8291 sizeof(multich_gain.data);
8292 multich_gain.data.reserved = 0;
8293
8294 if (use_default) {
8295 rc = q6asm_map_channels(default_chmap, channels, false);
8296 if (rc < 0)
Xiaojun Sanga4648082018-04-27 14:57:33 +08008297 goto fail_cmd;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308298 for (i = 0; i < channels; i++) {
8299 multich_gain.gain_data[i].channeltype =
8300 default_chmap[i];
8301 multich_gain.gain_data[i].gain = gains[i] << 15;
8302 }
8303 } else {
8304 for (i = 0; i < channels; i++) {
8305 multich_gain.gain_data[i].channeltype = ch_map[i];
8306 multich_gain.gain_data[i].gain = gains[i] << 15;
8307 }
8308 }
8309 multich_gain.num_channels = channels;
8310
8311 rc = apr_send_pkt(ac->apr, (uint32_t *) &multich_gain);
8312 if (rc < 0) {
8313 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
8314 __func__, multich_gain.data.param_id, rc);
Xiaojun Sanga4648082018-04-27 14:57:33 +08008315 goto fail_cmd;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308316 }
8317
8318 rc = wait_event_timeout(ac->cmd_wait,
8319 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
8320 if (!rc) {
8321 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
8322 multich_gain.data.param_id);
8323 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008324 goto fail_cmd;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308325 }
8326 if (atomic_read(&ac->cmd_state_pp) > 0) {
8327 pr_err("%s: DSP returned error[%d] , set-params paramid[0x%x]\n",
8328 __func__, atomic_read(&ac->cmd_state_pp),
8329 multich_gain.data.param_id);
8330 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008331 goto fail_cmd;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308332 }
8333 rc = 0;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008334fail_cmd:
8335 mutex_unlock(&session[session_id].mutex_lock_per_session);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308336done:
8337 return rc;
8338}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308339EXPORT_SYMBOL(q6asm_set_multich_gain);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308340
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308341/**
8342 * q6asm_set_mute -
8343 * command to set mute for ASM
8344 *
8345 * @ac: Audio client handle
8346 * @muteflag: mute value
8347 *
8348 * Returns 0 on success or error on failure
8349 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308350int q6asm_set_mute(struct audio_client *ac, int muteflag)
8351{
8352 struct asm_volume_ctrl_mute_config mute;
8353 int sz = 0;
8354 int rc = 0;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008355 int session_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308356
8357 if (ac == NULL) {
8358 pr_err("%s: APR handle NULL\n", __func__);
8359 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008360 goto done;
8361 }
8362
8363 session_id = q6asm_get_session_id_from_audio_client(ac);
8364 if (!session_id) {
8365 rc = -EINVAL;
8366 goto done;
8367 }
8368
8369 mutex_lock(&session[session_id].mutex_lock_per_session);
8370 if (!q6asm_is_valid_audio_client(ac)) {
8371 rc = -EINVAL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308372 goto fail_cmd;
8373 }
Xiaojun Sanga4648082018-04-27 14:57:33 +08008374
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308375 if (ac->apr == NULL) {
8376 pr_err("%s: AC APR handle NULL\n", __func__);
8377 rc = -EINVAL;
8378 goto fail_cmd;
8379 }
8380
8381 sz = sizeof(struct asm_volume_ctrl_mute_config);
8382 q6asm_add_hdr_async(ac, &mute.hdr, sz, TRUE);
8383 atomic_set(&ac->cmd_state_pp, -1);
8384 mute.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
8385 mute.param.data_payload_addr_lsw = 0;
8386 mute.param.data_payload_addr_msw = 0;
8387 mute.param.mem_map_handle = 0;
8388 mute.param.data_payload_size = sizeof(mute) -
8389 sizeof(mute.hdr) - sizeof(mute.param);
8390 mute.data.module_id = ASM_MODULE_ID_VOL_CTRL;
8391 mute.data.param_id = ASM_PARAM_ID_VOL_CTRL_MUTE_CONFIG;
8392 mute.data.param_size = mute.param.data_payload_size - sizeof(mute.data);
8393 mute.data.reserved = 0;
8394 mute.mute_flag = muteflag;
8395
8396 rc = apr_send_pkt(ac->apr, (uint32_t *) &mute);
8397 if (rc < 0) {
8398 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
8399 __func__, mute.data.param_id, rc);
8400 rc = -EINVAL;
8401 goto fail_cmd;
8402 }
8403
8404 rc = wait_event_timeout(ac->cmd_wait,
8405 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
8406 if (!rc) {
8407 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
8408 mute.data.param_id);
8409 rc = -ETIMEDOUT;
8410 goto fail_cmd;
8411 }
8412 if (atomic_read(&ac->cmd_state_pp) > 0) {
8413 pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
8414 __func__, adsp_err_get_err_str(
8415 atomic_read(&ac->cmd_state_pp)),
8416 mute.data.param_id);
8417 rc = adsp_err_get_lnx_err_code(
8418 atomic_read(&ac->cmd_state_pp));
8419 goto fail_cmd;
8420 }
8421 rc = 0;
8422fail_cmd:
Xiaojun Sanga4648082018-04-27 14:57:33 +08008423 mutex_unlock(&session[session_id].mutex_lock_per_session);
8424done:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308425 return rc;
8426}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308427EXPORT_SYMBOL(q6asm_set_mute);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308428
8429static int __q6asm_set_volume(struct audio_client *ac, int volume, int instance)
8430{
8431 struct asm_volume_ctrl_master_gain vol;
8432 int sz = 0;
8433 int rc = 0;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008434 int module_id, session_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308435
8436 if (ac == NULL) {
8437 pr_err("%s: APR handle NULL\n", __func__);
8438 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008439 goto done;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308440 }
Xiaojun Sanga4648082018-04-27 14:57:33 +08008441
8442 session_id = q6asm_get_session_id_from_audio_client(ac);
8443 if (!session_id) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308444 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008445 goto done;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308446 }
8447
8448 switch (instance) {
8449 case SOFT_VOLUME_INSTANCE_2:
8450 module_id = ASM_MODULE_ID_VOL_CTRL2;
8451 break;
8452 case SOFT_VOLUME_INSTANCE_1:
8453 default:
8454 module_id = ASM_MODULE_ID_VOL_CTRL;
8455 break;
8456 }
8457
8458 sz = sizeof(struct asm_volume_ctrl_master_gain);
Xiaojun Sanga4648082018-04-27 14:57:33 +08008459 mutex_lock(&session[session_id].mutex_lock_per_session);
8460 if (!q6asm_is_valid_audio_client(ac)) {
8461 rc = -EINVAL;
8462 goto fail_cmd;
8463 }
8464
8465 if (ac->apr == NULL) {
8466 pr_err("%s: AC APR handle NULL\n", __func__);
8467 rc = -EINVAL;
8468 goto fail_cmd;
8469 }
8470
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308471 q6asm_add_hdr_async(ac, &vol.hdr, sz, TRUE);
8472 atomic_set(&ac->cmd_state_pp, -1);
8473 vol.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
8474 vol.param.data_payload_addr_lsw = 0;
8475 vol.param.data_payload_addr_msw = 0;
8476 vol.param.mem_map_handle = 0;
8477 vol.param.data_payload_size = sizeof(vol) -
8478 sizeof(vol.hdr) - sizeof(vol.param);
8479 vol.data.module_id = module_id;
8480 vol.data.param_id = ASM_PARAM_ID_VOL_CTRL_MASTER_GAIN;
8481 vol.data.param_size = vol.param.data_payload_size - sizeof(vol.data);
8482 vol.data.reserved = 0;
8483 vol.master_gain = volume;
8484
8485 rc = apr_send_pkt(ac->apr, (uint32_t *) &vol);
8486 if (rc < 0) {
8487 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
8488 __func__, vol.data.param_id, rc);
8489 rc = -EINVAL;
8490 goto fail_cmd;
8491 }
8492
8493 rc = wait_event_timeout(ac->cmd_wait,
8494 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
8495 if (!rc) {
8496 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
8497 vol.data.param_id);
8498 rc = -ETIMEDOUT;
8499 goto fail_cmd;
8500 }
8501 if (atomic_read(&ac->cmd_state_pp) > 0) {
8502 pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
8503 __func__, adsp_err_get_err_str(
8504 atomic_read(&ac->cmd_state_pp)),
8505 vol.data.param_id);
8506 rc = adsp_err_get_lnx_err_code(
8507 atomic_read(&ac->cmd_state_pp));
8508 goto fail_cmd;
8509 }
8510
8511 rc = 0;
8512fail_cmd:
Xiaojun Sanga4648082018-04-27 14:57:33 +08008513 mutex_unlock(&session[session_id].mutex_lock_per_session);
8514done:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308515 return rc;
8516}
8517
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308518/**
8519 * q6asm_set_volume -
8520 * command to set volume for ASM
8521 *
8522 * @ac: Audio client handle
8523 * @volume: volume level
8524 *
8525 * Returns 0 on success or error on failure
8526 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308527int q6asm_set_volume(struct audio_client *ac, int volume)
8528{
8529 return __q6asm_set_volume(ac, volume, SOFT_VOLUME_INSTANCE_1);
8530}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308531EXPORT_SYMBOL(q6asm_set_volume);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308532
8533int q6asm_set_volume_v2(struct audio_client *ac, int volume, int instance)
8534{
8535 return __q6asm_set_volume(ac, volume, instance);
8536}
8537
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308538/**
8539 * q6asm_set_aptx_dec_bt_addr -
8540 * command to aptx decoder BT addr for ASM
8541 *
8542 * @ac: Audio client handle
8543 * @cfg: APTX decoder bt addr config
8544 *
8545 * Returns 0 on success or error on failure
8546 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308547int q6asm_set_aptx_dec_bt_addr(struct audio_client *ac,
8548 struct aptx_dec_bt_addr_cfg *cfg)
8549{
8550 struct aptx_dec_bt_dev_addr paylod;
8551 int sz = 0;
8552 int rc = 0;
8553
8554 pr_debug("%s: BT addr nap %d, uap %d, lap %d\n", __func__, cfg->nap,
8555 cfg->uap, cfg->lap);
8556
8557 if (ac == NULL) {
8558 pr_err("%s: AC handle NULL\n", __func__);
8559 rc = -EINVAL;
8560 goto fail_cmd;
8561 }
8562 if (ac->apr == NULL) {
8563 pr_err("%s: AC APR handle NULL\n", __func__);
8564 rc = -EINVAL;
8565 goto fail_cmd;
8566 }
8567
8568 sz = sizeof(struct aptx_dec_bt_dev_addr);
8569 q6asm_add_hdr_async(ac, &paylod.hdr, sz, TRUE);
8570 atomic_set(&ac->cmd_state, -1);
8571 paylod.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
8572 paylod.encdec.param_id = APTX_DECODER_BT_ADDRESS;
8573 paylod.encdec.param_size = sz - sizeof(paylod.hdr)
8574 - sizeof(paylod.encdec);
8575 paylod.bt_addr_cfg.lap = cfg->lap;
8576 paylod.bt_addr_cfg.uap = cfg->uap;
8577 paylod.bt_addr_cfg.nap = cfg->nap;
8578
8579 rc = apr_send_pkt(ac->apr, (uint32_t *) &paylod);
8580 if (rc < 0) {
8581 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
8582 __func__, paylod.encdec.param_id, rc);
8583 rc = -EINVAL;
8584 goto fail_cmd;
8585 }
8586
8587 rc = wait_event_timeout(ac->cmd_wait,
8588 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
8589 if (!rc) {
8590 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
8591 paylod.encdec.param_id);
8592 rc = -ETIMEDOUT;
8593 goto fail_cmd;
8594 }
8595 if (atomic_read(&ac->cmd_state) > 0) {
8596 pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
8597 __func__, adsp_err_get_err_str(
8598 atomic_read(&ac->cmd_state)),
8599 paylod.encdec.param_id);
8600 rc = adsp_err_get_lnx_err_code(
8601 atomic_read(&ac->cmd_state));
8602 goto fail_cmd;
8603 }
8604 pr_debug("%s: set BT addr is success\n", __func__);
8605 rc = 0;
8606fail_cmd:
8607 return rc;
8608}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308609EXPORT_SYMBOL(q6asm_set_aptx_dec_bt_addr);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308610
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308611/**
8612 * q6asm_send_ion_fd -
8613 * command to send ION memory map for ASM
8614 *
8615 * @ac: Audio client handle
8616 * @fd: ION file desc
8617 *
8618 * Returns 0 on success or error on failure
8619 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308620int q6asm_send_ion_fd(struct audio_client *ac, int fd)
8621{
8622 struct ion_client *client;
8623 struct ion_handle *handle;
8624 ion_phys_addr_t paddr;
8625 size_t pa_len = 0;
8626 void *vaddr;
8627 int ret;
8628 int sz = 0;
8629 struct avs_rtic_shared_mem_addr shm;
8630
8631 if (ac == NULL) {
8632 pr_err("%s: APR handle NULL\n", __func__);
8633 ret = -EINVAL;
8634 goto fail_cmd;
8635 }
8636 if (ac->apr == NULL) {
8637 pr_err("%s: AC APR handle NULL\n", __func__);
8638 ret = -EINVAL;
8639 goto fail_cmd;
8640 }
8641
8642 ret = msm_audio_ion_import("audio_mem_client",
8643 &client,
8644 &handle,
8645 fd,
8646 NULL,
8647 0,
8648 &paddr,
8649 &pa_len,
8650 &vaddr);
8651 if (ret) {
8652 pr_err("%s: audio ION import failed, rc = %d\n",
8653 __func__, ret);
8654 ret = -ENOMEM;
8655 goto fail_cmd;
8656 }
8657 /* get payload length */
8658 sz = sizeof(struct avs_rtic_shared_mem_addr);
8659 q6asm_add_hdr_async(ac, &shm.hdr, sz, TRUE);
8660 atomic_set(&ac->cmd_state, -1);
8661 shm.shm_buf_addr_lsw = lower_32_bits(paddr);
8662 shm.shm_buf_addr_msw = msm_audio_populate_upper_32_bits(paddr);
8663 shm.buf_size = pa_len;
8664 shm.shm_buf_num_regions = 1;
8665 shm.shm_buf_mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
8666 shm.shm_buf_flag = 0x00;
8667 shm.encdec.param_id = AVS_PARAM_ID_RTIC_SHARED_MEMORY_ADDR;
8668 shm.encdec.param_size = sizeof(struct avs_rtic_shared_mem_addr) -
8669 sizeof(struct apr_hdr) -
8670 sizeof(struct asm_stream_cmd_set_encdec_param_v2);
8671 shm.encdec.service_id = OUT;
8672 shm.encdec.reserved = 0;
8673 shm.map_region.shm_addr_lsw = shm.shm_buf_addr_lsw;
8674 shm.map_region.shm_addr_msw = shm.shm_buf_addr_msw;
8675 shm.map_region.mem_size_bytes = pa_len;
8676 shm.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM_V2;
8677 ret = apr_send_pkt(ac->apr, (uint32_t *) &shm);
8678 if (ret < 0) {
8679 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
8680 __func__, shm.encdec.param_id, ret);
8681 ret = -EINVAL;
8682 goto fail_cmd;
8683 }
8684
8685 ret = wait_event_timeout(ac->cmd_wait,
8686 (atomic_read(&ac->cmd_state) >= 0), 1*HZ);
8687 if (!ret) {
8688 pr_err("%s: timeout, shm.encdec paramid[0x%x]\n", __func__,
8689 shm.encdec.param_id);
8690 ret = -ETIMEDOUT;
8691 goto fail_cmd;
8692 }
8693 if (atomic_read(&ac->cmd_state) > 0) {
8694 pr_err("%s: DSP returned error[%s] shm.encdec paramid[0x%x]\n",
8695 __func__,
8696 adsp_err_get_err_str(atomic_read(&ac->cmd_state)),
8697 shm.encdec.param_id);
8698 ret = adsp_err_get_lnx_err_code(atomic_read(&ac->cmd_state));
8699 goto fail_cmd;
8700 }
8701 ret = 0;
8702fail_cmd:
8703 return ret;
8704}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308705EXPORT_SYMBOL(q6asm_send_ion_fd);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308706
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308707/**
8708 * q6asm_send_rtic_event_ack -
8709 * command to send RTIC event ack
8710 *
8711 * @ac: Audio client handle
8712 * @param: params for event ack
8713 * @params_length: length of params
8714 *
8715 * Returns 0 on success or error on failure
8716 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308717int q6asm_send_rtic_event_ack(struct audio_client *ac,
8718 void *param, uint32_t params_length)
8719{
8720 char *asm_params = NULL;
8721 int sz, rc;
8722 struct avs_param_rtic_event_ack ack;
8723
8724 if (!param || !ac) {
8725 pr_err("%s: %s is NULL\n", __func__,
8726 (!param) ? "param" : "ac");
8727 rc = -EINVAL;
8728 goto done;
8729 }
8730
8731 sz = sizeof(struct avs_param_rtic_event_ack) + params_length;
8732 asm_params = kzalloc(sz, GFP_KERNEL);
8733 if (!asm_params) {
8734 rc = -ENOMEM;
8735 goto done;
8736 }
8737
8738 q6asm_add_hdr_async(ac, &ack.hdr,
8739 sizeof(struct avs_param_rtic_event_ack) +
8740 params_length, TRUE);
8741 atomic_set(&ac->cmd_state, -1);
8742 ack.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM_V2;
8743 ack.encdec.param_id = AVS_PARAM_ID_RTIC_EVENT_ACK;
8744 ack.encdec.param_size = params_length;
8745 ack.encdec.reserved = 0;
8746 ack.encdec.service_id = OUT;
8747 memcpy(asm_params, &ack, sizeof(struct avs_param_rtic_event_ack));
8748 memcpy(asm_params + sizeof(struct avs_param_rtic_event_ack),
8749 param, params_length);
8750 rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params);
8751 if (rc < 0) {
8752 pr_err("%s: apr pkt failed for rtic event ack\n", __func__);
8753 rc = -EINVAL;
8754 goto fail_send_param;
8755 }
8756
8757 rc = wait_event_timeout(ac->cmd_wait,
8758 (atomic_read(&ac->cmd_state) >= 0), 1 * HZ);
8759 if (!rc) {
8760 pr_err("%s: timeout for rtic event ack cmd\n", __func__);
8761 rc = -ETIMEDOUT;
8762 goto fail_send_param;
8763 }
8764
8765 if (atomic_read(&ac->cmd_state) > 0) {
8766 pr_err("%s: DSP returned error[%s] for rtic event ack cmd\n",
8767 __func__, adsp_err_get_err_str(
8768 atomic_read(&ac->cmd_state)));
8769 rc = adsp_err_get_lnx_err_code(
8770 atomic_read(&ac->cmd_state));
8771 goto fail_send_param;
8772 }
8773 rc = 0;
8774
8775fail_send_param:
8776 kfree(asm_params);
8777done:
8778 return rc;
8779}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308780EXPORT_SYMBOL(q6asm_send_rtic_event_ack);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308781
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308782/**
8783 * q6asm_set_softpause -
8784 * command to set pause for ASM
8785 *
8786 * @ac: Audio client handle
8787 * @pause_param: params for pause
8788 *
8789 * Returns 0 on success or error on failure
8790 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308791int q6asm_set_softpause(struct audio_client *ac,
8792 struct asm_softpause_params *pause_param)
8793{
8794 struct asm_soft_pause_params softpause;
8795 int sz = 0;
8796 int rc = 0;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008797 int session_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308798
8799 if (ac == NULL) {
8800 pr_err("%s: APR handle NULL\n", __func__);
8801 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008802 goto done;
8803 }
8804
8805 session_id = q6asm_get_session_id_from_audio_client(ac);
8806 if (!session_id) {
8807 rc = -EINVAL;
8808 goto done;
8809 }
8810
8811 mutex_lock(&session[session_id].mutex_lock_per_session);
8812 if (!q6asm_is_valid_audio_client(ac)) {
8813 rc = -EINVAL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308814 goto fail_cmd;
8815 }
Xiaojun Sanga4648082018-04-27 14:57:33 +08008816
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308817 if (ac->apr == NULL) {
8818 pr_err("%s: AC APR handle NULL\n", __func__);
8819 rc = -EINVAL;
8820 goto fail_cmd;
8821 }
8822
8823 sz = sizeof(struct asm_soft_pause_params);
8824 q6asm_add_hdr_async(ac, &softpause.hdr, sz, TRUE);
8825 atomic_set(&ac->cmd_state_pp, -1);
8826 softpause.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
8827
8828 softpause.param.data_payload_addr_lsw = 0;
8829 softpause.param.data_payload_addr_msw = 0;
8830 softpause.param.mem_map_handle = 0;
8831 softpause.param.data_payload_size = sizeof(softpause) -
8832 sizeof(softpause.hdr) - sizeof(softpause.param);
8833 softpause.data.module_id = ASM_MODULE_ID_VOL_CTRL;
8834 softpause.data.param_id = ASM_PARAM_ID_SOFT_PAUSE_PARAMETERS;
8835 softpause.data.param_size = softpause.param.data_payload_size -
8836 sizeof(softpause.data);
8837 softpause.data.reserved = 0;
8838 softpause.enable_flag = pause_param->enable;
8839 softpause.period = pause_param->period;
8840 softpause.step = pause_param->step;
8841 softpause.ramping_curve = pause_param->rampingcurve;
8842
8843 rc = apr_send_pkt(ac->apr, (uint32_t *) &softpause);
8844 if (rc < 0) {
8845 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
8846 __func__, softpause.data.param_id, rc);
8847 rc = -EINVAL;
8848 goto fail_cmd;
8849 }
8850
8851 rc = wait_event_timeout(ac->cmd_wait,
8852 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
8853 if (!rc) {
8854 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
8855 softpause.data.param_id);
8856 rc = -ETIMEDOUT;
8857 goto fail_cmd;
8858 }
8859 if (atomic_read(&ac->cmd_state_pp) > 0) {
8860 pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
8861 __func__, adsp_err_get_err_str(
8862 atomic_read(&ac->cmd_state_pp)),
8863 softpause.data.param_id);
8864 rc = adsp_err_get_lnx_err_code(
8865 atomic_read(&ac->cmd_state_pp));
8866 goto fail_cmd;
8867 }
8868 rc = 0;
8869fail_cmd:
Xiaojun Sanga4648082018-04-27 14:57:33 +08008870 mutex_unlock(&session[session_id].mutex_lock_per_session);
8871done:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308872 return rc;
8873}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308874EXPORT_SYMBOL(q6asm_set_softpause);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308875
8876static int __q6asm_set_softvolume(struct audio_client *ac,
8877 struct asm_softvolume_params *softvol_param,
8878 int instance)
8879{
8880 struct asm_soft_step_volume_params softvol;
8881 int sz = 0;
8882 int rc = 0;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008883 int module_id, session_id;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308884
8885 if (ac == NULL) {
8886 pr_err("%s: APR handle NULL\n", __func__);
8887 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008888 goto done;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308889 }
Xiaojun Sanga4648082018-04-27 14:57:33 +08008890
8891 session_id = q6asm_get_session_id_from_audio_client(ac);
8892 if (!session_id) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308893 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008894 goto done;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308895 }
8896
8897 switch (instance) {
8898 case SOFT_VOLUME_INSTANCE_2:
8899 module_id = ASM_MODULE_ID_VOL_CTRL2;
8900 break;
8901 case SOFT_VOLUME_INSTANCE_1:
8902 default:
8903 module_id = ASM_MODULE_ID_VOL_CTRL;
8904 break;
8905 }
8906
8907 sz = sizeof(struct asm_soft_step_volume_params);
Xiaojun Sanga4648082018-04-27 14:57:33 +08008908 mutex_lock(&session[session_id].mutex_lock_per_session);
8909 if (!q6asm_is_valid_audio_client(ac)) {
8910 rc = -EINVAL;
8911 goto fail_cmd;
8912 }
8913
8914 if (ac->apr == NULL) {
8915 pr_err("%s: AC APR handle NULL\n", __func__);
8916 rc = -EINVAL;
8917 goto fail_cmd;
8918 }
8919
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308920 q6asm_add_hdr_async(ac, &softvol.hdr, sz, TRUE);
8921 atomic_set(&ac->cmd_state_pp, -1);
8922 softvol.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
8923 softvol.param.data_payload_addr_lsw = 0;
8924 softvol.param.data_payload_addr_msw = 0;
8925 softvol.param.mem_map_handle = 0;
8926 softvol.param.data_payload_size = sizeof(softvol) -
8927 sizeof(softvol.hdr) - sizeof(softvol.param);
8928 softvol.data.module_id = module_id;
8929 softvol.data.param_id = ASM_PARAM_ID_SOFT_VOL_STEPPING_PARAMETERS;
8930 softvol.data.param_size = softvol.param.data_payload_size -
8931 sizeof(softvol.data);
8932 softvol.data.reserved = 0;
8933 softvol.period = softvol_param->period;
8934 softvol.step = softvol_param->step;
8935 softvol.ramping_curve = softvol_param->rampingcurve;
8936
8937 rc = apr_send_pkt(ac->apr, (uint32_t *) &softvol);
8938 if (rc < 0) {
8939 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
8940 __func__, softvol.data.param_id, rc);
8941 rc = -EINVAL;
8942 goto fail_cmd;
8943 }
8944
8945 rc = wait_event_timeout(ac->cmd_wait,
8946 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
8947 if (!rc) {
8948 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
8949 softvol.data.param_id);
8950 rc = -ETIMEDOUT;
8951 goto fail_cmd;
8952 }
8953 if (atomic_read(&ac->cmd_state_pp) > 0) {
8954 pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
8955 __func__, adsp_err_get_err_str(
8956 atomic_read(&ac->cmd_state_pp)),
8957 softvol.data.param_id);
8958 rc = adsp_err_get_lnx_err_code(
8959 atomic_read(&ac->cmd_state_pp));
8960 goto fail_cmd;
8961 }
8962 rc = 0;
8963fail_cmd:
Xiaojun Sanga4648082018-04-27 14:57:33 +08008964 mutex_unlock(&session[session_id].mutex_lock_per_session);
8965done:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308966 return rc;
8967}
8968
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308969/**
8970 * q6asm_set_softvolume -
8971 * command to set softvolume for ASM
8972 *
8973 * @ac: Audio client handle
8974 * @softvol_param: params for softvol
8975 *
8976 * Returns 0 on success or error on failure
8977 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308978int q6asm_set_softvolume(struct audio_client *ac,
8979 struct asm_softvolume_params *softvol_param)
8980{
8981 return __q6asm_set_softvolume(ac, softvol_param,
8982 SOFT_VOLUME_INSTANCE_1);
8983}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308984EXPORT_SYMBOL(q6asm_set_softvolume);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308985
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308986/**
8987 * q6asm_set_softvolume_v2 -
8988 * command to set softvolume V2 for ASM
8989 *
8990 * @ac: Audio client handle
8991 * @softvol_param: params for softvol
8992 * @instance: instance to apply softvol
8993 *
8994 * Returns 0 on success or error on failure
8995 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308996int q6asm_set_softvolume_v2(struct audio_client *ac,
8997 struct asm_softvolume_params *softvol_param,
8998 int instance)
8999{
9000 return __q6asm_set_softvolume(ac, softvol_param, instance);
9001}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309002EXPORT_SYMBOL(q6asm_set_softvolume_v2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309003
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309004/**
9005 * q6asm_equalizer -
9006 * command to set equalizer for ASM
9007 *
9008 * @ac: Audio client handle
9009 * @eq_p: Equalizer params
9010 *
9011 * Returns 0 on success or error on failure
9012 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309013int q6asm_equalizer(struct audio_client *ac, void *eq_p)
9014{
9015 struct asm_eq_params eq;
9016 struct msm_audio_eq_stream_config *eq_params = NULL;
9017 int i = 0;
9018 int sz = 0;
9019 int rc = 0;
Xiaojun Sanga4648082018-04-27 14:57:33 +08009020 int session_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309021
9022 if (ac == NULL) {
9023 pr_err("%s: APR handle NULL\n", __func__);
9024 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08009025 goto done;
9026 }
9027
9028 session_id = q6asm_get_session_id_from_audio_client(ac);
9029 if (!session_id) {
9030 rc = -EINVAL;
9031 goto done;
9032 }
9033
9034 mutex_lock(&session[session_id].mutex_lock_per_session);
9035 if (!q6asm_is_valid_audio_client(ac)) {
9036 rc = -EINVAL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309037 goto fail_cmd;
9038 }
Xiaojun Sanga4648082018-04-27 14:57:33 +08009039
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309040 if (ac->apr == NULL) {
9041 pr_err("%s: AC APR handle NULL\n", __func__);
9042 rc = -EINVAL;
9043 goto fail_cmd;
9044 }
9045
9046 if (eq_p == NULL) {
9047 pr_err("%s: [%d]: Invalid Eq param\n", __func__, ac->session);
9048 rc = -EINVAL;
9049 goto fail_cmd;
9050 }
9051 sz = sizeof(struct asm_eq_params);
9052 eq_params = (struct msm_audio_eq_stream_config *) eq_p;
9053 q6asm_add_hdr(ac, &eq.hdr, sz, TRUE);
9054 atomic_set(&ac->cmd_state_pp, -1);
9055
9056 eq.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
9057 eq.param.data_payload_addr_lsw = 0;
9058 eq.param.data_payload_addr_msw = 0;
9059 eq.param.mem_map_handle = 0;
9060 eq.param.data_payload_size = sizeof(eq) -
9061 sizeof(eq.hdr) - sizeof(eq.param);
9062 eq.data.module_id = ASM_MODULE_ID_EQUALIZER;
9063 eq.data.param_id = ASM_PARAM_ID_EQUALIZER_PARAMETERS;
9064 eq.data.param_size = eq.param.data_payload_size - sizeof(eq.data);
9065 eq.enable_flag = eq_params->enable;
9066 eq.num_bands = eq_params->num_bands;
9067
9068 pr_debug("%s: enable:%d numbands:%d\n", __func__, eq_params->enable,
9069 eq_params->num_bands);
9070 for (i = 0; i < eq_params->num_bands; i++) {
9071 eq.eq_bands[i].band_idx =
9072 eq_params->eq_bands[i].band_idx;
9073 eq.eq_bands[i].filterype =
9074 eq_params->eq_bands[i].filter_type;
9075 eq.eq_bands[i].center_freq_hz =
9076 eq_params->eq_bands[i].center_freq_hz;
9077 eq.eq_bands[i].filter_gain =
9078 eq_params->eq_bands[i].filter_gain;
9079 eq.eq_bands[i].q_factor =
9080 eq_params->eq_bands[i].q_factor;
9081 pr_debug("%s: filter_type:%u bandnum:%d\n", __func__,
9082 eq_params->eq_bands[i].filter_type, i);
9083 pr_debug("%s: center_freq_hz:%u bandnum:%d\n", __func__,
9084 eq_params->eq_bands[i].center_freq_hz, i);
9085 pr_debug("%s: filter_gain:%d bandnum:%d\n", __func__,
9086 eq_params->eq_bands[i].filter_gain, i);
9087 pr_debug("%s: q_factor:%d bandnum:%d\n", __func__,
9088 eq_params->eq_bands[i].q_factor, i);
9089 }
9090 rc = apr_send_pkt(ac->apr, (uint32_t *)&eq);
9091 if (rc < 0) {
9092 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
9093 __func__, eq.data.param_id, rc);
9094 rc = -EINVAL;
9095 goto fail_cmd;
9096 }
9097
9098 rc = wait_event_timeout(ac->cmd_wait,
9099 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
9100 if (!rc) {
9101 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
9102 eq.data.param_id);
9103 rc = -ETIMEDOUT;
9104 goto fail_cmd;
9105 }
9106 if (atomic_read(&ac->cmd_state_pp) > 0) {
9107 pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
9108 __func__, adsp_err_get_err_str(
9109 atomic_read(&ac->cmd_state_pp)),
9110 eq.data.param_id);
9111 rc = adsp_err_get_lnx_err_code(
9112 atomic_read(&ac->cmd_state_pp));
9113 goto fail_cmd;
9114 }
9115 rc = 0;
9116fail_cmd:
Xiaojun Sanga4648082018-04-27 14:57:33 +08009117 mutex_unlock(&session[session_id].mutex_lock_per_session);
9118done:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309119 return rc;
9120}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309121EXPORT_SYMBOL(q6asm_equalizer);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309122
9123static int __q6asm_read(struct audio_client *ac, bool is_custom_len_reqd,
9124 int len)
9125{
9126 struct asm_data_cmd_read_v2 read;
9127 struct asm_buffer_node *buf_node = NULL;
9128 struct list_head *ptr, *next;
9129 struct audio_buffer *ab;
9130 int dsp_buf;
9131 struct audio_port_data *port;
9132 int rc;
9133
9134 if (ac == NULL) {
9135 pr_err("%s: APR handle NULL\n", __func__);
9136 return -EINVAL;
9137 }
9138 if (ac->apr == NULL) {
9139 pr_err("%s: AC APR handle NULL\n", __func__);
9140 return -EINVAL;
9141 }
9142
9143 if (ac->io_mode & SYNC_IO_MODE) {
9144 port = &ac->port[OUT];
9145
9146 q6asm_add_hdr(ac, &read.hdr, sizeof(read), FALSE);
9147
9148 mutex_lock(&port->lock);
9149
9150 dsp_buf = port->dsp_buf;
9151 if (port->buf == NULL) {
9152 pr_err("%s: buf is NULL\n", __func__);
9153 mutex_unlock(&port->lock);
9154 return -EINVAL;
9155 }
9156 ab = &port->buf[dsp_buf];
9157
9158 dev_vdbg(ac->dev, "%s: session[%d]dsp-buf[%d][%pK]cpu_buf[%d][%pK]\n",
9159 __func__,
9160 ac->session,
9161 dsp_buf,
9162 port->buf[dsp_buf].data,
9163 port->cpu_buf,
9164 &port->buf[port->cpu_buf].phys);
9165
9166 read.hdr.opcode = ASM_DATA_CMD_READ_V2;
9167 read.buf_addr_lsw = lower_32_bits(ab->phys);
9168 read.buf_addr_msw = msm_audio_populate_upper_32_bits(ab->phys);
9169
9170 list_for_each_safe(ptr, next, &ac->port[OUT].mem_map_handle) {
9171 buf_node = list_entry(ptr, struct asm_buffer_node,
9172 list);
Vignesh Kulothunganc894ac42018-01-04 13:49:12 -08009173 if (buf_node->buf_phys_addr == ab->phys) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309174 read.mem_map_handle = buf_node->mmap_hdl;
Vignesh Kulothunganc894ac42018-01-04 13:49:12 -08009175 break;
9176 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309177 }
9178 dev_vdbg(ac->dev, "memory_map handle in q6asm_read: [%0x]:",
9179 read.mem_map_handle);
9180 read.buf_size = is_custom_len_reqd ? len : ab->size;
9181 read.seq_id = port->dsp_buf;
9182 q6asm_update_token(&read.hdr.token,
9183 0, /* Session ID is NA */
9184 0, /* Stream ID is NA */
9185 port->dsp_buf,
9186 0, /* Direction flag is NA */
9187 WAIT_CMD);
9188 port->dsp_buf = q6asm_get_next_buf(ac, port->dsp_buf,
9189 port->max_buf_cnt);
9190 mutex_unlock(&port->lock);
9191 dev_vdbg(ac->dev, "%s: buf add[%pK] token[0x%x] uid[%d]\n",
9192 __func__, &ab->phys, read.hdr.token,
9193 read.seq_id);
9194 rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
9195 if (rc < 0) {
9196 pr_err("%s: read op[0x%x]rc[%d]\n",
9197 __func__, read.hdr.opcode, rc);
9198 goto fail_cmd;
9199 }
9200 return 0;
9201 }
9202fail_cmd:
9203 return -EINVAL;
9204}
9205
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309206/**
9207 * q6asm_read -
9208 * command to read buffer data from DSP
9209 *
9210 * @ac: Audio client handle
9211 *
9212 * Returns 0 on success or error on failure
9213 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309214int q6asm_read(struct audio_client *ac)
9215{
9216 return __q6asm_read(ac, false/*is_custom_len_reqd*/, 0);
9217}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309218EXPORT_SYMBOL(q6asm_read);
9219
9220
9221/**
9222 * q6asm_read_v2 -
9223 * command to read buffer data from DSP
9224 *
9225 * @ac: Audio client handle
9226 * @len: buffer size to read
9227 *
9228 * Returns 0 on success or error on failure
9229 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309230int q6asm_read_v2(struct audio_client *ac, uint32_t len)
9231{
9232 return __q6asm_read(ac, true /*is_custom_len_reqd*/, len);
9233}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309234EXPORT_SYMBOL(q6asm_read_v2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309235
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309236/**
9237 * q6asm_read_nolock -
9238 * command to read buffer data from DSP
9239 * with no wait for ack.
9240 *
9241 * @ac: Audio client handle
9242 *
9243 * Returns 0 on success or error on failure
9244 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309245int q6asm_read_nolock(struct audio_client *ac)
9246{
9247 struct asm_data_cmd_read_v2 read;
9248 struct asm_buffer_node *buf_node = NULL;
9249 struct list_head *ptr, *next;
9250 struct audio_buffer *ab;
9251 int dsp_buf;
9252 struct audio_port_data *port;
9253 int rc;
9254
9255 if (ac == NULL) {
9256 pr_err("%s: APR handle NULL\n", __func__);
9257 return -EINVAL;
9258 }
9259 if (ac->apr == NULL) {
9260 pr_err("%s: AC APR handle NULL\n", __func__);
9261 return -EINVAL;
9262 }
9263
9264 if (ac->io_mode & SYNC_IO_MODE) {
9265 port = &ac->port[OUT];
9266
9267 q6asm_add_hdr_async(ac, &read.hdr, sizeof(read), FALSE);
9268
9269
9270 dsp_buf = port->dsp_buf;
9271 ab = &port->buf[dsp_buf];
9272
9273 dev_vdbg(ac->dev, "%s: session[%d]dsp-buf[%d][%pK]cpu_buf[%d][%pK]\n",
9274 __func__,
9275 ac->session,
9276 dsp_buf,
9277 port->buf[dsp_buf].data,
9278 port->cpu_buf,
9279 &port->buf[port->cpu_buf].phys);
9280
9281 read.hdr.opcode = ASM_DATA_CMD_READ_V2;
9282 read.buf_addr_lsw = lower_32_bits(ab->phys);
9283 read.buf_addr_msw = msm_audio_populate_upper_32_bits(ab->phys);
9284 read.buf_size = ab->size;
9285 read.seq_id = port->dsp_buf;
9286 q6asm_update_token(&read.hdr.token,
9287 0, /* Session ID is NA */
9288 0, /* Stream ID is NA */
9289 port->dsp_buf,
9290 0, /* Direction flag is NA */
9291 WAIT_CMD);
9292
9293 list_for_each_safe(ptr, next, &ac->port[OUT].mem_map_handle) {
9294 buf_node = list_entry(ptr, struct asm_buffer_node,
9295 list);
9296 if (buf_node->buf_phys_addr == ab->phys) {
9297 read.mem_map_handle = buf_node->mmap_hdl;
9298 break;
9299 }
9300 }
9301
9302 port->dsp_buf = q6asm_get_next_buf(ac, port->dsp_buf,
9303 port->max_buf_cnt);
9304 dev_vdbg(ac->dev, "%s: buf add[%pK] token[0x%x] uid[%d]\n",
9305 __func__, &ab->phys, read.hdr.token,
9306 read.seq_id);
9307 rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
9308 if (rc < 0) {
9309 pr_err("%s: read op[0x%x]rc[%d]\n",
9310 __func__, read.hdr.opcode, rc);
9311 goto fail_cmd;
9312 }
9313 return 0;
9314 }
9315fail_cmd:
9316 return -EINVAL;
9317}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309318EXPORT_SYMBOL(q6asm_read_nolock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309319
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309320/**
9321 * q6asm_async_write -
9322 * command to write DSP buffer
9323 *
9324 * @ac: Audio client handle
9325 * @param: params for async write
9326 *
9327 * Returns 0 on success or error on failure
9328 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309329int q6asm_async_write(struct audio_client *ac,
9330 struct audio_aio_write_param *param)
9331{
9332 int rc = 0;
9333 struct asm_data_cmd_write_v2 write;
9334 struct asm_buffer_node *buf_node = NULL;
9335 struct list_head *ptr, *next;
9336 struct audio_buffer *ab;
9337 struct audio_port_data *port;
9338 phys_addr_t lbuf_phys_addr;
9339 u32 liomode;
9340 u32 io_compressed;
9341 u32 io_compressed_stream;
9342
9343 if (ac == NULL) {
9344 pr_err("%s: APR handle NULL\n", __func__);
9345 return -EINVAL;
9346 }
9347 if (ac->apr == NULL) {
9348 pr_err("%s: AC APR handle NULL\n", __func__);
9349 return -EINVAL;
9350 }
9351
9352 q6asm_stream_add_hdr_async(
9353 ac, &write.hdr, sizeof(write), TRUE, ac->stream_id);
9354 port = &ac->port[IN];
9355 ab = &port->buf[port->dsp_buf];
9356
9357 /* Pass session id as token for AIO scheme */
9358 write.hdr.token = param->uid;
9359 write.hdr.opcode = ASM_DATA_CMD_WRITE_V2;
9360 write.buf_addr_lsw = lower_32_bits(param->paddr);
9361 write.buf_addr_msw = msm_audio_populate_upper_32_bits(param->paddr);
9362 write.buf_size = param->len;
9363 write.timestamp_msw = param->msw_ts;
9364 write.timestamp_lsw = param->lsw_ts;
9365 liomode = (ASYNC_IO_MODE | NT_MODE);
9366 io_compressed = (ASYNC_IO_MODE | COMPRESSED_IO);
9367 io_compressed_stream = (ASYNC_IO_MODE | COMPRESSED_STREAM_IO);
9368
9369 if (ac->io_mode == liomode)
9370 lbuf_phys_addr = (param->paddr - 32);
9371 else if (ac->io_mode == io_compressed ||
9372 ac->io_mode == io_compressed_stream)
9373 lbuf_phys_addr = (param->paddr - param->metadata_len);
9374 else {
9375 if (param->flags & SET_TIMESTAMP)
9376 lbuf_phys_addr = param->paddr -
9377 sizeof(struct snd_codec_metadata);
9378 else
9379 lbuf_phys_addr = param->paddr;
9380 }
9381 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",
9382 __func__,
9383 write.hdr.token, &param->paddr,
9384 write.buf_size, write.timestamp_msw,
9385 write.timestamp_lsw, &lbuf_phys_addr);
9386
9387 /* Use 0xFF00 for disabling timestamps */
9388 if (param->flags == 0xFF00)
9389 write.flags = (0x00000000 | (param->flags & 0x800000FF));
9390 else
9391 write.flags = (0x80000000 | param->flags);
9392 write.flags |= param->last_buffer << ASM_SHIFT_LAST_BUFFER_FLAG;
9393 write.seq_id = param->uid;
9394 list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
9395 buf_node = list_entry(ptr, struct asm_buffer_node,
9396 list);
9397 if (buf_node->buf_phys_addr == lbuf_phys_addr) {
9398 write.mem_map_handle = buf_node->mmap_hdl;
9399 break;
9400 }
9401 }
9402
9403 rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
9404 if (rc < 0) {
9405 pr_err("%s: write op[0x%x]rc[%d]\n", __func__,
9406 write.hdr.opcode, rc);
9407 goto fail_cmd;
9408 }
9409 return 0;
9410fail_cmd:
9411 return -EINVAL;
9412}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309413EXPORT_SYMBOL(q6asm_async_write);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309414
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309415/**
9416 * q6asm_async_read -
9417 * command to read DSP buffer
9418 *
9419 * @ac: Audio client handle
9420 * @param: params for async read
9421 *
9422 * Returns 0 on success or error on failure
9423 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309424int q6asm_async_read(struct audio_client *ac,
9425 struct audio_aio_read_param *param)
9426{
9427 int rc = 0;
9428 struct asm_data_cmd_read_v2 read;
9429 struct asm_buffer_node *buf_node = NULL;
9430 struct list_head *ptr, *next;
9431 phys_addr_t lbuf_phys_addr;
9432 u32 liomode;
9433 u32 io_compressed;
9434 int dir = 0;
9435
9436 if (ac == NULL) {
9437 pr_err("%s: APR handle NULL\n", __func__);
9438 return -EINVAL;
9439 }
9440 if (ac->apr == NULL) {
9441 pr_err("%s: AC APR handle NULL\n", __func__);
9442 return -EINVAL;
9443 }
9444
9445 q6asm_add_hdr_async(ac, &read.hdr, sizeof(read), FALSE);
9446
9447 /* Pass session id as token for AIO scheme */
9448 read.hdr.token = param->uid;
9449 read.hdr.opcode = ASM_DATA_CMD_READ_V2;
9450 read.buf_addr_lsw = lower_32_bits(param->paddr);
9451 read.buf_addr_msw = msm_audio_populate_upper_32_bits(param->paddr);
9452 read.buf_size = param->len;
9453 read.seq_id = param->uid;
9454 liomode = (NT_MODE | ASYNC_IO_MODE);
9455 io_compressed = (ASYNC_IO_MODE | COMPRESSED_IO);
9456 if (ac->io_mode == liomode) {
9457 lbuf_phys_addr = (param->paddr - 32);
9458 /*legacy wma driver case*/
9459 dir = IN;
9460 } else if (ac->io_mode == io_compressed) {
9461 lbuf_phys_addr = (param->paddr - 64);
9462 dir = OUT;
9463 } else {
9464 if (param->flags & COMPRESSED_TIMESTAMP_FLAG)
9465 lbuf_phys_addr = param->paddr -
9466 sizeof(struct snd_codec_metadata);
9467 else
9468 lbuf_phys_addr = param->paddr;
9469 dir = OUT;
9470 }
9471
9472 list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
9473 buf_node = list_entry(ptr, struct asm_buffer_node,
9474 list);
9475 if (buf_node->buf_phys_addr == lbuf_phys_addr) {
9476 read.mem_map_handle = buf_node->mmap_hdl;
9477 break;
9478 }
9479 }
9480
9481 rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
9482 if (rc < 0) {
9483 pr_err("%s: read op[0x%x]rc[%d]\n", __func__,
9484 read.hdr.opcode, rc);
9485 goto fail_cmd;
9486 }
9487 return 0;
9488fail_cmd:
9489 return -EINVAL;
9490}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309491EXPORT_SYMBOL(q6asm_async_read);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309492
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309493/**
9494 * q6asm_write -
9495 * command to write buffer data to DSP
9496 *
9497 * @ac: Audio client handle
9498 * @len: buffer size
9499 * @msw_ts: upper 32bits of timestamp
9500 * @lsw_ts: lower 32bits of timestamp
9501 * @flags: Flags for timestamp mode
9502 *
9503 * Returns 0 on success or error on failure
9504 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309505int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
9506 uint32_t lsw_ts, uint32_t flags)
9507{
9508 int rc = 0;
9509 struct asm_data_cmd_write_v2 write;
9510 struct asm_buffer_node *buf_node = NULL;
9511 struct audio_port_data *port;
9512 struct audio_buffer *ab;
9513 int dsp_buf = 0;
9514
9515 if (ac == NULL) {
9516 pr_err("%s: APR handle NULL\n", __func__);
9517 return -EINVAL;
9518 }
9519 if (ac->apr == NULL) {
9520 pr_err("%s: AC APR handle NULL\n", __func__);
9521 return -EINVAL;
9522 }
9523
9524 dev_vdbg(ac->dev, "%s: session[%d] len=%d\n",
9525 __func__, ac->session, len);
9526 if (ac->io_mode & SYNC_IO_MODE) {
9527 port = &ac->port[IN];
9528
9529 q6asm_add_hdr(ac, &write.hdr, sizeof(write),
9530 FALSE);
9531 mutex_lock(&port->lock);
9532
9533 dsp_buf = port->dsp_buf;
9534 ab = &port->buf[dsp_buf];
9535
9536 q6asm_update_token(&write.hdr.token,
9537 0, /* Session ID is NA */
9538 0, /* Stream ID is NA */
9539 port->dsp_buf,
9540 0, /* Direction flag is NA */
9541 NO_WAIT_CMD);
9542 write.hdr.opcode = ASM_DATA_CMD_WRITE_V2;
9543 write.buf_addr_lsw = lower_32_bits(ab->phys);
9544 write.buf_addr_msw = msm_audio_populate_upper_32_bits(ab->phys);
9545 write.buf_size = len;
9546 write.seq_id = port->dsp_buf;
9547 write.timestamp_lsw = lsw_ts;
9548 write.timestamp_msw = msw_ts;
9549 /* Use 0xFF00 for disabling timestamps */
9550 if (flags == 0xFF00)
9551 write.flags = (0x00000000 | (flags & 0x800000FF));
9552 else
9553 write.flags = (0x80000000 | flags);
9554 port->dsp_buf = q6asm_get_next_buf(ac, port->dsp_buf,
9555 port->max_buf_cnt);
9556 buf_node = list_first_entry(&ac->port[IN].mem_map_handle,
9557 struct asm_buffer_node,
9558 list);
9559 write.mem_map_handle = buf_node->mmap_hdl;
9560
9561 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]"
9562 , __func__,
9563 &ab->phys,
9564 write.buf_addr_lsw,
9565 write.hdr.token,
9566 write.seq_id,
9567 write.buf_size,
9568 write.mem_map_handle);
9569 mutex_unlock(&port->lock);
9570
9571 config_debug_fs_write(ab);
9572
9573 rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
9574 if (rc < 0) {
9575 pr_err("%s: write op[0x%x]rc[%d]\n",
9576 __func__, write.hdr.opcode, rc);
9577 goto fail_cmd;
9578 }
9579 return 0;
9580 }
9581fail_cmd:
9582 return -EINVAL;
9583}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309584EXPORT_SYMBOL(q6asm_write);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309585
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309586/**
9587 * q6asm_write_nolock -
9588 * command to write buffer data to DSP
9589 * with no wait for ack.
9590 *
9591 * @ac: Audio client handle
9592 * @len: buffer size
9593 * @msw_ts: upper 32bits of timestamp
9594 * @lsw_ts: lower 32bits of timestamp
9595 * @flags: Flags for timestamp mode
9596 *
9597 * Returns 0 on success or error on failure
9598 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309599int q6asm_write_nolock(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
9600 uint32_t lsw_ts, uint32_t flags)
9601{
9602 int rc = 0;
9603 struct asm_data_cmd_write_v2 write;
9604 struct asm_buffer_node *buf_node = NULL;
9605 struct audio_port_data *port;
9606 struct audio_buffer *ab;
9607 int dsp_buf = 0;
9608
9609 if (ac == NULL) {
9610 pr_err("%s: APR handle NULL\n", __func__);
9611 return -EINVAL;
9612 }
9613 if (ac->apr == NULL) {
9614 pr_err("%s: AC APR handle NULL\n", __func__);
9615 return -EINVAL;
9616 }
9617
9618 dev_vdbg(ac->dev, "%s: session[%d] len=%d\n",
9619 __func__, ac->session, len);
9620 if (ac->io_mode & SYNC_IO_MODE) {
9621 port = &ac->port[IN];
9622
9623 q6asm_add_hdr_async(ac, &write.hdr, sizeof(write),
9624 FALSE);
9625
9626 dsp_buf = port->dsp_buf;
9627 ab = &port->buf[dsp_buf];
9628
9629 q6asm_update_token(&write.hdr.token,
9630 0, /* Session ID is NA */
9631 0, /* Stream ID is NA */
9632 port->dsp_buf,
9633 0, /* Direction flag is NA */
9634 NO_WAIT_CMD);
9635
9636 write.hdr.opcode = ASM_DATA_CMD_WRITE_V2;
9637 write.buf_addr_lsw = lower_32_bits(ab->phys);
9638 write.buf_addr_msw = msm_audio_populate_upper_32_bits(ab->phys);
9639 write.buf_size = len;
9640 write.seq_id = port->dsp_buf;
9641 write.timestamp_lsw = lsw_ts;
9642 write.timestamp_msw = msw_ts;
9643 buf_node = list_first_entry(&ac->port[IN].mem_map_handle,
9644 struct asm_buffer_node,
9645 list);
9646 write.mem_map_handle = buf_node->mmap_hdl;
9647 /* Use 0xFF00 for disabling timestamps */
9648 if (flags == 0xFF00)
9649 write.flags = (0x00000000 | (flags & 0x800000FF));
9650 else
9651 write.flags = (0x80000000 | flags);
9652 port->dsp_buf = q6asm_get_next_buf(ac, port->dsp_buf,
9653 port->max_buf_cnt);
9654
9655 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]"
9656 , __func__,
9657 &ab->phys,
9658 write.buf_addr_lsw,
9659 write.hdr.token,
9660 write.seq_id,
9661 write.buf_size,
9662 write.mem_map_handle);
9663
9664 rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
9665 if (rc < 0) {
9666 pr_err("%s: write op[0x%x]rc[%d]\n",
9667 __func__, write.hdr.opcode, rc);
9668 goto fail_cmd;
9669 }
9670 return 0;
9671 }
9672fail_cmd:
9673 return -EINVAL;
9674}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309675EXPORT_SYMBOL(q6asm_write_nolock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309676
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309677/**
9678 * q6asm_get_session_time -
9679 * command to retrieve timestamp info
9680 *
9681 * @ac: Audio client handle
9682 * @tstamp: pointer to fill with timestamp info
9683 *
9684 * Returns 0 on success or error on failure
9685 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309686int q6asm_get_session_time(struct audio_client *ac, uint64_t *tstamp)
9687{
9688 struct asm_mtmx_strtr_get_params mtmx_params;
9689 int rc;
9690
9691 if (ac == NULL) {
9692 pr_err("%s: APR handle NULL\n", __func__);
9693 return -EINVAL;
9694 }
9695 if (ac->apr == NULL) {
9696 pr_err("%s: AC APR handle NULL\n", __func__);
9697 return -EINVAL;
9698 }
9699 if (tstamp == NULL) {
9700 pr_err("%s: tstamp NULL\n", __func__);
9701 return -EINVAL;
9702 }
9703
9704 q6asm_add_hdr(ac, &mtmx_params.hdr, sizeof(mtmx_params), TRUE);
9705 mtmx_params.hdr.opcode = ASM_SESSION_CMD_GET_MTMX_STRTR_PARAMS_V2;
9706 mtmx_params.param_info.data_payload_addr_lsw = 0;
9707 mtmx_params.param_info.data_payload_addr_msw = 0;
9708 mtmx_params.param_info.mem_map_handle = 0;
9709 mtmx_params.param_info.direction = (ac->io_mode & TUN_READ_IO_MODE
9710 ? 1 : 0);
9711 mtmx_params.param_info.module_id =
9712 ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
9713 mtmx_params.param_info.param_id =
9714 ASM_SESSION_MTMX_STRTR_PARAM_SESSION_TIME_V3;
9715 mtmx_params.param_info.param_max_size =
9716 sizeof(struct asm_stream_param_data_v2) +
9717 sizeof(struct asm_session_mtmx_strtr_param_session_time_v3_t);
9718 atomic_set(&ac->time_flag, 1);
9719
9720 dev_vdbg(ac->dev, "%s: session[%d]opcode[0x%x]\n", __func__,
9721 ac->session, mtmx_params.hdr.opcode);
9722 rc = apr_send_pkt(ac->apr, (uint32_t *) &mtmx_params);
9723 if (rc < 0) {
9724 pr_err("%s: Commmand 0x%x failed %d\n", __func__,
9725 mtmx_params.hdr.opcode, rc);
9726 goto fail_cmd;
9727 }
9728 rc = wait_event_timeout(ac->time_wait,
9729 (atomic_read(&ac->time_flag) == 0), 5*HZ);
9730 if (!rc) {
9731 pr_err("%s: timeout in getting session time from DSP\n",
9732 __func__);
9733 goto fail_cmd;
9734 }
9735
9736 *tstamp = ac->time_stamp;
9737 return 0;
9738
9739fail_cmd:
9740 return -EINVAL;
9741}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309742EXPORT_SYMBOL(q6asm_get_session_time);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309743
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309744/**
9745 * q6asm_get_session_time_legacy -
9746 * command to retrieve timestamp info
9747 *
9748 * @ac: Audio client handle
9749 * @tstamp: pointer to fill with timestamp info
9750 *
9751 * Returns 0 on success or error on failure
9752 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309753int q6asm_get_session_time_legacy(struct audio_client *ac, uint64_t *tstamp)
9754{
9755 struct apr_hdr hdr;
9756 int rc;
9757
9758 if (ac == NULL) {
9759 pr_err("%s: APR handle NULL\n", __func__);
9760 return -EINVAL;
9761 }
9762 if (ac->apr == NULL) {
9763 pr_err("%s: AC APR handle NULL\n", __func__);
9764 return -EINVAL;
9765 }
9766 if (tstamp == NULL) {
9767 pr_err("%s: tstamp NULL\n", __func__);
9768 return -EINVAL;
9769 }
9770
9771 q6asm_add_hdr(ac, &hdr, sizeof(hdr), TRUE);
9772 hdr.opcode = ASM_SESSION_CMD_GET_SESSIONTIME_V3;
9773 atomic_set(&ac->time_flag, 1);
9774
9775 dev_vdbg(ac->dev, "%s: session[%d]opcode[0x%x]\n", __func__,
9776 ac->session,
9777 hdr.opcode);
9778 rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
9779 if (rc < 0) {
9780 pr_err("%s: Commmand 0x%x failed %d\n",
9781 __func__, hdr.opcode, rc);
9782 goto fail_cmd;
9783 }
9784 rc = wait_event_timeout(ac->time_wait,
9785 (atomic_read(&ac->time_flag) == 0), 5*HZ);
9786 if (!rc) {
9787 pr_err("%s: timeout in getting session time from DSP\n",
9788 __func__);
9789 goto fail_cmd;
9790 }
9791
9792 *tstamp = ac->time_stamp;
9793 return 0;
9794
9795fail_cmd:
9796 return -EINVAL;
9797}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309798EXPORT_SYMBOL(q6asm_get_session_time_legacy);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309799
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309800/**
9801 * q6asm_send_audio_effects_params -
9802 * command to send audio effects params
9803 *
9804 * @ac: Audio client handle
9805 * @params: audio effects params
9806 * @params_length: size of params
9807 *
9808 * Returns 0 on success or error on failure
9809 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309810int q6asm_send_audio_effects_params(struct audio_client *ac, char *params,
9811 uint32_t params_length)
9812{
9813 char *asm_params = NULL;
9814 struct apr_hdr hdr;
9815 struct asm_stream_cmd_set_pp_params_v2 payload_params;
Xiaojun Sanga4648082018-04-27 14:57:33 +08009816 int sz, rc, session_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309817
9818 pr_debug("%s:\n", __func__);
9819 if (!ac) {
9820 pr_err("%s: APR handle NULL\n", __func__);
9821 return -EINVAL;
9822 }
Xiaojun Sanga4648082018-04-27 14:57:33 +08009823
9824 session_id = q6asm_get_session_id_from_audio_client(ac);
9825 if (!session_id)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309826 return -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08009827
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309828 if (params == NULL) {
9829 pr_err("%s: params NULL\n", __func__);
9830 return -EINVAL;
9831 }
9832 sz = sizeof(struct apr_hdr) +
9833 sizeof(struct asm_stream_cmd_set_pp_params_v2) +
9834 params_length;
9835 asm_params = kzalloc(sz, GFP_KERNEL);
9836 if (!asm_params) {
9837 pr_err("%s, asm params memory alloc failed", __func__);
9838 return -ENOMEM;
9839 }
Xiaojun Sanga4648082018-04-27 14:57:33 +08009840 mutex_lock(&session[session_id].mutex_lock_per_session);
9841 if (!q6asm_is_valid_audio_client(ac)) {
9842 rc = -EINVAL;
9843 goto fail_send_param;
9844 }
9845
9846 if (ac->apr == NULL) {
9847 pr_err("%s: AC APR handle NULL\n", __func__);
9848 rc = -EINVAL;
9849 goto fail_send_param;
9850 }
9851
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309852 q6asm_add_hdr_async(ac, &hdr, (sizeof(struct apr_hdr) +
9853 sizeof(struct asm_stream_cmd_set_pp_params_v2) +
9854 params_length), TRUE);
9855 atomic_set(&ac->cmd_state_pp, -1);
9856 hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
9857 payload_params.data_payload_addr_lsw = 0;
9858 payload_params.data_payload_addr_msw = 0;
9859 payload_params.mem_map_handle = 0;
9860 payload_params.data_payload_size = params_length;
9861 memcpy(((u8 *)asm_params), &hdr, sizeof(struct apr_hdr));
9862 memcpy(((u8 *)asm_params + sizeof(struct apr_hdr)), &payload_params,
9863 sizeof(struct asm_stream_cmd_set_pp_params_v2));
9864 memcpy(((u8 *)asm_params + sizeof(struct apr_hdr) +
9865 sizeof(struct asm_stream_cmd_set_pp_params_v2)),
9866 params, params_length);
9867 rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params);
9868 if (rc < 0) {
9869 pr_err("%s: audio effects set-params send failed\n", __func__);
9870 rc = -EINVAL;
9871 goto fail_send_param;
9872 }
9873 rc = wait_event_timeout(ac->cmd_wait,
9874 (atomic_read(&ac->cmd_state_pp) >= 0), 1*HZ);
9875 if (!rc) {
9876 pr_err("%s: timeout, audio effects set-params\n", __func__);
9877 rc = -ETIMEDOUT;
9878 goto fail_send_param;
9879 }
9880 if (atomic_read(&ac->cmd_state_pp) > 0) {
9881 pr_err("%s: DSP returned error[%s] set-params\n",
9882 __func__, adsp_err_get_err_str(
9883 atomic_read(&ac->cmd_state_pp)));
9884 rc = adsp_err_get_lnx_err_code(
9885 atomic_read(&ac->cmd_state_pp));
9886 goto fail_send_param;
9887 }
9888
9889 rc = 0;
9890fail_send_param:
Xiaojun Sanga4648082018-04-27 14:57:33 +08009891 mutex_unlock(&session[session_id].mutex_lock_per_session);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309892 kfree(asm_params);
9893 return rc;
9894}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309895EXPORT_SYMBOL(q6asm_send_audio_effects_params);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309896
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309897/**
9898 * q6asm_send_mtmx_strtr_window -
9899 * command to send matrix for window params
9900 *
9901 * @ac: Audio client handle
9902 * @window_param: window params
9903 * @param_id: param id for window
9904 *
9905 * Returns 0 on success or error on failure
9906 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309907int q6asm_send_mtmx_strtr_window(struct audio_client *ac,
9908 struct asm_session_mtmx_strtr_param_window_v2_t *window_param,
9909 uint32_t param_id)
9910{
9911 struct asm_mtmx_strtr_params matrix;
9912 int sz = 0;
9913 int rc = 0;
9914
9915 pr_debug("%s: Window lsw is %d, window msw is %d\n", __func__,
9916 window_param->window_lsw, window_param->window_msw);
9917
9918 if (!ac) {
9919 pr_err("%s: audio client handle is NULL\n", __func__);
9920 rc = -EINVAL;
9921 goto fail_cmd;
9922 }
9923
9924 if (ac->apr == NULL) {
9925 pr_err("%s: ac->apr is NULL", __func__);
9926 rc = -EINVAL;
9927 goto fail_cmd;
9928 }
9929
9930 sz = sizeof(struct asm_mtmx_strtr_params);
9931 q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE);
9932 atomic_set(&ac->cmd_state, -1);
9933 matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2;
9934
9935 matrix.param.data_payload_addr_lsw = 0;
9936 matrix.param.data_payload_addr_msw = 0;
9937 matrix.param.mem_map_handle = 0;
9938 matrix.param.data_payload_size =
9939 sizeof(struct asm_stream_param_data_v2) +
9940 sizeof(struct asm_session_mtmx_strtr_param_window_v2_t);
9941 matrix.param.direction = 0; /* RX */
9942 matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
9943 matrix.data.param_id = param_id;
9944 matrix.data.param_size =
9945 sizeof(struct asm_session_mtmx_strtr_param_window_v2_t);
9946 matrix.data.reserved = 0;
9947 memcpy(&(matrix.config.window_param),
9948 window_param,
9949 sizeof(struct asm_session_mtmx_strtr_param_window_v2_t));
9950
9951 rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix);
9952 if (rc < 0) {
9953 pr_err("%s: Render window start send failed paramid [0x%x]\n",
9954 __func__, matrix.data.param_id);
9955 rc = -EINVAL;
9956 goto fail_cmd;
9957 }
9958
9959 rc = wait_event_timeout(ac->cmd_wait,
9960 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
9961 if (!rc) {
9962 pr_err("%s: timeout, Render window start paramid[0x%x]\n",
9963 __func__, matrix.data.param_id);
9964 rc = -ETIMEDOUT;
9965 goto fail_cmd;
9966 }
9967
9968 if (atomic_read(&ac->cmd_state) > 0) {
9969 pr_err("%s: DSP returned error[%s]\n",
9970 __func__, adsp_err_get_err_str(
9971 atomic_read(&ac->cmd_state)));
9972 rc = adsp_err_get_lnx_err_code(
9973 atomic_read(&ac->cmd_state));
9974 goto fail_cmd;
9975 }
9976 rc = 0;
9977fail_cmd:
9978 return rc;
9979}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309980EXPORT_SYMBOL(q6asm_send_mtmx_strtr_window);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309981
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309982/**
9983 * q6asm_send_mtmx_strtr_render_mode -
9984 * command to send matrix for render mode
9985 *
9986 * @ac: Audio client handle
9987 * @render_mode: rendering mode
9988 *
9989 * Returns 0 on success or error on failure
9990 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309991int q6asm_send_mtmx_strtr_render_mode(struct audio_client *ac,
9992 uint32_t render_mode)
9993{
9994 struct asm_mtmx_strtr_params matrix;
9995 struct asm_session_mtmx_strtr_param_render_mode_t render_param;
9996 int sz = 0;
9997 int rc = 0;
9998
9999 pr_debug("%s: render mode is %d\n", __func__, render_mode);
10000
10001 if (!ac) {
10002 pr_err("%s: audio client handle is NULL\n", __func__);
10003 rc = -EINVAL;
10004 goto exit;
10005 }
10006
10007 if (ac->apr == NULL) {
10008 pr_err("%s: ac->apr is NULL\n", __func__);
10009 rc = -EINVAL;
10010 goto exit;
10011 }
10012
10013 if ((render_mode != ASM_SESSION_MTMX_STRTR_PARAM_RENDER_DEFAULT) &&
10014 (render_mode != ASM_SESSION_MTMX_STRTR_PARAM_RENDER_LOCAL_STC)) {
10015 pr_err("%s: Invalid render mode %d\n", __func__, render_mode);
10016 rc = -EINVAL;
10017 goto exit;
10018 }
10019
10020 memset(&render_param, 0,
10021 sizeof(struct asm_session_mtmx_strtr_param_render_mode_t));
10022 render_param.flags = render_mode;
10023
10024 memset(&matrix, 0, sizeof(struct asm_mtmx_strtr_params));
10025 sz = sizeof(struct asm_mtmx_strtr_params);
10026 q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE);
10027 atomic_set(&ac->cmd_state, -1);
10028 matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2;
10029
10030 matrix.param.data_payload_addr_lsw = 0;
10031 matrix.param.data_payload_addr_msw = 0;
10032 matrix.param.mem_map_handle = 0;
10033 matrix.param.data_payload_size =
10034 sizeof(struct asm_stream_param_data_v2) +
10035 sizeof(struct asm_session_mtmx_strtr_param_render_mode_t);
10036 matrix.param.direction = 0; /* RX */
10037 matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
10038 matrix.data.param_id = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_MODE_CMD;
10039 matrix.data.param_size =
10040 sizeof(struct asm_session_mtmx_strtr_param_render_mode_t);
10041 matrix.data.reserved = 0;
10042 memcpy(&(matrix.config.render_param),
10043 &render_param,
10044 sizeof(struct asm_session_mtmx_strtr_param_render_mode_t));
10045
10046 rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix);
10047 if (rc < 0) {
10048 pr_err("%s: Render mode send failed paramid [0x%x]\n",
10049 __func__, matrix.data.param_id);
10050 rc = -EINVAL;
10051 goto exit;
10052 }
10053
10054 rc = wait_event_timeout(ac->cmd_wait,
10055 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
10056 if (!rc) {
10057 pr_err("%s: timeout, Render mode send paramid [0x%x]\n",
10058 __func__, matrix.data.param_id);
10059 rc = -ETIMEDOUT;
10060 goto exit;
10061 }
10062
10063 if (atomic_read(&ac->cmd_state) > 0) {
10064 pr_err("%s: DSP returned error[%s]\n",
10065 __func__, adsp_err_get_err_str(
10066 atomic_read(&ac->cmd_state)));
10067 rc = adsp_err_get_lnx_err_code(
10068 atomic_read(&ac->cmd_state));
10069 goto exit;
10070 }
10071 rc = 0;
10072exit:
10073 return rc;
10074}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010075EXPORT_SYMBOL(q6asm_send_mtmx_strtr_render_mode);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010076
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010077/**
10078 * q6asm_send_mtmx_strtr_clk_rec_mode -
10079 * command to send matrix for clock rec
10080 *
10081 * @ac: Audio client handle
10082 * @clk_rec_mode: mode for clock rec
10083 *
10084 * Returns 0 on success or error on failure
10085 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010086int q6asm_send_mtmx_strtr_clk_rec_mode(struct audio_client *ac,
10087 uint32_t clk_rec_mode)
10088{
10089 struct asm_mtmx_strtr_params matrix;
10090 struct asm_session_mtmx_strtr_param_clk_rec_t clk_rec_param;
10091 int sz = 0;
10092 int rc = 0;
10093
10094 pr_debug("%s: clk rec mode is %d\n", __func__, clk_rec_mode);
10095
10096 if (!ac) {
10097 pr_err("%s: audio client handle is NULL\n", __func__);
10098 rc = -EINVAL;
10099 goto exit;
10100 }
10101
10102 if (ac->apr == NULL) {
10103 pr_err("%s: ac->apr is NULL\n", __func__);
10104 rc = -EINVAL;
10105 goto exit;
10106 }
10107
10108 if ((clk_rec_mode != ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_NONE) &&
10109 (clk_rec_mode != ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_AUTO)) {
10110 pr_err("%s: Invalid clk rec mode %d\n", __func__, clk_rec_mode);
10111 rc = -EINVAL;
10112 goto exit;
10113 }
10114
10115 memset(&clk_rec_param, 0,
10116 sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t));
10117 clk_rec_param.flags = clk_rec_mode;
10118
10119 memset(&matrix, 0, sizeof(struct asm_mtmx_strtr_params));
10120 sz = sizeof(struct asm_mtmx_strtr_params);
10121 q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE);
10122 atomic_set(&ac->cmd_state, -1);
10123 matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2;
10124
10125 matrix.param.data_payload_addr_lsw = 0;
10126 matrix.param.data_payload_addr_msw = 0;
10127 matrix.param.mem_map_handle = 0;
10128 matrix.param.data_payload_size =
10129 sizeof(struct asm_stream_param_data_v2) +
10130 sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t);
10131 matrix.param.direction = 0; /* RX */
10132 matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
10133 matrix.data.param_id = ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_CMD;
10134 matrix.data.param_size =
10135 sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t);
10136 matrix.data.reserved = 0;
10137 memcpy(&(matrix.config.clk_rec_param),
10138 &clk_rec_param,
10139 sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t));
10140
10141 rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix);
10142 if (rc < 0) {
10143 pr_err("%s: clk rec mode send failed paramid [0x%x]\n",
10144 __func__, matrix.data.param_id);
10145 rc = -EINVAL;
10146 goto exit;
10147 }
10148
10149 rc = wait_event_timeout(ac->cmd_wait,
10150 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
10151 if (!rc) {
10152 pr_err("%s: timeout, clk rec mode send paramid [0x%x]\n",
10153 __func__, matrix.data.param_id);
10154 rc = -ETIMEDOUT;
10155 goto exit;
10156 }
10157
10158 if (atomic_read(&ac->cmd_state) > 0) {
10159 pr_err("%s: DSP returned error[%s]\n",
10160 __func__, adsp_err_get_err_str(
10161 atomic_read(&ac->cmd_state)));
10162 rc = adsp_err_get_lnx_err_code(
10163 atomic_read(&ac->cmd_state));
10164 goto exit;
10165 }
10166 rc = 0;
10167exit:
10168 return rc;
10169}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010170EXPORT_SYMBOL(q6asm_send_mtmx_strtr_clk_rec_mode);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010171
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010172/**
10173 * q6asm_send_mtmx_strtr_enable_adjust_session_clock -
10174 * command to send matrix for adjust time
10175 *
10176 * @ac: Audio client handle
10177 * @enable: flag to adjust time or not
10178 *
10179 * Returns 0 on success or error on failure
10180 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010181int q6asm_send_mtmx_strtr_enable_adjust_session_clock(struct audio_client *ac,
10182 bool enable)
10183{
10184 struct asm_mtmx_strtr_params matrix;
10185 struct asm_session_mtmx_param_adjust_session_time_ctl_t adjust_time;
10186 int sz = 0;
10187 int rc = 0;
10188
10189 pr_debug("%s: adjust session enable %d\n", __func__, enable);
10190
10191 if (!ac) {
10192 pr_err("%s: audio client handle is NULL\n", __func__);
10193 rc = -EINVAL;
10194 goto exit;
10195 }
10196
10197 if (ac->apr == NULL) {
10198 pr_err("%s: ac->apr is NULL\n", __func__);
10199 rc = -EINVAL;
10200 goto exit;
10201 }
10202
10203 adjust_time.enable = enable;
10204 memset(&matrix, 0, sizeof(struct asm_mtmx_strtr_params));
10205 sz = sizeof(struct asm_mtmx_strtr_params);
10206 q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE);
10207 atomic_set(&ac->cmd_state, -1);
10208 matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2;
10209
10210 matrix.param.data_payload_addr_lsw = 0;
10211 matrix.param.data_payload_addr_msw = 0;
10212 matrix.param.mem_map_handle = 0;
10213 matrix.param.data_payload_size =
10214 sizeof(struct asm_stream_param_data_v2) +
10215 sizeof(struct asm_session_mtmx_param_adjust_session_time_ctl_t);
10216 matrix.param.direction = 0; /* RX */
10217 matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
10218 matrix.data.param_id = ASM_SESSION_MTMX_PARAM_ADJUST_SESSION_TIME_CTL;
10219 matrix.data.param_size =
10220 sizeof(struct asm_session_mtmx_param_adjust_session_time_ctl_t);
10221 matrix.data.reserved = 0;
10222 matrix.config.adj_time_param.enable = adjust_time.enable;
10223
10224 rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix);
10225 if (rc < 0) {
10226 pr_err("%s: enable adjust session failed failed paramid [0x%x]\n",
10227 __func__, matrix.data.param_id);
10228 rc = -EINVAL;
10229 goto exit;
10230 }
10231
10232 rc = wait_event_timeout(ac->cmd_wait,
10233 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
10234 if (!rc) {
10235 pr_err("%s: enable adjust session failed failed paramid [0x%x]\n",
10236 __func__, matrix.data.param_id);
10237 rc = -ETIMEDOUT;
10238 goto exit;
10239 }
10240
10241 if (atomic_read(&ac->cmd_state) > 0) {
10242 pr_err("%s: DSP returned error[%s]\n",
10243 __func__, adsp_err_get_err_str(
10244 atomic_read(&ac->cmd_state)));
10245 rc = adsp_err_get_lnx_err_code(
10246 atomic_read(&ac->cmd_state));
10247 goto exit;
10248 }
10249 rc = 0;
10250exit:
10251 return rc;
10252}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010253EXPORT_SYMBOL(q6asm_send_mtmx_strtr_enable_adjust_session_clock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010254
10255
10256static int __q6asm_cmd(struct audio_client *ac, int cmd, uint32_t stream_id)
10257{
10258 struct apr_hdr hdr;
10259 int rc;
10260 atomic_t *state;
10261 int cnt = 0;
10262
10263 if (!ac) {
Xiaojun Sangc3277492018-09-06 14:34:03 +080010264 pr_err_ratelimited("%s: APR handle NULL\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010265 return -EINVAL;
10266 }
10267 if (ac->apr == NULL) {
Xiaojun Sangc3277492018-09-06 14:34:03 +080010268 pr_err_ratelimited("%s: AC APR handle NULL\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010269 return -EINVAL;
10270 }
10271 q6asm_stream_add_hdr(ac, &hdr, sizeof(hdr), TRUE, stream_id);
10272 atomic_set(&ac->cmd_state, -1);
10273 /*
10274 * Updated the token field with stream/session for compressed playback
10275 * Platform driver must know the the stream with which the command is
10276 * associated
10277 */
10278 if (ac->io_mode & COMPRESSED_STREAM_IO)
10279 q6asm_update_token(&hdr.token,
10280 ac->session,
10281 stream_id,
10282 0, /* Buffer index is NA */
10283 0, /* Direction flag is NA */
10284 WAIT_CMD);
10285 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
10286 __func__, hdr.token, stream_id, ac->session);
10287 switch (cmd) {
10288 case CMD_PAUSE:
10289 pr_debug("%s: CMD_PAUSE\n", __func__);
10290 hdr.opcode = ASM_SESSION_CMD_PAUSE;
10291 state = &ac->cmd_state;
10292 break;
10293 case CMD_SUSPEND:
10294 pr_debug("%s: CMD_SUSPEND\n", __func__);
10295 hdr.opcode = ASM_SESSION_CMD_SUSPEND;
10296 state = &ac->cmd_state;
10297 break;
10298 case CMD_FLUSH:
10299 pr_debug("%s: CMD_FLUSH\n", __func__);
10300 hdr.opcode = ASM_STREAM_CMD_FLUSH;
10301 state = &ac->cmd_state;
10302 break;
10303 case CMD_OUT_FLUSH:
10304 pr_debug("%s: CMD_OUT_FLUSH\n", __func__);
10305 hdr.opcode = ASM_STREAM_CMD_FLUSH_READBUFS;
10306 state = &ac->cmd_state;
10307 break;
10308 case CMD_EOS:
10309 pr_debug("%s: CMD_EOS\n", __func__);
10310 hdr.opcode = ASM_DATA_CMD_EOS;
10311 atomic_set(&ac->cmd_state, 0);
10312 state = &ac->cmd_state;
10313 break;
10314 case CMD_CLOSE:
10315 pr_debug("%s: CMD_CLOSE\n", __func__);
10316 hdr.opcode = ASM_STREAM_CMD_CLOSE;
10317 state = &ac->cmd_state;
10318 break;
10319 default:
10320 pr_err("%s: Invalid format[%d]\n", __func__, cmd);
10321 rc = -EINVAL;
10322 goto fail_cmd;
10323 }
10324 pr_debug("%s: session[%d]opcode[0x%x]\n", __func__,
10325 ac->session,
10326 hdr.opcode);
10327 rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
10328 if (rc < 0) {
10329 pr_err("%s: Commmand 0x%x failed %d\n",
10330 __func__, hdr.opcode, rc);
10331 rc = -EINVAL;
10332 goto fail_cmd;
10333 }
10334 rc = wait_event_timeout(ac->cmd_wait, (atomic_read(state) >= 0), 5*HZ);
10335 if (!rc) {
10336 pr_err("%s: timeout. waited for response opcode[0x%x]\n",
10337 __func__, hdr.opcode);
10338 rc = -ETIMEDOUT;
10339 goto fail_cmd;
10340 }
10341 if (atomic_read(state) > 0) {
10342 pr_err("%s: DSP returned error[%s] opcode %d\n",
10343 __func__, adsp_err_get_err_str(
10344 atomic_read(state)),
10345 hdr.opcode);
10346 rc = adsp_err_get_lnx_err_code(atomic_read(state));
10347 goto fail_cmd;
10348 }
10349
10350 if (cmd == CMD_FLUSH)
10351 q6asm_reset_buf_state(ac);
10352 if (cmd == CMD_CLOSE) {
10353 /* check if DSP return all buffers */
10354 if (ac->port[IN].buf) {
10355 for (cnt = 0; cnt < ac->port[IN].max_buf_cnt;
10356 cnt++) {
10357 if (ac->port[IN].buf[cnt].used == IN) {
10358 dev_vdbg(ac->dev, "Write Buf[%d] not returned\n",
10359 cnt);
10360 }
10361 }
10362 }
10363 if (ac->port[OUT].buf) {
10364 for (cnt = 0; cnt < ac->port[OUT].max_buf_cnt; cnt++) {
10365 if (ac->port[OUT].buf[cnt].used == OUT) {
10366 dev_vdbg(ac->dev, "Read Buf[%d] not returned\n",
10367 cnt);
10368 }
10369 }
10370 }
10371 }
10372 return 0;
10373fail_cmd:
10374 return rc;
10375}
10376
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010377/**
10378 * q6asm_cmd -
10379 * Function used to send commands for
10380 * ASM with wait for ack.
10381 *
10382 * @ac: Audio client handle
10383 * @cmd: command to send
10384 *
10385 * Returns 0 on success or error on failure
10386 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010387int q6asm_cmd(struct audio_client *ac, int cmd)
10388{
10389 return __q6asm_cmd(ac, cmd, ac->stream_id);
10390}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010391EXPORT_SYMBOL(q6asm_cmd);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010392
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010393/**
10394 * q6asm_stream_cmd -
10395 * Function used to send commands for
10396 * ASM stream with wait for ack.
10397 *
10398 * @ac: Audio client handle
10399 * @cmd: command to send
10400 * @stream_id: Stream ID
10401 *
10402 * Returns 0 on success or error on failure
10403 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010404int q6asm_stream_cmd(struct audio_client *ac, int cmd, uint32_t stream_id)
10405{
10406 return __q6asm_cmd(ac, cmd, stream_id);
10407}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010408EXPORT_SYMBOL(q6asm_stream_cmd);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010409
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010410/**
10411 * q6asm_cmd_nowait -
10412 * Function used to send commands for
10413 * ASM stream without wait for ack.
10414 *
10415 * @ac: Audio client handle
10416 * @cmd: command to send
10417 * @stream_id: Stream ID
10418 *
10419 * Returns 0 on success or error on failure
10420 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010421static int __q6asm_cmd_nowait(struct audio_client *ac, int cmd,
10422 uint32_t stream_id)
10423{
10424 struct apr_hdr hdr;
10425 int rc;
10426
10427 if (!ac) {
Xiaojun Sangc3277492018-09-06 14:34:03 +080010428 pr_err_ratelimited("%s: APR handle NULL\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010429 return -EINVAL;
10430 }
10431 if (ac->apr == NULL) {
Xiaojun Sangc3277492018-09-06 14:34:03 +080010432 pr_err_ratelimited("%s: AC APR handle NULL\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010433 return -EINVAL;
10434 }
10435 q6asm_stream_add_hdr_async(ac, &hdr, sizeof(hdr), TRUE, stream_id);
10436 atomic_set(&ac->cmd_state, 1);
10437 /*
10438 * Updated the token field with stream/session for compressed playback
10439 * Platform driver must know the the stream with which the command is
10440 * associated
10441 */
10442 if (ac->io_mode & COMPRESSED_STREAM_IO)
10443 q6asm_update_token(&hdr.token,
10444 ac->session,
10445 stream_id,
10446 0, /* Buffer index is NA */
10447 0, /* Direction flag is NA */
10448 NO_WAIT_CMD);
10449
10450 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
10451 __func__, hdr.token, stream_id, ac->session);
10452 switch (cmd) {
10453 case CMD_PAUSE:
10454 pr_debug("%s: CMD_PAUSE\n", __func__);
10455 hdr.opcode = ASM_SESSION_CMD_PAUSE;
10456 break;
Sidipotu Ashok5c6855b2019-01-08 15:58:37 +053010457
10458 case CMD_FLUSH:
10459 pr_debug("%s: CMD_FLUSH\n", __func__);
10460 hdr.opcode = ASM_STREAM_CMD_FLUSH;
10461 break;
10462
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010463 case CMD_EOS:
10464 pr_debug("%s: CMD_EOS\n", __func__);
10465 hdr.opcode = ASM_DATA_CMD_EOS;
10466 break;
10467 case CMD_CLOSE:
10468 pr_debug("%s: CMD_CLOSE\n", __func__);
10469 hdr.opcode = ASM_STREAM_CMD_CLOSE;
10470 break;
10471 default:
10472 pr_err("%s: Invalid format[%d]\n", __func__, cmd);
10473 goto fail_cmd;
10474 }
10475 pr_debug("%s: session[%d]opcode[0x%x]\n", __func__,
10476 ac->session,
10477 hdr.opcode);
10478
10479 rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
10480 if (rc < 0) {
10481 pr_err("%s: Commmand 0x%x failed %d\n",
10482 __func__, hdr.opcode, rc);
10483 goto fail_cmd;
10484 }
10485 return 0;
10486fail_cmd:
10487 return -EINVAL;
10488}
10489
10490int q6asm_cmd_nowait(struct audio_client *ac, int cmd)
10491{
10492 pr_debug("%s: stream_id: %d\n", __func__, ac->stream_id);
10493 return __q6asm_cmd_nowait(ac, cmd, ac->stream_id);
10494}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010495EXPORT_SYMBOL(q6asm_cmd_nowait);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010496
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010497/**
10498 * q6asm_stream_cmd_nowait -
10499 * Function used to send commands for
10500 * ASM stream without wait for ack.
10501 *
10502 * @ac: Audio client handle
10503 * @cmd: command to send
10504 * @stream_id: Stream ID
10505 *
10506 * Returns 0 on success or error on failure
10507 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010508int q6asm_stream_cmd_nowait(struct audio_client *ac, int cmd,
10509 uint32_t stream_id)
10510{
10511 pr_debug("%s: stream_id: %d\n", __func__, stream_id);
10512 return __q6asm_cmd_nowait(ac, cmd, stream_id);
10513}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010514EXPORT_SYMBOL(q6asm_stream_cmd_nowait);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010515
10516int __q6asm_send_meta_data(struct audio_client *ac, uint32_t stream_id,
10517 uint32_t initial_samples, uint32_t trailing_samples)
10518{
10519 struct asm_data_cmd_remove_silence silence;
10520 int rc = 0;
10521
10522 if (!ac) {
Xiaojun Sangc3277492018-09-06 14:34:03 +080010523 pr_err_ratelimited("%s: APR handle NULL\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010524 return -EINVAL;
10525 }
10526 if (ac->apr == NULL) {
Xiaojun Sangc3277492018-09-06 14:34:03 +080010527 pr_err_ratelimited("%s: AC APR handle NULL\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010528 return -EINVAL;
10529 }
10530 pr_debug("%s: session[%d]\n", __func__, ac->session);
10531 q6asm_stream_add_hdr_async(ac, &silence.hdr, sizeof(silence), TRUE,
10532 stream_id);
10533
10534 /*
10535 * Updated the token field with stream/session for compressed playback
10536 * Platform driver must know the the stream with which the command is
10537 * associated
10538 */
10539 if (ac->io_mode & COMPRESSED_STREAM_IO)
10540 q6asm_update_token(&silence.hdr.token,
10541 ac->session,
10542 stream_id,
10543 0, /* Buffer index is NA */
10544 0, /* Direction flag is NA */
10545 NO_WAIT_CMD);
10546 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
10547 __func__, silence.hdr.token, stream_id, ac->session);
10548
10549 silence.hdr.opcode = ASM_DATA_CMD_REMOVE_INITIAL_SILENCE;
10550 silence.num_samples_to_remove = initial_samples;
10551
10552 rc = apr_send_pkt(ac->apr, (uint32_t *) &silence);
10553 if (rc < 0) {
10554 pr_err("%s: Commmand silence failed[%d]", __func__, rc);
10555
10556 goto fail_cmd;
10557 }
10558
10559 silence.hdr.opcode = ASM_DATA_CMD_REMOVE_TRAILING_SILENCE;
10560 silence.num_samples_to_remove = trailing_samples;
10561
10562
10563 rc = apr_send_pkt(ac->apr, (uint32_t *) &silence);
10564 if (rc < 0) {
10565 pr_err("%s: Commmand silence failed[%d]", __func__, rc);
10566 goto fail_cmd;
10567 }
10568
10569 return 0;
10570fail_cmd:
10571 return -EINVAL;
10572}
10573
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010574/**
10575 * q6asm_stream_send_meta_data -
10576 * command to send meta data for stream
10577 *
10578 * @ac: Audio client handle
10579 * @stream_id: Stream ID
10580 * @initial_samples: Initial samples of stream
10581 * @trailing_samples: Trailing samples of stream
10582 *
10583 * Returns 0 on success or error on failure
10584 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010585int q6asm_stream_send_meta_data(struct audio_client *ac, uint32_t stream_id,
10586 uint32_t initial_samples, uint32_t trailing_samples)
10587{
10588 return __q6asm_send_meta_data(ac, stream_id, initial_samples,
10589 trailing_samples);
10590}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010591EXPORT_SYMBOL(q6asm_stream_send_meta_data);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010592
10593int q6asm_send_meta_data(struct audio_client *ac, uint32_t initial_samples,
10594 uint32_t trailing_samples)
10595{
10596 return __q6asm_send_meta_data(ac, ac->stream_id, initial_samples,
10597 trailing_samples);
10598}
10599
10600static void q6asm_reset_buf_state(struct audio_client *ac)
10601{
10602 int cnt = 0;
10603 int loopcnt = 0;
10604 int used;
10605 struct audio_port_data *port = NULL;
10606
10607 if (ac->io_mode & SYNC_IO_MODE) {
10608 used = (ac->io_mode & TUN_WRITE_IO_MODE ? 1 : 0);
10609 mutex_lock(&ac->cmd_lock);
10610 for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
10611 port = &ac->port[loopcnt];
10612 cnt = port->max_buf_cnt - 1;
10613 port->dsp_buf = 0;
10614 port->cpu_buf = 0;
10615 while (cnt >= 0) {
10616 if (!port->buf)
10617 continue;
10618 port->buf[cnt].used = used;
10619 cnt--;
10620 }
10621 }
10622 mutex_unlock(&ac->cmd_lock);
10623 }
10624}
10625
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010626/**
10627 * q6asm_reg_tx_overflow -
10628 * command to register for TX overflow events
10629 *
10630 * @ac: Audio client handle
10631 * @enable: flag to enable or disable events
10632 *
10633 * Returns 0 on success or error on failure
10634 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010635int q6asm_reg_tx_overflow(struct audio_client *ac, uint16_t enable)
10636{
10637 struct asm_session_cmd_regx_overflow tx_overflow;
10638 int rc;
10639
10640 if (!ac) {
10641 pr_err("%s: APR handle NULL\n", __func__);
10642 return -EINVAL;
10643 }
10644 if (ac->apr == NULL) {
10645 pr_err("%s: AC APR handle NULL\n", __func__);
10646 return -EINVAL;
10647 }
10648 pr_debug("%s: session[%d]enable[%d]\n", __func__,
10649 ac->session, enable);
10650 q6asm_add_hdr(ac, &tx_overflow.hdr, sizeof(tx_overflow), TRUE);
10651 atomic_set(&ac->cmd_state, -1);
10652
10653 tx_overflow.hdr.opcode =
10654 ASM_SESSION_CMD_REGISTER_FORX_OVERFLOW_EVENTS;
10655 /* tx overflow event: enable */
10656 tx_overflow.enable_flag = enable;
10657
10658 rc = apr_send_pkt(ac->apr, (uint32_t *) &tx_overflow);
10659 if (rc < 0) {
10660 pr_err("%s: tx overflow op[0x%x]rc[%d]\n",
10661 __func__, tx_overflow.hdr.opcode, rc);
10662 rc = -EINVAL;
10663 goto fail_cmd;
10664 }
10665 rc = wait_event_timeout(ac->cmd_wait,
10666 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
10667 if (!rc) {
10668 pr_err("%s: timeout. waited for tx overflow\n", __func__);
10669 rc = -ETIMEDOUT;
10670 goto fail_cmd;
10671 }
10672 if (atomic_read(&ac->cmd_state) > 0) {
10673 pr_err("%s: DSP returned error[%s]\n",
10674 __func__, adsp_err_get_err_str(
10675 atomic_read(&ac->cmd_state)));
10676 rc = adsp_err_get_lnx_err_code(
10677 atomic_read(&ac->cmd_state));
10678 goto fail_cmd;
10679 }
10680
10681 return 0;
10682fail_cmd:
10683 return rc;
10684}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010685EXPORT_SYMBOL(q6asm_reg_tx_overflow);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010686
10687int q6asm_reg_rx_underflow(struct audio_client *ac, uint16_t enable)
10688{
10689 struct asm_session_cmd_rgstr_rx_underflow rx_underflow;
10690 int rc;
10691
10692 if (!ac) {
10693 pr_err("%s: AC APR handle NULL\n", __func__);
10694 return -EINVAL;
10695 }
10696 if (ac->apr == NULL) {
10697 pr_err("%s: APR handle NULL\n", __func__);
10698 return -EINVAL;
10699 }
10700 pr_debug("%s: session[%d]enable[%d]\n", __func__,
10701 ac->session, enable);
10702 q6asm_add_hdr_async(ac, &rx_underflow.hdr, sizeof(rx_underflow), FALSE);
10703
10704 rx_underflow.hdr.opcode =
10705 ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS;
10706 /* tx overflow event: enable */
10707 rx_underflow.enable_flag = enable;
10708
10709 rc = apr_send_pkt(ac->apr, (uint32_t *) &rx_underflow);
10710 if (rc < 0) {
10711 pr_err("%s: tx overflow op[0x%x]rc[%d]\n",
10712 __func__, rx_underflow.hdr.opcode, rc);
10713 goto fail_cmd;
10714 }
10715 return 0;
10716fail_cmd:
10717 return -EINVAL;
10718}
10719
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010720/**
10721 * q6asm_adjust_session_clock -
10722 * command to adjust session clock
10723 *
10724 * @ac: Audio client handle
10725 * @adjust_time_lsw: lower 32bits
10726 * @adjust_time_msw: upper 32bits
10727 *
10728 * Returns 0 on success or error on failure
10729 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010730int q6asm_adjust_session_clock(struct audio_client *ac,
10731 uint32_t adjust_time_lsw,
10732 uint32_t adjust_time_msw)
10733{
10734 int rc = 0;
10735 int sz = 0;
10736 struct asm_session_cmd_adjust_session_clock_v2 adjust_clock;
10737
10738 pr_debug("%s: adjust_time_lsw is %x, adjust_time_msw is %x\n", __func__,
10739 adjust_time_lsw, adjust_time_msw);
10740
10741 if (!ac) {
10742 pr_err("%s: audio client handle is NULL\n", __func__);
10743 rc = -EINVAL;
10744 goto fail_cmd;
10745 }
10746
10747 if (ac->apr == NULL) {
10748 pr_err("%s: ac->apr is NULL", __func__);
10749 rc = -EINVAL;
10750 goto fail_cmd;
10751 }
10752
10753 sz = sizeof(struct asm_session_cmd_adjust_session_clock_v2);
10754 q6asm_add_hdr(ac, &adjust_clock.hdr, sz, TRUE);
10755 atomic_set(&ac->cmd_state, -1);
10756 adjust_clock.hdr.opcode = ASM_SESSION_CMD_ADJUST_SESSION_CLOCK_V2;
10757
10758 adjust_clock.adjustime_lsw = adjust_time_lsw;
10759 adjust_clock.adjustime_msw = adjust_time_msw;
10760
10761
10762 rc = apr_send_pkt(ac->apr, (uint32_t *) &adjust_clock);
10763 if (rc < 0) {
10764 pr_err("%s: adjust_clock send failed paramid [0x%x]\n",
10765 __func__, adjust_clock.hdr.opcode);
10766 rc = -EINVAL;
10767 goto fail_cmd;
10768 }
10769
10770 rc = wait_event_timeout(ac->cmd_wait,
10771 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
10772 if (!rc) {
10773 pr_err("%s: timeout, adjust_clock paramid[0x%x]\n",
10774 __func__, adjust_clock.hdr.opcode);
10775 rc = -ETIMEDOUT;
10776 goto fail_cmd;
10777 }
10778
10779 if (atomic_read(&ac->cmd_state) > 0) {
10780 pr_err("%s: DSP returned error[%s]\n",
10781 __func__, adsp_err_get_err_str(
10782 atomic_read(&ac->cmd_state)));
10783 rc = adsp_err_get_lnx_err_code(
10784 atomic_read(&ac->cmd_state));
10785 goto fail_cmd;
10786 }
10787 rc = 0;
10788fail_cmd:
10789 return rc;
10790}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010791EXPORT_SYMBOL(q6asm_adjust_session_clock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010792
10793/*
10794 * q6asm_get_path_delay() - get the path delay for an audio session
10795 * @ac: audio client handle
10796 *
10797 * Retrieves the current audio DSP path delay for the given audio session.
10798 *
10799 * Return: 0 on success, error code otherwise
10800 */
10801int q6asm_get_path_delay(struct audio_client *ac)
10802{
10803 int rc = 0;
10804 struct apr_hdr hdr;
10805
10806 if (!ac || ac->apr == NULL) {
10807 pr_err("%s: invalid audio client\n", __func__);
10808 return -EINVAL;
10809 }
10810
10811 hdr.opcode = ASM_SESSION_CMD_GET_PATH_DELAY_V2;
10812 q6asm_add_hdr(ac, &hdr, sizeof(hdr), TRUE);
10813 atomic_set(&ac->cmd_state, -1);
10814
10815 rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
10816 if (rc < 0) {
10817 pr_err("%s: Commmand 0x%x failed %d\n", __func__,
10818 hdr.opcode, rc);
10819 return rc;
10820 }
10821
10822 rc = wait_event_timeout(ac->cmd_wait,
10823 (atomic_read(&ac->cmd_state) >= 0), 5 * HZ);
10824 if (!rc) {
10825 pr_err("%s: timeout. waited for response opcode[0x%x]\n",
10826 __func__, hdr.opcode);
10827 return -ETIMEDOUT;
10828 }
10829
10830 if (atomic_read(&ac->cmd_state) > 0) {
10831 pr_err("%s: DSP returned error[%s]\n",
10832 __func__, adsp_err_get_err_str(
10833 atomic_read(&ac->cmd_state)));
10834 rc = adsp_err_get_lnx_err_code(
10835 atomic_read(&ac->cmd_state));
10836 return rc;
10837 }
10838
10839 return 0;
10840}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010841EXPORT_SYMBOL(q6asm_get_path_delay);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010842
10843int q6asm_get_apr_service_id(int session_id)
10844{
10845 pr_debug("%s:\n", __func__);
10846
10847 if (session_id <= 0 || session_id > ASM_ACTIVE_STREAMS_ALLOWED) {
10848 pr_err("%s: invalid session_id = %d\n", __func__, session_id);
10849 return -EINVAL;
10850 }
10851
Meng Wang9730cdd2017-09-26 12:48:31 +080010852 return ((struct apr_svc *)(session[session_id].ac)->apr)->id;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010853}
10854
10855int q6asm_get_asm_topology(int session_id)
10856{
10857 int topology = -EINVAL;
10858
10859 if (session_id <= 0 || session_id > ASM_ACTIVE_STREAMS_ALLOWED) {
10860 pr_err("%s: invalid session_id = %d\n", __func__, session_id);
10861 goto done;
10862 }
Meng Wang9730cdd2017-09-26 12:48:31 +080010863 if (session[session_id].ac == NULL) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010864 pr_err("%s: session not created for session id = %d\n",
10865 __func__, session_id);
10866 goto done;
10867 }
Meng Wang9730cdd2017-09-26 12:48:31 +080010868 topology = (session[session_id].ac)->topology;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010869done:
10870 return topology;
10871}
10872
10873int q6asm_get_asm_app_type(int session_id)
10874{
10875 int app_type = -EINVAL;
10876
10877 if (session_id <= 0 || session_id > ASM_ACTIVE_STREAMS_ALLOWED) {
10878 pr_err("%s: invalid session_id = %d\n", __func__, session_id);
10879 goto done;
10880 }
Meng Wang9730cdd2017-09-26 12:48:31 +080010881 if (session[session_id].ac == NULL) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010882 pr_err("%s: session not created for session id = %d\n",
10883 __func__, session_id);
10884 goto done;
10885 }
Meng Wang9730cdd2017-09-26 12:48:31 +080010886 app_type = (session[session_id].ac)->app_type;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010887done:
10888 return app_type;
10889}
10890
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -070010891/*
10892 * Retrieving cal_block will mark cal_block as stale.
10893 * Hence it cannot be reused or resent unless the flag
10894 * is reset.
10895 */
10896static int q6asm_get_asm_topology_apptype(struct q6asm_cal_info *cal_info)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010897{
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010898 struct cal_block_data *cal_block = NULL;
10899
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -070010900 cal_info->topology_id = DEFAULT_POPP_TOPOLOGY;
10901 cal_info->app_type = DEFAULT_APP_TYPE;
10902
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010903 if (cal_data[ASM_TOPOLOGY_CAL] == NULL)
10904 goto done;
10905
10906 mutex_lock(&cal_data[ASM_TOPOLOGY_CAL]->lock);
10907 cal_block = cal_utils_get_only_cal_block(cal_data[ASM_TOPOLOGY_CAL]);
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -070010908 if (cal_block == NULL || cal_utils_is_cal_stale(cal_block))
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010909 goto unlock;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -070010910 cal_info->topology_id = ((struct audio_cal_info_asm_top *)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010911 cal_block->cal_info)->topology;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -070010912 cal_info->app_type = ((struct audio_cal_info_asm_top *)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010913 cal_block->cal_info)->app_type;
10914
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -070010915 cal_utils_mark_cal_used(cal_block);
10916
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010917unlock:
10918 mutex_unlock(&cal_data[ASM_TOPOLOGY_CAL]->lock);
10919done:
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -070010920 pr_debug("%s: Using topology %d app_type %d\n", __func__,
10921 cal_info->topology_id, cal_info->app_type);
10922
10923 return 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010924}
10925
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010926/**
10927 * q6asm_send_cal -
10928 * command to send ASM calibration
10929 *
10930 * @ac: Audio client handle
10931 *
10932 * Returns 0 on success or error on failure
10933 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010934int q6asm_send_cal(struct audio_client *ac)
10935{
10936 struct cal_block_data *cal_block = NULL;
10937 struct apr_hdr hdr;
10938 char *asm_params = NULL;
10939 struct asm_stream_cmd_set_pp_params_v2 payload_params;
Xiaojun Sanga4648082018-04-27 14:57:33 +080010940 int sz, rc = -EINVAL, session_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010941
10942 pr_debug("%s:\n", __func__);
10943
10944 if (!ac) {
10945 pr_err("%s: APR handle NULL\n", __func__);
10946 goto done;
10947 }
Xiaojun Sanga4648082018-04-27 14:57:33 +080010948
10949 session_id = q6asm_get_session_id_from_audio_client(ac);
10950 if (!session_id)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010951 goto done;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010952
10953 if (cal_data[ASM_AUDSTRM_CAL] == NULL)
10954 goto done;
10955
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010956 mutex_lock(&cal_data[ASM_AUDSTRM_CAL]->lock);
10957 cal_block = cal_utils_get_only_cal_block(cal_data[ASM_AUDSTRM_CAL]);
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -070010958 if (cal_block == NULL || cal_utils_is_cal_stale(cal_block)) {
10959 rc = 0; /* not error case */
10960 pr_err("%s: cal_block is NULL or stale\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010961 __func__);
10962 goto unlock;
10963 }
10964
10965 if (cal_block->cal_data.size == 0) {
10966 rc = 0; /* not error case */
10967 pr_debug("%s: cal_data.size is 0, don't send cal data\n",
10968 __func__);
10969 goto unlock;
10970 }
10971
10972 rc = remap_cal_data(ASM_AUDSTRM_CAL_TYPE, cal_block);
10973 if (rc) {
10974 pr_err("%s: Remap_cal_data failed for cal %d!\n",
10975 __func__, ASM_AUDSTRM_CAL);
10976 goto unlock;
10977 }
10978
10979 sz = sizeof(struct apr_hdr) +
10980 sizeof(struct asm_stream_cmd_set_pp_params_v2);
10981 asm_params = kzalloc(sz, GFP_KERNEL);
10982 if (!asm_params) {
10983 pr_err("%s, asm params memory alloc failed", __func__);
10984 rc = -ENOMEM;
10985 goto unlock;
10986 }
10987
Xiaojun Sanga4648082018-04-27 14:57:33 +080010988 mutex_lock(&session[session_id].mutex_lock_per_session);
10989 if (!q6asm_is_valid_audio_client(ac)) {
10990 rc = -EINVAL;
10991 goto free;
10992 }
10993
10994 if (ac->apr == NULL) {
10995 pr_err("%s: AC APR handle NULL\n", __func__);
10996 goto free;
10997 }
10998 if (ac->io_mode & NT_MODE) {
10999 pr_debug("%s: called for NT MODE, exiting\n", __func__);
11000 goto free;
11001 }
11002
11003 if (ac->perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) {
11004 rc = 0; /* no cal is required, not error case */
11005 goto free;
11006 }
11007
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053011008 /* asm_stream_cmd_set_pp_params_v2 has no APR header in it */
11009 q6asm_add_hdr_async(ac, &hdr, (sizeof(struct apr_hdr) +
11010 sizeof(struct asm_stream_cmd_set_pp_params_v2)), TRUE);
11011
11012 atomic_set(&ac->cmd_state_pp, -1);
11013 hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
11014 payload_params.data_payload_addr_lsw =
11015 lower_32_bits(cal_block->cal_data.paddr);
11016 payload_params.data_payload_addr_msw =
11017 msm_audio_populate_upper_32_bits(
11018 cal_block->cal_data.paddr);
11019 payload_params.mem_map_handle = cal_block->map_data.q6map_handle;
11020 payload_params.data_payload_size = cal_block->cal_data.size;
11021 memcpy(((u8 *)asm_params), &hdr, sizeof(struct apr_hdr));
11022 memcpy(((u8 *)asm_params + sizeof(struct apr_hdr)), &payload_params,
11023 sizeof(struct asm_stream_cmd_set_pp_params_v2));
11024
11025 pr_debug("%s: phyaddr lsw = %x msw = %x, maphdl = %x calsize = %d\n",
11026 __func__, payload_params.data_payload_addr_lsw,
11027 payload_params.data_payload_addr_msw,
11028 payload_params.mem_map_handle,
11029 payload_params.data_payload_size);
11030
11031 rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params);
11032 if (rc < 0) {
11033 pr_err("%s: audio audstrm cal send failed\n", __func__);
11034 rc = -EINVAL;
11035 goto free;
11036 }
11037 rc = wait_event_timeout(ac->cmd_wait,
11038 (atomic_read(&ac->cmd_state_pp) >= 0), 5 * HZ);
11039 if (!rc) {
11040 pr_err("%s: timeout, audio audstrm cal send\n", __func__);
11041 rc = -ETIMEDOUT;
11042 goto free;
11043 }
11044 if (atomic_read(&ac->cmd_state_pp) > 0) {
11045 pr_err("%s: DSP returned error[%d] audio audstrm cal send\n",
11046 __func__, atomic_read(&ac->cmd_state_pp));
11047 rc = -EINVAL;
11048 goto free;
11049 }
11050
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -070011051 if (cal_block)
11052 cal_utils_mark_cal_used(cal_block);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053011053 rc = 0;
11054
11055free:
Xiaojun Sanga4648082018-04-27 14:57:33 +080011056 mutex_unlock(&session[session_id].mutex_lock_per_session);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053011057 kfree(asm_params);
11058unlock:
11059 mutex_unlock(&cal_data[ASM_AUDSTRM_CAL]->lock);
11060done:
11061 return rc;
11062}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053011063EXPORT_SYMBOL(q6asm_send_cal);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053011064
11065static int get_cal_type_index(int32_t cal_type)
11066{
11067 int ret = -EINVAL;
11068
11069 switch (cal_type) {
11070 case ASM_TOPOLOGY_CAL_TYPE:
11071 ret = ASM_TOPOLOGY_CAL;
11072 break;
11073 case ASM_CUST_TOPOLOGY_CAL_TYPE:
11074 ret = ASM_CUSTOM_TOP_CAL;
11075 break;
11076 case ASM_AUDSTRM_CAL_TYPE:
11077 ret = ASM_AUDSTRM_CAL;
11078 break;
11079 case ASM_RTAC_APR_CAL_TYPE:
11080 ret = ASM_RTAC_APR_CAL;
11081 break;
11082 default:
11083 pr_err("%s: invalid cal type %d!\n", __func__, cal_type);
11084 }
11085 return ret;
11086}
11087
11088static int q6asm_alloc_cal(int32_t cal_type,
11089 size_t data_size, void *data)
11090{
11091 int ret = 0;
11092 int cal_index;
11093
11094 pr_debug("%s:\n", __func__);
11095
11096 cal_index = get_cal_type_index(cal_type);
11097 if (cal_index < 0) {
11098 pr_err("%s: could not get cal index %d!\n",
11099 __func__, cal_index);
11100 ret = -EINVAL;
11101 goto done;
11102 }
11103
11104 ret = cal_utils_alloc_cal(data_size, data,
11105 cal_data[cal_index], 0, NULL);
11106 if (ret < 0) {
11107 pr_err("%s: cal_utils_alloc_block failed, ret = %d, cal type = %d!\n",
11108 __func__, ret, cal_type);
11109 ret = -EINVAL;
11110 goto done;
11111 }
11112done:
11113 return ret;
11114}
11115
11116static int q6asm_dealloc_cal(int32_t cal_type,
11117 size_t data_size, void *data)
11118{
11119 int ret = 0;
11120 int cal_index;
11121
11122 pr_debug("%s:\n", __func__);
11123
11124 cal_index = get_cal_type_index(cal_type);
11125 if (cal_index < 0) {
11126 pr_err("%s: could not get cal index %d!\n",
11127 __func__, cal_index);
11128 ret = -EINVAL;
11129 goto done;
11130 }
11131
11132 ret = cal_utils_dealloc_cal(data_size, data,
11133 cal_data[cal_index]);
11134 if (ret < 0) {
11135 pr_err("%s: cal_utils_dealloc_block failed, ret = %d, cal type = %d!\n",
11136 __func__, ret, cal_type);
11137 ret = -EINVAL;
11138 goto done;
11139 }
11140done:
11141 return ret;
11142}
11143
11144static int q6asm_set_cal(int32_t cal_type,
11145 size_t data_size, void *data)
11146{
11147 int ret = 0;
11148 int cal_index;
11149
11150 pr_debug("%s:\n", __func__);
11151
11152 cal_index = get_cal_type_index(cal_type);
11153 if (cal_index < 0) {
11154 pr_err("%s: could not get cal index %d!\n",
11155 __func__, cal_index);
11156 ret = -EINVAL;
11157 goto done;
11158 }
11159
11160 ret = cal_utils_set_cal(data_size, data,
11161 cal_data[cal_index], 0, NULL);
11162 if (ret < 0) {
11163 pr_err("%s: cal_utils_set_cal failed, ret = %d, cal type = %d!\n",
11164 __func__, ret, cal_type);
11165 ret = -EINVAL;
11166 goto done;
11167 }
11168
11169 if (cal_index == ASM_CUSTOM_TOP_CAL) {
11170 mutex_lock(&cal_data[ASM_CUSTOM_TOP_CAL]->lock);
11171 set_custom_topology = 1;
11172 mutex_unlock(&cal_data[ASM_CUSTOM_TOP_CAL]->lock);
11173 }
11174done:
11175 return ret;
11176}
11177
11178static void q6asm_delete_cal_data(void)
11179{
11180 pr_debug("%s:\n", __func__);
11181 cal_utils_destroy_cal_types(ASM_MAX_CAL_TYPES, cal_data);
11182}
11183
11184static int q6asm_init_cal_data(void)
11185{
11186 int ret = 0;
11187 struct cal_type_info cal_type_info[] = {
11188 {{ASM_TOPOLOGY_CAL_TYPE,
11189 {NULL, NULL, NULL,
11190 q6asm_set_cal, NULL, NULL} },
11191 {NULL, NULL, cal_utils_match_buf_num} },
11192
11193 {{ASM_CUST_TOPOLOGY_CAL_TYPE,
11194 {q6asm_alloc_cal, q6asm_dealloc_cal, NULL,
11195 q6asm_set_cal, NULL, NULL} },
11196 {NULL, q6asm_unmap_cal_memory, cal_utils_match_buf_num} },
11197
11198 {{ASM_AUDSTRM_CAL_TYPE,
11199 {q6asm_alloc_cal, q6asm_dealloc_cal, NULL,
11200 q6asm_set_cal, NULL, NULL} },
11201 {NULL, q6asm_unmap_cal_memory, cal_utils_match_buf_num} },
11202
11203 {{ASM_RTAC_APR_CAL_TYPE,
11204 {NULL, NULL, NULL, NULL, NULL, NULL} },
11205 {NULL, NULL, cal_utils_match_buf_num} }
11206 };
11207 pr_debug("%s\n", __func__);
11208
11209 ret = cal_utils_create_cal_types(ASM_MAX_CAL_TYPES, cal_data,
11210 cal_type_info);
11211 if (ret < 0) {
11212 pr_err("%s: could not create cal type! %d\n",
11213 __func__, ret);
11214 ret = -EINVAL;
11215 goto err;
11216 }
11217
11218 return ret;
11219err:
11220 q6asm_delete_cal_data();
11221 return ret;
11222}
11223
11224static int q6asm_is_valid_session(struct apr_client_data *data, void *priv)
11225{
11226 struct audio_client *ac = (struct audio_client *)priv;
11227 union asm_token_struct asm_token;
11228
11229 asm_token.token = data->token;
11230 if (asm_token._token.session_id != ac->session) {
11231 pr_err("%s: Invalid session[%d] rxed expected[%d]",
11232 __func__, asm_token._token.session_id, ac->session);
11233 return -EINVAL;
11234 }
11235 return 0;
11236}
11237
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053011238int __init q6asm_init(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053011239{
11240 int lcnt, ret;
11241
11242 pr_debug("%s:\n", __func__);
11243
Meng Wang9730cdd2017-09-26 12:48:31 +080011244 memset(session, 0, sizeof(struct audio_session) *
11245 (ASM_ACTIVE_STREAMS_ALLOWED + 1));
Xiaojun Sanga4648082018-04-27 14:57:33 +080011246 for (lcnt = 0; lcnt <= ASM_ACTIVE_STREAMS_ALLOWED; lcnt++) {
Meng Wang9730cdd2017-09-26 12:48:31 +080011247 spin_lock_init(&(session[lcnt].session_lock));
Xiaojun Sanga4648082018-04-27 14:57:33 +080011248 mutex_init(&(session[lcnt].mutex_lock_per_session));
11249 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053011250 set_custom_topology = 1;
11251
11252 /*setup common client used for cal mem map */
11253 common_client.session = ASM_CONTROL_SESSION;
11254 common_client.port[0].buf = &common_buf[0];
11255 common_client.port[1].buf = &common_buf[1];
11256 init_waitqueue_head(&common_client.cmd_wait);
11257 init_waitqueue_head(&common_client.time_wait);
11258 init_waitqueue_head(&common_client.mem_wait);
11259 atomic_set(&common_client.time_flag, 1);
11260 INIT_LIST_HEAD(&common_client.port[0].mem_map_handle);
11261 INIT_LIST_HEAD(&common_client.port[1].mem_map_handle);
11262 mutex_init(&common_client.cmd_lock);
11263 for (lcnt = 0; lcnt <= OUT; lcnt++) {
11264 mutex_init(&common_client.port[lcnt].lock);
11265 spin_lock_init(&common_client.port[lcnt].dsp_lock);
11266 }
11267 atomic_set(&common_client.cmd_state, 0);
11268 atomic_set(&common_client.mem_state, 0);
11269
11270 ret = q6asm_init_cal_data();
11271 if (ret)
11272 pr_err("%s: could not init cal data! ret %d\n",
11273 __func__, ret);
11274
11275 config_debug_fs_init();
11276
11277 return 0;
11278}
11279
Asish Bhattacharya5faacb32017-12-04 17:23:15 +053011280void q6asm_exit(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053011281{
11282 q6asm_delete_cal_data();
11283}