mirror of
https://github.com/torvalds/linux.git
synced 2024-12-05 02:23:16 +00:00
49754ffef5
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: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> Link: https://lkml.kernel.org/r/1397483433-25836-3-git-send-email-thomas.petazzoni@free-electrons.com Acked-by: Gregory CLEMENT <gregory.clement@free-electrons.com> Signed-off-by: Jason Cooper <jason@lakedaemon.net>
104 lines
2.1 KiB
C
104 lines
2.1 KiB
C
/*
|
|
* 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 mvebu_cpu_reset_map(struct device_node *np, int res_idx)
|
|
{
|
|
struct resource res;
|
|
|
|
if (of_address_to_resource(np, res_idx, &res)) {
|
|
pr_err("unable to get resource\n");
|
|
return -ENOENT;
|
|
}
|
|
|
|
if (!request_mem_region(res.start, resource_size(&res),
|
|
np->full_name)) {
|
|
pr_err("unable to request region\n");
|
|
return -EBUSY;
|
|
}
|
|
|
|
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));
|
|
return -ENOMEM;
|
|
}
|
|
|
|
cpu_reset_size = resource_size(&res);
|
|
|
|
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);
|
|
|
|
return ret;
|
|
}
|
|
|
|
early_initcall(mvebu_cpu_reset_init);
|