xref: /kvm-unit-tests/lib/arm/timer.c (revision e526bc786e9878c3880ae4b09b01a4572756e492)
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 
timer_save_state_fdt(void)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 
timer_save_state_acpi(void)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 
timer_save_state_acpi(void)79 static void timer_save_state_acpi(void)
80 {
81 	assert_msg(false, "ACPI not available");
82 }
83 
84 #endif
85 
timer_save_state(void)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