Unverified Commit f13b349e authored by Shengjiu Wang's avatar Shengjiu Wang Committed by Mark Brown
Browse files

ASoC: fsl_xcvr: Add support for i.MX95 platform



On i.MX95, the XCVR uses a new PLL in the PHY, which is
General Purpose (GP) PLL. Add GP PLL configuration support
in the driver and add the 'pll_ver' flag to distinguish
different PLL on different platforms.

The XCVR also use PHY but limited for SPDIF only case
Add 'use_phy' flag to distinguish these platforms.

When there are 'pll8k' and 'pll11k' clock existing, the clock
source of 'phy_clk' can be changed for different sample rate
requirement.

Signed-off-by: default avatarShengjiu Wang <shengjiu.wang@nxp.com>
Reviewed-by: default avatarChancel Liu <chancel.liu@nxp.com>
Link: https://msgid.link/r/1716972002-2315-3-git-send-email-shengjiu.wang@nxp.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent fc127733
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -103,6 +103,7 @@ config SND_SOC_FSL_XCVR
	select REGMAP_MMIO
	select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n
	select SND_SOC_GENERIC_DMAENGINE_PCM
	select SND_SOC_FSL_UTILS
	help
	  Say Y if you want to add Audio Transceiver (XCVR) support for NXP
	  iMX CPUs. XCVR is a digital module that supports HDMI2.1 eARC,
+85 −43
Original line number Diff line number Diff line
@@ -15,14 +15,22 @@
#include <sound/pcm_params.h>

#include "fsl_xcvr.h"
#include "fsl_utils.h"
#include "imx-pcm.h"

#define FSL_XCVR_CAPDS_SIZE	256

enum fsl_xcvr_pll_verison {
	PLL_MX8MP,
	PLL_MX95,
};

struct fsl_xcvr_soc_data {
	const char *fw_name;
	bool spdif_only;
	bool use_edma;
	bool use_phy;
	enum fsl_xcvr_pll_verison pll_ver;
};

struct fsl_xcvr {
@@ -33,6 +41,8 @@ struct fsl_xcvr {
	struct clk *pll_ipg_clk;
	struct clk *phy_clk;
	struct clk *spba_clk;
	struct clk *pll8k_clk;
	struct clk *pll11k_clk;
	struct reset_control *reset;
	u8 streams;
	u32 mode;
@@ -262,10 +272,10 @@ static int fsl_xcvr_ai_write(struct fsl_xcvr *xcvr, u8 reg, u32 data, bool phy)
static int fsl_xcvr_en_phy_pll(struct fsl_xcvr *xcvr, u32 freq, bool tx)
{
	struct device *dev = &xcvr->pdev->dev;
	u32 i, div = 0, log2;
	u32 i, div = 0, log2, val;
	int ret;

	if (xcvr->soc_data->spdif_only)
	if (!xcvr->soc_data->use_phy)
		return 0;

	for (i = 0; i < ARRAY_SIZE(fsl_xcvr_pll_cfg); i++) {
@@ -288,6 +298,8 @@ static int fsl_xcvr_en_phy_pll(struct fsl_xcvr *xcvr, u32 freq, bool tx)
		return ret;
	}

	switch (xcvr->soc_data->pll_ver) {
	case PLL_MX8MP:
		/* PLL: BANDGAP_SET: EN_VBG (enable bandgap) */
		fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_BANDGAP_SET,
				  FSL_XCVR_PLL_BANDGAP_EN_VBG, 0);
@@ -328,6 +340,21 @@ static int fsl_xcvr_en_phy_pll(struct fsl_xcvr *xcvr, u32 freq, bool tx)
			fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET,
					  FSL_XCVR_PLL_CTRL0_CM2_EN, 0);
		}
		break;
	case PLL_MX95:
		val = fsl_xcvr_pll_cfg[i].mfi << FSL_XCVR_GP_PLL_DIV_MFI_SHIFT | div;
		fsl_xcvr_ai_write(xcvr, FSL_XCVR_GP_PLL_DIV, val, 0);
		val = fsl_xcvr_pll_cfg[i].mfn << FSL_XCVR_GP_PLL_NUMERATOR_MFN_SHIFT;
		fsl_xcvr_ai_write(xcvr, FSL_XCVR_GP_PLL_NUMERATOR, val, 0);
		fsl_xcvr_ai_write(xcvr, FSL_XCVR_GP_PLL_DENOMINATOR,
				  fsl_xcvr_pll_cfg[i].mfd, 0);
		val = FSL_XCVR_GP_PLL_CTRL_POWERUP | FSL_XCVR_GP_PLL_CTRL_CLKMUX_EN;
		fsl_xcvr_ai_write(xcvr, FSL_XCVR_GP_PLL_CTRL, val, 0);
		break;
	default:
		dev_err(dev, "Error for PLL version %d\n", xcvr->soc_data->pll_ver);
		return -EINVAL;
	}

	if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC mode */
		/* PHY: CTRL_SET: TX_DIFF_OE, PHY_EN */
@@ -362,6 +389,8 @@ static int fsl_xcvr_en_aud_pll(struct fsl_xcvr *xcvr, u32 freq)

	freq = xcvr->soc_data->spdif_only ? freq / 5 : freq;
	clk_disable_unprepare(xcvr->phy_clk);
	fsl_asoc_reparent_pll_clocks(dev, xcvr->phy_clk,
				     xcvr->pll8k_clk, xcvr->pll11k_clk, freq);
	ret = clk_set_rate(xcvr->phy_clk, freq);
	if (ret < 0) {
		dev_err(dev, "Error while setting AUD PLL rate: %d\n", ret);
@@ -373,7 +402,7 @@ static int fsl_xcvr_en_aud_pll(struct fsl_xcvr *xcvr, u32 freq)
		return ret;
	}

	if (xcvr->soc_data->spdif_only)
	if (!xcvr->soc_data->use_phy)
		return 0;
	/* Release AI interface from reset */
	ret = regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET,
@@ -1017,7 +1046,7 @@ static bool fsl_xcvr_readable_reg(struct device *dev, unsigned int reg)
{
	struct fsl_xcvr *xcvr = dev_get_drvdata(dev);

	if (xcvr->soc_data->spdif_only)
	if (!xcvr->soc_data->use_phy)
		if ((reg >= FSL_XCVR_IER && reg <= FSL_XCVR_PHY_AI_RDATA) ||
		    reg > FSL_XCVR_TX_DPTH_BCRR)
			return false;
@@ -1090,7 +1119,7 @@ static bool fsl_xcvr_writeable_reg(struct device *dev, unsigned int reg)
{
	struct fsl_xcvr *xcvr = dev_get_drvdata(dev);

	if (xcvr->soc_data->spdif_only)
	if (!xcvr->soc_data->use_phy)
		if (reg >= FSL_XCVR_IER && reg <= FSL_XCVR_PHY_AI_RDATA)
			return false;
	switch (reg) {
@@ -1234,6 +1263,8 @@ static irqreturn_t irq0_isr(int irq, void *devid)

static const struct fsl_xcvr_soc_data fsl_xcvr_imx8mp_data = {
	.fw_name = "imx/xcvr/xcvr-imx8mp.bin",
	.use_phy = true,
	.pll_ver = PLL_MX8MP,
};

static const struct fsl_xcvr_soc_data fsl_xcvr_imx93_data = {
@@ -1241,9 +1272,17 @@ static const struct fsl_xcvr_soc_data fsl_xcvr_imx93_data = {
	.use_edma = true,
};

static const struct fsl_xcvr_soc_data fsl_xcvr_imx95_data = {
	.spdif_only = true,
	.use_phy = true,
	.use_edma = true,
	.pll_ver = PLL_MX95,
};

static const struct of_device_id fsl_xcvr_dt_ids[] = {
	{ .compatible = "fsl,imx8mp-xcvr", .data = &fsl_xcvr_imx8mp_data },
	{ .compatible = "fsl,imx93-xcvr", .data = &fsl_xcvr_imx93_data},
	{ .compatible = "fsl,imx95-xcvr", .data = &fsl_xcvr_imx95_data},
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, fsl_xcvr_dt_ids);
@@ -1287,6 +1326,9 @@ static int fsl_xcvr_probe(struct platform_device *pdev)
		return PTR_ERR(xcvr->pll_ipg_clk);
	}

	fsl_asoc_get_pll_clocks(dev, &xcvr->pll8k_clk,
				&xcvr->pll11k_clk);

	xcvr->ram_addr = devm_platform_ioremap_resource_byname(pdev, "ram");
	if (IS_ERR(xcvr->ram_addr))
		return PTR_ERR(xcvr->ram_addr);
+91 −0
Original line number Diff line number Diff line
@@ -291,4 +291,95 @@
#define FSL_XCVR_RX_CS_BUFF_1		0xA0 /* Second RX CS buffer */
#define FSL_XCVR_CAP_DATA_STR		0x300 /* Capabilities data structure */

/* GP PLL Registers */
#define FSL_XCVR_GP_PLL_CTRL			0x00
#define FSL_XCVR_GP_PLL_CTRL_SET		0x04
#define FSL_XCVR_GP_PLL_CTRL_CLR		0x08
#define FSL_XCVR_GP_PLL_CTRL_TOG		0x0C
#define FSL_XCVR_GP_PLL_ANA_PRG			0x10
#define FSL_XCVR_GP_PLL_ANA_PRG_SET		0x14
#define FSL_XCVR_GP_PLL_ANA_PRG_CLR		0x18
#define FSL_XCVR_GP_PLL_ANA_PRG_TOG		0x1C
#define FSL_XCVR_GP_PLL_TEST			0x20
#define FSL_XCVR_GP_PLL_TEST_SET		0x24
#define FSL_XCVR_GP_PLL_TEST_CLR		0x28
#define FSL_XCVR_GP_PLL_TEST_TOG		0x2C
#define FSL_XCVR_GP_PLL_SPREAD_SPECTRUM		0x30
#define FSL_XCVR_GP_PLL_SPREAD_SPECTRUM_SET	0x34
#define FSL_XCVR_GP_PLL_SPREAD_SPECTRUM_CLR	0x38
#define FSL_XCVR_GP_PLL_SPREAD_SPECTRUM_TOG	0x3C
#define FSL_XCVR_GP_PLL_NUMERATOR		0x40
#define FSL_XCVR_GP_PLL_NUMERATOR_SET		0x44
#define FSL_XCVR_GP_PLL_NUMERATOR_CLR		0x48
#define FSL_XCVR_GP_PLL_NUMERATOR_TOG		0x4C
#define FSL_XCVR_GP_PLL_DENOMINATOR		0x50
#define FSL_XCVR_GP_PLL_DENOMINATOR_SET		0x54
#define FSL_XCVR_GP_PLL_DENOMINATOR_CLR		0x58
#define FSL_XCVR_GP_PLL_DENOMINATOR_TOG		0x5C
#define FSL_XCVR_GP_PLL_DIV			0x60
#define FSL_XCVR_GP_PLL_DIV_SET			0x64
#define FSL_XCVR_GP_PLL_DIV_CLR			0x68
#define FSL_XCVR_GP_PLL_DIV_TOG			0x6C
#define FSL_XCVR_GP_PLL_DFS_CTRL0		0x70
#define FSL_XCVR_GP_PLL_DFS_CTRL0_SET		0x74
#define FSL_XCVR_GP_PLL_DFS_CTRL0_CLR		0x78
#define FSL_XCVR_GP_PLL_DFS_CTRL0_TOG		0x7C
#define FSL_XCVR_GP_PLL_DFS_DIV0		0x80
#define FSL_XCVR_GP_PLL_DFS_DIV0_SET		0x84
#define FSL_XCVR_GP_PLL_DFS_DIV0_CLR		0x88
#define FSL_XCVR_GP_PLL_DFS_DIV0_TOG		0x8C
#define FSL_XCVR_GP_PLL_DFS_CTRL1		0x90
#define FSL_XCVR_GP_PLL_DFS_CTRL1_SET		0x94
#define FSL_XCVR_GP_PLL_DFS_CTRL1_CLR		0x98
#define FSL_XCVR_GP_PLL_DFS_CTRL1_TOG		0x9C
#define FSL_XCVR_GP_PLL_DFS_DIV1		0xA0
#define FSL_XCVR_GP_PLL_DFS_DIV1_SET		0xA4
#define FSL_XCVR_GP_PLL_DFS_DIV1_CLR		0xA8
#define FSL_XCVR_GP_PLL_DFS_DIV1_TOG		0xAC
#define FSL_XCVR_GP_PLL_DFS_CTRL2		0xB0
#define FSL_XCVR_GP_PLL_DFS_CTRL2_SET		0xB4
#define FSL_XCVR_GP_PLL_DFS_CTRL2_CLR		0xB8
#define FSL_XCVR_GP_PLL_DFS_CTRL2_TOG		0xBC
#define FSL_XCVR_GP_PLL_DFS_DIV2		0xC0
#define FSL_XCVR_GP_PLL_DFS_DIV2_SET		0xC4
#define FSL_XCVR_GP_PLL_DFS_DIV2_CLR		0xC8
#define FSL_XCVR_GP_PLL_DFS_DIV2_TOG		0xCC
#define FSL_XCVR_GP_PLL_DFS_CTRL3		0xD0
#define FSL_XCVR_GP_PLL_DFS_CTRL3_SET		0xD4
#define FSL_XCVR_GP_PLL_DFS_CTRL3_CLR		0xD8
#define FSL_XCVR_GP_PLL_DFS_CTRL3_TOG		0xDC
#define FSL_XCVR_GP_PLL_DFS_DIV3		0xE0
#define FSL_XCVR_GP_PLL_DFS_DIV3_SET		0xE4
#define FSL_XCVR_GP_PLL_DFS_DIV3_CLR		0xE8
#define FSL_XCVR_GP_PLL_DFS_DIV3_TOG		0xEC
#define FSL_XCVR_GP_PLL_STATUS			0xF0
#define FSL_XCVR_GP_PLL_STATUS_SET		0xF4
#define FSL_XCVR_GP_PLL_STATUS_CLR		0xF8
#define FSL_XCVR_GP_PLL_STATUS_TOG		0xFC

/* GP PLL Control Register */
#define FSL_XCVR_GP_PLL_CTRL_LBYPASS		BIT(31)
#define FSL_XCVR_GP_PLL_CTRL_HCS		BIT(16)
#define FSL_XCVR_GP_PLL_CTRL_MSD		BIT(12)
#define FSL_XCVR_GP_PLL_CTRL_DITHER_EN3		BIT(11)
#define FSL_XCVR_GP_PLL_CTRL_DITHER_EN2		BIT(10)
#define FSL_XCVR_GP_PLL_CTRL_DITHER_EN1		BIT(9)
#define FSL_XCVR_GP_PLL_CTRL_SPREADCTL		BIT(8)
#define FSL_XCVR_GP_PLL_CTRL_CLKMUX_BYPASS	BIT(2)
#define FSL_XCVR_GP_PLL_CTRL_CLKMUX_EN		BIT(1)
#define FSL_XCVR_GP_PLL_CTRL_POWERUP		BIT(0)

/* GP PLL Numerator Register */
#define FSL_XCVR_GP_PLL_NUMERATOR_MFN_SHIFT	2
#define FSL_XCVR_GP_PLL_NUMERATOR_MFN		GENMASK(31, 2)

/* GP PLL Denominator Register */
#define FSL_XCVR_GP_PLL_DENOMINATOR_MFD		GENMASK(29, 0)

/* GP PLL Dividers Register */
#define FSL_XCVR_GP_PLL_DIV_MFI_SHIFT		16
#define FSL_XCVR_GP_PLL_DIV_MFI			GENMASK(24, 16)
#define FSL_XCVR_GP_PLL_DIV_RDIV		GENMASK(15, 13)
#define FSL_XCVR_GP_PLL_DIV_ODIV		GENMASK(7, 0)

#endif /* __FSL_XCVR_H */