uboot/drivers/watchdog/orion_wdt.c
<<
>>
Prefs
   1/*
   2 * drivers/watchdog/orion_wdt.c
   3 *
   4 * Watchdog driver for Orion/Kirkwood processors
   5 *
   6 * Authors:     Tomas Hlavacek <tmshlvck@gmail.com>
   7 *              Sylver Bruneau <sylver.bruneau@googlemail.com>
   8 *              Marek Behun <marek.behun@nic.cz>
   9 *
  10 * This file is licensed under  the terms of the GNU General Public
  11 * License version 2. This program is licensed "as is" without any
  12 * warranty of any kind, whether express or implied.
  13 */
  14
  15#include <common.h>
  16#include <dm.h>
  17#include <wdt.h>
  18#include <asm/io.h>
  19#include <asm/arch/cpu.h>
  20#include <asm/arch/soc.h>
  21
  22DECLARE_GLOBAL_DATA_PTR;
  23
  24struct orion_wdt_priv {
  25        void __iomem *reg;
  26        int wdt_counter_offset;
  27        void __iomem *rstout;
  28        void __iomem *rstout_mask;
  29        u32 timeout;
  30};
  31
  32#define RSTOUT_ENABLE_BIT               BIT(8)
  33#define RSTOUT_MASK_BIT                 BIT(10)
  34#define WDT_ENABLE_BIT                  BIT(8)
  35
  36#define TIMER_CTRL                      0x0000
  37#define TIMER_A370_STATUS               0x04
  38
  39#define WDT_AXP_FIXED_ENABLE_BIT        BIT(10)
  40#define WDT_A370_EXPIRED                BIT(31)
  41
  42static int orion_wdt_reset(struct udevice *dev)
  43{
  44        struct orion_wdt_priv *priv = dev_get_priv(dev);
  45
  46        /* Reload watchdog duration */
  47        writel(priv->timeout, priv->reg + priv->wdt_counter_offset);
  48
  49        return 0;
  50}
  51
  52static int orion_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
  53{
  54        struct orion_wdt_priv *priv = dev_get_priv(dev);
  55        u32 reg;
  56
  57        priv->timeout = (u32) timeout;
  58
  59        /* Enable the fixed watchdog clock input */
  60        reg = readl(priv->reg + TIMER_CTRL);
  61        reg |= WDT_AXP_FIXED_ENABLE_BIT;
  62        writel(reg, priv->reg + TIMER_CTRL);
  63
  64        /* Set watchdog duration */
  65        writel(priv->timeout, priv->reg + priv->wdt_counter_offset);
  66
  67        /* Clear the watchdog expiration bit */
  68        reg = readl(priv->reg + TIMER_A370_STATUS);
  69        reg &= ~WDT_A370_EXPIRED;
  70        writel(reg, priv->reg + TIMER_A370_STATUS);
  71
  72        /* Enable watchdog timer */
  73        reg = readl(priv->reg + TIMER_CTRL);
  74        reg |= WDT_ENABLE_BIT;
  75        writel(reg, priv->reg + TIMER_CTRL);
  76
  77        /* Enable reset on watchdog */
  78        reg = readl(priv->rstout);
  79        reg |= RSTOUT_ENABLE_BIT;
  80        writel(reg, priv->rstout);
  81
  82        reg = readl(priv->rstout_mask);
  83        reg &= ~RSTOUT_MASK_BIT;
  84        writel(reg, priv->rstout_mask);
  85
  86        return 0;
  87}
  88
  89static int orion_wdt_stop(struct udevice *dev)
  90{
  91        struct orion_wdt_priv *priv = dev_get_priv(dev);
  92        u32 reg;
  93
  94        /* Disable reset on watchdog */
  95        reg = readl(priv->rstout_mask);
  96        reg |= RSTOUT_MASK_BIT;
  97        writel(reg, priv->rstout_mask);
  98
  99        reg = readl(priv->rstout);
 100        reg &= ~RSTOUT_ENABLE_BIT;
 101        writel(reg, priv->rstout);
 102
 103        /* Disable watchdog timer */
 104        reg = readl(priv->reg + TIMER_CTRL);
 105        reg &= ~WDT_ENABLE_BIT;
 106        writel(reg, priv->reg + TIMER_CTRL);
 107
 108        return 0;
 109}
 110
 111static inline bool save_reg_from_ofdata(struct udevice *dev, int index,
 112                                        void __iomem **reg, int *offset)
 113{
 114        fdt_addr_t addr;
 115        fdt_size_t off;
 116
 117        addr = fdtdec_get_addr_size_auto_noparent(
 118                gd->fdt_blob, dev_of_offset(dev), "reg", index, &off, true);
 119
 120        if (addr == FDT_ADDR_T_NONE)
 121                return false;
 122
 123        *reg = (void __iomem *) addr;
 124        if (offset)
 125                *offset = off;
 126
 127        return true;
 128}
 129
 130static int orion_wdt_ofdata_to_platdata(struct udevice *dev)
 131{
 132        struct orion_wdt_priv *priv = dev_get_priv(dev);
 133
 134        if (!save_reg_from_ofdata(dev, 0, &priv->reg,
 135                                  &priv->wdt_counter_offset))
 136                goto err;
 137
 138        if (!save_reg_from_ofdata(dev, 1, &priv->rstout, NULL))
 139                goto err;
 140
 141        if (!save_reg_from_ofdata(dev, 2, &priv->rstout_mask, NULL))
 142                goto err;
 143
 144        return 0;
 145err:
 146        debug("%s: Could not determine Orion wdt IO addresses\n", __func__);
 147        return -ENXIO;
 148}
 149
 150static int orion_wdt_probe(struct udevice *dev)
 151{
 152        debug("%s: Probing wdt%u\n", __func__, dev->seq);
 153        orion_wdt_stop(dev);
 154
 155        return 0;
 156}
 157
 158static const struct wdt_ops orion_wdt_ops = {
 159        .start = orion_wdt_start,
 160        .reset = orion_wdt_reset,
 161        .stop = orion_wdt_stop,
 162};
 163
 164static const struct udevice_id orion_wdt_ids[] = {
 165        { .compatible = "marvell,armada-380-wdt" },
 166        {}
 167};
 168
 169U_BOOT_DRIVER(orion_wdt) = {
 170        .name = "orion_wdt",
 171        .id = UCLASS_WDT,
 172        .of_match = orion_wdt_ids,
 173        .probe = orion_wdt_probe,
 174        .priv_auto_alloc_size = sizeof(struct orion_wdt_priv),
 175        .ofdata_to_platdata = orion_wdt_ofdata_to_platdata,
 176        .ops = &orion_wdt_ops,
 177};
 178