diff options
Diffstat (limited to 'arch/arm/mach-omap2/sram.c')
-rw-r--r-- | arch/arm/mach-omap2/sram.c | 91 |
1 files changed, 88 insertions, 3 deletions
diff --git a/arch/arm/mach-omap2/sram.c b/arch/arm/mach-omap2/sram.c index c98855f5594b..c685afb8bd03 100644 --- a/arch/arm/mach-omap2/sram.c +++ b/arch/arm/mach-omap2/sram.c @@ -18,6 +18,7 @@ #include <asm/fncpy.h> #include <asm/tlb.h> #include <asm/cacheflush.h> +#include <asm/set_memory.h> #include <asm/mach/map.h> @@ -47,8 +48,68 @@ #define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1))) static unsigned long omap_sram_start; -static unsigned long omap_sram_skip; static unsigned long omap_sram_size; +static void __iomem *omap_sram_base; +static unsigned long omap_sram_skip; +static void __iomem *omap_sram_ceil; + +/* + * Memory allocator for SRAM: calculates the new ceiling address + * for pushing a function using the fncpy API. + * + * Note that fncpy requires the returned address to be aligned + * to an 8-byte boundary. + */ +static void *omap_sram_push_address(unsigned long size) +{ + unsigned long available, new_ceil = (unsigned long)omap_sram_ceil; + + available = omap_sram_ceil - (omap_sram_base + omap_sram_skip); + + if (size > available) { + pr_err("Not enough space in SRAM\n"); + return NULL; + } + + new_ceil -= size; + new_ceil = ROUND_DOWN(new_ceil, FNCPY_ALIGN); + omap_sram_ceil = IOMEM(new_ceil); + + return (void *)omap_sram_ceil; +} + +void *omap_sram_push(void *funcp, unsigned long size) +{ + void *sram; + unsigned long base; + int pages; + void *dst = NULL; + + sram = omap_sram_push_address(size); + if (!sram) + return NULL; + + base = (unsigned long)sram & PAGE_MASK; + pages = PAGE_ALIGN(size) / PAGE_SIZE; + + set_memory_rw(base, pages); + + dst = fncpy(sram, funcp, size); + + set_memory_ro(base, pages); + set_memory_x(base, pages); + + return dst; +} + +/* + * The SRAM context is lost during off-idle and stack + * needs to be reset. + */ +static void omap_sram_reset(void) +{ + omap_sram_ceil = omap_sram_base + omap_sram_size; +} /* * Depending on the target RAMFS firewall setup, the public usable amount of @@ -119,6 +180,8 @@ static void __init omap_detect_sram(void) */ static void __init omap2_map_sram(void) { + unsigned long base; + int pages; int cached = 1; if (cpu_is_omap34xx()) { @@ -132,8 +195,30 @@ static void __init omap2_map_sram(void) cached = 0; } - omap_map_sram(omap_sram_start, omap_sram_size, - omap_sram_skip, cached); + if (omap_sram_size == 0) + return; + + omap_sram_start = ROUND_DOWN(omap_sram_start, PAGE_SIZE); + omap_sram_base = __arm_ioremap_exec(omap_sram_start, omap_sram_size, cached); + if (!omap_sram_base) { + pr_err("SRAM: Could not map\n"); + return; + } + + omap_sram_reset(); + + /* + * Looks like we need to preserve some bootloader code at the + * beginning of SRAM for jumping to flash for reboot to work... + */ + memset_io(omap_sram_base + omap_sram_skip, 0, + omap_sram_size - omap_sram_skip); + + base = (unsigned long)omap_sram_base; + pages = PAGE_ALIGN(omap_sram_size) / PAGE_SIZE; + + set_memory_ro(base, pages); + set_memory_x(base, pages); } static void (*_omap2_sram_ddr_init)(u32 *slow_dll_ctrl, u32 fast_dll_ctrl, |