1/*
2 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7#pragma once
8
9#include <config.h>
10
11#define TISR_OVF_FLAG       BIT(1)
12#define TISR_MATCH_FLAG     BIT(0)
13
14struct timer {
15    uint32_t tidr;   /* GPTIMER_TIDR 0x00 */
16    uint32_t padding1[3];
17    uint32_t cfg;    /* GPTIMER_CFG 0x10 */
18    uint32_t tistat; /* GPTIMER_TISTAT 0x14 */
19    uint32_t tisr;   /* GPTIMER_TISR 0x18 */
20    uint32_t tier;   /* GPTIMER_TIER 0x1C */
21    uint32_t twer;   /* GPTIMER_TWER 0x20 */
22    uint32_t tclr;   /* GPTIMER_TCLR 0x24 */
23    uint32_t tcrr;   /* GPTIMER_TCRR 0x28 */
24    uint32_t tldr;   /* GPTIMER_TLDR 0x2C */
25    uint32_t ttgr;   /* GPTIMER_TTGR 0x30 */
26    uint32_t twps;   /* GPTIMER_TWPS 0x34 */
27    uint32_t tmar;   /* GPTIMER_TMAR 0x38 */
28    uint32_t tcar1;  /* GPTIMER_TCAR1 0x3C */
29    uint32_t tsicr;  /* GPTIMER_TSICR 0x40 */
30    uint32_t tcar2;  /* GPTIMER_TCAR2 0x44 */
31    uint32_t tpir;   /* GPTIMER_TPIR 0x48 */
32    uint32_t tnir;   /* GPTIMER_TNIR 0x4C */
33    uint32_t tcvr;   /* GPTIMER_TCVR 0x50 */
34    uint32_t tocr;   /* GPTIMER_TOCR 0x54 */
35    uint32_t towr;   /* GPTIMER_TOWR 0x58 */
36};
37typedef volatile struct timer timer_t;
38extern timer_t *timer;
39
40#ifdef CONFIG_KERNEL_MCS
41/* this is a 32-bit timer, track high_bits here */
42extern uint32_t high_bits;
43
44/** DONT_TRANSLATE */
45static inline void setDeadline(ticks_t deadline)
46{
47    timer->tmar = (uint32_t) deadline;
48}
49
50/** DONT_TRANSLATE */
51static inline ticks_t getCurrentTime(void)
52{
53    bool_t overflow = !!(timer->tisr & TISR_OVF_FLAG);
54    return (((uint64_t) high_bits + overflow) << 32llu) + timer->tcrr;
55}
56
57/** DONT_TRANSLATE */
58static inline void ackDeadlineIRQ(void)
59{
60    /* check if this is an overflow irq */
61    if (timer->tisr & TISR_OVF_FLAG) {
62        high_bits++;
63    }
64
65    /* ack everything */
66    timer->tisr = TISR_OVF_FLAG | TISR_MATCH_FLAG;
67    assert((timer->tisr & TISR_OVF_FLAG) == 0);
68}
69#else /* CONFIG_KERNEL_MCS */
70static inline void resetTimer(void)
71{
72    timer->tisr = TISR_OVF_FLAG;
73    ackInterrupt(KERNEL_TIMER_IRQ);
74}
75#endif /* !CONFIG_KERNEL_MCS */
76