brintos

brintos / linux-shallow public Read only

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