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