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 <util.h>
10 #include <config.h>
11 #include <model/statedata.h>
12 
13 #ifndef CONFIG_KERNEL_MCS
14 #error "This driver should only be selected for MCS kernel"
15 #endif /* CONFIG_KERNEL_MCS */
16 
17 /* ARM Cortex-A9 MPCore global timer driver
18  * Documentation for this timer is available in
19  * the Cortex-A9 MPCore Technical Reference Manual
20  * section "Global Timer Counter Registers"
21  */
22 struct timer {
23     uint32_t countLower;
24     uint32_t countUpper;
25     uint32_t control;
26     uint32_t isr;
27     uint32_t comparatorLower;
28     uint32_t comparatorUpper;
29     uint32_t autoInc;
30 };
31 typedef volatile struct timer timer_t;
32 extern timer_t *const globalTimer;
33 
34 enum control {
35     ENABLE = 0,
36     COMP_ENABLE = 1,
37     IRQ_ENABLE = 2,
38     AUTO_INC = 3,
39     RESERVED = 4,
40     PRESCALER = 8,
41     RESERVED_2 = 16
42 };
43 
44 /** DONT_TRANSLATE */
getCurrentTime(void)45 static inline ticks_t getCurrentTime(void)
46 {
47     uint32_t upper, upper2, lower;
48 
49     upper = globalTimer->countUpper;
50     lower = globalTimer->countLower;
51     upper2 = globalTimer->countUpper;
52 
53     /* account for race: upper could have increased while we
54      * read lower */
55     if (upper != upper2) {
56         lower = globalTimer->countLower;
57     }
58 
59     return (((ticks_t) upper2 << 32llu) + (ticks_t) lower);
60 }
61 
62 /** DONT_TRANSLATE */
setDeadline(ticks_t deadline)63 static inline void setDeadline(ticks_t deadline)
64 {
65     /* disable cmp */
66     globalTimer->control &= ~(BIT(COMP_ENABLE));
67     /* set low bits */
68     globalTimer->comparatorLower = (uint32_t) deadline;
69     /* set high bits */
70     globalTimer->comparatorUpper = (uint32_t)(deadline >> 32llu);
71     /* enable cmp */
72     globalTimer->control |= BIT(COMP_ENABLE);
73     /* if this fails PRECISION is too low */
74     assert(getCurrentTime() < deadline || globalTimer->isr == 1u);
75 }
76 
77 /** DONT_TRANSLATE */
ackDeadlineIRQ(void)78 static inline void ackDeadlineIRQ(void)
79 {
80     /* disable cmp */
81     globalTimer->control &= ~(BIT(COMP_ENABLE));
82     /* ack the isr */
83     globalTimer->isr = 1;
84 }
85 
86 
87