Blame view

drivers/watchdog/mpc8xxx_wdt.c 6.82 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
2
  /*
0d7b10140   Anton Vorontsov   [WATCHDOG] mpc8xx...
3
   * mpc8xxx_wdt.c - MPC8xx/MPC83xx/MPC86xx watchdog userspace interface
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
4
5
   *
   * Authors: Dave Updegraff <dave@cray.org>
5f3b27569   Wim Van Sebroeck   watchdog: cleanup...
6
7
8
   *	    Kumar Gala <galak@kernel.crashing.org>
   *		Attribution: from 83xx_wst: Florian Schirmer <jolt@tuxbox.org>
   *				..and from sc520_wdt
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
9
10
   * Copyright (c) 2008  MontaVista Software, Inc.
   *                     Anton Vorontsov <avorontsov@ru.mvista.com>
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
11
12
13
   *
   * Note: it appears that you can only actually ENABLE or DISABLE the thing
   * once after POR. Once enabled, you cannot disable, and vice versa.
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
14
   */
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
15
16
17
  #include <linux/fs.h>
  #include <linux/init.h>
  #include <linux/kernel.h>
5af507300   Rob Herring   drivers: clean-up...
18
  #include <linux/of_address.h>
ef8ab12ec   Anton Vorontsov   [WATCHDOG] mpc83x...
19
  #include <linux/of_platform.h>
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
20
21
  #include <linux/module.h>
  #include <linux/watchdog.h>
f26ef3dc6   Alan Cox   [WATCHDOG 26/57] ...
22
23
  #include <linux/io.h>
  #include <linux/uaccess.h>
ef8ab12ec   Anton Vorontsov   [WATCHDOG] mpc83x...
24
  #include <sysdev/fsl_soc.h>
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
25

19ce9490a   Christophe Leroy   watchdog: mpc8xxx...
26
  #define WATCHDOG_TIMEOUT 10
59ca1b0d1   Anton Vorontsov   [WATCHDOG] mpc8xx...
27
  struct mpc8xxx_wdt {
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
28
29
30
  	__be32 res0;
  	__be32 swcrr; /* System watchdog control register */
  #define SWCRR_SWTC 0xFFFF0000 /* Software Watchdog Time Count. */
19ce9490a   Christophe Leroy   watchdog: mpc8xxx...
31
  #define SWCRR_SWF  0x00000008 /* Software Watchdog Freeze (mpc8xx). */
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
32
33
34
35
36
37
38
39
  #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...
40
  struct mpc8xxx_wdt_type {
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
41
42
  	int prescaler;
  	bool hw_enabled;
38e48b718   Christophe Leroy   watchdog: mpc8xxx...
43
  	u32 rsr_mask;
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
44
  };
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
45
46
47
  struct mpc8xxx_wdt_ddata {
  	struct mpc8xxx_wdt __iomem *base;
  	struct watchdog_device wdd;
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
48
  	spinlock_t lock;
19ce9490a   Christophe Leroy   watchdog: mpc8xxx...
49
  	u16 swtc;
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
50
  };
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
51

19ce9490a   Christophe Leroy   watchdog: mpc8xxx...
52
  static u16 timeout;
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
53
  module_param(timeout, ushort, 0);
f26ef3dc6   Alan Cox   [WATCHDOG 26/57] ...
54
  MODULE_PARM_DESC(timeout,
19ce9490a   Christophe Leroy   watchdog: mpc8xxx...
55
56
  	"Watchdog timeout in seconds. (1<timeout<65535, default="
  	__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
57

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

86a1e1896   Wim Van Sebroeck   watchdog: nowayou...
63
64
  static bool nowayout = WATCHDOG_NOWAYOUT;
  module_param(nowayout, bool, 0);
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
65
66
  MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
  		 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
67
  static void mpc8xxx_wdt_keepalive(struct mpc8xxx_wdt_ddata *ddata)
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
68
69
  {
  	/* Ping the WDT */
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
70
71
72
73
  	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: ...
74
  }
d5cfaf0a8   Christophe Leroy   watchdog: mpc8xxx...
75
  static int mpc8xxx_wdt_start(struct watchdog_device *w)
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
76
  {
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
77
78
  	struct mpc8xxx_wdt_ddata *ddata =
  		container_of(w, struct mpc8xxx_wdt_ddata, wdd);
19ce9490a   Christophe Leroy   watchdog: mpc8xxx...
79
  	u32 tmp = in_be32(&ddata->base->swcrr);
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
80
81
  
  	/* Good, fire up the show */
19ce9490a   Christophe Leroy   watchdog: mpc8xxx...
82
83
  	tmp &= ~(SWCRR_SWTC | SWCRR_SWF | SWCRR_SWEN | SWCRR_SWRI | SWCRR_SWPR);
  	tmp |= SWCRR_SWEN | SWCRR_SWPR | (ddata->swtc << 16);
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
84
85
  	if (reset)
  		tmp |= SWCRR_SWRI;
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
86
  	out_be32(&ddata->base->swcrr, tmp);
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
87

19ce9490a   Christophe Leroy   watchdog: mpc8xxx...
88
89
90
91
92
93
  	tmp = in_be32(&ddata->base->swcrr);
  	if (!(tmp & SWCRR_SWEN))
  		return -EOPNOTSUPP;
  
  	ddata->swtc = tmp >> 16;
  	set_bit(WDOG_HW_RUNNING, &ddata->wdd.status);
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
94

d5cfaf0a8   Christophe Leroy   watchdog: mpc8xxx...
95
  	return 0;
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
96
  }
d5cfaf0a8   Christophe Leroy   watchdog: mpc8xxx...
97
  static int mpc8xxx_wdt_ping(struct watchdog_device *w)
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
98
  {
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
99
100
101
102
  	struct mpc8xxx_wdt_ddata *ddata =
  		container_of(w, struct mpc8xxx_wdt_ddata, wdd);
  
  	mpc8xxx_wdt_keepalive(ddata);
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
103
104
  	return 0;
  }
d5cfaf0a8   Christophe Leroy   watchdog: mpc8xxx...
105
  static struct watchdog_info mpc8xxx_wdt_info = {
19ce9490a   Christophe Leroy   watchdog: mpc8xxx...
106
  	.options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT,
d5cfaf0a8   Christophe Leroy   watchdog: mpc8xxx...
107
108
  	.firmware_version = 1,
  	.identity = "MPC8xxx",
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
109
  };
d5cfaf0a8   Christophe Leroy   watchdog: mpc8xxx...
110
111
112
113
  static struct watchdog_ops mpc8xxx_wdt_ops = {
  	.owner = THIS_MODULE,
  	.start = mpc8xxx_wdt_start,
  	.ping = mpc8xxx_wdt_ping,
d5cfaf0a8   Christophe Leroy   watchdog: mpc8xxx...
114
  };
2d991a164   Bill Pemberton   watchdog: remove ...
115
  static int mpc8xxx_wdt_probe(struct platform_device *ofdev)
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
116
  {
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
117
  	int ret;
de5f71222   Uwe Kleine-König   watchdog: mpc8xxx...
118
  	struct resource *res;
639397e48   Arnd Bergmann   watchdog/mpc8xxx:...
119
  	const struct mpc8xxx_wdt_type *wdt_type;
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
120
  	struct mpc8xxx_wdt_ddata *ddata;
ef8ab12ec   Anton Vorontsov   [WATCHDOG] mpc83x...
121
  	u32 freq = fsl_get_sys_freq();
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
122
  	bool enabled;
79b10e09b   Christophe Leroy   watchdog: mpc8xxx...
123
  	struct device *dev = &ofdev->dev;
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
124

79b10e09b   Christophe Leroy   watchdog: mpc8xxx...
125
  	wdt_type = of_device_get_match_data(dev);
f0ded83b9   Uwe Kleine-König   watchdog: mpc8xxx...
126
  	if (!wdt_type)
1c48a5c93   Grant Likely   dt: Eliminate of_...
127
  		return -EINVAL;
1c48a5c93   Grant Likely   dt: Eliminate of_...
128

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

79b10e09b   Christophe Leroy   watchdog: mpc8xxx...
132
  	ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
133
134
  	if (!ddata)
  		return -ENOMEM;
0f0a6a285   Guenter Roeck   watchdog: Convert...
135
  	ddata->base = devm_platform_ioremap_resource(ofdev, 0);
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
136
137
  	if (IS_ERR(ddata->base))
  		return PTR_ERR(ddata->base);
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
138

7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
139
  	enabled = in_be32(&ddata->base->swcrr) & SWCRR_SWEN;
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
140
  	if (!enabled && wdt_type->hw_enabled) {
79b10e09b   Christophe Leroy   watchdog: mpc8xxx...
141
142
  		dev_info(dev, "could not be enabled in software
  ");
72cd501e6   Uwe Kleine-König   watchdog: mpc8xxx...
143
  		return -ENODEV;
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
144
  	}
38e48b718   Christophe Leroy   watchdog: mpc8xxx...
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
  	res = platform_get_resource(ofdev, IORESOURCE_MEM, 1);
  	if (res) {
  		bool status;
  		u32 __iomem *rsr = ioremap(res->start, resource_size(res));
  
  		if (!rsr)
  			return -ENOMEM;
  
  		status = in_be32(rsr) & wdt_type->rsr_mask;
  		ddata->wdd.bootstatus = status ? WDIOF_CARDRESET : 0;
  		 /* clear reset status bits related to watchdog timer */
  		out_be32(rsr, wdt_type->rsr_mask);
  		iounmap(rsr);
  
  		dev_info(dev, "Last boot was %scaused by watchdog
  ",
  			 status ? "" : "not ");
  	}
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
163
  	spin_lock_init(&ddata->lock);
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
164
165
166
  
  	ddata->wdd.info = &mpc8xxx_wdt_info,
  	ddata->wdd.ops = &mpc8xxx_wdt_ops,
19ce9490a   Christophe Leroy   watchdog: mpc8xxx...
167
  	ddata->wdd.timeout = WATCHDOG_TIMEOUT;
79b10e09b   Christophe Leroy   watchdog: mpc8xxx...
168
  	watchdog_init_timeout(&ddata->wdd, timeout, dev);
50ffb53ef   Uwe Kleine-König   watchdog: mpc8xxx...
169

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

19ce9490a   Christophe Leroy   watchdog: mpc8xxx...
172
173
  	ddata->swtc = min(ddata->wdd.timeout * freq / wdt_type->prescaler,
  			  0xffffU);
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
174
175
176
  
  	/*
  	 * If the watchdog was previously enabled or we're running on
59ca1b0d1   Anton Vorontsov   [WATCHDOG] mpc8xx...
177
  	 * MPC8xxx, we should ping the wdt from the kernel until the
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
178
179
180
  	 * userspace handles it.
  	 */
  	if (enabled)
19ce9490a   Christophe Leroy   watchdog: mpc8xxx...
181
182
183
184
185
186
187
  		mpc8xxx_wdt_start(&ddata->wdd);
  
  	ddata->wdd.max_hw_heartbeat_ms = (ddata->swtc * wdt_type->prescaler) /
  					 (freq / 1000);
  	ddata->wdd.min_timeout = ddata->wdd.max_hw_heartbeat_ms / 1000;
  	if (ddata->wdd.timeout < ddata->wdd.min_timeout)
  		ddata->wdd.timeout = ddata->wdd.min_timeout;
81df6db68   Guenter Roeck   watchdog: mpc8xxx...
188
  	ret = devm_watchdog_register_device(dev, &ddata->wdd);
a23902732   Wolfram Sang   watchdog: mpc8xxx...
189
  	if (ret)
19ce9490a   Christophe Leroy   watchdog: mpc8xxx...
190
  		return ret;
19ce9490a   Christophe Leroy   watchdog: mpc8xxx...
191

79b10e09b   Christophe Leroy   watchdog: mpc8xxx...
192
193
194
195
  	dev_info(dev,
  		 "WDT driver for MPC8xxx initialized. mode:%s timeout=%d sec
  ",
  		 reset ? "reset" : "interrupt", ddata->wdd.timeout);
7997ebad4   Uwe Kleine-König   watchdog: mpc8xxx...
196
197
  
  	platform_set_drvdata(ofdev, ddata);
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
198
  	return 0;
fabbfb9e8   Kumar Gala   [PATCH] powerpc: ...
199
  }
59ca1b0d1   Anton Vorontsov   [WATCHDOG] mpc8xx...
200
  static const struct of_device_id mpc8xxx_wdt_match[] = {
ef8ab12ec   Anton Vorontsov   [WATCHDOG] mpc83x...
201
202
  	{
  		.compatible = "mpc83xx_wdt",
59ca1b0d1   Anton Vorontsov   [WATCHDOG] mpc8xx...
203
  		.data = &(struct mpc8xxx_wdt_type) {
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
204
  			.prescaler = 0x10000,
38e48b718   Christophe Leroy   watchdog: mpc8xxx...
205
  			.rsr_mask = BIT(3), /* RSR Bit SWRS */
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
206
207
208
209
  		},
  	},
  	{
  		.compatible = "fsl,mpc8610-wdt",
59ca1b0d1   Anton Vorontsov   [WATCHDOG] mpc8xx...
210
  		.data = &(struct mpc8xxx_wdt_type) {
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
211
212
  			.prescaler = 0x10000,
  			.hw_enabled = true,
38e48b718   Christophe Leroy   watchdog: mpc8xxx...
213
  			.rsr_mask = BIT(20), /* RSTRSCR Bit WDT_RR */
500c919e3   Anton Vorontsov   [WATCHDOG] mpc83x...
214
  		},
ef8ab12ec   Anton Vorontsov   [WATCHDOG] mpc83x...
215
  	},
0d7b10140   Anton Vorontsov   [WATCHDOG] mpc8xx...
216
217
218
219
  	{
  		.compatible = "fsl,mpc823-wdt",
  		.data = &(struct mpc8xxx_wdt_type) {
  			.prescaler = 0x800,
4af897fa9   Christophe Leroy   watchdog: mpc8xxx...
220
  			.hw_enabled = true,
38e48b718   Christophe Leroy   watchdog: mpc8xxx...
221
  			.rsr_mask = BIT(28), /* RSR Bit SWRS */
0d7b10140   Anton Vorontsov   [WATCHDOG] mpc8xx...
222
223
  		},
  	},
ef8ab12ec   Anton Vorontsov   [WATCHDOG] mpc83x...
224
225
  	{},
  };
59ca1b0d1   Anton Vorontsov   [WATCHDOG] mpc8xx...
226
  MODULE_DEVICE_TABLE(of, mpc8xxx_wdt_match);
ef8ab12ec   Anton Vorontsov   [WATCHDOG] mpc83x...
227

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

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