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 #include "mpc_sie_drv.h"
17 #include "mpc_sie_reg_map.h"
18 
19 #include <stddef.h>
20 #include <stdbool.h>
21 
22 #include "cmsis_compiler.h"
23 
24 /* Values for hardware version in PIDR0 reg */
25 #define SIE200      0x60
26 #define SIE300      0x65
27 
28 #define MPC_SIE_BLK_CFG_OFFSET  5U
29 
30 /* Defines with numbering (eg: SIE300) are only relevant to the given SIE
31  * version. Defines without the numbering are applicable to all SIE versions.
32  */
33 
34 /* CTRL register bit indexes */
35 #define MPC_SIE200_CTRL_SEC_RESP      (1UL << 4UL)  /* MPC fault triggers a
36                                                      * bus error
37                                                      */
38 #define MPC_SIE300_CTRL_GATE_REQ      (1UL << 6UL)  /* Request for gating
39                                                      * incoming transfers
40                                                      */
41 #define MPC_SIE300_CTRL_GATE_ACK      (1UL << 7UL)  /* Acknowledge for gating
42                                                      * incoming transfers
43                                                      */
44 #define MPC_SIE_CTRL_AUTOINCREMENT    (1UL << 8UL)  /* BLK_IDX auto increment */
45 #define MPC_SIE300_CTRL_SEC_RESP      (1UL << 16UL) /* Response type when SW
46                                                      * asks to gate the transfer
47                                                      */
48 #define MPC_SIE300_CTRL_GATE_PRESENT  (1UL << 23UL) /* Gating feature present */
49 #define MPC_SIE_CTRL_SEC_LOCK_DOWN    (1UL << 31UL) /* MPC Security lock down */
50 
51 /* PIDR register bit masks */
52 #define MPC_PIDR0_SIE_VERSION_MASK    ((1UL << 8UL) - 1UL)
53 
54 /* ARM MPC interrupt */
55 #define MPC_SIE_INT_BIT               (1UL)
56 
57 /* Error code returned by the internal driver functions */
58 enum mpc_sie_intern_error_t {
59     MPC_SIE_INTERN_ERR_NONE = MPC_SIE_ERR_NONE,
60     MPC_SIE_INTERN_ERR_NOT_IN_RANGE = MPC_SIE_ERR_NOT_IN_RANGE,
61     MPC_SIE_INTERN_ERR_NOT_ALIGNED = MPC_SIE_ERR_NOT_ALIGNED,
62     MPC_SIE_INTERN_ERR_INVALID_RANGE = MPC_SIE_ERR_INVALID_RANGE,
63     MPC_INTERN_ERR_RANGE_SEC_ATTR_NON_COMPATIBLE =
64                                    MPC_SIE_ERR_RANGE_SEC_ATTR_NON_COMPATIBLE,
65     /* Calculated block index
66      * is higher than the maximum allowed by the MPC. It should never
67      * happen unless the controlled ranges of the MPC are misconfigured
68      * in the driver or if the IP has not enough LUTs to cover the
69      * range, due to wrong reported block size for example.
70      */
71     MPC_SIE_INTERN_ERR_BLK_IDX_TOO_HIGH = -1,
72 
73 };
74 
75 /*
76  * Checks if the address is controlled by the MPC and returns
77  * the range index in which it is contained.
78  *
79  * \param[in]  dev         MPC device to initialize \ref mpc_sie_dev_t
80  * \param[in]  addr        Address to check if it is controlled by MPC.
81  * \param[out] addr_range  Range index in which it is contained.
82  *
83  * \return True if the base is controller by the range list, false otherwise.
84  */
is_ctrl_by_range_list(struct mpc_sie_dev_t * dev,uint32_t addr,const struct mpc_sie_memory_range_t ** addr_range)85 static uint32_t is_ctrl_by_range_list(
86                             struct mpc_sie_dev_t* dev,
87                             uint32_t addr,
88                             const struct mpc_sie_memory_range_t** addr_range)
89 {
90     uint32_t i;
91     const struct mpc_sie_memory_range_t* range;
92 
93     for(i = 0; i < dev->cfg->nbr_of_ranges; i++) {
94         range = dev->cfg->range_list[i];
95         if(addr >= range->base && addr <= range->limit) {
96             *addr_range = range;
97             return 1;
98         }
99     }
100     return 0;
101 }
102 
103 /*
104  * Gets the masks selecting the bits in the LUT of the MPC corresponding
105  * to the base address (included) up to the limit address (included)
106  *
107  * \param[in]   mpc_dev          The MPC device.
108  * \param[in]   base             Address in a range controlled by this MPC
109  *                               (included), aligned on block size.
110  * \param[in]   limit            Address in a range controlled by this MPC
111  *                               (included), aligned on block size.
112  * \param[out]  range            Memory range in which the base address and
113  *                               limit are.
114  * \param[out]  first_word_idx   Index of the first touched word in the LUT.
115  * \param[out]  nr_words         Number of words used in the LUT. If 1, only
116  *                               first_word_mask is valid and limit_word_mask
117  *                               must not be used.
118  * \param[out]  first_word_mask  First word mask in the LUT will be stored here.
119  * \param[out]  limit_word_mask  Limit word mask in the LUT will be stored here.
120  *
121  * \return Returns error code as specified in \ref mpc_sie_intern_error_t
122  */
get_lut_masks(struct mpc_sie_dev_t * dev,const uint32_t base,const uint32_t limit,const struct mpc_sie_memory_range_t ** range,uint32_t * first_word_idx,uint32_t * nr_words,uint32_t * first_word_mask,uint32_t * limit_word_mask)123 static enum mpc_sie_intern_error_t get_lut_masks(
124                                  struct mpc_sie_dev_t* dev,
125                                  const uint32_t base, const uint32_t limit,
126                                  const struct mpc_sie_memory_range_t** range,
127                                  uint32_t *first_word_idx,
128                                  uint32_t *nr_words,
129                                  uint32_t *first_word_mask,
130                                  uint32_t *limit_word_mask)
131 {
132     const struct mpc_sie_memory_range_t* base_range;
133     uint32_t block_size;
134     uint32_t base_block_idx;
135     uint32_t base_word_idx;
136     uint32_t blk_max;
137     const struct mpc_sie_memory_range_t* limit_range;
138     uint32_t limit_block_idx;
139     uint32_t limit_word_idx;
140     uint32_t mask;
141     uint32_t norm_base;
142     uint32_t norm_limit;
143     struct mpc_sie_reg_map_t* p_mpc =
144                                    (struct mpc_sie_reg_map_t*)dev->cfg->base;
145 
146     /*
147      * Check that the addresses are within the controlled regions
148      * of this MPC
149      */
150     if(!is_ctrl_by_range_list(dev, base, &base_range) ||
151        !is_ctrl_by_range_list(dev, limit, &limit_range)) {
152         return MPC_SIE_INTERN_ERR_NOT_IN_RANGE;
153     }
154 
155     /* Base and limit should be part of the same range */
156     if(base_range != limit_range) {
157         return MPC_SIE_INTERN_ERR_INVALID_RANGE;
158     }
159     *range = base_range;
160 
161     block_size = (1 << (p_mpc->blk_cfg + MPC_SIE_BLK_CFG_OFFSET));
162 
163     /* Base and limit+1 addresses must be aligned on the MPC block size */
164     if(base % block_size || (limit+1) % block_size) {
165         return MPC_SIE_INTERN_ERR_NOT_ALIGNED;
166     }
167 
168     /*
169      * Get a normalized address that is an offset from the beginning
170      * of the lowest range controlled by the MPC
171      */
172     norm_base  = (base - base_range->base) + base_range->range_offset;
173     norm_limit = (limit - base_range->base) + base_range->range_offset;
174 
175     /*
176      * Calculate block index and to which 32 bits word it belongs
177      */
178     limit_block_idx = norm_limit/block_size;
179     limit_word_idx = limit_block_idx/32;
180 
181     base_block_idx = norm_base/block_size;
182     base_word_idx = base_block_idx/32;
183 
184     if(base_block_idx > limit_block_idx) {
185         return MPC_SIE_INTERN_ERR_INVALID_RANGE;
186     }
187 
188     /* Transmit the information to the caller */
189     *nr_words = limit_word_idx - base_word_idx + 1;
190     *first_word_idx = base_word_idx;
191 
192     /* Limit to the highest block that can be configured */
193     blk_max = p_mpc->blk_max;
194 
195     if((limit_word_idx > blk_max) || (base_word_idx > blk_max)) {
196         return MPC_SIE_INTERN_ERR_BLK_IDX_TOO_HIGH;
197     }
198 
199     /*
200      * Create the mask for the first word to only select the limit N bits
201      */
202     *first_word_mask = ~((1 << (base_block_idx % 32)) - 1);
203 
204     /*
205      * Create the mask for the limit word to select only the first M bits.
206      */
207     *limit_word_mask = (1 << ((limit_block_idx+1) % 32)) - 1;
208     /*
209      * If limit_word_mask is 0, it means that the limit touched block index is
210      * the limit in its word, so the limit word mask has all its bits selected
211      */
212     if(*limit_word_mask == 0) {
213         *limit_word_mask = 0xFFFFFFFF;
214     }
215 
216     /*
217      * If the blocks to configure are all packed in one word, only
218      * touch this word.
219      * Code using the computed masks should test if this mask
220      * is non-zero, and if so, only use this one instead of the limit_word_mask
221      * and first_word_mask.
222      * As the only bits that are the same in both masks are the 1 that we want
223      * to select, just use XOR to extract them.
224      */
225     if(base_word_idx == limit_word_idx) {
226         mask = ~(*first_word_mask ^ *limit_word_mask);
227         *first_word_mask = mask;
228         *limit_word_mask = mask;
229     }
230 
231     return MPC_SIE_INTERN_ERR_NONE;
232 }
233 
mpc_sie_init(struct mpc_sie_dev_t * dev)234 enum mpc_sie_error_t mpc_sie_init(struct mpc_sie_dev_t* dev)
235 {
236     dev->data->sie_version = get_sie_version(dev);
237 
238     if ((dev->data->sie_version != SIE200) &&
239         (dev->data->sie_version != SIE300)) {
240         return MPC_SIE_UNSUPPORTED_HARDWARE_VERSION;
241     }
242     dev->data->is_initialized = true;
243 
244     return MPC_SIE_ERR_NONE;
245 }
246 
mpc_sie_get_block_size(struct mpc_sie_dev_t * dev,uint32_t * blk_size)247 enum mpc_sie_error_t mpc_sie_get_block_size(struct mpc_sie_dev_t* dev,
248                                             uint32_t* blk_size)
249 {
250     struct mpc_sie_reg_map_t* p_mpc =
251                                    (struct mpc_sie_reg_map_t*)dev->cfg->base;
252 
253     if(dev->data->is_initialized != true) {
254         return MPC_SIE_NOT_INIT;
255     }
256 
257     if(blk_size == 0) {
258         return MPC_SIE_INVALID_ARG;
259     }
260 
261     /* Calculate the block size in byte according to the manual */
262     *blk_size = (1 << (p_mpc->blk_cfg + MPC_SIE_BLK_CFG_OFFSET));
263 
264     return MPC_SIE_ERR_NONE;
265 }
266 
mpc_sie_config_region(struct mpc_sie_dev_t * dev,const uint32_t base,const uint32_t limit,enum mpc_sie_sec_attr_t attr)267 enum mpc_sie_error_t mpc_sie_config_region(struct mpc_sie_dev_t* dev,
268                                            const uint32_t base,
269                                            const uint32_t limit,
270                                            enum mpc_sie_sec_attr_t attr)
271 {
272     enum mpc_sie_intern_error_t error;
273     uint32_t first_word_idx;
274     uint32_t first_word_mask;
275     uint32_t i;
276     uint32_t limit_word_mask;
277     uint32_t limit_word_idx;
278     uint32_t nr_words;
279     const struct mpc_sie_memory_range_t* range;
280     uint32_t word_value;
281     struct mpc_sie_reg_map_t* p_mpc =
282                                    (struct mpc_sie_reg_map_t*)dev->cfg->base;
283 
284     if(dev->data->is_initialized != true) {
285         return MPC_SIE_NOT_INIT;
286     }
287 
288     /* Get the bitmasks used to select the bits in the LUT */
289     error = get_lut_masks(dev, base, limit, &range, &first_word_idx, &nr_words,
290                           &first_word_mask, &limit_word_mask);
291 
292     limit_word_idx = first_word_idx + nr_words - 1;
293 
294     if(error != MPC_SIE_INTERN_ERR_NONE) {
295         /* Map internal error code lower than 0 to a generic errpr */
296         if(error < 0) {
297             return MPC_SIE_ERR_INVALID_RANGE;
298         }
299         return (enum mpc_sie_error_t)error;
300     }
301 
302     /*
303      * The memory range should allow accesses in with the wanted security
304      * attribute if it requires special attribute for successful accesses
305      */
306     if(range->attr != attr) {
307         return MPC_SIE_ERR_RANGE_SEC_ATTR_NON_COMPATIBLE;
308     }
309 
310     /*
311      * Starts changing actual configuration so issue DMB to ensure every
312      * transaction has completed by now
313      */
314     __DMB();
315 
316     /* Set the block index to the first word that will be updated */
317     p_mpc->blk_idx = first_word_idx;
318 
319     /* If only one word needs to be touched in the LUT */
320     if(nr_words == 1) {
321         word_value = p_mpc->blk_lutn;
322         if(attr == MPC_SIE_SEC_ATTR_NONSECURE) {
323             word_value |= first_word_mask;
324         } else {
325             word_value &= ~first_word_mask;
326         }
327 
328         /*
329          * Set the index again because full word read or write could have
330          * incremented it
331          */
332         p_mpc->blk_idx = first_word_idx;
333         p_mpc->blk_lutn = word_value;
334 
335         /* Commit the configuration change */
336         __DSB();
337         __ISB();
338 
339         return MPC_SIE_ERR_NONE;
340     }
341 
342     /* First word */
343     word_value = p_mpc->blk_lutn;
344     if(attr == MPC_SIE_SEC_ATTR_NONSECURE) {
345         word_value |= first_word_mask;
346     } else {
347         word_value &= ~first_word_mask;
348     }
349     /*
350      * Set the index again because full word read or write could have
351      * incremented it
352      */
353     p_mpc->blk_idx = first_word_idx;
354     /* Partially configure the first word */
355     p_mpc->blk_lutn = word_value;
356 
357     /* Fully configure the intermediate words if there are any */
358     for(i=first_word_idx+1; i<limit_word_idx; i++) {
359         p_mpc->blk_idx = i;
360         if(attr == MPC_SIE_SEC_ATTR_NONSECURE) {
361             p_mpc->blk_lutn = 0xFFFFFFFF;
362         } else {
363             p_mpc->blk_lutn = 0x00000000;
364         }
365     }
366 
367     /* Partially configure the limit word */
368     p_mpc->blk_idx = limit_word_idx;
369     word_value = p_mpc->blk_lutn;
370     if(attr == MPC_SIE_SEC_ATTR_NONSECURE) {
371         word_value |= limit_word_mask;
372     } else {
373         word_value &= ~limit_word_mask;
374     }
375     p_mpc->blk_idx = limit_word_idx;
376     p_mpc->blk_lutn = word_value;
377 
378     /* Commit the configuration change */
379     __DSB();
380     __ISB();
381 
382     return MPC_SIE_ERR_NONE;
383 }
384 
mpc_sie_get_region_config(struct mpc_sie_dev_t * dev,uint32_t base,uint32_t limit,enum mpc_sie_sec_attr_t * attr)385 enum mpc_sie_error_t mpc_sie_get_region_config(
386                                                struct mpc_sie_dev_t* dev,
387                                                uint32_t base, uint32_t limit,
388                                                enum mpc_sie_sec_attr_t* attr)
389 {
390     enum mpc_sie_sec_attr_t attr_prev;
391     uint32_t block_size;
392     uint32_t block_size_mask;
393     enum mpc_sie_intern_error_t error;
394     uint32_t first_word_idx;
395     uint32_t first_word_mask;
396     uint32_t i;
397     uint32_t limit_word_idx;
398     uint32_t limit_word_mask;
399     uint32_t nr_words;
400     struct mpc_sie_reg_map_t* p_mpc =
401                                    (struct mpc_sie_reg_map_t*)dev->cfg->base;
402     const struct mpc_sie_memory_range_t* range;
403     uint32_t word_value;
404 
405     if(dev->data->is_initialized != true) {
406         return MPC_SIE_NOT_INIT;
407     }
408 
409     if(attr == 0) {
410         return MPC_SIE_INVALID_ARG;
411     }
412 
413     /*
414      * Initialize the security attribute to mixed in case of early
415      * termination of this function. A caller that does not check the
416      * returned error will act as if it does not know anything about the
417      * region queried, which is the safest bet
418      */
419     *attr = MPC_SIE_SEC_ATTR_MIXED;
420 
421     /*
422      * If the base and limit are not aligned, align them and make sure
423      * that the resulting region fully includes the original region
424      */
425     block_size = (1 << (p_mpc->blk_cfg + MPC_SIE_BLK_CFG_OFFSET));
426 
427     block_size_mask = block_size - 1;
428     base &= ~(block_size_mask);
429     limit &= ~(block_size_mask);
430     limit += block_size - 1; /* Round to the upper block address,
431                               * and then remove one to get the preceding
432                               * address.
433                               */
434 
435     /* Get the bitmasks used to select the bits in the LUT */
436     error = get_lut_masks(dev, base, limit, &range, &first_word_idx, &nr_words,
437                           &first_word_mask, &limit_word_mask);
438 
439     limit_word_idx = first_word_idx+nr_words - 1;
440 
441     if(error != MPC_SIE_INTERN_ERR_NONE) {
442         /* Map internal error code lower than 0 to generic error */
443         if(error < 0) {
444             return MPC_SIE_ERR_INVALID_RANGE;
445         }
446         return (enum mpc_sie_error_t)error;
447     }
448 
449     /* Set the block index to the first word that will be updated */
450     p_mpc->blk_idx = first_word_idx;
451 
452     /* If only one word needs to be touched in the LUT */
453     if(nr_words == 1) {
454         word_value = p_mpc->blk_lutn;
455         word_value &= first_word_mask;
456         if(word_value == 0) {
457             *attr = MPC_SIE_SEC_ATTR_SECURE;
458         /*
459          * If there are differences between the mask and the word value,
460          * it means that the security attributes of blocks are mixed
461          */
462         } else if(word_value ^ first_word_mask) {
463             *attr = MPC_SIE_SEC_ATTR_MIXED;
464         } else {
465             *attr = MPC_SIE_SEC_ATTR_NONSECURE;
466         }
467         return MPC_SIE_ERR_NONE;
468     }
469 
470     /* Get the partial configuration of the first word */
471     word_value = p_mpc->blk_lutn & first_word_mask;
472     if(word_value == 0x00000000) {
473         *attr = MPC_SIE_SEC_ATTR_SECURE;
474     } else if(word_value ^ first_word_mask) {
475         *attr = MPC_SIE_SEC_ATTR_MIXED;
476         /*
477          * Bail out as the security attribute will be the same regardless
478          * of the configuration of other blocks
479          */
480         return MPC_SIE_ERR_NONE;
481     } else {
482         *attr = MPC_SIE_SEC_ATTR_NONSECURE;
483     }
484     /*
485      * Store the current found attribute, to check that all the blocks indeed
486      * have the same security attribute.
487      */
488     attr_prev = *attr;
489 
490     /* Get the configuration of the intermediate words if there are any */
491     for(i=first_word_idx+1; i<limit_word_idx; i++) {
492         p_mpc->blk_idx = i;
493         word_value = p_mpc->blk_lutn;
494         if(word_value == 0x00000000) {
495             *attr = MPC_SIE_SEC_ATTR_SECURE;
496         } else if(word_value == 0xFFFFFFFF) {
497             *attr = MPC_SIE_SEC_ATTR_NONSECURE;
498         } else {
499             *attr = MPC_SIE_SEC_ATTR_MIXED;
500             return MPC_SIE_ERR_NONE;
501         }
502 
503         /* If the attribute is different than the one found before, bail out */
504         if(*attr != attr_prev) {
505             *attr = MPC_SIE_SEC_ATTR_MIXED;
506             return MPC_SIE_ERR_NONE;
507         }
508         attr_prev = *attr;
509     }
510 
511     /* Get the partial configuration of the limit word */
512     p_mpc->blk_idx = limit_word_idx;
513     word_value = p_mpc->blk_lutn & limit_word_mask;
514     if(word_value == 0x00000000) {
515         *attr = MPC_SIE_SEC_ATTR_SECURE;
516     } else if(word_value ^ first_word_mask) {
517         *attr = MPC_SIE_SEC_ATTR_MIXED;
518         return MPC_SIE_ERR_NONE;
519     } else {
520         *attr = MPC_SIE_SEC_ATTR_NONSECURE;
521     }
522 
523     if(*attr != attr_prev) {
524         *attr = MPC_SIE_SEC_ATTR_MIXED;
525         return MPC_SIE_ERR_NONE;
526     }
527 
528     return MPC_SIE_ERR_NONE;
529 }
530 
mpc_sie_get_ctrl(struct mpc_sie_dev_t * dev,uint32_t * ctrl_val)531 enum mpc_sie_error_t mpc_sie_get_ctrl(struct mpc_sie_dev_t* dev,
532                                       uint32_t* ctrl_val)
533 {
534     struct mpc_sie_reg_map_t* p_mpc =
535                                    (struct mpc_sie_reg_map_t*)dev->cfg->base;
536 
537     if(dev->data->is_initialized != true) {
538         return MPC_SIE_NOT_INIT;
539     }
540 
541     if(ctrl_val == 0) {
542         return MPC_SIE_INVALID_ARG;
543     }
544 
545     *ctrl_val = p_mpc->ctrl;
546 
547     return MPC_SIE_ERR_NONE;
548 }
549 
mpc_sie_set_ctrl(struct mpc_sie_dev_t * dev,uint32_t mpc_ctrl)550 enum mpc_sie_error_t mpc_sie_set_ctrl(struct mpc_sie_dev_t* dev,
551                                       uint32_t mpc_ctrl)
552 {
553     struct mpc_sie_reg_map_t* p_mpc =
554                                    (struct mpc_sie_reg_map_t*)dev->cfg->base;
555 
556     if(dev->data->is_initialized != true) {
557         return MPC_SIE_NOT_INIT;
558     }
559 
560     p_mpc->ctrl = mpc_ctrl;
561 
562     return MPC_SIE_ERR_NONE;
563 }
564 
mpc_sie_get_sec_resp(struct mpc_sie_dev_t * dev,enum mpc_sie_sec_resp_t * sec_rep)565 enum mpc_sie_error_t mpc_sie_get_sec_resp(struct mpc_sie_dev_t* dev,
566                                           enum mpc_sie_sec_resp_t* sec_rep)
567 {
568     struct mpc_sie_reg_map_t* p_mpc =
569                                    (struct mpc_sie_reg_map_t*)dev->cfg->base;
570     bool gating_present = false;
571 
572     if(dev->data->is_initialized != true) {
573         return MPC_SIE_NOT_INIT;
574     }
575 
576     if(sec_rep == NULL) {
577         return MPC_SIE_INVALID_ARG;
578     }
579 
580     if (dev->data->sie_version == SIE200) {
581         if(p_mpc->ctrl & MPC_SIE200_CTRL_SEC_RESP) {
582             *sec_rep = MPC_SIE_RESP_BUS_ERROR;
583         } else {
584             *sec_rep = MPC_SIE_RESP_RAZ_WI;
585         }
586 
587     } else if (dev->data->sie_version == SIE300) {
588         mpc_sie_is_gating_present(dev, &gating_present);
589         if (!gating_present) {
590             return MPC_SIE_ERR_GATING_NOT_PRESENT;
591         }
592 
593         if(p_mpc->ctrl & MPC_SIE300_CTRL_SEC_RESP) {
594             /* MPC returns a BUS ERROR response */
595             *sec_rep = MPC_SIE_RESP_BUS_ERROR;
596         } else {
597             /* MPC sets the ready signals LOW, which stalls any transactions */
598             *sec_rep = MPC_SIE_RESP_WAIT_GATING_DISABLED;
599         }
600     } else {
601         return MPC_SIE_UNSUPPORTED_HARDWARE_VERSION;
602     }
603 
604     return MPC_SIE_ERR_NONE;
605 }
606 
mpc_sie_set_sec_resp(struct mpc_sie_dev_t * dev,enum mpc_sie_sec_resp_t sec_rep)607 enum mpc_sie_error_t  mpc_sie_set_sec_resp(struct mpc_sie_dev_t* dev,
608                                            enum mpc_sie_sec_resp_t sec_rep)
609 {
610     struct mpc_sie_reg_map_t* p_mpc =
611                                    (struct mpc_sie_reg_map_t*)dev->cfg->base;
612     bool gating_present = false;
613 
614     if(dev->data->is_initialized != true) {
615         return MPC_SIE_NOT_INIT;
616     }
617 
618     if (dev->data->sie_version == SIE200) {
619         if (sec_rep == MPC_SIE_RESP_BUS_ERROR) {
620             p_mpc->ctrl |= MPC_SIE200_CTRL_SEC_RESP;
621         } else if (sec_rep == MPC_SIE_RESP_RAZ_WI) {
622             p_mpc->ctrl &= ~MPC_SIE200_CTRL_SEC_RESP;
623         } else {
624             return MPC_SIE_INVALID_ARG;
625         }
626 
627     } else if (dev->data->sie_version == SIE300) {
628         mpc_sie_is_gating_present(dev, &gating_present);
629         if (!gating_present) {
630             return MPC_SIE_ERR_GATING_NOT_PRESENT;
631         }
632 
633         if (sec_rep == MPC_SIE_RESP_BUS_ERROR) {
634             p_mpc->ctrl |= MPC_SIE300_CTRL_SEC_RESP;
635         } else if (sec_rep == MPC_SIE_RESP_WAIT_GATING_DISABLED) {
636             p_mpc->ctrl &= ~MPC_SIE300_CTRL_SEC_RESP;
637         } else {
638             return MPC_SIE_INVALID_ARG;
639         }
640 
641     } else {
642         return MPC_SIE_UNSUPPORTED_HARDWARE_VERSION;
643     }
644 
645     return MPC_SIE_ERR_NONE;
646 }
647 
mpc_sie_irq_enable(struct mpc_sie_dev_t * dev)648 enum mpc_sie_error_t mpc_sie_irq_enable(struct mpc_sie_dev_t* dev)
649 {
650     struct mpc_sie_reg_map_t* p_mpc =
651                                    (struct mpc_sie_reg_map_t*)dev->cfg->base;
652 
653     if(dev->data->is_initialized != true) {
654         return MPC_SIE_NOT_INIT;
655     }
656 
657     p_mpc->int_en |= MPC_SIE_INT_BIT;
658 
659     return MPC_SIE_ERR_NONE;
660 }
661 
mpc_sie_irq_disable(struct mpc_sie_dev_t * dev)662 void mpc_sie_irq_disable(struct mpc_sie_dev_t* dev)
663 {
664     struct mpc_sie_reg_map_t* p_mpc =
665                                    (struct mpc_sie_reg_map_t*)dev->cfg->base;
666 
667     p_mpc->int_en &= ~MPC_SIE_INT_BIT;
668 }
669 
mpc_sie_clear_irq(struct mpc_sie_dev_t * dev)670 void mpc_sie_clear_irq(struct mpc_sie_dev_t* dev)
671 {
672     struct mpc_sie_reg_map_t* p_mpc =
673                                    (struct mpc_sie_reg_map_t*)dev->cfg->base;
674 
675     p_mpc->int_clear = MPC_SIE_INT_BIT;
676 }
677 
mpc_sie_irq_state(struct mpc_sie_dev_t * dev)678 uint32_t mpc_sie_irq_state(struct mpc_sie_dev_t* dev)
679 {
680     struct mpc_sie_reg_map_t* p_mpc =
681                                    (struct mpc_sie_reg_map_t*)dev->cfg->base;
682 
683     return (p_mpc->int_stat & MPC_SIE_INT_BIT);
684 }
685 
mpc_sie_lock_down(struct mpc_sie_dev_t * dev)686 enum mpc_sie_error_t mpc_sie_lock_down(struct mpc_sie_dev_t* dev)
687 {
688     struct mpc_sie_reg_map_t* p_mpc =
689                                    (struct mpc_sie_reg_map_t*)dev->cfg->base;
690 
691     if(dev->data->is_initialized != true) {
692         return MPC_SIE_NOT_INIT;
693     }
694 
695     p_mpc->ctrl |= (MPC_SIE_CTRL_AUTOINCREMENT
696                     | MPC_SIE_CTRL_SEC_LOCK_DOWN);
697 
698     return MPC_SIE_ERR_NONE;
699 }
700 
mpc_sie_is_gating_present(struct mpc_sie_dev_t * dev,bool * gating_present)701 enum mpc_sie_error_t mpc_sie_is_gating_present(struct mpc_sie_dev_t* dev,
702                                                bool* gating_present)
703 {
704     struct mpc_sie_reg_map_t* p_mpc =
705                                    (struct mpc_sie_reg_map_t*)dev->cfg->base;
706 
707     if(dev->data->is_initialized != true) {
708         return MPC_SIE_NOT_INIT;
709     }
710 
711     if (dev->data->sie_version != SIE300) {
712         return MPC_SIE_UNSUPPORTED_HARDWARE_VERSION;
713     }
714 
715     *gating_present = (bool)(p_mpc->ctrl & MPC_SIE300_CTRL_GATE_PRESENT);
716 
717     return MPC_SIE_ERR_NONE;
718 }
719 
get_sie_version(struct mpc_sie_dev_t * dev)720 uint32_t get_sie_version(struct mpc_sie_dev_t* dev)
721 {
722     struct mpc_sie_reg_map_t* p_mpc =
723                                    (struct mpc_sie_reg_map_t*)dev->cfg->base;
724 
725     return p_mpc->pidr0 & MPC_PIDR0_SIE_VERSION_MASK;
726 }
727 
mpc_sie_get_gate_ack(struct mpc_sie_dev_t * dev)728 bool mpc_sie_get_gate_ack(struct mpc_sie_dev_t* dev)
729 {
730     struct mpc_sie_reg_map_t* p_mpc =
731                                    (struct mpc_sie_reg_map_t*)dev->cfg->base;
732 
733     return (bool)(p_mpc->ctrl & MPC_SIE300_CTRL_GATE_ACK);
734 }
735 
mpc_sie_request_gating(struct mpc_sie_dev_t * dev)736 void mpc_sie_request_gating(struct mpc_sie_dev_t* dev)
737 {
738     struct mpc_sie_reg_map_t* p_mpc =
739                                    (struct mpc_sie_reg_map_t*)dev->cfg->base;
740 
741     p_mpc->ctrl |= MPC_SIE300_CTRL_GATE_REQ;
742 }
743 
mpc_sie_release_gating(struct mpc_sie_dev_t * dev)744 void mpc_sie_release_gating(struct mpc_sie_dev_t* dev)
745 {
746     struct mpc_sie_reg_map_t* p_mpc =
747                                    (struct mpc_sie_reg_map_t*)dev->cfg->base;
748 
749     p_mpc->ctrl &= ~MPC_SIE300_CTRL_GATE_REQ;
750 }
751