GNU Linux-libre 5.10.76-gnu1
[releases.git] / sound / soc / qcom / qdsp6 / q6asm.c
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
3 // Copyright (c) 2018, Linaro Limited
4
5 #include <linux/mutex.h>
6 #include <linux/wait.h>
7 #include <linux/module.h>
8 #include <linux/soc/qcom/apr.h>
9 #include <linux/device.h>
10 #include <linux/of_platform.h>
11 #include <linux/spinlock.h>
12 #include <linux/kref.h>
13 #include <linux/of.h>
14 #include <uapi/sound/asound.h>
15 #include <uapi/sound/compress_params.h>
16 #include <linux/delay.h>
17 #include <linux/slab.h>
18 #include <linux/mm.h>
19 #include "q6asm.h"
20 #include "q6core.h"
21 #include "q6dsp-errno.h"
22 #include "q6dsp-common.h"
23
24 #define ASM_STREAM_CMD_CLOSE                    0x00010BCD
25 #define ASM_STREAM_CMD_FLUSH                    0x00010BCE
26 #define ASM_SESSION_CMD_PAUSE                   0x00010BD3
27 #define ASM_DATA_CMD_EOS                        0x00010BDB
28 #define ASM_DATA_EVENT_RENDERED_EOS             0x00010C1C
29 #define ASM_NULL_POPP_TOPOLOGY                  0x00010C68
30 #define ASM_STREAM_CMD_FLUSH_READBUFS           0x00010C09
31 #define ASM_STREAM_CMD_SET_ENCDEC_PARAM         0x00010C10
32 #define ASM_STREAM_POSTPROC_TOPO_ID_NONE        0x00010C68
33 #define ASM_CMD_SHARED_MEM_MAP_REGIONS          0x00010D92
34 #define ASM_CMDRSP_SHARED_MEM_MAP_REGIONS       0x00010D93
35 #define ASM_CMD_SHARED_MEM_UNMAP_REGIONS        0x00010D94
36 #define ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2        0x00010D98
37 #define ASM_DATA_EVENT_WRITE_DONE_V2            0x00010D99
38 #define ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2      0x00010DA3
39 #define ASM_SESSION_CMD_RUN_V2                  0x00010DAA
40 #define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2      0x00010DA5
41 #define ASM_MEDIA_FMT_MP3                       0x00010BE9
42 #define ASM_MEDIA_FMT_FLAC                      0x00010C16
43 #define ASM_MEDIA_FMT_WMA_V9                    0x00010DA8
44 #define ASM_MEDIA_FMT_WMA_V10                   0x00010DA7
45 #define ASM_DATA_CMD_WRITE_V2                   0x00010DAB
46 #define ASM_DATA_CMD_READ_V2                    0x00010DAC
47 #define ASM_SESSION_CMD_SUSPEND                 0x00010DEC
48 #define ASM_STREAM_CMD_OPEN_WRITE_V3            0x00010DB3
49 #define ASM_STREAM_CMD_OPEN_READ_V3                 0x00010DB4
50 #define ASM_DATA_EVENT_READ_DONE_V2 0x00010D9A
51 #define ASM_STREAM_CMD_OPEN_READWRITE_V2        0x00010D8D
52 #define ASM_MEDIA_FMT_ALAC                      0x00012f31
53 #define ASM_MEDIA_FMT_APE                       0x00012f32
54 #define ASM_DATA_CMD_REMOVE_INITIAL_SILENCE     0x00010D67
55 #define ASM_DATA_CMD_REMOVE_TRAILING_SILENCE    0x00010D68
56
57
58 #define ASM_LEGACY_STREAM_SESSION       0
59 /* Bit shift for the stream_perf_mode subfield. */
60 #define ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ              29
61 #define ASM_END_POINT_DEVICE_MATRIX     0
62 #define ASM_DEFAULT_APP_TYPE            0
63 #define ASM_SYNC_IO_MODE                0x0001
64 #define ASM_ASYNC_IO_MODE               0x0002
65 #define ASM_TUN_READ_IO_MODE            0x0004  /* tunnel read write mode */
66 #define ASM_TUN_WRITE_IO_MODE           0x0008  /* tunnel read write mode */
67 #define ASM_SHIFT_GAPLESS_MODE_FLAG     31
68 #define ADSP_MEMORY_MAP_SHMEM8_4K_POOL  3
69
70 struct avs_cmd_shared_mem_map_regions {
71         u16 mem_pool_id;
72         u16 num_regions;
73         u32 property_flag;
74 } __packed;
75
76 struct avs_shared_map_region_payload {
77         u32 shm_addr_lsw;
78         u32 shm_addr_msw;
79         u32 mem_size_bytes;
80 } __packed;
81
82 struct avs_cmd_shared_mem_unmap_regions {
83         u32 mem_map_handle;
84 } __packed;
85
86 struct asm_data_cmd_media_fmt_update_v2 {
87         u32 fmt_blk_size;
88 } __packed;
89
90 struct asm_multi_channel_pcm_fmt_blk_v2 {
91         struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
92         u16 num_channels;
93         u16 bits_per_sample;
94         u32 sample_rate;
95         u16 is_signed;
96         u16 reserved;
97         u8 channel_mapping[PCM_MAX_NUM_CHANNEL];
98 } __packed;
99
100 struct asm_flac_fmt_blk_v2 {
101         struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
102         u16 is_stream_info_present;
103         u16 num_channels;
104         u16 min_blk_size;
105         u16 max_blk_size;
106         u16 md5_sum[8];
107         u32 sample_rate;
108         u32 min_frame_size;
109         u32 max_frame_size;
110         u16 sample_size;
111         u16 reserved;
112 } __packed;
113
114 struct asm_wmastdv9_fmt_blk_v2 {
115         struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
116         u16          fmtag;
117         u16          num_channels;
118         u32          sample_rate;
119         u32          bytes_per_sec;
120         u16          blk_align;
121         u16          bits_per_sample;
122         u32          channel_mask;
123         u16          enc_options;
124         u16          reserved;
125 } __packed;
126
127 struct asm_wmaprov10_fmt_blk_v2 {
128         struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
129         u16          fmtag;
130         u16          num_channels;
131         u32          sample_rate;
132         u32          bytes_per_sec;
133         u16          blk_align;
134         u16          bits_per_sample;
135         u32          channel_mask;
136         u16          enc_options;
137         u16          advanced_enc_options1;
138         u32          advanced_enc_options2;
139 } __packed;
140
141 struct asm_alac_fmt_blk_v2 {
142         struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
143         u32 frame_length;
144         u8 compatible_version;
145         u8 bit_depth;
146         u8 pb;
147         u8 mb;
148         u8 kb;
149         u8 num_channels;
150         u16 max_run;
151         u32 max_frame_bytes;
152         u32 avg_bit_rate;
153         u32 sample_rate;
154         u32 channel_layout_tag;
155 } __packed;
156
157 struct asm_ape_fmt_blk_v2 {
158         struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
159         u16 compatible_version;
160         u16 compression_level;
161         u32 format_flags;
162         u32 blocks_per_frame;
163         u32 final_frame_blocks;
164         u32 total_frames;
165         u16 bits_per_sample;
166         u16 num_channels;
167         u32 sample_rate;
168         u32 seek_table_present;
169 } __packed;
170
171 struct asm_stream_cmd_set_encdec_param {
172         u32                  param_id;
173         u32                  param_size;
174 } __packed;
175
176 struct asm_enc_cfg_blk_param_v2 {
177         u32                  frames_per_buf;
178         u32                  enc_cfg_blk_size;
179 } __packed;
180
181 struct asm_multi_channel_pcm_enc_cfg_v2 {
182         struct asm_stream_cmd_set_encdec_param  encdec;
183         struct asm_enc_cfg_blk_param_v2 encblk;
184         uint16_t  num_channels;
185         uint16_t  bits_per_sample;
186         uint32_t  sample_rate;
187         uint16_t  is_signed;
188         uint16_t  reserved;
189         uint8_t   channel_mapping[8];
190 } __packed;
191
192 struct asm_data_cmd_read_v2 {
193         u32                  buf_addr_lsw;
194         u32                  buf_addr_msw;
195         u32                  mem_map_handle;
196         u32                  buf_size;
197         u32                  seq_id;
198 } __packed;
199
200 struct asm_data_cmd_read_v2_done {
201         u32     status;
202         u32     buf_addr_lsw;
203         u32     buf_addr_msw;
204 };
205
206 struct asm_stream_cmd_open_read_v3 {
207         u32                    mode_flags;
208         u32                    src_endpointype;
209         u32                    preprocopo_id;
210         u32                    enc_cfg_id;
211         u16                    bits_per_sample;
212         u16                    reserved;
213 } __packed;
214
215 struct asm_data_cmd_write_v2 {
216         u32 buf_addr_lsw;
217         u32 buf_addr_msw;
218         u32 mem_map_handle;
219         u32 buf_size;
220         u32 seq_id;
221         u32 timestamp_lsw;
222         u32 timestamp_msw;
223         u32 flags;
224 } __packed;
225
226 struct asm_stream_cmd_open_write_v3 {
227         uint32_t mode_flags;
228         uint16_t sink_endpointype;
229         uint16_t bits_per_sample;
230         uint32_t postprocopo_id;
231         uint32_t dec_fmt_id;
232 } __packed;
233
234 struct asm_session_cmd_run_v2 {
235         u32 flags;
236         u32 time_lsw;
237         u32 time_msw;
238 } __packed;
239
240 struct audio_buffer {
241         phys_addr_t phys;
242         uint32_t size;          /* size of buffer */
243 };
244
245 struct audio_port_data {
246         struct audio_buffer *buf;
247         uint32_t num_periods;
248         uint32_t dsp_buf;
249         uint32_t mem_map_handle;
250 };
251
252 struct q6asm {
253         struct apr_device *adev;
254         struct device *dev;
255         struct q6core_svc_api_info ainfo;
256         wait_queue_head_t mem_wait;
257         spinlock_t slock;
258         struct audio_client *session[MAX_SESSIONS + 1];
259 };
260
261 struct audio_client {
262         int session;
263         q6asm_cb cb;
264         void *priv;
265         uint32_t io_mode;
266         struct apr_device *adev;
267         struct mutex cmd_lock;
268         spinlock_t lock;
269         struct kref refcount;
270         /* idx:1 out port, 0: in port */
271         struct audio_port_data port[2];
272         wait_queue_head_t cmd_wait;
273         struct aprv2_ibasic_rsp_result_t result;
274         int perf_mode;
275         struct q6asm *q6asm;
276         struct device *dev;
277 };
278
279 static inline void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
280                                  uint32_t pkt_size, bool cmd_flg,
281                                  uint32_t stream_id)
282 {
283         hdr->hdr_field = APR_SEQ_CMD_HDR_FIELD;
284         hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id);
285         hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id);
286         hdr->pkt_size = pkt_size;
287         if (cmd_flg)
288                 hdr->token = ac->session;
289 }
290
291 static int q6asm_apr_send_session_pkt(struct q6asm *a, struct audio_client *ac,
292                                       struct apr_pkt *pkt, uint32_t rsp_opcode)
293 {
294         struct apr_hdr *hdr = &pkt->hdr;
295         int rc;
296
297         mutex_lock(&ac->cmd_lock);
298         ac->result.opcode = 0;
299         ac->result.status = 0;
300         rc = apr_send_pkt(a->adev, pkt);
301         if (rc < 0)
302                 goto err;
303
304         if (rsp_opcode)
305                 rc = wait_event_timeout(a->mem_wait,
306                                         (ac->result.opcode == hdr->opcode) ||
307                                         (ac->result.opcode == rsp_opcode),
308                                         5 * HZ);
309         else
310                 rc = wait_event_timeout(a->mem_wait,
311                                         (ac->result.opcode == hdr->opcode),
312                                         5 * HZ);
313
314         if (!rc) {
315                 dev_err(a->dev, "CMD %x timeout\n", hdr->opcode);
316                 rc = -ETIMEDOUT;
317         } else if (ac->result.status > 0) {
318                 dev_err(a->dev, "DSP returned error[%x]\n",
319                         ac->result.status);
320                 rc = -EINVAL;
321         }
322
323 err:
324         mutex_unlock(&ac->cmd_lock);
325         return rc;
326 }
327
328 static int __q6asm_memory_unmap(struct audio_client *ac,
329                                 phys_addr_t buf_add, int dir)
330 {
331         struct avs_cmd_shared_mem_unmap_regions *mem_unmap;
332         struct q6asm *a = dev_get_drvdata(ac->dev->parent);
333         struct apr_pkt *pkt;
334         int rc, pkt_size;
335         void *p;
336
337         if (ac->port[dir].mem_map_handle == 0) {
338                 dev_err(ac->dev, "invalid mem handle\n");
339                 return -EINVAL;
340         }
341
342         pkt_size = APR_HDR_SIZE + sizeof(*mem_unmap);
343         p = kzalloc(pkt_size, GFP_KERNEL);
344         if (!p)
345                 return -ENOMEM;
346
347         pkt = p;
348         mem_unmap = p + APR_HDR_SIZE;
349
350         pkt->hdr.hdr_field = APR_SEQ_CMD_HDR_FIELD;
351         pkt->hdr.src_port = 0;
352         pkt->hdr.dest_port = 0;
353         pkt->hdr.pkt_size = pkt_size;
354         pkt->hdr.token = ((ac->session << 8) | dir);
355
356         pkt->hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS;
357         mem_unmap->mem_map_handle = ac->port[dir].mem_map_handle;
358
359         rc = q6asm_apr_send_session_pkt(a, ac, pkt, 0);
360         if (rc < 0) {
361                 kfree(pkt);
362                 return rc;
363         }
364
365         ac->port[dir].mem_map_handle = 0;
366
367         kfree(pkt);
368         return 0;
369 }
370
371
372 static void q6asm_audio_client_free_buf(struct audio_client *ac,
373                                         struct audio_port_data *port)
374 {
375         unsigned long flags;
376
377         spin_lock_irqsave(&ac->lock, flags);
378         port->num_periods = 0;
379         kfree(port->buf);
380         port->buf = NULL;
381         spin_unlock_irqrestore(&ac->lock, flags);
382 }
383
384 /**
385  * q6asm_unmap_memory_regions() - unmap memory regions in the dsp.
386  *
387  * @dir: direction of audio stream
388  * @ac: audio client instanace
389  *
390  * Return: Will be an negative value on failure or zero on success
391  */
392 int q6asm_unmap_memory_regions(unsigned int dir, struct audio_client *ac)
393 {
394         struct audio_port_data *port;
395         int cnt = 0;
396         int rc = 0;
397
398         port = &ac->port[dir];
399         if (!port->buf) {
400                 rc = -EINVAL;
401                 goto err;
402         }
403
404         cnt = port->num_periods - 1;
405         if (cnt >= 0) {
406                 rc = __q6asm_memory_unmap(ac, port->buf[dir].phys, dir);
407                 if (rc < 0) {
408                         dev_err(ac->dev, "%s: Memory_unmap_regions failed %d\n",
409                                 __func__, rc);
410                         goto err;
411                 }
412         }
413
414         q6asm_audio_client_free_buf(ac, port);
415
416 err:
417         return rc;
418 }
419 EXPORT_SYMBOL_GPL(q6asm_unmap_memory_regions);
420
421 static int __q6asm_memory_map_regions(struct audio_client *ac, int dir,
422                                       size_t period_sz, unsigned int periods,
423                                       bool is_contiguous)
424 {
425         struct avs_cmd_shared_mem_map_regions *cmd = NULL;
426         struct avs_shared_map_region_payload *mregions = NULL;
427         struct q6asm *a = dev_get_drvdata(ac->dev->parent);
428         struct audio_port_data *port = NULL;
429         struct audio_buffer *ab = NULL;
430         struct apr_pkt *pkt;
431         void *p;
432         unsigned long flags;
433         uint32_t num_regions, buf_sz;
434         int rc, i, pkt_size;
435
436         if (is_contiguous) {
437                 num_regions = 1;
438                 buf_sz = period_sz * periods;
439         } else {
440                 buf_sz = period_sz;
441                 num_regions = periods;
442         }
443
444         /* DSP expects size should be aligned to 4K */
445         buf_sz = ALIGN(buf_sz, 4096);
446
447         pkt_size = APR_HDR_SIZE + sizeof(*cmd) +
448                    (sizeof(*mregions) * num_regions);
449
450         p = kzalloc(pkt_size, GFP_KERNEL);
451         if (!p)
452                 return -ENOMEM;
453
454         pkt = p;
455         cmd = p + APR_HDR_SIZE;
456         mregions = p + APR_HDR_SIZE +  sizeof(*cmd);
457
458         pkt->hdr.hdr_field = APR_SEQ_CMD_HDR_FIELD;
459         pkt->hdr.src_port = 0;
460         pkt->hdr.dest_port = 0;
461         pkt->hdr.pkt_size = pkt_size;
462         pkt->hdr.token = ((ac->session << 8) | dir);
463         pkt->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS;
464
465         cmd->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
466         cmd->num_regions = num_regions;
467         cmd->property_flag = 0x00;
468
469         spin_lock_irqsave(&ac->lock, flags);
470         port = &ac->port[dir];
471
472         for (i = 0; i < num_regions; i++) {
473                 ab = &port->buf[i];
474                 mregions->shm_addr_lsw = lower_32_bits(ab->phys);
475                 mregions->shm_addr_msw = upper_32_bits(ab->phys);
476                 mregions->mem_size_bytes = buf_sz;
477                 ++mregions;
478         }
479         spin_unlock_irqrestore(&ac->lock, flags);
480
481         rc = q6asm_apr_send_session_pkt(a, ac, pkt,
482                                         ASM_CMDRSP_SHARED_MEM_MAP_REGIONS);
483
484         kfree(pkt);
485
486         return rc;
487 }
488
489 /**
490  * q6asm_map_memory_regions() - map memory regions in the dsp.
491  *
492  * @dir: direction of audio stream
493  * @ac: audio client instanace
494  * @phys: physcial address that needs mapping.
495  * @period_sz: audio period size
496  * @periods: number of periods
497  *
498  * Return: Will be an negative value on failure or zero on success
499  */
500 int q6asm_map_memory_regions(unsigned int dir, struct audio_client *ac,
501                              phys_addr_t phys,
502                              size_t period_sz, unsigned int periods)
503 {
504         struct audio_buffer *buf;
505         unsigned long flags;
506         int cnt;
507         int rc;
508
509         spin_lock_irqsave(&ac->lock, flags);
510         if (ac->port[dir].buf) {
511                 dev_err(ac->dev, "Buffer already allocated\n");
512                 spin_unlock_irqrestore(&ac->lock, flags);
513                 return 0;
514         }
515
516         buf = kzalloc(((sizeof(struct audio_buffer)) * periods), GFP_ATOMIC);
517         if (!buf) {
518                 spin_unlock_irqrestore(&ac->lock, flags);
519                 return -ENOMEM;
520         }
521
522
523         ac->port[dir].buf = buf;
524
525         buf[0].phys = phys;
526         buf[0].size = period_sz;
527
528         for (cnt = 1; cnt < periods; cnt++) {
529                 if (period_sz > 0) {
530                         buf[cnt].phys = buf[0].phys + (cnt * period_sz);
531                         buf[cnt].size = period_sz;
532                 }
533         }
534         ac->port[dir].num_periods = periods;
535
536         spin_unlock_irqrestore(&ac->lock, flags);
537
538         rc = __q6asm_memory_map_regions(ac, dir, period_sz, periods, 1);
539         if (rc < 0) {
540                 dev_err(ac->dev, "Memory_map_regions failed\n");
541                 q6asm_audio_client_free_buf(ac, &ac->port[dir]);
542         }
543
544         return rc;
545 }
546 EXPORT_SYMBOL_GPL(q6asm_map_memory_regions);
547
548 static void q6asm_audio_client_release(struct kref *ref)
549 {
550         struct audio_client *ac;
551         struct q6asm *a;
552         unsigned long flags;
553
554         ac = container_of(ref, struct audio_client, refcount);
555         a = ac->q6asm;
556
557         spin_lock_irqsave(&a->slock, flags);
558         a->session[ac->session] = NULL;
559         spin_unlock_irqrestore(&a->slock, flags);
560
561         kfree(ac);
562 }
563
564 /**
565  * q6asm_audio_client_free() - Freee allocated audio client
566  *
567  * @ac: audio client to free
568  */
569 void q6asm_audio_client_free(struct audio_client *ac)
570 {
571         kref_put(&ac->refcount, q6asm_audio_client_release);
572 }
573 EXPORT_SYMBOL_GPL(q6asm_audio_client_free);
574
575 static struct audio_client *q6asm_get_audio_client(struct q6asm *a,
576                                                    int session_id)
577 {
578         struct audio_client *ac = NULL;
579         unsigned long flags;
580
581         spin_lock_irqsave(&a->slock, flags);
582         if ((session_id <= 0) || (session_id > MAX_SESSIONS)) {
583                 dev_err(a->dev, "invalid session: %d\n", session_id);
584                 goto err;
585         }
586
587         /* check for valid session */
588         if (!a->session[session_id])
589                 goto err;
590         else if (a->session[session_id]->session != session_id)
591                 goto err;
592
593         ac = a->session[session_id];
594         kref_get(&ac->refcount);
595 err:
596         spin_unlock_irqrestore(&a->slock, flags);
597         return ac;
598 }
599
600 static int32_t q6asm_stream_callback(struct apr_device *adev,
601                                      struct apr_resp_pkt *data,
602                                      int session_id)
603 {
604         struct q6asm *q6asm = dev_get_drvdata(&adev->dev);
605         struct aprv2_ibasic_rsp_result_t *result;
606         struct apr_hdr *hdr = &data->hdr;
607         struct audio_port_data *port;
608         struct audio_client *ac;
609         uint32_t client_event = 0;
610         int ret = 0;
611
612         ac = q6asm_get_audio_client(q6asm, session_id);
613         if (!ac)/* Audio client might already be freed by now */
614                 return 0;
615
616         result = data->payload;
617
618         switch (hdr->opcode) {
619         case APR_BASIC_RSP_RESULT:
620                 switch (result->opcode) {
621                 case ASM_SESSION_CMD_PAUSE:
622                         client_event = ASM_CLIENT_EVENT_CMD_PAUSE_DONE;
623                         break;
624                 case ASM_SESSION_CMD_SUSPEND:
625                         client_event = ASM_CLIENT_EVENT_CMD_SUSPEND_DONE;
626                         break;
627                 case ASM_STREAM_CMD_FLUSH:
628                         client_event = ASM_CLIENT_EVENT_CMD_FLUSH_DONE;
629                         break;
630                 case ASM_SESSION_CMD_RUN_V2:
631                         client_event = ASM_CLIENT_EVENT_CMD_RUN_DONE;
632                         break;
633                 case ASM_STREAM_CMD_CLOSE:
634                         client_event = ASM_CLIENT_EVENT_CMD_CLOSE_DONE;
635                         break;
636                 case ASM_STREAM_CMD_FLUSH_READBUFS:
637                         client_event = ASM_CLIENT_EVENT_CMD_OUT_FLUSH_DONE;
638                         break;
639                 case ASM_STREAM_CMD_OPEN_WRITE_V3:
640                 case ASM_STREAM_CMD_OPEN_READ_V3:
641                 case ASM_STREAM_CMD_OPEN_READWRITE_V2:
642                 case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
643                 case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
644                 case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE:
645                 case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE:
646                         if (result->status != 0) {
647                                 dev_err(ac->dev,
648                                         "cmd = 0x%x returned error = 0x%x\n",
649                                         result->opcode, result->status);
650                                 ac->result = *result;
651                                 wake_up(&ac->cmd_wait);
652                                 ret = 0;
653                                 goto done;
654                         }
655                         break;
656                 default:
657                         dev_err(ac->dev, "command[0x%x] not expecting rsp\n",
658                                 result->opcode);
659                         break;
660                 }
661
662                 ac->result = *result;
663                 wake_up(&ac->cmd_wait);
664
665                 if (ac->cb)
666                         ac->cb(client_event, hdr->token,
667                                data->payload, ac->priv);
668
669                 ret = 0;
670                 goto done;
671
672         case ASM_DATA_EVENT_WRITE_DONE_V2:
673                 client_event = ASM_CLIENT_EVENT_DATA_WRITE_DONE;
674                 if (ac->io_mode & ASM_SYNC_IO_MODE) {
675                         phys_addr_t phys;
676                         unsigned long flags;
677                         int token = hdr->token & ASM_WRITE_TOKEN_MASK;
678
679                         spin_lock_irqsave(&ac->lock, flags);
680
681                         port =  &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
682
683                         if (!port->buf) {
684                                 spin_unlock_irqrestore(&ac->lock, flags);
685                                 ret = 0;
686                                 goto done;
687                         }
688
689                         phys = port->buf[token].phys;
690
691                         if (lower_32_bits(phys) != result->opcode ||
692                             upper_32_bits(phys) != result->status) {
693                                 dev_err(ac->dev, "Expected addr %pa\n",
694                                         &port->buf[token].phys);
695                                 spin_unlock_irqrestore(&ac->lock, flags);
696                                 ret = -EINVAL;
697                                 goto done;
698                         }
699                         spin_unlock_irqrestore(&ac->lock, flags);
700                 }
701                 break;
702         case ASM_DATA_EVENT_READ_DONE_V2:
703                 client_event = ASM_CLIENT_EVENT_DATA_READ_DONE;
704                 if (ac->io_mode & ASM_SYNC_IO_MODE) {
705                         struct asm_data_cmd_read_v2_done *done = data->payload;
706                         unsigned long flags;
707                         phys_addr_t phys;
708
709                         spin_lock_irqsave(&ac->lock, flags);
710                         port =  &ac->port[SNDRV_PCM_STREAM_CAPTURE];
711                         if (!port->buf) {
712                                 spin_unlock_irqrestore(&ac->lock, flags);
713                                 ret = 0;
714                                 goto done;
715                         }
716
717                         phys = port->buf[hdr->token].phys;
718
719                         if (upper_32_bits(phys) != done->buf_addr_msw ||
720                             lower_32_bits(phys) != done->buf_addr_lsw) {
721                                 dev_err(ac->dev, "Expected addr %pa %08x-%08x\n",
722                                         &port->buf[hdr->token].phys,
723                                         done->buf_addr_lsw,
724                                         done->buf_addr_msw);
725                                 spin_unlock_irqrestore(&ac->lock, flags);
726                                 ret = -EINVAL;
727                                 goto done;
728                         }
729                         spin_unlock_irqrestore(&ac->lock, flags);
730                 }
731
732                 break;
733         case ASM_DATA_EVENT_RENDERED_EOS:
734                 client_event = ASM_CLIENT_EVENT_CMD_EOS_DONE;
735                 break;
736         }
737
738         if (ac->cb)
739                 ac->cb(client_event, hdr->token, data->payload, ac->priv);
740
741 done:
742         kref_put(&ac->refcount, q6asm_audio_client_release);
743         return ret;
744 }
745
746 static int q6asm_srvc_callback(struct apr_device *adev,
747                                struct apr_resp_pkt *data)
748 {
749         struct q6asm *q6asm = dev_get_drvdata(&adev->dev);
750         struct aprv2_ibasic_rsp_result_t *result;
751         struct audio_port_data *port;
752         struct audio_client *ac = NULL;
753         struct apr_hdr *hdr = &data->hdr;
754         struct q6asm *a;
755         uint32_t sid = 0;
756         uint32_t dir = 0;
757         int session_id;
758
759         session_id = (hdr->dest_port >> 8) & 0xFF;
760         if (session_id)
761                 return q6asm_stream_callback(adev, data, session_id);
762
763         sid = (hdr->token >> 8) & 0x0F;
764         ac = q6asm_get_audio_client(q6asm, sid);
765         if (!ac) {
766                 dev_err(&adev->dev, "Audio Client not active\n");
767                 return 0;
768         }
769
770         a = dev_get_drvdata(ac->dev->parent);
771         dir = (hdr->token & 0x0F);
772         port = &ac->port[dir];
773         result = data->payload;
774
775         switch (hdr->opcode) {
776         case APR_BASIC_RSP_RESULT:
777                 switch (result->opcode) {
778                 case ASM_CMD_SHARED_MEM_MAP_REGIONS:
779                 case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:
780                         ac->result = *result;
781                         wake_up(&a->mem_wait);
782                         break;
783                 default:
784                         dev_err(&adev->dev, "command[0x%x] not expecting rsp\n",
785                                  result->opcode);
786                         break;
787                 }
788                 goto done;
789         case ASM_CMDRSP_SHARED_MEM_MAP_REGIONS:
790                 ac->result.status = 0;
791                 ac->result.opcode = hdr->opcode;
792                 port->mem_map_handle = result->opcode;
793                 wake_up(&a->mem_wait);
794                 break;
795         case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:
796                 ac->result.opcode = hdr->opcode;
797                 ac->result.status = 0;
798                 port->mem_map_handle = 0;
799                 wake_up(&a->mem_wait);
800                 break;
801         default:
802                 dev_dbg(&adev->dev, "command[0x%x]success [0x%x]\n",
803                         result->opcode, result->status);
804                 break;
805         }
806
807         if (ac->cb)
808                 ac->cb(hdr->opcode, hdr->token, data->payload, ac->priv);
809
810 done:
811         kref_put(&ac->refcount, q6asm_audio_client_release);
812
813         return 0;
814 }
815
816 /**
817  * q6asm_get_session_id() - get session id for audio client
818  *
819  * @c: audio client pointer
820  *
821  * Return: Will be an session id of the audio client.
822  */
823 int q6asm_get_session_id(struct audio_client *c)
824 {
825         return c->session;
826 }
827 EXPORT_SYMBOL_GPL(q6asm_get_session_id);
828
829 /**
830  * q6asm_audio_client_alloc() - Allocate a new audio client
831  *
832  * @dev: Pointer to asm child device.
833  * @cb: event callback.
834  * @priv: private data associated with this client.
835  * @session_id: session id
836  * @perf_mode: performace mode for this client
837  *
838  * Return: Will be an error pointer on error or a valid audio client
839  * on success.
840  */
841 struct audio_client *q6asm_audio_client_alloc(struct device *dev, q6asm_cb cb,
842                                               void *priv, int session_id,
843                                               int perf_mode)
844 {
845         struct q6asm *a = dev_get_drvdata(dev->parent);
846         struct audio_client *ac;
847         unsigned long flags;
848
849         ac = q6asm_get_audio_client(a, session_id + 1);
850         if (ac) {
851                 dev_err(dev, "Audio Client already active\n");
852                 return ac;
853         }
854
855         ac = kzalloc(sizeof(*ac), GFP_KERNEL);
856         if (!ac)
857                 return ERR_PTR(-ENOMEM);
858
859         spin_lock_irqsave(&a->slock, flags);
860         a->session[session_id + 1] = ac;
861         spin_unlock_irqrestore(&a->slock, flags);
862         ac->session = session_id + 1;
863         ac->cb = cb;
864         ac->dev = dev;
865         ac->q6asm = a;
866         ac->priv = priv;
867         ac->io_mode = ASM_SYNC_IO_MODE;
868         ac->perf_mode = perf_mode;
869         ac->adev = a->adev;
870         kref_init(&ac->refcount);
871
872         init_waitqueue_head(&ac->cmd_wait);
873         mutex_init(&ac->cmd_lock);
874         spin_lock_init(&ac->lock);
875
876         return ac;
877 }
878 EXPORT_SYMBOL_GPL(q6asm_audio_client_alloc);
879
880 static int q6asm_ac_send_cmd_sync(struct audio_client *ac, struct apr_pkt *pkt)
881 {
882         struct apr_hdr *hdr = &pkt->hdr;
883         int rc;
884
885         mutex_lock(&ac->cmd_lock);
886         ac->result.opcode = 0;
887         ac->result.status = 0;
888
889         rc = apr_send_pkt(ac->adev, pkt);
890         if (rc < 0)
891                 goto err;
892
893         rc = wait_event_timeout(ac->cmd_wait,
894                                 (ac->result.opcode == hdr->opcode), 5 * HZ);
895         if (!rc) {
896                 dev_err(ac->dev, "CMD %x timeout\n", hdr->opcode);
897                 rc =  -ETIMEDOUT;
898                 goto err;
899         }
900
901         if (ac->result.status > 0) {
902                 dev_err(ac->dev, "DSP returned error[%x]\n",
903                         ac->result.status);
904                 rc = -EINVAL;
905         } else {
906                 rc = 0;
907         }
908
909
910 err:
911         mutex_unlock(&ac->cmd_lock);
912         return rc;
913 }
914
915 /**
916  * q6asm_open_write() - Open audio client for writing
917  * @ac: audio client pointer
918  * @stream_id: stream id of q6asm session
919  * @format: audio sample format
920  * @codec_profile: compressed format profile
921  * @bits_per_sample: bits per sample
922  * @is_gapless: flag to indicate if this is a gapless stream
923  *
924  * Return: Will be an negative value on error or zero on success
925  */
926 int q6asm_open_write(struct audio_client *ac, uint32_t stream_id,
927                      uint32_t format, u32 codec_profile,
928                      uint16_t bits_per_sample, bool is_gapless)
929 {
930         struct asm_stream_cmd_open_write_v3 *open;
931         struct apr_pkt *pkt;
932         void *p;
933         int rc, pkt_size;
934
935         pkt_size = APR_HDR_SIZE + sizeof(*open);
936
937         p = kzalloc(pkt_size, GFP_KERNEL);
938         if (!p)
939                 return -ENOMEM;
940
941         pkt = p;
942         open = p + APR_HDR_SIZE;
943         q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
944
945         pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
946         open->mode_flags = 0x00;
947         open->mode_flags |= ASM_LEGACY_STREAM_SESSION;
948         if (is_gapless)
949                 open->mode_flags |= BIT(ASM_SHIFT_GAPLESS_MODE_FLAG);
950
951         /* source endpoint : matrix */
952         open->sink_endpointype = ASM_END_POINT_DEVICE_MATRIX;
953         open->bits_per_sample = bits_per_sample;
954         open->postprocopo_id = ASM_NULL_POPP_TOPOLOGY;
955
956         switch (format) {
957         case SND_AUDIOCODEC_MP3:
958                 open->dec_fmt_id = ASM_MEDIA_FMT_MP3;
959                 break;
960         case FORMAT_LINEAR_PCM:
961                 open->dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
962                 break;
963         case SND_AUDIOCODEC_FLAC:
964                 open->dec_fmt_id = ASM_MEDIA_FMT_FLAC;
965                 break;
966         case SND_AUDIOCODEC_WMA:
967                 switch (codec_profile) {
968                 case SND_AUDIOPROFILE_WMA9:
969                         open->dec_fmt_id = ASM_MEDIA_FMT_WMA_V9;
970                         break;
971                 case SND_AUDIOPROFILE_WMA10:
972                 case SND_AUDIOPROFILE_WMA9_PRO:
973                 case SND_AUDIOPROFILE_WMA9_LOSSLESS:
974                 case SND_AUDIOPROFILE_WMA10_LOSSLESS:
975                         open->dec_fmt_id = ASM_MEDIA_FMT_WMA_V10;
976                         break;
977                 default:
978                         dev_err(ac->dev, "Invalid codec profile 0x%x\n",
979                                 codec_profile);
980                         rc = -EINVAL;
981                         goto err;
982                 }
983                 break;
984         case SND_AUDIOCODEC_ALAC:
985                 open->dec_fmt_id = ASM_MEDIA_FMT_ALAC;
986                 break;
987         case SND_AUDIOCODEC_APE:
988                 open->dec_fmt_id = ASM_MEDIA_FMT_APE;
989                 break;
990         default:
991                 dev_err(ac->dev, "Invalid format 0x%x\n", format);
992                 rc = -EINVAL;
993                 goto err;
994         }
995
996         rc = q6asm_ac_send_cmd_sync(ac, pkt);
997         if (rc < 0)
998                 goto err;
999
1000         ac->io_mode |= ASM_TUN_WRITE_IO_MODE;
1001
1002 err:
1003         kfree(pkt);
1004         return rc;
1005 }
1006 EXPORT_SYMBOL_GPL(q6asm_open_write);
1007
1008 static int __q6asm_run(struct audio_client *ac, uint32_t stream_id,
1009                        uint32_t flags, uint32_t msw_ts, uint32_t lsw_ts,
1010                        bool wait)
1011 {
1012         struct asm_session_cmd_run_v2 *run;
1013         struct apr_pkt *pkt;
1014         int pkt_size, rc;
1015         void *p;
1016
1017         pkt_size = APR_HDR_SIZE + sizeof(*run);
1018         p = kzalloc(pkt_size, GFP_ATOMIC);
1019         if (!p)
1020                 return -ENOMEM;
1021
1022         pkt = p;
1023         run = p + APR_HDR_SIZE;
1024
1025         q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1026
1027         pkt->hdr.opcode = ASM_SESSION_CMD_RUN_V2;
1028         run->flags = flags;
1029         run->time_lsw = lsw_ts;
1030         run->time_msw = msw_ts;
1031         if (wait) {
1032                 rc = q6asm_ac_send_cmd_sync(ac, pkt);
1033         } else {
1034                 rc = apr_send_pkt(ac->adev, pkt);
1035                 if (rc == pkt_size)
1036                         rc = 0;
1037         }
1038
1039         kfree(pkt);
1040         return rc;
1041 }
1042
1043 /**
1044  * q6asm_run() - start the audio client
1045  *
1046  * @ac: audio client pointer
1047  * @stream_id: stream id of q6asm session
1048  * @flags: flags associated with write
1049  * @msw_ts: timestamp msw
1050  * @lsw_ts: timestamp lsw
1051  *
1052  * Return: Will be an negative value on error or zero on success
1053  */
1054 int q6asm_run(struct audio_client *ac, uint32_t stream_id, uint32_t flags,
1055               uint32_t msw_ts, uint32_t lsw_ts)
1056 {
1057         return __q6asm_run(ac, stream_id, flags, msw_ts, lsw_ts, true);
1058 }
1059 EXPORT_SYMBOL_GPL(q6asm_run);
1060
1061 /**
1062  * q6asm_run_nowait() - start the audio client withou blocking
1063  *
1064  * @ac: audio client pointer
1065  * @stream_id: stream id
1066  * @flags: flags associated with write
1067  * @msw_ts: timestamp msw
1068  * @lsw_ts: timestamp lsw
1069  *
1070  * Return: Will be an negative value on error or zero on success
1071  */
1072 int q6asm_run_nowait(struct audio_client *ac, uint32_t stream_id,
1073                      uint32_t flags, uint32_t msw_ts, uint32_t lsw_ts)
1074 {
1075         return __q6asm_run(ac, stream_id, flags, msw_ts, lsw_ts, false);
1076 }
1077 EXPORT_SYMBOL_GPL(q6asm_run_nowait);
1078
1079 /**
1080  * q6asm_media_format_block_multi_ch_pcm() - setup pcm configuration
1081  *
1082  * @ac: audio client pointer
1083  * @stream_id: stream id
1084  * @rate: audio sample rate
1085  * @channels: number of audio channels.
1086  * @channel_map: channel map pointer
1087  * @bits_per_sample: bits per sample
1088  *
1089  * Return: Will be an negative value on error or zero on success
1090  */
1091 int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
1092                                           uint32_t stream_id,
1093                                           uint32_t rate, uint32_t channels,
1094                                           u8 channel_map[PCM_MAX_NUM_CHANNEL],
1095                                           uint16_t bits_per_sample)
1096 {
1097         struct asm_multi_channel_pcm_fmt_blk_v2 *fmt;
1098         struct apr_pkt *pkt;
1099         u8 *channel_mapping;
1100         void *p;
1101         int rc, pkt_size;
1102
1103         pkt_size = APR_HDR_SIZE + sizeof(*fmt);
1104         p = kzalloc(pkt_size, GFP_KERNEL);
1105         if (!p)
1106                 return -ENOMEM;
1107
1108         pkt = p;
1109         fmt = p + APR_HDR_SIZE;
1110
1111         q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1112
1113         pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
1114         fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
1115         fmt->num_channels = channels;
1116         fmt->bits_per_sample = bits_per_sample;
1117         fmt->sample_rate = rate;
1118         fmt->is_signed = 1;
1119
1120         channel_mapping = fmt->channel_mapping;
1121
1122         if (channel_map) {
1123                 memcpy(channel_mapping, channel_map, PCM_MAX_NUM_CHANNEL);
1124         } else {
1125                 if (q6dsp_map_channels(channel_mapping, channels)) {
1126                         dev_err(ac->dev, " map channels failed %d\n", channels);
1127                         rc = -EINVAL;
1128                         goto err;
1129                 }
1130         }
1131
1132         rc = q6asm_ac_send_cmd_sync(ac, pkt);
1133
1134 err:
1135         kfree(pkt);
1136         return rc;
1137 }
1138 EXPORT_SYMBOL_GPL(q6asm_media_format_block_multi_ch_pcm);
1139
1140 int q6asm_stream_media_format_block_flac(struct audio_client *ac,
1141                                          uint32_t stream_id,
1142                                          struct q6asm_flac_cfg *cfg)
1143 {
1144         struct asm_flac_fmt_blk_v2 *fmt;
1145         struct apr_pkt *pkt;
1146         void *p;
1147         int rc, pkt_size;
1148
1149         pkt_size = APR_HDR_SIZE + sizeof(*fmt);
1150         p = kzalloc(pkt_size, GFP_KERNEL);
1151         if (!p)
1152                 return -ENOMEM;
1153
1154         pkt = p;
1155         fmt = p + APR_HDR_SIZE;
1156
1157         q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1158
1159         pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
1160         fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
1161         fmt->is_stream_info_present = cfg->stream_info_present;
1162         fmt->num_channels = cfg->ch_cfg;
1163         fmt->min_blk_size = cfg->min_blk_size;
1164         fmt->max_blk_size = cfg->max_blk_size;
1165         fmt->sample_rate = cfg->sample_rate;
1166         fmt->min_frame_size = cfg->min_frame_size;
1167         fmt->max_frame_size = cfg->max_frame_size;
1168         fmt->sample_size = cfg->sample_size;
1169
1170         rc = q6asm_ac_send_cmd_sync(ac, pkt);
1171         kfree(pkt);
1172
1173         return rc;
1174 }
1175 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_flac);
1176
1177 int q6asm_stream_media_format_block_wma_v9(struct audio_client *ac,
1178                                            uint32_t stream_id,
1179                                            struct q6asm_wma_cfg *cfg)
1180 {
1181         struct asm_wmastdv9_fmt_blk_v2 *fmt;
1182         struct apr_pkt *pkt;
1183         void *p;
1184         int rc, pkt_size;
1185
1186         pkt_size = APR_HDR_SIZE + sizeof(*fmt);
1187         p = kzalloc(pkt_size, GFP_KERNEL);
1188         if (!p)
1189                 return -ENOMEM;
1190
1191         pkt = p;
1192         fmt = p + APR_HDR_SIZE;
1193
1194         q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1195
1196         pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
1197         fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
1198         fmt->fmtag = cfg->fmtag;
1199         fmt->num_channels = cfg->num_channels;
1200         fmt->sample_rate = cfg->sample_rate;
1201         fmt->bytes_per_sec = cfg->bytes_per_sec;
1202         fmt->blk_align = cfg->block_align;
1203         fmt->bits_per_sample = cfg->bits_per_sample;
1204         fmt->channel_mask = cfg->channel_mask;
1205         fmt->enc_options = cfg->enc_options;
1206         fmt->reserved = 0;
1207
1208         rc = q6asm_ac_send_cmd_sync(ac, pkt);
1209         kfree(pkt);
1210
1211         return rc;
1212 }
1213 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_wma_v9);
1214
1215 int q6asm_stream_media_format_block_wma_v10(struct audio_client *ac,
1216                                             uint32_t stream_id,
1217                                             struct q6asm_wma_cfg *cfg)
1218 {
1219         struct asm_wmaprov10_fmt_blk_v2 *fmt;
1220         struct apr_pkt *pkt;
1221         void *p;
1222         int rc, pkt_size;
1223
1224         pkt_size = APR_HDR_SIZE + sizeof(*fmt);
1225         p = kzalloc(pkt_size, GFP_KERNEL);
1226         if (!p)
1227                 return -ENOMEM;
1228
1229         pkt = p;
1230         fmt = p + APR_HDR_SIZE;
1231
1232         q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1233
1234         pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
1235         fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
1236         fmt->fmtag = cfg->fmtag;
1237         fmt->num_channels = cfg->num_channels;
1238         fmt->sample_rate = cfg->sample_rate;
1239         fmt->bytes_per_sec = cfg->bytes_per_sec;
1240         fmt->blk_align = cfg->block_align;
1241         fmt->bits_per_sample = cfg->bits_per_sample;
1242         fmt->channel_mask = cfg->channel_mask;
1243         fmt->enc_options = cfg->enc_options;
1244         fmt->advanced_enc_options1 = cfg->adv_enc_options;
1245         fmt->advanced_enc_options2 = cfg->adv_enc_options2;
1246
1247         rc = q6asm_ac_send_cmd_sync(ac, pkt);
1248         kfree(pkt);
1249
1250         return rc;
1251 }
1252 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_wma_v10);
1253
1254 int q6asm_stream_media_format_block_alac(struct audio_client *ac,
1255                                          uint32_t stream_id,
1256                                          struct q6asm_alac_cfg *cfg)
1257 {
1258         struct asm_alac_fmt_blk_v2 *fmt;
1259         struct apr_pkt *pkt;
1260         void *p;
1261         int rc, pkt_size;
1262
1263         pkt_size = APR_HDR_SIZE + sizeof(*fmt);
1264         p = kzalloc(pkt_size, GFP_KERNEL);
1265         if (!p)
1266                 return -ENOMEM;
1267
1268         pkt = p;
1269         fmt = p + APR_HDR_SIZE;
1270
1271         q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1272
1273         pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
1274         fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
1275
1276         fmt->frame_length = cfg->frame_length;
1277         fmt->compatible_version = cfg->compatible_version;
1278         fmt->bit_depth =  cfg->bit_depth;
1279         fmt->num_channels = cfg->num_channels;
1280         fmt->max_run = cfg->max_run;
1281         fmt->max_frame_bytes = cfg->max_frame_bytes;
1282         fmt->avg_bit_rate = cfg->avg_bit_rate;
1283         fmt->sample_rate = cfg->sample_rate;
1284         fmt->channel_layout_tag = cfg->channel_layout_tag;
1285         fmt->pb = cfg->pb;
1286         fmt->mb = cfg->mb;
1287         fmt->kb = cfg->kb;
1288
1289         rc = q6asm_ac_send_cmd_sync(ac, pkt);
1290         kfree(pkt);
1291
1292         return rc;
1293 }
1294 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_alac);
1295
1296 int q6asm_stream_media_format_block_ape(struct audio_client *ac,
1297                                         uint32_t stream_id,
1298                                         struct q6asm_ape_cfg *cfg)
1299 {
1300         struct asm_ape_fmt_blk_v2 *fmt;
1301         struct apr_pkt *pkt;
1302         void *p;
1303         int rc, pkt_size;
1304
1305         pkt_size = APR_HDR_SIZE + sizeof(*fmt);
1306         p = kzalloc(pkt_size, GFP_KERNEL);
1307         if (!p)
1308                 return -ENOMEM;
1309
1310         pkt = p;
1311         fmt = p + APR_HDR_SIZE;
1312
1313         q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1314
1315         pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
1316         fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
1317
1318         fmt->compatible_version = cfg->compatible_version;
1319         fmt->compression_level = cfg->compression_level;
1320         fmt->format_flags = cfg->format_flags;
1321         fmt->blocks_per_frame = cfg->blocks_per_frame;
1322         fmt->final_frame_blocks = cfg->final_frame_blocks;
1323         fmt->total_frames = cfg->total_frames;
1324         fmt->bits_per_sample = cfg->bits_per_sample;
1325         fmt->num_channels = cfg->num_channels;
1326         fmt->sample_rate = cfg->sample_rate;
1327         fmt->seek_table_present = cfg->seek_table_present;
1328
1329         rc = q6asm_ac_send_cmd_sync(ac, pkt);
1330         kfree(pkt);
1331
1332         return rc;
1333 }
1334 EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_ape);
1335
1336 static int q6asm_stream_remove_silence(struct audio_client *ac, uint32_t stream_id,
1337                                        uint32_t cmd,
1338                                        uint32_t num_samples)
1339 {
1340         uint32_t *samples;
1341         struct apr_pkt *pkt;
1342         void *p;
1343         int rc, pkt_size;
1344
1345         pkt_size = APR_HDR_SIZE + sizeof(uint32_t);
1346         p = kzalloc(pkt_size, GFP_ATOMIC);
1347         if (!p)
1348                 return -ENOMEM;
1349
1350         pkt = p;
1351         samples = p + APR_HDR_SIZE;
1352
1353         q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1354
1355         pkt->hdr.opcode = cmd;
1356         *samples = num_samples;
1357         rc = apr_send_pkt(ac->adev, pkt);
1358         if (rc == pkt_size)
1359                 rc = 0;
1360
1361         kfree(pkt);
1362
1363         return rc;
1364 }
1365
1366 int q6asm_stream_remove_initial_silence(struct audio_client *ac,
1367                                         uint32_t stream_id,
1368                                         uint32_t initial_samples)
1369 {
1370         return q6asm_stream_remove_silence(ac, stream_id,
1371                                            ASM_DATA_CMD_REMOVE_INITIAL_SILENCE,
1372                                            initial_samples);
1373 }
1374 EXPORT_SYMBOL_GPL(q6asm_stream_remove_initial_silence);
1375
1376 int q6asm_stream_remove_trailing_silence(struct audio_client *ac, uint32_t stream_id,
1377                                          uint32_t trailing_samples)
1378 {
1379         return q6asm_stream_remove_silence(ac, stream_id,
1380                                    ASM_DATA_CMD_REMOVE_TRAILING_SILENCE,
1381                                    trailing_samples);
1382 }
1383 EXPORT_SYMBOL_GPL(q6asm_stream_remove_trailing_silence);
1384
1385 /**
1386  * q6asm_enc_cfg_blk_pcm_format_support() - setup pcm configuration for capture
1387  *
1388  * @ac: audio client pointer
1389  * @stream_id: stream id
1390  * @rate: audio sample rate
1391  * @channels: number of audio channels.
1392  * @bits_per_sample: bits per sample
1393  *
1394  * Return: Will be an negative value on error or zero on success
1395  */
1396 int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
1397                                          uint32_t stream_id, uint32_t rate,
1398                                          uint32_t channels,
1399                                          uint16_t bits_per_sample)
1400 {
1401         struct asm_multi_channel_pcm_enc_cfg_v2  *enc_cfg;
1402         struct apr_pkt *pkt;
1403         u8 *channel_mapping;
1404         u32 frames_per_buf = 0;
1405         int pkt_size, rc;
1406         void *p;
1407
1408         pkt_size = APR_HDR_SIZE + sizeof(*enc_cfg);
1409         p = kzalloc(pkt_size, GFP_KERNEL);
1410         if (!p)
1411                 return -ENOMEM;
1412
1413         pkt = p;
1414         enc_cfg = p + APR_HDR_SIZE;
1415         q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id);
1416
1417         pkt->hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
1418         enc_cfg->encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
1419         enc_cfg->encdec.param_size = sizeof(*enc_cfg) - sizeof(enc_cfg->encdec);
1420         enc_cfg->encblk.frames_per_buf = frames_per_buf;
1421         enc_cfg->encblk.enc_cfg_blk_size  = enc_cfg->encdec.param_size -
1422                                         sizeof(struct asm_enc_cfg_blk_param_v2);
1423
1424         enc_cfg->num_channels = channels;
1425         enc_cfg->bits_per_sample = bits_per_sample;
1426         enc_cfg->sample_rate = rate;
1427         enc_cfg->is_signed = 1;
1428         channel_mapping = enc_cfg->channel_mapping;
1429
1430         if (q6dsp_map_channels(channel_mapping, channels)) {
1431                 rc = -EINVAL;
1432                 goto err;
1433         }
1434
1435         rc = q6asm_ac_send_cmd_sync(ac, pkt);
1436 err:
1437         kfree(pkt);
1438         return rc;
1439 }
1440 EXPORT_SYMBOL_GPL(q6asm_enc_cfg_blk_pcm_format_support);
1441
1442
1443 /**
1444  * q6asm_read() - read data of period size from audio client
1445  *
1446  * @ac: audio client pointer
1447  * @stream_id: stream id
1448  *
1449  * Return: Will be an negative value on error or zero on success
1450  */
1451 int q6asm_read(struct audio_client *ac, uint32_t stream_id)
1452 {
1453         struct asm_data_cmd_read_v2 *read;
1454         struct audio_port_data *port;
1455         struct audio_buffer *ab;
1456         struct apr_pkt *pkt;
1457         unsigned long flags;
1458         int pkt_size;
1459         int rc = 0;
1460         void *p;
1461
1462         pkt_size = APR_HDR_SIZE + sizeof(*read);
1463         p = kzalloc(pkt_size, GFP_ATOMIC);
1464         if (!p)
1465                 return -ENOMEM;
1466
1467         pkt = p;
1468         read = p + APR_HDR_SIZE;
1469
1470         spin_lock_irqsave(&ac->lock, flags);
1471         port = &ac->port[SNDRV_PCM_STREAM_CAPTURE];
1472         q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, stream_id);
1473         ab = &port->buf[port->dsp_buf];
1474         pkt->hdr.opcode = ASM_DATA_CMD_READ_V2;
1475         read->buf_addr_lsw = lower_32_bits(ab->phys);
1476         read->buf_addr_msw = upper_32_bits(ab->phys);
1477         read->mem_map_handle = port->mem_map_handle;
1478
1479         read->buf_size = ab->size;
1480         read->seq_id = port->dsp_buf;
1481         pkt->hdr.token = port->dsp_buf;
1482
1483         port->dsp_buf++;
1484
1485         if (port->dsp_buf >= port->num_periods)
1486                 port->dsp_buf = 0;
1487
1488         spin_unlock_irqrestore(&ac->lock, flags);
1489         rc = apr_send_pkt(ac->adev, pkt);
1490         if (rc == pkt_size)
1491                 rc = 0;
1492         else
1493                 pr_err("read op[0x%x]rc[%d]\n", pkt->hdr.opcode, rc);
1494
1495         kfree(pkt);
1496         return rc;
1497 }
1498 EXPORT_SYMBOL_GPL(q6asm_read);
1499
1500 static int __q6asm_open_read(struct audio_client *ac, uint32_t stream_id,
1501                 uint32_t format, uint16_t bits_per_sample)
1502 {
1503         struct asm_stream_cmd_open_read_v3 *open;
1504         struct apr_pkt *pkt;
1505         int pkt_size, rc;
1506         void *p;
1507
1508         pkt_size = APR_HDR_SIZE + sizeof(*open);
1509         p = kzalloc(pkt_size, GFP_KERNEL);
1510         if (!p)
1511                 return -ENOMEM;
1512
1513         pkt = p;
1514         open = p + APR_HDR_SIZE;
1515
1516         q6asm_add_hdr(ac, &pkt->hdr,  pkt_size, true, stream_id);
1517         pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V3;
1518         /* Stream prio : High, provide meta info with encoded frames */
1519         open->src_endpointype = ASM_END_POINT_DEVICE_MATRIX;
1520
1521         open->preprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE;
1522         open->bits_per_sample = bits_per_sample;
1523         open->mode_flags = 0x0;
1524
1525         open->mode_flags |= ASM_LEGACY_STREAM_SESSION <<
1526                                 ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
1527
1528         switch (format) {
1529         case FORMAT_LINEAR_PCM:
1530                 open->mode_flags |= 0x00;
1531                 open->enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
1532                 break;
1533         default:
1534                 pr_err("Invalid format[%d]\n", format);
1535         }
1536
1537         rc = q6asm_ac_send_cmd_sync(ac, pkt);
1538
1539         kfree(pkt);
1540         return rc;
1541 }
1542
1543 /**
1544  * q6asm_open_read() - Open audio client for reading
1545  *
1546  * @ac: audio client pointer
1547  * @stream_id: stream id
1548  * @format: audio sample format
1549  * @bits_per_sample: bits per sample
1550  *
1551  * Return: Will be an negative value on error or zero on success
1552  */
1553 int q6asm_open_read(struct audio_client *ac, uint32_t stream_id,
1554                     uint32_t format, uint16_t bits_per_sample)
1555 {
1556         return __q6asm_open_read(ac, stream_id, format, bits_per_sample);
1557 }
1558 EXPORT_SYMBOL_GPL(q6asm_open_read);
1559
1560 /**
1561  * q6asm_write_async() - non blocking write
1562  *
1563  * @ac: audio client pointer
1564  * @stream_id: stream id
1565  * @len: length in bytes
1566  * @msw_ts: timestamp msw
1567  * @lsw_ts: timestamp lsw
1568  * @wflags: flags associated with write
1569  *
1570  * Return: Will be an negative value on error or zero on success
1571  */
1572 int q6asm_write_async(struct audio_client *ac, uint32_t stream_id, uint32_t len,
1573                       uint32_t msw_ts, uint32_t lsw_ts, uint32_t wflags)
1574 {
1575         struct asm_data_cmd_write_v2 *write;
1576         struct audio_port_data *port;
1577         struct audio_buffer *ab;
1578         unsigned long flags;
1579         struct apr_pkt *pkt;
1580         int pkt_size;
1581         int rc = 0;
1582         void *p;
1583
1584         pkt_size = APR_HDR_SIZE + sizeof(*write);
1585         p = kzalloc(pkt_size, GFP_ATOMIC);
1586         if (!p)
1587                 return -ENOMEM;
1588
1589         pkt = p;
1590         write = p + APR_HDR_SIZE;
1591
1592         spin_lock_irqsave(&ac->lock, flags);
1593         port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
1594         q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, stream_id);
1595
1596         ab = &port->buf[port->dsp_buf];
1597         pkt->hdr.token = port->dsp_buf | (len << ASM_WRITE_TOKEN_LEN_SHIFT);
1598         pkt->hdr.opcode = ASM_DATA_CMD_WRITE_V2;
1599         write->buf_addr_lsw = lower_32_bits(ab->phys);
1600         write->buf_addr_msw = upper_32_bits(ab->phys);
1601         write->buf_size = len;
1602         write->seq_id = port->dsp_buf;
1603         write->timestamp_lsw = lsw_ts;
1604         write->timestamp_msw = msw_ts;
1605         write->mem_map_handle =
1606             ac->port[SNDRV_PCM_STREAM_PLAYBACK].mem_map_handle;
1607
1608         write->flags = wflags;
1609
1610         port->dsp_buf++;
1611
1612         if (port->dsp_buf >= port->num_periods)
1613                 port->dsp_buf = 0;
1614
1615         spin_unlock_irqrestore(&ac->lock, flags);
1616         rc = apr_send_pkt(ac->adev, pkt);
1617         if (rc == pkt_size)
1618                 rc = 0;
1619
1620         kfree(pkt);
1621         return rc;
1622 }
1623 EXPORT_SYMBOL_GPL(q6asm_write_async);
1624
1625 static void q6asm_reset_buf_state(struct audio_client *ac)
1626 {
1627         struct audio_port_data *port = NULL;
1628         unsigned long flags;
1629
1630         spin_lock_irqsave(&ac->lock, flags);
1631         port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
1632         port->dsp_buf = 0;
1633         port = &ac->port[SNDRV_PCM_STREAM_CAPTURE];
1634         port->dsp_buf = 0;
1635         spin_unlock_irqrestore(&ac->lock, flags);
1636 }
1637
1638 static int __q6asm_cmd(struct audio_client *ac, uint32_t stream_id, int cmd,
1639                        bool wait)
1640 {
1641         struct apr_pkt pkt;
1642         int rc;
1643
1644         q6asm_add_hdr(ac, &pkt.hdr, APR_HDR_SIZE, true, stream_id);
1645
1646         switch (cmd) {
1647         case CMD_PAUSE:
1648                 pkt.hdr.opcode = ASM_SESSION_CMD_PAUSE;
1649                 break;
1650         case CMD_SUSPEND:
1651                 pkt.hdr.opcode = ASM_SESSION_CMD_SUSPEND;
1652                 break;
1653         case CMD_FLUSH:
1654                 pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH;
1655                 break;
1656         case CMD_OUT_FLUSH:
1657                 pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH_READBUFS;
1658                 break;
1659         case CMD_EOS:
1660                 pkt.hdr.opcode = ASM_DATA_CMD_EOS;
1661                 break;
1662         case CMD_CLOSE:
1663                 pkt.hdr.opcode = ASM_STREAM_CMD_CLOSE;
1664                 break;
1665         default:
1666                 return -EINVAL;
1667         }
1668
1669         if (wait)
1670                 rc = q6asm_ac_send_cmd_sync(ac, &pkt);
1671         else
1672                 return apr_send_pkt(ac->adev, &pkt);
1673
1674         if (rc < 0)
1675                 return rc;
1676
1677         if (cmd == CMD_FLUSH)
1678                 q6asm_reset_buf_state(ac);
1679
1680         return 0;
1681 }
1682
1683 /**
1684  * q6asm_cmd() - run cmd on audio client
1685  *
1686  * @ac: audio client pointer
1687  * @stream_id: stream id
1688  * @cmd: command to run on audio client.
1689  *
1690  * Return: Will be an negative value on error or zero on success
1691  */
1692 int q6asm_cmd(struct audio_client *ac, uint32_t stream_id, int cmd)
1693 {
1694         return __q6asm_cmd(ac, stream_id, cmd, true);
1695 }
1696 EXPORT_SYMBOL_GPL(q6asm_cmd);
1697
1698 /**
1699  * q6asm_cmd_nowait() - non blocking, run cmd on audio client
1700  *
1701  * @ac: audio client pointer
1702  * @stream_id: stream id
1703  * @cmd: command to run on audio client.
1704  *
1705  * Return: Will be an negative value on error or zero on success
1706  */
1707 int q6asm_cmd_nowait(struct audio_client *ac, uint32_t stream_id, int cmd)
1708 {
1709         return __q6asm_cmd(ac, stream_id, cmd, false);
1710 }
1711 EXPORT_SYMBOL_GPL(q6asm_cmd_nowait);
1712
1713 static int q6asm_probe(struct apr_device *adev)
1714 {
1715         struct device *dev = &adev->dev;
1716         struct q6asm *q6asm;
1717
1718         q6asm = devm_kzalloc(dev, sizeof(*q6asm), GFP_KERNEL);
1719         if (!q6asm)
1720                 return -ENOMEM;
1721
1722         q6core_get_svc_api_info(adev->svc_id, &q6asm->ainfo);
1723
1724         q6asm->dev = dev;
1725         q6asm->adev = adev;
1726         init_waitqueue_head(&q6asm->mem_wait);
1727         spin_lock_init(&q6asm->slock);
1728         dev_set_drvdata(dev, q6asm);
1729
1730         return of_platform_populate(dev->of_node, NULL, NULL, dev);
1731 }
1732
1733 static int q6asm_remove(struct apr_device *adev)
1734 {
1735         of_platform_depopulate(&adev->dev);
1736
1737         return 0;
1738 }
1739
1740 #ifdef CONFIG_OF
1741 static const struct of_device_id q6asm_device_id[]  = {
1742         { .compatible = "qcom,q6asm" },
1743         {},
1744 };
1745 MODULE_DEVICE_TABLE(of, q6asm_device_id);
1746 #endif
1747
1748 static struct apr_driver qcom_q6asm_driver = {
1749         .probe = q6asm_probe,
1750         .remove = q6asm_remove,
1751         .callback = q6asm_srvc_callback,
1752         .driver = {
1753                 .name = "qcom-q6asm",
1754                 .of_match_table = of_match_ptr(q6asm_device_id),
1755         },
1756 };
1757
1758 module_apr_driver(qcom_q6asm_driver);
1759 MODULE_DESCRIPTION("Q6 Audio Stream Manager driver");
1760 MODULE_LICENSE("GPL v2");