cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

q6asm.c (43407B)


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