]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
power: reset: Add a driver for the Microsemi Ocelot reset
authorAlexandre Belloni <alexandre.belloni@free-electrons.com>
Tue, 16 Jan 2018 10:12:35 +0000 (11:12 +0100)
committerSebastian Reichel <sre@kernel.org>
Mon, 12 Feb 2018 10:23:46 +0000 (11:23 +0100)
The Microsemi Ocelot SoC has a register allowing to reset the MIPS core.
Unfortunately, the syscon-reboot driver can't be used directly (but almost)
as the reset control may be disabled using another register.

Cc: linux-pm@vger.kernel.org
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>
drivers/power/reset/Kconfig
drivers/power/reset/Makefile
drivers/power/reset/ocelot-reset.c [new file with mode: 0644]

index a102e74ab24e5e1d19d1f60c9977e06875b0c2a9..176bd6df1238e73e31bd91b5a5e1ae2da50866a7 100644 (file)
@@ -104,6 +104,13 @@ config POWER_RESET_MSM
        help
          Power off and restart support for Qualcomm boards.
 
+config POWER_RESET_OCELOT_RESET
+       bool "Microsemi Ocelot reset driver"
+       depends on MSCC_OCELOT || COMPILE_TEST
+       select MFD_SYSCON
+       help
+         This driver supports restart for Microsemi Ocelot SoC.
+
 config POWER_RESET_PIIX4_POWEROFF
        tristate "Intel PIIX4 power-off driver"
        depends on PCI
index dcc92f5f7a37d9b3934b2c7baa3020d69d36d4cd..6b9eb139317958694d673b06c001b7e101023fb4 100644 (file)
@@ -11,6 +11,7 @@ obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
 obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o
 obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o
 obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
+obj-$(CONFIG_POWER_RESET_OCELOT_RESET) += ocelot-reset.o
 obj-$(CONFIG_POWER_RESET_PIIX4_POWEROFF) += piix4-poweroff.o
 obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o
 obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
diff --git a/drivers/power/reset/ocelot-reset.c b/drivers/power/reset/ocelot-reset.c
new file mode 100644 (file)
index 0000000..5a13a5c
--- /dev/null
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Microsemi MIPS SoC reset driver
+ *
+ * License: Dual MIT/GPL
+ * Copyright (c) 2017 Microsemi Corporation
+ */
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/notifier.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/regmap.h>
+
+struct ocelot_reset_context {
+       void __iomem *base;
+       struct regmap *cpu_ctrl;
+       struct notifier_block restart_handler;
+};
+
+#define ICPU_CFG_CPU_SYSTEM_CTRL_RESET 0x20
+#define CORE_RST_PROTECT BIT(2)
+
+#define SOFT_CHIP_RST BIT(0)
+
+static int ocelot_restart_handle(struct notifier_block *this,
+                                unsigned long mode, void *cmd)
+{
+       struct ocelot_reset_context *ctx = container_of(this, struct
+                                                       ocelot_reset_context,
+                                                       restart_handler);
+
+       /* Make sure the core is not protected from reset */
+       regmap_update_bits(ctx->cpu_ctrl, ICPU_CFG_CPU_SYSTEM_CTRL_RESET,
+                          CORE_RST_PROTECT, 0);
+
+       writel(SOFT_CHIP_RST, ctx->base);
+
+       pr_emerg("Unable to restart system\n");
+       return NOTIFY_DONE;
+}
+
+static int ocelot_reset_probe(struct platform_device *pdev)
+{
+       struct ocelot_reset_context *ctx;
+       struct resource *res;
+
+       struct device *dev = &pdev->dev;
+       int err;
+
+       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       ctx->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(ctx->base))
+               return PTR_ERR(ctx->base);
+
+       ctx->cpu_ctrl = syscon_regmap_lookup_by_compatible("mscc,ocelot-cpu-syscon");
+       if (IS_ERR(ctx->cpu_ctrl))
+               return PTR_ERR(ctx->cpu_ctrl);
+
+       ctx->restart_handler.notifier_call = ocelot_restart_handle;
+       ctx->restart_handler.priority = 192;
+       err = register_restart_handler(&ctx->restart_handler);
+       if (err)
+               dev_err(dev, "can't register restart notifier (err=%d)\n", err);
+
+       return err;
+}
+
+static const struct of_device_id ocelot_reset_of_match[] = {
+       { .compatible = "mscc,ocelot-chip-reset" },
+       {}
+};
+
+static struct platform_driver ocelot_reset_driver = {
+       .probe = ocelot_reset_probe,
+       .driver = {
+               .name = "ocelot-chip-reset",
+               .of_match_table = ocelot_reset_of_match,
+       },
+};
+builtin_platform_driver(ocelot_reset_driver);