说明
- 公司SOC使用的watchdog模块是新思(Synopsys)的IP。
需求
- 用户有时会在uboot/kernel中做些开发,新增一些功能(OTA升级等),可能会出现uboot/kernel启动崩溃甚至设备死机等问题,需要在uboot启动阶段开启watchdog监控设备运行实现异常后复位。
实现
- 前提:dts watchdog节点配置ok。
- 由于历史原因,根据是否支持DM(Driver model),uboot原生支持两种wdt驱动和使用的配置/实现方式。
-
不支持DM,常见于较早版本(uboot,wdt驱动)实现
核心配置项:CONFIG_HW_WATCHDOG
-
支持DM
核心配置项:CONFIG_WDT
// file: drivers/watchdog/Kconfig
config WDT
bool "Enable driver model for watchdog timer drivers"
depends on DM
....
不支持DM
配置项
-
核心配置
CONFIG_HW_WATCHDOG
-
wdt timeout时间
CONFIG_WATCHDOG_TIMEOUT_MSECS
-
具体型号的wdt,例如:dw wdt。
CONFIG_DESIGNWARE_WATCHDOG
-
如果未配置支持DM(CONFIG_WDT),但是配置了硬件wdt,CONFIG_HW_WATCHDOG会自动选上,例如:
config DESIGNWARE_WATCHDOG
bool "Designware watchdog timer support"
select HW_WATCHDOG if !WDT
...
驱动代码
-
定义并实现驱动相关功能接口
//file: drivers/watchdog/designware_wdt.c
static int designware_wdt_settimeout(unsigned int timeout)
{
....
}static void designware_wdt_enable(void)
{
....
}static void designware_wdt_disable(void)
{
....
}static unsigned int designware_wdt_is_enabled(void)
{
....
} -
定义实现对外接口
//file: drivers/watchdog/designware_wdt.c
#if defined(CONFIG_HW_WATCHDOG)
void hw_watchdog_reset(void)
{
...
}void hw_watchdog_init(void)
{
// 初始化wdt,并enable
...
}void hw_watchdog_disable(void)
{
...
}
#endif
uboot中使用
-
头文件(watchdog.h)中会定义统一的宏(WATCHDOG_RESET、WATCHDOG_DISABLE)指向驱动文件中实现的hw对外接口,具体使用后面统一说明。
// file: include/watchdog.h
#if defined(CONFIG_WATCHDOG) || defined(CONFIG_HW_WATCHDOG)
#define INIT_FUNC_WATCHDOG_INIT init_func_watchdog_init,
#define INIT_FUNC_WATCHDOG_RESET init_func_watchdog_reset,
#else
#define INIT_FUNC_WATCHDOG_INIT
#define INIT_FUNC_WATCHDOG_RESET
#endif#ifdef CONFIG_HW_WATCHDOG
#if defined(ASSEMBLY)
#define WATCHDOG_RESET bl hw_watchdog_reset
#else
extern void hw_watchdog_reset(void);
extern void hw_watchdog_disable(void);#define WATCHDOG_RESET hw_watchdog_reset #define WATCHDOG_DISABLE hw_watchdog_disable #endif /* __ASSEMBLY__ */
#else
....
#endif -
由于不支持DM,wdt-uclass.c(DM接口)未使用。
验证
- 这种方式,整体上执行流程比较固定,uboot启动wdt就会自动运行,支持配置项较少,验证方法只能代码调试。
- 由于不支持DM,这种模式,不支持wdt cmd。
支持DM
配置项
-
核心配置
CONFIG_WDT
CONFIG_WATCHDOG // enable uboot内部使用的喂狗接口,该方式下必需enable
-
配置CONFIG_WDT后会自动开启CONFIG_WATCHDOG, 如下:
// file: drivers/watchdog/Kconfig
config WDT
bool "Enable driver model for watchdog timer drivers"
depends on DM
imply WATCHDOG
...
-
自动启动配置(可选配置)
CONFIG_WATCHDOG_AUTOSTART=y // 自动启动
CONFIG_WATCHDOG_TIMEOUT_MSECS //wdt timeout时间, 默认60s -
具体型号的wdt,例如:dw wdt。
CONFIG_DESIGNWARE_WATCHDOG
驱动代码
-
按照DM模型,实现probe等相关接口
-
实现DM定义的 wdt 操作接口
//file: include/wdt.h
struct wdt_ops {
int (*start)(struct udevice *dev, u64 timeout_ms, ulong flags);
int (*stop)(struct udevice *dev);
int (*reset)(struct udevice *dev);
int (*expire_now)(struct udevice *dev, ulong flags);
}
uboot中使用
-
wdt cmd使用的是wdt-uclass.c中的统一接口,wdt-uclass.c中的函数再调用具体驱动的接口。
-
头文件(watchdog.h)中会定义统一的宏(WATCHDOG_RESET)指向wdt-uclass.c中实现的对外喂狗接口,具体使用后面统一说明。
// file: include/watchdog.h
#ifdef CONFIG_HW_WATCHDOG
...
#else
/*
* Maybe a software watchdog?
/
#if defined(CONFIG_WATCHDOG)
#if defined(ASSEMBLY)
#define WATCHDOG_RESET bl watchdog_reset
#else
/ Don't require the watchdog to be enabled in SPL */
#if defined(CONFIG_SPL_BUILD) &&
!defined(CONFIG_SPL_WATCHDOG)
#define WATCHDOG_RESET() {}
#else
extern void watchdog_reset(void);#define WATCHDOG_RESET watchdog_reset #endif #endif #else /* * No hardware or software watchdog. */ #if defined(__ASSEMBLY__) #define WATCHDOG_RESET /*XXX DO_NOT_DEL_THIS_COMMENT*/ #else #define WATCHDOG_RESET() {} #endif /* __ASSEMBLY__ */ #endif /* CONFIG_WATCHDOG && !__ASSEMBLY__ */
#endif /* CONFIG_HW_WATCHDOG */
验证
- 使用cli命令验证
-
enable wdt命令(cmdline)
CONFIG_CMD_WDT=y // wdt cmd
-
运行效果
uboot# wdt
wdt - Watchdog sub-systemUsage:
wdt list - list watchdog devices
wdt dev [<name>] - get/set current watchdog device
wdt start <timeout ms> [flags] - start watchdog timer
wdt stop - stop watchdog timer
wdt reset - reset watchdog timer
wdt expire [flags] - expire watchdog timer immediatelyuboot# wdt list
dw-wd@0x27000000 (designware_wdt) // dts配置
uboot# wdt dev dw-wd@0x27000000
uboot# wdt start 30000
uboot中使用
- 两种配置(是否支持DM)方式,uboot中都是使用统一的宏(WATCHDOG_RESET等)去操作wdt,不同的是宏指向的函数。
- 不支持DM,WATCHDOG_RESET指向的是wdt驱动中hw_watchdog_reset函数。
- 支持DM,WATCHDOG_RESET指向的是wdt-uclass.c中watchdog_reset函数。
-
uboot初始化时会主动调用INIT_FUNC_WATCHDOG_INIT初始化wdt,不支持DM配置(CONFIG_HW_WATCHDOG),wdt初始化时会直接enable wdt。
//file: common/board_f.c
#if defined(CONFIG_WATCHDOG) || defined(CONFIG_HW_WATCHDOG)
static int init_func_watchdog_init(void)
{if defined(CONFIG_HW_WATCHDOG) && \
(defined(CONFIG_M68K) || defined(CONFIG_MICROBLAZE) || \ defined(CONFIG_SH) || \ defined(CONFIG_DESIGNWARE_WATCHDOG) || \ defined(CONFIG_IMX_WATCHDOG)) hw_watchdog_init(); //该函数,默认实现会配置好wdt,并enable puts(" Watchdog enabled\n");
endif
WATCHDOG_RESET(); return 0;
}
int init_func_watchdog_reset(void)
{
WATCHDOG_RESET();return 0;
}
#endif /* CONFIG_WATCHDOG */ -
uboot是裸机程序,所有操作都是顺序执行,开启wdt后,如有耗时操作需要自己调用WATCHDOG_RESET进行喂狗,进到cli时,uboot cli会间隔调用WATCHDOG_RESET喂狗。