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