ARM: mvebu: introduce CPU reset code
[firefly-linux-kernel-4.4.55.git] / arch / arm / mach-mvebu / cpu-reset.c
diff --git a/arch/arm/mach-mvebu/cpu-reset.c b/arch/arm/mach-mvebu/cpu-reset.c
new file mode 100644 (file)
index 0000000..4ff4ce7
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2014 Marvell
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) "mvebu-cpureset: " fmt
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/of_address.h>
+#include <linux/io.h>
+#include <linux/resource.h>
+#include "armada-370-xp.h"
+
+static void __iomem *cpu_reset_base;
+static size_t cpu_reset_size;
+
+#define CPU_RESET_OFFSET(cpu) (cpu * 0x8)
+#define CPU_RESET_ASSERT      BIT(0)
+
+int mvebu_cpu_reset_deassert(int cpu)
+{
+       u32 reg;
+
+       if (!cpu_reset_base)
+               return -ENODEV;
+
+       if (CPU_RESET_OFFSET(cpu) >= cpu_reset_size)
+               return -EINVAL;
+
+       reg = readl(cpu_reset_base + CPU_RESET_OFFSET(cpu));
+       reg &= ~CPU_RESET_ASSERT;
+       writel(reg, cpu_reset_base + CPU_RESET_OFFSET(cpu));
+
+       return 0;
+}
+
+static int __init mvebu_cpu_reset_init(void)
+{
+       struct device_node *np;
+       struct resource res;
+       int ret = 0;
+
+       np = of_find_compatible_node(NULL, NULL,
+                                    "marvell,armada-370-cpu-reset");
+       if (!np)
+               return 0;
+
+       if (of_address_to_resource(np, 0, &res)) {
+               pr_err("unable to get resource\n");
+               ret = -ENOENT;
+               goto out;
+       }
+
+       if (!request_mem_region(res.start, resource_size(&res),
+                               np->full_name)) {
+               pr_err("unable to request region\n");
+               ret = -EBUSY;
+               goto out;
+       }
+
+       cpu_reset_base = ioremap(res.start, resource_size(&res));
+       if (!cpu_reset_base) {
+               pr_err("unable to map registers\n");
+               release_mem_region(res.start, resource_size(&res));
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       cpu_reset_size = resource_size(&res);
+
+out:
+       of_node_put(np);
+       return ret;
+}
+
+early_initcall(mvebu_cpu_reset_init);