diff --git a/components/drivers/Kconfig b/components/drivers/Kconfig index b77eda40d1..4a8a3e5c8a 100755 --- a/components/drivers/Kconfig +++ b/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 diff --git a/components/drivers/hwtimer/Kconfig b/components/drivers/hwtimer/Kconfig new file mode 100644 index 0000000000..a1755ba0e6 --- /dev/null +++ b/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 diff --git a/components/drivers/hwtimer/SConscript b/components/drivers/hwtimer/SConscript index 534e04b6c0..b6ffc580ed 100644 --- a/components/drivers/hwtimer/SConscript +++ b/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') diff --git a/components/drivers/hwtimer/hwtimer-arm_arch.c b/components/drivers/hwtimer/hwtimer-arm_arch.c new file mode 100644 index 0000000000..3cfb4318d8 --- /dev/null +++ b/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 +#include +#include + +/* support registers access and timer registers in libcpu */ +#include +#include + +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); diff --git a/components/drivers/hwtimer/hwtimer.c b/components/drivers/hwtimer/hwtimer.c index 27ffff6025..bcf9ea9a2a 100644 --- a/components/drivers/hwtimer/hwtimer.c +++ b/components/drivers/hwtimer/hwtimer.c @@ -15,6 +15,24 @@ #define DBG_LVL DBG_INFO #include +#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; diff --git a/components/drivers/include/drivers/hwtimer.h b/components/drivers/include/drivers/hwtimer.h index 5676765d60..6f11ff2c54 100644 --- a/components/drivers/include/drivers/hwtimer.h +++ b/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 diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h index a48269af42..5da3c955d6 100644 --- a/components/drivers/include/rtdevice.h +++ b/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" diff --git a/libcpu/aarch64/common/setup.c b/libcpu/aarch64/common/setup.c index 3ecddbc523..c74976b499 100644 --- a/libcpu/aarch64/common/setup.c +++ b/libcpu/aarch64/common/setup.c @@ -24,11 +24,6 @@ #include #include -#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);