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