Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 
0003 /*
0004  * Driver for watchdog aspect of for Zodiac Inflight Innovations RAVE
0005  * Supervisory Processor(SP) MCU
0006  *
0007  * Copyright (C) 2017 Zodiac Inflight Innovation
0008  *
0009  */
0010 
0011 #include <linux/delay.h>
0012 #include <linux/kernel.h>
0013 #include <linux/mfd/rave-sp.h>
0014 #include <linux/module.h>
0015 #include <linux/nvmem-consumer.h>
0016 #include <linux/of_device.h>
0017 #include <linux/platform_device.h>
0018 #include <linux/reboot.h>
0019 #include <linux/slab.h>
0020 #include <linux/watchdog.h>
0021 
0022 enum {
0023     RAVE_SP_RESET_BYTE = 1,
0024     RAVE_SP_RESET_REASON_NORMAL = 0,
0025     RAVE_SP_RESET_DELAY_MS = 500,
0026 };
0027 
0028 /**
0029  * struct rave_sp_wdt_variant - RAVE SP watchdog variant
0030  *
0031  * @max_timeout:    Largest possible watchdog timeout setting
0032  * @min_timeout:    Smallest possible watchdog timeout setting
0033  *
0034  * @configure:      Function to send configuration command
0035  * @restart:        Function to send "restart" command
0036  */
0037 struct rave_sp_wdt_variant {
0038     unsigned int max_timeout;
0039     unsigned int min_timeout;
0040 
0041     int (*configure)(struct watchdog_device *, bool);
0042     int (*restart)(struct watchdog_device *);
0043 };
0044 
0045 /**
0046  * struct rave_sp_wdt - RAVE SP watchdog
0047  *
0048  * @wdd:        Underlying watchdog device
0049  * @sp:         Pointer to parent RAVE SP device
0050  * @variant:        Device specific variant information
0051  * @reboot_notifier:    Reboot notifier implementing machine reset
0052  */
0053 struct rave_sp_wdt {
0054     struct watchdog_device wdd;
0055     struct rave_sp *sp;
0056     const struct rave_sp_wdt_variant *variant;
0057     struct notifier_block reboot_notifier;
0058 };
0059 
0060 static struct rave_sp_wdt *to_rave_sp_wdt(struct watchdog_device *wdd)
0061 {
0062     return container_of(wdd, struct rave_sp_wdt, wdd);
0063 }
0064 
0065 static int rave_sp_wdt_exec(struct watchdog_device *wdd, void *data,
0066                 size_t data_size)
0067 {
0068     return rave_sp_exec(to_rave_sp_wdt(wdd)->sp,
0069                 data, data_size, NULL, 0);
0070 }
0071 
0072 static int rave_sp_wdt_legacy_configure(struct watchdog_device *wdd, bool on)
0073 {
0074     u8 cmd[] = {
0075         [0] = RAVE_SP_CMD_SW_WDT,
0076         [1] = 0,
0077         [2] = 0,
0078         [3] = on,
0079         [4] = on ? wdd->timeout : 0,
0080     };
0081 
0082     return rave_sp_wdt_exec(wdd, cmd, sizeof(cmd));
0083 }
0084 
0085 static int rave_sp_wdt_rdu_configure(struct watchdog_device *wdd, bool on)
0086 {
0087     u8 cmd[] = {
0088         [0] = RAVE_SP_CMD_SW_WDT,
0089         [1] = 0,
0090         [2] = on,
0091         [3] = (u8)wdd->timeout,
0092         [4] = (u8)(wdd->timeout >> 8),
0093     };
0094 
0095     return rave_sp_wdt_exec(wdd, cmd, sizeof(cmd));
0096 }
0097 
0098 /**
0099  * rave_sp_wdt_configure - Configure watchdog device
0100  *
0101  * @wdd:    Device to configure
0102  * @on:     Desired state of the watchdog timer (ON/OFF)
0103  *
0104  * This function configures two aspects of the watchdog timer:
0105  *
0106  *  - Wheither it is ON or OFF
0107  *  - Its timeout duration
0108  *
0109  * with first aspect specified via function argument and second via
0110  * the value of 'wdd->timeout'.
0111  */
0112 static int rave_sp_wdt_configure(struct watchdog_device *wdd, bool on)
0113 {
0114     return to_rave_sp_wdt(wdd)->variant->configure(wdd, on);
0115 }
0116 
0117 static int rave_sp_wdt_legacy_restart(struct watchdog_device *wdd)
0118 {
0119     u8 cmd[] = {
0120         [0] = RAVE_SP_CMD_RESET,
0121         [1] = 0,
0122         [2] = RAVE_SP_RESET_BYTE
0123     };
0124 
0125     return rave_sp_wdt_exec(wdd, cmd, sizeof(cmd));
0126 }
0127 
0128 static int rave_sp_wdt_rdu_restart(struct watchdog_device *wdd)
0129 {
0130     u8 cmd[] = {
0131         [0] = RAVE_SP_CMD_RESET,
0132         [1] = 0,
0133         [2] = RAVE_SP_RESET_BYTE,
0134         [3] = RAVE_SP_RESET_REASON_NORMAL
0135     };
0136 
0137     return rave_sp_wdt_exec(wdd, cmd, sizeof(cmd));
0138 }
0139 
0140 static int rave_sp_wdt_reboot_notifier(struct notifier_block *nb,
0141                        unsigned long action, void *data)
0142 {
0143     /*
0144      * Restart handler is called in atomic context which means we
0145      * can't communicate to SP via UART. Luckily for use SP will
0146      * wait 500ms before actually resetting us, so we ask it to do
0147      * so here and let the rest of the system go on wrapping
0148      * things up.
0149      */
0150     if (action == SYS_DOWN || action == SYS_HALT) {
0151         struct rave_sp_wdt *sp_wd =
0152             container_of(nb, struct rave_sp_wdt, reboot_notifier);
0153 
0154         const int ret = sp_wd->variant->restart(&sp_wd->wdd);
0155 
0156         if (ret < 0)
0157             dev_err(sp_wd->wdd.parent,
0158                 "Failed to issue restart command (%d)", ret);
0159         return NOTIFY_OK;
0160     }
0161 
0162     return NOTIFY_DONE;
0163 }
0164 
0165 static int rave_sp_wdt_restart(struct watchdog_device *wdd,
0166                    unsigned long action, void *data)
0167 {
0168     /*
0169      * The actual work was done by reboot notifier above. SP
0170      * firmware waits 500 ms before issuing reset, so let's hang
0171      * here for twice that delay and hopefuly we'd never reach
0172      * the return statement.
0173      */
0174     mdelay(2 * RAVE_SP_RESET_DELAY_MS);
0175 
0176     return -EIO;
0177 }
0178 
0179 static int rave_sp_wdt_start(struct watchdog_device *wdd)
0180 {
0181     int ret;
0182 
0183     ret = rave_sp_wdt_configure(wdd, true);
0184     if (!ret)
0185         set_bit(WDOG_HW_RUNNING, &wdd->status);
0186 
0187     return ret;
0188 }
0189 
0190 static int rave_sp_wdt_stop(struct watchdog_device *wdd)
0191 {
0192     return rave_sp_wdt_configure(wdd, false);
0193 }
0194 
0195 static int rave_sp_wdt_set_timeout(struct watchdog_device *wdd,
0196                    unsigned int timeout)
0197 {
0198     wdd->timeout = timeout;
0199 
0200     return rave_sp_wdt_configure(wdd, watchdog_active(wdd));
0201 }
0202 
0203 static int rave_sp_wdt_ping(struct watchdog_device *wdd)
0204 {
0205     u8 cmd[] = {
0206         [0] = RAVE_SP_CMD_PET_WDT,
0207         [1] = 0,
0208     };
0209 
0210     return rave_sp_wdt_exec(wdd, cmd, sizeof(cmd));
0211 }
0212 
0213 static const struct watchdog_info rave_sp_wdt_info = {
0214     .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
0215     .identity = "RAVE SP Watchdog",
0216 };
0217 
0218 static const struct watchdog_ops rave_sp_wdt_ops = {
0219     .owner = THIS_MODULE,
0220     .start = rave_sp_wdt_start,
0221     .stop = rave_sp_wdt_stop,
0222     .ping = rave_sp_wdt_ping,
0223     .set_timeout = rave_sp_wdt_set_timeout,
0224     .restart = rave_sp_wdt_restart,
0225 };
0226 
0227 static const struct rave_sp_wdt_variant rave_sp_wdt_legacy = {
0228     .max_timeout = 255,
0229     .min_timeout = 1,
0230     .configure = rave_sp_wdt_legacy_configure,
0231     .restart   = rave_sp_wdt_legacy_restart,
0232 };
0233 
0234 static const struct rave_sp_wdt_variant rave_sp_wdt_rdu = {
0235     .max_timeout = 180,
0236     .min_timeout = 60,
0237     .configure = rave_sp_wdt_rdu_configure,
0238     .restart   = rave_sp_wdt_rdu_restart,
0239 };
0240 
0241 static const struct of_device_id rave_sp_wdt_of_match[] = {
0242     {
0243         .compatible = "zii,rave-sp-watchdog-legacy",
0244         .data = &rave_sp_wdt_legacy,
0245     },
0246     {
0247         .compatible = "zii,rave-sp-watchdog",
0248         .data = &rave_sp_wdt_rdu,
0249     },
0250     { /* sentinel */ }
0251 };
0252 
0253 static int rave_sp_wdt_probe(struct platform_device *pdev)
0254 {
0255     struct device *dev = &pdev->dev;
0256     struct watchdog_device *wdd;
0257     struct rave_sp_wdt *sp_wd;
0258     struct nvmem_cell *cell;
0259     __le16 timeout = 0;
0260     int ret;
0261 
0262     sp_wd = devm_kzalloc(dev, sizeof(*sp_wd), GFP_KERNEL);
0263     if (!sp_wd)
0264         return -ENOMEM;
0265 
0266     sp_wd->variant = of_device_get_match_data(dev);
0267     sp_wd->sp      = dev_get_drvdata(dev->parent);
0268 
0269     wdd              = &sp_wd->wdd;
0270     wdd->parent      = dev;
0271     wdd->info        = &rave_sp_wdt_info;
0272     wdd->ops         = &rave_sp_wdt_ops;
0273     wdd->min_timeout = sp_wd->variant->min_timeout;
0274     wdd->max_timeout = sp_wd->variant->max_timeout;
0275     wdd->status      = WATCHDOG_NOWAYOUT_INIT_STATUS;
0276     wdd->timeout     = 60;
0277 
0278     cell = nvmem_cell_get(dev, "wdt-timeout");
0279     if (!IS_ERR(cell)) {
0280         size_t len;
0281         void *value = nvmem_cell_read(cell, &len);
0282 
0283         if (!IS_ERR(value)) {
0284             memcpy(&timeout, value, min(len, sizeof(timeout)));
0285             kfree(value);
0286         }
0287         nvmem_cell_put(cell);
0288     }
0289     watchdog_init_timeout(wdd, le16_to_cpu(timeout), dev);
0290     watchdog_set_restart_priority(wdd, 255);
0291     watchdog_stop_on_unregister(wdd);
0292 
0293     sp_wd->reboot_notifier.notifier_call = rave_sp_wdt_reboot_notifier;
0294     ret = devm_register_reboot_notifier(dev, &sp_wd->reboot_notifier);
0295     if (ret) {
0296         dev_err(dev, "Failed to register reboot notifier\n");
0297         return ret;
0298     }
0299 
0300     /*
0301      * We don't know if watchdog is running now. To be sure, let's
0302      * start it and depend on watchdog core to ping it
0303      */
0304     wdd->max_hw_heartbeat_ms = wdd->max_timeout * 1000;
0305     ret = rave_sp_wdt_start(wdd);
0306     if (ret) {
0307         dev_err(dev, "Watchdog didn't start\n");
0308         return ret;
0309     }
0310 
0311     ret = devm_watchdog_register_device(dev, wdd);
0312     if (ret) {
0313         rave_sp_wdt_stop(wdd);
0314         return ret;
0315     }
0316 
0317     return 0;
0318 }
0319 
0320 static struct platform_driver rave_sp_wdt_driver = {
0321     .probe = rave_sp_wdt_probe,
0322     .driver = {
0323         .name = KBUILD_MODNAME,
0324         .of_match_table = rave_sp_wdt_of_match,
0325     },
0326 };
0327 
0328 module_platform_driver(rave_sp_wdt_driver);
0329 
0330 MODULE_DEVICE_TABLE(of, rave_sp_wdt_of_match);
0331 MODULE_LICENSE("GPL");
0332 MODULE_AUTHOR("Andrey Vostrikov <andrey.vostrikov@cogentembedded.com>");
0333 MODULE_AUTHOR("Nikita Yushchenko <nikita.yoush@cogentembedded.com>");
0334 MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
0335 MODULE_DESCRIPTION("RAVE SP Watchdog driver");
0336 MODULE_ALIAS("platform:rave-sp-watchdog");