File Index
Files and directories
Sign in
FILE

acp-legacy-common.c

File preview with syntax highlighting.

linux-6.19.14/sound/soc/amd/acp/acp-legacy-common.c C
  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 <Syed.SabaKareem@amd.com>
  9//
 10
 11/*
 12 * Common file to be used by amd platforms
 13 */
 14
 15#include "amd.h"
 16#include <linux/acpi.h>
 17#include <linux/pci.h>
 18#include <linux/export.h>
 19
 20#include "../mach-config.h"
 21
 22#define ACP_RENOIR_PDM_ADDR	0x02
 23#define ACP_REMBRANDT_PDM_ADDR	0x03
 24#define ACP63_PDM_ADDR		0x02
 25#define ACP70_PDM_ADDR		0x02
 26
 27struct acp_resource rn_rsrc = {
 28	.offset = 20,
 29	.no_of_ctrls = 1,
 30	.irqp_used = 0,
 31	.irq_reg_offset = 0x1800,
 32	.scratch_reg_offset = 0x12800,
 33	.sram_pte_offset = 0x02052800,
 34};
 35EXPORT_SYMBOL_NS_GPL(rn_rsrc, "SND_SOC_ACP_COMMON");
 36
 37struct acp_resource rmb_rsrc = {
 38	.offset = 0,
 39	.no_of_ctrls = 2,
 40	.irqp_used = 1,
 41	.soc_mclk = true,
 42	.irq_reg_offset = 0x1a00,
 43	.scratch_reg_offset = 0x12800,
 44	.sram_pte_offset = 0x03802800,
 45};
 46EXPORT_SYMBOL_NS_GPL(rmb_rsrc, "SND_SOC_ACP_COMMON");
 47
 48struct acp_resource acp63_rsrc = {
 49	.offset = 0,
 50	.no_of_ctrls = 2,
 51	.irqp_used = 1,
 52	.soc_mclk = true,
 53	.irq_reg_offset = 0x1a00,
 54	.scratch_reg_offset = 0x12800,
 55	.sram_pte_offset = 0x03802800,
 56};
 57EXPORT_SYMBOL_NS_GPL(acp63_rsrc, "SND_SOC_ACP_COMMON");
 58
 59struct acp_resource acp70_rsrc = {
 60	.offset = 0,
 61	.no_of_ctrls = 2,
 62	.irqp_used = 1,
 63	.soc_mclk = true,
 64	.irq_reg_offset = 0x1a00,
 65	.scratch_reg_offset = 0x10000,
 66	.sram_pte_offset = 0x03800000,
 67};
 68EXPORT_SYMBOL_NS_GPL(acp70_rsrc, "SND_SOC_ACP_COMMON");
 69
 70static const struct snd_acp_hw_ops acp_common_hw_ops = {
 71	/* ACP hardware initilizations */
 72	.acp_init = acp_init,
 73	.acp_deinit = acp_deinit,
 74
 75	/* ACP Interrupts*/
 76	.irq = acp_irq_handler,
 77	.en_interrupts = acp_enable_interrupts,
 78	.dis_interrupts = acp_disable_interrupts,
 79};
 80
 81irqreturn_t acp_irq_handler(int irq, void *data)
 82{
 83	struct acp_chip_info *chip = data;
 84	struct acp_resource *rsrc = chip->rsrc;
 85	struct acp_stream *stream;
 86	u16 i2s_flag = 0;
 87	u32 ext_intr_stat, ext_intr_stat1;
 88
 89	if (rsrc->no_of_ctrls == 2)
 90		ext_intr_stat1 = readl(ACP_EXTERNAL_INTR_STAT(chip, (rsrc->irqp_used - 1)));
 91
 92	ext_intr_stat = readl(ACP_EXTERNAL_INTR_STAT(chip, rsrc->irqp_used));
 93
 94	spin_lock(&chip->acp_lock);
 95	list_for_each_entry(stream, &chip->stream_list, list) {
 96		if (ext_intr_stat & stream->irq_bit) {
 97			writel(stream->irq_bit,
 98			       ACP_EXTERNAL_INTR_STAT(chip, rsrc->irqp_used));
 99			snd_pcm_period_elapsed(stream->substream);
100			i2s_flag = 1;
101		}
102		if (chip->rsrc->no_of_ctrls == 2) {
103			if (ext_intr_stat1 & stream->irq_bit) {
104				writel(stream->irq_bit, ACP_EXTERNAL_INTR_STAT(chip,
105				       (rsrc->irqp_used - 1)));
106				snd_pcm_period_elapsed(stream->substream);
107				i2s_flag = 1;
108			}
109		}
110	}
111	spin_unlock(&chip->acp_lock);
112	if (i2s_flag)
113		return IRQ_HANDLED;
114
115	return IRQ_NONE;
116}
117
118int acp_enable_interrupts(struct acp_chip_info *chip)
119{
120	struct acp_resource *rsrc;
121	u32 ext_intr_ctrl;
122
123	rsrc = chip->rsrc;
124	writel(0x01, ACP_EXTERNAL_INTR_ENB(chip));
125	ext_intr_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(chip, rsrc->irqp_used));
126	ext_intr_ctrl |= ACP_ERROR_MASK;
127	writel(ext_intr_ctrl, ACP_EXTERNAL_INTR_CNTL(chip, rsrc->irqp_used));
128
129	return 0;
130}
131EXPORT_SYMBOL_NS_GPL(acp_enable_interrupts, "SND_SOC_ACP_COMMON");
132
133int acp_disable_interrupts(struct acp_chip_info *chip)
134{
135	struct acp_resource *rsrc;
136
137	rsrc = chip->rsrc;
138	writel(ACP_EXT_INTR_STAT_CLEAR_MASK, ACP_EXTERNAL_INTR_STAT(chip, rsrc->irqp_used));
139	writel(0x00, ACP_EXTERNAL_INTR_ENB(chip));
140
141	return 0;
142}
143EXPORT_SYMBOL_NS_GPL(acp_disable_interrupts, "SND_SOC_ACP_COMMON");
144
145static void set_acp_pdm_ring_buffer(struct snd_pcm_substream *substream,
146				    struct snd_soc_dai *dai)
147{
148	struct snd_pcm_runtime *runtime = substream->runtime;
149	struct acp_stream *stream = runtime->private_data;
150	struct device *dev = dai->component->dev;
151	struct acp_chip_info *chip = dev_get_platdata(dev);
152
153	u32 physical_addr, pdm_size, period_bytes;
154
155	period_bytes = frames_to_bytes(runtime, runtime->period_size);
156	pdm_size = frames_to_bytes(runtime, runtime->buffer_size);
157	physical_addr = stream->reg_offset + MEM_WINDOW_START;
158
159	/* Init ACP PDM Ring buffer */
160	writel(physical_addr, chip->base + ACP_WOV_RX_RINGBUFADDR);
161	writel(pdm_size, chip->base + ACP_WOV_RX_RINGBUFSIZE);
162	writel(period_bytes, chip->base + ACP_WOV_RX_INTR_WATERMARK_SIZE);
163	writel(0x01, chip->base + ACPAXI2AXI_ATU_CTRL);
164}
165
166static void set_acp_pdm_clk(struct snd_pcm_substream *substream,
167			    struct snd_soc_dai *dai)
168{
169	struct device *dev = dai->component->dev;
170	struct acp_chip_info *chip = dev_get_platdata(dev);
171	unsigned int pdm_ctrl;
172
173	/* Enable default ACP PDM clk */
174	writel(PDM_CLK_FREQ_MASK, chip->base + ACP_WOV_CLK_CTRL);
175	pdm_ctrl = readl(chip->base + ACP_WOV_MISC_CTRL);
176	pdm_ctrl |= PDM_MISC_CTRL_MASK;
177	writel(pdm_ctrl, chip->base + ACP_WOV_MISC_CTRL);
178	set_acp_pdm_ring_buffer(substream, dai);
179}
180
181void restore_acp_pdm_params(struct snd_pcm_substream *substream,
182			    struct acp_chip_info *chip)
183{
184	struct snd_soc_dai *dai;
185	struct snd_soc_pcm_runtime *soc_runtime;
186	u32 ext_int_ctrl;
187
188	soc_runtime = snd_soc_substream_to_rtd(substream);
189	dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
190
191	/* Programming channel mask and sampling rate */
192	writel(chip->ch_mask, chip->base + ACP_WOV_PDM_NO_OF_CHANNELS);
193	writel(PDM_DEC_64, chip->base + ACP_WOV_PDM_DECIMATION_FACTOR);
194
195	/* Enabling ACP Pdm interuppts */
196	ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(chip, 0));
197	ext_int_ctrl |= PDM_DMA_INTR_MASK;
198	writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(chip, 0));
199	set_acp_pdm_clk(substream, dai);
200}
201EXPORT_SYMBOL_NS_GPL(restore_acp_pdm_params, "SND_SOC_ACP_COMMON");
202
203static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream,
204				struct snd_soc_dai *dai)
205{
206	struct device *dev = dai->component->dev;
207	struct acp_chip_info *chip = dev_get_platdata(dev);
208	struct acp_resource *rsrc = chip->rsrc;
209	struct acp_stream *stream = substream->runtime->private_data;
210	u32 reg_dma_size, reg_fifo_size, reg_fifo_addr;
211	u32 phy_addr, acp_fifo_addr, ext_int_ctrl;
212	unsigned int dir = substream->stream;
213
214	switch (dai->driver->id) {
215	case I2S_SP_INSTANCE:
216		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
217			reg_dma_size = ACP_I2S_TX_DMA_SIZE(chip);
218			acp_fifo_addr = rsrc->sram_pte_offset +
219					SP_PB_FIFO_ADDR_OFFSET;
220			reg_fifo_addr = ACP_I2S_TX_FIFOADDR(chip);
221			reg_fifo_size = ACP_I2S_TX_FIFOSIZE(chip);
222			if (chip->acp_rev >= ACP70_PCI_ID)
223				phy_addr = ACP7x_I2S_SP_TX_MEM_WINDOW_START;
224			else
225				phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset;
226			writel(phy_addr, chip->base + ACP_I2S_TX_RINGBUFADDR(chip));
227		} else {
228			reg_dma_size = ACP_I2S_RX_DMA_SIZE(chip);
229			acp_fifo_addr = rsrc->sram_pte_offset +
230					SP_CAPT_FIFO_ADDR_OFFSET;
231			reg_fifo_addr = ACP_I2S_RX_FIFOADDR(chip);
232			reg_fifo_size = ACP_I2S_RX_FIFOSIZE(chip);
233			if (chip->acp_rev >= ACP70_PCI_ID)
234				phy_addr = ACP7x_I2S_SP_RX_MEM_WINDOW_START;
235			else
236				phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset;
237			writel(phy_addr, chip->base + ACP_I2S_RX_RINGBUFADDR(chip));
238		}
239		break;
240	case I2S_BT_INSTANCE:
241		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
242			reg_dma_size = ACP_BT_TX_DMA_SIZE(chip);
243			acp_fifo_addr = rsrc->sram_pte_offset +
244					BT_PB_FIFO_ADDR_OFFSET;
245			reg_fifo_addr = ACP_BT_TX_FIFOADDR(chip);
246			reg_fifo_size = ACP_BT_TX_FIFOSIZE(chip);
247			if (chip->acp_rev >= ACP70_PCI_ID)
248				phy_addr = ACP7x_I2S_BT_TX_MEM_WINDOW_START;
249			else
250				phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
251			writel(phy_addr, chip->base + ACP_BT_TX_RINGBUFADDR(chip));
252		} else {
253			reg_dma_size = ACP_BT_RX_DMA_SIZE(chip);
254			acp_fifo_addr = rsrc->sram_pte_offset +
255					BT_CAPT_FIFO_ADDR_OFFSET;
256			reg_fifo_addr = ACP_BT_RX_FIFOADDR(chip);
257			reg_fifo_size = ACP_BT_RX_FIFOSIZE(chip);
258			if (chip->acp_rev >= ACP70_PCI_ID)
259				phy_addr = ACP7x_I2S_BT_RX_MEM_WINDOW_START;
260			else
261				phy_addr = I2S_BT_RX_MEM_WINDOW_START + stream->reg_offset;
262			writel(phy_addr, chip->base + ACP_BT_RX_RINGBUFADDR(chip));
263		}
264		break;
265	case I2S_HS_INSTANCE:
266		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
267			reg_dma_size = ACP_HS_TX_DMA_SIZE;
268			acp_fifo_addr = rsrc->sram_pte_offset +
269					HS_PB_FIFO_ADDR_OFFSET;
270			reg_fifo_addr = ACP_HS_TX_FIFOADDR;
271			reg_fifo_size = ACP_HS_TX_FIFOSIZE;
272			if (chip->acp_rev >= ACP70_PCI_ID)
273				phy_addr = ACP7x_I2S_HS_TX_MEM_WINDOW_START;
274			else
275				phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset;
276			writel(phy_addr, chip->base + ACP_HS_TX_RINGBUFADDR);
277		} else {
278			reg_dma_size = ACP_HS_RX_DMA_SIZE;
279			acp_fifo_addr = rsrc->sram_pte_offset +
280					HS_CAPT_FIFO_ADDR_OFFSET;
281			reg_fifo_addr = ACP_HS_RX_FIFOADDR;
282			reg_fifo_size = ACP_HS_RX_FIFOSIZE;
283			if (chip->acp_rev >= ACP70_PCI_ID)
284				phy_addr = ACP7x_I2S_HS_RX_MEM_WINDOW_START;
285			else
286				phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset;
287			writel(phy_addr, chip->base + ACP_HS_RX_RINGBUFADDR);
288		}
289		break;
290	default:
291		dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
292		return -EINVAL;
293	}
294
295	writel(DMA_SIZE, chip->base + reg_dma_size);
296	writel(acp_fifo_addr, chip->base + reg_fifo_addr);
297	writel(FIFO_SIZE, chip->base + reg_fifo_size);
298
299	ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(chip, rsrc->irqp_used));
300	ext_int_ctrl |= BIT(I2S_RX_THRESHOLD(rsrc->offset)) |
301			BIT(BT_RX_THRESHOLD(rsrc->offset)) |
302			BIT(I2S_TX_THRESHOLD(rsrc->offset)) |
303			BIT(BT_TX_THRESHOLD(rsrc->offset)) |
304			BIT(HS_RX_THRESHOLD(rsrc->offset)) |
305			BIT(HS_TX_THRESHOLD(rsrc->offset));
306
307	writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(chip, rsrc->irqp_used));
308	return 0;
309}
310
311int restore_acp_i2s_params(struct snd_pcm_substream *substream,
312			   struct acp_chip_info *chip,
313			   struct acp_stream *stream)
314{
315	struct snd_soc_dai *dai;
316	struct snd_soc_pcm_runtime *soc_runtime;
317	u32 tdm_fmt, reg_val, fmt_reg, val;
318
319	soc_runtime = snd_soc_substream_to_rtd(substream);
320	dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
321	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
322		tdm_fmt = chip->tdm_tx_fmt[stream->dai_id - 1];
323		switch (stream->dai_id) {
324		case I2S_BT_INSTANCE:
325			reg_val = ACP_BTTDM_ITER;
326			fmt_reg = ACP_BTTDM_TXFRMT;
327			break;
328		case I2S_SP_INSTANCE:
329			reg_val = ACP_I2STDM_ITER;
330			fmt_reg = ACP_I2STDM_TXFRMT;
331			break;
332		case I2S_HS_INSTANCE:
333			reg_val = ACP_HSTDM_ITER;
334			fmt_reg = ACP_HSTDM_TXFRMT;
335			break;
336		default:
337			pr_err("Invalid dai id %x\n", stream->dai_id);
338			return -EINVAL;
339		}
340		val = chip->xfer_tx_resolution[stream->dai_id - 1] << 3;
341	} else {
342		tdm_fmt = chip->tdm_rx_fmt[stream->dai_id - 1];
343		switch (stream->dai_id) {
344		case I2S_BT_INSTANCE:
345			reg_val = ACP_BTTDM_IRER;
346			fmt_reg = ACP_BTTDM_RXFRMT;
347			break;
348		case I2S_SP_INSTANCE:
349			reg_val = ACP_I2STDM_IRER;
350			fmt_reg = ACP_I2STDM_RXFRMT;
351			break;
352		case I2S_HS_INSTANCE:
353			reg_val = ACP_HSTDM_IRER;
354			fmt_reg = ACP_HSTDM_RXFRMT;
355			break;
356		default:
357			pr_err("Invalid dai id %x\n", stream->dai_id);
358			return -EINVAL;
359		}
360		val = chip->xfer_rx_resolution[stream->dai_id - 1] << 3;
361	}
362	writel(val, chip->base + reg_val);
363	if (chip->tdm_mode == TDM_ENABLE) {
364		writel(tdm_fmt, chip->base + fmt_reg);
365		val = readl(chip->base + reg_val);
366		writel(val | 0x2, chip->base + reg_val);
367	}
368	return set_acp_i2s_dma_fifo(substream, dai);
369}
370EXPORT_SYMBOL_NS_GPL(restore_acp_i2s_params, "SND_SOC_ACP_COMMON");
371
372static int acp_power_on(struct acp_chip_info *chip)
373{
374	u32 val, acp_pgfsm_stat_reg, acp_pgfsm_ctrl_reg;
375	void __iomem *base;
376
377	base = chip->base;
378	switch (chip->acp_rev) {
379	case ACP_RN_PCI_ID:
380		acp_pgfsm_stat_reg = ACP_PGFSM_STATUS;
381		acp_pgfsm_ctrl_reg = ACP_PGFSM_CONTROL;
382		break;
383	case ACP_RMB_PCI_ID:
384		acp_pgfsm_stat_reg = ACP6X_PGFSM_STATUS;
385		acp_pgfsm_ctrl_reg = ACP6X_PGFSM_CONTROL;
386		break;
387	case ACP63_PCI_ID:
388		acp_pgfsm_stat_reg = ACP63_PGFSM_STATUS;
389		acp_pgfsm_ctrl_reg = ACP63_PGFSM_CONTROL;
390		break;
391	case ACP70_PCI_ID:
392	case ACP71_PCI_ID:
393	case ACP72_PCI_ID:
394		acp_pgfsm_stat_reg = ACP70_PGFSM_STATUS;
395		acp_pgfsm_ctrl_reg = ACP70_PGFSM_CONTROL;
396		break;
397	default:
398		return -EINVAL;
399	}
400
401	val = readl(base + acp_pgfsm_stat_reg);
402	if (val == ACP_POWERED_ON)
403		return 0;
404
405	if ((val & ACP_PGFSM_STATUS_MASK) != ACP_POWER_ON_IN_PROGRESS)
406		writel(ACP_PGFSM_CNTL_POWER_ON_MASK, base + acp_pgfsm_ctrl_reg);
407
408	return readl_poll_timeout(base + acp_pgfsm_stat_reg, val,
409				  !val, DELAY_US, ACP_TIMEOUT);
410}
411
412static int acp_reset(void __iomem *base)
413{
414	u32 val;
415	int ret;
416
417	writel(1, base + ACP_SOFT_RESET);
418	ret = readl_poll_timeout(base + ACP_SOFT_RESET, val, val & ACP_SOFT_RST_DONE_MASK,
419				 DELAY_US, ACP_TIMEOUT);
420	if (ret)
421		return ret;
422
423	writel(0, base + ACP_SOFT_RESET);
424	return readl_poll_timeout(base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP_TIMEOUT);
425}
426
427int acp_init(struct acp_chip_info *chip)
428{
429	int ret;
430
431	/* power on */
432	ret = acp_power_on(chip);
433	if (ret) {
434		pr_err("ACP power on failed\n");
435		return ret;
436	}
437	writel(0x01, chip->base + ACP_CONTROL);
438
439	/* Reset */
440	ret = acp_reset(chip->base);
441	if (ret) {
442		pr_err("ACP reset failed\n");
443		return ret;
444	}
445	if (chip->acp_rev >= ACP70_PCI_ID)
446		writel(0, chip->base + ACP_ZSC_DSP_CTRL);
447	return 0;
448}
449EXPORT_SYMBOL_NS_GPL(acp_init, "SND_SOC_ACP_COMMON");
450
451int acp_deinit(struct acp_chip_info *chip)
452{
453	int ret;
454
455	/* Reset */
456	ret = acp_reset(chip->base);
457	if (ret)
458		return ret;
459
460	if (chip->acp_rev < ACP70_PCI_ID)
461		writel(0, chip->base + ACP_CONTROL);
462	else
463		writel(0x01, chip->base + ACP_ZSC_DSP_CTRL);
464	return 0;
465}
466EXPORT_SYMBOL_NS_GPL(acp_deinit, "SND_SOC_ACP_COMMON");
467int acp_machine_select(struct acp_chip_info *chip)
468{
469	struct snd_soc_acpi_mach *mach;
470	int size, platform;
471
472	if (chip->flag == FLAG_AMD_LEGACY_ONLY_DMIC && chip->is_pdm_dev) {
473		platform = chip->acp_rev;
474		chip->mach_dev = platform_device_register_data(chip->dev, "acp-pdm-mach",
475							       PLATFORM_DEVID_NONE, &platform,
476							       sizeof(platform));
477	} else {
478		size = sizeof(*chip->machines);
479		mach = snd_soc_acpi_find_machine(chip->machines);
480		if (!mach) {
481			dev_err(chip->dev, "warning: No matching ASoC machine driver found\n");
482			return -EINVAL;
483		}
484		mach->mach_params.subsystem_rev = chip->acp_rev;
485		chip->mach_dev = platform_device_register_data(chip->dev, mach->drv_name,
486							       PLATFORM_DEVID_NONE, mach, size);
487	}
488	if (IS_ERR(chip->mach_dev))
489		dev_warn(chip->dev, "Unable to register Machine device\n");
490	return 0;
491}
492EXPORT_SYMBOL_NS_GPL(acp_machine_select, "SND_SOC_ACP_COMMON");
493
494static void check_acp3x_config(struct acp_chip_info *chip)
495{
496	u32 val;
497
498	val = readl(chip->base + ACP3X_PIN_CONFIG);
499	switch (val) {
500	case ACP_CONFIG_4:
501		chip->is_i2s_config = true;
502		chip->is_pdm_config = true;
503		break;
504	default:
505		chip->is_pdm_config = true;
506		break;
507	}
508}
509
510static void check_acp6x_config(struct acp_chip_info *chip)
511{
512	u32 val;
513
514	val = readl(chip->base + ACP_PIN_CONFIG);
515	switch (val) {
516	case ACP_CONFIG_4:
517	case ACP_CONFIG_5:
518	case ACP_CONFIG_6:
519	case ACP_CONFIG_7:
520	case ACP_CONFIG_8:
521	case ACP_CONFIG_11:
522	case ACP_CONFIG_14:
523		chip->is_pdm_config = true;
524		break;
525	case ACP_CONFIG_9:
526		chip->is_i2s_config = true;
527		break;
528	case ACP_CONFIG_10:
529	case ACP_CONFIG_12:
530	case ACP_CONFIG_13:
531		chip->is_i2s_config = true;
532		chip->is_pdm_config = true;
533		break;
534	default:
535		break;
536	}
537}
538
539static void check_acp70_config(struct acp_chip_info *chip)
540{
541	u32 val;
542
543	val = readl(chip->base + ACP_PIN_CONFIG);
544	switch (val) {
545	case ACP_CONFIG_4:
546	case ACP_CONFIG_5:
547	case ACP_CONFIG_6:
548	case ACP_CONFIG_7:
549	case ACP_CONFIG_8:
550	case ACP_CONFIG_11:
551	case ACP_CONFIG_14:
552	case ACP_CONFIG_17:
553	case ACP_CONFIG_18:
554		chip->is_pdm_config = true;
555		break;
556	case ACP_CONFIG_9:
557		chip->is_i2s_config = true;
558		break;
559	case ACP_CONFIG_10:
560	case ACP_CONFIG_12:
561	case ACP_CONFIG_13:
562	case ACP_CONFIG_19:
563	case ACP_CONFIG_20:
564		chip->is_i2s_config = true;
565		chip->is_pdm_config = true;
566		break;
567	default:
568		break;
569	}
570}
571
572void check_acp_config(struct pci_dev *pci, struct acp_chip_info *chip)
573{
574	struct acpi_device *pdm_dev;
575	const union acpi_object *obj;
576	acpi_handle handle;
577	acpi_integer dmic_status;
578	u32 pdm_addr, ret;
579
580	switch (chip->acp_rev) {
581	case ACP_RN_PCI_ID:
582		pdm_addr = ACP_RENOIR_PDM_ADDR;
583		check_acp3x_config(chip);
584		break;
585	case ACP_RMB_PCI_ID:
586		pdm_addr = ACP_REMBRANDT_PDM_ADDR;
587		check_acp6x_config(chip);
588		break;
589	case ACP63_PCI_ID:
590		pdm_addr = ACP63_PDM_ADDR;
591		check_acp6x_config(chip);
592		break;
593	case ACP70_PCI_ID:
594	case ACP71_PCI_ID:
595	case ACP72_PCI_ID:
596		pdm_addr = ACP70_PDM_ADDR;
597		check_acp70_config(chip);
598		break;
599	default:
600		break;
601	}
602
603	if (chip->is_pdm_config) {
604		pdm_dev = acpi_find_child_device(ACPI_COMPANION(&pci->dev), pdm_addr, 0);
605		if (pdm_dev) {
606			if (!acpi_dev_get_property(pdm_dev, "acp-audio-device-type",
607						   ACPI_TYPE_INTEGER, &obj) &&
608						   obj->integer.value == pdm_addr)
609				chip->is_pdm_dev = true;
610		}
611
612		handle = ACPI_HANDLE(&pci->dev);
613		ret = acpi_evaluate_integer(handle, "_WOV", NULL, &dmic_status);
614		if (!ACPI_FAILURE(ret))
615			chip->is_pdm_dev = dmic_status;
616	}
617}
618EXPORT_SYMBOL_NS_GPL(check_acp_config, "SND_SOC_ACP_COMMON");
619
620struct snd_acp_hw_ops acp31_common_hw_ops;
621EXPORT_SYMBOL_NS_GPL(acp31_common_hw_ops, "SND_SOC_ACP_COMMON");
622int acp31_hw_ops_init(struct acp_chip_info *chip)
623{
624	memcpy(&acp31_common_hw_ops, &acp_common_hw_ops, sizeof(acp_common_hw_ops));
625	chip->acp_hw_ops = &acp31_common_hw_ops;
626
627	return 0;
628}
629EXPORT_SYMBOL_NS_GPL(acp31_hw_ops_init, "SND_SOC_ACP_COMMON");
630
631struct snd_acp_hw_ops acp6x_common_hw_ops;
632EXPORT_SYMBOL_NS_GPL(acp6x_common_hw_ops, "SND_SOC_ACP_COMMON");
633int acp6x_hw_ops_init(struct acp_chip_info *chip)
634{
635	memcpy(&acp6x_common_hw_ops, &acp_common_hw_ops, sizeof(acp_common_hw_ops));
636	chip->acp_hw_ops = &acp6x_common_hw_ops;
637
638	return 0;
639}
640EXPORT_SYMBOL_NS_GPL(acp6x_hw_ops_init, "SND_SOC_ACP_COMMON");
641
642struct snd_acp_hw_ops acp63_common_hw_ops;
643EXPORT_SYMBOL_NS_GPL(acp63_common_hw_ops, "SND_SOC_ACP_COMMON");
644int acp63_hw_ops_init(struct acp_chip_info *chip)
645{
646	memcpy(&acp63_common_hw_ops, &acp_common_hw_ops, sizeof(acp_common_hw_ops));
647	chip->acp_hw_ops = &acp63_common_hw_ops;
648
649	return 0;
650}
651EXPORT_SYMBOL_NS_GPL(acp63_hw_ops_init, "SND_SOC_ACP_COMMON");
652
653struct snd_acp_hw_ops acp70_common_hw_ops;
654EXPORT_SYMBOL_NS_GPL(acp70_common_hw_ops, "SND_SOC_ACP_COMMON");
655int acp70_hw_ops_init(struct acp_chip_info *chip)
656{
657	memcpy(&acp70_common_hw_ops, &acp_common_hw_ops, sizeof(acp_common_hw_ops));
658	chip->acp_hw_ops = &acp70_common_hw_ops;
659
660	return 0;
661}
662EXPORT_SYMBOL_NS_GPL(acp70_hw_ops_init, "SND_SOC_ACP_COMMON");
663
664MODULE_DESCRIPTION("AMD ACP legacy common features");
665MODULE_LICENSE("Dual BSD/GPL");
~/ Read-only file preview.