xref: /OK3568_Linux_fs/kernel/arch/arm/mach-berlin/platsmp.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2014 Marvell Technology Group Ltd.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Antoine Ténart <antoine.tenart@free-electrons.com>
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/io.h>
9*4882a593Smuzhiyun #include <linux/delay.h>
10*4882a593Smuzhiyun #include <linux/of.h>
11*4882a593Smuzhiyun #include <linux/of_address.h>
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <asm/cacheflush.h>
14*4882a593Smuzhiyun #include <asm/cp15.h>
15*4882a593Smuzhiyun #include <asm/memory.h>
16*4882a593Smuzhiyun #include <asm/smp_plat.h>
17*4882a593Smuzhiyun #include <asm/smp_scu.h>
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun /*
20*4882a593Smuzhiyun  * There are two reset registers, one with self-clearing (SC)
21*4882a593Smuzhiyun  * reset and one with non-self-clearing reset (NON_SC).
22*4882a593Smuzhiyun  */
23*4882a593Smuzhiyun #define CPU_RESET_SC		0x00
24*4882a593Smuzhiyun #define CPU_RESET_NON_SC	0x20
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #define RESET_VECT		0x00
27*4882a593Smuzhiyun #define SW_RESET_ADDR		0x94
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun extern u32 boot_inst;
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun static void __iomem *cpu_ctrl;
32*4882a593Smuzhiyun 
berlin_perform_reset_cpu(unsigned int cpu)33*4882a593Smuzhiyun static inline void berlin_perform_reset_cpu(unsigned int cpu)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun 	u32 val;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	val = readl(cpu_ctrl + CPU_RESET_NON_SC);
38*4882a593Smuzhiyun 	val &= ~BIT(cpu_logical_map(cpu));
39*4882a593Smuzhiyun 	writel(val, cpu_ctrl + CPU_RESET_NON_SC);
40*4882a593Smuzhiyun 	val |= BIT(cpu_logical_map(cpu));
41*4882a593Smuzhiyun 	writel(val, cpu_ctrl + CPU_RESET_NON_SC);
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun 
berlin_boot_secondary(unsigned int cpu,struct task_struct * idle)44*4882a593Smuzhiyun static int berlin_boot_secondary(unsigned int cpu, struct task_struct *idle)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun 	if (!cpu_ctrl)
47*4882a593Smuzhiyun 		return -EFAULT;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	/*
50*4882a593Smuzhiyun 	 * Reset the CPU, making it to execute the instruction in the reset
51*4882a593Smuzhiyun 	 * exception vector.
52*4882a593Smuzhiyun 	 */
53*4882a593Smuzhiyun 	berlin_perform_reset_cpu(cpu);
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	return 0;
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun 
berlin_smp_prepare_cpus(unsigned int max_cpus)58*4882a593Smuzhiyun static void __init berlin_smp_prepare_cpus(unsigned int max_cpus)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun 	struct device_node *np;
61*4882a593Smuzhiyun 	void __iomem *scu_base;
62*4882a593Smuzhiyun 	void __iomem *vectors_base;
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
65*4882a593Smuzhiyun 	scu_base = of_iomap(np, 0);
66*4882a593Smuzhiyun 	of_node_put(np);
67*4882a593Smuzhiyun 	if (!scu_base)
68*4882a593Smuzhiyun 		return;
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	np = of_find_compatible_node(NULL, NULL, "marvell,berlin-cpu-ctrl");
71*4882a593Smuzhiyun 	cpu_ctrl = of_iomap(np, 0);
72*4882a593Smuzhiyun 	of_node_put(np);
73*4882a593Smuzhiyun 	if (!cpu_ctrl)
74*4882a593Smuzhiyun 		goto unmap_scu;
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	vectors_base = ioremap(VECTORS_BASE, SZ_32K);
77*4882a593Smuzhiyun 	if (!vectors_base)
78*4882a593Smuzhiyun 		goto unmap_scu;
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	scu_enable(scu_base);
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	/*
83*4882a593Smuzhiyun 	 * Write the first instruction the CPU will execute after being reset
84*4882a593Smuzhiyun 	 * in the reset exception vector.
85*4882a593Smuzhiyun 	 */
86*4882a593Smuzhiyun 	writel(boot_inst, vectors_base + RESET_VECT);
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	/*
89*4882a593Smuzhiyun 	 * Write the secondary startup address into the SW reset address
90*4882a593Smuzhiyun 	 * vector. This is used by boot_inst.
91*4882a593Smuzhiyun 	 */
92*4882a593Smuzhiyun 	writel(__pa_symbol(secondary_startup), vectors_base + SW_RESET_ADDR);
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	iounmap(vectors_base);
95*4882a593Smuzhiyun unmap_scu:
96*4882a593Smuzhiyun 	iounmap(scu_base);
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun #ifdef CONFIG_HOTPLUG_CPU
berlin_cpu_die(unsigned int cpu)100*4882a593Smuzhiyun static void berlin_cpu_die(unsigned int cpu)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun 	v7_exit_coherency_flush(louis);
103*4882a593Smuzhiyun 	while (1)
104*4882a593Smuzhiyun 		cpu_do_idle();
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun 
berlin_cpu_kill(unsigned int cpu)107*4882a593Smuzhiyun static int berlin_cpu_kill(unsigned int cpu)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun 	u32 val;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	val = readl(cpu_ctrl + CPU_RESET_NON_SC);
112*4882a593Smuzhiyun 	val &= ~BIT(cpu_logical_map(cpu));
113*4882a593Smuzhiyun 	writel(val, cpu_ctrl + CPU_RESET_NON_SC);
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	return 1;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun #endif
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun static const struct smp_operations berlin_smp_ops __initconst = {
120*4882a593Smuzhiyun 	.smp_prepare_cpus	= berlin_smp_prepare_cpus,
121*4882a593Smuzhiyun 	.smp_boot_secondary	= berlin_boot_secondary,
122*4882a593Smuzhiyun #ifdef CONFIG_HOTPLUG_CPU
123*4882a593Smuzhiyun 	.cpu_die		= berlin_cpu_die,
124*4882a593Smuzhiyun 	.cpu_kill		= berlin_cpu_kill,
125*4882a593Smuzhiyun #endif
126*4882a593Smuzhiyun };
127*4882a593Smuzhiyun CPU_METHOD_OF_DECLARE(berlin_smp, "marvell,berlin-smp", &berlin_smp_ops);
128