uboot - 驱动开发 - dw watchdog

说明

  • 公司SOC使用的watchdog模块是新思(Synopsys)的IP。

需求

  • 用户有时会在uboot/kernel中做些开发,新增一些功能(OTA升级等),可能会出现uboot/kernel启动崩溃甚至设备死机等问题,需要在uboot启动阶段开启watchdog监控设备运行实现异常后复位。

实现

  • 前提:dts watchdog节点配置ok。
  • 由于历史原因,根据是否支持DM(Driver model),uboot原生支持两种wdt驱动和使用的配置/实现方式。
  1. 不支持DM,常见于较早版本(uboot,wdt驱动)实现

    核心配置项:CONFIG_HW_WATCHDOG

  2. 支持DM

    核心配置项:CONFIG_WDT

    // file: drivers/watchdog/Kconfig
    config WDT
    bool "Enable driver model for watchdog timer drivers"
    depends on DM
    ....

不支持DM

配置项

  1. 核心配置

    CONFIG_HW_WATCHDOG

  2. wdt timeout时间

    CONFIG_WATCHDOG_TIMEOUT_MSECS

  3. 具体型号的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
    ...

驱动代码

  1. 定义并实现驱动相关功能接口

    //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)
    {
    ....
    }

  2. 定义实现对外接口

    //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中使用

  1. 头文件(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

  2. 由于不支持DM,wdt-uclass.c(DM接口)未使用。

验证

  • 这种方式,整体上执行流程比较固定,uboot启动wdt就会自动运行,支持配置项较少,验证方法只能代码调试。
  • 由于不支持DM,这种模式,不支持wdt cmd。

支持DM

配置项

  1. 核心配置

    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
    ...

  1. 自动启动配置(可选配置)

    CONFIG_WATCHDOG_AUTOSTART=y // 自动启动
    CONFIG_WATCHDOG_TIMEOUT_MSECS //wdt timeout时间, 默认60s

  2. 具体型号的wdt,例如:dw wdt。

    CONFIG_DESIGNWARE_WATCHDOG

驱动代码

  1. 按照DM模型,实现probe等相关接口

  2. 实现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中使用

  1. wdt cmd使用的是wdt-uclass.c中的统一接口,wdt-uclass.c中的函数再调用具体驱动的接口。

  2. 头文件(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 */

验证

  1. 使用cli命令验证
  • enable wdt命令(cmdline)

    CONFIG_CMD_WDT=y // wdt cmd

  • 运行效果

    uboot# wdt
    wdt - Watchdog sub-system

    Usage:
    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 immediately

    uboot# wdt list
    dw-wd@0x27000000 (designware_wdt) // dts配置
    uboot# wdt dev dw-wd@0x27000000
    uboot# wdt start 30000

uboot中使用

  • 两种配置(是否支持DM)方式,uboot中都是使用统一的宏(WATCHDOG_RESET等)去操作wdt,不同的是宏指向的函数。
  1. 不支持DM,WATCHDOG_RESET指向的是wdt驱动中hw_watchdog_reset函数。
  2. 支持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喂狗。

相关推荐
学习嵌入式的小羊~13 小时前
linux驱动-i2c子系统框架学习(1)
linux·驱动开发
挨踢小明1 天前
DPDK eth 网卡驱动开发
驱动开发
TeYiToKu2 天前
笔记整理—linux驱动开发部分(6)platform平台总线
linux·c语言·arm开发·驱动开发·笔记·嵌入式硬件
学习嵌入式的小羊~3 天前
linux驱动-认识输入子系统源码以及裁剪
linux·驱动开发
学习嵌入式的小羊~5 天前
linux驱动—input输入子系统
驱动开发
深度学习渣5 天前
SCSI驱动与 UFS 驱动交互概况
驱动开发·交互
郁大锤5 天前
linux alsa-lib snd_pcm_open函数源码分析(一)
linux·驱动开发·嵌入式硬件·音频·pcm·视频编解码
郁大锤5 天前
linux alsa-lib snd_pcm_open函数源码分析(二)
linux·驱动开发·嵌入式硬件·音视频
weixin_750335526 天前
OpenHarmony驱动开发--UART(串口)驱动
驱动开发
deamer_7 天前
【屏幕驱动移植记录】
linux·驱动开发