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