diff options
author | Haojian Zhuang <haojian.zhuang@linaro.org> | 2013-12-19 21:52:56 -0500 |
---|---|---|
committer | Kevin Hilman <khilman@linaro.org> | 2013-12-20 11:23:01 -0500 |
commit | 389ee0c2ffedf5819dccc2c67dd15757c4550765 (patch) | |
tree | 6b59caa70e41a290b8957d5383fe2b22ebee31a6 /arch/arm/mach-hisi | |
parent | 22e99a6d43f2ccd1d1a28c65a803bb71ea293098 (diff) |
ARM: hisi: rename hi3xxx to hisi
Since some new Hisilicon SoCs are not named as hi3xxx, rename mach-hi3xxx
to mach-hisi instead. And the pronounciation of "hisi" is similar to the
chinese pronounciation of Hisilicon. So Hisilicon guys like this name.
ARCH_HI3xxx will be renamed later since other drivers are using it and
they are still in linux-next git tree. So rename ARCH_HI3xxx later.
Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
Signed-off-by: Kevin Hilman <khilman@linaro.org>
Diffstat (limited to 'arch/arm/mach-hisi')
-rw-r--r-- | arch/arm/mach-hisi/Kconfig | 17 | ||||
-rw-r--r-- | arch/arm/mach-hisi/Makefile | 7 | ||||
-rw-r--r-- | arch/arm/mach-hisi/core.h | 15 | ||||
-rw-r--r-- | arch/arm/mach-hisi/hisilicon.c | 97 | ||||
-rw-r--r-- | arch/arm/mach-hisi/hotplug.c | 200 | ||||
-rw-r--r-- | arch/arm/mach-hisi/platsmp.c | 89 |
6 files changed, 425 insertions, 0 deletions
diff --git a/arch/arm/mach-hisi/Kconfig b/arch/arm/mach-hisi/Kconfig new file mode 100644 index 000000000000..018ad67f1b38 --- /dev/null +++ b/arch/arm/mach-hisi/Kconfig | |||
@@ -0,0 +1,17 @@ | |||
1 | config ARCH_HI3xxx | ||
2 | bool "Hisilicon Hi36xx/Hi37xx family" if ARCH_MULTI_V7 | ||
3 | select ARM_AMBA | ||
4 | select ARM_GIC | ||
5 | select ARM_TIMER_SP804 | ||
6 | select ARCH_WANT_OPTIONAL_GPIOLIB | ||
7 | select CACHE_L2X0 | ||
8 | select CLKSRC_OF | ||
9 | select GENERIC_CLOCKEVENTS | ||
10 | select HAVE_ARM_SCU | ||
11 | select HAVE_ARM_TWD | ||
12 | select HAVE_SMP | ||
13 | select PINCTRL | ||
14 | select PINCTRL_SINGLE | ||
15 | select SMP | ||
16 | help | ||
17 | Support for Hisilicon Hi36xx/Hi37xx processor family | ||
diff --git a/arch/arm/mach-hisi/Makefile b/arch/arm/mach-hisi/Makefile new file mode 100644 index 000000000000..6870058d0a48 --- /dev/null +++ b/arch/arm/mach-hisi/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | # | ||
2 | # Makefile for Hisilicon processors family | ||
3 | # | ||
4 | |||
5 | obj-y += hisilicon.o | ||
6 | obj-$(CONFIG_SMP) += platsmp.o | ||
7 | obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o | ||
diff --git a/arch/arm/mach-hisi/core.h b/arch/arm/mach-hisi/core.h new file mode 100644 index 000000000000..af23ec204538 --- /dev/null +++ b/arch/arm/mach-hisi/core.h | |||
@@ -0,0 +1,15 @@ | |||
1 | #ifndef __HISILICON_CORE_H | ||
2 | #define __HISILICON_CORE_H | ||
3 | |||
4 | #include <linux/reboot.h> | ||
5 | |||
6 | extern void hi3xxx_set_cpu_jump(int cpu, void *jump_addr); | ||
7 | extern int hi3xxx_get_cpu_jump(int cpu); | ||
8 | extern void secondary_startup(void); | ||
9 | extern struct smp_operations hi3xxx_smp_ops; | ||
10 | |||
11 | extern void hi3xxx_cpu_die(unsigned int cpu); | ||
12 | extern int hi3xxx_cpu_kill(unsigned int cpu); | ||
13 | extern void hi3xxx_set_cpu(int cpu, bool enable); | ||
14 | |||
15 | #endif | ||
diff --git a/arch/arm/mach-hisi/hisilicon.c b/arch/arm/mach-hisi/hisilicon.c new file mode 100644 index 000000000000..685d9ebd612d --- /dev/null +++ b/arch/arm/mach-hisi/hisilicon.c | |||
@@ -0,0 +1,97 @@ | |||
1 | /* | ||
2 | * (Hisilicon's SoC based) flattened device tree enabled machine | ||
3 | * | ||
4 | * Copyright (c) 2012-2013 Hisilicon Ltd. | ||
5 | * Copyright (c) 2012-2013 Linaro Ltd. | ||
6 | * | ||
7 | * Author: Haojian Zhuang <haojian.zhuang@linaro.org> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/clk-provider.h> | ||
15 | #include <linux/clocksource.h> | ||
16 | #include <linux/irqchip.h> | ||
17 | #include <linux/of_address.h> | ||
18 | #include <linux/of_platform.h> | ||
19 | |||
20 | #include <asm/proc-fns.h> | ||
21 | |||
22 | #include <asm/mach/arch.h> | ||
23 | #include <asm/mach/map.h> | ||
24 | |||
25 | #include "core.h" | ||
26 | |||
27 | #define HI3620_SYSCTRL_PHYS_BASE 0xfc802000 | ||
28 | #define HI3620_SYSCTRL_VIRT_BASE 0xfe802000 | ||
29 | |||
30 | /* | ||
31 | * This table is only for optimization. Since ioremap() could always share | ||
32 | * the same mapping if it's defined as static IO mapping. | ||
33 | * | ||
34 | * Without this table, system could also work. The cost is some virtual address | ||
35 | * spaces wasted since ioremap() may be called multi times for the same | ||
36 | * IO space. | ||
37 | */ | ||
38 | static struct map_desc hi3620_io_desc[] __initdata = { | ||
39 | { | ||
40 | /* sysctrl */ | ||
41 | .pfn = __phys_to_pfn(HI3620_SYSCTRL_PHYS_BASE), | ||
42 | .virtual = HI3620_SYSCTRL_VIRT_BASE, | ||
43 | .length = 0x1000, | ||
44 | .type = MT_DEVICE, | ||
45 | }, | ||
46 | }; | ||
47 | |||
48 | static void __init hi3620_map_io(void) | ||
49 | { | ||
50 | debug_ll_io_init(); | ||
51 | iotable_init(hi3620_io_desc, ARRAY_SIZE(hi3620_io_desc)); | ||
52 | } | ||
53 | |||
54 | static void __init hi3xxx_timer_init(void) | ||
55 | { | ||
56 | of_clk_init(NULL); | ||
57 | clocksource_of_init(); | ||
58 | } | ||
59 | |||
60 | static void hi3xxx_restart(enum reboot_mode mode, const char *cmd) | ||
61 | { | ||
62 | struct device_node *np; | ||
63 | void __iomem *base; | ||
64 | int offset; | ||
65 | |||
66 | np = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl"); | ||
67 | if (!np) { | ||
68 | pr_err("failed to find hisilicon,sysctrl node\n"); | ||
69 | return; | ||
70 | } | ||
71 | base = of_iomap(np, 0); | ||
72 | if (!base) { | ||
73 | pr_err("failed to map address in hisilicon,sysctrl node\n"); | ||
74 | return; | ||
75 | } | ||
76 | if (of_property_read_u32(np, "reboot-offset", &offset) < 0) { | ||
77 | pr_err("failed to find reboot-offset property\n"); | ||
78 | return; | ||
79 | } | ||
80 | writel_relaxed(0xdeadbeef, base + offset); | ||
81 | |||
82 | while (1) | ||
83 | cpu_do_idle(); | ||
84 | } | ||
85 | |||
86 | static const char *hi3xxx_compat[] __initconst = { | ||
87 | "hisilicon,hi3620-hi4511", | ||
88 | NULL, | ||
89 | }; | ||
90 | |||
91 | DT_MACHINE_START(HI3620, "Hisilicon Hi3620 (Flattened Device Tree)") | ||
92 | .map_io = hi3620_map_io, | ||
93 | .init_time = hi3xxx_timer_init, | ||
94 | .dt_compat = hi3xxx_compat, | ||
95 | .smp = smp_ops(hi3xxx_smp_ops), | ||
96 | .restart = hi3xxx_restart, | ||
97 | MACHINE_END | ||
diff --git a/arch/arm/mach-hisi/hotplug.c b/arch/arm/mach-hisi/hotplug.c new file mode 100644 index 000000000000..b909854eee7f --- /dev/null +++ b/arch/arm/mach-hisi/hotplug.c | |||
@@ -0,0 +1,200 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013 Linaro Ltd. | ||
3 | * Copyright (c) 2013 Hisilicon Limited. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/cpu.h> | ||
11 | #include <linux/delay.h> | ||
12 | #include <linux/io.h> | ||
13 | #include <linux/of_address.h> | ||
14 | #include <linux/of_platform.h> | ||
15 | #include <asm/cacheflush.h> | ||
16 | #include <asm/smp_plat.h> | ||
17 | #include "core.h" | ||
18 | |||
19 | /* Sysctrl registers in Hi3620 SoC */ | ||
20 | #define SCISOEN 0xc0 | ||
21 | #define SCISODIS 0xc4 | ||
22 | #define SCPERPWREN 0xd0 | ||
23 | #define SCPERPWRDIS 0xd4 | ||
24 | #define SCCPUCOREEN 0xf4 | ||
25 | #define SCCPUCOREDIS 0xf8 | ||
26 | #define SCPERCTRL0 0x200 | ||
27 | #define SCCPURSTEN 0x410 | ||
28 | #define SCCPURSTDIS 0x414 | ||
29 | |||
30 | /* | ||
31 | * bit definition in SCISOEN/SCPERPWREN/... | ||
32 | * | ||
33 | * CPU2_ISO_CTRL (1 << 5) | ||
34 | * CPU3_ISO_CTRL (1 << 6) | ||
35 | * ... | ||
36 | */ | ||
37 | #define CPU2_ISO_CTRL (1 << 5) | ||
38 | |||
39 | /* | ||
40 | * bit definition in SCPERCTRL0 | ||
41 | * | ||
42 | * CPU0_WFI_MASK_CFG (1 << 28) | ||
43 | * CPU1_WFI_MASK_CFG (1 << 29) | ||
44 | * ... | ||
45 | */ | ||
46 | #define CPU0_WFI_MASK_CFG (1 << 28) | ||
47 | |||
48 | /* | ||
49 | * bit definition in SCCPURSTEN/... | ||
50 | * | ||
51 | * CPU0_SRST_REQ_EN (1 << 0) | ||
52 | * CPU1_SRST_REQ_EN (1 << 1) | ||
53 | * ... | ||
54 | */ | ||
55 | #define CPU0_HPM_SRST_REQ_EN (1 << 22) | ||
56 | #define CPU0_DBG_SRST_REQ_EN (1 << 12) | ||
57 | #define CPU0_NEON_SRST_REQ_EN (1 << 4) | ||
58 | #define CPU0_SRST_REQ_EN (1 << 0) | ||
59 | |||
60 | enum { | ||
61 | HI3620_CTRL, | ||
62 | ERROR_CTRL, | ||
63 | }; | ||
64 | |||
65 | static void __iomem *ctrl_base; | ||
66 | static int id; | ||
67 | |||
68 | static void set_cpu_hi3620(int cpu, bool enable) | ||
69 | { | ||
70 | u32 val = 0; | ||
71 | |||
72 | if (enable) { | ||
73 | /* MTCMOS set */ | ||
74 | if ((cpu == 2) || (cpu == 3)) | ||
75 | writel_relaxed(CPU2_ISO_CTRL << (cpu - 2), | ||
76 | ctrl_base + SCPERPWREN); | ||
77 | udelay(100); | ||
78 | |||
79 | /* Enable core */ | ||
80 | writel_relaxed(0x01 << cpu, ctrl_base + SCCPUCOREEN); | ||
81 | |||
82 | /* unreset */ | ||
83 | val = CPU0_DBG_SRST_REQ_EN | CPU0_NEON_SRST_REQ_EN | ||
84 | | CPU0_SRST_REQ_EN; | ||
85 | writel_relaxed(val << cpu, ctrl_base + SCCPURSTDIS); | ||
86 | /* reset */ | ||
87 | val |= CPU0_HPM_SRST_REQ_EN; | ||
88 | writel_relaxed(val << cpu, ctrl_base + SCCPURSTEN); | ||
89 | |||
90 | /* ISO disable */ | ||
91 | if ((cpu == 2) || (cpu == 3)) | ||
92 | writel_relaxed(CPU2_ISO_CTRL << (cpu - 2), | ||
93 | ctrl_base + SCISODIS); | ||
94 | udelay(1); | ||
95 | |||
96 | /* WFI Mask */ | ||
97 | val = readl_relaxed(ctrl_base + SCPERCTRL0); | ||
98 | val &= ~(CPU0_WFI_MASK_CFG << cpu); | ||
99 | writel_relaxed(val, ctrl_base + SCPERCTRL0); | ||
100 | |||
101 | /* Unreset */ | ||
102 | val = CPU0_DBG_SRST_REQ_EN | CPU0_NEON_SRST_REQ_EN | ||
103 | | CPU0_SRST_REQ_EN | CPU0_HPM_SRST_REQ_EN; | ||
104 | writel_relaxed(val << cpu, ctrl_base + SCCPURSTDIS); | ||
105 | } else { | ||
106 | /* wfi mask */ | ||
107 | val = readl_relaxed(ctrl_base + SCPERCTRL0); | ||
108 | val |= (CPU0_WFI_MASK_CFG << cpu); | ||
109 | writel_relaxed(val, ctrl_base + SCPERCTRL0); | ||
110 | |||
111 | /* disable core*/ | ||
112 | writel_relaxed(0x01 << cpu, ctrl_base + SCCPUCOREDIS); | ||
113 | |||
114 | if ((cpu == 2) || (cpu == 3)) { | ||
115 | /* iso enable */ | ||
116 | writel_relaxed(CPU2_ISO_CTRL << (cpu - 2), | ||
117 | ctrl_base + SCISOEN); | ||
118 | udelay(1); | ||
119 | } | ||
120 | |||
121 | /* reset */ | ||
122 | val = CPU0_DBG_SRST_REQ_EN | CPU0_NEON_SRST_REQ_EN | ||
123 | | CPU0_SRST_REQ_EN | CPU0_HPM_SRST_REQ_EN; | ||
124 | writel_relaxed(val << cpu, ctrl_base + SCCPURSTEN); | ||
125 | |||
126 | if ((cpu == 2) || (cpu == 3)) { | ||
127 | /* MTCMOS unset */ | ||
128 | writel_relaxed(CPU2_ISO_CTRL << (cpu - 2), | ||
129 | ctrl_base + SCPERPWRDIS); | ||
130 | udelay(100); | ||
131 | } | ||
132 | } | ||
133 | } | ||
134 | |||
135 | static int hi3xxx_hotplug_init(void) | ||
136 | { | ||
137 | struct device_node *node; | ||
138 | |||
139 | node = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl"); | ||
140 | if (node) { | ||
141 | ctrl_base = of_iomap(node, 0); | ||
142 | id = HI3620_CTRL; | ||
143 | return 0; | ||
144 | } | ||
145 | id = ERROR_CTRL; | ||
146 | return -ENOENT; | ||
147 | } | ||
148 | |||
149 | void hi3xxx_set_cpu(int cpu, bool enable) | ||
150 | { | ||
151 | if (!ctrl_base) { | ||
152 | if (hi3xxx_hotplug_init() < 0) | ||
153 | return; | ||
154 | } | ||
155 | |||
156 | if (id == HI3620_CTRL) | ||
157 | set_cpu_hi3620(cpu, enable); | ||
158 | } | ||
159 | |||
160 | static inline void cpu_enter_lowpower(void) | ||
161 | { | ||
162 | unsigned int v; | ||
163 | |||
164 | flush_cache_all(); | ||
165 | |||
166 | /* | ||
167 | * Turn off coherency and L1 D-cache | ||
168 | */ | ||
169 | asm volatile( | ||
170 | " mrc p15, 0, %0, c1, c0, 1\n" | ||
171 | " bic %0, %0, #0x40\n" | ||
172 | " mcr p15, 0, %0, c1, c0, 1\n" | ||
173 | " mrc p15, 0, %0, c1, c0, 0\n" | ||
174 | " bic %0, %0, #0x04\n" | ||
175 | " mcr p15, 0, %0, c1, c0, 0\n" | ||
176 | : "=&r" (v) | ||
177 | : "r" (0) | ||
178 | : "cc"); | ||
179 | } | ||
180 | |||
181 | void hi3xxx_cpu_die(unsigned int cpu) | ||
182 | { | ||
183 | cpu_enter_lowpower(); | ||
184 | hi3xxx_set_cpu_jump(cpu, phys_to_virt(0)); | ||
185 | cpu_do_idle(); | ||
186 | |||
187 | /* We should have never returned from idle */ | ||
188 | panic("cpu %d unexpectedly exit from shutdown\n", cpu); | ||
189 | } | ||
190 | |||
191 | int hi3xxx_cpu_kill(unsigned int cpu) | ||
192 | { | ||
193 | unsigned long timeout = jiffies + msecs_to_jiffies(50); | ||
194 | |||
195 | while (hi3xxx_get_cpu_jump(cpu)) | ||
196 | if (time_after(jiffies, timeout)) | ||
197 | return 0; | ||
198 | hi3xxx_set_cpu(cpu, false); | ||
199 | return 1; | ||
200 | } | ||
diff --git a/arch/arm/mach-hisi/platsmp.c b/arch/arm/mach-hisi/platsmp.c new file mode 100644 index 000000000000..471f1ee3be2b --- /dev/null +++ b/arch/arm/mach-hisi/platsmp.c | |||
@@ -0,0 +1,89 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013 Linaro Ltd. | ||
3 | * Copyright (c) 2013 Hisilicon Limited. | ||
4 | * Based on arch/arm/mach-vexpress/platsmp.c, Copyright (C) 2002 ARM Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | */ | ||
10 | #include <linux/smp.h> | ||
11 | #include <linux/io.h> | ||
12 | #include <linux/of_address.h> | ||
13 | |||
14 | #include <asm/cacheflush.h> | ||
15 | #include <asm/smp_plat.h> | ||
16 | #include <asm/smp_scu.h> | ||
17 | |||
18 | #include "core.h" | ||
19 | |||
20 | static void __iomem *ctrl_base; | ||
21 | |||
22 | void hi3xxx_set_cpu_jump(int cpu, void *jump_addr) | ||
23 | { | ||
24 | cpu = cpu_logical_map(cpu); | ||
25 | if (!cpu || !ctrl_base) | ||
26 | return; | ||
27 | writel_relaxed(virt_to_phys(jump_addr), ctrl_base + ((cpu - 1) << 2)); | ||
28 | } | ||
29 | |||
30 | int hi3xxx_get_cpu_jump(int cpu) | ||
31 | { | ||
32 | cpu = cpu_logical_map(cpu); | ||
33 | if (!cpu || !ctrl_base) | ||
34 | return 0; | ||
35 | return readl_relaxed(ctrl_base + ((cpu - 1) << 2)); | ||
36 | } | ||
37 | |||
38 | static void __init hi3xxx_smp_prepare_cpus(unsigned int max_cpus) | ||
39 | { | ||
40 | struct device_node *np = NULL; | ||
41 | unsigned long base = 0; | ||
42 | u32 offset = 0; | ||
43 | void __iomem *scu_base = NULL; | ||
44 | |||
45 | if (scu_a9_has_base()) { | ||
46 | base = scu_a9_get_base(); | ||
47 | scu_base = ioremap(base, SZ_4K); | ||
48 | if (!scu_base) { | ||
49 | pr_err("ioremap(scu_base) failed\n"); | ||
50 | return; | ||
51 | } | ||
52 | scu_enable(scu_base); | ||
53 | iounmap(scu_base); | ||
54 | } | ||
55 | if (!ctrl_base) { | ||
56 | np = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl"); | ||
57 | if (!np) { | ||
58 | pr_err("failed to find hisilicon,sysctrl node\n"); | ||
59 | return; | ||
60 | } | ||
61 | ctrl_base = of_iomap(np, 0); | ||
62 | if (!ctrl_base) { | ||
63 | pr_err("failed to map address\n"); | ||
64 | return; | ||
65 | } | ||
66 | if (of_property_read_u32(np, "smp-offset", &offset) < 0) { | ||
67 | pr_err("failed to find smp-offset property\n"); | ||
68 | return; | ||
69 | } | ||
70 | ctrl_base += offset; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | static int hi3xxx_boot_secondary(unsigned int cpu, struct task_struct *idle) | ||
75 | { | ||
76 | hi3xxx_set_cpu(cpu, true); | ||
77 | hi3xxx_set_cpu_jump(cpu, secondary_startup); | ||
78 | arch_send_wakeup_ipi_mask(cpumask_of(cpu)); | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | struct smp_operations hi3xxx_smp_ops __initdata = { | ||
83 | .smp_prepare_cpus = hi3xxx_smp_prepare_cpus, | ||
84 | .smp_boot_secondary = hi3xxx_boot_secondary, | ||
85 | #ifdef CONFIG_HOTPLUG_CPU | ||
86 | .cpu_die = hi3xxx_cpu_die, | ||
87 | .cpu_kill = hi3xxx_cpu_kill, | ||
88 | #endif | ||
89 | }; | ||