* refresh storm patches * disable BX in uClibc config, add ethernet and watchdog...
[librecmc/librecmc.git] / target / linux / storm / patches / 1022-watchdog.patch
1 --- a/arch/arm/mach-sl2312/sl3516_device.c
2 +++ b/arch/arm/mach-sl2312/sl3516_device.c
3 @@ -76,9 +76,30 @@
4         .resource       = sl3516_sata0_resources,
5  };
6  
7 +static struct resource sl351x_wdt_resources[] = {
8 +       [0] = {
9 +               .start  = SL2312_WAQTCHDOG_BASE + 0x00,
10 +               .end    = SL2312_WAQTCHDOG_BASE + 0x1C,
11 +               .flags  = IORESOURCE_MEM,
12 +       },
13 +       [1] = {
14 +               .start  = IRQ_WATCHDOG,
15 +               .end    = IRQ_WATCHDOG,
16 +               .flags  = IORESOURCE_IRQ,
17 +       },
18 +};
19 +
20 +static struct platform_device sl351x_wdt = {
21 +       .name           = "sl351x-wdt",
22 +       .id             = -1,
23 +       .resource       = sl351x_wdt_resources,
24 +       .num_resources  = ARRAY_SIZE(sl351x_wdt_resources),
25 +};
26 +
27  static struct platform_device *sata_devices[] __initdata = {
28         &sata_device,
29         &sata0_device,
30 +       &sl351x_wdt,
31  };
32  
33  static int __init sl3516_init(void)
34 --- a/drivers/char/watchdog/Kconfig
35 +++ b/drivers/char/watchdog/Kconfig
36 @@ -171,6 +171,17 @@
37           To compile this driver as a module, choose M here: the
38           module will be called ep93xx_wdt.
39  
40 +config WATCHDOG_SL351X
41 +       tristate "SL351x Watchdog"
42 +       depends on WATCHDOG && ARCH_SL2312
43 +       help
44 +         This driver adds watchdog support for the integrated watchdog in the
45 +         SL351x processors (Farraday core). If you have one of these processors
46 +         and wish to have watchdog support enabled, say Y, otherwise say N.
47 +
48 +         To compile this driver as a module, choose M here: the
49 +         module will be called sl351x_wdt.
50 +
51  config OMAP_WATCHDOG
52         tristate "OMAP Watchdog"
53         depends on ARCH_OMAP16XX || ARCH_OMAP24XX
54 --- a/drivers/char/watchdog/Makefile
55 +++ b/drivers/char/watchdog/Makefile
56 @@ -36,6 +36,7 @@
57  obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
58  obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
59  obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
60 +obj-$(CONFIG_WATCHDOG_SL351X) += sl351x_wdt.o
61  obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
62  obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
63  obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
64 --- /dev/null
65 +++ b/drivers/char/watchdog/sl351x_wdt.c
66 @@ -0,0 +1,332 @@
67 +#include <linux/module.h>
68 +#include <linux/types.h>
69 +#include <linux/fs.h>
70 +#include <linux/mm.h>
71 +#include <linux/errno.h>
72 +#include <linux/init.h>
73 +#include <linux/miscdevice.h>
74 +#include <linux/watchdog.h>
75 +#include <linux/platform_device.h>
76 +#include <asm/uaccess.h>
77 +#include <asm/arch/sl2312.h>
78 +#include <asm/arch/hardware.h>
79 +#include <asm/arch/irqs.h>
80 +#include <asm/arch/watchdog.h>
81 +#include <asm/io.h>
82 +#include <linux/interrupt.h>
83 +
84 +#define WATCHDOG_TEST 1
85 +#define PFX "sl351x-wdt: "
86 +
87 +#define _WATCHDOG_COUNTER  0x00
88 +#define _WATCHDOG_LOAD     0x04
89 +#define _WATCHDOG_RESTART  0x08
90 +#define _WATCHDOG_CR       0x0C
91 +#define _WATCHDOG_STATUS   0x10
92 +#define _WATCHDOG_CLEAR    0x14
93 +#define _WATCHDOG_INTRLEN  0x18
94 +
95 +static struct resource  *wdt_mem;
96 +static struct resource  *wdt_irq;
97 +static void __iomem     *wdt_base;
98 +static int             wdt_margin = WATCHDOG_TIMEOUT_MARGIN;   /* in range of 0 .. 60s */
99 +
100 +static int open_state = WATCHDOG_DRIVER_CLOSE;
101 +static int wd_expire = 0;
102 +
103 +static void watchdog_enable(void)
104 +{
105 +       unsigned long wdcr;
106 +
107 +       wdcr = readl(wdt_base + _WATCHDOG_CR);
108 +       wdcr |= (WATCHDOG_WDENABLE_MSK|WATCHDOG_WDRST_MSK);
109 +#ifdef WATCHDOG_TEST
110 +       wdcr |= WATCHDOG_WDINTR_MSK;
111 +//     wdcr &= ~WATCHDOG_WDRST_MSK;
112 +#endif
113 +       wdcr &= ~WATCHDOG_WDCLOCK_MSK;
114 +       writel(wdcr, wdt_base + _WATCHDOG_CR);
115 +}
116 +
117 +static void watchdog_set_timeout(unsigned long timeout)
118 +{
119 +       timeout = WATCHDOG_TIMEOUT_SCALE * timeout;
120 +       writel(timeout, wdt_base + _WATCHDOG_LOAD);
121 +       writel(WATCHDOG_RESTART_VALUE, wdt_base + _WATCHDOG_RESTART);
122 +}
123 +
124 +static void watchdog_keepalive(void)
125 +{
126 +       writel(WATCHDOG_RESTART_VALUE, wdt_base + _WATCHDOG_RESTART);
127 +}
128 +
129 +static void watchdog_disable(void)
130 +{
131 +       unsigned long wdcr;
132 +
133 +       wdcr = readl(wdt_base + _WATCHDOG_CR);
134 +       wdcr &= ~WATCHDOG_WDENABLE_MSK;
135 +       writel(wdcr, wdt_base + _WATCHDOG_CR);
136 +}
137 +
138 +
139 +#ifdef WATCHDOG_TEST
140 +static irqreturn_t watchdog_irq(int irq, void *dev_id, struct pt_regs *regs)
141 +{
142 +       unsigned int clear;
143 +
144 +       writel(WATCHDOG_CLEAR_STATUS, wdt_base + _WATCHDOG_CLEAR);
145 +       printk(KERN_INFO PFX "Watchdog timeout, resetting system...\n");
146 +
147 +       clear = __raw_readl(IO_ADDRESS(SL2312_INTERRUPT_BASE)+0x0C);
148 +       clear &= 0x01;
149 +       __raw_writel(clear,IO_ADDRESS(SL2312_INTERRUPT_BASE)+0x08);
150 +       wd_expire = 1;
151 +       return IRQ_HANDLED;
152 +}
153 +
154 +#endif
155 +
156 +#define OPTIONS WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE
157 +static struct watchdog_info sl351x_wdt_ident = {
158 +       .options          =     OPTIONS,
159 +       .firmware_version =     0,
160 +       .identity         =     "sl351x Watchdog",
161 +};
162 +
163 +struct file_operations watchdog_fops = {
164 +       .write          = watchdog_write,
165 +       .read           = watchdog_read,
166 +       .open           = watchdog_open,
167 +       .release        = watchdog_release,
168 +       .ioctl          = watchdog_ioctl,
169 +};
170 +
171 +static int watchdog_open(struct inode *inode, struct file *filp)
172 +{
173 +       if (open_state == WATCHDOG_DRIVER_OPEN)
174 +               return -EBUSY;
175 +
176 +       wd_expire = 0;
177 +
178 +       watchdog_disable();
179 +       watchdog_set_timeout(wdt_margin);
180 +       watchdog_enable();
181 +
182 +       printk(KERN_INFO PFX "watchog timer enabled, margin: %ds.\n", wdt_margin);
183 +       open_state = WATCHDOG_DRIVER_OPEN;
184 +
185 +       return nonseekable_open(inode, filp);
186 +}
187 +
188 +static int watchdog_release(struct inode *inode, struct file *filp)
189 +{
190 +       watchdog_disable();
191 +
192 +       open_state = WATCHDOG_DRIVER_CLOSE;
193 +       wd_expire = 0;
194 +       printk(KERN_INFO PFX "watchog timer disabled, margin: %ds.\n", wdt_margin);
195 +
196 +       return 0;
197 +}
198 +
199 +static ssize_t watchdog_read(struct file *filp, char *buf, size_t count, loff_t *off)
200 +{
201 +       int i;
202 +       unsigned long val;
203 +
204 +
205 +       for(i=0;i< count;i++)
206 +       {
207 +               if ((i%4)==0)
208 +                       val = *((unsigned long *)WATCHDOG_COUNTER);
209 +               buf[i] = (val & 0xFF);
210 +               val >>= 8;
211 +       }
212 +       return count;
213 +}
214 +
215 +static ssize_t watchdog_write(struct file *filp, const char *buf, size_t len, loff_t *off)
216 +{
217 +       /*  Refresh the timer. */
218 +       if (len) {
219 +               watchdog_keepalive();
220 +       }
221 +       return len;
222 +
223 +}
224 +
225 +static int watchdog_ioctl(struct inode *inode, struct file *filp,
226 +                         unsigned int cmd, unsigned long arg)
227 +{
228 +       void __user *argp = (void __user *)arg;
229 +       int margin;
230 +
231 +       switch(cmd)
232 +       {
233 +       case WDIOC_GETSUPPORT:
234 +               return copy_to_user(argp, &sl351x_wdt_ident,
235 +                                   sizeof(sl351x_wdt_ident)) ? -EFAULT : 0;
236 +
237 +       case WDIOC_GETSTATUS:
238 +       case WDIOC_GETBOOTSTATUS:
239 +               return put_user(0, (int __user*)argp);
240 +
241 +       case WDIOC_KEEPALIVE:
242 +               watchdog_keepalive();
243 +               return 0;
244 +
245 +       case WDIOC_SETTIMEOUT:
246 +               if (get_user(margin, (int __user*)argp))
247 +                       return -EFAULT;
248 +
249 +               /* Arbitrary, can't find the card's limits */
250 +               if ((margin < 0) || (margin > 60))
251 +                       return -EINVAL;
252 +
253 +               // watchdog_disable();
254 +               wdt_margin = margin;
255 +               watchdog_set_timeout(margin);
256 +               watchdog_keepalive();
257 +               // watchdog_enable();
258 +
259 +               /* Fall through */
260 +
261 +       case WDIOC_GETTIMEOUT:
262 +               return put_user(wdt_margin, (int *)arg);
263 +
264 +       default:
265 +               return -ENOIOCTLCMD;
266 +       }
267 +}
268 +
269 +static struct miscdevice wd_dev= {
270 +       WATCHDOG_MINOR,
271 +       "watchdog",
272 +       &watchdog_fops
273 +};
274 +
275 +static char banner[] __initdata = KERN_INFO "SL351x Watchdog Timer, (c) 2007 WILIBOX\n";
276 +
277 +static int sl351x_wdt_probe(struct platform_device *pdev)
278 +{
279 +       struct resource *res;
280 +       int ret, size;
281 +       unsigned long wdcr;
282 +
283 +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
284 +       if (res == NULL) {
285 +               printk(KERN_INFO PFX "failed to get memory region resouce\n");
286 +               return -ENOMEM;
287 +       }
288 +
289 +       size = (res->end-res->start)+1;
290 +
291 +       wdt_mem = request_mem_region(res->start, size, pdev->name);
292 +       if (wdt_mem == NULL) {
293 +               printk(KERN_INFO PFX "failed to get memory region\n");
294 +               return -ENOENT;
295 +       }
296 +
297 +       wdt_base = ioremap(res->start, size);
298 +       if (wdt_base == NULL) {
299 +               printk(KERN_INFO PFX "failed to ioremap() region\n");
300 +               return -EINVAL;
301 +       }
302 +
303 +       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
304 +       if (res == NULL) {
305 +                printk(KERN_INFO PFX "failed to get irq resource\n");
306 +                return -ENOENT;
307 +       }
308 +
309 +       wdt_irq = res;
310 +
311 +       ret = request_irq(res->start, watchdog_irq, 0, pdev->name, pdev);
312 +       if (ret != 0) {
313 +               printk(KERN_INFO PFX "failed to install irq (%d)\n", ret);
314 +               return ret;
315 +       }
316 +
317 +       wdcr = readl(wdt_base + _WATCHDOG_CR);
318 +       if (wdcr & WATCHDOG_WDENABLE_MSK) {
319 +               printk(KERN_INFO PFX "Found watchdog in enabled state, reseting ...\n");
320 +               wdcr &= ~WATCHDOG_WDENABLE_MSK;
321 +               writel(wdcr, wdt_base + _WATCHDOG_CR);
322 +       }
323 +
324 +       ret = misc_register(&wd_dev);
325 +
326 +       return ret;
327 +}
328 +
329 +static int sl351x_wdt_remove(struct platform_device *pdev)
330 +{
331 +       if (wdt_base != NULL) {
332 +               iounmap(wdt_base);
333 +               wdt_base = NULL;
334 +       }
335 +
336 +       if (wdt_irq != NULL) {
337 +               free_irq(wdt_irq->start, pdev);
338 +               release_resource(wdt_irq);
339 +               wdt_irq = NULL;
340 +       }
341 +
342 +       if (wdt_mem != NULL) {
343 +               release_resource(wdt_mem);
344 +               wdt_mem = NULL;
345 +       }
346 +
347 +       misc_deregister(&wd_dev);
348 +
349 +       return 0;
350 +}
351 +
352 +static void sl351x_wdt_shutdown(struct platform_device *dev)
353 +{
354 +       watchdog_disable();
355 +}
356 +
357 +#ifdef CONFIG_PM
358 +static int sl351x_wdt_suspend(struct platform_device *dev, pm_message_t state)
359 +{
360 +       watchdog_disable();
361 +}
362 +
363 +static int sl351x_wdt_resume(struct platform_device *dev)
364 +{
365 +       watchdog_set_timeout(wdt_margin);
366 +       watchdog_enable();
367 +}
368 +
369 +#else
370 +#define sl351x_wdt_suspend     NULL
371 +#define sl351x_wdt_resume      NULL
372 +#endif
373 +
374 +static struct platform_driver sl351x_wdt_driver = {
375 +       .probe          = sl351x_wdt_probe,
376 +       .remove         = sl351x_wdt_remove,
377 +       .shutdown       = sl351x_wdt_shutdown,
378 +       .suspend        = sl351x_wdt_suspend,
379 +       .resume         = sl351x_wdt_resume,
380 +       .driver         = {
381 +               .owner  = THIS_MODULE,
382 +               .name   = "sl351x-wdt",
383 +       },
384 +};
385 +
386 +static int __init watchdog_init(void)
387 +{
388 +       printk(banner);
389 +       return platform_driver_register(&sl351x_wdt_driver);
390 +}
391 +
392 +static void __exit watchdog_exit(void)
393 +{
394 +       platform_driver_unregister(&sl351x_wdt_driver);
395 +}
396 +
397 +module_init(watchdog_init);
398 +module_exit(watchdog_exit);