linux-watchdog 5.6-rc1 tag
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.14 (GNU/Linux) iEYEABECAAYFAl48a0YACgkQ+iyteGJfRsoOcQCeMHtMpkUEYQa6X/bMkEnlu9DT bhEAoN0fFm53Y/SVPipe/r1+0JQOkMoI =/D+E -----END PGP SIGNATURE----- Merge tag 'linux-watchdog-5.6-rc1' of git://www.linux-watchdog.org/linux-watchdog Pull watchdog updates from Wim Van Sebroeck: - add IT8786 chipset ID - addition of sam9x60 compatible watchdog - da9062 improvements - fix UAF in reboot notifier handling in watchdog core code - other fixes and small improvements * tag 'linux-watchdog-5.6-rc1' of git://www.linux-watchdog.org/linux-watchdog: watchdog: da9062: make restart handler atomic safe watchdog: mtk_wdt: mt2712: Add reset controller watchdog: mtk_wdt: mt8183: Add reset controller dt-bindings: mediatek: mt2712: Add #reset-cells dt-bindings: mediatek: mt8183: Add #reset-cells dt-bindings: watchdog: da9062: add suspend disable option watchdog: it87_wdt: add IT8786 ID watchdog: dw_wdt: ping watchdog to reset countdown before start watchdog: fix UAF in reboot notifier handling in watchdog core code watchdog: cadence: Skip printing pointer value watchdog: qcom: Use platform_get_irq_optional() for bark irq watchdog: da9062: add power management ops watchdog: make DesignWare watchdog allow users to set bigger timeout value drivers: watchdog: stm32_iwdg: set WDOG_HW_RUNNING at probe watchdog: sama5d4_wdt: addition of sam9x60 compatible watchdog
This commit is contained in:
commit
b34f01f76a
|
@ -6,6 +6,11 @@ Required properties:
|
|||
"dlg,da9061-watchdog", "dlg,da9062-watchdog"
|
||||
"dlg,da9062-watchdog"
|
||||
|
||||
Optional properties:
|
||||
- dlg,use-sw-pm: Add this property to disable the watchdog during suspend.
|
||||
Only use this option if you can't use the watchdog automatic suspend
|
||||
function during a suspend (see register CONTROL_B).
|
||||
|
||||
Example: DA9062
|
||||
|
||||
pmic0: da9062@58 {
|
||||
|
|
|
@ -4,22 +4,27 @@ Required properties:
|
|||
|
||||
- compatible should contain:
|
||||
"mediatek,mt2701-wdt", "mediatek,mt6589-wdt": for MT2701
|
||||
"mediatek,mt2712-wdt", "mediatek,mt6589-wdt": for MT2712
|
||||
"mediatek,mt6589-wdt": for MT6589
|
||||
"mediatek,mt6797-wdt", "mediatek,mt6589-wdt": for MT6797
|
||||
"mediatek,mt7622-wdt", "mediatek,mt6589-wdt": for MT7622
|
||||
"mediatek,mt7623-wdt", "mediatek,mt6589-wdt": for MT7623
|
||||
"mediatek,mt7629-wdt", "mediatek,mt6589-wdt": for MT7629
|
||||
"mediatek,mt8183-wdt", "mediatek,mt6589-wdt": for MT8183
|
||||
"mediatek,mt8516-wdt", "mediatek,mt6589-wdt": for MT8516
|
||||
|
||||
- reg : Specifies base physical address and size of the registers.
|
||||
|
||||
Optional properties:
|
||||
- timeout-sec: contains the watchdog timeout in seconds.
|
||||
- #reset-cells: Should be 1.
|
||||
|
||||
Example:
|
||||
|
||||
wdt: watchdog@10000000 {
|
||||
compatible = "mediatek,mt6589-wdt";
|
||||
reg = <0x10000000 0x18>;
|
||||
watchdog: watchdog@10007000 {
|
||||
compatible = "mediatek,mt8183-wdt",
|
||||
"mediatek,mt6589-wdt";
|
||||
reg = <0 0x10007000 0 0x100>;
|
||||
timeout-sec = <10>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
|
|
@ -24,7 +24,10 @@
|
|||
#define AT91_WDT_MR 0x04 /* Watchdog Mode Register */
|
||||
#define AT91_WDT_WDV (0xfffUL << 0) /* Counter Value */
|
||||
#define AT91_WDT_SET_WDV(x) ((x) & AT91_WDT_WDV)
|
||||
#define AT91_SAM9X60_PERIODRST BIT(4) /* Period Reset */
|
||||
#define AT91_SAM9X60_RPTHRST BIT(5) /* Minimum Restart Period */
|
||||
#define AT91_WDT_WDFIEN BIT(12) /* Fault Interrupt Enable */
|
||||
#define AT91_SAM9X60_WDDIS BIT(12) /* Watchdog Disable */
|
||||
#define AT91_WDT_WDRSTEN BIT(13) /* Reset Processor */
|
||||
#define AT91_WDT_WDRPROC BIT(14) /* Timer Restart */
|
||||
#define AT91_WDT_WDDIS BIT(15) /* Watchdog Disable */
|
||||
|
@ -37,4 +40,22 @@
|
|||
#define AT91_WDT_WDUNF BIT(0) /* Watchdog Underflow */
|
||||
#define AT91_WDT_WDERR BIT(1) /* Watchdog Error */
|
||||
|
||||
/* Watchdog Timer Value Register */
|
||||
#define AT91_SAM9X60_VR 0x08
|
||||
|
||||
/* Watchdog Window Level Register */
|
||||
#define AT91_SAM9X60_WLR 0x0c
|
||||
/* Watchdog Period Value */
|
||||
#define AT91_SAM9X60_COUNTER (0xfffUL << 0)
|
||||
#define AT91_SAM9X60_SET_COUNTER(x) ((x) & AT91_SAM9X60_COUNTER)
|
||||
|
||||
/* Interrupt Enable Register */
|
||||
#define AT91_SAM9X60_IER 0x14
|
||||
/* Period Interrupt Enable */
|
||||
#define AT91_SAM9X60_PERINT BIT(0)
|
||||
/* Interrupt Disable Register */
|
||||
#define AT91_SAM9X60_IDR 0x18
|
||||
/* Interrupt Status Register */
|
||||
#define AT91_SAM9X60_ISR 0x1c
|
||||
|
||||
#endif
|
||||
|
|
|
@ -369,9 +369,8 @@ static int cdns_wdt_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
platform_set_drvdata(pdev, wdt);
|
||||
|
||||
dev_info(dev, "Xilinx Watchdog Timer at %p with timeout %ds%s\n",
|
||||
wdt->regs, cdns_wdt_device->timeout,
|
||||
nowayout ? ", nowayout" : "");
|
||||
dev_info(dev, "Xilinx Watchdog Timer with timeout %ds%s\n",
|
||||
cdns_wdt_device->timeout, nowayout ? ", nowayout" : "");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/mfd/da9062/registers.h>
|
||||
|
@ -147,12 +148,13 @@ static int da9062_wdt_restart(struct watchdog_device *wdd, unsigned long action,
|
|||
void *data)
|
||||
{
|
||||
struct da9062_watchdog *wdt = watchdog_get_drvdata(wdd);
|
||||
struct i2c_client *client = to_i2c_client(wdt->hw->dev);
|
||||
int ret;
|
||||
|
||||
ret = regmap_write(wdt->hw->regmap,
|
||||
DA9062AA_CONTROL_F,
|
||||
DA9062AA_SHUTDOWN_MASK);
|
||||
if (ret)
|
||||
/* Don't use regmap because it is not atomic safe */
|
||||
ret = i2c_smbus_write_byte_data(client, DA9062AA_CONTROL_F,
|
||||
DA9062AA_SHUTDOWN_MASK);
|
||||
if (ret < 0)
|
||||
dev_alert(wdt->hw->dev, "Failed to shutdown (err = %d)\n",
|
||||
ret);
|
||||
|
||||
|
@ -212,6 +214,7 @@ static int da9062_wdt_probe(struct platform_device *pdev)
|
|||
watchdog_set_restart_priority(&wdt->wdtdev, 128);
|
||||
|
||||
watchdog_set_drvdata(&wdt->wdtdev, wdt);
|
||||
dev_set_drvdata(dev, &wdt->wdtdev);
|
||||
|
||||
ret = devm_watchdog_register_device(dev, &wdt->wdtdev);
|
||||
if (ret < 0)
|
||||
|
@ -220,10 +223,34 @@ static int da9062_wdt_probe(struct platform_device *pdev)
|
|||
return da9062_wdt_ping(&wdt->wdtdev);
|
||||
}
|
||||
|
||||
static int __maybe_unused da9062_wdt_suspend(struct device *dev)
|
||||
{
|
||||
struct watchdog_device *wdd = dev_get_drvdata(dev);
|
||||
|
||||
if (watchdog_active(wdd))
|
||||
return da9062_wdt_stop(wdd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused da9062_wdt_resume(struct device *dev)
|
||||
{
|
||||
struct watchdog_device *wdd = dev_get_drvdata(dev);
|
||||
|
||||
if (watchdog_active(wdd))
|
||||
return da9062_wdt_start(wdd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(da9062_wdt_pm_ops,
|
||||
da9062_wdt_suspend, da9062_wdt_resume);
|
||||
|
||||
static struct platform_driver da9062_wdt_driver = {
|
||||
.probe = da9062_wdt_probe,
|
||||
.driver = {
|
||||
.name = "da9062-watchdog",
|
||||
.pm = &da9062_wdt_pm_ops,
|
||||
.of_match_table = da9062_compatible_id_table,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -114,7 +114,15 @@ static int dw_wdt_set_timeout(struct watchdog_device *wdd, unsigned int top_s)
|
|||
writel(top_val | top_val << WDOG_TIMEOUT_RANGE_TOPINIT_SHIFT,
|
||||
dw_wdt->regs + WDOG_TIMEOUT_RANGE_REG_OFFSET);
|
||||
|
||||
wdd->timeout = dw_wdt_top_in_seconds(dw_wdt, top_val);
|
||||
/*
|
||||
* In case users set bigger timeout value than HW can support,
|
||||
* kernel(watchdog_dev.c) helps to feed watchdog before
|
||||
* wdd->max_hw_heartbeat_ms
|
||||
*/
|
||||
if (top_s * 1000 <= wdd->max_hw_heartbeat_ms)
|
||||
wdd->timeout = dw_wdt_top_in_seconds(dw_wdt, top_val);
|
||||
else
|
||||
wdd->timeout = top_s;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -135,6 +143,7 @@ static int dw_wdt_start(struct watchdog_device *wdd)
|
|||
struct dw_wdt *dw_wdt = to_dw_wdt(wdd);
|
||||
|
||||
dw_wdt_set_timeout(wdd, wdd->timeout);
|
||||
dw_wdt_ping(&dw_wdt->wdd);
|
||||
dw_wdt_arm_system_reset(dw_wdt);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
#define IT8726_ID 0x8726 /* the data sheet suggest wrongly 0x8716 */
|
||||
#define IT8728_ID 0x8728
|
||||
#define IT8783_ID 0x8783
|
||||
#define IT8786_ID 0x8786
|
||||
|
||||
/* GPIO Configuration Registers LDN=0x07 */
|
||||
#define WDTCTRL 0x71
|
||||
|
@ -294,6 +295,7 @@ static int __init it87_wdt_init(void)
|
|||
case IT8721_ID:
|
||||
case IT8728_ID:
|
||||
case IT8783_ID:
|
||||
case IT8786_ID:
|
||||
max_units = 65535;
|
||||
break;
|
||||
case IT8705_ID:
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
* Based on sunxi_wdt.c
|
||||
*/
|
||||
|
||||
#include <dt-bindings/reset-controller/mt2712-resets.h>
|
||||
#include <dt-bindings/reset-controller/mt8183-resets.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
|
@ -16,10 +19,11 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/watchdog.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define WDT_MAX_TIMEOUT 31
|
||||
#define WDT_MIN_TIMEOUT 1
|
||||
|
@ -44,6 +48,9 @@
|
|||
#define WDT_SWRST 0x14
|
||||
#define WDT_SWRST_KEY 0x1209
|
||||
|
||||
#define WDT_SWSYSRST 0x18U
|
||||
#define WDT_SWSYS_RST_KEY 0x88000000
|
||||
|
||||
#define DRV_NAME "mtk-wdt"
|
||||
#define DRV_VERSION "1.0"
|
||||
|
||||
|
@ -53,8 +60,94 @@ static unsigned int timeout;
|
|||
struct mtk_wdt_dev {
|
||||
struct watchdog_device wdt_dev;
|
||||
void __iomem *wdt_base;
|
||||
spinlock_t lock; /* protects WDT_SWSYSRST reg */
|
||||
struct reset_controller_dev rcdev;
|
||||
};
|
||||
|
||||
struct mtk_wdt_data {
|
||||
int toprgu_sw_rst_num;
|
||||
};
|
||||
|
||||
static const struct mtk_wdt_data mt2712_data = {
|
||||
.toprgu_sw_rst_num = MT2712_TOPRGU_SW_RST_NUM,
|
||||
};
|
||||
|
||||
static const struct mtk_wdt_data mt8183_data = {
|
||||
.toprgu_sw_rst_num = MT8183_TOPRGU_SW_RST_NUM,
|
||||
};
|
||||
|
||||
static int toprgu_reset_update(struct reset_controller_dev *rcdev,
|
||||
unsigned long id, bool assert)
|
||||
{
|
||||
unsigned int tmp;
|
||||
unsigned long flags;
|
||||
struct mtk_wdt_dev *data =
|
||||
container_of(rcdev, struct mtk_wdt_dev, rcdev);
|
||||
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
|
||||
tmp = readl(data->wdt_base + WDT_SWSYSRST);
|
||||
if (assert)
|
||||
tmp |= BIT(id);
|
||||
else
|
||||
tmp &= ~BIT(id);
|
||||
tmp |= WDT_SWSYS_RST_KEY;
|
||||
writel(tmp, data->wdt_base + WDT_SWSYSRST);
|
||||
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int toprgu_reset_assert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
return toprgu_reset_update(rcdev, id, true);
|
||||
}
|
||||
|
||||
static int toprgu_reset_deassert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
return toprgu_reset_update(rcdev, id, false);
|
||||
}
|
||||
|
||||
static int toprgu_reset(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = toprgu_reset_assert(rcdev, id);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return toprgu_reset_deassert(rcdev, id);
|
||||
}
|
||||
|
||||
static const struct reset_control_ops toprgu_reset_ops = {
|
||||
.assert = toprgu_reset_assert,
|
||||
.deassert = toprgu_reset_deassert,
|
||||
.reset = toprgu_reset,
|
||||
};
|
||||
|
||||
static int toprgu_register_reset_controller(struct platform_device *pdev,
|
||||
int rst_num)
|
||||
{
|
||||
int ret;
|
||||
struct mtk_wdt_dev *mtk_wdt = platform_get_drvdata(pdev);
|
||||
|
||||
spin_lock_init(&mtk_wdt->lock);
|
||||
|
||||
mtk_wdt->rcdev.owner = THIS_MODULE;
|
||||
mtk_wdt->rcdev.nr_resets = rst_num;
|
||||
mtk_wdt->rcdev.ops = &toprgu_reset_ops;
|
||||
mtk_wdt->rcdev.of_node = pdev->dev.of_node;
|
||||
ret = devm_reset_controller_register(&pdev->dev, &mtk_wdt->rcdev);
|
||||
if (ret != 0)
|
||||
dev_err(&pdev->dev,
|
||||
"couldn't register wdt reset controller: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mtk_wdt_restart(struct watchdog_device *wdt_dev,
|
||||
unsigned long action, void *data)
|
||||
{
|
||||
|
@ -155,6 +248,7 @@ static int mtk_wdt_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct mtk_wdt_dev *mtk_wdt;
|
||||
const struct mtk_wdt_data *wdt_data;
|
||||
int err;
|
||||
|
||||
mtk_wdt = devm_kzalloc(dev, sizeof(*mtk_wdt), GFP_KERNEL);
|
||||
|
@ -190,6 +284,13 @@ static int mtk_wdt_probe(struct platform_device *pdev)
|
|||
dev_info(dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)\n",
|
||||
mtk_wdt->wdt_dev.timeout, nowayout);
|
||||
|
||||
wdt_data = of_device_get_match_data(dev);
|
||||
if (wdt_data) {
|
||||
err = toprgu_register_reset_controller(pdev,
|
||||
wdt_data->toprgu_sw_rst_num);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -218,7 +319,9 @@ static int mtk_wdt_resume(struct device *dev)
|
|||
#endif
|
||||
|
||||
static const struct of_device_id mtk_wdt_dt_ids[] = {
|
||||
{ .compatible = "mediatek,mt2712-wdt", .data = &mt2712_data },
|
||||
{ .compatible = "mediatek,mt6589-wdt" },
|
||||
{ .compatible = "mediatek,mt8183-wdt", .data = &mt8183_data },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mtk_wdt_dt_ids);
|
||||
|
|
|
@ -246,7 +246,7 @@ static int qcom_wdt_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
/* check if there is pretimeout support */
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
irq = platform_get_irq_optional(pdev, 0);
|
||||
if (irq > 0) {
|
||||
ret = devm_request_irq(dev, irq, qcom_wdt_isr,
|
||||
IRQF_TRIGGER_RISING,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
/*
|
||||
* Driver for Atmel SAMA5D4 Watchdog Timer
|
||||
*
|
||||
* Copyright (C) 2015 Atmel Corporation
|
||||
* Copyright (C) 2015-2019 Microchip Technology Inc. and its subsidiaries
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
@ -11,6 +11,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reboot.h>
|
||||
|
@ -29,7 +30,10 @@ struct sama5d4_wdt {
|
|||
struct watchdog_device wdd;
|
||||
void __iomem *reg_base;
|
||||
u32 mr;
|
||||
u32 ir;
|
||||
unsigned long last_ping;
|
||||
bool need_irq;
|
||||
bool sam9x60_support;
|
||||
};
|
||||
|
||||
static int wdt_timeout;
|
||||
|
@ -78,7 +82,12 @@ static int sama5d4_wdt_start(struct watchdog_device *wdd)
|
|||
{
|
||||
struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd);
|
||||
|
||||
wdt->mr &= ~AT91_WDT_WDDIS;
|
||||
if (wdt->sam9x60_support) {
|
||||
writel_relaxed(wdt->ir, wdt->reg_base + AT91_SAM9X60_IER);
|
||||
wdt->mr &= ~AT91_SAM9X60_WDDIS;
|
||||
} else {
|
||||
wdt->mr &= ~AT91_WDT_WDDIS;
|
||||
}
|
||||
wdt_write(wdt, AT91_WDT_MR, wdt->mr);
|
||||
|
||||
return 0;
|
||||
|
@ -88,7 +97,12 @@ static int sama5d4_wdt_stop(struct watchdog_device *wdd)
|
|||
{
|
||||
struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd);
|
||||
|
||||
wdt->mr |= AT91_WDT_WDDIS;
|
||||
if (wdt->sam9x60_support) {
|
||||
writel_relaxed(wdt->ir, wdt->reg_base + AT91_SAM9X60_IDR);
|
||||
wdt->mr |= AT91_SAM9X60_WDDIS;
|
||||
} else {
|
||||
wdt->mr |= AT91_WDT_WDDIS;
|
||||
}
|
||||
wdt_write(wdt, AT91_WDT_MR, wdt->mr);
|
||||
|
||||
return 0;
|
||||
|
@ -109,6 +123,14 @@ static int sama5d4_wdt_set_timeout(struct watchdog_device *wdd,
|
|||
struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd);
|
||||
u32 value = WDT_SEC2TICKS(timeout);
|
||||
|
||||
if (wdt->sam9x60_support) {
|
||||
wdt_write(wdt, AT91_SAM9X60_WLR,
|
||||
AT91_SAM9X60_SET_COUNTER(value));
|
||||
|
||||
wdd->timeout = timeout;
|
||||
return 0;
|
||||
}
|
||||
|
||||
wdt->mr &= ~AT91_WDT_WDV;
|
||||
wdt->mr |= AT91_WDT_SET_WDV(value);
|
||||
|
||||
|
@ -143,8 +165,14 @@ static const struct watchdog_ops sama5d4_wdt_ops = {
|
|||
static irqreturn_t sama5d4_wdt_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct sama5d4_wdt *wdt = platform_get_drvdata(dev_id);
|
||||
u32 reg;
|
||||
|
||||
if (wdt_read(wdt, AT91_WDT_SR)) {
|
||||
if (wdt->sam9x60_support)
|
||||
reg = wdt_read(wdt, AT91_SAM9X60_ISR);
|
||||
else
|
||||
reg = wdt_read(wdt, AT91_WDT_SR);
|
||||
|
||||
if (reg) {
|
||||
pr_crit("Atmel Watchdog Software Reset\n");
|
||||
emergency_restart();
|
||||
pr_crit("Reboot didn't succeed\n");
|
||||
|
@ -157,13 +185,14 @@ static int of_sama5d4_wdt_init(struct device_node *np, struct sama5d4_wdt *wdt)
|
|||
{
|
||||
const char *tmp;
|
||||
|
||||
wdt->mr = AT91_WDT_WDDIS;
|
||||
if (wdt->sam9x60_support)
|
||||
wdt->mr = AT91_SAM9X60_WDDIS;
|
||||
else
|
||||
wdt->mr = AT91_WDT_WDDIS;
|
||||
|
||||
if (!of_property_read_string(np, "atmel,watchdog-type", &tmp) &&
|
||||
!strcmp(tmp, "software"))
|
||||
wdt->mr |= AT91_WDT_WDFIEN;
|
||||
else
|
||||
wdt->mr |= AT91_WDT_WDRSTEN;
|
||||
wdt->need_irq = true;
|
||||
|
||||
if (of_property_read_bool(np, "atmel,idle-halt"))
|
||||
wdt->mr |= AT91_WDT_WDIDLEHLT;
|
||||
|
@ -176,21 +205,46 @@ static int of_sama5d4_wdt_init(struct device_node *np, struct sama5d4_wdt *wdt)
|
|||
|
||||
static int sama5d4_wdt_init(struct sama5d4_wdt *wdt)
|
||||
{
|
||||
u32 reg;
|
||||
u32 reg, val;
|
||||
|
||||
val = WDT_SEC2TICKS(WDT_DEFAULT_TIMEOUT);
|
||||
/*
|
||||
* When booting and resuming, the bootloader may have changed the
|
||||
* watchdog configuration.
|
||||
* If the watchdog is already running, we can safely update it.
|
||||
* Else, we have to disable it properly.
|
||||
*/
|
||||
if (wdt_enabled) {
|
||||
wdt_write_nosleep(wdt, AT91_WDT_MR, wdt->mr);
|
||||
} else {
|
||||
if (!wdt_enabled) {
|
||||
reg = wdt_read(wdt, AT91_WDT_MR);
|
||||
if (!(reg & AT91_WDT_WDDIS))
|
||||
if (wdt->sam9x60_support && (!(reg & AT91_SAM9X60_WDDIS)))
|
||||
wdt_write_nosleep(wdt, AT91_WDT_MR,
|
||||
reg | AT91_SAM9X60_WDDIS);
|
||||
else if (!wdt->sam9x60_support &&
|
||||
(!(reg & AT91_WDT_WDDIS)))
|
||||
wdt_write_nosleep(wdt, AT91_WDT_MR,
|
||||
reg | AT91_WDT_WDDIS);
|
||||
}
|
||||
|
||||
if (wdt->sam9x60_support) {
|
||||
if (wdt->need_irq)
|
||||
wdt->ir = AT91_SAM9X60_PERINT;
|
||||
else
|
||||
wdt->mr |= AT91_SAM9X60_PERIODRST;
|
||||
|
||||
wdt_write(wdt, AT91_SAM9X60_IER, wdt->ir);
|
||||
wdt_write(wdt, AT91_SAM9X60_WLR, AT91_SAM9X60_SET_COUNTER(val));
|
||||
} else {
|
||||
wdt->mr |= AT91_WDT_SET_WDD(WDT_SEC2TICKS(MAX_WDT_TIMEOUT));
|
||||
wdt->mr |= AT91_WDT_SET_WDV(val);
|
||||
|
||||
if (wdt->need_irq)
|
||||
wdt->mr |= AT91_WDT_WDFIEN;
|
||||
else
|
||||
wdt->mr |= AT91_WDT_WDRSTEN;
|
||||
}
|
||||
|
||||
wdt_write_nosleep(wdt, AT91_WDT_MR, wdt->mr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -201,7 +255,6 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
|
|||
struct sama5d4_wdt *wdt;
|
||||
void __iomem *regs;
|
||||
u32 irq = 0;
|
||||
u32 timeout;
|
||||
int ret;
|
||||
|
||||
wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
|
||||
|
@ -215,6 +268,8 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
|
|||
wdd->min_timeout = MIN_WDT_TIMEOUT;
|
||||
wdd->max_timeout = MAX_WDT_TIMEOUT;
|
||||
wdt->last_ping = jiffies;
|
||||
wdt->sam9x60_support = of_device_is_compatible(dev->of_node,
|
||||
"microchip,sam9x60-wdt");
|
||||
|
||||
watchdog_set_drvdata(wdd, wdt);
|
||||
|
||||
|
@ -224,15 +279,19 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
|
|||
|
||||
wdt->reg_base = regs;
|
||||
|
||||
irq = irq_of_parse_and_map(dev->of_node, 0);
|
||||
if (!irq)
|
||||
dev_warn(dev, "failed to get IRQ from DT\n");
|
||||
|
||||
ret = of_sama5d4_wdt_init(dev->of_node, wdt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if ((wdt->mr & AT91_WDT_WDFIEN) && irq) {
|
||||
if (wdt->need_irq) {
|
||||
irq = irq_of_parse_and_map(dev->of_node, 0);
|
||||
if (!irq) {
|
||||
dev_warn(dev, "failed to get IRQ from DT\n");
|
||||
wdt->need_irq = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (wdt->need_irq) {
|
||||
ret = devm_request_irq(dev, irq, sama5d4_wdt_irq_handler,
|
||||
IRQF_SHARED | IRQF_IRQPOLL |
|
||||
IRQF_NO_SUSPEND, pdev->name, pdev);
|
||||
|
@ -244,11 +303,6 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
|
|||
|
||||
watchdog_init_timeout(wdd, wdt_timeout, dev);
|
||||
|
||||
timeout = WDT_SEC2TICKS(wdd->timeout);
|
||||
|
||||
wdt->mr |= AT91_WDT_SET_WDD(WDT_SEC2TICKS(MAX_WDT_TIMEOUT));
|
||||
wdt->mr |= AT91_WDT_SET_WDV(timeout);
|
||||
|
||||
ret = sama5d4_wdt_init(wdt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -269,7 +323,12 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
static const struct of_device_id sama5d4_wdt_of_match[] = {
|
||||
{ .compatible = "atmel,sama5d4-wdt", },
|
||||
{
|
||||
.compatible = "atmel,sama5d4-wdt",
|
||||
},
|
||||
{
|
||||
.compatible = "microchip,sam9x60-wdt",
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sama5d4_wdt_of_match);
|
||||
|
|
|
@ -262,6 +262,24 @@ static int stm32_iwdg_probe(struct platform_device *pdev)
|
|||
watchdog_set_nowayout(wdd, WATCHDOG_NOWAYOUT);
|
||||
watchdog_init_timeout(wdd, 0, dev);
|
||||
|
||||
/*
|
||||
* In case of CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED is set
|
||||
* (Means U-Boot/bootloaders leaves the watchdog running)
|
||||
* When we get here we should make a decision to prevent
|
||||
* any side effects before user space daemon will take care of it.
|
||||
* The best option, taking into consideration that there is no
|
||||
* way to read values back from hardware, is to enforce watchdog
|
||||
* being run with deterministic values.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED)) {
|
||||
ret = stm32_iwdg_start(wdd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Make sure the watchdog is serviced */
|
||||
set_bit(WDOG_HW_RUNNING, &wdd->status);
|
||||
}
|
||||
|
||||
ret = devm_watchdog_register_device(dev, wdd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
@ -147,6 +147,25 @@ int watchdog_init_timeout(struct watchdog_device *wdd,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(watchdog_init_timeout);
|
||||
|
||||
static int watchdog_reboot_notifier(struct notifier_block *nb,
|
||||
unsigned long code, void *data)
|
||||
{
|
||||
struct watchdog_device *wdd;
|
||||
|
||||
wdd = container_of(nb, struct watchdog_device, reboot_nb);
|
||||
if (code == SYS_DOWN || code == SYS_HALT) {
|
||||
if (watchdog_active(wdd)) {
|
||||
int ret;
|
||||
|
||||
ret = wdd->ops->stop(wdd);
|
||||
if (ret)
|
||||
return NOTIFY_BAD;
|
||||
}
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static int watchdog_restart_notifier(struct notifier_block *nb,
|
||||
unsigned long action, void *data)
|
||||
{
|
||||
|
@ -235,6 +254,19 @@ static int __watchdog_register_device(struct watchdog_device *wdd)
|
|||
}
|
||||
}
|
||||
|
||||
if (test_bit(WDOG_STOP_ON_REBOOT, &wdd->status)) {
|
||||
wdd->reboot_nb.notifier_call = watchdog_reboot_notifier;
|
||||
|
||||
ret = register_reboot_notifier(&wdd->reboot_nb);
|
||||
if (ret) {
|
||||
pr_err("watchdog%d: Cannot register reboot notifier (%d)\n",
|
||||
wdd->id, ret);
|
||||
watchdog_dev_unregister(wdd);
|
||||
ida_simple_remove(&watchdog_ida, id);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (wdd->ops->restart) {
|
||||
wdd->restart_nb.notifier_call = watchdog_restart_notifier;
|
||||
|
||||
|
@ -289,6 +321,9 @@ static void __watchdog_unregister_device(struct watchdog_device *wdd)
|
|||
if (wdd->ops->restart)
|
||||
unregister_restart_handler(&wdd->restart_nb);
|
||||
|
||||
if (test_bit(WDOG_STOP_ON_REBOOT, &wdd->status))
|
||||
unregister_reboot_notifier(&wdd->reboot_nb);
|
||||
|
||||
watchdog_dev_unregister(wdd);
|
||||
ida_simple_remove(&watchdog_ida, wdd->id);
|
||||
}
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
#include <linux/miscdevice.h> /* For handling misc devices */
|
||||
#include <linux/module.h> /* For module stuff/... */
|
||||
#include <linux/mutex.h> /* For mutexes */
|
||||
#include <linux/reboot.h> /* For reboot notifier */
|
||||
#include <linux/slab.h> /* For memory functions */
|
||||
#include <linux/types.h> /* For standard types (like size_t) */
|
||||
#include <linux/watchdog.h> /* For watchdog specific items */
|
||||
|
@ -1097,25 +1096,6 @@ static void watchdog_cdev_unregister(struct watchdog_device *wdd)
|
|||
put_device(&wd_data->dev);
|
||||
}
|
||||
|
||||
static int watchdog_reboot_notifier(struct notifier_block *nb,
|
||||
unsigned long code, void *data)
|
||||
{
|
||||
struct watchdog_device *wdd;
|
||||
|
||||
wdd = container_of(nb, struct watchdog_device, reboot_nb);
|
||||
if (code == SYS_DOWN || code == SYS_HALT) {
|
||||
if (watchdog_active(wdd)) {
|
||||
int ret;
|
||||
|
||||
ret = wdd->ops->stop(wdd);
|
||||
if (ret)
|
||||
return NOTIFY_BAD;
|
||||
}
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* watchdog_dev_register: register a watchdog device
|
||||
* @wdd: watchdog device
|
||||
|
@ -1134,22 +1114,8 @@ int watchdog_dev_register(struct watchdog_device *wdd)
|
|||
return ret;
|
||||
|
||||
ret = watchdog_register_pretimeout(wdd);
|
||||
if (ret) {
|
||||
if (ret)
|
||||
watchdog_cdev_unregister(wdd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (test_bit(WDOG_STOP_ON_REBOOT, &wdd->status)) {
|
||||
wdd->reboot_nb.notifier_call = watchdog_reboot_notifier;
|
||||
|
||||
ret = devm_register_reboot_notifier(&wdd->wd_data->dev,
|
||||
&wdd->reboot_nb);
|
||||
if (ret) {
|
||||
pr_err("watchdog%d: Cannot register reboot notifier (%d)\n",
|
||||
wdd->id, ret);
|
||||
watchdog_dev_unregister(wdd);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2019 MediaTek Inc.
|
||||
* Author: Yong Liang <yong.liang@mediatek.com>
|
||||
*/
|
||||
|
||||
#ifndef _DT_BINDINGS_RESET_CONTROLLER_MT2712
|
||||
#define _DT_BINDINGS_RESET_CONTROLLER_MT2712
|
||||
|
||||
#define MT2712_TOPRGU_INFRA_SW_RST 0
|
||||
#define MT2712_TOPRGU_MM_SW_RST 1
|
||||
#define MT2712_TOPRGU_MFG_SW_RST 2
|
||||
#define MT2712_TOPRGU_VENC_SW_RST 3
|
||||
#define MT2712_TOPRGU_VDEC_SW_RST 4
|
||||
#define MT2712_TOPRGU_IMG_SW_RST 5
|
||||
#define MT2712_TOPRGU_INFRA_AO_SW_RST 8
|
||||
#define MT2712_TOPRGU_USB_SW_RST 9
|
||||
#define MT2712_TOPRGU_APMIXED_SW_RST 10
|
||||
|
||||
#define MT2712_TOPRGU_SW_RST_NUM 11
|
||||
|
||||
#endif /* _DT_BINDINGS_RESET_CONTROLLER_MT2712 */
|
|
@ -78,4 +78,21 @@
|
|||
#define MT8183_INFRACFG_AO_I2C7_SW_RST 126
|
||||
#define MT8183_INFRACFG_AO_I2C8_SW_RST 127
|
||||
|
||||
#define MT8183_INFRACFG_SW_RST_NUM 128
|
||||
|
||||
#define MT8183_TOPRGU_MM_SW_RST 1
|
||||
#define MT8183_TOPRGU_MFG_SW_RST 2
|
||||
#define MT8183_TOPRGU_VENC_SW_RST 3
|
||||
#define MT8183_TOPRGU_VDEC_SW_RST 4
|
||||
#define MT8183_TOPRGU_IMG_SW_RST 5
|
||||
#define MT8183_TOPRGU_MD_SW_RST 7
|
||||
#define MT8183_TOPRGU_CONN_SW_RST 9
|
||||
#define MT8183_TOPRGU_CONN_MCU_SW_RST 12
|
||||
#define MT8183_TOPRGU_IPU0_SW_RST 14
|
||||
#define MT8183_TOPRGU_IPU1_SW_RST 15
|
||||
#define MT8183_TOPRGU_AUDIO_SW_RST 17
|
||||
#define MT8183_TOPRGU_CAMSYS_SW_RST 18
|
||||
|
||||
#define MT8183_TOPRGU_SW_RST_NUM 19
|
||||
|
||||
#endif /* _DT_BINDINGS_RESET_CONTROLLER_MT8183 */
|
||||
|
|
Loading…
Reference in New Issue