arm: mach-mvebu: add source files
[firefly-linux-kernel-4.4.55.git] / arch / arm / mach-mvebu / system-controller.c
diff --git a/arch/arm/mach-mvebu/system-controller.c b/arch/arm/mach-mvebu/system-controller.c
new file mode 100644 (file)
index 0000000..b8079df
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * System controller support for Armada 370 and XP platforms.
+ *
+ * Copyright (C) 2012 Marvell
+ *
+ * Lior Amsalem <alior@marvell.com>
+ * Gregory CLEMENT <gregory.clement@free-electrons.com>
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ *
+ * The Armada 370 and Armada XP SoCs both have a range of
+ * miscellaneous registers, that do not belong to a particular device,
+ * but rather provide system-level features. This basic
+ * system-controller driver provides a device tree binding for those
+ * registers, and implements utility functions offering various
+ * features related to those registers.
+ *
+ * For now, the feature set is limited to restarting the platform by a
+ * soft-reset, but it might be extended in the future.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/of_address.h>
+#include <linux/io.h>
+
+static void __iomem *system_controller_base;
+
+struct mvebu_system_controller {
+       u32 rstoutn_mask_offset;
+       u32 system_soft_reset_offset;
+
+       u32 rstoutn_mask_reset_out_en;
+       u32 system_soft_reset;
+};
+static struct mvebu_system_controller *mvebu_sc;
+
+const struct mvebu_system_controller armada_370_xp_system_controller = {
+       .rstoutn_mask_offset = 0x60,
+       .system_soft_reset_offset = 0x64,
+       .rstoutn_mask_reset_out_en = 0x1,
+       .system_soft_reset = 0x1,
+};
+
+const struct mvebu_system_controller orion_system_controller = {
+       .rstoutn_mask_offset = 0x108,
+       .system_soft_reset_offset = 0x10c,
+       .rstoutn_mask_reset_out_en = 0x4,
+       .system_soft_reset = 0x1,
+};
+
+static struct of_device_id of_system_controller_table[] = {
+       {
+               .compatible = "marvell,orion-system-controller",
+               .data = (void *) &orion_system_controller,
+       }, {
+               .compatible = "marvell,armada-370-xp-system-controller",
+               .data = (void *) &armada_370_xp_system_controller,
+       },
+       { /* end of list */ },
+};
+
+void mvebu_restart(char mode, const char *cmd)
+{
+       if (!system_controller_base) {
+               pr_err("Cannot restart, system-controller not available: check the device tree\n");
+       } else {
+               /*
+                * Enable soft reset to assert RSTOUTn.
+                */
+               writel(mvebu_sc->rstoutn_mask_reset_out_en,
+                       system_controller_base +
+                       mvebu_sc->rstoutn_mask_offset);
+               /*
+                * Assert soft reset.
+                */
+               writel(mvebu_sc->system_soft_reset,
+                       system_controller_base +
+                       mvebu_sc->system_soft_reset_offset);
+       }
+
+       while (1)
+               ;
+}
+
+static int __init mvebu_system_controller_init(void)
+{
+       struct device_node *np;
+
+       np = of_find_matching_node(NULL, of_system_controller_table);
+       if (np) {
+               const struct of_device_id *match =
+                   of_match_node(of_system_controller_table, np);
+               BUG_ON(!match);
+               system_controller_base = of_iomap(np, 0);
+               mvebu_sc = (struct mvebu_system_controller *)match->data;
+       }
+
+       return 0;
+}
+
+arch_initcall(mvebu_system_controller_init);