[PATCH 1/3] watchdog: Add a driver for the Apple watchdog

Stefan Roese sr at denx.de
Tue Jan 11 09:57:12 CET 2022


On 11/14/21 12:19, Mark Kettenis wrote:
> This driver supports the watchdog timer found on Apple's M1 SoC.
> On systems that use these SoC, the watchdog timer is the primary
> way to reboot the system.
> 
> Signed-off-by: Mark Kettenis <kettenis at openbsd.org>
> ---
>   MAINTAINERS                  |   1 +
>   drivers/watchdog/Kconfig     |   9 +++
>   drivers/watchdog/Makefile    |   1 +
>   drivers/watchdog/apple_wdt.c | 111 +++++++++++++++++++++++++++++++++++
>   4 files changed, 122 insertions(+)
>   create mode 100644 drivers/watchdog/apple_wdt.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 00ff572d4d..fe56ffed60 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -115,6 +115,7 @@ F:	arch/arm/include/asm/arch-m1/
>   F:	arch/arm/mach-apple/
>   F:	configs/apple_m1_defconfig
>   F:	drivers/iommu/apple_dart.c
> +F:	drivers/watchdog/apple_wdt.c
>   F:	include/configs/apple.h
>   
>   ARM
> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> index 1177f17fd8..cabac29053 100644
> --- a/drivers/watchdog/Kconfig
> +++ b/drivers/watchdog/Kconfig
> @@ -81,6 +81,15 @@ config WDT
>   	  What exactly happens when the timer expires is up to a particular
>   	  device/driver.
>   
> +config WDT_APPLE
> +	bool "Apple watchdog timer support"
> +	depends on WDT
> +	default y if ARCH_APPLE
> +	help
> +	  Enable support for the watchdog timer on Apple SoCs.
> +	  The watchdog will perform a full SoC reset resulting in a
> +	  reboot of the entire system.
> +
>   config WDT_ARMADA_37XX
>   	bool "Marvell Armada 37xx watchdog timer support"
>   	depends on WDT && ARMADA_3700
> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
> index fa7ce583ce..6d2b3822c0 100644
> --- a/drivers/watchdog/Makefile
> +++ b/drivers/watchdog/Makefile
> @@ -17,6 +17,7 @@ obj-$(CONFIG_DESIGNWARE_WATCHDOG) += designware_wdt.o
>   obj-$(CONFIG_ULP_WATCHDOG) += ulp_wdog.o
>   obj-$(CONFIG_$(SPL_TPL_)WDT) += wdt-uclass.o
>   obj-$(CONFIG_WDT_SANDBOX) += sandbox_wdt.o
> +obj-$(CONFIG_WDT_APPLE) += apple_wdt.o
>   obj-$(CONFIG_WDT_ARMADA_37XX) += armada-37xx-wdt.o
>   obj-$(CONFIG_WDT_ASPEED) += ast_wdt.o
>   obj-$(CONFIG_WDT_AST2600) += ast2600_wdt.o
> diff --git a/drivers/watchdog/apple_wdt.c b/drivers/watchdog/apple_wdt.c
> new file mode 100644
> index 0000000000..08eefcdaf9
> --- /dev/null
> +++ b/drivers/watchdog/apple_wdt.c
> @@ -0,0 +1,111 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2021 Mark Kettenis <kettenis at openbsd.org>
> + */
> +
> +#include <clk.h>
> +#include <dm.h>
> +#include <wdt.h>
> +#include <asm/io.h>
> +#include <linux/delay.h>
> +
> +#define APPLE_WDT_CUR_TIME		0x10
> +#define APPLE_WDT_BARK_TIME		0x14
> +#define APPLE_WDT_CTRL			0x1c
> +#define  APPLE_WDT_CTRL_RESET_EN	BIT(2)
> +
> +struct apple_wdt_priv {
> +	void *base;
> +	ulong clk_rate;
> +};
> +
> +static int apple_wdt_reset(struct udevice *dev)
> +{
> +	struct apple_wdt_priv *priv = dev_get_priv(dev);
> +
> +	writel(0, priv->base + APPLE_WDT_CUR_TIME);
> +
> +	return 0;
> +}
> +
> +static int apple_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
> +{
> +	struct apple_wdt_priv *priv = dev_get_priv(dev);
> +	u64 timeout;
> +
> +	timeout = (timeout_ms * priv->clk_rate) / 1000;
> +	if (timeout > U32_MAX)
> +		return -EINVAL;
> +
> +	writel(0, priv->base + APPLE_WDT_CUR_TIME);
> +	writel(timeout, priv->base + APPLE_WDT_BARK_TIME);
> +	writel(APPLE_WDT_CTRL_RESET_EN, priv->base + APPLE_WDT_CTRL);
> +
> +	return 0;
> +}
> +
> +static int apple_wdt_stop(struct udevice *dev)
> +{
> +	struct apple_wdt_priv *priv = dev_get_priv(dev);
> +
> +	writel(0, priv->base + APPLE_WDT_CTRL);
> +
> +	return 0;
> +}
> +
> +static int apple_wdt_expire_now(struct udevice *dev, ulong flags)
> +{
> +	int ret;
> +
> +	ret = apple_wdt_start(dev, 0, flags);
> +	if (ret)
> +		return ret;
> +
> +	mdelay(150);

Could you perhaps add a short comment here, why you chose 150ms?

Other than this:

Reviewed-by: Stefan Roese <sr at denx.de>

Thanks,
Stefan

> +
> +	return 0;
> +}
> +
> +static const struct wdt_ops apple_wdt_ops = {
> +	.reset = apple_wdt_reset,
> +	.start = apple_wdt_start,
> +	.stop = apple_wdt_stop,
> +	.expire_now = apple_wdt_expire_now,
> +};
> +
> +static const struct udevice_id apple_wdt_ids[] = {
> +	{ .compatible = "apple,wdt" },
> +	{ /* sentinel */ }
> +};
> +
> +static int apple_wdt_probe(struct udevice *dev)
> +{
> +	struct apple_wdt_priv *priv = dev_get_priv(dev);
> +	struct clk clk;
> +	int ret;
> +
> +	priv->base = dev_read_addr_ptr(dev);
> +	if (!priv->base)
> +		return -EINVAL;
> +
> +	ret = clk_get_by_index(dev, 0, &clk);
> +	if (ret)
> +		return ret;
> +
> +	ret = clk_enable(&clk);
> +	if (ret)
> +		return ret;
> +
> +	priv->clk_rate = clk_get_rate(&clk);
> +
> +	return 0;
> +}
> +
> +U_BOOT_DRIVER(apple_wdt) = {
> +	.name = "apple_wdt",
> +	.id = UCLASS_WDT,
> +	.of_match = apple_wdt_ids,
> +	.priv_auto = sizeof(struct apple_wdt_priv),
> +	.probe = apple_wdt_probe,
> +	.ops = &apple_wdt_ops,
> +};
> 

Viele Grüße,
Stefan Roese

-- 
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-51 Fax: (+49)-8142-66989-80 Email: sr at denx.de


More information about the U-Boot mailing list