Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/amd/ps/ps-common.c
26481 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* AMD ACP PCI driver callback routines for ACP6.3, ACP7.0 & ACP7.1
4
* platforms.
5
*
6
* Copyright 2025 Advanced Micro Devices, Inc.
7
* Authors: Vijendar Mukunda <[email protected]>
8
*/
9
10
#include <linux/bitops.h>
11
#include <linux/delay.h>
12
#include <linux/export.h>
13
#include <linux/io.h>
14
#include <linux/iopoll.h>
15
#include <linux/pci.h>
16
#include <linux/platform_device.h>
17
#include <linux/pm_runtime.h>
18
#include <sound/pcm_params.h>
19
20
#include "acp63.h"
21
22
static int acp63_power_on(void __iomem *acp_base)
23
{
24
u32 val;
25
26
val = readl(acp_base + ACP_PGFSM_STATUS);
27
28
if (!val)
29
return val;
30
31
if ((val & ACP63_PGFSM_STATUS_MASK) != ACP63_POWER_ON_IN_PROGRESS)
32
writel(ACP63_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL);
33
34
return readl_poll_timeout(acp_base + ACP_PGFSM_STATUS, val, !val, DELAY_US, ACP63_TIMEOUT);
35
}
36
37
static int acp63_reset(void __iomem *acp_base)
38
{
39
u32 val;
40
int ret;
41
42
writel(1, acp_base + ACP_SOFT_RESET);
43
44
ret = readl_poll_timeout(acp_base + ACP_SOFT_RESET, val,
45
val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK,
46
DELAY_US, ACP63_TIMEOUT);
47
if (ret)
48
return ret;
49
50
writel(0, acp_base + ACP_SOFT_RESET);
51
52
return readl_poll_timeout(acp_base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP63_TIMEOUT);
53
}
54
55
static void acp63_enable_interrupts(void __iomem *acp_base)
56
{
57
writel(1, acp_base + ACP_EXTERNAL_INTR_ENB);
58
writel(ACP_ERROR_IRQ, acp_base + ACP_EXTERNAL_INTR_CNTL);
59
}
60
61
static void acp63_disable_interrupts(void __iomem *acp_base)
62
{
63
writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp_base + ACP_EXTERNAL_INTR_STAT);
64
writel(0, acp_base + ACP_EXTERNAL_INTR_CNTL);
65
writel(0, acp_base + ACP_EXTERNAL_INTR_ENB);
66
}
67
68
static int acp63_init(void __iomem *acp_base, struct device *dev)
69
{
70
int ret;
71
72
ret = acp63_power_on(acp_base);
73
if (ret) {
74
dev_err(dev, "ACP power on failed\n");
75
return ret;
76
}
77
writel(0x01, acp_base + ACP_CONTROL);
78
ret = acp63_reset(acp_base);
79
if (ret) {
80
dev_err(dev, "ACP reset failed\n");
81
return ret;
82
}
83
acp63_enable_interrupts(acp_base);
84
writel(0, acp_base + ACP_ZSC_DSP_CTRL);
85
return 0;
86
}
87
88
static int acp63_deinit(void __iomem *acp_base, struct device *dev)
89
{
90
int ret;
91
92
acp63_disable_interrupts(acp_base);
93
ret = acp63_reset(acp_base);
94
if (ret) {
95
dev_err(dev, "ACP reset failed\n");
96
return ret;
97
}
98
writel(0, acp_base + ACP_CONTROL);
99
writel(1, acp_base + ACP_ZSC_DSP_CTRL);
100
return 0;
101
}
102
103
static void acp63_get_config(struct pci_dev *pci, struct acp63_dev_data *acp_data)
104
{
105
u32 config;
106
107
config = readl(acp_data->acp63_base + ACP_PIN_CONFIG);
108
dev_dbg(&pci->dev, "ACP config value: %d\n", config);
109
switch (config) {
110
case ACP_CONFIG_4:
111
case ACP_CONFIG_5:
112
case ACP_CONFIG_10:
113
case ACP_CONFIG_11:
114
acp_data->is_pdm_config = true;
115
break;
116
case ACP_CONFIG_2:
117
case ACP_CONFIG_3:
118
acp_data->is_sdw_config = true;
119
break;
120
case ACP_CONFIG_6:
121
case ACP_CONFIG_7:
122
case ACP_CONFIG_12:
123
case ACP_CONFIG_8:
124
case ACP_CONFIG_13:
125
case ACP_CONFIG_14:
126
acp_data->is_pdm_config = true;
127
acp_data->is_sdw_config = true;
128
break;
129
default:
130
break;
131
}
132
}
133
134
static bool check_acp_sdw_enable_status(struct acp63_dev_data *adata)
135
{
136
u32 sdw0_en, sdw1_en;
137
138
sdw0_en = readl(adata->acp63_base + ACP_SW0_EN);
139
sdw1_en = readl(adata->acp63_base + ACP_SW1_EN);
140
return (sdw0_en || sdw1_en);
141
}
142
143
static void handle_acp63_sdw_pme_event(struct acp63_dev_data *adata)
144
{
145
u32 val;
146
147
val = readl(adata->acp63_base + ACP_SW0_WAKE_EN);
148
if (val && adata->sdw->pdev[0])
149
pm_request_resume(&adata->sdw->pdev[0]->dev);
150
151
val = readl(adata->acp63_base + ACP_SW1_WAKE_EN);
152
if (val && adata->sdw->pdev[1])
153
pm_request_resume(&adata->sdw->pdev[1]->dev);
154
}
155
156
static int __maybe_unused snd_acp63_suspend(struct device *dev)
157
{
158
struct acp63_dev_data *adata;
159
int ret;
160
161
adata = dev_get_drvdata(dev);
162
if (adata->is_sdw_dev) {
163
adata->acp_sw_pad_keeper_en = readl(adata->acp63_base + ACP_SW0_PAD_KEEPER_EN);
164
adata->acp_pad_pulldown_ctrl = readl(adata->acp63_base + ACP_PAD_PULLDOWN_CTRL);
165
adata->sdw_en_stat = check_acp_sdw_enable_status(adata);
166
if (adata->sdw_en_stat) {
167
writel(1, adata->acp63_base + ACP_ZSC_DSP_CTRL);
168
return 0;
169
}
170
}
171
ret = acp_hw_deinit(adata, dev);
172
if (ret)
173
dev_err(dev, "ACP de-init failed\n");
174
175
return ret;
176
}
177
178
static int __maybe_unused snd_acp63_runtime_resume(struct device *dev)
179
{
180
struct acp63_dev_data *adata;
181
int ret;
182
183
adata = dev_get_drvdata(dev);
184
if (adata->sdw_en_stat) {
185
writel(0, adata->acp63_base + ACP_ZSC_DSP_CTRL);
186
return 0;
187
}
188
ret = acp_hw_init(adata, dev);
189
if (ret) {
190
dev_err(dev, "ACP init failed\n");
191
return ret;
192
}
193
194
if (!adata->sdw_en_stat)
195
handle_acp63_sdw_pme_event(adata);
196
return 0;
197
}
198
199
static int __maybe_unused snd_acp63_resume(struct device *dev)
200
{
201
struct acp63_dev_data *adata;
202
u32 acp_sw_pad_keeper_en;
203
int ret;
204
205
adata = dev_get_drvdata(dev);
206
if (adata->sdw_en_stat) {
207
writel(0, adata->acp63_base + ACP_ZSC_DSP_CTRL);
208
return 0;
209
}
210
211
ret = acp_hw_init(adata, dev);
212
if (ret)
213
dev_err(dev, "ACP init failed\n");
214
215
acp_sw_pad_keeper_en = readl(adata->acp63_base + ACP_SW0_PAD_KEEPER_EN);
216
dev_dbg(dev, "ACP_SW0_PAD_KEEPER_EN:0x%x\n", acp_sw_pad_keeper_en);
217
if (!acp_sw_pad_keeper_en) {
218
writel(adata->acp_sw_pad_keeper_en, adata->acp63_base + ACP_SW0_PAD_KEEPER_EN);
219
writel(adata->acp_pad_pulldown_ctrl, adata->acp63_base + ACP_PAD_PULLDOWN_CTRL);
220
}
221
return ret;
222
}
223
224
static void acp63_sdw_dma_irq_thread(struct acp63_dev_data *adata)
225
{
226
struct sdw_dma_dev_data *sdw_data;
227
u32 stream_id;
228
229
sdw_data = dev_get_drvdata(&adata->sdw_dma_dev->dev);
230
231
for (stream_id = 0; stream_id < ACP63_SDW0_DMA_MAX_STREAMS; stream_id++) {
232
if (adata->acp63_sdw0_dma_intr_stat[stream_id]) {
233
if (sdw_data->acp63_sdw0_dma_stream[stream_id])
234
snd_pcm_period_elapsed(sdw_data->acp63_sdw0_dma_stream[stream_id]);
235
adata->acp63_sdw0_dma_intr_stat[stream_id] = 0;
236
}
237
}
238
for (stream_id = 0; stream_id < ACP63_SDW1_DMA_MAX_STREAMS; stream_id++) {
239
if (adata->acp63_sdw1_dma_intr_stat[stream_id]) {
240
if (sdw_data->acp63_sdw1_dma_stream[stream_id])
241
snd_pcm_period_elapsed(sdw_data->acp63_sdw1_dma_stream[stream_id]);
242
adata->acp63_sdw1_dma_intr_stat[stream_id] = 0;
243
}
244
}
245
}
246
247
void acp63_hw_init_ops(struct acp_hw_ops *hw_ops)
248
{
249
hw_ops->acp_init = acp63_init;
250
hw_ops->acp_deinit = acp63_deinit;
251
hw_ops->acp_get_config = acp63_get_config;
252
hw_ops->acp_sdw_dma_irq_thread = acp63_sdw_dma_irq_thread;
253
hw_ops->acp_suspend = snd_acp63_suspend;
254
hw_ops->acp_resume = snd_acp63_resume;
255
hw_ops->acp_suspend_runtime = snd_acp63_suspend;
256
hw_ops->acp_resume_runtime = snd_acp63_runtime_resume;
257
}
258
259
static int acp70_power_on(void __iomem *acp_base)
260
{
261
u32 val = 0;
262
263
val = readl(acp_base + ACP_PGFSM_STATUS);
264
265
if (!val)
266
return 0;
267
if (val & ACP70_PGFSM_STATUS_MASK)
268
writel(ACP70_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL);
269
270
return readl_poll_timeout(acp_base + ACP_PGFSM_STATUS, val, !val, DELAY_US, ACP70_TIMEOUT);
271
}
272
273
static int acp70_reset(void __iomem *acp_base)
274
{
275
u32 val;
276
int ret;
277
278
writel(1, acp_base + ACP_SOFT_RESET);
279
280
ret = readl_poll_timeout(acp_base + ACP_SOFT_RESET, val,
281
val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK,
282
DELAY_US, ACP70_TIMEOUT);
283
if (ret)
284
return ret;
285
286
writel(0, acp_base + ACP_SOFT_RESET);
287
288
return readl_poll_timeout(acp_base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP70_TIMEOUT);
289
}
290
291
static void acp70_enable_sdw_host_wake_interrupts(void __iomem *acp_base)
292
{
293
u32 ext_intr_cntl1;
294
295
ext_intr_cntl1 = readl(acp_base + ACP_EXTERNAL_INTR_CNTL1);
296
ext_intr_cntl1 |= ACP70_SDW_HOST_WAKE_MASK;
297
writel(ext_intr_cntl1, acp_base + ACP_EXTERNAL_INTR_CNTL1);
298
}
299
300
static void acp70_enable_interrupts(void __iomem *acp_base)
301
{
302
u32 sdw0_wake_en, sdw1_wake_en;
303
304
writel(1, acp_base + ACP_EXTERNAL_INTR_ENB);
305
writel(ACP_ERROR_IRQ, acp_base + ACP_EXTERNAL_INTR_CNTL);
306
sdw0_wake_en = readl(acp_base + ACP_SW0_WAKE_EN);
307
sdw1_wake_en = readl(acp_base + ACP_SW1_WAKE_EN);
308
if (sdw0_wake_en || sdw1_wake_en)
309
acp70_enable_sdw_host_wake_interrupts(acp_base);
310
}
311
312
static void acp70_disable_interrupts(void __iomem *acp_base)
313
{
314
writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp_base + ACP_EXTERNAL_INTR_STAT);
315
writel(0, acp_base + ACP_EXTERNAL_INTR_CNTL);
316
writel(0, acp_base + ACP_EXTERNAL_INTR_ENB);
317
}
318
319
static int acp70_init(void __iomem *acp_base, struct device *dev)
320
{
321
int ret;
322
323
ret = acp70_power_on(acp_base);
324
if (ret) {
325
dev_err(dev, "ACP power on failed\n");
326
return ret;
327
}
328
writel(0x01, acp_base + ACP_CONTROL);
329
ret = acp70_reset(acp_base);
330
if (ret) {
331
dev_err(dev, "ACP reset failed\n");
332
return ret;
333
}
334
writel(0, acp_base + ACP_ZSC_DSP_CTRL);
335
acp70_enable_interrupts(acp_base);
336
writel(0x1, acp_base + ACP_PME_EN);
337
return 0;
338
}
339
340
static int acp70_deinit(void __iomem *acp_base, struct device *dev)
341
{
342
int ret;
343
344
acp70_disable_interrupts(acp_base);
345
ret = acp70_reset(acp_base);
346
if (ret) {
347
dev_err(dev, "ACP reset failed\n");
348
return ret;
349
}
350
writel(0x01, acp_base + ACP_ZSC_DSP_CTRL);
351
return 0;
352
}
353
354
static void acp70_get_config(struct pci_dev *pci, struct acp63_dev_data *acp_data)
355
{
356
u32 config;
357
358
config = readl(acp_data->acp63_base + ACP_PIN_CONFIG);
359
dev_dbg(&pci->dev, "ACP config value: %d\n", config);
360
switch (config) {
361
case ACP_CONFIG_4:
362
case ACP_CONFIG_5:
363
case ACP_CONFIG_10:
364
case ACP_CONFIG_11:
365
case ACP_CONFIG_20:
366
acp_data->is_pdm_config = true;
367
break;
368
case ACP_CONFIG_2:
369
case ACP_CONFIG_3:
370
case ACP_CONFIG_16:
371
acp_data->is_sdw_config = true;
372
break;
373
case ACP_CONFIG_6:
374
case ACP_CONFIG_7:
375
case ACP_CONFIG_12:
376
case ACP_CONFIG_8:
377
case ACP_CONFIG_13:
378
case ACP_CONFIG_14:
379
case ACP_CONFIG_17:
380
case ACP_CONFIG_18:
381
case ACP_CONFIG_19:
382
acp_data->is_pdm_config = true;
383
acp_data->is_sdw_config = true;
384
break;
385
default:
386
break;
387
}
388
}
389
390
static void acp70_sdw_dma_irq_thread(struct acp63_dev_data *adata)
391
{
392
struct sdw_dma_dev_data *sdw_data;
393
u32 stream_id;
394
395
sdw_data = dev_get_drvdata(&adata->sdw_dma_dev->dev);
396
397
for (stream_id = 0; stream_id < ACP70_SDW0_DMA_MAX_STREAMS; stream_id++) {
398
if (adata->acp70_sdw0_dma_intr_stat[stream_id]) {
399
if (sdw_data->acp70_sdw0_dma_stream[stream_id])
400
snd_pcm_period_elapsed(sdw_data->acp70_sdw0_dma_stream[stream_id]);
401
adata->acp70_sdw0_dma_intr_stat[stream_id] = 0;
402
}
403
}
404
for (stream_id = 0; stream_id < ACP70_SDW1_DMA_MAX_STREAMS; stream_id++) {
405
if (adata->acp70_sdw1_dma_intr_stat[stream_id]) {
406
if (sdw_data->acp70_sdw1_dma_stream[stream_id])
407
snd_pcm_period_elapsed(sdw_data->acp70_sdw1_dma_stream[stream_id]);
408
adata->acp70_sdw1_dma_intr_stat[stream_id] = 0;
409
}
410
}
411
}
412
413
static int __maybe_unused snd_acp70_suspend(struct device *dev)
414
{
415
struct acp63_dev_data *adata;
416
int ret;
417
418
adata = dev_get_drvdata(dev);
419
if (adata->is_sdw_dev) {
420
adata->acp_sw_pad_keeper_en = readl(adata->acp63_base + ACP_SW0_PAD_KEEPER_EN);
421
adata->acp_pad_pulldown_ctrl = readl(adata->acp63_base + ACP_PAD_PULLDOWN_CTRL);
422
adata->sdw_en_stat = check_acp_sdw_enable_status(adata);
423
if (adata->sdw_en_stat) {
424
writel(1, adata->acp63_base + ACP_ZSC_DSP_CTRL);
425
return 0;
426
}
427
}
428
ret = acp_hw_deinit(adata, dev);
429
if (ret)
430
dev_err(dev, "ACP de-init failed\n");
431
432
return ret;
433
}
434
435
static int __maybe_unused snd_acp70_runtime_resume(struct device *dev)
436
{
437
struct acp63_dev_data *adata;
438
int ret;
439
440
adata = dev_get_drvdata(dev);
441
442
if (adata->sdw_en_stat) {
443
writel(0, adata->acp63_base + ACP_ZSC_DSP_CTRL);
444
writel(1, adata->acp63_base + ACP_PME_EN);
445
return 0;
446
}
447
448
ret = acp_hw_init(adata, dev);
449
if (ret) {
450
dev_err(dev, "ACP init failed\n");
451
return ret;
452
}
453
return 0;
454
}
455
456
static int __maybe_unused snd_acp70_resume(struct device *dev)
457
{
458
struct acp63_dev_data *adata;
459
u32 acp_sw_pad_keeper_en;
460
int ret;
461
462
adata = dev_get_drvdata(dev);
463
464
if (adata->sdw_en_stat) {
465
writel(0, adata->acp63_base + ACP_ZSC_DSP_CTRL);
466
writel(1, adata->acp63_base + ACP_PME_EN);
467
return 0;
468
}
469
470
ret = acp_hw_init(adata, dev);
471
if (ret)
472
dev_err(dev, "ACP init failed\n");
473
474
acp_sw_pad_keeper_en = readl(adata->acp63_base + ACP_SW0_PAD_KEEPER_EN);
475
dev_dbg(dev, "ACP_SW0_PAD_KEEPER_EN:0x%x\n", acp_sw_pad_keeper_en);
476
if (!acp_sw_pad_keeper_en) {
477
writel(adata->acp_sw_pad_keeper_en, adata->acp63_base + ACP_SW0_PAD_KEEPER_EN);
478
writel(adata->acp_pad_pulldown_ctrl, adata->acp63_base + ACP_PAD_PULLDOWN_CTRL);
479
}
480
return ret;
481
}
482
483
void acp70_hw_init_ops(struct acp_hw_ops *hw_ops)
484
{
485
hw_ops->acp_init = acp70_init;
486
hw_ops->acp_deinit = acp70_deinit;
487
hw_ops->acp_get_config = acp70_get_config;
488
hw_ops->acp_sdw_dma_irq_thread = acp70_sdw_dma_irq_thread;
489
hw_ops->acp_suspend = snd_acp70_suspend;
490
hw_ops->acp_resume = snd_acp70_resume;
491
hw_ops->acp_suspend_runtime = snd_acp70_suspend;
492
hw_ops->acp_resume_runtime = snd_acp70_runtime_resume;
493
}
494
495