blob: 04dd092211b893271fc65df344ef42adb1e3f754 [file] [log] [blame]
Russell Kingceade892010-02-11 21:44:53 +00001/*
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>
Pawel Moll8deed172012-02-23 13:04:51 +00009#include <linux/of_address.h>
10#include <linux/of_fdt.h>
11#include <linux/of_irq.h>
12#include <linux/of_platform.h>
Russell Kingceade892010-02-11 21:44:53 +000013#include <linux/platform_device.h>
Nick Bowler95c34f82011-01-21 15:51:06 +010014#include <linux/ata_platform.h>
Russell Kingceade892010-02-11 21:44:53 +000015#include <linux/smsc911x.h>
16#include <linux/spinlock.h>
Kay Sieversedbaa602011-12-21 16:26:03 -080017#include <linux/device.h>
Russell Kingceade892010-02-11 21:44:53 +000018#include <linux/usb/isp1760.h>
Jean-Christop PLAGNIOL-VILLARD6d803ba2010-11-17 10:04:33 +010019#include <linux/clkdev.h>
Marc Zyngier0f71fd42011-05-18 10:51:51 +010020#include <linux/mtd/physmap.h>
Russell Kingceade892010-02-11 21:44:53 +000021
Marc Zyngier120f3d62012-03-28 17:13:53 +010022#include <asm/arch_timer.h>
Will Deacon80b5efbd2011-02-28 17:01:04 +010023#include <asm/mach-types.h>
Russell Kingceade892010-02-11 21:44:53 +000024#include <asm/sizes.h>
Marc Zyngier120f3d62012-03-28 17:13:53 +010025#include <asm/smp_twd.h>
Will Deacon80b5efbd2011-02-28 17:01:04 +010026#include <asm/mach/arch.h>
Russell Kingceade892010-02-11 21:44:53 +000027#include <asm/mach/map.h>
28#include <asm/mach/time.h>
29#include <asm/hardware/arm_timer.h>
Pawel Moll8deed172012-02-23 13:04:51 +000030#include <asm/hardware/cache-l2x0.h>
31#include <asm/hardware/gic.h>
Russell King58daf182011-01-05 18:09:03 +000032#include <asm/hardware/timer-sp.h>
Pawel Mollbaaece22011-01-25 15:53:03 +010033#include <asm/hardware/sp810.h>
Marc Zyngierabd3ca52011-09-06 10:23:45 +010034#include <asm/hardware/gic.h>
Russell Kingceade892010-02-11 21:44:53 +000035
Will Deacon80b5efbd2011-02-28 17:01:04 +010036#include <mach/ct-ca9x4.h>
Russell Kingceade892010-02-11 21:44:53 +000037#include <mach/motherboard.h>
38
Russell King0af85dd2010-12-15 21:58:50 +000039#include <plat/sched_clock.h>
Russell Kingceade892010-02-11 21:44:53 +000040
41#include "core.h"
42
43#define V2M_PA_CS0 0x40000000
44#define V2M_PA_CS1 0x44000000
45#define V2M_PA_CS2 0x48000000
46#define V2M_PA_CS3 0x4c000000
47#define V2M_PA_CS7 0x10000000
48
49static struct map_desc v2m_io_desc[] __initdata = {
50 {
Pawel Moll98ed4ce2012-01-25 15:37:29 +000051 .virtual = V2M_PERIPH,
Russell Kingceade892010-02-11 21:44:53 +000052 .pfn = __phys_to_pfn(V2M_PA_CS7),
53 .length = SZ_128K,
54 .type = MT_DEVICE,
55 },
56};
57
Pawel Moll98ed4ce2012-01-25 15:37:29 +000058static void __iomem *v2m_sysreg_base;
59
60static void __init v2m_sysctl_init(void __iomem *base)
Russell Kingceade892010-02-11 21:44:53 +000061{
Pawel Mollbaaece22011-01-25 15:53:03 +010062 u32 scctrl;
63
Pawel Moll98ed4ce2012-01-25 15:37:29 +000064 if (WARN_ON(!base))
65 return;
66
Pawel Mollbaaece22011-01-25 15:53:03 +010067 /* Select 1MHz TIMCLK as the reference clock for SP804 timers */
Pawel Moll98ed4ce2012-01-25 15:37:29 +000068 scctrl = readl(base + SCCTRL);
Pawel Mollbaaece22011-01-25 15:53:03 +010069 scctrl |= SCCTRL_TIMEREN0SEL_TIMCLK;
70 scctrl |= SCCTRL_TIMEREN1SEL_TIMCLK;
Pawel Moll98ed4ce2012-01-25 15:37:29 +000071 writel(scctrl, base + SCCTRL);
72}
Pawel Mollbaaece22011-01-25 15:53:03 +010073
Pawel Moll98ed4ce2012-01-25 15:37:29 +000074static void __init v2m_sp804_init(void __iomem *base, unsigned int irq)
75{
76 if (WARN_ON(!base || irq == NO_IRQ))
77 return;
Russell Kingceade892010-02-11 21:44:53 +000078
Pawel Moll98ed4ce2012-01-25 15:37:29 +000079 writel(0, base + TIMER_1_BASE + TIMER_CTRL);
80 writel(0, base + TIMER_2_BASE + TIMER_CTRL);
81
82 sp804_clocksource_init(base + TIMER_2_BASE, "v2m-timer1");
83 sp804_clockevents_init(base + TIMER_1_BASE, irq, "v2m-timer0");
84}
85
86static void __init v2m_timer_init(void)
87{
88 v2m_sysctl_init(ioremap(V2M_SYSCTL, SZ_4K));
89 v2m_sp804_init(ioremap(V2M_TIMER01, SZ_4K), IRQ_V2M_TIMER0);
Russell Kingceade892010-02-11 21:44:53 +000090}
91
Will Deacon80b5efbd2011-02-28 17:01:04 +010092static struct sys_timer v2m_timer = {
Russell Kingceade892010-02-11 21:44:53 +000093 .init = v2m_timer_init,
94};
95
96
97static DEFINE_SPINLOCK(v2m_cfg_lock);
98
99int v2m_cfg_write(u32 devfn, u32 data)
100{
101 /* Configuration interface broken? */
102 u32 val;
103
104 printk("%s: writing %08x to %08x\n", __func__, data, devfn);
105
106 devfn |= SYS_CFG_START | SYS_CFG_WRITE;
107
108 spin_lock(&v2m_cfg_lock);
Pawel Moll98ed4ce2012-01-25 15:37:29 +0000109 val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT);
110 writel(val & ~SYS_CFG_COMPLETE, v2m_sysreg_base + V2M_SYS_CFGSTAT);
Russell Kingceade892010-02-11 21:44:53 +0000111
Pawel Moll98ed4ce2012-01-25 15:37:29 +0000112 writel(data, v2m_sysreg_base + V2M_SYS_CFGDATA);
113 writel(devfn, v2m_sysreg_base + V2M_SYS_CFGCTRL);
Russell Kingceade892010-02-11 21:44:53 +0000114
115 do {
Pawel Moll98ed4ce2012-01-25 15:37:29 +0000116 val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT);
Russell Kingceade892010-02-11 21:44:53 +0000117 } while (val == 0);
118 spin_unlock(&v2m_cfg_lock);
119
120 return !!(val & SYS_CFG_ERR);
121}
122
123int v2m_cfg_read(u32 devfn, u32 *data)
124{
125 u32 val;
126
127 devfn |= SYS_CFG_START;
128
129 spin_lock(&v2m_cfg_lock);
Pawel Moll98ed4ce2012-01-25 15:37:29 +0000130 writel(0, v2m_sysreg_base + V2M_SYS_CFGSTAT);
131 writel(devfn, v2m_sysreg_base + V2M_SYS_CFGCTRL);
Russell Kingceade892010-02-11 21:44:53 +0000132
133 mb();
134
135 do {
136 cpu_relax();
Pawel Moll98ed4ce2012-01-25 15:37:29 +0000137 val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT);
Russell Kingceade892010-02-11 21:44:53 +0000138 } while (val == 0);
139
Pawel Moll98ed4ce2012-01-25 15:37:29 +0000140 *data = readl(v2m_sysreg_base + V2M_SYS_CFGDATA);
Russell Kingceade892010-02-11 21:44:53 +0000141 spin_unlock(&v2m_cfg_lock);
142
143 return !!(val & SYS_CFG_ERR);
144}
145
Pawel Moll98ed4ce2012-01-25 15:37:29 +0000146void __init v2m_flags_set(u32 data)
147{
148 writel(~0, v2m_sysreg_base + V2M_SYS_FLAGSCLR);
149 writel(data, v2m_sysreg_base + V2M_SYS_FLAGSSET);
150}
151
Russell Kingceade892010-02-11 21:44:53 +0000152
153static struct resource v2m_pcie_i2c_resource = {
154 .start = V2M_SERIAL_BUS_PCI,
155 .end = V2M_SERIAL_BUS_PCI + SZ_4K - 1,
156 .flags = IORESOURCE_MEM,
157};
158
159static struct platform_device v2m_pcie_i2c_device = {
160 .name = "versatile-i2c",
161 .id = 0,
162 .num_resources = 1,
163 .resource = &v2m_pcie_i2c_resource,
164};
165
166static struct resource v2m_ddc_i2c_resource = {
167 .start = V2M_SERIAL_BUS_DVI,
168 .end = V2M_SERIAL_BUS_DVI + SZ_4K - 1,
169 .flags = IORESOURCE_MEM,
170};
171
172static struct platform_device v2m_ddc_i2c_device = {
173 .name = "versatile-i2c",
174 .id = 1,
175 .num_resources = 1,
176 .resource = &v2m_ddc_i2c_resource,
177};
178
179static struct resource v2m_eth_resources[] = {
180 {
181 .start = V2M_LAN9118,
182 .end = V2M_LAN9118 + SZ_64K - 1,
183 .flags = IORESOURCE_MEM,
184 }, {
185 .start = IRQ_V2M_LAN9118,
186 .end = IRQ_V2M_LAN9118,
187 .flags = IORESOURCE_IRQ,
188 },
189};
190
191static struct smsc911x_platform_config v2m_eth_config = {
192 .flags = SMSC911X_USE_32BIT,
193 .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH,
194 .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL,
195 .phy_interface = PHY_INTERFACE_MODE_MII,
196};
197
198static struct platform_device v2m_eth_device = {
199 .name = "smsc911x",
200 .id = -1,
201 .resource = v2m_eth_resources,
202 .num_resources = ARRAY_SIZE(v2m_eth_resources),
203 .dev.platform_data = &v2m_eth_config,
204};
205
206static struct resource v2m_usb_resources[] = {
207 {
208 .start = V2M_ISP1761,
209 .end = V2M_ISP1761 + SZ_128K - 1,
210 .flags = IORESOURCE_MEM,
211 }, {
212 .start = IRQ_V2M_ISP1761,
213 .end = IRQ_V2M_ISP1761,
214 .flags = IORESOURCE_IRQ,
215 },
216};
217
218static struct isp1760_platform_data v2m_usb_config = {
219 .is_isp1761 = true,
220 .bus_width_16 = false,
221 .port1_otg = true,
222 .analog_oc = false,
223 .dack_polarity_high = false,
224 .dreq_polarity_high = false,
225};
226
227static struct platform_device v2m_usb_device = {
228 .name = "isp1760",
229 .id = -1,
230 .resource = v2m_usb_resources,
231 .num_resources = ARRAY_SIZE(v2m_usb_resources),
232 .dev.platform_data = &v2m_usb_config,
233};
234
Marc Zyngier667f3902011-05-18 10:51:55 +0100235static void v2m_flash_set_vpp(struct platform_device *pdev, int on)
Russell Kingceade892010-02-11 21:44:53 +0000236{
Pawel Moll98ed4ce2012-01-25 15:37:29 +0000237 writel(on != 0, v2m_sysreg_base + V2M_SYS_FLASH);
Russell Kingceade892010-02-11 21:44:53 +0000238}
239
Marc Zyngier0f71fd42011-05-18 10:51:51 +0100240static struct physmap_flash_data v2m_flash_data = {
Russell Kingceade892010-02-11 21:44:53 +0000241 .width = 4,
Russell Kingceade892010-02-11 21:44:53 +0000242 .set_vpp = v2m_flash_set_vpp,
243};
244
245static struct resource v2m_flash_resources[] = {
246 {
247 .start = V2M_NOR0,
248 .end = V2M_NOR0 + SZ_64M - 1,
249 .flags = IORESOURCE_MEM,
250 }, {
251 .start = V2M_NOR1,
252 .end = V2M_NOR1 + SZ_64M - 1,
253 .flags = IORESOURCE_MEM,
254 },
255};
256
257static struct platform_device v2m_flash_device = {
Marc Zyngier0f71fd42011-05-18 10:51:51 +0100258 .name = "physmap-flash",
Russell Kingceade892010-02-11 21:44:53 +0000259 .id = -1,
260 .resource = v2m_flash_resources,
261 .num_resources = ARRAY_SIZE(v2m_flash_resources),
262 .dev.platform_data = &v2m_flash_data,
263};
264
Nick Bowler95c34f82011-01-21 15:51:06 +0100265static struct pata_platform_info v2m_pata_data = {
266 .ioport_shift = 2,
267};
268
269static struct resource v2m_pata_resources[] = {
270 {
271 .start = V2M_CF,
272 .end = V2M_CF + 0xff,
273 .flags = IORESOURCE_MEM,
274 }, {
275 .start = V2M_CF + 0x100,
276 .end = V2M_CF + SZ_4K - 1,
277 .flags = IORESOURCE_MEM,
278 },
279};
280
281static struct platform_device v2m_cf_device = {
282 .name = "pata_platform",
283 .id = -1,
284 .resource = v2m_pata_resources,
285 .num_resources = ARRAY_SIZE(v2m_pata_resources),
286 .dev.platform_data = &v2m_pata_data,
287};
Russell Kingceade892010-02-11 21:44:53 +0000288
289static unsigned int v2m_mmci_status(struct device *dev)
290{
Pawel Moll98ed4ce2012-01-25 15:37:29 +0000291 return readl(v2m_sysreg_base + V2M_SYS_MCI) & (1 << 0);
Russell Kingceade892010-02-11 21:44:53 +0000292}
293
294static struct mmci_platform_data v2m_mmci_data = {
295 .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
296 .status = v2m_mmci_status,
297};
298
Russell Kingcdd4e1a2011-12-18 12:07:09 +0000299static AMBA_APB_DEVICE(aaci, "mb:aaci", 0, V2M_AACI, IRQ_V2M_AACI, NULL);
300static AMBA_APB_DEVICE(mmci, "mb:mmci", 0, V2M_MMCI, IRQ_V2M_MMCI, &v2m_mmci_data);
301static AMBA_APB_DEVICE(kmi0, "mb:kmi0", 0, V2M_KMI0, IRQ_V2M_KMI0, NULL);
302static AMBA_APB_DEVICE(kmi1, "mb:kmi1", 0, V2M_KMI1, IRQ_V2M_KMI1, NULL);
303static AMBA_APB_DEVICE(uart0, "mb:uart0", 0, V2M_UART0, IRQ_V2M_UART0, NULL);
304static AMBA_APB_DEVICE(uart1, "mb:uart1", 0, V2M_UART1, IRQ_V2M_UART1, NULL);
305static AMBA_APB_DEVICE(uart2, "mb:uart2", 0, V2M_UART2, IRQ_V2M_UART2, NULL);
306static AMBA_APB_DEVICE(uart3, "mb:uart3", 0, V2M_UART3, IRQ_V2M_UART3, NULL);
307static AMBA_APB_DEVICE(wdt, "mb:wdt", 0, V2M_WDT, IRQ_V2M_WDT, NULL);
308static AMBA_APB_DEVICE(rtc, "mb:rtc", 0, V2M_RTC, IRQ_V2M_RTC, NULL);
Russell Kingceade892010-02-11 21:44:53 +0000309
310static struct amba_device *v2m_amba_devs[] __initdata = {
311 &aaci_device,
312 &mmci_device,
313 &kmi0_device,
314 &kmi1_device,
315 &uart0_device,
316 &uart1_device,
317 &uart2_device,
318 &uart3_device,
319 &wdt_device,
320 &rtc_device,
321};
322
323
324static long v2m_osc_round(struct clk *clk, unsigned long rate)
325{
326 return rate;
327}
328
329static int v2m_osc1_set(struct clk *clk, unsigned long rate)
330{
331 return v2m_cfg_write(SYS_CFG_OSC | SYS_CFG_SITE_MB | 1, rate);
332}
333
334static const struct clk_ops osc1_clk_ops = {
335 .round = v2m_osc_round,
336 .set = v2m_osc1_set,
337};
338
339static struct clk osc1_clk = {
340 .ops = &osc1_clk_ops,
341 .rate = 24000000,
342};
343
344static struct clk osc2_clk = {
345 .rate = 24000000,
346};
347
Russell King7ff550d2011-05-12 13:31:48 +0100348static struct clk v2m_sp804_clk = {
349 .rate = 1000000,
350};
351
Nick Bowler0ebb9622011-07-20 15:43:42 +0100352static struct clk v2m_ref_clk = {
353 .rate = 32768,
354};
355
Russell King3126c7b2010-07-15 11:01:17 +0100356static struct clk dummy_apb_pclk;
357
Russell Kingceade892010-02-11 21:44:53 +0000358static struct clk_lookup v2m_lookups[] = {
Russell King3126c7b2010-07-15 11:01:17 +0100359 { /* AMBA bus clock */
360 .con_id = "apb_pclk",
361 .clk = &dummy_apb_pclk,
362 }, { /* UART0 */
Russell Kingceade892010-02-11 21:44:53 +0000363 .dev_id = "mb:uart0",
364 .clk = &osc2_clk,
365 }, { /* UART1 */
366 .dev_id = "mb:uart1",
367 .clk = &osc2_clk,
368 }, { /* UART2 */
369 .dev_id = "mb:uart2",
370 .clk = &osc2_clk,
371 }, { /* UART3 */
372 .dev_id = "mb:uart3",
373 .clk = &osc2_clk,
374 }, { /* KMI0 */
375 .dev_id = "mb:kmi0",
376 .clk = &osc2_clk,
377 }, { /* KMI1 */
378 .dev_id = "mb:kmi1",
379 .clk = &osc2_clk,
380 }, { /* MMC0 */
381 .dev_id = "mb:mmci",
382 .clk = &osc2_clk,
383 }, { /* CLCD */
384 .dev_id = "mb:clcd",
385 .clk = &osc1_clk,
Nick Bowler0ebb9622011-07-20 15:43:42 +0100386 }, { /* SP805 WDT */
387 .dev_id = "mb:wdt",
388 .clk = &v2m_ref_clk,
Russell King7ff550d2011-05-12 13:31:48 +0100389 }, { /* SP804 timers */
390 .dev_id = "sp804",
Russell King23828a72011-05-12 15:45:16 +0100391 .con_id = "v2m-timer0",
392 .clk = &v2m_sp804_clk,
393 }, { /* SP804 timers */
394 .dev_id = "sp804",
Russell King7ff550d2011-05-12 13:31:48 +0100395 .con_id = "v2m-timer1",
396 .clk = &v2m_sp804_clk,
Russell Kingceade892010-02-11 21:44:53 +0000397 },
398};
399
Rob Herring2fdf9992011-05-30 19:44:22 +0100400static void __init v2m_init_early(void)
401{
402 ct_desc->init_early();
403 clkdev_add_table(v2m_lookups, ARRAY_SIZE(v2m_lookups));
Pawel Moll98ed4ce2012-01-25 15:37:29 +0000404 versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000);
Rob Herring2fdf9992011-05-30 19:44:22 +0100405}
406
Russell Kingceade892010-02-11 21:44:53 +0000407static void v2m_power_off(void)
408{
409 if (v2m_cfg_write(SYS_CFG_SHUTDOWN | SYS_CFG_SITE_MB, 0))
410 printk(KERN_EMERG "Unable to shutdown\n");
411}
412
413static void v2m_restart(char str, const char *cmd)
414{
415 if (v2m_cfg_write(SYS_CFG_REBOOT | SYS_CFG_SITE_MB, 0))
416 printk(KERN_EMERG "Unable to reboot\n");
417}
418
Will Deacon80b5efbd2011-02-28 17:01:04 +0100419struct ct_desc *ct_desc;
420
421static struct ct_desc *ct_descs[] __initdata = {
422#ifdef CONFIG_ARCH_VEXPRESS_CA9X4
423 &ct_ca9x4_desc,
424#endif
425};
426
427static void __init v2m_populate_ct_desc(void)
428{
429 int i;
430 u32 current_tile_id;
431
432 ct_desc = NULL;
Pawel Moll98ed4ce2012-01-25 15:37:29 +0000433 current_tile_id = readl(v2m_sysreg_base + V2M_SYS_PROCID0)
434 & V2M_CT_ID_MASK;
Will Deacon80b5efbd2011-02-28 17:01:04 +0100435
436 for (i = 0; i < ARRAY_SIZE(ct_descs) && !ct_desc; ++i)
437 if (ct_descs[i]->id == current_tile_id)
438 ct_desc = ct_descs[i];
439
440 if (!ct_desc)
Pawel Moll8deed172012-02-23 13:04:51 +0000441 panic("vexpress: this kernel does not support core tile ID 0x%08x when booting via ATAGs.\n"
442 "You may need a device tree blob or a different kernel to boot on this board.\n",
443 current_tile_id);
Will Deacon80b5efbd2011-02-28 17:01:04 +0100444}
445
446static void __init v2m_map_io(void)
447{
448 iotable_init(v2m_io_desc, ARRAY_SIZE(v2m_io_desc));
Pawel Moll98ed4ce2012-01-25 15:37:29 +0000449 v2m_sysreg_base = ioremap(V2M_SYSREGS, SZ_4K);
Will Deacon80b5efbd2011-02-28 17:01:04 +0100450 v2m_populate_ct_desc();
451 ct_desc->map_io();
452}
453
454static void __init v2m_init_irq(void)
455{
456 ct_desc->init_irq();
457}
458
459static void __init v2m_init(void)
Russell Kingceade892010-02-11 21:44:53 +0000460{
461 int i;
462
Russell Kingceade892010-02-11 21:44:53 +0000463 platform_device_register(&v2m_pcie_i2c_device);
464 platform_device_register(&v2m_ddc_i2c_device);
465 platform_device_register(&v2m_flash_device);
Nick Bowler95c34f82011-01-21 15:51:06 +0100466 platform_device_register(&v2m_cf_device);
Russell Kingceade892010-02-11 21:44:53 +0000467 platform_device_register(&v2m_eth_device);
468 platform_device_register(&v2m_usb_device);
469
470 for (i = 0; i < ARRAY_SIZE(v2m_amba_devs); i++)
471 amba_device_register(v2m_amba_devs[i], &iomem_resource);
472
473 pm_power_off = v2m_power_off;
Russell Kingceade892010-02-11 21:44:53 +0000474
Will Deacon80b5efbd2011-02-28 17:01:04 +0100475 ct_desc->init_tile();
Russell Kingceade892010-02-11 21:44:53 +0000476}
Will Deacon80b5efbd2011-02-28 17:01:04 +0100477
478MACHINE_START(VEXPRESS, "ARM-Versatile Express")
Nicolas Pitree9ce8e52011-07-05 22:38:18 -0400479 .atag_offset = 0x100,
Will Deacon80b5efbd2011-02-28 17:01:04 +0100480 .map_io = v2m_map_io,
481 .init_early = v2m_init_early,
482 .init_irq = v2m_init_irq,
483 .timer = &v2m_timer,
Marc Zyngierabd3ca52011-09-06 10:23:45 +0100484 .handle_irq = gic_handle_irq,
Will Deacon80b5efbd2011-02-28 17:01:04 +0100485 .init_machine = v2m_init,
Russell Kingf5733a12011-11-04 15:47:50 +0000486 .restart = v2m_restart,
Will Deacon80b5efbd2011-02-28 17:01:04 +0100487MACHINE_END
Pawel Moll8deed172012-02-23 13:04:51 +0000488
489#if defined(CONFIG_ARCH_VEXPRESS_DT)
490
Pawel Moll6a371952011-12-09 18:47:39 +0000491static struct map_desc v2m_rs1_io_desc __initdata = {
492 .virtual = V2M_PERIPH,
493 .pfn = __phys_to_pfn(0x1c000000),
494 .length = SZ_2M,
495 .type = MT_DEVICE,
496};
497
498static int __init v2m_dt_scan_memory_map(unsigned long node, const char *uname,
499 int depth, void *data)
500{
501 const char **map = data;
502
503 if (strcmp(uname, "motherboard") != 0)
504 return 0;
505
506 *map = of_get_flat_dt_prop(node, "arm,v2m-memory-map", NULL);
507
508 return 1;
509}
510
Pawel Moll8deed172012-02-23 13:04:51 +0000511void __init v2m_dt_map_io(void)
512{
Pawel Moll6a371952011-12-09 18:47:39 +0000513 const char *map = NULL;
514
515 of_scan_flat_dt(v2m_dt_scan_memory_map, &map);
516
517 if (map && strcmp(map, "rs1") == 0)
518 iotable_init(&v2m_rs1_io_desc, 1);
519 else
520 iotable_init(v2m_io_desc, ARRAY_SIZE(v2m_io_desc));
Pawel Moll8deed172012-02-23 13:04:51 +0000521
522#if defined(CONFIG_SMP)
523 vexpress_dt_smp_map_io();
524#endif
525}
526
527static struct clk_lookup v2m_dt_lookups[] = {
528 { /* AMBA bus clock */
529 .con_id = "apb_pclk",
530 .clk = &dummy_apb_pclk,
531 }, { /* SP804 timers */
532 .dev_id = "sp804",
533 .con_id = "v2m-timer0",
534 .clk = &v2m_sp804_clk,
535 }, { /* SP804 timers */
536 .dev_id = "sp804",
537 .con_id = "v2m-timer1",
538 .clk = &v2m_sp804_clk,
539 }, { /* PL180 MMCI */
540 .dev_id = "mb:mmci", /* 10005000.mmci */
541 .clk = &osc2_clk,
542 }, { /* PL050 KMI0 */
543 .dev_id = "10006000.kmi",
544 .clk = &osc2_clk,
545 }, { /* PL050 KMI1 */
546 .dev_id = "10007000.kmi",
547 .clk = &osc2_clk,
548 }, { /* PL011 UART0 */
549 .dev_id = "10009000.uart",
550 .clk = &osc2_clk,
551 }, { /* PL011 UART1 */
552 .dev_id = "1000a000.uart",
553 .clk = &osc2_clk,
554 }, { /* PL011 UART2 */
555 .dev_id = "1000b000.uart",
556 .clk = &osc2_clk,
557 }, { /* PL011 UART3 */
558 .dev_id = "1000c000.uart",
559 .clk = &osc2_clk,
560 }, { /* SP805 WDT */
561 .dev_id = "1000f000.wdt",
562 .clk = &v2m_ref_clk,
563 }, { /* PL111 CLCD */
564 .dev_id = "1001f000.clcd",
565 .clk = &osc1_clk,
566 },
Pawel Moll6a371952011-12-09 18:47:39 +0000567 /* RS1 memory map */
568 { /* PL180 MMCI */
569 .dev_id = "mb:mmci", /* 1c050000.mmci */
570 .clk = &osc2_clk,
571 }, { /* PL050 KMI0 */
572 .dev_id = "1c060000.kmi",
573 .clk = &osc2_clk,
574 }, { /* PL050 KMI1 */
575 .dev_id = "1c070000.kmi",
576 .clk = &osc2_clk,
577 }, { /* PL011 UART0 */
578 .dev_id = "1c090000.uart",
579 .clk = &osc2_clk,
580 }, { /* PL011 UART1 */
581 .dev_id = "1c0a0000.uart",
582 .clk = &osc2_clk,
583 }, { /* PL011 UART2 */
584 .dev_id = "1c0b0000.uart",
585 .clk = &osc2_clk,
586 }, { /* PL011 UART3 */
587 .dev_id = "1c0c0000.uart",
588 .clk = &osc2_clk,
589 }, { /* SP805 WDT */
590 .dev_id = "1c0f0000.wdt",
591 .clk = &v2m_ref_clk,
592 }, { /* PL111 CLCD */
593 .dev_id = "1c1f0000.clcd",
594 .clk = &osc1_clk,
595 },
Pawel Moll8deed172012-02-23 13:04:51 +0000596};
597
598void __init v2m_dt_init_early(void)
599{
600 struct device_node *node;
601 u32 dt_hbi;
602
603 node = of_find_compatible_node(NULL, NULL, "arm,vexpress-sysreg");
604 v2m_sysreg_base = of_iomap(node, 0);
605 if (WARN_ON(!v2m_sysreg_base))
606 return;
607
608 /* Confirm board type against DT property, if available */
609 if (of_property_read_u32(allnodes, "arm,hbi", &dt_hbi) == 0) {
610 u32 misc = readl(v2m_sysreg_base + V2M_SYS_MISC);
611 u32 id = readl(v2m_sysreg_base + (misc & SYS_MISC_MASTERSITE ?
612 V2M_SYS_PROCID1 : V2M_SYS_PROCID0));
613 u32 hbi = id & SYS_PROCIDx_HBI_MASK;
614
615 if (WARN_ON(dt_hbi != hbi))
616 pr_warning("vexpress: DT HBI (%x) is not matching "
617 "hardware (%x)!\n", dt_hbi, hbi);
618 }
619
620 clkdev_add_table(v2m_dt_lookups, ARRAY_SIZE(v2m_dt_lookups));
Pawel Moll8deed172012-02-23 13:04:51 +0000621}
622
623static struct of_device_id vexpress_irq_match[] __initdata = {
624 { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
625 {}
626};
627
628static void __init v2m_dt_init_irq(void)
629{
630 of_irq_init(vexpress_irq_match);
631}
632
633static void __init v2m_dt_timer_init(void)
634{
635 struct device_node *node;
636 const char *path;
637 int err;
638
639 node = of_find_compatible_node(NULL, NULL, "arm,sp810");
640 v2m_sysctl_init(of_iomap(node, 0));
641
642 err = of_property_read_string(of_aliases, "arm,v2m_timer", &path);
643 if (WARN_ON(err))
644 return;
645 node = of_find_node_by_path(path);
646 v2m_sp804_init(of_iomap(node, 0), irq_of_parse_and_map(node, 0));
Marc Zyngier120f3d62012-03-28 17:13:53 +0100647 if (arch_timer_of_register() != 0)
648 twd_local_timer_of_register();
649
650 if (arch_timer_sched_clock_init() != 0)
651 versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000);
Pawel Moll8deed172012-02-23 13:04:51 +0000652}
653
654static struct sys_timer v2m_dt_timer = {
655 .init = v2m_dt_timer_init,
656};
657
658static struct of_dev_auxdata v2m_dt_auxdata_lookup[] __initdata = {
659 OF_DEV_AUXDATA("arm,vexpress-flash", V2M_NOR0, "physmap-flash",
660 &v2m_flash_data),
661 OF_DEV_AUXDATA("arm,primecell", V2M_MMCI, "mb:mmci", &v2m_mmci_data),
Pawel Moll6a371952011-12-09 18:47:39 +0000662 /* RS1 memory map */
663 OF_DEV_AUXDATA("arm,vexpress-flash", 0x08000000, "physmap-flash",
664 &v2m_flash_data),
665 OF_DEV_AUXDATA("arm,primecell", 0x1c050000, "mb:mmci", &v2m_mmci_data),
Pawel Moll8deed172012-02-23 13:04:51 +0000666 {}
667};
668
669static void __init v2m_dt_init(void)
670{
671 l2x0_of_init(0x00400000, 0xfe0fffff);
672 of_platform_populate(NULL, of_default_bus_match_table,
673 v2m_dt_auxdata_lookup, NULL);
674 pm_power_off = v2m_power_off;
675}
676
677const static char *v2m_dt_match[] __initconst = {
678 "arm,vexpress",
679 NULL,
680};
681
682DT_MACHINE_START(VEXPRESS_DT, "ARM-Versatile Express")
683 .dt_compat = v2m_dt_match,
684 .map_io = v2m_dt_map_io,
685 .init_early = v2m_dt_init_early,
686 .init_irq = v2m_dt_init_irq,
687 .timer = &v2m_dt_timer,
688 .init_machine = v2m_dt_init,
689 .handle_irq = gic_handle_irq,
690 .restart = v2m_restart,
691MACHINE_END
692
693#endif