summary refs log tree commit diff
path: root/sound/soc/sof/amd/acp-probes.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/sof/amd/acp-probes.c')
-rw-r--r--sound/soc/sof/amd/acp-probes.c147
1 files changed, 147 insertions, 0 deletions
diff --git a/sound/soc/sof/amd/acp-probes.c b/sound/soc/sof/amd/acp-probes.c
new file mode 100644
index 000000000000..778cf1a8b610
--- /dev/null
+++ b/sound/soc/sof/amd/acp-probes.c
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license. When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2023 Advanced Micro Devices, Inc.
+//
+// Authors: V Sujith Kumar Reddy <Vsujithkumar.Reddy@amd.com>
+
+/*
+ * Probe interface for generic AMD audio ACP DSP block
+ */
+
+#include <linux/module.h>
+#include <sound/soc.h>
+#include "../sof-priv.h"
+#include "../sof-client-probes.h"
+#include "../sof-client.h"
+#include "../ops.h"
+#include "acp.h"
+#include "acp-dsp-offset.h"
+
+static int acp_probes_compr_startup(struct sof_client_dev *cdev,
+				    struct snd_compr_stream *cstream,
+				    struct snd_soc_dai *dai, u32 *stream_id)
+{
+	struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
+	struct acp_dsp_stream *stream;
+	struct acp_dev_data *adata;
+
+	adata = sdev->pdata->hw_pdata;
+	stream = acp_dsp_stream_get(sdev, 0);
+	if (!stream)
+		return -ENODEV;
+
+	stream->cstream = cstream;
+	cstream->runtime->private_data = stream;
+
+	adata->probe_stream = stream;
+	*stream_id = stream->stream_tag;
+
+	return 0;
+}
+
+static int acp_probes_compr_shutdown(struct sof_client_dev *cdev,
+				     struct snd_compr_stream *cstream,
+				     struct snd_soc_dai *dai)
+{
+	struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
+	struct acp_dsp_stream *stream = cstream->runtime->private_data;
+	struct acp_dev_data *adata;
+	int ret;
+
+	ret = acp_dsp_stream_put(sdev, stream);
+	if (ret < 0) {
+		dev_err(sdev->dev, "Failed to release probe compress stream\n");
+		return ret;
+	}
+
+	adata = sdev->pdata->hw_pdata;
+	stream->cstream = NULL;
+	cstream->runtime->private_data = NULL;
+	adata->probe_stream = NULL;
+
+	return 0;
+}
+
+static int acp_probes_compr_set_params(struct sof_client_dev *cdev,
+				       struct snd_compr_stream *cstream,
+				       struct snd_compr_params *params,
+				       struct snd_soc_dai *dai)
+{
+	struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
+	struct acp_dsp_stream *stream = cstream->runtime->private_data;
+	unsigned int buf_offset, index;
+	u32 size;
+	int ret;
+
+	stream->dmab = cstream->runtime->dma_buffer_p;
+	stream->num_pages = PFN_UP(cstream->runtime->dma_bytes);
+	size = cstream->runtime->buffer_size;
+
+	ret = acp_dsp_stream_config(sdev, stream);
+	if (ret < 0) {
+		acp_dsp_stream_put(sdev, stream);
+		return ret;
+	}
+
+	/* write buffer size of stream in scratch memory */
+
+	buf_offset = sdev->debug_box.offset +
+		     offsetof(struct scratch_reg_conf, buf_size);
+	index = stream->stream_tag - 1;
+	buf_offset = buf_offset + index * 4;
+
+	snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + buf_offset, size);
+
+	return 0;
+}
+
+static int acp_probes_compr_trigger(struct sof_client_dev *cdev,
+				    struct snd_compr_stream *cstream,
+				    int cmd, struct snd_soc_dai *dai)
+{
+	/* Nothing to do here, as it is a mandatory callback just defined */
+	return 0;
+}
+
+static int acp_probes_compr_pointer(struct sof_client_dev *cdev,
+				    struct snd_compr_stream *cstream,
+				    struct snd_compr_tstamp *tstamp,
+				    struct snd_soc_dai *dai)
+{
+	struct acp_dsp_stream *stream = cstream->runtime->private_data;
+	struct snd_soc_pcm_stream *pstream;
+
+	pstream = &dai->driver->capture;
+	tstamp->copied_total = stream->cstream_posn;
+	tstamp->sampling_rate = snd_pcm_rate_bit_to_rate(pstream->rates);
+
+	return 0;
+}
+
+/* SOF client implementation */
+static const struct sof_probes_host_ops acp_probes_ops = {
+	.startup = acp_probes_compr_startup,
+	.shutdown = acp_probes_compr_shutdown,
+	.set_params = acp_probes_compr_set_params,
+	.trigger = acp_probes_compr_trigger,
+	.pointer = acp_probes_compr_pointer,
+};
+
+int acp_probes_register(struct snd_sof_dev *sdev)
+{
+	return sof_client_dev_register(sdev, "acp-probes", 0, &acp_probes_ops,
+				       sizeof(acp_probes_ops));
+}
+EXPORT_SYMBOL_NS(acp_probes_register, SND_SOC_SOF_AMD_COMMON);
+
+void acp_probes_unregister(struct snd_sof_dev *sdev)
+{
+	sof_client_dev_unregister(sdev, "acp-probes", 0);
+}
+EXPORT_SYMBOL_NS(acp_probes_unregister, SND_SOC_SOF_AMD_COMMON);
+
+MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT);
+