aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-hisi
diff options
context:
space:
mode:
authorHaojian Zhuang <haojian.zhuang@linaro.org>2013-12-19 21:52:56 -0500
committerKevin Hilman <khilman@linaro.org>2013-12-20 11:23:01 -0500
commit389ee0c2ffedf5819dccc2c67dd15757c4550765 (patch)
tree6b59caa70e41a290b8957d5383fe2b22ebee31a6 /arch/arm/mach-hisi
parent22e99a6d43f2ccd1d1a28c65a803bb71ea293098 (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/Kconfig17
-rw-r--r--arch/arm/mach-hisi/Makefile7
-rw-r--r--arch/arm/mach-hisi/core.h15
-rw-r--r--arch/arm/mach-hisi/hisilicon.c97
-rw-r--r--arch/arm/mach-hisi/hotplug.c200
-rw-r--r--arch/arm/mach-hisi/platsmp.c89
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 @@
1config 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
5obj-y += hisilicon.o
6obj-$(CONFIG_SMP) += platsmp.o
7obj-$(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
6extern void hi3xxx_set_cpu_jump(int cpu, void *jump_addr);
7extern int hi3xxx_get_cpu_jump(int cpu);
8extern void secondary_startup(void);
9extern struct smp_operations hi3xxx_smp_ops;
10
11extern void hi3xxx_cpu_die(unsigned int cpu);
12extern int hi3xxx_cpu_kill(unsigned int cpu);
13extern 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 */
38static 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
48static 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
54static void __init hi3xxx_timer_init(void)
55{
56 of_clk_init(NULL);
57 clocksource_of_init();
58}
59
60static 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
86static const char *hi3xxx_compat[] __initconst = {
87 "hisilicon,hi3620-hi4511",
88 NULL,
89};
90
91DT_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,
97MACHINE_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
60enum {
61 HI3620_CTRL,
62 ERROR_CTRL,
63};
64
65static void __iomem *ctrl_base;
66static int id;
67
68static 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
135static 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
149void 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
160static 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
181void 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
191int 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
20static void __iomem *ctrl_base;
21
22void 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
30int 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
38static 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
74static 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
82struct 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};