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