0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/clk.h>
0010 #include <linux/init.h>
0011 #include <linux/interrupt.h>
0012 #include <linux/io.h>
0013 #include <linux/irq.h>
0014 #include <linux/kernel.h>
0015 #include <linux/module.h>
0016 #include <linux/of.h>
0017 #include <linux/platform_device.h>
0018 #include <linux/watchdog.h>
0019
0020 #define CDNS_WDT_DEFAULT_TIMEOUT 10
0021
0022 #define CDNS_WDT_MIN_TIMEOUT 1
0023 #define CDNS_WDT_MAX_TIMEOUT 516
0024
0025
0026 #define CDNS_WDT_RESTART_KEY 0x00001999
0027
0028
0029 #define CDNS_WDT_REGISTER_ACCESS_KEY 0x00920000
0030
0031
0032 #define CDNS_WDT_COUNTER_VALUE_DIVISOR 0x1000
0033
0034
0035 #define CDNS_WDT_PRESCALE_64 64
0036 #define CDNS_WDT_PRESCALE_512 512
0037 #define CDNS_WDT_PRESCALE_4096 4096
0038 #define CDNS_WDT_PRESCALE_SELECT_64 1
0039 #define CDNS_WDT_PRESCALE_SELECT_512 2
0040 #define CDNS_WDT_PRESCALE_SELECT_4096 3
0041
0042
0043 #define CDNS_WDT_CLK_10MHZ 10000000
0044 #define CDNS_WDT_CLK_75MHZ 75000000
0045
0046
0047 #define CDNS_WDT_COUNTER_MAX 0xFFF
0048
0049 static int wdt_timeout;
0050 static int nowayout = WATCHDOG_NOWAYOUT;
0051
0052 module_param(wdt_timeout, int, 0644);
0053 MODULE_PARM_DESC(wdt_timeout,
0054 "Watchdog time in seconds. (default="
0055 __MODULE_STRING(CDNS_WDT_DEFAULT_TIMEOUT) ")");
0056
0057 module_param(nowayout, int, 0644);
0058 MODULE_PARM_DESC(nowayout,
0059 "Watchdog cannot be stopped once started (default="
0060 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074 struct cdns_wdt {
0075 void __iomem *regs;
0076 bool rst;
0077 struct clk *clk;
0078 u32 prescaler;
0079 u32 ctrl_clksel;
0080 spinlock_t io_lock;
0081 struct watchdog_device cdns_wdt_device;
0082 };
0083
0084
0085 static inline void cdns_wdt_writereg(struct cdns_wdt *wdt, u32 offset, u32 val)
0086 {
0087 writel_relaxed(val, wdt->regs + offset);
0088 }
0089
0090
0091
0092
0093 #define CDNS_WDT_ZMR_OFFSET 0x0
0094 #define CDNS_WDT_CCR_OFFSET 0x4
0095 #define CDNS_WDT_RESTART_OFFSET 0x8
0096 #define CDNS_WDT_SR_OFFSET 0xC
0097
0098
0099
0100
0101
0102 #define CDNS_WDT_ZMR_WDEN_MASK 0x00000001
0103 #define CDNS_WDT_ZMR_RSTEN_MASK 0x00000002
0104 #define CDNS_WDT_ZMR_IRQEN_MASK 0x00000004
0105 #define CDNS_WDT_ZMR_RSTLEN_16 0x00000030
0106 #define CDNS_WDT_ZMR_ZKEY_VAL 0x00ABC000
0107
0108
0109
0110
0111
0112 #define CDNS_WDT_CCR_CRV_MASK 0x00003FFC
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124 static int cdns_wdt_stop(struct watchdog_device *wdd)
0125 {
0126 struct cdns_wdt *wdt = watchdog_get_drvdata(wdd);
0127
0128 spin_lock(&wdt->io_lock);
0129 cdns_wdt_writereg(wdt, CDNS_WDT_ZMR_OFFSET,
0130 CDNS_WDT_ZMR_ZKEY_VAL & (~CDNS_WDT_ZMR_WDEN_MASK));
0131 spin_unlock(&wdt->io_lock);
0132
0133 return 0;
0134 }
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145 static int cdns_wdt_reload(struct watchdog_device *wdd)
0146 {
0147 struct cdns_wdt *wdt = watchdog_get_drvdata(wdd);
0148
0149 spin_lock(&wdt->io_lock);
0150 cdns_wdt_writereg(wdt, CDNS_WDT_RESTART_OFFSET,
0151 CDNS_WDT_RESTART_KEY);
0152 spin_unlock(&wdt->io_lock);
0153
0154 return 0;
0155 }
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175 static int cdns_wdt_start(struct watchdog_device *wdd)
0176 {
0177 struct cdns_wdt *wdt = watchdog_get_drvdata(wdd);
0178 unsigned int data = 0;
0179 unsigned short count;
0180 unsigned long clock_f = clk_get_rate(wdt->clk);
0181
0182
0183
0184
0185
0186 count = (wdd->timeout * (clock_f / wdt->prescaler)) /
0187 CDNS_WDT_COUNTER_VALUE_DIVISOR + 1;
0188
0189 if (count > CDNS_WDT_COUNTER_MAX)
0190 count = CDNS_WDT_COUNTER_MAX;
0191
0192 spin_lock(&wdt->io_lock);
0193 cdns_wdt_writereg(wdt, CDNS_WDT_ZMR_OFFSET,
0194 CDNS_WDT_ZMR_ZKEY_VAL);
0195
0196 count = (count << 2) & CDNS_WDT_CCR_CRV_MASK;
0197
0198
0199 data = count | CDNS_WDT_REGISTER_ACCESS_KEY | wdt->ctrl_clksel;
0200 cdns_wdt_writereg(wdt, CDNS_WDT_CCR_OFFSET, data);
0201 data = CDNS_WDT_ZMR_WDEN_MASK | CDNS_WDT_ZMR_RSTLEN_16 |
0202 CDNS_WDT_ZMR_ZKEY_VAL;
0203
0204
0205 if (wdt->rst) {
0206 data |= CDNS_WDT_ZMR_RSTEN_MASK;
0207 data &= ~CDNS_WDT_ZMR_IRQEN_MASK;
0208 } else {
0209 data &= ~CDNS_WDT_ZMR_RSTEN_MASK;
0210 data |= CDNS_WDT_ZMR_IRQEN_MASK;
0211 }
0212 cdns_wdt_writereg(wdt, CDNS_WDT_ZMR_OFFSET, data);
0213 cdns_wdt_writereg(wdt, CDNS_WDT_RESTART_OFFSET,
0214 CDNS_WDT_RESTART_KEY);
0215 spin_unlock(&wdt->io_lock);
0216
0217 return 0;
0218 }
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230 static int cdns_wdt_settimeout(struct watchdog_device *wdd,
0231 unsigned int new_time)
0232 {
0233 wdd->timeout = new_time;
0234
0235 return cdns_wdt_start(wdd);
0236 }
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248 static irqreturn_t cdns_wdt_irq_handler(int irq, void *dev_id)
0249 {
0250 struct platform_device *pdev = dev_id;
0251
0252 dev_info(&pdev->dev,
0253 "Watchdog timed out. Internal reset not enabled\n");
0254
0255 return IRQ_HANDLED;
0256 }
0257
0258
0259
0260
0261
0262 static const struct watchdog_info cdns_wdt_info = {
0263 .identity = "cdns_wdt watchdog",
0264 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
0265 WDIOF_MAGICCLOSE,
0266 };
0267
0268
0269 static const struct watchdog_ops cdns_wdt_ops = {
0270 .owner = THIS_MODULE,
0271 .start = cdns_wdt_start,
0272 .stop = cdns_wdt_stop,
0273 .ping = cdns_wdt_reload,
0274 .set_timeout = cdns_wdt_settimeout,
0275 };
0276
0277 static void cdns_clk_disable_unprepare(void *data)
0278 {
0279 clk_disable_unprepare(data);
0280 }
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291 static int cdns_wdt_probe(struct platform_device *pdev)
0292 {
0293 struct device *dev = &pdev->dev;
0294 int ret, irq;
0295 unsigned long clock_f;
0296 struct cdns_wdt *wdt;
0297 struct watchdog_device *cdns_wdt_device;
0298
0299 wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
0300 if (!wdt)
0301 return -ENOMEM;
0302
0303 cdns_wdt_device = &wdt->cdns_wdt_device;
0304 cdns_wdt_device->info = &cdns_wdt_info;
0305 cdns_wdt_device->ops = &cdns_wdt_ops;
0306 cdns_wdt_device->timeout = CDNS_WDT_DEFAULT_TIMEOUT;
0307 cdns_wdt_device->min_timeout = CDNS_WDT_MIN_TIMEOUT;
0308 cdns_wdt_device->max_timeout = CDNS_WDT_MAX_TIMEOUT;
0309
0310 wdt->regs = devm_platform_ioremap_resource(pdev, 0);
0311 if (IS_ERR(wdt->regs))
0312 return PTR_ERR(wdt->regs);
0313
0314
0315 wdt->rst = of_property_read_bool(dev->of_node, "reset-on-timeout");
0316 irq = platform_get_irq(pdev, 0);
0317 if (!wdt->rst && irq >= 0) {
0318 ret = devm_request_irq(dev, irq, cdns_wdt_irq_handler, 0,
0319 pdev->name, pdev);
0320 if (ret) {
0321 dev_err(dev,
0322 "cannot register interrupt handler err=%d\n",
0323 ret);
0324 return ret;
0325 }
0326 }
0327
0328
0329 cdns_wdt_device->parent = dev;
0330
0331 watchdog_init_timeout(cdns_wdt_device, wdt_timeout, dev);
0332 watchdog_set_nowayout(cdns_wdt_device, nowayout);
0333 watchdog_stop_on_reboot(cdns_wdt_device);
0334 watchdog_set_drvdata(cdns_wdt_device, wdt);
0335
0336 wdt->clk = devm_clk_get(dev, NULL);
0337 if (IS_ERR(wdt->clk))
0338 return dev_err_probe(dev, PTR_ERR(wdt->clk),
0339 "input clock not found\n");
0340
0341 ret = clk_prepare_enable(wdt->clk);
0342 if (ret) {
0343 dev_err(dev, "unable to enable clock\n");
0344 return ret;
0345 }
0346 ret = devm_add_action_or_reset(dev, cdns_clk_disable_unprepare,
0347 wdt->clk);
0348 if (ret)
0349 return ret;
0350
0351 clock_f = clk_get_rate(wdt->clk);
0352 if (clock_f <= CDNS_WDT_CLK_75MHZ) {
0353 wdt->prescaler = CDNS_WDT_PRESCALE_512;
0354 wdt->ctrl_clksel = CDNS_WDT_PRESCALE_SELECT_512;
0355 } else {
0356 wdt->prescaler = CDNS_WDT_PRESCALE_4096;
0357 wdt->ctrl_clksel = CDNS_WDT_PRESCALE_SELECT_4096;
0358 }
0359
0360 spin_lock_init(&wdt->io_lock);
0361
0362 watchdog_stop_on_reboot(cdns_wdt_device);
0363 watchdog_stop_on_unregister(cdns_wdt_device);
0364 ret = devm_watchdog_register_device(dev, cdns_wdt_device);
0365 if (ret)
0366 return ret;
0367 platform_set_drvdata(pdev, wdt);
0368
0369 dev_info(dev, "Xilinx Watchdog Timer with timeout %ds%s\n",
0370 cdns_wdt_device->timeout, nowayout ? ", nowayout" : "");
0371
0372 return 0;
0373 }
0374
0375
0376
0377
0378
0379
0380
0381 static int __maybe_unused cdns_wdt_suspend(struct device *dev)
0382 {
0383 struct cdns_wdt *wdt = dev_get_drvdata(dev);
0384
0385 if (watchdog_active(&wdt->cdns_wdt_device)) {
0386 cdns_wdt_stop(&wdt->cdns_wdt_device);
0387 clk_disable_unprepare(wdt->clk);
0388 }
0389
0390 return 0;
0391 }
0392
0393
0394
0395
0396
0397
0398
0399 static int __maybe_unused cdns_wdt_resume(struct device *dev)
0400 {
0401 int ret;
0402 struct cdns_wdt *wdt = dev_get_drvdata(dev);
0403
0404 if (watchdog_active(&wdt->cdns_wdt_device)) {
0405 ret = clk_prepare_enable(wdt->clk);
0406 if (ret) {
0407 dev_err(dev, "unable to enable clock\n");
0408 return ret;
0409 }
0410 cdns_wdt_start(&wdt->cdns_wdt_device);
0411 }
0412
0413 return 0;
0414 }
0415
0416 static SIMPLE_DEV_PM_OPS(cdns_wdt_pm_ops, cdns_wdt_suspend, cdns_wdt_resume);
0417
0418 static const struct of_device_id cdns_wdt_of_match[] = {
0419 { .compatible = "cdns,wdt-r1p2", },
0420 { }
0421 };
0422 MODULE_DEVICE_TABLE(of, cdns_wdt_of_match);
0423
0424
0425 static struct platform_driver cdns_wdt_driver = {
0426 .probe = cdns_wdt_probe,
0427 .driver = {
0428 .name = "cdns-wdt",
0429 .of_match_table = cdns_wdt_of_match,
0430 .pm = &cdns_wdt_pm_ops,
0431 },
0432 };
0433
0434 module_platform_driver(cdns_wdt_driver);
0435
0436 MODULE_AUTHOR("Xilinx, Inc.");
0437 MODULE_DESCRIPTION("Watchdog driver for Cadence WDT");
0438 MODULE_LICENSE("GPL");