1 /*
2  * Copyright (c) 2015-2018, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <stdint.h>
34 #include <stdlib.h>
35 
36 #include <ti/drivers/dpl/HwiP.h>
37 #include <ti/drivers/dpl/ClockP.h>
38 
39 #include <ti/drivers/Power.h>
40 #include <ti/drivers/power/PowerCC32XX.h>
41 
42 #include <ti/drivers/watchdog/WatchdogCC32XX.h>
43 
44 #include <ti/devices/cc32xx/inc/hw_types.h>
45 #include <ti/devices/cc32xx/driverlib/rom.h>
46 #include <ti/devices/cc32xx/driverlib/rom_map.h>
47 #include <ti/devices/cc32xx/driverlib/wdt.h>
48 
49 /* Function prototypes */
50 void WatchdogCC32XX_clear(Watchdog_Handle handle);
51 void WatchdogCC32XX_close(Watchdog_Handle handle);
52 int_fast16_t WatchdogCC32XX_control(Watchdog_Handle handle,
53     uint_fast16_t cmd, void *arg);
54 void WatchdogCC32XX_init(Watchdog_Handle handle);
55 Watchdog_Handle WatchdogCC32XX_open(Watchdog_Handle handle, Watchdog_Params *params);
56 int_fast16_t WatchdogCC32XX_setReload(Watchdog_Handle handle,
57     uint32_t value);
58 uint32_t WatchdogCC32XX_convertMsToTicks(Watchdog_Handle handle,
59     uint32_t milliseconds);
60 
61 /* Internal functions */
62 static void WatchdogCC32XX_initHardware(Watchdog_Handle handle);
63 static int WatchdogCC32XX_postNotifyFxn(unsigned int eventType,
64     uintptr_t eventArg, uintptr_t clientArg);
65 
66 /* Watchdog function table for CC32XX implementation */
67 const Watchdog_FxnTable WatchdogCC32XX_fxnTable = {
68     WatchdogCC32XX_clear,
69     WatchdogCC32XX_close,
70     WatchdogCC32XX_control,
71     WatchdogCC32XX_init,
72     WatchdogCC32XX_open,
73     WatchdogCC32XX_setReload,
74     WatchdogCC32XX_convertMsToTicks
75 };
76 
77 /* Maximum allowable setReload value */
78 #define MAX_RELOAD_VALUE        0xFFFFFFFF
79 
80 /* Millisecond to second ratio */
81 #define MS_RATIO                1000
82 
83 /*
84  *  ======== WatchdogCC32XX_initHardware ========
85  */
WatchdogCC32XX_initHardware(Watchdog_Handle handle)86 static void WatchdogCC32XX_initHardware(Watchdog_Handle handle)
87 {
88     WatchdogCC32XX_HWAttrs const *hwAttrs = handle->hwAttrs;
89     WatchdogCC32XX_Object  const *object  = handle->object;
90 
91     MAP_WatchdogUnlock(hwAttrs->baseAddr);
92     MAP_WatchdogReloadSet(hwAttrs->baseAddr, object->reloadValue);
93     MAP_WatchdogIntClear(hwAttrs->baseAddr);
94 
95     /* Set debug stall mode */
96     if (object->debugMode == Watchdog_DEBUG_STALL_ON) {
97         MAP_WatchdogStallEnable(hwAttrs->baseAddr);
98     }
99     else {
100         MAP_WatchdogStallDisable(hwAttrs->baseAddr);
101     }
102 
103     MAP_WatchdogEnable(hwAttrs->baseAddr);
104 
105     MAP_WatchdogLock(hwAttrs->baseAddr);
106 }
107 
108 /*
109  *  ======== WatchdogCC32XX_postNotifyFxn ========
110  *  This functions is called when a transition from LPDS mode is made.
111  *  clientArg is a handle of a previously opened Watchdog instance.
112  */
WatchdogCC32XX_postNotifyFxn(unsigned int eventType,uintptr_t eventArg,uintptr_t clientArg)113 static int WatchdogCC32XX_postNotifyFxn(unsigned int eventType,
114     uintptr_t eventArg, uintptr_t clientArg)
115 {
116     WatchdogCC32XX_initHardware((Watchdog_Handle) clientArg);
117 
118     return (Power_NOTIFYDONE);
119 }
120 
121 /*
122  *  ======== WatchdogCC32XX_clear ========
123  */
WatchdogCC32XX_clear(Watchdog_Handle handle)124 void WatchdogCC32XX_clear(Watchdog_Handle handle)
125 {
126     WatchdogCC32XX_HWAttrs const *hwAttrs = handle->hwAttrs;
127 
128     MAP_WatchdogIntClear(hwAttrs->baseAddr);
129 }
130 
131 /*
132  *  ======== WatchdogCC32XX_close ========
133  */
WatchdogCC32XX_close(Watchdog_Handle handle)134 void WatchdogCC32XX_close(Watchdog_Handle handle)
135 {
136     /*
137      *  Not supported for CC32XX - Once the INTEN bit of the WDTCTL
138      *  register has been set, it can only be cleared by a hardware
139      *  reset.
140      */
141 }
142 
143 /*
144  *  ======== WatchdogCC32XX_control ========
145  *  @pre    Function assumes that the handle is not NULL
146  */
WatchdogCC32XX_control(Watchdog_Handle handle,uint_fast16_t cmd,void * arg)147 int_fast16_t WatchdogCC32XX_control(Watchdog_Handle handle, uint_fast16_t cmd,
148         void *arg)
149 {
150     WatchdogCC32XX_HWAttrs const *hwAttrs = handle->hwAttrs;
151 
152     switch (cmd) {
153         /* Specific Watchdog CMDs */
154         case (WatchdogCC32XX_CMD_IS_TIMER_ENABLE):
155             *(bool *)arg = MAP_WatchdogRunning(hwAttrs->baseAddr);
156             return (Watchdog_STATUS_SUCCESS);
157 
158         case (WatchdogCC32XX_CMD_GET_TIMER_VALUE):
159             *(uint32_t *)arg = MAP_WatchdogValueGet(hwAttrs->baseAddr);
160             return (Watchdog_STATUS_SUCCESS);
161 
162         case (WatchdogCC32XX_CMD_IS_TIMER_LOCKED):
163             *(bool *)arg = MAP_WatchdogLockState(hwAttrs->baseAddr);
164             return (Watchdog_STATUS_SUCCESS);
165 
166         case (WatchdogCC32XX_CMD_GET_TIMER_RELOAD_VALUE):
167             *(uint32_t *)arg = MAP_WatchdogReloadGet(hwAttrs->baseAddr);
168             return (Watchdog_STATUS_SUCCESS);
169 
170         default:
171             return (Watchdog_STATUS_UNDEFINEDCMD);
172     }
173 }
174 
175 /*
176  *  ======== WatchdogCC32XX_init ========
177  */
WatchdogCC32XX_init(Watchdog_Handle handle)178 void WatchdogCC32XX_init(Watchdog_Handle handle)
179 {
180     WatchdogCC32XX_Object *object = handle->object;
181 
182     object->isOpen = false;
183 }
184 
185 /*
186  *  ======== WatchdogCC32XX_open ========
187  */
WatchdogCC32XX_open(Watchdog_Handle handle,Watchdog_Params * params)188 Watchdog_Handle WatchdogCC32XX_open(Watchdog_Handle handle, Watchdog_Params *params)
189 {
190     uintptr_t                     key;
191     HwiP_Handle                   hwiHandle;
192     HwiP_Params                   hwiParams;
193     WatchdogCC32XX_HWAttrs const *hwAttrs = handle->hwAttrs;
194     WatchdogCC32XX_Object        *object  = handle->object;
195 
196     key = HwiP_disable();
197 
198     if (object->isOpen == true) {
199         HwiP_restore(key);
200         return (NULL);
201     }
202 
203     object->isOpen = true;
204     HwiP_restore(key);
205 
206     /* Register the hardware interrupt for this watchdog */
207     if (params->callbackFxn) {
208         HwiP_Params_init(&hwiParams);
209         hwiParams.arg = (uintptr_t) handle;
210         hwiParams.priority = hwAttrs->intPriority;
211         hwiHandle = HwiP_create(hwAttrs->intNum, params->callbackFxn,
212             &hwiParams);
213         if (hwiHandle == NULL) {
214             object->isOpen = false;
215             return (NULL);
216         }
217     }
218 
219     Power_setDependency(PowerCC32XX_PERIPH_WDT);
220     Power_registerNotify(&(object->notifyObj), PowerCC32XX_AWAKE_LPDS,
221         WatchdogCC32XX_postNotifyFxn, (uintptr_t) handle);
222 
223     object->debugMode = params->debugStallMode;
224     object->reloadValue = hwAttrs->reloadValue;
225 
226     WatchdogCC32XX_initHardware(handle);
227 
228     return (handle);
229 }
230 
231 /*
232  *  ======== WatchdogCC32XX_setReload ========
233  */
WatchdogCC32XX_setReload(Watchdog_Handle handle,uint32_t value)234 int_fast16_t WatchdogCC32XX_setReload(Watchdog_Handle handle, uint32_t value)
235 {
236     WatchdogCC32XX_HWAttrs const *hwAttrs = handle->hwAttrs;
237     WatchdogCC32XX_Object        *object  = handle->object;
238 
239     /* Set value */
240     MAP_WatchdogUnlock(hwAttrs->baseAddr);
241     MAP_WatchdogReloadSet(hwAttrs->baseAddr, value);
242     MAP_WatchdogLock(hwAttrs->baseAddr);
243     object->reloadValue = value;
244 
245     return (Watchdog_STATUS_SUCCESS);
246 }
247 
248 /*
249  *  ======== WatchdogCC32XX_convertMsToTicks ========
250  *  This function converts the input value from milliseconds to
251  *  Watchdog clock ticks.
252  */
WatchdogCC32XX_convertMsToTicks(Watchdog_Handle handle,uint32_t milliseconds)253 uint32_t WatchdogCC32XX_convertMsToTicks(Watchdog_Handle handle,
254     uint32_t milliseconds)
255 {
256     uint32_t        tickValue;
257     uint32_t        convertRatio;
258     uint32_t        maxConvertMs;
259     ClockP_FreqHz   freq;
260 
261     /* Determine milliseconds to clock ticks conversion ratio */
262     ClockP_getCpuFreq(&freq);
263 
264     /* Watchdog clock ticks/ms = CPU clock / MS_RATIO */
265     convertRatio = freq.lo / MS_RATIO;
266     maxConvertMs = MAX_RELOAD_VALUE / convertRatio;
267 
268     /* Convert milliseconds to watchdog timer ticks */
269     /* Check if value exceeds maximum */
270     if (milliseconds > maxConvertMs) {
271         tickValue = 0;  /* Return zero to indicate overflow */
272     }
273     else {
274         tickValue = (uint32_t)(milliseconds * convertRatio);
275     }
276 
277     return(tickValue);
278 }
279