summaryrefslogtreecommitdiff
path: root/arch/arm/mach-vexpress/v2m.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-vexpress/v2m.c')
-rw-r--r--arch/arm/mach-vexpress/v2m.c281
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 @@
#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>
@@ -40,29 +46,45 @@
static struct map_desc v2m_io_desc[] __initdata = {
{
- .virtual = __MMIO_P2V(V2M_PA_CS7),
+ .virtual = V2M_PERIPH,
.pfn = __phys_to_pfn(V2M_PA_CS7),
.length = SZ_128K,
.type = MT_DEVICE,
},
};
-static void __init v2m_timer_init(void)
+static void __iomem *v2m_sysreg_base;
+
+static void __init v2m_sysctl_init(void __iomem *base)
{
u32 scctrl;
+ if (WARN_ON(!base))
+ return;
+
/* Select 1MHz TIMCLK as the reference clock for SP804 timers */
- scctrl = readl(MMIO_P2V(V2M_SYSCTL + SCCTRL));
+ scctrl = readl(base + SCCTRL);
scctrl |= SCCTRL_TIMEREN0SEL_TIMCLK;
scctrl |= SCCTRL_TIMEREN1SEL_TIMCLK;
- writel(scctrl, MMIO_P2V(V2M_SYSCTL + SCCTRL));
+ writel(scctrl, base + SCCTRL);
+}
+
+static void __init v2m_sp804_init(void __iomem *base, unsigned int irq)
+{
+ if (WARN_ON(!base || irq == NO_IRQ))
+ return;
+
+ writel(0, base + TIMER_1_BASE + TIMER_CTRL);
+ writel(0, base + TIMER_2_BASE + TIMER_CTRL);
- writel(0, MMIO_P2V(V2M_TIMER0) + TIMER_CTRL);
- writel(0, MMIO_P2V(V2M_TIMER1) + TIMER_CTRL);
+ sp804_clocksource_init(base + TIMER_2_BASE, "v2m-timer1");
+ sp804_clockevents_init(base + TIMER_1_BASE, irq, "v2m-timer0");
+}
- sp804_clocksource_init(MMIO_P2V(V2M_TIMER1), "v2m-timer1");
- sp804_clockevents_init(MMIO_P2V(V2M_TIMER0), IRQ_V2M_TIMER0,
- "v2m-timer0");
+static void __init v2m_timer_init(void)
+{
+ v2m_sysctl_init(ioremap(V2M_SYSCTL, SZ_4K));
+ v2m_sp804_init(ioremap(V2M_TIMER01, SZ_4K), IRQ_V2M_TIMER0);
}
static struct sys_timer v2m_timer = {
@@ -82,14 +104,14 @@ int v2m_cfg_write(u32 devfn, u32 data)
devfn |= SYS_CFG_START | SYS_CFG_WRITE;
spin_lock(&v2m_cfg_lock);
- val = readl(MMIO_P2V(V2M_SYS_CFGSTAT));
- writel(val & ~SYS_CFG_COMPLETE, MMIO_P2V(V2M_SYS_CFGSTAT));
+ val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT);
+ writel(val & ~SYS_CFG_COMPLETE, v2m_sysreg_base + V2M_SYS_CFGSTAT);
- writel(data, MMIO_P2V(V2M_SYS_CFGDATA));
- writel(devfn, MMIO_P2V(V2M_SYS_CFGCTRL));
+ writel(data, v2m_sysreg_base + V2M_SYS_CFGDATA);
+ writel(devfn, v2m_sysreg_base + V2M_SYS_CFGCTRL);
do {
- val = readl(MMIO_P2V(V2M_SYS_CFGSTAT));
+ val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT);
} while (val == 0);
spin_unlock(&v2m_cfg_lock);
@@ -103,22 +125,28 @@ int v2m_cfg_read(u32 devfn, u32 *data)
devfn |= SYS_CFG_START;
spin_lock(&v2m_cfg_lock);
- writel(0, MMIO_P2V(V2M_SYS_CFGSTAT));
- writel(devfn, MMIO_P2V(V2M_SYS_CFGCTRL));
+ writel(0, v2m_sysreg_base + V2M_SYS_CFGSTAT);
+ writel(devfn, v2m_sysreg_base + V2M_SYS_CFGCTRL);
mb();
do {
cpu_relax();
- val = readl(MMIO_P2V(V2M_SYS_CFGSTAT));
+ val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT);
} while (val == 0);
- *data = readl(MMIO_P2V(V2M_SYS_CFGDATA));
+ *data = readl(v2m_sysreg_base + V2M_SYS_CFGDATA);
spin_unlock(&v2m_cfg_lock);
return !!(val & SYS_CFG_ERR);
}
+void __init v2m_flags_set(u32 data)
+{
+ writel(~0, v2m_sysreg_base + V2M_SYS_FLAGSCLR);
+ writel(data, v2m_sysreg_base + V2M_SYS_FLAGSSET);
+}
+
static struct resource v2m_pcie_i2c_resource = {
.start = V2M_SERIAL_BUS_PCI,
@@ -204,7 +232,7 @@ static struct platform_device v2m_usb_device = {
static void v2m_flash_set_vpp(struct platform_device *pdev, int on)
{
- writel(on != 0, MMIO_P2V(V2M_SYS_FLASH));
+ writel(on != 0, v2m_sysreg_base + V2M_SYS_FLASH);
}
static struct physmap_flash_data v2m_flash_data = {
@@ -258,7 +286,7 @@ static struct platform_device v2m_cf_device = {
static unsigned int v2m_mmci_status(struct device *dev)
{
- return readl(MMIO_P2V(V2M_SYS_MCI)) & (1 << 0);
+ return readl(v2m_sysreg_base + V2M_SYS_MCI) & (1 << 0);
}
static struct mmci_platform_data v2m_mmci_data = {
@@ -371,7 +399,7 @@ static void __init v2m_init_early(void)
{
ct_desc->init_early();
clkdev_add_table(v2m_lookups, ARRAY_SIZE(v2m_lookups));
- versatile_sched_clock_init(MMIO_P2V(V2M_SYS_24MHZ), 24000000);
+ versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000);
}
static void v2m_power_off(void)
@@ -400,20 +428,23 @@ static void __init v2m_populate_ct_desc(void)
u32 current_tile_id;
ct_desc = NULL;
- current_tile_id = readl(MMIO_P2V(V2M_SYS_PROCID0)) & V2M_CT_ID_MASK;
+ current_tile_id = readl(v2m_sysreg_base + V2M_SYS_PROCID0)
+ & V2M_CT_ID_MASK;
for (i = 0; i < ARRAY_SIZE(ct_descs) && !ct_desc; ++i)
if (ct_descs[i]->id == current_tile_id)
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)
{
iotable_init(v2m_io_desc, ARRAY_SIZE(v2m_io_desc));
+ v2m_sysreg_base = ioremap(V2M_SYSREGS, SZ_4K);
v2m_populate_ct_desc();
ct_desc->map_io();
}
@@ -452,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