1 /*
2 * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc.
3 * Copyright 2016-2020 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_sysmpu.h"
10
11 /* Component ID definition, used by tools. */
12 #ifndef FSL_COMPONENT_ID
13 #define FSL_COMPONENT_ID "platform.drivers.sysmpu"
14 #endif
15
16 /*******************************************************************************
17 * Variables
18 ******************************************************************************/
19
20 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
21 static const clock_ip_name_t g_sysmpuClock[] = SYSMPU_CLOCKS;
22 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
23
24 /*******************************************************************************
25 * Codes
26 ******************************************************************************/
27
28 /*!
29 * brief Initializes the SYSMPU with the user configuration structure.
30 *
31 * This function configures the SYSMPU module with the user-defined configuration.
32 *
33 * param base SYSMPU peripheral base address.
34 * param config The pointer to the configuration structure.
35 */
SYSMPU_Init(SYSMPU_Type * base,const sysmpu_config_t * config)36 void SYSMPU_Init(SYSMPU_Type *base, const sysmpu_config_t *config)
37 {
38 assert(config);
39 uint8_t count;
40
41 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
42 /* Un-gate SYSMPU clock */
43 CLOCK_EnableClock(g_sysmpuClock[0]);
44 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
45
46 /* Initializes the regions. */
47 for (count = 1; count < (uint32_t)FSL_FEATURE_SYSMPU_DESCRIPTOR_COUNT; count++)
48 {
49 base->WORD[count][3] = 0; /* VLD/VID+PID. */
50 base->WORD[count][0] = 0; /* Start address. */
51 base->WORD[count][1] = 0; /* End address. */
52 base->WORD[count][2] = 0; /* Access rights. */
53 base->RGDAAC[count] = 0; /* Alternate access rights. */
54 }
55
56 /* SYSMPU configure. */
57 while (config != NULL)
58 {
59 SYSMPU_SetRegionConfig(base, &(config->regionConfig));
60 config = config->next;
61 }
62 /* Enable SYSMPU. */
63 SYSMPU_Enable(base, true);
64 }
65
66 /*!
67 * brief Deinitializes the SYSMPU regions.
68 *
69 * param base SYSMPU peripheral base address.
70 */
SYSMPU_Deinit(SYSMPU_Type * base)71 void SYSMPU_Deinit(SYSMPU_Type *base)
72 {
73 /* Disable SYSMPU. */
74 SYSMPU_Enable(base, false);
75
76 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
77 /* Gate the clock. */
78 CLOCK_DisableClock(g_sysmpuClock[0]);
79 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
80 }
81
82 /*!
83 * brief Gets the SYSMPU basic hardware information.
84 *
85 * param base SYSMPU peripheral base address.
86 * param hardwareInform The pointer to the SYSMPU hardware information structure. See "sysmpu_hardware_info_t".
87 */
SYSMPU_GetHardwareInfo(SYSMPU_Type * base,sysmpu_hardware_info_t * hardwareInform)88 void SYSMPU_GetHardwareInfo(SYSMPU_Type *base, sysmpu_hardware_info_t *hardwareInform)
89 {
90 assert(hardwareInform);
91
92 uint32_t cesReg = base->CESR;
93 uint32_t regionsNumber_temp = (cesReg & SYSMPU_CESR_NRGD_MASK) >> SYSMPU_CESR_NRGD_SHIFT;
94
95 hardwareInform->hardwareRevisionLevel = (uint8_t)((cesReg & SYSMPU_CESR_HRL_MASK) >> SYSMPU_CESR_HRL_SHIFT);
96 hardwareInform->slavePortsNumbers = (uint8_t)((cesReg & SYSMPU_CESR_NSP_MASK) >> SYSMPU_CESR_NSP_SHIFT);
97 hardwareInform->regionsNumbers = (sysmpu_region_total_num_t)(regionsNumber_temp);
98 }
99
100 /*!
101 * brief Sets the SYSMPU region.
102 *
103 * Note: Due to the SYSMPU protection, the region number 0 does not allow writes from
104 * core to affect the start and end address nor the permissions associated with
105 * the debugger. It can only write the permission fields associated
106 * with the other masters.
107 *
108 * param base SYSMPU peripheral base address.
109 * param regionConfig The pointer to the SYSMPU user configuration structure. See "sysmpu_region_config_t".
110 */
SYSMPU_SetRegionConfig(SYSMPU_Type * base,const sysmpu_region_config_t * regionConfig)111 void SYSMPU_SetRegionConfig(SYSMPU_Type *base, const sysmpu_region_config_t *regionConfig)
112 {
113 assert(regionConfig);
114 assert(regionConfig->regionNum < (uint32_t)FSL_FEATURE_SYSMPU_DESCRIPTOR_COUNT);
115
116 uint32_t wordReg = 0;
117 uint8_t msPortNum;
118 uint8_t regNumber = (uint8_t)regionConfig->regionNum;
119
120 /* The start and end address of the region descriptor. */
121 base->WORD[regNumber][0] = regionConfig->startAddress;
122 base->WORD[regNumber][1] = regionConfig->endAddress;
123
124 /* Set the privilege rights for master 0 ~ master 3. */
125 for (msPortNum = 0; msPortNum < SYSMPU_MASTER_RWATTRIBUTE_START_PORT; msPortNum++)
126 {
127 wordReg |= SYSMPU_REGION_RWXRIGHTS_MASTER(
128 msPortNum, (((uint32_t)regionConfig->accessRights1[msPortNum].superAccessRights << 3U) |
129 (uint32_t)regionConfig->accessRights1[msPortNum].userAccessRights));
130
131 #if FSL_FEATURE_SYSMPU_HAS_PROCESS_IDENTIFIER
132 wordReg |= SYSMPU_REGION_RWXRIGHTS_MASTER_PE(msPortNum,
133 regionConfig->accessRights1[msPortNum].processIdentifierEnable);
134 #endif /* FSL_FEATURE_SYSMPU_HAS_PROCESS_IDENTIFIER */
135 }
136
137 #if FSL_FEATURE_SYSMPU_MASTER_COUNT > SYSMPU_MASTER_RWATTRIBUTE_START_PORT
138 /* Set the normal read write rights for master 4 ~ master 7. */
139 for (msPortNum = SYSMPU_MASTER_RWATTRIBUTE_START_PORT; msPortNum < (uint32_t)FSL_FEATURE_SYSMPU_MASTER_COUNT;
140 msPortNum++)
141 {
142 wordReg |= SYSMPU_REGION_RWRIGHTS_MASTER(
143 msPortNum,
144 ((uint32_t)regionConfig->accessRights2[msPortNum - SYSMPU_MASTER_RWATTRIBUTE_START_PORT].readEnable << 1U |
145 (uint32_t)regionConfig->accessRights2[msPortNum - SYSMPU_MASTER_RWATTRIBUTE_START_PORT].writeEnable));
146 }
147 #endif /* FSL_FEATURE_SYSMPU_MASTER_COUNT > SYSMPU_MASTER_RWATTRIBUTE_START_PORT */
148
149 /* Set region descriptor access rights. */
150 base->WORD[regNumber][2] = wordReg;
151
152 wordReg = SYSMPU_WORD_VLD(1);
153 #if FSL_FEATURE_SYSMPU_HAS_PROCESS_IDENTIFIER
154 wordReg |= SYSMPU_WORD_PID(regionConfig->processIdentifier) | SYSMPU_WORD_PIDMASK(regionConfig->processIdMask);
155 #endif /* FSL_FEATURE_SYSMPU_HAS_PROCESS_IDENTIFIER */
156
157 base->WORD[regNumber][3] = wordReg;
158 }
159
160 /*!
161 * brief Sets the region start and end address.
162 *
163 * Memory region start address. Note: bit0 ~ bit4 is always marked as 0 by SYSMPU.
164 * The actual start address by SYSMPU is 0-modulo-32 byte address.
165 * Memory region end address. Note: bit0 ~ bit4 always be marked as 1 by SYSMPU.
166 * The end address used by the SYSMPU is 31-modulo-32 byte address.
167 * Note: Due to the SYSMPU protection, the startAddr and endAddr can't be
168 * changed by the core when regionNum is 0.
169 *
170 * param base SYSMPU peripheral base address.
171 * param regionNum SYSMPU region number. The range is from 0 to
172 * FSL_FEATURE_SYSMPU_DESCRIPTOR_COUNT - 1.
173 * param startAddr Region start address.
174 * param endAddr Region end address.
175 */
SYSMPU_SetRegionAddr(SYSMPU_Type * base,uint32_t regionNum,uint32_t startAddr,uint32_t endAddr)176 void SYSMPU_SetRegionAddr(SYSMPU_Type *base, uint32_t regionNum, uint32_t startAddr, uint32_t endAddr)
177 {
178 assert(regionNum < (uint32_t)FSL_FEATURE_SYSMPU_DESCRIPTOR_COUNT);
179
180 base->WORD[regionNum][0] = startAddr;
181 base->WORD[regionNum][1] = endAddr;
182 }
183
184 /*!
185 * brief Sets the SYSMPU region access rights for masters with read, write, and execute rights.
186 * The SYSMPU access rights depend on two board classifications of bus masters.
187 * The privilege rights masters and the normal rights masters.
188 * The privilege rights masters have the read, write, and execute access rights.
189 * Except the normal read and write rights, the execute rights are also
190 * allowed for these masters. The privilege rights masters normally range from
191 * bus masters 0 - 3. However, the maximum master number is device-specific.
192 * See the "SYSMPU_PRIVILEGED_RIGHTS_MASTER_MAX_INDEX".
193 * The normal rights masters access rights control see
194 * "SYSMPU_SetRegionRwMasterAccessRights()".
195 *
196 * param base SYSMPU peripheral base address.
197 * param regionNum SYSMPU region number. Should range from 0 to
198 * FSL_FEATURE_SYSMPU_DESCRIPTOR_COUNT - 1.
199 * param masterNum SYSMPU bus master number. Should range from 0 to
200 * SYSMPU_PRIVILEGED_RIGHTS_MASTER_MAX_INDEX.
201 * param accessRights The pointer to the SYSMPU access rights configuration. See
202 * "sysmpu_rwxrights_master_access_control_t".
203 */
SYSMPU_SetRegionRwxMasterAccessRights(SYSMPU_Type * base,uint32_t regionNum,uint32_t masterNum,const sysmpu_rwxrights_master_access_control_t * accessRights)204 void SYSMPU_SetRegionRwxMasterAccessRights(SYSMPU_Type *base,
205 uint32_t regionNum,
206 uint32_t masterNum,
207 const sysmpu_rwxrights_master_access_control_t *accessRights)
208 {
209 assert(accessRights);
210 assert(regionNum < (uint32_t)FSL_FEATURE_SYSMPU_DESCRIPTOR_COUNT);
211 assert(masterNum < SYSMPU_MASTER_RWATTRIBUTE_START_PORT);
212
213 uint32_t mask = SYSMPU_REGION_RWXRIGHTS_MASTER_MASK(masterNum);
214 uint32_t right = base->RGDAAC[regionNum];
215
216 #if FSL_FEATURE_SYSMPU_HAS_PROCESS_IDENTIFIER
217 mask |= SYSMPU_REGION_RWXRIGHTS_MASTER_PE_MASK(masterNum);
218 #endif
219
220 /* Build rights control value. */
221 right &= ~mask;
222 right |= SYSMPU_REGION_RWXRIGHTS_MASTER(
223 masterNum, (((uint32_t)accessRights->superAccessRights << 3U) | (uint32_t)accessRights->userAccessRights));
224 #if FSL_FEATURE_SYSMPU_HAS_PROCESS_IDENTIFIER
225 right |= SYSMPU_REGION_RWXRIGHTS_MASTER_PE(masterNum, accessRights->processIdentifierEnable);
226 #endif /* FSL_FEATURE_SYSMPU_HAS_PROCESS_IDENTIFIER */
227
228 /* Set low master region access rights. */
229 base->RGDAAC[regionNum] = right;
230 }
231
232 #if FSL_FEATURE_SYSMPU_MASTER_COUNT > 4
233 /*!
234 * brief Sets the SYSMPU region access rights for masters with read and write rights.
235 * The SYSMPU access rights depend on two board classifications of bus masters.
236 * The privilege rights masters and the normal rights masters.
237 * The normal rights masters only have the read and write access permissions.
238 * The privilege rights access control see "SYSMPU_SetRegionRwxMasterAccessRights".
239 *
240 * param base SYSMPU peripheral base address.
241 * param regionNum SYSMPU region number. The range is from 0 to
242 * FSL_FEATURE_SYSMPU_DESCRIPTOR_COUNT - 1.
243 * param masterNum SYSMPU bus master number. Should range from SYSMPU_MASTER_RWATTRIBUTE_START_PORT
244 * to ~ FSL_FEATURE_SYSMPU_MASTER_COUNT - 1.
245 * param accessRights The pointer to the SYSMPU access rights configuration. See
246 * "sysmpu_rwrights_master_access_control_t".
247 */
SYSMPU_SetRegionRwMasterAccessRights(SYSMPU_Type * base,uint32_t regionNum,uint32_t masterNum,const sysmpu_rwrights_master_access_control_t * accessRights)248 void SYSMPU_SetRegionRwMasterAccessRights(SYSMPU_Type *base,
249 uint32_t regionNum,
250 uint32_t masterNum,
251 const sysmpu_rwrights_master_access_control_t *accessRights)
252 {
253 assert(accessRights);
254 assert(regionNum < (uint32_t)FSL_FEATURE_SYSMPU_DESCRIPTOR_COUNT);
255 assert(masterNum >= SYSMPU_MASTER_RWATTRIBUTE_START_PORT);
256 assert(masterNum <= ((uint32_t)FSL_FEATURE_SYSMPU_MASTER_COUNT - 1U));
257
258 uint32_t mask = SYSMPU_REGION_RWRIGHTS_MASTER_MASK(masterNum);
259 uint32_t right = base->RGDAAC[regionNum];
260
261 /* Build rights control value. */
262 right &= ~mask;
263 right |= SYSMPU_REGION_RWRIGHTS_MASTER(
264 masterNum, (((uint32_t)accessRights->readEnable << 1U) | (uint32_t)accessRights->writeEnable));
265 /* Set low master region access rights. */
266 base->RGDAAC[regionNum] = right;
267 }
268 #endif /* FSL_FEATURE_SYSMPU_MASTER_COUNT > 4 */
269
270 /*!
271 * brief Gets the numbers of slave ports where errors occur.
272 *
273 * param base SYSMPU peripheral base address.
274 * param slaveNum SYSMPU slave port number.
275 * return The slave ports error status.
276 * true - error happens in this slave port.
277 * false - error didn't happen in this slave port.
278 */
SYSMPU_GetSlavePortErrorStatus(SYSMPU_Type * base,sysmpu_slave_t slaveNum)279 bool SYSMPU_GetSlavePortErrorStatus(SYSMPU_Type *base, sysmpu_slave_t slaveNum)
280 {
281 uint8_t sperr;
282
283 sperr = (uint8_t)(((base->CESR & SYSMPU_CESR_SPERR_MASK) >> SYSMPU_CESR_SPERR_SHIFT) &
284 (0x1U << ((uint32_t)FSL_FEATURE_SYSMPU_SLAVE_COUNT - (uint32_t)slaveNum - 1U)));
285
286 return (sperr != 0U) ? true : false;
287 }
288
289 /*!
290 * brief Gets the SYSMPU detailed error access information.
291 *
292 * param base SYSMPU peripheral base address.
293 * param slaveNum SYSMPU slave port number.
294 * param errInform The pointer to the SYSMPU access error information. See "sysmpu_access_err_info_t".
295 */
SYSMPU_GetDetailErrorAccessInfo(SYSMPU_Type * base,sysmpu_slave_t slaveNum,sysmpu_access_err_info_t * errInform)296 void SYSMPU_GetDetailErrorAccessInfo(SYSMPU_Type *base, sysmpu_slave_t slaveNum, sysmpu_access_err_info_t *errInform)
297 {
298 assert(errInform);
299
300 uint32_t value;
301 uint32_t cesReg;
302 uint32_t attributes_temp;
303 uint32_t accessType_temp;
304
305 /* Error address. */
306 errInform->address = base->SP[slaveNum].EAR;
307
308 /* Error detail information. */
309 value = (base->SP[slaveNum].EDR & SYSMPU_EDR_EACD_MASK) >> SYSMPU_EDR_EACD_SHIFT;
310 if (value == 0U)
311 {
312 errInform->accessControl = kSYSMPU_NoRegionHit;
313 }
314 else if ((value & (uint16_t)(value - 1U)) == 0U)
315 {
316 errInform->accessControl = kSYSMPU_NoneOverlappRegion;
317 }
318 else
319 {
320 errInform->accessControl = kSYSMPU_OverlappRegion;
321 }
322
323 value = base->SP[slaveNum].EDR & (~SYSMPU_EDR_EACD_MASK);
324 attributes_temp = (value & SYSMPU_EDR_EATTR_MASK) >> SYSMPU_EDR_EATTR_SHIFT;
325 accessType_temp = (value & SYSMPU_EDR_ERW_MASK) >> SYSMPU_EDR_ERW_SHIFT;
326
327 errInform->master = (value & SYSMPU_EDR_EMN_MASK) >> SYSMPU_EDR_EMN_SHIFT;
328 errInform->attributes = (sysmpu_err_attributes_t)attributes_temp;
329 errInform->accessType = (sysmpu_err_access_type_t)accessType_temp;
330 #if FSL_FEATURE_SYSMPU_HAS_PROCESS_IDENTIFIER
331 errInform->processorIdentification = (uint8_t)((value & SYSMPU_EDR_EPID_MASK) >> SYSMPU_EDR_EPID_SHIFT);
332 #endif
333
334 /* Clears error slave port bit. */
335 cesReg =
336 (base->CESR & ~SYSMPU_CESR_SPERR_MASK) |
337 ((0x1UL << ((uint32_t)FSL_FEATURE_SYSMPU_SLAVE_COUNT - (uint32_t)slaveNum - 1U)) << SYSMPU_CESR_SPERR_SHIFT);
338 base->CESR = cesReg;
339 }
340