424 lines
12 KiB
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
|
|
}
|
|
|
|
/** @} */
|