1 /* 2 * Watchdog Device Driver for Xilinx axi/xps_timebase_wdt 3 * 4 * (C) Copyright 2013 - 2014 Xilinx, Inc. 5 * (C) Copyright 2011 (Alejandro Cabrera <aldaya@gmail.com>) 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 10 * 2 of the License, or (at your option) any later version. 11 */ 12 13 #include <linux/err.h> 14 #include <linux/module.h> 15 #include <linux/types.h> 16 #include <linux/kernel.h> 17 #include <linux/ioport.h> 18 #include <linux/watchdog.h> 19 #include <linux/io.h> 20 #include <linux/of.h> 21 #include <linux/of_device.h> 22 #include <linux/of_address.h> 23 24 /* Register offsets for the Wdt device */ 25 #define XWT_TWCSR0_OFFSET 0x0 /* Control/Status Register0 */ 26 #define XWT_TWCSR1_OFFSET 0x4 /* Control/Status Register1 */ 27 #define XWT_TBR_OFFSET 0x8 /* Timebase Register Offset */ 28 29 /* Control/Status Register Masks */ 30 #define XWT_CSR0_WRS_MASK 0x00000008 /* Reset status */ 31 #define XWT_CSR0_WDS_MASK 0x00000004 /* Timer state */ 32 #define XWT_CSR0_EWDT1_MASK 0x00000002 /* Enable bit 1 */ 33 34 /* Control/Status Register 0/1 bits */ 35 #define XWT_CSRX_EWDT2_MASK 0x00000001 /* Enable bit 2 */ 36 37 /* SelfTest constants */ 38 #define XWT_MAX_SELFTEST_LOOP_COUNT 0x00010000 39 #define XWT_TIMER_FAILED 0xFFFFFFFF 40 41 #define WATCHDOG_NAME "Xilinx Watchdog" 42 43 struct xwdt_device { 44 void __iomem *base; 45 u32 wdt_interval; 46 spinlock_t spinlock; 47 struct watchdog_device xilinx_wdt_wdd; 48 }; 49 50 static int xilinx_wdt_start(struct watchdog_device *wdd) 51 { 52 u32 control_status_reg; 53 struct xwdt_device *xdev = watchdog_get_drvdata(wdd); 54 55 spin_lock(&xdev->spinlock); 56 57 /* Clean previous status and enable the watchdog timer */ 58 control_status_reg = ioread32(xdev->base + XWT_TWCSR0_OFFSET); 59 control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK); 60 61 iowrite32((control_status_reg | XWT_CSR0_EWDT1_MASK), 62 xdev->base + XWT_TWCSR0_OFFSET); 63 64 iowrite32(XWT_CSRX_EWDT2_MASK, xdev->base + XWT_TWCSR1_OFFSET); 65 66 spin_unlock(&xdev->spinlock); 67 68 return 0; 69 } 70 71 static int xilinx_wdt_stop(struct watchdog_device *wdd) 72 { 73 u32 control_status_reg; 74 struct xwdt_device *xdev = watchdog_get_drvdata(wdd); 75 76 spin_lock(&xdev->spinlock); 77 78 control_status_reg = ioread32(xdev->base + XWT_TWCSR0_OFFSET); 79 80 iowrite32((control_status_reg & ~XWT_CSR0_EWDT1_MASK), 81 xdev->base + XWT_TWCSR0_OFFSET); 82 83 iowrite32(0, xdev->base + XWT_TWCSR1_OFFSET); 84 85 spin_unlock(&xdev->spinlock); 86 pr_info("Stopped!\n"); 87 88 return 0; 89 } 90 91 static int xilinx_wdt_keepalive(struct watchdog_device *wdd) 92 { 93 u32 control_status_reg; 94 struct xwdt_device *xdev = watchdog_get_drvdata(wdd); 95 96 spin_lock(&xdev->spinlock); 97 98 control_status_reg = ioread32(xdev->base + XWT_TWCSR0_OFFSET); 99 control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK); 100 iowrite32(control_status_reg, xdev->base + XWT_TWCSR0_OFFSET); 101 102 spin_unlock(&xdev->spinlock); 103 104 return 0; 105 } 106 107 static const struct watchdog_info xilinx_wdt_ident = { 108 .options = WDIOF_MAGICCLOSE | 109 WDIOF_KEEPALIVEPING, 110 .firmware_version = 1, 111 .identity = WATCHDOG_NAME, 112 }; 113 114 static const struct watchdog_ops xilinx_wdt_ops = { 115 .owner = THIS_MODULE, 116 .start = xilinx_wdt_start, 117 .stop = xilinx_wdt_stop, 118 .ping = xilinx_wdt_keepalive, 119 }; 120 121 static u32 xwdt_selftest(struct xwdt_device *xdev) 122 { 123 int i; 124 u32 timer_value1; 125 u32 timer_value2; 126 127 spin_lock(&xdev->spinlock); 128 129 timer_value1 = ioread32(xdev->base + XWT_TBR_OFFSET); 130 timer_value2 = ioread32(xdev->base + XWT_TBR_OFFSET); 131 132 for (i = 0; 133 ((i <= XWT_MAX_SELFTEST_LOOP_COUNT) && 134 (timer_value2 == timer_value1)); i++) { 135 timer_value2 = ioread32(xdev->base + XWT_TBR_OFFSET); 136 } 137 138 spin_unlock(&xdev->spinlock); 139 140 if (timer_value2 != timer_value1) 141 return ~XWT_TIMER_FAILED; 142 else 143 return XWT_TIMER_FAILED; 144 } 145 146 static int xwdt_probe(struct platform_device *pdev) 147 { 148 int rc; 149 u32 pfreq = 0, enable_once = 0; 150 struct resource *res; 151 struct xwdt_device *xdev; 152 struct watchdog_device *xilinx_wdt_wdd; 153 154 xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL); 155 if (!xdev) 156 return -ENOMEM; 157 158 xilinx_wdt_wdd = &xdev->xilinx_wdt_wdd; 159 xilinx_wdt_wdd->info = &xilinx_wdt_ident; 160 xilinx_wdt_wdd->ops = &xilinx_wdt_ops; 161 xilinx_wdt_wdd->parent = &pdev->dev; 162 163 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 164 xdev->base = devm_ioremap_resource(&pdev->dev, res); 165 if (IS_ERR(xdev->base)) 166 return PTR_ERR(xdev->base); 167 168 rc = of_property_read_u32(pdev->dev.of_node, "clock-frequency", &pfreq); 169 if (rc) 170 dev_warn(&pdev->dev, 171 "The watchdog clock frequency cannot be obtained\n"); 172 173 rc = of_property_read_u32(pdev->dev.of_node, "xlnx,wdt-interval", 174 &xdev->wdt_interval); 175 if (rc) 176 dev_warn(&pdev->dev, 177 "Parameter \"xlnx,wdt-interval\" not found\n"); 178 179 rc = of_property_read_u32(pdev->dev.of_node, "xlnx,wdt-enable-once", 180 &enable_once); 181 if (rc) 182 dev_warn(&pdev->dev, 183 "Parameter \"xlnx,wdt-enable-once\" not found\n"); 184 185 watchdog_set_nowayout(xilinx_wdt_wdd, enable_once); 186 187 /* 188 * Twice of the 2^wdt_interval / freq because the first wdt overflow is 189 * ignored (interrupt), reset is only generated at second wdt overflow 190 */ 191 if (pfreq && xdev->wdt_interval) 192 xilinx_wdt_wdd->timeout = 2 * ((1 << xdev->wdt_interval) / 193 pfreq); 194 195 spin_lock_init(&xdev->spinlock); 196 watchdog_set_drvdata(xilinx_wdt_wdd, xdev); 197 198 rc = xwdt_selftest(xdev); 199 if (rc == XWT_TIMER_FAILED) { 200 dev_err(&pdev->dev, "SelfTest routine error\n"); 201 return rc; 202 } 203 204 rc = watchdog_register_device(xilinx_wdt_wdd); 205 if (rc) { 206 dev_err(&pdev->dev, "Cannot register watchdog (err=%d)\n", rc); 207 return rc; 208 } 209 210 dev_info(&pdev->dev, "Xilinx Watchdog Timer at %p with timeout %ds\n", 211 xdev->base, xilinx_wdt_wdd->timeout); 212 213 platform_set_drvdata(pdev, xdev); 214 215 return 0; 216 } 217 218 static int xwdt_remove(struct platform_device *pdev) 219 { 220 struct xwdt_device *xdev = platform_get_drvdata(pdev); 221 222 watchdog_unregister_device(&xdev->xilinx_wdt_wdd); 223 224 return 0; 225 } 226 227 /* Match table for of_platform binding */ 228 static const struct of_device_id xwdt_of_match[] = { 229 { .compatible = "xlnx,xps-timebase-wdt-1.00.a", }, 230 { .compatible = "xlnx,xps-timebase-wdt-1.01.a", }, 231 {}, 232 }; 233 MODULE_DEVICE_TABLE(of, xwdt_of_match); 234 235 static struct platform_driver xwdt_driver = { 236 .probe = xwdt_probe, 237 .remove = xwdt_remove, 238 .driver = { 239 .owner = THIS_MODULE, 240 .name = WATCHDOG_NAME, 241 .of_match_table = xwdt_of_match, 242 }, 243 }; 244 245 module_platform_driver(xwdt_driver); 246 247 MODULE_AUTHOR("Alejandro Cabrera <aldaya@gmail.com>"); 248 MODULE_DESCRIPTION("Xilinx Watchdog driver"); 249 MODULE_LICENSE("GPL v2"); 250