1cbb41c91SAbhishek Shah /* SPDX-License-Identifier: BSD-2-Clause */
2cbb41c91SAbhishek Shah /*
3cbb41c91SAbhishek Shah * Copyright 2019 Broadcom.
4cbb41c91SAbhishek Shah */
5cbb41c91SAbhishek Shah
6d50fee03SEtienne Carriere #ifndef __DRIVERS_WDT_H
7d50fee03SEtienne Carriere #define __DRIVERS_WDT_H
8cbb41c91SAbhishek Shah
9011a8f96SClément Léger #include <assert.h>
10cbb41c91SAbhishek Shah #include <kernel/interrupt.h>
11cb60bce4SClément Léger #include <kernel/thread.h>
12cb60bce4SClément Léger #include <sm/sm.h>
13cbb41c91SAbhishek Shah #include <tee_api_types.h>
14cbb41c91SAbhishek Shah
15cbb41c91SAbhishek Shah struct wdt_chip {
16cbb41c91SAbhishek Shah const struct wdt_ops *ops;
17cbb41c91SAbhishek Shah struct itr_handler *wdt_itr;
18cbb41c91SAbhishek Shah };
19cbb41c91SAbhishek Shah
20cbb41c91SAbhishek Shah /*
21cbb41c91SAbhishek Shah * struct wdt_ops - The watchdog device operations
22cbb41c91SAbhishek Shah *
23011a8f96SClément Léger * @init: The routine to initialized the watchdog resources.
24cbb41c91SAbhishek Shah * @start: The routine for starting the watchdog device.
25cbb41c91SAbhishek Shah * @stop: The routine for stopping the watchdog device.
26cbb41c91SAbhishek Shah * @ping: The routine that sends a keepalive ping to the watchdog device.
27cbb41c91SAbhishek Shah * @set_timeout:The routine that finds the load value that will reset system in
28cbb41c91SAbhishek Shah * required timeout (in seconds).
29*a7f2d4bdSAntonio Borneo * @get_timeleft:The optional routine that finds if the watchdog is already
30*a7f2d4bdSAntonio Borneo * started and the time left (in seconds) before the watchdog timeouts.
31cbb41c91SAbhishek Shah *
32cbb41c91SAbhishek Shah * The wdt_ops structure contains a list of low-level operations
33cbb41c91SAbhishek Shah * that control a watchdog device.
34cbb41c91SAbhishek Shah */
35cbb41c91SAbhishek Shah struct wdt_ops {
36011a8f96SClément Léger TEE_Result (*init)(struct wdt_chip *chip, unsigned long *min_timeout,
37011a8f96SClément Léger unsigned long *max_timeout);
38cbb41c91SAbhishek Shah void (*start)(struct wdt_chip *chip);
39cbb41c91SAbhishek Shah void (*stop)(struct wdt_chip *chip);
40cbb41c91SAbhishek Shah void (*ping)(struct wdt_chip *chip);
41cbb41c91SAbhishek Shah TEE_Result (*set_timeout)(struct wdt_chip *chip, unsigned long timeout);
42*a7f2d4bdSAntonio Borneo TEE_Result (*get_timeleft)(struct wdt_chip *chip, bool *is_started,
43*a7f2d4bdSAntonio Borneo unsigned long *timeleft);
44cbb41c91SAbhishek Shah };
45cbb41c91SAbhishek Shah
46011a8f96SClément Léger #ifdef CFG_WDT
47011a8f96SClément Léger extern struct wdt_chip *wdt_chip;
48011a8f96SClément Léger
49011a8f96SClément Léger /* Register a watchdog as the system watchdog */
50011a8f96SClément Léger TEE_Result watchdog_register(struct wdt_chip *chip);
51011a8f96SClément Léger
52011a8f96SClément Léger static inline
watchdog_init(unsigned long * min_timeout,unsigned long * max_timeout)53011a8f96SClément Léger TEE_Result watchdog_init(unsigned long *min_timeout, unsigned long *max_timeout)
54011a8f96SClément Léger {
55011a8f96SClément Léger if (!wdt_chip)
56011a8f96SClément Léger return TEE_ERROR_NOT_SUPPORTED;
57011a8f96SClément Léger
58011a8f96SClément Léger if (!wdt_chip->ops->init)
59011a8f96SClément Léger return TEE_SUCCESS;
60011a8f96SClément Léger
61011a8f96SClément Léger return wdt_chip->ops->init(wdt_chip, min_timeout, max_timeout);
62011a8f96SClément Léger }
63011a8f96SClément Léger
watchdog_start(void)64011a8f96SClément Léger static inline void watchdog_start(void)
65011a8f96SClément Léger {
66011a8f96SClément Léger if (wdt_chip)
67011a8f96SClément Léger wdt_chip->ops->start(wdt_chip);
68011a8f96SClément Léger }
69011a8f96SClément Léger
watchdog_stop(void)70011a8f96SClément Léger static inline void watchdog_stop(void)
71011a8f96SClément Léger {
72011a8f96SClément Léger if (wdt_chip && wdt_chip->ops->stop)
73011a8f96SClément Léger wdt_chip->ops->stop(wdt_chip);
74011a8f96SClément Léger }
75011a8f96SClément Léger
watchdog_ping(void)76011a8f96SClément Léger static inline void watchdog_ping(void)
77011a8f96SClément Léger {
78011a8f96SClément Léger if (wdt_chip)
79011a8f96SClément Léger wdt_chip->ops->ping(wdt_chip);
80011a8f96SClément Léger }
81011a8f96SClément Léger
watchdog_settimeout(unsigned long timeout)82011a8f96SClément Léger static inline void watchdog_settimeout(unsigned long timeout)
83011a8f96SClément Léger {
84011a8f96SClément Léger if (wdt_chip)
85011a8f96SClément Léger wdt_chip->ops->set_timeout(wdt_chip, timeout);
86011a8f96SClément Léger }
87*a7f2d4bdSAntonio Borneo
88*a7f2d4bdSAntonio Borneo /*
89*a7f2d4bdSAntonio Borneo * watchdog_gettimeleft() - Get the time left before the watchdog timeouts
90*a7f2d4bdSAntonio Borneo * @is_started: [out] true if watchdog has started, false otherwise
91*a7f2d4bdSAntonio Borneo * @timeleft: [out] time left in seconds before expiration if @is_started==true
92*a7f2d4bdSAntonio Borneo */
watchdog_gettimeleft(bool * is_started,unsigned long * timeleft)93*a7f2d4bdSAntonio Borneo static inline TEE_Result watchdog_gettimeleft(bool *is_started,
94*a7f2d4bdSAntonio Borneo unsigned long *timeleft)
95*a7f2d4bdSAntonio Borneo {
96*a7f2d4bdSAntonio Borneo if (!wdt_chip || !wdt_chip->ops->get_timeleft)
97*a7f2d4bdSAntonio Borneo return TEE_ERROR_NOT_SUPPORTED;
98*a7f2d4bdSAntonio Borneo
99*a7f2d4bdSAntonio Borneo return wdt_chip->ops->get_timeleft(wdt_chip, is_started, timeleft);
100*a7f2d4bdSAntonio Borneo }
101011a8f96SClément Léger #else
watchdog_register(struct wdt_chip * chip __unused)102011a8f96SClément Léger static inline TEE_Result watchdog_register(struct wdt_chip *chip __unused)
103011a8f96SClément Léger {
104011a8f96SClément Léger return TEE_ERROR_NOT_SUPPORTED;
105011a8f96SClément Léger }
106011a8f96SClément Léger
watchdog_init(unsigned long * min_timeout __unused,unsigned long * max_timeout __unused)107011a8f96SClément Léger static inline TEE_Result watchdog_init(unsigned long *min_timeout __unused,
108011a8f96SClément Léger unsigned long *max_timeout __unused)
109011a8f96SClément Léger {
110011a8f96SClément Léger return TEE_ERROR_NOT_SUPPORTED;
111011a8f96SClément Léger }
112011a8f96SClément Léger
watchdog_start(void)113011a8f96SClément Léger static inline void watchdog_start(void) {}
watchdog_stop(void)114011a8f96SClément Léger static inline void watchdog_stop(void) {}
watchdog_ping(void)115011a8f96SClément Léger static inline void watchdog_ping(void) {}
watchdog_settimeout(unsigned long timeout __unused)116011a8f96SClément Léger static inline void watchdog_settimeout(unsigned long timeout __unused) {}
watchdog_gettimeleft(bool * is_started __unused,unsigned long * timeleft __unused)117*a7f2d4bdSAntonio Borneo static inline TEE_Result watchdog_gettimeleft(bool *is_started __unused,
118*a7f2d4bdSAntonio Borneo unsigned long *timeleft __unused)
119*a7f2d4bdSAntonio Borneo {
120*a7f2d4bdSAntonio Borneo return TEE_ERROR_NOT_SUPPORTED;
121*a7f2d4bdSAntonio Borneo }
122011a8f96SClément Léger #endif
123011a8f96SClément Léger
124cb60bce4SClément Léger #ifdef CFG_WDT_SM_HANDLER
125cb60bce4SClément Léger enum sm_handler_ret __wdt_sm_handler(struct thread_smc_args *args);
126cb60bce4SClément Léger
127cb60bce4SClément Léger static inline
wdt_sm_handler(struct thread_smc_args * args)128cb60bce4SClément Léger enum sm_handler_ret wdt_sm_handler(struct thread_smc_args *args)
129cb60bce4SClément Léger {
130cb60bce4SClément Léger if (args->a0 != CFG_WDT_SM_HANDLER_ID)
131cb60bce4SClément Léger return SM_HANDLER_PENDING_SMC;
132cb60bce4SClément Léger
133cb60bce4SClément Léger return __wdt_sm_handler(args);
134cb60bce4SClément Léger }
135cb60bce4SClément Léger #else
136cb60bce4SClément Léger static inline
wdt_sm_handler(struct thread_smc_args * args __unused)137cb60bce4SClément Léger enum sm_handler_ret wdt_sm_handler(struct thread_smc_args *args __unused)
138cb60bce4SClément Léger {
139cb60bce4SClément Léger return SM_HANDLER_PENDING_SMC;
140cb60bce4SClément Léger }
141cb60bce4SClément Léger #endif
142cb60bce4SClément Léger
143d50fee03SEtienne Carriere #endif /* __DRIVERS_WDT_H */
144