diff --git a/arch/arm/include/asm/ti-common/omap_wdt.h b/arch/arm/include/asm/ti-common/omap_wdt.h index 7d72e3af02..fbc421b630 100644 --- a/arch/arm/include/asm/ti-common/omap_wdt.h +++ b/arch/arm/include/asm/ti-common/omap_wdt.h @@ -56,4 +56,9 @@ struct wd_timer { unsigned int wdt_unfr; /* offset 0x100 */ }; +struct omap3_wdt_priv { + struct wd_timer *regs; + unsigned int wdt_trgr_pattern; +}; + #endif /* __OMAP_WDT_H__ */ diff --git a/configs/am335x_evm_defconfig b/configs/am335x_evm_defconfig index ff96f192e0..fa6b03060a 100644 --- a/configs/am335x_evm_defconfig +++ b/configs/am335x_evm_defconfig @@ -58,6 +58,8 @@ CONFIG_DM_SPI=y CONFIG_OMAP3_SPI=y CONFIG_TIMER=y CONFIG_OMAP_TIMER=y +CONFIG_WDT=y +CONFIG_WDT_OMAP3=y CONFIG_USB=y CONFIG_DM_USB=y CONFIG_DM_USB_GADGET=y diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 1e5d14c4ff..a66a9bcbe2 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -28,7 +28,6 @@ config OMAP_WATCHDOG bool "TI OMAP watchdog driver" depends on ARCH_OMAP2PLUS select HW_WATCHDOG - default y if AM33XX help Say Y here to enable the OMAP3+ watchdog driver. @@ -113,6 +112,14 @@ config WDT_MTK The watchdog timer is stopped when initialized. It performs full SoC reset. +config WDT_OMAP3 + bool "TI OMAP watchdog timer support" + depends on WDT && ARCH_OMAP2PLUS + default y if AM33XX + help + This enables OMAP3+ watchdog timer driver, which can be + found on some TI chipsets and inline with driver model. + config WDT_ORION bool "Orion watchdog timer support" depends on WDT diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 414ba2430a..955caef815 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o obj-$(CONFIG_WDT_MPC8xx) += mpc8xx_wdt.o obj-$(CONFIG_WDT_MT7621) += mt7621_wdt.o obj-$(CONFIG_WDT_MTK) += mtk_wdt.o +obj-$(CONFIG_WDT_OMAP3) += omap_wdt.o obj-$(CONFIG_WDT_SP805) += sp805_wdt.o obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o obj-$(CONFIG_WDT_TANGIER) += tangier_wdt.o diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c index 343adb00c7..86f7cf1aaf 100644 --- a/drivers/watchdog/omap_wdt.c +++ b/drivers/watchdog/omap_wdt.c @@ -42,10 +42,14 @@ #include #include #include +#include +#include +#include /* Hardware timeout in seconds */ #define WDT_HW_TIMEOUT 60 +#if !CONFIG_IS_ENABLED(WDT) static unsigned int wdt_trgr_pattern = 0x1234; void hw_watchdog_reset(void) @@ -134,3 +138,113 @@ void hw_watchdog_init(void) while ((readl(&wdt->wdtwwps)) & WDT_WWPS_PEND_WSPR) ; } +#else +static int omap3_wdt_reset(struct udevice *dev) +{ + struct omap3_wdt_priv *priv = dev_get_priv(dev); + + priv->wdt_trgr_pattern = 0x1234; +/* + * Somebody just triggered watchdog reset and write to WTGR register + * is in progress. It is resetting right now, no need to trigger it + * again + */ + if ((readl(&priv->regs->wdtwwps)) & WDT_WWPS_PEND_WTGR) + return 0; + + priv->wdt_trgr_pattern = ~(priv->wdt_trgr_pattern); + writel(priv->wdt_trgr_pattern, &priv->regs->wdtwtgr); +/* + * Don't wait for posted write to complete, i.e. don't check + * WDT_WWPS_PEND_WTGR bit in WWPS register. There is no writes to + * WTGR register outside of this func, and if entering it + * we see WDT_WWPS_PEND_WTGR bit set, it means watchdog reset + * was just triggered. This prevents us from wasting time in busy + * polling of WDT_WWPS_PEND_WTGR bit. + */ + return 0; +} + +static int omap3_wdt_stop(struct udevice *dev) +{ + struct omap3_wdt_priv *priv = dev_get_priv(dev); + +/* disable watchdog */ + writel(0xAAAA, &priv->regs->wdtwspr); + while (readl(&priv->regs->wdtwwps) != 0x0) + ; + writel(0x5555, &priv->regs->wdtwspr); + while (readl(&priv->regs->wdtwwps) != 0x0) + ; + return 0; +} + +static int omap3_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + struct omap3_wdt_priv *priv = dev_get_priv(dev); + u32 pre_margin = GET_WLDR_VAL(timeout_ms); +/* + * Make sure the watchdog is disabled. This is unfortunately required + * because writing to various registers with the watchdog running has no + * effect. + */ + omap3_wdt_stop(dev); + +/* initialize prescaler */ + while (readl(&priv->regs->wdtwwps) & WDT_WWPS_PEND_WCLR) + ; + + writel(WDT_WCLR_PRE | (PTV << WDT_WCLR_PTV_OFF), &priv->regs->wdtwclr); + while (readl(&priv->regs->wdtwwps) & WDT_WWPS_PEND_WCLR) + ; +/* just count up at 32 KHz */ + while (readl(&priv->regs->wdtwwps) & WDT_WWPS_PEND_WLDR) + ; + + writel(pre_margin, &priv->regs->wdtwldr); + while (readl(&priv->regs->wdtwwps) & WDT_WWPS_PEND_WLDR) + ; +/* Sequence to enable the watchdog */ + writel(0xBBBB, &priv->regs->wdtwspr); + while ((readl(&priv->regs->wdtwwps)) & WDT_WWPS_PEND_WSPR) + ; + + writel(0x4444, &priv->regs->wdtwspr); + while ((readl(&priv->regs->wdtwwps)) & WDT_WWPS_PEND_WSPR) + ; + + return 0; +} + +static int omap3_wdt_probe(struct udevice *dev) +{ + struct omap3_wdt_priv *priv = dev_get_priv(dev); + + priv->regs = (struct wd_timer *)devfdt_get_addr(dev); + if (!priv->regs) + return -EINVAL; + + debug("%s: Probing wdt%u\n", __func__, dev->seq); + return 0; +} + +static const struct wdt_ops omap3_wdt_ops = { + .start = omap3_wdt_start, + .stop = omap3_wdt_stop, + .reset = omap3_wdt_reset, +}; + +static const struct udevice_id omap3_wdt_ids[] = { + { .compatible = "ti,omap3-wdt" }, + { } +}; + +U_BOOT_DRIVER(omap3_wdt) = { + .name = "omap3_wdt", + .id = UCLASS_WDT, + .of_match = omap3_wdt_ids, + .ops = &omap3_wdt_ops, + .probe = omap3_wdt_probe, + .priv_auto_alloc_size = sizeof(struct omap3_wdt_priv), +}; +#endif /* !CONFIG_IS_ENABLED(WDT) */