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 */
18
mpu_armv8m_enable(struct mpu_armv8m_dev_t * dev,uint32_t privdef_en,uint32_t hfnmi_en)19 enum mpu_armv8m_error_t mpu_armv8m_enable(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 return MPU_ARMV8M_OK;
51 }
52
mpu_armv8m_disable(struct mpu_armv8m_dev_t * dev)53 enum mpu_armv8m_error_t mpu_armv8m_disable(struct mpu_armv8m_dev_t *dev)
54 {
55 MPU_Type *mpu = (MPU_Type *)dev->base;
56
57 /* Reset all fields as enable does full setup */
58 mpu->CTRL = 0;
59
60 return MPU_ARMV8M_OK;
61 }
62
63
mpu_armv8m_region_enable(struct mpu_armv8m_dev_t * dev,struct mpu_armv8m_region_cfg_t * region_cfg)64 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 enum mpu_armv8m_error_t ret_val = MPU_ARMV8M_OK;
71 uint32_t ctrl_before;
72 uint32_t base_cfg;
73 uint32_t limit_cfg;
74
75 /*FIXME : Add complete error checking*/
76 if ((region_cfg->region_base & ~MPU_RBAR_BASE_Msk) != 0) {
77 return MPU_ARMV8M_ERROR;
78 }
79 /* region_limit doesn't need to be aligned but the scatter
80 * file needs to be setup to ensure that partitions do not overlap.
81 */
82
83 ctrl_before = mpu->CTRL;
84 mpu->CTRL = 0;
85
86 mpu->RNR = region_cfg->region_nr & MPU_RNR_REGION_Msk;
87
88 /* This zeroes the lower bits of the base address */
89 base_cfg = region_cfg->region_base & MPU_RBAR_BASE_Msk;
90 base_cfg |= (region_cfg->attr_sh << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk;
91 base_cfg |= (region_cfg->attr_access << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk;
92 base_cfg |= (region_cfg->attr_exec << MPU_RBAR_XN_Pos) & MPU_RBAR_XN_Msk;
93
94 mpu->RBAR = base_cfg;
95
96 /* This zeroes the lower bits of limit address but they are treated as 1 */
97 limit_cfg = (region_cfg->region_limit-1) & MPU_RLAR_LIMIT_Msk;
98
99 limit_cfg |= (region_cfg->region_attridx << MPU_RLAR_AttrIndx_Pos) &
100 MPU_RLAR_AttrIndx_Msk;
101
102 limit_cfg |= MPU_RLAR_EN_Msk;
103
104 mpu->RLAR = limit_cfg;
105
106 /*Restore main MPU control*/
107 mpu->CTRL = ctrl_before;
108
109 /* Enable MPU before the next instruction */
110 __DSB();
111 __ISB();
112
113 return ret_val;
114 }
115
116
mpu_armv8m_region_disable(struct mpu_armv8m_dev_t * dev,uint32_t region_nr)117 enum mpu_armv8m_error_t mpu_armv8m_region_disable(
118 struct mpu_armv8m_dev_t *dev,
119 uint32_t region_nr)
120 {
121
122 MPU_Type *mpu = (MPU_Type *)dev->base;
123
124 enum mpu_armv8m_error_t ret_val = MPU_ARMV8M_OK;
125 uint32_t ctrl_before;
126
127 /*FIXME : Add complete error checking*/
128
129 ctrl_before = mpu->CTRL;
130 mpu->CTRL = 0;
131
132 mpu->RNR = region_nr & MPU_RNR_REGION_Msk;
133
134 mpu->RBAR = 0;
135 mpu->RLAR = 0;
136
137 /*Restore main MPU control*/
138 mpu->CTRL = ctrl_before;
139
140 return ret_val;
141 }
142
mpu_armv8m_clean(struct mpu_armv8m_dev_t * dev)143 enum mpu_armv8m_error_t mpu_armv8m_clean(struct mpu_armv8m_dev_t *dev)
144 {
145 MPU_Type *mpu = (MPU_Type *)dev->base;
146 uint32_t i = (mpu->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos;
147
148 while (i > 0) {
149 mpu_armv8m_region_disable(dev, i-1);
150 i--;
151 }
152
153 return MPU_ARMV8M_OK;
154
155 }
156