1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2017 Intel Corporation
4  */
5 #include <common.h>
6 #include <watchdog.h>
7 #include <asm/scu.h>
8 
9 /* Hardware timeout in seconds */
10 #define WDT_PRETIMEOUT		15
11 #define WDT_TIMEOUT_MIN		(1 + WDT_PRETIMEOUT)
12 #define WDT_TIMEOUT_MAX		170
13 #define WDT_DEFAULT_TIMEOUT	90
14 
15 #ifndef CONFIG_WATCHDOG_TIMEOUT_MSECS
16 #define WATCHDOG_HEARTBEAT 60000
17 #else
18 #define WATCHDOG_HEARTBEAT CONFIG_WATCHDOG_TIMEOUT_MSECS
19 #endif
20 
21 enum {
22 	SCU_WATCHDOG_START			= 0,
23 	SCU_WATCHDOG_STOP			= 1,
24 	SCU_WATCHDOG_KEEPALIVE			= 2,
25 	SCU_WATCHDOG_SET_ACTION_ON_TIMEOUT	= 3,
26 };
27 
28 void hw_watchdog_reset(void)
29 {
30 	static unsigned long last;
31 	unsigned long now;
32 
33 	if (gd->timer)
34 		now = timer_get_us();
35 	else
36 		now = rdtsc() / 1000;
37 
38 	/* Do not flood SCU */
39 	if (last > now)
40 		last = 0;
41 
42 	if (unlikely((now - last) > (WDT_PRETIMEOUT / 2) * 1000000)) {
43 		last = now;
44 		scu_ipc_simple_command(IPCMSG_WATCHDOG_TIMER, SCU_WATCHDOG_KEEPALIVE);
45 	}
46 }
47 
48 int hw_watchdog_disable(void)
49 {
50 	return scu_ipc_simple_command(IPCMSG_WATCHDOG_TIMER, SCU_WATCHDOG_STOP);
51 }
52 
53 void hw_watchdog_init(void)
54 {
55 	u32 timeout = WATCHDOG_HEARTBEAT / 1000;
56 	int in_size;
57 	struct ipc_wd_start {
58 		u32 pretimeout;
59 		u32 timeout;
60 	} ipc_wd_start = { timeout - WDT_PRETIMEOUT, timeout };
61 
62 	/*
63 	 * SCU expects the input size for watchdog IPC
64 	 * to be based on 4 bytes
65 	 */
66 	in_size = DIV_ROUND_UP(sizeof(ipc_wd_start), 4);
67 
68 	scu_ipc_command(IPCMSG_WATCHDOG_TIMER, SCU_WATCHDOG_START,
69 			(u32 *)&ipc_wd_start, in_size, NULL, 0);
70 }
71