1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * SMP support for R-Mobile / SH-Mobile - sh73a0 portion |
4 | * |
5 | * Copyright (C) 2010 Magnus Damm |
6 | * Copyright (C) 2010 Takashi Yoshii |
7 | */ |
8 | #include <linux/kernel.h> |
9 | #include <linux/init.h> |
10 | #include <linux/smp.h> |
11 | #include <linux/io.h> |
12 | #include <linux/delay.h> |
13 | |
14 | #include <asm/smp_plat.h> |
15 | |
16 | #include "common.h" |
17 | #include "sh73a0.h" |
18 | |
19 | #define CPG_BASE2 0xe6151000 |
20 | #define WUPCR 0x10 /* System-CPU Wake Up Control Register */ |
21 | #define SRESCR 0x18 /* System-CPU Software Reset Control Register */ |
22 | #define PSTR 0x40 /* System-CPU Power Status Register */ |
23 | |
24 | #define SYSC_BASE 0xe6180000 |
25 | #define SBAR 0x20 /* SYS Boot Address Register */ |
26 | |
27 | #define AP_BASE 0xe6f10000 |
28 | #define APARMBAREA 0x20 /* Address Translation Area Register */ |
29 | |
30 | #define SH73A0_SCU_BASE 0xf0000000 |
31 | |
32 | static int sh73a0_boot_secondary(unsigned int cpu, struct task_struct *idle) |
33 | { |
34 | unsigned int lcpu = cpu_logical_map(cpu); |
35 | void __iomem *cpg2 = ioremap(CPG_BASE2, PAGE_SIZE); |
36 | |
37 | if (((readl(addr: cpg2 + PSTR) >> (4 * lcpu)) & 3) == 3) |
38 | writel(val: 1 << lcpu, addr: cpg2 + WUPCR); /* wake up */ |
39 | else |
40 | writel(val: 1 << lcpu, addr: cpg2 + SRESCR); /* reset */ |
41 | iounmap(addr: cpg2); |
42 | return 0; |
43 | } |
44 | |
45 | static void __init sh73a0_smp_prepare_cpus(unsigned int max_cpus) |
46 | { |
47 | void __iomem *ap, *sysc; |
48 | |
49 | if (!request_mem_region(0, SZ_4K, "Boot Area" )) { |
50 | pr_err("Failed to request boot area\n" ); |
51 | return; |
52 | } |
53 | |
54 | /* Map the reset vector (in headsmp.S) */ |
55 | ap = ioremap(AP_BASE, PAGE_SIZE); |
56 | sysc = ioremap(SYSC_BASE, PAGE_SIZE); |
57 | writel(val: 0, addr: ap + APARMBAREA); /* 4k */ |
58 | writel(__pa(shmobile_boot_vector), addr: sysc + SBAR); |
59 | iounmap(addr: sysc); |
60 | iounmap(addr: ap); |
61 | |
62 | /* setup sh73a0 specific SCU bits */ |
63 | shmobile_smp_scu_prepare_cpus(SH73A0_SCU_BASE, max_cpus); |
64 | } |
65 | |
66 | const struct smp_operations sh73a0_smp_ops __initconst = { |
67 | .smp_prepare_cpus = sh73a0_smp_prepare_cpus, |
68 | .smp_boot_secondary = sh73a0_boot_secondary, |
69 | #ifdef CONFIG_HOTPLUG_CPU |
70 | .cpu_can_disable = shmobile_smp_cpu_can_disable, |
71 | .cpu_die = shmobile_smp_scu_cpu_die, |
72 | .cpu_kill = shmobile_smp_scu_cpu_kill, |
73 | #endif |
74 | }; |
75 | |