diff --git a/arch/arm/core/cortex_m/mpu/Kconfig b/arch/arm/core/cortex_m/mpu/Kconfig index 892a242adaf..cdc061075b5 100644 --- a/arch/arm/core/cortex_m/mpu/Kconfig +++ b/arch/arm/core/cortex_m/mpu/Kconfig @@ -13,3 +13,11 @@ config ARM_MPU default n help MCU has ARM MPU + +config NXP_MPU + bool "NXP MPU Support" + depends on CPU_HAS_MPU + depends on SOC_FAMILY_KINETIS + default n + help + MCU has NXP MPU diff --git a/arch/arm/core/cortex_m/mpu/Makefile b/arch/arm/core/cortex_m/mpu/Makefile index 2b08f730435..69556bc0147 100644 --- a/arch/arm/core/cortex_m/mpu/Makefile +++ b/arch/arm/core/cortex_m/mpu/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_ARM_MPU) += arm_mpu.o +obj-$(CONFIG_NXP_MPU) += nxp_mpu.o diff --git a/arch/arm/core/cortex_m/mpu/nxp_mpu.c b/arch/arm/core/cortex_m/mpu/nxp_mpu.c new file mode 100644 index 00000000000..eb472e582ca --- /dev/null +++ b/arch/arm/core/cortex_m/mpu/nxp_mpu.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2017 Linaro Limited. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static inline u8_t _get_num_regions(void) +{ + u32_t type = (SYSMPU->CESR & SYSMPU_CESR_NRGD_MASK) + >> SYSMPU_CESR_NRGD_SHIFT; + + switch (type) { + case 0: + return 8; + case 1: + return 12; + case 2: + return 16; + default: + __ASSERT(0, "Unsupported MPU configuration."); + return 0; + } + + return NXP_MPU_REGION_NUMBER; +} + +static void _region_init(u32_t index, u32_t region_base, + u32_t region_end, u32_t region_attr) +{ + SYSMPU->WORD[index][0] = region_base; + SYSMPU->WORD[index][1] = region_end; + SYSMPU->WORD[index][2] = region_attr; + SYSMPU->WORD[index][3] = SYSMPU_WORD_VLD_MASK; + + SYS_LOG_DBG("[%d] 0x%08x 0x%08x 0x%08x 0x%08x", index, + SYSMPU->WORD[index][0], + SYSMPU->WORD[index][1], + SYSMPU->WORD[index][2], + SYSMPU->WORD[index][3]); +} + +/* + * @brief MPU default configuration + * + * This function provides the default configuration mechanism for the Memory + * Protection Unit (MPU). + */ +static void _nxp_mpu_config(void) +{ + u32_t r_index; + + SYS_LOG_DBG("region number: %d", _get_num_regions()); + + /* NXP MPU supports up to 16 Regions */ + if (mpu_config.num_regions > _get_num_regions()) { + return; + } + + /* Disable MPU */ + SYSMPU->CESR &= ~SYSMPU_CESR_VLD_MASK; + /* Clear Interrupts */ + SYSMPU->CESR |= SYSMPU_CESR_SPERR_MASK; + + /* MPU Configuration */ + + /* Disable Region 0 */ + SYSMPU->WORD[0][2] = 0; + + /* + * Configure regions: + * r_index starts from 0 but is passed to region_init as r_index + 1, + * region 0 is not configurable + */ + for (r_index = 0; r_index < mpu_config.num_regions; r_index++) { + _region_init(r_index + 1, + mpu_config.mpu_regions[r_index].base, + mpu_config.mpu_regions[r_index].end, + mpu_config.mpu_regions[r_index].attr); + } + + /* Enable MPU */ + SYSMPU->CESR |= SYSMPU_CESR_VLD_MASK; + + /* Make sure that all the registers are set before proceeding */ + __DSB(); + __ISB(); +} + +/* + * @brief MPU clock configuration + * + * This function provides the clock configuration for the Memory Protection + * Unit (MPU). + */ +static void _nxp_mpu_clock_cfg(void) +{ + /* Enable Clock */ + CLOCK_EnableClock(kCLOCK_Sysmpu0); +} + +static int nxp_mpu_init(struct device *arg) +{ + ARG_UNUSED(arg); + + _nxp_mpu_clock_cfg(); + + _nxp_mpu_config(); + + return 0; +} + +#if defined(CONFIG_SYS_LOG) +/* To have logging the driver needs to be initialized later */ +SYS_INIT(nxp_mpu_init, POST_KERNEL, + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +#else +SYS_INIT(nxp_mpu_init, PRE_KERNEL_1, + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +#endif diff --git a/arch/arm/soc/nxp_kinetis/Kconfig b/arch/arm/soc/nxp_kinetis/Kconfig index ceb58e7d9ef..f74c8a5f477 100644 --- a/arch/arm/soc/nxp_kinetis/Kconfig +++ b/arch/arm/soc/nxp_kinetis/Kconfig @@ -64,6 +64,14 @@ config HAS_LPSCI help Set if the low power uart (LPSCI) module is present in the SoC. +config HAS_SYSMPU + bool "Enable MPU" + depends on CPU_HAS_MPU + select NXP_MPU + default n + help + Enable MPU + if HAS_OSC choice diff --git a/arch/arm/soc/nxp_kinetis/k6x/Kconfig.series b/arch/arm/soc/nxp_kinetis/k6x/Kconfig.series index 8b01a2175d9..273560d9224 100644 --- a/arch/arm/soc/nxp_kinetis/k6x/Kconfig.series +++ b/arch/arm/soc/nxp_kinetis/k6x/Kconfig.series @@ -12,5 +12,6 @@ config SOC_SERIES_KINETIS_K6X select SOC_FAMILY_KINETIS select SYS_POWER_LOW_POWER_STATE_SUPPORTED select CPU_HAS_SYSTICK + select CPU_HAS_MPU help Enable support for Kinetis K6x MCU series diff --git a/arch/arm/soc/nxp_kinetis/k6x/Makefile b/arch/arm/soc/nxp_kinetis/k6x/Makefile index 5a808ab1e36..0dd63afaa34 100644 --- a/arch/arm/soc/nxp_kinetis/k6x/Makefile +++ b/arch/arm/soc/nxp_kinetis/k6x/Makefile @@ -1,2 +1,3 @@ obj-y += soc.o obj-y += wdog.o +obj-$(CONFIG_HAS_SYSMPU) += nxp_mpu_regions.o diff --git a/arch/arm/soc/nxp_kinetis/k6x/nxp_mpu_regions.c b/arch/arm/soc/nxp_kinetis/k6x/nxp_mpu_regions.c new file mode 100644 index 00000000000..72da4a6ea62 --- /dev/null +++ b/arch/arm/soc/nxp_kinetis/k6x/nxp_mpu_regions.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2017 Linaro Limited. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include + +#define FLEXBUS_BASE_ADDRESS 0x08000000 +#define SRAM_L_BASE_ADDRESS 0x1FFF0000 +#define DEVICE_S_BASE_ADDRESS 0x20030000 + +static struct nxp_mpu_region mpu_regions[] = { + /* Region 0 */ + MPU_REGION_ENTRY("FLASH_0", + CONFIG_FLASH_BASE_ADDRESS, + 0x07FFFFFF, + REGION_FLASH_ATTR), + /* Region 1 */ + /* + * This region (Flexbus + FlexNVM) is bigger than the FLEXBUS one in + * order to save 1 region allocation in the MPU. + */ + MPU_REGION_ENTRY("FLEXBUS_0", + FLEXBUS_BASE_ADDRESS, + 0x1BFFFFFF, + REGION_IO_ATTR), + /* Region 2 */ + MPU_REGION_ENTRY("RAM_L_0", + SRAM_L_BASE_ADDRESS, + 0x1FFFFFFF, + REGION_RAM_ATTR), + /* Region 3 */ + MPU_REGION_ENTRY("RAM_U_0", + CONFIG_SRAM_BASE_ADDRESS, + (CONFIG_SRAM_BASE_ADDRESS + + (CONFIG_SRAM_SIZE * 1024) - 1), + REGION_RAM_ATTR), + /* Region 4 */ + MPU_REGION_ENTRY("DEVICE_0", + DEVICE_S_BASE_ADDRESS, + 0xFFFFFFFF, + REGION_IO_ATTR), +}; + +struct nxp_mpu_config mpu_config = { + .num_regions = ARRAY_SIZE(mpu_regions), + .mpu_regions = mpu_regions, +}; diff --git a/arch/arm/soc/nxp_kinetis/k6x/soc.c b/arch/arm/soc/nxp_kinetis/k6x/soc.c index 9a612b6653c..7248bf112d6 100644 --- a/arch/arm/soc/nxp_kinetis/k6x/soc.c +++ b/arch/arm/soc/nxp_kinetis/k6x/soc.c @@ -153,7 +153,9 @@ static int fsl_frdm_k64f_init(struct device *arg) ARG_UNUSED(arg); int oldLevel; /* old interrupt lock level */ +#if !defined(CONFIG_HAS_SYSMPU) u32_t temp_reg; +#endif /* !CONFIG_HAS_SYSMPU */ /* disable interrupts */ oldLevel = irq_lock(); @@ -161,6 +163,7 @@ static int fsl_frdm_k64f_init(struct device *arg) /* release I/O power hold to allow normal run state */ PMC->REGSC |= PMC_REGSC_ACKISO_MASK; +#if !defined(CONFIG_HAS_SYSMPU) /* * Disable memory protection and clear slave port errors. * Note that the K64F does not implement the optional ARMv7-M memory @@ -171,6 +174,7 @@ static int fsl_frdm_k64f_init(struct device *arg) temp_reg &= ~SYSMPU_CESR_VLD_MASK; temp_reg |= SYSMPU_CESR_SPERR_MASK; SYSMPU->CESR = temp_reg; +#endif /* !CONFIG_HAS_SYSMPU */ _ClearFaults(); diff --git a/boards/arm/frdm_k64f/frdm_k64f_defconfig b/boards/arm/frdm_k64f/frdm_k64f_defconfig index 6c1d8a7f91d..93bd45e2b2a 100644 --- a/boards/arm/frdm_k64f/frdm_k64f_defconfig +++ b/boards/arm/frdm_k64f/frdm_k64f_defconfig @@ -9,3 +9,6 @@ CONFIG_CORTEX_M_SYSTICK=y CONFIG_GPIO=y CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=120000000 CONFIG_OSC_EXTERNAL=y + +# Enable MPU +CONFIG_HAS_SYSMPU=y diff --git a/include/arch/arm/cortex_m/mpu/nxp_mpu.h b/include/arch/arm/cortex_m/mpu/nxp_mpu.h new file mode 100644 index 00000000000..cd163ac7cca --- /dev/null +++ b/include/arch/arm/cortex_m/mpu/nxp_mpu.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2017 Linaro Limited. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef _NXP_MPU_H_ +#define _NXP_MPU_H_ + +#include + +#define NXP_MPU_BASE SYSMPU_BASE + +#define NXP_MPU_REGION_NUMBER 12 + +/* Read Attribute */ +#define MPU_REGION_READ ((1 << 2) | (1 << 8) | (1 << 14)) + +/* Write Attribute */ +#define MPU_REGION_WRITE ((1 << 1) | (1 << 7) | (1 << 13)) + +/* Execute Attribute */ +#define MPU_REGION_EXEC ((1 << 0) | (1 << 6) | (1 << 12)) + +/* Super User Attributes */ +#define MPU_REGION_SU ((3 << 3) | (3 << 9) | (3 << 15) | (3 << 21)) + +/* Some helper defines for common regions */ +#define REGION_RAM_ATTR (MPU_REGION_READ | MPU_REGION_WRITE | MPU_REGION_SU) +#define REGION_FLASH_ATTR (MPU_REGION_READ | MPU_REGION_EXEC | MPU_REGION_SU) +#define REGION_IO_ATTR (MPU_REGION_READ | MPU_REGION_WRITE | \ + MPU_REGION_EXEC | MPU_REGION_SU) + +/* Region definition data structure */ +struct nxp_mpu_region { + /* Region Base Address */ + u32_t base; + /* Region End Address */ + u32_t end; + /* Region Name */ + const char *name; + /* Region Attributes */ + u32_t attr; +}; + +#define MPU_REGION_ENTRY(_name, _base, _end, _attr) \ + {\ + .name = _name, \ + .base = _base, \ + .end = _end, \ + .attr = _attr, \ + } + +/* MPU configuration data structure */ +struct nxp_mpu_config { + /* Number of regions */ + u32_t num_regions; + /* Regions */ + struct nxp_mpu_region *mpu_regions; +}; + +/* Reference to the MPU configuration */ +extern struct nxp_mpu_config mpu_config; + +#endif /* _NXP_MPU_H_ */