]> git.sur5r.net Git - freertos/blobdiff - 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
diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_rtc0.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_rtc0.c
new file mode 100644 (file)
index 0000000..79b81e7
--- /dev/null
@@ -0,0 +1,121 @@
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <metal/machine/platform.h>
+
+#ifdef METAL_SIFIVE_RTC0
+
+#include <metal/drivers/sifive_rtc0.h>
+#include <metal/machine.h>
+
+#include <limits.h>
+
+/* RTCCFG */
+#define METAL_RTCCFG_RTCSCALE_MASK 0xF
+#define METAL_RTCCFG_ENALWAYS (1 << 12)
+#define METAL_RTCCFG_IP0 (1 << 28)
+
+/* RTCCMP0 */
+#define METAL_RTCCMP0_MAX UINT32_MAX
+
+#define RTC_REG(base, offset) (((unsigned long)base + offset))
+#define RTC_REGW(base, offset) (__METAL_ACCESS_ONCE((__metal_io_u32 *)RTC_REG(base, offset)))
+
+uint64_t __metal_driver_sifive_rtc0_get_rate(const struct metal_rtc *const rtc) {
+    const struct metal_clock *const clock  = __metal_driver_sifive_rtc0_clock(rtc);
+    return metal_clock_get_rate_hz(clock);
+}
+
+uint64_t __metal_driver_sifive_rtc0_set_rate(const struct metal_rtc *const rtc, const uint64_t rate) {
+    const struct metal_clock *const clock  = __metal_driver_sifive_rtc0_clock(rtc);
+    return metal_clock_get_rate_hz(clock);
+}
+
+uint64_t __metal_driver_sifive_rtc0_get_compare(const struct metal_rtc *const rtc) {
+    const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc);
+
+    const uint32_t shift = RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) & METAL_RTCCFG_RTCSCALE_MASK;
+
+    return ((uint64_t)RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCMP0) << shift);
+}
+
+uint64_t __metal_driver_sifive_rtc0_set_compare(const struct metal_rtc *const rtc, const uint64_t compare) {
+    const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc);
+
+    /* Determine the bit shift and shifted value to store in rtccmp0/rtccfg.scale */
+    uint32_t shift = 0;
+    uint64_t comp_shifted = compare;
+    while (comp_shifted > METAL_RTCCMP0_MAX) {
+        shift += 1;
+        comp_shifted = comp_shifted >> shift;
+    }
+
+    /* Set the value of rtccfg.scale */
+    uint32_t cfg = RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG);
+    cfg &= ~(METAL_RTCCFG_RTCSCALE_MASK);
+    cfg |= (METAL_RTCCFG_RTCSCALE_MASK & shift);
+    RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) = cfg;
+
+    /* Set the value of rtccmp0 */
+    RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCMP0) = (uint32_t) comp_shifted;
+
+    return __metal_driver_sifive_rtc0_get_compare(rtc);
+}
+
+uint64_t __metal_driver_sifive_rtc0_get_count(const struct metal_rtc *const rtc) {
+    const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc);
+
+    uint64_t count = RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTHI);
+    count <<= 32;
+    count |= RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTLO);
+
+    return count;
+}
+
+uint64_t __metal_driver_sifive_rtc0_set_count(const struct metal_rtc *const rtc, const uint64_t count) {
+    const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc);
+
+    RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTHI) = (UINT_MAX & (count >> 32));
+    RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTLO) = (UINT_MAX & count);
+
+    return __metal_driver_sifive_rtc0_get_count(rtc);
+}
+
+int __metal_driver_sifive_rtc0_run(const struct metal_rtc *const rtc, const enum metal_rtc_run_option option) {
+    const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc);
+
+    switch (option) {
+    default:
+    case METAL_RTC_STOP:
+        RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) &= ~(METAL_RTCCFG_ENALWAYS);
+        break;
+    case METAL_RTC_RUN:
+        RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) |= METAL_RTCCFG_ENALWAYS;
+        break;
+    }
+
+    return 0;
+}
+
+struct metal_interrupt *__metal_driver_sifive_rtc0_get_interrupt(const struct metal_rtc *const rtc) {
+    return __metal_driver_sifive_rtc0_interrupt_parent(rtc);
+}
+
+int __metal_driver_sifive_rtc0_get_interrupt_id(const struct metal_rtc *const rtc) {
+    return __metal_driver_sifive_rtc0_interrupt_line(rtc);
+}
+
+__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_rtc0) = {
+    .rtc.get_rate = __metal_driver_sifive_rtc0_get_rate,
+    .rtc.set_rate = __metal_driver_sifive_rtc0_set_rate,
+    .rtc.get_compare = __metal_driver_sifive_rtc0_get_compare,
+    .rtc.set_compare = __metal_driver_sifive_rtc0_set_compare,
+    .rtc.get_count = __metal_driver_sifive_rtc0_get_count,
+    .rtc.set_count = __metal_driver_sifive_rtc0_set_count,
+    .rtc.run = __metal_driver_sifive_rtc0_run,
+    .rtc.get_interrupt = __metal_driver_sifive_rtc0_get_interrupt,
+    .rtc.get_interrupt_id = __metal_driver_sifive_rtc0_get_interrupt_id,
+};
+
+#endif
+