[components/drivers]update hwtimer (#8565)
This commit is contained in:
parent
97c5edf947
commit
6b5058ba5c
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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')
|
||||
|
|
|
@ -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);
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue