1 /*
2 * Copyright (c) 2017-2024, Arm Limited. All rights reserved.
3 * Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon
4 * company) or an affiliate of Cypress Semiconductor Corporation. All rights
5 * reserved.
6 *
7 * SPDX-License-Identifier: BSD-3-Clause
8 *
9 */
10
11 #include "mpu_armv8m_drv.h"
12 #include "tfm_hal_device_header.h"
13
14 /*
15 * FixMe:
16 * This is a beta quality driver for MPU in v8M. To be finalized.
17 */
mpu_armv8m_enable(struct mpu_armv8m_dev_t * dev,uint32_t privdef_en,uint32_t hfnmi_en)18 FIH_RET_TYPE(enum mpu_armv8m_error_t) mpu_armv8m_enable(
19 struct mpu_armv8m_dev_t *dev,
20 uint32_t privdef_en,
21 uint32_t hfnmi_en)
22 {
23 /*No error checking*/
24
25 MPU_Type *mpu = (MPU_Type *)dev->base;
26
27 /*
28 * FixMe: Set 3 pre-defined MAIR_ATTR for memory. The attributes come
29 * from default memory map, need to check if fine-tune is necessary.
30 *
31 * MAIR0_0: Peripheral, Device-nGnRE.
32 * MAIR0_1: Code, WT RA. Same attr for Outer and Inner.
33 * MAIR0_2: SRAM, WBWA RA. Same attr for Outer and Inner.
34 */
35 mpu->MAIR0 = (MPU_ARMV8M_MAIR_ATTR_DEVICE_VAL << MPU_MAIR0_Attr0_Pos) |
36 (MPU_ARMV8M_MAIR_ATTR_CODE_VAL << MPU_MAIR0_Attr1_Pos) |
37 (MPU_ARMV8M_MAIR_ATTR_DATA_VAL << MPU_MAIR0_Attr2_Pos);
38
39 mpu->CTRL =
40 (privdef_en ? MPU_CTRL_PRIVDEFENA_Msk : 0) |
41 (hfnmi_en ? MPU_CTRL_HFNMIENA_Msk : 0);
42
43 /*Ensure all configuration is written before enable*/
44
45 mpu->CTRL |= MPU_CTRL_ENABLE_Msk;
46
47 /* Enable MPU before next instruction */
48 __DSB();
49 __ISB();
50
51 FIH_RET(fih_int_encode(MPU_ARMV8M_OK));
52 }
53
mpu_armv8m_disable(struct mpu_armv8m_dev_t * dev)54 enum mpu_armv8m_error_t mpu_armv8m_disable(struct mpu_armv8m_dev_t *dev)
55 {
56 MPU_Type *mpu = (MPU_Type *)dev->base;
57
58 /* Reset all fields as enable does full setup */
59 mpu->CTRL = 0;
60
61 return MPU_ARMV8M_OK;
62 }
63
mpu_armv8m_region_enable(struct mpu_armv8m_dev_t * dev,struct mpu_armv8m_region_cfg_t * region_cfg)64 FIH_RET_TYPE(enum mpu_armv8m_error_t) mpu_armv8m_region_enable(
65 struct mpu_armv8m_dev_t *dev,
66 struct mpu_armv8m_region_cfg_t *region_cfg)
67 {
68 MPU_Type *mpu = (MPU_Type *)dev->base;
69
70 uint32_t ctrl_before;
71 uint32_t base_cfg;
72 uint32_t limit_cfg;
73
74 /* FIXME : Add region-overlap error check */
75 if ((region_cfg->region_base & ~MPU_RBAR_BASE_Msk) != 0) {
76 FIH_RET(fih_int_encode(MPU_ARMV8M_ERROR));
77 }
78 if ((region_cfg->region_limit & ~MPU_RLAR_LIMIT_Msk) != 0x1F) {
79 FIH_RET(fih_int_encode(MPU_ARMV8M_ERROR));
80 }
81
82 ctrl_before = mpu->CTRL;
83 mpu->CTRL = 0;
84
85 mpu->RNR = region_cfg->region_nr & MPU_RNR_REGION_Msk;
86
87 /* This zeroes the lower bits of the base address */
88 base_cfg = region_cfg->region_base & MPU_RBAR_BASE_Msk;
89 base_cfg |= (region_cfg->attr_sh << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk;
90 base_cfg |= (region_cfg->attr_access << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk;
91 base_cfg |= (region_cfg->attr_exec << MPU_RBAR_XN_Pos) & MPU_RBAR_XN_Msk;
92
93 mpu->RBAR = base_cfg;
94
95 /* MPU Region Limit Address Register is used to set the limit address, the
96 * attribute set, and to enable/disable the seleted region.
97 * These parameters are passed through the lower 5 bits of this register.
98 * These bits are discarded and treated as ones when decoding the address.
99 */
100 limit_cfg = (region_cfg->region_limit) & MPU_RLAR_LIMIT_Msk;
101
102 limit_cfg |= (region_cfg->region_attridx << MPU_RLAR_AttrIndx_Pos) &
103 MPU_RLAR_AttrIndx_Msk;
104
105 #ifdef TFM_PXN_ENABLE
106 limit_cfg |= (region_cfg->attr_pxn << MPU_RLAR_PXN_Pos) & MPU_RLAR_PXN_Msk;
107 #endif
108
109 limit_cfg |= MPU_RLAR_EN_Msk;
110
111 mpu->RLAR = limit_cfg;
112
113 /*Restore main MPU control*/
114 mpu->CTRL = ctrl_before;
115
116 /* Enable MPU before the next instruction */
117 __DSB();
118 __ISB();
119
120 FIH_RET(fih_int_encode(MPU_ARMV8M_OK));
121 }
122
mpu_armv8m_region_disable(struct mpu_armv8m_dev_t * dev,uint32_t region_nr)123 FIH_RET_TYPE(enum mpu_armv8m_error_t) mpu_armv8m_region_disable(
124 struct mpu_armv8m_dev_t *dev,
125 uint32_t region_nr)
126 {
127
128 MPU_Type *mpu = (MPU_Type *)dev->base;
129 uint32_t ctrl_before;
130
131 /*FIXME : Add complete error checking*/
132
133 ctrl_before = mpu->CTRL;
134 mpu->CTRL = 0;
135
136 mpu->RNR = region_nr & MPU_RNR_REGION_Msk;
137
138 mpu->RBAR = 0;
139 mpu->RLAR = 0;
140
141 /*Restore main MPU control*/
142 mpu->CTRL = ctrl_before;
143
144 FIH_RET(fih_int_encode(MPU_ARMV8M_OK));
145 }
146
mpu_armv8m_clean(struct mpu_armv8m_dev_t * dev)147 enum mpu_armv8m_error_t mpu_armv8m_clean(struct mpu_armv8m_dev_t *dev)
148 {
149 MPU_Type *mpu = (MPU_Type *)dev->base;
150 uint32_t i = (mpu->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos;
151 fih_int fih_rc = FIH_FAILURE;
152
153 while (i > 0) {
154 FIH_CALL(mpu_armv8m_region_disable, fih_rc, dev, i - 1);
155 i--;
156 }
157
158 return MPU_ARMV8M_OK;
159 }
160