Merge branch 'master' of git://git.denx.de/u-boot-i2c
[platform/kernel/u-boot.git] / drivers / watchdog / tangier_wdt.c
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 }