diff options
Diffstat (limited to 'arch/arm/mach-vexpress')
-rw-r--r-- | arch/arm/mach-vexpress/Kconfig | 47 | ||||
-rw-r--r-- | arch/arm/mach-vexpress/Makefile.boot | 6 | ||||
-rw-r--r-- | arch/arm/mach-vexpress/core.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-vexpress/include/mach/debug-macro.S | 30 | ||||
-rw-r--r-- | arch/arm/mach-vexpress/include/mach/irqs.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-vexpress/include/mach/motherboard.h | 6 | ||||
-rw-r--r-- | arch/arm/mach-vexpress/include/mach/uncompress.h | 22 | ||||
-rw-r--r-- | arch/arm/mach-vexpress/platsmp.c | 155 | ||||
-rw-r--r-- | arch/arm/mach-vexpress/v2m.c | 213 |
9 files changed, 470 insertions, 13 deletions
diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig index 88c3ba151e87..cf8730d35e70 100644 --- a/arch/arm/mach-vexpress/Kconfig +++ b/arch/arm/mach-vexpress/Kconfig @@ -1,14 +1,55 @@ menu "Versatile Express platform type" depends on ARCH_VEXPRESS +config ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA + bool + select ARM_ERRATA_720789 + select ARM_ERRATA_751472 + select PL310_ERRATA_753970 if CACHE_PL310 + help + Provides common dependencies for Versatile Express platforms + based on Cortex-A5 and Cortex-A9 processors. In order to + build a working kernel, you must also enable relevant core + tile support or Flattened Device Tree based support options. + config ARCH_VEXPRESS_CA9X4 bool "Versatile Express Cortex-A9x4 tile" + select ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA + select ARM_GIC select CPU_V7 + select HAVE_SMP + select MIGHT_HAVE_CACHE_L2X0 + +config ARCH_VEXPRESS_DT + bool "Device Tree support for Versatile Express platforms" + select ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA select ARM_GIC - select ARM_ERRATA_720789 - select ARM_ERRATA_751472 - select PL310_ERRATA_753970 + select ARM_PATCH_PHYS_VIRT + select AUTO_ZRELADDR + select CPU_V7 select HAVE_SMP select MIGHT_HAVE_CACHE_L2X0 + select USE_OF + help + New Versatile Express platforms require Flattened Device Tree to + be passed to the kernel. + + This option enables support for systems using Cortex processor based + ARM core and logic (FPGA) tiles on the Versatile Express motherboard, + for example: + + - CoreTile Express A5x2 (V2P-CA5s) + - CoreTile Express A9x4 (V2P-CA9) + - CoreTile Express A15x2 (V2P-CA15) + - LogicTile Express 13MG (V2F-2XV6) with A5, A7, A9 or A15 SMMs + (Soft Macrocell Models) + - Versatile Express RTSMs (Models) + + You must boot using a Flattened Device Tree in order to use these + platforms. The traditional (ATAGs) boot method is not usable on + these boards with this option. + + If your bootloader supports Flattened Device Tree based booting, + say Y here. endmenu diff --git a/arch/arm/mach-vexpress/Makefile.boot b/arch/arm/mach-vexpress/Makefile.boot index 8630b3d10a4d..909f85ebf5f4 100644 --- a/arch/arm/mach-vexpress/Makefile.boot +++ b/arch/arm/mach-vexpress/Makefile.boot @@ -1,3 +1,9 @@ +# Those numbers are used only by the non-DT V2P-CA9 platform +# The DT-enabled ones require CONFIG_AUTO_ZRELADDR=y zreladdr-y += 0x60008000 params_phys-y := 0x60000100 initrd_phys-y := 0x60800000 + +dtb-$(CONFIG_ARCH_VEXPRESS_DT) += vexpress-v2p-ca5s.dtb \ + vexpress-v2p-ca9.dtb \ + vexpress-v2p-ca15-tc1.dtb diff --git a/arch/arm/mach-vexpress/core.h b/arch/arm/mach-vexpress/core.h index 33c5a825aba1..a3a4980770bd 100644 --- a/arch/arm/mach-vexpress/core.h +++ b/arch/arm/mach-vexpress/core.h @@ -3,3 +3,5 @@ /* Tile's peripherals static mappings should start here */ #define V2T_PERIPH 0xf8200000 + +void vexpress_dt_smp_map_io(void); diff --git a/arch/arm/mach-vexpress/include/mach/debug-macro.S b/arch/arm/mach-vexpress/include/mach/debug-macro.S index fd9e6c7ea49f..fa8224794e0b 100644 --- a/arch/arm/mach-vexpress/include/mach/debug-macro.S +++ b/arch/arm/mach-vexpress/include/mach/debug-macro.S @@ -10,12 +10,34 @@ * published by the Free Software Foundation. */ -#define DEBUG_LL_UART_OFFSET 0x00009000 +#define DEBUG_LL_PHYS_BASE 0x10000000 +#define DEBUG_LL_UART_OFFSET 0x00009000 + +#define DEBUG_LL_PHYS_BASE_RS1 0x1c000000 +#define DEBUG_LL_UART_OFFSET_RS1 0x00090000 + +#define DEBUG_LL_VIRT_BASE 0xf8000000 .macro addruart,rp,rv,tmp - mov \rp, #DEBUG_LL_UART_OFFSET - orr \rv, \rp, #0xf8000000 @ virtual base - orr \rp, \rp, #0x10000000 @ physical base + + @ Make an educated guess regarding the memory map: + @ - the original A9 core tile, which has MPCore peripherals + @ located at 0x1e000000, should use UART at 0x10009000 + @ - all other (RS1 complaint) tiles use UART mapped + @ at 0x1c090000 + mrc p15, 4, \tmp, c15, c0, 0 + cmp \tmp, #0x1e000000 + + @ Original memory map + moveq \rp, #DEBUG_LL_UART_OFFSET + orreq \rv, \rp, #DEBUG_LL_VIRT_BASE + orreq \rp, \rp, #DEBUG_LL_PHYS_BASE + + @ RS1 memory map + movne \rp, #DEBUG_LL_UART_OFFSET_RS1 + orrne \rv, \rp, #DEBUG_LL_VIRT_BASE + orrne \rp, \rp, #DEBUG_LL_PHYS_BASE_RS1 + .endm #include <asm/hardware/debug-pl01x.S> diff --git a/arch/arm/mach-vexpress/include/mach/irqs.h b/arch/arm/mach-vexpress/include/mach/irqs.h index 7054cbfc9de5..4b10ee7657a6 100644 --- a/arch/arm/mach-vexpress/include/mach/irqs.h +++ b/arch/arm/mach-vexpress/include/mach/irqs.h @@ -1,4 +1,4 @@ #define IRQ_LOCALTIMER 29 #define IRQ_LOCALWDOG 30 -#define NR_IRQS 128 +#define NR_IRQS 256 diff --git a/arch/arm/mach-vexpress/include/mach/motherboard.h b/arch/arm/mach-vexpress/include/mach/motherboard.h index b4c498c1dbee..31a92890893d 100644 --- a/arch/arm/mach-vexpress/include/mach/motherboard.h +++ b/arch/arm/mach-vexpress/include/mach/motherboard.h @@ -117,6 +117,12 @@ int v2m_cfg_read(u32 devfn, u32 *data); void v2m_flags_set(u32 data); /* + * Miscellaneous + */ +#define SYS_MISC_MASTERSITE (1 << 14) +#define SYS_PROCIDx_HBI_MASK 0xfff + +/* * Core tile IDs */ #define V2M_CT_ID_CA9 0x0c000191 diff --git a/arch/arm/mach-vexpress/include/mach/uncompress.h b/arch/arm/mach-vexpress/include/mach/uncompress.h index 7972c5748d0e..7dab5596b868 100644 --- a/arch/arm/mach-vexpress/include/mach/uncompress.h +++ b/arch/arm/mach-vexpress/include/mach/uncompress.h @@ -22,7 +22,27 @@ #define AMBA_UART_CR(base) (*(volatile unsigned char *)((base) + 0x30)) #define AMBA_UART_FR(base) (*(volatile unsigned char *)((base) + 0x18)) -#define get_uart_base() (0x10000000 + 0x00009000) +#define UART_BASE 0x10009000 +#define UART_BASE_RS1 0x1c090000 + +static unsigned long get_uart_base(void) +{ + unsigned long mpcore_periph; + + /* + * Make an educated guess regarding the memory map: + * - the original A9 core tile, which has MPCore peripherals + * located at 0x1e000000, should use UART at 0x10009000 + * - all other (RS1 complaint) tiles use UART mapped + * at 0x1c090000 + */ + asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (mpcore_periph)); + + if (mpcore_periph == 0x1e000000) + return UART_BASE; + else + return UART_BASE_RS1; +} /* * This does not append a newline diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c index a1ed6d68597d..14ba1128ae8d 100644 --- a/arch/arm/mach-vexpress/platsmp.c +++ b/arch/arm/mach-vexpress/platsmp.c @@ -12,6 +12,11 @@ #include <linux/errno.h> #include <linux/smp.h> #include <linux/io.h> +#include <linux/of_fdt.h> + +#include <asm/smp_scu.h> +#include <asm/hardware/gic.h> +#include <asm/mach/map.h> #include <mach/motherboard.h> @@ -19,13 +24,156 @@ extern void versatile_secondary_startup(void); +#if defined(CONFIG_OF) + +static enum { + GENERIC_SCU, + CORTEX_A9_SCU, +} vexpress_dt_scu __initdata = GENERIC_SCU; + +static struct map_desc vexpress_dt_cortex_a9_scu_map __initdata = { + .virtual = V2T_PERIPH, + /* .pfn set in vexpress_dt_init_cortex_a9_scu() */ + .length = SZ_128, + .type = MT_DEVICE, +}; + +static void *vexpress_dt_cortex_a9_scu_base __initdata; + +const static char *vexpress_dt_cortex_a9_match[] __initconst = { + "arm,cortex-a5-scu", + "arm,cortex-a9-scu", + NULL +}; + +static int __init vexpress_dt_find_scu(unsigned long node, + const char *uname, int depth, void *data) +{ + if (of_flat_dt_match(node, vexpress_dt_cortex_a9_match)) { + phys_addr_t phys_addr; + __be32 *reg = of_get_flat_dt_prop(node, "reg", NULL); + + if (WARN_ON(!reg)) + return -EINVAL; + + phys_addr = be32_to_cpup(reg); + vexpress_dt_scu = CORTEX_A9_SCU; + + vexpress_dt_cortex_a9_scu_map.pfn = __phys_to_pfn(phys_addr); + iotable_init(&vexpress_dt_cortex_a9_scu_map, 1); + vexpress_dt_cortex_a9_scu_base = ioremap(phys_addr, SZ_256); + if (WARN_ON(!vexpress_dt_cortex_a9_scu_base)) + return -EFAULT; + } + + return 0; +} + +void __init vexpress_dt_smp_map_io(void) +{ + if (initial_boot_params) + WARN_ON(of_scan_flat_dt(vexpress_dt_find_scu, NULL)); +} + +static int __init vexpress_dt_cpus_num(unsigned long node, const char *uname, + int depth, void *data) +{ + static int prev_depth = -1; + static int nr_cpus = -1; + + if (prev_depth > depth && nr_cpus > 0) + return nr_cpus; + + if (nr_cpus < 0 && strcmp(uname, "cpus") == 0) + nr_cpus = 0; + + if (nr_cpus >= 0) { + const char *device_type = of_get_flat_dt_prop(node, + "device_type", NULL); + + if (device_type && strcmp(device_type, "cpu") == 0) + nr_cpus++; + } + + prev_depth = depth; + + return 0; +} + +static void __init vexpress_dt_smp_init_cpus(void) +{ + int ncores = 0, i; + + switch (vexpress_dt_scu) { + case GENERIC_SCU: + ncores = of_scan_flat_dt(vexpress_dt_cpus_num, NULL); + break; + case CORTEX_A9_SCU: + ncores = scu_get_core_count(vexpress_dt_cortex_a9_scu_base); + break; + default: + WARN_ON(1); + break; + } + + if (ncores < 2) + return; + + if (ncores > nr_cpu_ids) { + pr_warn("SMP: %u cores greater than maximum (%u), clipping\n", + ncores, nr_cpu_ids); + ncores = nr_cpu_ids; + } + + for (i = 0; i < ncores; ++i) + set_cpu_possible(i, true); + + set_smp_cross_call(gic_raise_softirq); +} + +static void __init vexpress_dt_smp_prepare_cpus(unsigned int max_cpus) +{ + int i; + + switch (vexpress_dt_scu) { + case GENERIC_SCU: + for (i = 0; i < max_cpus; i++) + set_cpu_present(i, true); + break; + case CORTEX_A9_SCU: + scu_enable(vexpress_dt_cortex_a9_scu_base); + break; + default: + WARN_ON(1); + break; + } +} + +#else + +static void __init vexpress_dt_smp_init_cpus(void) +{ + WARN_ON(1); +} + +void __init vexpress_dt_smp_prepare_cpus(unsigned int max_cpus) +{ + WARN_ON(1); +} + +#endif + /* * Initialise the CPU possible map early - this describes the CPUs * which may be present or become present in the system. */ void __init smp_init_cpus(void) { - ct_desc->init_cpu_map(); + if (ct_desc) + ct_desc->init_cpu_map(); + else + vexpress_dt_smp_init_cpus(); + } void __init platform_smp_prepare_cpus(unsigned int max_cpus) @@ -34,7 +182,10 @@ void __init platform_smp_prepare_cpus(unsigned int max_cpus) * Initialise the present map, which describes the set of CPUs * actually populated at the present time. */ - ct_desc->smp_enable(max_cpus); + if (ct_desc) + ct_desc->smp_enable(max_cpus); + else + vexpress_dt_smp_prepare_cpus(max_cpus); /* * Write the address of secondary startup into the diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c index 663a98831920..47cdcca5a7e7 100644 --- a/arch/arm/mach-vexpress/v2m.c +++ b/arch/arm/mach-vexpress/v2m.c @@ -6,6 +6,10 @@ #include <linux/amba/mmci.h> #include <linux/io.h> #include <linux/init.h> +#include <linux/of_address.h> +#include <linux/of_fdt.h> +#include <linux/of_irq.h> +#include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/ata_platform.h> #include <linux/smsc911x.h> @@ -21,6 +25,8 @@ #include <asm/mach/map.h> #include <asm/mach/time.h> #include <asm/hardware/arm_timer.h> +#include <asm/hardware/cache-l2x0.h> +#include <asm/hardware/gic.h> #include <asm/hardware/timer-sp.h> #include <asm/hardware/sp810.h> #include <asm/hardware/gic.h> @@ -430,8 +436,9 @@ static void __init v2m_populate_ct_desc(void) ct_desc = ct_descs[i]; if (!ct_desc) - panic("vexpress: failed to populate core tile description " - "for tile ID 0x%8x\n", current_tile_id); + panic("vexpress: this kernel does not support core tile ID 0x%08x when booting via ATAGs.\n" + "You may need a device tree blob or a different kernel to boot on this board.\n", + current_tile_id); } static void __init v2m_map_io(void) @@ -476,3 +483,205 @@ MACHINE_START(VEXPRESS, "ARM-Versatile Express") .init_machine = v2m_init, .restart = v2m_restart, MACHINE_END + +#if defined(CONFIG_ARCH_VEXPRESS_DT) + +static struct map_desc v2m_rs1_io_desc __initdata = { + .virtual = V2M_PERIPH, + .pfn = __phys_to_pfn(0x1c000000), + .length = SZ_2M, + .type = MT_DEVICE, +}; + +static int __init v2m_dt_scan_memory_map(unsigned long node, const char *uname, + int depth, void *data) +{ + const char **map = data; + + if (strcmp(uname, "motherboard") != 0) + return 0; + + *map = of_get_flat_dt_prop(node, "arm,v2m-memory-map", NULL); + + return 1; +} + +void __init v2m_dt_map_io(void) +{ + const char *map = NULL; + + of_scan_flat_dt(v2m_dt_scan_memory_map, &map); + + if (map && strcmp(map, "rs1") == 0) + iotable_init(&v2m_rs1_io_desc, 1); + else + iotable_init(v2m_io_desc, ARRAY_SIZE(v2m_io_desc)); + +#if defined(CONFIG_SMP) + vexpress_dt_smp_map_io(); +#endif +} + +static struct clk_lookup v2m_dt_lookups[] = { + { /* AMBA bus clock */ + .con_id = "apb_pclk", + .clk = &dummy_apb_pclk, + }, { /* SP804 timers */ + .dev_id = "sp804", + .con_id = "v2m-timer0", + .clk = &v2m_sp804_clk, + }, { /* SP804 timers */ + .dev_id = "sp804", + .con_id = "v2m-timer1", + .clk = &v2m_sp804_clk, + }, { /* PL180 MMCI */ + .dev_id = "mb:mmci", /* 10005000.mmci */ + .clk = &osc2_clk, + }, { /* PL050 KMI0 */ + .dev_id = "10006000.kmi", + .clk = &osc2_clk, + }, { /* PL050 KMI1 */ + .dev_id = "10007000.kmi", + .clk = &osc2_clk, + }, { /* PL011 UART0 */ + .dev_id = "10009000.uart", + .clk = &osc2_clk, + }, { /* PL011 UART1 */ + .dev_id = "1000a000.uart", + .clk = &osc2_clk, + }, { /* PL011 UART2 */ + .dev_id = "1000b000.uart", + .clk = &osc2_clk, + }, { /* PL011 UART3 */ + .dev_id = "1000c000.uart", + .clk = &osc2_clk, + }, { /* SP805 WDT */ + .dev_id = "1000f000.wdt", + .clk = &v2m_ref_clk, + }, { /* PL111 CLCD */ + .dev_id = "1001f000.clcd", + .clk = &osc1_clk, + }, + /* RS1 memory map */ + { /* PL180 MMCI */ + .dev_id = "mb:mmci", /* 1c050000.mmci */ + .clk = &osc2_clk, + }, { /* PL050 KMI0 */ + .dev_id = "1c060000.kmi", + .clk = &osc2_clk, + }, { /* PL050 KMI1 */ + .dev_id = "1c070000.kmi", + .clk = &osc2_clk, + }, { /* PL011 UART0 */ + .dev_id = "1c090000.uart", + .clk = &osc2_clk, + }, { /* PL011 UART1 */ + .dev_id = "1c0a0000.uart", + .clk = &osc2_clk, + }, { /* PL011 UART2 */ + .dev_id = "1c0b0000.uart", + .clk = &osc2_clk, + }, { /* PL011 UART3 */ + .dev_id = "1c0c0000.uart", + .clk = &osc2_clk, + }, { /* SP805 WDT */ + .dev_id = "1c0f0000.wdt", + .clk = &v2m_ref_clk, + }, { /* PL111 CLCD */ + .dev_id = "1c1f0000.clcd", + .clk = &osc1_clk, + }, +}; + +void __init v2m_dt_init_early(void) +{ + struct device_node *node; + u32 dt_hbi; + + node = of_find_compatible_node(NULL, NULL, "arm,vexpress-sysreg"); + v2m_sysreg_base = of_iomap(node, 0); + if (WARN_ON(!v2m_sysreg_base)) + return; + + /* Confirm board type against DT property, if available */ + if (of_property_read_u32(allnodes, "arm,hbi", &dt_hbi) == 0) { + u32 misc = readl(v2m_sysreg_base + V2M_SYS_MISC); + u32 id = readl(v2m_sysreg_base + (misc & SYS_MISC_MASTERSITE ? + V2M_SYS_PROCID1 : V2M_SYS_PROCID0)); + u32 hbi = id & SYS_PROCIDx_HBI_MASK; + + if (WARN_ON(dt_hbi != hbi)) + pr_warning("vexpress: DT HBI (%x) is not matching " + "hardware (%x)!\n", dt_hbi, hbi); + } + + clkdev_add_table(v2m_dt_lookups, ARRAY_SIZE(v2m_dt_lookups)); + versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000); +} + +static struct of_device_id vexpress_irq_match[] __initdata = { + { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, + {} +}; + +static void __init v2m_dt_init_irq(void) +{ + of_irq_init(vexpress_irq_match); +} + +static void __init v2m_dt_timer_init(void) +{ + struct device_node *node; + const char *path; + int err; + + node = of_find_compatible_node(NULL, NULL, "arm,sp810"); + v2m_sysctl_init(of_iomap(node, 0)); + + err = of_property_read_string(of_aliases, "arm,v2m_timer", &path); + if (WARN_ON(err)) + return; + node = of_find_node_by_path(path); + v2m_sp804_init(of_iomap(node, 0), irq_of_parse_and_map(node, 0)); +} + +static struct sys_timer v2m_dt_timer = { + .init = v2m_dt_timer_init, +}; + +static struct of_dev_auxdata v2m_dt_auxdata_lookup[] __initdata = { + OF_DEV_AUXDATA("arm,vexpress-flash", V2M_NOR0, "physmap-flash", + &v2m_flash_data), + OF_DEV_AUXDATA("arm,primecell", V2M_MMCI, "mb:mmci", &v2m_mmci_data), + /* RS1 memory map */ + OF_DEV_AUXDATA("arm,vexpress-flash", 0x08000000, "physmap-flash", + &v2m_flash_data), + OF_DEV_AUXDATA("arm,primecell", 0x1c050000, "mb:mmci", &v2m_mmci_data), + {} +}; + +static void __init v2m_dt_init(void) +{ + l2x0_of_init(0x00400000, 0xfe0fffff); + of_platform_populate(NULL, of_default_bus_match_table, + v2m_dt_auxdata_lookup, NULL); + pm_power_off = v2m_power_off; +} + +const static char *v2m_dt_match[] __initconst = { + "arm,vexpress", + NULL, +}; + +DT_MACHINE_START(VEXPRESS_DT, "ARM-Versatile Express") + .dt_compat = v2m_dt_match, + .map_io = v2m_dt_map_io, + .init_early = v2m_dt_init_early, + .init_irq = v2m_dt_init_irq, + .timer = &v2m_dt_timer, + .init_machine = v2m_dt_init, + .handle_irq = gic_handle_irq, + .restart = v2m_restart, +MACHINE_END + +#endif |