1 /* Copyright 2019 SiFive, Inc */
2 /* SPDX-License-Identifier: Apache-2.0 */
4 #include <metal/machine/platform.h>
6 #ifdef METAL_SIFIVE_RTC0
8 #include <metal/drivers/sifive_rtc0.h>
9 #include <metal/machine.h>
14 #define METAL_RTCCFG_RTCSCALE_MASK 0xF
15 #define METAL_RTCCFG_ENALWAYS (1 << 12)
16 #define METAL_RTCCFG_IP0 (1 << 28)
19 #define METAL_RTCCMP0_MAX UINT32_MAX
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)))
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);
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);
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);
37 const uint32_t shift = RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) & METAL_RTCCFG_RTCSCALE_MASK;
39 return ((uint64_t)RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCMP0) << shift);
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);
45 /* Determine the bit shift and shifted value to store in rtccmp0/rtccfg.scale */
47 uint64_t comp_shifted = compare;
48 while (comp_shifted > METAL_RTCCMP0_MAX) {
50 comp_shifted = comp_shifted >> shift;
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;
59 /* Set the value of rtccmp0 */
60 RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCMP0) = (uint32_t) comp_shifted;
62 return __metal_driver_sifive_rtc0_get_compare(rtc);
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);
68 uint64_t count = RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTHI);
70 count |= RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTLO);
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);
78 RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTHI) = (UINT_MAX & (count >> 32));
79 RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTLO) = (UINT_MAX & count);
81 return __metal_driver_sifive_rtc0_get_count(rtc);
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);
90 RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) &= ~(METAL_RTCCFG_ENALWAYS);
93 RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) |= METAL_RTCCFG_ENALWAYS;
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);
104 int __metal_driver_sifive_rtc0_get_interrupt_id(const struct metal_rtc *const rtc) {
105 return __metal_driver_sifive_rtc0_interrupt_line(rtc);
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,