[PATCH v1 08/10] reset: add Microchip sparx5 / LAN969X / LAN966X switch reset driver
Oleksij Rempel
o.rempel at pengutronix.de
Thu Jun 11 22:59:24 PDT 2026
Add the reset controller for the Microchip sparx5 / LAN969X / LAN966X
switch SoCs. The reset is asserted once at probe time so downstream
peripherals (SGPIO, MDIO, switch core) come up against a clean IP
state instead of inheriting whatever the previous boot stage left.
Ported from Linux drivers/reset/reset-microchip-sparx5.c at tag
v7.1-rc7
Signed-off-by: Oleksij Rempel <o.rempel at pengutronix.de>
---
drivers/reset/Kconfig | 10 ++
drivers/reset/Makefile | 1 +
drivers/reset/reset-microchip-sparx5.c | 170 +++++++++++++++++++++++++
3 files changed, 181 insertions(+)
create mode 100644 drivers/reset/reset-microchip-sparx5.c
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index c3779f087490..1819da73b27f 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -63,4 +63,14 @@ config RESET_SOCFPGA32
help
This enables the reset controller driver for 32-bit SoCFPGA platforms.
+config RESET_MICROCHIP_SPARX5
+ bool "Microchip Sparx5 / LAN969X / LAN966X switch reset driver"
+ depends on OFDEVICE
+ select MFD_SYSCON
+ help
+ This enables the switch reset controller driver for the Microchip
+ Sparx5 / LAN969X / LAN966X switch SoCs. The reset is asserted once
+ at probe time so downstream peripherals (SGPIO, MDIO, switch core)
+ see a clean IP state.
+
endif
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index a446cb20d0b7..b5540252bc9a 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_RESET_SOCFPGA32) += reset-socfpga.o
obj-$(CONFIG_RESET_IMX7) += reset-imx7.o
obj-$(CONFIG_RESET_STARFIVE) += reset-starfive-vic.o
obj-$(CONFIG_RESET_SCMI) += reset-scmi.o
+obj-$(CONFIG_RESET_MICROCHIP_SPARX5) += reset-microchip-sparx5.o
diff --git a/drivers/reset/reset-microchip-sparx5.c b/drivers/reset/reset-microchip-sparx5.c
new file mode 100644
index 000000000000..8944e3fc1510
--- /dev/null
+++ b/drivers/reset/reset-microchip-sparx5.c
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Microchip Sparx5 / LAN969X / LAN966X Switch Reset driver
+ *
+ * Copyright (c) 2020 Microchip Technology Inc. and its subsidiaries.
+ *
+ * Ported from Linux drivers/reset/reset-microchip-sparx5.c. Identifiers,
+ * struct layouts and per-SoC props are kept aligned with Linux so future
+ * fixes can be backported with minimal context churn.
+ */
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <io.h>
+#include <of.h>
+#include <linux/err.h>
+#include <linux/iopoll.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+#include <mfd/syscon.h>
+
+struct reset_props {
+ u32 protect_reg;
+ u32 protect_bit;
+ u32 reset_reg;
+ u32 reset_bit;
+};
+
+struct mchp_reset_context {
+ struct regmap *cpu_ctrl;
+ struct regmap *gcb_ctrl;
+ struct reset_controller_dev rcdev;
+ const struct reset_props *props;
+};
+
+static const struct regmap_config sparx5_reset_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
+static int sparx5_switch_reset(struct mchp_reset_context *ctx)
+{
+ u32 val;
+
+ /* Make sure the core is PROTECTED from reset */
+ regmap_update_bits(ctx->cpu_ctrl, ctx->props->protect_reg,
+ ctx->props->protect_bit, ctx->props->protect_bit);
+
+ /* Start soft reset */
+ regmap_write(ctx->gcb_ctrl, ctx->props->reset_reg,
+ ctx->props->reset_bit);
+
+ /* Wait for soft reset done */
+ return regmap_read_poll_timeout(ctx->gcb_ctrl, ctx->props->reset_reg,
+ val,
+ (val & ctx->props->reset_bit) == 0,
+ 100);
+}
+
+static int sparx5_reset_noop(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ return 0;
+}
+
+static const struct reset_control_ops sparx5_reset_ops = {
+ .reset = sparx5_reset_noop,
+};
+
+static int mchp_sparx5_reset_probe(struct device *dev)
+{
+ struct device_node *dn = dev->of_node;
+ struct mchp_reset_context *ctx;
+ struct device_node *syscon_np;
+ struct resource *iores;
+ void __iomem *base;
+ int ret;
+
+ ctx = xzalloc(sizeof(*ctx));
+
+ syscon_np = of_parse_phandle(dn, "cpu-syscon", 0);
+ if (!syscon_np) {
+ dev_err(dev, "missing 'cpu-syscon' phandle\n");
+ ret = -ENODEV;
+ goto err;
+ }
+ ctx->cpu_ctrl = syscon_node_to_regmap(syscon_np);
+ if (IS_ERR(ctx->cpu_ctrl)) {
+ dev_err(dev, "failed to map cpu-syscon: %pe\n", ctx->cpu_ctrl);
+ ret = PTR_ERR(ctx->cpu_ctrl);
+ goto err;
+ }
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores)) {
+ ret = PTR_ERR(iores);
+ goto err;
+ }
+ base = IOMEM(iores->start);
+ ctx->gcb_ctrl = regmap_init_mmio(dev, base, &sparx5_reset_regmap_config);
+ if (IS_ERR(ctx->gcb_ctrl)) {
+ ret = PTR_ERR(ctx->gcb_ctrl);
+ goto err;
+ }
+
+ ctx->props = device_get_match_data(dev);
+ if (!ctx->props) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ctx->rcdev.nr_resets = 1;
+ ctx->rcdev.ops = &sparx5_reset_ops;
+ ctx->rcdev.of_node = dn;
+
+ /*
+ * Issue the reset very early; reset_control_reset() callers see a
+ * no-op afterwards.
+ */
+ ret = sparx5_switch_reset(ctx);
+ if (ret) {
+ dev_err(dev, "switch reset timed out: %d\n", ret);
+ goto err;
+ }
+
+ ret = reset_controller_register(&ctx->rcdev);
+ if (ret)
+ goto err;
+
+ dev_info(dev, "switch reset complete\n");
+ return 0;
+
+err:
+ free(ctx);
+ return ret;
+}
+
+static const struct reset_props reset_props_sparx5 = {
+ .protect_reg = 0x84,
+ .protect_bit = BIT(10),
+ .reset_reg = 0x0,
+ .reset_bit = BIT(1),
+};
+
+static const struct reset_props reset_props_lan966x = {
+ .protect_reg = 0x88,
+ .protect_bit = BIT(5),
+ .reset_reg = 0x0,
+ .reset_bit = BIT(1),
+};
+
+static const struct of_device_id mchp_sparx5_reset_of_match[] = {
+ { .compatible = "microchip,sparx5-switch-reset",
+ .data = &reset_props_sparx5 },
+ { .compatible = "microchip,lan966x-switch-reset",
+ .data = &reset_props_lan966x },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mchp_sparx5_reset_of_match);
+
+static struct driver mchp_sparx5_reset_driver = {
+ .name = "sparx5-switch-reset",
+ .probe = mchp_sparx5_reset_probe,
+ .of_compatible = DRV_OF_COMPAT(mchp_sparx5_reset_of_match),
+};
+/*
+ * Same rationale as Linux's postcore_initcall(): the switch IP must be
+ * reset before downstream consumers (SGPIO, MDIO, switch fabric) probe.
+ */
+coredevice_platform_driver(mchp_sparx5_reset_driver);
--
2.47.3
More information about the barebox
mailing list