1 /* 2 * Initialize timers. 3 * 4 * Copyright (C) 2022, Arm Ltd., Nikos Nikoleris <nikos.nikoleris@arm.com> 5 * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com> 6 * 7 * This work is licensed under the terms of the GNU LGPL, version 2. 8 */ 9 #include <libcflat.h> 10 #include <acpi.h> 11 #include <devicetree.h> 12 #include <libfdt/libfdt.h> 13 #include <asm/gic.h> 14 #include <asm/timer.h> 15 16 struct timer_state __timer_state; 17 18 static void timer_save_state_fdt(void) 19 { 20 const struct fdt_property *prop; 21 const void *fdt = dt_fdt(); 22 int node, len; 23 u32 *data; 24 25 node = fdt_node_offset_by_compatible(fdt, -1, "arm,armv8-timer"); 26 assert(node >= 0 || node == -FDT_ERR_NOTFOUND); 27 28 if (node == -FDT_ERR_NOTFOUND) { 29 __timer_state.ptimer.irq = -1; 30 __timer_state.vtimer.irq = -1; 31 return; 32 } 33 34 /* 35 * From Linux devicetree timer binding documentation 36 * 37 * interrupts <type irq flags>: 38 * secure timer irq 39 * non-secure timer irq (ptimer) 40 * virtual timer irq (vtimer) 41 * hypervisor timer irq 42 */ 43 prop = fdt_get_property(fdt, node, "interrupts", &len); 44 assert(prop && len == (4 * 3 * sizeof(u32))); 45 46 data = (u32 *) prop->data; 47 assert(fdt32_to_cpu(data[3]) == 1 /* PPI */ ); 48 __timer_state.ptimer.irq = PPI(fdt32_to_cpu(data[4])); 49 __timer_state.ptimer.irq_flags = fdt32_to_cpu(data[5]); 50 assert(fdt32_to_cpu(data[6]) == 1 /* PPI */ ); 51 __timer_state.vtimer.irq = PPI(fdt32_to_cpu(data[7])); 52 __timer_state.vtimer.irq_flags = fdt32_to_cpu(data[8]); 53 } 54 55 #ifdef CONFIG_EFI 56 57 #include <acpi.h> 58 59 static void timer_save_state_acpi(void) 60 { 61 struct acpi_table_gtdt *gtdt = find_acpi_table_addr(GTDT_SIGNATURE); 62 63 if (!gtdt) { 64 printf("Cannot find ACPI GTDT"); 65 __timer_state.ptimer.irq = -1; 66 __timer_state.vtimer.irq = -1; 67 return; 68 } 69 70 __timer_state.ptimer.irq = gtdt->non_secure_el1_interrupt; 71 __timer_state.ptimer.irq_flags = gtdt->non_secure_el1_flags; 72 73 __timer_state.vtimer.irq = gtdt->virtual_timer_interrupt; 74 __timer_state.vtimer.irq_flags = gtdt->virtual_timer_flags; 75 } 76 77 #else 78 79 static void timer_save_state_acpi(void) 80 { 81 assert_msg(false, "ACPI not available"); 82 } 83 84 #endif 85 86 void timer_save_state(void) 87 { 88 if (dt_available()) 89 timer_save_state_fdt(); 90 else 91 timer_save_state_acpi(); 92 } 93