[PATCH 1/2] watchdog: Add booke watchdog driver

Add a driver for the PowerPC Book E watchdog driver that is present on a number of Freescale/NXP SoCs.
Signed-off-by: Chris Packham judge.packham@gmail.com ---
drivers/watchdog/Kconfig | 7 +++ drivers/watchdog/Makefile | 1 + drivers/watchdog/booke_wdt.c | 107 +++++++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 drivers/watchdog/booke_wdt.c
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 602ccbe41c00..82a24871451b 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -111,6 +111,13 @@ config WDT_BCM6345 The watchdog timer is stopped when initialized. It performs full SoC reset.
+config WDT_BOOKE + bool "PowerPC Book-E watchdog driver" + depends on WDT && MPC85xx + help + Watchdog driver for PowerPC Book-E chips, such as the Freescale + MPC85xx SOCs and the IBM PowerPC 440. + config WDT_CDNS bool "Cadence watchdog timer support" depends on WDT diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 6e70c7ae19ce..5c7ef593fe53 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -21,6 +21,7 @@ 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_BCM6345) += bcm6345_wdt.o +obj-$(CONFIG_WDT_BOOKE) += booke_wdt.o obj-$(CONFIG_WDT_CORTINA) += cortina_wdt.o obj-$(CONFIG_WDT_ORION) += orion_wdt.o obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c new file mode 100644 index 000000000000..4a2d0f3baabd --- /dev/null +++ b/drivers/watchdog/booke_wdt.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Watchdog timer for PowerPC Book-E systems + */ + +#include <common.h> +#include <div64.h> +#include <dm.h> +#include <wdt.h> +#include <asm/processor.h> + +#define WDTP_MASK TCR_WP(0x3f) + +/* For the specified period, determine the number of seconds + * corresponding to the reset time. There will be a watchdog + * exception at approximately 3/5 of this time. + * + * The formula to calculate this is given by: + * 2.5 * (2^(63-period+1)) / timebase_freq + * + * In order to simplify things, we assume that period is + * at least 1. This will still result in a very long timeout. + */ +static unsigned long long period_to_sec(unsigned int period) +{ + unsigned long long tmp = 1ULL << (64 - period); + unsigned long tmp2 = get_tbclk(); + + /* tmp may be a very large number and we don't want to overflow, + * so divide the timebase freq instead of multiplying tmp + */ + tmp2 = tmp2 / 5 * 2; + + do_div(tmp, tmp2); + return tmp; +} + +/* + * This procedure will find the highest period which will give a timeout + * greater than the one required. e.g. for a bus speed of 66666666 and + * and a parameter of 2 secs, then this procedure will return a value of 38. + */ +static unsigned int sec_to_period(unsigned int secs) +{ + unsigned int period; + + for (period = 63; period > 0; period--) { + if (period_to_sec(period) >= secs) + return period; + } + return 0; +} + +static int booke_wdt_reset(struct udevice *dev) +{ + mtspr(SPRN_TSR, TSR_ENW | TSR_WIS); + + return 0; +} + +static int booke_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + u32 val; + unsigned int timeout = DIV_ROUND_UP(timeout_ms, 1000); + + /* clear status before enabling watchdog */ + booke_wdt_reset(dev); + val = mfspr(SPRN_TCR); + val &= ~WDTP_MASK; + val |= (TCR_WIE | TCR_WRC(WRC_CHIP) | TCR_WP(sec_to_period(timeout))); + + mtspr(SPRN_TCR, val); + + return 0; +} + +static int booke_wdt_stop(struct udevice *dev) +{ + u32 val; + + val = mfspr(SPRN_TCR); + val &= ~(TCR_WIE | WDTP_MASK); + mtspr(SPRN_TCR, val); + + /* clear status to make sure nothing is pending */ + booke_wdt_reset(dev); + + return 0; +} + +static const struct wdt_ops booke_wdt_ops = { + .start = booke_wdt_start, + .stop = booke_wdt_stop, + .reset = booke_wdt_reset, +}; + +static const struct udevice_id booke_wdt_ids[] = { + { .compatible = "fsl,booke-wdt" }, + {} +}; + +U_BOOT_DRIVER(booke_wdt) = { + .name = "booke_wdt", + .id = UCLASS_WDT, + .of_match = booke_wdt_ids, + .ops = &booke_wdt_ops, +};

Enable the watchdog on the T2080RDB.
Signed-off-by: Chris Packham judge.packham@gmail.com --- I've included this patch to show how I've been testing the driver. I'm not entirely happy with how the watchdog is represented in the DTS. Technically it's part of the CPU core so it should probably be under each of the CPU nodes. The driver itself doesn't deal with any of the per-cpu stuff that it's Linux counterpart does but I think that's OK for u-boot.
Maybe it should be one node under the first CPU node (will it actually get probed there?).
arch/powerpc/dts/t2080.dtsi | 4 ++++ configs/T2080RDB_defconfig | 3 +++ 2 files changed, 7 insertions(+)
diff --git a/arch/powerpc/dts/t2080.dtsi b/arch/powerpc/dts/t2080.dtsi index 7e446b18df61..cd73adb735f3 100644 --- a/arch/powerpc/dts/t2080.dtsi +++ b/arch/powerpc/dts/t2080.dtsi @@ -41,6 +41,10 @@ }; };
+ watchdog@0 { + compatible = "fsl,booke-wdt"; + }; + soc: soc@ffe000000 { ranges = <0x00000000 0xf 0xfe000000 0x1000000>; reg = <0xf 0xfe000000 0 0x00001000>; diff --git a/configs/T2080RDB_defconfig b/configs/T2080RDB_defconfig index 9dd01bbe50a5..84494bed188f 100644 --- a/configs/T2080RDB_defconfig +++ b/configs/T2080RDB_defconfig @@ -70,5 +70,8 @@ CONFIG_FSL_ESPI=y CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_STORAGE=y +# CONFIG_WATCHDOG is not set +CONFIG_WDT=y +CONFIG_WDT_BOOKE=y CONFIG_ADDR_MAP=y CONFIG_SYS_NUM_ADDR_MAP=64

On 03.03.21 02:39, Chris Packham wrote:
Add a driver for the PowerPC Book E watchdog driver that is present on a number of Freescale/NXP SoCs.
Signed-off-by: Chris Packham judge.packham@gmail.com
drivers/watchdog/Kconfig | 7 +++ drivers/watchdog/Makefile | 1 + drivers/watchdog/booke_wdt.c | 107 +++++++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 drivers/watchdog/booke_wdt.c
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 602ccbe41c00..82a24871451b 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -111,6 +111,13 @@ config WDT_BCM6345 The watchdog timer is stopped when initialized. It performs full SoC reset.
+config WDT_BOOKE
- bool "PowerPC Book-E watchdog driver"
- depends on WDT && MPC85xx
- help
Watchdog driver for PowerPC Book-E chips, such as the Freescale
MPC85xx SOCs and the IBM PowerPC 440.
- config WDT_CDNS bool "Cadence watchdog timer support" depends on WDT
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 6e70c7ae19ce..5c7ef593fe53 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -21,6 +21,7 @@ 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_BCM6345) += bcm6345_wdt.o +obj-$(CONFIG_WDT_BOOKE) += booke_wdt.o obj-$(CONFIG_WDT_CORTINA) += cortina_wdt.o obj-$(CONFIG_WDT_ORION) += orion_wdt.o obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c new file mode 100644 index 000000000000..4a2d0f3baabd --- /dev/null +++ b/drivers/watchdog/booke_wdt.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/*
- Watchdog timer for PowerPC Book-E systems
- */
+#include <common.h>
Please don't include "common.h" any more. There is ongoing work to depricate this common header.
Other than this:
Reviewed-by: Stefan Roese sr@denx.de
Thanks, Stefan
+#include <div64.h> +#include <dm.h> +#include <wdt.h> +#include <asm/processor.h>
+#define WDTP_MASK TCR_WP(0x3f)
+/* For the specified period, determine the number of seconds
- corresponding to the reset time. There will be a watchdog
- exception at approximately 3/5 of this time.
- The formula to calculate this is given by:
- 2.5 * (2^(63-period+1)) / timebase_freq
- In order to simplify things, we assume that period is
- at least 1. This will still result in a very long timeout.
- */
+static unsigned long long period_to_sec(unsigned int period) +{
- unsigned long long tmp = 1ULL << (64 - period);
- unsigned long tmp2 = get_tbclk();
- /* tmp may be a very large number and we don't want to overflow,
* so divide the timebase freq instead of multiplying tmp
*/
- tmp2 = tmp2 / 5 * 2;
- do_div(tmp, tmp2);
- return tmp;
+}
+/*
- This procedure will find the highest period which will give a timeout
- greater than the one required. e.g. for a bus speed of 66666666 and
- and a parameter of 2 secs, then this procedure will return a value of 38.
- */
+static unsigned int sec_to_period(unsigned int secs) +{
- unsigned int period;
- for (period = 63; period > 0; period--) {
if (period_to_sec(period) >= secs)
return period;
- }
- return 0;
+}
+static int booke_wdt_reset(struct udevice *dev) +{
- mtspr(SPRN_TSR, TSR_ENW | TSR_WIS);
- return 0;
+}
+static int booke_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{
- u32 val;
- unsigned int timeout = DIV_ROUND_UP(timeout_ms, 1000);
- /* clear status before enabling watchdog */
- booke_wdt_reset(dev);
- val = mfspr(SPRN_TCR);
- val &= ~WDTP_MASK;
- val |= (TCR_WIE | TCR_WRC(WRC_CHIP) | TCR_WP(sec_to_period(timeout)));
- mtspr(SPRN_TCR, val);
- return 0;
+}
+static int booke_wdt_stop(struct udevice *dev) +{
- u32 val;
- val = mfspr(SPRN_TCR);
- val &= ~(TCR_WIE | WDTP_MASK);
- mtspr(SPRN_TCR, val);
- /* clear status to make sure nothing is pending */
- booke_wdt_reset(dev);
- return 0;
+}
+static const struct wdt_ops booke_wdt_ops = {
- .start = booke_wdt_start,
- .stop = booke_wdt_stop,
- .reset = booke_wdt_reset,
+};
+static const struct udevice_id booke_wdt_ids[] = {
- { .compatible = "fsl,booke-wdt" },
- {}
+};
+U_BOOT_DRIVER(booke_wdt) = {
- .name = "booke_wdt",
- .id = UCLASS_WDT,
- .of_match = booke_wdt_ids,
- .ops = &booke_wdt_ops,
+};
Viele Grüße, Stefan
participants (2)
-
Chris Packham
-
Stefan Roese