/* SPDX-License-Identifier: GPL-2.0+ */ /* * timer.c - generic timer delays, the system counter from D10. the * counter is a fixed frequency free running counter, CNTFRQ_EL0 * carries the frequency, CNTVCT_EL0 the 64 bit count. delays are a * busy wait on the counter, no interrupts needed, microsecond and * millisecond granularity. * * CNTVCT_EL0 is the virtual counter view; at EL2 with no offset * configured it is the physical count. the read is not speculative * and needs an isb to serialize against subsequent counter reads * per the counter access rules. * * Copyright (C) 2026 Bradley Morgan */ #include static uint64_t read_cntfrq(void) { uint64_t v; asm volatile("mrs %0, cntfrq_el0" : "=r" (v)); return v; } static uint64_t read_counter(void) { uint64_t v; asm volatile("isb\nmrs %0, cntvct_el0" : "=r" (v)); return v; } void tb_udelay(uint32_t us) { uint64_t freq = read_cntfrq(); uint64_t start = read_counter(); uint64_t ticks = (uint64_t)us * freq / 1000000ULL; while (read_counter() - start < ticks) ; } void tb_mdelay(uint32_t ms) { tb_udelay(ms * 1000); }