MOXA linux-2.6.x / linux-2.6.9-uc0 from sdlinux-moxaart.tgz
[linux-2.6.9-moxart.git] / drivers / char / mcfwatchdog.c
blob9cc2b6de81399aca13cbb30eb9047f2a794e9cff
1 /***************************************************************************/
3 /*
4 * linux/drivers/char/mcfwatchdog.c
6 * Copyright (C) 1999-2000, Greg Ungerer (gerg@snapgear.com)
7 * Copyright (C) 2000 Lineo Inc. (www.lineo.com)
9 * Changes:
10 * 10/28/2004 Christian Magnusson <mag@mag.cx>
11 * Bug: MCFSIM_SYPCR can only be written once after reset!
12 * MCF5272 support copied from 2.4.x driver.
13 * Reset on overflow. (For 5206e at least)
14 * Added module support.
15 * I have noticed that some flash-identification from mtd
16 * locks the processor too long, and therefor this watchdog
17 * has to be used as a module and started after mtd is done.
21 /***************************************************************************/
23 #include <linux/config.h>
24 #include <linux/module.h>
25 #include <linux/miscdevice.h>
26 #include <linux/watchdog.h>
27 #include <linux/fs.h>
28 #include <linux/kernel.h>
29 #include <linux/sched.h>
30 #include <linux/param.h>
31 #include <linux/notifier.h>
32 #include <linux/reboot.h>
33 #include <asm/irq.h>
34 #include <asm/traps.h>
35 #include <asm/machdep.h>
36 #include <asm/coldfire.h>
37 #include <asm/mcftimer.h>
38 #include <asm/mcfsim.h>
39 #include <asm/irq.h>
40 #include <asm/delay.h>
42 /***************************************************************************/
45 * Define the watchdog vector.
47 #ifdef CONFIG_M5272
48 #define IRQ_WATCHDOG 92
49 #define TIMEPOLL 100
50 #else
51 #define IRQ_WATCHDOG 250
52 #define TIMEPOLL HZ/100
53 #endif
55 #if defined(CONFIG_M5206e)
56 #define RESET_ON_SWTR
57 #endif
59 /***************************************************************************/
61 void watchdog_alive(unsigned long arg);
62 static irqreturn_t watchdog_timeout(int irq, void *dummy, struct pt_regs *fp);
64 #ifndef MODULE
65 extern void dump(struct pt_regs *fp);
66 #endif
69 * Data for registering the watchdog alive routine with ticker.
71 static struct timer_list watchdog_timerlist;
73 static int watchdog_overflows;
75 #ifdef CONFIG_OLDMASK
77 * The old mask 5307 has a broken watchdog timer. It will interrupt
78 * you regardless of writing to its "alive" register. It can still
79 * be useful but you have to play some tricks with it. This code
80 * supports a clock ticker timeout. If the right number of clock
81 * ticks are not counted then it is assumed that the watchdog saved
82 * us from a bad bus cycle.
84 #define SWTREF_COUNT 25
86 int swt_inwatchdog = 0; /* Has watchdog expired */
87 int swt_doit = 0; /* Start delay before tripping */
88 int swt_lastjiffies = 0; /* Tick count at last watchdog */
89 int swt_reference = SWTREF_COUNT; /* Refereence tick count */
90 #endif
93 static struct file_operations watchdog_fops = {
94 .owner = THIS_MODULE,
97 static struct miscdevice watchdog_miscdev = {
98 .minor = WATCHDOG_MINOR,
99 .name = "watchdog",
100 .fops = &watchdog_fops,
103 /***************************************************************************/
106 * Software Watchdog Timer enable. Seems to be the same across all
107 * ColdFire CPU members.
109 void watchdog_enable(void)
111 #ifdef CONFIG_M5272
112 *(volatile unsigned short *)(MCF_MBAR + MCFSIM_WRRR) = 0x2001; // upper watchdog limit
113 *(volatile unsigned short *)(MCF_MBAR + MCFSIM_WIRR) = 0x1000; // we don't do interrupts, just reset (o;
114 *(volatile unsigned short *)(MCF_MBAR + MCFSIM_WCR) = 0x0000; // clear counter
115 #else /* CONFIG_M5272 */
116 volatile unsigned char *mbar = (volatile unsigned char *) MCF_MBAR;
117 *(mbar + MCFSIM_SWSR) = 0x55;
118 *(mbar + MCFSIM_SWSR) = 0xaa; // kick watchdog
121 SYPCR Can only be written once after system reset!
122 0x80 Software Watchdog, 0="Disable" / 1="Enable"
123 0x40 Software Watchdog, 0="level7 interrupt" / 1="reset"
124 0x20 Watchdog prescaled (SWP), 0="1" / 1="512"
125 0x10 Timing SWT1
126 0x08 Timing SWT0
127 SWT|SWT1|SWT0
128 000=2^9 001=2^11 010=2^13 011=2^15 / System Freq.
129 100=2^18 101=2^20 110=2^22 111=2^24 / System Freq.
130 0x04 Bus Timeout Monitor BMTE 0="Disable" / 1="Enable"
131 0x02 Bus Monitor Timing BMT1
132 0x01 Bus Monitor Timing BMT0
133 BMT1|BMT0
134 00=1024 01=512 10=256 11=128 system clocks
136 #ifdef CONFIG_OLDMASK
137 *(mbar + MCFSIM_SYPCR) = 0xbe; // level 7 interrupt, 2^22
138 #else
140 #ifdef RESET_ON_SWTR
141 *(mbar + MCFSIM_SYPCR) = 0xfe; // reset, 2^22
142 #else
143 *(mbar + MCFSIM_SYPCR) = 0xbe; // level 7 interrupt, 2^22
144 #endif /* RESET_ON_SWTR */
145 #endif /* CONFIG_OLDMASK */
146 #endif /* CONFIG_M5272 */
149 /***************************************************************************/
151 void watchdog_disable(void)
153 #ifdef CONFIG_M5272
154 *(volatile unsigned short *)(MCF_MBAR + MCFSIM_WRRR) = 0xFFFE;
155 *(volatile unsigned short *)(MCF_MBAR + MCFSIM_WIRR) = 0x0000;
156 *(volatile unsigned short *)(MCF_MBAR + MCFSIM_WCR) = 0x0000;
157 #else
158 volatile unsigned char *mbar = (volatile unsigned char *) MCF_MBAR;
160 If watchdog is set to 'reset', this function is useless...
161 If timer is disabled, this reset will occour at once.
163 *(mbar + MCFSIM_SWSR) = 0x55;
164 *(mbar + MCFSIM_SWSR) = 0xaa;
165 #if 0
167 SYPCR Can only be written once after system reset!
168 This will probably be ignored according to MCF5206E User Manual
170 *(mbar + MCFSIM_SYPCR) = 0x00 /*0x3e*/;
171 #endif
172 mcf_setimr(mcf_getimr() | MCFSIM_IMR_SWD);
173 #endif
174 del_timer(&watchdog_timerlist);
177 /***************************************************************************/
179 static int watchdog_notify_sys(struct notifier_block *this, unsigned long code,
180 void *unused)
182 if(code==SYS_DOWN || code==SYS_HALT) {
183 /* Turn the card off */
184 watchdog_disable();
186 If watchdog is set to 'reset', this function is useless...
187 When timer is disabled, reset will occour during reboot...
190 return NOTIFY_DONE;
193 static struct notifier_block watchdog_notifier = {
194 .notifier_call = watchdog_notify_sys,
197 /***************************************************************************/
200 * Process a watchdog timeout interrupt. For a normal clean watchdog
201 * we just do a process dump. For old broken 5307 we need to verify
202 * if this was a real watchdog event or not...
204 static irqreturn_t watchdog_timeout(int irq, void *dummy, struct pt_regs *fp)
206 #ifdef CONFIG_OLDMASK
207 #define TIMEDELAY 45
209 * Debuging code for software watchdog. If we get in here
210 * and timer interrupt counts don't match we know that a
211 * bad external bus cycle must have locked the CPU.
213 if ((swt_doit++ > TIMEDELAY) &&
214 ((swt_lastjiffies + swt_reference) > jiffies)) {
215 if (swt_inwatchdog) {
216 cli();
217 watchdog_disable();
218 mcf_setimr(mcf_getimr() | MCFSIM_IMR_SWD);
219 printk("%s(%d): Double WATCHDOG PANIC!!\n",
220 __FILE__, __LINE__);
221 for (;;)
225 swt_inwatchdog++;
226 swt_doit = TIMEDELAY - 8; /* 8 seconds grace */
227 printk("mcfwatchdog: expired last=%d(%d) jiffies=%d!\n",
228 swt_lastjiffies, swt_reference, jiffies);
229 #ifndef MODULE
230 dump(fp);
231 #endif
232 force_sig(SIGSEGV, current);
233 swt_inwatchdog = 0;
235 swt_lastjiffies = jiffies;
236 #else
238 #ifdef RESET_ON_SWTR
239 /* nothing will be done... reset will occour */
240 #else /* RESET_ON_SWTR */
241 // lev7 interrupt is used.
242 if(++watchdog_overflows >= 10) {
244 printk("mcfwatchdog: expired!\n");
245 #ifndef MODULE
246 dump(fp);
247 #endif
248 mcf_setimr(mcf_getimr() | MCFSIM_IMR_SWD);
249 HARD_RESET_NOW();
250 for (;;) ; // hang until reboot
251 } else {
252 volatile unsigned char *mbar = (volatile unsigned char *) MCF_MBAR;
253 *(mbar + MCFSIM_SWSR) = 0x55;
254 *(mbar + MCFSIM_SWSR) = 0xaa; // kick watchdog
256 #endif /* RESET_ON_SWTR */
257 #endif /* CONFIG_OLDMASK */
258 return IRQ_HANDLED;
261 /***************************************************************************/
263 static int __init watchdog_init(void)
265 printk("mcfwatchdog: initializing at vector=%d\n", IRQ_WATCHDOG);
267 if(misc_register(&watchdog_miscdev))
268 return -ENODEV;
270 if(register_reboot_notifier(&watchdog_notifier)) {
271 printk("watchdog: cannot register reboot notifier\n");
272 return 1;
275 request_irq(IRQ_WATCHDOG, watchdog_timeout, SA_INTERRUPT,
276 "Watchdog Timer", &watchdog_miscdev);
278 init_timer (&watchdog_timerlist);
279 watchdog_timerlist.function = watchdog_alive;
280 watchdog_timerlist.expires = (jiffies + 1);
281 add_timer(&watchdog_timerlist);
283 #ifdef CONFIG_M5272
285 volatile unsigned long *icrp;
286 icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR4);
287 *icrp = (*icrp & 0x77707777) | 0x000E0000;
288 watchdog_enable();
290 #else /* CONFIG_M5272 */
292 volatile unsigned char *mbar = (volatile unsigned char *) MCF_MBAR;
293 unsigned char ch;
295 ch = *(mbar + MCFSIM_RSR);
296 printk("mcfwatchdog: Last reset was generated by %s\n",
297 (ch&0x80 ? "HRST": (ch&0x20 ? "SWTR":"")));
299 #ifdef RESET_ON_SWTR
300 // high priority just to make sure watchdog won't overflow.
301 *(mbar + MCFSIM_SWDICR) = MCFSIM_ICR_LEVEL1 | MCFSIM_ICR_PRI1;
302 #else
303 *(mbar + MCFSIM_SWDICR) = MCFSIM_ICR_LEVEL1 | MCFSIM_ICR_PRI3;
304 #endif
305 *(mbar + MCFSIM_SWIVR) = IRQ_WATCHDOG;
306 mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_SWD);
307 watchdog_enable();
309 printk("mcfwatchdog: Coldfire watchdog is enabled, \"%s\" is generated on error\n",
310 ((*(mbar + MCFSIM_SYPCR) & 0x40)?
311 "Reset" : "Level7 interrupt"));
313 #ifdef MODULE
314 if(*(mbar + MCFSIM_SYPCR) & 0x40) {
315 printk("mcfwatchdog: Warning: If module is unloaded, Watchdog will reset card.\n");
317 #endif
319 #endif /* CONFIG_M5272 */
320 return 0;
323 /***************************************************************************/
325 static void __exit watchdog_exit(void)
327 #ifdef CONFIG_M5272
328 /* Reset watchdog counter */
329 *(volatile unsigned short *)(MCF_MBAR + MCFSIM_WCR) = 0x0000;
330 #else
331 volatile unsigned char *mbar = (volatile unsigned char *) MCF_MBAR;
332 *(mbar + MCFSIM_RSR) = 0; // clear reset cause
333 #endif
334 unregister_reboot_notifier(&watchdog_notifier);
335 misc_deregister(&watchdog_miscdev);
336 watchdog_disable();
337 printk("mcfwatchdog: Coldfire watchdog is disabled and unloaded\n");
340 /***************************************************************************/
342 void watchdog_alive(unsigned long arg)
344 #ifdef CONFIG_M5272
345 /* Reset watchdog counter */
346 *(volatile unsigned short *)(MCF_MBAR + MCFSIM_WCR) = 0x0000;
347 #else
348 volatile unsigned char *mbar = (volatile unsigned char *) MCF_MBAR;
349 *(mbar + MCFSIM_SWSR) = 0x55;
350 *(mbar + MCFSIM_SWSR) = 0xaa; // kick watchdog
351 #endif
352 /* Re-arm the watchdog alive poll */
353 mod_timer(&watchdog_timerlist, jiffies+TIMEPOLL);
354 watchdog_overflows = 0;
357 /***************************************************************************/
359 module_init(watchdog_init);
360 module_exit(watchdog_exit);
362 MODULE_AUTHOR("Greg Ungerer");
363 MODULE_DESCRIPTION("Coldfire Watchdog Driver");
364 MODULE_LICENSE("GPL");
366 /***************************************************************************/