diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-02-11 16:44:53 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-05-02 04:35:38 -0400 |
commit | ceade897f31b8bb66f378cc35859fcfd0d46aaa2 (patch) | |
tree | 44f6fffb4f93ec6247b468e4009e414b4124f585 /arch/arm/mach-vexpress/v2m.c | |
parent | 9bf5b2ef673237e0e43161c56f70ac8bf24e43f9 (diff) |
ARM: Add Versatile Express support
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mach-vexpress/v2m.c')
-rw-r--r-- | arch/arm/mach-vexpress/v2m.c | 361 |
1 files changed, 361 insertions, 0 deletions
diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c new file mode 100644 index 000000000000..d250711b8c7a --- /dev/null +++ b/arch/arm/mach-vexpress/v2m.c | |||
@@ -0,0 +1,361 @@ | |||
1 | /* | ||
2 | * Versatile Express V2M Motherboard Support | ||
3 | */ | ||
4 | #include <linux/device.h> | ||
5 | #include <linux/amba/bus.h> | ||
6 | #include <linux/amba/mmci.h> | ||
7 | #include <linux/io.h> | ||
8 | #include <linux/init.h> | ||
9 | #include <linux/platform_device.h> | ||
10 | #include <linux/smsc911x.h> | ||
11 | #include <linux/spinlock.h> | ||
12 | #include <linux/sysdev.h> | ||
13 | #include <linux/usb/isp1760.h> | ||
14 | |||
15 | #include <asm/clkdev.h> | ||
16 | #include <asm/sizes.h> | ||
17 | #include <asm/mach/flash.h> | ||
18 | #include <asm/mach/map.h> | ||
19 | #include <asm/mach/time.h> | ||
20 | #include <asm/hardware/arm_timer.h> | ||
21 | |||
22 | #include <mach/clkdev.h> | ||
23 | #include <mach/motherboard.h> | ||
24 | |||
25 | #include <plat/timer-sp.h> | ||
26 | |||
27 | #include "core.h" | ||
28 | |||
29 | #define V2M_PA_CS0 0x40000000 | ||
30 | #define V2M_PA_CS1 0x44000000 | ||
31 | #define V2M_PA_CS2 0x48000000 | ||
32 | #define V2M_PA_CS3 0x4c000000 | ||
33 | #define V2M_PA_CS7 0x10000000 | ||
34 | |||
35 | static struct map_desc v2m_io_desc[] __initdata = { | ||
36 | { | ||
37 | .virtual = __MMIO_P2V(V2M_PA_CS7), | ||
38 | .pfn = __phys_to_pfn(V2M_PA_CS7), | ||
39 | .length = SZ_128K, | ||
40 | .type = MT_DEVICE, | ||
41 | }, | ||
42 | }; | ||
43 | |||
44 | void __init v2m_map_io(struct map_desc *tile, size_t num) | ||
45 | { | ||
46 | iotable_init(v2m_io_desc, ARRAY_SIZE(v2m_io_desc)); | ||
47 | iotable_init(tile, num); | ||
48 | } | ||
49 | |||
50 | |||
51 | static void v2m_timer_init(void) | ||
52 | { | ||
53 | writel(0, MMIO_P2V(V2M_TIMER0) + TIMER_CTRL); | ||
54 | writel(0, MMIO_P2V(V2M_TIMER1) + TIMER_CTRL); | ||
55 | |||
56 | sp804_clocksource_init(MMIO_P2V(V2M_TIMER1)); | ||
57 | sp804_clockevents_init(MMIO_P2V(V2M_TIMER0), IRQ_V2M_TIMER0); | ||
58 | } | ||
59 | |||
60 | struct sys_timer v2m_timer = { | ||
61 | .init = v2m_timer_init, | ||
62 | }; | ||
63 | |||
64 | |||
65 | static DEFINE_SPINLOCK(v2m_cfg_lock); | ||
66 | |||
67 | int v2m_cfg_write(u32 devfn, u32 data) | ||
68 | { | ||
69 | /* Configuration interface broken? */ | ||
70 | u32 val; | ||
71 | |||
72 | printk("%s: writing %08x to %08x\n", __func__, data, devfn); | ||
73 | |||
74 | devfn |= SYS_CFG_START | SYS_CFG_WRITE; | ||
75 | |||
76 | spin_lock(&v2m_cfg_lock); | ||
77 | val = readl(MMIO_P2V(V2M_SYS_CFGSTAT)); | ||
78 | writel(val & ~SYS_CFG_COMPLETE, MMIO_P2V(V2M_SYS_CFGSTAT)); | ||
79 | |||
80 | writel(data, MMIO_P2V(V2M_SYS_CFGDATA)); | ||
81 | writel(devfn, MMIO_P2V(V2M_SYS_CFGCTRL)); | ||
82 | |||
83 | do { | ||
84 | val = readl(MMIO_P2V(V2M_SYS_CFGSTAT)); | ||
85 | } while (val == 0); | ||
86 | spin_unlock(&v2m_cfg_lock); | ||
87 | |||
88 | return !!(val & SYS_CFG_ERR); | ||
89 | } | ||
90 | |||
91 | int v2m_cfg_read(u32 devfn, u32 *data) | ||
92 | { | ||
93 | u32 val; | ||
94 | |||
95 | devfn |= SYS_CFG_START; | ||
96 | |||
97 | spin_lock(&v2m_cfg_lock); | ||
98 | writel(0, MMIO_P2V(V2M_SYS_CFGSTAT)); | ||
99 | writel(devfn, MMIO_P2V(V2M_SYS_CFGCTRL)); | ||
100 | |||
101 | mb(); | ||
102 | |||
103 | do { | ||
104 | cpu_relax(); | ||
105 | val = readl(MMIO_P2V(V2M_SYS_CFGSTAT)); | ||
106 | } while (val == 0); | ||
107 | |||
108 | *data = readl(MMIO_P2V(V2M_SYS_CFGDATA)); | ||
109 | spin_unlock(&v2m_cfg_lock); | ||
110 | |||
111 | return !!(val & SYS_CFG_ERR); | ||
112 | } | ||
113 | |||
114 | |||
115 | static struct resource v2m_pcie_i2c_resource = { | ||
116 | .start = V2M_SERIAL_BUS_PCI, | ||
117 | .end = V2M_SERIAL_BUS_PCI + SZ_4K - 1, | ||
118 | .flags = IORESOURCE_MEM, | ||
119 | }; | ||
120 | |||
121 | static struct platform_device v2m_pcie_i2c_device = { | ||
122 | .name = "versatile-i2c", | ||
123 | .id = 0, | ||
124 | .num_resources = 1, | ||
125 | .resource = &v2m_pcie_i2c_resource, | ||
126 | }; | ||
127 | |||
128 | static struct resource v2m_ddc_i2c_resource = { | ||
129 | .start = V2M_SERIAL_BUS_DVI, | ||
130 | .end = V2M_SERIAL_BUS_DVI + SZ_4K - 1, | ||
131 | .flags = IORESOURCE_MEM, | ||
132 | }; | ||
133 | |||
134 | static struct platform_device v2m_ddc_i2c_device = { | ||
135 | .name = "versatile-i2c", | ||
136 | .id = 1, | ||
137 | .num_resources = 1, | ||
138 | .resource = &v2m_ddc_i2c_resource, | ||
139 | }; | ||
140 | |||
141 | static struct resource v2m_eth_resources[] = { | ||
142 | { | ||
143 | .start = V2M_LAN9118, | ||
144 | .end = V2M_LAN9118 + SZ_64K - 1, | ||
145 | .flags = IORESOURCE_MEM, | ||
146 | }, { | ||
147 | .start = IRQ_V2M_LAN9118, | ||
148 | .end = IRQ_V2M_LAN9118, | ||
149 | .flags = IORESOURCE_IRQ, | ||
150 | }, | ||
151 | }; | ||
152 | |||
153 | static struct smsc911x_platform_config v2m_eth_config = { | ||
154 | .flags = SMSC911X_USE_32BIT, | ||
155 | .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH, | ||
156 | .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, | ||
157 | .phy_interface = PHY_INTERFACE_MODE_MII, | ||
158 | }; | ||
159 | |||
160 | static struct platform_device v2m_eth_device = { | ||
161 | .name = "smsc911x", | ||
162 | .id = -1, | ||
163 | .resource = v2m_eth_resources, | ||
164 | .num_resources = ARRAY_SIZE(v2m_eth_resources), | ||
165 | .dev.platform_data = &v2m_eth_config, | ||
166 | }; | ||
167 | |||
168 | static struct resource v2m_usb_resources[] = { | ||
169 | { | ||
170 | .start = V2M_ISP1761, | ||
171 | .end = V2M_ISP1761 + SZ_128K - 1, | ||
172 | .flags = IORESOURCE_MEM, | ||
173 | }, { | ||
174 | .start = IRQ_V2M_ISP1761, | ||
175 | .end = IRQ_V2M_ISP1761, | ||
176 | .flags = IORESOURCE_IRQ, | ||
177 | }, | ||
178 | }; | ||
179 | |||
180 | static struct isp1760_platform_data v2m_usb_config = { | ||
181 | .is_isp1761 = true, | ||
182 | .bus_width_16 = false, | ||
183 | .port1_otg = true, | ||
184 | .analog_oc = false, | ||
185 | .dack_polarity_high = false, | ||
186 | .dreq_polarity_high = false, | ||
187 | }; | ||
188 | |||
189 | static struct platform_device v2m_usb_device = { | ||
190 | .name = "isp1760", | ||
191 | .id = -1, | ||
192 | .resource = v2m_usb_resources, | ||
193 | .num_resources = ARRAY_SIZE(v2m_usb_resources), | ||
194 | .dev.platform_data = &v2m_usb_config, | ||
195 | }; | ||
196 | |||
197 | static int v2m_flash_init(void) | ||
198 | { | ||
199 | writel(0, MMIO_P2V(V2M_SYS_FLASH)); | ||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | static void v2m_flash_exit(void) | ||
204 | { | ||
205 | writel(0, MMIO_P2V(V2M_SYS_FLASH)); | ||
206 | } | ||
207 | |||
208 | static void v2m_flash_set_vpp(int on) | ||
209 | { | ||
210 | writel(on != 0, MMIO_P2V(V2M_SYS_FLASH)); | ||
211 | } | ||
212 | |||
213 | static struct flash_platform_data v2m_flash_data = { | ||
214 | .map_name = "cfi_probe", | ||
215 | .width = 4, | ||
216 | .init = v2m_flash_init, | ||
217 | .exit = v2m_flash_exit, | ||
218 | .set_vpp = v2m_flash_set_vpp, | ||
219 | }; | ||
220 | |||
221 | static struct resource v2m_flash_resources[] = { | ||
222 | { | ||
223 | .start = V2M_NOR0, | ||
224 | .end = V2M_NOR0 + SZ_64M - 1, | ||
225 | .flags = IORESOURCE_MEM, | ||
226 | }, { | ||
227 | .start = V2M_NOR1, | ||
228 | .end = V2M_NOR1 + SZ_64M - 1, | ||
229 | .flags = IORESOURCE_MEM, | ||
230 | }, | ||
231 | }; | ||
232 | |||
233 | static struct platform_device v2m_flash_device = { | ||
234 | .name = "armflash", | ||
235 | .id = -1, | ||
236 | .resource = v2m_flash_resources, | ||
237 | .num_resources = ARRAY_SIZE(v2m_flash_resources), | ||
238 | .dev.platform_data = &v2m_flash_data, | ||
239 | }; | ||
240 | |||
241 | |||
242 | static unsigned int v2m_mmci_status(struct device *dev) | ||
243 | { | ||
244 | return !(readl(MMIO_P2V(V2M_SYS_MCI)) & (1 << 0)); | ||
245 | } | ||
246 | |||
247 | static struct mmci_platform_data v2m_mmci_data = { | ||
248 | .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, | ||
249 | .status = v2m_mmci_status, | ||
250 | }; | ||
251 | |||
252 | static AMBA_DEVICE(aaci, "mb:aaci", V2M_AACI, NULL); | ||
253 | static AMBA_DEVICE(mmci, "mb:mmci", V2M_MMCI, &v2m_mmci_data); | ||
254 | static AMBA_DEVICE(kmi0, "mb:kmi0", V2M_KMI0, NULL); | ||
255 | static AMBA_DEVICE(kmi1, "mb:kmi1", V2M_KMI1, NULL); | ||
256 | static AMBA_DEVICE(uart0, "mb:uart0", V2M_UART0, NULL); | ||
257 | static AMBA_DEVICE(uart1, "mb:uart1", V2M_UART1, NULL); | ||
258 | static AMBA_DEVICE(uart2, "mb:uart2", V2M_UART2, NULL); | ||
259 | static AMBA_DEVICE(uart3, "mb:uart3", V2M_UART3, NULL); | ||
260 | static AMBA_DEVICE(wdt, "mb:wdt", V2M_WDT, NULL); | ||
261 | static AMBA_DEVICE(rtc, "mb:rtc", V2M_RTC, NULL); | ||
262 | |||
263 | static struct amba_device *v2m_amba_devs[] __initdata = { | ||
264 | &aaci_device, | ||
265 | &mmci_device, | ||
266 | &kmi0_device, | ||
267 | &kmi1_device, | ||
268 | &uart0_device, | ||
269 | &uart1_device, | ||
270 | &uart2_device, | ||
271 | &uart3_device, | ||
272 | &wdt_device, | ||
273 | &rtc_device, | ||
274 | }; | ||
275 | |||
276 | |||
277 | static long v2m_osc_round(struct clk *clk, unsigned long rate) | ||
278 | { | ||
279 | return rate; | ||
280 | } | ||
281 | |||
282 | static int v2m_osc1_set(struct clk *clk, unsigned long rate) | ||
283 | { | ||
284 | return v2m_cfg_write(SYS_CFG_OSC | SYS_CFG_SITE_MB | 1, rate); | ||
285 | } | ||
286 | |||
287 | static const struct clk_ops osc1_clk_ops = { | ||
288 | .round = v2m_osc_round, | ||
289 | .set = v2m_osc1_set, | ||
290 | }; | ||
291 | |||
292 | static struct clk osc1_clk = { | ||
293 | .ops = &osc1_clk_ops, | ||
294 | .rate = 24000000, | ||
295 | }; | ||
296 | |||
297 | static struct clk osc2_clk = { | ||
298 | .rate = 24000000, | ||
299 | }; | ||
300 | |||
301 | static struct clk_lookup v2m_lookups[] = { | ||
302 | { /* UART0 */ | ||
303 | .dev_id = "mb:uart0", | ||
304 | .clk = &osc2_clk, | ||
305 | }, { /* UART1 */ | ||
306 | .dev_id = "mb:uart1", | ||
307 | .clk = &osc2_clk, | ||
308 | }, { /* UART2 */ | ||
309 | .dev_id = "mb:uart2", | ||
310 | .clk = &osc2_clk, | ||
311 | }, { /* UART3 */ | ||
312 | .dev_id = "mb:uart3", | ||
313 | .clk = &osc2_clk, | ||
314 | }, { /* KMI0 */ | ||
315 | .dev_id = "mb:kmi0", | ||
316 | .clk = &osc2_clk, | ||
317 | }, { /* KMI1 */ | ||
318 | .dev_id = "mb:kmi1", | ||
319 | .clk = &osc2_clk, | ||
320 | }, { /* MMC0 */ | ||
321 | .dev_id = "mb:mmci", | ||
322 | .clk = &osc2_clk, | ||
323 | }, { /* CLCD */ | ||
324 | .dev_id = "mb:clcd", | ||
325 | .clk = &osc1_clk, | ||
326 | }, | ||
327 | }; | ||
328 | |||
329 | static void v2m_power_off(void) | ||
330 | { | ||
331 | if (v2m_cfg_write(SYS_CFG_SHUTDOWN | SYS_CFG_SITE_MB, 0)) | ||
332 | printk(KERN_EMERG "Unable to shutdown\n"); | ||
333 | } | ||
334 | |||
335 | static void v2m_restart(char str, const char *cmd) | ||
336 | { | ||
337 | if (v2m_cfg_write(SYS_CFG_REBOOT | SYS_CFG_SITE_MB, 0)) | ||
338 | printk(KERN_EMERG "Unable to reboot\n"); | ||
339 | } | ||
340 | |||
341 | static int __init v2m_init(void) | ||
342 | { | ||
343 | int i; | ||
344 | |||
345 | clkdev_add_table(v2m_lookups, ARRAY_SIZE(v2m_lookups)); | ||
346 | |||
347 | platform_device_register(&v2m_pcie_i2c_device); | ||
348 | platform_device_register(&v2m_ddc_i2c_device); | ||
349 | platform_device_register(&v2m_flash_device); | ||
350 | platform_device_register(&v2m_eth_device); | ||
351 | platform_device_register(&v2m_usb_device); | ||
352 | |||
353 | for (i = 0; i < ARRAY_SIZE(v2m_amba_devs); i++) | ||
354 | amba_device_register(v2m_amba_devs[i], &iomem_resource); | ||
355 | |||
356 | pm_power_off = v2m_power_off; | ||
357 | arm_pm_restart = v2m_restart; | ||
358 | |||
359 | return 0; | ||
360 | } | ||
361 | arch_initcall(v2m_init); | ||