blob: c800cce73c1e7b5cec6b5eac97ba990c825092c0 [file] [log] [blame]
Kumar Galaa2f40cc2005-09-03 15:55:33 -07001/*
2 * drivers/char/watchdog/booke_wdt.c
3 *
4 * Watchdog timer for PowerPC Book-E systems
5 *
6 * Author: Matthew McClintock
Kumar Gala4c8d3d92005-11-13 16:06:30 -08007 * Maintainer: Kumar Gala <galak@kernel.crashing.org>
Kumar Galaa2f40cc2005-09-03 15:55:33 -07008 *
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>
Kumar Gala39cdc4b2005-09-03 15:55:39 -070026#include <asm/system.h>
Kumar Galaa2f40cc2005-09-03 15:55:33 -070027
28/* If the kernel parameter wdt_enable=1, the watchdog will be enabled at boot.
29 * Also, the wdt_period sets the watchdog timer period timeout.
30 * For E500 cpus the wdt_period sets which bit changing from 0->1 will
31 * trigger a watchog timeout. This watchdog timeout will occur 3 times, the
32 * first time nothing will happen, the second time a watchdog exception will
33 * occur, and the final time the board will reset.
34 */
35
36#ifdef CONFIG_FSL_BOOKE
37#define WDT_PERIOD_DEFAULT 63 /* Ex. wdt_period=28 bus=333Mhz , reset=~40sec */
38#else
39#define WDT_PERIOD_DEFAULT 4 /* Refer to the PPC40x and PPC4xx manuals */
40#endif /* for timing information */
41
Kumar Gala39cdc4b2005-09-03 15:55:39 -070042u32 booke_wdt_enabled = 0;
43u32 booke_wdt_period = WDT_PERIOD_DEFAULT;
Kumar Galaa2f40cc2005-09-03 15:55:33 -070044
45#ifdef CONFIG_FSL_BOOKE
46#define WDTP(x) ((((63-x)&0x3)<<30)|(((63-x)&0x3c)<<15))
47#else
48#define WDTP(x) (TCR_WP(x))
49#endif
50
51/*
52 * booke_wdt_enable:
53 */
54static __inline__ void booke_wdt_enable(void)
55{
56 u32 val;
57
58 val = mfspr(SPRN_TCR);
Kumar Gala39cdc4b2005-09-03 15:55:39 -070059 val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(booke_wdt_period));
Kumar Galaa2f40cc2005-09-03 15:55:33 -070060
61 mtspr(SPRN_TCR, val);
62}
63
64/*
65 * booke_wdt_ping:
66 */
67static __inline__ void booke_wdt_ping(void)
68{
69 mtspr(SPRN_TSR, TSR_ENW|TSR_WIS);
70}
71
72/*
73 * booke_wdt_write:
74 */
Al Viro538bacf2005-12-15 09:18:20 +000075static ssize_t booke_wdt_write (struct file *file, const char __user *buf,
Kumar Galaa2f40cc2005-09-03 15:55:33 -070076 size_t count, loff_t *ppos)
77{
78 booke_wdt_ping();
79 return count;
80}
81
82static struct watchdog_info ident = {
83 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
84 .firmware_version = 0,
85 .identity = "PowerPC Book-E Watchdog",
86};
87
88/*
89 * booke_wdt_ioctl:
90 */
91static int booke_wdt_ioctl (struct inode *inode, struct file *file,
92 unsigned int cmd, unsigned long arg)
93{
94 u32 tmp = 0;
Al Viro538bacf2005-12-15 09:18:20 +000095 u32 __user *p = (u32 __user *)arg;
Kumar Galaa2f40cc2005-09-03 15:55:33 -070096
97 switch (cmd) {
98 case WDIOC_GETSUPPORT:
Al Viro538bacf2005-12-15 09:18:20 +000099 if (copy_to_user ((struct watchdog_info __user *) arg, &ident,
Kumar Galaa2f40cc2005-09-03 15:55:33 -0700100 sizeof(struct watchdog_info)))
101 return -EFAULT;
102 case WDIOC_GETSTATUS:
Al Viro538bacf2005-12-15 09:18:20 +0000103 return put_user(ident.options, p);
Kumar Galaa2f40cc2005-09-03 15:55:33 -0700104 case WDIOC_GETBOOTSTATUS:
105 /* XXX: something is clearing TSR */
106 tmp = mfspr(SPRN_TSR) & TSR_WRS(3);
107 /* returns 1 if last reset was caused by the WDT */
108 return (tmp ? 1 : 0);
109 case WDIOC_KEEPALIVE:
110 booke_wdt_ping();
111 return 0;
112 case WDIOC_SETTIMEOUT:
Al Viro538bacf2005-12-15 09:18:20 +0000113 if (get_user(booke_wdt_period, p))
Kumar Galaa2f40cc2005-09-03 15:55:33 -0700114 return -EFAULT;
Kumar Gala39cdc4b2005-09-03 15:55:39 -0700115 mtspr(SPRN_TCR, (mfspr(SPRN_TCR)&~WDTP(0))|WDTP(booke_wdt_period));
Kumar Galaa2f40cc2005-09-03 15:55:33 -0700116 return 0;
117 case WDIOC_GETTIMEOUT:
Al Viro538bacf2005-12-15 09:18:20 +0000118 return put_user(booke_wdt_period, p);
Kumar Galaa2f40cc2005-09-03 15:55:33 -0700119 case WDIOC_SETOPTIONS:
Al Viro538bacf2005-12-15 09:18:20 +0000120 if (get_user(tmp, p))
Kumar Galaa2f40cc2005-09-03 15:55:33 -0700121 return -EINVAL;
122 if (tmp == WDIOS_ENABLECARD) {
123 booke_wdt_ping();
124 break;
125 } else
126 return -EINVAL;
127 return 0;
128 default:
129 return -ENOIOCTLCMD;
130 }
131
132 return 0;
133}
134/*
135 * booke_wdt_open:
136 */
137static int booke_wdt_open (struct inode *inode, struct file *file)
138{
Kumar Gala39cdc4b2005-09-03 15:55:39 -0700139 if (booke_wdt_enabled == 0) {
140 booke_wdt_enabled = 1;
Kumar Galaa2f40cc2005-09-03 15:55:33 -0700141 booke_wdt_enable();
142 printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n",
Kumar Gala39cdc4b2005-09-03 15:55:39 -0700143 booke_wdt_period);
Kumar Galaa2f40cc2005-09-03 15:55:33 -0700144 }
145
146 return 0;
147}
148
149static struct file_operations booke_wdt_fops = {
150 .owner = THIS_MODULE,
151 .llseek = no_llseek,
152 .write = booke_wdt_write,
153 .ioctl = booke_wdt_ioctl,
154 .open = booke_wdt_open,
155};
156
157static struct miscdevice booke_wdt_miscdev = {
158 .minor = WATCHDOG_MINOR,
159 .name = "watchdog",
160 .fops = &booke_wdt_fops,
161};
162
163static void __exit booke_wdt_exit(void)
164{
165 misc_deregister(&booke_wdt_miscdev);
166}
167
168/*
169 * booke_wdt_init:
170 */
171static int __init booke_wdt_init(void)
172{
173 int ret = 0;
174
175 printk (KERN_INFO "PowerPC Book-E Watchdog Timer Loaded\n");
176 ident.firmware_version = cpu_specs[0].pvr_value;
177
178 ret = misc_register(&booke_wdt_miscdev);
179 if (ret) {
180 printk (KERN_CRIT "Cannot register miscdev on minor=%d (err=%d)\n",
181 WATCHDOG_MINOR, ret);
182 return ret;
183 }
184
Kumar Gala39cdc4b2005-09-03 15:55:39 -0700185 if (booke_wdt_enabled == 1) {
Kumar Galaa2f40cc2005-09-03 15:55:33 -0700186 printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n",
Kumar Gala39cdc4b2005-09-03 15:55:39 -0700187 booke_wdt_period);
Kumar Galaa2f40cc2005-09-03 15:55:33 -0700188 booke_wdt_enable();
189 }
190
191 return ret;
192}
193device_initcall(booke_wdt_init);