1e8a33a94SV sujith kumar Reddy // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2e8a33a94SV sujith kumar Reddy //
3e8a33a94SV sujith kumar Reddy // This file is provided under a dual BSD/GPLv2 license. When using or
4e8a33a94SV sujith kumar Reddy // redistributing this file, you may do so under either license.
5e8a33a94SV sujith kumar Reddy //
6e8a33a94SV sujith kumar Reddy // Copyright(c) 2022 Advanced Micro Devices, Inc.
7e8a33a94SV sujith kumar Reddy //
8e8a33a94SV sujith kumar Reddy // Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
9e8a33a94SV sujith kumar Reddy // V sujith kumar Reddy <Vsujithkumar.Reddy@amd.com>
10e8a33a94SV sujith kumar Reddy /*
11e8a33a94SV sujith kumar Reddy * Hardware interface for Renoir ACP block
12e8a33a94SV sujith kumar Reddy */
13e8a33a94SV sujith kumar Reddy
14e8a33a94SV sujith kumar Reddy #include <linux/platform_device.h>
15e8a33a94SV sujith kumar Reddy #include <linux/module.h>
16e8a33a94SV sujith kumar Reddy #include <linux/err.h>
17e8a33a94SV sujith kumar Reddy #include <linux/io.h>
18e8a33a94SV sujith kumar Reddy #include <sound/pcm_params.h>
19e8a33a94SV sujith kumar Reddy #include <sound/soc.h>
20e8a33a94SV sujith kumar Reddy #include <sound/soc-dai.h>
21e8a33a94SV sujith kumar Reddy #include <linux/dma-mapping.h>
227ad6fb9dSSyed Saba Kareem #include <linux/pci.h>
23*5debf4aeSSyed Saba Kareem #include <linux/pm_runtime.h>
24e8a33a94SV sujith kumar Reddy
25e8a33a94SV sujith kumar Reddy #include "amd.h"
26e8a33a94SV sujith kumar Reddy
27e8a33a94SV sujith kumar Reddy #define DRV_NAME "acp_asoc_rembrandt"
28e8a33a94SV sujith kumar Reddy
297ad6fb9dSSyed Saba Kareem #define MP1_C2PMSG_69 0x3B10A14
307ad6fb9dSSyed Saba Kareem #define MP1_C2PMSG_85 0x3B10A54
317ad6fb9dSSyed Saba Kareem #define MP1_C2PMSG_93 0x3B10A74
327ad6fb9dSSyed Saba Kareem #define HOST_BRIDGE_ID 0x14B5
337ad6fb9dSSyed Saba Kareem
34e8a33a94SV sujith kumar Reddy static struct acp_resource rsrc = {
35e8a33a94SV sujith kumar Reddy .offset = 0,
36e8a33a94SV sujith kumar Reddy .no_of_ctrls = 2,
37e8a33a94SV sujith kumar Reddy .irqp_used = 1,
38e8a33a94SV sujith kumar Reddy .soc_mclk = true,
39e8a33a94SV sujith kumar Reddy .irq_reg_offset = 0x1a00,
40e8a33a94SV sujith kumar Reddy .i2s_pin_cfg_offset = 0x1440,
41e8a33a94SV sujith kumar Reddy .i2s_mode = 0x0a,
42e8a33a94SV sujith kumar Reddy .scratch_reg_offset = 0x12800,
43e8a33a94SV sujith kumar Reddy .sram_pte_offset = 0x03802800,
44e8a33a94SV sujith kumar Reddy };
45e8a33a94SV sujith kumar Reddy
46e8a33a94SV sujith kumar Reddy static struct snd_soc_acpi_codecs amp_rt1019 = {
47e8a33a94SV sujith kumar Reddy .num_codecs = 1,
48e8a33a94SV sujith kumar Reddy .codecs = {"10EC1019"}
49e8a33a94SV sujith kumar Reddy };
50e8a33a94SV sujith kumar Reddy
51e8a33a94SV sujith kumar Reddy static struct snd_soc_acpi_codecs amp_max = {
52e8a33a94SV sujith kumar Reddy .num_codecs = 1,
53e8a33a94SV sujith kumar Reddy .codecs = {"MX98360A"}
54e8a33a94SV sujith kumar Reddy };
55e8a33a94SV sujith kumar Reddy
56e8a33a94SV sujith kumar Reddy static struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_acp_machines[] = {
57e8a33a94SV sujith kumar Reddy {
58e8a33a94SV sujith kumar Reddy .id = "10508825",
59e8a33a94SV sujith kumar Reddy .drv_name = "rmb-nau8825-max",
60e8a33a94SV sujith kumar Reddy .machine_quirk = snd_soc_acpi_codec_list,
61e8a33a94SV sujith kumar Reddy .quirk_data = &_max,
62e8a33a94SV sujith kumar Reddy },
63e8a33a94SV sujith kumar Reddy {
64e8a33a94SV sujith kumar Reddy .id = "AMDI0007",
65e8a33a94SV sujith kumar Reddy .drv_name = "rembrandt-acp",
66e8a33a94SV sujith kumar Reddy },
67e8a33a94SV sujith kumar Reddy {
68e8a33a94SV sujith kumar Reddy .id = "RTL5682",
69e8a33a94SV sujith kumar Reddy .drv_name = "rmb-rt5682s-rt1019",
70e8a33a94SV sujith kumar Reddy .machine_quirk = snd_soc_acpi_codec_list,
71e8a33a94SV sujith kumar Reddy .quirk_data = &_rt1019,
72e8a33a94SV sujith kumar Reddy },
73e8a33a94SV sujith kumar Reddy {},
74e8a33a94SV sujith kumar Reddy };
75e8a33a94SV sujith kumar Reddy
76e8a33a94SV sujith kumar Reddy static struct snd_soc_dai_driver acp_rmb_dai[] = {
77e8a33a94SV sujith kumar Reddy {
78e8a33a94SV sujith kumar Reddy .name = "acp-i2s-sp",
79e8a33a94SV sujith kumar Reddy .id = I2S_SP_INSTANCE,
80e8a33a94SV sujith kumar Reddy .playback = {
81e8a33a94SV sujith kumar Reddy .stream_name = "I2S SP Playback",
82e8a33a94SV sujith kumar Reddy .rates = SNDRV_PCM_RATE_8000_96000,
83e8a33a94SV sujith kumar Reddy .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
84e8a33a94SV sujith kumar Reddy SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
85e8a33a94SV sujith kumar Reddy .channels_min = 2,
86e8a33a94SV sujith kumar Reddy .channels_max = 8,
87e8a33a94SV sujith kumar Reddy .rate_min = 8000,
88e8a33a94SV sujith kumar Reddy .rate_max = 96000,
89e8a33a94SV sujith kumar Reddy },
90e8a33a94SV sujith kumar Reddy .capture = {
91e8a33a94SV sujith kumar Reddy .stream_name = "I2S SP Capture",
92e8a33a94SV sujith kumar Reddy .rates = SNDRV_PCM_RATE_8000_48000,
93e8a33a94SV sujith kumar Reddy .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
94e8a33a94SV sujith kumar Reddy SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
95e8a33a94SV sujith kumar Reddy .channels_min = 2,
96e8a33a94SV sujith kumar Reddy .channels_max = 2,
97e8a33a94SV sujith kumar Reddy .rate_min = 8000,
98e8a33a94SV sujith kumar Reddy .rate_max = 48000,
99e8a33a94SV sujith kumar Reddy },
100e8a33a94SV sujith kumar Reddy .ops = &asoc_acp_cpu_dai_ops,
101e8a33a94SV sujith kumar Reddy },
102e8a33a94SV sujith kumar Reddy {
103e8a33a94SV sujith kumar Reddy .name = "acp-i2s-bt",
104e8a33a94SV sujith kumar Reddy .id = I2S_BT_INSTANCE,
105e8a33a94SV sujith kumar Reddy .playback = {
106e8a33a94SV sujith kumar Reddy .stream_name = "I2S BT Playback",
107e8a33a94SV sujith kumar Reddy .rates = SNDRV_PCM_RATE_8000_96000,
108e8a33a94SV sujith kumar Reddy .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
109e8a33a94SV sujith kumar Reddy SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
110e8a33a94SV sujith kumar Reddy .channels_min = 2,
111e8a33a94SV sujith kumar Reddy .channels_max = 8,
112e8a33a94SV sujith kumar Reddy .rate_min = 8000,
113e8a33a94SV sujith kumar Reddy .rate_max = 96000,
114e8a33a94SV sujith kumar Reddy },
115e8a33a94SV sujith kumar Reddy .capture = {
116e8a33a94SV sujith kumar Reddy .stream_name = "I2S BT Capture",
117e8a33a94SV sujith kumar Reddy .rates = SNDRV_PCM_RATE_8000_48000,
118e8a33a94SV sujith kumar Reddy .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
119e8a33a94SV sujith kumar Reddy SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
120e8a33a94SV sujith kumar Reddy .channels_min = 2,
121e8a33a94SV sujith kumar Reddy .channels_max = 2,
122e8a33a94SV sujith kumar Reddy .rate_min = 8000,
123e8a33a94SV sujith kumar Reddy .rate_max = 48000,
124e8a33a94SV sujith kumar Reddy },
125e8a33a94SV sujith kumar Reddy .ops = &asoc_acp_cpu_dai_ops,
126e8a33a94SV sujith kumar Reddy },
127e8a33a94SV sujith kumar Reddy {
128e8a33a94SV sujith kumar Reddy .name = "acp-i2s-hs",
129e8a33a94SV sujith kumar Reddy .id = I2S_HS_INSTANCE,
130e8a33a94SV sujith kumar Reddy .playback = {
131e8a33a94SV sujith kumar Reddy .stream_name = "I2S HS Playback",
132e8a33a94SV sujith kumar Reddy .rates = SNDRV_PCM_RATE_8000_96000,
133e8a33a94SV sujith kumar Reddy .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
134e8a33a94SV sujith kumar Reddy SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
135e8a33a94SV sujith kumar Reddy .channels_min = 2,
136e8a33a94SV sujith kumar Reddy .channels_max = 8,
137e8a33a94SV sujith kumar Reddy .rate_min = 8000,
138e8a33a94SV sujith kumar Reddy .rate_max = 96000,
139e8a33a94SV sujith kumar Reddy },
140e8a33a94SV sujith kumar Reddy .capture = {
141e8a33a94SV sujith kumar Reddy .stream_name = "I2S HS Capture",
142e8a33a94SV sujith kumar Reddy .rates = SNDRV_PCM_RATE_8000_48000,
143e8a33a94SV sujith kumar Reddy .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
144e8a33a94SV sujith kumar Reddy SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
145e8a33a94SV sujith kumar Reddy .channels_min = 2,
146e8a33a94SV sujith kumar Reddy .channels_max = 8,
147e8a33a94SV sujith kumar Reddy .rate_min = 8000,
148e8a33a94SV sujith kumar Reddy .rate_max = 48000,
149e8a33a94SV sujith kumar Reddy },
150e8a33a94SV sujith kumar Reddy .ops = &asoc_acp_cpu_dai_ops,
151e8a33a94SV sujith kumar Reddy },
152e8a33a94SV sujith kumar Reddy {
153e8a33a94SV sujith kumar Reddy .name = "acp-pdm-dmic",
154e8a33a94SV sujith kumar Reddy .id = DMIC_INSTANCE,
155e8a33a94SV sujith kumar Reddy .capture = {
156e8a33a94SV sujith kumar Reddy .rates = SNDRV_PCM_RATE_8000_48000,
157e8a33a94SV sujith kumar Reddy .formats = SNDRV_PCM_FMTBIT_S32_LE,
158e8a33a94SV sujith kumar Reddy .channels_min = 2,
159e8a33a94SV sujith kumar Reddy .channels_max = 2,
160e8a33a94SV sujith kumar Reddy .rate_min = 8000,
161e8a33a94SV sujith kumar Reddy .rate_max = 48000,
162e8a33a94SV sujith kumar Reddy },
163e8a33a94SV sujith kumar Reddy .ops = &acp_dmic_dai_ops,
164e8a33a94SV sujith kumar Reddy },
165e8a33a94SV sujith kumar Reddy };
166e8a33a94SV sujith kumar Reddy
acp6x_master_clock_generate(struct device * dev)1677ad6fb9dSSyed Saba Kareem static int acp6x_master_clock_generate(struct device *dev)
1687ad6fb9dSSyed Saba Kareem {
1697ad6fb9dSSyed Saba Kareem int data = 0;
1707ad6fb9dSSyed Saba Kareem struct pci_dev *smn_dev;
1717ad6fb9dSSyed Saba Kareem
1727ad6fb9dSSyed Saba Kareem smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, HOST_BRIDGE_ID, NULL);
1737ad6fb9dSSyed Saba Kareem if (!smn_dev) {
1747ad6fb9dSSyed Saba Kareem dev_err(dev, "Failed to get host bridge device\n");
1757ad6fb9dSSyed Saba Kareem return -ENODEV;
1767ad6fb9dSSyed Saba Kareem }
1777ad6fb9dSSyed Saba Kareem
1787ad6fb9dSSyed Saba Kareem smn_write(smn_dev, MP1_C2PMSG_93, 0);
1797ad6fb9dSSyed Saba Kareem smn_write(smn_dev, MP1_C2PMSG_85, 0xC4);
1807ad6fb9dSSyed Saba Kareem smn_write(smn_dev, MP1_C2PMSG_69, 0x4);
1817ad6fb9dSSyed Saba Kareem read_poll_timeout(smn_read, data, data, DELAY_US,
1827ad6fb9dSSyed Saba Kareem ACP_TIMEOUT, false, smn_dev, MP1_C2PMSG_93);
1837ad6fb9dSSyed Saba Kareem return 0;
1847ad6fb9dSSyed Saba Kareem }
1857ad6fb9dSSyed Saba Kareem
rembrandt_audio_probe(struct platform_device * pdev)186e8a33a94SV sujith kumar Reddy static int rembrandt_audio_probe(struct platform_device *pdev)
187e8a33a94SV sujith kumar Reddy {
188e8a33a94SV sujith kumar Reddy struct device *dev = &pdev->dev;
189e8a33a94SV sujith kumar Reddy struct acp_chip_info *chip;
190e8a33a94SV sujith kumar Reddy struct acp_dev_data *adata;
191e8a33a94SV sujith kumar Reddy struct resource *res;
192e8a33a94SV sujith kumar Reddy
193e8a33a94SV sujith kumar Reddy chip = dev_get_platdata(&pdev->dev);
194e8a33a94SV sujith kumar Reddy if (!chip || !chip->base) {
195e8a33a94SV sujith kumar Reddy dev_err(&pdev->dev, "ACP chip data is NULL\n");
196e8a33a94SV sujith kumar Reddy return -ENODEV;
197e8a33a94SV sujith kumar Reddy }
198e8a33a94SV sujith kumar Reddy
199e8a33a94SV sujith kumar Reddy if (chip->acp_rev != ACP6X_DEV) {
200e8a33a94SV sujith kumar Reddy dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev);
201e8a33a94SV sujith kumar Reddy return -ENODEV;
202e8a33a94SV sujith kumar Reddy }
203e8a33a94SV sujith kumar Reddy
204e8a33a94SV sujith kumar Reddy adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL);
205e8a33a94SV sujith kumar Reddy if (!adata)
206e8a33a94SV sujith kumar Reddy return -ENOMEM;
207e8a33a94SV sujith kumar Reddy
208e8a33a94SV sujith kumar Reddy res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acp_mem");
209e8a33a94SV sujith kumar Reddy if (!res) {
210e8a33a94SV sujith kumar Reddy dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n");
211e8a33a94SV sujith kumar Reddy return -ENODEV;
212e8a33a94SV sujith kumar Reddy }
213e8a33a94SV sujith kumar Reddy
214e8a33a94SV sujith kumar Reddy adata->acp_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
215e8a33a94SV sujith kumar Reddy if (!adata->acp_base)
216e8a33a94SV sujith kumar Reddy return -ENOMEM;
217e8a33a94SV sujith kumar Reddy
218e8a33a94SV sujith kumar Reddy res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "acp_dai_irq");
219e8a33a94SV sujith kumar Reddy if (!res) {
220e8a33a94SV sujith kumar Reddy dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
221e8a33a94SV sujith kumar Reddy return -ENODEV;
222e8a33a94SV sujith kumar Reddy }
223e8a33a94SV sujith kumar Reddy
224e8a33a94SV sujith kumar Reddy adata->i2s_irq = res->start;
225e8a33a94SV sujith kumar Reddy adata->dev = dev;
226e8a33a94SV sujith kumar Reddy adata->dai_driver = acp_rmb_dai;
227e8a33a94SV sujith kumar Reddy adata->num_dai = ARRAY_SIZE(acp_rmb_dai);
228e8a33a94SV sujith kumar Reddy adata->rsrc = &rsrc;
229e8a33a94SV sujith kumar Reddy
230e8a33a94SV sujith kumar Reddy adata->machines = snd_soc_acpi_amd_rmb_acp_machines;
231e8a33a94SV sujith kumar Reddy acp_machine_select(adata);
232e8a33a94SV sujith kumar Reddy
233e8a33a94SV sujith kumar Reddy dev_set_drvdata(dev, adata);
2347ad6fb9dSSyed Saba Kareem acp6x_master_clock_generate(dev);
235fc11d326SSyed Saba Kareem acp_enable_interrupts(adata);
236e8a33a94SV sujith kumar Reddy acp_platform_register(dev);
237*5debf4aeSSyed Saba Kareem pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS);
238*5debf4aeSSyed Saba Kareem pm_runtime_use_autosuspend(&pdev->dev);
239*5debf4aeSSyed Saba Kareem pm_runtime_mark_last_busy(&pdev->dev);
240*5debf4aeSSyed Saba Kareem pm_runtime_set_active(&pdev->dev);
241*5debf4aeSSyed Saba Kareem pm_runtime_enable(&pdev->dev);
242e8a33a94SV sujith kumar Reddy return 0;
243e8a33a94SV sujith kumar Reddy }
244e8a33a94SV sujith kumar Reddy
rembrandt_audio_remove(struct platform_device * pdev)24537846af6SUwe Kleine-König static void rembrandt_audio_remove(struct platform_device *pdev)
246e8a33a94SV sujith kumar Reddy {
247e8a33a94SV sujith kumar Reddy struct device *dev = &pdev->dev;
248e8a33a94SV sujith kumar Reddy struct acp_dev_data *adata = dev_get_drvdata(dev);
249e8a33a94SV sujith kumar Reddy
250fc11d326SSyed Saba Kareem acp_disable_interrupts(adata);
251e8a33a94SV sujith kumar Reddy acp_platform_unregister(dev);
252*5debf4aeSSyed Saba Kareem pm_runtime_disable(&pdev->dev);
253e8a33a94SV sujith kumar Reddy }
254e8a33a94SV sujith kumar Reddy
rmb_pcm_resume(struct device * dev)255*5debf4aeSSyed Saba Kareem static int __maybe_unused rmb_pcm_resume(struct device *dev)
256*5debf4aeSSyed Saba Kareem {
257*5debf4aeSSyed Saba Kareem struct acp_dev_data *adata = dev_get_drvdata(dev);
258*5debf4aeSSyed Saba Kareem struct acp_stream *stream;
259*5debf4aeSSyed Saba Kareem struct snd_pcm_substream *substream;
260*5debf4aeSSyed Saba Kareem snd_pcm_uframes_t buf_in_frames;
261*5debf4aeSSyed Saba Kareem u64 buf_size;
262*5debf4aeSSyed Saba Kareem
263*5debf4aeSSyed Saba Kareem acp6x_master_clock_generate(dev);
264*5debf4aeSSyed Saba Kareem spin_lock(&adata->acp_lock);
265*5debf4aeSSyed Saba Kareem list_for_each_entry(stream, &adata->stream_list, list) {
266*5debf4aeSSyed Saba Kareem substream = stream->substream;
267*5debf4aeSSyed Saba Kareem if (substream && substream->runtime) {
268*5debf4aeSSyed Saba Kareem buf_in_frames = (substream->runtime->buffer_size);
269*5debf4aeSSyed Saba Kareem buf_size = frames_to_bytes(substream->runtime, buf_in_frames);
270*5debf4aeSSyed Saba Kareem config_pte_for_stream(adata, stream);
271*5debf4aeSSyed Saba Kareem config_acp_dma(adata, stream, buf_size);
272*5debf4aeSSyed Saba Kareem if (stream->dai_id)
273*5debf4aeSSyed Saba Kareem restore_acp_i2s_params(substream, adata, stream);
274*5debf4aeSSyed Saba Kareem else
275*5debf4aeSSyed Saba Kareem restore_acp_pdm_params(substream, adata);
276*5debf4aeSSyed Saba Kareem }
277*5debf4aeSSyed Saba Kareem }
278*5debf4aeSSyed Saba Kareem spin_unlock(&adata->acp_lock);
279*5debf4aeSSyed Saba Kareem return 0;
280*5debf4aeSSyed Saba Kareem }
281*5debf4aeSSyed Saba Kareem
282*5debf4aeSSyed Saba Kareem static const struct dev_pm_ops rmb_dma_pm_ops = {
283*5debf4aeSSyed Saba Kareem SET_SYSTEM_SLEEP_PM_OPS(NULL, rmb_pcm_resume)
284*5debf4aeSSyed Saba Kareem };
285*5debf4aeSSyed Saba Kareem
286e8a33a94SV sujith kumar Reddy static struct platform_driver rembrandt_driver = {
287e8a33a94SV sujith kumar Reddy .probe = rembrandt_audio_probe,
28837846af6SUwe Kleine-König .remove_new = rembrandt_audio_remove,
289e8a33a94SV sujith kumar Reddy .driver = {
290e8a33a94SV sujith kumar Reddy .name = "acp_asoc_rembrandt",
291*5debf4aeSSyed Saba Kareem .pm = &rmb_dma_pm_ops,
292e8a33a94SV sujith kumar Reddy },
293e8a33a94SV sujith kumar Reddy };
294e8a33a94SV sujith kumar Reddy
295e8a33a94SV sujith kumar Reddy module_platform_driver(rembrandt_driver);
296e8a33a94SV sujith kumar Reddy
297e8a33a94SV sujith kumar Reddy MODULE_DESCRIPTION("AMD ACP Rembrandt Driver");
298e8a33a94SV sujith kumar Reddy MODULE_IMPORT_NS(SND_SOC_ACP_COMMON);
299e8a33a94SV sujith kumar Reddy MODULE_LICENSE("Dual BSD/GPL");
300e8a33a94SV sujith kumar Reddy MODULE_ALIAS("platform:" DRV_NAME);
301