diff options
Diffstat (limited to 'arch/arm/mach-exynos')
-rw-r--r-- | arch/arm/mach-exynos/Makefile | 6 | ||||
-rw-r--r-- | arch/arm/mach-exynos/common.c | 35 | ||||
-rw-r--r-- | arch/arm/mach-exynos/common.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-exynos/exynos-smc.S | 22 | ||||
-rw-r--r-- | arch/arm/mach-exynos/firmware.c | 70 | ||||
-rw-r--r-- | arch/arm/mach-exynos/include/mach/map.h | 3 | ||||
-rw-r--r-- | arch/arm/mach-exynos/mach-exynos4-dt.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-exynos/platsmp.c | 32 | ||||
-rw-r--r-- | arch/arm/mach-exynos/smc.h | 31 |
9 files changed, 197 insertions, 5 deletions
diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile index d2f6b362b6dd..b09b027178f3 100644 --- a/arch/arm/mach-exynos/Makefile +++ b/arch/arm/mach-exynos/Makefile | |||
@@ -24,6 +24,12 @@ obj-$(CONFIG_SMP) += platsmp.o headsmp.o | |||
24 | 24 | ||
25 | obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o | 25 | obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o |
26 | 26 | ||
27 | obj-$(CONFIG_ARCH_EXYNOS) += exynos-smc.o | ||
28 | obj-$(CONFIG_ARCH_EXYNOS) += firmware.o | ||
29 | |||
30 | plus_sec := $(call as-instr,.arch_extension sec,+sec) | ||
31 | AFLAGS_exynos-smc.o :=-Wa,-march=armv7-a$(plus_sec) | ||
32 | |||
27 | # machine support | 33 | # machine support |
28 | 34 | ||
29 | obj-$(CONFIG_MACH_SMDKC210) += mach-smdkv310.o | 35 | obj-$(CONFIG_MACH_SMDKC210) += mach-smdkv310.o |
diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c index b35c60059bb8..46089fe24705 100644 --- a/arch/arm/mach-exynos/common.c +++ b/arch/arm/mach-exynos/common.c | |||
@@ -233,6 +233,33 @@ static struct map_desc exynos4_iodesc1[] __initdata = { | |||
233 | }, | 233 | }, |
234 | }; | 234 | }; |
235 | 235 | ||
236 | static struct map_desc exynos4210_iodesc[] __initdata = { | ||
237 | { | ||
238 | .virtual = (unsigned long)S5P_VA_SYSRAM_NS, | ||
239 | .pfn = __phys_to_pfn(EXYNOS4210_PA_SYSRAM_NS), | ||
240 | .length = SZ_4K, | ||
241 | .type = MT_DEVICE, | ||
242 | }, | ||
243 | }; | ||
244 | |||
245 | static struct map_desc exynos4x12_iodesc[] __initdata = { | ||
246 | { | ||
247 | .virtual = (unsigned long)S5P_VA_SYSRAM_NS, | ||
248 | .pfn = __phys_to_pfn(EXYNOS4x12_PA_SYSRAM_NS), | ||
249 | .length = SZ_4K, | ||
250 | .type = MT_DEVICE, | ||
251 | }, | ||
252 | }; | ||
253 | |||
254 | static struct map_desc exynos5250_iodesc[] __initdata = { | ||
255 | { | ||
256 | .virtual = (unsigned long)S5P_VA_SYSRAM_NS, | ||
257 | .pfn = __phys_to_pfn(EXYNOS5250_PA_SYSRAM_NS), | ||
258 | .length = SZ_4K, | ||
259 | .type = MT_DEVICE, | ||
260 | }, | ||
261 | }; | ||
262 | |||
236 | static struct map_desc exynos5_iodesc[] __initdata = { | 263 | static struct map_desc exynos5_iodesc[] __initdata = { |
237 | { | 264 | { |
238 | .virtual = (unsigned long)S3C_VA_SYS, | 265 | .virtual = (unsigned long)S3C_VA_SYS, |
@@ -361,6 +388,11 @@ static void __init exynos4_map_io(void) | |||
361 | else | 388 | else |
362 | iotable_init(exynos4_iodesc1, ARRAY_SIZE(exynos4_iodesc1)); | 389 | iotable_init(exynos4_iodesc1, ARRAY_SIZE(exynos4_iodesc1)); |
363 | 390 | ||
391 | if (soc_is_exynos4210()) | ||
392 | iotable_init(exynos4210_iodesc, ARRAY_SIZE(exynos4210_iodesc)); | ||
393 | if (soc_is_exynos4212() || soc_is_exynos4412()) | ||
394 | iotable_init(exynos4x12_iodesc, ARRAY_SIZE(exynos4x12_iodesc)); | ||
395 | |||
364 | /* initialize device information early */ | 396 | /* initialize device information early */ |
365 | exynos4_default_sdhci0(); | 397 | exynos4_default_sdhci0(); |
366 | exynos4_default_sdhci1(); | 398 | exynos4_default_sdhci1(); |
@@ -393,6 +425,9 @@ static void __init exynos4_map_io(void) | |||
393 | static void __init exynos5_map_io(void) | 425 | static void __init exynos5_map_io(void) |
394 | { | 426 | { |
395 | iotable_init(exynos5_iodesc, ARRAY_SIZE(exynos5_iodesc)); | 427 | iotable_init(exynos5_iodesc, ARRAY_SIZE(exynos5_iodesc)); |
428 | |||
429 | if (soc_is_exynos5250()) | ||
430 | iotable_init(exynos5250_iodesc, ARRAY_SIZE(exynos5250_iodesc)); | ||
396 | } | 431 | } |
397 | 432 | ||
398 | static void __init exynos5440_map_io(void) | 433 | static void __init exynos5440_map_io(void) |
diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h index cb89ab886950..b17448c1a164 100644 --- a/arch/arm/mach-exynos/common.h +++ b/arch/arm/mach-exynos/common.h | |||
@@ -30,6 +30,8 @@ void exynos_init_late(void); | |||
30 | void exynos4_clk_init(struct device_node *np); | 30 | void exynos4_clk_init(struct device_node *np); |
31 | void exynos4_clk_register_fixed_ext(unsigned long, unsigned long); | 31 | void exynos4_clk_register_fixed_ext(unsigned long, unsigned long); |
32 | 32 | ||
33 | void exynos_firmware_init(void); | ||
34 | |||
33 | #ifdef CONFIG_PM_GENERIC_DOMAINS | 35 | #ifdef CONFIG_PM_GENERIC_DOMAINS |
34 | int exynos_pm_late_initcall(void); | 36 | int exynos_pm_late_initcall(void); |
35 | #else | 37 | #else |
diff --git a/arch/arm/mach-exynos/exynos-smc.S b/arch/arm/mach-exynos/exynos-smc.S new file mode 100644 index 000000000000..2e27aa3813fd --- /dev/null +++ b/arch/arm/mach-exynos/exynos-smc.S | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Samsung Electronics. | ||
3 | * | ||
4 | * Copied from omap-smc.S Copyright (C) 2010 Texas Instruments, Inc. | ||
5 | * | ||
6 | * This program is free software,you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/linkage.h> | ||
12 | |||
13 | /* | ||
14 | * Function signature: void exynos_smc(u32 cmd, u32 arg1, u32 arg2, u32 arg3) | ||
15 | */ | ||
16 | |||
17 | ENTRY(exynos_smc) | ||
18 | stmfd sp!, {r4-r11, lr} | ||
19 | dsb | ||
20 | smc #0 | ||
21 | ldmfd sp!, {r4-r11, pc} | ||
22 | ENDPROC(exynos_smc) | ||
diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c new file mode 100644 index 000000000000..ed11f100d479 --- /dev/null +++ b/arch/arm/mach-exynos/firmware.c | |||
@@ -0,0 +1,70 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Samsung Electronics. | ||
3 | * Kyungmin Park <kyungmin.park@samsung.com> | ||
4 | * Tomasz Figa <t.figa@samsung.com> | ||
5 | * | ||
6 | * This program is free software,you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/io.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/of.h> | ||
15 | #include <linux/of_address.h> | ||
16 | |||
17 | #include <asm/firmware.h> | ||
18 | |||
19 | #include <mach/map.h> | ||
20 | |||
21 | #include "smc.h" | ||
22 | |||
23 | static int exynos_do_idle(void) | ||
24 | { | ||
25 | exynos_smc(SMC_CMD_SLEEP, 0, 0, 0); | ||
26 | return 0; | ||
27 | } | ||
28 | |||
29 | static int exynos_cpu_boot(int cpu) | ||
30 | { | ||
31 | exynos_smc(SMC_CMD_CPU1BOOT, cpu, 0, 0); | ||
32 | return 0; | ||
33 | } | ||
34 | |||
35 | static int exynos_set_cpu_boot_addr(int cpu, unsigned long boot_addr) | ||
36 | { | ||
37 | void __iomem *boot_reg = S5P_VA_SYSRAM_NS + 0x1c + 4*cpu; | ||
38 | |||
39 | __raw_writel(boot_addr, boot_reg); | ||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | static const struct firmware_ops exynos_firmware_ops = { | ||
44 | .do_idle = exynos_do_idle, | ||
45 | .set_cpu_boot_addr = exynos_set_cpu_boot_addr, | ||
46 | .cpu_boot = exynos_cpu_boot, | ||
47 | }; | ||
48 | |||
49 | void __init exynos_firmware_init(void) | ||
50 | { | ||
51 | if (of_have_populated_dt()) { | ||
52 | struct device_node *nd; | ||
53 | const __be32 *addr; | ||
54 | |||
55 | nd = of_find_compatible_node(NULL, NULL, | ||
56 | "samsung,secure-firmware"); | ||
57 | if (!nd) | ||
58 | return; | ||
59 | |||
60 | addr = of_get_address(nd, 0, NULL, NULL); | ||
61 | if (!addr) { | ||
62 | pr_err("%s: No address specified.\n", __func__); | ||
63 | return; | ||
64 | } | ||
65 | } | ||
66 | |||
67 | pr_info("Running under secure firmware.\n"); | ||
68 | |||
69 | register_firmware_ops(&exynos_firmware_ops); | ||
70 | } | ||
diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h index 7f99b7b187d6..99e0a79f3b1f 100644 --- a/arch/arm/mach-exynos/include/mach/map.h +++ b/arch/arm/mach-exynos/include/mach/map.h | |||
@@ -26,6 +26,9 @@ | |||
26 | #define EXYNOS4_PA_SYSRAM0 0x02025000 | 26 | #define EXYNOS4_PA_SYSRAM0 0x02025000 |
27 | #define EXYNOS4_PA_SYSRAM1 0x02020000 | 27 | #define EXYNOS4_PA_SYSRAM1 0x02020000 |
28 | #define EXYNOS5_PA_SYSRAM 0x02020000 | 28 | #define EXYNOS5_PA_SYSRAM 0x02020000 |
29 | #define EXYNOS4210_PA_SYSRAM_NS 0x0203F000 | ||
30 | #define EXYNOS4x12_PA_SYSRAM_NS 0x0204F000 | ||
31 | #define EXYNOS5250_PA_SYSRAM_NS 0x0204F000 | ||
29 | 32 | ||
30 | #define EXYNOS4_PA_FIMC0 0x11800000 | 33 | #define EXYNOS4_PA_FIMC0 0x11800000 |
31 | #define EXYNOS4_PA_FIMC1 0x11810000 | 34 | #define EXYNOS4_PA_FIMC1 0x11810000 |
diff --git a/arch/arm/mach-exynos/mach-exynos4-dt.c b/arch/arm/mach-exynos/mach-exynos4-dt.c index ac27f3cd121f..b9ed834a7eee 100644 --- a/arch/arm/mach-exynos/mach-exynos4-dt.c +++ b/arch/arm/mach-exynos/mach-exynos4-dt.c | |||
@@ -57,6 +57,7 @@ DT_MACHINE_START(EXYNOS4210_DT, "Samsung Exynos4 (Flattened Device Tree)") | |||
57 | .smp = smp_ops(exynos_smp_ops), | 57 | .smp = smp_ops(exynos_smp_ops), |
58 | .init_irq = exynos4_init_irq, | 58 | .init_irq = exynos4_init_irq, |
59 | .map_io = exynos4_dt_map_io, | 59 | .map_io = exynos4_dt_map_io, |
60 | .init_early = exynos_firmware_init, | ||
60 | .init_machine = exynos4_dt_machine_init, | 61 | .init_machine = exynos4_dt_machine_init, |
61 | .init_late = exynos_init_late, | 62 | .init_late = exynos_init_late, |
62 | .init_time = exynos_init_time, | 63 | .init_time = exynos_init_time, |
diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c index 95e04bd5813f..a0e8ff7758a4 100644 --- a/arch/arm/mach-exynos/platsmp.c +++ b/arch/arm/mach-exynos/platsmp.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <asm/cacheflush.h> | 24 | #include <asm/cacheflush.h> |
25 | #include <asm/smp_plat.h> | 25 | #include <asm/smp_plat.h> |
26 | #include <asm/smp_scu.h> | 26 | #include <asm/smp_scu.h> |
27 | #include <asm/firmware.h> | ||
27 | 28 | ||
28 | #include <mach/hardware.h> | 29 | #include <mach/hardware.h> |
29 | #include <mach/regs-clock.h> | 30 | #include <mach/regs-clock.h> |
@@ -137,10 +138,21 @@ static int __cpuinit exynos_boot_secondary(unsigned int cpu, struct task_struct | |||
137 | 138 | ||
138 | timeout = jiffies + (1 * HZ); | 139 | timeout = jiffies + (1 * HZ); |
139 | while (time_before(jiffies, timeout)) { | 140 | while (time_before(jiffies, timeout)) { |
141 | unsigned long boot_addr; | ||
142 | |||
140 | smp_rmb(); | 143 | smp_rmb(); |
141 | 144 | ||
142 | __raw_writel(virt_to_phys(exynos4_secondary_startup), | 145 | boot_addr = virt_to_phys(exynos4_secondary_startup); |
143 | cpu_boot_reg(phys_cpu)); | 146 | |
147 | /* | ||
148 | * Try to set boot address using firmware first | ||
149 | * and fall back to boot register if it fails. | ||
150 | */ | ||
151 | if (call_firmware_op(set_cpu_boot_addr, phys_cpu, boot_addr)) | ||
152 | __raw_writel(boot_addr, cpu_boot_reg(phys_cpu)); | ||
153 | |||
154 | call_firmware_op(cpu_boot, phys_cpu); | ||
155 | |||
144 | arch_send_wakeup_ipi_mask(cpumask_of(cpu)); | 156 | arch_send_wakeup_ipi_mask(cpumask_of(cpu)); |
145 | 157 | ||
146 | if (pen_release == -1) | 158 | if (pen_release == -1) |
@@ -196,10 +208,20 @@ static void __init exynos_smp_prepare_cpus(unsigned int max_cpus) | |||
196 | * system-wide flags register. The boot monitor waits | 208 | * system-wide flags register. The boot monitor waits |
197 | * until it receives a soft interrupt, and then the | 209 | * until it receives a soft interrupt, and then the |
198 | * secondary CPU branches to this address. | 210 | * secondary CPU branches to this address. |
211 | * | ||
212 | * Try using firmware operation first and fall back to | ||
213 | * boot register if it fails. | ||
199 | */ | 214 | */ |
200 | for (i = 1; i < max_cpus; ++i) | 215 | for (i = 1; i < max_cpus; ++i) { |
201 | __raw_writel(virt_to_phys(exynos4_secondary_startup), | 216 | unsigned long phys_cpu; |
202 | cpu_boot_reg(cpu_logical_map(i))); | 217 | unsigned long boot_addr; |
218 | |||
219 | phys_cpu = cpu_logical_map(i); | ||
220 | boot_addr = virt_to_phys(exynos4_secondary_startup); | ||
221 | |||
222 | if (call_firmware_op(set_cpu_boot_addr, phys_cpu, boot_addr)) | ||
223 | __raw_writel(boot_addr, cpu_boot_reg(phys_cpu)); | ||
224 | } | ||
203 | } | 225 | } |
204 | 226 | ||
205 | struct smp_operations exynos_smp_ops __initdata = { | 227 | struct smp_operations exynos_smp_ops __initdata = { |
diff --git a/arch/arm/mach-exynos/smc.h b/arch/arm/mach-exynos/smc.h new file mode 100644 index 000000000000..13a1dc8ecbf2 --- /dev/null +++ b/arch/arm/mach-exynos/smc.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Samsung Electronics. | ||
3 | * | ||
4 | * EXYNOS - SMC Call | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #ifndef __ASM_ARCH_EXYNOS_SMC_H | ||
12 | #define __ASM_ARCH_EXYNOS_SMC_H | ||
13 | |||
14 | #define SMC_CMD_INIT (-1) | ||
15 | #define SMC_CMD_INFO (-2) | ||
16 | /* For Power Management */ | ||
17 | #define SMC_CMD_SLEEP (-3) | ||
18 | #define SMC_CMD_CPU1BOOT (-4) | ||
19 | #define SMC_CMD_CPU0AFTR (-5) | ||
20 | /* For CP15 Access */ | ||
21 | #define SMC_CMD_C15RESUME (-11) | ||
22 | /* For L2 Cache Access */ | ||
23 | #define SMC_CMD_L2X0CTRL (-21) | ||
24 | #define SMC_CMD_L2X0SETUP1 (-22) | ||
25 | #define SMC_CMD_L2X0SETUP2 (-23) | ||
26 | #define SMC_CMD_L2X0INVALL (-24) | ||
27 | #define SMC_CMD_L2X0DEBUG (-25) | ||
28 | |||
29 | extern void exynos_smc(u32 cmd, u32 arg1, u32 arg2, u32 arg3); | ||
30 | |||
31 | #endif | ||