]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_rtc0.c
Update RISCC-V-RV32-SiFive_HiFive1_FreedomStudio project to latest tools and metal...
[freertos] / FreeRTOS / Demo / RISC-V_RV32_SiFive_HiFive1_FreedomStudio / freedom-metal / src / drivers / sifive_rtc0.c
1 /* Copyright 2019 SiFive, Inc */
2 /* SPDX-License-Identifier: Apache-2.0 */
3
4 #include <metal/machine/platform.h>
5
6 #ifdef METAL_SIFIVE_RTC0
7
8 #include <metal/drivers/sifive_rtc0.h>
9 #include <metal/machine.h>
10
11 #include <limits.h>
12
13 /* RTCCFG */
14 #define METAL_RTCCFG_RTCSCALE_MASK 0xF
15 #define METAL_RTCCFG_ENALWAYS (1 << 12)
16 #define METAL_RTCCFG_IP0 (1 << 28)
17
18 /* RTCCMP0 */
19 #define METAL_RTCCMP0_MAX UINT32_MAX
20
21 #define RTC_REG(base, offset) (((unsigned long)base + offset))
22 #define RTC_REGW(base, offset) (__METAL_ACCESS_ONCE((__metal_io_u32 *)RTC_REG(base, offset)))
23
24 uint64_t __metal_driver_sifive_rtc0_get_rate(const struct metal_rtc *const rtc) {
25     const struct metal_clock *const clock  = __metal_driver_sifive_rtc0_clock(rtc);
26     return metal_clock_get_rate_hz(clock);
27 }
28
29 uint64_t __metal_driver_sifive_rtc0_set_rate(const struct metal_rtc *const rtc, const uint64_t rate) {
30     const struct metal_clock *const clock  = __metal_driver_sifive_rtc0_clock(rtc);
31     return metal_clock_get_rate_hz(clock);
32 }
33
34 uint64_t __metal_driver_sifive_rtc0_get_compare(const struct metal_rtc *const rtc) {
35     const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc);
36
37     const uint32_t shift = RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) & METAL_RTCCFG_RTCSCALE_MASK;
38
39     return ((uint64_t)RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCMP0) << shift);
40 }
41
42 uint64_t __metal_driver_sifive_rtc0_set_compare(const struct metal_rtc *const rtc, const uint64_t compare) {
43     const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc);
44
45     /* Determine the bit shift and shifted value to store in rtccmp0/rtccfg.scale */
46     uint32_t shift = 0;
47     uint64_t comp_shifted = compare;
48     while (comp_shifted > METAL_RTCCMP0_MAX) {
49         shift += 1;
50         comp_shifted = comp_shifted >> shift;
51     }
52
53     /* Set the value of rtccfg.scale */
54     uint32_t cfg = RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG);
55     cfg &= ~(METAL_RTCCFG_RTCSCALE_MASK);
56     cfg |= (METAL_RTCCFG_RTCSCALE_MASK & shift);
57     RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) = cfg;
58
59     /* Set the value of rtccmp0 */
60     RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCMP0) = (uint32_t) comp_shifted;
61
62     return __metal_driver_sifive_rtc0_get_compare(rtc);
63 }
64
65 uint64_t __metal_driver_sifive_rtc0_get_count(const struct metal_rtc *const rtc) {
66     const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc);
67
68     uint64_t count = RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTHI);
69     count <<= 32;
70     count |= RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTLO);
71
72     return count;
73 }
74
75 uint64_t __metal_driver_sifive_rtc0_set_count(const struct metal_rtc *const rtc, const uint64_t count) {
76     const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc);
77
78     RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTHI) = (UINT_MAX & (count >> 32));
79     RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTLO) = (UINT_MAX & count);
80
81     return __metal_driver_sifive_rtc0_get_count(rtc);
82 }
83
84 int __metal_driver_sifive_rtc0_run(const struct metal_rtc *const rtc, const enum metal_rtc_run_option option) {
85     const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc);
86
87     switch (option) {
88     default:
89     case METAL_RTC_STOP:
90         RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) &= ~(METAL_RTCCFG_ENALWAYS);
91         break;
92     case METAL_RTC_RUN:
93         RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) |= METAL_RTCCFG_ENALWAYS;
94         break;
95     }
96
97     return 0;
98 }
99
100 struct metal_interrupt *__metal_driver_sifive_rtc0_get_interrupt(const struct metal_rtc *const rtc) {
101     return __metal_driver_sifive_rtc0_interrupt_parent(rtc);
102 }
103
104 int __metal_driver_sifive_rtc0_get_interrupt_id(const struct metal_rtc *const rtc) {
105     return __metal_driver_sifive_rtc0_interrupt_line(rtc);
106 }
107
108 __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_rtc0) = {
109     .rtc.get_rate = __metal_driver_sifive_rtc0_get_rate,
110     .rtc.set_rate = __metal_driver_sifive_rtc0_set_rate,
111     .rtc.get_compare = __metal_driver_sifive_rtc0_get_compare,
112     .rtc.set_compare = __metal_driver_sifive_rtc0_set_compare,
113     .rtc.get_count = __metal_driver_sifive_rtc0_get_count,
114     .rtc.set_count = __metal_driver_sifive_rtc0_set_count,
115     .rtc.run = __metal_driver_sifive_rtc0_run,
116     .rtc.get_interrupt = __metal_driver_sifive_rtc0_get_interrupt,
117     .rtc.get_interrupt_id = __metal_driver_sifive_rtc0_get_interrupt_id,
118 };
119
120 #endif
121