QMK/lib/chibios/os/common/startup/ARM/devices/SAMA5D2/mmu.c

424 lines
12 KiB
C

/*
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 <http://www.gnu.org/licenses/>.
*/
/**
* @file mmu.c
* @brief MMU code.
*
* @addtogroup MMU
* @{
*/
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#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
}
/** @} */