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