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 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 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 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 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