aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKumar Gala <galak@freescale.com>2005-09-03 18:55:33 -0400
committerLinus Torvalds <torvalds@evo.osdl.org>2005-09-05 03:05:56 -0400
commita2f40ccd294d14e5aca464c1913e8e0d8de35fca (patch)
treed900ebdbf37656d77acf7934db40021b21d49fde
parent886b9fa49900b055e20cd98f379fda49835d1ee6 (diff)
[PATCH] ppc32: Added support for the Book-E style Watchdog Timer
PowerPC 40x and Book-E processors support a watchdog timer at the processor core level. The timer has implementation dependent timeout frequencies that can be configured by software. One the first Watchdog timeout we get a critical exception. It is left to board specific code to determine what should happen at this point. If nothing is done and another timeout period expires the processor may attempt to reset the machine. Command line parameters: wdt=0 : disable watchdog (default) wdt=1 : enable watchdog wdt_period=N : N sets the value of the Watchdog Timer Period. The Watchdog Timer Period meaning is implementation specific. Check User Manual for the processor for more details. This patch is based off of work done by Takeharu Kato. Signed-off-by: Matt McClintock <msm@freescale.com> Signed-off-by: Kumar Gala <kumar.gala@freescale.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--Documentation/watchdog/watchdog-api.txt20
-rw-r--r--arch/ppc/kernel/head_44x.S4
-rw-r--r--arch/ppc/kernel/head_4xx.S4
-rw-r--r--arch/ppc/kernel/head_fsl_booke.S5
-rw-r--r--arch/ppc/kernel/setup.c24
-rw-r--r--arch/ppc/kernel/traps.c19
-rw-r--r--arch/ppc/syslib/ppc4xx_setup.c25
-rw-r--r--drivers/char/watchdog/Kconfig4
-rw-r--r--drivers/char/watchdog/Makefile1
-rw-r--r--drivers/char/watchdog/booke_wdt.c191
10 files changed, 270 insertions, 27 deletions
diff --git a/Documentation/watchdog/watchdog-api.txt b/Documentation/watchdog/watchdog-api.txt
index 28388aa700c6..c5beb548cfc4 100644
--- a/Documentation/watchdog/watchdog-api.txt
+++ b/Documentation/watchdog/watchdog-api.txt
@@ -228,6 +228,26 @@ advantechwdt.c -- Advantech Single Board Computer
228 The GETSTATUS call returns if the device is open or not. 228 The GETSTATUS call returns if the device is open or not.
229 [FIXME -- silliness again?] 229 [FIXME -- silliness again?]
230 230
231booke_wdt.c -- PowerPC BookE Watchdog Timer
232
233 Timeout default varies according to frequency, supports
234 SETTIMEOUT
235
236 Watchdog can not be turned off, CONFIG_WATCHDOG_NOWAYOUT
237 does not make sense
238
239 GETSUPPORT returns the watchdog_info struct, and
240 GETSTATUS returns the supported options. GETBOOTSTATUS
241 returns a 1 if the last reset was caused by the
242 watchdog and a 0 otherwise. This watchdog can not be
243 disabled once it has been started. The wdt_period kernel
244 parameter selects which bit of the time base changing
245 from 0->1 will trigger the watchdog exception. Changing
246 the timeout from the ioctl calls will change the
247 wdt_period as defined above. Finally if you would like to
248 replace the default Watchdog Handler you can implement the
249 WatchdogHandler() function in your own code.
250
231eurotechwdt.c -- Eurotech CPU-1220/1410 251eurotechwdt.c -- Eurotech CPU-1220/1410
232 252
233 The timeout can be set using the SETTIMEOUT ioctl and defaults 253 The timeout can be set using the SETTIMEOUT ioctl and defaults
diff --git a/arch/ppc/kernel/head_44x.S b/arch/ppc/kernel/head_44x.S
index 69ff3a9961e8..9e68e32edb60 100644
--- a/arch/ppc/kernel/head_44x.S
+++ b/arch/ppc/kernel/head_44x.S
@@ -462,7 +462,11 @@ interrupt_base:
462 462
463 /* Watchdog Timer Interrupt */ 463 /* Watchdog Timer Interrupt */
464 /* TODO: Add watchdog support */ 464 /* TODO: Add watchdog support */
465#ifdef CONFIG_BOOKE_WDT
466 CRITICAL_EXCEPTION(0x1020, WatchdogTimer, WatchdogException)
467#else
465 CRITICAL_EXCEPTION(0x1020, WatchdogTimer, UnknownException) 468 CRITICAL_EXCEPTION(0x1020, WatchdogTimer, UnknownException)
469#endif
466 470
467 /* Data TLB Error Interrupt */ 471 /* Data TLB Error Interrupt */
468 START_EXCEPTION(DataTLBError) 472 START_EXCEPTION(DataTLBError)
diff --git a/arch/ppc/kernel/head_4xx.S b/arch/ppc/kernel/head_4xx.S
index 23fb51819ba5..0a5e723d3be6 100644
--- a/arch/ppc/kernel/head_4xx.S
+++ b/arch/ppc/kernel/head_4xx.S
@@ -448,7 +448,9 @@ label:
448 448
449/* 0x1020 - Watchdog Timer (WDT) Exception 449/* 0x1020 - Watchdog Timer (WDT) Exception
450*/ 450*/
451 451#ifdef CONFIG_BOOKE_WDT
452 CRITICAL_EXCEPTION(0x1020, WDTException, WatchdogException)
453#else
452 CRITICAL_EXCEPTION(0x1020, WDTException, UnknownException) 454 CRITICAL_EXCEPTION(0x1020, WDTException, UnknownException)
453#endif 455#endif
454 456
diff --git a/arch/ppc/kernel/head_fsl_booke.S b/arch/ppc/kernel/head_fsl_booke.S
index eb804b7a3cb2..4028f4c7d978 100644
--- a/arch/ppc/kernel/head_fsl_booke.S
+++ b/arch/ppc/kernel/head_fsl_booke.S
@@ -564,8 +564,11 @@ interrupt_base:
564 EXCEPTION(0x3100, FixedIntervalTimer, UnknownException, EXC_XFER_EE) 564 EXCEPTION(0x3100, FixedIntervalTimer, UnknownException, EXC_XFER_EE)
565 565
566 /* Watchdog Timer Interrupt */ 566 /* Watchdog Timer Interrupt */
567 /* TODO: Add watchdog support */ 567#ifdef CONFIG_BOOKE_WDT
568 CRITICAL_EXCEPTION(0x3200, WatchdogTimer, WatchdogException)
569#else
568 CRITICAL_EXCEPTION(0x3200, WatchdogTimer, UnknownException) 570 CRITICAL_EXCEPTION(0x3200, WatchdogTimer, UnknownException)
571#endif
569 572
570 /* Data TLB Error Interrupt */ 573 /* Data TLB Error Interrupt */
571 START_EXCEPTION(DataTLBError) 574 START_EXCEPTION(DataTLBError)
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index 929e5d1cc7fe..cf74a744e375 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -615,6 +615,30 @@ machine_init(unsigned long r3, unsigned long r4, unsigned long r5,
615 if (ppc_md.progress) 615 if (ppc_md.progress)
616 ppc_md.progress("id mach(): done", 0x200); 616 ppc_md.progress("id mach(): done", 0x200);
617} 617}
618#ifdef CONFIG_BOOKE_WDT
619/* Checks wdt=x and wdt_period=xx command-line option */
620int __init early_parse_wdt(char *p)
621{
622 extern u32 wdt_enable;
623
624 if (p && strncmp(p, "0", 1) != 0)
625 wdt_enable = 1;
626
627 return 0;
628}
629early_param("wdt", early_parse_wdt);
630
631int __init early_parse_wdt_period (char *p)
632{
633 extern u32 wdt_period;
634
635 if (p)
636 wdt_period = simple_strtoul(p, NULL, 0);
637
638 return 0;
639}
640early_param("wdt_period", early_parse_wdt_period);
641#endif /* CONFIG_BOOKE_WDT */
618 642
619/* Checks "l2cr=xxxx" command-line option */ 643/* Checks "l2cr=xxxx" command-line option */
620int __init ppc_setup_l2cr(char *str) 644int __init ppc_setup_l2cr(char *str)
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index 9e6ae5696650..d87423d1003a 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -904,6 +904,25 @@ void SPEFloatingPointException(struct pt_regs *regs)
904} 904}
905#endif 905#endif
906 906
907#ifdef CONFIG_BOOKE_WDT
908/*
909 * Default handler for a Watchdog exception,
910 * spins until a reboot occurs
911 */
912void __attribute__ ((weak)) WatchdogHandler(struct pt_regs *regs)
913{
914 /* Generic WatchdogHandler, implement your own */
915 mtspr(SPRN_TCR, mfspr(SPRN_TCR)&(~TCR_WIE));
916 return;
917}
918
919void WatchdogException(struct pt_regs *regs)
920{
921 printk (KERN_EMERG "PowerPC Book-E Watchdog Exception\n");
922 WatchdogHandler(regs);
923}
924#endif
925
907void __init trap_init(void) 926void __init trap_init(void)
908{ 927{
909} 928}
diff --git a/arch/ppc/syslib/ppc4xx_setup.c b/arch/ppc/syslib/ppc4xx_setup.c
index 795b966e696a..b843c4fef25e 100644
--- a/arch/ppc/syslib/ppc4xx_setup.c
+++ b/arch/ppc/syslib/ppc4xx_setup.c
@@ -48,10 +48,6 @@
48extern void abort(void); 48extern void abort(void);
49extern void ppc4xx_find_bridges(void); 49extern void ppc4xx_find_bridges(void);
50 50
51extern void ppc4xx_wdt_heartbeat(void);
52extern int wdt_enable;
53extern unsigned long wdt_period;
54
55/* Global Variables */ 51/* Global Variables */
56bd_t __res; 52bd_t __res;
57 53
@@ -257,22 +253,6 @@ ppc4xx_init(unsigned long r3, unsigned long r4, unsigned long r5,
257 *(char *) (r7 + KERNELBASE) = 0; 253 *(char *) (r7 + KERNELBASE) = 0;
258 strcpy(cmd_line, (char *) (r6 + KERNELBASE)); 254 strcpy(cmd_line, (char *) (r6 + KERNELBASE));
259 } 255 }
260#if defined(CONFIG_PPC405_WDT)
261/* Look for wdt= option on command line */
262 if (strstr(cmd_line, "wdt=")) {
263 int valid_wdt = 0;
264 char *p, *q;
265 for (q = cmd_line; (p = strstr(q, "wdt=")) != 0;) {
266 q = p + 4;
267 if (p > cmd_line && p[-1] != ' ')
268 continue;
269 wdt_period = simple_strtoul(q, &q, 0);
270 valid_wdt = 1;
271 ++q;
272 }
273 wdt_enable = valid_wdt;
274 }
275#endif
276 256
277 /* Initialize machine-dependent vectors */ 257 /* Initialize machine-dependent vectors */
278 258
@@ -287,11 +267,6 @@ ppc4xx_init(unsigned long r3, unsigned long r4, unsigned long r5,
287 267
288 ppc_md.calibrate_decr = ppc4xx_calibrate_decr; 268 ppc_md.calibrate_decr = ppc4xx_calibrate_decr;
289 269
290#ifdef CONFIG_PPC405_WDT
291 ppc_md.heartbeat = ppc4xx_wdt_heartbeat;
292#endif
293 ppc_md.heartbeat_count = 0;
294
295 ppc_md.find_end_of_memory = ppc4xx_find_end_of_memory; 270 ppc_md.find_end_of_memory = ppc4xx_find_end_of_memory;
296 ppc_md.setup_io_mappings = ppc4xx_map_io; 271 ppc_md.setup_io_mappings = ppc4xx_map_io;
297 272
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
index b53e2e2b5aee..95335b443a8f 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -346,6 +346,10 @@ config 8xx_WDT
346 tristate "MPC8xx Watchdog Timer" 346 tristate "MPC8xx Watchdog Timer"
347 depends on WATCHDOG && 8xx 347 depends on WATCHDOG && 8xx
348 348
349config BOOKE_WDT
350 tristate "PowerPC Book-E Watchdog Timer"
351 depends on WATCHDOG && (BOOKE || 4xx)
352
349# MIPS Architecture 353# MIPS Architecture
350 354
351config INDYDOG 355config INDYDOG
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile
index c1838834ea7f..b16dfea28134 100644
--- a/drivers/char/watchdog/Makefile
+++ b/drivers/char/watchdog/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
34obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o 34obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
35obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o 35obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
36obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o 36obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o
37obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o
37 38
38# Only one watchdog can succeed. We probe the hardware watchdog 39# Only one watchdog can succeed. We probe the hardware watchdog
39# drivers first, then the softdog driver. This means if your hardware 40# drivers first, then the softdog driver. This means if your hardware
diff --git a/drivers/char/watchdog/booke_wdt.c b/drivers/char/watchdog/booke_wdt.c
new file mode 100644
index 000000000000..7281f394f682
--- /dev/null
+++ b/drivers/char/watchdog/booke_wdt.c
@@ -0,0 +1,191 @@
1/*
2 * drivers/char/watchdog/booke_wdt.c
3 *
4 * Watchdog timer for PowerPC Book-E systems
5 *
6 * Author: Matthew McClintock
7 * Maintainer: Kumar Gala <kumar.gala@freescale.com>
8 *
9 * Copyright 2005 Freescale Semiconductor Inc.
10 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
15 */
16
17#include <linux/config.h>
18#include <linux/module.h>
19#include <linux/fs.h>
20#include <linux/miscdevice.h>
21#include <linux/notifier.h>
22#include <linux/watchdog.h>
23
24#include <asm/reg_booke.h>
25#include <asm/uaccess.h>
26
27/* If the kernel parameter wdt_enable=1, the watchdog will be enabled at boot.
28 * Also, the wdt_period sets the watchdog timer period timeout.
29 * For E500 cpus the wdt_period sets which bit changing from 0->1 will
30 * trigger a watchog timeout. This watchdog timeout will occur 3 times, the
31 * first time nothing will happen, the second time a watchdog exception will
32 * occur, and the final time the board will reset.
33 */
34
35#ifdef CONFIG_FSL_BOOKE
36#define WDT_PERIOD_DEFAULT 63 /* Ex. wdt_period=28 bus=333Mhz , reset=~40sec */
37#else
38#define WDT_PERIOD_DEFAULT 4 /* Refer to the PPC40x and PPC4xx manuals */
39#endif /* for timing information */
40
41u32 wdt_enable = 0;
42u32 wdt_period = WDT_PERIOD_DEFAULT;
43
44#ifdef CONFIG_FSL_BOOKE
45#define WDTP(x) ((((63-x)&0x3)<<30)|(((63-x)&0x3c)<<15))
46#else
47#define WDTP(x) (TCR_WP(x))
48#endif
49
50/*
51 * booke_wdt_enable:
52 */
53static __inline__ void booke_wdt_enable(void)
54{
55 u32 val;
56
57 val = mfspr(SPRN_TCR);
58 val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(wdt_period));
59
60 mtspr(SPRN_TCR, val);
61}
62
63/*
64 * booke_wdt_ping:
65 */
66static __inline__ void booke_wdt_ping(void)
67{
68 mtspr(SPRN_TSR, TSR_ENW|TSR_WIS);
69}
70
71/*
72 * booke_wdt_write:
73 */
74static ssize_t booke_wdt_write (struct file *file, const char *buf,
75 size_t count, loff_t *ppos)
76{
77 booke_wdt_ping();
78 return count;
79}
80
81static struct watchdog_info ident = {
82 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
83 .firmware_version = 0,
84 .identity = "PowerPC Book-E Watchdog",
85};
86
87/*
88 * booke_wdt_ioctl:
89 */
90static int booke_wdt_ioctl (struct inode *inode, struct file *file,
91 unsigned int cmd, unsigned long arg)
92{
93 u32 tmp = 0;
94
95 switch (cmd) {
96 case WDIOC_GETSUPPORT:
97 if (copy_to_user ((struct watchdog_info *) arg, &ident,
98 sizeof(struct watchdog_info)))
99 return -EFAULT;
100 case WDIOC_GETSTATUS:
101 return put_user(ident.options, (u32 *) arg);
102 case WDIOC_GETBOOTSTATUS:
103 /* XXX: something is clearing TSR */
104 tmp = mfspr(SPRN_TSR) & TSR_WRS(3);
105 /* returns 1 if last reset was caused by the WDT */
106 return (tmp ? 1 : 0);
107 case WDIOC_KEEPALIVE:
108 booke_wdt_ping();
109 return 0;
110 case WDIOC_SETTIMEOUT:
111 if (get_user(wdt_period, (u32 *) arg))
112 return -EFAULT;
113 mtspr(SPRN_TCR, (mfspr(SPRN_TCR)&~WDTP(0))|WDTP(wdt_period));
114 return 0;
115 case WDIOC_GETTIMEOUT:
116 return put_user(wdt_period, (u32 *) arg);
117 case WDIOC_SETOPTIONS:
118 if (get_user(tmp, (u32 *) arg))
119 return -EINVAL;
120 if (tmp == WDIOS_ENABLECARD) {
121 booke_wdt_ping();
122 break;
123 } else
124 return -EINVAL;
125 return 0;
126 default:
127 return -ENOIOCTLCMD;
128 }
129
130 return 0;
131}
132/*
133 * booke_wdt_open:
134 */
135static int booke_wdt_open (struct inode *inode, struct file *file)
136{
137 if (wdt_enable == 0) {
138 wdt_enable = 1;
139 booke_wdt_enable();
140 printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n",
141 wdt_period);
142 }
143
144 return 0;
145}
146
147static struct file_operations booke_wdt_fops = {
148 .owner = THIS_MODULE,
149 .llseek = no_llseek,
150 .write = booke_wdt_write,
151 .ioctl = booke_wdt_ioctl,
152 .open = booke_wdt_open,
153};
154
155static struct miscdevice booke_wdt_miscdev = {
156 .minor = WATCHDOG_MINOR,
157 .name = "watchdog",
158 .fops = &booke_wdt_fops,
159};
160
161static void __exit booke_wdt_exit(void)
162{
163 misc_deregister(&booke_wdt_miscdev);
164}
165
166/*
167 * booke_wdt_init:
168 */
169static int __init booke_wdt_init(void)
170{
171 int ret = 0;
172
173 printk (KERN_INFO "PowerPC Book-E Watchdog Timer Loaded\n");
174 ident.firmware_version = cpu_specs[0].pvr_value;
175
176 ret = misc_register(&booke_wdt_miscdev);
177 if (ret) {
178 printk (KERN_CRIT "Cannot register miscdev on minor=%d (err=%d)\n",
179 WATCHDOG_MINOR, ret);
180 return ret;
181 }
182
183 if (wdt_enable == 1) {
184 printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n",
185 wdt_period);
186 booke_wdt_enable();
187 }
188
189 return ret;
190}
191device_initcall(booke_wdt_init);