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