Unverified Commit e8afccf8 authored by Ajit Kumar Pandey's avatar Ajit Kumar Pandey Committed by Mark Brown
Browse files

ASoC: SOF: amd: Add PCM stream callback for Renoir dai's



Add module to support ALSA pcm stream configurations for ACP I2S
and DMIC endpoints

Signed-off-by: default avatarAjit Kumar Pandey <AjitKumar.Pandey@amd.com>
Reviewed-by: default avatarBard Liao <bard.liao@intel.com>
Reviewed-by: default avatarKai Vehmanen <kai.vehmanen@linux.intel.com>
Signed-off-by: default avatarDaniel Baluta <daniel.baluta@nxp.com>
Link: https://lore.kernel.org/r/20211117093734.17407-7-daniel.baluta@oss.nxp.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent bda93076
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@
#
# Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved.

snd-sof-amd-acp-objs := acp.o acp-loader.o acp-ipc.o
snd-sof-amd-acp-objs := acp.o acp-loader.o acp-ipc.o acp-pcm.o acp-stream.o
snd-sof-amd-renoir-objs := renoir.o

obj-$(CONFIG_SND_SOC_SOF_AMD_COMMON) += snd-sof-amd-acp.o
+82 −0
Original line number Diff line number Diff line
// 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) 2021 Advanced Micro Devices, Inc.
//
// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>

/*
 * PCM interface for generic AMD audio ACP DSP block
 */
#include <sound/pcm_params.h>

#include "../ops.h"
#include "acp.h"
#include "acp-dsp-offset.h"

int acp_pcm_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream,
		      struct snd_pcm_hw_params *params, struct sof_ipc_stream_params *ipc_params)
{
	struct acp_dsp_stream *stream = substream->runtime->private_data;
	unsigned int buf_offset, index;
	u32 size;
	int ret;

	size = ipc_params->buffer.size;
	stream->num_pages = ipc_params->buffer.pages;
	stream->dmab = substream->runtime->dma_buffer_p;

	ret = acp_dsp_stream_config(sdev, stream);
	if (ret < 0) {
		dev_err(sdev->dev, "stream configuration failed\n");
		return ret;
	}

	ipc_params->buffer.phy_addr = stream->reg_offset;
	ipc_params->stream_tag = stream->stream_tag;

	/* write buffer size of stream in scratch memory */

	buf_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;
}
EXPORT_SYMBOL_NS(acp_pcm_hw_params, SND_SOC_SOF_AMD_COMMON);

int acp_pcm_open(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream)
{
	struct acp_dsp_stream *stream;

	stream = acp_dsp_stream_get(sdev, 0);
	if (!stream)
		return -ENODEV;

	substream->runtime->private_data = stream;
	stream->substream = substream;

	return 0;
}
EXPORT_SYMBOL_NS(acp_pcm_open, SND_SOC_SOF_AMD_COMMON);

int acp_pcm_close(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream)
{
	struct acp_dsp_stream *stream;

	stream = substream->runtime->private_data;
	if (!stream) {
		dev_err(sdev->dev, "No open stream\n");
		return -EINVAL;
	}

	stream->substream = NULL;
	substream->runtime->private_data = NULL;

	return acp_dsp_stream_put(sdev, stream);
}
EXPORT_SYMBOL_NS(acp_pcm_close, SND_SOC_SOF_AMD_COMMON);
+181 −0
Original line number Diff line number Diff line
// 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) 2021 Advanced Micro Devices, Inc.
//
// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>

/*
 * Hardware interface for generic AMD audio DSP ACP IP
 */

#include "../ops.h"
#include "acp-dsp-offset.h"
#include "acp.h"

#define PTE_GRP1_OFFSET		0x00000000
#define PTE_GRP2_OFFSET		0x00800000
#define PTE_GRP3_OFFSET		0x01000000
#define PTE_GRP4_OFFSET		0x01800000
#define PTE_GRP5_OFFSET		0x02000000
#define PTE_GRP6_OFFSET		0x02800000
#define PTE_GRP7_OFFSET		0x03000000
#define PTE_GRP8_OFFSET		0x03800000

int acp_dsp_stream_config(struct snd_sof_dev *sdev, struct acp_dsp_stream *stream)
{
	unsigned int pte_reg, pte_size, phy_addr_offset, index;
	int stream_tag = stream->stream_tag;
	u32 low, high, offset, reg_val;
	dma_addr_t addr;
	int page_idx;

	switch (stream_tag) {
	case 1:
		pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_1;
		pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1;
		offset = offsetof(struct scratch_reg_conf, grp1_pte);
		stream->reg_offset = PTE_GRP1_OFFSET;
		break;
	case 2:
		pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_2;
		pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_2;
		offset = offsetof(struct scratch_reg_conf, grp2_pte);
		stream->reg_offset = PTE_GRP2_OFFSET;
		break;
	case 3:
		pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_3;
		pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_3;
		offset = offsetof(struct scratch_reg_conf, grp3_pte);
		stream->reg_offset = PTE_GRP3_OFFSET;
		break;
	case 4:
		pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_4;
		pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_4;
		offset = offsetof(struct scratch_reg_conf, grp4_pte);
		stream->reg_offset = PTE_GRP4_OFFSET;
		break;
	case 5:
		pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_5;
		pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5;
		offset = offsetof(struct scratch_reg_conf, grp5_pte);
		stream->reg_offset = PTE_GRP5_OFFSET;
		break;
	case 6:
		pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_6;
		pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_6;
		offset = offsetof(struct scratch_reg_conf, grp6_pte);
		stream->reg_offset = PTE_GRP6_OFFSET;
		break;
	case 7:
		pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_7;
		pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_7;
		offset = offsetof(struct scratch_reg_conf, grp7_pte);
		stream->reg_offset = PTE_GRP7_OFFSET;
		break;
	case 8:
		pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_8;
		pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_8;
		offset = offsetof(struct scratch_reg_conf, grp8_pte);
		stream->reg_offset = PTE_GRP8_OFFSET;
		break;
	default:
		dev_err(sdev->dev, "Invalid stream tag %d\n", stream_tag);
		return -EINVAL;
	}

	/* write phy_addr in scratch memory */

	phy_addr_offset = offsetof(struct scratch_reg_conf, reg_offset);
	index = stream_tag - 1;
	phy_addr_offset = phy_addr_offset + index * 4;

	snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 +
			  phy_addr_offset, stream->reg_offset);

	/* Group Enable */
	reg_val = ACP_SRAM_PTE_OFFSET + offset;
	snd_sof_dsp_write(sdev, ACP_DSP_BAR, pte_reg, reg_val | BIT(31));
	snd_sof_dsp_write(sdev, ACP_DSP_BAR, pte_size, PAGE_SIZE_4K_ENABLE);

	for (page_idx = 0; page_idx < stream->num_pages; page_idx++) {
		addr = snd_sgbuf_get_addr(stream->dmab, page_idx * PAGE_SIZE);

		/* Load the low address of page int ACP SRAM through SRBM */
		low = lower_32_bits(addr);
		high = upper_32_bits(addr);

		snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + offset, low);

		high |= BIT(31);
		snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + offset + 4, high);
		/* Move to next physically contiguous page */
		offset += 8;
	}

	return 0;
}

struct acp_dsp_stream *acp_dsp_stream_get(struct snd_sof_dev *sdev, int tag)
{
	struct acp_dev_data *adata = sdev->pdata->hw_pdata;
	struct acp_dsp_stream *stream = adata->stream_buf;
	int i;

	for (i = 0; i < ACP_MAX_STREAM; i++, stream++) {
		if (stream->active)
			continue;

		/* return stream if tag not specified*/
		if (!tag) {
			stream->active = 1;
			return stream;
		}

		/* check if this is the requested stream tag */
		if (stream->stream_tag == tag) {
			stream->active = 1;
			return stream;
		}
	}

	dev_err(sdev->dev, "stream %d active or no inactive stream\n", tag);
	return NULL;
}
EXPORT_SYMBOL_NS(acp_dsp_stream_get, SND_SOC_SOF_AMD_COMMON);

int acp_dsp_stream_put(struct snd_sof_dev *sdev,
		       struct acp_dsp_stream *acp_stream)
{
	struct acp_dev_data *adata = sdev->pdata->hw_pdata;
	struct acp_dsp_stream *stream = adata->stream_buf;
	int i;

	/* Free an active stream */
	for (i = 0; i < ACP_MAX_STREAM; i++, stream++) {
		if (stream == acp_stream) {
			stream->active = 0;
			return 0;
		}
	}

	dev_err(sdev->dev, "Cannot find active stream tag %d\n", acp_stream->stream_tag);
	return -EINVAL;
}
EXPORT_SYMBOL_NS(acp_dsp_stream_put, SND_SOC_SOF_AMD_COMMON);

int acp_dsp_stream_init(struct snd_sof_dev *sdev)
{
	struct acp_dev_data *adata = sdev->pdata->hw_pdata;
	int i;

	for (i = 0; i < ACP_MAX_STREAM; i++) {
		adata->stream_buf[i].sdev = sdev;
		adata->stream_buf[i].active = 0;
		adata->stream_buf[i].stream_tag = i + 1;
	}
	return 0;
}
EXPORT_SYMBOL_NS(acp_dsp_stream_init, SND_SOC_SOF_AMD_COMMON);
+2 −0
Original line number Diff line number Diff line
@@ -363,6 +363,8 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev)

	acp_memory_init(sdev);

	acp_dsp_stream_init(sdev);

	return 0;
}
EXPORT_SYMBOL_NS(amd_sof_acp_probe, SND_SOC_SOF_AMD_COMMON);
+28 −0
Original line number Diff line number Diff line
@@ -13,6 +13,8 @@

#include "../sof-priv.h"

#define ACP_MAX_STREAM	8

#define ACP_DSP_BAR	0

#define ACP_REG_POLL_INTERVAL                   500
@@ -114,6 +116,17 @@ struct scratch_reg_conf {
	unsigned int    reserve[];
};

struct acp_dsp_stream {
	struct list_head list;
	struct snd_sof_dev *sdev;
	struct snd_pcm_substream *substream;
	struct snd_dma_buffer *dmab;
	int num_pages;
	int stream_tag;
	int active;
	unsigned int reg_offset;
};

/* Common device data struct for ACP devices */
struct acp_dev_data {
	struct snd_sof_dev  *dev;
@@ -125,6 +138,7 @@ struct acp_dev_data {
	dma_addr_t dma_addr;
	u8 *data_buf;
	struct dma_descriptor dscr_info[ACP_MAX_DESC];
	struct acp_dsp_stream stream_buf[ACP_MAX_STREAM];
};

void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes);
@@ -165,5 +179,19 @@ int acp_sof_ipc_pcm_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *s
void acp_mailbox_write(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes);
void acp_mailbox_read(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes);

/* ACP - DSP  stream callbacks */
int acp_dsp_stream_config(struct snd_sof_dev *sdev, struct acp_dsp_stream *stream);
int acp_dsp_stream_init(struct snd_sof_dev *sdev);
struct acp_dsp_stream *acp_dsp_stream_get(struct snd_sof_dev *sdev, int tag);
int acp_dsp_stream_put(struct snd_sof_dev *sdev, struct acp_dsp_stream *acp_stream);

/*
 * DSP PCM Operations.
 */
int acp_pcm_open(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream);
int acp_pcm_close(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream);
int acp_pcm_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream,
		      struct snd_pcm_hw_params *params, struct sof_ipc_stream_params *ipc_params);

extern const struct snd_sof_dsp_ops sof_renoir_ops;
#endif
Loading