Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/amd/acp/acp63.c
26481 views
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
24
#include <asm/amd/node.h>
25
26
#include "amd.h"
27
#include "acp-mach.h"
28
#include "../mach-config.h"
29
30
#define DRV_NAME "acp_asoc_acp63"
31
32
#define CLK_PLL_PWR_REQ_N0 0X0006C2C0
33
#define CLK_SPLL_FIELD_2_N0 0X0006C114
34
#define CLK_PLL_REQ_N0 0X0006C0DC
35
#define CLK_DFSBYPASS_CONTR 0X0006C2C8
36
#define CLK_DFS_CNTL_N0 0X0006C1A4
37
38
#define PLL_AUTO_STOP_REQ BIT(4)
39
#define PLL_AUTO_START_REQ BIT(0)
40
#define PLL_FRANCE_EN BIT(4)
41
#define EXIT_DPF_BYPASS_0 BIT(16)
42
#define EXIT_DPF_BYPASS_1 BIT(17)
43
#define CLK0_DIVIDER 0X30
44
45
union clk_pll_req_no {
46
struct {
47
u32 fb_mult_int : 9;
48
u32 reserved : 3;
49
u32 pll_spine_div : 4;
50
u32 gb_mult_frac : 16;
51
} bitfields, bits;
52
u32 clk_pll_req_no_reg;
53
};
54
55
static struct snd_soc_dai_driver acp63_dai[] = {
56
{
57
.name = "acp-i2s-sp",
58
.id = I2S_SP_INSTANCE,
59
.playback = {
60
.stream_name = "I2S SP Playback",
61
.rates = SNDRV_PCM_RATE_8000_96000,
62
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
63
SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
64
.channels_min = 2,
65
.channels_max = 8,
66
.rate_min = 8000,
67
.rate_max = 96000,
68
},
69
.capture = {
70
.stream_name = "I2S SP Capture",
71
.rates = SNDRV_PCM_RATE_8000_48000,
72
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
73
SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
74
.channels_min = 2,
75
.channels_max = 2,
76
.rate_min = 8000,
77
.rate_max = 48000,
78
},
79
.ops = &asoc_acp_cpu_dai_ops,
80
},
81
{
82
.name = "acp-i2s-bt",
83
.id = I2S_BT_INSTANCE,
84
.playback = {
85
.stream_name = "I2S BT Playback",
86
.rates = SNDRV_PCM_RATE_8000_96000,
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 = 8,
91
.rate_min = 8000,
92
.rate_max = 96000,
93
},
94
.capture = {
95
.stream_name = "I2S BT Capture",
96
.rates = SNDRV_PCM_RATE_8000_48000,
97
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
98
SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
99
.channels_min = 2,
100
.channels_max = 2,
101
.rate_min = 8000,
102
.rate_max = 48000,
103
},
104
.ops = &asoc_acp_cpu_dai_ops,
105
},
106
{
107
.name = "acp-i2s-hs",
108
.id = I2S_HS_INSTANCE,
109
.playback = {
110
.stream_name = "I2S HS Playback",
111
.rates = SNDRV_PCM_RATE_8000_96000,
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 = 8,
116
.rate_min = 8000,
117
.rate_max = 96000,
118
},
119
.capture = {
120
.stream_name = "I2S HS Capture",
121
.rates = SNDRV_PCM_RATE_8000_48000,
122
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
123
SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
124
.channels_min = 2,
125
.channels_max = 8,
126
.rate_min = 8000,
127
.rate_max = 48000,
128
},
129
.ops = &asoc_acp_cpu_dai_ops,
130
},
131
{
132
.name = "acp-pdm-dmic",
133
.id = DMIC_INSTANCE,
134
.capture = {
135
.rates = SNDRV_PCM_RATE_8000_48000,
136
.formats = SNDRV_PCM_FMTBIT_S32_LE,
137
.channels_min = 2,
138
.channels_max = 2,
139
.rate_min = 8000,
140
.rate_max = 48000,
141
},
142
.ops = &acp_dmic_dai_ops,
143
},
144
};
145
146
static int acp63_i2s_master_clock_generate(struct acp_chip_info *chip)
147
{
148
int rc;
149
u32 data;
150
union clk_pll_req_no clk_pll;
151
152
/* Clk5 pll register values to get mclk as 196.6MHz*/
153
clk_pll.bits.fb_mult_int = 0x31;
154
clk_pll.bits.pll_spine_div = 0;
155
clk_pll.bits.gb_mult_frac = 0x26E9;
156
157
rc = amd_smn_read(0, CLK_PLL_PWR_REQ_N0, &data);
158
if (rc)
159
return rc;
160
rc = amd_smn_write(0, CLK_PLL_PWR_REQ_N0, data | PLL_AUTO_STOP_REQ);
161
if (rc)
162
return rc;
163
164
rc = amd_smn_read(0, CLK_SPLL_FIELD_2_N0, &data);
165
if (rc)
166
return rc;
167
if (data & PLL_FRANCE_EN) {
168
rc = amd_smn_write(0, CLK_SPLL_FIELD_2_N0, data | PLL_FRANCE_EN);
169
if (rc)
170
return rc;
171
}
172
173
rc = amd_smn_write(0, CLK_PLL_REQ_N0, clk_pll.clk_pll_req_no_reg);
174
if (rc)
175
return rc;
176
177
rc = amd_smn_read(0, CLK_PLL_PWR_REQ_N0, &data);
178
if (rc)
179
return rc;
180
rc = amd_smn_write(0, CLK_PLL_PWR_REQ_N0, data | PLL_AUTO_START_REQ);
181
if (rc)
182
return rc;
183
184
rc = amd_smn_read(0, CLK_DFSBYPASS_CONTR, &data);
185
if (rc)
186
return rc;
187
rc = amd_smn_write(0, CLK_DFSBYPASS_CONTR, data | EXIT_DPF_BYPASS_0);
188
if (rc)
189
return rc;
190
rc = amd_smn_write(0, CLK_DFSBYPASS_CONTR, data | EXIT_DPF_BYPASS_1);
191
if (rc)
192
return rc;
193
194
return amd_smn_write(0, CLK_DFS_CNTL_N0, CLK0_DIVIDER);
195
}
196
197
static int acp63_audio_probe(struct platform_device *pdev)
198
{
199
struct device *dev = &pdev->dev;
200
struct acp_chip_info *chip;
201
int ret;
202
203
chip = dev_get_platdata(&pdev->dev);
204
if (!chip || !chip->base) {
205
dev_err(&pdev->dev, "ACP chip data is NULL\n");
206
return -ENODEV;
207
}
208
209
if (chip->acp_rev != ACP63_PCI_ID) {
210
dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev);
211
return -ENODEV;
212
}
213
214
chip->dev = dev;
215
chip->dai_driver = acp63_dai;
216
chip->num_dai = ARRAY_SIZE(acp63_dai);
217
218
if (chip->is_i2s_config && chip->rsrc->soc_mclk) {
219
ret = acp63_i2s_master_clock_generate(chip);
220
if (ret)
221
return ret;
222
}
223
ret = acp_hw_en_interrupts(chip);
224
if (ret) {
225
dev_err(dev, "ACP en-interrupts failed\n");
226
return ret;
227
}
228
acp_platform_register(dev);
229
pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS);
230
pm_runtime_use_autosuspend(&pdev->dev);
231
pm_runtime_mark_last_busy(&pdev->dev);
232
pm_runtime_set_active(&pdev->dev);
233
pm_runtime_enable(&pdev->dev);
234
return 0;
235
}
236
237
static void acp63_audio_remove(struct platform_device *pdev)
238
{
239
struct device *dev = &pdev->dev;
240
struct acp_chip_info *chip = dev_get_platdata(dev);
241
int ret;
242
243
ret = acp_hw_dis_interrupts(chip);
244
if (ret)
245
dev_err(dev, "ACP dis-interrupts failed\n");
246
247
acp_platform_unregister(dev);
248
pm_runtime_disable(&pdev->dev);
249
}
250
251
static int acp63_pcm_resume(struct device *dev)
252
{
253
struct acp_chip_info *chip = dev_get_drvdata(dev->parent);
254
struct acp_stream *stream;
255
struct snd_pcm_substream *substream;
256
snd_pcm_uframes_t buf_in_frames;
257
u64 buf_size;
258
259
if (chip->is_i2s_config && chip->rsrc->soc_mclk)
260
acp63_i2s_master_clock_generate(chip);
261
262
spin_lock(&chip->acp_lock);
263
list_for_each_entry(stream, &chip->stream_list, list) {
264
substream = stream->substream;
265
if (substream && substream->runtime) {
266
buf_in_frames = (substream->runtime->buffer_size);
267
buf_size = frames_to_bytes(substream->runtime, buf_in_frames);
268
config_pte_for_stream(chip, stream);
269
config_acp_dma(chip, stream, buf_size);
270
if (stream->dai_id)
271
restore_acp_i2s_params(substream, chip, stream);
272
else
273
restore_acp_pdm_params(substream, chip);
274
}
275
}
276
spin_unlock(&chip->acp_lock);
277
return 0;
278
}
279
280
static const struct dev_pm_ops acp63_dma_pm_ops = {
281
SYSTEM_SLEEP_PM_OPS(NULL, acp63_pcm_resume)
282
};
283
284
static struct platform_driver acp63_driver = {
285
.probe = acp63_audio_probe,
286
.remove = acp63_audio_remove,
287
.driver = {
288
.name = "acp_asoc_acp63",
289
.pm = pm_ptr(&acp63_dma_pm_ops),
290
},
291
};
292
293
module_platform_driver(acp63_driver);
294
295
MODULE_DESCRIPTION("AMD ACP acp63 Driver");
296
MODULE_IMPORT_NS("SND_SOC_ACP_COMMON");
297
MODULE_LICENSE("Dual BSD/GPL");
298
MODULE_ALIAS("platform:" DRV_NAME);
299
300