aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-shmobile
diff options
context:
space:
mode:
authorMagnus Damm <damm@opensource.se>2012-05-16 02:44:58 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2012-05-17 18:14:01 -0400
commit7f627f0380cb5ba3e05bcaac31ecf40c1f508ec1 (patch)
treec9a6738e73afdeb7aca1bef4d0114b1f3fc7428c /arch/arm/mach-shmobile
parenta07e103ef08c6907d695a06467d7ee950796fccf (diff)
mach-shmobile: Emma Mobile EV2 SoC base support V3
This is V3 of the Emma Mobile EV2 SoC support. Included here is support for serial and timer devices which is just about enough to boot a kernel. Signed-off-by: Magnus Damm <damm@opensource.se> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'arch/arm/mach-shmobile')
-rw-r--r--arch/arm/mach-shmobile/Kconfig5
-rw-r--r--arch/arm/mach-shmobile/Makefile1
-rw-r--r--arch/arm/mach-shmobile/clock-emev2.c226
-rw-r--r--arch/arm/mach-shmobile/include/mach/emev2.h9
-rw-r--r--arch/arm/mach-shmobile/setup-emev2.c180
5 files changed, 421 insertions, 0 deletions
diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
index 34560cab45d9..fadafe3b4e88 100644
--- a/arch/arm/mach-shmobile/Kconfig
+++ b/arch/arm/mach-shmobile/Kconfig
@@ -41,6 +41,11 @@ 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
44comment "SH-Mobile Board Type" 49comment "SH-Mobile Board Type"
45 50
46config MACH_G3EVM 51config MACH_G3EVM
diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile
index e7c2590b75d9..fd84aa2108a9 100644
--- a/arch/arm/mach-shmobile/Makefile
+++ b/arch/arm/mach-shmobile/Makefile
@@ -12,6 +12,7 @@ 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
diff --git a/arch/arm/mach-shmobile/clock-emev2.c b/arch/arm/mach-shmobile/clock-emev2.c
new file mode 100644
index 000000000000..73a121659314
--- /dev/null
+++ b/arch/arm/mach-shmobile/clock-emev2.c
@@ -0,0 +1,226 @@
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
44/* not pretty, but hey */
45static void __iomem *smu_base;
46
47static void emev2_smu_write(unsigned long value, int offs)
48{
49 BUG_ON(!smu_base || (offs >= PAGE_SIZE));
50 iowrite32(value, smu_base + offs);
51}
52
53static struct clk_mapping smu_mapping = {
54 .phys = EMEV2_SMU_BASE,
55 .len = PAGE_SIZE,
56};
57
58/* Fixed 32 KHz root clock from C32K pin */
59static struct clk c32k_clk = {
60 .rate = 32768,
61 .mapping = &smu_mapping,
62};
63
64/* PLL3 multiplies C32K with 7000 */
65static unsigned long pll3_recalc(struct clk *clk)
66{
67 return clk->parent->rate * 7000;
68}
69
70static struct sh_clk_ops pll3_clk_ops = {
71 .recalc = pll3_recalc,
72};
73
74static struct clk pll3_clk = {
75 .ops = &pll3_clk_ops,
76 .parent = &c32k_clk,
77};
78
79static struct clk *main_clks[] = {
80 &c32k_clk,
81 &pll3_clk,
82};
83
84enum { SCLKDIV_USIAU0, SCLKDIV_USIBU2, SCLKDIV_USIBU1, SCLKDIV_USIBU3,
85 SCLKDIV_NR };
86
87#define SCLKDIV(_reg, _shift) \
88{ \
89 .parent = &pll3_clk, \
90 .enable_reg = IOMEM(EMEV2_SMU_BASE + (_reg)), \
91 .enable_bit = _shift, \
92}
93
94static struct clk sclkdiv_clks[SCLKDIV_NR] = {
95 [SCLKDIV_USIAU0] = SCLKDIV(USIAU0SCLKDIV, 0),
96 [SCLKDIV_USIBU2] = SCLKDIV(USIB2SCLKDIV, 16),
97 [SCLKDIV_USIBU1] = SCLKDIV(USIB2SCLKDIV, 0),
98 [SCLKDIV_USIBU3] = SCLKDIV(USIB3SCLKDIV, 0),
99};
100
101enum { GCLK_USIAU0_SCLK, GCLK_USIBU1_SCLK, GCLK_USIBU2_SCLK, GCLK_USIBU3_SCLK,
102 GCLK_STI_SCLK,
103 GCLK_NR };
104
105#define GCLK_SCLK(_parent, _reg) \
106{ \
107 .parent = _parent, \
108 .enable_reg = IOMEM(EMEV2_SMU_BASE + (_reg)), \
109 .enable_bit = 1, /* SCLK_GCC */ \
110}
111
112static struct clk gclk_clks[GCLK_NR] = {
113 [GCLK_USIAU0_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIAU0],
114 USIAU0GCLKCTRL),
115 [GCLK_USIBU1_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU1],
116 USIBU1GCLKCTRL),
117 [GCLK_USIBU2_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU2],
118 USIBU2GCLKCTRL),
119 [GCLK_USIBU3_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU3],
120 USIBU3GCLKCTRL),
121 [GCLK_STI_SCLK] = GCLK_SCLK(&c32k_clk, STIGCLKCTRL),
122};
123
124static int emev2_gclk_enable(struct clk *clk)
125{
126 iowrite32(ioread32(clk->mapped_reg) | (1 << clk->enable_bit),
127 clk->mapped_reg);
128 return 0;
129}
130
131static void emev2_gclk_disable(struct clk *clk)
132{
133 iowrite32(ioread32(clk->mapped_reg) & ~(1 << clk->enable_bit),
134 clk->mapped_reg);
135}
136
137static struct sh_clk_ops emev2_gclk_clk_ops = {
138 .enable = emev2_gclk_enable,
139 .disable = emev2_gclk_disable,
140 .recalc = followparent_recalc,
141};
142
143static int __init emev2_gclk_register(struct clk *clks, int nr)
144{
145 struct clk *clkp;
146 int ret = 0;
147 int k;
148
149 for (k = 0; !ret && (k < nr); k++) {
150 clkp = clks + k;
151 clkp->ops = &emev2_gclk_clk_ops;
152 ret |= clk_register(clkp);
153 }
154
155 return ret;
156}
157
158static unsigned long emev2_sclkdiv_recalc(struct clk *clk)
159{
160 unsigned int sclk_div;
161
162 sclk_div = (ioread32(clk->mapped_reg) >> clk->enable_bit) & 0xff;
163
164 return clk->parent->rate / (sclk_div + 1);
165}
166
167static struct sh_clk_ops emev2_sclkdiv_clk_ops = {
168 .recalc = emev2_sclkdiv_recalc,
169};
170
171static int __init emev2_sclkdiv_register(struct clk *clks, int nr)
172{
173 struct clk *clkp;
174 int ret = 0;
175 int k;
176
177 for (k = 0; !ret && (k < nr); k++) {
178 clkp = clks + k;
179 clkp->ops = &emev2_sclkdiv_clk_ops;
180 ret |= clk_register(clkp);
181 }
182
183 return ret;
184}
185
186static struct clk_lookup lookups[] = {
187 CLKDEV_DEV_ID("serial8250-em.0", &gclk_clks[GCLK_USIAU0_SCLK]),
188 CLKDEV_DEV_ID("serial8250-em.1", &gclk_clks[GCLK_USIBU1_SCLK]),
189 CLKDEV_DEV_ID("serial8250-em.2", &gclk_clks[GCLK_USIBU2_SCLK]),
190 CLKDEV_DEV_ID("serial8250-em.3", &gclk_clks[GCLK_USIBU3_SCLK]),
191 CLKDEV_DEV_ID("em_sti.0", &gclk_clks[GCLK_STI_SCLK]),
192};
193
194void __init emev2_clock_init(void)
195{
196 int k, ret = 0;
197
198 smu_base = ioremap(EMEV2_SMU_BASE, PAGE_SIZE);
199 BUG_ON(!smu_base);
200
201 /* setup STI timer to run on 37.768 kHz and deassert reset */
202 emev2_smu_write(0, STI_CLKSEL);
203 emev2_smu_write(1, STI_RSTCTRL);
204
205 /* deassert reset for UART0->UART3 */
206 emev2_smu_write(2, USIAU0_RSTCTRL);
207 emev2_smu_write(2, USIBU1_RSTCTRL);
208 emev2_smu_write(2, USIBU2_RSTCTRL);
209 emev2_smu_write(2, USIBU3_RSTCTRL);
210
211 for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
212 ret = clk_register(main_clks[k]);
213
214 if (!ret)
215 ret = emev2_sclkdiv_register(sclkdiv_clks, SCLKDIV_NR);
216
217 if (!ret)
218 ret = emev2_gclk_register(gclk_clks, GCLK_NR);
219
220 clkdev_add_table(lookups, ARRAY_SIZE(lookups));
221
222 if (!ret)
223 shmobile_clk_init();
224 else
225 panic("failed to setup emev2 clocks\n");
226}
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..92646c1de616
--- /dev/null
+++ b/arch/arm/mach-shmobile/include/mach/emev2.h
@@ -0,0 +1,9 @@
1#ifndef __ASM_EMEV2_H__
2#define __ASM_EMEV2_H__
3
4extern void emev2_init_irq(void);
5extern void emev2_add_early_devices(void);
6extern void emev2_add_standard_devices(void);
7extern void emev2_clock_init(void);
8
9#endif /* __ASM_EMEV2_H__ */
diff --git a/arch/arm/mach-shmobile/setup-emev2.c b/arch/arm/mach-shmobile/setup-emev2.c
new file mode 100644
index 000000000000..9fff62336911
--- /dev/null
+++ b/arch/arm/mach-shmobile/setup-emev2.c
@@ -0,0 +1,180 @@
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/delay.h>
25#include <linux/input.h>
26#include <linux/io.h>
27#include <mach/hardware.h>
28#include <mach/common.h>
29#include <mach/emev2.h>
30#include <mach/irqs.h>
31#include <asm/mach-types.h>
32#include <asm/mach/arch.h>
33#include <asm/mach/map.h>
34#include <asm/mach/time.h>
35#include <asm/hardware/gic.h>
36
37/* UART */
38static struct resource uart0_resources[] = {
39 [0] = {
40 .start = 0xe1020000,
41 .end = 0xe1020037,
42 .flags = IORESOURCE_MEM,
43 },
44 [1] = {
45 .start = 40,
46 .flags = IORESOURCE_IRQ,
47 }
48};
49
50static struct platform_device uart0_device = {
51 .name = "serial8250-em",
52 .id = 0,
53 .num_resources = ARRAY_SIZE(uart0_resources),
54 .resource = uart0_resources,
55};
56
57static struct resource uart1_resources[] = {
58 [0] = {
59 .start = 0xe1030000,
60 .end = 0xe1030037,
61 .flags = IORESOURCE_MEM,
62 },
63 [1] = {
64 .start = 41,
65 .flags = IORESOURCE_IRQ,
66 }
67};
68
69static struct platform_device uart1_device = {
70 .name = "serial8250-em",
71 .id = 1,
72 .num_resources = ARRAY_SIZE(uart1_resources),
73 .resource = uart1_resources,
74};
75
76static struct resource uart2_resources[] = {
77 [0] = {
78 .start = 0xe1040000,
79 .end = 0xe1040037,
80 .flags = IORESOURCE_MEM,
81 },
82 [1] = {
83 .start = 42,
84 .flags = IORESOURCE_IRQ,
85 }
86};
87
88static struct platform_device uart2_device = {
89 .name = "serial8250-em",
90 .id = 2,
91 .num_resources = ARRAY_SIZE(uart2_resources),
92 .resource = uart2_resources,
93};
94
95static struct resource uart3_resources[] = {
96 [0] = {
97 .start = 0xe1050000,
98 .end = 0xe1050037,
99 .flags = IORESOURCE_MEM,
100 },
101 [1] = {
102 .start = 43,
103 .flags = IORESOURCE_IRQ,
104 }
105};
106
107static struct platform_device uart3_device = {
108 .name = "serial8250-em",
109 .id = 3,
110 .num_resources = ARRAY_SIZE(uart3_resources),
111 .resource = uart3_resources,
112};
113
114/* STI */
115static struct resource sti_resources[] = {
116 [0] = {
117 .name = "STI",
118 .start = 0xe0180000,
119 .end = 0xe0180053,
120 .flags = IORESOURCE_MEM,
121 },
122 [1] = {
123 .start = 157,
124 .flags = IORESOURCE_IRQ,
125 },
126};
127
128static struct platform_device sti_device = {
129 .name = "em_sti",
130 .id = 0,
131 .resource = sti_resources,
132 .num_resources = ARRAY_SIZE(sti_resources),
133};
134
135static struct platform_device *emev2_early_devices[] __initdata = {
136 &uart0_device,
137 &uart1_device,
138 &uart2_device,
139 &uart3_device,
140};
141
142static struct platform_device *emev2_late_devices[] __initdata = {
143 &sti_device,
144};
145
146void __init emev2_add_standard_devices(void)
147{
148 emev2_clock_init();
149
150 platform_add_devices(emev2_early_devices,
151 ARRAY_SIZE(emev2_early_devices));
152
153 platform_add_devices(emev2_late_devices,
154 ARRAY_SIZE(emev2_late_devices));
155}
156
157void __init emev2_add_early_devices(void)
158{
159 shmobile_setup_delay(533, 1, 3); /* Cortex-A9 @ 533MHz */
160
161 early_platform_add_devices(emev2_early_devices,
162 ARRAY_SIZE(emev2_early_devices));
163
164 /* setup early console here as well */
165 shmobile_setup_console();
166}
167
168void __init emev2_init_irq(void)
169{
170 void __iomem *gic_dist_base;
171 void __iomem *gic_cpu_base;
172
173 /* Static mappings, never released */
174 gic_dist_base = ioremap(0xe0028000, PAGE_SIZE);
175 gic_cpu_base = ioremap(0xe0020000, PAGE_SIZE);
176 BUG_ON(!gic_dist_base || !gic_cpu_base);
177
178 /* Use GIC to handle interrupts */
179 gic_init(0, 29, gic_dist_base, gic_cpu_base);
180}