aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2014-03-09 01:55:31 -0500
committerOlof Johansson <olof@lixom.net>2014-03-09 01:55:31 -0500
commitc381585fcc2426da35a6388fcc72a91ecd4f9add (patch)
treee76ef91de1726ec83656dac09184c5768541f527
parent6c41a9979c3f2d5c9cf3458dda3fdb6542535df8 (diff)
parenta7a2b3118b410fb3cd3a8363b157c56f4211ee05 (diff)
Merge tag 'v3.15-rockchip-smp' of git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip into next/soc
Merge Rockchip SMP support from Heiko Stübner: SMP-support for RK3066 and RK3188 SoCs from Rockchip. * tag 'v3.15-rockchip-smp' of git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip: ARM: rockchip: add smp bringup code ARM: rockchip: add power-management-unit ARM: rockchip: add sram dt nodes and documentation ARM: rockchip: add snoop-control-unit Signed-off-by: Olof Johansson <olof@lixom.net>
-rw-r--r--Documentation/devicetree/bindings/arm/rockchip/pmu.txt16
-rw-r--r--Documentation/devicetree/bindings/arm/rockchip/smp-sram.txt30
-rw-r--r--arch/arm/boot/dts/rk3066a.dtsi13
-rw-r--r--arch/arm/boot/dts/rk3188.dtsi13
-rw-r--r--arch/arm/boot/dts/rk3xxx.dtsi10
-rw-r--r--arch/arm/mach-rockchip/Kconfig1
-rw-r--r--arch/arm/mach-rockchip/Makefile1
-rw-r--r--arch/arm/mach-rockchip/core.h22
-rw-r--r--arch/arm/mach-rockchip/headsmp.S30
-rw-r--r--arch/arm/mach-rockchip/platsmp.c184
-rw-r--r--arch/arm/mach-rockchip/rockchip.c2
11 files changed, 322 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/arm/rockchip/pmu.txt b/Documentation/devicetree/bindings/arm/rockchip/pmu.txt
new file mode 100644
index 000000000000..3ee9b428b2f7
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/rockchip/pmu.txt
@@ -0,0 +1,16 @@
1Rockchip power-management-unit:
2-------------------------------
3
4The pmu is used to turn off and on different power domains of the SoCs
5This includes the power to the CPU cores.
6
7Required node properties:
8- compatible value : = "rockchip,rk3066-pmu";
9- reg : physical base address and the size of the registers window
10
11Example:
12
13 pmu@20004000 {
14 compatible = "rockchip,rk3066-pmu";
15 reg = <0x20004000 0x100>;
16 };
diff --git a/Documentation/devicetree/bindings/arm/rockchip/smp-sram.txt b/Documentation/devicetree/bindings/arm/rockchip/smp-sram.txt
new file mode 100644
index 000000000000..d9416fb8db6f
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/rockchip/smp-sram.txt
@@ -0,0 +1,30 @@
1Rockchip SRAM for smp bringup:
2------------------------------
3
4Rockchip's smp-capable SoCs use the first part of the sram for the bringup
5of the cores. Once the core gets powered up it executes the code that is
6residing at the very beginning of the sram.
7
8Therefore a reserved section sub-node has to be added to the mmio-sram
9declaration.
10
11Required sub-node properties:
12- compatible : should be "rockchip,rk3066-smp-sram"
13
14The rest of the properties should follow the generic mmio-sram discription
15found in ../../misc/sram.txt
16
17Example:
18
19 sram: sram@10080000 {
20 compatible = "mmio-sram";
21 reg = <0x10080000 0x10000>;
22 #address-cells = <1>;
23 #size-cells = <1>;
24 ranges;
25
26 smp-sram@10080000 {
27 compatible = "rockchip,rk3066-smp-sram";
28 reg = <0x10080000 0x50>;
29 };
30 };
diff --git a/arch/arm/boot/dts/rk3066a.dtsi b/arch/arm/boot/dts/rk3066a.dtsi
index be5d2b09a363..4d4dfbb59f4b 100644
--- a/arch/arm/boot/dts/rk3066a.dtsi
+++ b/arch/arm/boot/dts/rk3066a.dtsi
@@ -64,6 +64,19 @@
64 clock-names = "timer", "pclk"; 64 clock-names = "timer", "pclk";
65 }; 65 };
66 66
67 sram: sram@10080000 {
68 compatible = "mmio-sram";
69 reg = <0x10080000 0x10000>;
70 #address-cells = <1>;
71 #size-cells = <1>;
72 ranges = <0 0x10080000 0x10000>;
73
74 smp-sram@0 {
75 compatible = "rockchip,rk3066-smp-sram";
76 reg = <0x0 0x50>;
77 };
78 };
79
67 pinctrl@20008000 { 80 pinctrl@20008000 {
68 compatible = "rockchip,rk3066a-pinctrl"; 81 compatible = "rockchip,rk3066a-pinctrl";
69 reg = <0x20008000 0x150>; 82 reg = <0x20008000 0x150>;
diff --git a/arch/arm/boot/dts/rk3188.dtsi b/arch/arm/boot/dts/rk3188.dtsi
index 1a26b03b3649..bb36596ea205 100644
--- a/arch/arm/boot/dts/rk3188.dtsi
+++ b/arch/arm/boot/dts/rk3188.dtsi
@@ -60,6 +60,19 @@
60 interrupts = <GIC_PPI 13 0xf04>; 60 interrupts = <GIC_PPI 13 0xf04>;
61 }; 61 };
62 62
63 sram: sram@10080000 {
64 compatible = "mmio-sram";
65 reg = <0x10080000 0x8000>;
66 #address-cells = <1>;
67 #size-cells = <1>;
68 ranges = <0 0x10080000 0x8000>;
69
70 smp-sram@0 {
71 compatible = "rockchip,rk3066-smp-sram";
72 reg = <0x0 0x50>;
73 };
74 };
75
63 pinctrl@20008000 { 76 pinctrl@20008000 {
64 compatible = "rockchip,rk3188-pinctrl"; 77 compatible = "rockchip,rk3188-pinctrl";
65 reg = <0x20008000 0xa0>, 78 reg = <0x20008000 0xa0>,
diff --git a/arch/arm/boot/dts/rk3xxx.dtsi b/arch/arm/boot/dts/rk3xxx.dtsi
index 0fcbcfd67de2..26e5a968d49d 100644
--- a/arch/arm/boot/dts/rk3xxx.dtsi
+++ b/arch/arm/boot/dts/rk3xxx.dtsi
@@ -26,6 +26,16 @@
26 compatible = "simple-bus"; 26 compatible = "simple-bus";
27 ranges; 27 ranges;
28 28
29 scu@1013c000 {
30 compatible = "arm,cortex-a9-scu";
31 reg = <0x1013c000 0x100>;
32 };
33
34 pmu@20004000 {
35 compatible = "rockchip,rk3066-pmu";
36 reg = <0x20004000 0x100>;
37 };
38
29 gic: interrupt-controller@1013d000 { 39 gic: interrupt-controller@1013d000 {
30 compatible = "arm,cortex-a9-gic"; 40 compatible = "arm,cortex-a9-gic";
31 interrupt-controller; 41 interrupt-controller;
diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig
index cf073dea5784..133410e178a7 100644
--- a/arch/arm/mach-rockchip/Kconfig
+++ b/arch/arm/mach-rockchip/Kconfig
@@ -5,6 +5,7 @@ config ARCH_ROCKCHIP
5 select ARCH_REQUIRE_GPIOLIB 5 select ARCH_REQUIRE_GPIOLIB
6 select ARM_GIC 6 select ARM_GIC
7 select CACHE_L2X0 7 select CACHE_L2X0
8 select HAVE_ARM_SCU if SMP
8 select HAVE_ARM_TWD if SMP 9 select HAVE_ARM_TWD if SMP
9 select HAVE_SMP 10 select HAVE_SMP
10 select COMMON_CLK 11 select COMMON_CLK
diff --git a/arch/arm/mach-rockchip/Makefile b/arch/arm/mach-rockchip/Makefile
index 1547d4fc920a..4377a1436a98 100644
--- a/arch/arm/mach-rockchip/Makefile
+++ b/arch/arm/mach-rockchip/Makefile
@@ -1 +1,2 @@
1obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip.o 1obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip.o
2obj-$(CONFIG_SMP) += headsmp.o platsmp.o
diff --git a/arch/arm/mach-rockchip/core.h b/arch/arm/mach-rockchip/core.h
new file mode 100644
index 000000000000..e2e7c9dbb200
--- /dev/null
+++ b/arch/arm/mach-rockchip/core.h
@@ -0,0 +1,22 @@
1/*
2 * Copyright (c) 2013 MundoReader S.L.
3 * Author: Heiko Stuebner <heiko@sntech.de>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16extern char rockchip_secondary_trampoline;
17extern char rockchip_secondary_trampoline_end;
18
19extern unsigned long rockchip_boot_fn;
20extern void rockchip_secondary_startup(void);
21
22extern struct smp_operations rockchip_smp_ops;
diff --git a/arch/arm/mach-rockchip/headsmp.S b/arch/arm/mach-rockchip/headsmp.S
new file mode 100644
index 000000000000..73206e360e31
--- /dev/null
+++ b/arch/arm/mach-rockchip/headsmp.S
@@ -0,0 +1,30 @@
1/*
2 * Copyright (c) 2013 MundoReader S.L.
3 * Author: Heiko Stuebner <heiko@sntech.de>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15#include <linux/linkage.h>
16#include <linux/init.h>
17
18ENTRY(rockchip_secondary_startup)
19 bl v7_invalidate_l1
20 b secondary_startup
21ENDPROC(rockchip_secondary_startup)
22
23ENTRY(rockchip_secondary_trampoline)
24 ldr pc, 1f
25ENDPROC(rockchip_secondary_trampoline)
26 .globl rockchip_boot_fn
27rockchip_boot_fn:
281: .space 4
29
30ENTRY(rockchip_secondary_trampoline_end)
diff --git a/arch/arm/mach-rockchip/platsmp.c b/arch/arm/mach-rockchip/platsmp.c
new file mode 100644
index 000000000000..dbfa5a26cfff
--- /dev/null
+++ b/arch/arm/mach-rockchip/platsmp.c
@@ -0,0 +1,184 @@
1/*
2 * Copyright (c) 2013 MundoReader S.L.
3 * Author: Heiko Stuebner <heiko@sntech.de>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <linux/delay.h>
17#include <linux/init.h>
18#include <linux/smp.h>
19#include <linux/io.h>
20#include <linux/of.h>
21#include <linux/of_address.h>
22
23#include <asm/cacheflush.h>
24#include <asm/smp_scu.h>
25#include <asm/smp_plat.h>
26#include <asm/mach/map.h>
27
28#include "core.h"
29
30static void __iomem *scu_base_addr;
31static void __iomem *sram_base_addr;
32static int ncores;
33
34#define PMU_PWRDN_CON 0x08
35#define PMU_PWRDN_ST 0x0c
36
37#define PMU_PWRDN_SCU 4
38
39static void __iomem *pmu_base_addr;
40
41static inline bool pmu_power_domain_is_on(int pd)
42{
43 return !(readl_relaxed(pmu_base_addr + PMU_PWRDN_ST) & BIT(pd));
44}
45
46static void pmu_set_power_domain(int pd, bool on)
47{
48 u32 val = readl_relaxed(pmu_base_addr + PMU_PWRDN_CON);
49 if (on)
50 val &= ~BIT(pd);
51 else
52 val |= BIT(pd);
53 writel(val, pmu_base_addr + PMU_PWRDN_CON);
54
55 while (pmu_power_domain_is_on(pd) != on) { }
56}
57
58/*
59 * Handling of CPU cores
60 */
61
62static int __cpuinit rockchip_boot_secondary(unsigned int cpu,
63 struct task_struct *idle)
64{
65 if (!sram_base_addr || !pmu_base_addr) {
66 pr_err("%s: sram or pmu missing for cpu boot\n", __func__);
67 return -ENXIO;
68 }
69
70 if (cpu >= ncores) {
71 pr_err("%s: cpu %d outside maximum number of cpus %d\n",
72 __func__, cpu, ncores);
73 return -ENXIO;
74 }
75
76 /* start the core */
77 pmu_set_power_domain(0 + cpu, true);
78
79 return 0;
80}
81
82/**
83 * rockchip_smp_prepare_sram - populate necessary sram block
84 * Starting cores execute the code residing at the start of the on-chip sram
85 * after power-on. Therefore make sure, this sram region is reserved and
86 * big enough. After this check, copy the trampoline code that directs the
87 * core to the real startup code in ram into the sram-region.
88 * @node: mmio-sram device node
89 */
90static int __init rockchip_smp_prepare_sram(struct device_node *node)
91{
92 unsigned int trampoline_sz = &rockchip_secondary_trampoline_end -
93 &rockchip_secondary_trampoline;
94 struct resource res;
95 unsigned int rsize;
96 int ret;
97
98 ret = of_address_to_resource(node, 0, &res);
99 if (ret < 0) {
100 pr_err("%s: could not get address for node %s\n",
101 __func__, node->full_name);
102 return ret;
103 }
104
105 rsize = resource_size(&res);
106 if (rsize < trampoline_sz) {
107 pr_err("%s: reserved block with size 0x%x is to small for trampoline size 0x%x\n",
108 __func__, rsize, trampoline_sz);
109 return -EINVAL;
110 }
111
112 sram_base_addr = of_iomap(node, 0);
113
114 /* set the boot function for the sram code */
115 rockchip_boot_fn = virt_to_phys(rockchip_secondary_startup);
116
117 /* copy the trampoline to sram, that runs during startup of the core */
118 memcpy(sram_base_addr, &rockchip_secondary_trampoline, trampoline_sz);
119 flush_cache_all();
120 outer_clean_range(0, trampoline_sz);
121
122 dsb_sev();
123
124 return 0;
125}
126
127static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus)
128{
129 struct device_node *node;
130 unsigned int i;
131
132 node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
133 if (!node) {
134 pr_err("%s: missing scu\n", __func__);
135 return;
136 }
137
138 scu_base_addr = of_iomap(node, 0);
139 if (!scu_base_addr) {
140 pr_err("%s: could not map scu registers\n", __func__);
141 return;
142 }
143
144 node = of_find_compatible_node(NULL, NULL, "rockchip,rk3066-smp-sram");
145 if (!node) {
146 pr_err("%s: could not find sram dt node\n", __func__);
147 return;
148 }
149
150 if (rockchip_smp_prepare_sram(node))
151 return;
152
153 node = of_find_compatible_node(NULL, NULL, "rockchip,rk3066-pmu");
154 if (!node) {
155 pr_err("%s: could not find sram dt node\n", __func__);
156 return;
157 }
158
159 pmu_base_addr = of_iomap(node, 0);
160 if (!pmu_base_addr) {
161 pr_err("%s: could not map pmu registers\n", __func__);
162 return;
163 }
164
165 /* enable the SCU power domain */
166 pmu_set_power_domain(PMU_PWRDN_SCU, true);
167
168 /*
169 * While the number of cpus is gathered from dt, also get the number
170 * of cores from the scu to verify this value when booting the cores.
171 */
172 ncores = scu_get_core_count(scu_base_addr);
173
174 scu_enable(scu_base_addr);
175
176 /* Make sure that all cores except the first are really off */
177 for (i = 1; i < ncores; i++)
178 pmu_set_power_domain(0 + i, false);
179}
180
181struct smp_operations rockchip_smp_ops __initdata = {
182 .smp_prepare_cpus = rockchip_smp_prepare_cpus,
183 .smp_boot_secondary = rockchip_boot_secondary,
184};
diff --git a/arch/arm/mach-rockchip/rockchip.c b/arch/arm/mach-rockchip/rockchip.c
index 82c0b0709712..d211d6fa0d98 100644
--- a/arch/arm/mach-rockchip/rockchip.c
+++ b/arch/arm/mach-rockchip/rockchip.c
@@ -22,6 +22,7 @@
22#include <asm/mach/arch.h> 22#include <asm/mach/arch.h>
23#include <asm/mach/map.h> 23#include <asm/mach/map.h>
24#include <asm/hardware/cache-l2x0.h> 24#include <asm/hardware/cache-l2x0.h>
25#include "core.h"
25 26
26static void __init rockchip_dt_init(void) 27static void __init rockchip_dt_init(void)
27{ 28{
@@ -38,6 +39,7 @@ static const char * const rockchip_board_dt_compat[] = {
38}; 39};
39 40
40DT_MACHINE_START(ROCKCHIP_DT, "Rockchip Cortex-A9 (Device Tree)") 41DT_MACHINE_START(ROCKCHIP_DT, "Rockchip Cortex-A9 (Device Tree)")
42 .smp = smp_ops(rockchip_smp_ops),
41 .init_machine = rockchip_dt_init, 43 .init_machine = rockchip_dt_init,
42 .dt_compat = rockchip_board_dt_compat, 44 .dt_compat = rockchip_board_dt_compat,
43MACHINE_END 45MACHINE_END