xref: /optee_os/core/drivers/hfic.c (revision e37b526d7289a9c5b8c399c20ff303bc19c150a9)
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 
23 #define HF_INVALID_INTID	0xffffffff
24 #define HF_MANAGED_EXIT_INTID	4
25 
26 #define HF_INTERRUPT_TYPE_IRQ	0
27 #define HF_INTERRUPT_TYPE_FIQ	1
28 #define HF_ENABLE		1
29 #define HF_DISABLE		0
30 
31 struct hfic_data {
32 	struct itr_chip chip;
33 };
34 
35 static struct hfic_data hfic_data __nex_bss;
36 
37 static void hfic_op_add(struct itr_chip *chip __unused, size_t it __unused,
38 			uint32_t type __unused, uint32_t prio __unused)
39 {
40 }
41 
42 static void hfic_op_enable(struct itr_chip *chip __unused, size_t it)
43 {
44 	uint32_t res __maybe_unused = 0;
45 
46 	res = thread_hvc(HF_INTERRUPT_ENABLE, it, HF_ENABLE,
47 			 HF_INTERRUPT_TYPE_IRQ);
48 	assert(!res);
49 }
50 
51 static void hfic_op_disable(struct itr_chip *chip __unused, size_t it)
52 {
53 	uint32_t res __maybe_unused = 0;
54 
55 	res = thread_hvc(HF_INTERRUPT_ENABLE, it, HF_DISABLE,
56 			 HF_INTERRUPT_TYPE_IRQ);
57 	assert(!res);
58 }
59 
60 static const struct itr_ops hfic_ops = {
61 	.add = hfic_op_add,
62 	.mask = hfic_op_disable,
63 	.unmask = hfic_op_enable,
64 	.enable = hfic_op_enable,
65 	.disable = hfic_op_disable,
66 };
67 
68 void hfic_init(void)
69 {
70 	hfic_data.chip.ops = &hfic_ops;
71 	interrupt_main_init(&hfic_data.chip);
72 }
73 
74 /* Override interrupt_main_handler() with driver implementation */
75 void interrupt_main_handler(void)
76 {
77 	uint32_t id = 0;
78 	uint32_t res __maybe_unused = 0;
79 
80 	id = thread_hvc(HF_INTERRUPT_GET, 0, 0, 0);
81 	if (id == HF_INVALID_INTID) {
82 		DMSG("ignoring invalid interrupt %#"PRIx32, id);
83 		return;
84 	}
85 
86 	interrupt_call_handlers(&hfic_data.chip, id);
87 
88 	res = thread_hvc(HF_INTERRUPT_DEACTIVATE, id, id, 0);
89 	assert(!res);
90 }
91