162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * OMAP SRAM detection and management 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2005 Nokia Corporation 762306a36Sopenharmony_ci * Written by Tony Lindgren <tony@atomide.com> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Copyright (C) 2009-2012 Texas Instruments 1062306a36Sopenharmony_ci * Added OMAP4/5 support - Santosh Shilimkar <santosh.shilimkar@ti.com> 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/kernel.h> 1562306a36Sopenharmony_ci#include <linux/init.h> 1662306a36Sopenharmony_ci#include <linux/io.h> 1762306a36Sopenharmony_ci#include <linux/set_memory.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <asm/fncpy.h> 2062306a36Sopenharmony_ci#include <asm/tlb.h> 2162306a36Sopenharmony_ci#include <asm/cacheflush.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <asm/mach/map.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include "soc.h" 2662306a36Sopenharmony_ci#include "iomap.h" 2762306a36Sopenharmony_ci#include "prm2xxx_3xxx.h" 2862306a36Sopenharmony_ci#include "sdrc.h" 2962306a36Sopenharmony_ci#include "sram.h" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define OMAP2_SRAM_PUB_PA (OMAP2_SRAM_PA + 0xf800) 3262306a36Sopenharmony_ci#define OMAP3_SRAM_PUB_PA (OMAP3_SRAM_PA + 0x8000) 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define SRAM_BOOTLOADER_SZ 0x00 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define OMAP24XX_VA_REQINFOPERM0 OMAP2_L3_IO_ADDRESS(0x68005048) 3762306a36Sopenharmony_ci#define OMAP24XX_VA_READPERM0 OMAP2_L3_IO_ADDRESS(0x68005050) 3862306a36Sopenharmony_ci#define OMAP24XX_VA_WRITEPERM0 OMAP2_L3_IO_ADDRESS(0x68005058) 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define OMAP34XX_VA_REQINFOPERM0 OMAP2_L3_IO_ADDRESS(0x68012848) 4162306a36Sopenharmony_ci#define OMAP34XX_VA_READPERM0 OMAP2_L3_IO_ADDRESS(0x68012850) 4262306a36Sopenharmony_ci#define OMAP34XX_VA_WRITEPERM0 OMAP2_L3_IO_ADDRESS(0x68012858) 4362306a36Sopenharmony_ci#define OMAP34XX_VA_ADDR_MATCH2 OMAP2_L3_IO_ADDRESS(0x68012880) 4462306a36Sopenharmony_ci#define OMAP34XX_VA_SMS_RG_ATT0 OMAP2_L3_IO_ADDRESS(0x6C000048) 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define GP_DEVICE 0x300 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define ROUND_DOWN(value, boundary) ((value) & (~((boundary) - 1))) 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic unsigned long omap_sram_start; 5162306a36Sopenharmony_cistatic unsigned long omap_sram_size; 5262306a36Sopenharmony_cistatic void __iomem *omap_sram_base; 5362306a36Sopenharmony_cistatic unsigned long omap_sram_skip; 5462306a36Sopenharmony_cistatic void __iomem *omap_sram_ceil; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* 5762306a36Sopenharmony_ci * Memory allocator for SRAM: calculates the new ceiling address 5862306a36Sopenharmony_ci * for pushing a function using the fncpy API. 5962306a36Sopenharmony_ci * 6062306a36Sopenharmony_ci * Note that fncpy requires the returned address to be aligned 6162306a36Sopenharmony_ci * to an 8-byte boundary. 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_cistatic void *omap_sram_push_address(unsigned long size) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci unsigned long available, new_ceil = (unsigned long)omap_sram_ceil; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci available = omap_sram_ceil - (omap_sram_base + omap_sram_skip); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci if (size > available) { 7062306a36Sopenharmony_ci pr_err("Not enough space in SRAM\n"); 7162306a36Sopenharmony_ci return NULL; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci new_ceil -= size; 7562306a36Sopenharmony_ci new_ceil = ROUND_DOWN(new_ceil, FNCPY_ALIGN); 7662306a36Sopenharmony_ci omap_sram_ceil = IOMEM(new_ceil); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci return (void __force *)omap_sram_ceil; 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_civoid *omap_sram_push(void *funcp, unsigned long size) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci void *sram; 8462306a36Sopenharmony_ci unsigned long base; 8562306a36Sopenharmony_ci int pages; 8662306a36Sopenharmony_ci void *dst = NULL; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci sram = omap_sram_push_address(size); 8962306a36Sopenharmony_ci if (!sram) 9062306a36Sopenharmony_ci return NULL; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci base = (unsigned long)sram & PAGE_MASK; 9362306a36Sopenharmony_ci pages = PAGE_ALIGN(size) / PAGE_SIZE; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci set_memory_rw(base, pages); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci dst = fncpy(sram, funcp, size); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci set_memory_rox(base, pages); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci return dst; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* 10562306a36Sopenharmony_ci * The SRAM context is lost during off-idle and stack 10662306a36Sopenharmony_ci * needs to be reset. 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_cistatic void omap_sram_reset(void) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci omap_sram_ceil = omap_sram_base + omap_sram_size; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/* 11462306a36Sopenharmony_ci * Depending on the target RAMFS firewall setup, the public usable amount of 11562306a36Sopenharmony_ci * SRAM varies. The default accessible size for all device types is 2k. A GP 11662306a36Sopenharmony_ci * device allows ARM11 but not other initiators for full size. This 11762306a36Sopenharmony_ci * functionality seems ok until some nice security API happens. 11862306a36Sopenharmony_ci */ 11962306a36Sopenharmony_cistatic int is_sram_locked(void) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci if (omap_type() == OMAP2_DEVICE_TYPE_GP) { 12262306a36Sopenharmony_ci /* RAMFW: R/W access to all initiators for all qualifier sets */ 12362306a36Sopenharmony_ci if (cpu_is_omap242x()) { 12462306a36Sopenharmony_ci writel_relaxed(0xFF, OMAP24XX_VA_REQINFOPERM0); /* all q-vects */ 12562306a36Sopenharmony_ci writel_relaxed(0xCFDE, OMAP24XX_VA_READPERM0); /* all i-read */ 12662306a36Sopenharmony_ci writel_relaxed(0xCFDE, OMAP24XX_VA_WRITEPERM0); /* all i-write */ 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci if (cpu_is_omap34xx()) { 12962306a36Sopenharmony_ci writel_relaxed(0xFFFF, OMAP34XX_VA_REQINFOPERM0); /* all q-vects */ 13062306a36Sopenharmony_ci writel_relaxed(0xFFFF, OMAP34XX_VA_READPERM0); /* all i-read */ 13162306a36Sopenharmony_ci writel_relaxed(0xFFFF, OMAP34XX_VA_WRITEPERM0); /* all i-write */ 13262306a36Sopenharmony_ci writel_relaxed(0x0, OMAP34XX_VA_ADDR_MATCH2); 13362306a36Sopenharmony_ci writel_relaxed(0xFFFFFFFF, OMAP34XX_VA_SMS_RG_ATT0); 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci return 0; 13662306a36Sopenharmony_ci } else 13762306a36Sopenharmony_ci return 1; /* assume locked with no PPA or security driver */ 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci/* 14162306a36Sopenharmony_ci * The amount of SRAM depends on the core type. 14262306a36Sopenharmony_ci * Note that we cannot try to test for SRAM here because writes 14362306a36Sopenharmony_ci * to secure SRAM will hang the system. Also the SRAM is not 14462306a36Sopenharmony_ci * yet mapped at this point. 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_cistatic void __init omap_detect_sram(void) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci omap_sram_skip = SRAM_BOOTLOADER_SZ; 14962306a36Sopenharmony_ci if (is_sram_locked()) { 15062306a36Sopenharmony_ci if (cpu_is_omap34xx()) { 15162306a36Sopenharmony_ci omap_sram_start = OMAP3_SRAM_PUB_PA; 15262306a36Sopenharmony_ci if ((omap_type() == OMAP2_DEVICE_TYPE_EMU) || 15362306a36Sopenharmony_ci (omap_type() == OMAP2_DEVICE_TYPE_SEC)) { 15462306a36Sopenharmony_ci omap_sram_size = 0x7000; /* 28K */ 15562306a36Sopenharmony_ci omap_sram_skip += SZ_16K; 15662306a36Sopenharmony_ci } else { 15762306a36Sopenharmony_ci omap_sram_size = 0x8000; /* 32K */ 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci } else { 16062306a36Sopenharmony_ci omap_sram_start = OMAP2_SRAM_PUB_PA; 16162306a36Sopenharmony_ci omap_sram_size = 0x800; /* 2K */ 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci } else { 16462306a36Sopenharmony_ci if (cpu_is_omap34xx()) { 16562306a36Sopenharmony_ci omap_sram_start = OMAP3_SRAM_PA; 16662306a36Sopenharmony_ci omap_sram_size = 0x10000; /* 64K */ 16762306a36Sopenharmony_ci } else { 16862306a36Sopenharmony_ci omap_sram_start = OMAP2_SRAM_PA; 16962306a36Sopenharmony_ci if (cpu_is_omap242x()) 17062306a36Sopenharmony_ci omap_sram_size = 0xa0000; /* 640K */ 17162306a36Sopenharmony_ci else if (cpu_is_omap243x()) 17262306a36Sopenharmony_ci omap_sram_size = 0x10000; /* 64K */ 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci/* 17862306a36Sopenharmony_ci * Note that we cannot use ioremap for SRAM, as clock init needs SRAM early. 17962306a36Sopenharmony_ci */ 18062306a36Sopenharmony_cistatic void __init omap2_map_sram(void) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci unsigned long base; 18362306a36Sopenharmony_ci int pages; 18462306a36Sopenharmony_ci int cached = 1; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (cpu_is_omap34xx()) { 18762306a36Sopenharmony_ci /* 18862306a36Sopenharmony_ci * SRAM must be marked as non-cached on OMAP3 since the 18962306a36Sopenharmony_ci * CORE DPLL M2 divider change code (in SRAM) runs with the 19062306a36Sopenharmony_ci * SDRAM controller disabled, and if it is marked cached, 19162306a36Sopenharmony_ci * the ARM may attempt to write cache lines back to SDRAM 19262306a36Sopenharmony_ci * which will cause the system to hang. 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_ci cached = 0; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (omap_sram_size == 0) 19862306a36Sopenharmony_ci return; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci omap_sram_start = ROUND_DOWN(omap_sram_start, PAGE_SIZE); 20162306a36Sopenharmony_ci omap_sram_base = __arm_ioremap_exec(omap_sram_start, omap_sram_size, cached); 20262306a36Sopenharmony_ci if (!omap_sram_base) { 20362306a36Sopenharmony_ci pr_err("SRAM: Could not map\n"); 20462306a36Sopenharmony_ci return; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci omap_sram_reset(); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* 21062306a36Sopenharmony_ci * Looks like we need to preserve some bootloader code at the 21162306a36Sopenharmony_ci * beginning of SRAM for jumping to flash for reboot to work... 21262306a36Sopenharmony_ci */ 21362306a36Sopenharmony_ci memset_io(omap_sram_base + omap_sram_skip, 0, 21462306a36Sopenharmony_ci omap_sram_size - omap_sram_skip); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci base = (unsigned long)omap_sram_base; 21762306a36Sopenharmony_ci pages = PAGE_ALIGN(omap_sram_size) / PAGE_SIZE; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci set_memory_rox(base, pages); 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistatic void (*_omap2_sram_ddr_init)(u32 *slow_dll_ctrl, u32 fast_dll_ctrl, 22362306a36Sopenharmony_ci u32 base_cs, u32 force_unlock); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_civoid omap2_sram_ddr_init(u32 *slow_dll_ctrl, u32 fast_dll_ctrl, 22662306a36Sopenharmony_ci u32 base_cs, u32 force_unlock) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci BUG_ON(!_omap2_sram_ddr_init); 22962306a36Sopenharmony_ci _omap2_sram_ddr_init(slow_dll_ctrl, fast_dll_ctrl, 23062306a36Sopenharmony_ci base_cs, force_unlock); 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic void (*_omap2_sram_reprogram_sdrc)(u32 perf_level, u32 dll_val, 23462306a36Sopenharmony_ci u32 mem_type); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_civoid omap2_sram_reprogram_sdrc(u32 perf_level, u32 dll_val, u32 mem_type) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci BUG_ON(!_omap2_sram_reprogram_sdrc); 23962306a36Sopenharmony_ci _omap2_sram_reprogram_sdrc(perf_level, dll_val, mem_type); 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic u32 (*_omap2_set_prcm)(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ciu32 omap2_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci BUG_ON(!_omap2_set_prcm); 24762306a36Sopenharmony_ci return _omap2_set_prcm(dpll_ctrl_val, sdrc_rfr_val, bypass); 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci#ifdef CONFIG_SOC_OMAP2420 25162306a36Sopenharmony_cistatic int __init omap242x_sram_init(void) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci _omap2_sram_ddr_init = omap_sram_push(omap242x_sram_ddr_init, 25462306a36Sopenharmony_ci omap242x_sram_ddr_init_sz); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci _omap2_sram_reprogram_sdrc = omap_sram_push(omap242x_sram_reprogram_sdrc, 25762306a36Sopenharmony_ci omap242x_sram_reprogram_sdrc_sz); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci _omap2_set_prcm = omap_sram_push(omap242x_sram_set_prcm, 26062306a36Sopenharmony_ci omap242x_sram_set_prcm_sz); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci return 0; 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci#else 26562306a36Sopenharmony_cistatic inline int omap242x_sram_init(void) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci return 0; 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci#endif 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci#ifdef CONFIG_SOC_OMAP2430 27262306a36Sopenharmony_cistatic int __init omap243x_sram_init(void) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci _omap2_sram_ddr_init = omap_sram_push(omap243x_sram_ddr_init, 27562306a36Sopenharmony_ci omap243x_sram_ddr_init_sz); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci _omap2_sram_reprogram_sdrc = omap_sram_push(omap243x_sram_reprogram_sdrc, 27862306a36Sopenharmony_ci omap243x_sram_reprogram_sdrc_sz); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci _omap2_set_prcm = omap_sram_push(omap243x_sram_set_prcm, 28162306a36Sopenharmony_ci omap243x_sram_set_prcm_sz); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci return 0; 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci#else 28662306a36Sopenharmony_cistatic inline int omap243x_sram_init(void) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci return 0; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci#endif 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci#ifdef CONFIG_ARCH_OMAP3 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_civoid omap3_sram_restore_context(void) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci omap_sram_reset(); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci omap_push_sram_idle(); 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic inline int omap34xx_sram_init(void) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci omap3_sram_restore_context(); 30462306a36Sopenharmony_ci return 0; 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci#else 30762306a36Sopenharmony_cistatic inline int omap34xx_sram_init(void) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci return 0; 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci#endif /* CONFIG_ARCH_OMAP3 */ 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ciint __init omap_sram_init(void) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci omap_detect_sram(); 31662306a36Sopenharmony_ci omap2_map_sram(); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if (cpu_is_omap242x()) 31962306a36Sopenharmony_ci omap242x_sram_init(); 32062306a36Sopenharmony_ci else if (cpu_is_omap2430()) 32162306a36Sopenharmony_ci omap243x_sram_init(); 32262306a36Sopenharmony_ci else if (cpu_is_omap34xx()) 32362306a36Sopenharmony_ci omap34xx_sram_init(); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci return 0; 32662306a36Sopenharmony_ci} 327