1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <cpu/cpuMath.h>
18 #include <plat/gpio.h>
19 #include <plat/usart.h>
20 #include <plat/cmsis.h>
21 #include <plat/pwr.h>
22 #include <plat/rtc.h>
23 #include <plat/plat.h>
24 #include <plat/exti.h>
25 #include <plat/wdt.h>
26 #include <plat/dma.h>
27 #include <stdbool.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <pthread.h>
31 #include <unistd.h>
32 #include <platform.h>
33 #include <seos.h>
34 #include <heap.h>
35 #include <timer.h>
36 #include <usart.h>
37 #include <gpio.h>
38 #include <mpu.h>
39 #include <cpu.h>
40 #include <hostIntf.h>
41 #include <atomic.h>
42 #include <hostIntf.h>
43 #include <nanohubPacket.h>
44 #include <sensType.h>
45 #include <variant/variant.h>
46 
47 
48 struct StmDbg {
49     volatile uint32_t IDCODE;
50     volatile uint32_t CR;
51     volatile uint32_t APB1FZ;
52     volatile uint32_t APB2FZ;
53 };
54 
55 struct StmTim {
56 
57     volatile uint16_t CR1;
58     uint8_t unused0[2];
59     volatile uint16_t CR2;
60     uint8_t unused1[2];
61     volatile uint16_t SMCR;
62     uint8_t unused2[2];
63     volatile uint16_t DIER;
64     uint8_t unused3[2];
65     volatile uint16_t SR;
66     uint8_t unused4[2];
67     volatile uint16_t EGR;
68     uint8_t unused5[2];
69     volatile uint16_t CCMR1;
70     uint8_t unused6[2];
71     volatile uint16_t CCMR2;
72     uint8_t unused7[2];
73     volatile uint16_t CCER;
74     uint8_t unused8[2];
75     volatile uint32_t CNT;
76     volatile uint16_t PSC;
77     uint8_t unused9[2];
78     volatile uint32_t ARR;
79     volatile uint16_t RCR;
80     uint8_t unused10[2];
81     volatile uint32_t CCR1;
82     volatile uint32_t CCR2;
83     volatile uint32_t CCR3;
84     volatile uint32_t CCR4;
85     volatile uint16_t BDTR;
86     uint8_t unused11[2];
87     volatile uint16_t DCR;
88     uint8_t unused12[2];
89     volatile uint16_t DMAR;
90     uint8_t unused13[2];
91     volatile uint16_t OR;
92     uint8_t unused14[2];
93 };
94 
95 /* RTC bit defintions */
96 #define TIM_EGR_UG          0x0001
97 
98 
99 #ifdef DEBUG_UART_UNITNO
100 static struct usart mDbgUart;
101 #endif
102 
103 #ifdef DEBUG_LOG_EVT
104 #ifndef EARLY_LOG_BUF_SIZE
105 #define EARLY_LOG_BUF_SIZE      1024
106 #endif
107 #define HOSTINTF_HEADER_SIZE    4
108 uint8_t *mEarlyLogBuffer;
109 uint16_t mEarlyLogBufferCnt;
110 uint16_t mEarlyLogBufferOffset;
111 bool mLateBoot;
112 #endif
113 
114 static uint64_t mTimeAccumulated = 0;
115 static uint32_t mMaxJitterPpm = 0, mMaxDriftPpm = 0, mMaxErrTotalPpm = 0;
116 static uint32_t mSleepDevsToKeepAlive = 0;
117 static uint64_t mWakeupTime = 0;
118 static uint32_t mDevsMaxWakeTime[PLAT_MAX_SLEEP_DEVS] = {0,};
119 
platUninitialize(void)120 void platUninitialize(void)
121 {
122 #ifdef DEBUG_UART_UNITNO
123     usartClose(&mDbgUart);
124 #endif
125 }
126 
platLogAllocUserData()127 void *platLogAllocUserData()
128 {
129 #if defined(DEBUG_LOG_EVT)
130     struct HostIntfDataBuffer *userData = NULL;
131 
132     if (mLateBoot) {
133         userData = heapAlloc(sizeof(struct HostIntfDataBuffer));
134     } else if (mEarlyLogBufferOffset < EARLY_LOG_BUF_SIZE - HOSTINTF_HEADER_SIZE) {
135         userData = (struct HostIntfDataBuffer *)(mEarlyLogBuffer + mEarlyLogBufferOffset);
136         mEarlyLogBufferOffset += HOSTINTF_HEADER_SIZE;
137     }
138     if (userData) {
139         userData->sensType = SENS_TYPE_INVALID;
140         userData->length = 0;
141         userData->dataType = HOSTINTF_DATA_TYPE_LOG;
142         userData->interrupt = NANOHUB_INT_NONWAKEUP;
143     }
144     return userData;
145 #else
146     return NULL;
147 #endif
148 }
149 
150 #if defined(DEBUG_LOG_EVT)
platEarlyLogFree(void * buf)151 static void platEarlyLogFree(void *buf)
152 {
153     struct HostIntfDataBuffer *userData = (struct HostIntfDataBuffer *)buf;
154     mEarlyLogBufferCnt += userData->length + HOSTINTF_HEADER_SIZE;
155     if (mEarlyLogBufferCnt >= mEarlyLogBufferOffset) {
156         heapFree(mEarlyLogBuffer);
157     }
158 }
159 #endif
160 
platEarlyLogFlush(void)161 void platEarlyLogFlush(void)
162 {
163 #if defined(DEBUG_LOG_EVT)
164     uint16_t i = 0;
165     struct HostIntfDataBuffer *userData;
166 
167     mLateBoot = true;
168 
169     while (i < mEarlyLogBufferOffset) {
170         userData = (struct HostIntfDataBuffer *)(mEarlyLogBuffer + i);
171         osEnqueueEvt(EVENT_TYPE_BIT_DISCARDABLE | EVT_DEBUG_LOG, userData, platEarlyLogFree);
172         i += HOSTINTF_HEADER_SIZE + userData->length;
173     }
174 #endif
175 }
176 
platLogFlush(void * userData)177 void platLogFlush(void *userData)
178 {
179 #if defined(DEBUG_LOG_EVT)
180     if (userData && mLateBoot)
181         osEnqueueEvtOrFree(EVENT_TYPE_BIT_DISCARDABLE | EVT_DEBUG_LOG, userData, heapFree);
182 #endif
183 }
184 
platLogPutcharF(void * userData,char ch)185 bool platLogPutcharF(void *userData, char ch)
186 {
187 #if defined(DEBUG) && defined(DEBUG_UART_PIN)
188     if (ch == '\n')
189         gpioBitbangedUartOut('\r');
190     gpioBitbangedUartOut(ch);
191 #endif
192 #if defined(DEBUG_UART_UNITNO)
193     usartPutchar(&mDbgUart, ch);
194 #endif
195 #if defined(DEBUG_LOG_EVT)
196     struct HostIntfDataBuffer *buffer;
197 
198     if (userData) {
199         buffer = userData;
200         size_t maxSize = sizeof(buffer->buffer);
201 
202         // if doing early logging, and early log buffer is full, ignore the rest of early output
203         if (!mLateBoot && mEarlyLogBufferOffset >= EARLY_LOG_BUF_SIZE && buffer->length < maxSize)
204             maxSize = buffer->length;
205 
206         if (buffer->length < maxSize) {
207             buffer->buffer[buffer->length++] = ch;
208             if (!mLateBoot)
209                 mEarlyLogBufferOffset++;
210         } else {
211             buffer->buffer[maxSize - 1] = '\n';
212             return false;
213         }
214     }
215 #endif
216     return true;
217 }
218 
platInitialize(void)219 void platInitialize(void)
220 {
221     const uint32_t debugStateInSleepMode = 0x00000007; /* debug in all modes */
222     struct StmTim *tim = (struct StmTim*)TIM2_BASE;
223     struct StmDbg *dbg = (struct StmDbg*)DBG_BASE;
224     uint32_t i;
225 
226     pwrSystemInit();
227 
228     //prepare for sleep mode(s)
229     SCB->SCR &=~ SCB_SCR_SLEEPONEXIT_Msk;
230 
231     //set ints up for a sane state
232     //3 bits preemptPriority, 1 bit subPriority
233     NVIC_SetPriorityGrouping(4);
234     for (i = 0; i < NUM_INTERRUPTS; i++) {
235         NVIC_SetPriority(i, NVIC_EncodePriority(4, 2, 1));
236         NVIC_DisableIRQ(i);
237         NVIC_ClearPendingIRQ(i);
238     }
239 
240     /* disable pins */
241     for (i = 0; i < 16; i++) {
242 #if defined(DEBUG) && defined(DEBUG_SWD)
243         /* pins PA13 and PA14 are used for SWD */
244         if ((i != 13) && (i != 14))
245             gpioConfigAnalog(gpioRequest(GPIO_PA(i)));
246 #else
247         gpioConfigAnalog(gpioRequest(GPIO_PA(i)));
248 #endif
249         gpioConfigAnalog(gpioRequest(GPIO_PB(i)));
250         gpioConfigAnalog(gpioRequest(GPIO_PC(i)));
251         gpioConfigAnalog(gpioRequest(GPIO_PD(i)));
252         gpioConfigAnalog(gpioRequest(GPIO_PE(i)));
253         gpioConfigAnalog(gpioRequest(GPIO_PH(i)));
254     }
255 
256 #ifdef DEBUG_UART_UNITNO
257     /* Open mDbgUart on PA2 and PA3 */
258     usartOpen(&mDbgUart, DEBUG_UART_UNITNO, DEBUG_UART_GPIO_TX, DEBUG_UART_GPIO_RX,
259                115200, USART_DATA_BITS_8,
260                USART_STOP_BITS_1_0, USART_PARITY_NONE,
261                USART_FLOW_CONTROL_NONE);
262 #endif
263 
264     /* set up debugging */
265 #if defined(DEBUG) && defined(DEBUG_SWD)
266     dbg->CR |= debugStateInSleepMode;
267 #else
268     dbg->CR &=~ debugStateInSleepMode;
269 #endif
270 
271     /* enable MPU */
272     mpuStart();
273 
274     /* set up timer used for alarms */
275     pwrUnitClock(PERIPH_BUS_APB1, PERIPH_APB1_TIM2, true);
276     tim->CR1 = (tim->CR1 &~ 0x03E1) | 0x0010; //count down mode with no clock division, disabled
277     tim->PSC = 15; // prescale by 16, so that at 16MHz CPU clock, we get 1MHz timer
278     tim->DIER |= 1; // interrupt when updated (underflowed)
279     tim->ARR = 0xffffffff;
280     tim->EGR = TIM_EGR_UG; // force a reload of the prescaler
281     NVIC_EnableIRQ(TIM2_IRQn);
282 
283     rtcInit();
284 
285     /* bring up systick */
286     SysTick->CTRL = 0;
287     SysTick->LOAD = 0x00FFFFFF;
288     SysTick->VAL = 0;
289     SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk;
290 
291 #ifdef DEBUG_LOG_EVT
292     /* allocate buffer for early boot log message*/
293     mEarlyLogBuffer = heapAlloc(EARLY_LOG_BUF_SIZE);
294 #endif
295 
296 }
297 
platsystickTicksToNs(uint32_t systickTicks)298 static uint64_t platsystickTicksToNs(uint32_t systickTicks)
299 {
300     return (uint64_t)systickTicks * 125 / 2;
301 }
302 
platGetTicks(void)303 uint64_t platGetTicks(void)
304 {
305     uint64_t ret;
306     uint32_t val;
307 
308     do {
309         mem_reorder_barrier(); //mTimeAccumulated may change since it was read in condition check
310 
311         ret = mTimeAccumulated;
312         val = SysTick->VAL;
313 
314         mem_reorder_barrier(); //mTimeAccumulated may change since it was read above
315 
316     } while (mTimeAccumulated != ret || SysTick->VAL > val);
317 
318     return platsystickTicksToNs(0x01000000 - val) + ret;
319 }
320 
321 /* Timer interrupt handler */
322 void TIM2_IRQHandler(void);
TIM2_IRQHandler(void)323 void TIM2_IRQHandler(void)
324 {
325     struct StmTim *tim = (struct StmTim*)TIM2_BASE;
326 
327     /* int clear */
328     tim->SR &=~ 1;
329 
330     /* timer off */
331     tim->CR1 &=~ 1;
332 
333     /* call timer handler since it might need to reschedule an interrupt (eg: in case where initial delay was too far off & we were limited by timer length) */
334     timIntHandler();
335 }
336 
337 /* SysTick interrupt handler */
338 void SysTick_Handler(void);
SysTick_Handler(void)339 void SysTick_Handler(void)
340 {
341     mTimeAccumulated += platsystickTicksToNs(SysTick->LOAD + 1); //todo - incremenet by actual elapsed nanoseconds and not just "1"
342 }
343 
platRequestDevInSleepMode(uint32_t sleepDevID,uint32_t maxWakeupTime)344 bool platRequestDevInSleepMode(uint32_t sleepDevID, uint32_t maxWakeupTime)
345 {
346     if (sleepDevID >= PLAT_MAX_SLEEP_DEVS || sleepDevID >= Stm32sleepDevNum)
347         return false;
348 
349     mDevsMaxWakeTime[sleepDevID] = maxWakeupTime;
350     while (!atomicCmpXchg32bits(&mSleepDevsToKeepAlive, mSleepDevsToKeepAlive, mSleepDevsToKeepAlive | (1UL << sleepDevID)));
351 
352     return true;
353 }
354 
platAdjustDevInSleepMode(uint32_t sleepDevID,uint32_t maxWakeupTime)355 bool platAdjustDevInSleepMode(uint32_t sleepDevID, uint32_t maxWakeupTime)
356 {
357     if (sleepDevID >= PLAT_MAX_SLEEP_DEVS || sleepDevID >= Stm32sleepDevNum)
358         return false;
359 
360     mDevsMaxWakeTime[sleepDevID] = maxWakeupTime;
361 
362     return true;
363 }
364 
platReleaseDevInSleepMode(uint32_t sleepDevID)365 bool platReleaseDevInSleepMode(uint32_t sleepDevID)
366 {
367     if (sleepDevID >= PLAT_MAX_SLEEP_DEVS || sleepDevID >= Stm32sleepDevNum)
368         return false;
369 
370     while (!atomicCmpXchg32bits(&mSleepDevsToKeepAlive, mSleepDevsToKeepAlive, mSleepDevsToKeepAlive &~ (1UL << sleepDevID)));
371 
372     return true;
373 }
374 
platSetTimerAlarm(uint64_t delay)375 static uint64_t platSetTimerAlarm(uint64_t delay) //delay at most that many nsec
376 {
377     struct StmTim *tim = (struct StmTim*)TIM2_BASE;
378     uint32_t delayInUsecs;
379 
380     //turn off timer to prevent interrupts now
381     tim->CR1 &=~ 1;
382 
383     if (delay >= (1000ULL << 32)) //it is only a 32-bit counter - we cannot set delays bigger than that
384         delayInUsecs = 0xffffffff;
385     else
386         delayInUsecs = cpuMathUint44Div1000ToUint32(delay);
387 
388     tim->CNT = delayInUsecs;
389     tim->SR &=~ 1; //clear int
390     tim->CR1 |= 1;
391 
392     return delayInUsecs;
393 }
394 
platSleepClockRequest(uint64_t wakeupTime,uint32_t maxJitterPpm,uint32_t maxDriftPpm,uint32_t maxErrTotalPpm)395 bool platSleepClockRequest(uint64_t wakeupTime, uint32_t maxJitterPpm, uint32_t maxDriftPpm, uint32_t maxErrTotalPpm)
396 {
397     uint64_t intState, curTime = timGetTime();
398 
399     if (wakeupTime && curTime >= wakeupTime)
400         return false;
401 
402     intState = cpuIntsOff();
403 
404     mMaxJitterPpm = maxJitterPpm;
405     mMaxDriftPpm = maxDriftPpm;
406     mMaxErrTotalPpm = maxErrTotalPpm;
407     mWakeupTime = wakeupTime;
408 
409     //TODO: set an actual alarm here so that if we keep running and do not sleep till this is due, we still fire an interrupt for it!
410     if (wakeupTime)
411         platSetTimerAlarm(wakeupTime - curTime);
412 
413     cpuIntsRestore(intState);
414 
415     return true;
416 }
417 
sleepClockRtcPrepare(uint64_t delay,uint32_t acceptableJitter,uint32_t acceptableDrift,uint32_t maxAcceptableError,void * userData,uint64_t * savedData)418 static bool sleepClockRtcPrepare(uint64_t delay, uint32_t acceptableJitter, uint32_t acceptableDrift, uint32_t maxAcceptableError, void *userData, uint64_t *savedData)
419 {
420     pwrSetSleepType((uint32_t)userData);
421     *savedData = rtcGetTime();
422 
423     if (delay && rtcSetWakeupTimer(delay) < 0)
424         return false;
425 
426     //sleep with systick off (for timing) and interrupts off (for power due to HWR errata)
427     SysTick->CTRL &= ~(SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk);
428     return true;
429 }
430 
sleepClockRtcWake(void * userData,uint64_t * savedData)431 static void sleepClockRtcWake(void *userData, uint64_t *savedData)
432 {
433     //re-enable Systic and its interrupt
434     SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk;
435 
436     mTimeAccumulated += rtcGetTime() - *savedData;
437 }
438 
439 
sleepClockTmrPrepare(uint64_t delay,uint32_t acceptableJitter,uint32_t acceptableDrift,uint32_t maxAcceptableError,void * userData,uint64_t * savedData)440 static bool sleepClockTmrPrepare(uint64_t delay, uint32_t acceptableJitter, uint32_t acceptableDrift, uint32_t maxAcceptableError, void *userData, uint64_t *savedData)
441 {
442     pwrSetSleepType(stm32f411SleepModeSleep);
443     platRequestDevInSleepMode(Stm32sleepDevTim2, 0);
444 
445     *savedData = platSetTimerAlarm(delay ?: ~0ull);
446 
447     //sleep with systick off (for timing) and interrupts off (for power due to HWR errata)
448     SysTick->CTRL &= ~(SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk);
449     return true;
450 }
451 
sleepClockTmrWake(void * userData,uint64_t * savedData)452 static void sleepClockTmrWake(void *userData, uint64_t *savedData)
453 {
454     struct StmTim *tim = (struct StmTim*)TIM2_BASE;
455     uint32_t cnt;
456     uint16_t sr;
457     uint64_t leftTicks;
458 
459     //re-enable Systic and its interrupt
460     SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk;
461 
462     //stop the timer counting;
463     tim->CR1 &=~ 1;
464 
465     //If we are within one time tick of overflow, it is possible for SR to
466     //not indicate a pending overflow, but CNT contain 0xFFFFFFFF or vice versa,
467     //depending on the read order of SR and CNT
468     //read both values until they are stable
469     do {
470         sr = tim->SR;
471         cnt = tim->CNT;
472     } while (sr != tim->SR || cnt != tim->CNT);
473 
474     leftTicks = cnt; //if we wake NOT from timer, only count the ticks that actually ticked as "time passed"
475     if (sr & 1) //if there was an overflow, account for it
476         leftTicks -= 0x100000000ull;
477 
478     mTimeAccumulated += (*savedData - leftTicks) * 1000; //this clock runs at 1MHz
479 
480     platReleaseDevInSleepMode(Stm32sleepDevTim2);
481 }
482 
483 
sleepClockJustWfiPrepare(uint64_t delay,uint32_t acceptableJitter,uint32_t acceptableDrift,uint32_t maxAcceptableError,void * userData,uint64_t * savedData)484 static bool sleepClockJustWfiPrepare(uint64_t delay, uint32_t acceptableJitter, uint32_t acceptableDrift, uint32_t maxAcceptableError, void *userData, uint64_t *savedData)
485 {
486     pwrSetSleepType(stm32f411SleepModeSleep);
487 
488     return true;
489 }
490 
491 struct PlatSleepAndClockInfo {
492     uint64_t resolution;
493     uint64_t resolutionReciprocal; // speed up runtime by using 48 more code bytes? yes please!
494     uint32_t maxCounter;
495     uint32_t jitterPpm;
496     uint32_t driftPpm;
497     uint32_t maxWakeupTime;
498     uint32_t devsAvail; //what is available in sleep mode?
499     bool (*prepare)(uint64_t delay, uint32_t acceptableJitter, uint32_t acceptableDrift, uint32_t maxAcceptableError, void *userData, uint64_t *savedData);
500     void (*wake)(void *userData, uint64_t *savedData);
501     void *userData;
502 } static const platSleepClocks[] = {
503 #ifndef STM32F4xx_DISABLE_LPLV_SLEEP
504     { /* RTC + LPLV STOP MODE */
505         .resolution = 1000000000ull/32768,
506         .resolutionReciprocal = U64_RECIPROCAL_CALCULATE(1000000000ull/32768),
507         .maxCounter = 0xffffffff,
508         .jitterPpm = 0,
509         .driftPpm = 50,
510         .maxWakeupTime = 407000ull,
511         .devsAvail = (1 << Stm32sleepDevExti),
512         .prepare = sleepClockRtcPrepare,
513         .wake = sleepClockRtcWake,
514         .userData = (void*)stm32f411SleepModeStopLPLV,
515     },
516 #endif
517 #ifndef STM32F4xx_DISABLE_LPFD_SLEEP
518     { /* RTC + LPFD STOP MODE */
519         .resolution = 1000000000ull/32768,
520         .resolutionReciprocal = U64_RECIPROCAL_CALCULATE(1000000000ull/32768),
521         .maxCounter = 0xffffffff,
522         .jitterPpm = 0,
523         .driftPpm = 50,
524         .maxWakeupTime = 130000ull,
525         .devsAvail = (1 << Stm32sleepDevExti),
526         .prepare = sleepClockRtcPrepare,
527         .wake = sleepClockRtcWake,
528         .userData = (void*)stm32f411SleepModeStopLPFD,
529     },
530 #endif
531 #ifndef STM32F4xx_DISABLE_MRFPD_SLEEP
532     { /* RTC + MRFPD STOP MODE */
533         .resolution = 1000000000ull/32768,
534         .resolutionReciprocal = U64_RECIPROCAL_CALCULATE(1000000000ull/32768),
535         .maxCounter = 0xffffffff,
536         .jitterPpm = 0,
537         .driftPpm = 50,
538         .maxWakeupTime = 111000ull,
539         .devsAvail = (1 << Stm32sleepDevExti),
540         .prepare = sleepClockRtcPrepare,
541         .wake = sleepClockRtcWake,
542         .userData = (void*)stm32f411SleepModeStopMRFPD,
543     },
544 #endif
545 #ifndef STM32F4xx_DISABLE_MR_SLEEP
546     { /* RTC + MR STOP MODE */
547         .resolution = 1000000000ull/32768,
548         .resolutionReciprocal = U64_RECIPROCAL_CALCULATE(1000000000ull/32768),
549         .maxCounter = 0xffffffff,
550         .jitterPpm = 0,
551         .driftPpm = 50,
552         .maxWakeupTime = 14500ull,
553         .devsAvail = (1 << Stm32sleepDevExti),
554         .prepare = sleepClockRtcPrepare,
555         .wake = sleepClockRtcWake,
556         .userData = (void*)stm32f411SleepModeStopMR,
557     },
558 #endif
559 #ifndef STM32F4xx_DISABLE_TIM2_SLEEP
560     { /* TIM2 + SLEEP MODE */
561         .resolution = 1000000000ull/1000000,
562         .resolutionReciprocal = U64_RECIPROCAL_CALCULATE(1000000000ull/1000000),
563         .maxCounter = 0xffffffff,
564         .jitterPpm = 0,
565         .driftPpm = 30,
566         .maxWakeupTime = 12ull,
567         .devsAvail = (1 << Stm32sleepDevTim2) | (1 << Stm32sleepDevTim4) | (1 << Stm32sleepDevTim5) | (1 << Stm32sleepDevTim9) | (1 << Stm32sleepWakeup) | (1 << Stm32sleepDevSpi2) | (1 << Stm32sleepDevSpi3) | (1 << Stm32sleepDevI2c1) | (1 << Stm32sleepDevI2c2) | (1 << Stm32sleepDevI2c3) | (1 << Stm32sleepDevExti),
568         .prepare = sleepClockTmrPrepare,
569         .wake = sleepClockTmrWake,
570     },
571 #endif
572     { /* just WFI */
573         .resolution = 16000000000ull/1000000,
574         .resolutionReciprocal = U64_RECIPROCAL_CALCULATE(16000000000ull/1000000),
575         .maxCounter = 0xffffffff,
576         .jitterPpm = 0,
577         .driftPpm = 0,
578         .maxWakeupTime = 0,
579         .devsAvail = (1 << Stm32sleepDevTim2) | (1 << Stm32sleepDevTim4) | (1 << Stm32sleepDevTim5) | (1 << Stm32sleepDevTim9) | (1 << Stm32sleepWakeup) | (1 << Stm32sleepDevSpi2) | (1 << Stm32sleepDevSpi3) | (1 << Stm32sleepDevI2c1) | (1 << Stm32sleepDevI2c2) | (1 << Stm32sleepDevI2c3) | (1 << Stm32sleepDevExti),
580         .prepare = sleepClockJustWfiPrepare,
581     },
582 
583     /* terminator */
584     {0},
585 };
586 
platSleep(void)587 void platSleep(void)
588 {
589     uint64_t predecrement = 0, curTime = timGetTime(), length = mWakeupTime - curTime, intState;
590     const struct PlatSleepAndClockInfo *sleepClock, *leastBadOption = NULL;
591     uint64_t savedData;
592     uint32_t i;
593 
594     //shortcut the sleep if it is time to wake up already
595     if (mWakeupTime && mWakeupTime < curTime)
596         return;
597 
598     for (sleepClock = platSleepClocks; sleepClock->maxCounter; sleepClock++) {
599 
600         bool potentialLeastBadOption = false;
601 
602         //if we have timers, consider them
603         if (mWakeupTime) {
604 
605             //calculate how much we WOULD predecerement by
606             predecrement = sleepClock->resolution + sleepClock->maxWakeupTime;
607 
608             //skip options with too much jitter (after accounting for error
609             if (sleepClock->jitterPpm > mMaxJitterPpm)
610                 continue;
611 
612             //skip options that will take too long to wake up to be of use
613             if (predecrement > length)
614                 continue;
615 
616             //skip options with too much drift
617             if (sleepClock->driftPpm > mMaxDriftPpm)
618                 continue;
619 
620             //skip options that do not let us sleep enough, but save them for later if we simply must pick something
621             if (cpuMathRecipAssistedUdiv64by64(length, sleepClock->resolution, sleepClock->resolutionReciprocal) > sleepClock->maxCounter && !leastBadOption)
622                 potentialLeastBadOption = true;
623         }
624 
625         //skip all options that do not keep enough deviceas awake
626         if ((sleepClock->devsAvail & mSleepDevsToKeepAlive) != mSleepDevsToKeepAlive)
627             continue;
628 
629         //skip all options that wake up too slowly
630         for (i = 0; i < Stm32sleepDevNum; i++) {
631             if (!(mSleepDevsToKeepAlive & (1 << i)))
632                 continue;
633             if (mDevsMaxWakeTime[i] < sleepClock->maxWakeupTime)
634                 break;
635         }
636         if (i != Stm32sleepDevNum)
637             continue;
638 
639         //if it will not let us sleep long enough save it as a possibility and go on
640         if (potentialLeastBadOption && !leastBadOption)
641             leastBadOption = sleepClock;
642         else //if it fits us perfectly, pick it
643             break;
644     }
645     if (!sleepClock->maxCounter)
646         sleepClock = leastBadOption;
647 
648     if (!sleepClock) {
649         //should never happen - this will spin the CPU and be bad, but it WILL work in all cases
650         return;
651     }
652 
653     //turn ints off in prep for sleep
654     wdtDisableClk();
655     intState = cpuIntsOff();
656 
657     //options? config it
658     if (sleepClock->prepare &&
659         sleepClock->prepare(mWakeupTime ? length - sleepClock->maxWakeupTime : 0,
660                             mMaxJitterPpm, mMaxDriftPpm, mMaxErrTotalPpm,
661                             sleepClock->userData, &savedData)) {
662 
663         asm volatile ("wfi\n"
664             "nop" :::"memory");
665 
666         //wakeup
667         if (sleepClock->wake)
668             sleepClock->wake(sleepClock->userData, &savedData);
669     }
670     //re-enable interrupts and let the handlers run
671     cpuIntsRestore(intState);
672     wdtEnableClk();
673 }
674 
platGetPersistentRamStore(uint32_t * bytes)675 void* platGetPersistentRamStore(uint32_t *bytes)
676 {
677     *bytes = sizeof(uint32_t[RTC_NUM_BACKUP_REGS]);
678     return rtcGetBackupStorage();
679 }
680 
platFreeResources(uint32_t tid)681 uint32_t platFreeResources(uint32_t tid)
682 {
683     uint32_t dmaCount = dmaStopAll(tid);
684     uint32_t irqCount = extiUnchainAll(tid);
685 
686     return (dmaCount << 8) | irqCount;
687 }
688 
platPeriodic()689 void platPeriodic()
690 {
691     wdtPing();
692 }
693