天天看點

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

繼續閱讀