188 lines · c
1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)2//3// This file is provided under a dual BSD/GPLv2 license. When using or4// redistributing this file, you may do so under either license.5//6// Copyright(c) 2021 Advanced Micro Devices, Inc.7//8// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>9 10/*11 * Hardware interface for generic AMD audio DSP ACP IP12 */13 14#include "../ops.h"15#include "acp-dsp-offset.h"16#include "acp.h"17 18#define PTE_GRP1_OFFSET 0x0000000019#define PTE_GRP2_OFFSET 0x0080000020#define PTE_GRP3_OFFSET 0x0100000021#define PTE_GRP4_OFFSET 0x0180000022#define PTE_GRP5_OFFSET 0x0200000023#define PTE_GRP6_OFFSET 0x0280000024#define PTE_GRP7_OFFSET 0x0300000025#define PTE_GRP8_OFFSET 0x0380000026 27int acp_dsp_stream_config(struct snd_sof_dev *sdev, struct acp_dsp_stream *stream)28{29 const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);30 unsigned int pte_reg, pte_size, phy_addr_offset, index;31 int stream_tag = stream->stream_tag;32 u32 low, high, offset, reg_val;33 dma_addr_t addr;34 int page_idx;35 36 switch (stream_tag) {37 case 1:38 pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_1;39 pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1;40 offset = offsetof(struct scratch_reg_conf, grp1_pte);41 stream->reg_offset = PTE_GRP1_OFFSET;42 break;43 case 2:44 pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_2;45 pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_2;46 offset = offsetof(struct scratch_reg_conf, grp2_pte);47 stream->reg_offset = PTE_GRP2_OFFSET;48 break;49 case 3:50 pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_3;51 pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_3;52 offset = offsetof(struct scratch_reg_conf, grp3_pte);53 stream->reg_offset = PTE_GRP3_OFFSET;54 break;55 case 4:56 pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_4;57 pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_4;58 offset = offsetof(struct scratch_reg_conf, grp4_pte);59 stream->reg_offset = PTE_GRP4_OFFSET;60 break;61 case 5:62 pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_5;63 pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5;64 offset = offsetof(struct scratch_reg_conf, grp5_pte);65 stream->reg_offset = PTE_GRP5_OFFSET;66 break;67 case 6:68 pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_6;69 pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_6;70 offset = offsetof(struct scratch_reg_conf, grp6_pte);71 stream->reg_offset = PTE_GRP6_OFFSET;72 break;73 case 7:74 pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_7;75 pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_7;76 offset = offsetof(struct scratch_reg_conf, grp7_pte);77 stream->reg_offset = PTE_GRP7_OFFSET;78 break;79 case 8:80 pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_8;81 pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_8;82 offset = offsetof(struct scratch_reg_conf, grp8_pte);83 stream->reg_offset = PTE_GRP8_OFFSET;84 break;85 default:86 dev_err(sdev->dev, "Invalid stream tag %d\n", stream_tag);87 return -EINVAL;88 }89 90 /* write phy_addr in scratch memory */91 92 phy_addr_offset = sdev->debug_box.offset +93 offsetof(struct scratch_reg_conf, reg_offset);94 index = stream_tag - 1;95 phy_addr_offset = phy_addr_offset + index * 4;96 97 snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 +98 phy_addr_offset, stream->reg_offset);99 100 /* Group Enable */101 offset = offset + sdev->debug_box.offset;102 reg_val = desc->sram_pte_offset + offset;103 snd_sof_dsp_write(sdev, ACP_DSP_BAR, pte_reg, reg_val | BIT(31));104 snd_sof_dsp_write(sdev, ACP_DSP_BAR, pte_size, PAGE_SIZE_4K_ENABLE);105 106 for (page_idx = 0; page_idx < stream->num_pages; page_idx++) {107 addr = snd_sgbuf_get_addr(stream->dmab, page_idx * PAGE_SIZE);108 109 /* Load the low address of page int ACP SRAM through SRBM */110 low = lower_32_bits(addr);111 high = upper_32_bits(addr);112 113 snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + offset, low);114 115 high |= BIT(31);116 snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + offset + 4, high);117 /* Move to next physically contiguous page */118 offset += 8;119 }120 121 /* Flush ATU Cache after PTE Update */122 snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACPAXI2AXI_ATU_CTRL, ACP_ATU_CACHE_INVALID);123 124 return 0;125}126 127struct acp_dsp_stream *acp_dsp_stream_get(struct snd_sof_dev *sdev, int tag)128{129 struct acp_dev_data *adata = sdev->pdata->hw_pdata;130 struct acp_dsp_stream *stream = adata->stream_buf;131 int i;132 133 for (i = 0; i < ACP_MAX_STREAM; i++, stream++) {134 if (stream->active)135 continue;136 137 /* return stream if tag not specified*/138 if (!tag) {139 stream->active = 1;140 return stream;141 }142 143 /* check if this is the requested stream tag */144 if (stream->stream_tag == tag) {145 stream->active = 1;146 return stream;147 }148 }149 150 dev_err(sdev->dev, "stream %d active or no inactive stream\n", tag);151 return NULL;152}153EXPORT_SYMBOL_NS(acp_dsp_stream_get, SND_SOC_SOF_AMD_COMMON);154 155int acp_dsp_stream_put(struct snd_sof_dev *sdev,156 struct acp_dsp_stream *acp_stream)157{158 struct acp_dev_data *adata = sdev->pdata->hw_pdata;159 struct acp_dsp_stream *stream = adata->stream_buf;160 int i;161 162 /* Free an active stream */163 for (i = 0; i < ACP_MAX_STREAM; i++, stream++) {164 if (stream == acp_stream) {165 stream->active = 0;166 return 0;167 }168 }169 170 dev_err(sdev->dev, "Cannot find active stream tag %d\n", acp_stream->stream_tag);171 return -EINVAL;172}173EXPORT_SYMBOL_NS(acp_dsp_stream_put, SND_SOC_SOF_AMD_COMMON);174 175int acp_dsp_stream_init(struct snd_sof_dev *sdev)176{177 struct acp_dev_data *adata = sdev->pdata->hw_pdata;178 int i;179 180 for (i = 0; i < ACP_MAX_STREAM; i++) {181 adata->stream_buf[i].sdev = sdev;182 adata->stream_buf[i].active = 0;183 adata->stream_buf[i].stream_tag = i + 1;184 }185 return 0;186}187EXPORT_SYMBOL_NS(acp_dsp_stream_init, SND_SOC_SOF_AMD_COMMON);188