File Index
Files and directories
Sign in
FILE

ps-common.c

File preview with syntax highlighting.

linux-6.19.14/sound/soc/amd/ps/ps-common.c C
  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 <Vijendar.Mukunda@amd.com>
  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
 22static 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
 37static 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
 55static 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
 61static 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
 68static 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
 88static 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
103static 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
134static 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
143static 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
156static 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
178static 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
199static 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
224static 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
247void 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
259static 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
273static 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
291static 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
300static 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
312static 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
319static 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
340static 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
354static 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
390static 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
413static 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
435static 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
456static 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
483void 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}
~/ Read-only file preview.