| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- // SPDX-License-Identifier: GPL-2.0+
- /*
- * Copyright (C) 2016 Freescale Semiconductor, Inc.
- */
- #include <common.h>
- #include <cpu_func.h>
- #include <asm/io.h>
- #include <asm/arch/imx-regs.h>
- #include <dm.h>
- #include <wdt.h>
- /*
- * MX7ULP WDOG Register Map
- */
- struct wdog_regs {
- u32 cs;
- u32 cnt;
- u32 toval;
- u32 win;
- };
- struct ulp_wdt_priv {
- struct wdog_regs *wdog;
- u32 clk_rate;
- };
- #define REFRESH_WORD0 0xA602 /* 1st refresh word */
- #define REFRESH_WORD1 0xB480 /* 2nd refresh word */
- #define UNLOCK_WORD0 0xC520 /* 1st unlock word */
- #define UNLOCK_WORD1 0xD928 /* 2nd unlock word */
- #define UNLOCK_WORD 0xD928C520 /* unlock word */
- #define REFRESH_WORD 0xB480A602 /* refresh word */
- #define WDGCS_WDGE BIT(7)
- #define WDGCS_WDGUPDATE BIT(5)
- #define WDGCS_RCS BIT(10)
- #define WDGCS_ULK BIT(11)
- #define WDOG_CS_PRES BIT(12)
- #define WDGCS_CMD32EN BIT(13)
- #define WDGCS_FLG BIT(14)
- #define WDGCS_INT BIT(6)
- #define WDG_BUS_CLK (0x0)
- #define WDG_LPO_CLK (0x1)
- #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 */
- struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
- writel(val, &wdog->toval);
- }
- void ulp_watchdog_reset(struct wdog_regs *wdog)
- {
- if (readl(&wdog->cs) & WDGCS_CMD32EN) {
- writel(REFRESH_WORD, &wdog->cnt);
- } else {
- dmb();
- __raw_writel(REFRESH_WORD0, &wdog->cnt);
- __raw_writel(REFRESH_WORD1, &wdog->cnt);
- dmb();
- }
- }
- void ulp_watchdog_init(struct wdog_regs *wdog, u16 timeout)
- {
- u32 cmd32 = 0;
- if (readl(&wdog->cs) & WDGCS_CMD32EN) {
- writel(UNLOCK_WORD, &wdog->cnt);
- cmd32 = WDGCS_CMD32EN;
- } else {
- dmb();
- __raw_writel(UNLOCK_WORD0, &wdog->cnt);
- __raw_writel(UNLOCK_WORD1, &wdog->cnt);
- dmb();
- }
- /* Wait WDOG Unlock */
- while (!(readl(&wdog->cs) & WDGCS_ULK))
- ;
- hw_watchdog_set_timeout(timeout);
- writel(0, &wdog->win);
- /* setting 1-kHz clock source, enable counter running, and clear interrupt */
- if (IS_ENABLED(CONFIG_ARCH_IMX9))
- writel((cmd32 | WDGCS_WDGE | WDGCS_WDGUPDATE | (WDG_LPO_CLK << 8) |
- WDGCS_FLG | WDOG_CS_PRES | WDGCS_INT), &wdog->cs);
- else
- writel((cmd32 | WDGCS_WDGE | WDGCS_WDGUPDATE | (WDG_LPO_CLK << 8) |
- WDGCS_FLG), &wdog->cs);
- /* Wait WDOG reconfiguration */
- while (!(readl(&wdog->cs) & WDGCS_RCS))
- ;
- 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);
- }
- #if !CONFIG_IS_ENABLED(SYSRESET)
- void reset_cpu(void)
- {
- struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
- u32 cmd32 = 0;
- if (readl(&wdog->cs) & WDGCS_CMD32EN) {
- writel(UNLOCK_WORD, &wdog->cnt);
- cmd32 = WDGCS_CMD32EN;
- } else {
- dmb();
- __raw_writel(UNLOCK_WORD0, &wdog->cnt);
- __raw_writel(UNLOCK_WORD1, &wdog->cnt);
- dmb();
- }
- /* Wait WDOG Unlock */
- while (!(readl(&wdog->cs) & WDGCS_ULK))
- ;
- hw_watchdog_set_timeout(5); /* 5ms timeout for general; 40ms timeout for imx93 */
- writel(0, &wdog->win);
- /* enable counter running */
- if (IS_ENABLED(CONFIG_ARCH_IMX9))
- writel((cmd32 | WDGCS_WDGE | (WDG_LPO_CLK << 8) | WDOG_CS_PRES |
- WDGCS_INT), &wdog->cs);
- else
- writel((cmd32 | WDGCS_WDGE | (WDG_LPO_CLK << 8)), &wdog->cs);
- /* Wait WDOG reconfiguration */
- while (!(readl(&wdog->cs) & WDGCS_RCS))
- ;
- hw_watchdog_reset();
- while (1);
- }
- #endif
- 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,
- };
|