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 59 struct tegra_wdt { 60 struct watchdog_device wdd; 61 void __iomem *wdt_regs; 62 void __iomem *tmr_regs; 63 }; 64 65 #define WDT_HEARTBEAT 120 66 static int heartbeat = WDT_HEARTBEAT; 67 module_param(heartbeat, int, 0); 68 MODULE_PARM_DESC(heartbeat, 69 "Watchdog heartbeats in seconds. (default = " 70 __MODULE_STRING(WDT_HEARTBEAT) ")"); 71 72 static bool nowayout = WATCHDOG_NOWAYOUT; 73 module_param(nowayout, bool, 0); 74 MODULE_PARM_DESC(nowayout, 75 "Watchdog cannot be stopped once started (default=" 76 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 77 78 static 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 110 static 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 121 static 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 130 static 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 143 static 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 165 static 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 173 static 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 182 static int tegra_wdt_probe(struct platform_device *pdev) 183 { 184 struct watchdog_device *wdd; 185 struct tegra_wdt *wdt; 186 struct resource *res; 187 void __iomem *regs; 188 int ret; 189 190 /* This is the timer base. */ 191 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 192 regs = devm_ioremap_resource(&pdev->dev, res); 193 if (IS_ERR(regs)) 194 return PTR_ERR(regs); 195 196 /* 197 * Allocate our watchdog driver data, which has the 198 * struct watchdog_device nested within it. 199 */ 200 wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); 201 if (!wdt) 202 return -ENOMEM; 203 204 /* Initialize struct tegra_wdt. */ 205 wdt->wdt_regs = regs + WDT_BASE; 206 wdt->tmr_regs = regs + WDT_TIMER_BASE; 207 208 /* Initialize struct watchdog_device. */ 209 wdd = &wdt->wdd; 210 wdd->timeout = heartbeat; 211 wdd->info = &tegra_wdt_info; 212 wdd->ops = &tegra_wdt_ops; 213 wdd->min_timeout = MIN_WDT_TIMEOUT; 214 wdd->max_timeout = MAX_WDT_TIMEOUT; 215 wdd->parent = &pdev->dev; 216 217 watchdog_set_drvdata(wdd, wdt); 218 219 watchdog_set_nowayout(wdd, nowayout); 220 221 ret = devm_watchdog_register_device(&pdev->dev, wdd); 222 if (ret) { 223 dev_err(&pdev->dev, 224 "failed to register watchdog device\n"); 225 return ret; 226 } 227 228 platform_set_drvdata(pdev, wdt); 229 230 dev_info(&pdev->dev, 231 "initialized (heartbeat = %d sec, nowayout = %d)\n", 232 heartbeat, nowayout); 233 234 return 0; 235 } 236 237 static int tegra_wdt_remove(struct platform_device *pdev) 238 { 239 struct tegra_wdt *wdt = platform_get_drvdata(pdev); 240 241 tegra_wdt_stop(&wdt->wdd); 242 243 dev_info(&pdev->dev, "removed wdt\n"); 244 245 return 0; 246 } 247 248 #ifdef CONFIG_PM_SLEEP 249 static int tegra_wdt_runtime_suspend(struct device *dev) 250 { 251 struct tegra_wdt *wdt = dev_get_drvdata(dev); 252 253 if (watchdog_active(&wdt->wdd)) 254 tegra_wdt_stop(&wdt->wdd); 255 256 return 0; 257 } 258 259 static int tegra_wdt_runtime_resume(struct device *dev) 260 { 261 struct tegra_wdt *wdt = dev_get_drvdata(dev); 262 263 if (watchdog_active(&wdt->wdd)) 264 tegra_wdt_start(&wdt->wdd); 265 266 return 0; 267 } 268 #endif 269 270 static const struct of_device_id tegra_wdt_of_match[] = { 271 { .compatible = "nvidia,tegra30-timer", }, 272 { }, 273 }; 274 MODULE_DEVICE_TABLE(of, tegra_wdt_of_match); 275 276 static const struct dev_pm_ops tegra_wdt_pm_ops = { 277 SET_SYSTEM_SLEEP_PM_OPS(tegra_wdt_runtime_suspend, 278 tegra_wdt_runtime_resume) 279 }; 280 281 static struct platform_driver tegra_wdt_driver = { 282 .probe = tegra_wdt_probe, 283 .remove = tegra_wdt_remove, 284 .driver = { 285 .name = "tegra-wdt", 286 .pm = &tegra_wdt_pm_ops, 287 .of_match_table = tegra_wdt_of_match, 288 }, 289 }; 290 module_platform_driver(tegra_wdt_driver); 291 292 MODULE_AUTHOR("NVIDIA Corporation"); 293 MODULE_DESCRIPTION("Tegra Watchdog Driver"); 294 MODULE_LICENSE("GPL v2"); 295