1 /*******************************************************************************
2  * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * MPFS HAL Embedded Software
7  *
8  */
9 /*******************************************************************************
10  * @file mss_mpu.c
11  * @author Microchip-FPGA Embedded Systems Solutions
12  * @brief PolarFire SoC MSS MPU driver for configuring access regions for the
13  * external masters.
14  *
15  */
16 /*=========================================================================*//**
17 
18  *//*=========================================================================*/
19 #include <stdio.h>
20 #include <string.h>
21 #include "mpfs_hal/mss_hal.h"
22 
23 #ifndef SIFIVE_HIFIVE_UNLEASHED
24 
25 static uint64_t pmp_get_napot_base_and_range(uint64_t reg, uint64_t *range);
26 
27 uint8_t num_pmp_lut[10U] = {16U,16U,8U,4U,8U,8U,4U,4U,8U,2U};
28 
29 /**
30  * \brief MPU configuration from Libero for FIC0
31  *
32  */
33 const uint64_t    mpu_fic0_values[] = {
34     LIBERO_SETTING_FIC0_MPU_CFG_PMP0,
35     LIBERO_SETTING_FIC0_MPU_CFG_PMP1,
36     LIBERO_SETTING_FIC0_MPU_CFG_PMP2,
37     LIBERO_SETTING_FIC0_MPU_CFG_PMP3,
38     LIBERO_SETTING_FIC0_MPU_CFG_PMP4,
39     LIBERO_SETTING_FIC0_MPU_CFG_PMP5,
40     LIBERO_SETTING_FIC0_MPU_CFG_PMP6,
41     LIBERO_SETTING_FIC0_MPU_CFG_PMP7,
42     LIBERO_SETTING_FIC0_MPU_CFG_PMP8,
43     LIBERO_SETTING_FIC0_MPU_CFG_PMP9,
44     LIBERO_SETTING_FIC0_MPU_CFG_PMP10,
45     LIBERO_SETTING_FIC0_MPU_CFG_PMP11,
46     LIBERO_SETTING_FIC0_MPU_CFG_PMP12,
47     LIBERO_SETTING_FIC0_MPU_CFG_PMP13,
48     LIBERO_SETTING_FIC0_MPU_CFG_PMP14,
49     LIBERO_SETTING_FIC0_MPU_CFG_PMP15
50 };
51 
52 /**
53  * \brief MPU configuration from Libero for FIC1
54  *
55  */
56 const uint64_t    mpu_fic1_values[] = {
57     LIBERO_SETTING_FIC1_MPU_CFG_PMP0,
58     LIBERO_SETTING_FIC1_MPU_CFG_PMP1,
59     LIBERO_SETTING_FIC1_MPU_CFG_PMP2,
60     LIBERO_SETTING_FIC1_MPU_CFG_PMP3,
61     LIBERO_SETTING_FIC1_MPU_CFG_PMP4,
62     LIBERO_SETTING_FIC1_MPU_CFG_PMP5,
63     LIBERO_SETTING_FIC1_MPU_CFG_PMP6,
64     LIBERO_SETTING_FIC1_MPU_CFG_PMP7,
65     LIBERO_SETTING_FIC1_MPU_CFG_PMP8,
66     LIBERO_SETTING_FIC1_MPU_CFG_PMP9,
67     LIBERO_SETTING_FIC1_MPU_CFG_PMP10,
68     LIBERO_SETTING_FIC1_MPU_CFG_PMP11,
69     LIBERO_SETTING_FIC1_MPU_CFG_PMP12,
70     LIBERO_SETTING_FIC1_MPU_CFG_PMP13,
71     LIBERO_SETTING_FIC1_MPU_CFG_PMP14,
72     LIBERO_SETTING_FIC1_MPU_CFG_PMP15
73 };
74 
75 /**
76  * \brief MPU configuration from Libero for FIC2
77  *
78  */
79 const uint64_t    mpu_fic2_values[] = {
80     LIBERO_SETTING_FIC2_MPU_CFG_PMP0,
81     LIBERO_SETTING_FIC2_MPU_CFG_PMP1,
82     LIBERO_SETTING_FIC2_MPU_CFG_PMP2,
83     LIBERO_SETTING_FIC2_MPU_CFG_PMP3,
84     LIBERO_SETTING_FIC2_MPU_CFG_PMP4,
85     LIBERO_SETTING_FIC2_MPU_CFG_PMP5,
86     LIBERO_SETTING_FIC2_MPU_CFG_PMP6,
87     LIBERO_SETTING_FIC2_MPU_CFG_PMP7,
88 };
89 
90 /**
91  * \brief MPU configuration from Libero for ATHENA
92  *
93  */
94 const uint64_t    mpu_crypto_values[] = {
95     LIBERO_SETTING_CRYPTO_MPU_CFG_PMP0,
96     LIBERO_SETTING_CRYPTO_MPU_CFG_PMP1,
97     LIBERO_SETTING_CRYPTO_MPU_CFG_PMP2,
98     LIBERO_SETTING_CRYPTO_MPU_CFG_PMP3,
99 };
100 
101 /**
102  * \brief MPU configuration from Libero for GEM0
103  *
104  */
105 const uint64_t    mpu_gem0_values[] = {
106     LIBERO_SETTING_GEM0_MPU_CFG_PMP0,
107     LIBERO_SETTING_GEM0_MPU_CFG_PMP1,
108     LIBERO_SETTING_GEM0_MPU_CFG_PMP2,
109     LIBERO_SETTING_GEM0_MPU_CFG_PMP3,
110     LIBERO_SETTING_GEM0_MPU_CFG_PMP4,
111     LIBERO_SETTING_GEM0_MPU_CFG_PMP5,
112     LIBERO_SETTING_GEM0_MPU_CFG_PMP6,
113     LIBERO_SETTING_GEM0_MPU_CFG_PMP7,
114 };
115 
116 /**
117  * \brief MPU configuration from Libero for GEM1
118  *
119  */
120 const uint64_t    mpu_gem1_values[] = {
121     LIBERO_SETTING_GEM1_MPU_CFG_PMP0,
122     LIBERO_SETTING_GEM1_MPU_CFG_PMP1,
123     LIBERO_SETTING_GEM1_MPU_CFG_PMP2,
124     LIBERO_SETTING_GEM1_MPU_CFG_PMP3,
125     LIBERO_SETTING_GEM1_MPU_CFG_PMP4,
126     LIBERO_SETTING_GEM1_MPU_CFG_PMP5,
127     LIBERO_SETTING_GEM1_MPU_CFG_PMP6,
128     LIBERO_SETTING_GEM1_MPU_CFG_PMP7,
129 };
130 
131 /**
132  * \brief MPU configuration from Libero for MMC
133  *
134  */
135 const uint64_t    mpu_mmc_values[] = {
136     LIBERO_SETTING_MMC_MPU_CFG_PMP0,
137     LIBERO_SETTING_MMC_MPU_CFG_PMP1,
138     LIBERO_SETTING_MMC_MPU_CFG_PMP2,
139     LIBERO_SETTING_MMC_MPU_CFG_PMP3,
140 };
141 
142 /**
143  * \brief MPU configuration from Libero for SCB
144  *
145  */
146 const uint64_t    mpu_scb_values[] = {
147     LIBERO_SETTING_SCB_MPU_CFG_PMP0,
148     LIBERO_SETTING_SCB_MPU_CFG_PMP1,
149     LIBERO_SETTING_SCB_MPU_CFG_PMP2,
150     LIBERO_SETTING_SCB_MPU_CFG_PMP3,
151     LIBERO_SETTING_SCB_MPU_CFG_PMP4,
152     LIBERO_SETTING_SCB_MPU_CFG_PMP5,
153     LIBERO_SETTING_SCB_MPU_CFG_PMP6,
154     LIBERO_SETTING_SCB_MPU_CFG_PMP7,
155 };
156 
157 /**
158  * \brief MPU configuration from Libero for USB
159  *
160  */
161 const uint64_t    mpu_usb_values[] = {
162     LIBERO_SETTING_USB_MPU_CFG_PMP0,
163     LIBERO_SETTING_USB_MPU_CFG_PMP1,
164     LIBERO_SETTING_USB_MPU_CFG_PMP2,
165     LIBERO_SETTING_USB_MPU_CFG_PMP3,
166 };
167 
168 /**
169  * \brief MPU configuration from Libero for TRACE
170  *
171  */
172 const uint64_t    mpu_trace_values[] = {
173     LIBERO_SETTING_TRACE_MPU_CFG_PMP0,
174     LIBERO_SETTING_TRACE_MPU_CFG_PMP1,
175 };
176 
177 
178 /***************************************************************************//**
179  * MSS_MPU_auto_configure()
180  * Set MPU's up with configuration from Libero
181  *
182  *
183  * @return
184  */
mpu_configure(void)185 uint8_t mpu_configure(void)
186 {
187     config_64_copy((void *)(&(MSS_MPU(MSS_MPU_FIC0)->PMPCFG)),
188                  &(mpu_fic0_values),
189                  sizeof(mpu_fic0_values));
190 
191     config_64_copy((void *)(&(MSS_MPU(MSS_MPU_FIC1)->PMPCFG)),
192                 &(mpu_fic1_values),
193                 sizeof(mpu_fic1_values));
194 
195     config_64_copy((void *)(&(MSS_MPU(MSS_MPU_FIC2)->PMPCFG)),
196                 &(mpu_fic2_values),
197                 sizeof(mpu_fic2_values));
198 
199     config_64_copy((void *)(&(MSS_MPU(MSS_MPU_CRYPTO)->PMPCFG)),
200                 &(mpu_crypto_values),
201                 sizeof(mpu_crypto_values));
202 
203     config_64_copy((void *)(&(MSS_MPU(MSS_MPU_GEM0)->PMPCFG)),
204                 &(mpu_gem0_values),
205                 sizeof(mpu_gem0_values));
206 
207     config_64_copy((void *)(&(MSS_MPU(MSS_MPU_GEM1)->PMPCFG)),
208                 &(mpu_gem1_values),
209                 sizeof(mpu_gem1_values));
210 
211     config_64_copy((void *)(&(MSS_MPU(MSS_MPU_USB)->PMPCFG)),
212                 &(mpu_usb_values),
213                 sizeof(mpu_usb_values));
214 
215     config_64_copy((void *)(&(MSS_MPU(MSS_MPU_MMC)->PMPCFG)),
216                 &(mpu_mmc_values),
217                 sizeof(mpu_mmc_values));
218 
219     config_64_copy((void *)(&(MSS_MPU(MSS_MPU_SCB)->PMPCFG)),
220                 &(mpu_scb_values),
221                 sizeof(mpu_scb_values));
222 
223     config_64_copy((void *)(&(MSS_MPU(MSS_MPU_TRACE)->PMPCFG)),
224                 &(mpu_trace_values),
225                 sizeof(mpu_trace_values));
226 
227     return(0);
228 }
229 
230 
231 
232 
233 
234 /***************************************************************************//**
235 */
MSS_MPU_configure(mss_mpu_mport_t master_port,mss_mpu_pmp_region_t pmp_region,uint64_t base,uint64_t size,uint8_t permission,mss_mpu_addrm_t matching_mode,uint8_t lock_en)236 uint8_t MSS_MPU_configure(mss_mpu_mport_t master_port,
237                                         mss_mpu_pmp_region_t pmp_region,
238                                         uint64_t base,
239                                         uint64_t size,
240                                         uint8_t permission,
241                                         mss_mpu_addrm_t matching_mode,
242                                         uint8_t lock_en)
243 {
244     uint64_t temp = size, cnt=0ULL;
245     uint64_t range;
246 
247     /*size must be minimum 4k
248       Size must be power of 2
249       different masters have different number of regions*/
250     if((size >= 4096ULL) && (0U == (size & (size - 1U))) && (pmp_region < num_pmp_lut[master_port]))
251     {
252         while((0 == (temp & 0x01U)))
253         {
254             cnt++;
255             temp >>= 1U;
256         }
257 
258         range = (1ULL << (cnt-1U))-1U;
259 
260         MSS_MPU(master_port)->PMPCFG[pmp_region].raw = (base | range) >> 2U;
261 
262         MSS_MPU(master_port)->PMPCFG[pmp_region].MPUCFG_TypeDef.mode = (uint8_t)(permission |
263                                               (uint8_t)(matching_mode << 3U) |
264                                                         (lock_en << 0x7U));
265 
266         return ((uint8_t)0);
267     }
268     else
269     {
270         return ((uint8_t)1);
271     }
272 }
273 
MSS_MPU_get_config(mss_mpu_mport_t master_port,mss_mpu_pmp_region_t pmp_region,uint64_t * base,uint64_t * size,uint8_t * permission,mss_mpu_addrm_t * matching_mode,uint8_t * lock_en)274 uint8_t MSS_MPU_get_config(mss_mpu_mport_t master_port,
275                            mss_mpu_pmp_region_t pmp_region,
276                            uint64_t* base,
277                            uint64_t* size,
278                            uint8_t* permission,
279                            mss_mpu_addrm_t* matching_mode,
280                            uint8_t* lock_en)
281 {
282     uint64_t reg;
283 
284     /*All AXI external masters dont have same number of PMP regions*/
285     if(pmp_region < num_pmp_lut[master_port])
286     {
287         reg = MSS_MPU(master_port)->PMPCFG[pmp_region].MPUCFG_TypeDef.pmp;
288         *base = pmp_get_napot_base_and_range(reg, size);
289 
290         reg = MSS_MPU(master_port)->PMPCFG[pmp_region].MPUCFG_TypeDef.mode;
291         *lock_en = ( reg >> 0x7U) & 0x1U;
292         *matching_mode = (mss_mpu_addrm_t)( (reg >> 3ULL) & 0x3U);
293         *permission = reg & 0x7U;
294 
295         return ((uint8_t)0);
296     }
297     else
298     {
299         return ((uint8_t)1);
300     }
301 }
302 
pmp_get_napot_base_and_range(uint64_t reg,uint64_t * range)303 static uint64_t pmp_get_napot_base_and_range(uint64_t reg, uint64_t *range)
304 {
305     /* construct a mask of all bits bar the top bit */
306     uint64_t mask = 0U;
307     uint64_t base = reg;
308     uint64_t numbits = (sizeof(uint64_t) * 8U) + 2U;
309     mask = (mask - 1U) >> 1U;
310 
311     while (mask)
312     {
313         if ((reg & mask) == mask)
314         {
315             /* this is the mask to use */
316             base = reg & ~mask;
317             break;
318         }
319         mask >>= 1U;
320         numbits--;
321     }
322 
323     *range = (1LU << numbits);
324     return (base << 2U);
325 }
326 
327 #endif
328