xref: /aosp_15_r20/external/arm-trusted-firmware/drivers/arm/tzc/tzc400.c (revision 54fd6939e177f8ff529b10183254802c76df6d08)
1*54fd6939SJiyong Park /*
2*54fd6939SJiyong Park  * Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
3*54fd6939SJiyong Park  *
4*54fd6939SJiyong Park  * SPDX-License-Identifier: BSD-3-Clause
5*54fd6939SJiyong Park  */
6*54fd6939SJiyong Park 
7*54fd6939SJiyong Park #include <assert.h>
8*54fd6939SJiyong Park #include <stddef.h>
9*54fd6939SJiyong Park 
10*54fd6939SJiyong Park #include <common/debug.h>
11*54fd6939SJiyong Park #include <drivers/arm/tzc400.h>
12*54fd6939SJiyong Park #include <lib/mmio.h>
13*54fd6939SJiyong Park #include <lib/utils_def.h>
14*54fd6939SJiyong Park 
15*54fd6939SJiyong Park #include "tzc_common_private.h"
16*54fd6939SJiyong Park 
17*54fd6939SJiyong Park /*
18*54fd6939SJiyong Park  * Macros which will be used by common core functions.
19*54fd6939SJiyong Park  */
20*54fd6939SJiyong Park #define TZC_400_REGION_BASE_LOW_0_OFFSET	U(0x100)
21*54fd6939SJiyong Park #define TZC_400_REGION_BASE_HIGH_0_OFFSET	U(0x104)
22*54fd6939SJiyong Park #define TZC_400_REGION_TOP_LOW_0_OFFSET		U(0x108)
23*54fd6939SJiyong Park #define TZC_400_REGION_TOP_HIGH_0_OFFSET	U(0x10c)
24*54fd6939SJiyong Park #define TZC_400_REGION_ATTR_0_OFFSET		U(0x110)
25*54fd6939SJiyong Park #define TZC_400_REGION_ID_ACCESS_0_OFFSET	U(0x114)
26*54fd6939SJiyong Park 
27*54fd6939SJiyong Park /*
28*54fd6939SJiyong Park  * Implementation defined values used to validate inputs later.
29*54fd6939SJiyong Park  * Filters : max of 4 ; 0 to 3
30*54fd6939SJiyong Park  * Regions : max of 9 ; 0 to 8
31*54fd6939SJiyong Park  * Address width : Values between 32 to 64
32*54fd6939SJiyong Park  */
33*54fd6939SJiyong Park typedef struct tzc400_instance {
34*54fd6939SJiyong Park 	uintptr_t base;
35*54fd6939SJiyong Park 	uint8_t addr_width;
36*54fd6939SJiyong Park 	uint8_t num_filters;
37*54fd6939SJiyong Park 	uint8_t num_regions;
38*54fd6939SJiyong Park } tzc400_instance_t;
39*54fd6939SJiyong Park 
40*54fd6939SJiyong Park static tzc400_instance_t tzc400;
41*54fd6939SJiyong Park 
_tzc400_read_build_config(uintptr_t base)42*54fd6939SJiyong Park static inline unsigned int _tzc400_read_build_config(uintptr_t base)
43*54fd6939SJiyong Park {
44*54fd6939SJiyong Park 	return mmio_read_32(base + BUILD_CONFIG_OFF);
45*54fd6939SJiyong Park }
46*54fd6939SJiyong Park 
_tzc400_read_gate_keeper(uintptr_t base)47*54fd6939SJiyong Park static inline unsigned int _tzc400_read_gate_keeper(uintptr_t base)
48*54fd6939SJiyong Park {
49*54fd6939SJiyong Park 	return mmio_read_32(base + GATE_KEEPER_OFF);
50*54fd6939SJiyong Park }
51*54fd6939SJiyong Park 
_tzc400_write_gate_keeper(uintptr_t base,unsigned int val)52*54fd6939SJiyong Park static inline void _tzc400_write_gate_keeper(uintptr_t base, unsigned int val)
53*54fd6939SJiyong Park {
54*54fd6939SJiyong Park 	mmio_write_32(base + GATE_KEEPER_OFF, val);
55*54fd6939SJiyong Park }
56*54fd6939SJiyong Park 
57*54fd6939SJiyong Park /*
58*54fd6939SJiyong Park  * Get the open status information for all filter units.
59*54fd6939SJiyong Park  */
60*54fd6939SJiyong Park #define get_gate_keeper_os(_base)	((_tzc400_read_gate_keeper(_base) >>  \
61*54fd6939SJiyong Park 					GATE_KEEPER_OS_SHIFT) &		\
62*54fd6939SJiyong Park 					GATE_KEEPER_OS_MASK)
63*54fd6939SJiyong Park 
64*54fd6939SJiyong Park 
65*54fd6939SJiyong Park /* Define common core functions used across different TZC peripherals. */
66*54fd6939SJiyong Park DEFINE_TZC_COMMON_WRITE_ACTION(400, 400)
67*54fd6939SJiyong Park DEFINE_TZC_COMMON_WRITE_REGION_BASE(400, 400)
68*54fd6939SJiyong Park DEFINE_TZC_COMMON_WRITE_REGION_TOP(400, 400)
69*54fd6939SJiyong Park DEFINE_TZC_COMMON_WRITE_REGION_ATTRIBUTES(400, 400)
70*54fd6939SJiyong Park DEFINE_TZC_COMMON_WRITE_REGION_ID_ACCESS(400, 400)
71*54fd6939SJiyong Park DEFINE_TZC_COMMON_UPDATE_FILTERS(400, 400)
72*54fd6939SJiyong Park DEFINE_TZC_COMMON_CONFIGURE_REGION0(400)
73*54fd6939SJiyong Park DEFINE_TZC_COMMON_CONFIGURE_REGION(400)
74*54fd6939SJiyong Park 
_tzc400_clear_it(uintptr_t base,uint32_t filter)75*54fd6939SJiyong Park static void _tzc400_clear_it(uintptr_t base, uint32_t filter)
76*54fd6939SJiyong Park {
77*54fd6939SJiyong Park 	mmio_write_32(base + INT_CLEAR, BIT_32(filter));
78*54fd6939SJiyong Park }
79*54fd6939SJiyong Park 
_tzc400_get_int_by_filter(uintptr_t base,uint32_t filter)80*54fd6939SJiyong Park static uint32_t _tzc400_get_int_by_filter(uintptr_t base, uint32_t filter)
81*54fd6939SJiyong Park {
82*54fd6939SJiyong Park 	return mmio_read_32(base + INT_STATUS) & BIT_32(filter);
83*54fd6939SJiyong Park }
84*54fd6939SJiyong Park 
85*54fd6939SJiyong Park #if DEBUG
_tzc400_get_fail_address(uintptr_t base,uint32_t filter)86*54fd6939SJiyong Park static unsigned long _tzc400_get_fail_address(uintptr_t base, uint32_t filter)
87*54fd6939SJiyong Park {
88*54fd6939SJiyong Park 	unsigned long fail_address;
89*54fd6939SJiyong Park 
90*54fd6939SJiyong Park 	fail_address = mmio_read_32(base + FAIL_ADDRESS_LOW_OFF +
91*54fd6939SJiyong Park 				    (filter * FILTER_OFFSET));
92*54fd6939SJiyong Park #ifdef __aarch64__
93*54fd6939SJiyong Park 	fail_address += (unsigned long)mmio_read_32(base + FAIL_ADDRESS_HIGH_OFF +
94*54fd6939SJiyong Park 						    (filter * FILTER_OFFSET)) << 32;
95*54fd6939SJiyong Park #endif
96*54fd6939SJiyong Park 
97*54fd6939SJiyong Park 	return fail_address;
98*54fd6939SJiyong Park }
99*54fd6939SJiyong Park 
_tzc400_get_fail_id(uintptr_t base,uint32_t filter)100*54fd6939SJiyong Park static uint32_t _tzc400_get_fail_id(uintptr_t base, uint32_t filter)
101*54fd6939SJiyong Park {
102*54fd6939SJiyong Park 	return mmio_read_32(base + FAIL_ID + (filter * FILTER_OFFSET));
103*54fd6939SJiyong Park }
104*54fd6939SJiyong Park 
_tzc400_get_fail_control(uintptr_t base,uint32_t filter)105*54fd6939SJiyong Park static uint32_t _tzc400_get_fail_control(uintptr_t base, uint32_t filter)
106*54fd6939SJiyong Park {
107*54fd6939SJiyong Park 	return mmio_read_32(base + FAIL_CONTROL_OFF + (filter * FILTER_OFFSET));
108*54fd6939SJiyong Park }
109*54fd6939SJiyong Park 
_tzc400_dump_fail_filter(uintptr_t base,uint32_t filter)110*54fd6939SJiyong Park static void _tzc400_dump_fail_filter(uintptr_t base, uint32_t filter)
111*54fd6939SJiyong Park {
112*54fd6939SJiyong Park 	uint32_t control_fail;
113*54fd6939SJiyong Park 	uint32_t fail_id;
114*54fd6939SJiyong Park 	unsigned long address_fail;
115*54fd6939SJiyong Park 
116*54fd6939SJiyong Park 	address_fail = _tzc400_get_fail_address(base, filter);
117*54fd6939SJiyong Park 	ERROR("Illegal access to 0x%lx:\n", address_fail);
118*54fd6939SJiyong Park 
119*54fd6939SJiyong Park 	fail_id = _tzc400_get_fail_id(base, filter);
120*54fd6939SJiyong Park 	ERROR("\tFAIL_ID = 0x%x\n", fail_id);
121*54fd6939SJiyong Park 
122*54fd6939SJiyong Park 	control_fail = _tzc400_get_fail_control(base, filter);
123*54fd6939SJiyong Park 	if (((control_fail & BIT_32(FAIL_CONTROL_NS_SHIFT)) >> FAIL_CONTROL_NS_SHIFT) ==
124*54fd6939SJiyong Park 	    FAIL_CONTROL_NS_NONSECURE) {
125*54fd6939SJiyong Park 		ERROR("\tNon-Secure\n");
126*54fd6939SJiyong Park 	} else {
127*54fd6939SJiyong Park 		ERROR("\tSecure\n");
128*54fd6939SJiyong Park 	}
129*54fd6939SJiyong Park 
130*54fd6939SJiyong Park 	if (((control_fail & BIT_32(FAIL_CONTROL_PRIV_SHIFT)) >> FAIL_CONTROL_PRIV_SHIFT) ==
131*54fd6939SJiyong Park 	    FAIL_CONTROL_PRIV_PRIV) {
132*54fd6939SJiyong Park 		ERROR("\tPrivilege\n");
133*54fd6939SJiyong Park 	} else {
134*54fd6939SJiyong Park 		ERROR("\tUnprivilege\n");
135*54fd6939SJiyong Park 	}
136*54fd6939SJiyong Park 
137*54fd6939SJiyong Park 	if (((control_fail & BIT_32(FAIL_CONTROL_DIR_SHIFT)) >> FAIL_CONTROL_DIR_SHIFT) ==
138*54fd6939SJiyong Park 	    FAIL_CONTROL_DIR_WRITE) {
139*54fd6939SJiyong Park 		ERROR("\tWrite\n");
140*54fd6939SJiyong Park 	} else {
141*54fd6939SJiyong Park 		ERROR("\tRead\n");
142*54fd6939SJiyong Park 	}
143*54fd6939SJiyong Park }
144*54fd6939SJiyong Park #endif /* DEBUG */
145*54fd6939SJiyong Park 
_tzc400_get_gate_keeper(uintptr_t base,unsigned int filter)146*54fd6939SJiyong Park static unsigned int _tzc400_get_gate_keeper(uintptr_t base,
147*54fd6939SJiyong Park 				unsigned int filter)
148*54fd6939SJiyong Park {
149*54fd6939SJiyong Park 	unsigned int open_status;
150*54fd6939SJiyong Park 
151*54fd6939SJiyong Park 	open_status = get_gate_keeper_os(base);
152*54fd6939SJiyong Park 
153*54fd6939SJiyong Park 	return (open_status >> filter) & GATE_KEEPER_FILTER_MASK;
154*54fd6939SJiyong Park }
155*54fd6939SJiyong Park 
156*54fd6939SJiyong Park /* This function is not MP safe. */
_tzc400_set_gate_keeper(uintptr_t base,unsigned int filter,int val)157*54fd6939SJiyong Park static void _tzc400_set_gate_keeper(uintptr_t base,
158*54fd6939SJiyong Park 				unsigned int filter,
159*54fd6939SJiyong Park 				int val)
160*54fd6939SJiyong Park {
161*54fd6939SJiyong Park 	unsigned int open_status;
162*54fd6939SJiyong Park 
163*54fd6939SJiyong Park 	/* Upper half is current state. Lower half is requested state. */
164*54fd6939SJiyong Park 	open_status = get_gate_keeper_os(base);
165*54fd6939SJiyong Park 
166*54fd6939SJiyong Park 	if (val != 0)
167*54fd6939SJiyong Park 		open_status |=  (1UL << filter);
168*54fd6939SJiyong Park 	else
169*54fd6939SJiyong Park 		open_status &= ~(1UL << filter);
170*54fd6939SJiyong Park 
171*54fd6939SJiyong Park 	_tzc400_write_gate_keeper(base, (open_status & GATE_KEEPER_OR_MASK) <<
172*54fd6939SJiyong Park 			      GATE_KEEPER_OR_SHIFT);
173*54fd6939SJiyong Park 
174*54fd6939SJiyong Park 	/* Wait here until we see the change reflected in the TZC status. */
175*54fd6939SJiyong Park 	while ((get_gate_keeper_os(base)) != open_status)
176*54fd6939SJiyong Park 		;
177*54fd6939SJiyong Park }
178*54fd6939SJiyong Park 
tzc400_set_action(unsigned int action)179*54fd6939SJiyong Park void tzc400_set_action(unsigned int action)
180*54fd6939SJiyong Park {
181*54fd6939SJiyong Park 	assert(tzc400.base != 0U);
182*54fd6939SJiyong Park 	assert(action <= TZC_ACTION_ERR_INT);
183*54fd6939SJiyong Park 
184*54fd6939SJiyong Park 	_tzc400_write_action(tzc400.base, action);
185*54fd6939SJiyong Park }
186*54fd6939SJiyong Park 
tzc400_init(uintptr_t base)187*54fd6939SJiyong Park void tzc400_init(uintptr_t base)
188*54fd6939SJiyong Park {
189*54fd6939SJiyong Park #if DEBUG
190*54fd6939SJiyong Park 	unsigned int tzc400_id;
191*54fd6939SJiyong Park #endif
192*54fd6939SJiyong Park 	unsigned int tzc400_build;
193*54fd6939SJiyong Park 
194*54fd6939SJiyong Park 	assert(base != 0U);
195*54fd6939SJiyong Park 	tzc400.base = base;
196*54fd6939SJiyong Park 
197*54fd6939SJiyong Park #if DEBUG
198*54fd6939SJiyong Park 	tzc400_id = _tzc_read_peripheral_id(base);
199*54fd6939SJiyong Park 	if (tzc400_id != TZC_400_PERIPHERAL_ID) {
200*54fd6939SJiyong Park 		ERROR("TZC-400 : Wrong device ID (0x%x).\n", tzc400_id);
201*54fd6939SJiyong Park 		panic();
202*54fd6939SJiyong Park 	}
203*54fd6939SJiyong Park #endif
204*54fd6939SJiyong Park 
205*54fd6939SJiyong Park 	/* Save values we will use later. */
206*54fd6939SJiyong Park 	tzc400_build = _tzc400_read_build_config(tzc400.base);
207*54fd6939SJiyong Park 	tzc400.num_filters = (uint8_t)((tzc400_build >> BUILD_CONFIG_NF_SHIFT) &
208*54fd6939SJiyong Park 					BUILD_CONFIG_NF_MASK) + 1U;
209*54fd6939SJiyong Park 	tzc400.addr_width  = (uint8_t)((tzc400_build >> BUILD_CONFIG_AW_SHIFT) &
210*54fd6939SJiyong Park 					BUILD_CONFIG_AW_MASK) + 1U;
211*54fd6939SJiyong Park 	tzc400.num_regions = (uint8_t)((tzc400_build >> BUILD_CONFIG_NR_SHIFT) &
212*54fd6939SJiyong Park 					BUILD_CONFIG_NR_MASK) + 1U;
213*54fd6939SJiyong Park }
214*54fd6939SJiyong Park 
215*54fd6939SJiyong Park /*
216*54fd6939SJiyong Park  * `tzc400_configure_region0` is used to program region 0 into the TrustZone
217*54fd6939SJiyong Park  * controller. Region 0 covers the whole address space that is not mapped
218*54fd6939SJiyong Park  * to any other region, and is enabled on all filters; this cannot be
219*54fd6939SJiyong Park  * changed. This function only changes the access permissions.
220*54fd6939SJiyong Park  */
tzc400_configure_region0(unsigned int sec_attr,unsigned int ns_device_access)221*54fd6939SJiyong Park void tzc400_configure_region0(unsigned int sec_attr,
222*54fd6939SJiyong Park 			   unsigned int ns_device_access)
223*54fd6939SJiyong Park {
224*54fd6939SJiyong Park 	assert(tzc400.base != 0U);
225*54fd6939SJiyong Park 	assert(sec_attr <= TZC_REGION_S_RDWR);
226*54fd6939SJiyong Park 
227*54fd6939SJiyong Park 	_tzc400_configure_region0(tzc400.base, sec_attr, ns_device_access);
228*54fd6939SJiyong Park }
229*54fd6939SJiyong Park 
230*54fd6939SJiyong Park /*
231*54fd6939SJiyong Park  * `tzc400_configure_region` is used to program regions into the TrustZone
232*54fd6939SJiyong Park  * controller. A region can be associated with more than one filter. The
233*54fd6939SJiyong Park  * associated filters are passed in as a bitmap (bit0 = filter0), except that
234*54fd6939SJiyong Park  * the value TZC_400_REGION_ATTR_FILTER_BIT_ALL selects all filters, based on
235*54fd6939SJiyong Park  * the value of tzc400.num_filters.
236*54fd6939SJiyong Park  * NOTE:
237*54fd6939SJiyong Park  * Region 0 is special; it is preferable to use tzc400_configure_region0
238*54fd6939SJiyong Park  * for this region (see comment for that function).
239*54fd6939SJiyong Park  */
tzc400_configure_region(unsigned int filters,unsigned int region,unsigned long long region_base,unsigned long long region_top,unsigned int sec_attr,unsigned int nsaid_permissions)240*54fd6939SJiyong Park void tzc400_configure_region(unsigned int filters,
241*54fd6939SJiyong Park 			  unsigned int region,
242*54fd6939SJiyong Park 			  unsigned long long region_base,
243*54fd6939SJiyong Park 			  unsigned long long region_top,
244*54fd6939SJiyong Park 			  unsigned int sec_attr,
245*54fd6939SJiyong Park 			  unsigned int nsaid_permissions)
246*54fd6939SJiyong Park {
247*54fd6939SJiyong Park 	assert(tzc400.base != 0U);
248*54fd6939SJiyong Park 
249*54fd6939SJiyong Park 	/* Adjust filter mask by real filter number */
250*54fd6939SJiyong Park 	if (filters == TZC_400_REGION_ATTR_FILTER_BIT_ALL) {
251*54fd6939SJiyong Park 		filters = (1U << tzc400.num_filters) - 1U;
252*54fd6939SJiyong Park 	}
253*54fd6939SJiyong Park 
254*54fd6939SJiyong Park 	/* Do range checks on filters and regions. */
255*54fd6939SJiyong Park 	assert(((filters >> tzc400.num_filters) == 0U) &&
256*54fd6939SJiyong Park 	       (region < tzc400.num_regions));
257*54fd6939SJiyong Park 
258*54fd6939SJiyong Park 	/*
259*54fd6939SJiyong Park 	 * Do address range check based on TZC configuration. A 64bit address is
260*54fd6939SJiyong Park 	 * the max and expected case.
261*54fd6939SJiyong Park 	 */
262*54fd6939SJiyong Park 	assert((region_top <= (UINT64_MAX >> (64U - tzc400.addr_width))) &&
263*54fd6939SJiyong Park 		(region_base < region_top));
264*54fd6939SJiyong Park 
265*54fd6939SJiyong Park 	/* region_base and (region_top + 1) must be 4KB aligned */
266*54fd6939SJiyong Park 	assert(((region_base | (region_top + 1U)) & (4096U - 1U)) == 0U);
267*54fd6939SJiyong Park 
268*54fd6939SJiyong Park 	assert(sec_attr <= TZC_REGION_S_RDWR);
269*54fd6939SJiyong Park 
270*54fd6939SJiyong Park 	_tzc400_configure_region(tzc400.base, filters, region, region_base,
271*54fd6939SJiyong Park 						region_top,
272*54fd6939SJiyong Park 						sec_attr, nsaid_permissions);
273*54fd6939SJiyong Park }
274*54fd6939SJiyong Park 
tzc400_update_filters(unsigned int region,unsigned int filters)275*54fd6939SJiyong Park void tzc400_update_filters(unsigned int region, unsigned int filters)
276*54fd6939SJiyong Park {
277*54fd6939SJiyong Park 	/* Do range checks on filters and regions. */
278*54fd6939SJiyong Park 	assert(((filters >> tzc400.num_filters) == 0U) &&
279*54fd6939SJiyong Park 	       (region < tzc400.num_regions));
280*54fd6939SJiyong Park 
281*54fd6939SJiyong Park 	_tzc400_update_filters(tzc400.base, region, tzc400.num_filters, filters);
282*54fd6939SJiyong Park }
283*54fd6939SJiyong Park 
tzc400_enable_filters(void)284*54fd6939SJiyong Park void tzc400_enable_filters(void)
285*54fd6939SJiyong Park {
286*54fd6939SJiyong Park 	unsigned int state;
287*54fd6939SJiyong Park 	unsigned int filter;
288*54fd6939SJiyong Park 
289*54fd6939SJiyong Park 	assert(tzc400.base != 0U);
290*54fd6939SJiyong Park 
291*54fd6939SJiyong Park 	for (filter = 0U; filter < tzc400.num_filters; filter++) {
292*54fd6939SJiyong Park 		state = _tzc400_get_gate_keeper(tzc400.base, filter);
293*54fd6939SJiyong Park 		if (state != 0U) {
294*54fd6939SJiyong Park 			/* Filter 0 is special and cannot be disabled.
295*54fd6939SJiyong Park 			 * So here we allow it being already enabled. */
296*54fd6939SJiyong Park 			if (filter == 0U) {
297*54fd6939SJiyong Park 				continue;
298*54fd6939SJiyong Park 			}
299*54fd6939SJiyong Park 			/*
300*54fd6939SJiyong Park 			 * The TZC filter is already configured. Changing the
301*54fd6939SJiyong Park 			 * programmer's view in an active system can cause
302*54fd6939SJiyong Park 			 * unpredictable behavior therefore panic for now rather
303*54fd6939SJiyong Park 			 * than try to determine whether this is safe in this
304*54fd6939SJiyong Park 			 * instance.
305*54fd6939SJiyong Park 			 *
306*54fd6939SJiyong Park 			 * See the 'ARM (R) CoreLink TM TZC-400 TrustZone (R)
307*54fd6939SJiyong Park 			 * Address Space Controller' Technical Reference Manual.
308*54fd6939SJiyong Park 			 */
309*54fd6939SJiyong Park 			ERROR("TZC-400 : Filter %d Gatekeeper already"
310*54fd6939SJiyong Park 				" enabled.\n", filter);
311*54fd6939SJiyong Park 			panic();
312*54fd6939SJiyong Park 		}
313*54fd6939SJiyong Park 		_tzc400_set_gate_keeper(tzc400.base, filter, 1);
314*54fd6939SJiyong Park 	}
315*54fd6939SJiyong Park }
316*54fd6939SJiyong Park 
tzc400_disable_filters(void)317*54fd6939SJiyong Park void tzc400_disable_filters(void)
318*54fd6939SJiyong Park {
319*54fd6939SJiyong Park 	unsigned int filter;
320*54fd6939SJiyong Park 	unsigned int state;
321*54fd6939SJiyong Park 	unsigned int start = 0U;
322*54fd6939SJiyong Park 
323*54fd6939SJiyong Park 	assert(tzc400.base != 0U);
324*54fd6939SJiyong Park 
325*54fd6939SJiyong Park 	/* Filter 0 is special and cannot be disabled. */
326*54fd6939SJiyong Park 	state = _tzc400_get_gate_keeper(tzc400.base, 0);
327*54fd6939SJiyong Park 	if (state != 0U) {
328*54fd6939SJiyong Park 		start++;
329*54fd6939SJiyong Park 	}
330*54fd6939SJiyong Park 	for (filter = start; filter < tzc400.num_filters; filter++)
331*54fd6939SJiyong Park 		_tzc400_set_gate_keeper(tzc400.base, filter, 0);
332*54fd6939SJiyong Park }
333*54fd6939SJiyong Park 
tzc400_it_handler(void)334*54fd6939SJiyong Park int tzc400_it_handler(void)
335*54fd6939SJiyong Park {
336*54fd6939SJiyong Park 	uint32_t filter;
337*54fd6939SJiyong Park 	uint32_t filter_it_pending = tzc400.num_filters;
338*54fd6939SJiyong Park 
339*54fd6939SJiyong Park 	assert(tzc400.base != 0U);
340*54fd6939SJiyong Park 
341*54fd6939SJiyong Park 	for (filter = 0U; filter < tzc400.num_filters; filter++) {
342*54fd6939SJiyong Park 		if (_tzc400_get_int_by_filter(tzc400.base, filter) != 0U) {
343*54fd6939SJiyong Park 			filter_it_pending = filter;
344*54fd6939SJiyong Park 			break;
345*54fd6939SJiyong Park 		}
346*54fd6939SJiyong Park 	}
347*54fd6939SJiyong Park 
348*54fd6939SJiyong Park 	if (filter_it_pending == tzc400.num_filters) {
349*54fd6939SJiyong Park 		ERROR("TZC-400: No interrupt pending!\n");
350*54fd6939SJiyong Park 		return -1;
351*54fd6939SJiyong Park 	}
352*54fd6939SJiyong Park 
353*54fd6939SJiyong Park #if DEBUG
354*54fd6939SJiyong Park 	_tzc400_dump_fail_filter(tzc400.base, filter_it_pending);
355*54fd6939SJiyong Park #endif
356*54fd6939SJiyong Park 
357*54fd6939SJiyong Park 	_tzc400_clear_it(tzc400.base, filter_it_pending);
358*54fd6939SJiyong Park 
359*54fd6939SJiyong Park 	return 0;
360*54fd6939SJiyong Park }
361