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. If not defined
  72         * in configuration file, sets 128 Seconds
  73         */
  74#ifndef CONFIG_WATCHDOG_TIMEOUT_MSECS
  75#define CONFIG_WATCHDOG_TIMEOUT_MSECS 128000
  76#endif
  77
  78        timeout = max_t(u64, timeout, TIMEOUT_MIN);
  79        timeout = min_t(u64, timeout, TIMEOUT_MAX);
  80        timeout = lldiv(timeout, 500) - 1;
  81
  82#ifdef CONFIG_FSL_LSCH2
  83        wcr = (WCR_WDA | WCR_SRS | WCR_WDE) << 8 | timeout;
  84#else
  85        wcr = WCR_WDZST | WCR_WDBG | WCR_WDE | WCR_SRS |
  86                WCR_WDA | SET_WCR_WT(timeout);
  87        if (ext_reset)
  88                wcr |= WCR_WDT;
  89#endif /* CONFIG_FSL_LSCH2*/
  90        writew(wcr, &wdog->wcr);
  91        imx_watchdog_reset(wdog);
  92}
  93
  94#if !CONFIG_IS_ENABLED(WDT)
  95void hw_watchdog_reset(void)
  96{
  97        struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
  98
  99        imx_watchdog_reset(wdog);
 100}
 101
 102void hw_watchdog_init(void)
 103{
 104        struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
 105
 106        imx_watchdog_init(wdog, true, CONFIG_WATCHDOG_TIMEOUT_MSECS);
 107}
 108#else
 109struct imx_wdt_priv {
 110        void __iomem *base;
 111        bool ext_reset;
 112};
 113
 114static int imx_wdt_reset(struct udevice *dev)
 115{
 116        struct imx_wdt_priv *priv = dev_get_priv(dev);
 117
 118        imx_watchdog_reset(priv->base);
 119
 120        return 0;
 121}
 122
 123static int imx_wdt_expire_now(struct udevice *dev, ulong flags)
 124{
 125        struct imx_wdt_priv *priv = dev_get_priv(dev);
 126
 127        imx_watchdog_expire_now(priv->base, priv->ext_reset);
 128        hang();
 129
 130        return 0;
 131}
 132
 133static int imx_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
 134{
 135        struct imx_wdt_priv *priv = dev_get_priv(dev);
 136
 137        imx_watchdog_init(priv->base, priv->ext_reset, timeout);
 138
 139        return 0;
 140}
 141
 142static int imx_wdt_probe(struct udevice *dev)
 143{
 144        struct imx_wdt_priv *priv = dev_get_priv(dev);
 145
 146        priv->base = dev_read_addr_ptr(dev);
 147        if (!priv->base)
 148                return -ENOENT;
 149
 150        priv->ext_reset = dev_read_bool(dev, "fsl,ext-reset-output");
 151
 152        return 0;
 153}
 154
 155static const struct wdt_ops imx_wdt_ops = {
 156        .start          = imx_wdt_start,
 157        .reset          = imx_wdt_reset,
 158        .expire_now     = imx_wdt_expire_now,
 159};
 160
 161static const struct udevice_id imx_wdt_ids[] = {
 162        { .compatible = "fsl,imx21-wdt" },
 163        {}
 164};
 165
 166U_BOOT_DRIVER(imx_wdt) = {
 167        .name           = "imx_wdt",
 168        .id             = UCLASS_WDT,
 169        .of_match       = imx_wdt_ids,
 170        .probe          = imx_wdt_probe,
 171        .ops            = &imx_wdt_ops,
 172        .priv_auto      = sizeof(struct imx_wdt_priv),
 173        .flags          = DM_FLAG_PRE_RELOC,
 174};
 175#endif
 176#endif
 177