diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-17 09:27:54 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-17 09:27:54 -0800 |
commit | 878ba61aa98cbb97a513757800e77613f856a029 (patch) | |
tree | c03b8373cdb7163f81141a867c9cda1a9f71e73e /drivers/bus | |
parent | ea7531ac4a9d0b39edce43472147dc41cc2b7a34 (diff) | |
parent | df1a66812535e04bfd960e15d5be4893853b6730 (diff) |
Merge tag 'soc-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC platform changes from Olof Johansson:
"New and updated SoC support. Also included are some cleanups where
the platform maintainers hadn't separated cleanups from new developent
in separate branches.
Some of the larger things worth pointing out:
- A large set of changes from Alexandre Belloni and Nicolas Ferre
preparing at91 platforms for multiplatform and cleaning up quite a
bit in the process.
- Removal of CSR's "Marco" SoC platform that never made it out to the
market. We love seeing these since it means the vendor published
support before product was out, which is exactly what we want!
New platforms this release are:
- Conexant Digicolor (CX92755 SoC)
- Hisilicon HiP01 SoC
- CSR/sirf Atlas7 SoC
- ST STiH418 SoC
- Common code changes for Nvidia Tegra132 (64-bit SoC)
We're seeing more and more platforms having a harder time labelling
changes as cleanups vs new development -- which is a good sign that
we've come quite far on the cleanup effort. So over time we might
start combining the cleanup and new-development branches more"
* tag 'soc-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (124 commits)
ARM: at91/trivial: unify functions and machine names
ARM: at91: remove at91_dt_initialize and machine init_early()
ARM: at91: change board files into SoC files
ARM: at91: remove at91_boot_soc
ARM: at91: move alternative initial mapping to board-dt-sama5.c
ARM: at91: merge all SOC_AT91SAM9xxx
ARM: at91: at91rm9200: set idle and restart from rm9200_dt_device_init()
ARM: digicolor: select syscon and timer
ARM: zynq: Simplify SLCR initialization
ARM: zynq: PM: Fixed simple typo.
ARM: zynq: Setup default gpio number for Xilinx Zynq
ARM: digicolor: add low level debug support
ARM: initial support for Conexant Digicolor CX92755 SoC
ARM: OMAP2+: Add dm816x hwmod support
ARM: OMAP2+: Add clock domain support for dm816x
ARM: OMAP2+: Add board-generic.c entry for ti81xx
ARM: at91: pm: remove warning to remove SOC_AT91SAM9263 usage
ARM: at91: remove unused mach/system_rev.h
ARM: at91: stop using HAVE_AT91_DBGUx
ARM: at91: fix ordering of SRAM and PM initialization
...
Diffstat (limited to 'drivers/bus')
-rw-r--r-- | drivers/bus/mvebu-mbus.c | 286 |
1 files changed, 219 insertions, 67 deletions
diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c index 81bf297f1034..fb9ec6221730 100644 --- a/drivers/bus/mvebu-mbus.c +++ b/drivers/bus/mvebu-mbus.c @@ -58,6 +58,7 @@ #include <linux/debugfs.h> #include <linux/log2.h> #include <linux/syscore_ops.h> +#include <linux/memblock.h> /* * DDR target is the same on all platforms. @@ -69,6 +70,7 @@ */ #define WIN_CTRL_OFF 0x0000 #define WIN_CTRL_ENABLE BIT(0) +#define WIN_CTRL_SYNCBARRIER BIT(1) #define WIN_CTRL_TGT_MASK 0xf0 #define WIN_CTRL_TGT_SHIFT 4 #define WIN_CTRL_ATTR_MASK 0xff00 @@ -82,6 +84,9 @@ #define WIN_REMAP_LOW 0xffff0000 #define WIN_REMAP_HI_OFF 0x000c +#define UNIT_SYNC_BARRIER_OFF 0x84 +#define UNIT_SYNC_BARRIER_ALL 0xFFFF + #define ATTR_HW_COHERENCY (0x1 << 4) #define DDR_BASE_CS_OFF(n) (0x0000 + ((n) << 3)) @@ -97,7 +102,9 @@ /* Relative to mbusbridge_base */ #define MBUS_BRIDGE_CTRL_OFF 0x0 +#define MBUS_BRIDGE_SIZE_MASK 0xffff0000 #define MBUS_BRIDGE_BASE_OFF 0x4 +#define MBUS_BRIDGE_BASE_MASK 0xffff0000 /* Maximum number of windows, for all known platforms */ #define MBUS_WINS_MAX 20 @@ -106,9 +113,9 @@ struct mvebu_mbus_state; struct mvebu_mbus_soc_data { unsigned int num_wins; - unsigned int num_remappable_wins; bool has_mbus_bridge; unsigned int (*win_cfg_offset)(const int win); + unsigned int (*win_remap_offset)(const int win); void (*setup_cpu_target)(struct mvebu_mbus_state *s); int (*save_cpu_target)(struct mvebu_mbus_state *s, u32 *store_addr); @@ -154,6 +161,13 @@ const struct mbus_dram_target_info *mv_mbus_dram_info(void) } EXPORT_SYMBOL_GPL(mv_mbus_dram_info); +/* Checks whether the given window has remap capability */ +static bool mvebu_mbus_window_is_remappable(struct mvebu_mbus_state *mbus, + const int win) +{ + return mbus->soc->win_remap_offset(win) != MVEBU_MBUS_NO_REMAP; +} + /* * Functions to manipulate the address decoding windows */ @@ -185,9 +199,12 @@ static void mvebu_mbus_read_window(struct mvebu_mbus_state *mbus, *attr = (ctrlreg & WIN_CTRL_ATTR_MASK) >> WIN_CTRL_ATTR_SHIFT; if (remap) { - if (win < mbus->soc->num_remappable_wins) { - u32 remap_low = readl(addr + WIN_REMAP_LO_OFF); - u32 remap_hi = readl(addr + WIN_REMAP_HI_OFF); + if (mvebu_mbus_window_is_remappable(mbus, win)) { + u32 remap_low, remap_hi; + void __iomem *addr_rmp = mbus->mbuswins_base + + mbus->soc->win_remap_offset(win); + remap_low = readl(addr_rmp + WIN_REMAP_LO_OFF); + remap_hi = readl(addr_rmp + WIN_REMAP_HI_OFF); *remap = ((u64)remap_hi << 32) | remap_low; } else *remap = 0; @@ -200,10 +217,11 @@ static void mvebu_mbus_disable_window(struct mvebu_mbus_state *mbus, void __iomem *addr; addr = mbus->mbuswins_base + mbus->soc->win_cfg_offset(win); - writel(0, addr + WIN_BASE_OFF); writel(0, addr + WIN_CTRL_OFF); - if (win < mbus->soc->num_remappable_wins) { + + if (mvebu_mbus_window_is_remappable(mbus, win)) { + addr = mbus->mbuswins_base + mbus->soc->win_remap_offset(win); writel(0, addr + WIN_REMAP_LO_OFF); writel(0, addr + WIN_REMAP_HI_OFF); } @@ -211,14 +229,6 @@ static void mvebu_mbus_disable_window(struct mvebu_mbus_state *mbus, /* Checks whether the given window number is available */ -/* On Armada XP, 375 and 38x the MBus window 13 has the remap - * capability, like windows 0 to 7. However, the mvebu-mbus driver - * isn't currently taking into account this special case, which means - * that when window 13 is actually used, the remap registers are left - * to 0, making the device using this MBus window unavailable. The - * quick fix for stable is to not use window 13. A follow up patch - * will correctly handle this window. -*/ static int mvebu_mbus_window_is_free(struct mvebu_mbus_state *mbus, const int win) { @@ -226,9 +236,6 @@ static int mvebu_mbus_window_is_free(struct mvebu_mbus_state *mbus, mbus->soc->win_cfg_offset(win); u32 ctrl = readl(addr + WIN_CTRL_OFF); - if (win == 13) - return false; - return !(ctrl & WIN_CTRL_ENABLE); } @@ -316,17 +323,22 @@ static int mvebu_mbus_setup_window(struct mvebu_mbus_state *mbus, ctrl = ((size - 1) & WIN_CTRL_SIZE_MASK) | (attr << WIN_CTRL_ATTR_SHIFT) | (target << WIN_CTRL_TGT_SHIFT) | + WIN_CTRL_SYNCBARRIER | WIN_CTRL_ENABLE; writel(base & WIN_BASE_LOW, addr + WIN_BASE_OFF); writel(ctrl, addr + WIN_CTRL_OFF); - if (win < mbus->soc->num_remappable_wins) { + + if (mvebu_mbus_window_is_remappable(mbus, win)) { + void __iomem *addr_rmp = mbus->mbuswins_base + + mbus->soc->win_remap_offset(win); + if (remap == MVEBU_MBUS_NO_REMAP) remap_addr = base; else remap_addr = remap; - writel(remap_addr & WIN_REMAP_LOW, addr + WIN_REMAP_LO_OFF); - writel(0, addr + WIN_REMAP_HI_OFF); + writel(remap_addr & WIN_REMAP_LOW, addr_rmp + WIN_REMAP_LO_OFF); + writel(0, addr_rmp + WIN_REMAP_HI_OFF); } return 0; @@ -340,19 +352,27 @@ static int mvebu_mbus_alloc_window(struct mvebu_mbus_state *mbus, int win; if (remap == MVEBU_MBUS_NO_REMAP) { - for (win = mbus->soc->num_remappable_wins; - win < mbus->soc->num_wins; win++) + for (win = 0; win < mbus->soc->num_wins; win++) { + if (mvebu_mbus_window_is_remappable(mbus, win)) + continue; + if (mvebu_mbus_window_is_free(mbus, win)) return mvebu_mbus_setup_window(mbus, win, base, size, remap, target, attr); + } } + for (win = 0; win < mbus->soc->num_wins; win++) { + /* Skip window if need remap but is not supported */ + if ((remap != MVEBU_MBUS_NO_REMAP) && + !mvebu_mbus_window_is_remappable(mbus, win)) + continue; - for (win = 0; win < mbus->soc->num_wins; win++) if (mvebu_mbus_window_is_free(mbus, win)) return mvebu_mbus_setup_window(mbus, win, base, size, remap, target, attr); + } return -ENOMEM; } @@ -464,7 +484,7 @@ static int mvebu_devs_debug_show(struct seq_file *seq, void *v) ((wbase & (u64)(wsize - 1)) != 0)) seq_puts(seq, " (Invalid base/size!!)"); - if (win < mbus->soc->num_remappable_wins) { + if (mvebu_mbus_window_is_remappable(mbus, win)) { seq_printf(seq, " (remap %016llx)\n", (unsigned long long)wremap); } else @@ -490,12 +510,12 @@ static const struct file_operations mvebu_devs_debug_fops = { * SoC-specific functions and definitions */ -static unsigned int orion_mbus_win_offset(int win) +static unsigned int generic_mbus_win_cfg_offset(int win) { return win << 4; } -static unsigned int armada_370_xp_mbus_win_offset(int win) +static unsigned int armada_370_xp_mbus_win_cfg_offset(int win) { /* The register layout is a bit annoying and the below code * tries to cope with it. @@ -515,7 +535,7 @@ static unsigned int armada_370_xp_mbus_win_offset(int win) return 0x90 + ((win - 8) << 3); } -static unsigned int mv78xx0_mbus_win_offset(int win) +static unsigned int mv78xx0_mbus_win_cfg_offset(int win) { if (win < 8) return win << 4; @@ -523,36 +543,140 @@ static unsigned int mv78xx0_mbus_win_offset(int win) return 0x900 + ((win - 8) << 4); } +static unsigned int generic_mbus_win_remap_2_offset(int win) +{ + if (win < 2) + return generic_mbus_win_cfg_offset(win); + else + return MVEBU_MBUS_NO_REMAP; +} + +static unsigned int generic_mbus_win_remap_4_offset(int win) +{ + if (win < 4) + return generic_mbus_win_cfg_offset(win); + else + return MVEBU_MBUS_NO_REMAP; +} + +static unsigned int generic_mbus_win_remap_8_offset(int win) +{ + if (win < 8) + return generic_mbus_win_cfg_offset(win); + else + return MVEBU_MBUS_NO_REMAP; +} + +static unsigned int armada_xp_mbus_win_remap_offset(int win) +{ + if (win < 8) + return generic_mbus_win_cfg_offset(win); + else if (win == 13) + return 0xF0 - WIN_REMAP_LO_OFF; + else + return MVEBU_MBUS_NO_REMAP; +} + +/* + * Use the memblock information to find the MBus bridge hole in the + * physical address space. + */ +static void __init +mvebu_mbus_find_bridge_hole(uint64_t *start, uint64_t *end) +{ + struct memblock_region *r; + uint64_t s = 0; + + for_each_memblock(memory, r) { + /* + * This part of the memory is above 4 GB, so we don't + * care for the MBus bridge hole. + */ + if (r->base >= 0x100000000) + continue; + + /* + * The MBus bridge hole is at the end of the RAM under + * the 4 GB limit. + */ + if (r->base + r->size > s) + s = r->base + r->size; + } + + *start = s; + *end = 0x100000000; +} + static void __init mvebu_mbus_default_setup_cpu_target(struct mvebu_mbus_state *mbus) { int i; int cs; + uint64_t mbus_bridge_base, mbus_bridge_end; mvebu_mbus_dram_info.mbus_dram_target_id = TARGET_DDR; + mvebu_mbus_find_bridge_hole(&mbus_bridge_base, &mbus_bridge_end); + for (i = 0, cs = 0; i < 4; i++) { - u32 base = readl(mbus->sdramwins_base + DDR_BASE_CS_OFF(i)); - u32 size = readl(mbus->sdramwins_base + DDR_SIZE_CS_OFF(i)); + u64 base = readl(mbus->sdramwins_base + DDR_BASE_CS_OFF(i)); + u64 size = readl(mbus->sdramwins_base + DDR_SIZE_CS_OFF(i)); + u64 end; + struct mbus_dram_window *w; + + /* Ignore entries that are not enabled */ + if (!(size & DDR_SIZE_ENABLED)) + continue; /* - * We only take care of entries for which the chip - * select is enabled, and that don't have high base - * address bits set (devices can only access the first - * 32 bits of the memory). + * Ignore entries whose base address is above 2^32, + * since devices cannot DMA to such high addresses */ - if ((size & DDR_SIZE_ENABLED) && - !(base & DDR_BASE_CS_HIGH_MASK)) { - struct mbus_dram_window *w; + if (base & DDR_BASE_CS_HIGH_MASK) + continue; - w = &mvebu_mbus_dram_info.cs[cs++]; - w->cs_index = i; - w->mbus_attr = 0xf & ~(1 << i); - if (mbus->hw_io_coherency) - w->mbus_attr |= ATTR_HW_COHERENCY; - w->base = base & DDR_BASE_CS_LOW_MASK; - w->size = (size | ~DDR_SIZE_MASK) + 1; + base = base & DDR_BASE_CS_LOW_MASK; + size = (size | ~DDR_SIZE_MASK) + 1; + end = base + size; + + /* + * Adjust base/size of the current CS to make sure it + * doesn't overlap with the MBus bridge hole. This is + * particularly important for devices that do DMA from + * DRAM to a SRAM mapped in a MBus window, such as the + * CESA cryptographic engine. + */ + + /* + * The CS is fully enclosed inside the MBus bridge + * area, so ignore it. + */ + if (base >= mbus_bridge_base && end <= mbus_bridge_end) + continue; + + /* + * Beginning of CS overlaps with end of MBus, raise CS + * base address, and shrink its size. + */ + if (base >= mbus_bridge_base && end > mbus_bridge_end) { + size -= mbus_bridge_end - base; + base = mbus_bridge_end; } + + /* + * End of CS overlaps with beginning of MBus, shrink + * CS size. + */ + if (base < mbus_bridge_base && end > mbus_bridge_base) + size -= end - mbus_bridge_base; + + w = &mvebu_mbus_dram_info.cs[cs++]; + w->cs_index = i; + w->mbus_attr = 0xf & ~(1 << i); + if (mbus->hw_io_coherency) + w->mbus_attr |= ATTR_HW_COHERENCY; + w->base = base; + w->size = size; } mvebu_mbus_dram_info.num_cs = cs; } @@ -632,30 +756,40 @@ int mvebu_mbus_save_cpu_target(u32 *store_addr) return mbus_state.soc->save_cpu_target(&mbus_state, store_addr); } -static const struct mvebu_mbus_soc_data armada_370_xp_mbus_data = { +static const struct mvebu_mbus_soc_data armada_370_mbus_data = { .num_wins = 20, - .num_remappable_wins = 8, .has_mbus_bridge = true, - .win_cfg_offset = armada_370_xp_mbus_win_offset, + .win_cfg_offset = armada_370_xp_mbus_win_cfg_offset, + .win_remap_offset = generic_mbus_win_remap_8_offset, + .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, + .show_cpu_target = mvebu_sdram_debug_show_orion, .save_cpu_target = mvebu_mbus_default_save_cpu_target, +}; + +static const struct mvebu_mbus_soc_data armada_xp_mbus_data = { + .num_wins = 20, + .has_mbus_bridge = true, + .win_cfg_offset = armada_370_xp_mbus_win_cfg_offset, + .win_remap_offset = armada_xp_mbus_win_remap_offset, .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, .show_cpu_target = mvebu_sdram_debug_show_orion, + .save_cpu_target = mvebu_mbus_default_save_cpu_target, }; static const struct mvebu_mbus_soc_data kirkwood_mbus_data = { .num_wins = 8, - .num_remappable_wins = 4, - .win_cfg_offset = orion_mbus_win_offset, + .win_cfg_offset = generic_mbus_win_cfg_offset, .save_cpu_target = mvebu_mbus_default_save_cpu_target, + .win_remap_offset = generic_mbus_win_remap_4_offset, .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, .show_cpu_target = mvebu_sdram_debug_show_orion, }; static const struct mvebu_mbus_soc_data dove_mbus_data = { .num_wins = 8, - .num_remappable_wins = 4, - .win_cfg_offset = orion_mbus_win_offset, + .win_cfg_offset = generic_mbus_win_cfg_offset, .save_cpu_target = mvebu_mbus_dove_save_cpu_target, + .win_remap_offset = generic_mbus_win_remap_4_offset, .setup_cpu_target = mvebu_mbus_dove_setup_cpu_target, .show_cpu_target = mvebu_sdram_debug_show_dove, }; @@ -666,36 +800,40 @@ static const struct mvebu_mbus_soc_data dove_mbus_data = { */ static const struct mvebu_mbus_soc_data orion5x_4win_mbus_data = { .num_wins = 8, - .num_remappable_wins = 4, - .win_cfg_offset = orion_mbus_win_offset, + .win_cfg_offset = generic_mbus_win_cfg_offset, .save_cpu_target = mvebu_mbus_default_save_cpu_target, + .win_remap_offset = generic_mbus_win_remap_4_offset, .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, .show_cpu_target = mvebu_sdram_debug_show_orion, }; static const struct mvebu_mbus_soc_data orion5x_2win_mbus_data = { .num_wins = 8, - .num_remappable_wins = 2, - .win_cfg_offset = orion_mbus_win_offset, + .win_cfg_offset = generic_mbus_win_cfg_offset, .save_cpu_target = mvebu_mbus_default_save_cpu_target, + .win_remap_offset = generic_mbus_win_remap_2_offset, .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, .show_cpu_target = mvebu_sdram_debug_show_orion, }; static const struct mvebu_mbus_soc_data mv78xx0_mbus_data = { .num_wins = 14, - .num_remappable_wins = 8, - .win_cfg_offset = mv78xx0_mbus_win_offset, + .win_cfg_offset = mv78xx0_mbus_win_cfg_offset, .save_cpu_target = mvebu_mbus_default_save_cpu_target, + .win_remap_offset = generic_mbus_win_remap_8_offset, .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, .show_cpu_target = mvebu_sdram_debug_show_orion, }; static const struct of_device_id of_mvebu_mbus_ids[] = { { .compatible = "marvell,armada370-mbus", - .data = &armada_370_xp_mbus_data, }, + .data = &armada_370_mbus_data, }, + { .compatible = "marvell,armada375-mbus", + .data = &armada_xp_mbus_data, }, + { .compatible = "marvell,armada380-mbus", + .data = &armada_xp_mbus_data, }, { .compatible = "marvell,armadaxp-mbus", - .data = &armada_370_xp_mbus_data, }, + .data = &armada_xp_mbus_data, }, { .compatible = "marvell,kirkwood-mbus", .data = &kirkwood_mbus_data, }, { .compatible = "marvell,dove-mbus", @@ -802,15 +940,19 @@ static int mvebu_mbus_suspend(void) for (win = 0; win < s->soc->num_wins; win++) { void __iomem *addr = s->mbuswins_base + s->soc->win_cfg_offset(win); + void __iomem *addr_rmp; s->wins[win].base = readl(addr + WIN_BASE_OFF); s->wins[win].ctrl = readl(addr + WIN_CTRL_OFF); - if (win >= s->soc->num_remappable_wins) + if (!mvebu_mbus_window_is_remappable(s, win)) continue; - s->wins[win].remap_lo = readl(addr + WIN_REMAP_LO_OFF); - s->wins[win].remap_hi = readl(addr + WIN_REMAP_HI_OFF); + addr_rmp = s->mbuswins_base + + s->soc->win_remap_offset(win); + + s->wins[win].remap_lo = readl(addr_rmp + WIN_REMAP_LO_OFF); + s->wins[win].remap_hi = readl(addr_rmp + WIN_REMAP_HI_OFF); } s->mbus_bridge_ctrl = readl(s->mbusbridge_base + @@ -834,15 +976,19 @@ static void mvebu_mbus_resume(void) for (win = 0; win < s->soc->num_wins; win++) { void __iomem *addr = s->mbuswins_base + s->soc->win_cfg_offset(win); + void __iomem *addr_rmp; writel(s->wins[win].base, addr + WIN_BASE_OFF); writel(s->wins[win].ctrl, addr + WIN_CTRL_OFF); - if (win >= s->soc->num_remappable_wins) + if (!mvebu_mbus_window_is_remappable(s, win)) continue; - writel(s->wins[win].remap_lo, addr + WIN_REMAP_LO_OFF); - writel(s->wins[win].remap_hi, addr + WIN_REMAP_HI_OFF); + addr_rmp = s->mbuswins_base + + s->soc->win_remap_offset(win); + + writel(s->wins[win].remap_lo, addr_rmp + WIN_REMAP_LO_OFF); + writel(s->wins[win].remap_hi, addr_rmp + WIN_REMAP_HI_OFF); } } @@ -857,7 +1003,8 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus, phys_addr_t sdramwins_phys_base, size_t sdramwins_size, phys_addr_t mbusbridge_phys_base, - size_t mbusbridge_size) + size_t mbusbridge_size, + bool is_coherent) { int win; @@ -889,6 +1036,10 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus, mbus->soc->setup_cpu_target(mbus); + if (is_coherent) + writel(UNIT_SYNC_BARRIER_ALL, + mbus->mbuswins_base + UNIT_SYNC_BARRIER_OFF); + register_syscore_ops(&mvebu_mbus_syscore_ops); return 0; @@ -916,7 +1067,7 @@ int __init mvebu_mbus_init(const char *soc, phys_addr_t mbuswins_phys_base, mbuswins_phys_base, mbuswins_size, sdramwins_phys_base, - sdramwins_size, 0, 0); + sdramwins_size, 0, 0, false); } #ifdef CONFIG_OF @@ -1118,7 +1269,8 @@ int __init mvebu_mbus_dt_init(bool is_coherent) sdramwins_res.start, resource_size(&sdramwins_res), mbusbridge_res.start, - resource_size(&mbusbridge_res)); + resource_size(&mbusbridge_res), + is_coherent); if (ret) return ret; |