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#define TISR_MATCH_FLAG     BIT(0)
10#define TISR_OVF_FLAG       BIT(1)
11#define TISR_TCAR_FLAG      BIT(2)
12
13/* Kernel uses DMTIMER4 */
14struct timer {
15    uint32_t tidr; // 00h TIDR Identification Register
16    uint32_t padding1[3];
17    uint32_t cfg; // 10h TIOCP_CFG Timer OCP Configuration Register
18    uint32_t padding2[3];
19    uint32_t tieoi; // 20h IRQ_EOI Timer IRQ End-Of-Interrupt Register
20    uint32_t tisrr; // 24h IRQSTATUS_RAW Timer IRQSTATUS Raw Register
21    uint32_t tisr; // 28h IRQSTATUS Timer IRQSTATUS Register
22    uint32_t tier; // 2Ch IRQSTATUS_SET Timer IRQENABLE Set Register
23    uint32_t ticr; // 30h IRQSTATUS_CLR Timer IRQENABLE Clear Register
24    uint32_t twer; // 34h IRQWAKEEN Timer IRQ Wakeup Enable Register
25    uint32_t tclr; // 38h TCLR Timer Control Register
26    uint32_t tcrr; // 3Ch TCRR Timer Counter Register
27    uint32_t tldr; // 40h TLDR Timer Load Register
28    uint32_t ttgr; // 44h TTGR Timer Trigger Register
29    uint32_t twps; // 48h TWPS Timer Write Posted Status Register
30    uint32_t tmar; // 4Ch TMAR Timer Match Register
31    uint32_t tcar1; // 50h TCAR1 Timer Capture Register
32    uint32_t tsicr; // 54h TSICR Timer Synchronous Interface Control Register
33    uint32_t tcar2; // 58h TCAR2 Timer Capture Register
34};
35
36typedef volatile struct timer timer_t;
37extern timer_t *timer;
38
39#ifdef CONFIG_KERNEL_MCS
40
41extern uint32_t high_bits;
42
43/* Read the current time from the timer. */
44static inline ticks_t getCurrentTime(void)
45{
46    bool_t overflow = !!(timer->tisr & TISR_OVF_FLAG);
47    return ((((uint64_t) high_bits + overflow) << 32llu) + timer->tcrr);
48}
49
50#define HIGH_BYTES 0xffffffff00000000
51
52bool_t high_deadline = false;
53/* set the next deadline irq - deadline is absolute */
54static inline void setDeadline(ticks_t deadline)
55{
56    /* Set the deadline in two parts */
57    if ((deadline & HIGH_BYTES) != 0) {
58        deadline = (deadline & HIGH_BYTES) >> 32;
59        high_deadline = true;
60    }
61    assert((deadline & HIGH_BYTES) == 0);
62    timer->tmar = (uint32_t)deadline;
63}
64
65/* ack previous deadline irq */
66static inline void ackDeadlineIRQ(void)
67{
68    /* check if this is an overflow or match irq and ack */
69    if (timer->tisr & TISR_OVF_FLAG) {
70        high_bits++;
71        timer->tisr = TISR_OVF_FLAG;
72        assert((timer->tisr & TISR_OVF_FLAG) == 0);
73
74    }
75    if (timer->tisr & TISR_MATCH_FLAG) {
76        if (high_deadline) {
77            timer->tmar = 0xffffffff;
78            high_deadline = false;
79        }
80        timer->tisr = TISR_MATCH_FLAG;
81        assert((timer->tisr & TISR_MATCH_FLAG) == 0);
82    }
83}
84#else /* CONFIG_KERNEL_MCS */
85
86static inline void resetTimer(void)
87{
88    timer->tisr = TISR_OVF_FLAG | TISR_MATCH_FLAG | TISR_TCAR_FLAG;
89    ackInterrupt(KERNEL_TIMER_IRQ);
90}
91#endif /* !CONFIG_KERNEL_MCS */
92
93