CS5536中MFGPT时钟的实现
来源:互联网 发布:手办淘宝店推荐贴吧 编辑:程序博客网 时间:2024/03/28 17:19
MFGPT简介:
全称:Multi-Function General Purpose Timer.
它包括了8个timers,其中的6个工作在 working domain,频率为32 KHZ 和 14318 KHZ
另外2个工作在 standy domain,频率为32 KHZ.
对于输入时钟频率,都有15位可以用来分频,从而分别产生15种时钟频率.
MFGPT1
I/O Reg Clock Switch Timer
对于每一个MFGPT,都有4个 software accessible I/O寄存器:
Up Counter, Comparator 1 Value, Comparator 2 Value, Setup register
这4个寄存器初始化顺序:
如果先初始化setup寄存器,那么在comparator 1 or 2 和 counter 都未初始化,为0时,
时钟event 将会立即触发。
所以应该:
1.先初始化 comparator 1 or 2 ,
2.然后 counter 清0 ,
3.最后设置setup。
寄存器的重新初始化顺序:
1.清理 counter enable 为 0;
2.清理中断使能: NMI Enable Reset Enable bits in MSRs,disable GPIO的输入输出
3.更新 counter compare 1 or 2;
4.清除任何已经设置的 event bits;
5.set up 中断
MFGPT寄存器描述符:
MFGPT的寄存器分为3部分:1. Standard GeodeLink Device MSRs2. MFGPT Specific MSRs3. MFGPT Native RegistersMSRs都是通过 __rdmsr() __wrmsr() 函数访问的,所有的MSRs都是64bits的,但是MFGPT Spcific MSRs是32bits的,对于高32bits的写会补齐,而读出来的高32bits是无效的。A. MFGPT Specific MSRs Summary:51400028h r/w MFGPT IRQ Mask(MFGPT_IRQ)51400029h r/w MFGPT NMI AND Reset Mask(MFGPT_NR)5140002Ah r/w MFGPT Reserved(MFGPT_RSVD)5140002Bh r/w MFGPT Clear Setup test(MFGPT_SETUP)B. MFGPT Native Registers Summary:这个寄存器组是通过 base + offsets访问的,base is MSR_LBAR_MFGPT(5140000Dh)如果我们只是创建一个时钟,即MFGPT0,则用到的offsets只有:00h R/W MFGPT0 Comparator 1(MFGPT0_CMP1)02h R/W MFGPT0 Comparator 2(MFGPT0_CMP2)04h R/W MFGPT0 Up Counter (MFGPT0_CNT)06h R/W MFGPT0 Setup (MFGPT0_SETUP)
代码实现:
时钟工作原理:简单的说,就是给一个comparator寄存器设置一个初值,把counter寄存器置0,然后在setup寄存器中设置好工作模式,使能等位。counter寄存器就会在每一个到来的时钟脉冲后+1, 当counter = comparator预设值时,发出一个时钟中断,通知系统一段时间过去了,系统时间应该增加了
要使用MFGPT,只需在内核中注册mfgpt的 clock_event_device, clocksource.
clock_event_device的初始化:
重要的是.set_mode方法的初始化,它其实就是MFGPT的初始化函数:
inti_mfgpt_timer(enum clock_event_mode mode,struct clock_event_device *evt)
{
...
switch(mode){
case CLOCK_EVT_MODE_PERIODIC:
/**给comparator2 设置初值/
outw(COMPARE, base + 2);
/*counter 清 0*/
outw(0, base+ 4);
/*设置setup*/
outw(0xe310, base+ 6);
break;
}
...
}
其中 base 是从0x8000000d中读出来的native msr基地址
_rdmsr(0x8000000d, &basehi,&base),上面说了,读出来的高32位会被丢弃。
base + 2, 4, 6刚好是 MFGPT0_CMP2, MFGPT0_CNT, MFGPT0_SETUP的地址。
#define COMPARE ((14318000 + HZ/2) / HZ)
当然,注册clock_event_device之前,还要对此结构体中的cpumask, min/max_delta_ns,
等初始化,然后:
/* connect multifunction timer0 comparator 2 to irq mapper*/
_wrmsr(0x80000028, 0, 0x100);
/* map unrestricted interrupt source Z4 to IG5 */
_wrmsr(0x80000022, 0, 0x50000);
接着就可以 clockevents_register_device(mfgpt_clockevent) 了;
最后不要忘了,setup_irq(5, &irq5); 当然这个5号中断,必须要在之前定义.
其中这个irq5的中断处理函数 timer_interrupt要做的是:
/*MFGPT_CNT_EN MFGPT_CMP2 2bits 置 1*/
outw(0xc000, base + 6);
mfgpt_clockevent.event_handler(&mfgpt_clockevent);
return IRQ_HANDLED;
注册完clockevent, 就该注册 clocksource 了:
这里需要注意的是 .read 方法。 这个函数是内核,应用程序读取时间的接口
这个函数返回的是:
return (cycle_t)(jiffies * COMPARE) + count;
显然,返回的是时钟晶振震荡的次数,由于时钟晶振振动的频率是可知的,所以从返回值可以推算出
当前时间。
在这个函数里,需要注意的是:
由于延迟,或者中断等原因:count的值有可能出现回退,溢出,所以要对count寄存器进行校正:
if(count < old_count && jifs== old_jifs){
count = old_count;
}
old_count = count;
old_jifs = jifs;
就此,一个MFGPT时钟源已经注册完成。
在内核初始化进程 time_init() --> plat_time_init() --> init_mfgpt_clocksource()
来初始化这个时钟。
- CS5536中MFGPT时钟的实现
- CS5536中MFGPT时钟的实现
- CS5536中SMB寄存器的说明
- MFC中数字时钟的实现分析
- 在HTML中实现动态的时钟
- 简单的时钟实现
- 模拟时钟的实现
- 动态时钟的实现
- 时钟的实现
- 时钟的简单实现
- 数字时钟的实现
- 门控时钟、使能时钟的实现
- 在AS3中实现时钟
- J2ME游戏开发中时钟的简单实现
- J2ME游戏开发中时钟的简单实现
- J2ME游戏开发中时钟的简单实现
- J2ME游戏开发中时钟的简单实现
- 在android中实现iphone时钟app的秒表功能
- 设置Google同步帐号
- linux常用基本命令
- Visual Studio 2008 + Wince 6.0
- oracle 11.2.0.2创建DBFS
- 读研还是找工作?
- CS5536中MFGPT时钟的实现
- 《深入理解计算机系统》笔记一:信息的表示与处理(1)——基本数据类型与字节序
- 冒泡排序bubbleSort
- c/c++字符串处理函数
- Git学习教程(一):git简介
- java 多线程(multithreading)(一)
- 【算法复习三】算法设计技巧与优化----算法设计技巧
- HashCode相关:重载类的equals方法就必须也重载hashCode方法
- Git学习教程(二):配置和初始化