Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 1 | /* |
Anton Moberg | fa3e51b | 2021-03-31 11:05:02 +0200 | [diff] [blame] | 2 | * Copyright (c) 2016-2021 Arm Limited. All rights reserved. |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 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 | |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 18 | #include <stdbool.h> |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 19 | #include <stddef.h> |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 20 | |
| 21 | #include "cmsis_compiler.h" |
| 22 | |
| 23 | /* Values for hardware version in PIDR0 reg */ |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 24 | #define SIE200 0x60 |
| 25 | #define SIE300 0x65 |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 26 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 27 | #define MPC_SIE_BLK_CFG_OFFSET 5U |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 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 */ |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 34 | #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 Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 53 | |
| 54 | /* PIDR register bit masks */ |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 55 | #define MPC_PIDR0_SIE_VERSION_MASK ((1UL << 8UL) - 1UL) |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 56 | |
| 57 | /* ARM MPC interrupt */ |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 58 | #define MPC_SIE_INT_BIT (1UL) |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 59 | |
| 60 | /* Error code returned by the internal driver functions */ |
| 61 | enum mpc_sie_intern_error_t { |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 62 | 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 Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 67 | /* 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 */ |
| 78 | struct mpc_sie_reg_map_t { |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 79 | 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 Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 95 | volatile uint32_t reserved2[998]; /* Reserved */ |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 96 | 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 Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 108 | }; |
| 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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 120 | static uint32_t |
| 121 | is_ctrl_by_range_list(struct mpc_sie_dev_t *dev, uint32_t addr, const struct mpc_sie_memory_range_t **addr_range) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 122 | uint32_t i; |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 123 | const struct mpc_sie_memory_range_t *range; |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 124 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 125 | for (i = 0; i < dev->data->nbr_of_ranges; i++) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 126 | range = dev->data->range_list[i]; |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 127 | if (addr >= range->base && addr <= range->limit) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 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 | */ |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 155 | static 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 Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 164 | uint32_t block_size; |
| 165 | uint32_t base_block_idx; |
| 166 | uint32_t base_word_idx; |
| 167 | uint32_t blk_max; |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 168 | const struct mpc_sie_memory_range_t *limit_range; |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 169 | 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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 174 | struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base; |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 175 | |
| 176 | /* |
| 177 | * Check that the addresses are within the controlled regions |
| 178 | * of this MPC |
| 179 | */ |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 180 | if (!is_ctrl_by_range_list(dev, base, &base_range) || !is_ctrl_by_range_list(dev, limit, &limit_range)) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 181 | return MPC_SIE_INTERN_ERR_NOT_IN_RANGE; |
| 182 | } |
| 183 | |
| 184 | /* Base and limit should be part of the same range */ |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 185 | if (base_range != limit_range) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 186 | 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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 193 | if (base % block_size || (limit + 1) % block_size) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 194 | 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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 207 | limit_block_idx = norm_limit / block_size; |
| 208 | limit_word_idx = limit_block_idx / 32; |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 209 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 210 | base_block_idx = norm_base / block_size; |
| 211 | base_word_idx = base_block_idx / 32; |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 212 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 213 | if (base_block_idx > limit_block_idx) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 214 | return MPC_SIE_INTERN_ERR_INVALID_RANGE; |
| 215 | } |
| 216 | |
| 217 | /* Transmit the information to the caller */ |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 218 | *nr_words = limit_word_idx - base_word_idx + 1; |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 219 | *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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 224 | if ((limit_word_idx > blk_max) || (base_word_idx > blk_max)) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 225 | 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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 236 | *limit_word_mask = (1 << ((limit_block_idx + 1) % 32)) - 1; |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 237 | /* |
| 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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 241 | if (*limit_word_mask == 0) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 242 | *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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 254 | if (base_word_idx == limit_word_idx) { |
| 255 | mask = ~(*first_word_mask ^ *limit_word_mask); |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 256 | *first_word_mask = mask; |
| 257 | *limit_word_mask = mask; |
| 258 | } |
| 259 | |
| 260 | return MPC_SIE_INTERN_ERR_NONE; |
| 261 | } |
| 262 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 263 | enum mpc_sie_error_t |
| 264 | mpc_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 Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 266 | return MPC_SIE_INVALID_ARG; |
| 267 | } |
| 268 | |
| 269 | dev->data->sie_version = get_sie_version(dev); |
| 270 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 271 | if ((dev->data->sie_version != SIE200) && (dev->data->sie_version != SIE300)) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 272 | return MPC_SIE_UNSUPPORTED_HARDWARE_VERSION; |
| 273 | } |
| 274 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 275 | dev->data->range_list = range_list; |
| 276 | dev->data->nbr_of_ranges = nbr_of_ranges; |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 277 | dev->data->is_initialized = true; |
| 278 | |
| 279 | return MPC_SIE_ERR_NONE; |
| 280 | } |
| 281 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 282 | enum 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 Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 284 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 285 | if (dev->data->is_initialized != true) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 286 | return MPC_SIE_NOT_INIT; |
| 287 | } |
| 288 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 289 | if (blk_size == 0) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 290 | 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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 299 | enum mpc_sie_error_t mpc_sie_config_region(struct mpc_sie_dev_t *dev, |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 300 | const uint32_t base, |
| 301 | const uint32_t limit, |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 302 | enum mpc_sie_sec_attr_t attr) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 303 | 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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 310 | const struct mpc_sie_memory_range_t *range; |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 311 | uint32_t word_value; |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 312 | struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base; |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 313 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 314 | if (dev->data->is_initialized != true) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 315 | return MPC_SIE_NOT_INIT; |
| 316 | } |
| 317 | |
| 318 | /* Get the bitmasks used to select the bits in the LUT */ |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 319 | error = get_lut_masks(dev, base, limit, &range, &first_word_idx, &nr_words, &first_word_mask, &limit_word_mask); |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 320 | |
| 321 | limit_word_idx = first_word_idx + nr_words - 1; |
| 322 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 323 | if (error != MPC_SIE_INTERN_ERR_NONE) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 324 | /* Map internal error code lower than 0 to a generic errpr */ |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 325 | if (error < 0) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 326 | 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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 335 | if (range->attr != attr) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 336 | 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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 349 | if (nr_words == 1) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 350 | word_value = p_mpc->blk_lutn; |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 351 | if (attr == MPC_SIE_SEC_ATTR_NONSECURE) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 352 | 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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 361 | p_mpc->blk_idx = first_word_idx; |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 362 | 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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 373 | if (attr == MPC_SIE_SEC_ATTR_NONSECURE) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 374 | 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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 387 | for (i = first_word_idx + 1; i < limit_word_idx; i++) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 388 | p_mpc->blk_idx = i; |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 389 | if (attr == MPC_SIE_SEC_ATTR_NONSECURE) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 390 | 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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 398 | word_value = p_mpc->blk_lutn; |
| 399 | if (attr == MPC_SIE_SEC_ATTR_NONSECURE) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 400 | word_value |= limit_word_mask; |
| 401 | } else { |
| 402 | word_value &= ~limit_word_mask; |
| 403 | } |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 404 | p_mpc->blk_idx = limit_word_idx; |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 405 | 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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 414 | enum mpc_sie_error_t |
| 415 | mpc_sie_get_region_config(struct mpc_sie_dev_t *dev, uint32_t base, uint32_t limit, enum mpc_sie_sec_attr_t *attr) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 416 | 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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 426 | 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 Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 428 | uint32_t word_value; |
| 429 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 430 | if (dev->data->is_initialized != true) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 431 | return MPC_SIE_NOT_INIT; |
| 432 | } |
| 433 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 434 | if (attr == 0) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 435 | 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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 461 | error = get_lut_masks(dev, base, limit, &range, &first_word_idx, &nr_words, &first_word_mask, &limit_word_mask); |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 462 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 463 | limit_word_idx = first_word_idx + nr_words - 1; |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 464 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 465 | if (error != MPC_SIE_INTERN_ERR_NONE) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 466 | /* Map internal error code lower than 0 to generic error */ |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 467 | if (error < 0) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 468 | 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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 477 | if (nr_words == 1) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 478 | word_value = p_mpc->blk_lutn; |
| 479 | word_value &= first_word_mask; |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 480 | if (word_value == 0) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 481 | *attr = MPC_SIE_SEC_ATTR_SECURE; |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 482 | /* |
| 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 Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 487 | *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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 496 | if (word_value == 0x00000000) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 497 | *attr = MPC_SIE_SEC_ATTR_SECURE; |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 498 | } else if (word_value ^ first_word_mask) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 499 | *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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 515 | for (i = first_word_idx + 1; i < limit_word_idx; i++) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 516 | p_mpc->blk_idx = i; |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 517 | word_value = p_mpc->blk_lutn; |
| 518 | if (word_value == 0x00000000) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 519 | *attr = MPC_SIE_SEC_ATTR_SECURE; |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 520 | } else if (word_value == 0xFFFFFFFF) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 521 | *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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 528 | if (*attr != attr_prev) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 529 | *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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 537 | word_value = p_mpc->blk_lutn & limit_word_mask; |
| 538 | if (word_value == 0x00000000) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 539 | *attr = MPC_SIE_SEC_ATTR_SECURE; |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 540 | } else if (word_value ^ first_word_mask) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 541 | *attr = MPC_SIE_SEC_ATTR_MIXED; |
| 542 | return MPC_SIE_ERR_NONE; |
| 543 | } else { |
| 544 | *attr = MPC_SIE_SEC_ATTR_NONSECURE; |
| 545 | } |
| 546 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 547 | if (*attr != attr_prev) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 548 | *attr = MPC_SIE_SEC_ATTR_MIXED; |
| 549 | return MPC_SIE_ERR_NONE; |
| 550 | } |
| 551 | |
| 552 | return MPC_SIE_ERR_NONE; |
| 553 | } |
| 554 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 555 | enum 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 Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 557 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 558 | if (dev->data->is_initialized != true) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 559 | return MPC_SIE_NOT_INIT; |
| 560 | } |
| 561 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 562 | if (ctrl_val == 0) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 563 | return MPC_SIE_INVALID_ARG; |
| 564 | } |
| 565 | |
| 566 | *ctrl_val = p_mpc->ctrl; |
| 567 | |
| 568 | return MPC_SIE_ERR_NONE; |
| 569 | } |
| 570 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 571 | enum 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 Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 573 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 574 | if (dev->data->is_initialized != true) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 575 | return MPC_SIE_NOT_INIT; |
| 576 | } |
| 577 | |
| 578 | p_mpc->ctrl = mpc_ctrl; |
| 579 | |
| 580 | return MPC_SIE_ERR_NONE; |
| 581 | } |
| 582 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 583 | enum 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 Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 586 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 587 | if (dev->data->is_initialized != true) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 588 | return MPC_SIE_NOT_INIT; |
| 589 | } |
| 590 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 591 | if (sec_rep == NULL) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 592 | return MPC_SIE_INVALID_ARG; |
| 593 | } |
| 594 | |
| 595 | if (dev->data->sie_version == SIE200) { |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 596 | if (p_mpc->ctrl & MPC_SIE200_CTRL_SEC_RESP) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 597 | *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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 608 | if (p_mpc->ctrl & MPC_SIE300_CTRL_SEC_RESP) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 609 | /* 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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 622 | enum 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 Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 625 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 626 | if (dev->data->is_initialized != true) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 627 | 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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 660 | enum 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 Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 662 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 663 | if (dev->data->is_initialized != true) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 664 | 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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 672 | void 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 Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 674 | |
| 675 | p_mpc->int_en &= ~MPC_SIE_INT_BIT; |
| 676 | } |
| 677 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 678 | void 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 Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 680 | |
| 681 | p_mpc->int_clear = MPC_SIE_INT_BIT; |
| 682 | } |
| 683 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 684 | uint32_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 Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 686 | |
| 687 | return (p_mpc->int_stat & MPC_SIE_INT_BIT); |
| 688 | } |
| 689 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 690 | enum 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 Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 692 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 693 | if (dev->data->is_initialized != true) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 694 | return MPC_SIE_NOT_INIT; |
| 695 | } |
| 696 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 697 | p_mpc->ctrl |= (MPC_SIE_CTRL_AUTOINCREMENT | MPC_SIE_CTRL_SEC_LOCK_DOWN); |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 698 | |
| 699 | return MPC_SIE_ERR_NONE; |
| 700 | } |
| 701 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 702 | enum 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 Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 704 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 705 | if (dev->data->is_initialized != true) { |
Per Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 706 | 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 Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 718 | uint32_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 Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 720 | |
| 721 | return p_mpc->pidr0 & MPC_PIDR0_SIE_VERSION_MASK; |
| 722 | } |
| 723 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 724 | bool 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 Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 726 | |
| 727 | return (bool)(p_mpc->ctrl & MPC_SIE300_CTRL_GATE_ACK); |
| 728 | } |
| 729 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 730 | void 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 Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 732 | |
| 733 | p_mpc->ctrl |= MPC_SIE300_CTRL_GATE_REQ; |
| 734 | } |
| 735 | |
Anton Moberg | 908a07c | 2021-04-08 09:50:57 +0200 | [diff] [blame^] | 736 | void 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 Åstrand | 79929ff | 2021-01-26 14:42:43 +0100 | [diff] [blame] | 738 | |
| 739 | p_mpc->ctrl &= ~MPC_SIE300_CTRL_GATE_REQ; |
| 740 | } |