uboot/drivers/watchdog/imx_watchdog.c
<<
>>
Prefs
   1/*
   2 * watchdog.c - driver for i.mx on-chip watchdog
   3 *
   4 * Licensed under the GPL-2 or later.
   5 */
   6
   7#include <common.h>
   8#include <cpu_func.h>
   9#include <dm.h>
  10#include <hang.h>
  11#include <asm/io.h>
  12#include <wdt.h>
  13#include <watchdog.h>
  14#include <asm/arch/imx-regs.h>
  15#ifdef CONFIG_FSL_LSCH2
  16#include <asm/arch/immap_lsch2.h>
  17#endif
  18#include <fsl_wdog.h>
  19#include <div64.h>
  20
  21#define TIMEOUT_MAX     128000
  22#define TIMEOUT_MIN     500
  23
  24static void imx_watchdog_expire_now(struct watchdog_regs *wdog, bool ext_reset)
  25{
  26        u16 wcr = WCR_WDE;
  27
  28        if (ext_reset)
  29                wcr |= WCR_SRS; /* do not assert internal reset */
  30        else
  31                wcr |= WCR_WDA; /* do not assert external reset */
  32
  33        /* Write 3 times to ensure it works, due to IMX6Q errata ERR004346 */
  34        writew(wcr, &wdog->wcr);
  35        writew(wcr, &wdog->wcr);
  36        writew(wcr, &wdog->wcr);
  37
  38        while (1) {
  39                /*
  40                 * spin before reset
  41                 */
  42        }
  43}
  44
  45#if !defined(CONFIG_IMX_WATCHDOG) || \
  46    (defined(CONFIG_IMX_WATCHDOG) && !CONFIG_IS_ENABLED(WDT))
  47void __attribute__((weak)) reset_cpu(void)
  48{
  49        struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
  50
  51        imx_watchdog_expire_now(wdog, true);
  52}
  53#endif
  54
  55#if defined(CONFIG_IMX_WATCHDOG)
  56static void imx_watchdog_reset(struct watchdog_regs *wdog)
  57{
  58#ifndef CONFIG_WATCHDOG_RESET_DISABLE
  59        writew(0x5555, &wdog->wsr);
  60        writew(0xaaaa, &wdog->wsr);
  61#endif /* CONFIG_WATCHDOG_RESET_DISABLE*/
  62}
  63
  64static void imx_watchdog_init(struct watchdog_regs *wdog, bool ext_reset,
  65                              u64 timeout)
  66{
  67        u16 wcr;
  68
  69        /*
  70         * The timer watchdog can be set between
  71         * 0.5 and 128 Seconds.
  72         */
  73        timeout = max_t(u64, timeout, TIMEOUT_MIN);
  74        timeout = min_t(u64, timeout, TIMEOUT_MAX);
  75        timeout = lldiv(timeout, 500) - 1;
  76
  77#ifdef CONFIG_FSL_LSCH2
  78        wcr = (WCR_WDA | WCR_SRS | WCR_WDE) << 8 | timeout;
  79#else
  80        wcr = WCR_WDZST | WCR_WDBG | WCR_WDE | WCR_SRS |
  81                WCR_WDA | SET_WCR_WT(timeout);
  82        if (ext_reset)
  83                wcr |= WCR_WDT;
  84#endif /* CONFIG_FSL_LSCH2*/
  85        writew(wcr, &wdog->wcr);
  86        imx_watchdog_reset(wdog);
  87}
  88
  89#if !CONFIG_IS_ENABLED(WDT)
  90void hw_watchdog_reset(void)
  91{
  92        struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
  93
  94        imx_watchdog_reset(wdog);
  95}
  96
  97void hw_watchdog_init(void)
  98{
  99        struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
 100
 101        imx_watchdog_init(wdog, true, CONFIG_WATCHDOG_TIMEOUT_MSECS);
 102}
 103#else
 104struct imx_wdt_priv {
 105        void __iomem *base;
 106        bool ext_reset;
 107};
 108
 109static int imx_wdt_reset(struct udevice *dev)
 110{
 111        struct imx_wdt_priv *priv = dev_get_priv(dev);
 112
 113        imx_watchdog_reset(priv->base);
 114
 115        return 0;
 116}
 117
 118static int imx_wdt_expire_now(struct udevice *dev, ulong flags)
 119{
 120        struct imx_wdt_priv *priv = dev_get_priv(dev);
 121
 122        imx_watchdog_expire_now(priv->base, priv->ext_reset);
 123        hang();
 124
 125        return 0;
 126}
 127
 128static int imx_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
 129{
 130        struct imx_wdt_priv *priv = dev_get_priv(dev);
 131
 132        imx_watchdog_init(priv->base, priv->ext_reset, timeout);
 133
 134        return 0;
 135}
 136
 137static int imx_wdt_probe(struct udevice *dev)
 138{
 139        struct imx_wdt_priv *priv = dev_get_priv(dev);
 140
 141        priv->base = dev_read_addr_ptr(dev);
 142        if (!priv->base)
 143                return -ENOENT;
 144
 145        priv->ext_reset = dev_read_bool(dev, "fsl,ext-reset-output");
 146
 147        return 0;
 148}
 149
 150static const struct wdt_ops imx_wdt_ops = {
 151        .start          = imx_wdt_start,
 152        .reset          = imx_wdt_reset,
 153        .expire_now     = imx_wdt_expire_now,
 154};
 155
 156static const struct udevice_id imx_wdt_ids[] = {
 157        { .compatible = "fsl,imx21-wdt" },
 158        {}
 159};
 160
 161U_BOOT_DRIVER(imx_wdt) = {
 162        .name           = "imx_wdt",
 163        .id             = UCLASS_WDT,
 164        .of_match       = imx_wdt_ids,
 165        .probe          = imx_wdt_probe,
 166        .ops            = &imx_wdt_ops,
 167        .priv_auto      = sizeof(struct imx_wdt_priv),
 168        .flags          = DM_FLAG_PRE_RELOC,
 169};
 170#endif
 171#endif
 172