文章目录

https://github.com/wdfk-prog/linux-study
arch/arm/lib/delay.c
register_current_timer_delay 注册当前定时器延迟
void __init register_current_timer_delay(const struct delay_timer *timer)
{
u32 new_mult, new_shift;
u64 res;
clocks_calc_mult_shift(&new_mult, &new_shift, timer->freq,
NSEC_PER_SEC, 3600);
res = cyc_to_ns(1ULL, new_mult, new_shift);
if (res > 1000) {
pr_err("Ignoring delay timer %ps, which has insufficient resolution of %lluns\n",
timer, res);
return;
}
if (!delay_calibrated && (!delay_res || (res < delay_res))) {
pr_info("Switching to timer-based delay loop, resolution %lluns\n", res);
delay_timer = timer;
lpj_fine = timer->freq / HZ;
delay_res = res;
/* cpufreq 可能会loops_per_jiffy扩展,因此请保留一个私有副本 */
arm_delay_ops.ticks_per_jiffy = lpj_fine;
arm_delay_ops.delay = __timer_delay;
arm_delay_ops.const_udelay = __timer_const_udelay;
arm_delay_ops.udelay = __timer_udelay;
} else {
pr_info("Ignoring duplicate/late registration of read_current_timer delay\n");
}
}
read_current_timer 读取当前定时器
int read_current_timer(unsigned long *timer_val)
{
if (!delay_timer)
return -ENXIO;
*timer_val = delay_timer->read_current_timer();
return 0;
}
EXPORT_SYMBOL_GPL(read_current_timer);
drivers/clocksource/timer-stm32.c
stm32_clocksource_init STM32 平台上初始化时钟源
static unsigned long stm32_read_delay(void)
{
return readl_relaxed(stm32_timer_cnt);
}
static int __init stm32_clocksource_init(struct timer_of *to)
{
u32 bits = stm32_timer_of_bits_get(to);
const char *name = to->np->full_name;
/*
* 此驱动程序允许注册多个计时器,并依赖于通用时间框架来选择正确的计时器。
* 但是,不允许对 sched_clock 执行相同的作。
* 我们对 16 位定时器的 sched_clock 不感兴趣,而只对 32 位定时器感兴趣,
* 因此如果尚未注册 32 位定时器,我们选择这个 32 位定时器作为sched_clock。
*/
if (bits == 32 && !stm32_timer_cnt) {
/*
* 立即启动计数器,因为我们将在之后立即使用它。
*/
stm32_timer_start(to);
/* 获取计数器寄存器地址 */
stm32_timer_cnt = timer_of_base(to) + TIM_CNT;
sched_clock_register(stm32_read_sched_clock, bits, timer_of_rate(to));
pr_info("%s: STM32 sched_clock registered\n", name);
stm32_timer_delay.read_current_timer = stm32_read_delay;
stm32_timer_delay.freq = timer_of_rate(to);
register_current_timer_delay(&stm32_timer_delay);
pr_info("%s: STM32 delay timer registered\n", name);
}
return clocksource_mmio_init(timer_of_base(to) + TIM_CNT, name,
timer_of_rate(to), bits == 32 ? 250 : 100,
bits, clocksource_mmio_readl_up);
}