Linux Audio

Check our new training course

Loading...
/*
 * Copyright (c) 2017 Linaro Limited.
 *
 * SPDX-License-Identifier: Apache-2.0
 */
#ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_MPU_NXP_MPU_H_
#define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_MPU_NXP_MPU_H_

#ifndef _ASMLANGUAGE

#include <fsl_common.h>

#define NXP_MPU_BASE SYSMPU_BASE

#define NXP_MPU_REGION_NUMBER 12

/* Bus Master User Mode Access */
#define UM_READ		4
#define UM_WRITE	2
#define UM_EXEC		1

#define BM0_UM_SHIFT	0
#define BM1_UM_SHIFT	6
#define BM2_UM_SHIFT	12
#define BM3_UM_SHIFT	18

/* Bus Master Supervisor Mode Access */
#define SM_RWX_ALLOW	0
#define SM_RX_ALLOW	1
#define SM_RW_ALLOW	2
#define SM_SAME_AS_UM	3

#define BM0_SM_SHIFT	3
#define BM1_SM_SHIFT	9
#define BM2_SM_SHIFT	15
#define BM3_SM_SHIFT	21

#define BM4_WE_SHIFT	24
#define BM4_RE_SHIFT	25

#ifdef CONFIG_USB_KINETIS
#define BM4_PERMISSIONS	((1 << BM4_RE_SHIFT) | (1 << BM4_WE_SHIFT))
#else
#define BM4_PERMISSIONS	0
#endif

/* Read Attribute */
#define MPU_REGION_READ  ((UM_READ << BM0_UM_SHIFT) | \
			  (UM_READ << BM1_UM_SHIFT) | \
			  (UM_READ << BM2_UM_SHIFT) | \
			  (UM_READ << BM3_UM_SHIFT))

/* Write Attribute */
#define MPU_REGION_WRITE ((UM_WRITE << BM0_UM_SHIFT) | \
			  (UM_WRITE << BM1_UM_SHIFT) | \
			  (UM_WRITE << BM2_UM_SHIFT) | \
			  (UM_WRITE << BM3_UM_SHIFT))

/* Execute Attribute */
#define MPU_REGION_EXEC  ((UM_EXEC << BM0_UM_SHIFT) | \
			  (UM_EXEC << BM1_UM_SHIFT) | \
			  (UM_EXEC << BM2_UM_SHIFT) | \
			  (UM_EXEC << BM3_UM_SHIFT))

/* Super User Attributes */
#define MPU_REGION_SU	 ((SM_SAME_AS_UM << BM0_SM_SHIFT) | \
			  (SM_SAME_AS_UM << BM1_SM_SHIFT) | \
			  (SM_SAME_AS_UM << BM2_SM_SHIFT) | \
			  (SM_SAME_AS_UM << BM3_SM_SHIFT))

#define MPU_REGION_SU_RX ((SM_RX_ALLOW << BM0_SM_SHIFT) | \
			  (SM_RX_ALLOW << BM1_SM_SHIFT) | \
			  (SM_RX_ALLOW << BM2_SM_SHIFT) | \
			  (SM_RX_ALLOW << BM3_SM_SHIFT))

#define MPU_REGION_SU_RW ((SM_RW_ALLOW << BM0_SM_SHIFT) | \
			  (SM_RW_ALLOW << BM1_SM_SHIFT) | \
			  (SM_RW_ALLOW << BM2_SM_SHIFT) | \
			  (SM_RW_ALLOW << BM3_SM_SHIFT))

#define MPU_REGION_SU_RWX ((SM_RWX_ALLOW << BM0_SM_SHIFT) | \
			   (SM_RWX_ALLOW << BM1_SM_SHIFT) | \
			   (SM_RWX_ALLOW << BM2_SM_SHIFT) | \
			   (SM_RWX_ALLOW << BM3_SM_SHIFT))

/* The ENDADDR field has the last 5 bit reserved and set to 1 */
#define ENDADDR_ROUND(x) (x - 0x1F)

#define REGION_USER_MODE_ATTR {(MPU_REGION_READ | \
				MPU_REGION_WRITE | \
				MPU_REGION_SU)}

/* Some helper defines for common regions */
#if defined(CONFIG_MPU_ALLOW_FLASH_WRITE)
#define REGION_RAM_ATTR	  {((MPU_REGION_SU_RWX) | \
			   ((UM_READ | UM_WRITE | UM_EXEC) << BM3_UM_SHIFT) | \
			   (BM4_PERMISSIONS))}

#define REGION_FLASH_ATTR {(MPU_REGION_SU_RWX)}

#else
#define REGION_RAM_ATTR	  {((MPU_REGION_SU_RW) | \
			   ((UM_READ | UM_WRITE) << BM3_UM_SHIFT) | \
			   (BM4_PERMISSIONS))}

#define REGION_FLASH_ATTR {(MPU_REGION_READ | \
			   MPU_REGION_EXEC | \
			   MPU_REGION_SU)}
#endif

#define REGION_IO_ATTR	  {(MPU_REGION_READ | \
			   MPU_REGION_WRITE | \
			   MPU_REGION_EXEC | \
			   MPU_REGION_SU)}

#define REGION_RO_ATTR	  {(MPU_REGION_READ | MPU_REGION_SU)}

#define REGION_USER_RO_ATTR {(MPU_REGION_READ | \
			     MPU_REGION_SU)}

/* ENET device (Master 3) will not be able to access RAM when
ram region is dynamically disabled in NXP MPU.
DEBUGGER (Master 1) can't be disabled in Region 0. */
#define REGION_DEBUGGER_AND_DEVICE_ATTR  {((MPU_REGION_SU) | \
				((UM_READ | UM_WRITE) << BM3_UM_SHIFT))}

#define REGION_DEBUG_ATTR  {MPU_REGION_SU}

#define REGION_BACKGROUND_ATTR	{MPU_REGION_SU_RW}

struct nxp_mpu_region_attr {
	/* NXP MPU region access permission attributes */
	u32_t attr;
};

typedef struct nxp_mpu_region_attr nxp_mpu_region_attr_t;

/* Typedef for the k_mem_partition attribute*/
typedef struct {
	u32_t ap_attr;
} k_mem_partition_attr_t;

/* Kernel macros for memory attribution
 * (access permissions and cache-ability).
 *
 * The macros are to be stored in k_mem_partition_attr_t
 * objects.
 */

/* Read-Write access permission attributes */
#define K_MEM_PARTITION_P_NA_U_NA	((k_mem_partition_attr_t) \
	{(MPU_REGION_SU)})
#define K_MEM_PARTITION_P_RW_U_RW	((k_mem_partition_attr_t) \
	{(MPU_REGION_READ | MPU_REGION_WRITE | MPU_REGION_SU)})
#define K_MEM_PARTITION_P_RW_U_RO	((k_mem_partition_attr_t) \
	{(MPU_REGION_READ | MPU_REGION_SU_RW)})
#define K_MEM_PARTITION_P_RW_U_NA	((k_mem_partition_attr_t) \
	{(MPU_REGION_SU_RW)})
#define K_MEM_PARTITION_P_RO_U_RO	((k_mem_partition_attr_t) \
	{(MPU_REGION_READ | MPU_REGION_SU)})
#define K_MEM_PARTITION_P_RO_U_NA	((k_mem_partition_attr_t) \
	{(MPU_REGION_SU_RX)})

/* Execution-allowed attributes */
#define K_MEM_PARTITION_P_RWX_U_RWX	((k_mem_partition_attr_t) \
	{(MPU_REGION_READ | MPU_REGION_WRITE | \
	  MPU_REGION_EXEC | MPU_REGION_SU)})
#define K_MEM_PARTITION_P_RWX_U_RX	((k_mem_partition_attr_t) \
	{(MPU_REGION_READ | MPU_REGION_EXEC | MPU_REGION_SU_RWX)})
#define K_MEM_PARTITION_P_RX_U_RX	((k_mem_partition_attr_t) \
	{(MPU_REGION_READ | MPU_REGION_EXEC | MPU_REGION_SU)})

/*
 * @brief Evaluate Write-ability
 *
 * Evaluate whether the access permissions include write-ability.
 *
 * @param attr The k_mem_partition_attr_t object holding the
 *             MPU attributes to be checked against write-ability.
 */
#define K_MEM_PARTITION_IS_WRITABLE(attr) \
	({ \
		int __is_writable__; \
		switch (attr.ap_attr) { \
		case MPU_REGION_WRITE: \
		case MPU_REGION_SU_RW: \
			__is_writable__ = 1; \
			break; \
		default: \
			__is_writable__ = 0; \
		} \
		__is_writable__; \
	})

/*
 * @brief Evaluate Execution allowance
 *
 * Evaluate whether the access permissions include execution.
 *
 * @param attr The k_mem_partition_attr_t object holding the
 *             MPU attributes to be checked against execution
 *             allowance.
 */
#define K_MEM_PARTITION_IS_EXECUTABLE(attr) \
	({ \
		int __is_executable__; \
		switch (attr.ap_attr) { \
		case MPU_REGION_SU_RX: \
		case MPU_REGION_EXEC: \
			__is_executable__ = 1; \
			break; \
		default: \
			__is_executable__ = 0; \
		} \
		__is_executable__; \
	})


/* 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 */
	nxp_mpu_region_attr_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 */
	const struct nxp_mpu_region *mpu_regions;
	/* SRAM Region */
	u32_t sram_region;
};

/* Reference to the MPU configuration.
 *
 * This struct is defined and populated for each SoC (in the SoC definition),
 * and holds the build-time configuration information for the fixed MPU
 * regions enabled during kernel initialization. Dynamic MPU regions (e.g.
 * for Thread Stack, Stack Guards, etc.) are programmed during runtime, thus,
 * not kept here.
 */
extern const struct nxp_mpu_config mpu_config;

#endif /* _ASMLANGUAGE */

#define _ARCH_MEM_PARTITION_ALIGN_CHECK(start, size) \
	BUILD_ASSERT_MSG((size) % \
		CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE == 0 && \
		(size) >= CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE && \
		(u32_t)(start) % CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE == 0, \
		"the size of the partition must align with minimum MPU \
		 region size" \
		" and greater than or equal to minimum MPU region size." \
		"start address of the partition must align with minimum MPU \
		 region size.")

#endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_MPU_NXP_MPU_H_ */