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