Răsfoiți Sursa

[components/drivers]update hwtimer (#8565)

zms123456 1 an în urmă
părinte
comite
6b5058ba5c

+ 1 - 4
components/drivers/Kconfig

@@ -81,10 +81,6 @@ if RT_USING_CAN
         default n
 endif
 
-config RT_USING_HWTIMER
-    bool "Using hardware timer device drivers"
-    default n
-
 config RT_USING_CPUTIME
     bool "Enable CPU time for high resolution clock counter"
     default n
@@ -970,6 +966,7 @@ source "$RTT_DIR/components/drivers/pin/Kconfig"
 source "$RTT_DIR/components/drivers/pinctrl/Kconfig"
 source "$RTT_DIR/components/drivers/ktime/Kconfig"
 source "$RTT_DIR/components/drivers/clk/Kconfig"
+source "$RTT_DIR/components/drivers/hwtimer/Kconfig"
 
 menu "Using USB"
     config RT_USING_USB

+ 10 - 0
components/drivers/hwtimer/Kconfig

@@ -0,0 +1,10 @@
+menuconfig RT_USING_HWTIMER
+    bool "Using Hardware Timer device drivers"
+    default n
+
+config RT_HWTIMER_ARM_ARCH
+    bool "ARM ARCH Timer"
+    depends on RT_USING_DM
+    depends on RT_USING_HWTIMER
+    depends on ARCH_ARM_CORTEX_A || ARCH_ARMV8
+    default n

+ 13 - 3
components/drivers/hwtimer/SConscript

@@ -1,8 +1,18 @@
 from building import *
 
-cwd     = GetCurrentDir()
-src     = Glob('*.c')
+group = []
+
+if not GetDepend(['RT_USING_HWTIMER']):
+    Return('group')
+
+cwd = GetCurrentDir()
 CPPPATH = [cwd + '/../include']
-group   = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_HWTIMER'], CPPPATH = CPPPATH)
+
+src = ['hwtimer.c']
+
+if GetDepend(['RT_HWTIMER_ARM_ARCH']):
+    src += ['hwtimer-arm_arch.c']
+
+group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
 
 Return('group')

+ 383 - 0
components/drivers/hwtimer/hwtimer-arm_arch.c

@@ -0,0 +1,383 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2021-12-20     GuEe-GUI     first version
+ * 2022-08-24     GuEe-GUI     Add OFW support
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+#include <rtdevice.h>
+
+/* support registers access and timer registers in libcpu */
+#include <cpu.h>
+#include <cpuport.h>
+
+typedef void (*timer_ctrl_handle)(rt_bool_t enable);
+typedef rt_uint64_t (*timer_value_handle)(rt_uint64_t val);
+
+static volatile rt_uint64_t timer_step;
+
+static int arm_arch_timer_irq = -1;
+static timer_ctrl_handle arm_arch_timer_ctrl_handle = RT_NULL;
+static timer_value_handle arm_arch_timer_value_handle = RT_NULL;
+
+/* CTL */
+static void mon_ptimer_ctrl(rt_bool_t enable)
+{
+    rt_hw_sysreg_write(CNTPS_CTL, !!enable);
+}
+
+static void hyp_s_ptimer_ctrl(rt_bool_t enable)
+{
+#if ARCH_ARMV8_EXTENSIONS > 1
+    rt_hw_sysreg_write(CNTHPS_CTL, !!enable);
+#endif
+}
+
+static void hyp_ns_ptimer_ctrl(rt_bool_t enable)
+{
+    rt_hw_sysreg_write(CNTHP_CTL, !!enable);
+}
+
+static void hyp_s_vtimer_ctrl(rt_bool_t enable)
+{
+#if ARCH_ARMV8_EXTENSIONS > 1
+    rt_hw_sysreg_write(CNTHVS_CTL, !!enable);
+#endif
+}
+
+static void hyp_ns_vtimer_ctrl(rt_bool_t enable)
+{
+#if ARCH_ARMV8_EXTENSIONS > 1
+    rt_hw_sysreg_write(CNTHV_CTL, !!enable);
+#endif
+}
+
+static void os_ptimer_ctrl(rt_bool_t enable)
+{
+    rt_hw_sysreg_write(CNTP_CTL, !!enable);
+}
+
+static void os_vtimer_ctrl(rt_bool_t enable)
+{
+    rt_hw_sysreg_write(CNTV_CTL, !!enable);
+}
+
+/* TVAL */
+static rt_uint64_t mon_ptimer_value(rt_uint64_t val)
+{
+    if (val)
+    {
+        rt_hw_sysreg_write(CNTPS_TVAL, val);
+    }
+    else
+    {
+        rt_hw_sysreg_read(CNTPS_TVAL, val);
+    }
+
+    return val;
+}
+
+static rt_uint64_t hyp_s_ptimer_value(rt_uint64_t val)
+{
+#if ARCH_ARMV8_EXTENSIONS > 1
+    if (val)
+    {
+        rt_hw_sysreg_write(CNTHPS_TVAL, val);
+    }
+    else
+    {
+        rt_hw_sysreg_read(CNTHPS_TVAL, val);
+    }
+
+    return val;
+#else
+    return 0;
+#endif
+}
+
+static rt_uint64_t hyp_ns_ptimer_value(rt_uint64_t val)
+{
+    if (val)
+    {
+        rt_hw_sysreg_write(CNTHP_TVAL, val);
+    }
+    else
+    {
+        rt_hw_sysreg_read(CNTHP_TVAL, val);
+    }
+
+    return val;
+}
+
+static rt_uint64_t hyp_s_vtimer_value(rt_uint64_t val)
+{
+#if ARCH_ARMV8_EXTENSIONS > 1
+    if (val)
+    {
+        rt_hw_sysreg_write(CNTHVS_TVAL, val);
+    }
+    else
+    {
+        rt_hw_sysreg_read(CNTHVS_TVAL, val);
+    }
+
+    return val;
+#else
+    return 0;
+#endif
+}
+
+static rt_uint64_t hyp_ns_vtimer_value(rt_uint64_t val)
+{
+#if ARCH_ARMV8_EXTENSIONS > 1
+    if (val)
+    {
+        rt_hw_sysreg_write(CNTHV_TVAL, val);
+    }
+    else
+    {
+        rt_hw_sysreg_read(CNTHV_TVAL, val);
+    }
+
+    return val;
+#else
+    return 0;
+#endif
+}
+
+static rt_uint64_t os_ptimer_value(rt_uint64_t val)
+{
+    if (val)
+    {
+        rt_hw_sysreg_write(CNTP_TVAL, val);
+    }
+    else
+    {
+        rt_hw_sysreg_read(CNTP_TVAL, val);
+    }
+
+    return val;
+}
+
+static rt_uint64_t os_vtimer_value(rt_uint64_t val)
+{
+    if (val)
+    {
+        rt_hw_sysreg_write(CNTV_TVAL, val);
+    }
+    else
+    {
+        rt_hw_sysreg_read(CNTV_TVAL, val);
+    }
+
+    return val;
+}
+
+static timer_ctrl_handle ctrl_handle[] =
+{
+    mon_ptimer_ctrl,
+    hyp_s_ptimer_ctrl,
+    hyp_ns_ptimer_ctrl,
+    hyp_s_vtimer_ctrl,
+    hyp_ns_vtimer_ctrl,
+    os_ptimer_ctrl,
+    os_vtimer_ctrl,
+};
+
+static timer_value_handle value_handle[] =
+{
+    mon_ptimer_value,
+    hyp_s_ptimer_value,
+    hyp_ns_ptimer_value,
+    hyp_s_vtimer_value,
+    hyp_ns_vtimer_value,
+    os_ptimer_value,
+    os_vtimer_value,
+};
+
+static rt_err_t arm_arch_timer_local_enable(void)
+{
+    rt_err_t ret = RT_EOK;
+
+    if (arm_arch_timer_irq >= 0)
+    {
+        arm_arch_timer_ctrl_handle(RT_FALSE);
+        arm_arch_timer_value_handle(timer_step);
+
+        rt_hw_interrupt_umask(arm_arch_timer_irq);
+
+        arm_arch_timer_ctrl_handle(RT_TRUE);
+    }
+    else
+    {
+        ret = -RT_ENOSYS;
+    }
+
+    return ret;
+}
+
+rt_used
+static rt_err_t arm_arch_timer_local_disable(void)
+{
+    rt_err_t ret = RT_EOK;
+
+    if (arm_arch_timer_ctrl_handle)
+    {
+        arm_arch_timer_ctrl_handle(RT_FALSE);
+        rt_hw_interrupt_mask(arm_arch_timer_irq);
+    }
+    else
+    {
+        ret = -RT_ENOSYS;
+    }
+
+    return ret;
+}
+
+rt_used
+static rt_err_t arm_arch_timer_set_frequency(rt_uint64_t frq)
+{
+    rt_err_t ret = RT_EOK;
+
+#ifdef ARCH_SUPPORT_TEE
+    rt_hw_isb();
+    rt_hw_sysreg_write(CNTFRQ, frq);
+    rt_hw_dsb();
+#else
+    ret = -RT_ENOSYS;
+#endif
+
+    return ret;
+}
+
+rt_used
+static rt_uint64_t arm_arch_timer_get_frequency(void)
+{
+    rt_uint64_t frq;
+
+    rt_hw_isb();
+    rt_hw_sysreg_read(CNTFRQ, frq);
+    rt_hw_isb();
+
+    return frq;
+}
+
+rt_used
+static rt_err_t arm_arch_timer_set_value(rt_uint64_t val)
+{
+    rt_err_t ret = RT_EOK;
+
+    if (arm_arch_timer_value_handle)
+    {
+        val = arm_arch_timer_value_handle(val);
+    }
+    else
+    {
+        ret = -RT_ENOSYS;
+    }
+
+    return ret;
+}
+
+rt_used
+static rt_uint64_t arm_arch_timer_get_value(void)
+{
+    rt_uint64_t val = 0;
+
+    if (arm_arch_timer_value_handle)
+    {
+        val = arm_arch_timer_value_handle(0);
+    }
+
+    return val;
+}
+
+static void arm_arch_timer_isr(int vector, void *param)
+{
+    arm_arch_timer_set_value(timer_step);
+
+    rt_tick_increase();
+}
+
+static int arm_arch_timer_post_init(void)
+{
+    arm_arch_timer_local_enable();
+
+    return 0;
+}
+INIT_SECONDARY_CPU_EXPORT(arm_arch_timer_post_init);
+
+static rt_err_t arm_arch_timer_probe(struct rt_platform_device *pdev)
+{
+    int mode_idx, irq_idx;
+    const char *irq_name[] =
+    {
+        "phys",     /* Secure Phys IRQ */
+        "virt",     /* Non-secure Phys IRQ */
+        "hyp-phys", /* Virt IRQ */
+        "hyp-virt", /* Hyp IRQ */
+    };
+
+#if defined(ARCH_SUPPORT_TEE)
+    mode_idx = 0;
+    irq_idx = 0;
+#elif defined(ARCH_SUPPORT_HYP)
+    mode_idx = 2;
+    irq_idx = 3;
+#else
+    mode_idx = 5;
+    irq_idx = 1;
+#endif
+
+    arm_arch_timer_irq = rt_dm_dev_get_irq_by_name(&pdev->parent, irq_name[irq_idx]);
+
+    if (arm_arch_timer_irq < 0)
+    {
+        arm_arch_timer_irq = rt_dm_dev_get_irq(&pdev->parent, irq_idx);
+    }
+
+    if (arm_arch_timer_irq < 0)
+    {
+        return -RT_EEMPTY;
+    }
+
+    arm_arch_timer_ctrl_handle = ctrl_handle[mode_idx];
+    arm_arch_timer_value_handle = value_handle[mode_idx];
+
+    rt_hw_interrupt_install(arm_arch_timer_irq, arm_arch_timer_isr, RT_NULL, "tick-arm-timer");
+
+    timer_step = arm_arch_timer_get_frequency() / RT_TICK_PER_SECOND;
+
+    arm_arch_timer_local_enable();
+
+    return RT_EOK;
+}
+
+static const struct rt_ofw_node_id arm_arch_timer_ofw_ids[] =
+{
+    { .compatible = "arm,armv7-timer", },
+    { .compatible = "arm,armv8-timer", },
+    { /* sentinel */ }
+};
+
+static struct rt_platform_driver arm_arch_timer_driver =
+{
+    .name = "arm-arch-timer",
+    .ids = arm_arch_timer_ofw_ids,
+
+    .probe = arm_arch_timer_probe,
+};
+
+static int arm_arch_timer_drv_register(void)
+{
+    rt_platform_driver_register(&arm_arch_timer_driver);
+
+    return 0;
+}
+INIT_SUBSYS_EXPORT(arm_arch_timer_drv_register);

+ 18 - 0
components/drivers/hwtimer/hwtimer.c

@@ -15,6 +15,24 @@
 #define DBG_LVL DBG_INFO
 #include <rtdbg.h>
 
+#ifdef RT_USING_DM
+void (*rt_device_hwtimer_us_delay)(rt_uint32_t us) = RT_NULL;
+
+void rt_hw_us_delay(rt_uint32_t us)
+{
+    if (rt_device_hwtimer_us_delay)
+    {
+        rt_device_hwtimer_us_delay(us);
+    }
+    else
+    {
+        LOG_E("Implemented at least in the libcpu");
+
+        RT_ASSERT(0);
+    }
+}
+#endif /* RT_USING_DM */
+
 rt_inline rt_uint32_t timeout_calc(rt_hwtimer_t *timer, rt_hwtimerval_t *tv)
 {
     float overflow;

+ 4 - 0
components/drivers/include/drivers/hwtimer.h

@@ -78,6 +78,10 @@ typedef struct rt_hwtimer_device
 rt_err_t rt_device_hwtimer_register(rt_hwtimer_t *timer, const char *name, void *user_data);
 void rt_device_hwtimer_isr(rt_hwtimer_t *timer);
 
+#ifdef RT_USING_DM
+extern void (*rt_device_hwtimer_us_delay)(rt_uint32_t us);
+#endif
+
 #ifdef __cplusplus
 }
 #endif

+ 1 - 0
components/drivers/include/rtdevice.h

@@ -183,6 +183,7 @@ extern "C" {
 
 #ifdef RT_USING_DM
 #include "drivers/core/dm.h"
+#include "drivers/platform.h"
 
 #ifdef RT_USING_OFW
 #include "drivers/ofw.h"

+ 73 - 7
libcpu/aarch64/common/setup.c

@@ -24,11 +24,6 @@
 #include <ioremap.h>
 #include <rtdevice.h>
 
-#define rt_sysreg_write(sysreg, val) \
-    __asm__ volatile ("msr "RT_STRINGIFY(sysreg)", %0"::"r"((rt_uint64_t)(val)))
-
-#define rt_sysreg_read(sysreg, val) \
-    __asm__ volatile ("mrs %0, "RT_STRINGIFY(sysreg)"":"=r"((val)))
 #define SIZE_KB  1024
 #define SIZE_MB (1024 * SIZE_KB)
 #define SIZE_GB (1024 * SIZE_MB)
@@ -73,6 +68,68 @@ void rt_hw_fdt_install_early(void *fdt)
     }
 }
 
+#ifdef RT_USING_HWTIMER
+static rt_ubase_t loops_per_tick[RT_CPUS_NR];
+
+static rt_ubase_t cpu_get_cycles(void)
+{
+    rt_ubase_t cycles;
+
+    rt_hw_sysreg_read(cntpct_el0, cycles);
+
+    return cycles;
+}
+
+static void cpu_loops_per_tick_init(void)
+{
+    rt_ubase_t offset;
+    volatile rt_ubase_t freq, step, cycles_end1, cycles_end2;
+    volatile rt_uint32_t cycles_count1 = 0, cycles_count2 = 0;
+
+    rt_hw_sysreg_read(cntfrq_el0, freq);
+    step = freq / RT_TICK_PER_SECOND;
+
+    cycles_end1 = cpu_get_cycles() + step;
+
+    while (cpu_get_cycles() < cycles_end1)
+    {
+        __asm__ volatile ("nop");
+        __asm__ volatile ("add %0, %0, #1":"=r"(cycles_count1));
+    }
+
+    cycles_end2 = cpu_get_cycles() + step;
+
+    while (cpu_get_cycles() < cycles_end2)
+    {
+        __asm__ volatile ("add %0, %0, #1":"=r"(cycles_count2));
+    }
+
+    if ((rt_int32_t)(cycles_count2 - cycles_count1) > 0)
+    {
+        offset = cycles_count2 - cycles_count1;
+    }
+    else
+    {
+        /* Impossible, but prepared for any eventualities */
+        offset = cycles_count2 / 4;
+    }
+
+    loops_per_tick[rt_hw_cpu_id()] = offset;
+}
+
+static void cpu_us_delay(rt_uint32_t us)
+{
+    volatile rt_base_t start = cpu_get_cycles(), cycles;
+
+    cycles = ((us * 0x10c7UL) * loops_per_tick[rt_hw_cpu_id()] * RT_TICK_PER_SECOND) >> 32;
+
+    while ((cpu_get_cycles() - start) < cycles)
+    {
+        rt_hw_cpu_relax();
+    }
+}
+#endif /* RT_USING_HWTIMER */
+
 rt_weak void rt_hw_idle_wfi(void)
 {
     __asm__ volatile ("wfi");
@@ -90,7 +147,7 @@ rt_inline void cpu_info_init(void)
     struct rt_ofw_node *np;
 
     /* get boot cpu info */
-    rt_sysreg_read(mpidr_el1, mpidr);
+    rt_hw_sysreg_read(mpidr_el1, mpidr);
 
     rt_ofw_foreach_cpu_node(np)
     {
@@ -128,6 +185,15 @@ rt_inline void cpu_info_init(void)
     }
 
     rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, rt_cpu_mpidr_table, sizeof(rt_cpu_mpidr_table));
+
+#ifdef RT_USING_HWTIMER
+    cpu_loops_per_tick_init();
+
+    if (!rt_device_hwtimer_us_delay)
+    {
+        rt_device_hwtimer_us_delay = &cpu_us_delay;
+    }
+#endif /* RT_USING_HWTIMER */
 }
 
 rt_inline rt_bool_t is_kernel_aspace(const char *name)
@@ -421,7 +487,7 @@ rt_weak void rt_hw_secondary_cpu_bsp_start(void)
     rt_hw_spin_lock(&_cpus_lock);
 
     /* Save all mpidr */
-    rt_sysreg_read(mpidr_el1, rt_cpu_mpidr_table[cpu_id]);
+    rt_hw_sysreg_read(mpidr_el1, rt_cpu_mpidr_table[cpu_id]);
 
     rt_hw_mmu_ktbl_set((unsigned long)MMUTable);