aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYann Gautier <yann.gautier@st.com>2019-02-15 16:45:48 +0100
committerYann Gautier <yann.gautier@foss.st.com>2021-03-23 13:06:15 +0100
commit34c1a1a43c2d238bc756e6ce618ec8bb9169bf2d (patch)
tree70df60d964ea163a3f1b754fc8b204cac16fad6e
parente84ca571306641dc04037059f27eb5a14e199934 (diff)
downloadtrusted-firmware-a-34c1a1a43c2d238bc756e6ce618ec8bb9169bf2d.tar.gz
tzc400: add support for interrupts
A new function tzc400_it_handler() is created to manage TZC400 interrupts. The required helpers to read and clear interrupts are added as well. In case DEBUG is enabled, more information about the faulty access (address, NSAID, type of access) is displayed. Change-Id: Ie9ab1c199a8f12b2c9472d7120efbdf35711284a Signed-off-by: Yann Gautier <yann.gautier@st.com>
-rw-r--r--drivers/arm/tzc/tzc400.c105
-rw-r--r--include/drivers/arm/tzc400.h3
2 files changed, 103 insertions, 5 deletions
diff --git a/drivers/arm/tzc/tzc400.c b/drivers/arm/tzc/tzc400.c
index 9798ed4e5f..9fc1578a1a 100644
--- a/drivers/arm/tzc/tzc400.c
+++ b/drivers/arm/tzc/tzc400.c
@@ -10,6 +10,7 @@
#include <common/debug.h>
#include <drivers/arm/tzc400.h>
#include <lib/mmio.h>
+#include <lib/utils_def.h>
#include "tzc_common_private.h"
@@ -70,6 +71,77 @@ DEFINE_TZC_COMMON_WRITE_REGION_ID_ACCESS(400, 400)
DEFINE_TZC_COMMON_CONFIGURE_REGION0(400)
DEFINE_TZC_COMMON_CONFIGURE_REGION(400)
+static void _tzc400_clear_it(uintptr_t base, uint32_t filter)
+{
+ mmio_write_32(base + INT_CLEAR, BIT_32(filter));
+}
+
+static uint32_t _tzc400_get_int_by_filter(uintptr_t base, uint32_t filter)
+{
+ return mmio_read_32(base + INT_STATUS) & BIT_32(filter);
+}
+
+#if DEBUG
+static unsigned long _tzc400_get_fail_address(uintptr_t base, uint32_t filter)
+{
+ unsigned long fail_address;
+
+ fail_address = mmio_read_32(base + FAIL_ADDRESS_LOW_OFF +
+ (filter * FILTER_OFFSET));
+#ifdef __aarch64__
+ fail_address += (unsigned long)mmio_read_32(base + FAIL_ADDRESS_HIGH_OFF +
+ (filter * FILTER_OFFSET)) << 32;
+#endif
+
+ return fail_address;
+}
+
+static uint32_t _tzc400_get_fail_id(uintptr_t base, uint32_t filter)
+{
+ return mmio_read_32(base + FAIL_ID + (filter * FILTER_OFFSET));
+}
+
+static uint32_t _tzc400_get_fail_control(uintptr_t base, uint32_t filter)
+{
+ return mmio_read_32(base + FAIL_CONTROL_OFF + (filter * FILTER_OFFSET));
+}
+
+static void _tzc400_dump_fail_filter(uintptr_t base, uint32_t filter)
+{
+ uint32_t control_fail;
+ uint32_t fail_id;
+ unsigned long address_fail;
+
+ address_fail = _tzc400_get_fail_address(base, filter);
+ ERROR("Illegal access to 0x%lx:\n", address_fail);
+
+ fail_id = _tzc400_get_fail_id(base, filter);
+ ERROR("\tFAIL_ID = 0x%x\n", fail_id);
+
+ control_fail = _tzc400_get_fail_control(base, filter);
+ if (((control_fail & BIT_32(FAIL_CONTROL_NS_SHIFT)) >> FAIL_CONTROL_NS_SHIFT) ==
+ FAIL_CONTROL_NS_NONSECURE) {
+ ERROR("\tNon-Secure\n");
+ } else {
+ ERROR("\tSecure\n");
+ }
+
+ if (((control_fail & BIT_32(FAIL_CONTROL_PRIV_SHIFT)) >> FAIL_CONTROL_PRIV_SHIFT) ==
+ FAIL_CONTROL_PRIV_PRIV) {
+ ERROR("\tPrivilege\n");
+ } else {
+ ERROR("\tUnprivilege\n");
+ }
+
+ if (((control_fail & BIT_32(FAIL_CONTROL_DIR_SHIFT)) >> FAIL_CONTROL_DIR_SHIFT) ==
+ FAIL_CONTROL_DIR_WRITE) {
+ ERROR("\tWrite\n");
+ } else {
+ ERROR("\tRead\n");
+ }
+}
+#endif /* DEBUG */
+
static unsigned int _tzc400_get_gate_keeper(uintptr_t base,
unsigned int filter)
{
@@ -108,11 +180,6 @@ void tzc400_set_action(unsigned int action)
assert(tzc400.base != 0U);
assert(action <= TZC_ACTION_ERR_INT);
- /*
- * - Currently no handler is provided to trap an error via interrupt
- * or exception.
- * - The interrupt action has not been tested.
- */
_tzc400_write_action(tzc400.base, action);
}
@@ -245,3 +312,31 @@ void tzc400_disable_filters(void)
for (filter = 0; filter < tzc400.num_filters; filter++)
_tzc400_set_gate_keeper(tzc400.base, filter, 0);
}
+
+int tzc400_it_handler(void)
+{
+ uint32_t filter;
+ uint32_t filter_it_pending = tzc400.num_filters;
+
+ assert(tzc400.base != 0U);
+
+ for (filter = 0U; filter < tzc400.num_filters; filter++) {
+ if (_tzc400_get_int_by_filter(tzc400.base, filter) != 0U) {
+ filter_it_pending = filter;
+ break;
+ }
+ }
+
+ if (filter_it_pending == tzc400.num_filters) {
+ ERROR("TZC-400: No interrupt pending!\n");
+ return -1;
+ }
+
+#if DEBUG
+ _tzc400_dump_fail_filter(tzc400.base, filter_it_pending);
+#endif
+
+ _tzc400_clear_it(tzc400.base, filter_it_pending);
+
+ return 0;
+}
diff --git a/include/drivers/arm/tzc400.h b/include/drivers/arm/tzc400.h
index aacd5dfea3..5f8a48f570 100644
--- a/include/drivers/arm/tzc400.h
+++ b/include/drivers/arm/tzc400.h
@@ -90,6 +90,8 @@
#define TZC_400_REGION_SIZE U(0x20)
#define TZC_400_ACTION_OFF U(0x4)
+#define FILTER_OFFSET U(0x10)
+
#ifndef __ASSEMBLER__
#include <cdefs.h>
@@ -110,6 +112,7 @@ void tzc400_configure_region(unsigned int filters,
void tzc400_set_action(unsigned int action);
void tzc400_enable_filters(void);
void tzc400_disable_filters(void);
+int tzc400_it_handler(void);
static inline void tzc_init(uintptr_t base)
{