天天看点

powerpc平台watchdog总结

1. 硬件原理图

这里使用了ADM706芯片,wdi喂狗引脚与CPUGPIO3相连。

wdo看门狗超时复位信号输出引脚,与/MR手动复位输入相连,也就是会产生一个RESET信号。

原理图如下所示:

powerpc平台watchdog总结

2. uboot中添加watchdog喂狗功能

首先需要在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

#else

        #if defined(CONFIG_WATCHDOG)

                #if defined(__ASSEMBLY__)

                        #define WATCHDOG_RESETbl watchdog_reset

                #else

                        extern voidwatchdog_reset(void);

                        #define WATCHDOG_RESETwatchdog_reset

                #endif

        #else

                #if defined(__ASSEMBLY__)

                        #define WATCHDOG_RESET

                #else

                        #defineWATCHDOG_RESET() {}

                #endif

        #endif

#endif

在定义了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宏,基本上每运行一段时间就会调用这个宏来喂狗,这样实现的一个看门狗伪狗功能。

3. linux驱动中添加一个看门狗喂狗程序

这个驱动很简单,就是添加一个定时器,每隔一段时间就喂狗一次。

代码如下:

#include<linux/module.h>

#include<linux/moduleparam.h>

#include<linux/types.h>

#include<linux/errno.h>

#include<linux/miscdevice.h>

#include<linux/fs.h>

#include<linux/init.h>

#include<linux/ioport.h>

#include<linux/timer.h>

#include<linux/completion.h>

#include<linux/jiffies.h>

#include<linux/watchdog.h>

#include<linux/platform_device.h>

#include<linux/io.h>

#include<linux/uaccess.h>

#include<linux/gpio.h>

#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");

继续阅读