blob: e802ca836ec7c32e4bac5f0a8ae68cdf90b33a9a [file] [log] [blame]
Masahiro Yamadaba56a982015-05-08 13:07:11 +09001/*
2 * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
Masahiro Yamadab1e40062015-10-02 13:42:20 +090015#define pr_fmt(fmt) "uniphier: " fmt
16
Masahiro Yamadaba56a982015-05-08 13:07:11 +090017#include <linux/init.h>
18#include <linux/io.h>
Masahiro Yamadab1e40062015-10-02 13:42:20 +090019#include <linux/ioport.h>
20#include <linux/of.h>
21#include <linux/of_address.h>
22#include <linux/sizes.h>
23#include <asm/cacheflush.h>
24#include <asm/hardware/cache-uniphier.h>
25#include <asm/pgtable.h>
Masahiro Yamadaba56a982015-05-08 13:07:11 +090026#include <asm/smp.h>
27#include <asm/smp_scu.h>
28
Masahiro Yamadab1e40062015-10-02 13:42:20 +090029/*
30 * The secondary CPUs check this register from the boot ROM for the jump
31 * destination. After that, it can be reused as a scratch register.
32 */
Masahiro Yamada307d40c2016-02-26 16:16:08 +090033#define UNIPHIER_SMPCTRL_ROM_RSV2 0x208
Masahiro Yamadaba56a982015-05-08 13:07:11 +090034
Masahiro Yamadab1e40062015-10-02 13:42:20 +090035static void __iomem *uniphier_smp_rom_boot_rsv2;
36static unsigned int uniphier_smp_max_cpus;
37
38extern char uniphier_smp_trampoline;
39extern char uniphier_smp_trampoline_jump;
40extern char uniphier_smp_trampoline_poll_addr;
41extern char uniphier_smp_trampoline_end;
42
43/*
44 * Copy trampoline code to the tail of the 1st section of the page table used
45 * in the boot ROM. This area is directly accessible by the secondary CPUs
46 * for all the UniPhier SoCs.
47 */
48static const phys_addr_t uniphier_smp_trampoline_dest_end = SECTION_SIZE;
49static phys_addr_t uniphier_smp_trampoline_dest;
50
51static int __init uniphier_smp_copy_trampoline(phys_addr_t poll_addr)
Masahiro Yamadaba56a982015-05-08 13:07:11 +090052{
Masahiro Yamadab1e40062015-10-02 13:42:20 +090053 size_t trmp_size;
54 static void __iomem *trmp_base;
55
56 if (!uniphier_cache_l2_is_enabled()) {
57 pr_warn("outer cache is needed for SMP, but not enabled\n");
58 return -ENODEV;
59 }
60
61 uniphier_cache_l2_set_locked_ways(1);
62
63 outer_flush_all();
64
65 trmp_size = &uniphier_smp_trampoline_end - &uniphier_smp_trampoline;
66 uniphier_smp_trampoline_dest = uniphier_smp_trampoline_dest_end -
67 trmp_size;
68
69 uniphier_cache_l2_touch_range(uniphier_smp_trampoline_dest,
70 uniphier_smp_trampoline_dest_end);
71
72 trmp_base = ioremap_cache(uniphier_smp_trampoline_dest, trmp_size);
73 if (!trmp_base) {
74 pr_err("failed to map trampoline destination area\n");
75 return -ENOMEM;
76 }
77
78 memcpy(trmp_base, &uniphier_smp_trampoline, trmp_size);
79
80 writel(virt_to_phys(secondary_startup),
81 trmp_base + (&uniphier_smp_trampoline_jump -
82 &uniphier_smp_trampoline));
83
84 writel(poll_addr, trmp_base + (&uniphier_smp_trampoline_poll_addr -
85 &uniphier_smp_trampoline));
86
87 flush_cache_all(); /* flush out trampoline code to outer cache */
88
89 iounmap(trmp_base);
90
91 return 0;
92}
93
94static int __init uniphier_smp_prepare_trampoline(unsigned int max_cpus)
95{
96 struct device_node *np;
97 struct resource res;
98 phys_addr_t rom_rsv2_phys;
99 int ret;
100
Masahiro Yamada307d40c2016-02-26 16:16:08 +0900101 np = of_find_compatible_node(NULL, NULL, "socionext,uniphier-smpctrl");
Masahiro Yamada307d40c2016-02-26 16:16:08 +0900102 ret = of_address_to_resource(np, 0, &res);
Masahiro Yamada01bbcdf2016-04-15 19:48:29 +0900103 of_node_put(np);
Masahiro Yamada307d40c2016-02-26 16:16:08 +0900104 if (!ret) {
105 rom_rsv2_phys = res.start + UNIPHIER_SMPCTRL_ROM_RSV2;
106 } else {
107 /* try old binding too */
108 np = of_find_compatible_node(NULL, NULL,
109 "socionext,uniphier-system-bus-controller");
Masahiro Yamada307d40c2016-02-26 16:16:08 +0900110 ret = of_address_to_resource(np, 1, &res);
Masahiro Yamada01bbcdf2016-04-15 19:48:29 +0900111 of_node_put(np);
Masahiro Yamada307d40c2016-02-26 16:16:08 +0900112 if (ret) {
113 pr_err("failed to get resource of SMP control\n");
114 return ret;
115 }
116 rom_rsv2_phys = res.start + 0x1000 + UNIPHIER_SMPCTRL_ROM_RSV2;
Masahiro Yamadab1e40062015-10-02 13:42:20 +0900117 }
118
Masahiro Yamadab1e40062015-10-02 13:42:20 +0900119 ret = uniphier_smp_copy_trampoline(rom_rsv2_phys);
120 if (ret)
121 return ret;
122
Masahiro Yamada3137b712016-03-25 11:14:02 +0900123 uniphier_smp_rom_boot_rsv2 = ioremap(rom_rsv2_phys, SZ_4);
Masahiro Yamadab1e40062015-10-02 13:42:20 +0900124 if (!uniphier_smp_rom_boot_rsv2) {
125 pr_err("failed to map ROM_BOOT_RSV2 register\n");
126 return -ENOMEM;
127 }
128
129 writel(uniphier_smp_trampoline_dest, uniphier_smp_rom_boot_rsv2);
130 asm("sev"); /* Bring up all secondary CPUs to the trampoline code */
131
132 uniphier_smp_max_cpus = max_cpus; /* save for later use */
133
134 return 0;
135}
136
137static void __init uniphier_smp_unprepare_trampoline(void)
138{
139 iounmap(uniphier_smp_rom_boot_rsv2);
140
141 if (uniphier_smp_trampoline_dest)
142 outer_inv_range(uniphier_smp_trampoline_dest,
143 uniphier_smp_trampoline_dest_end);
144
145 uniphier_cache_l2_set_locked_ways(0);
146}
147
148static int __init uniphier_smp_enable_scu(void)
149{
Masahiro Yamadaba56a982015-05-08 13:07:11 +0900150 unsigned long scu_base_phys = 0;
151 void __iomem *scu_base;
152
Masahiro Yamadaba56a982015-05-08 13:07:11 +0900153 if (scu_a9_has_base())
154 scu_base_phys = scu_a9_get_base();
155
156 if (!scu_base_phys) {
157 pr_err("failed to get scu base\n");
Masahiro Yamadab1e40062015-10-02 13:42:20 +0900158 return -ENODEV;
Masahiro Yamadaba56a982015-05-08 13:07:11 +0900159 }
160
161 scu_base = ioremap(scu_base_phys, SZ_128);
162 if (!scu_base) {
Masahiro Yamadab1e40062015-10-02 13:42:20 +0900163 pr_err("failed to map scu base\n");
164 return -ENOMEM;
Masahiro Yamadaba56a982015-05-08 13:07:11 +0900165 }
166
167 scu_enable(scu_base);
168 iounmap(scu_base);
169
Masahiro Yamadab1e40062015-10-02 13:42:20 +0900170 return 0;
171}
172
173static void __init uniphier_smp_prepare_cpus(unsigned int max_cpus)
174{
175 static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 };
176 int ret;
177
178 ret = uniphier_smp_prepare_trampoline(max_cpus);
179 if (ret)
180 goto err;
181
182 ret = uniphier_smp_enable_scu();
183 if (ret)
184 goto err;
185
Masahiro Yamadaba56a982015-05-08 13:07:11 +0900186 return;
187err:
188 pr_warn("disabling SMP\n");
189 init_cpu_present(&only_cpu_0);
Masahiro Yamadab1e40062015-10-02 13:42:20 +0900190 uniphier_smp_unprepare_trampoline();
Masahiro Yamadaba56a982015-05-08 13:07:11 +0900191}
192
Masahiro Yamadab1e40062015-10-02 13:42:20 +0900193static int __init uniphier_smp_boot_secondary(unsigned int cpu,
194 struct task_struct *idle)
Masahiro Yamadaba56a982015-05-08 13:07:11 +0900195{
Masahiro Yamadab1e40062015-10-02 13:42:20 +0900196 if (WARN_ON_ONCE(!uniphier_smp_rom_boot_rsv2))
197 return -EFAULT;
Masahiro Yamadaba56a982015-05-08 13:07:11 +0900198
Masahiro Yamadab1e40062015-10-02 13:42:20 +0900199 writel(cpu, uniphier_smp_rom_boot_rsv2);
200 readl(uniphier_smp_rom_boot_rsv2); /* relax */
Masahiro Yamadaba56a982015-05-08 13:07:11 +0900201
Masahiro Yamadab1e40062015-10-02 13:42:20 +0900202 asm("sev"); /* wake up secondary CPUs sleeping in the trampoline */
Masahiro Yamadaba56a982015-05-08 13:07:11 +0900203
Masahiro Yamadab1e40062015-10-02 13:42:20 +0900204 if (cpu == uniphier_smp_max_cpus - 1) {
205 /* clean up resources if this is the last CPU */
206 uniphier_smp_unprepare_trampoline();
207 }
208
209 return 0;
Masahiro Yamadaba56a982015-05-08 13:07:11 +0900210}
211
Masahiro Yamada75305272015-11-15 10:39:53 +0900212static const struct smp_operations uniphier_smp_ops __initconst = {
Masahiro Yamadaba56a982015-05-08 13:07:11 +0900213 .smp_prepare_cpus = uniphier_smp_prepare_cpus,
Masahiro Yamadab1e40062015-10-02 13:42:20 +0900214 .smp_boot_secondary = uniphier_smp_boot_secondary,
Masahiro Yamadaba56a982015-05-08 13:07:11 +0900215};
216CPU_METHOD_OF_DECLARE(uniphier_smp, "socionext,uniphier-smp",
217 &uniphier_smp_ops);