1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2017 ��lvaro Fern��ndez Rojas <noltari@gmail.com> 4 * 5 * Derived from linux/drivers/watchdog/bcm63xx_wdt.c: 6 * Copyright (C) 2007 Miguel Gaio <miguel.gaio@efixo.com> 7 * Copyright (C) 2008 Florian Fainelli <florian@openwrt.org> 8 */ 9 10#include <dm.h> 11#include <log.h> 12#include <wdt.h> 13#include <clk.h> 14#include <asm/io.h> 15 16/* WDT Value register */ 17#define WDT_VAL_REG 0x0 18#define WDT_VAL_MIN 0x00000002 19#define WDT_VAL_MAX 0xfffffffe 20 21/* WDT Control register */ 22#define WDT_CTL_REG 0x4 23#define WDT_CTL_START1_MASK 0x0000ff00 24#define WDT_CTL_START2_MASK 0x000000ff 25#define WDT_CTL_STOP1_MASK 0x0000ee00 26#define WDT_CTL_STOP2_MASK 0x000000ee 27 28struct bcm6345_wdt_priv { 29 void __iomem *regs; 30 unsigned long clk_rate; 31}; 32 33static int bcm6345_wdt_reset(struct udevice *dev) 34{ 35 struct bcm6345_wdt_priv *priv = dev_get_priv(dev); 36 37 writel(WDT_CTL_START1_MASK, priv->regs + WDT_CTL_REG); 38 writel(WDT_CTL_START2_MASK, priv->regs + WDT_CTL_REG); 39 40 return 0; 41} 42 43static int bcm6345_wdt_start(struct udevice *dev, u64 timeout, ulong flags) 44{ 45 struct bcm6345_wdt_priv *priv = dev_get_priv(dev); 46 u32 val = priv->clk_rate / 1000 * timeout; 47 48 if (val < WDT_VAL_MIN) { 49 debug("watchdog won't fire with less than 2 ticks\n"); 50 val = WDT_VAL_MIN; 51 } else if (val > WDT_VAL_MAX) { 52 debug("maximum watchdog timeout exceeded\n"); 53 val = WDT_VAL_MAX; 54 } 55 56 writel(val, priv->regs + WDT_VAL_REG); 57 58 return bcm6345_wdt_reset(dev); 59} 60 61static int bcm6345_wdt_expire_now(struct udevice *dev, ulong flags) 62{ 63 return bcm6345_wdt_start(dev, WDT_VAL_MIN, flags); 64} 65 66static int bcm6345_wdt_stop(struct udevice *dev) 67{ 68 struct bcm6345_wdt_priv *priv = dev_get_priv(dev); 69 70 writel(WDT_CTL_STOP1_MASK, priv->regs + WDT_CTL_REG); 71 writel(WDT_CTL_STOP2_MASK, priv->regs + WDT_CTL_REG); 72 73 return 0; 74} 75 76static const struct wdt_ops bcm6345_wdt_ops = { 77 .expire_now = bcm6345_wdt_expire_now, 78 .reset = bcm6345_wdt_reset, 79 .start = bcm6345_wdt_start, 80 .stop = bcm6345_wdt_stop, 81}; 82 83static const struct udevice_id bcm6345_wdt_ids[] = { 84 { .compatible = "brcm,bcm6345-wdt" }, 85 { /* sentinel */ } 86}; 87 88static int bcm6345_wdt_probe(struct udevice *dev) 89{ 90 struct bcm6345_wdt_priv *priv = dev_get_priv(dev); 91 struct clk clk; 92 int ret; 93 94 priv->regs = dev_remap_addr(dev); 95 if (!priv->regs) 96 return -EINVAL; 97 98 ret = clk_get_by_index(dev, 0, &clk); 99 if (!ret) 100 priv->clk_rate = clk_get_rate(&clk); 101 else 102 return -EINVAL; 103 104 bcm6345_wdt_stop(dev); 105 106 return 0; 107} 108 109U_BOOT_DRIVER(wdt_bcm6345) = { 110 .name = "wdt_bcm6345", 111 .id = UCLASS_WDT, 112 .of_match = bcm6345_wdt_ids, 113 .ops = &bcm6345_wdt_ops, 114 .priv_auto = sizeof(struct bcm6345_wdt_priv), 115 .probe = bcm6345_wdt_probe, 116}; 117