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
acp_enable_interrupts(struct acp_dev_data * adata)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
acp_disable_interrupts(struct acp_dev_data * adata)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
set_acp_pdm_ring_buffer(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)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
set_acp_pdm_clk(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)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
restore_acp_pdm_params(struct snd_pcm_substream * substream,struct acp_dev_data * adata)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
set_acp_i2s_dma_fifo(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)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
restore_acp_i2s_params(struct snd_pcm_substream * substream,struct acp_dev_data * adata,struct acp_stream * stream)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
acp_power_on(struct acp_chip_info * chip)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
acp_reset(void __iomem * base)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
acp_init(struct acp_chip_info * chip)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
acp_deinit(void __iomem * base)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
smn_write(struct pci_dev * dev,u32 smn_addr,u32 data)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
smn_read(struct pci_dev * dev,u32 smn_addr)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