162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// This file is provided under a dual BSD/GPLv2 license. When using or
462306a36Sopenharmony_ci// redistributing this file, you may do so under either license.
562306a36Sopenharmony_ci//
662306a36Sopenharmony_ci// Copyright(c) 2023 Advanced Micro Devices, Inc.
762306a36Sopenharmony_ci//
862306a36Sopenharmony_ci// Authors: V Sujith Kumar Reddy <Vsujithkumar.Reddy@amd.com>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci/*
1162306a36Sopenharmony_ci * Probe interface for generic AMD audio ACP DSP block
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <sound/soc.h>
1662306a36Sopenharmony_ci#include "../sof-priv.h"
1762306a36Sopenharmony_ci#include "../sof-client-probes.h"
1862306a36Sopenharmony_ci#include "../sof-client.h"
1962306a36Sopenharmony_ci#include "../ops.h"
2062306a36Sopenharmony_ci#include "acp.h"
2162306a36Sopenharmony_ci#include "acp-dsp-offset.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic int acp_probes_compr_startup(struct sof_client_dev *cdev,
2462306a36Sopenharmony_ci				    struct snd_compr_stream *cstream,
2562306a36Sopenharmony_ci				    struct snd_soc_dai *dai, u32 *stream_id)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci	struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
2862306a36Sopenharmony_ci	struct acp_dsp_stream *stream;
2962306a36Sopenharmony_ci	struct acp_dev_data *adata;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	adata = sdev->pdata->hw_pdata;
3262306a36Sopenharmony_ci	stream = acp_dsp_stream_get(sdev, 0);
3362306a36Sopenharmony_ci	if (!stream)
3462306a36Sopenharmony_ci		return -ENODEV;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	stream->cstream = cstream;
3762306a36Sopenharmony_ci	cstream->runtime->private_data = stream;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	adata->probe_stream = stream;
4062306a36Sopenharmony_ci	*stream_id = stream->stream_tag;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	return 0;
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic int acp_probes_compr_shutdown(struct sof_client_dev *cdev,
4662306a36Sopenharmony_ci				     struct snd_compr_stream *cstream,
4762306a36Sopenharmony_ci				     struct snd_soc_dai *dai)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
5062306a36Sopenharmony_ci	struct acp_dsp_stream *stream = cstream->runtime->private_data;
5162306a36Sopenharmony_ci	struct acp_dev_data *adata;
5262306a36Sopenharmony_ci	int ret;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	ret = acp_dsp_stream_put(sdev, stream);
5562306a36Sopenharmony_ci	if (ret < 0) {
5662306a36Sopenharmony_ci		dev_err(sdev->dev, "Failed to release probe compress stream\n");
5762306a36Sopenharmony_ci		return ret;
5862306a36Sopenharmony_ci	}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	adata = sdev->pdata->hw_pdata;
6162306a36Sopenharmony_ci	stream->cstream = NULL;
6262306a36Sopenharmony_ci	cstream->runtime->private_data = NULL;
6362306a36Sopenharmony_ci	adata->probe_stream = NULL;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	return 0;
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic int acp_probes_compr_set_params(struct sof_client_dev *cdev,
6962306a36Sopenharmony_ci				       struct snd_compr_stream *cstream,
7062306a36Sopenharmony_ci				       struct snd_compr_params *params,
7162306a36Sopenharmony_ci				       struct snd_soc_dai *dai)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
7462306a36Sopenharmony_ci	struct acp_dsp_stream *stream = cstream->runtime->private_data;
7562306a36Sopenharmony_ci	unsigned int buf_offset, index;
7662306a36Sopenharmony_ci	u32 size;
7762306a36Sopenharmony_ci	int ret;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	stream->dmab = cstream->runtime->dma_buffer_p;
8062306a36Sopenharmony_ci	stream->num_pages = PFN_UP(cstream->runtime->dma_bytes);
8162306a36Sopenharmony_ci	size = cstream->runtime->buffer_size;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	ret = acp_dsp_stream_config(sdev, stream);
8462306a36Sopenharmony_ci	if (ret < 0) {
8562306a36Sopenharmony_ci		acp_dsp_stream_put(sdev, stream);
8662306a36Sopenharmony_ci		return ret;
8762306a36Sopenharmony_ci	}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	/* write buffer size of stream in scratch memory */
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	buf_offset = sdev->debug_box.offset +
9262306a36Sopenharmony_ci		     offsetof(struct scratch_reg_conf, buf_size);
9362306a36Sopenharmony_ci	index = stream->stream_tag - 1;
9462306a36Sopenharmony_ci	buf_offset = buf_offset + index * 4;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + buf_offset, size);
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	return 0;
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic int acp_probes_compr_trigger(struct sof_client_dev *cdev,
10262306a36Sopenharmony_ci				    struct snd_compr_stream *cstream,
10362306a36Sopenharmony_ci				    int cmd, struct snd_soc_dai *dai)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	/* Nothing to do here, as it is a mandatory callback just defined */
10662306a36Sopenharmony_ci	return 0;
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistatic int acp_probes_compr_pointer(struct sof_client_dev *cdev,
11062306a36Sopenharmony_ci				    struct snd_compr_stream *cstream,
11162306a36Sopenharmony_ci				    struct snd_compr_tstamp *tstamp,
11262306a36Sopenharmony_ci				    struct snd_soc_dai *dai)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	struct acp_dsp_stream *stream = cstream->runtime->private_data;
11562306a36Sopenharmony_ci	struct snd_soc_pcm_stream *pstream;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	pstream = &dai->driver->capture;
11862306a36Sopenharmony_ci	tstamp->copied_total = stream->cstream_posn;
11962306a36Sopenharmony_ci	tstamp->sampling_rate = snd_pcm_rate_bit_to_rate(pstream->rates);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	return 0;
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci/* SOF client implementation */
12562306a36Sopenharmony_cistatic const struct sof_probes_host_ops acp_probes_ops = {
12662306a36Sopenharmony_ci	.startup = acp_probes_compr_startup,
12762306a36Sopenharmony_ci	.shutdown = acp_probes_compr_shutdown,
12862306a36Sopenharmony_ci	.set_params = acp_probes_compr_set_params,
12962306a36Sopenharmony_ci	.trigger = acp_probes_compr_trigger,
13062306a36Sopenharmony_ci	.pointer = acp_probes_compr_pointer,
13162306a36Sopenharmony_ci};
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ciint acp_probes_register(struct snd_sof_dev *sdev)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	return sof_client_dev_register(sdev, "acp-probes", 0, &acp_probes_ops,
13662306a36Sopenharmony_ci				       sizeof(acp_probes_ops));
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ciEXPORT_SYMBOL_NS(acp_probes_register, SND_SOC_SOF_AMD_COMMON);
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_civoid acp_probes_unregister(struct snd_sof_dev *sdev)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	sof_client_dev_unregister(sdev, "acp-probes", 0);
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ciEXPORT_SYMBOL_NS(acp_probes_unregister, SND_SOC_SOF_AMD_COMMON);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ciMODULE_IMPORT_NS(SND_SOC_SOF_CLIENT);
14762306a36Sopenharmony_ci
148