18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * AMD ALSA SoC PCM Driver for ACP 2.x 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2014-2015 Advanced Micro Devices, Inc. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/delay.h> 108c2ecf20Sopenharmony_ci#include <linux/io.h> 118c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 128c2ecf20Sopenharmony_ci#include <linux/sizes.h> 138c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <sound/soc.h> 168c2ecf20Sopenharmony_ci#include <drm/amd_asic_type.h> 178c2ecf20Sopenharmony_ci#include "acp.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define DRV_NAME "acp_audio_dma" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define PLAYBACK_MIN_NUM_PERIODS 2 228c2ecf20Sopenharmony_ci#define PLAYBACK_MAX_NUM_PERIODS 2 238c2ecf20Sopenharmony_ci#define PLAYBACK_MAX_PERIOD_SIZE 16384 248c2ecf20Sopenharmony_ci#define PLAYBACK_MIN_PERIOD_SIZE 1024 258c2ecf20Sopenharmony_ci#define CAPTURE_MIN_NUM_PERIODS 2 268c2ecf20Sopenharmony_ci#define CAPTURE_MAX_NUM_PERIODS 2 278c2ecf20Sopenharmony_ci#define CAPTURE_MAX_PERIOD_SIZE 16384 288c2ecf20Sopenharmony_ci#define CAPTURE_MIN_PERIOD_SIZE 1024 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define MAX_BUFFER (PLAYBACK_MAX_PERIOD_SIZE * PLAYBACK_MAX_NUM_PERIODS) 318c2ecf20Sopenharmony_ci#define MIN_BUFFER MAX_BUFFER 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define ST_PLAYBACK_MAX_PERIOD_SIZE 4096 348c2ecf20Sopenharmony_ci#define ST_CAPTURE_MAX_PERIOD_SIZE ST_PLAYBACK_MAX_PERIOD_SIZE 358c2ecf20Sopenharmony_ci#define ST_MAX_BUFFER (ST_PLAYBACK_MAX_PERIOD_SIZE * PLAYBACK_MAX_NUM_PERIODS) 368c2ecf20Sopenharmony_ci#define ST_MIN_BUFFER ST_MAX_BUFFER 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define DRV_NAME "acp_audio_dma" 398c2ecf20Sopenharmony_cibool bt_uart_enable = true; 408c2ecf20Sopenharmony_ciEXPORT_SYMBOL(bt_uart_enable); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware acp_pcm_hardware_playback = { 438c2ecf20Sopenharmony_ci .info = SNDRV_PCM_INFO_INTERLEAVED | 448c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | 458c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH | 468c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, 478c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | 488c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, 498c2ecf20Sopenharmony_ci .channels_min = 1, 508c2ecf20Sopenharmony_ci .channels_max = 8, 518c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_96000, 528c2ecf20Sopenharmony_ci .rate_min = 8000, 538c2ecf20Sopenharmony_ci .rate_max = 96000, 548c2ecf20Sopenharmony_ci .buffer_bytes_max = PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE, 558c2ecf20Sopenharmony_ci .period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE, 568c2ecf20Sopenharmony_ci .period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE, 578c2ecf20Sopenharmony_ci .periods_min = PLAYBACK_MIN_NUM_PERIODS, 588c2ecf20Sopenharmony_ci .periods_max = PLAYBACK_MAX_NUM_PERIODS, 598c2ecf20Sopenharmony_ci}; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware acp_pcm_hardware_capture = { 628c2ecf20Sopenharmony_ci .info = SNDRV_PCM_INFO_INTERLEAVED | 638c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | 648c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH | 658c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, 668c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | 678c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, 688c2ecf20Sopenharmony_ci .channels_min = 1, 698c2ecf20Sopenharmony_ci .channels_max = 2, 708c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_48000, 718c2ecf20Sopenharmony_ci .rate_min = 8000, 728c2ecf20Sopenharmony_ci .rate_max = 48000, 738c2ecf20Sopenharmony_ci .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE, 748c2ecf20Sopenharmony_ci .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE, 758c2ecf20Sopenharmony_ci .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE, 768c2ecf20Sopenharmony_ci .periods_min = CAPTURE_MIN_NUM_PERIODS, 778c2ecf20Sopenharmony_ci .periods_max = CAPTURE_MAX_NUM_PERIODS, 788c2ecf20Sopenharmony_ci}; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware acp_st_pcm_hardware_playback = { 818c2ecf20Sopenharmony_ci .info = SNDRV_PCM_INFO_INTERLEAVED | 828c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | 838c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH | 848c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, 858c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | 868c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, 878c2ecf20Sopenharmony_ci .channels_min = 1, 888c2ecf20Sopenharmony_ci .channels_max = 8, 898c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_96000, 908c2ecf20Sopenharmony_ci .rate_min = 8000, 918c2ecf20Sopenharmony_ci .rate_max = 96000, 928c2ecf20Sopenharmony_ci .buffer_bytes_max = ST_MAX_BUFFER, 938c2ecf20Sopenharmony_ci .period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE, 948c2ecf20Sopenharmony_ci .period_bytes_max = ST_PLAYBACK_MAX_PERIOD_SIZE, 958c2ecf20Sopenharmony_ci .periods_min = PLAYBACK_MIN_NUM_PERIODS, 968c2ecf20Sopenharmony_ci .periods_max = PLAYBACK_MAX_NUM_PERIODS, 978c2ecf20Sopenharmony_ci}; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware acp_st_pcm_hardware_capture = { 1008c2ecf20Sopenharmony_ci .info = SNDRV_PCM_INFO_INTERLEAVED | 1018c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | 1028c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH | 1038c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, 1048c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | 1058c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, 1068c2ecf20Sopenharmony_ci .channels_min = 1, 1078c2ecf20Sopenharmony_ci .channels_max = 2, 1088c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_48000, 1098c2ecf20Sopenharmony_ci .rate_min = 8000, 1108c2ecf20Sopenharmony_ci .rate_max = 48000, 1118c2ecf20Sopenharmony_ci .buffer_bytes_max = ST_MAX_BUFFER, 1128c2ecf20Sopenharmony_ci .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE, 1138c2ecf20Sopenharmony_ci .period_bytes_max = ST_CAPTURE_MAX_PERIOD_SIZE, 1148c2ecf20Sopenharmony_ci .periods_min = CAPTURE_MIN_NUM_PERIODS, 1158c2ecf20Sopenharmony_ci .periods_max = CAPTURE_MAX_NUM_PERIODS, 1168c2ecf20Sopenharmony_ci}; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic u32 acp_reg_read(void __iomem *acp_mmio, u32 reg) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci return readl(acp_mmio + (reg * 4)); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic void acp_reg_write(u32 val, void __iomem *acp_mmio, u32 reg) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci writel(val, acp_mmio + (reg * 4)); 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci/* 1298c2ecf20Sopenharmony_ci * Configure a given dma channel parameters - enable/disable, 1308c2ecf20Sopenharmony_ci * number of descriptors, priority 1318c2ecf20Sopenharmony_ci */ 1328c2ecf20Sopenharmony_cistatic void config_acp_dma_channel(void __iomem *acp_mmio, u8 ch_num, 1338c2ecf20Sopenharmony_ci u16 dscr_strt_idx, u16 num_dscrs, 1348c2ecf20Sopenharmony_ci enum acp_dma_priority_level priority_level) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci u32 dma_ctrl; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci /* disable the channel run field */ 1398c2ecf20Sopenharmony_ci dma_ctrl = acp_reg_read(acp_mmio, mmACP_DMA_CNTL_0 + ch_num); 1408c2ecf20Sopenharmony_ci dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChRun_MASK; 1418c2ecf20Sopenharmony_ci acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci /* program a DMA channel with first descriptor to be processed. */ 1448c2ecf20Sopenharmony_ci acp_reg_write((ACP_DMA_DSCR_STRT_IDX_0__DMAChDscrStrtIdx_MASK 1458c2ecf20Sopenharmony_ci & dscr_strt_idx), 1468c2ecf20Sopenharmony_ci acp_mmio, mmACP_DMA_DSCR_STRT_IDX_0 + ch_num); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /* 1498c2ecf20Sopenharmony_ci * program a DMA channel with the number of descriptors to be 1508c2ecf20Sopenharmony_ci * processed in the transfer 1518c2ecf20Sopenharmony_ci */ 1528c2ecf20Sopenharmony_ci acp_reg_write(ACP_DMA_DSCR_CNT_0__DMAChDscrCnt_MASK & num_dscrs, 1538c2ecf20Sopenharmony_ci acp_mmio, mmACP_DMA_DSCR_CNT_0 + ch_num); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* set DMA channel priority */ 1568c2ecf20Sopenharmony_ci acp_reg_write(priority_level, acp_mmio, mmACP_DMA_PRIO_0 + ch_num); 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci/* Initialize a dma descriptor in SRAM based on descritor information passed */ 1608c2ecf20Sopenharmony_cistatic void config_dma_descriptor_in_sram(void __iomem *acp_mmio, 1618c2ecf20Sopenharmony_ci u16 descr_idx, 1628c2ecf20Sopenharmony_ci acp_dma_dscr_transfer_t *descr_info) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci u32 sram_offset; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci sram_offset = (descr_idx * sizeof(acp_dma_dscr_transfer_t)); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* program the source base address. */ 1698c2ecf20Sopenharmony_ci acp_reg_write(sram_offset, acp_mmio, mmACP_SRBM_Targ_Idx_Addr); 1708c2ecf20Sopenharmony_ci acp_reg_write(descr_info->src, acp_mmio, mmACP_SRBM_Targ_Idx_Data); 1718c2ecf20Sopenharmony_ci /* program the destination base address. */ 1728c2ecf20Sopenharmony_ci acp_reg_write(sram_offset + 4, acp_mmio, mmACP_SRBM_Targ_Idx_Addr); 1738c2ecf20Sopenharmony_ci acp_reg_write(descr_info->dest, acp_mmio, mmACP_SRBM_Targ_Idx_Data); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* program the number of bytes to be transferred for this descriptor. */ 1768c2ecf20Sopenharmony_ci acp_reg_write(sram_offset + 8, acp_mmio, mmACP_SRBM_Targ_Idx_Addr); 1778c2ecf20Sopenharmony_ci acp_reg_write(descr_info->xfer_val, acp_mmio, mmACP_SRBM_Targ_Idx_Data); 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic void pre_config_reset(void __iomem *acp_mmio, u16 ch_num) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci u32 dma_ctrl; 1838c2ecf20Sopenharmony_ci int ret; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci /* clear the reset bit */ 1868c2ecf20Sopenharmony_ci dma_ctrl = acp_reg_read(acp_mmio, mmACP_DMA_CNTL_0 + ch_num); 1878c2ecf20Sopenharmony_ci dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChRst_MASK; 1888c2ecf20Sopenharmony_ci acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num); 1898c2ecf20Sopenharmony_ci /* check the reset bit before programming configuration registers */ 1908c2ecf20Sopenharmony_ci ret = readl_poll_timeout(acp_mmio + ((mmACP_DMA_CNTL_0 + ch_num) * 4), 1918c2ecf20Sopenharmony_ci dma_ctrl, 1928c2ecf20Sopenharmony_ci !(dma_ctrl & ACP_DMA_CNTL_0__DMAChRst_MASK), 1938c2ecf20Sopenharmony_ci 100, ACP_DMA_RESET_TIME); 1948c2ecf20Sopenharmony_ci if (ret < 0) 1958c2ecf20Sopenharmony_ci pr_err("Failed to clear reset of channel : %d\n", ch_num); 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci/* 1998c2ecf20Sopenharmony_ci * Initialize the DMA descriptor information for transfer between 2008c2ecf20Sopenharmony_ci * system memory <-> ACP SRAM 2018c2ecf20Sopenharmony_ci */ 2028c2ecf20Sopenharmony_cistatic void set_acp_sysmem_dma_descriptors(void __iomem *acp_mmio, 2038c2ecf20Sopenharmony_ci u32 size, int direction, 2048c2ecf20Sopenharmony_ci u32 pte_offset, u16 ch, 2058c2ecf20Sopenharmony_ci u32 sram_bank, u16 dma_dscr_idx, 2068c2ecf20Sopenharmony_ci u32 asic_type) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci u16 i; 2098c2ecf20Sopenharmony_ci acp_dma_dscr_transfer_t dmadscr[NUM_DSCRS_PER_CHANNEL]; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci for (i = 0; i < NUM_DSCRS_PER_CHANNEL; i++) { 2128c2ecf20Sopenharmony_ci dmadscr[i].xfer_val = 0; 2138c2ecf20Sopenharmony_ci if (direction == SNDRV_PCM_STREAM_PLAYBACK) { 2148c2ecf20Sopenharmony_ci dma_dscr_idx = dma_dscr_idx + i; 2158c2ecf20Sopenharmony_ci dmadscr[i].dest = sram_bank + (i * (size / 2)); 2168c2ecf20Sopenharmony_ci dmadscr[i].src = ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS 2178c2ecf20Sopenharmony_ci + (pte_offset * SZ_4K) + (i * (size / 2)); 2188c2ecf20Sopenharmony_ci switch (asic_type) { 2198c2ecf20Sopenharmony_ci case CHIP_STONEY: 2208c2ecf20Sopenharmony_ci dmadscr[i].xfer_val |= 2218c2ecf20Sopenharmony_ci (ACP_DMA_ATTR_DAGB_GARLIC_TO_SHAREDMEM << 16) | 2228c2ecf20Sopenharmony_ci (size / 2); 2238c2ecf20Sopenharmony_ci break; 2248c2ecf20Sopenharmony_ci default: 2258c2ecf20Sopenharmony_ci dmadscr[i].xfer_val |= 2268c2ecf20Sopenharmony_ci (ACP_DMA_ATTR_DAGB_ONION_TO_SHAREDMEM << 16) | 2278c2ecf20Sopenharmony_ci (size / 2); 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci } else { 2308c2ecf20Sopenharmony_ci dma_dscr_idx = dma_dscr_idx + i; 2318c2ecf20Sopenharmony_ci dmadscr[i].src = sram_bank + (i * (size / 2)); 2328c2ecf20Sopenharmony_ci dmadscr[i].dest = 2338c2ecf20Sopenharmony_ci ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS + 2348c2ecf20Sopenharmony_ci (pte_offset * SZ_4K) + (i * (size / 2)); 2358c2ecf20Sopenharmony_ci switch (asic_type) { 2368c2ecf20Sopenharmony_ci case CHIP_STONEY: 2378c2ecf20Sopenharmony_ci dmadscr[i].xfer_val |= 2388c2ecf20Sopenharmony_ci (ACP_DMA_ATTR_SHARED_MEM_TO_DAGB_GARLIC << 16) | 2398c2ecf20Sopenharmony_ci (size / 2); 2408c2ecf20Sopenharmony_ci break; 2418c2ecf20Sopenharmony_ci default: 2428c2ecf20Sopenharmony_ci dmadscr[i].xfer_val |= 2438c2ecf20Sopenharmony_ci (ACP_DMA_ATTR_SHAREDMEM_TO_DAGB_ONION << 16) | 2448c2ecf20Sopenharmony_ci (size / 2); 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci config_dma_descriptor_in_sram(acp_mmio, dma_dscr_idx, 2488c2ecf20Sopenharmony_ci &dmadscr[i]); 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci pre_config_reset(acp_mmio, ch); 2518c2ecf20Sopenharmony_ci config_acp_dma_channel(acp_mmio, ch, 2528c2ecf20Sopenharmony_ci dma_dscr_idx - 1, 2538c2ecf20Sopenharmony_ci NUM_DSCRS_PER_CHANNEL, 2548c2ecf20Sopenharmony_ci ACP_DMA_PRIORITY_LEVEL_NORMAL); 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci/* 2588c2ecf20Sopenharmony_ci * Initialize the DMA descriptor information for transfer between 2598c2ecf20Sopenharmony_ci * ACP SRAM <-> I2S 2608c2ecf20Sopenharmony_ci */ 2618c2ecf20Sopenharmony_cistatic void set_acp_to_i2s_dma_descriptors(void __iomem *acp_mmio, u32 size, 2628c2ecf20Sopenharmony_ci int direction, u32 sram_bank, 2638c2ecf20Sopenharmony_ci u16 destination, u16 ch, 2648c2ecf20Sopenharmony_ci u16 dma_dscr_idx, u32 asic_type) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci u16 i; 2678c2ecf20Sopenharmony_ci acp_dma_dscr_transfer_t dmadscr[NUM_DSCRS_PER_CHANNEL]; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci for (i = 0; i < NUM_DSCRS_PER_CHANNEL; i++) { 2708c2ecf20Sopenharmony_ci dmadscr[i].xfer_val = 0; 2718c2ecf20Sopenharmony_ci if (direction == SNDRV_PCM_STREAM_PLAYBACK) { 2728c2ecf20Sopenharmony_ci dma_dscr_idx = dma_dscr_idx + i; 2738c2ecf20Sopenharmony_ci dmadscr[i].src = sram_bank + (i * (size / 2)); 2748c2ecf20Sopenharmony_ci /* dmadscr[i].dest is unused by hardware. */ 2758c2ecf20Sopenharmony_ci dmadscr[i].dest = 0; 2768c2ecf20Sopenharmony_ci dmadscr[i].xfer_val |= BIT(22) | (destination << 16) | 2778c2ecf20Sopenharmony_ci (size / 2); 2788c2ecf20Sopenharmony_ci } else { 2798c2ecf20Sopenharmony_ci dma_dscr_idx = dma_dscr_idx + i; 2808c2ecf20Sopenharmony_ci /* dmadscr[i].src is unused by hardware. */ 2818c2ecf20Sopenharmony_ci dmadscr[i].src = 0; 2828c2ecf20Sopenharmony_ci dmadscr[i].dest = 2838c2ecf20Sopenharmony_ci sram_bank + (i * (size / 2)); 2848c2ecf20Sopenharmony_ci dmadscr[i].xfer_val |= BIT(22) | 2858c2ecf20Sopenharmony_ci (destination << 16) | (size / 2); 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci config_dma_descriptor_in_sram(acp_mmio, dma_dscr_idx, 2888c2ecf20Sopenharmony_ci &dmadscr[i]); 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci pre_config_reset(acp_mmio, ch); 2918c2ecf20Sopenharmony_ci /* Configure the DMA channel with the above descriptore */ 2928c2ecf20Sopenharmony_ci config_acp_dma_channel(acp_mmio, ch, dma_dscr_idx - 1, 2938c2ecf20Sopenharmony_ci NUM_DSCRS_PER_CHANNEL, 2948c2ecf20Sopenharmony_ci ACP_DMA_PRIORITY_LEVEL_NORMAL); 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci/* Create page table entries in ACP SRAM for the allocated memory */ 2988c2ecf20Sopenharmony_cistatic void acp_pte_config(void __iomem *acp_mmio, dma_addr_t addr, 2998c2ecf20Sopenharmony_ci u16 num_of_pages, u32 pte_offset) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci u16 page_idx; 3028c2ecf20Sopenharmony_ci u32 low; 3038c2ecf20Sopenharmony_ci u32 high; 3048c2ecf20Sopenharmony_ci u32 offset; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci offset = ACP_DAGB_GRP_SRBM_SRAM_BASE_OFFSET + (pte_offset * 8); 3078c2ecf20Sopenharmony_ci for (page_idx = 0; page_idx < (num_of_pages); page_idx++) { 3088c2ecf20Sopenharmony_ci /* Load the low address of page int ACP SRAM through SRBM */ 3098c2ecf20Sopenharmony_ci acp_reg_write((offset + (page_idx * 8)), 3108c2ecf20Sopenharmony_ci acp_mmio, mmACP_SRBM_Targ_Idx_Addr); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci low = lower_32_bits(addr); 3138c2ecf20Sopenharmony_ci high = upper_32_bits(addr); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci acp_reg_write(low, acp_mmio, mmACP_SRBM_Targ_Idx_Data); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci /* Load the High address of page int ACP SRAM through SRBM */ 3188c2ecf20Sopenharmony_ci acp_reg_write((offset + (page_idx * 8) + 4), 3198c2ecf20Sopenharmony_ci acp_mmio, mmACP_SRBM_Targ_Idx_Addr); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* page enable in ACP */ 3228c2ecf20Sopenharmony_ci high |= BIT(31); 3238c2ecf20Sopenharmony_ci acp_reg_write(high, acp_mmio, mmACP_SRBM_Targ_Idx_Data); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci /* Move to next physically contiguos page */ 3268c2ecf20Sopenharmony_ci addr += PAGE_SIZE; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic void config_acp_dma(void __iomem *acp_mmio, 3318c2ecf20Sopenharmony_ci struct audio_substream_data *rtd, 3328c2ecf20Sopenharmony_ci u32 asic_type) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci u16 ch_acp_sysmem, ch_acp_i2s; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci acp_pte_config(acp_mmio, rtd->dma_addr, rtd->num_of_pages, 3378c2ecf20Sopenharmony_ci rtd->pte_offset); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (rtd->direction == SNDRV_PCM_STREAM_PLAYBACK) { 3408c2ecf20Sopenharmony_ci ch_acp_sysmem = rtd->ch1; 3418c2ecf20Sopenharmony_ci ch_acp_i2s = rtd->ch2; 3428c2ecf20Sopenharmony_ci } else { 3438c2ecf20Sopenharmony_ci ch_acp_i2s = rtd->ch1; 3448c2ecf20Sopenharmony_ci ch_acp_sysmem = rtd->ch2; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci /* Configure System memory <-> ACP SRAM DMA descriptors */ 3478c2ecf20Sopenharmony_ci set_acp_sysmem_dma_descriptors(acp_mmio, rtd->size, 3488c2ecf20Sopenharmony_ci rtd->direction, rtd->pte_offset, 3498c2ecf20Sopenharmony_ci ch_acp_sysmem, rtd->sram_bank, 3508c2ecf20Sopenharmony_ci rtd->dma_dscr_idx_1, asic_type); 3518c2ecf20Sopenharmony_ci /* Configure ACP SRAM <-> I2S DMA descriptors */ 3528c2ecf20Sopenharmony_ci set_acp_to_i2s_dma_descriptors(acp_mmio, rtd->size, 3538c2ecf20Sopenharmony_ci rtd->direction, rtd->sram_bank, 3548c2ecf20Sopenharmony_ci rtd->destination, ch_acp_i2s, 3558c2ecf20Sopenharmony_ci rtd->dma_dscr_idx_2, asic_type); 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic void acp_dma_cap_channel_enable(void __iomem *acp_mmio, 3598c2ecf20Sopenharmony_ci u16 cap_channel) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci u32 val, ch_reg, imr_reg, res_reg; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci switch (cap_channel) { 3648c2ecf20Sopenharmony_ci case CAP_CHANNEL1: 3658c2ecf20Sopenharmony_ci ch_reg = mmACP_I2SMICSP_RER1; 3668c2ecf20Sopenharmony_ci res_reg = mmACP_I2SMICSP_RCR1; 3678c2ecf20Sopenharmony_ci imr_reg = mmACP_I2SMICSP_IMR1; 3688c2ecf20Sopenharmony_ci break; 3698c2ecf20Sopenharmony_ci case CAP_CHANNEL0: 3708c2ecf20Sopenharmony_ci default: 3718c2ecf20Sopenharmony_ci ch_reg = mmACP_I2SMICSP_RER0; 3728c2ecf20Sopenharmony_ci res_reg = mmACP_I2SMICSP_RCR0; 3738c2ecf20Sopenharmony_ci imr_reg = mmACP_I2SMICSP_IMR0; 3748c2ecf20Sopenharmony_ci break; 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci val = acp_reg_read(acp_mmio, 3778c2ecf20Sopenharmony_ci mmACP_I2S_16BIT_RESOLUTION_EN); 3788c2ecf20Sopenharmony_ci if (val & ACP_I2S_MIC_16BIT_RESOLUTION_EN) { 3798c2ecf20Sopenharmony_ci acp_reg_write(0x0, acp_mmio, ch_reg); 3808c2ecf20Sopenharmony_ci /* Set 16bit resolution on capture */ 3818c2ecf20Sopenharmony_ci acp_reg_write(0x2, acp_mmio, res_reg); 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci val = acp_reg_read(acp_mmio, imr_reg); 3848c2ecf20Sopenharmony_ci val &= ~ACP_I2SMICSP_IMR1__I2SMICSP_RXDAM_MASK; 3858c2ecf20Sopenharmony_ci val &= ~ACP_I2SMICSP_IMR1__I2SMICSP_RXFOM_MASK; 3868c2ecf20Sopenharmony_ci acp_reg_write(val, acp_mmio, imr_reg); 3878c2ecf20Sopenharmony_ci acp_reg_write(0x1, acp_mmio, ch_reg); 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic void acp_dma_cap_channel_disable(void __iomem *acp_mmio, 3918c2ecf20Sopenharmony_ci u16 cap_channel) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci u32 val, ch_reg, imr_reg; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci switch (cap_channel) { 3968c2ecf20Sopenharmony_ci case CAP_CHANNEL1: 3978c2ecf20Sopenharmony_ci imr_reg = mmACP_I2SMICSP_IMR1; 3988c2ecf20Sopenharmony_ci ch_reg = mmACP_I2SMICSP_RER1; 3998c2ecf20Sopenharmony_ci break; 4008c2ecf20Sopenharmony_ci case CAP_CHANNEL0: 4018c2ecf20Sopenharmony_ci default: 4028c2ecf20Sopenharmony_ci imr_reg = mmACP_I2SMICSP_IMR0; 4038c2ecf20Sopenharmony_ci ch_reg = mmACP_I2SMICSP_RER0; 4048c2ecf20Sopenharmony_ci break; 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci val = acp_reg_read(acp_mmio, imr_reg); 4078c2ecf20Sopenharmony_ci val |= ACP_I2SMICSP_IMR1__I2SMICSP_RXDAM_MASK; 4088c2ecf20Sopenharmony_ci val |= ACP_I2SMICSP_IMR1__I2SMICSP_RXFOM_MASK; 4098c2ecf20Sopenharmony_ci acp_reg_write(val, acp_mmio, imr_reg); 4108c2ecf20Sopenharmony_ci acp_reg_write(0x0, acp_mmio, ch_reg); 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci/* Start a given DMA channel transfer */ 4148c2ecf20Sopenharmony_cistatic void acp_dma_start(void __iomem *acp_mmio, u16 ch_num, bool is_circular) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci u32 dma_ctrl; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci /* read the dma control register and disable the channel run field */ 4198c2ecf20Sopenharmony_ci dma_ctrl = acp_reg_read(acp_mmio, mmACP_DMA_CNTL_0 + ch_num); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci /* Invalidating the DAGB cache */ 4228c2ecf20Sopenharmony_ci acp_reg_write(1, acp_mmio, mmACP_DAGB_ATU_CTRL); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci /* 4258c2ecf20Sopenharmony_ci * configure the DMA channel and start the DMA transfer 4268c2ecf20Sopenharmony_ci * set dmachrun bit to start the transfer and enable the 4278c2ecf20Sopenharmony_ci * interrupt on completion of the dma transfer 4288c2ecf20Sopenharmony_ci */ 4298c2ecf20Sopenharmony_ci dma_ctrl |= ACP_DMA_CNTL_0__DMAChRun_MASK; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci switch (ch_num) { 4328c2ecf20Sopenharmony_ci case ACP_TO_I2S_DMA_CH_NUM: 4338c2ecf20Sopenharmony_ci case I2S_TO_ACP_DMA_CH_NUM: 4348c2ecf20Sopenharmony_ci case ACP_TO_I2S_DMA_BT_INSTANCE_CH_NUM: 4358c2ecf20Sopenharmony_ci case I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM: 4368c2ecf20Sopenharmony_ci dma_ctrl |= ACP_DMA_CNTL_0__DMAChIOCEn_MASK; 4378c2ecf20Sopenharmony_ci break; 4388c2ecf20Sopenharmony_ci default: 4398c2ecf20Sopenharmony_ci dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChIOCEn_MASK; 4408c2ecf20Sopenharmony_ci break; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci /* enable for ACP to SRAM DMA channel */ 4448c2ecf20Sopenharmony_ci if (is_circular == true) 4458c2ecf20Sopenharmony_ci dma_ctrl |= ACP_DMA_CNTL_0__Circular_DMA_En_MASK; 4468c2ecf20Sopenharmony_ci else 4478c2ecf20Sopenharmony_ci dma_ctrl &= ~ACP_DMA_CNTL_0__Circular_DMA_En_MASK; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num); 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci/* Stop a given DMA channel transfer */ 4538c2ecf20Sopenharmony_cistatic int acp_dma_stop(void __iomem *acp_mmio, u8 ch_num) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci u32 dma_ctrl; 4568c2ecf20Sopenharmony_ci u32 dma_ch_sts; 4578c2ecf20Sopenharmony_ci u32 count = ACP_DMA_RESET_TIME; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci dma_ctrl = acp_reg_read(acp_mmio, mmACP_DMA_CNTL_0 + ch_num); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* 4628c2ecf20Sopenharmony_ci * clear the dma control register fields before writing zero 4638c2ecf20Sopenharmony_ci * in reset bit 4648c2ecf20Sopenharmony_ci */ 4658c2ecf20Sopenharmony_ci dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChRun_MASK; 4668c2ecf20Sopenharmony_ci dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChIOCEn_MASK; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num); 4698c2ecf20Sopenharmony_ci dma_ch_sts = acp_reg_read(acp_mmio, mmACP_DMA_CH_STS); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (dma_ch_sts & BIT(ch_num)) { 4728c2ecf20Sopenharmony_ci /* 4738c2ecf20Sopenharmony_ci * set the reset bit for this channel to stop the dma 4748c2ecf20Sopenharmony_ci * transfer 4758c2ecf20Sopenharmony_ci */ 4768c2ecf20Sopenharmony_ci dma_ctrl |= ACP_DMA_CNTL_0__DMAChRst_MASK; 4778c2ecf20Sopenharmony_ci acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num); 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci /* check the channel status bit for some time and return the status */ 4818c2ecf20Sopenharmony_ci while (true) { 4828c2ecf20Sopenharmony_ci dma_ch_sts = acp_reg_read(acp_mmio, mmACP_DMA_CH_STS); 4838c2ecf20Sopenharmony_ci if (!(dma_ch_sts & BIT(ch_num))) { 4848c2ecf20Sopenharmony_ci /* 4858c2ecf20Sopenharmony_ci * clear the reset flag after successfully stopping 4868c2ecf20Sopenharmony_ci * the dma transfer and break from the loop 4878c2ecf20Sopenharmony_ci */ 4888c2ecf20Sopenharmony_ci dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChRst_MASK; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 4918c2ecf20Sopenharmony_ci + ch_num); 4928c2ecf20Sopenharmony_ci break; 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci if (--count == 0) { 4958c2ecf20Sopenharmony_ci pr_err("Failed to stop ACP DMA channel : %d\n", ch_num); 4968c2ecf20Sopenharmony_ci return -ETIMEDOUT; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci udelay(100); 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci return 0; 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_cistatic void acp_set_sram_bank_state(void __iomem *acp_mmio, u16 bank, 5048c2ecf20Sopenharmony_ci bool power_on) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci u32 val, req_reg, sts_reg, sts_reg_mask; 5078c2ecf20Sopenharmony_ci u32 loops = 1000; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci if (bank < 32) { 5108c2ecf20Sopenharmony_ci req_reg = mmACP_MEM_SHUT_DOWN_REQ_LO; 5118c2ecf20Sopenharmony_ci sts_reg = mmACP_MEM_SHUT_DOWN_STS_LO; 5128c2ecf20Sopenharmony_ci sts_reg_mask = 0xFFFFFFFF; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci } else { 5158c2ecf20Sopenharmony_ci bank -= 32; 5168c2ecf20Sopenharmony_ci req_reg = mmACP_MEM_SHUT_DOWN_REQ_HI; 5178c2ecf20Sopenharmony_ci sts_reg = mmACP_MEM_SHUT_DOWN_STS_HI; 5188c2ecf20Sopenharmony_ci sts_reg_mask = 0x0000FFFF; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci val = acp_reg_read(acp_mmio, req_reg); 5228c2ecf20Sopenharmony_ci if (val & (1 << bank)) { 5238c2ecf20Sopenharmony_ci /* bank is in off state */ 5248c2ecf20Sopenharmony_ci if (power_on == true) 5258c2ecf20Sopenharmony_ci /* request to on */ 5268c2ecf20Sopenharmony_ci val &= ~(1 << bank); 5278c2ecf20Sopenharmony_ci else 5288c2ecf20Sopenharmony_ci /* request to off */ 5298c2ecf20Sopenharmony_ci return; 5308c2ecf20Sopenharmony_ci } else { 5318c2ecf20Sopenharmony_ci /* bank is in on state */ 5328c2ecf20Sopenharmony_ci if (power_on == false) 5338c2ecf20Sopenharmony_ci /* request to off */ 5348c2ecf20Sopenharmony_ci val |= 1 << bank; 5358c2ecf20Sopenharmony_ci else 5368c2ecf20Sopenharmony_ci /* request to on */ 5378c2ecf20Sopenharmony_ci return; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci acp_reg_write(val, acp_mmio, req_reg); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci while (acp_reg_read(acp_mmio, sts_reg) != sts_reg_mask) { 5428c2ecf20Sopenharmony_ci if (!loops--) { 5438c2ecf20Sopenharmony_ci pr_err("ACP SRAM bank %d state change failed\n", bank); 5448c2ecf20Sopenharmony_ci break; 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci cpu_relax(); 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci} 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci/* Initialize and bring ACP hardware to default state. */ 5518c2ecf20Sopenharmony_cistatic int acp_init(void __iomem *acp_mmio, u32 asic_type) 5528c2ecf20Sopenharmony_ci{ 5538c2ecf20Sopenharmony_ci u16 bank; 5548c2ecf20Sopenharmony_ci u32 val, count, sram_pte_offset; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci /* Assert Soft reset of ACP */ 5578c2ecf20Sopenharmony_ci val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci val |= ACP_SOFT_RESET__SoftResetAud_MASK; 5608c2ecf20Sopenharmony_ci acp_reg_write(val, acp_mmio, mmACP_SOFT_RESET); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci count = ACP_SOFT_RESET_DONE_TIME_OUT_VALUE; 5638c2ecf20Sopenharmony_ci while (true) { 5648c2ecf20Sopenharmony_ci val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET); 5658c2ecf20Sopenharmony_ci if (ACP_SOFT_RESET__SoftResetAudDone_MASK == 5668c2ecf20Sopenharmony_ci (val & ACP_SOFT_RESET__SoftResetAudDone_MASK)) 5678c2ecf20Sopenharmony_ci break; 5688c2ecf20Sopenharmony_ci if (--count == 0) { 5698c2ecf20Sopenharmony_ci pr_err("Failed to reset ACP\n"); 5708c2ecf20Sopenharmony_ci return -ETIMEDOUT; 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci udelay(100); 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci /* Enable clock to ACP and wait until the clock is enabled */ 5768c2ecf20Sopenharmony_ci val = acp_reg_read(acp_mmio, mmACP_CONTROL); 5778c2ecf20Sopenharmony_ci val = val | ACP_CONTROL__ClkEn_MASK; 5788c2ecf20Sopenharmony_ci acp_reg_write(val, acp_mmio, mmACP_CONTROL); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci count = ACP_CLOCK_EN_TIME_OUT_VALUE; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci while (true) { 5838c2ecf20Sopenharmony_ci val = acp_reg_read(acp_mmio, mmACP_STATUS); 5848c2ecf20Sopenharmony_ci if (val & (u32)0x1) 5858c2ecf20Sopenharmony_ci break; 5868c2ecf20Sopenharmony_ci if (--count == 0) { 5878c2ecf20Sopenharmony_ci pr_err("Failed to reset ACP\n"); 5888c2ecf20Sopenharmony_ci return -ETIMEDOUT; 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci udelay(100); 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci /* Deassert the SOFT RESET flags */ 5948c2ecf20Sopenharmony_ci val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET); 5958c2ecf20Sopenharmony_ci val &= ~ACP_SOFT_RESET__SoftResetAud_MASK; 5968c2ecf20Sopenharmony_ci acp_reg_write(val, acp_mmio, mmACP_SOFT_RESET); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci /* For BT instance change pins from UART to BT */ 5998c2ecf20Sopenharmony_ci if (!bt_uart_enable) { 6008c2ecf20Sopenharmony_ci val = acp_reg_read(acp_mmio, mmACP_BT_UART_PAD_SEL); 6018c2ecf20Sopenharmony_ci val |= ACP_BT_UART_PAD_SELECT_MASK; 6028c2ecf20Sopenharmony_ci acp_reg_write(val, acp_mmio, mmACP_BT_UART_PAD_SEL); 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci /* initiailize Onion control DAGB register */ 6068c2ecf20Sopenharmony_ci acp_reg_write(ACP_ONION_CNTL_DEFAULT, acp_mmio, 6078c2ecf20Sopenharmony_ci mmACP_AXI2DAGB_ONION_CNTL); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci /* initiailize Garlic control DAGB registers */ 6108c2ecf20Sopenharmony_ci acp_reg_write(ACP_GARLIC_CNTL_DEFAULT, acp_mmio, 6118c2ecf20Sopenharmony_ci mmACP_AXI2DAGB_GARLIC_CNTL); 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci sram_pte_offset = ACP_DAGB_GRP_SRAM_BASE_ADDRESS | 6148c2ecf20Sopenharmony_ci ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBSnoopSel_MASK | 6158c2ecf20Sopenharmony_ci ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBTargetMemSel_MASK | 6168c2ecf20Sopenharmony_ci ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBGrpEnable_MASK; 6178c2ecf20Sopenharmony_ci acp_reg_write(sram_pte_offset, acp_mmio, mmACP_DAGB_BASE_ADDR_GRP_1); 6188c2ecf20Sopenharmony_ci acp_reg_write(ACP_PAGE_SIZE_4K_ENABLE, acp_mmio, 6198c2ecf20Sopenharmony_ci mmACP_DAGB_PAGE_SIZE_GRP_1); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci acp_reg_write(ACP_SRAM_BASE_ADDRESS, acp_mmio, 6228c2ecf20Sopenharmony_ci mmACP_DMA_DESC_BASE_ADDR); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci /* Num of descriptiors in SRAM 0x4, means 256 descriptors;(64 * 4) */ 6258c2ecf20Sopenharmony_ci acp_reg_write(0x4, acp_mmio, mmACP_DMA_DESC_MAX_NUM_DSCR); 6268c2ecf20Sopenharmony_ci acp_reg_write(ACP_EXTERNAL_INTR_CNTL__DMAIOCMask_MASK, 6278c2ecf20Sopenharmony_ci acp_mmio, mmACP_EXTERNAL_INTR_CNTL); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci /* 6308c2ecf20Sopenharmony_ci * When ACP_TILE_P1 is turned on, all SRAM banks get turned on. 6318c2ecf20Sopenharmony_ci * Now, turn off all of them. This can't be done in 'poweron' of 6328c2ecf20Sopenharmony_ci * ACP pm domain, as this requires ACP to be initialized. 6338c2ecf20Sopenharmony_ci * For Stoney, Memory gating is disabled,i.e SRAM Banks 6348c2ecf20Sopenharmony_ci * won't be turned off. The default state for SRAM banks is ON. 6358c2ecf20Sopenharmony_ci * Setting SRAM bank state code skipped for STONEY platform. 6368c2ecf20Sopenharmony_ci */ 6378c2ecf20Sopenharmony_ci if (asic_type != CHIP_STONEY) { 6388c2ecf20Sopenharmony_ci for (bank = 1; bank < 48; bank++) 6398c2ecf20Sopenharmony_ci acp_set_sram_bank_state(acp_mmio, bank, false); 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci return 0; 6428c2ecf20Sopenharmony_ci} 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci/* Deinitialize ACP */ 6458c2ecf20Sopenharmony_cistatic int acp_deinit(void __iomem *acp_mmio) 6468c2ecf20Sopenharmony_ci{ 6478c2ecf20Sopenharmony_ci u32 val; 6488c2ecf20Sopenharmony_ci u32 count; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci /* Assert Soft reset of ACP */ 6518c2ecf20Sopenharmony_ci val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci val |= ACP_SOFT_RESET__SoftResetAud_MASK; 6548c2ecf20Sopenharmony_ci acp_reg_write(val, acp_mmio, mmACP_SOFT_RESET); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci count = ACP_SOFT_RESET_DONE_TIME_OUT_VALUE; 6578c2ecf20Sopenharmony_ci while (true) { 6588c2ecf20Sopenharmony_ci val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET); 6598c2ecf20Sopenharmony_ci if (ACP_SOFT_RESET__SoftResetAudDone_MASK == 6608c2ecf20Sopenharmony_ci (val & ACP_SOFT_RESET__SoftResetAudDone_MASK)) 6618c2ecf20Sopenharmony_ci break; 6628c2ecf20Sopenharmony_ci if (--count == 0) { 6638c2ecf20Sopenharmony_ci pr_err("Failed to reset ACP\n"); 6648c2ecf20Sopenharmony_ci return -ETIMEDOUT; 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci udelay(100); 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci /* Disable ACP clock */ 6698c2ecf20Sopenharmony_ci val = acp_reg_read(acp_mmio, mmACP_CONTROL); 6708c2ecf20Sopenharmony_ci val &= ~ACP_CONTROL__ClkEn_MASK; 6718c2ecf20Sopenharmony_ci acp_reg_write(val, acp_mmio, mmACP_CONTROL); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci count = ACP_CLOCK_EN_TIME_OUT_VALUE; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci while (true) { 6768c2ecf20Sopenharmony_ci val = acp_reg_read(acp_mmio, mmACP_STATUS); 6778c2ecf20Sopenharmony_ci if (!(val & (u32)0x1)) 6788c2ecf20Sopenharmony_ci break; 6798c2ecf20Sopenharmony_ci if (--count == 0) { 6808c2ecf20Sopenharmony_ci pr_err("Failed to reset ACP\n"); 6818c2ecf20Sopenharmony_ci return -ETIMEDOUT; 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci udelay(100); 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci return 0; 6868c2ecf20Sopenharmony_ci} 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci/* ACP DMA irq handler routine for playback, capture usecases */ 6898c2ecf20Sopenharmony_cistatic irqreturn_t dma_irq_handler(int irq, void *arg) 6908c2ecf20Sopenharmony_ci{ 6918c2ecf20Sopenharmony_ci u16 dscr_idx; 6928c2ecf20Sopenharmony_ci u32 intr_flag, ext_intr_status; 6938c2ecf20Sopenharmony_ci struct audio_drv_data *irq_data; 6948c2ecf20Sopenharmony_ci void __iomem *acp_mmio; 6958c2ecf20Sopenharmony_ci struct device *dev = arg; 6968c2ecf20Sopenharmony_ci bool valid_irq = false; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci irq_data = dev_get_drvdata(dev); 6998c2ecf20Sopenharmony_ci acp_mmio = irq_data->acp_mmio; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci ext_intr_status = acp_reg_read(acp_mmio, mmACP_EXTERNAL_INTR_STAT); 7028c2ecf20Sopenharmony_ci intr_flag = (((ext_intr_status & 7038c2ecf20Sopenharmony_ci ACP_EXTERNAL_INTR_STAT__DMAIOCStat_MASK) >> 7048c2ecf20Sopenharmony_ci ACP_EXTERNAL_INTR_STAT__DMAIOCStat__SHIFT)); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci if ((intr_flag & BIT(ACP_TO_I2S_DMA_CH_NUM)) != 0) { 7078c2ecf20Sopenharmony_ci valid_irq = true; 7088c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(irq_data->play_i2ssp_stream); 7098c2ecf20Sopenharmony_ci acp_reg_write((intr_flag & BIT(ACP_TO_I2S_DMA_CH_NUM)) << 16, 7108c2ecf20Sopenharmony_ci acp_mmio, mmACP_EXTERNAL_INTR_STAT); 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci if ((intr_flag & BIT(ACP_TO_I2S_DMA_BT_INSTANCE_CH_NUM)) != 0) { 7148c2ecf20Sopenharmony_ci valid_irq = true; 7158c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(irq_data->play_i2sbt_stream); 7168c2ecf20Sopenharmony_ci acp_reg_write((intr_flag & 7178c2ecf20Sopenharmony_ci BIT(ACP_TO_I2S_DMA_BT_INSTANCE_CH_NUM)) << 16, 7188c2ecf20Sopenharmony_ci acp_mmio, mmACP_EXTERNAL_INTR_STAT); 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci if ((intr_flag & BIT(I2S_TO_ACP_DMA_CH_NUM)) != 0) { 7228c2ecf20Sopenharmony_ci valid_irq = true; 7238c2ecf20Sopenharmony_ci if (acp_reg_read(acp_mmio, mmACP_DMA_CUR_DSCR_14) == 7248c2ecf20Sopenharmony_ci CAPTURE_START_DMA_DESCR_CH15) 7258c2ecf20Sopenharmony_ci dscr_idx = CAPTURE_END_DMA_DESCR_CH14; 7268c2ecf20Sopenharmony_ci else 7278c2ecf20Sopenharmony_ci dscr_idx = CAPTURE_START_DMA_DESCR_CH14; 7288c2ecf20Sopenharmony_ci config_acp_dma_channel(acp_mmio, ACP_TO_SYSRAM_CH_NUM, dscr_idx, 7298c2ecf20Sopenharmony_ci 1, 0); 7308c2ecf20Sopenharmony_ci acp_dma_start(acp_mmio, ACP_TO_SYSRAM_CH_NUM, false); 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(irq_data->capture_i2ssp_stream); 7338c2ecf20Sopenharmony_ci acp_reg_write((intr_flag & BIT(I2S_TO_ACP_DMA_CH_NUM)) << 16, 7348c2ecf20Sopenharmony_ci acp_mmio, mmACP_EXTERNAL_INTR_STAT); 7358c2ecf20Sopenharmony_ci } 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci if ((intr_flag & BIT(I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM)) != 0) { 7388c2ecf20Sopenharmony_ci valid_irq = true; 7398c2ecf20Sopenharmony_ci if (acp_reg_read(acp_mmio, mmACP_DMA_CUR_DSCR_10) == 7408c2ecf20Sopenharmony_ci CAPTURE_START_DMA_DESCR_CH11) 7418c2ecf20Sopenharmony_ci dscr_idx = CAPTURE_END_DMA_DESCR_CH10; 7428c2ecf20Sopenharmony_ci else 7438c2ecf20Sopenharmony_ci dscr_idx = CAPTURE_START_DMA_DESCR_CH10; 7448c2ecf20Sopenharmony_ci config_acp_dma_channel(acp_mmio, 7458c2ecf20Sopenharmony_ci ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM, 7468c2ecf20Sopenharmony_ci dscr_idx, 1, 0); 7478c2ecf20Sopenharmony_ci acp_dma_start(acp_mmio, ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM, 7488c2ecf20Sopenharmony_ci false); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(irq_data->capture_i2sbt_stream); 7518c2ecf20Sopenharmony_ci acp_reg_write((intr_flag & 7528c2ecf20Sopenharmony_ci BIT(I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM)) << 16, 7538c2ecf20Sopenharmony_ci acp_mmio, mmACP_EXTERNAL_INTR_STAT); 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci if (valid_irq) 7578c2ecf20Sopenharmony_ci return IRQ_HANDLED; 7588c2ecf20Sopenharmony_ci else 7598c2ecf20Sopenharmony_ci return IRQ_NONE; 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_cistatic int acp_dma_open(struct snd_soc_component *component, 7638c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream) 7648c2ecf20Sopenharmony_ci{ 7658c2ecf20Sopenharmony_ci u16 bank; 7668c2ecf20Sopenharmony_ci int ret = 0; 7678c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 7688c2ecf20Sopenharmony_ci struct audio_drv_data *intr_data = dev_get_drvdata(component->dev); 7698c2ecf20Sopenharmony_ci struct audio_substream_data *adata = 7708c2ecf20Sopenharmony_ci kzalloc(sizeof(struct audio_substream_data), GFP_KERNEL); 7718c2ecf20Sopenharmony_ci if (!adata) 7728c2ecf20Sopenharmony_ci return -ENOMEM; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 7758c2ecf20Sopenharmony_ci switch (intr_data->asic_type) { 7768c2ecf20Sopenharmony_ci case CHIP_STONEY: 7778c2ecf20Sopenharmony_ci runtime->hw = acp_st_pcm_hardware_playback; 7788c2ecf20Sopenharmony_ci break; 7798c2ecf20Sopenharmony_ci default: 7808c2ecf20Sopenharmony_ci runtime->hw = acp_pcm_hardware_playback; 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci } else { 7838c2ecf20Sopenharmony_ci switch (intr_data->asic_type) { 7848c2ecf20Sopenharmony_ci case CHIP_STONEY: 7858c2ecf20Sopenharmony_ci runtime->hw = acp_st_pcm_hardware_capture; 7868c2ecf20Sopenharmony_ci break; 7878c2ecf20Sopenharmony_ci default: 7888c2ecf20Sopenharmony_ci runtime->hw = acp_pcm_hardware_capture; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci ret = snd_pcm_hw_constraint_integer(runtime, 7938c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIODS); 7948c2ecf20Sopenharmony_ci if (ret < 0) { 7958c2ecf20Sopenharmony_ci dev_err(component->dev, "set integer constraint failed\n"); 7968c2ecf20Sopenharmony_ci kfree(adata); 7978c2ecf20Sopenharmony_ci return ret; 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci adata->acp_mmio = intr_data->acp_mmio; 8018c2ecf20Sopenharmony_ci runtime->private_data = adata; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci /* 8048c2ecf20Sopenharmony_ci * Enable ACP irq, when neither playback or capture streams are 8058c2ecf20Sopenharmony_ci * active by the time when a new stream is being opened. 8068c2ecf20Sopenharmony_ci * This enablement is not required for another stream, if current 8078c2ecf20Sopenharmony_ci * stream is not closed 8088c2ecf20Sopenharmony_ci */ 8098c2ecf20Sopenharmony_ci if (!intr_data->play_i2ssp_stream && !intr_data->capture_i2ssp_stream && 8108c2ecf20Sopenharmony_ci !intr_data->play_i2sbt_stream && !intr_data->capture_i2sbt_stream) 8118c2ecf20Sopenharmony_ci acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB); 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 8148c2ecf20Sopenharmony_ci /* 8158c2ecf20Sopenharmony_ci * For Stoney, Memory gating is disabled,i.e SRAM Banks 8168c2ecf20Sopenharmony_ci * won't be turned off. The default state for SRAM banks is ON. 8178c2ecf20Sopenharmony_ci * Setting SRAM bank state code skipped for STONEY platform. 8188c2ecf20Sopenharmony_ci */ 8198c2ecf20Sopenharmony_ci if (intr_data->asic_type != CHIP_STONEY) { 8208c2ecf20Sopenharmony_ci for (bank = 1; bank <= 4; bank++) 8218c2ecf20Sopenharmony_ci acp_set_sram_bank_state(intr_data->acp_mmio, 8228c2ecf20Sopenharmony_ci bank, true); 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci } else { 8258c2ecf20Sopenharmony_ci if (intr_data->asic_type != CHIP_STONEY) { 8268c2ecf20Sopenharmony_ci for (bank = 5; bank <= 8; bank++) 8278c2ecf20Sopenharmony_ci acp_set_sram_bank_state(intr_data->acp_mmio, 8288c2ecf20Sopenharmony_ci bank, true); 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci return 0; 8338c2ecf20Sopenharmony_ci} 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_cistatic int acp_dma_hw_params(struct snd_soc_component *component, 8368c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream, 8378c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 8388c2ecf20Sopenharmony_ci{ 8398c2ecf20Sopenharmony_ci uint64_t size; 8408c2ecf20Sopenharmony_ci u32 val = 0; 8418c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime; 8428c2ecf20Sopenharmony_ci struct audio_substream_data *rtd; 8438c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *prtd = asoc_substream_to_rtd(substream); 8448c2ecf20Sopenharmony_ci struct audio_drv_data *adata = dev_get_drvdata(component->dev); 8458c2ecf20Sopenharmony_ci struct snd_soc_card *card = prtd->card; 8468c2ecf20Sopenharmony_ci struct acp_platform_info *pinfo = snd_soc_card_get_drvdata(card); 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci runtime = substream->runtime; 8498c2ecf20Sopenharmony_ci rtd = runtime->private_data; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci if (WARN_ON(!rtd)) 8528c2ecf20Sopenharmony_ci return -EINVAL; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci if (pinfo) { 8558c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 8568c2ecf20Sopenharmony_ci rtd->i2s_instance = pinfo->play_i2s_instance; 8578c2ecf20Sopenharmony_ci } else { 8588c2ecf20Sopenharmony_ci rtd->i2s_instance = pinfo->cap_i2s_instance; 8598c2ecf20Sopenharmony_ci rtd->capture_channel = pinfo->capture_channel; 8608c2ecf20Sopenharmony_ci } 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci if (adata->asic_type == CHIP_STONEY) { 8638c2ecf20Sopenharmony_ci val = acp_reg_read(adata->acp_mmio, 8648c2ecf20Sopenharmony_ci mmACP_I2S_16BIT_RESOLUTION_EN); 8658c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 8668c2ecf20Sopenharmony_ci switch (rtd->i2s_instance) { 8678c2ecf20Sopenharmony_ci case I2S_BT_INSTANCE: 8688c2ecf20Sopenharmony_ci val |= ACP_I2S_BT_16BIT_RESOLUTION_EN; 8698c2ecf20Sopenharmony_ci break; 8708c2ecf20Sopenharmony_ci case I2S_SP_INSTANCE: 8718c2ecf20Sopenharmony_ci default: 8728c2ecf20Sopenharmony_ci val |= ACP_I2S_SP_16BIT_RESOLUTION_EN; 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci } else { 8758c2ecf20Sopenharmony_ci switch (rtd->i2s_instance) { 8768c2ecf20Sopenharmony_ci case I2S_BT_INSTANCE: 8778c2ecf20Sopenharmony_ci val |= ACP_I2S_BT_16BIT_RESOLUTION_EN; 8788c2ecf20Sopenharmony_ci break; 8798c2ecf20Sopenharmony_ci case I2S_SP_INSTANCE: 8808c2ecf20Sopenharmony_ci default: 8818c2ecf20Sopenharmony_ci val |= ACP_I2S_MIC_16BIT_RESOLUTION_EN; 8828c2ecf20Sopenharmony_ci } 8838c2ecf20Sopenharmony_ci } 8848c2ecf20Sopenharmony_ci acp_reg_write(val, adata->acp_mmio, 8858c2ecf20Sopenharmony_ci mmACP_I2S_16BIT_RESOLUTION_EN); 8868c2ecf20Sopenharmony_ci } 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 8898c2ecf20Sopenharmony_ci switch (rtd->i2s_instance) { 8908c2ecf20Sopenharmony_ci case I2S_BT_INSTANCE: 8918c2ecf20Sopenharmony_ci rtd->pte_offset = ACP_ST_BT_PLAYBACK_PTE_OFFSET; 8928c2ecf20Sopenharmony_ci rtd->ch1 = SYSRAM_TO_ACP_BT_INSTANCE_CH_NUM; 8938c2ecf20Sopenharmony_ci rtd->ch2 = ACP_TO_I2S_DMA_BT_INSTANCE_CH_NUM; 8948c2ecf20Sopenharmony_ci rtd->sram_bank = ACP_SRAM_BANK_3_ADDRESS; 8958c2ecf20Sopenharmony_ci rtd->destination = TO_BLUETOOTH; 8968c2ecf20Sopenharmony_ci rtd->dma_dscr_idx_1 = PLAYBACK_START_DMA_DESCR_CH8; 8978c2ecf20Sopenharmony_ci rtd->dma_dscr_idx_2 = PLAYBACK_START_DMA_DESCR_CH9; 8988c2ecf20Sopenharmony_ci rtd->byte_cnt_high_reg_offset = 8998c2ecf20Sopenharmony_ci mmACP_I2S_BT_TRANSMIT_BYTE_CNT_HIGH; 9008c2ecf20Sopenharmony_ci rtd->byte_cnt_low_reg_offset = 9018c2ecf20Sopenharmony_ci mmACP_I2S_BT_TRANSMIT_BYTE_CNT_LOW; 9028c2ecf20Sopenharmony_ci adata->play_i2sbt_stream = substream; 9038c2ecf20Sopenharmony_ci break; 9048c2ecf20Sopenharmony_ci case I2S_SP_INSTANCE: 9058c2ecf20Sopenharmony_ci default: 9068c2ecf20Sopenharmony_ci switch (adata->asic_type) { 9078c2ecf20Sopenharmony_ci case CHIP_STONEY: 9088c2ecf20Sopenharmony_ci rtd->pte_offset = ACP_ST_PLAYBACK_PTE_OFFSET; 9098c2ecf20Sopenharmony_ci break; 9108c2ecf20Sopenharmony_ci default: 9118c2ecf20Sopenharmony_ci rtd->pte_offset = ACP_PLAYBACK_PTE_OFFSET; 9128c2ecf20Sopenharmony_ci } 9138c2ecf20Sopenharmony_ci rtd->ch1 = SYSRAM_TO_ACP_CH_NUM; 9148c2ecf20Sopenharmony_ci rtd->ch2 = ACP_TO_I2S_DMA_CH_NUM; 9158c2ecf20Sopenharmony_ci rtd->sram_bank = ACP_SRAM_BANK_1_ADDRESS; 9168c2ecf20Sopenharmony_ci rtd->destination = TO_ACP_I2S_1; 9178c2ecf20Sopenharmony_ci rtd->dma_dscr_idx_1 = PLAYBACK_START_DMA_DESCR_CH12; 9188c2ecf20Sopenharmony_ci rtd->dma_dscr_idx_2 = PLAYBACK_START_DMA_DESCR_CH13; 9198c2ecf20Sopenharmony_ci rtd->byte_cnt_high_reg_offset = 9208c2ecf20Sopenharmony_ci mmACP_I2S_TRANSMIT_BYTE_CNT_HIGH; 9218c2ecf20Sopenharmony_ci rtd->byte_cnt_low_reg_offset = 9228c2ecf20Sopenharmony_ci mmACP_I2S_TRANSMIT_BYTE_CNT_LOW; 9238c2ecf20Sopenharmony_ci adata->play_i2ssp_stream = substream; 9248c2ecf20Sopenharmony_ci } 9258c2ecf20Sopenharmony_ci } else { 9268c2ecf20Sopenharmony_ci switch (rtd->i2s_instance) { 9278c2ecf20Sopenharmony_ci case I2S_BT_INSTANCE: 9288c2ecf20Sopenharmony_ci rtd->pte_offset = ACP_ST_BT_CAPTURE_PTE_OFFSET; 9298c2ecf20Sopenharmony_ci rtd->ch1 = I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM; 9308c2ecf20Sopenharmony_ci rtd->ch2 = ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM; 9318c2ecf20Sopenharmony_ci rtd->sram_bank = ACP_SRAM_BANK_4_ADDRESS; 9328c2ecf20Sopenharmony_ci rtd->destination = FROM_BLUETOOTH; 9338c2ecf20Sopenharmony_ci rtd->dma_dscr_idx_1 = CAPTURE_START_DMA_DESCR_CH10; 9348c2ecf20Sopenharmony_ci rtd->dma_dscr_idx_2 = CAPTURE_START_DMA_DESCR_CH11; 9358c2ecf20Sopenharmony_ci rtd->byte_cnt_high_reg_offset = 9368c2ecf20Sopenharmony_ci mmACP_I2S_BT_RECEIVE_BYTE_CNT_HIGH; 9378c2ecf20Sopenharmony_ci rtd->byte_cnt_low_reg_offset = 9388c2ecf20Sopenharmony_ci mmACP_I2S_BT_RECEIVE_BYTE_CNT_LOW; 9398c2ecf20Sopenharmony_ci rtd->dma_curr_dscr = mmACP_DMA_CUR_DSCR_11; 9408c2ecf20Sopenharmony_ci adata->capture_i2sbt_stream = substream; 9418c2ecf20Sopenharmony_ci break; 9428c2ecf20Sopenharmony_ci case I2S_SP_INSTANCE: 9438c2ecf20Sopenharmony_ci default: 9448c2ecf20Sopenharmony_ci rtd->pte_offset = ACP_CAPTURE_PTE_OFFSET; 9458c2ecf20Sopenharmony_ci rtd->ch1 = I2S_TO_ACP_DMA_CH_NUM; 9468c2ecf20Sopenharmony_ci rtd->ch2 = ACP_TO_SYSRAM_CH_NUM; 9478c2ecf20Sopenharmony_ci switch (adata->asic_type) { 9488c2ecf20Sopenharmony_ci case CHIP_STONEY: 9498c2ecf20Sopenharmony_ci rtd->pte_offset = ACP_ST_CAPTURE_PTE_OFFSET; 9508c2ecf20Sopenharmony_ci rtd->sram_bank = ACP_SRAM_BANK_2_ADDRESS; 9518c2ecf20Sopenharmony_ci break; 9528c2ecf20Sopenharmony_ci default: 9538c2ecf20Sopenharmony_ci rtd->pte_offset = ACP_CAPTURE_PTE_OFFSET; 9548c2ecf20Sopenharmony_ci rtd->sram_bank = ACP_SRAM_BANK_5_ADDRESS; 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci rtd->destination = FROM_ACP_I2S_1; 9578c2ecf20Sopenharmony_ci rtd->dma_dscr_idx_1 = CAPTURE_START_DMA_DESCR_CH14; 9588c2ecf20Sopenharmony_ci rtd->dma_dscr_idx_2 = CAPTURE_START_DMA_DESCR_CH15; 9598c2ecf20Sopenharmony_ci rtd->byte_cnt_high_reg_offset = 9608c2ecf20Sopenharmony_ci mmACP_I2S_RECEIVED_BYTE_CNT_HIGH; 9618c2ecf20Sopenharmony_ci rtd->byte_cnt_low_reg_offset = 9628c2ecf20Sopenharmony_ci mmACP_I2S_RECEIVED_BYTE_CNT_LOW; 9638c2ecf20Sopenharmony_ci rtd->dma_curr_dscr = mmACP_DMA_CUR_DSCR_15; 9648c2ecf20Sopenharmony_ci adata->capture_i2ssp_stream = substream; 9658c2ecf20Sopenharmony_ci } 9668c2ecf20Sopenharmony_ci } 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci size = params_buffer_bytes(params); 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci acp_set_sram_bank_state(rtd->acp_mmio, 0, true); 9718c2ecf20Sopenharmony_ci /* Save for runtime private data */ 9728c2ecf20Sopenharmony_ci rtd->dma_addr = runtime->dma_addr; 9738c2ecf20Sopenharmony_ci rtd->order = get_order(size); 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci /* Fill the page table entries in ACP SRAM */ 9768c2ecf20Sopenharmony_ci rtd->size = size; 9778c2ecf20Sopenharmony_ci rtd->num_of_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; 9788c2ecf20Sopenharmony_ci rtd->direction = substream->stream; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci config_acp_dma(rtd->acp_mmio, rtd, adata->asic_type); 9818c2ecf20Sopenharmony_ci return 0; 9828c2ecf20Sopenharmony_ci} 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_cistatic u64 acp_get_byte_count(struct audio_substream_data *rtd) 9858c2ecf20Sopenharmony_ci{ 9868c2ecf20Sopenharmony_ci union acp_dma_count byte_count; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci byte_count.bcount.high = acp_reg_read(rtd->acp_mmio, 9898c2ecf20Sopenharmony_ci rtd->byte_cnt_high_reg_offset); 9908c2ecf20Sopenharmony_ci byte_count.bcount.low = acp_reg_read(rtd->acp_mmio, 9918c2ecf20Sopenharmony_ci rtd->byte_cnt_low_reg_offset); 9928c2ecf20Sopenharmony_ci return byte_count.bytescount; 9938c2ecf20Sopenharmony_ci} 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t acp_dma_pointer(struct snd_soc_component *component, 9968c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream) 9978c2ecf20Sopenharmony_ci{ 9988c2ecf20Sopenharmony_ci u32 buffersize; 9998c2ecf20Sopenharmony_ci u32 pos = 0; 10008c2ecf20Sopenharmony_ci u64 bytescount = 0; 10018c2ecf20Sopenharmony_ci u16 dscr; 10028c2ecf20Sopenharmony_ci u32 period_bytes, delay; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 10058c2ecf20Sopenharmony_ci struct audio_substream_data *rtd = runtime->private_data; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci if (!rtd) 10088c2ecf20Sopenharmony_ci return -EINVAL; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 10118c2ecf20Sopenharmony_ci period_bytes = frames_to_bytes(runtime, runtime->period_size); 10128c2ecf20Sopenharmony_ci bytescount = acp_get_byte_count(rtd); 10138c2ecf20Sopenharmony_ci if (bytescount >= rtd->bytescount) 10148c2ecf20Sopenharmony_ci bytescount -= rtd->bytescount; 10158c2ecf20Sopenharmony_ci if (bytescount < period_bytes) { 10168c2ecf20Sopenharmony_ci pos = 0; 10178c2ecf20Sopenharmony_ci } else { 10188c2ecf20Sopenharmony_ci dscr = acp_reg_read(rtd->acp_mmio, rtd->dma_curr_dscr); 10198c2ecf20Sopenharmony_ci if (dscr == rtd->dma_dscr_idx_1) 10208c2ecf20Sopenharmony_ci pos = period_bytes; 10218c2ecf20Sopenharmony_ci else 10228c2ecf20Sopenharmony_ci pos = 0; 10238c2ecf20Sopenharmony_ci } 10248c2ecf20Sopenharmony_ci if (bytescount > 0) { 10258c2ecf20Sopenharmony_ci delay = do_div(bytescount, period_bytes); 10268c2ecf20Sopenharmony_ci runtime->delay = bytes_to_frames(runtime, delay); 10278c2ecf20Sopenharmony_ci } 10288c2ecf20Sopenharmony_ci } else { 10298c2ecf20Sopenharmony_ci buffersize = frames_to_bytes(runtime, runtime->buffer_size); 10308c2ecf20Sopenharmony_ci bytescount = acp_get_byte_count(rtd); 10318c2ecf20Sopenharmony_ci if (bytescount > rtd->bytescount) 10328c2ecf20Sopenharmony_ci bytescount -= rtd->bytescount; 10338c2ecf20Sopenharmony_ci pos = do_div(bytescount, buffersize); 10348c2ecf20Sopenharmony_ci } 10358c2ecf20Sopenharmony_ci return bytes_to_frames(runtime, pos); 10368c2ecf20Sopenharmony_ci} 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_cistatic int acp_dma_mmap(struct snd_soc_component *component, 10398c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream, 10408c2ecf20Sopenharmony_ci struct vm_area_struct *vma) 10418c2ecf20Sopenharmony_ci{ 10428c2ecf20Sopenharmony_ci return snd_pcm_lib_default_mmap(substream, vma); 10438c2ecf20Sopenharmony_ci} 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_cistatic int acp_dma_prepare(struct snd_soc_component *component, 10468c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream) 10478c2ecf20Sopenharmony_ci{ 10488c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 10498c2ecf20Sopenharmony_ci struct audio_substream_data *rtd = runtime->private_data; 10508c2ecf20Sopenharmony_ci u16 ch_acp_sysmem, ch_acp_i2s; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci if (!rtd) 10538c2ecf20Sopenharmony_ci return -EINVAL; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci if (rtd->direction == SNDRV_PCM_STREAM_PLAYBACK) { 10568c2ecf20Sopenharmony_ci ch_acp_sysmem = rtd->ch1; 10578c2ecf20Sopenharmony_ci ch_acp_i2s = rtd->ch2; 10588c2ecf20Sopenharmony_ci } else { 10598c2ecf20Sopenharmony_ci ch_acp_i2s = rtd->ch1; 10608c2ecf20Sopenharmony_ci ch_acp_sysmem = rtd->ch2; 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci config_acp_dma_channel(rtd->acp_mmio, 10638c2ecf20Sopenharmony_ci ch_acp_sysmem, 10648c2ecf20Sopenharmony_ci rtd->dma_dscr_idx_1, 10658c2ecf20Sopenharmony_ci NUM_DSCRS_PER_CHANNEL, 0); 10668c2ecf20Sopenharmony_ci config_acp_dma_channel(rtd->acp_mmio, 10678c2ecf20Sopenharmony_ci ch_acp_i2s, 10688c2ecf20Sopenharmony_ci rtd->dma_dscr_idx_2, 10698c2ecf20Sopenharmony_ci NUM_DSCRS_PER_CHANNEL, 0); 10708c2ecf20Sopenharmony_ci return 0; 10718c2ecf20Sopenharmony_ci} 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_cistatic int acp_dma_trigger(struct snd_soc_component *component, 10748c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream, int cmd) 10758c2ecf20Sopenharmony_ci{ 10768c2ecf20Sopenharmony_ci int ret; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 10798c2ecf20Sopenharmony_ci struct audio_substream_data *rtd = runtime->private_data; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci if (!rtd) 10828c2ecf20Sopenharmony_ci return -EINVAL; 10838c2ecf20Sopenharmony_ci switch (cmd) { 10848c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 10858c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 10868c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 10878c2ecf20Sopenharmony_ci rtd->bytescount = acp_get_byte_count(rtd); 10888c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 10898c2ecf20Sopenharmony_ci if (rtd->capture_channel == CAP_CHANNEL0) { 10908c2ecf20Sopenharmony_ci acp_dma_cap_channel_disable(rtd->acp_mmio, 10918c2ecf20Sopenharmony_ci CAP_CHANNEL1); 10928c2ecf20Sopenharmony_ci acp_dma_cap_channel_enable(rtd->acp_mmio, 10938c2ecf20Sopenharmony_ci CAP_CHANNEL0); 10948c2ecf20Sopenharmony_ci } 10958c2ecf20Sopenharmony_ci if (rtd->capture_channel == CAP_CHANNEL1) { 10968c2ecf20Sopenharmony_ci acp_dma_cap_channel_disable(rtd->acp_mmio, 10978c2ecf20Sopenharmony_ci CAP_CHANNEL0); 10988c2ecf20Sopenharmony_ci acp_dma_cap_channel_enable(rtd->acp_mmio, 10998c2ecf20Sopenharmony_ci CAP_CHANNEL1); 11008c2ecf20Sopenharmony_ci } 11018c2ecf20Sopenharmony_ci acp_dma_start(rtd->acp_mmio, rtd->ch1, true); 11028c2ecf20Sopenharmony_ci } else { 11038c2ecf20Sopenharmony_ci acp_dma_start(rtd->acp_mmio, rtd->ch1, true); 11048c2ecf20Sopenharmony_ci acp_dma_start(rtd->acp_mmio, rtd->ch2, true); 11058c2ecf20Sopenharmony_ci } 11068c2ecf20Sopenharmony_ci ret = 0; 11078c2ecf20Sopenharmony_ci break; 11088c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 11098c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 11108c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 11118c2ecf20Sopenharmony_ci acp_dma_stop(rtd->acp_mmio, rtd->ch2); 11128c2ecf20Sopenharmony_ci ret = acp_dma_stop(rtd->acp_mmio, rtd->ch1); 11138c2ecf20Sopenharmony_ci break; 11148c2ecf20Sopenharmony_ci default: 11158c2ecf20Sopenharmony_ci ret = -EINVAL; 11168c2ecf20Sopenharmony_ci } 11178c2ecf20Sopenharmony_ci return ret; 11188c2ecf20Sopenharmony_ci} 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_cistatic int acp_dma_new(struct snd_soc_component *component, 11218c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd) 11228c2ecf20Sopenharmony_ci{ 11238c2ecf20Sopenharmony_ci struct audio_drv_data *adata = dev_get_drvdata(component->dev); 11248c2ecf20Sopenharmony_ci struct device *parent = component->dev->parent; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci switch (adata->asic_type) { 11278c2ecf20Sopenharmony_ci case CHIP_STONEY: 11288c2ecf20Sopenharmony_ci snd_pcm_set_managed_buffer_all(rtd->pcm, 11298c2ecf20Sopenharmony_ci SNDRV_DMA_TYPE_DEV, 11308c2ecf20Sopenharmony_ci parent, 11318c2ecf20Sopenharmony_ci ST_MIN_BUFFER, 11328c2ecf20Sopenharmony_ci ST_MAX_BUFFER); 11338c2ecf20Sopenharmony_ci break; 11348c2ecf20Sopenharmony_ci default: 11358c2ecf20Sopenharmony_ci snd_pcm_set_managed_buffer_all(rtd->pcm, 11368c2ecf20Sopenharmony_ci SNDRV_DMA_TYPE_DEV, 11378c2ecf20Sopenharmony_ci parent, 11388c2ecf20Sopenharmony_ci MIN_BUFFER, 11398c2ecf20Sopenharmony_ci MAX_BUFFER); 11408c2ecf20Sopenharmony_ci break; 11418c2ecf20Sopenharmony_ci } 11428c2ecf20Sopenharmony_ci return 0; 11438c2ecf20Sopenharmony_ci} 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_cistatic int acp_dma_close(struct snd_soc_component *component, 11468c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream) 11478c2ecf20Sopenharmony_ci{ 11488c2ecf20Sopenharmony_ci u16 bank; 11498c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 11508c2ecf20Sopenharmony_ci struct audio_substream_data *rtd = runtime->private_data; 11518c2ecf20Sopenharmony_ci struct audio_drv_data *adata = dev_get_drvdata(component->dev); 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 11548c2ecf20Sopenharmony_ci switch (rtd->i2s_instance) { 11558c2ecf20Sopenharmony_ci case I2S_BT_INSTANCE: 11568c2ecf20Sopenharmony_ci adata->play_i2sbt_stream = NULL; 11578c2ecf20Sopenharmony_ci break; 11588c2ecf20Sopenharmony_ci case I2S_SP_INSTANCE: 11598c2ecf20Sopenharmony_ci default: 11608c2ecf20Sopenharmony_ci adata->play_i2ssp_stream = NULL; 11618c2ecf20Sopenharmony_ci /* 11628c2ecf20Sopenharmony_ci * For Stoney, Memory gating is disabled,i.e SRAM Banks 11638c2ecf20Sopenharmony_ci * won't be turned off. The default state for SRAM banks 11648c2ecf20Sopenharmony_ci * is ON.Setting SRAM bank state code skipped for STONEY 11658c2ecf20Sopenharmony_ci * platform. Added condition checks for Carrizo platform 11668c2ecf20Sopenharmony_ci * only. 11678c2ecf20Sopenharmony_ci */ 11688c2ecf20Sopenharmony_ci if (adata->asic_type != CHIP_STONEY) { 11698c2ecf20Sopenharmony_ci for (bank = 1; bank <= 4; bank++) 11708c2ecf20Sopenharmony_ci acp_set_sram_bank_state(adata->acp_mmio, 11718c2ecf20Sopenharmony_ci bank, false); 11728c2ecf20Sopenharmony_ci } 11738c2ecf20Sopenharmony_ci } 11748c2ecf20Sopenharmony_ci } else { 11758c2ecf20Sopenharmony_ci switch (rtd->i2s_instance) { 11768c2ecf20Sopenharmony_ci case I2S_BT_INSTANCE: 11778c2ecf20Sopenharmony_ci adata->capture_i2sbt_stream = NULL; 11788c2ecf20Sopenharmony_ci break; 11798c2ecf20Sopenharmony_ci case I2S_SP_INSTANCE: 11808c2ecf20Sopenharmony_ci default: 11818c2ecf20Sopenharmony_ci adata->capture_i2ssp_stream = NULL; 11828c2ecf20Sopenharmony_ci if (adata->asic_type != CHIP_STONEY) { 11838c2ecf20Sopenharmony_ci for (bank = 5; bank <= 8; bank++) 11848c2ecf20Sopenharmony_ci acp_set_sram_bank_state(adata->acp_mmio, 11858c2ecf20Sopenharmony_ci bank, false); 11868c2ecf20Sopenharmony_ci } 11878c2ecf20Sopenharmony_ci } 11888c2ecf20Sopenharmony_ci } 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci /* 11918c2ecf20Sopenharmony_ci * Disable ACP irq, when the current stream is being closed and 11928c2ecf20Sopenharmony_ci * another stream is also not active. 11938c2ecf20Sopenharmony_ci */ 11948c2ecf20Sopenharmony_ci if (!adata->play_i2ssp_stream && !adata->capture_i2ssp_stream && 11958c2ecf20Sopenharmony_ci !adata->play_i2sbt_stream && !adata->capture_i2sbt_stream) 11968c2ecf20Sopenharmony_ci acp_reg_write(0, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB); 11978c2ecf20Sopenharmony_ci kfree(rtd); 11988c2ecf20Sopenharmony_ci return 0; 11998c2ecf20Sopenharmony_ci} 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver acp_asoc_platform = { 12028c2ecf20Sopenharmony_ci .name = DRV_NAME, 12038c2ecf20Sopenharmony_ci .open = acp_dma_open, 12048c2ecf20Sopenharmony_ci .close = acp_dma_close, 12058c2ecf20Sopenharmony_ci .hw_params = acp_dma_hw_params, 12068c2ecf20Sopenharmony_ci .trigger = acp_dma_trigger, 12078c2ecf20Sopenharmony_ci .pointer = acp_dma_pointer, 12088c2ecf20Sopenharmony_ci .mmap = acp_dma_mmap, 12098c2ecf20Sopenharmony_ci .prepare = acp_dma_prepare, 12108c2ecf20Sopenharmony_ci .pcm_construct = acp_dma_new, 12118c2ecf20Sopenharmony_ci}; 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_cistatic int acp_audio_probe(struct platform_device *pdev) 12148c2ecf20Sopenharmony_ci{ 12158c2ecf20Sopenharmony_ci int status; 12168c2ecf20Sopenharmony_ci struct audio_drv_data *audio_drv_data; 12178c2ecf20Sopenharmony_ci struct resource *res; 12188c2ecf20Sopenharmony_ci const u32 *pdata = pdev->dev.platform_data; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci if (!pdata) { 12218c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Missing platform data\n"); 12228c2ecf20Sopenharmony_ci return -ENODEV; 12238c2ecf20Sopenharmony_ci } 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci audio_drv_data = devm_kzalloc(&pdev->dev, sizeof(struct audio_drv_data), 12268c2ecf20Sopenharmony_ci GFP_KERNEL); 12278c2ecf20Sopenharmony_ci if (!audio_drv_data) 12288c2ecf20Sopenharmony_ci return -ENOMEM; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci audio_drv_data->acp_mmio = devm_platform_ioremap_resource(pdev, 0); 12318c2ecf20Sopenharmony_ci if (IS_ERR(audio_drv_data->acp_mmio)) 12328c2ecf20Sopenharmony_ci return PTR_ERR(audio_drv_data->acp_mmio); 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci /* 12358c2ecf20Sopenharmony_ci * The following members gets populated in device 'open' 12368c2ecf20Sopenharmony_ci * function. Till then interrupts are disabled in 'acp_init' 12378c2ecf20Sopenharmony_ci * and device doesn't generate any interrupts. 12388c2ecf20Sopenharmony_ci */ 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci audio_drv_data->play_i2ssp_stream = NULL; 12418c2ecf20Sopenharmony_ci audio_drv_data->capture_i2ssp_stream = NULL; 12428c2ecf20Sopenharmony_ci audio_drv_data->play_i2sbt_stream = NULL; 12438c2ecf20Sopenharmony_ci audio_drv_data->capture_i2sbt_stream = NULL; 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci audio_drv_data->asic_type = *pdata; 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 12488c2ecf20Sopenharmony_ci if (!res) { 12498c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n"); 12508c2ecf20Sopenharmony_ci return -ENODEV; 12518c2ecf20Sopenharmony_ci } 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci status = devm_request_irq(&pdev->dev, res->start, dma_irq_handler, 12548c2ecf20Sopenharmony_ci 0, "ACP_IRQ", &pdev->dev); 12558c2ecf20Sopenharmony_ci if (status) { 12568c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "ACP IRQ request failed\n"); 12578c2ecf20Sopenharmony_ci return status; 12588c2ecf20Sopenharmony_ci } 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci dev_set_drvdata(&pdev->dev, audio_drv_data); 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci /* Initialize the ACP */ 12638c2ecf20Sopenharmony_ci status = acp_init(audio_drv_data->acp_mmio, audio_drv_data->asic_type); 12648c2ecf20Sopenharmony_ci if (status) { 12658c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "ACP Init failed status:%d\n", status); 12668c2ecf20Sopenharmony_ci return status; 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci status = devm_snd_soc_register_component(&pdev->dev, 12708c2ecf20Sopenharmony_ci &acp_asoc_platform, NULL, 0); 12718c2ecf20Sopenharmony_ci if (status != 0) { 12728c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Fail to register ALSA platform device\n"); 12738c2ecf20Sopenharmony_ci return status; 12748c2ecf20Sopenharmony_ci } 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(&pdev->dev, 10000); 12778c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(&pdev->dev); 12788c2ecf20Sopenharmony_ci pm_runtime_enable(&pdev->dev); 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci return status; 12818c2ecf20Sopenharmony_ci} 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_cistatic int acp_audio_remove(struct platform_device *pdev) 12848c2ecf20Sopenharmony_ci{ 12858c2ecf20Sopenharmony_ci int status; 12868c2ecf20Sopenharmony_ci struct audio_drv_data *adata = dev_get_drvdata(&pdev->dev); 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci status = acp_deinit(adata->acp_mmio); 12898c2ecf20Sopenharmony_ci if (status) 12908c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "ACP Deinit failed status:%d\n", status); 12918c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci return 0; 12948c2ecf20Sopenharmony_ci} 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_cistatic int acp_pcm_resume(struct device *dev) 12978c2ecf20Sopenharmony_ci{ 12988c2ecf20Sopenharmony_ci u16 bank; 12998c2ecf20Sopenharmony_ci int status; 13008c2ecf20Sopenharmony_ci struct audio_substream_data *rtd; 13018c2ecf20Sopenharmony_ci struct audio_drv_data *adata = dev_get_drvdata(dev); 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci status = acp_init(adata->acp_mmio, adata->asic_type); 13048c2ecf20Sopenharmony_ci if (status) { 13058c2ecf20Sopenharmony_ci dev_err(dev, "ACP Init failed status:%d\n", status); 13068c2ecf20Sopenharmony_ci return status; 13078c2ecf20Sopenharmony_ci } 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci if (adata->play_i2ssp_stream && adata->play_i2ssp_stream->runtime) { 13108c2ecf20Sopenharmony_ci /* 13118c2ecf20Sopenharmony_ci * For Stoney, Memory gating is disabled,i.e SRAM Banks 13128c2ecf20Sopenharmony_ci * won't be turned off. The default state for SRAM banks is ON. 13138c2ecf20Sopenharmony_ci * Setting SRAM bank state code skipped for STONEY platform. 13148c2ecf20Sopenharmony_ci */ 13158c2ecf20Sopenharmony_ci if (adata->asic_type != CHIP_STONEY) { 13168c2ecf20Sopenharmony_ci for (bank = 1; bank <= 4; bank++) 13178c2ecf20Sopenharmony_ci acp_set_sram_bank_state(adata->acp_mmio, bank, 13188c2ecf20Sopenharmony_ci true); 13198c2ecf20Sopenharmony_ci } 13208c2ecf20Sopenharmony_ci rtd = adata->play_i2ssp_stream->runtime->private_data; 13218c2ecf20Sopenharmony_ci config_acp_dma(adata->acp_mmio, rtd, adata->asic_type); 13228c2ecf20Sopenharmony_ci } 13238c2ecf20Sopenharmony_ci if (adata->capture_i2ssp_stream && 13248c2ecf20Sopenharmony_ci adata->capture_i2ssp_stream->runtime) { 13258c2ecf20Sopenharmony_ci if (adata->asic_type != CHIP_STONEY) { 13268c2ecf20Sopenharmony_ci for (bank = 5; bank <= 8; bank++) 13278c2ecf20Sopenharmony_ci acp_set_sram_bank_state(adata->acp_mmio, bank, 13288c2ecf20Sopenharmony_ci true); 13298c2ecf20Sopenharmony_ci } 13308c2ecf20Sopenharmony_ci rtd = adata->capture_i2ssp_stream->runtime->private_data; 13318c2ecf20Sopenharmony_ci config_acp_dma(adata->acp_mmio, rtd, adata->asic_type); 13328c2ecf20Sopenharmony_ci } 13338c2ecf20Sopenharmony_ci if (adata->asic_type != CHIP_CARRIZO) { 13348c2ecf20Sopenharmony_ci if (adata->play_i2sbt_stream && 13358c2ecf20Sopenharmony_ci adata->play_i2sbt_stream->runtime) { 13368c2ecf20Sopenharmony_ci rtd = adata->play_i2sbt_stream->runtime->private_data; 13378c2ecf20Sopenharmony_ci config_acp_dma(adata->acp_mmio, rtd, adata->asic_type); 13388c2ecf20Sopenharmony_ci } 13398c2ecf20Sopenharmony_ci if (adata->capture_i2sbt_stream && 13408c2ecf20Sopenharmony_ci adata->capture_i2sbt_stream->runtime) { 13418c2ecf20Sopenharmony_ci rtd = adata->capture_i2sbt_stream->runtime->private_data; 13428c2ecf20Sopenharmony_ci config_acp_dma(adata->acp_mmio, rtd, adata->asic_type); 13438c2ecf20Sopenharmony_ci } 13448c2ecf20Sopenharmony_ci } 13458c2ecf20Sopenharmony_ci acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB); 13468c2ecf20Sopenharmony_ci return 0; 13478c2ecf20Sopenharmony_ci} 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_cistatic int acp_pcm_runtime_suspend(struct device *dev) 13508c2ecf20Sopenharmony_ci{ 13518c2ecf20Sopenharmony_ci int status; 13528c2ecf20Sopenharmony_ci struct audio_drv_data *adata = dev_get_drvdata(dev); 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci status = acp_deinit(adata->acp_mmio); 13558c2ecf20Sopenharmony_ci if (status) 13568c2ecf20Sopenharmony_ci dev_err(dev, "ACP Deinit failed status:%d\n", status); 13578c2ecf20Sopenharmony_ci acp_reg_write(0, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB); 13588c2ecf20Sopenharmony_ci return 0; 13598c2ecf20Sopenharmony_ci} 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_cistatic int acp_pcm_runtime_resume(struct device *dev) 13628c2ecf20Sopenharmony_ci{ 13638c2ecf20Sopenharmony_ci int status; 13648c2ecf20Sopenharmony_ci struct audio_drv_data *adata = dev_get_drvdata(dev); 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci status = acp_init(adata->acp_mmio, adata->asic_type); 13678c2ecf20Sopenharmony_ci if (status) { 13688c2ecf20Sopenharmony_ci dev_err(dev, "ACP Init failed status:%d\n", status); 13698c2ecf20Sopenharmony_ci return status; 13708c2ecf20Sopenharmony_ci } 13718c2ecf20Sopenharmony_ci acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB); 13728c2ecf20Sopenharmony_ci return 0; 13738c2ecf20Sopenharmony_ci} 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_cistatic const struct dev_pm_ops acp_pm_ops = { 13768c2ecf20Sopenharmony_ci .resume = acp_pcm_resume, 13778c2ecf20Sopenharmony_ci .runtime_suspend = acp_pcm_runtime_suspend, 13788c2ecf20Sopenharmony_ci .runtime_resume = acp_pcm_runtime_resume, 13798c2ecf20Sopenharmony_ci}; 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_cistatic struct platform_driver acp_dma_driver = { 13828c2ecf20Sopenharmony_ci .probe = acp_audio_probe, 13838c2ecf20Sopenharmony_ci .remove = acp_audio_remove, 13848c2ecf20Sopenharmony_ci .driver = { 13858c2ecf20Sopenharmony_ci .name = DRV_NAME, 13868c2ecf20Sopenharmony_ci .pm = &acp_pm_ops, 13878c2ecf20Sopenharmony_ci }, 13888c2ecf20Sopenharmony_ci}; 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_cimodule_platform_driver(acp_dma_driver); 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ciMODULE_AUTHOR("Vijendar.Mukunda@amd.com"); 13938c2ecf20Sopenharmony_ciMODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com"); 13948c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("AMD ACP PCM Driver"); 13958c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 13968c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:"DRV_NAME); 1397