-
Notifications
You must be signed in to change notification settings - Fork 6.1k
/
wdt_cmsdk_apb.c
207 lines (162 loc) · 5.13 KB
/
wdt_cmsdk_apb.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
/*
* Copyright (c) 2016 Linaro Limited
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT arm_cmsdk_watchdog
/**
* @brief Driver for CMSDK APB Watchdog.
*/
#include <errno.h>
#include <soc.h>
#include <zephyr/arch/arm/nmi.h>
#include <zephyr/drivers/watchdog.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/reboot.h>
struct wdog_cmsdk_apb {
/* offset: 0x000 (r/w) watchdog load register */
volatile uint32_t load;
/* offset: 0x004 (r/ ) watchdog value register */
volatile uint32_t value;
/* offset: 0x008 (r/w) watchdog control register */
volatile uint32_t ctrl;
/* offset: 0x00c ( /w) watchdog clear interrupt register */
volatile uint32_t intclr;
/* offset: 0x010 (r/ ) watchdog raw interrupt status register */
volatile uint32_t rawintstat;
/* offset: 0x014 (r/ ) watchdog interrupt status register */
volatile uint32_t maskintstat;
volatile uint32_t reserved0[762];
/* offset: 0xc00 (r/w) watchdog lock register */
volatile uint32_t lock;
volatile uint32_t reserved1[191];
/* offset: 0xf00 (r/w) watchdog integration test control register */
volatile uint32_t itcr;
/* offset: 0xf04 ( /w) watchdog integration test output set register */
volatile uint32_t itop;
};
#define CMSDK_APB_WDOG_LOAD (0xFFFFFFFF << 0)
#define CMSDK_APB_WDOG_RELOAD (0xE4E1C00 << 0)
#define CMSDK_APB_WDOG_VALUE (0xFFFFFFFF << 0)
#define CMSDK_APB_WDOG_CTRL_RESEN (0x1 << 1)
#define CMSDK_APB_WDOG_CTRL_INTEN (0x1 << 0)
#define CMSDK_APB_WDOG_INTCLR (0x1 << 0)
#define CMSDK_APB_WDOG_RAWINTSTAT (0x1 << 0)
#define CMSDK_APB_WDOG_MASKINTSTAT (0x1 << 0)
#define CMSDK_APB_WDOG_LOCK (0x1 << 0)
#define CMSDK_APB_WDOG_INTEGTESTEN (0x1 << 0)
#define CMSDK_APB_WDOG_INTEGTESTOUTSET (0x1 << 1)
/*
* Value written to the LOCK register to lock or unlock the write access
* to all of the registers of the watchdog (except the LOCK register)
*/
#define CMSDK_APB_WDOG_UNLOCK_VALUE (0x1ACCE551)
#define CMSDK_APB_WDOG_LOCK_VALUE (0x2BDDF662)
#define WDOG_STRUCT \
((volatile struct wdog_cmsdk_apb *)(DT_INST_REG_ADDR(0)))
/* Keep reference of the device to pass it to the callback */
const struct device *wdog_r;
/* watchdog reload value in sec */
static unsigned int reload_s = CMSDK_APB_WDOG_RELOAD;
static uint8_t flags;
static void (*user_cb)(const struct device *dev, int channel_id);
static void wdog_cmsdk_apb_unlock(const struct device *dev)
{
volatile struct wdog_cmsdk_apb *wdog = WDOG_STRUCT;
ARG_UNUSED(dev);
wdog->lock = CMSDK_APB_WDOG_UNLOCK_VALUE;
}
static int wdog_cmsdk_apb_setup(const struct device *dev, uint8_t options)
{
volatile struct wdog_cmsdk_apb *wdog = WDOG_STRUCT;
ARG_UNUSED(dev);
ARG_UNUSED(options);
/* Start the watchdog counter with INTEN bit */
wdog->ctrl = (CMSDK_APB_WDOG_CTRL_RESEN | CMSDK_APB_WDOG_CTRL_INTEN);
return 0;
}
static int wdog_cmsdk_apb_disable(const struct device *dev)
{
volatile struct wdog_cmsdk_apb *wdog = WDOG_STRUCT;
ARG_UNUSED(dev);
/* Stop the watchdog counter with INTEN bit */
wdog->ctrl = ~(CMSDK_APB_WDOG_CTRL_RESEN | CMSDK_APB_WDOG_CTRL_INTEN);
return 0;
}
static int wdog_cmsdk_apb_install_timeout(const struct device *dev,
const struct wdt_timeout_cfg *config)
{
volatile struct wdog_cmsdk_apb *wdog = WDOG_STRUCT;
ARG_UNUSED(dev);
/* Reload value */
reload_s = config->window.max *
DT_INST_PROP_BY_PHANDLE(0, clocks, clock_frequency);
flags = config->flags;
wdog->load = reload_s;
/* Configure only the callback */
user_cb = config->callback;
return 0;
}
static int wdog_cmsdk_apb_feed(const struct device *dev, int channel_id)
{
volatile struct wdog_cmsdk_apb *wdog = WDOG_STRUCT;
ARG_UNUSED(dev);
ARG_UNUSED(channel_id);
/* Clear the interrupt */
wdog->intclr = CMSDK_APB_WDOG_INTCLR;
/* Reload */
wdog->load = reload_s;
return 0;
}
static const struct wdt_driver_api wdog_cmsdk_apb_api = {
.setup = wdog_cmsdk_apb_setup,
.disable = wdog_cmsdk_apb_disable,
.install_timeout = wdog_cmsdk_apb_install_timeout,
.feed = wdog_cmsdk_apb_feed,
};
#ifdef CONFIG_RUNTIME_NMI
static int wdog_cmsdk_apb_has_fired(void)
{
volatile struct wdog_cmsdk_apb *wdog = WDOG_STRUCT;
return (wdog->maskintstat & CMSDK_APB_WDOG_MASKINTSTAT) != 0U;
}
static void wdog_cmsdk_apb_isr(void)
{
/*
* Check if the watchdog was the reason of the NMI interrupt
* and if not, exit immediately
*/
if (!wdog_cmsdk_apb_has_fired()) {
printk("NMI received! Rebooting...\n");
/* In ARM implementation sys_reboot ignores the parameter */
sys_reboot(0);
} else {
if (user_cb != NULL) {
user_cb(wdog_r, 0);
}
}
}
#endif /* CONFIG_RUNTIME_NMI */
static int wdog_cmsdk_apb_init(const struct device *dev)
{
volatile struct wdog_cmsdk_apb *wdog = WDOG_STRUCT;
wdog_r = dev;
/* unlock access to configuration registers */
wdog_cmsdk_apb_unlock(dev);
/* set default reload value */
wdog->load = reload_s;
#ifdef CONFIG_RUNTIME_NMI
/* Configure the interrupts */
z_arm_nmi_set_handler(wdog_cmsdk_apb_isr);
#endif
#ifdef CONFIG_WDOG_CMSDK_APB_START_AT_BOOT
wdog_cmsdk_apb_setup(dev, 0);
#endif
return 0;
}
DEVICE_DT_INST_DEFINE(0,
wdog_cmsdk_apb_init,
NULL,
NULL, NULL,
PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
&wdog_cmsdk_apb_api);