1 /*
2  * Copyright 2022-2024 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT nxp_s32_swt
8 
9 #include <zephyr/kernel.h>
10 #include <zephyr/drivers/watchdog.h>
11 #include <zephyr/drivers/clock_control.h>
12 #include <zephyr/irq.h>
13 
14 #define LOG_LEVEL CONFIG_WDT_LOG_LEVEL
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(swt_nxp_s32);
17 
18 /* Software Watchdog Timer (SWT) register definitions */
19 /* Control */
20 #define SWT_CR           0x0
21 #define SWT_CR_WEN_MASK  BIT(0)
22 #define SWT_CR_WEN(v)    FIELD_PREP(SWT_CR_WEN_MASK, (v))
23 #define SWT_CR_FRZ_MASK  BIT(1)
24 #define SWT_CR_FRZ(v)    FIELD_PREP(SWT_CR_FRZ_MASK, (v))
25 #define SWT_CR_STP_MASK  BIT(2)
26 #define SWT_CR_STP(v)    FIELD_PREP(SWT_CR_STP_MASK, (v))
27 #define SWT_CR_SLK_MASK  BIT(4)
28 #define SWT_CR_SLK(v)    FIELD_PREP(SWT_CR_SLK_MASK, (v))
29 #define SWT_CR_HLK_MASK  BIT(5)
30 #define SWT_CR_HLK(v)    FIELD_PREP(SWT_CR_HLK_MASK, (v))
31 #define SWT_CR_ITR_MASK  BIT(6)
32 #define SWT_CR_ITR(v)    FIELD_PREP(SWT_CR_ITR_MASK, (v))
33 #define SWT_CR_WND_MASK  BIT(7)
34 #define SWT_CR_WND(v)    FIELD_PREP(SWT_CR_WND_MASK, (v))
35 #define SWT_CR_RIA_MASK  BIT(8)
36 #define SWT_CR_RIA(v)    FIELD_PREP(SWT_CR_RIA_MASK, (v))
37 #define SWT_CR_SMD_MASK  GENMASK(10, 9)
38 #define SWT_CR_SMD(v)    FIELD_PREP(SWT_CR_SMD_MASK, (v))
39 #define SWT_CR_MAP_MASK  GENMASK(31, 24)
40 #define SWT_CR_MAP(v)    FIELD_PREP(SWT_CR_MAP_MASK, (v))
41 /* Interrupt */
42 #define SWT_IR           0x4
43 #define SWT_IR_TIF_MASK  BIT(0)
44 #define SWT_IR_TIF(v)    FIELD_PREP(SWT_IR_TIF_MASK, (v))
45 /* Timeout */
46 #define SWT_TO           0x8
47 #define SWT_TO_WTO_MASK  GENMASK(31, 0)
48 #define SWT_TO_WTO(v)    FIELD_PREP(SWT_TO_WTO_MASK, (v))
49 /* Window */
50 #define SWT_WN           0xc
51 #define SWT_WN_WST_MASK  GENMASK(31, 0)
52 #define SWT_WN_WST(v)    FIELD_PREP(SWT_WN_WST_MASK, (v))
53 /* Service */
54 #define SWT_SR           0x10
55 #define SWT_SR_WSC_MASK  GENMASK(15, 0)
56 #define SWT_SR_WSC(v)    FIELD_PREP(SWT_SR_WSC_MASK, (v))
57 /* Counter Output */
58 #define SWT_CO           0x14
59 #define SWT_CO_CNT_MASK  GENMASK(31, 0)
60 #define SWT_CO_CNT(v)    FIELD_PREP(SWT_CO_CNT_MASK, (v))
61 /* Service Key */
62 #define SWT_SK           0x18
63 #define SWT_SK_SK_MASK   GENMASK(15, 0)
64 #define SWT_SK_SK(v)     FIELD_PREP(SWT_SK_SK_MASK, (v))
65 /* Event Request */
66 #define SWT_RRR          0x1c
67 #define SWT_RRR_RRF_MASK BIT(0)
68 #define SWT_RRR_RRF(v)   FIELD_PREP(SWT_RRR_RRF_MASK, (v))
69 
70 #define SWT_TO_WTO_MIN 0x100
71 
72 #define SWT_SR_WSC_UNLOCK_KEY1  0xC520U
73 #define SWT_SR_WSC_UNLOCK_KEY2  0xD928U
74 
75 #define SWT_SR_WSC_SERVICE_KEY1 0xA602U
76 #define SWT_SR_WSC_SERVICE_KEY2 0xB480U
77 
78 #define SWT_SOFT_LOCK_TIMEOUT_US 3000
79 
80 /* Handy accessors */
81 #define REG_READ(r)      sys_read32(config->base + (r))
82 #define REG_WRITE(r, v)  sys_write32((v), config->base + (r))
83 
84 enum swt_service_mode {
85 	SWT_FIXED_SERVICE = 0,
86 	SWT_KEYED_SERVICE = 1,
87 };
88 
89 enum swt_lock_mode {
90 	SWT_UNLOCKED  = 0,
91 	SWT_SOFT_LOCK = 1,
92 	SWT_HARD_LOCK = 2,
93 };
94 
95 struct swt_nxp_s32_timeout {
96 	uint32_t period;
97 	uint32_t window_start;
98 	bool window_mode;
99 };
100 
101 struct swt_nxp_s32_config {
102 	mem_addr_t base;
103 	const struct device *clock_dev;
104 	clock_control_subsys_t clock_subsys;
105 	uint8_t master_access_mask;
106 	enum swt_lock_mode lock_mode;
107 	enum swt_service_mode service_mode;
108 	uint16_t initial_key;
109 	bool reset_on_invalid_access;
110 };
111 
112 struct swt_nxp_s32_data {
113 	wdt_callback_t callback;
114 	bool timeout_valid;
115 	struct swt_nxp_s32_timeout timeout;
116 };
117 
swt_lock(const struct swt_nxp_s32_config * config)118 static void swt_lock(const struct swt_nxp_s32_config *config)
119 {
120 	switch (config->lock_mode) {
121 	case SWT_HARD_LOCK:
122 		REG_WRITE(SWT_CR, REG_READ(SWT_CR) | SWT_CR_HLK(1U));
123 		break;
124 	case SWT_SOFT_LOCK:
125 		REG_WRITE(SWT_CR, REG_READ(SWT_CR) | SWT_CR_SLK(1U));
126 		break;
127 	case SWT_UNLOCKED:
128 		__fallthrough;
129 	default:
130 		break;
131 	}
132 }
133 
swt_unlock(const struct swt_nxp_s32_config * config)134 static int swt_unlock(const struct swt_nxp_s32_config *config)
135 {
136 	int err = 0;
137 
138 	if (FIELD_GET(SWT_CR_HLK_MASK, REG_READ(SWT_CR)) != 0U) {
139 		LOG_ERR("Watchdog hard-locked");
140 		err = -EFAULT;
141 
142 	} else if (FIELD_GET(SWT_CR_SLK_MASK, REG_READ(SWT_CR)) != 0U) {
143 		REG_WRITE(SWT_SR, SWT_SR_WSC(SWT_SR_WSC_UNLOCK_KEY1));
144 		REG_WRITE(SWT_SR, SWT_SR_WSC(SWT_SR_WSC_UNLOCK_KEY2));
145 
146 		if (!WAIT_FOR(FIELD_GET(SWT_CR_SLK_MASK, REG_READ(SWT_CR) != 0),
147 			      SWT_SOFT_LOCK_TIMEOUT_US, NULL)) {
148 
149 			LOG_ERR("Timedout while trying to unlock");
150 			err = -ETIMEDOUT;
151 			/* make sure is locked again before we leave */
152 			REG_WRITE(SWT_CR, REG_READ(SWT_CR) | SWT_CR_SLK(1U));
153 		}
154 	}
155 
156 	return err;
157 }
158 
swt_gen_service_key(const struct swt_nxp_s32_config * config)159 static inline uint16_t swt_gen_service_key(const struct swt_nxp_s32_config *config)
160 {
161 	/* Calculated pseudo-random key according to Service Key Generation chapter in RM */
162 	return (uint16_t)((FIELD_GET(SWT_SK_SK_MASK, REG_READ(SWT_SK)) * 17U) + 3U);
163 }
164 
swt_nxp_s32_setup(const struct device * dev,uint8_t options)165 static int swt_nxp_s32_setup(const struct device *dev, uint8_t options)
166 {
167 	const struct swt_nxp_s32_config *config = dev->config;
168 	struct swt_nxp_s32_data *data = dev->data;
169 	int err;
170 	uint32_t reg_val;
171 
172 	if (!data->timeout_valid) {
173 		LOG_ERR("No valid timeouts installed");
174 		return -EINVAL;
175 	}
176 
177 	err = swt_unlock(config);
178 	if (err) {
179 		return err;
180 	}
181 
182 	reg_val = REG_READ(SWT_CR);
183 	reg_val &= ~(SWT_CR_WND_MASK | SWT_CR_STP_MASK | SWT_CR_FRZ_MASK | SWT_CR_ITR_MASK);
184 	REG_WRITE(SWT_CR, reg_val |
185 		  SWT_CR_WND(data->timeout.window_mode ? 1U : 0U) |
186 		  SWT_CR_ITR(data->callback ? 1U : 0U) |
187 		  SWT_CR_STP((options & WDT_OPT_PAUSE_IN_SLEEP) ? 1U : 0U) |
188 		  SWT_CR_FRZ((options & WDT_OPT_PAUSE_HALTED_BY_DBG) ? 1U : 0U));
189 
190 	REG_WRITE(SWT_IR, SWT_IR_TIF(1U));
191 	REG_WRITE(SWT_TO, SWT_TO_WTO(data->timeout.period));
192 	REG_WRITE(SWT_WN, SWT_WN_WST(data->timeout.window_start));
193 
194 	if (config->service_mode == SWT_KEYED_SERVICE) {
195 		REG_WRITE(SWT_SK, SWT_SK_SK(config->initial_key));
196 	}
197 
198 	REG_WRITE(SWT_CR, REG_READ(SWT_CR) | SWT_CR_WEN(1U));
199 	swt_lock(config);
200 
201 	return 0;
202 }
203 
swt_nxp_s32_disable(const struct device * dev)204 static int swt_nxp_s32_disable(const struct device *dev)
205 {
206 	const struct swt_nxp_s32_config *config = dev->config;
207 	struct swt_nxp_s32_data *data = dev->data;
208 	int err;
209 
210 	if (!FIELD_GET(SWT_CR_WEN_MASK, REG_READ(SWT_CR))) {
211 		LOG_ERR("Watchdog is not enabled");
212 		return -EFAULT;
213 	}
214 
215 	err = swt_unlock(config);
216 	if (err) {
217 		return err;
218 	}
219 
220 	/* Disable the watchdog and clear interrupt flags */
221 	REG_WRITE(SWT_CR, REG_READ(SWT_CR) & ~SWT_CR_WEN_MASK);
222 	REG_WRITE(SWT_IR, SWT_IR_TIF(1U));
223 
224 	swt_lock(config);
225 
226 	data->timeout_valid = false;
227 
228 	return 0;
229 }
230 
swt_nxp_s32_install_timeout(const struct device * dev,const struct wdt_timeout_cfg * cfg)231 static int swt_nxp_s32_install_timeout(const struct device *dev,
232 				       const struct wdt_timeout_cfg *cfg)
233 {
234 	const struct swt_nxp_s32_config *config = dev->config;
235 	struct swt_nxp_s32_data *data = dev->data;
236 	bool window_mode = false;
237 	uint32_t window = 0;
238 	uint32_t period;
239 	uint32_t clock_rate;
240 	int err;
241 
242 	if (data->timeout_valid) {
243 		LOG_ERR("No more timeouts can be installed");
244 		return -ENOMEM;
245 	}
246 
247 	err = clock_control_get_rate(config->clock_dev, config->clock_subsys, &clock_rate);
248 	if (err) {
249 		LOG_ERR("Failed to get module clock frequency");
250 		return err;
251 	}
252 
253 	period = clock_rate / 1000U * cfg->window.max;
254 
255 	if (cfg->window.min) {
256 		window_mode = true;
257 		window = clock_rate / 1000U * (cfg->window.max - cfg->window.min);
258 	}
259 
260 	if ((period < SWT_TO_WTO_MIN) || (period < window)) {
261 		LOG_ERR("Invalid timeout");
262 		return -EINVAL;
263 	}
264 
265 	data->timeout.period = period;
266 	data->timeout.window_start = window;
267 	data->timeout.window_mode = window_mode;
268 	data->callback = cfg->callback;
269 	data->timeout_valid = true;
270 	LOG_DBG("Installed timeout: period=%d, window=%d (%s)",
271 		period, window, window_mode ? "enabled" : "disabled");
272 
273 	return 0;
274 }
275 
swt_nxp_s32_feed(const struct device * dev,int channel)276 static int swt_nxp_s32_feed(const struct device *dev, int channel)
277 {
278 	const struct swt_nxp_s32_config *config = dev->config;
279 	bool match_unlock_seq = false;
280 	int err = 0;
281 
282 	ARG_UNUSED(channel);
283 
284 	switch (config->service_mode) {
285 	case SWT_FIXED_SERVICE:
286 		REG_WRITE(SWT_SR, SWT_SR_WSC(SWT_SR_WSC_SERVICE_KEY1));
287 		REG_WRITE(SWT_SR, SWT_SR_WSC(SWT_SR_WSC_SERVICE_KEY2));
288 		break;
289 	case SWT_KEYED_SERVICE:
290 		/*
291 		 * If one or more service routines use both unlock keys in the proper order,
292 		 * the watchdog unlocks the soft lock
293 		 */
294 		if (swt_gen_service_key(config) == SWT_SR_WSC_UNLOCK_KEY1) {
295 			match_unlock_seq = true;
296 		}
297 		REG_WRITE(SWT_SR, SWT_SR_WSC(swt_gen_service_key(config)));
298 
299 		if (swt_gen_service_key(config) == SWT_SR_WSC_UNLOCK_KEY1) {
300 			match_unlock_seq = true;
301 		}
302 		REG_WRITE(SWT_SR, SWT_SR_WSC(swt_gen_service_key(config)));
303 
304 		if (match_unlock_seq && (config->lock_mode == SWT_SOFT_LOCK)) {
305 			/*
306 			 * Service key generated matched the unlock sequence, complete the
307 			 * unlock sequence and reinitiate the soft lock
308 			 */
309 			REG_WRITE(SWT_SR, SWT_SR_WSC(SWT_SR_WSC_UNLOCK_KEY2));
310 			swt_lock(config);
311 		}
312 		break;
313 	default:
314 		LOG_ERR("Invalid service mode");
315 		err = -EINVAL;
316 		break;
317 	}
318 
319 	LOG_DBG("Fed the watchdog");
320 
321 	return err;
322 }
323 
swt_nxp_s32_isr(const struct device * dev)324 static void swt_nxp_s32_isr(const struct device *dev)
325 {
326 	const struct swt_nxp_s32_config *config = dev->config;
327 	struct swt_nxp_s32_data *data = dev->data;
328 	uint32_t reg_val;
329 
330 	if (FIELD_GET(SWT_IR_TIF_MASK, REG_READ(SWT_IR)) &&
331 	    FIELD_GET(SWT_CR_ITR_MASK, REG_READ(SWT_CR))) {
332 		/* Clear interrupt flag */
333 		reg_val = REG_READ(SWT_IR);
334 		reg_val &= SWT_IR_TIF_MASK;
335 		REG_WRITE(SWT_IR, reg_val);
336 
337 		if (data->callback) {
338 			/* SWT only has one channel */
339 			data->callback(dev, 0U);
340 		}
341 	}
342 }
343 
swt_nxp_s32_init(const struct device * dev)344 static int swt_nxp_s32_init(const struct device *dev)
345 {
346 	const struct swt_nxp_s32_config *config = dev->config;
347 	int err;
348 
349 	if (!device_is_ready(config->clock_dev)) {
350 		return -ENODEV;
351 	}
352 
353 	err = clock_control_on(config->clock_dev, config->clock_subsys);
354 	if (err) {
355 		return err;
356 	}
357 
358 	REG_WRITE(SWT_CR,
359 		  SWT_CR_MAP(config->master_access_mask) |
360 		  SWT_CR_RIA(config->reset_on_invalid_access) |
361 		  SWT_CR_SMD(config->service_mode));
362 
363 	return 0;
364 }
365 
366 static DEVICE_API(wdt, swt_nxp_s32_driver_api) = {
367 	.setup = swt_nxp_s32_setup,
368 	.disable = swt_nxp_s32_disable,
369 	.install_timeout = swt_nxp_s32_install_timeout,
370 	.feed = swt_nxp_s32_feed,
371 };
372 
373 #define SWT_NXP_S32_DEVICE_INIT(n)							\
374 	static struct swt_nxp_s32_data swt_nxp_s32_data_##n;				\
375 											\
376 	static const struct swt_nxp_s32_config swt_nxp_s32_config_##n = {		\
377 		.base = DT_INST_REG_ADDR(n),						\
378 		.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)),			\
379 		.clock_subsys = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(n, name),	\
380 		.master_access_mask = DT_INST_PROP(n, master_access_mask),		\
381 		.reset_on_invalid_access = DT_INST_PROP(n, reset_on_invalid_access),	\
382 		.service_mode = DT_INST_ENUM_IDX(n, service_mode),			\
383 		.initial_key = (uint16_t)DT_INST_PROP(n, initial_key),			\
384 		.lock_mode = DT_INST_ENUM_IDX(n, lock_mode),				\
385 	};										\
386 											\
387 	static int swt_nxp_s32_##n##_init(const struct device *dev)			\
388 	{										\
389 		int err;								\
390 											\
391 		err = swt_nxp_s32_init(dev);						\
392 		if (err) {								\
393 			return err;							\
394 		}									\
395 											\
396 		IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority),			\
397 			    swt_nxp_s32_isr, DEVICE_DT_INST_GET(n),			\
398 			    COND_CODE_1(DT_INST_IRQ_HAS_CELL(n, flags),			\
399 					(DT_INST_IRQ(n, flags)), (0)));			\
400 		irq_enable(DT_INST_IRQN(n));						\
401 											\
402 		return 0;								\
403 	}										\
404 											\
405 	DEVICE_DT_INST_DEFINE(n,							\
406 			 swt_nxp_s32_##n##_init,					\
407 			 NULL,								\
408 			 &swt_nxp_s32_data_##n,						\
409 			 &swt_nxp_s32_config_##n,					\
410 			 POST_KERNEL,							\
411 			 CONFIG_KERNEL_INIT_PRIORITY_DEVICE,				\
412 			 &swt_nxp_s32_driver_api);
413 
414 DT_INST_FOREACH_STATUS_OKAY(SWT_NXP_S32_DEVICE_INIT)
415