| /* |
| * 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; |
| |
| } |