Commit 29057cc5 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'linux-watchdog-6.6-rc1' of git://www.linux-watchdog.org/linux-watchdog

Pull watchdog updates from Wim Van Sebroeck:

 - add marvell GTI watchdog driver

 - add support for Amlogic-T7 SoCs

 - document the IPQ5018 watchdog compatible

 - enable COMPILE_TEST for more watchdog device drivers

 - core: stop watchdog when executing poweroff command

 - other small improvements and fixes

* tag 'linux-watchdog-6.6-rc1' of git://www.linux-watchdog.org/linux-watchdog: (21 commits)
  watchdog: Add support for Amlogic-T7 SoCs
  watchdog: Add a new struct for Amlogic-GXBB driver
  dt-bindings: watchdog: Add support for Amlogic-T7 SoCs
  dt-bindings: watchdog: qcom-wdt: document IPQ5018
  watchdog: imx2_wdt: Improve dev_crit() message
  watchdog: stm32: Drop unnecessary of_match_ptr()
  watchdog: sama5d4: readout initial state
  watchdog: intel-mid_wdt: add MODULE_ALIAS() to allow auto-load
  watchdog: core: stop watchdog when executing poweroff command
  watchdog: pm8916_wdt: Remove redundant of_match_ptr()
  watchdog: xilinx_wwdt: Use div_u64() in xilinx_wwdt_start()
  watchdog: starfive: Remove #ifdef guards for PM related functions
  watchdog: s3c2410: Fix potential deadlock on &wdt->lock
  watchdog:rit_wdt: Add support for WDIOF_CARDRESET
  dt-bindings: watchdog: ti,rti-wdt: Add support for WDIOF_CARDRESET
  watchdog: Enable COMPILE_TEST for more drivers
  watchdog: advantech_ec_wdt: fix Kconfig dependencies
  watchdog: Explicitly include correct DT includes
  Watchdog: Add marvell GTI watchdog driver
  dt-bindings: watchdog: marvell GTI system watchdog driver
  ...
parents 57ac7ff8 8c776a04
......@@ -17,6 +17,7 @@ properties:
compatible:
enum:
- amlogic,meson-gxbb-wdt
- amlogic,t7-wdt
reg:
maxItems: 1
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/watchdog/marvell,cn10624-wdt.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Marvell Global Timer (GTI) system watchdog
maintainers:
- Bharat Bhushan <bbhushan2@marvell.com>
allOf:
- $ref: watchdog.yaml#
properties:
compatible:
oneOf:
- enum:
- marvell,cn9670-wdt
- marvell,cn10624-wdt
- items:
- enum:
- marvell,cn9880-wdt
- marvell,cnf9535-wdt
- const: marvell,cn9670-wdt
- items:
- enum:
- marvell,cn10308-wdt
- marvell,cnf10518-wdt
- const: marvell,cn10624-wdt
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 1
clock-names:
items:
- const: refclk
marvell,wdt-timer-index:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 63
description:
An SoC have many timers (up to 64), firmware can reserve one or more timer
for some other use case and configures one of the global timer as watchdog
timer. Firmware will update this field with the timer number configured
as watchdog timer.
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
watchdog@802000040000 {
compatible = "marvell,cn9670-wdt";
reg = <0x00008020 0x00040000 0x00000000 0x00020000>;
interrupts = <GIC_SPI 38 IRQ_TYPE_EDGE_RISING>;
clocks = <&sclk>;
clock-names = "refclk";
marvell,wdt-timer-index = <63>;
};
};
...
......@@ -18,6 +18,7 @@ properties:
- items:
- enum:
- qcom,kpss-wdt-ipq4019
- qcom,apss-wdt-ipq5018
- qcom,apss-wdt-ipq5332
- qcom,apss-wdt-ipq9574
- qcom,apss-wdt-msm8994
......
......@@ -34,6 +34,20 @@ properties:
power-domains:
maxItems: 1
memory-region:
maxItems: 1
description:
Contains the watchdog reserved memory. It is optional.
In the reserved memory, the specified values, which are
PON_REASON_SOF_NUM(0xBBBBCCCC), PON_REASON_MAGIC_NUM(0xDDDDDDDD),
and PON_REASON_EOF_NUM(0xCCCCBBBB), are pre-stored at the first
3 * 4 bytes to tell that last boot was caused by watchdog reset.
Once the PON reason is captured by driver(rti_wdt.c), the driver
is supposed to wipe the whole memory region. Surely, if this
property is set, at least 12 bytes reserved memory starting from
specific memory address(0xa220000) should be set. More please
refer to example.
required:
- compatible
- reg
......@@ -47,7 +61,18 @@ examples:
/*
* RTI WDT in main domain on J721e SoC. Assigned clocks are used to
* select the source clock for the watchdog, forcing it to tick with
* a 32kHz clock in this case.
* a 32kHz clock in this case. Add a reserved memory(optional) to keep
* the watchdog reset cause persistent, which was be written in 12 bytes
* starting from 0xa2200000 by RTI Watchdog Firmware, then make it
* possible to get watchdog reset cause in driver.
*
* Reserved memory should be defined as follows:
* reserved-memory {
* wdt_reset_memory_region: wdt-memory@a2200000 {
* reg = <0x00 0xa2200000 0x00 0x1000>;
* no-map;
* };
* }
*/
#include <dt-bindings/soc/ti,sci_pm_domain.h>
......@@ -58,4 +83,5 @@ examples:
power-domains = <&k3_pds 252 TI_SCI_PD_EXCLUSIVE>;
assigned-clocks = <&k3_clks 252 1>;
assigned-clock-parents = <&k3_clks 252 5>;
memory-region = <&wdt_reset_memory_region>;
};
This diff is collapsed.
......@@ -98,6 +98,7 @@ obj-$(CONFIG_VISCONTI_WATCHDOG) += visconti_wdt.o
obj-$(CONFIG_MSC313E_WATCHDOG) += msc313e_wdt.o
obj-$(CONFIG_APPLE_WATCHDOG) += apple_wdt.o
obj-$(CONFIG_SUNPLUS_WATCHDOG) += sunplus_wdt.o
obj-$(CONFIG_MARVELL_GTI_WDT) += marvell_gti_wdt.o
# X86 (i386 + ia64 + x86_64) Architecture
obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
......
......@@ -14,7 +14,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/types.h>
......
......@@ -18,6 +18,7 @@
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/atmel-st.h>
#include <linux/miscdevice.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
......@@ -26,8 +27,6 @@
#include <linux/types.h>
#include <linux/watchdog.h>
#include <linux/uaccess.h>
#include <linux/of.h>
#include <linux/of_device.h>
#define WDT_DEFAULT_TIME 5 /* seconds */
#define WDT_MAX_TIME 256 /* seconds */
......
......@@ -31,7 +31,7 @@
#include <linux/mutex.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <asm/irq.h>
......
......@@ -14,7 +14,7 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/watchdog.h>
......@@ -221,20 +221,18 @@ static const struct dev_pm_ops ftwdt010_wdt_dev_pm_ops = {
ftwdt010_wdt_resume)
};
#ifdef CONFIG_OF
static const struct of_device_id ftwdt010_wdt_match[] = {
{ .compatible = "faraday,ftwdt010" },
{ .compatible = "cortina,gemini-watchdog" },
{},
};
MODULE_DEVICE_TABLE(of, ftwdt010_wdt_match);
#endif
static struct platform_driver ftwdt010_wdt_driver = {
.probe = ftwdt010_wdt_probe,
.driver = {
.name = "ftwdt010-wdt",
.of_match_table = of_match_ptr(ftwdt010_wdt_match),
.of_match_table = ftwdt010_wdt_match,
.pm = &ftwdt010_wdt_dev_pm_ops,
},
};
......
......@@ -31,7 +31,7 @@
#include <linux/fs.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/uaccess.h>
......
......@@ -26,8 +26,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/watchdog.h>
......@@ -375,7 +374,7 @@ static void imx2_wdt_shutdown(struct platform_device *pdev)
*/
imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
imx2_wdt_ping(wdog);
dev_crit(&pdev->dev, "Device shutdown: Expect reboot!\n");
dev_crit(&pdev->dev, "Device shutdown.\n");
}
}
......
......@@ -9,7 +9,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
#include <linux/watchdog.h>
......
......@@ -203,3 +203,4 @@ module_platform_driver(mid_wdt_driver);
MODULE_AUTHOR("David Cohen <david.a.cohen@linux.intel.com>");
MODULE_DESCRIPTION("Watchdog Driver for Intel MID platform");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:intel_mid_wdt");
......@@ -9,7 +9,8 @@
#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/watchdog.h>
#include <linux/of_platform.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <linux/clk.h>
#include <linux/io.h>
......
......@@ -4,6 +4,7 @@
*/
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
......
// SPDX-License-Identifier: GPL-2.0
/* Marvell GTI Watchdog driver
*
* Copyright (C) 2023 Marvell.
*/
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/watchdog.h>
/*
* Hardware supports following mode of operation:
* 1) Interrupt Only:
* This will generate the interrupt to arm core whenever timeout happens.
*
* 2) Interrupt + del3t (Interrupt to firmware (SCP processor)).
* This will generate interrupt to arm core on 1st timeout happens
* This will generate interrupt to SCP processor on 2nd timeout happens
*
* 3) Interrupt + Interrupt to SCP processor (called delt3t) + reboot.
* This will generate interrupt to arm core on 1st timeout happens
* Will generate interrupt to SCP processor on 2nd timeout happens,
* if interrupt is configured.
* Reboot on 3rd timeout.
*
* Driver will use hardware in mode-3 above so that system can reboot in case
* a hardware hang. Also h/w is configured not to generate SCP interrupt, so
* effectively 2nd timeout is ignored within hardware.
*
* First timeout is effectively watchdog pretimeout.
*/
/* GTI CWD Watchdog (GTI_CWD_WDOG) Register */
#define GTI_CWD_WDOG(reg_offset) (0x8 * (reg_offset))
#define GTI_CWD_WDOG_MODE_INT_DEL3T_RST 0x3
#define GTI_CWD_WDOG_MODE_MASK GENMASK_ULL(1, 0)
#define GTI_CWD_WDOG_LEN_SHIFT 4
#define GTI_CWD_WDOG_LEN_MASK GENMASK_ULL(19, 4)
#define GTI_CWD_WDOG_CNT_SHIFT 20
#define GTI_CWD_WDOG_CNT_MASK GENMASK_ULL(43, 20)
/* GTI CWD Watchdog Interrupt (GTI_CWD_INT) Register */
#define GTI_CWD_INT 0x200
#define GTI_CWD_INT_PENDING_STATUS(bit) BIT_ULL(bit)
/* GTI CWD Watchdog Interrupt Enable Clear (GTI_CWD_INT_ENA_CLR) Register */
#define GTI_CWD_INT_ENA_CLR 0x210
#define GTI_CWD_INT_ENA_CLR_VAL(bit) BIT_ULL(bit)
/* GTI CWD Watchdog Interrupt Enable Set (GTI_CWD_INT_ENA_SET) Register */
#define GTI_CWD_INT_ENA_SET 0x218
#define GTI_CWD_INT_ENA_SET_VAL(bit) BIT_ULL(bit)
/* GTI CWD Watchdog Poke (GTI_CWD_POKE) Registers */
#define GTI_CWD_POKE(reg_offset) (0x10000 + 0x8 * (reg_offset))
#define GTI_CWD_POKE_VAL 1
struct gti_match_data {
u32 gti_num_timers;
};
static const struct gti_match_data match_data_octeontx2 = {
.gti_num_timers = 54,
};
static const struct gti_match_data match_data_cn10k = {
.gti_num_timers = 64,
};
struct gti_wdt_priv {
struct watchdog_device wdev;
void __iomem *base;
u32 clock_freq;
struct clk *sclk;
/* wdt_timer_idx used for timer to be used for system watchdog */
u32 wdt_timer_idx;
const struct gti_match_data *data;
};
static irqreturn_t gti_wdt_interrupt(int irq, void *data)
{
struct watchdog_device *wdev = data;
struct gti_wdt_priv *priv = watchdog_get_drvdata(wdev);
/* Clear Interrupt Pending Status */
writeq(GTI_CWD_INT_PENDING_STATUS(priv->wdt_timer_idx),
priv->base + GTI_CWD_INT);
watchdog_notify_pretimeout(wdev);
return IRQ_HANDLED;
}
static int gti_wdt_ping(struct watchdog_device *wdev)
{
struct gti_wdt_priv *priv = watchdog_get_drvdata(wdev);
writeq(GTI_CWD_POKE_VAL,
priv->base + GTI_CWD_POKE(priv->wdt_timer_idx));
return 0;
}
static int gti_wdt_start(struct watchdog_device *wdev)
{
struct gti_wdt_priv *priv = watchdog_get_drvdata(wdev);
u64 regval;
if (!wdev->pretimeout)
return -EINVAL;
set_bit(WDOG_HW_RUNNING, &wdev->status);
/* Clear any pending interrupt */
writeq(GTI_CWD_INT_PENDING_STATUS(priv->wdt_timer_idx),
priv->base + GTI_CWD_INT);
/* Enable Interrupt */
writeq(GTI_CWD_INT_ENA_SET_VAL(priv->wdt_timer_idx),
priv->base + GTI_CWD_INT_ENA_SET);
/* Set (Interrupt + SCP interrupt (DEL3T) + core domain reset) Mode */
regval = readq(priv->base + GTI_CWD_WDOG(priv->wdt_timer_idx));
regval |= GTI_CWD_WDOG_MODE_INT_DEL3T_RST;
writeq(regval, priv->base + GTI_CWD_WDOG(priv->wdt_timer_idx));
return 0;
}
static int gti_wdt_stop(struct watchdog_device *wdev)
{
struct gti_wdt_priv *priv = watchdog_get_drvdata(wdev);
u64 regval;
/* Disable Interrupt */
writeq(GTI_CWD_INT_ENA_CLR_VAL(priv->wdt_timer_idx),
priv->base + GTI_CWD_INT_ENA_CLR);
/* Set GTI_CWD_WDOG.Mode = 0 to stop the timer */
regval = readq(priv->base + GTI_CWD_WDOG(priv->wdt_timer_idx));
regval &= ~GTI_CWD_WDOG_MODE_MASK;
writeq(regval, priv->base + GTI_CWD_WDOG(priv->wdt_timer_idx));
return 0;
}
static int gti_wdt_settimeout(struct watchdog_device *wdev,
unsigned int timeout)
{
struct gti_wdt_priv *priv = watchdog_get_drvdata(wdev);
u64 timeout_wdog, regval;
/* Update new timeout */
wdev->timeout = timeout;
/* Pretimeout is 1/3 of timeout */
wdev->pretimeout = timeout / 3;
/* Get clock cycles from pretimeout */
timeout_wdog = (u64)priv->clock_freq * wdev->pretimeout;
/* Watchdog counts in 1024 cycle steps */
timeout_wdog = timeout_wdog >> 10;
/* GTI_CWD_WDOG.CNT: reload counter is 16-bit */
timeout_wdog = (timeout_wdog + 0xff) >> 8;
if (timeout_wdog >= 0x10000)
timeout_wdog = 0xffff;
/*
* GTI_CWD_WDOG.LEN is 24bit, lower 8-bits should be zero and
* upper 16-bits are same as GTI_CWD_WDOG.CNT
*/
regval = readq(priv->base + GTI_CWD_WDOG(priv->wdt_timer_idx));
regval &= GTI_CWD_WDOG_MODE_MASK;
regval |= (timeout_wdog << (GTI_CWD_WDOG_CNT_SHIFT + 8)) |
(timeout_wdog << GTI_CWD_WDOG_LEN_SHIFT);
writeq(regval, priv->base + GTI_CWD_WDOG(priv->wdt_timer_idx));
return 0;
}
static int gti_wdt_set_pretimeout(struct watchdog_device *wdev,
unsigned int timeout)
{
struct gti_wdt_priv *priv = watchdog_get_drvdata(wdev);
struct watchdog_device *wdog_dev = &priv->wdev;
/* pretimeout should 1/3 of max_timeout */
if (timeout * 3 <= wdog_dev->max_timeout)
return gti_wdt_settimeout(wdev, timeout * 3);
return -EINVAL;
}
static void gti_clk_disable_unprepare(void *data)
{
clk_disable_unprepare(data);
}
static int gti_wdt_get_cntfrq(struct platform_device *pdev,
struct gti_wdt_priv *priv)
{
int err;
priv->sclk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(priv->sclk))
return PTR_ERR(priv->sclk);
err = devm_add_action_or_reset(&pdev->dev,
gti_clk_disable_unprepare, priv->sclk);
if (err)
return err;
priv->clock_freq = clk_get_rate(priv->sclk);
if (!priv->clock_freq)
return -EINVAL;
return 0;
}
static const struct watchdog_info gti_wdt_ident = {
.identity = "Marvell GTI watchdog",
.options = WDIOF_SETTIMEOUT | WDIOF_PRETIMEOUT | WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE | WDIOF_CARDRESET,
};
static const struct watchdog_ops gti_wdt_ops = {
.owner = THIS_MODULE,
.start = gti_wdt_start,
.stop = gti_wdt_stop,
.ping = gti_wdt_ping,
.set_timeout = gti_wdt_settimeout,
.set_pretimeout = gti_wdt_set_pretimeout,
};
static int gti_wdt_probe(struct platform_device *pdev)
{
struct gti_wdt_priv *priv;
struct device *dev = &pdev->dev;
struct watchdog_device *wdog_dev;
u64 max_pretimeout;
u32 wdt_idx;
int irq;
int err;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base))
return dev_err_probe(&pdev->dev, PTR_ERR(priv->base),
"reg property not valid/found\n");
err = gti_wdt_get_cntfrq(pdev, priv);
if (err)
return dev_err_probe(&pdev->dev, err,
"GTI clock frequency not valid/found");
priv->data = of_device_get_match_data(dev);
/* default use last timer for watchdog */
priv->wdt_timer_idx = priv->data->gti_num_timers - 1;
err = of_property_read_u32(dev->of_node, "marvell,wdt-timer-index",
&wdt_idx);
if (!err) {
if (wdt_idx >= priv->data->gti_num_timers)
return dev_err_probe(&pdev->dev, err,
"GTI wdog timer index not valid");
priv->wdt_timer_idx = wdt_idx;
}
wdog_dev = &priv->wdev;
wdog_dev->info = &gti_wdt_ident,
wdog_dev->ops = &gti_wdt_ops,
wdog_dev->parent = dev;
/*
* Watchdog counter is 24 bit where lower 8 bits are zeros
* This counter decrements every 1024 clock cycles.
*/
max_pretimeout = (GTI_CWD_WDOG_CNT_MASK >> GTI_CWD_WDOG_CNT_SHIFT);
max_pretimeout &= ~0xFFUL;
max_pretimeout = (max_pretimeout * 1024) / priv->clock_freq;
wdog_dev->pretimeout = max_pretimeout;
/* Maximum timeout is 3 times the pretimeout */
wdog_dev->max_timeout = max_pretimeout * 3;
/* Minimum first timeout (pretimeout) is 1, so min_timeout as 3 */
wdog_dev->min_timeout = 3;
wdog_dev->timeout = wdog_dev->pretimeout;
watchdog_set_drvdata(wdog_dev, priv);
platform_set_drvdata(pdev, priv);
gti_wdt_settimeout(wdog_dev, wdog_dev->timeout);
watchdog_stop_on_reboot(wdog_dev);
watchdog_stop_on_unregister(wdog_dev);
err = devm_watchdog_register_device(dev, wdog_dev);
if (err)
return err;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return dev_err_probe(&pdev->dev, irq, "IRQ resource not found\n");
err = devm_request_irq(dev, irq, gti_wdt_interrupt, 0,
pdev->name, &priv->wdev);
if (err)
return dev_err_probe(dev, err, "Failed to register interrupt handler\n");
dev_info(dev, "Watchdog enabled (timeout=%d sec)\n", wdog_dev->timeout);
return 0;
}
static const struct of_device_id gti_wdt_of_match[] = {
{ .compatible = "marvell,cn9670-wdt", .data = &match_data_octeontx2},
{ .compatible = "marvell,cn10624-wdt", .data = &match_data_cn10k},
{ },
};
MODULE_DEVICE_TABLE(of, gti_wdt_of_match);
static struct platform_driver gti_wdt_driver = {
.driver = {
.name = "gti-wdt",
.of_match_table = gti_wdt_of_match,
},
.probe = gti_wdt_probe,
};
module_platform_driver(gti_wdt_driver);
MODULE_AUTHOR("Bharat Bhushan <bbhushan2@marvell.com>");
MODULE_DESCRIPTION("Marvell GTI watchdog driver");
MODULE_LICENSE("GPL");
......@@ -153,7 +153,6 @@ MODULE_DEVICE_TABLE(mcb, men_z069_ids);
static struct mcb_driver men_z069_driver = {
.driver = {
.name = "z069-wdt",
.owner = THIS_MODULE,
},
.probe = men_z069_probe,
.remove = men_z069_remove,
......
......@@ -22,7 +22,6 @@
#define GXBB_WDT_CTRL_CLKDIV_EN BIT(25)
#define GXBB_WDT_CTRL_CLK_EN BIT(24)
#define GXBB_WDT_CTRL_EE_RESET BIT(21)
#define GXBB_WDT_CTRL_EN BIT(18)
#define GXBB_WDT_CTRL_DIV_MASK (BIT(18) - 1)
......@@ -45,6 +44,10 @@ struct meson_gxbb_wdt {
struct clk *clk;
};
struct wdt_params {
u32 rst;
};
static int meson_gxbb_wdt_start(struct watchdog_device *wdt_dev)
{
struct meson_gxbb_wdt *data = watchdog_get_drvdata(wdt_dev);
......@@ -140,8 +143,17 @@ static const struct dev_pm_ops meson_gxbb_wdt_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(meson_gxbb_wdt_suspend, meson_gxbb_wdt_resume)
};
static const struct wdt_params gxbb_params = {
.rst = BIT(21),
};
static const struct wdt_params t7_params = {
.rst = BIT(22),
};
static const struct of_device_id meson_gxbb_wdt_dt_ids[] = {
{ .compatible = "amlogic,meson-gxbb-wdt", },
{ .compatible = "amlogic,meson-gxbb-wdt", .data = &gxbb_params, },
{ .compatible = "amlogic,t7-wdt", .data = &t7_params, },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, meson_gxbb_wdt_dt_ids);
......@@ -150,6 +162,7 @@ static int meson_gxbb_wdt_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct meson_gxbb_wdt *data;
struct wdt_params *params;
u32 ctrl_reg;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
......@@ -164,6 +177,8 @@ static int meson_gxbb_wdt_probe(struct platform_device *pdev)
if (IS_ERR(data->clk))
return PTR_ERR(data->clk);
params = (struct wdt_params *)of_device_get_match_data(dev);
platform_set_drvdata(pdev, data);
data->wdt_dev.parent = dev;
......@@ -191,7 +206,7 @@ static int meson_gxbb_wdt_probe(struct platform_device *pdev)
/* Setup with 1ms timebase */
ctrl_reg |= ((clk_get_rate(data->clk) / 1000) &
GXBB_WDT_CTRL_DIV_MASK) |
GXBB_WDT_CTRL_EE_RESET |
params->rst |
GXBB_WDT_CTRL_CLK_EN |
GXBB_WDT_CTRL_CLKDIV_EN;
......
......@@ -11,11 +11,11 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/types.h>
#include <linux/watchdog.h>
......
......@@ -16,8 +16,8 @@
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/watchdog.h>
#include <linux/io.h>
......
......@@ -25,7 +25,6 @@
#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>
......
......@@ -10,14 +10,13 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/watchdog.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
/* Register offsets for the Wdt device */
#define XWT_TWCSR0_OFFSET 0x0 /* Control/Status Register0 */
......
......@@ -12,7 +12,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/watchdog.h>
......
......@@ -12,7 +12,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/watchdog.h>
......
......@@ -23,8 +23,8 @@
#include <linux/bitops.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#define DRV_NAME "PIKA-WDT"
......
......@@ -266,7 +266,7 @@ static struct platform_driver pm8916_wdt_driver = {
.probe = pm8916_wdt_probe,
.driver = {
.name = "pm8916-wdt",
.of_match_table = of_match_ptr(pm8916_wdt_id_table),
.of_match_table = pm8916_wdt_id_table,
.pm = &pm8916_wdt_pm_ops,
},
};
......
......@@ -11,7 +11,6 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/watchdog.h>
#include <linux/of_device.h>
enum wdt_reg {
WDT_RST,
......
......@@ -13,7 +13,7 @@
#include <linux/mfd/rave-sp.h>
#include <linux/module.h>
#include <linux/nvmem-consumer.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
#include <linux/slab.h>
......
......@@ -14,7 +14,7 @@
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
......
......@@ -14,6 +14,8 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/types.h>
......@@ -52,6 +54,11 @@
#define DWDST BIT(1)
#define PON_REASON_SOF_NUM 0xBBBBCCCC
#define PON_REASON_MAGIC_NUM 0xDDDDDDDD
#define PON_REASON_EOF_NUM 0xCCCCBBBB
#define RESERVED_MEM_MIN_SIZE 12
static int heartbeat = DEFAULT_HEARTBEAT;
/*
......@@ -198,6 +205,11 @@ static int rti_wdt_probe(struct platform_device *pdev)
struct rti_wdt_device *wdt;
struct clk *clk;
u32 last_ping = 0;
struct device_node *node;
u32 reserved_mem_size;
struct resource res;
u32 *vaddr;
u64 paddr;
wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
if (!wdt)
......@@ -284,6 +296,42 @@ static int rti_wdt_probe(struct platform_device *pdev)
}
}
node = of_parse_phandle(pdev->dev.of_node, "memory-region", 0);
if (node) {
ret = of_address_to_resource(node, 0, &res);
if (ret) {
dev_err(dev, "No memory address assigned to the region.\n");
goto err_iomap;
}
/*
* If reserved memory is defined for watchdog reset cause.
* Readout the Power-on(PON) reason and pass to bootstatus.
*/
paddr = res.start;
reserved_mem_size = resource_size(&res);
if (reserved_mem_size < RESERVED_MEM_MIN_SIZE) {
dev_err(dev, "The size of reserved memory is too small.\n");
ret = -EINVAL;
goto err_iomap;
}
vaddr = memremap(paddr, reserved_mem_size, MEMREMAP_WB);
if (!vaddr) {
dev_err(dev, "Failed to map memory-region.\n");
ret = -ENOMEM;
goto err_iomap;
}
if (vaddr[0] == PON_REASON_SOF_NUM &&
vaddr[1] == PON_REASON_MAGIC_NUM &&
vaddr[2] == PON_REASON_EOF_NUM) {
wdd->bootstatus |= WDIOF_CARDRESET;
}
memset(vaddr, 0, reserved_mem_size);
memunmap(vaddr);
}
watchdog_init_timeout(wdd, heartbeat, dev);
ret = watchdog_register_device(wdd);
......
......@@ -9,9 +9,9 @@
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/watchdog.h>
......
......@@ -11,7 +11,7 @@
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
......
......@@ -23,7 +23,6 @@
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/delay.h>
......@@ -379,10 +378,11 @@ static int s3c2410wdt_enable(struct s3c2410_wdt *wdt, bool en)
static int s3c2410wdt_keepalive(struct watchdog_device *wdd)
{
struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd);
unsigned long flags;
spin_lock(&wdt->lock);
spin_lock_irqsave(&wdt->lock, flags);
writel(wdt->count, wdt->reg_base + S3C2410_WTCNT);
spin_unlock(&wdt->lock);
spin_unlock_irqrestore(&wdt->lock, flags);
return 0;
}
......@@ -399,10 +399,11 @@ static void __s3c2410wdt_stop(struct s3c2410_wdt *wdt)
static int s3c2410wdt_stop(struct watchdog_device *wdd)
{
struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd);
unsigned long flags;
spin_lock(&wdt->lock);
spin_lock_irqsave(&wdt->lock, flags);
__s3c2410wdt_stop(wdt);
spin_unlock(&wdt->lock);
spin_unlock_irqrestore(&wdt->lock, flags);
return 0;
}
......@@ -411,8 +412,9 @@ static int s3c2410wdt_start(struct watchdog_device *wdd)
{
unsigned long wtcon;
struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd);
unsigned long flags;
spin_lock(&wdt->lock);
spin_lock_irqsave(&wdt->lock, flags);
__s3c2410wdt_stop(wdt);
......@@ -433,7 +435,7 @@ static int s3c2410wdt_start(struct watchdog_device *wdd)
writel(wdt->count, wdt->reg_base + S3C2410_WTDAT);
writel(wdt->count, wdt->reg_base + S3C2410_WTCNT);
writel(wtcon, wdt->reg_base + S3C2410_WTCON);
spin_unlock(&wdt->lock);
spin_unlock_irqrestore(&wdt->lock, flags);
return 0;
}
......
......@@ -11,7 +11,6 @@
#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>
......@@ -255,6 +254,7 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
struct sama5d4_wdt *wdt;
void __iomem *regs;
u32 irq = 0;
u32 reg;
int ret;
wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
......@@ -305,6 +305,12 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
watchdog_init_timeout(wdd, wdt_timeout, dev);
reg = wdt_read(wdt, AT91_WDT_MR);
if (!(reg & AT91_WDT_WDDIS)) {
wdt->mr &= ~AT91_WDT_WDDIS;
set_bit(WDOG_HW_RUNNING, &wdd->status);
}
ret = sama5d4_wdt_init(wdt);
if (ret)
return ret;
......
......@@ -43,10 +43,9 @@
#include <linux/io.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/interrupt.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <linux/watchdog.h>
......
......@@ -8,7 +8,8 @@
#include <linux/clk.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/watchdog.h>
......@@ -526,7 +527,6 @@ static void starfive_wdt_shutdown(struct platform_device *pdev)
starfive_wdt_pm_stop(&wdt->wdd);
}
#ifdef CONFIG_PM_SLEEP
static int starfive_wdt_suspend(struct device *dev)
{
struct starfive_wdt *wdt = dev_get_drvdata(dev);
......@@ -556,9 +556,7 @@ static int starfive_wdt_resume(struct device *dev)
return starfive_wdt_start(wdt);
}
#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_PM
static int starfive_wdt_runtime_suspend(struct device *dev)
{
struct starfive_wdt *wdt = dev_get_drvdata(dev);
......@@ -574,11 +572,10 @@ static int starfive_wdt_runtime_resume(struct device *dev)
return starfive_wdt_enable_clock(wdt);
}
#endif /* CONFIG_PM */
static const struct dev_pm_ops starfive_wdt_pm_ops = {
SET_RUNTIME_PM_OPS(starfive_wdt_runtime_suspend, starfive_wdt_runtime_resume, NULL)
SET_SYSTEM_SLEEP_PM_OPS(starfive_wdt_suspend, starfive_wdt_resume)
RUNTIME_PM_OPS(starfive_wdt_runtime_suspend, starfive_wdt_runtime_resume, NULL)
SYSTEM_SLEEP_PM_OPS(starfive_wdt_suspend, starfive_wdt_resume)
};
static const struct of_device_id starfive_wdt_match[] = {
......@@ -594,7 +591,7 @@ static struct platform_driver starfive_wdt_driver = {
.shutdown = starfive_wdt_shutdown,
.driver = {
.name = "starfive-wdt",
.pm = &starfive_wdt_pm_ops,
.pm = pm_ptr(&starfive_wdt_pm_ops),
.of_match_table = starfive_wdt_match,
},
};
......
......@@ -17,7 +17,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/watchdog.h>
......@@ -288,7 +287,7 @@ static struct platform_driver stm32_iwdg_driver = {
.probe = stm32_iwdg_probe,
.driver = {
.name = "iwdg",
.of_match_table = of_match_ptr(stm32_iwdg_of_match),
.of_match_table = stm32_iwdg_of_match,
},
};
module_platform_driver(stm32_iwdg_driver);
......
......@@ -18,7 +18,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/watchdog.h>
......
......@@ -161,7 +161,7 @@ static int watchdog_reboot_notifier(struct notifier_block *nb,
struct watchdog_device *wdd;
wdd = container_of(nb, struct watchdog_device, reboot_nb);
if (code == SYS_DOWN || code == SYS_HALT) {
if (code == SYS_DOWN || code == SYS_HALT || code == SYS_POWER_OFF) {
if (watchdog_hw_running(wdd)) {
int ret;
......
......@@ -9,9 +9,10 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/math64.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/watchdog.h>
/* Max timeout is calculated at 100MHz source clock */
......@@ -71,7 +72,7 @@ static int xilinx_wwdt_start(struct watchdog_device *wdd)
/* Calculate timeout count */
time_out = xdev->freq * wdd->timeout;
closed_timeout = (time_out * xdev->close_percent) / 100;
closed_timeout = div_u64(time_out * xdev->close_percent, 100);
open_timeout = time_out - closed_timeout;
wdd->min_hw_heartbeat_ms = xdev->close_percent * 10 * wdd->timeout;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment