Blame view
drivers/watchdog/orion_wdt.c
3.94 KB
2ab7704a6
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
/* * drivers/watchdog/orion_wdt.c * * Watchdog driver for Orion/Kirkwood processors * * Authors: Tomas Hlavacek <tmshlvck@gmail.com> * Sylver Bruneau <sylver.bruneau@googlemail.com> * Marek Behun <marek.behun@nic.cz> * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ #include <common.h> #include <dm.h> #include <wdt.h> #include <asm/io.h> #include <asm/arch/cpu.h> #include <asm/arch/soc.h> DECLARE_GLOBAL_DATA_PTR; struct orion_wdt_priv { void __iomem *reg; int wdt_counter_offset; void __iomem *rstout; void __iomem *rstout_mask; u32 timeout; }; #define RSTOUT_ENABLE_BIT BIT(8) #define RSTOUT_MASK_BIT BIT(10) #define WDT_ENABLE_BIT BIT(8) #define TIMER_CTRL 0x0000 #define TIMER_A370_STATUS 0x04 #define WDT_AXP_FIXED_ENABLE_BIT BIT(10) #define WDT_A370_EXPIRED BIT(31) static int orion_wdt_reset(struct udevice *dev) { struct orion_wdt_priv *priv = dev_get_priv(dev); /* Reload watchdog duration */ writel(priv->timeout, priv->reg + priv->wdt_counter_offset); return 0; } static int orion_wdt_start(struct udevice *dev, u64 timeout, ulong flags) { struct orion_wdt_priv *priv = dev_get_priv(dev); u32 reg; priv->timeout = (u32) timeout; /* Enable the fixed watchdog clock input */ reg = readl(priv->reg + TIMER_CTRL); reg |= WDT_AXP_FIXED_ENABLE_BIT; writel(reg, priv->reg + TIMER_CTRL); /* Set watchdog duration */ writel(priv->timeout, priv->reg + priv->wdt_counter_offset); /* Clear the watchdog expiration bit */ reg = readl(priv->reg + TIMER_A370_STATUS); reg &= ~WDT_A370_EXPIRED; writel(reg, priv->reg + TIMER_A370_STATUS); /* Enable watchdog timer */ reg = readl(priv->reg + TIMER_CTRL); reg |= WDT_ENABLE_BIT; writel(reg, priv->reg + TIMER_CTRL); /* Enable reset on watchdog */ reg = readl(priv->rstout); reg |= RSTOUT_ENABLE_BIT; writel(reg, priv->rstout); reg = readl(priv->rstout_mask); reg &= ~RSTOUT_MASK_BIT; writel(reg, priv->rstout_mask); return 0; } static int orion_wdt_stop(struct udevice *dev) { struct orion_wdt_priv *priv = dev_get_priv(dev); u32 reg; /* Disable reset on watchdog */ reg = readl(priv->rstout_mask); reg |= RSTOUT_MASK_BIT; writel(reg, priv->rstout_mask); reg = readl(priv->rstout); reg &= ~RSTOUT_ENABLE_BIT; writel(reg, priv->rstout); /* Disable watchdog timer */ reg = readl(priv->reg + TIMER_CTRL); reg &= ~WDT_ENABLE_BIT; writel(reg, priv->reg + TIMER_CTRL); return 0; } static inline bool save_reg_from_ofdata(struct udevice *dev, int index, void __iomem **reg, int *offset) { fdt_addr_t addr; fdt_size_t off; addr = fdtdec_get_addr_size_auto_noparent( gd->fdt_blob, dev_of_offset(dev), "reg", index, &off, true); if (addr == FDT_ADDR_T_NONE) return false; *reg = (void __iomem *) addr; if (offset) *offset = off; return true; } static int orion_wdt_ofdata_to_platdata(struct udevice *dev) { struct orion_wdt_priv *priv = dev_get_priv(dev); if (!save_reg_from_ofdata(dev, 0, &priv->reg, &priv->wdt_counter_offset)) goto err; if (!save_reg_from_ofdata(dev, 1, &priv->rstout, NULL)) goto err; if (!save_reg_from_ofdata(dev, 2, &priv->rstout_mask, NULL)) goto err; return 0; err: debug("%s: Could not determine Orion wdt IO addresses ", __func__); return -ENXIO; } static int orion_wdt_probe(struct udevice *dev) { debug("%s: Probing wdt%u ", __func__, dev->seq); orion_wdt_stop(dev); return 0; } static const struct wdt_ops orion_wdt_ops = { .start = orion_wdt_start, .reset = orion_wdt_reset, .stop = orion_wdt_stop, }; static const struct udevice_id orion_wdt_ids[] = { { .compatible = "marvell,armada-380-wdt" }, {} }; U_BOOT_DRIVER(orion_wdt) = { .name = "orion_wdt", .id = UCLASS_WDT, .of_match = orion_wdt_ids, .probe = orion_wdt_probe, .priv_auto_alloc_size = sizeof(struct orion_wdt_priv), .ofdata_to_platdata = orion_wdt_ofdata_to_platdata, .ops = &orion_wdt_ops, }; |