Blame view

drivers/watchdog/mpc8xxx_wdt.c 6.86 KB
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
1
  /*
0d7b10140   Anton Vorontsov   [WATCHDOG] mpc8xx...
2
   * mpc8xxx_wdt.c - MPC8xx/MPC83xx/MPC86xx watchdog userspace interface
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
3
4
   *
   * Authors: Dave Updegraff <dave@cray.org>
5f3b27569   Wim Van Sebroeck   watchdog: cleanup...
5
6
7
   *	    Kumar Gala <galak@kernel.crashing.org>
   *		Attribution: from 83xx_wst: Florian Schirmer <jolt@tuxbox.org>
   *				..and from sc520_wdt
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
8
9
   * Copyright (c) 2008  MontaVista Software, Inc.
   *                     Anton Vorontsov <avorontsov@ru.mvista.com>
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
10
11
12
13
14
15
16
17
18
   *
   * Note: it appears that you can only actually ENABLE or DISABLE the thing
   * once after POR. Once enabled, you cannot disable, and vice versa.
   *
   * This program is free software; you can redistribute  it and/or modify it
   * under  the terms of  the GNU General  Public License as published by the
   * Free Software Foundation;  either version 2 of the  License, or (at your
   * option) any later version.
   */
27c766aaa   Joe Perches   watchdog: Use pr_...
19
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
20
21
22
  #include <linux/fs.h>
  #include <linux/init.h>
  #include <linux/kernel.h>
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
23
  #include <linux/timer.h>
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
24
  #include <linux/miscdevice.h>
5af507300   Rob Herring   drivers: clean-up...
25
  #include <linux/of_address.h>
ef8ab12ec   Anton Vorontsov   [WATCHDOG] mpc83x...
26
  #include <linux/of_platform.h>
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
27
28
  #include <linux/module.h>
  #include <linux/watchdog.h>
f26ef3dc6   Alan Cox   [WATCHDOG 26/57] ...
29
30
  #include <linux/io.h>
  #include <linux/uaccess.h>
ef8ab12ec   Anton Vorontsov   [WATCHDOG] mpc83x...
31
  #include <sysdev/fsl_soc.h>
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
32

59ca1b0d1   Anton Vorontsov   [WATCHDOG] mpc8xx...
33
  struct mpc8xxx_wdt {
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
34
35
36
37
38
39
40
41
42
43
44
  	__be32 res0;
  	__be32 swcrr; /* System watchdog control register */
  #define SWCRR_SWTC 0xFFFF0000 /* Software Watchdog Time Count. */
  #define SWCRR_SWEN 0x00000004 /* Watchdog Enable bit. */
  #define SWCRR_SWRI 0x00000002 /* Software Watchdog Reset/Interrupt Select bit.*/
  #define SWCRR_SWPR 0x00000001 /* Software Watchdog Counter Prescale bit. */
  	__be32 swcnr; /* System watchdog count register */
  	u8 res1[2];
  	__be16 swsrr; /* System watchdog service register */
  	u8 res2[0xF0];
  };
59ca1b0d1   Anton Vorontsov   [WATCHDOG] mpc8xx...
45
  struct mpc8xxx_wdt_type {
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
46
47
48
  	int prescaler;
  	bool hw_enabled;
  };
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
49
50
51
52
53
54
  struct mpc8xxx_wdt_ddata {
  	struct mpc8xxx_wdt __iomem *base;
  	struct watchdog_device wdd;
  	struct timer_list timer;
  	spinlock_t lock;
  };
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
55
56
57
  
  static u16 timeout = 0xffff;
  module_param(timeout, ushort, 0);
f26ef3dc6   Alan Cox   [WATCHDOG 26/57] ...
58
  MODULE_PARM_DESC(timeout,
76550d329   Randy Dunlap   watchdog: fix sev...
59
  	"Watchdog timeout in ticks. (0<timeout<65536, default=65535)");
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
60

90ab5ee94   Rusty Russell   module_param: mak...
61
  static bool reset = 1;
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
62
  module_param(reset, bool, 0);
f26ef3dc6   Alan Cox   [WATCHDOG 26/57] ...
63
64
  MODULE_PARM_DESC(reset,
  	"Watchdog Interrupt/Reset Mode. 0 = interrupt, 1 = reset");
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
65

86a1e1896   Wim Van Sebroeck   watchdog: nowayou...
66
67
  static bool nowayout = WATCHDOG_NOWAYOUT;
  module_param(nowayout, bool, 0);
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
68
69
  MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
  		 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
70
  static void mpc8xxx_wdt_keepalive(struct mpc8xxx_wdt_ddata *ddata)
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
71
72
  {
  	/* Ping the WDT */
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
73
74
75
76
  	spin_lock(&ddata->lock);
  	out_be16(&ddata->base->swsrr, 0x556c);
  	out_be16(&ddata->base->swsrr, 0xaa39);
  	spin_unlock(&ddata->lock);
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
77
  }
59ca1b0d1   Anton Vorontsov   [WATCHDOG] mpc8xx...
78
  static void mpc8xxx_wdt_timer_ping(unsigned long arg)
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
79
  {
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
80
  	struct mpc8xxx_wdt_ddata *ddata = (void *)arg;
d5cfaf0a8   Christophe Leroy   watchdog: mpc8xxx...
81

7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
82
  	mpc8xxx_wdt_keepalive(ddata);
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
83
  	/* We're pinging it twice faster than needed, just to be sure. */
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
84
  	mod_timer(&ddata->timer, jiffies + HZ * ddata->wdd.timeout / 2);
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
85
  }
d5cfaf0a8   Christophe Leroy   watchdog: mpc8xxx...
86
  static int mpc8xxx_wdt_start(struct watchdog_device *w)
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
87
  {
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
88
89
  	struct mpc8xxx_wdt_ddata *ddata =
  		container_of(w, struct mpc8xxx_wdt_ddata, wdd);
a57e06f7c   Uwe Kleine-König   watchdog: mpc8xxx...
90
  	u32 tmp = SWCRR_SWEN | SWCRR_SWPR;
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
91
92
  
  	/* Good, fire up the show */
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
93
94
95
96
  	if (reset)
  		tmp |= SWCRR_SWRI;
  
  	tmp |= timeout << 16;
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
97
  	out_be32(&ddata->base->swcrr, tmp);
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
98

7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
99
  	del_timer_sync(&ddata->timer);
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
100

d5cfaf0a8   Christophe Leroy   watchdog: mpc8xxx...
101
  	return 0;
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
102
  }
d5cfaf0a8   Christophe Leroy   watchdog: mpc8xxx...
103
  static int mpc8xxx_wdt_ping(struct watchdog_device *w)
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
104
  {
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
105
106
107
108
  	struct mpc8xxx_wdt_ddata *ddata =
  		container_of(w, struct mpc8xxx_wdt_ddata, wdd);
  
  	mpc8xxx_wdt_keepalive(ddata);
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
109
110
  	return 0;
  }
d5cfaf0a8   Christophe Leroy   watchdog: mpc8xxx...
111
  static int mpc8xxx_wdt_stop(struct watchdog_device *w)
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
112
  {
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
113
114
115
116
  	struct mpc8xxx_wdt_ddata *ddata =
  		container_of(w, struct mpc8xxx_wdt_ddata, wdd);
  
  	mod_timer(&ddata->timer, jiffies);
d5cfaf0a8   Christophe Leroy   watchdog: mpc8xxx...
117
  	return 0;
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
118
  }
d5cfaf0a8   Christophe Leroy   watchdog: mpc8xxx...
119
120
121
122
  static struct watchdog_info mpc8xxx_wdt_info = {
  	.options = WDIOF_KEEPALIVEPING,
  	.firmware_version = 1,
  	.identity = "MPC8xxx",
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
123
  };
d5cfaf0a8   Christophe Leroy   watchdog: mpc8xxx...
124
125
126
127
128
129
  static struct watchdog_ops mpc8xxx_wdt_ops = {
  	.owner = THIS_MODULE,
  	.start = mpc8xxx_wdt_start,
  	.ping = mpc8xxx_wdt_ping,
  	.stop = mpc8xxx_wdt_stop,
  };
2d991a164   Bill Pemberton   watchdog: remove ...
130
  static int mpc8xxx_wdt_probe(struct platform_device *ofdev)
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
131
  {
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
132
  	int ret;
de5f71222   Uwe Kleine-König   watchdog: mpc8xxx...
133
  	struct resource *res;
639397e48   Arnd Bergmann   watchdog/mpc8xxx:...
134
  	const struct mpc8xxx_wdt_type *wdt_type;
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
135
  	struct mpc8xxx_wdt_ddata *ddata;
ef8ab12ec   Anton Vorontsov   [WATCHDOG] mpc83x...
136
  	u32 freq = fsl_get_sys_freq();
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
137
  	bool enabled;
d5cfaf0a8   Christophe Leroy   watchdog: mpc8xxx...
138
  	unsigned int timeout_sec;
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
139

f0ded83b9   Uwe Kleine-König   watchdog: mpc8xxx...
140
141
  	wdt_type = of_device_get_match_data(&ofdev->dev);
  	if (!wdt_type)
1c48a5c93   Grant Likely   dt: Eliminate of_...
142
  		return -EINVAL;
1c48a5c93   Grant Likely   dt: Eliminate of_...
143

ef8ab12ec   Anton Vorontsov   [WATCHDOG] mpc83x...
144
145
  	if (!freq || freq == -1)
  		return -EINVAL;
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
146

7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
147
148
149
  	ddata = devm_kzalloc(&ofdev->dev, sizeof(*ddata), GFP_KERNEL);
  	if (!ddata)
  		return -ENOMEM;
de5f71222   Uwe Kleine-König   watchdog: mpc8xxx...
150
  	res = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
151
152
153
  	ddata->base = devm_ioremap_resource(&ofdev->dev, res);
  	if (IS_ERR(ddata->base))
  		return PTR_ERR(ddata->base);
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
154

7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
155
  	enabled = in_be32(&ddata->base->swcrr) & SWCRR_SWEN;
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
156
  	if (!enabled && wdt_type->hw_enabled) {
27c766aaa   Joe Perches   watchdog: Use pr_...
157
158
  		pr_info("could not be enabled in software
  ");
72cd501e6   Uwe Kleine-König   watchdog: mpc8xxx...
159
  		return -ENODEV;
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
160
  	}
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
161
162
163
164
165
166
  	spin_lock_init(&ddata->lock);
  	setup_timer(&ddata->timer, mpc8xxx_wdt_timer_ping,
  		    (unsigned long)ddata);
  
  	ddata->wdd.info = &mpc8xxx_wdt_info,
  	ddata->wdd.ops = &mpc8xxx_wdt_ops,
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
167
  	/* Calculate the timeout in seconds */
a57e06f7c   Uwe Kleine-König   watchdog: mpc8xxx...
168
  	timeout_sec = (timeout * wdt_type->prescaler) / freq;
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
169

7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
170
  	ddata->wdd.timeout = timeout_sec;
50ffb53ef   Uwe Kleine-König   watchdog: mpc8xxx...
171

7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
172
  	watchdog_set_nowayout(&ddata->wdd, nowayout);
50ffb53ef   Uwe Kleine-König   watchdog: mpc8xxx...
173

7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
174
  	ret = watchdog_register_device(&ddata->wdd);
50ffb53ef   Uwe Kleine-König   watchdog: mpc8xxx...
175
176
177
  	if (ret) {
  		pr_err("cannot register watchdog device (err=%d)
  ", ret);
de5f71222   Uwe Kleine-König   watchdog: mpc8xxx...
178
  		return ret;
50ffb53ef   Uwe Kleine-König   watchdog: mpc8xxx...
179
  	}
593fc178f   Anton Vorontsov   [WATCHDOG] mpc8xx...
180

27c766aaa   Joe Perches   watchdog: Use pr_...
181
182
183
  	pr_info("WDT driver for MPC8xxx initialized. mode:%s timeout=%d (%d seconds)
  ",
  		reset ? "reset" : "interrupt", timeout, timeout_sec);
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
184
185
186
  
  	/*
  	 * If the watchdog was previously enabled or we're running on
59ca1b0d1   Anton Vorontsov   [WATCHDOG] mpc8xx...
187
  	 * MPC8xxx, we should ping the wdt from the kernel until the
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
188
189
190
  	 * userspace handles it.
  	 */
  	if (enabled)
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
191
192
193
  		mod_timer(&ddata->timer, jiffies);
  
  	platform_set_drvdata(ofdev, ddata);
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
194
  	return 0;
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
195
  }
4b12b896c   Bill Pemberton   watchdog: remove ...
196
  static int mpc8xxx_wdt_remove(struct platform_device *ofdev)
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
197
  {
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
198
  	struct mpc8xxx_wdt_ddata *ddata = platform_get_drvdata(ofdev);
d5cfaf0a8   Christophe Leroy   watchdog: mpc8xxx...
199
200
201
  	pr_crit("Watchdog removed, expect the %s soon!
  ",
  		reset ? "reset" : "machine check exception");
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
202
203
  	del_timer_sync(&ddata->timer);
  	watchdog_unregister_device(&ddata->wdd);
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
204
205
206
  
  	return 0;
  }
59ca1b0d1   Anton Vorontsov   [WATCHDOG] mpc8xx...
207
  static const struct of_device_id mpc8xxx_wdt_match[] = {
ef8ab12ec   Anton Vorontsov   [WATCHDOG] mpc83x...
208
209
  	{
  		.compatible = "mpc83xx_wdt",
59ca1b0d1   Anton Vorontsov   [WATCHDOG] mpc8xx...
210
  		.data = &(struct mpc8xxx_wdt_type) {
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
211
212
213
214
215
  			.prescaler = 0x10000,
  		},
  	},
  	{
  		.compatible = "fsl,mpc8610-wdt",
59ca1b0d1   Anton Vorontsov   [WATCHDOG] mpc8xx...
216
  		.data = &(struct mpc8xxx_wdt_type) {
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
217
218
219
  			.prescaler = 0x10000,
  			.hw_enabled = true,
  		},
ef8ab12ec   Anton Vorontsov   [WATCHDOG] mpc83x...
220
  	},
0d7b10140   Anton Vorontsov   [WATCHDOG] mpc8xx...
221
222
223
224
  	{
  		.compatible = "fsl,mpc823-wdt",
  		.data = &(struct mpc8xxx_wdt_type) {
  			.prescaler = 0x800,
4af897fa9   Christophe Leroy   watchdog: mpc8xxx...
225
  			.hw_enabled = true,
0d7b10140   Anton Vorontsov   [WATCHDOG] mpc8xx...
226
227
  		},
  	},
ef8ab12ec   Anton Vorontsov   [WATCHDOG] mpc83x...
228
229
  	{},
  };
59ca1b0d1   Anton Vorontsov   [WATCHDOG] mpc8xx...
230
  MODULE_DEVICE_TABLE(of, mpc8xxx_wdt_match);
ef8ab12ec   Anton Vorontsov   [WATCHDOG] mpc83x...
231

1c48a5c93   Grant Likely   dt: Eliminate of_...
232
  static struct platform_driver mpc8xxx_wdt_driver = {
59ca1b0d1   Anton Vorontsov   [WATCHDOG] mpc8xx...
233
  	.probe		= mpc8xxx_wdt_probe,
82268714b   Bill Pemberton   watchdog: remove ...
234
  	.remove		= mpc8xxx_wdt_remove,
4018294b5   Grant Likely   of: Remove duplic...
235
236
  	.driver = {
  		.name = "mpc8xxx_wdt",
4018294b5   Grant Likely   of: Remove duplic...
237
  		.of_match_table = mpc8xxx_wdt_match,
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
238
239
  	},
  };
59ca1b0d1   Anton Vorontsov   [WATCHDOG] mpc8xx...
240
  static int __init mpc8xxx_wdt_init(void)
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
241
  {
1c48a5c93   Grant Likely   dt: Eliminate of_...
242
  	return platform_driver_register(&mpc8xxx_wdt_driver);
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
243
  }
0d7b10140   Anton Vorontsov   [WATCHDOG] mpc8xx...
244
  arch_initcall(mpc8xxx_wdt_init);
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
245

59ca1b0d1   Anton Vorontsov   [WATCHDOG] mpc8xx...
246
  static void __exit mpc8xxx_wdt_exit(void)
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
247
  {
1c48a5c93   Grant Likely   dt: Eliminate of_...
248
  	platform_driver_unregister(&mpc8xxx_wdt_driver);
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
249
  }
59ca1b0d1   Anton Vorontsov   [WATCHDOG] mpc8xx...
250
  module_exit(mpc8xxx_wdt_exit);
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
251
252
  
  MODULE_AUTHOR("Dave Updegraff, Kumar Gala");
0d7b10140   Anton Vorontsov   [WATCHDOG] mpc8xx...
253
254
  MODULE_DESCRIPTION("Driver for watchdog timer in MPC8xx/MPC83xx/MPC86xx "
  		   "uProcessors");
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
255
  MODULE_LICENSE("GPL");