[PATCH 3/5] soc: fsl: guts: add the RCW override of any RCWSR
Vincent Jardin via B4 Relay
devnull+vjardin.free.fr at kernel.org
Tue Nov 3 01:51:56 PST 2026
From: Vincent Jardin <vjardin at free.fr>
fsl_guts_rcw_rmw() only serves the SerDes lane modes. Export it for
other fields of the RCW:
- fsl_guts_rcw_read() reads a status register
- fsl_guts_rcw_override() changes fields of one under rcwcr_lock and
waits for the status register to follow
- fsl_guts_rcw_override_supported() tells whether the DCSR view of DCFG,
which holds the override registers, is mapped
Signed-off-by: Vincent Jardin <vjardin at free.fr>
---
drivers/soc/fsl/guts.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/fsl/guts.h | 3 ++
2 files changed, 76 insertions(+)
diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
index 28361c63e26c..d2e3f66d0da4 100644
--- a/drivers/soc/fsl/guts.c
+++ b/drivers/soc/fsl/guts.c
@@ -369,6 +369,79 @@ int fsl_guts_lane_set_mode(int serdes_idx, int lane, enum lynx_lane_mode lane_mo
}
EXPORT_SYMBOL_NS_GPL(fsl_guts_lane_set_mode, "FSL_GUTS");
+/**
+ * fsl_guts_rcw_read() - read a RCW status register
+ * @index: one-based index, RCWSR1 to RCWSR32
+ * @val: the value read
+ *
+ * Return: 0 on success, -ENODEV before the DCFG block is mapped,
+ * -EINVAL when @index is not 1 to 32
+ */
+int fsl_guts_rcw_read(unsigned int index, u32 *val)
+{
+ if (!soc.dcfg_ccsr)
+ return -ENODEV;
+ if (index < 1 || index > ARRAY_SIZE(soc.dcfg_ccsr->rcwsr))
+ return -EINVAL;
+
+ *val = fsl_guts_read(&soc.dcfg_ccsr->rcwsr[index - 1]);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(fsl_guts_rcw_read, "FSL_GUTS");
+
+/**
+ * fsl_guts_rcw_override() - override fields of a RCW
+ * @index: one-based index of the RCWSR and RCWCR pair
+ * @val: the new value of the fields, in place
+ * @mask: the fields to change
+ *
+ * The fields outside @mask keep the value the status register shows. The
+ * override register is written and the status register polled until it
+ * shows the result, as fsl_guts_lane_set_mode() does for a SerDes lane.
+ *
+ * Context: takes rcwcr_lock, shared with fsl_guts_lane_set_mode(), and
+ * busy-polls the status register for up to RCW_TIMEOUT_US. Does not
+ * sleep; must not be called from interrupt context.
+ *
+ * Return: 0 on success, -EOPNOTSUPP without a DCSR mapping of DCFG,
+ * negative error otherwise
+ */
+int fsl_guts_rcw_override(unsigned int index, u32 val, u32 mask)
+{
+ int err;
+
+ if (!soc.dcfg_ccsr)
+ return -ENODEV;
+ if (!soc.dcfg_dcsr)
+ return -EOPNOTSUPP;
+ if (index < 1 || index > ARRAY_SIZE(soc.dcfg_ccsr->rcwsr))
+ return -EINVAL;
+
+ spin_lock(&soc.rcwcr_lock);
+ err = fsl_guts_rcw_rmw(index - 1, val & mask, mask);
+ spin_unlock(&soc.rcwcr_lock);
+ if (err)
+ pr_err("RCW override of RCWSR%u failed: %pe\n", index,
+ ERR_PTR(err));
+
+ return err;
+}
+EXPORT_SYMBOL_NS_GPL(fsl_guts_rcw_override, "FSL_GUTS");
+
+/**
+ * fsl_guts_rcw_override_supported() - can a Reset Configuration Word be
+ * overridden?
+ *
+ * Return: true when the DCFG block is mapped with its DCSR view, the
+ * second reg of the dcfg node, which holds the override registers
+ */
+bool fsl_guts_rcw_override_supported(void)
+{
+ return soc.dcfg_ccsr && soc.dcfg_dcsr;
+}
+EXPORT_SYMBOL_NS_GPL(fsl_guts_rcw_override_supported, "FSL_GUTS");
+
static u64 fsl_guts_get_soc_uid(const char *compat, unsigned int offset)
{
struct device_node *np;
diff --git a/include/linux/fsl/guts.h b/include/linux/fsl/guts.h
index 8d5ffb985fee..7127de897c23 100644
--- a/include/linux/fsl/guts.h
+++ b/include/linux/fsl/guts.h
@@ -142,6 +142,9 @@ 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);
+int fsl_guts_rcw_read(unsigned int index, u32 *val);
+int fsl_guts_rcw_override(unsigned int index, u32 val, u32 mask);
+bool fsl_guts_rcw_override_supported(void);
/* Alternate function signal multiplex control */
#define MPC85xx_PMUXCR_QE(x) (0x8000 >> (x))
--
2.43.0
More information about the linux-arm-kernel
mailing list