1 /* 2 * mpc8xxx_wdt.c - MPC8xx/MPC83xx/MPC86xx watchdog userspace interface 3 * 4 * Authors: Dave Updegraff <dave@cray.org> 5 * Kumar Gala <galak@kernel.crashing.org> 6 * Attribution: from 83xx_wst: Florian Schirmer <jolt@tuxbox.org> 7 * ..and from sc520_wdt 8 * Copyright (c) 2008 MontaVista Software, Inc. 9 * Anton Vorontsov <avorontsov@ru.mvista.com> 10 * 11 * Note: it appears that you can only actually ENABLE or DISABLE the thing 12 * once after POR. Once enabled, you cannot disable, and vice versa. 13 * 14 * This program is free software; you can redistribute it and/or modify it 15 * under the terms of the GNU General Public License as published by the 16 * Free Software Foundation; either version 2 of the License, or (at your 17 * option) any later version. 18 */ 19 20 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 21 22 #include <linux/fs.h> 23 #include <linux/init.h> 24 #include <linux/kernel.h> 25 #include <linux/timer.h> 26 #include <linux/miscdevice.h> 27 #include <linux/of_address.h> 28 #include <linux/of_platform.h> 29 #include <linux/module.h> 30 #include <linux/watchdog.h> 31 #include <linux/io.h> 32 #include <linux/uaccess.h> 33 #include <sysdev/fsl_soc.h> 34 35 struct mpc8xxx_wdt { 36 __be32 res0; 37 __be32 swcrr; /* System watchdog control register */ 38 #define SWCRR_SWTC 0xFFFF0000 /* Software Watchdog Time Count. */ 39 #define SWCRR_SWEN 0x00000004 /* Watchdog Enable bit. */ 40 #define SWCRR_SWRI 0x00000002 /* Software Watchdog Reset/Interrupt Select bit.*/ 41 #define SWCRR_SWPR 0x00000001 /* Software Watchdog Counter Prescale bit. */ 42 __be32 swcnr; /* System watchdog count register */ 43 u8 res1[2]; 44 __be16 swsrr; /* System watchdog service register */ 45 u8 res2[0xF0]; 46 }; 47 48 struct mpc8xxx_wdt_type { 49 int prescaler; 50 bool hw_enabled; 51 }; 52 53 struct mpc8xxx_wdt_ddata { 54 struct mpc8xxx_wdt __iomem *base; 55 struct watchdog_device wdd; 56 struct timer_list timer; 57 spinlock_t lock; 58 }; 59 60 static u16 timeout = 0xffff; 61 module_param(timeout, ushort, 0); 62 MODULE_PARM_DESC(timeout, 63 "Watchdog timeout in ticks. (0<timeout<65536, default=65535)"); 64 65 static bool reset = 1; 66 module_param(reset, bool, 0); 67 MODULE_PARM_DESC(reset, 68 "Watchdog Interrupt/Reset Mode. 0 = interrupt, 1 = reset"); 69 70 static bool nowayout = WATCHDOG_NOWAYOUT; 71 module_param(nowayout, bool, 0); 72 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " 73 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 74 75 static void mpc8xxx_wdt_keepalive(struct mpc8xxx_wdt_ddata *ddata) 76 { 77 /* Ping the WDT */ 78 spin_lock(&ddata->lock); 79 out_be16(&ddata->base->swsrr, 0x556c); 80 out_be16(&ddata->base->swsrr, 0xaa39); 81 spin_unlock(&ddata->lock); 82 } 83 84 static void mpc8xxx_wdt_timer_ping(unsigned long arg) 85 { 86 struct mpc8xxx_wdt_ddata *ddata = (void *)arg; 87 88 mpc8xxx_wdt_keepalive(ddata); 89 /* We're pinging it twice faster than needed, just to be sure. */ 90 mod_timer(&ddata->timer, jiffies + HZ * ddata->wdd.timeout / 2); 91 } 92 93 static int mpc8xxx_wdt_start(struct watchdog_device *w) 94 { 95 struct mpc8xxx_wdt_ddata *ddata = 96 container_of(w, struct mpc8xxx_wdt_ddata, wdd); 97 98 u32 tmp = SWCRR_SWEN | SWCRR_SWPR; 99 100 /* Good, fire up the show */ 101 if (reset) 102 tmp |= SWCRR_SWRI; 103 104 tmp |= timeout << 16; 105 106 out_be32(&ddata->base->swcrr, tmp); 107 108 del_timer_sync(&ddata->timer); 109 110 return 0; 111 } 112 113 static int mpc8xxx_wdt_ping(struct watchdog_device *w) 114 { 115 struct mpc8xxx_wdt_ddata *ddata = 116 container_of(w, struct mpc8xxx_wdt_ddata, wdd); 117 118 mpc8xxx_wdt_keepalive(ddata); 119 return 0; 120 } 121 122 static int mpc8xxx_wdt_stop(struct watchdog_device *w) 123 { 124 struct mpc8xxx_wdt_ddata *ddata = 125 container_of(w, struct mpc8xxx_wdt_ddata, wdd); 126 127 mod_timer(&ddata->timer, jiffies); 128 return 0; 129 } 130 131 static struct watchdog_info mpc8xxx_wdt_info = { 132 .options = WDIOF_KEEPALIVEPING, 133 .firmware_version = 1, 134 .identity = "MPC8xxx", 135 }; 136 137 static struct watchdog_ops mpc8xxx_wdt_ops = { 138 .owner = THIS_MODULE, 139 .start = mpc8xxx_wdt_start, 140 .ping = mpc8xxx_wdt_ping, 141 .stop = mpc8xxx_wdt_stop, 142 }; 143 144 static int mpc8xxx_wdt_probe(struct platform_device *ofdev) 145 { 146 int ret; 147 struct resource *res; 148 const struct mpc8xxx_wdt_type *wdt_type; 149 struct mpc8xxx_wdt_ddata *ddata; 150 u32 freq = fsl_get_sys_freq(); 151 bool enabled; 152 unsigned int timeout_sec; 153 154 wdt_type = of_device_get_match_data(&ofdev->dev); 155 if (!wdt_type) 156 return -EINVAL; 157 158 if (!freq || freq == -1) 159 return -EINVAL; 160 161 ddata = devm_kzalloc(&ofdev->dev, sizeof(*ddata), GFP_KERNEL); 162 if (!ddata) 163 return -ENOMEM; 164 165 res = platform_get_resource(ofdev, IORESOURCE_MEM, 0); 166 ddata->base = devm_ioremap_resource(&ofdev->dev, res); 167 if (IS_ERR(ddata->base)) 168 return PTR_ERR(ddata->base); 169 170 enabled = in_be32(&ddata->base->swcrr) & SWCRR_SWEN; 171 if (!enabled && wdt_type->hw_enabled) { 172 pr_info("could not be enabled in software\n"); 173 return -ENODEV; 174 } 175 176 spin_lock_init(&ddata->lock); 177 setup_timer(&ddata->timer, mpc8xxx_wdt_timer_ping, 178 (unsigned long)ddata); 179 180 ddata->wdd.info = &mpc8xxx_wdt_info, 181 ddata->wdd.ops = &mpc8xxx_wdt_ops, 182 183 /* Calculate the timeout in seconds */ 184 timeout_sec = (timeout * wdt_type->prescaler) / freq; 185 186 ddata->wdd.timeout = timeout_sec; 187 188 watchdog_set_nowayout(&ddata->wdd, nowayout); 189 190 ret = watchdog_register_device(&ddata->wdd); 191 if (ret) { 192 pr_err("cannot register watchdog device (err=%d)\n", ret); 193 return ret; 194 } 195 196 pr_info("WDT driver for MPC8xxx initialized. mode:%s timeout=%d (%d seconds)\n", 197 reset ? "reset" : "interrupt", timeout, timeout_sec); 198 199 /* 200 * If the watchdog was previously enabled or we're running on 201 * MPC8xxx, we should ping the wdt from the kernel until the 202 * userspace handles it. 203 */ 204 if (enabled) 205 mod_timer(&ddata->timer, jiffies); 206 207 platform_set_drvdata(ofdev, ddata); 208 return 0; 209 } 210 211 static int mpc8xxx_wdt_remove(struct platform_device *ofdev) 212 { 213 struct mpc8xxx_wdt_ddata *ddata = platform_get_drvdata(ofdev); 214 215 pr_crit("Watchdog removed, expect the %s soon!\n", 216 reset ? "reset" : "machine check exception"); 217 del_timer_sync(&ddata->timer); 218 watchdog_unregister_device(&ddata->wdd); 219 220 return 0; 221 } 222 223 static const struct of_device_id mpc8xxx_wdt_match[] = { 224 { 225 .compatible = "mpc83xx_wdt", 226 .data = &(struct mpc8xxx_wdt_type) { 227 .prescaler = 0x10000, 228 }, 229 }, 230 { 231 .compatible = "fsl,mpc8610-wdt", 232 .data = &(struct mpc8xxx_wdt_type) { 233 .prescaler = 0x10000, 234 .hw_enabled = true, 235 }, 236 }, 237 { 238 .compatible = "fsl,mpc823-wdt", 239 .data = &(struct mpc8xxx_wdt_type) { 240 .prescaler = 0x800, 241 .hw_enabled = true, 242 }, 243 }, 244 {}, 245 }; 246 MODULE_DEVICE_TABLE(of, mpc8xxx_wdt_match); 247 248 static struct platform_driver mpc8xxx_wdt_driver = { 249 .probe = mpc8xxx_wdt_probe, 250 .remove = mpc8xxx_wdt_remove, 251 .driver = { 252 .name = "mpc8xxx_wdt", 253 .of_match_table = mpc8xxx_wdt_match, 254 }, 255 }; 256 257 static int __init mpc8xxx_wdt_init(void) 258 { 259 return platform_driver_register(&mpc8xxx_wdt_driver); 260 } 261 arch_initcall(mpc8xxx_wdt_init); 262 263 static void __exit mpc8xxx_wdt_exit(void) 264 { 265 platform_driver_unregister(&mpc8xxx_wdt_driver); 266 } 267 module_exit(mpc8xxx_wdt_exit); 268 269 MODULE_AUTHOR("Dave Updegraff, Kumar Gala"); 270 MODULE_DESCRIPTION("Driver for watchdog timer in MPC8xx/MPC83xx/MPC86xx " 271 "uProcessors"); 272 MODULE_LICENSE("GPL"); 273