blob: 04632900b3ef593ed514a204341c7ddc1b3b8811 [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
Per Åstrand79929ff2021-01-26 14:42:43 +010018#include <stdbool.h>
Anton Moberg908a07c2021-04-08 09:50:57 +020019#include <stddef.h>
Per Åstrand79929ff2021-01-26 14:42:43 +010020
21#include "cmsis_compiler.h"
22
23/* Values for hardware version in PIDR0 reg */
Anton Moberg908a07c2021-04-08 09:50:57 +020024#define SIE200 0x60
25#define SIE300 0x65
Per Åstrand79929ff2021-01-26 14:42:43 +010026
Anton Moberg908a07c2021-04-08 09:50:57 +020027#define MPC_SIE_BLK_CFG_OFFSET 5U
Per Åstrand79929ff2021-01-26 14:42:43 +010028
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 */
Anton Moberg908a07c2021-04-08 09:50:57 +020034#define MPC_SIE200_CTRL_SEC_RESP \
35 (1UL << 4UL) /* MPC fault triggers a \
36 * bus error \
37 */
38#define MPC_SIE300_CTRL_GATE_REQ \
39 (1UL << 6UL) /* Request for gating \
40 * incoming transfers \
41 */
42#define MPC_SIE300_CTRL_GATE_ACK \
43 (1UL << 7UL) /* Acknowledge for gating \
44 * incoming transfers \
45 */
46#define MPC_SIE_CTRL_AUTOINCREMENT (1UL << 8UL) /* BLK_IDX auto increment */
47#define MPC_SIE300_CTRL_SEC_RESP \
48 (1UL << 16UL) /* Response type when SW \
49 * asks to gate the transfer \
50 */
51#define MPC_SIE300_CTRL_GATE_PRESENT (1UL << 23UL) /* Gating feature present */
52#define MPC_SIE_CTRL_SEC_LOCK_DOWN (1UL << 31UL) /* MPC Security lock down */
Per Åstrand79929ff2021-01-26 14:42:43 +010053
54/* PIDR register bit masks */
Anton Moberg908a07c2021-04-08 09:50:57 +020055#define MPC_PIDR0_SIE_VERSION_MASK ((1UL << 8UL) - 1UL)
Per Åstrand79929ff2021-01-26 14:42:43 +010056
57/* ARM MPC interrupt */
Anton Moberg908a07c2021-04-08 09:50:57 +020058#define MPC_SIE_INT_BIT (1UL)
Per Åstrand79929ff2021-01-26 14:42:43 +010059
60/* Error code returned by the internal driver functions */
61enum mpc_sie_intern_error_t {
Anton Moberg908a07c2021-04-08 09:50:57 +020062 MPC_SIE_INTERN_ERR_NONE = MPC_SIE_ERR_NONE,
63 MPC_SIE_INTERN_ERR_NOT_IN_RANGE = MPC_SIE_ERR_NOT_IN_RANGE,
64 MPC_SIE_INTERN_ERR_NOT_ALIGNED = MPC_SIE_ERR_NOT_ALIGNED,
65 MPC_SIE_INTERN_ERR_INVALID_RANGE = MPC_SIE_ERR_INVALID_RANGE,
66 MPC_INTERN_ERR_RANGE_SEC_ATTR_NON_COMPATIBLE = MPC_SIE_ERR_RANGE_SEC_ATTR_NON_COMPATIBLE,
Per Åstrand79929ff2021-01-26 14:42:43 +010067 /* Calculated block index
68 * is higher than the maximum allowed by the MPC. It should never
69 * happen unless the controlled ranges of the MPC are misconfigured
70 * in the driver or if the IP has not enough LUTs to cover the
71 * range, due to wrong reported block size for example.
72 */
73 MPC_SIE_INTERN_ERR_BLK_IDX_TOO_HIGH = -1,
74
75};
76
77/* ARM MPC memory mapped register access structure */
78struct mpc_sie_reg_map_t {
Anton Moberg908a07c2021-04-08 09:50:57 +020079 volatile uint32_t ctrl; /* (R/W) MPC Control */
80 volatile uint32_t reserved[3]; /* Reserved */
81 volatile uint32_t blk_max; /* (R/ ) Maximum value of block based index */
82 volatile uint32_t blk_cfg; /* (R/ ) Block configuration */
83 volatile uint32_t blk_idx; /* (R/W) Index value for accessing block
84 * based look up table
85 */
86 volatile uint32_t blk_lutn; /* (R/W) Block based gating
87 * Look Up Table (LUT)
88 */
89 volatile uint32_t int_stat; /* (R/ ) Interrupt state */
90 volatile uint32_t int_clear; /* ( /W) Interrupt clear */
91 volatile uint32_t int_en; /* (R/W) Interrupt enable */
92 volatile uint32_t int_info1; /* (R/ ) Interrupt information 1 */
93 volatile uint32_t int_info2; /* (R/ ) Interrupt information 2 */
94 volatile uint32_t int_set; /* ( /W) Interrupt set. Debug purpose only */
Per Åstrand79929ff2021-01-26 14:42:43 +010095 volatile uint32_t reserved2[998]; /* Reserved */
Anton Moberg908a07c2021-04-08 09:50:57 +020096 volatile uint32_t pidr4; /* (R/ ) Peripheral ID 4 */
97 volatile uint32_t pidr5; /* (R/ ) Peripheral ID 5 */
98 volatile uint32_t pidr6; /* (R/ ) Peripheral ID 6 */
99 volatile uint32_t pidr7; /* (R/ ) Peripheral ID 7 */
100 volatile uint32_t pidr0; /* (R/ ) Peripheral ID 0 */
101 volatile uint32_t pidr1; /* (R/ ) Peripheral ID 1 */
102 volatile uint32_t pidr2; /* (R/ ) Peripheral ID 2 */
103 volatile uint32_t pidr3; /* (R/ ) Peripheral ID 3 */
104 volatile uint32_t cidr0; /* (R/ ) Component ID 0 */
105 volatile uint32_t cidr1; /* (R/ ) Component ID 1 */
106 volatile uint32_t cidr2; /* (R/ ) Component ID 2 */
107 volatile uint32_t cidr3; /* (R/ ) Component ID 3 */
Per Åstrand79929ff2021-01-26 14:42:43 +0100108};
109
110/*
111 * Checks if the address is controlled by the MPC and returns
112 * the range index in which it is contained.
113 *
114 * \param[in] dev MPC device to initialize \ref mpc_sie_dev_t
115 * \param[in] addr Address to check if it is controlled by MPC.
116 * \param[out] addr_range Range index in which it is contained.
117 *
118 * \return True if the base is controller by the range list, false otherwise.
119 */
Anton Moberg908a07c2021-04-08 09:50:57 +0200120static uint32_t
121is_ctrl_by_range_list(struct mpc_sie_dev_t *dev, uint32_t addr, const struct mpc_sie_memory_range_t **addr_range) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100122 uint32_t i;
Anton Moberg908a07c2021-04-08 09:50:57 +0200123 const struct mpc_sie_memory_range_t *range;
Per Åstrand79929ff2021-01-26 14:42:43 +0100124
Anton Moberg908a07c2021-04-08 09:50:57 +0200125 for (i = 0; i < dev->data->nbr_of_ranges; i++) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100126 range = dev->data->range_list[i];
Anton Moberg908a07c2021-04-08 09:50:57 +0200127 if (addr >= range->base && addr <= range->limit) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100128 *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 */
Anton Moberg908a07c2021-04-08 09:50:57 +0200155static enum mpc_sie_intern_error_t get_lut_masks(struct mpc_sie_dev_t *dev,
156 const uint32_t base,
157 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 const struct mpc_sie_memory_range_t *base_range;
Per Åstrand79929ff2021-01-26 14:42:43 +0100164 uint32_t block_size;
165 uint32_t base_block_idx;
166 uint32_t base_word_idx;
167 uint32_t blk_max;
Anton Moberg908a07c2021-04-08 09:50:57 +0200168 const struct mpc_sie_memory_range_t *limit_range;
Per Åstrand79929ff2021-01-26 14:42:43 +0100169 uint32_t limit_block_idx;
170 uint32_t limit_word_idx;
171 uint32_t mask;
172 uint32_t norm_base;
173 uint32_t norm_limit;
Anton Moberg908a07c2021-04-08 09:50:57 +0200174 struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
Per Åstrand79929ff2021-01-26 14:42:43 +0100175
176 /*
177 * Check that the addresses are within the controlled regions
178 * of this MPC
179 */
Anton Moberg908a07c2021-04-08 09:50:57 +0200180 if (!is_ctrl_by_range_list(dev, base, &base_range) || !is_ctrl_by_range_list(dev, limit, &limit_range)) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100181 return MPC_SIE_INTERN_ERR_NOT_IN_RANGE;
182 }
183
184 /* Base and limit should be part of the same range */
Anton Moberg908a07c2021-04-08 09:50:57 +0200185 if (base_range != limit_range) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100186 return MPC_SIE_INTERN_ERR_INVALID_RANGE;
187 }
188 *range = base_range;
189
190 block_size = (1 << (p_mpc->blk_cfg + MPC_SIE_BLK_CFG_OFFSET));
191
192 /* Base and limit+1 addresses must be aligned on the MPC block size */
Anton Moberg908a07c2021-04-08 09:50:57 +0200193 if (base % block_size || (limit + 1) % block_size) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100194 return MPC_SIE_INTERN_ERR_NOT_ALIGNED;
195 }
196
197 /*
198 * Get a normalized address that is an offset from the beginning
199 * of the lowest range controlled by the MPC
200 */
201 norm_base = (base - base_range->base) + base_range->range_offset;
202 norm_limit = (limit - base_range->base) + base_range->range_offset;
203
204 /*
205 * Calculate block index and to which 32 bits word it belongs
206 */
Anton Moberg908a07c2021-04-08 09:50:57 +0200207 limit_block_idx = norm_limit / block_size;
208 limit_word_idx = limit_block_idx / 32;
Per Åstrand79929ff2021-01-26 14:42:43 +0100209
Anton Moberg908a07c2021-04-08 09:50:57 +0200210 base_block_idx = norm_base / block_size;
211 base_word_idx = base_block_idx / 32;
Per Åstrand79929ff2021-01-26 14:42:43 +0100212
Anton Moberg908a07c2021-04-08 09:50:57 +0200213 if (base_block_idx > limit_block_idx) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100214 return MPC_SIE_INTERN_ERR_INVALID_RANGE;
215 }
216
217 /* Transmit the information to the caller */
Anton Moberg908a07c2021-04-08 09:50:57 +0200218 *nr_words = limit_word_idx - base_word_idx + 1;
Per Åstrand79929ff2021-01-26 14:42:43 +0100219 *first_word_idx = base_word_idx;
220
221 /* Limit to the highest block that can be configured */
222 blk_max = p_mpc->blk_max;
223
Anton Moberg908a07c2021-04-08 09:50:57 +0200224 if ((limit_word_idx > blk_max) || (base_word_idx > blk_max)) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100225 return MPC_SIE_INTERN_ERR_BLK_IDX_TOO_HIGH;
226 }
227
228 /*
229 * Create the mask for the first word to only select the limit N bits
230 */
231 *first_word_mask = ~((1 << (base_block_idx % 32)) - 1);
232
233 /*
234 * Create the mask for the limit word to select only the first M bits.
235 */
Anton Moberg908a07c2021-04-08 09:50:57 +0200236 *limit_word_mask = (1 << ((limit_block_idx + 1) % 32)) - 1;
Per Åstrand79929ff2021-01-26 14:42:43 +0100237 /*
238 * If limit_word_mask is 0, it means that the limit touched block index is
239 * the limit in its word, so the limit word mask has all its bits selected
240 */
Anton Moberg908a07c2021-04-08 09:50:57 +0200241 if (*limit_word_mask == 0) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100242 *limit_word_mask = 0xFFFFFFFF;
243 }
244
245 /*
246 * If the blocks to configure are all packed in one word, only
247 * touch this word.
248 * Code using the computed masks should test if this mask
249 * is non-zero, and if so, only use this one instead of the limit_word_mask
250 * and first_word_mask.
251 * As the only bits that are the same in both masks are the 1 that we want
252 * to select, just use XOR to extract them.
253 */
Anton Moberg908a07c2021-04-08 09:50:57 +0200254 if (base_word_idx == limit_word_idx) {
255 mask = ~(*first_word_mask ^ *limit_word_mask);
Per Åstrand79929ff2021-01-26 14:42:43 +0100256 *first_word_mask = mask;
257 *limit_word_mask = mask;
258 }
259
260 return MPC_SIE_INTERN_ERR_NONE;
261}
262
Anton Moberg908a07c2021-04-08 09:50:57 +0200263enum mpc_sie_error_t
264mpc_sie_init(struct mpc_sie_dev_t *dev, const struct mpc_sie_memory_range_t **range_list, uint8_t nbr_of_ranges) {
265 if ((range_list == NULL) || (nbr_of_ranges == 0)) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100266 return MPC_SIE_INVALID_ARG;
267 }
268
269 dev->data->sie_version = get_sie_version(dev);
270
Anton Moberg908a07c2021-04-08 09:50:57 +0200271 if ((dev->data->sie_version != SIE200) && (dev->data->sie_version != SIE300)) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100272 return MPC_SIE_UNSUPPORTED_HARDWARE_VERSION;
273 }
274
Anton Moberg908a07c2021-04-08 09:50:57 +0200275 dev->data->range_list = range_list;
276 dev->data->nbr_of_ranges = nbr_of_ranges;
Per Åstrand79929ff2021-01-26 14:42:43 +0100277 dev->data->is_initialized = true;
278
279 return MPC_SIE_ERR_NONE;
280}
281
Anton Moberg908a07c2021-04-08 09:50:57 +0200282enum mpc_sie_error_t mpc_sie_get_block_size(struct mpc_sie_dev_t *dev, uint32_t *blk_size) {
283 struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
Per Åstrand79929ff2021-01-26 14:42:43 +0100284
Anton Moberg908a07c2021-04-08 09:50:57 +0200285 if (dev->data->is_initialized != true) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100286 return MPC_SIE_NOT_INIT;
287 }
288
Anton Moberg908a07c2021-04-08 09:50:57 +0200289 if (blk_size == 0) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100290 return MPC_SIE_INVALID_ARG;
291 }
292
293 /* Calculate the block size in byte according to the manual */
294 *blk_size = (1 << (p_mpc->blk_cfg + MPC_SIE_BLK_CFG_OFFSET));
295
296 return MPC_SIE_ERR_NONE;
297}
298
Anton Moberg908a07c2021-04-08 09:50:57 +0200299enum mpc_sie_error_t mpc_sie_config_region(struct mpc_sie_dev_t *dev,
Per Åstrand79929ff2021-01-26 14:42:43 +0100300 const uint32_t base,
301 const uint32_t limit,
Anton Moberg908a07c2021-04-08 09:50:57 +0200302 enum mpc_sie_sec_attr_t attr) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100303 enum mpc_sie_intern_error_t error;
304 uint32_t first_word_idx;
305 uint32_t first_word_mask;
306 uint32_t i;
307 uint32_t limit_word_mask;
308 uint32_t limit_word_idx;
309 uint32_t nr_words;
Anton Moberg908a07c2021-04-08 09:50:57 +0200310 const struct mpc_sie_memory_range_t *range;
Per Åstrand79929ff2021-01-26 14:42:43 +0100311 uint32_t word_value;
Anton Moberg908a07c2021-04-08 09:50:57 +0200312 struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
Per Åstrand79929ff2021-01-26 14:42:43 +0100313
Anton Moberg908a07c2021-04-08 09:50:57 +0200314 if (dev->data->is_initialized != true) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100315 return MPC_SIE_NOT_INIT;
316 }
317
318 /* Get the bitmasks used to select the bits in the LUT */
Anton Moberg908a07c2021-04-08 09:50:57 +0200319 error = get_lut_masks(dev, base, limit, &range, &first_word_idx, &nr_words, &first_word_mask, &limit_word_mask);
Per Åstrand79929ff2021-01-26 14:42:43 +0100320
321 limit_word_idx = first_word_idx + nr_words - 1;
322
Anton Moberg908a07c2021-04-08 09:50:57 +0200323 if (error != MPC_SIE_INTERN_ERR_NONE) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100324 /* Map internal error code lower than 0 to a generic errpr */
Anton Moberg908a07c2021-04-08 09:50:57 +0200325 if (error < 0) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100326 return MPC_SIE_ERR_INVALID_RANGE;
327 }
328 return (enum mpc_sie_error_t)error;
329 }
330
331 /*
332 * The memory range should allow accesses in with the wanted security
333 * attribute if it requires special attribute for successful accesses
334 */
Anton Moberg908a07c2021-04-08 09:50:57 +0200335 if (range->attr != attr) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100336 return MPC_SIE_ERR_RANGE_SEC_ATTR_NON_COMPATIBLE;
337 }
338
339 /*
340 * Starts changing actual configuration so issue DMB to ensure every
341 * transaction has completed by now
342 */
343 __DMB();
344
345 /* Set the block index to the first word that will be updated */
346 p_mpc->blk_idx = first_word_idx;
347
348 /* If only one word needs to be touched in the LUT */
Anton Moberg908a07c2021-04-08 09:50:57 +0200349 if (nr_words == 1) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100350 word_value = p_mpc->blk_lutn;
Anton Moberg908a07c2021-04-08 09:50:57 +0200351 if (attr == MPC_SIE_SEC_ATTR_NONSECURE) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100352 word_value |= first_word_mask;
353 } else {
354 word_value &= ~first_word_mask;
355 }
356
357 /*
358 * Set the index again because full word read or write could have
359 * incremented it
360 */
Anton Moberg908a07c2021-04-08 09:50:57 +0200361 p_mpc->blk_idx = first_word_idx;
Per Åstrand79929ff2021-01-26 14:42:43 +0100362 p_mpc->blk_lutn = word_value;
363
364 /* Commit the configuration change */
365 __DSB();
366 __ISB();
367
368 return MPC_SIE_ERR_NONE;
369 }
370
371 /* First word */
372 word_value = p_mpc->blk_lutn;
Anton Moberg908a07c2021-04-08 09:50:57 +0200373 if (attr == MPC_SIE_SEC_ATTR_NONSECURE) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100374 word_value |= first_word_mask;
375 } else {
376 word_value &= ~first_word_mask;
377 }
378 /*
379 * Set the index again because full word read or write could have
380 * incremented it
381 */
382 p_mpc->blk_idx = first_word_idx;
383 /* Partially configure the first word */
384 p_mpc->blk_lutn = word_value;
385
386 /* Fully configure the intermediate words if there are any */
Anton Moberg908a07c2021-04-08 09:50:57 +0200387 for (i = first_word_idx + 1; i < limit_word_idx; i++) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100388 p_mpc->blk_idx = i;
Anton Moberg908a07c2021-04-08 09:50:57 +0200389 if (attr == MPC_SIE_SEC_ATTR_NONSECURE) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100390 p_mpc->blk_lutn = 0xFFFFFFFF;
391 } else {
392 p_mpc->blk_lutn = 0x00000000;
393 }
394 }
395
396 /* Partially configure the limit word */
397 p_mpc->blk_idx = limit_word_idx;
Anton Moberg908a07c2021-04-08 09:50:57 +0200398 word_value = p_mpc->blk_lutn;
399 if (attr == MPC_SIE_SEC_ATTR_NONSECURE) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100400 word_value |= limit_word_mask;
401 } else {
402 word_value &= ~limit_word_mask;
403 }
Anton Moberg908a07c2021-04-08 09:50:57 +0200404 p_mpc->blk_idx = limit_word_idx;
Per Åstrand79929ff2021-01-26 14:42:43 +0100405 p_mpc->blk_lutn = word_value;
406
407 /* Commit the configuration change */
408 __DSB();
409 __ISB();
410
411 return MPC_SIE_ERR_NONE;
412}
413
Anton Moberg908a07c2021-04-08 09:50:57 +0200414enum mpc_sie_error_t
415mpc_sie_get_region_config(struct mpc_sie_dev_t *dev, uint32_t base, uint32_t limit, enum mpc_sie_sec_attr_t *attr) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100416 enum mpc_sie_sec_attr_t attr_prev;
417 uint32_t block_size;
418 uint32_t block_size_mask;
419 enum mpc_sie_intern_error_t error;
420 uint32_t first_word_idx;
421 uint32_t first_word_mask;
422 uint32_t i;
423 uint32_t limit_word_idx;
424 uint32_t limit_word_mask;
425 uint32_t nr_words;
Anton Moberg908a07c2021-04-08 09:50:57 +0200426 struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
427 const struct mpc_sie_memory_range_t *range;
Per Åstrand79929ff2021-01-26 14:42:43 +0100428 uint32_t word_value;
429
Anton Moberg908a07c2021-04-08 09:50:57 +0200430 if (dev->data->is_initialized != true) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100431 return MPC_SIE_NOT_INIT;
432 }
433
Anton Moberg908a07c2021-04-08 09:50:57 +0200434 if (attr == 0) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100435 return MPC_SIE_INVALID_ARG;
436 }
437
438 /*
439 * Initialize the security attribute to mixed in case of early
440 * termination of this function. A caller that does not check the
441 * returned error will act as if it does not know anything about the
442 * region queried, which is the safest bet
443 */
444 *attr = MPC_SIE_SEC_ATTR_MIXED;
445
446 /*
447 * If the base and limit are not aligned, align them and make sure
448 * that the resulting region fully includes the original region
449 */
450 block_size = (1 << (p_mpc->blk_cfg + MPC_SIE_BLK_CFG_OFFSET));
451
452 block_size_mask = block_size - 1;
453 base &= ~(block_size_mask);
454 limit &= ~(block_size_mask);
455 limit += block_size - 1; /* Round to the upper block address,
456 * and then remove one to get the preceding
457 * address.
458 */
459
460 /* Get the bitmasks used to select the bits in the LUT */
Anton Moberg908a07c2021-04-08 09:50:57 +0200461 error = get_lut_masks(dev, base, limit, &range, &first_word_idx, &nr_words, &first_word_mask, &limit_word_mask);
Per Åstrand79929ff2021-01-26 14:42:43 +0100462
Anton Moberg908a07c2021-04-08 09:50:57 +0200463 limit_word_idx = first_word_idx + nr_words - 1;
Per Åstrand79929ff2021-01-26 14:42:43 +0100464
Anton Moberg908a07c2021-04-08 09:50:57 +0200465 if (error != MPC_SIE_INTERN_ERR_NONE) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100466 /* Map internal error code lower than 0 to generic error */
Anton Moberg908a07c2021-04-08 09:50:57 +0200467 if (error < 0) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100468 return MPC_SIE_ERR_INVALID_RANGE;
469 }
470 return (enum mpc_sie_error_t)error;
471 }
472
473 /* Set the block index to the first word that will be updated */
474 p_mpc->blk_idx = first_word_idx;
475
476 /* If only one word needs to be touched in the LUT */
Anton Moberg908a07c2021-04-08 09:50:57 +0200477 if (nr_words == 1) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100478 word_value = p_mpc->blk_lutn;
479 word_value &= first_word_mask;
Anton Moberg908a07c2021-04-08 09:50:57 +0200480 if (word_value == 0) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100481 *attr = MPC_SIE_SEC_ATTR_SECURE;
Anton Moberg908a07c2021-04-08 09:50:57 +0200482 /*
483 * If there are differences between the mask and the word value,
484 * it means that the security attributes of blocks are mixed
485 */
486 } else if (word_value ^ first_word_mask) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100487 *attr = MPC_SIE_SEC_ATTR_MIXED;
488 } else {
489 *attr = MPC_SIE_SEC_ATTR_NONSECURE;
490 }
491 return MPC_SIE_ERR_NONE;
492 }
493
494 /* Get the partial configuration of the first word */
495 word_value = p_mpc->blk_lutn & first_word_mask;
Anton Moberg908a07c2021-04-08 09:50:57 +0200496 if (word_value == 0x00000000) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100497 *attr = MPC_SIE_SEC_ATTR_SECURE;
Anton Moberg908a07c2021-04-08 09:50:57 +0200498 } else if (word_value ^ first_word_mask) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100499 *attr = MPC_SIE_SEC_ATTR_MIXED;
500 /*
501 * Bail out as the security attribute will be the same regardless
502 * of the configuration of other blocks
503 */
504 return MPC_SIE_ERR_NONE;
505 } else {
506 *attr = MPC_SIE_SEC_ATTR_NONSECURE;
507 }
508 /*
509 * Store the current found attribute, to check that all the blocks indeed
510 * have the same security attribute.
511 */
512 attr_prev = *attr;
513
514 /* Get the configuration of the intermediate words if there are any */
Anton Moberg908a07c2021-04-08 09:50:57 +0200515 for (i = first_word_idx + 1; i < limit_word_idx; i++) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100516 p_mpc->blk_idx = i;
Anton Moberg908a07c2021-04-08 09:50:57 +0200517 word_value = p_mpc->blk_lutn;
518 if (word_value == 0x00000000) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100519 *attr = MPC_SIE_SEC_ATTR_SECURE;
Anton Moberg908a07c2021-04-08 09:50:57 +0200520 } else if (word_value == 0xFFFFFFFF) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100521 *attr = MPC_SIE_SEC_ATTR_NONSECURE;
522 } else {
523 *attr = MPC_SIE_SEC_ATTR_MIXED;
524 return MPC_SIE_ERR_NONE;
525 }
526
527 /* If the attribute is different than the one found before, bail out */
Anton Moberg908a07c2021-04-08 09:50:57 +0200528 if (*attr != attr_prev) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100529 *attr = MPC_SIE_SEC_ATTR_MIXED;
530 return MPC_SIE_ERR_NONE;
531 }
532 attr_prev = *attr;
533 }
534
535 /* Get the partial configuration of the limit word */
536 p_mpc->blk_idx = limit_word_idx;
Anton Moberg908a07c2021-04-08 09:50:57 +0200537 word_value = p_mpc->blk_lutn & limit_word_mask;
538 if (word_value == 0x00000000) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100539 *attr = MPC_SIE_SEC_ATTR_SECURE;
Anton Moberg908a07c2021-04-08 09:50:57 +0200540 } else if (word_value ^ first_word_mask) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100541 *attr = MPC_SIE_SEC_ATTR_MIXED;
542 return MPC_SIE_ERR_NONE;
543 } else {
544 *attr = MPC_SIE_SEC_ATTR_NONSECURE;
545 }
546
Anton Moberg908a07c2021-04-08 09:50:57 +0200547 if (*attr != attr_prev) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100548 *attr = MPC_SIE_SEC_ATTR_MIXED;
549 return MPC_SIE_ERR_NONE;
550 }
551
552 return MPC_SIE_ERR_NONE;
553}
554
Anton Moberg908a07c2021-04-08 09:50:57 +0200555enum mpc_sie_error_t mpc_sie_get_ctrl(struct mpc_sie_dev_t *dev, uint32_t *ctrl_val) {
556 struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
Per Åstrand79929ff2021-01-26 14:42:43 +0100557
Anton Moberg908a07c2021-04-08 09:50:57 +0200558 if (dev->data->is_initialized != true) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100559 return MPC_SIE_NOT_INIT;
560 }
561
Anton Moberg908a07c2021-04-08 09:50:57 +0200562 if (ctrl_val == 0) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100563 return MPC_SIE_INVALID_ARG;
564 }
565
566 *ctrl_val = p_mpc->ctrl;
567
568 return MPC_SIE_ERR_NONE;
569}
570
Anton Moberg908a07c2021-04-08 09:50:57 +0200571enum mpc_sie_error_t mpc_sie_set_ctrl(struct mpc_sie_dev_t *dev, uint32_t mpc_ctrl) {
572 struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
Per Åstrand79929ff2021-01-26 14:42:43 +0100573
Anton Moberg908a07c2021-04-08 09:50:57 +0200574 if (dev->data->is_initialized != true) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100575 return MPC_SIE_NOT_INIT;
576 }
577
578 p_mpc->ctrl = mpc_ctrl;
579
580 return MPC_SIE_ERR_NONE;
581}
582
Anton Moberg908a07c2021-04-08 09:50:57 +0200583enum mpc_sie_error_t mpc_sie_get_sec_resp(struct mpc_sie_dev_t *dev, enum mpc_sie_sec_resp_t *sec_rep) {
584 struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
585 bool gating_present = false;
Per Åstrand79929ff2021-01-26 14:42:43 +0100586
Anton Moberg908a07c2021-04-08 09:50:57 +0200587 if (dev->data->is_initialized != true) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100588 return MPC_SIE_NOT_INIT;
589 }
590
Anton Moberg908a07c2021-04-08 09:50:57 +0200591 if (sec_rep == NULL) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100592 return MPC_SIE_INVALID_ARG;
593 }
594
595 if (dev->data->sie_version == SIE200) {
Anton Moberg908a07c2021-04-08 09:50:57 +0200596 if (p_mpc->ctrl & MPC_SIE200_CTRL_SEC_RESP) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100597 *sec_rep = MPC_SIE_RESP_BUS_ERROR;
598 } else {
599 *sec_rep = MPC_SIE_RESP_RAZ_WI;
600 }
601
602 } else if (dev->data->sie_version == SIE300) {
603 mpc_sie_is_gating_present(dev, &gating_present);
604 if (!gating_present) {
605 return MPC_SIE_ERR_GATING_NOT_PRESENT;
606 }
607
Anton Moberg908a07c2021-04-08 09:50:57 +0200608 if (p_mpc->ctrl & MPC_SIE300_CTRL_SEC_RESP) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100609 /* MPC returns a BUS ERROR response */
610 *sec_rep = MPC_SIE_RESP_BUS_ERROR;
611 } else {
612 /* MPC sets the ready signals LOW, which stalls any transactions */
613 *sec_rep = MPC_SIE_RESP_WAIT_GATING_DISABLED;
614 }
615 } else {
616 return MPC_SIE_UNSUPPORTED_HARDWARE_VERSION;
617 }
618
619 return MPC_SIE_ERR_NONE;
620}
621
Anton Moberg908a07c2021-04-08 09:50:57 +0200622enum mpc_sie_error_t mpc_sie_set_sec_resp(struct mpc_sie_dev_t *dev, enum mpc_sie_sec_resp_t sec_rep) {
623 struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
624 bool gating_present = false;
Per Åstrand79929ff2021-01-26 14:42:43 +0100625
Anton Moberg908a07c2021-04-08 09:50:57 +0200626 if (dev->data->is_initialized != true) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100627 return MPC_SIE_NOT_INIT;
628 }
629
630 if (dev->data->sie_version == SIE200) {
631 if (sec_rep == MPC_SIE_RESP_BUS_ERROR) {
632 p_mpc->ctrl |= MPC_SIE200_CTRL_SEC_RESP;
633 } else if (sec_rep == MPC_SIE_RESP_RAZ_WI) {
634 p_mpc->ctrl &= ~MPC_SIE200_CTRL_SEC_RESP;
635 } else {
636 return MPC_SIE_INVALID_ARG;
637 }
638
639 } else if (dev->data->sie_version == SIE300) {
640 mpc_sie_is_gating_present(dev, &gating_present);
641 if (!gating_present) {
642 return MPC_SIE_ERR_GATING_NOT_PRESENT;
643 }
644
645 if (sec_rep == MPC_SIE_RESP_BUS_ERROR) {
646 p_mpc->ctrl |= MPC_SIE300_CTRL_SEC_RESP;
647 } else if (sec_rep == MPC_SIE_RESP_WAIT_GATING_DISABLED) {
648 p_mpc->ctrl &= ~MPC_SIE300_CTRL_SEC_RESP;
649 } else {
650 return MPC_SIE_INVALID_ARG;
651 }
652
653 } else {
654 return MPC_SIE_UNSUPPORTED_HARDWARE_VERSION;
655 }
656
657 return MPC_SIE_ERR_NONE;
658}
659
Anton Moberg908a07c2021-04-08 09:50:57 +0200660enum mpc_sie_error_t mpc_sie_irq_enable(struct mpc_sie_dev_t *dev) {
661 struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
Per Åstrand79929ff2021-01-26 14:42:43 +0100662
Anton Moberg908a07c2021-04-08 09:50:57 +0200663 if (dev->data->is_initialized != true) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100664 return MPC_SIE_NOT_INIT;
665 }
666
667 p_mpc->int_en |= MPC_SIE_INT_BIT;
668
669 return MPC_SIE_ERR_NONE;
670}
671
Anton Moberg908a07c2021-04-08 09:50:57 +0200672void mpc_sie_irq_disable(struct mpc_sie_dev_t *dev) {
673 struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
Per Åstrand79929ff2021-01-26 14:42:43 +0100674
675 p_mpc->int_en &= ~MPC_SIE_INT_BIT;
676}
677
Anton Moberg908a07c2021-04-08 09:50:57 +0200678void mpc_sie_clear_irq(struct mpc_sie_dev_t *dev) {
679 struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
Per Åstrand79929ff2021-01-26 14:42:43 +0100680
681 p_mpc->int_clear = MPC_SIE_INT_BIT;
682}
683
Anton Moberg908a07c2021-04-08 09:50:57 +0200684uint32_t mpc_sie_irq_state(struct mpc_sie_dev_t *dev) {
685 struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
Per Åstrand79929ff2021-01-26 14:42:43 +0100686
687 return (p_mpc->int_stat & MPC_SIE_INT_BIT);
688}
689
Anton Moberg908a07c2021-04-08 09:50:57 +0200690enum mpc_sie_error_t mpc_sie_lock_down(struct mpc_sie_dev_t *dev) {
691 struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
Per Åstrand79929ff2021-01-26 14:42:43 +0100692
Anton Moberg908a07c2021-04-08 09:50:57 +0200693 if (dev->data->is_initialized != true) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100694 return MPC_SIE_NOT_INIT;
695 }
696
Anton Moberg908a07c2021-04-08 09:50:57 +0200697 p_mpc->ctrl |= (MPC_SIE_CTRL_AUTOINCREMENT | MPC_SIE_CTRL_SEC_LOCK_DOWN);
Per Åstrand79929ff2021-01-26 14:42:43 +0100698
699 return MPC_SIE_ERR_NONE;
700}
701
Anton Moberg908a07c2021-04-08 09:50:57 +0200702enum mpc_sie_error_t mpc_sie_is_gating_present(struct mpc_sie_dev_t *dev, bool *gating_present) {
703 struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
Per Åstrand79929ff2021-01-26 14:42:43 +0100704
Anton Moberg908a07c2021-04-08 09:50:57 +0200705 if (dev->data->is_initialized != true) {
Per Åstrand79929ff2021-01-26 14:42:43 +0100706 return MPC_SIE_NOT_INIT;
707 }
708
709 if (dev->data->sie_version != SIE300) {
710 return MPC_SIE_UNSUPPORTED_HARDWARE_VERSION;
711 }
712
713 *gating_present = (bool)(p_mpc->ctrl & MPC_SIE300_CTRL_GATE_PRESENT);
714
715 return MPC_SIE_ERR_NONE;
716}
717
Anton Moberg908a07c2021-04-08 09:50:57 +0200718uint32_t get_sie_version(struct mpc_sie_dev_t *dev) {
719 struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
Per Åstrand79929ff2021-01-26 14:42:43 +0100720
721 return p_mpc->pidr0 & MPC_PIDR0_SIE_VERSION_MASK;
722}
723
Anton Moberg908a07c2021-04-08 09:50:57 +0200724bool mpc_sie_get_gate_ack(struct mpc_sie_dev_t *dev) {
725 struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
Per Åstrand79929ff2021-01-26 14:42:43 +0100726
727 return (bool)(p_mpc->ctrl & MPC_SIE300_CTRL_GATE_ACK);
728}
729
Anton Moberg908a07c2021-04-08 09:50:57 +0200730void mpc_sie_request_gating(struct mpc_sie_dev_t *dev) {
731 struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
Per Åstrand79929ff2021-01-26 14:42:43 +0100732
733 p_mpc->ctrl |= MPC_SIE300_CTRL_GATE_REQ;
734}
735
Anton Moberg908a07c2021-04-08 09:50:57 +0200736void mpc_sie_release_gating(struct mpc_sie_dev_t *dev) {
737 struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
Per Åstrand79929ff2021-01-26 14:42:43 +0100738
739 p_mpc->ctrl &= ~MPC_SIE300_CTRL_GATE_REQ;
740}