1 //*****************************************************************************
2 //
3 //! @file am_hal_wdt.c
4 //!
5 //! @brief Watchdog Timer
6 //!
7 //! @addtogroup wdt_4p WDT - Watchdog Timer Functionality
8 //! @ingroup apollo4p_hal
9 //! @{
10 //
11 //*****************************************************************************
12 
13 //*****************************************************************************
14 //
15 // Copyright (c) 2023, Ambiq Micro, Inc.
16 // All rights reserved.
17 //
18 // Redistribution and use in source and binary forms, with or without
19 // modification, are permitted provided that the following conditions are met:
20 //
21 // 1. Redistributions of source code must retain the above copyright notice,
22 // this list of conditions and the following disclaimer.
23 //
24 // 2. Redistributions in binary form must reproduce the above copyright
25 // notice, this list of conditions and the following disclaimer in the
26 // documentation and/or other materials provided with the distribution.
27 //
28 // 3. Neither the name of the copyright holder nor the names of its
29 // contributors may be used to endorse or promote products derived from this
30 // software without specific prior written permission.
31 //
32 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
33 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
36 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
37 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
38 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
39 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
40 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42 // POSSIBILITY OF SUCH DAMAGE.
43 //
44 // This is part of revision release_sdk_4_4_0-3c5977e664 of the AmbiqSuite Development Package.
45 //
46 //*****************************************************************************
47 
48 #include <stdint.h>
49 #include <stdbool.h>
50 #include "am_mcu_apollo.h"
51 
52 //*****************************************************************************
53 //
54 // Static function prototypes
55 //
56 //*****************************************************************************
57 static uint32_t dsp_wdt_config(am_hal_wdt_select_e eTimer, void *pvConfig);
58 
59 //*****************************************************************************
60 //
61 // Configure the watchdog timer.
62 //
63 //*****************************************************************************
64 uint32_t
am_hal_wdt_config(am_hal_wdt_select_e eTimer,void * pvConfig)65 am_hal_wdt_config(am_hal_wdt_select_e eTimer, void *pvConfig)
66 {
67     uint32_t ui32ConfigValue;
68     am_hal_wdt_config_t *psConfig = pvConfig;
69 
70     //
71     // Check to see if we're configuring the MCU watchdog, or one of the DSP
72     // watchdogs.
73     //
74     if (eTimer == AM_HAL_WDT_MCU)
75     {
76         ui32ConfigValue = 0;
77 
78         //
79         // Apply the settings from our configuration structure.
80         //
81         ui32ConfigValue |= _VAL2FLD(WDT_CFG_CLKSEL, psConfig->eClockSource);
82         ui32ConfigValue |= _VAL2FLD(WDT_CFG_INTVAL, psConfig->ui32InterruptValue);
83         ui32ConfigValue |= _VAL2FLD(WDT_CFG_RESVAL, psConfig->ui32ResetValue);
84 
85         if (psConfig->bAlertOnDSPReset)
86         {
87             ui32ConfigValue |= _VAL2FLD(WDT_CFG_DSPRESETINTEN, 1);
88         }
89 
90         if (psConfig->bResetEnable)
91         {
92             ui32ConfigValue |= _VAL2FLD(WDT_CFG_RESEN, 1);
93         }
94 
95         if (psConfig->bInterruptEnable)
96         {
97             ui32ConfigValue |= _VAL2FLD(WDT_CFG_INTEN, 1);
98         }
99 
100         //
101         // Write the settings to the WDT config register.
102         //
103         WDT->CFG = ui32ConfigValue;
104 
105         //
106         // Enabled the WDT Reset if requested.
107         //
108         RSTGEN->CFG_b.WDREN = psConfig->bResetEnable;
109 
110         return AM_HAL_STATUS_SUCCESS;
111     }
112     else
113     {
114         //
115         // DSP register settings are a little different.
116         //
117         return dsp_wdt_config(eTimer, pvConfig);
118     }
119 }
120 
121 //*****************************************************************************
122 //
123 // Configure the watchdog for a DSP.
124 //
125 //*****************************************************************************
126 uint32_t
dsp_wdt_config(am_hal_wdt_select_e eTimer,void * pvConfig)127 dsp_wdt_config(am_hal_wdt_select_e eTimer, void *pvConfig)
128 {
129     uint32_t ui32ConfigValue = 0;
130     am_hal_wdt_config_dsp_t *psConfig = pvConfig;
131 
132     switch (eTimer)
133     {
134         case AM_HAL_WDT_DSP0:
135             //
136             // Apply the settings from our configuration structure.
137             //
138             ui32ConfigValue |= _FLD2VAL(WDT_DSP0CFG_DSP0PMRESVAL, psConfig->ui32PMResetValue);
139             ui32ConfigValue |= _FLD2VAL(WDT_DSP0CFG_DSP0INTVAL, psConfig->ui32InterruptValue);
140             ui32ConfigValue |= _FLD2VAL(WDT_DSP0CFG_DSP0RESVAL, psConfig->ui32ResetValue);
141 
142             if (psConfig->bPMResetEnable)
143             {
144                 ui32ConfigValue |= _FLD2VAL(WDT_DSP0CFG_DSP0PMRESEN, 1);
145             }
146 
147             if (psConfig->bResetEnable)
148             {
149                 ui32ConfigValue |= _FLD2VAL(WDT_DSP0CFG_DSP0RESEN, 1);
150             }
151 
152             if (psConfig->bInterruptEnable)
153             {
154                 ui32ConfigValue |= _FLD2VAL(WDT_DSP0CFG_DSP0INTEN, 1);
155             }
156 
157             //
158             // Write the settings to the WDT config register.
159             //
160             WDT->DSP0CFG = ui32ConfigValue;
161             break;
162 
163         case AM_HAL_WDT_DSP1:
164             //
165             // Apply the settings from our configuration structure.
166             //
167             ui32ConfigValue |= _FLD2VAL(WDT_DSP1CFG_DSP1PMRESVAL, psConfig->ui32PMResetValue);
168             ui32ConfigValue |= _FLD2VAL(WDT_DSP1CFG_DSP1INTVAL, psConfig->ui32InterruptValue);
169             ui32ConfigValue |= _FLD2VAL(WDT_DSP1CFG_DSP1RESVAL, psConfig->ui32ResetValue);
170 
171             if (psConfig->bPMResetEnable)
172             {
173                 ui32ConfigValue |= _FLD2VAL(WDT_DSP1CFG_DSP1PMRESEN, 1);
174             }
175 
176             if (psConfig->bResetEnable)
177             {
178                 ui32ConfigValue |= _FLD2VAL(WDT_DSP1CFG_DSP1RESEN, 1);
179             }
180 
181             if (psConfig->bInterruptEnable)
182             {
183                 ui32ConfigValue |= _FLD2VAL(WDT_DSP1CFG_DSP1INTEN, 1);
184             }
185 
186             //
187             // Write the settings to the WDT config register.
188             //
189             WDT->DSP1CFG = ui32ConfigValue;
190             break;
191 
192         //
193         // Error. The option we were given was not a valid DSP WDT.
194         //
195         default:
196             return AM_HAL_STATUS_FAIL;
197     }
198 
199     return AM_HAL_STATUS_SUCCESS;
200 }
201 
202 //*****************************************************************************
203 //
204 // Enables the watchdog timer.
205 //
206 //*****************************************************************************
207 uint32_t
am_hal_wdt_start(am_hal_wdt_select_e eTimer,bool bLock)208 am_hal_wdt_start(am_hal_wdt_select_e eTimer, bool bLock)
209 {
210     //
211     // Enable the timer.
212     //
213     switch (eTimer)
214     {
215         case AM_HAL_WDT_MCU:
216             WDT->RSTRT = WDT_RSTRT_RSTRT_KEYVALUE;
217             WDT->CFG_b.WDTEN = 1;
218             break;
219 
220         case AM_HAL_WDT_DSP0:
221             WDT->DSP0RSTRT = WDT_DSP0RSTRT_DSP0RSTART_KEYVALUE;
222             WDT->DSP0CFG_b.DSP0WDTEN = 1;
223             break;
224 
225         case AM_HAL_WDT_DSP1:
226             WDT->DSP1RSTRT = WDT_DSP1RSTRT_DSP1RSTART_KEYVALUE;
227             WDT->DSP1CFG_b.DSP1WDTEN = 1;
228             break;
229 
230         default:
231             return AM_HAL_STATUS_FAIL;
232     }
233 
234     //
235     // Lock the timer if we were asked to do so.
236     //
237     if (bLock)
238     {
239         switch (eTimer)
240         {
241             case AM_HAL_WDT_MCU:
242                 WDT->LOCK = WDT_LOCK_LOCK_KEYVALUE;
243                 break;
244 
245             case AM_HAL_WDT_DSP0:
246                 WDT->DSP0TLOCK = WDT_DSP0TLOCK_DSP0LOCK_KEYVALUE;
247                 break;
248 
249             case AM_HAL_WDT_DSP1:
250                 WDT->DSP1TLOCK = WDT_DSP1TLOCK_DSP1LOCK_KEYVALUE;
251                 break;
252 
253             default:
254                 return AM_HAL_STATUS_FAIL;
255         }
256     }
257 
258     return AM_HAL_STATUS_SUCCESS;
259 }
260 
261 //*****************************************************************************
262 //
263 // Disables the watchdog timer.
264 //
265 //*****************************************************************************
266 uint32_t
am_hal_wdt_stop(am_hal_wdt_select_e eTimer)267 am_hal_wdt_stop(am_hal_wdt_select_e eTimer)
268 {
269     switch (eTimer)
270     {
271         case AM_HAL_WDT_MCU:
272             WDT->CFG_b.WDTEN = 0;
273             break;
274 
275         case AM_HAL_WDT_DSP0:
276             WDT->DSP0CFG_b.DSP0WDTEN = 0;
277             break;
278 
279         case AM_HAL_WDT_DSP1:
280             WDT->DSP1CFG_b.DSP1WDTEN = 0;
281             break;
282 
283         default:
284             return AM_HAL_STATUS_FAIL;
285     }
286 
287     return AM_HAL_STATUS_SUCCESS;
288 }
289 
290 //*****************************************************************************
291 //
292 // Restart (pet/feed) the watchdgog
293 //
294 //*****************************************************************************
295 uint32_t
am_hal_wdt_restart(am_hal_wdt_select_e eTimer)296 am_hal_wdt_restart(am_hal_wdt_select_e eTimer)
297 {
298     switch (eTimer)
299     {
300         case AM_HAL_WDT_MCU:
301             WDT->RSTRT = WDT_RSTRT_RSTRT_KEYVALUE;
302             break;
303 
304         case AM_HAL_WDT_DSP0:
305             WDT->DSP0RSTRT = WDT_DSP0RSTRT_DSP0RSTART_KEYVALUE;
306             break;
307 
308         case AM_HAL_WDT_DSP1:
309             WDT->DSP1RSTRT = WDT_DSP1RSTRT_DSP1RSTART_KEYVALUE;
310             break;
311 
312         default:
313             return AM_HAL_STATUS_FAIL;
314     }
315 
316     return AM_HAL_STATUS_SUCCESS;
317 }
318 
319 //*****************************************************************************
320 //
321 // Reads the watchdog timer's current value.
322 //
323 //*****************************************************************************
324 uint32_t
am_hal_wdt_read(am_hal_wdt_select_e eTimer,uint32_t * ui32Value)325 am_hal_wdt_read(am_hal_wdt_select_e eTimer, uint32_t *ui32Value)
326 {
327     switch (eTimer)
328     {
329         case AM_HAL_WDT_MCU:
330             *ui32Value = WDT->COUNT;
331             break;
332 
333         case AM_HAL_WDT_DSP0:
334             *ui32Value = WDT->DSP0COUNT;
335             break;
336 
337         case AM_HAL_WDT_DSP1:
338             *ui32Value = WDT->DSP1COUNT;
339             break;
340 
341         default:
342             return AM_HAL_STATUS_FAIL;
343     }
344 
345     return AM_HAL_STATUS_SUCCESS;
346 }
347 
348 //*****************************************************************************
349 //
350 // Watchdog interrupt enable.
351 //
352 //*****************************************************************************
353 uint32_t
am_hal_wdt_interrupt_enable(am_hal_wdt_select_e eTimer,uint32_t ui32InterruptMask)354 am_hal_wdt_interrupt_enable(am_hal_wdt_select_e eTimer,
355                             uint32_t ui32InterruptMask)
356 {
357     switch (eTimer)
358     {
359         case AM_HAL_WDT_MCU:
360             WDT->WDTIEREN |= ui32InterruptMask;
361             break;
362 
363         case AM_HAL_WDT_DSP0:
364             WDT->DSP0IEREN |= ui32InterruptMask;
365             break;
366 
367         case AM_HAL_WDT_DSP1:
368             WDT->DSP1IEREN |= ui32InterruptMask;
369             break;
370 
371         default:
372             return AM_HAL_STATUS_FAIL;
373     }
374 
375     return AM_HAL_STATUS_SUCCESS;
376 }
377 
378 //*****************************************************************************
379 //
380 // Check to see which WDT interrupts are enabled.
381 //
382 //*****************************************************************************
383 uint32_t
am_hal_wdt_interrupt_enable_get(am_hal_wdt_select_e eTimer,uint32_t * pui32InterruptMask)384 am_hal_wdt_interrupt_enable_get(am_hal_wdt_select_e eTimer,
385                                 uint32_t *pui32InterruptMask)
386 {
387     switch (eTimer)
388     {
389         case AM_HAL_WDT_MCU:
390             *pui32InterruptMask = WDT->WDTIEREN;
391             break;
392 
393         case AM_HAL_WDT_DSP0:
394             *pui32InterruptMask = WDT->DSP0IEREN;
395             break;
396 
397         case AM_HAL_WDT_DSP1:
398             *pui32InterruptMask = WDT->DSP1IEREN;
399             break;
400 
401         default:
402             return AM_HAL_STATUS_FAIL;
403     }
404 
405     return AM_HAL_STATUS_SUCCESS;
406 }
407 
408 //*****************************************************************************
409 //
410 // Disable a WDT interrupt.
411 //
412 //*****************************************************************************
413 uint32_t
am_hal_wdt_interrupt_disable(am_hal_wdt_select_e eTimer,uint32_t ui32InterruptMask)414 am_hal_wdt_interrupt_disable(am_hal_wdt_select_e eTimer,
415                              uint32_t ui32InterruptMask)
416 {
417     switch (eTimer)
418     {
419         case AM_HAL_WDT_MCU:
420             WDT->WDTIEREN &= ~ui32InterruptMask;
421             break;
422 
423         case AM_HAL_WDT_DSP0:
424             WDT->DSP0IEREN &= ~ui32InterruptMask;
425             break;
426 
427         case AM_HAL_WDT_DSP1:
428             WDT->DSP1IEREN &= ~ui32InterruptMask;
429             break;
430 
431         default:
432             return AM_HAL_STATUS_FAIL;
433     }
434 
435     return AM_HAL_STATUS_SUCCESS;
436 }
437 
438 //*****************************************************************************
439 //
440 // Read the WDT interrupt status.
441 //
442 //*****************************************************************************
443 uint32_t
am_hal_wdt_interrupt_status_get(am_hal_wdt_select_e eTimer,uint32_t * pui32InterruptMask,bool bEnabledOnly)444 am_hal_wdt_interrupt_status_get(am_hal_wdt_select_e eTimer,
445                                 uint32_t *pui32InterruptMask,
446                                 bool bEnabledOnly)
447 {
448     uint32_t ui32Status;
449 
450     if (bEnabledOnly)
451     {
452         switch (eTimer)
453         {
454             case AM_HAL_WDT_MCU:
455                 ui32Status = WDT->WDTIERSTAT;
456                 ui32Status &= WDT->WDTIEREN;
457                 break;
458 
459             case AM_HAL_WDT_DSP0:
460                 ui32Status = WDT->DSP0IERSTAT;
461                 ui32Status &= WDT->DSP0IEREN;
462                 break;
463 
464             case AM_HAL_WDT_DSP1:
465                 ui32Status = WDT->DSP1IERSTAT;
466                 ui32Status &= WDT->DSP1IEREN;
467                 break;
468 
469             default:
470                 return AM_HAL_STATUS_FAIL;
471         }
472 
473         *pui32InterruptMask = ui32Status;
474     }
475     else
476     {
477         switch (eTimer)
478         {
479             case AM_HAL_WDT_MCU:
480                 *pui32InterruptMask = WDT->WDTIERSTAT;
481                 break;
482 
483             case AM_HAL_WDT_DSP0:
484                 *pui32InterruptMask = WDT->DSP0IERSTAT;
485                 break;
486 
487             case AM_HAL_WDT_DSP1:
488                 *pui32InterruptMask = WDT->DSP1IERSTAT;
489                 break;
490 
491             default:
492                 return AM_HAL_STATUS_FAIL;
493         }
494     }
495 
496     return AM_HAL_STATUS_SUCCESS;
497 }
498 
499 //*****************************************************************************
500 //
501 // Clears the WDT interrupt.
502 //
503 //*****************************************************************************
504 uint32_t
am_hal_wdt_interrupt_clear(am_hal_wdt_select_e eTimer,uint32_t ui32InterruptMask)505 am_hal_wdt_interrupt_clear(am_hal_wdt_select_e eTimer,
506                            uint32_t ui32InterruptMask)
507 {
508     switch (eTimer)
509     {
510         case AM_HAL_WDT_MCU:
511             WDT->WDTIERCLR = ui32InterruptMask;
512             break;
513 
514         case AM_HAL_WDT_DSP0:
515             WDT->DSP0IERCLR = ui32InterruptMask;
516             break;
517 
518         case AM_HAL_WDT_DSP1:
519             WDT->DSP1IERCLR = ui32InterruptMask;
520             break;
521 
522         default:
523             return AM_HAL_STATUS_FAIL;
524     }
525 
526     return AM_HAL_STATUS_SUCCESS;
527 }
528 
529 //*****************************************************************************
530 //
531 // Sets a WDT interrupt.
532 //
533 //*****************************************************************************
534 uint32_t
am_hal_wdt_interrupt_set(am_hal_wdt_select_e eTimer,uint32_t ui32InterruptMask)535 am_hal_wdt_interrupt_set(am_hal_wdt_select_e eTimer,
536                          uint32_t ui32InterruptMask)
537 {
538     switch (eTimer)
539     {
540         case AM_HAL_WDT_MCU:
541             WDT->WDTIERSET = ui32InterruptMask;
542             break;
543 
544         case AM_HAL_WDT_DSP0:
545             WDT->DSP0IERSET = ui32InterruptMask;
546             break;
547 
548         case AM_HAL_WDT_DSP1:
549             WDT->DSP1IERSET = ui32InterruptMask;
550             break;
551 
552         default:
553             return AM_HAL_STATUS_FAIL;
554     }
555     return AM_HAL_STATUS_SUCCESS;
556 }
557 
558 //*****************************************************************************
559 //
560 // End Doxygen group.
561 //! @}
562 //
563 //*****************************************************************************
564