blob: 04632900b3ef593ed514a204341c7ddc1b3b8811 [file] [log] [blame]
/*
* Copyright (c) 2016-2021 Arm Limited. All rights reserved.
*
* 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_sie_drv.h"
#include <stdbool.h>
#include <stddef.h>
#include "cmsis_compiler.h"
/* Values for hardware version in PIDR0 reg */
#define SIE200 0x60
#define SIE300 0x65
#define MPC_SIE_BLK_CFG_OFFSET 5U
/* Defines with numbering (eg: SIE300) are only relevant to the given SIE
* version. Defines without the numbering are applicable to all SIE versions.
*/
/* CTRL register bit indexes */
#define MPC_SIE200_CTRL_SEC_RESP \
(1UL << 4UL) /* MPC fault triggers a \
* bus error \
*/
#define MPC_SIE300_CTRL_GATE_REQ \
(1UL << 6UL) /* Request for gating \
* incoming transfers \
*/
#define MPC_SIE300_CTRL_GATE_ACK \
(1UL << 7UL) /* Acknowledge for gating \
* incoming transfers \
*/
#define MPC_SIE_CTRL_AUTOINCREMENT (1UL << 8UL) /* BLK_IDX auto increment */
#define MPC_SIE300_CTRL_SEC_RESP \
(1UL << 16UL) /* Response type when SW \
* asks to gate the transfer \
*/
#define MPC_SIE300_CTRL_GATE_PRESENT (1UL << 23UL) /* Gating feature present */
#define MPC_SIE_CTRL_SEC_LOCK_DOWN (1UL << 31UL) /* MPC Security lock down */
/* PIDR register bit masks */
#define MPC_PIDR0_SIE_VERSION_MASK ((1UL << 8UL) - 1UL)
/* ARM MPC interrupt */
#define MPC_SIE_INT_BIT (1UL)
/* Error code returned by the internal driver functions */
enum mpc_sie_intern_error_t {
MPC_SIE_INTERN_ERR_NONE = MPC_SIE_ERR_NONE,
MPC_SIE_INTERN_ERR_NOT_IN_RANGE = MPC_SIE_ERR_NOT_IN_RANGE,
MPC_SIE_INTERN_ERR_NOT_ALIGNED = MPC_SIE_ERR_NOT_ALIGNED,
MPC_SIE_INTERN_ERR_INVALID_RANGE = MPC_SIE_ERR_INVALID_RANGE,
MPC_INTERN_ERR_RANGE_SEC_ATTR_NON_COMPATIBLE = MPC_SIE_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_SIE_INTERN_ERR_BLK_IDX_TOO_HIGH = -1,
};
/* ARM MPC memory mapped register access structure */
struct mpc_sie_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[998]; /* 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 initialize \ref mpc_sie_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_sie_dev_t *dev, uint32_t addr, const struct mpc_sie_memory_range_t **addr_range) {
uint32_t i;
const struct mpc_sie_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_sie_intern_error_t
*/
static enum mpc_sie_intern_error_t get_lut_masks(struct mpc_sie_dev_t *dev,
const uint32_t base,
const uint32_t limit,
const struct mpc_sie_memory_range_t **range,
uint32_t *first_word_idx,
uint32_t *nr_words,
uint32_t *first_word_mask,
uint32_t *limit_word_mask) {
const struct mpc_sie_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_sie_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_sie_reg_map_t *p_mpc = (struct mpc_sie_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_SIE_INTERN_ERR_NOT_IN_RANGE;
}
/* Base and limit should be part of the same range */
if (base_range != limit_range) {
return MPC_SIE_INTERN_ERR_INVALID_RANGE;
}
*range = base_range;
block_size = (1 << (p_mpc->blk_cfg + MPC_SIE_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_SIE_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) + base_range->range_offset;
norm_limit = (limit - base_range->base) + base_range->range_offset;
/*
* 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_SIE_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_SIE_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_SIE_INTERN_ERR_NONE;
}
enum mpc_sie_error_t
mpc_sie_init(struct mpc_sie_dev_t *dev, const struct mpc_sie_memory_range_t **range_list, uint8_t nbr_of_ranges) {
if ((range_list == NULL) || (nbr_of_ranges == 0)) {
return MPC_SIE_INVALID_ARG;
}
dev->data->sie_version = get_sie_version(dev);
if ((dev->data->sie_version != SIE200) && (dev->data->sie_version != SIE300)) {
return MPC_SIE_UNSUPPORTED_HARDWARE_VERSION;
}
dev->data->range_list = range_list;
dev->data->nbr_of_ranges = nbr_of_ranges;
dev->data->is_initialized = true;
return MPC_SIE_ERR_NONE;
}
enum mpc_sie_error_t mpc_sie_get_block_size(struct mpc_sie_dev_t *dev, uint32_t *blk_size) {
struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
if (dev->data->is_initialized != true) {
return MPC_SIE_NOT_INIT;
}
if (blk_size == 0) {
return MPC_SIE_INVALID_ARG;
}
/* Calculate the block size in byte according to the manual */
*blk_size = (1 << (p_mpc->blk_cfg + MPC_SIE_BLK_CFG_OFFSET));
return MPC_SIE_ERR_NONE;
}
enum mpc_sie_error_t mpc_sie_config_region(struct mpc_sie_dev_t *dev,
const uint32_t base,
const uint32_t limit,
enum mpc_sie_sec_attr_t attr) {
enum mpc_sie_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_sie_memory_range_t *range;
uint32_t word_value;
struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
if (dev->data->is_initialized != true) {
return MPC_SIE_NOT_INIT;
}
/* 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_SIE_INTERN_ERR_NONE) {
/* Map internal error code lower than 0 to a generic errpr */
if (error < 0) {
return MPC_SIE_ERR_INVALID_RANGE;
}
return (enum mpc_sie_error_t)error;
}
/*
* The memory range should allow accesses in with the wanted security
* attribute if it requires special attribute for successful accesses
*/
if (range->attr != attr) {
return MPC_SIE_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_SIE_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_SIE_ERR_NONE;
}
/* First word */
word_value = p_mpc->blk_lutn;
if (attr == MPC_SIE_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_SIE_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_SIE_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_SIE_ERR_NONE;
}
enum mpc_sie_error_t
mpc_sie_get_region_config(struct mpc_sie_dev_t *dev, uint32_t base, uint32_t limit, enum mpc_sie_sec_attr_t *attr) {
enum mpc_sie_sec_attr_t attr_prev;
uint32_t block_size;
uint32_t block_size_mask;
enum mpc_sie_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_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
const struct mpc_sie_memory_range_t *range;
uint32_t word_value;
if (dev->data->is_initialized != true) {
return MPC_SIE_NOT_INIT;
}
if (attr == 0) {
return MPC_SIE_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_SIE_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_SIE_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_SIE_INTERN_ERR_NONE) {
/* Map internal error code lower than 0 to generic error */
if (error < 0) {
return MPC_SIE_ERR_INVALID_RANGE;
}
return (enum mpc_sie_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_SIE_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_SIE_SEC_ATTR_MIXED;
} else {
*attr = MPC_SIE_SEC_ATTR_NONSECURE;
}
return MPC_SIE_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_SIE_SEC_ATTR_SECURE;
} else if (word_value ^ first_word_mask) {
*attr = MPC_SIE_SEC_ATTR_MIXED;
/*
* Bail out as the security attribute will be the same regardless
* of the configuration of other blocks
*/
return MPC_SIE_ERR_NONE;
} else {
*attr = MPC_SIE_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_SIE_SEC_ATTR_SECURE;
} else if (word_value == 0xFFFFFFFF) {
*attr = MPC_SIE_SEC_ATTR_NONSECURE;
} else {
*attr = MPC_SIE_SEC_ATTR_MIXED;
return MPC_SIE_ERR_NONE;
}
/* If the attribute is different than the one found before, bail out */
if (*attr != attr_prev) {
*attr = MPC_SIE_SEC_ATTR_MIXED;
return MPC_SIE_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_SIE_SEC_ATTR_SECURE;
} else if (word_value ^ first_word_mask) {
*attr = MPC_SIE_SEC_ATTR_MIXED;
return MPC_SIE_ERR_NONE;
} else {
*attr = MPC_SIE_SEC_ATTR_NONSECURE;
}
if (*attr != attr_prev) {
*attr = MPC_SIE_SEC_ATTR_MIXED;
return MPC_SIE_ERR_NONE;
}
return MPC_SIE_ERR_NONE;
}
enum mpc_sie_error_t mpc_sie_get_ctrl(struct mpc_sie_dev_t *dev, uint32_t *ctrl_val) {
struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
if (dev->data->is_initialized != true) {
return MPC_SIE_NOT_INIT;
}
if (ctrl_val == 0) {
return MPC_SIE_INVALID_ARG;
}
*ctrl_val = p_mpc->ctrl;
return MPC_SIE_ERR_NONE;
}
enum mpc_sie_error_t mpc_sie_set_ctrl(struct mpc_sie_dev_t *dev, uint32_t mpc_ctrl) {
struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
if (dev->data->is_initialized != true) {
return MPC_SIE_NOT_INIT;
}
p_mpc->ctrl = mpc_ctrl;
return MPC_SIE_ERR_NONE;
}
enum mpc_sie_error_t mpc_sie_get_sec_resp(struct mpc_sie_dev_t *dev, enum mpc_sie_sec_resp_t *sec_rep) {
struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
bool gating_present = false;
if (dev->data->is_initialized != true) {
return MPC_SIE_NOT_INIT;
}
if (sec_rep == NULL) {
return MPC_SIE_INVALID_ARG;
}
if (dev->data->sie_version == SIE200) {
if (p_mpc->ctrl & MPC_SIE200_CTRL_SEC_RESP) {
*sec_rep = MPC_SIE_RESP_BUS_ERROR;
} else {
*sec_rep = MPC_SIE_RESP_RAZ_WI;
}
} else if (dev->data->sie_version == SIE300) {
mpc_sie_is_gating_present(dev, &gating_present);
if (!gating_present) {
return MPC_SIE_ERR_GATING_NOT_PRESENT;
}
if (p_mpc->ctrl & MPC_SIE300_CTRL_SEC_RESP) {
/* MPC returns a BUS ERROR response */
*sec_rep = MPC_SIE_RESP_BUS_ERROR;
} else {
/* MPC sets the ready signals LOW, which stalls any transactions */
*sec_rep = MPC_SIE_RESP_WAIT_GATING_DISABLED;
}
} else {
return MPC_SIE_UNSUPPORTED_HARDWARE_VERSION;
}
return MPC_SIE_ERR_NONE;
}
enum mpc_sie_error_t mpc_sie_set_sec_resp(struct mpc_sie_dev_t *dev, enum mpc_sie_sec_resp_t sec_rep) {
struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
bool gating_present = false;
if (dev->data->is_initialized != true) {
return MPC_SIE_NOT_INIT;
}
if (dev->data->sie_version == SIE200) {
if (sec_rep == MPC_SIE_RESP_BUS_ERROR) {
p_mpc->ctrl |= MPC_SIE200_CTRL_SEC_RESP;
} else if (sec_rep == MPC_SIE_RESP_RAZ_WI) {
p_mpc->ctrl &= ~MPC_SIE200_CTRL_SEC_RESP;
} else {
return MPC_SIE_INVALID_ARG;
}
} else if (dev->data->sie_version == SIE300) {
mpc_sie_is_gating_present(dev, &gating_present);
if (!gating_present) {
return MPC_SIE_ERR_GATING_NOT_PRESENT;
}
if (sec_rep == MPC_SIE_RESP_BUS_ERROR) {
p_mpc->ctrl |= MPC_SIE300_CTRL_SEC_RESP;
} else if (sec_rep == MPC_SIE_RESP_WAIT_GATING_DISABLED) {
p_mpc->ctrl &= ~MPC_SIE300_CTRL_SEC_RESP;
} else {
return MPC_SIE_INVALID_ARG;
}
} else {
return MPC_SIE_UNSUPPORTED_HARDWARE_VERSION;
}
return MPC_SIE_ERR_NONE;
}
enum mpc_sie_error_t mpc_sie_irq_enable(struct mpc_sie_dev_t *dev) {
struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
if (dev->data->is_initialized != true) {
return MPC_SIE_NOT_INIT;
}
p_mpc->int_en |= MPC_SIE_INT_BIT;
return MPC_SIE_ERR_NONE;
}
void mpc_sie_irq_disable(struct mpc_sie_dev_t *dev) {
struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
p_mpc->int_en &= ~MPC_SIE_INT_BIT;
}
void mpc_sie_clear_irq(struct mpc_sie_dev_t *dev) {
struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
p_mpc->int_clear = MPC_SIE_INT_BIT;
}
uint32_t mpc_sie_irq_state(struct mpc_sie_dev_t *dev) {
struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
return (p_mpc->int_stat & MPC_SIE_INT_BIT);
}
enum mpc_sie_error_t mpc_sie_lock_down(struct mpc_sie_dev_t *dev) {
struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
if (dev->data->is_initialized != true) {
return MPC_SIE_NOT_INIT;
}
p_mpc->ctrl |= (MPC_SIE_CTRL_AUTOINCREMENT | MPC_SIE_CTRL_SEC_LOCK_DOWN);
return MPC_SIE_ERR_NONE;
}
enum mpc_sie_error_t mpc_sie_is_gating_present(struct mpc_sie_dev_t *dev, bool *gating_present) {
struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
if (dev->data->is_initialized != true) {
return MPC_SIE_NOT_INIT;
}
if (dev->data->sie_version != SIE300) {
return MPC_SIE_UNSUPPORTED_HARDWARE_VERSION;
}
*gating_present = (bool)(p_mpc->ctrl & MPC_SIE300_CTRL_GATE_PRESENT);
return MPC_SIE_ERR_NONE;
}
uint32_t get_sie_version(struct mpc_sie_dev_t *dev) {
struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
return p_mpc->pidr0 & MPC_PIDR0_SIE_VERSION_MASK;
}
bool mpc_sie_get_gate_ack(struct mpc_sie_dev_t *dev) {
struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
return (bool)(p_mpc->ctrl & MPC_SIE300_CTRL_GATE_ACK);
}
void mpc_sie_request_gating(struct mpc_sie_dev_t *dev) {
struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
p_mpc->ctrl |= MPC_SIE300_CTRL_GATE_REQ;
}
void mpc_sie_release_gating(struct mpc_sie_dev_t *dev) {
struct mpc_sie_reg_map_t *p_mpc = (struct mpc_sie_reg_map_t *)dev->cfg->base;
p_mpc->ctrl &= ~MPC_SIE300_CTRL_GATE_REQ;
}