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