1 /*! *********************************************************************************
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2018-2022 NXP
4 * All rights reserved.
5 *
6 * \file
7 *
8 * SPDX-License-Identifier: BSD-3-Clause
9 ********************************************************************************** */
10 
11 #include "Phy.h"
12 #include "PhyTime.h"
13 #include "EmbeddedTypes.h"
14 
15 #include "fsl_os_abstraction.h"
16 #include "fsl_device_registers.h"
17 
18 #define gPhyTimeMinSetupTime_c (4) /* symbols */
19 
20 static phyTimeEvent_t  maPhyTimers[gMaxPhyTimers_c];
21 static phyTimeEvent_t *pNextEvent;
22 volatile uint64_t      gPhyTimerOverflow;
23 static uint8_t         mPhyActiveTimers;
24 static bool            bTimerInitDone = false;
25 static void (*gpfPhyTimeNotify)(void) = NULL;
26 
27 static void PhyTime_OverflowCB(uint32_t param);
28 static phyTimeEvent_t *PhyTime_GetNextEvent(void);
29 
30 
PhyTimeGetEventTimeout(void)31 phyTime_t PhyTimeGetEventTimeout(void)
32 {
33     return ZLL->T3CMP;
34 }
35 
PhyTime_ReadClock()36 phyTime_t PhyTime_ReadClock()
37 {
38     return (phyTime_t)(ZLL->EVENT_TMR >> ZLL_EVENT_TMR_EVENT_TMR_SHIFT);
39 }
40 
PhyTime_ISR(void)41 void PhyTime_ISR(void)
42 {
43     if (pNextEvent->callback == PhyTime_OverflowCB)
44     {
45         gPhyTimerOverflow += (uint64_t)(1 << gPhyTimeShift_c);
46     }
47 
48     if (gpfPhyTimeNotify)
49     {
50         gpfPhyTimeNotify();
51     }
52     else
53     {
54         PhyTime_RunCallback();
55         PhyTime_Maintenance();
56     }
57 }
58 
PhyTime_TimerInit(void (* cb)(void))59 phyTimeStatus_t PhyTime_TimerInit(void (*cb)(void))
60 {
61     // Check whether timer has already been initialised
62     if (bTimerInitDone == true)
63     {
64 		return gPhyTimeError_c;
65     }
66 
67     gpfPhyTimeNotify = cb;
68     gPhyTimerOverflow = 0;
69     memset(maPhyTimers, 0, sizeof(maPhyTimers));
70 
71     /* Schedule Overflow Calback */
72     pNextEvent = &maPhyTimers[0];
73     pNextEvent->callback = PhyTime_OverflowCB;
74     pNextEvent->timestamp = (uint64_t)(1 << gPhyTimeShift_c);
75     PhyTimeSetWaitTimeout(pNextEvent->timestamp);
76     mPhyActiveTimers = 1;
77 
78     // indicate that phytimer layer is initialized
79     bTimerInitDone = true;
80 
81     return gPhyTimeOk_c;
82 }
83 
PhyTime_TimerDeinit(void)84 void PhyTime_TimerDeinit ( void )
85 {
86     bTimerInitDone = false;
87     gpfPhyTimeNotify = NULL;
88 }
89 
PhyTime_GetTimestamp(void)90 phyTime_t PhyTime_GetTimestamp(void)
91 {
92     phyTime_t t;
93 
94     OSA_InterruptDisable();
95     t = PhyTime_ReadClock();
96     t |= gPhyTimerOverflow;
97     /* Check for overflow */
98     if(pNextEvent != NULL)
99     {
100         if (pNextEvent->callback == PhyTime_OverflowCB)
101         {
102             if (ZLL->IRQSTS & ZLL_IRQSTS_TMR1IRQ_MASK)
103             {
104                 t = PhyTime_ReadClock();
105                 t |= gPhyTimerOverflow;
106                 t += (1 << gPhyTimeShift_c);
107             }
108         }
109     }
110     OSA_InterruptEnable();
111 
112     return t;
113 }
114 
PhyTime_ScheduleEvent(phyTimeEvent_t * pEvent)115 phyTimeTimerId_t PhyTime_ScheduleEvent(phyTimeEvent_t *pEvent)
116 {
117     phyTimeTimerId_t tmr;
118 
119     if (NULL == pEvent->callback)
120     {
121         return gInvalidTimerId_c;
122     }
123 
124     /* Search for a free slot (slot 0 is reserved for the Overflow calback) */
125     OSA_InterruptDisable();
126     for (tmr = 1; tmr < gMaxPhyTimers_c; tmr++)
127     {
128         if (maPhyTimers[tmr].callback == NULL)
129         {
130             if (mPhyActiveTimers == 1)
131             {
132                 /* PHY_disallow_sleep(); */
133             }
134 
135             mPhyActiveTimers++;
136             maPhyTimers[tmr] = *pEvent;
137             break;
138         }
139     }
140     OSA_InterruptEnable();
141 
142     if (tmr >= gMaxPhyTimers_c)
143     {
144         return gInvalidTimerId_c;
145     }
146 
147     /* Program the next event */
148     if ((NULL == pNextEvent) || ((NULL != pNextEvent) && (maPhyTimers[tmr].timestamp < pNextEvent->timestamp)))
149     {
150         PhyTime_Maintenance();
151     }
152 
153     return tmr;
154 }
155 
PhyTime_CancelEvent(phyTimeTimerId_t timerId)156 phyTimeStatus_t PhyTime_CancelEvent(phyTimeTimerId_t timerId)
157 {
158     if ((timerId == 0) || (timerId >= gMaxPhyTimers_c) || (NULL == maPhyTimers[timerId].callback))
159     {
160         return gPhyTimeNotFound_c;
161     }
162 
163     OSA_InterruptDisable();
164     if (pNextEvent == &maPhyTimers[timerId])
165     {
166         pNextEvent = NULL;
167     }
168 
169     maPhyTimers[timerId].callback = NULL;
170     mPhyActiveTimers--;
171 
172     if (mPhyActiveTimers == 1)
173     {
174         /* PHY_allow_sleep(); */
175     }
176 
177     OSA_InterruptEnable();
178 
179     return gPhyTimeOk_c;
180 }
181 
PhyTime_CancelEventsWithParam(uint32_t param)182 phyTimeStatus_t PhyTime_CancelEventsWithParam(uint32_t param)
183 {
184     uint32_t i;
185     phyTimeStatus_t status = gPhyTimeNotFound_c;
186 
187     OSA_InterruptDisable();
188     for (i = 1; i < gMaxPhyTimers_c; i++)
189     {
190         if ((NULL != maPhyTimers[i].callback) && (param == maPhyTimers[i].parameter))
191         {
192             status = gPhyTimeOk_c;
193             maPhyTimers[i].callback = NULL;
194             mPhyActiveTimers--;
195 
196             if (pNextEvent == &maPhyTimers[i])
197             {
198                 pNextEvent = NULL;
199             }
200         }
201     }
202 
203     if (mPhyActiveTimers == 1)
204     {
205         /* PHY_allow_sleep(); */
206     }
207     OSA_InterruptEnable();
208 
209     return status;
210 }
211 
PhyTime_RunCallback(void)212 void PhyTime_RunCallback(void)
213 {
214 /* for V18 compiler, variable need be given initial value */
215     uint32_t param =0;
216     phyTimeCallback_t cb = NULL;
217 
218     OSA_InterruptDisable();
219 
220     if (pNextEvent)
221     {
222         param = pNextEvent->parameter;
223         cb = pNextEvent->callback;
224         pNextEvent->callback = NULL;
225         pNextEvent = NULL;
226         mPhyActiveTimers--;
227 
228         if (mPhyActiveTimers == 1)
229         {
230             /* PHY_allow_sleep(); */
231         }
232     }
233 
234     OSA_InterruptEnable();
235 
236     if (cb)
237     {
238         cb(param);
239     }
240 }
241 
PhyTime_Maintenance(void)242 void PhyTime_Maintenance(void)
243 {
244     phyTime_t currentTime;
245     phyTimeEvent_t *pEv;
246 
247     PhyTimeDisableWaitTimeout();
248 
249     while (1)
250     {
251         OSA_InterruptDisable();
252 
253         pEv = PhyTime_GetNextEvent();
254         currentTime = PhyTime_GetTimestamp();
255 
256         /* Program next event if exists */
257         if (pEv)
258         {
259             pNextEvent = pEv;
260 
261             if (pEv->timestamp > (currentTime + gPhyTimeMinSetupTime_c))
262             {
263                 PhyTimeSetWaitTimeout(pEv->timestamp);
264                 pEv = NULL;
265             }
266         }
267 
268         OSA_InterruptEnable();
269 
270         if (!pEv)
271         {
272             break;
273         }
274 
275         PhyTime_RunCallback();
276     }
277 }
278 
PhyTime_OverflowCB(uint32_t param)279 static void PhyTime_OverflowCB(uint32_t param)
280 {
281     param = param;
282 
283     /* Reprogram the next overflow callback */
284     OSA_InterruptDisable();
285     mPhyActiveTimers++;
286     maPhyTimers[0].callback = PhyTime_OverflowCB;
287     maPhyTimers[0].timestamp = gPhyTimerOverflow + (1 << gPhyTimeShift_c);
288     OSA_InterruptEnable();
289 }
290 
PhyTime_GetNextEvent(void)291 static phyTimeEvent_t *PhyTime_GetNextEvent(void)
292 {
293     phyTimeEvent_t *pEv = NULL;
294     uint32_t i;
295 
296     /* Search for the next event to be serviced */
297     for (i = 0; i < gMaxPhyTimers_c; i++)
298     {
299         if (NULL != maPhyTimers[i].callback)
300         {
301             if (NULL == pEv)
302             {
303                 pEv = &maPhyTimers[i];
304             }
305             /* Check which event expires first */
306             else
307             {
308                 if (maPhyTimers[i].timestamp < pEv->timestamp)
309                 {
310                     pEv = &maPhyTimers[i];
311                 }
312             }
313         }
314     }
315 
316     return pEv;
317 }
318 
PhyTime_can_sleep()319 bool_t PhyTime_can_sleep()
320 {
321     return (mPhyActiveTimers == 1);
322 }
323