xref: /rk3399_ARM-atf/plat/qti/common/src/qti_interrupt_svc.c (revision 5de3e03dbd7c2da6748e294f423c83f9582f459c)
1 /*
2  * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
3  * Copyright (c) 2018,2020, The Linux Foundation. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 #include <assert.h>
8 #include <stdint.h>
9 
10 #include <arch_helpers.h>
11 #include <bl31/interrupt_mgmt.h>
12 #include <common/debug.h>
13 #include <drivers/arm/gic_common.h>
14 #include <lib/el3_runtime/context_mgmt.h>
15 #include <lib/spinlock.h>
16 #include <lib/utils_def.h>
17 
18 #include <platform.h>
19 #include <qti_interrupt_svc.h>
20 #include <qtiseclib_interface.h>
21 
22 #define QTI_INTR_INVALID_INT_NUM		0xFFFFFFFFU
23 #define ISR_TABLE_LEN				20
24 
25 static struct qti_isr_table {
26 	struct qti_isr {
27 		qti_int_svc_isr_t func;
28 		uint32_t id;
29 		void *ctx;
30 	} entry[ISR_TABLE_LEN];
31 
32 	spinlock_t lock;
33 	uint8_t cnt;
34 } isr_table = {
35 	.entry[0 ... ISR_TABLE_LEN - 1] = { .id = QTI_INTR_INVALID_INT_NUM },
36 };
37 
qti_interrupt_svc_register(uint32_t id,qti_int_svc_isr_t func,void * ctx)38 int qti_interrupt_svc_register(uint32_t id, qti_int_svc_isr_t func, void *ctx)
39 {
40 	struct qti_isr *p = isr_table.entry;
41 
42 	spin_lock(&isr_table.lock);
43 	if (isr_table.cnt >= ISR_TABLE_LEN)
44 		goto error;
45 
46 	for (size_t i = 0; i < ISR_TABLE_LEN; i++, p++) {
47 		if (p->id != QTI_INTR_INVALID_INT_NUM) {
48 			continue;
49 		}
50 
51 		p->func = func;
52 		p->ctx = ctx;
53 		p->id = id;
54 		isr_table.cnt++;
55 		spin_unlock(&isr_table.lock);
56 
57 		return 0;
58 	}
59 error:
60 	spin_unlock(&isr_table.lock);
61 
62 	return -ENOTCAPABLE;
63 }
64 
qti_interrupt_svc_unregister(uint32_t id)65 int qti_interrupt_svc_unregister(uint32_t id)
66 {
67 	struct qti_isr *p = isr_table.entry;
68 
69 	spin_lock(&isr_table.lock);
70 	if (!isr_table.cnt)
71 		goto error;
72 
73 	for (size_t i = 0; i < ISR_TABLE_LEN; i++, p++) {
74 		if (p->id != id) {
75 			continue;
76 		}
77 
78 		memset(p, 0, sizeof(*p));
79 		p->id = QTI_INTR_INVALID_INT_NUM;
80 		isr_table.cnt--;
81 		spin_unlock(&isr_table.lock);
82 
83 		return 0;
84 	}
85 error:
86 	spin_unlock(&isr_table.lock);
87 
88 	return -ENOENT;
89 }
90 
interrupt_svc_invoke_isr(uint32_t id,void * handle)91 static void interrupt_svc_invoke_isr(uint32_t id, void *handle)
92 {
93 	struct qti_isr *p = isr_table.entry;
94 	qti_int_svc_isr_t invoke_isr = NULL;
95 
96 	spin_lock(&isr_table.lock);
97 	if (!isr_table.cnt)
98 		goto qtiseclib_dispatch;
99 
100 	for (size_t i = 0; i < ISR_TABLE_LEN; i++, p++) {
101 		if (p->id != id) {
102 			continue;
103 		}
104 
105 		invoke_isr = p->func;
106 		spin_unlock(&isr_table.lock);
107 		p->ctx = invoke_isr(id, p->ctx);
108 
109 		return;
110 	}
111 
112 qtiseclib_dispatch:
113 	spin_unlock(&isr_table.lock);
114 	qtiseclib_invoke_isr(id, handle);
115 }
116 
117 /*
118  * Top-level EL3 interrupt handler.
119  */
qti_el3_interrupt_handler(uint32_t id,uint32_t flags,void * handle,void * cookie)120 static uint64_t qti_el3_interrupt_handler(uint32_t id, uint32_t flags,
121 					  void *handle, void *cookie)
122 {
123 	uint32_t irq = QTI_INTR_INVALID_INT_NUM;
124 
125 	/*
126 	 * EL3 non-interruptible. Interrupt shouldn't occur when we are at
127 	 * EL3 / Secure.
128 	 */
129 	assert(handle != cm_get_context(SECURE));
130 
131 	irq = plat_ic_acknowledge_interrupt();
132 
133 	interrupt_svc_invoke_isr(irq, handle);
134 
135 	/* End of Interrupt. */
136 	if (irq < 1022U) {
137 		plat_ic_end_of_interrupt(irq);
138 	}
139 
140 	return (uint64_t) handle;
141 }
142 
qti_interrupt_svc_init(bool have_sel1)143 int qti_interrupt_svc_init(bool have_sel1)
144 {
145 	int ret;
146 	uint64_t flags = 0U;
147 
148 	/*
149 	 * Route EL3 interrupts to EL3 when in Non-secure.
150 	 * Note: EL3 won't have interrupts enabled.
151 	 * When we have a Secure EL1 interrupt handler, allow it
152 	 * to handle Secure interrupts.
153 	 */
154 	set_interrupt_rm_flag(flags, NON_SECURE);
155 	if (!have_sel1)
156 		set_interrupt_rm_flag(flags, SECURE);
157 
158 	/* Register handler for EL3 interrupts */
159 	ret = register_interrupt_type_handler(INTR_TYPE_EL3,
160 					      qti_el3_interrupt_handler, flags);
161 	assert(ret == 0);
162 
163 	return ret;
164 }
165