aboutsummaryrefslogtreecommitdiff
path: root/platform/ext/target/mps2/an521/native_drivers/mpc_sie200_drv.c
diff options
context:
space:
mode:
Diffstat (limited to 'platform/ext/target/mps2/an521/native_drivers/mpc_sie200_drv.c')
-rw-r--r--platform/ext/target/mps2/an521/native_drivers/mpc_sie200_drv.c656
1 files changed, 656 insertions, 0 deletions
diff --git a/platform/ext/target/mps2/an521/native_drivers/mpc_sie200_drv.c b/platform/ext/target/mps2/an521/native_drivers/mpc_sie200_drv.c
new file mode 100644
index 0000000000..e842681cd6
--- /dev/null
+++ b/platform/ext/target/mps2/an521/native_drivers/mpc_sie200_drv.c
@@ -0,0 +1,656 @@
+/*
+ * Copyright (c) 2016-2017 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "mpc_sie200_drv.h"
+
+#include <stddef.h>
+
+#include "cmsis.h"
+
+#define MPC_SIE200_BLK_CFG_OFFSET 5U
+
+#define MPC_SIE200_CTRL_SEC_RESP (1UL << 4UL) /* MPC fault triggers a
+ * bus error */
+#define MPC_SIE200_CTRL_AUTOINCREMENT (1UL << 8UL) /* BLK_IDX auto increment */
+#define MPC_SIE200_CTRL_SEC_LOCK_DOWN (1UL << 31UL) /* MPC Security lock down */
+
+/* ARM MPC interrupt */
+#define MPC_SIE200_INT_EN 1UL
+#define MPC_SIE200_INT_STAT 1UL
+
+/* ARM MPC state definitions */
+#define MPC_SIE200_INITIALIZED (1 << 0)
+
+/* Error code returned by the internal driver functions */
+enum mpc_sie200_intern_error_t{
+ MPC_SIE200_INTERN_ERR_NONE = MPC_SIE200_ERR_NONE,
+ MPC_SIE200_INTERN_ERR_NOT_IN_RANGE = MPC_SIE200_ERR_NOT_IN_RANGE,
+ MPC_SIE200_INTERN_ERR_NOT_ALIGNED = MPC_SIE200_ERR_NOT_ALIGNED,
+ MPC_SIE200_INTERN_ERR_INVALID_RANGE = MPC_SIE200_ERR_INVALID_RANGE,
+ MPC_INTERN_ERR_RANGE_SEC_ATTR_NON_COMPATIBLE =
+ MPC_SIE200_ERR_RANGE_SEC_ATTR_NON_COMPATIBLE,
+ /* Calculated block index
+ is higher than the maximum allowed by the MPC. It should never
+ happen unless the controlled ranges of the MPC are misconfigured
+ in the driver or if the IP has not enough LUTs to cover the
+ range, due to wrong reported block size for example.
+ */
+ MPC_SIE200_INTERN_ERR_BLK_IDX_TOO_HIGH = -1,
+
+};
+
+/* ARM MPC memory mapped register access structure */
+struct mpc_sie200_reg_map_t {
+ volatile uint32_t ctrl; /* (R/W) MPC Control */
+ volatile uint32_t reserved[3];/* Reserved */
+ volatile uint32_t blk_max; /* (R/ ) Maximum value of block based index */
+ volatile uint32_t blk_cfg; /* (R/ ) Block configuration */
+ volatile uint32_t blk_idx; /* (R/W) Index value for accessing block
+ * based look up table */
+ volatile uint32_t blk_lutn; /* (R/W) Block based gating
+ * Look Up Table (LUT) */
+ volatile uint32_t int_stat; /* (R/ ) Interrupt state */
+ volatile uint32_t int_clear; /* ( /W) Interrupt clear */
+ volatile uint32_t int_en; /* (R/W) Interrupt enable */
+ volatile uint32_t int_info1; /* (R/ ) Interrupt information 1 */
+ volatile uint32_t int_info2; /* (R/ ) Interrupt information 2 */
+ volatile uint32_t int_set; /* ( /W) Interrupt set. Debug purpose only */
+ volatile uint32_t reserved2[997]; /* Reserved */
+ volatile uint32_t pidr4; /* (R/ ) Peripheral ID 4 */
+ volatile uint32_t pidr5; /* (R/ ) Peripheral ID 5 */
+ volatile uint32_t pidr6; /* (R/ ) Peripheral ID 6 */
+ volatile uint32_t pidr7; /* (R/ ) Peripheral ID 7 */
+ volatile uint32_t pidr0; /* (R/ ) Peripheral ID 0 */
+ volatile uint32_t pidr1; /* (R/ ) Peripheral ID 1 */
+ volatile uint32_t pidr2; /* (R/ ) Peripheral ID 2 */
+ volatile uint32_t pidr3; /* (R/ ) Peripheral ID 3 */
+ volatile uint32_t cidr0; /* (R/ ) Component ID 0 */
+ volatile uint32_t cidr1; /* (R/ ) Component ID 1 */
+ volatile uint32_t cidr2; /* (R/ ) Component ID 2 */
+ volatile uint32_t cidr3; /* (R/ ) Component ID 3 */
+};
+
+/*
+ * Checks if the address is controlled by the MPC and returns
+ * the range index in which it is contained.
+ *
+ * \param[in] dev MPC device to initalize \ref mpc_sie200_dev_t
+ * \param[in] addr Address to check if it is controlled by MPC.
+ * \param[out] addr_range Range index in which it is contained.
+ *
+ * \return True if the base is controller by the range list, false otherwise.
+ */
+static uint32_t is_ctrl_by_range_list(struct mpc_sie200_dev_t* dev, uint32_t addr,
+ const struct mpc_sie200_memory_range_t** addr_range)
+{
+ uint32_t i;
+ const struct mpc_sie200_memory_range_t* range;
+
+ for(i = 0; i < dev->data->nbr_of_ranges; i++) {
+ range = dev->data->range_list[i];
+ if(addr >= range->base && addr <= range->limit) {
+ *addr_range = range;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Gets the masks selecting the bits in the LUT of the MPC corresponding
+ * to the base address (included) up to the limit address (included)
+ *
+ * \param[in] mpc_dev The MPC device.
+ * \param[in] base Address in a range controlled by this MPC
+ * (included), aligned on block size.
+ * \param[in] limit Address in a range controlled by this MPC
+ * (included), aligned on block size.
+ * \param[out] range Memory range in which the base address and
+ * limit are.
+ * \param[out] first_word_idx Index of the first touched word in the LUT.
+ * \param[out] nr_words Number of words used in the LUT. If 1, only
+ * first_word_mask is valid and limit_word_mask
+ * must not be used.
+ * \param[out] first_word_mask First word mask in the LUT will be stored here.
+ * \param[out] limit_word_mask Limit word mask in the LUT will be stored here.
+ *
+ * \return Returns error code as specified in \ref mpc_sie200_intern_error_t
+ */
+static enum mpc_sie200_intern_error_t get_lut_masks(
+ struct mpc_sie200_dev_t* dev,
+ const uint32_t base, const uint32_t limit,
+ const struct mpc_sie200_memory_range_t** range,
+ uint32_t *first_word_idx,
+ uint32_t *nr_words,
+ uint32_t *first_word_mask,
+ uint32_t *limit_word_mask)
+{
+ const struct mpc_sie200_memory_range_t* base_range;
+ uint32_t block_size;
+ uint32_t base_block_idx;
+ uint32_t base_word_idx;
+ uint32_t blk_max;
+ const struct mpc_sie200_memory_range_t* limit_range;
+ uint32_t limit_block_idx;
+ uint32_t limit_word_idx;
+ uint32_t mask;
+ uint32_t norm_base;
+ uint32_t norm_limit;
+ struct mpc_sie200_reg_map_t* p_mpc =
+ (struct mpc_sie200_reg_map_t*)dev->cfg->base;
+
+ /*
+ * Check that the addresses are within the controlled regions
+ * of this MPC
+ */
+ if(!is_ctrl_by_range_list(dev, base, &base_range) ||
+ !is_ctrl_by_range_list(dev, limit, &limit_range)) {
+ return MPC_SIE200_INTERN_ERR_NOT_IN_RANGE;
+ }
+
+ /* Base and limit should be part of the same range */
+ if(base_range != limit_range) {
+ return MPC_SIE200_INTERN_ERR_INVALID_RANGE;
+ }
+ *range = base_range;
+
+ block_size = (1 << (p_mpc->blk_cfg + MPC_SIE200_BLK_CFG_OFFSET));
+
+ /* Base and limit+1 addresses must be aligned on the MPC block size */
+ if(base % block_size || (limit+1) % block_size) {
+ return MPC_SIE200_INTERN_ERR_NOT_ALIGNED;
+ }
+
+ /*
+ * Get a normalized address that is an offset from the beginning
+ * of the lowest range controlled by the MPC
+ */
+ norm_base = (base - base_range->base);
+ norm_limit = (limit - base_range->base);
+
+ /*
+ * Calculate block index and to which 32 bits word it belongs
+ */
+ limit_block_idx = norm_limit/block_size;
+ limit_word_idx = limit_block_idx/32;
+
+ base_block_idx = norm_base/block_size;
+ base_word_idx = base_block_idx/32;
+
+ if(base_block_idx > limit_block_idx) {
+ return MPC_SIE200_INTERN_ERR_INVALID_RANGE;
+ }
+
+ /* Transmit the information to the caller */
+ *nr_words = limit_word_idx - base_word_idx + 1;
+ *first_word_idx = base_word_idx;
+
+ /* Limit to the highest block that can be configured */
+ blk_max = p_mpc->blk_max;
+
+ if((limit_word_idx > blk_max) || (base_word_idx > blk_max)) {
+ return MPC_SIE200_INTERN_ERR_BLK_IDX_TOO_HIGH;
+ }
+
+ /*
+ * Create the mask for the first word to only select the limit N bits
+ */
+ *first_word_mask = ~((1 << (base_block_idx % 32)) - 1);
+
+ /*
+ * Create the mask for the limit word to select only the first M bits.
+ */
+ *limit_word_mask = (1 << ((limit_block_idx+1) % 32)) - 1;
+ /*
+ * If limit_word_mask is 0, it means that the limit touched block index is
+ * the limit in its word, so the limit word mask has all its bits selected
+ */
+ if(*limit_word_mask == 0) {
+ *limit_word_mask = 0xFFFFFFFF;
+ }
+
+ /*
+ * If the blocks to configure are all packed in one word, only
+ * touch this word.
+ * Code using the computed masks should test if this mask
+ * is non-zero, and if so, only use this one instead of the limit_word_mask
+ * and first_word_mask.
+ * As the only bits that are the same in both masks are the 1 that we want
+ * to select, just use XOR to extract them.
+ */
+ if(base_word_idx == limit_word_idx) {
+ mask = ~(*first_word_mask ^ *limit_word_mask);
+ *first_word_mask = mask;
+ *limit_word_mask = mask;
+ }
+
+ return MPC_SIE200_INTERN_ERR_NONE;
+}
+
+enum mpc_sie200_error_t mpc_sie200_init(struct mpc_sie200_dev_t* dev,
+ const struct mpc_sie200_memory_range_t** range_list,
+ uint8_t nbr_of_ranges)
+{
+ if((range_list == NULL) || (nbr_of_ranges == 0)) {
+ return MPC_SIE200_INVALID_ARG;
+ }
+
+ dev->data->range_list = range_list;
+ dev->data->nbr_of_ranges = nbr_of_ranges;
+ dev->data->state = MPC_SIE200_INITIALIZED;
+
+ return MPC_SIE200_ERR_NONE;
+}
+
+enum mpc_sie200_error_t mpc_sie200_get_block_size(struct mpc_sie200_dev_t* dev,
+ uint32_t* blk_size)
+{
+ struct mpc_sie200_reg_map_t* p_mpc =
+ (struct mpc_sie200_reg_map_t*)dev->cfg->base;
+
+ if(!(dev->data->state & MPC_SIE200_INITIALIZED)) {
+ return MPC_SIE200_NOT_INIT;
+ }
+
+ if(blk_size == 0) {
+ return MPC_SIE200_INVALID_ARG;
+ }
+
+ /* Calculate the block size in byte according to the manual */
+ *blk_size = (1 << (p_mpc->blk_cfg + MPC_SIE200_BLK_CFG_OFFSET));
+
+ return MPC_SIE200_ERR_NONE;
+}
+
+enum mpc_sie200_error_t mpc_sie200_config_region(struct mpc_sie200_dev_t* dev,
+ const uint32_t base,
+ const uint32_t limit,
+ enum mpc_sie200_sec_attr_t attr)
+{
+ enum mpc_sie200_intern_error_t error;
+ uint32_t first_word_idx;
+ uint32_t first_word_mask;
+ uint32_t i;
+ uint32_t limit_word_mask;
+ uint32_t limit_word_idx;
+ uint32_t nr_words;
+ const struct mpc_sie200_memory_range_t* range;
+ uint32_t word_value;
+ struct mpc_sie200_reg_map_t* p_mpc =
+ (struct mpc_sie200_reg_map_t*)dev->cfg->base;
+
+ if(!(dev->data->state & MPC_SIE200_INITIALIZED)) {
+ return MPC_SIE200_NOT_INIT;
+ }
+
+ /* Sanity check to make sure the given range is within this MPCs range */
+ if ((dev->data->range_list[attr]->base > base) ||
+ (dev->data->range_list[attr]->limit < limit) ) {
+ return MPC_SIE200_ERR_NOT_IN_RANGE;
+ }
+
+ /* Get the bitmasks used to select the bits in the LUT */
+ error = get_lut_masks(dev, base, limit, &range, &first_word_idx, &nr_words,
+ &first_word_mask, &limit_word_mask);
+
+ limit_word_idx = first_word_idx + nr_words - 1;
+
+ if(error != MPC_SIE200_INTERN_ERR_NONE) {
+ /* Map internal error code lower than 0 to a generic errpr */
+ if(error < 0) {
+ return MPC_SIE200_ERR_INVALID_RANGE;
+ }
+ return (enum mpc_sie200_error_t)error;
+ }
+
+ /*
+ * The memory range should allow accesses in with the wanted security
+ * attribute if it requires special attribute for successfull accesses
+ */
+ if(range->attr != attr) {
+ return MPC_SIE200_ERR_RANGE_SEC_ATTR_NON_COMPATIBLE;
+ }
+
+ /*
+ * Starts changing actual configuration so issue DMB to ensure every
+ * transaction has completed by now
+ */
+ __DMB();
+
+ /* Set the block index to the first word that will be updated */
+ p_mpc->blk_idx = first_word_idx;
+
+ /* If only one word needs to be touched in the LUT */
+ if(nr_words == 1) {
+ word_value = p_mpc->blk_lutn;
+ if(attr == MPC_SIE200_SEC_ATTR_NONSECURE) {
+ word_value |= first_word_mask;
+ } else {
+ word_value &= ~first_word_mask;
+ }
+
+ /*
+ * Set the index again because full word read or write could have
+ * incremented it
+ */
+ p_mpc->blk_idx = first_word_idx;
+ p_mpc->blk_lutn = word_value;
+
+ /* Commit the configuration change */
+ __DSB();
+ __ISB();
+
+ return MPC_SIE200_ERR_NONE;
+ }
+
+ /* First word */
+ word_value = p_mpc->blk_lutn;
+ if(attr == MPC_SIE200_SEC_ATTR_NONSECURE) {
+ word_value |= first_word_mask;
+ } else {
+ word_value &= ~first_word_mask;
+ }
+ /*
+ * Set the index again because full word read or write could have
+ * incremented it
+ */
+ p_mpc->blk_idx = first_word_idx;
+ /* Partially configure the first word */
+ p_mpc->blk_lutn = word_value;
+
+ /* Fully configure the intermediate words if there are any */
+ for(i=first_word_idx+1; i<limit_word_idx; i++) {
+ p_mpc->blk_idx = i;
+ if(attr == MPC_SIE200_SEC_ATTR_NONSECURE) {
+ p_mpc->blk_lutn = 0xFFFFFFFF;
+ } else {
+ p_mpc->blk_lutn = 0x00000000;
+ }
+ }
+
+ /* Partially configure the limit word */
+ p_mpc->blk_idx = limit_word_idx;
+ word_value = p_mpc->blk_lutn;
+ if(attr == MPC_SIE200_SEC_ATTR_NONSECURE) {
+ word_value |= limit_word_mask;
+ } else {
+ word_value &= ~limit_word_mask;
+ }
+ p_mpc->blk_idx = limit_word_idx;
+ p_mpc->blk_lutn = word_value;
+
+ /* Commit the configuration change */
+ __DSB();
+ __ISB();
+
+ return MPC_SIE200_ERR_NONE;
+}
+
+enum mpc_sie200_error_t mpc_sie200_get_region_config(
+ struct mpc_sie200_dev_t* dev,
+ uint32_t base, uint32_t limit,
+ enum mpc_sie200_sec_attr_t* attr)
+{
+ enum mpc_sie200_sec_attr_t attr_prev;
+ uint32_t block_size;
+ uint32_t block_size_mask;
+ enum mpc_sie200_intern_error_t error;
+ uint32_t first_word_idx;
+ uint32_t first_word_mask;
+ uint32_t i;
+ uint32_t limit_word_idx;
+ uint32_t limit_word_mask;
+ uint32_t nr_words;
+ struct mpc_sie200_reg_map_t* p_mpc =
+ (struct mpc_sie200_reg_map_t*)dev->cfg->base;
+ const struct mpc_sie200_memory_range_t* range;
+ uint32_t word_value;
+
+ if(!(dev->data->state & MPC_SIE200_INITIALIZED)) {
+ return MPC_SIE200_NOT_INIT;
+ }
+
+ if(attr == 0) {
+ return MPC_SIE200_INVALID_ARG;
+ }
+
+ /*
+ * Initialize the security attribute to mixed in case of early
+ * termination of this function. A caller that does not check the
+ * returned error will act as if it does not know anything about the
+ * region queried, which is the safest bet
+ */
+ *attr = MPC_SIE200_SEC_ATTR_MIXED;
+
+ /*
+ * If the base and limit are not aligned, align them and make sure
+ * that the resulting region fully includes the original region
+ */
+ block_size = (1 << (p_mpc->blk_cfg + MPC_SIE200_BLK_CFG_OFFSET));
+
+ block_size_mask = block_size - 1;
+ base &= ~(block_size_mask);
+ limit &= ~(block_size_mask);
+ limit += block_size - 1; /* Round to the upper block address,
+ * and then remove one to get the preceding
+ * address.
+ */
+
+ /* Get the bitmasks used to select the bits in the LUT */
+ error = get_lut_masks(dev, base, limit, &range, &first_word_idx, &nr_words,
+ &first_word_mask, &limit_word_mask);
+
+ limit_word_idx = first_word_idx+nr_words - 1;
+
+ if(error != MPC_SIE200_INTERN_ERR_NONE) {
+ /* Map internal error code lower than 0 to generic error */
+ if(error < 0) {
+ return MPC_SIE200_ERR_INVALID_RANGE;
+ }
+ return (enum mpc_sie200_error_t)error;
+ }
+
+ /* Set the block index to the first word that will be updated */
+ p_mpc->blk_idx = first_word_idx;
+
+ /* If only one word needs to be touched in the LUT */
+ if(nr_words == 1) {
+ word_value = p_mpc->blk_lutn;
+ word_value &= first_word_mask;
+ if(word_value == 0) {
+ *attr = MPC_SIE200_SEC_ATTR_SECURE;
+ /*
+ * If there are differences between the mask and the word value,
+ * it means that the security attributes of blocks are mixed
+ */
+ } else if(word_value ^ first_word_mask) {
+ *attr = MPC_SIE200_SEC_ATTR_MIXED;
+ } else {
+ *attr = MPC_SIE200_SEC_ATTR_NONSECURE;
+ }
+ return MPC_SIE200_ERR_NONE;
+ }
+
+ /* Get the partial configuration of the first word */
+ word_value = p_mpc->blk_lutn & first_word_mask;
+ if(word_value == 0x00000000) {
+ *attr = MPC_SIE200_SEC_ATTR_SECURE;
+ } else if(word_value ^ first_word_mask) {
+ *attr = MPC_SIE200_SEC_ATTR_MIXED;
+ /*
+ * Bail out as the security attribute will be the same regardless
+ * of the configuration of other blocks
+ */
+ return MPC_SIE200_ERR_NONE;
+ } else {
+ *attr = MPC_SIE200_SEC_ATTR_NONSECURE;
+ }
+ /*
+ * Store the current found attribute, to check that all the blocks indeed
+ * have the same security attribute.
+ */
+ attr_prev = *attr;
+
+ /* Get the configuration of the intermediate words if there are any */
+ for(i=first_word_idx+1; i<limit_word_idx; i++) {
+ p_mpc->blk_idx = i;
+ word_value = p_mpc->blk_lutn;
+ if(word_value == 0x00000000) {
+ *attr = MPC_SIE200_SEC_ATTR_SECURE;
+ } else if(word_value == 0xFFFFFFFF) {
+ *attr = MPC_SIE200_SEC_ATTR_NONSECURE;
+ } else {
+ *attr = MPC_SIE200_SEC_ATTR_MIXED;
+ return MPC_SIE200_ERR_NONE;
+ }
+
+ /* If the attribute is different than the one found before, bail out */
+ if(*attr != attr_prev) {
+ *attr = MPC_SIE200_SEC_ATTR_MIXED;
+ return MPC_SIE200_ERR_NONE;
+ }
+ attr_prev = *attr;
+ }
+
+ /* Get the partial configuration of the limit word */
+ p_mpc->blk_idx = limit_word_idx;
+ word_value = p_mpc->blk_lutn & limit_word_mask;
+ if(word_value == 0x00000000) {
+ *attr = MPC_SIE200_SEC_ATTR_SECURE;
+ } else if(word_value ^ first_word_mask) {
+ *attr = MPC_SIE200_SEC_ATTR_MIXED;
+ return MPC_SIE200_ERR_NONE;
+ } else {
+ *attr = MPC_SIE200_SEC_ATTR_NONSECURE;
+ }
+
+ if(*attr != attr_prev) {
+ *attr = MPC_SIE200_SEC_ATTR_MIXED;
+ return MPC_SIE200_ERR_NONE;
+ }
+
+ return MPC_SIE200_ERR_NONE;
+}
+
+enum mpc_sie200_error_t mpc_sie200_get_ctrl(struct mpc_sie200_dev_t* dev,
+ uint32_t* ctrl_val)
+{
+ struct mpc_sie200_reg_map_t* p_mpc =
+ (struct mpc_sie200_reg_map_t*)dev->cfg->base;
+
+ if(!(dev->data->state & MPC_SIE200_INITIALIZED)) {
+ return MPC_SIE200_NOT_INIT;
+ }
+
+ if(ctrl_val == 0) {
+ return MPC_SIE200_INVALID_ARG;
+ }
+
+ *ctrl_val = p_mpc->ctrl;
+
+ return MPC_SIE200_ERR_NONE;
+}
+
+enum mpc_sie200_error_t mpc_sie200_set_ctrl(struct mpc_sie200_dev_t* dev,
+ uint32_t mpc_ctrl)
+{
+ struct mpc_sie200_reg_map_t* p_mpc =
+ (struct mpc_sie200_reg_map_t*)dev->cfg->base;
+
+ if(!(dev->data->state & MPC_SIE200_INITIALIZED)) {
+ return MPC_SIE200_NOT_INIT;
+ }
+
+ p_mpc->ctrl = mpc_ctrl;
+
+ return MPC_SIE200_ERR_NONE;
+}
+
+enum mpc_sie200_error_t mpc_sie200_get_sec_resp(struct mpc_sie200_dev_t* dev,
+ enum mpc_sie200_sec_resp_t* sec_rep)
+{
+ struct mpc_sie200_reg_map_t* p_mpc =
+ (struct mpc_sie200_reg_map_t*)dev->cfg->base;
+
+ if(!(dev->data->state & MPC_SIE200_INITIALIZED)) {
+ return MPC_SIE200_NOT_INIT;
+ }
+
+ if(sec_rep == 0) {
+ return MPC_SIE200_INVALID_ARG;
+ }
+
+ if(p_mpc->ctrl & MPC_SIE200_CTRL_SEC_RESP) {
+ *sec_rep = MPC_SIE200_RESP_BUS_ERROR;
+ return MPC_SIE200_ERR_NONE;
+ }
+
+ *sec_rep = MPC_SIE200_RESP_RAZ_WI;
+
+ return MPC_SIE200_ERR_NONE;
+}
+
+enum mpc_sie200_error_t mpc_sie200_irq_enable(struct mpc_sie200_dev_t* dev)
+{
+ struct mpc_sie200_reg_map_t* p_mpc =
+ (struct mpc_sie200_reg_map_t*)dev->cfg->base;
+
+ if(!(dev->data->state & MPC_SIE200_INITIALIZED)) {
+ return MPC_SIE200_NOT_INIT;
+ }
+
+ p_mpc->int_en |= MPC_SIE200_INT_EN;
+
+ return MPC_SIE200_ERR_NONE;
+}
+
+void mpc_sie200_irq_disable(struct mpc_sie200_dev_t* dev)
+{
+ struct mpc_sie200_reg_map_t* p_mpc =
+ (struct mpc_sie200_reg_map_t*)dev->cfg->base;
+
+ p_mpc->int_en &= ~MPC_SIE200_INT_EN;
+}
+
+void mpc_sie200_clear_irq(struct mpc_sie200_dev_t* dev)
+{
+ struct mpc_sie200_reg_map_t* p_mpc =
+ (struct mpc_sie200_reg_map_t*)dev->cfg->base;
+
+ p_mpc->int_clear = MPC_SIE200_INT_EN;
+}
+
+uint32_t mpc_sie200_irq_state(struct mpc_sie200_dev_t* dev)
+{
+ struct mpc_sie200_reg_map_t* p_mpc =
+ (struct mpc_sie200_reg_map_t*)dev->cfg->base;
+
+ return (p_mpc->int_stat & MPC_SIE200_INT_STAT);
+}
+
+enum mpc_sie200_error_t mpc_sie200_lock_down(struct mpc_sie200_dev_t* dev)
+{
+ struct mpc_sie200_reg_map_t* p_mpc =
+ (struct mpc_sie200_reg_map_t*)dev->cfg->base;
+
+ if(!(dev->data->state & MPC_SIE200_INITIALIZED)) {
+ return MPC_SIE200_NOT_INIT;
+ }
+
+ p_mpc->ctrl |= (MPC_SIE200_CTRL_AUTOINCREMENT
+ | MPC_SIE200_CTRL_SEC_LOCK_DOWN);
+
+ return MPC_SIE200_ERR_NONE;
+}