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
19void 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}
29EXPORT_SYMBOL_NS_GPL(acp_enable_interrupts, SND_SOC_ACP_COMMON);
30
31void 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}
38EXPORT_SYMBOL_NS_GPL(acp_disable_interrupts, SND_SOC_ACP_COMMON);
39
40static 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
61static 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
76void 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}
95EXPORT_SYMBOL_NS_GPL(restore_acp_pdm_params, SND_SOC_ACP_COMMON);
96
97static 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
187int 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}
246EXPORT_SYMBOL_NS_GPL(restore_acp_i2s_params, SND_SOC_ACP_COMMON);
247
248static 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
278static 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
293int 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}
313EXPORT_SYMBOL_NS_GPL(acp_init, SND_SOC_ACP_COMMON);
314
315int 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}
327EXPORT_SYMBOL_NS_GPL(acp_deinit, SND_SOC_ACP_COMMON);
328
329int 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}
335EXPORT_SYMBOL_NS_GPL(smn_write, SND_SOC_ACP_COMMON);
336
337int 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}
345EXPORT_SYMBOL_NS_GPL(smn_read, SND_SOC_ACP_COMMON);
346
347MODULE_LICENSE("Dual BSD/GPL");
348