* [PATCH v4 phy-next 15/16] phy: lynx-10g: new driver
From: Vladimir Oltean @ 2026-06-08 22:17 UTC (permalink / raw)
To: linux-phy
Cc: Ioana Ciornei, Vinod Koul, Neil Armstrong, Tanjeff Moos,
linux-kernel, devicetree, Conor Dooley, Krzysztof Kozlowski,
Rob Herring, linux-arm-kernel, chleroy, linuxppc-dev
In-Reply-To: <20260608221710.1572971-1-vladimir.oltean@nxp.com>
Introduce a driver for the networking lanes of the 10G Lynx SerDes
block, present on the majority of Layerscape and QorIQ (Freescale/NXP)
SoCs.
As with the 28G Lynx, the SerDes lanes come pre-initialized out of
reset and the consumers use them that way outside the Generic PHY
framework (for networking, the static configuration remains for the
entire SoC lifetime, whereas for SATA and PCIe, the hardware
reconfigures itself automatically for other link speeds).
The need for the Generic PHY framework comes specifically for networking
use cases where a static lane configuration is not sufficient. For
example a network MAC is connected to an SFP cage, where various SFP or
SFP+ modules can be connected. Each of them may require a different
SerDes protocol (SGMII, 1000Base-X, 10GBase-R), which phylink + sfp-bus
are responsible of figuring out. The phylink drivers are:
- enetc
- felix
- dpaa_eth (fman_memac)
- dpaa2-eth
- dpaa2-switch
and they all need to reconfigure the SerDes for the requested link mode,
using phy_set_mode_ext() (and phy_validate() to see if it is supported
in the first place).
Note that SerDes 2 on LS1088A is exclusively non-networking, so there is
currently no need for this driver. Therefore we skip matching on its
compatible string and do not probe on that device.
Co-developed-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
Cc: devicetree@vger.kernel.org
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Rob Herring <robh@kernel.org>
Cc: linux-arm-kernel@lists.infradead.org
Cc: chleroy@kernel.org
Cc: linuxppc-dev@lists.ozlabs.org
v3->v4: none
v2->v3:
- fix lynx_10g_power_on() procedure
- include <linux/of.h> instead of <linux/of_device.h>
- fix build warning introduced in v2 in lynx_10g_lane_set_nrate()
v1->v2:
- move lynx_lane_restrict_fixed_mode_change() to lynx-core, even though
the 28G Lynx as instantiated in LX2 does not have QSGMII.
- lynx_10g_validate() now calls the new lynx_phy_mode_to_lane_mode()
which does verify that the current lane mode is supported
- avoid line size checkpatch warnings in lynx_10g_lane_set_nrate() by
saving the nrate to a variable and calling lynx_lane_rmw() only once
- remove redundant "if (!lane->powered_up)" checks from
lynx_10g_lane_halt() and lynx_10g_lane_reset() - also checked at
the only call site, lynx_10g_set_mode(), as in lynx-28g
- expand CC list (flagged by Patchwork)
---
drivers/phy/freescale/Kconfig | 10 +
drivers/phy/freescale/Makefile | 1 +
drivers/phy/freescale/phy-fsl-lynx-10g.c | 1278 +++++++++++++++++++++
drivers/phy/freescale/phy-fsl-lynx-core.c | 38 +
drivers/phy/freescale/phy-fsl-lynx-core.h | 4 +
include/soc/fsl/phy-fsl-lynx.h | 27 +
6 files changed, 1358 insertions(+)
create mode 100644 drivers/phy/freescale/phy-fsl-lynx-10g.c
diff --git a/drivers/phy/freescale/Kconfig b/drivers/phy/freescale/Kconfig
index ac575d531db7..5bf3864fbe64 100644
--- a/drivers/phy/freescale/Kconfig
+++ b/drivers/phy/freescale/Kconfig
@@ -54,6 +54,16 @@ endif
config PHY_FSL_LYNX_CORE
tristate
+config PHY_FSL_LYNX_10G
+ tristate "Freescale Layerscape Lynx 10G SerDes PHY support"
+ depends on OF
+ depends on ARCH_LAYERSCAPE || COMPILE_TEST
+ select GENERIC_PHY
+ select PHY_FSL_LYNX_CORE
+ help
+ Enable this to add support for the Lynx 10G SerDes PHY as found on
+ NXP's Layerscape platform such as LS1088A or LS1028A.
+
config PHY_FSL_LYNX_28G
tristate "Freescale Layerscape Lynx 28G SerDes PHY support"
depends on OF
diff --git a/drivers/phy/freescale/Makefile b/drivers/phy/freescale/Makefile
index d7aa62cdeb39..5b0e180d6972 100644
--- a/drivers/phy/freescale/Makefile
+++ b/drivers/phy/freescale/Makefile
@@ -5,5 +5,6 @@ obj-$(CONFIG_PHY_MIXEL_MIPI_DPHY) += phy-fsl-imx8-mipi-dphy.o
obj-$(CONFIG_PHY_FSL_IMX8M_PCIE) += phy-fsl-imx8m-pcie.o
obj-$(CONFIG_PHY_FSL_IMX8QM_HSIO) += phy-fsl-imx8qm-hsio.o
obj-$(CONFIG_PHY_FSL_LYNX_CORE) += phy-fsl-lynx-core.o
+obj-$(CONFIG_PHY_FSL_LYNX_10G) += phy-fsl-lynx-10g.o
obj-$(CONFIG_PHY_FSL_LYNX_28G) += phy-fsl-lynx-28g.o
obj-$(CONFIG_PHY_FSL_SAMSUNG_HDMI_PHY) += phy-fsl-samsung-hdmi.o
diff --git a/drivers/phy/freescale/phy-fsl-lynx-10g.c b/drivers/phy/freescale/phy-fsl-lynx-10g.c
new file mode 100644
index 000000000000..7dd5d94b51cf
--- /dev/null
+++ b/drivers/phy/freescale/phy-fsl-lynx-10g.c
@@ -0,0 +1,1278 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright 2021-2026 NXP */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/phy.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+
+#include "phy-fsl-lynx-core.h"
+
+/* SoC IP wrapper for protocol converters */
+#define PCCR8 0x220
+#define PCCR8_SGMIIa_KX BIT(3)
+#define PCCR8_SGMIIa_CFG BIT(0)
+
+#define PCCR9 0x224
+#define PCCR9_QSGMIIa_CFG BIT(0)
+#define PCCR9_QXGMIIa_CFG BIT(0)
+
+#define PCCRB 0x22c
+#define PCCRB_XFIa_CFG BIT(0)
+#define PCCRB_SXGMIIa_CFG BIT(0)
+
+#define SGMII_CFG(id) (28 - (id) * 4)
+#define QSGMII_CFG(id) (28 - (id) * 4)
+#define SXGMII_CFG(id) (28 - (id) * 4)
+#define QXGMII_CFG(id) (12 - (id) * 4)
+#define XFI_CFG(id) (28 - (id) * 4)
+
+#define CR(x) ((x) * 4)
+
+#define A 0
+#define B 1
+#define C 2
+#define D 3
+#define E 4
+#define F 5
+#define G 6
+#define H 7
+
+#define SGMIIaCR0(id) (0x1800 + (id) * 0x10)
+#define QSGMIIaCR0(id) (0x1880 + (id) * 0x10)
+#define XAUIaCR0(id) (0x1900 + (id) * 0x10)
+#define XFIaCR0(id) (0x1980 + (id) * 0x10)
+#define SXGMIIaCR0(id) (0x1a80 + (id) * 0x10)
+#define QXGMIIaCR0(id) (0x1b00 + (id) * 0x20)
+
+#define SGMIIaCR0_RST_SGM BIT(31)
+#define SGMIIaCR0_RST_SGM_OFF SGMIIaCR0_RST_SGM
+#define SGMIIaCR0_RST_SGM_ON 0
+#define SGMIIaCR0_PD_SGM BIT(30)
+#define SGMIIaCR1_SGPCS_EN BIT(11)
+#define SGMIIaCR1_SGPCS_DIS 0x0
+
+#define QSGMIIaCR0_RST_QSGM BIT(31)
+#define QSGMIIaCR0_RST_QSGM_OFF QSGMIIaCR0_RST_QSGM
+#define QSGMIIaCR0_RST_QSGM_ON 0
+#define QSGMIIaCR0_PD_QSGM BIT(30)
+
+/* Per PLL registers */
+#define PLLnCR0(pll) ((pll) * 0x20 + 0x4)
+
+#define PLLnCR0_POFF BIT(31)
+
+#define PLLnCR0_REFCLK_SEL GENMASK(30, 28)
+#define PLLnCR0_REFCLK_SEL_100MHZ 0x0
+#define PLLnCR0_REFCLK_SEL_125MHZ 0x1
+#define PLLnCR0_REFCLK_SEL_156MHZ 0x2
+#define PLLnCR0_REFCLK_SEL_150MHZ 0x3
+#define PLLnCR0_REFCLK_SEL_161MHZ 0x4
+#define PLLnCR0_PLL_LCK BIT(23)
+#define PLLnCR0_FRATE_SEL GENMASK(19, 16)
+#define PLLnCR0_FRATE_5G 0x0
+#define PLLnCR0_FRATE_5_15625G 0x6
+#define PLLnCR0_FRATE_4G 0x7
+#define PLLnCR0_FRATE_3_125G 0x9
+#define PLLnCR0_FRATE_3G 0xa
+
+/* Per SerDes lane registers */
+
+/* Lane a Protocol Select status register */
+#define LNaPSSR0(lane) (0x100 + (lane) * 0x20)
+#define LNaPSSR0_TYPE GENMASK(30, 26)
+#define LNaPSSR0_IS_QUAD GENMASK(25, 24)
+#define LNaPSSR0_MAC GENMASK(19, 16)
+#define LNaPSSR0_PCS GENMASK(10, 8)
+#define LNaPSSR0_LANE GENMASK(2, 0)
+
+/* Lane a General Control Register */
+#define LNaGCR0(lane) (0x800 + (lane) * 0x40 + 0x0)
+#define LNaGCR0_RPLL_PLLF BIT(31)
+#define LNaGCR0_RPLL_PLLS 0x0
+#define LNaGCR0_RPLL_MSK BIT(31)
+#define LNaGCR0_RRAT_SEL GENMASK(29, 28)
+#define LNaGCR0_TRAT_SEL GENMASK(25, 24)
+#define LNaGCR0_TPLL_PLLF BIT(27)
+#define LNaGCR0_TPLL_PLLS 0x0
+#define LNaGCR0_TPLL_MSK BIT(27)
+#define LNaGCR0_RRST_OFF LNaGCR0_RRST
+#define LNaGCR0_TRST_OFF LNaGCR0_TRST
+#define LNaGCR0_RRST_ON 0x0
+#define LNaGCR0_TRST_ON 0x0
+#define LNaGCR0_RRST BIT(22)
+#define LNaGCR0_TRST BIT(21)
+#define LNaGCR0_RX_PD BIT(20)
+#define LNaGCR0_TX_PD BIT(19)
+#define LNaGCR0_IF20BIT_EN BIT(18)
+#define LNaGCR0_PROTS GENMASK(11, 7)
+
+#define LNaGCR1(lane) (0x800 + (lane) * 0x40 + 0x4)
+#define LNaGCR1_RDAT_INV BIT(31)
+#define LNaGCR1_TDAT_INV BIT(30)
+#define LNaGCR1_OPAD_CTL BIT(26)
+#define LNaGCR1_REIDL_TH GENMASK(22, 20)
+#define LNaGCR1_REIDL_EX_SEL GENMASK(19, 18)
+#define LNaGCR1_REIDL_ET_SEL GENMASK(17, 16)
+#define LNaGCR1_REIDL_EX_MSB BIT(15)
+#define LNaGCR1_REIDL_ET_MSB BIT(14)
+#define LNaGCR1_REQ_CTL_SNP BIT(13)
+#define LNaGCR1_REQ_CDR_SNP BIT(12)
+#define LNaGCR1_TRSTDIR BIT(7)
+#define LNaGCR1_REQ_BIN_SNP BIT(6)
+#define LNaGCR1_ISLEW_RCTL GENMASK(5, 4)
+#define LNaGCR1_OSLEW_RCTL GENMASK(1, 0)
+
+#define LNaRECR0(lane) (0x800 + (lane) * 0x40 + 0x10)
+#define LNaRECR0_RXEQ_BST BIT(28)
+#define LNaRECR0_GK2OVD GENMASK(27, 24)
+#define LNaRECR0_GK3OVD GENMASK(19, 16)
+#define LNaRECR0_GK2OVD_EN BIT(15)
+#define LNaRECR0_GK3OVD_EN BIT(14)
+#define LNaRECR0_OSETOVD_EN BIT(13)
+#define LNaRECR0_BASE_WAND GENMASK(11, 10)
+#define LNaRECR0_OSETOVD GENMASK(6, 0)
+
+#define LNaTECR0(lane) (0x800 + (lane) * 0x40 + 0x18)
+#define LNaTECR0_TEQ_TYPE GENMASK(29, 28)
+#define LNaTECR0_SGN_PREQ BIT(26)
+#define LNaTECR0_RATIO_PREQ GENMASK(25, 22)
+#define LNaTECR0_SGN_POST1Q BIT(21)
+#define LNaTECR0_RATIO_PST1Q GENMASK(20, 16)
+#define LNaTECR0_ADPT_EQ GENMASK(13, 8)
+#define LNaTECR0_AMP_RED GENMASK(5, 0)
+
+#define LNaTTLCR0(lane) (0x800 + (lane) * 0x40 + 0x20)
+#define LNaTTLCR1(lane) (0x800 + (lane) * 0x40 + 0x24)
+#define LNaTTLCR2(lane) (0x800 + (lane) * 0x40 + 0x28)
+
+#define LNaTCSR3(lane) (0x800 + (lane) * 0x40 + 0x3C)
+#define LNaTCSR3_CDR_LCK BIT(27)
+
+enum lynx_10g_rat_sel {
+ RAT_SEL_FULL = 0x0,
+ RAT_SEL_HALF = 0x1,
+ RAT_SEL_QUARTER = 0x2,
+ RAT_SEL_DOUBLE = 0x3,
+};
+
+enum lynx_10g_eq_type {
+ EQ_TYPE_NO_EQ = 0,
+ EQ_TYPE_2TAP = 1,
+ EQ_TYPE_3TAP = 2,
+};
+
+enum lynx_10g_proto_sel {
+ PROTO_SEL_PCIE = 0,
+ PROTO_SEL_SGMII_BASEX_KX_QSGMII = 1,
+ PROTO_SEL_SATA = 2,
+ PROTO_SEL_XAUI = 4,
+ PROTO_SEL_XFI_10GBASER_KR_SXGMII = 0xa,
+};
+
+struct lynx_10g_proto_conf {
+ int proto_sel;
+ int if20bit_en;
+ int reidl_th;
+ int reidl_et_msb;
+ int reidl_et_sel;
+ int reidl_ex_msb;
+ int reidl_ex_sel;
+ int islew_rctl;
+ int oslew_rctl;
+ int rxeq_bst;
+ int gk2ovd;
+ int gk3ovd;
+ int gk2ovd_en;
+ int gk3ovd_en;
+ int base_wand;
+ int teq_type;
+ int sgn_preq;
+ int ratio_preq;
+ int sgn_post1q;
+ int ratio_post1q;
+ int adpt_eq;
+ int amp_red;
+ int ttlcr0;
+};
+
+static const struct lynx_10g_proto_conf lynx_10g_proto_conf[LANE_MODE_MAX] = {
+ [LANE_MODE_1000BASEX_SGMII] = {
+ .proto_sel = PROTO_SEL_SGMII_BASEX_KX_QSGMII,
+ .reidl_th = 1,
+ .reidl_ex_sel = 3,
+ .reidl_et_msb = 1,
+ .islew_rctl = 1,
+ .oslew_rctl = 1,
+ .gk2ovd = 15,
+ .gk3ovd = 15,
+ .gk2ovd_en = 1,
+ .gk3ovd_en = 1,
+ .teq_type = EQ_TYPE_NO_EQ,
+ .adpt_eq = 48,
+ .amp_red = 6,
+ .ttlcr0 = 0x39000400,
+ },
+ [LANE_MODE_2500BASEX] = {
+ .proto_sel = PROTO_SEL_SGMII_BASEX_KX_QSGMII,
+ .islew_rctl = 2,
+ .oslew_rctl = 2,
+ .teq_type = EQ_TYPE_2TAP,
+ .sgn_post1q = 1,
+ .ratio_post1q = 6,
+ .adpt_eq = 48,
+ .ttlcr0 = 0x00000400,
+ },
+ [LANE_MODE_QSGMII] = {
+ .proto_sel = PROTO_SEL_SGMII_BASEX_KX_QSGMII,
+ .islew_rctl = 1,
+ .oslew_rctl = 1,
+ .teq_type = EQ_TYPE_2TAP,
+ .sgn_post1q = 1,
+ .ratio_post1q = 6,
+ .adpt_eq = 48,
+ .amp_red = 2,
+ .ttlcr0 = 0x00000400,
+ },
+ [LANE_MODE_10G_QXGMII] = {
+ .proto_sel = PROTO_SEL_XFI_10GBASER_KR_SXGMII,
+ .if20bit_en = 1,
+ .islew_rctl = 1,
+ .oslew_rctl = 1,
+ .base_wand = 1,
+ .teq_type = EQ_TYPE_NO_EQ,
+ .adpt_eq = 48,
+ .ttlcr0 = 0x00000400,
+ },
+ [LANE_MODE_USXGMII] = {
+ .proto_sel = PROTO_SEL_XFI_10GBASER_KR_SXGMII,
+ .if20bit_en = 1,
+ .islew_rctl = 1,
+ .oslew_rctl = 1,
+ .base_wand = 1,
+ .teq_type = EQ_TYPE_NO_EQ,
+ .sgn_post1q = 1,
+ .adpt_eq = 48,
+ .ttlcr0 = 0x00000400,
+ },
+ [LANE_MODE_10GBASER] = {
+ .proto_sel = PROTO_SEL_XFI_10GBASER_KR_SXGMII,
+ .if20bit_en = 1,
+ .islew_rctl = 2,
+ .oslew_rctl = 2,
+ .rxeq_bst = 1,
+ .base_wand = 1,
+ .teq_type = EQ_TYPE_2TAP,
+ .sgn_post1q = 1,
+ .ratio_post1q = 3,
+ .adpt_eq = 48,
+ .amp_red = 7,
+ .ttlcr0 = 0x00000400,
+ },
+};
+
+static void lynx_10g_cdr_lock_check(struct lynx_lane *lane)
+{
+ u32 tcsr3 = lynx_lane_read(lane, LNaTCSR3);
+
+ if (tcsr3 & LNaTCSR3_CDR_LCK)
+ return;
+
+ dev_dbg(&lane->phy->dev,
+ "Lane %c CDR unlocked, resetting receiver...\n",
+ 'A' + lane->id);
+
+ lynx_lane_rmw(lane, LNaGCR0, LNaGCR0_RRST_ON, LNaGCR0_RRST);
+ usleep_range(1, 2);
+ lynx_lane_rmw(lane, LNaGCR0, LNaGCR0_RRST_OFF, LNaGCR0_RRST);
+
+ usleep_range(1, 2);
+}
+
+static void lynx_10g_pll_read_configuration(struct lynx_pll *pll)
+{
+ u32 val;
+
+ val = lynx_pll_read(pll, PLLnCR0);
+ pll->frate_sel = FIELD_GET(PLLnCR0_FRATE_SEL, val);
+ pll->refclk_sel = FIELD_GET(PLLnCR0_REFCLK_SEL, val);
+ pll->enabled = !(val & PLLnCR0_POFF);
+ pll->locked = !!(val & PLLnCR0_PLL_LCK);
+
+ if (!pll->enabled)
+ return;
+
+ switch (pll->frate_sel) {
+ case PLLnCR0_FRATE_5G:
+ /* 5GHz clock net */
+ __set_bit(LANE_MODE_1000BASEX_SGMII, pll->supported);
+ __set_bit(LANE_MODE_QSGMII, pll->supported);
+ break;
+ case PLLnCR0_FRATE_3_125G:
+ __set_bit(LANE_MODE_2500BASEX, pll->supported);
+ break;
+ case PLLnCR0_FRATE_5_15625G:
+ /* 10.3125GHz clock net */
+ __set_bit(LANE_MODE_10GBASER, pll->supported);
+ __set_bit(LANE_MODE_USXGMII, pll->supported);
+ __set_bit(LANE_MODE_10G_QXGMII, pll->supported);
+ break;
+ default:
+ break;
+ }
+}
+
+/* On LS1028A, SGMIIA_CFG, SGMIIB_CFG, and SGMIIC_CFG from PCCR8 have the
+ * ability to map either an ENETC PCS or a Felix switch PCS to the same lane.
+ * The PHY API lacks the capability to distinguish between one consumer and
+ * another, so we don't support changing the initial muxing done by the RCW.
+ * However, when disabling a PCS through PCCR8, we need to properly restore
+ * the original value to keep the same muxing, and for that we need to back
+ * it up (here).
+ */
+static void lynx_10g_backup_pccr_val(struct lynx_lane *lane)
+{
+ u32 val;
+ int err;
+
+ if (lane->mode == LANE_MODE_UNKNOWN)
+ return;
+
+ err = lynx_pccr_read(lane, lane->mode, &val);
+ if (err) {
+ dev_warn(&lane->phy->dev,
+ "The driver doesn't know how to access the PCCR for lane mode %s\n",
+ lynx_lane_mode_str(lane->mode));
+ lane->mode = LANE_MODE_UNKNOWN;
+ return;
+ }
+
+ lane->default_pccr[lane->mode] = val;
+
+ switch (lane->mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ case LANE_MODE_2500BASEX:
+ lane->default_pccr[LANE_MODE_1000BASEX_SGMII] = val & ~PCCR8_SGMIIa_KX;
+ lane->default_pccr[LANE_MODE_2500BASEX] = val & ~PCCR8_SGMIIa_KX;
+ break;
+ default:
+ break;
+ }
+}
+
+static bool lynx_10g_lane_is_3_125g(struct lynx_lane *lane)
+{
+ struct lynx_priv *priv = lane->priv;
+ struct lynx_pll *pll;
+ u32 gcr0;
+
+ gcr0 = lynx_lane_read(lane, LNaGCR0);
+
+ if (gcr0 & LNaGCR0_TPLL_PLLF)
+ pll = &priv->pll[0];
+ else
+ pll = &priv->pll[1];
+
+ if (pll->frate_sel != PLLnCR0_FRATE_3_125G)
+ return false;
+
+ if (FIELD_GET(LNaGCR0_TRAT_SEL, gcr0) != RAT_SEL_FULL ||
+ FIELD_GET(LNaGCR0_RRAT_SEL, gcr0) != RAT_SEL_FULL)
+ return false;
+
+ return true;
+}
+
+static void lynx_10g_lane_read_configuration(struct lynx_lane *lane)
+{
+ u32 pssr0 = lynx_lane_read(lane, LNaPSSR0);
+ struct lynx_priv *priv = lane->priv;
+ int proto;
+
+ proto = FIELD_GET(LNaPSSR0_TYPE, pssr0);
+ switch (proto) {
+ case PROTO_SEL_SGMII_BASEX_KX_QSGMII:
+ if (lynx_10g_lane_is_3_125g(lane))
+ lane->mode = LANE_MODE_2500BASEX;
+ else if (FIELD_GET(LNaPSSR0_IS_QUAD, pssr0))
+ lane->mode = LANE_MODE_QSGMII;
+ else
+ lane->mode = LANE_MODE_1000BASEX_SGMII;
+ break;
+ case PROTO_SEL_XFI_10GBASER_KR_SXGMII:
+ if (FIELD_GET(LNaPSSR0_IS_QUAD, pssr0))
+ lane->mode = LANE_MODE_10G_QXGMII;
+ else if (priv->info->quirks & LYNX_QUIRK_HAS_HARDCODED_USXGMII)
+ lane->mode = LANE_MODE_USXGMII;
+ else
+ lane->mode = LANE_MODE_10GBASER;
+ break;
+ case PROTO_SEL_PCIE:
+ case PROTO_SEL_SATA:
+ case PROTO_SEL_XAUI:
+ break;
+ default:
+ dev_warn(&lane->phy->dev, "Unknown lane protocol 0x%x\n",
+ proto);
+ }
+
+ lynx_10g_backup_pccr_val(lane);
+}
+
+static int ls1028a_get_pccr(enum lynx_lane_mode lane_mode, int lane,
+ struct lynx_pccr *pccr)
+{
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ case LANE_MODE_2500BASEX:
+ pccr->offset = PCCR8;
+ pccr->width = 4;
+ pccr->shift = SGMII_CFG(lane);
+ break;
+ case LANE_MODE_QSGMII:
+ if (lane != 1)
+ return -EINVAL;
+
+ pccr->offset = PCCR9;
+ pccr->width = 3;
+ pccr->shift = QSGMII_CFG(A);
+ break;
+ case LANE_MODE_10G_QXGMII:
+ if (lane != 1)
+ return -EINVAL;
+
+ pccr->offset = PCCR9;
+ pccr->width = 3;
+ pccr->shift = QXGMII_CFG(A);
+ break;
+ case LANE_MODE_USXGMII:
+ if (lane != 0)
+ return -EINVAL;
+
+ pccr->offset = PCCRB;
+ pccr->width = 3;
+ pccr->shift = SXGMII_CFG(A);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ls1028a_get_pcvt_offset(int lane, enum lynx_lane_mode mode)
+{
+ switch (mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ case LANE_MODE_2500BASEX:
+ return SGMIIaCR0(lane);
+ case LANE_MODE_QSGMII:
+ return lane == 1 ? QSGMIIaCR0(A) : -EINVAL;
+ case LANE_MODE_USXGMII:
+ return lane == 0 ? SXGMIIaCR0(A) : -EINVAL;
+ case LANE_MODE_10G_QXGMII:
+ return lane == 1 ? QXGMIIaCR0(A) : -EINVAL;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct lynx_info lynx_info_ls1028a = {
+ .get_pccr = ls1028a_get_pccr,
+ .get_pcvt_offset = ls1028a_get_pcvt_offset,
+ .pll_read_configuration = lynx_10g_pll_read_configuration,
+ .lane_read_configuration = lynx_10g_lane_read_configuration,
+ .cdr_lock_check = lynx_10g_cdr_lock_check,
+ .num_lanes = 4,
+ .index = 1,
+ .quirks = LYNX_QUIRK_HAS_HARDCODED_USXGMII,
+};
+
+static int ls1046a_serdes1_get_pccr(enum lynx_lane_mode lane_mode, int lane,
+ struct lynx_pccr *pccr)
+{
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ case LANE_MODE_2500BASEX:
+ pccr->offset = PCCR8;
+ pccr->width = 4;
+ pccr->shift = SGMII_CFG(lane);
+ break;
+ case LANE_MODE_QSGMII:
+ if (lane != 1)
+ return -EINVAL;
+
+ pccr->offset = PCCR9;
+ pccr->width = 3;
+ pccr->shift = QSGMII_CFG(B);
+ break;
+ case LANE_MODE_10GBASER:
+ switch (lane) {
+ case 2:
+ pccr->shift = XFI_CFG(A);
+ break;
+ case 3:
+ pccr->shift = XFI_CFG(B);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ pccr->offset = PCCRB;
+ pccr->width = 3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ls1046a_serdes1_get_pcvt_offset(int lane, enum lynx_lane_mode mode)
+{
+ switch (mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ case LANE_MODE_2500BASEX:
+ return SGMIIaCR0(lane);
+ case LANE_MODE_QSGMII:
+ if (lane != 1)
+ return -EINVAL;
+
+ return QSGMIIaCR0(B);
+ case LANE_MODE_10GBASER:
+ switch (lane) {
+ case 2:
+ return XFIaCR0(A);
+ case 3:
+ return XFIaCR0(B);
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct lynx_info lynx_info_ls1046a_serdes1 = {
+ .get_pccr = ls1046a_serdes1_get_pccr,
+ .get_pcvt_offset = ls1046a_serdes1_get_pcvt_offset,
+ .pll_read_configuration = lynx_10g_pll_read_configuration,
+ .lane_read_configuration = lynx_10g_lane_read_configuration,
+ .cdr_lock_check = lynx_10g_cdr_lock_check,
+ .num_lanes = 4,
+ .index = 1,
+};
+
+static int ls1046a_serdes2_get_pccr(enum lynx_lane_mode lane_mode, int lane,
+ struct lynx_pccr *pccr)
+{
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ case LANE_MODE_2500BASEX:
+ if (lane != 1)
+ return -EINVAL;
+
+ pccr->offset = PCCR8;
+ pccr->width = 4;
+ pccr->shift = SGMII_CFG(B);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ls1046a_serdes2_get_pcvt_offset(int lane, enum lynx_lane_mode mode)
+{
+ switch (mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ case LANE_MODE_2500BASEX:
+ if (lane != 1)
+ return -EINVAL;
+
+ return SGMIIaCR0(B);
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct lynx_info lynx_info_ls1046a_serdes2 = {
+ .get_pccr = ls1046a_serdes2_get_pccr,
+ .get_pcvt_offset = ls1046a_serdes2_get_pcvt_offset,
+ .pll_read_configuration = lynx_10g_pll_read_configuration,
+ .lane_read_configuration = lynx_10g_lane_read_configuration,
+ .cdr_lock_check = lynx_10g_cdr_lock_check,
+ .num_lanes = 4,
+ .index = 2,
+};
+
+static int ls1088a_serdes1_get_pccr(enum lynx_lane_mode lane_mode, int lane,
+ struct lynx_pccr *pccr)
+{
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ pccr->offset = PCCR8;
+ pccr->width = 4;
+ pccr->shift = SGMII_CFG(lane);
+ break;
+ case LANE_MODE_QSGMII:
+ switch (lane) {
+ case 0:
+ pccr->shift = QSGMII_CFG(A);
+ break;
+ case 1:
+ case 3:
+ pccr->shift = QSGMII_CFG(B);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ pccr->offset = PCCR9;
+ pccr->width = 3;
+ break;
+ case LANE_MODE_10GBASER:
+ switch (lane) {
+ case 2:
+ pccr->shift = XFI_CFG(A);
+ break;
+ case 3:
+ pccr->shift = XFI_CFG(B);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ pccr->offset = PCCRB;
+ pccr->width = 3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ls1088a_serdes1_get_pcvt_offset(int lane, enum lynx_lane_mode mode)
+{
+ switch (mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ return SGMIIaCR0(lane);
+ case LANE_MODE_QSGMII:
+ switch (lane) {
+ case 0:
+ return QSGMIIaCR0(A);
+ case 1:
+ case 3:
+ return QSGMIIaCR0(B);
+ default:
+ return -EINVAL;
+ }
+ case LANE_MODE_10GBASER:
+ switch (lane) {
+ case 2:
+ return XFIaCR0(A);
+ case 3:
+ return XFIaCR0(B);
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct lynx_info lynx_info_ls1088a_serdes1 = {
+ .get_pccr = ls1088a_serdes1_get_pccr,
+ .get_pcvt_offset = ls1088a_serdes1_get_pcvt_offset,
+ .pll_read_configuration = lynx_10g_pll_read_configuration,
+ .lane_read_configuration = lynx_10g_lane_read_configuration,
+ .cdr_lock_check = lynx_10g_cdr_lock_check,
+ .num_lanes = 4,
+ .index = 1,
+};
+
+static int ls2088a_serdes1_get_pccr(enum lynx_lane_mode lane_mode, int lane,
+ struct lynx_pccr *pccr)
+{
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ case LANE_MODE_2500BASEX:
+ pccr->offset = PCCR8;
+ pccr->width = 4;
+ pccr->shift = SGMII_CFG(lane);
+ break;
+ case LANE_MODE_QSGMII:
+ switch (lane) {
+ case 2:
+ case 6:
+ pccr->shift = QSGMII_CFG(A);
+ break;
+ case 7:
+ pccr->shift = QSGMII_CFG(B);
+ break;
+ case 0:
+ case 4:
+ pccr->shift = QSGMII_CFG(C);
+ break;
+ case 1:
+ case 5:
+ pccr->shift = QSGMII_CFG(D);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ pccr->offset = PCCR9;
+ pccr->width = 3;
+ break;
+ case LANE_MODE_10GBASER:
+ pccr->offset = PCCRB;
+ pccr->width = 3;
+ pccr->shift = XFI_CFG(lane);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ls2088a_serdes1_get_pcvt_offset(int lane, enum lynx_lane_mode mode)
+{
+ switch (mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ case LANE_MODE_2500BASEX:
+ return SGMIIaCR0(lane);
+ case LANE_MODE_QSGMII:
+ switch (lane) {
+ case 2:
+ case 6:
+ return QSGMIIaCR0(A);
+ case 7:
+ return QSGMIIaCR0(B);
+ case 0:
+ case 4:
+ return QSGMIIaCR0(C);
+ case 1:
+ case 5:
+ return QSGMIIaCR0(D);
+ default:
+ return -EINVAL;
+ }
+ case LANE_MODE_10GBASER:
+ return XFIaCR0(lane);
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct lynx_info lynx_info_ls2088a_serdes1 = {
+ .get_pccr = ls2088a_serdes1_get_pccr,
+ .get_pcvt_offset = ls2088a_serdes1_get_pcvt_offset,
+ .pll_read_configuration = lynx_10g_pll_read_configuration,
+ .lane_read_configuration = lynx_10g_lane_read_configuration,
+ .cdr_lock_check = lynx_10g_cdr_lock_check,
+ .num_lanes = 8,
+ .index = 1,
+};
+
+static int ls2088a_serdes2_get_pccr(enum lynx_lane_mode lane_mode, int lane,
+ struct lynx_pccr *pccr)
+{
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ case LANE_MODE_2500BASEX:
+ pccr->offset = PCCR8;
+ pccr->width = 4;
+ pccr->shift = SGMII_CFG(lane);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ls2088a_serdes2_get_pcvt_offset(int lane, enum lynx_lane_mode mode)
+{
+ switch (mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ case LANE_MODE_2500BASEX:
+ return SGMIIaCR0(lane);
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct lynx_info lynx_info_ls2088a_serdes2 = {
+ .get_pccr = ls2088a_serdes2_get_pccr,
+ .get_pcvt_offset = ls2088a_serdes2_get_pcvt_offset,
+ .pll_read_configuration = lynx_10g_pll_read_configuration,
+ .lane_read_configuration = lynx_10g_lane_read_configuration,
+ .cdr_lock_check = lynx_10g_cdr_lock_check,
+ .num_lanes = 8,
+ .index = 2,
+};
+
+/* Halting puts the lane in a mode in which it can be reconfigured */
+static void lynx_10g_lane_halt(struct phy *phy)
+{
+ struct lynx_lane *lane = phy_get_drvdata(phy);
+
+ /* Issue a reset request */
+ lynx_lane_rmw(lane, LNaGCR0,
+ LNaGCR0_RRST_ON | LNaGCR0_TRST_ON,
+ LNaGCR0_RRST | LNaGCR0_TRST);
+
+ /* The RM says to wait for at least 50ns */
+ usleep_range(1, 2);
+}
+
+static void lynx_10g_lane_reset(struct phy *phy)
+{
+ struct lynx_lane *lane = phy_get_drvdata(phy);
+
+ /* Finalize the reset request */
+ lynx_lane_rmw(lane, LNaGCR0,
+ LNaGCR0_RRST_OFF | LNaGCR0_TRST_OFF,
+ LNaGCR0_RRST | LNaGCR0_TRST);
+}
+
+static int lynx_10g_power_off(struct phy *phy)
+{
+ struct lynx_lane *lane = phy_get_drvdata(phy);
+
+ if (!lane->powered_up)
+ return 0;
+
+ /* Issue a reset request with the power down bits set */
+ lynx_lane_rmw(lane, LNaGCR0,
+ LNaGCR0_RRST_ON | LNaGCR0_TRST_ON |
+ LNaGCR0_RX_PD | LNaGCR0_TX_PD,
+ LNaGCR0_RRST | LNaGCR0_TRST |
+ LNaGCR0_RX_PD | LNaGCR0_TX_PD);
+
+ /* The RM says to wait for at least 50ns */
+ usleep_range(1, 2);
+
+ lane->powered_up = false;
+
+ return 0;
+}
+
+static int lynx_10g_power_on(struct phy *phy)
+{
+ struct lynx_lane *lane = phy_get_drvdata(phy);
+
+ if (lane->powered_up)
+ return 0;
+
+ /* RM says that to enable a previously powered down lane, set
+ * LNmGCR0[{R,T}X_PD]=0, wait 15 us, then set LNmGCR0[{R,T}RST]=1.
+ */
+ lynx_lane_rmw(lane, LNaGCR0, 0, LNaGCR0_RX_PD | LNaGCR0_TX_PD);
+ usleep_range(150, 300);
+ lynx_10g_lane_reset(phy);
+
+ lane->powered_up = true;
+
+ return 0;
+}
+
+static void lynx_10g_lane_set_nrate(struct lynx_lane *lane,
+ struct lynx_pll *pll,
+ enum lynx_lane_mode mode)
+{
+ enum lynx_10g_rat_sel nrate;
+
+ switch (pll->frate_sel) {
+ case PLLnCR0_FRATE_5G:
+ switch (mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ nrate = RAT_SEL_QUARTER;
+ break;
+ case LANE_MODE_QSGMII:
+ nrate = RAT_SEL_FULL;
+ break;
+ default:
+ return;
+ }
+ break;
+ case PLLnCR0_FRATE_3_125G:
+ switch (mode) {
+ case LANE_MODE_2500BASEX:
+ nrate = RAT_SEL_FULL;
+ break;
+ default:
+ return;
+ }
+ break;
+ case PLLnCR0_FRATE_5_15625G:
+ switch (mode) {
+ case LANE_MODE_10GBASER:
+ case LANE_MODE_USXGMII:
+ case LANE_MODE_10G_QXGMII:
+ nrate = RAT_SEL_DOUBLE;
+ break;
+ default:
+ return;
+ }
+ break;
+ default:
+ return;
+ }
+
+ lynx_lane_rmw(lane, LNaGCR0,
+ FIELD_PREP(LNaGCR0_TRAT_SEL, nrate) |
+ FIELD_PREP(LNaGCR0_RRAT_SEL, nrate),
+ LNaGCR0_RRAT_SEL | LNaGCR0_TRAT_SEL);
+}
+
+static void lynx_10g_lane_set_pll(struct lynx_lane *lane,
+ struct lynx_pll *pll)
+{
+ if (pll->id == 0) {
+ lynx_lane_rmw(lane, LNaGCR0,
+ LNaGCR0_RPLL_PLLF | LNaGCR0_TPLL_PLLF,
+ LNaGCR0_RPLL_MSK | LNaGCR0_TPLL_MSK);
+ } else {
+ lynx_lane_rmw(lane, LNaGCR0,
+ LNaGCR0_RPLL_PLLS | LNaGCR0_TPLL_PLLS,
+ LNaGCR0_RPLL_MSK | LNaGCR0_TPLL_MSK);
+ }
+}
+
+static void lynx_10g_lane_remap_pll(struct lynx_lane *lane,
+ enum lynx_lane_mode lane_mode)
+{
+ struct lynx_priv *priv = lane->priv;
+ struct lynx_pll *pll;
+
+ /* Switch to the PLL that works with this interface type */
+ pll = lynx_pll_get(priv, lane_mode);
+ if (unlikely(!pll))
+ return;
+
+ lynx_10g_lane_set_pll(lane, pll);
+
+ /* Choose the portion of clock net to be used on this lane */
+ lynx_10g_lane_set_nrate(lane, pll, lane_mode);
+}
+
+static void lynx_10g_lane_change_proto_conf(struct lynx_lane *lane,
+ enum lynx_lane_mode mode)
+{
+ const struct lynx_10g_proto_conf *conf = &lynx_10g_proto_conf[mode];
+
+ lynx_lane_rmw(lane, LNaGCR0,
+ FIELD_PREP(LNaGCR0_PROTS, conf->proto_sel) |
+ FIELD_PREP(LNaGCR0_IF20BIT_EN, conf->if20bit_en),
+ LNaGCR0_PROTS | LNaGCR0_IF20BIT_EN);
+ lynx_lane_rmw(lane, LNaGCR1,
+ FIELD_PREP(LNaGCR1_REIDL_TH, conf->reidl_th) |
+ FIELD_PREP(LNaGCR1_REIDL_ET_MSB, conf->reidl_et_msb) |
+ FIELD_PREP(LNaGCR1_REIDL_ET_SEL, conf->reidl_et_sel) |
+ FIELD_PREP(LNaGCR1_REIDL_EX_MSB, conf->reidl_ex_msb) |
+ FIELD_PREP(LNaGCR1_REIDL_EX_SEL, conf->reidl_ex_sel) |
+ FIELD_PREP(LNaGCR1_ISLEW_RCTL, conf->islew_rctl) |
+ FIELD_PREP(LNaGCR1_OSLEW_RCTL, conf->oslew_rctl),
+ LNaGCR1_REIDL_TH |
+ LNaGCR1_REIDL_ET_MSB | LNaGCR1_REIDL_ET_SEL |
+ LNaGCR1_REIDL_EX_MSB | LNaGCR1_REIDL_EX_SEL |
+ LNaGCR1_ISLEW_RCTL | LNaGCR1_OSLEW_RCTL);
+ lynx_lane_rmw(lane, LNaRECR0,
+ FIELD_PREP(LNaRECR0_RXEQ_BST, conf->rxeq_bst) |
+ FIELD_PREP(LNaRECR0_GK2OVD, conf->gk2ovd) |
+ FIELD_PREP(LNaRECR0_GK3OVD, conf->gk3ovd) |
+ FIELD_PREP(LNaRECR0_GK2OVD_EN, conf->gk2ovd_en) |
+ FIELD_PREP(LNaRECR0_GK3OVD_EN, conf->gk3ovd_en) |
+ FIELD_PREP(LNaRECR0_BASE_WAND, conf->base_wand),
+ LNaRECR0_RXEQ_BST | LNaRECR0_GK2OVD | LNaRECR0_GK3OVD |
+ LNaRECR0_GK2OVD_EN | LNaRECR0_GK3OVD_EN |
+ LNaRECR0_BASE_WAND);
+ lynx_lane_rmw(lane, LNaTECR0,
+ FIELD_PREP(LNaTECR0_TEQ_TYPE, conf->teq_type) |
+ FIELD_PREP(LNaTECR0_SGN_PREQ, conf->sgn_preq) |
+ FIELD_PREP(LNaTECR0_RATIO_PREQ, conf->ratio_preq) |
+ FIELD_PREP(LNaTECR0_SGN_POST1Q, conf->sgn_post1q) |
+ FIELD_PREP(LNaTECR0_RATIO_PST1Q, conf->ratio_post1q) |
+ FIELD_PREP(LNaTECR0_ADPT_EQ, conf->adpt_eq) |
+ FIELD_PREP(LNaTECR0_AMP_RED, conf->amp_red),
+ LNaTECR0_TEQ_TYPE | LNaTECR0_SGN_PREQ |
+ LNaTECR0_RATIO_PREQ | LNaTECR0_SGN_POST1Q |
+ LNaTECR0_RATIO_PST1Q | LNaTECR0_ADPT_EQ |
+ LNaTECR0_AMP_RED);
+ lynx_lane_write(lane, LNaTTLCR0, conf->ttlcr0);
+}
+
+static int lynx_10g_lane_disable_pcvt(struct lynx_lane *lane,
+ enum lynx_lane_mode mode)
+{
+ struct lynx_priv *priv = lane->priv;
+ int err;
+
+ spin_lock(&priv->pcc_lock);
+
+ err = lynx_pccr_write(lane, mode, 0);
+ if (err)
+ goto out;
+
+ switch (mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ case LANE_MODE_2500BASEX:
+ err = lynx_pcvt_rmw(lane, mode, CR(1), SGMIIaCR1_SGPCS_DIS,
+ SGMIIaCR1_SGPCS_EN);
+ if (err)
+ goto out;
+
+ lynx_pcvt_rmw(lane, mode, CR(0),
+ SGMIIaCR0_RST_SGM_ON | SGMIIaCR0_PD_SGM,
+ SGMIIaCR0_RST_SGM | SGMIIaCR0_PD_SGM);
+ break;
+ case LANE_MODE_QSGMII:
+ err = lynx_pcvt_rmw(lane, mode, CR(0),
+ QSGMIIaCR0_RST_QSGM_ON | QSGMIIaCR0_PD_QSGM,
+ QSGMIIaCR0_RST_QSGM | QSGMIIaCR0_PD_QSGM);
+ if (err)
+ goto out;
+ break;
+ default:
+ err = 0;
+ }
+
+out:
+ spin_unlock(&priv->pcc_lock);
+
+ return err;
+}
+
+static int lynx_10g_lane_enable_pcvt(struct lynx_lane *lane,
+ enum lynx_lane_mode mode)
+{
+ struct lynx_priv *priv = lane->priv;
+ u32 val;
+ int err;
+
+ spin_lock(&priv->pcc_lock);
+
+ switch (mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ case LANE_MODE_2500BASEX:
+ err = lynx_pcvt_rmw(lane, mode, CR(1), SGMIIaCR1_SGPCS_EN,
+ SGMIIaCR1_SGPCS_EN);
+ if (err)
+ goto out;
+
+ lynx_pcvt_rmw(lane, mode, CR(0), SGMIIaCR0_RST_SGM_OFF,
+ SGMIIaCR0_RST_SGM | SGMIIaCR0_PD_SGM);
+ break;
+ case LANE_MODE_QSGMII:
+ err = lynx_pcvt_rmw(lane, mode, CR(0), QSGMIIaCR0_RST_QSGM_OFF,
+ QSGMIIaCR0_RST_QSGM | QSGMIIaCR0_PD_QSGM);
+ if (err)
+ goto out;
+ break;
+ default:
+ err = 0;
+ }
+
+ if (lane->default_pccr[mode]) {
+ err = lynx_pccr_write(lane, mode, lane->default_pccr[mode]);
+ goto out;
+ }
+
+ val = 0;
+
+ switch (mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ case LANE_MODE_2500BASEX:
+ val |= PCCR8_SGMIIa_CFG;
+ break;
+ case LANE_MODE_QSGMII:
+ val |= PCCR9_QSGMIIa_CFG;
+ break;
+ case LANE_MODE_10G_QXGMII:
+ val |= PCCR9_QXGMIIa_CFG;
+ break;
+ case LANE_MODE_10GBASER:
+ val |= PCCRB_XFIa_CFG;
+ break;
+ case LANE_MODE_USXGMII:
+ val |= PCCRB_SXGMIIa_CFG;
+ break;
+ default:
+ err = 0;
+ goto out;
+ }
+
+ err = lynx_pccr_write(lane, mode, val);
+out:
+ spin_unlock(&priv->pcc_lock);
+
+ return err;
+}
+
+static bool lynx_10g_lane_mode_needs_rcw_override(struct lynx_lane *lane,
+ enum lynx_lane_mode new)
+{
+ enum lynx_lane_mode curr = lane->mode;
+
+ /* Major protocol changes, which involve changing the PCS connection to
+ * the GMII MAC with the one to the XGMII MAC, require an RCW override
+ * procedure to reconfigure an internal mux, as documented here:
+ * https://lore.kernel.org/linux-phy/20230810102631.bvozjer3t67r67iy@skbuf/
+ * This is SoC-specific, and not yet implemented in drivers/soc/fsl/guts.c.
+ *
+ * So the supported set of protocols depends on the initial lane mode.
+ *
+ * Minor protocol changes (SGMII <-> 1000Base-X <-> 2500Base-X or
+ * 10GBase-R <-> USXGMII) are supported.
+ */
+ if ((lynx_lane_mode_uses_gmii_mac(curr) &&
+ lynx_lane_mode_uses_xgmii_mac(new)) ||
+ (lynx_lane_mode_uses_xgmii_mac(curr) &&
+ lynx_lane_mode_uses_gmii_mac(new)))
+ return true;
+
+ return false;
+}
+
+static int lynx_10g_validate(struct phy *phy, enum phy_mode mode, int submode,
+ union phy_configure_opts *opts)
+{
+ struct lynx_lane *lane = phy_get_drvdata(phy);
+ enum lynx_lane_mode lane_mode;
+ int err;
+
+ err = lynx_phy_mode_to_lane_mode(phy, mode, submode, &lane_mode);
+ if (err)
+ return err;
+
+ if (lynx_10g_lane_mode_needs_rcw_override(lane, lane_mode))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int lynx_10g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
+{
+ struct lynx_lane *lane = phy_get_drvdata(phy);
+ bool powered_up = lane->powered_up;
+ enum lynx_lane_mode lane_mode;
+ int err;
+
+ err = lynx_10g_validate(phy, mode, submode, NULL);
+ if (err)
+ return err;
+
+ lane_mode = phy_interface_to_lane_mode(submode);
+ /* lynx_10g_validate() already made sure the lane_mode is supported */
+
+ if (lane_mode == lane->mode)
+ return 0;
+
+ /* If the lane is powered up, put the lane into the halt state while
+ * the reconfiguration is being done.
+ */
+ if (powered_up)
+ lynx_10g_lane_halt(phy);
+
+ err = lynx_10g_lane_disable_pcvt(lane, lane->mode);
+ if (err)
+ goto out;
+
+ lynx_10g_lane_change_proto_conf(lane, lane_mode);
+ lynx_10g_lane_remap_pll(lane, lane_mode);
+ WARN_ON(lynx_10g_lane_enable_pcvt(lane, lane_mode));
+
+ lane->mode = lane_mode;
+
+out:
+ if (powered_up) {
+ /* The RM says to wait for at least 120 ns */
+ usleep_range(1, 2);
+ lynx_10g_lane_reset(phy);
+ }
+
+ return err;
+}
+
+static int lynx_10g_init(struct phy *phy)
+{
+ struct lynx_lane *lane = phy_get_drvdata(phy);
+
+ /* Mark the fact that the lane was init */
+ lane->init = true;
+
+ /* SerDes lanes are powered on at boot time. Any lane that is
+ * managed by this driver will get powered off when its consumer
+ * calls phy_init().
+ */
+ lane->powered_up = true;
+ lynx_10g_power_off(phy);
+
+ return 0;
+}
+
+static int lynx_10g_exit(struct phy *phy)
+{
+ struct lynx_lane *lane = phy_get_drvdata(phy);
+
+ /* The lane returns to the state where it isn't managed by the
+ * consumer, so we must treat is as if it isn't initialized, and always
+ * powered on.
+ */
+ lane->init = false;
+ lane->powered_up = false;
+ lynx_10g_power_on(phy);
+
+ return 0;
+}
+
+static const struct phy_ops lynx_10g_ops = {
+ .init = lynx_10g_init,
+ .exit = lynx_10g_exit,
+ .power_on = lynx_10g_power_on,
+ .power_off = lynx_10g_power_off,
+ .set_mode = lynx_10g_set_mode,
+ .validate = lynx_10g_validate,
+ .owner = THIS_MODULE,
+};
+
+static int lynx_10g_probe(struct platform_device *pdev)
+{
+ return lynx_probe(pdev, of_device_get_match_data(&pdev->dev),
+ &lynx_10g_ops);
+}
+
+static const struct of_device_id lynx_10g_of_match_table[] = {
+ { .compatible = "fsl,ls1028a-serdes", .data = &lynx_info_ls1028a },
+ { .compatible = "fsl,ls1046a-serdes1", .data = &lynx_info_ls1046a_serdes1 },
+ { .compatible = "fsl,ls1046a-serdes2", .data = &lynx_info_ls1046a_serdes2 },
+ { .compatible = "fsl,ls1088a-serdes1", .data = &lynx_info_ls1088a_serdes1 },
+ { .compatible = "fsl,ls2088a-serdes1", .data = &lynx_info_ls2088a_serdes1 },
+ { .compatible = "fsl,ls2088a-serdes2", .data = &lynx_info_ls2088a_serdes2 },
+ {}
+};
+MODULE_DEVICE_TABLE(of, lynx_10g_of_match_table);
+
+static struct platform_driver lynx_10g_driver = {
+ .probe = lynx_10g_probe,
+ .remove = lynx_remove,
+ .driver = {
+ .name = "lynx-10g",
+ .of_match_table = lynx_10g_of_match_table,
+ },
+};
+module_platform_driver(lynx_10g_driver);
+
+MODULE_IMPORT_NS("PHY_FSL_LYNX");
+MODULE_AUTHOR("Ioana Ciornei <ioana.ciornei@nxp.com>");
+MODULE_AUTHOR("Vladimir Oltean <vladimir.oltean@nxp.com>");
+MODULE_DESCRIPTION("Lynx 10G SerDes PHY driver for Layerscape SoCs");
+MODULE_LICENSE("GPL");
diff --git a/drivers/phy/freescale/phy-fsl-lynx-core.c b/drivers/phy/freescale/phy-fsl-lynx-core.c
index 1e411bfab404..2cfe9236ffc5 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-core.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-core.c
@@ -11,6 +11,12 @@ const char *lynx_lane_mode_str(enum lynx_lane_mode lane_mode)
switch (lane_mode) {
case LANE_MODE_1000BASEX_SGMII:
return "1000Base-X/SGMII";
+ case LANE_MODE_2500BASEX:
+ return "2500Base-X";
+ case LANE_MODE_QSGMII:
+ return "QSGMII";
+ case LANE_MODE_10G_QXGMII:
+ return "10G-QXGMII";
case LANE_MODE_10GBASER:
return "10GBase-R";
case LANE_MODE_USXGMII:
@@ -29,6 +35,12 @@ enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf)
case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_1000BASEX:
return LANE_MODE_1000BASEX_SGMII;
+ case PHY_INTERFACE_MODE_2500BASEX:
+ return LANE_MODE_2500BASEX;
+ case PHY_INTERFACE_MODE_QSGMII:
+ return LANE_MODE_QSGMII;
+ case PHY_INTERFACE_MODE_10G_QXGMII:
+ return LANE_MODE_10G_QXGMII;
case PHY_INTERFACE_MODE_10GBASER:
return LANE_MODE_10GBASER;
case PHY_INTERFACE_MODE_USXGMII:
@@ -89,6 +101,29 @@ bool lynx_lane_supports_mode(struct lynx_lane *lane, enum lynx_lane_mode mode)
}
EXPORT_SYMBOL_NS_GPL(lynx_lane_supports_mode, "PHY_FSL_LYNX");
+/* The quad protocols are fixed because the lane has multiple consumers, and
+ * one phy_set_mode_ext() affects the other consumers as well. We have no use
+ * case for dynamic protocol changing here, so disallow it.
+ */
+static enum lynx_lane_mode lynx_fixed_protocols[] = {
+ LANE_MODE_QSGMII,
+ LANE_MODE_10G_QXGMII,
+};
+
+static bool lynx_lane_restrict_fixed_mode_change(struct lynx_lane *lane,
+ enum lynx_lane_mode new)
+{
+ enum lynx_lane_mode curr = lane->mode;
+
+ for (int i = 0; i < ARRAY_SIZE(lynx_fixed_protocols); i++)
+ if ((curr == lynx_fixed_protocols[i] ||
+ new == lynx_fixed_protocols[i]) &&
+ curr != new)
+ return true;
+
+ return false;
+}
+
/* Translate the mode/submode from phy_validate() and phy_set_mode_ext() to a
* lane_mode and return 0 if it is supported and we can transition to it from
* the current lane mode, or return negative error otherwise.
@@ -112,6 +147,9 @@ int lynx_phy_mode_to_lane_mode(struct phy *phy, enum phy_mode mode,
if (!lynx_lane_supports_mode(lane, tmp_lane_mode))
return -EINVAL;
+ if (lynx_lane_restrict_fixed_mode_change(lane, tmp_lane_mode))
+ return -EINVAL;
+
if (lane_mode)
*lane_mode = tmp_lane_mode;
diff --git a/drivers/phy/freescale/phy-fsl-lynx-core.h b/drivers/phy/freescale/phy-fsl-lynx-core.h
index 37fa4b544faa..a60429ba9324 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-core.h
+++ b/drivers/phy/freescale/phy-fsl-lynx-core.h
@@ -9,6 +9,7 @@
#include <soc/fsl/phy-fsl-lynx.h>
#define LYNX_NUM_PLL 2
+#define LYNX_QUIRK_HAS_HARDCODED_USXGMII BIT(0)
struct lynx_priv;
struct lynx_lane;
@@ -36,6 +37,7 @@ struct lynx_lane {
bool init;
unsigned int id;
enum lynx_lane_mode mode;
+ u32 default_pccr[LANE_MODE_MAX];
};
struct lynx_info {
@@ -48,6 +50,8 @@ struct lynx_info {
void (*cdr_lock_check)(struct lynx_lane *lane);
int first_lane;
int num_lanes;
+ int index;
+ unsigned long quirks;
};
struct lynx_priv {
diff --git a/include/soc/fsl/phy-fsl-lynx.h b/include/soc/fsl/phy-fsl-lynx.h
index 92e8272d5ae1..ff5a7d1835b5 100644
--- a/include/soc/fsl/phy-fsl-lynx.h
+++ b/include/soc/fsl/phy-fsl-lynx.h
@@ -7,10 +7,37 @@
enum lynx_lane_mode {
LANE_MODE_UNKNOWN,
LANE_MODE_1000BASEX_SGMII,
+ LANE_MODE_2500BASEX,
+ LANE_MODE_QSGMII,
+ LANE_MODE_10G_QXGMII,
LANE_MODE_10GBASER,
LANE_MODE_USXGMII,
LANE_MODE_25GBASER,
LANE_MODE_MAX,
};
+static inline bool lynx_lane_mode_uses_gmii_mac(enum lynx_lane_mode mode)
+{
+ switch (mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ case LANE_MODE_2500BASEX:
+ case LANE_MODE_QSGMII:
+ case LANE_MODE_10G_QXGMII:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static inline bool lynx_lane_mode_uses_xgmii_mac(enum lynx_lane_mode mode)
+{
+ switch (mode) {
+ case LANE_MODE_10GBASER:
+ case LANE_MODE_USXGMII:
+ return true;
+ default:
+ return false;
+ }
+}
+
#endif /* __PHY_FSL_LYNX_H_ */
--
2.34.1
^ permalink raw reply related
* Re: [PATCH v5 0/4] Enable sysfs module symlink for more built-in drivers
From: Danilo Krummrich @ 2026-06-08 22:16 UTC (permalink / raw)
To: Shashank Balaji
Cc: Suzuki K Poulose, James Clark, Alexander Shishkin,
Greg Kroah-Hartman, Rafael J. Wysocki, Miguel Ojeda, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Alice Ryhl, Trevor Gross, Jonathan Corbet, Shuah Khan,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Mike Leach, Leo Yan, Thierry Reding,
Jonathan Hunter, Rahul Bukte, linux-kernel, coresight,
linux-arm-kernel, driver-core, rust-for-linux, linux-doc,
Daniel Palmer, Tim Bird, linux-modules, linux-tegra, Sumit Gupta
In-Reply-To: <20260518-acpi_mod_name-v5-0-705ccc430885@sony.com>
On Mon May 18, 2026 at 12:19 PM CEST, Shashank Balaji wrote:
> Shashank Balaji (4):
> soc/tegra: cbb: Move driver registration from pure_initcall to core_initcall
> kernel: param: initialize module_kset in a pure_initcall
> coresight: pass THIS_MODULE implicitly through a macro
> driver core: platform: set mod_name in driver registration
Picking this up now, so it can still make it for 7.2-rc1 and get some time in
linux-next.
Suzuki, since I haven't heard back I figured it should be fine to also pick the
coresight change as it is purely mechanic and driver-core motivated, but please
let me know if you have any concerns.
Thanks,
Danilo
^ permalink raw reply
* [PATCH v2 2/2] cache: add SMCCC-backed cache invalidate provider
From: Srirangan Madhavan @ 2026-06-08 22:07 UTC (permalink / raw)
To: Mark Rutland, Lorenzo Pieralisi, Sudeep Holla, Conor Dooley,
Jonathan Cameron
Cc: Catalin Marinas, Will Deacon, Dan Williams, Thierry Reding,
Jonathan Hunter, Souvik Chakravarty, linux-arm-kernel,
linux-kernel, linux-tegra, Srirangan Madhavan
In-Reply-To: <20260608220709.1300245-1-smadhavan@nvidia.com>
Add a cache maintenance provider for the Arm SMCCC cache clean+invalidate
interface.
The provider discovers SMCCC support and attributes at init time,
serializes firmware calls, handles transient BUSY and RATE_LIMITED
responses with bounded retries, and registers with the generic cache
coherency framework used by memregion callers.
Signed-off-by: Srirangan Madhavan <smadhavan@nvidia.com>
Reviewed-by: Jonathan Cameron <jic23@kernel.org>
---
drivers/cache/Kconfig | 11 +++
drivers/cache/Makefile | 2 +
drivers/cache/arm_smccc_cache.c | 157 ++++++++++++++++++++++++++++++++
3 files changed, 170 insertions(+)
create mode 100644 drivers/cache/arm_smccc_cache.c
diff --git a/drivers/cache/Kconfig b/drivers/cache/Kconfig
index 1518449d47b5..57fd1823dec5 100644
--- a/drivers/cache/Kconfig
+++ b/drivers/cache/Kconfig
@@ -42,6 +42,17 @@ menuconfig CACHEMAINT_FOR_HOTPLUG
if CACHEMAINT_FOR_HOTPLUG
+config ARM_SMCCC_CACHE
+ bool "Arm SMCCC cache maintenance provider"
+ depends on ARM64 && HAVE_ARM_SMCCC_DISCOVERY
+ help
+ Enable support for the Arm SMCCC cache clean+invalidate
+ interface as a provider for memory hotplug-like cache
+ maintenance operations.
+ The provider registers only when firmware advertises the
+ SMCCC calls and attributes, so systems without firmware support
+ continue without this registered provider.
+
config HISI_SOC_HHA
tristate "HiSilicon Hydra Home Agent (HHA) device driver"
depends on (ARM64 && ACPI) || COMPILE_TEST
diff --git a/drivers/cache/Makefile b/drivers/cache/Makefile
index b3362b15d6c1..55736a032d6f 100644
--- a/drivers/cache/Makefile
+++ b/drivers/cache/Makefile
@@ -4,4 +4,6 @@ obj-$(CONFIG_AX45MP_L2_CACHE) += ax45mp_cache.o
obj-$(CONFIG_SIFIVE_CCACHE) += sifive_ccache.o
obj-$(CONFIG_STARFIVE_STARLINK_CACHE) += starfive_starlink_cache.o
+# Providers below depend on CACHEMAINT_FOR_HOTPLUG.
+obj-$(CONFIG_ARM_SMCCC_CACHE) += arm_smccc_cache.o
obj-$(CONFIG_HISI_SOC_HHA) += hisi_soc_hha.o
diff --git a/drivers/cache/arm_smccc_cache.c b/drivers/cache/arm_smccc_cache.c
new file mode 100644
index 000000000000..82b9efdb190b
--- /dev/null
+++ b/drivers/cache/arm_smccc_cache.c
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026 NVIDIA Corporation
+ *
+ * Arm SMCCC cache maintenance provider using cache clean+invalidate calls.
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/cache_coherency.h>
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/nmi.h>
+
+#define SMCCC_CACHE_MAX_RETRIES 5
+#define SMCCC_CACHE_DEFAULT_DELAY_US 1000UL
+#define SMCCC_CACHE_MAX_DELAY_US 20000UL
+
+struct smccc_cache {
+ /* Must be first member */
+ struct cache_coherency_ops_inst cci;
+ struct mutex lock; /* Serializes SMCCC cache maintenance calls. */
+ u32 latency_us;
+ u32 rate_limit;
+};
+
+static int smccc_cache_status_to_errno(s32 status)
+{
+ switch (status) {
+ case SMCCC_RET_SUCCESS:
+ return 0;
+ case SMCCC_RET_NOT_SUPPORTED:
+ return -EOPNOTSUPP;
+ case SMCCC_RET_INVALID_PARAMETER:
+ return -EINVAL;
+ case SMCCC_RET_RATE_LIMITED:
+ return -EAGAIN;
+ case SMCCC_RET_BUSY:
+ return -EBUSY;
+ default:
+ return -EIO;
+ }
+}
+
+static unsigned long smccc_cache_delay_us(const struct smccc_cache *cache)
+{
+ unsigned long delay_us = 0;
+
+ if (cache->rate_limit)
+ delay_us = DIV_ROUND_UP_ULL(USEC_PER_SEC, cache->rate_limit);
+
+ if (cache->latency_us)
+ delay_us = max(delay_us, (unsigned long)cache->latency_us);
+
+ /*
+ * Firmware may advertise neither a rate limit nor a latency hint; use
+ * a small bounded backoff instead of retrying in a tight loop.
+ */
+ if (!delay_us)
+ delay_us = SMCCC_CACHE_DEFAULT_DELAY_US;
+
+ return min(delay_us, SMCCC_CACHE_MAX_DELAY_US);
+}
+
+static int smccc_cache_wbinv(struct cache_coherency_ops_inst *cci,
+ struct cc_inval_params *invp)
+{
+ struct smccc_cache *cache = container_of(cci, struct smccc_cache, cci);
+ struct arm_smccc_res res = {};
+ unsigned long delay_us = smccc_cache_delay_us(cache);
+ int ret;
+
+ if (!invp->size)
+ return -EINVAL;
+
+ /*
+ * Serialize the full retry sequence. With the default bounds, a caller
+ * may hold the mutex across up to five 20ms backoff sleeps.
+ */
+ guard(mutex)(&cache->lock);
+
+ for (unsigned int i = 0; i < SMCCC_CACHE_MAX_RETRIES; i++) {
+ /* Long firmware operations can trigger watchdog checks. */
+ touch_nmi_watchdog();
+
+ arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_CLEAN_INV_MEMREGION,
+ invp->addr, invp->size, 0UL, &res);
+
+ ret = smccc_cache_status_to_errno((s32)res.a0);
+ if (!ret)
+ return 0;
+
+ if (ret != -EBUSY && ret != -EAGAIN)
+ return ret;
+
+ fsleep(delay_us);
+ }
+
+ return -EBUSY;
+}
+
+static const struct cache_coherency_ops smccc_cache_ops = {
+ .wbinv = smccc_cache_wbinv,
+};
+
+static int __init smccc_cache_init(void)
+{
+ struct smccc_cache *cache;
+ struct arm_smccc_res res = {};
+ int ret;
+
+ if (arm_smccc_get_version() < ARM_SMCCC_VERSION_1_1)
+ return -ENODEV;
+
+ if (arm_smccc_1_1_get_conduit() == SMCCC_CONDUIT_NONE)
+ return -ENODEV;
+
+ arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
+ ARM_SMCCC_ARCH_CLEAN_INV_MEMREGION, &res);
+ if ((s32)res.a0 < 0)
+ return -ENODEV;
+
+ arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
+ ARM_SMCCC_ARCH_CLEAN_INV_MEMREGION_ATTRIBUTES,
+ &res);
+ if ((s32)res.a0 < 0)
+ return -ENODEV;
+
+ arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_CLEAN_INV_MEMREGION_ATTRIBUTES,
+ &res);
+ if ((s32)res.a0)
+ return -ENODEV;
+
+ cache = cache_coherency_ops_instance_alloc(&smccc_cache_ops,
+ struct smccc_cache, cci);
+ if (!cache)
+ return -ENOMEM;
+
+ mutex_init(&cache->lock);
+ cache->latency_us = lower_32_bits(res.a2);
+ cache->rate_limit = lower_32_bits(res.a3);
+
+ ret = cache_coherency_ops_instance_register(&cache->cci);
+ if (ret) {
+ mutex_destroy(&cache->lock);
+ cache_coherency_ops_instance_put(&cache->cci);
+ return ret;
+ }
+
+ pr_info("SMCCC cache clean+invalidate provider registered\n");
+
+ return 0;
+}
+arch_initcall(smccc_cache_init);
--
2.43.0
^ permalink raw reply related
* [PATCH v2 1/2] arm64: smccc: add cache clean/invalidate IDs and return codes
From: Srirangan Madhavan @ 2026-06-08 22:07 UTC (permalink / raw)
To: Mark Rutland, Lorenzo Pieralisi, Sudeep Holla, Conor Dooley,
Jonathan Cameron
Cc: Catalin Marinas, Will Deacon, Dan Williams, Thierry Reding,
Jonathan Hunter, Souvik Chakravarty, linux-arm-kernel,
linux-kernel, linux-tegra, Srirangan Madhavan
In-Reply-To: <20260608220709.1300245-1-smadhavan@nvidia.com>
Define SMCCC Arch function IDs for CLEAN_INV_MEMREGION and its ATTRIBUTES
call, and add RATE_LIMITED/BUSY return codes from DEN0028 for callers that
need transient error handling.
Signed-off-by: Srirangan Madhavan <smadhavan@nvidia.com>
Reviewed-by: Jonathan Cameron <jic23@kernel.org>
---
include/linux/arm-smccc.h | 21 +++++++++++++++++++--
tools/include/linux/arm-smccc.h | 21 +++++++++++++++++++--
2 files changed, 38 insertions(+), 4 deletions(-)
diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
index 50b47eba7d01..8cba040e0816 100644
--- a/include/linux/arm-smccc.h
+++ b/include/linux/arm-smccc.h
@@ -105,6 +105,22 @@
ARM_SMCCC_SMC_32, \
0, 0x3fff)
+/*
+ * DEN0028 v1.7 defines these cache maintenance functions as SMC64
+ * because they carry 64-bit memory range arguments.
+ */
+#define ARM_SMCCC_ARCH_CLEAN_INV_MEMREGION \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
+ ARM_SMCCC_SMC_64, \
+ ARM_SMCCC_OWNER_ARCH, \
+ 0x5)
+
+#define ARM_SMCCC_ARCH_CLEAN_INV_MEMREGION_ATTRIBUTES \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
+ ARM_SMCCC_SMC_64, \
+ ARM_SMCCC_OWNER_ARCH, \
+ 0x6)
+
#define ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID \
ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
ARM_SMCCC_SMC_32, \
@@ -294,13 +310,14 @@
0x53)
/*
- * Return codes defined in ARM DEN 0070A
- * ARM DEN 0070A is now merged/consolidated into ARM DEN 0028 C
+ * Return codes defined by Arm SMCCC (DEN0028 v1.7).
*/
#define SMCCC_RET_SUCCESS 0
#define SMCCC_RET_NOT_SUPPORTED -1
#define SMCCC_RET_NOT_REQUIRED -2
#define SMCCC_RET_INVALID_PARAMETER -3
+#define SMCCC_RET_RATE_LIMITED -4
+#define SMCCC_RET_BUSY -5
#ifndef __ASSEMBLY__
diff --git a/tools/include/linux/arm-smccc.h b/tools/include/linux/arm-smccc.h
index 63ce9bebccd3..ae5637b3240f 100644
--- a/tools/include/linux/arm-smccc.h
+++ b/tools/include/linux/arm-smccc.h
@@ -96,6 +96,22 @@
ARM_SMCCC_SMC_32, \
0, 0x3fff)
+/*
+ * DEN0028 v1.7 defines these cache maintenance functions as SMC64
+ * because they carry 64-bit memory range arguments.
+ */
+#define ARM_SMCCC_ARCH_CLEAN_INV_MEMREGION \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
+ ARM_SMCCC_SMC_64, \
+ ARM_SMCCC_OWNER_ARCH, \
+ 0x5)
+
+#define ARM_SMCCC_ARCH_CLEAN_INV_MEMREGION_ATTRIBUTES \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
+ ARM_SMCCC_SMC_64, \
+ ARM_SMCCC_OWNER_ARCH, \
+ 0x6)
+
#define ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID \
ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
ARM_SMCCC_SMC_32, \
@@ -182,12 +198,13 @@
0x53)
/*
- * Return codes defined in ARM DEN 0070A
- * ARM DEN 0070A is now merged/consolidated into ARM DEN 0028 C
+ * Return codes defined by Arm SMCCC (DEN0028 v1.7).
*/
#define SMCCC_RET_SUCCESS 0
#define SMCCC_RET_NOT_SUPPORTED -1
#define SMCCC_RET_NOT_REQUIRED -2
#define SMCCC_RET_INVALID_PARAMETER -3
+#define SMCCC_RET_RATE_LIMITED -4
+#define SMCCC_RET_BUSY -5
#endif /*__LINUX_ARM_SMCCC_H*/
--
2.43.0
^ permalink raw reply related
* [PATCH v2 0/2] Add SMCCC cache clean/invalidate provider
From: Srirangan Madhavan @ 2026-06-08 22:07 UTC (permalink / raw)
To: Mark Rutland, Lorenzo Pieralisi, Sudeep Holla, Conor Dooley,
Jonathan Cameron
Cc: Catalin Marinas, Will Deacon, Dan Williams, Thierry Reding,
Jonathan Hunter, Souvik Chakravarty, linux-arm-kernel,
linux-kernel, linux-tegra, Srirangan Madhavan
This series adds an arm64 backend for memregion cache invalidation users
based on the Arm SMCCC cache clean+invalidate interface.
Per DEN0028, this interface targets systems where a Normal Cacheable
memory region can be modified in ways that are not handled by usual PE
coherency mechanisms, and where VA-based CMOs may be too slow or
insufficient for large ranges and/or system-cache implementations.
Representative use cases include device-backed memory state transitions
where stale CPU/system cache lines must be invalidated reliably (for
example secure erase, reset/offline flows, and dynamic memory
reconfiguration).
Patch 1 introduces the Arm SMCCC cache clean/invalidate function IDs and
transient return codes needed by callers [1].
Patch 2 adds a cache maintenance provider that:
- discovers SMCCC support and attributes at init time
- registers with the generic cache coherency framework used by
cpu_cache_invalidate_memregion()
- handles transient BUSY/RATE_LIMITED responses with bounded retries
This patch set does not add a software fallback path; when firmware does
not implement the SMCCC cache maintenance interface, the provider is not
registered and existing behavior is preserved.
Reference:
[1] https://developer.arm.com/documentation/den0028/latest
Note: Jonathan Cameron raised whether DEN0028 v1.7 BET0 is sufficient
for merge. Input from Arm maintainers / SMCCC spec owners on that point
would be appreciated.
Changes since v1:
- Added Jonathan Cameron's Reviewed-by tags.
- Clarified the ARM_SMCCC_CACHE Kconfig help text.
- Added a Makefile comment identifying the providers that depend on
CACHEMAINT_FOR_HOTPLUG.
- Dropped the final-backoff-sleep skip in the retry loop.
Changes since RFC:
- Dropped the RFC tag.
- Moved the provider from arch/arm64/mm to drivers/cache.
- Added a dedicated CONFIG_ARM_SMCCC_CACHE option under the existing
CACHEMAINT_FOR_HOTPLUG menu.
- Dropped the global-operation coalescing optimization.
- Dropped provider handling for SMCCC_RET_NOT_REQUIRED.
- Removed the unnecessary global provider pointer.
- Removed arm64_ prefixes from static provider-local names.
- Documented why these SMCCC Arch cache maintenance calls use SMC64.
- Anchored the SMCCC return-code comment to DEN0028 v1.7.
- Used fsleep() for retry backoff.
- Used unsigned long for retry delay values passed to fsleep().
- Skipped the final backoff sleep when no retry remains.
- Documented the bounded mutex hold time across the serialized retry
sequence.
- Added mutex_destroy() on the registration failure path.
Srirangan Madhavan (2):
arm64: smccc: add cache clean/invalidate IDs and return codes
cache: add SMCCC-backed cache invalidate provider
drivers/cache/Kconfig | 11 +++
drivers/cache/Makefile | 2 +
drivers/cache/arm_smccc_cache.c | 157 ++++++++++++++++++++++++++++++++
include/linux/arm-smccc.h | 21 ++++-
tools/include/linux/arm-smccc.h | 21 ++++-
5 files changed, 208 insertions(+), 4 deletions(-)
create mode 100644 drivers/cache/arm_smccc_cache.c
base-commit: 3b3bea6d4b9c162f9e555905d96b8c1da67ecd5b
--
2.43.0
^ permalink raw reply
* Re: [PATCH v2 2/6] leds: is31fl319x: Fix shutdown GPIO initial state and remove redundant startup pulse
From: Linus Walleij @ 2026-06-08 22:03 UTC (permalink / raw)
To: Jun Yan
Cc: dmitry.baryshkov, Lee Jones, Pavel Machek, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio,
Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
Bartosz Golaszewski, Vincent Knecht, Grant Feng, Andre Przywara,
Geert Uytterhoeven, Viresh Kumar, Florian Fainelli, Robert Marko,
Pavel Machek, Krzysztof Kozlowski, Shawn Guo, Michal Simek,
Heiko Stuebner, linux-leds, devicetree, linux-kernel,
linux-arm-msm, linux-arm-kernel, linux-gpio
In-Reply-To: <20260525144629.498630-3-jerrysteve1101@gmail.com>
Hi Jun,
thanks for your patch!
On Mon, May 25, 2026 at 4:47 PM Jun Yan <jerrysteve1101@gmail.com> wrote:
> - is31->shutdown_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH);
> + /* Driving this GPIO line low (in fact high) takes the chip out of shutdown,
> + * as it is flagged as GPIO_ACTIVE_LOW in provider (such as the device tree).
> + */
> + is31->shutdown_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_LOW);
This is fine but only if you also add a quirk to
drivers/gpio/gpiolib-of.c in of_gpio_try_fixup_polarity()
that will enforce the GPIOD_OUT_LOW property on the line.
Follow the examples.
This solves the API breakage.
It should probably be part of the same patch for bisectability.
Yours,
Linus Walleij
^ permalink raw reply
* Re: [PATCH] pinctrl: mediatek: mt8167: Fix Schmitt trigger register offset of pins 34-39
From: Linus Walleij @ 2026-06-08 21:56 UTC (permalink / raw)
To: Luca Leonardo Scorcia
Cc: linux-mediatek, Sean Wang, Matthias Brugger,
AngeloGioacchino Del Regno, Fabien Parent, linux-gpio,
linux-kernel, linux-arm-kernel
In-Reply-To: <20260531162340.5326-1-l.scorcia@gmail.com>
On Sun, May 31, 2026 at 6:23 PM Luca Leonardo Scorcia
<l.scorcia@gmail.com> wrote:
> The correct Schmitt trigger register offset for pins 34-39 is 0xA00. Value
> was verified with SoC data sheet.
>
> Signed-off-by: Luca Leonardo Scorcia <l.scorcia@gmail.com>
> Fixes: 82d70627e94a ("pinctrl: mediatek: Add MT8167 Pinctrl driver")
Patch applied.
Yours,
Linus Walleij
^ permalink raw reply
* Re: [PATCH] pinctrl: mediatek: mt8516: Fix Schmitt trigger register offset of pins 34-39
From: Linus Walleij @ 2026-06-08 21:55 UTC (permalink / raw)
To: Luca Leonardo Scorcia
Cc: linux-mediatek, Sean Wang, Matthias Brugger,
AngeloGioacchino Del Regno, Fabien Parent, linux-gpio,
linux-kernel, linux-arm-kernel
In-Reply-To: <20260531162237.5290-1-l.scorcia@gmail.com>
On Sun, May 31, 2026 at 6:23 PM Luca Leonardo Scorcia
<l.scorcia@gmail.com> wrote:
> The correct Schmitt trigger register offset for pins 34-39 is 0xA00.
>
> Signed-off-by: Luca Leonardo Scorcia <l.scorcia@gmail.com>
> Fixes: 264667112ef0 ("pinctrl: mediatek: Add MT8516 Pinctrl driver")
Patch applied.
Yours,
Linus Walleij
^ permalink raw reply
* [PATCH net-next] net: airoha: move get_sport() callback at the beginning of airoha_enable_gdm2_loopback()
From: Lorenzo Bianconi @ 2026-06-08 21:24 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: linux-arm-kernel, linux-mediatek, netdev, Lorenzo Bianconi
Move the get_sport() callback invocation at the beginning of
airoha_enable_gdm2_loopback() routine in order to avoid leaving the
hardware in a partially configured state if get_sport() fails.
Previously, get_sport() was called after GDM2 forwarding, loopback,
channel, length, VIP and IFC registers had already been programmed.
A failure at that point would return an error leaving GDM2 with
loopback enabled but WAN port, PPE CPU port and flow control mappings
not configured.
Performing the get_sport() lookup before any register write guarantees
the routine either completes the full configuration sequence or exits
with no side effects on the hardware.
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/net/ethernet/airoha/airoha_eth.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 5a8e84fa9918..cbc0f4079df0 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -1905,6 +1905,10 @@ static int airoha_enable_gdm2_loopback(struct airoha_gdm_dev *dev)
u32 val, pse_port, chan;
int i, src_port;
+ src_port = eth->soc->ops.get_sport(port, dev->nbq);
+ if (src_port < 0)
+ return src_port;
+
airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(AIROHA_GDM2_IDX),
FE_PSE_PORT_DROP);
airoha_fe_clear(eth, REG_GDM_FWD_CFG(AIROHA_GDM2_IDX),
@@ -1934,10 +1938,6 @@ static int airoha_enable_gdm2_loopback(struct airoha_gdm_dev *dev)
airoha_fe_clear(eth, REG_FE_VIP_PORT_EN, BIT(AIROHA_GDM2_IDX));
airoha_fe_clear(eth, REG_FE_IFC_PORT_EN, BIT(AIROHA_GDM2_IDX));
- src_port = eth->soc->ops.get_sport(port, dev->nbq);
- if (src_port < 0)
- return src_port;
-
airoha_fe_rmw(eth, REG_FE_WAN_PORT,
WAN1_EN_MASK | WAN1_MASK | WAN0_MASK,
FIELD_PREP(WAN0_MASK, src_port));
---
base-commit: 903db046d5579bef0ea699eae4b279dd6455fc9f
change-id: 20260608-airoha_enable_gdm2_loopback-minor-change-fda3a3351a06
Best regards,
--
Lorenzo Bianconi <lorenzo@kernel.org>
^ permalink raw reply related
* Re: [PATCH] KVM: arm64: Expose PMMIR_EL1.SLOTS to guests
From: Congkai Tan @ 2026-06-08 21:03 UTC (permalink / raw)
To: oupton
Cc: blakgeof, catalin.marinas, congkai, harisokn, joey.gouly, kvmarm,
linux-arm-kernel, linux-kernel, mark.rutland, maz, suzuki.poulose,
will, yuzenghui
In-Reply-To: <ah3mObchzwb80_3S@kernel.org>
On Mon, Jun 01, 2026 at 01:06:17PM -0700, Oliver Upton wrote:
> We can't change the value of PMMIR_EL1 unconditionally since older KVM
> treated this register as RAZ/WI. This also mixes poorly with the default
> PMU garbage that we have since as the value of the register can change
> based on where KVM_ARM_VCPU_INIT gets called...
>
> Considering everything, I'd like to see this wired up where:
>
> - PMMIR_EL1.SLOTS takes the value of the underlying hardware PMU only
> if the VMM explicitly selects a particular PMU implementation
>
> - KVM allows userspace to set PMMIR_EL1.SLOTS=0 for backwards
> compatibility
Thanks a lot for the review! Makes sense. We'll work on v2, and here is
the high-level design we plan to follow:
- Introduce a new VM-wide field, e.g. kvm->arch.pmmir_slots.
- Seed it from the underlying hardware value only when handling
KVM_ARM_VCPU_PMU_V3_SET_PMU; otherwise it stays 0.
- access_pmmir() returns whatever is in pmmir_slots.
- set_pmmir() writes pmmir_slots to 0 if the user input is 0;
otherwise it no-ops or rejects.
This way the guest only sees the underlying hardware value if the VMM
selects a PMU via KVM_ARM_VCPU_PMU_V3_SET_PMU, and userspace can pin
SLOTS = 0 through KVM_SET_ONE_REG for backwards compatibility.
Please let me know if there are any concerns. I'll send v2 once it's
ready.
Thanks,
Congkai
^ permalink raw reply
* [PATCH v2] gpiolib: handle gpio-hogs only once
From: Daniel Drake @ 2026-06-08 21:01 UTC (permalink / raw)
To: linusw, brgl; +Cc: linux-gpio, linux-arm-kernel, Daniel Drake
Commit d1d564ec49929 ("gpio: move hogs into GPIO core") introduced a
behaviour change that breaks boot on Raspberry Pi 5 when using the
firmware-supplied device tree:
gpiochip_add_data_with_key: GPIOs 544..575
(/soc@107c000000/gpio@7d517c00) failed to register, -22
brcmstb-gpio 107d517c00.gpio: Could not add gpiochip for bank 1
brcmstb-gpio 107d517c00.gpio: probe with driver brcmstb-gpio failed
with error -22
gpio-brcmstb registers two gpio_chips against the device tree
node gpio@7d517c00, one for each bank. The firmware-supplied DT includes
a gpio-hog on RP1 RUN, and this gpio-hog is attempted to be applied to
*both* gpio_chips. This succeeds against bank 0 (which hosts the GPIO)
and fails for bank 1 (which does not).
In the previous implementation, failures to apply gpio-hogs were
quietly ignored. In the new code, the error code propagates and causes
probe to fail.
Closely approximate the previous behaviour by using the OF_POPULATED flag
to ensure that each gpio-hog is processed only once. The flag was
previously being set before the gpio-hogs were processed, so as part
of this change, the flag now gets set only after the gpio-hog is actioned.
The handling of gpio-hogs on a DT node with multiple gpio_chips remains a
bit incomplete/unclear, but this at least retains the ability to apply
hogs to the first gpio_chip per node.
Signed-off-by: Daniel Drake <dan@reactivated.net>
---
drivers/gpio/gpiolib-of.c | 5 -----
drivers/gpio/gpiolib.c | 8 ++++++++
2 files changed, 8 insertions(+), 5 deletions(-)
v2: move OF_POPULATED flag setting to happen after the gpio-hog has
been applied (otherwise all hogs were considered already-applied
and never applied at all, oops!)
This bug is only exposed by the RPi5 firmware-provided DT that has the
gpio-hog. The DT shipped in the mainline kernel does not have the hog
here. I'm not sure to what extent Linux cares about supporting the
downstream firmware DT.
I'm also happy to consider other approaches. This multi-gpiochip setup is
a bit weird and gpio-brcmstb could perhaps be converted to register only a
single gpio_chip covering all banks. I verified that the other drivers
that obviously follow this same multiple-gpiochip pattern
(pinctrl-amlogic-a4, pinctrl-st and pinctrl-stm32) do not seem to be used by
any board DTs that include gpio-hogs.
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 2c923d17541f..813dbcb91f6f 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -1066,11 +1066,6 @@ int of_gpiochip_add(struct gpio_chip *chip)
of_node_get(np);
- for_each_available_child_of_node_scoped(np, child) {
- if (of_property_read_bool(child, "gpio-hog"))
- of_node_set_flag(child, OF_POPULATED);
- }
-
return ret;
}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 1e6dce430dca..b02d711289d0 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1031,9 +1031,17 @@ static int gpiochip_hog_lines(struct gpio_chip *gc)
if (!fwnode_property_present(fwnode, "gpio-hog"))
continue;
+ /* The hog may have been handled by another gpio_chip on the same fwnode */
+ if (is_of_node(fwnode) &&
+ of_node_check_flag(to_of_node(fwnode), OF_POPULATED))
+ continue;
+
ret = gpiochip_add_hog(gc, fwnode);
if (ret)
return ret;
+
+ if (is_of_node(fwnode))
+ of_node_set_flag(to_of_node(fwnode), OF_POPULATED);
}
return 0;
--
2.54.0
^ permalink raw reply related
* Re: -next boot failures during KVM setup
From: Ard Biesheuvel @ 2026-06-08 20:56 UTC (permalink / raw)
To: Marc Zyngier, Mark Brown, Will Deacon, Catalin Marinas
Cc: Oliver Upton, Aishwarya.TCV, linux-arm-kernel
In-Reply-To: <87tsrc946i.wl-maz@kernel.org>
On Mon, 8 Jun 2026, at 22:18, Marc Zyngier wrote:
> [+ Will, Catalin, Ard]
>
> On Mon, 08 Jun 2026 20:19:37 +0100,
> Mark Brown <broonie@kernel.org> wrote:
>>
>> I'm seeing boot failures on a range of physical arm64 platforms in
>> today's -next. Turning on earlycon it looks like we're getting bad
>> pointer dereferences during KVM initialisation:
>>
>> [ 0.728923] kvm [1]: nv: 570 coarse grained trap handlers
>> [ 0.735138] kvm [1]: nv: 710 fine grained trap handlers
>> [ 0.741326] kvm [1]: IPA Size Limit: 40 bits
>> [ 0.748840] Unable to handle kernel paging request at virtual address ffff00000478e000
>
> That really doesn't look like a duff pointer.
>
>> [ 0.757027] Mem abort info:
>> [ 0.759917] ESR = 0x0000000096000147
>
> Translation fault, level 3. My take is that something is getting
> unmapped.
>
...
> I've reproduced with -next on an A72 platform. But it doesn't happen
> with kvmarm/next on its own. So it is likely something coming from
> another tree that messes up with CMOs, or .
>
> The stack trace here is slightly better:
>
> [ 0.099138] Unable to handle kernel paging request at virtual
> address ffff0023d9ead000
...
> [ 2.136462] Call trace:
> [ 2.138896] dcache_clean_inval_poc+0x24/0x48 (P)
> [ 2.143592] init_hyp_mode+0x644/0x960
> [ 2.147333] kvm_arm_init+0x128/0x280
> [ 2.150987] do_one_initcall+0x4c/0x458
> [ 2.154813] kernel_init_freeable+0x1f4/0x2a0
> [ 2.159161] kernel_init+0x2c/0x150
> [ 2.162642] ret_from_fork+0x10/0x20
> [ 2.166210] Code: 9ac32042 d1000443 8a230000 d503201f (d50b7e20)
> [ 2.172292] ---[ end trace 0000000000000000 ]---
> [ 2.176958] Kernel panic - not syncing: Attempted to kill init!
> exitcode=0x0000000b
> [ 2.184608] SMP: stopping secondary CPUs
> [ 2.188523] Kernel Offset: 0x47dbd5dc0000 from 0xffff800080000000
> [ 2.194604] PHYS_OFFSET: 0x80000000
> [ 2.198080] CPU features: 0x04000000,804b0008,00040001,0400421b
> [ 2.203988] Memory Limit: none
> [ 2.207031] ---[ end Kernel panic - not syncing: Attempted to kill
> init! exitcode=0x0000000b ]---
>
> This points to the following code in kvm_hyp_init_symbols():
>
> <quote>
> /*
> * Flush entire BSS since part of its data containing init symbols is read
> * while the MMU is off.
> */
> kvm_flush_dcache_to_poc(kvm_ksym_ref(__hyp_bss_start),
> kvm_ksym_ref(__hyp_bss_end) - kvm_ksym_ref(__hyp_bss_start))
>
> </quote>
>
> which I suspect is related to some of the new BSS related code in
> arm64/for-next/mm.
>
> Ard, does this ring a bell?
>
Haven't seen this myself, surprisingly, but yeah, this is obviously related.
By now, I am wondering if unmapping that region entirely is really worth the
hassle, or whether we'd be better off just remapping it read-only.
Given we're at -rc7, I'd lean towards dropping the whole branch for now, or
alternatively, only drop/revert "arm64: mm: Unmap kernel data/bss entirely from the
linear map" (and its followup fix "arm64: mm: Defer remap of linear alias of
data/bss") so that the region always remains readable via the linear map.
^ permalink raw reply
* Re: [PATCH] KVM: arm64: Hold kvm->mmu_lock while initialising vcpu->arch.vncr_tlb
From: Yosry Ahmed @ 2026-06-08 20:55 UTC (permalink / raw)
To: Marc Zyngier
Cc: kvmarm, kvm, linux-arm-kernel, Steffen Eiden, Joey Gouly,
Suzuki K Poulose, Oliver Upton, Zenghui Yu
In-Reply-To: <20260608081108.2244133-1-maz@kernel.org>
On Mon, Jun 08, 2026 at 09:11:08AM +0100, Marc Zyngier wrote:
> Sashiko reports that there is a race between initialising vncr_tlb
> and making use of it, as we don't hold the mmu_lock at this point.
>
> Additionally, it identifies a memory leak, should userspace repeatedly
> invokes the KVM_RUN ioctl after a failure of kvm_arch_vcpu_run_pid_change(),
> as we assign vncr_tlb blindly on first run, irrespective of prior
> allocations.
>
> Slap the two bugs in one go by taking the kvm->mmu_lock on assigning
> vncr_tlb, preventing the race for good, and by checking that vncr_tlb
> is indeed NULL prior to allocation.
>
> Reported-by: Sashiko <sashiko-bot@kernel.org>
> Signed-off-by: Marc Zyngier <maz@kernel.org>
> Link: https://lore.kernel.org/r/20260607180815.85FBC1F00893@smtp.kernel.org
> ---
> arch/arm64/kvm/nested.c | 10 ++++++++--
> 1 file changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
> index 690b8e8564166..d11e36b3cfcc2 100644
> --- a/arch/arm64/kvm/nested.c
> +++ b/arch/arm64/kvm/nested.c
> @@ -1253,8 +1253,14 @@ int kvm_vcpu_allocate_vncr_tlb(struct kvm_vcpu *vcpu)
> if (!kvm_has_feat(vcpu->kvm, ID_AA64MMFR4_EL1, NV_frac, NV2_ONLY))
> return 0;
>
> - vcpu->arch.vncr_tlb = kzalloc_obj(*vcpu->arch.vncr_tlb,
> - GFP_KERNEL_ACCOUNT);
> + if (!vcpu->arch.vncr_tlb) {
> + struct vncr_tlb *vt = kzalloc_obj(*vcpu->arch.vncr_tlb,
> + GFP_KERNEL_ACCOUNT);
> +
> + scoped_guard(write_lock, &vcpu->kvm->mmu_lock)
> + vcpu->arch.vncr_tlb = vt;
> + }
(I am not familiar with this code at all, so apologies in advance if I
am making an idiot out of myself here)
IIUC, the point of holding the lock here is *not* to protect against
concurrent initialization, as in this case the NULL check needs to be
done under the lock.
Rather, the goal is to prevent re-ordering of zeroing from kzalloc and
the assignment to vcpu->arch.vncr_tlb, by depending on the barriers
provided by the lock. The lock is held by the readers so holding it here
conviently means we do not need to add any barriers to the readers.
Is my understanding correct?
If yes, I think the code looks confusing, at least to a layman like
myself. It initially seems like the lock protects against concurrent
initializations, but then the NULL check is not done again under the
lock. The goal of the lock is not clear without the original report.
Mayeb it's clearer to explicitly use barriers if the goal is preventing
reordering?
^ permalink raw reply
* Re: [PATCH v2 0/2] watchdog: sama5d4_wdt: Fix WDDIS handling for SAM9X60 and SAMA7G5
From: Guenter Roeck @ 2026-06-08 20:53 UTC (permalink / raw)
To: Balakrishnan.S, linux-watchdog
Cc: wim, alexandre.belloni, andrei.simion, linux-kernel,
linux-arm-kernel
In-Reply-To: <322c623a-0da8-4821-b0d9-ba2c96bf62ca@microchip.com>
Hi,
On 5/27/26 06:04, Balakrishnan.S@microchip.com wrote:
> Hi Wim,
>
> Gentle ping — both patches have been reviewed. Could this be queued for
> the next cycle?
>
Please check linux-next to determine if patches are queued for the next
commit window.
Thanks,
Guenter
> Thanks,
> Balakrishnan
>
> On 02/03/26 5:03 pm, Balakrishnan Sambath wrote:
>> The sama5d4_wdt driver hardcodes AT91_WDT_WDDIS (bit 15) for WDDIS
>> detection, which is incorrect for SAM9X60 and SAMA7G5 that use bit 12
>> (AT91_SAM9X60_WDDIS). This series fixes the detection by introducing
>> a per-device wddis_mask and documents the bit position difference in
>> the header.
>>
>> Changes in v2:
>> - Reorder patches: fix first, documentation second
>> - Drop patch 3/3, not needed with wddis_mask approach
>> - Keep AT91_SAM9X60_* register names, drop _LEGACY/_MODERN naming
>> - Limit header changes to WDDIS comments and datasheet references
>>
>> Balakrishnan Sambath (2):
>> watchdog: sama5d4_wdt: Fix WDDIS detection on SAM9X60 and SAMA7G5
>> watchdog: at91sam9_wdt.h: Document WDDIS bit position per SoC family
>>
>> drivers/watchdog/at91sam9_wdt.h | 6 +++--
>> drivers/watchdog/sama5d4_wdt.c | 48 +++++++++++++++------------------
>> 2 files changed, 25 insertions(+), 29 deletions(-)
>>
>
^ permalink raw reply
* Re: [RFC PATCH 2/2] firmware: arm_scmi: Add bus support for autoloading
From: Cristian Marussi @ 2026-06-08 20:53 UTC (permalink / raw)
To: Daniel Lezcano
Cc: Cristian Marussi, arm-scmi, guomin_chen, linux-arm-kernel,
peng.fan, quic_xinqzhan, sudeep.holla
In-Reply-To: <256c182e-a093-4bf5-a353-ca5c06eff489@oss.qualcomm.com>
On Mon, Jun 08, 2026 at 07:06:42PM +0200, Daniel Lezcano wrote:
>
> Hi Cristian,
>
> thanks for your answer
>
> On 6/8/26 18:51, Cristian Marussi wrote:
> > On Mon, Jun 08, 2026 at 04:51:03PM +0200, Daniel Lezcano wrote:
> > > On Mon, Feb 03, 2025 at 10:01:54AM +0000, Cristian Marussi wrote:
> > > > Emit proper MODALIAS uevents when SCMI devices are created and make sure
> > > > all the standard protocol devices are requested when the bus is
> > > > initialized.
> > > >
> > > > Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> > > > ---
> > >
> > > Hi Cristian,
Hi,
> > >
> >
> > Hi Daniel,
> >
> > nice to hear from you in the SCMI land :P
> >
> > > what is the status of this patch ?
> >
> > ....I'd say forgotten/abandoned...I worked on that a bit when I realized
> > only part of the stack was autoloaded...then it did NOT received much
> > love and then I forgot it....buried by other prios....
> >
> > Indeed I have still the local branch...but after a quick check I think
> > is the same as the RFC posted.
> >
> > bbd14b0f7733 firmware: arm_scmi: Add bus support for autoloading
> > 8d982393b505 firmware: arm_scmi: Generate aliases for SCMI modules
> > 383c127faa97 (scmi_vendors_autoload_V2) firmware: arm_scmi: Add aliases to transport modules
> > 00caa894bce2 firmware: arm_scmi: Add module aliases to i.MX vendor protocols
> > d900620c46bb firmware: arm_scmi: Support vendor protocol modules autoloading
> > 4fe57bbeb6dc firmware: arm_scmi: Allow transport properties for multiple instances
> > ad236e5a7f01 Linux 6.13-rc1
> >
> > ...where scmi_vendors_autoload_V2 is merged already...
>
> Actually, I'm puzzled.
>
> On our platform, until 7.1-rc1 we had to add a modprobe.d script to load the
> scmi_cpufreq driver because autoload was not suppported.
>
> Now (7.1-rc1) it seems to be automatically loaded.
>
mmm...I am not sure....but I have a memory to have seen this behaviour
with cpufreq...on some more full-fledged distro (not the usual bare
minimum deboostrapped thing...)...never fully investigated though...
> I imagined the autoload module has been added between 7.0 and 7.1, but the
> series you are mentioning is from 6.13.
Not sure when effectively merged BUT definitely NOT 7.0/7.1...
>
> What I am missing ?
Any chance that on a more complete kernel/distro some symbol dependencies
in modules.dep kicks in, unknowingly, that triggers the load of
scmi-coufreq ?
Not sure if it make any sense...since I miss anyway where the
SCMI-cpufreq <---> cpufreq-driver association is baked in with the current
module device tables...
Not so much of an help here...sorry.
Anyway, I may respin this in the future if there is some interest...unless
someone precedes me :D
Thanks
Cristian
^ permalink raw reply
* Re: [PATCHv2] dmaengine: st_fdma: simplify allocation
From: Rosen Penev @ 2026-06-08 20:52 UTC (permalink / raw)
To: Frank Li
Cc: dmaengine, Patrice Chotard, Vinod Koul, Frank Li, Kees Cook,
Gustavo A. R. Silva, moderated list:ARM/STI ARCHITECTURE,
open list,
open list:KERNEL HARDENING (not covered by other areas):Keyword:b__counted_by(_le|_be|_ptr)?b
In-Reply-To: <aibs9gb5M4-gbCFY@SMW015318>
On Mon, Jun 8, 2026 at 9:25 AM Frank Li <Frank.li@oss.nxp.com> wrote:
>
> On Sun, Jun 07, 2026 at 10:18:29PM -0700, Rosen Penev wrote:
>
> Nit: dmaengine: st_fdma: simplify allocation by using flexible array
that's in the description. Did it that was to not have it as long,
flexible array member is the proper terminology.
>
> Reviewed-by: Frank Li <Frank.Li@nxp.com>
>
> > Use a flexible array member to combine kzalloc and kcalloc to a single
> > allocation.
> >
> > Add __counted_by for extra runtime analysis. Assign counting variable
> > after allocation before any array accesses.
> >
> > Signed-off-by: Rosen Penev <rosenp@gmail.com>
> > ---
> >
^ permalink raw reply
* Re: [PATCH v2 1/7] dt-bindings: media: qcom: Add Shikra CAMSS compatible
From: Krzysztof Kozlowski @ 2026-06-08 20:46 UTC (permalink / raw)
To: Nihal Kumar Gupta
Cc: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Robert Foss, Andi Shyti, Bryan O'Donoghue,
Bjorn Andersson, Konrad Dybcio, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, linux-arm-msm,
linux-media, devicetree, linux-kernel, linux-i2c, imx,
linux-arm-kernel, Suresh Vankadara, Vikram Sharma
In-Reply-To: <20260608-shikra-camss-review-v2-1-ca1936bf1219@oss.qualcomm.com>
On Mon, Jun 08, 2026 at 07:36:38PM +0530, Nihal Kumar Gupta wrote:
> Shikra contains the same Camera Subsystem IP as QCM2290. Document the
> platform-specific compatible string, using qcom,qcm2290-camss as
> fallback.
>
> Unlike QCM2290, Shikra omits the CDM and OPE blocks, requiring only a
> single IOMMU context bank instead of four.
>
> Signed-off-by: Nihal Kumar Gupta <nihal.gupta@oss.qualcomm.com>
> ---
> .../devicetree/bindings/media/qcom,qcm2290-camss.yaml | 16 +++++++++++++---
> 1 file changed, 13 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/media/qcom,qcm2290-camss.yaml b/Documentation/devicetree/bindings/media/qcom,qcm2290-camss.yaml
> index 391d0f6f67ef5fdfea31dd3683477561516b1556..4f39eefb4898ebc22117407f26cfb4f41deb111b 100644
> --- a/Documentation/devicetree/bindings/media/qcom,qcm2290-camss.yaml
> +++ b/Documentation/devicetree/bindings/media/qcom,qcm2290-camss.yaml
> @@ -14,8 +14,11 @@ description:
>
> properties:
> compatible:
> - const: qcom,qcm2290-camss
> -
Do not remove blank lines.
> + oneOf:
> + - items:
> + - const: qcom,shikra-camss
> + - const: qcom,qcm2290-camss
> + - const: qcom,qcm2290-camss
> reg:
With this fixed:
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Best regards,
Krzysztof
^ permalink raw reply
* [PATCH v3 3/3] ARM: dts: ti: Add specific compatibles for SCM conf nodes
From: Krzysztof Kozlowski @ 2026-06-08 20:44 UTC (permalink / raw)
To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno, Jacky Huang,
Shan-Chun Hung, Geert Uytterhoeven, Magnus Damm, Heiko Stuebner,
Aaro Koskinen, Andreas Kemnade, Kevin Hilman, Roger Quadros,
Tony Lindgren
Cc: devicetree, linux-kernel, linux-arm-kernel, linux-mediatek,
linux-renesas-soc, linux-rockchip, linux-omap,
Krzysztof Kozlowski
In-Reply-To: <20260608-n-dt-bindings-simple-bus-syscon-v3-0-4eba9ec1212a@oss.qualcomm.com>
writing-bindings.rst rules dictate that "syscon" must come with a
specific compatible identifying the register layout. Add specific
compatibles for these devices.
This also allows to solve a different problem: "syscon" is contradictory
to "simple-bus". A system controller with registers having their own
functions is not really a trivial MMIO simple bus. These two cannot be
used together, unless listed as an exception.
Reviewed-by: Andreas Kemnade <andreas@kemnade.info>
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
Changes in v3:
1. s/ti,omap5-scm-conf/ti,omap5-sysc-padconf-global/ because it is more
appropriate (specific)
---
arch/arm/boot/dts/ti/omap/am33xx-l4.dtsi | 2 +-
arch/arm/boot/dts/ti/omap/am437x-l4.dtsi | 2 +-
arch/arm/boot/dts/ti/omap/dm814x.dtsi | 2 +-
arch/arm/boot/dts/ti/omap/dm816x.dtsi | 2 +-
arch/arm/boot/dts/ti/omap/dra7-l4.dtsi | 2 +-
arch/arm/boot/dts/ti/omap/omap2430.dtsi | 2 +-
arch/arm/boot/dts/ti/omap/omap3.dtsi | 2 +-
arch/arm/boot/dts/ti/omap/omap4-l4.dtsi | 2 +-
arch/arm/boot/dts/ti/omap/omap5-l4.dtsi | 6 +++---
9 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/arch/arm/boot/dts/ti/omap/am33xx-l4.dtsi b/arch/arm/boot/dts/ti/omap/am33xx-l4.dtsi
index 89d16fcc773e..1e09d2b48925 100644
--- a/arch/arm/boot/dts/ti/omap/am33xx-l4.dtsi
+++ b/arch/arm/boot/dts/ti/omap/am33xx-l4.dtsi
@@ -308,7 +308,7 @@ am33xx_pinmux: pinmux@800 {
};
scm_conf: scm_conf@0 {
- compatible = "syscon", "simple-bus";
+ compatible = "ti,am3352-scm-conf", "syscon", "simple-bus";
reg = <0x0 0x800>;
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/ti/omap/am437x-l4.dtsi b/arch/arm/boot/dts/ti/omap/am437x-l4.dtsi
index e08f356e71cb..30fcce33f4b7 100644
--- a/arch/arm/boot/dts/ti/omap/am437x-l4.dtsi
+++ b/arch/arm/boot/dts/ti/omap/am437x-l4.dtsi
@@ -301,7 +301,7 @@ am43xx_pinmux: pinmux@800 {
};
scm_conf: scm_conf@0 {
- compatible = "syscon", "simple-bus";
+ compatible = "ti,am4372-scm-conf", "syscon", "simple-bus";
reg = <0x0 0x800>;
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/ti/omap/dm814x.dtsi b/arch/arm/boot/dts/ti/omap/dm814x.dtsi
index 27d1f35a31fd..9e02bfa5c3a2 100644
--- a/arch/arm/boot/dts/ti/omap/dm814x.dtsi
+++ b/arch/arm/boot/dts/ti/omap/dm814x.dtsi
@@ -432,7 +432,7 @@ control: control@140000 {
ranges = <0 0x140000 0x20000>;
scm_conf: scm_conf@0 {
- compatible = "syscon", "simple-bus";
+ compatible = "ti,dm814-scm-conf", "syscon", "simple-bus";
reg = <0x0 0x800>;
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/ti/omap/dm816x.dtsi b/arch/arm/boot/dts/ti/omap/dm816x.dtsi
index a1e0e904e0f0..ee0090f7aa64 100644
--- a/arch/arm/boot/dts/ti/omap/dm816x.dtsi
+++ b/arch/arm/boot/dts/ti/omap/dm816x.dtsi
@@ -100,7 +100,7 @@ dm816x_pinmux: pinmux@800 {
/* Device Configuration Registers */
scm_conf: syscon@600 {
- compatible = "syscon", "simple-bus";
+ compatible = "ti,dm8168-scm-conf", "syscon", "simple-bus";
reg = <0x600 0x110>;
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/ti/omap/dra7-l4.dtsi b/arch/arm/boot/dts/ti/omap/dra7-l4.dtsi
index c8d325b0f57b..9df7648c4b79 100644
--- a/arch/arm/boot/dts/ti/omap/dra7-l4.dtsi
+++ b/arch/arm/boot/dts/ti/omap/dra7-l4.dtsi
@@ -64,7 +64,7 @@ scm: scm@0 {
ranges = <0 0 0x2000>;
scm_conf: scm_conf@0 {
- compatible = "syscon", "simple-bus";
+ compatible = "ti,dra7-scm-conf", "syscon", "simple-bus";
reg = <0x0 0x1400>;
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/ti/omap/omap2430.dtsi b/arch/arm/boot/dts/ti/omap/omap2430.dtsi
index 222613d2a4d1..01bd471f9223 100644
--- a/arch/arm/boot/dts/ti/omap/omap2430.dtsi
+++ b/arch/arm/boot/dts/ti/omap/omap2430.dtsi
@@ -50,7 +50,7 @@ omap2430_pmx: pinmux@30 {
};
scm_conf: scm_conf@270 {
- compatible = "syscon",
+ compatible = "ti,omap2-scm-conf", "syscon",
"simple-bus";
reg = <0x270 0x240>;
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/ti/omap/omap3.dtsi b/arch/arm/boot/dts/ti/omap/omap3.dtsi
index 959069e24730..447736d2e53c 100644
--- a/arch/arm/boot/dts/ti/omap/omap3.dtsi
+++ b/arch/arm/boot/dts/ti/omap/omap3.dtsi
@@ -116,7 +116,7 @@ omap3_pmx_core: pinmux@30 {
};
scm_conf: scm_conf@270 {
- compatible = "syscon", "simple-bus";
+ compatible = "ti,omap3-scm-conf", "syscon", "simple-bus";
reg = <0x270 0x330>;
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/ti/omap/omap4-l4.dtsi b/arch/arm/boot/dts/ti/omap/omap4-l4.dtsi
index 4c78a0b28fab..c1afc49f456c 100644
--- a/arch/arm/boot/dts/ti/omap/omap4-l4.dtsi
+++ b/arch/arm/boot/dts/ti/omap/omap4-l4.dtsi
@@ -681,7 +681,7 @@ omap4_pmx_core: pinmux@40 {
};
omap4_padconf_global: omap4_padconf_global@5a0 {
- compatible = "syscon",
+ compatible = "ti,omap4-sysc-padconf-global", "syscon",
"simple-bus";
reg = <0x5a0 0x170>;
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/ti/omap/omap5-l4.dtsi b/arch/arm/boot/dts/ti/omap/omap5-l4.dtsi
index 915870eb5c99..72849e1c95b0 100644
--- a/arch/arm/boot/dts/ti/omap/omap5-l4.dtsi
+++ b/arch/arm/boot/dts/ti/omap/omap5-l4.dtsi
@@ -96,8 +96,7 @@ omap5_pmx_core: pinmux@40 {
};
omap5_padconf_global: omap5_padconf_global@5a0 {
- compatible = "syscon",
- "simple-bus";
+ compatible = "ti,omap5-sysc-padconf-global", "syscon", "simple-bus";
reg = <0x5a0 0xec>;
#address-cells = <1>;
#size-cells = <1>;
@@ -2311,7 +2310,8 @@ omap5_scm_wkup_pad_conf: omap5_scm_wkup_pad_conf@da0 {
ranges = <0 0 0x60>;
scm_wkup_pad_conf: scm_conf@0 {
- compatible = "syscon", "simple-bus";
+ compatible = "ti,omap5-scm-wkup-conf",
+ "syscon", "simple-bus";
reg = <0x0 0x60>;
#address-cells = <1>;
#size-cells = <1>;
--
2.53.0
^ permalink raw reply related
* [PATCH v3 2/3] dt-bindings: mfd: syscon: Drop custom select for older dtschema
From: Krzysztof Kozlowski @ 2026-06-08 20:44 UTC (permalink / raw)
To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno, Jacky Huang,
Shan-Chun Hung, Geert Uytterhoeven, Magnus Damm, Heiko Stuebner,
Aaro Koskinen, Andreas Kemnade, Kevin Hilman, Roger Quadros,
Tony Lindgren
Cc: devicetree, linux-kernel, linux-arm-kernel, linux-mediatek,
linux-renesas-soc, linux-rockchip, linux-omap,
Krzysztof Kozlowski
In-Reply-To: <20260608-n-dt-bindings-simple-bus-syscon-v3-0-4eba9ec1212a@oss.qualcomm.com>
Older dtschema <2024.02 required custom select to avoid applying this
binding to anything having "syscon" compatible. That's not the case
anymore and this additional select has two headaches:
1. Duplicates all the compatibles listed in the schema.
2. Is error-prone, because it requires contributor to add the compatible
in two places, otherwise the schema will be silently ignored.
The select list already misses mentioning compatibles:
mediatek,mt8365-infracfg-nao and renesas,r9a08g046-lvds-cmn (with the
latter being reverted for different reasons).
This requires bumping minimum dtschema requirement to v2024.04, which
feels old enough to be a safe requirement.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
Changes in v3:
1. Bump dtschema requirement
Changes in v2:
1. New patch
---
Documentation/devicetree/bindings/Makefile | 2 +-
Documentation/devicetree/bindings/mfd/syscon.yaml | 116 ----------------------
2 files changed, 1 insertion(+), 117 deletions(-)
diff --git a/Documentation/devicetree/bindings/Makefile b/Documentation/devicetree/bindings/Makefile
index 7b668f7fd400..40c2094f47c2 100644
--- a/Documentation/devicetree/bindings/Makefile
+++ b/Documentation/devicetree/bindings/Makefile
@@ -6,7 +6,7 @@ DT_MK_SCHEMA ?= dt-mk-schema
DT_SCHEMA_LINT = $(shell which yamllint || \
echo "warning: python package 'yamllint' not installed, skipping" >&2)
-DT_SCHEMA_MIN_VERSION = 2023.9
+DT_SCHEMA_MIN_VERSION = 2024.4
PHONY += check_dtschema_version
check_dtschema_version:
diff --git a/Documentation/devicetree/bindings/mfd/syscon.yaml b/Documentation/devicetree/bindings/mfd/syscon.yaml
index 9c81010d5a74..b70018bf1bcf 100644
--- a/Documentation/devicetree/bindings/mfd/syscon.yaml
+++ b/Documentation/devicetree/bindings/mfd/syscon.yaml
@@ -19,122 +19,6 @@ description: |
maintainers:
- Lee Jones <lee@kernel.org>
-# Need a select with all compatibles listed for compatibility with older
-# dtschema (<2024.02), so this will not be selected for other schemas having
-# syscon fallback.
-select:
- properties:
- compatible:
- contains:
- enum:
- - airoha,en7581-pbus-csr
- - al,alpine-sysfabric-service
- - allwinner,sun8i-a83t-system-controller
- - allwinner,sun8i-h3-system-controller
- - allwinner,sun8i-v3s-system-controller
- - allwinner,sun50i-a64-system-controller
- - altr,l3regs
- - altr,sdr-ctl
- - amd,pensando-elba-syscon
- - amlogic,meson-mx-assist
- - amlogic,meson-mx-bootrom
- - amlogic,meson8-analog-top
- - amlogic,meson8b-analog-top
- - amlogic,meson8-pmu
- - amlogic,meson8b-pmu
- - apm,merlin-poweroff-mailbox
- - apm,mustang-poweroff-mailbox
- - apm,xgene-csw
- - apm,xgene-efuse
- - apm,xgene-mcb
- - apm,xgene-rb
- - apm,xgene-scu
- - atmel,sama5d2-sfrbu
- - atmel,sama5d3-nfc-io
- - atmel,sama5d3-sfrbu
- - atmel,sama5d4-sfrbu
- - axis,artpec6-syscon
- - brcm,cru-clkset
- - brcm,sr-cdru
- - brcm,sr-mhb
- - cirrus,ep7209-syscon1
- - cirrus,ep7209-syscon2
- - cirrus,ep7209-syscon3
- - cnxt,cx92755-uc
- - econet,en751221-chip-scu
- - freecom,fsg-cs2-system-controller
- - fsl,imx93-aonmix-ns-syscfg
- - fsl,imx93-wakeupmix-syscfg
- - fsl,ls1088a-reset
- - fsl,vf610-anatop
- - fsl,vf610-mscm-cpucfg
- - hisilicon,dsa-subctrl
- - hisilicon,hi6220-sramctrl
- - hisilicon,hip04-ppe
- - hisilicon,pcie-sas-subctrl
- - hisilicon,peri-subctrl
- - hpe,gxp-sysreg
- - loongson,ls1b-syscon
- - loongson,ls1c-syscon
- - lsi,axxia-syscon
- - marvell,armada-3700-cpu-misc
- - marvell,armada-3700-nb-pm
- - marvell,armada-3700-avs
- - marvell,armada-3700-usb2-host-device-misc
- - marvell,armada-3700-usb2-host-misc
- - marvell,dove-global-config
- - mediatek,mt2701-pctl-a-syscfg
- - mediatek,mt2712-pctl-a-syscfg
- - mediatek,mt6397-pctl-pmic-syscfg
- - mediatek,mt7981-topmisc
- - mediatek,mt7988-topmisc
- - mediatek,mt8135-pctl-a-syscfg
- - mediatek,mt8135-pctl-b-syscfg
- - mediatek,mt8173-pctl-a-syscfg
- - mediatek,mt8365-syscfg
- - microchip,lan966x-cpu-syscon
- - microchip,mpfs-control-scb
- - microchip,mpfs-sysreg-scb
- - microchip,sam9x60-sfr
- - microchip,sama7d65-ddr3phy
- - microchip,sama7d65-sfrbu
- - microchip,sama7g5-ddr3phy
- - mscc,ocelot-cpu-syscon
- - mstar,msc313-pmsleep
- - nuvoton,ma35d1-sys
- - nuvoton,wpcm450-shm
- - nxp,s32g2-gpr
- - nxp,s32g3-gpr
- - qcom,apq8064-mmss-sfpb
- - qcom,apq8064-sps-sic
- - rockchip,px30-qos
- - rockchip,rk3036-qos
- - rockchip,rk3066-qos
- - rockchip,rk3128-qos
- - rockchip,rk3228-qos
- - rockchip,rk3288-qos
- - rockchip,rk3368-qos
- - rockchip,rk3399-qos
- - rockchip,rk3528-qos
- - rockchip,rk3562-qos
- - rockchip,rk3568-qos
- - rockchip,rk3576-qos
- - rockchip,rk3588-qos
- - rockchip,rv1126-qos
- - st,spear1340-misc
- - stericsson,nomadik-pmu
- - starfive,jh7100-sysmain
- - ti,am62-opp-efuse-table
- - ti,am62-usb-phy-ctrl
- - ti,am625-dss-oldi-io-ctrl
- - ti,am62p-cpsw-mac-efuse
- - ti,am654-dss-oldi-io-ctrl
- - ti,j784s4-acspcie-proxy-ctrl
- - ti,j784s4-pcie-ctrl
- - ti,keystone-pllctrl
- required:
- - compatible
-
properties:
compatible:
oneOf:
--
2.53.0
^ permalink raw reply related
* [PATCH v3 1/3] dt-bindings: mfd: syscon: Disallow simple-bus with syscon
From: Krzysztof Kozlowski @ 2026-06-08 20:44 UTC (permalink / raw)
To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno, Jacky Huang,
Shan-Chun Hung, Geert Uytterhoeven, Magnus Damm, Heiko Stuebner,
Aaro Koskinen, Andreas Kemnade, Kevin Hilman, Roger Quadros,
Tony Lindgren
Cc: devicetree, linux-kernel, linux-arm-kernel, linux-mediatek,
linux-renesas-soc, linux-rockchip, linux-omap,
Krzysztof Kozlowski
In-Reply-To: <20260608-n-dt-bindings-simple-bus-syscon-v3-0-4eba9ec1212a@oss.qualcomm.com>
"syscon" is a system controller with registers having their own
functions, thus not really a trivial MMIO simple bus. "simple-bus" on
the other hand is just a bus on which multiple devices sit and the
"simple" means no functions are allowed here.
Combination of both "syscon" and "simple-bus" is abuse of DT for easier
instantiating of Linux device drivers so add a schema to disallow that.
Unfortunately there are a few old cases of that patterns, so add
exceptions:
1. "cznic,turris1x-cpld" and "img,pistachio-cr-periph" are already used
in upstream DTS.
2. TI has several DTSI with a child of SCM device (e.g. "ti,am3-scm")
using "syscon" and "simple-bus" but without a dedicated compatible
documented anywhere. Add new compatibles for such cases.
Additionally, add comments around code enforcing two or three
compatibles: it is similar safeguard detecting incorrect bindings.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
Changes in v3:
1. s/ti,omap5-scm-conf/ti,omap5-sysc-padconf-global/ because it is more
appropriate (specific)
2. Add comments, why simple-mfd+syscon has dedicated if:then:
Changes in v2:
1. Complete patch. I accidentally sent only part of it, built on top of
internal WIP which I forgot to squash.
I received Ack from Rob, but change is significant, so please kindly
re-review.
---
.../devicetree/bindings/mfd/syscon-common.yaml | 34 ++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/Documentation/devicetree/bindings/mfd/syscon-common.yaml b/Documentation/devicetree/bindings/mfd/syscon-common.yaml
index 14a08e7bc8bd..2d5eef5add54 100644
--- a/Documentation/devicetree/bindings/mfd/syscon-common.yaml
+++ b/Documentation/devicetree/bindings/mfd/syscon-common.yaml
@@ -32,6 +32,7 @@ properties:
compatible:
contains:
const: syscon
+ # Always require a specific compatible for syscon
minItems: 2
maxItems: 5 # Should be enough
@@ -52,11 +53,44 @@ allOf:
contains:
const: simple-mfd
then:
+ # Always require a specific compatible for syscon with simple-mfd
properties:
compatible:
minItems: 3
maxItems: 5
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: simple-bus
+ then:
+ # simple-bus conflicts with syscon - if a device is a system controller
+ # with miscellaneous registers, then it has at least one dedicated
+ # function thus it is not a simple bus. Allow existing exceptions.
+ if:
+ properties:
+ compatible:
+ not:
+ contains:
+ # This list CANNOT grow
+ enum:
+ - cznic,turris1x-cpld
+ - img,pistachio-cr-periph
+ - ti,am3352-scm-conf
+ - ti,am4372-scm-conf
+ - ti,dm814-scm-conf
+ - ti,dm8168-scm-conf
+ - ti,dra7-scm-conf
+ - ti,omap2-scm-conf
+ - ti,omap3-scm-conf
+ - ti,omap4-sysc-padconf-global
+ - ti,omap5-scm-wkup-conf
+ - ti,omap5-sysc-padconf-global
+ then:
+ required:
+ - incorrect-usage-of-simple-bus-and-syscon
+
additionalProperties: true
examples:
--
2.53.0
^ permalink raw reply related
* [PATCH v3 0/3] dt-bindings: mfd: syscon: Tighten checks
From: Krzysztof Kozlowski @ 2026-06-08 20:44 UTC (permalink / raw)
To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno, Jacky Huang,
Shan-Chun Hung, Geert Uytterhoeven, Magnus Damm, Heiko Stuebner,
Aaro Koskinen, Andreas Kemnade, Kevin Hilman, Roger Quadros,
Tony Lindgren
Cc: devicetree, linux-kernel, linux-arm-kernel, linux-mediatek,
linux-renesas-soc, linux-rockchip, linux-omap,
Krzysztof Kozlowski
Changes in v3:
- Drop patch #2:
dt-bindings: mfd: syscon: Drop unneeded case for syscon + simple-mfd
- Bump dtschema requirement
- Link to v2: https://patch.msgid.link/20260608-n-dt-bindings-simple-bus-syscon-v2-0-0203e6c249dc@oss.qualcomm.com
Changes in v2:
1. New patches #2 and #3
1. Add missing part of patch #1, thus not adding Rob's Ack.
https://lore.kernel.org/all/20260531110404.12768-3-krzysztof.kozlowski@oss.qualcomm.com/
I tested dt_binding_check and dtbs_check for arm, arm64 and riscv and I
think I did not introduce new dtbs_check warnings. Old code anyway has
multiple abuses of syscon, thus tricky to judge for arm at least.
Best regards,
Krzysztof
---
Krzysztof Kozlowski (3):
dt-bindings: mfd: syscon: Disallow simple-bus with syscon
dt-bindings: mfd: syscon: Drop custom select for older dtschema
ARM: dts: ti: Add specific compatibles for SCM conf nodes
Documentation/devicetree/bindings/Makefile | 2 +-
.../devicetree/bindings/mfd/syscon-common.yaml | 34 ++++++
Documentation/devicetree/bindings/mfd/syscon.yaml | 116 ---------------------
arch/arm/boot/dts/ti/omap/am33xx-l4.dtsi | 2 +-
arch/arm/boot/dts/ti/omap/am437x-l4.dtsi | 2 +-
arch/arm/boot/dts/ti/omap/dm814x.dtsi | 2 +-
arch/arm/boot/dts/ti/omap/dm816x.dtsi | 2 +-
arch/arm/boot/dts/ti/omap/dra7-l4.dtsi | 2 +-
arch/arm/boot/dts/ti/omap/omap2430.dtsi | 2 +-
arch/arm/boot/dts/ti/omap/omap3.dtsi | 2 +-
arch/arm/boot/dts/ti/omap/omap4-l4.dtsi | 2 +-
arch/arm/boot/dts/ti/omap/omap5-l4.dtsi | 6 +-
12 files changed, 46 insertions(+), 128 deletions(-)
---
base-commit: 78f5e68a8d0a1123dd1b007688ccf0e6876a5c15
change-id: 20260608-n-dt-bindings-simple-bus-syscon-e39df408a02d
Best regards,
--
Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCHv2 0/3] watchdog: sama5d4: fix IRQ and timeout bugs, use platform_get_irq_optional
From: Rosen Penev @ 2026-06-08 20:42 UTC (permalink / raw)
To: Nicolas Ferre
Cc: linux-watchdog, Alexandre Belloni, Claudiu Beznea,
Wim Van Sebroeck, Guenter Roeck,
moderated list:ARM/Microchip (AT91) SoC support, open list
In-Reply-To: <10b595d3-d44b-4fbb-a834-a94b154a0381@microchip.com>
On Mon, Jun 8, 2026 at 1:38 PM Nicolas Ferre
<nicolas.ferre@microchip.com> wrote:
>
> On 08/06/2026 at 13:09, Rosen Penev wrote:
> > EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> >
> > This series fixes three issues in the sama5d4 watchdog driver:
> >
> > Patch 1: Return IRQ_NONE when the status register indicates no watchdog
> > interrupt is pending, and pass the configured timeout (not the hardcoded
> > default) to sama5d4_wdt_init().
> >
> > Patch 2: Replace irq_of_parse_and_map() with platform_get_irq_optional()
> > for simpler error handling and EPROBE_DEFER support.
> >
> > Patch 3: Move platform_set_drvdata() before devm_request_irq() to prevent
> > a NULL pointer dereference in the interrupt handler if the shared System
> > IRQ fires immediately after registration.
> >
> > v2: address sashiko review
>
> Rosen,
>
> I'd like to hear how these issues where found and how the patches were
> tested.
They were not. Maintainer has explicitly asked me to fix issues
discovered by https://sashiko.dev
I originally only had patch 2, which is true of multiple places.
>
> Best regards,
> Nicolas
>
> > Rosen Penev (3):
> > watchdog: sama5d4: fix shared IRQ and hardcoded timeout issues
> > watchdog: sama5d4: use platform_get_irq_optional()
> > watchdog: sama5d4: fix NULL deref in irq handler
> >
> > drivers/watchdog/sama5d4_wdt.c | 32 +++++++++++++++++---------------
> > 1 file changed, 17 insertions(+), 15 deletions(-)
> >
> > --
> > 2.54.0
> >
>
^ permalink raw reply
* Re: [PATCHv2 0/3] watchdog: sama5d4: fix IRQ and timeout bugs, use platform_get_irq_optional
From: Nicolas Ferre @ 2026-06-08 20:38 UTC (permalink / raw)
To: Rosen Penev, linux-watchdog
Cc: Alexandre Belloni, Claudiu Beznea, Wim Van Sebroeck,
Guenter Roeck, moderated list:ARM/Microchip (AT91) SoC support,
open list
In-Reply-To: <20260608200933.18669-1-rosenp@gmail.com>
On 08/06/2026 at 13:09, Rosen Penev wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
>
> This series fixes three issues in the sama5d4 watchdog driver:
>
> Patch 1: Return IRQ_NONE when the status register indicates no watchdog
> interrupt is pending, and pass the configured timeout (not the hardcoded
> default) to sama5d4_wdt_init().
>
> Patch 2: Replace irq_of_parse_and_map() with platform_get_irq_optional()
> for simpler error handling and EPROBE_DEFER support.
>
> Patch 3: Move platform_set_drvdata() before devm_request_irq() to prevent
> a NULL pointer dereference in the interrupt handler if the shared System
> IRQ fires immediately after registration.
>
> v2: address sashiko review
Rosen,
I'd like to hear how these issues where found and how the patches were
tested.
Best regards,
Nicolas
> Rosen Penev (3):
> watchdog: sama5d4: fix shared IRQ and hardcoded timeout issues
> watchdog: sama5d4: use platform_get_irq_optional()
> watchdog: sama5d4: fix NULL deref in irq handler
>
> drivers/watchdog/sama5d4_wdt.c | 32 +++++++++++++++++---------------
> 1 file changed, 17 insertions(+), 15 deletions(-)
>
> --
> 2.54.0
>
^ permalink raw reply
* Re: [GIT PULL] coresight: Updates for Linux v7.2
From: Greg KH @ 2026-06-08 19:37 UTC (permalink / raw)
To: Suzuki K Poulose
Cc: linux-arm-kernel, coresight, james.clark, leo.yan, mike.leach
In-Reply-To: <20260608125424.283998-1-suzuki.poulose@arm.com>
On Mon, Jun 08, 2026 at 01:54:24PM +0100, Suzuki K Poulose wrote:
> Hi Greg
>
> Please find the updates for CoreSight self hosted tracing subsystem targeting
> Linux v7.2
>
> Kindly pull,
>
> Suzuki
>
> ---
>
>
> The following changes since commit 7fd2df204f342fc17d1a0bfcd474b24232fb0f32:
>
> Linux 7.1-rc2 (2026-05-03 14:21:25 -0700)
>
> are available in the Git repository at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/coresight/linux.git tags/coresight-next-v7.2
Pulled and pushed out, thanks.
greg k-h
^ permalink raw reply
* Re: -next boot failures during KVM setup
From: Marc Zyngier @ 2026-06-08 20:18 UTC (permalink / raw)
To: Mark Brown, Will Deacon, Catalin Marinas, Ard Biesheuvel
Cc: Oliver Upton, Aishwarya.TCV, linux-arm-kernel
In-Reply-To: <aicVyebkEMs6w6UV@sirena.co.uk>
[+ Will, Catalin, Ard]
On Mon, 08 Jun 2026 20:19:37 +0100,
Mark Brown <broonie@kernel.org> wrote:
>
> I'm seeing boot failures on a range of physical arm64 platforms in
> today's -next. Turning on earlycon it looks like we're getting bad
> pointer dereferences during KVM initialisation:
>
> [ 0.728923] kvm [1]: nv: 570 coarse grained trap handlers
> [ 0.735138] kvm [1]: nv: 710 fine grained trap handlers
> [ 0.741326] kvm [1]: IPA Size Limit: 40 bits
> [ 0.748840] Unable to handle kernel paging request at virtual address ffff00000478e000
That really doesn't look like a duff pointer.
> [ 0.757027] Mem abort info:
> [ 0.759917] ESR = 0x0000000096000147
Translation fault, level 3. My take is that something is getting
unmapped.
> [ 0.763772] EC = 0x25: DABT (current EL), IL = 32 bits
> [ 0.851526] pc : dcache_clean_inval_poc+0x24/0x48
> [ 0.856367] lr : kvm_arm_init+0xbb0/0x13f0
> ...
>
> [ 0.937120] Call trace:
> [ 0.939628] dcache_clean_inval_poc+0x24/0x48 (P)
> [ 0.944457] do_one_initcall+0x60/0x1d4
> [ 0.948393] kernel_init_freeable+0x250/0x2d8
>
> https://lava.sirena.org.uk/scheduler/job/2849583#L848
>
> (with other platforms I've got earlycon logs showing basically the same
> thing). I have some bisects but they seem to have been confused by
> earlier driver core issues, I've tweaked to try to avoid that and am
> retrying. FVP and qemu seem unaffected:
>
> https://lava.sirena.org.uk/scheduler/job/2848374#L888
> https://lava.sirena.org.uk/scheduler/job/2848966#L447
>
> The affected platforms thus far are all SMP Cortex A53/5 systems, but
> that's the vast majority of my lab. They have both GICv3 and GICv2.
I've reproduced with -next on an A72 platform. But it doesn't happen
with kvmarm/next on its own. So it is likely something coming from
another tree that messes up with CMOs, or .
The stack trace here is slightly better:
[ 0.099138] Unable to handle kernel paging request at virtual address ffff0023d9ead000
[ 0.099141] Mem abort info:
[ 0.099142] ESR = 0x0000000096000147
[ 0.099144] EC = 0x25: DABT (current EL), IL = 32 bits
[ 0.099146] SET = 0, FnV = 0
[ 0.099148] EA = 0, S1PTW = 0
[ 0.099150] FSC = 0x07: level 3 translation fault
[ 0.099151] Data abort info:
[ 0.099153] ISV = 0, ISS = 0x00000147, ISS2 = 0x00000000
[ 0.099155] CM = 1, WnR = 1, TnD = 0, TagAccess = 0
[ 0.099157] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
[ 0.099159] swapper pgtable: 4k pages, 48-bit VAs, pgdp=000000245983b000
[ 0.099162] [ffff0023d9ead000] pgd=18000027fffff403, p4d=18000027fffff403, pud=18000027ffffe403, pmd=18000027fffed403, pte=00e8002459eadf06
[ 0.099173] Internal error: Oops: 0000000096000147 [#1] SMP
[ 0.582137] Freeing initrd memory: 29068K
[ 2.025400] Modules linked in:
[ 2.028447] CPU: 2 UID: 0 PID: 1 Comm: swapper/0 Not tainted 7.1.0-rc7-next-20260608 #6265 PREEMPT
[ 2.037482] Hardware name: SolidRun Ltd. SolidRun CEX7 Platform, BIOS EDK II May 30 2024
[ 2.045559] pstate: 80000005 (Nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[ 2.052510] pc : dcache_clean_inval_poc+0x24/0x48
[ 2.057210] lr : kvm_hyp_init_symbols+0x370/0x388
[ 2.061904] sp : ffff80008009bd00
[ 2.065206] x29: ffff80008009bd00 x28: 0000000000000000 x27: 0000002022116000
[ 2.072332] x26: ffff0020232967f0 x25: 00000020a2116000 x24: 00000000000038b0
[ 2.079458] x23: 0000000000000030 x22: ffffc7dc575880c8 x21: ffffc7dc57948fb0
[ 2.086584] x20: 0000000000000001 x19: 0000000001002222 x18: 00000000ffffffff
[ 2.093709] x17: 000000007a3345b6 x16: 0000000073a611dd x15: 0000000000000000
[ 2.100835] x14: 0000000000000000 x13: 0000000000000000 x12: fffffffffffff800
[ 2.107960] x11: 00000000000007ff x10: 0000000000000000 x9 : fffffffffffff800
[ 2.115086] x8 : 00000000000007ff x7 : 0000000000000000 x6 : ffffc7dc5740af58
[ 2.122211] x5 : 0000000080000000 x4 : ffffc7b87de00000 x3 : 000000000000003f
[ 2.129336] x2 : 0000000000000040 x1 : ffff0023d9eaf000 x0 : ffff0023d9ead000
[ 2.136462] Call trace:
[ 2.138896] dcache_clean_inval_poc+0x24/0x48 (P)
[ 2.143592] init_hyp_mode+0x644/0x960
[ 2.147333] kvm_arm_init+0x128/0x280
[ 2.150987] do_one_initcall+0x4c/0x458
[ 2.154813] kernel_init_freeable+0x1f4/0x2a0
[ 2.159161] kernel_init+0x2c/0x150
[ 2.162642] ret_from_fork+0x10/0x20
[ 2.166210] Code: 9ac32042 d1000443 8a230000 d503201f (d50b7e20)
[ 2.172292] ---[ end trace 0000000000000000 ]---
[ 2.176958] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b
[ 2.184608] SMP: stopping secondary CPUs
[ 2.188523] Kernel Offset: 0x47dbd5dc0000 from 0xffff800080000000
[ 2.194604] PHYS_OFFSET: 0x80000000
[ 2.198080] CPU features: 0x04000000,804b0008,00040001,0400421b
[ 2.203988] Memory Limit: none
[ 2.207031] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]---
This points to the following code in kvm_hyp_init_symbols():
<quote>
/*
* Flush entire BSS since part of its data containing init symbols is read
* while the MMU is off.
*/
kvm_flush_dcache_to_poc(kvm_ksym_ref(__hyp_bss_start),
kvm_ksym_ref(__hyp_bss_end) - kvm_ksym_ref(__hyp_bss_start))
</quote>
which I suspect is related to some of the new BSS related code in
arm64/for-next/mm.
Ard, does this ring a bell?
Thanks,
M.
--
Jazz isn't dead. It just smells funny.
^ 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