1 /*
2  * Copyright (c) 2016-2022 Arm Limited. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /**
18  * \file mpc_sie_drv.h
19  * \brief Generic driver for ARM SIE Memory Protection
20  *        Controllers (MPC).
21  *        Features of ARM MPC driver:
22  *          1. Get MPC block size
23  *          2. Configure memory region
24  *          3. Get memory region configuration
25  *          4. Get/Set MPC control value
26  *          5. Get configured secure response
27  *          6. Set secure response type
28  *          7. Enable/Disable/Clear MPC interrupt
29  *          8. Get MPC interrupt state
30  *          9. Lock down MPC configuration
31  *          10. Check if gating is present in hardware
32  *          11. Get ID register value
33  *          12. Check ack for gating incoming transfers
34  *          13. Request/Release for gating incoming transfers
35  */
36 
37 #ifndef __MPC_SIE_DRV_H__
38 #define __MPC_SIE_DRV_H__
39 
40 #include <stdint.h>
41 #include <stdbool.h>
42 
43 #ifdef __cplusplus
44 extern "C" {
45 #endif
46 
47 /* Error code returned by the driver functions */
48 enum mpc_sie_error_t {
49     MPC_SIE_ERR_NONE,          /*!< No error */
50     MPC_SIE_INVALID_ARG,       /*!< MPC invalid input arguments */
51     MPC_SIE_NOT_INIT,          /*!< MPC not initialized */
52     MPC_SIE_ERR_NOT_IN_RANGE,  /*!< Address does not belong to a range
53                                    *   controlled by the MPC */
54     MPC_SIE_ERR_NOT_ALIGNED,   /*!< Address is not aligned on the block size
55                                    *   of this MPC
56                                    */
57     MPC_SIE_ERR_INVALID_RANGE, /*!< The given address range to configure
58                                    *   is invalid. This could be because:
59                                    *   - The base and limit swapped
60                                    *   - The base and limit addresses
61                                    *     are in different ranges
62                                    */
63     MPC_SIE_ERR_RANGE_SEC_ATTR_NON_COMPATIBLE, /*!< The given range cannot be
64                                                    *   accessed with the wanted
65                                                    *   security attributes
66                                                    */
67     MPC_SIE_UNSUPPORTED_HARDWARE_VERSION, /*!< MPC hardware version read from
68                                               *   PIDR0 is not supported
69                                               */
70     MPC_SIE_ERR_GATING_NOT_PRESENT        /*!< MPC gating not present in HW */
71 };
72 
73 /* Security attribute used in various place of the API */
74 enum mpc_sie_sec_attr_t {
75     MPC_SIE_SEC_ATTR_SECURE,     /*!< Secure attribute */
76     MPC_SIE_SEC_ATTR_NONSECURE,  /*!< Non-secure attribute */
77     /*!< Used when getting the configuration of a memory range and some blocks
78      *   are secure whereas some other are non secure
79      */
80     MPC_SIE_SEC_ATTR_MIXED,
81 };
82 
83 /* What can happen when trying to do an illegal memory access */
84 enum mpc_sie_sec_resp_t {
85     MPC_SIE_RESP_RAZ_WI,    /*!< Read As Zero, Write Ignored */
86     MPC_SIE_RESP_BUS_ERROR, /*!< Bus error */
87     MPC_SIE_RESP_WAIT_GATING_DISABLED  /*!< Wait until gating is disabled */
88 };
89 
90 /* Description of a memory range controlled by the MPC */
91 struct mpc_sie_memory_range_t {
92     const uint32_t base;   /*!< Base address (included in the range) */
93     const uint32_t limit;  /*!< Limit address (included in the range) */
94     const uint32_t range_offset; /*!< Offset of current range area to the 0
95                                   *   point of the whole area (the sum of the
96                                   *   sizes of the previous memory ranges
97                                   *   covered by the same MPC)
98                                   */
99     const enum mpc_sie_sec_attr_t attr; /*!< Optional security attribute
100                                             *   needed to be matched when
101                                             *   accessing this range.
102                                             *   For example, the non-secure
103                                             *   alias of a memory region can not
104                                             *   be accessed using secure access,
105                                             *   and configuring the MPC to
106                                             *   secure using that range will not
107                                             *   be permitted by the driver.
108                                             */
109 };
110 
111 /* ARM MPC SIE device configuration structure */
112 struct mpc_sie_dev_cfg_t {
113     const uint32_t base;  /*!< MPC base address */
114     /*!< Array of pointers to memory ranges controlled by the MPC */
115     const struct mpc_sie_memory_range_t** range_list;
116     uint8_t nbr_of_ranges;  /*!< Number of memory ranges in the list */
117 };
118 
119 /* ARM MPC SIE device data structure */
120 struct mpc_sie_dev_data_t {
121     bool is_initialized;    /*!< Indicates if the MPC driver
122                              *   is initialized and enabled
123                              */
124     uint32_t sie_version;   /*!< SIE version */
125 };
126 
127 /* ARM MPC SIE device structure */
128 struct mpc_sie_dev_t {
129     const struct mpc_sie_dev_cfg_t* const cfg;  /*!< MPC configuration */
130     struct mpc_sie_dev_data_t* const data;      /*!< MPC data */
131 };
132 
133 /**
134  * \brief Initializes a MPC device.
135  *
136  * \param[in] dev            MPC device \ref mpc_sie_dev_t
137  *
138  * \return Returns error code as specified in \ref mpc_sie_error_t
139  *
140  * \note This function doesn't check if dev is NULL.
141  */
142 enum mpc_sie_error_t mpc_sie_init(struct mpc_sie_dev_t* dev);
143 
144 /**
145  * \brief Gets MPC block size. All regions must be aligned on this block
146  *        size (base address and limit+1 address).
147  *
148  * \param[in]  dev       MPC device \ref mpc_sie_dev_t
149  * \param[out] blk_size  MPC block size
150  *
151  * \return Returns error code as specified in \ref mpc_sie_error_t
152  *
153  * \note This function doesn't check if dev is NULL.
154  */
155 enum mpc_sie_error_t mpc_sie_get_block_size(struct mpc_sie_dev_t* dev,
156                                             uint32_t* blk_size);
157 
158 /**
159  * \brief Configures a memory region (base and limit included).
160  *
161  * \param[in] dev    MPC device \ref mpc_sie_dev_t
162  * \param[in] base   Base address of the region to poll. This bound is
163  *                   included. It does not need to be aligned in any way.
164  *
165  * \param[in] limit  Limit address of the region to poll. This bound is
166  *                   included. (limit+1) does not need to be aligned
167  *                   in any way.
168  * \param[in] attr   Security attribute of the region. If the region has mixed
169  *                   secure/non-secure, a special value is returned
170  *                   (\ref mpc_sie_sec_attr_t).
171  *
172  *            In case base and limit+1 addresses are not aligned on
173  *            the block size, the enclosing region with base and
174  *            limit+1 aligned on block size will be queried.
175  *            In case of early termination of the function (error), the
176  *            security attribute will be set to MPC_SIE_ATTR_MIXED.
177  *
178  * \return Returns error code as specified in \ref mpc_sie_error_t
179  *
180  * \note This function doesn't check if dev is NULL.
181  */
182 enum mpc_sie_error_t mpc_sie_config_region(struct mpc_sie_dev_t* dev,
183                                            const uint32_t base,
184                                            const uint32_t limit,
185                                            enum mpc_sie_sec_attr_t attr);
186 
187 /**
188  * \brief Gets a memory region configuration(base and limit included).
189  *
190  * \param[in]  dev    MPC device \ref mpc_sie_dev_t
191  * \param[in]  base   Base address of the region to get the configuration.
192  * \param[in]  limit  Limit address of the region to get the configuration.
193  * \param[out] attr   Security attribute of the region
194  *                    \ref mpc_sie_sec_attr_t
195  *
196  * \return Returns error code as specified in \ref mpc_sie_error_t
197  *
198  * \note This function doesn't check if dev is NULL.
199  */
200 enum mpc_sie_error_t mpc_sie_get_region_config(struct mpc_sie_dev_t* dev,
201                                                uint32_t base,
202                                                uint32_t limit,
203                                                enum mpc_sie_sec_attr_t* attr);
204 
205 /**
206  * \brief Gets the MPC control value.
207  *
208  * \param[in]  dev       MPC device \ref mpc_sie_dev_t
209  * \param[out] ctrl_val  Current MPC control value.
210  *
211  * \return Returns error code as specified in \ref mpc_sie_error_t
212  *
213  * \note This function doesn't check if dev is NULL.
214  */
215 enum mpc_sie_error_t mpc_sie_get_ctrl(struct mpc_sie_dev_t* dev,
216                                       uint32_t* ctrl_val);
217 
218 /**
219  * \brief Sets the MPC control value.
220  *
221  * \param[in] dev       MPC device \ref mpc_sie_dev_t
222  * \param[in] mpc_ctrl  New MPC control value
223  *
224  * \return Returns error code as specified in \ref mpc_sie_error_t
225  *
226  * \note This function doesn't check if dev is NULL.
227  */
228 enum mpc_sie_error_t mpc_sie_set_ctrl(struct mpc_sie_dev_t* dev,
229                                       uint32_t mpc_ctrl);
230 
231 /**
232  * \brief Gets the configured secure response.
233  *
234  * \param[in]  dev      MPC device \ref mpc_sie_dev_t
235  * \param[out] sec_rep  Configured secure response (\ref mpc_sie_sec_resp_t).
236  *
237  * \return Returns error code as specified in \ref mpc_sie_error_t
238  *
239  * \note This function doesn't check if dev is NULL.
240  */
241 enum mpc_sie_error_t mpc_sie_get_sec_resp(struct mpc_sie_dev_t* dev,
242                                           enum mpc_sie_sec_resp_t* sec_rep);
243 
244 /**
245  * \brief Sets the response type when SW asks to gate the incoming transfers.
246  *
247  * \param[in] dev     MPC device \ref mpc_sie_dev_t
248  * \param[in] sec_rep Secure response to configure (\ref mpc_sie_sec_resp_t).
249  *
250  * \note This function doesn't check if dev is NULL.
251  */
252 enum mpc_sie_error_t mpc_sie_set_sec_resp(struct mpc_sie_dev_t* dev,
253                                           enum mpc_sie_sec_resp_t sec_rep);
254 
255 /**
256  * \brief Enables MPC interrupt.
257  *
258  * \param[in] dev  MPC device \ref mpc_sie_dev_t
259  *
260  * \return Returns error code as specified in \ref mpc_sie_error_t
261  *
262  * \note This function doesn't check if dev is NULL.
263  */
264 enum mpc_sie_error_t mpc_sie_irq_enable(struct mpc_sie_dev_t* dev);
265 
266 /**
267  * \brief Disables MPC interrupt
268  *
269  * \param[in] dev  MPC device \ref mpc_sie_dev_t
270  *
271  * \note This function doesn't check if dev is NULL.
272  */
273 void mpc_sie_irq_disable(struct mpc_sie_dev_t* dev);
274 
275 /**
276  * \brief Clears MPC interrupt.
277  *
278  * \param[in] dev  MPC device \ref mpc_sie_dev_t
279  *
280  * \note This function doesn't check if dev is NULL.
281  */
282 void mpc_sie_clear_irq(struct mpc_sie_dev_t* dev);
283 
284 /**
285  * \brief Returns the MPC interrupt state.
286  *
287  * \param[in] dev  MPC device \ref mpc_sie_dev_t
288  *
289  * \return Returns 1 if the interrupt is active, 0 otherwise.
290  *
291  * \note This function doesn't check if dev is NULL.
292  */
293 uint32_t mpc_sie_irq_state(struct mpc_sie_dev_t* dev);
294 
295 /**
296  * \brief Locks down the MPC configuration.
297  *
298  * \param[in] dev  MPC device \ref mpc_sie_dev_t
299  *
300  * \return Returns error code as specified in \ref mpc_sie_error_t
301  *
302  * \note This function doesn't check if dev is NULL.
303  */
304 enum mpc_sie_error_t mpc_sie_lock_down(struct mpc_sie_dev_t* dev);
305 
306 /**
307  * \brief Returns if gating is present in hardware.
308  *
309  * \param[in]  dev             MPC device \ref mpc_sie_dev_t
310  * \param[out] gating_present  Returns if gating is present in hardware.
311  *
312  * \return Returns error code as specified in \ref mpc_sie_error_t
313  *
314  * \note This function doesn't check if dev is NULL.
315  */
316 enum mpc_sie_error_t mpc_sie_is_gating_present(struct mpc_sie_dev_t* dev,
317                                                bool* gating_present);
318 
319 /**
320  * \brief Returns the value of Peripheral ID 0 register.
321  *
322  * \param[in] dev  MPC device \ref mpc_sie_dev_t
323  *
324  * \return Returns the value of Peripheral ID 0 register.
325  *
326  * \note This function doesn't check if dev is NULL.
327  */
328 uint32_t get_sie_version(struct mpc_sie_dev_t* dev);
329 
330 /**
331  * \brief Reads bit indicating acknowledge for gating incoming transfers.
332  *
333  * \param[in] dev  MPC device \ref mpc_sie_dev_t
334  *
335  * \return True if acknowledge is set.
336  *
337  * \note This function doesn't check if dev is NULL.
338  */
339 bool mpc_sie_get_gate_ack(struct mpc_sie_dev_t* dev);
340 
341 /**
342  * \brief Sets bit to request for gating incoming transfers.
343  *
344  * \param[in] dev  MPC device \ref mpc_sie_dev_t
345  *
346  * \note This function doesn't check if dev is NULL.
347  */
348 void mpc_sie_request_gating(struct mpc_sie_dev_t* dev);
349 
350 /**
351  * \brief Clears bit to request for gating incoming transfers.
352  *
353  * \param[in] dev  MPC device \ref mpc_sie_dev_t
354  *
355  * \note This function doesn't check if dev is NULL.
356  */
357 void mpc_sie_release_gating(struct mpc_sie_dev_t* dev);
358 
359 #ifdef __cplusplus
360 }
361 #endif
362 #endif /* __MPC_SIE_DRV_H__ */
363