blob: 95bb8edb9c1856cad286c8e87545c1688d348245 [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);
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -0700128static int q6asm_get_asm_topology_apptype(struct q6asm_cal_info *cal_info);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530129
130/* for ASM custom topology */
131static struct cal_type_data *cal_data[ASM_MAX_CAL_TYPES];
132static struct audio_buffer common_buf[2];
133static struct audio_client common_client;
134static int set_custom_topology;
135static int topology_map_handle;
136
137struct generic_get_data_ {
138 int valid;
139 int is_inband;
140 int size_in_ints;
141 int ints[];
142};
143static struct generic_get_data_ *generic_get_data;
144
145#ifdef CONFIG_DEBUG_FS
146#define OUT_BUFFER_SIZE 56
147#define IN_BUFFER_SIZE 24
148
149static struct timeval out_cold_tv;
150static struct timeval out_warm_tv;
151static struct timeval out_cont_tv;
152static struct timeval in_cont_tv;
153static long out_enable_flag;
154static long in_enable_flag;
155static struct dentry *out_dentry;
156static struct dentry *in_dentry;
157static int in_cont_index;
158/*This var is used to keep track of first write done for cold output latency */
159static int out_cold_index;
160static char *out_buffer;
161static char *in_buffer;
162
163static uint32_t adsp_reg_event_opcode[] = {
164 ASM_STREAM_CMD_REGISTER_PP_EVENTS,
165 ASM_STREAM_CMD_REGISTER_ENCDEC_EVENTS,
166 ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE };
167
168static uint32_t adsp_raise_event_opcode[] = {
169 ASM_STREAM_PP_EVENT,
170 ASM_STREAM_CMD_ENCDEC_EVENTS,
171 ASM_IEC_61937_MEDIA_FMT_EVENT };
172
173static int is_adsp_reg_event(uint32_t cmd)
174{
175 int i;
176
177 for (i = 0; i < ARRAY_SIZE(adsp_reg_event_opcode); i++) {
178 if (cmd == adsp_reg_event_opcode[i])
179 return i;
180 }
181 return -EINVAL;
182}
183
184static int is_adsp_raise_event(uint32_t cmd)
185{
186 int i;
187
188 for (i = 0; i < ARRAY_SIZE(adsp_raise_event_opcode); i++) {
189 if (cmd == adsp_raise_event_opcode[i])
190 return i;
191 }
192 return -EINVAL;
193}
194
195static inline void q6asm_set_flag_in_token(union asm_token_struct *asm_token,
196 int flag, int flag_offset)
197{
198 if (flag)
199 ASM_SET_BIT(asm_token->_token.flags, flag_offset);
200}
201
202static inline int q6asm_get_flag_from_token(union asm_token_struct *asm_token,
203 int flag_offset)
204{
205 return ASM_TEST_BIT(asm_token->_token.flags, flag_offset);
206}
207
208static inline void q6asm_update_token(u32 *token, u8 session_id, u8 stream_id,
209 u8 buf_index, u8 dir, u8 nowait_flag)
210{
211 union asm_token_struct asm_token;
212
213 asm_token.token = 0;
214 asm_token._token.session_id = session_id;
215 asm_token._token.stream_id = stream_id;
216 asm_token._token.buf_index = buf_index;
217 q6asm_set_flag_in_token(&asm_token, dir, ASM_DIRECTION_OFFSET);
218 q6asm_set_flag_in_token(&asm_token, nowait_flag,
219 ASM_CMD_NO_WAIT_OFFSET);
220 *token = asm_token.token;
221}
222
223static inline uint32_t q6asm_get_pcm_format_id(uint32_t media_format_block_ver)
224{
225 uint32_t pcm_format_id;
226
227 switch (media_format_block_ver) {
228 case PCM_MEDIA_FORMAT_V4:
229 pcm_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V4;
230 break;
231 case PCM_MEDIA_FORMAT_V3:
232 pcm_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3;
233 break;
234 case PCM_MEDIA_FORMAT_V2:
235 default:
236 pcm_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
237 break;
238 }
239 return pcm_format_id;
240}
241
242/*
243 * q6asm_get_buf_index_from_token:
244 * Retrieve buffer index from token.
245 *
246 * @token: token value sent to ASM service on q6.
247 * Returns buffer index in the read/write commands.
248 */
249uint8_t q6asm_get_buf_index_from_token(uint32_t token)
250{
251 union asm_token_struct asm_token;
252
253 asm_token.token = token;
254 return asm_token._token.buf_index;
255}
256EXPORT_SYMBOL(q6asm_get_buf_index_from_token);
257
258/*
259 * q6asm_get_stream_id_from_token:
260 * Retrieve stream id from token.
261 *
262 * @token: token value sent to ASM service on q6.
263 * Returns stream id.
264 */
265uint8_t q6asm_get_stream_id_from_token(uint32_t token)
266{
267 union asm_token_struct asm_token;
268
269 asm_token.token = token;
270 return asm_token._token.stream_id;
271}
272EXPORT_SYMBOL(q6asm_get_stream_id_from_token);
273
274static int audio_output_latency_dbgfs_open(struct inode *inode,
275 struct file *file)
276{
277 file->private_data = inode->i_private;
278 return 0;
279}
280static ssize_t audio_output_latency_dbgfs_read(struct file *file,
281 char __user *buf, size_t count, loff_t *ppos)
282{
283 if (out_buffer == NULL) {
284 pr_err("%s: out_buffer is null\n", __func__);
285 return 0;
286 }
Karthikeyan Mani1dfff342018-02-15 17:46:25 -0800287 if (count < OUT_BUFFER_SIZE) {
288 pr_err("%s: read size %d exceeds buf size %zd\n", __func__,
289 OUT_BUFFER_SIZE, count);
290 return 0;
291 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530292 snprintf(out_buffer, OUT_BUFFER_SIZE, "%ld,%ld,%ld,%ld,%ld,%ld,",
293 out_cold_tv.tv_sec, out_cold_tv.tv_usec, out_warm_tv.tv_sec,
294 out_warm_tv.tv_usec, out_cont_tv.tv_sec, out_cont_tv.tv_usec);
295 return simple_read_from_buffer(buf, OUT_BUFFER_SIZE, ppos,
296 out_buffer, OUT_BUFFER_SIZE);
297}
298static ssize_t audio_output_latency_dbgfs_write(struct file *file,
299 const char __user *buf, size_t count, loff_t *ppos)
300{
301 char *temp;
302
303 if (count > 2*sizeof(char)) {
304 pr_err("%s: err count is more %zd\n", __func__, count);
305 return -EINVAL;
306 }
307 temp = kmalloc(2*sizeof(char), GFP_KERNEL);
308
309 out_cold_index = 0;
310
311 if (temp) {
312 if (copy_from_user(temp, buf, 2*sizeof(char))) {
313 pr_err("%s: copy from user failed for size %zd\n",
314 __func__, 2*sizeof(char));
315 kfree(temp);
316 return -EFAULT;
317 }
318 if (!kstrtol(temp, 10, &out_enable_flag)) {
319 kfree(temp);
320 return count;
321 }
322 kfree(temp);
323 }
324 return -EINVAL;
325}
326static const struct file_operations audio_output_latency_debug_fops = {
327 .open = audio_output_latency_dbgfs_open,
328 .read = audio_output_latency_dbgfs_read,
329 .write = audio_output_latency_dbgfs_write
330};
331static int audio_input_latency_dbgfs_open(struct inode *inode,
332 struct file *file)
333{
334 file->private_data = inode->i_private;
335 return 0;
336}
337static ssize_t audio_input_latency_dbgfs_read(struct file *file,
338 char __user *buf, size_t count, loff_t *ppos)
339{
340 if (in_buffer == NULL) {
341 pr_err("%s: in_buffer is null\n", __func__);
342 return 0;
343 }
Karthikeyan Mani1dfff342018-02-15 17:46:25 -0800344 if (count < IN_BUFFER_SIZE) {
345 pr_err("%s: read size %d exceeds buf size %zd\n", __func__,
346 IN_BUFFER_SIZE, count);
347 return 0;
348 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530349 snprintf(in_buffer, IN_BUFFER_SIZE, "%ld,%ld,",
350 in_cont_tv.tv_sec, in_cont_tv.tv_usec);
351 return simple_read_from_buffer(buf, IN_BUFFER_SIZE, ppos,
352 in_buffer, IN_BUFFER_SIZE);
353}
354static ssize_t audio_input_latency_dbgfs_write(struct file *file,
355 const char __user *buf, size_t count, loff_t *ppos)
356{
357 char *temp;
358
359 if (count > 2*sizeof(char)) {
360 pr_err("%s: err count is more %zd\n", __func__, count);
361 return -EINVAL;
362 }
363 temp = kmalloc(2*sizeof(char), GFP_KERNEL);
364
365 if (temp) {
366 if (copy_from_user(temp, buf, 2*sizeof(char))) {
367 pr_err("%s: copy from user failed for size %zd\n",
368 __func__, 2*sizeof(char));
369 kfree(temp);
370 return -EFAULT;
371 }
372 if (!kstrtol(temp, 10, &in_enable_flag)) {
373 kfree(temp);
374 return count;
375 }
376 kfree(temp);
377 }
378 return -EINVAL;
379}
380static const struct file_operations audio_input_latency_debug_fops = {
381 .open = audio_input_latency_dbgfs_open,
382 .read = audio_input_latency_dbgfs_read,
383 .write = audio_input_latency_dbgfs_write
384};
385
386static void config_debug_fs_write_cb(void)
387{
388 if (out_enable_flag) {
389 /* For first Write done log the time and reset
390 * out_cold_index
391 */
392 if (out_cold_index != 1) {
393 do_gettimeofday(&out_cold_tv);
394 pr_debug("COLD: apr_send_pkt at %ld sec %ld microsec\n",
395 out_cold_tv.tv_sec,
396 out_cold_tv.tv_usec);
397 out_cold_index = 1;
398 }
399 pr_debug("%s: out_enable_flag %ld\n",
400 __func__, out_enable_flag);
401 }
402}
403static void config_debug_fs_read_cb(void)
404{
405 if (in_enable_flag) {
406 /* when in_cont_index == 7, DSP would be
407 * writing into the 8th 512 byte buffer and this
408 * timestamp is tapped here.Once done it then writes
409 * to 9th 512 byte buffer.These two buffers(8th, 9th)
410 * reach the test application in 5th iteration and that
411 * timestamp is tapped at user level. The difference
412 * of these two timestamps gives us the time between
413 * the time at which dsp started filling the sample
414 * required and when it reached the test application.
415 * Hence continuous input latency
416 */
417 if (in_cont_index == 7) {
418 do_gettimeofday(&in_cont_tv);
419 pr_info("%s: read buffer at %ld sec %ld microsec\n",
420 __func__,
421 in_cont_tv.tv_sec, in_cont_tv.tv_usec);
422 }
423 in_cont_index++;
424 }
425}
426
427static void config_debug_fs_reset_index(void)
428{
429 in_cont_index = 0;
430}
431
432static void config_debug_fs_run(void)
433{
434 if (out_enable_flag) {
435 do_gettimeofday(&out_cold_tv);
436 pr_debug("%s: COLD apr_send_pkt at %ld sec %ld microsec\n",
437 __func__, out_cold_tv.tv_sec, out_cold_tv.tv_usec);
438 }
439}
440
441static void config_debug_fs_write(struct audio_buffer *ab)
442{
443 if (out_enable_flag) {
444 char zero_pattern[2] = {0x00, 0x00};
445 /* If First two byte is non zero and last two byte
446 * is zero then it is warm output pattern
447 */
448 if ((strcmp(((char *)ab->data), zero_pattern)) &&
449 (!strcmp(((char *)ab->data + 2), zero_pattern))) {
450 do_gettimeofday(&out_warm_tv);
451 pr_debug("%s: WARM:apr_send_pkt at %ld sec %ld microsec\n",
452 __func__,
453 out_warm_tv.tv_sec,
454 out_warm_tv.tv_usec);
455 pr_debug("%s: Warm Pattern Matched\n", __func__);
456 }
457 /* If First two byte is zero and last two byte is
458 * non zero then it is cont output pattern
459 */
460 else if ((!strcmp(((char *)ab->data), zero_pattern))
461 && (strcmp(((char *)ab->data + 2), zero_pattern))) {
462 do_gettimeofday(&out_cont_tv);
463 pr_debug("%s: CONT:apr_send_pkt at %ld sec %ld microsec\n",
464 __func__,
465 out_cont_tv.tv_sec,
466 out_cont_tv.tv_usec);
467 pr_debug("%s: Cont Pattern Matched\n", __func__);
468 }
469 }
470}
471static void config_debug_fs_init(void)
472{
473 out_buffer = kzalloc(OUT_BUFFER_SIZE, GFP_KERNEL);
474 if (out_buffer == NULL)
475 goto outbuf_fail;
476
477 in_buffer = kzalloc(IN_BUFFER_SIZE, GFP_KERNEL);
478 if (in_buffer == NULL)
479 goto inbuf_fail;
480
481 out_dentry = debugfs_create_file("audio_out_latency_measurement_node",
482 0664,
483 NULL, NULL, &audio_output_latency_debug_fops);
484 if (IS_ERR(out_dentry)) {
485 pr_err("%s: debugfs_create_file failed\n", __func__);
486 goto file_fail;
487 }
488 in_dentry = debugfs_create_file("audio_in_latency_measurement_node",
489 0664,
490 NULL, NULL, &audio_input_latency_debug_fops);
491 if (IS_ERR(in_dentry)) {
492 pr_err("%s: debugfs_create_file failed\n", __func__);
493 goto file_fail;
494 }
495 return;
496file_fail:
497 kfree(in_buffer);
498inbuf_fail:
499 kfree(out_buffer);
500outbuf_fail:
501 in_buffer = NULL;
502 out_buffer = NULL;
503}
504#else
505static void config_debug_fs_write(struct audio_buffer *ab)
506{
507}
508static void config_debug_fs_run(void)
509{
510}
511static void config_debug_fs_reset_index(void)
512{
513}
514static void config_debug_fs_read_cb(void)
515{
516}
517static void config_debug_fs_write_cb(void)
518{
519}
520static void config_debug_fs_init(void)
521{
522}
523#endif
524
525int q6asm_mmap_apr_dereg(void)
526{
527 int c;
528
529 c = atomic_sub_return(1, &this_mmap.ref_cnt);
530 if (c == 0) {
531 apr_deregister(this_mmap.apr);
532 common_client.mmap_apr = NULL;
533 pr_debug("%s: APR De-Register common port\n", __func__);
534 } else if (c < 0) {
535 pr_err("%s: APR Common Port Already Closed %d\n",
536 __func__, c);
537 atomic_set(&this_mmap.ref_cnt, 0);
538 }
539
540 return 0;
541}
542
543static int q6asm_session_alloc(struct audio_client *ac)
544{
545 int n;
546
547 for (n = 1; n <= ASM_ACTIVE_STREAMS_ALLOWED; n++) {
Meng Wang9730cdd2017-09-26 12:48:31 +0800548 if (!(session[n].ac)) {
549 session[n].ac = ac;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530550 return n;
551 }
552 }
553 pr_err("%s: session not available\n", __func__);
554 return -ENOMEM;
555}
556
Meng Wang9730cdd2017-09-26 12:48:31 +0800557static int q6asm_get_session_id_from_audio_client(struct audio_client *ac)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530558{
559 int n;
560
561 for (n = 1; n <= ASM_ACTIVE_STREAMS_ALLOWED; n++) {
Meng Wang9730cdd2017-09-26 12:48:31 +0800562 if (session[n].ac == ac)
563 return n;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530564 }
Xiaojun Sanga4648082018-04-27 14:57:33 +0800565 pr_debug("%s: cannot find matching audio client. ac = %pK\n",
566 __func__, ac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530567 return 0;
568}
569
Meng Wang9730cdd2017-09-26 12:48:31 +0800570static bool q6asm_is_valid_audio_client(struct audio_client *ac)
571{
572 return q6asm_get_session_id_from_audio_client(ac) ? 1 : 0;
573}
574
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530575static void q6asm_session_free(struct audio_client *ac)
576{
Meng Wang9730cdd2017-09-26 12:48:31 +0800577 int session_id;
Vignesh Kulothungan023a5322018-06-21 11:13:29 -0700578 unsigned long flags = 0;
Meng Wang9730cdd2017-09-26 12:48:31 +0800579
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530580 pr_debug("%s: sessionid[%d]\n", __func__, ac->session);
Meng Wang9730cdd2017-09-26 12:48:31 +0800581 session_id = ac->session;
Xiaojun Sanga4648082018-04-27 14:57:33 +0800582 mutex_lock(&session[session_id].mutex_lock_per_session);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530583 rtac_remove_popp_from_adm_devices(ac->session);
Meng Wangb6afa8c2017-11-30 17:55:05 +0800584 spin_lock_irqsave(&(session[session_id].session_lock), flags);
Meng Wang9730cdd2017-09-26 12:48:31 +0800585 session[ac->session].ac = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530586 ac->session = 0;
587 ac->perf_mode = LEGACY_PCM_MODE;
588 ac->fptr_cache_ops = NULL;
Meng Wang9730cdd2017-09-26 12:48:31 +0800589 ac->cb = NULL;
590 ac->priv = NULL;
591 kfree(ac);
592 ac = NULL;
Meng Wangb6afa8c2017-11-30 17:55:05 +0800593 spin_unlock_irqrestore(&(session[session_id].session_lock), flags);
Xiaojun Sanga4648082018-04-27 14:57:33 +0800594 mutex_unlock(&session[session_id].mutex_lock_per_session);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530595}
596
597static uint32_t q6asm_get_next_buf(struct audio_client *ac,
598 uint32_t curr_buf, uint32_t max_buf_cnt)
599{
600 dev_vdbg(ac->dev, "%s: curr_buf = %d, max_buf_cnt = %d\n",
601 __func__, curr_buf, max_buf_cnt);
602 curr_buf += 1;
603 return (curr_buf >= max_buf_cnt) ? 0 : curr_buf;
604}
605
606static int q6asm_map_cal_memory(int32_t cal_type,
607 struct cal_block_data *cal_block)
608{
609 int result = 0;
610 struct asm_buffer_node *buf_node = NULL;
611 struct list_head *ptr, *next;
612
613 if (cal_block == NULL) {
614 pr_err("%s: cal_block is NULL!\n",
615 __func__);
616 goto done;
617 }
618
619 if (cal_block->cal_data.paddr == 0) {
620 pr_debug("%s: No address to map!\n",
621 __func__);
622 goto done;
623 }
624
625 common_client.mmap_apr = q6asm_mmap_apr_reg();
626 if (common_client.mmap_apr == NULL) {
627 pr_err("%s: q6asm_mmap_apr_reg failed\n",
628 __func__);
629 result = -EPERM;
630 goto done;
631 }
632 common_client.apr = common_client.mmap_apr;
633 if (cal_block->map_data.map_size == 0) {
634 pr_debug("%s: map size is 0!\n",
635 __func__);
636 goto done;
637 }
638
639 /* Use second asm buf to map memory */
640 if (common_client.port[IN].buf == NULL) {
641 pr_err("%s: common buf is NULL\n",
642 __func__);
643 result = -EINVAL;
644 goto done;
645 }
646
647 common_client.port[IN].buf->phys = cal_block->cal_data.paddr;
648
649 result = q6asm_memory_map_regions(&common_client,
650 IN, cal_block->map_data.map_size, 1, 1);
651 if (result < 0) {
652 pr_err("%s: mmap did not work! size = %zd result %d\n",
653 __func__,
654 cal_block->map_data.map_size, result);
655 pr_debug("%s: mmap did not work! addr = 0x%pK, size = %zd\n",
656 __func__,
657 &cal_block->cal_data.paddr,
658 cal_block->map_data.map_size);
659 goto done;
660 }
661
662 list_for_each_safe(ptr, next,
663 &common_client.port[IN].mem_map_handle) {
664 buf_node = list_entry(ptr, struct asm_buffer_node,
665 list);
666 if (buf_node->buf_phys_addr == cal_block->cal_data.paddr) {
667 cal_block->map_data.q6map_handle = buf_node->mmap_hdl;
668 break;
669 }
670 }
671done:
672 return result;
673}
674
675static int remap_cal_data(int32_t cal_type, struct cal_block_data *cal_block)
676{
677 int ret = 0;
678
679 if (cal_block->map_data.ion_client == NULL) {
680 pr_err("%s: No ION allocation for cal type %d!\n",
681 __func__, cal_type);
682 ret = -EINVAL;
683 goto done;
684 }
685
686 if ((cal_block->map_data.map_size > 0) &&
687 (cal_block->map_data.q6map_handle == 0)) {
688
689 ret = q6asm_map_cal_memory(cal_type, cal_block);
690 if (ret < 0) {
691 pr_err("%s: mmap did not work! size = %zd ret %d\n",
692 __func__, cal_block->map_data.map_size, ret);
693 goto done;
694 }
695 }
696done:
697 return ret;
698}
699
700static int q6asm_unmap_cal_memory(int32_t cal_type,
701 struct cal_block_data *cal_block)
702{
703 int result = 0;
704 int result2 = 0;
705
706 if (cal_block == NULL) {
707 pr_err("%s: cal_block is NULL!\n",
708 __func__);
709 result = -EINVAL;
710 goto done;
711 }
712
713 if (cal_block->map_data.q6map_handle == 0) {
714 pr_debug("%s: No address to unmap!\n",
715 __func__);
716 result = -EINVAL;
717 goto done;
718 }
719
720 if (common_client.mmap_apr == NULL) {
721 common_client.mmap_apr = q6asm_mmap_apr_reg();
722 if (common_client.mmap_apr == NULL) {
723 pr_err("%s: q6asm_mmap_apr_reg failed\n",
724 __func__);
725 result = -EPERM;
726 goto done;
727 }
728 }
729
730 result2 = q6asm_memory_unmap_regions(&common_client, IN);
731 if (result2 < 0) {
732 pr_err("%s: unmap failed, err %d\n",
733 __func__, result2);
734 result = result2;
735 }
736
737 cal_block->map_data.q6map_handle = 0;
738done:
739 return result;
740}
741
742int q6asm_unmap_cal_data(int cal_type, struct cal_block_data *cal_block)
743{
744 int ret = 0;
745
746 if ((cal_block->map_data.map_size > 0) &&
747 (cal_block->map_data.q6map_handle != 0)) {
748
749 ret = q6asm_unmap_cal_memory(cal_type, cal_block);
750 if (ret < 0) {
751 pr_err("%s: unmap did not work! size = %zd ret %d\n",
752 __func__, cal_block->map_data.map_size, ret);
753 goto done;
754 }
755 }
756done:
757 return ret;
758}
759
760int send_asm_custom_topology(struct audio_client *ac)
761{
762 struct cal_block_data *cal_block = NULL;
763 struct cmd_set_topologies asm_top;
764 int result = 0;
765 int result1 = 0;
766
767 if (cal_data[ASM_CUSTOM_TOP_CAL] == NULL)
768 goto done;
769
770 mutex_lock(&cal_data[ASM_CUSTOM_TOP_CAL]->lock);
771 if (!set_custom_topology)
772 goto unlock;
773 set_custom_topology = 0;
774
775 cal_block = cal_utils_get_only_cal_block(cal_data[ASM_CUSTOM_TOP_CAL]);
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -0700776 if (cal_block == NULL || cal_utils_is_cal_stale(cal_block))
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530777 goto unlock;
778
779 if (cal_block->cal_data.size == 0) {
780 pr_debug("%s: No cal to send!\n", __func__);
781 goto unlock;
782 }
783
784 pr_debug("%s: Sending cal_index %d\n", __func__, ASM_CUSTOM_TOP_CAL);
785
786 result = remap_cal_data(ASM_CUST_TOPOLOGY_CAL_TYPE, cal_block);
787 if (result) {
788 pr_err("%s: Remap_cal_data failed for cal %d!\n",
789 __func__, ASM_CUSTOM_TOP_CAL);
790 goto unlock;
791 }
792
793 q6asm_add_hdr_custom_topology(ac, &asm_top.hdr, sizeof(asm_top));
794 atomic_set(&ac->mem_state, -1);
795 asm_top.hdr.opcode = ASM_CMD_ADD_TOPOLOGIES;
796 asm_top.payload_addr_lsw = lower_32_bits(cal_block->cal_data.paddr);
797 asm_top.payload_addr_msw = msm_audio_populate_upper_32_bits(
798 cal_block->cal_data.paddr);
799 asm_top.mem_map_handle = cal_block->map_data.q6map_handle;
800 asm_top.payload_size = cal_block->cal_data.size;
801
802 pr_debug("%s: Sending ASM_CMD_ADD_TOPOLOGIES payload = %pK, size = %d, map handle = 0x%x\n",
803 __func__, &cal_block->cal_data.paddr,
804 asm_top.payload_size, asm_top.mem_map_handle);
805
806 result = apr_send_pkt(ac->apr, (uint32_t *) &asm_top);
807 if (result < 0) {
808 pr_err("%s: Set topologies failed result %d\n",
809 __func__, result);
810 pr_debug("%s: Set topologies failed payload = 0x%pK\n",
811 __func__, &cal_block->cal_data.paddr);
812 goto unmap;
813
814 }
815
816 result = wait_event_timeout(ac->mem_wait,
817 (atomic_read(&ac->mem_state) >= 0), 5*HZ);
818 if (!result) {
819 pr_err("%s: Set topologies failed timeout\n", __func__);
820 pr_debug("%s: Set topologies failed after timedout payload = 0x%pK\n",
821 __func__, &cal_block->cal_data.paddr);
822 result = -ETIMEDOUT;
823 goto unmap;
824 }
825 if (atomic_read(&ac->mem_state) > 0) {
826 pr_err("%s: DSP returned error[%s]\n",
827 __func__, adsp_err_get_err_str(
828 atomic_read(&ac->mem_state)));
829 result = adsp_err_get_lnx_err_code(
830 atomic_read(&ac->mem_state));
831 goto unmap;
832 }
833
834unmap:
835 result1 = q6asm_unmap_cal_memory(ASM_CUST_TOPOLOGY_CAL_TYPE,
836 cal_block);
837 if (result1 < 0) {
838 result = result1;
839 pr_debug("%s: unmap cal failed! %d\n", __func__, result);
840 }
841unlock:
842 mutex_unlock(&cal_data[ASM_CUSTOM_TOP_CAL]->lock);
843done:
844 return result;
845}
846
847int q6asm_map_rtac_block(struct rtac_cal_block_data *cal_block)
848{
849 int result = 0;
850 struct asm_buffer_node *buf_node = NULL;
851 struct list_head *ptr, *next;
852
853 pr_debug("%s:\n", __func__);
854
855 if (cal_block == NULL) {
856 pr_err("%s: cal_block is NULL!\n",
857 __func__);
858 result = -EINVAL;
859 goto done;
860 }
861
862 if (cal_block->cal_data.paddr == 0) {
863 pr_debug("%s: No address to map!\n",
864 __func__);
865 result = -EINVAL;
866 goto done;
867 }
868
869 if (common_client.mmap_apr == NULL) {
870 common_client.mmap_apr = q6asm_mmap_apr_reg();
871 if (common_client.mmap_apr == NULL) {
872 pr_err("%s: q6asm_mmap_apr_reg failed\n",
873 __func__);
874 result = -EPERM;
875 goto done;
876 }
877 }
878
879 if (cal_block->map_data.map_size == 0) {
880 pr_debug("%s: map size is 0!\n",
881 __func__);
882 result = -EINVAL;
883 goto done;
884 }
885
886 /* Use second asm buf to map memory */
887 if (common_client.port[OUT].buf == NULL) {
888 pr_err("%s: common buf is NULL\n",
889 __func__);
890 result = -EINVAL;
891 goto done;
892 }
893
894 common_client.port[OUT].buf->phys = cal_block->cal_data.paddr;
895
896 result = q6asm_memory_map_regions(&common_client,
897 OUT, cal_block->map_data.map_size, 1, 1);
898 if (result < 0) {
899 pr_err("%s: mmap did not work! size = %d result %d\n",
900 __func__,
901 cal_block->map_data.map_size, result);
902 pr_debug("%s: mmap did not work! addr = 0x%pK, size = %d\n",
903 __func__,
904 &cal_block->cal_data.paddr,
905 cal_block->map_data.map_size);
906 goto done;
907 }
908
909 list_for_each_safe(ptr, next,
910 &common_client.port[OUT].mem_map_handle) {
911 buf_node = list_entry(ptr, struct asm_buffer_node,
912 list);
913 if (buf_node->buf_phys_addr == cal_block->cal_data.paddr) {
914 cal_block->map_data.map_handle = buf_node->mmap_hdl;
915 break;
916 }
917 }
918done:
919 return result;
920}
921
922int q6asm_unmap_rtac_block(uint32_t *mem_map_handle)
923{
924 int result = 0;
925 int result2 = 0;
926
927 pr_debug("%s:\n", __func__);
928
929 if (mem_map_handle == NULL) {
930 pr_debug("%s: Map handle is NULL, nothing to unmap\n",
931 __func__);
932 goto done;
933 }
934
935 if (*mem_map_handle == 0) {
936 pr_debug("%s: Map handle is 0, nothing to unmap\n",
937 __func__);
938 goto done;
939 }
940
941 if (common_client.mmap_apr == NULL) {
942 common_client.mmap_apr = q6asm_mmap_apr_reg();
943 if (common_client.mmap_apr == NULL) {
944 pr_err("%s: q6asm_mmap_apr_reg failed\n",
945 __func__);
946 result = -EPERM;
947 goto done;
948 }
949 }
950
951
952 result2 = q6asm_memory_unmap_regions(&common_client, OUT);
953 if (result2 < 0) {
954 pr_err("%s: unmap failed, err %d\n",
955 __func__, result2);
956 result = result2;
957 } else {
Aditya Bavanari271b0c92018-06-18 11:59:09 +0530958 *mem_map_handle = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530959 }
960
961 result2 = q6asm_mmap_apr_dereg();
962 if (result2 < 0) {
963 pr_err("%s: q6asm_mmap_apr_dereg failed, err %d\n",
964 __func__, result2);
965 result = result2;
966 }
967done:
968 return result;
969}
970
971int q6asm_audio_client_buf_free(unsigned int dir,
972 struct audio_client *ac)
973{
974 struct audio_port_data *port;
975 int cnt = 0;
976 int rc = 0;
977
978 pr_debug("%s: Session id %d\n", __func__, ac->session);
979 mutex_lock(&ac->cmd_lock);
980 if (ac->io_mode & SYNC_IO_MODE) {
981 port = &ac->port[dir];
982 if (!port->buf) {
983 pr_err("%s: buf NULL\n", __func__);
984 mutex_unlock(&ac->cmd_lock);
985 return 0;
986 }
987 cnt = port->max_buf_cnt - 1;
988
989 if (cnt >= 0) {
990 rc = q6asm_memory_unmap_regions(ac, dir);
991 if (rc < 0)
992 pr_err("%s: Memory_unmap_regions failed %d\n",
993 __func__, rc);
994 }
995
996 while (cnt >= 0) {
997 if (port->buf[cnt].data) {
998 if (!rc || atomic_read(&ac->reset))
999 msm_audio_ion_free(
1000 port->buf[cnt].client,
1001 port->buf[cnt].handle);
1002
1003 port->buf[cnt].client = NULL;
1004 port->buf[cnt].handle = NULL;
1005 port->buf[cnt].data = NULL;
1006 port->buf[cnt].phys = 0;
1007 --(port->max_buf_cnt);
1008 }
1009 --cnt;
1010 }
1011 kfree(port->buf);
1012 port->buf = NULL;
1013 }
1014 mutex_unlock(&ac->cmd_lock);
1015 return 0;
1016}
1017
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301018/**
1019 * q6asm_audio_client_buf_free_contiguous -
1020 * frees the memory buffers for ASM
1021 *
1022 * @dir: RX or TX direction
1023 * @ac: audio client handle
1024 *
1025 * Returns 0 on success or error on failure
1026 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301027int q6asm_audio_client_buf_free_contiguous(unsigned int dir,
1028 struct audio_client *ac)
1029{
1030 struct audio_port_data *port;
1031 int cnt = 0;
1032 int rc = 0;
1033
1034 pr_debug("%s: Session id %d\n", __func__, ac->session);
1035 mutex_lock(&ac->cmd_lock);
1036 port = &ac->port[dir];
1037 if (!port->buf) {
1038 mutex_unlock(&ac->cmd_lock);
1039 return 0;
1040 }
1041 cnt = port->max_buf_cnt - 1;
1042
1043 if (cnt >= 0) {
1044 rc = q6asm_memory_unmap(ac, port->buf[0].phys, dir);
1045 if (rc < 0)
1046 pr_err("%s: Memory_unmap_regions failed %d\n",
1047 __func__, rc);
1048 }
1049
1050 if (port->buf[0].data) {
1051 pr_debug("%s: data[%pK]phys[%pK][%pK] , client[%pK] handle[%pK]\n",
1052 __func__,
1053 port->buf[0].data,
1054 &port->buf[0].phys,
1055 &port->buf[0].phys,
1056 port->buf[0].client,
1057 port->buf[0].handle);
1058 if (!rc || atomic_read(&ac->reset))
1059 msm_audio_ion_free(port->buf[0].client,
1060 port->buf[0].handle);
1061 port->buf[0].client = NULL;
1062 port->buf[0].handle = NULL;
1063 }
1064
1065 while (cnt >= 0) {
1066 port->buf[cnt].data = NULL;
1067 port->buf[cnt].phys = 0;
1068 cnt--;
1069 }
1070 port->max_buf_cnt = 0;
1071 kfree(port->buf);
1072 port->buf = NULL;
1073 mutex_unlock(&ac->cmd_lock);
1074 return 0;
1075}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301076EXPORT_SYMBOL(q6asm_audio_client_buf_free_contiguous);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301077
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301078/**
1079 * q6asm_audio_client_free -
1080 * frees the audio client for ASM
1081 *
1082 * @ac: audio client handle
1083 *
1084 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301085void q6asm_audio_client_free(struct audio_client *ac)
1086{
1087 int loopcnt;
1088 struct audio_port_data *port;
1089
1090 if (!ac) {
1091 pr_err("%s: ac %pK\n", __func__, ac);
1092 return;
1093 }
1094 if (!ac->session) {
1095 pr_err("%s: ac session invalid\n", __func__);
1096 return;
1097 }
1098
1099 mutex_lock(&session_lock);
1100
1101 pr_debug("%s: Session id %d\n", __func__, ac->session);
1102 if (ac->io_mode & SYNC_IO_MODE) {
1103 for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
1104 port = &ac->port[loopcnt];
1105 if (!port->buf)
1106 continue;
1107 pr_debug("%s: loopcnt = %d\n",
1108 __func__, loopcnt);
1109 q6asm_audio_client_buf_free(loopcnt, ac);
1110 }
1111 }
1112
1113 rtac_set_asm_handle(ac->session, NULL);
1114 apr_deregister(ac->apr2);
1115 apr_deregister(ac->apr);
1116 q6asm_mmap_apr_dereg();
1117 ac->apr2 = NULL;
1118 ac->apr = NULL;
1119 ac->mmap_apr = NULL;
1120 q6asm_session_free(ac);
1121
1122 pr_debug("%s: APR De-Register\n", __func__);
1123
1124/*done:*/
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301125 mutex_unlock(&session_lock);
1126}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301127EXPORT_SYMBOL(q6asm_audio_client_free);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301128
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301129/**
1130 * q6asm_set_io_mode -
1131 * Update IO mode for ASM
1132 *
1133 * @ac: audio client handle
1134 * @mode1: IO mode to update
1135 *
1136 * Returns 0 on success or error on failure
1137 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301138int q6asm_set_io_mode(struct audio_client *ac, uint32_t mode1)
1139{
1140 uint32_t mode;
1141 int ret = 0;
1142
1143 if (ac == NULL) {
1144 pr_err("%s: APR handle NULL\n", __func__);
1145 return -EINVAL;
1146 }
1147
1148 ac->io_mode &= 0xFF00;
1149 mode = (mode1 & 0xF);
1150
1151 pr_debug("%s: ac->mode after anding with FF00:0x%x,\n",
1152 __func__, ac->io_mode);
1153
1154 if ((mode == ASYNC_IO_MODE) || (mode == SYNC_IO_MODE)) {
1155 ac->io_mode |= mode1;
1156 pr_debug("%s: Set Mode to 0x%x\n", __func__, ac->io_mode);
1157 } else {
1158 pr_err("%s: Not an valid IO Mode:%d\n", __func__, ac->io_mode);
1159 ret = -EINVAL;
1160 }
1161
1162 return ret;
1163}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301164EXPORT_SYMBOL(q6asm_set_io_mode);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301165
1166void *q6asm_mmap_apr_reg(void)
1167{
1168 if ((atomic_read(&this_mmap.ref_cnt) == 0) ||
1169 (this_mmap.apr == NULL)) {
1170 this_mmap.apr = apr_register("ADSP", "ASM",
1171 (apr_fn)q6asm_srvc_callback,
1172 0x0FFFFFFFF, &this_mmap);
1173 if (this_mmap.apr == NULL) {
1174 pr_debug("%s: Unable to register APR ASM common port\n",
1175 __func__);
1176 goto fail;
1177 }
1178 }
1179 atomic_inc(&this_mmap.ref_cnt);
1180
1181 return this_mmap.apr;
1182fail:
1183 return NULL;
1184}
1185
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301186/**
1187 * q6asm_send_stream_cmd -
1188 * command to send for ASM stream
1189 *
1190 * @ac: audio client handle
1191 * @data: event data
1192 *
1193 * Returns 0 on success or error on failure
1194 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301195int q6asm_send_stream_cmd(struct audio_client *ac,
1196 struct msm_adsp_event_data *data)
1197{
1198 char *asm_params = NULL;
1199 struct apr_hdr hdr;
Xiaojun Sanga4648082018-04-27 14:57:33 +08001200 int rc, session_id = 0;
Aditya Bavanari2e3341d2018-02-23 12:58:57 +05301201 uint32_t sz = 0;
1202 uint64_t actual_sz = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301203
1204 if (!data || !ac) {
1205 pr_err("%s: %s is NULL\n", __func__,
1206 (!data) ? "data" : "ac");
1207 rc = -EINVAL;
1208 goto done;
1209 }
1210
Xiaojun Sanga4648082018-04-27 14:57:33 +08001211 session_id = q6asm_get_session_id_from_audio_client(ac);
1212 if (!session_id) {
1213 rc = -EINVAL;
1214 goto done;
1215 }
1216
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301217 if (data->event_type >= ARRAY_SIZE(adsp_reg_event_opcode)) {
1218 pr_err("%s: event %u out of boundary of array size of (%lu)\n",
1219 __func__, data->event_type,
1220 (long)ARRAY_SIZE(adsp_reg_event_opcode));
1221 rc = -EINVAL;
1222 goto done;
1223 }
1224
Aditya Bavanari2e3341d2018-02-23 12:58:57 +05301225 actual_sz = sizeof(struct apr_hdr) + data->payload_len;
1226 if (actual_sz > U32_MAX) {
1227 pr_err("%s: payload size 0x%X exceeds limit\n",
1228 __func__, data->payload_len);
1229 rc = -EINVAL;
1230 goto done;
1231 }
1232
1233 sz = (uint32_t)actual_sz;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301234 asm_params = kzalloc(sz, GFP_KERNEL);
1235 if (!asm_params) {
1236 rc = -ENOMEM;
1237 goto done;
1238 }
1239
Xiaojun Sanga4648082018-04-27 14:57:33 +08001240 mutex_lock(&session[session_id].mutex_lock_per_session);
1241 if (!q6asm_is_valid_audio_client(ac)) {
1242 rc = -EINVAL;
1243 goto fail_send_param;
1244 }
1245
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301246 q6asm_add_hdr_async(ac, &hdr, sz, TRUE);
1247 atomic_set(&ac->cmd_state_pp, -1);
1248 hdr.opcode = adsp_reg_event_opcode[data->event_type];
1249 memcpy(asm_params, &hdr, sizeof(struct apr_hdr));
1250 memcpy(asm_params + sizeof(struct apr_hdr),
1251 data->payload, data->payload_len);
1252 rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params);
1253 if (rc < 0) {
1254 pr_err("%s: stream event cmd apr pkt failed\n", __func__);
1255 rc = -EINVAL;
1256 goto fail_send_param;
1257 }
1258
1259 rc = wait_event_timeout(ac->cmd_wait,
1260 (atomic_read(&ac->cmd_state_pp) >= 0), 1 * HZ);
1261 if (!rc) {
1262 pr_err("%s: timeout for stream event cmd resp\n", __func__);
1263 rc = -ETIMEDOUT;
1264 goto fail_send_param;
1265 }
1266
1267 if (atomic_read(&ac->cmd_state_pp) > 0) {
1268 pr_err("%s: DSP returned error[%s] for stream event cmd\n",
1269 __func__, adsp_err_get_err_str(
1270 atomic_read(&ac->cmd_state_pp)));
1271 rc = adsp_err_get_lnx_err_code(
1272 atomic_read(&ac->cmd_state_pp));
1273 goto fail_send_param;
1274 }
1275
1276 rc = 0;
1277fail_send_param:
Xiaojun Sanga4648082018-04-27 14:57:33 +08001278 mutex_unlock(&session[session_id].mutex_lock_per_session);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301279 kfree(asm_params);
1280done:
1281 return rc;
1282}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301283EXPORT_SYMBOL(q6asm_send_stream_cmd);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301284
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301285/**
1286 * q6asm_audio_client_alloc -
1287 * Alloc audio client for ASM
1288 *
1289 * @cb: callback fn
1290 * @priv: private data
1291 *
1292 * Returns ac pointer on success or NULL on failure
1293 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301294struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv)
1295{
1296 struct audio_client *ac;
1297 int n;
1298 int lcnt = 0;
1299 int rc = 0;
1300
1301 ac = kzalloc(sizeof(struct audio_client), GFP_KERNEL);
1302 if (!ac)
1303 return NULL;
1304
1305 mutex_lock(&session_lock);
1306 n = q6asm_session_alloc(ac);
1307 if (n <= 0) {
1308 pr_err("%s: ASM Session alloc fail n=%d\n", __func__, n);
1309 mutex_unlock(&session_lock);
Meng Wang9730cdd2017-09-26 12:48:31 +08001310 kfree(ac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301311 goto fail_session;
1312 }
1313 ac->session = n;
1314 ac->cb = cb;
1315 ac->path_delay = UINT_MAX;
1316 ac->priv = priv;
1317 ac->io_mode = SYNC_IO_MODE;
1318 ac->perf_mode = LEGACY_PCM_MODE;
1319 ac->fptr_cache_ops = NULL;
1320 /* DSP expects stream id from 1 */
1321 ac->stream_id = 1;
1322 ac->apr = apr_register("ADSP", "ASM",
1323 (apr_fn)q6asm_callback,
1324 ((ac->session) << 8 | 0x0001),
1325 ac);
1326
1327 if (ac->apr == NULL) {
1328 pr_err("%s: Registration with APR failed\n", __func__);
1329 mutex_unlock(&session_lock);
1330 goto fail_apr1;
1331 }
1332 ac->apr2 = apr_register("ADSP", "ASM",
1333 (apr_fn)q6asm_callback,
1334 ((ac->session) << 8 | 0x0002),
1335 ac);
1336
1337 if (ac->apr2 == NULL) {
1338 pr_err("%s: Registration with APR-2 failed\n", __func__);
1339 mutex_unlock(&session_lock);
1340 goto fail_apr2;
1341 }
1342
1343 rtac_set_asm_handle(n, ac->apr);
1344
1345 pr_debug("%s: Registering the common port with APR\n", __func__);
1346 ac->mmap_apr = q6asm_mmap_apr_reg();
1347 if (ac->mmap_apr == NULL) {
1348 mutex_unlock(&session_lock);
1349 goto fail_mmap;
1350 }
1351
1352 init_waitqueue_head(&ac->cmd_wait);
1353 init_waitqueue_head(&ac->time_wait);
1354 init_waitqueue_head(&ac->mem_wait);
1355 atomic_set(&ac->time_flag, 1);
1356 atomic_set(&ac->reset, 0);
1357 INIT_LIST_HEAD(&ac->port[0].mem_map_handle);
1358 INIT_LIST_HEAD(&ac->port[1].mem_map_handle);
1359 pr_debug("%s: mem_map_handle list init'ed\n", __func__);
1360 mutex_init(&ac->cmd_lock);
1361 for (lcnt = 0; lcnt <= OUT; lcnt++) {
1362 mutex_init(&ac->port[lcnt].lock);
1363 spin_lock_init(&ac->port[lcnt].dsp_lock);
1364 }
1365 atomic_set(&ac->cmd_state, 0);
1366 atomic_set(&ac->cmd_state_pp, 0);
1367 atomic_set(&ac->mem_state, 0);
1368
1369 rc = send_asm_custom_topology(ac);
1370 if (rc < 0) {
1371 mutex_unlock(&session_lock);
1372 goto fail_mmap;
1373 }
1374
1375 pr_debug("%s: session[%d]\n", __func__, ac->session);
1376
1377 mutex_unlock(&session_lock);
1378
1379 return ac;
1380fail_mmap:
1381 apr_deregister(ac->apr2);
1382fail_apr2:
1383 apr_deregister(ac->apr);
1384fail_apr1:
1385 q6asm_session_free(ac);
1386fail_session:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301387 return NULL;
1388}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301389EXPORT_SYMBOL(q6asm_audio_client_alloc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301390
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301391/**
1392 * q6asm_get_audio_client -
1393 * Retrieve audio client for ASM
1394 *
1395 * @session_id: ASM session id
1396 *
1397 * Returns valid pointer on success or NULL on failure
1398 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301399struct audio_client *q6asm_get_audio_client(int session_id)
1400{
1401 if (session_id == ASM_CONTROL_SESSION)
1402 return &common_client;
1403
1404 if ((session_id <= 0) || (session_id > ASM_ACTIVE_STREAMS_ALLOWED)) {
1405 pr_err("%s: invalid session: %d\n", __func__, session_id);
1406 goto err;
1407 }
1408
Meng Wang9730cdd2017-09-26 12:48:31 +08001409 if (!(session[session_id].ac)) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301410 pr_err("%s: session not active: %d\n", __func__, session_id);
1411 goto err;
1412 }
Meng Wang9730cdd2017-09-26 12:48:31 +08001413 return session[session_id].ac;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301414err:
1415 return NULL;
1416}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301417EXPORT_SYMBOL(q6asm_get_audio_client);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301418
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301419/**
1420 * q6asm_audio_client_buf_alloc -
1421 * Allocs memory from ION for ASM
1422 *
1423 * @dir: RX or TX direction
1424 * @ac: Audio client handle
1425 * @bufsz: size of each buffer
1426 * @bufcnt: number of buffers to alloc
1427 *
1428 * Returns 0 on success or error on failure
1429 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301430int q6asm_audio_client_buf_alloc(unsigned int dir,
1431 struct audio_client *ac,
1432 unsigned int bufsz,
1433 uint32_t bufcnt)
1434{
1435 int cnt = 0;
1436 int rc = 0;
1437 struct audio_buffer *buf;
1438 size_t len;
1439
1440 if (!(ac) || !(bufsz) || ((dir != IN) && (dir != OUT))) {
1441 pr_err("%s: ac %pK bufsz %d dir %d\n", __func__, ac, bufsz,
1442 dir);
1443 return -EINVAL;
1444 }
1445
1446 pr_debug("%s: session[%d]bufsz[%d]bufcnt[%d]\n", __func__, ac->session,
1447 bufsz, bufcnt);
1448
1449 if (ac->session <= 0 || ac->session > 8) {
1450 pr_err("%s: Session ID is invalid, session = %d\n", __func__,
1451 ac->session);
1452 goto fail;
1453 }
1454
1455 if (ac->io_mode & SYNC_IO_MODE) {
1456 if (ac->port[dir].buf) {
1457 pr_debug("%s: buffer already allocated\n", __func__);
1458 return 0;
1459 }
1460 mutex_lock(&ac->cmd_lock);
1461 if (bufcnt > (U32_MAX/sizeof(struct audio_buffer))) {
1462 pr_err("%s: Buffer size overflows", __func__);
1463 mutex_unlock(&ac->cmd_lock);
1464 goto fail;
1465 }
1466 buf = kzalloc(((sizeof(struct audio_buffer))*bufcnt),
1467 GFP_KERNEL);
1468
1469 if (!buf) {
1470 mutex_unlock(&ac->cmd_lock);
1471 goto fail;
1472 }
1473
1474 ac->port[dir].buf = buf;
1475
1476 while (cnt < bufcnt) {
1477 if (bufsz > 0) {
1478 if (!buf[cnt].data) {
1479 rc = msm_audio_ion_alloc("asm_client",
1480 &buf[cnt].client, &buf[cnt].handle,
1481 bufsz,
1482 (ion_phys_addr_t *)&buf[cnt].phys,
1483 &len,
1484 &buf[cnt].data);
1485 if (rc) {
1486 pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n",
1487 __func__, rc);
1488 mutex_unlock(&ac->cmd_lock);
1489 goto fail;
1490 }
1491
1492 buf[cnt].used = 1;
1493 buf[cnt].size = bufsz;
1494 buf[cnt].actual_size = bufsz;
1495 pr_debug("%s: data[%pK]phys[%pK][%pK]\n",
1496 __func__,
1497 buf[cnt].data,
1498 &buf[cnt].phys,
1499 &buf[cnt].phys);
1500 cnt++;
1501 }
1502 }
1503 }
1504 ac->port[dir].max_buf_cnt = cnt;
1505
1506 mutex_unlock(&ac->cmd_lock);
1507 rc = q6asm_memory_map_regions(ac, dir, bufsz, cnt, 0);
1508 if (rc < 0) {
1509 pr_err("%s: CMD Memory_map_regions failed %d for size %d\n",
1510 __func__, rc, bufsz);
1511 goto fail;
1512 }
1513 }
1514 return 0;
1515fail:
1516 q6asm_audio_client_buf_free(dir, ac);
1517 return -EINVAL;
1518}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301519EXPORT_SYMBOL(q6asm_audio_client_buf_alloc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301520
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301521/**
1522 * q6asm_audio_client_buf_alloc_contiguous -
1523 * Alloc contiguous memory from ION for ASM
1524 *
1525 * @dir: RX or TX direction
1526 * @ac: Audio client handle
1527 * @bufsz: size of each buffer
1528 * @bufcnt: number of buffers to alloc
1529 *
1530 * Returns 0 on success or error on failure
1531 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301532int q6asm_audio_client_buf_alloc_contiguous(unsigned int dir,
1533 struct audio_client *ac,
1534 unsigned int bufsz,
1535 unsigned int bufcnt)
1536{
1537 int cnt = 0;
1538 int rc = 0;
1539 struct audio_buffer *buf;
1540 size_t len;
1541 int bytes_to_alloc;
1542
1543 if (!(ac) || ((dir != IN) && (dir != OUT))) {
1544 pr_err("%s: ac %pK dir %d\n", __func__, ac, dir);
1545 return -EINVAL;
1546 }
1547
1548 pr_debug("%s: session[%d]bufsz[%d]bufcnt[%d]\n",
1549 __func__, ac->session,
1550 bufsz, bufcnt);
1551
1552 if (ac->session <= 0 || ac->session > 8) {
1553 pr_err("%s: Session ID is invalid, session = %d\n", __func__,
1554 ac->session);
1555 goto fail;
1556 }
1557
1558 if (ac->port[dir].buf) {
1559 pr_err("%s: buffer already allocated\n", __func__);
1560 return 0;
1561 }
Soumya Managoli70a195a2018-09-05 11:02:56 +05301562
1563 if (bufcnt == 0) {
1564 pr_err("%s: invalid buffer count\n", __func__);
1565 return -EINVAL;
1566 }
1567
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301568 mutex_lock(&ac->cmd_lock);
1569 buf = kzalloc(((sizeof(struct audio_buffer))*bufcnt),
1570 GFP_KERNEL);
1571
1572 if (!buf) {
1573 pr_err("%s: buffer allocation failed\n", __func__);
1574 mutex_unlock(&ac->cmd_lock);
1575 goto fail;
1576 }
1577
1578 ac->port[dir].buf = buf;
1579
1580 /* check for integer overflow */
1581 if ((bufcnt > 0) && ((INT_MAX / bufcnt) < bufsz)) {
1582 pr_err("%s: integer overflow\n", __func__);
1583 mutex_unlock(&ac->cmd_lock);
1584 goto fail;
1585 }
1586 bytes_to_alloc = bufsz * bufcnt;
1587
1588 /* The size to allocate should be multiple of 4K bytes */
1589 bytes_to_alloc = PAGE_ALIGN(bytes_to_alloc);
1590
1591 rc = msm_audio_ion_alloc("asm_client", &buf[0].client, &buf[0].handle,
1592 bytes_to_alloc,
1593 (ion_phys_addr_t *)&buf[0].phys, &len,
1594 &buf[0].data);
1595 if (rc) {
1596 pr_err("%s: Audio ION alloc is failed, rc = %d\n",
1597 __func__, rc);
1598 mutex_unlock(&ac->cmd_lock);
1599 goto fail;
1600 }
1601
1602 buf[0].used = dir ^ 1;
1603 buf[0].size = bufsz;
1604 buf[0].actual_size = bufsz;
1605 cnt = 1;
1606 while (cnt < bufcnt) {
1607 if (bufsz > 0) {
1608 buf[cnt].data = buf[0].data + (cnt * bufsz);
1609 buf[cnt].phys = buf[0].phys + (cnt * bufsz);
1610 if (!buf[cnt].data) {
1611 pr_err("%s: Buf alloc failed\n",
1612 __func__);
1613 mutex_unlock(&ac->cmd_lock);
1614 goto fail;
1615 }
1616 buf[cnt].used = dir ^ 1;
1617 buf[cnt].size = bufsz;
1618 buf[cnt].actual_size = bufsz;
1619 pr_debug("%s: data[%pK]phys[%pK][%pK]\n",
1620 __func__,
1621 buf[cnt].data,
1622 &buf[cnt].phys,
1623 &buf[cnt].phys);
1624 }
1625 cnt++;
1626 }
1627 ac->port[dir].max_buf_cnt = cnt;
1628 mutex_unlock(&ac->cmd_lock);
1629 rc = q6asm_memory_map_regions(ac, dir, bufsz, cnt, 1);
1630 if (rc < 0) {
1631 pr_err("%s: CMD Memory_map_regions failed %d for size %d\n",
1632 __func__, rc, bufsz);
1633 goto fail;
1634 }
1635 return 0;
1636fail:
1637 q6asm_audio_client_buf_free_contiguous(dir, ac);
1638 return -EINVAL;
1639}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301640EXPORT_SYMBOL(q6asm_audio_client_buf_alloc_contiguous);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301641
1642static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv)
1643{
1644 uint32_t dir = 0;
1645 uint32_t i = IN;
1646 uint32_t *payload;
Vignesh Kulothungan023a5322018-06-21 11:13:29 -07001647 unsigned long dsp_flags = 0;
Meng Wangb6afa8c2017-11-30 17:55:05 +08001648 unsigned long flags = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301649 struct asm_buffer_node *buf_node = NULL;
1650 struct list_head *ptr, *next;
1651 union asm_token_struct asm_token;
1652
1653 struct audio_client *ac = NULL;
1654 struct audio_port_data *port;
1655
Meng Wang9730cdd2017-09-26 12:48:31 +08001656 int session_id;
1657
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301658 if (!data) {
1659 pr_err("%s: Invalid CB\n", __func__);
1660 return 0;
1661 }
1662
1663 payload = data->payload;
1664
1665 if (data->opcode == RESET_EVENTS) {
1666 pr_debug("%s: Reset event is received: %d %d apr[%pK]\n",
1667 __func__,
1668 data->reset_event,
1669 data->reset_proc,
1670 this_mmap.apr);
1671 atomic_set(&this_mmap.ref_cnt, 0);
1672 apr_reset(this_mmap.apr);
1673 this_mmap.apr = NULL;
1674 for (; i <= OUT; i++) {
1675 list_for_each_safe(ptr, next,
1676 &common_client.port[i].mem_map_handle) {
1677 buf_node = list_entry(ptr,
1678 struct asm_buffer_node,
1679 list);
1680 if (buf_node->buf_phys_addr ==
1681 common_client.port[i].buf->phys) {
1682 list_del(&buf_node->list);
1683 kfree(buf_node);
1684 }
1685 }
1686 pr_debug("%s: Clearing custom topology\n", __func__);
1687 }
1688
1689 cal_utils_clear_cal_block_q6maps(ASM_MAX_CAL_TYPES, cal_data);
1690 common_client.mmap_apr = NULL;
1691 mutex_lock(&cal_data[ASM_CUSTOM_TOP_CAL]->lock);
1692 set_custom_topology = 1;
1693 mutex_unlock(&cal_data[ASM_CUSTOM_TOP_CAL]->lock);
1694 topology_map_handle = 0;
1695 rtac_clear_mapping(ASM_RTAC_CAL);
1696 return 0;
1697 }
1698 asm_token.token = data->token;
Meng Wang9730cdd2017-09-26 12:48:31 +08001699 session_id = asm_token._token.session_id;
1700
1701 if ((session_id > 0 && session_id <= ASM_ACTIVE_STREAMS_ALLOWED))
Meng Wangb6afa8c2017-11-30 17:55:05 +08001702 spin_lock_irqsave(&(session[session_id].session_lock), flags);
Meng Wang9730cdd2017-09-26 12:48:31 +08001703
1704 ac = q6asm_get_audio_client(session_id);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301705 dir = q6asm_get_flag_from_token(&asm_token, ASM_DIRECTION_OFFSET);
1706
1707 if (!ac) {
1708 pr_debug("%s: session[%d] already freed\n",
Meng Wang9730cdd2017-09-26 12:48:31 +08001709 __func__, session_id);
1710 if ((session_id > 0 &&
1711 session_id <= ASM_ACTIVE_STREAMS_ALLOWED))
Meng Wangb6afa8c2017-11-30 17:55:05 +08001712 spin_unlock_irqrestore(
1713 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301714 return 0;
1715 }
1716
Xiaojun Sang55ee5692019-02-15 16:26:16 +08001717 if (data->payload_size >= 2 * sizeof(uint32_t)) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301718 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",
1719 __func__, payload[0], payload[1], data->opcode,
1720 data->token, data->payload_size, data->src_port,
1721 data->dest_port, asm_token._token.session_id, dir);
1722 pr_debug("%s:Payload = [0x%x] status[0x%x]\n",
1723 __func__, payload[0], payload[1]);
Xiaojun Sang55ee5692019-02-15 16:26:16 +08001724 } else if (data->payload_size == sizeof(uint32_t)) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301725 pr_debug("%s:ptr0[0x%x]opcode[0x%x] token[0x%x]payload_s[%d] src[%d] dest[%d]sid[%d]dir[%d]\n",
1726 __func__, payload[0], data->opcode,
1727 data->token, data->payload_size, data->src_port,
1728 data->dest_port, asm_token._token.session_id, dir);
1729 pr_debug("%s:Payload = [0x%x]\n",
1730 __func__, payload[0]);
1731 }
1732
1733 if (data->opcode == APR_BASIC_RSP_RESULT) {
1734 switch (payload[0]) {
1735 case ASM_CMD_SHARED_MEM_MAP_REGIONS:
1736 case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:
1737 case ASM_CMD_ADD_TOPOLOGIES:
Xiaojun Sang55ee5692019-02-15 16:26:16 +08001738 if (data->payload_size >=
1739 2 * sizeof(uint32_t)
1740 && payload[1] != 0) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301741 pr_err("%s: cmd = 0x%x returned error = 0x%x sid:%d\n",
1742 __func__, payload[0], payload[1],
1743 asm_token._token.session_id);
1744 if (payload[0] ==
1745 ASM_CMD_SHARED_MEM_UNMAP_REGIONS)
1746 atomic_set(&ac->unmap_cb_success, 0);
1747
1748 atomic_set(&ac->mem_state, payload[1]);
1749 wake_up(&ac->mem_wait);
1750 } else {
1751 if (payload[0] ==
1752 ASM_CMD_SHARED_MEM_UNMAP_REGIONS)
1753 atomic_set(&ac->unmap_cb_success, 1);
1754 }
1755
1756 if (atomic_cmpxchg(&ac->mem_state, -1, 0) == -1)
1757 wake_up(&ac->mem_wait);
Xiaojun Sang55ee5692019-02-15 16:26:16 +08001758 if (data->payload_size >= 2 * sizeof(uint32_t))
1759 dev_vdbg(ac->dev, "%s: Payload = [0x%x] status[0x%x]\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301760 __func__, payload[0], payload[1]);
Xiaojun Sang55ee5692019-02-15 16:26:16 +08001761 else
1762 dev_vdbg(ac->dev, "%s: Payload size of %d is less than expected.\n",
1763 __func__, data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301764 break;
1765 default:
1766 pr_debug("%s: command[0x%x] not expecting rsp\n",
1767 __func__, payload[0]);
1768 break;
1769 }
Meng Wang9730cdd2017-09-26 12:48:31 +08001770 if ((session_id > 0 &&
1771 session_id <= ASM_ACTIVE_STREAMS_ALLOWED))
Meng Wangb6afa8c2017-11-30 17:55:05 +08001772 spin_unlock_irqrestore(
1773 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301774 return 0;
1775 }
1776
Soumya Managoli5ae26ba2019-11-06 15:37:08 +05301777 if (dir != IN && dir != OUT) {
1778 pr_err("%s: Invalid audio port index: %d\n", __func__, dir);
1779 if ((session_id > 0 && session_id <= SESSION_MAX))
1780 spin_unlock_irqrestore(
1781 &(session[session_id].session_lock), flags);
1782 return 0;
1783 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301784 port = &ac->port[dir];
1785
1786 switch (data->opcode) {
1787 case ASM_CMDRSP_SHARED_MEM_MAP_REGIONS:{
1788 pr_debug("%s:PL#0[0x%x] dir=0x%x s_id=0x%x\n",
1789 __func__, payload[0], dir, asm_token._token.session_id);
1790 spin_lock_irqsave(&port->dsp_lock, dsp_flags);
1791 if (atomic_cmpxchg(&ac->mem_state, -1, 0) == -1) {
1792 ac->port[dir].tmp_hdl = payload[0];
1793 wake_up(&ac->mem_wait);
1794 }
1795 spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
1796 break;
1797 }
1798 case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:{
Xiaojun Sang55ee5692019-02-15 16:26:16 +08001799 if (data->payload_size >= 2 * sizeof(uint32_t))
1800 pr_debug("%s: PL#0[0x%x]PL#1 [0x%x]\n",
1801 __func__, payload[0], payload[1]);
1802 else
1803 pr_debug("%s: Payload size of %d is less than expected.\n",
1804 __func__, data->payload_size);
1805
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301806 spin_lock_irqsave(&port->dsp_lock, dsp_flags);
1807 if (atomic_cmpxchg(&ac->mem_state, -1, 0) == -1)
1808 wake_up(&ac->mem_wait);
1809 spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
1810
1811 break;
1812 }
1813 default:
Xiaojun Sang55ee5692019-02-15 16:26:16 +08001814 if (data->payload_size >= 2 * sizeof(uint32_t))
1815 pr_debug("%s: command[0x%x]success [0x%x]\n",
1816 __func__, payload[0], payload[1]);
1817 else
1818 pr_debug("%s: Payload size of %d is less than expected.\n",
1819 __func__, data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301820 }
1821 if (ac->cb)
1822 ac->cb(data->opcode, data->token,
1823 data->payload, ac->priv);
Meng Wang9730cdd2017-09-26 12:48:31 +08001824 if ((session_id > 0 && session_id <= ASM_ACTIVE_STREAMS_ALLOWED))
Meng Wangb6afa8c2017-11-30 17:55:05 +08001825 spin_unlock_irqrestore(
1826 &(session[session_id].session_lock), flags);
Meng Wang9730cdd2017-09-26 12:48:31 +08001827
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301828 return 0;
1829}
1830
1831static void q6asm_process_mtmx_get_param_rsp(struct audio_client *ac,
1832 struct asm_mtmx_strtr_get_params_cmdrsp *cmdrsp)
1833{
1834 struct asm_session_mtmx_strtr_param_session_time_v3_t *time;
1835
1836 if (cmdrsp->err_code) {
1837 dev_err_ratelimited(ac->dev,
1838 "%s: err=%x, mod_id=%x, param_id=%x\n",
1839 __func__, cmdrsp->err_code,
1840 cmdrsp->param_info.module_id,
1841 cmdrsp->param_info.param_id);
1842 return;
1843 }
1844 dev_dbg_ratelimited(ac->dev,
1845 "%s: mod_id=%x, param_id=%x\n", __func__,
1846 cmdrsp->param_info.module_id,
1847 cmdrsp->param_info.param_id);
1848
1849 switch (cmdrsp->param_info.module_id) {
1850 case ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC:
1851 switch (cmdrsp->param_info.param_id) {
1852 case ASM_SESSION_MTMX_STRTR_PARAM_SESSION_TIME_V3:
1853 time = &cmdrsp->param_data.session_time;
1854 dev_vdbg(ac->dev, "%s: GET_TIME_V3, time_lsw=%x, time_msw=%x\n",
1855 __func__, time->session_time_lsw,
1856 time->session_time_msw);
1857 ac->time_stamp = (uint64_t)(((uint64_t)
1858 time->session_time_msw << 32) |
1859 time->session_time_lsw);
1860 if (time->flags &
1861 ASM_SESSION_MTMX_STRTR_PARAM_STIME_TSTMP_FLG_BMASK)
1862 dev_warn_ratelimited(ac->dev,
1863 "%s: recv inval tstmp\n",
1864 __func__);
1865 if (atomic_cmpxchg(&ac->time_flag, 1, 0))
1866 wake_up(&ac->time_wait);
1867
1868 break;
1869 default:
1870 dev_err(ac->dev, "%s: unexpected param_id %x\n",
1871 __func__, cmdrsp->param_info.param_id);
1872 break;
1873 }
1874 break;
1875 default:
1876 dev_err(ac->dev, "%s: unexpected mod_id %x\n", __func__,
1877 cmdrsp->param_info.module_id);
1878 break;
1879 }
1880}
1881
1882static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
1883{
1884 int i = 0;
1885 struct audio_client *ac = (struct audio_client *)priv;
Vignesh Kulothungan023a5322018-06-21 11:13:29 -07001886 unsigned long dsp_flags = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301887 uint32_t *payload;
1888 uint32_t wakeup_flag = 1;
1889 int32_t ret = 0;
1890 union asm_token_struct asm_token;
1891 uint8_t buf_index;
1892 struct msm_adsp_event_data *pp_event_package = NULL;
1893 uint32_t payload_size = 0;
Vignesh Kulothungan023a5322018-06-21 11:13:29 -07001894 unsigned long flags = 0;
Meng Wang9730cdd2017-09-26 12:48:31 +08001895 int session_id;
1896
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301897 if (ac == NULL) {
1898 pr_err("%s: ac NULL\n", __func__);
1899 return -EINVAL;
1900 }
1901 if (data == NULL) {
1902 pr_err("%s: data NULL\n", __func__);
1903 return -EINVAL;
1904 }
Meng Wang9730cdd2017-09-26 12:48:31 +08001905
1906 session_id = q6asm_get_session_id_from_audio_client(ac);
1907 if (session_id <= 0 || session_id > ASM_ACTIVE_STREAMS_ALLOWED) {
1908 pr_err("%s: Session ID is invalid, session = %d\n", __func__,
1909 session_id);
1910 return -EINVAL;
1911 }
Meng Wangb6afa8c2017-11-30 17:55:05 +08001912 spin_lock_irqsave(&(session[session_id].session_lock), flags);
Meng Wang9730cdd2017-09-26 12:48:31 +08001913
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301914 if (!q6asm_is_valid_audio_client(ac)) {
1915 pr_err("%s: audio client pointer is invalid, ac = %pK\n",
1916 __func__, ac);
Meng Wangb6afa8c2017-11-30 17:55:05 +08001917 spin_unlock_irqrestore(
1918 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301919 return -EINVAL;
1920 }
1921
1922 payload = data->payload;
1923 asm_token.token = data->token;
1924 if (q6asm_get_flag_from_token(&asm_token, ASM_CMD_NO_WAIT_OFFSET)) {
1925 pr_debug("%s: No wait command opcode[0x%x] cmd_opcode:%x\n",
1926 __func__, data->opcode, payload ? payload[0] : 0);
1927 wakeup_flag = 0;
1928 }
1929
1930 if (data->opcode == RESET_EVENTS) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301931 atomic_set(&ac->reset, 1);
1932 if (ac->apr == NULL) {
1933 ac->apr = ac->apr2;
1934 ac->apr2 = NULL;
1935 }
1936 pr_debug("%s: Reset event is received: %d %d apr[%pK]\n",
1937 __func__,
1938 data->reset_event, data->reset_proc, ac->apr);
1939 if (ac->cb)
1940 ac->cb(data->opcode, data->token,
1941 (uint32_t *)data->payload, ac->priv);
1942 apr_reset(ac->apr);
1943 ac->apr = NULL;
1944 atomic_set(&ac->time_flag, 0);
1945 atomic_set(&ac->cmd_state, 0);
1946 atomic_set(&ac->mem_state, 0);
1947 atomic_set(&ac->cmd_state_pp, 0);
1948 wake_up(&ac->time_wait);
1949 wake_up(&ac->cmd_wait);
1950 wake_up(&ac->mem_wait);
Meng Wangb6afa8c2017-11-30 17:55:05 +08001951 spin_unlock_irqrestore(
1952 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301953 return 0;
1954 }
1955
1956 dev_vdbg(ac->dev, "%s: session[%d]opcode[0x%x] token[0x%x]payload_size[%d] src[%d] dest[%d]\n",
1957 __func__,
1958 ac->session, data->opcode,
1959 data->token, data->payload_size, data->src_port,
1960 data->dest_port);
1961 if ((data->opcode != ASM_DATA_EVENT_RENDERED_EOS) &&
1962 (data->opcode != ASM_DATA_EVENT_EOS) &&
Vignesh Kulothunganb79df2f2019-01-22 10:31:21 -08001963 (data->opcode != ASM_SESSION_EVENTX_OVERFLOW) &&
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301964 (data->opcode != ASM_SESSION_EVENT_RX_UNDERFLOW)) {
1965 if (payload == NULL) {
1966 pr_err("%s: payload is null\n", __func__);
Meng Wangb6afa8c2017-11-30 17:55:05 +08001967 spin_unlock_irqrestore(
1968 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301969 return -EINVAL;
1970 }
Xiaojun Sang55ee5692019-02-15 16:26:16 +08001971 if (data->payload_size >=
1972 2 * sizeof(uint32_t))
1973 dev_vdbg(ac->dev, "%s: Payload = [0x%x] status[0x%x] opcode 0x%x\n",
1974 __func__, payload[0], payload[1], data->opcode);
1975 else
1976 dev_vdbg(ac->dev, "%s: Payload size of %d is less than expected.\n",
1977 __func__, data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301978 }
1979 if (data->opcode == APR_BASIC_RSP_RESULT) {
1980 switch (payload[0]) {
1981 case ASM_STREAM_CMD_SET_PP_PARAMS_V2:
1982 if (rtac_make_asm_callback(ac->session, payload,
1983 data->payload_size))
1984 break;
1985 case ASM_SESSION_CMD_PAUSE:
1986 case ASM_SESSION_CMD_SUSPEND:
1987 case ASM_DATA_CMD_EOS:
1988 case ASM_STREAM_CMD_CLOSE:
1989 case ASM_STREAM_CMD_FLUSH:
1990 case ASM_SESSION_CMD_RUN_V2:
1991 case ASM_SESSION_CMD_REGISTER_FORX_OVERFLOW_EVENTS:
1992 case ASM_STREAM_CMD_FLUSH_READBUFS:
1993 pr_debug("%s: session %d opcode 0x%x token 0x%x Payload = [0x%x] src %d dest %d\n",
1994 __func__, ac->session, data->opcode, data->token,
1995 payload[0], data->src_port, data->dest_port);
1996 ret = q6asm_is_valid_session(data, priv);
1997 if (ret != 0) {
1998 pr_err("%s: session invalid %d\n", __func__, ret);
Meng Wangb6afa8c2017-11-30 17:55:05 +08001999 spin_unlock_irqrestore(
2000 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302001 return ret;
2002 }
2003 case ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2:
2004 case ASM_STREAM_CMD_OPEN_READ_V3:
2005 case ASM_STREAM_CMD_OPEN_WRITE_V3:
2006 case ASM_STREAM_CMD_OPEN_PULL_MODE_WRITE:
2007 case ASM_STREAM_CMD_OPEN_PUSH_MODE_READ:
2008 case ASM_STREAM_CMD_OPEN_READWRITE_V2:
2009 case ASM_STREAM_CMD_OPEN_LOOPBACK_V2:
2010 case ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK:
2011 case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
2012 case ASM_DATA_CMD_IEC_60958_MEDIA_FMT:
2013 case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
2014 case ASM_STREAM_CMD_SET_ENCDEC_PARAM_V2:
2015 case ASM_STREAM_CMD_REGISTER_ENCDEC_EVENTS:
2016 case ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE:
2017 case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE:
2018 case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE:
2019 case ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS:
2020 case ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED:
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002021 if (data->payload_size >=
2022 2 * sizeof(uint32_t) &&
2023 payload[1] != 0) {
2024 pr_debug("%s: session %d opcode 0x%x token 0x%x Payload = [0x%x] stat 0x%x src %d dest %d\n",
2025 __func__, ac->session,
2026 data->opcode, data->token,
2027 payload[0], payload[1],
2028 data->src_port, data->dest_port);
2029 pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302030 __func__, payload[0], payload[1]);
2031 if (wakeup_flag) {
2032 if ((is_adsp_reg_event(payload[0]) >= 0)
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002033 || (payload[0] ==
2034 ASM_STREAM_CMD_SET_PP_PARAMS_V2))
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302035 atomic_set(&ac->cmd_state_pp,
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002036 payload[1]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302037 else
2038 atomic_set(&ac->cmd_state,
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002039 payload[1]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302040 wake_up(&ac->cmd_wait);
2041 }
Meng Wangb6afa8c2017-11-30 17:55:05 +08002042 spin_unlock_irqrestore(
2043 &(session[session_id].session_lock),
2044 flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302045 return 0;
2046 }
2047 if ((is_adsp_reg_event(payload[0]) >= 0) ||
2048 (payload[0] == ASM_STREAM_CMD_SET_PP_PARAMS_V2)) {
2049 if (atomic_read(&ac->cmd_state_pp) &&
2050 wakeup_flag) {
2051 atomic_set(&ac->cmd_state_pp, 0);
2052 wake_up(&ac->cmd_wait);
2053 }
2054 } else {
2055 if (atomic_read(&ac->cmd_state) &&
2056 wakeup_flag) {
2057 atomic_set(&ac->cmd_state, 0);
2058 wake_up(&ac->cmd_wait);
2059 }
2060 }
2061 if (ac->cb)
2062 ac->cb(data->opcode, data->token,
2063 (uint32_t *)data->payload, ac->priv);
2064 break;
2065 case ASM_CMD_ADD_TOPOLOGIES:
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002066 if (data->payload_size >=
2067 2 * sizeof(uint32_t) &&
2068 payload[1] != 0) {
2069 pr_debug("%s:Payload = [0x%x]stat[0x%x]\n",
2070 __func__, payload[0], payload[1]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302071 pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
2072 __func__, payload[0], payload[1]);
2073 if (wakeup_flag) {
2074 atomic_set(&ac->mem_state, payload[1]);
2075 wake_up(&ac->mem_wait);
2076 }
Meng Wangb6afa8c2017-11-30 17:55:05 +08002077 spin_unlock_irqrestore(
2078 &(session[session_id].session_lock),
2079 flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302080 return 0;
2081 }
2082 if (atomic_read(&ac->mem_state) && wakeup_flag) {
2083 atomic_set(&ac->mem_state, 0);
2084 wake_up(&ac->mem_wait);
2085 }
2086 if (ac->cb)
2087 ac->cb(data->opcode, data->token,
2088 (uint32_t *)data->payload, ac->priv);
2089 break;
2090 case ASM_DATA_EVENT_WATERMARK: {
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002091 if (data->payload_size >= 2 * sizeof(uint32_t))
2092 pr_debug("%s: Watermark opcode[0x%x] status[0x%x]",
2093 __func__, payload[0], payload[1]);
2094 else
2095 pr_err("%s: payload size of %x is less than expected.\n",
2096 __func__, data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302097 break;
2098 }
2099 case ASM_STREAM_CMD_GET_PP_PARAMS_V2:
2100 pr_debug("%s: ASM_STREAM_CMD_GET_PP_PARAMS_V2 session %d opcode 0x%x token 0x%x src %d dest %d\n",
2101 __func__, ac->session,
2102 data->opcode, data->token,
2103 data->src_port, data->dest_port);
2104 /* Should only come here if there is an APR */
2105 /* error or malformed APR packet. Otherwise */
2106 /* response will be returned as */
2107 /* ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2 */
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002108 if (data->payload_size >= 2 * sizeof(uint32_t)) {
2109 if (payload[1] != 0) {
2110 pr_err("%s: ASM get param error = %d, resuming\n",
2111 __func__, payload[1]);
2112 rtac_make_asm_callback(ac->session,
2113 payload,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302114 data->payload_size);
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002115 }
2116 } else {
2117 pr_err("%s: payload size of %x is less than expected.\n",
2118 __func__, data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302119 }
2120 break;
2121 case ASM_STREAM_CMD_REGISTER_PP_EVENTS:
2122 pr_debug("%s: ASM_STREAM_CMD_REGISTER_PP_EVENTS session %d opcode 0x%x token 0x%x src %d dest %d\n",
2123 __func__, ac->session,
2124 data->opcode, data->token,
2125 data->src_port, data->dest_port);
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002126 if (data->payload_size >= 2 * sizeof(uint32_t)) {
2127 if (payload[1] != 0)
2128 pr_err("%s: ASM get param error = %d, resuming\n",
2129 __func__, payload[1]);
2130 atomic_set(&ac->cmd_state_pp, payload[1]);
2131 wake_up(&ac->cmd_wait);
2132 } else {
2133 pr_err("%s: payload size of %x is less than expected.\n",
2134 __func__, data->payload_size);
2135 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302136 break;
2137 default:
2138 pr_debug("%s: command[0x%x] not expecting rsp\n",
2139 __func__, payload[0]);
2140 break;
2141 }
Meng Wang9730cdd2017-09-26 12:48:31 +08002142
Meng Wangb6afa8c2017-11-30 17:55:05 +08002143 spin_unlock_irqrestore(
2144 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302145 return 0;
2146 }
2147
2148 switch (data->opcode) {
2149 case ASM_DATA_EVENT_WRITE_DONE_V2:{
2150 struct audio_port_data *port = &ac->port[IN];
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002151 if (data->payload_size >= 2 * sizeof(uint32_t))
2152 dev_vdbg(ac->dev, "%s: Rxed opcode[0x%x] status[0x%x] token[%d]",
2153 __func__, payload[0], payload[1],
2154 data->token);
2155 else
2156 dev_err(ac->dev, "%s: payload size of %x is less than expected.\n",
2157 __func__, data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302158 if (ac->io_mode & SYNC_IO_MODE) {
2159 if (port->buf == NULL) {
2160 pr_err("%s: Unexpected Write Done\n",
2161 __func__);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002162 spin_unlock_irqrestore(
2163 &(session[session_id].session_lock),
2164 flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302165 return -EINVAL;
2166 }
2167 spin_lock_irqsave(&port->dsp_lock, dsp_flags);
2168 buf_index = asm_token._token.buf_index;
Vignesh Kulothunganb79df2f2019-01-22 10:31:21 -08002169 if (buf_index < 0 || buf_index >= port->max_buf_cnt) {
2170 pr_debug("%s: Invalid buffer index %u\n",
2171 __func__, buf_index);
2172 spin_unlock_irqrestore(&port->dsp_lock,
2173 dsp_flags);
2174 spin_unlock_irqrestore(
2175 &(session[session_id].session_lock),
2176 flags);
2177 return -EINVAL;
2178 }
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002179 if (data->payload_size >= 2 * sizeof(uint32_t) &&
2180 (lower_32_bits(port->buf[buf_index].phys) !=
2181 payload[0] ||
2182 msm_audio_populate_upper_32_bits(
2183 port->buf[buf_index].phys) !=
2184 payload[1])) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302185 pr_debug("%s: Expected addr %pK\n",
2186 __func__, &port->buf[buf_index].phys);
2187 pr_err("%s: rxedl[0x%x] rxedu [0x%x]\n",
2188 __func__, payload[0], payload[1]);
2189 spin_unlock_irqrestore(&port->dsp_lock,
2190 dsp_flags);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002191 spin_unlock_irqrestore(
2192 &(session[session_id].session_lock),
2193 flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302194 return -EINVAL;
2195 }
2196 port->buf[buf_index].used = 1;
2197 spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
2198
2199 config_debug_fs_write_cb();
2200
2201 for (i = 0; i < port->max_buf_cnt; i++)
2202 dev_vdbg(ac->dev, "%s %d\n",
2203 __func__, port->buf[i].used);
2204
2205 }
2206 break;
2207 }
2208 case ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2:
2209 pr_debug("%s: ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2 session %d opcode 0x%x token 0x%x src %d dest %d\n",
2210 __func__, ac->session, data->opcode,
2211 data->token,
2212 data->src_port, data->dest_port);
2213 if (payload[0] != 0) {
2214 pr_err("%s: ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2 returned error = 0x%x\n",
2215 __func__, payload[0]);
2216 } else if (generic_get_data) {
2217 generic_get_data->valid = 1;
2218 if (generic_get_data->is_inband) {
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002219 if (data->payload_size >= 4 * sizeof(uint32_t))
2220 pr_debug("%s: payload[1] = 0x%x, payload[2]=0x%x, payload[3]=0x%x\n",
2221 __func__, payload[1],
2222 payload[2], payload[3]);
2223 else
2224 pr_err("%s: payload size of %x is less than expected.\n",
2225 __func__,
2226 data->payload_size);
2227
2228 if (data->payload_size >=
2229 (4 + (payload[3]>>2))
2230 * sizeof(uint32_t)) {
2231 generic_get_data->size_in_ints =
2232 payload[3]>>2;
2233 for (i = 0; i < payload[3]>>2; i++) {
2234 generic_get_data->ints[i] =
2235 payload[4+i];
2236 pr_debug("%s: ASM callback val %i = %i\n",
2237 __func__, i,
2238 payload[4+i]);
2239 }
2240 } else {
2241 pr_err("%s: payload size of %x is less than expected.\n",
2242 __func__,
2243 data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302244 }
2245 pr_debug("%s: callback size in ints = %i\n",
2246 __func__,
2247 generic_get_data->size_in_ints);
2248 }
2249 if (atomic_read(&ac->cmd_state) && wakeup_flag) {
2250 atomic_set(&ac->cmd_state, 0);
2251 wake_up(&ac->cmd_wait);
2252 }
2253 break;
2254 }
2255 rtac_make_asm_callback(ac->session, payload,
2256 data->payload_size);
2257 break;
2258 case ASM_DATA_EVENT_READ_DONE_V2:{
2259
2260 struct audio_port_data *port = &ac->port[OUT];
2261
2262 config_debug_fs_read_cb();
2263
2264 dev_vdbg(ac->dev, "%s: ReadDone: status=%d buff_add=0x%x act_size=%d offset=%d\n",
2265 __func__, payload[READDONE_IDX_STATUS],
2266 payload[READDONE_IDX_BUFADD_LSW],
2267 payload[READDONE_IDX_SIZE],
2268 payload[READDONE_IDX_OFFSET]);
2269
2270 dev_vdbg(ac->dev, "%s: ReadDone:msw_ts=%d lsw_ts=%d memmap_hdl=0x%x flags=%d id=%d num=%d\n",
2271 __func__, payload[READDONE_IDX_MSW_TS],
2272 payload[READDONE_IDX_LSW_TS],
2273 payload[READDONE_IDX_MEMMAP_HDL],
2274 payload[READDONE_IDX_FLAGS],
2275 payload[READDONE_IDX_SEQ_ID],
2276 payload[READDONE_IDX_NUMFRAMES]);
2277
2278 if (ac->io_mode & SYNC_IO_MODE) {
2279 if (port->buf == NULL) {
2280 pr_err("%s: Unexpected Write Done\n", __func__);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002281 spin_unlock_irqrestore(
2282 &(session[session_id].session_lock),
2283 flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302284 return -EINVAL;
2285 }
2286 spin_lock_irqsave(&port->dsp_lock, dsp_flags);
2287 buf_index = asm_token._token.buf_index;
Vignesh Kulothunganb79df2f2019-01-22 10:31:21 -08002288 if (buf_index < 0 || buf_index >= port->max_buf_cnt) {
2289 pr_debug("%s: Invalid buffer index %u\n",
2290 __func__, buf_index);
2291 spin_unlock_irqrestore(&port->dsp_lock,
2292 dsp_flags);
2293 spin_unlock_irqrestore(
2294 &(session[session_id].session_lock),
2295 flags);
2296 return -EINVAL;
2297 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302298 port->buf[buf_index].used = 0;
2299 if (lower_32_bits(port->buf[buf_index].phys) !=
2300 payload[READDONE_IDX_BUFADD_LSW] ||
2301 msm_audio_populate_upper_32_bits(
2302 port->buf[buf_index].phys) !=
2303 payload[READDONE_IDX_BUFADD_MSW]) {
2304 dev_vdbg(ac->dev, "%s: Expected addr %pK\n",
2305 __func__, &port->buf[buf_index].phys);
2306 pr_err("%s: rxedl[0x%x] rxedu[0x%x]\n",
2307 __func__,
2308 payload[READDONE_IDX_BUFADD_LSW],
2309 payload[READDONE_IDX_BUFADD_MSW]);
2310 spin_unlock_irqrestore(&port->dsp_lock,
2311 dsp_flags);
2312 break;
2313 }
2314 port->buf[buf_index].actual_size =
2315 payload[READDONE_IDX_SIZE];
2316 spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
2317 }
2318 break;
2319 }
2320 case ASM_DATA_EVENT_EOS:
2321 case ASM_DATA_EVENT_RENDERED_EOS:
2322 pr_debug("%s: EOS ACK received: rxed 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_EVENTX_OVERFLOW:
2328 pr_debug("%s: ASM_SESSION_EVENTX_OVERFLOW 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_EVENT_RX_UNDERFLOW:
2334 pr_debug("%s: ASM_SESSION_EVENT_RX_UNDERFLOW session %d opcode 0x%x token 0x%x src %d dest %d\n",
2335 __func__, ac->session,
2336 data->opcode, data->token,
2337 data->src_port, data->dest_port);
2338 break;
2339 case ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3:
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002340 if (data->payload_size >= 3 * sizeof(uint32_t)) {
2341 dev_vdbg(ac->dev, "%s: ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3, payload[0] = %d, payload[1] = %d, payload[2] = %d\n",
2342 __func__,
2343 payload[0], payload[1], payload[2]);
2344 ac->time_stamp =
2345 (uint64_t)(((uint64_t)payload[2] << 32) |
2346 payload[1]);
2347 } else {
2348 dev_err(ac->dev, "%s: payload size of %x is less than expected.n",
2349 __func__, data->payload_size);
2350 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302351 if (atomic_cmpxchg(&ac->time_flag, 1, 0))
2352 wake_up(&ac->time_wait);
2353 break;
2354 case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
2355 case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY:
2356 pr_debug("%s: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY session %d opcode 0x%x token 0x%x src %d dest %d\n",
2357 __func__, ac->session,
2358 data->opcode, data->token,
2359 data->src_port, data->dest_port);
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002360 if (data->payload_size >= 4 * sizeof(uint32_t))
2361 pr_debug("%s: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, payload[0] = %d, payload[1] = %d, payload[2] = %d, payload[3] = %d\n",
2362 __func__,
2363 payload[0], payload[1], payload[2],
2364 payload[3]);
2365 else
2366 pr_debug("%s: payload size of %x is less than expected.\n",
2367 __func__, data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302368 break;
2369 case ASM_SESSION_CMDRSP_GET_MTMX_STRTR_PARAMS_V2:
2370 q6asm_process_mtmx_get_param_rsp(ac, (void *) payload);
2371 break;
2372 case ASM_STREAM_PP_EVENT:
2373 case ASM_STREAM_CMD_ENCDEC_EVENTS:
2374 case ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE:
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002375 if (data->payload_size >= 2 * sizeof(uint32_t))
2376 pr_debug("%s: ASM_STREAM_EVENT payload[0][0x%x] payload[1][0x%x]",
2377 __func__, payload[0], payload[1]);
2378 else
2379 pr_debug("%s: payload size of %x is less than expected.\n",
2380 __func__, data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302381 i = is_adsp_raise_event(data->opcode);
Meng Wang9730cdd2017-09-26 12:48:31 +08002382 if (i < 0) {
Meng Wangb6afa8c2017-11-30 17:55:05 +08002383 spin_unlock_irqrestore(
2384 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302385 return 0;
Meng Wang9730cdd2017-09-26 12:48:31 +08002386 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302387
2388 /* repack payload for asm_stream_pp_event
2389 * package is composed of event type + size + actual payload
2390 */
2391 payload_size = data->payload_size;
Xiaojun Sangae3d8862018-03-23 08:57:33 +08002392 if (payload_size > UINT_MAX
2393 - sizeof(struct msm_adsp_event_data)) {
2394 pr_err("%s: payload size = %d exceeds limit.\n",
2395 __func__, payload_size);
2396 spin_unlock(&(session[session_id].session_lock));
2397 return -EINVAL;
2398 }
2399
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302400 pp_event_package = kzalloc(payload_size
2401 + sizeof(struct msm_adsp_event_data),
2402 GFP_ATOMIC);
Meng Wang9730cdd2017-09-26 12:48:31 +08002403 if (!pp_event_package) {
Meng Wangb6afa8c2017-11-30 17:55:05 +08002404 spin_unlock_irqrestore(
2405 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302406 return -ENOMEM;
Meng Wang9730cdd2017-09-26 12:48:31 +08002407 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302408
2409 pp_event_package->event_type = i;
2410 pp_event_package->payload_len = payload_size;
2411 memcpy((void *)pp_event_package->payload,
2412 data->payload, payload_size);
2413 ac->cb(data->opcode, data->token,
2414 (void *)pp_event_package, ac->priv);
2415 kfree(pp_event_package);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002416 spin_unlock_irqrestore(
2417 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302418 return 0;
2419 case ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2:
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002420 if (data->payload_size >= 3 * sizeof(uint32_t))
2421 pr_debug("%s: ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2 sesion %d status 0x%x msw %u lsw %u\n",
2422 __func__, ac->session, payload[0], payload[2],
2423 payload[1]);
2424 else
2425 pr_err("%s: payload size of %x is less than expected.\n",
2426 __func__, data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302427 wake_up(&ac->cmd_wait);
2428 break;
2429 case ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2:
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002430 if (data->payload_size >= 3 * sizeof(uint32_t))
2431 pr_debug("%s: ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2 session %d status 0x%x msw %u lsw %u\n",
2432 __func__, ac->session,
2433 payload[0], payload[2],
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302434 payload[1]);
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002435 else
2436 pr_err("%s: payload size of %x is less than expected.\n",
2437 __func__, data->payload_size);
2438 if (data->payload_size >= 2 * sizeof(uint32_t) &&
2439 payload[0] == 0) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302440 atomic_set(&ac->cmd_state, 0);
2441 /* ignore msw, as a delay that large shouldn't happen */
2442 ac->path_delay = payload[1];
2443 } else {
2444 atomic_set(&ac->cmd_state, payload[0]);
2445 ac->path_delay = UINT_MAX;
2446 }
2447 wake_up(&ac->cmd_wait);
2448 break;
2449 }
2450 if (ac->cb)
2451 ac->cb(data->opcode, data->token,
2452 data->payload, ac->priv);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002453 spin_unlock_irqrestore(
2454 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302455 return 0;
2456}
2457
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302458/**
2459 * q6asm_is_cpu_buf_avail -
2460 * retrieve next CPU buf avail
2461 *
2462 * @dir: RX or TX direction
2463 * @ac: Audio client handle
2464 * @size: size pointer to be updated with size of buffer
2465 * @index: index pointer to be updated with
2466 * CPU buffer index available
2467 *
2468 * Returns buffer pointer on success or NULL on failure
2469 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302470void *q6asm_is_cpu_buf_avail(int dir, struct audio_client *ac, uint32_t *size,
2471 uint32_t *index)
2472{
2473 void *data;
2474 unsigned char idx;
2475 struct audio_port_data *port;
2476
2477 if (!ac || ((dir != IN) && (dir != OUT))) {
2478 pr_err("%s: ac %pK dir %d\n", __func__, ac, dir);
2479 return NULL;
2480 }
2481
2482 if (ac->io_mode & SYNC_IO_MODE) {
2483 port = &ac->port[dir];
2484
2485 mutex_lock(&port->lock);
2486 idx = port->cpu_buf;
2487 if (port->buf == NULL) {
2488 pr_err("%s: Buffer pointer null\n", __func__);
2489 mutex_unlock(&port->lock);
2490 return NULL;
2491 }
2492 /* dir 0: used = 0 means buf in use
2493 * dir 1: used = 1 means buf in use
2494 */
2495 if (port->buf[idx].used == dir) {
2496 /* To make it more robust, we could loop and get the
2497 * next avail buf, its risky though
2498 */
2499 pr_err("%s: Next buf idx[0x%x] not available, dir[%d]\n",
2500 __func__, idx, dir);
2501 mutex_unlock(&port->lock);
2502 return NULL;
2503 }
2504 *size = port->buf[idx].actual_size;
2505 *index = port->cpu_buf;
2506 data = port->buf[idx].data;
2507 dev_vdbg(ac->dev, "%s: session[%d]index[%d] data[%pK]size[%d]\n",
2508 __func__,
2509 ac->session,
2510 port->cpu_buf,
2511 data, *size);
2512 /* By default increase the cpu_buf cnt
2513 * user accesses this function,increase cpu
2514 * buf(to avoid another api)
2515 */
2516 port->buf[idx].used = dir;
2517 port->cpu_buf = q6asm_get_next_buf(ac, port->cpu_buf,
2518 port->max_buf_cnt);
2519 mutex_unlock(&port->lock);
2520 return data;
2521 }
2522 return NULL;
2523}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302524EXPORT_SYMBOL(q6asm_is_cpu_buf_avail);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302525
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302526/**
2527 * q6asm_cpu_buf_release -
2528 * releases cpu buffer for ASM
2529 *
2530 * @dir: RX or TX direction
2531 * @ac: Audio client handle
2532 *
2533 * Returns 0 on success or error on failure
2534 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302535int q6asm_cpu_buf_release(int dir, struct audio_client *ac)
2536{
2537 struct audio_port_data *port;
2538 int ret = 0;
2539 int idx;
2540
2541 if (!ac || ((dir != IN) && (dir != OUT))) {
2542 pr_err("%s: ac %pK dir %d\n", __func__, ac, dir);
2543 ret = -EINVAL;
2544 goto exit;
2545 }
2546
2547 if (ac->io_mode & SYNC_IO_MODE) {
2548 port = &ac->port[dir];
2549 mutex_lock(&port->lock);
2550 idx = port->cpu_buf;
2551 if (port->cpu_buf == 0) {
2552 port->cpu_buf = port->max_buf_cnt - 1;
2553 } else if (port->cpu_buf < port->max_buf_cnt) {
2554 port->cpu_buf = port->cpu_buf - 1;
2555 } else {
2556 pr_err("%s: buffer index(%d) out of range\n",
2557 __func__, port->cpu_buf);
2558 ret = -EINVAL;
2559 mutex_unlock(&port->lock);
2560 goto exit;
2561 }
2562 port->buf[port->cpu_buf].used = dir ^ 1;
2563 mutex_unlock(&port->lock);
2564 }
2565exit:
2566 return ret;
2567}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302568EXPORT_SYMBOL(q6asm_cpu_buf_release);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302569
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302570/**
2571 * q6asm_is_cpu_buf_avail_nolock -
2572 * retrieve next CPU buf avail without lock acquire
2573 *
2574 * @dir: RX or TX direction
2575 * @ac: Audio client handle
2576 * @size: size pointer to be updated with size of buffer
2577 * @index: index pointer to be updated with
2578 * CPU buffer index available
2579 *
2580 * Returns buffer pointer on success or NULL on failure
2581 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302582void *q6asm_is_cpu_buf_avail_nolock(int dir, struct audio_client *ac,
2583 uint32_t *size, uint32_t *index)
2584{
2585 void *data;
2586 unsigned char idx;
2587 struct audio_port_data *port;
2588
2589 if (!ac || ((dir != IN) && (dir != OUT))) {
2590 pr_err("%s: ac %pK dir %d\n", __func__, ac, dir);
2591 return NULL;
2592 }
2593
2594 port = &ac->port[dir];
2595
2596 idx = port->cpu_buf;
2597 if (port->buf == NULL) {
2598 pr_err("%s: Buffer pointer null\n", __func__);
2599 return NULL;
2600 }
2601 /*
2602 * dir 0: used = 0 means buf in use
2603 * dir 1: used = 1 means buf in use
2604 */
2605 if (port->buf[idx].used == dir) {
2606 /*
2607 * To make it more robust, we could loop and get the
2608 * next avail buf, its risky though
2609 */
2610 pr_err("%s: Next buf idx[0x%x] not available, dir[%d]\n",
2611 __func__, idx, dir);
2612 return NULL;
2613 }
2614 *size = port->buf[idx].actual_size;
2615 *index = port->cpu_buf;
2616 data = port->buf[idx].data;
2617 dev_vdbg(ac->dev, "%s: session[%d]index[%d] data[%pK]size[%d]\n",
2618 __func__, ac->session, port->cpu_buf,
2619 data, *size);
2620 /*
2621 * By default increase the cpu_buf cnt
2622 * user accesses this function,increase cpu
2623 * buf(to avoid another api)
2624 */
2625 port->buf[idx].used = dir;
2626 port->cpu_buf = q6asm_get_next_buf(ac, port->cpu_buf,
2627 port->max_buf_cnt);
2628 return data;
2629}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302630EXPORT_SYMBOL(q6asm_is_cpu_buf_avail_nolock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302631
2632int q6asm_is_dsp_buf_avail(int dir, struct audio_client *ac)
2633{
2634 int ret = -1;
2635 struct audio_port_data *port;
2636 uint32_t idx;
2637
2638 if (!ac || (dir != OUT)) {
2639 pr_err("%s: ac %pK dir %d\n", __func__, ac, dir);
2640 return ret;
2641 }
2642
2643 if (ac->io_mode & SYNC_IO_MODE) {
2644 port = &ac->port[dir];
2645
2646 mutex_lock(&port->lock);
2647 idx = port->dsp_buf;
2648
2649 if (port->buf[idx].used == (dir ^ 1)) {
2650 /* To make it more robust, we could loop and get the
2651 * next avail buf, its risky though
2652 */
2653 pr_err("%s: Next buf idx[0x%x] not available, dir[%d]\n",
2654 __func__, idx, dir);
2655 mutex_unlock(&port->lock);
2656 return ret;
2657 }
2658 dev_vdbg(ac->dev, "%s: session[%d]dsp_buf=%d cpu_buf=%d\n",
2659 __func__,
2660 ac->session, port->dsp_buf, port->cpu_buf);
2661 ret = ((port->dsp_buf != port->cpu_buf) ? 0 : -1);
2662 mutex_unlock(&port->lock);
2663 }
2664 return ret;
2665}
2666
2667static void __q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
2668 uint32_t pkt_size, uint32_t cmd_flg, uint32_t stream_id)
2669{
Vignesh Kulothungan023a5322018-06-21 11:13:29 -07002670 unsigned long flags = 0;
Meng Wangb6afa8c2017-11-30 17:55:05 +08002671
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302672 dev_vdbg(ac->dev, "%s: pkt_size=%d cmd_flg=%d session=%d stream_id=%d\n",
2673 __func__, pkt_size, cmd_flg, ac->session, stream_id);
2674 mutex_lock(&ac->cmd_lock);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002675 spin_lock_irqsave(&(session[ac->session].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302676 if (ac->apr == NULL) {
2677 pr_err("%s: AC APR handle NULL", __func__);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002678 spin_unlock_irqrestore(
2679 &(session[ac->session].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302680 mutex_unlock(&ac->cmd_lock);
2681 return;
2682 }
2683
2684 hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
2685 APR_HDR_LEN(sizeof(struct apr_hdr)),
2686 APR_PKT_VER);
2687 hdr->src_svc = ((struct apr_svc *)ac->apr)->id;
2688 hdr->src_domain = APR_DOMAIN_APPS;
2689 hdr->dest_svc = APR_SVC_ASM;
2690 hdr->dest_domain = APR_DOMAIN_ADSP;
2691 hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id);
2692 hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id);
2693 if (cmd_flg)
2694 q6asm_update_token(&hdr->token,
2695 ac->session,
2696 0, /* Stream ID is NA */
2697 0, /* Buffer index is NA */
2698 0, /* Direction flag is NA */
2699 WAIT_CMD);
2700
2701 hdr->pkt_size = pkt_size;
Meng Wangb6afa8c2017-11-30 17:55:05 +08002702 spin_unlock_irqrestore(
2703 &(session[ac->session].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302704 mutex_unlock(&ac->cmd_lock);
2705}
2706
2707static void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
2708 uint32_t pkt_size, uint32_t cmd_flg)
2709{
2710 __q6asm_add_hdr(ac, hdr, pkt_size, cmd_flg, ac->stream_id);
2711}
2712
2713static void q6asm_stream_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
2714 uint32_t pkt_size, uint32_t cmd_flg, int32_t stream_id)
2715{
2716 __q6asm_add_hdr(ac, hdr, pkt_size, cmd_flg, stream_id);
2717}
2718
2719static void __q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
2720 uint32_t pkt_size, uint32_t cmd_flg,
2721 uint32_t stream_id, u8 no_wait_flag)
2722{
2723 dev_vdbg(ac->dev, "%s: pkt_size = %d, cmd_flg = %d, session = %d stream_id=%d\n",
2724 __func__, pkt_size, cmd_flg, ac->session, stream_id);
2725 hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
2726 APR_HDR_LEN(sizeof(struct apr_hdr)),
2727 APR_PKT_VER);
2728 if (ac->apr == NULL) {
2729 pr_err("%s: AC APR is NULL", __func__);
2730 return;
2731 }
2732 hdr->src_svc = ((struct apr_svc *)ac->apr)->id;
2733 hdr->src_domain = APR_DOMAIN_APPS;
2734 hdr->dest_svc = APR_SVC_ASM;
2735 hdr->dest_domain = APR_DOMAIN_ADSP;
2736 hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id);
2737 hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id);
2738 if (cmd_flg) {
2739 q6asm_update_token(&hdr->token,
2740 ac->session,
2741 0, /* Stream ID is NA */
2742 0, /* Buffer index is NA */
2743 0, /* Direction flag is NA */
2744 no_wait_flag);
2745
2746 }
2747 hdr->pkt_size = pkt_size;
2748}
2749
2750static void q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
2751 uint32_t pkt_size, uint32_t cmd_flg)
2752{
2753 __q6asm_add_hdr_async(ac, hdr, pkt_size, cmd_flg,
2754 ac->stream_id, WAIT_CMD);
2755}
2756
2757static void q6asm_stream_add_hdr_async(struct audio_client *ac,
2758 struct apr_hdr *hdr, uint32_t pkt_size,
2759 uint32_t cmd_flg, int32_t stream_id)
2760{
2761 __q6asm_add_hdr_async(ac, hdr, pkt_size, cmd_flg,
2762 stream_id, NO_WAIT_CMD);
2763}
2764
2765static void q6asm_add_hdr_custom_topology(struct audio_client *ac,
2766 struct apr_hdr *hdr,
2767 uint32_t pkt_size)
2768{
2769 pr_debug("%s: pkt_size=%d session=%d\n",
2770 __func__, pkt_size, ac->session);
2771 if (ac->apr == NULL) {
2772 pr_err("%s: AC APR handle NULL\n", __func__);
2773 return;
2774 }
2775
2776 mutex_lock(&ac->cmd_lock);
2777 hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
2778 APR_HDR_LEN(sizeof(struct apr_hdr)),
2779 APR_PKT_VER);
2780 hdr->src_svc = ((struct apr_svc *)ac->apr)->id;
2781 hdr->src_domain = APR_DOMAIN_APPS;
2782 hdr->dest_svc = APR_SVC_ASM;
2783 hdr->dest_domain = APR_DOMAIN_ADSP;
2784 hdr->src_port = ((ac->session << 8) & 0xFF00) | 0x01;
2785 hdr->dest_port = 0;
2786 q6asm_update_token(&hdr->token,
2787 ac->session,
2788 0, /* Stream ID is NA */
2789 0, /* Buffer index is NA */
2790 0, /* Direction flag is NA */
2791 WAIT_CMD);
2792 hdr->pkt_size = pkt_size;
2793 mutex_unlock(&ac->cmd_lock);
2794}
2795
2796static void q6asm_add_mmaphdr(struct audio_client *ac, struct apr_hdr *hdr,
2797 u32 pkt_size, int dir)
2798{
2799 pr_debug("%s: pkt size=%d\n",
2800 __func__, pkt_size);
2801 hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
2802 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
2803 hdr->src_port = 0;
2804 hdr->dest_port = 0;
2805 q6asm_update_token(&hdr->token,
2806 ac->session,
2807 0, /* Stream ID is NA */
2808 0, /* Buffer index is NA */
2809 dir,
2810 WAIT_CMD);
2811 hdr->pkt_size = pkt_size;
2812}
2813
2814static int __q6asm_open_read(struct audio_client *ac,
2815 uint32_t format, uint16_t bits_per_sample,
2816 uint32_t pcm_format_block_ver,
2817 bool ts_mode)
2818{
2819 int rc = 0x00;
2820 struct asm_stream_cmd_open_read_v3 open;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07002821 struct q6asm_cal_info cal_info;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302822
2823 config_debug_fs_reset_index();
2824
2825 if (ac == NULL) {
2826 pr_err("%s: APR handle NULL\n", __func__);
2827 return -EINVAL;
2828 }
2829 if (ac->apr == NULL) {
2830 pr_err("%s: AC APR handle NULL\n", __func__);
2831 return -EINVAL;
2832 }
2833 pr_debug("%s: session[%d]\n", __func__, ac->session);
2834
2835 q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
2836 atomic_set(&ac->cmd_state, -1);
2837 open.hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V3;
2838 /* Stream prio : High, provide meta info with encoded frames */
2839 open.src_endpointype = ASM_END_POINT_DEVICE_MATRIX;
2840
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07002841 rc = q6asm_get_asm_topology_apptype(&cal_info);
2842 open.preprocopo_id = cal_info.topology_id;
2843
2844
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302845 open.bits_per_sample = bits_per_sample;
2846 open.mode_flags = 0x0;
2847
2848 ac->topology = open.preprocopo_id;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07002849 ac->app_type = cal_info.app_type;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302850 if (ac->perf_mode == LOW_LATENCY_PCM_MODE) {
2851 open.mode_flags |= ASM_LOW_LATENCY_TX_STREAM_SESSION <<
2852 ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
2853 } else {
2854 open.mode_flags |= ASM_LEGACY_STREAM_SESSION <<
2855 ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
2856 }
2857
2858 switch (format) {
2859 case FORMAT_LINEAR_PCM:
2860 open.mode_flags |= 0x00;
2861 open.enc_cfg_id = q6asm_get_pcm_format_id(pcm_format_block_ver);
2862 if (ts_mode)
2863 open.mode_flags |= ABSOLUTE_TIMESTAMP_ENABLE;
2864 break;
2865 case FORMAT_MPEG4_AAC:
2866 open.mode_flags |= BUFFER_META_ENABLE;
2867 open.enc_cfg_id = ASM_MEDIA_FMT_AAC_V2;
2868 break;
2869 case FORMAT_G711_ALAW_FS:
2870 open.mode_flags |= BUFFER_META_ENABLE;
2871 open.enc_cfg_id = ASM_MEDIA_FMT_G711_ALAW_FS;
2872 break;
2873 case FORMAT_G711_MLAW_FS:
2874 open.mode_flags |= BUFFER_META_ENABLE;
2875 open.enc_cfg_id = ASM_MEDIA_FMT_G711_MLAW_FS;
2876 break;
2877 case FORMAT_V13K:
2878 open.mode_flags |= BUFFER_META_ENABLE;
2879 open.enc_cfg_id = ASM_MEDIA_FMT_V13K_FS;
2880 break;
2881 case FORMAT_EVRC:
2882 open.mode_flags |= BUFFER_META_ENABLE;
2883 open.enc_cfg_id = ASM_MEDIA_FMT_EVRC_FS;
2884 break;
2885 case FORMAT_AMRNB:
2886 open.mode_flags |= BUFFER_META_ENABLE;
2887 open.enc_cfg_id = ASM_MEDIA_FMT_AMRNB_FS;
2888 break;
2889 case FORMAT_AMRWB:
2890 open.mode_flags |= BUFFER_META_ENABLE;
2891 open.enc_cfg_id = ASM_MEDIA_FMT_AMRWB_FS;
2892 break;
2893 default:
2894 pr_err("%s: Invalid format 0x%x\n",
2895 __func__, format);
2896 rc = -EINVAL;
2897 goto fail_cmd;
2898 }
2899 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
2900 if (rc < 0) {
2901 pr_err("%s: open failed op[0x%x]rc[%d]\n",
2902 __func__, open.hdr.opcode, rc);
2903 rc = -EINVAL;
2904 goto fail_cmd;
2905 }
2906 rc = wait_event_timeout(ac->cmd_wait,
2907 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
2908 if (!rc) {
2909 pr_err("%s: timeout. waited for open read\n",
2910 __func__);
2911 rc = -ETIMEDOUT;
2912 goto fail_cmd;
2913 }
2914 if (atomic_read(&ac->cmd_state) > 0) {
2915 pr_err("%s: DSP returned error[%s]\n",
2916 __func__, adsp_err_get_err_str(
2917 atomic_read(&ac->cmd_state)));
2918 rc = adsp_err_get_lnx_err_code(
2919 atomic_read(&ac->cmd_state));
2920 goto fail_cmd;
2921 }
2922
2923 ac->io_mode |= TUN_READ_IO_MODE;
2924
2925 return 0;
2926fail_cmd:
2927 return rc;
2928}
2929
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302930/**
2931 * q6asm_open_read -
2932 * command to open ASM in read mode
2933 *
2934 * @ac: Audio client handle
2935 * @format: capture format for ASM
2936 *
2937 * Returns 0 on success or error on failure
2938 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302939int q6asm_open_read(struct audio_client *ac,
2940 uint32_t format)
2941{
2942 return __q6asm_open_read(ac, format, 16,
2943 PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/,
2944 false/*ts_mode*/);
2945}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302946EXPORT_SYMBOL(q6asm_open_read);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302947
2948int q6asm_open_read_v2(struct audio_client *ac, uint32_t format,
2949 uint16_t bits_per_sample)
2950{
2951 return __q6asm_open_read(ac, format, bits_per_sample,
2952 PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/,
2953 false/*ts_mode*/);
2954}
2955
2956/*
2957 * asm_open_read_v3 - Opens audio capture session
2958 *
2959 * @ac: Client session handle
2960 * @format: encoder format
2961 * @bits_per_sample: bit width of capture session
2962 */
2963int q6asm_open_read_v3(struct audio_client *ac, uint32_t format,
2964 uint16_t bits_per_sample)
2965{
2966 return __q6asm_open_read(ac, format, bits_per_sample,
2967 PCM_MEDIA_FORMAT_V3/*media fmt block ver*/,
2968 false/*ts_mode*/);
2969}
2970EXPORT_SYMBOL(q6asm_open_read_v3);
2971
2972/*
2973 * asm_open_read_v4 - Opens audio capture session
2974 *
2975 * @ac: Client session handle
2976 * @format: encoder format
2977 * @bits_per_sample: bit width of capture session
2978 * @ts_mode: timestamp mode
2979 */
2980int q6asm_open_read_v4(struct audio_client *ac, uint32_t format,
2981 uint16_t bits_per_sample, bool ts_mode)
2982{
2983 return __q6asm_open_read(ac, format, bits_per_sample,
2984 PCM_MEDIA_FORMAT_V4 /*media fmt block ver*/,
2985 ts_mode);
2986}
2987EXPORT_SYMBOL(q6asm_open_read_v4);
2988
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302989/**
2990 * q6asm_open_write_compressed -
2991 * command to open ASM in compressed write mode
2992 *
2993 * @ac: Audio client handle
2994 * @format: playback format for ASM
2995 * @passthrough_flag: flag to indicate passthrough option
2996 *
2997 * Returns 0 on success or error on failure
2998 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302999int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format,
3000 uint32_t passthrough_flag)
3001{
3002 int rc = 0;
3003 struct asm_stream_cmd_open_write_compressed open;
3004
3005 if (ac == NULL) {
3006 pr_err("%s: ac[%pK] NULL\n", __func__, ac);
3007 rc = -EINVAL;
3008 goto fail_cmd;
3009 }
3010
3011 if (ac->apr == NULL) {
3012 pr_err("%s: APR handle[%pK] NULL\n", __func__, ac->apr);
3013 rc = -EINVAL;
3014 goto fail_cmd;
3015 }
3016 pr_debug("%s: session[%d] wr_format[0x%x]", __func__, ac->session,
3017 format);
3018
3019 q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
3020 open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED;
3021 atomic_set(&ac->cmd_state, -1);
3022
3023 switch (format) {
3024 case FORMAT_AC3:
3025 open.fmt_id = ASM_MEDIA_FMT_AC3;
3026 break;
3027 case FORMAT_EAC3:
3028 open.fmt_id = ASM_MEDIA_FMT_EAC3;
3029 break;
3030 case FORMAT_DTS:
3031 open.fmt_id = ASM_MEDIA_FMT_DTS;
3032 break;
3033 case FORMAT_DSD:
3034 open.fmt_id = ASM_MEDIA_FMT_DSD;
3035 break;
3036 case FORMAT_GEN_COMPR:
3037 open.fmt_id = ASM_MEDIA_FMT_GENERIC_COMPRESSED;
3038 break;
3039 case FORMAT_TRUEHD:
3040 open.fmt_id = ASM_MEDIA_FMT_TRUEHD;
3041 break;
3042 case FORMAT_IEC61937:
3043 open.fmt_id = ASM_MEDIA_FMT_IEC;
3044 break;
3045 default:
3046 pr_err("%s: Invalid format[%d]\n", __func__, format);
3047 rc = -EINVAL;
3048 goto fail_cmd;
3049 }
3050 /* Below flag indicates the DSP that Compressed audio input
3051 * stream is not IEC 61937 or IEC 60958 packetizied
3052 */
3053 if (passthrough_flag == COMPRESSED_PASSTHROUGH ||
3054 passthrough_flag == COMPRESSED_PASSTHROUGH_DSD ||
3055 passthrough_flag == COMPRESSED_PASSTHROUGH_GEN) {
3056 open.flags = 0x0;
3057 pr_debug("%s: Flag 0 COMPRESSED_PASSTHROUGH\n", __func__);
3058 } else if (passthrough_flag == COMPRESSED_PASSTHROUGH_CONVERT) {
3059 open.flags = 0x8;
3060 pr_debug("%s: Flag 8 - COMPRESSED_PASSTHROUGH_CONVERT\n",
3061 __func__);
3062 } else if (passthrough_flag == COMPRESSED_PASSTHROUGH_IEC61937) {
3063 open.flags = 0x1;
3064 pr_debug("%s: Flag 1 - COMPRESSED_PASSTHROUGH_IEC61937\n",
3065 __func__);
3066 } else {
3067 pr_err("%s: Invalid passthrough type[%d]\n",
3068 __func__, passthrough_flag);
3069 rc = -EINVAL;
3070 goto fail_cmd;
3071 }
3072 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
3073 if (rc < 0) {
3074 pr_err("%s: open failed op[0x%x]rc[%d]\n",
3075 __func__, open.hdr.opcode, rc);
3076 rc = -EINVAL;
3077 goto fail_cmd;
3078 }
3079 rc = wait_event_timeout(ac->cmd_wait,
3080 (atomic_read(&ac->cmd_state) >= 0), 1*HZ);
3081 if (!rc) {
3082 pr_err("%s: timeout. waited for OPEN_WRITE_COMPR rc[%d]\n",
3083 __func__, rc);
3084 rc = -ETIMEDOUT;
3085 goto fail_cmd;
3086 }
3087
3088 if (atomic_read(&ac->cmd_state) > 0) {
3089 pr_err("%s: DSP returned error[%s]\n",
3090 __func__, adsp_err_get_err_str(
3091 atomic_read(&ac->cmd_state)));
3092 rc = adsp_err_get_lnx_err_code(
3093 atomic_read(&ac->cmd_state));
3094 goto fail_cmd;
3095 }
3096
3097 return 0;
3098
3099fail_cmd:
3100 return rc;
3101}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303102EXPORT_SYMBOL(q6asm_open_write_compressed);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303103
3104static int __q6asm_open_write(struct audio_client *ac, uint32_t format,
3105 uint16_t bits_per_sample, uint32_t stream_id,
3106 bool is_gapless_mode,
3107 uint32_t pcm_format_block_ver)
3108{
3109 int rc = 0x00;
3110 struct asm_stream_cmd_open_write_v3 open;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003111 struct q6asm_cal_info cal_info;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303112
3113 if (ac == NULL) {
3114 pr_err("%s: APR handle NULL\n", __func__);
3115 return -EINVAL;
3116 }
3117 if (ac->apr == NULL) {
3118 pr_err("%s: AC APR handle NULL\n", __func__);
3119 return -EINVAL;
3120 }
3121
3122 dev_vdbg(ac->dev, "%s: session[%d] wr_format[0x%x]\n",
3123 __func__, ac->session, format);
3124
3125 q6asm_stream_add_hdr(ac, &open.hdr, sizeof(open), TRUE, stream_id);
3126 atomic_set(&ac->cmd_state, -1);
3127 /*
3128 * Updated the token field with stream/session for compressed playback
3129 * Platform driver must know the the stream with which the command is
3130 * associated
3131 */
3132 if (ac->io_mode & COMPRESSED_STREAM_IO)
3133 q6asm_update_token(&open.hdr.token,
3134 ac->session,
3135 stream_id,
3136 0, /* Buffer index is NA */
3137 0, /* Direction flag is NA */
3138 WAIT_CMD);
3139
3140 dev_vdbg(ac->dev, "%s: token = 0x%x, stream_id %d, session 0x%x\n",
3141 __func__, open.hdr.token, stream_id, ac->session);
3142 open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
3143 open.mode_flags = 0x00;
3144 if (ac->perf_mode == ULL_POST_PROCESSING_PCM_MODE)
3145 open.mode_flags |= ASM_ULL_POST_PROCESSING_STREAM_SESSION;
3146 else if (ac->perf_mode == ULTRA_LOW_LATENCY_PCM_MODE)
3147 open.mode_flags |= ASM_ULTRA_LOW_LATENCY_STREAM_SESSION;
3148 else if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
3149 open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION;
3150 else {
3151 open.mode_flags |= ASM_LEGACY_STREAM_SESSION;
3152 if (is_gapless_mode)
3153 open.mode_flags |= 1 << ASM_SHIFT_GAPLESS_MODE_FLAG;
3154 }
3155
3156 /* source endpoint : matrix */
3157 open.sink_endpointype = ASM_END_POINT_DEVICE_MATRIX;
3158 open.bits_per_sample = bits_per_sample;
3159
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003160 rc = q6asm_get_asm_topology_apptype(&cal_info);
3161 open.postprocopo_id = cal_info.topology_id;
3162
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303163 if (ac->perf_mode != LEGACY_PCM_MODE)
3164 open.postprocopo_id = ASM_STREAM_POSTPROCOPO_ID_NONE;
3165
3166 pr_debug("%s: perf_mode %d asm_topology 0x%x bps %d\n", __func__,
3167 ac->perf_mode, open.postprocopo_id, open.bits_per_sample);
3168
3169 /*
3170 * For Gapless playback it will use the same session for next stream,
3171 * So use the same topology
3172 */
3173 if (!ac->topology) {
3174 ac->topology = open.postprocopo_id;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003175 ac->app_type = cal_info.app_type;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303176 }
3177 switch (format) {
3178 case FORMAT_LINEAR_PCM:
3179 open.dec_fmt_id = q6asm_get_pcm_format_id(pcm_format_block_ver);
3180 break;
3181 case FORMAT_MPEG4_AAC:
3182 open.dec_fmt_id = ASM_MEDIA_FMT_AAC_V2;
3183 break;
3184 case FORMAT_MPEG4_MULTI_AAC:
3185 open.dec_fmt_id = ASM_MEDIA_FMT_AAC_V2;
3186 break;
3187 case FORMAT_WMA_V9:
3188 open.dec_fmt_id = ASM_MEDIA_FMT_WMA_V9_V2;
3189 break;
3190 case FORMAT_WMA_V10PRO:
3191 open.dec_fmt_id = ASM_MEDIA_FMT_WMA_V10PRO_V2;
3192 break;
3193 case FORMAT_MP3:
3194 open.dec_fmt_id = ASM_MEDIA_FMT_MP3;
3195 break;
3196 case FORMAT_AC3:
3197 open.dec_fmt_id = ASM_MEDIA_FMT_AC3;
3198 break;
3199 case FORMAT_EAC3:
3200 open.dec_fmt_id = ASM_MEDIA_FMT_EAC3;
3201 break;
3202 case FORMAT_MP2:
3203 open.dec_fmt_id = ASM_MEDIA_FMT_MP2;
3204 break;
3205 case FORMAT_FLAC:
3206 open.dec_fmt_id = ASM_MEDIA_FMT_FLAC;
3207 break;
3208 case FORMAT_ALAC:
3209 open.dec_fmt_id = ASM_MEDIA_FMT_ALAC;
3210 break;
3211 case FORMAT_VORBIS:
3212 open.dec_fmt_id = ASM_MEDIA_FMT_VORBIS;
3213 break;
3214 case FORMAT_APE:
3215 open.dec_fmt_id = ASM_MEDIA_FMT_APE;
3216 break;
3217 case FORMAT_DSD:
3218 open.dec_fmt_id = ASM_MEDIA_FMT_DSD;
3219 break;
3220 case FORMAT_APTX:
3221 open.dec_fmt_id = ASM_MEDIA_FMT_APTX;
3222 break;
3223 case FORMAT_GEN_COMPR:
3224 open.dec_fmt_id = ASM_MEDIA_FMT_GENERIC_COMPRESSED;
3225 break;
3226 default:
3227 pr_err("%s: Invalid format 0x%x\n", __func__, format);
3228 rc = -EINVAL;
3229 goto fail_cmd;
3230 }
3231 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
3232 if (rc < 0) {
3233 pr_err("%s: open failed op[0x%x]rc[%d]\n",
3234 __func__, open.hdr.opcode, rc);
3235 rc = -EINVAL;
3236 goto fail_cmd;
3237 }
3238 rc = wait_event_timeout(ac->cmd_wait,
3239 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
3240 if (!rc) {
3241 pr_err("%s: timeout. waited for open write\n", __func__);
3242 rc = -ETIMEDOUT;
3243 goto fail_cmd;
3244 }
3245 if (atomic_read(&ac->cmd_state) > 0) {
3246 pr_err("%s: DSP returned error[%s]\n",
3247 __func__, adsp_err_get_err_str(
3248 atomic_read(&ac->cmd_state)));
3249 rc = adsp_err_get_lnx_err_code(
3250 atomic_read(&ac->cmd_state));
3251 goto fail_cmd;
3252 }
3253 ac->io_mode |= TUN_WRITE_IO_MODE;
3254
3255 return 0;
3256fail_cmd:
3257 return rc;
3258}
3259
3260int q6asm_open_write(struct audio_client *ac, uint32_t format)
3261{
3262 return __q6asm_open_write(ac, format, 16, ac->stream_id,
3263 false /*gapless*/,
3264 PCM_MEDIA_FORMAT_V2 /*pcm_format_block_ver*/);
3265}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303266EXPORT_SYMBOL(q6asm_open_write);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303267
3268int q6asm_open_write_v2(struct audio_client *ac, uint32_t format,
3269 uint16_t bits_per_sample)
3270{
3271 return __q6asm_open_write(ac, format, bits_per_sample,
3272 ac->stream_id, false /*gapless*/,
3273 PCM_MEDIA_FORMAT_V2 /*pcm_format_block_ver*/);
3274}
3275
3276/*
3277 * q6asm_open_write_v3 - Opens audio playback session
3278 *
3279 * @ac: Client session handle
3280 * @format: decoder format
3281 * @bits_per_sample: bit width of playback session
3282 */
3283int q6asm_open_write_v3(struct audio_client *ac, uint32_t format,
3284 uint16_t bits_per_sample)
3285{
3286 return __q6asm_open_write(ac, format, bits_per_sample,
3287 ac->stream_id, false /*gapless*/,
3288 PCM_MEDIA_FORMAT_V3 /*pcm_format_block_ver*/);
3289}
3290EXPORT_SYMBOL(q6asm_open_write_v3);
3291
3292/*
3293 * q6asm_open_write_v4 - Opens audio playback session
3294 *
3295 * @ac: Client session handle
3296 * @format: decoder format
3297 * @bits_per_sample: bit width of playback session
3298 */
3299int q6asm_open_write_v4(struct audio_client *ac, uint32_t format,
3300 uint16_t bits_per_sample)
3301{
3302 return __q6asm_open_write(ac, format, bits_per_sample,
3303 ac->stream_id, false /*gapless*/,
3304 PCM_MEDIA_FORMAT_V4 /*pcm_format_block_ver*/);
3305}
3306EXPORT_SYMBOL(q6asm_open_write_v4);
3307
3308int q6asm_stream_open_write_v2(struct audio_client *ac, uint32_t format,
3309 uint16_t bits_per_sample, int32_t stream_id,
3310 bool is_gapless_mode)
3311{
3312 return __q6asm_open_write(ac, format, bits_per_sample,
3313 stream_id, is_gapless_mode,
3314 PCM_MEDIA_FORMAT_V2 /*pcm_format_block_ver*/);
3315}
3316
3317/*
3318 * q6asm_stream_open_write_v3 - Creates audio stream for playback
3319 *
3320 * @ac: Client session handle
3321 * @format: asm playback format
3322 * @bits_per_sample: bit width of requested stream
3323 * @stream_id: stream id of stream to be associated with this session
3324 * @is_gapless_mode: true if gapless mode needs to be enabled
3325 */
3326int q6asm_stream_open_write_v3(struct audio_client *ac, uint32_t format,
3327 uint16_t bits_per_sample, int32_t stream_id,
3328 bool is_gapless_mode)
3329{
3330 return __q6asm_open_write(ac, format, bits_per_sample,
3331 stream_id, is_gapless_mode,
3332 PCM_MEDIA_FORMAT_V3 /*pcm_format_block_ver*/);
3333}
3334EXPORT_SYMBOL(q6asm_stream_open_write_v3);
3335
3336/*
3337 * q6asm_stream_open_write_v4 - Creates audio stream for playback
3338 *
3339 * @ac: Client session handle
3340 * @format: asm playback format
3341 * @bits_per_sample: bit width of requested stream
3342 * @stream_id: stream id of stream to be associated with this session
3343 * @is_gapless_mode: true if gapless mode needs to be enabled
3344 */
3345int q6asm_stream_open_write_v4(struct audio_client *ac, uint32_t format,
3346 uint16_t bits_per_sample, int32_t stream_id,
3347 bool is_gapless_mode)
3348{
3349 return __q6asm_open_write(ac, format, bits_per_sample,
3350 stream_id, is_gapless_mode,
3351 PCM_MEDIA_FORMAT_V4 /*pcm_format_block_ver*/);
3352}
3353EXPORT_SYMBOL(q6asm_stream_open_write_v4);
3354
3355static int __q6asm_open_read_write(struct audio_client *ac, uint32_t rd_format,
3356 uint32_t wr_format, bool is_meta_data_mode,
3357 uint32_t bits_per_sample,
3358 bool overwrite_topology, int topology)
3359{
3360 int rc = 0x00;
3361 struct asm_stream_cmd_open_readwrite_v2 open;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003362 struct q6asm_cal_info cal_info;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303363
3364 if (ac == NULL) {
3365 pr_err("%s: APR handle NULL\n", __func__);
3366 return -EINVAL;
3367 }
3368 if (ac->apr == NULL) {
3369 pr_err("%s: AC APR handle NULL\n", __func__);
3370 return -EINVAL;
3371 }
3372 pr_debug("%s: session[%d]\n", __func__, ac->session);
3373 pr_debug("%s: wr_format[0x%x]rd_format[0x%x]\n",
3374 __func__, wr_format, rd_format);
3375
3376 ac->io_mode |= NT_MODE;
3377 q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
3378 atomic_set(&ac->cmd_state, -1);
3379 open.hdr.opcode = ASM_STREAM_CMD_OPEN_READWRITE_V2;
3380
3381 open.mode_flags = is_meta_data_mode ? BUFFER_META_ENABLE : 0;
3382 open.bits_per_sample = bits_per_sample;
3383 /* source endpoint : matrix */
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003384 rc = q6asm_get_asm_topology_apptype(&cal_info);
3385 open.postprocopo_id = cal_info.topology_id;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303386
3387 open.postprocopo_id = overwrite_topology ?
3388 topology : open.postprocopo_id;
3389 ac->topology = open.postprocopo_id;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003390 ac->app_type = cal_info.app_type;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303391
3392
3393 switch (wr_format) {
3394 case FORMAT_LINEAR_PCM:
3395 case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
3396 open.dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
3397 break;
3398 case FORMAT_MPEG4_AAC:
3399 open.dec_fmt_id = ASM_MEDIA_FMT_AAC_V2;
3400 break;
3401 case FORMAT_MPEG4_MULTI_AAC:
3402 open.dec_fmt_id = ASM_MEDIA_FMT_AAC_V2;
3403 break;
3404 case FORMAT_WMA_V9:
3405 open.dec_fmt_id = ASM_MEDIA_FMT_WMA_V9_V2;
3406 break;
3407 case FORMAT_WMA_V10PRO:
3408 open.dec_fmt_id = ASM_MEDIA_FMT_WMA_V10PRO_V2;
3409 break;
3410 case FORMAT_AMRNB:
3411 open.dec_fmt_id = ASM_MEDIA_FMT_AMRNB_FS;
3412 break;
3413 case FORMAT_AMRWB:
3414 open.dec_fmt_id = ASM_MEDIA_FMT_AMRWB_FS;
3415 break;
3416 case FORMAT_AMR_WB_PLUS:
3417 open.dec_fmt_id = ASM_MEDIA_FMT_AMR_WB_PLUS_V2;
3418 break;
3419 case FORMAT_V13K:
3420 open.dec_fmt_id = ASM_MEDIA_FMT_V13K_FS;
3421 break;
3422 case FORMAT_EVRC:
3423 open.dec_fmt_id = ASM_MEDIA_FMT_EVRC_FS;
3424 break;
3425 case FORMAT_EVRCB:
3426 open.dec_fmt_id = ASM_MEDIA_FMT_EVRCB_FS;
3427 break;
3428 case FORMAT_EVRCWB:
3429 open.dec_fmt_id = ASM_MEDIA_FMT_EVRCWB_FS;
3430 break;
3431 case FORMAT_MP3:
3432 open.dec_fmt_id = ASM_MEDIA_FMT_MP3;
3433 break;
3434 case FORMAT_ALAC:
3435 open.dec_fmt_id = ASM_MEDIA_FMT_ALAC;
3436 break;
3437 case FORMAT_APE:
3438 open.dec_fmt_id = ASM_MEDIA_FMT_APE;
3439 break;
3440 case FORMAT_DSD:
3441 open.dec_fmt_id = ASM_MEDIA_FMT_DSD;
3442 break;
3443 case FORMAT_G711_ALAW_FS:
3444 open.dec_fmt_id = ASM_MEDIA_FMT_G711_ALAW_FS;
3445 break;
3446 case FORMAT_G711_MLAW_FS:
3447 open.dec_fmt_id = ASM_MEDIA_FMT_G711_MLAW_FS;
3448 break;
3449 default:
3450 pr_err("%s: Invalid format 0x%x\n",
3451 __func__, wr_format);
3452 rc = -EINVAL;
3453 goto fail_cmd;
3454 }
3455
3456 switch (rd_format) {
3457 case FORMAT_LINEAR_PCM:
3458 case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
3459 open.enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
3460 break;
3461 case FORMAT_MPEG4_AAC:
3462 open.enc_cfg_id = ASM_MEDIA_FMT_AAC_V2;
3463 break;
3464 case FORMAT_G711_ALAW_FS:
3465 open.enc_cfg_id = ASM_MEDIA_FMT_G711_ALAW_FS;
3466 break;
3467 case FORMAT_G711_MLAW_FS:
3468 open.enc_cfg_id = ASM_MEDIA_FMT_G711_MLAW_FS;
3469 break;
3470 case FORMAT_V13K:
3471 open.enc_cfg_id = ASM_MEDIA_FMT_V13K_FS;
3472 break;
3473 case FORMAT_EVRC:
3474 open.enc_cfg_id = ASM_MEDIA_FMT_EVRC_FS;
3475 break;
3476 case FORMAT_AMRNB:
3477 open.enc_cfg_id = ASM_MEDIA_FMT_AMRNB_FS;
3478 break;
3479 case FORMAT_AMRWB:
3480 open.enc_cfg_id = ASM_MEDIA_FMT_AMRWB_FS;
3481 break;
3482 case FORMAT_ALAC:
3483 open.enc_cfg_id = ASM_MEDIA_FMT_ALAC;
3484 break;
3485 case FORMAT_APE:
3486 open.enc_cfg_id = ASM_MEDIA_FMT_APE;
3487 break;
3488 default:
3489 pr_err("%s: Invalid format 0x%x\n",
3490 __func__, rd_format);
3491 rc = -EINVAL;
3492 goto fail_cmd;
3493 }
3494 dev_vdbg(ac->dev, "%s: rdformat[0x%x]wrformat[0x%x]\n", __func__,
3495 open.enc_cfg_id, open.dec_fmt_id);
3496
3497 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
3498 if (rc < 0) {
3499 pr_err("%s: open failed op[0x%x]rc[%d]\n",
3500 __func__, open.hdr.opcode, rc);
3501 rc = -EINVAL;
3502 goto fail_cmd;
3503 }
3504 rc = wait_event_timeout(ac->cmd_wait,
3505 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
3506 if (!rc) {
3507 pr_err("%s: timeout. waited for open read-write\n",
3508 __func__);
3509 rc = -ETIMEDOUT;
3510 goto fail_cmd;
3511 }
3512 if (atomic_read(&ac->cmd_state) > 0) {
3513 pr_err("%s: DSP returned error[%s]\n",
3514 __func__, adsp_err_get_err_str(
3515 atomic_read(&ac->cmd_state)));
3516 rc = adsp_err_get_lnx_err_code(
3517 atomic_read(&ac->cmd_state));
3518 goto fail_cmd;
3519 }
3520
3521 return 0;
3522fail_cmd:
3523 return rc;
3524}
3525
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303526/**
3527 * q6asm_open_read_write -
3528 * command to open ASM in read/write mode
3529 *
3530 * @ac: Audio client handle
3531 * @rd_format: capture format for ASM
3532 * @wr_format: playback format for ASM
3533 *
3534 * Returns 0 on success or error on failure
3535 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303536int q6asm_open_read_write(struct audio_client *ac, uint32_t rd_format,
3537 uint32_t wr_format)
3538{
3539 return __q6asm_open_read_write(ac, rd_format, wr_format,
3540 true/*meta data mode*/,
3541 16 /*bits_per_sample*/,
3542 false /*overwrite_topology*/, 0);
3543}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303544EXPORT_SYMBOL(q6asm_open_read_write);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303545
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303546/**
3547 * q6asm_open_read_write_v2 -
3548 * command to open ASM in bi-directional read/write mode
3549 *
3550 * @ac: Audio client handle
3551 * @rd_format: capture format for ASM
3552 * @wr_format: playback format for ASM
3553 * @is_meta_data_mode: mode to indicate if meta data present
3554 * @bits_per_sample: number of bits per sample
3555 * @overwrite_topology: topology to be overwritten flag
3556 * @topology: Topology for ASM
3557 *
3558 * Returns 0 on success or error on failure
3559 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303560int q6asm_open_read_write_v2(struct audio_client *ac, uint32_t rd_format,
3561 uint32_t wr_format, bool is_meta_data_mode,
3562 uint32_t bits_per_sample, bool overwrite_topology,
3563 int topology)
3564{
3565 return __q6asm_open_read_write(ac, rd_format, wr_format,
3566 is_meta_data_mode, bits_per_sample,
3567 overwrite_topology, topology);
3568}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303569EXPORT_SYMBOL(q6asm_open_read_write_v2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303570
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303571/**
3572 * q6asm_open_loopback_v2 -
3573 * command to open ASM in loopback mode
3574 *
3575 * @ac: Audio client handle
3576 * @bits_per_sample: number of bits per sample
3577 *
3578 * Returns 0 on success or error on failure
3579 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303580int q6asm_open_loopback_v2(struct audio_client *ac, uint16_t bits_per_sample)
3581{
3582 int rc = 0x00;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003583 struct q6asm_cal_info cal_info;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303584
3585 if (ac == NULL) {
3586 pr_err("%s: APR handle NULL\n", __func__);
3587 return -EINVAL;
3588 }
3589 if (ac->apr == NULL) {
3590 pr_err("%s: AC APR handle NULL\n", __func__);
3591 return -EINVAL;
3592 }
3593 pr_debug("%s: session[%d]\n", __func__, ac->session);
3594
3595 if (ac->perf_mode == LOW_LATENCY_PCM_MODE) {
3596 struct asm_stream_cmd_open_transcode_loopback_t open;
3597
3598 q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
3599 atomic_set(&ac->cmd_state, -1);
3600 open.hdr.opcode = ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK;
3601
3602 open.mode_flags = 0;
3603 open.src_endpoint_type = 0;
3604 open.sink_endpoint_type = 0;
3605 open.src_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
3606 open.sink_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
3607 /* source endpoint : matrix */
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003608 rc = q6asm_get_asm_topology_apptype(&cal_info);
3609 open.audproc_topo_id = cal_info.topology_id;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303610
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003611 ac->app_type = cal_info.app_type;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303612 if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
3613 open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION;
3614 else
3615 open.mode_flags |= ASM_LEGACY_STREAM_SESSION;
3616 ac->topology = open.audproc_topo_id;
3617 open.bits_per_sample = bits_per_sample;
3618 open.reserved = 0;
3619 pr_debug("%s: opening a transcode_loopback with mode_flags =[%d] session[%d]\n",
3620 __func__, open.mode_flags, ac->session);
3621
3622 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
3623 if (rc < 0) {
3624 pr_err("%s: open failed op[0x%x]rc[%d]\n",
3625 __func__, open.hdr.opcode, rc);
3626 rc = -EINVAL;
3627 goto fail_cmd;
3628 }
3629 } else {/*if(ac->perf_mode == LEGACY_PCM_MODE)*/
3630 struct asm_stream_cmd_open_loopback_v2 open;
3631
3632 q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
3633 atomic_set(&ac->cmd_state, -1);
3634 open.hdr.opcode = ASM_STREAM_CMD_OPEN_LOOPBACK_V2;
3635
3636 open.mode_flags = 0;
3637 open.src_endpointype = 0;
3638 open.sink_endpointype = 0;
3639 /* source endpoint : matrix */
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003640 rc = q6asm_get_asm_topology_apptype(&cal_info);
3641 open.postprocopo_id = cal_info.topology_id;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303642
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003643 ac->app_type = cal_info.app_type;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303644 ac->topology = open.postprocopo_id;
3645 open.bits_per_sample = bits_per_sample;
3646 open.reserved = 0;
3647 pr_debug("%s: opening a loopback_v2 with mode_flags =[%d] session[%d]\n",
3648 __func__, open.mode_flags, ac->session);
3649
3650 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
3651 if (rc < 0) {
3652 pr_err("%s: open failed op[0x%x]rc[%d]\n",
3653 __func__, open.hdr.opcode, rc);
3654 rc = -EINVAL;
3655 goto fail_cmd;
3656 }
3657 }
3658 rc = wait_event_timeout(ac->cmd_wait,
3659 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
3660 if (!rc) {
3661 pr_err("%s: timeout. waited for open_loopback\n",
3662 __func__);
3663 rc = -ETIMEDOUT;
3664 goto fail_cmd;
3665 }
3666 if (atomic_read(&ac->cmd_state) > 0) {
3667 pr_err("%s: DSP returned error[%s]\n",
3668 __func__, adsp_err_get_err_str(
3669 atomic_read(&ac->cmd_state)));
3670 rc = adsp_err_get_lnx_err_code(
3671 atomic_read(&ac->cmd_state));
3672 goto fail_cmd;
3673 }
3674
3675 return 0;
3676fail_cmd:
3677 return rc;
3678}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303679EXPORT_SYMBOL(q6asm_open_loopback_v2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303680
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303681/**
3682 * q6asm_open_transcode_loopback -
3683 * command to open ASM in transcode loopback mode
3684 *
3685 * @ac: Audio client handle
3686 * @bits_per_sample: number of bits per sample
3687 * @source_format: Format of clip
3688 * @sink_format: end device supported format
3689 *
3690 * Returns 0 on success or error on failure
3691 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303692int q6asm_open_transcode_loopback(struct audio_client *ac,
3693 uint16_t bits_per_sample,
3694 uint32_t source_format, uint32_t sink_format)
3695{
3696 int rc = 0x00;
3697 struct asm_stream_cmd_open_transcode_loopback_t open;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003698 struct q6asm_cal_info cal_info;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303699
3700 if (ac == NULL) {
3701 pr_err("%s: APR handle NULL\n", __func__);
3702 return -EINVAL;
3703 }
3704 if (ac->apr == NULL) {
3705 pr_err("%s: AC APR handle NULL\n", __func__);
3706 return -EINVAL;
3707 }
3708
3709 pr_debug("%s: session[%d]\n", __func__, ac->session);
3710
3711 q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
3712 atomic_set(&ac->cmd_state, -1);
3713 open.hdr.opcode = ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK;
3714
3715 open.mode_flags = 0;
3716 open.src_endpoint_type = 0;
3717 open.sink_endpoint_type = 0;
3718 switch (source_format) {
3719 case FORMAT_LINEAR_PCM:
3720 case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
3721 open.src_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3;
3722 break;
3723 case FORMAT_AC3:
3724 open.src_format_id = ASM_MEDIA_FMT_AC3;
3725 break;
3726 case FORMAT_EAC3:
3727 open.src_format_id = ASM_MEDIA_FMT_EAC3;
3728 break;
3729 default:
3730 pr_err("%s: Unsupported src fmt [%d]\n",
3731 __func__, source_format);
3732 return -EINVAL;
3733 }
3734 switch (sink_format) {
3735 case FORMAT_LINEAR_PCM:
3736 case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
3737 open.sink_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3;
3738 break;
3739 default:
3740 pr_err("%s: Unsupported sink fmt [%d]\n",
3741 __func__, sink_format);
3742 return -EINVAL;
3743 }
3744
3745 /* source endpoint : matrix */
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003746 rc = q6asm_get_asm_topology_apptype(&cal_info);
3747 open.audproc_topo_id = cal_info.topology_id;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303748
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003749
3750 ac->app_type = cal_info.app_type;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303751 if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
3752 open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION;
3753 else
3754 open.mode_flags |= ASM_LEGACY_STREAM_SESSION;
3755 ac->topology = open.audproc_topo_id;
3756 open.bits_per_sample = bits_per_sample;
3757 open.reserved = 0;
3758 pr_debug("%s: opening a transcode_loopback with mode_flags =[%d] session[%d]\n",
3759 __func__, open.mode_flags, ac->session);
3760
3761 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
3762 if (rc < 0) {
3763 pr_err("%s: open failed op[0x%x]rc[%d]\n",
3764 __func__, open.hdr.opcode, rc);
3765 rc = -EINVAL;
3766 goto fail_cmd;
3767 }
3768 rc = wait_event_timeout(ac->cmd_wait,
3769 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
3770 if (!rc) {
3771 pr_err("%s: timeout. waited for open_transcode_loopback\n",
3772 __func__);
3773 rc = -ETIMEDOUT;
3774 goto fail_cmd;
3775 }
3776 if (atomic_read(&ac->cmd_state) > 0) {
3777 pr_err("%s: DSP returned error[%s]\n",
3778 __func__, adsp_err_get_err_str(
3779 atomic_read(&ac->cmd_state)));
3780 rc = adsp_err_get_lnx_err_code(
3781 atomic_read(&ac->cmd_state));
3782 goto fail_cmd;
3783 }
3784
3785 return 0;
3786fail_cmd:
3787 return rc;
3788}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303789EXPORT_SYMBOL(q6asm_open_transcode_loopback);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303790
3791static
3792int q6asm_set_shared_circ_buff(struct audio_client *ac,
3793 struct asm_stream_cmd_open_shared_io *open,
3794 int bufsz, int bufcnt,
3795 int dir)
3796{
3797 struct audio_buffer *buf_circ;
3798 int bytes_to_alloc, rc;
3799 size_t len;
3800
Aditya Bavanaria8aea172017-09-13 11:37:53 +05303801 mutex_lock(&ac->cmd_lock);
3802
3803 if (ac->port[dir].buf) {
3804 pr_err("%s: Buffer already allocated\n", __func__);
3805 rc = -EINVAL;
Aditya Bavanaria8aea172017-09-13 11:37:53 +05303806 goto done;
3807 }
3808
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303809 buf_circ = kzalloc(sizeof(struct audio_buffer), GFP_KERNEL);
3810
3811 if (!buf_circ) {
3812 rc = -ENOMEM;
3813 goto done;
3814 }
3815
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303816 bytes_to_alloc = bufsz * bufcnt;
3817 bytes_to_alloc = PAGE_ALIGN(bytes_to_alloc);
3818
3819 rc = msm_audio_ion_alloc("audio_client", &buf_circ->client,
3820 &buf_circ->handle, bytes_to_alloc,
3821 (ion_phys_addr_t *)&buf_circ->phys,
3822 &len, &buf_circ->data);
3823
3824 if (rc) {
3825 pr_err("%s: Audio ION alloc is failed, rc = %d\n", __func__,
3826 rc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303827 kfree(buf_circ);
3828 goto done;
3829 }
3830
Aditya Bavanaria8aea172017-09-13 11:37:53 +05303831 ac->port[dir].buf = buf_circ;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303832 buf_circ->used = dir ^ 1;
3833 buf_circ->size = bytes_to_alloc;
3834 buf_circ->actual_size = bytes_to_alloc;
3835 memset(buf_circ->data, 0, buf_circ->actual_size);
3836
3837 ac->port[dir].max_buf_cnt = 1;
3838
3839 open->shared_circ_buf_mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
3840 open->shared_circ_buf_num_regions = 1;
3841 open->shared_circ_buf_property_flag = 0x00;
3842 open->shared_circ_buf_start_phy_addr_lsw =
3843 lower_32_bits(buf_circ->phys);
3844 open->shared_circ_buf_start_phy_addr_msw =
3845 msm_audio_populate_upper_32_bits(buf_circ->phys);
3846 open->shared_circ_buf_size = bufsz * bufcnt;
3847
3848 open->map_region_circ_buf.shm_addr_lsw = lower_32_bits(buf_circ->phys);
3849 open->map_region_circ_buf.shm_addr_msw =
3850 msm_audio_populate_upper_32_bits(buf_circ->phys);
3851 open->map_region_circ_buf.mem_size_bytes = bytes_to_alloc;
3852
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303853done:
Xiaoyu Yef423ab12017-11-22 11:38:29 -08003854 mutex_unlock(&ac->cmd_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303855 return rc;
3856}
3857
3858
3859static
3860int q6asm_set_shared_pos_buff(struct audio_client *ac,
3861 struct asm_stream_cmd_open_shared_io *open,
3862 int dir)
3863{
3864 struct audio_buffer *buf_pos = &ac->shared_pos_buf;
3865 int rc;
3866 size_t len;
3867 int bytes_to_alloc = sizeof(struct asm_shared_position_buffer);
3868
3869 mutex_lock(&ac->cmd_lock);
3870
3871 bytes_to_alloc = PAGE_ALIGN(bytes_to_alloc);
3872
3873 rc = msm_audio_ion_alloc("audio_client", &buf_pos->client,
3874 &buf_pos->handle, bytes_to_alloc,
3875 (ion_phys_addr_t *)&buf_pos->phys, &len,
3876 &buf_pos->data);
3877
3878 if (rc) {
3879 pr_err("%s: Audio pos buf ION alloc is failed, rc = %d\n",
3880 __func__, rc);
3881 goto done;
3882 }
3883
3884 buf_pos->used = dir ^ 1;
3885 buf_pos->size = bytes_to_alloc;
3886 buf_pos->actual_size = bytes_to_alloc;
3887
3888 open->shared_pos_buf_mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
3889 open->shared_pos_buf_num_regions = 1;
3890 open->shared_pos_buf_property_flag = 0x00;
3891 open->shared_pos_buf_phy_addr_lsw = lower_32_bits(buf_pos->phys);
3892 open->shared_pos_buf_phy_addr_msw =
3893 msm_audio_populate_upper_32_bits(buf_pos->phys);
3894
3895 open->map_region_pos_buf.shm_addr_lsw = lower_32_bits(buf_pos->phys);
3896 open->map_region_pos_buf.shm_addr_msw =
3897 msm_audio_populate_upper_32_bits(buf_pos->phys);
3898 open->map_region_pos_buf.mem_size_bytes = bytes_to_alloc;
3899
3900done:
3901 mutex_unlock(&ac->cmd_lock);
3902 return rc;
3903}
3904
3905/*
3906 * q6asm_open_shared_io: Open an ASM session for pull mode (playback)
3907 * or push mode (capture).
3908 * parameters
3909 * config - session parameters (channels, bits_per_sample, sr)
3910 * dir - stream direction (IN for playback, OUT for capture)
3911 * returns 0 if successful, error code otherwise
3912 */
3913int q6asm_open_shared_io(struct audio_client *ac,
3914 struct shared_io_config *config,
3915 int dir)
3916{
3917 struct asm_stream_cmd_open_shared_io *open;
3918 u8 *channel_mapping;
3919 int i, size_of_open, num_watermarks, bufsz, bufcnt, rc, flags = 0;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003920 struct q6asm_cal_info cal_info;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303921
3922 if (!ac || !config)
3923 return -EINVAL;
3924
Rohit kumar6a14cfb2019-02-04 11:22:49 +05303925 if (config->channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
3926 pr_err("%s: Invalid channel count %d\n", __func__,
3927 config->channels);
3928 return -EINVAL;
3929 }
3930
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303931 bufsz = config->bufsz;
3932 bufcnt = config->bufcnt;
3933 num_watermarks = 0;
3934
3935 ac->config = *config;
3936
3937 if (ac->session <= 0 || ac->session > SESSION_MAX) {
3938 pr_err("%s: Session %d is out of bounds\n",
3939 __func__, ac->session);
3940 return -EINVAL;
3941 }
3942
3943 size_of_open = sizeof(struct asm_stream_cmd_open_shared_io) +
3944 (sizeof(struct asm_shared_watermark_level) * num_watermarks);
3945
3946 open = kzalloc(PAGE_ALIGN(size_of_open), GFP_KERNEL);
3947 if (!open)
3948 return -ENOMEM;
3949
3950 q6asm_stream_add_hdr(ac, &open->hdr, size_of_open, TRUE,
3951 ac->stream_id);
3952
3953 atomic_set(&ac->cmd_state, 1);
3954
3955 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x, perf %d\n",
3956 __func__, open->hdr.token, ac->stream_id, ac->session,
3957 ac->perf_mode);
3958
3959 open->hdr.opcode =
3960 dir == IN ? ASM_STREAM_CMD_OPEN_PULL_MODE_WRITE :
3961 ASM_STREAM_CMD_OPEN_PUSH_MODE_READ;
3962
3963 pr_debug("%s perf_mode %d\n", __func__, ac->perf_mode);
3964 if (dir == IN)
3965 if (ac->perf_mode == ULL_POST_PROCESSING_PCM_MODE)
3966 flags = 4 << ASM_SHIFT_STREAM_PERF_FLAG_PULL_MODE_WRITE;
3967 else if (ac->perf_mode == ULTRA_LOW_LATENCY_PCM_MODE)
3968 flags = 2 << ASM_SHIFT_STREAM_PERF_FLAG_PULL_MODE_WRITE;
3969 else if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
3970 flags = 1 << ASM_SHIFT_STREAM_PERF_FLAG_PULL_MODE_WRITE;
3971 else
3972 pr_err("Invalid perf mode for pull write\n");
3973 else
3974 if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
3975 flags = ASM_LOW_LATENCY_TX_STREAM_SESSION <<
3976 ASM_SHIFT_STREAM_PERF_FLAG_PUSH_MODE_READ;
3977 else
3978 pr_err("Invalid perf mode for push read\n");
3979
3980 if (flags == 0) {
3981 pr_err("%s: Invalid mode[%d]\n", __func__,
3982 ac->perf_mode);
3983 kfree(open);
3984 return -EINVAL;
3985
3986 }
3987
3988 pr_debug("open.mode_flags = 0x%x\n", flags);
3989 open->mode_flags = flags;
3990 open->endpoint_type = ASM_END_POINT_DEVICE_MATRIX;
3991 open->topo_bits_per_sample = config->bits_per_sample;
3992
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003993 rc = q6asm_get_asm_topology_apptype(&cal_info);
3994 open->topo_id = cal_info.topology_id;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303995
3996 if (config->format == FORMAT_LINEAR_PCM)
3997 open->fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3;
3998 else {
3999 pr_err("%s: Invalid format[%d]\n", __func__, config->format);
4000 rc = -EINVAL;
4001 goto done;
4002 }
4003
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304004 rc = q6asm_set_shared_circ_buff(ac, open, bufsz, bufcnt, dir);
4005
4006 if (rc)
4007 goto done;
4008
4009 ac->port[dir].tmp_hdl = 0;
4010
4011 rc = q6asm_set_shared_pos_buff(ac, open, dir);
4012
4013 if (rc)
4014 goto done;
4015
4016 /* asm_multi_channel_pcm_fmt_blk_v3 */
4017 open->fmt.num_channels = config->channels;
4018 open->fmt.bits_per_sample = config->bits_per_sample;
4019 open->fmt.sample_rate = config->rate;
4020 open->fmt.is_signed = 1;
4021 open->fmt.sample_word_size = config->sample_word_size;
4022
4023 channel_mapping = open->fmt.channel_mapping;
4024
4025 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
4026
4027 rc = q6asm_map_channels(channel_mapping, config->channels, false);
4028 if (rc) {
4029 pr_err("%s: Map channels failed, ret: %d\n", __func__, rc);
4030 goto done;
4031 }
4032
4033 open->num_watermark_levels = num_watermarks;
4034 for (i = 0; i < num_watermarks; i++) {
4035 open->watermark[i].watermark_level_bytes = i *
4036 ((bufsz * bufcnt) / num_watermarks);
4037 pr_debug("%s: Watermark level set for %i\n",
4038 __func__,
4039 open->watermark[i].watermark_level_bytes);
4040 }
4041
4042 rc = apr_send_pkt(ac->apr, (uint32_t *) open);
4043 if (rc < 0) {
4044 pr_err("%s: Open failed op[0x%x]rc[%d]\n",
4045 __func__, open->hdr.opcode, rc);
4046 goto done;
4047 }
4048
4049 pr_debug("%s: sent open apr pkt\n", __func__);
4050 rc = wait_event_timeout(ac->cmd_wait,
4051 (atomic_read(&ac->cmd_state) <= 0), 5*HZ);
4052 if (!rc) {
4053 pr_err("%s: Timeout. Waited for open write apr pkt rc[%d]\n",
4054 __func__, rc);
4055 rc = -ETIMEDOUT;
4056 goto done;
4057 }
4058
4059 if (atomic_read(&ac->cmd_state) < 0) {
4060 pr_err("%s: DSP returned error [%d]\n", __func__,
4061 atomic_read(&ac->cmd_state));
4062 rc = -EINVAL;
4063 goto done;
4064 }
4065
4066 ac->io_mode |= TUN_WRITE_IO_MODE;
4067 rc = 0;
4068done:
4069 kfree(open);
4070 return rc;
4071}
4072EXPORT_SYMBOL(q6asm_open_shared_io);
4073
4074/*
4075 * q6asm_shared_io_buf: Returns handle to the shared circular buffer being
4076 * used for pull/push mode.
4077 * parameters
4078 * dir - used to identify input/output port
4079 * returns buffer handle
4080 */
4081struct audio_buffer *q6asm_shared_io_buf(struct audio_client *ac,
4082 int dir)
4083{
4084 struct audio_port_data *port;
4085
4086 if (!ac) {
4087 pr_err("%s: ac is null\n", __func__);
4088 return NULL;
4089 }
4090 port = &ac->port[dir];
4091 return port->buf;
4092}
4093EXPORT_SYMBOL(q6asm_shared_io_buf);
4094
4095/*
4096 * q6asm_shared_io_free: Frees memory allocated for a pull/push session
4097 * parameters
4098 * dir - port direction
4099 * returns 0 if successful, error otherwise
4100 */
4101int q6asm_shared_io_free(struct audio_client *ac, int dir)
4102{
4103 struct audio_port_data *port;
4104
4105 if (!ac) {
4106 pr_err("%s: audio client is null\n", __func__);
4107 return -EINVAL;
4108 }
4109 port = &ac->port[dir];
4110 mutex_lock(&ac->cmd_lock);
4111 if (port->buf && port->buf->data) {
4112 msm_audio_ion_free(port->buf->client, port->buf->handle);
4113 port->buf->client = NULL;
4114 port->buf->handle = NULL;
4115 port->max_buf_cnt = 0;
4116 kfree(port->buf);
4117 port->buf = NULL;
4118 }
4119 if (ac->shared_pos_buf.data) {
4120 msm_audio_ion_free(ac->shared_pos_buf.client,
4121 ac->shared_pos_buf.handle);
4122 ac->shared_pos_buf.client = NULL;
4123 ac->shared_pos_buf.handle = NULL;
4124 }
4125 mutex_unlock(&ac->cmd_lock);
4126 return 0;
4127}
4128EXPORT_SYMBOL(q6asm_shared_io_free);
4129
4130/*
4131 * q6asm_get_shared_pos: Returns current read index/write index as observed
4132 * by the DSP. Note that this is an offset and iterates from [0,BUF_SIZE - 1]
4133 * parameters - (all output)
4134 * read_index - offset
4135 * wall_clk_msw1 - ADSP wallclock msw
4136 * wall_clk_lsw1 - ADSP wallclock lsw
4137 * returns 0 if successful, -EAGAIN if DSP failed to update after some
4138 * retries
4139 */
4140int q6asm_get_shared_pos(struct audio_client *ac, uint32_t *read_index,
4141 uint32_t *wall_clk_msw1, uint32_t *wall_clk_lsw1)
4142{
4143 struct asm_shared_position_buffer *pos_buf;
4144 uint32_t frame_cnt1, frame_cnt2;
4145 int i, j;
4146
4147 if (!ac) {
4148 pr_err("%s: audio client is null\n", __func__);
4149 return -EINVAL;
4150 }
4151
4152 pos_buf = ac->shared_pos_buf.data;
4153
4154 /* always try to get the latest update in the shared pos buffer */
4155 for (i = 0; i < 2; i++) {
4156 /* retry until there is an update from DSP */
4157 for (j = 0; j < 5; j++) {
4158 frame_cnt1 = pos_buf->frame_counter;
4159 if (frame_cnt1 != 0)
4160 break;
4161 }
4162
4163 *wall_clk_msw1 = pos_buf->wall_clock_us_msw;
4164 *wall_clk_lsw1 = pos_buf->wall_clock_us_lsw;
4165 *read_index = pos_buf->index;
4166 frame_cnt2 = pos_buf->frame_counter;
4167
4168 if (frame_cnt1 != frame_cnt2)
4169 continue;
4170 return 0;
4171 }
4172 pr_err("%s out of tries trying to get a good read, try again\n",
4173 __func__);
4174 return -EAGAIN;
4175}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304176EXPORT_SYMBOL(q6asm_get_shared_pos);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304177
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304178/**
4179 * q6asm_run -
4180 * command to set ASM to run state
4181 *
4182 * @ac: Audio client handle
4183 * @flags: Flags for session
4184 * @msw_ts: upper 32bits timestamp
4185 * @lsw_ts: lower 32bits timestamp
4186 *
4187 * Returns 0 on success or error on failure
4188 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304189int q6asm_run(struct audio_client *ac, uint32_t flags,
4190 uint32_t msw_ts, uint32_t lsw_ts)
4191{
4192 struct asm_session_cmd_run_v2 run;
4193 int rc;
4194
4195 if (ac == NULL) {
4196 pr_err("%s: APR handle NULL\n", __func__);
4197 return -EINVAL;
4198 }
4199 if (ac->apr == NULL) {
4200 pr_err("%s: AC APR handle NULL\n", __func__);
4201 return -EINVAL;
4202 }
4203 pr_debug("%s: session[%d]\n", __func__, ac->session);
4204
4205 q6asm_add_hdr(ac, &run.hdr, sizeof(run), TRUE);
4206 atomic_set(&ac->cmd_state, -1);
4207
4208 run.hdr.opcode = ASM_SESSION_CMD_RUN_V2;
4209 run.flags = flags;
4210 run.time_lsw = lsw_ts;
4211 run.time_msw = msw_ts;
4212
4213 config_debug_fs_run();
4214
4215 rc = apr_send_pkt(ac->apr, (uint32_t *) &run);
4216 if (rc < 0) {
4217 pr_err("%s: Commmand run failed[%d]",
4218 __func__, rc);
4219 rc = -EINVAL;
4220 goto fail_cmd;
4221 }
4222
4223 rc = wait_event_timeout(ac->cmd_wait,
4224 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4225 if (!rc) {
4226 pr_err("%s: timeout. waited for run success",
4227 __func__);
4228 rc = -ETIMEDOUT;
4229 goto fail_cmd;
4230 }
4231 if (atomic_read(&ac->cmd_state) > 0) {
4232 pr_err("%s: DSP returned error[%s]\n",
4233 __func__, adsp_err_get_err_str(
4234 atomic_read(&ac->cmd_state)));
4235 rc = adsp_err_get_lnx_err_code(
4236 atomic_read(&ac->cmd_state));
4237 goto fail_cmd;
4238 }
4239
4240 return 0;
4241fail_cmd:
4242 return rc;
4243}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304244EXPORT_SYMBOL(q6asm_run);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304245
4246static int __q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
4247 uint32_t msw_ts, uint32_t lsw_ts, uint32_t stream_id)
4248{
4249 struct asm_session_cmd_run_v2 run;
4250 int rc;
4251
4252 if (ac == NULL) {
4253 pr_err("%s: APR handle NULL\n", __func__);
4254 return -EINVAL;
4255 }
4256 if (ac->apr == NULL) {
4257 pr_err("%s: AC APR handle NULL\n", __func__);
4258 return -EINVAL;
4259 }
4260 pr_debug("%s: session[%d]\n", __func__, ac->session);
4261
4262 q6asm_stream_add_hdr_async(ac, &run.hdr, sizeof(run), TRUE, stream_id);
4263 atomic_set(&ac->cmd_state, 1);
4264 run.hdr.opcode = ASM_SESSION_CMD_RUN_V2;
4265 run.flags = flags;
4266 run.time_lsw = lsw_ts;
4267 run.time_msw = msw_ts;
4268
4269 rc = apr_send_pkt(ac->apr, (uint32_t *) &run);
4270 if (rc < 0) {
4271 pr_err("%s: Commmand run failed[%d]", __func__, rc);
4272 return -EINVAL;
4273 }
4274 return 0;
4275}
4276
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304277/**
4278 * q6asm_run_nowait -
4279 * command to set ASM to run state with no wait for ack
4280 *
4281 * @ac: Audio client handle
4282 * @flags: Flags for session
4283 * @msw_ts: upper 32bits timestamp
4284 * @lsw_ts: lower 32bits timestamp
4285 *
4286 * Returns 0 on success or error on failure
4287 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304288int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
4289 uint32_t msw_ts, uint32_t lsw_ts)
4290{
4291 return __q6asm_run_nowait(ac, flags, msw_ts, lsw_ts, ac->stream_id);
4292}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304293EXPORT_SYMBOL(q6asm_run_nowait);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304294
4295int q6asm_stream_run_nowait(struct audio_client *ac, uint32_t flags,
4296 uint32_t msw_ts, uint32_t lsw_ts, uint32_t stream_id)
4297{
4298 return __q6asm_run_nowait(ac, flags, msw_ts, lsw_ts, stream_id);
4299}
4300
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304301/**
4302 * q6asm_enc_cfg_blk_aac -
4303 * command to set encode cfg block for aac
4304 *
4305 * @ac: Audio client handle
4306 * @frames_per_buf: number of frames per buffer
4307 * @sample_rate: Sample rate
4308 * @channels: number of ASM channels
4309 * @bit_rate: Bit rate info
4310 * @mode: mode of AAC stream encode
4311 * @format: aac format flag
4312 *
4313 * Returns 0 on success or error on failure
4314 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304315int q6asm_enc_cfg_blk_aac(struct audio_client *ac,
4316 uint32_t frames_per_buf,
4317 uint32_t sample_rate, uint32_t channels,
4318 uint32_t bit_rate, uint32_t mode, uint32_t format)
4319{
4320 struct asm_aac_enc_cfg_v2 enc_cfg;
4321 int rc = 0;
4322
4323 pr_debug("%s: session[%d]frames[%d]SR[%d]ch[%d]bitrate[%d]mode[%d] format[%d]\n",
4324 __func__, ac->session, frames_per_buf,
4325 sample_rate, channels, bit_rate, mode, format);
4326
4327 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
4328 atomic_set(&ac->cmd_state, -1);
4329
4330 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4331 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
4332 enc_cfg.encdec.param_size = sizeof(struct asm_aac_enc_cfg_v2) -
4333 sizeof(struct asm_stream_cmd_set_encdec_param);
4334 enc_cfg.encblk.frames_per_buf = frames_per_buf;
4335 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
4336 sizeof(struct asm_enc_cfg_blk_param_v2);
4337 enc_cfg.bit_rate = bit_rate;
4338 enc_cfg.enc_mode = mode;
4339 enc_cfg.aac_fmt_flag = format;
4340 enc_cfg.channel_cfg = channels;
4341 enc_cfg.sample_rate = sample_rate;
4342
4343 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
4344 if (rc < 0) {
4345 pr_err("%s: Comamnd %d failed %d\n",
4346 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
4347 rc = -EINVAL;
4348 goto fail_cmd;
4349 }
4350 rc = wait_event_timeout(ac->cmd_wait,
4351 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4352 if (!rc) {
4353 pr_err("%s: timeout. waited for FORMAT_UPDATE\n",
4354 __func__);
4355 rc = -ETIMEDOUT;
4356 goto fail_cmd;
4357 }
4358 if (atomic_read(&ac->cmd_state) > 0) {
4359 pr_err("%s: DSP returned error[%s]\n",
4360 __func__, adsp_err_get_err_str(
4361 atomic_read(&ac->cmd_state)));
4362 rc = adsp_err_get_lnx_err_code(
4363 atomic_read(&ac->cmd_state));
4364 goto fail_cmd;
4365 }
4366 return 0;
4367fail_cmd:
4368 return rc;
4369}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304370EXPORT_SYMBOL(q6asm_enc_cfg_blk_aac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304371
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304372/**
4373 * q6asm_enc_cfg_blk_g711 -
4374 * command to set encode cfg block for g711
4375 *
4376 * @ac: Audio client handle
4377 * @frames_per_buf: number of frames per buffer
4378 * @sample_rate: Sample rate
4379 *
4380 * Returns 0 on success or error on failure
4381 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304382int q6asm_enc_cfg_blk_g711(struct audio_client *ac,
4383 uint32_t frames_per_buf,
4384 uint32_t sample_rate)
4385{
4386 struct asm_g711_enc_cfg_v2 enc_cfg;
4387 int rc = 0;
4388
4389 pr_debug("%s: session[%d]frames[%d]SR[%d]\n",
4390 __func__, ac->session, frames_per_buf,
4391 sample_rate);
4392
4393 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
4394 atomic_set(&ac->cmd_state, -1);
4395
4396 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4397 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
4398 enc_cfg.encdec.param_size = sizeof(struct asm_g711_enc_cfg_v2) -
4399 sizeof(struct asm_stream_cmd_set_encdec_param);
4400 enc_cfg.encblk.frames_per_buf = frames_per_buf;
4401 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
4402 sizeof(struct asm_enc_cfg_blk_param_v2);
4403 enc_cfg.sample_rate = sample_rate;
4404
4405 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
4406 if (rc < 0) {
4407 pr_err("%s: Comamnd %d failed %d\n",
4408 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
4409 rc = -EINVAL;
4410 goto fail_cmd;
4411 }
4412 rc = wait_event_timeout(ac->cmd_wait,
4413 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4414 if (!rc) {
4415 pr_err("%s: timeout. waited for FORMAT_UPDATE\n",
4416 __func__);
4417 rc = -ETIMEDOUT;
4418 goto fail_cmd;
4419 }
4420 if (atomic_read(&ac->cmd_state) > 0) {
4421 pr_err("%s: DSP returned error[%s]\n",
4422 __func__, adsp_err_get_err_str(
4423 atomic_read(&ac->cmd_state)));
4424 rc = adsp_err_get_lnx_err_code(
4425 atomic_read(&ac->cmd_state));
4426 goto fail_cmd;
4427 }
4428 return 0;
4429fail_cmd:
4430 return rc;
4431}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304432EXPORT_SYMBOL(q6asm_enc_cfg_blk_g711);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304433
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304434/**
4435 * q6asm_set_encdec_chan_map -
4436 * command to set encdec channel map
4437 *
4438 * @ac: Audio client handle
4439 * @channels: number of channels
4440 *
4441 * Returns 0 on success or error on failure
4442 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304443int q6asm_set_encdec_chan_map(struct audio_client *ac,
4444 uint32_t num_channels)
4445{
4446 struct asm_dec_out_chan_map_param chan_map;
4447 u8 *channel_mapping;
4448 int rc = 0;
4449
Rohit kumar6a14cfb2019-02-04 11:22:49 +05304450 if (num_channels > MAX_CHAN_MAP_CHANNELS) {
4451 pr_err("%s: Invalid channel count %d\n", __func__,
4452 num_channels);
4453 return -EINVAL;
4454 }
4455
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304456 pr_debug("%s: Session %d, num_channels = %d\n",
4457 __func__, ac->session, num_channels);
4458 q6asm_add_hdr(ac, &chan_map.hdr, sizeof(chan_map), TRUE);
4459 atomic_set(&ac->cmd_state, -1);
4460 chan_map.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4461 chan_map.encdec.param_id = ASM_PARAM_ID_DEC_OUTPUT_CHAN_MAP;
4462 chan_map.encdec.param_size = sizeof(struct asm_dec_out_chan_map_param) -
4463 (sizeof(struct apr_hdr) +
4464 sizeof(struct asm_stream_cmd_set_encdec_param));
4465 chan_map.num_channels = num_channels;
4466 channel_mapping = chan_map.channel_mapping;
4467 memset(channel_mapping, PCM_CHANNEL_NULL, MAX_CHAN_MAP_CHANNELS);
4468
4469 if (q6asm_map_channels(channel_mapping, num_channels, false)) {
4470 pr_err("%s: map channels failed %d\n", __func__, num_channels);
4471 return -EINVAL;
4472 }
4473
4474 rc = apr_send_pkt(ac->apr, (uint32_t *) &chan_map);
4475 if (rc < 0) {
4476 pr_err("%s: Command opcode[0x%x]paramid[0x%x] failed %d\n",
4477 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM,
4478 ASM_PARAM_ID_DEC_OUTPUT_CHAN_MAP, rc);
4479 goto fail_cmd;
4480 }
4481 rc = wait_event_timeout(ac->cmd_wait,
4482 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4483 if (!rc) {
4484 pr_err("%s: timeout opcode[0x%x]\n", __func__,
4485 chan_map.hdr.opcode);
4486 rc = -ETIMEDOUT;
4487 goto fail_cmd;
4488 }
4489 if (atomic_read(&ac->cmd_state) > 0) {
4490 pr_err("%s: DSP returned error[%s]\n",
4491 __func__, adsp_err_get_err_str(
4492 atomic_read(&ac->cmd_state)));
4493 rc = adsp_err_get_lnx_err_code(
4494 atomic_read(&ac->cmd_state));
4495 goto fail_cmd;
4496 }
4497 return 0;
4498fail_cmd:
4499 return rc;
4500}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304501EXPORT_SYMBOL(q6asm_set_encdec_chan_map);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304502
4503/*
4504 * q6asm_enc_cfg_blk_pcm_v4 - sends encoder configuration parameters
4505 *
4506 * @ac: Client session handle
4507 * @rate: sample rate
4508 * @channels: number of channels
4509 * @bits_per_sample: bit width of encoder session
4510 * @use_default_chmap: true if default channel map to be used
4511 * @use_back_flavor: to configure back left and right channel
4512 * @channel_map: input channel map
4513 * @sample_word_size: Size in bits of the word that holds a sample of a channel
4514 * @endianness: endianness of the pcm data
4515 * @mode: Mode to provide additional info about the pcm input data
4516 */
4517int q6asm_enc_cfg_blk_pcm_v4(struct audio_client *ac,
4518 uint32_t rate, uint32_t channels,
4519 uint16_t bits_per_sample, bool use_default_chmap,
4520 bool use_back_flavor, u8 *channel_map,
4521 uint16_t sample_word_size, uint16_t endianness,
4522 uint16_t mode)
4523{
4524 struct asm_multi_channel_pcm_enc_cfg_v4 enc_cfg;
4525 struct asm_enc_cfg_blk_param_v2 enc_fg_blk;
4526 u8 *channel_mapping;
4527 u32 frames_per_buf = 0;
4528 int rc;
4529
4530 if (!use_default_chmap && (channel_map == NULL)) {
4531 pr_err("%s: No valid chan map and can't use default\n",
4532 __func__);
4533 rc = -EINVAL;
4534 goto fail_cmd;
4535 }
4536
Rohit kumar6a14cfb2019-02-04 11:22:49 +05304537 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
4538 pr_err("%s: Invalid channel count %d\n", __func__, channels);
4539 rc = -EINVAL;
4540 goto fail_cmd;
4541 }
4542
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304543 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
4544 ac->session, rate, channels,
4545 bits_per_sample, sample_word_size);
4546
4547 memset(&enc_cfg, 0, sizeof(enc_cfg));
4548 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
4549 atomic_set(&ac->cmd_state, -1);
4550 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4551 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
4552 enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
4553 sizeof(enc_cfg.encdec);
4554 enc_cfg.encblk.frames_per_buf = frames_per_buf;
4555 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
4556 sizeof(enc_fg_blk);
4557 enc_cfg.num_channels = channels;
4558 enc_cfg.bits_per_sample = bits_per_sample;
4559 enc_cfg.sample_rate = rate;
4560 enc_cfg.is_signed = 1;
4561 enc_cfg.sample_word_size = sample_word_size;
4562 enc_cfg.endianness = endianness;
4563 enc_cfg.mode = mode;
4564 channel_mapping = enc_cfg.channel_mapping;
4565
4566 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
4567
4568 if (use_default_chmap) {
4569 pr_debug("%s: setting default channel map for %d channels",
4570 __func__, channels);
4571 if (q6asm_map_channels(channel_mapping, channels,
4572 use_back_flavor)) {
4573 pr_err("%s: map channels failed %d\n",
4574 __func__, channels);
4575 rc = -EINVAL;
4576 goto fail_cmd;
4577 }
4578 } else {
4579 pr_debug("%s: Using pre-defined channel map", __func__);
4580 memcpy(channel_mapping, channel_map,
4581 PCM_FORMAT_MAX_NUM_CHANNEL);
4582 }
4583
4584 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
4585 if (rc < 0) {
4586 pr_err("%s: Command open failed %d\n", __func__, rc);
4587 goto fail_cmd;
4588 }
4589 rc = wait_event_timeout(ac->cmd_wait,
4590 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4591 if (!rc) {
4592 pr_err("%s: timeout opcode[0x%x]\n",
4593 __func__, enc_cfg.hdr.opcode);
4594 rc = -ETIMEDOUT;
4595 goto fail_cmd;
4596 }
4597 if (atomic_read(&ac->cmd_state) > 0) {
4598 pr_err("%s: DSP returned error[%s]\n",
4599 __func__, adsp_err_get_err_str(
4600 atomic_read(&ac->cmd_state)));
4601 rc = adsp_err_get_lnx_err_code(
4602 atomic_read(&ac->cmd_state));
4603 goto fail_cmd;
4604 }
4605 return 0;
4606fail_cmd:
4607 return rc;
4608}
4609EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_v4);
4610
4611/*
4612 * q6asm_enc_cfg_blk_pcm_v3 - sends encoder configuration parameters
4613 *
4614 * @ac: Client session handle
4615 * @rate: sample rate
4616 * @channels: number of channels
4617 * @bits_per_sample: bit width of encoder session
4618 * @use_default_chmap: true if default channel map to be used
4619 * @use_back_flavor: to configure back left and right channel
4620 * @channel_map: input channel map
4621 * @sample_word_size: Size in bits of the word that holds a sample of a channel
4622 */
4623int q6asm_enc_cfg_blk_pcm_v3(struct audio_client *ac,
4624 uint32_t rate, uint32_t channels,
4625 uint16_t bits_per_sample, bool use_default_chmap,
4626 bool use_back_flavor, u8 *channel_map,
4627 uint16_t sample_word_size)
4628{
4629 struct asm_multi_channel_pcm_enc_cfg_v3 enc_cfg;
4630 struct asm_enc_cfg_blk_param_v2 enc_fg_blk;
4631 u8 *channel_mapping;
4632 u32 frames_per_buf = 0;
4633 int rc;
4634
4635 if (!use_default_chmap && (channel_map == NULL)) {
4636 pr_err("%s: No valid chan map and can't use default\n",
4637 __func__);
4638 rc = -EINVAL;
4639 goto fail_cmd;
4640 }
4641
Rohit kumar6a14cfb2019-02-04 11:22:49 +05304642 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
4643 pr_err("%s: Invalid channel count %d\n", __func__, channels);
4644 rc = -EINVAL;
4645 goto fail_cmd;
4646 }
4647
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304648 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
4649 ac->session, rate, channels,
4650 bits_per_sample, sample_word_size);
4651
4652 memset(&enc_cfg, 0, sizeof(enc_cfg));
4653 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
4654 atomic_set(&ac->cmd_state, -1);
4655 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4656 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
4657 enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
4658 sizeof(enc_cfg.encdec);
4659 enc_cfg.encblk.frames_per_buf = frames_per_buf;
4660 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
4661 sizeof(enc_fg_blk);
4662 enc_cfg.num_channels = channels;
4663 enc_cfg.bits_per_sample = bits_per_sample;
4664 enc_cfg.sample_rate = rate;
4665 enc_cfg.is_signed = 1;
4666 enc_cfg.sample_word_size = sample_word_size;
4667 channel_mapping = enc_cfg.channel_mapping;
4668
4669 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
4670
4671 if (use_default_chmap) {
4672 pr_debug("%s: setting default channel map for %d channels",
4673 __func__, channels);
4674 if (q6asm_map_channels(channel_mapping, channels,
4675 use_back_flavor)) {
4676 pr_err("%s: map channels failed %d\n",
4677 __func__, channels);
4678 rc = -EINVAL;
4679 goto fail_cmd;
4680 }
4681 } else {
4682 pr_debug("%s: Using pre-defined channel map", __func__);
4683 memcpy(channel_mapping, channel_map,
4684 PCM_FORMAT_MAX_NUM_CHANNEL);
4685 }
4686
4687 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
4688 if (rc < 0) {
4689 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
4690 goto fail_cmd;
4691 }
4692 rc = wait_event_timeout(ac->cmd_wait,
4693 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4694 if (!rc) {
4695 pr_err("%s: timeout opcode[0x%x]\n",
4696 __func__, enc_cfg.hdr.opcode);
4697 rc = -ETIMEDOUT;
4698 goto fail_cmd;
4699 }
4700 if (atomic_read(&ac->cmd_state) > 0) {
4701 pr_err("%s: DSP returned error[%s]\n",
4702 __func__, adsp_err_get_err_str(
4703 atomic_read(&ac->cmd_state)));
4704 rc = adsp_err_get_lnx_err_code(
4705 atomic_read(&ac->cmd_state));
4706 goto fail_cmd;
4707 }
4708 return 0;
4709fail_cmd:
4710 return rc;
4711}
4712EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_v3);
4713
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304714/**
4715 * q6asm_enc_cfg_blk_pcm_v2 -
4716 * command to set encode config block for pcm_v2
4717 *
4718 * @ac: Audio client handle
4719 * @rate: sample rate
4720 * @channels: number of channels
4721 * @bits_per_sample: number of bits per sample
4722 * @use_default_chmap: Flag indicating to use default ch_map or not
4723 * @use_back_flavor: back flavor flag
4724 * @channel_map: Custom channel map settings
4725 *
4726 * Returns 0 on success or error on failure
4727 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304728int q6asm_enc_cfg_blk_pcm_v2(struct audio_client *ac,
4729 uint32_t rate, uint32_t channels, uint16_t bits_per_sample,
4730 bool use_default_chmap, bool use_back_flavor, u8 *channel_map)
4731{
4732 struct asm_multi_channel_pcm_enc_cfg_v2 enc_cfg;
4733 u8 *channel_mapping;
4734 u32 frames_per_buf = 0;
4735
4736 int rc = 0;
4737
4738 if (!use_default_chmap && (channel_map == NULL)) {
4739 pr_err("%s: No valid chan map and can't use default\n",
4740 __func__);
4741 return -EINVAL;
4742 }
4743
Rohit kumar6a14cfb2019-02-04 11:22:49 +05304744 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
4745 pr_err("%s: Invalid channel count %d\n", __func__, channels);
4746 return -EINVAL;
4747 }
4748
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304749 pr_debug("%s: Session %d, rate = %d, channels = %d\n", __func__,
4750 ac->session, rate, channels);
4751
4752 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
4753 atomic_set(&ac->cmd_state, -1);
4754 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4755 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
4756 enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
4757 sizeof(enc_cfg.encdec);
4758 enc_cfg.encblk.frames_per_buf = frames_per_buf;
4759 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
4760 sizeof(struct asm_enc_cfg_blk_param_v2);
4761
4762 enc_cfg.num_channels = channels;
4763 enc_cfg.bits_per_sample = bits_per_sample;
4764 enc_cfg.sample_rate = rate;
4765 enc_cfg.is_signed = 1;
4766 channel_mapping = enc_cfg.channel_mapping;
4767
4768 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
4769
4770 if (use_default_chmap) {
4771 pr_debug("%s: setting default channel map for %d channels",
4772 __func__, channels);
4773 if (q6asm_map_channels(channel_mapping, channels,
4774 use_back_flavor)) {
4775 pr_err("%s: map channels failed %d\n",
4776 __func__, channels);
4777 return -EINVAL;
4778 }
4779 } else {
4780 pr_debug("%s: Using pre-defined channel map", __func__);
4781 memcpy(channel_mapping, channel_map,
4782 PCM_FORMAT_MAX_NUM_CHANNEL);
4783 }
4784
4785 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
4786 if (rc < 0) {
4787 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
4788 rc = -EINVAL;
4789 goto fail_cmd;
4790 }
4791 rc = wait_event_timeout(ac->cmd_wait,
4792 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4793 if (!rc) {
4794 pr_err("%s: timeout opcode[0x%x]\n",
4795 __func__, enc_cfg.hdr.opcode);
4796 rc = -ETIMEDOUT;
4797 goto fail_cmd;
4798 }
4799 if (atomic_read(&ac->cmd_state) > 0) {
4800 pr_err("%s: DSP returned error[%s]\n",
4801 __func__, adsp_err_get_err_str(
4802 atomic_read(&ac->cmd_state)));
4803 rc = adsp_err_get_lnx_err_code(
4804 atomic_read(&ac->cmd_state));
4805 goto fail_cmd;
4806 }
4807 return 0;
4808fail_cmd:
4809 return rc;
4810}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304811EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_v2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304812
4813static int __q6asm_enc_cfg_blk_pcm_v4(struct audio_client *ac,
4814 uint32_t rate, uint32_t channels,
4815 uint16_t bits_per_sample,
4816 uint16_t sample_word_size,
4817 uint16_t endianness,
4818 uint16_t mode)
4819{
4820 return q6asm_enc_cfg_blk_pcm_v4(ac, rate, channels,
4821 bits_per_sample, true, false, NULL,
4822 sample_word_size, endianness, mode);
4823}
4824
4825static int __q6asm_enc_cfg_blk_pcm_v3(struct audio_client *ac,
4826 uint32_t rate, uint32_t channels,
4827 uint16_t bits_per_sample,
4828 uint16_t sample_word_size)
4829{
4830 return q6asm_enc_cfg_blk_pcm_v3(ac, rate, channels,
4831 bits_per_sample, true, false, NULL,
4832 sample_word_size);
4833}
4834
4835static int __q6asm_enc_cfg_blk_pcm(struct audio_client *ac,
4836 uint32_t rate, uint32_t channels, uint16_t bits_per_sample)
4837{
4838 return q6asm_enc_cfg_blk_pcm_v2(ac, rate, channels,
4839 bits_per_sample, true, false, NULL);
4840}
4841
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304842/**
4843 * q6asm_enc_cfg_blk_pcm -
4844 * command to set encode config block for pcm
4845 *
4846 * @ac: Audio client handle
4847 * @rate: sample rate
4848 * @channels: number of channels
4849 *
4850 * Returns 0 on success or error on failure
4851 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304852int q6asm_enc_cfg_blk_pcm(struct audio_client *ac,
4853 uint32_t rate, uint32_t channels)
4854{
4855 return __q6asm_enc_cfg_blk_pcm(ac, rate, channels, 16);
4856}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304857EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304858
4859int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
4860 uint32_t rate, uint32_t channels, uint16_t bits_per_sample)
4861{
4862 return __q6asm_enc_cfg_blk_pcm(ac, rate, channels, bits_per_sample);
4863}
4864
4865/*
4866 * q6asm_enc_cfg_blk_pcm_format_support_v3 - sends encoder configuration
4867 * parameters
4868 *
4869 * @ac: Client session handle
4870 * @rate: sample rate
4871 * @channels: number of channels
4872 * @bits_per_sample: bit width of encoder session
4873 * @sample_word_size: Size in bits of the word that holds a sample of a channel
4874 */
4875int q6asm_enc_cfg_blk_pcm_format_support_v3(struct audio_client *ac,
4876 uint32_t rate, uint32_t channels,
4877 uint16_t bits_per_sample,
4878 uint16_t sample_word_size)
4879{
4880 return __q6asm_enc_cfg_blk_pcm_v3(ac, rate, channels,
4881 bits_per_sample, sample_word_size);
4882}
4883EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_format_support_v3);
4884
4885/*
4886 * q6asm_enc_cfg_blk_pcm_format_support_v4 - sends encoder configuration
4887 * parameters
4888 *
4889 * @ac: Client session handle
4890 * @rate: sample rate
4891 * @channels: number of channels
4892 * @bits_per_sample: bit width of encoder session
4893 * @sample_word_size: Size in bits of the word that holds a sample of a channel
4894 * @endianness: endianness of the pcm data
4895 * @mode: Mode to provide additional info about the pcm input data
4896 */
4897int q6asm_enc_cfg_blk_pcm_format_support_v4(struct audio_client *ac,
4898 uint32_t rate, uint32_t channels,
4899 uint16_t bits_per_sample,
4900 uint16_t sample_word_size,
4901 uint16_t endianness,
4902 uint16_t mode)
4903{
4904 return __q6asm_enc_cfg_blk_pcm_v4(ac, rate, channels,
4905 bits_per_sample, sample_word_size,
4906 endianness, mode);
4907}
4908EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_format_support_v4);
4909
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304910/**
4911 * q6asm_enc_cfg_blk_pcm_native -
4912 * command to set encode config block for pcm_native
4913 *
4914 * @ac: Audio client handle
4915 * @rate: sample rate
4916 * @channels: number of channels
4917 *
4918 * Returns 0 on success or error on failure
4919 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304920int q6asm_enc_cfg_blk_pcm_native(struct audio_client *ac,
4921 uint32_t rate, uint32_t channels)
4922{
4923 struct asm_multi_channel_pcm_enc_cfg_v2 enc_cfg;
4924 u8 *channel_mapping;
4925 u32 frames_per_buf = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304926 int rc = 0;
4927
Rohit kumar6a14cfb2019-02-04 11:22:49 +05304928 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
4929 pr_err("%s: Invalid channel count %d\n", __func__, channels);
4930 return -EINVAL;
4931 }
4932
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304933 pr_debug("%s: Session %d, rate = %d, channels = %d\n", __func__,
4934 ac->session, rate, channels);
4935
4936 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
4937 atomic_set(&ac->cmd_state, -1);
4938 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4939 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
4940 enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
4941 sizeof(enc_cfg.encdec);
4942 enc_cfg.encblk.frames_per_buf = frames_per_buf;
4943 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
4944 sizeof(struct asm_enc_cfg_blk_param_v2);
4945
4946 enc_cfg.num_channels = 0;/*channels;*/
4947 enc_cfg.bits_per_sample = 16;
4948 enc_cfg.sample_rate = 0;/*rate;*/
4949 enc_cfg.is_signed = 1;
4950 channel_mapping = enc_cfg.channel_mapping;
4951
4952
4953 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
4954
4955 if (q6asm_map_channels(channel_mapping, channels, false)) {
4956 pr_err("%s: map channels failed %d\n", __func__, channels);
4957 return -EINVAL;
4958 }
4959
4960 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
4961 if (rc < 0) {
4962 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
4963 rc = -EINVAL;
4964 goto fail_cmd;
4965 }
4966 rc = wait_event_timeout(ac->cmd_wait,
4967 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4968 if (!rc) {
4969 pr_err("%s: timeout opcode[0x%x]\n",
4970 __func__, enc_cfg.hdr.opcode);
4971 rc = -ETIMEDOUT;
4972 goto fail_cmd;
4973 }
4974 if (atomic_read(&ac->cmd_state) > 0) {
4975 pr_err("%s: DSP returned error[%s]\n",
4976 __func__, adsp_err_get_err_str(
4977 atomic_read(&ac->cmd_state)));
4978 rc = adsp_err_get_lnx_err_code(
4979 atomic_read(&ac->cmd_state));
4980 goto fail_cmd;
4981 }
4982 return 0;
4983fail_cmd:
4984 return rc;
4985}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304986EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_native);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304987
4988static int q6asm_map_channels(u8 *channel_mapping, uint32_t channels,
4989 bool use_back_flavor)
4990{
4991 u8 *lchannel_mapping;
4992
4993 lchannel_mapping = channel_mapping;
4994 pr_debug("%s: channels passed: %d\n", __func__, channels);
4995 if (channels == 1) {
4996 lchannel_mapping[0] = PCM_CHANNEL_FC;
4997 } else if (channels == 2) {
4998 lchannel_mapping[0] = PCM_CHANNEL_FL;
4999 lchannel_mapping[1] = PCM_CHANNEL_FR;
5000 } else if (channels == 3) {
5001 lchannel_mapping[0] = PCM_CHANNEL_FL;
5002 lchannel_mapping[1] = PCM_CHANNEL_FR;
5003 lchannel_mapping[2] = PCM_CHANNEL_FC;
5004 } else if (channels == 4) {
5005 lchannel_mapping[0] = PCM_CHANNEL_FL;
5006 lchannel_mapping[1] = PCM_CHANNEL_FR;
5007 lchannel_mapping[2] = use_back_flavor ?
5008 PCM_CHANNEL_LB : PCM_CHANNEL_LS;
5009 lchannel_mapping[3] = use_back_flavor ?
5010 PCM_CHANNEL_RB : PCM_CHANNEL_RS;
5011 } else if (channels == 5) {
5012 lchannel_mapping[0] = PCM_CHANNEL_FL;
5013 lchannel_mapping[1] = PCM_CHANNEL_FR;
5014 lchannel_mapping[2] = PCM_CHANNEL_FC;
5015 lchannel_mapping[3] = use_back_flavor ?
5016 PCM_CHANNEL_LB : PCM_CHANNEL_LS;
5017 lchannel_mapping[4] = use_back_flavor ?
5018 PCM_CHANNEL_RB : PCM_CHANNEL_RS;
5019 } else if (channels == 6) {
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] = use_back_flavor ?
5025 PCM_CHANNEL_LB : PCM_CHANNEL_LS;
5026 lchannel_mapping[5] = use_back_flavor ?
5027 PCM_CHANNEL_RB : PCM_CHANNEL_RS;
5028 } else if (channels == 7) {
5029 /*
5030 * Configured for 5.1 channel mapping + 1 channel for debug
5031 * Can be customized based on DSP.
5032 */
5033 lchannel_mapping[0] = PCM_CHANNEL_FL;
5034 lchannel_mapping[1] = PCM_CHANNEL_FR;
5035 lchannel_mapping[2] = PCM_CHANNEL_FC;
5036 lchannel_mapping[3] = PCM_CHANNEL_LFE;
5037 lchannel_mapping[4] = use_back_flavor ?
5038 PCM_CHANNEL_LB : PCM_CHANNEL_LS;
5039 lchannel_mapping[5] = use_back_flavor ?
5040 PCM_CHANNEL_RB : PCM_CHANNEL_RS;
5041 lchannel_mapping[6] = PCM_CHANNEL_CS;
5042 } else if (channels == 8) {
5043 lchannel_mapping[0] = PCM_CHANNEL_FL;
5044 lchannel_mapping[1] = PCM_CHANNEL_FR;
5045 lchannel_mapping[2] = PCM_CHANNEL_FC;
5046 lchannel_mapping[3] = PCM_CHANNEL_LFE;
5047 lchannel_mapping[4] = PCM_CHANNEL_LB;
5048 lchannel_mapping[5] = PCM_CHANNEL_RB;
5049 lchannel_mapping[6] = PCM_CHANNEL_LS;
5050 lchannel_mapping[7] = PCM_CHANNEL_RS;
5051 } else {
5052 pr_err("%s: ERROR.unsupported num_ch = %u\n",
5053 __func__, channels);
5054 return -EINVAL;
5055 }
5056 return 0;
5057}
5058
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305059/**
5060 * q6asm_enable_sbrps -
5061 * command to enable sbrps for ASM
5062 *
5063 * @ac: Audio client handle
5064 * @sbr_ps_enable: flag for sbr_ps enable or disable
5065 *
5066 * Returns 0 on success or error on failure
5067 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305068int q6asm_enable_sbrps(struct audio_client *ac,
5069 uint32_t sbr_ps_enable)
5070{
5071 struct asm_aac_sbr_ps_flag_param sbrps;
5072 u32 frames_per_buf = 0;
5073
5074 int rc = 0;
5075
5076 pr_debug("%s: Session %d\n", __func__, ac->session);
5077
5078 q6asm_add_hdr(ac, &sbrps.hdr, sizeof(sbrps), TRUE);
5079 atomic_set(&ac->cmd_state, -1);
5080
5081 sbrps.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
5082 sbrps.encdec.param_id = ASM_PARAM_ID_AAC_SBR_PS_FLAG;
5083 sbrps.encdec.param_size = sizeof(struct asm_aac_sbr_ps_flag_param) -
5084 sizeof(struct asm_stream_cmd_set_encdec_param);
5085 sbrps.encblk.frames_per_buf = frames_per_buf;
5086 sbrps.encblk.enc_cfg_blk_size = sbrps.encdec.param_size -
5087 sizeof(struct asm_enc_cfg_blk_param_v2);
5088
5089 sbrps.sbr_ps_flag = sbr_ps_enable;
5090
5091 rc = apr_send_pkt(ac->apr, (uint32_t *) &sbrps);
5092 if (rc < 0) {
5093 pr_err("%s: Command opcode[0x%x]paramid[0x%x] failed %d\n",
5094 __func__,
5095 ASM_STREAM_CMD_SET_ENCDEC_PARAM,
5096 ASM_PARAM_ID_AAC_SBR_PS_FLAG, rc);
5097 rc = -EINVAL;
5098 goto fail_cmd;
5099 }
5100 rc = wait_event_timeout(ac->cmd_wait,
5101 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5102 if (!rc) {
5103 pr_err("%s: timeout opcode[0x%x] ", __func__, sbrps.hdr.opcode);
5104 rc = -ETIMEDOUT;
5105 goto fail_cmd;
5106 }
5107 if (atomic_read(&ac->cmd_state) > 0) {
5108 pr_err("%s: DSP returned error[%s]\n",
5109 __func__, adsp_err_get_err_str(
5110 atomic_read(&ac->cmd_state)));
5111 rc = adsp_err_get_lnx_err_code(
5112 atomic_read(&ac->cmd_state));
5113 goto fail_cmd;
5114 }
5115 return 0;
5116fail_cmd:
5117 return rc;
5118}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305119EXPORT_SYMBOL(q6asm_enable_sbrps);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305120
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305121/**
5122 * q6asm_cfg_dual_mono_aac -
5123 * command to set config for dual mono aac
5124 *
5125 * @ac: Audio client handle
5126 * @sce_left: left sce val
5127 * @sce_right: right sce val
5128 *
5129 * Returns 0 on success or error on failure
5130 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305131int q6asm_cfg_dual_mono_aac(struct audio_client *ac,
5132 uint16_t sce_left, uint16_t sce_right)
5133{
5134 struct asm_aac_dual_mono_mapping_param dual_mono;
5135
5136 int rc = 0;
5137
5138 pr_debug("%s: Session %d, sce_left = %d, sce_right = %d\n",
5139 __func__, ac->session, sce_left, sce_right);
5140
5141 q6asm_add_hdr(ac, &dual_mono.hdr, sizeof(dual_mono), TRUE);
5142 atomic_set(&ac->cmd_state, -1);
5143
5144 dual_mono.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
5145 dual_mono.encdec.param_id = ASM_PARAM_ID_AAC_DUAL_MONO_MAPPING;
5146 dual_mono.encdec.param_size = sizeof(dual_mono.left_channel_sce) +
5147 sizeof(dual_mono.right_channel_sce);
5148 dual_mono.left_channel_sce = sce_left;
5149 dual_mono.right_channel_sce = sce_right;
5150
5151 rc = apr_send_pkt(ac->apr, (uint32_t *) &dual_mono);
5152 if (rc < 0) {
5153 pr_err("%s: Command opcode[0x%x]paramid[0x%x] failed %d\n",
5154 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM,
5155 ASM_PARAM_ID_AAC_DUAL_MONO_MAPPING, rc);
5156 rc = -EINVAL;
5157 goto fail_cmd;
5158 }
5159 rc = wait_event_timeout(ac->cmd_wait,
5160 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5161 if (!rc) {
5162 pr_err("%s: timeout opcode[0x%x]\n", __func__,
5163 dual_mono.hdr.opcode);
5164 rc = -ETIMEDOUT;
5165 goto fail_cmd;
5166 }
5167 if (atomic_read(&ac->cmd_state) > 0) {
5168 pr_err("%s: DSP returned error[%s]\n",
5169 __func__, adsp_err_get_err_str(
5170 atomic_read(&ac->cmd_state)));
5171 rc = adsp_err_get_lnx_err_code(
5172 atomic_read(&ac->cmd_state));
5173 goto fail_cmd;
5174 }
5175 return 0;
5176fail_cmd:
5177 return rc;
5178}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305179EXPORT_SYMBOL(q6asm_cfg_dual_mono_aac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305180
5181/* Support for selecting stereo mixing coefficients for B family not done */
5182int q6asm_cfg_aac_sel_mix_coef(struct audio_client *ac, uint32_t mix_coeff)
5183{
5184 struct asm_aac_stereo_mix_coeff_selection_param_v2 aac_mix_coeff;
5185 int rc = 0;
5186
5187 q6asm_add_hdr(ac, &aac_mix_coeff.hdr, sizeof(aac_mix_coeff), TRUE);
5188 atomic_set(&ac->cmd_state, -1);
5189 aac_mix_coeff.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
5190 aac_mix_coeff.param_id =
5191 ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG_V2;
5192 aac_mix_coeff.param_size =
5193 sizeof(struct asm_aac_stereo_mix_coeff_selection_param_v2);
5194 aac_mix_coeff.aac_stereo_mix_coeff_flag = mix_coeff;
5195 pr_debug("%s: mix_coeff = %u\n", __func__, mix_coeff);
5196 rc = apr_send_pkt(ac->apr, (uint32_t *) &aac_mix_coeff);
5197 if (rc < 0) {
5198 pr_err("%s: Command opcode[0x%x]paramid[0x%x] failed %d\n",
5199 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM,
5200 ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG_V2,
5201 rc);
5202 rc = -EINVAL;
5203 goto fail_cmd;
5204 }
5205 rc = wait_event_timeout(ac->cmd_wait,
5206 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5207 if (!rc) {
5208 pr_err("%s: timeout opcode[0x%x]\n",
5209 __func__, aac_mix_coeff.hdr.opcode);
5210 rc = -ETIMEDOUT;
5211 goto fail_cmd;
5212 }
5213 if (atomic_read(&ac->cmd_state) > 0) {
5214 pr_err("%s: DSP returned error[%s]\n",
5215 __func__, adsp_err_get_err_str(
5216 atomic_read(&ac->cmd_state)));
5217 rc = adsp_err_get_lnx_err_code(
5218 atomic_read(&ac->cmd_state));
5219 goto fail_cmd;
5220 }
5221 return 0;
5222fail_cmd:
5223 return rc;
5224}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305225EXPORT_SYMBOL(q6asm_cfg_aac_sel_mix_coef);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305226
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305227/**
5228 * q6asm_enc_cfg_blk_qcelp -
5229 * command to set encode config block for QCELP
5230 *
5231 * @ac: Audio client handle
5232 * @frames_per_buf: Number of frames per buffer
5233 * @min_rate: Minimum Enc rate
5234 * @max_rate: Maximum Enc rate
5235 * reduced_rate_level: Reduced rate level
5236 * @rate_modulation_cmd: rate modulation command
5237 *
5238 * Returns 0 on success or error on failure
5239 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305240int q6asm_enc_cfg_blk_qcelp(struct audio_client *ac, uint32_t frames_per_buf,
5241 uint16_t min_rate, uint16_t max_rate,
5242 uint16_t reduced_rate_level, uint16_t rate_modulation_cmd)
5243{
5244 struct asm_v13k_enc_cfg enc_cfg;
5245 int rc = 0;
5246
5247 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",
5248 __func__,
5249 ac->session, frames_per_buf, min_rate, max_rate,
5250 reduced_rate_level, rate_modulation_cmd);
5251
5252 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
5253 atomic_set(&ac->cmd_state, -1);
5254 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
5255 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
5256 enc_cfg.encdec.param_size = sizeof(struct asm_v13k_enc_cfg) -
5257 sizeof(struct asm_stream_cmd_set_encdec_param);
5258 enc_cfg.encblk.frames_per_buf = frames_per_buf;
5259 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
5260 sizeof(struct asm_enc_cfg_blk_param_v2);
5261
5262 enc_cfg.min_rate = min_rate;
5263 enc_cfg.max_rate = max_rate;
5264 enc_cfg.reduced_rate_cmd = reduced_rate_level;
5265 enc_cfg.rate_mod_cmd = rate_modulation_cmd;
5266
5267 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
5268 if (rc < 0) {
5269 pr_err("%s: Comamnd %d failed %d\n",
5270 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
5271 rc = -EINVAL;
5272 goto fail_cmd;
5273 }
5274 rc = wait_event_timeout(ac->cmd_wait,
5275 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5276 if (!rc) {
5277 pr_err("%s: timeout. waited for setencdec v13k resp\n",
5278 __func__);
5279 rc = -ETIMEDOUT;
5280 goto fail_cmd;
5281 }
5282 if (atomic_read(&ac->cmd_state) > 0) {
5283 pr_err("%s: DSP returned error[%s]\n",
5284 __func__, adsp_err_get_err_str(
5285 atomic_read(&ac->cmd_state)));
5286 rc = adsp_err_get_lnx_err_code(
5287 atomic_read(&ac->cmd_state));
5288 goto fail_cmd;
5289 }
5290 return 0;
5291fail_cmd:
5292 return rc;
5293}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305294EXPORT_SYMBOL(q6asm_enc_cfg_blk_qcelp);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305295
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305296/**
5297 * q6asm_enc_cfg_blk_evrc -
5298 * command to set encode config block for EVRC
5299 *
5300 * @ac: Audio client handle
5301 * @frames_per_buf: Number of frames per buffer
5302 * @min_rate: Minimum Enc rate
5303 * @max_rate: Maximum Enc rate
5304 * @rate_modulation_cmd: rate modulation command
5305 *
5306 * Returns 0 on success or error on failure
5307 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305308int q6asm_enc_cfg_blk_evrc(struct audio_client *ac, uint32_t frames_per_buf,
5309 uint16_t min_rate, uint16_t max_rate,
5310 uint16_t rate_modulation_cmd)
5311{
5312 struct asm_evrc_enc_cfg enc_cfg;
5313 int rc = 0;
5314
5315 pr_debug("%s: session[%d]frames[%d]min_rate[0x%4x]max_rate[0x%4x] rate_modulation_cmd[0x%4x]\n",
5316 __func__, ac->session,
5317 frames_per_buf, min_rate, max_rate, rate_modulation_cmd);
5318
5319 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
5320 atomic_set(&ac->cmd_state, -1);
5321 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
5322 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
5323 enc_cfg.encdec.param_size = sizeof(struct asm_evrc_enc_cfg) -
5324 sizeof(struct asm_stream_cmd_set_encdec_param);
5325 enc_cfg.encblk.frames_per_buf = frames_per_buf;
5326 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
5327 sizeof(struct asm_enc_cfg_blk_param_v2);
5328
5329 enc_cfg.min_rate = min_rate;
5330 enc_cfg.max_rate = max_rate;
5331 enc_cfg.rate_mod_cmd = rate_modulation_cmd;
5332 enc_cfg.reserved = 0;
5333
5334 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
5335 if (rc < 0) {
5336 pr_err("%s: Comamnd %d failed %d\n",
5337 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
5338 rc = -EINVAL;
5339 goto fail_cmd;
5340 }
5341 rc = wait_event_timeout(ac->cmd_wait,
5342 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5343 if (!rc) {
5344 pr_err("%s: timeout. waited for encdec evrc\n", __func__);
5345 rc = -ETIMEDOUT;
5346 goto fail_cmd;
5347 }
5348 if (atomic_read(&ac->cmd_state) > 0) {
5349 pr_err("%s: DSP returned error[%s]\n",
5350 __func__, adsp_err_get_err_str(
5351 atomic_read(&ac->cmd_state)));
5352 rc = adsp_err_get_lnx_err_code(
5353 atomic_read(&ac->cmd_state));
5354 goto fail_cmd;
5355 }
5356 return 0;
5357fail_cmd:
5358 return rc;
5359}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305360EXPORT_SYMBOL(q6asm_enc_cfg_blk_evrc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305361
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305362/**
5363 * q6asm_enc_cfg_blk_amrnb -
5364 * command to set encode config block for AMRNB
5365 *
5366 * @ac: Audio client handle
5367 * @frames_per_buf: Number of frames per buffer
5368 * @band_mode: Band mode used
5369 * @dtx_enable: DTX en flag
5370 *
5371 * Returns 0 on success or error on failure
5372 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305373int q6asm_enc_cfg_blk_amrnb(struct audio_client *ac, uint32_t frames_per_buf,
5374 uint16_t band_mode, uint16_t dtx_enable)
5375{
5376 struct asm_amrnb_enc_cfg enc_cfg;
5377 int rc = 0;
5378
5379 pr_debug("%s: session[%d]frames[%d]band_mode[0x%4x]dtx_enable[0x%4x]\n",
5380 __func__, ac->session, frames_per_buf, band_mode, dtx_enable);
5381
5382 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
5383 atomic_set(&ac->cmd_state, -1);
5384 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
5385 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
5386 enc_cfg.encdec.param_size = sizeof(struct asm_amrnb_enc_cfg) -
5387 sizeof(struct asm_stream_cmd_set_encdec_param);
5388 enc_cfg.encblk.frames_per_buf = frames_per_buf;
5389 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
5390 sizeof(struct asm_enc_cfg_blk_param_v2);
5391
5392 enc_cfg.enc_mode = band_mode;
5393 enc_cfg.dtx_mode = dtx_enable;
5394
5395 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
5396 if (rc < 0) {
5397 pr_err("%s: Comamnd %d failed %d\n",
5398 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
5399 rc = -EINVAL;
5400 goto fail_cmd;
5401 }
5402 rc = wait_event_timeout(ac->cmd_wait,
5403 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5404 if (!rc) {
5405 pr_err("%s: timeout. waited for set encdec amrnb\n", __func__);
5406 rc = -ETIMEDOUT;
5407 goto fail_cmd;
5408 }
5409 if (atomic_read(&ac->cmd_state) > 0) {
5410 pr_err("%s: DSP returned error[%s]\n",
5411 __func__, adsp_err_get_err_str(
5412 atomic_read(&ac->cmd_state)));
5413 rc = adsp_err_get_lnx_err_code(
5414 atomic_read(&ac->cmd_state));
5415 goto fail_cmd;
5416 }
5417 return 0;
5418fail_cmd:
5419 return rc;
5420}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305421EXPORT_SYMBOL(q6asm_enc_cfg_blk_amrnb);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305422
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305423/**
5424 * q6asm_enc_cfg_blk_amrwb -
5425 * command to set encode config block for AMRWB
5426 *
5427 * @ac: Audio client handle
5428 * @frames_per_buf: Number of frames per buffer
5429 * @band_mode: Band mode used
5430 * @dtx_enable: DTX en flag
5431 *
5432 * Returns 0 on success or error on failure
5433 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305434int q6asm_enc_cfg_blk_amrwb(struct audio_client *ac, uint32_t frames_per_buf,
5435 uint16_t band_mode, uint16_t dtx_enable)
5436{
5437 struct asm_amrwb_enc_cfg enc_cfg;
5438 int rc = 0;
5439
5440 pr_debug("%s: session[%d]frames[%d]band_mode[0x%4x]dtx_enable[0x%4x]\n",
5441 __func__, ac->session, frames_per_buf, band_mode, dtx_enable);
5442
5443 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
5444 atomic_set(&ac->cmd_state, -1);
5445 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
5446 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
5447 enc_cfg.encdec.param_size = sizeof(struct asm_amrwb_enc_cfg) -
5448 sizeof(struct asm_stream_cmd_set_encdec_param);
5449 enc_cfg.encblk.frames_per_buf = frames_per_buf;
5450 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
5451 sizeof(struct asm_enc_cfg_blk_param_v2);
5452
5453 enc_cfg.enc_mode = band_mode;
5454 enc_cfg.dtx_mode = dtx_enable;
5455
5456 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
5457 if (rc < 0) {
5458 pr_err("%s: Comamnd %d failed %d\n",
5459 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
5460 rc = -EINVAL;
5461 goto fail_cmd;
5462 }
5463 rc = wait_event_timeout(ac->cmd_wait,
5464 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5465 if (!rc) {
5466 pr_err("%s: timeout. waited for FORMAT_UPDATE\n", __func__);
5467 rc = -ETIMEDOUT;
5468 goto fail_cmd;
5469 }
5470 if (atomic_read(&ac->cmd_state) > 0) {
5471 pr_err("%s: DSP returned error[%s]\n",
5472 __func__, adsp_err_get_err_str(
5473 atomic_read(&ac->cmd_state)));
5474 rc = adsp_err_get_lnx_err_code(
5475 atomic_read(&ac->cmd_state));
5476 goto fail_cmd;
5477 }
5478 return 0;
5479fail_cmd:
5480 return rc;
5481}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305482EXPORT_SYMBOL(q6asm_enc_cfg_blk_amrwb);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305483
5484
5485static int __q6asm_media_format_block_pcm(struct audio_client *ac,
5486 uint32_t rate, uint32_t channels,
5487 uint16_t bits_per_sample, int stream_id,
5488 bool use_default_chmap, char *channel_map)
5489{
5490 struct asm_multi_channel_pcm_fmt_blk_v2 fmt;
5491 u8 *channel_mapping;
5492 int rc = 0;
5493
Rohit kumar6a14cfb2019-02-04 11:22:49 +05305494 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
5495 pr_err("%s: Invalid channel count %d\n", __func__, channels);
5496 return -EINVAL;
5497 }
5498
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305499 pr_debug("%s: session[%d]rate[%d]ch[%d]\n", __func__, ac->session, rate,
5500 channels);
5501
5502 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
5503 atomic_set(&ac->cmd_state, -1);
5504 /*
5505 * Updated the token field with stream/session for compressed playback
5506 * Platform driver must know the the stream with which the command is
5507 * associated
5508 */
5509 if (ac->io_mode & COMPRESSED_STREAM_IO)
5510 q6asm_update_token(&fmt.hdr.token,
5511 ac->session,
5512 stream_id,
5513 0, /* Buffer index is NA */
5514 0, /* Direction flag is NA */
5515 WAIT_CMD);
5516
5517 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
5518 __func__, fmt.hdr.token, stream_id, ac->session);
5519
5520 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
5521 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
5522 sizeof(fmt.fmt_blk);
5523 fmt.num_channels = channels;
5524 fmt.bits_per_sample = bits_per_sample;
5525 fmt.sample_rate = rate;
5526 fmt.is_signed = 1;
5527
5528 channel_mapping = fmt.channel_mapping;
5529
5530 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
5531
5532 if (use_default_chmap) {
5533 if (q6asm_map_channels(channel_mapping, channels, false)) {
5534 pr_err("%s: map channels failed %d\n",
5535 __func__, channels);
5536 return -EINVAL;
5537 }
5538 } else {
5539 memcpy(channel_mapping, channel_map,
5540 PCM_FORMAT_MAX_NUM_CHANNEL);
5541 }
5542
5543 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
5544 if (rc < 0) {
5545 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
5546 rc = -EINVAL;
5547 goto fail_cmd;
5548 }
5549 rc = wait_event_timeout(ac->cmd_wait,
5550 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5551 if (!rc) {
5552 pr_err("%s: timeout. waited for format update\n", __func__);
5553 rc = -ETIMEDOUT;
5554 goto fail_cmd;
5555 }
5556 if (atomic_read(&ac->cmd_state) > 0) {
5557 pr_err("%s: DSP returned error[%s]\n",
5558 __func__, adsp_err_get_err_str(
5559 atomic_read(&ac->cmd_state)));
5560 rc = adsp_err_get_lnx_err_code(
5561 atomic_read(&ac->cmd_state));
5562 goto fail_cmd;
5563 }
5564 return 0;
5565fail_cmd:
5566 return rc;
5567}
5568
5569static int __q6asm_media_format_block_pcm_v3(struct audio_client *ac,
5570 uint32_t rate, uint32_t channels,
5571 uint16_t bits_per_sample,
5572 int stream_id,
5573 bool use_default_chmap,
5574 char *channel_map,
5575 uint16_t sample_word_size)
5576{
5577 struct asm_multi_channel_pcm_fmt_blk_param_v3 fmt;
5578 u8 *channel_mapping;
5579 int rc;
5580
Rohit kumar6a14cfb2019-02-04 11:22:49 +05305581 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
5582 pr_err("%s: Invalid channel count %d\n", __func__, channels);
5583 return -EINVAL;
5584 }
5585
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305586 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
5587 ac->session, rate, channels,
5588 bits_per_sample, sample_word_size);
5589
5590 memset(&fmt, 0, sizeof(fmt));
5591 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
5592 atomic_set(&ac->cmd_state, -1);
5593 /*
5594 * Updated the token field with stream/session for compressed playback
5595 * Platform driver must know the the stream with which the command is
5596 * associated
5597 */
5598 if (ac->io_mode & COMPRESSED_STREAM_IO)
5599 fmt.hdr.token = ((ac->session << 8) & 0xFFFF00) |
5600 (stream_id & 0xFF);
5601
5602 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
5603 __func__, fmt.hdr.token, stream_id, ac->session);
5604
5605 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
5606 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
5607 sizeof(fmt.fmt_blk);
5608 fmt.param.num_channels = channels;
5609 fmt.param.bits_per_sample = bits_per_sample;
5610 fmt.param.sample_rate = rate;
5611 fmt.param.is_signed = 1;
5612 fmt.param.sample_word_size = sample_word_size;
5613 channel_mapping = fmt.param.channel_mapping;
5614
5615 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
5616
5617 if (use_default_chmap) {
5618 if (q6asm_map_channels(channel_mapping, channels, false)) {
5619 pr_err("%s: map channels failed %d\n",
5620 __func__, channels);
5621 rc = -EINVAL;
5622 goto fail_cmd;
5623 }
5624 } else {
5625 memcpy(channel_mapping, channel_map,
5626 PCM_FORMAT_MAX_NUM_CHANNEL);
5627 }
5628
5629 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
5630 if (rc < 0) {
5631 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
5632 rc = -EINVAL;
5633 goto fail_cmd;
5634 }
5635 rc = wait_event_timeout(ac->cmd_wait,
5636 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5637 if (!rc) {
5638 pr_err("%s: timeout. waited for format update\n", __func__);
5639 rc = -ETIMEDOUT;
5640 goto fail_cmd;
5641 }
5642 if (atomic_read(&ac->cmd_state) > 0) {
5643 pr_err("%s: DSP returned error[%s]\n",
5644 __func__, adsp_err_get_err_str(
5645 atomic_read(&ac->cmd_state)));
5646 rc = adsp_err_get_lnx_err_code(
5647 atomic_read(&ac->cmd_state));
5648 goto fail_cmd;
5649 }
5650 return 0;
5651fail_cmd:
5652 return rc;
5653}
5654
5655static int __q6asm_media_format_block_pcm_v4(struct audio_client *ac,
5656 uint32_t rate, uint32_t channels,
5657 uint16_t bits_per_sample,
5658 int stream_id,
5659 bool use_default_chmap,
5660 char *channel_map,
5661 uint16_t sample_word_size,
5662 uint16_t endianness,
5663 uint16_t mode)
5664{
5665 struct asm_multi_channel_pcm_fmt_blk_param_v4 fmt;
5666 u8 *channel_mapping;
5667 int rc;
5668
Rohit kumar6a14cfb2019-02-04 11:22:49 +05305669 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
5670 pr_err("%s: Invalid channel count %d\n", __func__, channels);
5671 return -EINVAL;
5672 }
5673
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305674 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
5675 ac->session, rate, channels,
5676 bits_per_sample, sample_word_size);
5677
5678 memset(&fmt, 0, sizeof(fmt));
5679 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
5680 atomic_set(&ac->cmd_state, -1);
5681 /*
5682 * Updated the token field with stream/session for compressed playback
5683 * Platform driver must know the the stream with which the command is
5684 * associated
5685 */
5686 if (ac->io_mode & COMPRESSED_STREAM_IO)
5687 fmt.hdr.token = ((ac->session << 8) & 0xFFFF00) |
5688 (stream_id & 0xFF);
5689
5690 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
5691 __func__, fmt.hdr.token, stream_id, ac->session);
5692
5693 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
5694 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
5695 sizeof(fmt.fmt_blk);
5696 fmt.param.num_channels = channels;
5697 fmt.param.bits_per_sample = bits_per_sample;
5698 fmt.param.sample_rate = rate;
5699 fmt.param.is_signed = 1;
5700 fmt.param.sample_word_size = sample_word_size;
5701 fmt.param.endianness = endianness;
5702 fmt.param.mode = mode;
5703 channel_mapping = fmt.param.channel_mapping;
5704
5705 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
5706
5707 if (use_default_chmap) {
5708 if (q6asm_map_channels(channel_mapping, channels, false)) {
5709 pr_err("%s: map channels failed %d\n",
5710 __func__, channels);
5711 rc = -EINVAL;
5712 goto fail_cmd;
5713 }
5714 } else {
5715 memcpy(channel_mapping, channel_map,
5716 PCM_FORMAT_MAX_NUM_CHANNEL);
5717 }
5718
5719 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
5720 if (rc < 0) {
5721 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
5722 rc = -EINVAL;
5723 goto fail_cmd;
5724 }
5725 rc = wait_event_timeout(ac->cmd_wait,
5726 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5727 if (!rc) {
5728 pr_err("%s: timeout. waited for format update\n", __func__);
5729 rc = -ETIMEDOUT;
5730 goto fail_cmd;
5731 }
5732 if (atomic_read(&ac->cmd_state) > 0) {
5733 pr_err("%s: DSP returned error[%s]\n",
5734 __func__, adsp_err_get_err_str(
5735 atomic_read(&ac->cmd_state)));
5736 rc = adsp_err_get_lnx_err_code(
5737 atomic_read(&ac->cmd_state));
5738 goto fail_cmd;
5739 }
5740 return 0;
5741fail_cmd:
5742 return rc;
5743}
5744
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305745/**
5746 * q6asm_media_format_block_pcm -
5747 * command to set mediafmt block for PCM on ASM stream
5748 *
5749 * @ac: Audio client handle
5750 * @rate: sample rate
5751 * @channels: number of ASM channels
5752 *
5753 * Returns 0 on success or error on failure
5754 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305755int q6asm_media_format_block_pcm(struct audio_client *ac,
5756 uint32_t rate, uint32_t channels)
5757{
5758 return __q6asm_media_format_block_pcm(ac, rate,
5759 channels, 16, ac->stream_id,
5760 true, NULL);
5761}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305762EXPORT_SYMBOL(q6asm_media_format_block_pcm);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305763
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305764/**
5765 * q6asm_media_format_block_pcm_format_support -
5766 * command to set mediafmt block for PCM format support
5767 *
5768 * @ac: Audio client handle
5769 * @rate: sample rate
5770 * @channels: number of ASM channels
5771 * @bits_per_sample: number of bits per sample
5772 *
5773 * Returns 0 on success or error on failure
5774 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305775int q6asm_media_format_block_pcm_format_support(struct audio_client *ac,
5776 uint32_t rate, uint32_t channels,
5777 uint16_t bits_per_sample)
5778{
5779 return __q6asm_media_format_block_pcm(ac, rate,
5780 channels, bits_per_sample, ac->stream_id,
5781 true, NULL);
5782}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305783EXPORT_SYMBOL(q6asm_media_format_block_pcm_format_support);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305784
5785int q6asm_media_format_block_pcm_format_support_v2(struct audio_client *ac,
5786 uint32_t rate, uint32_t channels,
5787 uint16_t bits_per_sample, int stream_id,
5788 bool use_default_chmap, char *channel_map)
5789{
5790 if (!use_default_chmap && (channel_map == NULL)) {
5791 pr_err("%s: No valid chan map and can't use default\n",
5792 __func__);
5793 return -EINVAL;
5794 }
5795 return __q6asm_media_format_block_pcm(ac, rate,
5796 channels, bits_per_sample, stream_id,
5797 use_default_chmap, channel_map);
5798}
5799
5800/*
5801 * q6asm_media_format_block_pcm_format_support_v3- sends pcm decoder
5802 * configuration parameters
5803 *
5804 * @ac: Client session handle
5805 * @rate: sample rate
5806 * @channels: number of channels
5807 * @bits_per_sample: bit width of encoder session
5808 * @stream_id: stream id of stream to be associated with this session
5809 * @use_default_chmap: true if default channel map to be used
5810 * @channel_map: input channel map
5811 * @sample_word_size: Size in bits of the word that holds a sample of a channel
5812 */
5813int q6asm_media_format_block_pcm_format_support_v3(struct audio_client *ac,
5814 uint32_t rate,
5815 uint32_t channels,
5816 uint16_t bits_per_sample,
5817 int stream_id,
5818 bool use_default_chmap,
5819 char *channel_map,
5820 uint16_t sample_word_size)
5821{
5822 if (!use_default_chmap && (channel_map == NULL)) {
5823 pr_err("%s: No valid chan map and can't use default\n",
5824 __func__);
5825 return -EINVAL;
5826 }
5827 return __q6asm_media_format_block_pcm_v3(ac, rate,
5828 channels, bits_per_sample, stream_id,
5829 use_default_chmap, channel_map,
5830 sample_word_size);
5831
5832}
5833EXPORT_SYMBOL(q6asm_media_format_block_pcm_format_support_v3);
5834
5835/*
5836 * q6asm_media_format_block_pcm_format_support_v4- sends pcm decoder
5837 * configuration parameters
5838 *
5839 * @ac: Client session handle
5840 * @rate: sample rate
5841 * @channels: number of channels
5842 * @bits_per_sample: bit width of encoder session
5843 * @stream_id: stream id of stream to be associated with this session
5844 * @use_default_chmap: true if default channel map to be used
5845 * @channel_map: input channel map
5846 * @sample_word_size: Size in bits of the word that holds a sample of a channel
5847 * @endianness: endianness of the pcm data
5848 * @mode: Mode to provide additional info about the pcm input data
5849 */
5850int q6asm_media_format_block_pcm_format_support_v4(struct audio_client *ac,
5851 uint32_t rate,
5852 uint32_t channels,
5853 uint16_t bits_per_sample,
5854 int stream_id,
5855 bool use_default_chmap,
5856 char *channel_map,
5857 uint16_t sample_word_size,
5858 uint16_t endianness,
5859 uint16_t mode)
5860{
5861 if (!use_default_chmap && (channel_map == NULL)) {
5862 pr_err("%s: No valid chan map and can't use default\n",
5863 __func__);
5864 return -EINVAL;
5865 }
5866 return __q6asm_media_format_block_pcm_v4(ac, rate,
5867 channels, bits_per_sample, stream_id,
5868 use_default_chmap, channel_map,
5869 sample_word_size, endianness,
5870 mode);
5871
5872}
5873EXPORT_SYMBOL(q6asm_media_format_block_pcm_format_support_v4);
5874
5875
5876static int __q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
5877 uint32_t rate, uint32_t channels,
5878 bool use_default_chmap, char *channel_map,
5879 uint16_t bits_per_sample)
5880{
5881 struct asm_multi_channel_pcm_fmt_blk_v2 fmt;
5882 u8 *channel_mapping;
5883 int rc = 0;
5884
Rohit kumar6a14cfb2019-02-04 11:22:49 +05305885 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
5886 pr_err("%s: Invalid channel count %d\n", __func__, channels);
5887 return -EINVAL;
5888 }
5889
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305890 pr_debug("%s: session[%d]rate[%d]ch[%d]\n", __func__, ac->session, rate,
5891 channels);
5892
5893 q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
5894 atomic_set(&ac->cmd_state, -1);
5895
5896 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
5897 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
5898 sizeof(fmt.fmt_blk);
5899 fmt.num_channels = channels;
5900 fmt.bits_per_sample = bits_per_sample;
5901 fmt.sample_rate = rate;
5902 fmt.is_signed = 1;
5903
5904 channel_mapping = fmt.channel_mapping;
5905
5906 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
5907
5908 if (use_default_chmap) {
5909 if (q6asm_map_channels(channel_mapping, channels, false)) {
5910 pr_err("%s: map channels failed %d\n",
5911 __func__, channels);
5912 return -EINVAL;
5913 }
5914 } else {
5915 memcpy(channel_mapping, channel_map,
5916 PCM_FORMAT_MAX_NUM_CHANNEL);
5917 }
5918
5919 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
5920 if (rc < 0) {
5921 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
5922 rc = -EINVAL;
5923 goto fail_cmd;
5924 }
5925 rc = wait_event_timeout(ac->cmd_wait,
5926 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5927 if (!rc) {
5928 pr_err("%s: timeout. waited for format update\n", __func__);
5929 rc = -ETIMEDOUT;
5930 goto fail_cmd;
5931 }
5932 if (atomic_read(&ac->cmd_state) > 0) {
5933 pr_err("%s: DSP returned error[%s]\n",
5934 __func__, adsp_err_get_err_str(
5935 atomic_read(&ac->cmd_state)));
5936 rc = adsp_err_get_lnx_err_code(
5937 atomic_read(&ac->cmd_state));
5938 goto fail_cmd;
5939 }
5940 return 0;
5941fail_cmd:
5942 return rc;
5943}
5944
5945static int __q6asm_media_format_block_multi_ch_pcm_v3(struct audio_client *ac,
5946 uint32_t rate,
5947 uint32_t channels,
5948 bool use_default_chmap,
5949 char *channel_map,
5950 uint16_t bits_per_sample,
5951 uint16_t sample_word_size)
5952{
5953 struct asm_multi_channel_pcm_fmt_blk_param_v3 fmt;
5954 u8 *channel_mapping;
5955 int rc;
5956
Rohit kumar6a14cfb2019-02-04 11:22:49 +05305957 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
5958 pr_err("%s: Invalid channel count %d\n", __func__, channels);
5959 return -EINVAL;
5960 }
5961
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305962 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
5963 ac->session, rate, channels,
5964 bits_per_sample, sample_word_size);
5965
5966 memset(&fmt, 0, sizeof(fmt));
5967 q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
5968 atomic_set(&ac->cmd_state, -1);
5969
5970 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
5971 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
5972 sizeof(fmt.fmt_blk);
5973 fmt.param.num_channels = channels;
5974 fmt.param.bits_per_sample = bits_per_sample;
5975 fmt.param.sample_rate = rate;
5976 fmt.param.is_signed = 1;
5977 fmt.param.sample_word_size = sample_word_size;
5978 channel_mapping = fmt.param.channel_mapping;
5979
5980 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
5981
5982 if (use_default_chmap) {
5983 if (q6asm_map_channels(channel_mapping, channels, false)) {
5984 pr_err("%s: map channels failed %d\n",
5985 __func__, channels);
5986 rc = -EINVAL;
5987 goto fail_cmd;
5988 }
5989 } else {
5990 memcpy(channel_mapping, channel_map,
5991 PCM_FORMAT_MAX_NUM_CHANNEL);
5992 }
5993
5994 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
5995 if (rc < 0) {
5996 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
5997 goto fail_cmd;
5998 }
5999 rc = wait_event_timeout(ac->cmd_wait,
6000 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6001 if (!rc) {
6002 pr_err("%s: timeout. waited for format update\n", __func__);
6003 rc = -ETIMEDOUT;
6004 goto fail_cmd;
6005 }
6006 if (atomic_read(&ac->cmd_state) > 0) {
6007 pr_err("%s: DSP returned error[%s]\n",
6008 __func__, adsp_err_get_err_str(
6009 atomic_read(&ac->cmd_state)));
6010 rc = adsp_err_get_lnx_err_code(
6011 atomic_read(&ac->cmd_state));
6012 goto fail_cmd;
6013 }
6014 return 0;
6015fail_cmd:
6016 return rc;
6017}
6018
6019static int __q6asm_media_format_block_multi_ch_pcm_v4(struct audio_client *ac,
6020 uint32_t rate,
6021 uint32_t channels,
6022 bool use_default_chmap,
6023 char *channel_map,
6024 uint16_t bits_per_sample,
6025 uint16_t sample_word_size,
6026 uint16_t endianness,
6027 uint16_t mode)
6028{
6029 struct asm_multi_channel_pcm_fmt_blk_param_v4 fmt;
6030 u8 *channel_mapping;
6031 int rc;
6032
Rohit kumar6a14cfb2019-02-04 11:22:49 +05306033 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
6034 pr_err("%s: Invalid channel count %d\n", __func__, channels);
6035 return -EINVAL;
6036 }
6037
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306038 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
6039 ac->session, rate, channels,
6040 bits_per_sample, sample_word_size);
6041
6042 memset(&fmt, 0, sizeof(fmt));
6043 q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
6044 atomic_set(&ac->cmd_state, -1);
6045
6046 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6047 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6048 sizeof(fmt.fmt_blk);
6049 fmt.param.num_channels = channels;
6050 fmt.param.bits_per_sample = bits_per_sample;
6051 fmt.param.sample_rate = rate;
6052 fmt.param.is_signed = 1;
6053 fmt.param.sample_word_size = sample_word_size;
6054 fmt.param.endianness = endianness;
6055 fmt.param.mode = mode;
6056 channel_mapping = fmt.param.channel_mapping;
6057
6058 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
6059
6060 if (use_default_chmap) {
6061 if (q6asm_map_channels(channel_mapping, channels, false)) {
6062 pr_err("%s: map channels failed %d\n",
6063 __func__, channels);
6064 rc = -EINVAL;
6065 goto fail_cmd;
6066 }
6067 } else {
6068 memcpy(channel_mapping, channel_map,
6069 PCM_FORMAT_MAX_NUM_CHANNEL);
6070 }
6071
6072 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6073 if (rc < 0) {
6074 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
6075 goto fail_cmd;
6076 }
6077 rc = wait_event_timeout(ac->cmd_wait,
6078 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6079 if (!rc) {
6080 pr_err("%s: timeout. waited for format update\n", __func__);
6081 rc = -ETIMEDOUT;
6082 goto fail_cmd;
6083 }
6084 if (atomic_read(&ac->cmd_state) > 0) {
6085 pr_err("%s: DSP returned error[%s]\n",
6086 __func__, adsp_err_get_err_str(
6087 atomic_read(&ac->cmd_state)));
6088 rc = adsp_err_get_lnx_err_code(
6089 atomic_read(&ac->cmd_state));
6090 goto fail_cmd;
6091 }
6092 return 0;
6093fail_cmd:
6094 return rc;
6095}
6096
6097int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
6098 uint32_t rate, uint32_t channels,
6099 bool use_default_chmap, char *channel_map)
6100{
6101 return __q6asm_media_format_block_multi_ch_pcm(ac, rate,
6102 channels, use_default_chmap, channel_map, 16);
6103}
6104
6105int q6asm_media_format_block_multi_ch_pcm_v2(
6106 struct audio_client *ac,
6107 uint32_t rate, uint32_t channels,
6108 bool use_default_chmap, char *channel_map,
6109 uint16_t bits_per_sample)
6110{
6111 return __q6asm_media_format_block_multi_ch_pcm(ac, rate,
6112 channels, use_default_chmap, channel_map,
6113 bits_per_sample);
6114}
6115
6116/*
6117 * q6asm_media_format_block_multi_ch_pcm_v3 - sends pcm decoder configuration
6118 * parameters
6119 *
6120 * @ac: Client session handle
6121 * @rate: sample rate
6122 * @channels: number of channels
6123 * @bits_per_sample: bit width of encoder session
6124 * @use_default_chmap: true if default channel map to be used
6125 * @channel_map: input channel map
6126 * @sample_word_size: Size in bits of the word that holds a sample of a channel
6127 */
6128int q6asm_media_format_block_multi_ch_pcm_v3(struct audio_client *ac,
6129 uint32_t rate, uint32_t channels,
6130 bool use_default_chmap,
6131 char *channel_map,
6132 uint16_t bits_per_sample,
6133 uint16_t sample_word_size)
6134{
6135 return __q6asm_media_format_block_multi_ch_pcm_v3(ac, rate, channels,
6136 use_default_chmap,
6137 channel_map,
6138 bits_per_sample,
6139 sample_word_size);
6140}
6141EXPORT_SYMBOL(q6asm_media_format_block_multi_ch_pcm_v3);
6142
6143/*
6144 * q6asm_media_format_block_multi_ch_pcm_v4 - sends pcm decoder configuration
6145 * parameters
6146 *
6147 * @ac: Client session handle
6148 * @rate: sample rate
6149 * @channels: number of channels
6150 * @bits_per_sample: bit width of encoder session
6151 * @use_default_chmap: true if default channel map to be used
6152 * @channel_map: input channel map
6153 * @sample_word_size: Size in bits of the word that holds a sample of a channel
6154 * @endianness: endianness of the pcm data
6155 * @mode: Mode to provide additional info about the pcm input data
6156 */
6157int q6asm_media_format_block_multi_ch_pcm_v4(struct audio_client *ac,
6158 uint32_t rate, uint32_t channels,
6159 bool use_default_chmap,
6160 char *channel_map,
6161 uint16_t bits_per_sample,
6162 uint16_t sample_word_size,
6163 uint16_t endianness,
6164 uint16_t mode)
6165{
6166 return __q6asm_media_format_block_multi_ch_pcm_v4(ac, rate, channels,
6167 use_default_chmap,
6168 channel_map,
6169 bits_per_sample,
6170 sample_word_size,
6171 endianness,
6172 mode);
6173}
6174EXPORT_SYMBOL(q6asm_media_format_block_multi_ch_pcm_v4);
6175
6176/*
6177 * q6asm_media_format_block_gen_compr - set up generic compress format params
6178 *
6179 * @ac: Client session handle
6180 * @rate: sample rate
6181 * @channels: number of channels
6182 * @use_default_chmap: true if default channel map to be used
6183 * @channel_map: input channel map
6184 * @bits_per_sample: bit width of gen compress stream
6185 */
6186int q6asm_media_format_block_gen_compr(struct audio_client *ac,
6187 uint32_t rate, uint32_t channels,
6188 bool use_default_chmap, char *channel_map,
6189 uint16_t bits_per_sample)
6190{
6191 struct asm_generic_compressed_fmt_blk_t fmt;
6192 u8 *channel_mapping;
6193 int rc = 0;
6194
Rohit kumar6a14cfb2019-02-04 11:22:49 +05306195 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
6196 pr_err("%s: Invalid channel count %d\n", __func__, channels);
6197 return -EINVAL;
6198 }
6199
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306200 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]\n",
6201 __func__, ac->session, rate,
6202 channels, bits_per_sample);
6203
6204 memset(&fmt, 0, sizeof(fmt));
6205 q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
6206
6207 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6208 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6209 sizeof(fmt.fmt_blk);
6210 fmt.num_channels = channels;
6211 fmt.bits_per_sample = bits_per_sample;
6212 fmt.sampling_rate = rate;
6213
6214 channel_mapping = fmt.channel_mapping;
6215
6216 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
6217
6218 if (use_default_chmap) {
6219 if (q6asm_map_channels(channel_mapping, channels, false)) {
6220 pr_err("%s: map channels failed %d\n",
6221 __func__, channels);
6222 return -EINVAL;
6223 }
6224 } else {
6225 memcpy(channel_mapping, channel_map,
6226 PCM_FORMAT_MAX_NUM_CHANNEL);
6227 }
6228
6229 atomic_set(&ac->cmd_state, -1);
6230 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6231 if (rc < 0) {
6232 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
6233 rc = -EINVAL;
6234 goto fail_cmd;
6235 }
6236 rc = wait_event_timeout(ac->cmd_wait,
6237 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6238 if (!rc) {
6239 pr_err("%s: timeout. waited for format update\n", __func__);
6240 rc = -ETIMEDOUT;
6241 goto fail_cmd;
6242 }
6243
6244 if (atomic_read(&ac->cmd_state) > 0) {
6245 pr_err("%s: DSP returned error[%s]\n",
6246 __func__, adsp_err_get_err_str(
6247 atomic_read(&ac->cmd_state)));
6248 rc = adsp_err_get_lnx_err_code(
6249 atomic_read(&ac->cmd_state));
6250 }
6251 return 0;
6252fail_cmd:
6253 return rc;
6254}
6255EXPORT_SYMBOL(q6asm_media_format_block_gen_compr);
6256
6257
6258/*
6259 * q6asm_media_format_block_iec - set up IEC61937 (compressed) or IEC60958
6260 * (pcm) format params. Both audio standards
6261 * use the same format and are used for
6262 * HDMI or SPDIF.
6263 *
6264 * @ac: Client session handle
6265 * @rate: sample rate
6266 * @channels: number of channels
6267 */
6268int q6asm_media_format_block_iec(struct audio_client *ac,
6269 uint32_t rate, uint32_t channels)
6270{
6271 struct asm_iec_compressed_fmt_blk_t fmt;
6272 int rc = 0;
6273
6274 pr_debug("%s: session[%d]rate[%d]ch[%d]\n",
6275 __func__, ac->session, rate,
6276 channels);
6277
6278 memset(&fmt, 0, sizeof(fmt));
6279 q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
6280
6281 fmt.hdr.opcode = ASM_DATA_CMD_IEC_60958_MEDIA_FMT;
6282 fmt.num_channels = channels;
6283 fmt.sampling_rate = rate;
6284
6285 atomic_set(&ac->cmd_state, -1);
6286 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6287 if (rc < 0) {
6288 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
6289 rc = -EINVAL;
6290 goto fail_cmd;
6291 }
6292 rc = wait_event_timeout(ac->cmd_wait,
6293 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6294 if (!rc) {
6295 pr_err("%s: timeout. waited for format update\n", __func__);
6296 rc = -ETIMEDOUT;
6297 goto fail_cmd;
6298 }
6299
6300 if (atomic_read(&ac->cmd_state) > 0) {
6301 pr_err("%s: DSP returned error[%s]\n",
6302 __func__, adsp_err_get_err_str(
6303 atomic_read(&ac->cmd_state)));
6304 rc = adsp_err_get_lnx_err_code(
6305 atomic_read(&ac->cmd_state));
6306 }
6307 return 0;
6308fail_cmd:
6309 return rc;
6310}
6311EXPORT_SYMBOL(q6asm_media_format_block_iec);
6312
6313static int __q6asm_media_format_block_multi_aac(struct audio_client *ac,
6314 struct asm_aac_cfg *cfg, int stream_id)
6315{
6316 struct asm_aac_fmt_blk_v2 fmt;
6317 int rc = 0;
6318
6319 pr_debug("%s: session[%d]rate[%d]ch[%d]\n", __func__, ac->session,
6320 cfg->sample_rate, cfg->ch_cfg);
6321
6322 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6323 atomic_set(&ac->cmd_state, -1);
6324 /*
6325 * Updated the token field with stream/session for compressed playback
6326 * Platform driver must know the the stream with which the command is
6327 * associated
6328 */
6329 if (ac->io_mode & COMPRESSED_STREAM_IO)
6330 q6asm_update_token(&fmt.hdr.token,
6331 ac->session,
6332 stream_id,
6333 0, /* Buffer index is NA */
6334 0, /* Direction flag is NA */
6335 WAIT_CMD);
6336
6337 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
6338 __func__, fmt.hdr.token, stream_id, ac->session);
6339 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6340 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6341 sizeof(fmt.fmt_blk);
6342 fmt.aac_fmt_flag = cfg->format;
6343 fmt.audio_objype = cfg->aot;
6344 /* If zero, PCE is assumed to be available in bitstream*/
6345 fmt.total_size_of_PCE_bits = 0;
6346 fmt.channel_config = cfg->ch_cfg;
6347 fmt.sample_rate = cfg->sample_rate;
6348
6349 pr_debug("%s: format=0x%x cfg_size=%d aac-cfg=0x%x aot=%d ch=%d sr=%d\n",
6350 __func__, fmt.aac_fmt_flag, fmt.fmt_blk.fmt_blk_size,
6351 fmt.aac_fmt_flag,
6352 fmt.audio_objype,
6353 fmt.channel_config,
6354 fmt.sample_rate);
6355 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6356 if (rc < 0) {
6357 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
6358 rc = -EINVAL;
6359 goto fail_cmd;
6360 }
6361 rc = wait_event_timeout(ac->cmd_wait,
6362 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6363 if (!rc) {
6364 pr_err("%s: timeout. waited for FORMAT_UPDATE\n", __func__);
6365 rc = -ETIMEDOUT;
6366 goto fail_cmd;
6367 }
6368 if (atomic_read(&ac->cmd_state) > 0) {
6369 pr_err("%s: DSP returned error[%s]\n",
6370 __func__, adsp_err_get_err_str(
6371 atomic_read(&ac->cmd_state)));
6372 rc = adsp_err_get_lnx_err_code(
6373 atomic_read(&ac->cmd_state));
6374 goto fail_cmd;
6375 }
6376 return 0;
6377fail_cmd:
6378 return rc;
6379}
6380
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306381/**
6382 * q6asm_media_format_block_multi_aac -
6383 * command to set mediafmt block for multi_aac on ASM stream
6384 *
6385 * @ac: Audio client handle
6386 * @cfg: multi_aac config
6387 *
6388 * Returns 0 on success or error on failure
6389 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306390int q6asm_media_format_block_multi_aac(struct audio_client *ac,
6391 struct asm_aac_cfg *cfg)
6392{
6393 return __q6asm_media_format_block_multi_aac(ac, cfg, ac->stream_id);
6394}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306395EXPORT_SYMBOL(q6asm_media_format_block_multi_aac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306396
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306397/**
6398 * q6asm_media_format_block_aac -
6399 * command to set mediafmt block for aac on ASM
6400 *
6401 * @ac: Audio client handle
6402 * @cfg: aac config
6403 *
6404 * Returns 0 on success or error on failure
6405 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306406int q6asm_media_format_block_aac(struct audio_client *ac,
6407 struct asm_aac_cfg *cfg)
6408{
6409 return __q6asm_media_format_block_multi_aac(ac, cfg, ac->stream_id);
6410}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306411EXPORT_SYMBOL(q6asm_media_format_block_aac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306412
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306413/**
6414 * q6asm_stream_media_format_block_aac -
6415 * command to set mediafmt block for aac on ASM stream
6416 *
6417 * @ac: Audio client handle
6418 * @cfg: aac config
6419 * @stream_id: stream ID info
6420 *
6421 * Returns 0 on success or error on failure
6422 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306423int q6asm_stream_media_format_block_aac(struct audio_client *ac,
6424 struct asm_aac_cfg *cfg, int stream_id)
6425{
6426 return __q6asm_media_format_block_multi_aac(ac, cfg, stream_id);
6427}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306428EXPORT_SYMBOL(q6asm_stream_media_format_block_aac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306429
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306430/**
6431 * q6asm_media_format_block_wma -
6432 * command to set mediafmt block for wma on ASM stream
6433 *
6434 * @ac: Audio client handle
6435 * @cfg: wma config
6436 * @stream_id: stream ID info
6437 *
6438 * Returns 0 on success or error on failure
6439 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306440int q6asm_media_format_block_wma(struct audio_client *ac,
6441 void *cfg, int stream_id)
6442{
6443 struct asm_wmastdv9_fmt_blk_v2 fmt;
6444 struct asm_wma_cfg *wma_cfg = (struct asm_wma_cfg *)cfg;
6445 int rc = 0;
6446
6447 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",
6448 ac->session, wma_cfg->format_tag, wma_cfg->sample_rate,
6449 wma_cfg->ch_cfg, wma_cfg->avg_bytes_per_sec,
6450 wma_cfg->block_align, wma_cfg->valid_bits_per_sample,
6451 wma_cfg->ch_mask, wma_cfg->encode_opt);
6452
6453 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6454 atomic_set(&ac->cmd_state, -1);
6455
6456 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6457 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6458 sizeof(fmt.fmtblk);
6459 fmt.fmtag = wma_cfg->format_tag;
6460 fmt.num_channels = wma_cfg->ch_cfg;
6461 fmt.sample_rate = wma_cfg->sample_rate;
6462 fmt.avg_bytes_per_sec = wma_cfg->avg_bytes_per_sec;
6463 fmt.blk_align = wma_cfg->block_align;
6464 fmt.bits_per_sample =
6465 wma_cfg->valid_bits_per_sample;
6466 fmt.channel_mask = wma_cfg->ch_mask;
6467 fmt.enc_options = wma_cfg->encode_opt;
6468
6469 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6470 if (rc < 0) {
6471 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
6472 rc = -EINVAL;
6473 goto fail_cmd;
6474 }
6475 rc = wait_event_timeout(ac->cmd_wait,
6476 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6477 if (!rc) {
6478 pr_err("%s: timeout. waited for FORMAT_UPDATE\n", __func__);
6479 rc = -ETIMEDOUT;
6480 goto fail_cmd;
6481 }
6482 if (atomic_read(&ac->cmd_state) > 0) {
6483 pr_err("%s: DSP returned error[%s]\n",
6484 __func__, adsp_err_get_err_str(
6485 atomic_read(&ac->cmd_state)));
6486 rc = adsp_err_get_lnx_err_code(
6487 atomic_read(&ac->cmd_state));
6488 goto fail_cmd;
6489 }
6490 return 0;
6491fail_cmd:
6492 return rc;
6493}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306494EXPORT_SYMBOL(q6asm_media_format_block_wma);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306495
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306496/**
6497 * q6asm_media_format_block_wmapro -
6498 * command to set mediafmt block for wmapro on ASM stream
6499 *
6500 * @ac: Audio client handle
6501 * @cfg: wmapro config
6502 * @stream_id: stream ID info
6503 *
6504 * Returns 0 on success or error on failure
6505 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306506int q6asm_media_format_block_wmapro(struct audio_client *ac,
6507 void *cfg, int stream_id)
6508{
6509 struct asm_wmaprov10_fmt_blk_v2 fmt;
6510 struct asm_wmapro_cfg *wmapro_cfg = (struct asm_wmapro_cfg *)cfg;
6511 int rc = 0;
6512
6513 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",
6514 __func__,
6515 ac->session, wmapro_cfg->format_tag, wmapro_cfg->sample_rate,
6516 wmapro_cfg->ch_cfg, wmapro_cfg->avg_bytes_per_sec,
6517 wmapro_cfg->block_align, wmapro_cfg->valid_bits_per_sample,
6518 wmapro_cfg->ch_mask, wmapro_cfg->encode_opt,
6519 wmapro_cfg->adv_encode_opt, wmapro_cfg->adv_encode_opt2);
6520
6521 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6522 atomic_set(&ac->cmd_state, -1);
6523
6524 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6525 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6526 sizeof(fmt.fmtblk);
6527
6528 fmt.fmtag = wmapro_cfg->format_tag;
6529 fmt.num_channels = wmapro_cfg->ch_cfg;
6530 fmt.sample_rate = wmapro_cfg->sample_rate;
6531 fmt.avg_bytes_per_sec =
6532 wmapro_cfg->avg_bytes_per_sec;
6533 fmt.blk_align = wmapro_cfg->block_align;
6534 fmt.bits_per_sample = wmapro_cfg->valid_bits_per_sample;
6535 fmt.channel_mask = wmapro_cfg->ch_mask;
6536 fmt.enc_options = wmapro_cfg->encode_opt;
6537 fmt.usAdvancedEncodeOpt = wmapro_cfg->adv_encode_opt;
6538 fmt.advanced_enc_options2 = wmapro_cfg->adv_encode_opt2;
6539
6540 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6541 if (rc < 0) {
6542 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
6543 rc = -EINVAL;
6544 goto fail_cmd;
6545 }
6546 rc = wait_event_timeout(ac->cmd_wait,
6547 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6548 if (!rc) {
6549 pr_err("%s: timeout. waited for FORMAT_UPDATE\n", __func__);
6550 rc = -ETIMEDOUT;
6551 goto fail_cmd;
6552 }
6553 if (atomic_read(&ac->cmd_state) > 0) {
6554 pr_err("%s: DSP returned error[%s]\n",
6555 __func__, adsp_err_get_err_str(
6556 atomic_read(&ac->cmd_state)));
6557 rc = adsp_err_get_lnx_err_code(
6558 atomic_read(&ac->cmd_state));
6559 goto fail_cmd;
6560 }
6561 return 0;
6562fail_cmd:
6563 return rc;
6564}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306565EXPORT_SYMBOL(q6asm_media_format_block_wmapro);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306566
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306567/**
6568 * q6asm_media_format_block_amrwbplus -
6569 * command to set mediafmt block for amrwbplus on ASM stream
6570 *
6571 * @ac: Audio client handle
6572 * @cfg: amrwbplus config
6573 * @stream_id: stream ID info
6574 *
6575 * Returns 0 on success or error on failure
6576 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306577int q6asm_media_format_block_amrwbplus(struct audio_client *ac,
6578 struct asm_amrwbplus_cfg *cfg)
6579{
6580 struct asm_amrwbplus_fmt_blk_v2 fmt;
6581 int rc = 0;
6582
6583 pr_debug("%s: session[%d]band-mode[%d]frame-fmt[%d]ch[%d]\n",
6584 __func__,
6585 ac->session,
6586 cfg->amr_band_mode,
6587 cfg->amr_frame_fmt,
6588 cfg->num_channels);
6589
6590 q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
6591 atomic_set(&ac->cmd_state, -1);
6592
6593 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6594 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6595 sizeof(fmt.fmtblk);
6596 fmt.amr_frame_fmt = cfg->amr_frame_fmt;
6597
6598 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6599 if (rc < 0) {
6600 pr_err("%s: Comamnd media format update failed.. %d\n",
6601 __func__, rc);
6602 rc = -EINVAL;
6603 goto fail_cmd;
6604 }
6605 rc = wait_event_timeout(ac->cmd_wait,
6606 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6607 if (!rc) {
6608 pr_err("%s: timeout. waited for FORMAT_UPDATE\n", __func__);
6609 rc = -ETIMEDOUT;
6610 goto fail_cmd;
6611 }
6612 if (atomic_read(&ac->cmd_state) > 0) {
6613 pr_err("%s: DSP returned error[%s]\n",
6614 __func__, adsp_err_get_err_str(
6615 atomic_read(&ac->cmd_state)));
6616 rc = adsp_err_get_lnx_err_code(
6617 atomic_read(&ac->cmd_state));
6618 goto fail_cmd;
6619 }
6620 return 0;
6621fail_cmd:
6622 return rc;
6623}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306624EXPORT_SYMBOL(q6asm_media_format_block_amrwbplus);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306625
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306626/**
6627 * q6asm_stream_media_format_block_flac -
6628 * command to set mediafmt block for flac on ASM stream
6629 *
6630 * @ac: Audio client handle
6631 * @cfg: FLAC config
6632 * @stream_id: stream ID info
6633 *
6634 * Returns 0 on success or error on failure
6635 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306636int q6asm_stream_media_format_block_flac(struct audio_client *ac,
6637 struct asm_flac_cfg *cfg, int stream_id)
6638{
6639 struct asm_flac_fmt_blk_v2 fmt;
6640 int rc = 0;
6641
6642 pr_debug("%s :session[%d] rate[%d] ch[%d] size[%d] stream_id[%d]\n",
6643 __func__, ac->session, cfg->sample_rate, cfg->ch_cfg,
6644 cfg->sample_size, stream_id);
6645
6646 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6647 atomic_set(&ac->cmd_state, -1);
6648
6649 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6650 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6651 sizeof(fmt.fmtblk);
6652
6653 fmt.is_stream_info_present = cfg->stream_info_present;
6654 fmt.num_channels = cfg->ch_cfg;
6655 fmt.min_blk_size = cfg->min_blk_size;
6656 fmt.max_blk_size = cfg->max_blk_size;
6657 fmt.sample_rate = cfg->sample_rate;
6658 fmt.min_frame_size = cfg->min_frame_size;
6659 fmt.max_frame_size = cfg->max_frame_size;
6660 fmt.sample_size = cfg->sample_size;
6661
6662 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6663 if (rc < 0) {
6664 pr_err("%s :Comamnd media format update failed %d\n",
6665 __func__, rc);
6666 goto fail_cmd;
6667 }
6668 rc = wait_event_timeout(ac->cmd_wait,
6669 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6670 if (!rc) {
6671 pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
6672 rc = -ETIMEDOUT;
6673 goto fail_cmd;
6674 }
6675
6676 if (atomic_read(&ac->cmd_state) > 0) {
6677 pr_err("%s: DSP returned error[%s]\n",
6678 __func__, adsp_err_get_err_str(
6679 atomic_read(&ac->cmd_state)));
6680 rc = adsp_err_get_lnx_err_code(
6681 atomic_read(&ac->cmd_state));
6682 goto fail_cmd;
6683 }
6684 return 0;
6685fail_cmd:
6686 return rc;
6687}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306688EXPORT_SYMBOL(q6asm_stream_media_format_block_flac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306689
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306690/**
6691 * q6asm_media_format_block_alac -
6692 * command to set mediafmt block for alac on ASM stream
6693 *
6694 * @ac: Audio client handle
6695 * @cfg: ALAC config
6696 * @stream_id: stream ID info
6697 *
6698 * Returns 0 on success or error on failure
6699 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306700int q6asm_media_format_block_alac(struct audio_client *ac,
6701 struct asm_alac_cfg *cfg, int stream_id)
6702{
6703 struct asm_alac_fmt_blk_v2 fmt;
6704 int rc = 0;
6705
6706 pr_debug("%s :session[%d]rate[%d]ch[%d]\n", __func__,
6707 ac->session, cfg->sample_rate, cfg->num_channels);
6708
6709 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6710 atomic_set(&ac->cmd_state, -1);
6711
6712 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6713 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6714 sizeof(fmt.fmtblk);
6715
6716 fmt.frame_length = cfg->frame_length;
6717 fmt.compatible_version = cfg->compatible_version;
6718 fmt.bit_depth = cfg->bit_depth;
6719 fmt.pb = cfg->pb;
6720 fmt.mb = cfg->mb;
6721 fmt.kb = cfg->kb;
6722 fmt.num_channels = cfg->num_channels;
6723 fmt.max_run = cfg->max_run;
6724 fmt.max_frame_bytes = cfg->max_frame_bytes;
6725 fmt.avg_bit_rate = cfg->avg_bit_rate;
6726 fmt.sample_rate = cfg->sample_rate;
6727 fmt.channel_layout_tag = cfg->channel_layout_tag;
6728
6729 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6730 if (rc < 0) {
6731 pr_err("%s :Comamnd media format update failed %d\n",
6732 __func__, rc);
6733 goto fail_cmd;
6734 }
6735 rc = wait_event_timeout(ac->cmd_wait,
6736 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6737 if (!rc) {
6738 pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
6739 rc = -ETIMEDOUT;
6740 goto fail_cmd;
6741 }
6742
6743 if (atomic_read(&ac->cmd_state) > 0) {
6744 pr_err("%s: DSP returned error[%s]\n",
6745 __func__, adsp_err_get_err_str(
6746 atomic_read(&ac->cmd_state)));
6747 rc = adsp_err_get_lnx_err_code(
6748 atomic_read(&ac->cmd_state));
6749 goto fail_cmd;
6750 }
6751 return 0;
6752fail_cmd:
6753 return rc;
6754}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306755EXPORT_SYMBOL(q6asm_media_format_block_alac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306756
6757/*
6758 * q6asm_media_format_block_g711 - sends g711 decoder configuration
6759 * parameters
6760 * @ac: Client session handle
6761 * @cfg: Audio stream manager configuration parameters
6762 * @stream_id: Stream id
6763 */
6764int q6asm_media_format_block_g711(struct audio_client *ac,
6765 struct asm_g711_dec_cfg *cfg, int stream_id)
6766{
6767 struct asm_g711_dec_fmt_blk_v2 fmt;
6768 int rc = 0;
6769
6770 if (!ac) {
6771 pr_err("%s: audio client is null\n", __func__);
6772 return -EINVAL;
6773 }
6774 if (!cfg) {
6775 pr_err("%s: Invalid ASM config\n", __func__);
6776 return -EINVAL;
6777 }
6778
6779 if (stream_id <= 0) {
6780 pr_err("%s: Invalid stream id\n", __func__);
6781 return -EINVAL;
6782 }
6783
6784 pr_debug("%s :session[%d]rate[%d]\n", __func__,
6785 ac->session, cfg->sample_rate);
6786
6787 memset(&fmt, 0, sizeof(struct asm_g711_dec_fmt_blk_v2));
6788
6789 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6790 atomic_set(&ac->cmd_state, -1);
6791
6792 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6793 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6794 sizeof(fmt.fmtblk);
6795
6796 fmt.sample_rate = cfg->sample_rate;
6797
6798 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6799 if (rc < 0) {
6800 pr_err("%s :Command media format update failed %d\n",
6801 __func__, rc);
6802 goto fail_cmd;
6803 }
6804 rc = wait_event_timeout(ac->cmd_wait,
6805 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6806 if (!rc) {
6807 pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
6808 rc = -ETIMEDOUT;
6809 goto fail_cmd;
6810 }
6811
6812 if (atomic_read(&ac->cmd_state) > 0) {
6813 pr_err("%s: DSP returned error[%s]\n",
6814 __func__, adsp_err_get_err_str(
6815 atomic_read(&ac->cmd_state)));
6816 rc = adsp_err_get_lnx_err_code(
6817 atomic_read(&ac->cmd_state));
6818 goto fail_cmd;
6819 }
6820 return 0;
6821fail_cmd:
6822 return rc;
6823}
6824EXPORT_SYMBOL(q6asm_media_format_block_g711);
6825
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306826/**
6827 * q6asm_stream_media_format_block_vorbis -
6828 * command to set mediafmt block for vorbis on ASM stream
6829 *
6830 * @ac: Audio client handle
6831 * @cfg: vorbis config
6832 * @stream_id: stream ID info
6833 *
6834 * Returns 0 on success or error on failure
6835 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306836int q6asm_stream_media_format_block_vorbis(struct audio_client *ac,
6837 struct asm_vorbis_cfg *cfg, int stream_id)
6838{
6839 struct asm_vorbis_fmt_blk_v2 fmt;
6840 int rc = 0;
6841
6842 pr_debug("%s :session[%d] bit_stream_fmt[%d] stream_id[%d]\n",
6843 __func__, ac->session, cfg->bit_stream_fmt, stream_id);
6844
6845 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6846 atomic_set(&ac->cmd_state, -1);
6847
6848 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6849 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6850 sizeof(fmt.fmtblk);
6851
6852 fmt.bit_stream_fmt = cfg->bit_stream_fmt;
6853
6854 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6855 if (rc < 0) {
6856 pr_err("%s :Comamnd media format update failed %d\n",
6857 __func__, rc);
6858 goto fail_cmd;
6859 }
6860 rc = wait_event_timeout(ac->cmd_wait,
6861 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6862 if (!rc) {
6863 pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
6864 rc = -ETIMEDOUT;
6865 goto fail_cmd;
6866 }
6867
6868 if (atomic_read(&ac->cmd_state) > 0) {
6869 pr_err("%s: DSP returned error[%s]\n",
6870 __func__, adsp_err_get_err_str(
6871 atomic_read(&ac->cmd_state)));
6872 rc = adsp_err_get_lnx_err_code(
6873 atomic_read(&ac->cmd_state));
6874 goto fail_cmd;
6875 }
6876 return 0;
6877fail_cmd:
6878 return rc;
6879}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306880EXPORT_SYMBOL(q6asm_stream_media_format_block_vorbis);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306881
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306882/**
6883 * q6asm_media_format_block_ape -
6884 * command to set mediafmt block for APE on ASM stream
6885 *
6886 * @ac: Audio client handle
6887 * @cfg: APE config
6888 * @stream_id: stream ID info
6889 *
6890 * Returns 0 on success or error on failure
6891 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306892int q6asm_media_format_block_ape(struct audio_client *ac,
6893 struct asm_ape_cfg *cfg, int stream_id)
6894{
6895 struct asm_ape_fmt_blk_v2 fmt;
6896 int rc = 0;
6897
6898 pr_debug("%s :session[%d]rate[%d]ch[%d]\n", __func__,
6899 ac->session, cfg->sample_rate, cfg->num_channels);
6900
6901 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6902 atomic_set(&ac->cmd_state, -1);
6903
6904 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6905 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6906 sizeof(fmt.fmtblk);
6907
6908 fmt.compatible_version = cfg->compatible_version;
6909 fmt.compression_level = cfg->compression_level;
6910 fmt.format_flags = cfg->format_flags;
6911 fmt.blocks_per_frame = cfg->blocks_per_frame;
6912 fmt.final_frame_blocks = cfg->final_frame_blocks;
6913 fmt.total_frames = cfg->total_frames;
6914 fmt.bits_per_sample = cfg->bits_per_sample;
6915 fmt.num_channels = cfg->num_channels;
6916 fmt.sample_rate = cfg->sample_rate;
6917 fmt.seek_table_present = cfg->seek_table_present;
6918
6919 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6920 if (rc < 0) {
6921 pr_err("%s :Comamnd media format update failed %d\n",
6922 __func__, rc);
6923 goto fail_cmd;
6924 }
6925 rc = wait_event_timeout(ac->cmd_wait,
6926 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6927 if (!rc) {
6928 pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
6929 rc = -ETIMEDOUT;
6930 goto fail_cmd;
6931 }
6932
6933 if (atomic_read(&ac->cmd_state) > 0) {
6934 pr_err("%s: DSP returned error[%s]\n",
6935 __func__, adsp_err_get_err_str(
6936 atomic_read(&ac->cmd_state)));
6937 rc = adsp_err_get_lnx_err_code(
6938 atomic_read(&ac->cmd_state));
6939 goto fail_cmd;
6940 }
6941 return 0;
6942fail_cmd:
6943 return rc;
6944}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306945EXPORT_SYMBOL(q6asm_media_format_block_ape);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306946
6947/*
6948 * q6asm_media_format_block_dsd- Sends DSD Decoder
6949 * configuration parameters
6950 *
6951 * @ac: Client session handle
6952 * @cfg: DSD Media Format Configuration.
6953 * @stream_id: stream id of stream to be associated with this session
6954 *
6955 * Return 0 on success or negative error code on failure
6956 */
6957int q6asm_media_format_block_dsd(struct audio_client *ac,
6958 struct asm_dsd_cfg *cfg, int stream_id)
6959{
6960 struct asm_dsd_fmt_blk_v2 fmt;
6961 int rc;
6962
6963 pr_debug("%s: session[%d] data_rate[%d] ch[%d]\n", __func__,
6964 ac->session, cfg->dsd_data_rate, cfg->num_channels);
6965
6966 memset(&fmt, 0, sizeof(fmt));
6967 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6968
6969 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6970 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6971 sizeof(fmt.fmtblk);
6972
6973 fmt.num_version = cfg->num_version;
6974 fmt.is_bitwise_big_endian = cfg->is_bitwise_big_endian;
6975 fmt.dsd_channel_block_size = cfg->dsd_channel_block_size;
6976 fmt.num_channels = cfg->num_channels;
6977 fmt.dsd_data_rate = cfg->dsd_data_rate;
6978 atomic_set(&ac->cmd_state, -1);
6979 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6980 if (rc < 0) {
6981 pr_err("%s: Command DSD media format update failed, err: %d\n",
6982 __func__, rc);
6983 goto done;
6984 }
6985 rc = wait_event_timeout(ac->cmd_wait,
6986 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6987 if (!rc) {
6988 pr_err("%s: timeout. waited for DSD FORMAT_UPDATE\n", __func__);
6989 rc = -ETIMEDOUT;
6990 goto done;
6991 }
6992
6993 if (atomic_read(&ac->cmd_state) > 0) {
6994 pr_err("%s: DSP returned error[%s]\n",
6995 __func__, adsp_err_get_err_str(
6996 atomic_read(&ac->cmd_state)));
6997 rc = adsp_err_get_lnx_err_code(
6998 atomic_read(&ac->cmd_state));
6999 goto done;
7000 }
7001 return 0;
7002done:
7003 return rc;
7004}
7005EXPORT_SYMBOL(q6asm_media_format_block_dsd);
7006
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307007/**
7008 * q6asm_stream_media_format_block_aptx_dec -
7009 * command to set mediafmt block for APTX dec on ASM stream
7010 *
7011 * @ac: Audio client handle
7012 * @srate: sample rate
7013 * @stream_id: stream ID info
7014 *
7015 * Returns 0 on success or error on failure
7016 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307017int q6asm_stream_media_format_block_aptx_dec(struct audio_client *ac,
7018 uint32_t srate, int stream_id)
7019{
7020 struct asm_aptx_dec_fmt_blk_v2 aptx_fmt;
7021 int rc = 0;
7022
7023 if (!ac->session) {
7024 pr_err("%s: ac session invalid\n", __func__);
7025 rc = -EINVAL;
7026 goto fail_cmd;
7027 }
7028 pr_debug("%s :session[%d] rate[%d] stream_id[%d]\n",
7029 __func__, ac->session, srate, stream_id);
7030
7031 q6asm_stream_add_hdr(ac, &aptx_fmt.hdr, sizeof(aptx_fmt), TRUE,
7032 stream_id);
7033 atomic_set(&ac->cmd_state, -1);
7034
7035 aptx_fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
7036 aptx_fmt.fmtblk.fmt_blk_size = sizeof(aptx_fmt) - sizeof(aptx_fmt.hdr) -
7037 sizeof(aptx_fmt.fmtblk);
7038
7039 aptx_fmt.sample_rate = srate;
7040
7041 rc = apr_send_pkt(ac->apr, (uint32_t *) &aptx_fmt);
7042 if (rc < 0) {
7043 pr_err("%s :Comamnd media format update failed %d\n",
7044 __func__, rc);
7045 goto fail_cmd;
7046 }
7047 rc = wait_event_timeout(ac->cmd_wait,
7048 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
7049 if (!rc) {
7050 pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
7051 rc = -ETIMEDOUT;
7052 goto fail_cmd;
7053 }
7054
7055 if (atomic_read(&ac->cmd_state) > 0) {
7056 pr_err("%s: DSP returned error[%s]\n",
7057 __func__, adsp_err_get_err_str(
7058 atomic_read(&ac->cmd_state)));
7059 rc = adsp_err_get_lnx_err_code(
7060 atomic_read(&ac->cmd_state));
7061 goto fail_cmd;
7062 }
7063 rc = 0;
7064fail_cmd:
7065 return rc;
7066}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307067EXPORT_SYMBOL(q6asm_stream_media_format_block_aptx_dec);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307068
7069static int __q6asm_ds1_set_endp_params(struct audio_client *ac, int param_id,
7070 int param_value, int stream_id)
7071{
7072 struct asm_dec_ddp_endp_param_v2 ddp_cfg;
7073 int rc = 0;
7074
7075 pr_debug("%s: session[%d] stream[%d],param_id[%d]param_value[%d]",
7076 __func__, ac->session, stream_id, param_id, param_value);
7077
7078 q6asm_stream_add_hdr(ac, &ddp_cfg.hdr, sizeof(ddp_cfg), TRUE,
7079 stream_id);
7080 atomic_set(&ac->cmd_state, -1);
7081 /*
7082 * Updated the token field with stream/session for compressed playback
7083 * Platform driver must know the stream with which the command is
7084 * associated
7085 */
7086 if (ac->io_mode & COMPRESSED_STREAM_IO)
7087 q6asm_update_token(&ddp_cfg.hdr.token,
7088 ac->session,
7089 stream_id,
7090 0, /* Buffer index is NA */
7091 0, /* Direction flag is NA */
7092 WAIT_CMD);
7093 ddp_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
7094 ddp_cfg.encdec.param_id = param_id;
7095 ddp_cfg.encdec.param_size = sizeof(struct asm_dec_ddp_endp_param_v2) -
7096 (sizeof(struct apr_hdr) +
7097 sizeof(struct asm_stream_cmd_set_encdec_param));
7098 ddp_cfg.endp_param_value = param_value;
7099 rc = apr_send_pkt(ac->apr, (uint32_t *) &ddp_cfg);
7100 if (rc < 0) {
7101 pr_err("%s: Command opcode[0x%x] failed %d\n",
7102 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
7103 goto fail_cmd;
7104 }
7105 rc = wait_event_timeout(ac->cmd_wait,
7106 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
7107 if (!rc) {
7108 pr_err("%s: timeout opcode[0x%x]\n", __func__,
7109 ddp_cfg.hdr.opcode);
7110 rc = -ETIMEDOUT;
7111 goto fail_cmd;
7112 }
7113 if (atomic_read(&ac->cmd_state) > 0) {
7114 pr_err("%s: DSP returned error[%s]\n",
7115 __func__, adsp_err_get_err_str(
7116 atomic_read(&ac->cmd_state)));
7117 rc = adsp_err_get_lnx_err_code(
7118 atomic_read(&ac->cmd_state));
7119 goto fail_cmd;
7120 }
7121 return 0;
7122fail_cmd:
7123 return rc;
7124}
7125
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307126/**
7127 * q6asm_ds1_set_endp_params -
7128 * command to set DS1 params for ASM
7129 *
7130 * @ac: Audio client handle
7131 * @param_id: param id
7132 * @param_value: value of param
7133 *
7134 * Returns 0 on success or error on failure
7135 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307136int q6asm_ds1_set_endp_params(struct audio_client *ac,
7137 int param_id, int param_value)
7138{
7139 return __q6asm_ds1_set_endp_params(ac, param_id, param_value,
7140 ac->stream_id);
7141}
7142
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307143/**
7144 * q6asm_ds1_set_stream_endp_params -
7145 * command to set DS1 params for ASM stream
7146 *
7147 * @ac: Audio client handle
7148 * @param_id: param id
7149 * @param_value: value of param
7150 * @stream_id: stream ID info
7151 *
7152 * Returns 0 on success or error on failure
7153 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307154int q6asm_ds1_set_stream_endp_params(struct audio_client *ac,
7155 int param_id, int param_value,
7156 int stream_id)
7157{
7158 return __q6asm_ds1_set_endp_params(ac, param_id, param_value,
7159 stream_id);
7160}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307161EXPORT_SYMBOL(q6asm_ds1_set_stream_endp_params);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307162
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307163/**
7164 * q6asm_memory_map -
7165 * command to send memory map for ASM
7166 *
7167 * @ac: Audio client handle
7168 * @buf_add: buffer address to map
7169 * @dir: RX or TX session
7170 * @bufsz: size of each buffer
7171 * @bufcnt: buffer count
7172 *
7173 * Returns 0 on success or error on failure
7174 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307175int q6asm_memory_map(struct audio_client *ac, phys_addr_t buf_add, int dir,
7176 uint32_t bufsz, uint32_t bufcnt)
7177{
7178 struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
7179 struct avs_shared_map_region_payload *mregions = NULL;
7180 struct audio_port_data *port = NULL;
7181 void *mmap_region_cmd = NULL;
7182 void *payload = NULL;
7183 struct asm_buffer_node *buffer_node = NULL;
7184 int rc = 0;
7185 int cmd_size = 0;
7186
7187 if (!ac) {
7188 pr_err("%s: APR handle NULL\n", __func__);
7189 return -EINVAL;
7190 }
7191 if (ac->mmap_apr == NULL) {
7192 pr_err("%s: mmap APR handle NULL\n", __func__);
7193 return -EINVAL;
7194 }
7195 pr_debug("%s: Session[%d]\n", __func__, ac->session);
7196
7197 buffer_node = kmalloc(sizeof(struct asm_buffer_node), GFP_KERNEL);
7198 if (!buffer_node)
7199 return -ENOMEM;
7200
7201 cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions)
7202 + sizeof(struct avs_shared_map_region_payload) * bufcnt;
7203
7204 mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
7205 if (mmap_region_cmd == NULL) {
7206 rc = -EINVAL;
7207 kfree(buffer_node);
7208 return rc;
7209 }
7210 mmap_regions = (struct avs_cmd_shared_mem_map_regions *)
7211 mmap_region_cmd;
7212 q6asm_add_mmaphdr(ac, &mmap_regions->hdr, cmd_size, dir);
7213 atomic_set(&ac->mem_state, -1);
7214 mmap_regions->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS;
7215 mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
7216 mmap_regions->num_regions = bufcnt & 0x00ff;
7217 mmap_regions->property_flag = 0x00;
7218 payload = ((u8 *) mmap_region_cmd +
7219 sizeof(struct avs_cmd_shared_mem_map_regions));
7220 mregions = (struct avs_shared_map_region_payload *)payload;
7221
7222 ac->port[dir].tmp_hdl = 0;
7223 port = &ac->port[dir];
7224 pr_debug("%s: buf_add 0x%pK, bufsz: %d\n", __func__,
7225 &buf_add, bufsz);
7226 mregions->shm_addr_lsw = lower_32_bits(buf_add);
7227 mregions->shm_addr_msw = msm_audio_populate_upper_32_bits(buf_add);
7228 mregions->mem_size_bytes = bufsz;
7229 ++mregions;
7230
7231 rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) mmap_region_cmd);
7232 if (rc < 0) {
7233 pr_err("%s: mmap op[0x%x]rc[%d]\n", __func__,
7234 mmap_regions->hdr.opcode, rc);
7235 rc = -EINVAL;
7236 kfree(buffer_node);
7237 goto fail_cmd;
7238 }
7239
7240 rc = wait_event_timeout(ac->mem_wait,
7241 (atomic_read(&ac->mem_state) >= 0 &&
7242 ac->port[dir].tmp_hdl), 5*HZ);
7243 if (!rc) {
7244 pr_err("%s: timeout. waited for memory_map\n", __func__);
7245 rc = -ETIMEDOUT;
7246 kfree(buffer_node);
7247 goto fail_cmd;
7248 }
7249 if (atomic_read(&ac->mem_state) > 0) {
7250 pr_err("%s: DSP returned error[%s] for memory_map\n",
7251 __func__, adsp_err_get_err_str(
7252 atomic_read(&ac->mem_state)));
7253 rc = adsp_err_get_lnx_err_code(
7254 atomic_read(&ac->mem_state));
7255 kfree(buffer_node);
7256 goto fail_cmd;
7257 }
7258 buffer_node->buf_phys_addr = buf_add;
7259 buffer_node->mmap_hdl = ac->port[dir].tmp_hdl;
7260 list_add_tail(&buffer_node->list, &ac->port[dir].mem_map_handle);
7261 ac->port[dir].tmp_hdl = 0;
7262 rc = 0;
7263
7264fail_cmd:
7265 kfree(mmap_region_cmd);
7266 return rc;
7267}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307268EXPORT_SYMBOL(q6asm_memory_map);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307269
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307270/**
7271 * q6asm_memory_unmap -
7272 * command to send memory unmap for ASM
7273 *
7274 * @ac: Audio client handle
7275 * @buf_add: buffer address to unmap
7276 * @dir: RX or TX session
7277 *
7278 * Returns 0 on success or error on failure
7279 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307280int q6asm_memory_unmap(struct audio_client *ac, phys_addr_t buf_add, int dir)
7281{
7282 struct avs_cmd_shared_mem_unmap_regions mem_unmap;
7283 struct asm_buffer_node *buf_node = NULL;
7284 struct list_head *ptr, *next;
7285
7286 int rc = 0;
7287
7288 if (!ac) {
7289 pr_err("%s: APR handle NULL\n", __func__);
7290 return -EINVAL;
7291 }
7292 if (this_mmap.apr == NULL) {
7293 pr_err("%s: APR handle NULL\n", __func__);
7294 return -EINVAL;
7295 }
7296 pr_debug("%s: Session[%d]\n", __func__, ac->session);
7297
7298 q6asm_add_mmaphdr(ac, &mem_unmap.hdr,
7299 sizeof(struct avs_cmd_shared_mem_unmap_regions),
7300 dir);
7301 atomic_set(&ac->mem_state, -1);
7302 mem_unmap.hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS;
7303 mem_unmap.mem_map_handle = 0;
7304 list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
7305 buf_node = list_entry(ptr, struct asm_buffer_node,
7306 list);
7307 if (buf_node->buf_phys_addr == buf_add) {
7308 pr_debug("%s: Found the element\n", __func__);
7309 mem_unmap.mem_map_handle = buf_node->mmap_hdl;
7310 break;
7311 }
7312 }
7313 pr_debug("%s: mem_unmap-mem_map_handle: 0x%x\n",
7314 __func__, mem_unmap.mem_map_handle);
7315
7316 if (mem_unmap.mem_map_handle == 0) {
7317 pr_err("%s: Do not send null mem handle to DSP\n", __func__);
7318 rc = 0;
7319 goto fail_cmd;
7320 }
7321 rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) &mem_unmap);
7322 if (rc < 0) {
7323 pr_err("%s: mem_unmap op[0x%x]rc[%d]\n", __func__,
7324 mem_unmap.hdr.opcode, rc);
7325 rc = -EINVAL;
7326 goto fail_cmd;
7327 }
7328
7329 rc = wait_event_timeout(ac->mem_wait,
7330 (atomic_read(&ac->mem_state) >= 0), 5 * HZ);
7331 if (!rc) {
7332 pr_err("%s: timeout. waited for memory_unmap of handle 0x%x\n",
7333 __func__, mem_unmap.mem_map_handle);
7334 rc = -ETIMEDOUT;
7335 goto fail_cmd;
7336 } else if (atomic_read(&ac->mem_state) > 0) {
7337 pr_err("%s DSP returned error [%s] map handle 0x%x\n",
7338 __func__, adsp_err_get_err_str(
7339 atomic_read(&ac->mem_state)),
7340 mem_unmap.mem_map_handle);
7341 rc = adsp_err_get_lnx_err_code(
7342 atomic_read(&ac->mem_state));
7343 goto fail_cmd;
7344 } else if (atomic_read(&ac->unmap_cb_success) == 0) {
7345 pr_err("%s: Error in mem unmap callback of handle 0x%x\n",
7346 __func__, mem_unmap.mem_map_handle);
7347 rc = -EINVAL;
7348 goto fail_cmd;
7349 }
7350
7351 rc = 0;
7352fail_cmd:
7353 list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
7354 buf_node = list_entry(ptr, struct asm_buffer_node,
7355 list);
7356 if (buf_node->buf_phys_addr == buf_add) {
7357 list_del(&buf_node->list);
7358 kfree(buf_node);
7359 break;
7360 }
7361 }
7362 return rc;
7363}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307364EXPORT_SYMBOL(q6asm_memory_unmap);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307365
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307366/**
7367 * q6asm_memory_map_regions -
7368 * command to send memory map regions for ASM
7369 *
7370 * @ac: Audio client handle
7371 * @dir: RX or TX session
7372 * @bufsz: size of each buffer
7373 * @bufcnt: buffer count
7374 * @is_contiguous: alloc contiguous mem or not
7375 *
7376 * Returns 0 on success or error on failure
7377 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307378static int q6asm_memory_map_regions(struct audio_client *ac, int dir,
7379 uint32_t bufsz, uint32_t bufcnt,
7380 bool is_contiguous)
7381{
7382 struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
7383 struct avs_shared_map_region_payload *mregions = NULL;
7384 struct audio_port_data *port = NULL;
7385 struct audio_buffer *ab = NULL;
7386 void *mmap_region_cmd = NULL;
7387 void *payload = NULL;
7388 struct asm_buffer_node *buffer_node = NULL;
7389 int rc = 0;
7390 int i = 0;
7391 uint32_t cmd_size = 0;
7392 uint32_t bufcnt_t;
7393 uint32_t bufsz_t;
7394
7395 if (!ac) {
7396 pr_err("%s: APR handle NULL\n", __func__);
7397 return -EINVAL;
7398 }
7399 if (ac->mmap_apr == NULL) {
7400 pr_err("%s: mmap APR handle NULL\n", __func__);
7401 return -EINVAL;
7402 }
7403 pr_debug("%s: Session[%d]\n", __func__, ac->session);
7404
7405 bufcnt_t = (is_contiguous) ? 1 : bufcnt;
7406 bufsz_t = (is_contiguous) ? (bufsz * bufcnt) : bufsz;
7407
7408 if (is_contiguous) {
7409 /* The size to memory map should be multiple of 4K bytes */
7410 bufsz_t = PAGE_ALIGN(bufsz_t);
7411 }
7412
7413 if (bufcnt_t > (UINT_MAX
7414 - sizeof(struct avs_cmd_shared_mem_map_regions))
7415 / sizeof(struct avs_shared_map_region_payload)) {
7416 pr_err("%s: Unsigned Integer Overflow. bufcnt_t = %u\n",
7417 __func__, bufcnt_t);
7418 return -EINVAL;
7419 }
7420
7421 cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions)
7422 + (sizeof(struct avs_shared_map_region_payload)
7423 * bufcnt_t);
7424
7425
7426 if (bufcnt > (UINT_MAX / sizeof(struct asm_buffer_node))) {
7427 pr_err("%s: Unsigned Integer Overflow. bufcnt = %u\n",
7428 __func__, bufcnt);
7429 return -EINVAL;
7430 }
7431
7432 buffer_node = kzalloc(sizeof(struct asm_buffer_node) * bufcnt,
7433 GFP_KERNEL);
7434 if (!buffer_node)
7435 return -ENOMEM;
7436
7437 mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
7438 if (mmap_region_cmd == NULL) {
7439 rc = -EINVAL;
7440 kfree(buffer_node);
7441 return rc;
7442 }
7443 mmap_regions = (struct avs_cmd_shared_mem_map_regions *)
7444 mmap_region_cmd;
7445 q6asm_add_mmaphdr(ac, &mmap_regions->hdr, cmd_size, dir);
7446 atomic_set(&ac->mem_state, -1);
7447 pr_debug("%s: mmap_region=0x%pK token=0x%x\n", __func__,
7448 mmap_regions, ((ac->session << 8) | dir));
7449
7450 mmap_regions->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS;
7451 mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
7452 mmap_regions->num_regions = bufcnt_t; /*bufcnt & 0x00ff; */
7453 mmap_regions->property_flag = 0x00;
7454 pr_debug("%s: map_regions->nregions = %d\n", __func__,
7455 mmap_regions->num_regions);
7456 payload = ((u8 *) mmap_region_cmd +
7457 sizeof(struct avs_cmd_shared_mem_map_regions));
7458 mregions = (struct avs_shared_map_region_payload *)payload;
7459
7460 ac->port[dir].tmp_hdl = 0;
7461 port = &ac->port[dir];
7462 for (i = 0; i < bufcnt_t; i++) {
7463 ab = &port->buf[i];
7464 mregions->shm_addr_lsw = lower_32_bits(ab->phys);
7465 mregions->shm_addr_msw =
7466 msm_audio_populate_upper_32_bits(ab->phys);
7467 mregions->mem_size_bytes = bufsz_t;
7468 ++mregions;
7469 }
7470
7471 rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) mmap_region_cmd);
7472 if (rc < 0) {
7473 pr_err("%s: mmap_regions op[0x%x]rc[%d]\n", __func__,
7474 mmap_regions->hdr.opcode, rc);
7475 rc = -EINVAL;
7476 kfree(buffer_node);
7477 goto fail_cmd;
7478 }
7479
7480 rc = wait_event_timeout(ac->mem_wait,
Meng Wang56d55952018-02-27 11:16:32 +08007481 (atomic_read(&ac->mem_state) >= 0 &&
7482 ac->port[dir].tmp_hdl), 5*HZ);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307483 if (!rc) {
7484 pr_err("%s: timeout. waited for memory_map\n", __func__);
7485 rc = -ETIMEDOUT;
7486 kfree(buffer_node);
7487 goto fail_cmd;
7488 }
7489 if (atomic_read(&ac->mem_state) > 0) {
7490 pr_err("%s DSP returned error for memory_map [%s]\n",
7491 __func__, adsp_err_get_err_str(
7492 atomic_read(&ac->mem_state)));
7493 rc = adsp_err_get_lnx_err_code(
7494 atomic_read(&ac->mem_state));
7495 kfree(buffer_node);
7496 goto fail_cmd;
7497 }
7498 mutex_lock(&ac->cmd_lock);
7499
7500 for (i = 0; i < bufcnt; i++) {
7501 ab = &port->buf[i];
7502 buffer_node[i].buf_phys_addr = ab->phys;
7503 buffer_node[i].mmap_hdl = ac->port[dir].tmp_hdl;
7504 list_add_tail(&buffer_node[i].list,
7505 &ac->port[dir].mem_map_handle);
7506 pr_debug("%s: i=%d, bufadd[i] = 0x%pK, maphdl[i] = 0x%x\n",
7507 __func__, i, &buffer_node[i].buf_phys_addr,
7508 buffer_node[i].mmap_hdl);
7509 }
7510 ac->port[dir].tmp_hdl = 0;
7511 mutex_unlock(&ac->cmd_lock);
7512 rc = 0;
7513fail_cmd:
7514 kfree(mmap_region_cmd);
7515 return rc;
7516}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307517EXPORT_SYMBOL(q6asm_memory_map_regions);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307518
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307519/**
7520 * q6asm_memory_unmap_regions -
7521 * command to send memory unmap regions for ASM
7522 *
7523 * @ac: Audio client handle
7524 * @dir: RX or TX session
7525 *
7526 * Returns 0 on success or error on failure
7527 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307528static int q6asm_memory_unmap_regions(struct audio_client *ac, int dir)
7529{
7530 struct avs_cmd_shared_mem_unmap_regions mem_unmap;
7531 struct audio_port_data *port = NULL;
7532 struct asm_buffer_node *buf_node = NULL;
7533 struct list_head *ptr, *next;
7534 phys_addr_t buf_add;
7535 int rc = 0;
7536 int cmd_size = 0;
7537
7538 if (!ac) {
7539 pr_err("%s: APR handle NULL\n", __func__);
7540 return -EINVAL;
7541 }
7542 if (ac->mmap_apr == NULL) {
7543 pr_err("%s: mmap APR handle NULL\n", __func__);
7544 return -EINVAL;
7545 }
7546 pr_debug("%s: Session[%d]\n", __func__, ac->session);
7547
7548 cmd_size = sizeof(struct avs_cmd_shared_mem_unmap_regions);
7549 q6asm_add_mmaphdr(ac, &mem_unmap.hdr, cmd_size, dir);
7550 atomic_set(&ac->mem_state, -1);
7551 port = &ac->port[dir];
7552 buf_add = port->buf->phys;
7553 mem_unmap.hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS;
7554 mem_unmap.mem_map_handle = 0;
7555 list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
7556 buf_node = list_entry(ptr, struct asm_buffer_node,
7557 list);
7558 if (buf_node->buf_phys_addr == buf_add) {
7559 pr_debug("%s: Found the element\n", __func__);
7560 mem_unmap.mem_map_handle = buf_node->mmap_hdl;
7561 break;
7562 }
7563 }
7564
7565 pr_debug("%s: mem_unmap-mem_map_handle: 0x%x\n",
7566 __func__, mem_unmap.mem_map_handle);
7567
7568 if (mem_unmap.mem_map_handle == 0) {
7569 pr_err("%s: Do not send null mem handle to DSP\n", __func__);
7570 rc = 0;
7571 goto fail_cmd;
7572 }
7573 rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) &mem_unmap);
7574 if (rc < 0) {
7575 pr_err("mmap_regions op[0x%x]rc[%d]\n",
7576 mem_unmap.hdr.opcode, rc);
7577 goto fail_cmd;
7578 }
7579
7580 rc = wait_event_timeout(ac->mem_wait,
7581 (atomic_read(&ac->mem_state) >= 0), 5*HZ);
7582 if (!rc) {
7583 pr_err("%s: timeout. waited for memory_unmap of handle 0x%x\n",
7584 __func__, mem_unmap.mem_map_handle);
7585 rc = -ETIMEDOUT;
7586 goto fail_cmd;
7587 } else if (atomic_read(&ac->mem_state) > 0) {
7588 pr_err("%s: DSP returned error[%s]\n",
7589 __func__, adsp_err_get_err_str(
7590 atomic_read(&ac->mem_state)));
7591 rc = adsp_err_get_lnx_err_code(
7592 atomic_read(&ac->mem_state));
7593 goto fail_cmd;
7594 } else if (atomic_read(&ac->unmap_cb_success) == 0) {
7595 pr_err("%s: Error in mem unmap callback of handle 0x%x\n",
7596 __func__, mem_unmap.mem_map_handle);
7597 rc = -EINVAL;
7598 goto fail_cmd;
7599 }
7600 rc = 0;
7601
7602fail_cmd:
7603 list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
7604 buf_node = list_entry(ptr, struct asm_buffer_node,
7605 list);
7606 if (buf_node->buf_phys_addr == buf_add) {
7607 list_del(&buf_node->list);
7608 kfree(buf_node);
7609 break;
7610 }
7611 }
7612 return rc;
7613}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307614EXPORT_SYMBOL(q6asm_memory_unmap_regions);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307615
7616int q6asm_set_lrgain(struct audio_client *ac, int left_gain, int right_gain)
7617{
7618 struct asm_volume_ctrl_multichannel_gain multi_ch_gain;
7619 int sz = 0;
7620 int rc = 0;
Xiaojun Sanga4648082018-04-27 14:57:33 +08007621 int session_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307622
7623 if (ac == NULL) {
7624 pr_err("%s: APR handle NULL\n", __func__);
7625 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08007626 goto done;
7627 }
7628
7629 session_id = q6asm_get_session_id_from_audio_client(ac);
7630 if (!session_id) {
7631 rc = -EINVAL;
7632 goto done;
7633 }
7634
7635 mutex_lock(&session[session_id].mutex_lock_per_session);
7636 if (!q6asm_is_valid_audio_client(ac)) {
7637 rc = -EINVAL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307638 goto fail_cmd;
7639 }
Xiaojun Sanga4648082018-04-27 14:57:33 +08007640
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307641 if (ac->apr == NULL) {
7642 pr_err("%s: AC APR handle NULL\n", __func__);
7643 rc = -EINVAL;
7644 goto fail_cmd;
7645 }
7646
7647 memset(&multi_ch_gain, 0, sizeof(multi_ch_gain));
7648 sz = sizeof(struct asm_volume_ctrl_multichannel_gain);
7649 q6asm_add_hdr_async(ac, &multi_ch_gain.hdr, sz, TRUE);
7650 atomic_set(&ac->cmd_state_pp, -1);
7651 multi_ch_gain.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
7652 multi_ch_gain.param.data_payload_addr_lsw = 0;
7653 multi_ch_gain.param.data_payload_addr_msw = 0;
7654 multi_ch_gain.param.mem_map_handle = 0;
7655 multi_ch_gain.param.data_payload_size = sizeof(multi_ch_gain) -
7656 sizeof(multi_ch_gain.hdr) - sizeof(multi_ch_gain.param);
7657 multi_ch_gain.data.module_id = ASM_MODULE_ID_VOL_CTRL;
7658 multi_ch_gain.data.param_id = ASM_PARAM_ID_MULTICHANNEL_GAIN;
7659 multi_ch_gain.data.param_size = multi_ch_gain.param.data_payload_size -
7660 sizeof(multi_ch_gain.data);
7661 multi_ch_gain.data.reserved = 0;
7662 multi_ch_gain.gain_data[0].channeltype = PCM_CHANNEL_FL;
7663 multi_ch_gain.gain_data[0].gain = left_gain << 15;
7664 multi_ch_gain.gain_data[1].channeltype = PCM_CHANNEL_FR;
7665 multi_ch_gain.gain_data[1].gain = right_gain << 15;
7666 multi_ch_gain.num_channels = 2;
7667 rc = apr_send_pkt(ac->apr, (uint32_t *) &multi_ch_gain);
7668 if (rc < 0) {
7669 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
7670 __func__, multi_ch_gain.data.param_id, rc);
7671 rc = -EINVAL;
7672 goto fail_cmd;
7673 }
7674
7675 rc = wait_event_timeout(ac->cmd_wait,
7676 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
7677 if (!rc) {
7678 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
7679 multi_ch_gain.data.param_id);
7680 rc = -ETIMEDOUT;
7681 goto fail_cmd;
7682 }
7683 if (atomic_read(&ac->cmd_state_pp) > 0) {
7684 pr_err("%s: DSP returned error[%s] , set-params paramid[0x%x]\n",
7685 __func__, adsp_err_get_err_str(
7686 atomic_read(&ac->cmd_state_pp)),
7687 multi_ch_gain.data.param_id);
7688 rc = adsp_err_get_lnx_err_code(
7689 atomic_read(&ac->cmd_state_pp));
7690 goto fail_cmd;
7691 }
7692 rc = 0;
7693fail_cmd:
Xiaojun Sanga4648082018-04-27 14:57:33 +08007694 mutex_unlock(&session[session_id].mutex_lock_per_session);
7695done:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307696 return rc;
7697}
7698
7699/*
7700 * q6asm_set_multich_gain: set multiple channel gains on an ASM session
7701 * @ac: audio client handle
7702 * @channels: number of channels caller intends to set gains
7703 * @gains: list of gains of audio channels
7704 * @ch_map: list of channel mapping. Only valid if use_default is false
7705 * @use_default: flag to indicate whether to use default mapping
7706 */
7707int q6asm_set_multich_gain(struct audio_client *ac, uint32_t channels,
7708 uint32_t *gains, uint8_t *ch_map, bool use_default)
7709{
7710 struct asm_volume_ctrl_multichannel_gain multich_gain;
7711 int sz = 0;
7712 int rc = 0;
Xiaojun Sanga4648082018-04-27 14:57:33 +08007713 int i, session_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307714 u8 default_chmap[VOLUME_CONTROL_MAX_CHANNELS];
7715
7716 if (ac == NULL) {
7717 pr_err("%s: ac is NULL\n", __func__);
7718 rc = -EINVAL;
7719 goto done;
7720 }
Xiaojun Sanga4648082018-04-27 14:57:33 +08007721
7722 session_id = q6asm_get_session_id_from_audio_client(ac);
7723 if (!session_id) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307724 rc = -EINVAL;
7725 goto done;
7726 }
7727
7728 memset(&multich_gain, 0, sizeof(multich_gain));
7729 sz = sizeof(struct asm_volume_ctrl_multichannel_gain);
Xiaojun Sanga4648082018-04-27 14:57:33 +08007730 mutex_lock(&session[session_id].mutex_lock_per_session);
7731 if (!q6asm_is_valid_audio_client(ac)) {
7732 rc = -EINVAL;
7733 goto fail_cmd;
7734 }
7735
7736 if (ac->apr == NULL) {
7737 dev_err(ac->dev, "%s: AC APR handle NULL\n", __func__);
7738 rc = -EINVAL;
7739 goto fail_cmd;
7740 }
7741
7742 if (gains == NULL) {
7743 dev_err(ac->dev, "%s: gain_list is NULL\n", __func__);
7744 rc = -EINVAL;
7745 goto fail_cmd;
7746 }
7747 if (channels > VOLUME_CONTROL_MAX_CHANNELS) {
7748 dev_err(ac->dev, "%s: Invalid channel count %d\n",
7749 __func__, channels);
7750 rc = -EINVAL;
7751 goto fail_cmd;
7752 }
7753 if (!use_default && ch_map == NULL) {
7754 dev_err(ac->dev, "%s: NULL channel map\n", __func__);
7755 rc = -EINVAL;
7756 goto fail_cmd;
7757 }
7758
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307759 q6asm_add_hdr_async(ac, &multich_gain.hdr, sz, TRUE);
7760 atomic_set(&ac->cmd_state_pp, -1);
7761 multich_gain.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
7762 multich_gain.param.data_payload_addr_lsw = 0;
7763 multich_gain.param.data_payload_addr_msw = 0;
7764 multich_gain.param.mem_map_handle = 0;
7765 multich_gain.param.data_payload_size = sizeof(multich_gain) -
7766 sizeof(multich_gain.hdr) - sizeof(multich_gain.param);
7767 multich_gain.data.module_id = ASM_MODULE_ID_VOL_CTRL;
7768 multich_gain.data.param_id = ASM_PARAM_ID_MULTICHANNEL_GAIN;
7769 multich_gain.data.param_size = multich_gain.param.data_payload_size -
7770 sizeof(multich_gain.data);
7771 multich_gain.data.reserved = 0;
7772
7773 if (use_default) {
7774 rc = q6asm_map_channels(default_chmap, channels, false);
7775 if (rc < 0)
Xiaojun Sanga4648082018-04-27 14:57:33 +08007776 goto fail_cmd;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307777 for (i = 0; i < channels; i++) {
7778 multich_gain.gain_data[i].channeltype =
7779 default_chmap[i];
7780 multich_gain.gain_data[i].gain = gains[i] << 15;
7781 }
7782 } else {
7783 for (i = 0; i < channels; i++) {
7784 multich_gain.gain_data[i].channeltype = ch_map[i];
7785 multich_gain.gain_data[i].gain = gains[i] << 15;
7786 }
7787 }
7788 multich_gain.num_channels = channels;
7789
7790 rc = apr_send_pkt(ac->apr, (uint32_t *) &multich_gain);
7791 if (rc < 0) {
7792 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
7793 __func__, multich_gain.data.param_id, rc);
Xiaojun Sanga4648082018-04-27 14:57:33 +08007794 goto fail_cmd;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307795 }
7796
7797 rc = wait_event_timeout(ac->cmd_wait,
7798 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
7799 if (!rc) {
7800 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
7801 multich_gain.data.param_id);
7802 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08007803 goto fail_cmd;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307804 }
7805 if (atomic_read(&ac->cmd_state_pp) > 0) {
7806 pr_err("%s: DSP returned error[%d] , set-params paramid[0x%x]\n",
7807 __func__, atomic_read(&ac->cmd_state_pp),
7808 multich_gain.data.param_id);
7809 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08007810 goto fail_cmd;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307811 }
7812 rc = 0;
Xiaojun Sanga4648082018-04-27 14:57:33 +08007813fail_cmd:
7814 mutex_unlock(&session[session_id].mutex_lock_per_session);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307815done:
7816 return rc;
7817}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307818EXPORT_SYMBOL(q6asm_set_multich_gain);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307819
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307820/**
7821 * q6asm_set_mute -
7822 * command to set mute for ASM
7823 *
7824 * @ac: Audio client handle
7825 * @muteflag: mute value
7826 *
7827 * Returns 0 on success or error on failure
7828 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307829int q6asm_set_mute(struct audio_client *ac, int muteflag)
7830{
7831 struct asm_volume_ctrl_mute_config mute;
7832 int sz = 0;
7833 int rc = 0;
Xiaojun Sanga4648082018-04-27 14:57:33 +08007834 int session_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307835
7836 if (ac == NULL) {
7837 pr_err("%s: APR handle NULL\n", __func__);
7838 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08007839 goto done;
7840 }
7841
7842 session_id = q6asm_get_session_id_from_audio_client(ac);
7843 if (!session_id) {
7844 rc = -EINVAL;
7845 goto done;
7846 }
7847
7848 mutex_lock(&session[session_id].mutex_lock_per_session);
7849 if (!q6asm_is_valid_audio_client(ac)) {
7850 rc = -EINVAL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307851 goto fail_cmd;
7852 }
Xiaojun Sanga4648082018-04-27 14:57:33 +08007853
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307854 if (ac->apr == NULL) {
7855 pr_err("%s: AC APR handle NULL\n", __func__);
7856 rc = -EINVAL;
7857 goto fail_cmd;
7858 }
7859
7860 sz = sizeof(struct asm_volume_ctrl_mute_config);
7861 q6asm_add_hdr_async(ac, &mute.hdr, sz, TRUE);
7862 atomic_set(&ac->cmd_state_pp, -1);
7863 mute.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
7864 mute.param.data_payload_addr_lsw = 0;
7865 mute.param.data_payload_addr_msw = 0;
7866 mute.param.mem_map_handle = 0;
7867 mute.param.data_payload_size = sizeof(mute) -
7868 sizeof(mute.hdr) - sizeof(mute.param);
7869 mute.data.module_id = ASM_MODULE_ID_VOL_CTRL;
7870 mute.data.param_id = ASM_PARAM_ID_VOL_CTRL_MUTE_CONFIG;
7871 mute.data.param_size = mute.param.data_payload_size - sizeof(mute.data);
7872 mute.data.reserved = 0;
7873 mute.mute_flag = muteflag;
7874
7875 rc = apr_send_pkt(ac->apr, (uint32_t *) &mute);
7876 if (rc < 0) {
7877 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
7878 __func__, mute.data.param_id, rc);
7879 rc = -EINVAL;
7880 goto fail_cmd;
7881 }
7882
7883 rc = wait_event_timeout(ac->cmd_wait,
7884 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
7885 if (!rc) {
7886 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
7887 mute.data.param_id);
7888 rc = -ETIMEDOUT;
7889 goto fail_cmd;
7890 }
7891 if (atomic_read(&ac->cmd_state_pp) > 0) {
7892 pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
7893 __func__, adsp_err_get_err_str(
7894 atomic_read(&ac->cmd_state_pp)),
7895 mute.data.param_id);
7896 rc = adsp_err_get_lnx_err_code(
7897 atomic_read(&ac->cmd_state_pp));
7898 goto fail_cmd;
7899 }
7900 rc = 0;
7901fail_cmd:
Xiaojun Sanga4648082018-04-27 14:57:33 +08007902 mutex_unlock(&session[session_id].mutex_lock_per_session);
7903done:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307904 return rc;
7905}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307906EXPORT_SYMBOL(q6asm_set_mute);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307907
7908static int __q6asm_set_volume(struct audio_client *ac, int volume, int instance)
7909{
7910 struct asm_volume_ctrl_master_gain vol;
7911 int sz = 0;
7912 int rc = 0;
Xiaojun Sanga4648082018-04-27 14:57:33 +08007913 int module_id, session_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307914
7915 if (ac == NULL) {
7916 pr_err("%s: APR handle NULL\n", __func__);
7917 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08007918 goto done;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307919 }
Xiaojun Sanga4648082018-04-27 14:57:33 +08007920
7921 session_id = q6asm_get_session_id_from_audio_client(ac);
7922 if (!session_id) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307923 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08007924 goto done;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307925 }
7926
7927 switch (instance) {
7928 case SOFT_VOLUME_INSTANCE_2:
7929 module_id = ASM_MODULE_ID_VOL_CTRL2;
7930 break;
7931 case SOFT_VOLUME_INSTANCE_1:
7932 default:
7933 module_id = ASM_MODULE_ID_VOL_CTRL;
7934 break;
7935 }
7936
7937 sz = sizeof(struct asm_volume_ctrl_master_gain);
Xiaojun Sanga4648082018-04-27 14:57:33 +08007938 mutex_lock(&session[session_id].mutex_lock_per_session);
7939 if (!q6asm_is_valid_audio_client(ac)) {
7940 rc = -EINVAL;
7941 goto fail_cmd;
7942 }
7943
7944 if (ac->apr == NULL) {
7945 pr_err("%s: AC APR handle NULL\n", __func__);
7946 rc = -EINVAL;
7947 goto fail_cmd;
7948 }
7949
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307950 q6asm_add_hdr_async(ac, &vol.hdr, sz, TRUE);
7951 atomic_set(&ac->cmd_state_pp, -1);
7952 vol.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
7953 vol.param.data_payload_addr_lsw = 0;
7954 vol.param.data_payload_addr_msw = 0;
7955 vol.param.mem_map_handle = 0;
7956 vol.param.data_payload_size = sizeof(vol) -
7957 sizeof(vol.hdr) - sizeof(vol.param);
7958 vol.data.module_id = module_id;
7959 vol.data.param_id = ASM_PARAM_ID_VOL_CTRL_MASTER_GAIN;
7960 vol.data.param_size = vol.param.data_payload_size - sizeof(vol.data);
7961 vol.data.reserved = 0;
7962 vol.master_gain = volume;
7963
7964 rc = apr_send_pkt(ac->apr, (uint32_t *) &vol);
7965 if (rc < 0) {
7966 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
7967 __func__, vol.data.param_id, rc);
7968 rc = -EINVAL;
7969 goto fail_cmd;
7970 }
7971
7972 rc = wait_event_timeout(ac->cmd_wait,
7973 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
7974 if (!rc) {
7975 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
7976 vol.data.param_id);
7977 rc = -ETIMEDOUT;
7978 goto fail_cmd;
7979 }
7980 if (atomic_read(&ac->cmd_state_pp) > 0) {
7981 pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
7982 __func__, adsp_err_get_err_str(
7983 atomic_read(&ac->cmd_state_pp)),
7984 vol.data.param_id);
7985 rc = adsp_err_get_lnx_err_code(
7986 atomic_read(&ac->cmd_state_pp));
7987 goto fail_cmd;
7988 }
7989
7990 rc = 0;
7991fail_cmd:
Xiaojun Sanga4648082018-04-27 14:57:33 +08007992 mutex_unlock(&session[session_id].mutex_lock_per_session);
7993done:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307994 return rc;
7995}
7996
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307997/**
7998 * q6asm_set_volume -
7999 * command to set volume for ASM
8000 *
8001 * @ac: Audio client handle
8002 * @volume: volume level
8003 *
8004 * Returns 0 on success or error on failure
8005 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308006int q6asm_set_volume(struct audio_client *ac, int volume)
8007{
8008 return __q6asm_set_volume(ac, volume, SOFT_VOLUME_INSTANCE_1);
8009}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308010EXPORT_SYMBOL(q6asm_set_volume);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308011
8012int q6asm_set_volume_v2(struct audio_client *ac, int volume, int instance)
8013{
8014 return __q6asm_set_volume(ac, volume, instance);
8015}
8016
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308017/**
8018 * q6asm_set_aptx_dec_bt_addr -
8019 * command to aptx decoder BT addr for ASM
8020 *
8021 * @ac: Audio client handle
8022 * @cfg: APTX decoder bt addr config
8023 *
8024 * Returns 0 on success or error on failure
8025 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308026int q6asm_set_aptx_dec_bt_addr(struct audio_client *ac,
8027 struct aptx_dec_bt_addr_cfg *cfg)
8028{
8029 struct aptx_dec_bt_dev_addr paylod;
8030 int sz = 0;
8031 int rc = 0;
8032
8033 pr_debug("%s: BT addr nap %d, uap %d, lap %d\n", __func__, cfg->nap,
8034 cfg->uap, cfg->lap);
8035
8036 if (ac == NULL) {
8037 pr_err("%s: AC handle NULL\n", __func__);
8038 rc = -EINVAL;
8039 goto fail_cmd;
8040 }
8041 if (ac->apr == NULL) {
8042 pr_err("%s: AC APR handle NULL\n", __func__);
8043 rc = -EINVAL;
8044 goto fail_cmd;
8045 }
8046
8047 sz = sizeof(struct aptx_dec_bt_dev_addr);
8048 q6asm_add_hdr_async(ac, &paylod.hdr, sz, TRUE);
8049 atomic_set(&ac->cmd_state, -1);
8050 paylod.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
8051 paylod.encdec.param_id = APTX_DECODER_BT_ADDRESS;
8052 paylod.encdec.param_size = sz - sizeof(paylod.hdr)
8053 - sizeof(paylod.encdec);
8054 paylod.bt_addr_cfg.lap = cfg->lap;
8055 paylod.bt_addr_cfg.uap = cfg->uap;
8056 paylod.bt_addr_cfg.nap = cfg->nap;
8057
8058 rc = apr_send_pkt(ac->apr, (uint32_t *) &paylod);
8059 if (rc < 0) {
8060 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
8061 __func__, paylod.encdec.param_id, rc);
8062 rc = -EINVAL;
8063 goto fail_cmd;
8064 }
8065
8066 rc = wait_event_timeout(ac->cmd_wait,
8067 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
8068 if (!rc) {
8069 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
8070 paylod.encdec.param_id);
8071 rc = -ETIMEDOUT;
8072 goto fail_cmd;
8073 }
8074 if (atomic_read(&ac->cmd_state) > 0) {
8075 pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
8076 __func__, adsp_err_get_err_str(
8077 atomic_read(&ac->cmd_state)),
8078 paylod.encdec.param_id);
8079 rc = adsp_err_get_lnx_err_code(
8080 atomic_read(&ac->cmd_state));
8081 goto fail_cmd;
8082 }
8083 pr_debug("%s: set BT addr is success\n", __func__);
8084 rc = 0;
8085fail_cmd:
8086 return rc;
8087}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308088EXPORT_SYMBOL(q6asm_set_aptx_dec_bt_addr);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308089
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308090/**
8091 * q6asm_send_ion_fd -
8092 * command to send ION memory map for ASM
8093 *
8094 * @ac: Audio client handle
8095 * @fd: ION file desc
8096 *
8097 * Returns 0 on success or error on failure
8098 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308099int q6asm_send_ion_fd(struct audio_client *ac, int fd)
8100{
8101 struct ion_client *client;
8102 struct ion_handle *handle;
8103 ion_phys_addr_t paddr;
8104 size_t pa_len = 0;
8105 void *vaddr;
8106 int ret;
8107 int sz = 0;
8108 struct avs_rtic_shared_mem_addr shm;
8109
8110 if (ac == NULL) {
8111 pr_err("%s: APR handle NULL\n", __func__);
8112 ret = -EINVAL;
8113 goto fail_cmd;
8114 }
8115 if (ac->apr == NULL) {
8116 pr_err("%s: AC APR handle NULL\n", __func__);
8117 ret = -EINVAL;
8118 goto fail_cmd;
8119 }
8120
8121 ret = msm_audio_ion_import("audio_mem_client",
8122 &client,
8123 &handle,
8124 fd,
8125 NULL,
8126 0,
8127 &paddr,
8128 &pa_len,
8129 &vaddr);
8130 if (ret) {
8131 pr_err("%s: audio ION import failed, rc = %d\n",
8132 __func__, ret);
8133 ret = -ENOMEM;
8134 goto fail_cmd;
8135 }
8136 /* get payload length */
8137 sz = sizeof(struct avs_rtic_shared_mem_addr);
8138 q6asm_add_hdr_async(ac, &shm.hdr, sz, TRUE);
8139 atomic_set(&ac->cmd_state, -1);
8140 shm.shm_buf_addr_lsw = lower_32_bits(paddr);
8141 shm.shm_buf_addr_msw = msm_audio_populate_upper_32_bits(paddr);
8142 shm.buf_size = pa_len;
8143 shm.shm_buf_num_regions = 1;
8144 shm.shm_buf_mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
8145 shm.shm_buf_flag = 0x00;
8146 shm.encdec.param_id = AVS_PARAM_ID_RTIC_SHARED_MEMORY_ADDR;
8147 shm.encdec.param_size = sizeof(struct avs_rtic_shared_mem_addr) -
8148 sizeof(struct apr_hdr) -
8149 sizeof(struct asm_stream_cmd_set_encdec_param_v2);
8150 shm.encdec.service_id = OUT;
8151 shm.encdec.reserved = 0;
8152 shm.map_region.shm_addr_lsw = shm.shm_buf_addr_lsw;
8153 shm.map_region.shm_addr_msw = shm.shm_buf_addr_msw;
8154 shm.map_region.mem_size_bytes = pa_len;
8155 shm.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM_V2;
8156 ret = apr_send_pkt(ac->apr, (uint32_t *) &shm);
8157 if (ret < 0) {
8158 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
8159 __func__, shm.encdec.param_id, ret);
8160 ret = -EINVAL;
8161 goto fail_cmd;
8162 }
8163
8164 ret = wait_event_timeout(ac->cmd_wait,
8165 (atomic_read(&ac->cmd_state) >= 0), 1*HZ);
8166 if (!ret) {
8167 pr_err("%s: timeout, shm.encdec paramid[0x%x]\n", __func__,
8168 shm.encdec.param_id);
8169 ret = -ETIMEDOUT;
8170 goto fail_cmd;
8171 }
8172 if (atomic_read(&ac->cmd_state) > 0) {
8173 pr_err("%s: DSP returned error[%s] shm.encdec paramid[0x%x]\n",
8174 __func__,
8175 adsp_err_get_err_str(atomic_read(&ac->cmd_state)),
8176 shm.encdec.param_id);
8177 ret = adsp_err_get_lnx_err_code(atomic_read(&ac->cmd_state));
8178 goto fail_cmd;
8179 }
8180 ret = 0;
8181fail_cmd:
8182 return ret;
8183}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308184EXPORT_SYMBOL(q6asm_send_ion_fd);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308185
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308186/**
8187 * q6asm_send_rtic_event_ack -
8188 * command to send RTIC event ack
8189 *
8190 * @ac: Audio client handle
8191 * @param: params for event ack
8192 * @params_length: length of params
8193 *
8194 * Returns 0 on success or error on failure
8195 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308196int q6asm_send_rtic_event_ack(struct audio_client *ac,
8197 void *param, uint32_t params_length)
8198{
8199 char *asm_params = NULL;
8200 int sz, rc;
8201 struct avs_param_rtic_event_ack ack;
8202
8203 if (!param || !ac) {
8204 pr_err("%s: %s is NULL\n", __func__,
8205 (!param) ? "param" : "ac");
8206 rc = -EINVAL;
8207 goto done;
8208 }
8209
8210 sz = sizeof(struct avs_param_rtic_event_ack) + params_length;
8211 asm_params = kzalloc(sz, GFP_KERNEL);
8212 if (!asm_params) {
8213 rc = -ENOMEM;
8214 goto done;
8215 }
8216
8217 q6asm_add_hdr_async(ac, &ack.hdr,
8218 sizeof(struct avs_param_rtic_event_ack) +
8219 params_length, TRUE);
8220 atomic_set(&ac->cmd_state, -1);
8221 ack.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM_V2;
8222 ack.encdec.param_id = AVS_PARAM_ID_RTIC_EVENT_ACK;
8223 ack.encdec.param_size = params_length;
8224 ack.encdec.reserved = 0;
8225 ack.encdec.service_id = OUT;
8226 memcpy(asm_params, &ack, sizeof(struct avs_param_rtic_event_ack));
8227 memcpy(asm_params + sizeof(struct avs_param_rtic_event_ack),
8228 param, params_length);
8229 rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params);
8230 if (rc < 0) {
8231 pr_err("%s: apr pkt failed for rtic event ack\n", __func__);
8232 rc = -EINVAL;
8233 goto fail_send_param;
8234 }
8235
8236 rc = wait_event_timeout(ac->cmd_wait,
8237 (atomic_read(&ac->cmd_state) >= 0), 1 * HZ);
8238 if (!rc) {
8239 pr_err("%s: timeout for rtic event ack cmd\n", __func__);
8240 rc = -ETIMEDOUT;
8241 goto fail_send_param;
8242 }
8243
8244 if (atomic_read(&ac->cmd_state) > 0) {
8245 pr_err("%s: DSP returned error[%s] for rtic event ack cmd\n",
8246 __func__, adsp_err_get_err_str(
8247 atomic_read(&ac->cmd_state)));
8248 rc = adsp_err_get_lnx_err_code(
8249 atomic_read(&ac->cmd_state));
8250 goto fail_send_param;
8251 }
8252 rc = 0;
8253
8254fail_send_param:
8255 kfree(asm_params);
8256done:
8257 return rc;
8258}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308259EXPORT_SYMBOL(q6asm_send_rtic_event_ack);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308260
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308261/**
8262 * q6asm_set_softpause -
8263 * command to set pause for ASM
8264 *
8265 * @ac: Audio client handle
8266 * @pause_param: params for pause
8267 *
8268 * Returns 0 on success or error on failure
8269 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308270int q6asm_set_softpause(struct audio_client *ac,
8271 struct asm_softpause_params *pause_param)
8272{
8273 struct asm_soft_pause_params softpause;
8274 int sz = 0;
8275 int rc = 0;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008276 int session_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308277
8278 if (ac == NULL) {
8279 pr_err("%s: APR handle NULL\n", __func__);
8280 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008281 goto done;
8282 }
8283
8284 session_id = q6asm_get_session_id_from_audio_client(ac);
8285 if (!session_id) {
8286 rc = -EINVAL;
8287 goto done;
8288 }
8289
8290 mutex_lock(&session[session_id].mutex_lock_per_session);
8291 if (!q6asm_is_valid_audio_client(ac)) {
8292 rc = -EINVAL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308293 goto fail_cmd;
8294 }
Xiaojun Sanga4648082018-04-27 14:57:33 +08008295
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308296 if (ac->apr == NULL) {
8297 pr_err("%s: AC APR handle NULL\n", __func__);
8298 rc = -EINVAL;
8299 goto fail_cmd;
8300 }
8301
8302 sz = sizeof(struct asm_soft_pause_params);
8303 q6asm_add_hdr_async(ac, &softpause.hdr, sz, TRUE);
8304 atomic_set(&ac->cmd_state_pp, -1);
8305 softpause.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
8306
8307 softpause.param.data_payload_addr_lsw = 0;
8308 softpause.param.data_payload_addr_msw = 0;
8309 softpause.param.mem_map_handle = 0;
8310 softpause.param.data_payload_size = sizeof(softpause) -
8311 sizeof(softpause.hdr) - sizeof(softpause.param);
8312 softpause.data.module_id = ASM_MODULE_ID_VOL_CTRL;
8313 softpause.data.param_id = ASM_PARAM_ID_SOFT_PAUSE_PARAMETERS;
8314 softpause.data.param_size = softpause.param.data_payload_size -
8315 sizeof(softpause.data);
8316 softpause.data.reserved = 0;
8317 softpause.enable_flag = pause_param->enable;
8318 softpause.period = pause_param->period;
8319 softpause.step = pause_param->step;
8320 softpause.ramping_curve = pause_param->rampingcurve;
8321
8322 rc = apr_send_pkt(ac->apr, (uint32_t *) &softpause);
8323 if (rc < 0) {
8324 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
8325 __func__, softpause.data.param_id, rc);
8326 rc = -EINVAL;
8327 goto fail_cmd;
8328 }
8329
8330 rc = wait_event_timeout(ac->cmd_wait,
8331 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
8332 if (!rc) {
8333 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
8334 softpause.data.param_id);
8335 rc = -ETIMEDOUT;
8336 goto fail_cmd;
8337 }
8338 if (atomic_read(&ac->cmd_state_pp) > 0) {
8339 pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
8340 __func__, adsp_err_get_err_str(
8341 atomic_read(&ac->cmd_state_pp)),
8342 softpause.data.param_id);
8343 rc = adsp_err_get_lnx_err_code(
8344 atomic_read(&ac->cmd_state_pp));
8345 goto fail_cmd;
8346 }
8347 rc = 0;
8348fail_cmd:
Xiaojun Sanga4648082018-04-27 14:57:33 +08008349 mutex_unlock(&session[session_id].mutex_lock_per_session);
8350done:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308351 return rc;
8352}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308353EXPORT_SYMBOL(q6asm_set_softpause);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308354
8355static int __q6asm_set_softvolume(struct audio_client *ac,
8356 struct asm_softvolume_params *softvol_param,
8357 int instance)
8358{
8359 struct asm_soft_step_volume_params softvol;
8360 int sz = 0;
8361 int rc = 0;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008362 int module_id, session_id;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308363
8364 if (ac == NULL) {
8365 pr_err("%s: APR handle NULL\n", __func__);
8366 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008367 goto done;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308368 }
Xiaojun Sanga4648082018-04-27 14:57:33 +08008369
8370 session_id = q6asm_get_session_id_from_audio_client(ac);
8371 if (!session_id) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308372 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008373 goto done;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308374 }
8375
8376 switch (instance) {
8377 case SOFT_VOLUME_INSTANCE_2:
8378 module_id = ASM_MODULE_ID_VOL_CTRL2;
8379 break;
8380 case SOFT_VOLUME_INSTANCE_1:
8381 default:
8382 module_id = ASM_MODULE_ID_VOL_CTRL;
8383 break;
8384 }
8385
8386 sz = sizeof(struct asm_soft_step_volume_params);
Xiaojun Sanga4648082018-04-27 14:57:33 +08008387 mutex_lock(&session[session_id].mutex_lock_per_session);
8388 if (!q6asm_is_valid_audio_client(ac)) {
8389 rc = -EINVAL;
8390 goto fail_cmd;
8391 }
8392
8393 if (ac->apr == NULL) {
8394 pr_err("%s: AC APR handle NULL\n", __func__);
8395 rc = -EINVAL;
8396 goto fail_cmd;
8397 }
8398
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308399 q6asm_add_hdr_async(ac, &softvol.hdr, sz, TRUE);
8400 atomic_set(&ac->cmd_state_pp, -1);
8401 softvol.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
8402 softvol.param.data_payload_addr_lsw = 0;
8403 softvol.param.data_payload_addr_msw = 0;
8404 softvol.param.mem_map_handle = 0;
8405 softvol.param.data_payload_size = sizeof(softvol) -
8406 sizeof(softvol.hdr) - sizeof(softvol.param);
8407 softvol.data.module_id = module_id;
8408 softvol.data.param_id = ASM_PARAM_ID_SOFT_VOL_STEPPING_PARAMETERS;
8409 softvol.data.param_size = softvol.param.data_payload_size -
8410 sizeof(softvol.data);
8411 softvol.data.reserved = 0;
8412 softvol.period = softvol_param->period;
8413 softvol.step = softvol_param->step;
8414 softvol.ramping_curve = softvol_param->rampingcurve;
8415
8416 rc = apr_send_pkt(ac->apr, (uint32_t *) &softvol);
8417 if (rc < 0) {
8418 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
8419 __func__, softvol.data.param_id, rc);
8420 rc = -EINVAL;
8421 goto fail_cmd;
8422 }
8423
8424 rc = wait_event_timeout(ac->cmd_wait,
8425 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
8426 if (!rc) {
8427 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
8428 softvol.data.param_id);
8429 rc = -ETIMEDOUT;
8430 goto fail_cmd;
8431 }
8432 if (atomic_read(&ac->cmd_state_pp) > 0) {
8433 pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
8434 __func__, adsp_err_get_err_str(
8435 atomic_read(&ac->cmd_state_pp)),
8436 softvol.data.param_id);
8437 rc = adsp_err_get_lnx_err_code(
8438 atomic_read(&ac->cmd_state_pp));
8439 goto fail_cmd;
8440 }
8441 rc = 0;
8442fail_cmd:
Xiaojun Sanga4648082018-04-27 14:57:33 +08008443 mutex_unlock(&session[session_id].mutex_lock_per_session);
8444done:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308445 return rc;
8446}
8447
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308448/**
8449 * q6asm_set_softvolume -
8450 * command to set softvolume for ASM
8451 *
8452 * @ac: Audio client handle
8453 * @softvol_param: params for softvol
8454 *
8455 * Returns 0 on success or error on failure
8456 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308457int q6asm_set_softvolume(struct audio_client *ac,
8458 struct asm_softvolume_params *softvol_param)
8459{
8460 return __q6asm_set_softvolume(ac, softvol_param,
8461 SOFT_VOLUME_INSTANCE_1);
8462}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308463EXPORT_SYMBOL(q6asm_set_softvolume);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308464
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308465/**
8466 * q6asm_set_softvolume_v2 -
8467 * command to set softvolume V2 for ASM
8468 *
8469 * @ac: Audio client handle
8470 * @softvol_param: params for softvol
8471 * @instance: instance to apply softvol
8472 *
8473 * Returns 0 on success or error on failure
8474 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308475int q6asm_set_softvolume_v2(struct audio_client *ac,
8476 struct asm_softvolume_params *softvol_param,
8477 int instance)
8478{
8479 return __q6asm_set_softvolume(ac, softvol_param, instance);
8480}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308481EXPORT_SYMBOL(q6asm_set_softvolume_v2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308482
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308483/**
8484 * q6asm_equalizer -
8485 * command to set equalizer for ASM
8486 *
8487 * @ac: Audio client handle
8488 * @eq_p: Equalizer params
8489 *
8490 * Returns 0 on success or error on failure
8491 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308492int q6asm_equalizer(struct audio_client *ac, void *eq_p)
8493{
8494 struct asm_eq_params eq;
8495 struct msm_audio_eq_stream_config *eq_params = NULL;
8496 int i = 0;
8497 int sz = 0;
8498 int rc = 0;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008499 int session_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308500
8501 if (ac == NULL) {
8502 pr_err("%s: APR handle NULL\n", __func__);
8503 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008504 goto done;
8505 }
8506
8507 session_id = q6asm_get_session_id_from_audio_client(ac);
8508 if (!session_id) {
8509 rc = -EINVAL;
8510 goto done;
8511 }
8512
8513 mutex_lock(&session[session_id].mutex_lock_per_session);
8514 if (!q6asm_is_valid_audio_client(ac)) {
8515 rc = -EINVAL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308516 goto fail_cmd;
8517 }
Xiaojun Sanga4648082018-04-27 14:57:33 +08008518
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308519 if (ac->apr == NULL) {
8520 pr_err("%s: AC APR handle NULL\n", __func__);
8521 rc = -EINVAL;
8522 goto fail_cmd;
8523 }
8524
8525 if (eq_p == NULL) {
8526 pr_err("%s: [%d]: Invalid Eq param\n", __func__, ac->session);
8527 rc = -EINVAL;
8528 goto fail_cmd;
8529 }
8530 sz = sizeof(struct asm_eq_params);
8531 eq_params = (struct msm_audio_eq_stream_config *) eq_p;
8532 q6asm_add_hdr(ac, &eq.hdr, sz, TRUE);
8533 atomic_set(&ac->cmd_state_pp, -1);
8534
8535 eq.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
8536 eq.param.data_payload_addr_lsw = 0;
8537 eq.param.data_payload_addr_msw = 0;
8538 eq.param.mem_map_handle = 0;
8539 eq.param.data_payload_size = sizeof(eq) -
8540 sizeof(eq.hdr) - sizeof(eq.param);
8541 eq.data.module_id = ASM_MODULE_ID_EQUALIZER;
8542 eq.data.param_id = ASM_PARAM_ID_EQUALIZER_PARAMETERS;
8543 eq.data.param_size = eq.param.data_payload_size - sizeof(eq.data);
8544 eq.enable_flag = eq_params->enable;
8545 eq.num_bands = eq_params->num_bands;
8546
8547 pr_debug("%s: enable:%d numbands:%d\n", __func__, eq_params->enable,
8548 eq_params->num_bands);
8549 for (i = 0; i < eq_params->num_bands; i++) {
8550 eq.eq_bands[i].band_idx =
8551 eq_params->eq_bands[i].band_idx;
8552 eq.eq_bands[i].filterype =
8553 eq_params->eq_bands[i].filter_type;
8554 eq.eq_bands[i].center_freq_hz =
8555 eq_params->eq_bands[i].center_freq_hz;
8556 eq.eq_bands[i].filter_gain =
8557 eq_params->eq_bands[i].filter_gain;
8558 eq.eq_bands[i].q_factor =
8559 eq_params->eq_bands[i].q_factor;
8560 pr_debug("%s: filter_type:%u bandnum:%d\n", __func__,
8561 eq_params->eq_bands[i].filter_type, i);
8562 pr_debug("%s: center_freq_hz:%u bandnum:%d\n", __func__,
8563 eq_params->eq_bands[i].center_freq_hz, i);
8564 pr_debug("%s: filter_gain:%d bandnum:%d\n", __func__,
8565 eq_params->eq_bands[i].filter_gain, i);
8566 pr_debug("%s: q_factor:%d bandnum:%d\n", __func__,
8567 eq_params->eq_bands[i].q_factor, i);
8568 }
8569 rc = apr_send_pkt(ac->apr, (uint32_t *)&eq);
8570 if (rc < 0) {
8571 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
8572 __func__, eq.data.param_id, rc);
8573 rc = -EINVAL;
8574 goto fail_cmd;
8575 }
8576
8577 rc = wait_event_timeout(ac->cmd_wait,
8578 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
8579 if (!rc) {
8580 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
8581 eq.data.param_id);
8582 rc = -ETIMEDOUT;
8583 goto fail_cmd;
8584 }
8585 if (atomic_read(&ac->cmd_state_pp) > 0) {
8586 pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
8587 __func__, adsp_err_get_err_str(
8588 atomic_read(&ac->cmd_state_pp)),
8589 eq.data.param_id);
8590 rc = adsp_err_get_lnx_err_code(
8591 atomic_read(&ac->cmd_state_pp));
8592 goto fail_cmd;
8593 }
8594 rc = 0;
8595fail_cmd:
Xiaojun Sanga4648082018-04-27 14:57:33 +08008596 mutex_unlock(&session[session_id].mutex_lock_per_session);
8597done:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308598 return rc;
8599}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308600EXPORT_SYMBOL(q6asm_equalizer);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308601
8602static int __q6asm_read(struct audio_client *ac, bool is_custom_len_reqd,
8603 int len)
8604{
8605 struct asm_data_cmd_read_v2 read;
8606 struct asm_buffer_node *buf_node = NULL;
8607 struct list_head *ptr, *next;
8608 struct audio_buffer *ab;
8609 int dsp_buf;
8610 struct audio_port_data *port;
8611 int rc;
8612
8613 if (ac == NULL) {
8614 pr_err("%s: APR handle NULL\n", __func__);
8615 return -EINVAL;
8616 }
8617 if (ac->apr == NULL) {
8618 pr_err("%s: AC APR handle NULL\n", __func__);
8619 return -EINVAL;
8620 }
8621
8622 if (ac->io_mode & SYNC_IO_MODE) {
8623 port = &ac->port[OUT];
8624
8625 q6asm_add_hdr(ac, &read.hdr, sizeof(read), FALSE);
8626
8627 mutex_lock(&port->lock);
8628
8629 dsp_buf = port->dsp_buf;
8630 if (port->buf == NULL) {
8631 pr_err("%s: buf is NULL\n", __func__);
8632 mutex_unlock(&port->lock);
8633 return -EINVAL;
8634 }
8635 ab = &port->buf[dsp_buf];
8636
8637 dev_vdbg(ac->dev, "%s: session[%d]dsp-buf[%d][%pK]cpu_buf[%d][%pK]\n",
8638 __func__,
8639 ac->session,
8640 dsp_buf,
8641 port->buf[dsp_buf].data,
8642 port->cpu_buf,
8643 &port->buf[port->cpu_buf].phys);
8644
8645 read.hdr.opcode = ASM_DATA_CMD_READ_V2;
8646 read.buf_addr_lsw = lower_32_bits(ab->phys);
8647 read.buf_addr_msw = msm_audio_populate_upper_32_bits(ab->phys);
8648
8649 list_for_each_safe(ptr, next, &ac->port[OUT].mem_map_handle) {
8650 buf_node = list_entry(ptr, struct asm_buffer_node,
8651 list);
Vignesh Kulothunganc894ac42018-01-04 13:49:12 -08008652 if (buf_node->buf_phys_addr == ab->phys) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308653 read.mem_map_handle = buf_node->mmap_hdl;
Vignesh Kulothunganc894ac42018-01-04 13:49:12 -08008654 break;
8655 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308656 }
8657 dev_vdbg(ac->dev, "memory_map handle in q6asm_read: [%0x]:",
8658 read.mem_map_handle);
8659 read.buf_size = is_custom_len_reqd ? len : ab->size;
8660 read.seq_id = port->dsp_buf;
8661 q6asm_update_token(&read.hdr.token,
8662 0, /* Session ID is NA */
8663 0, /* Stream ID is NA */
8664 port->dsp_buf,
8665 0, /* Direction flag is NA */
8666 WAIT_CMD);
8667 port->dsp_buf = q6asm_get_next_buf(ac, port->dsp_buf,
8668 port->max_buf_cnt);
8669 mutex_unlock(&port->lock);
8670 dev_vdbg(ac->dev, "%s: buf add[%pK] token[0x%x] uid[%d]\n",
8671 __func__, &ab->phys, read.hdr.token,
8672 read.seq_id);
8673 rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
8674 if (rc < 0) {
8675 pr_err("%s: read op[0x%x]rc[%d]\n",
8676 __func__, read.hdr.opcode, rc);
8677 goto fail_cmd;
8678 }
8679 return 0;
8680 }
8681fail_cmd:
8682 return -EINVAL;
8683}
8684
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308685/**
8686 * q6asm_read -
8687 * command to read buffer data from DSP
8688 *
8689 * @ac: Audio client handle
8690 *
8691 * Returns 0 on success or error on failure
8692 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308693int q6asm_read(struct audio_client *ac)
8694{
8695 return __q6asm_read(ac, false/*is_custom_len_reqd*/, 0);
8696}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308697EXPORT_SYMBOL(q6asm_read);
8698
8699
8700/**
8701 * q6asm_read_v2 -
8702 * command to read buffer data from DSP
8703 *
8704 * @ac: Audio client handle
8705 * @len: buffer size to read
8706 *
8707 * Returns 0 on success or error on failure
8708 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308709int q6asm_read_v2(struct audio_client *ac, uint32_t len)
8710{
8711 return __q6asm_read(ac, true /*is_custom_len_reqd*/, len);
8712}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308713EXPORT_SYMBOL(q6asm_read_v2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308714
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308715/**
8716 * q6asm_read_nolock -
8717 * command to read buffer data from DSP
8718 * with no wait for ack.
8719 *
8720 * @ac: Audio client handle
8721 *
8722 * Returns 0 on success or error on failure
8723 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308724int q6asm_read_nolock(struct audio_client *ac)
8725{
8726 struct asm_data_cmd_read_v2 read;
8727 struct asm_buffer_node *buf_node = NULL;
8728 struct list_head *ptr, *next;
8729 struct audio_buffer *ab;
8730 int dsp_buf;
8731 struct audio_port_data *port;
8732 int rc;
8733
8734 if (ac == NULL) {
8735 pr_err("%s: APR handle NULL\n", __func__);
8736 return -EINVAL;
8737 }
8738 if (ac->apr == NULL) {
8739 pr_err("%s: AC APR handle NULL\n", __func__);
8740 return -EINVAL;
8741 }
8742
8743 if (ac->io_mode & SYNC_IO_MODE) {
8744 port = &ac->port[OUT];
8745
8746 q6asm_add_hdr_async(ac, &read.hdr, sizeof(read), FALSE);
8747
8748
8749 dsp_buf = port->dsp_buf;
8750 ab = &port->buf[dsp_buf];
8751
8752 dev_vdbg(ac->dev, "%s: session[%d]dsp-buf[%d][%pK]cpu_buf[%d][%pK]\n",
8753 __func__,
8754 ac->session,
8755 dsp_buf,
8756 port->buf[dsp_buf].data,
8757 port->cpu_buf,
8758 &port->buf[port->cpu_buf].phys);
8759
8760 read.hdr.opcode = ASM_DATA_CMD_READ_V2;
8761 read.buf_addr_lsw = lower_32_bits(ab->phys);
8762 read.buf_addr_msw = msm_audio_populate_upper_32_bits(ab->phys);
8763 read.buf_size = ab->size;
8764 read.seq_id = port->dsp_buf;
8765 q6asm_update_token(&read.hdr.token,
8766 0, /* Session ID is NA */
8767 0, /* Stream ID is NA */
8768 port->dsp_buf,
8769 0, /* Direction flag is NA */
8770 WAIT_CMD);
8771
8772 list_for_each_safe(ptr, next, &ac->port[OUT].mem_map_handle) {
8773 buf_node = list_entry(ptr, struct asm_buffer_node,
8774 list);
8775 if (buf_node->buf_phys_addr == ab->phys) {
8776 read.mem_map_handle = buf_node->mmap_hdl;
8777 break;
8778 }
8779 }
8780
8781 port->dsp_buf = q6asm_get_next_buf(ac, port->dsp_buf,
8782 port->max_buf_cnt);
8783 dev_vdbg(ac->dev, "%s: buf add[%pK] token[0x%x] uid[%d]\n",
8784 __func__, &ab->phys, read.hdr.token,
8785 read.seq_id);
8786 rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
8787 if (rc < 0) {
8788 pr_err("%s: read op[0x%x]rc[%d]\n",
8789 __func__, read.hdr.opcode, rc);
8790 goto fail_cmd;
8791 }
8792 return 0;
8793 }
8794fail_cmd:
8795 return -EINVAL;
8796}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308797EXPORT_SYMBOL(q6asm_read_nolock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308798
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308799/**
8800 * q6asm_async_write -
8801 * command to write DSP buffer
8802 *
8803 * @ac: Audio client handle
8804 * @param: params for async write
8805 *
8806 * Returns 0 on success or error on failure
8807 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308808int q6asm_async_write(struct audio_client *ac,
8809 struct audio_aio_write_param *param)
8810{
8811 int rc = 0;
8812 struct asm_data_cmd_write_v2 write;
8813 struct asm_buffer_node *buf_node = NULL;
8814 struct list_head *ptr, *next;
8815 struct audio_buffer *ab;
8816 struct audio_port_data *port;
8817 phys_addr_t lbuf_phys_addr;
8818 u32 liomode;
8819 u32 io_compressed;
8820 u32 io_compressed_stream;
8821
8822 if (ac == NULL) {
8823 pr_err("%s: APR handle NULL\n", __func__);
8824 return -EINVAL;
8825 }
8826 if (ac->apr == NULL) {
8827 pr_err("%s: AC APR handle NULL\n", __func__);
8828 return -EINVAL;
8829 }
8830
8831 q6asm_stream_add_hdr_async(
8832 ac, &write.hdr, sizeof(write), TRUE, ac->stream_id);
8833 port = &ac->port[IN];
8834 ab = &port->buf[port->dsp_buf];
8835
8836 /* Pass session id as token for AIO scheme */
8837 write.hdr.token = param->uid;
8838 write.hdr.opcode = ASM_DATA_CMD_WRITE_V2;
8839 write.buf_addr_lsw = lower_32_bits(param->paddr);
8840 write.buf_addr_msw = msm_audio_populate_upper_32_bits(param->paddr);
8841 write.buf_size = param->len;
8842 write.timestamp_msw = param->msw_ts;
8843 write.timestamp_lsw = param->lsw_ts;
8844 liomode = (ASYNC_IO_MODE | NT_MODE);
8845 io_compressed = (ASYNC_IO_MODE | COMPRESSED_IO);
8846 io_compressed_stream = (ASYNC_IO_MODE | COMPRESSED_STREAM_IO);
8847
8848 if (ac->io_mode == liomode)
8849 lbuf_phys_addr = (param->paddr - 32);
8850 else if (ac->io_mode == io_compressed ||
8851 ac->io_mode == io_compressed_stream)
8852 lbuf_phys_addr = (param->paddr - param->metadata_len);
8853 else {
8854 if (param->flags & SET_TIMESTAMP)
8855 lbuf_phys_addr = param->paddr -
8856 sizeof(struct snd_codec_metadata);
8857 else
8858 lbuf_phys_addr = param->paddr;
8859 }
8860 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",
8861 __func__,
8862 write.hdr.token, &param->paddr,
8863 write.buf_size, write.timestamp_msw,
8864 write.timestamp_lsw, &lbuf_phys_addr);
8865
8866 /* Use 0xFF00 for disabling timestamps */
8867 if (param->flags == 0xFF00)
8868 write.flags = (0x00000000 | (param->flags & 0x800000FF));
8869 else
8870 write.flags = (0x80000000 | param->flags);
8871 write.flags |= param->last_buffer << ASM_SHIFT_LAST_BUFFER_FLAG;
8872 write.seq_id = param->uid;
8873 list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
8874 buf_node = list_entry(ptr, struct asm_buffer_node,
8875 list);
8876 if (buf_node->buf_phys_addr == lbuf_phys_addr) {
8877 write.mem_map_handle = buf_node->mmap_hdl;
8878 break;
8879 }
8880 }
8881
8882 rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
8883 if (rc < 0) {
8884 pr_err("%s: write op[0x%x]rc[%d]\n", __func__,
8885 write.hdr.opcode, rc);
8886 goto fail_cmd;
8887 }
8888 return 0;
8889fail_cmd:
8890 return -EINVAL;
8891}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308892EXPORT_SYMBOL(q6asm_async_write);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308893
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308894/**
8895 * q6asm_async_read -
8896 * command to read DSP buffer
8897 *
8898 * @ac: Audio client handle
8899 * @param: params for async read
8900 *
8901 * Returns 0 on success or error on failure
8902 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308903int q6asm_async_read(struct audio_client *ac,
8904 struct audio_aio_read_param *param)
8905{
8906 int rc = 0;
8907 struct asm_data_cmd_read_v2 read;
8908 struct asm_buffer_node *buf_node = NULL;
8909 struct list_head *ptr, *next;
8910 phys_addr_t lbuf_phys_addr;
8911 u32 liomode;
8912 u32 io_compressed;
8913 int dir = 0;
8914
8915 if (ac == NULL) {
8916 pr_err("%s: APR handle NULL\n", __func__);
8917 return -EINVAL;
8918 }
8919 if (ac->apr == NULL) {
8920 pr_err("%s: AC APR handle NULL\n", __func__);
8921 return -EINVAL;
8922 }
8923
8924 q6asm_add_hdr_async(ac, &read.hdr, sizeof(read), FALSE);
8925
8926 /* Pass session id as token for AIO scheme */
8927 read.hdr.token = param->uid;
8928 read.hdr.opcode = ASM_DATA_CMD_READ_V2;
8929 read.buf_addr_lsw = lower_32_bits(param->paddr);
8930 read.buf_addr_msw = msm_audio_populate_upper_32_bits(param->paddr);
8931 read.buf_size = param->len;
8932 read.seq_id = param->uid;
8933 liomode = (NT_MODE | ASYNC_IO_MODE);
8934 io_compressed = (ASYNC_IO_MODE | COMPRESSED_IO);
8935 if (ac->io_mode == liomode) {
8936 lbuf_phys_addr = (param->paddr - 32);
8937 /*legacy wma driver case*/
8938 dir = IN;
8939 } else if (ac->io_mode == io_compressed) {
8940 lbuf_phys_addr = (param->paddr - 64);
8941 dir = OUT;
8942 } else {
8943 if (param->flags & COMPRESSED_TIMESTAMP_FLAG)
8944 lbuf_phys_addr = param->paddr -
8945 sizeof(struct snd_codec_metadata);
8946 else
8947 lbuf_phys_addr = param->paddr;
8948 dir = OUT;
8949 }
8950
8951 list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
8952 buf_node = list_entry(ptr, struct asm_buffer_node,
8953 list);
8954 if (buf_node->buf_phys_addr == lbuf_phys_addr) {
8955 read.mem_map_handle = buf_node->mmap_hdl;
8956 break;
8957 }
8958 }
8959
8960 rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
8961 if (rc < 0) {
8962 pr_err("%s: read op[0x%x]rc[%d]\n", __func__,
8963 read.hdr.opcode, rc);
8964 goto fail_cmd;
8965 }
8966 return 0;
8967fail_cmd:
8968 return -EINVAL;
8969}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308970EXPORT_SYMBOL(q6asm_async_read);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308971
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308972/**
8973 * q6asm_write -
8974 * command to write buffer data to DSP
8975 *
8976 * @ac: Audio client handle
8977 * @len: buffer size
8978 * @msw_ts: upper 32bits of timestamp
8979 * @lsw_ts: lower 32bits of timestamp
8980 * @flags: Flags for timestamp mode
8981 *
8982 * Returns 0 on success or error on failure
8983 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308984int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
8985 uint32_t lsw_ts, uint32_t flags)
8986{
8987 int rc = 0;
8988 struct asm_data_cmd_write_v2 write;
8989 struct asm_buffer_node *buf_node = NULL;
8990 struct audio_port_data *port;
8991 struct audio_buffer *ab;
8992 int dsp_buf = 0;
8993
8994 if (ac == NULL) {
8995 pr_err("%s: APR handle NULL\n", __func__);
8996 return -EINVAL;
8997 }
8998 if (ac->apr == NULL) {
8999 pr_err("%s: AC APR handle NULL\n", __func__);
9000 return -EINVAL;
9001 }
9002
9003 dev_vdbg(ac->dev, "%s: session[%d] len=%d\n",
9004 __func__, ac->session, len);
9005 if (ac->io_mode & SYNC_IO_MODE) {
9006 port = &ac->port[IN];
9007
9008 q6asm_add_hdr(ac, &write.hdr, sizeof(write),
9009 FALSE);
9010 mutex_lock(&port->lock);
9011
9012 dsp_buf = port->dsp_buf;
9013 ab = &port->buf[dsp_buf];
9014
9015 q6asm_update_token(&write.hdr.token,
9016 0, /* Session ID is NA */
9017 0, /* Stream ID is NA */
9018 port->dsp_buf,
9019 0, /* Direction flag is NA */
9020 NO_WAIT_CMD);
9021 write.hdr.opcode = ASM_DATA_CMD_WRITE_V2;
9022 write.buf_addr_lsw = lower_32_bits(ab->phys);
9023 write.buf_addr_msw = msm_audio_populate_upper_32_bits(ab->phys);
9024 write.buf_size = len;
9025 write.seq_id = port->dsp_buf;
9026 write.timestamp_lsw = lsw_ts;
9027 write.timestamp_msw = msw_ts;
9028 /* Use 0xFF00 for disabling timestamps */
9029 if (flags == 0xFF00)
9030 write.flags = (0x00000000 | (flags & 0x800000FF));
9031 else
9032 write.flags = (0x80000000 | flags);
9033 port->dsp_buf = q6asm_get_next_buf(ac, port->dsp_buf,
9034 port->max_buf_cnt);
9035 buf_node = list_first_entry(&ac->port[IN].mem_map_handle,
9036 struct asm_buffer_node,
9037 list);
9038 write.mem_map_handle = buf_node->mmap_hdl;
9039
9040 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]"
9041 , __func__,
9042 &ab->phys,
9043 write.buf_addr_lsw,
9044 write.hdr.token,
9045 write.seq_id,
9046 write.buf_size,
9047 write.mem_map_handle);
9048 mutex_unlock(&port->lock);
9049
9050 config_debug_fs_write(ab);
9051
9052 rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
9053 if (rc < 0) {
9054 pr_err("%s: write op[0x%x]rc[%d]\n",
9055 __func__, write.hdr.opcode, rc);
9056 goto fail_cmd;
9057 }
9058 return 0;
9059 }
9060fail_cmd:
9061 return -EINVAL;
9062}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309063EXPORT_SYMBOL(q6asm_write);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309064
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309065/**
9066 * q6asm_write_nolock -
9067 * command to write buffer data to DSP
9068 * with no wait for ack.
9069 *
9070 * @ac: Audio client handle
9071 * @len: buffer size
9072 * @msw_ts: upper 32bits of timestamp
9073 * @lsw_ts: lower 32bits of timestamp
9074 * @flags: Flags for timestamp mode
9075 *
9076 * Returns 0 on success or error on failure
9077 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309078int q6asm_write_nolock(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
9079 uint32_t lsw_ts, uint32_t flags)
9080{
9081 int rc = 0;
9082 struct asm_data_cmd_write_v2 write;
9083 struct asm_buffer_node *buf_node = NULL;
9084 struct audio_port_data *port;
9085 struct audio_buffer *ab;
9086 int dsp_buf = 0;
9087
9088 if (ac == NULL) {
9089 pr_err("%s: APR handle NULL\n", __func__);
9090 return -EINVAL;
9091 }
9092 if (ac->apr == NULL) {
9093 pr_err("%s: AC APR handle NULL\n", __func__);
9094 return -EINVAL;
9095 }
9096
9097 dev_vdbg(ac->dev, "%s: session[%d] len=%d\n",
9098 __func__, ac->session, len);
9099 if (ac->io_mode & SYNC_IO_MODE) {
9100 port = &ac->port[IN];
9101
9102 q6asm_add_hdr_async(ac, &write.hdr, sizeof(write),
9103 FALSE);
9104
9105 dsp_buf = port->dsp_buf;
9106 ab = &port->buf[dsp_buf];
9107
9108 q6asm_update_token(&write.hdr.token,
9109 0, /* Session ID is NA */
9110 0, /* Stream ID is NA */
9111 port->dsp_buf,
9112 0, /* Direction flag is NA */
9113 NO_WAIT_CMD);
9114
9115 write.hdr.opcode = ASM_DATA_CMD_WRITE_V2;
9116 write.buf_addr_lsw = lower_32_bits(ab->phys);
9117 write.buf_addr_msw = msm_audio_populate_upper_32_bits(ab->phys);
9118 write.buf_size = len;
9119 write.seq_id = port->dsp_buf;
9120 write.timestamp_lsw = lsw_ts;
9121 write.timestamp_msw = msw_ts;
9122 buf_node = list_first_entry(&ac->port[IN].mem_map_handle,
9123 struct asm_buffer_node,
9124 list);
9125 write.mem_map_handle = buf_node->mmap_hdl;
9126 /* Use 0xFF00 for disabling timestamps */
9127 if (flags == 0xFF00)
9128 write.flags = (0x00000000 | (flags & 0x800000FF));
9129 else
9130 write.flags = (0x80000000 | flags);
9131 port->dsp_buf = q6asm_get_next_buf(ac, port->dsp_buf,
9132 port->max_buf_cnt);
9133
9134 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]"
9135 , __func__,
9136 &ab->phys,
9137 write.buf_addr_lsw,
9138 write.hdr.token,
9139 write.seq_id,
9140 write.buf_size,
9141 write.mem_map_handle);
9142
9143 rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
9144 if (rc < 0) {
9145 pr_err("%s: write op[0x%x]rc[%d]\n",
9146 __func__, write.hdr.opcode, rc);
9147 goto fail_cmd;
9148 }
9149 return 0;
9150 }
9151fail_cmd:
9152 return -EINVAL;
9153}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309154EXPORT_SYMBOL(q6asm_write_nolock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309155
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309156/**
9157 * q6asm_get_session_time -
9158 * command to retrieve timestamp info
9159 *
9160 * @ac: Audio client handle
9161 * @tstamp: pointer to fill with timestamp info
9162 *
9163 * Returns 0 on success or error on failure
9164 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309165int q6asm_get_session_time(struct audio_client *ac, uint64_t *tstamp)
9166{
9167 struct asm_mtmx_strtr_get_params mtmx_params;
9168 int rc;
9169
9170 if (ac == NULL) {
9171 pr_err("%s: APR handle NULL\n", __func__);
9172 return -EINVAL;
9173 }
9174 if (ac->apr == NULL) {
9175 pr_err("%s: AC APR handle NULL\n", __func__);
9176 return -EINVAL;
9177 }
9178 if (tstamp == NULL) {
9179 pr_err("%s: tstamp NULL\n", __func__);
9180 return -EINVAL;
9181 }
9182
9183 q6asm_add_hdr(ac, &mtmx_params.hdr, sizeof(mtmx_params), TRUE);
9184 mtmx_params.hdr.opcode = ASM_SESSION_CMD_GET_MTMX_STRTR_PARAMS_V2;
9185 mtmx_params.param_info.data_payload_addr_lsw = 0;
9186 mtmx_params.param_info.data_payload_addr_msw = 0;
9187 mtmx_params.param_info.mem_map_handle = 0;
9188 mtmx_params.param_info.direction = (ac->io_mode & TUN_READ_IO_MODE
9189 ? 1 : 0);
9190 mtmx_params.param_info.module_id =
9191 ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
9192 mtmx_params.param_info.param_id =
9193 ASM_SESSION_MTMX_STRTR_PARAM_SESSION_TIME_V3;
9194 mtmx_params.param_info.param_max_size =
9195 sizeof(struct asm_stream_param_data_v2) +
9196 sizeof(struct asm_session_mtmx_strtr_param_session_time_v3_t);
9197 atomic_set(&ac->time_flag, 1);
9198
9199 dev_vdbg(ac->dev, "%s: session[%d]opcode[0x%x]\n", __func__,
9200 ac->session, mtmx_params.hdr.opcode);
9201 rc = apr_send_pkt(ac->apr, (uint32_t *) &mtmx_params);
9202 if (rc < 0) {
9203 pr_err("%s: Commmand 0x%x failed %d\n", __func__,
9204 mtmx_params.hdr.opcode, rc);
9205 goto fail_cmd;
9206 }
9207 rc = wait_event_timeout(ac->time_wait,
9208 (atomic_read(&ac->time_flag) == 0), 5*HZ);
9209 if (!rc) {
9210 pr_err("%s: timeout in getting session time from DSP\n",
9211 __func__);
9212 goto fail_cmd;
9213 }
9214
9215 *tstamp = ac->time_stamp;
9216 return 0;
9217
9218fail_cmd:
9219 return -EINVAL;
9220}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309221EXPORT_SYMBOL(q6asm_get_session_time);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309222
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309223/**
9224 * q6asm_get_session_time_legacy -
9225 * command to retrieve timestamp info
9226 *
9227 * @ac: Audio client handle
9228 * @tstamp: pointer to fill with timestamp info
9229 *
9230 * Returns 0 on success or error on failure
9231 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309232int q6asm_get_session_time_legacy(struct audio_client *ac, uint64_t *tstamp)
9233{
9234 struct apr_hdr hdr;
9235 int rc;
9236
9237 if (ac == NULL) {
9238 pr_err("%s: APR handle NULL\n", __func__);
9239 return -EINVAL;
9240 }
9241 if (ac->apr == NULL) {
9242 pr_err("%s: AC APR handle NULL\n", __func__);
9243 return -EINVAL;
9244 }
9245 if (tstamp == NULL) {
9246 pr_err("%s: tstamp NULL\n", __func__);
9247 return -EINVAL;
9248 }
9249
9250 q6asm_add_hdr(ac, &hdr, sizeof(hdr), TRUE);
9251 hdr.opcode = ASM_SESSION_CMD_GET_SESSIONTIME_V3;
9252 atomic_set(&ac->time_flag, 1);
9253
9254 dev_vdbg(ac->dev, "%s: session[%d]opcode[0x%x]\n", __func__,
9255 ac->session,
9256 hdr.opcode);
9257 rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
9258 if (rc < 0) {
9259 pr_err("%s: Commmand 0x%x failed %d\n",
9260 __func__, hdr.opcode, rc);
9261 goto fail_cmd;
9262 }
9263 rc = wait_event_timeout(ac->time_wait,
9264 (atomic_read(&ac->time_flag) == 0), 5*HZ);
9265 if (!rc) {
9266 pr_err("%s: timeout in getting session time from DSP\n",
9267 __func__);
9268 goto fail_cmd;
9269 }
9270
9271 *tstamp = ac->time_stamp;
9272 return 0;
9273
9274fail_cmd:
9275 return -EINVAL;
9276}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309277EXPORT_SYMBOL(q6asm_get_session_time_legacy);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309278
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309279/**
9280 * q6asm_send_audio_effects_params -
9281 * command to send audio effects params
9282 *
9283 * @ac: Audio client handle
9284 * @params: audio effects params
9285 * @params_length: size of params
9286 *
9287 * Returns 0 on success or error on failure
9288 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309289int q6asm_send_audio_effects_params(struct audio_client *ac, char *params,
9290 uint32_t params_length)
9291{
9292 char *asm_params = NULL;
9293 struct apr_hdr hdr;
9294 struct asm_stream_cmd_set_pp_params_v2 payload_params;
Xiaojun Sanga4648082018-04-27 14:57:33 +08009295 int sz, rc, session_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309296
9297 pr_debug("%s:\n", __func__);
9298 if (!ac) {
9299 pr_err("%s: APR handle NULL\n", __func__);
9300 return -EINVAL;
9301 }
Xiaojun Sanga4648082018-04-27 14:57:33 +08009302
9303 session_id = q6asm_get_session_id_from_audio_client(ac);
9304 if (!session_id)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309305 return -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08009306
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309307 if (params == NULL) {
9308 pr_err("%s: params NULL\n", __func__);
9309 return -EINVAL;
9310 }
9311 sz = sizeof(struct apr_hdr) +
9312 sizeof(struct asm_stream_cmd_set_pp_params_v2) +
9313 params_length;
9314 asm_params = kzalloc(sz, GFP_KERNEL);
9315 if (!asm_params) {
9316 pr_err("%s, asm params memory alloc failed", __func__);
9317 return -ENOMEM;
9318 }
Xiaojun Sanga4648082018-04-27 14:57:33 +08009319 mutex_lock(&session[session_id].mutex_lock_per_session);
9320 if (!q6asm_is_valid_audio_client(ac)) {
9321 rc = -EINVAL;
9322 goto fail_send_param;
9323 }
9324
9325 if (ac->apr == NULL) {
9326 pr_err("%s: AC APR handle NULL\n", __func__);
9327 rc = -EINVAL;
9328 goto fail_send_param;
9329 }
9330
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309331 q6asm_add_hdr_async(ac, &hdr, (sizeof(struct apr_hdr) +
9332 sizeof(struct asm_stream_cmd_set_pp_params_v2) +
9333 params_length), TRUE);
9334 atomic_set(&ac->cmd_state_pp, -1);
9335 hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
9336 payload_params.data_payload_addr_lsw = 0;
9337 payload_params.data_payload_addr_msw = 0;
9338 payload_params.mem_map_handle = 0;
9339 payload_params.data_payload_size = params_length;
9340 memcpy(((u8 *)asm_params), &hdr, sizeof(struct apr_hdr));
9341 memcpy(((u8 *)asm_params + sizeof(struct apr_hdr)), &payload_params,
9342 sizeof(struct asm_stream_cmd_set_pp_params_v2));
9343 memcpy(((u8 *)asm_params + sizeof(struct apr_hdr) +
9344 sizeof(struct asm_stream_cmd_set_pp_params_v2)),
9345 params, params_length);
9346 rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params);
9347 if (rc < 0) {
9348 pr_err("%s: audio effects set-params send failed\n", __func__);
9349 rc = -EINVAL;
9350 goto fail_send_param;
9351 }
9352 rc = wait_event_timeout(ac->cmd_wait,
9353 (atomic_read(&ac->cmd_state_pp) >= 0), 1*HZ);
9354 if (!rc) {
9355 pr_err("%s: timeout, audio effects set-params\n", __func__);
9356 rc = -ETIMEDOUT;
9357 goto fail_send_param;
9358 }
9359 if (atomic_read(&ac->cmd_state_pp) > 0) {
9360 pr_err("%s: DSP returned error[%s] set-params\n",
9361 __func__, adsp_err_get_err_str(
9362 atomic_read(&ac->cmd_state_pp)));
9363 rc = adsp_err_get_lnx_err_code(
9364 atomic_read(&ac->cmd_state_pp));
9365 goto fail_send_param;
9366 }
9367
9368 rc = 0;
9369fail_send_param:
Xiaojun Sanga4648082018-04-27 14:57:33 +08009370 mutex_unlock(&session[session_id].mutex_lock_per_session);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309371 kfree(asm_params);
9372 return rc;
9373}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309374EXPORT_SYMBOL(q6asm_send_audio_effects_params);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309375
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309376/**
9377 * q6asm_send_mtmx_strtr_window -
9378 * command to send matrix for window params
9379 *
9380 * @ac: Audio client handle
9381 * @window_param: window params
9382 * @param_id: param id for window
9383 *
9384 * Returns 0 on success or error on failure
9385 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309386int q6asm_send_mtmx_strtr_window(struct audio_client *ac,
9387 struct asm_session_mtmx_strtr_param_window_v2_t *window_param,
9388 uint32_t param_id)
9389{
9390 struct asm_mtmx_strtr_params matrix;
9391 int sz = 0;
9392 int rc = 0;
9393
9394 pr_debug("%s: Window lsw is %d, window msw is %d\n", __func__,
9395 window_param->window_lsw, window_param->window_msw);
9396
9397 if (!ac) {
9398 pr_err("%s: audio client handle is NULL\n", __func__);
9399 rc = -EINVAL;
9400 goto fail_cmd;
9401 }
9402
9403 if (ac->apr == NULL) {
9404 pr_err("%s: ac->apr is NULL", __func__);
9405 rc = -EINVAL;
9406 goto fail_cmd;
9407 }
9408
9409 sz = sizeof(struct asm_mtmx_strtr_params);
9410 q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE);
9411 atomic_set(&ac->cmd_state, -1);
9412 matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2;
9413
9414 matrix.param.data_payload_addr_lsw = 0;
9415 matrix.param.data_payload_addr_msw = 0;
9416 matrix.param.mem_map_handle = 0;
9417 matrix.param.data_payload_size =
9418 sizeof(struct asm_stream_param_data_v2) +
9419 sizeof(struct asm_session_mtmx_strtr_param_window_v2_t);
9420 matrix.param.direction = 0; /* RX */
9421 matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
9422 matrix.data.param_id = param_id;
9423 matrix.data.param_size =
9424 sizeof(struct asm_session_mtmx_strtr_param_window_v2_t);
9425 matrix.data.reserved = 0;
9426 memcpy(&(matrix.config.window_param),
9427 window_param,
9428 sizeof(struct asm_session_mtmx_strtr_param_window_v2_t));
9429
9430 rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix);
9431 if (rc < 0) {
9432 pr_err("%s: Render window start send failed paramid [0x%x]\n",
9433 __func__, matrix.data.param_id);
9434 rc = -EINVAL;
9435 goto fail_cmd;
9436 }
9437
9438 rc = wait_event_timeout(ac->cmd_wait,
9439 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
9440 if (!rc) {
9441 pr_err("%s: timeout, Render window start paramid[0x%x]\n",
9442 __func__, matrix.data.param_id);
9443 rc = -ETIMEDOUT;
9444 goto fail_cmd;
9445 }
9446
9447 if (atomic_read(&ac->cmd_state) > 0) {
9448 pr_err("%s: DSP returned error[%s]\n",
9449 __func__, adsp_err_get_err_str(
9450 atomic_read(&ac->cmd_state)));
9451 rc = adsp_err_get_lnx_err_code(
9452 atomic_read(&ac->cmd_state));
9453 goto fail_cmd;
9454 }
9455 rc = 0;
9456fail_cmd:
9457 return rc;
9458}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309459EXPORT_SYMBOL(q6asm_send_mtmx_strtr_window);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309460
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309461/**
9462 * q6asm_send_mtmx_strtr_render_mode -
9463 * command to send matrix for render mode
9464 *
9465 * @ac: Audio client handle
9466 * @render_mode: rendering mode
9467 *
9468 * Returns 0 on success or error on failure
9469 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309470int q6asm_send_mtmx_strtr_render_mode(struct audio_client *ac,
9471 uint32_t render_mode)
9472{
9473 struct asm_mtmx_strtr_params matrix;
9474 struct asm_session_mtmx_strtr_param_render_mode_t render_param;
9475 int sz = 0;
9476 int rc = 0;
9477
9478 pr_debug("%s: render mode is %d\n", __func__, render_mode);
9479
9480 if (!ac) {
9481 pr_err("%s: audio client handle is NULL\n", __func__);
9482 rc = -EINVAL;
9483 goto exit;
9484 }
9485
9486 if (ac->apr == NULL) {
9487 pr_err("%s: ac->apr is NULL\n", __func__);
9488 rc = -EINVAL;
9489 goto exit;
9490 }
9491
9492 if ((render_mode != ASM_SESSION_MTMX_STRTR_PARAM_RENDER_DEFAULT) &&
9493 (render_mode != ASM_SESSION_MTMX_STRTR_PARAM_RENDER_LOCAL_STC)) {
9494 pr_err("%s: Invalid render mode %d\n", __func__, render_mode);
9495 rc = -EINVAL;
9496 goto exit;
9497 }
9498
9499 memset(&render_param, 0,
9500 sizeof(struct asm_session_mtmx_strtr_param_render_mode_t));
9501 render_param.flags = render_mode;
9502
9503 memset(&matrix, 0, sizeof(struct asm_mtmx_strtr_params));
9504 sz = sizeof(struct asm_mtmx_strtr_params);
9505 q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE);
9506 atomic_set(&ac->cmd_state, -1);
9507 matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2;
9508
9509 matrix.param.data_payload_addr_lsw = 0;
9510 matrix.param.data_payload_addr_msw = 0;
9511 matrix.param.mem_map_handle = 0;
9512 matrix.param.data_payload_size =
9513 sizeof(struct asm_stream_param_data_v2) +
9514 sizeof(struct asm_session_mtmx_strtr_param_render_mode_t);
9515 matrix.param.direction = 0; /* RX */
9516 matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
9517 matrix.data.param_id = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_MODE_CMD;
9518 matrix.data.param_size =
9519 sizeof(struct asm_session_mtmx_strtr_param_render_mode_t);
9520 matrix.data.reserved = 0;
9521 memcpy(&(matrix.config.render_param),
9522 &render_param,
9523 sizeof(struct asm_session_mtmx_strtr_param_render_mode_t));
9524
9525 rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix);
9526 if (rc < 0) {
9527 pr_err("%s: Render mode send failed paramid [0x%x]\n",
9528 __func__, matrix.data.param_id);
9529 rc = -EINVAL;
9530 goto exit;
9531 }
9532
9533 rc = wait_event_timeout(ac->cmd_wait,
9534 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
9535 if (!rc) {
9536 pr_err("%s: timeout, Render mode send paramid [0x%x]\n",
9537 __func__, matrix.data.param_id);
9538 rc = -ETIMEDOUT;
9539 goto exit;
9540 }
9541
9542 if (atomic_read(&ac->cmd_state) > 0) {
9543 pr_err("%s: DSP returned error[%s]\n",
9544 __func__, adsp_err_get_err_str(
9545 atomic_read(&ac->cmd_state)));
9546 rc = adsp_err_get_lnx_err_code(
9547 atomic_read(&ac->cmd_state));
9548 goto exit;
9549 }
9550 rc = 0;
9551exit:
9552 return rc;
9553}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309554EXPORT_SYMBOL(q6asm_send_mtmx_strtr_render_mode);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309555
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309556/**
9557 * q6asm_send_mtmx_strtr_clk_rec_mode -
9558 * command to send matrix for clock rec
9559 *
9560 * @ac: Audio client handle
9561 * @clk_rec_mode: mode for clock rec
9562 *
9563 * Returns 0 on success or error on failure
9564 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309565int q6asm_send_mtmx_strtr_clk_rec_mode(struct audio_client *ac,
9566 uint32_t clk_rec_mode)
9567{
9568 struct asm_mtmx_strtr_params matrix;
9569 struct asm_session_mtmx_strtr_param_clk_rec_t clk_rec_param;
9570 int sz = 0;
9571 int rc = 0;
9572
9573 pr_debug("%s: clk rec mode is %d\n", __func__, clk_rec_mode);
9574
9575 if (!ac) {
9576 pr_err("%s: audio client handle is NULL\n", __func__);
9577 rc = -EINVAL;
9578 goto exit;
9579 }
9580
9581 if (ac->apr == NULL) {
9582 pr_err("%s: ac->apr is NULL\n", __func__);
9583 rc = -EINVAL;
9584 goto exit;
9585 }
9586
9587 if ((clk_rec_mode != ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_NONE) &&
9588 (clk_rec_mode != ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_AUTO)) {
9589 pr_err("%s: Invalid clk rec mode %d\n", __func__, clk_rec_mode);
9590 rc = -EINVAL;
9591 goto exit;
9592 }
9593
9594 memset(&clk_rec_param, 0,
9595 sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t));
9596 clk_rec_param.flags = clk_rec_mode;
9597
9598 memset(&matrix, 0, sizeof(struct asm_mtmx_strtr_params));
9599 sz = sizeof(struct asm_mtmx_strtr_params);
9600 q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE);
9601 atomic_set(&ac->cmd_state, -1);
9602 matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2;
9603
9604 matrix.param.data_payload_addr_lsw = 0;
9605 matrix.param.data_payload_addr_msw = 0;
9606 matrix.param.mem_map_handle = 0;
9607 matrix.param.data_payload_size =
9608 sizeof(struct asm_stream_param_data_v2) +
9609 sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t);
9610 matrix.param.direction = 0; /* RX */
9611 matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
9612 matrix.data.param_id = ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_CMD;
9613 matrix.data.param_size =
9614 sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t);
9615 matrix.data.reserved = 0;
9616 memcpy(&(matrix.config.clk_rec_param),
9617 &clk_rec_param,
9618 sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t));
9619
9620 rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix);
9621 if (rc < 0) {
9622 pr_err("%s: clk rec mode send failed paramid [0x%x]\n",
9623 __func__, matrix.data.param_id);
9624 rc = -EINVAL;
9625 goto exit;
9626 }
9627
9628 rc = wait_event_timeout(ac->cmd_wait,
9629 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
9630 if (!rc) {
9631 pr_err("%s: timeout, clk rec mode send paramid [0x%x]\n",
9632 __func__, matrix.data.param_id);
9633 rc = -ETIMEDOUT;
9634 goto exit;
9635 }
9636
9637 if (atomic_read(&ac->cmd_state) > 0) {
9638 pr_err("%s: DSP returned error[%s]\n",
9639 __func__, adsp_err_get_err_str(
9640 atomic_read(&ac->cmd_state)));
9641 rc = adsp_err_get_lnx_err_code(
9642 atomic_read(&ac->cmd_state));
9643 goto exit;
9644 }
9645 rc = 0;
9646exit:
9647 return rc;
9648}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309649EXPORT_SYMBOL(q6asm_send_mtmx_strtr_clk_rec_mode);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309650
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309651/**
9652 * q6asm_send_mtmx_strtr_enable_adjust_session_clock -
9653 * command to send matrix for adjust time
9654 *
9655 * @ac: Audio client handle
9656 * @enable: flag to adjust time or not
9657 *
9658 * Returns 0 on success or error on failure
9659 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309660int q6asm_send_mtmx_strtr_enable_adjust_session_clock(struct audio_client *ac,
9661 bool enable)
9662{
9663 struct asm_mtmx_strtr_params matrix;
9664 struct asm_session_mtmx_param_adjust_session_time_ctl_t adjust_time;
9665 int sz = 0;
9666 int rc = 0;
9667
9668 pr_debug("%s: adjust session enable %d\n", __func__, enable);
9669
9670 if (!ac) {
9671 pr_err("%s: audio client handle is NULL\n", __func__);
9672 rc = -EINVAL;
9673 goto exit;
9674 }
9675
9676 if (ac->apr == NULL) {
9677 pr_err("%s: ac->apr is NULL\n", __func__);
9678 rc = -EINVAL;
9679 goto exit;
9680 }
9681
9682 adjust_time.enable = enable;
9683 memset(&matrix, 0, sizeof(struct asm_mtmx_strtr_params));
9684 sz = sizeof(struct asm_mtmx_strtr_params);
9685 q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE);
9686 atomic_set(&ac->cmd_state, -1);
9687 matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2;
9688
9689 matrix.param.data_payload_addr_lsw = 0;
9690 matrix.param.data_payload_addr_msw = 0;
9691 matrix.param.mem_map_handle = 0;
9692 matrix.param.data_payload_size =
9693 sizeof(struct asm_stream_param_data_v2) +
9694 sizeof(struct asm_session_mtmx_param_adjust_session_time_ctl_t);
9695 matrix.param.direction = 0; /* RX */
9696 matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
9697 matrix.data.param_id = ASM_SESSION_MTMX_PARAM_ADJUST_SESSION_TIME_CTL;
9698 matrix.data.param_size =
9699 sizeof(struct asm_session_mtmx_param_adjust_session_time_ctl_t);
9700 matrix.data.reserved = 0;
9701 matrix.config.adj_time_param.enable = adjust_time.enable;
9702
9703 rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix);
9704 if (rc < 0) {
9705 pr_err("%s: enable adjust session failed failed paramid [0x%x]\n",
9706 __func__, matrix.data.param_id);
9707 rc = -EINVAL;
9708 goto exit;
9709 }
9710
9711 rc = wait_event_timeout(ac->cmd_wait,
9712 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
9713 if (!rc) {
9714 pr_err("%s: enable adjust session failed failed paramid [0x%x]\n",
9715 __func__, matrix.data.param_id);
9716 rc = -ETIMEDOUT;
9717 goto exit;
9718 }
9719
9720 if (atomic_read(&ac->cmd_state) > 0) {
9721 pr_err("%s: DSP returned error[%s]\n",
9722 __func__, adsp_err_get_err_str(
9723 atomic_read(&ac->cmd_state)));
9724 rc = adsp_err_get_lnx_err_code(
9725 atomic_read(&ac->cmd_state));
9726 goto exit;
9727 }
9728 rc = 0;
9729exit:
9730 return rc;
9731}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309732EXPORT_SYMBOL(q6asm_send_mtmx_strtr_enable_adjust_session_clock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309733
9734
9735static int __q6asm_cmd(struct audio_client *ac, int cmd, uint32_t stream_id)
9736{
9737 struct apr_hdr hdr;
9738 int rc;
9739 atomic_t *state;
9740 int cnt = 0;
9741
9742 if (!ac) {
Xiaojun Sangc3277492018-09-06 14:34:03 +08009743 pr_err_ratelimited("%s: APR handle NULL\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309744 return -EINVAL;
9745 }
9746 if (ac->apr == NULL) {
Xiaojun Sangc3277492018-09-06 14:34:03 +08009747 pr_err_ratelimited("%s: AC APR handle NULL\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309748 return -EINVAL;
9749 }
9750 q6asm_stream_add_hdr(ac, &hdr, sizeof(hdr), TRUE, stream_id);
9751 atomic_set(&ac->cmd_state, -1);
9752 /*
9753 * Updated the token field with stream/session for compressed playback
9754 * Platform driver must know the the stream with which the command is
9755 * associated
9756 */
9757 if (ac->io_mode & COMPRESSED_STREAM_IO)
9758 q6asm_update_token(&hdr.token,
9759 ac->session,
9760 stream_id,
9761 0, /* Buffer index is NA */
9762 0, /* Direction flag is NA */
9763 WAIT_CMD);
9764 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
9765 __func__, hdr.token, stream_id, ac->session);
9766 switch (cmd) {
9767 case CMD_PAUSE:
9768 pr_debug("%s: CMD_PAUSE\n", __func__);
9769 hdr.opcode = ASM_SESSION_CMD_PAUSE;
9770 state = &ac->cmd_state;
9771 break;
9772 case CMD_SUSPEND:
9773 pr_debug("%s: CMD_SUSPEND\n", __func__);
9774 hdr.opcode = ASM_SESSION_CMD_SUSPEND;
9775 state = &ac->cmd_state;
9776 break;
9777 case CMD_FLUSH:
9778 pr_debug("%s: CMD_FLUSH\n", __func__);
9779 hdr.opcode = ASM_STREAM_CMD_FLUSH;
9780 state = &ac->cmd_state;
9781 break;
9782 case CMD_OUT_FLUSH:
9783 pr_debug("%s: CMD_OUT_FLUSH\n", __func__);
9784 hdr.opcode = ASM_STREAM_CMD_FLUSH_READBUFS;
9785 state = &ac->cmd_state;
9786 break;
9787 case CMD_EOS:
9788 pr_debug("%s: CMD_EOS\n", __func__);
9789 hdr.opcode = ASM_DATA_CMD_EOS;
9790 atomic_set(&ac->cmd_state, 0);
9791 state = &ac->cmd_state;
9792 break;
9793 case CMD_CLOSE:
9794 pr_debug("%s: CMD_CLOSE\n", __func__);
9795 hdr.opcode = ASM_STREAM_CMD_CLOSE;
9796 state = &ac->cmd_state;
9797 break;
9798 default:
9799 pr_err("%s: Invalid format[%d]\n", __func__, cmd);
9800 rc = -EINVAL;
9801 goto fail_cmd;
9802 }
9803 pr_debug("%s: session[%d]opcode[0x%x]\n", __func__,
9804 ac->session,
9805 hdr.opcode);
9806 rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
9807 if (rc < 0) {
9808 pr_err("%s: Commmand 0x%x failed %d\n",
9809 __func__, hdr.opcode, rc);
9810 rc = -EINVAL;
9811 goto fail_cmd;
9812 }
9813 rc = wait_event_timeout(ac->cmd_wait, (atomic_read(state) >= 0), 5*HZ);
9814 if (!rc) {
9815 pr_err("%s: timeout. waited for response opcode[0x%x]\n",
9816 __func__, hdr.opcode);
9817 rc = -ETIMEDOUT;
9818 goto fail_cmd;
9819 }
9820 if (atomic_read(state) > 0) {
9821 pr_err("%s: DSP returned error[%s] opcode %d\n",
9822 __func__, adsp_err_get_err_str(
9823 atomic_read(state)),
9824 hdr.opcode);
9825 rc = adsp_err_get_lnx_err_code(atomic_read(state));
9826 goto fail_cmd;
9827 }
9828
9829 if (cmd == CMD_FLUSH)
9830 q6asm_reset_buf_state(ac);
9831 if (cmd == CMD_CLOSE) {
9832 /* check if DSP return all buffers */
9833 if (ac->port[IN].buf) {
9834 for (cnt = 0; cnt < ac->port[IN].max_buf_cnt;
9835 cnt++) {
9836 if (ac->port[IN].buf[cnt].used == IN) {
9837 dev_vdbg(ac->dev, "Write Buf[%d] not returned\n",
9838 cnt);
9839 }
9840 }
9841 }
9842 if (ac->port[OUT].buf) {
9843 for (cnt = 0; cnt < ac->port[OUT].max_buf_cnt; cnt++) {
9844 if (ac->port[OUT].buf[cnt].used == OUT) {
9845 dev_vdbg(ac->dev, "Read Buf[%d] not returned\n",
9846 cnt);
9847 }
9848 }
9849 }
9850 }
9851 return 0;
9852fail_cmd:
9853 return rc;
9854}
9855
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309856/**
9857 * q6asm_cmd -
9858 * Function used to send commands for
9859 * ASM with wait for ack.
9860 *
9861 * @ac: Audio client handle
9862 * @cmd: command to send
9863 *
9864 * Returns 0 on success or error on failure
9865 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309866int q6asm_cmd(struct audio_client *ac, int cmd)
9867{
9868 return __q6asm_cmd(ac, cmd, ac->stream_id);
9869}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309870EXPORT_SYMBOL(q6asm_cmd);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309871
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309872/**
9873 * q6asm_stream_cmd -
9874 * Function used to send commands for
9875 * ASM stream with wait for ack.
9876 *
9877 * @ac: Audio client handle
9878 * @cmd: command to send
9879 * @stream_id: Stream ID
9880 *
9881 * Returns 0 on success or error on failure
9882 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309883int q6asm_stream_cmd(struct audio_client *ac, int cmd, uint32_t stream_id)
9884{
9885 return __q6asm_cmd(ac, cmd, stream_id);
9886}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309887EXPORT_SYMBOL(q6asm_stream_cmd);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309888
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309889/**
9890 * q6asm_cmd_nowait -
9891 * Function used to send commands for
9892 * ASM stream without wait for ack.
9893 *
9894 * @ac: Audio client handle
9895 * @cmd: command to send
9896 * @stream_id: Stream ID
9897 *
9898 * Returns 0 on success or error on failure
9899 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309900static int __q6asm_cmd_nowait(struct audio_client *ac, int cmd,
9901 uint32_t stream_id)
9902{
9903 struct apr_hdr hdr;
9904 int rc;
9905
9906 if (!ac) {
Xiaojun Sangc3277492018-09-06 14:34:03 +08009907 pr_err_ratelimited("%s: APR handle NULL\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309908 return -EINVAL;
9909 }
9910 if (ac->apr == NULL) {
Xiaojun Sangc3277492018-09-06 14:34:03 +08009911 pr_err_ratelimited("%s: AC APR handle NULL\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309912 return -EINVAL;
9913 }
9914 q6asm_stream_add_hdr_async(ac, &hdr, sizeof(hdr), TRUE, stream_id);
9915 atomic_set(&ac->cmd_state, 1);
9916 /*
9917 * Updated the token field with stream/session for compressed playback
9918 * Platform driver must know the the stream with which the command is
9919 * associated
9920 */
9921 if (ac->io_mode & COMPRESSED_STREAM_IO)
9922 q6asm_update_token(&hdr.token,
9923 ac->session,
9924 stream_id,
9925 0, /* Buffer index is NA */
9926 0, /* Direction flag is NA */
9927 NO_WAIT_CMD);
9928
9929 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
9930 __func__, hdr.token, stream_id, ac->session);
9931 switch (cmd) {
9932 case CMD_PAUSE:
9933 pr_debug("%s: CMD_PAUSE\n", __func__);
9934 hdr.opcode = ASM_SESSION_CMD_PAUSE;
9935 break;
Sidipotu Ashok5c6855b2019-01-08 15:58:37 +05309936
9937 case CMD_FLUSH:
9938 pr_debug("%s: CMD_FLUSH\n", __func__);
9939 hdr.opcode = ASM_STREAM_CMD_FLUSH;
9940 break;
9941
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309942 case CMD_EOS:
9943 pr_debug("%s: CMD_EOS\n", __func__);
9944 hdr.opcode = ASM_DATA_CMD_EOS;
9945 break;
9946 case CMD_CLOSE:
9947 pr_debug("%s: CMD_CLOSE\n", __func__);
9948 hdr.opcode = ASM_STREAM_CMD_CLOSE;
9949 break;
9950 default:
9951 pr_err("%s: Invalid format[%d]\n", __func__, cmd);
9952 goto fail_cmd;
9953 }
9954 pr_debug("%s: session[%d]opcode[0x%x]\n", __func__,
9955 ac->session,
9956 hdr.opcode);
9957
9958 rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
9959 if (rc < 0) {
9960 pr_err("%s: Commmand 0x%x failed %d\n",
9961 __func__, hdr.opcode, rc);
9962 goto fail_cmd;
9963 }
9964 return 0;
9965fail_cmd:
9966 return -EINVAL;
9967}
9968
9969int q6asm_cmd_nowait(struct audio_client *ac, int cmd)
9970{
9971 pr_debug("%s: stream_id: %d\n", __func__, ac->stream_id);
9972 return __q6asm_cmd_nowait(ac, cmd, ac->stream_id);
9973}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309974EXPORT_SYMBOL(q6asm_cmd_nowait);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309975
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309976/**
9977 * q6asm_stream_cmd_nowait -
9978 * Function used to send commands for
9979 * ASM stream without wait for ack.
9980 *
9981 * @ac: Audio client handle
9982 * @cmd: command to send
9983 * @stream_id: Stream ID
9984 *
9985 * Returns 0 on success or error on failure
9986 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309987int q6asm_stream_cmd_nowait(struct audio_client *ac, int cmd,
9988 uint32_t stream_id)
9989{
9990 pr_debug("%s: stream_id: %d\n", __func__, stream_id);
9991 return __q6asm_cmd_nowait(ac, cmd, stream_id);
9992}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309993EXPORT_SYMBOL(q6asm_stream_cmd_nowait);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309994
9995int __q6asm_send_meta_data(struct audio_client *ac, uint32_t stream_id,
9996 uint32_t initial_samples, uint32_t trailing_samples)
9997{
9998 struct asm_data_cmd_remove_silence silence;
9999 int rc = 0;
10000
10001 if (!ac) {
Xiaojun Sangc3277492018-09-06 14:34:03 +080010002 pr_err_ratelimited("%s: APR handle NULL\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010003 return -EINVAL;
10004 }
10005 if (ac->apr == NULL) {
Xiaojun Sangc3277492018-09-06 14:34:03 +080010006 pr_err_ratelimited("%s: AC APR handle NULL\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010007 return -EINVAL;
10008 }
10009 pr_debug("%s: session[%d]\n", __func__, ac->session);
10010 q6asm_stream_add_hdr_async(ac, &silence.hdr, sizeof(silence), TRUE,
10011 stream_id);
10012
10013 /*
10014 * Updated the token field with stream/session for compressed playback
10015 * Platform driver must know the the stream with which the command is
10016 * associated
10017 */
10018 if (ac->io_mode & COMPRESSED_STREAM_IO)
10019 q6asm_update_token(&silence.hdr.token,
10020 ac->session,
10021 stream_id,
10022 0, /* Buffer index is NA */
10023 0, /* Direction flag is NA */
10024 NO_WAIT_CMD);
10025 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
10026 __func__, silence.hdr.token, stream_id, ac->session);
10027
10028 silence.hdr.opcode = ASM_DATA_CMD_REMOVE_INITIAL_SILENCE;
10029 silence.num_samples_to_remove = initial_samples;
10030
10031 rc = apr_send_pkt(ac->apr, (uint32_t *) &silence);
10032 if (rc < 0) {
10033 pr_err("%s: Commmand silence failed[%d]", __func__, rc);
10034
10035 goto fail_cmd;
10036 }
10037
10038 silence.hdr.opcode = ASM_DATA_CMD_REMOVE_TRAILING_SILENCE;
10039 silence.num_samples_to_remove = trailing_samples;
10040
10041
10042 rc = apr_send_pkt(ac->apr, (uint32_t *) &silence);
10043 if (rc < 0) {
10044 pr_err("%s: Commmand silence failed[%d]", __func__, rc);
10045 goto fail_cmd;
10046 }
10047
10048 return 0;
10049fail_cmd:
10050 return -EINVAL;
10051}
10052
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010053/**
10054 * q6asm_stream_send_meta_data -
10055 * command to send meta data for stream
10056 *
10057 * @ac: Audio client handle
10058 * @stream_id: Stream ID
10059 * @initial_samples: Initial samples of stream
10060 * @trailing_samples: Trailing samples of stream
10061 *
10062 * Returns 0 on success or error on failure
10063 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010064int q6asm_stream_send_meta_data(struct audio_client *ac, uint32_t stream_id,
10065 uint32_t initial_samples, uint32_t trailing_samples)
10066{
10067 return __q6asm_send_meta_data(ac, stream_id, initial_samples,
10068 trailing_samples);
10069}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010070EXPORT_SYMBOL(q6asm_stream_send_meta_data);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010071
10072int q6asm_send_meta_data(struct audio_client *ac, uint32_t initial_samples,
10073 uint32_t trailing_samples)
10074{
10075 return __q6asm_send_meta_data(ac, ac->stream_id, initial_samples,
10076 trailing_samples);
10077}
10078
10079static void q6asm_reset_buf_state(struct audio_client *ac)
10080{
10081 int cnt = 0;
10082 int loopcnt = 0;
10083 int used;
10084 struct audio_port_data *port = NULL;
10085
10086 if (ac->io_mode & SYNC_IO_MODE) {
10087 used = (ac->io_mode & TUN_WRITE_IO_MODE ? 1 : 0);
10088 mutex_lock(&ac->cmd_lock);
10089 for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
10090 port = &ac->port[loopcnt];
10091 cnt = port->max_buf_cnt - 1;
10092 port->dsp_buf = 0;
10093 port->cpu_buf = 0;
10094 while (cnt >= 0) {
10095 if (!port->buf)
10096 continue;
10097 port->buf[cnt].used = used;
10098 cnt--;
10099 }
10100 }
10101 mutex_unlock(&ac->cmd_lock);
10102 }
10103}
10104
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010105/**
10106 * q6asm_reg_tx_overflow -
10107 * command to register for TX overflow events
10108 *
10109 * @ac: Audio client handle
10110 * @enable: flag to enable or disable events
10111 *
10112 * Returns 0 on success or error on failure
10113 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010114int q6asm_reg_tx_overflow(struct audio_client *ac, uint16_t enable)
10115{
10116 struct asm_session_cmd_regx_overflow tx_overflow;
10117 int rc;
10118
10119 if (!ac) {
10120 pr_err("%s: APR handle NULL\n", __func__);
10121 return -EINVAL;
10122 }
10123 if (ac->apr == NULL) {
10124 pr_err("%s: AC APR handle NULL\n", __func__);
10125 return -EINVAL;
10126 }
10127 pr_debug("%s: session[%d]enable[%d]\n", __func__,
10128 ac->session, enable);
10129 q6asm_add_hdr(ac, &tx_overflow.hdr, sizeof(tx_overflow), TRUE);
10130 atomic_set(&ac->cmd_state, -1);
10131
10132 tx_overflow.hdr.opcode =
10133 ASM_SESSION_CMD_REGISTER_FORX_OVERFLOW_EVENTS;
10134 /* tx overflow event: enable */
10135 tx_overflow.enable_flag = enable;
10136
10137 rc = apr_send_pkt(ac->apr, (uint32_t *) &tx_overflow);
10138 if (rc < 0) {
10139 pr_err("%s: tx overflow op[0x%x]rc[%d]\n",
10140 __func__, tx_overflow.hdr.opcode, rc);
10141 rc = -EINVAL;
10142 goto fail_cmd;
10143 }
10144 rc = wait_event_timeout(ac->cmd_wait,
10145 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
10146 if (!rc) {
10147 pr_err("%s: timeout. waited for tx overflow\n", __func__);
10148 rc = -ETIMEDOUT;
10149 goto fail_cmd;
10150 }
10151 if (atomic_read(&ac->cmd_state) > 0) {
10152 pr_err("%s: DSP returned error[%s]\n",
10153 __func__, adsp_err_get_err_str(
10154 atomic_read(&ac->cmd_state)));
10155 rc = adsp_err_get_lnx_err_code(
10156 atomic_read(&ac->cmd_state));
10157 goto fail_cmd;
10158 }
10159
10160 return 0;
10161fail_cmd:
10162 return rc;
10163}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010164EXPORT_SYMBOL(q6asm_reg_tx_overflow);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010165
10166int q6asm_reg_rx_underflow(struct audio_client *ac, uint16_t enable)
10167{
10168 struct asm_session_cmd_rgstr_rx_underflow rx_underflow;
10169 int rc;
10170
10171 if (!ac) {
10172 pr_err("%s: AC APR handle NULL\n", __func__);
10173 return -EINVAL;
10174 }
10175 if (ac->apr == NULL) {
10176 pr_err("%s: APR handle NULL\n", __func__);
10177 return -EINVAL;
10178 }
10179 pr_debug("%s: session[%d]enable[%d]\n", __func__,
10180 ac->session, enable);
10181 q6asm_add_hdr_async(ac, &rx_underflow.hdr, sizeof(rx_underflow), FALSE);
10182
10183 rx_underflow.hdr.opcode =
10184 ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS;
10185 /* tx overflow event: enable */
10186 rx_underflow.enable_flag = enable;
10187
10188 rc = apr_send_pkt(ac->apr, (uint32_t *) &rx_underflow);
10189 if (rc < 0) {
10190 pr_err("%s: tx overflow op[0x%x]rc[%d]\n",
10191 __func__, rx_underflow.hdr.opcode, rc);
10192 goto fail_cmd;
10193 }
10194 return 0;
10195fail_cmd:
10196 return -EINVAL;
10197}
10198
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010199/**
10200 * q6asm_adjust_session_clock -
10201 * command to adjust session clock
10202 *
10203 * @ac: Audio client handle
10204 * @adjust_time_lsw: lower 32bits
10205 * @adjust_time_msw: upper 32bits
10206 *
10207 * Returns 0 on success or error on failure
10208 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010209int q6asm_adjust_session_clock(struct audio_client *ac,
10210 uint32_t adjust_time_lsw,
10211 uint32_t adjust_time_msw)
10212{
10213 int rc = 0;
10214 int sz = 0;
10215 struct asm_session_cmd_adjust_session_clock_v2 adjust_clock;
10216
10217 pr_debug("%s: adjust_time_lsw is %x, adjust_time_msw is %x\n", __func__,
10218 adjust_time_lsw, adjust_time_msw);
10219
10220 if (!ac) {
10221 pr_err("%s: audio client handle is NULL\n", __func__);
10222 rc = -EINVAL;
10223 goto fail_cmd;
10224 }
10225
10226 if (ac->apr == NULL) {
10227 pr_err("%s: ac->apr is NULL", __func__);
10228 rc = -EINVAL;
10229 goto fail_cmd;
10230 }
10231
10232 sz = sizeof(struct asm_session_cmd_adjust_session_clock_v2);
10233 q6asm_add_hdr(ac, &adjust_clock.hdr, sz, TRUE);
10234 atomic_set(&ac->cmd_state, -1);
10235 adjust_clock.hdr.opcode = ASM_SESSION_CMD_ADJUST_SESSION_CLOCK_V2;
10236
10237 adjust_clock.adjustime_lsw = adjust_time_lsw;
10238 adjust_clock.adjustime_msw = adjust_time_msw;
10239
10240
10241 rc = apr_send_pkt(ac->apr, (uint32_t *) &adjust_clock);
10242 if (rc < 0) {
10243 pr_err("%s: adjust_clock send failed paramid [0x%x]\n",
10244 __func__, adjust_clock.hdr.opcode);
10245 rc = -EINVAL;
10246 goto fail_cmd;
10247 }
10248
10249 rc = wait_event_timeout(ac->cmd_wait,
10250 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
10251 if (!rc) {
10252 pr_err("%s: timeout, adjust_clock paramid[0x%x]\n",
10253 __func__, adjust_clock.hdr.opcode);
10254 rc = -ETIMEDOUT;
10255 goto fail_cmd;
10256 }
10257
10258 if (atomic_read(&ac->cmd_state) > 0) {
10259 pr_err("%s: DSP returned error[%s]\n",
10260 __func__, adsp_err_get_err_str(
10261 atomic_read(&ac->cmd_state)));
10262 rc = adsp_err_get_lnx_err_code(
10263 atomic_read(&ac->cmd_state));
10264 goto fail_cmd;
10265 }
10266 rc = 0;
10267fail_cmd:
10268 return rc;
10269}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010270EXPORT_SYMBOL(q6asm_adjust_session_clock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010271
10272/*
10273 * q6asm_get_path_delay() - get the path delay for an audio session
10274 * @ac: audio client handle
10275 *
10276 * Retrieves the current audio DSP path delay for the given audio session.
10277 *
10278 * Return: 0 on success, error code otherwise
10279 */
10280int q6asm_get_path_delay(struct audio_client *ac)
10281{
10282 int rc = 0;
10283 struct apr_hdr hdr;
10284
10285 if (!ac || ac->apr == NULL) {
10286 pr_err("%s: invalid audio client\n", __func__);
10287 return -EINVAL;
10288 }
10289
10290 hdr.opcode = ASM_SESSION_CMD_GET_PATH_DELAY_V2;
10291 q6asm_add_hdr(ac, &hdr, sizeof(hdr), TRUE);
10292 atomic_set(&ac->cmd_state, -1);
10293
10294 rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
10295 if (rc < 0) {
10296 pr_err("%s: Commmand 0x%x failed %d\n", __func__,
10297 hdr.opcode, rc);
10298 return rc;
10299 }
10300
10301 rc = wait_event_timeout(ac->cmd_wait,
10302 (atomic_read(&ac->cmd_state) >= 0), 5 * HZ);
10303 if (!rc) {
10304 pr_err("%s: timeout. waited for response opcode[0x%x]\n",
10305 __func__, hdr.opcode);
10306 return -ETIMEDOUT;
10307 }
10308
10309 if (atomic_read(&ac->cmd_state) > 0) {
10310 pr_err("%s: DSP returned error[%s]\n",
10311 __func__, adsp_err_get_err_str(
10312 atomic_read(&ac->cmd_state)));
10313 rc = adsp_err_get_lnx_err_code(
10314 atomic_read(&ac->cmd_state));
10315 return rc;
10316 }
10317
10318 return 0;
10319}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010320EXPORT_SYMBOL(q6asm_get_path_delay);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010321
10322int q6asm_get_apr_service_id(int session_id)
10323{
10324 pr_debug("%s:\n", __func__);
10325
10326 if (session_id <= 0 || session_id > ASM_ACTIVE_STREAMS_ALLOWED) {
10327 pr_err("%s: invalid session_id = %d\n", __func__, session_id);
10328 return -EINVAL;
10329 }
10330
Meng Wang9730cdd2017-09-26 12:48:31 +080010331 return ((struct apr_svc *)(session[session_id].ac)->apr)->id;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010332}
10333
10334int q6asm_get_asm_topology(int session_id)
10335{
10336 int topology = -EINVAL;
10337
10338 if (session_id <= 0 || session_id > ASM_ACTIVE_STREAMS_ALLOWED) {
10339 pr_err("%s: invalid session_id = %d\n", __func__, session_id);
10340 goto done;
10341 }
Meng Wang9730cdd2017-09-26 12:48:31 +080010342 if (session[session_id].ac == NULL) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010343 pr_err("%s: session not created for session id = %d\n",
10344 __func__, session_id);
10345 goto done;
10346 }
Meng Wang9730cdd2017-09-26 12:48:31 +080010347 topology = (session[session_id].ac)->topology;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010348done:
10349 return topology;
10350}
10351
10352int q6asm_get_asm_app_type(int session_id)
10353{
10354 int app_type = -EINVAL;
10355
10356 if (session_id <= 0 || session_id > ASM_ACTIVE_STREAMS_ALLOWED) {
10357 pr_err("%s: invalid session_id = %d\n", __func__, session_id);
10358 goto done;
10359 }
Meng Wang9730cdd2017-09-26 12:48:31 +080010360 if (session[session_id].ac == NULL) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010361 pr_err("%s: session not created for session id = %d\n",
10362 __func__, session_id);
10363 goto done;
10364 }
Meng Wang9730cdd2017-09-26 12:48:31 +080010365 app_type = (session[session_id].ac)->app_type;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010366done:
10367 return app_type;
10368}
10369
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -070010370/*
10371 * Retrieving cal_block will mark cal_block as stale.
10372 * Hence it cannot be reused or resent unless the flag
10373 * is reset.
10374 */
10375static int q6asm_get_asm_topology_apptype(struct q6asm_cal_info *cal_info)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010376{
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010377 struct cal_block_data *cal_block = NULL;
10378
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -070010379 cal_info->topology_id = DEFAULT_POPP_TOPOLOGY;
10380 cal_info->app_type = DEFAULT_APP_TYPE;
10381
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010382 if (cal_data[ASM_TOPOLOGY_CAL] == NULL)
10383 goto done;
10384
10385 mutex_lock(&cal_data[ASM_TOPOLOGY_CAL]->lock);
10386 cal_block = cal_utils_get_only_cal_block(cal_data[ASM_TOPOLOGY_CAL]);
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -070010387 if (cal_block == NULL || cal_utils_is_cal_stale(cal_block))
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010388 goto unlock;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -070010389 cal_info->topology_id = ((struct audio_cal_info_asm_top *)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010390 cal_block->cal_info)->topology;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -070010391 cal_info->app_type = ((struct audio_cal_info_asm_top *)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010392 cal_block->cal_info)->app_type;
10393
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -070010394 cal_utils_mark_cal_used(cal_block);
10395
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010396unlock:
10397 mutex_unlock(&cal_data[ASM_TOPOLOGY_CAL]->lock);
10398done:
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -070010399 pr_debug("%s: Using topology %d app_type %d\n", __func__,
10400 cal_info->topology_id, cal_info->app_type);
10401
10402 return 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010403}
10404
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010405/**
10406 * q6asm_send_cal -
10407 * command to send ASM calibration
10408 *
10409 * @ac: Audio client handle
10410 *
10411 * Returns 0 on success or error on failure
10412 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010413int q6asm_send_cal(struct audio_client *ac)
10414{
10415 struct cal_block_data *cal_block = NULL;
10416 struct apr_hdr hdr;
10417 char *asm_params = NULL;
10418 struct asm_stream_cmd_set_pp_params_v2 payload_params;
Xiaojun Sanga4648082018-04-27 14:57:33 +080010419 int sz, rc = -EINVAL, session_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010420
10421 pr_debug("%s:\n", __func__);
10422
10423 if (!ac) {
10424 pr_err("%s: APR handle NULL\n", __func__);
10425 goto done;
10426 }
Xiaojun Sanga4648082018-04-27 14:57:33 +080010427
10428 session_id = q6asm_get_session_id_from_audio_client(ac);
10429 if (!session_id)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010430 goto done;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010431
10432 if (cal_data[ASM_AUDSTRM_CAL] == NULL)
10433 goto done;
10434
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010435 mutex_lock(&cal_data[ASM_AUDSTRM_CAL]->lock);
10436 cal_block = cal_utils_get_only_cal_block(cal_data[ASM_AUDSTRM_CAL]);
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -070010437 if (cal_block == NULL || cal_utils_is_cal_stale(cal_block)) {
10438 rc = 0; /* not error case */
10439 pr_err("%s: cal_block is NULL or stale\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010440 __func__);
10441 goto unlock;
10442 }
10443
10444 if (cal_block->cal_data.size == 0) {
10445 rc = 0; /* not error case */
10446 pr_debug("%s: cal_data.size is 0, don't send cal data\n",
10447 __func__);
10448 goto unlock;
10449 }
10450
10451 rc = remap_cal_data(ASM_AUDSTRM_CAL_TYPE, cal_block);
10452 if (rc) {
10453 pr_err("%s: Remap_cal_data failed for cal %d!\n",
10454 __func__, ASM_AUDSTRM_CAL);
10455 goto unlock;
10456 }
10457
10458 sz = sizeof(struct apr_hdr) +
10459 sizeof(struct asm_stream_cmd_set_pp_params_v2);
10460 asm_params = kzalloc(sz, GFP_KERNEL);
10461 if (!asm_params) {
10462 pr_err("%s, asm params memory alloc failed", __func__);
10463 rc = -ENOMEM;
10464 goto unlock;
10465 }
10466
Xiaojun Sanga4648082018-04-27 14:57:33 +080010467 mutex_lock(&session[session_id].mutex_lock_per_session);
10468 if (!q6asm_is_valid_audio_client(ac)) {
10469 rc = -EINVAL;
10470 goto free;
10471 }
10472
10473 if (ac->apr == NULL) {
10474 pr_err("%s: AC APR handle NULL\n", __func__);
10475 goto free;
10476 }
10477 if (ac->io_mode & NT_MODE) {
10478 pr_debug("%s: called for NT MODE, exiting\n", __func__);
10479 goto free;
10480 }
10481
10482 if (ac->perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) {
10483 rc = 0; /* no cal is required, not error case */
10484 goto free;
10485 }
10486
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010487 /* asm_stream_cmd_set_pp_params_v2 has no APR header in it */
10488 q6asm_add_hdr_async(ac, &hdr, (sizeof(struct apr_hdr) +
10489 sizeof(struct asm_stream_cmd_set_pp_params_v2)), TRUE);
10490
10491 atomic_set(&ac->cmd_state_pp, -1);
10492 hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
10493 payload_params.data_payload_addr_lsw =
10494 lower_32_bits(cal_block->cal_data.paddr);
10495 payload_params.data_payload_addr_msw =
10496 msm_audio_populate_upper_32_bits(
10497 cal_block->cal_data.paddr);
10498 payload_params.mem_map_handle = cal_block->map_data.q6map_handle;
10499 payload_params.data_payload_size = cal_block->cal_data.size;
10500 memcpy(((u8 *)asm_params), &hdr, sizeof(struct apr_hdr));
10501 memcpy(((u8 *)asm_params + sizeof(struct apr_hdr)), &payload_params,
10502 sizeof(struct asm_stream_cmd_set_pp_params_v2));
10503
10504 pr_debug("%s: phyaddr lsw = %x msw = %x, maphdl = %x calsize = %d\n",
10505 __func__, payload_params.data_payload_addr_lsw,
10506 payload_params.data_payload_addr_msw,
10507 payload_params.mem_map_handle,
10508 payload_params.data_payload_size);
10509
10510 rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params);
10511 if (rc < 0) {
10512 pr_err("%s: audio audstrm cal send failed\n", __func__);
10513 rc = -EINVAL;
10514 goto free;
10515 }
10516 rc = wait_event_timeout(ac->cmd_wait,
10517 (atomic_read(&ac->cmd_state_pp) >= 0), 5 * HZ);
10518 if (!rc) {
10519 pr_err("%s: timeout, audio audstrm cal send\n", __func__);
10520 rc = -ETIMEDOUT;
10521 goto free;
10522 }
10523 if (atomic_read(&ac->cmd_state_pp) > 0) {
10524 pr_err("%s: DSP returned error[%d] audio audstrm cal send\n",
10525 __func__, atomic_read(&ac->cmd_state_pp));
10526 rc = -EINVAL;
10527 goto free;
10528 }
10529
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -070010530 if (cal_block)
10531 cal_utils_mark_cal_used(cal_block);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010532 rc = 0;
10533
10534free:
Xiaojun Sanga4648082018-04-27 14:57:33 +080010535 mutex_unlock(&session[session_id].mutex_lock_per_session);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010536 kfree(asm_params);
10537unlock:
10538 mutex_unlock(&cal_data[ASM_AUDSTRM_CAL]->lock);
10539done:
10540 return rc;
10541}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010542EXPORT_SYMBOL(q6asm_send_cal);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010543
10544static int get_cal_type_index(int32_t cal_type)
10545{
10546 int ret = -EINVAL;
10547
10548 switch (cal_type) {
10549 case ASM_TOPOLOGY_CAL_TYPE:
10550 ret = ASM_TOPOLOGY_CAL;
10551 break;
10552 case ASM_CUST_TOPOLOGY_CAL_TYPE:
10553 ret = ASM_CUSTOM_TOP_CAL;
10554 break;
10555 case ASM_AUDSTRM_CAL_TYPE:
10556 ret = ASM_AUDSTRM_CAL;
10557 break;
10558 case ASM_RTAC_APR_CAL_TYPE:
10559 ret = ASM_RTAC_APR_CAL;
10560 break;
10561 default:
10562 pr_err("%s: invalid cal type %d!\n", __func__, cal_type);
10563 }
10564 return ret;
10565}
10566
10567static int q6asm_alloc_cal(int32_t cal_type,
10568 size_t data_size, void *data)
10569{
10570 int ret = 0;
10571 int cal_index;
10572
10573 pr_debug("%s:\n", __func__);
10574
10575 cal_index = get_cal_type_index(cal_type);
10576 if (cal_index < 0) {
10577 pr_err("%s: could not get cal index %d!\n",
10578 __func__, cal_index);
10579 ret = -EINVAL;
10580 goto done;
10581 }
10582
10583 ret = cal_utils_alloc_cal(data_size, data,
10584 cal_data[cal_index], 0, NULL);
10585 if (ret < 0) {
10586 pr_err("%s: cal_utils_alloc_block failed, ret = %d, cal type = %d!\n",
10587 __func__, ret, cal_type);
10588 ret = -EINVAL;
10589 goto done;
10590 }
10591done:
10592 return ret;
10593}
10594
10595static int q6asm_dealloc_cal(int32_t cal_type,
10596 size_t data_size, void *data)
10597{
10598 int ret = 0;
10599 int cal_index;
10600
10601 pr_debug("%s:\n", __func__);
10602
10603 cal_index = get_cal_type_index(cal_type);
10604 if (cal_index < 0) {
10605 pr_err("%s: could not get cal index %d!\n",
10606 __func__, cal_index);
10607 ret = -EINVAL;
10608 goto done;
10609 }
10610
10611 ret = cal_utils_dealloc_cal(data_size, data,
10612 cal_data[cal_index]);
10613 if (ret < 0) {
10614 pr_err("%s: cal_utils_dealloc_block failed, ret = %d, cal type = %d!\n",
10615 __func__, ret, cal_type);
10616 ret = -EINVAL;
10617 goto done;
10618 }
10619done:
10620 return ret;
10621}
10622
10623static int q6asm_set_cal(int32_t cal_type,
10624 size_t data_size, void *data)
10625{
10626 int ret = 0;
10627 int cal_index;
10628
10629 pr_debug("%s:\n", __func__);
10630
10631 cal_index = get_cal_type_index(cal_type);
10632 if (cal_index < 0) {
10633 pr_err("%s: could not get cal index %d!\n",
10634 __func__, cal_index);
10635 ret = -EINVAL;
10636 goto done;
10637 }
10638
10639 ret = cal_utils_set_cal(data_size, data,
10640 cal_data[cal_index], 0, NULL);
10641 if (ret < 0) {
10642 pr_err("%s: cal_utils_set_cal failed, ret = %d, cal type = %d!\n",
10643 __func__, ret, cal_type);
10644 ret = -EINVAL;
10645 goto done;
10646 }
10647
10648 if (cal_index == ASM_CUSTOM_TOP_CAL) {
10649 mutex_lock(&cal_data[ASM_CUSTOM_TOP_CAL]->lock);
10650 set_custom_topology = 1;
10651 mutex_unlock(&cal_data[ASM_CUSTOM_TOP_CAL]->lock);
10652 }
10653done:
10654 return ret;
10655}
10656
10657static void q6asm_delete_cal_data(void)
10658{
10659 pr_debug("%s:\n", __func__);
10660 cal_utils_destroy_cal_types(ASM_MAX_CAL_TYPES, cal_data);
10661}
10662
10663static int q6asm_init_cal_data(void)
10664{
10665 int ret = 0;
10666 struct cal_type_info cal_type_info[] = {
10667 {{ASM_TOPOLOGY_CAL_TYPE,
10668 {NULL, NULL, NULL,
10669 q6asm_set_cal, NULL, NULL} },
10670 {NULL, NULL, cal_utils_match_buf_num} },
10671
10672 {{ASM_CUST_TOPOLOGY_CAL_TYPE,
10673 {q6asm_alloc_cal, q6asm_dealloc_cal, NULL,
10674 q6asm_set_cal, NULL, NULL} },
10675 {NULL, q6asm_unmap_cal_memory, cal_utils_match_buf_num} },
10676
10677 {{ASM_AUDSTRM_CAL_TYPE,
10678 {q6asm_alloc_cal, q6asm_dealloc_cal, NULL,
10679 q6asm_set_cal, NULL, NULL} },
10680 {NULL, q6asm_unmap_cal_memory, cal_utils_match_buf_num} },
10681
10682 {{ASM_RTAC_APR_CAL_TYPE,
10683 {NULL, NULL, NULL, NULL, NULL, NULL} },
10684 {NULL, NULL, cal_utils_match_buf_num} }
10685 };
10686 pr_debug("%s\n", __func__);
10687
10688 ret = cal_utils_create_cal_types(ASM_MAX_CAL_TYPES, cal_data,
10689 cal_type_info);
10690 if (ret < 0) {
10691 pr_err("%s: could not create cal type! %d\n",
10692 __func__, ret);
10693 ret = -EINVAL;
10694 goto err;
10695 }
10696
10697 return ret;
10698err:
10699 q6asm_delete_cal_data();
10700 return ret;
10701}
10702
10703static int q6asm_is_valid_session(struct apr_client_data *data, void *priv)
10704{
10705 struct audio_client *ac = (struct audio_client *)priv;
10706 union asm_token_struct asm_token;
10707
10708 asm_token.token = data->token;
10709 if (asm_token._token.session_id != ac->session) {
10710 pr_err("%s: Invalid session[%d] rxed expected[%d]",
10711 __func__, asm_token._token.session_id, ac->session);
10712 return -EINVAL;
10713 }
10714 return 0;
10715}
10716
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010717int __init q6asm_init(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010718{
10719 int lcnt, ret;
10720
10721 pr_debug("%s:\n", __func__);
10722
Meng Wang9730cdd2017-09-26 12:48:31 +080010723 memset(session, 0, sizeof(struct audio_session) *
10724 (ASM_ACTIVE_STREAMS_ALLOWED + 1));
Xiaojun Sanga4648082018-04-27 14:57:33 +080010725 for (lcnt = 0; lcnt <= ASM_ACTIVE_STREAMS_ALLOWED; lcnt++) {
Meng Wang9730cdd2017-09-26 12:48:31 +080010726 spin_lock_init(&(session[lcnt].session_lock));
Xiaojun Sanga4648082018-04-27 14:57:33 +080010727 mutex_init(&(session[lcnt].mutex_lock_per_session));
10728 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010729 set_custom_topology = 1;
10730
10731 /*setup common client used for cal mem map */
10732 common_client.session = ASM_CONTROL_SESSION;
10733 common_client.port[0].buf = &common_buf[0];
10734 common_client.port[1].buf = &common_buf[1];
10735 init_waitqueue_head(&common_client.cmd_wait);
10736 init_waitqueue_head(&common_client.time_wait);
10737 init_waitqueue_head(&common_client.mem_wait);
10738 atomic_set(&common_client.time_flag, 1);
10739 INIT_LIST_HEAD(&common_client.port[0].mem_map_handle);
10740 INIT_LIST_HEAD(&common_client.port[1].mem_map_handle);
10741 mutex_init(&common_client.cmd_lock);
10742 for (lcnt = 0; lcnt <= OUT; lcnt++) {
10743 mutex_init(&common_client.port[lcnt].lock);
10744 spin_lock_init(&common_client.port[lcnt].dsp_lock);
10745 }
10746 atomic_set(&common_client.cmd_state, 0);
10747 atomic_set(&common_client.mem_state, 0);
10748
10749 ret = q6asm_init_cal_data();
10750 if (ret)
10751 pr_err("%s: could not init cal data! ret %d\n",
10752 __func__, ret);
10753
10754 config_debug_fs_init();
10755
10756 return 0;
10757}
10758
Asish Bhattacharya5faacb32017-12-04 17:23:15 +053010759void q6asm_exit(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010760{
10761 q6asm_delete_cal_data();
10762}