162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * OMAP SRAM detection and management 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2005 Nokia Corporation 662306a36Sopenharmony_ci * Written by Tony Lindgren <tony@atomide.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/init.h> 1262306a36Sopenharmony_ci#include <linux/io.h> 1362306a36Sopenharmony_ci#include <linux/set_memory.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <asm/fncpy.h> 1662306a36Sopenharmony_ci#include <asm/tlb.h> 1762306a36Sopenharmony_ci#include <asm/cacheflush.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <asm/mach/map.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include "soc.h" 2262306a36Sopenharmony_ci#include "sram.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define OMAP1_SRAM_PA 0x20000000 2562306a36Sopenharmony_ci#define SRAM_BOOTLOADER_SZ 0x80 2662306a36Sopenharmony_ci#define ROUND_DOWN(value, boundary) ((value) & (~((boundary) - 1))) 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic void __iomem *omap_sram_base; 2962306a36Sopenharmony_cistatic unsigned long omap_sram_start; 3062306a36Sopenharmony_cistatic unsigned long omap_sram_skip; 3162306a36Sopenharmony_cistatic unsigned long omap_sram_size; 3262306a36Sopenharmony_cistatic void __iomem *omap_sram_ceil; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* 3562306a36Sopenharmony_ci * Memory allocator for SRAM: calculates the new ceiling address 3662306a36Sopenharmony_ci * for pushing a function using the fncpy API. 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * Note that fncpy requires the returned address to be aligned 3962306a36Sopenharmony_ci * to an 8-byte boundary. 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_cistatic void *omap_sram_push_address(unsigned long size) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci unsigned long available, new_ceil = (unsigned long)omap_sram_ceil; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci available = omap_sram_ceil - (omap_sram_base + omap_sram_skip); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci if (size > available) { 4862306a36Sopenharmony_ci pr_err("Not enough space in SRAM\n"); 4962306a36Sopenharmony_ci return NULL; 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci new_ceil -= size; 5362306a36Sopenharmony_ci new_ceil = ROUND_DOWN(new_ceil, FNCPY_ALIGN); 5462306a36Sopenharmony_ci omap_sram_ceil = IOMEM(new_ceil); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci return (void __force *)omap_sram_ceil; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_civoid *omap_sram_push(void *funcp, unsigned long size) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci void *sram; 6262306a36Sopenharmony_ci unsigned long base; 6362306a36Sopenharmony_ci int pages; 6462306a36Sopenharmony_ci void *dst = NULL; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci sram = omap_sram_push_address(size); 6762306a36Sopenharmony_ci if (!sram) 6862306a36Sopenharmony_ci return NULL; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci base = (unsigned long)sram & PAGE_MASK; 7162306a36Sopenharmony_ci pages = PAGE_ALIGN(size) / PAGE_SIZE; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci set_memory_rw(base, pages); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci dst = fncpy(sram, funcp, size); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci set_memory_rox(base, pages); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci return dst; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* 8362306a36Sopenharmony_ci * The amount of SRAM depends on the core type. 8462306a36Sopenharmony_ci * Note that we cannot try to test for SRAM here because writes 8562306a36Sopenharmony_ci * to secure SRAM will hang the system. Also the SRAM is not 8662306a36Sopenharmony_ci * yet mapped at this point. 8762306a36Sopenharmony_ci * Note that we cannot use ioremap for SRAM, as clock init needs SRAM early. 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_cistatic void __init omap_detect_and_map_sram(void) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci unsigned long base; 9262306a36Sopenharmony_ci int pages; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci omap_sram_skip = SRAM_BOOTLOADER_SZ; 9562306a36Sopenharmony_ci omap_sram_start = OMAP1_SRAM_PA; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci if (cpu_is_omap15xx()) 9862306a36Sopenharmony_ci omap_sram_size = 0x30000; /* 192K */ 9962306a36Sopenharmony_ci else if (cpu_is_omap1610() || cpu_is_omap1611() || 10062306a36Sopenharmony_ci cpu_is_omap1621() || cpu_is_omap1710()) 10162306a36Sopenharmony_ci omap_sram_size = 0x4000; /* 16K */ 10262306a36Sopenharmony_ci else { 10362306a36Sopenharmony_ci pr_err("Could not detect SRAM size\n"); 10462306a36Sopenharmony_ci omap_sram_size = 0x4000; 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci omap_sram_start = ROUND_DOWN(omap_sram_start, PAGE_SIZE); 10862306a36Sopenharmony_ci omap_sram_base = __arm_ioremap_exec(omap_sram_start, omap_sram_size, 1); 10962306a36Sopenharmony_ci if (!omap_sram_base) { 11062306a36Sopenharmony_ci pr_err("SRAM: Could not map\n"); 11162306a36Sopenharmony_ci return; 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci omap_sram_ceil = omap_sram_base + omap_sram_size; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci /* 11762306a36Sopenharmony_ci * Looks like we need to preserve some bootloader code at the 11862306a36Sopenharmony_ci * beginning of SRAM for jumping to flash for reboot to work... 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_ci memset_io(omap_sram_base + omap_sram_skip, 0, 12162306a36Sopenharmony_ci omap_sram_size - omap_sram_skip); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci base = (unsigned long)omap_sram_base; 12462306a36Sopenharmony_ci pages = PAGE_ALIGN(omap_sram_size) / PAGE_SIZE; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci set_memory_rox(base, pages); 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic void (*_omap_sram_reprogram_clock)(u32 dpllctl, u32 ckctl); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_civoid omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci BUG_ON(!_omap_sram_reprogram_clock); 13462306a36Sopenharmony_ci _omap_sram_reprogram_clock(dpllctl, ckctl); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ciint __init omap1_sram_init(void) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci omap_detect_and_map_sram(); 14062306a36Sopenharmony_ci _omap_sram_reprogram_clock = 14162306a36Sopenharmony_ci omap_sram_push(omap1_sram_reprogram_clock, 14262306a36Sopenharmony_ci omap1_sram_reprogram_clock_sz); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci return 0; 14562306a36Sopenharmony_ci} 146