@@ -11,10 +11,57 @@
#ifndef _ACP_DSP_IP_OFFSET_H
#define _ACP_DSP_IP_OFFSET_H
+/* Registers from ACP_DMA_0 block */
+#define ACP_DMA_CNTL_0 0x00
+#define ACP_DMA_DSCR_STRT_IDX_0 0x20
+#define ACP_DMA_DSCR_CNT_0 0x40
+#define ACP_DMA_PRIO_0 0x60
+#define ACP_DMA_CUR_DSCR_0 0x80
+#define ACP_DMA_ERR_STS_0 0xC0
+#define ACP_DMA_DESC_BASE_ADDR 0xE0
+#define ACP_DMA_DESC_MAX_NUM_DSCR 0xE4
+#define ACP_DMA_CH_STS 0xE8
+#define ACP_DMA_CH_GROUP 0xEC
+#define ACP_DMA_CH_RST_STS 0xF0
+
+/* Registers from ACP_AXI2AXIATU block */
+#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1 0xC00
+#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_1 0xC04
+#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_2 0xC08
+#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_2 0xC0C
+#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_3 0xC10
+#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_3 0xC14
+#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_4 0xC18
+#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_4 0xC1C
+#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5 0xC20
+#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_5 0xC24
+#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_6 0xC28
+#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_6 0xC2C
+#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_7 0xC30
+#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_7 0xC34
+#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_8 0xC38
+#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_8 0xC3C
+#define ACPAXI2AXI_ATU_CTRL 0xC40
#define ACP_SOFT_RESET 0x1000
/* Registers from ACP_PGFSM block */
#define ACP_PGFSM_CONTROL 0x141C
#define ACP_PGFSM_STATUS 0x1420
+/* Registers from ACP_INTR block */
+#define ACP_DSP_SW_INTR_CNTL 0x1814
+#define ACP_ERROR_STATUS 0x18C4
+
+/* Registers from ACP_SHA block */
+#define ACP_SHA_DSP_FW_QUALIFIER 0x1C70
+#define ACP_SHA_DMA_CMD 0x1CB0
+#define ACP_SHA_MSG_LENGTH 0x1CB4
+#define ACP_SHA_DMA_STRT_ADDR 0x1CB8
+#define ACP_SHA_DMA_DESTINATION_ADDR 0x1CBC
+#define ACP_SHA_DMA_CMD_STS 0x1CC0
+#define ACP_SHA_DMA_ERR_STATUS 0x1CC4
+#define ACP_SHA_TRANSFER_BYTE_CNT 0x1CC8
+
+#define ACP_SCRATCH_REG_0 0x10000
+
#endif
@@ -20,6 +20,219 @@
#include "acp.h"
#include "acp-dsp-offset.h"
+static void configure_acp_groupregisters(struct acp_dev_data *adata)
+{
+ struct snd_sof_dev *sdev = adata->dev;
+
+ /* Group Enable */
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACPAXI2AXI_ATU_BASE_ADDR_GRP_1,
+ ACP_SRAM_PTE_OFFSET | BIT(31));
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1,
+ PAGE_SIZE_4K_ENABLE);
+
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACPAXI2AXI_ATU_CTRL, ACP_ATU_CACHE_INVALID);
+}
+
+static void init_dma_descriptor(struct acp_dev_data *adata)
+{
+ struct snd_sof_dev *sdev = adata->dev;
+ unsigned int addr;
+
+ addr = ACP_SRAM_PTE_OFFSET + offsetof(struct scratch_reg_conf, dma_desc);
+
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_DESC_BASE_ADDR, addr);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_DESC_MAX_NUM_DSCR, ACP_MAX_DESC_CNT);
+}
+
+static void configure_dma_descriptor(struct acp_dev_data *adata, unsigned short idx,
+ struct dma_descriptor *dscr_info)
+{
+ struct snd_sof_dev *sdev = adata->dev;
+ unsigned int offset;
+
+ offset = ACP_SCRATCH_REG_0 + offsetof(struct scratch_reg_conf, dma_desc) +
+ idx * sizeof(struct dma_descriptor);
+
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, offset, dscr_info->src_addr);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, offset + 0x4, dscr_info->dest_addr);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, offset + 0x8, dscr_info->tx_cnt.u32_all);
+}
+
+static int config_dma_channel(struct acp_dev_data *adata, unsigned int ch,
+ unsigned int idx, unsigned int dscr_count)
+{
+ struct snd_sof_dev *sdev = adata->dev;
+ unsigned int val, status;
+ int ret;
+
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_CNTL_0 + ch * sizeof(u32),
+ ACP_DMA_CH_RST | ACP_DMA_CH_GRACEFUL_RST_EN);
+
+ ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_DMA_CH_RST_STS, val,
+ val & (1 << ch), ACP_REG_POLL_INTERVAL,
+ ACP_REG_POLL_TIMEOUT_US);
+ if (ret < 0) {
+ status = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_ERROR_STATUS);
+ val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_DMA_ERR_STS_0 + ch * sizeof(u32));
+
+ dev_err(sdev->dev, "ACP_DMA_ERR_STS :0x%x ACP_ERROR_STATUS :0x%x\n", val, status);
+ return ret;
+ }
+
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, (ACP_DMA_CNTL_0 + ch * sizeof(u32)), 0);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_DSCR_CNT_0 + ch * sizeof(u32), dscr_count);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_DSCR_STRT_IDX_0 + ch * sizeof(u32), idx);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_PRIO_0 + ch * sizeof(u32), 0);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_CNTL_0 + ch * sizeof(u32), ACP_DMA_CH_RUN);
+
+ return ret;
+}
+
+static int acpbus_dma_start(struct acp_dev_data *adata, unsigned int ch,
+ unsigned int dscr_count, struct dma_descriptor *dscr_info)
+{
+ struct snd_sof_dev *sdev = adata->dev;
+ int ret;
+ u16 dscr;
+
+ if (!dscr_info || !dscr_count)
+ return -EINVAL;
+
+ for (dscr = 0; dscr < dscr_count; dscr++)
+ configure_dma_descriptor(adata, dscr, dscr_info++);
+
+ ret = config_dma_channel(adata, ch, 0, dscr_count);
+ if (ret < 0)
+ dev_err(sdev->dev, "config dma ch failed:%d\n", ret);
+
+ return ret;
+}
+
+int configure_and_run_dma(struct acp_dev_data *adata, unsigned int src_addr,
+ unsigned int dest_addr, int dsp_data_size)
+{
+ struct snd_sof_dev *sdev = adata->dev;
+ unsigned int desc_count, index;
+ int ret;
+
+ for (desc_count = 0; desc_count < ACP_MAX_DESC && dsp_data_size >= 0;
+ desc_count++, dsp_data_size -= ACP_PAGE_SIZE) {
+ adata->dscr_info[desc_count].src_addr = src_addr + desc_count * ACP_PAGE_SIZE;
+ adata->dscr_info[desc_count].dest_addr = dest_addr + desc_count * ACP_PAGE_SIZE;
+ adata->dscr_info[desc_count].tx_cnt.bits.count = ACP_PAGE_SIZE;
+ if (dsp_data_size < ACP_PAGE_SIZE)
+ adata->dscr_info[desc_count].tx_cnt.bits.count = dsp_data_size;
+ }
+
+ ret = acpbus_dma_start(adata, 0, desc_count, adata->dscr_info);
+ if (ret)
+ dev_err(sdev->dev, "acpbus_dma_start failed\n");
+
+ /* Clear descriptor array */
+ for (index = 0; index < desc_count; index++)
+ memset(&adata->dscr_info[index], 0x00, sizeof(struct dma_descriptor));
+
+ return ret;
+}
+
+int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr,
+ unsigned int start_addr, unsigned int dest_addr,
+ unsigned int image_length)
+{
+ struct snd_sof_dev *sdev = adata->dev;
+ unsigned int tx_count, fw_qualifier, val;
+ int ret;
+
+ if (!image_addr) {
+ dev_err(sdev->dev, "SHA DMA image address is NULL\n");
+ return -EINVAL;
+ }
+
+ val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SHA_DMA_CMD);
+ if (val & ACP_SHA_RUN) {
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_CMD, ACP_SHA_RESET);
+ ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_SHA_DMA_CMD_STS,
+ val, val & ACP_SHA_RESET,
+ ACP_REG_POLL_INTERVAL,
+ ACP_REG_POLL_TIMEOUT_US);
+ if (ret < 0) {
+ dev_err(sdev->dev, "SHA DMA Failed to Reset\n");
+ return ret;
+ }
+ }
+
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_STRT_ADDR, start_addr);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_DESTINATION_ADDR, dest_addr);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_MSG_LENGTH, image_length);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_CMD, ACP_SHA_RUN);
+
+ ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_SHA_TRANSFER_BYTE_CNT,
+ tx_count, tx_count == image_length,
+ ACP_REG_POLL_INTERVAL, ACP_DMA_COMPLETE_TIMEOUT_US);
+ if (ret < 0) {
+ dev_err(sdev->dev, "SHA DMA Failed to Transfer Length %x\n", tx_count);
+ return ret;
+ }
+
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DSP_FW_QUALIFIER, DSP_FW_RUN_ENABLE);
+
+ fw_qualifier = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SHA_DSP_FW_QUALIFIER);
+ if (!(fw_qualifier & DSP_FW_RUN_ENABLE)) {
+ dev_err(sdev->dev, "PSP validation failed\n");
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+int acp_dma_status(struct acp_dev_data *adata, unsigned char ch)
+{
+ struct snd_sof_dev *sdev = adata->dev;
+ unsigned int val;
+ int ret = 0;
+
+ val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_DMA_CNTL_0 + ch * sizeof(u32));
+ if (val & ACP_DMA_CH_RUN) {
+ ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_DMA_CH_STS, val, !val,
+ ACP_REG_POLL_INTERVAL,
+ ACP_DMA_COMPLETE_TIMEOUT_US);
+ if (ret < 0)
+ dev_err(sdev->dev, "DMA_CHANNEL %d status timeout\n", ch);
+ }
+
+ return ret;
+}
+
+void memcpy_from_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *dst, size_t bytes)
+{
+ unsigned int reg_offset = offset + ACP_SCRATCH_REG_0;
+ int i, j;
+
+ for (i = 0, j = 0; i < bytes; i = i + 4, j++)
+ dst[j] = snd_sof_dsp_read(sdev, ACP_DSP_BAR, reg_offset + i);
+}
+
+void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes)
+{
+ unsigned int reg_offset = offset + ACP_SCRATCH_REG_0;
+ int i, j;
+
+ for (i = 0, j = 0; i < bytes; i = i + 4, j++)
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, reg_offset + i, src[j]);
+}
+
+static int acp_memory_init(struct snd_sof_dev *sdev)
+{
+ struct acp_dev_data *adata = sdev->pdata->hw_pdata;
+
+ snd_sof_dsp_update_bits(sdev, ACP_DSP_BAR, ACP_DSP_SW_INTR_CNTL,
+ ACP_DSP_INTR_EN_MASK, ACP_DSP_INTR_EN_MASK);
+ configure_acp_groupregisters(adata);
+ init_dma_descriptor(adata);
+
+ return 0;
+}
+
static int acp_power_on(struct snd_sof_dev *sdev)
{
unsigned int val;
@@ -86,6 +299,7 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev)
struct pci_dev *pci = to_pci_dev(sdev->dev);
struct acp_dev_data *adata;
unsigned int addr;
+ int ret;
adata = devm_kzalloc(sdev->dev, sizeof(struct acp_dev_data),
GFP_KERNEL);
@@ -104,7 +318,13 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev)
sdev->pdata->hw_pdata = adata;
- return acp_init(sdev);
+ ret = acp_init(sdev);
+ if (ret < 0)
+ return ret;
+
+ acp_memory_init(sdev);
+
+ return 0;
}
EXPORT_SYMBOL_NS(amd_sof_acp_probe, SND_SOC_SOF_AMD_COMMON);
@@ -15,6 +15,7 @@
#define ACP_REG_POLL_INTERVAL 500
#define ACP_REG_POLL_TIMEOUT_US 2000
+#define ACP_DMA_COMPLETE_TIMEOUT_US 5000
#define ACP_PGFSM_CNTL_POWER_ON_MASK 0x01
#define ACP_PGFSM_STATUS_MASK 0x03
@@ -23,11 +24,101 @@
#define ACP_RELEASE_RESET 0x00
#define ACP_SOFT_RESET_DONE_MASK 0x00010001
+#define ACP_DSP_INTR_EN_MASK 0x00000001
+#define ACP_SRAM_PTE_OFFSET 0x02050000
+#define PAGE_SIZE_4K_ENABLE 0x2
+#define ACP_PAGE_SIZE 0x1000
+#define ACP_DMA_CH_RUN 0x02
+#define ACP_MAX_DESC_CNT 0x02
+#define DSP_FW_RUN_ENABLE 0x01
+#define ACP_SHA_RUN 0x01
+#define ACP_SHA_RESET 0x02
+#define ACP_DMA_CH_RST 0x01
+#define ACP_DMA_CH_GRACEFUL_RST_EN 0x10
+#define ACP_ATU_CACHE_INVALID 0x01
+#define ACP_MAX_DESC 128
+#define ACPBUS_REG_BASE_OFFSET ACP_DMA_CNTL_0
+
+struct acp_atu_grp_pte {
+ u32 low;
+ u32 high;
+};
+
+union dma_tx_cnt {
+ struct {
+ unsigned int count : 19;
+ unsigned int reserved : 12;
+ unsigned ioc : 1;
+ } bitfields, bits;
+ unsigned int u32_all;
+ signed int i32_all;
+};
+
+struct dma_descriptor {
+ unsigned int src_addr;
+ unsigned int dest_addr;
+ union dma_tx_cnt tx_cnt;
+ unsigned int reserved;
+};
+
+/* Scratch memory structure for communication b/w host and dsp */
+struct scratch_ipc_conf {
+ /* DSP mailbox */
+ u8 sof_out_box[512];
+ /* Host mailbox */
+ u8 sof_in_box[512];
+ /* Debug memory */
+ u8 sof_debug_box[1024];
+ /* Exception memory*/
+ u8 sof_except_box[1024];
+ /* Stream buffer */
+ u8 sof_stream_box[1024];
+ /* Trace buffer */
+ u8 sof_trace_box[1024];
+ /* Host msg flag */
+ u32 sof_host_msg_write;
+ /* Host ack flag*/
+ u32 sof_host_ack_write;
+ /* DSP msg flag */
+ u32 sof_dsp_msg_write;
+ /* Dsp ack flag */
+ u32 sof_dsp_ack_write;
+};
+
+struct scratch_reg_conf {
+ struct scratch_ipc_conf info;
+ struct acp_atu_grp_pte grp1_pte[16];
+ struct acp_atu_grp_pte grp2_pte[16];
+ struct acp_atu_grp_pte grp3_pte[16];
+ struct acp_atu_grp_pte grp4_pte[16];
+ struct acp_atu_grp_pte grp5_pte[16];
+ struct acp_atu_grp_pte grp6_pte[16];
+ struct acp_atu_grp_pte grp7_pte[16];
+ struct acp_atu_grp_pte grp8_pte[16];
+ struct dma_descriptor dma_desc[64];
+ unsigned int reg_offset[8];
+ unsigned int buf_size[8];
+ u8 acp_tx_fifo_buf[256];
+ u8 acp_rx_fifo_buf[256];
+ unsigned int reserve[];
+};
+
/* Common device data struct for ACP devices */
struct acp_dev_data {
struct snd_sof_dev *dev;
+ struct dma_descriptor dscr_info[ACP_MAX_DESC];
};
+void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes);
+void memcpy_from_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *dst, size_t bytes);
+
+int acp_dma_status(struct acp_dev_data *adata, unsigned char ch);
+int configure_and_run_dma(struct acp_dev_data *adata, unsigned int src_addr,
+ unsigned int dest_addr, int dsp_data_size);
+int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr,
+ unsigned int start_addr, unsigned int dest_addr,
+ unsigned int image_length);
+
/* ACP device probe/remove */
int amd_sof_acp_probe(struct snd_sof_dev *sdev);
int amd_sof_acp_remove(struct snd_sof_dev *sdev);