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 BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13#include <stdio.h>
14#include <assert.h>
15#include <errno.h>
16
17#include <utils/util.h>
18#include <utils/time.h>
19
20#include <platsupport/plat/rtc.h>
21
22#define HIKEY_RTCCR_ENABLE_SHIFT    (0)
23
24typedef volatile struct rtc_regs {
25    uint32_t rtcdr;     /* Data reg: RO: returns current value of 1Hz upcounter */
26    uint32_t rtcmr;     /* Comparison reg: RW: for the alarm (irq) feature.
27                         * Generates an IRQ when rtcmr == rtcdr.
28                         * Don't care: we don't use the alarm feature.
29                         */
30    uint32_t rtclr;     /* Load reg: RW: the initial value of the upcounter. */
31    uint32_t rtccr;     /* Control reg: literally only has an enable bit (bit 0)
32                         * and that's it. Absolute control.
33                         */
34    uint32_t rtcimsc;   /* Interrupt mask reg: Don't care. we don't use the alarm
35                         * feature.
36                         */
37    uint32_t rtcris;    /* Raw Interrupt status reg: don't care. */
38    uint32_t rtcmis;    /* Masked interrupt status reg: don't care. */
39    uint32_t rtcicr;    /* interrupt clear reg: don't care. */
40} rtc_regs_t;
41
42static inline rtc_regs_t *
43rtc_get_regs(rtc_t *rtc)
44{
45    assert(rtc != NULL);
46    assert(rtc->vaddr != NULL);
47    return rtc->vaddr;
48}
49
50int rtc_start(rtc_t *rtc)
51{
52    rtc_regs_t *regs = rtc_get_regs(rtc);
53
54    /* We set the initial value of the upcounter to 0 when
55     * initializing, because we have no reason to use any
56     * other value, and because we have no guarantee that
57     * it starts at a sensibly low value if not explicitly set.
58     */
59    regs->rtclr = 0;
60    regs->rtccr = BIT(HIKEY_RTCCR_ENABLE_SHIFT);
61    return 0;
62}
63
64int rtc_stop(rtc_t *rtc)
65{
66    rtc_regs_t *regs = rtc_get_regs(rtc);
67    regs->rtccr = 0;
68    return 0;
69}
70
71uint32_t rtc_get_time(rtc_t *rtc)
72{
73    rtc_regs_t *regs = rtc_get_regs(rtc);
74    return regs->rtcdr;
75}
76
77int rtc_init(rtc_t *rtc, rtc_config_t config)
78{
79    if (config.id < RTC0 || config.id > RTC1) {
80        ZF_LOGE("Invalid timer device ID for a hikey RTC timer.");
81        return EINVAL;
82    }
83
84    if (config.vaddr == NULL) {
85        ZF_LOGE("Vaddr of the mapped RTC device register frame is required.");
86        return EINVAL;
87    }
88
89    rtc->vaddr = config.vaddr;
90    return 0;
91}
92