blob: e415db02d98f207a3147231e6b0e4da2f31b8136 [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
1777 port = &ac->port[dir];
1778
1779 switch (data->opcode) {
1780 case ASM_CMDRSP_SHARED_MEM_MAP_REGIONS:{
1781 pr_debug("%s:PL#0[0x%x] dir=0x%x s_id=0x%x\n",
1782 __func__, payload[0], dir, asm_token._token.session_id);
1783 spin_lock_irqsave(&port->dsp_lock, dsp_flags);
1784 if (atomic_cmpxchg(&ac->mem_state, -1, 0) == -1) {
1785 ac->port[dir].tmp_hdl = payload[0];
1786 wake_up(&ac->mem_wait);
1787 }
1788 spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
1789 break;
1790 }
1791 case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:{
Xiaojun Sang55ee5692019-02-15 16:26:16 +08001792 if (data->payload_size >= 2 * sizeof(uint32_t))
1793 pr_debug("%s: PL#0[0x%x]PL#1 [0x%x]\n",
1794 __func__, payload[0], payload[1]);
1795 else
1796 pr_debug("%s: Payload size of %d is less than expected.\n",
1797 __func__, data->payload_size);
1798
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301799 spin_lock_irqsave(&port->dsp_lock, dsp_flags);
1800 if (atomic_cmpxchg(&ac->mem_state, -1, 0) == -1)
1801 wake_up(&ac->mem_wait);
1802 spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
1803
1804 break;
1805 }
1806 default:
Xiaojun Sang55ee5692019-02-15 16:26:16 +08001807 if (data->payload_size >= 2 * sizeof(uint32_t))
1808 pr_debug("%s: command[0x%x]success [0x%x]\n",
1809 __func__, payload[0], payload[1]);
1810 else
1811 pr_debug("%s: Payload size of %d is less than expected.\n",
1812 __func__, data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301813 }
1814 if (ac->cb)
1815 ac->cb(data->opcode, data->token,
1816 data->payload, ac->priv);
Meng Wang9730cdd2017-09-26 12:48:31 +08001817 if ((session_id > 0 && session_id <= ASM_ACTIVE_STREAMS_ALLOWED))
Meng Wangb6afa8c2017-11-30 17:55:05 +08001818 spin_unlock_irqrestore(
1819 &(session[session_id].session_lock), flags);
Meng Wang9730cdd2017-09-26 12:48:31 +08001820
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301821 return 0;
1822}
1823
1824static void q6asm_process_mtmx_get_param_rsp(struct audio_client *ac,
1825 struct asm_mtmx_strtr_get_params_cmdrsp *cmdrsp)
1826{
1827 struct asm_session_mtmx_strtr_param_session_time_v3_t *time;
1828
1829 if (cmdrsp->err_code) {
1830 dev_err_ratelimited(ac->dev,
1831 "%s: err=%x, mod_id=%x, param_id=%x\n",
1832 __func__, cmdrsp->err_code,
1833 cmdrsp->param_info.module_id,
1834 cmdrsp->param_info.param_id);
1835 return;
1836 }
1837 dev_dbg_ratelimited(ac->dev,
1838 "%s: mod_id=%x, param_id=%x\n", __func__,
1839 cmdrsp->param_info.module_id,
1840 cmdrsp->param_info.param_id);
1841
1842 switch (cmdrsp->param_info.module_id) {
1843 case ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC:
1844 switch (cmdrsp->param_info.param_id) {
1845 case ASM_SESSION_MTMX_STRTR_PARAM_SESSION_TIME_V3:
1846 time = &cmdrsp->param_data.session_time;
1847 dev_vdbg(ac->dev, "%s: GET_TIME_V3, time_lsw=%x, time_msw=%x\n",
1848 __func__, time->session_time_lsw,
1849 time->session_time_msw);
1850 ac->time_stamp = (uint64_t)(((uint64_t)
1851 time->session_time_msw << 32) |
1852 time->session_time_lsw);
1853 if (time->flags &
1854 ASM_SESSION_MTMX_STRTR_PARAM_STIME_TSTMP_FLG_BMASK)
1855 dev_warn_ratelimited(ac->dev,
1856 "%s: recv inval tstmp\n",
1857 __func__);
1858 if (atomic_cmpxchg(&ac->time_flag, 1, 0))
1859 wake_up(&ac->time_wait);
1860
1861 break;
1862 default:
1863 dev_err(ac->dev, "%s: unexpected param_id %x\n",
1864 __func__, cmdrsp->param_info.param_id);
1865 break;
1866 }
1867 break;
1868 default:
1869 dev_err(ac->dev, "%s: unexpected mod_id %x\n", __func__,
1870 cmdrsp->param_info.module_id);
1871 break;
1872 }
1873}
1874
1875static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
1876{
1877 int i = 0;
1878 struct audio_client *ac = (struct audio_client *)priv;
Vignesh Kulothungan023a5322018-06-21 11:13:29 -07001879 unsigned long dsp_flags = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301880 uint32_t *payload;
1881 uint32_t wakeup_flag = 1;
1882 int32_t ret = 0;
1883 union asm_token_struct asm_token;
1884 uint8_t buf_index;
1885 struct msm_adsp_event_data *pp_event_package = NULL;
1886 uint32_t payload_size = 0;
Vignesh Kulothungan023a5322018-06-21 11:13:29 -07001887 unsigned long flags = 0;
Meng Wang9730cdd2017-09-26 12:48:31 +08001888 int session_id;
1889
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301890 if (ac == NULL) {
1891 pr_err("%s: ac NULL\n", __func__);
1892 return -EINVAL;
1893 }
1894 if (data == NULL) {
1895 pr_err("%s: data NULL\n", __func__);
1896 return -EINVAL;
1897 }
Meng Wang9730cdd2017-09-26 12:48:31 +08001898
1899 session_id = q6asm_get_session_id_from_audio_client(ac);
1900 if (session_id <= 0 || session_id > ASM_ACTIVE_STREAMS_ALLOWED) {
1901 pr_err("%s: Session ID is invalid, session = %d\n", __func__,
1902 session_id);
1903 return -EINVAL;
1904 }
Meng Wangb6afa8c2017-11-30 17:55:05 +08001905 spin_lock_irqsave(&(session[session_id].session_lock), flags);
Meng Wang9730cdd2017-09-26 12:48:31 +08001906
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301907 if (!q6asm_is_valid_audio_client(ac)) {
1908 pr_err("%s: audio client pointer is invalid, ac = %pK\n",
1909 __func__, ac);
Meng Wangb6afa8c2017-11-30 17:55:05 +08001910 spin_unlock_irqrestore(
1911 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301912 return -EINVAL;
1913 }
1914
1915 payload = data->payload;
1916 asm_token.token = data->token;
1917 if (q6asm_get_flag_from_token(&asm_token, ASM_CMD_NO_WAIT_OFFSET)) {
1918 pr_debug("%s: No wait command opcode[0x%x] cmd_opcode:%x\n",
1919 __func__, data->opcode, payload ? payload[0] : 0);
1920 wakeup_flag = 0;
1921 }
1922
1923 if (data->opcode == RESET_EVENTS) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301924 atomic_set(&ac->reset, 1);
1925 if (ac->apr == NULL) {
1926 ac->apr = ac->apr2;
1927 ac->apr2 = NULL;
1928 }
1929 pr_debug("%s: Reset event is received: %d %d apr[%pK]\n",
1930 __func__,
1931 data->reset_event, data->reset_proc, ac->apr);
1932 if (ac->cb)
1933 ac->cb(data->opcode, data->token,
1934 (uint32_t *)data->payload, ac->priv);
1935 apr_reset(ac->apr);
1936 ac->apr = NULL;
1937 atomic_set(&ac->time_flag, 0);
1938 atomic_set(&ac->cmd_state, 0);
1939 atomic_set(&ac->mem_state, 0);
1940 atomic_set(&ac->cmd_state_pp, 0);
1941 wake_up(&ac->time_wait);
1942 wake_up(&ac->cmd_wait);
1943 wake_up(&ac->mem_wait);
Meng Wangb6afa8c2017-11-30 17:55:05 +08001944 spin_unlock_irqrestore(
1945 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301946 return 0;
1947 }
1948
1949 dev_vdbg(ac->dev, "%s: session[%d]opcode[0x%x] token[0x%x]payload_size[%d] src[%d] dest[%d]\n",
1950 __func__,
1951 ac->session, data->opcode,
1952 data->token, data->payload_size, data->src_port,
1953 data->dest_port);
1954 if ((data->opcode != ASM_DATA_EVENT_RENDERED_EOS) &&
1955 (data->opcode != ASM_DATA_EVENT_EOS) &&
Vignesh Kulothunganb79df2f2019-01-22 10:31:21 -08001956 (data->opcode != ASM_SESSION_EVENTX_OVERFLOW) &&
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301957 (data->opcode != ASM_SESSION_EVENT_RX_UNDERFLOW)) {
1958 if (payload == NULL) {
1959 pr_err("%s: payload is null\n", __func__);
Meng Wangb6afa8c2017-11-30 17:55:05 +08001960 spin_unlock_irqrestore(
1961 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301962 return -EINVAL;
1963 }
Xiaojun Sang55ee5692019-02-15 16:26:16 +08001964 if (data->payload_size >=
1965 2 * sizeof(uint32_t))
1966 dev_vdbg(ac->dev, "%s: Payload = [0x%x] status[0x%x] opcode 0x%x\n",
1967 __func__, payload[0], payload[1], data->opcode);
1968 else
1969 dev_vdbg(ac->dev, "%s: Payload size of %d is less than expected.\n",
1970 __func__, data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301971 }
1972 if (data->opcode == APR_BASIC_RSP_RESULT) {
1973 switch (payload[0]) {
1974 case ASM_STREAM_CMD_SET_PP_PARAMS_V2:
1975 if (rtac_make_asm_callback(ac->session, payload,
1976 data->payload_size))
1977 break;
1978 case ASM_SESSION_CMD_PAUSE:
1979 case ASM_SESSION_CMD_SUSPEND:
1980 case ASM_DATA_CMD_EOS:
1981 case ASM_STREAM_CMD_CLOSE:
1982 case ASM_STREAM_CMD_FLUSH:
1983 case ASM_SESSION_CMD_RUN_V2:
1984 case ASM_SESSION_CMD_REGISTER_FORX_OVERFLOW_EVENTS:
1985 case ASM_STREAM_CMD_FLUSH_READBUFS:
1986 pr_debug("%s: session %d opcode 0x%x token 0x%x Payload = [0x%x] src %d dest %d\n",
1987 __func__, ac->session, data->opcode, data->token,
1988 payload[0], data->src_port, data->dest_port);
1989 ret = q6asm_is_valid_session(data, priv);
1990 if (ret != 0) {
1991 pr_err("%s: session invalid %d\n", __func__, ret);
Meng Wangb6afa8c2017-11-30 17:55:05 +08001992 spin_unlock_irqrestore(
1993 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301994 return ret;
1995 }
1996 case ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2:
1997 case ASM_STREAM_CMD_OPEN_READ_V3:
1998 case ASM_STREAM_CMD_OPEN_WRITE_V3:
1999 case ASM_STREAM_CMD_OPEN_PULL_MODE_WRITE:
2000 case ASM_STREAM_CMD_OPEN_PUSH_MODE_READ:
2001 case ASM_STREAM_CMD_OPEN_READWRITE_V2:
2002 case ASM_STREAM_CMD_OPEN_LOOPBACK_V2:
2003 case ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK:
2004 case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
2005 case ASM_DATA_CMD_IEC_60958_MEDIA_FMT:
2006 case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
2007 case ASM_STREAM_CMD_SET_ENCDEC_PARAM_V2:
2008 case ASM_STREAM_CMD_REGISTER_ENCDEC_EVENTS:
2009 case ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE:
2010 case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE:
2011 case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE:
2012 case ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS:
2013 case ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED:
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002014 if (data->payload_size >=
2015 2 * sizeof(uint32_t) &&
2016 payload[1] != 0) {
2017 pr_debug("%s: session %d opcode 0x%x token 0x%x Payload = [0x%x] stat 0x%x src %d dest %d\n",
2018 __func__, ac->session,
2019 data->opcode, data->token,
2020 payload[0], payload[1],
2021 data->src_port, data->dest_port);
2022 pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302023 __func__, payload[0], payload[1]);
2024 if (wakeup_flag) {
2025 if ((is_adsp_reg_event(payload[0]) >= 0)
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002026 || (payload[0] ==
2027 ASM_STREAM_CMD_SET_PP_PARAMS_V2))
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302028 atomic_set(&ac->cmd_state_pp,
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002029 payload[1]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302030 else
2031 atomic_set(&ac->cmd_state,
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002032 payload[1]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302033 wake_up(&ac->cmd_wait);
2034 }
Meng Wangb6afa8c2017-11-30 17:55:05 +08002035 spin_unlock_irqrestore(
2036 &(session[session_id].session_lock),
2037 flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302038 return 0;
2039 }
2040 if ((is_adsp_reg_event(payload[0]) >= 0) ||
2041 (payload[0] == ASM_STREAM_CMD_SET_PP_PARAMS_V2)) {
2042 if (atomic_read(&ac->cmd_state_pp) &&
2043 wakeup_flag) {
2044 atomic_set(&ac->cmd_state_pp, 0);
2045 wake_up(&ac->cmd_wait);
2046 }
2047 } else {
2048 if (atomic_read(&ac->cmd_state) &&
2049 wakeup_flag) {
2050 atomic_set(&ac->cmd_state, 0);
2051 wake_up(&ac->cmd_wait);
2052 }
2053 }
2054 if (ac->cb)
2055 ac->cb(data->opcode, data->token,
2056 (uint32_t *)data->payload, ac->priv);
2057 break;
2058 case ASM_CMD_ADD_TOPOLOGIES:
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002059 if (data->payload_size >=
2060 2 * sizeof(uint32_t) &&
2061 payload[1] != 0) {
2062 pr_debug("%s:Payload = [0x%x]stat[0x%x]\n",
2063 __func__, payload[0], payload[1]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302064 pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
2065 __func__, payload[0], payload[1]);
2066 if (wakeup_flag) {
2067 atomic_set(&ac->mem_state, payload[1]);
2068 wake_up(&ac->mem_wait);
2069 }
Meng Wangb6afa8c2017-11-30 17:55:05 +08002070 spin_unlock_irqrestore(
2071 &(session[session_id].session_lock),
2072 flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302073 return 0;
2074 }
2075 if (atomic_read(&ac->mem_state) && wakeup_flag) {
2076 atomic_set(&ac->mem_state, 0);
2077 wake_up(&ac->mem_wait);
2078 }
2079 if (ac->cb)
2080 ac->cb(data->opcode, data->token,
2081 (uint32_t *)data->payload, ac->priv);
2082 break;
2083 case ASM_DATA_EVENT_WATERMARK: {
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002084 if (data->payload_size >= 2 * sizeof(uint32_t))
2085 pr_debug("%s: Watermark opcode[0x%x] status[0x%x]",
2086 __func__, payload[0], payload[1]);
2087 else
2088 pr_err("%s: payload size of %x is less than expected.\n",
2089 __func__, data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302090 break;
2091 }
2092 case ASM_STREAM_CMD_GET_PP_PARAMS_V2:
2093 pr_debug("%s: ASM_STREAM_CMD_GET_PP_PARAMS_V2 session %d opcode 0x%x token 0x%x src %d dest %d\n",
2094 __func__, ac->session,
2095 data->opcode, data->token,
2096 data->src_port, data->dest_port);
2097 /* Should only come here if there is an APR */
2098 /* error or malformed APR packet. Otherwise */
2099 /* response will be returned as */
2100 /* ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2 */
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002101 if (data->payload_size >= 2 * sizeof(uint32_t)) {
2102 if (payload[1] != 0) {
2103 pr_err("%s: ASM get param error = %d, resuming\n",
2104 __func__, payload[1]);
2105 rtac_make_asm_callback(ac->session,
2106 payload,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302107 data->payload_size);
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002108 }
2109 } else {
2110 pr_err("%s: payload size of %x is less than expected.\n",
2111 __func__, data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302112 }
2113 break;
2114 case ASM_STREAM_CMD_REGISTER_PP_EVENTS:
2115 pr_debug("%s: ASM_STREAM_CMD_REGISTER_PP_EVENTS session %d opcode 0x%x token 0x%x src %d dest %d\n",
2116 __func__, ac->session,
2117 data->opcode, data->token,
2118 data->src_port, data->dest_port);
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002119 if (data->payload_size >= 2 * sizeof(uint32_t)) {
2120 if (payload[1] != 0)
2121 pr_err("%s: ASM get param error = %d, resuming\n",
2122 __func__, payload[1]);
2123 atomic_set(&ac->cmd_state_pp, payload[1]);
2124 wake_up(&ac->cmd_wait);
2125 } else {
2126 pr_err("%s: payload size of %x is less than expected.\n",
2127 __func__, data->payload_size);
2128 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302129 break;
2130 default:
2131 pr_debug("%s: command[0x%x] not expecting rsp\n",
2132 __func__, payload[0]);
2133 break;
2134 }
Meng Wang9730cdd2017-09-26 12:48:31 +08002135
Meng Wangb6afa8c2017-11-30 17:55:05 +08002136 spin_unlock_irqrestore(
2137 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302138 return 0;
2139 }
2140
2141 switch (data->opcode) {
2142 case ASM_DATA_EVENT_WRITE_DONE_V2:{
2143 struct audio_port_data *port = &ac->port[IN];
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002144 if (data->payload_size >= 2 * sizeof(uint32_t))
2145 dev_vdbg(ac->dev, "%s: Rxed opcode[0x%x] status[0x%x] token[%d]",
2146 __func__, payload[0], payload[1],
2147 data->token);
2148 else
2149 dev_err(ac->dev, "%s: payload size of %x is less than expected.\n",
2150 __func__, data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302151 if (ac->io_mode & SYNC_IO_MODE) {
2152 if (port->buf == NULL) {
2153 pr_err("%s: Unexpected Write Done\n",
2154 __func__);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002155 spin_unlock_irqrestore(
2156 &(session[session_id].session_lock),
2157 flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302158 return -EINVAL;
2159 }
2160 spin_lock_irqsave(&port->dsp_lock, dsp_flags);
2161 buf_index = asm_token._token.buf_index;
Vignesh Kulothunganb79df2f2019-01-22 10:31:21 -08002162 if (buf_index < 0 || buf_index >= port->max_buf_cnt) {
2163 pr_debug("%s: Invalid buffer index %u\n",
2164 __func__, buf_index);
2165 spin_unlock_irqrestore(&port->dsp_lock,
2166 dsp_flags);
2167 spin_unlock_irqrestore(
2168 &(session[session_id].session_lock),
2169 flags);
2170 return -EINVAL;
2171 }
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002172 if (data->payload_size >= 2 * sizeof(uint32_t) &&
2173 (lower_32_bits(port->buf[buf_index].phys) !=
2174 payload[0] ||
2175 msm_audio_populate_upper_32_bits(
2176 port->buf[buf_index].phys) !=
2177 payload[1])) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302178 pr_debug("%s: Expected addr %pK\n",
2179 __func__, &port->buf[buf_index].phys);
2180 pr_err("%s: rxedl[0x%x] rxedu [0x%x]\n",
2181 __func__, payload[0], payload[1]);
2182 spin_unlock_irqrestore(&port->dsp_lock,
2183 dsp_flags);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002184 spin_unlock_irqrestore(
2185 &(session[session_id].session_lock),
2186 flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302187 return -EINVAL;
2188 }
2189 port->buf[buf_index].used = 1;
2190 spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
2191
2192 config_debug_fs_write_cb();
2193
2194 for (i = 0; i < port->max_buf_cnt; i++)
2195 dev_vdbg(ac->dev, "%s %d\n",
2196 __func__, port->buf[i].used);
2197
2198 }
2199 break;
2200 }
2201 case ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2:
2202 pr_debug("%s: ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2 session %d opcode 0x%x token 0x%x src %d dest %d\n",
2203 __func__, ac->session, data->opcode,
2204 data->token,
2205 data->src_port, data->dest_port);
2206 if (payload[0] != 0) {
2207 pr_err("%s: ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2 returned error = 0x%x\n",
2208 __func__, payload[0]);
2209 } else if (generic_get_data) {
2210 generic_get_data->valid = 1;
2211 if (generic_get_data->is_inband) {
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002212 if (data->payload_size >= 4 * sizeof(uint32_t))
2213 pr_debug("%s: payload[1] = 0x%x, payload[2]=0x%x, payload[3]=0x%x\n",
2214 __func__, payload[1],
2215 payload[2], payload[3]);
2216 else
2217 pr_err("%s: payload size of %x is less than expected.\n",
2218 __func__,
2219 data->payload_size);
2220
2221 if (data->payload_size >=
2222 (4 + (payload[3]>>2))
2223 * sizeof(uint32_t)) {
2224 generic_get_data->size_in_ints =
2225 payload[3]>>2;
2226 for (i = 0; i < payload[3]>>2; i++) {
2227 generic_get_data->ints[i] =
2228 payload[4+i];
2229 pr_debug("%s: ASM callback val %i = %i\n",
2230 __func__, i,
2231 payload[4+i]);
2232 }
2233 } else {
2234 pr_err("%s: payload size of %x is less than expected.\n",
2235 __func__,
2236 data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302237 }
2238 pr_debug("%s: callback size in ints = %i\n",
2239 __func__,
2240 generic_get_data->size_in_ints);
2241 }
2242 if (atomic_read(&ac->cmd_state) && wakeup_flag) {
2243 atomic_set(&ac->cmd_state, 0);
2244 wake_up(&ac->cmd_wait);
2245 }
2246 break;
2247 }
2248 rtac_make_asm_callback(ac->session, payload,
2249 data->payload_size);
2250 break;
2251 case ASM_DATA_EVENT_READ_DONE_V2:{
2252
2253 struct audio_port_data *port = &ac->port[OUT];
2254
2255 config_debug_fs_read_cb();
2256
2257 dev_vdbg(ac->dev, "%s: ReadDone: status=%d buff_add=0x%x act_size=%d offset=%d\n",
2258 __func__, payload[READDONE_IDX_STATUS],
2259 payload[READDONE_IDX_BUFADD_LSW],
2260 payload[READDONE_IDX_SIZE],
2261 payload[READDONE_IDX_OFFSET]);
2262
2263 dev_vdbg(ac->dev, "%s: ReadDone:msw_ts=%d lsw_ts=%d memmap_hdl=0x%x flags=%d id=%d num=%d\n",
2264 __func__, payload[READDONE_IDX_MSW_TS],
2265 payload[READDONE_IDX_LSW_TS],
2266 payload[READDONE_IDX_MEMMAP_HDL],
2267 payload[READDONE_IDX_FLAGS],
2268 payload[READDONE_IDX_SEQ_ID],
2269 payload[READDONE_IDX_NUMFRAMES]);
2270
2271 if (ac->io_mode & SYNC_IO_MODE) {
2272 if (port->buf == NULL) {
2273 pr_err("%s: Unexpected Write Done\n", __func__);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002274 spin_unlock_irqrestore(
2275 &(session[session_id].session_lock),
2276 flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302277 return -EINVAL;
2278 }
2279 spin_lock_irqsave(&port->dsp_lock, dsp_flags);
2280 buf_index = asm_token._token.buf_index;
Vignesh Kulothunganb79df2f2019-01-22 10:31:21 -08002281 if (buf_index < 0 || buf_index >= port->max_buf_cnt) {
2282 pr_debug("%s: Invalid buffer index %u\n",
2283 __func__, buf_index);
2284 spin_unlock_irqrestore(&port->dsp_lock,
2285 dsp_flags);
2286 spin_unlock_irqrestore(
2287 &(session[session_id].session_lock),
2288 flags);
2289 return -EINVAL;
2290 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302291 port->buf[buf_index].used = 0;
2292 if (lower_32_bits(port->buf[buf_index].phys) !=
2293 payload[READDONE_IDX_BUFADD_LSW] ||
2294 msm_audio_populate_upper_32_bits(
2295 port->buf[buf_index].phys) !=
2296 payload[READDONE_IDX_BUFADD_MSW]) {
2297 dev_vdbg(ac->dev, "%s: Expected addr %pK\n",
2298 __func__, &port->buf[buf_index].phys);
2299 pr_err("%s: rxedl[0x%x] rxedu[0x%x]\n",
2300 __func__,
2301 payload[READDONE_IDX_BUFADD_LSW],
2302 payload[READDONE_IDX_BUFADD_MSW]);
2303 spin_unlock_irqrestore(&port->dsp_lock,
2304 dsp_flags);
2305 break;
2306 }
2307 port->buf[buf_index].actual_size =
2308 payload[READDONE_IDX_SIZE];
2309 spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
2310 }
2311 break;
2312 }
2313 case ASM_DATA_EVENT_EOS:
2314 case ASM_DATA_EVENT_RENDERED_EOS:
2315 pr_debug("%s: EOS ACK received: rxed session %d opcode 0x%x token 0x%x src %d dest %d\n",
2316 __func__, ac->session,
2317 data->opcode, data->token,
2318 data->src_port, data->dest_port);
2319 break;
2320 case ASM_SESSION_EVENTX_OVERFLOW:
2321 pr_debug("%s: ASM_SESSION_EVENTX_OVERFLOW session %d opcode 0x%x token 0x%x src %d dest %d\n",
2322 __func__, ac->session,
2323 data->opcode, data->token,
2324 data->src_port, data->dest_port);
2325 break;
2326 case ASM_SESSION_EVENT_RX_UNDERFLOW:
2327 pr_debug("%s: ASM_SESSION_EVENT_RX_UNDERFLOW session %d opcode 0x%x token 0x%x src %d dest %d\n",
2328 __func__, ac->session,
2329 data->opcode, data->token,
2330 data->src_port, data->dest_port);
2331 break;
2332 case ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3:
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002333 if (data->payload_size >= 3 * sizeof(uint32_t)) {
2334 dev_vdbg(ac->dev, "%s: ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3, payload[0] = %d, payload[1] = %d, payload[2] = %d\n",
2335 __func__,
2336 payload[0], payload[1], payload[2]);
2337 ac->time_stamp =
2338 (uint64_t)(((uint64_t)payload[2] << 32) |
2339 payload[1]);
2340 } else {
2341 dev_err(ac->dev, "%s: payload size of %x is less than expected.n",
2342 __func__, data->payload_size);
2343 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302344 if (atomic_cmpxchg(&ac->time_flag, 1, 0))
2345 wake_up(&ac->time_wait);
2346 break;
2347 case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
2348 case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY:
2349 pr_debug("%s: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY session %d opcode 0x%x token 0x%x src %d dest %d\n",
2350 __func__, ac->session,
2351 data->opcode, data->token,
2352 data->src_port, data->dest_port);
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002353 if (data->payload_size >= 4 * sizeof(uint32_t))
2354 pr_debug("%s: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, payload[0] = %d, payload[1] = %d, payload[2] = %d, payload[3] = %d\n",
2355 __func__,
2356 payload[0], payload[1], payload[2],
2357 payload[3]);
2358 else
2359 pr_debug("%s: payload size of %x is less than expected.\n",
2360 __func__, data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302361 break;
2362 case ASM_SESSION_CMDRSP_GET_MTMX_STRTR_PARAMS_V2:
2363 q6asm_process_mtmx_get_param_rsp(ac, (void *) payload);
2364 break;
2365 case ASM_STREAM_PP_EVENT:
2366 case ASM_STREAM_CMD_ENCDEC_EVENTS:
2367 case ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE:
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002368 if (data->payload_size >= 2 * sizeof(uint32_t))
2369 pr_debug("%s: ASM_STREAM_EVENT payload[0][0x%x] payload[1][0x%x]",
2370 __func__, payload[0], payload[1]);
2371 else
2372 pr_debug("%s: payload size of %x is less than expected.\n",
2373 __func__, data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302374 i = is_adsp_raise_event(data->opcode);
Meng Wang9730cdd2017-09-26 12:48:31 +08002375 if (i < 0) {
Meng Wangb6afa8c2017-11-30 17:55:05 +08002376 spin_unlock_irqrestore(
2377 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302378 return 0;
Meng Wang9730cdd2017-09-26 12:48:31 +08002379 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302380
2381 /* repack payload for asm_stream_pp_event
2382 * package is composed of event type + size + actual payload
2383 */
2384 payload_size = data->payload_size;
Xiaojun Sangae3d8862018-03-23 08:57:33 +08002385 if (payload_size > UINT_MAX
2386 - sizeof(struct msm_adsp_event_data)) {
2387 pr_err("%s: payload size = %d exceeds limit.\n",
2388 __func__, payload_size);
2389 spin_unlock(&(session[session_id].session_lock));
2390 return -EINVAL;
2391 }
2392
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302393 pp_event_package = kzalloc(payload_size
2394 + sizeof(struct msm_adsp_event_data),
2395 GFP_ATOMIC);
Meng Wang9730cdd2017-09-26 12:48:31 +08002396 if (!pp_event_package) {
Meng Wangb6afa8c2017-11-30 17:55:05 +08002397 spin_unlock_irqrestore(
2398 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302399 return -ENOMEM;
Meng Wang9730cdd2017-09-26 12:48:31 +08002400 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302401
2402 pp_event_package->event_type = i;
2403 pp_event_package->payload_len = payload_size;
2404 memcpy((void *)pp_event_package->payload,
2405 data->payload, payload_size);
2406 ac->cb(data->opcode, data->token,
2407 (void *)pp_event_package, ac->priv);
2408 kfree(pp_event_package);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002409 spin_unlock_irqrestore(
2410 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302411 return 0;
2412 case ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2:
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002413 if (data->payload_size >= 3 * sizeof(uint32_t))
2414 pr_debug("%s: ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2 sesion %d status 0x%x msw %u lsw %u\n",
2415 __func__, ac->session, payload[0], payload[2],
2416 payload[1]);
2417 else
2418 pr_err("%s: payload size of %x is less than expected.\n",
2419 __func__, data->payload_size);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302420 wake_up(&ac->cmd_wait);
2421 break;
2422 case ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2:
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002423 if (data->payload_size >= 3 * sizeof(uint32_t))
2424 pr_debug("%s: ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2 session %d status 0x%x msw %u lsw %u\n",
2425 __func__, ac->session,
2426 payload[0], payload[2],
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302427 payload[1]);
Xiaojun Sang55ee5692019-02-15 16:26:16 +08002428 else
2429 pr_err("%s: payload size of %x is less than expected.\n",
2430 __func__, data->payload_size);
2431 if (data->payload_size >= 2 * sizeof(uint32_t) &&
2432 payload[0] == 0) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302433 atomic_set(&ac->cmd_state, 0);
2434 /* ignore msw, as a delay that large shouldn't happen */
2435 ac->path_delay = payload[1];
2436 } else {
2437 atomic_set(&ac->cmd_state, payload[0]);
2438 ac->path_delay = UINT_MAX;
2439 }
2440 wake_up(&ac->cmd_wait);
2441 break;
2442 }
2443 if (ac->cb)
2444 ac->cb(data->opcode, data->token,
2445 data->payload, ac->priv);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002446 spin_unlock_irqrestore(
2447 &(session[session_id].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302448 return 0;
2449}
2450
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302451/**
2452 * q6asm_is_cpu_buf_avail -
2453 * retrieve next CPU buf avail
2454 *
2455 * @dir: RX or TX direction
2456 * @ac: Audio client handle
2457 * @size: size pointer to be updated with size of buffer
2458 * @index: index pointer to be updated with
2459 * CPU buffer index available
2460 *
2461 * Returns buffer pointer on success or NULL on failure
2462 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302463void *q6asm_is_cpu_buf_avail(int dir, struct audio_client *ac, uint32_t *size,
2464 uint32_t *index)
2465{
2466 void *data;
2467 unsigned char idx;
2468 struct audio_port_data *port;
2469
2470 if (!ac || ((dir != IN) && (dir != OUT))) {
2471 pr_err("%s: ac %pK dir %d\n", __func__, ac, dir);
2472 return NULL;
2473 }
2474
2475 if (ac->io_mode & SYNC_IO_MODE) {
2476 port = &ac->port[dir];
2477
2478 mutex_lock(&port->lock);
2479 idx = port->cpu_buf;
2480 if (port->buf == NULL) {
2481 pr_err("%s: Buffer pointer null\n", __func__);
2482 mutex_unlock(&port->lock);
2483 return NULL;
2484 }
2485 /* dir 0: used = 0 means buf in use
2486 * dir 1: used = 1 means buf in use
2487 */
2488 if (port->buf[idx].used == dir) {
2489 /* To make it more robust, we could loop and get the
2490 * next avail buf, its risky though
2491 */
2492 pr_err("%s: Next buf idx[0x%x] not available, dir[%d]\n",
2493 __func__, idx, dir);
2494 mutex_unlock(&port->lock);
2495 return NULL;
2496 }
2497 *size = port->buf[idx].actual_size;
2498 *index = port->cpu_buf;
2499 data = port->buf[idx].data;
2500 dev_vdbg(ac->dev, "%s: session[%d]index[%d] data[%pK]size[%d]\n",
2501 __func__,
2502 ac->session,
2503 port->cpu_buf,
2504 data, *size);
2505 /* By default increase the cpu_buf cnt
2506 * user accesses this function,increase cpu
2507 * buf(to avoid another api)
2508 */
2509 port->buf[idx].used = dir;
2510 port->cpu_buf = q6asm_get_next_buf(ac, port->cpu_buf,
2511 port->max_buf_cnt);
2512 mutex_unlock(&port->lock);
2513 return data;
2514 }
2515 return NULL;
2516}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302517EXPORT_SYMBOL(q6asm_is_cpu_buf_avail);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302518
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302519/**
2520 * q6asm_cpu_buf_release -
2521 * releases cpu buffer for ASM
2522 *
2523 * @dir: RX or TX direction
2524 * @ac: Audio client handle
2525 *
2526 * Returns 0 on success or error on failure
2527 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302528int q6asm_cpu_buf_release(int dir, struct audio_client *ac)
2529{
2530 struct audio_port_data *port;
2531 int ret = 0;
2532 int idx;
2533
2534 if (!ac || ((dir != IN) && (dir != OUT))) {
2535 pr_err("%s: ac %pK dir %d\n", __func__, ac, dir);
2536 ret = -EINVAL;
2537 goto exit;
2538 }
2539
2540 if (ac->io_mode & SYNC_IO_MODE) {
2541 port = &ac->port[dir];
2542 mutex_lock(&port->lock);
2543 idx = port->cpu_buf;
2544 if (port->cpu_buf == 0) {
2545 port->cpu_buf = port->max_buf_cnt - 1;
2546 } else if (port->cpu_buf < port->max_buf_cnt) {
2547 port->cpu_buf = port->cpu_buf - 1;
2548 } else {
2549 pr_err("%s: buffer index(%d) out of range\n",
2550 __func__, port->cpu_buf);
2551 ret = -EINVAL;
2552 mutex_unlock(&port->lock);
2553 goto exit;
2554 }
2555 port->buf[port->cpu_buf].used = dir ^ 1;
2556 mutex_unlock(&port->lock);
2557 }
2558exit:
2559 return ret;
2560}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302561EXPORT_SYMBOL(q6asm_cpu_buf_release);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302562
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302563/**
2564 * q6asm_is_cpu_buf_avail_nolock -
2565 * retrieve next CPU buf avail without lock acquire
2566 *
2567 * @dir: RX or TX direction
2568 * @ac: Audio client handle
2569 * @size: size pointer to be updated with size of buffer
2570 * @index: index pointer to be updated with
2571 * CPU buffer index available
2572 *
2573 * Returns buffer pointer on success or NULL on failure
2574 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302575void *q6asm_is_cpu_buf_avail_nolock(int dir, struct audio_client *ac,
2576 uint32_t *size, uint32_t *index)
2577{
2578 void *data;
2579 unsigned char idx;
2580 struct audio_port_data *port;
2581
2582 if (!ac || ((dir != IN) && (dir != OUT))) {
2583 pr_err("%s: ac %pK dir %d\n", __func__, ac, dir);
2584 return NULL;
2585 }
2586
2587 port = &ac->port[dir];
2588
2589 idx = port->cpu_buf;
2590 if (port->buf == NULL) {
2591 pr_err("%s: Buffer pointer null\n", __func__);
2592 return NULL;
2593 }
2594 /*
2595 * dir 0: used = 0 means buf in use
2596 * dir 1: used = 1 means buf in use
2597 */
2598 if (port->buf[idx].used == dir) {
2599 /*
2600 * To make it more robust, we could loop and get the
2601 * next avail buf, its risky though
2602 */
2603 pr_err("%s: Next buf idx[0x%x] not available, dir[%d]\n",
2604 __func__, idx, dir);
2605 return NULL;
2606 }
2607 *size = port->buf[idx].actual_size;
2608 *index = port->cpu_buf;
2609 data = port->buf[idx].data;
2610 dev_vdbg(ac->dev, "%s: session[%d]index[%d] data[%pK]size[%d]\n",
2611 __func__, ac->session, port->cpu_buf,
2612 data, *size);
2613 /*
2614 * By default increase the cpu_buf cnt
2615 * user accesses this function,increase cpu
2616 * buf(to avoid another api)
2617 */
2618 port->buf[idx].used = dir;
2619 port->cpu_buf = q6asm_get_next_buf(ac, port->cpu_buf,
2620 port->max_buf_cnt);
2621 return data;
2622}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302623EXPORT_SYMBOL(q6asm_is_cpu_buf_avail_nolock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302624
2625int q6asm_is_dsp_buf_avail(int dir, struct audio_client *ac)
2626{
2627 int ret = -1;
2628 struct audio_port_data *port;
2629 uint32_t idx;
2630
2631 if (!ac || (dir != OUT)) {
2632 pr_err("%s: ac %pK dir %d\n", __func__, ac, dir);
2633 return ret;
2634 }
2635
2636 if (ac->io_mode & SYNC_IO_MODE) {
2637 port = &ac->port[dir];
2638
2639 mutex_lock(&port->lock);
2640 idx = port->dsp_buf;
2641
2642 if (port->buf[idx].used == (dir ^ 1)) {
2643 /* To make it more robust, we could loop and get the
2644 * next avail buf, its risky though
2645 */
2646 pr_err("%s: Next buf idx[0x%x] not available, dir[%d]\n",
2647 __func__, idx, dir);
2648 mutex_unlock(&port->lock);
2649 return ret;
2650 }
2651 dev_vdbg(ac->dev, "%s: session[%d]dsp_buf=%d cpu_buf=%d\n",
2652 __func__,
2653 ac->session, port->dsp_buf, port->cpu_buf);
2654 ret = ((port->dsp_buf != port->cpu_buf) ? 0 : -1);
2655 mutex_unlock(&port->lock);
2656 }
2657 return ret;
2658}
2659
2660static void __q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
2661 uint32_t pkt_size, uint32_t cmd_flg, uint32_t stream_id)
2662{
Vignesh Kulothungan023a5322018-06-21 11:13:29 -07002663 unsigned long flags = 0;
Meng Wangb6afa8c2017-11-30 17:55:05 +08002664
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302665 dev_vdbg(ac->dev, "%s: pkt_size=%d cmd_flg=%d session=%d stream_id=%d\n",
2666 __func__, pkt_size, cmd_flg, ac->session, stream_id);
2667 mutex_lock(&ac->cmd_lock);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002668 spin_lock_irqsave(&(session[ac->session].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302669 if (ac->apr == NULL) {
2670 pr_err("%s: AC APR handle NULL", __func__);
Meng Wangb6afa8c2017-11-30 17:55:05 +08002671 spin_unlock_irqrestore(
2672 &(session[ac->session].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302673 mutex_unlock(&ac->cmd_lock);
2674 return;
2675 }
2676
2677 hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
2678 APR_HDR_LEN(sizeof(struct apr_hdr)),
2679 APR_PKT_VER);
2680 hdr->src_svc = ((struct apr_svc *)ac->apr)->id;
2681 hdr->src_domain = APR_DOMAIN_APPS;
2682 hdr->dest_svc = APR_SVC_ASM;
2683 hdr->dest_domain = APR_DOMAIN_ADSP;
2684 hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id);
2685 hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id);
2686 if (cmd_flg)
2687 q6asm_update_token(&hdr->token,
2688 ac->session,
2689 0, /* Stream ID is NA */
2690 0, /* Buffer index is NA */
2691 0, /* Direction flag is NA */
2692 WAIT_CMD);
2693
2694 hdr->pkt_size = pkt_size;
Meng Wangb6afa8c2017-11-30 17:55:05 +08002695 spin_unlock_irqrestore(
2696 &(session[ac->session].session_lock), flags);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302697 mutex_unlock(&ac->cmd_lock);
2698}
2699
2700static void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
2701 uint32_t pkt_size, uint32_t cmd_flg)
2702{
2703 __q6asm_add_hdr(ac, hdr, pkt_size, cmd_flg, ac->stream_id);
2704}
2705
2706static void q6asm_stream_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
2707 uint32_t pkt_size, uint32_t cmd_flg, int32_t stream_id)
2708{
2709 __q6asm_add_hdr(ac, hdr, pkt_size, cmd_flg, stream_id);
2710}
2711
2712static void __q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
2713 uint32_t pkt_size, uint32_t cmd_flg,
2714 uint32_t stream_id, u8 no_wait_flag)
2715{
2716 dev_vdbg(ac->dev, "%s: pkt_size = %d, cmd_flg = %d, session = %d stream_id=%d\n",
2717 __func__, pkt_size, cmd_flg, ac->session, stream_id);
2718 hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
2719 APR_HDR_LEN(sizeof(struct apr_hdr)),
2720 APR_PKT_VER);
2721 if (ac->apr == NULL) {
2722 pr_err("%s: AC APR is NULL", __func__);
2723 return;
2724 }
2725 hdr->src_svc = ((struct apr_svc *)ac->apr)->id;
2726 hdr->src_domain = APR_DOMAIN_APPS;
2727 hdr->dest_svc = APR_SVC_ASM;
2728 hdr->dest_domain = APR_DOMAIN_ADSP;
2729 hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id);
2730 hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id);
2731 if (cmd_flg) {
2732 q6asm_update_token(&hdr->token,
2733 ac->session,
2734 0, /* Stream ID is NA */
2735 0, /* Buffer index is NA */
2736 0, /* Direction flag is NA */
2737 no_wait_flag);
2738
2739 }
2740 hdr->pkt_size = pkt_size;
2741}
2742
2743static void q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
2744 uint32_t pkt_size, uint32_t cmd_flg)
2745{
2746 __q6asm_add_hdr_async(ac, hdr, pkt_size, cmd_flg,
2747 ac->stream_id, WAIT_CMD);
2748}
2749
2750static void q6asm_stream_add_hdr_async(struct audio_client *ac,
2751 struct apr_hdr *hdr, uint32_t pkt_size,
2752 uint32_t cmd_flg, int32_t stream_id)
2753{
2754 __q6asm_add_hdr_async(ac, hdr, pkt_size, cmd_flg,
2755 stream_id, NO_WAIT_CMD);
2756}
2757
2758static void q6asm_add_hdr_custom_topology(struct audio_client *ac,
2759 struct apr_hdr *hdr,
2760 uint32_t pkt_size)
2761{
2762 pr_debug("%s: pkt_size=%d session=%d\n",
2763 __func__, pkt_size, ac->session);
2764 if (ac->apr == NULL) {
2765 pr_err("%s: AC APR handle NULL\n", __func__);
2766 return;
2767 }
2768
2769 mutex_lock(&ac->cmd_lock);
2770 hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
2771 APR_HDR_LEN(sizeof(struct apr_hdr)),
2772 APR_PKT_VER);
2773 hdr->src_svc = ((struct apr_svc *)ac->apr)->id;
2774 hdr->src_domain = APR_DOMAIN_APPS;
2775 hdr->dest_svc = APR_SVC_ASM;
2776 hdr->dest_domain = APR_DOMAIN_ADSP;
2777 hdr->src_port = ((ac->session << 8) & 0xFF00) | 0x01;
2778 hdr->dest_port = 0;
2779 q6asm_update_token(&hdr->token,
2780 ac->session,
2781 0, /* Stream ID is NA */
2782 0, /* Buffer index is NA */
2783 0, /* Direction flag is NA */
2784 WAIT_CMD);
2785 hdr->pkt_size = pkt_size;
2786 mutex_unlock(&ac->cmd_lock);
2787}
2788
2789static void q6asm_add_mmaphdr(struct audio_client *ac, struct apr_hdr *hdr,
2790 u32 pkt_size, int dir)
2791{
2792 pr_debug("%s: pkt size=%d\n",
2793 __func__, pkt_size);
2794 hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
2795 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
2796 hdr->src_port = 0;
2797 hdr->dest_port = 0;
2798 q6asm_update_token(&hdr->token,
2799 ac->session,
2800 0, /* Stream ID is NA */
2801 0, /* Buffer index is NA */
2802 dir,
2803 WAIT_CMD);
2804 hdr->pkt_size = pkt_size;
2805}
2806
2807static int __q6asm_open_read(struct audio_client *ac,
2808 uint32_t format, uint16_t bits_per_sample,
2809 uint32_t pcm_format_block_ver,
2810 bool ts_mode)
2811{
2812 int rc = 0x00;
2813 struct asm_stream_cmd_open_read_v3 open;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07002814 struct q6asm_cal_info cal_info;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302815
2816 config_debug_fs_reset_index();
2817
2818 if (ac == NULL) {
2819 pr_err("%s: APR handle NULL\n", __func__);
2820 return -EINVAL;
2821 }
2822 if (ac->apr == NULL) {
2823 pr_err("%s: AC APR handle NULL\n", __func__);
2824 return -EINVAL;
2825 }
2826 pr_debug("%s: session[%d]\n", __func__, ac->session);
2827
2828 q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
2829 atomic_set(&ac->cmd_state, -1);
2830 open.hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V3;
2831 /* Stream prio : High, provide meta info with encoded frames */
2832 open.src_endpointype = ASM_END_POINT_DEVICE_MATRIX;
2833
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07002834 rc = q6asm_get_asm_topology_apptype(&cal_info);
2835 open.preprocopo_id = cal_info.topology_id;
2836
2837
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302838 open.bits_per_sample = bits_per_sample;
2839 open.mode_flags = 0x0;
2840
2841 ac->topology = open.preprocopo_id;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07002842 ac->app_type = cal_info.app_type;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302843 if (ac->perf_mode == LOW_LATENCY_PCM_MODE) {
2844 open.mode_flags |= ASM_LOW_LATENCY_TX_STREAM_SESSION <<
2845 ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
2846 } else {
2847 open.mode_flags |= ASM_LEGACY_STREAM_SESSION <<
2848 ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
2849 }
2850
2851 switch (format) {
2852 case FORMAT_LINEAR_PCM:
2853 open.mode_flags |= 0x00;
2854 open.enc_cfg_id = q6asm_get_pcm_format_id(pcm_format_block_ver);
2855 if (ts_mode)
2856 open.mode_flags |= ABSOLUTE_TIMESTAMP_ENABLE;
2857 break;
2858 case FORMAT_MPEG4_AAC:
2859 open.mode_flags |= BUFFER_META_ENABLE;
2860 open.enc_cfg_id = ASM_MEDIA_FMT_AAC_V2;
2861 break;
2862 case FORMAT_G711_ALAW_FS:
2863 open.mode_flags |= BUFFER_META_ENABLE;
2864 open.enc_cfg_id = ASM_MEDIA_FMT_G711_ALAW_FS;
2865 break;
2866 case FORMAT_G711_MLAW_FS:
2867 open.mode_flags |= BUFFER_META_ENABLE;
2868 open.enc_cfg_id = ASM_MEDIA_FMT_G711_MLAW_FS;
2869 break;
2870 case FORMAT_V13K:
2871 open.mode_flags |= BUFFER_META_ENABLE;
2872 open.enc_cfg_id = ASM_MEDIA_FMT_V13K_FS;
2873 break;
2874 case FORMAT_EVRC:
2875 open.mode_flags |= BUFFER_META_ENABLE;
2876 open.enc_cfg_id = ASM_MEDIA_FMT_EVRC_FS;
2877 break;
2878 case FORMAT_AMRNB:
2879 open.mode_flags |= BUFFER_META_ENABLE;
2880 open.enc_cfg_id = ASM_MEDIA_FMT_AMRNB_FS;
2881 break;
2882 case FORMAT_AMRWB:
2883 open.mode_flags |= BUFFER_META_ENABLE;
2884 open.enc_cfg_id = ASM_MEDIA_FMT_AMRWB_FS;
2885 break;
2886 default:
2887 pr_err("%s: Invalid format 0x%x\n",
2888 __func__, format);
2889 rc = -EINVAL;
2890 goto fail_cmd;
2891 }
2892 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
2893 if (rc < 0) {
2894 pr_err("%s: open failed op[0x%x]rc[%d]\n",
2895 __func__, open.hdr.opcode, rc);
2896 rc = -EINVAL;
2897 goto fail_cmd;
2898 }
2899 rc = wait_event_timeout(ac->cmd_wait,
2900 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
2901 if (!rc) {
2902 pr_err("%s: timeout. waited for open read\n",
2903 __func__);
2904 rc = -ETIMEDOUT;
2905 goto fail_cmd;
2906 }
2907 if (atomic_read(&ac->cmd_state) > 0) {
2908 pr_err("%s: DSP returned error[%s]\n",
2909 __func__, adsp_err_get_err_str(
2910 atomic_read(&ac->cmd_state)));
2911 rc = adsp_err_get_lnx_err_code(
2912 atomic_read(&ac->cmd_state));
2913 goto fail_cmd;
2914 }
2915
2916 ac->io_mode |= TUN_READ_IO_MODE;
2917
2918 return 0;
2919fail_cmd:
2920 return rc;
2921}
2922
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302923/**
2924 * q6asm_open_read -
2925 * command to open ASM in read mode
2926 *
2927 * @ac: Audio client handle
2928 * @format: capture format for ASM
2929 *
2930 * Returns 0 on success or error on failure
2931 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302932int q6asm_open_read(struct audio_client *ac,
2933 uint32_t format)
2934{
2935 return __q6asm_open_read(ac, format, 16,
2936 PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/,
2937 false/*ts_mode*/);
2938}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302939EXPORT_SYMBOL(q6asm_open_read);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302940
2941int q6asm_open_read_v2(struct audio_client *ac, uint32_t format,
2942 uint16_t bits_per_sample)
2943{
2944 return __q6asm_open_read(ac, format, bits_per_sample,
2945 PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/,
2946 false/*ts_mode*/);
2947}
2948
2949/*
2950 * asm_open_read_v3 - Opens audio capture session
2951 *
2952 * @ac: Client session handle
2953 * @format: encoder format
2954 * @bits_per_sample: bit width of capture session
2955 */
2956int q6asm_open_read_v3(struct audio_client *ac, uint32_t format,
2957 uint16_t bits_per_sample)
2958{
2959 return __q6asm_open_read(ac, format, bits_per_sample,
2960 PCM_MEDIA_FORMAT_V3/*media fmt block ver*/,
2961 false/*ts_mode*/);
2962}
2963EXPORT_SYMBOL(q6asm_open_read_v3);
2964
2965/*
2966 * asm_open_read_v4 - Opens audio capture session
2967 *
2968 * @ac: Client session handle
2969 * @format: encoder format
2970 * @bits_per_sample: bit width of capture session
2971 * @ts_mode: timestamp mode
2972 */
2973int q6asm_open_read_v4(struct audio_client *ac, uint32_t format,
2974 uint16_t bits_per_sample, bool ts_mode)
2975{
2976 return __q6asm_open_read(ac, format, bits_per_sample,
2977 PCM_MEDIA_FORMAT_V4 /*media fmt block ver*/,
2978 ts_mode);
2979}
2980EXPORT_SYMBOL(q6asm_open_read_v4);
2981
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05302982/**
2983 * q6asm_open_write_compressed -
2984 * command to open ASM in compressed write mode
2985 *
2986 * @ac: Audio client handle
2987 * @format: playback format for ASM
2988 * @passthrough_flag: flag to indicate passthrough option
2989 *
2990 * Returns 0 on success or error on failure
2991 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302992int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format,
2993 uint32_t passthrough_flag)
2994{
2995 int rc = 0;
2996 struct asm_stream_cmd_open_write_compressed open;
2997
2998 if (ac == NULL) {
2999 pr_err("%s: ac[%pK] NULL\n", __func__, ac);
3000 rc = -EINVAL;
3001 goto fail_cmd;
3002 }
3003
3004 if (ac->apr == NULL) {
3005 pr_err("%s: APR handle[%pK] NULL\n", __func__, ac->apr);
3006 rc = -EINVAL;
3007 goto fail_cmd;
3008 }
3009 pr_debug("%s: session[%d] wr_format[0x%x]", __func__, ac->session,
3010 format);
3011
3012 q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
3013 open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED;
3014 atomic_set(&ac->cmd_state, -1);
3015
3016 switch (format) {
3017 case FORMAT_AC3:
3018 open.fmt_id = ASM_MEDIA_FMT_AC3;
3019 break;
3020 case FORMAT_EAC3:
3021 open.fmt_id = ASM_MEDIA_FMT_EAC3;
3022 break;
3023 case FORMAT_DTS:
3024 open.fmt_id = ASM_MEDIA_FMT_DTS;
3025 break;
3026 case FORMAT_DSD:
3027 open.fmt_id = ASM_MEDIA_FMT_DSD;
3028 break;
3029 case FORMAT_GEN_COMPR:
3030 open.fmt_id = ASM_MEDIA_FMT_GENERIC_COMPRESSED;
3031 break;
3032 case FORMAT_TRUEHD:
3033 open.fmt_id = ASM_MEDIA_FMT_TRUEHD;
3034 break;
3035 case FORMAT_IEC61937:
3036 open.fmt_id = ASM_MEDIA_FMT_IEC;
3037 break;
3038 default:
3039 pr_err("%s: Invalid format[%d]\n", __func__, format);
3040 rc = -EINVAL;
3041 goto fail_cmd;
3042 }
3043 /* Below flag indicates the DSP that Compressed audio input
3044 * stream is not IEC 61937 or IEC 60958 packetizied
3045 */
3046 if (passthrough_flag == COMPRESSED_PASSTHROUGH ||
3047 passthrough_flag == COMPRESSED_PASSTHROUGH_DSD ||
3048 passthrough_flag == COMPRESSED_PASSTHROUGH_GEN) {
3049 open.flags = 0x0;
3050 pr_debug("%s: Flag 0 COMPRESSED_PASSTHROUGH\n", __func__);
3051 } else if (passthrough_flag == COMPRESSED_PASSTHROUGH_CONVERT) {
3052 open.flags = 0x8;
3053 pr_debug("%s: Flag 8 - COMPRESSED_PASSTHROUGH_CONVERT\n",
3054 __func__);
3055 } else if (passthrough_flag == COMPRESSED_PASSTHROUGH_IEC61937) {
3056 open.flags = 0x1;
3057 pr_debug("%s: Flag 1 - COMPRESSED_PASSTHROUGH_IEC61937\n",
3058 __func__);
3059 } else {
3060 pr_err("%s: Invalid passthrough type[%d]\n",
3061 __func__, passthrough_flag);
3062 rc = -EINVAL;
3063 goto fail_cmd;
3064 }
3065 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
3066 if (rc < 0) {
3067 pr_err("%s: open failed op[0x%x]rc[%d]\n",
3068 __func__, open.hdr.opcode, rc);
3069 rc = -EINVAL;
3070 goto fail_cmd;
3071 }
3072 rc = wait_event_timeout(ac->cmd_wait,
3073 (atomic_read(&ac->cmd_state) >= 0), 1*HZ);
3074 if (!rc) {
3075 pr_err("%s: timeout. waited for OPEN_WRITE_COMPR rc[%d]\n",
3076 __func__, rc);
3077 rc = -ETIMEDOUT;
3078 goto fail_cmd;
3079 }
3080
3081 if (atomic_read(&ac->cmd_state) > 0) {
3082 pr_err("%s: DSP returned error[%s]\n",
3083 __func__, adsp_err_get_err_str(
3084 atomic_read(&ac->cmd_state)));
3085 rc = adsp_err_get_lnx_err_code(
3086 atomic_read(&ac->cmd_state));
3087 goto fail_cmd;
3088 }
3089
3090 return 0;
3091
3092fail_cmd:
3093 return rc;
3094}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303095EXPORT_SYMBOL(q6asm_open_write_compressed);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303096
3097static int __q6asm_open_write(struct audio_client *ac, uint32_t format,
3098 uint16_t bits_per_sample, uint32_t stream_id,
3099 bool is_gapless_mode,
3100 uint32_t pcm_format_block_ver)
3101{
3102 int rc = 0x00;
3103 struct asm_stream_cmd_open_write_v3 open;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003104 struct q6asm_cal_info cal_info;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303105
3106 if (ac == NULL) {
3107 pr_err("%s: APR handle NULL\n", __func__);
3108 return -EINVAL;
3109 }
3110 if (ac->apr == NULL) {
3111 pr_err("%s: AC APR handle NULL\n", __func__);
3112 return -EINVAL;
3113 }
3114
3115 dev_vdbg(ac->dev, "%s: session[%d] wr_format[0x%x]\n",
3116 __func__, ac->session, format);
3117
3118 q6asm_stream_add_hdr(ac, &open.hdr, sizeof(open), TRUE, stream_id);
3119 atomic_set(&ac->cmd_state, -1);
3120 /*
3121 * Updated the token field with stream/session for compressed playback
3122 * Platform driver must know the the stream with which the command is
3123 * associated
3124 */
3125 if (ac->io_mode & COMPRESSED_STREAM_IO)
3126 q6asm_update_token(&open.hdr.token,
3127 ac->session,
3128 stream_id,
3129 0, /* Buffer index is NA */
3130 0, /* Direction flag is NA */
3131 WAIT_CMD);
3132
3133 dev_vdbg(ac->dev, "%s: token = 0x%x, stream_id %d, session 0x%x\n",
3134 __func__, open.hdr.token, stream_id, ac->session);
3135 open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
3136 open.mode_flags = 0x00;
3137 if (ac->perf_mode == ULL_POST_PROCESSING_PCM_MODE)
3138 open.mode_flags |= ASM_ULL_POST_PROCESSING_STREAM_SESSION;
3139 else if (ac->perf_mode == ULTRA_LOW_LATENCY_PCM_MODE)
3140 open.mode_flags |= ASM_ULTRA_LOW_LATENCY_STREAM_SESSION;
3141 else if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
3142 open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION;
3143 else {
3144 open.mode_flags |= ASM_LEGACY_STREAM_SESSION;
3145 if (is_gapless_mode)
3146 open.mode_flags |= 1 << ASM_SHIFT_GAPLESS_MODE_FLAG;
3147 }
3148
3149 /* source endpoint : matrix */
3150 open.sink_endpointype = ASM_END_POINT_DEVICE_MATRIX;
3151 open.bits_per_sample = bits_per_sample;
3152
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003153 rc = q6asm_get_asm_topology_apptype(&cal_info);
3154 open.postprocopo_id = cal_info.topology_id;
3155
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303156 if (ac->perf_mode != LEGACY_PCM_MODE)
3157 open.postprocopo_id = ASM_STREAM_POSTPROCOPO_ID_NONE;
3158
3159 pr_debug("%s: perf_mode %d asm_topology 0x%x bps %d\n", __func__,
3160 ac->perf_mode, open.postprocopo_id, open.bits_per_sample);
3161
3162 /*
3163 * For Gapless playback it will use the same session for next stream,
3164 * So use the same topology
3165 */
3166 if (!ac->topology) {
3167 ac->topology = open.postprocopo_id;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003168 ac->app_type = cal_info.app_type;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303169 }
3170 switch (format) {
3171 case FORMAT_LINEAR_PCM:
3172 open.dec_fmt_id = q6asm_get_pcm_format_id(pcm_format_block_ver);
3173 break;
3174 case FORMAT_MPEG4_AAC:
3175 open.dec_fmt_id = ASM_MEDIA_FMT_AAC_V2;
3176 break;
3177 case FORMAT_MPEG4_MULTI_AAC:
3178 open.dec_fmt_id = ASM_MEDIA_FMT_AAC_V2;
3179 break;
3180 case FORMAT_WMA_V9:
3181 open.dec_fmt_id = ASM_MEDIA_FMT_WMA_V9_V2;
3182 break;
3183 case FORMAT_WMA_V10PRO:
3184 open.dec_fmt_id = ASM_MEDIA_FMT_WMA_V10PRO_V2;
3185 break;
3186 case FORMAT_MP3:
3187 open.dec_fmt_id = ASM_MEDIA_FMT_MP3;
3188 break;
3189 case FORMAT_AC3:
3190 open.dec_fmt_id = ASM_MEDIA_FMT_AC3;
3191 break;
3192 case FORMAT_EAC3:
3193 open.dec_fmt_id = ASM_MEDIA_FMT_EAC3;
3194 break;
3195 case FORMAT_MP2:
3196 open.dec_fmt_id = ASM_MEDIA_FMT_MP2;
3197 break;
3198 case FORMAT_FLAC:
3199 open.dec_fmt_id = ASM_MEDIA_FMT_FLAC;
3200 break;
3201 case FORMAT_ALAC:
3202 open.dec_fmt_id = ASM_MEDIA_FMT_ALAC;
3203 break;
3204 case FORMAT_VORBIS:
3205 open.dec_fmt_id = ASM_MEDIA_FMT_VORBIS;
3206 break;
3207 case FORMAT_APE:
3208 open.dec_fmt_id = ASM_MEDIA_FMT_APE;
3209 break;
3210 case FORMAT_DSD:
3211 open.dec_fmt_id = ASM_MEDIA_FMT_DSD;
3212 break;
3213 case FORMAT_APTX:
3214 open.dec_fmt_id = ASM_MEDIA_FMT_APTX;
3215 break;
3216 case FORMAT_GEN_COMPR:
3217 open.dec_fmt_id = ASM_MEDIA_FMT_GENERIC_COMPRESSED;
3218 break;
3219 default:
3220 pr_err("%s: Invalid format 0x%x\n", __func__, format);
3221 rc = -EINVAL;
3222 goto fail_cmd;
3223 }
3224 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
3225 if (rc < 0) {
3226 pr_err("%s: open failed op[0x%x]rc[%d]\n",
3227 __func__, open.hdr.opcode, rc);
3228 rc = -EINVAL;
3229 goto fail_cmd;
3230 }
3231 rc = wait_event_timeout(ac->cmd_wait,
3232 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
3233 if (!rc) {
3234 pr_err("%s: timeout. waited for open write\n", __func__);
3235 rc = -ETIMEDOUT;
3236 goto fail_cmd;
3237 }
3238 if (atomic_read(&ac->cmd_state) > 0) {
3239 pr_err("%s: DSP returned error[%s]\n",
3240 __func__, adsp_err_get_err_str(
3241 atomic_read(&ac->cmd_state)));
3242 rc = adsp_err_get_lnx_err_code(
3243 atomic_read(&ac->cmd_state));
3244 goto fail_cmd;
3245 }
3246 ac->io_mode |= TUN_WRITE_IO_MODE;
3247
3248 return 0;
3249fail_cmd:
3250 return rc;
3251}
3252
3253int q6asm_open_write(struct audio_client *ac, uint32_t format)
3254{
3255 return __q6asm_open_write(ac, format, 16, ac->stream_id,
3256 false /*gapless*/,
3257 PCM_MEDIA_FORMAT_V2 /*pcm_format_block_ver*/);
3258}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303259EXPORT_SYMBOL(q6asm_open_write);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303260
3261int q6asm_open_write_v2(struct audio_client *ac, uint32_t format,
3262 uint16_t bits_per_sample)
3263{
3264 return __q6asm_open_write(ac, format, bits_per_sample,
3265 ac->stream_id, false /*gapless*/,
3266 PCM_MEDIA_FORMAT_V2 /*pcm_format_block_ver*/);
3267}
3268
3269/*
3270 * q6asm_open_write_v3 - Opens audio playback session
3271 *
3272 * @ac: Client session handle
3273 * @format: decoder format
3274 * @bits_per_sample: bit width of playback session
3275 */
3276int q6asm_open_write_v3(struct audio_client *ac, uint32_t format,
3277 uint16_t bits_per_sample)
3278{
3279 return __q6asm_open_write(ac, format, bits_per_sample,
3280 ac->stream_id, false /*gapless*/,
3281 PCM_MEDIA_FORMAT_V3 /*pcm_format_block_ver*/);
3282}
3283EXPORT_SYMBOL(q6asm_open_write_v3);
3284
3285/*
3286 * q6asm_open_write_v4 - Opens audio playback session
3287 *
3288 * @ac: Client session handle
3289 * @format: decoder format
3290 * @bits_per_sample: bit width of playback session
3291 */
3292int q6asm_open_write_v4(struct audio_client *ac, uint32_t format,
3293 uint16_t bits_per_sample)
3294{
3295 return __q6asm_open_write(ac, format, bits_per_sample,
3296 ac->stream_id, false /*gapless*/,
3297 PCM_MEDIA_FORMAT_V4 /*pcm_format_block_ver*/);
3298}
3299EXPORT_SYMBOL(q6asm_open_write_v4);
3300
3301int q6asm_stream_open_write_v2(struct audio_client *ac, uint32_t format,
3302 uint16_t bits_per_sample, int32_t stream_id,
3303 bool is_gapless_mode)
3304{
3305 return __q6asm_open_write(ac, format, bits_per_sample,
3306 stream_id, is_gapless_mode,
3307 PCM_MEDIA_FORMAT_V2 /*pcm_format_block_ver*/);
3308}
3309
3310/*
3311 * q6asm_stream_open_write_v3 - Creates audio stream for playback
3312 *
3313 * @ac: Client session handle
3314 * @format: asm playback format
3315 * @bits_per_sample: bit width of requested stream
3316 * @stream_id: stream id of stream to be associated with this session
3317 * @is_gapless_mode: true if gapless mode needs to be enabled
3318 */
3319int q6asm_stream_open_write_v3(struct audio_client *ac, uint32_t format,
3320 uint16_t bits_per_sample, int32_t stream_id,
3321 bool is_gapless_mode)
3322{
3323 return __q6asm_open_write(ac, format, bits_per_sample,
3324 stream_id, is_gapless_mode,
3325 PCM_MEDIA_FORMAT_V3 /*pcm_format_block_ver*/);
3326}
3327EXPORT_SYMBOL(q6asm_stream_open_write_v3);
3328
3329/*
3330 * q6asm_stream_open_write_v4 - Creates audio stream for playback
3331 *
3332 * @ac: Client session handle
3333 * @format: asm playback format
3334 * @bits_per_sample: bit width of requested stream
3335 * @stream_id: stream id of stream to be associated with this session
3336 * @is_gapless_mode: true if gapless mode needs to be enabled
3337 */
3338int q6asm_stream_open_write_v4(struct audio_client *ac, uint32_t format,
3339 uint16_t bits_per_sample, int32_t stream_id,
3340 bool is_gapless_mode)
3341{
3342 return __q6asm_open_write(ac, format, bits_per_sample,
3343 stream_id, is_gapless_mode,
3344 PCM_MEDIA_FORMAT_V4 /*pcm_format_block_ver*/);
3345}
3346EXPORT_SYMBOL(q6asm_stream_open_write_v4);
3347
3348static int __q6asm_open_read_write(struct audio_client *ac, uint32_t rd_format,
3349 uint32_t wr_format, bool is_meta_data_mode,
3350 uint32_t bits_per_sample,
3351 bool overwrite_topology, int topology)
3352{
3353 int rc = 0x00;
3354 struct asm_stream_cmd_open_readwrite_v2 open;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003355 struct q6asm_cal_info cal_info;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303356
3357 if (ac == NULL) {
3358 pr_err("%s: APR handle NULL\n", __func__);
3359 return -EINVAL;
3360 }
3361 if (ac->apr == NULL) {
3362 pr_err("%s: AC APR handle NULL\n", __func__);
3363 return -EINVAL;
3364 }
3365 pr_debug("%s: session[%d]\n", __func__, ac->session);
3366 pr_debug("%s: wr_format[0x%x]rd_format[0x%x]\n",
3367 __func__, wr_format, rd_format);
3368
3369 ac->io_mode |= NT_MODE;
3370 q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
3371 atomic_set(&ac->cmd_state, -1);
3372 open.hdr.opcode = ASM_STREAM_CMD_OPEN_READWRITE_V2;
3373
3374 open.mode_flags = is_meta_data_mode ? BUFFER_META_ENABLE : 0;
3375 open.bits_per_sample = bits_per_sample;
3376 /* source endpoint : matrix */
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003377 rc = q6asm_get_asm_topology_apptype(&cal_info);
3378 open.postprocopo_id = cal_info.topology_id;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303379
3380 open.postprocopo_id = overwrite_topology ?
3381 topology : open.postprocopo_id;
3382 ac->topology = open.postprocopo_id;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003383 ac->app_type = cal_info.app_type;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303384
3385
3386 switch (wr_format) {
3387 case FORMAT_LINEAR_PCM:
3388 case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
3389 open.dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
3390 break;
3391 case FORMAT_MPEG4_AAC:
3392 open.dec_fmt_id = ASM_MEDIA_FMT_AAC_V2;
3393 break;
3394 case FORMAT_MPEG4_MULTI_AAC:
3395 open.dec_fmt_id = ASM_MEDIA_FMT_AAC_V2;
3396 break;
3397 case FORMAT_WMA_V9:
3398 open.dec_fmt_id = ASM_MEDIA_FMT_WMA_V9_V2;
3399 break;
3400 case FORMAT_WMA_V10PRO:
3401 open.dec_fmt_id = ASM_MEDIA_FMT_WMA_V10PRO_V2;
3402 break;
3403 case FORMAT_AMRNB:
3404 open.dec_fmt_id = ASM_MEDIA_FMT_AMRNB_FS;
3405 break;
3406 case FORMAT_AMRWB:
3407 open.dec_fmt_id = ASM_MEDIA_FMT_AMRWB_FS;
3408 break;
3409 case FORMAT_AMR_WB_PLUS:
3410 open.dec_fmt_id = ASM_MEDIA_FMT_AMR_WB_PLUS_V2;
3411 break;
3412 case FORMAT_V13K:
3413 open.dec_fmt_id = ASM_MEDIA_FMT_V13K_FS;
3414 break;
3415 case FORMAT_EVRC:
3416 open.dec_fmt_id = ASM_MEDIA_FMT_EVRC_FS;
3417 break;
3418 case FORMAT_EVRCB:
3419 open.dec_fmt_id = ASM_MEDIA_FMT_EVRCB_FS;
3420 break;
3421 case FORMAT_EVRCWB:
3422 open.dec_fmt_id = ASM_MEDIA_FMT_EVRCWB_FS;
3423 break;
3424 case FORMAT_MP3:
3425 open.dec_fmt_id = ASM_MEDIA_FMT_MP3;
3426 break;
3427 case FORMAT_ALAC:
3428 open.dec_fmt_id = ASM_MEDIA_FMT_ALAC;
3429 break;
3430 case FORMAT_APE:
3431 open.dec_fmt_id = ASM_MEDIA_FMT_APE;
3432 break;
3433 case FORMAT_DSD:
3434 open.dec_fmt_id = ASM_MEDIA_FMT_DSD;
3435 break;
3436 case FORMAT_G711_ALAW_FS:
3437 open.dec_fmt_id = ASM_MEDIA_FMT_G711_ALAW_FS;
3438 break;
3439 case FORMAT_G711_MLAW_FS:
3440 open.dec_fmt_id = ASM_MEDIA_FMT_G711_MLAW_FS;
3441 break;
3442 default:
3443 pr_err("%s: Invalid format 0x%x\n",
3444 __func__, wr_format);
3445 rc = -EINVAL;
3446 goto fail_cmd;
3447 }
3448
3449 switch (rd_format) {
3450 case FORMAT_LINEAR_PCM:
3451 case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
3452 open.enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
3453 break;
3454 case FORMAT_MPEG4_AAC:
3455 open.enc_cfg_id = ASM_MEDIA_FMT_AAC_V2;
3456 break;
3457 case FORMAT_G711_ALAW_FS:
3458 open.enc_cfg_id = ASM_MEDIA_FMT_G711_ALAW_FS;
3459 break;
3460 case FORMAT_G711_MLAW_FS:
3461 open.enc_cfg_id = ASM_MEDIA_FMT_G711_MLAW_FS;
3462 break;
3463 case FORMAT_V13K:
3464 open.enc_cfg_id = ASM_MEDIA_FMT_V13K_FS;
3465 break;
3466 case FORMAT_EVRC:
3467 open.enc_cfg_id = ASM_MEDIA_FMT_EVRC_FS;
3468 break;
3469 case FORMAT_AMRNB:
3470 open.enc_cfg_id = ASM_MEDIA_FMT_AMRNB_FS;
3471 break;
3472 case FORMAT_AMRWB:
3473 open.enc_cfg_id = ASM_MEDIA_FMT_AMRWB_FS;
3474 break;
3475 case FORMAT_ALAC:
3476 open.enc_cfg_id = ASM_MEDIA_FMT_ALAC;
3477 break;
3478 case FORMAT_APE:
3479 open.enc_cfg_id = ASM_MEDIA_FMT_APE;
3480 break;
3481 default:
3482 pr_err("%s: Invalid format 0x%x\n",
3483 __func__, rd_format);
3484 rc = -EINVAL;
3485 goto fail_cmd;
3486 }
3487 dev_vdbg(ac->dev, "%s: rdformat[0x%x]wrformat[0x%x]\n", __func__,
3488 open.enc_cfg_id, open.dec_fmt_id);
3489
3490 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
3491 if (rc < 0) {
3492 pr_err("%s: open failed op[0x%x]rc[%d]\n",
3493 __func__, open.hdr.opcode, rc);
3494 rc = -EINVAL;
3495 goto fail_cmd;
3496 }
3497 rc = wait_event_timeout(ac->cmd_wait,
3498 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
3499 if (!rc) {
3500 pr_err("%s: timeout. waited for open read-write\n",
3501 __func__);
3502 rc = -ETIMEDOUT;
3503 goto fail_cmd;
3504 }
3505 if (atomic_read(&ac->cmd_state) > 0) {
3506 pr_err("%s: DSP returned error[%s]\n",
3507 __func__, adsp_err_get_err_str(
3508 atomic_read(&ac->cmd_state)));
3509 rc = adsp_err_get_lnx_err_code(
3510 atomic_read(&ac->cmd_state));
3511 goto fail_cmd;
3512 }
3513
3514 return 0;
3515fail_cmd:
3516 return rc;
3517}
3518
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303519/**
3520 * q6asm_open_read_write -
3521 * command to open ASM in read/write mode
3522 *
3523 * @ac: Audio client handle
3524 * @rd_format: capture format for ASM
3525 * @wr_format: playback format for ASM
3526 *
3527 * Returns 0 on success or error on failure
3528 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303529int q6asm_open_read_write(struct audio_client *ac, uint32_t rd_format,
3530 uint32_t wr_format)
3531{
3532 return __q6asm_open_read_write(ac, rd_format, wr_format,
3533 true/*meta data mode*/,
3534 16 /*bits_per_sample*/,
3535 false /*overwrite_topology*/, 0);
3536}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303537EXPORT_SYMBOL(q6asm_open_read_write);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303538
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303539/**
3540 * q6asm_open_read_write_v2 -
3541 * command to open ASM in bi-directional read/write mode
3542 *
3543 * @ac: Audio client handle
3544 * @rd_format: capture format for ASM
3545 * @wr_format: playback format for ASM
3546 * @is_meta_data_mode: mode to indicate if meta data present
3547 * @bits_per_sample: number of bits per sample
3548 * @overwrite_topology: topology to be overwritten flag
3549 * @topology: Topology for ASM
3550 *
3551 * Returns 0 on success or error on failure
3552 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303553int q6asm_open_read_write_v2(struct audio_client *ac, uint32_t rd_format,
3554 uint32_t wr_format, bool is_meta_data_mode,
3555 uint32_t bits_per_sample, bool overwrite_topology,
3556 int topology)
3557{
3558 return __q6asm_open_read_write(ac, rd_format, wr_format,
3559 is_meta_data_mode, bits_per_sample,
3560 overwrite_topology, topology);
3561}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303562EXPORT_SYMBOL(q6asm_open_read_write_v2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303563
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303564/**
3565 * q6asm_open_loopback_v2 -
3566 * command to open ASM in loopback mode
3567 *
3568 * @ac: Audio client handle
3569 * @bits_per_sample: number of bits per sample
3570 *
3571 * Returns 0 on success or error on failure
3572 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303573int q6asm_open_loopback_v2(struct audio_client *ac, uint16_t bits_per_sample)
3574{
3575 int rc = 0x00;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003576 struct q6asm_cal_info cal_info;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303577
3578 if (ac == NULL) {
3579 pr_err("%s: APR handle NULL\n", __func__);
3580 return -EINVAL;
3581 }
3582 if (ac->apr == NULL) {
3583 pr_err("%s: AC APR handle NULL\n", __func__);
3584 return -EINVAL;
3585 }
3586 pr_debug("%s: session[%d]\n", __func__, ac->session);
3587
3588 if (ac->perf_mode == LOW_LATENCY_PCM_MODE) {
3589 struct asm_stream_cmd_open_transcode_loopback_t open;
3590
3591 q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
3592 atomic_set(&ac->cmd_state, -1);
3593 open.hdr.opcode = ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK;
3594
3595 open.mode_flags = 0;
3596 open.src_endpoint_type = 0;
3597 open.sink_endpoint_type = 0;
3598 open.src_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
3599 open.sink_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
3600 /* source endpoint : matrix */
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003601 rc = q6asm_get_asm_topology_apptype(&cal_info);
3602 open.audproc_topo_id = cal_info.topology_id;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303603
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003604 ac->app_type = cal_info.app_type;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303605 if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
3606 open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION;
3607 else
3608 open.mode_flags |= ASM_LEGACY_STREAM_SESSION;
3609 ac->topology = open.audproc_topo_id;
3610 open.bits_per_sample = bits_per_sample;
3611 open.reserved = 0;
3612 pr_debug("%s: opening a transcode_loopback with mode_flags =[%d] session[%d]\n",
3613 __func__, open.mode_flags, ac->session);
3614
3615 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
3616 if (rc < 0) {
3617 pr_err("%s: open failed op[0x%x]rc[%d]\n",
3618 __func__, open.hdr.opcode, rc);
3619 rc = -EINVAL;
3620 goto fail_cmd;
3621 }
3622 } else {/*if(ac->perf_mode == LEGACY_PCM_MODE)*/
3623 struct asm_stream_cmd_open_loopback_v2 open;
3624
3625 q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
3626 atomic_set(&ac->cmd_state, -1);
3627 open.hdr.opcode = ASM_STREAM_CMD_OPEN_LOOPBACK_V2;
3628
3629 open.mode_flags = 0;
3630 open.src_endpointype = 0;
3631 open.sink_endpointype = 0;
3632 /* source endpoint : matrix */
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003633 rc = q6asm_get_asm_topology_apptype(&cal_info);
3634 open.postprocopo_id = cal_info.topology_id;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303635
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003636 ac->app_type = cal_info.app_type;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303637 ac->topology = open.postprocopo_id;
3638 open.bits_per_sample = bits_per_sample;
3639 open.reserved = 0;
3640 pr_debug("%s: opening a loopback_v2 with mode_flags =[%d] session[%d]\n",
3641 __func__, open.mode_flags, ac->session);
3642
3643 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
3644 if (rc < 0) {
3645 pr_err("%s: open failed op[0x%x]rc[%d]\n",
3646 __func__, open.hdr.opcode, rc);
3647 rc = -EINVAL;
3648 goto fail_cmd;
3649 }
3650 }
3651 rc = wait_event_timeout(ac->cmd_wait,
3652 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
3653 if (!rc) {
3654 pr_err("%s: timeout. waited for open_loopback\n",
3655 __func__);
3656 rc = -ETIMEDOUT;
3657 goto fail_cmd;
3658 }
3659 if (atomic_read(&ac->cmd_state) > 0) {
3660 pr_err("%s: DSP returned error[%s]\n",
3661 __func__, adsp_err_get_err_str(
3662 atomic_read(&ac->cmd_state)));
3663 rc = adsp_err_get_lnx_err_code(
3664 atomic_read(&ac->cmd_state));
3665 goto fail_cmd;
3666 }
3667
3668 return 0;
3669fail_cmd:
3670 return rc;
3671}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303672EXPORT_SYMBOL(q6asm_open_loopback_v2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303673
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303674/**
3675 * q6asm_open_transcode_loopback -
3676 * command to open ASM in transcode loopback mode
3677 *
3678 * @ac: Audio client handle
3679 * @bits_per_sample: number of bits per sample
3680 * @source_format: Format of clip
3681 * @sink_format: end device supported format
3682 *
3683 * Returns 0 on success or error on failure
3684 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303685int q6asm_open_transcode_loopback(struct audio_client *ac,
3686 uint16_t bits_per_sample,
3687 uint32_t source_format, uint32_t sink_format)
3688{
3689 int rc = 0x00;
3690 struct asm_stream_cmd_open_transcode_loopback_t open;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003691 struct q6asm_cal_info cal_info;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303692
3693 if (ac == NULL) {
3694 pr_err("%s: APR handle NULL\n", __func__);
3695 return -EINVAL;
3696 }
3697 if (ac->apr == NULL) {
3698 pr_err("%s: AC APR handle NULL\n", __func__);
3699 return -EINVAL;
3700 }
3701
3702 pr_debug("%s: session[%d]\n", __func__, ac->session);
3703
3704 q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
3705 atomic_set(&ac->cmd_state, -1);
3706 open.hdr.opcode = ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK;
3707
3708 open.mode_flags = 0;
3709 open.src_endpoint_type = 0;
3710 open.sink_endpoint_type = 0;
3711 switch (source_format) {
3712 case FORMAT_LINEAR_PCM:
3713 case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
3714 open.src_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3;
3715 break;
3716 case FORMAT_AC3:
3717 open.src_format_id = ASM_MEDIA_FMT_AC3;
3718 break;
3719 case FORMAT_EAC3:
3720 open.src_format_id = ASM_MEDIA_FMT_EAC3;
3721 break;
3722 default:
3723 pr_err("%s: Unsupported src fmt [%d]\n",
3724 __func__, source_format);
3725 return -EINVAL;
3726 }
3727 switch (sink_format) {
3728 case FORMAT_LINEAR_PCM:
3729 case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
3730 open.sink_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3;
3731 break;
3732 default:
3733 pr_err("%s: Unsupported sink fmt [%d]\n",
3734 __func__, sink_format);
3735 return -EINVAL;
3736 }
3737
3738 /* source endpoint : matrix */
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003739 rc = q6asm_get_asm_topology_apptype(&cal_info);
3740 open.audproc_topo_id = cal_info.topology_id;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303741
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003742
3743 ac->app_type = cal_info.app_type;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303744 if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
3745 open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION;
3746 else
3747 open.mode_flags |= ASM_LEGACY_STREAM_SESSION;
3748 ac->topology = open.audproc_topo_id;
3749 open.bits_per_sample = bits_per_sample;
3750 open.reserved = 0;
3751 pr_debug("%s: opening a transcode_loopback with mode_flags =[%d] session[%d]\n",
3752 __func__, open.mode_flags, ac->session);
3753
3754 rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
3755 if (rc < 0) {
3756 pr_err("%s: open failed op[0x%x]rc[%d]\n",
3757 __func__, open.hdr.opcode, rc);
3758 rc = -EINVAL;
3759 goto fail_cmd;
3760 }
3761 rc = wait_event_timeout(ac->cmd_wait,
3762 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
3763 if (!rc) {
3764 pr_err("%s: timeout. waited for open_transcode_loopback\n",
3765 __func__);
3766 rc = -ETIMEDOUT;
3767 goto fail_cmd;
3768 }
3769 if (atomic_read(&ac->cmd_state) > 0) {
3770 pr_err("%s: DSP returned error[%s]\n",
3771 __func__, adsp_err_get_err_str(
3772 atomic_read(&ac->cmd_state)));
3773 rc = adsp_err_get_lnx_err_code(
3774 atomic_read(&ac->cmd_state));
3775 goto fail_cmd;
3776 }
3777
3778 return 0;
3779fail_cmd:
3780 return rc;
3781}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05303782EXPORT_SYMBOL(q6asm_open_transcode_loopback);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303783
3784static
3785int q6asm_set_shared_circ_buff(struct audio_client *ac,
3786 struct asm_stream_cmd_open_shared_io *open,
3787 int bufsz, int bufcnt,
3788 int dir)
3789{
3790 struct audio_buffer *buf_circ;
3791 int bytes_to_alloc, rc;
3792 size_t len;
3793
Aditya Bavanaria8aea172017-09-13 11:37:53 +05303794 mutex_lock(&ac->cmd_lock);
3795
3796 if (ac->port[dir].buf) {
3797 pr_err("%s: Buffer already allocated\n", __func__);
3798 rc = -EINVAL;
Aditya Bavanaria8aea172017-09-13 11:37:53 +05303799 goto done;
3800 }
3801
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303802 buf_circ = kzalloc(sizeof(struct audio_buffer), GFP_KERNEL);
3803
3804 if (!buf_circ) {
3805 rc = -ENOMEM;
3806 goto done;
3807 }
3808
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303809 bytes_to_alloc = bufsz * bufcnt;
3810 bytes_to_alloc = PAGE_ALIGN(bytes_to_alloc);
3811
3812 rc = msm_audio_ion_alloc("audio_client", &buf_circ->client,
3813 &buf_circ->handle, bytes_to_alloc,
3814 (ion_phys_addr_t *)&buf_circ->phys,
3815 &len, &buf_circ->data);
3816
3817 if (rc) {
3818 pr_err("%s: Audio ION alloc is failed, rc = %d\n", __func__,
3819 rc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303820 kfree(buf_circ);
3821 goto done;
3822 }
3823
Aditya Bavanaria8aea172017-09-13 11:37:53 +05303824 ac->port[dir].buf = buf_circ;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303825 buf_circ->used = dir ^ 1;
3826 buf_circ->size = bytes_to_alloc;
3827 buf_circ->actual_size = bytes_to_alloc;
3828 memset(buf_circ->data, 0, buf_circ->actual_size);
3829
3830 ac->port[dir].max_buf_cnt = 1;
3831
3832 open->shared_circ_buf_mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
3833 open->shared_circ_buf_num_regions = 1;
3834 open->shared_circ_buf_property_flag = 0x00;
3835 open->shared_circ_buf_start_phy_addr_lsw =
3836 lower_32_bits(buf_circ->phys);
3837 open->shared_circ_buf_start_phy_addr_msw =
3838 msm_audio_populate_upper_32_bits(buf_circ->phys);
3839 open->shared_circ_buf_size = bufsz * bufcnt;
3840
3841 open->map_region_circ_buf.shm_addr_lsw = lower_32_bits(buf_circ->phys);
3842 open->map_region_circ_buf.shm_addr_msw =
3843 msm_audio_populate_upper_32_bits(buf_circ->phys);
3844 open->map_region_circ_buf.mem_size_bytes = bytes_to_alloc;
3845
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303846done:
Xiaoyu Yef423ab12017-11-22 11:38:29 -08003847 mutex_unlock(&ac->cmd_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303848 return rc;
3849}
3850
3851
3852static
3853int q6asm_set_shared_pos_buff(struct audio_client *ac,
3854 struct asm_stream_cmd_open_shared_io *open,
3855 int dir)
3856{
3857 struct audio_buffer *buf_pos = &ac->shared_pos_buf;
3858 int rc;
3859 size_t len;
3860 int bytes_to_alloc = sizeof(struct asm_shared_position_buffer);
3861
3862 mutex_lock(&ac->cmd_lock);
3863
3864 bytes_to_alloc = PAGE_ALIGN(bytes_to_alloc);
3865
3866 rc = msm_audio_ion_alloc("audio_client", &buf_pos->client,
3867 &buf_pos->handle, bytes_to_alloc,
3868 (ion_phys_addr_t *)&buf_pos->phys, &len,
3869 &buf_pos->data);
3870
3871 if (rc) {
3872 pr_err("%s: Audio pos buf ION alloc is failed, rc = %d\n",
3873 __func__, rc);
3874 goto done;
3875 }
3876
3877 buf_pos->used = dir ^ 1;
3878 buf_pos->size = bytes_to_alloc;
3879 buf_pos->actual_size = bytes_to_alloc;
3880
3881 open->shared_pos_buf_mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
3882 open->shared_pos_buf_num_regions = 1;
3883 open->shared_pos_buf_property_flag = 0x00;
3884 open->shared_pos_buf_phy_addr_lsw = lower_32_bits(buf_pos->phys);
3885 open->shared_pos_buf_phy_addr_msw =
3886 msm_audio_populate_upper_32_bits(buf_pos->phys);
3887
3888 open->map_region_pos_buf.shm_addr_lsw = lower_32_bits(buf_pos->phys);
3889 open->map_region_pos_buf.shm_addr_msw =
3890 msm_audio_populate_upper_32_bits(buf_pos->phys);
3891 open->map_region_pos_buf.mem_size_bytes = bytes_to_alloc;
3892
3893done:
3894 mutex_unlock(&ac->cmd_lock);
3895 return rc;
3896}
3897
3898/*
3899 * q6asm_open_shared_io: Open an ASM session for pull mode (playback)
3900 * or push mode (capture).
3901 * parameters
3902 * config - session parameters (channels, bits_per_sample, sr)
3903 * dir - stream direction (IN for playback, OUT for capture)
3904 * returns 0 if successful, error code otherwise
3905 */
3906int q6asm_open_shared_io(struct audio_client *ac,
3907 struct shared_io_config *config,
3908 int dir)
3909{
3910 struct asm_stream_cmd_open_shared_io *open;
3911 u8 *channel_mapping;
3912 int i, size_of_open, num_watermarks, bufsz, bufcnt, rc, flags = 0;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003913 struct q6asm_cal_info cal_info;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303914
3915 if (!ac || !config)
3916 return -EINVAL;
3917
Rohit kumar6a14cfb2019-02-04 11:22:49 +05303918 if (config->channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
3919 pr_err("%s: Invalid channel count %d\n", __func__,
3920 config->channels);
3921 return -EINVAL;
3922 }
3923
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303924 bufsz = config->bufsz;
3925 bufcnt = config->bufcnt;
3926 num_watermarks = 0;
3927
3928 ac->config = *config;
3929
3930 if (ac->session <= 0 || ac->session > SESSION_MAX) {
3931 pr_err("%s: Session %d is out of bounds\n",
3932 __func__, ac->session);
3933 return -EINVAL;
3934 }
3935
3936 size_of_open = sizeof(struct asm_stream_cmd_open_shared_io) +
3937 (sizeof(struct asm_shared_watermark_level) * num_watermarks);
3938
3939 open = kzalloc(PAGE_ALIGN(size_of_open), GFP_KERNEL);
3940 if (!open)
3941 return -ENOMEM;
3942
3943 q6asm_stream_add_hdr(ac, &open->hdr, size_of_open, TRUE,
3944 ac->stream_id);
3945
3946 atomic_set(&ac->cmd_state, 1);
3947
3948 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x, perf %d\n",
3949 __func__, open->hdr.token, ac->stream_id, ac->session,
3950 ac->perf_mode);
3951
3952 open->hdr.opcode =
3953 dir == IN ? ASM_STREAM_CMD_OPEN_PULL_MODE_WRITE :
3954 ASM_STREAM_CMD_OPEN_PUSH_MODE_READ;
3955
3956 pr_debug("%s perf_mode %d\n", __func__, ac->perf_mode);
3957 if (dir == IN)
3958 if (ac->perf_mode == ULL_POST_PROCESSING_PCM_MODE)
3959 flags = 4 << ASM_SHIFT_STREAM_PERF_FLAG_PULL_MODE_WRITE;
3960 else if (ac->perf_mode == ULTRA_LOW_LATENCY_PCM_MODE)
3961 flags = 2 << ASM_SHIFT_STREAM_PERF_FLAG_PULL_MODE_WRITE;
3962 else if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
3963 flags = 1 << ASM_SHIFT_STREAM_PERF_FLAG_PULL_MODE_WRITE;
3964 else
3965 pr_err("Invalid perf mode for pull write\n");
3966 else
3967 if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
3968 flags = ASM_LOW_LATENCY_TX_STREAM_SESSION <<
3969 ASM_SHIFT_STREAM_PERF_FLAG_PUSH_MODE_READ;
3970 else
3971 pr_err("Invalid perf mode for push read\n");
3972
3973 if (flags == 0) {
3974 pr_err("%s: Invalid mode[%d]\n", __func__,
3975 ac->perf_mode);
3976 kfree(open);
3977 return -EINVAL;
3978
3979 }
3980
3981 pr_debug("open.mode_flags = 0x%x\n", flags);
3982 open->mode_flags = flags;
3983 open->endpoint_type = ASM_END_POINT_DEVICE_MATRIX;
3984 open->topo_bits_per_sample = config->bits_per_sample;
3985
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -07003986 rc = q6asm_get_asm_topology_apptype(&cal_info);
3987 open->topo_id = cal_info.topology_id;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303988
3989 if (config->format == FORMAT_LINEAR_PCM)
3990 open->fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3;
3991 else {
3992 pr_err("%s: Invalid format[%d]\n", __func__, config->format);
3993 rc = -EINVAL;
3994 goto done;
3995 }
3996
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303997 rc = q6asm_set_shared_circ_buff(ac, open, bufsz, bufcnt, dir);
3998
3999 if (rc)
4000 goto done;
4001
4002 ac->port[dir].tmp_hdl = 0;
4003
4004 rc = q6asm_set_shared_pos_buff(ac, open, dir);
4005
4006 if (rc)
4007 goto done;
4008
4009 /* asm_multi_channel_pcm_fmt_blk_v3 */
4010 open->fmt.num_channels = config->channels;
4011 open->fmt.bits_per_sample = config->bits_per_sample;
4012 open->fmt.sample_rate = config->rate;
4013 open->fmt.is_signed = 1;
4014 open->fmt.sample_word_size = config->sample_word_size;
4015
4016 channel_mapping = open->fmt.channel_mapping;
4017
4018 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
4019
4020 rc = q6asm_map_channels(channel_mapping, config->channels, false);
4021 if (rc) {
4022 pr_err("%s: Map channels failed, ret: %d\n", __func__, rc);
4023 goto done;
4024 }
4025
4026 open->num_watermark_levels = num_watermarks;
4027 for (i = 0; i < num_watermarks; i++) {
4028 open->watermark[i].watermark_level_bytes = i *
4029 ((bufsz * bufcnt) / num_watermarks);
4030 pr_debug("%s: Watermark level set for %i\n",
4031 __func__,
4032 open->watermark[i].watermark_level_bytes);
4033 }
4034
4035 rc = apr_send_pkt(ac->apr, (uint32_t *) open);
4036 if (rc < 0) {
4037 pr_err("%s: Open failed op[0x%x]rc[%d]\n",
4038 __func__, open->hdr.opcode, rc);
4039 goto done;
4040 }
4041
4042 pr_debug("%s: sent open apr pkt\n", __func__);
4043 rc = wait_event_timeout(ac->cmd_wait,
4044 (atomic_read(&ac->cmd_state) <= 0), 5*HZ);
4045 if (!rc) {
4046 pr_err("%s: Timeout. Waited for open write apr pkt rc[%d]\n",
4047 __func__, rc);
4048 rc = -ETIMEDOUT;
4049 goto done;
4050 }
4051
4052 if (atomic_read(&ac->cmd_state) < 0) {
4053 pr_err("%s: DSP returned error [%d]\n", __func__,
4054 atomic_read(&ac->cmd_state));
4055 rc = -EINVAL;
4056 goto done;
4057 }
4058
4059 ac->io_mode |= TUN_WRITE_IO_MODE;
4060 rc = 0;
4061done:
4062 kfree(open);
4063 return rc;
4064}
4065EXPORT_SYMBOL(q6asm_open_shared_io);
4066
4067/*
4068 * q6asm_shared_io_buf: Returns handle to the shared circular buffer being
4069 * used for pull/push mode.
4070 * parameters
4071 * dir - used to identify input/output port
4072 * returns buffer handle
4073 */
4074struct audio_buffer *q6asm_shared_io_buf(struct audio_client *ac,
4075 int dir)
4076{
4077 struct audio_port_data *port;
4078
4079 if (!ac) {
4080 pr_err("%s: ac is null\n", __func__);
4081 return NULL;
4082 }
4083 port = &ac->port[dir];
4084 return port->buf;
4085}
4086EXPORT_SYMBOL(q6asm_shared_io_buf);
4087
4088/*
4089 * q6asm_shared_io_free: Frees memory allocated for a pull/push session
4090 * parameters
4091 * dir - port direction
4092 * returns 0 if successful, error otherwise
4093 */
4094int q6asm_shared_io_free(struct audio_client *ac, int dir)
4095{
4096 struct audio_port_data *port;
4097
4098 if (!ac) {
4099 pr_err("%s: audio client is null\n", __func__);
4100 return -EINVAL;
4101 }
4102 port = &ac->port[dir];
4103 mutex_lock(&ac->cmd_lock);
4104 if (port->buf && port->buf->data) {
4105 msm_audio_ion_free(port->buf->client, port->buf->handle);
4106 port->buf->client = NULL;
4107 port->buf->handle = NULL;
4108 port->max_buf_cnt = 0;
4109 kfree(port->buf);
4110 port->buf = NULL;
4111 }
4112 if (ac->shared_pos_buf.data) {
4113 msm_audio_ion_free(ac->shared_pos_buf.client,
4114 ac->shared_pos_buf.handle);
4115 ac->shared_pos_buf.client = NULL;
4116 ac->shared_pos_buf.handle = NULL;
4117 }
4118 mutex_unlock(&ac->cmd_lock);
4119 return 0;
4120}
4121EXPORT_SYMBOL(q6asm_shared_io_free);
4122
4123/*
4124 * q6asm_get_shared_pos: Returns current read index/write index as observed
4125 * by the DSP. Note that this is an offset and iterates from [0,BUF_SIZE - 1]
4126 * parameters - (all output)
4127 * read_index - offset
4128 * wall_clk_msw1 - ADSP wallclock msw
4129 * wall_clk_lsw1 - ADSP wallclock lsw
4130 * returns 0 if successful, -EAGAIN if DSP failed to update after some
4131 * retries
4132 */
4133int q6asm_get_shared_pos(struct audio_client *ac, uint32_t *read_index,
4134 uint32_t *wall_clk_msw1, uint32_t *wall_clk_lsw1)
4135{
4136 struct asm_shared_position_buffer *pos_buf;
4137 uint32_t frame_cnt1, frame_cnt2;
4138 int i, j;
4139
4140 if (!ac) {
4141 pr_err("%s: audio client is null\n", __func__);
4142 return -EINVAL;
4143 }
4144
4145 pos_buf = ac->shared_pos_buf.data;
4146
4147 /* always try to get the latest update in the shared pos buffer */
4148 for (i = 0; i < 2; i++) {
4149 /* retry until there is an update from DSP */
4150 for (j = 0; j < 5; j++) {
4151 frame_cnt1 = pos_buf->frame_counter;
4152 if (frame_cnt1 != 0)
4153 break;
4154 }
4155
4156 *wall_clk_msw1 = pos_buf->wall_clock_us_msw;
4157 *wall_clk_lsw1 = pos_buf->wall_clock_us_lsw;
4158 *read_index = pos_buf->index;
4159 frame_cnt2 = pos_buf->frame_counter;
4160
4161 if (frame_cnt1 != frame_cnt2)
4162 continue;
4163 return 0;
4164 }
4165 pr_err("%s out of tries trying to get a good read, try again\n",
4166 __func__);
4167 return -EAGAIN;
4168}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304169EXPORT_SYMBOL(q6asm_get_shared_pos);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304170
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304171/**
4172 * q6asm_run -
4173 * command to set ASM to run state
4174 *
4175 * @ac: Audio client handle
4176 * @flags: Flags for session
4177 * @msw_ts: upper 32bits timestamp
4178 * @lsw_ts: lower 32bits timestamp
4179 *
4180 * Returns 0 on success or error on failure
4181 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304182int q6asm_run(struct audio_client *ac, uint32_t flags,
4183 uint32_t msw_ts, uint32_t lsw_ts)
4184{
4185 struct asm_session_cmd_run_v2 run;
4186 int rc;
4187
4188 if (ac == NULL) {
4189 pr_err("%s: APR handle NULL\n", __func__);
4190 return -EINVAL;
4191 }
4192 if (ac->apr == NULL) {
4193 pr_err("%s: AC APR handle NULL\n", __func__);
4194 return -EINVAL;
4195 }
4196 pr_debug("%s: session[%d]\n", __func__, ac->session);
4197
4198 q6asm_add_hdr(ac, &run.hdr, sizeof(run), TRUE);
4199 atomic_set(&ac->cmd_state, -1);
4200
4201 run.hdr.opcode = ASM_SESSION_CMD_RUN_V2;
4202 run.flags = flags;
4203 run.time_lsw = lsw_ts;
4204 run.time_msw = msw_ts;
4205
4206 config_debug_fs_run();
4207
4208 rc = apr_send_pkt(ac->apr, (uint32_t *) &run);
4209 if (rc < 0) {
4210 pr_err("%s: Commmand run failed[%d]",
4211 __func__, rc);
4212 rc = -EINVAL;
4213 goto fail_cmd;
4214 }
4215
4216 rc = wait_event_timeout(ac->cmd_wait,
4217 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4218 if (!rc) {
4219 pr_err("%s: timeout. waited for run success",
4220 __func__);
4221 rc = -ETIMEDOUT;
4222 goto fail_cmd;
4223 }
4224 if (atomic_read(&ac->cmd_state) > 0) {
4225 pr_err("%s: DSP returned error[%s]\n",
4226 __func__, adsp_err_get_err_str(
4227 atomic_read(&ac->cmd_state)));
4228 rc = adsp_err_get_lnx_err_code(
4229 atomic_read(&ac->cmd_state));
4230 goto fail_cmd;
4231 }
4232
4233 return 0;
4234fail_cmd:
4235 return rc;
4236}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304237EXPORT_SYMBOL(q6asm_run);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304238
4239static int __q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
4240 uint32_t msw_ts, uint32_t lsw_ts, uint32_t stream_id)
4241{
4242 struct asm_session_cmd_run_v2 run;
4243 int rc;
4244
4245 if (ac == NULL) {
4246 pr_err("%s: APR handle NULL\n", __func__);
4247 return -EINVAL;
4248 }
4249 if (ac->apr == NULL) {
4250 pr_err("%s: AC APR handle NULL\n", __func__);
4251 return -EINVAL;
4252 }
4253 pr_debug("%s: session[%d]\n", __func__, ac->session);
4254
4255 q6asm_stream_add_hdr_async(ac, &run.hdr, sizeof(run), TRUE, stream_id);
4256 atomic_set(&ac->cmd_state, 1);
4257 run.hdr.opcode = ASM_SESSION_CMD_RUN_V2;
4258 run.flags = flags;
4259 run.time_lsw = lsw_ts;
4260 run.time_msw = msw_ts;
4261
4262 rc = apr_send_pkt(ac->apr, (uint32_t *) &run);
4263 if (rc < 0) {
4264 pr_err("%s: Commmand run failed[%d]", __func__, rc);
4265 return -EINVAL;
4266 }
4267 return 0;
4268}
4269
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304270/**
4271 * q6asm_run_nowait -
4272 * command to set ASM to run state with no wait for ack
4273 *
4274 * @ac: Audio client handle
4275 * @flags: Flags for session
4276 * @msw_ts: upper 32bits timestamp
4277 * @lsw_ts: lower 32bits timestamp
4278 *
4279 * Returns 0 on success or error on failure
4280 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304281int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
4282 uint32_t msw_ts, uint32_t lsw_ts)
4283{
4284 return __q6asm_run_nowait(ac, flags, msw_ts, lsw_ts, ac->stream_id);
4285}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304286EXPORT_SYMBOL(q6asm_run_nowait);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304287
4288int q6asm_stream_run_nowait(struct audio_client *ac, uint32_t flags,
4289 uint32_t msw_ts, uint32_t lsw_ts, uint32_t stream_id)
4290{
4291 return __q6asm_run_nowait(ac, flags, msw_ts, lsw_ts, stream_id);
4292}
4293
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304294/**
4295 * q6asm_enc_cfg_blk_aac -
4296 * command to set encode cfg block for aac
4297 *
4298 * @ac: Audio client handle
4299 * @frames_per_buf: number of frames per buffer
4300 * @sample_rate: Sample rate
4301 * @channels: number of ASM channels
4302 * @bit_rate: Bit rate info
4303 * @mode: mode of AAC stream encode
4304 * @format: aac format flag
4305 *
4306 * Returns 0 on success or error on failure
4307 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304308int q6asm_enc_cfg_blk_aac(struct audio_client *ac,
4309 uint32_t frames_per_buf,
4310 uint32_t sample_rate, uint32_t channels,
4311 uint32_t bit_rate, uint32_t mode, uint32_t format)
4312{
4313 struct asm_aac_enc_cfg_v2 enc_cfg;
4314 int rc = 0;
4315
4316 pr_debug("%s: session[%d]frames[%d]SR[%d]ch[%d]bitrate[%d]mode[%d] format[%d]\n",
4317 __func__, ac->session, frames_per_buf,
4318 sample_rate, channels, bit_rate, mode, format);
4319
4320 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
4321 atomic_set(&ac->cmd_state, -1);
4322
4323 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4324 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
4325 enc_cfg.encdec.param_size = sizeof(struct asm_aac_enc_cfg_v2) -
4326 sizeof(struct asm_stream_cmd_set_encdec_param);
4327 enc_cfg.encblk.frames_per_buf = frames_per_buf;
4328 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
4329 sizeof(struct asm_enc_cfg_blk_param_v2);
4330 enc_cfg.bit_rate = bit_rate;
4331 enc_cfg.enc_mode = mode;
4332 enc_cfg.aac_fmt_flag = format;
4333 enc_cfg.channel_cfg = channels;
4334 enc_cfg.sample_rate = sample_rate;
4335
4336 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
4337 if (rc < 0) {
4338 pr_err("%s: Comamnd %d failed %d\n",
4339 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
4340 rc = -EINVAL;
4341 goto fail_cmd;
4342 }
4343 rc = wait_event_timeout(ac->cmd_wait,
4344 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4345 if (!rc) {
4346 pr_err("%s: timeout. waited for FORMAT_UPDATE\n",
4347 __func__);
4348 rc = -ETIMEDOUT;
4349 goto fail_cmd;
4350 }
4351 if (atomic_read(&ac->cmd_state) > 0) {
4352 pr_err("%s: DSP returned error[%s]\n",
4353 __func__, adsp_err_get_err_str(
4354 atomic_read(&ac->cmd_state)));
4355 rc = adsp_err_get_lnx_err_code(
4356 atomic_read(&ac->cmd_state));
4357 goto fail_cmd;
4358 }
4359 return 0;
4360fail_cmd:
4361 return rc;
4362}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304363EXPORT_SYMBOL(q6asm_enc_cfg_blk_aac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304364
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304365/**
4366 * q6asm_enc_cfg_blk_g711 -
4367 * command to set encode cfg block for g711
4368 *
4369 * @ac: Audio client handle
4370 * @frames_per_buf: number of frames per buffer
4371 * @sample_rate: Sample rate
4372 *
4373 * Returns 0 on success or error on failure
4374 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304375int q6asm_enc_cfg_blk_g711(struct audio_client *ac,
4376 uint32_t frames_per_buf,
4377 uint32_t sample_rate)
4378{
4379 struct asm_g711_enc_cfg_v2 enc_cfg;
4380 int rc = 0;
4381
4382 pr_debug("%s: session[%d]frames[%d]SR[%d]\n",
4383 __func__, ac->session, frames_per_buf,
4384 sample_rate);
4385
4386 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
4387 atomic_set(&ac->cmd_state, -1);
4388
4389 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4390 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
4391 enc_cfg.encdec.param_size = sizeof(struct asm_g711_enc_cfg_v2) -
4392 sizeof(struct asm_stream_cmd_set_encdec_param);
4393 enc_cfg.encblk.frames_per_buf = frames_per_buf;
4394 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
4395 sizeof(struct asm_enc_cfg_blk_param_v2);
4396 enc_cfg.sample_rate = sample_rate;
4397
4398 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
4399 if (rc < 0) {
4400 pr_err("%s: Comamnd %d failed %d\n",
4401 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
4402 rc = -EINVAL;
4403 goto fail_cmd;
4404 }
4405 rc = wait_event_timeout(ac->cmd_wait,
4406 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4407 if (!rc) {
4408 pr_err("%s: timeout. waited for FORMAT_UPDATE\n",
4409 __func__);
4410 rc = -ETIMEDOUT;
4411 goto fail_cmd;
4412 }
4413 if (atomic_read(&ac->cmd_state) > 0) {
4414 pr_err("%s: DSP returned error[%s]\n",
4415 __func__, adsp_err_get_err_str(
4416 atomic_read(&ac->cmd_state)));
4417 rc = adsp_err_get_lnx_err_code(
4418 atomic_read(&ac->cmd_state));
4419 goto fail_cmd;
4420 }
4421 return 0;
4422fail_cmd:
4423 return rc;
4424}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304425EXPORT_SYMBOL(q6asm_enc_cfg_blk_g711);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304426
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304427/**
4428 * q6asm_set_encdec_chan_map -
4429 * command to set encdec channel map
4430 *
4431 * @ac: Audio client handle
4432 * @channels: number of channels
4433 *
4434 * Returns 0 on success or error on failure
4435 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304436int q6asm_set_encdec_chan_map(struct audio_client *ac,
4437 uint32_t num_channels)
4438{
4439 struct asm_dec_out_chan_map_param chan_map;
4440 u8 *channel_mapping;
4441 int rc = 0;
4442
Rohit kumar6a14cfb2019-02-04 11:22:49 +05304443 if (num_channels > MAX_CHAN_MAP_CHANNELS) {
4444 pr_err("%s: Invalid channel count %d\n", __func__,
4445 num_channels);
4446 return -EINVAL;
4447 }
4448
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304449 pr_debug("%s: Session %d, num_channels = %d\n",
4450 __func__, ac->session, num_channels);
4451 q6asm_add_hdr(ac, &chan_map.hdr, sizeof(chan_map), TRUE);
4452 atomic_set(&ac->cmd_state, -1);
4453 chan_map.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4454 chan_map.encdec.param_id = ASM_PARAM_ID_DEC_OUTPUT_CHAN_MAP;
4455 chan_map.encdec.param_size = sizeof(struct asm_dec_out_chan_map_param) -
4456 (sizeof(struct apr_hdr) +
4457 sizeof(struct asm_stream_cmd_set_encdec_param));
4458 chan_map.num_channels = num_channels;
4459 channel_mapping = chan_map.channel_mapping;
4460 memset(channel_mapping, PCM_CHANNEL_NULL, MAX_CHAN_MAP_CHANNELS);
4461
4462 if (q6asm_map_channels(channel_mapping, num_channels, false)) {
4463 pr_err("%s: map channels failed %d\n", __func__, num_channels);
4464 return -EINVAL;
4465 }
4466
4467 rc = apr_send_pkt(ac->apr, (uint32_t *) &chan_map);
4468 if (rc < 0) {
4469 pr_err("%s: Command opcode[0x%x]paramid[0x%x] failed %d\n",
4470 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM,
4471 ASM_PARAM_ID_DEC_OUTPUT_CHAN_MAP, rc);
4472 goto fail_cmd;
4473 }
4474 rc = wait_event_timeout(ac->cmd_wait,
4475 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4476 if (!rc) {
4477 pr_err("%s: timeout opcode[0x%x]\n", __func__,
4478 chan_map.hdr.opcode);
4479 rc = -ETIMEDOUT;
4480 goto fail_cmd;
4481 }
4482 if (atomic_read(&ac->cmd_state) > 0) {
4483 pr_err("%s: DSP returned error[%s]\n",
4484 __func__, adsp_err_get_err_str(
4485 atomic_read(&ac->cmd_state)));
4486 rc = adsp_err_get_lnx_err_code(
4487 atomic_read(&ac->cmd_state));
4488 goto fail_cmd;
4489 }
4490 return 0;
4491fail_cmd:
4492 return rc;
4493}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304494EXPORT_SYMBOL(q6asm_set_encdec_chan_map);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304495
4496/*
4497 * q6asm_enc_cfg_blk_pcm_v4 - sends encoder configuration parameters
4498 *
4499 * @ac: Client session handle
4500 * @rate: sample rate
4501 * @channels: number of channels
4502 * @bits_per_sample: bit width of encoder session
4503 * @use_default_chmap: true if default channel map to be used
4504 * @use_back_flavor: to configure back left and right channel
4505 * @channel_map: input channel map
4506 * @sample_word_size: Size in bits of the word that holds a sample of a channel
4507 * @endianness: endianness of the pcm data
4508 * @mode: Mode to provide additional info about the pcm input data
4509 */
4510int q6asm_enc_cfg_blk_pcm_v4(struct audio_client *ac,
4511 uint32_t rate, uint32_t channels,
4512 uint16_t bits_per_sample, bool use_default_chmap,
4513 bool use_back_flavor, u8 *channel_map,
4514 uint16_t sample_word_size, uint16_t endianness,
4515 uint16_t mode)
4516{
4517 struct asm_multi_channel_pcm_enc_cfg_v4 enc_cfg;
4518 struct asm_enc_cfg_blk_param_v2 enc_fg_blk;
4519 u8 *channel_mapping;
4520 u32 frames_per_buf = 0;
4521 int rc;
4522
4523 if (!use_default_chmap && (channel_map == NULL)) {
4524 pr_err("%s: No valid chan map and can't use default\n",
4525 __func__);
4526 rc = -EINVAL;
4527 goto fail_cmd;
4528 }
4529
Rohit kumar6a14cfb2019-02-04 11:22:49 +05304530 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
4531 pr_err("%s: Invalid channel count %d\n", __func__, channels);
4532 rc = -EINVAL;
4533 goto fail_cmd;
4534 }
4535
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304536 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
4537 ac->session, rate, channels,
4538 bits_per_sample, sample_word_size);
4539
4540 memset(&enc_cfg, 0, sizeof(enc_cfg));
4541 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
4542 atomic_set(&ac->cmd_state, -1);
4543 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4544 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
4545 enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
4546 sizeof(enc_cfg.encdec);
4547 enc_cfg.encblk.frames_per_buf = frames_per_buf;
4548 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
4549 sizeof(enc_fg_blk);
4550 enc_cfg.num_channels = channels;
4551 enc_cfg.bits_per_sample = bits_per_sample;
4552 enc_cfg.sample_rate = rate;
4553 enc_cfg.is_signed = 1;
4554 enc_cfg.sample_word_size = sample_word_size;
4555 enc_cfg.endianness = endianness;
4556 enc_cfg.mode = mode;
4557 channel_mapping = enc_cfg.channel_mapping;
4558
4559 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
4560
4561 if (use_default_chmap) {
4562 pr_debug("%s: setting default channel map for %d channels",
4563 __func__, channels);
4564 if (q6asm_map_channels(channel_mapping, channels,
4565 use_back_flavor)) {
4566 pr_err("%s: map channels failed %d\n",
4567 __func__, channels);
4568 rc = -EINVAL;
4569 goto fail_cmd;
4570 }
4571 } else {
4572 pr_debug("%s: Using pre-defined channel map", __func__);
4573 memcpy(channel_mapping, channel_map,
4574 PCM_FORMAT_MAX_NUM_CHANNEL);
4575 }
4576
4577 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
4578 if (rc < 0) {
4579 pr_err("%s: Command open failed %d\n", __func__, rc);
4580 goto fail_cmd;
4581 }
4582 rc = wait_event_timeout(ac->cmd_wait,
4583 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4584 if (!rc) {
4585 pr_err("%s: timeout opcode[0x%x]\n",
4586 __func__, enc_cfg.hdr.opcode);
4587 rc = -ETIMEDOUT;
4588 goto fail_cmd;
4589 }
4590 if (atomic_read(&ac->cmd_state) > 0) {
4591 pr_err("%s: DSP returned error[%s]\n",
4592 __func__, adsp_err_get_err_str(
4593 atomic_read(&ac->cmd_state)));
4594 rc = adsp_err_get_lnx_err_code(
4595 atomic_read(&ac->cmd_state));
4596 goto fail_cmd;
4597 }
4598 return 0;
4599fail_cmd:
4600 return rc;
4601}
4602EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_v4);
4603
4604/*
4605 * q6asm_enc_cfg_blk_pcm_v3 - sends encoder configuration parameters
4606 *
4607 * @ac: Client session handle
4608 * @rate: sample rate
4609 * @channels: number of channels
4610 * @bits_per_sample: bit width of encoder session
4611 * @use_default_chmap: true if default channel map to be used
4612 * @use_back_flavor: to configure back left and right channel
4613 * @channel_map: input channel map
4614 * @sample_word_size: Size in bits of the word that holds a sample of a channel
4615 */
4616int q6asm_enc_cfg_blk_pcm_v3(struct audio_client *ac,
4617 uint32_t rate, uint32_t channels,
4618 uint16_t bits_per_sample, bool use_default_chmap,
4619 bool use_back_flavor, u8 *channel_map,
4620 uint16_t sample_word_size)
4621{
4622 struct asm_multi_channel_pcm_enc_cfg_v3 enc_cfg;
4623 struct asm_enc_cfg_blk_param_v2 enc_fg_blk;
4624 u8 *channel_mapping;
4625 u32 frames_per_buf = 0;
4626 int rc;
4627
4628 if (!use_default_chmap && (channel_map == NULL)) {
4629 pr_err("%s: No valid chan map and can't use default\n",
4630 __func__);
4631 rc = -EINVAL;
4632 goto fail_cmd;
4633 }
4634
Rohit kumar6a14cfb2019-02-04 11:22:49 +05304635 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
4636 pr_err("%s: Invalid channel count %d\n", __func__, channels);
4637 rc = -EINVAL;
4638 goto fail_cmd;
4639 }
4640
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304641 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
4642 ac->session, rate, channels,
4643 bits_per_sample, sample_word_size);
4644
4645 memset(&enc_cfg, 0, sizeof(enc_cfg));
4646 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
4647 atomic_set(&ac->cmd_state, -1);
4648 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4649 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
4650 enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
4651 sizeof(enc_cfg.encdec);
4652 enc_cfg.encblk.frames_per_buf = frames_per_buf;
4653 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
4654 sizeof(enc_fg_blk);
4655 enc_cfg.num_channels = channels;
4656 enc_cfg.bits_per_sample = bits_per_sample;
4657 enc_cfg.sample_rate = rate;
4658 enc_cfg.is_signed = 1;
4659 enc_cfg.sample_word_size = sample_word_size;
4660 channel_mapping = enc_cfg.channel_mapping;
4661
4662 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
4663
4664 if (use_default_chmap) {
4665 pr_debug("%s: setting default channel map for %d channels",
4666 __func__, channels);
4667 if (q6asm_map_channels(channel_mapping, channels,
4668 use_back_flavor)) {
4669 pr_err("%s: map channels failed %d\n",
4670 __func__, channels);
4671 rc = -EINVAL;
4672 goto fail_cmd;
4673 }
4674 } else {
4675 pr_debug("%s: Using pre-defined channel map", __func__);
4676 memcpy(channel_mapping, channel_map,
4677 PCM_FORMAT_MAX_NUM_CHANNEL);
4678 }
4679
4680 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
4681 if (rc < 0) {
4682 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
4683 goto fail_cmd;
4684 }
4685 rc = wait_event_timeout(ac->cmd_wait,
4686 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4687 if (!rc) {
4688 pr_err("%s: timeout opcode[0x%x]\n",
4689 __func__, enc_cfg.hdr.opcode);
4690 rc = -ETIMEDOUT;
4691 goto fail_cmd;
4692 }
4693 if (atomic_read(&ac->cmd_state) > 0) {
4694 pr_err("%s: DSP returned error[%s]\n",
4695 __func__, adsp_err_get_err_str(
4696 atomic_read(&ac->cmd_state)));
4697 rc = adsp_err_get_lnx_err_code(
4698 atomic_read(&ac->cmd_state));
4699 goto fail_cmd;
4700 }
4701 return 0;
4702fail_cmd:
4703 return rc;
4704}
4705EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_v3);
4706
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304707/**
4708 * q6asm_enc_cfg_blk_pcm_v2 -
4709 * command to set encode config block for pcm_v2
4710 *
4711 * @ac: Audio client handle
4712 * @rate: sample rate
4713 * @channels: number of channels
4714 * @bits_per_sample: number of bits per sample
4715 * @use_default_chmap: Flag indicating to use default ch_map or not
4716 * @use_back_flavor: back flavor flag
4717 * @channel_map: Custom channel map settings
4718 *
4719 * Returns 0 on success or error on failure
4720 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304721int q6asm_enc_cfg_blk_pcm_v2(struct audio_client *ac,
4722 uint32_t rate, uint32_t channels, uint16_t bits_per_sample,
4723 bool use_default_chmap, bool use_back_flavor, u8 *channel_map)
4724{
4725 struct asm_multi_channel_pcm_enc_cfg_v2 enc_cfg;
4726 u8 *channel_mapping;
4727 u32 frames_per_buf = 0;
4728
4729 int rc = 0;
4730
4731 if (!use_default_chmap && (channel_map == NULL)) {
4732 pr_err("%s: No valid chan map and can't use default\n",
4733 __func__);
4734 return -EINVAL;
4735 }
4736
Rohit kumar6a14cfb2019-02-04 11:22:49 +05304737 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
4738 pr_err("%s: Invalid channel count %d\n", __func__, channels);
4739 return -EINVAL;
4740 }
4741
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304742 pr_debug("%s: Session %d, rate = %d, channels = %d\n", __func__,
4743 ac->session, rate, channels);
4744
4745 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
4746 atomic_set(&ac->cmd_state, -1);
4747 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4748 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
4749 enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
4750 sizeof(enc_cfg.encdec);
4751 enc_cfg.encblk.frames_per_buf = frames_per_buf;
4752 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
4753 sizeof(struct asm_enc_cfg_blk_param_v2);
4754
4755 enc_cfg.num_channels = channels;
4756 enc_cfg.bits_per_sample = bits_per_sample;
4757 enc_cfg.sample_rate = rate;
4758 enc_cfg.is_signed = 1;
4759 channel_mapping = enc_cfg.channel_mapping;
4760
4761 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
4762
4763 if (use_default_chmap) {
4764 pr_debug("%s: setting default channel map for %d channels",
4765 __func__, channels);
4766 if (q6asm_map_channels(channel_mapping, channels,
4767 use_back_flavor)) {
4768 pr_err("%s: map channels failed %d\n",
4769 __func__, channels);
4770 return -EINVAL;
4771 }
4772 } else {
4773 pr_debug("%s: Using pre-defined channel map", __func__);
4774 memcpy(channel_mapping, channel_map,
4775 PCM_FORMAT_MAX_NUM_CHANNEL);
4776 }
4777
4778 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
4779 if (rc < 0) {
4780 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
4781 rc = -EINVAL;
4782 goto fail_cmd;
4783 }
4784 rc = wait_event_timeout(ac->cmd_wait,
4785 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4786 if (!rc) {
4787 pr_err("%s: timeout opcode[0x%x]\n",
4788 __func__, enc_cfg.hdr.opcode);
4789 rc = -ETIMEDOUT;
4790 goto fail_cmd;
4791 }
4792 if (atomic_read(&ac->cmd_state) > 0) {
4793 pr_err("%s: DSP returned error[%s]\n",
4794 __func__, adsp_err_get_err_str(
4795 atomic_read(&ac->cmd_state)));
4796 rc = adsp_err_get_lnx_err_code(
4797 atomic_read(&ac->cmd_state));
4798 goto fail_cmd;
4799 }
4800 return 0;
4801fail_cmd:
4802 return rc;
4803}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304804EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_v2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304805
4806static int __q6asm_enc_cfg_blk_pcm_v4(struct audio_client *ac,
4807 uint32_t rate, uint32_t channels,
4808 uint16_t bits_per_sample,
4809 uint16_t sample_word_size,
4810 uint16_t endianness,
4811 uint16_t mode)
4812{
4813 return q6asm_enc_cfg_blk_pcm_v4(ac, rate, channels,
4814 bits_per_sample, true, false, NULL,
4815 sample_word_size, endianness, mode);
4816}
4817
4818static int __q6asm_enc_cfg_blk_pcm_v3(struct audio_client *ac,
4819 uint32_t rate, uint32_t channels,
4820 uint16_t bits_per_sample,
4821 uint16_t sample_word_size)
4822{
4823 return q6asm_enc_cfg_blk_pcm_v3(ac, rate, channels,
4824 bits_per_sample, true, false, NULL,
4825 sample_word_size);
4826}
4827
4828static int __q6asm_enc_cfg_blk_pcm(struct audio_client *ac,
4829 uint32_t rate, uint32_t channels, uint16_t bits_per_sample)
4830{
4831 return q6asm_enc_cfg_blk_pcm_v2(ac, rate, channels,
4832 bits_per_sample, true, false, NULL);
4833}
4834
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304835/**
4836 * q6asm_enc_cfg_blk_pcm -
4837 * command to set encode config block for pcm
4838 *
4839 * @ac: Audio client handle
4840 * @rate: sample rate
4841 * @channels: number of channels
4842 *
4843 * Returns 0 on success or error on failure
4844 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304845int q6asm_enc_cfg_blk_pcm(struct audio_client *ac,
4846 uint32_t rate, uint32_t channels)
4847{
4848 return __q6asm_enc_cfg_blk_pcm(ac, rate, channels, 16);
4849}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304850EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304851
4852int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
4853 uint32_t rate, uint32_t channels, uint16_t bits_per_sample)
4854{
4855 return __q6asm_enc_cfg_blk_pcm(ac, rate, channels, bits_per_sample);
4856}
4857
4858/*
4859 * q6asm_enc_cfg_blk_pcm_format_support_v3 - sends encoder configuration
4860 * parameters
4861 *
4862 * @ac: Client session handle
4863 * @rate: sample rate
4864 * @channels: number of channels
4865 * @bits_per_sample: bit width of encoder session
4866 * @sample_word_size: Size in bits of the word that holds a sample of a channel
4867 */
4868int q6asm_enc_cfg_blk_pcm_format_support_v3(struct audio_client *ac,
4869 uint32_t rate, uint32_t channels,
4870 uint16_t bits_per_sample,
4871 uint16_t sample_word_size)
4872{
4873 return __q6asm_enc_cfg_blk_pcm_v3(ac, rate, channels,
4874 bits_per_sample, sample_word_size);
4875}
4876EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_format_support_v3);
4877
4878/*
4879 * q6asm_enc_cfg_blk_pcm_format_support_v4 - sends encoder configuration
4880 * parameters
4881 *
4882 * @ac: Client session handle
4883 * @rate: sample rate
4884 * @channels: number of channels
4885 * @bits_per_sample: bit width of encoder session
4886 * @sample_word_size: Size in bits of the word that holds a sample of a channel
4887 * @endianness: endianness of the pcm data
4888 * @mode: Mode to provide additional info about the pcm input data
4889 */
4890int q6asm_enc_cfg_blk_pcm_format_support_v4(struct audio_client *ac,
4891 uint32_t rate, uint32_t channels,
4892 uint16_t bits_per_sample,
4893 uint16_t sample_word_size,
4894 uint16_t endianness,
4895 uint16_t mode)
4896{
4897 return __q6asm_enc_cfg_blk_pcm_v4(ac, rate, channels,
4898 bits_per_sample, sample_word_size,
4899 endianness, mode);
4900}
4901EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_format_support_v4);
4902
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304903/**
4904 * q6asm_enc_cfg_blk_pcm_native -
4905 * command to set encode config block for pcm_native
4906 *
4907 * @ac: Audio client handle
4908 * @rate: sample rate
4909 * @channels: number of channels
4910 *
4911 * Returns 0 on success or error on failure
4912 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304913int q6asm_enc_cfg_blk_pcm_native(struct audio_client *ac,
4914 uint32_t rate, uint32_t channels)
4915{
4916 struct asm_multi_channel_pcm_enc_cfg_v2 enc_cfg;
4917 u8 *channel_mapping;
4918 u32 frames_per_buf = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304919 int rc = 0;
4920
Rohit kumar6a14cfb2019-02-04 11:22:49 +05304921 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
4922 pr_err("%s: Invalid channel count %d\n", __func__, channels);
4923 return -EINVAL;
4924 }
4925
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304926 pr_debug("%s: Session %d, rate = %d, channels = %d\n", __func__,
4927 ac->session, rate, channels);
4928
4929 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
4930 atomic_set(&ac->cmd_state, -1);
4931 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
4932 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
4933 enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
4934 sizeof(enc_cfg.encdec);
4935 enc_cfg.encblk.frames_per_buf = frames_per_buf;
4936 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
4937 sizeof(struct asm_enc_cfg_blk_param_v2);
4938
4939 enc_cfg.num_channels = 0;/*channels;*/
4940 enc_cfg.bits_per_sample = 16;
4941 enc_cfg.sample_rate = 0;/*rate;*/
4942 enc_cfg.is_signed = 1;
4943 channel_mapping = enc_cfg.channel_mapping;
4944
4945
4946 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
4947
4948 if (q6asm_map_channels(channel_mapping, channels, false)) {
4949 pr_err("%s: map channels failed %d\n", __func__, channels);
4950 return -EINVAL;
4951 }
4952
4953 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
4954 if (rc < 0) {
4955 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
4956 rc = -EINVAL;
4957 goto fail_cmd;
4958 }
4959 rc = wait_event_timeout(ac->cmd_wait,
4960 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
4961 if (!rc) {
4962 pr_err("%s: timeout opcode[0x%x]\n",
4963 __func__, enc_cfg.hdr.opcode);
4964 rc = -ETIMEDOUT;
4965 goto fail_cmd;
4966 }
4967 if (atomic_read(&ac->cmd_state) > 0) {
4968 pr_err("%s: DSP returned error[%s]\n",
4969 __func__, adsp_err_get_err_str(
4970 atomic_read(&ac->cmd_state)));
4971 rc = adsp_err_get_lnx_err_code(
4972 atomic_read(&ac->cmd_state));
4973 goto fail_cmd;
4974 }
4975 return 0;
4976fail_cmd:
4977 return rc;
4978}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05304979EXPORT_SYMBOL(q6asm_enc_cfg_blk_pcm_native);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304980
4981static int q6asm_map_channels(u8 *channel_mapping, uint32_t channels,
4982 bool use_back_flavor)
4983{
4984 u8 *lchannel_mapping;
4985
4986 lchannel_mapping = channel_mapping;
4987 pr_debug("%s: channels passed: %d\n", __func__, channels);
4988 if (channels == 1) {
4989 lchannel_mapping[0] = PCM_CHANNEL_FC;
4990 } else if (channels == 2) {
4991 lchannel_mapping[0] = PCM_CHANNEL_FL;
4992 lchannel_mapping[1] = PCM_CHANNEL_FR;
4993 } else if (channels == 3) {
4994 lchannel_mapping[0] = PCM_CHANNEL_FL;
4995 lchannel_mapping[1] = PCM_CHANNEL_FR;
4996 lchannel_mapping[2] = PCM_CHANNEL_FC;
4997 } else if (channels == 4) {
4998 lchannel_mapping[0] = PCM_CHANNEL_FL;
4999 lchannel_mapping[1] = PCM_CHANNEL_FR;
5000 lchannel_mapping[2] = use_back_flavor ?
5001 PCM_CHANNEL_LB : PCM_CHANNEL_LS;
5002 lchannel_mapping[3] = use_back_flavor ?
5003 PCM_CHANNEL_RB : PCM_CHANNEL_RS;
5004 } else if (channels == 5) {
5005 lchannel_mapping[0] = PCM_CHANNEL_FL;
5006 lchannel_mapping[1] = PCM_CHANNEL_FR;
5007 lchannel_mapping[2] = PCM_CHANNEL_FC;
5008 lchannel_mapping[3] = use_back_flavor ?
5009 PCM_CHANNEL_LB : PCM_CHANNEL_LS;
5010 lchannel_mapping[4] = use_back_flavor ?
5011 PCM_CHANNEL_RB : PCM_CHANNEL_RS;
5012 } else if (channels == 6) {
5013 lchannel_mapping[0] = PCM_CHANNEL_FL;
5014 lchannel_mapping[1] = PCM_CHANNEL_FR;
5015 lchannel_mapping[2] = PCM_CHANNEL_FC;
5016 lchannel_mapping[3] = PCM_CHANNEL_LFE;
5017 lchannel_mapping[4] = use_back_flavor ?
5018 PCM_CHANNEL_LB : PCM_CHANNEL_LS;
5019 lchannel_mapping[5] = use_back_flavor ?
5020 PCM_CHANNEL_RB : PCM_CHANNEL_RS;
5021 } else if (channels == 7) {
5022 /*
5023 * Configured for 5.1 channel mapping + 1 channel for debug
5024 * Can be customized based on DSP.
5025 */
5026 lchannel_mapping[0] = PCM_CHANNEL_FL;
5027 lchannel_mapping[1] = PCM_CHANNEL_FR;
5028 lchannel_mapping[2] = PCM_CHANNEL_FC;
5029 lchannel_mapping[3] = PCM_CHANNEL_LFE;
5030 lchannel_mapping[4] = use_back_flavor ?
5031 PCM_CHANNEL_LB : PCM_CHANNEL_LS;
5032 lchannel_mapping[5] = use_back_flavor ?
5033 PCM_CHANNEL_RB : PCM_CHANNEL_RS;
5034 lchannel_mapping[6] = PCM_CHANNEL_CS;
5035 } else if (channels == 8) {
5036 lchannel_mapping[0] = PCM_CHANNEL_FL;
5037 lchannel_mapping[1] = PCM_CHANNEL_FR;
5038 lchannel_mapping[2] = PCM_CHANNEL_FC;
5039 lchannel_mapping[3] = PCM_CHANNEL_LFE;
5040 lchannel_mapping[4] = PCM_CHANNEL_LB;
5041 lchannel_mapping[5] = PCM_CHANNEL_RB;
5042 lchannel_mapping[6] = PCM_CHANNEL_LS;
5043 lchannel_mapping[7] = PCM_CHANNEL_RS;
5044 } else {
5045 pr_err("%s: ERROR.unsupported num_ch = %u\n",
5046 __func__, channels);
5047 return -EINVAL;
5048 }
5049 return 0;
5050}
5051
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305052/**
5053 * q6asm_enable_sbrps -
5054 * command to enable sbrps for ASM
5055 *
5056 * @ac: Audio client handle
5057 * @sbr_ps_enable: flag for sbr_ps enable or disable
5058 *
5059 * Returns 0 on success or error on failure
5060 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305061int q6asm_enable_sbrps(struct audio_client *ac,
5062 uint32_t sbr_ps_enable)
5063{
5064 struct asm_aac_sbr_ps_flag_param sbrps;
5065 u32 frames_per_buf = 0;
5066
5067 int rc = 0;
5068
5069 pr_debug("%s: Session %d\n", __func__, ac->session);
5070
5071 q6asm_add_hdr(ac, &sbrps.hdr, sizeof(sbrps), TRUE);
5072 atomic_set(&ac->cmd_state, -1);
5073
5074 sbrps.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
5075 sbrps.encdec.param_id = ASM_PARAM_ID_AAC_SBR_PS_FLAG;
5076 sbrps.encdec.param_size = sizeof(struct asm_aac_sbr_ps_flag_param) -
5077 sizeof(struct asm_stream_cmd_set_encdec_param);
5078 sbrps.encblk.frames_per_buf = frames_per_buf;
5079 sbrps.encblk.enc_cfg_blk_size = sbrps.encdec.param_size -
5080 sizeof(struct asm_enc_cfg_blk_param_v2);
5081
5082 sbrps.sbr_ps_flag = sbr_ps_enable;
5083
5084 rc = apr_send_pkt(ac->apr, (uint32_t *) &sbrps);
5085 if (rc < 0) {
5086 pr_err("%s: Command opcode[0x%x]paramid[0x%x] failed %d\n",
5087 __func__,
5088 ASM_STREAM_CMD_SET_ENCDEC_PARAM,
5089 ASM_PARAM_ID_AAC_SBR_PS_FLAG, rc);
5090 rc = -EINVAL;
5091 goto fail_cmd;
5092 }
5093 rc = wait_event_timeout(ac->cmd_wait,
5094 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5095 if (!rc) {
5096 pr_err("%s: timeout opcode[0x%x] ", __func__, sbrps.hdr.opcode);
5097 rc = -ETIMEDOUT;
5098 goto fail_cmd;
5099 }
5100 if (atomic_read(&ac->cmd_state) > 0) {
5101 pr_err("%s: DSP returned error[%s]\n",
5102 __func__, adsp_err_get_err_str(
5103 atomic_read(&ac->cmd_state)));
5104 rc = adsp_err_get_lnx_err_code(
5105 atomic_read(&ac->cmd_state));
5106 goto fail_cmd;
5107 }
5108 return 0;
5109fail_cmd:
5110 return rc;
5111}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305112EXPORT_SYMBOL(q6asm_enable_sbrps);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305113
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305114/**
5115 * q6asm_cfg_dual_mono_aac -
5116 * command to set config for dual mono aac
5117 *
5118 * @ac: Audio client handle
5119 * @sce_left: left sce val
5120 * @sce_right: right sce val
5121 *
5122 * Returns 0 on success or error on failure
5123 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305124int q6asm_cfg_dual_mono_aac(struct audio_client *ac,
5125 uint16_t sce_left, uint16_t sce_right)
5126{
5127 struct asm_aac_dual_mono_mapping_param dual_mono;
5128
5129 int rc = 0;
5130
5131 pr_debug("%s: Session %d, sce_left = %d, sce_right = %d\n",
5132 __func__, ac->session, sce_left, sce_right);
5133
5134 q6asm_add_hdr(ac, &dual_mono.hdr, sizeof(dual_mono), TRUE);
5135 atomic_set(&ac->cmd_state, -1);
5136
5137 dual_mono.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
5138 dual_mono.encdec.param_id = ASM_PARAM_ID_AAC_DUAL_MONO_MAPPING;
5139 dual_mono.encdec.param_size = sizeof(dual_mono.left_channel_sce) +
5140 sizeof(dual_mono.right_channel_sce);
5141 dual_mono.left_channel_sce = sce_left;
5142 dual_mono.right_channel_sce = sce_right;
5143
5144 rc = apr_send_pkt(ac->apr, (uint32_t *) &dual_mono);
5145 if (rc < 0) {
5146 pr_err("%s: Command opcode[0x%x]paramid[0x%x] failed %d\n",
5147 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM,
5148 ASM_PARAM_ID_AAC_DUAL_MONO_MAPPING, rc);
5149 rc = -EINVAL;
5150 goto fail_cmd;
5151 }
5152 rc = wait_event_timeout(ac->cmd_wait,
5153 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5154 if (!rc) {
5155 pr_err("%s: timeout opcode[0x%x]\n", __func__,
5156 dual_mono.hdr.opcode);
5157 rc = -ETIMEDOUT;
5158 goto fail_cmd;
5159 }
5160 if (atomic_read(&ac->cmd_state) > 0) {
5161 pr_err("%s: DSP returned error[%s]\n",
5162 __func__, adsp_err_get_err_str(
5163 atomic_read(&ac->cmd_state)));
5164 rc = adsp_err_get_lnx_err_code(
5165 atomic_read(&ac->cmd_state));
5166 goto fail_cmd;
5167 }
5168 return 0;
5169fail_cmd:
5170 return rc;
5171}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305172EXPORT_SYMBOL(q6asm_cfg_dual_mono_aac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305173
5174/* Support for selecting stereo mixing coefficients for B family not done */
5175int q6asm_cfg_aac_sel_mix_coef(struct audio_client *ac, uint32_t mix_coeff)
5176{
5177 struct asm_aac_stereo_mix_coeff_selection_param_v2 aac_mix_coeff;
5178 int rc = 0;
5179
5180 q6asm_add_hdr(ac, &aac_mix_coeff.hdr, sizeof(aac_mix_coeff), TRUE);
5181 atomic_set(&ac->cmd_state, -1);
5182 aac_mix_coeff.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
5183 aac_mix_coeff.param_id =
5184 ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG_V2;
5185 aac_mix_coeff.param_size =
5186 sizeof(struct asm_aac_stereo_mix_coeff_selection_param_v2);
5187 aac_mix_coeff.aac_stereo_mix_coeff_flag = mix_coeff;
5188 pr_debug("%s: mix_coeff = %u\n", __func__, mix_coeff);
5189 rc = apr_send_pkt(ac->apr, (uint32_t *) &aac_mix_coeff);
5190 if (rc < 0) {
5191 pr_err("%s: Command opcode[0x%x]paramid[0x%x] failed %d\n",
5192 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM,
5193 ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG_V2,
5194 rc);
5195 rc = -EINVAL;
5196 goto fail_cmd;
5197 }
5198 rc = wait_event_timeout(ac->cmd_wait,
5199 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5200 if (!rc) {
5201 pr_err("%s: timeout opcode[0x%x]\n",
5202 __func__, aac_mix_coeff.hdr.opcode);
5203 rc = -ETIMEDOUT;
5204 goto fail_cmd;
5205 }
5206 if (atomic_read(&ac->cmd_state) > 0) {
5207 pr_err("%s: DSP returned error[%s]\n",
5208 __func__, adsp_err_get_err_str(
5209 atomic_read(&ac->cmd_state)));
5210 rc = adsp_err_get_lnx_err_code(
5211 atomic_read(&ac->cmd_state));
5212 goto fail_cmd;
5213 }
5214 return 0;
5215fail_cmd:
5216 return rc;
5217}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305218EXPORT_SYMBOL(q6asm_cfg_aac_sel_mix_coef);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305219
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305220/**
5221 * q6asm_enc_cfg_blk_qcelp -
5222 * command to set encode config block for QCELP
5223 *
5224 * @ac: Audio client handle
5225 * @frames_per_buf: Number of frames per buffer
5226 * @min_rate: Minimum Enc rate
5227 * @max_rate: Maximum Enc rate
5228 * reduced_rate_level: Reduced rate level
5229 * @rate_modulation_cmd: rate modulation command
5230 *
5231 * Returns 0 on success or error on failure
5232 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305233int q6asm_enc_cfg_blk_qcelp(struct audio_client *ac, uint32_t frames_per_buf,
5234 uint16_t min_rate, uint16_t max_rate,
5235 uint16_t reduced_rate_level, uint16_t rate_modulation_cmd)
5236{
5237 struct asm_v13k_enc_cfg enc_cfg;
5238 int rc = 0;
5239
5240 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",
5241 __func__,
5242 ac->session, frames_per_buf, min_rate, max_rate,
5243 reduced_rate_level, rate_modulation_cmd);
5244
5245 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
5246 atomic_set(&ac->cmd_state, -1);
5247 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
5248 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
5249 enc_cfg.encdec.param_size = sizeof(struct asm_v13k_enc_cfg) -
5250 sizeof(struct asm_stream_cmd_set_encdec_param);
5251 enc_cfg.encblk.frames_per_buf = frames_per_buf;
5252 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
5253 sizeof(struct asm_enc_cfg_blk_param_v2);
5254
5255 enc_cfg.min_rate = min_rate;
5256 enc_cfg.max_rate = max_rate;
5257 enc_cfg.reduced_rate_cmd = reduced_rate_level;
5258 enc_cfg.rate_mod_cmd = rate_modulation_cmd;
5259
5260 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
5261 if (rc < 0) {
5262 pr_err("%s: Comamnd %d failed %d\n",
5263 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
5264 rc = -EINVAL;
5265 goto fail_cmd;
5266 }
5267 rc = wait_event_timeout(ac->cmd_wait,
5268 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5269 if (!rc) {
5270 pr_err("%s: timeout. waited for setencdec v13k resp\n",
5271 __func__);
5272 rc = -ETIMEDOUT;
5273 goto fail_cmd;
5274 }
5275 if (atomic_read(&ac->cmd_state) > 0) {
5276 pr_err("%s: DSP returned error[%s]\n",
5277 __func__, adsp_err_get_err_str(
5278 atomic_read(&ac->cmd_state)));
5279 rc = adsp_err_get_lnx_err_code(
5280 atomic_read(&ac->cmd_state));
5281 goto fail_cmd;
5282 }
5283 return 0;
5284fail_cmd:
5285 return rc;
5286}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305287EXPORT_SYMBOL(q6asm_enc_cfg_blk_qcelp);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305288
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305289/**
5290 * q6asm_enc_cfg_blk_evrc -
5291 * command to set encode config block for EVRC
5292 *
5293 * @ac: Audio client handle
5294 * @frames_per_buf: Number of frames per buffer
5295 * @min_rate: Minimum Enc rate
5296 * @max_rate: Maximum Enc rate
5297 * @rate_modulation_cmd: rate modulation command
5298 *
5299 * Returns 0 on success or error on failure
5300 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305301int q6asm_enc_cfg_blk_evrc(struct audio_client *ac, uint32_t frames_per_buf,
5302 uint16_t min_rate, uint16_t max_rate,
5303 uint16_t rate_modulation_cmd)
5304{
5305 struct asm_evrc_enc_cfg enc_cfg;
5306 int rc = 0;
5307
5308 pr_debug("%s: session[%d]frames[%d]min_rate[0x%4x]max_rate[0x%4x] rate_modulation_cmd[0x%4x]\n",
5309 __func__, ac->session,
5310 frames_per_buf, min_rate, max_rate, rate_modulation_cmd);
5311
5312 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
5313 atomic_set(&ac->cmd_state, -1);
5314 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
5315 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
5316 enc_cfg.encdec.param_size = sizeof(struct asm_evrc_enc_cfg) -
5317 sizeof(struct asm_stream_cmd_set_encdec_param);
5318 enc_cfg.encblk.frames_per_buf = frames_per_buf;
5319 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
5320 sizeof(struct asm_enc_cfg_blk_param_v2);
5321
5322 enc_cfg.min_rate = min_rate;
5323 enc_cfg.max_rate = max_rate;
5324 enc_cfg.rate_mod_cmd = rate_modulation_cmd;
5325 enc_cfg.reserved = 0;
5326
5327 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
5328 if (rc < 0) {
5329 pr_err("%s: Comamnd %d failed %d\n",
5330 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
5331 rc = -EINVAL;
5332 goto fail_cmd;
5333 }
5334 rc = wait_event_timeout(ac->cmd_wait,
5335 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5336 if (!rc) {
5337 pr_err("%s: timeout. waited for encdec evrc\n", __func__);
5338 rc = -ETIMEDOUT;
5339 goto fail_cmd;
5340 }
5341 if (atomic_read(&ac->cmd_state) > 0) {
5342 pr_err("%s: DSP returned error[%s]\n",
5343 __func__, adsp_err_get_err_str(
5344 atomic_read(&ac->cmd_state)));
5345 rc = adsp_err_get_lnx_err_code(
5346 atomic_read(&ac->cmd_state));
5347 goto fail_cmd;
5348 }
5349 return 0;
5350fail_cmd:
5351 return rc;
5352}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305353EXPORT_SYMBOL(q6asm_enc_cfg_blk_evrc);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305354
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305355/**
5356 * q6asm_enc_cfg_blk_amrnb -
5357 * command to set encode config block for AMRNB
5358 *
5359 * @ac: Audio client handle
5360 * @frames_per_buf: Number of frames per buffer
5361 * @band_mode: Band mode used
5362 * @dtx_enable: DTX en flag
5363 *
5364 * Returns 0 on success or error on failure
5365 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305366int q6asm_enc_cfg_blk_amrnb(struct audio_client *ac, uint32_t frames_per_buf,
5367 uint16_t band_mode, uint16_t dtx_enable)
5368{
5369 struct asm_amrnb_enc_cfg enc_cfg;
5370 int rc = 0;
5371
5372 pr_debug("%s: session[%d]frames[%d]band_mode[0x%4x]dtx_enable[0x%4x]\n",
5373 __func__, ac->session, frames_per_buf, band_mode, dtx_enable);
5374
5375 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
5376 atomic_set(&ac->cmd_state, -1);
5377 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
5378 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
5379 enc_cfg.encdec.param_size = sizeof(struct asm_amrnb_enc_cfg) -
5380 sizeof(struct asm_stream_cmd_set_encdec_param);
5381 enc_cfg.encblk.frames_per_buf = frames_per_buf;
5382 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
5383 sizeof(struct asm_enc_cfg_blk_param_v2);
5384
5385 enc_cfg.enc_mode = band_mode;
5386 enc_cfg.dtx_mode = dtx_enable;
5387
5388 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
5389 if (rc < 0) {
5390 pr_err("%s: Comamnd %d failed %d\n",
5391 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
5392 rc = -EINVAL;
5393 goto fail_cmd;
5394 }
5395 rc = wait_event_timeout(ac->cmd_wait,
5396 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5397 if (!rc) {
5398 pr_err("%s: timeout. waited for set encdec amrnb\n", __func__);
5399 rc = -ETIMEDOUT;
5400 goto fail_cmd;
5401 }
5402 if (atomic_read(&ac->cmd_state) > 0) {
5403 pr_err("%s: DSP returned error[%s]\n",
5404 __func__, adsp_err_get_err_str(
5405 atomic_read(&ac->cmd_state)));
5406 rc = adsp_err_get_lnx_err_code(
5407 atomic_read(&ac->cmd_state));
5408 goto fail_cmd;
5409 }
5410 return 0;
5411fail_cmd:
5412 return rc;
5413}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305414EXPORT_SYMBOL(q6asm_enc_cfg_blk_amrnb);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305415
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305416/**
5417 * q6asm_enc_cfg_blk_amrwb -
5418 * command to set encode config block for AMRWB
5419 *
5420 * @ac: Audio client handle
5421 * @frames_per_buf: Number of frames per buffer
5422 * @band_mode: Band mode used
5423 * @dtx_enable: DTX en flag
5424 *
5425 * Returns 0 on success or error on failure
5426 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305427int q6asm_enc_cfg_blk_amrwb(struct audio_client *ac, uint32_t frames_per_buf,
5428 uint16_t band_mode, uint16_t dtx_enable)
5429{
5430 struct asm_amrwb_enc_cfg enc_cfg;
5431 int rc = 0;
5432
5433 pr_debug("%s: session[%d]frames[%d]band_mode[0x%4x]dtx_enable[0x%4x]\n",
5434 __func__, ac->session, frames_per_buf, band_mode, dtx_enable);
5435
5436 q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
5437 atomic_set(&ac->cmd_state, -1);
5438 enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
5439 enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
5440 enc_cfg.encdec.param_size = sizeof(struct asm_amrwb_enc_cfg) -
5441 sizeof(struct asm_stream_cmd_set_encdec_param);
5442 enc_cfg.encblk.frames_per_buf = frames_per_buf;
5443 enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
5444 sizeof(struct asm_enc_cfg_blk_param_v2);
5445
5446 enc_cfg.enc_mode = band_mode;
5447 enc_cfg.dtx_mode = dtx_enable;
5448
5449 rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
5450 if (rc < 0) {
5451 pr_err("%s: Comamnd %d failed %d\n",
5452 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
5453 rc = -EINVAL;
5454 goto fail_cmd;
5455 }
5456 rc = wait_event_timeout(ac->cmd_wait,
5457 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5458 if (!rc) {
5459 pr_err("%s: timeout. waited for FORMAT_UPDATE\n", __func__);
5460 rc = -ETIMEDOUT;
5461 goto fail_cmd;
5462 }
5463 if (atomic_read(&ac->cmd_state) > 0) {
5464 pr_err("%s: DSP returned error[%s]\n",
5465 __func__, adsp_err_get_err_str(
5466 atomic_read(&ac->cmd_state)));
5467 rc = adsp_err_get_lnx_err_code(
5468 atomic_read(&ac->cmd_state));
5469 goto fail_cmd;
5470 }
5471 return 0;
5472fail_cmd:
5473 return rc;
5474}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305475EXPORT_SYMBOL(q6asm_enc_cfg_blk_amrwb);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305476
5477
5478static int __q6asm_media_format_block_pcm(struct audio_client *ac,
5479 uint32_t rate, uint32_t channels,
5480 uint16_t bits_per_sample, int stream_id,
5481 bool use_default_chmap, char *channel_map)
5482{
5483 struct asm_multi_channel_pcm_fmt_blk_v2 fmt;
5484 u8 *channel_mapping;
5485 int rc = 0;
5486
Rohit kumar6a14cfb2019-02-04 11:22:49 +05305487 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
5488 pr_err("%s: Invalid channel count %d\n", __func__, channels);
5489 return -EINVAL;
5490 }
5491
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305492 pr_debug("%s: session[%d]rate[%d]ch[%d]\n", __func__, ac->session, rate,
5493 channels);
5494
5495 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
5496 atomic_set(&ac->cmd_state, -1);
5497 /*
5498 * Updated the token field with stream/session for compressed playback
5499 * Platform driver must know the the stream with which the command is
5500 * associated
5501 */
5502 if (ac->io_mode & COMPRESSED_STREAM_IO)
5503 q6asm_update_token(&fmt.hdr.token,
5504 ac->session,
5505 stream_id,
5506 0, /* Buffer index is NA */
5507 0, /* Direction flag is NA */
5508 WAIT_CMD);
5509
5510 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
5511 __func__, fmt.hdr.token, stream_id, ac->session);
5512
5513 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
5514 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
5515 sizeof(fmt.fmt_blk);
5516 fmt.num_channels = channels;
5517 fmt.bits_per_sample = bits_per_sample;
5518 fmt.sample_rate = rate;
5519 fmt.is_signed = 1;
5520
5521 channel_mapping = fmt.channel_mapping;
5522
5523 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
5524
5525 if (use_default_chmap) {
5526 if (q6asm_map_channels(channel_mapping, channels, false)) {
5527 pr_err("%s: map channels failed %d\n",
5528 __func__, channels);
5529 return -EINVAL;
5530 }
5531 } else {
5532 memcpy(channel_mapping, channel_map,
5533 PCM_FORMAT_MAX_NUM_CHANNEL);
5534 }
5535
5536 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
5537 if (rc < 0) {
5538 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
5539 rc = -EINVAL;
5540 goto fail_cmd;
5541 }
5542 rc = wait_event_timeout(ac->cmd_wait,
5543 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5544 if (!rc) {
5545 pr_err("%s: timeout. waited for format update\n", __func__);
5546 rc = -ETIMEDOUT;
5547 goto fail_cmd;
5548 }
5549 if (atomic_read(&ac->cmd_state) > 0) {
5550 pr_err("%s: DSP returned error[%s]\n",
5551 __func__, adsp_err_get_err_str(
5552 atomic_read(&ac->cmd_state)));
5553 rc = adsp_err_get_lnx_err_code(
5554 atomic_read(&ac->cmd_state));
5555 goto fail_cmd;
5556 }
5557 return 0;
5558fail_cmd:
5559 return rc;
5560}
5561
5562static int __q6asm_media_format_block_pcm_v3(struct audio_client *ac,
5563 uint32_t rate, uint32_t channels,
5564 uint16_t bits_per_sample,
5565 int stream_id,
5566 bool use_default_chmap,
5567 char *channel_map,
5568 uint16_t sample_word_size)
5569{
5570 struct asm_multi_channel_pcm_fmt_blk_param_v3 fmt;
5571 u8 *channel_mapping;
5572 int rc;
5573
Rohit kumar6a14cfb2019-02-04 11:22:49 +05305574 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
5575 pr_err("%s: Invalid channel count %d\n", __func__, channels);
5576 return -EINVAL;
5577 }
5578
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305579 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
5580 ac->session, rate, channels,
5581 bits_per_sample, sample_word_size);
5582
5583 memset(&fmt, 0, sizeof(fmt));
5584 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
5585 atomic_set(&ac->cmd_state, -1);
5586 /*
5587 * Updated the token field with stream/session for compressed playback
5588 * Platform driver must know the the stream with which the command is
5589 * associated
5590 */
5591 if (ac->io_mode & COMPRESSED_STREAM_IO)
5592 fmt.hdr.token = ((ac->session << 8) & 0xFFFF00) |
5593 (stream_id & 0xFF);
5594
5595 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
5596 __func__, fmt.hdr.token, stream_id, ac->session);
5597
5598 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
5599 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
5600 sizeof(fmt.fmt_blk);
5601 fmt.param.num_channels = channels;
5602 fmt.param.bits_per_sample = bits_per_sample;
5603 fmt.param.sample_rate = rate;
5604 fmt.param.is_signed = 1;
5605 fmt.param.sample_word_size = sample_word_size;
5606 channel_mapping = fmt.param.channel_mapping;
5607
5608 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
5609
5610 if (use_default_chmap) {
5611 if (q6asm_map_channels(channel_mapping, channels, false)) {
5612 pr_err("%s: map channels failed %d\n",
5613 __func__, channels);
5614 rc = -EINVAL;
5615 goto fail_cmd;
5616 }
5617 } else {
5618 memcpy(channel_mapping, channel_map,
5619 PCM_FORMAT_MAX_NUM_CHANNEL);
5620 }
5621
5622 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
5623 if (rc < 0) {
5624 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
5625 rc = -EINVAL;
5626 goto fail_cmd;
5627 }
5628 rc = wait_event_timeout(ac->cmd_wait,
5629 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5630 if (!rc) {
5631 pr_err("%s: timeout. waited for format update\n", __func__);
5632 rc = -ETIMEDOUT;
5633 goto fail_cmd;
5634 }
5635 if (atomic_read(&ac->cmd_state) > 0) {
5636 pr_err("%s: DSP returned error[%s]\n",
5637 __func__, adsp_err_get_err_str(
5638 atomic_read(&ac->cmd_state)));
5639 rc = adsp_err_get_lnx_err_code(
5640 atomic_read(&ac->cmd_state));
5641 goto fail_cmd;
5642 }
5643 return 0;
5644fail_cmd:
5645 return rc;
5646}
5647
5648static int __q6asm_media_format_block_pcm_v4(struct audio_client *ac,
5649 uint32_t rate, uint32_t channels,
5650 uint16_t bits_per_sample,
5651 int stream_id,
5652 bool use_default_chmap,
5653 char *channel_map,
5654 uint16_t sample_word_size,
5655 uint16_t endianness,
5656 uint16_t mode)
5657{
5658 struct asm_multi_channel_pcm_fmt_blk_param_v4 fmt;
5659 u8 *channel_mapping;
5660 int rc;
5661
Rohit kumar6a14cfb2019-02-04 11:22:49 +05305662 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
5663 pr_err("%s: Invalid channel count %d\n", __func__, channels);
5664 return -EINVAL;
5665 }
5666
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305667 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
5668 ac->session, rate, channels,
5669 bits_per_sample, sample_word_size);
5670
5671 memset(&fmt, 0, sizeof(fmt));
5672 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
5673 atomic_set(&ac->cmd_state, -1);
5674 /*
5675 * Updated the token field with stream/session for compressed playback
5676 * Platform driver must know the the stream with which the command is
5677 * associated
5678 */
5679 if (ac->io_mode & COMPRESSED_STREAM_IO)
5680 fmt.hdr.token = ((ac->session << 8) & 0xFFFF00) |
5681 (stream_id & 0xFF);
5682
5683 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
5684 __func__, fmt.hdr.token, stream_id, ac->session);
5685
5686 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
5687 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
5688 sizeof(fmt.fmt_blk);
5689 fmt.param.num_channels = channels;
5690 fmt.param.bits_per_sample = bits_per_sample;
5691 fmt.param.sample_rate = rate;
5692 fmt.param.is_signed = 1;
5693 fmt.param.sample_word_size = sample_word_size;
5694 fmt.param.endianness = endianness;
5695 fmt.param.mode = mode;
5696 channel_mapping = fmt.param.channel_mapping;
5697
5698 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
5699
5700 if (use_default_chmap) {
5701 if (q6asm_map_channels(channel_mapping, channels, false)) {
5702 pr_err("%s: map channels failed %d\n",
5703 __func__, channels);
5704 rc = -EINVAL;
5705 goto fail_cmd;
5706 }
5707 } else {
5708 memcpy(channel_mapping, channel_map,
5709 PCM_FORMAT_MAX_NUM_CHANNEL);
5710 }
5711
5712 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
5713 if (rc < 0) {
5714 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
5715 rc = -EINVAL;
5716 goto fail_cmd;
5717 }
5718 rc = wait_event_timeout(ac->cmd_wait,
5719 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5720 if (!rc) {
5721 pr_err("%s: timeout. waited for format update\n", __func__);
5722 rc = -ETIMEDOUT;
5723 goto fail_cmd;
5724 }
5725 if (atomic_read(&ac->cmd_state) > 0) {
5726 pr_err("%s: DSP returned error[%s]\n",
5727 __func__, adsp_err_get_err_str(
5728 atomic_read(&ac->cmd_state)));
5729 rc = adsp_err_get_lnx_err_code(
5730 atomic_read(&ac->cmd_state));
5731 goto fail_cmd;
5732 }
5733 return 0;
5734fail_cmd:
5735 return rc;
5736}
5737
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305738/**
5739 * q6asm_media_format_block_pcm -
5740 * command to set mediafmt block for PCM on ASM stream
5741 *
5742 * @ac: Audio client handle
5743 * @rate: sample rate
5744 * @channels: number of ASM channels
5745 *
5746 * Returns 0 on success or error on failure
5747 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305748int q6asm_media_format_block_pcm(struct audio_client *ac,
5749 uint32_t rate, uint32_t channels)
5750{
5751 return __q6asm_media_format_block_pcm(ac, rate,
5752 channels, 16, ac->stream_id,
5753 true, NULL);
5754}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305755EXPORT_SYMBOL(q6asm_media_format_block_pcm);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305756
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305757/**
5758 * q6asm_media_format_block_pcm_format_support -
5759 * command to set mediafmt block for PCM format support
5760 *
5761 * @ac: Audio client handle
5762 * @rate: sample rate
5763 * @channels: number of ASM channels
5764 * @bits_per_sample: number of bits per sample
5765 *
5766 * Returns 0 on success or error on failure
5767 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305768int q6asm_media_format_block_pcm_format_support(struct audio_client *ac,
5769 uint32_t rate, uint32_t channels,
5770 uint16_t bits_per_sample)
5771{
5772 return __q6asm_media_format_block_pcm(ac, rate,
5773 channels, bits_per_sample, ac->stream_id,
5774 true, NULL);
5775}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05305776EXPORT_SYMBOL(q6asm_media_format_block_pcm_format_support);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305777
5778int q6asm_media_format_block_pcm_format_support_v2(struct audio_client *ac,
5779 uint32_t rate, uint32_t channels,
5780 uint16_t bits_per_sample, int stream_id,
5781 bool use_default_chmap, char *channel_map)
5782{
5783 if (!use_default_chmap && (channel_map == NULL)) {
5784 pr_err("%s: No valid chan map and can't use default\n",
5785 __func__);
5786 return -EINVAL;
5787 }
5788 return __q6asm_media_format_block_pcm(ac, rate,
5789 channels, bits_per_sample, stream_id,
5790 use_default_chmap, channel_map);
5791}
5792
5793/*
5794 * q6asm_media_format_block_pcm_format_support_v3- sends pcm decoder
5795 * configuration parameters
5796 *
5797 * @ac: Client session handle
5798 * @rate: sample rate
5799 * @channels: number of channels
5800 * @bits_per_sample: bit width of encoder session
5801 * @stream_id: stream id of stream to be associated with this session
5802 * @use_default_chmap: true if default channel map to be used
5803 * @channel_map: input channel map
5804 * @sample_word_size: Size in bits of the word that holds a sample of a channel
5805 */
5806int q6asm_media_format_block_pcm_format_support_v3(struct audio_client *ac,
5807 uint32_t rate,
5808 uint32_t channels,
5809 uint16_t bits_per_sample,
5810 int stream_id,
5811 bool use_default_chmap,
5812 char *channel_map,
5813 uint16_t sample_word_size)
5814{
5815 if (!use_default_chmap && (channel_map == NULL)) {
5816 pr_err("%s: No valid chan map and can't use default\n",
5817 __func__);
5818 return -EINVAL;
5819 }
5820 return __q6asm_media_format_block_pcm_v3(ac, rate,
5821 channels, bits_per_sample, stream_id,
5822 use_default_chmap, channel_map,
5823 sample_word_size);
5824
5825}
5826EXPORT_SYMBOL(q6asm_media_format_block_pcm_format_support_v3);
5827
5828/*
5829 * q6asm_media_format_block_pcm_format_support_v4- sends pcm decoder
5830 * configuration parameters
5831 *
5832 * @ac: Client session handle
5833 * @rate: sample rate
5834 * @channels: number of channels
5835 * @bits_per_sample: bit width of encoder session
5836 * @stream_id: stream id of stream to be associated with this session
5837 * @use_default_chmap: true if default channel map to be used
5838 * @channel_map: input channel map
5839 * @sample_word_size: Size in bits of the word that holds a sample of a channel
5840 * @endianness: endianness of the pcm data
5841 * @mode: Mode to provide additional info about the pcm input data
5842 */
5843int q6asm_media_format_block_pcm_format_support_v4(struct audio_client *ac,
5844 uint32_t rate,
5845 uint32_t channels,
5846 uint16_t bits_per_sample,
5847 int stream_id,
5848 bool use_default_chmap,
5849 char *channel_map,
5850 uint16_t sample_word_size,
5851 uint16_t endianness,
5852 uint16_t mode)
5853{
5854 if (!use_default_chmap && (channel_map == NULL)) {
5855 pr_err("%s: No valid chan map and can't use default\n",
5856 __func__);
5857 return -EINVAL;
5858 }
5859 return __q6asm_media_format_block_pcm_v4(ac, rate,
5860 channels, bits_per_sample, stream_id,
5861 use_default_chmap, channel_map,
5862 sample_word_size, endianness,
5863 mode);
5864
5865}
5866EXPORT_SYMBOL(q6asm_media_format_block_pcm_format_support_v4);
5867
5868
5869static int __q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
5870 uint32_t rate, uint32_t channels,
5871 bool use_default_chmap, char *channel_map,
5872 uint16_t bits_per_sample)
5873{
5874 struct asm_multi_channel_pcm_fmt_blk_v2 fmt;
5875 u8 *channel_mapping;
5876 int rc = 0;
5877
Rohit kumar6a14cfb2019-02-04 11:22:49 +05305878 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
5879 pr_err("%s: Invalid channel count %d\n", __func__, channels);
5880 return -EINVAL;
5881 }
5882
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305883 pr_debug("%s: session[%d]rate[%d]ch[%d]\n", __func__, ac->session, rate,
5884 channels);
5885
5886 q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
5887 atomic_set(&ac->cmd_state, -1);
5888
5889 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
5890 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
5891 sizeof(fmt.fmt_blk);
5892 fmt.num_channels = channels;
5893 fmt.bits_per_sample = bits_per_sample;
5894 fmt.sample_rate = rate;
5895 fmt.is_signed = 1;
5896
5897 channel_mapping = fmt.channel_mapping;
5898
5899 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
5900
5901 if (use_default_chmap) {
5902 if (q6asm_map_channels(channel_mapping, channels, false)) {
5903 pr_err("%s: map channels failed %d\n",
5904 __func__, channels);
5905 return -EINVAL;
5906 }
5907 } else {
5908 memcpy(channel_mapping, channel_map,
5909 PCM_FORMAT_MAX_NUM_CHANNEL);
5910 }
5911
5912 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
5913 if (rc < 0) {
5914 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
5915 rc = -EINVAL;
5916 goto fail_cmd;
5917 }
5918 rc = wait_event_timeout(ac->cmd_wait,
5919 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5920 if (!rc) {
5921 pr_err("%s: timeout. waited for format update\n", __func__);
5922 rc = -ETIMEDOUT;
5923 goto fail_cmd;
5924 }
5925 if (atomic_read(&ac->cmd_state) > 0) {
5926 pr_err("%s: DSP returned error[%s]\n",
5927 __func__, adsp_err_get_err_str(
5928 atomic_read(&ac->cmd_state)));
5929 rc = adsp_err_get_lnx_err_code(
5930 atomic_read(&ac->cmd_state));
5931 goto fail_cmd;
5932 }
5933 return 0;
5934fail_cmd:
5935 return rc;
5936}
5937
5938static int __q6asm_media_format_block_multi_ch_pcm_v3(struct audio_client *ac,
5939 uint32_t rate,
5940 uint32_t channels,
5941 bool use_default_chmap,
5942 char *channel_map,
5943 uint16_t bits_per_sample,
5944 uint16_t sample_word_size)
5945{
5946 struct asm_multi_channel_pcm_fmt_blk_param_v3 fmt;
5947 u8 *channel_mapping;
5948 int rc;
5949
Rohit kumar6a14cfb2019-02-04 11:22:49 +05305950 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
5951 pr_err("%s: Invalid channel count %d\n", __func__, channels);
5952 return -EINVAL;
5953 }
5954
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05305955 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
5956 ac->session, rate, channels,
5957 bits_per_sample, sample_word_size);
5958
5959 memset(&fmt, 0, sizeof(fmt));
5960 q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
5961 atomic_set(&ac->cmd_state, -1);
5962
5963 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
5964 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
5965 sizeof(fmt.fmt_blk);
5966 fmt.param.num_channels = channels;
5967 fmt.param.bits_per_sample = bits_per_sample;
5968 fmt.param.sample_rate = rate;
5969 fmt.param.is_signed = 1;
5970 fmt.param.sample_word_size = sample_word_size;
5971 channel_mapping = fmt.param.channel_mapping;
5972
5973 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
5974
5975 if (use_default_chmap) {
5976 if (q6asm_map_channels(channel_mapping, channels, false)) {
5977 pr_err("%s: map channels failed %d\n",
5978 __func__, channels);
5979 rc = -EINVAL;
5980 goto fail_cmd;
5981 }
5982 } else {
5983 memcpy(channel_mapping, channel_map,
5984 PCM_FORMAT_MAX_NUM_CHANNEL);
5985 }
5986
5987 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
5988 if (rc < 0) {
5989 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
5990 goto fail_cmd;
5991 }
5992 rc = wait_event_timeout(ac->cmd_wait,
5993 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
5994 if (!rc) {
5995 pr_err("%s: timeout. waited for format update\n", __func__);
5996 rc = -ETIMEDOUT;
5997 goto fail_cmd;
5998 }
5999 if (atomic_read(&ac->cmd_state) > 0) {
6000 pr_err("%s: DSP returned error[%s]\n",
6001 __func__, adsp_err_get_err_str(
6002 atomic_read(&ac->cmd_state)));
6003 rc = adsp_err_get_lnx_err_code(
6004 atomic_read(&ac->cmd_state));
6005 goto fail_cmd;
6006 }
6007 return 0;
6008fail_cmd:
6009 return rc;
6010}
6011
6012static int __q6asm_media_format_block_multi_ch_pcm_v4(struct audio_client *ac,
6013 uint32_t rate,
6014 uint32_t channels,
6015 bool use_default_chmap,
6016 char *channel_map,
6017 uint16_t bits_per_sample,
6018 uint16_t sample_word_size,
6019 uint16_t endianness,
6020 uint16_t mode)
6021{
6022 struct asm_multi_channel_pcm_fmt_blk_param_v4 fmt;
6023 u8 *channel_mapping;
6024 int rc;
6025
Rohit kumar6a14cfb2019-02-04 11:22:49 +05306026 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
6027 pr_err("%s: Invalid channel count %d\n", __func__, channels);
6028 return -EINVAL;
6029 }
6030
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306031 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]wordsize[%d]\n", __func__,
6032 ac->session, rate, channels,
6033 bits_per_sample, sample_word_size);
6034
6035 memset(&fmt, 0, sizeof(fmt));
6036 q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
6037 atomic_set(&ac->cmd_state, -1);
6038
6039 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6040 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6041 sizeof(fmt.fmt_blk);
6042 fmt.param.num_channels = channels;
6043 fmt.param.bits_per_sample = bits_per_sample;
6044 fmt.param.sample_rate = rate;
6045 fmt.param.is_signed = 1;
6046 fmt.param.sample_word_size = sample_word_size;
6047 fmt.param.endianness = endianness;
6048 fmt.param.mode = mode;
6049 channel_mapping = fmt.param.channel_mapping;
6050
6051 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
6052
6053 if (use_default_chmap) {
6054 if (q6asm_map_channels(channel_mapping, channels, false)) {
6055 pr_err("%s: map channels failed %d\n",
6056 __func__, channels);
6057 rc = -EINVAL;
6058 goto fail_cmd;
6059 }
6060 } else {
6061 memcpy(channel_mapping, channel_map,
6062 PCM_FORMAT_MAX_NUM_CHANNEL);
6063 }
6064
6065 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6066 if (rc < 0) {
6067 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
6068 goto fail_cmd;
6069 }
6070 rc = wait_event_timeout(ac->cmd_wait,
6071 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6072 if (!rc) {
6073 pr_err("%s: timeout. waited for format update\n", __func__);
6074 rc = -ETIMEDOUT;
6075 goto fail_cmd;
6076 }
6077 if (atomic_read(&ac->cmd_state) > 0) {
6078 pr_err("%s: DSP returned error[%s]\n",
6079 __func__, adsp_err_get_err_str(
6080 atomic_read(&ac->cmd_state)));
6081 rc = adsp_err_get_lnx_err_code(
6082 atomic_read(&ac->cmd_state));
6083 goto fail_cmd;
6084 }
6085 return 0;
6086fail_cmd:
6087 return rc;
6088}
6089
6090int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
6091 uint32_t rate, uint32_t channels,
6092 bool use_default_chmap, char *channel_map)
6093{
6094 return __q6asm_media_format_block_multi_ch_pcm(ac, rate,
6095 channels, use_default_chmap, channel_map, 16);
6096}
6097
6098int q6asm_media_format_block_multi_ch_pcm_v2(
6099 struct audio_client *ac,
6100 uint32_t rate, uint32_t channels,
6101 bool use_default_chmap, char *channel_map,
6102 uint16_t bits_per_sample)
6103{
6104 return __q6asm_media_format_block_multi_ch_pcm(ac, rate,
6105 channels, use_default_chmap, channel_map,
6106 bits_per_sample);
6107}
6108
6109/*
6110 * q6asm_media_format_block_multi_ch_pcm_v3 - sends pcm decoder configuration
6111 * parameters
6112 *
6113 * @ac: Client session handle
6114 * @rate: sample rate
6115 * @channels: number of channels
6116 * @bits_per_sample: bit width of encoder session
6117 * @use_default_chmap: true if default channel map to be used
6118 * @channel_map: input channel map
6119 * @sample_word_size: Size in bits of the word that holds a sample of a channel
6120 */
6121int q6asm_media_format_block_multi_ch_pcm_v3(struct audio_client *ac,
6122 uint32_t rate, uint32_t channels,
6123 bool use_default_chmap,
6124 char *channel_map,
6125 uint16_t bits_per_sample,
6126 uint16_t sample_word_size)
6127{
6128 return __q6asm_media_format_block_multi_ch_pcm_v3(ac, rate, channels,
6129 use_default_chmap,
6130 channel_map,
6131 bits_per_sample,
6132 sample_word_size);
6133}
6134EXPORT_SYMBOL(q6asm_media_format_block_multi_ch_pcm_v3);
6135
6136/*
6137 * q6asm_media_format_block_multi_ch_pcm_v4 - sends pcm decoder configuration
6138 * parameters
6139 *
6140 * @ac: Client session handle
6141 * @rate: sample rate
6142 * @channels: number of channels
6143 * @bits_per_sample: bit width of encoder session
6144 * @use_default_chmap: true if default channel map to be used
6145 * @channel_map: input channel map
6146 * @sample_word_size: Size in bits of the word that holds a sample of a channel
6147 * @endianness: endianness of the pcm data
6148 * @mode: Mode to provide additional info about the pcm input data
6149 */
6150int q6asm_media_format_block_multi_ch_pcm_v4(struct audio_client *ac,
6151 uint32_t rate, uint32_t channels,
6152 bool use_default_chmap,
6153 char *channel_map,
6154 uint16_t bits_per_sample,
6155 uint16_t sample_word_size,
6156 uint16_t endianness,
6157 uint16_t mode)
6158{
6159 return __q6asm_media_format_block_multi_ch_pcm_v4(ac, rate, channels,
6160 use_default_chmap,
6161 channel_map,
6162 bits_per_sample,
6163 sample_word_size,
6164 endianness,
6165 mode);
6166}
6167EXPORT_SYMBOL(q6asm_media_format_block_multi_ch_pcm_v4);
6168
6169/*
6170 * q6asm_media_format_block_gen_compr - set up generic compress format params
6171 *
6172 * @ac: Client session handle
6173 * @rate: sample rate
6174 * @channels: number of channels
6175 * @use_default_chmap: true if default channel map to be used
6176 * @channel_map: input channel map
6177 * @bits_per_sample: bit width of gen compress stream
6178 */
6179int q6asm_media_format_block_gen_compr(struct audio_client *ac,
6180 uint32_t rate, uint32_t channels,
6181 bool use_default_chmap, char *channel_map,
6182 uint16_t bits_per_sample)
6183{
6184 struct asm_generic_compressed_fmt_blk_t fmt;
6185 u8 *channel_mapping;
6186 int rc = 0;
6187
Rohit kumar6a14cfb2019-02-04 11:22:49 +05306188 if (channels > PCM_FORMAT_MAX_NUM_CHANNEL) {
6189 pr_err("%s: Invalid channel count %d\n", __func__, channels);
6190 return -EINVAL;
6191 }
6192
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306193 pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]\n",
6194 __func__, ac->session, rate,
6195 channels, bits_per_sample);
6196
6197 memset(&fmt, 0, sizeof(fmt));
6198 q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
6199
6200 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6201 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6202 sizeof(fmt.fmt_blk);
6203 fmt.num_channels = channels;
6204 fmt.bits_per_sample = bits_per_sample;
6205 fmt.sampling_rate = rate;
6206
6207 channel_mapping = fmt.channel_mapping;
6208
6209 memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
6210
6211 if (use_default_chmap) {
6212 if (q6asm_map_channels(channel_mapping, channels, false)) {
6213 pr_err("%s: map channels failed %d\n",
6214 __func__, channels);
6215 return -EINVAL;
6216 }
6217 } else {
6218 memcpy(channel_mapping, channel_map,
6219 PCM_FORMAT_MAX_NUM_CHANNEL);
6220 }
6221
6222 atomic_set(&ac->cmd_state, -1);
6223 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6224 if (rc < 0) {
6225 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
6226 rc = -EINVAL;
6227 goto fail_cmd;
6228 }
6229 rc = wait_event_timeout(ac->cmd_wait,
6230 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6231 if (!rc) {
6232 pr_err("%s: timeout. waited for format update\n", __func__);
6233 rc = -ETIMEDOUT;
6234 goto fail_cmd;
6235 }
6236
6237 if (atomic_read(&ac->cmd_state) > 0) {
6238 pr_err("%s: DSP returned error[%s]\n",
6239 __func__, adsp_err_get_err_str(
6240 atomic_read(&ac->cmd_state)));
6241 rc = adsp_err_get_lnx_err_code(
6242 atomic_read(&ac->cmd_state));
6243 }
6244 return 0;
6245fail_cmd:
6246 return rc;
6247}
6248EXPORT_SYMBOL(q6asm_media_format_block_gen_compr);
6249
6250
6251/*
6252 * q6asm_media_format_block_iec - set up IEC61937 (compressed) or IEC60958
6253 * (pcm) format params. Both audio standards
6254 * use the same format and are used for
6255 * HDMI or SPDIF.
6256 *
6257 * @ac: Client session handle
6258 * @rate: sample rate
6259 * @channels: number of channels
6260 */
6261int q6asm_media_format_block_iec(struct audio_client *ac,
6262 uint32_t rate, uint32_t channels)
6263{
6264 struct asm_iec_compressed_fmt_blk_t fmt;
6265 int rc = 0;
6266
6267 pr_debug("%s: session[%d]rate[%d]ch[%d]\n",
6268 __func__, ac->session, rate,
6269 channels);
6270
6271 memset(&fmt, 0, sizeof(fmt));
6272 q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
6273
6274 fmt.hdr.opcode = ASM_DATA_CMD_IEC_60958_MEDIA_FMT;
6275 fmt.num_channels = channels;
6276 fmt.sampling_rate = rate;
6277
6278 atomic_set(&ac->cmd_state, -1);
6279 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6280 if (rc < 0) {
6281 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
6282 rc = -EINVAL;
6283 goto fail_cmd;
6284 }
6285 rc = wait_event_timeout(ac->cmd_wait,
6286 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6287 if (!rc) {
6288 pr_err("%s: timeout. waited for format update\n", __func__);
6289 rc = -ETIMEDOUT;
6290 goto fail_cmd;
6291 }
6292
6293 if (atomic_read(&ac->cmd_state) > 0) {
6294 pr_err("%s: DSP returned error[%s]\n",
6295 __func__, adsp_err_get_err_str(
6296 atomic_read(&ac->cmd_state)));
6297 rc = adsp_err_get_lnx_err_code(
6298 atomic_read(&ac->cmd_state));
6299 }
6300 return 0;
6301fail_cmd:
6302 return rc;
6303}
6304EXPORT_SYMBOL(q6asm_media_format_block_iec);
6305
6306static int __q6asm_media_format_block_multi_aac(struct audio_client *ac,
6307 struct asm_aac_cfg *cfg, int stream_id)
6308{
6309 struct asm_aac_fmt_blk_v2 fmt;
6310 int rc = 0;
6311
6312 pr_debug("%s: session[%d]rate[%d]ch[%d]\n", __func__, ac->session,
6313 cfg->sample_rate, cfg->ch_cfg);
6314
6315 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6316 atomic_set(&ac->cmd_state, -1);
6317 /*
6318 * Updated the token field with stream/session for compressed playback
6319 * Platform driver must know the the stream with which the command is
6320 * associated
6321 */
6322 if (ac->io_mode & COMPRESSED_STREAM_IO)
6323 q6asm_update_token(&fmt.hdr.token,
6324 ac->session,
6325 stream_id,
6326 0, /* Buffer index is NA */
6327 0, /* Direction flag is NA */
6328 WAIT_CMD);
6329
6330 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
6331 __func__, fmt.hdr.token, stream_id, ac->session);
6332 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6333 fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6334 sizeof(fmt.fmt_blk);
6335 fmt.aac_fmt_flag = cfg->format;
6336 fmt.audio_objype = cfg->aot;
6337 /* If zero, PCE is assumed to be available in bitstream*/
6338 fmt.total_size_of_PCE_bits = 0;
6339 fmt.channel_config = cfg->ch_cfg;
6340 fmt.sample_rate = cfg->sample_rate;
6341
6342 pr_debug("%s: format=0x%x cfg_size=%d aac-cfg=0x%x aot=%d ch=%d sr=%d\n",
6343 __func__, fmt.aac_fmt_flag, fmt.fmt_blk.fmt_blk_size,
6344 fmt.aac_fmt_flag,
6345 fmt.audio_objype,
6346 fmt.channel_config,
6347 fmt.sample_rate);
6348 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6349 if (rc < 0) {
6350 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
6351 rc = -EINVAL;
6352 goto fail_cmd;
6353 }
6354 rc = wait_event_timeout(ac->cmd_wait,
6355 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6356 if (!rc) {
6357 pr_err("%s: timeout. waited for FORMAT_UPDATE\n", __func__);
6358 rc = -ETIMEDOUT;
6359 goto fail_cmd;
6360 }
6361 if (atomic_read(&ac->cmd_state) > 0) {
6362 pr_err("%s: DSP returned error[%s]\n",
6363 __func__, adsp_err_get_err_str(
6364 atomic_read(&ac->cmd_state)));
6365 rc = adsp_err_get_lnx_err_code(
6366 atomic_read(&ac->cmd_state));
6367 goto fail_cmd;
6368 }
6369 return 0;
6370fail_cmd:
6371 return rc;
6372}
6373
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306374/**
6375 * q6asm_media_format_block_multi_aac -
6376 * command to set mediafmt block for multi_aac on ASM stream
6377 *
6378 * @ac: Audio client handle
6379 * @cfg: multi_aac config
6380 *
6381 * Returns 0 on success or error on failure
6382 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306383int q6asm_media_format_block_multi_aac(struct audio_client *ac,
6384 struct asm_aac_cfg *cfg)
6385{
6386 return __q6asm_media_format_block_multi_aac(ac, cfg, ac->stream_id);
6387}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306388EXPORT_SYMBOL(q6asm_media_format_block_multi_aac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306389
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306390/**
6391 * q6asm_media_format_block_aac -
6392 * command to set mediafmt block for aac on ASM
6393 *
6394 * @ac: Audio client handle
6395 * @cfg: aac config
6396 *
6397 * Returns 0 on success or error on failure
6398 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306399int q6asm_media_format_block_aac(struct audio_client *ac,
6400 struct asm_aac_cfg *cfg)
6401{
6402 return __q6asm_media_format_block_multi_aac(ac, cfg, ac->stream_id);
6403}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306404EXPORT_SYMBOL(q6asm_media_format_block_aac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306405
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306406/**
6407 * q6asm_stream_media_format_block_aac -
6408 * command to set mediafmt block for aac on ASM stream
6409 *
6410 * @ac: Audio client handle
6411 * @cfg: aac config
6412 * @stream_id: stream ID info
6413 *
6414 * Returns 0 on success or error on failure
6415 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306416int q6asm_stream_media_format_block_aac(struct audio_client *ac,
6417 struct asm_aac_cfg *cfg, int stream_id)
6418{
6419 return __q6asm_media_format_block_multi_aac(ac, cfg, stream_id);
6420}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306421EXPORT_SYMBOL(q6asm_stream_media_format_block_aac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306422
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306423/**
6424 * q6asm_media_format_block_wma -
6425 * command to set mediafmt block for wma on ASM stream
6426 *
6427 * @ac: Audio client handle
6428 * @cfg: wma config
6429 * @stream_id: stream ID info
6430 *
6431 * Returns 0 on success or error on failure
6432 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306433int q6asm_media_format_block_wma(struct audio_client *ac,
6434 void *cfg, int stream_id)
6435{
6436 struct asm_wmastdv9_fmt_blk_v2 fmt;
6437 struct asm_wma_cfg *wma_cfg = (struct asm_wma_cfg *)cfg;
6438 int rc = 0;
6439
6440 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",
6441 ac->session, wma_cfg->format_tag, wma_cfg->sample_rate,
6442 wma_cfg->ch_cfg, wma_cfg->avg_bytes_per_sec,
6443 wma_cfg->block_align, wma_cfg->valid_bits_per_sample,
6444 wma_cfg->ch_mask, wma_cfg->encode_opt);
6445
6446 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6447 atomic_set(&ac->cmd_state, -1);
6448
6449 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6450 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6451 sizeof(fmt.fmtblk);
6452 fmt.fmtag = wma_cfg->format_tag;
6453 fmt.num_channels = wma_cfg->ch_cfg;
6454 fmt.sample_rate = wma_cfg->sample_rate;
6455 fmt.avg_bytes_per_sec = wma_cfg->avg_bytes_per_sec;
6456 fmt.blk_align = wma_cfg->block_align;
6457 fmt.bits_per_sample =
6458 wma_cfg->valid_bits_per_sample;
6459 fmt.channel_mask = wma_cfg->ch_mask;
6460 fmt.enc_options = wma_cfg->encode_opt;
6461
6462 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6463 if (rc < 0) {
6464 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
6465 rc = -EINVAL;
6466 goto fail_cmd;
6467 }
6468 rc = wait_event_timeout(ac->cmd_wait,
6469 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6470 if (!rc) {
6471 pr_err("%s: timeout. waited for FORMAT_UPDATE\n", __func__);
6472 rc = -ETIMEDOUT;
6473 goto fail_cmd;
6474 }
6475 if (atomic_read(&ac->cmd_state) > 0) {
6476 pr_err("%s: DSP returned error[%s]\n",
6477 __func__, adsp_err_get_err_str(
6478 atomic_read(&ac->cmd_state)));
6479 rc = adsp_err_get_lnx_err_code(
6480 atomic_read(&ac->cmd_state));
6481 goto fail_cmd;
6482 }
6483 return 0;
6484fail_cmd:
6485 return rc;
6486}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306487EXPORT_SYMBOL(q6asm_media_format_block_wma);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306488
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306489/**
6490 * q6asm_media_format_block_wmapro -
6491 * command to set mediafmt block for wmapro on ASM stream
6492 *
6493 * @ac: Audio client handle
6494 * @cfg: wmapro config
6495 * @stream_id: stream ID info
6496 *
6497 * Returns 0 on success or error on failure
6498 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306499int q6asm_media_format_block_wmapro(struct audio_client *ac,
6500 void *cfg, int stream_id)
6501{
6502 struct asm_wmaprov10_fmt_blk_v2 fmt;
6503 struct asm_wmapro_cfg *wmapro_cfg = (struct asm_wmapro_cfg *)cfg;
6504 int rc = 0;
6505
6506 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",
6507 __func__,
6508 ac->session, wmapro_cfg->format_tag, wmapro_cfg->sample_rate,
6509 wmapro_cfg->ch_cfg, wmapro_cfg->avg_bytes_per_sec,
6510 wmapro_cfg->block_align, wmapro_cfg->valid_bits_per_sample,
6511 wmapro_cfg->ch_mask, wmapro_cfg->encode_opt,
6512 wmapro_cfg->adv_encode_opt, wmapro_cfg->adv_encode_opt2);
6513
6514 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6515 atomic_set(&ac->cmd_state, -1);
6516
6517 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6518 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6519 sizeof(fmt.fmtblk);
6520
6521 fmt.fmtag = wmapro_cfg->format_tag;
6522 fmt.num_channels = wmapro_cfg->ch_cfg;
6523 fmt.sample_rate = wmapro_cfg->sample_rate;
6524 fmt.avg_bytes_per_sec =
6525 wmapro_cfg->avg_bytes_per_sec;
6526 fmt.blk_align = wmapro_cfg->block_align;
6527 fmt.bits_per_sample = wmapro_cfg->valid_bits_per_sample;
6528 fmt.channel_mask = wmapro_cfg->ch_mask;
6529 fmt.enc_options = wmapro_cfg->encode_opt;
6530 fmt.usAdvancedEncodeOpt = wmapro_cfg->adv_encode_opt;
6531 fmt.advanced_enc_options2 = wmapro_cfg->adv_encode_opt2;
6532
6533 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6534 if (rc < 0) {
6535 pr_err("%s: Comamnd open failed %d\n", __func__, rc);
6536 rc = -EINVAL;
6537 goto fail_cmd;
6538 }
6539 rc = wait_event_timeout(ac->cmd_wait,
6540 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6541 if (!rc) {
6542 pr_err("%s: timeout. waited for FORMAT_UPDATE\n", __func__);
6543 rc = -ETIMEDOUT;
6544 goto fail_cmd;
6545 }
6546 if (atomic_read(&ac->cmd_state) > 0) {
6547 pr_err("%s: DSP returned error[%s]\n",
6548 __func__, adsp_err_get_err_str(
6549 atomic_read(&ac->cmd_state)));
6550 rc = adsp_err_get_lnx_err_code(
6551 atomic_read(&ac->cmd_state));
6552 goto fail_cmd;
6553 }
6554 return 0;
6555fail_cmd:
6556 return rc;
6557}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306558EXPORT_SYMBOL(q6asm_media_format_block_wmapro);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306559
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306560/**
6561 * q6asm_media_format_block_amrwbplus -
6562 * command to set mediafmt block for amrwbplus on ASM stream
6563 *
6564 * @ac: Audio client handle
6565 * @cfg: amrwbplus config
6566 * @stream_id: stream ID info
6567 *
6568 * Returns 0 on success or error on failure
6569 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306570int q6asm_media_format_block_amrwbplus(struct audio_client *ac,
6571 struct asm_amrwbplus_cfg *cfg)
6572{
6573 struct asm_amrwbplus_fmt_blk_v2 fmt;
6574 int rc = 0;
6575
6576 pr_debug("%s: session[%d]band-mode[%d]frame-fmt[%d]ch[%d]\n",
6577 __func__,
6578 ac->session,
6579 cfg->amr_band_mode,
6580 cfg->amr_frame_fmt,
6581 cfg->num_channels);
6582
6583 q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
6584 atomic_set(&ac->cmd_state, -1);
6585
6586 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6587 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6588 sizeof(fmt.fmtblk);
6589 fmt.amr_frame_fmt = cfg->amr_frame_fmt;
6590
6591 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6592 if (rc < 0) {
6593 pr_err("%s: Comamnd media format update failed.. %d\n",
6594 __func__, rc);
6595 rc = -EINVAL;
6596 goto fail_cmd;
6597 }
6598 rc = wait_event_timeout(ac->cmd_wait,
6599 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6600 if (!rc) {
6601 pr_err("%s: timeout. waited for FORMAT_UPDATE\n", __func__);
6602 rc = -ETIMEDOUT;
6603 goto fail_cmd;
6604 }
6605 if (atomic_read(&ac->cmd_state) > 0) {
6606 pr_err("%s: DSP returned error[%s]\n",
6607 __func__, adsp_err_get_err_str(
6608 atomic_read(&ac->cmd_state)));
6609 rc = adsp_err_get_lnx_err_code(
6610 atomic_read(&ac->cmd_state));
6611 goto fail_cmd;
6612 }
6613 return 0;
6614fail_cmd:
6615 return rc;
6616}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306617EXPORT_SYMBOL(q6asm_media_format_block_amrwbplus);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306618
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306619/**
6620 * q6asm_stream_media_format_block_flac -
6621 * command to set mediafmt block for flac on ASM stream
6622 *
6623 * @ac: Audio client handle
6624 * @cfg: FLAC config
6625 * @stream_id: stream ID info
6626 *
6627 * Returns 0 on success or error on failure
6628 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306629int q6asm_stream_media_format_block_flac(struct audio_client *ac,
6630 struct asm_flac_cfg *cfg, int stream_id)
6631{
6632 struct asm_flac_fmt_blk_v2 fmt;
6633 int rc = 0;
6634
6635 pr_debug("%s :session[%d] rate[%d] ch[%d] size[%d] stream_id[%d]\n",
6636 __func__, ac->session, cfg->sample_rate, cfg->ch_cfg,
6637 cfg->sample_size, stream_id);
6638
6639 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6640 atomic_set(&ac->cmd_state, -1);
6641
6642 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6643 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6644 sizeof(fmt.fmtblk);
6645
6646 fmt.is_stream_info_present = cfg->stream_info_present;
6647 fmt.num_channels = cfg->ch_cfg;
6648 fmt.min_blk_size = cfg->min_blk_size;
6649 fmt.max_blk_size = cfg->max_blk_size;
6650 fmt.sample_rate = cfg->sample_rate;
6651 fmt.min_frame_size = cfg->min_frame_size;
6652 fmt.max_frame_size = cfg->max_frame_size;
6653 fmt.sample_size = cfg->sample_size;
6654
6655 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6656 if (rc < 0) {
6657 pr_err("%s :Comamnd media format update failed %d\n",
6658 __func__, rc);
6659 goto fail_cmd;
6660 }
6661 rc = wait_event_timeout(ac->cmd_wait,
6662 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6663 if (!rc) {
6664 pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
6665 rc = -ETIMEDOUT;
6666 goto fail_cmd;
6667 }
6668
6669 if (atomic_read(&ac->cmd_state) > 0) {
6670 pr_err("%s: DSP returned error[%s]\n",
6671 __func__, adsp_err_get_err_str(
6672 atomic_read(&ac->cmd_state)));
6673 rc = adsp_err_get_lnx_err_code(
6674 atomic_read(&ac->cmd_state));
6675 goto fail_cmd;
6676 }
6677 return 0;
6678fail_cmd:
6679 return rc;
6680}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306681EXPORT_SYMBOL(q6asm_stream_media_format_block_flac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306682
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306683/**
6684 * q6asm_media_format_block_alac -
6685 * command to set mediafmt block for alac on ASM stream
6686 *
6687 * @ac: Audio client handle
6688 * @cfg: ALAC config
6689 * @stream_id: stream ID info
6690 *
6691 * Returns 0 on success or error on failure
6692 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306693int q6asm_media_format_block_alac(struct audio_client *ac,
6694 struct asm_alac_cfg *cfg, int stream_id)
6695{
6696 struct asm_alac_fmt_blk_v2 fmt;
6697 int rc = 0;
6698
6699 pr_debug("%s :session[%d]rate[%d]ch[%d]\n", __func__,
6700 ac->session, cfg->sample_rate, cfg->num_channels);
6701
6702 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6703 atomic_set(&ac->cmd_state, -1);
6704
6705 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6706 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6707 sizeof(fmt.fmtblk);
6708
6709 fmt.frame_length = cfg->frame_length;
6710 fmt.compatible_version = cfg->compatible_version;
6711 fmt.bit_depth = cfg->bit_depth;
6712 fmt.pb = cfg->pb;
6713 fmt.mb = cfg->mb;
6714 fmt.kb = cfg->kb;
6715 fmt.num_channels = cfg->num_channels;
6716 fmt.max_run = cfg->max_run;
6717 fmt.max_frame_bytes = cfg->max_frame_bytes;
6718 fmt.avg_bit_rate = cfg->avg_bit_rate;
6719 fmt.sample_rate = cfg->sample_rate;
6720 fmt.channel_layout_tag = cfg->channel_layout_tag;
6721
6722 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6723 if (rc < 0) {
6724 pr_err("%s :Comamnd media format update failed %d\n",
6725 __func__, rc);
6726 goto fail_cmd;
6727 }
6728 rc = wait_event_timeout(ac->cmd_wait,
6729 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6730 if (!rc) {
6731 pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
6732 rc = -ETIMEDOUT;
6733 goto fail_cmd;
6734 }
6735
6736 if (atomic_read(&ac->cmd_state) > 0) {
6737 pr_err("%s: DSP returned error[%s]\n",
6738 __func__, adsp_err_get_err_str(
6739 atomic_read(&ac->cmd_state)));
6740 rc = adsp_err_get_lnx_err_code(
6741 atomic_read(&ac->cmd_state));
6742 goto fail_cmd;
6743 }
6744 return 0;
6745fail_cmd:
6746 return rc;
6747}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306748EXPORT_SYMBOL(q6asm_media_format_block_alac);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306749
6750/*
6751 * q6asm_media_format_block_g711 - sends g711 decoder configuration
6752 * parameters
6753 * @ac: Client session handle
6754 * @cfg: Audio stream manager configuration parameters
6755 * @stream_id: Stream id
6756 */
6757int q6asm_media_format_block_g711(struct audio_client *ac,
6758 struct asm_g711_dec_cfg *cfg, int stream_id)
6759{
6760 struct asm_g711_dec_fmt_blk_v2 fmt;
6761 int rc = 0;
6762
6763 if (!ac) {
6764 pr_err("%s: audio client is null\n", __func__);
6765 return -EINVAL;
6766 }
6767 if (!cfg) {
6768 pr_err("%s: Invalid ASM config\n", __func__);
6769 return -EINVAL;
6770 }
6771
6772 if (stream_id <= 0) {
6773 pr_err("%s: Invalid stream id\n", __func__);
6774 return -EINVAL;
6775 }
6776
6777 pr_debug("%s :session[%d]rate[%d]\n", __func__,
6778 ac->session, cfg->sample_rate);
6779
6780 memset(&fmt, 0, sizeof(struct asm_g711_dec_fmt_blk_v2));
6781
6782 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6783 atomic_set(&ac->cmd_state, -1);
6784
6785 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6786 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6787 sizeof(fmt.fmtblk);
6788
6789 fmt.sample_rate = cfg->sample_rate;
6790
6791 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6792 if (rc < 0) {
6793 pr_err("%s :Command media format update failed %d\n",
6794 __func__, rc);
6795 goto fail_cmd;
6796 }
6797 rc = wait_event_timeout(ac->cmd_wait,
6798 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6799 if (!rc) {
6800 pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
6801 rc = -ETIMEDOUT;
6802 goto fail_cmd;
6803 }
6804
6805 if (atomic_read(&ac->cmd_state) > 0) {
6806 pr_err("%s: DSP returned error[%s]\n",
6807 __func__, adsp_err_get_err_str(
6808 atomic_read(&ac->cmd_state)));
6809 rc = adsp_err_get_lnx_err_code(
6810 atomic_read(&ac->cmd_state));
6811 goto fail_cmd;
6812 }
6813 return 0;
6814fail_cmd:
6815 return rc;
6816}
6817EXPORT_SYMBOL(q6asm_media_format_block_g711);
6818
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306819/**
6820 * q6asm_stream_media_format_block_vorbis -
6821 * command to set mediafmt block for vorbis on ASM stream
6822 *
6823 * @ac: Audio client handle
6824 * @cfg: vorbis config
6825 * @stream_id: stream ID info
6826 *
6827 * Returns 0 on success or error on failure
6828 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306829int q6asm_stream_media_format_block_vorbis(struct audio_client *ac,
6830 struct asm_vorbis_cfg *cfg, int stream_id)
6831{
6832 struct asm_vorbis_fmt_blk_v2 fmt;
6833 int rc = 0;
6834
6835 pr_debug("%s :session[%d] bit_stream_fmt[%d] stream_id[%d]\n",
6836 __func__, ac->session, cfg->bit_stream_fmt, stream_id);
6837
6838 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6839 atomic_set(&ac->cmd_state, -1);
6840
6841 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6842 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6843 sizeof(fmt.fmtblk);
6844
6845 fmt.bit_stream_fmt = cfg->bit_stream_fmt;
6846
6847 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6848 if (rc < 0) {
6849 pr_err("%s :Comamnd media format update failed %d\n",
6850 __func__, rc);
6851 goto fail_cmd;
6852 }
6853 rc = wait_event_timeout(ac->cmd_wait,
6854 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6855 if (!rc) {
6856 pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
6857 rc = -ETIMEDOUT;
6858 goto fail_cmd;
6859 }
6860
6861 if (atomic_read(&ac->cmd_state) > 0) {
6862 pr_err("%s: DSP returned error[%s]\n",
6863 __func__, adsp_err_get_err_str(
6864 atomic_read(&ac->cmd_state)));
6865 rc = adsp_err_get_lnx_err_code(
6866 atomic_read(&ac->cmd_state));
6867 goto fail_cmd;
6868 }
6869 return 0;
6870fail_cmd:
6871 return rc;
6872}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306873EXPORT_SYMBOL(q6asm_stream_media_format_block_vorbis);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306874
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306875/**
6876 * q6asm_media_format_block_ape -
6877 * command to set mediafmt block for APE on ASM stream
6878 *
6879 * @ac: Audio client handle
6880 * @cfg: APE config
6881 * @stream_id: stream ID info
6882 *
6883 * Returns 0 on success or error on failure
6884 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306885int q6asm_media_format_block_ape(struct audio_client *ac,
6886 struct asm_ape_cfg *cfg, int stream_id)
6887{
6888 struct asm_ape_fmt_blk_v2 fmt;
6889 int rc = 0;
6890
6891 pr_debug("%s :session[%d]rate[%d]ch[%d]\n", __func__,
6892 ac->session, cfg->sample_rate, cfg->num_channels);
6893
6894 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6895 atomic_set(&ac->cmd_state, -1);
6896
6897 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6898 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6899 sizeof(fmt.fmtblk);
6900
6901 fmt.compatible_version = cfg->compatible_version;
6902 fmt.compression_level = cfg->compression_level;
6903 fmt.format_flags = cfg->format_flags;
6904 fmt.blocks_per_frame = cfg->blocks_per_frame;
6905 fmt.final_frame_blocks = cfg->final_frame_blocks;
6906 fmt.total_frames = cfg->total_frames;
6907 fmt.bits_per_sample = cfg->bits_per_sample;
6908 fmt.num_channels = cfg->num_channels;
6909 fmt.sample_rate = cfg->sample_rate;
6910 fmt.seek_table_present = cfg->seek_table_present;
6911
6912 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6913 if (rc < 0) {
6914 pr_err("%s :Comamnd media format update failed %d\n",
6915 __func__, rc);
6916 goto fail_cmd;
6917 }
6918 rc = wait_event_timeout(ac->cmd_wait,
6919 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6920 if (!rc) {
6921 pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
6922 rc = -ETIMEDOUT;
6923 goto fail_cmd;
6924 }
6925
6926 if (atomic_read(&ac->cmd_state) > 0) {
6927 pr_err("%s: DSP returned error[%s]\n",
6928 __func__, adsp_err_get_err_str(
6929 atomic_read(&ac->cmd_state)));
6930 rc = adsp_err_get_lnx_err_code(
6931 atomic_read(&ac->cmd_state));
6932 goto fail_cmd;
6933 }
6934 return 0;
6935fail_cmd:
6936 return rc;
6937}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05306938EXPORT_SYMBOL(q6asm_media_format_block_ape);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05306939
6940/*
6941 * q6asm_media_format_block_dsd- Sends DSD Decoder
6942 * configuration parameters
6943 *
6944 * @ac: Client session handle
6945 * @cfg: DSD Media Format Configuration.
6946 * @stream_id: stream id of stream to be associated with this session
6947 *
6948 * Return 0 on success or negative error code on failure
6949 */
6950int q6asm_media_format_block_dsd(struct audio_client *ac,
6951 struct asm_dsd_cfg *cfg, int stream_id)
6952{
6953 struct asm_dsd_fmt_blk_v2 fmt;
6954 int rc;
6955
6956 pr_debug("%s: session[%d] data_rate[%d] ch[%d]\n", __func__,
6957 ac->session, cfg->dsd_data_rate, cfg->num_channels);
6958
6959 memset(&fmt, 0, sizeof(fmt));
6960 q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
6961
6962 fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
6963 fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
6964 sizeof(fmt.fmtblk);
6965
6966 fmt.num_version = cfg->num_version;
6967 fmt.is_bitwise_big_endian = cfg->is_bitwise_big_endian;
6968 fmt.dsd_channel_block_size = cfg->dsd_channel_block_size;
6969 fmt.num_channels = cfg->num_channels;
6970 fmt.dsd_data_rate = cfg->dsd_data_rate;
6971 atomic_set(&ac->cmd_state, -1);
6972 rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
6973 if (rc < 0) {
6974 pr_err("%s: Command DSD media format update failed, err: %d\n",
6975 __func__, rc);
6976 goto done;
6977 }
6978 rc = wait_event_timeout(ac->cmd_wait,
6979 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
6980 if (!rc) {
6981 pr_err("%s: timeout. waited for DSD FORMAT_UPDATE\n", __func__);
6982 rc = -ETIMEDOUT;
6983 goto done;
6984 }
6985
6986 if (atomic_read(&ac->cmd_state) > 0) {
6987 pr_err("%s: DSP returned error[%s]\n",
6988 __func__, adsp_err_get_err_str(
6989 atomic_read(&ac->cmd_state)));
6990 rc = adsp_err_get_lnx_err_code(
6991 atomic_read(&ac->cmd_state));
6992 goto done;
6993 }
6994 return 0;
6995done:
6996 return rc;
6997}
6998EXPORT_SYMBOL(q6asm_media_format_block_dsd);
6999
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307000/**
7001 * q6asm_stream_media_format_block_aptx_dec -
7002 * command to set mediafmt block for APTX dec on ASM stream
7003 *
7004 * @ac: Audio client handle
7005 * @srate: sample rate
7006 * @stream_id: stream ID info
7007 *
7008 * Returns 0 on success or error on failure
7009 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307010int q6asm_stream_media_format_block_aptx_dec(struct audio_client *ac,
7011 uint32_t srate, int stream_id)
7012{
7013 struct asm_aptx_dec_fmt_blk_v2 aptx_fmt;
7014 int rc = 0;
7015
7016 if (!ac->session) {
7017 pr_err("%s: ac session invalid\n", __func__);
7018 rc = -EINVAL;
7019 goto fail_cmd;
7020 }
7021 pr_debug("%s :session[%d] rate[%d] stream_id[%d]\n",
7022 __func__, ac->session, srate, stream_id);
7023
7024 q6asm_stream_add_hdr(ac, &aptx_fmt.hdr, sizeof(aptx_fmt), TRUE,
7025 stream_id);
7026 atomic_set(&ac->cmd_state, -1);
7027
7028 aptx_fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
7029 aptx_fmt.fmtblk.fmt_blk_size = sizeof(aptx_fmt) - sizeof(aptx_fmt.hdr) -
7030 sizeof(aptx_fmt.fmtblk);
7031
7032 aptx_fmt.sample_rate = srate;
7033
7034 rc = apr_send_pkt(ac->apr, (uint32_t *) &aptx_fmt);
7035 if (rc < 0) {
7036 pr_err("%s :Comamnd media format update failed %d\n",
7037 __func__, rc);
7038 goto fail_cmd;
7039 }
7040 rc = wait_event_timeout(ac->cmd_wait,
7041 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
7042 if (!rc) {
7043 pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
7044 rc = -ETIMEDOUT;
7045 goto fail_cmd;
7046 }
7047
7048 if (atomic_read(&ac->cmd_state) > 0) {
7049 pr_err("%s: DSP returned error[%s]\n",
7050 __func__, adsp_err_get_err_str(
7051 atomic_read(&ac->cmd_state)));
7052 rc = adsp_err_get_lnx_err_code(
7053 atomic_read(&ac->cmd_state));
7054 goto fail_cmd;
7055 }
7056 rc = 0;
7057fail_cmd:
7058 return rc;
7059}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307060EXPORT_SYMBOL(q6asm_stream_media_format_block_aptx_dec);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307061
7062static int __q6asm_ds1_set_endp_params(struct audio_client *ac, int param_id,
7063 int param_value, int stream_id)
7064{
7065 struct asm_dec_ddp_endp_param_v2 ddp_cfg;
7066 int rc = 0;
7067
7068 pr_debug("%s: session[%d] stream[%d],param_id[%d]param_value[%d]",
7069 __func__, ac->session, stream_id, param_id, param_value);
7070
7071 q6asm_stream_add_hdr(ac, &ddp_cfg.hdr, sizeof(ddp_cfg), TRUE,
7072 stream_id);
7073 atomic_set(&ac->cmd_state, -1);
7074 /*
7075 * Updated the token field with stream/session for compressed playback
7076 * Platform driver must know the stream with which the command is
7077 * associated
7078 */
7079 if (ac->io_mode & COMPRESSED_STREAM_IO)
7080 q6asm_update_token(&ddp_cfg.hdr.token,
7081 ac->session,
7082 stream_id,
7083 0, /* Buffer index is NA */
7084 0, /* Direction flag is NA */
7085 WAIT_CMD);
7086 ddp_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
7087 ddp_cfg.encdec.param_id = param_id;
7088 ddp_cfg.encdec.param_size = sizeof(struct asm_dec_ddp_endp_param_v2) -
7089 (sizeof(struct apr_hdr) +
7090 sizeof(struct asm_stream_cmd_set_encdec_param));
7091 ddp_cfg.endp_param_value = param_value;
7092 rc = apr_send_pkt(ac->apr, (uint32_t *) &ddp_cfg);
7093 if (rc < 0) {
7094 pr_err("%s: Command opcode[0x%x] failed %d\n",
7095 __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
7096 goto fail_cmd;
7097 }
7098 rc = wait_event_timeout(ac->cmd_wait,
7099 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
7100 if (!rc) {
7101 pr_err("%s: timeout opcode[0x%x]\n", __func__,
7102 ddp_cfg.hdr.opcode);
7103 rc = -ETIMEDOUT;
7104 goto fail_cmd;
7105 }
7106 if (atomic_read(&ac->cmd_state) > 0) {
7107 pr_err("%s: DSP returned error[%s]\n",
7108 __func__, adsp_err_get_err_str(
7109 atomic_read(&ac->cmd_state)));
7110 rc = adsp_err_get_lnx_err_code(
7111 atomic_read(&ac->cmd_state));
7112 goto fail_cmd;
7113 }
7114 return 0;
7115fail_cmd:
7116 return rc;
7117}
7118
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307119/**
7120 * q6asm_ds1_set_endp_params -
7121 * command to set DS1 params for ASM
7122 *
7123 * @ac: Audio client handle
7124 * @param_id: param id
7125 * @param_value: value of param
7126 *
7127 * Returns 0 on success or error on failure
7128 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307129int q6asm_ds1_set_endp_params(struct audio_client *ac,
7130 int param_id, int param_value)
7131{
7132 return __q6asm_ds1_set_endp_params(ac, param_id, param_value,
7133 ac->stream_id);
7134}
7135
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307136/**
7137 * q6asm_ds1_set_stream_endp_params -
7138 * command to set DS1 params for ASM stream
7139 *
7140 * @ac: Audio client handle
7141 * @param_id: param id
7142 * @param_value: value of param
7143 * @stream_id: stream ID info
7144 *
7145 * Returns 0 on success or error on failure
7146 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307147int q6asm_ds1_set_stream_endp_params(struct audio_client *ac,
7148 int param_id, int param_value,
7149 int stream_id)
7150{
7151 return __q6asm_ds1_set_endp_params(ac, param_id, param_value,
7152 stream_id);
7153}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307154EXPORT_SYMBOL(q6asm_ds1_set_stream_endp_params);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307155
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307156/**
7157 * q6asm_memory_map -
7158 * command to send memory map for ASM
7159 *
7160 * @ac: Audio client handle
7161 * @buf_add: buffer address to map
7162 * @dir: RX or TX session
7163 * @bufsz: size of each buffer
7164 * @bufcnt: buffer count
7165 *
7166 * Returns 0 on success or error on failure
7167 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307168int q6asm_memory_map(struct audio_client *ac, phys_addr_t buf_add, int dir,
7169 uint32_t bufsz, uint32_t bufcnt)
7170{
7171 struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
7172 struct avs_shared_map_region_payload *mregions = NULL;
7173 struct audio_port_data *port = NULL;
7174 void *mmap_region_cmd = NULL;
7175 void *payload = NULL;
7176 struct asm_buffer_node *buffer_node = NULL;
7177 int rc = 0;
7178 int cmd_size = 0;
7179
7180 if (!ac) {
7181 pr_err("%s: APR handle NULL\n", __func__);
7182 return -EINVAL;
7183 }
7184 if (ac->mmap_apr == NULL) {
7185 pr_err("%s: mmap APR handle NULL\n", __func__);
7186 return -EINVAL;
7187 }
7188 pr_debug("%s: Session[%d]\n", __func__, ac->session);
7189
7190 buffer_node = kmalloc(sizeof(struct asm_buffer_node), GFP_KERNEL);
7191 if (!buffer_node)
7192 return -ENOMEM;
7193
7194 cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions)
7195 + sizeof(struct avs_shared_map_region_payload) * bufcnt;
7196
7197 mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
7198 if (mmap_region_cmd == NULL) {
7199 rc = -EINVAL;
7200 kfree(buffer_node);
7201 return rc;
7202 }
7203 mmap_regions = (struct avs_cmd_shared_mem_map_regions *)
7204 mmap_region_cmd;
7205 q6asm_add_mmaphdr(ac, &mmap_regions->hdr, cmd_size, dir);
7206 atomic_set(&ac->mem_state, -1);
7207 mmap_regions->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS;
7208 mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
7209 mmap_regions->num_regions = bufcnt & 0x00ff;
7210 mmap_regions->property_flag = 0x00;
7211 payload = ((u8 *) mmap_region_cmd +
7212 sizeof(struct avs_cmd_shared_mem_map_regions));
7213 mregions = (struct avs_shared_map_region_payload *)payload;
7214
7215 ac->port[dir].tmp_hdl = 0;
7216 port = &ac->port[dir];
7217 pr_debug("%s: buf_add 0x%pK, bufsz: %d\n", __func__,
7218 &buf_add, bufsz);
7219 mregions->shm_addr_lsw = lower_32_bits(buf_add);
7220 mregions->shm_addr_msw = msm_audio_populate_upper_32_bits(buf_add);
7221 mregions->mem_size_bytes = bufsz;
7222 ++mregions;
7223
7224 rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) mmap_region_cmd);
7225 if (rc < 0) {
7226 pr_err("%s: mmap op[0x%x]rc[%d]\n", __func__,
7227 mmap_regions->hdr.opcode, rc);
7228 rc = -EINVAL;
7229 kfree(buffer_node);
7230 goto fail_cmd;
7231 }
7232
7233 rc = wait_event_timeout(ac->mem_wait,
7234 (atomic_read(&ac->mem_state) >= 0 &&
7235 ac->port[dir].tmp_hdl), 5*HZ);
7236 if (!rc) {
7237 pr_err("%s: timeout. waited for memory_map\n", __func__);
7238 rc = -ETIMEDOUT;
7239 kfree(buffer_node);
7240 goto fail_cmd;
7241 }
7242 if (atomic_read(&ac->mem_state) > 0) {
7243 pr_err("%s: DSP returned error[%s] for memory_map\n",
7244 __func__, adsp_err_get_err_str(
7245 atomic_read(&ac->mem_state)));
7246 rc = adsp_err_get_lnx_err_code(
7247 atomic_read(&ac->mem_state));
7248 kfree(buffer_node);
7249 goto fail_cmd;
7250 }
7251 buffer_node->buf_phys_addr = buf_add;
7252 buffer_node->mmap_hdl = ac->port[dir].tmp_hdl;
7253 list_add_tail(&buffer_node->list, &ac->port[dir].mem_map_handle);
7254 ac->port[dir].tmp_hdl = 0;
7255 rc = 0;
7256
7257fail_cmd:
7258 kfree(mmap_region_cmd);
7259 return rc;
7260}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307261EXPORT_SYMBOL(q6asm_memory_map);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307262
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307263/**
7264 * q6asm_memory_unmap -
7265 * command to send memory unmap for ASM
7266 *
7267 * @ac: Audio client handle
7268 * @buf_add: buffer address to unmap
7269 * @dir: RX or TX session
7270 *
7271 * Returns 0 on success or error on failure
7272 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307273int q6asm_memory_unmap(struct audio_client *ac, phys_addr_t buf_add, int dir)
7274{
7275 struct avs_cmd_shared_mem_unmap_regions mem_unmap;
7276 struct asm_buffer_node *buf_node = NULL;
7277 struct list_head *ptr, *next;
7278
7279 int rc = 0;
7280
7281 if (!ac) {
7282 pr_err("%s: APR handle NULL\n", __func__);
7283 return -EINVAL;
7284 }
7285 if (this_mmap.apr == NULL) {
7286 pr_err("%s: APR handle NULL\n", __func__);
7287 return -EINVAL;
7288 }
7289 pr_debug("%s: Session[%d]\n", __func__, ac->session);
7290
7291 q6asm_add_mmaphdr(ac, &mem_unmap.hdr,
7292 sizeof(struct avs_cmd_shared_mem_unmap_regions),
7293 dir);
7294 atomic_set(&ac->mem_state, -1);
7295 mem_unmap.hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS;
7296 mem_unmap.mem_map_handle = 0;
7297 list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
7298 buf_node = list_entry(ptr, struct asm_buffer_node,
7299 list);
7300 if (buf_node->buf_phys_addr == buf_add) {
7301 pr_debug("%s: Found the element\n", __func__);
7302 mem_unmap.mem_map_handle = buf_node->mmap_hdl;
7303 break;
7304 }
7305 }
7306 pr_debug("%s: mem_unmap-mem_map_handle: 0x%x\n",
7307 __func__, mem_unmap.mem_map_handle);
7308
7309 if (mem_unmap.mem_map_handle == 0) {
7310 pr_err("%s: Do not send null mem handle to DSP\n", __func__);
7311 rc = 0;
7312 goto fail_cmd;
7313 }
7314 rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) &mem_unmap);
7315 if (rc < 0) {
7316 pr_err("%s: mem_unmap op[0x%x]rc[%d]\n", __func__,
7317 mem_unmap.hdr.opcode, rc);
7318 rc = -EINVAL;
7319 goto fail_cmd;
7320 }
7321
7322 rc = wait_event_timeout(ac->mem_wait,
7323 (atomic_read(&ac->mem_state) >= 0), 5 * HZ);
7324 if (!rc) {
7325 pr_err("%s: timeout. waited for memory_unmap of handle 0x%x\n",
7326 __func__, mem_unmap.mem_map_handle);
7327 rc = -ETIMEDOUT;
7328 goto fail_cmd;
7329 } else if (atomic_read(&ac->mem_state) > 0) {
7330 pr_err("%s DSP returned error [%s] map handle 0x%x\n",
7331 __func__, adsp_err_get_err_str(
7332 atomic_read(&ac->mem_state)),
7333 mem_unmap.mem_map_handle);
7334 rc = adsp_err_get_lnx_err_code(
7335 atomic_read(&ac->mem_state));
7336 goto fail_cmd;
7337 } else if (atomic_read(&ac->unmap_cb_success) == 0) {
7338 pr_err("%s: Error in mem unmap callback of handle 0x%x\n",
7339 __func__, mem_unmap.mem_map_handle);
7340 rc = -EINVAL;
7341 goto fail_cmd;
7342 }
7343
7344 rc = 0;
7345fail_cmd:
7346 list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
7347 buf_node = list_entry(ptr, struct asm_buffer_node,
7348 list);
7349 if (buf_node->buf_phys_addr == buf_add) {
7350 list_del(&buf_node->list);
7351 kfree(buf_node);
7352 break;
7353 }
7354 }
7355 return rc;
7356}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307357EXPORT_SYMBOL(q6asm_memory_unmap);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307358
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307359/**
7360 * q6asm_memory_map_regions -
7361 * command to send memory map regions for ASM
7362 *
7363 * @ac: Audio client handle
7364 * @dir: RX or TX session
7365 * @bufsz: size of each buffer
7366 * @bufcnt: buffer count
7367 * @is_contiguous: alloc contiguous mem or not
7368 *
7369 * Returns 0 on success or error on failure
7370 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307371static int q6asm_memory_map_regions(struct audio_client *ac, int dir,
7372 uint32_t bufsz, uint32_t bufcnt,
7373 bool is_contiguous)
7374{
7375 struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
7376 struct avs_shared_map_region_payload *mregions = NULL;
7377 struct audio_port_data *port = NULL;
7378 struct audio_buffer *ab = NULL;
7379 void *mmap_region_cmd = NULL;
7380 void *payload = NULL;
7381 struct asm_buffer_node *buffer_node = NULL;
7382 int rc = 0;
7383 int i = 0;
7384 uint32_t cmd_size = 0;
7385 uint32_t bufcnt_t;
7386 uint32_t bufsz_t;
7387
7388 if (!ac) {
7389 pr_err("%s: APR handle NULL\n", __func__);
7390 return -EINVAL;
7391 }
7392 if (ac->mmap_apr == NULL) {
7393 pr_err("%s: mmap APR handle NULL\n", __func__);
7394 return -EINVAL;
7395 }
7396 pr_debug("%s: Session[%d]\n", __func__, ac->session);
7397
7398 bufcnt_t = (is_contiguous) ? 1 : bufcnt;
7399 bufsz_t = (is_contiguous) ? (bufsz * bufcnt) : bufsz;
7400
7401 if (is_contiguous) {
7402 /* The size to memory map should be multiple of 4K bytes */
7403 bufsz_t = PAGE_ALIGN(bufsz_t);
7404 }
7405
7406 if (bufcnt_t > (UINT_MAX
7407 - sizeof(struct avs_cmd_shared_mem_map_regions))
7408 / sizeof(struct avs_shared_map_region_payload)) {
7409 pr_err("%s: Unsigned Integer Overflow. bufcnt_t = %u\n",
7410 __func__, bufcnt_t);
7411 return -EINVAL;
7412 }
7413
7414 cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions)
7415 + (sizeof(struct avs_shared_map_region_payload)
7416 * bufcnt_t);
7417
7418
7419 if (bufcnt > (UINT_MAX / sizeof(struct asm_buffer_node))) {
7420 pr_err("%s: Unsigned Integer Overflow. bufcnt = %u\n",
7421 __func__, bufcnt);
7422 return -EINVAL;
7423 }
7424
7425 buffer_node = kzalloc(sizeof(struct asm_buffer_node) * bufcnt,
7426 GFP_KERNEL);
7427 if (!buffer_node)
7428 return -ENOMEM;
7429
7430 mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
7431 if (mmap_region_cmd == NULL) {
7432 rc = -EINVAL;
7433 kfree(buffer_node);
7434 return rc;
7435 }
7436 mmap_regions = (struct avs_cmd_shared_mem_map_regions *)
7437 mmap_region_cmd;
7438 q6asm_add_mmaphdr(ac, &mmap_regions->hdr, cmd_size, dir);
7439 atomic_set(&ac->mem_state, -1);
7440 pr_debug("%s: mmap_region=0x%pK token=0x%x\n", __func__,
7441 mmap_regions, ((ac->session << 8) | dir));
7442
7443 mmap_regions->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS;
7444 mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
7445 mmap_regions->num_regions = bufcnt_t; /*bufcnt & 0x00ff; */
7446 mmap_regions->property_flag = 0x00;
7447 pr_debug("%s: map_regions->nregions = %d\n", __func__,
7448 mmap_regions->num_regions);
7449 payload = ((u8 *) mmap_region_cmd +
7450 sizeof(struct avs_cmd_shared_mem_map_regions));
7451 mregions = (struct avs_shared_map_region_payload *)payload;
7452
7453 ac->port[dir].tmp_hdl = 0;
7454 port = &ac->port[dir];
7455 for (i = 0; i < bufcnt_t; i++) {
7456 ab = &port->buf[i];
7457 mregions->shm_addr_lsw = lower_32_bits(ab->phys);
7458 mregions->shm_addr_msw =
7459 msm_audio_populate_upper_32_bits(ab->phys);
7460 mregions->mem_size_bytes = bufsz_t;
7461 ++mregions;
7462 }
7463
7464 rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) mmap_region_cmd);
7465 if (rc < 0) {
7466 pr_err("%s: mmap_regions op[0x%x]rc[%d]\n", __func__,
7467 mmap_regions->hdr.opcode, rc);
7468 rc = -EINVAL;
7469 kfree(buffer_node);
7470 goto fail_cmd;
7471 }
7472
7473 rc = wait_event_timeout(ac->mem_wait,
Meng Wang56d55952018-02-27 11:16:32 +08007474 (atomic_read(&ac->mem_state) >= 0 &&
7475 ac->port[dir].tmp_hdl), 5*HZ);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307476 if (!rc) {
7477 pr_err("%s: timeout. waited for memory_map\n", __func__);
7478 rc = -ETIMEDOUT;
7479 kfree(buffer_node);
7480 goto fail_cmd;
7481 }
7482 if (atomic_read(&ac->mem_state) > 0) {
7483 pr_err("%s DSP returned error for memory_map [%s]\n",
7484 __func__, adsp_err_get_err_str(
7485 atomic_read(&ac->mem_state)));
7486 rc = adsp_err_get_lnx_err_code(
7487 atomic_read(&ac->mem_state));
7488 kfree(buffer_node);
7489 goto fail_cmd;
7490 }
7491 mutex_lock(&ac->cmd_lock);
7492
7493 for (i = 0; i < bufcnt; i++) {
7494 ab = &port->buf[i];
7495 buffer_node[i].buf_phys_addr = ab->phys;
7496 buffer_node[i].mmap_hdl = ac->port[dir].tmp_hdl;
7497 list_add_tail(&buffer_node[i].list,
7498 &ac->port[dir].mem_map_handle);
7499 pr_debug("%s: i=%d, bufadd[i] = 0x%pK, maphdl[i] = 0x%x\n",
7500 __func__, i, &buffer_node[i].buf_phys_addr,
7501 buffer_node[i].mmap_hdl);
7502 }
7503 ac->port[dir].tmp_hdl = 0;
7504 mutex_unlock(&ac->cmd_lock);
7505 rc = 0;
7506fail_cmd:
7507 kfree(mmap_region_cmd);
7508 return rc;
7509}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307510EXPORT_SYMBOL(q6asm_memory_map_regions);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307511
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307512/**
7513 * q6asm_memory_unmap_regions -
7514 * command to send memory unmap regions for ASM
7515 *
7516 * @ac: Audio client handle
7517 * @dir: RX or TX session
7518 *
7519 * Returns 0 on success or error on failure
7520 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307521static int q6asm_memory_unmap_regions(struct audio_client *ac, int dir)
7522{
7523 struct avs_cmd_shared_mem_unmap_regions mem_unmap;
7524 struct audio_port_data *port = NULL;
7525 struct asm_buffer_node *buf_node = NULL;
7526 struct list_head *ptr, *next;
7527 phys_addr_t buf_add;
7528 int rc = 0;
7529 int cmd_size = 0;
7530
7531 if (!ac) {
7532 pr_err("%s: APR handle NULL\n", __func__);
7533 return -EINVAL;
7534 }
7535 if (ac->mmap_apr == NULL) {
7536 pr_err("%s: mmap APR handle NULL\n", __func__);
7537 return -EINVAL;
7538 }
7539 pr_debug("%s: Session[%d]\n", __func__, ac->session);
7540
7541 cmd_size = sizeof(struct avs_cmd_shared_mem_unmap_regions);
7542 q6asm_add_mmaphdr(ac, &mem_unmap.hdr, cmd_size, dir);
7543 atomic_set(&ac->mem_state, -1);
7544 port = &ac->port[dir];
7545 buf_add = port->buf->phys;
7546 mem_unmap.hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS;
7547 mem_unmap.mem_map_handle = 0;
7548 list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
7549 buf_node = list_entry(ptr, struct asm_buffer_node,
7550 list);
7551 if (buf_node->buf_phys_addr == buf_add) {
7552 pr_debug("%s: Found the element\n", __func__);
7553 mem_unmap.mem_map_handle = buf_node->mmap_hdl;
7554 break;
7555 }
7556 }
7557
7558 pr_debug("%s: mem_unmap-mem_map_handle: 0x%x\n",
7559 __func__, mem_unmap.mem_map_handle);
7560
7561 if (mem_unmap.mem_map_handle == 0) {
7562 pr_err("%s: Do not send null mem handle to DSP\n", __func__);
7563 rc = 0;
7564 goto fail_cmd;
7565 }
7566 rc = apr_send_pkt(ac->mmap_apr, (uint32_t *) &mem_unmap);
7567 if (rc < 0) {
7568 pr_err("mmap_regions op[0x%x]rc[%d]\n",
7569 mem_unmap.hdr.opcode, rc);
7570 goto fail_cmd;
7571 }
7572
7573 rc = wait_event_timeout(ac->mem_wait,
7574 (atomic_read(&ac->mem_state) >= 0), 5*HZ);
7575 if (!rc) {
7576 pr_err("%s: timeout. waited for memory_unmap of handle 0x%x\n",
7577 __func__, mem_unmap.mem_map_handle);
7578 rc = -ETIMEDOUT;
7579 goto fail_cmd;
7580 } else if (atomic_read(&ac->mem_state) > 0) {
7581 pr_err("%s: DSP returned error[%s]\n",
7582 __func__, adsp_err_get_err_str(
7583 atomic_read(&ac->mem_state)));
7584 rc = adsp_err_get_lnx_err_code(
7585 atomic_read(&ac->mem_state));
7586 goto fail_cmd;
7587 } else if (atomic_read(&ac->unmap_cb_success) == 0) {
7588 pr_err("%s: Error in mem unmap callback of handle 0x%x\n",
7589 __func__, mem_unmap.mem_map_handle);
7590 rc = -EINVAL;
7591 goto fail_cmd;
7592 }
7593 rc = 0;
7594
7595fail_cmd:
7596 list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
7597 buf_node = list_entry(ptr, struct asm_buffer_node,
7598 list);
7599 if (buf_node->buf_phys_addr == buf_add) {
7600 list_del(&buf_node->list);
7601 kfree(buf_node);
7602 break;
7603 }
7604 }
7605 return rc;
7606}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307607EXPORT_SYMBOL(q6asm_memory_unmap_regions);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307608
7609int q6asm_set_lrgain(struct audio_client *ac, int left_gain, int right_gain)
7610{
7611 struct asm_volume_ctrl_multichannel_gain multi_ch_gain;
7612 int sz = 0;
7613 int rc = 0;
Xiaojun Sanga4648082018-04-27 14:57:33 +08007614 int session_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307615
7616 if (ac == NULL) {
7617 pr_err("%s: APR handle NULL\n", __func__);
7618 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08007619 goto done;
7620 }
7621
7622 session_id = q6asm_get_session_id_from_audio_client(ac);
7623 if (!session_id) {
7624 rc = -EINVAL;
7625 goto done;
7626 }
7627
7628 mutex_lock(&session[session_id].mutex_lock_per_session);
7629 if (!q6asm_is_valid_audio_client(ac)) {
7630 rc = -EINVAL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307631 goto fail_cmd;
7632 }
Xiaojun Sanga4648082018-04-27 14:57:33 +08007633
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307634 if (ac->apr == NULL) {
7635 pr_err("%s: AC APR handle NULL\n", __func__);
7636 rc = -EINVAL;
7637 goto fail_cmd;
7638 }
7639
7640 memset(&multi_ch_gain, 0, sizeof(multi_ch_gain));
7641 sz = sizeof(struct asm_volume_ctrl_multichannel_gain);
7642 q6asm_add_hdr_async(ac, &multi_ch_gain.hdr, sz, TRUE);
7643 atomic_set(&ac->cmd_state_pp, -1);
7644 multi_ch_gain.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
7645 multi_ch_gain.param.data_payload_addr_lsw = 0;
7646 multi_ch_gain.param.data_payload_addr_msw = 0;
7647 multi_ch_gain.param.mem_map_handle = 0;
7648 multi_ch_gain.param.data_payload_size = sizeof(multi_ch_gain) -
7649 sizeof(multi_ch_gain.hdr) - sizeof(multi_ch_gain.param);
7650 multi_ch_gain.data.module_id = ASM_MODULE_ID_VOL_CTRL;
7651 multi_ch_gain.data.param_id = ASM_PARAM_ID_MULTICHANNEL_GAIN;
7652 multi_ch_gain.data.param_size = multi_ch_gain.param.data_payload_size -
7653 sizeof(multi_ch_gain.data);
7654 multi_ch_gain.data.reserved = 0;
7655 multi_ch_gain.gain_data[0].channeltype = PCM_CHANNEL_FL;
7656 multi_ch_gain.gain_data[0].gain = left_gain << 15;
7657 multi_ch_gain.gain_data[1].channeltype = PCM_CHANNEL_FR;
7658 multi_ch_gain.gain_data[1].gain = right_gain << 15;
7659 multi_ch_gain.num_channels = 2;
7660 rc = apr_send_pkt(ac->apr, (uint32_t *) &multi_ch_gain);
7661 if (rc < 0) {
7662 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
7663 __func__, multi_ch_gain.data.param_id, rc);
7664 rc = -EINVAL;
7665 goto fail_cmd;
7666 }
7667
7668 rc = wait_event_timeout(ac->cmd_wait,
7669 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
7670 if (!rc) {
7671 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
7672 multi_ch_gain.data.param_id);
7673 rc = -ETIMEDOUT;
7674 goto fail_cmd;
7675 }
7676 if (atomic_read(&ac->cmd_state_pp) > 0) {
7677 pr_err("%s: DSP returned error[%s] , set-params paramid[0x%x]\n",
7678 __func__, adsp_err_get_err_str(
7679 atomic_read(&ac->cmd_state_pp)),
7680 multi_ch_gain.data.param_id);
7681 rc = adsp_err_get_lnx_err_code(
7682 atomic_read(&ac->cmd_state_pp));
7683 goto fail_cmd;
7684 }
7685 rc = 0;
7686fail_cmd:
Xiaojun Sanga4648082018-04-27 14:57:33 +08007687 mutex_unlock(&session[session_id].mutex_lock_per_session);
7688done:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307689 return rc;
7690}
7691
7692/*
7693 * q6asm_set_multich_gain: set multiple channel gains on an ASM session
7694 * @ac: audio client handle
7695 * @channels: number of channels caller intends to set gains
7696 * @gains: list of gains of audio channels
7697 * @ch_map: list of channel mapping. Only valid if use_default is false
7698 * @use_default: flag to indicate whether to use default mapping
7699 */
7700int q6asm_set_multich_gain(struct audio_client *ac, uint32_t channels,
7701 uint32_t *gains, uint8_t *ch_map, bool use_default)
7702{
7703 struct asm_volume_ctrl_multichannel_gain multich_gain;
7704 int sz = 0;
7705 int rc = 0;
Xiaojun Sanga4648082018-04-27 14:57:33 +08007706 int i, session_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307707 u8 default_chmap[VOLUME_CONTROL_MAX_CHANNELS];
7708
7709 if (ac == NULL) {
7710 pr_err("%s: ac is NULL\n", __func__);
7711 rc = -EINVAL;
7712 goto done;
7713 }
Xiaojun Sanga4648082018-04-27 14:57:33 +08007714
7715 session_id = q6asm_get_session_id_from_audio_client(ac);
7716 if (!session_id) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307717 rc = -EINVAL;
7718 goto done;
7719 }
7720
7721 memset(&multich_gain, 0, sizeof(multich_gain));
7722 sz = sizeof(struct asm_volume_ctrl_multichannel_gain);
Xiaojun Sanga4648082018-04-27 14:57:33 +08007723 mutex_lock(&session[session_id].mutex_lock_per_session);
7724 if (!q6asm_is_valid_audio_client(ac)) {
7725 rc = -EINVAL;
7726 goto fail_cmd;
7727 }
7728
7729 if (ac->apr == NULL) {
7730 dev_err(ac->dev, "%s: AC APR handle NULL\n", __func__);
7731 rc = -EINVAL;
7732 goto fail_cmd;
7733 }
7734
7735 if (gains == NULL) {
7736 dev_err(ac->dev, "%s: gain_list is NULL\n", __func__);
7737 rc = -EINVAL;
7738 goto fail_cmd;
7739 }
7740 if (channels > VOLUME_CONTROL_MAX_CHANNELS) {
7741 dev_err(ac->dev, "%s: Invalid channel count %d\n",
7742 __func__, channels);
7743 rc = -EINVAL;
7744 goto fail_cmd;
7745 }
7746 if (!use_default && ch_map == NULL) {
7747 dev_err(ac->dev, "%s: NULL channel map\n", __func__);
7748 rc = -EINVAL;
7749 goto fail_cmd;
7750 }
7751
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307752 q6asm_add_hdr_async(ac, &multich_gain.hdr, sz, TRUE);
7753 atomic_set(&ac->cmd_state_pp, -1);
7754 multich_gain.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
7755 multich_gain.param.data_payload_addr_lsw = 0;
7756 multich_gain.param.data_payload_addr_msw = 0;
7757 multich_gain.param.mem_map_handle = 0;
7758 multich_gain.param.data_payload_size = sizeof(multich_gain) -
7759 sizeof(multich_gain.hdr) - sizeof(multich_gain.param);
7760 multich_gain.data.module_id = ASM_MODULE_ID_VOL_CTRL;
7761 multich_gain.data.param_id = ASM_PARAM_ID_MULTICHANNEL_GAIN;
7762 multich_gain.data.param_size = multich_gain.param.data_payload_size -
7763 sizeof(multich_gain.data);
7764 multich_gain.data.reserved = 0;
7765
7766 if (use_default) {
7767 rc = q6asm_map_channels(default_chmap, channels, false);
7768 if (rc < 0)
Xiaojun Sanga4648082018-04-27 14:57:33 +08007769 goto fail_cmd;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307770 for (i = 0; i < channels; i++) {
7771 multich_gain.gain_data[i].channeltype =
7772 default_chmap[i];
7773 multich_gain.gain_data[i].gain = gains[i] << 15;
7774 }
7775 } else {
7776 for (i = 0; i < channels; i++) {
7777 multich_gain.gain_data[i].channeltype = ch_map[i];
7778 multich_gain.gain_data[i].gain = gains[i] << 15;
7779 }
7780 }
7781 multich_gain.num_channels = channels;
7782
7783 rc = apr_send_pkt(ac->apr, (uint32_t *) &multich_gain);
7784 if (rc < 0) {
7785 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
7786 __func__, multich_gain.data.param_id, rc);
Xiaojun Sanga4648082018-04-27 14:57:33 +08007787 goto fail_cmd;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307788 }
7789
7790 rc = wait_event_timeout(ac->cmd_wait,
7791 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
7792 if (!rc) {
7793 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
7794 multich_gain.data.param_id);
7795 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08007796 goto fail_cmd;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307797 }
7798 if (atomic_read(&ac->cmd_state_pp) > 0) {
7799 pr_err("%s: DSP returned error[%d] , set-params paramid[0x%x]\n",
7800 __func__, atomic_read(&ac->cmd_state_pp),
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 rc = 0;
Xiaojun Sanga4648082018-04-27 14:57:33 +08007806fail_cmd:
7807 mutex_unlock(&session[session_id].mutex_lock_per_session);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307808done:
7809 return rc;
7810}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307811EXPORT_SYMBOL(q6asm_set_multich_gain);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307812
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307813/**
7814 * q6asm_set_mute -
7815 * command to set mute for ASM
7816 *
7817 * @ac: Audio client handle
7818 * @muteflag: mute value
7819 *
7820 * Returns 0 on success or error on failure
7821 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307822int q6asm_set_mute(struct audio_client *ac, int muteflag)
7823{
7824 struct asm_volume_ctrl_mute_config mute;
7825 int sz = 0;
7826 int rc = 0;
Xiaojun Sanga4648082018-04-27 14:57:33 +08007827 int session_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307828
7829 if (ac == NULL) {
7830 pr_err("%s: APR handle NULL\n", __func__);
7831 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08007832 goto done;
7833 }
7834
7835 session_id = q6asm_get_session_id_from_audio_client(ac);
7836 if (!session_id) {
7837 rc = -EINVAL;
7838 goto done;
7839 }
7840
7841 mutex_lock(&session[session_id].mutex_lock_per_session);
7842 if (!q6asm_is_valid_audio_client(ac)) {
7843 rc = -EINVAL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307844 goto fail_cmd;
7845 }
Xiaojun Sanga4648082018-04-27 14:57:33 +08007846
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307847 if (ac->apr == NULL) {
7848 pr_err("%s: AC APR handle NULL\n", __func__);
7849 rc = -EINVAL;
7850 goto fail_cmd;
7851 }
7852
7853 sz = sizeof(struct asm_volume_ctrl_mute_config);
7854 q6asm_add_hdr_async(ac, &mute.hdr, sz, TRUE);
7855 atomic_set(&ac->cmd_state_pp, -1);
7856 mute.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
7857 mute.param.data_payload_addr_lsw = 0;
7858 mute.param.data_payload_addr_msw = 0;
7859 mute.param.mem_map_handle = 0;
7860 mute.param.data_payload_size = sizeof(mute) -
7861 sizeof(mute.hdr) - sizeof(mute.param);
7862 mute.data.module_id = ASM_MODULE_ID_VOL_CTRL;
7863 mute.data.param_id = ASM_PARAM_ID_VOL_CTRL_MUTE_CONFIG;
7864 mute.data.param_size = mute.param.data_payload_size - sizeof(mute.data);
7865 mute.data.reserved = 0;
7866 mute.mute_flag = muteflag;
7867
7868 rc = apr_send_pkt(ac->apr, (uint32_t *) &mute);
7869 if (rc < 0) {
7870 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
7871 __func__, mute.data.param_id, rc);
7872 rc = -EINVAL;
7873 goto fail_cmd;
7874 }
7875
7876 rc = wait_event_timeout(ac->cmd_wait,
7877 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
7878 if (!rc) {
7879 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
7880 mute.data.param_id);
7881 rc = -ETIMEDOUT;
7882 goto fail_cmd;
7883 }
7884 if (atomic_read(&ac->cmd_state_pp) > 0) {
7885 pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
7886 __func__, adsp_err_get_err_str(
7887 atomic_read(&ac->cmd_state_pp)),
7888 mute.data.param_id);
7889 rc = adsp_err_get_lnx_err_code(
7890 atomic_read(&ac->cmd_state_pp));
7891 goto fail_cmd;
7892 }
7893 rc = 0;
7894fail_cmd:
Xiaojun Sanga4648082018-04-27 14:57:33 +08007895 mutex_unlock(&session[session_id].mutex_lock_per_session);
7896done:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307897 return rc;
7898}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307899EXPORT_SYMBOL(q6asm_set_mute);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307900
7901static int __q6asm_set_volume(struct audio_client *ac, int volume, int instance)
7902{
7903 struct asm_volume_ctrl_master_gain vol;
7904 int sz = 0;
7905 int rc = 0;
Xiaojun Sanga4648082018-04-27 14:57:33 +08007906 int module_id, session_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307907
7908 if (ac == NULL) {
7909 pr_err("%s: APR handle NULL\n", __func__);
7910 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08007911 goto done;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307912 }
Xiaojun Sanga4648082018-04-27 14:57:33 +08007913
7914 session_id = q6asm_get_session_id_from_audio_client(ac);
7915 if (!session_id) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307916 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08007917 goto done;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307918 }
7919
7920 switch (instance) {
7921 case SOFT_VOLUME_INSTANCE_2:
7922 module_id = ASM_MODULE_ID_VOL_CTRL2;
7923 break;
7924 case SOFT_VOLUME_INSTANCE_1:
7925 default:
7926 module_id = ASM_MODULE_ID_VOL_CTRL;
7927 break;
7928 }
7929
7930 sz = sizeof(struct asm_volume_ctrl_master_gain);
Xiaojun Sanga4648082018-04-27 14:57:33 +08007931 mutex_lock(&session[session_id].mutex_lock_per_session);
7932 if (!q6asm_is_valid_audio_client(ac)) {
7933 rc = -EINVAL;
7934 goto fail_cmd;
7935 }
7936
7937 if (ac->apr == NULL) {
7938 pr_err("%s: AC APR handle NULL\n", __func__);
7939 rc = -EINVAL;
7940 goto fail_cmd;
7941 }
7942
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307943 q6asm_add_hdr_async(ac, &vol.hdr, sz, TRUE);
7944 atomic_set(&ac->cmd_state_pp, -1);
7945 vol.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
7946 vol.param.data_payload_addr_lsw = 0;
7947 vol.param.data_payload_addr_msw = 0;
7948 vol.param.mem_map_handle = 0;
7949 vol.param.data_payload_size = sizeof(vol) -
7950 sizeof(vol.hdr) - sizeof(vol.param);
7951 vol.data.module_id = module_id;
7952 vol.data.param_id = ASM_PARAM_ID_VOL_CTRL_MASTER_GAIN;
7953 vol.data.param_size = vol.param.data_payload_size - sizeof(vol.data);
7954 vol.data.reserved = 0;
7955 vol.master_gain = volume;
7956
7957 rc = apr_send_pkt(ac->apr, (uint32_t *) &vol);
7958 if (rc < 0) {
7959 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
7960 __func__, vol.data.param_id, rc);
7961 rc = -EINVAL;
7962 goto fail_cmd;
7963 }
7964
7965 rc = wait_event_timeout(ac->cmd_wait,
7966 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
7967 if (!rc) {
7968 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
7969 vol.data.param_id);
7970 rc = -ETIMEDOUT;
7971 goto fail_cmd;
7972 }
7973 if (atomic_read(&ac->cmd_state_pp) > 0) {
7974 pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
7975 __func__, adsp_err_get_err_str(
7976 atomic_read(&ac->cmd_state_pp)),
7977 vol.data.param_id);
7978 rc = adsp_err_get_lnx_err_code(
7979 atomic_read(&ac->cmd_state_pp));
7980 goto fail_cmd;
7981 }
7982
7983 rc = 0;
7984fail_cmd:
Xiaojun Sanga4648082018-04-27 14:57:33 +08007985 mutex_unlock(&session[session_id].mutex_lock_per_session);
7986done:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307987 return rc;
7988}
7989
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05307990/**
7991 * q6asm_set_volume -
7992 * command to set volume for ASM
7993 *
7994 * @ac: Audio client handle
7995 * @volume: volume level
7996 *
7997 * Returns 0 on success or error on failure
7998 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05307999int q6asm_set_volume(struct audio_client *ac, int volume)
8000{
8001 return __q6asm_set_volume(ac, volume, SOFT_VOLUME_INSTANCE_1);
8002}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308003EXPORT_SYMBOL(q6asm_set_volume);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308004
8005int q6asm_set_volume_v2(struct audio_client *ac, int volume, int instance)
8006{
8007 return __q6asm_set_volume(ac, volume, instance);
8008}
8009
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308010/**
8011 * q6asm_set_aptx_dec_bt_addr -
8012 * command to aptx decoder BT addr for ASM
8013 *
8014 * @ac: Audio client handle
8015 * @cfg: APTX decoder bt addr config
8016 *
8017 * Returns 0 on success or error on failure
8018 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308019int q6asm_set_aptx_dec_bt_addr(struct audio_client *ac,
8020 struct aptx_dec_bt_addr_cfg *cfg)
8021{
8022 struct aptx_dec_bt_dev_addr paylod;
8023 int sz = 0;
8024 int rc = 0;
8025
8026 pr_debug("%s: BT addr nap %d, uap %d, lap %d\n", __func__, cfg->nap,
8027 cfg->uap, cfg->lap);
8028
8029 if (ac == NULL) {
8030 pr_err("%s: AC handle NULL\n", __func__);
8031 rc = -EINVAL;
8032 goto fail_cmd;
8033 }
8034 if (ac->apr == NULL) {
8035 pr_err("%s: AC APR handle NULL\n", __func__);
8036 rc = -EINVAL;
8037 goto fail_cmd;
8038 }
8039
8040 sz = sizeof(struct aptx_dec_bt_dev_addr);
8041 q6asm_add_hdr_async(ac, &paylod.hdr, sz, TRUE);
8042 atomic_set(&ac->cmd_state, -1);
8043 paylod.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
8044 paylod.encdec.param_id = APTX_DECODER_BT_ADDRESS;
8045 paylod.encdec.param_size = sz - sizeof(paylod.hdr)
8046 - sizeof(paylod.encdec);
8047 paylod.bt_addr_cfg.lap = cfg->lap;
8048 paylod.bt_addr_cfg.uap = cfg->uap;
8049 paylod.bt_addr_cfg.nap = cfg->nap;
8050
8051 rc = apr_send_pkt(ac->apr, (uint32_t *) &paylod);
8052 if (rc < 0) {
8053 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
8054 __func__, paylod.encdec.param_id, rc);
8055 rc = -EINVAL;
8056 goto fail_cmd;
8057 }
8058
8059 rc = wait_event_timeout(ac->cmd_wait,
8060 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
8061 if (!rc) {
8062 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
8063 paylod.encdec.param_id);
8064 rc = -ETIMEDOUT;
8065 goto fail_cmd;
8066 }
8067 if (atomic_read(&ac->cmd_state) > 0) {
8068 pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
8069 __func__, adsp_err_get_err_str(
8070 atomic_read(&ac->cmd_state)),
8071 paylod.encdec.param_id);
8072 rc = adsp_err_get_lnx_err_code(
8073 atomic_read(&ac->cmd_state));
8074 goto fail_cmd;
8075 }
8076 pr_debug("%s: set BT addr is success\n", __func__);
8077 rc = 0;
8078fail_cmd:
8079 return rc;
8080}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308081EXPORT_SYMBOL(q6asm_set_aptx_dec_bt_addr);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308082
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308083/**
8084 * q6asm_send_ion_fd -
8085 * command to send ION memory map for ASM
8086 *
8087 * @ac: Audio client handle
8088 * @fd: ION file desc
8089 *
8090 * Returns 0 on success or error on failure
8091 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308092int q6asm_send_ion_fd(struct audio_client *ac, int fd)
8093{
8094 struct ion_client *client;
8095 struct ion_handle *handle;
8096 ion_phys_addr_t paddr;
8097 size_t pa_len = 0;
8098 void *vaddr;
8099 int ret;
8100 int sz = 0;
8101 struct avs_rtic_shared_mem_addr shm;
8102
8103 if (ac == NULL) {
8104 pr_err("%s: APR handle NULL\n", __func__);
8105 ret = -EINVAL;
8106 goto fail_cmd;
8107 }
8108 if (ac->apr == NULL) {
8109 pr_err("%s: AC APR handle NULL\n", __func__);
8110 ret = -EINVAL;
8111 goto fail_cmd;
8112 }
8113
8114 ret = msm_audio_ion_import("audio_mem_client",
8115 &client,
8116 &handle,
8117 fd,
8118 NULL,
8119 0,
8120 &paddr,
8121 &pa_len,
8122 &vaddr);
8123 if (ret) {
8124 pr_err("%s: audio ION import failed, rc = %d\n",
8125 __func__, ret);
8126 ret = -ENOMEM;
8127 goto fail_cmd;
8128 }
8129 /* get payload length */
8130 sz = sizeof(struct avs_rtic_shared_mem_addr);
8131 q6asm_add_hdr_async(ac, &shm.hdr, sz, TRUE);
8132 atomic_set(&ac->cmd_state, -1);
8133 shm.shm_buf_addr_lsw = lower_32_bits(paddr);
8134 shm.shm_buf_addr_msw = msm_audio_populate_upper_32_bits(paddr);
8135 shm.buf_size = pa_len;
8136 shm.shm_buf_num_regions = 1;
8137 shm.shm_buf_mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
8138 shm.shm_buf_flag = 0x00;
8139 shm.encdec.param_id = AVS_PARAM_ID_RTIC_SHARED_MEMORY_ADDR;
8140 shm.encdec.param_size = sizeof(struct avs_rtic_shared_mem_addr) -
8141 sizeof(struct apr_hdr) -
8142 sizeof(struct asm_stream_cmd_set_encdec_param_v2);
8143 shm.encdec.service_id = OUT;
8144 shm.encdec.reserved = 0;
8145 shm.map_region.shm_addr_lsw = shm.shm_buf_addr_lsw;
8146 shm.map_region.shm_addr_msw = shm.shm_buf_addr_msw;
8147 shm.map_region.mem_size_bytes = pa_len;
8148 shm.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM_V2;
8149 ret = apr_send_pkt(ac->apr, (uint32_t *) &shm);
8150 if (ret < 0) {
8151 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
8152 __func__, shm.encdec.param_id, ret);
8153 ret = -EINVAL;
8154 goto fail_cmd;
8155 }
8156
8157 ret = wait_event_timeout(ac->cmd_wait,
8158 (atomic_read(&ac->cmd_state) >= 0), 1*HZ);
8159 if (!ret) {
8160 pr_err("%s: timeout, shm.encdec paramid[0x%x]\n", __func__,
8161 shm.encdec.param_id);
8162 ret = -ETIMEDOUT;
8163 goto fail_cmd;
8164 }
8165 if (atomic_read(&ac->cmd_state) > 0) {
8166 pr_err("%s: DSP returned error[%s] shm.encdec paramid[0x%x]\n",
8167 __func__,
8168 adsp_err_get_err_str(atomic_read(&ac->cmd_state)),
8169 shm.encdec.param_id);
8170 ret = adsp_err_get_lnx_err_code(atomic_read(&ac->cmd_state));
8171 goto fail_cmd;
8172 }
8173 ret = 0;
8174fail_cmd:
8175 return ret;
8176}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308177EXPORT_SYMBOL(q6asm_send_ion_fd);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308178
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308179/**
8180 * q6asm_send_rtic_event_ack -
8181 * command to send RTIC event ack
8182 *
8183 * @ac: Audio client handle
8184 * @param: params for event ack
8185 * @params_length: length of params
8186 *
8187 * Returns 0 on success or error on failure
8188 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308189int q6asm_send_rtic_event_ack(struct audio_client *ac,
8190 void *param, uint32_t params_length)
8191{
8192 char *asm_params = NULL;
8193 int sz, rc;
8194 struct avs_param_rtic_event_ack ack;
8195
8196 if (!param || !ac) {
8197 pr_err("%s: %s is NULL\n", __func__,
8198 (!param) ? "param" : "ac");
8199 rc = -EINVAL;
8200 goto done;
8201 }
8202
8203 sz = sizeof(struct avs_param_rtic_event_ack) + params_length;
8204 asm_params = kzalloc(sz, GFP_KERNEL);
8205 if (!asm_params) {
8206 rc = -ENOMEM;
8207 goto done;
8208 }
8209
8210 q6asm_add_hdr_async(ac, &ack.hdr,
8211 sizeof(struct avs_param_rtic_event_ack) +
8212 params_length, TRUE);
8213 atomic_set(&ac->cmd_state, -1);
8214 ack.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM_V2;
8215 ack.encdec.param_id = AVS_PARAM_ID_RTIC_EVENT_ACK;
8216 ack.encdec.param_size = params_length;
8217 ack.encdec.reserved = 0;
8218 ack.encdec.service_id = OUT;
8219 memcpy(asm_params, &ack, sizeof(struct avs_param_rtic_event_ack));
8220 memcpy(asm_params + sizeof(struct avs_param_rtic_event_ack),
8221 param, params_length);
8222 rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params);
8223 if (rc < 0) {
8224 pr_err("%s: apr pkt failed for rtic event ack\n", __func__);
8225 rc = -EINVAL;
8226 goto fail_send_param;
8227 }
8228
8229 rc = wait_event_timeout(ac->cmd_wait,
8230 (atomic_read(&ac->cmd_state) >= 0), 1 * HZ);
8231 if (!rc) {
8232 pr_err("%s: timeout for rtic event ack cmd\n", __func__);
8233 rc = -ETIMEDOUT;
8234 goto fail_send_param;
8235 }
8236
8237 if (atomic_read(&ac->cmd_state) > 0) {
8238 pr_err("%s: DSP returned error[%s] for rtic event ack cmd\n",
8239 __func__, adsp_err_get_err_str(
8240 atomic_read(&ac->cmd_state)));
8241 rc = adsp_err_get_lnx_err_code(
8242 atomic_read(&ac->cmd_state));
8243 goto fail_send_param;
8244 }
8245 rc = 0;
8246
8247fail_send_param:
8248 kfree(asm_params);
8249done:
8250 return rc;
8251}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308252EXPORT_SYMBOL(q6asm_send_rtic_event_ack);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308253
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308254/**
8255 * q6asm_set_softpause -
8256 * command to set pause for ASM
8257 *
8258 * @ac: Audio client handle
8259 * @pause_param: params for pause
8260 *
8261 * Returns 0 on success or error on failure
8262 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308263int q6asm_set_softpause(struct audio_client *ac,
8264 struct asm_softpause_params *pause_param)
8265{
8266 struct asm_soft_pause_params softpause;
8267 int sz = 0;
8268 int rc = 0;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008269 int session_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308270
8271 if (ac == NULL) {
8272 pr_err("%s: APR handle NULL\n", __func__);
8273 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008274 goto done;
8275 }
8276
8277 session_id = q6asm_get_session_id_from_audio_client(ac);
8278 if (!session_id) {
8279 rc = -EINVAL;
8280 goto done;
8281 }
8282
8283 mutex_lock(&session[session_id].mutex_lock_per_session);
8284 if (!q6asm_is_valid_audio_client(ac)) {
8285 rc = -EINVAL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308286 goto fail_cmd;
8287 }
Xiaojun Sanga4648082018-04-27 14:57:33 +08008288
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308289 if (ac->apr == NULL) {
8290 pr_err("%s: AC APR handle NULL\n", __func__);
8291 rc = -EINVAL;
8292 goto fail_cmd;
8293 }
8294
8295 sz = sizeof(struct asm_soft_pause_params);
8296 q6asm_add_hdr_async(ac, &softpause.hdr, sz, TRUE);
8297 atomic_set(&ac->cmd_state_pp, -1);
8298 softpause.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
8299
8300 softpause.param.data_payload_addr_lsw = 0;
8301 softpause.param.data_payload_addr_msw = 0;
8302 softpause.param.mem_map_handle = 0;
8303 softpause.param.data_payload_size = sizeof(softpause) -
8304 sizeof(softpause.hdr) - sizeof(softpause.param);
8305 softpause.data.module_id = ASM_MODULE_ID_VOL_CTRL;
8306 softpause.data.param_id = ASM_PARAM_ID_SOFT_PAUSE_PARAMETERS;
8307 softpause.data.param_size = softpause.param.data_payload_size -
8308 sizeof(softpause.data);
8309 softpause.data.reserved = 0;
8310 softpause.enable_flag = pause_param->enable;
8311 softpause.period = pause_param->period;
8312 softpause.step = pause_param->step;
8313 softpause.ramping_curve = pause_param->rampingcurve;
8314
8315 rc = apr_send_pkt(ac->apr, (uint32_t *) &softpause);
8316 if (rc < 0) {
8317 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
8318 __func__, softpause.data.param_id, rc);
8319 rc = -EINVAL;
8320 goto fail_cmd;
8321 }
8322
8323 rc = wait_event_timeout(ac->cmd_wait,
8324 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
8325 if (!rc) {
8326 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
8327 softpause.data.param_id);
8328 rc = -ETIMEDOUT;
8329 goto fail_cmd;
8330 }
8331 if (atomic_read(&ac->cmd_state_pp) > 0) {
8332 pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
8333 __func__, adsp_err_get_err_str(
8334 atomic_read(&ac->cmd_state_pp)),
8335 softpause.data.param_id);
8336 rc = adsp_err_get_lnx_err_code(
8337 atomic_read(&ac->cmd_state_pp));
8338 goto fail_cmd;
8339 }
8340 rc = 0;
8341fail_cmd:
Xiaojun Sanga4648082018-04-27 14:57:33 +08008342 mutex_unlock(&session[session_id].mutex_lock_per_session);
8343done:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308344 return rc;
8345}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308346EXPORT_SYMBOL(q6asm_set_softpause);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308347
8348static int __q6asm_set_softvolume(struct audio_client *ac,
8349 struct asm_softvolume_params *softvol_param,
8350 int instance)
8351{
8352 struct asm_soft_step_volume_params softvol;
8353 int sz = 0;
8354 int rc = 0;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008355 int module_id, session_id;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308356
8357 if (ac == NULL) {
8358 pr_err("%s: APR handle NULL\n", __func__);
8359 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008360 goto done;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308361 }
Xiaojun Sanga4648082018-04-27 14:57:33 +08008362
8363 session_id = q6asm_get_session_id_from_audio_client(ac);
8364 if (!session_id) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308365 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008366 goto done;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308367 }
8368
8369 switch (instance) {
8370 case SOFT_VOLUME_INSTANCE_2:
8371 module_id = ASM_MODULE_ID_VOL_CTRL2;
8372 break;
8373 case SOFT_VOLUME_INSTANCE_1:
8374 default:
8375 module_id = ASM_MODULE_ID_VOL_CTRL;
8376 break;
8377 }
8378
8379 sz = sizeof(struct asm_soft_step_volume_params);
Xiaojun Sanga4648082018-04-27 14:57:33 +08008380 mutex_lock(&session[session_id].mutex_lock_per_session);
8381 if (!q6asm_is_valid_audio_client(ac)) {
8382 rc = -EINVAL;
8383 goto fail_cmd;
8384 }
8385
8386 if (ac->apr == NULL) {
8387 pr_err("%s: AC APR handle NULL\n", __func__);
8388 rc = -EINVAL;
8389 goto fail_cmd;
8390 }
8391
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308392 q6asm_add_hdr_async(ac, &softvol.hdr, sz, TRUE);
8393 atomic_set(&ac->cmd_state_pp, -1);
8394 softvol.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
8395 softvol.param.data_payload_addr_lsw = 0;
8396 softvol.param.data_payload_addr_msw = 0;
8397 softvol.param.mem_map_handle = 0;
8398 softvol.param.data_payload_size = sizeof(softvol) -
8399 sizeof(softvol.hdr) - sizeof(softvol.param);
8400 softvol.data.module_id = module_id;
8401 softvol.data.param_id = ASM_PARAM_ID_SOFT_VOL_STEPPING_PARAMETERS;
8402 softvol.data.param_size = softvol.param.data_payload_size -
8403 sizeof(softvol.data);
8404 softvol.data.reserved = 0;
8405 softvol.period = softvol_param->period;
8406 softvol.step = softvol_param->step;
8407 softvol.ramping_curve = softvol_param->rampingcurve;
8408
8409 rc = apr_send_pkt(ac->apr, (uint32_t *) &softvol);
8410 if (rc < 0) {
8411 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
8412 __func__, softvol.data.param_id, rc);
8413 rc = -EINVAL;
8414 goto fail_cmd;
8415 }
8416
8417 rc = wait_event_timeout(ac->cmd_wait,
8418 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
8419 if (!rc) {
8420 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
8421 softvol.data.param_id);
8422 rc = -ETIMEDOUT;
8423 goto fail_cmd;
8424 }
8425 if (atomic_read(&ac->cmd_state_pp) > 0) {
8426 pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
8427 __func__, adsp_err_get_err_str(
8428 atomic_read(&ac->cmd_state_pp)),
8429 softvol.data.param_id);
8430 rc = adsp_err_get_lnx_err_code(
8431 atomic_read(&ac->cmd_state_pp));
8432 goto fail_cmd;
8433 }
8434 rc = 0;
8435fail_cmd:
Xiaojun Sanga4648082018-04-27 14:57:33 +08008436 mutex_unlock(&session[session_id].mutex_lock_per_session);
8437done:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308438 return rc;
8439}
8440
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308441/**
8442 * q6asm_set_softvolume -
8443 * command to set softvolume for ASM
8444 *
8445 * @ac: Audio client handle
8446 * @softvol_param: params for softvol
8447 *
8448 * Returns 0 on success or error on failure
8449 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308450int q6asm_set_softvolume(struct audio_client *ac,
8451 struct asm_softvolume_params *softvol_param)
8452{
8453 return __q6asm_set_softvolume(ac, softvol_param,
8454 SOFT_VOLUME_INSTANCE_1);
8455}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308456EXPORT_SYMBOL(q6asm_set_softvolume);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308457
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308458/**
8459 * q6asm_set_softvolume_v2 -
8460 * command to set softvolume V2 for ASM
8461 *
8462 * @ac: Audio client handle
8463 * @softvol_param: params for softvol
8464 * @instance: instance to apply softvol
8465 *
8466 * Returns 0 on success or error on failure
8467 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308468int q6asm_set_softvolume_v2(struct audio_client *ac,
8469 struct asm_softvolume_params *softvol_param,
8470 int instance)
8471{
8472 return __q6asm_set_softvolume(ac, softvol_param, instance);
8473}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308474EXPORT_SYMBOL(q6asm_set_softvolume_v2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308475
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308476/**
8477 * q6asm_equalizer -
8478 * command to set equalizer for ASM
8479 *
8480 * @ac: Audio client handle
8481 * @eq_p: Equalizer params
8482 *
8483 * Returns 0 on success or error on failure
8484 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308485int q6asm_equalizer(struct audio_client *ac, void *eq_p)
8486{
8487 struct asm_eq_params eq;
8488 struct msm_audio_eq_stream_config *eq_params = NULL;
8489 int i = 0;
8490 int sz = 0;
8491 int rc = 0;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008492 int session_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308493
8494 if (ac == NULL) {
8495 pr_err("%s: APR handle NULL\n", __func__);
8496 rc = -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08008497 goto done;
8498 }
8499
8500 session_id = q6asm_get_session_id_from_audio_client(ac);
8501 if (!session_id) {
8502 rc = -EINVAL;
8503 goto done;
8504 }
8505
8506 mutex_lock(&session[session_id].mutex_lock_per_session);
8507 if (!q6asm_is_valid_audio_client(ac)) {
8508 rc = -EINVAL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308509 goto fail_cmd;
8510 }
Xiaojun Sanga4648082018-04-27 14:57:33 +08008511
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308512 if (ac->apr == NULL) {
8513 pr_err("%s: AC APR handle NULL\n", __func__);
8514 rc = -EINVAL;
8515 goto fail_cmd;
8516 }
8517
8518 if (eq_p == NULL) {
8519 pr_err("%s: [%d]: Invalid Eq param\n", __func__, ac->session);
8520 rc = -EINVAL;
8521 goto fail_cmd;
8522 }
8523 sz = sizeof(struct asm_eq_params);
8524 eq_params = (struct msm_audio_eq_stream_config *) eq_p;
8525 q6asm_add_hdr(ac, &eq.hdr, sz, TRUE);
8526 atomic_set(&ac->cmd_state_pp, -1);
8527
8528 eq.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
8529 eq.param.data_payload_addr_lsw = 0;
8530 eq.param.data_payload_addr_msw = 0;
8531 eq.param.mem_map_handle = 0;
8532 eq.param.data_payload_size = sizeof(eq) -
8533 sizeof(eq.hdr) - sizeof(eq.param);
8534 eq.data.module_id = ASM_MODULE_ID_EQUALIZER;
8535 eq.data.param_id = ASM_PARAM_ID_EQUALIZER_PARAMETERS;
8536 eq.data.param_size = eq.param.data_payload_size - sizeof(eq.data);
8537 eq.enable_flag = eq_params->enable;
8538 eq.num_bands = eq_params->num_bands;
8539
8540 pr_debug("%s: enable:%d numbands:%d\n", __func__, eq_params->enable,
8541 eq_params->num_bands);
8542 for (i = 0; i < eq_params->num_bands; i++) {
8543 eq.eq_bands[i].band_idx =
8544 eq_params->eq_bands[i].band_idx;
8545 eq.eq_bands[i].filterype =
8546 eq_params->eq_bands[i].filter_type;
8547 eq.eq_bands[i].center_freq_hz =
8548 eq_params->eq_bands[i].center_freq_hz;
8549 eq.eq_bands[i].filter_gain =
8550 eq_params->eq_bands[i].filter_gain;
8551 eq.eq_bands[i].q_factor =
8552 eq_params->eq_bands[i].q_factor;
8553 pr_debug("%s: filter_type:%u bandnum:%d\n", __func__,
8554 eq_params->eq_bands[i].filter_type, i);
8555 pr_debug("%s: center_freq_hz:%u bandnum:%d\n", __func__,
8556 eq_params->eq_bands[i].center_freq_hz, i);
8557 pr_debug("%s: filter_gain:%d bandnum:%d\n", __func__,
8558 eq_params->eq_bands[i].filter_gain, i);
8559 pr_debug("%s: q_factor:%d bandnum:%d\n", __func__,
8560 eq_params->eq_bands[i].q_factor, i);
8561 }
8562 rc = apr_send_pkt(ac->apr, (uint32_t *)&eq);
8563 if (rc < 0) {
8564 pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
8565 __func__, eq.data.param_id, rc);
8566 rc = -EINVAL;
8567 goto fail_cmd;
8568 }
8569
8570 rc = wait_event_timeout(ac->cmd_wait,
8571 (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
8572 if (!rc) {
8573 pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
8574 eq.data.param_id);
8575 rc = -ETIMEDOUT;
8576 goto fail_cmd;
8577 }
8578 if (atomic_read(&ac->cmd_state_pp) > 0) {
8579 pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
8580 __func__, adsp_err_get_err_str(
8581 atomic_read(&ac->cmd_state_pp)),
8582 eq.data.param_id);
8583 rc = adsp_err_get_lnx_err_code(
8584 atomic_read(&ac->cmd_state_pp));
8585 goto fail_cmd;
8586 }
8587 rc = 0;
8588fail_cmd:
Xiaojun Sanga4648082018-04-27 14:57:33 +08008589 mutex_unlock(&session[session_id].mutex_lock_per_session);
8590done:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308591 return rc;
8592}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308593EXPORT_SYMBOL(q6asm_equalizer);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308594
8595static int __q6asm_read(struct audio_client *ac, bool is_custom_len_reqd,
8596 int len)
8597{
8598 struct asm_data_cmd_read_v2 read;
8599 struct asm_buffer_node *buf_node = NULL;
8600 struct list_head *ptr, *next;
8601 struct audio_buffer *ab;
8602 int dsp_buf;
8603 struct audio_port_data *port;
8604 int rc;
8605
8606 if (ac == NULL) {
8607 pr_err("%s: APR handle NULL\n", __func__);
8608 return -EINVAL;
8609 }
8610 if (ac->apr == NULL) {
8611 pr_err("%s: AC APR handle NULL\n", __func__);
8612 return -EINVAL;
8613 }
8614
8615 if (ac->io_mode & SYNC_IO_MODE) {
8616 port = &ac->port[OUT];
8617
8618 q6asm_add_hdr(ac, &read.hdr, sizeof(read), FALSE);
8619
8620 mutex_lock(&port->lock);
8621
8622 dsp_buf = port->dsp_buf;
8623 if (port->buf == NULL) {
8624 pr_err("%s: buf is NULL\n", __func__);
8625 mutex_unlock(&port->lock);
8626 return -EINVAL;
8627 }
8628 ab = &port->buf[dsp_buf];
8629
8630 dev_vdbg(ac->dev, "%s: session[%d]dsp-buf[%d][%pK]cpu_buf[%d][%pK]\n",
8631 __func__,
8632 ac->session,
8633 dsp_buf,
8634 port->buf[dsp_buf].data,
8635 port->cpu_buf,
8636 &port->buf[port->cpu_buf].phys);
8637
8638 read.hdr.opcode = ASM_DATA_CMD_READ_V2;
8639 read.buf_addr_lsw = lower_32_bits(ab->phys);
8640 read.buf_addr_msw = msm_audio_populate_upper_32_bits(ab->phys);
8641
8642 list_for_each_safe(ptr, next, &ac->port[OUT].mem_map_handle) {
8643 buf_node = list_entry(ptr, struct asm_buffer_node,
8644 list);
Vignesh Kulothunganc894ac42018-01-04 13:49:12 -08008645 if (buf_node->buf_phys_addr == ab->phys) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308646 read.mem_map_handle = buf_node->mmap_hdl;
Vignesh Kulothunganc894ac42018-01-04 13:49:12 -08008647 break;
8648 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308649 }
8650 dev_vdbg(ac->dev, "memory_map handle in q6asm_read: [%0x]:",
8651 read.mem_map_handle);
8652 read.buf_size = is_custom_len_reqd ? len : ab->size;
8653 read.seq_id = port->dsp_buf;
8654 q6asm_update_token(&read.hdr.token,
8655 0, /* Session ID is NA */
8656 0, /* Stream ID is NA */
8657 port->dsp_buf,
8658 0, /* Direction flag is NA */
8659 WAIT_CMD);
8660 port->dsp_buf = q6asm_get_next_buf(ac, port->dsp_buf,
8661 port->max_buf_cnt);
8662 mutex_unlock(&port->lock);
8663 dev_vdbg(ac->dev, "%s: buf add[%pK] token[0x%x] uid[%d]\n",
8664 __func__, &ab->phys, read.hdr.token,
8665 read.seq_id);
8666 rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
8667 if (rc < 0) {
8668 pr_err("%s: read op[0x%x]rc[%d]\n",
8669 __func__, read.hdr.opcode, rc);
8670 goto fail_cmd;
8671 }
8672 return 0;
8673 }
8674fail_cmd:
8675 return -EINVAL;
8676}
8677
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308678/**
8679 * q6asm_read -
8680 * command to read buffer data from DSP
8681 *
8682 * @ac: Audio client handle
8683 *
8684 * Returns 0 on success or error on failure
8685 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308686int q6asm_read(struct audio_client *ac)
8687{
8688 return __q6asm_read(ac, false/*is_custom_len_reqd*/, 0);
8689}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308690EXPORT_SYMBOL(q6asm_read);
8691
8692
8693/**
8694 * q6asm_read_v2 -
8695 * command to read buffer data from DSP
8696 *
8697 * @ac: Audio client handle
8698 * @len: buffer size to read
8699 *
8700 * Returns 0 on success or error on failure
8701 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308702int q6asm_read_v2(struct audio_client *ac, uint32_t len)
8703{
8704 return __q6asm_read(ac, true /*is_custom_len_reqd*/, len);
8705}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308706EXPORT_SYMBOL(q6asm_read_v2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308707
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308708/**
8709 * q6asm_read_nolock -
8710 * command to read buffer data from DSP
8711 * with no wait for ack.
8712 *
8713 * @ac: Audio client handle
8714 *
8715 * Returns 0 on success or error on failure
8716 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308717int q6asm_read_nolock(struct audio_client *ac)
8718{
8719 struct asm_data_cmd_read_v2 read;
8720 struct asm_buffer_node *buf_node = NULL;
8721 struct list_head *ptr, *next;
8722 struct audio_buffer *ab;
8723 int dsp_buf;
8724 struct audio_port_data *port;
8725 int rc;
8726
8727 if (ac == NULL) {
8728 pr_err("%s: APR handle NULL\n", __func__);
8729 return -EINVAL;
8730 }
8731 if (ac->apr == NULL) {
8732 pr_err("%s: AC APR handle NULL\n", __func__);
8733 return -EINVAL;
8734 }
8735
8736 if (ac->io_mode & SYNC_IO_MODE) {
8737 port = &ac->port[OUT];
8738
8739 q6asm_add_hdr_async(ac, &read.hdr, sizeof(read), FALSE);
8740
8741
8742 dsp_buf = port->dsp_buf;
8743 ab = &port->buf[dsp_buf];
8744
8745 dev_vdbg(ac->dev, "%s: session[%d]dsp-buf[%d][%pK]cpu_buf[%d][%pK]\n",
8746 __func__,
8747 ac->session,
8748 dsp_buf,
8749 port->buf[dsp_buf].data,
8750 port->cpu_buf,
8751 &port->buf[port->cpu_buf].phys);
8752
8753 read.hdr.opcode = ASM_DATA_CMD_READ_V2;
8754 read.buf_addr_lsw = lower_32_bits(ab->phys);
8755 read.buf_addr_msw = msm_audio_populate_upper_32_bits(ab->phys);
8756 read.buf_size = ab->size;
8757 read.seq_id = port->dsp_buf;
8758 q6asm_update_token(&read.hdr.token,
8759 0, /* Session ID is NA */
8760 0, /* Stream ID is NA */
8761 port->dsp_buf,
8762 0, /* Direction flag is NA */
8763 WAIT_CMD);
8764
8765 list_for_each_safe(ptr, next, &ac->port[OUT].mem_map_handle) {
8766 buf_node = list_entry(ptr, struct asm_buffer_node,
8767 list);
8768 if (buf_node->buf_phys_addr == ab->phys) {
8769 read.mem_map_handle = buf_node->mmap_hdl;
8770 break;
8771 }
8772 }
8773
8774 port->dsp_buf = q6asm_get_next_buf(ac, port->dsp_buf,
8775 port->max_buf_cnt);
8776 dev_vdbg(ac->dev, "%s: buf add[%pK] token[0x%x] uid[%d]\n",
8777 __func__, &ab->phys, read.hdr.token,
8778 read.seq_id);
8779 rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
8780 if (rc < 0) {
8781 pr_err("%s: read op[0x%x]rc[%d]\n",
8782 __func__, read.hdr.opcode, rc);
8783 goto fail_cmd;
8784 }
8785 return 0;
8786 }
8787fail_cmd:
8788 return -EINVAL;
8789}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308790EXPORT_SYMBOL(q6asm_read_nolock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308791
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308792/**
8793 * q6asm_async_write -
8794 * command to write DSP buffer
8795 *
8796 * @ac: Audio client handle
8797 * @param: params for async write
8798 *
8799 * Returns 0 on success or error on failure
8800 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308801int q6asm_async_write(struct audio_client *ac,
8802 struct audio_aio_write_param *param)
8803{
8804 int rc = 0;
8805 struct asm_data_cmd_write_v2 write;
8806 struct asm_buffer_node *buf_node = NULL;
8807 struct list_head *ptr, *next;
8808 struct audio_buffer *ab;
8809 struct audio_port_data *port;
8810 phys_addr_t lbuf_phys_addr;
8811 u32 liomode;
8812 u32 io_compressed;
8813 u32 io_compressed_stream;
8814
8815 if (ac == NULL) {
8816 pr_err("%s: APR handle NULL\n", __func__);
8817 return -EINVAL;
8818 }
8819 if (ac->apr == NULL) {
8820 pr_err("%s: AC APR handle NULL\n", __func__);
8821 return -EINVAL;
8822 }
8823
8824 q6asm_stream_add_hdr_async(
8825 ac, &write.hdr, sizeof(write), TRUE, ac->stream_id);
8826 port = &ac->port[IN];
8827 ab = &port->buf[port->dsp_buf];
8828
8829 /* Pass session id as token for AIO scheme */
8830 write.hdr.token = param->uid;
8831 write.hdr.opcode = ASM_DATA_CMD_WRITE_V2;
8832 write.buf_addr_lsw = lower_32_bits(param->paddr);
8833 write.buf_addr_msw = msm_audio_populate_upper_32_bits(param->paddr);
8834 write.buf_size = param->len;
8835 write.timestamp_msw = param->msw_ts;
8836 write.timestamp_lsw = param->lsw_ts;
8837 liomode = (ASYNC_IO_MODE | NT_MODE);
8838 io_compressed = (ASYNC_IO_MODE | COMPRESSED_IO);
8839 io_compressed_stream = (ASYNC_IO_MODE | COMPRESSED_STREAM_IO);
8840
8841 if (ac->io_mode == liomode)
8842 lbuf_phys_addr = (param->paddr - 32);
8843 else if (ac->io_mode == io_compressed ||
8844 ac->io_mode == io_compressed_stream)
8845 lbuf_phys_addr = (param->paddr - param->metadata_len);
8846 else {
8847 if (param->flags & SET_TIMESTAMP)
8848 lbuf_phys_addr = param->paddr -
8849 sizeof(struct snd_codec_metadata);
8850 else
8851 lbuf_phys_addr = param->paddr;
8852 }
8853 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",
8854 __func__,
8855 write.hdr.token, &param->paddr,
8856 write.buf_size, write.timestamp_msw,
8857 write.timestamp_lsw, &lbuf_phys_addr);
8858
8859 /* Use 0xFF00 for disabling timestamps */
8860 if (param->flags == 0xFF00)
8861 write.flags = (0x00000000 | (param->flags & 0x800000FF));
8862 else
8863 write.flags = (0x80000000 | param->flags);
8864 write.flags |= param->last_buffer << ASM_SHIFT_LAST_BUFFER_FLAG;
8865 write.seq_id = param->uid;
8866 list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
8867 buf_node = list_entry(ptr, struct asm_buffer_node,
8868 list);
8869 if (buf_node->buf_phys_addr == lbuf_phys_addr) {
8870 write.mem_map_handle = buf_node->mmap_hdl;
8871 break;
8872 }
8873 }
8874
8875 rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
8876 if (rc < 0) {
8877 pr_err("%s: write op[0x%x]rc[%d]\n", __func__,
8878 write.hdr.opcode, rc);
8879 goto fail_cmd;
8880 }
8881 return 0;
8882fail_cmd:
8883 return -EINVAL;
8884}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308885EXPORT_SYMBOL(q6asm_async_write);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308886
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308887/**
8888 * q6asm_async_read -
8889 * command to read DSP buffer
8890 *
8891 * @ac: Audio client handle
8892 * @param: params for async read
8893 *
8894 * Returns 0 on success or error on failure
8895 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308896int q6asm_async_read(struct audio_client *ac,
8897 struct audio_aio_read_param *param)
8898{
8899 int rc = 0;
8900 struct asm_data_cmd_read_v2 read;
8901 struct asm_buffer_node *buf_node = NULL;
8902 struct list_head *ptr, *next;
8903 phys_addr_t lbuf_phys_addr;
8904 u32 liomode;
8905 u32 io_compressed;
8906 int dir = 0;
8907
8908 if (ac == NULL) {
8909 pr_err("%s: APR handle NULL\n", __func__);
8910 return -EINVAL;
8911 }
8912 if (ac->apr == NULL) {
8913 pr_err("%s: AC APR handle NULL\n", __func__);
8914 return -EINVAL;
8915 }
8916
8917 q6asm_add_hdr_async(ac, &read.hdr, sizeof(read), FALSE);
8918
8919 /* Pass session id as token for AIO scheme */
8920 read.hdr.token = param->uid;
8921 read.hdr.opcode = ASM_DATA_CMD_READ_V2;
8922 read.buf_addr_lsw = lower_32_bits(param->paddr);
8923 read.buf_addr_msw = msm_audio_populate_upper_32_bits(param->paddr);
8924 read.buf_size = param->len;
8925 read.seq_id = param->uid;
8926 liomode = (NT_MODE | ASYNC_IO_MODE);
8927 io_compressed = (ASYNC_IO_MODE | COMPRESSED_IO);
8928 if (ac->io_mode == liomode) {
8929 lbuf_phys_addr = (param->paddr - 32);
8930 /*legacy wma driver case*/
8931 dir = IN;
8932 } else if (ac->io_mode == io_compressed) {
8933 lbuf_phys_addr = (param->paddr - 64);
8934 dir = OUT;
8935 } else {
8936 if (param->flags & COMPRESSED_TIMESTAMP_FLAG)
8937 lbuf_phys_addr = param->paddr -
8938 sizeof(struct snd_codec_metadata);
8939 else
8940 lbuf_phys_addr = param->paddr;
8941 dir = OUT;
8942 }
8943
8944 list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
8945 buf_node = list_entry(ptr, struct asm_buffer_node,
8946 list);
8947 if (buf_node->buf_phys_addr == lbuf_phys_addr) {
8948 read.mem_map_handle = buf_node->mmap_hdl;
8949 break;
8950 }
8951 }
8952
8953 rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
8954 if (rc < 0) {
8955 pr_err("%s: read op[0x%x]rc[%d]\n", __func__,
8956 read.hdr.opcode, rc);
8957 goto fail_cmd;
8958 }
8959 return 0;
8960fail_cmd:
8961 return -EINVAL;
8962}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308963EXPORT_SYMBOL(q6asm_async_read);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308964
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05308965/**
8966 * q6asm_write -
8967 * command to write buffer data to DSP
8968 *
8969 * @ac: Audio client handle
8970 * @len: buffer size
8971 * @msw_ts: upper 32bits of timestamp
8972 * @lsw_ts: lower 32bits of timestamp
8973 * @flags: Flags for timestamp mode
8974 *
8975 * Returns 0 on success or error on failure
8976 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308977int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
8978 uint32_t lsw_ts, uint32_t flags)
8979{
8980 int rc = 0;
8981 struct asm_data_cmd_write_v2 write;
8982 struct asm_buffer_node *buf_node = NULL;
8983 struct audio_port_data *port;
8984 struct audio_buffer *ab;
8985 int dsp_buf = 0;
8986
8987 if (ac == NULL) {
8988 pr_err("%s: APR handle NULL\n", __func__);
8989 return -EINVAL;
8990 }
8991 if (ac->apr == NULL) {
8992 pr_err("%s: AC APR handle NULL\n", __func__);
8993 return -EINVAL;
8994 }
8995
8996 dev_vdbg(ac->dev, "%s: session[%d] len=%d\n",
8997 __func__, ac->session, len);
8998 if (ac->io_mode & SYNC_IO_MODE) {
8999 port = &ac->port[IN];
9000
9001 q6asm_add_hdr(ac, &write.hdr, sizeof(write),
9002 FALSE);
9003 mutex_lock(&port->lock);
9004
9005 dsp_buf = port->dsp_buf;
9006 ab = &port->buf[dsp_buf];
9007
9008 q6asm_update_token(&write.hdr.token,
9009 0, /* Session ID is NA */
9010 0, /* Stream ID is NA */
9011 port->dsp_buf,
9012 0, /* Direction flag is NA */
9013 NO_WAIT_CMD);
9014 write.hdr.opcode = ASM_DATA_CMD_WRITE_V2;
9015 write.buf_addr_lsw = lower_32_bits(ab->phys);
9016 write.buf_addr_msw = msm_audio_populate_upper_32_bits(ab->phys);
9017 write.buf_size = len;
9018 write.seq_id = port->dsp_buf;
9019 write.timestamp_lsw = lsw_ts;
9020 write.timestamp_msw = msw_ts;
9021 /* Use 0xFF00 for disabling timestamps */
9022 if (flags == 0xFF00)
9023 write.flags = (0x00000000 | (flags & 0x800000FF));
9024 else
9025 write.flags = (0x80000000 | flags);
9026 port->dsp_buf = q6asm_get_next_buf(ac, port->dsp_buf,
9027 port->max_buf_cnt);
9028 buf_node = list_first_entry(&ac->port[IN].mem_map_handle,
9029 struct asm_buffer_node,
9030 list);
9031 write.mem_map_handle = buf_node->mmap_hdl;
9032
9033 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]"
9034 , __func__,
9035 &ab->phys,
9036 write.buf_addr_lsw,
9037 write.hdr.token,
9038 write.seq_id,
9039 write.buf_size,
9040 write.mem_map_handle);
9041 mutex_unlock(&port->lock);
9042
9043 config_debug_fs_write(ab);
9044
9045 rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
9046 if (rc < 0) {
9047 pr_err("%s: write op[0x%x]rc[%d]\n",
9048 __func__, write.hdr.opcode, rc);
9049 goto fail_cmd;
9050 }
9051 return 0;
9052 }
9053fail_cmd:
9054 return -EINVAL;
9055}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309056EXPORT_SYMBOL(q6asm_write);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309057
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309058/**
9059 * q6asm_write_nolock -
9060 * command to write buffer data to DSP
9061 * with no wait for ack.
9062 *
9063 * @ac: Audio client handle
9064 * @len: buffer size
9065 * @msw_ts: upper 32bits of timestamp
9066 * @lsw_ts: lower 32bits of timestamp
9067 * @flags: Flags for timestamp mode
9068 *
9069 * Returns 0 on success or error on failure
9070 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309071int q6asm_write_nolock(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
9072 uint32_t lsw_ts, uint32_t flags)
9073{
9074 int rc = 0;
9075 struct asm_data_cmd_write_v2 write;
9076 struct asm_buffer_node *buf_node = NULL;
9077 struct audio_port_data *port;
9078 struct audio_buffer *ab;
9079 int dsp_buf = 0;
9080
9081 if (ac == NULL) {
9082 pr_err("%s: APR handle NULL\n", __func__);
9083 return -EINVAL;
9084 }
9085 if (ac->apr == NULL) {
9086 pr_err("%s: AC APR handle NULL\n", __func__);
9087 return -EINVAL;
9088 }
9089
9090 dev_vdbg(ac->dev, "%s: session[%d] len=%d\n",
9091 __func__, ac->session, len);
9092 if (ac->io_mode & SYNC_IO_MODE) {
9093 port = &ac->port[IN];
9094
9095 q6asm_add_hdr_async(ac, &write.hdr, sizeof(write),
9096 FALSE);
9097
9098 dsp_buf = port->dsp_buf;
9099 ab = &port->buf[dsp_buf];
9100
9101 q6asm_update_token(&write.hdr.token,
9102 0, /* Session ID is NA */
9103 0, /* Stream ID is NA */
9104 port->dsp_buf,
9105 0, /* Direction flag is NA */
9106 NO_WAIT_CMD);
9107
9108 write.hdr.opcode = ASM_DATA_CMD_WRITE_V2;
9109 write.buf_addr_lsw = lower_32_bits(ab->phys);
9110 write.buf_addr_msw = msm_audio_populate_upper_32_bits(ab->phys);
9111 write.buf_size = len;
9112 write.seq_id = port->dsp_buf;
9113 write.timestamp_lsw = lsw_ts;
9114 write.timestamp_msw = msw_ts;
9115 buf_node = list_first_entry(&ac->port[IN].mem_map_handle,
9116 struct asm_buffer_node,
9117 list);
9118 write.mem_map_handle = buf_node->mmap_hdl;
9119 /* Use 0xFF00 for disabling timestamps */
9120 if (flags == 0xFF00)
9121 write.flags = (0x00000000 | (flags & 0x800000FF));
9122 else
9123 write.flags = (0x80000000 | flags);
9124 port->dsp_buf = q6asm_get_next_buf(ac, port->dsp_buf,
9125 port->max_buf_cnt);
9126
9127 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]"
9128 , __func__,
9129 &ab->phys,
9130 write.buf_addr_lsw,
9131 write.hdr.token,
9132 write.seq_id,
9133 write.buf_size,
9134 write.mem_map_handle);
9135
9136 rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
9137 if (rc < 0) {
9138 pr_err("%s: write op[0x%x]rc[%d]\n",
9139 __func__, write.hdr.opcode, rc);
9140 goto fail_cmd;
9141 }
9142 return 0;
9143 }
9144fail_cmd:
9145 return -EINVAL;
9146}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309147EXPORT_SYMBOL(q6asm_write_nolock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309148
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309149/**
9150 * q6asm_get_session_time -
9151 * command to retrieve timestamp info
9152 *
9153 * @ac: Audio client handle
9154 * @tstamp: pointer to fill with timestamp info
9155 *
9156 * Returns 0 on success or error on failure
9157 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309158int q6asm_get_session_time(struct audio_client *ac, uint64_t *tstamp)
9159{
9160 struct asm_mtmx_strtr_get_params mtmx_params;
9161 int rc;
9162
9163 if (ac == NULL) {
9164 pr_err("%s: APR handle NULL\n", __func__);
9165 return -EINVAL;
9166 }
9167 if (ac->apr == NULL) {
9168 pr_err("%s: AC APR handle NULL\n", __func__);
9169 return -EINVAL;
9170 }
9171 if (tstamp == NULL) {
9172 pr_err("%s: tstamp NULL\n", __func__);
9173 return -EINVAL;
9174 }
9175
9176 q6asm_add_hdr(ac, &mtmx_params.hdr, sizeof(mtmx_params), TRUE);
9177 mtmx_params.hdr.opcode = ASM_SESSION_CMD_GET_MTMX_STRTR_PARAMS_V2;
9178 mtmx_params.param_info.data_payload_addr_lsw = 0;
9179 mtmx_params.param_info.data_payload_addr_msw = 0;
9180 mtmx_params.param_info.mem_map_handle = 0;
9181 mtmx_params.param_info.direction = (ac->io_mode & TUN_READ_IO_MODE
9182 ? 1 : 0);
9183 mtmx_params.param_info.module_id =
9184 ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
9185 mtmx_params.param_info.param_id =
9186 ASM_SESSION_MTMX_STRTR_PARAM_SESSION_TIME_V3;
9187 mtmx_params.param_info.param_max_size =
9188 sizeof(struct asm_stream_param_data_v2) +
9189 sizeof(struct asm_session_mtmx_strtr_param_session_time_v3_t);
9190 atomic_set(&ac->time_flag, 1);
9191
9192 dev_vdbg(ac->dev, "%s: session[%d]opcode[0x%x]\n", __func__,
9193 ac->session, mtmx_params.hdr.opcode);
9194 rc = apr_send_pkt(ac->apr, (uint32_t *) &mtmx_params);
9195 if (rc < 0) {
9196 pr_err("%s: Commmand 0x%x failed %d\n", __func__,
9197 mtmx_params.hdr.opcode, rc);
9198 goto fail_cmd;
9199 }
9200 rc = wait_event_timeout(ac->time_wait,
9201 (atomic_read(&ac->time_flag) == 0), 5*HZ);
9202 if (!rc) {
9203 pr_err("%s: timeout in getting session time from DSP\n",
9204 __func__);
9205 goto fail_cmd;
9206 }
9207
9208 *tstamp = ac->time_stamp;
9209 return 0;
9210
9211fail_cmd:
9212 return -EINVAL;
9213}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309214EXPORT_SYMBOL(q6asm_get_session_time);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309215
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309216/**
9217 * q6asm_get_session_time_legacy -
9218 * command to retrieve timestamp info
9219 *
9220 * @ac: Audio client handle
9221 * @tstamp: pointer to fill with timestamp info
9222 *
9223 * Returns 0 on success or error on failure
9224 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309225int q6asm_get_session_time_legacy(struct audio_client *ac, uint64_t *tstamp)
9226{
9227 struct apr_hdr hdr;
9228 int rc;
9229
9230 if (ac == NULL) {
9231 pr_err("%s: APR handle NULL\n", __func__);
9232 return -EINVAL;
9233 }
9234 if (ac->apr == NULL) {
9235 pr_err("%s: AC APR handle NULL\n", __func__);
9236 return -EINVAL;
9237 }
9238 if (tstamp == NULL) {
9239 pr_err("%s: tstamp NULL\n", __func__);
9240 return -EINVAL;
9241 }
9242
9243 q6asm_add_hdr(ac, &hdr, sizeof(hdr), TRUE);
9244 hdr.opcode = ASM_SESSION_CMD_GET_SESSIONTIME_V3;
9245 atomic_set(&ac->time_flag, 1);
9246
9247 dev_vdbg(ac->dev, "%s: session[%d]opcode[0x%x]\n", __func__,
9248 ac->session,
9249 hdr.opcode);
9250 rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
9251 if (rc < 0) {
9252 pr_err("%s: Commmand 0x%x failed %d\n",
9253 __func__, hdr.opcode, rc);
9254 goto fail_cmd;
9255 }
9256 rc = wait_event_timeout(ac->time_wait,
9257 (atomic_read(&ac->time_flag) == 0), 5*HZ);
9258 if (!rc) {
9259 pr_err("%s: timeout in getting session time from DSP\n",
9260 __func__);
9261 goto fail_cmd;
9262 }
9263
9264 *tstamp = ac->time_stamp;
9265 return 0;
9266
9267fail_cmd:
9268 return -EINVAL;
9269}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309270EXPORT_SYMBOL(q6asm_get_session_time_legacy);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309271
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309272/**
9273 * q6asm_send_audio_effects_params -
9274 * command to send audio effects params
9275 *
9276 * @ac: Audio client handle
9277 * @params: audio effects params
9278 * @params_length: size of params
9279 *
9280 * Returns 0 on success or error on failure
9281 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309282int q6asm_send_audio_effects_params(struct audio_client *ac, char *params,
9283 uint32_t params_length)
9284{
9285 char *asm_params = NULL;
9286 struct apr_hdr hdr;
9287 struct asm_stream_cmd_set_pp_params_v2 payload_params;
Xiaojun Sanga4648082018-04-27 14:57:33 +08009288 int sz, rc, session_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309289
9290 pr_debug("%s:\n", __func__);
9291 if (!ac) {
9292 pr_err("%s: APR handle NULL\n", __func__);
9293 return -EINVAL;
9294 }
Xiaojun Sanga4648082018-04-27 14:57:33 +08009295
9296 session_id = q6asm_get_session_id_from_audio_client(ac);
9297 if (!session_id)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309298 return -EINVAL;
Xiaojun Sanga4648082018-04-27 14:57:33 +08009299
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309300 if (params == NULL) {
9301 pr_err("%s: params NULL\n", __func__);
9302 return -EINVAL;
9303 }
9304 sz = sizeof(struct apr_hdr) +
9305 sizeof(struct asm_stream_cmd_set_pp_params_v2) +
9306 params_length;
9307 asm_params = kzalloc(sz, GFP_KERNEL);
9308 if (!asm_params) {
9309 pr_err("%s, asm params memory alloc failed", __func__);
9310 return -ENOMEM;
9311 }
Xiaojun Sanga4648082018-04-27 14:57:33 +08009312 mutex_lock(&session[session_id].mutex_lock_per_session);
9313 if (!q6asm_is_valid_audio_client(ac)) {
9314 rc = -EINVAL;
9315 goto fail_send_param;
9316 }
9317
9318 if (ac->apr == NULL) {
9319 pr_err("%s: AC APR handle NULL\n", __func__);
9320 rc = -EINVAL;
9321 goto fail_send_param;
9322 }
9323
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309324 q6asm_add_hdr_async(ac, &hdr, (sizeof(struct apr_hdr) +
9325 sizeof(struct asm_stream_cmd_set_pp_params_v2) +
9326 params_length), TRUE);
9327 atomic_set(&ac->cmd_state_pp, -1);
9328 hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
9329 payload_params.data_payload_addr_lsw = 0;
9330 payload_params.data_payload_addr_msw = 0;
9331 payload_params.mem_map_handle = 0;
9332 payload_params.data_payload_size = params_length;
9333 memcpy(((u8 *)asm_params), &hdr, sizeof(struct apr_hdr));
9334 memcpy(((u8 *)asm_params + sizeof(struct apr_hdr)), &payload_params,
9335 sizeof(struct asm_stream_cmd_set_pp_params_v2));
9336 memcpy(((u8 *)asm_params + sizeof(struct apr_hdr) +
9337 sizeof(struct asm_stream_cmd_set_pp_params_v2)),
9338 params, params_length);
9339 rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params);
9340 if (rc < 0) {
9341 pr_err("%s: audio effects set-params send failed\n", __func__);
9342 rc = -EINVAL;
9343 goto fail_send_param;
9344 }
9345 rc = wait_event_timeout(ac->cmd_wait,
9346 (atomic_read(&ac->cmd_state_pp) >= 0), 1*HZ);
9347 if (!rc) {
9348 pr_err("%s: timeout, audio effects set-params\n", __func__);
9349 rc = -ETIMEDOUT;
9350 goto fail_send_param;
9351 }
9352 if (atomic_read(&ac->cmd_state_pp) > 0) {
9353 pr_err("%s: DSP returned error[%s] set-params\n",
9354 __func__, adsp_err_get_err_str(
9355 atomic_read(&ac->cmd_state_pp)));
9356 rc = adsp_err_get_lnx_err_code(
9357 atomic_read(&ac->cmd_state_pp));
9358 goto fail_send_param;
9359 }
9360
9361 rc = 0;
9362fail_send_param:
Xiaojun Sanga4648082018-04-27 14:57:33 +08009363 mutex_unlock(&session[session_id].mutex_lock_per_session);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309364 kfree(asm_params);
9365 return rc;
9366}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309367EXPORT_SYMBOL(q6asm_send_audio_effects_params);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309368
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309369/**
9370 * q6asm_send_mtmx_strtr_window -
9371 * command to send matrix for window params
9372 *
9373 * @ac: Audio client handle
9374 * @window_param: window params
9375 * @param_id: param id for window
9376 *
9377 * Returns 0 on success or error on failure
9378 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309379int q6asm_send_mtmx_strtr_window(struct audio_client *ac,
9380 struct asm_session_mtmx_strtr_param_window_v2_t *window_param,
9381 uint32_t param_id)
9382{
9383 struct asm_mtmx_strtr_params matrix;
9384 int sz = 0;
9385 int rc = 0;
9386
9387 pr_debug("%s: Window lsw is %d, window msw is %d\n", __func__,
9388 window_param->window_lsw, window_param->window_msw);
9389
9390 if (!ac) {
9391 pr_err("%s: audio client handle is NULL\n", __func__);
9392 rc = -EINVAL;
9393 goto fail_cmd;
9394 }
9395
9396 if (ac->apr == NULL) {
9397 pr_err("%s: ac->apr is NULL", __func__);
9398 rc = -EINVAL;
9399 goto fail_cmd;
9400 }
9401
9402 sz = sizeof(struct asm_mtmx_strtr_params);
9403 q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE);
9404 atomic_set(&ac->cmd_state, -1);
9405 matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2;
9406
9407 matrix.param.data_payload_addr_lsw = 0;
9408 matrix.param.data_payload_addr_msw = 0;
9409 matrix.param.mem_map_handle = 0;
9410 matrix.param.data_payload_size =
9411 sizeof(struct asm_stream_param_data_v2) +
9412 sizeof(struct asm_session_mtmx_strtr_param_window_v2_t);
9413 matrix.param.direction = 0; /* RX */
9414 matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
9415 matrix.data.param_id = param_id;
9416 matrix.data.param_size =
9417 sizeof(struct asm_session_mtmx_strtr_param_window_v2_t);
9418 matrix.data.reserved = 0;
9419 memcpy(&(matrix.config.window_param),
9420 window_param,
9421 sizeof(struct asm_session_mtmx_strtr_param_window_v2_t));
9422
9423 rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix);
9424 if (rc < 0) {
9425 pr_err("%s: Render window start send failed paramid [0x%x]\n",
9426 __func__, matrix.data.param_id);
9427 rc = -EINVAL;
9428 goto fail_cmd;
9429 }
9430
9431 rc = wait_event_timeout(ac->cmd_wait,
9432 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
9433 if (!rc) {
9434 pr_err("%s: timeout, Render window start paramid[0x%x]\n",
9435 __func__, matrix.data.param_id);
9436 rc = -ETIMEDOUT;
9437 goto fail_cmd;
9438 }
9439
9440 if (atomic_read(&ac->cmd_state) > 0) {
9441 pr_err("%s: DSP returned error[%s]\n",
9442 __func__, adsp_err_get_err_str(
9443 atomic_read(&ac->cmd_state)));
9444 rc = adsp_err_get_lnx_err_code(
9445 atomic_read(&ac->cmd_state));
9446 goto fail_cmd;
9447 }
9448 rc = 0;
9449fail_cmd:
9450 return rc;
9451}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309452EXPORT_SYMBOL(q6asm_send_mtmx_strtr_window);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309453
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309454/**
9455 * q6asm_send_mtmx_strtr_render_mode -
9456 * command to send matrix for render mode
9457 *
9458 * @ac: Audio client handle
9459 * @render_mode: rendering mode
9460 *
9461 * Returns 0 on success or error on failure
9462 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309463int q6asm_send_mtmx_strtr_render_mode(struct audio_client *ac,
9464 uint32_t render_mode)
9465{
9466 struct asm_mtmx_strtr_params matrix;
9467 struct asm_session_mtmx_strtr_param_render_mode_t render_param;
9468 int sz = 0;
9469 int rc = 0;
9470
9471 pr_debug("%s: render mode is %d\n", __func__, render_mode);
9472
9473 if (!ac) {
9474 pr_err("%s: audio client handle is NULL\n", __func__);
9475 rc = -EINVAL;
9476 goto exit;
9477 }
9478
9479 if (ac->apr == NULL) {
9480 pr_err("%s: ac->apr is NULL\n", __func__);
9481 rc = -EINVAL;
9482 goto exit;
9483 }
9484
9485 if ((render_mode != ASM_SESSION_MTMX_STRTR_PARAM_RENDER_DEFAULT) &&
9486 (render_mode != ASM_SESSION_MTMX_STRTR_PARAM_RENDER_LOCAL_STC)) {
9487 pr_err("%s: Invalid render mode %d\n", __func__, render_mode);
9488 rc = -EINVAL;
9489 goto exit;
9490 }
9491
9492 memset(&render_param, 0,
9493 sizeof(struct asm_session_mtmx_strtr_param_render_mode_t));
9494 render_param.flags = render_mode;
9495
9496 memset(&matrix, 0, sizeof(struct asm_mtmx_strtr_params));
9497 sz = sizeof(struct asm_mtmx_strtr_params);
9498 q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE);
9499 atomic_set(&ac->cmd_state, -1);
9500 matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2;
9501
9502 matrix.param.data_payload_addr_lsw = 0;
9503 matrix.param.data_payload_addr_msw = 0;
9504 matrix.param.mem_map_handle = 0;
9505 matrix.param.data_payload_size =
9506 sizeof(struct asm_stream_param_data_v2) +
9507 sizeof(struct asm_session_mtmx_strtr_param_render_mode_t);
9508 matrix.param.direction = 0; /* RX */
9509 matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
9510 matrix.data.param_id = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_MODE_CMD;
9511 matrix.data.param_size =
9512 sizeof(struct asm_session_mtmx_strtr_param_render_mode_t);
9513 matrix.data.reserved = 0;
9514 memcpy(&(matrix.config.render_param),
9515 &render_param,
9516 sizeof(struct asm_session_mtmx_strtr_param_render_mode_t));
9517
9518 rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix);
9519 if (rc < 0) {
9520 pr_err("%s: Render mode send failed paramid [0x%x]\n",
9521 __func__, matrix.data.param_id);
9522 rc = -EINVAL;
9523 goto exit;
9524 }
9525
9526 rc = wait_event_timeout(ac->cmd_wait,
9527 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
9528 if (!rc) {
9529 pr_err("%s: timeout, Render mode send paramid [0x%x]\n",
9530 __func__, matrix.data.param_id);
9531 rc = -ETIMEDOUT;
9532 goto exit;
9533 }
9534
9535 if (atomic_read(&ac->cmd_state) > 0) {
9536 pr_err("%s: DSP returned error[%s]\n",
9537 __func__, adsp_err_get_err_str(
9538 atomic_read(&ac->cmd_state)));
9539 rc = adsp_err_get_lnx_err_code(
9540 atomic_read(&ac->cmd_state));
9541 goto exit;
9542 }
9543 rc = 0;
9544exit:
9545 return rc;
9546}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309547EXPORT_SYMBOL(q6asm_send_mtmx_strtr_render_mode);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309548
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309549/**
9550 * q6asm_send_mtmx_strtr_clk_rec_mode -
9551 * command to send matrix for clock rec
9552 *
9553 * @ac: Audio client handle
9554 * @clk_rec_mode: mode for clock rec
9555 *
9556 * Returns 0 on success or error on failure
9557 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309558int q6asm_send_mtmx_strtr_clk_rec_mode(struct audio_client *ac,
9559 uint32_t clk_rec_mode)
9560{
9561 struct asm_mtmx_strtr_params matrix;
9562 struct asm_session_mtmx_strtr_param_clk_rec_t clk_rec_param;
9563 int sz = 0;
9564 int rc = 0;
9565
9566 pr_debug("%s: clk rec mode is %d\n", __func__, clk_rec_mode);
9567
9568 if (!ac) {
9569 pr_err("%s: audio client handle is NULL\n", __func__);
9570 rc = -EINVAL;
9571 goto exit;
9572 }
9573
9574 if (ac->apr == NULL) {
9575 pr_err("%s: ac->apr is NULL\n", __func__);
9576 rc = -EINVAL;
9577 goto exit;
9578 }
9579
9580 if ((clk_rec_mode != ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_NONE) &&
9581 (clk_rec_mode != ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_AUTO)) {
9582 pr_err("%s: Invalid clk rec mode %d\n", __func__, clk_rec_mode);
9583 rc = -EINVAL;
9584 goto exit;
9585 }
9586
9587 memset(&clk_rec_param, 0,
9588 sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t));
9589 clk_rec_param.flags = clk_rec_mode;
9590
9591 memset(&matrix, 0, sizeof(struct asm_mtmx_strtr_params));
9592 sz = sizeof(struct asm_mtmx_strtr_params);
9593 q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE);
9594 atomic_set(&ac->cmd_state, -1);
9595 matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2;
9596
9597 matrix.param.data_payload_addr_lsw = 0;
9598 matrix.param.data_payload_addr_msw = 0;
9599 matrix.param.mem_map_handle = 0;
9600 matrix.param.data_payload_size =
9601 sizeof(struct asm_stream_param_data_v2) +
9602 sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t);
9603 matrix.param.direction = 0; /* RX */
9604 matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
9605 matrix.data.param_id = ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_CMD;
9606 matrix.data.param_size =
9607 sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t);
9608 matrix.data.reserved = 0;
9609 memcpy(&(matrix.config.clk_rec_param),
9610 &clk_rec_param,
9611 sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t));
9612
9613 rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix);
9614 if (rc < 0) {
9615 pr_err("%s: clk rec mode send failed paramid [0x%x]\n",
9616 __func__, matrix.data.param_id);
9617 rc = -EINVAL;
9618 goto exit;
9619 }
9620
9621 rc = wait_event_timeout(ac->cmd_wait,
9622 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
9623 if (!rc) {
9624 pr_err("%s: timeout, clk rec mode send paramid [0x%x]\n",
9625 __func__, matrix.data.param_id);
9626 rc = -ETIMEDOUT;
9627 goto exit;
9628 }
9629
9630 if (atomic_read(&ac->cmd_state) > 0) {
9631 pr_err("%s: DSP returned error[%s]\n",
9632 __func__, adsp_err_get_err_str(
9633 atomic_read(&ac->cmd_state)));
9634 rc = adsp_err_get_lnx_err_code(
9635 atomic_read(&ac->cmd_state));
9636 goto exit;
9637 }
9638 rc = 0;
9639exit:
9640 return rc;
9641}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309642EXPORT_SYMBOL(q6asm_send_mtmx_strtr_clk_rec_mode);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309643
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309644/**
9645 * q6asm_send_mtmx_strtr_enable_adjust_session_clock -
9646 * command to send matrix for adjust time
9647 *
9648 * @ac: Audio client handle
9649 * @enable: flag to adjust time or not
9650 *
9651 * Returns 0 on success or error on failure
9652 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309653int q6asm_send_mtmx_strtr_enable_adjust_session_clock(struct audio_client *ac,
9654 bool enable)
9655{
9656 struct asm_mtmx_strtr_params matrix;
9657 struct asm_session_mtmx_param_adjust_session_time_ctl_t adjust_time;
9658 int sz = 0;
9659 int rc = 0;
9660
9661 pr_debug("%s: adjust session enable %d\n", __func__, enable);
9662
9663 if (!ac) {
9664 pr_err("%s: audio client handle is NULL\n", __func__);
9665 rc = -EINVAL;
9666 goto exit;
9667 }
9668
9669 if (ac->apr == NULL) {
9670 pr_err("%s: ac->apr is NULL\n", __func__);
9671 rc = -EINVAL;
9672 goto exit;
9673 }
9674
9675 adjust_time.enable = enable;
9676 memset(&matrix, 0, sizeof(struct asm_mtmx_strtr_params));
9677 sz = sizeof(struct asm_mtmx_strtr_params);
9678 q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE);
9679 atomic_set(&ac->cmd_state, -1);
9680 matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2;
9681
9682 matrix.param.data_payload_addr_lsw = 0;
9683 matrix.param.data_payload_addr_msw = 0;
9684 matrix.param.mem_map_handle = 0;
9685 matrix.param.data_payload_size =
9686 sizeof(struct asm_stream_param_data_v2) +
9687 sizeof(struct asm_session_mtmx_param_adjust_session_time_ctl_t);
9688 matrix.param.direction = 0; /* RX */
9689 matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
9690 matrix.data.param_id = ASM_SESSION_MTMX_PARAM_ADJUST_SESSION_TIME_CTL;
9691 matrix.data.param_size =
9692 sizeof(struct asm_session_mtmx_param_adjust_session_time_ctl_t);
9693 matrix.data.reserved = 0;
9694 matrix.config.adj_time_param.enable = adjust_time.enable;
9695
9696 rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix);
9697 if (rc < 0) {
9698 pr_err("%s: enable adjust session failed failed paramid [0x%x]\n",
9699 __func__, matrix.data.param_id);
9700 rc = -EINVAL;
9701 goto exit;
9702 }
9703
9704 rc = wait_event_timeout(ac->cmd_wait,
9705 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
9706 if (!rc) {
9707 pr_err("%s: enable adjust session failed failed paramid [0x%x]\n",
9708 __func__, matrix.data.param_id);
9709 rc = -ETIMEDOUT;
9710 goto exit;
9711 }
9712
9713 if (atomic_read(&ac->cmd_state) > 0) {
9714 pr_err("%s: DSP returned error[%s]\n",
9715 __func__, adsp_err_get_err_str(
9716 atomic_read(&ac->cmd_state)));
9717 rc = adsp_err_get_lnx_err_code(
9718 atomic_read(&ac->cmd_state));
9719 goto exit;
9720 }
9721 rc = 0;
9722exit:
9723 return rc;
9724}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309725EXPORT_SYMBOL(q6asm_send_mtmx_strtr_enable_adjust_session_clock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309726
9727
9728static int __q6asm_cmd(struct audio_client *ac, int cmd, uint32_t stream_id)
9729{
9730 struct apr_hdr hdr;
9731 int rc;
9732 atomic_t *state;
9733 int cnt = 0;
9734
9735 if (!ac) {
Xiaojun Sangc3277492018-09-06 14:34:03 +08009736 pr_err_ratelimited("%s: APR handle NULL\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309737 return -EINVAL;
9738 }
9739 if (ac->apr == NULL) {
Xiaojun Sangc3277492018-09-06 14:34:03 +08009740 pr_err_ratelimited("%s: AC APR handle NULL\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309741 return -EINVAL;
9742 }
9743 q6asm_stream_add_hdr(ac, &hdr, sizeof(hdr), TRUE, stream_id);
9744 atomic_set(&ac->cmd_state, -1);
9745 /*
9746 * Updated the token field with stream/session for compressed playback
9747 * Platform driver must know the the stream with which the command is
9748 * associated
9749 */
9750 if (ac->io_mode & COMPRESSED_STREAM_IO)
9751 q6asm_update_token(&hdr.token,
9752 ac->session,
9753 stream_id,
9754 0, /* Buffer index is NA */
9755 0, /* Direction flag is NA */
9756 WAIT_CMD);
9757 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
9758 __func__, hdr.token, stream_id, ac->session);
9759 switch (cmd) {
9760 case CMD_PAUSE:
9761 pr_debug("%s: CMD_PAUSE\n", __func__);
9762 hdr.opcode = ASM_SESSION_CMD_PAUSE;
9763 state = &ac->cmd_state;
9764 break;
9765 case CMD_SUSPEND:
9766 pr_debug("%s: CMD_SUSPEND\n", __func__);
9767 hdr.opcode = ASM_SESSION_CMD_SUSPEND;
9768 state = &ac->cmd_state;
9769 break;
9770 case CMD_FLUSH:
9771 pr_debug("%s: CMD_FLUSH\n", __func__);
9772 hdr.opcode = ASM_STREAM_CMD_FLUSH;
9773 state = &ac->cmd_state;
9774 break;
9775 case CMD_OUT_FLUSH:
9776 pr_debug("%s: CMD_OUT_FLUSH\n", __func__);
9777 hdr.opcode = ASM_STREAM_CMD_FLUSH_READBUFS;
9778 state = &ac->cmd_state;
9779 break;
9780 case CMD_EOS:
9781 pr_debug("%s: CMD_EOS\n", __func__);
9782 hdr.opcode = ASM_DATA_CMD_EOS;
9783 atomic_set(&ac->cmd_state, 0);
9784 state = &ac->cmd_state;
9785 break;
9786 case CMD_CLOSE:
9787 pr_debug("%s: CMD_CLOSE\n", __func__);
9788 hdr.opcode = ASM_STREAM_CMD_CLOSE;
9789 state = &ac->cmd_state;
9790 break;
9791 default:
9792 pr_err("%s: Invalid format[%d]\n", __func__, cmd);
9793 rc = -EINVAL;
9794 goto fail_cmd;
9795 }
9796 pr_debug("%s: session[%d]opcode[0x%x]\n", __func__,
9797 ac->session,
9798 hdr.opcode);
9799 rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
9800 if (rc < 0) {
9801 pr_err("%s: Commmand 0x%x failed %d\n",
9802 __func__, hdr.opcode, rc);
9803 rc = -EINVAL;
9804 goto fail_cmd;
9805 }
9806 rc = wait_event_timeout(ac->cmd_wait, (atomic_read(state) >= 0), 5*HZ);
9807 if (!rc) {
9808 pr_err("%s: timeout. waited for response opcode[0x%x]\n",
9809 __func__, hdr.opcode);
9810 rc = -ETIMEDOUT;
9811 goto fail_cmd;
9812 }
9813 if (atomic_read(state) > 0) {
9814 pr_err("%s: DSP returned error[%s] opcode %d\n",
9815 __func__, adsp_err_get_err_str(
9816 atomic_read(state)),
9817 hdr.opcode);
9818 rc = adsp_err_get_lnx_err_code(atomic_read(state));
9819 goto fail_cmd;
9820 }
9821
9822 if (cmd == CMD_FLUSH)
9823 q6asm_reset_buf_state(ac);
9824 if (cmd == CMD_CLOSE) {
9825 /* check if DSP return all buffers */
9826 if (ac->port[IN].buf) {
9827 for (cnt = 0; cnt < ac->port[IN].max_buf_cnt;
9828 cnt++) {
9829 if (ac->port[IN].buf[cnt].used == IN) {
9830 dev_vdbg(ac->dev, "Write Buf[%d] not returned\n",
9831 cnt);
9832 }
9833 }
9834 }
9835 if (ac->port[OUT].buf) {
9836 for (cnt = 0; cnt < ac->port[OUT].max_buf_cnt; cnt++) {
9837 if (ac->port[OUT].buf[cnt].used == OUT) {
9838 dev_vdbg(ac->dev, "Read Buf[%d] not returned\n",
9839 cnt);
9840 }
9841 }
9842 }
9843 }
9844 return 0;
9845fail_cmd:
9846 return rc;
9847}
9848
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309849/**
9850 * q6asm_cmd -
9851 * Function used to send commands for
9852 * ASM with wait for ack.
9853 *
9854 * @ac: Audio client handle
9855 * @cmd: command to send
9856 *
9857 * Returns 0 on success or error on failure
9858 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309859int q6asm_cmd(struct audio_client *ac, int cmd)
9860{
9861 return __q6asm_cmd(ac, cmd, ac->stream_id);
9862}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309863EXPORT_SYMBOL(q6asm_cmd);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309864
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309865/**
9866 * q6asm_stream_cmd -
9867 * Function used to send commands for
9868 * ASM stream with wait for ack.
9869 *
9870 * @ac: Audio client handle
9871 * @cmd: command to send
9872 * @stream_id: Stream ID
9873 *
9874 * Returns 0 on success or error on failure
9875 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309876int q6asm_stream_cmd(struct audio_client *ac, int cmd, uint32_t stream_id)
9877{
9878 return __q6asm_cmd(ac, cmd, stream_id);
9879}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309880EXPORT_SYMBOL(q6asm_stream_cmd);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309881
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309882/**
9883 * q6asm_cmd_nowait -
9884 * Function used to send commands for
9885 * ASM stream without wait for ack.
9886 *
9887 * @ac: Audio client handle
9888 * @cmd: command to send
9889 * @stream_id: Stream ID
9890 *
9891 * Returns 0 on success or error on failure
9892 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309893static int __q6asm_cmd_nowait(struct audio_client *ac, int cmd,
9894 uint32_t stream_id)
9895{
9896 struct apr_hdr hdr;
9897 int rc;
9898
9899 if (!ac) {
Xiaojun Sangc3277492018-09-06 14:34:03 +08009900 pr_err_ratelimited("%s: APR handle NULL\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309901 return -EINVAL;
9902 }
9903 if (ac->apr == NULL) {
Xiaojun Sangc3277492018-09-06 14:34:03 +08009904 pr_err_ratelimited("%s: AC APR handle NULL\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309905 return -EINVAL;
9906 }
9907 q6asm_stream_add_hdr_async(ac, &hdr, sizeof(hdr), TRUE, stream_id);
9908 atomic_set(&ac->cmd_state, 1);
9909 /*
9910 * Updated the token field with stream/session for compressed playback
9911 * Platform driver must know the the stream with which the command is
9912 * associated
9913 */
9914 if (ac->io_mode & COMPRESSED_STREAM_IO)
9915 q6asm_update_token(&hdr.token,
9916 ac->session,
9917 stream_id,
9918 0, /* Buffer index is NA */
9919 0, /* Direction flag is NA */
9920 NO_WAIT_CMD);
9921
9922 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
9923 __func__, hdr.token, stream_id, ac->session);
9924 switch (cmd) {
9925 case CMD_PAUSE:
9926 pr_debug("%s: CMD_PAUSE\n", __func__);
9927 hdr.opcode = ASM_SESSION_CMD_PAUSE;
9928 break;
Sidipotu Ashok5c6855b2019-01-08 15:58:37 +05309929
9930 case CMD_FLUSH:
9931 pr_debug("%s: CMD_FLUSH\n", __func__);
9932 hdr.opcode = ASM_STREAM_CMD_FLUSH;
9933 break;
9934
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309935 case CMD_EOS:
9936 pr_debug("%s: CMD_EOS\n", __func__);
9937 hdr.opcode = ASM_DATA_CMD_EOS;
9938 break;
9939 case CMD_CLOSE:
9940 pr_debug("%s: CMD_CLOSE\n", __func__);
9941 hdr.opcode = ASM_STREAM_CMD_CLOSE;
9942 break;
9943 default:
9944 pr_err("%s: Invalid format[%d]\n", __func__, cmd);
9945 goto fail_cmd;
9946 }
9947 pr_debug("%s: session[%d]opcode[0x%x]\n", __func__,
9948 ac->session,
9949 hdr.opcode);
9950
9951 rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
9952 if (rc < 0) {
9953 pr_err("%s: Commmand 0x%x failed %d\n",
9954 __func__, hdr.opcode, rc);
9955 goto fail_cmd;
9956 }
9957 return 0;
9958fail_cmd:
9959 return -EINVAL;
9960}
9961
9962int q6asm_cmd_nowait(struct audio_client *ac, int cmd)
9963{
9964 pr_debug("%s: stream_id: %d\n", __func__, ac->stream_id);
9965 return __q6asm_cmd_nowait(ac, cmd, ac->stream_id);
9966}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309967EXPORT_SYMBOL(q6asm_cmd_nowait);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309968
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309969/**
9970 * q6asm_stream_cmd_nowait -
9971 * Function used to send commands for
9972 * ASM stream without wait for ack.
9973 *
9974 * @ac: Audio client handle
9975 * @cmd: command to send
9976 * @stream_id: Stream ID
9977 *
9978 * Returns 0 on success or error on failure
9979 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309980int q6asm_stream_cmd_nowait(struct audio_client *ac, int cmd,
9981 uint32_t stream_id)
9982{
9983 pr_debug("%s: stream_id: %d\n", __func__, stream_id);
9984 return __q6asm_cmd_nowait(ac, cmd, stream_id);
9985}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05309986EXPORT_SYMBOL(q6asm_stream_cmd_nowait);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309987
9988int __q6asm_send_meta_data(struct audio_client *ac, uint32_t stream_id,
9989 uint32_t initial_samples, uint32_t trailing_samples)
9990{
9991 struct asm_data_cmd_remove_silence silence;
9992 int rc = 0;
9993
9994 if (!ac) {
Xiaojun Sangc3277492018-09-06 14:34:03 +08009995 pr_err_ratelimited("%s: APR handle NULL\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05309996 return -EINVAL;
9997 }
9998 if (ac->apr == NULL) {
Xiaojun Sangc3277492018-09-06 14:34:03 +08009999 pr_err_ratelimited("%s: AC APR handle NULL\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010000 return -EINVAL;
10001 }
10002 pr_debug("%s: session[%d]\n", __func__, ac->session);
10003 q6asm_stream_add_hdr_async(ac, &silence.hdr, sizeof(silence), TRUE,
10004 stream_id);
10005
10006 /*
10007 * Updated the token field with stream/session for compressed playback
10008 * Platform driver must know the the stream with which the command is
10009 * associated
10010 */
10011 if (ac->io_mode & COMPRESSED_STREAM_IO)
10012 q6asm_update_token(&silence.hdr.token,
10013 ac->session,
10014 stream_id,
10015 0, /* Buffer index is NA */
10016 0, /* Direction flag is NA */
10017 NO_WAIT_CMD);
10018 pr_debug("%s: token = 0x%x, stream_id %d, session 0x%x\n",
10019 __func__, silence.hdr.token, stream_id, ac->session);
10020
10021 silence.hdr.opcode = ASM_DATA_CMD_REMOVE_INITIAL_SILENCE;
10022 silence.num_samples_to_remove = initial_samples;
10023
10024 rc = apr_send_pkt(ac->apr, (uint32_t *) &silence);
10025 if (rc < 0) {
10026 pr_err("%s: Commmand silence failed[%d]", __func__, rc);
10027
10028 goto fail_cmd;
10029 }
10030
10031 silence.hdr.opcode = ASM_DATA_CMD_REMOVE_TRAILING_SILENCE;
10032 silence.num_samples_to_remove = trailing_samples;
10033
10034
10035 rc = apr_send_pkt(ac->apr, (uint32_t *) &silence);
10036 if (rc < 0) {
10037 pr_err("%s: Commmand silence failed[%d]", __func__, rc);
10038 goto fail_cmd;
10039 }
10040
10041 return 0;
10042fail_cmd:
10043 return -EINVAL;
10044}
10045
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010046/**
10047 * q6asm_stream_send_meta_data -
10048 * command to send meta data for stream
10049 *
10050 * @ac: Audio client handle
10051 * @stream_id: Stream ID
10052 * @initial_samples: Initial samples of stream
10053 * @trailing_samples: Trailing samples of stream
10054 *
10055 * Returns 0 on success or error on failure
10056 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010057int q6asm_stream_send_meta_data(struct audio_client *ac, uint32_t stream_id,
10058 uint32_t initial_samples, uint32_t trailing_samples)
10059{
10060 return __q6asm_send_meta_data(ac, stream_id, initial_samples,
10061 trailing_samples);
10062}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010063EXPORT_SYMBOL(q6asm_stream_send_meta_data);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010064
10065int q6asm_send_meta_data(struct audio_client *ac, uint32_t initial_samples,
10066 uint32_t trailing_samples)
10067{
10068 return __q6asm_send_meta_data(ac, ac->stream_id, initial_samples,
10069 trailing_samples);
10070}
10071
10072static void q6asm_reset_buf_state(struct audio_client *ac)
10073{
10074 int cnt = 0;
10075 int loopcnt = 0;
10076 int used;
10077 struct audio_port_data *port = NULL;
10078
10079 if (ac->io_mode & SYNC_IO_MODE) {
10080 used = (ac->io_mode & TUN_WRITE_IO_MODE ? 1 : 0);
10081 mutex_lock(&ac->cmd_lock);
10082 for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
10083 port = &ac->port[loopcnt];
10084 cnt = port->max_buf_cnt - 1;
10085 port->dsp_buf = 0;
10086 port->cpu_buf = 0;
10087 while (cnt >= 0) {
10088 if (!port->buf)
10089 continue;
10090 port->buf[cnt].used = used;
10091 cnt--;
10092 }
10093 }
10094 mutex_unlock(&ac->cmd_lock);
10095 }
10096}
10097
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010098/**
10099 * q6asm_reg_tx_overflow -
10100 * command to register for TX overflow events
10101 *
10102 * @ac: Audio client handle
10103 * @enable: flag to enable or disable events
10104 *
10105 * Returns 0 on success or error on failure
10106 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010107int q6asm_reg_tx_overflow(struct audio_client *ac, uint16_t enable)
10108{
10109 struct asm_session_cmd_regx_overflow tx_overflow;
10110 int rc;
10111
10112 if (!ac) {
10113 pr_err("%s: APR handle NULL\n", __func__);
10114 return -EINVAL;
10115 }
10116 if (ac->apr == NULL) {
10117 pr_err("%s: AC APR handle NULL\n", __func__);
10118 return -EINVAL;
10119 }
10120 pr_debug("%s: session[%d]enable[%d]\n", __func__,
10121 ac->session, enable);
10122 q6asm_add_hdr(ac, &tx_overflow.hdr, sizeof(tx_overflow), TRUE);
10123 atomic_set(&ac->cmd_state, -1);
10124
10125 tx_overflow.hdr.opcode =
10126 ASM_SESSION_CMD_REGISTER_FORX_OVERFLOW_EVENTS;
10127 /* tx overflow event: enable */
10128 tx_overflow.enable_flag = enable;
10129
10130 rc = apr_send_pkt(ac->apr, (uint32_t *) &tx_overflow);
10131 if (rc < 0) {
10132 pr_err("%s: tx overflow op[0x%x]rc[%d]\n",
10133 __func__, tx_overflow.hdr.opcode, rc);
10134 rc = -EINVAL;
10135 goto fail_cmd;
10136 }
10137 rc = wait_event_timeout(ac->cmd_wait,
10138 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
10139 if (!rc) {
10140 pr_err("%s: timeout. waited for tx overflow\n", __func__);
10141 rc = -ETIMEDOUT;
10142 goto fail_cmd;
10143 }
10144 if (atomic_read(&ac->cmd_state) > 0) {
10145 pr_err("%s: DSP returned error[%s]\n",
10146 __func__, adsp_err_get_err_str(
10147 atomic_read(&ac->cmd_state)));
10148 rc = adsp_err_get_lnx_err_code(
10149 atomic_read(&ac->cmd_state));
10150 goto fail_cmd;
10151 }
10152
10153 return 0;
10154fail_cmd:
10155 return rc;
10156}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010157EXPORT_SYMBOL(q6asm_reg_tx_overflow);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010158
10159int q6asm_reg_rx_underflow(struct audio_client *ac, uint16_t enable)
10160{
10161 struct asm_session_cmd_rgstr_rx_underflow rx_underflow;
10162 int rc;
10163
10164 if (!ac) {
10165 pr_err("%s: AC APR handle NULL\n", __func__);
10166 return -EINVAL;
10167 }
10168 if (ac->apr == NULL) {
10169 pr_err("%s: APR handle NULL\n", __func__);
10170 return -EINVAL;
10171 }
10172 pr_debug("%s: session[%d]enable[%d]\n", __func__,
10173 ac->session, enable);
10174 q6asm_add_hdr_async(ac, &rx_underflow.hdr, sizeof(rx_underflow), FALSE);
10175
10176 rx_underflow.hdr.opcode =
10177 ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS;
10178 /* tx overflow event: enable */
10179 rx_underflow.enable_flag = enable;
10180
10181 rc = apr_send_pkt(ac->apr, (uint32_t *) &rx_underflow);
10182 if (rc < 0) {
10183 pr_err("%s: tx overflow op[0x%x]rc[%d]\n",
10184 __func__, rx_underflow.hdr.opcode, rc);
10185 goto fail_cmd;
10186 }
10187 return 0;
10188fail_cmd:
10189 return -EINVAL;
10190}
10191
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010192/**
10193 * q6asm_adjust_session_clock -
10194 * command to adjust session clock
10195 *
10196 * @ac: Audio client handle
10197 * @adjust_time_lsw: lower 32bits
10198 * @adjust_time_msw: upper 32bits
10199 *
10200 * Returns 0 on success or error on failure
10201 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010202int q6asm_adjust_session_clock(struct audio_client *ac,
10203 uint32_t adjust_time_lsw,
10204 uint32_t adjust_time_msw)
10205{
10206 int rc = 0;
10207 int sz = 0;
10208 struct asm_session_cmd_adjust_session_clock_v2 adjust_clock;
10209
10210 pr_debug("%s: adjust_time_lsw is %x, adjust_time_msw is %x\n", __func__,
10211 adjust_time_lsw, adjust_time_msw);
10212
10213 if (!ac) {
10214 pr_err("%s: audio client handle is NULL\n", __func__);
10215 rc = -EINVAL;
10216 goto fail_cmd;
10217 }
10218
10219 if (ac->apr == NULL) {
10220 pr_err("%s: ac->apr is NULL", __func__);
10221 rc = -EINVAL;
10222 goto fail_cmd;
10223 }
10224
10225 sz = sizeof(struct asm_session_cmd_adjust_session_clock_v2);
10226 q6asm_add_hdr(ac, &adjust_clock.hdr, sz, TRUE);
10227 atomic_set(&ac->cmd_state, -1);
10228 adjust_clock.hdr.opcode = ASM_SESSION_CMD_ADJUST_SESSION_CLOCK_V2;
10229
10230 adjust_clock.adjustime_lsw = adjust_time_lsw;
10231 adjust_clock.adjustime_msw = adjust_time_msw;
10232
10233
10234 rc = apr_send_pkt(ac->apr, (uint32_t *) &adjust_clock);
10235 if (rc < 0) {
10236 pr_err("%s: adjust_clock send failed paramid [0x%x]\n",
10237 __func__, adjust_clock.hdr.opcode);
10238 rc = -EINVAL;
10239 goto fail_cmd;
10240 }
10241
10242 rc = wait_event_timeout(ac->cmd_wait,
10243 (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
10244 if (!rc) {
10245 pr_err("%s: timeout, adjust_clock paramid[0x%x]\n",
10246 __func__, adjust_clock.hdr.opcode);
10247 rc = -ETIMEDOUT;
10248 goto fail_cmd;
10249 }
10250
10251 if (atomic_read(&ac->cmd_state) > 0) {
10252 pr_err("%s: DSP returned error[%s]\n",
10253 __func__, adsp_err_get_err_str(
10254 atomic_read(&ac->cmd_state)));
10255 rc = adsp_err_get_lnx_err_code(
10256 atomic_read(&ac->cmd_state));
10257 goto fail_cmd;
10258 }
10259 rc = 0;
10260fail_cmd:
10261 return rc;
10262}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010263EXPORT_SYMBOL(q6asm_adjust_session_clock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010264
10265/*
10266 * q6asm_get_path_delay() - get the path delay for an audio session
10267 * @ac: audio client handle
10268 *
10269 * Retrieves the current audio DSP path delay for the given audio session.
10270 *
10271 * Return: 0 on success, error code otherwise
10272 */
10273int q6asm_get_path_delay(struct audio_client *ac)
10274{
10275 int rc = 0;
10276 struct apr_hdr hdr;
10277
10278 if (!ac || ac->apr == NULL) {
10279 pr_err("%s: invalid audio client\n", __func__);
10280 return -EINVAL;
10281 }
10282
10283 hdr.opcode = ASM_SESSION_CMD_GET_PATH_DELAY_V2;
10284 q6asm_add_hdr(ac, &hdr, sizeof(hdr), TRUE);
10285 atomic_set(&ac->cmd_state, -1);
10286
10287 rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
10288 if (rc < 0) {
10289 pr_err("%s: Commmand 0x%x failed %d\n", __func__,
10290 hdr.opcode, rc);
10291 return rc;
10292 }
10293
10294 rc = wait_event_timeout(ac->cmd_wait,
10295 (atomic_read(&ac->cmd_state) >= 0), 5 * HZ);
10296 if (!rc) {
10297 pr_err("%s: timeout. waited for response opcode[0x%x]\n",
10298 __func__, hdr.opcode);
10299 return -ETIMEDOUT;
10300 }
10301
10302 if (atomic_read(&ac->cmd_state) > 0) {
10303 pr_err("%s: DSP returned error[%s]\n",
10304 __func__, adsp_err_get_err_str(
10305 atomic_read(&ac->cmd_state)));
10306 rc = adsp_err_get_lnx_err_code(
10307 atomic_read(&ac->cmd_state));
10308 return rc;
10309 }
10310
10311 return 0;
10312}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010313EXPORT_SYMBOL(q6asm_get_path_delay);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010314
10315int q6asm_get_apr_service_id(int session_id)
10316{
10317 pr_debug("%s:\n", __func__);
10318
10319 if (session_id <= 0 || session_id > ASM_ACTIVE_STREAMS_ALLOWED) {
10320 pr_err("%s: invalid session_id = %d\n", __func__, session_id);
10321 return -EINVAL;
10322 }
10323
Meng Wang9730cdd2017-09-26 12:48:31 +080010324 return ((struct apr_svc *)(session[session_id].ac)->apr)->id;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010325}
10326
10327int q6asm_get_asm_topology(int session_id)
10328{
10329 int topology = -EINVAL;
10330
10331 if (session_id <= 0 || session_id > ASM_ACTIVE_STREAMS_ALLOWED) {
10332 pr_err("%s: invalid session_id = %d\n", __func__, session_id);
10333 goto done;
10334 }
Meng Wang9730cdd2017-09-26 12:48:31 +080010335 if (session[session_id].ac == NULL) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010336 pr_err("%s: session not created for session id = %d\n",
10337 __func__, session_id);
10338 goto done;
10339 }
Meng Wang9730cdd2017-09-26 12:48:31 +080010340 topology = (session[session_id].ac)->topology;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010341done:
10342 return topology;
10343}
10344
10345int q6asm_get_asm_app_type(int session_id)
10346{
10347 int app_type = -EINVAL;
10348
10349 if (session_id <= 0 || session_id > ASM_ACTIVE_STREAMS_ALLOWED) {
10350 pr_err("%s: invalid session_id = %d\n", __func__, session_id);
10351 goto done;
10352 }
Meng Wang9730cdd2017-09-26 12:48:31 +080010353 if (session[session_id].ac == NULL) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010354 pr_err("%s: session not created for session id = %d\n",
10355 __func__, session_id);
10356 goto done;
10357 }
Meng Wang9730cdd2017-09-26 12:48:31 +080010358 app_type = (session[session_id].ac)->app_type;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010359done:
10360 return app_type;
10361}
10362
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -070010363/*
10364 * Retrieving cal_block will mark cal_block as stale.
10365 * Hence it cannot be reused or resent unless the flag
10366 * is reset.
10367 */
10368static int q6asm_get_asm_topology_apptype(struct q6asm_cal_info *cal_info)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010369{
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010370 struct cal_block_data *cal_block = NULL;
10371
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -070010372 cal_info->topology_id = DEFAULT_POPP_TOPOLOGY;
10373 cal_info->app_type = DEFAULT_APP_TYPE;
10374
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010375 if (cal_data[ASM_TOPOLOGY_CAL] == NULL)
10376 goto done;
10377
10378 mutex_lock(&cal_data[ASM_TOPOLOGY_CAL]->lock);
10379 cal_block = cal_utils_get_only_cal_block(cal_data[ASM_TOPOLOGY_CAL]);
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -070010380 if (cal_block == NULL || cal_utils_is_cal_stale(cal_block))
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010381 goto unlock;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -070010382 cal_info->topology_id = ((struct audio_cal_info_asm_top *)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010383 cal_block->cal_info)->topology;
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -070010384 cal_info->app_type = ((struct audio_cal_info_asm_top *)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010385 cal_block->cal_info)->app_type;
10386
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -070010387 cal_utils_mark_cal_used(cal_block);
10388
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010389unlock:
10390 mutex_unlock(&cal_data[ASM_TOPOLOGY_CAL]->lock);
10391done:
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -070010392 pr_debug("%s: Using topology %d app_type %d\n", __func__,
10393 cal_info->topology_id, cal_info->app_type);
10394
10395 return 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010396}
10397
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010398/**
10399 * q6asm_send_cal -
10400 * command to send ASM calibration
10401 *
10402 * @ac: Audio client handle
10403 *
10404 * Returns 0 on success or error on failure
10405 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010406int q6asm_send_cal(struct audio_client *ac)
10407{
10408 struct cal_block_data *cal_block = NULL;
10409 struct apr_hdr hdr;
10410 char *asm_params = NULL;
10411 struct asm_stream_cmd_set_pp_params_v2 payload_params;
Xiaojun Sanga4648082018-04-27 14:57:33 +080010412 int sz, rc = -EINVAL, session_id = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010413
10414 pr_debug("%s:\n", __func__);
10415
10416 if (!ac) {
10417 pr_err("%s: APR handle NULL\n", __func__);
10418 goto done;
10419 }
Xiaojun Sanga4648082018-04-27 14:57:33 +080010420
10421 session_id = q6asm_get_session_id_from_audio_client(ac);
10422 if (!session_id)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010423 goto done;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010424
10425 if (cal_data[ASM_AUDSTRM_CAL] == NULL)
10426 goto done;
10427
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010428 mutex_lock(&cal_data[ASM_AUDSTRM_CAL]->lock);
10429 cal_block = cal_utils_get_only_cal_block(cal_data[ASM_AUDSTRM_CAL]);
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -070010430 if (cal_block == NULL || cal_utils_is_cal_stale(cal_block)) {
10431 rc = 0; /* not error case */
10432 pr_err("%s: cal_block is NULL or stale\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010433 __func__);
10434 goto unlock;
10435 }
10436
10437 if (cal_block->cal_data.size == 0) {
10438 rc = 0; /* not error case */
10439 pr_debug("%s: cal_data.size is 0, don't send cal data\n",
10440 __func__);
10441 goto unlock;
10442 }
10443
10444 rc = remap_cal_data(ASM_AUDSTRM_CAL_TYPE, cal_block);
10445 if (rc) {
10446 pr_err("%s: Remap_cal_data failed for cal %d!\n",
10447 __func__, ASM_AUDSTRM_CAL);
10448 goto unlock;
10449 }
10450
10451 sz = sizeof(struct apr_hdr) +
10452 sizeof(struct asm_stream_cmd_set_pp_params_v2);
10453 asm_params = kzalloc(sz, GFP_KERNEL);
10454 if (!asm_params) {
10455 pr_err("%s, asm params memory alloc failed", __func__);
10456 rc = -ENOMEM;
10457 goto unlock;
10458 }
10459
Xiaojun Sanga4648082018-04-27 14:57:33 +080010460 mutex_lock(&session[session_id].mutex_lock_per_session);
10461 if (!q6asm_is_valid_audio_client(ac)) {
10462 rc = -EINVAL;
10463 goto free;
10464 }
10465
10466 if (ac->apr == NULL) {
10467 pr_err("%s: AC APR handle NULL\n", __func__);
10468 goto free;
10469 }
10470 if (ac->io_mode & NT_MODE) {
10471 pr_debug("%s: called for NT MODE, exiting\n", __func__);
10472 goto free;
10473 }
10474
10475 if (ac->perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) {
10476 rc = 0; /* no cal is required, not error case */
10477 goto free;
10478 }
10479
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010480 /* asm_stream_cmd_set_pp_params_v2 has no APR header in it */
10481 q6asm_add_hdr_async(ac, &hdr, (sizeof(struct apr_hdr) +
10482 sizeof(struct asm_stream_cmd_set_pp_params_v2)), TRUE);
10483
10484 atomic_set(&ac->cmd_state_pp, -1);
10485 hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
10486 payload_params.data_payload_addr_lsw =
10487 lower_32_bits(cal_block->cal_data.paddr);
10488 payload_params.data_payload_addr_msw =
10489 msm_audio_populate_upper_32_bits(
10490 cal_block->cal_data.paddr);
10491 payload_params.mem_map_handle = cal_block->map_data.q6map_handle;
10492 payload_params.data_payload_size = cal_block->cal_data.size;
10493 memcpy(((u8 *)asm_params), &hdr, sizeof(struct apr_hdr));
10494 memcpy(((u8 *)asm_params + sizeof(struct apr_hdr)), &payload_params,
10495 sizeof(struct asm_stream_cmd_set_pp_params_v2));
10496
10497 pr_debug("%s: phyaddr lsw = %x msw = %x, maphdl = %x calsize = %d\n",
10498 __func__, payload_params.data_payload_addr_lsw,
10499 payload_params.data_payload_addr_msw,
10500 payload_params.mem_map_handle,
10501 payload_params.data_payload_size);
10502
10503 rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params);
10504 if (rc < 0) {
10505 pr_err("%s: audio audstrm cal send failed\n", __func__);
10506 rc = -EINVAL;
10507 goto free;
10508 }
10509 rc = wait_event_timeout(ac->cmd_wait,
10510 (atomic_read(&ac->cmd_state_pp) >= 0), 5 * HZ);
10511 if (!rc) {
10512 pr_err("%s: timeout, audio audstrm cal send\n", __func__);
10513 rc = -ETIMEDOUT;
10514 goto free;
10515 }
10516 if (atomic_read(&ac->cmd_state_pp) > 0) {
10517 pr_err("%s: DSP returned error[%d] audio audstrm cal send\n",
10518 __func__, atomic_read(&ac->cmd_state_pp));
10519 rc = -EINVAL;
10520 goto free;
10521 }
10522
Vikram Pandurangad3b58cc2017-09-27 12:17:36 -070010523 if (cal_block)
10524 cal_utils_mark_cal_used(cal_block);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010525 rc = 0;
10526
10527free:
Xiaojun Sanga4648082018-04-27 14:57:33 +080010528 mutex_unlock(&session[session_id].mutex_lock_per_session);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010529 kfree(asm_params);
10530unlock:
10531 mutex_unlock(&cal_data[ASM_AUDSTRM_CAL]->lock);
10532done:
10533 return rc;
10534}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010535EXPORT_SYMBOL(q6asm_send_cal);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010536
10537static int get_cal_type_index(int32_t cal_type)
10538{
10539 int ret = -EINVAL;
10540
10541 switch (cal_type) {
10542 case ASM_TOPOLOGY_CAL_TYPE:
10543 ret = ASM_TOPOLOGY_CAL;
10544 break;
10545 case ASM_CUST_TOPOLOGY_CAL_TYPE:
10546 ret = ASM_CUSTOM_TOP_CAL;
10547 break;
10548 case ASM_AUDSTRM_CAL_TYPE:
10549 ret = ASM_AUDSTRM_CAL;
10550 break;
10551 case ASM_RTAC_APR_CAL_TYPE:
10552 ret = ASM_RTAC_APR_CAL;
10553 break;
10554 default:
10555 pr_err("%s: invalid cal type %d!\n", __func__, cal_type);
10556 }
10557 return ret;
10558}
10559
10560static int q6asm_alloc_cal(int32_t cal_type,
10561 size_t data_size, void *data)
10562{
10563 int ret = 0;
10564 int cal_index;
10565
10566 pr_debug("%s:\n", __func__);
10567
10568 cal_index = get_cal_type_index(cal_type);
10569 if (cal_index < 0) {
10570 pr_err("%s: could not get cal index %d!\n",
10571 __func__, cal_index);
10572 ret = -EINVAL;
10573 goto done;
10574 }
10575
10576 ret = cal_utils_alloc_cal(data_size, data,
10577 cal_data[cal_index], 0, NULL);
10578 if (ret < 0) {
10579 pr_err("%s: cal_utils_alloc_block failed, ret = %d, cal type = %d!\n",
10580 __func__, ret, cal_type);
10581 ret = -EINVAL;
10582 goto done;
10583 }
10584done:
10585 return ret;
10586}
10587
10588static int q6asm_dealloc_cal(int32_t cal_type,
10589 size_t data_size, void *data)
10590{
10591 int ret = 0;
10592 int cal_index;
10593
10594 pr_debug("%s:\n", __func__);
10595
10596 cal_index = get_cal_type_index(cal_type);
10597 if (cal_index < 0) {
10598 pr_err("%s: could not get cal index %d!\n",
10599 __func__, cal_index);
10600 ret = -EINVAL;
10601 goto done;
10602 }
10603
10604 ret = cal_utils_dealloc_cal(data_size, data,
10605 cal_data[cal_index]);
10606 if (ret < 0) {
10607 pr_err("%s: cal_utils_dealloc_block failed, ret = %d, cal type = %d!\n",
10608 __func__, ret, cal_type);
10609 ret = -EINVAL;
10610 goto done;
10611 }
10612done:
10613 return ret;
10614}
10615
10616static int q6asm_set_cal(int32_t cal_type,
10617 size_t data_size, void *data)
10618{
10619 int ret = 0;
10620 int cal_index;
10621
10622 pr_debug("%s:\n", __func__);
10623
10624 cal_index = get_cal_type_index(cal_type);
10625 if (cal_index < 0) {
10626 pr_err("%s: could not get cal index %d!\n",
10627 __func__, cal_index);
10628 ret = -EINVAL;
10629 goto done;
10630 }
10631
10632 ret = cal_utils_set_cal(data_size, data,
10633 cal_data[cal_index], 0, NULL);
10634 if (ret < 0) {
10635 pr_err("%s: cal_utils_set_cal failed, ret = %d, cal type = %d!\n",
10636 __func__, ret, cal_type);
10637 ret = -EINVAL;
10638 goto done;
10639 }
10640
10641 if (cal_index == ASM_CUSTOM_TOP_CAL) {
10642 mutex_lock(&cal_data[ASM_CUSTOM_TOP_CAL]->lock);
10643 set_custom_topology = 1;
10644 mutex_unlock(&cal_data[ASM_CUSTOM_TOP_CAL]->lock);
10645 }
10646done:
10647 return ret;
10648}
10649
10650static void q6asm_delete_cal_data(void)
10651{
10652 pr_debug("%s:\n", __func__);
10653 cal_utils_destroy_cal_types(ASM_MAX_CAL_TYPES, cal_data);
10654}
10655
10656static int q6asm_init_cal_data(void)
10657{
10658 int ret = 0;
10659 struct cal_type_info cal_type_info[] = {
10660 {{ASM_TOPOLOGY_CAL_TYPE,
10661 {NULL, NULL, NULL,
10662 q6asm_set_cal, NULL, NULL} },
10663 {NULL, NULL, cal_utils_match_buf_num} },
10664
10665 {{ASM_CUST_TOPOLOGY_CAL_TYPE,
10666 {q6asm_alloc_cal, q6asm_dealloc_cal, NULL,
10667 q6asm_set_cal, NULL, NULL} },
10668 {NULL, q6asm_unmap_cal_memory, cal_utils_match_buf_num} },
10669
10670 {{ASM_AUDSTRM_CAL_TYPE,
10671 {q6asm_alloc_cal, q6asm_dealloc_cal, NULL,
10672 q6asm_set_cal, NULL, NULL} },
10673 {NULL, q6asm_unmap_cal_memory, cal_utils_match_buf_num} },
10674
10675 {{ASM_RTAC_APR_CAL_TYPE,
10676 {NULL, NULL, NULL, NULL, NULL, NULL} },
10677 {NULL, NULL, cal_utils_match_buf_num} }
10678 };
10679 pr_debug("%s\n", __func__);
10680
10681 ret = cal_utils_create_cal_types(ASM_MAX_CAL_TYPES, cal_data,
10682 cal_type_info);
10683 if (ret < 0) {
10684 pr_err("%s: could not create cal type! %d\n",
10685 __func__, ret);
10686 ret = -EINVAL;
10687 goto err;
10688 }
10689
10690 return ret;
10691err:
10692 q6asm_delete_cal_data();
10693 return ret;
10694}
10695
10696static int q6asm_is_valid_session(struct apr_client_data *data, void *priv)
10697{
10698 struct audio_client *ac = (struct audio_client *)priv;
10699 union asm_token_struct asm_token;
10700
10701 asm_token.token = data->token;
10702 if (asm_token._token.session_id != ac->session) {
10703 pr_err("%s: Invalid session[%d] rxed expected[%d]",
10704 __func__, asm_token._token.session_id, ac->session);
10705 return -EINVAL;
10706 }
10707 return 0;
10708}
10709
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053010710int __init q6asm_init(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010711{
10712 int lcnt, ret;
10713
10714 pr_debug("%s:\n", __func__);
10715
Meng Wang9730cdd2017-09-26 12:48:31 +080010716 memset(session, 0, sizeof(struct audio_session) *
10717 (ASM_ACTIVE_STREAMS_ALLOWED + 1));
Xiaojun Sanga4648082018-04-27 14:57:33 +080010718 for (lcnt = 0; lcnt <= ASM_ACTIVE_STREAMS_ALLOWED; lcnt++) {
Meng Wang9730cdd2017-09-26 12:48:31 +080010719 spin_lock_init(&(session[lcnt].session_lock));
Xiaojun Sanga4648082018-04-27 14:57:33 +080010720 mutex_init(&(session[lcnt].mutex_lock_per_session));
10721 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010722 set_custom_topology = 1;
10723
10724 /*setup common client used for cal mem map */
10725 common_client.session = ASM_CONTROL_SESSION;
10726 common_client.port[0].buf = &common_buf[0];
10727 common_client.port[1].buf = &common_buf[1];
10728 init_waitqueue_head(&common_client.cmd_wait);
10729 init_waitqueue_head(&common_client.time_wait);
10730 init_waitqueue_head(&common_client.mem_wait);
10731 atomic_set(&common_client.time_flag, 1);
10732 INIT_LIST_HEAD(&common_client.port[0].mem_map_handle);
10733 INIT_LIST_HEAD(&common_client.port[1].mem_map_handle);
10734 mutex_init(&common_client.cmd_lock);
10735 for (lcnt = 0; lcnt <= OUT; lcnt++) {
10736 mutex_init(&common_client.port[lcnt].lock);
10737 spin_lock_init(&common_client.port[lcnt].dsp_lock);
10738 }
10739 atomic_set(&common_client.cmd_state, 0);
10740 atomic_set(&common_client.mem_state, 0);
10741
10742 ret = q6asm_init_cal_data();
10743 if (ret)
10744 pr_err("%s: could not init cal data! ret %d\n",
10745 __func__, ret);
10746
10747 config_debug_fs_init();
10748
10749 return 0;
10750}
10751
Asish Bhattacharya5faacb32017-12-04 17:23:15 +053010752void q6asm_exit(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053010753{
10754 q6asm_delete_cal_data();
10755}