* [PATCH v3 2/5] soc: fsl: handle RCPM errata A-008646 on SoC LS1021A
From: Ran Wang @ 2020-09-29 8:22 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: <20200929082234.36619-1-ran.wang_1@nxp.com>
From: Biwen Li <biwen.li@nxp.com>
Hardware issue:
- Reading register RCPM_IPPDEXPCR1 always return zero, this causes
system firmware could not get correct information and wrongly do
clock gating for all wakeup source IP during system suspend. Then
those IPs will never get chance to wake system.
Workaround:
- Copy register RCPM_IPPDEXPCR1's setting to register SCFG_SPARECR8
to allow system firmware's psci method read it and do things accordingly.
Signed-off-by: Biwen Li <biwen.li@nxp.com>
Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
---
Change in v3:
- Add copy_ippdexpcr1_setting(), simplize workaournd's implementation
according to binding update.
- Minor update on commit message.
Change in v2:
- Update commit message to be more clear.
- Replace device_property_read_u32_array() with syscon_regmap_lookup_by_phandle_args()
to make code simpler.
drivers/soc/fsl/rcpm.c | 35 ++++++++++++++++++++++++++++++++++-
1 file changed, 34 insertions(+), 1 deletion(-)
diff --git a/drivers/soc/fsl/rcpm.c b/drivers/soc/fsl/rcpm.c
index a093dbe..4ac2a77 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>
@@ -22,6 +22,28 @@ struct rcpm {
bool little_endian;
};
+#define SCFG_SPARECR8 0x051c
+
+static void copy_ippdexpcr1_setting(u32 val)
+{
+ struct device_node *np;
+ void __iomem *regs;
+ u32 reg_val;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,ls1021a-scfg");
+ if (!np)
+ return;
+
+ regs = of_iomap(np, 0);
+ if (!regs)
+ return;
+
+ reg_val = ioread32be(regs + SCFG_SPARECR8);
+ iowrite32be(val | reg_val, regs + SCFG_SPARECR8);
+
+ iounmap(regs);
+}
+
/**
* rcpm_pm_prepare - performs device-level tasks associated with power
* management, such as programming related to the wakeup source control.
@@ -90,6 +112,17 @@ 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 (dev_of_node(dev) && (i == 1))
+ if (device_property_read_bool(dev, "fsl,ippdexpcr1-alt-reg"))
+ copy_ippdexpcr1_setting(tmp);
}
return 0;
--
2.7.4
^ permalink raw reply related
* [PATCH v3 5/5] arm: dts: ls1021a: fix rcpm failed to claim resource
From: Ran Wang @ 2020-09-29 8:22 UTC (permalink / raw)
To: Li Yang, Rob Herring, Shawn Guo
Cc: devicetree, Ran Wang, linuxppc-dev, linux-kernel,
linux-arm-kernel
In-Reply-To: <20200929082234.36619-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>
Acked-by: Li Yang <leoyang.li@nxp.com>
---
Change in v3:
- None
Change in v2:
- None
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 cb95964..9e588ad 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 v3 0/2] DAI driver for new XCVR IP
From: Viorel Suman (OSS) @ 2020-09-29 9:19 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, Cosmin-Gabriel Samoila,
Viorel Suman, Matthias Schiffer, 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
Changes since v1:
- improved 6- and 12-ch layout comment
- used regmap polling function, improved
clocks handling in runtime_resume
- added FW size check in FW load function,
improved IRQ handler, removed dummy IRQ handlers
- fixed yaml file
Changes since v2:
- used devm_reset_control_get_exclusive instead of of_reset_control_get
- moved reset_control_assert into runtime_suspend
.../devicetree/bindings/sound/fsl,xcvr.yaml | 103 ++
sound/soc/fsl/Kconfig | 10 +
sound/soc/fsl/Makefile | 2 +
sound/soc/fsl/fsl_xcvr.c | 1356 ++++++++++++++++++++
sound/soc/fsl/fsl_xcvr.h | 266 ++++
5 files changed, 1737 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
* [PATCH v3 1/2] ASoC: fsl_xcvr: Add XCVR ASoC CPU DAI driver
From: Viorel Suman (OSS) @ 2020-09-29 9:19 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, Cosmin-Gabriel Samoila,
Viorel Suman, Matthias Schiffer, alsa-devel, devicetree,
linux-kernel, linuxppc-dev
Cc: Viorel Suman, NXP Linux Team
In-Reply-To: <1601371167-32239-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 | 1356 ++++++++++++++++++++++++++++++++++++++++++++++
sound/soc/fsl/fsl_xcvr.h | 266 +++++++++
4 files changed, 1634 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..148bf48
--- /dev/null
+++ b/sound/soc/fsl/fsl_xcvr.c
@@ -0,0 +1,1356 @@
+// 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 */
+};
+
+/*
+ * HDMI2.1 spec defines 6- and 12-channels layout for one bit audio
+ * stream. Todo: to check how this case can be considered below
+ */
+static const u32 fsl_xcvr_earc_channels[] = { 1, 2, 8, 16, 32, };
+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 u32 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)
+{
+ struct device *dev = &xcvr->pdev->dev;
+ u32 val, idx, tidx;
+ int ret;
+
+ 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);
+
+ ret = regmap_read_poll_timeout(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL, val,
+ (val & idx) != ((val & tidx) >> 1),
+ 10, 10000);
+ if (ret)
+ dev_err(dev, "AI timeout: failed to set %s reg 0x%02x=0x%08x\n",
+ phy ? "PHY" : "PLL", reg, data);
+ return ret;
+}
+
+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 = 16KiB code + 4KiB data => max 10 pages 2KiB each */
+ if (rem > 16384) {
+ dev_err(dev, "FW size %d is bigger than 16KiB.\n", rem);
+ return -ENOMEM;
+ }
+
+ 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, isr_clr = 0, val, i;
+
+ regmap_read(regmap, FSL_XCVR_EXT_ISR, &isr);
+
+ if (isr & FSL_XCVR_IRQ_NEW_CS) {
+ dev_dbg(dev, "Received new CS block\n");
+ isr_clr |= FSL_XCVR_IRQ_NEW_CS;
+ /* 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");
+ isr_clr |= FSL_XCVR_IRQ_NEW_UD;
+ }
+ if (isr & FSL_XCVR_IRQ_MUTE) {
+ dev_dbg(dev, "HW mute bit detected\n");
+ isr_clr |= FSL_XCVR_IRQ_MUTE;
+ }
+ if (isr & FSL_XCVR_IRQ_FIFO_UOFL_ERR) {
+ dev_dbg(dev, "RX/TX FIFO full/empty\n");
+ isr_clr |= FSL_XCVR_IRQ_FIFO_UOFL_ERR;
+ }
+ if (isr & FSL_XCVR_IRQ_ARC_MODE) {
+ dev_dbg(dev, "CMDC SM falls out of eARC mode\n");
+ isr_clr |= FSL_XCVR_IRQ_ARC_MODE;
+ }
+ if (isr & FSL_XCVR_IRQ_DMA_RD_REQ) {
+ dev_dbg(dev, "DMA read request\n");
+ isr_clr |= FSL_XCVR_IRQ_DMA_RD_REQ;
+ }
+ if (isr & FSL_XCVR_IRQ_DMA_WR_REQ) {
+ dev_dbg(dev, "DMA write request\n");
+ isr_clr |= FSL_XCVR_IRQ_DMA_WR_REQ;
+ }
+
+ if (isr_clr) {
+ regmap_write(regmap, FSL_XCVR_EXT_ISR_CLR, isr_clr);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+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 = devm_reset_control_get_exclusive(dev, NULL);
+ if (IS_ERR(xcvr->reset)) {
+ dev_err(dev, "failed to get XCVR reset control\n");
+ return PTR_ERR(xcvr->reset);
+ }
+
+ 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;
+ }
+
+ 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;
+}
+
+static __maybe_unused 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);
+
+ ret = reset_control_assert(xcvr->reset);
+ if (ret < 0)
+ dev_err(dev, "Failed to assert M0+ reset: %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 __maybe_unused 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");
+ goto stop_ipg_clk;
+ }
+
+ ret = clk_prepare_enable(xcvr->phy_clk);
+ if (ret) {
+ dev_err(dev, "failed to start PHY clock: %d\n", ret);
+ goto stop_pll_ipg_clk;
+ }
+
+ ret = clk_prepare_enable(xcvr->spba_clk);
+ if (ret) {
+ dev_err(dev, "failed to start SPBA clock.\n");
+ goto stop_phy_clk;
+ }
+
+ 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");
+ goto stop_spba_clk;
+ }
+
+ ret = reset_control_deassert(xcvr->reset);
+ if (ret) {
+ dev_err(dev, "failed to deassert M0+ reset.\n");
+ goto stop_spba_clk;
+ }
+
+ ret = fsl_xcvr_load_firmware(xcvr);
+ if (ret) {
+ dev_err(dev, "failed to load firmware.\n");
+ goto stop_spba_clk;
+ }
+
+ /* 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);
+ goto stop_spba_clk;
+ }
+
+ /* Let M0+ core complete firmware initialization */
+ msleep(50);
+
+ return 0;
+
+stop_spba_clk:
+ clk_disable_unprepare(xcvr->spba_clk);
+stop_phy_clk:
+ clk_disable_unprepare(xcvr->phy_clk);
+stop_pll_ipg_clk:
+ clk_disable_unprepare(xcvr->pll_ipg_clk);
+stop_ipg_clk:
+ clk_disable_unprepare(xcvr->ipg_clk);
+
+ return ret;
+}
+
+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 v3 2/2] ASoC: dt-bindings: fsl_xcvr: Add document for XCVR
From: Viorel Suman (OSS) @ 2020-09-29 9:19 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, Cosmin-Gabriel Samoila,
Viorel Suman, Matthias Schiffer, alsa-devel, devicetree,
linux-kernel, linuxppc-dev
Cc: Viorel Suman, NXP Linux Team
In-Reply-To: <1601371167-32239-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 | 103 +++++++++++++++++++++
1 file changed, 103 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..8abab2d
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml
@@ -0,0 +1,103 @@
+# 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: 1
+
+ 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/interrupt-controller/arm-gic.h>
+ #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 = <0x0 128 IRQ_TYPE_LEVEL_HIGH>;
+ 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
* RE: [PATCH v2 1/2] ASoC: fsl_xcvr: Add XCVR ASoC CPU DAI driver
From: Viorel Suman (OSS) @ 2020-09-29 9:27 UTC (permalink / raw)
To: Philipp Zabel, Viorel Suman (OSS)
Cc: devicetree@vger.kernel.org, alsa-devel@alsa-project.org,
Matthias Schiffer, Timur Tabi, Xiubo Li, Shengjiu Wang,
linuxppc-dev@lists.ozlabs.org, Takashi Iwai, Rob Herring,
Liam Girdwood, Nicolin Chen, Mark Brown, dl-linux-imx,
Viorel Suman, Cosmin-Gabriel Samoila, Jaroslav Kysela,
Fabio Estevam, linux-kernel@vger.kernel.org
In-Reply-To: <20200922120854.GA15104@pengutronix.de>
Hi Philipp,
Thank you for your review, please check my comments inline.
/Viorel
> -----Original Message-----
> From: Philipp Zabel [mailto:pza@pengutronix.de]
> Sent: Tuesday, September 22, 2020 3:09 PM
> To: Viorel Suman (OSS) <viorel.suman@oss.nxp.com>
> Cc: Liam Girdwood <lgirdwood@gmail.com>; Mark Brown
> <broonie@kernel.org>; Rob Herring <robh+dt@kernel.org>; Jaroslav Kysela
> <perex@perex.cz>; Takashi Iwai <tiwai@suse.com>; Timur Tabi
> <timur@kernel.org>; Nicolin Chen <nicoleotsuka@gmail.com>; Xiubo Li
> <Xiubo.Lee@gmail.com>; Fabio Estevam <festevam@gmail.com>; Shengjiu
> Wang <shengjiu.wang@gmail.com>; Viorel Suman <viorel.suman@nxp.com>;
> Matthias Schiffer <matthias.schiffer@ew.tq-group.com>; Cosmin-Gabriel
> Samoila <cosmin.samoila@nxp.com>; alsa-devel@alsa-project.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; linuxppc-
> dev@lists.ozlabs.org; dl-linux-imx <linux-imx@nxp.com>; Viorel Suman
> <viorel.suman@gmail.com>
> Subject: Re: [PATCH v2 1/2] ASoC: fsl_xcvr: Add XCVR ASoC CPU DAI driver
>
> On Mon, Sep 21, 2020 at 10:08:11PM +0300, Viorel Suman (OSS) wrote:
> > 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 | 1343
> > ++++++++++++++++++++++++++++++++++++++++++++++
> > sound/soc/fsl/fsl_xcvr.h | 266 +++++++++
> > 4 files changed, 1621 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..7391bca
> > --- /dev/null
> > +++ b/sound/soc/fsl/fsl_xcvr.c
> > @@ -0,0 +1,1343 @@
> [...]
> > +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);
>
> Please use devm_reset_control_get_exclusive().
Done in V3.
>
> [...]
> > +static __maybe_unused 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");
> > + goto stop_ipg_clk;
> > + }
> > +
> > + ret = clk_prepare_enable(xcvr->phy_clk);
> > + if (ret) {
> > + dev_err(dev, "failed to start PHY clock: %d\n", ret);
> > + goto stop_pll_ipg_clk;
> > + }
> > +
> > + ret = clk_prepare_enable(xcvr->spba_clk);
> > + if (ret) {
> > + dev_err(dev, "failed to start SPBA clock.\n");
> > + goto stop_phy_clk;
> > + }
> > +
> > + 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");
> > + goto stop_spba_clk;
> > + }
> > +
> > + reset_control_assert(xcvr->reset);
> > + reset_control_deassert(xcvr->reset);
>
> No delay required between the two?
Not required. Just to keep things in proper context - in
V3 I moved reset_control_assert call into runtime_suspend.
/Viorel
^ permalink raw reply
* [PATCH -next] ASoC: fsl: imx-mc13783: use devm_snd_soc_register_card()
From: Qinglang Miao @ 2020-09-29 11:29 UTC (permalink / raw)
To: Timur Tabi, Nicolin Chen, Xiubo Li, Fabio Estevam, Shengjiu Wang,
Liam Girdwood, Mark Brown, Jaroslav Kysela, Takashi Iwai,
Shawn Guo, Sascha Hauer, Pengutronix Kernel Team, NXP Linux Team
Cc: alsa-devel, Qinglang Miao, linuxppc-dev, linux-kernel,
linux-arm-kernel
Using devm_snd_soc_register_card() can make the code
shorter and cleaner.
Signed-off-by: Qinglang Miao <miaoqinglang@huawei.com>
---
sound/soc/fsl/imx-mc13783.c | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
diff --git a/sound/soc/fsl/imx-mc13783.c b/sound/soc/fsl/imx-mc13783.c
index dd9c1ac81..d9dca7bbc 100644
--- a/sound/soc/fsl/imx-mc13783.c
+++ b/sound/soc/fsl/imx-mc13783.c
@@ -96,7 +96,7 @@ static int imx_mc13783_probe(struct platform_device *pdev)
imx_mc13783.dev = &pdev->dev;
- ret = snd_soc_register_card(&imx_mc13783);
+ ret = devm_snd_soc_register_card(&pdev->dev, &imx_mc13783);
if (ret) {
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
ret);
@@ -140,19 +140,11 @@ static int imx_mc13783_probe(struct platform_device *pdev)
return ret;
}
-static int imx_mc13783_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_card(&imx_mc13783);
-
- return 0;
-}
-
static struct platform_driver imx_mc13783_audio_driver = {
.driver = {
.name = "imx_mc13783",
},
.probe = imx_mc13783_probe,
- .remove = imx_mc13783_remove
};
module_platform_driver(imx_mc13783_audio_driver);
--
2.23.0
^ permalink raw reply related
* Re: [PATCH] linux: configure CONFIG_I2C_OPAL as in-built.
From: Mimi Zohar @ 2020-09-29 12:19 UTC (permalink / raw)
To: Joel Stanley, linuxppc-dev; +Cc: openpower-firmware, Nayna Jain, klaus
In-Reply-To: <CACPK8XdeAzbXcm2w6kJuAQzckdyFQ2P9h+fC36ZArpkubqC1mg@mail.gmail.com>
Hi Joel,
On Tue, 2020-09-29 at 06:14 +0000, Joel Stanley wrote:
> On Fri, 25 Sep 2020 at 18:19, Mimi Zohar <zohar@linux.ibm.com> wrote:
> >
> > Hi Nayna,
> >
> > On Wed, 2020-09-23 at 14:25 -0400, Nayna Jain wrote:
> > > Currently, skiroot_defconfig CONFIG_I2C_OPAL is built as a loadable
> > > module rather than builtin, even if CONFIG_I2C=y is defined. This
> > > results in a delay in the TPM initialization, causing IMA to go into
> > > TPM bypass mode. As a result, the IMA measurements are added to the
> > > measurement list, but do not extend the TPM. Because of this, it is
> > > impossible to verify or attest to the system's integrity, either from
> > > skiroot or the target Host OS.
> >
> > The patch description is good, but perhaps we could provide a bit more
> > context before.
> >
> > The concept of trusted boot requires the measurement to be added to the
> > measurement list and extend the TPM, prior to allowing access to the
> > file. By allowing access to a file before its measurement is included
> > in the measurement list and extended into the TPM PCR, a malicious file
> > could potentially prevent its own measurement from being added. As the
> > PCRs are tamper proof, measuring and extending the TPM prior to giving
> > access to the file, guarantees that all file measurements are included
> > in the measurement list, including the malicious file.
> >
> > IMA needs to be enabled before any files are accessed in order to
> > verify a file's integrity and extend the TPM with the file
> > measurement. Queueing file measurements breaks the measure and extend,
> > before usage, trusted boot paradigm.
> >
> > The ima-evm-utils package includes a test for walking the IMA
> > measurement list, calculating the expected TPM PCRs, and comparing the
> > calculated PCR values with the physical TPM. Testing is important to
> > ensure the TPM is initialized prior to IMA. Failure to validate the
> > IMA measurement list may indicate IMA went into TPM bypass mode, like
> > in this case.
>
> Thanks for the explanation Mimi. It's lucky that the TPM drivers can
> be loaded early enough!
>
> Should we add something like this to security/integrity/ima/Kconfig?
>
> select I2C_OPAL if PPC_POWERNV
>
> It's generally frowned upon to select user visible symbols, but IMA
> does this for the TCG options already.
The other examples enable the TPM. I2C_OPAL is dependent on I2C being
builtin. I'm not sure if this select is complete, nor if this is where
it belongs.
Mimi
^ permalink raw reply
* Re: [PATCH] linux: configure CONFIG_I2C_OPAL as in-built.
From: Nayna @ 2020-09-29 13:17 UTC (permalink / raw)
To: Joel Stanley, linuxppc-dev
Cc: openpower-firmware, Nayna Jain, klaus, Mimi Zohar
In-Reply-To: <CACPK8XdeAzbXcm2w6kJuAQzckdyFQ2P9h+fC36ZArpkubqC1mg@mail.gmail.com>
On 9/29/20 2:14 AM, Joel Stanley wrote:
> On Fri, 25 Sep 2020 at 18:19, Mimi Zohar <zohar@linux.ibm.com> wrote:
>> Hi Nayna,
>>
>> On Wed, 2020-09-23 at 14:25 -0400, Nayna Jain wrote:
>>> Currently, skiroot_defconfig CONFIG_I2C_OPAL is built as a loadable
>>> module rather than builtin, even if CONFIG_I2C=y is defined. This
>>> results in a delay in the TPM initialization, causing IMA to go into
>>> TPM bypass mode. As a result, the IMA measurements are added to the
>>> measurement list, but do not extend the TPM. Because of this, it is
>>> impossible to verify or attest to the system's integrity, either from
>>> skiroot or the target Host OS.
>> The patch description is good, but perhaps we could provide a bit more
>> context before.
>>
>> The concept of trusted boot requires the measurement to be added to the
>> measurement list and extend the TPM, prior to allowing access to the
>> file. By allowing access to a file before its measurement is included
>> in the measurement list and extended into the TPM PCR, a malicious file
>> could potentially prevent its own measurement from being added. As the
>> PCRs are tamper proof, measuring and extending the TPM prior to giving
>> access to the file, guarantees that all file measurements are included
>> in the measurement list, including the malicious file.
>>
>> IMA needs to be enabled before any files are accessed in order to
>> verify a file's integrity and extend the TPM with the file
>> measurement. Queueing file measurements breaks the measure and extend,
>> before usage, trusted boot paradigm.
>>
>> The ima-evm-utils package includes a test for walking the IMA
>> measurement list, calculating the expected TPM PCRs, and comparing the
>> calculated PCR values with the physical TPM. Testing is important to
>> ensure the TPM is initialized prior to IMA. Failure to validate the
>> IMA measurement list may indicate IMA went into TPM bypass mode, like
>> in this case.
> Thanks for the explanation Mimi. It's lucky that the TPM drivers can
> be loaded early enough!
>
> Should we add something like this to security/integrity/ima/Kconfig?
>
> select I2C_OPAL if PPC_POWERNV
>
> It's generally frowned upon to select user visible symbols, but IMA
> does this for the TCG options already.
I think yes, but in drivers/i2c/Kconfig and not in IMA Kconfig.
IMA is dependent on TPM, and it is specified in IMA Kconfig.
TPM NUVOTON driver has its dependency on I2C, which is taken care in
drivers/char/tpm/Kconfig
It is I2C driver which is dependent on I2C_OPAL for its functioning on
POWERNV Systems.
Thanks & Regards,
- Nayna
^ permalink raw reply
* Re: [PATCH v2 2/3] lkdtm/powerpc: Add SLB multihit test
From: Michal Suchánek @ 2020-09-29 15:01 UTC (permalink / raw)
To: Kees Cook; +Cc: linuxppc-dev, Ganesh Goudar, mahesh, npiggin
In-Reply-To: <202009251244.A4396AFF@keescook>
Hello,
On Fri, Sep 25, 2020 at 12:57:33PM -0700, Kees Cook wrote:
> On Fri, Sep 25, 2020 at 04:01:22PM +0530, Ganesh Goudar wrote:
> > Add support to inject slb multihit errors, to test machine
> > check handling.
>
> Thank you for more tests in here!
Thanks for working on integrating this.
>
> >
> > Based on work by Mahesh Salgaonkar and Michal Suchánek.
> >
> > Cc: Mahesh Salgaonkar <mahesh@linux.ibm.com>
> > Cc: Michal Suchánek <msuchanek@suse.de>
>
> Should these be Co-developed-by: with S-o-b?
I don't think I wrote any of this code. I packaged it for SUSE and maybe
changed some constants based on test result discussion.
I compared this code to my saved snapshots of past versions of the test
module and this covers all the test cases I have. The only difference is that
the development modules have verbose prints showing what's going on.
It is true that without the verbose prints some explanatory comments
could be helpful.
Reviewed-by: Michal Suchánek <msuchanek@suse.de>
>
> > Signed-off-by: Ganesh Goudar <ganeshgr@linux.ibm.com>
> > ---
> > drivers/misc/lkdtm/Makefile | 4 ++
> > drivers/misc/lkdtm/core.c | 3 +
> > drivers/misc/lkdtm/lkdtm.h | 3 +
> > drivers/misc/lkdtm/powerpc.c | 132 +++++++++++++++++++++++++++++++++++
> > 4 files changed, 142 insertions(+)
> > create mode 100644 drivers/misc/lkdtm/powerpc.c
> >
> > diff --git a/drivers/misc/lkdtm/Makefile b/drivers/misc/lkdtm/Makefile
> > index c70b3822013f..6a82f407fbcd 100644
> > --- a/drivers/misc/lkdtm/Makefile
> > +++ b/drivers/misc/lkdtm/Makefile
> > @@ -11,6 +11,10 @@ lkdtm-$(CONFIG_LKDTM) += usercopy.o
> > lkdtm-$(CONFIG_LKDTM) += stackleak.o
> > lkdtm-$(CONFIG_LKDTM) += cfi.o
> >
> > +ifeq ($(CONFIG_PPC64),y)
> > +lkdtm-$(CONFIG_LKDTM) += powerpc.o
> > +endif
>
> This can just be:
>
> lkdtm-$(CONFIG_PPC64) += powerpc.o
>
> > +
> > KASAN_SANITIZE_stackleak.o := n
> > KCOV_INSTRUMENT_rodata.o := n
> >
> > diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c
> > index a5e344df9166..8d5db42baa90 100644
> > --- a/drivers/misc/lkdtm/core.c
> > +++ b/drivers/misc/lkdtm/core.c
> > @@ -178,6 +178,9 @@ static const struct crashtype crashtypes[] = {
> > #ifdef CONFIG_X86_32
> > CRASHTYPE(DOUBLE_FAULT),
> > #endif
> > +#ifdef CONFIG_PPC64
> > + CRASHTYPE(PPC_SLB_MULTIHIT),
> > +#endif
> > };
> >
> >
> > diff --git a/drivers/misc/lkdtm/lkdtm.h b/drivers/misc/lkdtm/lkdtm.h
> > index 8878538b2c13..b305bd511ee5 100644
> > --- a/drivers/misc/lkdtm/lkdtm.h
> > +++ b/drivers/misc/lkdtm/lkdtm.h
> > @@ -104,4 +104,7 @@ void lkdtm_STACKLEAK_ERASING(void);
> > /* cfi.c */
> > void lkdtm_CFI_FORWARD_PROTO(void);
> >
> > +/* powerpc.c */
> > +void lkdtm_PPC_SLB_MULTIHIT(void);
> > +
> > #endif
> > diff --git a/drivers/misc/lkdtm/powerpc.c b/drivers/misc/lkdtm/powerpc.c
> > new file mode 100644
> > index 000000000000..d6db18444757
> > --- /dev/null
> > +++ b/drivers/misc/lkdtm/powerpc.c
> > @@ -0,0 +1,132 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +
>
> Please #include "lkdtm.h" here to get the correct pr_fmt heading (and
> any future header adjustments).
>
> > +#include <linux/slab.h>
> > +#include <linux/vmalloc.h>
> > +
> > +static inline unsigned long get_slb_index(void)
> > +{
> > + unsigned long index;
> > +
> > + index = get_paca()->stab_rr;
> > +
> > + /*
> > + * simple round-robin replacement of slb starting at SLB_NUM_BOLTED.
> > + */
> > + if (index < (mmu_slb_size - 1))
> > + index++;
> > + else
> > + index = SLB_NUM_BOLTED;
> > + get_paca()->stab_rr = index;
> > + return index;
> > +}
> > +
> > +#define slb_esid_mask(ssize) \
> > + (((ssize) == MMU_SEGSIZE_256M) ? ESID_MASK : ESID_MASK_1T)
> > +
> > +static inline unsigned long mk_esid_data(unsigned long ea, int ssize,
> > + unsigned long slot)
> > +{
> > + return (ea & slb_esid_mask(ssize)) | SLB_ESID_V | slot;
> > +}
> > +
> > +#define slb_vsid_shift(ssize) \
> > + ((ssize) == MMU_SEGSIZE_256M ? SLB_VSID_SHIFT : SLB_VSID_SHIFT_1T)
> > +
> > +static inline unsigned long mk_vsid_data(unsigned long ea, int ssize,
> > + unsigned long flags)
> > +{
> > + return (get_kernel_vsid(ea, ssize) << slb_vsid_shift(ssize)) | flags |
> > + ((unsigned long)ssize << SLB_VSID_SSIZE_SHIFT);
> > +}
> > +
> > +static void insert_slb_entry(char *p, int ssize)
> > +{
> > + unsigned long flags, entry;
> > +
> > + flags = SLB_VSID_KERNEL | mmu_psize_defs[MMU_PAGE_64K].sllp;
> > + preempt_disable();
> > +
> > + entry = get_slb_index();
> > + asm volatile("slbmte %0,%1" :
> > + : "r" (mk_vsid_data((unsigned long)p, ssize, flags)),
> > + "r" (mk_esid_data((unsigned long)p, ssize, entry))
> > + : "memory");
> > +
> > + entry = get_slb_index();
> > + asm volatile("slbmte %0,%1" :
> > + : "r" (mk_vsid_data((unsigned long)p, ssize, flags)),
> > + "r" (mk_esid_data((unsigned long)p, ssize, entry))
> > + : "memory");
> > + preempt_enable();
> > + p[0] = '!';
> > +}
>
> Can you add some comments to these helpers? It'll help people (me) with
> understanding what is actually being done here (and more importantly,
> what is _expected_ to happen).
>
> > +
> > +static void inject_vmalloc_slb_multihit(void)
> > +{
> > + char *p;
> > +
> > + p = vmalloc(2048);
> > + if (!p)
> > + return;
> > +
> > + insert_slb_entry(p, MMU_SEGSIZE_1T);
> > + vfree(p);
> > +}
> > +
> > +static void inject_kmalloc_slb_multihit(void)
> > +{
> > + char *p;
> > +
> > + p = kmalloc(2048, GFP_KERNEL);
> > + if (!p)
> > + return;
> > +
> > + insert_slb_entry(p, MMU_SEGSIZE_1T);
> > + kfree(p);
> > +}
>
> It looks like the expected failure injection is actually the "p[0] = '!'" line in the
> "insert" helper? I would expect pr_info/pr_err wrappers, etc, as in
> other lkdtm tests.
>
> If this is the negative test, what does the positive test look like?
> e.g. in other lkdtm tests, first a positive test is done, then a
> negative: first run a legit function, then run a function from a bad
> location.
>
> > +
> > +static void insert_dup_slb_entry_0(void)
> > +{
> > + unsigned long test_address = 0xC000000000000000;
> > + volatile unsigned long *test_ptr;
> > + unsigned long entry, i = 0;
> > + unsigned long esid, vsid;
> > +
> > + test_ptr = (unsigned long *)test_address;
> > + preempt_disable();
> > +
> > + asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
> > + asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
> > + entry = get_slb_index();
> > +
> > + /* for i !=0 we would need to mask out the old entry number */
> > + asm volatile("slbmte %0,%1" :
> > + : "r" (vsid),
> > + "r" (esid | entry)
> > + : "memory");
> > +
> > + asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
> > + asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
> > + entry = get_slb_index();
> > +
> > + /* for i !=0 we would need to mask out the old entry number */
> > + asm volatile("slbmte %0,%1" :
> > + : "r" (vsid),
> > + "r" (esid | entry)
> > + : "memory");
> > +
> > + pr_info("lkdtm: %s accessing test address 0x%lx: 0x%lx\n",
> > + __func__, test_address, *test_ptr);
> > +
> > + preempt_enable();
> > +}
>
> What does this do?
>
> > +
> > +void lkdtm_PPC_SLB_MULTIHIT(void)
> > +{
> > + if (mmu_has_feature(MMU_FTR_HPTE_TABLE)) {
> > + inject_vmalloc_slb_multihit();
> > + inject_kmalloc_slb_multihit();
> > + insert_dup_slb_entry_0();
> > + }
> > + pr_info("Recovered from SLB multihit. (Ignore this message on non HPTE machines)");
>
> Is this bad? If so, I'd expect pr_err("FAIL: ...") Can HPTE machines be
> detected so that an XFAIL can be emitted instead?
>
> Since there are three (two?) distinct regions being tested, should these
> be separate tests? Right now there is no way to separate a vmalloc
> failure from a kmalloc failure, and no way to fail the first without
> hiding the result from the latter (or maybe the machine cannot survive
> this test? ... which should also be a comment.)
>
> And finally, assuming a successful test (or testing from a separate
> thread later), so there any state that needs to be restored (or cleaned
> up before doing the "insert" calls)?
>
> Thanks!
>
> --
> Kees Cook
^ permalink raw reply
* Re: [PATCH] powerpc: net: bpf_jit_comp: Fix misuse of fallthrough
From: Daniel Borkmann @ 2020-09-29 14:41 UTC (permalink / raw)
To: zhe.he, gustavo, netdev, bpf, linuxppc-dev, linux-kernel
In-Reply-To: <20200928090023.38117-1-zhe.he@windriver.com>
On 9/28/20 11:00 AM, zhe.he@windriver.com wrote:
> From: He Zhe <zhe.he@windriver.com>
>
> The user defined label following "fallthrough" is not considered by GCC
> and causes build failure.
>
> kernel-source/include/linux/compiler_attributes.h:208:41: error: attribute
> 'fallthrough' not preceding a case label or default label [-Werror]
> 208 define fallthrough _attribute((fallthrough_))
> ^~~~~~~~~~~~~
>
> Signed-off-by: He Zhe <zhe.he@windriver.com>
Applied, thanks! I've also added Fixes tag with df561f6688fe ("treewide: Use fallthrough pseudo-keyword")
which added the bug.
^ permalink raw reply
* Re: [PATCH v2 01/14] powerpc/pseries/iommu: Replace hard-coded page shift
From: Leonardo Bras @ 2020-09-29 18:25 UTC (permalink / raw)
To: Alexey Kardashevskiy, Michael Ellerman, Benjamin Herrenschmidt,
Paul Mackerras, Joel Stanley, Christophe Leroy,
Thiago Jung Bauermann, Ram Pai, Brian King,
Murilo Fossa Vicentini, David Dai
Cc: linuxppc-dev
In-Reply-To: <5c23f1f9-4cb5-be24-3064-258c0f68c77c@ozlabs.ru>
On Tue, 2020-09-29 at 13:56 +1000, Alexey Kardashevskiy wrote:
>
> On 12/09/2020 03:07, Leonardo Bras wrote:
> > Cc: linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org,
>
> These normally go right before "signed-off-by".
>
Yeah, it looks like something went wrong between git format-patch and
git send-email. I will look for in in the next series.
>
> > Some functions assume IOMMU page size can only be 4K (pageshift == 12).
> > Update them to accept any page size passed, so we can use 64K pages.
> >
> > In the process, some defines like TCE_SHIFT were made obsolete, and then
> > removed.
> >
> > IODA3 Revision 3.0_prd1 (OpenPowerFoundation), Figures 3.4 and 3.5 show
> > a RPN of 52-bit, and considers a 12-bit pageshift, so there should be
> > no need of using TCE_RPN_MASK, which masks out any bit after 40 in rpn.
> > It's usage removed from tce_build_pSeries(), tce_build_pSeriesLP(), and
> > tce_buildmulti_pSeriesLP().
> >
> > Most places had a tbl struct, so using tbl->it_page_shift was simple.
> > tce_free_pSeriesLP() was a special case, since callers not always have a
> > tbl struct, so adding a tceshift parameter seems the right thing to do.
> >
> > Signed-off-by: Leonardo Bras <leobras.c@gmail.com>
>
> Reviewed-by: Alexey Kardashevskiy <aik@ozlabs.ru>
Thanks for reviewing!
>
>
> > ---
> > arch/powerpc/include/asm/tce.h | 8 ------
> > arch/powerpc/platforms/pseries/iommu.c | 39 +++++++++++++++-----------
> > 2 files changed, 23 insertions(+), 24 deletions(-)
> >
> > diff --git a/arch/powerpc/include/asm/tce.h b/arch/powerpc/include/asm/tce.h
> > index db5fc2f2262d..0c34d2756d92 100644
> > --- a/arch/powerpc/include/asm/tce.h
> > +++ b/arch/powerpc/include/asm/tce.h
> > @@ -19,15 +19,7 @@
> > #define TCE_VB 0
> > #define TCE_PCI 1
> >
> > -/* TCE page size is 4096 bytes (1 << 12) */
> > -
> > -#define TCE_SHIFT 12
> > -#define TCE_PAGE_SIZE (1 << TCE_SHIFT)
> > -
> > #define TCE_ENTRY_SIZE 8 /* each TCE is 64 bits */
> > -
> > -#define TCE_RPN_MASK 0xfffffffffful /* 40-bit RPN (4K pages) */
> > -#define TCE_RPN_SHIFT 12
> > #define TCE_VALID 0x800 /* TCE valid */
> > #define TCE_ALLIO 0x400 /* TCE valid for all lpars */
> > #define TCE_PCI_WRITE 0x2 /* write from PCI allowed */
> > diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
> > index e4198700ed1a..9db3927607a4 100644
> > --- a/arch/powerpc/platforms/pseries/iommu.c
> > +++ b/arch/powerpc/platforms/pseries/iommu.c
> > @@ -107,6 +107,8 @@ static int tce_build_pSeries(struct iommu_table *tbl, long index,
> > u64 proto_tce;
> > __be64 *tcep;
> > u64 rpn;
> > + const unsigned long tceshift = tbl->it_page_shift;
> > + const unsigned long pagesize = IOMMU_PAGE_SIZE(tbl);
> >
> > proto_tce = TCE_PCI_READ; // Read allowed
> >
> > @@ -117,10 +119,10 @@ static int tce_build_pSeries(struct iommu_table *tbl, long index,
> >
> > while (npages--) {
> > /* can't move this out since we might cross MEMBLOCK boundary */
> > - rpn = __pa(uaddr) >> TCE_SHIFT;
> > - *tcep = cpu_to_be64(proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT);
> > + rpn = __pa(uaddr) >> tceshift;
> > + *tcep = cpu_to_be64(proto_tce | rpn << tceshift);
> >
> > - uaddr += TCE_PAGE_SIZE;
> > + uaddr += pagesize;
> > tcep++;
> > }
> > return 0;
> > @@ -146,7 +148,7 @@ static unsigned long tce_get_pseries(struct iommu_table *tbl, long index)
> > return be64_to_cpu(*tcep);
> > }
> >
> > -static void tce_free_pSeriesLP(unsigned long liobn, long, long);
> > +static void tce_free_pSeriesLP(unsigned long liobn, long, long, long);
> > static void tce_freemulti_pSeriesLP(struct iommu_table*, long, long);
> >
> > static int tce_build_pSeriesLP(unsigned long liobn, long tcenum, long tceshift,
> > @@ -166,12 +168,12 @@ static int tce_build_pSeriesLP(unsigned long liobn, long tcenum, long tceshift,
> > proto_tce |= TCE_PCI_WRITE;
> >
> > while (npages--) {
> > - tce = proto_tce | (rpn & TCE_RPN_MASK) << tceshift;
> > + tce = proto_tce | rpn << tceshift;
> > rc = plpar_tce_put((u64)liobn, (u64)tcenum << tceshift, tce);
> >
> > if (unlikely(rc == H_NOT_ENOUGH_RESOURCES)) {
> > ret = (int)rc;
> > - tce_free_pSeriesLP(liobn, tcenum_start,
> > + tce_free_pSeriesLP(liobn, tcenum_start, tceshift,
> > (npages_start - (npages + 1)));
> > break;
> > }
> > @@ -205,10 +207,11 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
> > long tcenum_start = tcenum, npages_start = npages;
> > int ret = 0;
> > unsigned long flags;
> > + const unsigned long tceshift = tbl->it_page_shift;
> >
> > if ((npages == 1) || !firmware_has_feature(FW_FEATURE_PUT_TCE_IND)) {
> > return tce_build_pSeriesLP(tbl->it_index, tcenum,
> > - tbl->it_page_shift, npages, uaddr,
> > + tceshift, npages, uaddr,
> > direction, attrs);
> > }
> >
> > @@ -225,13 +228,13 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
> > if (!tcep) {
> > local_irq_restore(flags);
> > return tce_build_pSeriesLP(tbl->it_index, tcenum,
> > - tbl->it_page_shift,
> > + tceshift,
> > npages, uaddr, direction, attrs);
> > }
> > __this_cpu_write(tce_page, tcep);
> > }
> >
> > - rpn = __pa(uaddr) >> TCE_SHIFT;
> > + rpn = __pa(uaddr) >> tceshift;
> > proto_tce = TCE_PCI_READ;
> > if (direction != DMA_TO_DEVICE)
> > proto_tce |= TCE_PCI_WRITE;
> > @@ -245,12 +248,12 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
> > limit = min_t(long, npages, 4096/TCE_ENTRY_SIZE);
> >
> > for (l = 0; l < limit; l++) {
> > - tcep[l] = cpu_to_be64(proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT);
> > + tcep[l] = cpu_to_be64(proto_tce | rpn << tceshift);
> > rpn++;
> > }
> >
> > rc = plpar_tce_put_indirect((u64)tbl->it_index,
> > - (u64)tcenum << 12,
> > + (u64)tcenum << tceshift,
> > (u64)__pa(tcep),
> > limit);
> >
> > @@ -277,12 +280,13 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
> > return ret;
> > }
> >
> > -static void tce_free_pSeriesLP(unsigned long liobn, long tcenum, long npages)
> > +static void tce_free_pSeriesLP(unsigned long liobn, long tcenum, long tceshift,
> > + long npages)
> > {
> > u64 rc;
> >
> > while (npages--) {
> > - rc = plpar_tce_put((u64)liobn, (u64)tcenum << 12, 0);
> > + rc = plpar_tce_put((u64)liobn, (u64)tcenum << tceshift, 0);
> >
> > if (rc && printk_ratelimit()) {
> > printk("tce_free_pSeriesLP: plpar_tce_put failed. rc=%lld\n", rc);
> > @@ -301,9 +305,11 @@ static void tce_freemulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long n
> > u64 rc;
> >
> > if (!firmware_has_feature(FW_FEATURE_STUFF_TCE))
> > - return tce_free_pSeriesLP(tbl->it_index, tcenum, npages);
> > + return tce_free_pSeriesLP(tbl->it_index, tcenum,
> > + tbl->it_page_shift, npages);
> >
> > - rc = plpar_tce_stuff((u64)tbl->it_index, (u64)tcenum << 12, 0, npages);
> > + rc = plpar_tce_stuff((u64)tbl->it_index,
> > + (u64)tcenum << tbl->it_page_shift, 0, npages);
> >
> > if (rc && printk_ratelimit()) {
> > printk("tce_freemulti_pSeriesLP: plpar_tce_stuff failed\n");
> > @@ -319,7 +325,8 @@ static unsigned long tce_get_pSeriesLP(struct iommu_table *tbl, long tcenum)
> > u64 rc;
> > unsigned long tce_ret;
> >
> > - rc = plpar_tce_get((u64)tbl->it_index, (u64)tcenum << 12, &tce_ret);
> > + rc = plpar_tce_get((u64)tbl->it_index,
> > + (u64)tcenum << tbl->it_page_shift, &tce_ret);
> >
> > if (rc && printk_ratelimit()) {
> > printk("tce_get_pSeriesLP: plpar_tce_get failed. rc=%lld\n", rc);
> >
^ permalink raw reply
* Re: [PATCH v2 devicetree 2/2] powerpc: dts: t1040rdb: add ports for Seville Ethernet switch
From: Andrew Lunn @ 2020-09-29 19:11 UTC (permalink / raw)
To: Vladimir Oltean
Cc: devicetree, madalin.bucur, radu-andrei.bulie, linuxppc-dev,
linux-kernel, fido_max, robh+dt, paulus, Vladimir Oltean,
shawnguo, netdev
In-Reply-To: <20200929113209.3767787-3-vladimir.oltean@nxp.com>
> +&seville_port0 {
> + managed = "in-band-status";
> + phy-handle = <&phy_qsgmii_0>;
> + phy-mode = "qsgmii";
> + /* ETH4 written on chassis */
> + label = "swp4";
If ETH4 is on the chassis why not use ETH4?
Andrew
^ permalink raw reply
* Re: [PATCH v2 devicetree 2/2] powerpc: dts: t1040rdb: add ports for Seville Ethernet switch
From: Andrew Lunn @ 2020-09-29 20:10 UTC (permalink / raw)
To: Vladimir Oltean
Cc: devicetree@vger.kernel.org, Madalin Bucur (OSS),
Radu-andrei Bulie, linuxppc-dev@lists.ozlabs.org,
linux-kernel@vger.kernel.org, fido_max@inbox.ru,
robh+dt@kernel.org, paulus@samba.org, Vladimir Oltean,
shawnguo@kernel.org, netdev@vger.kernel.org
In-Reply-To: <20200929193953.rgibttgt6lh5huef@skbuf>
On Tue, Sep 29, 2020 at 07:39:54PM +0000, Vladimir Oltean wrote:
> On Tue, Sep 29, 2020 at 09:11:53PM +0200, Andrew Lunn wrote:
> > > +&seville_port0 {
> > > + managed = "in-band-status";
> > > + phy-handle = <&phy_qsgmii_0>;
> > > + phy-mode = "qsgmii";
> > > + /* ETH4 written on chassis */
> > > + label = "swp4";
> >
> > If ETH4 is on the chassis why not use ETH4?
>
> You mean all-caps, just like that?
Yes.
DSA is often used in WiFI access point, etc. The user is not a
computer professional. If the WebGUI says ETH4, and the label on the
front says ETH4, they probably think the two are the same, and are
happy.
I have one box which does not have an labels on the front panels, but
the industrial sockets for Ethernet are colour coded. So the interface
names are red, blue, green, to match the socket colour, and the cable
set is also colour coded the same.
So long as it is unique, the kernel does not care. So make it easy for
the user.
Andrew
^ permalink raw reply
* Re: [PATCH v2 14/14] powerpc/pseries/iommu: Rename "direct window" to "dma window"
From: Leonardo Bras @ 2020-09-29 20:54 UTC (permalink / raw)
To: Alexey Kardashevskiy, Michael Ellerman, Benjamin Herrenschmidt,
Paul Mackerras, Joel Stanley, Christophe Leroy,
Thiago Jung Bauermann, Ram Pai, Brian King,
Murilo Fossa Vicentini, David Dai
Cc: linuxppc-dev
In-Reply-To: <2ba89065-4e9c-57c2-3825-aed9a7d8451a@ozlabs.ru>
On Tue, 2020-09-29 at 13:55 +1000, Alexey Kardashevskiy wrote:
>
> On 12/09/2020 03:07, Leonardo Bras wrote:
> > Cc: linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org,
> >
> > A previous change introduced the usage of DDW as a bigger indirect DMA
> > mapping when the DDW available size does not map the whole partition.
> >
> > As most of the code that manipulates direct mappings was reused for
> > indirect mappings, it's necessary to rename all names and debug/info
> > messages to reflect that it can be used for both kinds of mapping.
> >
> > Also, defines DEFAULT_DMA_WIN as "ibm,dma-window" to document that
> > it's the name of the default DMA window.
>
> "ibm,dma-window" is so old so it does not need a macro (which btw would
> be DMA_WIN_PROPNAME to match the other names) :)
Thanks for bringing that to my attention!
In fact, DMA_WIN_PROPNAME makes more sense, but it's still generic and
doesn't look to point to a generic one.
Would that be ok to call it DEFAULT_WIN_PROPNAME ?
>
>
> > Those changes are not supposed to change how the code works in any
> > way, just adjust naming.
>
> I simply have this in my .vimrc for the cases like this one:
>
> ===
> This should cause no behavioural change.
> ===
Great tip! I will make sure to have this saved here :)
Thank you!
^ permalink raw reply
* [PATCH v2 devicetree 0/2] Add Seville Ethernet switch to T1040RDB
From: Vladimir Oltean @ 2020-09-29 11:32 UTC (permalink / raw)
To: robh+dt, shawnguo, mpe, devicetree
Cc: madalin.bucur, linux-kernel, radu-andrei.bulie, fido_max, paulus,
netdev, linuxppc-dev
Seville is a DSA switch that is embedded inside the T1040 SoC, and
supported by the mscc_seville DSA driver inside drivers/net/dsa/ocelot.
This series adds this switch to the SoC's dtsi files and to the T1040RDB
board file.
Vladimir Oltean (2):
powerpc: dts: t1040: add bindings for Seville Ethernet switch
powerpc: dts: t1040rdb: add ports for Seville Ethernet switch
arch/powerpc/boot/dts/fsl/t1040rdb.dts | 115 ++++++++++++++++++++
arch/powerpc/boot/dts/fsl/t1040si-post.dtsi | 76 +++++++++++++
2 files changed, 191 insertions(+)
--
2.25.1
^ permalink raw reply
* [PATCH v2 devicetree 1/2] powerpc: dts: t1040: add bindings for Seville Ethernet switch
From: Vladimir Oltean @ 2020-09-29 11:32 UTC (permalink / raw)
To: robh+dt, shawnguo, mpe, devicetree
Cc: madalin.bucur, linux-kernel, radu-andrei.bulie, fido_max, paulus,
netdev, linuxppc-dev
In-Reply-To: <20200929113209.3767787-1-vladimir.oltean@nxp.com>
Add the description of the embedded L2 switch inside the SoC dtsi file
for NXP T1040.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
Changes in v2:
Make switch node disabled by default.
arch/powerpc/boot/dts/fsl/t1040si-post.dtsi | 76 +++++++++++++++++++++
1 file changed, 76 insertions(+)
diff --git a/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi b/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi
index 315d0557eefc..5cb90c66cd3f 100644
--- a/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi
@@ -628,6 +628,82 @@ mdio@fd000 {
status = "disabled";
};
};
+
+ seville_switch: ethernet-switch@800000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "mscc,vsc9953-switch";
+ reg = <0x800000 0x290000>;
+ little-endian;
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ seville_port0: port@0 {
+ reg = <0>;
+ status = "disabled";
+ };
+
+ seville_port1: port@1 {
+ reg = <1>;
+ status = "disabled";
+ };
+
+ seville_port2: port@2 {
+ reg = <2>;
+ status = "disabled";
+ };
+
+ seville_port3: port@3 {
+ reg = <3>;
+ status = "disabled";
+ };
+
+ seville_port4: port@4 {
+ reg = <4>;
+ status = "disabled";
+ };
+
+ seville_port5: port@5 {
+ reg = <5>;
+ status = "disabled";
+ };
+
+ seville_port6: port@6 {
+ reg = <6>;
+ status = "disabled";
+ };
+
+ seville_port7: port@7 {
+ reg = <7>;
+ status = "disabled";
+ };
+
+ seville_port8: port@8 {
+ reg = <8>;
+ phy-mode = "internal";
+ status = "disabled";
+
+ fixed-link {
+ speed = <2500>;
+ full-duplex;
+ };
+ };
+
+ seville_port9: port@9 {
+ reg = <9>;
+ phy-mode = "internal";
+ status = "disabled";
+
+ fixed-link {
+ speed = <2500>;
+ full-duplex;
+ };
+ };
+ };
+ };
};
&qe {
--
2.25.1
^ permalink raw reply related
* [PATCH v2 devicetree 2/2] powerpc: dts: t1040rdb: add ports for Seville Ethernet switch
From: Vladimir Oltean @ 2020-09-29 11:32 UTC (permalink / raw)
To: robh+dt, shawnguo, mpe, devicetree
Cc: madalin.bucur, linux-kernel, radu-andrei.bulie, fido_max, paulus,
netdev, Vladimir Oltean, linuxppc-dev
In-Reply-To: <20200929113209.3767787-1-vladimir.oltean@nxp.com>
From: Vladimir Oltean <olteanv@gmail.com>
Define the network interface names for the switch ports and hook them up
to the 2 QSGMII PHYs that are onboard.
A conscious decision was taken to go along with the numbers that are
written on the front panel of the board and not with the hardware
numbers of the switch chip ports. The 2 numbering schemes are
shifted by 8.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
Changes in v2:
Use the existing way of accessing the mdio bus and not labels.
arch/powerpc/boot/dts/fsl/t1040rdb.dts | 115 +++++++++++++++++++++++++
1 file changed, 115 insertions(+)
diff --git a/arch/powerpc/boot/dts/fsl/t1040rdb.dts b/arch/powerpc/boot/dts/fsl/t1040rdb.dts
index 65ff34c49025..3fd08a2b6dcb 100644
--- a/arch/powerpc/boot/dts/fsl/t1040rdb.dts
+++ b/arch/powerpc/boot/dts/fsl/t1040rdb.dts
@@ -64,6 +64,40 @@ mdio@fc000 {
phy_sgmii_2: ethernet-phy@3 {
reg = <0x03>;
};
+
+ /* VSC8514 QSGMII PHY */
+ phy_qsgmii_0: ethernet-phy@4 {
+ reg = <0x4>;
+ };
+
+ phy_qsgmii_1: ethernet-phy@5 {
+ reg = <0x5>;
+ };
+
+ phy_qsgmii_2: ethernet-phy@6 {
+ reg = <0x6>;
+ };
+
+ phy_qsgmii_3: ethernet-phy@7 {
+ reg = <0x7>;
+ };
+
+ /* VSC8514 QSGMII PHY */
+ phy_qsgmii_4: ethernet-phy@8 {
+ reg = <0x8>;
+ };
+
+ phy_qsgmii_5: ethernet-phy@9 {
+ reg = <0x9>;
+ };
+
+ phy_qsgmii_6: ethernet-phy@a {
+ reg = <0xa>;
+ };
+
+ phy_qsgmii_7: ethernet-phy@b {
+ reg = <0xb>;
+ };
};
};
};
@@ -76,3 +110,84 @@ cpld@3,0 {
};
#include "t1040si-post.dtsi"
+
+&seville_switch {
+ status = "okay";
+};
+
+&seville_port0 {
+ managed = "in-band-status";
+ phy-handle = <&phy_qsgmii_0>;
+ phy-mode = "qsgmii";
+ /* ETH4 written on chassis */
+ label = "swp4";
+ status = "okay";
+};
+
+&seville_port1 {
+ managed = "in-band-status";
+ phy-handle = <&phy_qsgmii_1>;
+ phy-mode = "qsgmii";
+ /* ETH5 written on chassis */
+ label = "swp5";
+ status = "okay";
+};
+
+&seville_port2 {
+ managed = "in-band-status";
+ phy-handle = <&phy_qsgmii_2>;
+ phy-mode = "qsgmii";
+ /* ETH6 written on chassis */
+ label = "swp6";
+ status = "okay";
+};
+
+&seville_port3 {
+ managed = "in-band-status";
+ phy-handle = <&phy_qsgmii_3>;
+ phy-mode = "qsgmii";
+ /* ETH7 written on chassis */
+ label = "swp7";
+ status = "okay";
+};
+
+&seville_port4 {
+ managed = "in-band-status";
+ phy-handle = <&phy_qsgmii_4>;
+ phy-mode = "qsgmii";
+ /* ETH8 written on chassis */
+ label = "swp8";
+ status = "okay";
+};
+
+&seville_port5 {
+ managed = "in-band-status";
+ phy-handle = <&phy_qsgmii_5>;
+ phy-mode = "qsgmii";
+ /* ETH9 written on chassis */
+ label = "swp9";
+ status = "okay";
+};
+
+&seville_port6 {
+ managed = "in-band-status";
+ phy-handle = <&phy_qsgmii_6>;
+ phy-mode = "qsgmii";
+ /* ETH10 written on chassis */
+ label = "swp10";
+ status = "okay";
+};
+
+&seville_port7 {
+ managed = "in-band-status";
+ phy-handle = <&phy_qsgmii_7>;
+ phy-mode = "qsgmii";
+ /* ETH11 written on chassis */
+ label = "swp11";
+ status = "okay";
+};
+
+&seville_port8 {
+ ethernet = <&enet0>;
+ status = "okay";
+};
--
2.25.1
^ permalink raw reply related
* Re: [PATCH v2 devicetree 1/2] powerpc: dts: t1040: add bindings for Seville Ethernet switch
From: Maxim Kochetkov @ 2020-09-29 13:12 UTC (permalink / raw)
To: Vladimir Oltean, robh+dt, shawnguo, mpe, devicetree
Cc: madalin.bucur, linux-kernel, radu-andrei.bulie, paulus, netdev,
linuxppc-dev
In-Reply-To: <20200929113209.3767787-2-vladimir.oltean@nxp.com>
Reviewed-by: Maxim Kochetkov <fido_max@inbox.ru>
29.09.2020 14:32, Vladimir Oltean пишет:
> Add the description of the embedded L2 switch inside the SoC dtsi file
> for NXP T1040.
>
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> ---
> Changes in v2:
> Make switch node disabled by default.
>
> arch/powerpc/boot/dts/fsl/t1040si-post.dtsi | 76 +++++++++++++++++++++
> 1 file changed, 76 insertions(+)
>
> diff --git a/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi b/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi
> index 315d0557eefc..5cb90c66cd3f 100644
> --- a/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi
> +++ b/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi
> @@ -628,6 +628,82 @@ mdio@fd000 {
> status = "disabled";
> };
> };
> +
> + seville_switch: ethernet-switch@800000 {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + compatible = "mscc,vsc9953-switch";
> + reg = <0x800000 0x290000>;
> + little-endian;
> + status = "disabled";
> +
> + ports {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + seville_port0: port@0 {
> + reg = <0>;
> + status = "disabled";
> + };
> +
> + seville_port1: port@1 {
> + reg = <1>;
> + status = "disabled";
> + };
> +
> + seville_port2: port@2 {
> + reg = <2>;
> + status = "disabled";
> + };
> +
> + seville_port3: port@3 {
> + reg = <3>;
> + status = "disabled";
> + };
> +
> + seville_port4: port@4 {
> + reg = <4>;
> + status = "disabled";
> + };
> +
> + seville_port5: port@5 {
> + reg = <5>;
> + status = "disabled";
> + };
> +
> + seville_port6: port@6 {
> + reg = <6>;
> + status = "disabled";
> + };
> +
> + seville_port7: port@7 {
> + reg = <7>;
> + status = "disabled";
> + };
> +
> + seville_port8: port@8 {
> + reg = <8>;
> + phy-mode = "internal";
> + status = "disabled";
> +
> + fixed-link {
> + speed = <2500>;
> + full-duplex;
> + };
> + };
> +
> + seville_port9: port@9 {
> + reg = <9>;
> + phy-mode = "internal";
> + status = "disabled";
> +
> + fixed-link {
> + speed = <2500>;
> + full-duplex;
> + };
> + };
> + };
> + };
> };
>
> &qe {
>
^ permalink raw reply
* Re: [PATCH v2 devicetree 2/2] powerpc: dts: t1040rdb: add ports for Seville Ethernet switch
From: Maxim Kochetkov @ 2020-09-29 13:12 UTC (permalink / raw)
To: Vladimir Oltean, robh+dt, shawnguo, mpe, devicetree
Cc: madalin.bucur, linux-kernel, radu-andrei.bulie, paulus, netdev,
Vladimir Oltean, linuxppc-dev
In-Reply-To: <20200929113209.3767787-3-vladimir.oltean@nxp.com>
Reviewed-by: Maxim Kochetkov <fido_max@inbox.ru>
29.09.2020 14:32, Vladimir Oltean пишет:
> From: Vladimir Oltean <olteanv@gmail.com>
>
> Define the network interface names for the switch ports and hook them up
> to the 2 QSGMII PHYs that are onboard.
>
> A conscious decision was taken to go along with the numbers that are
> written on the front panel of the board and not with the hardware
> numbers of the switch chip ports. The 2 numbering schemes are
> shifted by 8.
>
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> ---
> Changes in v2:
> Use the existing way of accessing the mdio bus and not labels.
>
> arch/powerpc/boot/dts/fsl/t1040rdb.dts | 115 +++++++++++++++++++++++++
> 1 file changed, 115 insertions(+)
>
> diff --git a/arch/powerpc/boot/dts/fsl/t1040rdb.dts b/arch/powerpc/boot/dts/fsl/t1040rdb.dts
> index 65ff34c49025..3fd08a2b6dcb 100644
> --- a/arch/powerpc/boot/dts/fsl/t1040rdb.dts
> +++ b/arch/powerpc/boot/dts/fsl/t1040rdb.dts
> @@ -64,6 +64,40 @@ mdio@fc000 {
> phy_sgmii_2: ethernet-phy@3 {
> reg = <0x03>;
> };
> +
> + /* VSC8514 QSGMII PHY */
> + phy_qsgmii_0: ethernet-phy@4 {
> + reg = <0x4>;
> + };
> +
> + phy_qsgmii_1: ethernet-phy@5 {
> + reg = <0x5>;
> + };
> +
> + phy_qsgmii_2: ethernet-phy@6 {
> + reg = <0x6>;
> + };
> +
> + phy_qsgmii_3: ethernet-phy@7 {
> + reg = <0x7>;
> + };
> +
> + /* VSC8514 QSGMII PHY */
> + phy_qsgmii_4: ethernet-phy@8 {
> + reg = <0x8>;
> + };
> +
> + phy_qsgmii_5: ethernet-phy@9 {
> + reg = <0x9>;
> + };
> +
> + phy_qsgmii_6: ethernet-phy@a {
> + reg = <0xa>;
> + };
> +
> + phy_qsgmii_7: ethernet-phy@b {
> + reg = <0xb>;
> + };
> };
> };
> };
> @@ -76,3 +110,84 @@ cpld@3,0 {
> };
>
> #include "t1040si-post.dtsi"
> +
> +&seville_switch {
> + status = "okay";
> +};
> +
> +&seville_port0 {
> + managed = "in-band-status";
> + phy-handle = <&phy_qsgmii_0>;
> + phy-mode = "qsgmii";
> + /* ETH4 written on chassis */
> + label = "swp4";
> + status = "okay";
> +};
> +
> +&seville_port1 {
> + managed = "in-band-status";
> + phy-handle = <&phy_qsgmii_1>;
> + phy-mode = "qsgmii";
> + /* ETH5 written on chassis */
> + label = "swp5";
> + status = "okay";
> +};
> +
> +&seville_port2 {
> + managed = "in-band-status";
> + phy-handle = <&phy_qsgmii_2>;
> + phy-mode = "qsgmii";
> + /* ETH6 written on chassis */
> + label = "swp6";
> + status = "okay";
> +};
> +
> +&seville_port3 {
> + managed = "in-band-status";
> + phy-handle = <&phy_qsgmii_3>;
> + phy-mode = "qsgmii";
> + /* ETH7 written on chassis */
> + label = "swp7";
> + status = "okay";
> +};
> +
> +&seville_port4 {
> + managed = "in-band-status";
> + phy-handle = <&phy_qsgmii_4>;
> + phy-mode = "qsgmii";
> + /* ETH8 written on chassis */
> + label = "swp8";
> + status = "okay";
> +};
> +
> +&seville_port5 {
> + managed = "in-band-status";
> + phy-handle = <&phy_qsgmii_5>;
> + phy-mode = "qsgmii";
> + /* ETH9 written on chassis */
> + label = "swp9";
> + status = "okay";
> +};
> +
> +&seville_port6 {
> + managed = "in-band-status";
> + phy-handle = <&phy_qsgmii_6>;
> + phy-mode = "qsgmii";
> + /* ETH10 written on chassis */
> + label = "swp10";
> + status = "okay";
> +};
> +
> +&seville_port7 {
> + managed = "in-band-status";
> + phy-handle = <&phy_qsgmii_7>;
> + phy-mode = "qsgmii";
> + /* ETH11 written on chassis */
> + label = "swp11";
> + status = "okay";
> +};
> +
> +&seville_port8 {
> + ethernet = <&enet0>;
> + status = "okay";
> +};
>
^ permalink raw reply
* Re: [PATCH v2 devicetree 0/2] Add Seville Ethernet switch to T1040RDB
From: Maxim Kochetkov @ 2020-09-29 13:11 UTC (permalink / raw)
To: Vladimir Oltean, robh+dt, shawnguo, mpe, devicetree
Cc: madalin.bucur, linux-kernel, radu-andrei.bulie, paulus, netdev,
linuxppc-dev
In-Reply-To: <20200929113209.3767787-1-vladimir.oltean@nxp.com>
Reviewed-by: Maxim Kochetkov <fido_max@inbox.ru>
29.09.2020 14:32, Vladimir Oltean пишет:
> Seville is a DSA switch that is embedded inside the T1040 SoC, and
> supported by the mscc_seville DSA driver inside drivers/net/dsa/ocelot.
>
> This series adds this switch to the SoC's dtsi files and to the T1040RDB
> board file.
>
> Vladimir Oltean (2):
> powerpc: dts: t1040: add bindings for Seville Ethernet switch
> powerpc: dts: t1040rdb: add ports for Seville Ethernet switch
>
> arch/powerpc/boot/dts/fsl/t1040rdb.dts | 115 ++++++++++++++++++++
> arch/powerpc/boot/dts/fsl/t1040si-post.dtsi | 76 +++++++++++++
> 2 files changed, 191 insertions(+)
>
^ permalink raw reply
* Re: [PATCH v2 devicetree 2/2] powerpc: dts: t1040rdb: add ports for Seville Ethernet switch
From: Vladimir Oltean @ 2020-09-29 19:39 UTC (permalink / raw)
To: Andrew Lunn
Cc: devicetree@vger.kernel.org, Madalin Bucur (OSS),
Radu-andrei Bulie, linuxppc-dev@lists.ozlabs.org,
linux-kernel@vger.kernel.org, fido_max@inbox.ru,
robh+dt@kernel.org, paulus@samba.org, Vladimir Oltean,
shawnguo@kernel.org, netdev@vger.kernel.org
In-Reply-To: <20200929191153.GF3996795@lunn.ch>
On Tue, Sep 29, 2020 at 09:11:53PM +0200, Andrew Lunn wrote:
> > +&seville_port0 {
> > + managed = "in-band-status";
> > + phy-handle = <&phy_qsgmii_0>;
> > + phy-mode = "qsgmii";
> > + /* ETH4 written on chassis */
> > + label = "swp4";
>
> If ETH4 is on the chassis why not use ETH4?
You mean all-caps, just like that?
I don't know, I never saw an interface named in all-caps, it looks
strange to me. I understand that board designers are typically
case-insensitive, and that's kind of what my problem is, "eth4" is
clashing with the default naming scheme of the kernel and I also want to
avoid that. All in all, this is a reference design board, I don't care
too much. I've seen the "swp" convention being quite frequent, and I
thought that would be more intuitive. I've been using the same scheme
(the switch ports starting from swp2, corresponding to ETH2 on the
chassis) for the LS1021A-TSN board (arch/arm/boot/dts/ls1021a-tsn.dts)
and my users haven't complained about it.
Plus, it's not like the dpaa-eth (standalone) ports are named after the
chassis labels. Freescale/NXP typically ships an udev rule file that
names the interface after the associated FMan hardware port (for
example, the DSA master for the switch on this SoC is called "fm1-gb0",
and it's an internal port having nothing to do with ETH0, which is
"fm1-gb3").
I think it's a bit strange that the Rest Of World doesn't allow
interface naming via device tree, on this board the switch ports are not
where the big interface naming problem is. Although I'm not even sure
what to do to not increase it even more. With users being used to have
ETH0 going to fm1-gb3, maybe naming ETH4 as swp4 isn't the brightest
idea, true...
^ permalink raw reply
* Re: [PATCH v2 devicetree 2/2] powerpc: dts: t1040rdb: add ports for Seville Ethernet switch
From: Vladimir Oltean @ 2020-09-29 20:33 UTC (permalink / raw)
To: Andrew Lunn
Cc: devicetree@vger.kernel.org, Madalin Bucur (OSS),
Radu-andrei Bulie, linuxppc-dev@lists.ozlabs.org,
linux-kernel@vger.kernel.org, fido_max@inbox.ru,
robh+dt@kernel.org, paulus@samba.org, Vladimir Oltean,
shawnguo@kernel.org, netdev@vger.kernel.org
In-Reply-To: <20200929201048.GG3996795@lunn.ch>
On Tue, Sep 29, 2020 at 10:10:48PM +0200, Andrew Lunn wrote:
> On Tue, Sep 29, 2020 at 07:39:54PM +0000, Vladimir Oltean wrote:
> > On Tue, Sep 29, 2020 at 09:11:53PM +0200, Andrew Lunn wrote:
> > > > +&seville_port0 {
> > > > + managed = "in-band-status";
> > > > + phy-handle = <&phy_qsgmii_0>;
> > > > + phy-mode = "qsgmii";
> > > > + /* ETH4 written on chassis */
> > > > + label = "swp4";
> > >
> > > If ETH4 is on the chassis why not use ETH4?
> >
> > You mean all-caps, just like that?
>
> Yes.
>
> DSA is often used in WiFI access point, etc. The user is not a
> computer professional. If the WebGUI says ETH4, and the label on the
> front says ETH4, they probably think the two are the same, and are
> happy.
>
> I have one box which does not have an labels on the front panels, but
> the industrial sockets for Ethernet are colour coded. So the interface
> names are red, blue, green, to match the socket colour, and the cable
> set is also colour coded the same.
>
> So long as it is unique, the kernel does not care. So make it easy for
> the user.
It would look like this:
[root@T1040 ~] # ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: dummy0: <BROADCAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/ether de:91:41:1a:92:b8 brd ff:ff:ff:ff:ff:ff
3: fm1-gb3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
link/ether 00:1f:7b:6a:02:68 brd ff:ff:ff:ff:ff:ff
4: fm1-gb4: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc mq state DOWN mode DEFAULT group default qlen 1000
link/ether 00:1f:7b:6a:02:88 brd ff:ff:ff:ff:ff:ff
5: fm1-gb0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1504 qdisc mq state UP mode DEFAULT group default qlen 1000
link/ether 00:1f:7b:6a:02:08 brd ff:ff:ff:ff:ff:ff
6: fm1-gb1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
link/ether 00:1f:7b:6a:02:28 brd ff:ff:ff:ff:ff:ff
7: fm1-gb2: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc mq state DOWN mode DEFAULT group default qlen 1000
link/ether 00:1f:7b:6a:02:48 brd ff:ff:ff:ff:ff:ff
8: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
9: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/sit 0.0.0.0 brd 0.0.0.0
10: ETH4@fm1-gb0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether 00:1f:7b:6a:02:08 brd ff:ff:ff:ff:ff:ff
11: ETH5@fm1-gb0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
link/ether 00:1f:7b:6a:02:08 brd ff:ff:ff:ff:ff:ff
12: ETH6@fm1-gb0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
link/ether 00:1f:7b:6a:02:08 brd ff:ff:ff:ff:ff:ff
13: ETH7@fm1-gb0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
link/ether 00:1f:7b:6a:02:08 brd ff:ff:ff:ff:ff:ff
14: ETH8@fm1-gb0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
link/ether 00:1f:7b:6a:02:08 brd ff:ff:ff:ff:ff:ff
15: ETH9@fm1-gb0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
link/ether 00:1f:7b:6a:02:08 brd ff:ff:ff:ff:ff:ff
16: ETH10@fm1-gb0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
link/ether 00:1f:7b:6a:02:08 brd ff:ff:ff:ff:ff:ff
17: ETH11@fm1-gb0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
link/ether 00:1f:7b:6a:02:08 brd ff:ff:ff:ff:ff:ff
[root@T1040 ~] # ip link set ETH4 down
[ 94.942190] mscc_seville ffe800000.ethernet-switch ETH4: Link is Down
[root@T1040 ~] # ip link set ETH4 up
[ 100.262533] mscc_seville ffe800000.ethernet-switch ETH4: configuring for inband/qsgmii link mode
[ 100.272122] 8021q: adding VLAN 0 to HW filter on device ETH4
[ 103.333369] mscc_seville ffe800000.ethernet-switch ETH4: Link is Up - 1Gbps/Full - flow control rx/tx
[ 103.342697] IPv6: ADDRCONF(NETDEV_CHANGE): ETH4: link becomes ready
I'm not in love, but I guess at least there won't be any doubt if they
are named like this. I'm sending another revision with these names soon.
Thanks,
-Vladimir
^ permalink raw reply
* Re: [PATCH v2 4/7] powerpc: Remove PowerPC 601
From: Segher Boessenkool @ 2020-09-29 22:01 UTC (permalink / raw)
To: Christophe Leroy; +Cc: Paul Mackerras, linuxppc-dev, linux-kernel
In-Reply-To: <00a6948d659e017f8ca63437d1384222c3aede57.1601359702.git.christophe.leroy@csgroup.eu>
On Tue, Sep 29, 2020 at 06:09:21AM +0000, Christophe Leroy wrote:
> Powerpc 601 is 25 years old.
So is 603, but that one is still used! :-)
> It is not selected by any defconfig.
>
> It requires a lot of special handling as it deviates from the
> standard 6xx.
>
> Retire it.
That is fine with me of course. If I get a vote at all for this!
Thanks,
Segher
^ permalink raw reply
* Re: [PATCH] ibmvfc: Protect vhost->task_set increment by the host lock
From: Martin K. Petersen @ 2020-09-30 3:34 UTC (permalink / raw)
To: linux-scsi, Brian King; +Cc: tyreld, linuxppc-dev, Martin K . Petersen
In-Reply-To: <1600286999-22059-1-git-send-email-brking@linux.vnet.ibm.com>
On Wed, 16 Sep 2020 15:09:59 -0500, Brian King wrote:
> In the discovery thread, ibmvfc does a vhost->task_set++ without
> any lock held. This could result in two targets getting the same
> cancel key, which could have strange effects in error recovery.
> The actual probability of this occurring should be extremely
> small, since this should all be done in a single threaded loop
> from the discovery thread, but let's fix it up anyway to be safe.
Applied to 5.10/scsi-queue, thanks!
[1/1] scsi: ibmvfc: Protect vhost->task_set increment by the host lock
https://git.kernel.org/mkp/scsi/c/2584e5aef87a
--
Martin K. Petersen Oracle Linux Engineering
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox