/* * Initialize timers. * * Copyright (C) 2022, Arm Ltd., Nikos Nikoleris * Copyright (C) 2014, Red Hat Inc, Andrew Jones * * This work is licensed under the terms of the GNU LGPL, version 2. */ #include #include #include #include #include #include struct timer_state __timer_state; static void timer_save_state_fdt(void) { const struct fdt_property *prop; const void *fdt = dt_fdt(); int node, len; u32 *data; node = fdt_node_offset_by_compatible(fdt, -1, "arm,armv8-timer"); assert(node >= 0 || node == -FDT_ERR_NOTFOUND); if (node == -FDT_ERR_NOTFOUND) { __timer_state.ptimer.irq = -1; __timer_state.vtimer.irq = -1; return; } /* * From Linux devicetree timer binding documentation * * interrupts : * secure timer irq * non-secure timer irq (ptimer) * virtual timer irq (vtimer) * hypervisor timer irq */ prop = fdt_get_property(fdt, node, "interrupts", &len); assert(prop && len == (4 * 3 * sizeof(u32))); data = (u32 *) prop->data; assert(fdt32_to_cpu(data[3]) == 1 /* PPI */ ); __timer_state.ptimer.irq = PPI(fdt32_to_cpu(data[4])); __timer_state.ptimer.irq_flags = fdt32_to_cpu(data[5]); assert(fdt32_to_cpu(data[6]) == 1 /* PPI */ ); __timer_state.vtimer.irq = PPI(fdt32_to_cpu(data[7])); __timer_state.vtimer.irq_flags = fdt32_to_cpu(data[8]); } #ifdef CONFIG_EFI #include static void timer_save_state_acpi(void) { struct acpi_table_gtdt *gtdt = find_acpi_table_addr(GTDT_SIGNATURE); if (!gtdt) { printf("Cannot find ACPI GTDT"); __timer_state.ptimer.irq = -1; __timer_state.vtimer.irq = -1; return; } __timer_state.ptimer.irq = gtdt->non_secure_el1_interrupt; __timer_state.ptimer.irq_flags = gtdt->non_secure_el1_flags; __timer_state.vtimer.irq = gtdt->virtual_timer_interrupt; __timer_state.vtimer.irq_flags = gtdt->virtual_timer_flags; } #else static void timer_save_state_acpi(void) { assert_msg(false, "ACPI not available"); } #endif void timer_save_state(void) { if (dt_available()) timer_save_state_fdt(); else timer_save_state_acpi(); }