Skip to content

Commit 33d120a

Browse files
saba-kareembroonie
authored andcommitted
ASoC: amd: acp: Add acp6.3 pci legacy driver support
Add pci legacy driver support and create platform driver for acp6.3 based platforms. Signed-off-by: Syed Saba Kareem <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent f5c7bc7 commit 33d120a

File tree

4 files changed

+326
-0
lines changed

4 files changed

+326
-0
lines changed

sound/soc/amd/acp/acp-legacy-common.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,10 @@ static int acp_power_on(struct acp_chip_info *chip)
260260
acp_pgfsm_stat_reg = ACP6X_PGFSM_STATUS;
261261
acp_pgfsm_ctrl_reg = ACP6X_PGFSM_CONTROL;
262262
break;
263+
case ACP63_DEV:
264+
acp_pgfsm_stat_reg = ACP63_PGFSM_STATUS;
265+
acp_pgfsm_ctrl_reg = ACP63_PGFSM_CONTROL;
266+
break;
263267
default:
264268
return -EINVAL;
265269
}

sound/soc/amd/acp/acp-pci.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id
8787
chip->name = "acp_asoc_rembrandt";
8888
chip->acp_rev = ACP6X_DEV;
8989
break;
90+
case 0x63:
91+
chip->name = "acp_asoc_acp63";
92+
chip->acp_rev = ACP63_DEV;
93+
break;
9094
default:
9195
dev_err(dev, "Unsupported device revision:0x%x\n", pci->revision);
9296
ret = -EINVAL;

sound/soc/amd/acp/acp63.c

Lines changed: 314 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
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 <[email protected]>
9+
/*
10+
* Hardware interface for ACP6.3 block
11+
*/
12+
13+
#include <linux/platform_device.h>
14+
#include <linux/module.h>
15+
#include <linux/err.h>
16+
#include <linux/io.h>
17+
#include <sound/pcm_params.h>
18+
#include <sound/soc.h>
19+
#include <sound/soc-dai.h>
20+
#include <linux/dma-mapping.h>
21+
#include <linux/pm_runtime.h>
22+
#include <linux/pci.h>
23+
#include "amd.h"
24+
25+
#define DRV_NAME "acp_asoc_acp63"
26+
27+
#define CLK_PLL_PWR_REQ_N0 0X0006C2C0
28+
#define CLK_SPLL_FIELD_2_N0 0X0006C114
29+
#define CLK_PLL_REQ_N0 0X0006C0DC
30+
#define CLK_DFSBYPASS_CONTR 0X0006C2C8
31+
#define CLK_DFS_CNTL_N0 0X0006C1A4
32+
33+
#define PLL_AUTO_STOP_REQ BIT(4)
34+
#define PLL_AUTO_START_REQ BIT(0)
35+
#define PLL_FRANCE_EN BIT(4)
36+
#define EXIT_DPF_BYPASS_0 BIT(16)
37+
#define EXIT_DPF_BYPASS_1 BIT(17)
38+
#define CLK0_DIVIDER 0X30
39+
40+
union clk_pll_req_no {
41+
struct {
42+
u32 fb_mult_int : 9;
43+
u32 reserved : 3;
44+
u32 pll_spine_div : 4;
45+
u32 gb_mult_frac : 16;
46+
} bitfields, bits;
47+
u32 clk_pll_req_no_reg;
48+
};
49+
50+
static struct acp_resource rsrc = {
51+
.offset = 0,
52+
.no_of_ctrls = 2,
53+
.irqp_used = 1,
54+
.soc_mclk = true,
55+
.irq_reg_offset = 0x1a00,
56+
.i2s_pin_cfg_offset = 0x1440,
57+
.i2s_mode = 0x0a,
58+
.scratch_reg_offset = 0x12800,
59+
.sram_pte_offset = 0x03802800,
60+
};
61+
62+
static struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_acp_machines[] = {
63+
{
64+
.id = "AMDI0052",
65+
.drv_name = "acp63-acp",
66+
},
67+
{},
68+
};
69+
70+
static struct snd_soc_dai_driver acp63_dai[] = {
71+
{
72+
.name = "acp-i2s-sp",
73+
.id = I2S_SP_INSTANCE,
74+
.playback = {
75+
.stream_name = "I2S SP Playback",
76+
.rates = SNDRV_PCM_RATE_8000_96000,
77+
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
78+
SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
79+
.channels_min = 2,
80+
.channels_max = 8,
81+
.rate_min = 8000,
82+
.rate_max = 96000,
83+
},
84+
.capture = {
85+
.stream_name = "I2S SP Capture",
86+
.rates = SNDRV_PCM_RATE_8000_48000,
87+
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
88+
SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
89+
.channels_min = 2,
90+
.channels_max = 2,
91+
.rate_min = 8000,
92+
.rate_max = 48000,
93+
},
94+
.ops = &asoc_acp_cpu_dai_ops,
95+
},
96+
{
97+
.name = "acp-i2s-bt",
98+
.id = I2S_BT_INSTANCE,
99+
.playback = {
100+
.stream_name = "I2S BT Playback",
101+
.rates = SNDRV_PCM_RATE_8000_96000,
102+
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
103+
SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
104+
.channels_min = 2,
105+
.channels_max = 8,
106+
.rate_min = 8000,
107+
.rate_max = 96000,
108+
},
109+
.capture = {
110+
.stream_name = "I2S BT Capture",
111+
.rates = SNDRV_PCM_RATE_8000_48000,
112+
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
113+
SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
114+
.channels_min = 2,
115+
.channels_max = 2,
116+
.rate_min = 8000,
117+
.rate_max = 48000,
118+
},
119+
.ops = &asoc_acp_cpu_dai_ops,
120+
},
121+
{
122+
.name = "acp-i2s-hs",
123+
.id = I2S_HS_INSTANCE,
124+
.playback = {
125+
.stream_name = "I2S HS Playback",
126+
.rates = SNDRV_PCM_RATE_8000_96000,
127+
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
128+
SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
129+
.channels_min = 2,
130+
.channels_max = 8,
131+
.rate_min = 8000,
132+
.rate_max = 96000,
133+
},
134+
.capture = {
135+
.stream_name = "I2S HS Capture",
136+
.rates = SNDRV_PCM_RATE_8000_48000,
137+
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
138+
SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
139+
.channels_min = 2,
140+
.channels_max = 8,
141+
.rate_min = 8000,
142+
.rate_max = 48000,
143+
},
144+
.ops = &asoc_acp_cpu_dai_ops,
145+
},
146+
{
147+
.name = "acp-pdm-dmic",
148+
.id = DMIC_INSTANCE,
149+
.capture = {
150+
.rates = SNDRV_PCM_RATE_8000_48000,
151+
.formats = SNDRV_PCM_FMTBIT_S32_LE,
152+
.channels_min = 2,
153+
.channels_max = 2,
154+
.rate_min = 8000,
155+
.rate_max = 48000,
156+
},
157+
.ops = &acp_dmic_dai_ops,
158+
},
159+
};
160+
161+
static int acp63_i2s_master_clock_generate(struct acp_dev_data *adata)
162+
{
163+
u32 data;
164+
union clk_pll_req_no clk_pll;
165+
struct pci_dev *smn_dev;
166+
167+
smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x14E8, NULL);
168+
if (!smn_dev)
169+
return -ENODEV;
170+
171+
/* Clk5 pll register values to get mclk as 196.6MHz*/
172+
clk_pll.bits.fb_mult_int = 0x31;
173+
clk_pll.bits.pll_spine_div = 0;
174+
clk_pll.bits.gb_mult_frac = 0x26E9;
175+
176+
data = smn_read(smn_dev, CLK_PLL_PWR_REQ_N0);
177+
smn_write(smn_dev, CLK_PLL_PWR_REQ_N0, data | PLL_AUTO_STOP_REQ);
178+
179+
data = smn_read(smn_dev, CLK_SPLL_FIELD_2_N0);
180+
if (data & PLL_FRANCE_EN)
181+
smn_write(smn_dev, CLK_SPLL_FIELD_2_N0, data | PLL_FRANCE_EN);
182+
183+
smn_write(smn_dev, CLK_PLL_REQ_N0, clk_pll.clk_pll_req_no_reg);
184+
185+
data = smn_read(smn_dev, CLK_PLL_PWR_REQ_N0);
186+
smn_write(smn_dev, CLK_PLL_PWR_REQ_N0, data | PLL_AUTO_START_REQ);
187+
188+
data = smn_read(smn_dev, CLK_DFSBYPASS_CONTR);
189+
smn_write(smn_dev, CLK_DFSBYPASS_CONTR, data | EXIT_DPF_BYPASS_0);
190+
smn_write(smn_dev, CLK_DFSBYPASS_CONTR, data | EXIT_DPF_BYPASS_1);
191+
192+
smn_write(smn_dev, CLK_DFS_CNTL_N0, CLK0_DIVIDER);
193+
return 0;
194+
}
195+
196+
static int acp63_audio_probe(struct platform_device *pdev)
197+
{
198+
struct device *dev = &pdev->dev;
199+
struct acp_chip_info *chip;
200+
struct acp_dev_data *adata;
201+
struct resource *res;
202+
int ret;
203+
204+
chip = dev_get_platdata(&pdev->dev);
205+
if (!chip || !chip->base) {
206+
dev_err(&pdev->dev, "ACP chip data is NULL\n");
207+
return -ENODEV;
208+
}
209+
210+
if (chip->acp_rev != ACP63_DEV) {
211+
dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev);
212+
return -ENODEV;
213+
}
214+
215+
adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL);
216+
if (!adata)
217+
return -ENOMEM;
218+
219+
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acp_mem");
220+
if (!res) {
221+
dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n");
222+
return -ENODEV;
223+
}
224+
225+
adata->acp_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
226+
if (!adata->acp_base)
227+
return -ENOMEM;
228+
229+
res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "acp_dai_irq");
230+
if (!res) {
231+
dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
232+
return -ENODEV;
233+
}
234+
235+
adata->i2s_irq = res->start;
236+
adata->dev = dev;
237+
adata->dai_driver = acp63_dai;
238+
adata->num_dai = ARRAY_SIZE(acp63_dai);
239+
adata->rsrc = &rsrc;
240+
adata->machines = snd_soc_acpi_amd_acp63_acp_machines;
241+
acp_machine_select(adata);
242+
dev_set_drvdata(dev, adata);
243+
ret = acp63_i2s_master_clock_generate(adata);
244+
if (ret)
245+
return ret;
246+
247+
acp_enable_interrupts(adata);
248+
acp_platform_register(dev);
249+
pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS);
250+
pm_runtime_use_autosuspend(&pdev->dev);
251+
pm_runtime_mark_last_busy(&pdev->dev);
252+
pm_runtime_set_active(&pdev->dev);
253+
pm_runtime_enable(&pdev->dev);
254+
return 0;
255+
}
256+
257+
static void acp63_audio_remove(struct platform_device *pdev)
258+
{
259+
struct device *dev = &pdev->dev;
260+
struct acp_dev_data *adata = dev_get_drvdata(dev);
261+
262+
acp_disable_interrupts(adata);
263+
acp_platform_unregister(dev);
264+
pm_runtime_disable(&pdev->dev);
265+
}
266+
267+
static int __maybe_unused acp63_pcm_resume(struct device *dev)
268+
{
269+
struct acp_dev_data *adata = dev_get_drvdata(dev);
270+
struct acp_stream *stream;
271+
struct snd_pcm_substream *substream;
272+
snd_pcm_uframes_t buf_in_frames;
273+
u64 buf_size;
274+
275+
acp63_i2s_master_clock_generate(adata);
276+
spin_lock(&adata->acp_lock);
277+
list_for_each_entry(stream, &adata->stream_list, list) {
278+
if (stream) {
279+
substream = stream->substream;
280+
if (substream && substream->runtime) {
281+
buf_in_frames = (substream->runtime->buffer_size);
282+
buf_size = frames_to_bytes(substream->runtime, buf_in_frames);
283+
config_pte_for_stream(adata, stream);
284+
config_acp_dma(adata, stream, buf_size);
285+
if (stream->dai_id)
286+
restore_acp_i2s_params(substream, adata, stream);
287+
else
288+
restore_acp_pdm_params(substream, adata);
289+
}
290+
}
291+
}
292+
spin_unlock(&adata->acp_lock);
293+
return 0;
294+
}
295+
296+
static const struct dev_pm_ops acp63_dma_pm_ops = {
297+
SET_SYSTEM_SLEEP_PM_OPS(NULL, acp63_pcm_resume)
298+
};
299+
300+
static struct platform_driver acp63_driver = {
301+
.probe = acp63_audio_probe,
302+
.remove_new = acp63_audio_remove,
303+
.driver = {
304+
.name = "acp_asoc_acp63",
305+
.pm = &acp63_dma_pm_ops,
306+
},
307+
};
308+
309+
module_platform_driver(acp63_driver);
310+
311+
MODULE_DESCRIPTION("AMD ACP acp63 Driver");
312+
MODULE_IMPORT_NS(SND_SOC_ACP_COMMON);
313+
MODULE_LICENSE("Dual BSD/GPL");
314+
MODULE_ALIAS("platform:" DRV_NAME);

sound/soc/amd/acp/amd.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#define ACP3X_DEV 3
2222
#define ACP6X_DEV 6
23+
#define ACP63_DEV 0x63
2324

2425
#define DMIC_INSTANCE 0x00
2526
#define I2S_SP_INSTANCE 0x01
@@ -95,6 +96,9 @@
9596
#define ACP6X_PGFSM_CONTROL 0x1024
9697
#define ACP6X_PGFSM_STATUS 0x1028
9798

99+
#define ACP63_PGFSM_CONTROL ACP6X_PGFSM_CONTROL
100+
#define ACP63_PGFSM_STATUS ACP6X_PGFSM_STATUS
101+
98102
#define ACP_SOFT_RST_DONE_MASK 0x00010001
99103

100104
#define ACP_PGFSM_CNTL_POWER_ON_MASK 0x01

0 commit comments

Comments
 (0)