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