blob: 05f5a934f7a7dbbe8dd5766a5e21c9fdefe53399 [file] [log] [blame]
/*
* Copyright (c) 2017, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include "mpu_armv8m_drv.h"
#include "core_cm33.h"
/*
* FixMe:
* This is a beta quality driver for MPU in v8M. To be finalized and integrated
* into platform code
*/
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;
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 */
__asm("DSB");
__asm("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_ADDR_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 services 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_ADDR_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;
/*FIXME: Enable the memory attr setting */
limit_cfg |= MPU_RLAR_EN_Msk;
mpu->RLAR = limit_cfg;
/*Restore main MPU control*/
mpu->CTRL = ctrl_before;
/* Enable MPU before the next instruction */
__asm("DSB");
__asm("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;
}