uboot/drivers/watchdog/ast_wdt.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright 2017 Google, Inc
   4 */
   5
   6#include <common.h>
   7#include <dm.h>
   8#include <errno.h>
   9#include <wdt.h>
  10#include <asm/io.h>
  11#include <asm/arch/wdt.h>
  12
  13#define WDT_AST2500     2500
  14#define WDT_AST2400     2400
  15
  16struct ast_wdt_priv {
  17        struct ast_wdt *regs;
  18};
  19
  20static int ast_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
  21{
  22        struct ast_wdt_priv *priv = dev_get_priv(dev);
  23        ulong driver_data = dev_get_driver_data(dev);
  24        u32 reset_mode = ast_reset_mode_from_flags(flags);
  25
  26        /* 32 bits at 1MHz is 4294967ms */
  27        timeout = min_t(u64, timeout, 4294967);
  28
  29        /* WDT counts in ticks of 1MHz clock. 1ms / 1e3 * 1e6 */
  30        timeout *= 1000;
  31
  32        clrsetbits_le32(&priv->regs->ctrl,
  33                        WDT_CTRL_RESET_MASK << WDT_CTRL_RESET_MODE_SHIFT,
  34                        reset_mode << WDT_CTRL_RESET_MODE_SHIFT);
  35
  36        if (driver_data >= WDT_AST2500 && reset_mode == WDT_CTRL_RESET_SOC)
  37                writel(ast_reset_mask_from_flags(flags),
  38                       &priv->regs->reset_mask);
  39
  40        writel((u32) timeout, &priv->regs->counter_reload_val);
  41        writel(WDT_COUNTER_RESTART_VAL, &priv->regs->counter_restart);
  42        /*
  43         * Setting CLK1MHZ bit is just for compatibility with ast2400 part.
  44         * On ast2500 watchdog timer clock is fixed at 1MHz and the bit is
  45         * read-only
  46         */
  47        setbits_le32(&priv->regs->ctrl,
  48                     WDT_CTRL_EN | WDT_CTRL_RESET | WDT_CTRL_CLK1MHZ);
  49
  50        return 0;
  51}
  52
  53static int ast_wdt_stop(struct udevice *dev)
  54{
  55        struct ast_wdt_priv *priv = dev_get_priv(dev);
  56
  57        clrbits_le32(&priv->regs->ctrl, WDT_CTRL_EN);
  58
  59        writel(WDT_RESET_DEFAULT, &priv->regs->reset_mask);
  60        return 0;
  61}
  62
  63static int ast_wdt_reset(struct udevice *dev)
  64{
  65        struct ast_wdt_priv *priv = dev_get_priv(dev);
  66
  67        writel(WDT_COUNTER_RESTART_VAL, &priv->regs->counter_restart);
  68
  69        return 0;
  70}
  71
  72static int ast_wdt_expire_now(struct udevice *dev, ulong flags)
  73{
  74        struct ast_wdt_priv *priv = dev_get_priv(dev);
  75        int ret;
  76
  77        ret = ast_wdt_start(dev, 1, flags);
  78        if (ret)
  79                return ret;
  80
  81        while (readl(&priv->regs->ctrl) & WDT_CTRL_EN)
  82                ;
  83
  84        return ast_wdt_stop(dev);
  85}
  86
  87static int ast_wdt_ofdata_to_platdata(struct udevice *dev)
  88{
  89        struct ast_wdt_priv *priv = dev_get_priv(dev);
  90
  91        priv->regs = devfdt_get_addr_ptr(dev);
  92        if (IS_ERR(priv->regs))
  93                return PTR_ERR(priv->regs);
  94
  95        return 0;
  96}
  97
  98static const struct wdt_ops ast_wdt_ops = {
  99        .start = ast_wdt_start,
 100        .reset = ast_wdt_reset,
 101        .stop = ast_wdt_stop,
 102        .expire_now = ast_wdt_expire_now,
 103};
 104
 105static const struct udevice_id ast_wdt_ids[] = {
 106        { .compatible = "aspeed,wdt", .data = WDT_AST2500 },
 107        { .compatible = "aspeed,ast2500-wdt", .data = WDT_AST2500 },
 108        { .compatible = "aspeed,ast2400-wdt", .data = WDT_AST2400 },
 109        {}
 110};
 111
 112static int ast_wdt_probe(struct udevice *dev)
 113{
 114        debug("%s() wdt%u\n", __func__, dev->seq);
 115        ast_wdt_stop(dev);
 116
 117        return 0;
 118}
 119
 120U_BOOT_DRIVER(ast_wdt) = {
 121        .name = "ast_wdt",
 122        .id = UCLASS_WDT,
 123        .of_match = ast_wdt_ids,
 124        .probe = ast_wdt_probe,
 125        .priv_auto_alloc_size = sizeof(struct ast_wdt_priv),
 126        .ofdata_to_platdata = ast_wdt_ofdata_to_platdata,
 127        .ops = &ast_wdt_ops,
 128};
 129