return 0;
}
// 获取自ref_jiffies后所增加的计数值
int get_arch_cycles(unsigned long ref_jiffies)
{
extern unsigned long do_getmachinecycles(void);
int ret;
unsigned now;
unsigned temp_jiffies;
unsigned diff_jiffies;
do {
/* snapshot jiffies */
temp_jiffies = jiffies;
barrier();
/* calculate cycles since the current jiffy */
now = davinci_timer32_read(davinci_timers[tid_freerun]);
ret = now - davinci_timer32_last;
/* compensate for ref_jiffies in the past */
if (unlikely(diff_jiffies = jiffies - ref_jiffies))
ret += diff_jiffies * arch_cycles_per_jiffy;
barrier();
/* repeat if we didn't have a consistent view of the world */
} while (unlikely(temp_jiffies != jiffies));
return ret;
}
// high-res定时器的中断服务例程,用于调度高精度软定时器
static irqreturn_t
hr_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
/*
在include/linux/hrtime.h中又如下定义:
#ifdef HRTIME_PER_CPU
#define do_hr_timer_int() raise_softirq(HRTIMER_SOFTIRQ)
#else
extern struct tasklet_struct hrt_tasklet;
#define do_hr_timer_int() tasklet_schedule(&hrt_tasklet)
#endif
在DM644x平台,HRTIME_PER_CPU没有被定义,所以该中断例程只是用于调度高精度hrt_tasklet
软中断
*/
do_hr_timer_int();
return IRQ_HANDLED;
}
static int hr_timer_init(void)
{
int ret = 0;
/* Initialized by init of davinci_timers[] array */
return ret;
}
__initcall(hr_timer_init);
#endif /* CONFIG_HIGH_RES_TIMERS */
static davinci_timer_t davinci_system_timer = {
.name = "system tick", // 系统定时器,也就是系统的“心脏”,负责推动系统运行
.period = ((DM644X_CLOCK_TICK_RATE / HZ) - 1), // 设置系统定时器滴答时间(10ms)
.opts = TIMER_CONTINUOUS, // 连续运行模式
.irqaction = {
// 快速无延迟中断,SA_NODELAY在打开内核抢占的情况下表明不使用内核线程处理中断
.flags = SA_INTERRUPT | SA_NODELAY,
.handler = system_timer_interrupt,// 系统定时器中断处理例程
}
};
static davinci_timer_t davinci_freerun_timer = {
.name = "free-run counter",
.period = 0xffffffff, // 设置成这么大就是为了使他计时尽量久,作为标准值计数来参考
.opts = TIMER_CONTINUOUS, // 连续运行模式
.irqaction = {
.flags = SA_INTERRUPT, // 快速中断
.handler = freerun_interrupt, // 中断处理例程
}
};
#ifdef CONFIG_HIGH_RES_TIMERS
static davinci_timer_t davinci_hrt_timer = {
.name = "high-res timer", // 高精度定时器,用于调度高精度软定时器
.opts = TIMER_DISABLED, // 禁止运行模式,也就是不计数,但保留当前的值
.period = 0, // 暂时设置成0
.irqaction = {
.flags = SA_INTERRUPT | SA_NODELAY,//快速无延迟中断
.handler = hr_timer_interrupt,// 中断处理例程
}
};
#endif
static davinci_timer_t davinci_default_timer = {
.name = NULL,
};
// DM6446平台定时器初始化例程
void __init davinci_timer_init(void)
{
int i;
davinci_timer_regs_t *t0 = davinci_timer_base(T0_BOT);
davinci_timer_regs_t *t1 = davinci_timer_base(T1_BOT);
davinci_timer_regs_t *t2 = davinci_timer_base(T2_WDT);
// 针对DM6467平台
if (cpu_is_davinci_dm6467()) {
davinci_system_timer.period = (DM646X_CLOCK_TICK_RATE / HZ) - 1;
timer_irqs = dm646x_timer_irqs;
NUM_TIMERS = ARRAY_SIZE(dm646x_timer_irqs);
/*
* T0_BOT: Timer 0, bottom: AV Sync
* T0_TOP: Timer 0, top: free-running counter,
used for cycle counter
* T1_BOT: Timer 1, bottom: reserved for DSP
* T1_TOP: Timer 1, top : Linux system tick
* T2_WDT: Timer 2, : high-res timer programmable timer
*/
tid_system = T1_TOP;
tid_freerun = T0_TOP;
tid_hrt = T2_WDT;
} else {
if (cpu_is_davinci_dm355())
davinci_system_timer.period =
(DM355_CLOCK_TICK_RATE / HZ) - 1;
timer_irqs = davinci_timer_irqs;
NUM_TIMERS = ARRAY_SIZE(davinci_timer_irqs);
/*
* T0_BOT: Timer 0, bottom: free-running counter,
used for cycle counter
* T0_TOP: Timer 0, top : high-res timer programmable timer
* T1_BOT: Timer 1, bottom: reserved for DSP
* T1_TOP: Timer 1, top : Linux system tick
*/
tid_system = T1_TOP;
tid_freerun = T0_BOT;
tid_hrt = T0_TOP;
}
for (i = 0; i < NUM_TIMERS; i++)
davinci_timers[i] = &davinci_default_timer;
// 设置系统定时器控制结构体
davinci_timers[tid_system] = &davinci_system_timer;
davinci_timers[tid_freerun] = &davinci_freerun_timer;
#ifdef CONFIG_HIGH_RES_TIMERS
davinci_timers[tid_hrt] = &davinci_hrt_timer;
#endif
/*
Disabled, Internal clock source
T0和T1采用内部时钟源,且被禁止
*/
t0->tcr = 0x0;
t1->tcr = 0x0;
/*
reset both timers, no pre-scaler for timer34
T1禁止分频
*/
t0->tgcr = 0;
t1->tgcr = 0;
/*
Set both timers to unchained 32-bit
T0和T1设置成非级联的32位定时器
*/
t0->tgcr |= 0x4; // TIMMODE = 1
t1->tgcr |= 0x4;
/*
Unreset timers
激活定时器T0和T1
*/
t0->tgcr |= 0x3;
t1->tgcr |= 0x3;
/*
Init both counters to zero
计数寄存器置为0
*/
t0->tim12 = 0;
t0->tim34 = 0;
t1->tim12 = 0;
t1->tim34 = 0;
/* do the same thing for timer 2 if cpu is dm6467 */
if (cpu_is_davinci_dm6467()) {
t2->tcr = 0x0;
t2->tgcr = 0;
/* T2 can only operate as a single 64-bit timer
* t2->tgcr |= 0x4; */
t2->tgcr |= 0x3;
t2->tim12 = 0;
t2->tim34 = 0;
}
for (i = 0; i < NUM_TIMERS; i++) {
davinci_timer_t *t = davinci_timers[i];
if (t->name) {
t->id = i;
t->regs = // 映射各个定时器的寄存器组
(davinci_timer_regs_t *) davinci_timer_base(t->id);
t->irqaction.name = t->name; // 用户中断名称
t->irqaction.dev_id = (void *)t; // 用户中断私有数据
// 配置和注册时钟中断
davinci_timer32_config(t);
}
}
}
/*
这个结构体在arch/arm/mach-davinci文件中被调用,保存在机器描述符里(struct machine_desc),
在系统启动时会调用davinci_timer_init()例程初始化定时器。调用的过程是:
start_kernel()-->setup_arch()-->system_timer = mdesc->timer(system_timer是个全局
指针变量,mdesc->timer指针指向的就是本文中的已经注册到机器描述符里的davinci_timer结构体),
然后便是start_kernel()-->time_init()-->system_timer->init()(也就是
davinci_timer_init())。
从上可以看出经历了两个过程,才调用davinci_timer_init()例程来初始化定时器。
*/
struct sys_timer davinci_timer = {
.init = davinci_timer_init,
.offset = davinci_gettimeoffset,
};
/*
使用看门狗复位系统.
用户使用重启命令reboot后,会调用到该例程,具体过程是:sys_reboot()-->machine_restart()
-->arch_reset()-->davinci_watchdog_reset()。
*/
void davinci_watchdog_reset(void)
{
davinci_timer_regs_t *davinci_wdt =
(davinci_timer_regs_t *)IO_ADDRESS(DAVINCI_WDOG_BASE);
davinci_wdt->tcr = 0x0; /* disable timer */
davinci_wdt->tgcr = 0x0; /* reset timer */
davinci_wdt->tgcr = 0x8; /* configure timer2 as 64-bit */
davinci_wdt->tgcr |= 0x3; /* release timer from reset */
davinci_wdt->tim12 = 0; /* clear counter and period regs */
davinci_wdt->tim34 = 0;
davinci_wdt->prd12 = 0;
davinci_wdt->prd34 = 0;
davinci_wdt->wdtcr |= 0x4000; /* enable watchdog timer */
/* put watchdog in pre-active state */
davinci_wdt->wdtcr = 0xA5C64000;
/* put watchdog in active state */
davinci_wdt->wdtcr = 0xDA7E4000;
/*
write an invalid value to the WDKEY field to trigger
a watchdog reset
如果要喂看门狗,则使用:
davinci_wdt->wdtcr = 0xA5C64000;
davinci_wdt->wdtcr = 0xDA7E4000;
必须成对顺序使用。
*/
davinci_wdt->wdtcr = 0x00004000;
}
// 读取定时器clock_id的计数值
u32 davinci_timer_read(int clock_id)
{
davinci_timer_t *t = davinci_timers[clock_id]; // 获取该定时器的控制结构体
return davinci_timer32_read(t);
}
2.timex.h
/*
* linux/include/asm-arm/arch-davinci/timex.h
*
* BRIEF MODULE DESCRIPTION
* DAVINCI Virtual memofy definitions
*
* Copyright (C) 2006 Texas Instruments.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
http://www.61ic.com/Article/DaVinci/DM644X/201201/40300.html
#ifndef __ASM_ARCH_TIMEX_H
#define __ASM_ARCH_TIMEX_H
#include <asm/arch/cpu.h>
/* The source frequency for the timers is the 27MHz MXI clock */
#define CLOCK_TICK_RATE 24000000
#define DM644X_CLOCK_TICK_RATE 27000000
#define DM646X_CLOCK_TICK_RATE 148500000
#define DM355_CLOCK_TICK_RATE 24000000
#define DAVINCI_CLOCK_TICK_RATE ((cpu_is_davinci_dm6467()) ? \
DM646X_CLOCK_TICK_RATE : ((cpu_is_davinci_dm644x()) ? \
DM644X_CLOCK_TICK_RATE : DM355_CLOCK_TICK_RATE))
extern void davinci_watchdog_reset(void);
extern cycles_t davinci_get_cycles(void);
static inline cycles_t get_cycles(void)
{
return davinci_get_cycles();
}
#endif /* __ASM_ARCH_TIMEX_H__ */