RK3568 看门狗驱动开发详解
看门狗定时器(Watchdog Timer)是保障嵌入式系统可靠性的关键硬件,它通过定期接收 “喂狗” 信号监控系统运行状态,当系统故障导致信号中断时,自动触发硬件复位实现系统自愈。本文以 RK3568 平台为例,全面讲解看门狗驱动的开发流程,包括子系统架构、驱动实现及功能验证。
一、Linux 看门狗子系统架构
Linux 内核通过看门狗子系统实现对硬件看门狗的标准化管理,架构采用分层设计:
┌─────────────────────────────────────────┐
│ 用户空间 │
│ ┌──────────┐ ┌──────────┐ ┌────────┐ │
│ │ watchdogd│ │ 应用程序 │ │ 工具类 │ │
│ └──────────┘ └──────────┘ └────────┘ │
└───────────────────┬─────────────────────┘
│
┌───────────────────▼─────────────────────┐
│ 内核空间 │
│ ┌───────────────────────────────────┐ │
│ │ 核心层 │ │
│ │ (watchdog_core.c、watchdog_dev.c) │ │
│ └───────────────────┬───────────────┘ │
│ │ │
│ ┌───────────────────▼───────────────┐ │
│ │ 驱动层 │ │
│ │ (dw_wdt.c 具体实现) │ │
│ └───────────────────┬───────────────┘ │
└──────────────────────┼──────────────────┘
│
┌──────────────────────▼──────────────────┐
│ 硬件层 │
│ RK3568 看门狗定时器硬件 │
└─────────────────────────────────────────┘
核心组件解析
- 核心层:
- 提供统一的struct watchdog_device结构体抽象硬件
- 定义标准操作集struct watchdog_ops
- 管理/dev/watchdog字符设备节点
- 实现用户空间接口(ioctl、write 等)
- 驱动层:
- 实现硬件特定的操作(启动、停止、喂狗等)
- 处理硬件中断和复位逻辑
- 对接核心层接口完成设备注册
- 关键数据结构:
// 看门狗设备结构体
struct watchdog_device {
const struct watchdog_ops *ops; // 硬件操作函数集
struct device *dev; // 关联设备
int id; // 设备ID
unsigned int timeout; // 超时时间(秒)
unsigned int min_timeout; // 最小超时时间
unsigned int max_timeout; // 最大超时时间
unsigned int flags; // 设备标志(如WDIOF_KEEPALIVEPING)
// 其他成员...
};
// 看门狗操作函数集
struct watchdog_ops {
int (*start)(struct watchdog_device *wdd); // 启动看门狗
int (*stop)(struct watchdog_device *wdd); // 停止看门狗
int (*ping)(struct watchdog_device *wdd); // 喂狗
int (*set_timeout)(struct watchdog_device *wdd, unsigned int t); // 设置超时
// 其他可选操作...
};
二、设备树配置
RK3568 看门狗设备树节点配置如下:
kernel/arch/arm64/boot/dts/rockchip/rk3568.dtsi

三、 看门狗驱动实现
kernel/drivers/watchdog/dw_wdt.c
/*
* Copyright 2010-2011 Picochip Ltd., Jamie Iles
* http://www.picochip.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* This file implements a driver for the Synopsys DesignWare watchdog device
* in the many subsystems. The watchdog has 16 different timeout periods
* and these are a function of the input clock frequency.
*
* The DesignWare watchdog cannot be stopped once it has been started so we
* do not implement a stop function. The watchdog core will continue to send
* heartbeat requests after the watchdog device has been closed.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/of.h>
#include <linux/pm.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/watchdog.h>
#define WDOG_CONTROL_REG_OFFSET 0x00
#define WDOG_CONTROL_REG_WDT_EN_MASK 0x01
#define WDOG_CONTROL_REG_RESP_MODE_MASK 0x02
#define WDOG_TIMEOUT_RANGE_REG_OFFSET 0x04
#define WDOG_TIMEOUT_RANGE_TOPINIT_SHIFT 4
#define WDOG_CURRENT_COUNT_REG_OFFSET 0x08
#define WDOG_COUNTER_RESTART_REG_OFFSET 0x0c
#define WDOG_COUNTER_RESTART_KICK_VALUE 0x76
/* The maximum TOP (timeout period) value that can be set in the watchdog. */
#define DW_WDT_MAX_TOP 15
#define DW_WDT_DEFAULT_SECONDS 30
static bool nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
"(default=" __MODULE_STRING


2432

被折叠的 条评论
为什么被折叠?



