aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-exynos
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-exynos')
-rw-r--r--arch/arm/mach-exynos/Makefile6
-rw-r--r--arch/arm/mach-exynos/common.c35
-rw-r--r--arch/arm/mach-exynos/common.h2
-rw-r--r--arch/arm/mach-exynos/exynos-smc.S22
-rw-r--r--arch/arm/mach-exynos/firmware.c70
-rw-r--r--arch/arm/mach-exynos/include/mach/map.h3
-rw-r--r--arch/arm/mach-exynos/mach-exynos4-dt.c1
-rw-r--r--arch/arm/mach-exynos/platsmp.c32
-rw-r--r--arch/arm/mach-exynos/smc.h31
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
25obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o 25obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
26 26
27obj-$(CONFIG_ARCH_EXYNOS) += exynos-smc.o
28obj-$(CONFIG_ARCH_EXYNOS) += firmware.o
29
30plus_sec := $(call as-instr,.arch_extension sec,+sec)
31AFLAGS_exynos-smc.o :=-Wa,-march=armv7-a$(plus_sec)
32
27# machine support 33# machine support
28 34
29obj-$(CONFIG_MACH_SMDKC210) += mach-smdkv310.o 35obj-$(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
236static 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
245static 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
254static 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
236static struct map_desc exynos5_iodesc[] __initdata = { 263static 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)
393static void __init exynos5_map_io(void) 425static 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
398static void __init exynos5440_map_io(void) 433static 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);
30void exynos4_clk_init(struct device_node *np); 30void exynos4_clk_init(struct device_node *np);
31void exynos4_clk_register_fixed_ext(unsigned long, unsigned long); 31void exynos4_clk_register_fixed_ext(unsigned long, unsigned long);
32 32
33void exynos_firmware_init(void);
34
33#ifdef CONFIG_PM_GENERIC_DOMAINS 35#ifdef CONFIG_PM_GENERIC_DOMAINS
34int exynos_pm_late_initcall(void); 36int 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
17ENTRY(exynos_smc)
18 stmfd sp!, {r4-r11, lr}
19 dsb
20 smc #0
21 ldmfd sp!, {r4-r11, pc}
22ENDPROC(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
23static int exynos_do_idle(void)
24{
25 exynos_smc(SMC_CMD_SLEEP, 0, 0, 0);
26 return 0;
27}
28
29static int exynos_cpu_boot(int cpu)
30{
31 exynos_smc(SMC_CMD_CPU1BOOT, cpu, 0, 0);
32 return 0;
33}
34
35static 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
43static 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
49void __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
205struct smp_operations exynos_smp_ops __initdata = { 227struct 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
29extern void exynos_smc(u32 cmd, u32 arg1, u32 arg2, u32 arg3);
30
31#endif