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