* [PATCH v4 phy-next 0/9] RCW override for 10G Lynx dynamic protocol reconfiguration
@ 2026-07-21 23:15 Vladimir Oltean
2026-07-21 23:15 ` [PATCH v4 phy-next 1/9] soc: fsl: guts: perform fsl_guts_init() error teardown in reverse order of setup Vladimir Oltean
` (8 more replies)
0 siblings, 9 replies; 16+ messages in thread
From: Vladimir Oltean @ 2026-07-21 23:15 UTC (permalink / raw)
To: linux-phy
Cc: devicetree, linuxppc-dev, linux-arm-kernel, Ioana Ciornei,
Vinod Koul, Neil Armstrong, Tanjeff Moos,
Christophe Leroy (CS GROUP), Michael Walle, Shawn Guo, Frank Li,
linux-kernel, Conor Dooley, Krzysztof Kozlowski, Rob Herring
Previous set "New Generic PHY driver for Lynx 10G SerDes":
https://lore.kernel.org/linux-phy/20260610151952.2141019-1-vladimir.oltean@nxp.com/
introduced the 10G Lynx SerDes driver with a reduced functionality set.
Namely, only minor protocol changes are supported (1GbE <-> 2.5GbE).
The major protocol changes need a procedure named RCW override,
explained in more detail in commits 6/8 and 7/8.
This series adds kernel and device tree binding support for RCW
override, completing the SerDes PHY driver functionality.
Two components are involved:
- drivers/soc/fsl/guts.c (binding is fsl,layerscape-dcfg.yaml) - Device
Configuration Unit, this is API provider for the SerDes driver to
request RCW override depending on SoC
- drivers/phy/freescale/phy-fsl-lynx-10g.c - SerDes PHY driver, this is
API consumer
The guts driver probes on DCFG blocks from multiple Freescale SoC
generations:
- MPC85xx, BSC and QorIQ (PowerPC) are all covered by the
Documentation/devicetree/bindings/soc/fsl/guts.txt schema
- Layerscape (Arm) is covered by
Documentation/devicetree/bindings/soc/fsl/fsl,layerscape-dcfg.yaml
It is ultimately the same hardware block, just that (from what I can
tell) the Layerscape nodes are also compatible with syscon, and PowerPC
aren't.
RCW override has only been validated on select Layerscape SoCs, so
converting guts.txt to a PowerPC schema is out of scope for this
series - we don't even touch that (just in case it gets asked).
Using syscon to map the DCFG_DCSR register block in the Lynx SerDes
driver instead of creating this guts <-> lynx API was considered, but
because the RCW procedure is SoC-specific, it was ruled out for
polluting the SerDes driver. The guts driver is all about SoC awareness
anyway, and it offers some abstraction of all the gory details.
Changes since v3:
- new patch (1/9) to improve the fsl_guts_init() error path. The entire
patch set is adapted to use the new convention.
- patch 8/9: avoid accessing an invalid soc.rcwcr_lock if
fsl_guts_lane_set_mode() would be called too early
- patch 8/9: fix serdes block and lane count bounds
- patch 8/9 and 9/9: reimplement LS2088A RCW override in a way that is
self-contained within the guts driver (based on reading and decoding
RCWSR29[SRDS_PRTCL_S1]). Only a subset of SRDS_PRTCL_S1 values is
supported for RCW override, due to availabilty of hardware to test on
my side. Notably, protocols with XAUI and QSGMII are deliberately
omitted from the SerDes table because only testing can show whether
these protocols require RCWSR30_SRDS_CLK_SEL set to GMII or XGMII.
This new method completely replaces fsl_guts_lane_init(), and has the
advantage of also figuring out the initial protocol of unmanaged lanes,
thereby not breaking them on RCW overrides.
v3 at:
https://lore.kernel.org/linux-phy/20260720133642.136324-1-vladimir.oltean@nxp.com/
Changes since v2:
- fix error handling in fsl_guts_init() and make sure that all newly
introduced RCW override API functions fail if fsl_guts_init() failed.
- replace __bf_shf() use with __ffs()
- use read_poll_timeout_atomic() in fsl_guts_rcw_rmw() to clarify that
DCFG_DCSR writes are supposed to reflect back in DCFG_CCSR
- only operate on lanes on which fsl_guts_lane_init() was called in
ls2088a_serdes_init_rcwcr()
- put parentheses around (lane) in LS1088A_RCWSR29_SRDS_PRTCL_S1_LNn()
and LS1088A_RCWSR30_SRDS_PRTCL_S2_LNn() macro expressions
v2 at:
https://lore.kernel.org/linux-phy/20260612210859.266759-8-vladimir.oltean@nxp.com/
Changes since v1:
- add Conor's review tag on 6/8
- update email addresses of DT maintainers
- drop DT maintainers from explicit CC on patch 7/8
- keep devicetree@vger.kernel.org CCed on entire series
- include missing <linux/bitfield.h> in patch 7/8
- namespace SRDS_PRTCL values for LS1046A and LS1088A, even if they are
the same. For LS1028A (not covered here) they are not.
- prefix SRDS_CLK_SEL_{GMII,XGMII} with LS2088A_
- reorder alphanumerically (LS1046A should come before LS1088A)
Change logs also in individual patches.
v1 at:
https://lore.kernel.org/linux-phy/20260611193940.44416-1-vladimir.oltean@nxp.com/
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Rob Herring <robh@kernel.org>
Ioana Ciornei (4):
soc: fsl: guts: use a macro to encode the DCFG CCSR space
soc: fsl: guts: add a global structure to hold state
soc: fsl: guts: add a central fsl_guts_read() function
soc: fsl: guts: make it easier to determine on which SoC we are
running
Vladimir Oltean (5):
soc: fsl: guts: perform fsl_guts_init() error teardown in reverse
order of setup
soc: fsl: guts: make fsl_soc_data available after fsl_guts_init()
dt-bindings: fsl: layerscape-dcfg: define DCFG_DCSR region
soc: fsl: guts: implement the RCW override procedure
phy: lynx-10g: use RCW override procedure for dynamic protocol change
.../bindings/soc/fsl/fsl,layerscape-dcfg.yaml | 15 +-
drivers/phy/freescale/Kconfig | 1 +
drivers/phy/freescale/phy-fsl-lynx-10g.c | 23 +-
drivers/soc/fsl/guts.c | 528 ++++++++++++++++--
include/linux/fsl/guts.h | 18 +-
5 files changed, 532 insertions(+), 53 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v4 phy-next 1/9] soc: fsl: guts: perform fsl_guts_init() error teardown in reverse order of setup
2026-07-21 23:15 [PATCH v4 phy-next 0/9] RCW override for 10G Lynx dynamic protocol reconfiguration Vladimir Oltean
@ 2026-07-21 23:15 ` Vladimir Oltean
2026-07-22 7:18 ` Michael Walle
2026-07-22 9:15 ` Ioana Ciornei
2026-07-21 23:15 ` [PATCH v4 phy-next 2/9] soc: fsl: guts: use a macro to encode the DCFG CCSR space Vladimir Oltean
` (7 subsequent siblings)
8 siblings, 2 replies; 16+ messages in thread
From: Vladimir Oltean @ 2026-07-21 23:15 UTC (permalink / raw)
To: linux-phy
Cc: devicetree, linuxppc-dev, linux-arm-kernel, Ioana Ciornei,
Vinod Koul, Neil Armstrong, Tanjeff Moos,
Christophe Leroy (CS GROUP), Michael Walle, Shawn Guo, Frank Li,
linux-kernel
fsl_guts_init() is about to get much more complicated and the central
error handling procedure cannot scale in its current design, unless we
add a lot of "if" conditions to detect what has been allocated and what
hasn't.
Currently the code relies on the fact that kfree(NULL) is safe, but this
doesn't scale to the case where "soc_dev_attr" itself is NULL, because
this would dereference "soc_dev_attr->family" and friends of a NULL
pointer.
Convert to the more typical error handling pattern where the teardown is
in the strict reverse order of setup, and a teardown step is only called
if its corresponding setup step was executed.
At the same time, maintain the optionality of soc_dev_attr->serial_number
by not checking whether that kasprintf() has returned NULL. In the error
path, kfree(NULL) is safe, so we don't need to add an "if" condition for
it. Michael Walle has confirmed that ignoring the error was intentional,
and we preserve that:
https://lore.kernel.org/linux-phy/DK44809N7Y8I.J2Z3U4N32H0Q@kernel.org/
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v3->v4: patch is new
---
drivers/soc/fsl/guts.c | 33 ++++++++++++++++++++-------------
1 file changed, 20 insertions(+), 13 deletions(-)
diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
index 9bee7baec2b9..453456f31800 100644
--- a/drivers/soc/fsl/guts.c
+++ b/drivers/soc/fsl/guts.c
@@ -227,17 +227,23 @@ static int __init fsl_guts_init(void)
} else {
soc_dev_attr->family = kasprintf(GFP_KERNEL, "QorIQ");
}
- if (!soc_dev_attr->family)
- goto err_nomem;
+ if (!soc_dev_attr->family) {
+ ret = -ENOMEM;
+ goto err_free_soc_dev_attr;
+ }
soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "svr:0x%08x", svr);
- if (!soc_dev_attr->soc_id)
- goto err_nomem;
+ if (!soc_dev_attr->soc_id) {
+ ret = -ENOMEM;
+ goto err_free_family;
+ }
soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d.%d",
(svr >> 4) & 0xf, svr & 0xf);
- if (!soc_dev_attr->revision)
- goto err_nomem;
+ if (!soc_dev_attr->revision) {
+ ret = -ENOMEM;
+ goto err_free_soc_id;
+ }
if (soc_data)
soc_uid = fsl_guts_get_soc_uid(soc_data->sfp_compat,
@@ -249,7 +255,7 @@ static int __init fsl_guts_init(void)
soc_dev = soc_device_register(soc_dev_attr);
if (IS_ERR(soc_dev)) {
ret = PTR_ERR(soc_dev);
- goto err;
+ goto err_free_serial_number;
}
pr_info("Machine: %s\n", soc_dev_attr->machine);
@@ -259,13 +265,14 @@ static int __init fsl_guts_init(void)
return 0;
-err_nomem:
- ret = -ENOMEM;
-err:
- kfree(soc_dev_attr->family);
- kfree(soc_dev_attr->soc_id);
- kfree(soc_dev_attr->revision);
+err_free_serial_number:
kfree(soc_dev_attr->serial_number);
+ kfree(soc_dev_attr->revision);
+err_free_soc_id:
+ kfree(soc_dev_attr->soc_id);
+err_free_family:
+ kfree(soc_dev_attr->family);
+err_free_soc_dev_attr:
kfree(soc_dev_attr);
return ret;
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v4 phy-next 2/9] soc: fsl: guts: use a macro to encode the DCFG CCSR space
2026-07-21 23:15 [PATCH v4 phy-next 0/9] RCW override for 10G Lynx dynamic protocol reconfiguration Vladimir Oltean
2026-07-21 23:15 ` [PATCH v4 phy-next 1/9] soc: fsl: guts: perform fsl_guts_init() error teardown in reverse order of setup Vladimir Oltean
@ 2026-07-21 23:15 ` Vladimir Oltean
2026-07-21 23:15 ` [PATCH v4 phy-next 3/9] soc: fsl: guts: add a global structure to hold state Vladimir Oltean
` (6 subsequent siblings)
8 siblings, 0 replies; 16+ messages in thread
From: Vladimir Oltean @ 2026-07-21 23:15 UTC (permalink / raw)
To: linux-phy
Cc: devicetree, linuxppc-dev, linux-arm-kernel, Ioana Ciornei,
Vinod Koul, Neil Armstrong, Tanjeff Moos,
Christophe Leroy (CS GROUP), Michael Walle, Shawn Guo, Frank Li,
linux-kernel
From: Ioana Ciornei <ioana.ciornei@nxp.com>
Instead of using a hardcoded value when iomapping the DCFG CCSR space,
add a new macro for it. The code will be easier to follow this way,
especially when we add support for the DCFG DCSR space as well.
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v1->v4: none
---
drivers/soc/fsl/guts.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
index 453456f31800..b97eb80cea95 100644
--- a/drivers/soc/fsl/guts.c
+++ b/drivers/soc/fsl/guts.c
@@ -14,6 +14,8 @@
#include <linux/platform_device.h>
#include <linux/fsl/guts.h>
+#define DCFG_CCSR 0
+
struct fsl_soc_die_attr {
char *die;
u32 svr;
@@ -197,7 +199,7 @@ static int __init fsl_guts_init(void)
return 0;
soc_data = match->data;
- regs = of_iomap(np, 0);
+ regs = of_iomap(np, DCFG_CCSR);
if (!regs) {
of_node_put(np);
return -ENOMEM;
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v4 phy-next 3/9] soc: fsl: guts: add a global structure to hold state
2026-07-21 23:15 [PATCH v4 phy-next 0/9] RCW override for 10G Lynx dynamic protocol reconfiguration Vladimir Oltean
2026-07-21 23:15 ` [PATCH v4 phy-next 1/9] soc: fsl: guts: perform fsl_guts_init() error teardown in reverse order of setup Vladimir Oltean
2026-07-21 23:15 ` [PATCH v4 phy-next 2/9] soc: fsl: guts: use a macro to encode the DCFG CCSR space Vladimir Oltean
@ 2026-07-21 23:15 ` Vladimir Oltean
2026-07-21 23:15 ` [PATCH v4 phy-next 4/9] soc: fsl: guts: add a central fsl_guts_read() function Vladimir Oltean
` (5 subsequent siblings)
8 siblings, 0 replies; 16+ messages in thread
From: Vladimir Oltean @ 2026-07-21 23:15 UTC (permalink / raw)
To: linux-phy
Cc: devicetree, linuxppc-dev, linux-arm-kernel, Ioana Ciornei,
Vinod Koul, Neil Armstrong, Tanjeff Moos,
Christophe Leroy (CS GROUP), Michael Walle, Shawn Guo, Frank Li,
linux-kernel
From: Ioana Ciornei <ioana.ciornei@nxp.com>
Add the fsl_soc_guts structure in order to pass information like base
addresses, endianness etc between the init time and the runtime
operations (RCW override) which will get added in future patches.
There is no point in mapping and unmapping the DCFG CCSR space every
time we need to make a read, just map it once and keep its reference in
this new global struture.
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v3->v4:
- change error handling to a dedicated 'err_unmap_dcfg_ccsr' label
v2->v3:
- fix error handling in fsl_guts_init() - iounmap() the CCSR range and
set it to NULL on the "err" label rather than "err_nomem"
v1->v2: none
---
drivers/soc/fsl/guts.c | 29 ++++++++++++++++++-----------
1 file changed, 18 insertions(+), 11 deletions(-)
diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
index b97eb80cea95..bb65b62ed805 100644
--- a/drivers/soc/fsl/guts.c
+++ b/drivers/soc/fsl/guts.c
@@ -106,6 +106,11 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = {
{ },
};
+static struct fsl_soc_guts {
+ struct ccsr_guts __iomem *dcfg_ccsr;
+ bool little_endian;
+} soc;
+
static const struct fsl_soc_die_attr *fsl_soc_die_match(
u32 svr, const struct fsl_soc_die_attr *matches)
{
@@ -187,9 +192,7 @@ static int __init fsl_guts_init(void)
const struct fsl_soc_die_attr *soc_die;
const struct fsl_soc_data *soc_data;
const struct of_device_id *match;
- struct ccsr_guts __iomem *regs;
struct device_node *np;
- bool little_endian;
u64 soc_uid = 0;
u32 svr;
int ret;
@@ -199,24 +202,25 @@ static int __init fsl_guts_init(void)
return 0;
soc_data = match->data;
- regs = of_iomap(np, DCFG_CCSR);
- if (!regs) {
+ soc.dcfg_ccsr = of_iomap(np, DCFG_CCSR);
+ if (!soc.dcfg_ccsr) {
of_node_put(np);
return -ENOMEM;
}
- little_endian = of_property_read_bool(np, "little-endian");
- if (little_endian)
- svr = ioread32(®s->svr);
+ soc.little_endian = of_property_read_bool(np, "little-endian");
+ if (soc.little_endian)
+ svr = ioread32(&soc.dcfg_ccsr->svr);
else
- svr = ioread32be(®s->svr);
- iounmap(regs);
+ svr = ioread32be(&soc.dcfg_ccsr->svr);
of_node_put(np);
/* Register soc device */
soc_dev_attr = kzalloc_obj(*soc_dev_attr);
- if (!soc_dev_attr)
- return -ENOMEM;
+ if (!soc_dev_attr) {
+ ret = -ENOMEM;
+ goto err_unmap_dcfg_ccsr;
+ }
ret = soc_attr_read_machine(soc_dev_attr);
if (ret)
@@ -276,6 +280,9 @@ static int __init fsl_guts_init(void)
kfree(soc_dev_attr->family);
err_free_soc_dev_attr:
kfree(soc_dev_attr);
+err_unmap_dcfg_ccsr:
+ iounmap(soc.dcfg_ccsr);
+ soc.dcfg_ccsr = NULL;
return ret;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v4 phy-next 4/9] soc: fsl: guts: add a central fsl_guts_read() function
2026-07-21 23:15 [PATCH v4 phy-next 0/9] RCW override for 10G Lynx dynamic protocol reconfiguration Vladimir Oltean
` (2 preceding siblings ...)
2026-07-21 23:15 ` [PATCH v4 phy-next 3/9] soc: fsl: guts: add a global structure to hold state Vladimir Oltean
@ 2026-07-21 23:15 ` Vladimir Oltean
2026-07-21 23:15 ` [PATCH v4 phy-next 5/9] soc: fsl: guts: make it easier to determine on which SoC we are running Vladimir Oltean
` (4 subsequent siblings)
8 siblings, 0 replies; 16+ messages in thread
From: Vladimir Oltean @ 2026-07-21 23:15 UTC (permalink / raw)
To: linux-phy
Cc: devicetree, linuxppc-dev, linux-arm-kernel, Ioana Ciornei,
Vinod Koul, Neil Armstrong, Tanjeff Moos,
Christophe Leroy (CS GROUP), Michael Walle, Shawn Guo, Frank Li,
linux-kernel
From: Ioana Ciornei <ioana.ciornei@nxp.com>
Add a central fsl_guts_read() function which will take into account the
endianness that was already determined. No point is duplicating the
if-else statement each time we need to read a DCFG register.
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v1->v4: none
---
drivers/soc/fsl/guts.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
index bb65b62ed805..8e5c3cae811e 100644
--- a/drivers/soc/fsl/guts.c
+++ b/drivers/soc/fsl/guts.c
@@ -111,6 +111,14 @@ static struct fsl_soc_guts {
bool little_endian;
} soc;
+static unsigned int fsl_guts_read(const void __iomem *reg)
+{
+ if (soc.little_endian)
+ return ioread32(reg);
+
+ return ioread32be(reg);
+}
+
static const struct fsl_soc_die_attr *fsl_soc_die_match(
u32 svr, const struct fsl_soc_die_attr *matches)
{
@@ -209,10 +217,7 @@ static int __init fsl_guts_init(void)
}
soc.little_endian = of_property_read_bool(np, "little-endian");
- if (soc.little_endian)
- svr = ioread32(&soc.dcfg_ccsr->svr);
- else
- svr = ioread32be(&soc.dcfg_ccsr->svr);
+ svr = fsl_guts_read(&soc.dcfg_ccsr->svr);
of_node_put(np);
/* Register soc device */
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v4 phy-next 5/9] soc: fsl: guts: make it easier to determine on which SoC we are running
2026-07-21 23:15 [PATCH v4 phy-next 0/9] RCW override for 10G Lynx dynamic protocol reconfiguration Vladimir Oltean
` (3 preceding siblings ...)
2026-07-21 23:15 ` [PATCH v4 phy-next 4/9] soc: fsl: guts: add a central fsl_guts_read() function Vladimir Oltean
@ 2026-07-21 23:15 ` Vladimir Oltean
2026-07-21 23:16 ` [PATCH v4 phy-next 6/9] soc: fsl: guts: make fsl_soc_data available after fsl_guts_init() Vladimir Oltean
` (3 subsequent siblings)
8 siblings, 0 replies; 16+ messages in thread
From: Vladimir Oltean @ 2026-07-21 23:15 UTC (permalink / raw)
To: linux-phy
Cc: devicetree, linuxppc-dev, linux-arm-kernel, Ioana Ciornei,
Vinod Koul, Neil Armstrong, Tanjeff Moos,
Christophe Leroy (CS GROUP), Michael Walle, Shawn Guo, Frank Li,
linux-kernel
From: Ioana Ciornei <ioana.ciornei@nxp.com>
The guts driver will need to easily determine on which SoC it's running
when it will need to perform RCW override at runtime. The guts driver
knows this already because fsl_guts_init() reads the QorIQ/Layerscape
architectural System Version Register (SVR), but it doesn't save this
for later lookups.
Add a new qoriq_die enum to be used as an index in the fsl_soc_die
array. A new fsl_soc_die_match_one() function is also added so that we
can directly determine if the SVR is a match with a specific die.
The SVR value read from the DCFG CCSR is also kept in the global soc
structure so that it can be accessed when needed.
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v3->v4: adapt to different error handling scheme
v1->v3: none
---
drivers/soc/fsl/guts.c | 47 ++++++++++++++++++++++++++++++++++++------
1 file changed, 41 insertions(+), 6 deletions(-)
diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
index 8e5c3cae811e..15674c6734c6 100644
--- a/drivers/soc/fsl/guts.c
+++ b/drivers/soc/fsl/guts.c
@@ -27,6 +27,23 @@ struct fsl_soc_data {
u32 uid_offset;
};
+enum qoriq_die {
+ DIE_T4240,
+ DIE_T1040,
+ DIE_T2080,
+ DIE_T1024,
+ DIE_LS1043A,
+ DIE_LS2080A,
+ DIE_LS1088A,
+ DIE_LS1012A,
+ DIE_LS1046A,
+ DIE_LS2088A,
+ DIE_LS1021A,
+ DIE_LX2160A,
+ DIE_LS1028A,
+ DIE_MAX,
+};
+
/* SoC die attribute definition for QorIQ platform */
static const struct fsl_soc_die_attr fsl_soc_die[] = {
/*
@@ -34,21 +51,25 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = {
*/
/* Die: T4240, SoC: T4240/T4160/T4080 */
+ [DIE_T4240] =
{ .die = "T4240",
.svr = 0x82400000,
.mask = 0xfff00000,
},
/* Die: T1040, SoC: T1040/T1020/T1042/T1022 */
+ [DIE_T1040] =
{ .die = "T1040",
.svr = 0x85200000,
.mask = 0xfff00000,
},
/* Die: T2080, SoC: T2080/T2081 */
+ [DIE_T2080] =
{ .die = "T2080",
.svr = 0x85300000,
.mask = 0xfff00000,
},
/* Die: T1024, SoC: T1024/T1014/T1023/T1013 */
+ [DIE_T1024] =
{ .die = "T1024",
.svr = 0x85400000,
.mask = 0xfff00000,
@@ -59,46 +80,55 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = {
*/
/* Die: LS1043A, SoC: LS1043A/LS1023A */
+ [DIE_LS1043A] =
{ .die = "LS1043A",
.svr = 0x87920000,
.mask = 0xffff0000,
},
/* Die: LS2080A, SoC: LS2080A/LS2040A/LS2085A */
+ [DIE_LS2080A] =
{ .die = "LS2080A",
.svr = 0x87010000,
.mask = 0xff3f0000,
},
/* Die: LS1088A, SoC: LS1088A/LS1048A/LS1084A/LS1044A */
+ [DIE_LS1088A] =
{ .die = "LS1088A",
.svr = 0x87030000,
.mask = 0xff3f0000,
},
/* Die: LS1012A, SoC: LS1012A */
+ [DIE_LS1012A] =
{ .die = "LS1012A",
.svr = 0x87040000,
.mask = 0xffff0000,
},
/* Die: LS1046A, SoC: LS1046A/LS1026A */
+ [DIE_LS1046A] =
{ .die = "LS1046A",
.svr = 0x87070000,
.mask = 0xffff0000,
},
/* Die: LS2088A, SoC: LS2088A/LS2048A/LS2084A/LS2044A */
+ [DIE_LS2088A] =
{ .die = "LS2088A",
.svr = 0x87090000,
.mask = 0xff3f0000,
},
/* Die: LS1021A, SoC: LS1021A/LS1020A/LS1022A */
+ [DIE_LS1021A] =
{ .die = "LS1021A",
.svr = 0x87000000,
.mask = 0xfff70000,
},
/* Die: LX2160A, SoC: LX2160A/LX2120A/LX2080A */
+ [DIE_LX2160A] =
{ .die = "LX2160A",
.svr = 0x87360000,
.mask = 0xff3f0000,
},
/* Die: LS1028A, SoC: LS1028A */
+ [DIE_LS1028A] =
{ .die = "LS1028A",
.svr = 0x870b0000,
.mask = 0xff3f0000,
@@ -109,6 +139,7 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = {
static struct fsl_soc_guts {
struct ccsr_guts __iomem *dcfg_ccsr;
bool little_endian;
+ u32 svr;
} soc;
static unsigned int fsl_guts_read(const void __iomem *reg)
@@ -119,11 +150,16 @@ static unsigned int fsl_guts_read(const void __iomem *reg)
return ioread32be(reg);
}
+static bool fsl_soc_die_match_one(u32 svr, const struct fsl_soc_die_attr *match)
+{
+ return match->svr == (svr & match->mask);
+}
+
static const struct fsl_soc_die_attr *fsl_soc_die_match(
u32 svr, const struct fsl_soc_die_attr *matches)
{
while (matches->svr) {
- if (matches->svr == (svr & matches->mask))
+ if (fsl_soc_die_match_one(svr, matches))
return matches;
matches++;
}
@@ -202,7 +238,6 @@ static int __init fsl_guts_init(void)
const struct of_device_id *match;
struct device_node *np;
u64 soc_uid = 0;
- u32 svr;
int ret;
np = of_find_matching_node_and_match(NULL, fsl_guts_of_match, &match);
@@ -217,7 +252,7 @@ static int __init fsl_guts_init(void)
}
soc.little_endian = of_property_read_bool(np, "little-endian");
- svr = fsl_guts_read(&soc.dcfg_ccsr->svr);
+ soc.svr = fsl_guts_read(&soc.dcfg_ccsr->svr);
of_node_put(np);
/* Register soc device */
@@ -231,7 +266,7 @@ static int __init fsl_guts_init(void)
if (ret)
of_machine_read_compatible(&soc_dev_attr->machine, 0);
- soc_die = fsl_soc_die_match(svr, fsl_soc_die);
+ soc_die = fsl_soc_die_match(soc.svr, fsl_soc_die);
if (soc_die) {
soc_dev_attr->family = kasprintf(GFP_KERNEL, "QorIQ %s",
soc_die->die);
@@ -243,14 +278,14 @@ static int __init fsl_guts_init(void)
goto err_free_soc_dev_attr;
}
- soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "svr:0x%08x", svr);
+ soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "svr:0x%08x", soc.svr);
if (!soc_dev_attr->soc_id) {
ret = -ENOMEM;
goto err_free_family;
}
soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d.%d",
- (svr >> 4) & 0xf, svr & 0xf);
+ (soc.svr >> 4) & 0xf, soc.svr & 0xf);
if (!soc_dev_attr->revision) {
ret = -ENOMEM;
goto err_free_soc_id;
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v4 phy-next 6/9] soc: fsl: guts: make fsl_soc_data available after fsl_guts_init()
2026-07-21 23:15 [PATCH v4 phy-next 0/9] RCW override for 10G Lynx dynamic protocol reconfiguration Vladimir Oltean
` (4 preceding siblings ...)
2026-07-21 23:15 ` [PATCH v4 phy-next 5/9] soc: fsl: guts: make it easier to determine on which SoC we are running Vladimir Oltean
@ 2026-07-21 23:16 ` Vladimir Oltean
2026-07-22 9:19 ` Ioana Ciornei
2026-07-21 23:16 ` [PATCH v4 phy-next 7/9] dt-bindings: fsl: layerscape-dcfg: define DCFG_DCSR region Vladimir Oltean
` (2 subsequent siblings)
8 siblings, 1 reply; 16+ messages in thread
From: Vladimir Oltean @ 2026-07-21 23:16 UTC (permalink / raw)
To: linux-phy
Cc: devicetree, linuxppc-dev, linux-arm-kernel, Ioana Ciornei,
Vinod Koul, Neil Armstrong, Tanjeff Moos,
Christophe Leroy (CS GROUP), Michael Walle, Shawn Guo, Frank Li,
linux-kernel
In a future change, struct fsl_soc_data will be extended with methods
for performing RCW override.
Since this will be performed from a calling context outside
fsl_guts_init(), we need to keep track of the soc_data that we determine
at fsl_guts_init() time, so we can reference it later.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v3->v4: adapt to new error handling scheme
v2->v3: don't leave soc.data a valid pointer if fsl_guts_init() fails
v1->v2: none
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
drivers/soc/fsl/guts.c | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
index 15674c6734c6..c283d44b68a3 100644
--- a/drivers/soc/fsl/guts.c
+++ b/drivers/soc/fsl/guts.c
@@ -138,6 +138,7 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = {
static struct fsl_soc_guts {
struct ccsr_guts __iomem *dcfg_ccsr;
+ const struct fsl_soc_data *data;
bool little_endian;
u32 svr;
} soc;
@@ -231,10 +232,9 @@ static const struct of_device_id fsl_guts_of_match[] = {
static int __init fsl_guts_init(void)
{
- struct soc_device_attribute *soc_dev_attr;
+ struct soc_device_attribute *soc_dev_attr = NULL;
static struct soc_device *soc_dev;
const struct fsl_soc_die_attr *soc_die;
- const struct fsl_soc_data *soc_data;
const struct of_device_id *match;
struct device_node *np;
u64 soc_uid = 0;
@@ -243,12 +243,13 @@ static int __init fsl_guts_init(void)
np = of_find_matching_node_and_match(NULL, fsl_guts_of_match, &match);
if (!np)
return 0;
- soc_data = match->data;
+ soc.data = match->data;
soc.dcfg_ccsr = of_iomap(np, DCFG_CCSR);
if (!soc.dcfg_ccsr) {
of_node_put(np);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err_clear_soc_data;
}
soc.little_endian = of_property_read_bool(np, "little-endian");
@@ -291,9 +292,9 @@ static int __init fsl_guts_init(void)
goto err_free_soc_id;
}
- if (soc_data)
- soc_uid = fsl_guts_get_soc_uid(soc_data->sfp_compat,
- soc_data->uid_offset);
+ if (soc.data)
+ soc_uid = fsl_guts_get_soc_uid(soc.data->sfp_compat,
+ soc.data->uid_offset);
if (soc_uid)
soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX",
soc_uid);
@@ -323,6 +324,8 @@ static int __init fsl_guts_init(void)
err_unmap_dcfg_ccsr:
iounmap(soc.dcfg_ccsr);
soc.dcfg_ccsr = NULL;
+err_clear_soc_data:
+ soc.data = NULL;
return ret;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v4 phy-next 7/9] dt-bindings: fsl: layerscape-dcfg: define DCFG_DCSR region
2026-07-21 23:15 [PATCH v4 phy-next 0/9] RCW override for 10G Lynx dynamic protocol reconfiguration Vladimir Oltean
` (5 preceding siblings ...)
2026-07-21 23:16 ` [PATCH v4 phy-next 6/9] soc: fsl: guts: make fsl_soc_data available after fsl_guts_init() Vladimir Oltean
@ 2026-07-21 23:16 ` Vladimir Oltean
2026-07-21 23:16 ` [PATCH v4 phy-next 8/9] soc: fsl: guts: implement the RCW override procedure Vladimir Oltean
2026-07-21 23:16 ` [PATCH v4 phy-next 9/9] phy: lynx-10g: use RCW override procedure for dynamic protocol change Vladimir Oltean
8 siblings, 0 replies; 16+ messages in thread
From: Vladimir Oltean @ 2026-07-21 23:16 UTC (permalink / raw)
To: linux-phy
Cc: devicetree, linuxppc-dev, linux-arm-kernel, Ioana Ciornei,
Vinod Koul, Neil Armstrong, Tanjeff Moos,
Christophe Leroy (CS GROUP), Michael Walle, Shawn Guo, Frank Li,
linux-kernel, Conor Dooley, Conor Dooley, Krzysztof Kozlowski,
Rob Herring
In Layerscape (Arm) and QorIQ (PowerPC) devices, hardware peripherals
are accessed by the CPU through a portion of the SoC address space
called CCSR ("Configuration, Control, and Status Registers"). All
hardware IP blocks have their registers mapped here, and the Device
Configuration block makes no exception.
However, there exists a secondary range of the address space named DCSR
("Debug Control and Status Registers") which, like CCSR, also holds
registers of hardware IP blocks, except the DCSR contents is hidden in
all public reference manuals.
The intention of the CCSR/DCSR split, to the best of my knowledge, was
to place the functionality that is too low level for normal use, and
which is necessary only for debug, in a completely separate address
space which can be hidden.
A use case has appeared where networking SerDes lanes need to be
reconfigured at runtime for a different protocol (example: 10GBase-R to
SGMII), and the architecture of the SoCs does not normally permit that.
The Reset Configuration Word (RCW) is a data structure read by the SoC
preboot loader (PBL) which contains stuff like pinmuxing and SerDes
protocol mapping for each lane.
The RCW that the PBL has loaded is visible in the DCFG block's normal
status registers (from CCSR), as read only. Turns out, the RCW is also
mapped in the DCFG's shadow register map (in DCSR), in a write-only
form. Writing to the RCW registers from the DCFG's DCSR space to change
what the PBL has loaded is called "RCW override".
It has been validated that the RCW override procedure is necessary to
reconfigure the networking data path when a SerDes lane performs a major
protocol change. It changes some internal muxes which connect the PCS to
either the 10G MAC or to the 1G MAC.
Defining the DCSR area of the DCFG as a secondary 'reg' array element
allows operating systems to perform RCW overrides. Since it is
introduced late in the binding's lifetime, it is optional. It can be
identified by name, but also by index (first 'reg' is CCSR).
Note that while all SoCs should have a DCFG register block in DCSR, we
only need to expose it for the SoCs where the RCW override procedure is
known to be needed and has been validated.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
---
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Rob Herring <robh@kernel.org>
v2->v4: none
v1->v2:
- add Conor's review tag
- update email addresses of DT maintainers
---
.../bindings/soc/fsl/fsl,layerscape-dcfg.yaml | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/soc/fsl/fsl,layerscape-dcfg.yaml b/Documentation/devicetree/bindings/soc/fsl/fsl,layerscape-dcfg.yaml
index 3fb0534ea597..fc14fd0bf84b 100644
--- a/Documentation/devicetree/bindings/soc/fsl/fsl,layerscape-dcfg.yaml
+++ b/Documentation/devicetree/bindings/soc/fsl/fsl,layerscape-dcfg.yaml
@@ -36,7 +36,20 @@ properties:
- const: simple-mfd
reg:
- maxItems: 1
+ minItems: 1
+ items:
+ - description:
+ Customer-visible DCFG register map from CCSR address space
+ (Configuration, Control and Status Registers)
+ - description:
+ Customer-hidden DCFG register map from DCSR address space
+ (Debug Control and Status Registers)
+
+ reg-names:
+ minItems: 1
+ items:
+ - const: dcfg_ccsr
+ - const: dcfg_dcsr
little-endian: true
big-endian: true
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v4 phy-next 8/9] soc: fsl: guts: implement the RCW override procedure
2026-07-21 23:15 [PATCH v4 phy-next 0/9] RCW override for 10G Lynx dynamic protocol reconfiguration Vladimir Oltean
` (6 preceding siblings ...)
2026-07-21 23:16 ` [PATCH v4 phy-next 7/9] dt-bindings: fsl: layerscape-dcfg: define DCFG_DCSR region Vladimir Oltean
@ 2026-07-21 23:16 ` Vladimir Oltean
2026-07-22 11:01 ` Ioana Ciornei
2026-07-21 23:16 ` [PATCH v4 phy-next 9/9] phy: lynx-10g: use RCW override procedure for dynamic protocol change Vladimir Oltean
8 siblings, 1 reply; 16+ messages in thread
From: Vladimir Oltean @ 2026-07-21 23:16 UTC (permalink / raw)
To: linux-phy
Cc: devicetree, linuxppc-dev, linux-arm-kernel, Ioana Ciornei,
Vinod Koul, Neil Armstrong, Tanjeff Moos,
Christophe Leroy (CS GROUP), Michael Walle, Shawn Guo, Frank Li,
linux-kernel
Add support for the RCW override procedure which enables runtime
reconfiguration of the protocol running on a SerDes lane. The procedure
is done through the DCFG DCSR space which now can be defined as the
second memory region of the guts DT node.
Support is added on the following SoCs: LS1046A, LS1088A, LS2088A.
The procedure is exported to the "client" driver - the Lynx10G SerDes
PHY driver - through the following functions:
- fsl_guts_lane_validate() used to validate that changing the protocol
on a specific lane is supported.
- fsl_guts_lane_set_mode() which can be used to request the RCW
procedure be executed for a specific lane.
Since the RCW override procedure is different depending on the SoC, the
private fsl_soc_data structure is updated with two new per SoC callbacks
(.serdes_get_rcw_override() and .serdes_init_rcwcr()) which get used
from the generic fsl_guts_lane_set_mode() function. These two callbacks
hide all the SoC specific register offsets, masks and values so that the
_set_mode() procedure is straightforward.
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v3->v4:
- move spin_lock_init(&soc.rcwcr_lock) before the of_iomap(np, DCFG_DCSR)
assignment, so that fsl_guts_lane_set_mode() has no chance of using
uninitialized resources, but will fail cleanly
- adapt to new error handling scheme in fsl_guts_init()
- add comments and a print in fsl_guts_rcw_rmw()
- remove fsl_soc_die_match_one() from fsl_guts_serdes_get_rcw_override().
Shouldn't be necessary; implicit from presence of
soc_data->serdes_get_rcw_override() method.
- fix serdes block and lane count bounds
- replace fsl_guts_lane_init() with SRDS_PRTCL_S1 decoding
v2->v3:
- move iounmap() of dcfg_dcsr area on the 'err' label
- use __ffs() (standard API which also works on armv7) instead of
__bf_shf() (an internal helper meant for compile-time constants in
bitfield.h)
- only operate on lanes on which fsl_guts_lane_init() was called in
ls2088a_serdes_init_rcwcr()
- use read_poll_timeout_atomic() in fsl_guts_rcw_rmw() to clarify that
DCFG_DCSR writes are supposed to reflect back in DCFG_CCSR
- check soc.data in fsl_guts_serdes_get_rcw_override() to ensure
fsl_guts_init() succeeded
- put parentheses around (lane) in LS1088A_RCWSR29_SRDS_PRTCL_S1_LNn()
and LS1088A_RCWSR30_SRDS_PRTCL_S2_LNn() macro expressions
v1->v2:
- drop DT maintainers from explicit CC
- keep devicetree@vger.kernel.org CCed on entire series
- include missing <linux/bitfield.h>
- namespace SRDS_PRTCL values for LS1046A and LS1088A, even if they are
the same. For LS1028A (not covered here) they are not.
- prefix SRDS_CLK_SEL_{GMII,XGMII} with LS2088A_
- reorder alphanumerically (LS1046A should come before LS1088A)
---
drivers/soc/fsl/guts.c | 399 ++++++++++++++++++++++++++++++++++++++-
include/linux/fsl/guts.h | 18 +-
2 files changed, 409 insertions(+), 8 deletions(-)
diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
index c283d44b68a3..28361c63e26c 100644
--- a/drivers/soc/fsl/guts.c
+++ b/drivers/soc/fsl/guts.c
@@ -5,7 +5,10 @@
* Copyright (C) 2016 Freescale Semiconductor, Inc.
*/
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/of_fdt.h>
@@ -15,6 +18,28 @@
#include <linux/fsl/guts.h>
#define DCFG_CCSR 0
+#define DCFG_DCSR 1
+
+#define RCW_TIMEOUT_US 1
+
+#define LS1046A_RCWSR5_SRDS_PRTCL_S1(lane) \
+ GENMASK(19 + 4 * (lane), 16 + 4 * (lane))
+#define LS1046A_SRDS_PRTCL_XFI 1
+#define LS1046A_SRDS_PRTCL_100BASEX_SGMII 3
+
+#define LS1088A_RCWSR29_SRDS_PRTCL_S1_LNn(lane) \
+ GENMASK(19 + 4 * (3 - (lane)), 16 + 4 * (3 - (lane)))
+#define LS1088A_RCWSR30_SRDS_PRTCL_S2_LNn(lane) \
+ GENMASK(3 + 4 * (3 - (lane)), 4 * (3 - (lane)))
+#define LS1088A_SRDS_PRTCL_XFI 1
+#define LS1088A_SRDS_PRTCL_100BASEX_SGMII 3
+
+#define LS2088A_RCWSR29_SRDS_PRTCL_S1 GENMASK(23, 16)
+#define LS2088A_RCWSR30_SRDS_CLK_EN_SEL_XGMII_S1 BIT(14)
+#define LS2088A_RCWSR30_SRDS_CLK_SEL_XGMII_Ln_S1(lane) BIT(6 + (7 - (lane)))
+#define LS2088A_RCWSR30_SRDS_CLK_SEL_MSK GENMASK(13, 6)
+#define LS2088A_SRDS_CLK_SEL_XGMII 1
+#define LS2088A_SRDS_CLK_SEL_GMII 0
struct fsl_soc_die_attr {
char *die;
@@ -22,9 +47,21 @@ struct fsl_soc_die_attr {
u32 mask;
};
+struct fsl_soc_serdes_rcw_override {
+ int offset;
+ int mask;
+ int val;
+};
+
struct fsl_soc_data {
const char *sfp_compat;
u32 uid_offset;
+ int num_serdes_blocks;
+ int num_serdes_lanes;
+ int (*serdes_init_rcwcr)(int index);
+ int (*serdes_get_rcw_override)(int index, int lane,
+ enum lynx_lane_mode lane_mode,
+ struct fsl_soc_serdes_rcw_override *override);
};
enum qoriq_die {
@@ -44,6 +81,48 @@ enum qoriq_die {
DIE_MAX,
};
+struct rcw_full_srds_proto {
+ int srds_proto_val;
+ unsigned long xgmii_lanes;
+};
+
+static const struct rcw_full_srds_proto ls2088a_rcw_full_srds1_protos[] = {
+ { 0x05, 0 },
+ { 0x07, 0 },
+ { 0x09, 0 },
+ { 0x0a, 0 },
+ { 0x0c, 0 },
+ { 0x0e, 0 },
+ { 0x10, 0 },
+ { 0x12, 0 },
+ { 0x14, 0 },
+ { 0x16, 0 },
+ { 0x18, 0 },
+ { 0x1a, 0 },
+ { 0x1c, 0 },
+ { 0x1e, 0 },
+ { 0x20, 0 },
+ { 0x22, 0 },
+ { 0x24, 0 },
+ { 0x26, GENMASK(7, 6) },
+ { 0x28, GENMASK(7, 4) },
+ { 0x2a, GENMASK(7, 0) },
+ /* 0x2b: unimplemented because of XAUI1 (lanes E-H) */
+ /* 0x2d: unimplemented because of XAUI1 (lanes E-H) */
+ /* 0x2e: unimplemented because of XAUI1 (lanes E-H) */
+ /* 0x30: unimplemented because of XAUI1 (lanes E-H) */
+ /* 0x32: unimplemented because of XAUI1 (lanes E-H) and XAUI2 (A-D) */
+ /* 0x33: unimplemented because of QSGMII (lanes E-H) */
+ /* 0x35: unimplemented because of QSGMII (lanes A-C) */
+ /* 0x37: unimplemented because of QSGMII (lanes E-F) */
+ { 0x39, 0 },
+ { 0x3b, GENMASK(6, 4) | GENMASK(2, 0) },
+ { 0x4b, GENMASK(7, 4) },
+ { 0x4c, GENMASK(3, 0) },
+ { 0x4d, 0 },
+ { 0x58, 0 },
+};
+
/* SoC die attribute definition for QorIQ platform */
static const struct fsl_soc_die_attr fsl_soc_die[] = {
/*
@@ -138,9 +217,11 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = {
static struct fsl_soc_guts {
struct ccsr_guts __iomem *dcfg_ccsr;
+ struct ccsr_guts __iomem *dcfg_dcsr;
const struct fsl_soc_data *data;
bool little_endian;
u32 svr;
+ spinlock_t rcwcr_lock; /* serializes concurrent writes to the RCWCR */
} soc;
static unsigned int fsl_guts_read(const void __iomem *reg)
@@ -151,6 +232,36 @@ static unsigned int fsl_guts_read(const void __iomem *reg)
return ioread32be(reg);
}
+static void fsl_guts_write(void __iomem *reg, u32 val)
+{
+ if (soc.little_endian)
+ iowrite32(val, reg);
+ else
+ iowrite32be(val, reg);
+}
+
+/* Some fields of the Reset Configuration Word (RCW) can be overridden at
+ * runtime by writing to the RCWCRn registers contained within the DCSR space
+ * of the Device Configuration (DCFG) block. The layout of the RCWCRn registers
+ * is identical with the read-only RCWSRn from the CCSR space.
+ */
+static int fsl_guts_rcw_rmw(int offset, u32 val, u32 mask)
+{
+ u32 rcwcr, rcwsr = fsl_guts_read(&soc.dcfg_ccsr->rcwsr[offset]);
+
+ rcwcr = rcwsr & ~mask;
+ rcwcr |= val;
+ fsl_guts_write(&soc.dcfg_dcsr->rcwcr[offset], rcwcr);
+
+ pr_debug("RCW override: RCWSR%d 0x%x -> RCWCR%d 0x%x\n",
+ offset + 1, rcwsr, offset + 1, rcwcr);
+
+ /* Updates to RCWCR should be visible back in RCWSR immediately */
+ return read_poll_timeout_atomic(fsl_guts_read, rcwsr, rcwsr == rcwcr,
+ 0, RCW_TIMEOUT_US, false,
+ &soc.dcfg_ccsr->rcwsr[offset]);
+}
+
static bool fsl_soc_die_match_one(u32 svr, const struct fsl_soc_die_attr *match)
{
return match->svr == (svr & match->mask);
@@ -167,6 +278,97 @@ static const struct fsl_soc_die_attr *fsl_soc_die_match(
return NULL;
}
+static int
+fsl_guts_serdes_get_rcw_override(int serdes_idx, int lane,
+ enum lynx_lane_mode lane_mode,
+ struct fsl_soc_serdes_rcw_override *override)
+{
+ const struct fsl_soc_data *soc_data = soc.data;
+
+ if (!soc_data)
+ return -ENODEV;
+
+ /* serdes_idx is one-based */
+ if (serdes_idx > soc_data->num_serdes_blocks || serdes_idx <= 0)
+ return -ERANGE;
+
+ if (lane >= soc_data->num_serdes_lanes || lane < 0)
+ return -ERANGE;
+
+ if (!soc_data->serdes_get_rcw_override) {
+ pr_debug("RCW override not implemented for SoC\n");
+ return -EINVAL;
+ }
+
+ if (!soc.dcfg_dcsr) {
+ pr_debug("Device tree does not define DCFG_DCSR region necessary for RCW override\n");
+ return -EINVAL;
+ }
+
+ return soc_data->serdes_get_rcw_override(serdes_idx, lane, lane_mode,
+ override);
+}
+
+/**
+ * fsl_guts_lane_validate() - Validate that SerDes protocol is implemented and
+ * supported on current SoC
+ * @serdes_idx: one-based SerDes block index
+ * @lane: zero-based lane index within SerDes
+ * @lane_mode: requested SerDes protocol
+ *
+ * Should be called before actually requesting the RCW override procedure to be
+ * applied using %fsl_guts_lane_set_mode()
+ *
+ * Return: 0 if RCW override to protocol is possible, negative error otherwise
+ */
+int fsl_guts_lane_validate(int serdes_idx, int lane, enum lynx_lane_mode lane_mode)
+{
+ struct fsl_soc_serdes_rcw_override override;
+
+ return fsl_guts_serdes_get_rcw_override(serdes_idx, lane, lane_mode,
+ &override);
+}
+EXPORT_SYMBOL_NS_GPL(fsl_guts_lane_validate, "FSL_GUTS");
+
+/**
+ * fsl_guts_lane_set_mode() - apply RCW override procedure for SerDes lane
+ * @serdes_idx: one-based SerDes block index
+ * @lane: zero-based lane index within SerDes
+ * @lane_mode: requested SerDes protocol
+ *
+ * Return: 0 on success, negative error otherwise
+ */
+int fsl_guts_lane_set_mode(int serdes_idx, int lane, enum lynx_lane_mode lane_mode)
+{
+ struct fsl_soc_serdes_rcw_override override;
+ int err;
+
+ err = fsl_guts_serdes_get_rcw_override(serdes_idx, lane, lane_mode,
+ &override);
+ if (err)
+ return err;
+
+ spin_lock(&soc.rcwcr_lock);
+
+ if (soc.data->serdes_init_rcwcr) {
+ err = soc.data->serdes_init_rcwcr(serdes_idx);
+ if (err)
+ goto out_unlock;
+ }
+
+ err = fsl_guts_rcw_rmw(override.offset,
+ override.val << __ffs(override.mask),
+ override.mask);
+ if (err)
+ pr_err("RCW override failed: %pe\n", ERR_PTR(err));
+
+out_unlock:
+ spin_unlock(&soc.rcwcr_lock);
+
+ return err;
+}
+EXPORT_SYMBOL_NS_GPL(fsl_guts_lane_set_mode, "FSL_GUTS");
+
static u64 fsl_guts_get_soc_uid(const char *compat, unsigned int offset)
{
struct device_node *np;
@@ -193,9 +395,188 @@ static u64 fsl_guts_get_soc_uid(const char *compat, unsigned int offset)
return uid;
}
+static int ls1046a_serdes_get_rcw_override(int index, int lane,
+ enum lynx_lane_mode lane_mode,
+ struct fsl_soc_serdes_rcw_override *override)
+{
+ /* The RCW override procedure has to write to different registers
+ * depending on the SerDes block index.
+ */
+ switch (index) {
+ case 1:
+ override->offset = 4;
+ override->mask = LS1046A_RCWSR5_SRDS_PRTCL_S1(lane);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (lynx_lane_mode_uses_xgmii_mac(lane_mode))
+ override->val = LS1046A_SRDS_PRTCL_XFI;
+ else if (lynx_lane_mode_uses_gmii_mac(lane_mode))
+ override->val = LS1046A_SRDS_PRTCL_100BASEX_SGMII;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+static int ls1088a_serdes_get_rcw_override(int index, int lane,
+ enum lynx_lane_mode lane_mode,
+ struct fsl_soc_serdes_rcw_override *override)
+{
+ /* The RCW override procedure has to write to different registers
+ * depending on the SerDes block index.
+ */
+ switch (index) {
+ case 1:
+ override->offset = 28;
+ override->mask = LS1088A_RCWSR29_SRDS_PRTCL_S1_LNn(lane);
+ break;
+ case 2:
+ override->offset = 29;
+ override->mask = LS1088A_RCWSR30_SRDS_PRTCL_S2_LNn(lane);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (lynx_lane_mode_uses_xgmii_mac(lane_mode))
+ override->val = LS1088A_SRDS_PRTCL_XFI;
+ else if (lynx_lane_mode_uses_gmii_mac(lane_mode))
+ override->val = LS1088A_SRDS_PRTCL_100BASEX_SGMII;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct rcw_full_srds_proto *ls2088a_get_full_serdes1_proto(void)
+{
+ u32 rcwsr29 = fsl_guts_read(&soc.dcfg_ccsr->rcwsr[28]);
+ u32 srds_prtcl_s1 = FIELD_GET(LS2088A_RCWSR29_SRDS_PRTCL_S1, rcwsr29);
+
+ for (int i = 0; i < ARRAY_SIZE(ls2088a_rcw_full_srds1_protos); i++) {
+ const struct rcw_full_srds_proto *proto;
+
+ proto = &ls2088a_rcw_full_srds1_protos[i];
+ if (proto->srds_proto_val == srds_prtcl_s1)
+ return proto;
+ }
+
+ return NULL;
+}
+
+static int ls2088a_serdes_get_rcw_override(int index, int lane,
+ enum lynx_lane_mode lane_mode,
+ struct fsl_soc_serdes_rcw_override *override)
+{
+ switch (index) {
+ case 1:
+ override->offset = 29;
+ override->mask = LS2088A_RCWSR30_SRDS_CLK_SEL_XGMII_Ln_S1(lane);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* RCW override only supported if we know how to handle the initial
+ * RCWSR29[SRDS_PRTCL_S1] value and turn it into an override.
+ */
+ if (!ls2088a_get_full_serdes1_proto()) {
+ u32 rcwsr30 = fsl_guts_read(&soc.dcfg_ccsr->rcwsr[29]);
+
+ /* If a SerDes-level override is already in place (probably
+ * left there by a previous boot stage), use it.
+ */
+ if (!(rcwsr30 & LS2088A_RCWSR30_SRDS_CLK_EN_SEL_XGMII_S1))
+ return -EINVAL;
+ }
+
+ if (lynx_lane_mode_uses_xgmii_mac(lane_mode))
+ override->val = LS2088A_SRDS_CLK_SEL_XGMII;
+ else if (lynx_lane_mode_uses_gmii_mac(lane_mode))
+ override->val = LS2088A_SRDS_CLK_SEL_GMII;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+static int ls2088a_serdes_init_rcwcr(int serdes_idx)
+{
+ const struct rcw_full_srds_proto *srds_prtcl_s1;
+ const struct fsl_soc_data *soc_data = soc.data;
+ u32 rcwsr30;
+ int i, err;
+
+ /* SerDes 2 supports only SGMII for networking. There should be
+ * no need for RCW override
+ */
+ if (serdes_idx != 1)
+ return -EINVAL;
+
+ /* SRDS_CLK_EN_SEL_XGMII_S1: SerDes Clock Enable Select XGMII Serdes 1:
+ * Enables to select GMII/XGMII clock according to
+ * SRDS_CLK_SEL_XGMII_Ln_S1.
+ * If the GMII/XGMII select override has already been set, use it.
+ * Otherwise, derive an initial override for all lanes based on the
+ * full SerDes protocol table.
+ */
+ rcwsr30 = fsl_guts_read(&soc.dcfg_ccsr->rcwsr[29]);
+ if (rcwsr30 & LS2088A_RCWSR30_SRDS_CLK_EN_SEL_XGMII_S1) {
+ pr_debug("RCWSR30 = 0x%x, using this.\n", rcwsr30);
+ return 0;
+ }
+
+ srds_prtcl_s1 = ls2088a_get_full_serdes1_proto();
+
+ rcwsr30 = LS2088A_RCWSR30_SRDS_CLK_EN_SEL_XGMII_S1;
+
+ /* We need to configure the initial state of all lanes for
+ * the SerDes block #1
+ */
+ for_each_set_bit(i, &srds_prtcl_s1->xgmii_lanes, soc_data->num_serdes_lanes)
+ rcwsr30 |= LS2088A_RCWSR30_SRDS_CLK_SEL_XGMII_Ln_S1(i);
+
+ pr_debug("Setting initial RCWSR30 = 0x%x based on SRDS_PRTCL_S1 = 0x%x\n",
+ rcwsr30, srds_prtcl_s1->srds_proto_val);
+
+ err = fsl_guts_rcw_rmw(29, rcwsr30,
+ LS2088A_RCWSR30_SRDS_CLK_EN_SEL_XGMII_S1 |
+ LS2088A_RCWSR30_SRDS_CLK_SEL_MSK);
+ if (err) {
+ pr_err("Setting up initial RCWCR failed: %pe\n", ERR_PTR(err));
+ return err;
+ }
+
+ return 0;
+}
+
+static const struct fsl_soc_data ls1088a_data = {
+ .serdes_get_rcw_override = ls1088a_serdes_get_rcw_override,
+ .num_serdes_blocks = 2,
+ .num_serdes_lanes = 4,
+};
+
+static const struct fsl_soc_data ls1046a_data = {
+ .serdes_get_rcw_override = ls1046a_serdes_get_rcw_override,
+ .num_serdes_blocks = 2,
+ .num_serdes_lanes = 4,
+};
+
+static const struct fsl_soc_data ls2088a_data = {
+ .serdes_get_rcw_override = ls2088a_serdes_get_rcw_override,
+ .serdes_init_rcwcr = ls2088a_serdes_init_rcwcr,
+ .num_serdes_blocks = 2,
+ .num_serdes_lanes = 8,
+};
+
static const struct fsl_soc_data ls1028a_data = {
.sfp_compat = "fsl,ls1028a-sfp",
.uid_offset = 0x21c,
+ .num_serdes_blocks = 1,
+ .num_serdes_lanes = 4,
};
/*
@@ -221,10 +602,10 @@ static const struct of_device_id fsl_guts_of_match[] = {
{ .compatible = "fsl,mpc8572-guts", },
{ .compatible = "fsl,ls1021a-dcfg", },
{ .compatible = "fsl,ls1043a-dcfg", },
- { .compatible = "fsl,ls2080a-dcfg", },
- { .compatible = "fsl,ls1088a-dcfg", },
+ { .compatible = "fsl,ls2080a-dcfg", .data = &ls2088a_data},
+ { .compatible = "fsl,ls1088a-dcfg", .data = &ls1088a_data},
{ .compatible = "fsl,ls1012a-dcfg", },
- { .compatible = "fsl,ls1046a-dcfg", },
+ { .compatible = "fsl,ls1046a-dcfg", .data = &ls1046a_data},
{ .compatible = "fsl,lx2160a-dcfg", },
{ .compatible = "fsl,ls1028a-dcfg", .data = &ls1028a_data},
{}
@@ -240,6 +621,8 @@ static int __init fsl_guts_init(void)
u64 soc_uid = 0;
int ret;
+ spin_lock_init(&soc.rcwcr_lock);
+
np = of_find_matching_node_and_match(NULL, fsl_guts_of_match, &match);
if (!np)
return 0;
@@ -251,6 +634,8 @@ static int __init fsl_guts_init(void)
ret = -ENOMEM;
goto err_clear_soc_data;
}
+ /* DCFG_DCSR is optional */
+ soc.dcfg_dcsr = of_iomap(np, DCFG_DCSR);
soc.little_endian = of_property_read_bool(np, "little-endian");
soc.svr = fsl_guts_read(&soc.dcfg_ccsr->svr);
@@ -260,7 +645,7 @@ static int __init fsl_guts_init(void)
soc_dev_attr = kzalloc_obj(*soc_dev_attr);
if (!soc_dev_attr) {
ret = -ENOMEM;
- goto err_unmap_dcfg_ccsr;
+ goto err_unmap_dcfg_ccsr_dcsr;
}
ret = soc_attr_read_machine(soc_dev_attr);
@@ -321,7 +706,11 @@ static int __init fsl_guts_init(void)
kfree(soc_dev_attr->family);
err_free_soc_dev_attr:
kfree(soc_dev_attr);
-err_unmap_dcfg_ccsr:
+err_unmap_dcfg_ccsr_dcsr:
+ if (soc.dcfg_dcsr) {
+ iounmap(soc.dcfg_dcsr);
+ soc.dcfg_dcsr = NULL;
+ }
iounmap(soc.dcfg_ccsr);
soc.dcfg_ccsr = NULL;
err_clear_soc_data:
diff --git a/include/linux/fsl/guts.h b/include/linux/fsl/guts.h
index fdb55ca47a4f..8d5ffb985fee 100644
--- a/include/linux/fsl/guts.h
+++ b/include/linux/fsl/guts.h
@@ -13,6 +13,7 @@
#include <linux/types.h>
#include <linux/io.h>
+#include <soc/fsl/phy-fsl-lynx.h>
/*
* Global Utility Registers.
@@ -91,9 +92,15 @@ struct ccsr_guts {
u32 iovselsr; /* 0x.00c0 - I/O voltage select status register
Called 'elbcvselcr' on 86xx SOCs */
u8 res0c4[0x100 - 0xc4];
- u32 rcwsr[16]; /* 0x.0100 - Reset Control Word Status registers
- There are 16 registers */
- u8 res140[0x224 - 0x140];
+ /* 0x.0100 - read-only Reset Configuration Word Status registers in
+ * CCSR, or write-only Reset Configuration Word Control registers in
+ * DCSR. In both cases there are 32 registers.
+ */
+ union {
+ u32 rcwsr[32];
+ u32 rcwcr[32];
+ };
+ u8 res180[0x224 - 0x180];
u32 iodelay1; /* 0x.0224 - IO delay control register 1 */
u32 iodelay2; /* 0x.0228 - IO delay control register 2 */
u8 res22c[0x604 - 0x22c];
@@ -131,6 +138,11 @@ struct ccsr_guts {
u32 srds2cr1; /* 0x.0f44 - SerDes2 Control Register 0 */
} __attribute__ ((packed));
+int fsl_guts_lane_validate(int serdes_idx, int lane,
+ enum lynx_lane_mode lane_mode);
+int fsl_guts_lane_set_mode(int serdes_idx, int lane,
+ enum lynx_lane_mode lane_mode);
+
/* Alternate function signal multiplex control */
#define MPC85xx_PMUXCR_QE(x) (0x8000 >> (x))
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v4 phy-next 9/9] phy: lynx-10g: use RCW override procedure for dynamic protocol change
2026-07-21 23:15 [PATCH v4 phy-next 0/9] RCW override for 10G Lynx dynamic protocol reconfiguration Vladimir Oltean
` (7 preceding siblings ...)
2026-07-21 23:16 ` [PATCH v4 phy-next 8/9] soc: fsl: guts: implement the RCW override procedure Vladimir Oltean
@ 2026-07-21 23:16 ` Vladimir Oltean
2026-07-22 11:03 ` Ioana Ciornei
8 siblings, 1 reply; 16+ messages in thread
From: Vladimir Oltean @ 2026-07-21 23:16 UTC (permalink / raw)
To: linux-phy
Cc: devicetree, linuxppc-dev, linux-arm-kernel, Ioana Ciornei,
Vinod Koul, Neil Armstrong, Tanjeff Moos,
Christophe Leroy (CS GROUP), Michael Walle, Shawn Guo, Frank Li,
linux-kernel
Up until this patch, the only protocol change supported was between
1000Base-X/SGMII and 2500Base-X. The others require an RCW override
procedure which was lacking.
Since now the guts driver provides the means of applying this procedure,
make use of it and remove any comment which mentioned the limitation.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v3->v4:
- drop the lynx_10g_lane_read_configuration() -> fsl_guts_lane_init()
call. The guts driver now uses a self-contained procedure to figure
out initial SerDes protocols by decoding RCWSR29 on LS2088A, rather
than relying on the SerDes driver to tell it.
v1->v3: none
---
drivers/phy/freescale/Kconfig | 1 +
drivers/phy/freescale/phy-fsl-lynx-10g.c | 23 ++++++++++++++---------
2 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/drivers/phy/freescale/Kconfig b/drivers/phy/freescale/Kconfig
index 5bf3864fbe64..d4e189fffbf8 100644
--- a/drivers/phy/freescale/Kconfig
+++ b/drivers/phy/freescale/Kconfig
@@ -58,6 +58,7 @@ config PHY_FSL_LYNX_10G
tristate "Freescale Layerscape Lynx 10G SerDes PHY support"
depends on OF
depends on ARCH_LAYERSCAPE || COMPILE_TEST
+ select FSL_GUTS
select GENERIC_PHY
select PHY_FSL_LYNX_CORE
help
diff --git a/drivers/phy/freescale/phy-fsl-lynx-10g.c b/drivers/phy/freescale/phy-fsl-lynx-10g.c
index 38def160ef1a..60c85d08c33e 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-10g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-10g.c
@@ -8,6 +8,7 @@
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/workqueue.h>
+#include <linux/fsl/guts.h>
#include "phy-fsl-lynx-core.h"
@@ -1167,14 +1168,7 @@ static bool lynx_10g_lane_mode_needs_rcw_override(struct lynx_lane *lane,
/* 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.
+ * procedure to reconfigure an internal mux.
*/
if ((lynx_lane_mode_uses_gmii_mac(curr) &&
lynx_lane_mode_uses_xgmii_mac(new)) ||
@@ -1189,6 +1183,7 @@ 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);
+ struct lynx_priv *priv = lane->priv;
enum lynx_lane_mode lane_mode;
int err;
@@ -1197,7 +1192,8 @@ static int lynx_10g_validate(struct phy *phy, enum phy_mode mode, int submode,
return err;
if (lynx_10g_lane_mode_needs_rcw_override(lane, lane_mode))
- return -EINVAL;
+ return fsl_guts_lane_validate(priv->info->index, lane->id,
+ lane_mode);
return 0;
}
@@ -1205,6 +1201,7 @@ static int lynx_10g_validate(struct phy *phy, enum phy_mode mode, int submode,
static int lynx_10g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
{
struct lynx_lane *lane = phy_get_drvdata(phy);
+ struct lynx_priv *priv = lane->priv;
bool powered_up = lane->powered_up;
enum lynx_lane_mode lane_mode;
int err;
@@ -1225,6 +1222,13 @@ static int lynx_10g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
if (powered_up)
lynx_10g_lane_halt(phy);
+ if (lynx_10g_lane_mode_needs_rcw_override(lane, lane_mode)) {
+ err = fsl_guts_lane_set_mode(priv->info->index, lane->id,
+ lane_mode);
+ if (err)
+ goto out;
+ }
+
err = lynx_10g_lane_disable_pcvt(lane, lane->mode);
if (err)
goto out;
@@ -1314,6 +1318,7 @@ static struct platform_driver lynx_10g_driver = {
};
module_platform_driver(lynx_10g_driver);
+MODULE_IMPORT_NS("FSL_GUTS");
MODULE_IMPORT_NS("PHY_FSL_LYNX");
MODULE_AUTHOR("Ioana Ciornei <ioana.ciornei@nxp.com>");
MODULE_AUTHOR("Vladimir Oltean <vladimir.oltean@nxp.com>");
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH v4 phy-next 1/9] soc: fsl: guts: perform fsl_guts_init() error teardown in reverse order of setup
2026-07-21 23:15 ` [PATCH v4 phy-next 1/9] soc: fsl: guts: perform fsl_guts_init() error teardown in reverse order of setup Vladimir Oltean
@ 2026-07-22 7:18 ` Michael Walle
2026-07-22 7:55 ` Vladimir Oltean
2026-07-22 9:15 ` Ioana Ciornei
1 sibling, 1 reply; 16+ messages in thread
From: Michael Walle @ 2026-07-22 7:18 UTC (permalink / raw)
To: Vladimir Oltean, linux-phy
Cc: devicetree, linuxppc-dev, linux-arm-kernel, Ioana Ciornei,
Vinod Koul, Neil Armstrong, Tanjeff Moos,
Christophe Leroy (CS GROUP), Shawn Guo, Frank Li, linux-kernel
Hi,
On Wed Jul 22, 2026 at 1:15 AM CEST, Vladimir Oltean wrote:
> Michael Walle has confirmed that ignoring the error was intentional,
> and we preserve that:
> https://lore.kernel.org/linux-phy/DK44809N7Y8I.J2Z3U4N32H0Q@kernel.org/
I thought you wanted to check if kasprintf() fails and return an
error? Just to be clear, I'm fine with either way.
-michael
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v4 phy-next 1/9] soc: fsl: guts: perform fsl_guts_init() error teardown in reverse order of setup
2026-07-22 7:18 ` Michael Walle
@ 2026-07-22 7:55 ` Vladimir Oltean
0 siblings, 0 replies; 16+ messages in thread
From: Vladimir Oltean @ 2026-07-22 7:55 UTC (permalink / raw)
To: Michael Walle
Cc: Vladimir Oltean, linux-phy, devicetree, linuxppc-dev,
linux-arm-kernel, Ioana Ciornei, Vinod Koul, Neil Armstrong,
Tanjeff Moos, Christophe Leroy (CS GROUP), Shawn Guo, Frank Li,
linux-kernel
On Wed, Jul 22, 2026 at 09:18:48AM +0200, Michael Walle wrote:
> Hi,
>
> On Wed Jul 22, 2026 at 1:15 AM CEST, Vladimir Oltean wrote:
> > Michael Walle has confirmed that ignoring the error was intentional,
> > and we preserve that:
> > https://lore.kernel.org/linux-phy/DK44809N7Y8I.J2Z3U4N32H0Q@kernel.org/
>
> I thought you wanted to check if kasprintf() fails and return an
> error? Just to be clear, I'm fine with either way.
I did, but then I considered I don't have a strong justification, and it
isn't a change I need to make to make progress with this series, rather
more of a distraction.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v4 phy-next 1/9] soc: fsl: guts: perform fsl_guts_init() error teardown in reverse order of setup
2026-07-21 23:15 ` [PATCH v4 phy-next 1/9] soc: fsl: guts: perform fsl_guts_init() error teardown in reverse order of setup Vladimir Oltean
2026-07-22 7:18 ` Michael Walle
@ 2026-07-22 9:15 ` Ioana Ciornei
1 sibling, 0 replies; 16+ messages in thread
From: Ioana Ciornei @ 2026-07-22 9:15 UTC (permalink / raw)
To: Vladimir Oltean
Cc: linux-phy, devicetree, linuxppc-dev, linux-arm-kernel, Vinod Koul,
Neil Armstrong, Tanjeff Moos, Christophe Leroy (CS GROUP),
Michael Walle, Shawn Guo, Frank Li, linux-kernel
On Wed, Jul 22, 2026 at 02:15:55AM +0300, Vladimir Oltean wrote:
> fsl_guts_init() is about to get much more complicated and the central
> error handling procedure cannot scale in its current design, unless we
> add a lot of "if" conditions to detect what has been allocated and what
> hasn't.
>
> Currently the code relies on the fact that kfree(NULL) is safe, but this
> doesn't scale to the case where "soc_dev_attr" itself is NULL, because
> this would dereference "soc_dev_attr->family" and friends of a NULL
> pointer.
>
> Convert to the more typical error handling pattern where the teardown is
> in the strict reverse order of setup, and a teardown step is only called
> if its corresponding setup step was executed.
>
> At the same time, maintain the optionality of soc_dev_attr->serial_number
> by not checking whether that kasprintf() has returned NULL. In the error
> path, kfree(NULL) is safe, so we don't need to add an "if" condition for
> it. Michael Walle has confirmed that ignoring the error was intentional,
> and we preserve that:
> https://lore.kernel.org/linux-phy/DK44809N7Y8I.J2Z3U4N32H0Q@kernel.org/
>
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Ioana Ciornei <ioana.ciornei@nxp.com>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v4 phy-next 6/9] soc: fsl: guts: make fsl_soc_data available after fsl_guts_init()
2026-07-21 23:16 ` [PATCH v4 phy-next 6/9] soc: fsl: guts: make fsl_soc_data available after fsl_guts_init() Vladimir Oltean
@ 2026-07-22 9:19 ` Ioana Ciornei
0 siblings, 0 replies; 16+ messages in thread
From: Ioana Ciornei @ 2026-07-22 9:19 UTC (permalink / raw)
To: Vladimir Oltean
Cc: linux-phy, devicetree, linuxppc-dev, linux-arm-kernel, Vinod Koul,
Neil Armstrong, Tanjeff Moos, Christophe Leroy (CS GROUP),
Michael Walle, Shawn Guo, Frank Li, linux-kernel
On Wed, Jul 22, 2026 at 02:16:00AM +0300, Vladimir Oltean wrote:
> In a future change, struct fsl_soc_data will be extended with methods
> for performing RCW override.
>
> Since this will be performed from a calling context outside
> fsl_guts_init(), we need to keep track of the soc_data that we determine
> at fsl_guts_init() time, so we can reference it later.
>
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Ioana Ciornei <ioana.ciornei@nxp.com>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v4 phy-next 8/9] soc: fsl: guts: implement the RCW override procedure
2026-07-21 23:16 ` [PATCH v4 phy-next 8/9] soc: fsl: guts: implement the RCW override procedure Vladimir Oltean
@ 2026-07-22 11:01 ` Ioana Ciornei
0 siblings, 0 replies; 16+ messages in thread
From: Ioana Ciornei @ 2026-07-22 11:01 UTC (permalink / raw)
To: Vladimir Oltean
Cc: linux-phy, devicetree, linuxppc-dev, linux-arm-kernel, Vinod Koul,
Neil Armstrong, Tanjeff Moos, Christophe Leroy (CS GROUP),
Michael Walle, Shawn Guo, Frank Li, linux-kernel
On Wed, Jul 22, 2026 at 02:16:02AM +0300, Vladimir Oltean wrote:
> Add support for the RCW override procedure which enables runtime
> reconfiguration of the protocol running on a SerDes lane. The procedure
> is done through the DCFG DCSR space which now can be defined as the
> second memory region of the guts DT node.
> Support is added on the following SoCs: LS1046A, LS1088A, LS2088A.
>
> The procedure is exported to the "client" driver - the Lynx10G SerDes
> PHY driver - through the following functions:
> - fsl_guts_lane_validate() used to validate that changing the protocol
> on a specific lane is supported.
> - fsl_guts_lane_set_mode() which can be used to request the RCW
> procedure be executed for a specific lane.
>
> Since the RCW override procedure is different depending on the SoC, the
> private fsl_soc_data structure is updated with two new per SoC callbacks
> (.serdes_get_rcw_override() and .serdes_init_rcwcr()) which get used
> from the generic fsl_guts_lane_set_mode() function. These two callbacks
> hide all the SoC specific register offsets, masks and values so that the
> _set_mode() procedure is straightforward.
>
> Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Ioana Ciornei <ioana.ciornei@nxp.com>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v4 phy-next 9/9] phy: lynx-10g: use RCW override procedure for dynamic protocol change
2026-07-21 23:16 ` [PATCH v4 phy-next 9/9] phy: lynx-10g: use RCW override procedure for dynamic protocol change Vladimir Oltean
@ 2026-07-22 11:03 ` Ioana Ciornei
0 siblings, 0 replies; 16+ messages in thread
From: Ioana Ciornei @ 2026-07-22 11:03 UTC (permalink / raw)
To: Vladimir Oltean
Cc: linux-phy, devicetree, linuxppc-dev, linux-arm-kernel, Vinod Koul,
Neil Armstrong, Tanjeff Moos, Christophe Leroy (CS GROUP),
Michael Walle, Shawn Guo, Frank Li, linux-kernel
On Wed, Jul 22, 2026 at 02:16:03AM +0300, Vladimir Oltean wrote:
> Up until this patch, the only protocol change supported was between
> 1000Base-X/SGMII and 2500Base-X. The others require an RCW override
> procedure which was lacking.
>
> Since now the guts driver provides the means of applying this procedure,
> make use of it and remove any comment which mentioned the limitation.
>
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Ioana Ciornei <ioana.ciornei@nxp.com>
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2026-07-22 11:03 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-21 23:15 [PATCH v4 phy-next 0/9] RCW override for 10G Lynx dynamic protocol reconfiguration Vladimir Oltean
2026-07-21 23:15 ` [PATCH v4 phy-next 1/9] soc: fsl: guts: perform fsl_guts_init() error teardown in reverse order of setup Vladimir Oltean
2026-07-22 7:18 ` Michael Walle
2026-07-22 7:55 ` Vladimir Oltean
2026-07-22 9:15 ` Ioana Ciornei
2026-07-21 23:15 ` [PATCH v4 phy-next 2/9] soc: fsl: guts: use a macro to encode the DCFG CCSR space Vladimir Oltean
2026-07-21 23:15 ` [PATCH v4 phy-next 3/9] soc: fsl: guts: add a global structure to hold state Vladimir Oltean
2026-07-21 23:15 ` [PATCH v4 phy-next 4/9] soc: fsl: guts: add a central fsl_guts_read() function Vladimir Oltean
2026-07-21 23:15 ` [PATCH v4 phy-next 5/9] soc: fsl: guts: make it easier to determine on which SoC we are running Vladimir Oltean
2026-07-21 23:16 ` [PATCH v4 phy-next 6/9] soc: fsl: guts: make fsl_soc_data available after fsl_guts_init() Vladimir Oltean
2026-07-22 9:19 ` Ioana Ciornei
2026-07-21 23:16 ` [PATCH v4 phy-next 7/9] dt-bindings: fsl: layerscape-dcfg: define DCFG_DCSR region Vladimir Oltean
2026-07-21 23:16 ` [PATCH v4 phy-next 8/9] soc: fsl: guts: implement the RCW override procedure Vladimir Oltean
2026-07-22 11:01 ` Ioana Ciornei
2026-07-21 23:16 ` [PATCH v4 phy-next 9/9] phy: lynx-10g: use RCW override procedure for dynamic protocol change Vladimir Oltean
2026-07-22 11:03 ` Ioana Ciornei
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox