linux/arch/arm/plat-omap/sram.c
<<
>>
Prefs
   1/*
   2 * linux/arch/arm/plat-omap/sram.c
   3 *
   4 * OMAP SRAM detection and management
   5 *
   6 * Copyright (C) 2005 Nokia Corporation
   7 * Written by Tony Lindgren <tony@atomide.com>
   8 *
   9 * Copyright (C) 2009-2012 Texas Instruments
  10 * Added OMAP4/5 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
  11 *
  12 * This program is free software; you can redistribute it and/or modify
  13 * it under the terms of the GNU General Public License version 2 as
  14 * published by the Free Software Foundation.
  15 */
  16#undef DEBUG
  17
  18#include <linux/module.h>
  19#include <linux/kernel.h>
  20#include <linux/init.h>
  21#include <linux/io.h>
  22
  23#include <asm/fncpy.h>
  24#include <asm/tlb.h>
  25#include <asm/cacheflush.h>
  26#include <asm/set_memory.h>
  27
  28#include <asm/mach/map.h>
  29
  30#include <plat/sram.h>
  31
  32#define ROUND_DOWN(value,boundary)      ((value) & (~((boundary)-1)))
  33
  34static void __iomem *omap_sram_base;
  35static unsigned long omap_sram_skip;
  36static unsigned long omap_sram_size;
  37static void __iomem *omap_sram_ceil;
  38
  39/*
  40 * Memory allocator for SRAM: calculates the new ceiling address
  41 * for pushing a function using the fncpy API.
  42 *
  43 * Note that fncpy requires the returned address to be aligned
  44 * to an 8-byte boundary.
  45 */
  46static void *omap_sram_push_address(unsigned long size)
  47{
  48        unsigned long available, new_ceil = (unsigned long)omap_sram_ceil;
  49
  50        available = omap_sram_ceil - (omap_sram_base + omap_sram_skip);
  51
  52        if (size > available) {
  53                pr_err("Not enough space in SRAM\n");
  54                return NULL;
  55        }
  56
  57        new_ceil -= size;
  58        new_ceil = ROUND_DOWN(new_ceil, FNCPY_ALIGN);
  59        omap_sram_ceil = IOMEM(new_ceil);
  60
  61        return (void *)omap_sram_ceil;
  62}
  63
  64void *omap_sram_push(void *funcp, unsigned long size)
  65{
  66        void *sram;
  67        unsigned long base;
  68        int pages;
  69        void *dst = NULL;
  70
  71        sram = omap_sram_push_address(size);
  72        if (!sram)
  73                return NULL;
  74
  75        base = (unsigned long)sram & PAGE_MASK;
  76        pages = PAGE_ALIGN(size) / PAGE_SIZE;
  77
  78        set_memory_rw(base, pages);
  79
  80        dst = fncpy(sram, funcp, size);
  81
  82        set_memory_ro(base, pages);
  83        set_memory_x(base, pages);
  84
  85        return dst;
  86}
  87
  88/*
  89 * The SRAM context is lost during off-idle and stack
  90 * needs to be reset.
  91 */
  92void omap_sram_reset(void)
  93{
  94        omap_sram_ceil = omap_sram_base + omap_sram_size;
  95}
  96
  97/*
  98 * Note that we cannot use ioremap for SRAM, as clock init needs SRAM early.
  99 */
 100void __init omap_map_sram(unsigned long start, unsigned long size,
 101                                 unsigned long skip, int cached)
 102{
 103        unsigned long base;
 104        int pages;
 105
 106        if (size == 0)
 107                return;
 108
 109        start = ROUND_DOWN(start, PAGE_SIZE);
 110        omap_sram_size = size;
 111        omap_sram_skip = skip;
 112        omap_sram_base = __arm_ioremap_exec(start, size, cached);
 113        if (!omap_sram_base) {
 114                pr_err("SRAM: Could not map\n");
 115                return;
 116        }
 117
 118        omap_sram_reset();
 119
 120        /*
 121         * Looks like we need to preserve some bootloader code at the
 122         * beginning of SRAM for jumping to flash for reboot to work...
 123         */
 124        memset_io(omap_sram_base + omap_sram_skip, 0,
 125                  omap_sram_size - omap_sram_skip);
 126
 127        base = (unsigned long)omap_sram_base;
 128        pages = PAGE_ALIGN(omap_sram_size) / PAGE_SIZE;
 129
 130        set_memory_ro(base, pages);
 131        set_memory_x(base, pages);
 132}
 133