2021-11-30 16:18:33

by Sven Peter

[permalink] [raw]
Subject: [PATCH v2 1/2] dt-bindings: watchdog: Add Apple Watchdog

Apple SoCs come with a simple embedded watchdog. This watchdog is also
required in order to reset the SoC.

Reviewed-by: Mark Kettenis <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
Signed-off-by: Sven Peter <[email protected]>
---
v1 --> v2:
- add Mark's and Rob's r-b tags

.../bindings/watchdog/apple,wdt.yaml | 52 +++++++++++++++++++
MAINTAINERS | 1 +
2 files changed, 53 insertions(+)
create mode 100644 Documentation/devicetree/bindings/watchdog/apple,wdt.yaml

diff --git a/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml b/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml
new file mode 100644
index 000000000000..e58c56a6fdf6
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml
@@ -0,0 +1,52 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/watchdog/apple,wdt.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Apple SoC Watchdog
+
+allOf:
+ - $ref: "watchdog.yaml#"
+
+maintainers:
+ - Sven Peter <[email protected]>
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - apple,t8103-wdt
+ - apple,t6000-wdt
+ - const: apple,wdt
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - interrupts
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/apple-aic.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ wdt: watchdog@50000000 {
+ compatible = "apple,t8103-wdt", "apple,wdt";
+ reg = <0x50000000 0x4000>;
+ clocks = <&clk>;
+ interrupts = <AIC_IRQ 123 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 360e9aa0205d..859201bbd4e8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1750,6 +1750,7 @@ F: Documentation/devicetree/bindings/interrupt-controller/apple,aic.yaml
F: Documentation/devicetree/bindings/mailbox/apple,mailbox.yaml
F: Documentation/devicetree/bindings/pci/apple,pcie.yaml
F: Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml
+F: Documentation/devicetree/bindings/watchdog/apple,wdt.yaml
F: arch/arm64/boot/dts/apple/
F: drivers/i2c/busses/i2c-pasemi-core.c
F: drivers/i2c/busses/i2c-pasemi-platform.c
--
2.25.1



2021-11-30 16:18:35

by Sven Peter

[permalink] [raw]
Subject: [PATCH v2 2/2] watchdog: Add Apple SoC watchdog driver

Add support for the watchdog timer found in Apple SoCs. This driver is
also required to reboot these machines.

Signed-off-by: Sven Peter <[email protected]>
---
v1 -> v2:
- set the default timeout to 30s and call watchdog_init_timeout
to allow the device tree to override it
- set WDOG_HW_RUNNING if the watchdog is enabled at boot
- check that the clock rate is not zero
- use unsigned long instead of u32 for clk_rate
- use devm_add_action_or_reset instead of manually calling
clk_disable_unprepare
- explain the magic number in apple_wdt_restart

MAINTAINERS | 1 +
drivers/watchdog/Kconfig | 12 ++
drivers/watchdog/Makefile | 1 +
drivers/watchdog/apple_wdt.c | 226 +++++++++++++++++++++++++++++++++++
4 files changed, 240 insertions(+)
create mode 100644 drivers/watchdog/apple_wdt.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 859201bbd4e8..6190f0b40983 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1757,6 +1757,7 @@ F: drivers/i2c/busses/i2c-pasemi-platform.c
F: drivers/irqchip/irq-apple-aic.c
F: drivers/mailbox/apple-mailbox.c
F: drivers/pinctrl/pinctrl-apple-gpio.c
+F: drivers/watchdog/apple_wdt.c
F: include/dt-bindings/interrupt-controller/apple-aic.h
F: include/dt-bindings/pinctrl/apple.h
F: include/linux/apple-mailbox.h
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 9d222ba17ec6..170dec880c8f 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -976,6 +976,18 @@ config MSC313E_WATCHDOG
To compile this driver as a module, choose M here: the
module will be called msc313e_wdt.

+config APPLE_WATCHDOG
+ tristate "Apple SoC watchdog"
+ depends on ARCH_APPLE || COMPILE_TEST
+ select WATCHDOG_CORE
+ help
+ Say Y here to include support for the Watchdog found in Apple
+ SoCs such as the M1. Next to the common watchdog features this
+ driver is also required in order to reboot these SoCs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called apple_wdt.
+
# X86 (i386 + ia64 + x86_64) Architecture

config ACQUIRE_WDT
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 2ee97064145b..270a518bd8f3 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -93,6 +93,7 @@ obj-$(CONFIG_PM8916_WATCHDOG) += pm8916_wdt.o
obj-$(CONFIG_ARM_SMC_WATCHDOG) += arm_smc_wdt.o
obj-$(CONFIG_VISCONTI_WATCHDOG) += visconti_wdt.o
obj-$(CONFIG_MSC313E_WATCHDOG) += msc313e_wdt.o
+obj-$(CONFIG_APPLE_WATCHDOG) += apple_wdt.o

# X86 (i386 + ia64 + x86_64) Architecture
obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
diff --git a/drivers/watchdog/apple_wdt.c b/drivers/watchdog/apple_wdt.c
new file mode 100644
index 000000000000..76e5bedd50d1
--- /dev/null
+++ b/drivers/watchdog/apple_wdt.c
@@ -0,0 +1,226 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Apple SoC Watchdog driver
+ *
+ * Copyright (C) The Asahi Linux Contributors
+ */
+
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/limits.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/watchdog.h>
+
+/*
+ * Apple Watchdog MMIO registers
+ *
+ * This HW block has three separate watchdogs. WD0 resets the machine
+ * to recovery mode and is not very useful for us. WD1 and WD2 trigger a normal
+ * machine reset. WD0 additionally supports a configurable interrupt.
+ * This information can be used to implement pretimeout support at a later time.
+ *
+ * APPLE_WDT_WDx_CUR_TIME is a simple counter incremented for each tick of the
+ * reference clock. It can also be overwritten to any value.
+ * Whenever APPLE_WDT_CTRL_RESET_EN is set in APPLE_WDT_WDx_CTRL and
+ * APPLE_WDTx_WD1_CUR_TIME >= APPLE_WDTx_WD1_BITE_TIME the entire machine is
+ * reset.
+ * Whenever APPLE_WDT_CTRL_IRQ_EN is set and APPLE_WDTx_WD1_CUR_TIME >=
+ * APPLE_WDTx_WD1_BARK_TIME an interrupt is triggered and
+ * APPLE_WDT_CTRL_IRQ_STATUS is set. The interrupt can be cleared by writing
+ * 1 to APPLE_WDT_CTRL_IRQ_STATUS.
+ */
+#define APPLE_WDT_WD0_CUR_TIME 0x00
+#define APPLE_WDT_WD0_BITE_TIME 0x04
+#define APPLE_WDT_WD0_BARK_TIME 0x08
+#define APPLE_WDT_WD0_CTRL 0x0c
+
+#define APPLE_WDT_WD1_CUR_TIME 0x10
+#define APPLE_WDT_WD1_BITE_TIME 0x14
+#define APPLE_WDT_WD1_CTRL 0x1c
+
+#define APPLE_WDT_WD2_CUR_TIME 0x20
+#define APPLE_WDT_WD2_BITE_TIME 0x24
+#define APPLE_WDT_WD2_CTRL 0x2c
+
+#define APPLE_WDT_CTRL_IRQ_EN BIT(0)
+#define APPLE_WDT_CTRL_IRQ_STATUS BIT(1)
+#define APPLE_WDT_CTRL_RESET_EN BIT(2)
+
+#define APPLE_WDT_TIMEOUT_DEFAULT 30
+
+struct apple_wdt {
+ struct watchdog_device wdd;
+ void __iomem *regs;
+ unsigned long clk_rate;
+};
+
+static struct apple_wdt *to_apple_wdt(struct watchdog_device *wdd)
+{
+ return container_of(wdd, struct apple_wdt, wdd);
+}
+
+static int apple_wdt_start(struct watchdog_device *wdd)
+{
+ struct apple_wdt *wdt = to_apple_wdt(wdd);
+
+ writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CUR_TIME);
+ writel_relaxed(APPLE_WDT_CTRL_RESET_EN, wdt->regs + APPLE_WDT_WD1_CTRL);
+
+ return 0;
+}
+
+static int apple_wdt_stop(struct watchdog_device *wdd)
+{
+ struct apple_wdt *wdt = to_apple_wdt(wdd);
+
+ writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CTRL);
+
+ return 0;
+}
+
+static int apple_wdt_ping(struct watchdog_device *wdd)
+{
+ struct apple_wdt *wdt = to_apple_wdt(wdd);
+
+ writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CUR_TIME);
+
+ return 0;
+}
+
+static int apple_wdt_set_timeout(struct watchdog_device *wdd, unsigned int s)
+{
+ struct apple_wdt *wdt = to_apple_wdt(wdd);
+
+ writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CUR_TIME);
+ writel_relaxed(wdt->clk_rate * s, wdt->regs + APPLE_WDT_WD1_BITE_TIME);
+
+ wdd->timeout = s;
+
+ return 0;
+}
+
+static unsigned int apple_wdt_get_timeleft(struct watchdog_device *wdd)
+{
+ struct apple_wdt *wdt = to_apple_wdt(wdd);
+ u32 cur_time, reset_time;
+
+ cur_time = readl_relaxed(wdt->regs + APPLE_WDT_WD1_CUR_TIME);
+ reset_time = readl_relaxed(wdt->regs + APPLE_WDT_WD1_BITE_TIME);
+
+ return (reset_time - cur_time) / wdt->clk_rate;
+}
+
+static int apple_wdt_restart(struct watchdog_device *wdd, unsigned long mode,
+ void *cmd)
+{
+ struct apple_wdt *wdt = to_apple_wdt(wdd);
+
+ writel_relaxed(APPLE_WDT_CTRL_RESET_EN, wdt->regs + APPLE_WDT_WD1_CTRL);
+ writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_BITE_TIME);
+ writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CUR_TIME);
+
+ /*
+ * Flush writes and then wait for the SoC to reset. Even though the
+ * reset is queued almost immediately experiments have shown that it
+ * can take up to ~20-25ms until the SoC is actually reset. Just wait
+ * 50ms here to be safe.
+ */
+ (void)readl_relaxed(wdt->regs + APPLE_WDT_WD1_CUR_TIME);
+ mdelay(50);
+
+ return 0;
+}
+
+static void apple_wdt_clk_disable_unprepare(void *data)
+{
+ clk_disable_unprepare(data);
+}
+
+static struct watchdog_ops apple_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = apple_wdt_start,
+ .stop = apple_wdt_stop,
+ .ping = apple_wdt_ping,
+ .set_timeout = apple_wdt_set_timeout,
+ .get_timeleft = apple_wdt_get_timeleft,
+ .restart = apple_wdt_restart,
+};
+
+static struct watchdog_info apple_wdt_info = {
+ .identity = "Apple SoC Watchdog",
+ .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
+};
+
+static int apple_wdt_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct apple_wdt *wdt;
+ struct clk *clk;
+ u32 wdt_ctrl;
+ int ret;
+
+ wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
+ if (!wdt)
+ return -ENOMEM;
+
+ wdt->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(wdt->regs))
+ return PTR_ERR(wdt->regs);
+
+ clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ ret = clk_prepare_enable(clk);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, apple_wdt_clk_disable_unprepare,
+ clk);
+ if (ret)
+ return ret;
+
+ wdt->clk_rate = clk_get_rate(clk);
+ if (!wdt->clk_rate)
+ return -EINVAL;
+
+ wdt->wdd.ops = &apple_wdt_ops;
+ wdt->wdd.info = &apple_wdt_info;
+ wdt->wdd.max_timeout = U32_MAX / wdt->clk_rate;
+ wdt->wdd.timeout = APPLE_WDT_TIMEOUT_DEFAULT;
+
+ wdt_ctrl = readl_relaxed(wdt->regs + APPLE_WDT_WD1_CTRL);
+ if (wdt_ctrl & APPLE_WDT_CTRL_RESET_EN)
+ set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
+
+ watchdog_init_timeout(&wdt->wdd, 0, dev);
+ apple_wdt_set_timeout(&wdt->wdd, wdt->wdd.timeout);
+ watchdog_stop_on_unregister(&wdt->wdd);
+ watchdog_set_restart_priority(&wdt->wdd, 128);
+
+ return devm_watchdog_register_device(dev, &wdt->wdd);
+}
+
+static const struct of_device_id apple_wdt_of_match[] = {
+ { .compatible = "apple,wdt" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, apple_wdt_of_match);
+
+static struct platform_driver apple_wdt_driver = {
+ .driver = {
+ .name = "apple-watchdog",
+ .of_match_table = apple_wdt_of_match,
+ },
+ .probe = apple_wdt_probe,
+};
+module_platform_driver(apple_wdt_driver);
+
+MODULE_DESCRIPTION("Apple SoC watchdog driver");
+MODULE_AUTHOR("Sven Peter <[email protected]>");
+MODULE_LICENSE("Dual MIT/GPL");
--
2.25.1


2021-11-30 20:57:53

by Janne Grunau

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] watchdog: Add Apple SoC watchdog driver

Hej,

On 2021-11-30 17:18:09 +0100, Sven Peter wrote:
> Add support for the watchdog timer found in Apple SoCs. This driver is
> also required to reboot these machines.
>
> Signed-off-by: Sven Peter <[email protected]>
> ---
> v1 -> v2:
> - set the default timeout to 30s and call watchdog_init_timeout
> to allow the device tree to override it
> - set WDOG_HW_RUNNING if the watchdog is enabled at boot
> - check that the clock rate is not zero
> - use unsigned long instead of u32 for clk_rate
> - use devm_add_action_or_reset instead of manually calling
> clk_disable_unprepare
> - explain the magic number in apple_wdt_restart
>
> MAINTAINERS | 1 +
> drivers/watchdog/Kconfig | 12 ++
> drivers/watchdog/Makefile | 1 +
> drivers/watchdog/apple_wdt.c | 226 +++++++++++++++++++++++++++++++++++
> 4 files changed, 240 insertions(+)
> create mode 100644 drivers/watchdog/apple_wdt.c

Tested on M1 and M1 Max. Feel free to add
Tested-by: Janne Grunau <[email protected]>

best
Janne

2021-12-02 06:44:36

by Hector Martin

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] watchdog: Add Apple SoC watchdog driver



On 2021年12月1日 1:18:09 JST, Sven Peter <[email protected]> wrote:
>Add support for the watchdog timer found in Apple SoCs. This driver is
>also required to reboot these machines.
>
>Signed-off-by: Sven Peter <[email protected]>
>---
>v1 -> v2:
> - set the default timeout to 30s and call watchdog_init_timeout
> to allow the device tree to override it
> - set WDOG_HW_RUNNING if the watchdog is enabled at boot
> - check that the clock rate is not zero
> - use unsigned long instead of u32 for clk_rate
> - use devm_add_action_or_reset instead of manually calling
> clk_disable_unprepare
> - explain the magic number in apple_wdt_restart
>
> MAINTAINERS | 1 +
> drivers/watchdog/Kconfig | 12 ++
> drivers/watchdog/Makefile | 1 +
> drivers/watchdog/apple_wdt.c | 226 +++++++++++++++++++++++++++++++++++
> 4 files changed, 240 insertions(+)
> create mode 100644 drivers/watchdog/apple_wdt.c
>
>diff --git a/MAINTAINERS b/MAINTAINERS
>index 859201bbd4e8..6190f0b40983 100644
>--- a/MAINTAINERS
>+++ b/MAINTAINERS
>@@ -1757,6 +1757,7 @@ F: drivers/i2c/busses/i2c-pasemi-platform.c
> F: drivers/irqchip/irq-apple-aic.c
> F: drivers/mailbox/apple-mailbox.c
> F: drivers/pinctrl/pinctrl-apple-gpio.c
>+F: drivers/watchdog/apple_wdt.c
> F: include/dt-bindings/interrupt-controller/apple-aic.h
> F: include/dt-bindings/pinctrl/apple.h
> F: include/linux/apple-mailbox.h
>diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
>index 9d222ba17ec6..170dec880c8f 100644
>--- a/drivers/watchdog/Kconfig
>+++ b/drivers/watchdog/Kconfig
>@@ -976,6 +976,18 @@ config MSC313E_WATCHDOG
> To compile this driver as a module, choose M here: the
> module will be called msc313e_wdt.
>
>+config APPLE_WATCHDOG
>+ tristate "Apple SoC watchdog"
>+ depends on ARCH_APPLE || COMPILE_TEST
>+ select WATCHDOG_CORE
>+ help
>+ Say Y here to include support for the Watchdog found in Apple
>+ SoCs such as the M1. Next to the common watchdog features this
>+ driver is also required in order to reboot these SoCs.
>+
>+ To compile this driver as a module, choose M here: the
>+ module will be called apple_wdt.
>+
> # X86 (i386 + ia64 + x86_64) Architecture
>
> config ACQUIRE_WDT
>diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
>index 2ee97064145b..270a518bd8f3 100644
>--- a/drivers/watchdog/Makefile
>+++ b/drivers/watchdog/Makefile
>@@ -93,6 +93,7 @@ obj-$(CONFIG_PM8916_WATCHDOG) += pm8916_wdt.o
> obj-$(CONFIG_ARM_SMC_WATCHDOG) += arm_smc_wdt.o
> obj-$(CONFIG_VISCONTI_WATCHDOG) += visconti_wdt.o
> obj-$(CONFIG_MSC313E_WATCHDOG) += msc313e_wdt.o
>+obj-$(CONFIG_APPLE_WATCHDOG) += apple_wdt.o
>
> # X86 (i386 + ia64 + x86_64) Architecture
> obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
>diff --git a/drivers/watchdog/apple_wdt.c b/drivers/watchdog/apple_wdt.c
>new file mode 100644
>index 000000000000..76e5bedd50d1
>--- /dev/null
>+++ b/drivers/watchdog/apple_wdt.c
>@@ -0,0 +1,226 @@
>+// SPDX-License-Identifier: GPL-2.0-only OR MIT
>+/*
>+ * Apple SoC Watchdog driver
>+ *
>+ * Copyright (C) The Asahi Linux Contributors
>+ */
>+
>+#include <linux/bits.h>
>+#include <linux/clk.h>
>+#include <linux/delay.h>
>+#include <linux/io.h>
>+#include <linux/kernel.h>
>+#include <linux/limits.h>
>+#include <linux/module.h>
>+#include <linux/of.h>
>+#include <linux/platform_device.h>
>+#include <linux/watchdog.h>
>+
>+/*
>+ * Apple Watchdog MMIO registers
>+ *
>+ * This HW block has three separate watchdogs. WD0 resets the machine
>+ * to recovery mode and is not very useful for us. WD1 and WD2 trigger a normal
>+ * machine reset. WD0 additionally supports a configurable interrupt.
>+ * This information can be used to implement pretimeout support at a later time.
>+ *
>+ * APPLE_WDT_WDx_CUR_TIME is a simple counter incremented for each tick of the
>+ * reference clock. It can also be overwritten to any value.
>+ * Whenever APPLE_WDT_CTRL_RESET_EN is set in APPLE_WDT_WDx_CTRL and
>+ * APPLE_WDTx_WD1_CUR_TIME >= APPLE_WDTx_WD1_BITE_TIME the entire machine is
>+ * reset.
>+ * Whenever APPLE_WDT_CTRL_IRQ_EN is set and APPLE_WDTx_WD1_CUR_TIME >=
>+ * APPLE_WDTx_WD1_BARK_TIME an interrupt is triggered and
>+ * APPLE_WDT_CTRL_IRQ_STATUS is set. The interrupt can be cleared by writing
>+ * 1 to APPLE_WDT_CTRL_IRQ_STATUS.
>+ */
>+#define APPLE_WDT_WD0_CUR_TIME 0x00
>+#define APPLE_WDT_WD0_BITE_TIME 0x04
>+#define APPLE_WDT_WD0_BARK_TIME 0x08
>+#define APPLE_WDT_WD0_CTRL 0x0c
>+
>+#define APPLE_WDT_WD1_CUR_TIME 0x10
>+#define APPLE_WDT_WD1_BITE_TIME 0x14
>+#define APPLE_WDT_WD1_CTRL 0x1c
>+
>+#define APPLE_WDT_WD2_CUR_TIME 0x20
>+#define APPLE_WDT_WD2_BITE_TIME 0x24
>+#define APPLE_WDT_WD2_CTRL 0x2c
>+
>+#define APPLE_WDT_CTRL_IRQ_EN BIT(0)
>+#define APPLE_WDT_CTRL_IRQ_STATUS BIT(1)
>+#define APPLE_WDT_CTRL_RESET_EN BIT(2)
>+
>+#define APPLE_WDT_TIMEOUT_DEFAULT 30
>+
>+struct apple_wdt {
>+ struct watchdog_device wdd;
>+ void __iomem *regs;
>+ unsigned long clk_rate;
>+};
>+
>+static struct apple_wdt *to_apple_wdt(struct watchdog_device *wdd)
>+{
>+ return container_of(wdd, struct apple_wdt, wdd);
>+}
>+
>+static int apple_wdt_start(struct watchdog_device *wdd)
>+{
>+ struct apple_wdt *wdt = to_apple_wdt(wdd);
>+
>+ writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CUR_TIME);
>+ writel_relaxed(APPLE_WDT_CTRL_RESET_EN, wdt->regs + APPLE_WDT_WD1_CTRL);
>+
>+ return 0;
>+}
>+
>+static int apple_wdt_stop(struct watchdog_device *wdd)
>+{
>+ struct apple_wdt *wdt = to_apple_wdt(wdd);
>+
>+ writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CTRL);
>+
>+ return 0;
>+}
>+
>+static int apple_wdt_ping(struct watchdog_device *wdd)
>+{
>+ struct apple_wdt *wdt = to_apple_wdt(wdd);
>+
>+ writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CUR_TIME);
>+
>+ return 0;
>+}
>+
>+static int apple_wdt_set_timeout(struct watchdog_device *wdd, unsigned int s)
>+{
>+ struct apple_wdt *wdt = to_apple_wdt(wdd);
>+
>+ writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CUR_TIME);
>+ writel_relaxed(wdt->clk_rate * s, wdt->regs + APPLE_WDT_WD1_BITE_TIME);
>+
>+ wdd->timeout = s;
>+
>+ return 0;
>+}
>+
>+static unsigned int apple_wdt_get_timeleft(struct watchdog_device *wdd)
>+{
>+ struct apple_wdt *wdt = to_apple_wdt(wdd);
>+ u32 cur_time, reset_time;
>+
>+ cur_time = readl_relaxed(wdt->regs + APPLE_WDT_WD1_CUR_TIME);
>+ reset_time = readl_relaxed(wdt->regs + APPLE_WDT_WD1_BITE_TIME);
>+
>+ return (reset_time - cur_time) / wdt->clk_rate;
>+}
>+
>+static int apple_wdt_restart(struct watchdog_device *wdd, unsigned long mode,
>+ void *cmd)
>+{
>+ struct apple_wdt *wdt = to_apple_wdt(wdd);
>+
>+ writel_relaxed(APPLE_WDT_CTRL_RESET_EN, wdt->regs + APPLE_WDT_WD1_CTRL);
>+ writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_BITE_TIME);
>+ writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CUR_TIME);
>+
>+ /*
>+ * Flush writes and then wait for the SoC to reset. Even though the
>+ * reset is queued almost immediately experiments have shown that it
>+ * can take up to ~20-25ms until the SoC is actually reset. Just wait
>+ * 50ms here to be safe.
>+ */
>+ (void)readl_relaxed(wdt->regs + APPLE_WDT_WD1_CUR_TIME);
>+ mdelay(50);
>+
>+ return 0;
>+}
>+
>+static void apple_wdt_clk_disable_unprepare(void *data)
>+{
>+ clk_disable_unprepare(data);
>+}
>+
>+static struct watchdog_ops apple_wdt_ops = {
>+ .owner = THIS_MODULE,
>+ .start = apple_wdt_start,
>+ .stop = apple_wdt_stop,
>+ .ping = apple_wdt_ping,
>+ .set_timeout = apple_wdt_set_timeout,
>+ .get_timeleft = apple_wdt_get_timeleft,
>+ .restart = apple_wdt_restart,
>+};
>+
>+static struct watchdog_info apple_wdt_info = {
>+ .identity = "Apple SoC Watchdog",
>+ .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
>+};
>+
>+static int apple_wdt_probe(struct platform_device *pdev)
>+{
>+ struct device *dev = &pdev->dev;
>+ struct apple_wdt *wdt;
>+ struct clk *clk;
>+ u32 wdt_ctrl;
>+ int ret;
>+
>+ wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
>+ if (!wdt)
>+ return -ENOMEM;
>+
>+ wdt->regs = devm_platform_ioremap_resource(pdev, 0);
>+ if (IS_ERR(wdt->regs))
>+ return PTR_ERR(wdt->regs);
>+
>+ clk = devm_clk_get(dev, NULL);
>+ if (IS_ERR(clk))
>+ return PTR_ERR(clk);
>+
>+ ret = clk_prepare_enable(clk);
>+ if (ret)
>+ return ret;
>+
>+ ret = devm_add_action_or_reset(dev, apple_wdt_clk_disable_unprepare,
>+ clk);
>+ if (ret)
>+ return ret;
>+
>+ wdt->clk_rate = clk_get_rate(clk);
>+ if (!wdt->clk_rate)
>+ return -EINVAL;
>+
>+ wdt->wdd.ops = &apple_wdt_ops;
>+ wdt->wdd.info = &apple_wdt_info;
>+ wdt->wdd.max_timeout = U32_MAX / wdt->clk_rate;
>+ wdt->wdd.timeout = APPLE_WDT_TIMEOUT_DEFAULT;
>+
>+ wdt_ctrl = readl_relaxed(wdt->regs + APPLE_WDT_WD1_CTRL);
>+ if (wdt_ctrl & APPLE_WDT_CTRL_RESET_EN)
>+ set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
>+
>+ watchdog_init_timeout(&wdt->wdd, 0, dev);
>+ apple_wdt_set_timeout(&wdt->wdd, wdt->wdd.timeout);
>+ watchdog_stop_on_unregister(&wdt->wdd);
>+ watchdog_set_restart_priority(&wdt->wdd, 128);
>+
>+ return devm_watchdog_register_device(dev, &wdt->wdd);
>+}
>+
>+static const struct of_device_id apple_wdt_of_match[] = {
>+ { .compatible = "apple,wdt" },
>+ {},
>+};
>+MODULE_DEVICE_TABLE(of, apple_wdt_of_match);
>+
>+static struct platform_driver apple_wdt_driver = {
>+ .driver = {
>+ .name = "apple-watchdog",
>+ .of_match_table = apple_wdt_of_match,
>+ },
>+ .probe = apple_wdt_probe,
>+};
>+module_platform_driver(apple_wdt_driver);
>+
>+MODULE_DESCRIPTION("Apple SoC watchdog driver");
>+MODULE_AUTHOR("Sven Peter <[email protected]>");
>+MODULE_LICENSE("Dual MIT/GPL");

Reviewed-by: Hector Martin <[email protected]>

Thanks, looks good! Any chance you can do a quick v3 with the MAINTAINERS changes split off? As usual, I'd rather make life easier for people merging upstream :)

--
Hector Martin "marcan" ([email protected])
Public key: https://mrcn.st/pub

2021-12-02 12:38:15

by Hector Martin

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] watchdog: Add Apple SoC watchdog driver

On 01/12/2021 01.18, Sven Peter wrote:
> Add support for the watchdog timer found in Apple SoCs. This driver is
> also required to reboot these machines.
>
> Signed-off-by: Sven Peter <[email protected]>
> ---
<snip>

Tested on j274 and j314s. Feel free to add:

Tested-by: Hector Martin <[email protected]>

--
Hector Martin ([email protected])
Public Key: https://mrcn.st/pub

2021-12-02 14:37:08

by Guenter Roeck

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] watchdog: Add Apple SoC watchdog driver

On 12/1/21 10:44 PM, Hector Martin "marcan" wrote:
>
>
> On 2021年12月1日 1:18:09 JST, Sven Peter <[email protected]> wrote:
>> Add support for the watchdog timer found in Apple SoCs. This driver is
>> also required to reboot these machines.
>>
>> Signed-off-by: Sven Peter <[email protected]>
>> ---
>> v1 -> v2:
>> - set the default timeout to 30s and call watchdog_init_timeout
>> to allow the device tree to override it
>> - set WDOG_HW_RUNNING if the watchdog is enabled at boot
>> - check that the clock rate is not zero
>> - use unsigned long instead of u32 for clk_rate
>> - use devm_add_action_or_reset instead of manually calling
>> clk_disable_unprepare
>> - explain the magic number in apple_wdt_restart
>>
>> MAINTAINERS | 1 +
>> drivers/watchdog/Kconfig | 12 ++
>> drivers/watchdog/Makefile | 1 +
>> drivers/watchdog/apple_wdt.c | 226 +++++++++++++++++++++++++++++++++++
>> 4 files changed, 240 insertions(+)
>> create mode 100644 drivers/watchdog/apple_wdt.c
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 859201bbd4e8..6190f0b40983 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -1757,6 +1757,7 @@ F: drivers/i2c/busses/i2c-pasemi-platform.c
>> F: drivers/irqchip/irq-apple-aic.c
>> F: drivers/mailbox/apple-mailbox.c
>> F: drivers/pinctrl/pinctrl-apple-gpio.c
>> +F: drivers/watchdog/apple_wdt.c
>> F: include/dt-bindings/interrupt-controller/apple-aic.h
>> F: include/dt-bindings/pinctrl/apple.h
>> F: include/linux/apple-mailbox.h
>> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
>> index 9d222ba17ec6..170dec880c8f 100644
>> --- a/drivers/watchdog/Kconfig
>> +++ b/drivers/watchdog/Kconfig
>> @@ -976,6 +976,18 @@ config MSC313E_WATCHDOG
>> To compile this driver as a module, choose M here: the
>> module will be called msc313e_wdt.
>>
>> +config APPLE_WATCHDOG
>> + tristate "Apple SoC watchdog"
>> + depends on ARCH_APPLE || COMPILE_TEST
>> + select WATCHDOG_CORE
>> + help
>> + Say Y here to include support for the Watchdog found in Apple
>> + SoCs such as the M1. Next to the common watchdog features this
>> + driver is also required in order to reboot these SoCs.
>> +
>> + To compile this driver as a module, choose M here: the
>> + module will be called apple_wdt.
>> +
>> # X86 (i386 + ia64 + x86_64) Architecture
>>
>> config ACQUIRE_WDT
>> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
>> index 2ee97064145b..270a518bd8f3 100644
>> --- a/drivers/watchdog/Makefile
>> +++ b/drivers/watchdog/Makefile
>> @@ -93,6 +93,7 @@ obj-$(CONFIG_PM8916_WATCHDOG) += pm8916_wdt.o
>> obj-$(CONFIG_ARM_SMC_WATCHDOG) += arm_smc_wdt.o
>> obj-$(CONFIG_VISCONTI_WATCHDOG) += visconti_wdt.o
>> obj-$(CONFIG_MSC313E_WATCHDOG) += msc313e_wdt.o
>> +obj-$(CONFIG_APPLE_WATCHDOG) += apple_wdt.o
>>
>> # X86 (i386 + ia64 + x86_64) Architecture
>> obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
>> diff --git a/drivers/watchdog/apple_wdt.c b/drivers/watchdog/apple_wdt.c
>> new file mode 100644
>> index 000000000000..76e5bedd50d1
>> --- /dev/null
>> +++ b/drivers/watchdog/apple_wdt.c
>> @@ -0,0 +1,226 @@
>> +// SPDX-License-Identifier: GPL-2.0-only OR MIT
>> +/*
>> + * Apple SoC Watchdog driver
>> + *
>> + * Copyright (C) The Asahi Linux Contributors
>> + */
>> +
>> +#include <linux/bits.h>
>> +#include <linux/clk.h>
>> +#include <linux/delay.h>
>> +#include <linux/io.h>
>> +#include <linux/kernel.h>
>> +#include <linux/limits.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/watchdog.h>
>> +
>> +/*
>> + * Apple Watchdog MMIO registers
>> + *
>> + * This HW block has three separate watchdogs. WD0 resets the machine
>> + * to recovery mode and is not very useful for us. WD1 and WD2 trigger a normal
>> + * machine reset. WD0 additionally supports a configurable interrupt.
>> + * This information can be used to implement pretimeout support at a later time.
>> + *
>> + * APPLE_WDT_WDx_CUR_TIME is a simple counter incremented for each tick of the
>> + * reference clock. It can also be overwritten to any value.
>> + * Whenever APPLE_WDT_CTRL_RESET_EN is set in APPLE_WDT_WDx_CTRL and
>> + * APPLE_WDTx_WD1_CUR_TIME >= APPLE_WDTx_WD1_BITE_TIME the entire machine is
>> + * reset.
>> + * Whenever APPLE_WDT_CTRL_IRQ_EN is set and APPLE_WDTx_WD1_CUR_TIME >=
>> + * APPLE_WDTx_WD1_BARK_TIME an interrupt is triggered and
>> + * APPLE_WDT_CTRL_IRQ_STATUS is set. The interrupt can be cleared by writing
>> + * 1 to APPLE_WDT_CTRL_IRQ_STATUS.
>> + */
>> +#define APPLE_WDT_WD0_CUR_TIME 0x00
>> +#define APPLE_WDT_WD0_BITE_TIME 0x04
>> +#define APPLE_WDT_WD0_BARK_TIME 0x08
>> +#define APPLE_WDT_WD0_CTRL 0x0c
>> +
>> +#define APPLE_WDT_WD1_CUR_TIME 0x10
>> +#define APPLE_WDT_WD1_BITE_TIME 0x14
>> +#define APPLE_WDT_WD1_CTRL 0x1c
>> +
>> +#define APPLE_WDT_WD2_CUR_TIME 0x20
>> +#define APPLE_WDT_WD2_BITE_TIME 0x24
>> +#define APPLE_WDT_WD2_CTRL 0x2c
>> +
>> +#define APPLE_WDT_CTRL_IRQ_EN BIT(0)
>> +#define APPLE_WDT_CTRL_IRQ_STATUS BIT(1)
>> +#define APPLE_WDT_CTRL_RESET_EN BIT(2)
>> +
>> +#define APPLE_WDT_TIMEOUT_DEFAULT 30
>> +
>> +struct apple_wdt {
>> + struct watchdog_device wdd;
>> + void __iomem *regs;
>> + unsigned long clk_rate;
>> +};
>> +
>> +static struct apple_wdt *to_apple_wdt(struct watchdog_device *wdd)
>> +{
>> + return container_of(wdd, struct apple_wdt, wdd);
>> +}
>> +
>> +static int apple_wdt_start(struct watchdog_device *wdd)
>> +{
>> + struct apple_wdt *wdt = to_apple_wdt(wdd);
>> +
>> + writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CUR_TIME);
>> + writel_relaxed(APPLE_WDT_CTRL_RESET_EN, wdt->regs + APPLE_WDT_WD1_CTRL);
>> +
>> + return 0;
>> +}
>> +
>> +static int apple_wdt_stop(struct watchdog_device *wdd)
>> +{
>> + struct apple_wdt *wdt = to_apple_wdt(wdd);
>> +
>> + writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CTRL);
>> +
>> + return 0;
>> +}
>> +
>> +static int apple_wdt_ping(struct watchdog_device *wdd)
>> +{
>> + struct apple_wdt *wdt = to_apple_wdt(wdd);
>> +
>> + writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CUR_TIME);
>> +
>> + return 0;
>> +}
>> +
>> +static int apple_wdt_set_timeout(struct watchdog_device *wdd, unsigned int s)
>> +{
>> + struct apple_wdt *wdt = to_apple_wdt(wdd);
>> +
>> + writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CUR_TIME);
>> + writel_relaxed(wdt->clk_rate * s, wdt->regs + APPLE_WDT_WD1_BITE_TIME);
>> +
>> + wdd->timeout = s;
>> +
>> + return 0;
>> +}
>> +
>> +static unsigned int apple_wdt_get_timeleft(struct watchdog_device *wdd)
>> +{
>> + struct apple_wdt *wdt = to_apple_wdt(wdd);
>> + u32 cur_time, reset_time;
>> +
>> + cur_time = readl_relaxed(wdt->regs + APPLE_WDT_WD1_CUR_TIME);
>> + reset_time = readl_relaxed(wdt->regs + APPLE_WDT_WD1_BITE_TIME);
>> +
>> + return (reset_time - cur_time) / wdt->clk_rate;
>> +}
>> +
>> +static int apple_wdt_restart(struct watchdog_device *wdd, unsigned long mode,
>> + void *cmd)
>> +{
>> + struct apple_wdt *wdt = to_apple_wdt(wdd);
>> +
>> + writel_relaxed(APPLE_WDT_CTRL_RESET_EN, wdt->regs + APPLE_WDT_WD1_CTRL);
>> + writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_BITE_TIME);
>> + writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CUR_TIME);
>> +
>> + /*
>> + * Flush writes and then wait for the SoC to reset. Even though the
>> + * reset is queued almost immediately experiments have shown that it
>> + * can take up to ~20-25ms until the SoC is actually reset. Just wait
>> + * 50ms here to be safe.
>> + */
>> + (void)readl_relaxed(wdt->regs + APPLE_WDT_WD1_CUR_TIME);
>> + mdelay(50);
>> +
>> + return 0;
>> +}
>> +
>> +static void apple_wdt_clk_disable_unprepare(void *data)
>> +{
>> + clk_disable_unprepare(data);
>> +}
>> +
>> +static struct watchdog_ops apple_wdt_ops = {
>> + .owner = THIS_MODULE,
>> + .start = apple_wdt_start,
>> + .stop = apple_wdt_stop,
>> + .ping = apple_wdt_ping,
>> + .set_timeout = apple_wdt_set_timeout,
>> + .get_timeleft = apple_wdt_get_timeleft,
>> + .restart = apple_wdt_restart,
>> +};
>> +
>> +static struct watchdog_info apple_wdt_info = {
>> + .identity = "Apple SoC Watchdog",
>> + .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
>> +};
>> +
>> +static int apple_wdt_probe(struct platform_device *pdev)
>> +{
>> + struct device *dev = &pdev->dev;
>> + struct apple_wdt *wdt;
>> + struct clk *clk;
>> + u32 wdt_ctrl;
>> + int ret;
>> +
>> + wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
>> + if (!wdt)
>> + return -ENOMEM;
>> +
>> + wdt->regs = devm_platform_ioremap_resource(pdev, 0);
>> + if (IS_ERR(wdt->regs))
>> + return PTR_ERR(wdt->regs);
>> +
>> + clk = devm_clk_get(dev, NULL);
>> + if (IS_ERR(clk))
>> + return PTR_ERR(clk);
>> +
>> + ret = clk_prepare_enable(clk);
>> + if (ret)
>> + return ret;
>> +
>> + ret = devm_add_action_or_reset(dev, apple_wdt_clk_disable_unprepare,
>> + clk);
>> + if (ret)
>> + return ret;
>> +
>> + wdt->clk_rate = clk_get_rate(clk);
>> + if (!wdt->clk_rate)
>> + return -EINVAL;
>> +
>> + wdt->wdd.ops = &apple_wdt_ops;
>> + wdt->wdd.info = &apple_wdt_info;
>> + wdt->wdd.max_timeout = U32_MAX / wdt->clk_rate;
>> + wdt->wdd.timeout = APPLE_WDT_TIMEOUT_DEFAULT;
>> +
>> + wdt_ctrl = readl_relaxed(wdt->regs + APPLE_WDT_WD1_CTRL);
>> + if (wdt_ctrl & APPLE_WDT_CTRL_RESET_EN)
>> + set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
>> +
>> + watchdog_init_timeout(&wdt->wdd, 0, dev);
>> + apple_wdt_set_timeout(&wdt->wdd, wdt->wdd.timeout);
>> + watchdog_stop_on_unregister(&wdt->wdd);
>> + watchdog_set_restart_priority(&wdt->wdd, 128);
>> +
>> + return devm_watchdog_register_device(dev, &wdt->wdd);
>> +}
>> +
>> +static const struct of_device_id apple_wdt_of_match[] = {
>> + { .compatible = "apple,wdt" },
>> + {},
>> +};
>> +MODULE_DEVICE_TABLE(of, apple_wdt_of_match);
>> +
>> +static struct platform_driver apple_wdt_driver = {
>> + .driver = {
>> + .name = "apple-watchdog",
>> + .of_match_table = apple_wdt_of_match,
>> + },
>> + .probe = apple_wdt_probe,
>> +};
>> +module_platform_driver(apple_wdt_driver);
>> +
>> +MODULE_DESCRIPTION("Apple SoC watchdog driver");
>> +MODULE_AUTHOR("Sven Peter <[email protected]>");
>> +MODULE_LICENSE("Dual MIT/GPL");
>
> Reviewed-by: Hector Martin <[email protected]>
>
> Thanks, looks good! Any chance you can do a quick v3 with the MAINTAINERS changes split off? As usual, I'd rather make life easier for people merging upstream :)
>

Usually I don't ask for such a split, and I don't recall that being an issue.
So, from my perspective, that is not necessary.

Guenter

2021-12-02 14:43:31

by Guenter Roeck

[permalink] [raw]
Subject: Re: [PATCH v2 1/2] dt-bindings: watchdog: Add Apple Watchdog

On Tue, Nov 30, 2021 at 05:18:08PM +0100, Sven Peter wrote:
> Apple SoCs come with a simple embedded watchdog. This watchdog is also
> required in order to reset the SoC.
>
> Reviewed-by: Mark Kettenis <[email protected]>
> Reviewed-by: Rob Herring <[email protected]>
> Signed-off-by: Sven Peter <[email protected]>

Reviewed-by: Guenter Roeck <[email protected]>

> ---
> v1 --> v2:
> - add Mark's and Rob's r-b tags
>
> .../bindings/watchdog/apple,wdt.yaml | 52 +++++++++++++++++++
> MAINTAINERS | 1 +
> 2 files changed, 53 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/watchdog/apple,wdt.yaml
>
> diff --git a/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml b/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml
> new file mode 100644
> index 000000000000..e58c56a6fdf6
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml
> @@ -0,0 +1,52 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/watchdog/apple,wdt.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Apple SoC Watchdog
> +
> +allOf:
> + - $ref: "watchdog.yaml#"
> +
> +maintainers:
> + - Sven Peter <[email protected]>
> +
> +properties:
> + compatible:
> + items:
> + - enum:
> + - apple,t8103-wdt
> + - apple,t6000-wdt
> + - const: apple,wdt
> +
> + reg:
> + maxItems: 1
> +
> + clocks:
> + maxItems: 1
> +
> + interrupts:
> + maxItems: 1
> +
> +required:
> + - compatible
> + - reg
> + - clocks
> + - interrupts
> +
> +unevaluatedProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/interrupt-controller/apple-aic.h>
> + #include <dt-bindings/interrupt-controller/irq.h>
> +
> + wdt: watchdog@50000000 {
> + compatible = "apple,t8103-wdt", "apple,wdt";
> + reg = <0x50000000 0x4000>;
> + clocks = <&clk>;
> + interrupts = <AIC_IRQ 123 IRQ_TYPE_LEVEL_HIGH>;
> + };
> +
> +...
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 360e9aa0205d..859201bbd4e8 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1750,6 +1750,7 @@ F: Documentation/devicetree/bindings/interrupt-controller/apple,aic.yaml
> F: Documentation/devicetree/bindings/mailbox/apple,mailbox.yaml
> F: Documentation/devicetree/bindings/pci/apple,pcie.yaml
> F: Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml
> +F: Documentation/devicetree/bindings/watchdog/apple,wdt.yaml
> F: arch/arm64/boot/dts/apple/
> F: drivers/i2c/busses/i2c-pasemi-core.c
> F: drivers/i2c/busses/i2c-pasemi-platform.c
> --
> 2.25.1
>

2021-12-02 14:44:06

by Guenter Roeck

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] watchdog: Add Apple SoC watchdog driver

On Tue, Nov 30, 2021 at 05:18:09PM +0100, Sven Peter wrote:
> Add support for the watchdog timer found in Apple SoCs. This driver is
> also required to reboot these machines.
>
> Signed-off-by: Sven Peter <[email protected]>

Reviewed-by: Guenter Roeck <[email protected]>

> ---
> v1 -> v2:
> - set the default timeout to 30s and call watchdog_init_timeout
> to allow the device tree to override it
> - set WDOG_HW_RUNNING if the watchdog is enabled at boot
> - check that the clock rate is not zero
> - use unsigned long instead of u32 for clk_rate
> - use devm_add_action_or_reset instead of manually calling
> clk_disable_unprepare
> - explain the magic number in apple_wdt_restart
>
> MAINTAINERS | 1 +
> drivers/watchdog/Kconfig | 12 ++
> drivers/watchdog/Makefile | 1 +
> drivers/watchdog/apple_wdt.c | 226 +++++++++++++++++++++++++++++++++++
> 4 files changed, 240 insertions(+)
> create mode 100644 drivers/watchdog/apple_wdt.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 859201bbd4e8..6190f0b40983 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1757,6 +1757,7 @@ F: drivers/i2c/busses/i2c-pasemi-platform.c
> F: drivers/irqchip/irq-apple-aic.c
> F: drivers/mailbox/apple-mailbox.c
> F: drivers/pinctrl/pinctrl-apple-gpio.c
> +F: drivers/watchdog/apple_wdt.c
> F: include/dt-bindings/interrupt-controller/apple-aic.h
> F: include/dt-bindings/pinctrl/apple.h
> F: include/linux/apple-mailbox.h
> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> index 9d222ba17ec6..170dec880c8f 100644
> --- a/drivers/watchdog/Kconfig
> +++ b/drivers/watchdog/Kconfig
> @@ -976,6 +976,18 @@ config MSC313E_WATCHDOG
> To compile this driver as a module, choose M here: the
> module will be called msc313e_wdt.
>
> +config APPLE_WATCHDOG
> + tristate "Apple SoC watchdog"
> + depends on ARCH_APPLE || COMPILE_TEST
> + select WATCHDOG_CORE
> + help
> + Say Y here to include support for the Watchdog found in Apple
> + SoCs such as the M1. Next to the common watchdog features this
> + driver is also required in order to reboot these SoCs.
> +
> + To compile this driver as a module, choose M here: the
> + module will be called apple_wdt.
> +
> # X86 (i386 + ia64 + x86_64) Architecture
>
> config ACQUIRE_WDT
> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
> index 2ee97064145b..270a518bd8f3 100644
> --- a/drivers/watchdog/Makefile
> +++ b/drivers/watchdog/Makefile
> @@ -93,6 +93,7 @@ obj-$(CONFIG_PM8916_WATCHDOG) += pm8916_wdt.o
> obj-$(CONFIG_ARM_SMC_WATCHDOG) += arm_smc_wdt.o
> obj-$(CONFIG_VISCONTI_WATCHDOG) += visconti_wdt.o
> obj-$(CONFIG_MSC313E_WATCHDOG) += msc313e_wdt.o
> +obj-$(CONFIG_APPLE_WATCHDOG) += apple_wdt.o
>
> # X86 (i386 + ia64 + x86_64) Architecture
> obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
> diff --git a/drivers/watchdog/apple_wdt.c b/drivers/watchdog/apple_wdt.c
> new file mode 100644
> index 000000000000..76e5bedd50d1
> --- /dev/null
> +++ b/drivers/watchdog/apple_wdt.c
> @@ -0,0 +1,226 @@
> +// SPDX-License-Identifier: GPL-2.0-only OR MIT
> +/*
> + * Apple SoC Watchdog driver
> + *
> + * Copyright (C) The Asahi Linux Contributors
> + */
> +
> +#include <linux/bits.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/limits.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/watchdog.h>
> +
> +/*
> + * Apple Watchdog MMIO registers
> + *
> + * This HW block has three separate watchdogs. WD0 resets the machine
> + * to recovery mode and is not very useful for us. WD1 and WD2 trigger a normal
> + * machine reset. WD0 additionally supports a configurable interrupt.
> + * This information can be used to implement pretimeout support at a later time.
> + *
> + * APPLE_WDT_WDx_CUR_TIME is a simple counter incremented for each tick of the
> + * reference clock. It can also be overwritten to any value.
> + * Whenever APPLE_WDT_CTRL_RESET_EN is set in APPLE_WDT_WDx_CTRL and
> + * APPLE_WDTx_WD1_CUR_TIME >= APPLE_WDTx_WD1_BITE_TIME the entire machine is
> + * reset.
> + * Whenever APPLE_WDT_CTRL_IRQ_EN is set and APPLE_WDTx_WD1_CUR_TIME >=
> + * APPLE_WDTx_WD1_BARK_TIME an interrupt is triggered and
> + * APPLE_WDT_CTRL_IRQ_STATUS is set. The interrupt can be cleared by writing
> + * 1 to APPLE_WDT_CTRL_IRQ_STATUS.
> + */
> +#define APPLE_WDT_WD0_CUR_TIME 0x00
> +#define APPLE_WDT_WD0_BITE_TIME 0x04
> +#define APPLE_WDT_WD0_BARK_TIME 0x08
> +#define APPLE_WDT_WD0_CTRL 0x0c
> +
> +#define APPLE_WDT_WD1_CUR_TIME 0x10
> +#define APPLE_WDT_WD1_BITE_TIME 0x14
> +#define APPLE_WDT_WD1_CTRL 0x1c
> +
> +#define APPLE_WDT_WD2_CUR_TIME 0x20
> +#define APPLE_WDT_WD2_BITE_TIME 0x24
> +#define APPLE_WDT_WD2_CTRL 0x2c
> +
> +#define APPLE_WDT_CTRL_IRQ_EN BIT(0)
> +#define APPLE_WDT_CTRL_IRQ_STATUS BIT(1)
> +#define APPLE_WDT_CTRL_RESET_EN BIT(2)
> +
> +#define APPLE_WDT_TIMEOUT_DEFAULT 30
> +
> +struct apple_wdt {
> + struct watchdog_device wdd;
> + void __iomem *regs;
> + unsigned long clk_rate;
> +};
> +
> +static struct apple_wdt *to_apple_wdt(struct watchdog_device *wdd)
> +{
> + return container_of(wdd, struct apple_wdt, wdd);
> +}
> +
> +static int apple_wdt_start(struct watchdog_device *wdd)
> +{
> + struct apple_wdt *wdt = to_apple_wdt(wdd);
> +
> + writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CUR_TIME);
> + writel_relaxed(APPLE_WDT_CTRL_RESET_EN, wdt->regs + APPLE_WDT_WD1_CTRL);
> +
> + return 0;
> +}
> +
> +static int apple_wdt_stop(struct watchdog_device *wdd)
> +{
> + struct apple_wdt *wdt = to_apple_wdt(wdd);
> +
> + writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CTRL);
> +
> + return 0;
> +}
> +
> +static int apple_wdt_ping(struct watchdog_device *wdd)
> +{
> + struct apple_wdt *wdt = to_apple_wdt(wdd);
> +
> + writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CUR_TIME);
> +
> + return 0;
> +}
> +
> +static int apple_wdt_set_timeout(struct watchdog_device *wdd, unsigned int s)
> +{
> + struct apple_wdt *wdt = to_apple_wdt(wdd);
> +
> + writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CUR_TIME);
> + writel_relaxed(wdt->clk_rate * s, wdt->regs + APPLE_WDT_WD1_BITE_TIME);
> +
> + wdd->timeout = s;
> +
> + return 0;
> +}
> +
> +static unsigned int apple_wdt_get_timeleft(struct watchdog_device *wdd)
> +{
> + struct apple_wdt *wdt = to_apple_wdt(wdd);
> + u32 cur_time, reset_time;
> +
> + cur_time = readl_relaxed(wdt->regs + APPLE_WDT_WD1_CUR_TIME);
> + reset_time = readl_relaxed(wdt->regs + APPLE_WDT_WD1_BITE_TIME);
> +
> + return (reset_time - cur_time) / wdt->clk_rate;
> +}
> +
> +static int apple_wdt_restart(struct watchdog_device *wdd, unsigned long mode,
> + void *cmd)
> +{
> + struct apple_wdt *wdt = to_apple_wdt(wdd);
> +
> + writel_relaxed(APPLE_WDT_CTRL_RESET_EN, wdt->regs + APPLE_WDT_WD1_CTRL);
> + writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_BITE_TIME);
> + writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CUR_TIME);
> +
> + /*
> + * Flush writes and then wait for the SoC to reset. Even though the
> + * reset is queued almost immediately experiments have shown that it
> + * can take up to ~20-25ms until the SoC is actually reset. Just wait
> + * 50ms here to be safe.
> + */
> + (void)readl_relaxed(wdt->regs + APPLE_WDT_WD1_CUR_TIME);
> + mdelay(50);
> +
> + return 0;
> +}
> +
> +static void apple_wdt_clk_disable_unprepare(void *data)
> +{
> + clk_disable_unprepare(data);
> +}
> +
> +static struct watchdog_ops apple_wdt_ops = {
> + .owner = THIS_MODULE,
> + .start = apple_wdt_start,
> + .stop = apple_wdt_stop,
> + .ping = apple_wdt_ping,
> + .set_timeout = apple_wdt_set_timeout,
> + .get_timeleft = apple_wdt_get_timeleft,
> + .restart = apple_wdt_restart,
> +};
> +
> +static struct watchdog_info apple_wdt_info = {
> + .identity = "Apple SoC Watchdog",
> + .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
> +};
> +
> +static int apple_wdt_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct apple_wdt *wdt;
> + struct clk *clk;
> + u32 wdt_ctrl;
> + int ret;
> +
> + wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
> + if (!wdt)
> + return -ENOMEM;
> +
> + wdt->regs = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(wdt->regs))
> + return PTR_ERR(wdt->regs);
> +
> + clk = devm_clk_get(dev, NULL);
> + if (IS_ERR(clk))
> + return PTR_ERR(clk);
> +
> + ret = clk_prepare_enable(clk);
> + if (ret)
> + return ret;
> +
> + ret = devm_add_action_or_reset(dev, apple_wdt_clk_disable_unprepare,
> + clk);
> + if (ret)
> + return ret;
> +
> + wdt->clk_rate = clk_get_rate(clk);
> + if (!wdt->clk_rate)
> + return -EINVAL;
> +
> + wdt->wdd.ops = &apple_wdt_ops;
> + wdt->wdd.info = &apple_wdt_info;
> + wdt->wdd.max_timeout = U32_MAX / wdt->clk_rate;
> + wdt->wdd.timeout = APPLE_WDT_TIMEOUT_DEFAULT;
> +
> + wdt_ctrl = readl_relaxed(wdt->regs + APPLE_WDT_WD1_CTRL);
> + if (wdt_ctrl & APPLE_WDT_CTRL_RESET_EN)
> + set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
> +
> + watchdog_init_timeout(&wdt->wdd, 0, dev);
> + apple_wdt_set_timeout(&wdt->wdd, wdt->wdd.timeout);
> + watchdog_stop_on_unregister(&wdt->wdd);
> + watchdog_set_restart_priority(&wdt->wdd, 128);
> +
> + return devm_watchdog_register_device(dev, &wdt->wdd);
> +}
> +
> +static const struct of_device_id apple_wdt_of_match[] = {
> + { .compatible = "apple,wdt" },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, apple_wdt_of_match);
> +
> +static struct platform_driver apple_wdt_driver = {
> + .driver = {
> + .name = "apple-watchdog",
> + .of_match_table = apple_wdt_of_match,
> + },
> + .probe = apple_wdt_probe,
> +};
> +module_platform_driver(apple_wdt_driver);
> +
> +MODULE_DESCRIPTION("Apple SoC watchdog driver");
> +MODULE_AUTHOR("Sven Peter <[email protected]>");
> +MODULE_LICENSE("Dual MIT/GPL");
> --
> 2.25.1
>

2021-12-03 13:50:21

by Hector Martin

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] watchdog: Add Apple SoC watchdog driver

On 02/12/2021 23.36, Guenter Roeck wrote:
> On 12/1/21 10:44 PM, Hector Martin "marcan" wrote:
>>
>>
>> On 2021年12月1日 1:18:09 JST, Sven Peter <[email protected]> wrote:
>>> Add support for the watchdog timer found in Apple SoCs. This driver is
>>> also required to reboot these machines.
>>>
>>> Signed-off-by: Sven Peter <[email protected]>
>>> ---
>>> v1 -> v2:
>>> - set the default timeout to 30s and call watchdog_init_timeout
>>> to allow the device tree to override it
>>> - set WDOG_HW_RUNNING if the watchdog is enabled at boot
>>> - check that the clock rate is not zero
>>> - use unsigned long instead of u32 for clk_rate
>>> - use devm_add_action_or_reset instead of manually calling
>>> clk_disable_unprepare
>>> - explain the magic number in apple_wdt_restart
>>>
>>> MAINTAINERS | 1 +
>>> drivers/watchdog/Kconfig | 12 ++
>>> drivers/watchdog/Makefile | 1 +
>>> drivers/watchdog/apple_wdt.c | 226 +++++++++++++++++++++++++++++++++++
>>> 4 files changed, 240 insertions(+)
>>> create mode 100644 drivers/watchdog/apple_wdt.c
>>>
>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>> index 859201bbd4e8..6190f0b40983 100644
>>> --- a/MAINTAINERS
>>> +++ b/MAINTAINERS
>>> @@ -1757,6 +1757,7 @@ F: drivers/i2c/busses/i2c-pasemi-platform.c
>>> F: drivers/irqchip/irq-apple-aic.c
>>> F: drivers/mailbox/apple-mailbox.c
>>> F: drivers/pinctrl/pinctrl-apple-gpio.c
>>> +F: drivers/watchdog/apple_wdt.c
>>> F: include/dt-bindings/interrupt-controller/apple-aic.h
>>> F: include/dt-bindings/pinctrl/apple.h
>>> F: include/linux/apple-mailbox.h
>>> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
>>> index 9d222ba17ec6..170dec880c8f 100644
>>> --- a/drivers/watchdog/Kconfig
>>> +++ b/drivers/watchdog/Kconfig
>>> @@ -976,6 +976,18 @@ config MSC313E_WATCHDOG
>>> To compile this driver as a module, choose M here: the
>>> module will be called msc313e_wdt.
>>>
>>> +config APPLE_WATCHDOG
>>> + tristate "Apple SoC watchdog"
>>> + depends on ARCH_APPLE || COMPILE_TEST
>>> + select WATCHDOG_CORE
>>> + help
>>> + Say Y here to include support for the Watchdog found in Apple
>>> + SoCs such as the M1. Next to the common watchdog features this
>>> + driver is also required in order to reboot these SoCs.
>>> +
>>> + To compile this driver as a module, choose M here: the
>>> + module will be called apple_wdt.
>>> +
>>> # X86 (i386 + ia64 + x86_64) Architecture
>>>
>>> config ACQUIRE_WDT
>>> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
>>> index 2ee97064145b..270a518bd8f3 100644
>>> --- a/drivers/watchdog/Makefile
>>> +++ b/drivers/watchdog/Makefile
>>> @@ -93,6 +93,7 @@ obj-$(CONFIG_PM8916_WATCHDOG) += pm8916_wdt.o
>>> obj-$(CONFIG_ARM_SMC_WATCHDOG) += arm_smc_wdt.o
>>> obj-$(CONFIG_VISCONTI_WATCHDOG) += visconti_wdt.o
>>> obj-$(CONFIG_MSC313E_WATCHDOG) += msc313e_wdt.o
>>> +obj-$(CONFIG_APPLE_WATCHDOG) += apple_wdt.o
>>>
>>> # X86 (i386 + ia64 + x86_64) Architecture
>>> obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
>>> diff --git a/drivers/watchdog/apple_wdt.c b/drivers/watchdog/apple_wdt.c
>>> new file mode 100644
>>> index 000000000000..76e5bedd50d1
>>> --- /dev/null
>>> +++ b/drivers/watchdog/apple_wdt.c
>>> @@ -0,0 +1,226 @@
>>> +// SPDX-License-Identifier: GPL-2.0-only OR MIT
>>> +/*
>>> + * Apple SoC Watchdog driver
>>> + *
>>> + * Copyright (C) The Asahi Linux Contributors
>>> + */
>>> +
>>> +#include <linux/bits.h>
>>> +#include <linux/clk.h>
>>> +#include <linux/delay.h>
>>> +#include <linux/io.h>
>>> +#include <linux/kernel.h>
>>> +#include <linux/limits.h>
>>> +#include <linux/module.h>
>>> +#include <linux/of.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/watchdog.h>
>>> +
>>> +/*
>>> + * Apple Watchdog MMIO registers
>>> + *
>>> + * This HW block has three separate watchdogs. WD0 resets the machine
>>> + * to recovery mode and is not very useful for us. WD1 and WD2 trigger a normal
>>> + * machine reset. WD0 additionally supports a configurable interrupt.
>>> + * This information can be used to implement pretimeout support at a later time.
>>> + *
>>> + * APPLE_WDT_WDx_CUR_TIME is a simple counter incremented for each tick of the
>>> + * reference clock. It can also be overwritten to any value.
>>> + * Whenever APPLE_WDT_CTRL_RESET_EN is set in APPLE_WDT_WDx_CTRL and
>>> + * APPLE_WDTx_WD1_CUR_TIME >= APPLE_WDTx_WD1_BITE_TIME the entire machine is
>>> + * reset.
>>> + * Whenever APPLE_WDT_CTRL_IRQ_EN is set and APPLE_WDTx_WD1_CUR_TIME >=
>>> + * APPLE_WDTx_WD1_BARK_TIME an interrupt is triggered and
>>> + * APPLE_WDT_CTRL_IRQ_STATUS is set. The interrupt can be cleared by writing
>>> + * 1 to APPLE_WDT_CTRL_IRQ_STATUS.
>>> + */
>>> +#define APPLE_WDT_WD0_CUR_TIME 0x00
>>> +#define APPLE_WDT_WD0_BITE_TIME 0x04
>>> +#define APPLE_WDT_WD0_BARK_TIME 0x08
>>> +#define APPLE_WDT_WD0_CTRL 0x0c
>>> +
>>> +#define APPLE_WDT_WD1_CUR_TIME 0x10
>>> +#define APPLE_WDT_WD1_BITE_TIME 0x14
>>> +#define APPLE_WDT_WD1_CTRL 0x1c
>>> +
>>> +#define APPLE_WDT_WD2_CUR_TIME 0x20
>>> +#define APPLE_WDT_WD2_BITE_TIME 0x24
>>> +#define APPLE_WDT_WD2_CTRL 0x2c
>>> +
>>> +#define APPLE_WDT_CTRL_IRQ_EN BIT(0)
>>> +#define APPLE_WDT_CTRL_IRQ_STATUS BIT(1)
>>> +#define APPLE_WDT_CTRL_RESET_EN BIT(2)
>>> +
>>> +#define APPLE_WDT_TIMEOUT_DEFAULT 30
>>> +
>>> +struct apple_wdt {
>>> + struct watchdog_device wdd;
>>> + void __iomem *regs;
>>> + unsigned long clk_rate;
>>> +};
>>> +
>>> +static struct apple_wdt *to_apple_wdt(struct watchdog_device *wdd)
>>> +{
>>> + return container_of(wdd, struct apple_wdt, wdd);
>>> +}
>>> +
>>> +static int apple_wdt_start(struct watchdog_device *wdd)
>>> +{
>>> + struct apple_wdt *wdt = to_apple_wdt(wdd);
>>> +
>>> + writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CUR_TIME);
>>> + writel_relaxed(APPLE_WDT_CTRL_RESET_EN, wdt->regs + APPLE_WDT_WD1_CTRL);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int apple_wdt_stop(struct watchdog_device *wdd)
>>> +{
>>> + struct apple_wdt *wdt = to_apple_wdt(wdd);
>>> +
>>> + writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CTRL);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int apple_wdt_ping(struct watchdog_device *wdd)
>>> +{
>>> + struct apple_wdt *wdt = to_apple_wdt(wdd);
>>> +
>>> + writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CUR_TIME);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int apple_wdt_set_timeout(struct watchdog_device *wdd, unsigned int s)
>>> +{
>>> + struct apple_wdt *wdt = to_apple_wdt(wdd);
>>> +
>>> + writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CUR_TIME);
>>> + writel_relaxed(wdt->clk_rate * s, wdt->regs + APPLE_WDT_WD1_BITE_TIME);
>>> +
>>> + wdd->timeout = s;
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static unsigned int apple_wdt_get_timeleft(struct watchdog_device *wdd)
>>> +{
>>> + struct apple_wdt *wdt = to_apple_wdt(wdd);
>>> + u32 cur_time, reset_time;
>>> +
>>> + cur_time = readl_relaxed(wdt->regs + APPLE_WDT_WD1_CUR_TIME);
>>> + reset_time = readl_relaxed(wdt->regs + APPLE_WDT_WD1_BITE_TIME);
>>> +
>>> + return (reset_time - cur_time) / wdt->clk_rate;
>>> +}
>>> +
>>> +static int apple_wdt_restart(struct watchdog_device *wdd, unsigned long mode,
>>> + void *cmd)
>>> +{
>>> + struct apple_wdt *wdt = to_apple_wdt(wdd);
>>> +
>>> + writel_relaxed(APPLE_WDT_CTRL_RESET_EN, wdt->regs + APPLE_WDT_WD1_CTRL);
>>> + writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_BITE_TIME);
>>> + writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CUR_TIME);
>>> +
>>> + /*
>>> + * Flush writes and then wait for the SoC to reset. Even though the
>>> + * reset is queued almost immediately experiments have shown that it
>>> + * can take up to ~20-25ms until the SoC is actually reset. Just wait
>>> + * 50ms here to be safe.
>>> + */
>>> + (void)readl_relaxed(wdt->regs + APPLE_WDT_WD1_CUR_TIME);
>>> + mdelay(50);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static void apple_wdt_clk_disable_unprepare(void *data)
>>> +{
>>> + clk_disable_unprepare(data);
>>> +}
>>> +
>>> +static struct watchdog_ops apple_wdt_ops = {
>>> + .owner = THIS_MODULE,
>>> + .start = apple_wdt_start,
>>> + .stop = apple_wdt_stop,
>>> + .ping = apple_wdt_ping,
>>> + .set_timeout = apple_wdt_set_timeout,
>>> + .get_timeleft = apple_wdt_get_timeleft,
>>> + .restart = apple_wdt_restart,
>>> +};
>>> +
>>> +static struct watchdog_info apple_wdt_info = {
>>> + .identity = "Apple SoC Watchdog",
>>> + .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
>>> +};
>>> +
>>> +static int apple_wdt_probe(struct platform_device *pdev)
>>> +{
>>> + struct device *dev = &pdev->dev;
>>> + struct apple_wdt *wdt;
>>> + struct clk *clk;
>>> + u32 wdt_ctrl;
>>> + int ret;
>>> +
>>> + wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
>>> + if (!wdt)
>>> + return -ENOMEM;
>>> +
>>> + wdt->regs = devm_platform_ioremap_resource(pdev, 0);
>>> + if (IS_ERR(wdt->regs))
>>> + return PTR_ERR(wdt->regs);
>>> +
>>> + clk = devm_clk_get(dev, NULL);
>>> + if (IS_ERR(clk))
>>> + return PTR_ERR(clk);
>>> +
>>> + ret = clk_prepare_enable(clk);
>>> + if (ret)
>>> + return ret;
>>> +
>>> + ret = devm_add_action_or_reset(dev, apple_wdt_clk_disable_unprepare,
>>> + clk);
>>> + if (ret)
>>> + return ret;
>>> +
>>> + wdt->clk_rate = clk_get_rate(clk);
>>> + if (!wdt->clk_rate)
>>> + return -EINVAL;
>>> +
>>> + wdt->wdd.ops = &apple_wdt_ops;
>>> + wdt->wdd.info = &apple_wdt_info;
>>> + wdt->wdd.max_timeout = U32_MAX / wdt->clk_rate;
>>> + wdt->wdd.timeout = APPLE_WDT_TIMEOUT_DEFAULT;
>>> +
>>> + wdt_ctrl = readl_relaxed(wdt->regs + APPLE_WDT_WD1_CTRL);
>>> + if (wdt_ctrl & APPLE_WDT_CTRL_RESET_EN)
>>> + set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
>>> +
>>> + watchdog_init_timeout(&wdt->wdd, 0, dev);
>>> + apple_wdt_set_timeout(&wdt->wdd, wdt->wdd.timeout);
>>> + watchdog_stop_on_unregister(&wdt->wdd);
>>> + watchdog_set_restart_priority(&wdt->wdd, 128);
>>> +
>>> + return devm_watchdog_register_device(dev, &wdt->wdd);
>>> +}
>>> +
>>> +static const struct of_device_id apple_wdt_of_match[] = {
>>> + { .compatible = "apple,wdt" },
>>> + {},
>>> +};
>>> +MODULE_DEVICE_TABLE(of, apple_wdt_of_match);
>>> +
>>> +static struct platform_driver apple_wdt_driver = {
>>> + .driver = {
>>> + .name = "apple-watchdog",
>>> + .of_match_table = apple_wdt_of_match,
>>> + },
>>> + .probe = apple_wdt_probe,
>>> +};
>>> +module_platform_driver(apple_wdt_driver);
>>> +
>>> +MODULE_DESCRIPTION("Apple SoC watchdog driver");
>>> +MODULE_AUTHOR("Sven Peter <[email protected]>");
>>> +MODULE_LICENSE("Dual MIT/GPL");
>>
>> Reviewed-by: Hector Martin <[email protected]>
>>
>> Thanks, looks good! Any chance you can do a quick v3 with the MAINTAINERS changes split off? As usual, I'd rather make life easier for people merging upstream :)
>>
>
> Usually I don't ask for such a split, and I don't recall that being an issue.
> So, from my perspective, that is not necessary.

We're upstreaming a bunch of things in parallel that touch the same
MAINTAINERS section, and if each of those goes through subsystem trees,
they all end up creating a pile of conflicts when merged. This has
already happened a few times (I got a ping from linux-next about it the
other day).

To make life easier for upstream mergers, we prefer to split off
MAINTAINERS changes. Then instead of going through the subsystem tree, I
can push those up through the SoC tree, making sure to resolve any
conflicts/ordering issues. Then everyone upstream of us is happy :-)

--
Hector Martin ([email protected])
Public Key: https://mrcn.st/pub

2021-12-03 15:08:38

by Guenter Roeck

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] watchdog: Add Apple SoC watchdog driver

On 12/3/21 5:50 AM, Hector Martin wrote:
> On 02/12/2021 23.36, Guenter Roeck wrote:
>> On 12/1/21 10:44 PM, Hector Martin "marcan" wrote:
>>>
>>>
>>> On 2021年12月1日 1:18:09 JST, Sven Peter <[email protected]> wrote:
>>>> Add support for the watchdog timer found in Apple SoCs. This driver is
>>>> also required to reboot these machines.
>>>>
>>>> Signed-off-by: Sven Peter <[email protected]>
>>>> ---
>>>> v1 -> v2:
>>>> - set the default timeout to 30s and call watchdog_init_timeout
>>>>     to allow the device tree to override it
>>>> - set WDOG_HW_RUNNING if the watchdog is enabled at boot
>>>> - check that the clock rate is not zero
>>>> - use unsigned long instead of u32 for clk_rate
>>>> - use devm_add_action_or_reset instead of manually calling
>>>>     clk_disable_unprepare
>>>> - explain the magic number in apple_wdt_restart
>>>>
>>>> MAINTAINERS                  |   1 +
>>>> drivers/watchdog/Kconfig     |  12 ++
>>>> drivers/watchdog/Makefile    |   1 +
>>>> drivers/watchdog/apple_wdt.c | 226 +++++++++++++++++++++++++++++++++++
>>>> 4 files changed, 240 insertions(+)
>>>> create mode 100644 drivers/watchdog/apple_wdt.c
>>>>
>>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>>> index 859201bbd4e8..6190f0b40983 100644
>>>> --- a/MAINTAINERS
>>>> +++ b/MAINTAINERS
>>>> @@ -1757,6 +1757,7 @@ F:    drivers/i2c/busses/i2c-pasemi-platform.c
>>>> F:    drivers/irqchip/irq-apple-aic.c
>>>> F:    drivers/mailbox/apple-mailbox.c
>>>> F:    drivers/pinctrl/pinctrl-apple-gpio.c
>>>> +F:    drivers/watchdog/apple_wdt.c
>>>> F:    include/dt-bindings/interrupt-controller/apple-aic.h
>>>> F:    include/dt-bindings/pinctrl/apple.h
>>>> F:    include/linux/apple-mailbox.h
>>>> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
>>>> index 9d222ba17ec6..170dec880c8f 100644
>>>> --- a/drivers/watchdog/Kconfig
>>>> +++ b/drivers/watchdog/Kconfig
>>>> @@ -976,6 +976,18 @@ config MSC313E_WATCHDOG
>>>>       To compile this driver as a module, choose M here: the
>>>>       module will be called msc313e_wdt.
>>>>
>>>> +config APPLE_WATCHDOG
>>>> +    tristate "Apple SoC watchdog"
>>>> +    depends on ARCH_APPLE || COMPILE_TEST
>>>> +    select WATCHDOG_CORE
>>>> +    help
>>>> +      Say Y here to include support for the Watchdog found in Apple
>>>> +      SoCs such as the M1. Next to the common watchdog features this
>>>> +      driver is also required in order to reboot these SoCs.
>>>> +
>>>> +      To compile this driver as a module, choose M here: the
>>>> +      module will be called apple_wdt.
>>>> +
>>>> # X86 (i386 + ia64 + x86_64) Architecture
>>>>
>>>> config ACQUIRE_WDT
>>>> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
>>>> index 2ee97064145b..270a518bd8f3 100644
>>>> --- a/drivers/watchdog/Makefile
>>>> +++ b/drivers/watchdog/Makefile
>>>> @@ -93,6 +93,7 @@ obj-$(CONFIG_PM8916_WATCHDOG) += pm8916_wdt.o
>>>> obj-$(CONFIG_ARM_SMC_WATCHDOG) += arm_smc_wdt.o
>>>> obj-$(CONFIG_VISCONTI_WATCHDOG) += visconti_wdt.o
>>>> obj-$(CONFIG_MSC313E_WATCHDOG) += msc313e_wdt.o
>>>> +obj-$(CONFIG_APPLE_WATCHDOG) += apple_wdt.o
>>>>
>>>> # X86 (i386 + ia64 + x86_64) Architecture
>>>> obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
>>>> diff --git a/drivers/watchdog/apple_wdt.c b/drivers/watchdog/apple_wdt.c
>>>> new file mode 100644
>>>> index 000000000000..76e5bedd50d1
>>>> --- /dev/null
>>>> +++ b/drivers/watchdog/apple_wdt.c
>>>> @@ -0,0 +1,226 @@
>>>> +// SPDX-License-Identifier: GPL-2.0-only OR MIT
>>>> +/*
>>>> + * Apple SoC Watchdog driver
>>>> + *
>>>> + * Copyright (C) The Asahi Linux Contributors
>>>> + */
>>>> +
>>>> +#include <linux/bits.h>
>>>> +#include <linux/clk.h>
>>>> +#include <linux/delay.h>
>>>> +#include <linux/io.h>
>>>> +#include <linux/kernel.h>
>>>> +#include <linux/limits.h>
>>>> +#include <linux/module.h>
>>>> +#include <linux/of.h>
>>>> +#include <linux/platform_device.h>
>>>> +#include <linux/watchdog.h>
>>>> +
>>>> +/*
>>>> + * Apple Watchdog MMIO registers
>>>> + *
>>>> + * This HW block has three separate watchdogs. WD0 resets the machine
>>>> + * to recovery mode and is not very useful for us. WD1 and WD2 trigger a normal
>>>> + * machine reset. WD0 additionally supports a configurable interrupt.
>>>> + * This information can be used to implement pretimeout support at a later time.
>>>> + *
>>>> + * APPLE_WDT_WDx_CUR_TIME is a simple counter incremented for each tick of the
>>>> + * reference clock. It can also be overwritten to any value.
>>>> + * Whenever APPLE_WDT_CTRL_RESET_EN is set in APPLE_WDT_WDx_CTRL and
>>>> + * APPLE_WDTx_WD1_CUR_TIME >= APPLE_WDTx_WD1_BITE_TIME the entire machine is
>>>> + * reset.
>>>> + * Whenever APPLE_WDT_CTRL_IRQ_EN is set and APPLE_WDTx_WD1_CUR_TIME >=
>>>> + * APPLE_WDTx_WD1_BARK_TIME an interrupt is triggered and
>>>> + * APPLE_WDT_CTRL_IRQ_STATUS is set. The interrupt can be cleared by writing
>>>> + * 1 to APPLE_WDT_CTRL_IRQ_STATUS.
>>>> + */
>>>> +#define APPLE_WDT_WD0_CUR_TIME        0x00
>>>> +#define APPLE_WDT_WD0_BITE_TIME        0x04
>>>> +#define APPLE_WDT_WD0_BARK_TIME        0x08
>>>> +#define APPLE_WDT_WD0_CTRL        0x0c
>>>> +
>>>> +#define APPLE_WDT_WD1_CUR_TIME        0x10
>>>> +#define APPLE_WDT_WD1_BITE_TIME        0x14
>>>> +#define APPLE_WDT_WD1_CTRL        0x1c
>>>> +
>>>> +#define APPLE_WDT_WD2_CUR_TIME        0x20
>>>> +#define APPLE_WDT_WD2_BITE_TIME        0x24
>>>> +#define APPLE_WDT_WD2_CTRL        0x2c
>>>> +
>>>> +#define APPLE_WDT_CTRL_IRQ_EN        BIT(0)
>>>> +#define APPLE_WDT_CTRL_IRQ_STATUS    BIT(1)
>>>> +#define APPLE_WDT_CTRL_RESET_EN        BIT(2)
>>>> +
>>>> +#define APPLE_WDT_TIMEOUT_DEFAULT    30
>>>> +
>>>> +struct apple_wdt {
>>>> +    struct watchdog_device wdd;
>>>> +    void __iomem *regs;
>>>> +    unsigned long clk_rate;
>>>> +};
>>>> +
>>>> +static struct apple_wdt *to_apple_wdt(struct watchdog_device *wdd)
>>>> +{
>>>> +    return container_of(wdd, struct apple_wdt, wdd);
>>>> +}
>>>> +
>>>> +static int apple_wdt_start(struct watchdog_device *wdd)
>>>> +{
>>>> +    struct apple_wdt *wdt = to_apple_wdt(wdd);
>>>> +
>>>> +    writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CUR_TIME);
>>>> +    writel_relaxed(APPLE_WDT_CTRL_RESET_EN, wdt->regs + APPLE_WDT_WD1_CTRL);
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static int apple_wdt_stop(struct watchdog_device *wdd)
>>>> +{
>>>> +    struct apple_wdt *wdt = to_apple_wdt(wdd);
>>>> +
>>>> +    writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CTRL);
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static int apple_wdt_ping(struct watchdog_device *wdd)
>>>> +{
>>>> +    struct apple_wdt *wdt = to_apple_wdt(wdd);
>>>> +
>>>> +    writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CUR_TIME);
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static int apple_wdt_set_timeout(struct watchdog_device *wdd, unsigned int s)
>>>> +{
>>>> +    struct apple_wdt *wdt = to_apple_wdt(wdd);
>>>> +
>>>> +    writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CUR_TIME);
>>>> +    writel_relaxed(wdt->clk_rate * s, wdt->regs + APPLE_WDT_WD1_BITE_TIME);
>>>> +
>>>> +    wdd->timeout = s;
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static unsigned int apple_wdt_get_timeleft(struct watchdog_device *wdd)
>>>> +{
>>>> +    struct apple_wdt *wdt = to_apple_wdt(wdd);
>>>> +    u32 cur_time, reset_time;
>>>> +
>>>> +    cur_time = readl_relaxed(wdt->regs + APPLE_WDT_WD1_CUR_TIME);
>>>> +    reset_time = readl_relaxed(wdt->regs + APPLE_WDT_WD1_BITE_TIME);
>>>> +
>>>> +    return (reset_time - cur_time) / wdt->clk_rate;
>>>> +}
>>>> +
>>>> +static int apple_wdt_restart(struct watchdog_device *wdd, unsigned long mode,
>>>> +                 void *cmd)
>>>> +{
>>>> +    struct apple_wdt *wdt = to_apple_wdt(wdd);
>>>> +
>>>> +    writel_relaxed(APPLE_WDT_CTRL_RESET_EN, wdt->regs + APPLE_WDT_WD1_CTRL);
>>>> +    writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_BITE_TIME);
>>>> +    writel_relaxed(0, wdt->regs + APPLE_WDT_WD1_CUR_TIME);
>>>> +
>>>> +    /*
>>>> +     * Flush writes and then wait for the SoC to reset. Even though the
>>>> +     * reset is queued almost immediately experiments have shown that it
>>>> +     * can take up to ~20-25ms until the SoC is actually reset. Just wait
>>>> +     * 50ms here to be safe.
>>>> +     */
>>>> +    (void)readl_relaxed(wdt->regs + APPLE_WDT_WD1_CUR_TIME);
>>>> +    mdelay(50);
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static void apple_wdt_clk_disable_unprepare(void *data)
>>>> +{
>>>> +    clk_disable_unprepare(data);
>>>> +}
>>>> +
>>>> +static struct watchdog_ops apple_wdt_ops = {
>>>> +    .owner = THIS_MODULE,
>>>> +    .start = apple_wdt_start,
>>>> +    .stop = apple_wdt_stop,
>>>> +    .ping = apple_wdt_ping,
>>>> +    .set_timeout = apple_wdt_set_timeout,
>>>> +    .get_timeleft = apple_wdt_get_timeleft,
>>>> +    .restart = apple_wdt_restart,
>>>> +};
>>>> +
>>>> +static struct watchdog_info apple_wdt_info = {
>>>> +    .identity = "Apple SoC Watchdog",
>>>> +    .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
>>>> +};
>>>> +
>>>> +static int apple_wdt_probe(struct platform_device *pdev)
>>>> +{
>>>> +    struct device *dev = &pdev->dev;
>>>> +    struct apple_wdt *wdt;
>>>> +    struct clk *clk;
>>>> +    u32 wdt_ctrl;
>>>> +    int ret;
>>>> +
>>>> +    wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
>>>> +    if (!wdt)
>>>> +        return -ENOMEM;
>>>> +
>>>> +    wdt->regs = devm_platform_ioremap_resource(pdev, 0);
>>>> +    if (IS_ERR(wdt->regs))
>>>> +        return PTR_ERR(wdt->regs);
>>>> +
>>>> +    clk = devm_clk_get(dev, NULL);
>>>> +    if (IS_ERR(clk))
>>>> +        return PTR_ERR(clk);
>>>> +
>>>> +    ret = clk_prepare_enable(clk);
>>>> +    if (ret)
>>>> +        return ret;
>>>> +
>>>> +    ret = devm_add_action_or_reset(dev, apple_wdt_clk_disable_unprepare,
>>>> +                       clk);
>>>> +    if (ret)
>>>> +        return ret;
>>>> +
>>>> +    wdt->clk_rate = clk_get_rate(clk);
>>>> +    if (!wdt->clk_rate)
>>>> +        return -EINVAL;
>>>> +
>>>> +    wdt->wdd.ops = &apple_wdt_ops;
>>>> +    wdt->wdd.info = &apple_wdt_info;
>>>> +    wdt->wdd.max_timeout = U32_MAX / wdt->clk_rate;
>>>> +    wdt->wdd.timeout = APPLE_WDT_TIMEOUT_DEFAULT;
>>>> +
>>>> +    wdt_ctrl = readl_relaxed(wdt->regs + APPLE_WDT_WD1_CTRL);
>>>> +    if (wdt_ctrl & APPLE_WDT_CTRL_RESET_EN)
>>>> +        set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
>>>> +
>>>> +    watchdog_init_timeout(&wdt->wdd, 0, dev);
>>>> +    apple_wdt_set_timeout(&wdt->wdd, wdt->wdd.timeout);
>>>> +    watchdog_stop_on_unregister(&wdt->wdd);
>>>> +    watchdog_set_restart_priority(&wdt->wdd, 128);
>>>> +
>>>> +    return devm_watchdog_register_device(dev, &wdt->wdd);
>>>> +}
>>>> +
>>>> +static const struct of_device_id apple_wdt_of_match[] = {
>>>> +    { .compatible = "apple,wdt" },
>>>> +    {},
>>>> +};
>>>> +MODULE_DEVICE_TABLE(of, apple_wdt_of_match);
>>>> +
>>>> +static struct platform_driver apple_wdt_driver = {
>>>> +    .driver = {
>>>> +        .name = "apple-watchdog",
>>>> +        .of_match_table = apple_wdt_of_match,
>>>> +    },
>>>> +    .probe = apple_wdt_probe,
>>>> +};
>>>> +module_platform_driver(apple_wdt_driver);
>>>> +
>>>> +MODULE_DESCRIPTION("Apple SoC watchdog driver");
>>>> +MODULE_AUTHOR("Sven Peter <[email protected]>");
>>>> +MODULE_LICENSE("Dual MIT/GPL");
>>>
>>> Reviewed-by: Hector Martin <[email protected]>
>>>
>>> Thanks, looks good! Any chance you can do a quick v3 with the MAINTAINERS changes split off? As usual, I'd rather make life easier for people merging upstream :)
>>>
>>
>> Usually I don't ask for such a split, and I don't recall that being an issue.
>> So, from my perspective, that is not necessary.
>
> We're upstreaming a bunch of things in parallel that touch the same MAINTAINERS section, and if each of those goes through subsystem trees, they all end up creating a pile of conflicts when merged. This has already happened a few times (I got a ping from linux-next about it the other day).
>
> To make life easier for upstream mergers, we prefer to split off MAINTAINERS changes. Then instead of going through the subsystem tree, I can push those up through the SoC tree, making sure to resolve any conflicts/ordering issues. Then everyone upstream of us is happy :-)
>

Ok, makes sense.

Thanks,
Guenter

2021-12-07 04:35:56

by Hector Martin

[permalink] [raw]
Subject: Re: [PATCH v2 1/2] dt-bindings: watchdog: Add Apple Watchdog

On 02/12/2021 23.43, Guenter Roeck wrote:
> On Tue, Nov 30, 2021 at 05:18:08PM +0100, Sven Peter wrote:
>> Apple SoCs come with a simple embedded watchdog. This watchdog is also
>> required in order to reset the SoC.
>>
>> Reviewed-by: Mark Kettenis <[email protected]>
>> Reviewed-by: Rob Herring <[email protected]>
>> Signed-off-by: Sven Peter <[email protected]>
>
> Reviewed-by: Guenter Roeck <[email protected]>
>
>> ---
>> v1 --> v2:
>> - add Mark's and Rob's r-b tags
>>
>> .../bindings/watchdog/apple,wdt.yaml | 52 +++++++++++++++++++
>> MAINTAINERS | 1 +
>> 2 files changed, 53 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/watchdog/apple,wdt.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml b/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml
>> new file mode 100644
>> index 000000000000..e58c56a6fdf6
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml
>> @@ -0,0 +1,52 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/watchdog/apple,wdt.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Apple SoC Watchdog
>> +
>> +allOf:
>> + - $ref: "watchdog.yaml#"
>> +
>> +maintainers:
>> + - Sven Peter <[email protected]>
>> +
>> +properties:
>> + compatible:
>> + items:
>> + - enum:
>> + - apple,t8103-wdt
>> + - apple,t6000-wdt
>> + - const: apple,wdt
>> +
>> + reg:
>> + maxItems: 1
>> +
>> + clocks:
>> + maxItems: 1
>> +
>> + interrupts:
>> + maxItems: 1
>> +
>> +required:
>> + - compatible
>> + - reg
>> + - clocks
>> + - interrupts
>> +
>> +unevaluatedProperties: false
>> +
>> +examples:
>> + - |
>> + #include <dt-bindings/interrupt-controller/apple-aic.h>
>> + #include <dt-bindings/interrupt-controller/irq.h>
>> +
>> + wdt: watchdog@50000000 {
>> + compatible = "apple,t8103-wdt", "apple,wdt";
>> + reg = <0x50000000 0x4000>;
>> + clocks = <&clk>;
>> + interrupts = <AIC_IRQ 123 IRQ_TYPE_LEVEL_HIGH>;
>> + };
>> +
>> +...
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 360e9aa0205d..859201bbd4e8 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -1750,6 +1750,7 @@ F: Documentation/devicetree/bindings/interrupt-controller/apple,aic.yaml
>> F: Documentation/devicetree/bindings/mailbox/apple,mailbox.yaml
>> F: Documentation/devicetree/bindings/pci/apple,pcie.yaml
>> F: Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml
>> +F: Documentation/devicetree/bindings/watchdog/apple,wdt.yaml
>> F: arch/arm64/boot/dts/apple/
>> F: drivers/i2c/busses/i2c-pasemi-core.c
>> F: drivers/i2c/busses/i2c-pasemi-platform.c
>> --
>> 2.25.1
>>
>

I've gone ahead and applied this patch to the asahi-soc/dt tree, so we
can build off of that to add the DT nodes.

Sven, can you spin a v3 with the MAINTAINERS split and just the driver
itself, without this patch? I imagine Guenter will want to take the
driver itself through the linux-watchdog tree.

--
Hector Martin ([email protected])
Public Key: https://mrcn.st/pub