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