1/* 2 * Copyright 2019, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12#include <errno.h> 13#include <stdlib.h> 14#include <utils/util.h> 15#include "../../arch/arm/clock.h" 16#include <platsupport/timer.h> 17#include <platsupport/plat/system_timer.h> 18 19/* 20 * The system timer on the BCM283[5-7] is fairly simple in its nature. 21 * It has a 64-bit free-running counter and 4 compare registers. When 22 * the lower 32 bits of the free-running counter match one of the 23 * compare registers, an associated IRQ is generated and an associated 24 * control bit is set in the control register. 25 */ 26 27int system_timer_init(system_timer_t *timer, system_timer_config_t config) { 28 if (timer == NULL || config.vaddr == NULL) { 29 return EINVAL; 30 } 31 32 timer->regs = config.vaddr; 33 34 return 0; 35} 36 37uint64_t system_timer_get_time(system_timer_t *timer) { 38 if (timer == NULL) { 39 return EINVAL; 40 } 41 42 uint64_t initial_high = timer->regs->counter_high; 43 uint64_t low = timer->regs->counter_low; 44 uint64_t high = timer->regs->counter_high; 45 if (high != initial_high) { 46 /* get low again if high has ticked over. */ 47 low = timer->regs->counter_low; 48 } 49 50 uint64_t ticks = (high << 32) | low; 51 uint64_t time = ticks * SYSTEM_TIMER_NS_PER_TICK; 52 53 return time; 54} 55 56int system_timer_set_timeout(system_timer_t *timer, uint64_t ns) { 57 if (timer == NULL) { 58 return EINVAL; 59 } 60 61 /* Can only set a timeout within the next 2^32 microseconds. */ 62 uint64_t time = system_timer_get_time(timer); 63 uint64_t ticks = time / SYSTEM_TIMER_NS_PER_TICK; 64 uint64_t timeout_ticks = ns / SYSTEM_TIMER_NS_PER_TICK; 65 if (timeout_ticks < ticks) { 66 ZF_LOGE("Timeout in the past\n"); 67 return ETIME; 68 } else if ((timeout_ticks - ticks) > UINT32_MAX) { 69 ZF_LOGE("Timeout too far in the future\n"); 70 return ETIME; 71 } 72 73 /* Clear any existing interrupt. */ 74 timer->regs->ctrl = BIT(SYSTEM_TIMER_MATCH); 75 76 uint32_t timeout = timeout_ticks & MASK(32); 77 timer->regs->compare[SYSTEM_TIMER_MATCH] = timeout; 78 79 time = system_timer_get_time(timer); 80 if (time >= ns && !(timer->regs->ctrl & BIT(SYSTEM_TIMER_MATCH))) { 81 timer->regs->ctrl = BIT(SYSTEM_TIMER_MATCH); 82 ZF_LOGE("Timeout missed\n"); 83 return ETIME; 84 } 85 86 return 0; 87} 88 89int system_timer_handle_irq(system_timer_t *timer) { 90 if (timer == NULL) { 91 return EINVAL; 92 } 93 94 timer->regs->ctrl = BIT(SYSTEM_TIMER_MATCH); 95 96 return 0; 97} 98 99int system_timer_reset(system_timer_t *timer) { 100 if (timer == NULL) { 101 return EINVAL; 102 } 103 104 /* Just clear the one timer that is used. */ 105 timer->regs->ctrl = BIT(SYSTEM_TIMER_MATCH); 106 107 return 0; 108} 109