本系列文章基于Amlogic A311D SDK中的驱动,将我之前阅读代码的一些收获进行总结,算是学习笔记吧。
1.dts配置
先看dts调用的是看门狗的哪个驱动
wdt: watchdog@0xffd0f0d0 {
compatible = "amlogic, meson-wdt";//匹配驱动
status = "okay";
default_timeout=<10>;//默认超时时间
reset_watchdog_method=<1>; /* 0:sysfs,1:kernel *///看门狗复位行为1为kernel复位
reset_watchdog_time=<2>;//复位时间
shutdown_timeout=<10>;//关键时间
firmware_timeout=<6>;
suspend_timeout=<6>;//挂起时间
reg = <0xffd0f0d0 0x10>;//寄存器基地址
clock-names = "xtal";
clocks = <&xtal>;
};
2.驱动分析
代码位置:common\drivers\amlogic\watchdog\meson_wdt.c
meson_wdt注册为platform_driver。
platform_driver驱动编写流程大致如下--
xxx_probe--对应aml_wdt_probe
读取dts获得配置--aml_init_pdata
进行相关操作。
2.1 aml_wdt_probe
static int aml_wdt_probe(struct platform_device *pdev)
{
//看门狗设备--向系统注册
struct watchdog_device *aml_wdt;
//amlogic 看门狗设备
struct aml_wdt_dev *wdev;
int ret;
//创建aml_wdt 结构体
aml_wdt = devm_kzalloc(&pdev->dev, sizeof(*aml_wdt), GFP_KERNEL);
if (!aml_wdt)
return -ENOMEM;
wdev = devm_kzalloc(&pdev->dev, sizeof(*wdev), GFP_KERNEL);
if (!wdev)
return -ENOMEM;
wdev->dev = &pdev->dev;
mutex_init(&wdev->lock);
//读取dts,初始化wdev
aml_init_pdata(wdev);
aml_wdt->info = &aml_wdt_info;
aml_wdt->ops = &aml_wdt_ops;
aml_wdt->min_timeout = wdev->min_timeout;
aml_wdt->max_timeout = wdev->max_timeout;
aml_wdt->timeout = 0xffffffff;
wdev->timeout = 0xffffffff;
watchdog_set_drvdata(aml_wdt, wdev);
platform_set_drvdata(pdev, aml_wdt);
wdev->is_running = false;
//看门狗复位行为 1为由当前驱动来进行看门狗复位
//默认为1
if (wdev->reset_watchdog_method == 1) {
//创建一个任务用来喂狗
INIT_DELAYED_WORK(&wdev->boot_queue, boot_moniter_work);
mod_delayed_work(system_freezable_wq, &wdev->boot_queue,
round_jiffies(msecs_to_jiffies(wdev->reset_watchdog_time*1000)));
aml_wdt_start(aml_wdt);
dev_info(wdev->dev, "creat work queue for watch dog\n");
}
//向系统注册wdt
ret = watchdog_register_device(aml_wdt);
if (ret)
return ret;
//注册PM通知
wdev->pm_notifier = aml_wdt_pm_notifier;
//注册重启通知
wdev->reboot_notifier = aml_wdt_reboot_notifier;
register_pm_notifier(&wdev->pm_notifier);
register_reboot_notifier(&wdev->reboot_notifier);
dev_info(wdev->dev, "AML Watchdog Timer probed done\n");
#ifdef CONFIG_AMLOGIC_DEBUG_LOCKUP
g_awdt = wdev;
#endif
return 0;
}
2.2 喂狗方式
因为采用的是默认的kernel方式,因此在驱动中直接创建了一个任务,并初始化了相关计数器,通过不断的复位看门狗计数实现喂狗。
//喂狗任务
static void boot_moniter_work(struct work_struct *work)
{
struct aml_wdt_dev *wdev = container_of(work, struct aml_wdt_dev,
boot_queue.work);
//复位看门狗操作
reset_watchdog(wdev);
mod_delayed_work(system_freezable_wq, &wdev->boot_queue,
round_jiffies(msecs_to_jiffies(wdev->reset_watchdog_time*1000)));
}
//启动喂狗
static int aml_wdt_start(struct watchdog_device *wdog)
{
struct aml_wdt_dev *wdev = watchdog_get_drvdata(wdog);
mutex_lock(&wdev->lock);
//第一初始化时wdog->timeout=0xffffffff
//此时配置看梦狗计数器为默认的default_timeout(10)*one_second(记时单位1000)
//这么写的目的是aml_wdt_start还可以提供给上层重新配置
if (wdog->timeout == 0xffffffff)
set_watchdog_cnt(wdev, wdev->default_timeout *
wdev->one_second);
else
set_watchdog_cnt(wdev, wdog->timeout * wdev->one_second);
enable_watchdog(wdev);
mutex_unlock(&wdev->lock);
#if 0
if (wdev->boot_queue)
cancel_delayed_work(&wdev->boot_queue);
#endif
wdev->is_running = true;
dev_info(wdev->dev, "start watchdog\n");
return 0;
}
3.总结
amlogic的看门狗驱动采用了比较简单的方式,就是开启一个任务,然后不断的复位寄存器即可。
看门狗复位寄存器
看门狗tick