Files
base/drivers/source/firewall/sdrv_firewall_mpc.c
2025-11-07 09:57:14 +08:00

502 lines
21 KiB
C

/** ************************************************************************************************
* 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
*
* <table>
* <tr><th>Date <th>Version
* <tr><td>2023/11/29 <td>1.0.0
* </table>
**************************************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************************************
* Include header files
**************************************************************************************************/
#include <reg.h>
#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 */