|
@@ -4,7 +4,8 @@
|
|
|
*/
|
|
|
|
|
|
#include <common.h>
|
|
|
-#include <watchdog.h>
|
|
|
+#include <dm.h>
|
|
|
+#include <wdt.h>
|
|
|
#include <asm/io.h>
|
|
|
#include <asm/utils.h>
|
|
|
|
|
@@ -17,46 +18,51 @@
|
|
|
#define DW_WDT_CR_RMOD_VAL 0x00
|
|
|
#define DW_WDT_CRR_RESTART_VAL 0x76
|
|
|
|
|
|
+struct designware_wdt_priv {
|
|
|
+ void __iomem *base;
|
|
|
+};
|
|
|
+
|
|
|
/*
|
|
|
* Set the watchdog time interval.
|
|
|
* Counter is 32 bit.
|
|
|
*/
|
|
|
-static int designware_wdt_settimeout(unsigned int timeout)
|
|
|
+static int designware_wdt_settimeout(void __iomem *base, unsigned int clk_khz,
|
|
|
+ unsigned int timeout)
|
|
|
{
|
|
|
signed int i;
|
|
|
|
|
|
/* calculate the timeout range value */
|
|
|
- i = (log_2_n_round_up(timeout * CONFIG_DW_WDT_CLOCK_KHZ)) - 16;
|
|
|
- if (i > 15)
|
|
|
- i = 15;
|
|
|
- if (i < 0)
|
|
|
- i = 0;
|
|
|
+ i = log_2_n_round_up(timeout * clk_khz) - 16;
|
|
|
+ i = clamp(i, 0, 15);
|
|
|
+
|
|
|
+ writel(i | (i << 4), base + DW_WDT_TORR);
|
|
|
|
|
|
- writel((i | (i << 4)), (CONFIG_DW_WDT_BASE + DW_WDT_TORR));
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static void designware_wdt_enable(void)
|
|
|
+static void designware_wdt_enable(void __iomem *base)
|
|
|
{
|
|
|
- writel(((DW_WDT_CR_RMOD_VAL << DW_WDT_CR_RMOD_OFFSET) |
|
|
|
- (0x1 << DW_WDT_CR_EN_OFFSET)),
|
|
|
- (CONFIG_DW_WDT_BASE + DW_WDT_CR));
|
|
|
+ writel((DW_WDT_CR_RMOD_VAL << DW_WDT_CR_RMOD_OFFSET) |
|
|
|
+ BIT(DW_WDT_CR_EN_OFFSET),
|
|
|
+ base + DW_WDT_CR);
|
|
|
}
|
|
|
|
|
|
-static unsigned int designware_wdt_is_enabled(void)
|
|
|
+static unsigned int designware_wdt_is_enabled(void __iomem *base)
|
|
|
{
|
|
|
- unsigned long val;
|
|
|
- val = readl((CONFIG_DW_WDT_BASE + DW_WDT_CR));
|
|
|
- return val & 0x1;
|
|
|
+ return readl(base + DW_WDT_CR) & BIT(0);
|
|
|
}
|
|
|
|
|
|
-#if defined(CONFIG_HW_WATCHDOG)
|
|
|
-void hw_watchdog_reset(void)
|
|
|
+static void designware_wdt_reset_common(void __iomem *base)
|
|
|
{
|
|
|
- if (designware_wdt_is_enabled())
|
|
|
+ if (designware_wdt_is_enabled(base))
|
|
|
/* restart the watchdog counter */
|
|
|
- writel(DW_WDT_CRR_RESTART_VAL,
|
|
|
- (CONFIG_DW_WDT_BASE + DW_WDT_CRR));
|
|
|
+ writel(DW_WDT_CRR_RESTART_VAL, base + DW_WDT_CRR);
|
|
|
+}
|
|
|
+
|
|
|
+#if !CONFIG_IS_ENABLED(WDT)
|
|
|
+void hw_watchdog_reset(void)
|
|
|
+{
|
|
|
+ designware_wdt_reset_common((void __iomem *)CONFIG_DW_WDT_BASE);
|
|
|
}
|
|
|
|
|
|
void hw_watchdog_init(void)
|
|
@@ -64,10 +70,80 @@ void hw_watchdog_init(void)
|
|
|
/* reset to disable the watchdog */
|
|
|
hw_watchdog_reset();
|
|
|
/* set timer in miliseconds */
|
|
|
- designware_wdt_settimeout(CONFIG_WATCHDOG_TIMEOUT_MSECS);
|
|
|
+ designware_wdt_settimeout((void __iomem *)CONFIG_DW_WDT_BASE,
|
|
|
+ CONFIG_DW_WDT_CLOCK_KHZ,
|
|
|
+ CONFIG_WATCHDOG_TIMEOUT_MSECS);
|
|
|
/* enable the watchdog */
|
|
|
- designware_wdt_enable();
|
|
|
+ designware_wdt_enable((void __iomem *)CONFIG_DW_WDT_BASE);
|
|
|
/* reset the watchdog */
|
|
|
hw_watchdog_reset();
|
|
|
}
|
|
|
+#else
|
|
|
+static int designware_wdt_reset(struct udevice *dev)
|
|
|
+{
|
|
|
+ struct designware_wdt_priv *priv = dev_get_priv(dev);
|
|
|
+
|
|
|
+ designware_wdt_reset_common(priv->base);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int designware_wdt_stop(struct udevice *dev)
|
|
|
+{
|
|
|
+ struct designware_wdt_priv *priv = dev_get_priv(dev);
|
|
|
+
|
|
|
+ designware_wdt_reset(dev);
|
|
|
+ writel(DW_WDT_CR_RMOD_VAL << DW_WDT_CR_RMOD_OFFSET,
|
|
|
+ priv->base + DW_WDT_CR);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int designware_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
|
|
|
+{
|
|
|
+ struct designware_wdt_priv *priv = dev_get_priv(dev);
|
|
|
+
|
|
|
+ designware_wdt_stop(dev);
|
|
|
+
|
|
|
+ /* set timer in miliseconds */
|
|
|
+ designware_wdt_settimeout(priv->base, CONFIG_DW_WDT_CLOCK_KHZ, timeout);
|
|
|
+
|
|
|
+ designware_wdt_enable(priv->base);
|
|
|
+
|
|
|
+ /* reset the watchdog */
|
|
|
+ return designware_wdt_reset(dev);
|
|
|
+}
|
|
|
+
|
|
|
+static int designware_wdt_probe(struct udevice *dev)
|
|
|
+{
|
|
|
+ struct designware_wdt_priv *priv = dev_get_priv(dev);
|
|
|
+
|
|
|
+ priv->base = dev_remap_addr(dev);
|
|
|
+ if (!priv->base)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ /* reset to disable the watchdog */
|
|
|
+ return designware_wdt_stop(dev);
|
|
|
+}
|
|
|
+
|
|
|
+static const struct wdt_ops designware_wdt_ops = {
|
|
|
+ .start = designware_wdt_start,
|
|
|
+ .reset = designware_wdt_reset,
|
|
|
+ .stop = designware_wdt_stop,
|
|
|
+};
|
|
|
+
|
|
|
+static const struct udevice_id designware_wdt_ids[] = {
|
|
|
+ { .compatible = "snps,dw-wdt"},
|
|
|
+ {}
|
|
|
+};
|
|
|
+
|
|
|
+U_BOOT_DRIVER(designware_wdt) = {
|
|
|
+ .name = "designware_wdt",
|
|
|
+ .id = UCLASS_WDT,
|
|
|
+ .of_match = designware_wdt_ids,
|
|
|
+ .priv_auto_alloc_size = sizeof(struct designware_wdt_priv),
|
|
|
+ .probe = designware_wdt_probe,
|
|
|
+ .ops = &designware_wdt_ops,
|
|
|
+ .flags = DM_FLAG_PRE_RELOC,
|
|
|
+};
|
|
|
#endif
|