uboot/drivers/watchdog/sp805_wdt.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Watchdog driver for SP805 on some Layerscape SoC
   4 *
   5 * Copyright 2019 NXP
   6 */
   7
   8#include <asm/io.h>
   9#include <common.h>
  10#include <dm/device.h>
  11#include <dm/fdtaddr.h>
  12#include <dm/read.h>
  13#include <linux/bitops.h>
  14#include <watchdog.h>
  15#include <wdt.h>
  16
  17#define WDTLOAD                 0x000
  18#define WDTCONTROL              0x008
  19#define WDTINTCLR               0x00C
  20#define WDTLOCK                 0xC00
  21
  22#define TIME_OUT_MIN_MSECS      1
  23#define TIME_OUT_MAX_MSECS      120000
  24#define SYS_FSL_WDT_CLK_DIV     16
  25#define INT_ENABLE              BIT(0)
  26#define RESET_ENABLE            BIT(1)
  27#define DISABLE                 0
  28#define UNLOCK                  0x1ACCE551
  29#define LOCK                    0x00000001
  30#define INT_MASK                BIT(0)
  31
  32DECLARE_GLOBAL_DATA_PTR;
  33
  34struct sp805_wdt_priv {
  35        void __iomem *reg;
  36};
  37
  38static int sp805_wdt_reset(struct udevice *dev)
  39{
  40        struct sp805_wdt_priv *priv = dev_get_priv(dev);
  41
  42        writel(UNLOCK, priv->reg + WDTLOCK);
  43        writel(INT_MASK, priv->reg + WDTINTCLR);
  44        writel(LOCK, priv->reg + WDTLOCK);
  45        readl(priv->reg + WDTLOCK);
  46
  47        return 0;
  48}
  49
  50static int sp805_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
  51{
  52        u32 load_value;
  53        u32 load_time;
  54        struct sp805_wdt_priv *priv = dev_get_priv(dev);
  55
  56        load_time = (u32)timeout;
  57        if (timeout < TIME_OUT_MIN_MSECS)
  58                load_time = TIME_OUT_MIN_MSECS;
  59        else if (timeout > TIME_OUT_MAX_MSECS)
  60                load_time = TIME_OUT_MAX_MSECS;
  61        /* sp805 runs counter with given value twice, so when the max timeout is
  62         * set 120s, the gd->bus_clk is less than 1145MHz, the load_value will
  63         * not overflow.
  64         */
  65        load_value = (gd->bus_clk) /
  66                (2 * 1000 * SYS_FSL_WDT_CLK_DIV) * load_time;
  67
  68        writel(UNLOCK, priv->reg + WDTLOCK);
  69        writel(load_value, priv->reg + WDTLOAD);
  70        writel(INT_MASK, priv->reg + WDTINTCLR);
  71        writel(INT_ENABLE | RESET_ENABLE, priv->reg + WDTCONTROL);
  72        writel(LOCK, priv->reg + WDTLOCK);
  73        readl(priv->reg + WDTLOCK);
  74
  75        return 0;
  76}
  77
  78static int sp805_wdt_stop(struct udevice *dev)
  79{
  80        struct sp805_wdt_priv *priv = dev_get_priv(dev);
  81
  82        writel(UNLOCK, priv->reg + WDTLOCK);
  83        writel(DISABLE, priv->reg + WDTCONTROL);
  84        writel(LOCK, priv->reg + WDTLOCK);
  85        readl(priv->reg + WDTLOCK);
  86
  87        return 0;
  88}
  89
  90static int sp805_wdt_probe(struct udevice *dev)
  91{
  92        debug("%s: Probing wdt%u\n", __func__, dev->seq);
  93
  94        return 0;
  95}
  96
  97static int sp805_wdt_ofdata_to_platdata(struct udevice *dev)
  98{
  99        struct sp805_wdt_priv *priv = dev_get_priv(dev);
 100
 101        priv->reg = (void __iomem *)dev_read_addr(dev);
 102        if (IS_ERR(priv->reg))
 103                return PTR_ERR(priv->reg);
 104
 105        return 0;
 106}
 107
 108static const struct wdt_ops sp805_wdt_ops = {
 109        .start = sp805_wdt_start,
 110        .reset = sp805_wdt_reset,
 111        .stop = sp805_wdt_stop,
 112};
 113
 114static const struct udevice_id sp805_wdt_ids[] = {
 115        { .compatible = "arm,sp805-wdt" },
 116        {}
 117};
 118
 119U_BOOT_DRIVER(sp805_wdt) = {
 120        .name = "sp805_wdt",
 121        .id = UCLASS_WDT,
 122        .of_match = sp805_wdt_ids,
 123        .probe = sp805_wdt_probe,
 124        .priv_auto_alloc_size = sizeof(struct sp805_wdt_priv),
 125        .ofdata_to_platdata = sp805_wdt_ofdata_to_platdata,
 126        .ops = &sp805_wdt_ops,
 127};
 128