diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-02 07:11:00 +0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-02 07:11:00 +0400 |
commit | 952414505f55afe5cd6dc004765076aa22b3ed7e (patch) | |
tree | eba11ed702ae02fea7f1a0d422346454fc98296f /arch/arm/mach-ux500/cache-l2x0.c | |
parent | 68e24ba70465b82ad24e0774ceab5360180d4627 (diff) | |
parent | 3e965b176341b78620f7404fd8b7f9a0d061f8a2 (diff) | |
download | linux-952414505f55afe5cd6dc004765076aa22b3ed7e.tar.xz |
Merge branch 'next/cleanup' of git://git.linaro.org/people/arnd/arm-soc
* 'next/cleanup' of git://git.linaro.org/people/arnd/arm-soc: (125 commits)
ARM: mach-mxs: fix machines' initializers order
mmc: mxcmmc: explicitly includes mach/hardware.h
arm/imx: explicitly includes mach/hardware.h in pm-imx27.c
arm/imx: remove mx27_setup_weimcs() from mx27.h
arm/imx: explicitly includes mach/hardware.h in mach-kzm_arm11_01.c
arm/imx: remove mx31_setup_weimcs() from mx31.h
ARM: tegra: devices.c should include devices.h
ARM: tegra: cpu-tegra: unexport two functions
ARM: tegra: cpu-tegra: sparse type fix
ARM: tegra: dma: staticify some tables and functions
ARM: tegra: tegra2_clocks: don't export some tables
ARM: tegra: tegra_powergate_is_powered should be static
ARM: tegra: tegra_rtc_read_ms should be static
ARM: tegra: tegra_init_cache should be static
ARM: tegra: pcie: 0 -> NULL changes
ARM: tegra: pcie: include board.h
ARM: tegra: pcie: don't cast __iomem pointers
ARM: tegra: tegra2_clocks: 0 -> NULL changes
ARM: tegra: tegra2_clocks: don't cast __iomem pointers
ARM: tegra: timer: don't cast __iomem pointers
...
Fix up trivial conflicts in
arch/arm/mach-omap2/Makefile,
arch/arm/mach-u300/{Makefile.boot,core.c}
arch/arm/plat-{mxc,omap}/devices.c
Diffstat (limited to 'arch/arm/mach-ux500/cache-l2x0.c')
-rw-r--r-- | arch/arm/mach-ux500/cache-l2x0.c | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/arch/arm/mach-ux500/cache-l2x0.c b/arch/arm/mach-ux500/cache-l2x0.c new file mode 100644 index 000000000000..122ddde00ba7 --- /dev/null +++ b/arch/arm/mach-ux500/cache-l2x0.c @@ -0,0 +1,95 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include <linux/io.h> +#include <asm/cacheflush.h> +#include <asm/hardware/cache-l2x0.h> +#include <mach/hardware.h> +#include <mach/id.h> + +static void __iomem *l2x0_base; + +static inline void ux500_cache_wait(void __iomem *reg, unsigned long mask) +{ + /* wait for the operation to complete */ + while (readl_relaxed(reg) & mask) + cpu_relax(); +} + +static inline void ux500_cache_sync(void) +{ + writel_relaxed(0, l2x0_base + L2X0_CACHE_SYNC); + ux500_cache_wait(l2x0_base + L2X0_CACHE_SYNC, 1); +} + +/* + * The L2 cache cannot be turned off in the non-secure world. + * Dummy until a secure service is in place. + */ +static void ux500_l2x0_disable(void) +{ +} + +/* + * This is only called when doing a kexec, just after turning off the L2 + * and L1 cache, and it is surrounded by a spinlock in the generic version. + * However, we're not really turning off the L2 cache right now and the + * PL310 does not support exclusive accesses (used to implement the spinlock). + * So, the invalidation needs to be done without the spinlock. + */ +static void ux500_l2x0_inv_all(void) +{ + uint32_t l2x0_way_mask = (1<<16) - 1; /* Bitmask of active ways */ + + /* invalidate all ways */ + writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_INV_WAY); + ux500_cache_wait(l2x0_base + L2X0_INV_WAY, l2x0_way_mask); + ux500_cache_sync(); +} + +static int __init ux500_l2x0_unlock(void) +{ + int i; + + /* + * Unlock Data and Instruction Lock if locked. Ux500 U-Boot versions + * apparently locks both caches before jumping to the kernel. The + * l2x0 core will not touch the unlock registers if the l2x0 is + * already enabled, so we do it right here instead. The PL310 has + * 8 sets of registers, one per possible CPU. + */ + for (i = 0; i < 8; i++) { + writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_D_BASE + + i * L2X0_LOCKDOWN_STRIDE); + writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_I_BASE + + i * L2X0_LOCKDOWN_STRIDE); + } + return 0; +} + +static int __init ux500_l2x0_init(void) +{ + if (cpu_is_u5500()) + l2x0_base = __io_address(U5500_L2CC_BASE); + else if (cpu_is_u8500()) + l2x0_base = __io_address(U8500_L2CC_BASE); + else + ux500_unknown_soc(); + + /* Unlock before init */ + ux500_l2x0_unlock(); + + /* 64KB way size, 8 way associativity, force WA */ + l2x0_init(l2x0_base, 0x3e060000, 0xc0000fff); + + /* Override invalidate function */ + outer_cache.disable = ux500_l2x0_disable; + outer_cache.inv_all = ux500_l2x0_inv_all; + + return 0; +} + +early_initcall(ux500_l2x0_init); |