1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the GNU General Public License version 2. Note that NO WARRANTY is provided.
8 * See "LICENSE_GPLv2.txt" for details.
9 *
10 * @TAG(DATA61_GPL)
11 */
12#ifndef __ARCH_MACHINE_GLOBAL_TIMER_H
13#define __ARCH_MACHINE_GLOBAL_TIMER_H
14
15#include <util.h>
16#include <config.h>
17#include <model/statedata.h>
18
19/* ARM Cortex-A9 MPCore global timer driver
20 * Documentation for this timer is available in
21 * the Cortex-A9 MPCore Technical Reference Manual
22 * section "Global Timer Counter Registers"
23 */
24struct timer {
25    uint32_t countLower;
26    uint32_t countUpper;
27    uint32_t control;
28    uint32_t isr;
29    uint32_t comparatorLower;
30    uint32_t comparatorUpper;
31    uint32_t autoInc;
32};
33typedef volatile struct timer timer_t;
34extern timer_t * const globalTimer;
35
36enum control {
37    ENABLE = 0,
38    COMP_ENABLE = 1,
39    IRQ_ENABLE = 2,
40    AUTO_INC = 3,
41    RESERVED = 4,
42    PRESCALER = 8,
43    RESERVED_2 = 16
44};
45
46/** DONT_TRANSLATE */
47static inline CONST ticks_t
48getTimerPrecision(void)
49{
50    return usToTicks(2);
51}
52
53/** DONT_TRANSLATE */
54static inline ticks_t
55getCurrentTime(void)
56{
57    uint32_t upper, upper2, lower;
58
59    upper = globalTimer->countUpper;
60    lower = globalTimer->countLower;
61    upper2 = globalTimer->countUpper;
62
63    /* account for race: upper could have increased while we
64     * read lower */
65    if (upper != upper2) {
66        lower = globalTimer->countLower;
67    }
68
69    return (((ticks_t) upper2 << 32llu) + (ticks_t) lower);
70}
71
72/** DONT_TRANSLATE */
73static inline void
74setDeadline(ticks_t deadline)
75{
76    assert(deadline > NODE_STATE(ksCurTime));
77    /* disable cmp */
78    globalTimer->control &= ~(BIT(COMP_ENABLE));
79    /* set low bits */
80    globalTimer->comparatorLower = (uint32_t) deadline;
81    /* set high bits */
82    globalTimer->comparatorUpper = (uint32_t) (deadline >> 32llu);
83    /* enable cmp */
84    globalTimer->control |= BIT(COMP_ENABLE);
85    /* if this fails PRECISION is too low */
86    assert(getCurrentTime() < deadline || globalTimer->isr == 1u);
87}
88
89/** DONT_TRANSLATE */
90static inline void
91ackDeadlineIRQ(void)
92{
93    /* disable cmp */
94    globalTimer->control &= ~(BIT(COMP_ENABLE));
95    /* ack the isr */
96    globalTimer->isr = 1;
97}
98
99#endif /* __ARCH_MACHINE_GLOBAL_TIMER_H */
100