blob: b45338b4492c8eaa0d0e74a77d14036a264cd54a [file] [log] [blame]
/*
* Copyright (c) 2017-2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include "mpu_armv8m_drv.h"
#include "cmsis.h"
/*
* FixMe:
* This is a beta quality driver for MPU in v8M. To be finalized.
*/
enum mpu_armv8m_error_t mpu_armv8m_enable(struct mpu_armv8m_dev_t * dev, uint32_t privdef_en, uint32_t hfnmi_en)
{
/*No error checking*/
MPU_Type * mpu = (MPU_Type *) dev->base;
/*
* FixMe: Set 3 pre-defined MAIR_ATTR for memory. The attributes come
* from default memory map, need to check if fine-tune is necessary.
*
* MAIR0_0: Peripheral, Device-nGnRE.
* MAIR0_1: Code, WT RA. Same attr for Outer and Inner.
* MAIR0_2: SRAM, WBWA RA. Same attr for Outer and Inner.
*/
mpu->MAIR0 = (MPU_ARMV8M_MAIR_ATTR_DEVICE_VAL << MPU_MAIR0_Attr0_Pos) | (MPU_ARMV8M_MAIR_ATTR_CODE_VAL << MPU_MAIR0_Attr1_Pos) |
(MPU_ARMV8M_MAIR_ATTR_DATA_VAL << MPU_MAIR0_Attr2_Pos);
mpu->CTRL = (privdef_en ? MPU_CTRL_PRIVDEFENA_Msk : 0) | (hfnmi_en ? MPU_CTRL_HFNMIENA_Msk : 0);
/*Ensure all configuration is written before enable*/
mpu->CTRL |= MPU_CTRL_ENABLE_Msk;
/* Enable MPU before next instruction */
__DSB();
__ISB();
return MPU_ARMV8M_OK;
}
enum mpu_armv8m_error_t mpu_armv8m_disable(struct mpu_armv8m_dev_t * dev)
{
MPU_Type * mpu = (MPU_Type *) dev->base;
/* Reset all fields as enable does full setup */
mpu->CTRL = 0;
return MPU_ARMV8M_OK;
}
enum mpu_armv8m_error_t mpu_armv8m_region_enable(struct mpu_armv8m_dev_t * dev, struct mpu_armv8m_region_cfg_t * region_cfg)
{
MPU_Type * mpu = (MPU_Type *) dev->base;
enum mpu_armv8m_error_t ret_val = MPU_ARMV8M_OK;
uint32_t ctrl_before;
uint32_t base_cfg;
uint32_t limit_cfg;
/*FIXME : Add complete error checking*/
if ((region_cfg->region_base & ~MPU_RBAR_BASE_Msk) != 0)
{
return MPU_ARMV8M_ERROR;
}
/* region_limit doesn't need to be aligned but the scatter
* file needs to be setup to ensure that partitions do not overlap.
*/
ctrl_before = mpu->CTRL;
mpu->CTRL = 0;
mpu->RNR = region_cfg->region_nr & MPU_RNR_REGION_Msk;
/* This 0s the lower bits of the base address */
base_cfg = region_cfg->region_base & MPU_RBAR_BASE_Msk;
base_cfg |= (region_cfg->attr_sh << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk;
base_cfg |= (region_cfg->attr_access << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk;
base_cfg |= (region_cfg->attr_exec << MPU_RBAR_XN_Pos) & MPU_RBAR_XN_Msk;
mpu->RBAR = base_cfg;
/*This 0s the lower bits of base address but they are treated as 1 */
limit_cfg = (region_cfg->region_limit - 1) & MPU_RLAR_LIMIT_Msk;
limit_cfg |= (region_cfg->region_attridx << MPU_RLAR_AttrIndx_Pos) & MPU_RLAR_AttrIndx_Msk;
#ifdef TFM_PXN_ENABLE
limit_cfg |= (region_cfg->attr_pxn << MPU_RLAR_PXN_Pos) & MPU_RLAR_PXN_Msk;
#endif
limit_cfg |= MPU_RLAR_EN_Msk;
mpu->RLAR = limit_cfg;
/*Restore main MPU control*/
mpu->CTRL = ctrl_before;
/* Enable MPU before the next instruction */
__DSB();
__ISB();
return ret_val;
}
enum mpu_armv8m_error_t mpu_armv8m_region_disable(struct mpu_armv8m_dev_t * dev, uint32_t region_nr)
{
MPU_Type * mpu = (MPU_Type *) dev->base;
enum mpu_armv8m_error_t ret_val = MPU_ARMV8M_OK;
uint32_t ctrl_before;
/*FIXME : Add complete error checking*/
ctrl_before = mpu->CTRL;
mpu->CTRL = 0;
mpu->RNR = region_nr & MPU_RNR_REGION_Msk;
mpu->RBAR = 0;
mpu->RLAR = 0;
/*Restore main MPU control*/
mpu->CTRL = ctrl_before;
return ret_val;
}
enum mpu_armv8m_error_t mpu_armv8m_clean(struct mpu_armv8m_dev_t * dev)
{
MPU_Type * mpu = (MPU_Type *) dev->base;
uint32_t i = (mpu->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos;
while (i > 0)
{
mpu_armv8m_region_disable(dev, i - 1);
i--;
}
return MPU_ARMV8M_OK;
}