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) 2021 Advanced Micro Devices, Inc.
762306a36Sopenharmony_ci//
862306a36Sopenharmony_ci// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci/*
1162306a36Sopenharmony_ci * Hardware interface for generic AMD audio DSP ACP IP
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include "../ops.h"
1562306a36Sopenharmony_ci#include "acp-dsp-offset.h"
1662306a36Sopenharmony_ci#include "acp.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define PTE_GRP1_OFFSET		0x00000000
1962306a36Sopenharmony_ci#define PTE_GRP2_OFFSET		0x00800000
2062306a36Sopenharmony_ci#define PTE_GRP3_OFFSET		0x01000000
2162306a36Sopenharmony_ci#define PTE_GRP4_OFFSET		0x01800000
2262306a36Sopenharmony_ci#define PTE_GRP5_OFFSET		0x02000000
2362306a36Sopenharmony_ci#define PTE_GRP6_OFFSET		0x02800000
2462306a36Sopenharmony_ci#define PTE_GRP7_OFFSET		0x03000000
2562306a36Sopenharmony_ci#define PTE_GRP8_OFFSET		0x03800000
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ciint acp_dsp_stream_config(struct snd_sof_dev *sdev, struct acp_dsp_stream *stream)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
3062306a36Sopenharmony_ci	unsigned int pte_reg, pte_size, phy_addr_offset, index;
3162306a36Sopenharmony_ci	int stream_tag = stream->stream_tag;
3262306a36Sopenharmony_ci	u32 low, high, offset, reg_val;
3362306a36Sopenharmony_ci	dma_addr_t addr;
3462306a36Sopenharmony_ci	int page_idx;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	switch (stream_tag) {
3762306a36Sopenharmony_ci	case 1:
3862306a36Sopenharmony_ci		pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_1;
3962306a36Sopenharmony_ci		pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1;
4062306a36Sopenharmony_ci		offset = offsetof(struct scratch_reg_conf, grp1_pte);
4162306a36Sopenharmony_ci		stream->reg_offset = PTE_GRP1_OFFSET;
4262306a36Sopenharmony_ci		break;
4362306a36Sopenharmony_ci	case 2:
4462306a36Sopenharmony_ci		pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_2;
4562306a36Sopenharmony_ci		pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_2;
4662306a36Sopenharmony_ci		offset = offsetof(struct scratch_reg_conf, grp2_pte);
4762306a36Sopenharmony_ci		stream->reg_offset = PTE_GRP2_OFFSET;
4862306a36Sopenharmony_ci		break;
4962306a36Sopenharmony_ci	case 3:
5062306a36Sopenharmony_ci		pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_3;
5162306a36Sopenharmony_ci		pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_3;
5262306a36Sopenharmony_ci		offset = offsetof(struct scratch_reg_conf, grp3_pte);
5362306a36Sopenharmony_ci		stream->reg_offset = PTE_GRP3_OFFSET;
5462306a36Sopenharmony_ci		break;
5562306a36Sopenharmony_ci	case 4:
5662306a36Sopenharmony_ci		pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_4;
5762306a36Sopenharmony_ci		pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_4;
5862306a36Sopenharmony_ci		offset = offsetof(struct scratch_reg_conf, grp4_pte);
5962306a36Sopenharmony_ci		stream->reg_offset = PTE_GRP4_OFFSET;
6062306a36Sopenharmony_ci		break;
6162306a36Sopenharmony_ci	case 5:
6262306a36Sopenharmony_ci		pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_5;
6362306a36Sopenharmony_ci		pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5;
6462306a36Sopenharmony_ci		offset = offsetof(struct scratch_reg_conf, grp5_pte);
6562306a36Sopenharmony_ci		stream->reg_offset = PTE_GRP5_OFFSET;
6662306a36Sopenharmony_ci		break;
6762306a36Sopenharmony_ci	case 6:
6862306a36Sopenharmony_ci		pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_6;
6962306a36Sopenharmony_ci		pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_6;
7062306a36Sopenharmony_ci		offset = offsetof(struct scratch_reg_conf, grp6_pte);
7162306a36Sopenharmony_ci		stream->reg_offset = PTE_GRP6_OFFSET;
7262306a36Sopenharmony_ci		break;
7362306a36Sopenharmony_ci	case 7:
7462306a36Sopenharmony_ci		pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_7;
7562306a36Sopenharmony_ci		pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_7;
7662306a36Sopenharmony_ci		offset = offsetof(struct scratch_reg_conf, grp7_pte);
7762306a36Sopenharmony_ci		stream->reg_offset = PTE_GRP7_OFFSET;
7862306a36Sopenharmony_ci		break;
7962306a36Sopenharmony_ci	case 8:
8062306a36Sopenharmony_ci		pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_8;
8162306a36Sopenharmony_ci		pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_8;
8262306a36Sopenharmony_ci		offset = offsetof(struct scratch_reg_conf, grp8_pte);
8362306a36Sopenharmony_ci		stream->reg_offset = PTE_GRP8_OFFSET;
8462306a36Sopenharmony_ci		break;
8562306a36Sopenharmony_ci	default:
8662306a36Sopenharmony_ci		dev_err(sdev->dev, "Invalid stream tag %d\n", stream_tag);
8762306a36Sopenharmony_ci		return -EINVAL;
8862306a36Sopenharmony_ci	}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	/* write phy_addr in scratch memory */
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	phy_addr_offset = sdev->debug_box.offset +
9362306a36Sopenharmony_ci			  offsetof(struct scratch_reg_conf, reg_offset);
9462306a36Sopenharmony_ci	index = stream_tag - 1;
9562306a36Sopenharmony_ci	phy_addr_offset = phy_addr_offset + index * 4;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 +
9862306a36Sopenharmony_ci			  phy_addr_offset, stream->reg_offset);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	/* Group Enable */
10162306a36Sopenharmony_ci	offset = offset + sdev->debug_box.offset;
10262306a36Sopenharmony_ci	reg_val = desc->sram_pte_offset + offset;
10362306a36Sopenharmony_ci	snd_sof_dsp_write(sdev, ACP_DSP_BAR, pte_reg, reg_val | BIT(31));
10462306a36Sopenharmony_ci	snd_sof_dsp_write(sdev, ACP_DSP_BAR, pte_size, PAGE_SIZE_4K_ENABLE);
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	for (page_idx = 0; page_idx < stream->num_pages; page_idx++) {
10762306a36Sopenharmony_ci		addr = snd_sgbuf_get_addr(stream->dmab, page_idx * PAGE_SIZE);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci		/* Load the low address of page int ACP SRAM through SRBM */
11062306a36Sopenharmony_ci		low = lower_32_bits(addr);
11162306a36Sopenharmony_ci		high = upper_32_bits(addr);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci		snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + offset, low);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci		high |= BIT(31);
11662306a36Sopenharmony_ci		snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + offset + 4, high);
11762306a36Sopenharmony_ci		/* Move to next physically contiguous page */
11862306a36Sopenharmony_ci		offset += 8;
11962306a36Sopenharmony_ci	}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	/* Flush ATU Cache after PTE Update */
12262306a36Sopenharmony_ci	snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACPAXI2AXI_ATU_CTRL, ACP_ATU_CACHE_INVALID);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	return 0;
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistruct acp_dsp_stream *acp_dsp_stream_get(struct snd_sof_dev *sdev, int tag)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	struct acp_dev_data *adata = sdev->pdata->hw_pdata;
13062306a36Sopenharmony_ci	struct acp_dsp_stream *stream = adata->stream_buf;
13162306a36Sopenharmony_ci	int i;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	for (i = 0; i < ACP_MAX_STREAM; i++, stream++) {
13462306a36Sopenharmony_ci		if (stream->active)
13562306a36Sopenharmony_ci			continue;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci		/* return stream if tag not specified*/
13862306a36Sopenharmony_ci		if (!tag) {
13962306a36Sopenharmony_ci			stream->active = 1;
14062306a36Sopenharmony_ci			return stream;
14162306a36Sopenharmony_ci		}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci		/* check if this is the requested stream tag */
14462306a36Sopenharmony_ci		if (stream->stream_tag == tag) {
14562306a36Sopenharmony_ci			stream->active = 1;
14662306a36Sopenharmony_ci			return stream;
14762306a36Sopenharmony_ci		}
14862306a36Sopenharmony_ci	}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	dev_err(sdev->dev, "stream %d active or no inactive stream\n", tag);
15162306a36Sopenharmony_ci	return NULL;
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ciEXPORT_SYMBOL_NS(acp_dsp_stream_get, SND_SOC_SOF_AMD_COMMON);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ciint acp_dsp_stream_put(struct snd_sof_dev *sdev,
15662306a36Sopenharmony_ci		       struct acp_dsp_stream *acp_stream)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	struct acp_dev_data *adata = sdev->pdata->hw_pdata;
15962306a36Sopenharmony_ci	struct acp_dsp_stream *stream = adata->stream_buf;
16062306a36Sopenharmony_ci	int i;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	/* Free an active stream */
16362306a36Sopenharmony_ci	for (i = 0; i < ACP_MAX_STREAM; i++, stream++) {
16462306a36Sopenharmony_ci		if (stream == acp_stream) {
16562306a36Sopenharmony_ci			stream->active = 0;
16662306a36Sopenharmony_ci			return 0;
16762306a36Sopenharmony_ci		}
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	dev_err(sdev->dev, "Cannot find active stream tag %d\n", acp_stream->stream_tag);
17162306a36Sopenharmony_ci	return -EINVAL;
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ciEXPORT_SYMBOL_NS(acp_dsp_stream_put, SND_SOC_SOF_AMD_COMMON);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ciint acp_dsp_stream_init(struct snd_sof_dev *sdev)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	struct acp_dev_data *adata = sdev->pdata->hw_pdata;
17862306a36Sopenharmony_ci	int i;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	for (i = 0; i < ACP_MAX_STREAM; i++) {
18162306a36Sopenharmony_ci		adata->stream_buf[i].sdev = sdev;
18262306a36Sopenharmony_ci		adata->stream_buf[i].active = 0;
18362306a36Sopenharmony_ci		adata->stream_buf[i].stream_tag = i + 1;
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci	return 0;
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ciEXPORT_SYMBOL_NS(acp_dsp_stream_init, SND_SOC_SOF_AMD_COMMON);
188