0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 #include <linux/fs.h>
0017 #include <linux/init.h>
0018 #include <linux/kernel.h>
0019 #include <linux/of_address.h>
0020 #include <linux/of_platform.h>
0021 #include <linux/module.h>
0022 #include <linux/watchdog.h>
0023 #include <linux/io.h>
0024 #include <linux/uaccess.h>
0025 #include <sysdev/fsl_soc.h>
0026
0027 #define WATCHDOG_TIMEOUT 10
0028
0029 struct mpc8xxx_wdt {
0030 __be32 res0;
0031 __be32 swcrr;
0032 #define SWCRR_SWTC 0xFFFF0000
0033 #define SWCRR_SWF 0x00000008
0034 #define SWCRR_SWEN 0x00000004
0035 #define SWCRR_SWRI 0x00000002
0036 #define SWCRR_SWPR 0x00000001
0037 __be32 swcnr;
0038 u8 res1[2];
0039 __be16 swsrr;
0040 u8 res2[0xF0];
0041 };
0042
0043 struct mpc8xxx_wdt_type {
0044 int prescaler;
0045 bool hw_enabled;
0046 u32 rsr_mask;
0047 };
0048
0049 struct mpc8xxx_wdt_ddata {
0050 struct mpc8xxx_wdt __iomem *base;
0051 struct watchdog_device wdd;
0052 spinlock_t lock;
0053 u16 swtc;
0054 };
0055
0056 static u16 timeout;
0057 module_param(timeout, ushort, 0);
0058 MODULE_PARM_DESC(timeout,
0059 "Watchdog timeout in seconds. (1<timeout<65535, default="
0060 __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
0061
0062 static bool reset = 1;
0063 module_param(reset, bool, 0);
0064 MODULE_PARM_DESC(reset,
0065 "Watchdog Interrupt/Reset Mode. 0 = interrupt, 1 = reset");
0066
0067 static bool nowayout = WATCHDOG_NOWAYOUT;
0068 module_param(nowayout, bool, 0);
0069 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
0070 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
0071
0072 static void mpc8xxx_wdt_keepalive(struct mpc8xxx_wdt_ddata *ddata)
0073 {
0074
0075 spin_lock(&ddata->lock);
0076 out_be16(&ddata->base->swsrr, 0x556c);
0077 out_be16(&ddata->base->swsrr, 0xaa39);
0078 spin_unlock(&ddata->lock);
0079 }
0080
0081 static int mpc8xxx_wdt_start(struct watchdog_device *w)
0082 {
0083 struct mpc8xxx_wdt_ddata *ddata =
0084 container_of(w, struct mpc8xxx_wdt_ddata, wdd);
0085 u32 tmp = in_be32(&ddata->base->swcrr);
0086
0087
0088 tmp &= ~(SWCRR_SWTC | SWCRR_SWF | SWCRR_SWEN | SWCRR_SWRI | SWCRR_SWPR);
0089 tmp |= SWCRR_SWEN | SWCRR_SWPR | (ddata->swtc << 16);
0090
0091 if (reset)
0092 tmp |= SWCRR_SWRI;
0093
0094 out_be32(&ddata->base->swcrr, tmp);
0095
0096 tmp = in_be32(&ddata->base->swcrr);
0097 if (!(tmp & SWCRR_SWEN))
0098 return -EOPNOTSUPP;
0099
0100 ddata->swtc = tmp >> 16;
0101 set_bit(WDOG_HW_RUNNING, &ddata->wdd.status);
0102
0103 return 0;
0104 }
0105
0106 static int mpc8xxx_wdt_ping(struct watchdog_device *w)
0107 {
0108 struct mpc8xxx_wdt_ddata *ddata =
0109 container_of(w, struct mpc8xxx_wdt_ddata, wdd);
0110
0111 mpc8xxx_wdt_keepalive(ddata);
0112 return 0;
0113 }
0114
0115 static struct watchdog_info mpc8xxx_wdt_info = {
0116 .options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT,
0117 .firmware_version = 1,
0118 .identity = "MPC8xxx",
0119 };
0120
0121 static const struct watchdog_ops mpc8xxx_wdt_ops = {
0122 .owner = THIS_MODULE,
0123 .start = mpc8xxx_wdt_start,
0124 .ping = mpc8xxx_wdt_ping,
0125 };
0126
0127 static int mpc8xxx_wdt_probe(struct platform_device *ofdev)
0128 {
0129 int ret;
0130 struct resource *res;
0131 const struct mpc8xxx_wdt_type *wdt_type;
0132 struct mpc8xxx_wdt_ddata *ddata;
0133 u32 freq = fsl_get_sys_freq();
0134 bool enabled;
0135 struct device *dev = &ofdev->dev;
0136
0137 wdt_type = of_device_get_match_data(dev);
0138 if (!wdt_type)
0139 return -EINVAL;
0140
0141 if (!freq || freq == -1)
0142 return -EINVAL;
0143
0144 ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
0145 if (!ddata)
0146 return -ENOMEM;
0147
0148 ddata->base = devm_platform_ioremap_resource(ofdev, 0);
0149 if (IS_ERR(ddata->base))
0150 return PTR_ERR(ddata->base);
0151
0152 enabled = in_be32(&ddata->base->swcrr) & SWCRR_SWEN;
0153 if (!enabled && wdt_type->hw_enabled) {
0154 dev_info(dev, "could not be enabled in software\n");
0155 return -ENODEV;
0156 }
0157
0158 res = platform_get_resource(ofdev, IORESOURCE_MEM, 1);
0159 if (res) {
0160 bool status;
0161 u32 __iomem *rsr = ioremap(res->start, resource_size(res));
0162
0163 if (!rsr)
0164 return -ENOMEM;
0165
0166 status = in_be32(rsr) & wdt_type->rsr_mask;
0167 ddata->wdd.bootstatus = status ? WDIOF_CARDRESET : 0;
0168
0169 out_be32(rsr, wdt_type->rsr_mask);
0170 iounmap(rsr);
0171
0172 dev_info(dev, "Last boot was %scaused by watchdog\n",
0173 status ? "" : "not ");
0174 }
0175
0176 spin_lock_init(&ddata->lock);
0177
0178 ddata->wdd.info = &mpc8xxx_wdt_info;
0179 ddata->wdd.ops = &mpc8xxx_wdt_ops;
0180
0181 ddata->wdd.timeout = WATCHDOG_TIMEOUT;
0182 watchdog_init_timeout(&ddata->wdd, timeout, dev);
0183
0184 watchdog_set_nowayout(&ddata->wdd, nowayout);
0185
0186 ddata->swtc = min(ddata->wdd.timeout * freq / wdt_type->prescaler,
0187 0xffffU);
0188
0189
0190
0191
0192
0193
0194 if (enabled)
0195 mpc8xxx_wdt_start(&ddata->wdd);
0196
0197 ddata->wdd.max_hw_heartbeat_ms = (ddata->swtc * wdt_type->prescaler) /
0198 (freq / 1000);
0199 ddata->wdd.min_timeout = ddata->wdd.max_hw_heartbeat_ms / 1000;
0200 if (ddata->wdd.timeout < ddata->wdd.min_timeout)
0201 ddata->wdd.timeout = ddata->wdd.min_timeout;
0202
0203 ret = devm_watchdog_register_device(dev, &ddata->wdd);
0204 if (ret)
0205 return ret;
0206
0207 dev_info(dev,
0208 "WDT driver for MPC8xxx initialized. mode:%s timeout=%d sec\n",
0209 reset ? "reset" : "interrupt", ddata->wdd.timeout);
0210
0211 platform_set_drvdata(ofdev, ddata);
0212 return 0;
0213 }
0214
0215 static const struct of_device_id mpc8xxx_wdt_match[] = {
0216 {
0217 .compatible = "mpc83xx_wdt",
0218 .data = &(struct mpc8xxx_wdt_type) {
0219 .prescaler = 0x10000,
0220 .rsr_mask = BIT(3),
0221 },
0222 },
0223 {
0224 .compatible = "fsl,mpc8610-wdt",
0225 .data = &(struct mpc8xxx_wdt_type) {
0226 .prescaler = 0x10000,
0227 .hw_enabled = true,
0228 .rsr_mask = BIT(20),
0229 },
0230 },
0231 {
0232 .compatible = "fsl,mpc823-wdt",
0233 .data = &(struct mpc8xxx_wdt_type) {
0234 .prescaler = 0x800,
0235 .hw_enabled = true,
0236 .rsr_mask = BIT(28),
0237 },
0238 },
0239 {},
0240 };
0241 MODULE_DEVICE_TABLE(of, mpc8xxx_wdt_match);
0242
0243 static struct platform_driver mpc8xxx_wdt_driver = {
0244 .probe = mpc8xxx_wdt_probe,
0245 .driver = {
0246 .name = "mpc8xxx_wdt",
0247 .of_match_table = mpc8xxx_wdt_match,
0248 },
0249 };
0250
0251 static int __init mpc8xxx_wdt_init(void)
0252 {
0253 return platform_driver_register(&mpc8xxx_wdt_driver);
0254 }
0255 arch_initcall(mpc8xxx_wdt_init);
0256
0257 static void __exit mpc8xxx_wdt_exit(void)
0258 {
0259 platform_driver_unregister(&mpc8xxx_wdt_driver);
0260 }
0261 module_exit(mpc8xxx_wdt_exit);
0262
0263 MODULE_AUTHOR("Dave Updegraff, Kumar Gala");
0264 MODULE_DESCRIPTION("Driver for watchdog timer in MPC8xx/MPC83xx/MPC86xx "
0265 "uProcessors");
0266 MODULE_LICENSE("GPL");