irqchip/s3c24xx: Mark init_eint as __maybe_unused
[linux/fpc-iii.git] / arch / arm / mach-uniphier / platsmp.c
blobf0577664611c9a6456c8d371ff80955e2d19e011
1 /*
2 * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
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.
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.
15 #define pr_fmt(fmt) "uniphier: " fmt
17 #include <linux/init.h>
18 #include <linux/io.h>
19 #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>
26 #include <asm/smp.h>
27 #include <asm/smp_scu.h>
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.
33 #define UNIPHIER_SBC_ROM_BOOT_RSV2 0x1208
35 static void __iomem *uniphier_smp_rom_boot_rsv2;
36 static unsigned int uniphier_smp_max_cpus;
38 extern char uniphier_smp_trampoline;
39 extern char uniphier_smp_trampoline_jump;
40 extern char uniphier_smp_trampoline_poll_addr;
41 extern char uniphier_smp_trampoline_end;
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.
48 static const phys_addr_t uniphier_smp_trampoline_dest_end = SECTION_SIZE;
49 static phys_addr_t uniphier_smp_trampoline_dest;
51 static int __init uniphier_smp_copy_trampoline(phys_addr_t poll_addr)
53 size_t trmp_size;
54 static void __iomem *trmp_base;
56 if (!uniphier_cache_l2_is_enabled()) {
57 pr_warn("outer cache is needed for SMP, but not enabled\n");
58 return -ENODEV;
61 uniphier_cache_l2_set_locked_ways(1);
63 outer_flush_all();
65 trmp_size = &uniphier_smp_trampoline_end - &uniphier_smp_trampoline;
66 uniphier_smp_trampoline_dest = uniphier_smp_trampoline_dest_end -
67 trmp_size;
69 uniphier_cache_l2_touch_range(uniphier_smp_trampoline_dest,
70 uniphier_smp_trampoline_dest_end);
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;
78 memcpy(trmp_base, &uniphier_smp_trampoline, trmp_size);
80 writel(virt_to_phys(secondary_startup),
81 trmp_base + (&uniphier_smp_trampoline_jump -
82 &uniphier_smp_trampoline));
84 writel(poll_addr, trmp_base + (&uniphier_smp_trampoline_poll_addr -
85 &uniphier_smp_trampoline));
87 flush_cache_all(); /* flush out trampoline code to outer cache */
89 iounmap(trmp_base);
91 return 0;
94 static int __init uniphier_smp_prepare_trampoline(unsigned int max_cpus)
96 struct device_node *np;
97 struct resource res;
98 phys_addr_t rom_rsv2_phys;
99 int ret;
101 np = of_find_compatible_node(NULL, NULL,
102 "socionext,uniphier-system-bus-controller");
103 ret = of_address_to_resource(np, 1, &res);
104 if (ret) {
105 pr_err("failed to get resource of system-bus-controller\n");
106 return ret;
109 rom_rsv2_phys = res.start + UNIPHIER_SBC_ROM_BOOT_RSV2;
111 ret = uniphier_smp_copy_trampoline(rom_rsv2_phys);
112 if (ret)
113 return ret;
115 uniphier_smp_rom_boot_rsv2 = ioremap(rom_rsv2_phys, sizeof(SZ_4));
116 if (!uniphier_smp_rom_boot_rsv2) {
117 pr_err("failed to map ROM_BOOT_RSV2 register\n");
118 return -ENOMEM;
121 writel(uniphier_smp_trampoline_dest, uniphier_smp_rom_boot_rsv2);
122 asm("sev"); /* Bring up all secondary CPUs to the trampoline code */
124 uniphier_smp_max_cpus = max_cpus; /* save for later use */
126 return 0;
129 static void __init uniphier_smp_unprepare_trampoline(void)
131 iounmap(uniphier_smp_rom_boot_rsv2);
133 if (uniphier_smp_trampoline_dest)
134 outer_inv_range(uniphier_smp_trampoline_dest,
135 uniphier_smp_trampoline_dest_end);
137 uniphier_cache_l2_set_locked_ways(0);
140 static int __init uniphier_smp_enable_scu(void)
142 unsigned long scu_base_phys = 0;
143 void __iomem *scu_base;
145 if (scu_a9_has_base())
146 scu_base_phys = scu_a9_get_base();
148 if (!scu_base_phys) {
149 pr_err("failed to get scu base\n");
150 return -ENODEV;
153 scu_base = ioremap(scu_base_phys, SZ_128);
154 if (!scu_base) {
155 pr_err("failed to map scu base\n");
156 return -ENOMEM;
159 scu_enable(scu_base);
160 iounmap(scu_base);
162 return 0;
165 static void __init uniphier_smp_prepare_cpus(unsigned int max_cpus)
167 static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 };
168 int ret;
170 ret = uniphier_smp_prepare_trampoline(max_cpus);
171 if (ret)
172 goto err;
174 ret = uniphier_smp_enable_scu();
175 if (ret)
176 goto err;
178 return;
179 err:
180 pr_warn("disabling SMP\n");
181 init_cpu_present(&only_cpu_0);
182 uniphier_smp_unprepare_trampoline();
185 static int __init uniphier_smp_boot_secondary(unsigned int cpu,
186 struct task_struct *idle)
188 if (WARN_ON_ONCE(!uniphier_smp_rom_boot_rsv2))
189 return -EFAULT;
191 writel(cpu, uniphier_smp_rom_boot_rsv2);
192 readl(uniphier_smp_rom_boot_rsv2); /* relax */
194 asm("sev"); /* wake up secondary CPUs sleeping in the trampoline */
196 if (cpu == uniphier_smp_max_cpus - 1) {
197 /* clean up resources if this is the last CPU */
198 uniphier_smp_unprepare_trampoline();
201 return 0;
204 static struct smp_operations uniphier_smp_ops __initdata = {
205 .smp_prepare_cpus = uniphier_smp_prepare_cpus,
206 .smp_boot_secondary = uniphier_smp_boot_secondary,
208 CPU_METHOD_OF_DECLARE(uniphier_smp, "socionext,uniphier-smp",
209 &uniphier_smp_ops);