uboot/drivers/watchdog/sbsa_gwdt.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Watchdog driver for SBSA
   4 *
   5 * Copyright 2020 NXP
   6 */
   7
   8#include <asm/global_data.h>
   9#include <asm/io.h>
  10#include <common.h>
  11#include <dm/device.h>
  12#include <dm/fdtaddr.h>
  13#include <dm/read.h>
  14#include <linux/bitops.h>
  15#include <linux/err.h>
  16#include <watchdog.h>
  17#include <wdt.h>
  18
  19DECLARE_GLOBAL_DATA_PTR;
  20
  21/* SBSA Generic Watchdog register definitions */
  22/* refresh frame */
  23#define SBSA_GWDT_WRR           0x000
  24
  25/* control frame */
  26#define SBSA_GWDT_WCS           0x000
  27#define SBSA_GWDT_WOR           0x008
  28#define SBSA_GWDT_WCV           0x010
  29
  30/* refresh/control frame */
  31#define SBSA_GWDT_W_IIDR        0xfcc
  32#define SBSA_GWDT_IDR           0xfd0
  33
  34/* Watchdog Control and Status Register */
  35#define SBSA_GWDT_WCS_EN        BIT(0)
  36#define SBSA_GWDT_WCS_WS0       BIT(1)
  37#define SBSA_GWDT_WCS_WS1       BIT(2)
  38
  39struct sbsa_gwdt_priv {
  40        void __iomem *reg_refresh;
  41        void __iomem *reg_control;
  42};
  43
  44static int sbsa_gwdt_reset(struct udevice *dev)
  45{
  46        struct sbsa_gwdt_priv *priv = dev_get_priv(dev);
  47
  48        writel(0, priv->reg_refresh + SBSA_GWDT_WRR);
  49
  50        return 0;
  51}
  52
  53static int sbsa_gwdt_start(struct udevice *dev, u64 timeout, ulong flags)
  54{
  55        struct sbsa_gwdt_priv *priv = dev_get_priv(dev);
  56        u32 clk;
  57
  58        /*
  59         * it work in the single stage mode in u-boot,
  60         * The first signal (WS0) is ignored,
  61         * the timeout is (WOR * 2), so the WOR should be configured
  62         * to half value of timeout.
  63         */
  64        clk = get_tbclk();
  65        writel(clk / (2 * 1000) * timeout,
  66               priv->reg_control + SBSA_GWDT_WOR);
  67
  68        /* writing WCS will cause an explicit watchdog refresh */
  69        writel(SBSA_GWDT_WCS_EN, priv->reg_control + SBSA_GWDT_WCS);
  70
  71        return 0;
  72}
  73
  74static int sbsa_gwdt_stop(struct udevice *dev)
  75{
  76        struct sbsa_gwdt_priv *priv = dev_get_priv(dev);
  77
  78        writel(0, priv->reg_control + SBSA_GWDT_WCS);
  79
  80        return 0;
  81}
  82
  83static int sbsa_gwdt_expire_now(struct udevice *dev, ulong flags)
  84{
  85        sbsa_gwdt_start(dev, 0, flags);
  86
  87        return 0;
  88}
  89
  90static int sbsa_gwdt_probe(struct udevice *dev)
  91{
  92        debug("%s: Probing wdt%u (sbsa-gwdt)\n", __func__, dev_seq(dev));
  93
  94        return 0;
  95}
  96
  97static int sbsa_gwdt_of_to_plat(struct udevice *dev)
  98{
  99        struct sbsa_gwdt_priv *priv = dev_get_priv(dev);
 100
 101        priv->reg_control = (void __iomem *)dev_read_addr_index(dev, 0);
 102        if (IS_ERR(priv->reg_control))
 103                return PTR_ERR(priv->reg_control);
 104
 105        priv->reg_refresh = (void __iomem *)dev_read_addr_index(dev, 1);
 106        if (IS_ERR(priv->reg_refresh))
 107                return PTR_ERR(priv->reg_refresh);
 108
 109        return 0;
 110}
 111
 112static const struct wdt_ops sbsa_gwdt_ops = {
 113        .start = sbsa_gwdt_start,
 114        .reset = sbsa_gwdt_reset,
 115        .stop = sbsa_gwdt_stop,
 116        .expire_now = sbsa_gwdt_expire_now,
 117};
 118
 119static const struct udevice_id sbsa_gwdt_ids[] = {
 120        { .compatible = "arm,sbsa-gwdt" },
 121        {}
 122};
 123
 124U_BOOT_DRIVER(sbsa_gwdt) = {
 125        .name = "sbsa_gwdt",
 126        .id = UCLASS_WDT,
 127        .of_match = sbsa_gwdt_ids,
 128        .probe = sbsa_gwdt_probe,
 129        .priv_auto      = sizeof(struct sbsa_gwdt_priv),
 130        .of_to_plat = sbsa_gwdt_of_to_plat,
 131        .ops = &sbsa_gwdt_ops,
 132};
 133