diff mbox series

[07/14] ASoC: q6dsp: q6apm-dai: Add async compress write support

Message ID 20230201134947.1638197-8-quic_mohs@quicinc.com
State New
Headers show
Series Add support for compress offload and gapless playback. | expand

Commit Message

Mohammad Rafi Shaik Feb. 1, 2023, 1:49 p.m. UTC
Add async compress write API to send the compressed audio data packet
to ADSP. 

Signed-off-by: Mohammad Rafi Shaik <quic_mohs@quicinc.com>
Co-developed-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/qdsp6/audioreach.c | 38 +++++++++++++++++++++++++
 sound/soc/qcom/qdsp6/audioreach.h |  2 ++
 sound/soc/qcom/qdsp6/q6apm-dai.c  |  7 +++++
 sound/soc/qcom/qdsp6/q6apm.c      | 46 +++++++++++++++++++++++++++++++
 sound/soc/qcom/qdsp6/q6apm.h      |  3 ++
 5 files changed, 96 insertions(+)
diff mbox series

Patch

diff --git a/sound/soc/qcom/qdsp6/audioreach.c b/sound/soc/qcom/qdsp6/audioreach.c
index e84ccbacc0f7..7c45c36e9156 100644
--- a/sound/soc/qcom/qdsp6/audioreach.c
+++ b/sound/soc/qcom/qdsp6/audioreach.c
@@ -240,6 +240,44 @@  void *audioreach_alloc_pkt(int payload_size, uint32_t opcode, uint32_t token,
 }
 EXPORT_SYMBOL_GPL(audioreach_alloc_pkt);
 
+static void __audioreach_update_pkt(struct gpr_pkt *pkt, int payload_size, uint32_t opcode,
+				    uint32_t token, uint32_t src_port, uint32_t dest_port,
+				    bool has_cmd_hdr)
+{
+	int pkt_size = GPR_HDR_SIZE + payload_size;
+	void *p;
+
+	if (has_cmd_hdr)
+		pkt_size += APM_CMD_HDR_SIZE;
+
+	p = pkt;
+	pkt->hdr.version = GPR_PKT_VER;
+	pkt->hdr.hdr_size = GPR_PKT_HEADER_WORD_SIZE;
+	pkt->hdr.pkt_size = pkt_size;
+	pkt->hdr.dest_port = dest_port;
+	pkt->hdr.src_port = src_port;
+
+	pkt->hdr.dest_domain = GPR_DOMAIN_ID_ADSP;
+	pkt->hdr.src_domain = GPR_DOMAIN_ID_APPS;
+	pkt->hdr.token = token;
+	pkt->hdr.opcode = opcode;
+
+	if (has_cmd_hdr) {
+		struct apm_cmd_header *cmd_header;
+
+		p = p + GPR_HDR_SIZE;
+		cmd_header = p;
+		cmd_header->payload_size = payload_size;
+	}
+}
+
+void audioreach_update_pkt(struct gpr_pkt *pkt, int payload_size, uint32_t opcode, uint32_t token,
+			   uint32_t src_port, uint32_t dest_port)
+{
+	__audioreach_update_pkt(pkt, payload_size, opcode, token, src_port, dest_port, false);
+}
+EXPORT_SYMBOL_GPL(audioreach_update_pkt);
+
 void *audioreach_alloc_apm_pkt(int pkt_size, uint32_t opcode, uint32_t token, uint32_t src_port)
 {
 	return __audioreach_alloc_pkt(pkt_size, opcode, token, src_port, APM_MODULE_INSTANCE_ID,
diff --git a/sound/soc/qcom/qdsp6/audioreach.h b/sound/soc/qcom/qdsp6/audioreach.h
index 0faaf75115fd..044994ca4811 100644
--- a/sound/soc/qcom/qdsp6/audioreach.h
+++ b/sound/soc/qcom/qdsp6/audioreach.h
@@ -788,4 +788,6 @@  int audioreach_remove_trailing_silence(struct q6apm *apm, struct audioreach_modu
 				uint32_t trailing_samples);
 int audioreach_compr_set_param(struct q6apm_graph *graph, struct audioreach_module_config *mcfg);
 int audioreach_set_real_module_id(struct q6apm *apm, struct audioreach_module *module, uint32_t id);
+void audioreach_update_pkt(struct gpr_pkt *pkt, int payload_size, uint32_t opcode,
+			   uint32_t token, uint32_t src_port, uint32_t dest_port);
 #endif /* __AUDIOREACH_H__ */
diff --git a/sound/soc/qcom/qdsp6/q6apm-dai.c b/sound/soc/qcom/qdsp6/q6apm-dai.c
index 8f5d744b3365..e621e31294a1 100644
--- a/sound/soc/qcom/qdsp6/q6apm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6apm-dai.c
@@ -38,8 +38,10 @@  enum stream_state {
 struct q6apm_dai_rtd {
 	struct snd_pcm_substream *substream;
 	struct snd_compr_stream *cstream;
+	struct snd_codec codec;
 	struct snd_compr_params codec_param;
 	struct snd_dma_buffer dma_buffer;
+	spinlock_t lock;
 	phys_addr_t phys;
 	unsigned int pcm_size;
 	unsigned int pcm_count;
@@ -51,8 +53,13 @@  struct q6apm_dai_rtd {
 	uint16_t bits_per_sample;
 	uint16_t source; /* Encoding source bit mask */
 	uint16_t session_id;
+	bool next_track;
 	enum stream_state state;
 	struct q6apm_graph *graph;
+	uint32_t initial_samples_drop;
+	uint32_t trailing_samples_drop;
+	uint32_t next_track_stream_id;
+	bool notify_on_drain;
 };
 
 struct q6apm_dai_data {
diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c
index 811d86bdc092..1a6c7108bae0 100644
--- a/sound/soc/qcom/qdsp6/q6apm.c
+++ b/sound/soc/qcom/qdsp6/q6apm.c
@@ -25,6 +25,8 @@  struct apm_graph_mgmt_cmd {
 	uint32_t sub_graph_id_list[];
 } __packed;
 
+struct gpr_pkt *pkt;
+
 #define APM_GRAPH_MGMT_PSIZE(p, n) ALIGN(struct_size(p, sub_graph_id_list, n), 8)
 
 struct q6apm *g_apm;
@@ -457,6 +459,45 @@  int q6apm_write_async(struct q6apm_graph *graph, uint32_t len, uint32_t msw_ts,
 }
 EXPORT_SYMBOL_GPL(q6apm_write_async);
 
+int q6apm_write_async_compr(struct q6apm_graph *graph, uint32_t len, uint32_t msw_ts,
+		      uint32_t lsw_ts, uint32_t wflags)
+{
+	struct apm_data_cmd_wr_sh_mem_ep_data_buffer_v2 *write_buffer;
+	struct audio_buffer *ab;
+
+	int rc, iid;
+
+	iid = q6apm_graph_get_rx_shmem_module_iid(graph);
+
+	audioreach_update_pkt(pkt, sizeof(*write_buffer), DATA_CMD_WR_SH_MEM_EP_DATA_BUFFER_V2,
+			      graph->rx_data.dsp_buf | (len << APM_WRITE_TOKEN_LEN_SHIFT),
+			      graph->port->id, iid);
+
+	write_buffer = (void *)pkt + GPR_HDR_SIZE;
+
+	ab = &graph->rx_data.buf[graph->rx_data.dsp_buf];
+
+	write_buffer->buf_addr_lsw = lower_32_bits(ab->phys);
+	write_buffer->buf_addr_msw = upper_32_bits(ab->phys);
+	write_buffer->buf_size = len;
+	write_buffer->timestamp_lsw = lsw_ts;
+	write_buffer->timestamp_msw = msw_ts;
+	write_buffer->mem_map_handle = graph->rx_data.mem_map_handle;
+	write_buffer->flags = wflags;
+
+	graph->rx_data.dsp_buf++;
+
+	if (graph->rx_data.dsp_buf >= graph->rx_data.num_periods)
+		graph->rx_data.dsp_buf = 0;
+
+	rc = gpr_send_port_pkt(graph->port, pkt);
+
+	memset(pkt, 0, sizeof(write_buffer) + GPR_HDR_SIZE);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(q6apm_write_async_compr);
+
 int q6apm_read(struct q6apm_graph *graph)
 {
 	struct data_cmd_rd_sh_mem_ep_data_buffer_v2 *read_buffer;
@@ -724,6 +765,11 @@  static int apm_probe(gpr_device_t *gdev)
 
 	dev_set_drvdata(dev, apm);
 
+	pkt = devm_kzalloc(dev, sizeof(struct apm_data_cmd_wr_sh_mem_ep_data_buffer_v2) +
+			   GPR_HDR_SIZE, GFP_KERNEL);
+	if (!pkt)
+		return -ENOMEM;
+
 	mutex_init(&apm->lock);
 	apm->dev = dev;
 	apm->gdev = gdev;
diff --git a/sound/soc/qcom/qdsp6/q6apm.h b/sound/soc/qcom/qdsp6/q6apm.h
index 87d67faf5f1a..630c2bca0f06 100644
--- a/sound/soc/qcom/qdsp6/q6apm.h
+++ b/sound/soc/qcom/qdsp6/q6apm.h
@@ -45,6 +45,7 @@ 
 #define APM_WRITE_TOKEN_LEN_SHIFT              16
 
 #define APM_MAX_SESSIONS			8
+#define APM_LAST_BUFFER_FLAG			BIT(30)
 
 struct q6apm {
 	struct device *dev;
@@ -128,6 +129,8 @@  int q6apm_send_eos_nowait(struct q6apm_graph *graph);
 int q6apm_read(struct q6apm_graph *graph);
 int q6apm_write_async(struct q6apm_graph *graph, uint32_t len, uint32_t msw_ts,
 		      uint32_t lsw_ts, uint32_t wflags);
+int q6apm_write_async_compr(struct q6apm_graph *graph, uint32_t len, uint32_t msw_ts,
+			    uint32_t lsw_ts, uint32_t wflags);
 
 /* Memory Map related */
 int q6apm_map_memory_regions(struct q6apm_graph *graph,