Skip to content

Commit ff42294

Browse files
Nick HuDylan-Jhong
authored andcommitted
riscv: Porting Watch dog driver.
Porting the ATCWDT200 driver. NOTE: The current bitmap did not set the 'ATCWDT200_32BIT_TIMER' config, so the maximum timeout is 1 sec. According to it, the WDIOC_SETTIMEOUT of ioctl is not being support for now. It will be support in the future. Signed-off-by: Nick Hu <[email protected]>
1 parent 686726f commit ff42294

File tree

4 files changed

+301
-0
lines changed

4 files changed

+301
-0
lines changed

arch/riscv/include/asm/sbi.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@
5151
#define SBI_CALL_4(which, arg0, arg1, arg2, arg3) \
5252
SBI_CALL(which, arg0, arg1, arg2, arg3)
5353

54+
static inline void sbi_set_reset_vec(int val)
55+
{
56+
SBI_CALL_1(SBI_SET_RESET_VEC, val);
57+
}
58+
5459
static inline void sbi_console_putchar(int ch)
5560
{
5661
SBI_CALL_1(SBI_CONSOLE_PUTCHAR, ch);

drivers/watchdog/Kconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ config WATCHDOG_NOWAYOUT
4747
get killed. If you say Y here, the watchdog cannot be stopped once
4848
it has been started.
4949

50+
config WATCHDOG_DEBUG
51+
bool "Hang in watch dog interrupt handler"
52+
help
53+
When system failed, it will hang in watch dog interrupt handler for
54+
debugging.
55+
5056
config WATCHDOG_HANDLE_BOOT_ENABLED
5157
bool "Update boot-enabled watchdog until userspace takes over"
5258
default y
@@ -461,6 +467,13 @@ config FTWDT010_WATCHDOG
461467
To compile this driver as a module, choose M here: the
462468
module will be called ftwdt010_wdt.
463469

470+
config ATCWDT200_WATCHDOG
471+
tristate "ATCWDT200_WATCHDOG"
472+
depends on RISCV && PLAT_AE350
473+
help
474+
Support for Andes aycwdt200 watchdog. When the watchdog triigers the
475+
system will be reset.
476+
464477
config IXP4XX_WATCHDOG
465478
tristate "IXP4xx Watchdog"
466479
depends on ARCH_IXP4XX

drivers/watchdog/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ obj-$(CONFIG_TWL4030_WATCHDOG) += twl4030_wdt.o
4848
obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
4949
obj-$(CONFIG_977_WATCHDOG) += wdt977.o
5050
obj-$(CONFIG_FTWDT010_WATCHDOG) += ftwdt010_wdt.o
51+
obj-$(CONFIG_ATCWDT200_WATCHDOG) += atcwdt200_wdt.o
5152
obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
5253
obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
5354
obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o

drivers/watchdog/atcwdt200_wdt.c

Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
/*
2+
* Watchdog driver for the ATCWDT200 Watch Dog Driver
3+
*
4+
* (c) Copyright 2016 Andes Technology Corp. (www.andestech.com)
5+
* Based on sa1100_wdt.c by Oleg Drokin <[email protected]>
6+
* Based on SoftDog driver by Alan Cox <[email protected]>
7+
*
8+
* This program is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU General Public License
10+
* as published by the Free Software Foundation; either version
11+
* 2 of the License, or (at your option) any later version.
12+
*
13+
* 11/07/2016 Initial release
14+
*/
15+
#include <linux/module.h>
16+
#include <linux/fs.h>
17+
#include <linux/miscdevice.h>
18+
#include <linux/watchdog.h>
19+
#include <linux/delay.h>
20+
#include <asm/uaccess.h>
21+
#include <linux/reboot.h>
22+
#include <linux/of.h>
23+
#include <linux/of_platform.h>
24+
#include <linux/interrupt.h>
25+
#include <linux/io.h>
26+
#include <linux/reboot.h>
27+
#include <linux/uaccess.h>
28+
#include <linux/cpumask.h>
29+
#include <asm/processor.h>
30+
#include <asm/sbi.h>
31+
#define DRIVER_NAME "atcwdt200"
32+
#define DEBUG( str, ...) \
33+
do{ \
34+
if( debug) \
35+
printk( str, ##__VA_ARGS__); \
36+
} while(0)
37+
/* ID and Revision Register */
38+
#define idrev (*( volatile unsigned int *)( wdt_base + 0x00))
39+
#define ID_OFF 12
40+
#define ID_MSK (0xfffff<<ID_OFF)
41+
#define ID (0x03002<<ID_OFF)
42+
43+
/* Control Register */
44+
#define ctrl (*( volatile unsigned int *)( wdt_base + 0x10))
45+
#define RST_TIME_OFF 8
46+
#define RST_TIME_MSK (0x3<<RST_TIME_OFF)
47+
#define RST_CLK_128 (0<<RST_TIME_OFF)
48+
#define RST_CLK_256 (1<<RST_TIME_OFF)
49+
#define RST_CLK_512 (2<<RST_TIME_OFF)
50+
#define RST_CLK_1024 (3<<RST_TIME_OFF)
51+
#define INT_TIME_OFF 4
52+
#define INT_TIME_MSK (0xf<<INT_TIME_OFF)
53+
#define INT_CLK_64 (0<<INT_TIME_OFF)
54+
#define INT_CLK_256 (1<<INT_TIME_OFF)
55+
#define INT_CLK_1024 (2<<INT_TIME_OFF)
56+
#define INT_CLK_2048 (3<<INT_TIME_OFF)
57+
#define INT_CLK_4096 (4<<INT_TIME_OFF)
58+
#define INT_CLK_8192 (5<<INT_TIME_OFF)
59+
#define INT_CLK_16384 (6<<INT_TIME_OFF)
60+
#define INT_CLK_32768 (7<<INT_TIME_OFF)
61+
#define RST_EN (1<<3)
62+
#define INT_EN (1<<2)
63+
#define CLK_PCLK (1<<1)
64+
#define WDT_EN (1<<0)
65+
66+
/* Restart Register */
67+
#define restart (*( volatile unsigned int *)( wdt_base + 0x14))
68+
#define RESTART_MAGIC 0xcafe
69+
70+
/* Write Enable Register */
71+
#define wren (*( volatile unsigned int *)( wdt_base + 0x18))
72+
#define WP_MAGIC 0x5aa5
73+
74+
/* Status Register */
75+
#define st (*( volatile unsigned int *)( wdt_base + 0x1c))
76+
#define INT_EXPIRED (1<<0)
77+
78+
#define TIMER_MARGIN 60 /* (secs) Default is 1 minute */
79+
80+
static int expect_close = 0;
81+
static int debug = 0;
82+
static int timeout = TIMER_MARGIN; /* in seconds */
83+
static bool nowayout = WATCHDOG_NOWAYOUT;
84+
module_param(nowayout, bool, 0);
85+
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
86+
"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
87+
static int wdt_panic = 0;
88+
module_param(wdt_panic, int, 0);
89+
MODULE_PARM_DESC(wdt_panic,
90+
"Watchdog action, set to 1 to panic, 0 to reboot (default=0)");
91+
92+
module_param(debug, int, 0);
93+
module_param(timeout, int, 0);
94+
static u32 wdt_freq;
95+
static void __iomem *wdt_base;
96+
97+
// enable the WDT
98+
void wdt_start(void)
99+
{
100+
#ifdef CONFIG_WATCHDOG_DEBUG
101+
wren = WP_MAGIC;
102+
ctrl = (INT_CLK_32768|INT_EN|WDT_EN);
103+
#else
104+
wren = WP_MAGIC;
105+
ctrl = (INT_CLK_32768|INT_EN|RST_CLK_128|RST_EN|WDT_EN);
106+
#endif
107+
}
108+
109+
int wdt_get_timeout(void)
110+
{
111+
int time = (ctrl & INT_TIME_MSK) >> INT_TIME_OFF;
112+
113+
if (time > 7)
114+
return (time - 7) * 2;
115+
else
116+
return 1;
117+
}
118+
119+
// set reset vector and enable WDT
120+
static int wdtdog_open(struct inode *inode, struct file *file){
121+
int val = num_online_cpus();
122+
123+
sbi_set_reset_vec(val);
124+
wdt_start();
125+
DEBUG("Activating WDT..\n");
126+
return 0;
127+
}
128+
129+
// disable WDT, NOWAY_OUT MEANS NEED MAGIC NUMBER
130+
// OR just disable it if NOWAY_OUT not set
131+
static int wdtdog_release(struct inode *inode, struct file *file){
132+
#ifndef CONFIG_WATCHDOG_NOWAYOUT
133+
/*
134+
* Shut off the timer.
135+
* Lock it in if it's a module and we defined ...NOWAYOUT
136+
*/
137+
if(expect_close) {
138+
wren = WP_MAGIC;
139+
ctrl = 0;
140+
DEBUG( "Deactivating WDT..\n");
141+
}
142+
#endif
143+
expect_close = 0;
144+
return 0;
145+
}
146+
// clean the WDT
147+
static ssize_t wdtdog_write(struct file *file, const char *data, size_t len, loff_t *ppos){
148+
if (!len)
149+
return 0;
150+
151+
if (!nowayout){
152+
size_t i;
153+
for (i = 0; i < len; i++){
154+
char c;
155+
if (get_user(c, data + i))
156+
return -EFAULT;
157+
if (c == 'V'){
158+
expect_close = 42;
159+
break;
160+
}
161+
}
162+
}
163+
wren = WP_MAGIC;
164+
restart = RESTART_MAGIC;
165+
st |= INT_EXPIRED;
166+
return len;
167+
}
168+
169+
static long wdtdog_ioctl(struct file *file, unsigned int cmd, unsigned long arg){
170+
static struct watchdog_info ident = {
171+
.identity = "FTWDT010 watchdog",
172+
};
173+
174+
void __user *argp = (void __user *)arg;
175+
int __user *p = argp;
176+
int new_options, retval = -EINVAL;
177+
178+
switch( cmd){
179+
case WDIOC_GETSUPPORT:
180+
return copy_to_user(argp, &ident, sizeof( ident));
181+
182+
case WDIOC_GETSTATUS:
183+
case WDIOC_GETBOOTSTATUS:
184+
return put_user(0, p);
185+
186+
case WDIOC_SETOPTIONS:
187+
if (get_user(new_options, p))
188+
return -EFAULT;
189+
190+
if (new_options & WDIOS_DISABLECARD){
191+
wren = WP_MAGIC;
192+
ctrl &= ~WDT_EN;
193+
retval = 0;
194+
}
195+
196+
if (new_options & WDIOS_ENABLECARD){
197+
wdt_start();
198+
retval = 0;
199+
}
200+
return retval;
201+
202+
case WDIOC_GETTIMEOUT:
203+
timeout = wdt_get_timeout();
204+
return put_user(timeout, p);
205+
206+
case WDIOC_KEEPALIVE:
207+
wren = WP_MAGIC;
208+
restart = RESTART_MAGIC;
209+
st |= INT_EXPIRED;
210+
return 0;
211+
212+
default:
213+
return -ENOIOCTLCMD;
214+
}
215+
}
216+
217+
static struct file_operations wdtdog_fops = {
218+
.owner = THIS_MODULE,
219+
.llseek = no_llseek,
220+
.write = wdtdog_write,
221+
.unlocked_ioctl = wdtdog_ioctl,
222+
.open = wdtdog_open,
223+
.release = wdtdog_release,
224+
};
225+
226+
static struct miscdevice atcwdt200_dog_miscdev = {
227+
WATCHDOG_MINOR,
228+
"ATCWDT200 watchdog",
229+
&wdtdog_fops
230+
};
231+
232+
#ifdef CONFIG_OF
233+
static const struct of_device_id atcwdt200_dog_match[] = {
234+
{ .compatible = "andestech,atcwdt200" },
235+
{},
236+
};
237+
MODULE_DEVICE_TABLE(of, atcwdt200_dog_match);
238+
#endif
239+
240+
static int atcwdt200_dog_probe(struct platform_device *pdev){
241+
int ret;
242+
struct resource *res;
243+
struct device_node *node;
244+
245+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
246+
wdt_base = devm_ioremap_resource(&pdev->dev, res);
247+
if (IS_ERR(wdt_base))
248+
return PTR_ERR(wdt_base);
249+
250+
if((idrev & ID_MSK)!=ID)
251+
return -ENOENT;
252+
253+
node = of_find_matching_node(NULL, atcwdt200_dog_match);
254+
if (of_property_read_u32(node, "clock-frequency", &wdt_freq))
255+
panic("Can't read clock-frequency");
256+
257+
ret = misc_register(&atcwdt200_dog_miscdev);
258+
if( ret)
259+
return ret;
260+
261+
DEBUG("ATCWDT200 watchdog timer: timer timeout %d sec\n", timeout);
262+
return 0;
263+
}
264+
265+
static int atcwdt200_dog_remove(struct platform_device *pdev){
266+
misc_deregister(&atcwdt200_dog_miscdev);
267+
return 0;
268+
}
269+
270+
static struct platform_driver atcwdt200_dog_driver = {
271+
.probe = atcwdt200_dog_probe,
272+
.remove = atcwdt200_dog_remove,
273+
.driver = {
274+
.name = DRIVER_NAME,
275+
.owner = THIS_MODULE,
276+
.of_match_table = of_match_ptr(atcwdt200_dog_match),
277+
},
278+
};
279+
280+
module_platform_driver(atcwdt200_dog_driver);
281+
MODULE_AUTHOR("Andes Corp.");
282+
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)