brintos

brintos / linux-shallow public Read only

0
0
Text · 13.2 KiB · be01b17 Raw
486 lines · 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 or4// 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 platforms13 */14 15#include "amd.h"16#include <linux/pci.h>17#include <linux/export.h>18 19#define ACP_RENOIR_PDM_ADDR	0x0220#define ACP_REMBRANDT_PDM_ADDR	0x0321#define ACP63_PDM_ADDR		0x0222#define ACP70_PDM_ADDR		0x0223 24void acp_enable_interrupts(struct acp_dev_data *adata)25{26	struct acp_resource *rsrc = adata->rsrc;27	u32 ext_intr_ctrl;28 29	writel(0x01, ACP_EXTERNAL_INTR_ENB(adata));30	ext_intr_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));31	ext_intr_ctrl |= ACP_ERROR_MASK;32	writel(ext_intr_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));33}34EXPORT_SYMBOL_NS_GPL(acp_enable_interrupts, SND_SOC_ACP_COMMON);35 36void acp_disable_interrupts(struct acp_dev_data *adata)37{38	struct acp_resource *rsrc = adata->rsrc;39 40	writel(ACP_EXT_INTR_STAT_CLEAR_MASK, ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used));41	writel(0x00, ACP_EXTERNAL_INTR_ENB(adata));42}43EXPORT_SYMBOL_NS_GPL(acp_disable_interrupts, SND_SOC_ACP_COMMON);44 45static void set_acp_pdm_ring_buffer(struct snd_pcm_substream *substream,46				    struct snd_soc_dai *dai)47{48	struct snd_pcm_runtime *runtime = substream->runtime;49	struct acp_stream *stream = runtime->private_data;50	struct device *dev = dai->component->dev;51	struct acp_dev_data *adata = dev_get_drvdata(dev);52 53	u32 physical_addr, pdm_size, period_bytes;54 55	period_bytes = frames_to_bytes(runtime, runtime->period_size);56	pdm_size = frames_to_bytes(runtime, runtime->buffer_size);57	physical_addr = stream->reg_offset + MEM_WINDOW_START;58 59	/* Init ACP PDM Ring buffer */60	writel(physical_addr, adata->acp_base + ACP_WOV_RX_RINGBUFADDR);61	writel(pdm_size, adata->acp_base + ACP_WOV_RX_RINGBUFSIZE);62	writel(period_bytes, adata->acp_base + ACP_WOV_RX_INTR_WATERMARK_SIZE);63	writel(0x01, adata->acp_base + ACPAXI2AXI_ATU_CTRL);64}65 66static void set_acp_pdm_clk(struct snd_pcm_substream *substream,67			    struct snd_soc_dai *dai)68{69	struct device *dev = dai->component->dev;70	struct acp_dev_data *adata = dev_get_drvdata(dev);71	unsigned int pdm_ctrl;72 73	/* Enable default ACP PDM clk */74	writel(PDM_CLK_FREQ_MASK, adata->acp_base + ACP_WOV_CLK_CTRL);75	pdm_ctrl = readl(adata->acp_base + ACP_WOV_MISC_CTRL);76	pdm_ctrl |= PDM_MISC_CTRL_MASK;77	writel(pdm_ctrl, adata->acp_base + ACP_WOV_MISC_CTRL);78	set_acp_pdm_ring_buffer(substream, dai);79}80 81void restore_acp_pdm_params(struct snd_pcm_substream *substream,82			    struct acp_dev_data *adata)83{84	struct snd_soc_dai *dai;85	struct snd_soc_pcm_runtime *soc_runtime;86	u32 ext_int_ctrl;87 88	soc_runtime = snd_soc_substream_to_rtd(substream);89	dai = snd_soc_rtd_to_cpu(soc_runtime, 0);90	/* Programming channel mask and sampling rate */91	writel(adata->ch_mask, adata->acp_base + ACP_WOV_PDM_NO_OF_CHANNELS);92	writel(PDM_DEC_64, adata->acp_base + ACP_WOV_PDM_DECIMATION_FACTOR);93 94	/* Enabling ACP Pdm interuppts */95	ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, 0));96	ext_int_ctrl |= PDM_DMA_INTR_MASK;97	writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, 0));98	set_acp_pdm_clk(substream, dai);99}100EXPORT_SYMBOL_NS_GPL(restore_acp_pdm_params, SND_SOC_ACP_COMMON);101 102static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream,103				struct snd_soc_dai *dai)104{105	struct device *dev = dai->component->dev;106	struct acp_dev_data *adata = dev_get_drvdata(dev);107	struct acp_resource *rsrc = adata->rsrc;108	struct acp_stream *stream = substream->runtime->private_data;109	u32 reg_dma_size, reg_fifo_size, reg_fifo_addr;110	u32 phy_addr, acp_fifo_addr, ext_int_ctrl;111	unsigned int dir = substream->stream;112 113	switch (dai->driver->id) {114	case I2S_SP_INSTANCE:115		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {116			reg_dma_size = ACP_I2S_TX_DMA_SIZE(adata);117			acp_fifo_addr = rsrc->sram_pte_offset +118					SP_PB_FIFO_ADDR_OFFSET;119			reg_fifo_addr = ACP_I2S_TX_FIFOADDR(adata);120			reg_fifo_size = ACP_I2S_TX_FIFOSIZE(adata);121			phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset;122			writel(phy_addr, adata->acp_base + ACP_I2S_TX_RINGBUFADDR(adata));123		} else {124			reg_dma_size = ACP_I2S_RX_DMA_SIZE(adata);125			acp_fifo_addr = rsrc->sram_pte_offset +126					SP_CAPT_FIFO_ADDR_OFFSET;127			reg_fifo_addr = ACP_I2S_RX_FIFOADDR(adata);128			reg_fifo_size = ACP_I2S_RX_FIFOSIZE(adata);129			phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset;130			writel(phy_addr, adata->acp_base + ACP_I2S_RX_RINGBUFADDR(adata));131		}132		break;133	case I2S_BT_INSTANCE:134		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {135			reg_dma_size = ACP_BT_TX_DMA_SIZE(adata);136			acp_fifo_addr = rsrc->sram_pte_offset +137					BT_PB_FIFO_ADDR_OFFSET;138			reg_fifo_addr = ACP_BT_TX_FIFOADDR(adata);139			reg_fifo_size = ACP_BT_TX_FIFOSIZE(adata);140			phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;141			writel(phy_addr, adata->acp_base + ACP_BT_TX_RINGBUFADDR(adata));142		} else {143			reg_dma_size = ACP_BT_RX_DMA_SIZE(adata);144			acp_fifo_addr = rsrc->sram_pte_offset +145					BT_CAPT_FIFO_ADDR_OFFSET;146			reg_fifo_addr = ACP_BT_RX_FIFOADDR(adata);147			reg_fifo_size = ACP_BT_RX_FIFOSIZE(adata);148			phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;149			writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR(adata));150		}151		break;152	case I2S_HS_INSTANCE:153		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {154			reg_dma_size = ACP_HS_TX_DMA_SIZE;155			acp_fifo_addr = rsrc->sram_pte_offset +156					HS_PB_FIFO_ADDR_OFFSET;157			reg_fifo_addr = ACP_HS_TX_FIFOADDR;158			reg_fifo_size = ACP_HS_TX_FIFOSIZE;159			phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset;160			writel(phy_addr, adata->acp_base + ACP_HS_TX_RINGBUFADDR);161		} else {162			reg_dma_size = ACP_HS_RX_DMA_SIZE;163			acp_fifo_addr = rsrc->sram_pte_offset +164					HS_CAPT_FIFO_ADDR_OFFSET;165			reg_fifo_addr = ACP_HS_RX_FIFOADDR;166			reg_fifo_size = ACP_HS_RX_FIFOSIZE;167			phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset;168			writel(phy_addr, adata->acp_base + ACP_HS_RX_RINGBUFADDR);169		}170		break;171	default:172		dev_err(dev, "Invalid dai id %x\n", dai->driver->id);173		return -EINVAL;174	}175 176	writel(DMA_SIZE, adata->acp_base + reg_dma_size);177	writel(acp_fifo_addr, adata->acp_base + reg_fifo_addr);178	writel(FIFO_SIZE, adata->acp_base + reg_fifo_size);179 180	ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));181	ext_int_ctrl |= BIT(I2S_RX_THRESHOLD(rsrc->offset)) |182			BIT(BT_RX_THRESHOLD(rsrc->offset)) |183			BIT(I2S_TX_THRESHOLD(rsrc->offset)) |184			BIT(BT_TX_THRESHOLD(rsrc->offset)) |185			BIT(HS_RX_THRESHOLD(rsrc->offset)) |186			BIT(HS_TX_THRESHOLD(rsrc->offset));187 188	writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));189	return 0;190}191 192int restore_acp_i2s_params(struct snd_pcm_substream *substream,193			   struct acp_dev_data *adata,194			   struct acp_stream *stream)195{196	struct snd_soc_dai *dai;197	struct snd_soc_pcm_runtime *soc_runtime;198	u32 tdm_fmt, reg_val, fmt_reg, val;199 200	soc_runtime = snd_soc_substream_to_rtd(substream);201	dai = snd_soc_rtd_to_cpu(soc_runtime, 0);202	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {203		tdm_fmt = adata->tdm_tx_fmt[stream->dai_id - 1];204		switch (stream->dai_id) {205		case I2S_BT_INSTANCE:206			reg_val = ACP_BTTDM_ITER;207			fmt_reg = ACP_BTTDM_TXFRMT;208			break;209		case I2S_SP_INSTANCE:210			reg_val = ACP_I2STDM_ITER;211			fmt_reg = ACP_I2STDM_TXFRMT;212			break;213		case I2S_HS_INSTANCE:214			reg_val = ACP_HSTDM_ITER;215			fmt_reg = ACP_HSTDM_TXFRMT;216			break;217		default:218			pr_err("Invalid dai id %x\n", stream->dai_id);219			return -EINVAL;220		}221		val = adata->xfer_tx_resolution[stream->dai_id - 1] << 3;222	} else {223		tdm_fmt = adata->tdm_rx_fmt[stream->dai_id - 1];224		switch (stream->dai_id) {225		case I2S_BT_INSTANCE:226			reg_val = ACP_BTTDM_IRER;227			fmt_reg = ACP_BTTDM_RXFRMT;228			break;229		case I2S_SP_INSTANCE:230			reg_val = ACP_I2STDM_IRER;231			fmt_reg = ACP_I2STDM_RXFRMT;232			break;233		case I2S_HS_INSTANCE:234			reg_val = ACP_HSTDM_IRER;235			fmt_reg = ACP_HSTDM_RXFRMT;236			break;237		default:238			pr_err("Invalid dai id %x\n", stream->dai_id);239			return -EINVAL;240		}241		val = adata->xfer_rx_resolution[stream->dai_id - 1] << 3;242	}243	writel(val, adata->acp_base + reg_val);244	if (adata->tdm_mode == TDM_ENABLE) {245		writel(tdm_fmt, adata->acp_base + fmt_reg);246		val = readl(adata->acp_base + reg_val);247		writel(val | 0x2, adata->acp_base + reg_val);248	}249	return set_acp_i2s_dma_fifo(substream, dai);250}251EXPORT_SYMBOL_NS_GPL(restore_acp_i2s_params, SND_SOC_ACP_COMMON);252 253static int acp_power_on(struct acp_chip_info *chip)254{255	u32 val, acp_pgfsm_stat_reg, acp_pgfsm_ctrl_reg;256	void __iomem *base;257 258	base = chip->base;259	switch (chip->acp_rev) {260	case ACP3X_DEV:261		acp_pgfsm_stat_reg = ACP_PGFSM_STATUS;262		acp_pgfsm_ctrl_reg = ACP_PGFSM_CONTROL;263		break;264	case ACP6X_DEV:265		acp_pgfsm_stat_reg = ACP6X_PGFSM_STATUS;266		acp_pgfsm_ctrl_reg = ACP6X_PGFSM_CONTROL;267		break;268	case ACP63_DEV:269		acp_pgfsm_stat_reg = ACP63_PGFSM_STATUS;270		acp_pgfsm_ctrl_reg = ACP63_PGFSM_CONTROL;271		break;272	case ACP70_DEV:273	case ACP71_DEV:274		acp_pgfsm_stat_reg = ACP70_PGFSM_STATUS;275		acp_pgfsm_ctrl_reg = ACP70_PGFSM_CONTROL;276		break;277	default:278		return -EINVAL;279	}280 281	val = readl(base + acp_pgfsm_stat_reg);282	if (val == ACP_POWERED_ON)283		return 0;284 285	if ((val & ACP_PGFSM_STATUS_MASK) != ACP_POWER_ON_IN_PROGRESS)286		writel(ACP_PGFSM_CNTL_POWER_ON_MASK, base + acp_pgfsm_ctrl_reg);287 288	return readl_poll_timeout(base + acp_pgfsm_stat_reg, val,289				  !val, DELAY_US, ACP_TIMEOUT);290}291 292static int acp_reset(void __iomem *base)293{294	u32 val;295	int ret;296 297	writel(1, base + ACP_SOFT_RESET);298	ret = readl_poll_timeout(base + ACP_SOFT_RESET, val, val & ACP_SOFT_RST_DONE_MASK,299				 DELAY_US, ACP_TIMEOUT);300	if (ret)301		return ret;302 303	writel(0, base + ACP_SOFT_RESET);304	return readl_poll_timeout(base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP_TIMEOUT);305}306 307int acp_init(struct acp_chip_info *chip)308{309	int ret;310 311	/* power on */312	ret = acp_power_on(chip);313	if (ret) {314		pr_err("ACP power on failed\n");315		return ret;316	}317	writel(0x01, chip->base + ACP_CONTROL);318 319	/* Reset */320	ret = acp_reset(chip->base);321	if (ret) {322		pr_err("ACP reset failed\n");323		return ret;324	}325	if (chip->acp_rev >= ACP70_DEV)326		writel(0, chip->base + ACP_ZSC_DSP_CTRL);327	return 0;328}329EXPORT_SYMBOL_NS_GPL(acp_init, SND_SOC_ACP_COMMON);330 331int acp_deinit(struct acp_chip_info *chip)332{333	int ret;334 335	/* Reset */336	ret = acp_reset(chip->base);337	if (ret)338		return ret;339 340	if (chip->acp_rev < ACP70_DEV)341		writel(0, chip->base + ACP_CONTROL);342	else343		writel(0x01, chip->base + ACP_ZSC_DSP_CTRL);344	return 0;345}346EXPORT_SYMBOL_NS_GPL(acp_deinit, SND_SOC_ACP_COMMON);347 348int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data)349{350	pci_write_config_dword(dev, 0x60, smn_addr);351	pci_write_config_dword(dev, 0x64, data);352	return 0;353}354EXPORT_SYMBOL_NS_GPL(smn_write, SND_SOC_ACP_COMMON);355 356int smn_read(struct pci_dev *dev, u32 smn_addr)357{358	u32 data;359 360	pci_write_config_dword(dev, 0x60, smn_addr);361	pci_read_config_dword(dev, 0x64, &data);362	return data;363}364EXPORT_SYMBOL_NS_GPL(smn_read, SND_SOC_ACP_COMMON);365 366static void check_acp3x_config(struct acp_chip_info *chip)367{368	u32 val;369 370	val = readl(chip->base + ACP3X_PIN_CONFIG);371	switch (val) {372	case ACP_CONFIG_4:373		chip->is_i2s_config = true;374		chip->is_pdm_config = true;375		break;376	default:377		chip->is_pdm_config = true;378		break;379	}380}381 382static void check_acp6x_config(struct acp_chip_info *chip)383{384	u32 val;385 386	val = readl(chip->base + ACP_PIN_CONFIG);387	switch (val) {388	case ACP_CONFIG_4:389	case ACP_CONFIG_5:390	case ACP_CONFIG_6:391	case ACP_CONFIG_7:392	case ACP_CONFIG_8:393	case ACP_CONFIG_11:394	case ACP_CONFIG_14:395		chip->is_pdm_config = true;396		break;397	case ACP_CONFIG_9:398		chip->is_i2s_config = true;399		break;400	case ACP_CONFIG_10:401	case ACP_CONFIG_12:402	case ACP_CONFIG_13:403		chip->is_i2s_config = true;404		chip->is_pdm_config = true;405		break;406	default:407		break;408	}409}410 411static void check_acp70_config(struct acp_chip_info *chip)412{413	u32 val;414 415	val = readl(chip->base + ACP_PIN_CONFIG);416	switch (val) {417	case ACP_CONFIG_4:418	case ACP_CONFIG_5:419	case ACP_CONFIG_6:420	case ACP_CONFIG_7:421	case ACP_CONFIG_8:422	case ACP_CONFIG_11:423	case ACP_CONFIG_14:424	case ACP_CONFIG_17:425	case ACP_CONFIG_18:426		chip->is_pdm_config = true;427		break;428	case ACP_CONFIG_9:429		chip->is_i2s_config = true;430		break;431	case ACP_CONFIG_10:432	case ACP_CONFIG_12:433	case ACP_CONFIG_13:434	case ACP_CONFIG_19:435	case ACP_CONFIG_20:436		chip->is_i2s_config = true;437		chip->is_pdm_config = true;438		break;439	default:440		break;441	}442}443 444void check_acp_config(struct pci_dev *pci, struct acp_chip_info *chip)445{446	struct acpi_device *pdm_dev;447	const union acpi_object *obj;448	u32 pdm_addr;449 450	switch (chip->acp_rev) {451	case ACP3X_DEV:452		pdm_addr = ACP_RENOIR_PDM_ADDR;453		check_acp3x_config(chip);454		break;455	case ACP6X_DEV:456		pdm_addr = ACP_REMBRANDT_PDM_ADDR;457		check_acp6x_config(chip);458		break;459	case ACP63_DEV:460		pdm_addr = ACP63_PDM_ADDR;461		check_acp6x_config(chip);462		break;463	case ACP70_DEV:464	case ACP71_DEV:465		pdm_addr = ACP70_PDM_ADDR;466		check_acp70_config(chip);467		break;468	default:469		break;470	}471 472	if (chip->is_pdm_config) {473		pdm_dev = acpi_find_child_device(ACPI_COMPANION(&pci->dev), pdm_addr, 0);474		if (pdm_dev) {475			if (!acpi_dev_get_property(pdm_dev, "acp-audio-device-type",476						   ACPI_TYPE_INTEGER, &obj) &&477						   obj->integer.value == pdm_addr)478				chip->is_pdm_dev = true;479		}480	}481}482EXPORT_SYMBOL_NS_GPL(check_acp_config, SND_SOC_ACP_COMMON);483 484MODULE_DESCRIPTION("AMD ACP legacy common features");485MODULE_LICENSE("Dual BSD/GPL");486