tegra_wdt.c (7119B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. 4 */ 5 6#include <linux/kernel.h> 7#include <linux/module.h> 8#include <linux/interrupt.h> 9#include <linux/io.h> 10#include <linux/of.h> 11#include <linux/platform_device.h> 12#include <linux/watchdog.h> 13 14/* minimum and maximum watchdog trigger timeout, in seconds */ 15#define MIN_WDT_TIMEOUT 1 16#define MAX_WDT_TIMEOUT 255 17 18/* 19 * Base of the WDT registers, from the timer base address. There are 20 * actually 5 watchdogs that can be configured (by pairing with an available 21 * timer), at bases 0x100 + (WDT ID) * 0x20, where WDT ID is 0 through 4. 22 * This driver only configures the first watchdog (WDT ID 0). 23 */ 24#define WDT_BASE 0x100 25#define WDT_ID 0 26 27/* 28 * Register base of the timer that's selected for pairing with the watchdog. 29 * This driver arbitrarily uses timer 5, which is currently unused by 30 * other drivers (in particular, the Tegra clocksource driver). If this 31 * needs to change, take care that the new timer is not used by the 32 * clocksource driver. 33 */ 34#define WDT_TIMER_BASE 0x60 35#define WDT_TIMER_ID 5 36 37/* WDT registers */ 38#define WDT_CFG 0x0 39#define WDT_CFG_PERIOD_SHIFT 4 40#define WDT_CFG_PERIOD_MASK 0xff 41#define WDT_CFG_INT_EN (1 << 12) 42#define WDT_CFG_PMC2CAR_RST_EN (1 << 15) 43#define WDT_STS 0x4 44#define WDT_STS_COUNT_SHIFT 4 45#define WDT_STS_COUNT_MASK 0xff 46#define WDT_STS_EXP_SHIFT 12 47#define WDT_STS_EXP_MASK 0x3 48#define WDT_CMD 0x8 49#define WDT_CMD_START_COUNTER (1 << 0) 50#define WDT_CMD_DISABLE_COUNTER (1 << 1) 51#define WDT_UNLOCK (0xc) 52#define WDT_UNLOCK_PATTERN (0xc45a << 0) 53 54/* Timer registers */ 55#define TIMER_PTV 0x0 56#define TIMER_EN (1 << 31) 57#define TIMER_PERIODIC (1 << 30) 58 59struct tegra_wdt { 60 struct watchdog_device wdd; 61 void __iomem *wdt_regs; 62 void __iomem *tmr_regs; 63}; 64 65#define WDT_HEARTBEAT 120 66static int heartbeat = WDT_HEARTBEAT; 67module_param(heartbeat, int, 0); 68MODULE_PARM_DESC(heartbeat, 69 "Watchdog heartbeats in seconds. (default = " 70 __MODULE_STRING(WDT_HEARTBEAT) ")"); 71 72static bool nowayout = WATCHDOG_NOWAYOUT; 73module_param(nowayout, bool, 0); 74MODULE_PARM_DESC(nowayout, 75 "Watchdog cannot be stopped once started (default=" 76 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 77 78static int tegra_wdt_start(struct watchdog_device *wdd) 79{ 80 struct tegra_wdt *wdt = watchdog_get_drvdata(wdd); 81 u32 val; 82 83 /* 84 * This thing has a fixed 1MHz clock. Normally, we would set the 85 * period to 1 second by writing 1000000ul, but the watchdog system 86 * reset actually occurs on the 4th expiration of this counter, 87 * so we set the period to 1/4 of this amount. 88 */ 89 val = 1000000ul / 4; 90 val |= (TIMER_EN | TIMER_PERIODIC); 91 writel(val, wdt->tmr_regs + TIMER_PTV); 92 93 /* 94 * Set number of periods and start counter. 95 * 96 * Interrupt handler is not required for user space 97 * WDT accesses, since the caller is responsible to ping the 98 * WDT to reset the counter before expiration, through ioctls. 99 */ 100 val = WDT_TIMER_ID | 101 (wdd->timeout << WDT_CFG_PERIOD_SHIFT) | 102 WDT_CFG_PMC2CAR_RST_EN; 103 writel(val, wdt->wdt_regs + WDT_CFG); 104 105 writel(WDT_CMD_START_COUNTER, wdt->wdt_regs + WDT_CMD); 106 107 return 0; 108} 109 110static int tegra_wdt_stop(struct watchdog_device *wdd) 111{ 112 struct tegra_wdt *wdt = watchdog_get_drvdata(wdd); 113 114 writel(WDT_UNLOCK_PATTERN, wdt->wdt_regs + WDT_UNLOCK); 115 writel(WDT_CMD_DISABLE_COUNTER, wdt->wdt_regs + WDT_CMD); 116 writel(0, wdt->tmr_regs + TIMER_PTV); 117 118 return 0; 119} 120 121static int tegra_wdt_ping(struct watchdog_device *wdd) 122{ 123 struct tegra_wdt *wdt = watchdog_get_drvdata(wdd); 124 125 writel(WDT_CMD_START_COUNTER, wdt->wdt_regs + WDT_CMD); 126 127 return 0; 128} 129 130static int tegra_wdt_set_timeout(struct watchdog_device *wdd, 131 unsigned int timeout) 132{ 133 wdd->timeout = timeout; 134 135 if (watchdog_active(wdd)) { 136 tegra_wdt_stop(wdd); 137 return tegra_wdt_start(wdd); 138 } 139 140 return 0; 141} 142 143static unsigned int tegra_wdt_get_timeleft(struct watchdog_device *wdd) 144{ 145 struct tegra_wdt *wdt = watchdog_get_drvdata(wdd); 146 u32 val; 147 int count; 148 int exp; 149 150 val = readl(wdt->wdt_regs + WDT_STS); 151 152 /* Current countdown (from timeout) */ 153 count = (val >> WDT_STS_COUNT_SHIFT) & WDT_STS_COUNT_MASK; 154 155 /* Number of expirations (we are waiting for the 4th expiration) */ 156 exp = (val >> WDT_STS_EXP_SHIFT) & WDT_STS_EXP_MASK; 157 158 /* 159 * The entire thing is divided by 4 because we are ticking down 4 times 160 * faster due to needing to wait for the 4th expiration. 161 */ 162 return (((3 - exp) * wdd->timeout) + count) / 4; 163} 164 165static const struct watchdog_info tegra_wdt_info = { 166 .options = WDIOF_SETTIMEOUT | 167 WDIOF_MAGICCLOSE | 168 WDIOF_KEEPALIVEPING, 169 .firmware_version = 0, 170 .identity = "Tegra Watchdog", 171}; 172 173static const struct watchdog_ops tegra_wdt_ops = { 174 .owner = THIS_MODULE, 175 .start = tegra_wdt_start, 176 .stop = tegra_wdt_stop, 177 .ping = tegra_wdt_ping, 178 .set_timeout = tegra_wdt_set_timeout, 179 .get_timeleft = tegra_wdt_get_timeleft, 180}; 181 182static int tegra_wdt_probe(struct platform_device *pdev) 183{ 184 struct device *dev = &pdev->dev; 185 struct watchdog_device *wdd; 186 struct tegra_wdt *wdt; 187 void __iomem *regs; 188 int ret; 189 190 /* This is the timer base. */ 191 regs = devm_platform_ioremap_resource(pdev, 0); 192 if (IS_ERR(regs)) 193 return PTR_ERR(regs); 194 195 /* 196 * Allocate our watchdog driver data, which has the 197 * struct watchdog_device nested within it. 198 */ 199 wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL); 200 if (!wdt) 201 return -ENOMEM; 202 203 /* Initialize struct tegra_wdt. */ 204 wdt->wdt_regs = regs + WDT_BASE; 205 wdt->tmr_regs = regs + WDT_TIMER_BASE; 206 207 /* Initialize struct watchdog_device. */ 208 wdd = &wdt->wdd; 209 wdd->timeout = heartbeat; 210 wdd->info = &tegra_wdt_info; 211 wdd->ops = &tegra_wdt_ops; 212 wdd->min_timeout = MIN_WDT_TIMEOUT; 213 wdd->max_timeout = MAX_WDT_TIMEOUT; 214 wdd->parent = dev; 215 216 watchdog_set_drvdata(wdd, wdt); 217 218 watchdog_set_nowayout(wdd, nowayout); 219 220 watchdog_stop_on_unregister(wdd); 221 ret = devm_watchdog_register_device(dev, wdd); 222 if (ret) 223 return ret; 224 225 platform_set_drvdata(pdev, wdt); 226 227 dev_info(dev, "initialized (heartbeat = %d sec, nowayout = %d)\n", 228 heartbeat, nowayout); 229 230 return 0; 231} 232 233#ifdef CONFIG_PM_SLEEP 234static int tegra_wdt_runtime_suspend(struct device *dev) 235{ 236 struct tegra_wdt *wdt = dev_get_drvdata(dev); 237 238 if (watchdog_active(&wdt->wdd)) 239 tegra_wdt_stop(&wdt->wdd); 240 241 return 0; 242} 243 244static int tegra_wdt_runtime_resume(struct device *dev) 245{ 246 struct tegra_wdt *wdt = dev_get_drvdata(dev); 247 248 if (watchdog_active(&wdt->wdd)) 249 tegra_wdt_start(&wdt->wdd); 250 251 return 0; 252} 253#endif 254 255static const struct of_device_id tegra_wdt_of_match[] = { 256 { .compatible = "nvidia,tegra30-timer", }, 257 { }, 258}; 259MODULE_DEVICE_TABLE(of, tegra_wdt_of_match); 260 261static const struct dev_pm_ops tegra_wdt_pm_ops = { 262 SET_SYSTEM_SLEEP_PM_OPS(tegra_wdt_runtime_suspend, 263 tegra_wdt_runtime_resume) 264}; 265 266static struct platform_driver tegra_wdt_driver = { 267 .probe = tegra_wdt_probe, 268 .driver = { 269 .name = "tegra-wdt", 270 .pm = &tegra_wdt_pm_ops, 271 .of_match_table = tegra_wdt_of_match, 272 }, 273}; 274module_platform_driver(tegra_wdt_driver); 275 276MODULE_AUTHOR("NVIDIA Corporation"); 277MODULE_DESCRIPTION("Tegra Watchdog Driver"); 278MODULE_LICENSE("GPL v2");