aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-shmobile
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-shmobile')
-rw-r--r--arch/arm/mach-shmobile/Kconfig11
-rw-r--r--arch/arm/mach-shmobile/Makefile3
-rw-r--r--arch/arm/mach-shmobile/board-kzm9d.c85
-rw-r--r--arch/arm/mach-shmobile/clock-emev2.c249
-rw-r--r--arch/arm/mach-shmobile/include/mach/emev2.h19
-rw-r--r--arch/arm/mach-shmobile/include/mach/sh73a0.h34
-rw-r--r--arch/arm/mach-shmobile/platsmp.c17
-rw-r--r--arch/arm/mach-shmobile/setup-emev2.c452
-rw-r--r--arch/arm/mach-shmobile/smp-emev2.c97
9 files changed, 964 insertions, 3 deletions
diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
index 8e3602adabef..98327b7a503c 100644
--- a/arch/arm/mach-shmobile/Kconfig
+++ b/arch/arm/mach-shmobile/Kconfig
@@ -41,6 +41,12 @@ config ARCH_R8A7779
41 select ARM_GIC 41 select ARM_GIC
42 select ARCH_WANT_OPTIONAL_GPIOLIB 42 select ARCH_WANT_OPTIONAL_GPIOLIB
43 43
44config ARCH_EMEV2
45 bool "Emma Mobile EV2"
46 select CPU_V7
47 select ARM_GIC
48 select ARCH_WANT_OPTIONAL_GPIOLIB
49
44comment "SH-Mobile Board Type" 50comment "SH-Mobile Board Type"
45 51
46config MACH_G3EVM 52config MACH_G3EVM
@@ -104,6 +110,11 @@ config MACH_MARZEN
104 depends on ARCH_R8A7779 110 depends on ARCH_R8A7779
105 select ARCH_REQUIRE_GPIOLIB 111 select ARCH_REQUIRE_GPIOLIB
106 112
113config MACH_KZM9D
114 bool "KZM9D board"
115 depends on ARCH_EMEV2
116 select USE_OF
117
107config MACH_KZM9G 118config MACH_KZM9G
108 bool "KZM-A9-GT board" 119 bool "KZM-A9-GT board"
109 depends on ARCH_SH73A0 120 depends on ARCH_SH73A0
diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile
index 4ac8c12c72ba..e6b177bc9410 100644
--- a/arch/arm/mach-shmobile/Makefile
+++ b/arch/arm/mach-shmobile/Makefile
@@ -12,12 +12,14 @@ obj-$(CONFIG_ARCH_SH7372) += setup-sh7372.o clock-sh7372.o intc-sh7372.o
12obj-$(CONFIG_ARCH_SH73A0) += setup-sh73a0.o clock-sh73a0.o intc-sh73a0.o 12obj-$(CONFIG_ARCH_SH73A0) += setup-sh73a0.o clock-sh73a0.o intc-sh73a0.o
13obj-$(CONFIG_ARCH_R8A7740) += setup-r8a7740.o clock-r8a7740.o intc-r8a7740.o 13obj-$(CONFIG_ARCH_R8A7740) += setup-r8a7740.o clock-r8a7740.o intc-r8a7740.o
14obj-$(CONFIG_ARCH_R8A7779) += setup-r8a7779.o clock-r8a7779.o intc-r8a7779.o 14obj-$(CONFIG_ARCH_R8A7779) += setup-r8a7779.o clock-r8a7779.o intc-r8a7779.o
15obj-$(CONFIG_ARCH_EMEV2) += setup-emev2.o clock-emev2.o
15 16
16# SMP objects 17# SMP objects
17smp-y := platsmp.o headsmp.o 18smp-y := platsmp.o headsmp.o
18smp-$(CONFIG_HOTPLUG_CPU) += hotplug.o 19smp-$(CONFIG_HOTPLUG_CPU) += hotplug.o
19smp-$(CONFIG_ARCH_SH73A0) += smp-sh73a0.o 20smp-$(CONFIG_ARCH_SH73A0) += smp-sh73a0.o
20smp-$(CONFIG_ARCH_R8A7779) += smp-r8a7779.o 21smp-$(CONFIG_ARCH_R8A7779) += smp-r8a7779.o
22smp-$(CONFIG_ARCH_EMEV2) += smp-emev2.o
21 23
22# Pinmux setup 24# Pinmux setup
23pfc-y := 25pfc-y :=
@@ -50,6 +52,7 @@ obj-$(CONFIG_MACH_KOTA2) += board-kota2.o
50obj-$(CONFIG_MACH_BONITO) += board-bonito.o 52obj-$(CONFIG_MACH_BONITO) += board-bonito.o
51obj-$(CONFIG_MACH_MARZEN) += board-marzen.o 53obj-$(CONFIG_MACH_MARZEN) += board-marzen.o
52obj-$(CONFIG_MACH_ARMADILLO800EVA) += board-armadillo800eva.o 54obj-$(CONFIG_MACH_ARMADILLO800EVA) += board-armadillo800eva.o
55obj-$(CONFIG_MACH_KZM9D) += board-kzm9d.o
53obj-$(CONFIG_MACH_KZM9G) += board-kzm9g.o 56obj-$(CONFIG_MACH_KZM9G) += board-kzm9g.o
54 57
55# Framework support 58# Framework support
diff --git a/arch/arm/mach-shmobile/board-kzm9d.c b/arch/arm/mach-shmobile/board-kzm9d.c
new file mode 100644
index 000000000000..7bc5e7d39f9b
--- /dev/null
+++ b/arch/arm/mach-shmobile/board-kzm9d.c
@@ -0,0 +1,85 @@
1/*
2 * kzm9d board support
3 *
4 * Copyright (C) 2012 Renesas Solutions Corp.
5 * Copyright (C) 2012 Magnus Damm
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include <linux/kernel.h>
22#include <linux/interrupt.h>
23#include <linux/platform_device.h>
24#include <linux/smsc911x.h>
25#include <mach/common.h>
26#include <mach/emev2.h>
27#include <asm/mach-types.h>
28#include <asm/mach/arch.h>
29#include <asm/hardware/gic.h>
30
31/* Ether */
32static struct resource smsc911x_resources[] = {
33 [0] = {
34 .start = 0x20000000,
35 .end = 0x2000ffff,
36 .flags = IORESOURCE_MEM,
37 },
38 [1] = {
39 .start = EMEV2_GPIO_IRQ(1),
40 .flags = IORESOURCE_IRQ | IRQF_TRIGGER_HIGH,
41 },
42};
43
44static struct smsc911x_platform_config smsc911x_platdata = {
45 .flags = SMSC911X_USE_32BIT,
46 .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL,
47 .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH,
48};
49
50static struct platform_device smsc91x_device = {
51 .name = "smsc911x",
52 .id = 0,
53 .dev = {
54 .platform_data = &smsc911x_platdata,
55 },
56 .num_resources = ARRAY_SIZE(smsc911x_resources),
57 .resource = smsc911x_resources,
58};
59
60static struct platform_device *kzm9d_devices[] __initdata = {
61 &smsc91x_device,
62};
63
64void __init kzm9d_add_standard_devices(void)
65{
66 emev2_add_standard_devices();
67
68 platform_add_devices(kzm9d_devices, ARRAY_SIZE(kzm9d_devices));
69}
70
71static const char *kzm9d_boards_compat_dt[] __initdata = {
72 "renesas,kzm9d",
73 NULL,
74};
75
76DT_MACHINE_START(KZM9D_DT, "kzm9d")
77 .map_io = emev2_map_io,
78 .init_early = emev2_add_early_devices,
79 .nr_irqs = NR_IRQS_LEGACY,
80 .init_irq = emev2_init_irq,
81 .handle_irq = gic_handle_irq,
82 .init_machine = kzm9d_add_standard_devices,
83 .timer = &shmobile_timer,
84 .dt_compat = kzm9d_boards_compat_dt,
85MACHINE_END
diff --git a/arch/arm/mach-shmobile/clock-emev2.c b/arch/arm/mach-shmobile/clock-emev2.c
new file mode 100644
index 000000000000..4710f1847bb7
--- /dev/null
+++ b/arch/arm/mach-shmobile/clock-emev2.c
@@ -0,0 +1,249 @@
1/*
2 * Emma Mobile EV2 clock framework support
3 *
4 * Copyright (C) 2012 Magnus Damm
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 as published by
8 * the Free Software Foundation; version 2 of the License.
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 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19#include <linux/init.h>
20#include <linux/kernel.h>
21#include <linux/io.h>
22#include <linux/sh_clk.h>
23#include <linux/clkdev.h>
24#include <mach/common.h>
25
26#define EMEV2_SMU_BASE 0xe0110000
27
28/* EMEV2 SMU registers */
29#define USIAU0_RSTCTRL 0x094
30#define USIBU1_RSTCTRL 0x0ac
31#define USIBU2_RSTCTRL 0x0b0
32#define USIBU3_RSTCTRL 0x0b4
33#define STI_RSTCTRL 0x124
34#define USIAU0GCLKCTRL 0x4a0
35#define USIBU1GCLKCTRL 0x4b8
36#define USIBU2GCLKCTRL 0x4bc
37#define USIBU3GCLKCTRL 0x04c0
38#define STIGCLKCTRL 0x528
39#define USIAU0SCLKDIV 0x61c
40#define USIB2SCLKDIV 0x65c
41#define USIB3SCLKDIV 0x660
42#define STI_CLKSEL 0x688
43#define SMU_GENERAL_REG0 0x7c0
44
45/* not pretty, but hey */
46static void __iomem *smu_base;
47
48static void emev2_smu_write(unsigned long value, int offs)
49{
50 BUG_ON(!smu_base || (offs >= PAGE_SIZE));
51 iowrite32(value, smu_base + offs);
52}
53
54void emev2_set_boot_vector(unsigned long value)
55{
56 emev2_smu_write(value, SMU_GENERAL_REG0);
57}
58
59static struct clk_mapping smu_mapping = {
60 .phys = EMEV2_SMU_BASE,
61 .len = PAGE_SIZE,
62};
63
64/* Fixed 32 KHz root clock from C32K pin */
65static struct clk c32k_clk = {
66 .rate = 32768,
67 .mapping = &smu_mapping,
68};
69
70/* PLL3 multiplies C32K with 7000 */
71static unsigned long pll3_recalc(struct clk *clk)
72{
73 return clk->parent->rate * 7000;
74}
75
76static struct sh_clk_ops pll3_clk_ops = {
77 .recalc = pll3_recalc,
78};
79
80static struct clk pll3_clk = {
81 .ops = &pll3_clk_ops,
82 .parent = &c32k_clk,
83};
84
85static struct clk *main_clks[] = {
86 &c32k_clk,
87 &pll3_clk,
88};
89
90enum { SCLKDIV_USIAU0, SCLKDIV_USIBU2, SCLKDIV_USIBU1, SCLKDIV_USIBU3,
91 SCLKDIV_NR };
92
93#define SCLKDIV(_reg, _shift) \
94{ \
95 .parent = &pll3_clk, \
96 .enable_reg = IOMEM(EMEV2_SMU_BASE + (_reg)), \
97 .enable_bit = _shift, \
98}
99
100static struct clk sclkdiv_clks[SCLKDIV_NR] = {
101 [SCLKDIV_USIAU0] = SCLKDIV(USIAU0SCLKDIV, 0),
102 [SCLKDIV_USIBU2] = SCLKDIV(USIB2SCLKDIV, 16),
103 [SCLKDIV_USIBU1] = SCLKDIV(USIB2SCLKDIV, 0),
104 [SCLKDIV_USIBU3] = SCLKDIV(USIB3SCLKDIV, 0),
105};
106
107enum { GCLK_USIAU0_SCLK, GCLK_USIBU1_SCLK, GCLK_USIBU2_SCLK, GCLK_USIBU3_SCLK,
108 GCLK_STI_SCLK,
109 GCLK_NR };
110
111#define GCLK_SCLK(_parent, _reg) \
112{ \
113 .parent = _parent, \
114 .enable_reg = IOMEM(EMEV2_SMU_BASE + (_reg)), \
115 .enable_bit = 1, /* SCLK_GCC */ \
116}
117
118static struct clk gclk_clks[GCLK_NR] = {
119 [GCLK_USIAU0_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIAU0],
120 USIAU0GCLKCTRL),
121 [GCLK_USIBU1_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU1],
122 USIBU1GCLKCTRL),
123 [GCLK_USIBU2_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU2],
124 USIBU2GCLKCTRL),
125 [GCLK_USIBU3_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU3],
126 USIBU3GCLKCTRL),
127 [GCLK_STI_SCLK] = GCLK_SCLK(&c32k_clk, STIGCLKCTRL),
128};
129
130static int emev2_gclk_enable(struct clk *clk)
131{
132 iowrite32(ioread32(clk->mapped_reg) | (1 << clk->enable_bit),
133 clk->mapped_reg);
134 return 0;
135}
136
137static void emev2_gclk_disable(struct clk *clk)
138{
139 iowrite32(ioread32(clk->mapped_reg) & ~(1 << clk->enable_bit),
140 clk->mapped_reg);
141}
142
143static struct sh_clk_ops emev2_gclk_clk_ops = {
144 .enable = emev2_gclk_enable,
145 .disable = emev2_gclk_disable,
146 .recalc = followparent_recalc,
147};
148
149static int __init emev2_gclk_register(struct clk *clks, int nr)
150{
151 struct clk *clkp;
152 int ret = 0;
153 int k;
154
155 for (k = 0; !ret && (k < nr); k++) {
156 clkp = clks + k;
157 clkp->ops = &emev2_gclk_clk_ops;
158 ret |= clk_register(clkp);
159 }
160
161 return ret;
162}
163
164static unsigned long emev2_sclkdiv_recalc(struct clk *clk)
165{
166 unsigned int sclk_div;
167
168 sclk_div = (ioread32(clk->mapped_reg) >> clk->enable_bit) & 0xff;
169
170 return clk->parent->rate / (sclk_div + 1);
171}
172
173static struct sh_clk_ops emev2_sclkdiv_clk_ops = {
174 .recalc = emev2_sclkdiv_recalc,
175};
176
177static int __init emev2_sclkdiv_register(struct clk *clks, int nr)
178{
179 struct clk *clkp;
180 int ret = 0;
181 int k;
182
183 for (k = 0; !ret && (k < nr); k++) {
184 clkp = clks + k;
185 clkp->ops = &emev2_sclkdiv_clk_ops;
186 ret |= clk_register(clkp);
187 }
188
189 return ret;
190}
191
192static struct clk_lookup lookups[] = {
193 CLKDEV_DEV_ID("serial8250-em.0", &gclk_clks[GCLK_USIAU0_SCLK]),
194 CLKDEV_DEV_ID("e1020000.uart", &gclk_clks[GCLK_USIAU0_SCLK]),
195 CLKDEV_DEV_ID("serial8250-em.1", &gclk_clks[GCLK_USIBU1_SCLK]),
196 CLKDEV_DEV_ID("e1030000.uart", &gclk_clks[GCLK_USIBU1_SCLK]),
197 CLKDEV_DEV_ID("serial8250-em.2", &gclk_clks[GCLK_USIBU2_SCLK]),
198 CLKDEV_DEV_ID("e1040000.uart", &gclk_clks[GCLK_USIBU2_SCLK]),
199 CLKDEV_DEV_ID("serial8250-em.3", &gclk_clks[GCLK_USIBU3_SCLK]),
200 CLKDEV_DEV_ID("e1050000.uart", &gclk_clks[GCLK_USIBU3_SCLK]),
201 CLKDEV_DEV_ID("em_sti.0", &gclk_clks[GCLK_STI_SCLK]),
202 CLKDEV_DEV_ID("e0180000.sti", &gclk_clks[GCLK_STI_SCLK]),
203};
204
205void __init emev2_clock_init(void)
206{
207 int k, ret = 0;
208 static int is_setup;
209
210 /* yuck, this is ugly as hell, but the non-smp case of clocks
211 * code is now designed to rely on ioremap() instead of static
212 * entity maps. in the case of smp we need access to the SMU
213 * register earlier than ioremap() is actually working without
214 * any static maps. to enable SMP in ugly but with dynamic
215 * mappings we have to call emev2_clock_init() from different
216 * places depending on UP and SMP...
217 */
218 if (is_setup++)
219 return;
220
221 smu_base = ioremap(EMEV2_SMU_BASE, PAGE_SIZE);
222 BUG_ON(!smu_base);
223
224 /* setup STI timer to run on 37.768 kHz and deassert reset */
225 emev2_smu_write(0, STI_CLKSEL);
226 emev2_smu_write(1, STI_RSTCTRL);
227
228 /* deassert reset for UART0->UART3 */
229 emev2_smu_write(2, USIAU0_RSTCTRL);
230 emev2_smu_write(2, USIBU1_RSTCTRL);
231 emev2_smu_write(2, USIBU2_RSTCTRL);
232 emev2_smu_write(2, USIBU3_RSTCTRL);
233
234 for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
235 ret = clk_register(main_clks[k]);
236
237 if (!ret)
238 ret = emev2_sclkdiv_register(sclkdiv_clks, SCLKDIV_NR);
239
240 if (!ret)
241 ret = emev2_gclk_register(gclk_clks, GCLK_NR);
242
243 clkdev_add_table(lookups, ARRAY_SIZE(lookups));
244
245 if (!ret)
246 shmobile_clk_init();
247 else
248 panic("failed to setup emev2 clocks\n");
249}
diff --git a/arch/arm/mach-shmobile/include/mach/emev2.h b/arch/arm/mach-shmobile/include/mach/emev2.h
new file mode 100644
index 000000000000..e6b0c1bf4b7e
--- /dev/null
+++ b/arch/arm/mach-shmobile/include/mach/emev2.h
@@ -0,0 +1,19 @@
1#ifndef __ASM_EMEV2_H__
2#define __ASM_EMEV2_H__
3
4extern void emev2_map_io(void);
5extern void emev2_init_irq(void);
6extern void emev2_add_early_devices(void);
7extern void emev2_add_standard_devices(void);
8extern void emev2_clock_init(void);
9extern void emev2_set_boot_vector(unsigned long value);
10extern unsigned int emev2_get_core_count(void);
11extern int emev2_platform_cpu_kill(unsigned int cpu);
12extern void emev2_secondary_init(unsigned int cpu);
13extern int emev2_boot_secondary(unsigned int cpu);
14extern void emev2_smp_prepare_cpus(void);
15
16#define EMEV2_GPIO_BASE 200
17#define EMEV2_GPIO_IRQ(n) (EMEV2_GPIO_BASE + (n))
18
19#endif /* __ASM_EMEV2_H__ */
diff --git a/arch/arm/mach-shmobile/include/mach/sh73a0.h b/arch/arm/mach-shmobile/include/mach/sh73a0.h
index ac758579d4e9..398e2c10913b 100644
--- a/arch/arm/mach-shmobile/include/mach/sh73a0.h
+++ b/arch/arm/mach-shmobile/include/mach/sh73a0.h
@@ -518,8 +518,36 @@ enum {
518 SHDMA_SLAVE_MMCIF_RX, 518 SHDMA_SLAVE_MMCIF_RX,
519}; 519};
520 520
521/* PINT interrupts are located at Linux IRQ 800 and up */ 521/*
522#define SH73A0_PINT0_IRQ(irq) ((irq) + 800) 522 * SH73A0 IRQ LOCATION TABLE
523#define SH73A0_PINT1_IRQ(irq) ((irq) + 832) 523 *
524 * 416 -----------------------------------------
525 * IRQ0-IRQ15
526 * 431 -----------------------------------------
527 * ...
528 * 448 -----------------------------------------
529 * sh73a0-intcs
530 * sh73a0-intca-irq-pins
531 * 680 -----------------------------------------
532 * ...
533 * 700 -----------------------------------------
534 * sh73a0-pint0
535 * 731 -----------------------------------------
536 * 732 -----------------------------------------
537 * sh73a0-pint1
538 * 739 -----------------------------------------
539 * ...
540 * 800 -----------------------------------------
541 * IRQ16-IRQ31
542 * 815 -----------------------------------------
543 * ...
544 * 928 -----------------------------------------
545 * sh73a0-intca-irq-pins
546 * 943 -----------------------------------------
547 */
548
549/* PINT interrupts are located at Linux IRQ 700 and up */
550#define SH73A0_PINT0_IRQ(irq) ((irq) + 700)
551#define SH73A0_PINT1_IRQ(irq) ((irq) + 732)
524 552
525#endif /* __ASM_SH73A0_H__ */ 553#endif /* __ASM_SH73A0_H__ */
diff --git a/arch/arm/mach-shmobile/platsmp.c b/arch/arm/mach-shmobile/platsmp.c
index 5a2b69cf5ba6..bacdd667e3b1 100644
--- a/arch/arm/mach-shmobile/platsmp.c
+++ b/arch/arm/mach-shmobile/platsmp.c
@@ -20,10 +20,12 @@
20#include <asm/hardware/gic.h> 20#include <asm/hardware/gic.h>
21#include <asm/mach-types.h> 21#include <asm/mach-types.h>
22#include <mach/common.h> 22#include <mach/common.h>
23#include <mach/emev2.h>
23 24
24#define is_sh73a0() (machine_is_ag5evm() || machine_is_kota2() || \ 25#define is_sh73a0() (machine_is_ag5evm() || machine_is_kota2() || \
25 of_machine_is_compatible("renesas,sh73a0")) 26 of_machine_is_compatible("renesas,sh73a0"))
26#define is_r8a7779() machine_is_marzen() 27#define is_r8a7779() machine_is_marzen()
28#define is_emev2() of_machine_is_compatible("renesas,emev2")
27 29
28static unsigned int __init shmobile_smp_get_core_count(void) 30static unsigned int __init shmobile_smp_get_core_count(void)
29{ 31{
@@ -33,6 +35,9 @@ static unsigned int __init shmobile_smp_get_core_count(void)
33 if (is_r8a7779()) 35 if (is_r8a7779())
34 return r8a7779_get_core_count(); 36 return r8a7779_get_core_count();
35 37
38 if (is_emev2())
39 return emev2_get_core_count();
40
36 return 1; 41 return 1;
37} 42}
38 43
@@ -43,6 +48,9 @@ static void __init shmobile_smp_prepare_cpus(void)
43 48
44 if (is_r8a7779()) 49 if (is_r8a7779())
45 r8a7779_smp_prepare_cpus(); 50 r8a7779_smp_prepare_cpus();
51
52 if (is_emev2())
53 emev2_smp_prepare_cpus();
46} 54}
47 55
48int shmobile_platform_cpu_kill(unsigned int cpu) 56int shmobile_platform_cpu_kill(unsigned int cpu)
@@ -50,6 +58,9 @@ int shmobile_platform_cpu_kill(unsigned int cpu)
50 if (is_r8a7779()) 58 if (is_r8a7779())
51 return r8a7779_platform_cpu_kill(cpu); 59 return r8a7779_platform_cpu_kill(cpu);
52 60
61 if (is_emev2())
62 return emev2_platform_cpu_kill(cpu);
63
53 return 1; 64 return 1;
54} 65}
55 66
@@ -62,6 +73,9 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
62 73
63 if (is_r8a7779()) 74 if (is_r8a7779())
64 r8a7779_secondary_init(cpu); 75 r8a7779_secondary_init(cpu);
76
77 if (is_emev2())
78 emev2_secondary_init(cpu);
65} 79}
66 80
67int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) 81int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
@@ -72,6 +86,9 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
72 if (is_r8a7779()) 86 if (is_r8a7779())
73 return r8a7779_boot_secondary(cpu); 87 return r8a7779_boot_secondary(cpu);
74 88
89 if (is_emev2())
90 return emev2_boot_secondary(cpu);
91
75 return -ENOSYS; 92 return -ENOSYS;
76} 93}
77 94
diff --git a/arch/arm/mach-shmobile/setup-emev2.c b/arch/arm/mach-shmobile/setup-emev2.c
new file mode 100644
index 000000000000..dae9aa68bb09
--- /dev/null
+++ b/arch/arm/mach-shmobile/setup-emev2.c
@@ -0,0 +1,452 @@
1/*
2 * Emma Mobile EV2 processor support
3 *
4 * Copyright (C) 2012 Magnus Damm
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 as published by
8 * the Free Software Foundation; version 2 of the License.
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 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19#include <linux/kernel.h>
20#include <linux/init.h>
21#include <linux/interrupt.h>
22#include <linux/irq.h>
23#include <linux/platform_device.h>
24#include <linux/platform_data/gpio-em.h>
25#include <linux/of_platform.h>
26#include <linux/delay.h>
27#include <linux/input.h>
28#include <linux/io.h>
29#include <linux/of_irq.h>
30#include <mach/hardware.h>
31#include <mach/common.h>
32#include <mach/emev2.h>
33#include <mach/irqs.h>
34#include <asm/mach-types.h>
35#include <asm/mach/arch.h>
36#include <asm/mach/map.h>
37#include <asm/mach/time.h>
38#include <asm/hardware/gic.h>
39
40static struct map_desc emev2_io_desc[] __initdata = {
41#ifdef CONFIG_SMP
42 /* 128K entity map for 0xe0100000 (SMU) */
43 {
44 .virtual = 0xe0100000,
45 .pfn = __phys_to_pfn(0xe0100000),
46 .length = SZ_128K,
47 .type = MT_DEVICE
48 },
49 /* 2M mapping for SCU + L2 controller */
50 {
51 .virtual = 0xf0000000,
52 .pfn = __phys_to_pfn(0x1e000000),
53 .length = SZ_2M,
54 .type = MT_DEVICE
55 },
56#endif
57};
58
59void __init emev2_map_io(void)
60{
61 iotable_init(emev2_io_desc, ARRAY_SIZE(emev2_io_desc));
62}
63
64/* UART */
65static struct resource uart0_resources[] = {
66 [0] = {
67 .start = 0xe1020000,
68 .end = 0xe1020037,
69 .flags = IORESOURCE_MEM,
70 },
71 [1] = {
72 .start = 40,
73 .flags = IORESOURCE_IRQ,
74 }
75};
76
77static struct platform_device uart0_device = {
78 .name = "serial8250-em",
79 .id = 0,
80 .num_resources = ARRAY_SIZE(uart0_resources),
81 .resource = uart0_resources,
82};
83
84static struct resource uart1_resources[] = {
85 [0] = {
86 .start = 0xe1030000,
87 .end = 0xe1030037,
88 .flags = IORESOURCE_MEM,
89 },
90 [1] = {
91 .start = 41,
92 .flags = IORESOURCE_IRQ,
93 }
94};
95
96static struct platform_device uart1_device = {
97 .name = "serial8250-em",
98 .id = 1,
99 .num_resources = ARRAY_SIZE(uart1_resources),
100 .resource = uart1_resources,
101};
102
103static struct resource uart2_resources[] = {
104 [0] = {
105 .start = 0xe1040000,
106 .end = 0xe1040037,
107 .flags = IORESOURCE_MEM,
108 },
109 [1] = {
110 .start = 42,
111 .flags = IORESOURCE_IRQ,
112 }
113};
114
115static struct platform_device uart2_device = {
116 .name = "serial8250-em",
117 .id = 2,
118 .num_resources = ARRAY_SIZE(uart2_resources),
119 .resource = uart2_resources,
120};
121
122static struct resource uart3_resources[] = {
123 [0] = {
124 .start = 0xe1050000,
125 .end = 0xe1050037,
126 .flags = IORESOURCE_MEM,
127 },
128 [1] = {
129 .start = 43,
130 .flags = IORESOURCE_IRQ,
131 }
132};
133
134static struct platform_device uart3_device = {
135 .name = "serial8250-em",
136 .id = 3,
137 .num_resources = ARRAY_SIZE(uart3_resources),
138 .resource = uart3_resources,
139};
140
141/* STI */
142static struct resource sti_resources[] = {
143 [0] = {
144 .name = "STI",
145 .start = 0xe0180000,
146 .end = 0xe0180053,
147 .flags = IORESOURCE_MEM,
148 },
149 [1] = {
150 .start = 157,
151 .flags = IORESOURCE_IRQ,
152 },
153};
154
155static struct platform_device sti_device = {
156 .name = "em_sti",
157 .id = 0,
158 .resource = sti_resources,
159 .num_resources = ARRAY_SIZE(sti_resources),
160};
161
162
163/* GIO */
164static struct gpio_em_config gio0_config = {
165 .gpio_base = 0,
166 .irq_base = EMEV2_GPIO_IRQ(0),
167 .number_of_pins = 32,
168};
169
170static struct resource gio0_resources[] = {
171 [0] = {
172 .name = "GIO_000",
173 .start = 0xe0050000,
174 .end = 0xe005002b,
175 .flags = IORESOURCE_MEM,
176 },
177 [1] = {
178 .name = "GIO_000",
179 .start = 0xe0050040,
180 .end = 0xe005005f,
181 .flags = IORESOURCE_MEM,
182 },
183 [2] = {
184 .start = 99,
185 .flags = IORESOURCE_IRQ,
186 },
187 [3] = {
188 .start = 100,
189 .flags = IORESOURCE_IRQ,
190 },
191};
192
193static struct platform_device gio0_device = {
194 .name = "em_gio",
195 .id = 0,
196 .resource = gio0_resources,
197 .num_resources = ARRAY_SIZE(gio0_resources),
198 .dev = {
199 .platform_data = &gio0_config,
200 },
201};
202
203static struct gpio_em_config gio1_config = {
204 .gpio_base = 32,
205 .irq_base = EMEV2_GPIO_IRQ(32),
206 .number_of_pins = 32,
207};
208
209static struct resource gio1_resources[] = {
210 [0] = {
211 .name = "GIO_032",
212 .start = 0xe0050080,
213 .end = 0xe00500ab,
214 .flags = IORESOURCE_MEM,
215 },
216 [1] = {
217 .name = "GIO_032",
218 .start = 0xe00500c0,
219 .end = 0xe00500df,
220 .flags = IORESOURCE_MEM,
221 },
222 [2] = {
223 .start = 101,
224 .flags = IORESOURCE_IRQ,
225 },
226 [3] = {
227 .start = 102,
228 .flags = IORESOURCE_IRQ,
229 },
230};
231
232static struct platform_device gio1_device = {
233 .name = "em_gio",
234 .id = 1,
235 .resource = gio1_resources,
236 .num_resources = ARRAY_SIZE(gio1_resources),
237 .dev = {
238 .platform_data = &gio1_config,
239 },
240};
241
242static struct gpio_em_config gio2_config = {
243 .gpio_base = 64,
244 .irq_base = EMEV2_GPIO_IRQ(64),
245 .number_of_pins = 32,
246};
247
248static struct resource gio2_resources[] = {
249 [0] = {
250 .name = "GIO_064",
251 .start = 0xe0050100,
252 .end = 0xe005012b,
253 .flags = IORESOURCE_MEM,
254 },
255 [1] = {
256 .name = "GIO_064",
257 .start = 0xe0050140,
258 .end = 0xe005015f,
259 .flags = IORESOURCE_MEM,
260 },
261 [2] = {
262 .start = 103,
263 .flags = IORESOURCE_IRQ,
264 },
265 [3] = {
266 .start = 104,
267 .flags = IORESOURCE_IRQ,
268 },
269};
270
271static struct platform_device gio2_device = {
272 .name = "em_gio",
273 .id = 2,
274 .resource = gio2_resources,
275 .num_resources = ARRAY_SIZE(gio2_resources),
276 .dev = {
277 .platform_data = &gio2_config,
278 },
279};
280
281static struct gpio_em_config gio3_config = {
282 .gpio_base = 96,
283 .irq_base = EMEV2_GPIO_IRQ(96),
284 .number_of_pins = 32,
285};
286
287static struct resource gio3_resources[] = {
288 [0] = {
289 .name = "GIO_096",
290 .start = 0xe0050100,
291 .end = 0xe005012b,
292 .flags = IORESOURCE_MEM,
293 },
294 [1] = {
295 .name = "GIO_096",
296 .start = 0xe0050140,
297 .end = 0xe005015f,
298 .flags = IORESOURCE_MEM,
299 },
300 [2] = {
301 .start = 105,
302 .flags = IORESOURCE_IRQ,
303 },
304 [3] = {
305 .start = 106,
306 .flags = IORESOURCE_IRQ,
307 },
308};
309
310static struct platform_device gio3_device = {
311 .name = "em_gio",
312 .id = 3,
313 .resource = gio3_resources,
314 .num_resources = ARRAY_SIZE(gio3_resources),
315 .dev = {
316 .platform_data = &gio3_config,
317 },
318};
319
320static struct gpio_em_config gio4_config = {
321 .gpio_base = 128,
322 .irq_base = EMEV2_GPIO_IRQ(128),
323 .number_of_pins = 31,
324};
325
326static struct resource gio4_resources[] = {
327 [0] = {
328 .name = "GIO_128",
329 .start = 0xe0050200,
330 .end = 0xe005022b,
331 .flags = IORESOURCE_MEM,
332 },
333 [1] = {
334 .name = "GIO_128",
335 .start = 0xe0050240,
336 .end = 0xe005025f,
337 .flags = IORESOURCE_MEM,
338 },
339 [2] = {
340 .start = 107,
341 .flags = IORESOURCE_IRQ,
342 },
343 [3] = {
344 .start = 108,
345 .flags = IORESOURCE_IRQ,
346 },
347};
348
349static struct platform_device gio4_device = {
350 .name = "em_gio",
351 .id = 4,
352 .resource = gio4_resources,
353 .num_resources = ARRAY_SIZE(gio4_resources),
354 .dev = {
355 .platform_data = &gio4_config,
356 },
357};
358
359static struct platform_device *emev2_early_devices[] __initdata = {
360 &uart0_device,
361 &uart1_device,
362 &uart2_device,
363 &uart3_device,
364};
365
366static struct platform_device *emev2_late_devices[] __initdata = {
367 &sti_device,
368 &gio0_device,
369 &gio1_device,
370 &gio2_device,
371 &gio3_device,
372 &gio4_device,
373};
374
375void __init emev2_add_standard_devices(void)
376{
377 emev2_clock_init();
378
379 platform_add_devices(emev2_early_devices,
380 ARRAY_SIZE(emev2_early_devices));
381
382 platform_add_devices(emev2_late_devices,
383 ARRAY_SIZE(emev2_late_devices));
384}
385
386void __init emev2_init_delay(void)
387{
388 shmobile_setup_delay(533, 1, 3); /* Cortex-A9 @ 533MHz */
389}
390
391void __init emev2_add_early_devices(void)
392{
393 emev2_init_delay();
394
395 early_platform_add_devices(emev2_early_devices,
396 ARRAY_SIZE(emev2_early_devices));
397
398 /* setup early console here as well */
399 shmobile_setup_console();
400}
401
402void __init emev2_init_irq(void)
403{
404 void __iomem *gic_dist_base;
405 void __iomem *gic_cpu_base;
406
407 /* Static mappings, never released */
408 gic_dist_base = ioremap(0xe0028000, PAGE_SIZE);
409 gic_cpu_base = ioremap(0xe0020000, PAGE_SIZE);
410 BUG_ON(!gic_dist_base || !gic_cpu_base);
411
412 /* Use GIC to handle interrupts */
413 gic_init(0, 29, gic_dist_base, gic_cpu_base);
414}
415
416#ifdef CONFIG_USE_OF
417static const struct of_dev_auxdata emev2_auxdata_lookup[] __initconst = {
418 { }
419};
420
421void __init emev2_add_standard_devices_dt(void)
422{
423 of_platform_populate(NULL, of_default_bus_match_table,
424 emev2_auxdata_lookup, NULL);
425}
426
427static const struct of_device_id emev2_dt_irq_match[] = {
428 { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
429 {},
430};
431
432static const char *emev2_boards_compat_dt[] __initdata = {
433 "renesas,emev2",
434 NULL,
435};
436
437void __init emev2_init_irq_dt(void)
438{
439 of_irq_init(emev2_dt_irq_match);
440}
441
442DT_MACHINE_START(EMEV2_DT, "Generic Emma Mobile EV2 (Flattened Device Tree)")
443 .init_early = emev2_init_delay,
444 .nr_irqs = NR_IRQS_LEGACY,
445 .init_irq = emev2_init_irq_dt,
446 .handle_irq = gic_handle_irq,
447 .init_machine = emev2_add_standard_devices_dt,
448 .timer = &shmobile_timer,
449 .dt_compat = emev2_boards_compat_dt,
450MACHINE_END
451
452#endif /* CONFIG_USE_OF */
diff --git a/arch/arm/mach-shmobile/smp-emev2.c b/arch/arm/mach-shmobile/smp-emev2.c
new file mode 100644
index 000000000000..6a35c4a31e6c
--- /dev/null
+++ b/arch/arm/mach-shmobile/smp-emev2.c
@@ -0,0 +1,97 @@
1/*
2 * SMP support for Emma Mobile EV2
3 *
4 * Copyright (C) 2012 Renesas Solutions Corp.
5 * Copyright (C) 2012 Magnus Damm
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20#include <linux/kernel.h>
21#include <linux/init.h>
22#include <linux/smp.h>
23#include <linux/spinlock.h>
24#include <linux/io.h>
25#include <linux/delay.h>
26#include <mach/common.h>
27#include <mach/emev2.h>
28#include <asm/smp_plat.h>
29#include <asm/smp_scu.h>
30#include <asm/hardware/gic.h>
31#include <asm/cacheflush.h>
32
33#define EMEV2_SCU_BASE 0x1e000000
34
35static DEFINE_SPINLOCK(scu_lock);
36static void __iomem *scu_base;
37
38static void modify_scu_cpu_psr(unsigned long set, unsigned long clr)
39{
40 unsigned long tmp;
41
42 /* we assume this code is running on a different cpu
43 * than the one that is changing coherency setting */
44 spin_lock(&scu_lock);
45 tmp = readl(scu_base + 8);
46 tmp &= ~clr;
47 tmp |= set;
48 writel(tmp, scu_base + 8);
49 spin_unlock(&scu_lock);
50
51}
52
53unsigned int __init emev2_get_core_count(void)
54{
55 if (!scu_base) {
56 scu_base = ioremap(EMEV2_SCU_BASE, PAGE_SIZE);
57 emev2_clock_init(); /* need ioremapped SMU */
58 }
59
60 WARN_ON_ONCE(!scu_base);
61
62 return scu_base ? scu_get_core_count(scu_base) : 1;
63}
64
65int emev2_platform_cpu_kill(unsigned int cpu)
66{
67 return 0; /* not supported yet */
68}
69
70void __cpuinit emev2_secondary_init(unsigned int cpu)
71{
72 gic_secondary_init(0);
73}
74
75int __cpuinit emev2_boot_secondary(unsigned int cpu)
76{
77 cpu = cpu_logical_map(cpu);
78
79 /* enable cache coherency */
80 modify_scu_cpu_psr(0, 3 << (cpu * 8));
81
82 /* Tell ROM loader about our vector (in headsmp.S) */
83 emev2_set_boot_vector(__pa(shmobile_secondary_vector));
84
85 gic_raise_softirq(cpumask_of(cpu), 1);
86 return 0;
87}
88
89void __init emev2_smp_prepare_cpus(void)
90{
91 int cpu = cpu_logical_map(0);
92
93 scu_enable(scu_base);
94
95 /* enable cache coherency on CPU0 */
96 modify_scu_cpu_psr(0, 3 << (cpu * 8));
97}