1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
3 // Copyright (c) 2018, Linaro Limited
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>
14 #include <linux/of_platform.h>
15 #include <uapi/sound/asound.h>
16 #include <linux/delay.h>
17 #include <linux/slab.h>
21 #include "q6dsp-errno.h"
22 #include "q6dsp-common.h"
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_NULL_POPP_TOPOLOGY 0x00010C68
29 #define ASM_STREAM_CMD_FLUSH_READBUFS 0x00010C09
30 #define ASM_STREAM_CMD_SET_ENCDEC_PARAM 0x00010C10
31 #define ASM_STREAM_POSTPROC_TOPO_ID_NONE 0x00010C68
32 #define ASM_CMD_SHARED_MEM_MAP_REGIONS 0x00010D92
33 #define ASM_CMDRSP_SHARED_MEM_MAP_REGIONS 0x00010D93
34 #define ASM_CMD_SHARED_MEM_UNMAP_REGIONS 0x00010D94
35 #define ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2 0x00010D98
36 #define ASM_DATA_EVENT_WRITE_DONE_V2 0x00010D99
37 #define ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2 0x00010DA3
38 #define ASM_SESSION_CMD_RUN_V2 0x00010DAA
39 #define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2 0x00010DA5
40 #define ASM_DATA_CMD_WRITE_V2 0x00010DAB
41 #define ASM_DATA_CMD_READ_V2 0x00010DAC
42 #define ASM_SESSION_CMD_SUSPEND 0x00010DEC
43 #define ASM_STREAM_CMD_OPEN_WRITE_V3 0x00010DB3
44 #define ASM_STREAM_CMD_OPEN_READ_V3 0x00010DB4
45 #define ASM_DATA_EVENT_READ_DONE_V2 0x00010D9A
46 #define ASM_STREAM_CMD_OPEN_READWRITE_V2 0x00010D8D
49 #define ASM_LEGACY_STREAM_SESSION 0
50 /* Bit shift for the stream_perf_mode subfield. */
51 #define ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ 29
52 #define ASM_END_POINT_DEVICE_MATRIX 0
53 #define ASM_DEFAULT_APP_TYPE 0
54 #define ASM_SYNC_IO_MODE 0x0001
55 #define ASM_ASYNC_IO_MODE 0x0002
56 #define ASM_TUN_READ_IO_MODE 0x0004 /* tunnel read write mode */
57 #define ASM_TUN_WRITE_IO_MODE 0x0008 /* tunnel read write mode */
58 #define ASM_SHIFT_GAPLESS_MODE_FLAG 31
59 #define ADSP_MEMORY_MAP_SHMEM8_4K_POOL 3
61 struct avs_cmd_shared_mem_map_regions
{
67 struct avs_shared_map_region_payload
{
73 struct avs_cmd_shared_mem_unmap_regions
{
77 struct asm_data_cmd_media_fmt_update_v2
{
81 struct asm_multi_channel_pcm_fmt_blk_v2
{
82 struct asm_data_cmd_media_fmt_update_v2 fmt_blk
;
88 u8 channel_mapping
[PCM_MAX_NUM_CHANNEL
];
91 struct asm_stream_cmd_set_encdec_param
{
96 struct asm_enc_cfg_blk_param_v2
{
101 struct asm_multi_channel_pcm_enc_cfg_v2
{
102 struct asm_stream_cmd_set_encdec_param encdec
;
103 struct asm_enc_cfg_blk_param_v2 encblk
;
104 uint16_t num_channels
;
105 uint16_t bits_per_sample
;
106 uint32_t sample_rate
;
109 uint8_t channel_mapping
[8];
112 struct asm_data_cmd_read_v2
{
120 struct asm_data_cmd_read_v2_done
{
126 struct asm_stream_cmd_open_read_v3
{
135 struct asm_data_cmd_write_v2
{
146 struct asm_stream_cmd_open_write_v3
{
148 uint16_t sink_endpointype
;
149 uint16_t bits_per_sample
;
150 uint32_t postprocopo_id
;
154 struct asm_session_cmd_run_v2
{
160 struct audio_buffer
{
162 uint32_t size
; /* size of buffer */
165 struct audio_port_data
{
166 struct audio_buffer
*buf
;
167 uint32_t num_periods
;
169 uint32_t mem_map_handle
;
173 struct apr_device
*adev
;
175 struct q6core_svc_api_info ainfo
;
176 wait_queue_head_t mem_wait
;
178 struct audio_client
*session
[MAX_SESSIONS
+ 1];
181 struct audio_client
{
186 struct apr_device
*adev
;
187 struct mutex cmd_lock
;
189 struct kref refcount
;
190 /* idx:1 out port, 0: in port */
191 struct audio_port_data port
[2];
192 wait_queue_head_t cmd_wait
;
193 struct aprv2_ibasic_rsp_result_t result
;
200 static inline void q6asm_add_hdr(struct audio_client
*ac
, struct apr_hdr
*hdr
,
201 uint32_t pkt_size
, bool cmd_flg
,
204 hdr
->hdr_field
= APR_SEQ_CMD_HDR_FIELD
;
205 hdr
->src_port
= ((ac
->session
<< 8) & 0xFF00) | (stream_id
);
206 hdr
->dest_port
= ((ac
->session
<< 8) & 0xFF00) | (stream_id
);
207 hdr
->pkt_size
= pkt_size
;
209 hdr
->token
= ac
->session
;
212 static int q6asm_apr_send_session_pkt(struct q6asm
*a
, struct audio_client
*ac
,
213 struct apr_pkt
*pkt
, uint32_t rsp_opcode
)
215 struct apr_hdr
*hdr
= &pkt
->hdr
;
218 mutex_lock(&ac
->cmd_lock
);
219 ac
->result
.opcode
= 0;
220 ac
->result
.status
= 0;
221 rc
= apr_send_pkt(a
->adev
, pkt
);
226 rc
= wait_event_timeout(a
->mem_wait
,
227 (ac
->result
.opcode
== hdr
->opcode
) ||
228 (ac
->result
.opcode
== rsp_opcode
),
231 rc
= wait_event_timeout(a
->mem_wait
,
232 (ac
->result
.opcode
== hdr
->opcode
),
236 dev_err(a
->dev
, "CMD timeout\n");
238 } else if (ac
->result
.status
> 0) {
239 dev_err(a
->dev
, "DSP returned error[%x]\n",
245 mutex_unlock(&ac
->cmd_lock
);
249 static int __q6asm_memory_unmap(struct audio_client
*ac
,
250 phys_addr_t buf_add
, int dir
)
252 struct avs_cmd_shared_mem_unmap_regions
*mem_unmap
;
253 struct q6asm
*a
= dev_get_drvdata(ac
->dev
->parent
);
258 if (ac
->port
[dir
].mem_map_handle
== 0) {
259 dev_err(ac
->dev
, "invalid mem handle\n");
263 pkt_size
= APR_HDR_SIZE
+ sizeof(*mem_unmap
);
264 p
= kzalloc(pkt_size
, GFP_KERNEL
);
269 mem_unmap
= p
+ APR_HDR_SIZE
;
271 pkt
->hdr
.hdr_field
= APR_SEQ_CMD_HDR_FIELD
;
272 pkt
->hdr
.src_port
= 0;
273 pkt
->hdr
.dest_port
= 0;
274 pkt
->hdr
.pkt_size
= pkt_size
;
275 pkt
->hdr
.token
= ((ac
->session
<< 8) | dir
);
277 pkt
->hdr
.opcode
= ASM_CMD_SHARED_MEM_UNMAP_REGIONS
;
278 mem_unmap
->mem_map_handle
= ac
->port
[dir
].mem_map_handle
;
280 rc
= q6asm_apr_send_session_pkt(a
, ac
, pkt
, 0);
286 ac
->port
[dir
].mem_map_handle
= 0;
293 static void q6asm_audio_client_free_buf(struct audio_client
*ac
,
294 struct audio_port_data
*port
)
298 spin_lock_irqsave(&ac
->lock
, flags
);
299 port
->num_periods
= 0;
302 spin_unlock_irqrestore(&ac
->lock
, flags
);
306 * q6asm_unmap_memory_regions() - unmap memory regions in the dsp.
308 * @dir: direction of audio stream
309 * @ac: audio client instanace
311 * Return: Will be an negative value on failure or zero on success
313 int q6asm_unmap_memory_regions(unsigned int dir
, struct audio_client
*ac
)
315 struct audio_port_data
*port
;
319 port
= &ac
->port
[dir
];
325 cnt
= port
->num_periods
- 1;
327 rc
= __q6asm_memory_unmap(ac
, port
->buf
[dir
].phys
, dir
);
329 dev_err(ac
->dev
, "%s: Memory_unmap_regions failed %d\n",
335 q6asm_audio_client_free_buf(ac
, port
);
340 EXPORT_SYMBOL_GPL(q6asm_unmap_memory_regions
);
342 static int __q6asm_memory_map_regions(struct audio_client
*ac
, int dir
,
343 size_t period_sz
, unsigned int periods
,
346 struct avs_cmd_shared_mem_map_regions
*cmd
= NULL
;
347 struct avs_shared_map_region_payload
*mregions
= NULL
;
348 struct q6asm
*a
= dev_get_drvdata(ac
->dev
->parent
);
349 struct audio_port_data
*port
= NULL
;
350 struct audio_buffer
*ab
= NULL
;
354 uint32_t num_regions
, buf_sz
;
359 buf_sz
= period_sz
* periods
;
362 num_regions
= periods
;
365 /* DSP expects size should be aligned to 4K */
366 buf_sz
= ALIGN(buf_sz
, 4096);
368 pkt_size
= APR_HDR_SIZE
+ sizeof(*cmd
) +
369 (sizeof(*mregions
) * num_regions
);
371 p
= kzalloc(pkt_size
, GFP_KERNEL
);
376 cmd
= p
+ APR_HDR_SIZE
;
377 mregions
= p
+ APR_HDR_SIZE
+ sizeof(*cmd
);
379 pkt
->hdr
.hdr_field
= APR_SEQ_CMD_HDR_FIELD
;
380 pkt
->hdr
.src_port
= 0;
381 pkt
->hdr
.dest_port
= 0;
382 pkt
->hdr
.pkt_size
= pkt_size
;
383 pkt
->hdr
.token
= ((ac
->session
<< 8) | dir
);
384 pkt
->hdr
.opcode
= ASM_CMD_SHARED_MEM_MAP_REGIONS
;
386 cmd
->mem_pool_id
= ADSP_MEMORY_MAP_SHMEM8_4K_POOL
;
387 cmd
->num_regions
= num_regions
;
388 cmd
->property_flag
= 0x00;
390 spin_lock_irqsave(&ac
->lock
, flags
);
391 port
= &ac
->port
[dir
];
393 for (i
= 0; i
< num_regions
; i
++) {
395 mregions
->shm_addr_lsw
= lower_32_bits(ab
->phys
);
396 mregions
->shm_addr_msw
= upper_32_bits(ab
->phys
);
397 mregions
->mem_size_bytes
= buf_sz
;
400 spin_unlock_irqrestore(&ac
->lock
, flags
);
402 rc
= q6asm_apr_send_session_pkt(a
, ac
, pkt
,
403 ASM_CMDRSP_SHARED_MEM_MAP_REGIONS
);
411 * q6asm_map_memory_regions() - map memory regions in the dsp.
413 * @dir: direction of audio stream
414 * @ac: audio client instanace
415 * @phys: physcial address that needs mapping.
416 * @period_sz: audio period size
417 * @periods: number of periods
419 * Return: Will be an negative value on failure or zero on success
421 int q6asm_map_memory_regions(unsigned int dir
, struct audio_client
*ac
,
423 size_t period_sz
, unsigned int periods
)
425 struct audio_buffer
*buf
;
430 spin_lock_irqsave(&ac
->lock
, flags
);
431 if (ac
->port
[dir
].buf
) {
432 dev_err(ac
->dev
, "Buffer already allocated\n");
433 spin_unlock_irqrestore(&ac
->lock
, flags
);
437 buf
= kzalloc(((sizeof(struct audio_buffer
)) * periods
), GFP_ATOMIC
);
439 spin_unlock_irqrestore(&ac
->lock
, flags
);
444 ac
->port
[dir
].buf
= buf
;
447 buf
[0].size
= period_sz
;
449 for (cnt
= 1; cnt
< periods
; cnt
++) {
451 buf
[cnt
].phys
= buf
[0].phys
+ (cnt
* period_sz
);
452 buf
[cnt
].size
= period_sz
;
455 ac
->port
[dir
].num_periods
= periods
;
457 spin_unlock_irqrestore(&ac
->lock
, flags
);
459 rc
= __q6asm_memory_map_regions(ac
, dir
, period_sz
, periods
, 1);
461 dev_err(ac
->dev
, "Memory_map_regions failed\n");
462 q6asm_audio_client_free_buf(ac
, &ac
->port
[dir
]);
467 EXPORT_SYMBOL_GPL(q6asm_map_memory_regions
);
469 static void q6asm_audio_client_release(struct kref
*ref
)
471 struct audio_client
*ac
;
475 ac
= container_of(ref
, struct audio_client
, refcount
);
478 spin_lock_irqsave(&a
->slock
, flags
);
479 a
->session
[ac
->session
] = NULL
;
480 spin_unlock_irqrestore(&a
->slock
, flags
);
486 * q6asm_audio_client_free() - Freee allocated audio client
488 * @ac: audio client to free
490 void q6asm_audio_client_free(struct audio_client
*ac
)
492 kref_put(&ac
->refcount
, q6asm_audio_client_release
);
494 EXPORT_SYMBOL_GPL(q6asm_audio_client_free
);
496 static struct audio_client
*q6asm_get_audio_client(struct q6asm
*a
,
499 struct audio_client
*ac
= NULL
;
502 spin_lock_irqsave(&a
->slock
, flags
);
503 if ((session_id
<= 0) || (session_id
> MAX_SESSIONS
)) {
504 dev_err(a
->dev
, "invalid session: %d\n", session_id
);
508 /* check for valid session */
509 if (!a
->session
[session_id
])
511 else if (a
->session
[session_id
]->session
!= session_id
)
514 ac
= a
->session
[session_id
];
515 kref_get(&ac
->refcount
);
517 spin_unlock_irqrestore(&a
->slock
, flags
);
521 static int32_t q6asm_stream_callback(struct apr_device
*adev
,
522 struct apr_resp_pkt
*data
,
525 struct q6asm
*q6asm
= dev_get_drvdata(&adev
->dev
);
526 struct aprv2_ibasic_rsp_result_t
*result
;
527 struct apr_hdr
*hdr
= &data
->hdr
;
528 struct audio_port_data
*port
;
529 struct audio_client
*ac
;
530 uint32_t client_event
= 0;
533 ac
= q6asm_get_audio_client(q6asm
, session_id
);
534 if (!ac
)/* Audio client might already be freed by now */
537 result
= data
->payload
;
539 switch (hdr
->opcode
) {
540 case APR_BASIC_RSP_RESULT
:
541 switch (result
->opcode
) {
542 case ASM_SESSION_CMD_PAUSE
:
543 client_event
= ASM_CLIENT_EVENT_CMD_PAUSE_DONE
;
545 case ASM_SESSION_CMD_SUSPEND
:
546 client_event
= ASM_CLIENT_EVENT_CMD_SUSPEND_DONE
;
548 case ASM_DATA_CMD_EOS
:
549 client_event
= ASM_CLIENT_EVENT_CMD_EOS_DONE
;
551 case ASM_STREAM_CMD_FLUSH
:
552 client_event
= ASM_CLIENT_EVENT_CMD_FLUSH_DONE
;
554 case ASM_SESSION_CMD_RUN_V2
:
555 client_event
= ASM_CLIENT_EVENT_CMD_RUN_DONE
;
557 case ASM_STREAM_CMD_CLOSE
:
558 client_event
= ASM_CLIENT_EVENT_CMD_CLOSE_DONE
;
560 case ASM_STREAM_CMD_FLUSH_READBUFS
:
561 client_event
= ASM_CLIENT_EVENT_CMD_OUT_FLUSH_DONE
;
563 case ASM_STREAM_CMD_OPEN_WRITE_V3
:
564 case ASM_STREAM_CMD_OPEN_READ_V3
:
565 case ASM_STREAM_CMD_OPEN_READWRITE_V2
:
566 case ASM_STREAM_CMD_SET_ENCDEC_PARAM
:
567 case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2
:
568 if (result
->status
!= 0) {
570 "cmd = 0x%x returned error = 0x%x\n",
571 result
->opcode
, result
->status
);
572 ac
->result
= *result
;
573 wake_up(&ac
->cmd_wait
);
579 dev_err(ac
->dev
, "command[0x%x] not expecting rsp\n",
584 ac
->result
= *result
;
585 wake_up(&ac
->cmd_wait
);
588 ac
->cb(client_event
, hdr
->token
,
589 data
->payload
, ac
->priv
);
594 case ASM_DATA_EVENT_WRITE_DONE_V2
:
595 client_event
= ASM_CLIENT_EVENT_DATA_WRITE_DONE
;
596 if (ac
->io_mode
& ASM_SYNC_IO_MODE
) {
600 spin_lock_irqsave(&ac
->lock
, flags
);
602 port
= &ac
->port
[SNDRV_PCM_STREAM_PLAYBACK
];
605 spin_unlock_irqrestore(&ac
->lock
, flags
);
610 phys
= port
->buf
[hdr
->token
].phys
;
612 if (lower_32_bits(phys
) != result
->opcode
||
613 upper_32_bits(phys
) != result
->status
) {
614 dev_err(ac
->dev
, "Expected addr %pa\n",
615 &port
->buf
[hdr
->token
].phys
);
616 spin_unlock_irqrestore(&ac
->lock
, flags
);
620 spin_unlock_irqrestore(&ac
->lock
, flags
);
623 case ASM_DATA_EVENT_READ_DONE_V2
:
624 client_event
= ASM_CLIENT_EVENT_DATA_READ_DONE
;
625 if (ac
->io_mode
& ASM_SYNC_IO_MODE
) {
626 struct asm_data_cmd_read_v2_done
*done
= data
->payload
;
630 spin_lock_irqsave(&ac
->lock
, flags
);
631 port
= &ac
->port
[SNDRV_PCM_STREAM_CAPTURE
];
633 spin_unlock_irqrestore(&ac
->lock
, flags
);
638 phys
= port
->buf
[hdr
->token
].phys
;
640 if (upper_32_bits(phys
) != done
->buf_addr_msw
||
641 lower_32_bits(phys
) != done
->buf_addr_lsw
) {
642 dev_err(ac
->dev
, "Expected addr %pa %08x-%08x\n",
643 &port
->buf
[hdr
->token
].phys
,
646 spin_unlock_irqrestore(&ac
->lock
, flags
);
650 spin_unlock_irqrestore(&ac
->lock
, flags
);
657 ac
->cb(client_event
, hdr
->token
, data
->payload
, ac
->priv
);
660 kref_put(&ac
->refcount
, q6asm_audio_client_release
);
664 static int q6asm_srvc_callback(struct apr_device
*adev
,
665 struct apr_resp_pkt
*data
)
667 struct q6asm
*q6asm
= dev_get_drvdata(&adev
->dev
);
668 struct aprv2_ibasic_rsp_result_t
*result
;
669 struct audio_port_data
*port
;
670 struct audio_client
*ac
= NULL
;
671 struct apr_hdr
*hdr
= &data
->hdr
;
677 session_id
= (hdr
->dest_port
>> 8) & 0xFF;
679 return q6asm_stream_callback(adev
, data
, session_id
);
681 sid
= (hdr
->token
>> 8) & 0x0F;
682 ac
= q6asm_get_audio_client(q6asm
, sid
);
684 dev_err(&adev
->dev
, "Audio Client not active\n");
688 a
= dev_get_drvdata(ac
->dev
->parent
);
689 dir
= (hdr
->token
& 0x0F);
690 port
= &ac
->port
[dir
];
691 result
= data
->payload
;
693 switch (hdr
->opcode
) {
694 case APR_BASIC_RSP_RESULT
:
695 switch (result
->opcode
) {
696 case ASM_CMD_SHARED_MEM_MAP_REGIONS
:
697 case ASM_CMD_SHARED_MEM_UNMAP_REGIONS
:
698 ac
->result
= *result
;
699 wake_up(&a
->mem_wait
);
702 dev_err(&adev
->dev
, "command[0x%x] not expecting rsp\n",
707 case ASM_CMDRSP_SHARED_MEM_MAP_REGIONS
:
708 ac
->result
.status
= 0;
709 ac
->result
.opcode
= hdr
->opcode
;
710 port
->mem_map_handle
= result
->opcode
;
711 wake_up(&a
->mem_wait
);
713 case ASM_CMD_SHARED_MEM_UNMAP_REGIONS
:
714 ac
->result
.opcode
= hdr
->opcode
;
715 ac
->result
.status
= 0;
716 port
->mem_map_handle
= 0;
717 wake_up(&a
->mem_wait
);
720 dev_dbg(&adev
->dev
, "command[0x%x]success [0x%x]\n",
721 result
->opcode
, result
->status
);
726 ac
->cb(hdr
->opcode
, hdr
->token
, data
->payload
, ac
->priv
);
729 kref_put(&ac
->refcount
, q6asm_audio_client_release
);
735 * q6asm_get_session_id() - get session id for audio client
737 * @c: audio client pointer
739 * Return: Will be an session id of the audio client.
741 int q6asm_get_session_id(struct audio_client
*c
)
745 EXPORT_SYMBOL_GPL(q6asm_get_session_id
);
748 * q6asm_audio_client_alloc() - Allocate a new audio client
750 * @dev: Pointer to asm child device.
751 * @cb: event callback.
752 * @priv: private data associated with this client.
753 * @stream_id: stream id
754 * @perf_mode: performace mode for this client
756 * Return: Will be an error pointer on error or a valid audio client
759 struct audio_client
*q6asm_audio_client_alloc(struct device
*dev
, q6asm_cb cb
,
760 void *priv
, int stream_id
,
763 struct q6asm
*a
= dev_get_drvdata(dev
->parent
);
764 struct audio_client
*ac
;
767 ac
= q6asm_get_audio_client(a
, stream_id
+ 1);
769 dev_err(dev
, "Audio Client already active\n");
773 ac
= kzalloc(sizeof(*ac
), GFP_KERNEL
);
775 return ERR_PTR(-ENOMEM
);
777 spin_lock_irqsave(&a
->slock
, flags
);
778 a
->session
[stream_id
+ 1] = ac
;
779 spin_unlock_irqrestore(&a
->slock
, flags
);
780 ac
->session
= stream_id
+ 1;
785 ac
->io_mode
= ASM_SYNC_IO_MODE
;
786 ac
->perf_mode
= perf_mode
;
787 /* DSP expects stream id from 1 */
790 kref_init(&ac
->refcount
);
792 init_waitqueue_head(&ac
->cmd_wait
);
793 mutex_init(&ac
->cmd_lock
);
794 spin_lock_init(&ac
->lock
);
798 EXPORT_SYMBOL_GPL(q6asm_audio_client_alloc
);
800 static int q6asm_ac_send_cmd_sync(struct audio_client
*ac
, struct apr_pkt
*pkt
)
802 struct apr_hdr
*hdr
= &pkt
->hdr
;
805 mutex_lock(&ac
->cmd_lock
);
806 ac
->result
.opcode
= 0;
807 ac
->result
.status
= 0;
809 rc
= apr_send_pkt(ac
->adev
, pkt
);
813 rc
= wait_event_timeout(ac
->cmd_wait
,
814 (ac
->result
.opcode
== hdr
->opcode
), 5 * HZ
);
816 dev_err(ac
->dev
, "CMD timeout\n");
821 if (ac
->result
.status
> 0) {
822 dev_err(ac
->dev
, "DSP returned error[%x]\n",
831 mutex_unlock(&ac
->cmd_lock
);
836 * q6asm_open_write() - Open audio client for writing
838 * @ac: audio client pointer
839 * @format: audio sample format
840 * @bits_per_sample: bits per sample
842 * Return: Will be an negative value on error or zero on success
844 int q6asm_open_write(struct audio_client
*ac
, uint32_t format
,
845 uint16_t bits_per_sample
)
847 struct asm_stream_cmd_open_write_v3
*open
;
852 pkt_size
= APR_HDR_SIZE
+ sizeof(*open
);
854 p
= kzalloc(pkt_size
, GFP_KERNEL
);
859 open
= p
+ APR_HDR_SIZE
;
860 q6asm_add_hdr(ac
, &pkt
->hdr
, pkt_size
, true, ac
->stream_id
);
862 pkt
->hdr
.opcode
= ASM_STREAM_CMD_OPEN_WRITE_V3
;
863 open
->mode_flags
= 0x00;
864 open
->mode_flags
|= ASM_LEGACY_STREAM_SESSION
;
866 /* source endpoint : matrix */
867 open
->sink_endpointype
= ASM_END_POINT_DEVICE_MATRIX
;
868 open
->bits_per_sample
= bits_per_sample
;
869 open
->postprocopo_id
= ASM_NULL_POPP_TOPOLOGY
;
872 case FORMAT_LINEAR_PCM
:
873 open
->dec_fmt_id
= ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2
;
876 dev_err(ac
->dev
, "Invalid format 0x%x\n", format
);
881 rc
= q6asm_ac_send_cmd_sync(ac
, pkt
);
885 ac
->io_mode
|= ASM_TUN_WRITE_IO_MODE
;
891 EXPORT_SYMBOL_GPL(q6asm_open_write
);
893 static int __q6asm_run(struct audio_client
*ac
, uint32_t flags
,
894 uint32_t msw_ts
, uint32_t lsw_ts
, bool wait
)
896 struct asm_session_cmd_run_v2
*run
;
901 pkt_size
= APR_HDR_SIZE
+ sizeof(*run
);
902 p
= kzalloc(pkt_size
, GFP_ATOMIC
);
907 run
= p
+ APR_HDR_SIZE
;
909 q6asm_add_hdr(ac
, &pkt
->hdr
, pkt_size
, true, ac
->stream_id
);
911 pkt
->hdr
.opcode
= ASM_SESSION_CMD_RUN_V2
;
913 run
->time_lsw
= lsw_ts
;
914 run
->time_msw
= msw_ts
;
916 rc
= q6asm_ac_send_cmd_sync(ac
, pkt
);
918 rc
= apr_send_pkt(ac
->adev
, pkt
);
928 * q6asm_run() - start the audio client
930 * @ac: audio client pointer
931 * @flags: flags associated with write
932 * @msw_ts: timestamp msw
933 * @lsw_ts: timestamp lsw
935 * Return: Will be an negative value on error or zero on success
937 int q6asm_run(struct audio_client
*ac
, uint32_t flags
,
938 uint32_t msw_ts
, uint32_t lsw_ts
)
940 return __q6asm_run(ac
, flags
, msw_ts
, lsw_ts
, true);
942 EXPORT_SYMBOL_GPL(q6asm_run
);
945 * q6asm_run_nowait() - start the audio client withou blocking
947 * @ac: audio client pointer
948 * @flags: flags associated with write
949 * @msw_ts: timestamp msw
950 * @lsw_ts: timestamp lsw
952 * Return: Will be an negative value on error or zero on success
954 int q6asm_run_nowait(struct audio_client
*ac
, uint32_t flags
,
955 uint32_t msw_ts
, uint32_t lsw_ts
)
957 return __q6asm_run(ac
, flags
, msw_ts
, lsw_ts
, false);
959 EXPORT_SYMBOL_GPL(q6asm_run_nowait
);
962 * q6asm_media_format_block_multi_ch_pcm() - setup pcm configuration
964 * @ac: audio client pointer
965 * @rate: audio sample rate
966 * @channels: number of audio channels.
967 * @channel_map: channel map pointer
968 * @bits_per_sample: bits per sample
970 * Return: Will be an negative value on error or zero on success
972 int q6asm_media_format_block_multi_ch_pcm(struct audio_client
*ac
,
973 uint32_t rate
, uint32_t channels
,
974 u8 channel_map
[PCM_MAX_NUM_CHANNEL
],
975 uint16_t bits_per_sample
)
977 struct asm_multi_channel_pcm_fmt_blk_v2
*fmt
;
983 pkt_size
= APR_HDR_SIZE
+ sizeof(*fmt
);
984 p
= kzalloc(pkt_size
, GFP_KERNEL
);
989 fmt
= p
+ APR_HDR_SIZE
;
991 q6asm_add_hdr(ac
, &pkt
->hdr
, pkt_size
, true, ac
->stream_id
);
993 pkt
->hdr
.opcode
= ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2
;
994 fmt
->fmt_blk
.fmt_blk_size
= sizeof(*fmt
) - sizeof(fmt
->fmt_blk
);
995 fmt
->num_channels
= channels
;
996 fmt
->bits_per_sample
= bits_per_sample
;
997 fmt
->sample_rate
= rate
;
1000 channel_mapping
= fmt
->channel_mapping
;
1003 memcpy(channel_mapping
, channel_map
, PCM_MAX_NUM_CHANNEL
);
1005 if (q6dsp_map_channels(channel_mapping
, channels
)) {
1006 dev_err(ac
->dev
, " map channels failed %d\n", channels
);
1012 rc
= q6asm_ac_send_cmd_sync(ac
, pkt
);
1018 EXPORT_SYMBOL_GPL(q6asm_media_format_block_multi_ch_pcm
);
1021 * q6asm_enc_cfg_blk_pcm_format_support() - setup pcm configuration for capture
1023 * @ac: audio client pointer
1024 * @rate: audio sample rate
1025 * @channels: number of audio channels.
1026 * @bits_per_sample: bits per sample
1028 * Return: Will be an negative value on error or zero on success
1030 int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client
*ac
,
1031 uint32_t rate
, uint32_t channels
, uint16_t bits_per_sample
)
1033 struct asm_multi_channel_pcm_enc_cfg_v2
*enc_cfg
;
1034 struct apr_pkt
*pkt
;
1035 u8
*channel_mapping
;
1036 u32 frames_per_buf
= 0;
1040 pkt_size
= APR_HDR_SIZE
+ sizeof(*enc_cfg
);
1041 p
= kzalloc(pkt_size
, GFP_KERNEL
);
1046 enc_cfg
= p
+ APR_HDR_SIZE
;
1047 q6asm_add_hdr(ac
, &pkt
->hdr
, pkt_size
, true, ac
->stream_id
);
1049 pkt
->hdr
.opcode
= ASM_STREAM_CMD_SET_ENCDEC_PARAM
;
1050 enc_cfg
->encdec
.param_id
= ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2
;
1051 enc_cfg
->encdec
.param_size
= sizeof(*enc_cfg
) - sizeof(enc_cfg
->encdec
);
1052 enc_cfg
->encblk
.frames_per_buf
= frames_per_buf
;
1053 enc_cfg
->encblk
.enc_cfg_blk_size
= enc_cfg
->encdec
.param_size
-
1054 sizeof(struct asm_enc_cfg_blk_param_v2
);
1056 enc_cfg
->num_channels
= channels
;
1057 enc_cfg
->bits_per_sample
= bits_per_sample
;
1058 enc_cfg
->sample_rate
= rate
;
1059 enc_cfg
->is_signed
= 1;
1060 channel_mapping
= enc_cfg
->channel_mapping
;
1062 if (q6dsp_map_channels(channel_mapping
, channels
)) {
1067 rc
= q6asm_ac_send_cmd_sync(ac
, pkt
);
1072 EXPORT_SYMBOL_GPL(q6asm_enc_cfg_blk_pcm_format_support
);
1075 * q6asm_read() - read data of period size from audio client
1077 * @ac: audio client pointer
1079 * Return: Will be an negative value on error or zero on success
1081 int q6asm_read(struct audio_client
*ac
)
1083 struct asm_data_cmd_read_v2
*read
;
1084 struct audio_port_data
*port
;
1085 struct audio_buffer
*ab
;
1086 struct apr_pkt
*pkt
;
1087 unsigned long flags
;
1092 pkt_size
= APR_HDR_SIZE
+ sizeof(*read
);
1093 p
= kzalloc(pkt_size
, GFP_ATOMIC
);
1098 read
= p
+ APR_HDR_SIZE
;
1100 spin_lock_irqsave(&ac
->lock
, flags
);
1101 port
= &ac
->port
[SNDRV_PCM_STREAM_CAPTURE
];
1102 q6asm_add_hdr(ac
, &pkt
->hdr
, pkt_size
, false, ac
->stream_id
);
1103 ab
= &port
->buf
[port
->dsp_buf
];
1104 pkt
->hdr
.opcode
= ASM_DATA_CMD_READ_V2
;
1105 read
->buf_addr_lsw
= lower_32_bits(ab
->phys
);
1106 read
->buf_addr_msw
= upper_32_bits(ab
->phys
);
1107 read
->mem_map_handle
= port
->mem_map_handle
;
1109 read
->buf_size
= ab
->size
;
1110 read
->seq_id
= port
->dsp_buf
;
1111 pkt
->hdr
.token
= port
->dsp_buf
;
1115 if (port
->dsp_buf
>= port
->num_periods
)
1118 spin_unlock_irqrestore(&ac
->lock
, flags
);
1119 rc
= apr_send_pkt(ac
->adev
, pkt
);
1123 pr_err("read op[0x%x]rc[%d]\n", pkt
->hdr
.opcode
, rc
);
1128 EXPORT_SYMBOL_GPL(q6asm_read
);
1130 static int __q6asm_open_read(struct audio_client
*ac
,
1131 uint32_t format
, uint16_t bits_per_sample
)
1133 struct asm_stream_cmd_open_read_v3
*open
;
1134 struct apr_pkt
*pkt
;
1138 pkt_size
= APR_HDR_SIZE
+ sizeof(*open
);
1139 p
= kzalloc(pkt_size
, GFP_KERNEL
);
1144 open
= p
+ APR_HDR_SIZE
;
1146 q6asm_add_hdr(ac
, &pkt
->hdr
, pkt_size
, true, ac
->stream_id
);
1147 pkt
->hdr
.opcode
= ASM_STREAM_CMD_OPEN_READ_V3
;
1148 /* Stream prio : High, provide meta info with encoded frames */
1149 open
->src_endpointype
= ASM_END_POINT_DEVICE_MATRIX
;
1151 open
->preprocopo_id
= ASM_STREAM_POSTPROC_TOPO_ID_NONE
;
1152 open
->bits_per_sample
= bits_per_sample
;
1153 open
->mode_flags
= 0x0;
1155 open
->mode_flags
|= ASM_LEGACY_STREAM_SESSION
<<
1156 ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ
;
1159 case FORMAT_LINEAR_PCM
:
1160 open
->mode_flags
|= 0x00;
1161 open
->enc_cfg_id
= ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2
;
1164 pr_err("Invalid format[%d]\n", format
);
1167 rc
= q6asm_ac_send_cmd_sync(ac
, pkt
);
1174 * q6asm_open_read() - Open audio client for reading
1176 * @ac: audio client pointer
1177 * @format: audio sample format
1178 * @bits_per_sample: bits per sample
1180 * Return: Will be an negative value on error or zero on success
1182 int q6asm_open_read(struct audio_client
*ac
, uint32_t format
,
1183 uint16_t bits_per_sample
)
1185 return __q6asm_open_read(ac
, format
, bits_per_sample
);
1187 EXPORT_SYMBOL_GPL(q6asm_open_read
);
1190 * q6asm_write_async() - non blocking write
1192 * @ac: audio client pointer
1193 * @len: lenght in bytes
1194 * @msw_ts: timestamp msw
1195 * @lsw_ts: timestamp lsw
1196 * @wflags: flags associated with write
1198 * Return: Will be an negative value on error or zero on success
1200 int q6asm_write_async(struct audio_client
*ac
, uint32_t len
, uint32_t msw_ts
,
1201 uint32_t lsw_ts
, uint32_t wflags
)
1203 struct asm_data_cmd_write_v2
*write
;
1204 struct audio_port_data
*port
;
1205 struct audio_buffer
*ab
;
1206 unsigned long flags
;
1207 struct apr_pkt
*pkt
;
1212 pkt_size
= APR_HDR_SIZE
+ sizeof(*write
);
1213 p
= kzalloc(pkt_size
, GFP_ATOMIC
);
1218 write
= p
+ APR_HDR_SIZE
;
1220 spin_lock_irqsave(&ac
->lock
, flags
);
1221 port
= &ac
->port
[SNDRV_PCM_STREAM_PLAYBACK
];
1222 q6asm_add_hdr(ac
, &pkt
->hdr
, pkt_size
, false, ac
->stream_id
);
1224 ab
= &port
->buf
[port
->dsp_buf
];
1225 pkt
->hdr
.token
= port
->dsp_buf
;
1226 pkt
->hdr
.opcode
= ASM_DATA_CMD_WRITE_V2
;
1227 write
->buf_addr_lsw
= lower_32_bits(ab
->phys
);
1228 write
->buf_addr_msw
= upper_32_bits(ab
->phys
);
1229 write
->buf_size
= len
;
1230 write
->seq_id
= port
->dsp_buf
;
1231 write
->timestamp_lsw
= lsw_ts
;
1232 write
->timestamp_msw
= msw_ts
;
1233 write
->mem_map_handle
=
1234 ac
->port
[SNDRV_PCM_STREAM_PLAYBACK
].mem_map_handle
;
1236 if (wflags
== NO_TIMESTAMP
)
1237 write
->flags
= (wflags
& 0x800000FF);
1239 write
->flags
= (0x80000000 | wflags
);
1243 if (port
->dsp_buf
>= port
->num_periods
)
1246 spin_unlock_irqrestore(&ac
->lock
, flags
);
1247 rc
= apr_send_pkt(ac
->adev
, pkt
);
1254 EXPORT_SYMBOL_GPL(q6asm_write_async
);
1256 static void q6asm_reset_buf_state(struct audio_client
*ac
)
1258 struct audio_port_data
*port
= NULL
;
1259 unsigned long flags
;
1261 spin_lock_irqsave(&ac
->lock
, flags
);
1262 port
= &ac
->port
[SNDRV_PCM_STREAM_PLAYBACK
];
1264 port
= &ac
->port
[SNDRV_PCM_STREAM_CAPTURE
];
1266 spin_unlock_irqrestore(&ac
->lock
, flags
);
1269 static int __q6asm_cmd(struct audio_client
*ac
, int cmd
, bool wait
)
1271 int stream_id
= ac
->stream_id
;
1275 q6asm_add_hdr(ac
, &pkt
.hdr
, APR_HDR_SIZE
, true, stream_id
);
1279 pkt
.hdr
.opcode
= ASM_SESSION_CMD_PAUSE
;
1282 pkt
.hdr
.opcode
= ASM_SESSION_CMD_SUSPEND
;
1285 pkt
.hdr
.opcode
= ASM_STREAM_CMD_FLUSH
;
1288 pkt
.hdr
.opcode
= ASM_STREAM_CMD_FLUSH_READBUFS
;
1291 pkt
.hdr
.opcode
= ASM_DATA_CMD_EOS
;
1294 pkt
.hdr
.opcode
= ASM_STREAM_CMD_CLOSE
;
1301 rc
= q6asm_ac_send_cmd_sync(ac
, &pkt
);
1303 return apr_send_pkt(ac
->adev
, &pkt
);
1308 if (cmd
== CMD_FLUSH
)
1309 q6asm_reset_buf_state(ac
);
1315 * q6asm_cmd() - run cmd on audio client
1317 * @ac: audio client pointer
1318 * @cmd: command to run on audio client.
1320 * Return: Will be an negative value on error or zero on success
1322 int q6asm_cmd(struct audio_client
*ac
, int cmd
)
1324 return __q6asm_cmd(ac
, cmd
, true);
1326 EXPORT_SYMBOL_GPL(q6asm_cmd
);
1329 * q6asm_cmd_nowait() - non blocking, run cmd on audio client
1331 * @ac: audio client pointer
1332 * @cmd: command to run on audio client.
1334 * Return: Will be an negative value on error or zero on success
1336 int q6asm_cmd_nowait(struct audio_client
*ac
, int cmd
)
1338 return __q6asm_cmd(ac
, cmd
, false);
1340 EXPORT_SYMBOL_GPL(q6asm_cmd_nowait
);
1342 static int q6asm_probe(struct apr_device
*adev
)
1344 struct device
*dev
= &adev
->dev
;
1345 struct q6asm
*q6asm
;
1347 q6asm
= devm_kzalloc(dev
, sizeof(*q6asm
), GFP_KERNEL
);
1351 q6core_get_svc_api_info(adev
->svc_id
, &q6asm
->ainfo
);
1355 init_waitqueue_head(&q6asm
->mem_wait
);
1356 spin_lock_init(&q6asm
->slock
);
1357 dev_set_drvdata(dev
, q6asm
);
1359 return of_platform_populate(dev
->of_node
, NULL
, NULL
, dev
);
1362 static int q6asm_remove(struct apr_device
*adev
)
1364 of_platform_depopulate(&adev
->dev
);
1368 static const struct of_device_id q6asm_device_id
[] = {
1369 { .compatible
= "qcom,q6asm" },
1372 MODULE_DEVICE_TABLE(of
, q6asm_device_id
);
1374 static struct apr_driver qcom_q6asm_driver
= {
1375 .probe
= q6asm_probe
,
1376 .remove
= q6asm_remove
,
1377 .callback
= q6asm_srvc_callback
,
1379 .name
= "qcom-q6asm",
1380 .of_match_table
= of_match_ptr(q6asm_device_id
),
1384 module_apr_driver(qcom_q6asm_driver
);
1385 MODULE_DESCRIPTION("Q6 Audio Stream Manager driver");
1386 MODULE_LICENSE("GPL v2");