Commit 49754ffe authored by Thomas Petazzoni's avatar Thomas Petazzoni Committed by Jason Cooper

ARM: mvebu: start using the CPU reset driver

This commit changes the PMSU driver to no longer map itself the CPU
reset registers, and instead call into the CPU reset driver to
deassert the secondary CPUs for SMP booting.

In order to provide Device Tree backward compatibility, the CPU reset
driver is extended to not only support its official compatible string
"marvell,armada-370-cpu-reset", but to also look at the PMSU
compatible string "marvell,armada-370-xp-pmsu" to find the CPU reset
registers address. This allows old Device Tree to work correctly with
newer kernel versions. Therefore, the CPU reset driver implements the
following logic:

 * If one of the normal compatible strings
   "marvell,armada-370-cpu-reset" is found, then we map its first
   memory resource as the CPU reset registers.

 * Otherwise, if none of the normal compatible strings have been
   found, we look for the "marvell,armada-370-xp-pmsu" compatible
   string, and we map the second memory as the CPU reset registers.
Signed-off-by: default avatarThomas Petazzoni <thomas.petazzoni@free-electrons.com>
Link: https://lkml.kernel.org/r/1397483433-25836-3-git-send-email-thomas.petazzoni@free-electrons.comAcked-by: default avatarGregory CLEMENT <gregory.clement@free-electrons.com>
Signed-off-by: default avatarJason Cooper <jason@lakedaemon.net>
parent 3f20fb11
...@@ -40,42 +40,63 @@ int mvebu_cpu_reset_deassert(int cpu) ...@@ -40,42 +40,63 @@ int mvebu_cpu_reset_deassert(int cpu)
return 0; return 0;
} }
static int __init mvebu_cpu_reset_init(void) static int mvebu_cpu_reset_map(struct device_node *np, int res_idx)
{ {
struct device_node *np;
struct resource res; 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)) { if (of_address_to_resource(np, res_idx, &res)) {
pr_err("unable to get resource\n"); pr_err("unable to get resource\n");
ret = -ENOENT; return -ENOENT;
goto out;
} }
if (!request_mem_region(res.start, resource_size(&res), if (!request_mem_region(res.start, resource_size(&res),
np->full_name)) { np->full_name)) {
pr_err("unable to request region\n"); pr_err("unable to request region\n");
ret = -EBUSY; return -EBUSY;
goto out;
} }
cpu_reset_base = ioremap(res.start, resource_size(&res)); cpu_reset_base = ioremap(res.start, resource_size(&res));
if (!cpu_reset_base) { if (!cpu_reset_base) {
pr_err("unable to map registers\n"); pr_err("unable to map registers\n");
release_mem_region(res.start, resource_size(&res)); release_mem_region(res.start, resource_size(&res));
ret = -ENOMEM; return -ENOMEM;
goto out;
} }
cpu_reset_size = resource_size(&res); cpu_reset_size = resource_size(&res);
out: return 0;
}
int __init mvebu_cpu_reset_init(void)
{
struct device_node *np;
int res_idx;
int ret;
np = of_find_compatible_node(NULL, NULL,
"marvell,armada-370-cpu-reset");
if (np) {
res_idx = 0;
} else {
/*
* This code is kept for backward compatibility with
* old Device Trees.
*/
np = of_find_compatible_node(NULL, NULL,
"marvell,armada-370-xp-pmsu");
if (np) {
pr_warn(FW_WARN "deprecated pmsu binding\n");
res_idx = 1;
}
}
/* No reset node found */
if (!np)
return -ENODEV;
ret = mvebu_cpu_reset_map(np, res_idx);
of_node_put(np); of_node_put(np);
return ret; return ret;
} }
......
...@@ -21,14 +21,14 @@ ...@@ -21,14 +21,14 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/resource.h>
#include <asm/smp_plat.h> #include <asm/smp_plat.h>
#include "common.h"
#include "pmsu.h" #include "pmsu.h"
static void __iomem *pmsu_mp_base; static void __iomem *pmsu_mp_base;
static void __iomem *pmsu_reset_base;
#define PMSU_BOOT_ADDR_REDIRECT_OFFSET(cpu) ((cpu * 0x100) + 0x24) #define PMSU_BOOT_ADDR_REDIRECT_OFFSET(cpu) ((cpu * 0x100) + 0x24)
#define PMSU_RESET_CTL_OFFSET(cpu) (cpu * 0x8)
static struct of_device_id of_pmsu_table[] = { static struct of_device_id of_pmsu_table[] = {
{.compatible = "marvell,armada-370-xp-pmsu"}, {.compatible = "marvell,armada-370-xp-pmsu"},
...@@ -38,11 +38,11 @@ static struct of_device_id of_pmsu_table[] = { ...@@ -38,11 +38,11 @@ static struct of_device_id of_pmsu_table[] = {
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
int armada_xp_boot_cpu(unsigned int cpu_id, void *boot_addr) int armada_xp_boot_cpu(unsigned int cpu_id, void *boot_addr)
{ {
int reg, hw_cpu; int hw_cpu, ret;
if (!pmsu_mp_base || !pmsu_reset_base) { if (!pmsu_mp_base) {
pr_warn("Can't boot CPU. PMSU is uninitialized\n"); pr_warn("Can't boot CPU. PMSU is uninitialized\n");
return 1; return -ENODEV;
} }
hw_cpu = cpu_logical_map(cpu_id); hw_cpu = cpu_logical_map(cpu_id);
...@@ -50,10 +50,11 @@ int armada_xp_boot_cpu(unsigned int cpu_id, void *boot_addr) ...@@ -50,10 +50,11 @@ int armada_xp_boot_cpu(unsigned int cpu_id, void *boot_addr)
writel(virt_to_phys(boot_addr), pmsu_mp_base + writel(virt_to_phys(boot_addr), pmsu_mp_base +
PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu)); PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu));
/* Release CPU from reset by clearing reset bit*/ ret = mvebu_cpu_reset_deassert(hw_cpu);
reg = readl(pmsu_reset_base + PMSU_RESET_CTL_OFFSET(hw_cpu)); if (ret) {
reg &= (~0x1); pr_warn("unable to boot CPU: %d\n", ret);
writel(reg, pmsu_reset_base + PMSU_RESET_CTL_OFFSET(hw_cpu)); return ret;
}
return 0; return 0;
} }
...@@ -67,7 +68,6 @@ static int __init armada_370_xp_pmsu_init(void) ...@@ -67,7 +68,6 @@ static int __init armada_370_xp_pmsu_init(void)
if (np) { if (np) {
pr_info("Initializing Power Management Service Unit\n"); pr_info("Initializing Power Management Service Unit\n");
pmsu_mp_base = of_iomap(np, 0); pmsu_mp_base = of_iomap(np, 0);
pmsu_reset_base = of_iomap(np, 1);
of_node_put(np); of_node_put(np);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment