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