rave-sp-wdt.c (8288B)
1// SPDX-License-Identifier: GPL-2.0+ 2 3/* 4 * Driver for watchdog aspect of for Zodiac Inflight Innovations RAVE 5 * Supervisory Processor(SP) MCU 6 * 7 * Copyright (C) 2017 Zodiac Inflight Innovation 8 * 9 */ 10 11#include <linux/delay.h> 12#include <linux/kernel.h> 13#include <linux/mfd/rave-sp.h> 14#include <linux/module.h> 15#include <linux/nvmem-consumer.h> 16#include <linux/of_device.h> 17#include <linux/platform_device.h> 18#include <linux/reboot.h> 19#include <linux/slab.h> 20#include <linux/watchdog.h> 21 22enum { 23 RAVE_SP_RESET_BYTE = 1, 24 RAVE_SP_RESET_REASON_NORMAL = 0, 25 RAVE_SP_RESET_DELAY_MS = 500, 26}; 27 28/** 29 * struct rave_sp_wdt_variant - RAVE SP watchdog variant 30 * 31 * @max_timeout: Largest possible watchdog timeout setting 32 * @min_timeout: Smallest possible watchdog timeout setting 33 * 34 * @configure: Function to send configuration command 35 * @restart: Function to send "restart" command 36 */ 37struct rave_sp_wdt_variant { 38 unsigned int max_timeout; 39 unsigned int min_timeout; 40 41 int (*configure)(struct watchdog_device *, bool); 42 int (*restart)(struct watchdog_device *); 43}; 44 45/** 46 * struct rave_sp_wdt - RAVE SP watchdog 47 * 48 * @wdd: Underlying watchdog device 49 * @sp: Pointer to parent RAVE SP device 50 * @variant: Device specific variant information 51 * @reboot_notifier: Reboot notifier implementing machine reset 52 */ 53struct rave_sp_wdt { 54 struct watchdog_device wdd; 55 struct rave_sp *sp; 56 const struct rave_sp_wdt_variant *variant; 57 struct notifier_block reboot_notifier; 58}; 59 60static struct rave_sp_wdt *to_rave_sp_wdt(struct watchdog_device *wdd) 61{ 62 return container_of(wdd, struct rave_sp_wdt, wdd); 63} 64 65static int rave_sp_wdt_exec(struct watchdog_device *wdd, void *data, 66 size_t data_size) 67{ 68 return rave_sp_exec(to_rave_sp_wdt(wdd)->sp, 69 data, data_size, NULL, 0); 70} 71 72static int rave_sp_wdt_legacy_configure(struct watchdog_device *wdd, bool on) 73{ 74 u8 cmd[] = { 75 [0] = RAVE_SP_CMD_SW_WDT, 76 [1] = 0, 77 [2] = 0, 78 [3] = on, 79 [4] = on ? wdd->timeout : 0, 80 }; 81 82 return rave_sp_wdt_exec(wdd, cmd, sizeof(cmd)); 83} 84 85static int rave_sp_wdt_rdu_configure(struct watchdog_device *wdd, bool on) 86{ 87 u8 cmd[] = { 88 [0] = RAVE_SP_CMD_SW_WDT, 89 [1] = 0, 90 [2] = on, 91 [3] = (u8)wdd->timeout, 92 [4] = (u8)(wdd->timeout >> 8), 93 }; 94 95 return rave_sp_wdt_exec(wdd, cmd, sizeof(cmd)); 96} 97 98/** 99 * rave_sp_wdt_configure - Configure watchdog device 100 * 101 * @wdd: Device to configure 102 * @on: Desired state of the watchdog timer (ON/OFF) 103 * 104 * This function configures two aspects of the watchdog timer: 105 * 106 * - Wheither it is ON or OFF 107 * - Its timeout duration 108 * 109 * with first aspect specified via function argument and second via 110 * the value of 'wdd->timeout'. 111 */ 112static int rave_sp_wdt_configure(struct watchdog_device *wdd, bool on) 113{ 114 return to_rave_sp_wdt(wdd)->variant->configure(wdd, on); 115} 116 117static int rave_sp_wdt_legacy_restart(struct watchdog_device *wdd) 118{ 119 u8 cmd[] = { 120 [0] = RAVE_SP_CMD_RESET, 121 [1] = 0, 122 [2] = RAVE_SP_RESET_BYTE 123 }; 124 125 return rave_sp_wdt_exec(wdd, cmd, sizeof(cmd)); 126} 127 128static int rave_sp_wdt_rdu_restart(struct watchdog_device *wdd) 129{ 130 u8 cmd[] = { 131 [0] = RAVE_SP_CMD_RESET, 132 [1] = 0, 133 [2] = RAVE_SP_RESET_BYTE, 134 [3] = RAVE_SP_RESET_REASON_NORMAL 135 }; 136 137 return rave_sp_wdt_exec(wdd, cmd, sizeof(cmd)); 138} 139 140static int rave_sp_wdt_reboot_notifier(struct notifier_block *nb, 141 unsigned long action, void *data) 142{ 143 /* 144 * Restart handler is called in atomic context which means we 145 * can't communicate to SP via UART. Luckily for use SP will 146 * wait 500ms before actually resetting us, so we ask it to do 147 * so here and let the rest of the system go on wrapping 148 * things up. 149 */ 150 if (action == SYS_DOWN || action == SYS_HALT) { 151 struct rave_sp_wdt *sp_wd = 152 container_of(nb, struct rave_sp_wdt, reboot_notifier); 153 154 const int ret = sp_wd->variant->restart(&sp_wd->wdd); 155 156 if (ret < 0) 157 dev_err(sp_wd->wdd.parent, 158 "Failed to issue restart command (%d)", ret); 159 return NOTIFY_OK; 160 } 161 162 return NOTIFY_DONE; 163} 164 165static int rave_sp_wdt_restart(struct watchdog_device *wdd, 166 unsigned long action, void *data) 167{ 168 /* 169 * The actual work was done by reboot notifier above. SP 170 * firmware waits 500 ms before issuing reset, so let's hang 171 * here for twice that delay and hopefuly we'd never reach 172 * the return statement. 173 */ 174 mdelay(2 * RAVE_SP_RESET_DELAY_MS); 175 176 return -EIO; 177} 178 179static int rave_sp_wdt_start(struct watchdog_device *wdd) 180{ 181 int ret; 182 183 ret = rave_sp_wdt_configure(wdd, true); 184 if (!ret) 185 set_bit(WDOG_HW_RUNNING, &wdd->status); 186 187 return ret; 188} 189 190static int rave_sp_wdt_stop(struct watchdog_device *wdd) 191{ 192 return rave_sp_wdt_configure(wdd, false); 193} 194 195static int rave_sp_wdt_set_timeout(struct watchdog_device *wdd, 196 unsigned int timeout) 197{ 198 wdd->timeout = timeout; 199 200 return rave_sp_wdt_configure(wdd, watchdog_active(wdd)); 201} 202 203static int rave_sp_wdt_ping(struct watchdog_device *wdd) 204{ 205 u8 cmd[] = { 206 [0] = RAVE_SP_CMD_PET_WDT, 207 [1] = 0, 208 }; 209 210 return rave_sp_wdt_exec(wdd, cmd, sizeof(cmd)); 211} 212 213static const struct watchdog_info rave_sp_wdt_info = { 214 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, 215 .identity = "RAVE SP Watchdog", 216}; 217 218static const struct watchdog_ops rave_sp_wdt_ops = { 219 .owner = THIS_MODULE, 220 .start = rave_sp_wdt_start, 221 .stop = rave_sp_wdt_stop, 222 .ping = rave_sp_wdt_ping, 223 .set_timeout = rave_sp_wdt_set_timeout, 224 .restart = rave_sp_wdt_restart, 225}; 226 227static const struct rave_sp_wdt_variant rave_sp_wdt_legacy = { 228 .max_timeout = 255, 229 .min_timeout = 1, 230 .configure = rave_sp_wdt_legacy_configure, 231 .restart = rave_sp_wdt_legacy_restart, 232}; 233 234static const struct rave_sp_wdt_variant rave_sp_wdt_rdu = { 235 .max_timeout = 180, 236 .min_timeout = 60, 237 .configure = rave_sp_wdt_rdu_configure, 238 .restart = rave_sp_wdt_rdu_restart, 239}; 240 241static const struct of_device_id rave_sp_wdt_of_match[] = { 242 { 243 .compatible = "zii,rave-sp-watchdog-legacy", 244 .data = &rave_sp_wdt_legacy, 245 }, 246 { 247 .compatible = "zii,rave-sp-watchdog", 248 .data = &rave_sp_wdt_rdu, 249 }, 250 { /* sentinel */ } 251}; 252 253static int rave_sp_wdt_probe(struct platform_device *pdev) 254{ 255 struct device *dev = &pdev->dev; 256 struct watchdog_device *wdd; 257 struct rave_sp_wdt *sp_wd; 258 struct nvmem_cell *cell; 259 __le16 timeout = 0; 260 int ret; 261 262 sp_wd = devm_kzalloc(dev, sizeof(*sp_wd), GFP_KERNEL); 263 if (!sp_wd) 264 return -ENOMEM; 265 266 sp_wd->variant = of_device_get_match_data(dev); 267 sp_wd->sp = dev_get_drvdata(dev->parent); 268 269 wdd = &sp_wd->wdd; 270 wdd->parent = dev; 271 wdd->info = &rave_sp_wdt_info; 272 wdd->ops = &rave_sp_wdt_ops; 273 wdd->min_timeout = sp_wd->variant->min_timeout; 274 wdd->max_timeout = sp_wd->variant->max_timeout; 275 wdd->status = WATCHDOG_NOWAYOUT_INIT_STATUS; 276 wdd->timeout = 60; 277 278 cell = nvmem_cell_get(dev, "wdt-timeout"); 279 if (!IS_ERR(cell)) { 280 size_t len; 281 void *value = nvmem_cell_read(cell, &len); 282 283 if (!IS_ERR(value)) { 284 memcpy(&timeout, value, min(len, sizeof(timeout))); 285 kfree(value); 286 } 287 nvmem_cell_put(cell); 288 } 289 watchdog_init_timeout(wdd, le16_to_cpu(timeout), dev); 290 watchdog_set_restart_priority(wdd, 255); 291 watchdog_stop_on_unregister(wdd); 292 293 sp_wd->reboot_notifier.notifier_call = rave_sp_wdt_reboot_notifier; 294 ret = devm_register_reboot_notifier(dev, &sp_wd->reboot_notifier); 295 if (ret) { 296 dev_err(dev, "Failed to register reboot notifier\n"); 297 return ret; 298 } 299 300 /* 301 * We don't know if watchdog is running now. To be sure, let's 302 * start it and depend on watchdog core to ping it 303 */ 304 wdd->max_hw_heartbeat_ms = wdd->max_timeout * 1000; 305 ret = rave_sp_wdt_start(wdd); 306 if (ret) { 307 dev_err(dev, "Watchdog didn't start\n"); 308 return ret; 309 } 310 311 ret = devm_watchdog_register_device(dev, wdd); 312 if (ret) { 313 rave_sp_wdt_stop(wdd); 314 return ret; 315 } 316 317 return 0; 318} 319 320static struct platform_driver rave_sp_wdt_driver = { 321 .probe = rave_sp_wdt_probe, 322 .driver = { 323 .name = KBUILD_MODNAME, 324 .of_match_table = rave_sp_wdt_of_match, 325 }, 326}; 327 328module_platform_driver(rave_sp_wdt_driver); 329 330MODULE_DEVICE_TABLE(of, rave_sp_wdt_of_match); 331MODULE_LICENSE("GPL"); 332MODULE_AUTHOR("Andrey Vostrikov <andrey.vostrikov@cogentembedded.com>"); 333MODULE_AUTHOR("Nikita Yushchenko <nikita.yoush@cogentembedded.com>"); 334MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>"); 335MODULE_DESCRIPTION("RAVE SP Watchdog driver"); 336MODULE_ALIAS("platform:rave-sp-watchdog");