summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-uniphier/platsmp.c
blob: 5943e1cb7fe14d9e1140a1ccf1df02eb008715bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/*
 * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/sizes.h>
#include <linux/compiler.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
#include <asm/smp.h>
#include <asm/smp_scu.h>

static struct regmap *sbcm_regmap;

static void __init uniphier_smp_prepare_cpus(unsigned int max_cpus)
{
	static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 };
	unsigned long scu_base_phys = 0;
	void __iomem *scu_base;

	sbcm_regmap = syscon_regmap_lookup_by_compatible(
			"socionext,uniphier-system-bus-controller-misc");
	if (IS_ERR(sbcm_regmap)) {
		pr_err("failed to regmap system-bus-controller-misc\n");
		goto err;
	}

	if (scu_a9_has_base())
		scu_base_phys = scu_a9_get_base();

	if (!scu_base_phys) {
		pr_err("failed to get scu base\n");
		goto err;
	}

	scu_base = ioremap(scu_base_phys, SZ_128);
	if (!scu_base) {
		pr_err("failed to remap scu base (0x%08lx)\n", scu_base_phys);
		goto err;
	}

	scu_enable(scu_base);
	iounmap(scu_base);

	return;
err:
	pr_warn("disabling SMP\n");
	init_cpu_present(&only_cpu_0);
	sbcm_regmap = NULL;
}

static void __naked uniphier_secondary_startup(void)
{
	asm("bl		v7_invalidate_l1\n"
	    "b		secondary_startup\n");
};

static int uniphier_boot_secondary(unsigned int cpu,
				   struct task_struct *idle)
{
	int ret;

	if (!sbcm_regmap)
		return -ENODEV;

	ret = regmap_write(sbcm_regmap, 0x1208,
			   virt_to_phys(uniphier_secondary_startup));
	if (!ret)
		asm("sev"); /* wake up secondary CPU */

	return ret;
}

struct smp_operations uniphier_smp_ops __initdata = {
	.smp_prepare_cpus	= uniphier_smp_prepare_cpus,
	.smp_boot_secondary	= uniphier_boot_secondary,
};
CPU_METHOD_OF_DECLARE(uniphier_smp, "socionext,uniphier-smp",
		      &uniphier_smp_ops);