LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH -next] ide: Fix symbol undeclared warnings
From: Wang Wensheng @ 2020-09-16  9:23 UTC (permalink / raw)
  To: mpe, davem, benh, paulus, linux-ide, linuxppc-dev, linux-kernel

Build the object file with `C=2` and get the following warnings:
make allmodconfig ARCH=powerpc CROSS_COMPILE=powerpc64-linux-gnu-
make C=2 drivers/ide/pmac.o ARCH=powerpc64
CROSS_COMPILE=powerpc64-linux-gnu-

drivers/ide/pmac.c:228:23: warning: symbol 'mdma_timings_33' was not
declared. Should it be static?
drivers/ide/pmac.c:241:23: warning: symbol 'mdma_timings_33k' was not
declared. Should it be static?
drivers/ide/pmac.c:254:23: warning: symbol 'mdma_timings_66' was not
declared. Should it be static?
drivers/ide/pmac.c:272:3: warning: symbol 'kl66_udma_timings' was not
declared. Should it be static?
drivers/ide/pmac.c:1418:12: warning: symbol 'pmac_ide_probe' was not
declared. Should it be static?

Signed-off-by: Wang Wensheng <wangwensheng4@huawei.com>
---
 drivers/ide/pmac.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/ide/pmac.c b/drivers/ide/pmac.c
index ea0b064b5f56..6bb2fc6755c2 100644
--- a/drivers/ide/pmac.c
+++ b/drivers/ide/pmac.c
@@ -225,7 +225,7 @@ struct mdma_timings_t {
 	int	cycleTime;
 };
 
-struct mdma_timings_t mdma_timings_33[] =
+static struct mdma_timings_t mdma_timings_33[] =
 {
     { 240, 240, 480 },
     { 180, 180, 360 },
@@ -238,7 +238,7 @@ struct mdma_timings_t mdma_timings_33[] =
     {   0,   0,   0 }
 };
 
-struct mdma_timings_t mdma_timings_33k[] =
+static struct mdma_timings_t mdma_timings_33k[] =
 {
     { 240, 240, 480 },
     { 180, 180, 360 },
@@ -251,7 +251,7 @@ struct mdma_timings_t mdma_timings_33k[] =
     {   0,   0,   0 }
 };
 
-struct mdma_timings_t mdma_timings_66[] =
+static struct mdma_timings_t mdma_timings_66[] =
 {
     { 240, 240, 480 },
     { 180, 180, 360 },
@@ -265,7 +265,7 @@ struct mdma_timings_t mdma_timings_66[] =
 };
 
 /* KeyLargo ATA-4 Ultra DMA timings (rounded) */
-struct {
+static struct {
 	int	addrSetup; /* ??? */
 	int	rdy2pause;
 	int	wrDataSetup;
@@ -1415,7 +1415,7 @@ static struct pci_driver pmac_ide_pci_driver = {
 };
 MODULE_DEVICE_TABLE(pci, pmac_ide_pci_match);
 
-int __init pmac_ide_probe(void)
+static int __init pmac_ide_probe(void)
 {
 	int error;
 
-- 
2.25.0


^ permalink raw reply related

* [PATCH 2/2] ASoC: dt-bindings: fsl_xcvr: Add document for XCVR
From: Viorel Suman (OSS) @ 2020-09-16  9:17 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Jaroslav Kysela,
	Takashi Iwai, Timur Tabi, Nicolin Chen, Xiubo Li, Fabio Estevam,
	Shengjiu Wang, Philipp Zabel, Matthias Schiffer,
	Cosmin-Gabriel Samoila, Viorel Suman, alsa-devel, devicetree,
	linux-kernel, linuxppc-dev
  Cc: Viorel Suman, NXP Linux Team
In-Reply-To: <1600247876-8013-1-git-send-email-viorel.suman@oss.nxp.com>

From: Viorel Suman <viorel.suman@nxp.com>

XCVR (Audio Transceiver) is a new IP module found on i.MX8MP.

Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
---
 .../devicetree/bindings/sound/fsl,xcvr.yaml        | 104 +++++++++++++++++++++
 1 file changed, 104 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/fsl,xcvr.yaml

diff --git a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml
new file mode 100644
index 00000000..d4bb792
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml
@@ -0,0 +1,104 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/fsl,xcvr.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP Audio Transceiver (XCVR) Controller
+
+maintainers:
+  - Viorel Suman <viorel.suman@nxp.com>
+
+properties:
+  $nodename:
+    pattern: "^xcvr@.*"
+
+  compatible:
+    const: fsl,imx8mp-xcvr
+
+  reg:
+    items:
+      - description: 20K RAM for code and data
+      - description: registers space
+      - description: RX FIFO address
+      - description: TX FIFO address
+
+  reg-names:
+    items:
+      - const: ram
+      - const: regs
+      - const: rxfifo
+      - const: txfifo
+
+  interrupts:
+    maxItems: 3
+
+  clocks:
+    items:
+      - description: Peripheral clock
+      - description: PHY clock
+      - description: SPBA clock
+      - description: PLL clock
+
+  clock-names:
+    items:
+      - const: ipg
+      - const: phy
+      - const: spba
+      - const: pll_ipg
+
+  dmas:
+    maxItems: 2
+
+  dma-names:
+    items:
+      - const: rx
+      - const: tx
+
+  firmware-name:
+    $ref: /schemas/types.yaml#/definitions/string
+    const: imx/xcvr/xcvr-imx8mp.bin
+    description: |
+      Should contain the name of the default firmware image
+      file located on the firmware search path
+
+  resets:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - interrupts
+  - clocks
+  - clock-names
+  - dmas
+  - dma-names
+  - firmware-name
+  - resets
+
+examples:
+  - |
+    #include <dt-bindings/clock/imx8mp-clock.h>
+    #include <dt-bindings/reset/imx8mp-reset.h>
+
+    xcvr: xcvr@30cc0000 {
+           compatible = "fsl,imx8mp-xcvr";
+           reg = <0x30cc0000 0x800>,
+                 <0x30cc0800 0x400>,
+                 <0x30cc0c00 0x080>,
+                 <0x30cc0e00 0x080>;
+           reg-names = "ram", "regs", "rxfifo", "txfifo";
+           interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>, /* XCVR IRQ 0 */
+                        <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>, /* XCVR IRQ 1 */
+                        <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>; /* XCVR PHY - SPDIF wakeup IRQ */
+           clocks = <&audiomix_clk IMX8MP_CLK_AUDIOMIX_EARC_IPG>,
+                    <&audiomix_clk IMX8MP_CLK_AUDIOMIX_EARC_PHY>,
+                    <&audiomix_clk IMX8MP_CLK_AUDIOMIX_SPBA2_ROOT>,
+                    <&audiomix_clk IMX8MP_CLK_AUDIOMIX_AUDPLL_ROOT>;
+           clock-names = "ipg", "phy", "spba", "pll_ipg";
+           dmas = <&sdma2 30 2 0>, <&sdma2 31 2 0>;
+           dma-names = "rx", "tx";
+           firmware-name = "imx/xcvr/xcvr-imx8mp.bin";
+           resets = <&audiomix_reset 0>;
+    };
-- 
2.7.4


^ permalink raw reply related

* [PATCH 1/2] ASoC: fsl_xcvr: Add XCVR ASoC CPU DAI driver
From: Viorel Suman (OSS) @ 2020-09-16  9:17 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Jaroslav Kysela,
	Takashi Iwai, Timur Tabi, Nicolin Chen, Xiubo Li, Fabio Estevam,
	Shengjiu Wang, Philipp Zabel, Matthias Schiffer,
	Cosmin-Gabriel Samoila, Viorel Suman, alsa-devel, devicetree,
	linux-kernel, linuxppc-dev
  Cc: Viorel Suman, NXP Linux Team
In-Reply-To: <1600247876-8013-1-git-send-email-viorel.suman@oss.nxp.com>

From: Viorel Suman <viorel.suman@nxp.com>

XCVR (Audio Transceiver) is a on-chip functional module found
on i.MX8MP. It support HDMI2.1 eARC, HDMI1.4 ARC and SPDIF.

Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
---
 sound/soc/fsl/Kconfig    |   10 +
 sound/soc/fsl/Makefile   |    2 +
 sound/soc/fsl/fsl_xcvr.c | 1352 ++++++++++++++++++++++++++++++++++++++++++++++
 sound/soc/fsl/fsl_xcvr.h |  266 +++++++++
 4 files changed, 1630 insertions(+)
 create mode 100644 sound/soc/fsl/fsl_xcvr.c
 create mode 100644 sound/soc/fsl/fsl_xcvr.h

diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 3f76ff7..d04b64d 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -95,6 +95,16 @@ config SND_SOC_FSL_EASRC
 	  destination sample rate. It is a new design module compare with the
 	  old ASRC.
 
+config SND_SOC_FSL_XCVR
+	tristate "NXP Audio Transceiver (XCVR) module support"
+	select REGMAP_MMIO
+	select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n
+	select SND_SOC_GENERIC_DMAENGINE_PCM
+	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,
+	  HDMI1.4 ARC and SPDIF.
+
 config SND_SOC_FSL_UTILS
 	tristate
 
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index b835eeb..1d2231f 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -25,6 +25,7 @@ snd-soc-fsl-utils-objs := fsl_utils.o
 snd-soc-fsl-dma-objs := fsl_dma.o
 snd-soc-fsl-mqs-objs := fsl_mqs.o
 snd-soc-fsl-easrc-objs := fsl_easrc.o
+snd-soc-fsl-xcvr-objs := fsl_xcvr.o
 
 obj-$(CONFIG_SND_SOC_FSL_AUDMIX) += snd-soc-fsl-audmix.o
 obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o
@@ -38,6 +39,7 @@ obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o
 obj-$(CONFIG_SND_SOC_FSL_MQS) += snd-soc-fsl-mqs.o
 obj-$(CONFIG_SND_SOC_FSL_EASRC) += snd-soc-fsl-easrc.o
 obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o
+obj-$(CONFIG_SND_SOC_FSL_XCVR) += snd-soc-fsl-xcvr.o
 
 # MPC5200 Platform Support
 obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o
diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c
new file mode 100644
index 00000000..2e66f22
--- /dev/null
+++ b/sound/soc/fsl/fsl_xcvr.c
@@ -0,0 +1,1352 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright 2019 NXP
+
+#include <linux/bitrev.h>
+#include <linux/clk.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm_iec958.h>
+#include <sound/pcm_params.h>
+
+#include "fsl_xcvr.h"
+#include "imx-pcm.h"
+
+#define FSL_XCVR_CAPDS_SIZE	256
+
+struct fsl_xcvr {
+	struct platform_device *pdev;
+	struct regmap *regmap;
+	struct clk *ipg_clk;
+	struct clk *pll_ipg_clk;
+	struct clk *phy_clk;
+	struct clk *spba_clk;
+	struct reset_control *reset;
+	const char *fw_name;
+	u8 streams;
+	u32 mode;
+	u32 arc_mode;
+	void __iomem *ram_addr;
+	struct snd_dmaengine_dai_dma_data dma_prms_rx;
+	struct snd_dmaengine_dai_dma_data dma_prms_tx;
+	struct snd_aes_iec958 rx_iec958;
+	struct snd_aes_iec958 tx_iec958;
+	u8 cap_ds[FSL_XCVR_CAPDS_SIZE];
+};
+
+static const struct fsl_xcvr_pll_conf {
+	u8 mfi;   /* min=0x18, max=0x38 */
+	u32 mfn;  /* signed int, 2's compl., min=0x3FFF0000, max=0x00010000 */
+	u32 mfd;  /* unsigned int */
+	u32 fout; /* Fout = Fref*(MFI + MFN/MFD), Fref is 24MHz */
+} fsl_xcvr_pll_cfg[] = {
+	{ .mfi = 54, .mfn = 1,  .mfd = 6,   .fout = 1300000000, }, /* 1.3 GHz */
+	{ .mfi = 32, .mfn = 96, .mfd = 125, .fout = 786432000, },  /* 8000 Hz */
+	{ .mfi = 30, .mfn = 66, .mfd = 625, .fout = 722534400, },  /* 11025 Hz */
+	{ .mfi = 29, .mfn = 1,  .mfd = 6,   .fout = 700000000, },  /* 700 MHz */
+};
+
+static const u32 fsl_xcvr_earc_channels[] = { 1, 2, 8, 16, 32, }; /* one bit 6, 12 ? */
+static const struct snd_pcm_hw_constraint_list fsl_xcvr_earc_channels_constr = {
+	.count = ARRAY_SIZE(fsl_xcvr_earc_channels),
+	.list = fsl_xcvr_earc_channels,
+};
+
+static const u32 fsl_xcvr_earc_rates[] = {
+	32000, 44100, 48000, 64000, 88200, 96000,
+	128000, 176400, 192000, 256000, 352800, 384000,
+	512000, 705600, 768000, 1024000, 1411200, 1536000,
+};
+static const struct snd_pcm_hw_constraint_list fsl_xcvr_earc_rates_constr = {
+	.count = ARRAY_SIZE(fsl_xcvr_earc_rates),
+	.list = fsl_xcvr_earc_rates,
+};
+
+static const u32 fsl_xcvr_spdif_channels[] = { 2, };
+static const struct snd_pcm_hw_constraint_list fsl_xcvr_spdif_channels_constr = {
+	.count = ARRAY_SIZE(fsl_xcvr_spdif_channels),
+	.list = fsl_xcvr_spdif_channels,
+};
+
+static const u32 fsl_xcvr_spdif_rates[] = {
+	32000, 44100, 48000, 88200, 96000, 176400, 192000,
+};
+static const struct snd_pcm_hw_constraint_list fsl_xcvr_spdif_rates_constr = {
+	.count = ARRAY_SIZE(fsl_xcvr_spdif_rates),
+	.list = fsl_xcvr_spdif_rates,
+};
+
+static int fsl_xcvr_arc_mode_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int *item = ucontrol->value.enumerated.item;
+
+	xcvr->arc_mode = snd_soc_enum_item_to_val(e, item[0]);
+
+	return 0;
+}
+
+static int fsl_xcvr_arc_mode_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+	ucontrol->value.enumerated.item[0] = xcvr->arc_mode;
+
+	return 0;
+}
+
+static const int fsl_xcvr_phy_arc_cfg[] = {
+	FSL_XCVR_PHY_CTRL_ARC_MODE_SE_EN, FSL_XCVR_PHY_CTRL_ARC_MODE_CM_EN,
+};
+
+static const char * const fsl_xcvr_arc_mode[] = { "Single Ended", "Common", };
+static const struct soc_enum fsl_xcvr_arc_mode_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(fsl_xcvr_arc_mode), fsl_xcvr_arc_mode);
+static struct snd_kcontrol_new fsl_xcvr_arc_mode_kctl =
+	SOC_ENUM_EXT("ARC Mode", fsl_xcvr_arc_mode_enum,
+		     fsl_xcvr_arc_mode_get, fsl_xcvr_arc_mode_put);
+
+/* Capabilities data structure, bytes */
+static int fsl_xcvr_type_capds_bytes_info(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	uinfo->count = FSL_XCVR_CAPDS_SIZE;
+
+	return 0;
+}
+
+static int fsl_xcvr_capds_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+	memcpy(ucontrol->value.bytes.data, xcvr->cap_ds, FSL_XCVR_CAPDS_SIZE);
+
+	return 0;
+}
+
+static int fsl_xcvr_capds_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+	memcpy(xcvr->cap_ds, ucontrol->value.bytes.data, FSL_XCVR_CAPDS_SIZE);
+
+	return 0;
+}
+
+static struct snd_kcontrol_new fsl_xcvr_earc_capds_kctl = {
+	.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+	.name = "Capabilities Data Structure",
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.info = fsl_xcvr_type_capds_bytes_info,
+	.get = fsl_xcvr_capds_get,
+	.put = fsl_xcvr_capds_put,
+};
+
+static int fsl_xcvr_activate_ctl(struct snd_soc_dai *dai, const char *name,
+				 bool active)
+{
+	struct snd_soc_card *card = dai->component->card;
+	struct snd_kcontrol *kctl;
+	bool enabled;
+
+	kctl = snd_soc_card_get_kcontrol(card, name);
+	if (kctl == NULL)
+		return -ENOENT;
+
+	enabled = ((kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_WRITE) != 0);
+	if (active == enabled)
+		return 0; /* nothing to do */
+
+	if (active)
+		kctl->vd[0].access |=  SNDRV_CTL_ELEM_ACCESS_WRITE;
+	else
+		kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_WRITE;
+
+	snd_ctl_notify(card->snd_card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id);
+
+	return 1;
+}
+
+static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int *item = ucontrol->value.enumerated.item;
+	struct snd_soc_card *card = dai->component->card;
+	struct snd_soc_pcm_runtime *rtd;
+
+	xcvr->mode = snd_soc_enum_item_to_val(e, item[0]);
+
+	fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name,
+			      (xcvr->mode == FSL_XCVR_MODE_ARC));
+	fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name,
+			      (xcvr->mode == FSL_XCVR_MODE_EARC));
+	/* Allow playback for SPDIF only */
+	rtd = snd_soc_get_pcm_runtime(card, card->dai_link);
+	rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count =
+		(xcvr->mode == FSL_XCVR_MODE_SPDIF ? 1 : 0);
+	return 0;
+}
+
+static int fsl_xcvr_mode_get(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+	ucontrol->value.enumerated.item[0] = xcvr->mode;
+
+	return 0;
+}
+
+static const char * const fsl_xcvr_mode[] = { "SPDIF", "ARC RX", "eARC", };
+static const struct soc_enum fsl_xcvr_mode_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(fsl_xcvr_mode), fsl_xcvr_mode);
+static struct snd_kcontrol_new fsl_xcvr_mode_kctl =
+	SOC_ENUM_EXT("XCVR Mode", fsl_xcvr_mode_enum,
+		     fsl_xcvr_mode_get, fsl_xcvr_mode_put);
+
+/** phy: true => phy, false => pll */
+static int fsl_xcvr_ai_write(struct fsl_xcvr *xcvr, u8 reg, u32 data, bool phy)
+{
+	u32 val, idx, tidx;
+
+	idx  = BIT(phy ? 26 : 24);
+	tidx = BIT(phy ? 27 : 25);
+
+	regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_CLR, 0xFF);
+	regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET, reg);
+	regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_WDATA, data);
+	regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_TOG, idx);
+
+	do {
+		regmap_read(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL, &val);
+	} while ((val & idx) != ((val & tidx) >> 1));
+
+	return 0;
+}
+
+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;
+	int ret;
+
+	for (i = 0; i < ARRAY_SIZE(fsl_xcvr_pll_cfg); i++) {
+		if (fsl_xcvr_pll_cfg[i].fout % freq == 0) {
+			div = fsl_xcvr_pll_cfg[i].fout / freq;
+			break;
+		}
+	}
+
+	if (!div || i >= ARRAY_SIZE(fsl_xcvr_pll_cfg))
+		return -EINVAL;
+
+	log2 = ilog2(div);
+
+	/* Release AI interface from reset */
+	ret = regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET,
+			   FSL_XCVR_PHY_AI_CTRL_AI_RESETN);
+	if (ret < 0) {
+		dev_err(dev, "Error while setting IER0: %d\n", ret);
+		return ret;
+	}
+
+	/* PLL: BANDGAP_SET: EN_VBG (enable bandgap) */
+	fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_BANDGAP_SET,
+			  FSL_XCVR_PLL_BANDGAP_EN_VBG, 0);
+
+	/* PLL: CTRL0: DIV_INTEGER */
+	fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0, fsl_xcvr_pll_cfg[i].mfi, 0);
+	/* PLL: NUMERATOR: MFN */
+	fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_NUM, fsl_xcvr_pll_cfg[i].mfn, 0);
+	/* PLL: DENOMINATOR: MFD */
+	fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_DEN, fsl_xcvr_pll_cfg[i].mfd, 0);
+	/* PLL: CTRL0_SET: HOLD_RING_OFF, POWER_UP */
+	fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET,
+			  FSL_XCVR_PLL_CTRL0_HROFF | FSL_XCVR_PLL_CTRL0_PWP, 0);
+	udelay(25);
+	/* PLL: CTRL0: Clear Hold Ring Off */
+	fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_CLR,
+			  FSL_XCVR_PLL_CTRL0_HROFF, 0);
+	udelay(100);
+	if (tx) { /* TX is enabled for SPDIF only */
+		/* PLL: POSTDIV: PDIV0 */
+		fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV,
+				  FSL_XCVR_PLL_PDIVx(log2, 0), 0);
+		/* PLL: CTRL_SET: CLKMUX0_EN */
+		fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET,
+				  FSL_XCVR_PLL_CTRL0_CM0_EN, 0);
+	} else if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC RX */
+		/* PLL: POSTDIV: PDIV1 */
+		fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV,
+				  FSL_XCVR_PLL_PDIVx(log2, 1), 0);
+		/* PLL: CTRL_SET: CLKMUX1_EN */
+		fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET,
+				  FSL_XCVR_PLL_CTRL0_CM1_EN, 0);
+	} else { /* SPDIF / ARC RX */
+		/* PLL: POSTDIV: PDIV2 */
+		fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV,
+				  FSL_XCVR_PLL_PDIVx(log2, 2), 0);
+		/* PLL: CTRL_SET: CLKMUX2_EN */
+		fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET,
+				  FSL_XCVR_PLL_CTRL0_CM2_EN, 0);
+	}
+
+	if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC mode */
+		/* PHY: CTRL_SET: TX_DIFF_OE, PHY_EN */
+		fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET,
+				  FSL_XCVR_PHY_CTRL_TSDIFF_OE |
+				  FSL_XCVR_PHY_CTRL_PHY_EN, 1);
+		/* PHY: CTRL2_SET: EARC_TX_MODE */
+		fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL2_SET,
+				  FSL_XCVR_PHY_CTRL2_EARC_TXMS, 1);
+	} else if (!tx) { /* SPDIF / ARC RX mode */
+		if (xcvr->mode == FSL_XCVR_MODE_SPDIF)
+			/* PHY: CTRL_SET: SPDIF_EN */
+			fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET,
+					  FSL_XCVR_PHY_CTRL_SPDIF_EN, 1);
+		else	/* PHY: CTRL_SET: ARC RX setup */
+			fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET,
+					  FSL_XCVR_PHY_CTRL_PHY_EN |
+					  FSL_XCVR_PHY_CTRL_RX_CM_EN |
+					  fsl_xcvr_phy_arc_cfg[xcvr->arc_mode], 1);
+	}
+
+	dev_dbg(dev, "PLL Fexp: %u, Fout: %u, mfi: %u, mfn: %u, mfd: %d, div: %u, pdiv0: %u\n",
+		freq, fsl_xcvr_pll_cfg[i].fout, fsl_xcvr_pll_cfg[i].mfi,
+		fsl_xcvr_pll_cfg[i].mfn, fsl_xcvr_pll_cfg[i].mfd, div, log2);
+	return 0;
+}
+
+static int fsl_xcvr_en_aud_pll(struct fsl_xcvr *xcvr, u32 freq)
+{
+	struct device *dev = &xcvr->pdev->dev;
+	int ret;
+
+	clk_disable_unprepare(xcvr->phy_clk);
+	ret = clk_set_rate(xcvr->phy_clk, freq);
+	if (ret < 0) {
+		dev_err(dev, "Error while setting AUD PLL rate: %d\n", ret);
+		return ret;
+	}
+	ret = clk_prepare_enable(xcvr->phy_clk);
+	if (ret) {
+		dev_err(dev, "failed to start PHY clock: %d\n", ret);
+		return ret;
+	}
+
+	/* Release AI interface from reset */
+	ret = regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET,
+			   FSL_XCVR_PHY_AI_CTRL_AI_RESETN);
+	if (ret < 0) {
+		dev_err(dev, "Error while setting IER0: %d\n", ret);
+		return ret;
+	}
+
+	if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC mode */
+		/* PHY: CTRL_SET: TX_DIFF_OE, PHY_EN */
+		fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET,
+				  FSL_XCVR_PHY_CTRL_TSDIFF_OE |
+				  FSL_XCVR_PHY_CTRL_PHY_EN, 1);
+		/* PHY: CTRL2_SET: EARC_TX_MODE */
+		fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL2_SET,
+				  FSL_XCVR_PHY_CTRL2_EARC_TXMS, 1);
+	} else { /* SPDIF mode */
+		/* PHY: CTRL_SET: TX_CLK_AUD_SS | SPDIF_EN */
+		fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET,
+				  FSL_XCVR_PHY_CTRL_TX_CLK_AUD_SS |
+				  FSL_XCVR_PHY_CTRL_SPDIF_EN, 1);
+	}
+
+	dev_dbg(dev, "PLL Fexp: %u\n", freq);
+
+	return 0;
+}
+
+#define FSL_XCVR_SPDIF_RX_FREQ	175000000
+static int fsl_xcvr_prepare(struct snd_pcm_substream *substream,
+			    struct snd_soc_dai *dai)
+{
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	u32 m_ctl = 0, v_ctl = 0;
+	u32 r = substream->runtime->rate, ch = substream->runtime->channels;
+	u32 fout = 32 * r * ch * 10 * 2;
+	int ret = 0;
+
+	switch (xcvr->mode) {
+	case FSL_XCVR_MODE_SPDIF:
+	case FSL_XCVR_MODE_ARC:
+		if (tx) {
+			ret = fsl_xcvr_en_aud_pll(xcvr, fout);
+			if (ret < 0) {
+				dev_err(dai->dev, "Failed to set TX freq %u: %d\n",
+					fout, ret);
+				return ret;
+			}
+
+			ret = regmap_write(xcvr->regmap, FSL_XCVR_TX_DPTH_CTRL_SET,
+					   FSL_XCVR_TX_DPTH_CTRL_FRM_FMT);
+			if (ret < 0) {
+				dev_err(dai->dev, "Failed to set TX_DPTH: %d\n", ret);
+				return ret;
+			}
+
+			/**
+			 * set SPDIF MODE - this flag is used to gate
+			 * SPDIF output, useless for SPDIF RX
+			 */
+			m_ctl |= FSL_XCVR_EXT_CTRL_SPDIF_MODE;
+			v_ctl |= FSL_XCVR_EXT_CTRL_SPDIF_MODE;
+		} else {
+			/**
+			 * Clear RX FIFO, flip RX FIFO bits,
+			 * disable eARC related HW mode detects
+			 */
+			ret = regmap_write(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL_SET,
+					   FSL_XCVR_RX_DPTH_CTRL_STORE_FMT |
+					   FSL_XCVR_RX_DPTH_CTRL_CLR_RX_FIFO |
+					   FSL_XCVR_RX_DPTH_CTRL_COMP |
+					   FSL_XCVR_RX_DPTH_CTRL_LAYB_CTRL);
+			if (ret < 0) {
+				dev_err(dai->dev, "Failed to set RX_DPTH: %d\n", ret);
+				return ret;
+			}
+
+			ret = fsl_xcvr_en_phy_pll(xcvr, FSL_XCVR_SPDIF_RX_FREQ, tx);
+			if (ret < 0) {
+				dev_err(dai->dev, "Failed to set RX freq %u: %d\n",
+					FSL_XCVR_SPDIF_RX_FREQ, ret);
+				return ret;
+			}
+		}
+		break;
+	case FSL_XCVR_MODE_EARC:
+		if (!tx) {
+			/** Clear RX FIFO, flip RX FIFO bits */
+			ret = regmap_write(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL_SET,
+					   FSL_XCVR_RX_DPTH_CTRL_STORE_FMT |
+					   FSL_XCVR_RX_DPTH_CTRL_CLR_RX_FIFO);
+			if (ret < 0) {
+				dev_err(dai->dev, "Failed to set RX_DPTH: %d\n", ret);
+				return ret;
+			}
+
+			/** Enable eARC related HW mode detects */
+			ret = regmap_write(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL_CLR,
+					   FSL_XCVR_RX_DPTH_CTRL_COMP |
+					   FSL_XCVR_RX_DPTH_CTRL_LAYB_CTRL);
+			if (ret < 0) {
+				dev_err(dai->dev, "Failed to clr TX_DPTH: %d\n", ret);
+				return ret;
+			}
+		}
+
+		/* clear CMDC RESET */
+		m_ctl |= FSL_XCVR_EXT_CTRL_CMDC_RESET(tx);
+		/* set TX_RX_MODE */
+		m_ctl |= FSL_XCVR_EXT_CTRL_TX_RX_MODE;
+		v_ctl |= (tx ? FSL_XCVR_EXT_CTRL_TX_RX_MODE : 0);
+		break;
+	}
+
+	ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
+				 FSL_XCVR_IRQ_EARC_ALL, FSL_XCVR_IRQ_EARC_ALL);
+	if (ret < 0) {
+		dev_err(dai->dev, "Error while setting IER0: %d\n", ret);
+		return ret;
+	}
+
+	/* clear DPATH RESET */
+	m_ctl |= FSL_XCVR_EXT_CTRL_DPTH_RESET(tx);
+	ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, m_ctl, v_ctl);
+	if (ret < 0) {
+		dev_err(dai->dev, "Error while setting EXT_CTRL: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int fsl_xcvr_constr(const struct snd_pcm_substream *substream,
+			   const struct snd_pcm_hw_constraint_list *channels,
+			   const struct snd_pcm_hw_constraint_list *rates)
+{
+	struct snd_pcm_runtime *rt = substream->runtime;
+	int ret;
+
+	ret = snd_pcm_hw_constraint_list(rt, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+					 channels);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_pcm_hw_constraint_list(rt, 0, SNDRV_PCM_HW_PARAM_RATE,
+					 rates);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int fsl_xcvr_startup(struct snd_pcm_substream *substream,
+			    struct snd_soc_dai *dai)
+{
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	int ret = 0;
+
+	if (xcvr->streams & BIT(substream->stream)) {
+		dev_err(dai->dev, "%sX busy\n", tx ? "T" : "R");
+		return -EBUSY;
+	}
+
+	switch (xcvr->mode) {
+	case FSL_XCVR_MODE_SPDIF:
+	case FSL_XCVR_MODE_ARC:
+		ret = fsl_xcvr_constr(substream, &fsl_xcvr_spdif_channels_constr,
+				      &fsl_xcvr_spdif_rates_constr);
+		break;
+	case FSL_XCVR_MODE_EARC:
+		ret = fsl_xcvr_constr(substream, &fsl_xcvr_earc_channels_constr,
+				      &fsl_xcvr_earc_rates_constr);
+		break;
+	}
+	if (ret < 0)
+		return ret;
+
+	xcvr->streams |= BIT(substream->stream);
+
+	/* Disable XCVR controls if there is stream started */
+	fsl_xcvr_activate_ctl(dai, fsl_xcvr_mode_kctl.name, false);
+	fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name, false);
+	fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name, false);
+
+	return 0;
+}
+
+static void fsl_xcvr_shutdown(struct snd_pcm_substream *substream,
+			      struct snd_soc_dai *dai)
+{
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	u32 mask = 0, val = 0;
+	int ret;
+
+	xcvr->streams &= ~BIT(substream->stream);
+
+	/* Enable XCVR controls if there is no stream started */
+	if (!xcvr->streams) {
+		fsl_xcvr_activate_ctl(dai, fsl_xcvr_mode_kctl.name, true);
+		fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name,
+				      (xcvr->mode == FSL_XCVR_MODE_ARC));
+		fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name,
+				      (xcvr->mode == FSL_XCVR_MODE_EARC));
+
+		ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
+					 FSL_XCVR_IRQ_EARC_ALL, 0);
+		if (ret < 0) {
+			dev_err(dai->dev, "Failed to set IER0: %d\n", ret);
+			return;
+		}
+
+		/* clear SPDIF MODE */
+		if (xcvr->mode == FSL_XCVR_MODE_SPDIF)
+			mask |= FSL_XCVR_EXT_CTRL_SPDIF_MODE;
+	}
+
+	if (xcvr->mode == FSL_XCVR_MODE_EARC) {
+		/* set CMDC RESET */
+		mask |= FSL_XCVR_EXT_CTRL_CMDC_RESET(tx);
+		val  |= FSL_XCVR_EXT_CTRL_CMDC_RESET(tx);
+	}
+
+	/* set DPATH RESET */
+	mask |= FSL_XCVR_EXT_CTRL_DPTH_RESET(tx);
+	val  |= FSL_XCVR_EXT_CTRL_DPTH_RESET(tx);
+
+	ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, mask, val);
+	if (ret < 0) {
+		dev_err(dai->dev, "Err setting DPATH RESET: %d\n", ret);
+		return;
+	}
+}
+
+static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
+			    struct snd_soc_dai *dai)
+{
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	int ret;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		if (tx) {
+			switch (xcvr->mode) {
+			case FSL_XCVR_MODE_EARC:
+				/* set isr_cmdc_tx_en, w1c */
+				ret = regmap_write(xcvr->regmap,
+						   FSL_XCVR_ISR_SET,
+						   FSL_XCVR_ISR_CMDC_TX_EN);
+				if (ret < 0) {
+					dev_err(dai->dev, "err updating isr %d\n", ret);
+					return ret;
+				}
+				fallthrough;
+			case FSL_XCVR_MODE_SPDIF:
+				ret = regmap_write(xcvr->regmap,
+					 FSL_XCVR_TX_DPTH_CTRL_SET,
+					 FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX);
+				if (ret < 0) {
+					dev_err(dai->dev, "Failed to start DATA_TX: %d\n", ret);
+					return ret;
+				}
+				break;
+			}
+		}
+
+		/* enable DMA RD/WR */
+		ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+					 FSL_XCVR_EXT_CTRL_DMA_DIS(tx), 0);
+		if (ret < 0) {
+			dev_err(dai->dev, "Failed to enable DMA: %d\n", ret);
+			return ret;
+		}
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		/* disable DMA RD/WR */
+		ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+					 FSL_XCVR_EXT_CTRL_DMA_DIS(tx),
+					 FSL_XCVR_EXT_CTRL_DMA_DIS(tx));
+		if (ret < 0) {
+			dev_err(dai->dev, "Failed to disable DMA: %d\n", ret);
+			return ret;
+		}
+
+		if (tx) {
+			switch (xcvr->mode) {
+			case FSL_XCVR_MODE_SPDIF:
+				ret = regmap_write(xcvr->regmap,
+					 FSL_XCVR_TX_DPTH_CTRL_CLR,
+					 FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX);
+				if (ret < 0) {
+					dev_err(dai->dev, "Failed to stop DATA_TX: %d\n", ret);
+					return ret;
+				}
+				fallthrough;
+			case FSL_XCVR_MODE_EARC:
+				/* clear ISR_CMDC_TX_EN, W1C */
+				ret = regmap_write(xcvr->regmap,
+						   FSL_XCVR_ISR_CLR,
+						   FSL_XCVR_ISR_CMDC_TX_EN);
+				if (ret < 0) {
+					dev_err(dai->dev,
+						"Err updating ISR %d\n", ret);
+					return ret;
+				}
+				break;
+			}
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int fsl_xcvr_load_firmware(struct fsl_xcvr *xcvr)
+{
+	struct device *dev = &xcvr->pdev->dev;
+	const struct firmware *fw;
+	int ret = 0, rem, off, out, page = 0, size = FSL_XCVR_REG_OFFSET;
+	u32 mask, val;
+
+	ret = request_firmware(&fw, xcvr->fw_name, dev);
+	if (ret) {
+		dev_err(dev, "failed to request firmware.\n");
+		return ret;
+	}
+
+	rem = fw->size;
+
+	/* RAM is 20KiB => max 10 pages 2KiB each */
+	for (page = 0; page < 10; page++) {
+		ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+					 FSL_XCVR_EXT_CTRL_PAGE_MASK,
+					 FSL_XCVR_EXT_CTRL_PAGE(page));
+		if (ret < 0) {
+			dev_err(dev, "FW: failed to set page %d, err=%d\n",
+				page, ret);
+			goto err_firmware;
+		}
+
+		off = page * size;
+		out = min(rem, size);
+		/* IPG clock is assumed to be running, otherwise it will hang */
+		if (out > 0) {
+			/* write firmware into code memory */
+			memcpy_toio(xcvr->ram_addr, fw->data + off, out);
+			rem -= out;
+			if (rem == 0) {
+				/* last part of firmware written */
+				/* clean remaining part of code memory page */
+				memset_io(xcvr->ram_addr + out, 0, size - out);
+			}
+		} else {
+			/* clean current page, including data memory */
+			memset_io(xcvr->ram_addr, 0, size);
+		}
+	};
+
+err_firmware:
+	release_firmware(fw);
+	if (ret < 0)
+		return ret;
+
+	/* configure watermarks */
+	mask = FSL_XCVR_EXT_CTRL_RX_FWM_MASK | FSL_XCVR_EXT_CTRL_TX_FWM_MASK;
+	val  = FSL_XCVR_EXT_CTRL_RX_FWM(FSL_XCVR_FIFO_WMK_RX);
+	val |= FSL_XCVR_EXT_CTRL_TX_FWM(FSL_XCVR_FIFO_WMK_TX);
+	/* disable DMA RD/WR */
+	mask |= FSL_XCVR_EXT_CTRL_DMA_RD_DIS | FSL_XCVR_EXT_CTRL_DMA_WR_DIS;
+	val  |= FSL_XCVR_EXT_CTRL_DMA_RD_DIS | FSL_XCVR_EXT_CTRL_DMA_WR_DIS;
+	/* Data RAM is 4KiB, last two pages: 8 and 9. Select page 8. */
+	mask |= FSL_XCVR_EXT_CTRL_PAGE_MASK;
+	val  |= FSL_XCVR_EXT_CTRL_PAGE(8);
+
+	ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, mask, val);
+	if (ret < 0) {
+		dev_err(dev, "Failed to set watermarks: %d\n", ret);
+		return ret;
+	}
+
+	/* Store Capabilities Data Structure into Data RAM */
+	memcpy_toio(xcvr->ram_addr + FSL_XCVR_CAP_DATA_STR, xcvr->cap_ds,
+		    FSL_XCVR_CAPDS_SIZE);
+
+	return 0;
+}
+
+static int fsl_xcvr_type_iec958_info(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+	uinfo->count = 1;
+
+	return 0;
+}
+
+static int fsl_xcvr_type_iec958_bytes_info(struct snd_kcontrol *kcontrol,
+					   struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	uinfo->count = sizeof_field(struct snd_aes_iec958, status);
+
+	return 0;
+}
+
+static int fsl_xcvr_rx_cs_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+	memcpy(ucontrol->value.iec958.status, xcvr->rx_iec958.status, 24);
+
+	return 0;
+}
+
+static int fsl_xcvr_tx_cs_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+	memcpy(ucontrol->value.iec958.status, xcvr->tx_iec958.status, 24);
+
+	return 0;
+}
+
+static int fsl_xcvr_tx_cs_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+	memcpy(xcvr->tx_iec958.status, ucontrol->value.iec958.status, 24);
+
+	return 0;
+}
+
+static struct snd_kcontrol_new fsl_xcvr_rx_ctls[] = {
+	/* Channel status controller */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
+		.access = SNDRV_CTL_ELEM_ACCESS_READ,
+		.info = fsl_xcvr_type_iec958_info,
+		.get = fsl_xcvr_rx_cs_get,
+	},
+	/* Capture channel status, bytes */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = "Capture Channel Status",
+		.access = SNDRV_CTL_ELEM_ACCESS_READ,
+		.info = fsl_xcvr_type_iec958_bytes_info,
+		.get = fsl_xcvr_rx_cs_get,
+	},
+};
+
+static struct snd_kcontrol_new fsl_xcvr_tx_ctls[] = {
+	/* Channel status controller */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = fsl_xcvr_type_iec958_info,
+		.get = fsl_xcvr_tx_cs_get,
+		.put = fsl_xcvr_tx_cs_put,
+	},
+	/* Playback channel status, bytes */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = "Playback Channel Status",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = fsl_xcvr_type_iec958_bytes_info,
+		.get = fsl_xcvr_tx_cs_get,
+		.put = fsl_xcvr_tx_cs_put,
+	},
+};
+
+static struct snd_soc_dai_ops fsl_xcvr_dai_ops = {
+	.prepare = fsl_xcvr_prepare,
+	.startup = fsl_xcvr_startup,
+	.shutdown = fsl_xcvr_shutdown,
+	.trigger = fsl_xcvr_trigger,
+};
+
+static int fsl_xcvr_dai_probe(struct snd_soc_dai *dai)
+{
+	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+	snd_soc_dai_init_dma_data(dai, &xcvr->dma_prms_tx, &xcvr->dma_prms_rx);
+	snd_soc_dai_set_drvdata(dai, xcvr);
+
+	snd_soc_add_dai_controls(dai, &fsl_xcvr_mode_kctl, 1);
+	snd_soc_add_dai_controls(dai, &fsl_xcvr_arc_mode_kctl, 1);
+	snd_soc_add_dai_controls(dai, &fsl_xcvr_earc_capds_kctl, 1);
+	snd_soc_add_dai_controls(dai, fsl_xcvr_tx_ctls,
+				 ARRAY_SIZE(fsl_xcvr_tx_ctls));
+	snd_soc_add_dai_controls(dai, fsl_xcvr_rx_ctls,
+				 ARRAY_SIZE(fsl_xcvr_rx_ctls));
+	return 0;
+}
+
+static struct snd_soc_dai_driver fsl_xcvr_dai = {
+	.probe  = fsl_xcvr_dai_probe,
+	.ops = &fsl_xcvr_dai_ops,
+	.playback = {
+		.stream_name = "CPU-Playback",
+		.channels_min = 1,
+		.channels_max = 32,
+		.rate_min = 32000,
+		.rate_max = 1536000,
+		.rates = SNDRV_PCM_RATE_KNOT,
+		.formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
+	},
+	.capture = {
+		.stream_name = "CPU-Capture",
+		.channels_min = 1,
+		.channels_max = 32,
+		.rate_min = 32000,
+		.rate_max = 1536000,
+		.rates = SNDRV_PCM_RATE_KNOT,
+		.formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
+	},
+};
+
+static const struct snd_soc_component_driver fsl_xcvr_comp = {
+	.name = "fsl-xcvr-dai",
+};
+
+static const struct reg_default fsl_xcvr_reg_defaults[] = {
+	{ FSL_XCVR_VERSION,	0x00000000 },
+	{ FSL_XCVR_EXT_CTRL,	0xF8204040 },
+	{ FSL_XCVR_EXT_STATUS,	0x00000000 },
+	{ FSL_XCVR_EXT_IER0,	0x00000000 },
+	{ FSL_XCVR_EXT_IER1,	0x00000000 },
+	{ FSL_XCVR_EXT_ISR,	0x00000000 },
+	{ FSL_XCVR_EXT_ISR_SET,	0x00000000 },
+	{ FSL_XCVR_EXT_ISR_CLR,	0x00000000 },
+	{ FSL_XCVR_EXT_ISR_TOG,	0x00000000 },
+	{ FSL_XCVR_IER,		0x00000000 },
+	{ FSL_XCVR_ISR,		0x00000000 },
+	{ FSL_XCVR_ISR_SET,	0x00000000 },
+	{ FSL_XCVR_ISR_CLR,	0x00000000 },
+	{ FSL_XCVR_ISR_TOG,	0x00000000 },
+	{ FSL_XCVR_RX_DPTH_CTRL,	0x00002C89 },
+	{ FSL_XCVR_RX_DPTH_CTRL_SET,	0x00002C89 },
+	{ FSL_XCVR_RX_DPTH_CTRL_CLR,	0x00002C89 },
+	{ FSL_XCVR_RX_DPTH_CTRL_TOG,	0x00002C89 },
+	{ FSL_XCVR_TX_DPTH_CTRL,	0x00000000 },
+	{ FSL_XCVR_TX_DPTH_CTRL_SET,	0x00000000 },
+	{ FSL_XCVR_TX_DPTH_CTRL_CLR,	0x00000000 },
+	{ FSL_XCVR_TX_DPTH_CTRL_TOG,	0x00000000 },
+	{ FSL_XCVR_TX_CS_DATA_0,	0x00000000 },
+	{ FSL_XCVR_TX_CS_DATA_1,	0x00000000 },
+	{ FSL_XCVR_TX_CS_DATA_2,	0x00000000 },
+	{ FSL_XCVR_TX_CS_DATA_3,	0x00000000 },
+	{ FSL_XCVR_TX_CS_DATA_4,	0x00000000 },
+	{ FSL_XCVR_TX_CS_DATA_5,	0x00000000 },
+	{ FSL_XCVR_DEBUG_REG_0,		0x00000000 },
+	{ FSL_XCVR_DEBUG_REG_1,		0x00000000 },
+};
+
+static bool fsl_xcvr_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case FSL_XCVR_VERSION:
+	case FSL_XCVR_EXT_CTRL:
+	case FSL_XCVR_EXT_STATUS:
+	case FSL_XCVR_EXT_IER0:
+	case FSL_XCVR_EXT_IER1:
+	case FSL_XCVR_EXT_ISR:
+	case FSL_XCVR_EXT_ISR_SET:
+	case FSL_XCVR_EXT_ISR_CLR:
+	case FSL_XCVR_EXT_ISR_TOG:
+	case FSL_XCVR_IER:
+	case FSL_XCVR_ISR:
+	case FSL_XCVR_ISR_SET:
+	case FSL_XCVR_ISR_CLR:
+	case FSL_XCVR_ISR_TOG:
+	case FSL_XCVR_PHY_AI_CTRL:
+	case FSL_XCVR_PHY_AI_CTRL_SET:
+	case FSL_XCVR_PHY_AI_CTRL_CLR:
+	case FSL_XCVR_PHY_AI_CTRL_TOG:
+	case FSL_XCVR_PHY_AI_RDATA:
+	case FSL_XCVR_CLK_CTRL:
+	case FSL_XCVR_RX_DPTH_CTRL:
+	case FSL_XCVR_RX_DPTH_CTRL_SET:
+	case FSL_XCVR_RX_DPTH_CTRL_CLR:
+	case FSL_XCVR_RX_DPTH_CTRL_TOG:
+	case FSL_XCVR_TX_DPTH_CTRL:
+	case FSL_XCVR_TX_DPTH_CTRL_SET:
+	case FSL_XCVR_TX_DPTH_CTRL_CLR:
+	case FSL_XCVR_TX_DPTH_CTRL_TOG:
+	case FSL_XCVR_TX_CS_DATA_0:
+	case FSL_XCVR_TX_CS_DATA_1:
+	case FSL_XCVR_TX_CS_DATA_2:
+	case FSL_XCVR_TX_CS_DATA_3:
+	case FSL_XCVR_TX_CS_DATA_4:
+	case FSL_XCVR_TX_CS_DATA_5:
+	case FSL_XCVR_DEBUG_REG_0:
+	case FSL_XCVR_DEBUG_REG_1:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool fsl_xcvr_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case FSL_XCVR_EXT_CTRL:
+	case FSL_XCVR_EXT_IER0:
+	case FSL_XCVR_EXT_IER1:
+	case FSL_XCVR_EXT_ISR:
+	case FSL_XCVR_EXT_ISR_SET:
+	case FSL_XCVR_EXT_ISR_CLR:
+	case FSL_XCVR_EXT_ISR_TOG:
+	case FSL_XCVR_IER:
+	case FSL_XCVR_ISR_SET:
+	case FSL_XCVR_ISR_CLR:
+	case FSL_XCVR_ISR_TOG:
+	case FSL_XCVR_PHY_AI_CTRL:
+	case FSL_XCVR_PHY_AI_CTRL_SET:
+	case FSL_XCVR_PHY_AI_CTRL_CLR:
+	case FSL_XCVR_PHY_AI_CTRL_TOG:
+	case FSL_XCVR_PHY_AI_WDATA:
+	case FSL_XCVR_CLK_CTRL:
+	case FSL_XCVR_RX_DPTH_CTRL:
+	case FSL_XCVR_RX_DPTH_CTRL_SET:
+	case FSL_XCVR_RX_DPTH_CTRL_CLR:
+	case FSL_XCVR_RX_DPTH_CTRL_TOG:
+	case FSL_XCVR_TX_DPTH_CTRL_SET:
+	case FSL_XCVR_TX_DPTH_CTRL_CLR:
+	case FSL_XCVR_TX_DPTH_CTRL_TOG:
+	case FSL_XCVR_TX_CS_DATA_0:
+	case FSL_XCVR_TX_CS_DATA_1:
+	case FSL_XCVR_TX_CS_DATA_2:
+	case FSL_XCVR_TX_CS_DATA_3:
+	case FSL_XCVR_TX_CS_DATA_4:
+	case FSL_XCVR_TX_CS_DATA_5:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool fsl_xcvr_volatile_reg(struct device *dev, unsigned int reg)
+{
+	return fsl_xcvr_readable_reg(dev, reg);
+}
+
+static const struct regmap_config fsl_xcvr_regmap_cfg = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = FSL_XCVR_MAX_REG,
+	.reg_defaults = fsl_xcvr_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(fsl_xcvr_reg_defaults),
+	.readable_reg = fsl_xcvr_readable_reg,
+	.volatile_reg = fsl_xcvr_volatile_reg,
+	.writeable_reg = fsl_xcvr_writeable_reg,
+	.cache_type = REGCACHE_FLAT,
+};
+
+static irqreturn_t irq0_isr(int irq, void *devid)
+{
+	struct fsl_xcvr *xcvr = (struct fsl_xcvr *)devid;
+	struct device *dev = &xcvr->pdev->dev;
+	struct regmap *regmap = xcvr->regmap;
+	void __iomem *reg_ctrl, *reg_buff;
+	u32 isr, val, i;
+
+	regmap_read(regmap, FSL_XCVR_EXT_ISR, &isr);
+	regmap_write(regmap, FSL_XCVR_EXT_ISR_CLR, isr);
+
+	if (isr & FSL_XCVR_IRQ_NEW_CS) {
+		dev_dbg(dev, "Received new CS block\n");
+		/* Data RAM is 4KiB, last two pages: 8 and 9. Select page 8. */
+		regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+				   FSL_XCVR_EXT_CTRL_PAGE_MASK,
+				   FSL_XCVR_EXT_CTRL_PAGE(8));
+
+		/* Find updated CS buffer */
+		reg_ctrl = xcvr->ram_addr + FSL_XCVR_RX_CS_CTRL_0;
+		reg_buff = xcvr->ram_addr + FSL_XCVR_RX_CS_BUFF_0;
+		memcpy_fromio(&val, reg_ctrl, sizeof(val));
+		if (!val) {
+			reg_ctrl = xcvr->ram_addr + FSL_XCVR_RX_CS_CTRL_1;
+			reg_buff = xcvr->ram_addr + FSL_XCVR_RX_CS_BUFF_1;
+			memcpy_fromio(&val, reg_ctrl, sizeof(val));
+		}
+
+		if (val) {
+			/* copy CS buffer */
+			memcpy_fromio(&xcvr->rx_iec958.status, reg_buff,
+				      sizeof(xcvr->rx_iec958.status));
+			for (i = 0; i < 6; i++) {
+				val = *(u32 *)(xcvr->rx_iec958.status + i*4);
+				*(u32 *)(xcvr->rx_iec958.status + i*4) =
+					bitrev32(val);
+			}
+			/* clear CS control register */
+			memset_io(reg_ctrl, 0, sizeof(val));
+		}
+	}
+	if (isr & FSL_XCVR_IRQ_NEW_UD)
+		dev_dbg(dev, "Received new UD block\n");
+	if (isr & FSL_XCVR_IRQ_MUTE)
+		dev_dbg(dev, "HW mute bit detected\n");
+	if (isr & FSL_XCVR_IRQ_FIFO_UOFL_ERR)
+		dev_dbg(dev, "RX/TX FIFO full/empty\n");
+	if (isr & FSL_XCVR_IRQ_ARC_MODE)
+		dev_dbg(dev, "CMDC SM falls out of eARC mode\n");
+	if (isr & FSL_XCVR_IRQ_DMA_RD_REQ)
+		dev_dbg(dev, "DMA read request\n");
+	if (isr & FSL_XCVR_IRQ_DMA_WR_REQ)
+		dev_dbg(dev, "DMA write request\n");
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t irq1_isr(int irq, void *devid)
+{
+	struct fsl_xcvr *xcvr = (struct fsl_xcvr *)devid;
+	struct device *dev = &xcvr->pdev->dev;
+
+	dev_dbg(dev, "irq[1]: %d\n", irq);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t irq2_isr(int irq, void *devid)
+{
+	struct fsl_xcvr *xcvr = (struct fsl_xcvr *)devid;
+	struct device *dev = &xcvr->pdev->dev;
+
+	dev_dbg(dev, "irq[2]: %d\n", irq);
+
+	return IRQ_HANDLED;
+}
+
+static const struct of_device_id fsl_xcvr_dt_ids[] = {
+	{ .compatible = "fsl,imx8mp-xcvr", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, fsl_xcvr_dt_ids);
+
+static int fsl_xcvr_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	const struct of_device_id *of_id;
+	struct fsl_xcvr *xcvr;
+	struct resource *ram_res, *regs_res, *rx_res, *tx_res;
+	void __iomem *regs;
+	int ret, irq;
+
+	of_id = of_match_device(fsl_xcvr_dt_ids, dev);
+	if (!of_id)
+		return -EINVAL;
+
+	xcvr = devm_kzalloc(dev, sizeof(*xcvr), GFP_KERNEL);
+	if (!xcvr)
+		return -ENOMEM;
+
+	xcvr->pdev = pdev;
+	xcvr->ipg_clk = devm_clk_get(dev, "ipg");
+	if (IS_ERR(xcvr->ipg_clk)) {
+		dev_err(dev, "failed to get ipg clock\n");
+		return PTR_ERR(xcvr->ipg_clk);
+	}
+
+	xcvr->phy_clk = devm_clk_get(dev, "phy");
+	if (IS_ERR(xcvr->phy_clk)) {
+		dev_err(dev, "failed to get phy clock\n");
+		return PTR_ERR(xcvr->phy_clk);
+	}
+
+	xcvr->spba_clk = devm_clk_get(dev, "spba");
+	if (IS_ERR(xcvr->spba_clk)) {
+		dev_err(dev, "failed to get spba clock\n");
+		return PTR_ERR(xcvr->spba_clk);
+	}
+
+	xcvr->pll_ipg_clk = devm_clk_get(dev, "pll_ipg");
+	if (IS_ERR(xcvr->pll_ipg_clk)) {
+		dev_err(dev, "failed to get pll_ipg clock\n");
+		return PTR_ERR(xcvr->pll_ipg_clk);
+	}
+
+	ram_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ram");
+	xcvr->ram_addr = devm_ioremap_resource(dev, ram_res);
+	if (IS_ERR(xcvr->ram_addr))
+		return PTR_ERR(xcvr->ram_addr);
+
+	regs_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
+	regs = devm_ioremap_resource(dev, regs_res);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	xcvr->regmap = devm_regmap_init_mmio_clk(dev, NULL, regs,
+						 &fsl_xcvr_regmap_cfg);
+	if (IS_ERR(xcvr->regmap)) {
+		dev_err(dev, "failed to init XCVR regmap: %ld\n",
+			PTR_ERR(xcvr->regmap));
+		return PTR_ERR(xcvr->regmap);
+	}
+
+	xcvr->reset = of_reset_control_get(np, NULL);
+
+	ret = of_property_read_string(np, "firmware-name", &xcvr->fw_name);
+	if (ret) {
+		dev_err(dev, "failed to get fsl,xcvr-fw: %d\n", ret);
+		return ret;
+	}
+
+	/* get IRQs */
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(dev, "no irq[0]: %d\n", irq);
+		return irq;
+	}
+
+	ret = devm_request_irq(dev, irq, irq0_isr, 0, pdev->name, xcvr);
+	if (ret) {
+		dev_err(dev, "failed to claim IRQ0: %i\n", ret);
+		return ret;
+	}
+
+	irq = platform_get_irq(pdev, 1);
+	if (irq < 0) {
+		dev_err(dev, "no irq[1]: %d\n", irq);
+		return irq;
+	}
+
+	ret = devm_request_irq(dev, irq, irq1_isr, 0, pdev->name, xcvr);
+	if (ret) {
+		dev_err(dev, "failed to claim IRQ1: %i\n", ret);
+		return ret;
+	}
+
+	irq = platform_get_irq(pdev, 2);
+	if (irq < 0) {
+		dev_err(dev, "no irq[2]: %d\n", irq);
+		return irq;
+	}
+
+	ret = devm_request_irq(dev, irq, irq2_isr, 0, pdev->name, xcvr);
+	if (ret) {
+		dev_err(dev, "failed to claim IRQ2: %i\n", ret);
+		return ret;
+	}
+
+	rx_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rxfifo");
+	tx_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "txfifo");
+	xcvr->dma_prms_rx.chan_name = "rx";
+	xcvr->dma_prms_tx.chan_name = "tx";
+	xcvr->dma_prms_rx.addr = rx_res->start;
+	xcvr->dma_prms_tx.addr = tx_res->start;
+	xcvr->dma_prms_rx.maxburst = FSL_XCVR_MAXBURST_RX;
+	xcvr->dma_prms_tx.maxburst = FSL_XCVR_MAXBURST_TX;
+
+	platform_set_drvdata(pdev, xcvr);
+	pm_runtime_enable(dev);
+	regcache_cache_only(xcvr->regmap, true);
+
+	ret = devm_snd_soc_register_component(dev, &fsl_xcvr_comp,
+					      &fsl_xcvr_dai, 1);
+	if (ret) {
+		dev_err(dev, "failed to register component %s\n",
+			fsl_xcvr_comp.name);
+		return ret;
+	}
+
+	ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0);
+	if (ret)
+		dev_err(dev, "failed to pcm register\n");
+
+	return ret;
+}
+
+#ifdef CONFIG_PM
+static int fsl_xcvr_runtime_suspend(struct device *dev)
+{
+	struct fsl_xcvr *xcvr = dev_get_drvdata(dev);
+	int ret;
+
+	/* Assert M0+ reset */
+	ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+				 FSL_XCVR_EXT_CTRL_CORE_RESET,
+				 FSL_XCVR_EXT_CTRL_CORE_RESET);
+	if (ret < 0)
+		dev_err(dev, "Failed to assert M0+ core: %d\n", ret);
+
+	regcache_cache_only(xcvr->regmap, true);
+
+	clk_disable_unprepare(xcvr->spba_clk);
+	clk_disable_unprepare(xcvr->phy_clk);
+	clk_disable_unprepare(xcvr->pll_ipg_clk);
+	clk_disable_unprepare(xcvr->ipg_clk);
+
+	return 0;
+}
+
+static int fsl_xcvr_runtime_resume(struct device *dev)
+{
+	struct fsl_xcvr *xcvr = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_prepare_enable(xcvr->ipg_clk);
+	if (ret) {
+		dev_err(dev, "failed to start IPG clock.\n");
+		return ret;
+	}
+
+	ret = clk_prepare_enable(xcvr->pll_ipg_clk);
+	if (ret) {
+		dev_err(dev, "failed to start PLL IPG clock.\n");
+		return ret;
+	}
+
+	ret = clk_prepare_enable(xcvr->phy_clk);
+	if (ret) {
+		dev_err(dev, "failed to start PHY clock: %d\n", ret);
+		clk_disable_unprepare(xcvr->ipg_clk);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(xcvr->spba_clk);
+	if (ret) {
+		dev_err(dev, "failed to start SPBA clock.\n");
+		clk_disable_unprepare(xcvr->phy_clk);
+		clk_disable_unprepare(xcvr->ipg_clk);
+		return ret;
+	}
+
+	regcache_cache_only(xcvr->regmap, false);
+	regcache_mark_dirty(xcvr->regmap);
+	ret = regcache_sync(xcvr->regmap);
+
+	if (ret) {
+		dev_err(dev, "failed to sync regcache.\n");
+		return ret;
+	}
+
+	reset_control_assert(xcvr->reset);
+	reset_control_deassert(xcvr->reset);
+
+	ret = fsl_xcvr_load_firmware(xcvr);
+	if (ret) {
+		dev_err(dev, "failed to load firmware.\n");
+		return ret;
+	}
+
+	/* Release M0+ reset */
+	ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+				 FSL_XCVR_EXT_CTRL_CORE_RESET, 0);
+	if (ret < 0) {
+		dev_err(dev, "M0+ core release failed: %d\n", ret);
+		return ret;
+	}
+	mdelay(50);
+
+	return 0;
+}
+#endif /* CONFIG_PM*/
+
+static const struct dev_pm_ops fsl_xcvr_pm_ops = {
+	SET_RUNTIME_PM_OPS(fsl_xcvr_runtime_suspend,
+			   fsl_xcvr_runtime_resume,
+			   NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static struct platform_driver fsl_xcvr_driver = {
+	.probe = fsl_xcvr_probe,
+	.driver = {
+		.name = "fsl,imx8mp-audio-xcvr",
+		.pm = &fsl_xcvr_pm_ops,
+		.of_match_table = fsl_xcvr_dt_ids,
+	},
+};
+module_platform_driver(fsl_xcvr_driver);
+
+MODULE_AUTHOR("Viorel Suman <viorel.suman@nxp.com>");
+MODULE_DESCRIPTION("NXP Audio Transceiver (XCVR) driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/fsl_xcvr.h b/sound/soc/fsl/fsl_xcvr.h
new file mode 100644
index 00000000..7f2853c
--- /dev/null
+++ b/sound/soc/fsl/fsl_xcvr.h
@@ -0,0 +1,266 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * NXP XCVR ALSA SoC Digital Audio Interface (DAI) driver
+ *
+ * Copyright 2019 NXP
+ */
+
+#ifndef __FSL_XCVR_H
+#define __FSL_XCVR_H
+
+#define FSL_XCVR_MODE_SPDIF	0
+#define FSL_XCVR_MODE_ARC	1
+#define FSL_XCVR_MODE_EARC	2
+
+/* XCVR Registers */
+#define FSL_XCVR_REG_OFFSET		0x800 /* regs offset */
+#define FSL_XCVR_FIFO_SIZE		0x80  /* 128 */
+#define FSL_XCVR_FIFO_WMK_RX		(FSL_XCVR_FIFO_SIZE >> 1)   /* 64 */
+#define FSL_XCVR_FIFO_WMK_TX		(FSL_XCVR_FIFO_SIZE >> 1)   /* 64 */
+#define FSL_XCVR_MAXBURST_RX		(FSL_XCVR_FIFO_WMK_RX >> 2) /* 16 */
+#define FSL_XCVR_MAXBURST_TX		(FSL_XCVR_FIFO_WMK_TX >> 2) /* 16 */
+
+#define FSL_XCVR_RX_FIFO_ADDR		0x0C00
+#define FSL_XCVR_TX_FIFO_ADDR		0x0E00
+
+#define FSL_XCVR_VERSION		0x00  /* Version */
+#define FSL_XCVR_EXT_CTRL		0x10  /* Control */
+#define FSL_XCVR_EXT_STATUS		0x20  /* Status */
+#define FSL_XCVR_EXT_IER0		0x30  /* Interrupt en 0 */
+#define FSL_XCVR_EXT_IER1		0x40  /* Interrupt en 1 */
+#define FSL_XCVR_EXT_ISR		0x50  /* Interrupt status */
+#define FSL_XCVR_EXT_ISR_SET		0x54  /* Interrupt status */
+#define FSL_XCVR_EXT_ISR_CLR		0x58  /* Interrupt status */
+#define FSL_XCVR_EXT_ISR_TOG		0x5C  /* Interrupt status */
+#define FSL_XCVR_IER			0x70  /* Interrupt en for M0+ */
+#define FSL_XCVR_ISR			0x80  /* Interrupt status */
+#define FSL_XCVR_ISR_SET		0x84  /* Interrupt status set */
+#define FSL_XCVR_ISR_CLR		0x88  /* Interrupt status clear */
+#define FSL_XCVR_ISR_TOG		0x8C  /* Interrupt status toggle */
+#define FSL_XCVR_PHY_AI_CTRL		0x90
+#define FSL_XCVR_PHY_AI_CTRL_SET	0x94
+#define FSL_XCVR_PHY_AI_CTRL_CLR	0x98
+#define FSL_XCVR_PHY_AI_CTRL_TOG	0x9C
+#define FSL_XCVR_PHY_AI_WDATA		0xA0
+#define FSL_XCVR_PHY_AI_RDATA		0xA4
+#define FSL_XCVR_CLK_CTRL		0xB0
+#define FSL_XCVR_RX_DPTH_CTRL		0x180 /* RX datapath ctrl reg */
+#define FSL_XCVR_RX_DPTH_CTRL_SET	0x184
+#define FSL_XCVR_RX_DPTH_CTRL_CLR	0x188
+#define FSL_XCVR_RX_DPTH_CTRL_TOG	0x18c
+
+#define FSL_XCVR_TX_DPTH_CTRL		0x220 /* TX datapath ctrl reg */
+#define FSL_XCVR_TX_DPTH_CTRL_SET	0x224
+#define FSL_XCVR_TX_DPTH_CTRL_CLR	0x228
+#define FSL_XCVR_TX_DPTH_CTRL_TOG	0x22C
+#define FSL_XCVR_TX_CS_DATA_0		0x230 /* TX channel status bits regs */
+#define FSL_XCVR_TX_CS_DATA_1		0x234
+#define FSL_XCVR_TX_CS_DATA_2		0x238
+#define FSL_XCVR_TX_CS_DATA_3		0x23C
+#define FSL_XCVR_TX_CS_DATA_4		0x240
+#define FSL_XCVR_TX_CS_DATA_5		0x244
+#define FSL_XCVR_DEBUG_REG_0		0x2E0
+#define FSL_XCVR_DEBUG_REG_1		0x2F0
+
+#define FSL_XCVR_MAX_REG		FSL_XCVR_DEBUG_REG_1
+
+#define FSL_XCVR_EXT_CTRL_CORE_RESET	BIT(31)
+
+#define FSL_XCVR_EXT_CTRL_RX_CMDC_RESET	BIT(30)
+#define FSL_XCVR_EXT_CTRL_TX_CMDC_RESET	BIT(29)
+#define FSL_XCVR_EXT_CTRL_CMDC_RESET(t) (t ? BIT(29) : BIT(30))
+
+#define FSL_XCVR_EXT_CTRL_RX_DPTH_RESET	BIT(28)
+#define FSL_XCVR_EXT_CTRL_TX_DPTH_RESET	BIT(27)
+#define FSL_XCVR_EXT_CTRL_DPTH_RESET(t) (t ? BIT(27) : BIT(28))
+
+#define FSL_XCVR_EXT_CTRL_TX_RX_MODE	BIT(26)
+#define FSL_XCVR_EXT_CTRL_DMA_RD_DIS	BIT(25)
+#define FSL_XCVR_EXT_CTRL_DMA_WR_DIS	BIT(24)
+#define FSL_XCVR_EXT_CTRL_DMA_DIS(t)	(t ? BIT(24) : BIT(25))
+#define FSL_XCVR_EXT_CTRL_SPDIF_MODE	BIT(23)
+#define FSL_XCVR_EXT_CTRL_SLEEP_MODE	BIT(21)
+
+#define FSL_XCVR_EXT_CTRL_TX_FWM_SHFT	0
+#define FSL_XCVR_EXT_CTRL_TX_FWM_MASK	GENMASK(6, 0)
+#define FSL_XCVR_EXT_CTRL_TX_FWM(i)	(((i) << FSL_XCVR_EXT_CTRL_TX_FWM_SHFT) \
+					  & FSL_XCVR_EXT_CTRL_TX_FWM_MASK)
+#define FSL_XCVR_EXT_CTRL_RX_FWM_SHFT	8
+#define FSL_XCVR_EXT_CTRL_RX_FWM_MASK	GENMASK(14, 8)
+#define FSL_XCVR_EXT_CTRL_RX_FWM(i)	(((i) << FSL_XCVR_EXT_CTRL_RX_FWM_SHFT) \
+					  & FSL_XCVR_EXT_CTRL_RX_FWM_MASK)
+#define FSL_XCVR_EXT_CTRL_PAGE_SHFT	16
+#define FSL_XCVR_EXT_CTRL_PAGE_MASK	GENMASK(19, 16)
+#define FSL_XCVR_EXT_CTRL_PAGE(i)	(((i) << FSL_XCVR_EXT_CTRL_PAGE_SHFT) \
+					  & FSL_XCVR_EXT_CTRL_PAGE_MASK)
+
+#define FSL_XCVR_EXT_STUS_NT_FIFO_ENTR	GENMASK(7, 0)
+#define FSL_XCVR_EXT_STUS_NR_FIFO_ENTR	GENMASK(15, 8)
+#define FSL_XCVR_EXT_STUS_CM0_SLEEPING	BIT(16)
+#define FSL_XCVR_EXT_STUS_CM0_DEEP_SLP	BIT(17)
+#define FSL_XCVR_EXT_STUS_CM0_SLP_HACK	BIT(18)
+#define FSL_XCVR_EXT_STUS_RX_CMDC_RSTO	BIT(23)
+#define FSL_XCVR_EXT_STUS_TX_CMDC_RSTO	BIT(24)
+#define FSL_XCVR_EXT_STUS_RX_CMDC_COTO	BIT(25)
+#define FSL_XCVR_EXT_STUS_TX_CMDC_COTO	BIT(26)
+#define FSL_XCVR_EXT_STUS_HB_STATUS	BIT(27)
+#define FSL_XCVR_EXT_STUS_NEW_UD4_REC	BIT(28)
+#define FSL_XCVR_EXT_STUS_NEW_UD5_REC	BIT(29)
+#define FSL_XCVR_EXT_STUS_NEW_UD6_REC	BIT(30)
+#define FSL_XCVR_EXT_STUS_HPD_INPUT	BIT(31)
+
+#define FSL_XCVR_IRQ_NEW_CS		BIT(0)
+#define FSL_XCVR_IRQ_NEW_UD		BIT(1)
+#define FSL_XCVR_IRQ_MUTE		BIT(2)
+#define FSL_XCVR_IRQ_CMDC_RESP_TO	BIT(3)
+#define FSL_XCVR_IRQ_ECC_ERR		BIT(4)
+#define FSL_XCVR_IRQ_PREAMBLE_MISMATCH	BIT(5)
+#define FSL_XCVR_IRQ_FIFO_UOFL_ERR	BIT(6)
+#define FSL_XCVR_IRQ_HOST_WAKEUP	BIT(7)
+#define FSL_XCVR_IRQ_HOST_OHPD		BIT(8)
+#define FSL_XCVR_IRQ_DMAC_NO_DATA_REC	BIT(9)
+#define FSL_XCVR_IRQ_DMAC_FMT_CHG_DET	BIT(10)
+#define FSL_XCVR_IRQ_HB_STATE_CHG	BIT(11)
+#define FSL_XCVR_IRQ_CMDC_STATUS_UPD	BIT(12)
+#define FSL_XCVR_IRQ_TEMP_UPD		BIT(13)
+#define FSL_XCVR_IRQ_DMA_RD_REQ		BIT(14)
+#define FSL_XCVR_IRQ_DMA_WR_REQ		BIT(15)
+#define FSL_XCVR_IRQ_DMAC_BME_BIT_ERR	BIT(16)
+#define FSL_XCVR_IRQ_PREAMBLE_MATCH	BIT(17)
+#define FSL_XCVR_IRQ_M_W_PRE_MISMATCH	BIT(18)
+#define FSL_XCVR_IRQ_B_PRE_MISMATCH	BIT(19)
+#define FSL_XCVR_IRQ_UNEXP_PRE_REC	BIT(20)
+#define FSL_XCVR_IRQ_ARC_MODE		BIT(21)
+#define FSL_XCVR_IRQ_CH_UD_OFLOW	BIT(22)
+#define FSL_XCVR_IRQ_EARC_ALL		(FSL_XCVR_IRQ_NEW_CS | \
+					 FSL_XCVR_IRQ_NEW_UD | \
+					 FSL_XCVR_IRQ_MUTE | \
+					 FSL_XCVR_IRQ_FIFO_UOFL_ERR | \
+					 FSL_XCVR_IRQ_HOST_WAKEUP | \
+					 FSL_XCVR_IRQ_ARC_MODE)
+
+#define FSL_XCVR_ISR_CMDC_TX_EN		BIT(3)
+#define FSL_XCVR_ISR_HPD_TGL		BIT(15)
+#define FSL_XCVR_ISR_DMAC_SPARE_INT	BIT(19)
+#define FSL_XCVR_ISR_SET_SPDIF_RX_INT	BIT(20)
+#define FSL_XCVR_ISR_SET_SPDIF_TX_INT	BIT(21)
+#define FSL_XCVR_ISR_SET_SPDIF_MODE(t)	(t ? BIT(21) : BIT(20))
+#define FSL_XCVR_ISR_SET_ARC_CM_INT	BIT(22)
+#define FSL_XCVR_ISR_SET_ARC_SE_INT	BIT(23)
+
+#define FSL_XCVR_PHY_AI_ADDR_MASK	GENMASK(7, 0)
+#define FSL_XCVR_PHY_AI_RESETN		BIT(15)
+#define FSL_XCVR_PHY_AI_TOG_PLL		BIT(24)
+#define FSL_XCVR_PHY_AI_TOG_DONE_PLL	BIT(25)
+#define FSL_XCVR_PHY_AI_TOG_PHY		BIT(26)
+#define FSL_XCVR_PHY_AI_TOG_DONE_PHY	BIT(27)
+#define FSL_XCVR_PHY_AI_RW_MASK		BIT(31)
+
+#define FSL_XCVR_RX_DPTH_CTRL_PAPB_FIFO_STATUS	BIT(0)
+#define FSL_XCVR_RX_DPTH_CTRL_DIS_PRE_ERR_CHK	BIT(1)
+#define FSL_XCVR_RX_DPTH_CTRL_DIS_NOD_REC_CHK	BIT(2)
+#define FSL_XCVR_RX_DPTH_CTRL_ECC_VUC_BIT_CHK	BIT(3)
+#define FSL_XCVR_RX_DPTH_CTRL_EN_CMP_PAR_CALC	BIT(4)
+#define FSL_XCVR_RX_DPTH_CTRL_RST_PKT_CNT_FIFO	BIT(5)
+#define FSL_XCVR_RX_DPTH_CTRL_STORE_FMT		BIT(6)
+#define FSL_XCVR_RX_DPTH_CTRL_EN_PAR_CALC	BIT(7)
+#define FSL_XCVR_RX_DPTH_CTRL_UDR		BIT(8)
+#define FSL_XCVR_RX_DPTH_CTRL_CSR		BIT(9)
+#define FSL_XCVR_RX_DPTH_CTRL_UDA		BIT(10)
+#define FSL_XCVR_RX_DPTH_CTRL_CSA		BIT(11)
+#define FSL_XCVR_RX_DPTH_CTRL_CLR_RX_FIFO	BIT(12)
+#define FSL_XCVR_RX_DPTH_CTRL_DIS_B_PRE_ERR_CHK	BIT(13)
+#define FSL_XCVR_RX_DPTH_CTRL_PABS		BIT(19)
+#define FSL_XCVR_RX_DPTH_CTRL_DTS_CDS		BIT(20)
+#define FSL_XCVR_RX_DPTH_CTRL_BLKC		BIT(21)
+#define FSL_XCVR_RX_DPTH_CTRL_MUTE_CTRL		BIT(22)
+#define FSL_XCVR_RX_DPTH_CTRL_MUTE_MODE		BIT(23)
+#define FSL_XCVR_RX_DPTH_CTRL_FMT_CHG_CTRL	BIT(24)
+#define FSL_XCVR_RX_DPTH_CTRL_FMT_CHG_MODE	BIT(25)
+#define FSL_XCVR_RX_DPTH_CTRL_LAYB_CTRL		BIT(26)
+#define FSL_XCVR_RX_DPTH_CTRL_LAYB_MODE		BIT(27)
+#define FSL_XCVR_RX_DPTH_CTRL_PRC		BIT(28)
+#define FSL_XCVR_RX_DPTH_CTRL_COMP		BIT(29)
+#define FSL_XCVR_RX_DPTH_CTRL_FSM		GENMASK(31, 30)
+
+#define FSL_XCVR_TX_DPTH_CTRL_CS_ACK		BIT(0)
+#define FSL_XCVR_TX_DPTH_CTRL_UD_ACK		BIT(1)
+#define FSL_XCVR_TX_DPTH_CTRL_CS_MOD		BIT(2)
+#define FSL_XCVR_TX_DPTH_CTRL_UD_MOD		BIT(3)
+#define FSL_XCVR_TX_DPTH_CTRL_VLD_MOD		BIT(4)
+#define FSL_XCVR_TX_DPTH_CTRL_FRM_VLD		BIT(5)
+#define FSL_XCVR_TX_DPTH_CTRL_EN_PARITY		BIT(6)
+#define FSL_XCVR_TX_DPTH_CTRL_EN_PREAMBLE	BIT(7)
+#define FSL_XCVR_TX_DPTH_CTRL_EN_ECC_INTER	BIT(8)
+#define FSL_XCVR_TX_DPTH_CTRL_BYPASS_FEM	BIT(10)
+#define FSL_XCVR_TX_DPTH_CTRL_FRM_FMT		BIT(11)
+#define FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX	BIT(14)
+#define FSL_XCVR_TX_DPTH_CTRL_ADD_CYC_TX_OE_STR	BIT(15)
+#define FSL_XCVR_TX_DPTH_CTRL_ADD_CYC_TX_OE_END	BIT(16)
+#define FSL_XCVR_TX_DPTH_CTRL_CLK_RATIO		BIT(29)
+#define FSL_XCVR_TX_DPTH_CTRL_TM_NO_PRE_BME	GENMASK(31, 30)
+
+#define FSL_XCVR_PHY_AI_CTRL_AI_RESETN		BIT(15)
+
+#define FSL_XCVR_PLL_CTRL0			0x00
+#define FSL_XCVR_PLL_CTRL0_SET			0x04
+#define FSL_XCVR_PLL_CTRL0_CLR			0x08
+#define FSL_XCVR_PLL_NUM			0x20
+#define FSL_XCVR_PLL_DEN			0x30
+#define FSL_XCVR_PLL_PDIV			0x40
+#define FSL_XCVR_PLL_BANDGAP_SET		0x54
+#define FSL_XCVR_PHY_CTRL			0x00
+#define FSL_XCVR_PHY_CTRL_SET			0x04
+#define FSL_XCVR_PHY_CTRL_CLR			0x08
+#define FSL_XCVR_PHY_CTRL2			0x70
+#define FSL_XCVR_PHY_CTRL2_SET			0x74
+#define FSL_XCVR_PHY_CTRL2_CLR			0x78
+
+#define FSL_XCVR_PLL_BANDGAP_EN_VBG		BIT(0)
+#define FSL_XCVR_PLL_CTRL0_HROFF		BIT(13)
+#define FSL_XCVR_PLL_CTRL0_PWP			BIT(14)
+#define FSL_XCVR_PLL_CTRL0_CM0_EN		BIT(24)
+#define FSL_XCVR_PLL_CTRL0_CM1_EN		BIT(25)
+#define FSL_XCVR_PLL_CTRL0_CM2_EN		BIT(26)
+#define FSL_XCVR_PLL_PDIVx(v, i)		((v & 0x7) << (4 * i))
+
+#define FSL_XCVR_PHY_CTRL_PHY_EN		BIT(0)
+#define FSL_XCVR_PHY_CTRL_RX_CM_EN		BIT(1)
+#define FSL_XCVR_PHY_CTRL_TSDIFF_OE		BIT(5)
+#define FSL_XCVR_PHY_CTRL_SPDIF_EN		BIT(8)
+#define FSL_XCVR_PHY_CTRL_ARC_MODE_SE_EN	BIT(9)
+#define FSL_XCVR_PHY_CTRL_ARC_MODE_CM_EN	BIT(10)
+#define FSL_XCVR_PHY_CTRL_TX_CLK_MASK		GENMASK(26, 25)
+#define FSL_XCVR_PHY_CTRL_TX_CLK_HDMI_SS	BIT(25)
+#define FSL_XCVR_PHY_CTRL_TX_CLK_AUD_SS		BIT(26)
+#define FSL_XCVR_PHY_CTRL2_EARC_TXMS		BIT(14)
+
+#define FSL_XCVR_CS_DATA_0_FS_MASK		GENMASK(31, 24)
+#define FSL_XCVR_CS_DATA_0_FS_32000		0x3000000
+#define FSL_XCVR_CS_DATA_0_FS_44100		0x0000000
+#define FSL_XCVR_CS_DATA_0_FS_48000		0x2000000
+#define FSL_XCVR_CS_DATA_0_FS_64000		0xB000000
+#define FSL_XCVR_CS_DATA_0_FS_88200		0x8000000
+#define FSL_XCVR_CS_DATA_0_FS_96000		0xA000000
+#define FSL_XCVR_CS_DATA_0_FS_176400		0xC000000
+#define FSL_XCVR_CS_DATA_0_FS_192000		0xE000000
+
+#define FSL_XCVR_CS_DATA_0_CH_MASK		0x3A
+#define FSL_XCVR_CS_DATA_0_CH_U2LPCM		0x00
+#define FSL_XCVR_CS_DATA_0_CH_UMLPCM		0x20
+#define FSL_XCVR_CS_DATA_0_CH_U1BAUD		0x30
+
+#define FSL_XCVR_CS_DATA_1_CH_MASK		0xF000
+#define FSL_XCVR_CS_DATA_1_CH_2			0x0000
+#define FSL_XCVR_CS_DATA_1_CH_8			0x7000
+#define FSL_XCVR_CS_DATA_1_CH_16		0xB000
+#define FSL_XCVR_CS_DATA_1_CH_32		0x3000
+
+/* Data memory structures */
+#define FSL_XCVR_RX_CS_CTRL_0		0x20 /* First  RX CS control register */
+#define FSL_XCVR_RX_CS_CTRL_1		0x24 /* Second RX CS control register */
+#define FSL_XCVR_RX_CS_BUFF_0		0x80 /* First  RX CS buffer */
+#define FSL_XCVR_RX_CS_BUFF_1		0xA0 /* Second RX CS buffer */
+#define FSL_XCVR_CAP_DATA_STR		0x300 /* Capabilities data structure */
+
+#endif /* __FSL_XCVR_H */
-- 
2.7.4


^ permalink raw reply related

* [PATCH 0/2] DAI driver for new XCVR IP
From: Viorel Suman (OSS) @ 2020-09-16  9:17 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Jaroslav Kysela,
	Takashi Iwai, Timur Tabi, Nicolin Chen, Xiubo Li, Fabio Estevam,
	Shengjiu Wang, Philipp Zabel, Matthias Schiffer,
	Cosmin-Gabriel Samoila, Viorel Suman, alsa-devel, devicetree,
	linux-kernel, linuxppc-dev
  Cc: Viorel Suman, NXP Linux Team

From: Viorel Suman <viorel.suman@nxp.com>

DAI driver for new XCVR IP found in i.MX8MP.

Viorel Suman (2):
  ASoC: fsl_xcvr: Add XCVR ASoC CPU DAI driver
  ASoC: dt-bindings: fsl_xcvr: Add document for XCVR

 .../devicetree/bindings/sound/fsl,xcvr.yaml        |  104 ++
 sound/soc/fsl/Kconfig                              |   10 +
 sound/soc/fsl/Makefile                             |    2 +
 sound/soc/fsl/fsl_xcvr.c                           | 1352 ++++++++++++++++++++
 sound/soc/fsl/fsl_xcvr.h                           |  266 ++++
 5 files changed, 1734 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/fsl,xcvr.yaml
 create mode 100644 sound/soc/fsl/fsl_xcvr.c
 create mode 100644 sound/soc/fsl/fsl_xcvr.h

-- 
2.7.4


^ permalink raw reply

* Re: [PATCH] Revert "powerpc/64s: machine check interrupt update NMI accounting"
From: Michal Suchánek @ 2020-09-16  9:00 UTC (permalink / raw)
  To: peterz
  Cc: Aneesh Kumar K.V, Santosh Sivaraj, Alistair Popple,
	Greg Kroah-Hartman, Mahesh Salgaonkar, Nicholas Piggin,
	linux-kernel, Jordan Niethe, Paul Mackerras, Ganesh Goudar,
	stable, linuxppc-dev, Mike Rapoport
In-Reply-To: <20200915181642.GF2674@hirez.programming.kicks-ass.net>

On Tue, Sep 15, 2020 at 08:16:42PM +0200, peterz@infradead.org wrote:
> On Tue, Sep 15, 2020 at 08:06:59PM +0200, Michal Suchanek wrote:
> > This reverts commit 116ac378bb3ff844df333e7609e7604651a0db9d.
> > 
> > This commit causes the kernel to oops and reboot when injecting a SLB
> > multihit which causes a MCE.
> > 
> > Before this commit a SLB multihit was corrected by the kernel and the
> > system continued to operate normally.
> > 
> > cc: stable@vger.kernel.org
> > Fixes: 116ac378bb3f ("powerpc/64s: machine check interrupt update NMI accounting")
> > Signed-off-by: Michal Suchanek <msuchanek@suse.de>
> 
> Ever since 69ea03b56ed2 ("hardirq/nmi: Allow nested nmi_enter()")
> nmi_enter() supports nesting natively.

And this patch was merged in parallel with this native nesting support
and conflicted with it - hence the explicit nesting in the hunk that did
not conflict.

Either way the bug is present on kernels both with and without
69ea03b56ed2. So besides the conflict 69ea03b56ed2 does not affect this
problem.

Thanks

Michal

^ permalink raw reply

* [PATCH 5/5] arm: dts: ls1021a: fix rcpm failed to claim resource
From: Ran Wang @ 2020-09-16  8:18 UTC (permalink / raw)
  To: Li Yang, Rob Herring, Shawn Guo
  Cc: devicetree, Ran Wang, linuxppc-dev, linux-kernel,
	linux-arm-kernel
In-Reply-To: <20200916081831.24747-1-ran.wang_1@nxp.com>

The range of dcfg reg is wrong, which overlap with other device,
such as rcpm. This issue causing rcpm driver failed to claim
reg resource when calling devm_ioremap_resource().

Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
---
 arch/arm/boot/dts/ls1021a.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi
index e372630f..286c547 100644
--- a/arch/arm/boot/dts/ls1021a.dtsi
+++ b/arch/arm/boot/dts/ls1021a.dtsi
@@ -173,7 +173,7 @@
 
 		dcfg: dcfg@1ee0000 {
 			compatible = "fsl,ls1021a-dcfg", "syscon";
-			reg = <0x0 0x1ee0000 0x0 0x10000>;
+			reg = <0x0 0x1ee0000 0x0 0x1000>;
 			big-endian;
 		};
 
-- 
2.7.4


^ permalink raw reply related

* [PATCH 4/5] arm: dts: ls1021a: fix flextimer failed to wake system
From: Ran Wang @ 2020-09-16  8:18 UTC (permalink / raw)
  To: Li Yang, Rob Herring, Shawn Guo
  Cc: devicetree, Ran Wang, linuxppc-dev, linux-kernel,
	linux-arm-kernel
In-Reply-To: <20200916081831.24747-1-ran.wang_1@nxp.com>

The data of property 'fsl,rcpm-wakeup' is not corrcet, which causing
RCPM driver incorrectly program register IPPDEXPCR1, then flextimer is
wrongly clock gated during system suspend, can't send interrupt to
wake.

Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
---
 arch/arm/boot/dts/ls1021a.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi
index 089fe86..e372630f 100644
--- a/arch/arm/boot/dts/ls1021a.dtsi
+++ b/arch/arm/boot/dts/ls1021a.dtsi
@@ -1014,7 +1014,7 @@
 			compatible = "fsl,ls1021a-ftm-alarm";
 			reg = <0x0 0x29d0000 0x0 0x10000>;
 			reg-names = "ftm";
-			fsl,rcpm-wakeup = <&rcpm 0x20000 0x0>;
+			fsl,rcpm-wakeup = <&rcpm 0x0 0x20000000>;
 			interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
 			big-endian;
 		};
-- 
2.7.4


^ permalink raw reply related

* [PATCH 3/5] arm: dts: ls1021a: fix that FlexTimer cannot wakeup system in deep sleep
From: Ran Wang @ 2020-09-16  8:18 UTC (permalink / raw)
  To: Li Yang, Rob Herring, Shawn Guo
  Cc: devicetree, Biwen Li, linux-kernel, Ran Wang, linuxppc-dev,
	linux-arm-kernel
In-Reply-To: <20200916081831.24747-1-ran.wang_1@nxp.com>

From: Biwen Li <biwen.li@nxp.com>

The patch fixes a bug that FlexTimer cannot
wakeup system in deep sleep.

Signed-off-by: Biwen Li <biwen.li@nxp.com>
Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
---
 arch/arm/boot/dts/ls1021a.dtsi | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi
index 827373e..089fe86 100644
--- a/arch/arm/boot/dts/ls1021a.dtsi
+++ b/arch/arm/boot/dts/ls1021a.dtsi
@@ -1007,6 +1007,7 @@
 			compatible = "fsl,ls1021a-rcpm", "fsl,qoriq-rcpm-2.1+";
 			reg = <0x0 0x1ee2140 0x0 0x8>;
 			#fsl,rcpm-wakeup-cells = <2>;
+			fsl,ippdexpcr1-alt-addr = <&scfg 0x51c>;
 		};
 
 		ftm_alarm0: timer0@29d0000 {
-- 
2.7.4


^ permalink raw reply related

* [PATCH 2/5] soc: fsl: handle RCPM errata A-008646 on SoC LS1021A
From: Ran Wang @ 2020-09-16  8:18 UTC (permalink / raw)
  To: Li Yang, Rob Herring, Shawn Guo
  Cc: devicetree, Biwen Li, linux-kernel, Ran Wang, linuxppc-dev,
	linux-arm-kernel
In-Reply-To: <20200916081831.24747-1-ran.wang_1@nxp.com>

From: Biwen Li <biwen.li@nxp.com>

Description:
	- Reading configuration register RCPM_IPPDEXPCR1
	  always return zero

Workaround:
	- Save register RCPM_IPPDEXPCR1's value to
	  register SCFG_SPARECR8.(uboot's psci also
	  need reading value from the register SCFG_SPARECR8
	  to set register RCPM_IPPDEXPCR1)

Impact:
	- FlexTimer module will cannot wakeup system in
	  deep sleep on SoC LS1021A

Signed-off-by: Biwen Li <biwen.li@nxp.com>
Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
---
 drivers/soc/fsl/rcpm.c | 42 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/drivers/soc/fsl/rcpm.c b/drivers/soc/fsl/rcpm.c
index a093dbe..e6354f5 100644
--- a/drivers/soc/fsl/rcpm.c
+++ b/drivers/soc/fsl/rcpm.c
@@ -2,7 +2,7 @@
 //
 // rcpm.c - Freescale QorIQ RCPM driver
 //
-// Copyright 2019 NXP
+// Copyright 2019-2020 NXP
 //
 // Author: Ran Wang <ran.wang_1@nxp.com>
 
@@ -13,6 +13,9 @@
 #include <linux/slab.h>
 #include <linux/suspend.h>
 #include <linux/kernel.h>
+#include <linux/acpi.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
 
 #define RCPM_WAKEUP_CELL_MAX_SIZE	7
 
@@ -37,6 +40,9 @@ static int rcpm_pm_prepare(struct device *dev)
 	struct device_node	*np = dev->of_node;
 	u32 value[RCPM_WAKEUP_CELL_MAX_SIZE + 1];
 	u32 setting[RCPM_WAKEUP_CELL_MAX_SIZE] = {0};
+	struct regmap *scfg_addr_regmap = NULL;
+	u32 reg_offset[2];
+	u32 reg_value = 0;
 
 	rcpm = dev_get_drvdata(dev);
 	if (!rcpm)
@@ -90,6 +96,40 @@ static int rcpm_pm_prepare(struct device *dev)
 			tmp |= ioread32be(address);
 			iowrite32be(tmp, address);
 		}
+		/*
+		 * Workaround of errata A-008646 on SoC LS1021A:
+		 * There is a bug of register ippdexpcr1.
+		 * Reading configuration register RCPM_IPPDEXPCR1
+		 * always return zero. So save ippdexpcr1's value
+		 * to register SCFG_SPARECR8.And the value of
+		 * ippdexpcr1 will be read from SCFG_SPARECR8.
+		 */
+		if (device_property_present(dev, "fsl,ippdexpcr1-alt-addr")) {
+			if (dev_of_node(dev)) {
+				scfg_addr_regmap = syscon_regmap_lookup_by_phandle(np,
+										   "fsl,ippdexpcr1-alt-addr");
+			} else if (is_acpi_node(dev->fwnode)) {
+				continue;
+			}
+
+			if (scfg_addr_regmap && (i == 1)) {
+				if (device_property_read_u32_array(dev,
+				    "fsl,ippdexpcr1-alt-addr",
+				    reg_offset,
+				    2)) {
+					scfg_addr_regmap = NULL;
+					continue;
+				}
+				/* Read value from register SCFG_SPARECR8 */
+				regmap_read(scfg_addr_regmap,
+					    reg_offset[1],
+					    &reg_value);
+				/* Write value to register SCFG_SPARECR8 */
+				regmap_write(scfg_addr_regmap,
+					     reg_offset[1],
+					     tmp | reg_value);
+			}
+		}
 	}
 
 	return 0;
-- 
2.7.4


^ permalink raw reply related

* [PATCH 1/5] Documentation: dt: binding: fsl: Add 'fsl, ippdexpcr1-alt-addr' property
From: Ran Wang @ 2020-09-16  8:18 UTC (permalink / raw)
  To: Li Yang, Rob Herring, Shawn Guo
  Cc: devicetree, Biwen Li, linux-kernel, Ran Wang, linuxppc-dev,
	linux-arm-kernel

From: Biwen Li <biwen.li@nxp.com>

The 'fsl,ippdexpcr1-alt-addr' property is used to handle an errata A-008646
on LS1021A

Signed-off-by: Biwen Li <biwen.li@nxp.com>
Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
---
 Documentation/devicetree/bindings/soc/fsl/rcpm.txt | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/Documentation/devicetree/bindings/soc/fsl/rcpm.txt b/Documentation/devicetree/bindings/soc/fsl/rcpm.txt
index 5a33619..1be58a3 100644
--- a/Documentation/devicetree/bindings/soc/fsl/rcpm.txt
+++ b/Documentation/devicetree/bindings/soc/fsl/rcpm.txt
@@ -34,6 +34,11 @@ Chassis Version		Example Chips
 Optional properties:
  - little-endian : RCPM register block is Little Endian. Without it RCPM
    will be Big Endian (default case).
+ - fsl,ippdexpcr1-alt-addr : The property is related to a hardware issue
+   on SoC LS1021A and only needed on SoC LS1021A.
+   Must include 2 entries:
+   The first entry must be a link to the SCFG device node.
+   The 2nd entry must be offset of register IPPDEXPCR1 in SCFG.
 
 Example:
 The RCPM node for T4240:
@@ -43,6 +48,20 @@ The RCPM node for T4240:
 		#fsl,rcpm-wakeup-cells = <2>;
 	};
 
+The RCPM node for LS1021A:
+	rcpm: rcpm@1ee2140 {
+		compatible = "fsl,ls1021a-rcpm", "fsl,qoriq-rcpm-2.1+";
+		reg = <0x0 0x1ee2140 0x0 0x8>;
+		#fsl,rcpm-wakeup-cells = <2>;
+
+		/*
+		 * The second and third entry compose an alt offset
+		 * address for IPPDEXPCR1(SCFG_SPARECR8)
+		 */
+		fsl,ippdexpcr1-alt-addr = <&scfg 0x51c>;
+	};
+
+
 * Freescale RCPM Wakeup Source Device Tree Bindings
 -------------------------------------------
 Required fsl,rcpm-wakeup property should be added to a device node if the device
-- 
2.7.4


^ permalink raw reply related

* Re: [PATCH v3] pseries/hotplug-memory: hot-add: skip redundant LMB lookup
From: Laurent Dufour @ 2020-09-16  8:22 UTC (permalink / raw)
  To: Scott Cheloha, linuxppc-dev
  Cc: Nathan Lynch, Michal Suchanek, David Hildenbrand, Rick Lindsley
In-Reply-To: <20200915194647.3334645-1-cheloha@linux.ibm.com>

Le 15/09/2020 à 21:46, Scott Cheloha a écrit :
> During memory hot-add, dlpar_add_lmb() calls memory_add_physaddr_to_nid()
> to determine which node id (nid) to use when later calling __add_memory().
> 
> This is wasteful.  On pseries, memory_add_physaddr_to_nid() finds an
> appropriate nid for a given address by looking up the LMB containing the
> address and then passing that LMB to of_drconf_to_nid_single() to get the
> nid.  In dlpar_add_lmb() we get this address from the LMB itself.
> 
> In short, we have a pointer to an LMB and then we are searching for
> that LMB *again* in order to find its nid.
> 
> If we call of_drconf_to_nid_single() directly from dlpar_add_lmb() we
> can skip the redundant lookup.  The only error handling we need to
> duplicate from memory_add_physaddr_to_nid() is the fallback to the
> default nid when drconf_to_nid_single() returns -1 (NUMA_NO_NODE) or
> an invalid nid.
> 
> Skipping the extra lookup makes hot-add operations faster, especially
> on machines with many LMBs.
> 
> Consider an LPAR with 126976 LMBs.  In one test, hot-adding 126000
> LMBs on an upatched kernel took ~3.5 hours while a patched kernel
> completed the same operation in ~2 hours:
> 
> Unpatched (12450 seconds):
> Sep  9 04:06:31 ltc-brazos1 drmgr[810169]: drmgr: -c mem -a -q 126000
> Sep  9 04:06:31 ltc-brazos1 kernel: pseries-hotplug-mem: Attempting to hot-add 126000 LMB(s)
> [...]
> Sep  9 07:34:01 ltc-brazos1 kernel: pseries-hotplug-mem: Memory at 20000000 (drc index 80000002) was hot-added
> 
> Patched (7065 seconds):
> Sep  8 21:49:57 ltc-brazos1 drmgr[877703]: drmgr: -c mem -a -q 126000
> Sep  8 21:49:57 ltc-brazos1 kernel: pseries-hotplug-mem: Attempting to hot-add 126000 LMB(s)
> [...]
> Sep  8 23:27:42 ltc-brazos1 kernel: pseries-hotplug-mem: Memory at 20000000 (drc index 80000002) was hot-added
> 
> It should be noted that the speedup grows more substantial when
> hot-adding LMBs at the end of the drconf range.  This is because we
> are skipping a linear LMB search.
> 
> To see the distinction, consider smaller hot-add test on the same
> LPAR.  A perf-stat run with 10 iterations showed that hot-adding 4096
> LMBs completed less than 1 second faster on a patched kernel:
> 
> Unpatched:
>   Performance counter stats for 'drmgr -c mem -a -q 4096' (10 runs):
> 
>          104,753.42 msec task-clock                #    0.992 CPUs utilized            ( +-  0.55% )
>               4,708      context-switches          #    0.045 K/sec                    ( +-  0.69% )
>               2,444      cpu-migrations            #    0.023 K/sec                    ( +-  1.25% )
>                 394      page-faults               #    0.004 K/sec                    ( +-  0.22% )
>     445,902,503,057      cycles                    #    4.257 GHz                      ( +-  0.55% )  (66.67%)
>       8,558,376,740      stalled-cycles-frontend   #    1.92% frontend cycles idle     ( +-  0.88% )  (49.99%)
>     300,346,181,651      stalled-cycles-backend    #   67.36% backend cycles idle      ( +-  0.76% )  (50.01%)
>     258,091,488,691      instructions              #    0.58  insn per cycle
>                                                    #    1.16  stalled cycles per insn  ( +-  0.22% )  (66.67%)
>      70,568,169,256      branches                  #  673.660 M/sec                    ( +-  0.17% )  (50.01%)
>       3,100,725,426      branch-misses             #    4.39% of all branches          ( +-  0.20% )  (49.99%)
> 
>             105.583 +- 0.589 seconds time elapsed  ( +-  0.56% )
> 
> Patched:
>   Performance counter stats for 'drmgr -c mem -a -q 4096' (10 runs):
> 
>          104,055.69 msec task-clock                #    0.993 CPUs utilized            ( +-  0.32% )
>               4,606      context-switches          #    0.044 K/sec                    ( +-  0.20% )
>               2,463      cpu-migrations            #    0.024 K/sec                    ( +-  0.93% )
>                 394      page-faults               #    0.004 K/sec                    ( +-  0.25% )
>     442,951,129,921      cycles                    #    4.257 GHz                      ( +-  0.32% )  (66.66%)
>       8,710,413,329      stalled-cycles-frontend   #    1.97% frontend cycles idle     ( +-  0.47% )  (50.06%)
>     299,656,905,836      stalled-cycles-backend    #   67.65% backend cycles idle      ( +-  0.39% )  (50.02%)
>     252,731,168,193      instructions              #    0.57  insn per cycle
>                                                    #    1.19  stalled cycles per insn  ( +-  0.20% )  (66.66%)
>      68,902,851,121      branches                  #  662.173 M/sec                    ( +-  0.13% )  (49.94%)
>       3,100,242,882      branch-misses             #    4.50% of all branches          ( +-  0.15% )  (49.98%)
> 
>             104.829 +- 0.325 seconds time elapsed  ( +-  0.31% )
> 
> This is consistent.  An add-by-count hot-add operation adds LMBs
> greedily, so LMBs near the start of the drconf range are considered
> first.  On an otherwise idle LPAR with so many LMBs we would expect to
> find the LMBs we need near the start of the drconf range, hence the
> smaller speedup.
> 
> Signed-off-by: Scott Cheloha <cheloha@linux.ibm.com>
> ---
> Changelog:
> 
> v1: https://lore.kernel.org/linuxppc-dev/20200910175637.2865160-1-cheloha@linux.ibm.com/
> 
> v2:
> - Move prototype for of_drconf_to_nid_single() to topology.h.
>    Requested by Michael Ellerman.
> 
> v3:
> - Send the right patch.  v2 is from the wrong branch, my mistake.
> 
>   arch/powerpc/include/asm/topology.h             | 3 +++
>   arch/powerpc/mm/numa.c                          | 2 +-
>   arch/powerpc/platforms/pseries/hotplug-memory.c | 6 ++++--
>   3 files changed, 8 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h
> index f0b6300e7dd3..d15d9999bad6 100644
> --- a/arch/powerpc/include/asm/topology.h
> +++ b/arch/powerpc/include/asm/topology.h
> @@ -86,6 +86,9 @@ static inline int cpu_distance(__be32 *cpu1_assoc, __be32 *cpu2_assoc)
> 
>   #endif /* CONFIG_NUMA */
> 
> +struct drmem_lmb;
> +extern int of_drconf_to_nid_single(struct drmem_lmb *);

Hi Scott,

checkpatch.pl reports:

CHECK: extern prototypes should be avoided in .h files
#106: FILE: arch/powerpc/include/asm/topology.h:90:
+extern int of_drconf_to_nid_single(struct drmem_lmb *);

WARNING: function definition argument 'struct drmem_lmb *' should also have an 
identifier name
#106: FILE: arch/powerpc/include/asm/topology.h:90:
+extern int of_drconf_to_nid_single(struct drmem_lmb *);

cheers,
Laurent.

> +
>   #if defined(CONFIG_NUMA) && defined(CONFIG_PPC_SPLPAR)
>   extern int find_and_online_cpu_nid(int cpu);
>   #else
> diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
> index 1f61fa2148b5..63507b47164d 100644
> --- a/arch/powerpc/mm/numa.c
> +++ b/arch/powerpc/mm/numa.c
> @@ -430,7 +430,7 @@ static int of_get_assoc_arrays(struct assoc_arrays *aa)
>    * This is like of_node_to_nid_single() for memory represented in the
>    * ibm,dynamic-reconfiguration-memory node.
>    */
> -static int of_drconf_to_nid_single(struct drmem_lmb *lmb)
> +int of_drconf_to_nid_single(struct drmem_lmb *lmb)
>   {
>   	struct assoc_arrays aa = { .arrays = NULL };
>   	int default_nid = NUMA_NO_NODE;
> diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
> index 0ea976d1cac4..9a533acf8ad0 100644
> --- a/arch/powerpc/platforms/pseries/hotplug-memory.c
> +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
> @@ -611,8 +611,10 @@ static int dlpar_add_lmb(struct drmem_lmb *lmb)
> 
>   	block_sz = memory_block_size_bytes();
> 
> -	/* Find the node id for this address. */
> -	nid = memory_add_physaddr_to_nid(lmb->base_addr);
> +	/* Find the node id for this LMB.  Fake one if necessary. */
> +	nid = of_drconf_to_nid_single(lmb);
> +	if (nid < 0 || !node_possible(nid))
> +		nid = first_online_node;
> 
>   	/* Add the memory */
>   	rc = __add_memory(nid, lmb->base_addr, block_sz);
> 


^ permalink raw reply

* Re: [PATCH] Doc: admin-guide: Add entry for kvm_cma_resv_ratio kernel param
From: Satheesh Rajendran @ 2020-09-16  8:01 UTC (permalink / raw)
  To: Randy Dunlap
  Cc: Jonathan Corbet, linux-doc, linux-kernel, kvm-ppc, Paul Mackerras,
	sathnaga, linuxppc-dev
In-Reply-To: <28eb9747-e4cc-424c-1f16-c68ed165b36a@infradead.org>

Hi Randy,

Thanks for the comments, will send a V2 fixing them.

On Tue, Sep 15, 2020 at 11:18:52PM -0700, Randy Dunlap wrote:
> On 9/15/20 11:11 PM, sathnaga@linux.vnet.ibm.com wrote:
> > From: Satheesh Rajendran <sathnaga@linux.vnet.ibm.com>
> > 
> > Add document entry for kvm_cma_resv_ratio kernel param which
> > is used to alter the KVM contiguous memory allocation percentage
> > for hash pagetable allocation used by hash mode PowerPC KVM guests.
> > 
> > Cc: linux-kernel@vger.kernel.org
> > Cc: kvm-ppc@vger.kernel.org
> > Cc: linuxppc-dev@lists.ozlabs.org
> > Cc: Paul Mackerras <paulus@samba.org>
> > Cc: Michael Ellerman <mpe@ellerman.id.au>
> > Cc: Jonathan Corbet <corbet@lwn.net>  
> > Signed-off-by: Satheesh Rajendran <sathnaga@linux.vnet.ibm.com>
> > ---
> >  Documentation/admin-guide/kernel-parameters.txt | 9 +++++++++
> >  1 file changed, 9 insertions(+)
> > 
> > diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> > index a1068742a6df..9cb126573c71 100644
> > --- a/Documentation/admin-guide/kernel-parameters.txt
> > +++ b/Documentation/admin-guide/kernel-parameters.txt
> > @@ -599,6 +599,15 @@
> >  			altogether. For more information, see
> >  			include/linux/dma-contiguous.h
> >  
> > +        kvm_cma_resv_ratio=n
> > +                        [PPC]
> 
> You can put [PPC] on the line above.
> 
sure
> > +                        Reserves given percentage from system memory area for
> > +                        contiguous memory allocation for KVM hash pagetable
> > +                        allocation.
> > +                        Bydefault it reserves 5% of total system memory.
> 
> 			   By default
> 
> > +                        Format: <integer>
> > +                        Default: 5
> > +
> 
> and please use tabs for indentation, not all spaces.
> 
sure
> >  	cmo_free_hint=	[PPC] Format: { yes | no }
> >  			Specify whether pages are marked as being inactive
> >  			when they are freed.  This is used in CMO environments
> > 
> 
> Entries in kernel-parameters.txt should be sorted into dictionary order,
> so please put that with the other kvm parameters.
> 
sure.
> thanks.
> -- 
> ~Randy
> 

Thanks!
-Satheesh.

^ permalink raw reply

* [PATCH v1] powerpc: fix EDEADLOCK redefinition error in uapi/asm/errno.h
From: Tony Ambardar @ 2020-09-16  7:42 UTC (permalink / raw)
  To: Michael Ellerman
  Cc: Tony Ambardar, linux-kernel, Paul Mackerras, Rosen Penev, bpf,
	linuxppc-dev

A few archs like powerpc have different errno.h values for macros
EDEADLOCK and EDEADLK. In code including both libc and linux versions of
errno.h, this can result in multiple definitions of EDEADLOCK in the
include chain. Definitions to the same value (e.g. seen with mips) do
not raise warnings, but on powerpc there are redefinitions changing the
value, which raise warnings and errors (if using "-Werror").

Guard against these redefinitions to avoid build errors like the following,
first seen cross-compiling libbpf v5.8.9 for powerpc using GCC 8.4.0 with
musl 1.1.24:

  In file included from ../../arch/powerpc/include/uapi/asm/errno.h:5,
                   from ../../include/linux/err.h:8,
                   from libbpf.c:29:
  ../../include/uapi/asm-generic/errno.h:40: error: "EDEADLOCK" redefined [-Werror]
   #define EDEADLOCK EDEADLK

  In file included from toolchain-powerpc_8540_gcc-8.4.0_musl/include/errno.h:10,
                   from libbpf.c:26:
  toolchain-powerpc_8540_gcc-8.4.0_musl/include/bits/errno.h:58: note: this is the location of the previous definition
   #define EDEADLOCK       58

  cc1: all warnings being treated as errors
  make[5]: *** [target-powerpc_8540_musl/bpftools-5.8.9/tools/build/Makefile.build:97: /home/kodidev/openwrt-project/build_dir/target-powerpc_8540_musl/bpftools-minimal/bpftools-5.8.9//libbpf/staticobjs/libbpf.o] Error 1

Fixes: 95f28190aa01 ("tools include arch: Grab a copy of errno.h for arch's
                      supported by perf")
Fixes: c3617f72036c ("UAPI: (Scripted) Disintegrate arch/powerpc/include/asm")

Reported-by: Rosen Penev <rosenp@gmail.com>
Signed-off-by: Tony Ambardar <Tony.Ambardar@gmail.com>
---
 arch/powerpc/include/uapi/asm/errno.h       | 1 +
 tools/arch/powerpc/include/uapi/asm/errno.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/arch/powerpc/include/uapi/asm/errno.h b/arch/powerpc/include/uapi/asm/errno.h
index cc79856896a1..4ba87de32be0 100644
--- a/arch/powerpc/include/uapi/asm/errno.h
+++ b/arch/powerpc/include/uapi/asm/errno.h
@@ -2,6 +2,7 @@
 #ifndef _ASM_POWERPC_ERRNO_H
 #define _ASM_POWERPC_ERRNO_H
 
+#undef	EDEADLOCK
 #include <asm-generic/errno.h>
 
 #undef	EDEADLOCK
diff --git a/tools/arch/powerpc/include/uapi/asm/errno.h b/tools/arch/powerpc/include/uapi/asm/errno.h
index cc79856896a1..4ba87de32be0 100644
--- a/tools/arch/powerpc/include/uapi/asm/errno.h
+++ b/tools/arch/powerpc/include/uapi/asm/errno.h
@@ -2,6 +2,7 @@
 #ifndef _ASM_POWERPC_ERRNO_H
 #define _ASM_POWERPC_ERRNO_H
 
+#undef	EDEADLOCK
 #include <asm-generic/errno.h>
 
 #undef	EDEADLOCK
-- 
2.25.1


^ permalink raw reply related

* Re: [PATCH v3] pseries/hotplug-memory: hot-add: skip redundant LMB lookup
From: David Hildenbrand @ 2020-09-16  7:39 UTC (permalink / raw)
  To: Scott Cheloha, linuxppc-dev
  Cc: Nathan Lynch, Michal Suchanek, Laurent Dufour, Rick Lindsley
In-Reply-To: <20200915194647.3334645-1-cheloha@linux.ibm.com>

On 15.09.20 21:46, Scott Cheloha wrote:
> During memory hot-add, dlpar_add_lmb() calls memory_add_physaddr_to_nid()
> to determine which node id (nid) to use when later calling __add_memory().
> 
> This is wasteful.  On pseries, memory_add_physaddr_to_nid() finds an
> appropriate nid for a given address by looking up the LMB containing the
> address and then passing that LMB to of_drconf_to_nid_single() to get the
> nid.  In dlpar_add_lmb() we get this address from the LMB itself.
> 
> In short, we have a pointer to an LMB and then we are searching for
> that LMB *again* in order to find its nid.
> 
> If we call of_drconf_to_nid_single() directly from dlpar_add_lmb() we
> can skip the redundant lookup.  The only error handling we need to
> duplicate from memory_add_physaddr_to_nid() is the fallback to the
> default nid when drconf_to_nid_single() returns -1 (NUMA_NO_NODE) or
> an invalid nid.
> 
> Skipping the extra lookup makes hot-add operations faster, especially
> on machines with many LMBs.
> 
> Consider an LPAR with 126976 LMBs.  In one test, hot-adding 126000
> LMBs on an upatched kernel took ~3.5 hours while a patched kernel
> completed the same operation in ~2 hours:
> 
> Unpatched (12450 seconds):
> Sep  9 04:06:31 ltc-brazos1 drmgr[810169]: drmgr: -c mem -a -q 126000
> Sep  9 04:06:31 ltc-brazos1 kernel: pseries-hotplug-mem: Attempting to hot-add 126000 LMB(s)
> [...]
> Sep  9 07:34:01 ltc-brazos1 kernel: pseries-hotplug-mem: Memory at 20000000 (drc index 80000002) was hot-added
> 
> Patched (7065 seconds):
> Sep  8 21:49:57 ltc-brazos1 drmgr[877703]: drmgr: -c mem -a -q 126000
> Sep  8 21:49:57 ltc-brazos1 kernel: pseries-hotplug-mem: Attempting to hot-add 126000 LMB(s)
> [...]
> Sep  8 23:27:42 ltc-brazos1 kernel: pseries-hotplug-mem: Memory at 20000000 (drc index 80000002) was hot-added
> 
> It should be noted that the speedup grows more substantial when
> hot-adding LMBs at the end of the drconf range.  This is because we
> are skipping a linear LMB search.
> 
> To see the distinction, consider smaller hot-add test on the same
> LPAR.  A perf-stat run with 10 iterations showed that hot-adding 4096
> LMBs completed less than 1 second faster on a patched kernel:
> 
> Unpatched:
>  Performance counter stats for 'drmgr -c mem -a -q 4096' (10 runs):
> 
>         104,753.42 msec task-clock                #    0.992 CPUs utilized            ( +-  0.55% )
>              4,708      context-switches          #    0.045 K/sec                    ( +-  0.69% )
>              2,444      cpu-migrations            #    0.023 K/sec                    ( +-  1.25% )
>                394      page-faults               #    0.004 K/sec                    ( +-  0.22% )
>    445,902,503,057      cycles                    #    4.257 GHz                      ( +-  0.55% )  (66.67%)
>      8,558,376,740      stalled-cycles-frontend   #    1.92% frontend cycles idle     ( +-  0.88% )  (49.99%)
>    300,346,181,651      stalled-cycles-backend    #   67.36% backend cycles idle      ( +-  0.76% )  (50.01%)
>    258,091,488,691      instructions              #    0.58  insn per cycle
>                                                   #    1.16  stalled cycles per insn  ( +-  0.22% )  (66.67%)
>     70,568,169,256      branches                  #  673.660 M/sec                    ( +-  0.17% )  (50.01%)
>      3,100,725,426      branch-misses             #    4.39% of all branches          ( +-  0.20% )  (49.99%)
> 
>            105.583 +- 0.589 seconds time elapsed  ( +-  0.56% )
> 
> Patched:
>  Performance counter stats for 'drmgr -c mem -a -q 4096' (10 runs):
> 
>         104,055.69 msec task-clock                #    0.993 CPUs utilized            ( +-  0.32% )
>              4,606      context-switches          #    0.044 K/sec                    ( +-  0.20% )
>              2,463      cpu-migrations            #    0.024 K/sec                    ( +-  0.93% )
>                394      page-faults               #    0.004 K/sec                    ( +-  0.25% )
>    442,951,129,921      cycles                    #    4.257 GHz                      ( +-  0.32% )  (66.66%)
>      8,710,413,329      stalled-cycles-frontend   #    1.97% frontend cycles idle     ( +-  0.47% )  (50.06%)
>    299,656,905,836      stalled-cycles-backend    #   67.65% backend cycles idle      ( +-  0.39% )  (50.02%)
>    252,731,168,193      instructions              #    0.57  insn per cycle
>                                                   #    1.19  stalled cycles per insn  ( +-  0.20% )  (66.66%)
>     68,902,851,121      branches                  #  662.173 M/sec                    ( +-  0.13% )  (49.94%)
>      3,100,242,882      branch-misses             #    4.50% of all branches          ( +-  0.15% )  (49.98%)
> 
>            104.829 +- 0.325 seconds time elapsed  ( +-  0.31% )
> 
> This is consistent.  An add-by-count hot-add operation adds LMBs
> greedily, so LMBs near the start of the drconf range are considered
> first.  On an otherwise idle LPAR with so many LMBs we would expect to
> find the LMBs we need near the start of the drconf range, hence the
> smaller speedup.
> 
> Signed-off-by: Scott Cheloha <cheloha@linux.ibm.com>


Hi Scott,

IIRC, ppc DLPAR does a single add_memory() for each LMB (16 MB). With
tons of LMBs, this will also make /proc/iomem explode in size (using a a
list-based tree), making traversal significantly slower e.g., on
insertions and system ram walks.

I was wondering if you would get another performance boost under ppc
when using MEMHP_MERGE_RESOURCE [1]. AFAIKs, the resource boundaries are
not of interest. No guarantees, might be worth a try.

Did you investigate what else makes memory hotplug that slow? (126000
LMBs correspond to roughly 2TB, that shouldn't take 2 hours ...) Memory
block devices might still be a slowdown (although we have an xarray in
place now that takes care of most pain).

[1]
https://lore.kernel.org/linux-mm/20200911103459.10306-1-david@redhat.com/

-- 
Thanks,

David / dhildenb


^ permalink raw reply

* Re: Injecting SLB miltihit crashes kernel 5.9.0-rc5
From: Mahesh Jagannath Salgaonkar @ 2020-09-16  7:12 UTC (permalink / raw)
  To: Michal Suchánek, linuxppc-dev
In-Reply-To: <20200915084302.GG29778@kitsune.suse.cz>

On 9/15/20 2:13 PM, Michal Suchánek wrote:
> Hello,
> 
> Using the SLB mutihit injection test module (which I did not write so I
> do not want to post it here) to verify updates on my 5.3 frankernekernel
> I found that the kernel crashes with Oops: kernel bad access.
> 
> I tested on latest upstream kernel build that I have at hand and the
> result is te same (minus the message - nothing was logged and the kernel
> simply rebooted).


Yes, SLB multihit recovery is broken upstream. Fix is on the way.


> 
> Since the whole effort to write a real mode MCE handler was supposed to
> prevent this maybe the SLB injection module should be added to the
> kernel selftests?

Yes. We are working on adding SLB injection selftest patches will be
posted soon.

Thanks,
-Mahesh.

> 
> Thanks
> 
> Michal
> 


^ permalink raw reply

* RE: [PATCH v1] soc: fsl: rcpm: Add ACPI support
From: Ran Wang @ 2020-09-16  6:40 UTC (permalink / raw)
  To: Ard Biesheuvel, kuldip dwivedi, Leo Li,
	linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org
  Cc: Biwen Li, Samer El-Haj-Mahmoud, Arokia Samy, Paul Yang,
	Varun Sethi, tanveer
In-Reply-To: <caf01871-1c3d-bdf8-867d-daf7138966a8@arm.com>

Hi Ard,

On Wednesday, September 16, 2020 2:11 PM, Ard Biesheuvel wrote:
> Subject: Re: [PATCH v1] soc: fsl: rcpm: Add ACPI support
> 
> On 9/16/20 3:32 AM, Ran Wang wrote:
> > Hi Ard,
> >
> > On Tuesday, September 15, 2020 7:10 PM, Ard Biesheuvel wrote:
> >> Subject: Re: [PATCH v1] soc: fsl: rcpm: Add ACPI support
> >>
> >> On 9/15/20 1:06 PM, kuldip dwivedi wrote:
> >>> Add ACPI support in fsl RCPM driver. This is required to support
> >>> ACPI
> >>> S3 state. S3 is the ACPI sleep state that is known as "sleep" or
> >>> "suspend to RAM".
> >>> It essentially turns off most power of the system but keeps memory
> >>> powered.
> >>>
> >>> Signed-off-by: tanveer <tanveer.alam@puresoftware.com>
> >>> Signed-off-by: kuldip dwivedi <kuldip.dwivedi@puresoftware.com>
> >>
> >> Why does the OS need to program this device? Can't this be done by
> >> firmware?
> >
> > This device is use to tell HW which IP (such as USB, SDHC, SATA, etc)
> > should not be clock gated during system enter low power state (to
> > allow that IP work as a wakeup source). And user does this configuration in
> device tree.
> 
> The point of ACPI is *not* to describe a DT topology using a table format that
> is not suited for it. The point of ACPI is to describe a machine that is more
> abstracted from the hardware than is typically possible with DT, where the
> abstractions are implemented by AML code that is provided by the firmware,
> but executed in the context of the OS.
> 
> So the idea is *not* finding the shortest possible path to get your existing DT
> driver code running on a system that boots via ACPI.
> Instead, you should carefully think about the abstract ACPI machine that you
> will expose to the OS, and hide everything else in firmware.
> 
> In this particular case, it seems like your USB, SDHC and SATA device objects
> may need power state dependent AML methods that program this block
> directly.

Actually the scenario is a little bit complicated for RCPM function: it need to query
kernel wakeup source framework (see for_each_wakeup_source(ws)) to fetch all
potential candidates then do the programming accordingly. If we implement
this logic in AML methods, I have no idea how to collect those information stored in
wakeup source data of kernel.

Regards,
Ran

> 
> 
> > So implement
> > this RCPM driver to do it in kernel rather than firmware.
> >
> > Regards,
> > Ran
> >
> >>> ---
> >>>
> >>> Notes:
> >>>       1. Add ACPI match table
> >>>       2. NXP team members are added for confirming HID changes
> >>>       3. There is only one node in ACPI so no need to check for
> >>>          current device explicitly
> >>>       4. These changes are tested on LX2160A and LS1046A platforms
> >>>
> >>>    drivers/soc/fsl/rcpm.c | 22 +++++++++++++++++++---
> >>>    1 file changed, 19 insertions(+), 3 deletions(-)
> >>>
> >>> diff --git a/drivers/soc/fsl/rcpm.c b/drivers/soc/fsl/rcpm.c index
> >>> a093dbe6d2cb..e75a436fb159 100644
> >>> --- a/drivers/soc/fsl/rcpm.c
> >>> +++ b/drivers/soc/fsl/rcpm.c
> >>> @@ -2,10 +2,12 @@
> >>>    //
> >>>    // rcpm.c - Freescale QorIQ RCPM driver
> >>>    //
> >>> -// Copyright 2019 NXP
> >>> +// Copyright 2019-2020 NXP
> >>> +// Copyright 2020 Puresoftware Ltd.
> >>>    //
> >>>    // Author: Ran Wang <ran.wang_1@nxp.com>
> >>>
> >>> +#include <linux/acpi.h>
> >>>    #include <linux/init.h>
> >>>    #include <linux/module.h>
> >>>    #include <linux/platform_device.h> @@ -57,8 +59,13 @@ static int
> >>> rcpm_pm_prepare(struct device *dev)
> >>>    				rcpm->wakeup_cells + 1);
> >>>
> >>>    		/*  Wakeup source should refer to current rcpm device */
> >>> -		if (ret || (np->phandle != value[0]))
> >>> -			continue;
> >>> +		if (is_acpi_node(dev->fwnode)) {
> >>> +			if (ret)
> >>> +				continue;
> >>> +		} else {
> >>> +			if (ret || (np->phandle != value[0]))
> >>> +				continue;
> >>> +		}
> >>>
> >>>    		/* Property "#fsl,rcpm-wakeup-cells" of rcpm node defines the
> >>>    		 * number of IPPDEXPCR register cells, and "fsl,rcpm-wakeup"
> >>> @@ -139,10 +146,19 @@ static const struct of_device_id
> >>> rcpm_of_match[]
> >> = {
> >>>    };
> >>>    MODULE_DEVICE_TABLE(of, rcpm_of_match);
> >>>
> >>> +#ifdef CONFIG_ACPI
> >>> +static const struct acpi_device_id rcpm_acpi_match[] = {
> >>> +	{ "NXP0015", },
> >>> +	{ }
> >>> +};
> >>> +MODULE_DEVICE_TABLE(acpi, rcpm_acpi_match); #endif
> >>> +
> >>>    static struct platform_driver rcpm_driver = {
> >>>    	.driver = {
> >>>    		.name = "rcpm",
> >>>    		.of_match_table = rcpm_of_match,
> >>> +		.acpi_match_table = ACPI_PTR(rcpm_acpi_match),
> >>>    		.pm	= &rcpm_pm_ops,
> >>>    	},
> >>>    	.probe = rcpm_probe,
> >>>
> >


^ permalink raw reply

* [PATCH] fsl: imx-audmix : Replace seq_printf with seq_puts
From: Xu Wang @ 2020-09-16  6:14 UTC (permalink / raw)
  To: timur, nicoleotsuka, Xiubo.Lee, festevam, shengjiu.wang,
	lgirdwood, broonie, perex, tiwai, shawnguo, s.hauer, kernel,
	linux-imx, alsa-devel, linuxppc-dev, linux-arm-kernel
  Cc: linux-kernel, Xu Wang

A multiplication for the size determination of a memory allocation
indicated that an array data structure should be processed.
Thus use the corresponding function "devm_kcalloc".

Signed-off-by: Xu Wang <vulab@iscas.ac.cn>
---
 sound/soc/fsl/imx-audmix.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/sound/soc/fsl/imx-audmix.c b/sound/soc/fsl/imx-audmix.c
index 202fb8950078..cbdc0a2c09c5 100644
--- a/sound/soc/fsl/imx-audmix.c
+++ b/sound/soc/fsl/imx-audmix.c
@@ -185,20 +185,20 @@ static int imx_audmix_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	priv->num_dai = 2 * num_dai;
-	priv->dai = devm_kzalloc(&pdev->dev, priv->num_dai *
+	priv->dai = devm_kcalloc(&pdev->dev, priv->num_dai,
 				 sizeof(struct snd_soc_dai_link), GFP_KERNEL);
 	if (!priv->dai)
 		return -ENOMEM;
 
 	priv->num_dai_conf = num_dai;
-	priv->dai_conf = devm_kzalloc(&pdev->dev, priv->num_dai_conf *
+	priv->dai_conf = devm_kcalloc(&pdev->dev, priv->num_dai_conf,
 				      sizeof(struct snd_soc_codec_conf),
 				      GFP_KERNEL);
 	if (!priv->dai_conf)
 		return -ENOMEM;
 
 	priv->num_dapm_routes = 3 * num_dai;
-	priv->dapm_routes = devm_kzalloc(&pdev->dev, priv->num_dapm_routes *
+	priv->dapm_routes = devm_kcalloc(&pdev->dev, priv->num_dapm_routes,
 					 sizeof(struct snd_soc_dapm_route),
 					 GFP_KERNEL);
 	if (!priv->dapm_routes)
@@ -208,7 +208,7 @@ static int imx_audmix_probe(struct platform_device *pdev)
 		struct snd_soc_dai_link_component *dlc;
 
 		/* for CPU/Codec/Platform x 2 */
-		dlc = devm_kzalloc(&pdev->dev, 6 * sizeof(*dlc), GFP_KERNEL);
+		dlc = devm_kcalloc(&pdev->dev, 6, sizeof(*dlc), GFP_KERNEL);
 		if (!dlc) {
 			dev_err(&pdev->dev, "failed to allocate dai_link\n");
 			return -ENOMEM;
-- 
2.17.1


^ permalink raw reply related

* [PATCH -next] serial: pmac_zilog: use for_each_child_of_node() macro
From: Qinglang Miao @ 2020-09-16  6:21 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Jiri Slaby, Michael Ellerman,
	Benjamin Herrenschmidt, Paul Mackerras
  Cc: Qinglang Miao, linuxppc-dev, linux-kernel, linux-serial

Use for_each_child_of_node() macro instead of open coding it.

Signed-off-by: Qinglang Miao <miaoqinglang@huawei.com>
---
 drivers/tty/serial/pmac_zilog.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c
index 96e7aa479..063484b22 100644
--- a/drivers/tty/serial/pmac_zilog.c
+++ b/drivers/tty/serial/pmac_zilog.c
@@ -1644,7 +1644,7 @@ static int __init pmz_probe(void)
 		 * TODO: Add routines with proper locking to do that...
 		 */
 		node_a = node_b = NULL;
-		for (np = NULL; (np = of_get_next_child(node_p, np)) != NULL;) {
+		for_each_child_of_node(node_p, np) {
 			if (of_node_name_prefix(np, "ch-a"))
 				node_a = of_node_get(np);
 			else if (of_node_name_prefix(np, "ch-b"))
-- 
2.23.0


^ permalink raw reply related

* [PATCH -next] powerpc/powernv: fix wrong warning message in opalcore_config_init()
From: Qinglang Miao @ 2020-09-16  6:21 UTC (permalink / raw)
  To: Michael Ellerman, Benjamin Herrenschmidt, Paul Mackerras
  Cc: linuxppc-dev, linux-kernel, Qinglang Miao

The logic of the warn output is incorrect. The two args should be
exchanged.

Signed-off-by: Qinglang Miao <miaoqinglang@huawei.com>
---
 arch/powerpc/platforms/powernv/opal-core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/powerpc/platforms/powernv/opal-core.c b/arch/powerpc/platforms/powernv/opal-core.c
index 6dba3b622..23571f0b5 100644
--- a/arch/powerpc/platforms/powernv/opal-core.c
+++ b/arch/powerpc/platforms/powernv/opal-core.c
@@ -510,7 +510,7 @@ static void __init opalcore_config_init(void)
 	idx = be32_to_cpu(opalc_metadata->region_cnt);
 	if (idx > MAX_PT_LOAD_CNT) {
 		pr_warn("WARNING: OPAL regions count (%d) adjusted to limit (%d)",
-			MAX_PT_LOAD_CNT, idx);
+			idx, MAX_PT_LOAD_CNT);
 		idx = MAX_PT_LOAD_CNT;
 	}
 	for (i = 0; i < idx; i++) {
-- 
2.23.0


^ permalink raw reply related

* [PATCH -next] macintosh: smu_sensors: use for_each_child_of_node() macro
From: Qinglang Miao @ 2020-09-16  6:21 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, linux-kernel, Qinglang Miao

Use for_each_child_of_node() macro instead of open coding it.

Signed-off-by: Qinglang Miao <miaoqinglang@huawei.com>
---
 drivers/macintosh/windfarm_smu_sensors.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/macintosh/windfarm_smu_sensors.c b/drivers/macintosh/windfarm_smu_sensors.c
index 3e6059eaa..c8706cfb8 100644
--- a/drivers/macintosh/windfarm_smu_sensors.c
+++ b/drivers/macintosh/windfarm_smu_sensors.c
@@ -421,8 +421,7 @@ static int __init smu_sensors_init(void)
 		return -ENODEV;
 
 	/* Look for sensors subdir */
-	for (sensors = NULL;
-	     (sensors = of_get_next_child(smu, sensors)) != NULL;)
+	for_each_child_of_node(smu, sensors)
 		if (of_node_name_eq(sensors, "sensors"))
 			break;
 
-- 
2.23.0


^ permalink raw reply related

* [PATCH -next] PCI: rpadlpar: use for_each_child_of_node() and for_each_node_by_name
From: Qinglang Miao @ 2020-09-16  6:21 UTC (permalink / raw)
  To: Michael Ellerman, Benjamin Herrenschmidt, Paul Mackerras,
	Tyrel Datwyler, Bjorn Helgaas
  Cc: linux-pci, linuxppc-dev, linux-kernel, Qinglang Miao

Use for_each_child_of_node() and for_each_node_by_name macro
instead of open coding it.

Signed-off-by: Qinglang Miao <miaoqinglang@huawei.com>
---
 drivers/pci/hotplug/rpadlpar_core.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c
index f979b7098..0a3c80ba6 100644
--- a/drivers/pci/hotplug/rpadlpar_core.c
+++ b/drivers/pci/hotplug/rpadlpar_core.c
@@ -40,13 +40,13 @@ static DEFINE_MUTEX(rpadlpar_mutex);
 static struct device_node *find_vio_slot_node(char *drc_name)
 {
 	struct device_node *parent = of_find_node_by_name(NULL, "vdevice");
-	struct device_node *dn = NULL;
+	struct device_node *dn;
 	int rc;
 
 	if (!parent)
 		return NULL;
 
-	while ((dn = of_get_next_child(parent, dn))) {
+	for_each_child_of_node(parent, dn) {
 		rc = rpaphp_check_drc_props(dn, drc_name, NULL);
 		if (rc == 0)
 			break;
@@ -60,10 +60,10 @@ static struct device_node *find_vio_slot_node(char *drc_name)
 static struct device_node *find_php_slot_pci_node(char *drc_name,
 						  char *drc_type)
 {
-	struct device_node *np = NULL;
+	struct device_node *np;
 	int rc;
 
-	while ((np = of_find_node_by_name(np, "pci"))) {
+	for_each_node_by_name(np, "pci") {
 		rc = rpaphp_check_drc_props(np, drc_name, drc_type);
 		if (rc == 0)
 			break;
-- 
2.23.0


^ permalink raw reply related

* [PATCH -next] drivers/macintosh/smu.c: use for_each_child_of_node() macro
From: Qinglang Miao @ 2020-09-16  6:21 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, linux-kernel, Qinglang Miao

Use for_each_child_of_node() macro instead of open coding it.

Signed-off-by: Qinglang Miao <miaoqinglang@huawei.com>
---
 drivers/macintosh/smu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index 96684581a..45875e8c6 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -638,7 +638,7 @@ static void smu_expose_childs(struct work_struct *unused)
 {
 	struct device_node *np;
 
-	for (np = NULL; (np = of_get_next_child(smu->of_node, np)) != NULL;)
+	for_each_child_of_node(smu->of_node, np)
 		if (of_device_is_compatible(np, "smu-sensors"))
 			of_platform_device_create(np, "smu-sensors",
 						  &smu->of_dev->dev);
-- 
2.23.0


^ permalink raw reply related

* Re: [PATCH] Doc: admin-guide: Add entry for kvm_cma_resv_ratio kernel param
From: Randy Dunlap @ 2020-09-16  6:18 UTC (permalink / raw)
  To: sathnaga, linux-doc
  Cc: Jonathan Corbet, linux-kernel, kvm-ppc, Paul Mackerras,
	linuxppc-dev
In-Reply-To: <20200916061130.723411-1-sathnaga@linux.vnet.ibm.com>

On 9/15/20 11:11 PM, sathnaga@linux.vnet.ibm.com wrote:
> From: Satheesh Rajendran <sathnaga@linux.vnet.ibm.com>
> 
> Add document entry for kvm_cma_resv_ratio kernel param which
> is used to alter the KVM contiguous memory allocation percentage
> for hash pagetable allocation used by hash mode PowerPC KVM guests.
> 
> Cc: linux-kernel@vger.kernel.org
> Cc: kvm-ppc@vger.kernel.org
> Cc: linuxppc-dev@lists.ozlabs.org
> Cc: Paul Mackerras <paulus@samba.org>
> Cc: Michael Ellerman <mpe@ellerman.id.au>
> Cc: Jonathan Corbet <corbet@lwn.net>  
> Signed-off-by: Satheesh Rajendran <sathnaga@linux.vnet.ibm.com>
> ---
>  Documentation/admin-guide/kernel-parameters.txt | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index a1068742a6df..9cb126573c71 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -599,6 +599,15 @@
>  			altogether. For more information, see
>  			include/linux/dma-contiguous.h
>  
> +        kvm_cma_resv_ratio=n
> +                        [PPC]

You can put [PPC] on the line above.

> +                        Reserves given percentage from system memory area for
> +                        contiguous memory allocation for KVM hash pagetable
> +                        allocation.
> +                        Bydefault it reserves 5% of total system memory.

			   By default

> +                        Format: <integer>
> +                        Default: 5
> +

and please use tabs for indentation, not all spaces.

>  	cmo_free_hint=	[PPC] Format: { yes | no }
>  			Specify whether pages are marked as being inactive
>  			when they are freed.  This is used in CMO environments
> 

Entries in kernel-parameters.txt should be sorted into dictionary order,
so please put that with the other kvm parameters.

thanks.
-- 
~Randy


^ permalink raw reply

* [PATCH] Doc: admin-guide: Add entry for kvm_cma_resv_ratio kernel param
From: sathnaga @ 2020-09-16  6:11 UTC (permalink / raw)
  To: linux-doc
  Cc: Jonathan Corbet, linux-kernel, kvm-ppc, Paul Mackerras,
	Satheesh Rajendran, linuxppc-dev

From: Satheesh Rajendran <sathnaga@linux.vnet.ibm.com>

Add document entry for kvm_cma_resv_ratio kernel param which
is used to alter the KVM contiguous memory allocation percentage
for hash pagetable allocation used by hash mode PowerPC KVM guests.

Cc: linux-kernel@vger.kernel.org
Cc: kvm-ppc@vger.kernel.org
Cc: linuxppc-dev@lists.ozlabs.org
Cc: Paul Mackerras <paulus@samba.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Jonathan Corbet <corbet@lwn.net>  
Signed-off-by: Satheesh Rajendran <sathnaga@linux.vnet.ibm.com>
---
 Documentation/admin-guide/kernel-parameters.txt | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index a1068742a6df..9cb126573c71 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -599,6 +599,15 @@
 			altogether. For more information, see
 			include/linux/dma-contiguous.h
 
+        kvm_cma_resv_ratio=n
+                        [PPC]
+                        Reserves given percentage from system memory area for
+                        contiguous memory allocation for KVM hash pagetable
+                        allocation.
+                        Bydefault it reserves 5% of total system memory.
+                        Format: <integer>
+                        Default: 5
+
 	cmo_free_hint=	[PPC] Format: { yes | no }
 			Specify whether pages are marked as being inactive
 			when they are freed.  This is used in CMO environments
-- 
2.26.2


^ permalink raw reply related

* Re: [PATCH v1] soc: fsl: rcpm: Add ACPI support
From: Ard Biesheuvel @ 2020-09-16  6:10 UTC (permalink / raw)
  To: Ran Wang, kuldip dwivedi, Leo Li, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org
  Cc: Biwen Li, Samer El-Haj-Mahmoud, Arokia Samy, Paul Yang,
	Varun Sethi, tanveer
In-Reply-To: <AM6PR04MB5413903EAAEDB2EED2E254C6F1210@AM6PR04MB5413.eurprd04.prod.outlook.com>

On 9/16/20 3:32 AM, Ran Wang wrote:
> Hi Ard,
> 
> On Tuesday, September 15, 2020 7:10 PM, Ard Biesheuvel wrote:
>> Subject: Re: [PATCH v1] soc: fsl: rcpm: Add ACPI support
>>
>> On 9/15/20 1:06 PM, kuldip dwivedi wrote:
>>> Add ACPI support in fsl RCPM driver. This is required to support ACPI
>>> S3 state. S3 is the ACPI sleep state that is known as "sleep" or
>>> "suspend to RAM".
>>> It essentially turns off most power of the system but keeps memory
>>> powered.
>>>
>>> Signed-off-by: tanveer <tanveer.alam@puresoftware.com>
>>> Signed-off-by: kuldip dwivedi <kuldip.dwivedi@puresoftware.com>
>>
>> Why does the OS need to program this device? Can't this be done by
>> firmware?
> 
> This device is use to tell HW which IP (such as USB, SDHC, SATA, etc) should not be
> clock gated during system enter low power state (to allow that IP work as a
> wakeup source). And user does this configuration in device tree.

The point of ACPI is *not* to describe a DT topology using a table 
format that is not suited for it. The point of ACPI is to describe a 
machine that is more abstracted from the hardware than is typically 
possible with DT, where the abstractions are implemented by AML code 
that is provided by the firmware, but executed in the context of the OS.

So the idea is *not* finding the shortest possible path to get your 
existing DT driver code running on a system that boots via ACPI. 
Instead, you should carefully think about the abstract ACPI machine that 
you will expose to the OS, and hide everything else in firmware.

In this particular case, it seems like your USB, SDHC and SATA device 
objects may need power state dependent AML methods that program this 
block directly.



> So implement
> this RCPM driver to do it in kernel rather than firmware.
> 
> Regards,
> Ran
> 
>>> ---
>>>
>>> Notes:
>>>       1. Add ACPI match table
>>>       2. NXP team members are added for confirming HID changes
>>>       3. There is only one node in ACPI so no need to check for
>>>          current device explicitly
>>>       4. These changes are tested on LX2160A and LS1046A platforms
>>>
>>>    drivers/soc/fsl/rcpm.c | 22 +++++++++++++++++++---
>>>    1 file changed, 19 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/drivers/soc/fsl/rcpm.c b/drivers/soc/fsl/rcpm.c index
>>> a093dbe6d2cb..e75a436fb159 100644
>>> --- a/drivers/soc/fsl/rcpm.c
>>> +++ b/drivers/soc/fsl/rcpm.c
>>> @@ -2,10 +2,12 @@
>>>    //
>>>    // rcpm.c - Freescale QorIQ RCPM driver
>>>    //
>>> -// Copyright 2019 NXP
>>> +// Copyright 2019-2020 NXP
>>> +// Copyright 2020 Puresoftware Ltd.
>>>    //
>>>    // Author: Ran Wang <ran.wang_1@nxp.com>
>>>
>>> +#include <linux/acpi.h>
>>>    #include <linux/init.h>
>>>    #include <linux/module.h>
>>>    #include <linux/platform_device.h>
>>> @@ -57,8 +59,13 @@ static int rcpm_pm_prepare(struct device *dev)
>>>    				rcpm->wakeup_cells + 1);
>>>
>>>    		/*  Wakeup source should refer to current rcpm device */
>>> -		if (ret || (np->phandle != value[0]))
>>> -			continue;
>>> +		if (is_acpi_node(dev->fwnode)) {
>>> +			if (ret)
>>> +				continue;
>>> +		} else {
>>> +			if (ret || (np->phandle != value[0]))
>>> +				continue;
>>> +		}
>>>
>>>    		/* Property "#fsl,rcpm-wakeup-cells" of rcpm node defines the
>>>    		 * number of IPPDEXPCR register cells, and "fsl,rcpm-wakeup"
>>> @@ -139,10 +146,19 @@ static const struct of_device_id rcpm_of_match[]
>> = {
>>>    };
>>>    MODULE_DEVICE_TABLE(of, rcpm_of_match);
>>>
>>> +#ifdef CONFIG_ACPI
>>> +static const struct acpi_device_id rcpm_acpi_match[] = {
>>> +	{ "NXP0015", },
>>> +	{ }
>>> +};
>>> +MODULE_DEVICE_TABLE(acpi, rcpm_acpi_match); #endif
>>> +
>>>    static struct platform_driver rcpm_driver = {
>>>    	.driver = {
>>>    		.name = "rcpm",
>>>    		.of_match_table = rcpm_of_match,
>>> +		.acpi_match_table = ACPI_PTR(rcpm_acpi_match),
>>>    		.pm	= &rcpm_pm_ops,
>>>    	},
>>>    	.probe = rcpm_probe,
>>>
> 


^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox