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 */
22struct 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};
31typedef volatile struct timer timer_t;
32extern timer_t *const globalTimer;
33
34enum 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 */
45static 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 */
63static 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 */
78static 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