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