1 /*
2  * Copyright 2024 Microchip Technology Inc. and its subsidiaries.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <stddef.h>
7 #include <stdint.h>
8 
9 #include "mec_pcfg.h"
10 #include "mec_defs.h"
11 #include "mec_ecia_api.h"
12 #include "mec_wdt_api.h"
13 #include "mec_retval.h"
14 #include "device_mec5.h"
15 
16 /* Microchip MEC5 family watch dog timer (WDT) fires an optional interrupt
17  * to the EC before asserting internal RESET_SYS signal.
18  * Power domain: VTR
19  * Clock domain: 32KHz
20  * Counter is 16-bit, 1.007 ms per count
21  */
22 
23 #define MEC5_WDT0_GIRQ      21u
24 #define MEC5_WDT0_GIRQ_Z    13u
25 #define MEC5_WDT0_GIRQ_POS  2u
26 #define MEC5_WDT0_NVIC_NUM  171
27 #define MEC5_WDT0_ECIA_INFO MEC5_ECIA_INFO(21, 2, 13, 171)
28 
29 /* -------- WDT API -------- */
30 
31 /* Initialize a WDT instance
32  * regs - Pointer to instance HW registers.
33  * n32k_ticks - The number of 32KHz counts when expired will trigger the WDT action.
34  * n32k_ticks_intr - If WDT is configured to fire an interrupt before SoC reset,
35  *                   this is the number of 32KHz ticks before the SoC reset.
36  * flags - Configuration flags.
37  */
mec_hal_wdt_init(struct mec_wdt_regs * regs,uint16_t n32k_ticks,uint32_t flags)38 int mec_hal_wdt_init(struct mec_wdt_regs *regs, uint16_t n32k_ticks, uint32_t flags)
39 {
40     uint32_t ctrl = 0u;
41 
42     if ((uintptr_t)regs != (uintptr_t)MEC_WDT0_BASE) {
43         return MEC_RET_ERR_INVAL;
44     }
45 
46     regs->CTRL = ctrl;
47     regs->IEN = 0u;
48     regs->STATUS = UINT32_MAX;
49 
50     mec_hal_girq_ctrl(MEC5_WDT0_ECIA_INFO, 0);
51     mec_hal_girq_clr_src(MEC5_WDT0_ECIA_INFO);
52 
53     regs->LOAD = n32k_ticks;
54 
55     if (flags & MEC5_WDT_INIT_ENABLE) {
56         ctrl |= MEC_BIT(MEC_WDT_CTRL_ENABLE_Pos);
57     }
58     if (flags & MEC5_WDT_INIT_STALL_HTMR) {
59         ctrl |= MEC_BIT(MEC_WDT_CTRL_STALL_HTMR_Pos);
60     }
61     if (flags & MEC5_WDT_INIT_STALL_WKTMR) {
62         ctrl |= MEC_BIT(MEC_WDT_CTRL_STALL_WKTMR_Pos);
63     }
64     if (flags & MEC5_WDT_INIT_STALL_JTAG) {
65         ctrl |= MEC_BIT(MEC_WDT_CTRL_STALL_JTAG_Pos);
66     }
67     if (flags & MEC5_WDT_INIT_GEN_INTR) {
68         ctrl |= MEC_BIT(MEC_WDT_CTRL_RST_MODE_INTR_Pos);
69         regs->IEN |= MEC_BIT(MEC_WDT_IEN_INTREN_Pos);
70         mec_hal_girq_ctrl(MEC5_WDT0_ECIA_INFO, 1);
71     }
72 
73     regs->CTRL = ctrl;
74 
75     return MEC_RET_OK;
76 }
77 
mec_hal_wdt_is_enabled(struct mec_wdt_regs * regs)78 bool mec_hal_wdt_is_enabled(struct mec_wdt_regs *regs)
79 {
80     if (regs->CTRL & MEC_BIT(MEC_WDT_CTRL_ENABLE_Pos)) {
81         return true;
82     }
83 
84     return false;
85 }
86 
mec_hal_wdt_enable(struct mec_wdt_regs * regs)87 void mec_hal_wdt_enable(struct mec_wdt_regs *regs)
88 {
89     regs->CTRL |= MEC_BIT(MEC_WDT_CTRL_ENABLE_Pos);
90 }
91 
mec_hal_wdt_disable(struct mec_wdt_regs * regs)92 void mec_hal_wdt_disable(struct mec_wdt_regs *regs)
93 {
94     regs->CTRL &= (uint32_t)~MEC_BIT(MEC_WDT_CTRL_ENABLE_Pos);
95 }
96 
mec_hal_wdt_intr_ctrl(struct mec_wdt_regs * regs,uint8_t enable)97 void mec_hal_wdt_intr_ctrl(struct mec_wdt_regs *regs, uint8_t enable)
98 {
99     if (enable) {
100         regs->CTRL |= MEC_BIT(MEC_WDT_CTRL_RST_MODE_INTR_Pos);
101         regs->IEN |= MEC_BIT(MEC_WDT_IEN_INTREN_Pos);
102         mec_hal_girq_ctrl(MEC5_WDT0_ECIA_INFO, 1);
103     } else {
104         regs->CTRL &= (uint32_t)~MEC_BIT(MEC_WDT_CTRL_RST_MODE_INTR_Pos);
105         regs->IEN &= (uint32_t)~MEC_BIT(MEC_WDT_IEN_INTREN_Pos);
106     }
107 }
108 
mec_hal_wdt_intr_get_status(struct mec_wdt_regs * regs)109 uint8_t mec_hal_wdt_intr_get_status(struct mec_wdt_regs *regs)
110 {
111     return (uint8_t)(regs->STATUS & 0xffu);
112 }
113 
mec_hal_wdt_intr_clear_status(struct mec_wdt_regs * regs)114 void mec_hal_wdt_intr_clear_status(struct mec_wdt_regs *regs)
115 {
116     regs->STATUS = MEC_BIT(MEC_WDT_STATUS_ISTATUS_Pos);
117     mec_hal_girq_clr_src(MEC5_WDT0_ECIA_INFO);
118 }
119 
mec_hal_wdt_girq_enable(struct mec_wdt_regs * regs,uint8_t enable)120 void mec_hal_wdt_girq_enable(struct mec_wdt_regs *regs, uint8_t enable)
121 {
122     (void)regs;
123 
124     mec_hal_girq_ctrl(MEC5_WDT0_ECIA_INFO, (int)enable);
125 }
126 
mec_hal_wdt_intr_helper(struct mec_wdt_regs * regs,uint16_t counts_before_reset)127 void mec_hal_wdt_intr_helper(struct mec_wdt_regs *regs, uint16_t counts_before_reset)
128 {
129     uint16_t load = 1u;
130 
131     regs->CTRL &= (uint32_t)~(MEC_BIT(MEC_WDT_CTRL_ENABLE_Pos)
132                               | MEC_BIT(MEC_WDT_CTRL_RST_MODE_INTR_Pos));
133     regs->IEN = 0u;
134     regs->STATUS = MEC_BIT(MEC_WDT_STATUS_ISTATUS_Pos);
135     mec_hal_girq_clr_src(MEC5_WDT0_ECIA_INFO);
136 
137     if (counts_before_reset) {
138         load = counts_before_reset;
139     }
140 
141     regs->LOAD = load;
142     regs->CTRL |= MEC_BIT(MEC_WDT_CTRL_ENABLE_Pos);
143 }
144 
145 /* Force WDT to reload its counter from the currently configured count */
mec_hal_wdt_restart(struct mec_wdt_regs * regs)146 void mec_hal_wdt_restart(struct mec_wdt_regs *regs)
147 {
148     regs->KICK = 0u;
149 }
150 
151 /* Update configured WDT with a new count down value */
mec_hal_wdt_reload(struct mec_wdt_regs * regs,uint16_t nmsec)152 void mec_hal_wdt_reload(struct mec_wdt_regs *regs, uint16_t nmsec)
153 {
154     regs->LOAD = nmsec;
155     regs->KICK = nmsec;
156 }
157 
mec_hal_wdt_debug_stall(struct mec_wdt_regs * regs,uint8_t enable)158 void mec_hal_wdt_debug_stall(struct mec_wdt_regs *regs, uint8_t enable)
159 {
160     if (enable) {
161         regs->CTRL |= MEC_BIT(MEC_WDT_CTRL_STALL_JTAG_Pos);
162     } else {
163         regs->CTRL &= (uint32_t)~MEC_BIT(MEC_WDT_CTRL_STALL_JTAG_Pos);
164     }
165 }
166 
mec_hal_wdt_kick(struct mec_wdt_regs * regs)167 void mec_hal_wdt_kick(struct mec_wdt_regs *regs)
168 {
169     regs->KICK = 0;
170 }
171 
mec_hal_wdt_count(struct mec_wdt_regs * regs)172 uint32_t mec_hal_wdt_count(struct mec_wdt_regs *regs)
173 {
174     return regs->COUNT;
175 }
176 
177 /* end mec_wdt.c */
178