1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 2 // 3 // This file is provided under a dual BSD/GPLv2 license. When using or 4 // redistributing this file, you may do so under either license. 5 // 6 // Copyright(c) 2023 Advanced Micro Devices, Inc. 7 // 8 // Authors: Syed Saba Kareem <Syed.SabaKareem@amd.com> 9 // 10 11 /* 12 * Common file to be used by amd platforms 13 */ 14 15 #include "amd.h" 16 #include <linux/pci.h> 17 #include <linux/export.h> 18 19 void acp_enable_interrupts(struct acp_dev_data *adata) 20 { 21 struct acp_resource *rsrc = adata->rsrc; 22 u32 ext_intr_ctrl; 23 24 writel(0x01, ACP_EXTERNAL_INTR_ENB(adata)); 25 ext_intr_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); 26 ext_intr_ctrl |= ACP_ERROR_MASK; 27 writel(ext_intr_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); 28 } 29 EXPORT_SYMBOL_NS_GPL(acp_enable_interrupts, SND_SOC_ACP_COMMON); 30 31 void acp_disable_interrupts(struct acp_dev_data *adata) 32 { 33 struct acp_resource *rsrc = adata->rsrc; 34 35 writel(ACP_EXT_INTR_STAT_CLEAR_MASK, ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used)); 36 writel(0x00, ACP_EXTERNAL_INTR_ENB(adata)); 37 } 38 EXPORT_SYMBOL_NS_GPL(acp_disable_interrupts, SND_SOC_ACP_COMMON); 39 40 static void set_acp_pdm_ring_buffer(struct snd_pcm_substream *substream, 41 struct snd_soc_dai *dai) 42 { 43 struct snd_pcm_runtime *runtime = substream->runtime; 44 struct acp_stream *stream = runtime->private_data; 45 struct device *dev = dai->component->dev; 46 struct acp_dev_data *adata = dev_get_drvdata(dev); 47 48 u32 physical_addr, pdm_size, period_bytes; 49 50 period_bytes = frames_to_bytes(runtime, runtime->period_size); 51 pdm_size = frames_to_bytes(runtime, runtime->buffer_size); 52 physical_addr = stream->reg_offset + MEM_WINDOW_START; 53 54 /* Init ACP PDM Ring buffer */ 55 writel(physical_addr, adata->acp_base + ACP_WOV_RX_RINGBUFADDR); 56 writel(pdm_size, adata->acp_base + ACP_WOV_RX_RINGBUFSIZE); 57 writel(period_bytes, adata->acp_base + ACP_WOV_RX_INTR_WATERMARK_SIZE); 58 writel(0x01, adata->acp_base + ACPAXI2AXI_ATU_CTRL); 59 } 60 61 static void set_acp_pdm_clk(struct snd_pcm_substream *substream, 62 struct snd_soc_dai *dai) 63 { 64 struct device *dev = dai->component->dev; 65 struct acp_dev_data *adata = dev_get_drvdata(dev); 66 unsigned int pdm_ctrl; 67 68 /* Enable default ACP PDM clk */ 69 writel(PDM_CLK_FREQ_MASK, adata->acp_base + ACP_WOV_CLK_CTRL); 70 pdm_ctrl = readl(adata->acp_base + ACP_WOV_MISC_CTRL); 71 pdm_ctrl |= PDM_MISC_CTRL_MASK; 72 writel(pdm_ctrl, adata->acp_base + ACP_WOV_MISC_CTRL); 73 set_acp_pdm_ring_buffer(substream, dai); 74 } 75 76 void restore_acp_pdm_params(struct snd_pcm_substream *substream, 77 struct acp_dev_data *adata) 78 { 79 struct snd_soc_dai *dai; 80 struct snd_soc_pcm_runtime *soc_runtime; 81 u32 ext_int_ctrl; 82 83 soc_runtime = asoc_substream_to_rtd(substream); 84 dai = asoc_rtd_to_cpu(soc_runtime, 0); 85 /* Programming channel mask and sampling rate */ 86 writel(adata->ch_mask, adata->acp_base + ACP_WOV_PDM_NO_OF_CHANNELS); 87 writel(PDM_DEC_64, adata->acp_base + ACP_WOV_PDM_DECIMATION_FACTOR); 88 89 /* Enabling ACP Pdm interuppts */ 90 ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, 0)); 91 ext_int_ctrl |= PDM_DMA_INTR_MASK; 92 writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, 0)); 93 set_acp_pdm_clk(substream, dai); 94 } 95 EXPORT_SYMBOL_NS_GPL(restore_acp_pdm_params, SND_SOC_ACP_COMMON); 96 97 static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream, 98 struct snd_soc_dai *dai) 99 { 100 struct device *dev = dai->component->dev; 101 struct acp_dev_data *adata = dev_get_drvdata(dev); 102 struct acp_resource *rsrc = adata->rsrc; 103 struct acp_stream *stream = substream->runtime->private_data; 104 u32 reg_dma_size, reg_fifo_size, reg_fifo_addr; 105 u32 phy_addr, acp_fifo_addr, ext_int_ctrl; 106 unsigned int dir = substream->stream; 107 108 switch (dai->driver->id) { 109 case I2S_SP_INSTANCE: 110 if (dir == SNDRV_PCM_STREAM_PLAYBACK) { 111 reg_dma_size = ACP_I2S_TX_DMA_SIZE; 112 acp_fifo_addr = rsrc->sram_pte_offset + 113 SP_PB_FIFO_ADDR_OFFSET; 114 reg_fifo_addr = ACP_I2S_TX_FIFOADDR; 115 reg_fifo_size = ACP_I2S_TX_FIFOSIZE; 116 phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset; 117 writel(phy_addr, adata->acp_base + ACP_I2S_TX_RINGBUFADDR); 118 } else { 119 reg_dma_size = ACP_I2S_RX_DMA_SIZE; 120 acp_fifo_addr = rsrc->sram_pte_offset + 121 SP_CAPT_FIFO_ADDR_OFFSET; 122 reg_fifo_addr = ACP_I2S_RX_FIFOADDR; 123 reg_fifo_size = ACP_I2S_RX_FIFOSIZE; 124 phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset; 125 writel(phy_addr, adata->acp_base + ACP_I2S_RX_RINGBUFADDR); 126 } 127 break; 128 case I2S_BT_INSTANCE: 129 if (dir == SNDRV_PCM_STREAM_PLAYBACK) { 130 reg_dma_size = ACP_BT_TX_DMA_SIZE; 131 acp_fifo_addr = rsrc->sram_pte_offset + 132 BT_PB_FIFO_ADDR_OFFSET; 133 reg_fifo_addr = ACP_BT_TX_FIFOADDR; 134 reg_fifo_size = ACP_BT_TX_FIFOSIZE; 135 phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset; 136 writel(phy_addr, adata->acp_base + ACP_BT_TX_RINGBUFADDR); 137 } else { 138 reg_dma_size = ACP_BT_RX_DMA_SIZE; 139 acp_fifo_addr = rsrc->sram_pte_offset + 140 BT_CAPT_FIFO_ADDR_OFFSET; 141 reg_fifo_addr = ACP_BT_RX_FIFOADDR; 142 reg_fifo_size = ACP_BT_RX_FIFOSIZE; 143 phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset; 144 writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR); 145 } 146 break; 147 case I2S_HS_INSTANCE: 148 if (dir == SNDRV_PCM_STREAM_PLAYBACK) { 149 reg_dma_size = ACP_HS_TX_DMA_SIZE; 150 acp_fifo_addr = rsrc->sram_pte_offset + 151 HS_PB_FIFO_ADDR_OFFSET; 152 reg_fifo_addr = ACP_HS_TX_FIFOADDR; 153 reg_fifo_size = ACP_HS_TX_FIFOSIZE; 154 phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset; 155 writel(phy_addr, adata->acp_base + ACP_HS_TX_RINGBUFADDR); 156 } else { 157 reg_dma_size = ACP_HS_RX_DMA_SIZE; 158 acp_fifo_addr = rsrc->sram_pte_offset + 159 HS_CAPT_FIFO_ADDR_OFFSET; 160 reg_fifo_addr = ACP_HS_RX_FIFOADDR; 161 reg_fifo_size = ACP_HS_RX_FIFOSIZE; 162 phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset; 163 writel(phy_addr, adata->acp_base + ACP_HS_RX_RINGBUFADDR); 164 } 165 break; 166 default: 167 dev_err(dev, "Invalid dai id %x\n", dai->driver->id); 168 return -EINVAL; 169 } 170 171 writel(DMA_SIZE, adata->acp_base + reg_dma_size); 172 writel(acp_fifo_addr, adata->acp_base + reg_fifo_addr); 173 writel(FIFO_SIZE, adata->acp_base + reg_fifo_size); 174 175 ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); 176 ext_int_ctrl |= BIT(I2S_RX_THRESHOLD(rsrc->offset)) | 177 BIT(BT_RX_THRESHOLD(rsrc->offset)) | 178 BIT(I2S_TX_THRESHOLD(rsrc->offset)) | 179 BIT(BT_TX_THRESHOLD(rsrc->offset)) | 180 BIT(HS_RX_THRESHOLD(rsrc->offset)) | 181 BIT(HS_TX_THRESHOLD(rsrc->offset)); 182 183 writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); 184 return 0; 185 } 186 187 int restore_acp_i2s_params(struct snd_pcm_substream *substream, 188 struct acp_dev_data *adata, 189 struct acp_stream *stream) 190 { 191 struct snd_soc_dai *dai; 192 struct snd_soc_pcm_runtime *soc_runtime; 193 u32 tdm_fmt, reg_val, fmt_reg, val; 194 195 soc_runtime = asoc_substream_to_rtd(substream); 196 dai = asoc_rtd_to_cpu(soc_runtime, 0); 197 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 198 tdm_fmt = adata->tdm_tx_fmt[stream->dai_id - 1]; 199 switch (stream->dai_id) { 200 case I2S_BT_INSTANCE: 201 reg_val = ACP_BTTDM_ITER; 202 fmt_reg = ACP_BTTDM_TXFRMT; 203 break; 204 case I2S_SP_INSTANCE: 205 reg_val = ACP_I2STDM_ITER; 206 fmt_reg = ACP_I2STDM_TXFRMT; 207 break; 208 case I2S_HS_INSTANCE: 209 reg_val = ACP_HSTDM_ITER; 210 fmt_reg = ACP_HSTDM_TXFRMT; 211 break; 212 default: 213 pr_err("Invalid dai id %x\n", stream->dai_id); 214 return -EINVAL; 215 } 216 val = adata->xfer_tx_resolution[stream->dai_id - 1] << 3; 217 } else { 218 tdm_fmt = adata->tdm_rx_fmt[stream->dai_id - 1]; 219 switch (stream->dai_id) { 220 case I2S_BT_INSTANCE: 221 reg_val = ACP_BTTDM_IRER; 222 fmt_reg = ACP_BTTDM_RXFRMT; 223 break; 224 case I2S_SP_INSTANCE: 225 reg_val = ACP_I2STDM_IRER; 226 fmt_reg = ACP_I2STDM_RXFRMT; 227 break; 228 case I2S_HS_INSTANCE: 229 reg_val = ACP_HSTDM_IRER; 230 fmt_reg = ACP_HSTDM_RXFRMT; 231 break; 232 default: 233 pr_err("Invalid dai id %x\n", stream->dai_id); 234 return -EINVAL; 235 } 236 val = adata->xfer_rx_resolution[stream->dai_id - 1] << 3; 237 } 238 writel(val, adata->acp_base + reg_val); 239 if (adata->tdm_mode == TDM_ENABLE) { 240 writel(tdm_fmt, adata->acp_base + fmt_reg); 241 val = readl(adata->acp_base + reg_val); 242 writel(val | 0x2, adata->acp_base + reg_val); 243 } 244 return set_acp_i2s_dma_fifo(substream, dai); 245 } 246 EXPORT_SYMBOL_NS_GPL(restore_acp_i2s_params, SND_SOC_ACP_COMMON); 247 248 static int acp_power_on(struct acp_chip_info *chip) 249 { 250 u32 val, acp_pgfsm_stat_reg, acp_pgfsm_ctrl_reg; 251 void __iomem *base; 252 253 base = chip->base; 254 switch (chip->acp_rev) { 255 case ACP3X_DEV: 256 acp_pgfsm_stat_reg = ACP_PGFSM_STATUS; 257 acp_pgfsm_ctrl_reg = ACP_PGFSM_CONTROL; 258 break; 259 case ACP6X_DEV: 260 acp_pgfsm_stat_reg = ACP6X_PGFSM_STATUS; 261 acp_pgfsm_ctrl_reg = ACP6X_PGFSM_CONTROL; 262 break; 263 default: 264 return -EINVAL; 265 } 266 267 val = readl(base + acp_pgfsm_stat_reg); 268 if (val == ACP_POWERED_ON) 269 return 0; 270 271 if ((val & ACP_PGFSM_STATUS_MASK) != ACP_POWER_ON_IN_PROGRESS) 272 writel(ACP_PGFSM_CNTL_POWER_ON_MASK, base + acp_pgfsm_ctrl_reg); 273 274 return readl_poll_timeout(base + acp_pgfsm_stat_reg, val, 275 !val, DELAY_US, ACP_TIMEOUT); 276 } 277 278 static int acp_reset(void __iomem *base) 279 { 280 u32 val; 281 int ret; 282 283 writel(1, base + ACP_SOFT_RESET); 284 ret = readl_poll_timeout(base + ACP_SOFT_RESET, val, val & ACP_SOFT_RST_DONE_MASK, 285 DELAY_US, ACP_TIMEOUT); 286 if (ret) 287 return ret; 288 289 writel(0, base + ACP_SOFT_RESET); 290 return readl_poll_timeout(base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP_TIMEOUT); 291 } 292 293 int acp_init(struct acp_chip_info *chip) 294 { 295 int ret; 296 297 /* power on */ 298 ret = acp_power_on(chip); 299 if (ret) { 300 pr_err("ACP power on failed\n"); 301 return ret; 302 } 303 writel(0x01, chip->base + ACP_CONTROL); 304 305 /* Reset */ 306 ret = acp_reset(chip->base); 307 if (ret) { 308 pr_err("ACP reset failed\n"); 309 return ret; 310 } 311 return 0; 312 } 313 EXPORT_SYMBOL_NS_GPL(acp_init, SND_SOC_ACP_COMMON); 314 315 int acp_deinit(void __iomem *base) 316 { 317 int ret; 318 319 /* Reset */ 320 ret = acp_reset(base); 321 if (ret) 322 return ret; 323 324 writel(0, base + ACP_CONTROL); 325 return 0; 326 } 327 EXPORT_SYMBOL_NS_GPL(acp_deinit, SND_SOC_ACP_COMMON); 328 329 int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data) 330 { 331 pci_write_config_dword(dev, 0x60, smn_addr); 332 pci_write_config_dword(dev, 0x64, data); 333 return 0; 334 } 335 EXPORT_SYMBOL_NS_GPL(smn_write, SND_SOC_ACP_COMMON); 336 337 int smn_read(struct pci_dev *dev, u32 smn_addr) 338 { 339 u32 data; 340 341 pci_write_config_dword(dev, 0x60, smn_addr); 342 pci_read_config_dword(dev, 0x64, &data); 343 return data; 344 } 345 EXPORT_SYMBOL_NS_GPL(smn_read, SND_SOC_ACP_COMMON); 346 347 MODULE_LICENSE("Dual BSD/GPL"); 348