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