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