1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Watchdog driver for the K3 RTI module 4 * 5 * (c) Copyright 2019-2020 Texas Instruments Inc. 6 * All rights reserved. 7 */ 8 9 #include <linux/clk.h> 10 #include <linux/device.h> 11 #include <linux/err.h> 12 #include <linux/io.h> 13 #include <linux/kernel.h> 14 #include <linux/mod_devicetable.h> 15 #include <linux/module.h> 16 #include <linux/moduleparam.h> 17 #include <linux/of.h> 18 #include <linux/of_reserved_mem.h> 19 #include <linux/platform_device.h> 20 #include <linux/pm_runtime.h> 21 #include <linux/types.h> 22 #include <linux/watchdog.h> 23 24 #define DEFAULT_HEARTBEAT 60 25 26 /* Max heartbeat is calculated at 32kHz source clock */ 27 #define MAX_HEARTBEAT 1000 28 29 /* Timer register set definition */ 30 #define RTIDWDCTRL 0x90 31 #define RTIDWDPRLD 0x94 32 #define RTIWDSTATUS 0x98 33 #define RTIWDKEY 0x9c 34 #define RTIDWDCNTR 0xa0 35 #define RTIWWDRXCTRL 0xa4 36 #define RTIWWDSIZECTRL 0xa8 37 38 #define RTIWWDRX_NMI 0xa 39 40 #define RTIWWDSIZE_50P 0x50 41 #define RTIWWDSIZE_25P 0x500 42 #define RTIWWDSIZE_12P5 0x5000 43 #define RTIWWDSIZE_6P25 0x50000 44 #define RTIWWDSIZE_3P125 0x500000 45 46 #define WDENABLE_KEY 0xa98559da 47 48 #define WDKEY_SEQ0 0xe51a 49 #define WDKEY_SEQ1 0xa35c 50 51 #define WDT_PRELOAD_SHIFT 13 52 53 #define WDT_PRELOAD_MAX 0xfff 54 55 #define DWDST BIT(1) 56 57 #define PON_REASON_SOF_NUM 0xBBBBCCCC 58 #define PON_REASON_MAGIC_NUM 0xDDDDDDDD 59 #define PON_REASON_EOF_NUM 0xCCCCBBBB 60 #define RESERVED_MEM_MIN_SIZE 12 61 62 #define MAX_HW_ERROR 250 63 64 static int heartbeat; 65 66 /* 67 * struct to hold data for each WDT device 68 * @base - base io address of WD device 69 * @freq - source clock frequency of WDT 70 * @wdd - hold watchdog device as is in WDT core 71 */ 72 struct rti_wdt_device { 73 void __iomem *base; 74 unsigned long freq; 75 struct watchdog_device wdd; 76 }; 77 78 static int rti_wdt_start(struct watchdog_device *wdd) 79 { 80 u32 timer_margin; 81 struct rti_wdt_device *wdt = watchdog_get_drvdata(wdd); 82 int ret; 83 84 ret = pm_runtime_resume_and_get(wdd->parent); 85 if (ret) 86 return ret; 87 88 /* set timeout period */ 89 timer_margin = (u64)wdd->timeout * wdt->freq; 90 timer_margin >>= WDT_PRELOAD_SHIFT; 91 if (timer_margin > WDT_PRELOAD_MAX) 92 timer_margin = WDT_PRELOAD_MAX; 93 writel_relaxed(timer_margin, wdt->base + RTIDWDPRLD); 94 95 /* 96 * RTI only supports a windowed mode, where the watchdog can only 97 * be petted during the open window; not too early or not too late. 98 * The HW configuration options only allow for the open window size 99 * to be 50% or less than that; we obviouly want to configure the open 100 * window as large as possible so we select the 50% option. 101 */ 102 wdd->min_hw_heartbeat_ms = 520 * wdd->timeout + MAX_HW_ERROR; 103 104 /* Generate NMI when wdt expires */ 105 writel_relaxed(RTIWWDRX_NMI, wdt->base + RTIWWDRXCTRL); 106 107 /* Open window size 50%; this is the largest window size available */ 108 writel_relaxed(RTIWWDSIZE_50P, wdt->base + RTIWWDSIZECTRL); 109 110 readl_relaxed(wdt->base + RTIWWDSIZECTRL); 111 112 /* enable watchdog */ 113 writel_relaxed(WDENABLE_KEY, wdt->base + RTIDWDCTRL); 114 return 0; 115 } 116 117 static int rti_wdt_ping(struct watchdog_device *wdd) 118 { 119 struct rti_wdt_device *wdt = watchdog_get_drvdata(wdd); 120 121 /* put watchdog in service state */ 122 writel_relaxed(WDKEY_SEQ0, wdt->base + RTIWDKEY); 123 /* put watchdog in active state */ 124 writel_relaxed(WDKEY_SEQ1, wdt->base + RTIWDKEY); 125 126 return 0; 127 } 128 129 static int rti_wdt_setup_hw_hb(struct watchdog_device *wdd, u32 wsize) 130 { 131 /* 132 * RTI only supports a windowed mode, where the watchdog can only 133 * be petted during the open window; not too early or not too late. 134 * The HW configuration options only allow for the open window size 135 * to be 50% or less than that. 136 * To avoid any glitches, we accommodate 2% + max hardware error 137 * safety margin. 138 */ 139 switch (wsize) { 140 case RTIWWDSIZE_50P: 141 /* 50% open window => 52% min heartbeat */ 142 wdd->min_hw_heartbeat_ms = 520 * heartbeat + MAX_HW_ERROR; 143 break; 144 145 case RTIWWDSIZE_25P: 146 /* 25% open window => 77% min heartbeat */ 147 wdd->min_hw_heartbeat_ms = 770 * heartbeat + MAX_HW_ERROR; 148 break; 149 150 case RTIWWDSIZE_12P5: 151 /* 12.5% open window => 89.5% min heartbeat */ 152 wdd->min_hw_heartbeat_ms = 895 * heartbeat + MAX_HW_ERROR; 153 break; 154 155 case RTIWWDSIZE_6P25: 156 /* 6.5% open window => 95.5% min heartbeat */ 157 wdd->min_hw_heartbeat_ms = 955 * heartbeat + MAX_HW_ERROR; 158 break; 159 160 case RTIWWDSIZE_3P125: 161 /* 3.125% open window => 98.9% min heartbeat */ 162 wdd->min_hw_heartbeat_ms = 989 * heartbeat + MAX_HW_ERROR; 163 break; 164 165 default: 166 return -EINVAL; 167 } 168 169 return 0; 170 } 171 172 static unsigned int rti_wdt_get_timeleft_ms(struct watchdog_device *wdd) 173 { 174 u64 timer_counter; 175 u32 val; 176 struct rti_wdt_device *wdt = watchdog_get_drvdata(wdd); 177 178 /* if timeout has occurred then return 0 */ 179 val = readl_relaxed(wdt->base + RTIWDSTATUS); 180 if (val & DWDST) 181 return 0; 182 183 timer_counter = readl_relaxed(wdt->base + RTIDWDCNTR); 184 185 timer_counter *= 1000; 186 187 do_div(timer_counter, wdt->freq); 188 189 return timer_counter; 190 } 191 192 static unsigned int rti_wdt_get_timeleft(struct watchdog_device *wdd) 193 { 194 return rti_wdt_get_timeleft_ms(wdd) / 1000; 195 } 196 197 static const struct watchdog_info rti_wdt_info = { 198 .options = WDIOF_KEEPALIVEPING, 199 .identity = "K3 RTI Watchdog", 200 }; 201 202 static const struct watchdog_ops rti_wdt_ops = { 203 .owner = THIS_MODULE, 204 .start = rti_wdt_start, 205 .ping = rti_wdt_ping, 206 .get_timeleft = rti_wdt_get_timeleft, 207 }; 208 209 static int rti_wdt_probe(struct platform_device *pdev) 210 { 211 int ret = 0; 212 struct device *dev = &pdev->dev; 213 struct watchdog_device *wdd; 214 struct rti_wdt_device *wdt; 215 struct clk *clk; 216 u32 last_ping = 0; 217 u32 reserved_mem_size; 218 struct resource res; 219 u32 *vaddr; 220 u64 paddr; 221 222 wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL); 223 if (!wdt) 224 return -ENOMEM; 225 226 clk = clk_get(dev, NULL); 227 if (IS_ERR(clk)) 228 return dev_err_probe(dev, PTR_ERR(clk), "failed to get clock\n"); 229 230 wdt->freq = clk_get_rate(clk); 231 232 clk_put(clk); 233 234 if (!wdt->freq) { 235 dev_err(dev, "Failed to get fck rate.\n"); 236 return -EINVAL; 237 } 238 239 pm_runtime_enable(dev); 240 ret = pm_runtime_resume_and_get(dev); 241 if (ret < 0) { 242 pm_runtime_disable(&pdev->dev); 243 return dev_err_probe(dev, ret, "runtime pm failed\n"); 244 } 245 246 platform_set_drvdata(pdev, wdt); 247 248 wdd = &wdt->wdd; 249 wdd->info = &rti_wdt_info; 250 wdd->ops = &rti_wdt_ops; 251 wdd->min_timeout = 1; 252 wdd->max_hw_heartbeat_ms = (WDT_PRELOAD_MAX << WDT_PRELOAD_SHIFT) / 253 wdt->freq * 1000; 254 wdd->timeout = DEFAULT_HEARTBEAT; 255 wdd->parent = dev; 256 257 watchdog_set_drvdata(wdd, wdt); 258 watchdog_set_nowayout(wdd, 1); 259 watchdog_set_restart_priority(wdd, 128); 260 261 wdt->base = devm_platform_ioremap_resource(pdev, 0); 262 if (IS_ERR(wdt->base)) { 263 ret = PTR_ERR(wdt->base); 264 goto err_iomap; 265 } 266 267 if (readl(wdt->base + RTIDWDCTRL) == WDENABLE_KEY) { 268 int preset_heartbeat; 269 u32 time_left_ms; 270 u64 heartbeat_ms; 271 u32 wsize; 272 273 set_bit(WDOG_HW_RUNNING, &wdd->status); 274 time_left_ms = rti_wdt_get_timeleft_ms(wdd); 275 /* AM62x TRM: texp = (RTIDWDPRLD + 1) * (2^13) / RTICLK1 */ 276 heartbeat_ms = readl(wdt->base + RTIDWDPRLD) + 1; 277 heartbeat_ms <<= WDT_PRELOAD_SHIFT; 278 heartbeat_ms *= 1000; 279 do_div(heartbeat_ms, wdt->freq); 280 preset_heartbeat = heartbeat_ms + 500; 281 preset_heartbeat /= 1000; 282 if (preset_heartbeat != heartbeat) 283 dev_warn(dev, "watchdog already running, ignoring heartbeat config!\n"); 284 285 heartbeat = preset_heartbeat; 286 287 wsize = readl(wdt->base + RTIWWDSIZECTRL); 288 ret = rti_wdt_setup_hw_hb(wdd, wsize); 289 if (ret) { 290 dev_err(dev, "bad window size.\n"); 291 goto err_iomap; 292 } 293 294 last_ping = heartbeat_ms - time_left_ms; 295 if (time_left_ms > heartbeat_ms) { 296 dev_warn(dev, "time_left > heartbeat? Assuming last ping just before now.\n"); 297 last_ping = 0; 298 } 299 } 300 301 ret = of_reserved_mem_region_to_resource(pdev->dev.of_node, 0, &res); 302 if (!ret) { 303 /* 304 * If reserved memory is defined for watchdog reset cause. 305 * Readout the Power-on(PON) reason and pass to bootstatus. 306 */ 307 paddr = res.start; 308 reserved_mem_size = resource_size(&res); 309 if (reserved_mem_size < RESERVED_MEM_MIN_SIZE) { 310 dev_err(dev, "The size of reserved memory is too small.\n"); 311 ret = -EINVAL; 312 goto err_iomap; 313 } 314 315 vaddr = memremap(paddr, reserved_mem_size, MEMREMAP_WB); 316 if (!vaddr) { 317 dev_err(dev, "Failed to map memory-region.\n"); 318 ret = -ENOMEM; 319 goto err_iomap; 320 } 321 322 if (vaddr[0] == PON_REASON_SOF_NUM && 323 vaddr[1] == PON_REASON_MAGIC_NUM && 324 vaddr[2] == PON_REASON_EOF_NUM) { 325 wdd->bootstatus |= WDIOF_CARDRESET; 326 } 327 memset(vaddr, 0, reserved_mem_size); 328 memunmap(vaddr); 329 } 330 331 watchdog_init_timeout(wdd, heartbeat, dev); 332 333 ret = watchdog_register_device(wdd); 334 if (ret) 335 goto err_iomap; 336 337 if (last_ping) 338 watchdog_set_last_hw_keepalive(wdd, last_ping); 339 340 if (!watchdog_hw_running(wdd)) 341 pm_runtime_put_sync(&pdev->dev); 342 343 return 0; 344 345 err_iomap: 346 pm_runtime_put_sync(&pdev->dev); 347 pm_runtime_disable(&pdev->dev); 348 349 return ret; 350 } 351 352 static void rti_wdt_remove(struct platform_device *pdev) 353 { 354 struct rti_wdt_device *wdt = platform_get_drvdata(pdev); 355 356 watchdog_unregister_device(&wdt->wdd); 357 358 if (!pm_runtime_suspended(&pdev->dev)) 359 pm_runtime_put(&pdev->dev); 360 361 pm_runtime_disable(&pdev->dev); 362 } 363 364 static const struct of_device_id rti_wdt_of_match[] = { 365 { .compatible = "ti,j7-rti-wdt", }, 366 {}, 367 }; 368 MODULE_DEVICE_TABLE(of, rti_wdt_of_match); 369 370 static struct platform_driver rti_wdt_driver = { 371 .driver = { 372 .name = "rti-wdt", 373 .of_match_table = rti_wdt_of_match, 374 }, 375 .probe = rti_wdt_probe, 376 .remove = rti_wdt_remove, 377 }; 378 379 module_platform_driver(rti_wdt_driver); 380 381 MODULE_AUTHOR("Tero Kristo <t-kristo@ti.com>"); 382 MODULE_DESCRIPTION("K3 RTI Watchdog Driver"); 383 384 module_param(heartbeat, int, 0); 385 MODULE_PARM_DESC(heartbeat, 386 "Watchdog heartbeat period in seconds from 1 to " 387 __MODULE_STRING(MAX_HEARTBEAT) ", default " 388 __MODULE_STRING(DEFAULT_HEARTBEAT)); 389 390 MODULE_LICENSE("GPL"); 391 MODULE_ALIAS("platform:rti-wdt"); 392