xref: /optee_os/core/drivers/hfic.c (revision af3fb62410645ac9636d27c3d1db72c0c9fca913)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2022, Linaro Limited
4  */
5 
6 #include <assert.h>
7 #include <compiler.h>
8 #include <config.h>
9 #include <drivers/hfic.h>
10 #include <kernel/interrupt.h>
11 #include <kernel/panic.h>
12 #include <kernel/thread.h>
13 
14 /*
15  * For documentation of the paravirtualized interface see:
16  * https://hafnium.readthedocs.io/en/latest/design/secure-partition-manager.html#paravirtualized-interfaces
17  */
18 
19 #define HF_INTERRUPT_ENABLE	0xff03
20 #define HF_INTERRUPT_GET	0xff04
21 #define HF_INTERRUPT_DEACTIVATE	0xff08
22 #define HF_INTERRUPT_RECONFIGURE 0xff09
23 
24 #define HF_INVALID_INTID	0xffffffff
25 #define HF_MANAGED_EXIT_INTID	4
26 
27 #define HF_INTERRUPT_TYPE_IRQ	0
28 #define HF_INTERRUPT_TYPE_FIQ	1
29 #define HF_ENABLE		1
30 #define HF_DISABLE		0
31 
32 #define HF_INT_RECONFIGURE_STATUS 2
33 
34 struct hfic_data {
35 	struct itr_chip chip;
36 };
37 
38 static struct hfic_data hfic_data __nex_bss;
39 
40 static void hfic_op_add(struct itr_chip *chip __unused, size_t it,
41 			uint32_t type __unused, uint32_t prio __unused)
42 {
43 	uint32_t res __maybe_unused = 0;
44 
45 	res = thread_hvc(HF_INTERRUPT_ENABLE, it, HF_ENABLE,
46 			 HF_INTERRUPT_TYPE_IRQ);
47 	assert(!res);
48 }
49 
50 static void hfic_op_enable(struct itr_chip *chip __unused, size_t it)
51 {
52 	uint32_t res __maybe_unused = 0;
53 
54 	res = thread_hvc(HF_INTERRUPT_RECONFIGURE, it,
55 			 HF_INT_RECONFIGURE_STATUS, HF_ENABLE);
56 	assert(!res);
57 }
58 
59 static void hfic_op_disable(struct itr_chip *chip __unused, size_t it)
60 {
61 	uint32_t res __maybe_unused = 0;
62 
63 	res = thread_hvc(HF_INTERRUPT_RECONFIGURE, it,
64 			 HF_INT_RECONFIGURE_STATUS, HF_DISABLE);
65 	assert(!res);
66 }
67 
68 static const struct itr_ops hfic_ops = {
69 	.add = hfic_op_add,
70 	.mask = hfic_op_disable,
71 	.unmask = hfic_op_enable,
72 	.enable = hfic_op_enable,
73 	.disable = hfic_op_disable,
74 };
75 
76 void hfic_init(void)
77 {
78 	hfic_data.chip.ops = &hfic_ops;
79 	interrupt_main_init(&hfic_data.chip);
80 }
81 
82 /* Override interrupt_main_handler() with driver implementation */
83 void interrupt_main_handler(void)
84 {
85 	uint32_t id = 0;
86 	uint32_t res __maybe_unused = 0;
87 
88 	id = thread_hvc(HF_INTERRUPT_GET, 0, 0, 0);
89 	if (id == HF_INVALID_INTID) {
90 		DMSG("ignoring invalid interrupt %#"PRIx32, id);
91 		return;
92 	}
93 
94 	interrupt_call_handlers(&hfic_data.chip, id);
95 
96 	res = thread_hvc(HF_INTERRUPT_DEACTIVATE, id, id, 0);
97 	assert(!res);
98 }
99