Home | History | Annotate | Download | only in watchdog
      1 /*
      2  * drivers/watchdog/orion_wdt.c
      3  *
      4  * Watchdog driver for Orion/Kirkwood processors
      5  *
      6  * Authors:	Tomas Hlavacek <tmshlvck (at) gmail.com>
      7  * 		Sylver Bruneau <sylver.bruneau (at) googlemail.com>
      8  * 		Marek Behun <marek.behun (at) 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 
     22 DECLARE_GLOBAL_DATA_PTR;
     23 
     24 struct 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 
     42 static 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 
     52 static 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 
     89 static 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 
    111 static 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 
    130 static 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;
    145 err:
    146 	debug("%s: Could not determine Orion wdt IO addresses\n", __func__);
    147 	return -ENXIO;
    148 }
    149 
    150 static 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 
    158 static const struct wdt_ops orion_wdt_ops = {
    159 	.start = orion_wdt_start,
    160 	.reset = orion_wdt_reset,
    161 	.stop = orion_wdt_stop,
    162 };
    163 
    164 static const struct udevice_id orion_wdt_ids[] = {
    165 	{ .compatible = "marvell,armada-380-wdt" },
    166 	{}
    167 };
    168 
    169 U_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