From 5e112c7ca8ee45860e27f23059d9a319ba8eb6d3 Mon Sep 17 00:00:00 2001 From: Alice Guo Date: Fri, 21 Oct 2022 16:41:18 +0800 Subject: [PATCH] watchdog: ulp_wdog: add driver model for ulp watchdog driver Enable driver model for ulp watchdog timer. When CONFIG_WDT=y and the status of device node is "okay", initr_watchdog will be called and finally calls ulp_wdt_probe() and ulp_wdt_start(). Signed-off-by: Alice Guo Reviewed-by: Ye Li Reviewed-by: Stefan Roese --- drivers/watchdog/ulp_wdog.c | 94 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 87 insertions(+), 7 deletions(-) diff --git a/drivers/watchdog/ulp_wdog.c b/drivers/watchdog/ulp_wdog.c index 1b28681..e081054 100644 --- a/drivers/watchdog/ulp_wdog.c +++ b/drivers/watchdog/ulp_wdog.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include /* * MX7ULP WDOG Register Map @@ -18,6 +20,11 @@ struct wdog_regs { u32 win; }; +struct ulp_wdt_priv { + struct wdog_regs *wdog; + u32 clk_rate; +}; + #ifndef CONFIG_WATCHDOG_TIMEOUT_MSECS #define CONFIG_WATCHDOG_TIMEOUT_MSECS 0x1500 #endif @@ -46,6 +53,9 @@ struct wdog_regs { #define WDG_32KHZ_CLK (0x2) #define WDG_EXT_CLK (0x3) +#define CLK_RATE_1KHZ 1000 +#define CLK_RATE_32KHZ 125 + void hw_watchdog_set_timeout(u16 val) { /* setting timeout value */ @@ -54,10 +64,8 @@ void hw_watchdog_set_timeout(u16 val) writel(val, &wdog->toval); } -void hw_watchdog_reset(void) +void ulp_watchdog_reset(struct wdog_regs *wdog) { - struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR; - if (readl(&wdog->cs) & WDGCS_CMD32EN) { writel(REFRESH_WORD, &wdog->cnt); } else { @@ -68,9 +76,8 @@ void hw_watchdog_reset(void) } } -void hw_watchdog_init(void) +void ulp_watchdog_init(struct wdog_regs *wdog, u16 timeout) { - struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR; u32 cmd32 = 0; if (readl(&wdog->cs) & WDGCS_CMD32EN) { @@ -87,7 +94,7 @@ void hw_watchdog_init(void) while (!(readl(&wdog->cs) & WDGCS_ULK)) ; - hw_watchdog_set_timeout(CONFIG_WATCHDOG_TIMEOUT_MSECS); + hw_watchdog_set_timeout(timeout); writel(0, &wdog->win); /* setting 1-kHz clock source, enable counter running, and clear interrupt */ @@ -102,7 +109,21 @@ void hw_watchdog_init(void) while (!(readl(&wdog->cs) & WDGCS_RCS)) ; - hw_watchdog_reset(); + ulp_watchdog_reset(wdog); +} + +void hw_watchdog_reset(void) +{ + struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR; + + ulp_watchdog_reset(wdog); +} + +void hw_watchdog_init(void) +{ + struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR; + + ulp_watchdog_init(wdog, CONFIG_WATCHDOG_TIMEOUT_MSECS); } void reset_cpu(void) @@ -142,3 +163,62 @@ void reset_cpu(void) while (1); } + +static int ulp_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + struct ulp_wdt_priv *priv = dev_get_priv(dev); + u64 timeout = 0; + + timeout = (timeout_ms * priv->clk_rate) / 1000; + if (timeout > U16_MAX) + return -EINVAL; + + ulp_watchdog_init(priv->wdog, (u16)timeout); + + return 0; +} + +static int ulp_wdt_reset(struct udevice *dev) +{ + struct ulp_wdt_priv *priv = dev_get_priv(dev); + + ulp_watchdog_reset(priv->wdog); + + return 0; +} + +static int ulp_wdt_probe(struct udevice *dev) +{ + struct ulp_wdt_priv *priv = dev_get_priv(dev); + + priv->wdog = dev_read_addr_ptr(dev); + if (!priv->wdog) + return -EINVAL; + + priv->clk_rate = (u32)dev_get_driver_data(dev); + if (!priv->clk_rate) + return -EINVAL; + + return 0; +} + +static const struct wdt_ops ulp_wdt_ops = { + .start = ulp_wdt_start, + .reset = ulp_wdt_reset, +}; + +static const struct udevice_id ulp_wdt_ids[] = { + { .compatible = "fsl,imx7ulp-wdt", .data = CLK_RATE_1KHZ }, + { .compatible = "fsl,imx8ulp-wdt", .data = CLK_RATE_1KHZ }, + { .compatible = "fsl,imx93-wdt", .data = CLK_RATE_32KHZ }, + {} +}; + +U_BOOT_DRIVER(ulp_wdt) = { + .name = "ulp_wdt", + .id = UCLASS_WDT, + .of_match = ulp_wdt_ids, + .priv_auto = sizeof(struct ulp_wdt_priv), + .probe = ulp_wdt_probe, + .ops = &ulp_wdt_ops, +}; -- 2.7.4