diff options
Diffstat (limited to 'arch/arm/mach-vexpress/v2m.c')
-rw-r--r-- | arch/arm/mach-vexpress/v2m.c | 281 |
1 files changed, 257 insertions, 24 deletions
diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c index ad64f97a2003..47cdcca5a7e7 100644 --- a/arch/arm/mach-vexpress/v2m.c +++ b/arch/arm/mach-vexpress/v2m.c | |||
@@ -6,6 +6,10 @@ | |||
6 | #include <linux/amba/mmci.h> | 6 | #include <linux/amba/mmci.h> |
7 | #include <linux/io.h> | 7 | #include <linux/io.h> |
8 | #include <linux/init.h> | 8 | #include <linux/init.h> |
9 | #include <linux/of_address.h> | ||
10 | #include <linux/of_fdt.h> | ||
11 | #include <linux/of_irq.h> | ||
12 | #include <linux/of_platform.h> | ||
9 | #include <linux/platform_device.h> | 13 | #include <linux/platform_device.h> |
10 | #include <linux/ata_platform.h> | 14 | #include <linux/ata_platform.h> |
11 | #include <linux/smsc911x.h> | 15 | #include <linux/smsc911x.h> |
@@ -21,6 +25,8 @@ | |||
21 | #include <asm/mach/map.h> | 25 | #include <asm/mach/map.h> |
22 | #include <asm/mach/time.h> | 26 | #include <asm/mach/time.h> |
23 | #include <asm/hardware/arm_timer.h> | 27 | #include <asm/hardware/arm_timer.h> |
28 | #include <asm/hardware/cache-l2x0.h> | ||
29 | #include <asm/hardware/gic.h> | ||
24 | #include <asm/hardware/timer-sp.h> | 30 | #include <asm/hardware/timer-sp.h> |
25 | #include <asm/hardware/sp810.h> | 31 | #include <asm/hardware/sp810.h> |
26 | #include <asm/hardware/gic.h> | 32 | #include <asm/hardware/gic.h> |
@@ -40,29 +46,45 @@ | |||
40 | 46 | ||
41 | static struct map_desc v2m_io_desc[] __initdata = { | 47 | static struct map_desc v2m_io_desc[] __initdata = { |
42 | { | 48 | { |
43 | .virtual = __MMIO_P2V(V2M_PA_CS7), | 49 | .virtual = V2M_PERIPH, |
44 | .pfn = __phys_to_pfn(V2M_PA_CS7), | 50 | .pfn = __phys_to_pfn(V2M_PA_CS7), |
45 | .length = SZ_128K, | 51 | .length = SZ_128K, |
46 | .type = MT_DEVICE, | 52 | .type = MT_DEVICE, |
47 | }, | 53 | }, |
48 | }; | 54 | }; |
49 | 55 | ||
50 | static void __init v2m_timer_init(void) | 56 | static void __iomem *v2m_sysreg_base; |
57 | |||
58 | static void __init v2m_sysctl_init(void __iomem *base) | ||
51 | { | 59 | { |
52 | u32 scctrl; | 60 | u32 scctrl; |
53 | 61 | ||
62 | if (WARN_ON(!base)) | ||
63 | return; | ||
64 | |||
54 | /* Select 1MHz TIMCLK as the reference clock for SP804 timers */ | 65 | /* Select 1MHz TIMCLK as the reference clock for SP804 timers */ |
55 | scctrl = readl(MMIO_P2V(V2M_SYSCTL + SCCTRL)); | 66 | scctrl = readl(base + SCCTRL); |
56 | scctrl |= SCCTRL_TIMEREN0SEL_TIMCLK; | 67 | scctrl |= SCCTRL_TIMEREN0SEL_TIMCLK; |
57 | scctrl |= SCCTRL_TIMEREN1SEL_TIMCLK; | 68 | scctrl |= SCCTRL_TIMEREN1SEL_TIMCLK; |
58 | writel(scctrl, MMIO_P2V(V2M_SYSCTL + SCCTRL)); | 69 | writel(scctrl, base + SCCTRL); |
70 | } | ||
71 | |||
72 | static void __init v2m_sp804_init(void __iomem *base, unsigned int irq) | ||
73 | { | ||
74 | if (WARN_ON(!base || irq == NO_IRQ)) | ||
75 | return; | ||
76 | |||
77 | writel(0, base + TIMER_1_BASE + TIMER_CTRL); | ||
78 | writel(0, base + TIMER_2_BASE + TIMER_CTRL); | ||
59 | 79 | ||
60 | writel(0, MMIO_P2V(V2M_TIMER0) + TIMER_CTRL); | 80 | sp804_clocksource_init(base + TIMER_2_BASE, "v2m-timer1"); |
61 | writel(0, MMIO_P2V(V2M_TIMER1) + TIMER_CTRL); | 81 | sp804_clockevents_init(base + TIMER_1_BASE, irq, "v2m-timer0"); |
82 | } | ||
62 | 83 | ||
63 | sp804_clocksource_init(MMIO_P2V(V2M_TIMER1), "v2m-timer1"); | 84 | static void __init v2m_timer_init(void) |
64 | sp804_clockevents_init(MMIO_P2V(V2M_TIMER0), IRQ_V2M_TIMER0, | 85 | { |
65 | "v2m-timer0"); | 86 | v2m_sysctl_init(ioremap(V2M_SYSCTL, SZ_4K)); |
87 | v2m_sp804_init(ioremap(V2M_TIMER01, SZ_4K), IRQ_V2M_TIMER0); | ||
66 | } | 88 | } |
67 | 89 | ||
68 | static struct sys_timer v2m_timer = { | 90 | static struct sys_timer v2m_timer = { |
@@ -82,14 +104,14 @@ int v2m_cfg_write(u32 devfn, u32 data) | |||
82 | devfn |= SYS_CFG_START | SYS_CFG_WRITE; | 104 | devfn |= SYS_CFG_START | SYS_CFG_WRITE; |
83 | 105 | ||
84 | spin_lock(&v2m_cfg_lock); | 106 | spin_lock(&v2m_cfg_lock); |
85 | val = readl(MMIO_P2V(V2M_SYS_CFGSTAT)); | 107 | val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT); |
86 | writel(val & ~SYS_CFG_COMPLETE, MMIO_P2V(V2M_SYS_CFGSTAT)); | 108 | writel(val & ~SYS_CFG_COMPLETE, v2m_sysreg_base + V2M_SYS_CFGSTAT); |
87 | 109 | ||
88 | writel(data, MMIO_P2V(V2M_SYS_CFGDATA)); | 110 | writel(data, v2m_sysreg_base + V2M_SYS_CFGDATA); |
89 | writel(devfn, MMIO_P2V(V2M_SYS_CFGCTRL)); | 111 | writel(devfn, v2m_sysreg_base + V2M_SYS_CFGCTRL); |
90 | 112 | ||
91 | do { | 113 | do { |
92 | val = readl(MMIO_P2V(V2M_SYS_CFGSTAT)); | 114 | val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT); |
93 | } while (val == 0); | 115 | } while (val == 0); |
94 | spin_unlock(&v2m_cfg_lock); | 116 | spin_unlock(&v2m_cfg_lock); |
95 | 117 | ||
@@ -103,22 +125,28 @@ int v2m_cfg_read(u32 devfn, u32 *data) | |||
103 | devfn |= SYS_CFG_START; | 125 | devfn |= SYS_CFG_START; |
104 | 126 | ||
105 | spin_lock(&v2m_cfg_lock); | 127 | spin_lock(&v2m_cfg_lock); |
106 | writel(0, MMIO_P2V(V2M_SYS_CFGSTAT)); | 128 | writel(0, v2m_sysreg_base + V2M_SYS_CFGSTAT); |
107 | writel(devfn, MMIO_P2V(V2M_SYS_CFGCTRL)); | 129 | writel(devfn, v2m_sysreg_base + V2M_SYS_CFGCTRL); |
108 | 130 | ||
109 | mb(); | 131 | mb(); |
110 | 132 | ||
111 | do { | 133 | do { |
112 | cpu_relax(); | 134 | cpu_relax(); |
113 | val = readl(MMIO_P2V(V2M_SYS_CFGSTAT)); | 135 | val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT); |
114 | } while (val == 0); | 136 | } while (val == 0); |
115 | 137 | ||
116 | *data = readl(MMIO_P2V(V2M_SYS_CFGDATA)); | 138 | *data = readl(v2m_sysreg_base + V2M_SYS_CFGDATA); |
117 | spin_unlock(&v2m_cfg_lock); | 139 | spin_unlock(&v2m_cfg_lock); |
118 | 140 | ||
119 | return !!(val & SYS_CFG_ERR); | 141 | return !!(val & SYS_CFG_ERR); |
120 | } | 142 | } |
121 | 143 | ||
144 | void __init v2m_flags_set(u32 data) | ||
145 | { | ||
146 | writel(~0, v2m_sysreg_base + V2M_SYS_FLAGSCLR); | ||
147 | writel(data, v2m_sysreg_base + V2M_SYS_FLAGSSET); | ||
148 | } | ||
149 | |||
122 | 150 | ||
123 | static struct resource v2m_pcie_i2c_resource = { | 151 | static struct resource v2m_pcie_i2c_resource = { |
124 | .start = V2M_SERIAL_BUS_PCI, | 152 | .start = V2M_SERIAL_BUS_PCI, |
@@ -204,7 +232,7 @@ static struct platform_device v2m_usb_device = { | |||
204 | 232 | ||
205 | static void v2m_flash_set_vpp(struct platform_device *pdev, int on) | 233 | static void v2m_flash_set_vpp(struct platform_device *pdev, int on) |
206 | { | 234 | { |
207 | writel(on != 0, MMIO_P2V(V2M_SYS_FLASH)); | 235 | writel(on != 0, v2m_sysreg_base + V2M_SYS_FLASH); |
208 | } | 236 | } |
209 | 237 | ||
210 | static struct physmap_flash_data v2m_flash_data = { | 238 | static struct physmap_flash_data v2m_flash_data = { |
@@ -258,7 +286,7 @@ static struct platform_device v2m_cf_device = { | |||
258 | 286 | ||
259 | static unsigned int v2m_mmci_status(struct device *dev) | 287 | static unsigned int v2m_mmci_status(struct device *dev) |
260 | { | 288 | { |
261 | return readl(MMIO_P2V(V2M_SYS_MCI)) & (1 << 0); | 289 | return readl(v2m_sysreg_base + V2M_SYS_MCI) & (1 << 0); |
262 | } | 290 | } |
263 | 291 | ||
264 | static struct mmci_platform_data v2m_mmci_data = { | 292 | static struct mmci_platform_data v2m_mmci_data = { |
@@ -371,7 +399,7 @@ static void __init v2m_init_early(void) | |||
371 | { | 399 | { |
372 | ct_desc->init_early(); | 400 | ct_desc->init_early(); |
373 | clkdev_add_table(v2m_lookups, ARRAY_SIZE(v2m_lookups)); | 401 | clkdev_add_table(v2m_lookups, ARRAY_SIZE(v2m_lookups)); |
374 | versatile_sched_clock_init(MMIO_P2V(V2M_SYS_24MHZ), 24000000); | 402 | versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000); |
375 | } | 403 | } |
376 | 404 | ||
377 | static void v2m_power_off(void) | 405 | static void v2m_power_off(void) |
@@ -400,20 +428,23 @@ static void __init v2m_populate_ct_desc(void) | |||
400 | u32 current_tile_id; | 428 | u32 current_tile_id; |
401 | 429 | ||
402 | ct_desc = NULL; | 430 | ct_desc = NULL; |
403 | current_tile_id = readl(MMIO_P2V(V2M_SYS_PROCID0)) & V2M_CT_ID_MASK; | 431 | current_tile_id = readl(v2m_sysreg_base + V2M_SYS_PROCID0) |
432 | & V2M_CT_ID_MASK; | ||
404 | 433 | ||
405 | for (i = 0; i < ARRAY_SIZE(ct_descs) && !ct_desc; ++i) | 434 | for (i = 0; i < ARRAY_SIZE(ct_descs) && !ct_desc; ++i) |
406 | if (ct_descs[i]->id == current_tile_id) | 435 | if (ct_descs[i]->id == current_tile_id) |
407 | ct_desc = ct_descs[i]; | 436 | ct_desc = ct_descs[i]; |
408 | 437 | ||
409 | if (!ct_desc) | 438 | if (!ct_desc) |
410 | panic("vexpress: failed to populate core tile description " | 439 | panic("vexpress: this kernel does not support core tile ID 0x%08x when booting via ATAGs.\n" |
411 | "for tile ID 0x%8x\n", current_tile_id); | 440 | "You may need a device tree blob or a different kernel to boot on this board.\n", |
441 | current_tile_id); | ||
412 | } | 442 | } |
413 | 443 | ||
414 | static void __init v2m_map_io(void) | 444 | static void __init v2m_map_io(void) |
415 | { | 445 | { |
416 | iotable_init(v2m_io_desc, ARRAY_SIZE(v2m_io_desc)); | 446 | iotable_init(v2m_io_desc, ARRAY_SIZE(v2m_io_desc)); |
447 | v2m_sysreg_base = ioremap(V2M_SYSREGS, SZ_4K); | ||
417 | v2m_populate_ct_desc(); | 448 | v2m_populate_ct_desc(); |
418 | ct_desc->map_io(); | 449 | ct_desc->map_io(); |
419 | } | 450 | } |
@@ -452,3 +483,205 @@ MACHINE_START(VEXPRESS, "ARM-Versatile Express") | |||
452 | .init_machine = v2m_init, | 483 | .init_machine = v2m_init, |
453 | .restart = v2m_restart, | 484 | .restart = v2m_restart, |
454 | MACHINE_END | 485 | MACHINE_END |
486 | |||
487 | #if defined(CONFIG_ARCH_VEXPRESS_DT) | ||
488 | |||
489 | static struct map_desc v2m_rs1_io_desc __initdata = { | ||
490 | .virtual = V2M_PERIPH, | ||
491 | .pfn = __phys_to_pfn(0x1c000000), | ||
492 | .length = SZ_2M, | ||
493 | .type = MT_DEVICE, | ||
494 | }; | ||
495 | |||
496 | static int __init v2m_dt_scan_memory_map(unsigned long node, const char *uname, | ||
497 | int depth, void *data) | ||
498 | { | ||
499 | const char **map = data; | ||
500 | |||
501 | if (strcmp(uname, "motherboard") != 0) | ||
502 | return 0; | ||
503 | |||
504 | *map = of_get_flat_dt_prop(node, "arm,v2m-memory-map", NULL); | ||
505 | |||
506 | return 1; | ||
507 | } | ||
508 | |||
509 | void __init v2m_dt_map_io(void) | ||
510 | { | ||
511 | const char *map = NULL; | ||
512 | |||
513 | of_scan_flat_dt(v2m_dt_scan_memory_map, &map); | ||
514 | |||
515 | if (map && strcmp(map, "rs1") == 0) | ||
516 | iotable_init(&v2m_rs1_io_desc, 1); | ||
517 | else | ||
518 | iotable_init(v2m_io_desc, ARRAY_SIZE(v2m_io_desc)); | ||
519 | |||
520 | #if defined(CONFIG_SMP) | ||
521 | vexpress_dt_smp_map_io(); | ||
522 | #endif | ||
523 | } | ||
524 | |||
525 | static struct clk_lookup v2m_dt_lookups[] = { | ||
526 | { /* AMBA bus clock */ | ||
527 | .con_id = "apb_pclk", | ||
528 | .clk = &dummy_apb_pclk, | ||
529 | }, { /* SP804 timers */ | ||
530 | .dev_id = "sp804", | ||
531 | .con_id = "v2m-timer0", | ||
532 | .clk = &v2m_sp804_clk, | ||
533 | }, { /* SP804 timers */ | ||
534 | .dev_id = "sp804", | ||
535 | .con_id = "v2m-timer1", | ||
536 | .clk = &v2m_sp804_clk, | ||
537 | }, { /* PL180 MMCI */ | ||
538 | .dev_id = "mb:mmci", /* 10005000.mmci */ | ||
539 | .clk = &osc2_clk, | ||
540 | }, { /* PL050 KMI0 */ | ||
541 | .dev_id = "10006000.kmi", | ||
542 | .clk = &osc2_clk, | ||
543 | }, { /* PL050 KMI1 */ | ||
544 | .dev_id = "10007000.kmi", | ||
545 | .clk = &osc2_clk, | ||
546 | }, { /* PL011 UART0 */ | ||
547 | .dev_id = "10009000.uart", | ||
548 | .clk = &osc2_clk, | ||
549 | }, { /* PL011 UART1 */ | ||
550 | .dev_id = "1000a000.uart", | ||
551 | .clk = &osc2_clk, | ||
552 | }, { /* PL011 UART2 */ | ||
553 | .dev_id = "1000b000.uart", | ||
554 | .clk = &osc2_clk, | ||
555 | }, { /* PL011 UART3 */ | ||
556 | .dev_id = "1000c000.uart", | ||
557 | .clk = &osc2_clk, | ||
558 | }, { /* SP805 WDT */ | ||
559 | .dev_id = "1000f000.wdt", | ||
560 | .clk = &v2m_ref_clk, | ||
561 | }, { /* PL111 CLCD */ | ||
562 | .dev_id = "1001f000.clcd", | ||
563 | .clk = &osc1_clk, | ||
564 | }, | ||
565 | /* RS1 memory map */ | ||
566 | { /* PL180 MMCI */ | ||
567 | .dev_id = "mb:mmci", /* 1c050000.mmci */ | ||
568 | .clk = &osc2_clk, | ||
569 | }, { /* PL050 KMI0 */ | ||
570 | .dev_id = "1c060000.kmi", | ||
571 | .clk = &osc2_clk, | ||
572 | }, { /* PL050 KMI1 */ | ||
573 | .dev_id = "1c070000.kmi", | ||
574 | .clk = &osc2_clk, | ||
575 | }, { /* PL011 UART0 */ | ||
576 | .dev_id = "1c090000.uart", | ||
577 | .clk = &osc2_clk, | ||
578 | }, { /* PL011 UART1 */ | ||
579 | .dev_id = "1c0a0000.uart", | ||
580 | .clk = &osc2_clk, | ||
581 | }, { /* PL011 UART2 */ | ||
582 | .dev_id = "1c0b0000.uart", | ||
583 | .clk = &osc2_clk, | ||
584 | }, { /* PL011 UART3 */ | ||
585 | .dev_id = "1c0c0000.uart", | ||
586 | .clk = &osc2_clk, | ||
587 | }, { /* SP805 WDT */ | ||
588 | .dev_id = "1c0f0000.wdt", | ||
589 | .clk = &v2m_ref_clk, | ||
590 | }, { /* PL111 CLCD */ | ||
591 | .dev_id = "1c1f0000.clcd", | ||
592 | .clk = &osc1_clk, | ||
593 | }, | ||
594 | }; | ||
595 | |||
596 | void __init v2m_dt_init_early(void) | ||
597 | { | ||
598 | struct device_node *node; | ||
599 | u32 dt_hbi; | ||
600 | |||
601 | node = of_find_compatible_node(NULL, NULL, "arm,vexpress-sysreg"); | ||
602 | v2m_sysreg_base = of_iomap(node, 0); | ||
603 | if (WARN_ON(!v2m_sysreg_base)) | ||
604 | return; | ||
605 | |||
606 | /* Confirm board type against DT property, if available */ | ||
607 | if (of_property_read_u32(allnodes, "arm,hbi", &dt_hbi) == 0) { | ||
608 | u32 misc = readl(v2m_sysreg_base + V2M_SYS_MISC); | ||
609 | u32 id = readl(v2m_sysreg_base + (misc & SYS_MISC_MASTERSITE ? | ||
610 | V2M_SYS_PROCID1 : V2M_SYS_PROCID0)); | ||
611 | u32 hbi = id & SYS_PROCIDx_HBI_MASK; | ||
612 | |||
613 | if (WARN_ON(dt_hbi != hbi)) | ||
614 | pr_warning("vexpress: DT HBI (%x) is not matching " | ||
615 | "hardware (%x)!\n", dt_hbi, hbi); | ||
616 | } | ||
617 | |||
618 | clkdev_add_table(v2m_dt_lookups, ARRAY_SIZE(v2m_dt_lookups)); | ||
619 | versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000); | ||
620 | } | ||
621 | |||
622 | static struct of_device_id vexpress_irq_match[] __initdata = { | ||
623 | { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, | ||
624 | {} | ||
625 | }; | ||
626 | |||
627 | static void __init v2m_dt_init_irq(void) | ||
628 | { | ||
629 | of_irq_init(vexpress_irq_match); | ||
630 | } | ||
631 | |||
632 | static void __init v2m_dt_timer_init(void) | ||
633 | { | ||
634 | struct device_node *node; | ||
635 | const char *path; | ||
636 | int err; | ||
637 | |||
638 | node = of_find_compatible_node(NULL, NULL, "arm,sp810"); | ||
639 | v2m_sysctl_init(of_iomap(node, 0)); | ||
640 | |||
641 | err = of_property_read_string(of_aliases, "arm,v2m_timer", &path); | ||
642 | if (WARN_ON(err)) | ||
643 | return; | ||
644 | node = of_find_node_by_path(path); | ||
645 | v2m_sp804_init(of_iomap(node, 0), irq_of_parse_and_map(node, 0)); | ||
646 | } | ||
647 | |||
648 | static struct sys_timer v2m_dt_timer = { | ||
649 | .init = v2m_dt_timer_init, | ||
650 | }; | ||
651 | |||
652 | static struct of_dev_auxdata v2m_dt_auxdata_lookup[] __initdata = { | ||
653 | OF_DEV_AUXDATA("arm,vexpress-flash", V2M_NOR0, "physmap-flash", | ||
654 | &v2m_flash_data), | ||
655 | OF_DEV_AUXDATA("arm,primecell", V2M_MMCI, "mb:mmci", &v2m_mmci_data), | ||
656 | /* RS1 memory map */ | ||
657 | OF_DEV_AUXDATA("arm,vexpress-flash", 0x08000000, "physmap-flash", | ||
658 | &v2m_flash_data), | ||
659 | OF_DEV_AUXDATA("arm,primecell", 0x1c050000, "mb:mmci", &v2m_mmci_data), | ||
660 | {} | ||
661 | }; | ||
662 | |||
663 | static void __init v2m_dt_init(void) | ||
664 | { | ||
665 | l2x0_of_init(0x00400000, 0xfe0fffff); | ||
666 | of_platform_populate(NULL, of_default_bus_match_table, | ||
667 | v2m_dt_auxdata_lookup, NULL); | ||
668 | pm_power_off = v2m_power_off; | ||
669 | } | ||
670 | |||
671 | const static char *v2m_dt_match[] __initconst = { | ||
672 | "arm,vexpress", | ||
673 | NULL, | ||
674 | }; | ||
675 | |||
676 | DT_MACHINE_START(VEXPRESS_DT, "ARM-Versatile Express") | ||
677 | .dt_compat = v2m_dt_match, | ||
678 | .map_io = v2m_dt_map_io, | ||
679 | .init_early = v2m_dt_init_early, | ||
680 | .init_irq = v2m_dt_init_irq, | ||
681 | .timer = &v2m_dt_timer, | ||
682 | .init_machine = v2m_dt_init, | ||
683 | .handle_irq = gic_handle_irq, | ||
684 | .restart = v2m_restart, | ||
685 | MACHINE_END | ||
686 | |||
687 | #endif | ||