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