xref: /optee_os/core/drivers/hfic.c (revision 2a50ce7dc9dd9e8e91499769ffa6862ae01c868b)
1a0602052SJens Wiklander // SPDX-License-Identifier: BSD-2-Clause
2a0602052SJens Wiklander /*
3a0602052SJens Wiklander  * Copyright (c) 2022, Linaro Limited
4a0602052SJens Wiklander  */
5a0602052SJens Wiklander 
6a0602052SJens Wiklander #include <assert.h>
767e55c51SEtienne Carriere #include <compiler.h>
8a0602052SJens Wiklander #include <config.h>
9a0602052SJens Wiklander #include <drivers/hfic.h>
10a0602052SJens Wiklander #include <kernel/interrupt.h>
11a0602052SJens Wiklander #include <kernel/panic.h>
12a0602052SJens Wiklander #include <kernel/thread.h>
13a0602052SJens Wiklander 
14e37b526dSJens Wiklander /*
15e37b526dSJens Wiklander  * For documentation of the paravirtualized interface see:
16e37b526dSJens Wiklander  * https://hafnium.readthedocs.io/en/latest/design/secure-partition-manager.html#paravirtualized-interfaces
17e37b526dSJens Wiklander  */
18e37b526dSJens Wiklander 
19e37b526dSJens Wiklander #define HF_INTERRUPT_ENABLE	0xff03
20e37b526dSJens Wiklander #define HF_INTERRUPT_GET	0xff04
21e37b526dSJens Wiklander #define HF_INTERRUPT_DEACTIVATE	0xff08
2249655078SJens Wiklander #define HF_INTERRUPT_RECONFIGURE 0xff09
23e37b526dSJens Wiklander 
24e37b526dSJens Wiklander #define HF_INVALID_INTID	0xffffffff
25e37b526dSJens Wiklander #define HF_MANAGED_EXIT_INTID	4
26e37b526dSJens Wiklander 
27e37b526dSJens Wiklander #define HF_INTERRUPT_TYPE_IRQ	0
28e37b526dSJens Wiklander #define HF_INTERRUPT_TYPE_FIQ	1
29e37b526dSJens Wiklander #define HF_ENABLE		1
30e37b526dSJens Wiklander #define HF_DISABLE		0
31e37b526dSJens Wiklander 
3249655078SJens Wiklander #define HF_INT_RECONFIGURE_STATUS 2
3349655078SJens Wiklander 
3467e55c51SEtienne Carriere struct hfic_data {
3567e55c51SEtienne Carriere 	struct itr_chip chip;
3667e55c51SEtienne Carriere };
3767e55c51SEtienne Carriere 
3867e55c51SEtienne Carriere static struct hfic_data hfic_data __nex_bss;
3967e55c51SEtienne Carriere 
40*2a50ce7dSEtienne Carriere static void hfic_op_configure(struct itr_chip *chip __unused, size_t it,
41a0602052SJens Wiklander 			      uint32_t type __unused, uint32_t prio __unused)
42a0602052SJens Wiklander {
43a0602052SJens Wiklander 	uint32_t res __maybe_unused = 0;
44a0602052SJens Wiklander 
45a0602052SJens Wiklander 	res = thread_hvc(HF_INTERRUPT_ENABLE, it, HF_ENABLE,
46a0602052SJens Wiklander 			 HF_INTERRUPT_TYPE_IRQ);
47a0602052SJens Wiklander 	assert(!res);
48a0602052SJens Wiklander }
49a0602052SJens Wiklander 
5049655078SJens Wiklander static void hfic_op_enable(struct itr_chip *chip __unused, size_t it)
5149655078SJens Wiklander {
5249655078SJens Wiklander 	uint32_t res __maybe_unused = 0;
5349655078SJens Wiklander 
5449655078SJens Wiklander 	res = thread_hvc(HF_INTERRUPT_RECONFIGURE, it,
5549655078SJens Wiklander 			 HF_INT_RECONFIGURE_STATUS, HF_ENABLE);
5649655078SJens Wiklander 	assert(!res);
5749655078SJens Wiklander }
5849655078SJens Wiklander 
59a0602052SJens Wiklander static void hfic_op_disable(struct itr_chip *chip __unused, size_t it)
60a0602052SJens Wiklander {
61a0602052SJens Wiklander 	uint32_t res __maybe_unused = 0;
62a0602052SJens Wiklander 
6349655078SJens Wiklander 	res = thread_hvc(HF_INTERRUPT_RECONFIGURE, it,
6449655078SJens Wiklander 			 HF_INT_RECONFIGURE_STATUS, HF_DISABLE);
65a0602052SJens Wiklander 	assert(!res);
66a0602052SJens Wiklander }
67a0602052SJens Wiklander 
68a0602052SJens Wiklander static const struct itr_ops hfic_ops = {
69*2a50ce7dSEtienne Carriere 	.configure = hfic_op_configure,
7059feef28SEtienne Carriere 	.mask = hfic_op_disable,
7159feef28SEtienne Carriere 	.unmask = hfic_op_enable,
72a0602052SJens Wiklander 	.enable = hfic_op_enable,
73a0602052SJens Wiklander 	.disable = hfic_op_disable,
74a0602052SJens Wiklander };
75a0602052SJens Wiklander 
7667e55c51SEtienne Carriere void hfic_init(void)
77a0602052SJens Wiklander {
7867e55c51SEtienne Carriere 	hfic_data.chip.ops = &hfic_ops;
7901980f3fSEtienne Carriere 	interrupt_main_init(&hfic_data.chip);
80a0602052SJens Wiklander }
81a0602052SJens Wiklander 
82358bf47cSEtienne Carriere /* Override interrupt_main_handler() with driver implementation */
83358bf47cSEtienne Carriere void interrupt_main_handler(void)
84a0602052SJens Wiklander {
85a0602052SJens Wiklander 	uint32_t id = 0;
86a0602052SJens Wiklander 	uint32_t res __maybe_unused = 0;
87a0602052SJens Wiklander 
88a0602052SJens Wiklander 	id = thread_hvc(HF_INTERRUPT_GET, 0, 0, 0);
89a0602052SJens Wiklander 	if (id == HF_INVALID_INTID) {
90a0602052SJens Wiklander 		DMSG("ignoring invalid interrupt %#"PRIx32, id);
91a0602052SJens Wiklander 		return;
92a0602052SJens Wiklander 	}
93a0602052SJens Wiklander 
9499e2612cSEtienne Carriere 	interrupt_call_handlers(&hfic_data.chip, id);
9599e2612cSEtienne Carriere 
96a0602052SJens Wiklander 	res = thread_hvc(HF_INTERRUPT_DEACTIVATE, id, id, 0);
97a0602052SJens Wiklander 	assert(!res);
98a0602052SJens Wiklander }
99