这里使用了ADM706芯片,wdi喂狗引脚与CPUGPIO3相连。
wdo看门狗超时复位信号输出引脚,与/MR手动复位输入相连,也就是会产生一个RESET信号。
原理图如下所示:
首先需要在include/configs/xxx.h文件中,添加一个宏定义:
#defineCONFIG_HW_WATCHDOG
启动HW_WATCHDOG功能。
因为在include/watchdog.h中有WATCHDOG宏定义如下:
#ifdefCONFIG_HW_WATCHDOG
#if defined(__ASSEMBLY__)
#define WATCHDOG_RESET blhw_watchdog_reset
#else
extern voidhw_watchdog_reset(void);
#define WATCHDOG_RESEThw_watchdog_reset
#endif /* __ASSEMBLY__ */
#else
/*
* Maybe a software watchdog?
*/
#if defined(CONFIG_WATCHDOG)
#if defined(__ASSEMBLY__)
#define WATCHDOG_RESETbl watchdog_reset
#else
extern voidwatchdog_reset(void);
#define WATCHDOG_RESETwatchdog_reset
#endif
#else
/*
* No hardware or softwarewatchdog.
*/
#if defined(__ASSEMBLY__)
#define WATCHDOG_RESET/*XXX DO_NOT_DEL_THIS_COMMENT*/
#else
#defineWATCHDOG_RESET() {}
#endif /* __ASSEMBLY__ */
#endif /* CONFIG_WATCHDOG &&!__ASSEMBLY__ */
#endif/* CONFIG_HW_WATCHDOG */
在定义了CONFIG_HW_WATCHDOG宏之后,系统就会使用hw_watchdog_reset()函数,二者个函数就定义在arch/powerpc/cpu/mpc85xx/cpu.c文件中,这里使用的是powerpc的P2020芯片,也就是MPC85xx系列芯片。
添加watchdog功能代码实现如下:
#ifdefCONFIG_HW_WATCHDOG
#defineGPIO_REG_BASE 0xFFE0F000
#defineGPIO_REG_GPDIR (GPIO_REG_BASE + 0x00)
#defineGPIO_REG_GPODR (GPIO_REG_BASE + 0x04)
#defineGPIO_REG_GPDAT (GPIO_REG_BASE + 0x08)
#defineGPIO_3_OFFSET 0x10000000
void
watchdog_adm_reset(void)
{
*(volatile unsigned int*)GPIO_REG_GPDIR |= GPIO_3_OFFSET;
*(volatile unsigned int*)GPIO_REG_GPODR &= ~GPIO_3_OFFSET;
*(volatile unsigned int*)GPIO_REG_GPDAT &= ~GPIO_3_OFFSET;
*(volatile unsigned int*)GPIO_REG_GPDAT |= GPIO_3_OFFSET;
}
void
hw_watchdog_reset(void)
{
watchdog_adm_reset();
}
#endif
Uboot中基本是到处都使用了一个WATCHDOG_RESET宏,基本上每运行一段时间就会调用这个宏来喂狗,这样实现的一个看门狗伪狗功能。
这个驱动很简单,就是添加一个定时器,每隔一段时间就喂狗一次。
代码如下:
/*
* Driver for GPIO-controlled ADM706 Hardware Watchdogs.
*
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#defineGPIO_REG_BASE 0xFFE0F000
#defineGPIO_REG_GPDIR (gpio_mem + 0x00)
#defineGPIO_REG_GPODR (gpio_mem + 0x04)
#defineGPIO_REG_GPDAT (gpio_mem + 0x08)
#defineGPIO_3_OFFSET 0x10000000
staticvoid *gpio_mem;
void
watchdog_adm_reset(void)
{
*(volatile unsigned int *)GPIO_REG_GPDIR|= GPIO_3_OFFSET;
*(volatile unsigned int*)GPIO_REG_GPODR &= ~GPIO_3_OFFSET;
*(volatile unsigned int*)GPIO_REG_GPDAT &= ~GPIO_3_OFFSET;
*(volatile unsigned int*)GPIO_REG_GPDAT |= GPIO_3_OFFSET;
}
staticstruct {
spinlock_t lock;
struct timer_list timer;
int interval;
int first_interval;
}adm_wdt_device;
staticvoid adm_wdt_trigger(unsigned long unused)
{
spin_lock(&adm_wdt_device.lock);
watchdog_adm_reset();
mod_timer(&adm_wdt_device.timer, jiffies+ adm_wdt_device.interval);
spin_unlock(&adm_wdt_device.lock);
}
staticvoid adm_wdt_start(void)
{
unsigned long flags;
spin_lock_irqsave(&adm_wdt_device.lock, flags);
mod_timer(&adm_wdt_device.timer,jiffies + adm_wdt_device.first_interval);
spin_unlock_irqrestore(&adm_wdt_device.lock, flags);
}
staticint __init adm_wdt_init(void)
{
printk(KERN_INFO "ADM706 watchdogstart feeding\n");
spin_lock_init(&adm_wdt_device.lock);
setup_timer(&adm_wdt_device.timer,adm_wdt_trigger, 0L);
adm_wdt_device.first_interval = 0;
adm_wdt_device.interval =msecs_to_jiffies(1000);
gpio_mem = ioremap(GPIO_REG_BASE, 100);
adm_wdt_start();
return 0;
}
arch_initcall(adm_wdt_init);
staticvoid __exit adm_wdt_exit(void)
{
printk(KERN_INFO "ADM706 watchdogstop feeding\n");
iounmap(gpio_mem);
del_timer(&adm_wdt_device.timer);
}
module_exit(adm_wdt_exit);
MODULE_AUTHOR("XiaohaiXu");
MODULE_DESCRIPTION("Driverfor GPIO controlled ADM706 watchdogs");
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
MODULE_ALIAS("adm706gpio-controlled watchdog");