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