/** ************************************************************************************************ * SEMIDRIVE Copyright Statement * Copyright (c) SEMIDRIVE. All rights reserved * * This software and all rights therein are owned by SEMIDRIVE, and are * protected by copyright law and other relevant laws, regulations and * protection. Without SEMIDRIVE's prior written consent and/or related rights, * please do not use this software or any potion thereof in any form or by any * means. You may not reproduce, modify or distribute this software except in * compliance with the License. Unless required by applicable law or agreed to * in writing, software distributed under the License is distributed on * an 'AS IS' basis, WITHOUT WARRANTIES OF ANY KIND, either express or implied. * **************************************************************************************************/ /** ************************************************************************************************ * \file sdrv_firewall_mpc.c * \brief SSDK Firewall MPC Driver * * *
Date Version *
2023/11/29 1.0.0 *
**************************************************************************************************/ #ifdef __cplusplus extern "C" { #endif /*************************************************************************************************** * Include header files **************************************************************************************************/ #include #include "sdrv_firewall_mpc.h" /*************************************************************************************************** * Private Macro definition **************************************************************************************************/ /** \brief Address alignment. */ #define MPC_REGION_ADDR(addr) ((uint32_t)(addr) >> 12U) /** \brief The address offset of the domain0 ~ 3 permissions register * for the different memory port. */ #define MPC_DOM_PER0(n) ((uint32_t)((uint32_t)(n)*0xCU)) /** \brief The address offset of the domain4 ~ 7 permissions register \ * for the different memory port. \ */ \ #define MPC_DOM_PER1(n) \ ((uint32_t)(0x4U + ((uint32_t)(n)*0xCU))) /** \brief The mask of the permission lock. */ #define MPC_DOM_PER_LOCK_MASK (0xFFU) /** \brief The address offset of the permission lock register. */ #define MPC_DOM_PER_LOCK(n) ((uint32_t)(0x8U + ((uint32_t)(n)*0xCU))) /** \brief The bit offset of the domain0. */ #define DOM_PER_DOMAIN0_BIT (4U) /** \brief The bit offset of the domain1. */ #define DOM_PER_DOMAIN1_BIT (8U + 4U) /** \brief The bit offset of the domain2. */ #define DOM_PER_DOMAIN2_BIT (16U + 4U) /** \brief The bit offset of the domain3. */ #define DOM_PER_DOMAIN3_BIT (24U + 4U) /** \brief The bit offset of the domain4. */ #define DOM_PER_DOMAIN4_BIT (4U) /** \brief The bit offset of the domain5. */ #define DOM_PER_DOMAIN5_BIT (8U + 4U) /** \brief The bit offset of the domain6. */ #define DOM_PER_DOMAIN6_BIT (16U + 4U) /** \brief The bit offset of the domain7. */ #define DOM_PER_DOMAIN7_BIT (24U + 4U) /** \brief The address offset of the region start address register. */ #define MPC_RGN_START_ADDR(n) (uint32_t)((0x140U + ((uint32_t)(n)*0x10U))) /** \brief The address offset of the region end address register. */ #define MPC_RGN_END_ADDR(n) (uint32_t)((0x144U + ((uint32_t)(n)*0x10U))) /** \brief The bit mask of enabling region configuration. */ #define MPC_RGN_ENABLE (0x1UL << 30U) /** \brief The bit mask of locking region configuration. */ #define MPC_RGN_LOCK (0x1UL << 31U) /** \brief The address offset of the region low limit address register. */ #define RGN_LOW_LIM(n) (uint32_t)((0x148U + ((uint32_t)(n)*0x10U))) /** \brief The address offset of the region up limit address register. */ #define RGN_UP_LIM(n) (uint32_t)((0x14CU + ((uint32_t)(n)*0x10U))) /** \brief The address offset of the interrupt register of the specified memory * port. */ #define MPC_FUNC_PORT_OFFSET_ADDR(portId) \ ((uint32_t)((uint32_t)(portId)*0x400U)) /** \brief The address offset of the interrupt status register. */ #define MPC_FUNC_INT_STA (uint32_t)(0x2E0U) /** \brief The address offset of the interrupt register of the specified memory * port. */ #define MPC_FUNC_INT_STA_OFFSET_ADDR(portId) \ ((uint32_t)((uint32_t)(portId)*0x400U)) /** \brief The address offset of the interrupt control register. */ #define MPC_FUNC_INT_STA_EN ((uint32_t)0x2E4U) /** \brief The address offset of the interrupt signal register. */ #define MPC_FUNC_INT_SIG_EN ((uint32_t)0x2E8U) /** \brief The bit mask of setting register access error. */ #define MPC_REG_ACS_ERR (0x1U << 1U) /** \brief The bit mask of setting memory access error. */ #define MPC_MEM_ACS_ERR (0x1U) /** \brief The address offset of the response error register. */ #define MPC_RESP_ERR_DIS ((uint32_t)0x2F0U) /** \brief The bit mask of locking the response error configuration. */ #define MPC_RESP_ERR_DIS_LOCK (0x1UL << 31U) /** \brief The bit mask of disabling the response error feature. */ #define MPC_RESP_ERR_DIS_DIS (0x1UL) /** \brief Address alignment. */ #define MPC_REGION_ADDR(addr) ((uint32_t)(addr) >> 12U) #ifdef CONFIG_E3 /** \brief The base address of the sf firewall sem error scr. */ #define FIREWALL_SCR_SF_BASE (0xF0681028U) /** \brief The bit mask of firewall Sem error. */ #define FIREWALL_SCR_SF_APB_MAC_ENB_BIT (0xFFU << 4) #endif /* CONFIG_E3 */ /*************************************************************************************************** * Private Function Declarations **************************************************************************************************/ static status_t mpc_per_region(uint32_t base, const sdrv_mpc_memport_cfg_t *memory); /*************************************************************************************************** * Global Function Declarations **************************************************************************************************/ /** * @brief Configure the permission of memory port regions in MPC module. * * This function configure memory ports in MPC module. * The permissions of memory regions in MPC module should be locked after * configuring. * * @param[in] base the address of the MAC module. * @param[in] mpc_cfg The configuration of memory. * @param[in] memport_num The number of memory port. * * @return The result of the MPC initialization function. * @details - return FIREWALL_E_OK : initializa MPC success. * - return FIREWALL_E_NULL_POINTER : The pointer is a NULL_PTR. * - return FIREWALL_E_MPC_PORT_NUM : The number of memory port is * unvalid. */ status_t sdrv_firewall_mpc_configure(uint32_t base, const sdrv_mpc_memport_cfg_t *mpc_cfg, uint32_t memport_num) { status_t ret_val = FIREWALL_E_OK; uint8_t port_num; /* #10 Check the parameters. */ if (NULL == mpc_cfg) { ret_val = FIREWALL_E_NULL_POINTER; } else if (FIREWALL_MPC_MEMPORT_MAXNUM < memport_num) { ret_val = FIREWALL_E_MPC_PORT_NUM; } else { for (port_num = 0; port_num < memport_num; port_num++) { #ifdef CONFIG_E3 /* Disable sem error check. */ if (FIREWALL_MPC_GAMA_ADDR_OFFSET == mpc_cfg[port_num].base_offset) { writel(readl(FIREWALL_SCR_SF_BASE) & (~FIREWALL_SCR_SF_APB_MAC_ENB_BIT), FIREWALL_SCR_SF_BASE); } #endif /* #ifdef CONFIG_E3 */ /* Configure all regions of the memory port. */ ret_val = mpc_per_region(base, &mpc_cfg[port_num]); if (FIREWALL_E_OK != ret_val) { #ifdef CONFIG_E3 /* Enable sem error check. */ if (FIREWALL_MPC_GAMA_ADDR_OFFSET == mpc_cfg[port_num].base_offset) { writel(readl(FIREWALL_SCR_SF_BASE) | FIREWALL_SCR_SF_APB_MAC_ENB_BIT, FIREWALL_SCR_SF_BASE); } #endif /* #ifdef CONFIG_E3 */ break; } #if (1U == FIREWALL_INTERRUPT_EN) /* #30 Turn on inturrupt when illegal access. */ writel(MPC_REG_ACS_ERR | MPC_MEM_ACS_ERR, base + mpc_cfg[port_num].base_offset + MPC_FUNC_INT_STA_EN); writel(MPC_REG_ACS_ERR | MPC_MEM_ACS_ERR, base + mpc_cfg[port_num].base_offset + MPC_FUNC_INT_SIG_EN); #endif /** #if (1U == FIREWALL_INTERRUPT_EN) */ #if (1U != FIREWALL_RESPONSE_ERROR_EN) /* #40 Disable respone error when illegal access, and lock this * configuration. */ /* disable respone error when illegal access */ writel(MPC_RESP_ERR_DIS_DIS, base + mpc_cfg[port_num].base_offset + MPC_RESP_ERR_DIS); writel(MPC_RESP_ERR_DIS_DIS | MPC_RESP_ERR_DIS_LOCK, base + mpc_cfg[port_num].base_offset + MPC_RESP_ERR_DIS); #endif /** #if (1U != FIREWALL_RESPONSE_ERROR_EN) */ #ifdef CONFIG_E3 /* Enable sem error check. */ if (FIREWALL_MPC_GAMA_ADDR_OFFSET == mpc_cfg[port_num].base_offset) { writel(readl(FIREWALL_SCR_SF_BASE) | FIREWALL_SCR_SF_APB_MAC_ENB_BIT, FIREWALL_SCR_SF_BASE); } #endif /* #ifdef CONFIG_E3 */ } } return ret_val; } /** * @brief Lock MPC configuration. * * @param[in] base the address of the MAC module. */ void sdrv_firewall_mpc_lock(uint32_t base) { uint32_t port_base; uint8_t port_num; for (port_num = 0U; port_num < FIREWALL_MPC_MEMPORT_MAXNUM; ++port_num) { #ifdef CONFIG_E3 if (FIREWALL_MPC_RESERVED_PORTID == port_num) { continue; } #endif /* #ifdef CONFIG_E3 */ port_base = base + FIREWALL_MPC_ROMC_ADDR_OFFSET + MPC_FUNC_PORT_OFFSET_ADDR(port_num); /* Lock the permission configuration of all domains. */ writel(readl(port_base + MPC_DOM_PER_LOCK(port_num)) | MPC_DOM_PER_LOCK_MASK, port_base + MPC_DOM_PER_LOCK(port_num)); } #ifdef CONFIG_E3 /* Disable sem error check. */ writel(readl(FIREWALL_SCR_SF_BASE) & (~FIREWALL_SCR_SF_APB_MAC_ENB_BIT), FIREWALL_SCR_SF_BASE); #endif /* #ifdef CONFIG_E3 */ port_base = base + FIREWALL_MPC_ROMC_ADDR_OFFSET + MPC_FUNC_PORT_OFFSET_ADDR(FIREWALL_MPC_MEMPORT_MAXNUM); /* Lock the permission configuration of all domains. */ writel(readl(port_base + MPC_DOM_PER_LOCK(FIREWALL_MPC_MEMPORT_MAXNUM)) | MPC_DOM_PER_LOCK_MASK, port_base + MPC_DOM_PER_LOCK(FIREWALL_MPC_MEMPORT_MAXNUM)); #ifdef CONFIG_E3 /* Enable sem error check. */ writel(readl(FIREWALL_SCR_SF_BASE) | FIREWALL_SCR_SF_APB_MAC_ENB_BIT, FIREWALL_SCR_SF_BASE); #endif /* #ifdef CONFIG_E3 */ } /** * @brief Handle the interrupt status of the MPC module. * * This function get the illegal access error information of the MPC module. * The function exits as soon as it gets an illegal access message. * This function should be called by the firewall interrupt handler * sdrv_firewall_irq_handler(). * * @param[in] base the address of the MAC module. * @param[in] mpc_cfg The configuration of memory. * @param[in] memport_num The number of memory port. * @param[out] mpc_irqsta The status of mpc interrupt. * * @return The result of the MPC handler. * @details - return FIREWALL_E_OK : Handle MPC interrupt success. * - return FIREWALL_E_NULL_POINTER : The pointer is a NULL_PTR. * - return FIREWALL_E_MPC_PORT_NUM : The number of memory port is * unvalid. */ status_t sdrv_firewall_mpc_irq_handler(uint32_t base, const sdrv_mpc_memport_cfg_t *mpc_cfg, uint32_t memport_num, sdrv_mpc_irqsta_t *mpc_irqsta) { status_t ret_val = FIREWALL_E_OK; uint8_t port_num; uint32_t sta_enable; uint32_t sig_enable; uint32_t port_base; /* #10 Check the parameters. */ if ((NULL == mpc_cfg) || (NULL == mpc_irqsta)) { ret_val = FIREWALL_E_NULL_POINTER; } else if (FIREWALL_MPC_MEMPORT_MAXNUM < memport_num) { ret_val = FIREWALL_E_MPC_PORT_NUM; } else { /* #20 Get the illegal access information from the MPC module interrupt. */ for (port_num = 0U; port_num < memport_num; ++port_num) { #ifdef CONFIG_E3 /* Disable sem error check. */ if (FIREWALL_MPC_GAMA_ADDR_OFFSET == mpc_cfg[port_num].base_offset) { writel(readl(FIREWALL_SCR_SF_BASE) & (~FIREWALL_SCR_SF_APB_MAC_ENB_BIT), FIREWALL_SCR_SF_BASE); } #endif /* #ifdef CONFIG_E3 */ /* Get the interrupt status of the memory port. */ port_base = base + mpc_cfg[port_num].base_offset; mpc_irqsta->mpc_intr_sta = readl(port_base + MPC_FUNC_INT_STA); if (0U < mpc_irqsta->mpc_intr_sta) { /* Clear the interrupt status of the memory port. */ writel(mpc_irqsta->mpc_intr_sta, port_base + MPC_FUNC_INT_STA); sta_enable = readl(port_base + MPC_FUNC_INT_STA_EN); sig_enable = readl(port_base + MPC_FUNC_INT_SIG_EN); if (0U == ((uint32_t)mpc_irqsta->mpc_intr_sta & sta_enable & sig_enable)) { mpc_irqsta->mpc_intr_sta = 0U; } else { mpc_irqsta->mpc_memport_id = port_num; } #ifdef CONFIG_E3 /* Enable sem error check. */ if (FIREWALL_MPC_GAMA_ADDR_OFFSET == mpc_cfg[port_num].base_offset) { writel(readl(FIREWALL_SCR_SF_BASE) | FIREWALL_SCR_SF_APB_MAC_ENB_BIT, FIREWALL_SCR_SF_BASE); } #endif /* #ifdef CONFIG_E3 */ break; } /* else not needed */ #ifdef CONFIG_E3 /* Enable sem error check. */ if (FIREWALL_MPC_GAMA_ADDR_OFFSET == mpc_cfg[port_num].base_offset) { writel(readl(FIREWALL_SCR_SF_BASE) | FIREWALL_SCR_SF_APB_MAC_ENB_BIT, FIREWALL_SCR_SF_BASE); } #endif /* #ifdef CONFIG_E3 */ } } return ret_val; } /** * @brief Clear the interrupt status of the MPC module. * * This function will clear the interrupt registers in the MPC module. * This function should not be called after the firewall has been initialized. * * @param[in] base the address of the MAC module. */ void sdrv_firewall_mpc_clear_interrupt(uint32_t base) { uint32_t port_base; uint8_t port_num; /* #10 Clear the interrupt of all memory ports. */ for (port_num = 0U; port_num < FIREWALL_MPC_MEMPORT_MAXNUM; ++port_num) { #ifdef CONFIG_E3 if (FIREWALL_MPC_RESERVED_PORTID == port_num) { continue; } #endif /* #ifdef CONFIG_E3 */ port_base = base + FIREWALL_MPC_ROMC_ADDR_OFFSET + MPC_FUNC_PORT_OFFSET_ADDR(port_num); /* Disable the interrupt of the memory port. */ writel(FIREWALL_REG_VALUE_MIN, port_base + MPC_FUNC_INT_STA_EN); /* Disable the interrupt signal of the memory port. */ writel(FIREWALL_REG_VALUE_MIN, port_base + MPC_FUNC_INT_SIG_EN); /* Clear the interrupt status of the memory port. */ writel(FIREWALL_REG_VALUE_MAX, port_base + MPC_FUNC_INT_STA); } #ifdef CONFIG_E3 /* Disable sem error check. */ writel(readl(FIREWALL_SCR_SF_BASE) & (~FIREWALL_SCR_SF_APB_MAC_ENB_BIT), FIREWALL_SCR_SF_BASE); #endif /* #ifdef CONFIG_E3 */ port_base = base + FIREWALL_MPC_ROMC_ADDR_OFFSET + MPC_FUNC_PORT_OFFSET_ADDR(FIREWALL_MPC_MEMPORT_MAXNUM); /* Disable the interrupt of the memory port. */ writel(FIREWALL_REG_VALUE_MIN, port_base + MPC_FUNC_INT_STA_EN); /* Disable the interrupt signal of the memory port. */ writel(FIREWALL_REG_VALUE_MIN, port_base + MPC_FUNC_INT_SIG_EN); /* Clear the interrupt status of the memory port. */ writel(FIREWALL_REG_VALUE_MAX, port_base + MPC_FUNC_INT_STA); #ifdef CONFIG_E3 /* Enable sem error check. */ writel(readl(FIREWALL_SCR_SF_BASE) | FIREWALL_SCR_SF_APB_MAC_ENB_BIT, FIREWALL_SCR_SF_BASE); #endif /* #ifdef CONFIG_E3 */ } /*************************************************************************************************** * Private Function Declarations **************************************************************************************************/ /** * @brief Configure the permission of memory regions in MPC module. * * This function will be called by sdrv_firewall_mpc_configure(). * * @param[in] base the address of the MAC module. * @param[in] memory the address of the MPC port configuration. * * @return The result of the configuration. * @details - return FIREWALL_E_OK : initializa MPC regions success. * - return FIREWALL_E_NULL_POINTER : The pointer is a NULL_PTR. * - return FIREWALL_E_MPC_REGION_NUM : The number of regions in the * port is unvalid. */ static status_t mpc_per_region(uint32_t base, const sdrv_mpc_memport_cfg_t *memory) { status_t ret_val = FIREWALL_E_OK; const sdrv_mpc_region_cfg_t *region; uint32_t port_base; uint32_t temp_val; uint8_t num; /* #10 Check the parameters. */ if (NULL == memory) { ret_val = FIREWALL_E_NULL_POINTER; } else if (mpc_get_region_maxnum(memory->base_offset) < memory->region_nr) { ret_val = FIREWALL_E_MPC_REGION_NUM; } else { port_base = base + memory->base_offset; /* #20 Configure all regions of the memory port. */ for (num = 0; num < memory->region_nr; num++) { region = &memory->region_config[num]; /* Configure and lock the address range of the region. */ writel(MPC_REGION_ADDR(region->start_addr), port_base + MPC_RGN_START_ADDR(num)); writel(MPC_REGION_ADDR(region->end_addr), port_base + MPC_RGN_END_ADDR(num)); writel(MPC_REGION_ADDR(region->start_addr), port_base + RGN_LOW_LIM(num)); writel(MPC_REGION_ADDR(region->end_addr), port_base + RGN_UP_LIM(num)); temp_val = MPC_REGION_ADDR(region->end_addr) | MPC_RGN_ENABLE; writel(temp_val, port_base + MPC_RGN_END_ADDR(num)); temp_val |= MPC_RGN_LOCK; writel(temp_val, port_base + MPC_RGN_END_ADDR(num)); /* configure domain 0-3 permission */ temp_val = (uint32_t)region->domain0_perms << DOM_PER_DOMAIN0_BIT; temp_val |= (uint32_t)region->domain1_perms << DOM_PER_DOMAIN1_BIT; temp_val |= (uint32_t)region->domain2_perms << DOM_PER_DOMAIN2_BIT; temp_val |= (uint32_t)region->domain3_perms << DOM_PER_DOMAIN3_BIT; writel(temp_val, port_base + MPC_DOM_PER0(num)); /* configure domain 4-7 permission */ temp_val = (uint32_t)region->domain4_perms << DOM_PER_DOMAIN4_BIT; temp_val |= (uint32_t)region->domain5_perms << DOM_PER_DOMAIN5_BIT; temp_val |= (uint32_t)region->domain6_perms << DOM_PER_DOMAIN6_BIT; temp_val |= (uint32_t)region->domain7_perms << DOM_PER_DOMAIN7_BIT; writel(temp_val, port_base + MPC_DOM_PER1(num)); } } return ret_val; } #ifdef __cplusplus } #endif /* End of file */