diff options
Diffstat (limited to 'meta-amdfalconx86/recipes-kernel/linux/files/1127-ASoC-AMD-add-AMD-ASoC-ACP-2.x-DMA-driver.patch')
-rw-r--r-- | meta-amdfalconx86/recipes-kernel/linux/files/1127-ASoC-AMD-add-AMD-ASoC-ACP-2.x-DMA-driver.patch | 1092 |
1 files changed, 1092 insertions, 0 deletions
diff --git a/meta-amdfalconx86/recipes-kernel/linux/files/1127-ASoC-AMD-add-AMD-ASoC-ACP-2.x-DMA-driver.patch b/meta-amdfalconx86/recipes-kernel/linux/files/1127-ASoC-AMD-add-AMD-ASoC-ACP-2.x-DMA-driver.patch new file mode 100644 index 00000000..6ad546e3 --- /dev/null +++ b/meta-amdfalconx86/recipes-kernel/linux/files/1127-ASoC-AMD-add-AMD-ASoC-ACP-2.x-DMA-driver.patch @@ -0,0 +1,1092 @@ +From e3a10e5c1dd68d0a0133023084f15aa05662090c Mon Sep 17 00:00:00 2001 +From: Maruthi Srinivas Bayyavarapu <Maruthi.Bayyavarapu@amd.com> +Date: Tue, 24 Nov 2015 11:54:50 +0530 +Subject: [PATCH 02/17] ASoC: AMD: add AMD ASoC ACP 2.x DMA driver + +ACP IP has internal DMA controller with multiple channels which +can be programmed in cyclic/non cyclic manner. ACP can generate +interrupt upon completion of DMA transfer, if required. +The PCM driver provides the platform DMA component to ALSA core. + +Signed-off-by: Maruthi Bayyavarapu <maruthi.bayyavarapu@amd.com> +Reviewed-by: Alex Deucher <alexander.deucher@amd.com> +Reviewed-by: Murali Krishna Vemuri <murali-krishna.vemuri@amd.com> +Signed-off-by: Alex Deucher <alexander.deucher@amd.com> +Signed-off-by: Kalyan Alle <kalyan.alle@amd.com> +--- + sound/soc/amd/Kconfig | 4 + + sound/soc/amd/Makefile | 3 + + sound/soc/amd/acp-pcm-dma.c | 914 ++++++++++++++++++++++++++++++++++++++++++++ + sound/soc/amd/acp.h | 118 ++++++ + 4 files changed, 1039 insertions(+) + create mode 100644 sound/soc/amd/Kconfig + create mode 100644 sound/soc/amd/Makefile + create mode 100644 sound/soc/amd/acp-pcm-dma.c + create mode 100644 sound/soc/amd/acp.h + +diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig +new file mode 100644 +index 0000000..78187eb +--- /dev/null ++++ b/sound/soc/amd/Kconfig +@@ -0,0 +1,4 @@ ++config SND_SOC_AMD_ACP ++ tristate "AMD Audio Coprocessor support" ++ help ++ This option enables ACP DMA support on AMD platform. +diff --git a/sound/soc/amd/Makefile b/sound/soc/amd/Makefile +new file mode 100644 +index 0000000..1a66ec0 +--- /dev/null ++++ b/sound/soc/amd/Makefile +@@ -0,0 +1,3 @@ ++snd-soc-acp-pcm-objs := acp-pcm-dma.o ++ ++obj-$(CONFIG_SND_SOC_AMD_ACP) += snd-soc-acp-pcm.o +diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c +new file mode 100644 +index 0000000..0724d78 +--- /dev/null ++++ b/sound/soc/amd/acp-pcm-dma.c +@@ -0,0 +1,914 @@ ++/* ++ * AMD ALSA SoC PCM Driver for ACP 2.x ++ * ++ * Copyright 2014-2015 Advanced Micro Devices, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ */ ++ ++#include <linux/module.h> ++#include <linux/delay.h> ++#include <linux/sizes.h> ++ ++#include <sound/soc.h> ++ ++#include "acp.h" ++ ++#define PLAYBACK_MIN_NUM_PERIODS 2 ++#define PLAYBACK_MAX_NUM_PERIODS 2 ++#define PLAYBACK_MAX_PERIOD_SIZE 16384 ++#define PLAYBACK_MIN_PERIOD_SIZE 1024 ++#define CAPTURE_MIN_NUM_PERIODS 2 ++#define CAPTURE_MAX_NUM_PERIODS 2 ++#define CAPTURE_MAX_PERIOD_SIZE 16384 ++#define CAPTURE_MIN_PERIOD_SIZE 1024 ++ ++#define MAX_BUFFER (PLAYBACK_MAX_PERIOD_SIZE * PLAYBACK_MAX_NUM_PERIODS) ++#define MIN_BUFFER MAX_BUFFER ++ ++static const struct snd_pcm_hardware acp_pcm_hardware_playback = { ++ .info = SNDRV_PCM_INFO_INTERLEAVED | ++ SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | ++ SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH | ++ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE | ++ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, ++ .channels_min = 1, ++ .channels_max = 8, ++ .rates = SNDRV_PCM_RATE_8000_96000, ++ .rate_min = 8000, ++ .rate_max = 96000, ++ .buffer_bytes_max = PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE, ++ .period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE, ++ .period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE, ++ .periods_min = PLAYBACK_MIN_NUM_PERIODS, ++ .periods_max = PLAYBACK_MAX_NUM_PERIODS, ++}; ++ ++static const struct snd_pcm_hardware acp_pcm_hardware_capture = { ++ .info = SNDRV_PCM_INFO_INTERLEAVED | ++ SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | ++ SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH | ++ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE | ++ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, ++ .channels_min = 1, ++ .channels_max = 2, ++ .rates = SNDRV_PCM_RATE_8000_48000, ++ .rate_min = 8000, ++ .rate_max = 48000, ++ .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE, ++ .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE, ++ .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE, ++ .periods_min = CAPTURE_MIN_NUM_PERIODS, ++ .periods_max = CAPTURE_MAX_NUM_PERIODS, ++}; ++ ++struct audio_drv_data { ++ struct snd_pcm_substream *play_stream; ++ struct snd_pcm_substream *capture_stream; ++ void __iomem *acp_mmio; ++}; ++ ++static u32 acp_reg_read(void __iomem *acp_mmio, u32 reg) ++{ ++ return readl(acp_mmio + (reg * 4)); ++} ++ ++static void acp_reg_write(u32 val, void __iomem *acp_mmio, u32 reg) ++{ ++ writel(val, acp_mmio + (reg * 4)); ++} ++ ++/* Configure a given dma channel parameters - enable/disble, ++ * number of descriptors, priority ++ */ ++static void config_acp_dma_channel(void __iomem *acp_mmio, u8 ch_num, ++ u16 dscr_strt_idx, u16 num_dscrs, ++ enum acp_dma_priority_level priority_level) ++{ ++ u32 dma_ctrl; ++ ++ /* disable the channel run field */ ++ dma_ctrl = acp_reg_read(acp_mmio, mmACP_DMA_CNTL_0 + ch_num); ++ dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChRun_MASK; ++ acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num); ++ ++ /* program a DMA channel with first descriptor to be processed. */ ++ acp_reg_write((ACP_DMA_DSCR_STRT_IDX_0__DMAChDscrStrtIdx_MASK ++ & dscr_strt_idx), ++ acp_mmio, mmACP_DMA_DSCR_STRT_IDX_0 + ch_num); ++ ++ /* program a DMA channel with the number of descriptors to be ++ * processed in the transfer ++ */ ++ acp_reg_write(ACP_DMA_DSCR_CNT_0__DMAChDscrCnt_MASK & num_dscrs, ++ acp_mmio, mmACP_DMA_DSCR_CNT_0 + ch_num); ++ ++ /* set DMA channel priority */ ++ acp_reg_write(priority_level, acp_mmio, mmACP_DMA_PRIO_0 + ch_num); ++} ++ ++/* Initialize a dma descriptor in SRAM based on descritor information passed */ ++static void config_dma_descriptor_in_sram(void __iomem *acp_mmio, ++ u16 descr_idx, ++ acp_dma_dscr_transfer_t *descr_info) ++{ ++ u32 sram_offset; ++ ++ sram_offset = (descr_idx * sizeof(acp_dma_dscr_transfer_t)); ++ ++ /* program the source base address. */ ++ acp_reg_write(sram_offset, acp_mmio, mmACP_SRBM_Targ_Idx_Addr); ++ acp_reg_write(descr_info->src, acp_mmio, mmACP_SRBM_Targ_Idx_Data); ++ /* program the destination base address. */ ++ acp_reg_write(sram_offset + 4, acp_mmio, mmACP_SRBM_Targ_Idx_Addr); ++ acp_reg_write(descr_info->dest, acp_mmio, mmACP_SRBM_Targ_Idx_Data); ++ ++ /* program the number of bytes to be transferred for this descriptor. */ ++ acp_reg_write(sram_offset + 8, acp_mmio, mmACP_SRBM_Targ_Idx_Addr); ++ acp_reg_write(descr_info->xfer_val, acp_mmio, mmACP_SRBM_Targ_Idx_Data); ++} ++ ++/* Initialize the DMA descriptor information for transfer between ++ * system memory <-> ACP SRAM ++ */ ++static void set_acp_sysmem_dma_descriptors(void __iomem *acp_mmio, ++ u32 size, int direction, ++ u32 pte_offset) ++{ ++ u16 i; ++ u16 dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12; ++ acp_dma_dscr_transfer_t dmadscr[NUM_DSCRS_PER_CHANNEL]; ++ ++ for (i = 0; i < NUM_DSCRS_PER_CHANNEL; i++) { ++ dmadscr[i].xfer_val = 0; ++ if (direction == SNDRV_PCM_STREAM_PLAYBACK) { ++ dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12 + i; ++ dmadscr[i].dest = ACP_SHARED_RAM_BANK_1_ADDRESS + ++ (size / 2) - (i * (size/2)); ++ dmadscr[i].src = ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS ++ + (pte_offset * SZ_4K) + (i * (size/2)); ++ dmadscr[i].xfer_val |= ++ (ACP_DMA_ATTRIBUTES_DAGB_ONION_TO_SHAREDMEM << 16) | ++ (size / 2); ++ } else { ++ dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH14 + i; ++ dmadscr[i].src = ACP_SHARED_RAM_BANK_5_ADDRESS + ++ (i * (size/2)); ++ dmadscr[i].dest = ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS ++ + (pte_offset * SZ_4K) + ++ (i * (size/2)); ++ dmadscr[i].xfer_val |= ++ BIT(22) | ++ (ACP_DMA_ATTRIBUTES_SHAREDMEM_TO_DAGB_ONION << 16) | ++ (size / 2); ++ } ++ config_dma_descriptor_in_sram(acp_mmio, dma_dscr_idx, ++ &dmadscr[i]); ++ } ++ if (direction == SNDRV_PCM_STREAM_PLAYBACK) ++ config_acp_dma_channel(acp_mmio, SYSRAM_TO_ACP_CH_NUM, ++ PLAYBACK_START_DMA_DESCR_CH12, ++ NUM_DSCRS_PER_CHANNEL, ++ ACP_DMA_PRIORITY_LEVEL_NORMAL); ++ else ++ config_acp_dma_channel(acp_mmio, ACP_TO_SYSRAM_CH_NUM, ++ CAPTURE_START_DMA_DESCR_CH14, ++ NUM_DSCRS_PER_CHANNEL, ++ ACP_DMA_PRIORITY_LEVEL_NORMAL); ++} ++ ++/* Initialize the DMA descriptor information for transfer between ++ * ACP SRAM <-> I2S ++ */ ++static void set_acp_to_i2s_dma_descriptors(void __iomem *acp_mmio, ++ u32 size, int direction) ++{ ++ ++ u16 i; ++ u16 dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH13; ++ acp_dma_dscr_transfer_t dmadscr[NUM_DSCRS_PER_CHANNEL]; ++ ++ for (i = 0; i < NUM_DSCRS_PER_CHANNEL; i++) { ++ dmadscr[i].xfer_val = 0; ++ if (direction == SNDRV_PCM_STREAM_PLAYBACK) { ++ dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH13 + i; ++ dmadscr[i].src = ACP_SHARED_RAM_BANK_1_ADDRESS + ++ (i * (size/2)); ++ /* dmadscr[i].dest is unused by hardware. */ ++ dmadscr[i].dest = 0; ++ dmadscr[i].xfer_val |= BIT(22) | (TO_ACP_I2S_1 << 16) | ++ (size / 2); ++ } else { ++ dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH15 + i; ++ /* dmadscr[i].src is unused by hardware. */ ++ dmadscr[i].src = 0; ++ dmadscr[i].dest = ACP_SHARED_RAM_BANK_5_ADDRESS + ++ (i * (size / 2)); ++ dmadscr[i].xfer_val |= BIT(22) | ++ (FROM_ACP_I2S_1 << 16) | (size / 2); ++ } ++ config_dma_descriptor_in_sram(acp_mmio, dma_dscr_idx, ++ &dmadscr[i]); ++ } ++ /* Configure the DMA channel with the above descriptore */ ++ if (direction == SNDRV_PCM_STREAM_PLAYBACK) ++ config_acp_dma_channel(acp_mmio, ACP_TO_I2S_DMA_CH_NUM, ++ PLAYBACK_START_DMA_DESCR_CH13, ++ NUM_DSCRS_PER_CHANNEL, ++ ACP_DMA_PRIORITY_LEVEL_NORMAL); ++ else ++ config_acp_dma_channel(acp_mmio, I2S_TO_ACP_DMA_CH_NUM, ++ CAPTURE_START_DMA_DESCR_CH15, ++ NUM_DSCRS_PER_CHANNEL, ++ ACP_DMA_PRIORITY_LEVEL_NORMAL); ++} ++ ++/* Create page table entries in ACP SRAM for the allocated memory */ ++static void acp_pte_config(void __iomem *acp_mmio, struct page *pg, ++ u16 num_of_pages, u32 pte_offset) ++{ ++ u16 page_idx; ++ u64 addr; ++ u32 low; ++ u32 high; ++ u32 offset; ++ ++ offset = ACP_DAGB_GRP_SRBM_SRAM_BASE_OFFSET + (pte_offset * 8); ++ for (page_idx = 0; page_idx < (num_of_pages); page_idx++) { ++ /* Load the low address of page int ACP SRAM through SRBM */ ++ acp_reg_write((offset + (page_idx * 8)), ++ acp_mmio, mmACP_SRBM_Targ_Idx_Addr); ++ addr = page_to_phys(pg); ++ ++ low = lower_32_bits(addr); ++ high = upper_32_bits(addr); ++ ++ acp_reg_write(low, acp_mmio, mmACP_SRBM_Targ_Idx_Data); ++ ++ /* Load the High address of page int ACP SRAM through SRBM */ ++ acp_reg_write((offset + (page_idx * 8) + 4), ++ acp_mmio, mmACP_SRBM_Targ_Idx_Addr); ++ ++ /* page enable in ACP */ ++ high |= BIT(31); ++ acp_reg_write(high, acp_mmio, mmACP_SRBM_Targ_Idx_Data); ++ ++ /* Move to next physically contiguos page */ ++ pg++; ++ } ++} ++ ++static void config_acp_dma(void __iomem *acp_mmio, ++ struct audio_substream_data *audio_config) ++{ ++ u32 pte_offset; ++ ++ if (audio_config->direction == SNDRV_PCM_STREAM_PLAYBACK) ++ pte_offset = ACP_PLAYBACK_PTE_OFFSET; ++ else ++ pte_offset = ACP_CAPTURE_PTE_OFFSET; ++ ++ acp_pte_config(acp_mmio, audio_config->pg, audio_config->num_of_pages, ++ pte_offset); ++ ++ /* Configure System memory <-> ACP SRAM DMA descriptors */ ++ set_acp_sysmem_dma_descriptors(acp_mmio, audio_config->size, ++ audio_config->direction, pte_offset); ++ ++ /* Configure ACP SRAM <-> I2S DMA descriptors */ ++ set_acp_to_i2s_dma_descriptors(acp_mmio, audio_config->size, ++ audio_config->direction); ++} ++ ++/* Start a given DMA channel transfer */ ++static void acp_dma_start(void __iomem *acp_mmio, ++ u16 ch_num, bool is_circular) ++{ ++ u32 dma_ctrl; ++ ++ /* read the dma control register and disable the channel run field */ ++ dma_ctrl = acp_reg_read(acp_mmio, mmACP_DMA_CNTL_0 + ch_num); ++ ++ /* Invalidating the DAGB cache */ ++ acp_reg_write(1, acp_mmio, mmACP_DAGB_ATU_CTRL); ++ ++ /* configure the DMA channel and start the DMA transfer ++ * set dmachrun bit to start the transfer and enable the ++ * interrupt on completion of the dma transfer ++ */ ++ dma_ctrl |= ACP_DMA_CNTL_0__DMAChRun_MASK; ++ ++ switch (ch_num) { ++ case ACP_TO_I2S_DMA_CH_NUM: ++ case ACP_TO_SYSRAM_CH_NUM: ++ case I2S_TO_ACP_DMA_CH_NUM: ++ dma_ctrl |= ACP_DMA_CNTL_0__DMAChIOCEn_MASK; ++ break; ++ default: ++ dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChIOCEn_MASK; ++ break; ++ } ++ ++ /* enable for ACP SRAM to/from I2S DMA channel */ ++ if (is_circular == true) ++ dma_ctrl |= ACP_DMA_CNTL_0__Circular_DMA_En_MASK; ++ else ++ dma_ctrl &= ~ACP_DMA_CNTL_0__Circular_DMA_En_MASK; ++ ++ acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num); ++} ++ ++/* Stop a given DMA channel transfer */ ++static int acp_dma_stop(void __iomem *acp_mmio, u8 ch_num) ++{ ++ u32 dma_ctrl; ++ u32 dma_ch_sts; ++ u32 count = ACP_DMA_RESET_TIME; ++ ++ dma_ctrl = acp_reg_read(acp_mmio, mmACP_DMA_CNTL_0 + ch_num); ++ ++ /* clear the dma control register fields before writing zero ++ * in reset bit ++ */ ++ dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChRun_MASK; ++ dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChIOCEn_MASK; ++ ++ acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num); ++ dma_ch_sts = acp_reg_read(acp_mmio, mmACP_DMA_CH_STS); ++ ++ if (dma_ch_sts & BIT(ch_num)) { ++ /* set the reset bit for this channel to stop the dma ++ * transfer ++ */ ++ dma_ctrl |= ACP_DMA_CNTL_0__DMAChRst_MASK; ++ acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num); ++ } ++ ++ /* check the channel status bit for some time and return the status */ ++ while (true) { ++ dma_ch_sts = acp_reg_read(acp_mmio, mmACP_DMA_CH_STS); ++ if (!(dma_ch_sts & BIT(ch_num))) { ++ /* clear the reset flag after successfully stopping ++ * the dma transfer and break from the loop ++ */ ++ dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChRst_MASK; ++ ++ acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 ++ + ch_num); ++ break; ++ } ++ if (--count == 0) { ++ pr_err("Failed to stop ACP DMA channel : %d\n", ch_num); ++ return -ETIMEDOUT; ++ } ++ udelay(100); ++ } ++ return 0; ++} ++ ++/* Initialize and bring ACP hardware to default state. */ ++static int acp_init(void __iomem *acp_mmio) ++{ ++ u32 val, count, sram_pte_offset; ++ ++ /* Assert Soft reset of ACP */ ++ val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET); ++ ++ val |= ACP_SOFT_RESET__SoftResetAud_MASK; ++ acp_reg_write(val, acp_mmio, mmACP_SOFT_RESET); ++ ++ count = ACP_SOFT_RESET_DONE_TIME_OUT_VALUE; ++ while (true) { ++ val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET); ++ if (ACP_SOFT_RESET__SoftResetAudDone_MASK == ++ (val & ACP_SOFT_RESET__SoftResetAudDone_MASK)) ++ break; ++ if (--count == 0) { ++ pr_err("Failed to reset ACP\n"); ++ return -ETIMEDOUT; ++ } ++ udelay(100); ++ } ++ ++ /* Enable clock to ACP and wait until the clock is enabled */ ++ val = acp_reg_read(acp_mmio, mmACP_CONTROL); ++ val = val | ACP_CONTROL__ClkEn_MASK; ++ acp_reg_write(val, acp_mmio, mmACP_CONTROL); ++ ++ count = ACP_CLOCK_EN_TIME_OUT_VALUE; ++ ++ while (true) { ++ val = acp_reg_read(acp_mmio, mmACP_STATUS); ++ if (val & (u32) 0x1) ++ break; ++ if (--count == 0) { ++ pr_err("Failed to reset ACP\n"); ++ return -ETIMEDOUT; ++ } ++ udelay(100); ++ } ++ ++ /* Deassert the SOFT RESET flags */ ++ val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET); ++ val &= ~ACP_SOFT_RESET__SoftResetAud_MASK; ++ acp_reg_write(val, acp_mmio, mmACP_SOFT_RESET); ++ ++ /* initiailize Onion control DAGB register */ ++ acp_reg_write(ACP_ONION_CNTL_DEFAULT, acp_mmio, ++ mmACP_AXI2DAGB_ONION_CNTL); ++ ++ /* initiailize Garlic control DAGB registers */ ++ acp_reg_write(ACP_GARLIC_CNTL_DEFAULT, acp_mmio, ++ mmACP_AXI2DAGB_GARLIC_CNTL); ++ ++ sram_pte_offset = ACP_DAGB_GRP_SRAM_BASE_ADDRESS | ++ ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBSnoopSel_MASK | ++ ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBTargetMemSel_MASK | ++ ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBGrpEnable_MASK; ++ acp_reg_write(sram_pte_offset, acp_mmio, mmACP_DAGB_BASE_ADDR_GRP_1); ++ acp_reg_write(ACP_PAGE_SIZE_4K_ENABLE, acp_mmio, ++ mmACP_DAGB_PAGE_SIZE_GRP_1); ++ ++ acp_reg_write(ACP_SRAM_BASE_ADDRESS, acp_mmio, ++ mmACP_DMA_DESC_BASE_ADDR); ++ ++ /* Num of descriptiors in SRAM 0x4, means 256 descriptors;(64 * 4) */ ++ acp_reg_write(0x4, acp_mmio, mmACP_DMA_DESC_MAX_NUM_DSCR); ++ acp_reg_write(ACP_EXTERNAL_INTR_CNTL__DMAIOCMask_MASK, ++ acp_mmio, mmACP_EXTERNAL_INTR_CNTL); ++ ++ return 0; ++} ++ ++/* Deintialize ACP */ ++static int acp_deinit(void __iomem *acp_mmio) ++{ ++ u32 val; ++ u32 count; ++ ++ /* Assert Soft reset of ACP */ ++ val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET); ++ ++ val |= ACP_SOFT_RESET__SoftResetAud_MASK; ++ acp_reg_write(val, acp_mmio, mmACP_SOFT_RESET); ++ ++ count = ACP_SOFT_RESET_DONE_TIME_OUT_VALUE; ++ while (true) { ++ val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET); ++ if (ACP_SOFT_RESET__SoftResetAudDone_MASK == ++ (val & ACP_SOFT_RESET__SoftResetAudDone_MASK)) ++ break; ++ if (--count == 0) { ++ pr_err("Failed to reset ACP\n"); ++ return -ETIMEDOUT; ++ } ++ udelay(100); ++ } ++ /** Disable ACP clock */ ++ val = acp_reg_read(acp_mmio, mmACP_CONTROL); ++ val &= ~ACP_CONTROL__ClkEn_MASK; ++ acp_reg_write(val, acp_mmio, mmACP_CONTROL); ++ ++ count = ACP_CLOCK_EN_TIME_OUT_VALUE; ++ ++ while (true) { ++ val = acp_reg_read(acp_mmio, mmACP_STATUS); ++ if (!(val & (u32) 0x1)) ++ break; ++ if (--count == 0) { ++ pr_err("Failed to reset ACP\n"); ++ return -ETIMEDOUT; ++ } ++ udelay(100); ++ } ++ return 0; ++} ++ ++/* ACP DMA irq handler routine for playback, capture usecases */ ++static irqreturn_t dma_irq_handler(int irq, void *arg) ++{ ++ u16 dscr_idx; ++ u32 intr_flag, ext_intr_status; ++ struct audio_drv_data *irq_data; ++ void __iomem *acp_mmio; ++ struct device *dev = arg; ++ bool valid_irq = false; ++ ++ irq_data = dev_get_drvdata(dev); ++ acp_mmio = irq_data->acp_mmio; ++ ++ ext_intr_status = acp_reg_read(acp_mmio, mmACP_EXTERNAL_INTR_STAT); ++ intr_flag = (((ext_intr_status & ++ ACP_EXTERNAL_INTR_STAT__DMAIOCStat_MASK) >> ++ ACP_EXTERNAL_INTR_STAT__DMAIOCStat__SHIFT)); ++ ++ if ((intr_flag & BIT(ACP_TO_I2S_DMA_CH_NUM)) != 0) { ++ valid_irq = true; ++ if (acp_reg_read(acp_mmio, mmACP_DMA_CUR_DSCR_13) == ++ PLAYBACK_START_DMA_DESCR_CH13) ++ dscr_idx = PLAYBACK_START_DMA_DESCR_CH12; ++ else ++ dscr_idx = PLAYBACK_END_DMA_DESCR_CH12; ++ config_acp_dma_channel(acp_mmio, SYSRAM_TO_ACP_CH_NUM, dscr_idx, ++ 1, 0); ++ acp_dma_start(acp_mmio, SYSRAM_TO_ACP_CH_NUM, false); ++ ++ snd_pcm_period_elapsed(irq_data->play_stream); ++ ++ acp_reg_write((intr_flag & BIT(ACP_TO_I2S_DMA_CH_NUM)) << 16, ++ acp_mmio, mmACP_EXTERNAL_INTR_STAT); ++ } ++ ++ if ((intr_flag & BIT(I2S_TO_ACP_DMA_CH_NUM)) != 0) { ++ valid_irq = true; ++ if (acp_reg_read(acp_mmio, mmACP_DMA_CUR_DSCR_15) == ++ CAPTURE_START_DMA_DESCR_CH15) ++ dscr_idx = CAPTURE_END_DMA_DESCR_CH14; ++ else ++ dscr_idx = CAPTURE_START_DMA_DESCR_CH14; ++ config_acp_dma_channel(acp_mmio, ACP_TO_SYSRAM_CH_NUM, dscr_idx, ++ 1, 0); ++ acp_dma_start(acp_mmio, ACP_TO_SYSRAM_CH_NUM, false); ++ ++ acp_reg_write((intr_flag & BIT(I2S_TO_ACP_DMA_CH_NUM)) << 16, ++ acp_mmio, mmACP_EXTERNAL_INTR_STAT); ++ } ++ ++ if ((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) != 0) { ++ valid_irq = true; ++ snd_pcm_period_elapsed(irq_data->capture_stream); ++ acp_reg_write((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) << 16, ++ acp_mmio, mmACP_EXTERNAL_INTR_STAT); ++ } ++ ++ if (valid_irq) ++ return IRQ_HANDLED; ++ else ++ return IRQ_NONE; ++} ++ ++static int acp_dma_open(struct snd_pcm_substream *substream) ++{ ++ int ret = 0; ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct snd_soc_pcm_runtime *prtd = substream->private_data; ++ struct audio_drv_data *intr_data = dev_get_drvdata(prtd->platform->dev); ++ ++ struct audio_substream_data *adata = ++ kzalloc(sizeof(struct audio_substream_data), GFP_KERNEL); ++ if (adata == NULL) ++ return -ENOMEM; ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ runtime->hw = acp_pcm_hardware_playback; ++ else ++ runtime->hw = acp_pcm_hardware_capture; ++ ++ ret = snd_pcm_hw_constraint_integer(runtime, ++ SNDRV_PCM_HW_PARAM_PERIODS); ++ if (ret < 0) { ++ dev_err(prtd->platform->dev, "set integer constraint failed\n"); ++ return ret; ++ } ++ ++ adata->acp_mmio = intr_data->acp_mmio; ++ runtime->private_data = adata; ++ ++ /* Enable ACP irq, when neither playback or capture streams are ++ * active by the time when a new stream is being opened. ++ * This enablement is not required for another stream, if current ++ * stream is not closed ++ */ ++ if (!intr_data->play_stream && !intr_data->capture_stream) ++ acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ intr_data->play_stream = substream; ++ else ++ intr_data->capture_stream = substream; ++ ++ return 0; ++} ++ ++static int acp_dma_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ int status; ++ uint64_t size; ++ struct snd_dma_buffer *dma_buffer; ++ struct page *pg; ++ struct snd_pcm_runtime *runtime; ++ struct audio_substream_data *rtd; ++ ++ dma_buffer = &substream->dma_buffer; ++ ++ runtime = substream->runtime; ++ rtd = runtime->private_data; ++ ++ if (WARN_ON(!rtd)) ++ return -EINVAL; ++ ++ size = params_buffer_bytes(params); ++ status = snd_pcm_lib_malloc_pages(substream, size); ++ if (status < 0) ++ return status; ++ ++ memset(substream->runtime->dma_area, 0, params_buffer_bytes(params)); ++ pg = virt_to_page(substream->dma_buffer.area); ++ ++ if (pg != NULL) { ++ /* Save for runtime private data */ ++ rtd->pg = pg; ++ rtd->order = get_order(size); ++ ++ /* Fill the page table entries in ACP SRAM */ ++ rtd->pg = pg; ++ rtd->size = size; ++ rtd->num_of_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; ++ rtd->direction = substream->stream; ++ ++ config_acp_dma(rtd->acp_mmio, rtd); ++ status = 0; ++ } else { ++ status = -ENOMEM; ++ } ++ return status; ++} ++ ++static int acp_dma_hw_free(struct snd_pcm_substream *substream) ++{ ++ return snd_pcm_lib_free_pages(substream); ++} ++ ++static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream) ++{ ++ u16 dscr; ++ u32 mul, dma_config, period_bytes; ++ u32 pos = 0; ++ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct audio_substream_data *rtd = runtime->private_data; ++ ++ period_bytes = frames_to_bytes(runtime, runtime->period_size); ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ dscr = acp_reg_read(rtd->acp_mmio, mmACP_DMA_CUR_DSCR_13); ++ ++ if (dscr == PLAYBACK_START_DMA_DESCR_CH13) ++ mul = 0; ++ else ++ mul = 1; ++ pos = (mul * period_bytes); ++ } else { ++ dma_config = acp_reg_read(rtd->acp_mmio, mmACP_DMA_CNTL_14); ++ if (dma_config != 0) { ++ dscr = acp_reg_read(rtd->acp_mmio, ++ mmACP_DMA_CUR_DSCR_14); ++ if (dscr == CAPTURE_START_DMA_DESCR_CH14) ++ mul = 1; ++ else ++ mul = 2; ++ pos = (mul * period_bytes); ++ } ++ ++ if (pos >= (2 * period_bytes)) ++ pos = 0; ++ ++ } ++ return bytes_to_frames(runtime, pos); ++} ++ ++static int acp_dma_mmap(struct snd_pcm_substream *substream, ++ struct vm_area_struct *vma) ++{ ++ return snd_pcm_lib_default_mmap(substream, vma); ++} ++ ++static int acp_dma_prepare(struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct audio_substream_data *rtd = runtime->private_data; ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ config_acp_dma_channel(rtd->acp_mmio, SYSRAM_TO_ACP_CH_NUM, ++ PLAYBACK_START_DMA_DESCR_CH12, ++ NUM_DSCRS_PER_CHANNEL, 0); ++ config_acp_dma_channel(rtd->acp_mmio, ACP_TO_I2S_DMA_CH_NUM, ++ PLAYBACK_START_DMA_DESCR_CH13, ++ NUM_DSCRS_PER_CHANNEL, 0); ++ /* Fill ACP SRAM (2 periods) with zeros from System RAM ++ * which is zero-ed in hw_params ++ */ ++ acp_dma_start(rtd->acp_mmio, SYSRAM_TO_ACP_CH_NUM, false); ++ ++ /* ACP SRAM (2 periods of buffer size) is intially filled with ++ * zeros. Before rendering starts, 2nd half of SRAM will be ++ * filled with valid audio data DMA'ed from first half of system ++ * RAM and 1st half of SRAM will be filled with Zeros. This is ++ * the initial scenario when redering starts from SRAM. Later ++ * on, 2nd half of system memory will be DMA'ed to 1st half of ++ * SRAM, 1st half of system memory will be DMA'ed to 2nd half of ++ * SRAM in ping-pong way till rendering stops. ++ */ ++ config_acp_dma_channel(rtd->acp_mmio, SYSRAM_TO_ACP_CH_NUM, ++ PLAYBACK_START_DMA_DESCR_CH12, ++ 1, 0); ++ } else { ++ config_acp_dma_channel(rtd->acp_mmio, ACP_TO_SYSRAM_CH_NUM, ++ CAPTURE_START_DMA_DESCR_CH14, ++ NUM_DSCRS_PER_CHANNEL, 0); ++ config_acp_dma_channel(rtd->acp_mmio, I2S_TO_ACP_DMA_CH_NUM, ++ CAPTURE_START_DMA_DESCR_CH15, ++ NUM_DSCRS_PER_CHANNEL, 0); ++ } ++ return 0; ++} ++ ++static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd) ++{ ++ int ret; ++ u32 loops = 1000; ++ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct snd_soc_pcm_runtime *prtd = substream->private_data; ++ struct audio_substream_data *rtd = runtime->private_data; ++ ++ if (!rtd) ++ return -EINVAL; ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ acp_dma_start(rtd->acp_mmio, ++ SYSRAM_TO_ACP_CH_NUM, false); ++ while (acp_reg_read(rtd->acp_mmio, mmACP_DMA_CH_STS) & ++ BIT(SYSRAM_TO_ACP_CH_NUM)) { ++ if (!loops--) { ++ dev_err(prtd->platform->dev, ++ "acp dma start timeout\n"); ++ return -ETIMEDOUT; ++ } ++ cpu_relax(); ++ } ++ ++ acp_dma_start(rtd->acp_mmio, ++ ACP_TO_I2S_DMA_CH_NUM, true); ++ ++ } else { ++ acp_dma_start(rtd->acp_mmio, ++ I2S_TO_ACP_DMA_CH_NUM, true); ++ } ++ ret = 0; ++ break; ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ /* Need to stop only circular DMA channels : ++ * ACP_TO_I2S_DMA_CH_NUM / I2S_TO_ACP_DMA_CH_NUM. Non-circular ++ * channels will stopped automatically after its transfer ++ * completes : SYSRAM_TO_ACP_CH_NUM / ACP_TO_SYSRAM_CH_NUM ++ */ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ ret = acp_dma_stop(rtd->acp_mmio, ++ ACP_TO_I2S_DMA_CH_NUM); ++ else ++ ret = acp_dma_stop(rtd->acp_mmio, ++ I2S_TO_ACP_DMA_CH_NUM); ++ break; ++ default: ++ ret = -EINVAL; ++ ++ } ++ return ret; ++} ++ ++static int acp_dma_new(struct snd_soc_pcm_runtime *rtd) ++{ ++ return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, ++ SNDRV_DMA_TYPE_DEV, ++ NULL, MIN_BUFFER, ++ MAX_BUFFER); ++} ++ ++static int acp_dma_close(struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct audio_substream_data *rtd = runtime->private_data; ++ struct snd_soc_pcm_runtime *prtd = substream->private_data; ++ struct audio_drv_data *adata = dev_get_drvdata(prtd->platform->dev); ++ ++ kfree(rtd); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ adata->play_stream = NULL; ++ else ++ adata->capture_stream = NULL; ++ ++ /* Disable ACP irq, when the current stream is being closed and ++ * another stream is also not active. ++ */ ++ if (!adata->play_stream && !adata->capture_stream) ++ acp_reg_write(0, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB); ++ ++ return 0; ++} ++ ++static struct snd_pcm_ops acp_dma_ops = { ++ .open = acp_dma_open, ++ .close = acp_dma_close, ++ .ioctl = snd_pcm_lib_ioctl, ++ .hw_params = acp_dma_hw_params, ++ .hw_free = acp_dma_hw_free, ++ .trigger = acp_dma_trigger, ++ .pointer = acp_dma_pointer, ++ .mmap = acp_dma_mmap, ++ .prepare = acp_dma_prepare, ++}; ++ ++static struct snd_soc_platform_driver acp_asoc_platform = { ++ .ops = &acp_dma_ops, ++ .pcm_new = acp_dma_new, ++}; ++ ++static int acp_audio_probe(struct platform_device *pdev) ++{ ++ int status; ++ struct audio_drv_data *audio_drv_data; ++ struct resource *res; ++ ++ audio_drv_data = devm_kzalloc(&pdev->dev, sizeof(struct audio_drv_data), ++ GFP_KERNEL); ++ if (audio_drv_data == NULL) ++ return -ENOMEM; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ audio_drv_data->acp_mmio = devm_ioremap_resource(&pdev->dev, res); ++ ++ /* The following members gets populated in device 'open' ++ * function. Till then interrupts are disabled in 'acp_init' ++ * and device doesn't generate any interrupts. ++ */ ++ ++ audio_drv_data->play_stream = NULL; ++ audio_drv_data->capture_stream = NULL; ++ ++ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n"); ++ return -ENODEV; ++ } ++ ++ status = devm_request_irq(&pdev->dev, res->start, dma_irq_handler, ++ 0, "ACP_IRQ", &pdev->dev); ++ if (status) { ++ dev_err(&pdev->dev, "ACP IRQ request failed\n"); ++ return status; ++ } ++ ++ dev_set_drvdata(&pdev->dev, audio_drv_data); ++ ++ /* Initialize the ACP */ ++ acp_init(audio_drv_data->acp_mmio); ++ ++ status = snd_soc_register_platform(&pdev->dev, &acp_asoc_platform); ++ if (status != 0) { ++ dev_err(&pdev->dev, "Fail to register ALSA platform device\n"); ++ return status; ++ } ++ ++ return status; ++} ++ ++static int acp_audio_remove(struct platform_device *pdev) ++{ ++ struct audio_drv_data *adata = dev_get_drvdata(&pdev->dev); ++ ++ acp_deinit(adata->acp_mmio); ++ snd_soc_unregister_platform(&pdev->dev); ++ ++ return 0; ++} ++ ++static struct platform_driver acp_dma_driver = { ++ .probe = acp_audio_probe, ++ .remove = acp_audio_remove, ++ .driver = { ++ .name = "acp_audio_dma", ++ }, ++}; ++ ++module_platform_driver(acp_dma_driver); ++ ++MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com"); ++MODULE_DESCRIPTION("AMD ACP PCM Driver"); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("platform:acp-dma-audio"); +diff --git a/sound/soc/amd/acp.h b/sound/soc/amd/acp.h +new file mode 100644 +index 0000000..330832e +--- /dev/null ++++ b/sound/soc/amd/acp.h +@@ -0,0 +1,118 @@ ++#ifndef __ACP_HW_H ++#define __ACP_HW_H ++ ++#include "include/acp_2_2_d.h" ++#include "include/acp_2_2_sh_mask.h" ++ ++#define ACP_PAGE_SIZE_4K_ENABLE 0x02 ++ ++#define ACP_PLAYBACK_PTE_OFFSET 10 ++#define ACP_CAPTURE_PTE_OFFSET 0 ++ ++#define ACP_GARLIC_CNTL_DEFAULT 0x00000FB4 ++#define ACP_ONION_CNTL_DEFAULT 0x00000FB4 ++ ++#define ACP_PHYSICAL_BASE 0x14000 ++ ++/* Playback SRAM address (as a destination in dma descriptor) */ ++#define ACP_SHARED_RAM_BANK_1_ADDRESS 0x4002000 ++ ++/* Capture SRAM address (as a source in dma descriptor) */ ++#define ACP_SHARED_RAM_BANK_5_ADDRESS 0x400A000 ++ ++#define ACP_DMA_RESET_TIME 10000 ++#define ACP_CLOCK_EN_TIME_OUT_VALUE 0x000000FF ++#define ACP_SOFT_RESET_DONE_TIME_OUT_VALUE 0x000000FF ++#define ACP_DMA_COMPLETE_TIME_OUT_VALUE 0x000000FF ++ ++#define ACP_SRAM_BASE_ADDRESS 0x4000000 ++#define ACP_DAGB_GRP_SRAM_BASE_ADDRESS 0x4001000 ++#define ACP_DAGB_GRP_SRBM_SRAM_BASE_OFFSET 0x1000 ++#define ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS 0x00000000 ++#define ACP_INTERNAL_APERTURE_WINDOW_4_ADDRESS 0x01800000 ++ ++#define TO_ACP_I2S_1 0x2 ++#define TO_ACP_I2S_2 0x4 ++#define FROM_ACP_I2S_1 0xa ++#define FROM_ACP_I2S_2 0xb ++ ++#define ACP_TILE_ON_MASK 0x03 ++#define ACP_TILE_OFF_MASK 0x02 ++#define ACP_TILE_ON_RETAIN_REG_MASK 0x1f ++#define ACP_TILE_OFF_RETAIN_REG_MASK 0x20 ++ ++#define ACP_TILE_P1_MASK 0x3e ++#define ACP_TILE_P2_MASK 0x3d ++#define ACP_TILE_DSP0_MASK 0x3b ++#define ACP_TILE_DSP1_MASK 0x37 ++ ++#define ACP_TILE_DSP2_MASK 0x2f ++/* Playback DMA channels */ ++#define SYSRAM_TO_ACP_CH_NUM 12 ++#define ACP_TO_I2S_DMA_CH_NUM 13 ++ ++/* Capture DMA channels */ ++#define ACP_TO_SYSRAM_CH_NUM 14 ++#define I2S_TO_ACP_DMA_CH_NUM 15 ++ ++#define NUM_DSCRS_PER_CHANNEL 2 ++ ++#define PLAYBACK_START_DMA_DESCR_CH12 0 ++#define PLAYBACK_END_DMA_DESCR_CH12 1 ++#define PLAYBACK_START_DMA_DESCR_CH13 2 ++#define PLAYBACK_END_DMA_DESCR_CH13 3 ++ ++#define CAPTURE_START_DMA_DESCR_CH14 4 ++#define CAPTURE_END_DMA_DESCR_CH14 5 ++#define CAPTURE_START_DMA_DESCR_CH15 6 ++#define CAPTURE_END_DMA_DESCR_CH15 7 ++ ++enum acp_dma_priority_level { ++ /* 0x0 Specifies the DMA channel is given normal priority */ ++ ACP_DMA_PRIORITY_LEVEL_NORMAL = 0x0, ++ /* 0x1 Specifies the DMA channel is given high priority */ ++ ACP_DMA_PRIORITY_LEVEL_HIGH = 0x1, ++ ACP_DMA_PRIORITY_LEVEL_FORCESIZE = 0xFF ++}; ++ ++struct audio_substream_data { ++ struct page *pg; ++ unsigned int order; ++ u16 num_of_pages; ++ u16 direction; ++ uint64_t size; ++ void __iomem *acp_mmio; ++}; ++ ++enum { ++ ACP_TILE_P1 = 0, ++ ACP_TILE_P2, ++ ACP_TILE_DSP0, ++ ACP_TILE_DSP1, ++ ACP_TILE_DSP2, ++}; ++ ++enum { ++ ACP_DMA_ATTRIBUTES_SHAREDMEM_TO_DAGB_ONION = 0x0, ++ ACP_DMA_ATTRIBUTES_SHARED_MEM_TO_DAGB_GARLIC = 0x1, ++ ACP_DMA_ATTRIBUTES_DAGB_ONION_TO_SHAREDMEM = 0x8, ++ ACP_DMA_ATTRIBUTES_DAGB_GARLIC_TO_SHAREDMEM = 0x9, ++ ACP_DMA_ATTRIBUTES_FORCE_SIZE = 0xF ++}; ++ ++typedef struct acp_dma_dscr_transfer { ++ /* Specifies the source memory location for the DMA data transfer. */ ++ u32 src; ++ /* Specifies the destination memory location to where the data will ++ * be transferred. ++ */ ++ u32 dest; ++ /* Specifies the number of bytes need to be transferred ++ * from source to destination memory.Transfer direction & IOC enable ++ */ ++ u32 xfer_val; ++ /* Reserved for future use */ ++ u32 reserved; ++} acp_dma_dscr_transfer_t; ++ ++#endif /*__ACP_HW_H */ +-- +2.7.4 + |