blob: 317494e7b1e13988af6ba6cf969670f477a038fd [file] [log] [blame]
/*
* Copyright (c) 2019-2020 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 "ppc_sse300_drv.h"
#include <stdbool.h>
#include <stdint.h>
/* Default peripheral states */
#define SECURE_AS_DEFAULT_PERIPHERAL_STATE true
#define PRIVILEGE_ONLY_AS_DEFAULT_PERIPHERAL_STATE true
/* Secure Access Configuration Register Block */
struct sse300_sacfg_block_t
{
volatile uint32_t reserved0[8];
volatile uint32_t secppcintstat; /* 0x020 (R/ ) Secure PPC IRQ Status */
volatile uint32_t secppcintclr; /* 0x024 (R/W) Secure PPC IRQ Clear */
volatile uint32_t secppcinten; /* 0x028 (R/W) Secure PPC IRQ Enable */
volatile uint32_t reserved1[9];
volatile uint32_t mainnsppc0; /* 0x050 (R/W) Non-secure Access
* Peripheral Protection
* Control 0 on the Main
* Interconnect */
volatile uint32_t reserved2[3];
volatile uint32_t mainnsppcexp0; /* 0x060 (R/W) Expansion 0 Non-secure
* Access Peripheral
* Protection Control on the
* Main Interconnect */
volatile uint32_t mainnsppcexp1; /* 0x064 (R/W) Expansion 1 Non-secure
* Access Peripheral
* Protection Control on the
* Main Interconnect */
volatile uint32_t mainnsppcexp2; /* 0x068 (R/W) Expansion 2 Non-secure
* Access Peripheral
* Protection Control on the
* Main Interconnect */
volatile uint32_t mainnsppcexp3; /* 0x06C (R/W) Expansion 3 Non-secure
* Access Peripheral
* Protection Control on the
* Main Interconnect */
volatile uint32_t periphnsppc0; /* 0x070 (R/W) Non-secure Access
* Peripheral Protection
* Control 0 on the Peripheral
* Interconnect */
volatile uint32_t periphnsppc1; /* 0x074 (R/W) Non-secure Access
* Peripheral Protection
* Control 1 on the Peripheral
* Interconnect */
volatile uint32_t reserved3[2];
volatile uint32_t periphnsppcexp0; /* 0x080 (R/W) Expansion 0 Non-secure
* Access Peripheral
* Protection Control on
* Peripheral Bus */
volatile uint32_t periphnsppcexp1; /* 0x084 (R/W) Expansion 1 Non-secure
* Access Peripheral
* Protection Control on
* Peripheral Bus */
volatile uint32_t periphnsppcexp2; /* 0x088 (R/W) Expansion 2 Non-secure
* Access Peripheral
* Protection Control on
* Peripheral Bus */
volatile uint32_t periphnsppcexp3; /* 0x08C (R/W) Expansion 3 Non-secure
* Access Peripheral
* Protection Control on
* Peripheral Bus */
volatile uint32_t mainspppc0; /* 0x090 (R/W) Secure Unprivileged Access
* Peripheral Protection
* Control 0 on Main
* Interconnect */
volatile uint32_t reserved4[3];
volatile uint32_t mainspppcexp0; /* 0x0A0 (R/W) Expansion 0 Secure
* Unprivileged Access
* Peripheral Protection
* Control on Main
* Interconnect */
volatile uint32_t mainspppcexp1; /* 0x0A4 (R/W) Expansion 1 Secure
* Unprivileged Access
* Peripheral Protection
* Control on Main
* Interconnect */
volatile uint32_t mainspppcexp2; /* 0x0A8 (R/W) Expansion 2 Secure
* Unprivileged Access
* Peripheral Protection
* Control on Main
* Interconnect */
volatile uint32_t mainspppcexp3; /* 0x0AC (R/W) Expansion 3 Secure
* Unprivileged Access
* Peripheral Protection
* Control on Main
* Interconnect */
volatile uint32_t periphspppc0; /* 0x0B0 (R/W) Secure Unprivileged Access
* Peripheral Protection
* Control 0 on
* Peripheral Interconnect */
volatile uint32_t periphspppc1; /* 0x0B4 (R/W) Secure Unprivileged Access
* Peripheral Protection
* Control 1 on
* Peripheral Interconnect */
volatile uint32_t reserved5[2];
volatile uint32_t periphspppcexp0; /* 0x0C0 (R/W) Expansion 0 Secure
* Unprivileged Access
* Peripheral Protection
* Control on Peripheral
* Interconnect */
volatile uint32_t periphspppcexp1; /* 0x0C4 (R/W) Expansion 1 Secure
* Unprivileged Access
* Peripheral Protection
* Control on Peripheral
* Interconnect */
volatile uint32_t periphspppcexp2; /* 0x0C8 (R/W) Expansion 2 Secure
* Unprivileged Access
* Peripheral Protection
* Control on Peripheral
* Interconnect */
volatile uint32_t periphspppcexp3; /* 0x0CC (R/W) Expansion 3 Secure
* Unprivileged Access
* Peripheral Protection
* Control on Peripheral
* Interconnect */
volatile uint32_t reserved6[960];
volatile uint32_t pidr4; /* 0xFD0 (R/ ) Peripheral ID 4 */
volatile uint32_t reserved7[3];
volatile uint32_t pidr0; /* 0xFE0 (R/ ) Peripheral ID 0 */
volatile uint32_t pidr1; /* 0xFE4 (R/ ) Peripheral ID 1 */
volatile uint32_t pidr2; /* 0xFE8 (R/ ) Peripheral ID 2 */
volatile uint32_t pidr3; /* 0xFEC (R/ ) Peripheral ID 3 */
volatile uint32_t cidr0; /* 0xFF0 (R/ ) Component ID 0 */
volatile uint32_t cidr1; /* 0xFF4 (R/ ) Component ID 1 */
volatile uint32_t cidr2; /* 0xFF8 (R/ ) Component ID 2 */
volatile uint32_t cidr3; /* 0xFFC (R/ ) Component ID 3 */
};
/* PPC interrupt position mask */
#define PERIPH_PPC0_INT_POS_MASK (1UL << 0)
#define PERIPH_PPC1_INT_POS_MASK (1UL << 1)
#define PERIPH_PPCEXP0_INT_POS_MASK (1UL << 4)
#define PERIPH_PPCEXP1_INT_POS_MASK (1UL << 5)
#define PERIPH_PPCEXP2_INT_POS_MASK (1UL << 6)
#define PERIPH_PPCEXP3_INT_POS_MASK (1UL << 7)
#define MAIN_PPC0_INT_POS_MASK (1UL << 16)
#define MAIN_PPCEXP0_INT_POS_MASK (1UL << 20)
#define MAIN_PPCEXP1_INT_POS_MASK (1UL << 21)
#define MAIN_PPCEXP2_INT_POS_MASK (1UL << 22)
#define MAIN_PPCEXP3_INT_POS_MASK (1UL << 23)
/* Non-secure Access Configuration Register Block */
struct sse300_nsacfg_block_t
{
volatile uint32_t reserved0[36];
volatile uint32_t mainnspppc0; /* 0x090 (R/W) Non-secure Unprivileged
* Access Peripheral
* Protection Control 0 on
* Main Interconnect */
volatile uint32_t reserved1[3];
volatile uint32_t mainnspppcexp0; /* 0x0A0 (R/W) Expansion 0 Non-secure
* Unprivileged Access
* Peripheral Protection
* Control on Main
* Interconnect */
volatile uint32_t mainnspppcexp1; /* 0x0A4 (R/W) Expansion 1 Non-secure
* Unprivileged Access
* Peripheral Protection
* Control on Main
* Interconnect */
volatile uint32_t mainnspppcexp2; /* 0x0A8 (R/W) Expansion 2 Non-secure
* Unprivileged Access
* Peripheral Protection
* Control on Main
* Interconnect */
volatile uint32_t mainnspppcexp3; /* 0x0AC (R/W) Expansion 3 Non-secure
* Unprivileged Access
* Peripheral Protection
* Control on Main
* Interconnect */
volatile uint32_t periphnspppc0; /* 0x0B0 (R/W) Non-secure Unprivileged
* Access Peripheral
* Protection Control 0 on
* Peripheral Interconnect */
volatile uint32_t periphnspppc1; /* 0x0B4 (R/W) Non-secure Unprivileged
* Access Peripheral
* Protection Control 1 on
* Peripheral Interconnect */
volatile uint32_t reserved2[2];
volatile uint32_t periphnspppcexp0; /* 0x0C0 (R/W) Expansion 0 Non-secure
* Unprivileged Access
* Peripheral Protection
* Control on Peripheral
* Interconnect */
volatile uint32_t periphnspppcexp1; /* 0x0C4 (R/W) Expansion 1 Non-secure
* Unprivileged Access
* Peripheral Protection
* Control on Peripheral
* Interconnect */
volatile uint32_t periphnspppcexp2; /* 0x0C8 (R/W) Expansion 2 Non-secure
* Unprivileged Access
* Peripheral Protection
* Control on Peripheral
* Interconnect */
volatile uint32_t periphnspppcexp3; /* 0x0CC (R/W) Expansion 3 Non-secure
* Unprivileged Access
* Peripheral Protection
* Control on Peripheral
* Interconnect */
volatile uint32_t reserved3[960];
volatile uint32_t pidr4; /* 0xFD0 (R/ ) Peripheral ID 4 */
volatile uint32_t reserved4[3];
volatile uint32_t pidr0; /* 0xFE0 (R/ ) Peripheral ID 0 */
volatile uint32_t pidr1; /* 0xFE4 (R/ ) Peripheral ID 1 */
volatile uint32_t pidr2; /* 0xFE8 (R/ ) Peripheral ID 2 */
volatile uint32_t pidr3; /* 0xFEC (R/ ) Peripheral ID 3 */
volatile uint32_t cidr0; /* 0xFF0 (R/ ) Component ID 0 */
volatile uint32_t cidr1; /* 0xFF4 (R/ ) Component ID 1 */
volatile uint32_t cidr2; /* 0xFF8 (R/ ) Component ID 2 */
volatile uint32_t cidr3; /* 0xFFC (R/ ) Component ID 3 */
};
enum ppc_sse300_error_t ppc_sse300_init(struct ppc_sse300_dev_t * dev)
{
struct sse300_sacfg_block_t * p_sacfg = (struct sse300_sacfg_block_t *) dev->cfg->sacfg_base;
struct sse300_nsacfg_block_t * p_nsacfg = (struct sse300_nsacfg_block_t *) dev->cfg->nsacfg_base;
switch (dev->cfg->ppc_name)
{
/* Case for MAIN0 */
case PPC_SSE300_MAIN0:
dev->data->sacfg_ns_ppc = &p_sacfg->mainnsppc0;
dev->data->sacfg_sp_ppc = &p_sacfg->mainspppc0;
dev->data->nsacfg_nsp_ppc = &p_nsacfg->mainnspppc0;
dev->data->int_bit_mask = MAIN_PPC0_INT_POS_MASK;
break;
/* Case for MAIN EXPX */
case PPC_SSE300_MAIN_EXP0:
dev->data->sacfg_ns_ppc = &p_sacfg->mainnsppcexp0;
dev->data->sacfg_sp_ppc = &p_sacfg->mainspppcexp0;
dev->data->nsacfg_nsp_ppc = &p_nsacfg->mainnspppcexp0;
dev->data->int_bit_mask = MAIN_PPCEXP0_INT_POS_MASK;
break;
case PPC_SSE300_MAIN_EXP1:
dev->data->sacfg_ns_ppc = &p_sacfg->mainnsppcexp1;
dev->data->sacfg_sp_ppc = &p_sacfg->mainspppcexp1;
dev->data->nsacfg_nsp_ppc = &p_nsacfg->mainnspppcexp1;
dev->data->int_bit_mask = MAIN_PPCEXP1_INT_POS_MASK;
break;
case PPC_SSE300_MAIN_EXP2:
dev->data->sacfg_ns_ppc = &p_sacfg->mainnsppcexp2;
dev->data->sacfg_sp_ppc = &p_sacfg->mainspppcexp2;
dev->data->nsacfg_nsp_ppc = &p_nsacfg->mainnspppcexp2;
dev->data->int_bit_mask = MAIN_PPCEXP2_INT_POS_MASK;
break;
case PPC_SSE300_MAIN_EXP3:
dev->data->sacfg_ns_ppc = &p_sacfg->mainnsppcexp3;
dev->data->sacfg_sp_ppc = &p_sacfg->mainspppcexp3;
dev->data->nsacfg_nsp_ppc = &p_nsacfg->mainnspppcexp3;
dev->data->int_bit_mask = MAIN_PPCEXP3_INT_POS_MASK;
break;
/* Case for PERIPHX */
case PPC_SSE300_PERIPH0:
dev->data->sacfg_ns_ppc = &p_sacfg->periphnsppc0;
dev->data->sacfg_sp_ppc = &p_sacfg->periphspppc0;
dev->data->nsacfg_nsp_ppc = &p_nsacfg->periphnspppc0;
dev->data->int_bit_mask = PERIPH_PPC0_INT_POS_MASK;
break;
case PPC_SSE300_PERIPH1:
dev->data->sacfg_ns_ppc = &p_sacfg->periphnsppc1;
dev->data->sacfg_sp_ppc = &p_sacfg->periphspppc1;
dev->data->nsacfg_nsp_ppc = &p_nsacfg->periphnspppc1;
dev->data->int_bit_mask = PERIPH_PPC1_INT_POS_MASK;
break;
/* Case for PERIPH EXPX */
case PPC_SSE300_PERIPH_EXP0:
dev->data->sacfg_ns_ppc = &p_sacfg->periphnsppcexp0;
dev->data->sacfg_sp_ppc = &p_sacfg->periphspppcexp0;
dev->data->nsacfg_nsp_ppc = &p_nsacfg->periphnspppcexp0;
dev->data->int_bit_mask = PERIPH_PPCEXP0_INT_POS_MASK;
break;
case PPC_SSE300_PERIPH_EXP1:
dev->data->sacfg_ns_ppc = &p_sacfg->periphnsppcexp1;
dev->data->sacfg_sp_ppc = &p_sacfg->periphspppcexp1;
dev->data->nsacfg_nsp_ppc = &p_nsacfg->periphnspppcexp1;
dev->data->int_bit_mask = PERIPH_PPCEXP1_INT_POS_MASK;
break;
case PPC_SSE300_PERIPH_EXP2:
dev->data->sacfg_ns_ppc = &p_sacfg->periphnsppcexp2;
dev->data->sacfg_sp_ppc = &p_sacfg->periphspppcexp2;
dev->data->nsacfg_nsp_ppc = &p_nsacfg->periphnspppcexp2;
dev->data->int_bit_mask = PERIPH_PPCEXP2_INT_POS_MASK;
break;
case PPC_SSE300_PERIPH_EXP3:
dev->data->sacfg_ns_ppc = &p_sacfg->periphnsppcexp3;
dev->data->sacfg_sp_ppc = &p_sacfg->periphspppcexp3;
dev->data->nsacfg_nsp_ppc = &p_nsacfg->periphnspppcexp3;
dev->data->int_bit_mask = PERIPH_PPCEXP3_INT_POS_MASK;
break;
default:
return PPC_SSE300_ERR_INVALID_PARAM;
}
dev->data->is_initialized = true;
return PPC_SSE300_ERR_NONE;
}
enum ppc_sse300_error_t ppc_sse300_config_privilege(struct ppc_sse300_dev_t * dev, uint32_t mask,
enum ppc_sse300_sec_attr_t sec_attr, enum ppc_sse300_priv_attr_t priv_attr)
{
if (dev->data->is_initialized != true)
{
return PPC_SSE300_ERR_NOT_INIT;
}
if (sec_attr == PPC_SSE300_SECURE_ACCESS)
{
#if (defined(__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U))
/* Uses secure unprivileged access address (SACFG) to set privilege
* attribute
*/
if (priv_attr == PPC_SSE300_PRIV_ONLY_ACCESS)
{
*(dev->data->sacfg_sp_ppc) &= ~mask;
}
else
{
*(dev->data->sacfg_sp_ppc) |= mask;
}
#else
/* Configuring security from Non-Secure application is not permitted. */
return PPC_SSE300_ERR_NOT_PERMITTED;
#endif
}
else
{
/* Uses non-secure unprivileged access address (NSACFG) to set
* privilege attribute */
if (priv_attr == PPC_SSE300_PRIV_ONLY_ACCESS)
{
*(dev->data->nsacfg_nsp_ppc) &= ~mask;
}
else
{
*(dev->data->nsacfg_nsp_ppc) |= mask;
}
}
return PPC_SSE300_ERR_NONE;
}
bool ppc_sse300_is_periph_priv_only(struct ppc_sse300_dev_t * dev, uint32_t mask)
{
if (dev->data->is_initialized != true)
{
/* Return true as the default configuration is privilege only */
return true;
}
#if (defined(__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U))
/* In secure domain either secure or non-secure privilege access is returned
* based on the configuration */
if ((*(dev->data->sacfg_ns_ppc) & mask) == 0)
{
/* Returns secure unprivileged access (SACFG) */
return ((*(dev->data->sacfg_sp_ppc) & mask) == 0);
}
else
{
/* Returns non-secure unprivileged access (NSACFG) */
return ((*(dev->data->nsacfg_nsp_ppc) & mask) == 0);
}
#else
/* Returns non-secure unprivileged access (NSACFG) */
return ((*(dev->data->nsacfg_nsp_ppc) & mask) == 0);
#endif
}
/* Secure only functions */
#if (defined(__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U))
enum ppc_sse300_error_t ppc_sse300_config_security(struct ppc_sse300_dev_t * dev, uint32_t mask,
enum ppc_sse300_sec_attr_t sec_attr)
{
if (dev->data->is_initialized != true)
{
return PPC_SSE300_ERR_NOT_INIT;
}
if (sec_attr == PPC_SSE300_SECURE_ACCESS)
{
*(dev->data->sacfg_ns_ppc) &= ~mask;
}
else
{
*(dev->data->sacfg_ns_ppc) |= mask;
}
return PPC_SSE300_ERR_NONE;
}
bool ppc_sse300_is_periph_secure(struct ppc_sse300_dev_t * dev, uint32_t mask)
{
if (dev->data->is_initialized != true)
{
/* Return true as the default configuration is secure */
return true;
}
return ((*(dev->data->sacfg_ns_ppc) & mask) == 0);
}
enum ppc_sse300_error_t ppc_sse300_irq_enable(struct ppc_sse300_dev_t * dev)
{
struct sse300_sacfg_block_t * p_sacfg = (struct sse300_sacfg_block_t *) dev->cfg->sacfg_base;
if (dev->data->is_initialized != true)
{
return PPC_SSE300_ERR_NOT_INIT;
}
p_sacfg->secppcinten |= dev->data->int_bit_mask;
return PPC_SSE300_ERR_NONE;
}
void ppc_sse300_irq_disable(struct ppc_sse300_dev_t * dev)
{
struct sse300_sacfg_block_t * p_sacfg = (struct sse300_sacfg_block_t *) dev->cfg->sacfg_base;
if (dev->data->is_initialized == true)
{
p_sacfg->secppcinten &= ~(dev->data->int_bit_mask);
}
}
void ppc_sse300_clear_irq(struct ppc_sse300_dev_t * dev)
{
struct sse300_sacfg_block_t * p_sacfg = (struct sse300_sacfg_block_t *) dev->cfg->sacfg_base;
if (dev->data->is_initialized == true)
{
p_sacfg->secppcintclr = dev->data->int_bit_mask;
}
}
bool ppc_sse300_irq_state(struct ppc_sse300_dev_t * dev)
{
struct sse300_sacfg_block_t * p_sacfg = (struct sse300_sacfg_block_t *) dev->cfg->sacfg_base;
if (dev->data->is_initialized != true)
{
return false;
}
return ((p_sacfg->secppcintstat & dev->data->int_bit_mask) != 0);
}
#endif /* (defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)) */