嵌入式 在uboot中添加硬件看门狗小示例

来源:互联网 发布:商行天下软件 编辑:程序博客网 时间:2024/05/18 03:59
2Uboot添加硬件看门狗

uboot中默认看门狗策略由两个宏CONFIG_HW_WATCHDOG和CONFIG_WATCHDOG来使能。

此策略是在代码执行中的不同阶段,添加喂狗代码。

这种喂狗方法会使代码很乱,uboot中到处都充斥的喂狗代码。另外这种方法对代码执行时间是敏感的,如果有段代码执行时间很长(如搬运code),则需要添加喂狗代码,很繁。

uboot的默认策略比较适合外部看门狗。

我们现在用的是CPU内部看门狗,直接无视上述两宏。我们要在watchdog interrupt中喂狗,即只在watchdog interrupt handler中喂狗,比较简便。


2.1Watchdog Interrupt Handler

修改文件uboot/cpu/mpc85xx/start.S,修改默认的handler

  1. /* STD_EXCEPTION(0x0c00, WatchdogTimer, UnknownException) */

  2.     STD_EXCEPTION(0x0c00, WatchdogTimer, WatchdogHandler)

修改文件uboot/cpu/mpc85xx/traps.c,实现自己的handler

  1. void WatchdogHandle(struct pt_regs*regs){

  2.     unsigned long msr;//turn off all interrpt, may need it, not sure

  3.     msr = get_msr();

  4.     set_msr(0);

  5.     mtspr(SPRN_TSR, mfspr(SPRN_TSR)| TSR_WIS);//喂狗

  6.     set_msr(msr);

  7. }

2.2Watchdog 配置及开启

修改uboot/lib_ppc/board.c,添加watchdog的配置及开启例程

  1. init_fnc_t*init_sequence[]=
  2. {
  3.        ………
  4.        WatchdogCreate,//配置例程           这两个例程越靠前越好,没有强制要求
  5.        WatchdogStart,//开启例程
  6.        ……
  7. };

修改uboot/common/cmd_bootm.c,添加watchdog的配置例程,开启例程和暂停例程

  1. void WatchdogCreate(void)
  2. {
  3.     unsigned long register val;

  4.     //01.no time base counting now
  5.     mtspr(SPRN_HID0, mfspr(SPRN_HID0)&~HID0_TBEN);

  6.     //02.set timer period
  7.     val = mfspr(SPRN_TCR);
  8.     val &= ~(0xc0000000| 0x001e0000);// clear WP and WP_EXT
  9.     val |= (0x00120000);// 此处可修改为宏实现
  10.     mtspr(SPRN_TCR, val);

  11.     //03.set period unit
  12.     val = mfspr(SPRN_HID0);
  13.     val &= ~(0x00040000);
  14.     mtspr(SPRN_HID0, val);

  15.     //04. enable Watchdog timer interrupt
  16.     set_msr (get_msr()| MSR_CE);

  17.     //05: enable watchdog timer
  18.     mtspr(SPRN_TCR, mfspr(SPRN_TCR)| TCR_WIE);

  19.     //06: deal with sec timer out
  20.     val = mfspr(SPRN_TCR);
  21.     val &= ~30000000;
  22.     val |= 0x20000000;//reboot
  23.     mtspr(SPRN_TCR, val);

  24.     asm("isync");

  25. }
  1. void WatchdogStart(void)
  2. {
  3.     //01. clear time base
  4.     mtspr(SPRN_TBWL, 0);
  5.     mtspr(SPRN_TBWU, 0);

  6.     //02. now time base counting...
  7.     mtspr(SPRN_HID0, mfspr(SPRN_HID0)| HID0_TBEN);
  8.     asm("isync");
  9. }

  1. void WatchdogStop(void){// just for test,need to modify and more test

  2.     //01. clear tsr
  3.     mtspr( SPRN_TSR, 0xf0000000);

  4.     //02.clear watchdog timer period
  5.     mtspr( SPRN_TCR, mfspr(SPRN_TCR)&~(0xc0000000| 0x001e0000));

  6.     //03.disable watchdog timer
  7.     mtspr(SPRN_TCR, mfspr(SPRN_TCR)&~(TCR_WIE));

  8. }


2.3reset命令的实现

现在我们可以用wathdog来实现重启命令reset。

修改文件 uboot/cpu/mpc85xx/cpu.c

  1. int do_reset(cmd_tbl_t*cmdtp, bd_t*bd,int flag, int argc,char*argv[])
  2. {
  3. #if 0  // leon del for HRESET
  4.     /*
  5.      * Initiate hard reset in debug control register DBCR0
  6.      * Make sure MSR[DE] = 1
  7.      */
  8.     unsigned long val;
  9.     val = mfspr(DBCR0);
  10.     val |= 0x70000000;
  11.     mtspr(DBCR0,val);
  12. #endif

  13.     //leon add: just disable first time out,second time out will reset send HRESET_REQ
  14.     mtspr(SPRN_TCR, mfspr(SPRN_TCR)&~TCR_WIE);
  15.     return 1;
  16. }

2.4FLASH操作关闭看门狗 (??)


打开看门狗的话,对Flash进行写操作时,会使uboot崩溃。具体原因还没找到,一个比较靠谱的猜想是watchdog interrpt handler代码执行还会去flash中读指令。可是当你敲erase bank 1命令的时候,代码早就搬运到RAM中了啊,无解。。。望牛人指点,感激不尽。

所以,当对flash进行写操作指令前,首先要敲自己加的命令,如timer_stop,来关闭watchdog。
写操作完成后,敲命令timer_start,来启动watchdog。

命令timer_stop中再去调函数WatchdogStop().命令timer_start中调用WatchdogCreate()和WatchdogStart()
具体命令如何添加,参考
uboot添加命令,最快最简山寨法


3Linux添加硬件看门狗

Linux中watchdog机制是靠uboot传来的wdt和wdt_period启动参数来使能的。

wdt为1就使能watchdog机制,0就禁止;

wdt_perid就是上面所说的period值了。

WDT的配置和开启是在wdt驱动里实现的,入口函数是booke_wdt_init()

Linux的watchdog interrupt handler函数WatchdogException()会自旋直至CPU硬复位。

那我们在Decrementer Interrupt handler中喂狗,即在do_timer()中喂狗。

修改文件linux-2.6.24/kernel/timer.c

  1. externint stop_feed;

  2. void do_timer(unsignedlong ticks)
  3. {
  4.     if( likely(stop_feed== 0))
  5.         mtspr(SPRN_TSR, mfspr(SPRN_TSR)| TSR_WIS);//喂狗

  6.     jiffies_64 += ticks;
  7.     update_times(ticks);
  8. }

相应的reboot命令的实现就简单多了,文件linux-2.6.24/arch/ppc/syslib/ppc85xx_setup.c

  1. void mpc85xx_restart(char*cmd){
  2.     local_irq_disable();
  3.     myabort();
  4. }

  5. int stop_feed= 0;
  6. void myabort(void){
  7.    stop_feed = 1;
  8. }
修改到此结束。

当我们敲reboot命令后,do_timer()中停止喂狗,watchdog timer first time out后,会执行Watchdog interrupt handler函数 WatchdogException(),then spin until second timeout occur,then reboot。


//文件linux-2.6.24/arch/ppc/kernel/head_fsl_booke.S

  1. CRITICAL_EXCEPTION(0x3200, WatchdogTimer, WatchdogException)

//文件linux-2.6.24/arch/ppc/kernel/traps.c


  1. void WatchdogException(struct pt_regs*regs)
  2. {
  3.     printk (KERN_EMERG "PowerPC Book-E Watchdog Exception\n");
  4.     WatchdogHandler(regs);
  5. }


  6. /*
  7. * Default handler for a Watchdog exception,
  8. * spins until a reboot occurs  这句和CRITICAL_EXCEPTION宏有关
  9. */
  10. void __attribute__((weak)) WatchdogHandler(struct pt_regs*regs)
  11. {
  12.     /* Generic WatchdogHandler, implement your own */
  13.     mtspr(SPRN_TCR, mfspr(SPRN_TCR)&(~TCR_WIE));//
  14.     return;
  15. }
0 0
原创粉丝点击