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