/* ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio. This file is part of ChibiOS. ChibiOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. ChibiOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /** * @file mmu.c * @brief MMU code. * * @addtogroup MMU * @{ */ #include #include #include #include "mmu.h" #include "armparams.h" #include "mcuconf.h" #include "ARMCA5.h" #if defined(__GNUC__) || defined(__DOXYGEN__) #include "cmsis_gcc.h" #else #include "cmsis_armcc.h" #endif #include "ccportab.h" #if !defined(SAMA_L2CC_ASSUME_ENABLED) #define SAMA_L2CC_ASSUME_ENABLED 0 #endif #if !defined(SAMA_L2CC_ENABLE) #define SAMA_L2CC_ENABLE 0 #endif #if (SAMA_L2CC_ASSUME_ENABLED && SAMA_L2CC_ENABLE) #error "These macros are mutually exclusive" #endif /*===========================================================================*/ /* Module local definitions. */ /*===========================================================================*/ /* * @brief No cacheable memory start address. */ #define NO_CACHE_MEMORY_START_ADDR ((uint8_t *) 0x26F00000) /*===========================================================================*/ /* Module exported variables. */ /*===========================================================================*/ /*===========================================================================*/ /* Module local types. */ /*===========================================================================*/ /*===========================================================================*/ /* Module local variables. */ /*===========================================================================*/ /* * Use 1MB granularity. It best fits the SAMA5D2 memory layout. * * The MMU table contains 4096 entries. * Each entry in the mmu table (short descriptor, type 1MB section) is 32 bit wide (total 16kB), * and is structured in this way (with examples): * * +---------+--+-+--+-+-----+--------+-------+-+------+--+-+-+-+---+ * |3 2|1 |1|1 |1|1 |1 1|1 1| | | | | | | | * |1 0|9 |8|7 |6|5 |4 2|1 0|9|8 5|4 |3|2|1|0 | * +---------+--+-+--+-+-----+--------+-------+-+------+--+-+-+-+---+ * | section |NS|0|nG|S|AP[2]|TEX[2:0]|AP[1:0]| |domain|XN|C|B|1|PXN| * +---------+--+-+--+-+-----+--------+-------+-+------+--+-+-+-+---+ * | |X |0|0 |0|0 |111 |11 |0|0000 |0 |1|1|1|0 | == normal, cacheable, write back, no write allocate * | |0 |0|0 |1|0 |100 |11 |0|0000 |0 |0|0|1|0 | == normal, no-cacheable * | |0 |0|0 |1|0 |000 |11 |0|0000 |0 |0|1|1|0 | == device * | |0 |0|0 |1|0 |000 |11 |0|0000 |0 |0|0|1|0 | == strongly-ordered * | |0 |0|0 |0|0 |000 |00 |0|0000 |0 |0|0|0|0 | == undefined * * Domains are 'client'. Accesses are checked against the permission bits in tlb. */ static uint32_t mmuTable[4096] CC_ALIGN(16384); /*===========================================================================*/ /* Module local functions. */ /*===========================================================================*/ /*===========================================================================*/ /* Module exported functions. */ /*===========================================================================*/ /** * @brief Core/MMU Module initialization. * @note This function is implicitly invoked on system initialization, * there is no need to explicitly initialize the module. * * @notapi */ void __core_init(void) { uint32_t pm; #if ARM_SUPPORTS_L2CC #if !SAMA_L2CC_ASSUME_ENABLED /* Flush and disable an enabled L2 Cache invalidate a disabled L2 Cache.*/ if ((L2C_310->CONTROL & L2CC_CR_L2CEN) != 0) { L2C_Disable(); L2C_CleanInvAllByWay(); } #endif #endif /* Flush and disable an enabled L1 D Cache Invalidate a disabled L1 D Cache.*/ pm = __get_SCTLR(); if ((pm & SCTLR_C_Msk)) { L1C_DisableCaches(); L1C_CleanInvalidateCache(DCISW_CLEAN); } /* Disable the MMU and invalidate TLB.*/ MMU_Disable(); L1C_InvalidateBTAC(); MMU_InvalidateTLB(); /* * Default, undefined regions */ for (pm = 0; pm < 4096; ++pm) mmuTable[pm] = TTE_SECT_UNDEF; /* * ROM region * * 0x00000000 */ mmuTable[0] = TTE_SECT_SECTION(0x00000000) | TTE_SECT_MEM_NO_CACHEABLE | TTE_SECT_RO_ACCESS | TTE_SECT_DOM(0x00) | TTE_SECT_S | TTE_TYPE_SECT; /* * NFC SRAM region * * 0x00100000 */ mmuTable[1] = TTE_SECT_SECTION(0x00100000) | TTE_SECT_DEVICE | TTE_SECT_RW_ACCESS | TTE_SECT_DOM(0x00) | TTE_SECT_S | TTE_TYPE_SECT; /* * SRAM region * * 0x00200000 */ mmuTable[2] = TTE_SECT_SECTION(0x00200000) | TTE_SECT_MEM_CACHEABLE | TTE_SECT_RW_ACCESS | TTE_SECT_DOM(0x00) | TTE_TYPE_SECT; /* * UDPHS RAM region * * 0x00300000 */ mmuTable[3] = TTE_SECT_SECTION(0x00300000) | TTE_SECT_DEVICE | TTE_SECT_RW_ACCESS | TTE_SECT_DOM(0x00) | TTE_SECT_EXE_NEVER | TTE_SECT_S | TTE_TYPE_SECT; /* * UHPHS region * * 0x00400000 */ mmuTable[4] = TTE_SECT_SECTION(0x00400000) | TTE_SECT_DEVICE | TTE_SECT_RW_ACCESS | TTE_SECT_DOM(0x00) | TTE_SECT_EXE_NEVER | TTE_SECT_S | TTE_TYPE_SECT; /* * UDPHS region * * 0x00500000 */ mmuTable[5] = TTE_SECT_SECTION(0x00500000) | TTE_SECT_DEVICE | TTE_SECT_RW_ACCESS | TTE_SECT_DOM(0x00) | TTE_SECT_EXE_NEVER | TTE_SECT_S | TTE_TYPE_SECT; /* * AXIMX region * * 0x00600000 */ mmuTable[6] = TTE_SECT_SECTION(0x00600000) | TTE_SECT_DEVICE | TTE_SECT_RW_ACCESS | TTE_SECT_DOM(0x00) | TTE_SECT_EXE_NEVER | TTE_SECT_S | TTE_TYPE_SECT; /* * DAP region * * 0x00700000 */ mmuTable[7] = TTE_SECT_SECTION(0x00700000) | TTE_SECT_DEVICE | TTE_SECT_RW_ACCESS | TTE_SECT_DOM(0x00) | TTE_SECT_EXE_NEVER | TTE_SECT_S | TTE_TYPE_SECT; /* * L2CC region, low * * 0x00a00000 */ mmuTable[0xa] = TTE_SECT_SECTION(0x00a00000) | TTE_SECT_DEVICE | TTE_SECT_RW_ACCESS | TTE_SECT_DOM(0x00) | TTE_SECT_EXE_NEVER | TTE_SECT_S | TTE_TYPE_SECT; /* * L2CC region, hi * * 0x00b00000 */ mmuTable[0xb] = TTE_SECT_SECTION(0x00b00000) | TTE_SECT_DEVICE | TTE_SECT_RW_ACCESS | TTE_SECT_DOM(0x00) | TTE_SECT_EXE_NEVER | TTE_SECT_S | TTE_TYPE_SECT; /* * EBI regions * * 0x10000000 - 0x1fffffff */ for (pm = 0x100; pm < 0x200; pm++) mmuTable[pm] = TTE_SECT_SECTION(pm << 20) | TTE_SECT_MEM_STRONGLY_ORD | TTE_SECT_RW_ACCESS | TTE_SECT_DOM(0x00) | TTE_SECT_EXE_NEVER | TTE_SECT_S | TTE_TYPE_SECT; /* * DDR regions * * 0x20000000 - 0x3fffffff */ for (pm = 0x200; pm < 0x400; pm++) mmuTable[pm] = TTE_SECT_SECTION(pm << 20) | TTE_SECT_MEM_CACHEABLE | TTE_SECT_RW_ACCESS | TTE_SECT_DOM(0x00) | TTE_TYPE_SECT; /* * DDR AESB regions * * 0x40000000 - 0x5fffffff */ for (pm = 0x400; pm < 0x600; pm++) mmuTable[pm] = TTE_SECT_SECTION(pm << 20) | TTE_SECT_MEM_CACHEABLE | TTE_SECT_RW_ACCESS | TTE_SECT_DOM(0x00) | TTE_TYPE_SECT; /* * EBI 1, 2 and 3 regions * * 0x60000000 - 0x8fffffff */ for (pm = 0x600; pm < 0x900; pm++) mmuTable[pm] = TTE_SECT_SECTION(pm << 20) | TTE_SECT_MEM_STRONGLY_ORD | TTE_SECT_RW_ACCESS | TTE_SECT_DOM(0x00) | TTE_SECT_S | TTE_TYPE_SECT; /* * QSPI0/1 AESB MEM regions * * 0x90000000 - 0x9fffffff */ for (pm = 0x900; pm < 0xa00; pm++) mmuTable[pm] = TTE_SECT_SECTION(pm << 20) | TTE_SECT_MEM_STRONGLY_ORD | TTE_SECT_RW_ACCESS | TTE_SECT_DOM(0x00) | TTE_SECT_S | TTE_TYPE_SECT; /* * SDMMC0/1 regions * * 0xa0000000 - 0xbfffffff */ for (pm = 0xa00; pm < 0xc00; pm++) mmuTable[pm] = TTE_SECT_SECTION(pm << 20) | TTE_SECT_MEM_STRONGLY_ORD | TTE_SECT_RW_ACCESS | TTE_SECT_DOM(0x00) | TTE_SECT_EXE_NEVER | TTE_TYPE_SECT; /* * NFC regions * * 0xc0000000 - 0xcfffffff */ for (pm = 0xc00; pm < 0xd00; pm++) mmuTable[pm] = TTE_SECT_SECTION(pm << 20) | TTE_SECT_MEM_STRONGLY_ORD | TTE_SECT_RW_ACCESS | TTE_SECT_DOM(0x00) | TTE_SECT_EXE_NEVER | TTE_SECT_S | TTE_TYPE_SECT; /* * QSPI0/1 MEM regions * * 0xd0000000 - 0xdfffffff */ for (pm = 0xd00; pm < 0xe00; pm++) mmuTable[pm] = TTE_SECT_SECTION(pm << 20) | TTE_SECT_MEM_STRONGLY_ORD | TTE_SECT_RW_ACCESS | TTE_SECT_DOM(0x00) | TTE_SECT_S | TTE_TYPE_SECT; /* * Internal peripherals regions * * 0xf0000000 * 0xf8000000 * 0xfc000000 */ mmuTable[0xf00] = TTE_SECT_SECTION(0xf0000000) | TTE_SECT_DEVICE | TTE_SECT_RW_ACCESS | TTE_SECT_DOM(0x00) | TTE_SECT_EXE_NEVER | TTE_SECT_S | TTE_TYPE_SECT; mmuTable[0xf80] = TTE_SECT_SECTION(0xf8000000) | TTE_SECT_DEVICE | TTE_SECT_RW_ACCESS | TTE_SECT_DOM(0x00) | TTE_SECT_EXE_NEVER | TTE_SECT_S | TTE_TYPE_SECT; mmuTable[0xfc0] = TTE_SECT_SECTION(0xfc000000) | TTE_SECT_DEVICE | TTE_SECT_RW_ACCESS | TTE_SECT_DOM(0x00) | TTE_SECT_EXE_NEVER | TTE_SECT_S | TTE_TYPE_SECT; /* Make a NO CACHE AREA */ MMU_MemorySection((mmuTable + ((uint32_t)NO_CACHE_MEMORY_START_ADDR >> 20)), NORMAL, NON_CACHEABLE, NON_CACHEABLE); /* Invalidate TLB and L1 I cache Enable caches and MMU.*/ MMU_InvalidateTLB(); __set_TTBR0((uint32_t)mmuTable|0x5B); __set_DACR(0x00000001); __DSB(); __ISB(); /* L1 I cache invalidate and enable.*/ pm = __get_SCTLR(); if ((pm & SCTLR_I_Msk) == 0) { __set_ICIALLU(0); __set_SCTLR(pm | SCTLR_I_Msk); } /* MMU enable.*/ pm = __get_SCTLR(); if ((pm & SCTLR_M_Msk) == 0) __set_SCTLR(pm | SCTLR_M_Msk); /* L1 D cache enable.*/ pm = __get_SCTLR(); if ((pm & SCTLR_C_Msk) == 0) { L1C_CleanInvalidateCache(DCISW_INVALIDATE); __set_SCTLR(pm | SCTLR_C_Msk); } #if ARM_SUPPORTS_L2CC #if !(SAMA_L2CC_ASSUME_ENABLED) && (SAMA_L2CC_ENABLE) if (!(L2C_310->CONTROL & L2CC_CR_L2CEN)) { /* High SRAM to L2CC.*/ SFR->SFR_L2CC_HRAMC = 0x1; /* Invalidate and enable L2 cache.*/ L2C_InvAllByWay(); L2C_310->AUX_CNT = L2CC_ACR_DPEN | L2CC_ACR_IPEN; /* Prefetch control register. Double linefeed, instr and data enabled.*/ *((uint32_t *)((char *)L2C_310+0x0F60)) = 0x75800001; L2C_Enable(); __DSB(); __ISB(); } #endif #endif } /** @} */