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