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 */
14 struct 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 
36 typedef volatile struct timer timer_t;
37 extern timer_t *timer;
38 
39 #ifdef CONFIG_KERNEL_MCS
40 
41 extern uint32_t high_bits;
42 
43 /* Read the current time from the timer. */
getCurrentTime(void)44 static 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 
52 bool_t high_deadline = false;
53 /* set the next deadline irq - deadline is absolute */
setDeadline(ticks_t deadline)54 static 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 */
ackDeadlineIRQ(void)66 static 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 
resetTimer(void)86 static 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