From 74dd80a7b9fe5e8438458bd17cc9352dff8fd6b7 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Tue, 11 Sep 2012 14:27:29 +0200 Subject: arm: mvebu: add basic address decoding support to Armada 370/XP This commit adds basic support for address decoding configuration for the Armada 370 and Armada XP SoCs, re-using the infrastructure provided in plat-orion. For now, only a BootROM window is configured on Armada XP, which is needed to get the non-boot CPUs started and is therefore a requirement for SMP support. Signed-off-by: Thomas Petazzoni Acked-by: Gregory CLEMENT Acked-by: Arnd Bergmann Tested-by: Andrew Lunn Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/addr-map.c | 134 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 arch/arm/mach-mvebu/addr-map.c (limited to 'arch/arm/mach-mvebu/addr-map.c') diff --git a/arch/arm/mach-mvebu/addr-map.c b/arch/arm/mach-mvebu/addr-map.c new file mode 100644 index 00000000000..fe454a4430b --- /dev/null +++ b/arch/arm/mach-mvebu/addr-map.c @@ -0,0 +1,134 @@ +/* + * Address map functions for Marvell 370 / XP SoCs + * + * Copyright (C) 2012 Marvell + * + * Thomas Petazzoni + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Generic Address Decode Windows bit settings + */ +#define ARMADA_XP_TARGET_DEV_BUS 1 +#define ARMADA_XP_ATTR_DEV_BOOTROM 0x1D +#define ARMADA_XP_TARGET_ETH1 3 +#define ARMADA_XP_TARGET_PCIE_0_2 4 +#define ARMADA_XP_TARGET_ETH0 7 +#define ARMADA_XP_TARGET_PCIE_1_3 8 + +#define ARMADA_370_TARGET_DEV_BUS 1 +#define ARMADA_370_ATTR_DEV_BOOTROM 0x1D +#define ARMADA_370_TARGET_PCIE_0 4 +#define ARMADA_370_TARGET_PCIE_1 8 + +#define ARMADA_WINDOW_8_PLUS_OFFSET 0x90 +#define ARMADA_SDRAM_ADDR_DECODING_OFFSET 0x180 + +static const struct __initdata orion_addr_map_info +armada_xp_addr_map_info[] = { + /* + * Window for the BootROM, needed for SMP on Armada XP + */ + { 0, 0xfff00000, SZ_1M, ARMADA_XP_TARGET_DEV_BUS, + ARMADA_XP_ATTR_DEV_BOOTROM, -1 }, + /* End marker */ + { -1, 0, 0, 0, 0, 0 }, +}; + +static const struct __initdata orion_addr_map_info +armada_370_addr_map_info[] = { + /* End marker */ + { -1, 0, 0, 0, 0, 0 }, +}; + +static struct of_device_id of_addr_decoding_controller_table[] = { + { .compatible = "marvell,armada-addr-decoding-controller" }, + { /* end of list */ }, +}; + +static void __iomem * +armada_cfg_base(const struct orion_addr_map_cfg *cfg, int win) +{ + unsigned int offset; + + /* The register layout is a bit annoying and the below code + * tries to cope with it. + * - At offset 0x0, there are the registers for the first 8 + * windows, with 4 registers of 32 bits per window (ctrl, + * base, remap low, remap high) + * - Then at offset 0x80, there is a hole of 0x10 bytes for + * the internal registers base address and internal units + * sync barrier register. + * - Then at offset 0x90, there the registers for 12 + * windows, with only 2 registers of 32 bits per window + * (ctrl, base). + */ + if (win < 8) + offset = (win << 4); + else + offset = ARMADA_WINDOW_8_PLUS_OFFSET + (win << 3); + + return cfg->bridge_virt_base + offset; +} + +static struct __initdata orion_addr_map_cfg addr_map_cfg = { + .num_wins = 20, + .remappable_wins = 8, + .win_cfg_base = armada_cfg_base, +}; + +static int __init armada_setup_cpu_mbus(void) +{ + struct device_node *np; + void __iomem *mbus_unit_addr_decoding_base; + void __iomem *sdram_addr_decoding_base; + + np = of_find_matching_node(NULL, of_addr_decoding_controller_table); + if (!np) + return -ENODEV; + + mbus_unit_addr_decoding_base = of_iomap(np, 0); + BUG_ON(!mbus_unit_addr_decoding_base); + + sdram_addr_decoding_base = + mbus_unit_addr_decoding_base + + ARMADA_SDRAM_ADDR_DECODING_OFFSET; + + addr_map_cfg.bridge_virt_base = mbus_unit_addr_decoding_base; + + /* + * Disable, clear and configure windows. + */ + if (of_machine_is_compatible("marvell,armadaxp")) + orion_config_wins(&addr_map_cfg, armada_xp_addr_map_info); + else if (of_machine_is_compatible("marvell,armada370")) + orion_config_wins(&addr_map_cfg, armada_370_addr_map_info); + else { + pr_err("Unsupported SoC\n"); + return -EINVAL; + } + + /* + * Setup MBUS dram target info. + */ + orion_setup_cpu_mbus_target(&addr_map_cfg, + sdram_addr_decoding_base); + return 0; +} + +/* Using a early_initcall is needed so that this initialization gets + * done before the SMP initialization, which requires the BootROM to + * be remapped. */ +early_initcall(armada_setup_cpu_mbus); -- cgit v1.2.3 From e60304f8cb7bb545e79fe62d9b9762460c254ec2 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Fri, 12 Oct 2012 19:20:36 +0200 Subject: arm: mvebu: Add hardware I/O Coherency support Armada 370 and XP come with an unit called coherency fabric. This unit allows to use the Armada 370/XP as a nearly coherent architecture. The coherency mechanism uses snoop filters to ensure the coherency between caches, DRAM and devices. This mechanism needs a synchronization barrier which guarantees that all the memory writes initiated by the devices have reached their target and do not reside in intermediate write buffers. That's why the architecture is not totally coherent and we need to provide our own functions for some DMA operations. Beside the use of the coherency fabric, the device units will have to set the attribute flag of the decoding address window to select the accurate coherency process for the memory transaction. This is done each device driver programs the DRAM address windows. The value of the attribute set by the driver is retrieved through the orion_addr_map_cfg struct filled during the early initialization of the platform. Signed-off-by: Gregory CLEMENT Reviewed-by: Yehuda Yitschak Acked-by: Marek Szyprowski --- arch/arm/mach-mvebu/addr-map.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'arch/arm/mach-mvebu/addr-map.c') diff --git a/arch/arm/mach-mvebu/addr-map.c b/arch/arm/mach-mvebu/addr-map.c index fe454a4430b..595f6b722a8 100644 --- a/arch/arm/mach-mvebu/addr-map.c +++ b/arch/arm/mach-mvebu/addr-map.c @@ -108,6 +108,9 @@ static int __init armada_setup_cpu_mbus(void) addr_map_cfg.bridge_virt_base = mbus_unit_addr_decoding_base; + if (of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric")) + addr_map_cfg.hw_io_coherency = 1; + /* * Disable, clear and configure windows. */ -- cgit v1.2.3 From 9f3410ff217f55c2a30bd1b2eb1032806d17c80e Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 22 Nov 2012 18:09:53 +0100 Subject: arm: mvebu: fix address decoding armada_cfg_base() function The armada_cfg_base() function returns the base address of the registers that allow to configure the decoding for a particular address window. On Armada 370/XP, the lower windows have more configuration registers (4 registers) than the higher windows (2 registers). This armada_cfg_base() takes this into account by doing a different offset calculation depending on the window number, but this offset calculation was wrong for the higher windows. Even though we were not using high window numbers until now (only window 0 is used to map the BootROM, needed for SMP), we use this function at boot time to disable all windows to ensure that nothing remains intialized from what the bootloader has done. Unfortunately, the U-Boot on the OpenBlocks AX3-4 uses a window with a high number (above 8) to remap the BootROM. And then when the kernel boots, it remaps the BootROM in window 0. Normally, this is not a problem, because all windows have previously been disabled. Except that due to our wrong offset calculation, the windows with high numbers were not properly disabled, leading to the BootROM being mapped twice. The visible result of this bug was that the kernel was unable to get the second CPU started on the OpenBlocks AX3-4 platform. With this fix, all windows are properly cleared at boot time, the BootROM is remapped only once in window 0, and the second CPU boots fine. Thanks a lot to Lior Amsamlen for his help in debugging this problem. Signed-off-by: Thomas Petazzoni --- Strictly speaking, this bug was introduced in 3.7, but since the only platforms supported in 3.7 were Armada 370 and Armada XP, and there was anyway no SMP support at this time, it isn't really worth the effort to push this patch in 3.7. --- arch/arm/mach-mvebu/addr-map.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/mach-mvebu/addr-map.c') diff --git a/arch/arm/mach-mvebu/addr-map.c b/arch/arm/mach-mvebu/addr-map.c index fe454a4430b..b20fc751b1e 100644 --- a/arch/arm/mach-mvebu/addr-map.c +++ b/arch/arm/mach-mvebu/addr-map.c @@ -78,7 +78,7 @@ armada_cfg_base(const struct orion_addr_map_cfg *cfg, int win) if (win < 8) offset = (win << 4); else - offset = ARMADA_WINDOW_8_PLUS_OFFSET + (win << 3); + offset = ARMADA_WINDOW_8_PLUS_OFFSET + ((win - 8) << 3); return cfg->bridge_virt_base + offset; } -- cgit v1.2.3