uboot/drivers/watchdog/at91sam9_wdt.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * [origin: Linux kernel drivers/watchdog/at91sam9_wdt.c]
   4 *
   5 * Watchdog driver for AT91SAM9x processors.
   6 *
   7 * Copyright (C) 2008 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
   8 * Copyright (C) 2008 Renaud CERRATO r.cerrato@til-technologies.fr
   9 */
  10
  11/*
  12 * The Watchdog Timer Mode Register can be only written to once. If the
  13 * timeout need to be set from U-Boot, be sure that the bootstrap doesn't
  14 * write to this register. Inform Linux to it too
  15 */
  16
  17#include <log.h>
  18#include <asm/global_data.h>
  19#include <asm/io.h>
  20#include <asm/arch/at91_wdt.h>
  21#include <common.h>
  22#include <div64.h>
  23#include <dm.h>
  24#include <errno.h>
  25#include <wdt.h>
  26
  27DECLARE_GLOBAL_DATA_PTR;
  28
  29/*
  30 * AT91SAM9 watchdog runs a 12bit counter @ 256Hz,
  31 * use this to convert a watchdog
  32 * value from seconds.
  33 */
  34#define WDT_SEC2TICKS(s)        (((s) << 8) - 1)
  35
  36/*
  37 * Set the watchdog time interval in 1/256Hz (write-once)
  38 * Counter is 12 bit.
  39 */
  40static int at91_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
  41{
  42        struct at91_wdt_priv *priv = dev_get_priv(dev);
  43        u64 timeout;
  44        u32 ticks;
  45
  46        /* Calculate timeout in seconds and the resulting ticks */
  47        timeout = timeout_ms;
  48        do_div(timeout, 1000);
  49        timeout = min_t(u64, timeout, WDT_MAX_TIMEOUT);
  50        ticks = WDT_SEC2TICKS(timeout);
  51
  52        /* Check if disabled */
  53        if (readl(priv->regs + AT91_WDT_MR) & AT91_WDT_MR_WDDIS) {
  54                printf("sorry, watchdog is disabled\n");
  55                return -1;
  56        }
  57
  58        /*
  59         * All counting occurs at SLOW_CLOCK / 128 = 256 Hz
  60         *
  61         * Since WDV is a 12-bit counter, the maximum period is
  62         * 4096 / 256 = 16 seconds.
  63         */
  64        priv->regval = AT91_WDT_MR_WDRSTEN      /* causes watchdog reset */
  65                | AT91_WDT_MR_WDDBGHLT          /* disabled in debug mode */
  66                | AT91_WDT_MR_WDD(0xfff)        /* restart at any time */
  67                | AT91_WDT_MR_WDV(ticks);       /* timer value */
  68        writel(priv->regval, priv->regs + AT91_WDT_MR);
  69
  70        return 0;
  71}
  72
  73static int at91_wdt_stop(struct udevice *dev)
  74{
  75        struct at91_wdt_priv *priv = dev_get_priv(dev);
  76
  77        /* Disable Watchdog Timer */
  78        priv->regval |= AT91_WDT_MR_WDDIS;
  79        writel(priv->regval, priv->regs + AT91_WDT_MR);
  80
  81        return 0;
  82}
  83
  84static int at91_wdt_reset(struct udevice *dev)
  85{
  86        struct at91_wdt_priv *priv = dev_get_priv(dev);
  87
  88        writel(AT91_WDT_CR_WDRSTT | AT91_WDT_CR_KEY, priv->regs + AT91_WDT_CR);
  89
  90        return 0;
  91}
  92
  93static const struct wdt_ops at91_wdt_ops = {
  94        .start = at91_wdt_start,
  95        .stop = at91_wdt_stop,
  96        .reset = at91_wdt_reset,
  97};
  98
  99static const struct udevice_id at91_wdt_ids[] = {
 100        { .compatible = "atmel,at91sam9260-wdt" },
 101        {}
 102};
 103
 104static int at91_wdt_probe(struct udevice *dev)
 105{
 106        struct at91_wdt_priv *priv = dev_get_priv(dev);
 107
 108        priv->regs = dev_remap_addr(dev);
 109        if (!priv->regs)
 110                return -EINVAL;
 111
 112        debug("%s: Probing wdt%u\n", __func__, dev_seq(dev));
 113
 114        return 0;
 115}
 116
 117U_BOOT_DRIVER(atmel_at91sam9260_wdt) = {
 118        .name = "atmel_at91sam9260_wdt",
 119        .id = UCLASS_WDT,
 120        .of_match = at91_wdt_ids,
 121        .priv_auto      = sizeof(struct at91_wdt_priv),
 122        .ops = &at91_wdt_ops,
 123        .probe = at91_wdt_probe,
 124};
 125