From patchwork Wed Jan 25 09:57:28 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Etienne_Dubl=C3=A9?= X-Patchwork-Id: 1731614 X-Patchwork-Delegate: sr@denx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=imag.fr header.i=@imag.fr header.a=rsa-sha256 header.s=2022 header.b=t4DfeiYO; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4P1zmB1D7lz23gY for ; Wed, 25 Jan 2023 20:57:46 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id A5E7C85641; Wed, 25 Jan 2023 10:57:34 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=imag.fr Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=imag.fr header.i=@imag.fr header.b="t4DfeiYO"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 3E6BE8565F; Wed, 25 Jan 2023 10:57:32 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from zm-mta-out-3.u-ga.fr (zm-mta-out-3.u-ga.fr [152.77.200.56]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id BF6A38563A for ; Wed, 25 Jan 2023 10:57:28 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=imag.fr Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=etienne.duble@imag.fr Received: from mailhub.u-ga.fr (mailhub-1.u-ga.fr [129.88.178.98]) by zm-mta-out-3.u-ga.fr (Postfix) with ESMTP id 500CC40325; Wed, 25 Jan 2023 10:57:28 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=imag.fr; s=2022; t=1674640648; bh=zwi5S7t93vgG9XwqnFP8V/EfyBV17gNdXBSBZA3NQoA=; h=Date:From:To:Subject:From; b=t4DfeiYOQa4yfutoAuNMsghVYCh7L6yckCLWIGaXWtWkBzlFi0lnON1oSsS3bNCHj zZqy8TrJxAuOoz7VpZKZNw0kaGPtFzZkaSEpip58K0Ublxd6UkhHjCqg2VTHUx3uVP KOoAf//EMlwY8aVt0VyAaxv03bH7ULgHeHyuglnwOfe+ZEuyfnMCy/a14HE8JykmYJ aKVxw7EzY7qXwYWXbSXeg3+wThhDZjOfNq02kVhjZTh9fdCcGnSeXPFi2+dkwu7dNj b/1nIC9h0yjbHjxsuvlrAq+0NOB4UMUZ0GUg9DdV4gKToMl/puAxz9PMusMSNPWuiX mjt0E7sPyPejw== Received: from mailhost.u-ga.fr (mailhost2.u-ga.fr [129.88.177.242]) by mailhub.u-ga.fr (Postfix) with ESMTP id 4DC5F10005A; Wed, 25 Jan 2023 10:57:28 +0100 (CET) Received: from zm-mbx03.u-ga.fr (zm-mbx03.u-ga.fr [152.77.200.17]) by mailhost.u-ga.fr (Postfix) with ESMTP id 4881060067; Wed, 25 Jan 2023 10:57:28 +0100 (CET) Date: Wed, 25 Jan 2023 10:57:28 +0100 (CET) From: ETIENNE DUBLE To: Stefan Roese , u-boot Message-ID: <567596241.308425.1674640648249.JavaMail.zimbra@univ-grenoble-alpes.fr> Subject: [PATCH v3] watchdog: Add a watchdog driver for Raspberry Pi boards MIME-Version: 1.0 X-Originating-IP: [129.88.52.169] X-Mailer: Zimbra 8.8.15_GA_4484 (ZimbraWebClient - FF78 (Linux)/8.8.15_GA_4481) Thread-Index: wmGvsh+vV0rh9mPgXHMrCliwKzk0ww== Thread-Topic: watchdog: Add a watchdog driver for Raspberry Pi boards X-Greylist: Whitelist-UGA MAILHOST (SMTP non authentifie) depuis 152.77.200.17 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.6 at phobos.denx.de X-Virus-Status: Clean This driver supports the bcm2835 watchdog found on Raspberry Pi boards. It is derived from the Linux driver and was tested on two Raspberry Pi board versions (B+ and 3B+). Signed-off-by: Etienne Dublé Reviewed-by: Stefan Roese --- Changes for v2: - fixed whitespaces in email - moved a static variable to the priv struct Changes for v3: - used the max timeout value the hardware supports - turned the warning to a one-line message drivers/watchdog/Kconfig | 9 +++ drivers/watchdog/Makefile | 1 + drivers/watchdog/bcm2835_wdt.c | 132 +++++++++++++++++++++++++++++++++ 3 files changed, 142 insertions(+) create mode 100644 drivers/watchdog/bcm2835_wdt.c diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index f1b1cf63ca..06c0d630c8 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -30,6 +30,7 @@ config WATCHDOG_TIMEOUT_MSECS default 128000 if ARCH_MX7 || ARCH_VF610 default 30000 if ARCH_SOCFPGA default 16000 if ARCH_SUNXI + default 15000 if ARCH_BCM283X default 60000 help Watchdog timeout in msec @@ -326,6 +327,14 @@ config WDT_SUNXI help Enable support for the watchdog timer in Allwinner sunxi SoCs. +config WDT_BCM2835 + bool "Broadcom 2835 watchdog timer support" + depends on WDT && ARCH_BCM283X + default y + help + Enable support for the watchdog timer in Broadcom 283X SoCs such + as Raspberry Pi boards. + config XILINX_TB_WATCHDOG bool "Xilinx Axi watchdog timer support" depends on WDT diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 446d961d7d..f99915960c 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -21,6 +21,7 @@ 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 +obj-$(CONFIG_WDT_BCM2835) += bcm2835_wdt.o obj-$(CONFIG_WDT_BCM6345) += bcm6345_wdt.o obj-$(CONFIG_WDT_BOOKE) += booke_wdt.o obj-$(CONFIG_WDT_CORTINA) += cortina_wdt.o diff --git a/drivers/watchdog/bcm2835_wdt.c b/drivers/watchdog/bcm2835_wdt.c new file mode 100644 index 0000000000..3c1ead3dda --- /dev/null +++ b/drivers/watchdog/bcm2835_wdt.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Lubomir Rintel + * Copyright (C) 2023 Etienne Dublé (CNRS) + * + * This code is mostly derived from the linux driver. + */ + +#include +#include +#include +#include + +#define PM_RSTC 0x1c +#define PM_WDOG 0x24 + +#define PM_PASSWORD 0x5a000000 + +/* The hardware supports a maximum timeout value of 0xfffff ticks + * (just below 16 seconds). + */ +#define PM_WDOG_MAX_TICKS 0x000fffff +#define PM_RSTC_WRCFG_CLR 0xffffffcf +#define PM_RSTC_WRCFG_FULL_RESET 0x00000020 +#define PM_RSTC_RESET 0x00000102 + +#define MS_TO_WDOG_TICKS(x) (((x) << 16) / 1000) + +struct bcm2835_wdt_priv { + void __iomem *base; + u64 timeout_ticks; +}; + +static int bcm2835_wdt_start_ticks(struct udevice *dev, + u64 timeout_ticks, ulong flags) +{ + struct bcm2835_wdt_priv *priv = dev_get_priv(dev); + void __iomem *base = priv->base; + u32 cur; + + writel(PM_PASSWORD | timeout_ticks, base + PM_WDOG); + cur = readl(base + PM_RSTC); + writel(PM_PASSWORD | (cur & PM_RSTC_WRCFG_CLR) | PM_RSTC_WRCFG_FULL_RESET, + base + PM_RSTC); + + return 0; +} + +static int bcm2835_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + struct bcm2835_wdt_priv *priv = dev_get_priv(dev); + + priv->timeout_ticks = MS_TO_WDOG_TICKS(timeout_ms); + + if (priv->timeout_ticks > PM_WDOG_MAX_TICKS) { + printf("bcm2835_wdt: the timeout value is too high, using ~16s instead.\n"); + priv->timeout_ticks = PM_WDOG_MAX_TICKS; + } + + return bcm2835_wdt_start_ticks(dev, priv->timeout_ticks, flags); +} + +static int bcm2835_wdt_reset(struct udevice *dev) +{ + struct bcm2835_wdt_priv *priv = dev_get_priv(dev); + + /* restart the timer with the value of priv->timeout_ticks + * saved from the last bcm2835_wdt_start() call. + */ + return bcm2835_wdt_start_ticks(dev, priv->timeout_ticks, 0); +} + +static int bcm2835_wdt_stop(struct udevice *dev) +{ + struct bcm2835_wdt_priv *priv = dev_get_priv(dev); + void __iomem *base = priv->base; + + writel(PM_PASSWORD | PM_RSTC_RESET, base + PM_RSTC); + + return 0; +} + +static int bcm2835_wdt_expire_now(struct udevice *dev, ulong flags) +{ + int ret; + + /* use a timeout of 10 ticks (~150us) */ + ret = bcm2835_wdt_start_ticks(dev, 10, flags); + if (ret) + return ret; + + mdelay(500); + + return 0; +} + +static const struct wdt_ops bcm2835_wdt_ops = { + .reset = bcm2835_wdt_reset, + .start = bcm2835_wdt_start, + .stop = bcm2835_wdt_stop, + .expire_now = bcm2835_wdt_expire_now, +}; + +static const struct udevice_id bcm2835_wdt_ids[] = { + { .compatible = "brcm,bcm2835-pm" }, + { .compatible = "brcm,bcm2835-pm-wdt" }, + { /* sentinel */ } +}; + +static int bcm2835_wdt_probe(struct udevice *dev) +{ + struct bcm2835_wdt_priv *priv = dev_get_priv(dev); + + priv->base = dev_remap_addr(dev); + if (!priv->base) + return -EINVAL; + + priv->timeout_ticks = PM_WDOG_MAX_TICKS; + + bcm2835_wdt_stop(dev); + + return 0; +} + +U_BOOT_DRIVER(bcm2835_wdt) = { + .name = "bcm2835_wdt", + .id = UCLASS_WDT, + .of_match = bcm2835_wdt_ids, + .probe = bcm2835_wdt_probe, + .priv_auto = sizeof(struct bcm2835_wdt_priv), + .ops = &bcm2835_wdt_ops, +};