1 /*
2  * Copyright (c) 2015-2017, 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  *  ======== PowerCC32XX.c ========
34  */
35 
36 #include <stdint.h>
37 
38 /*
39  * By default disable both asserts and log for this module.
40  * This must be done before DebugP.h is included.
41  */
42 #ifndef DebugP_ASSERT_ENABLED
43 #define DebugP_ASSERT_ENABLED 0
44 #endif
45 #ifndef DebugP_LOG_ENABLED
46 #define DebugP_LOG_ENABLED 0
47 #endif
48 #include <ti/drivers/dpl/DebugP.h>
49 #include <ti/drivers/dpl/HwiP.h>
50 
51 #include <ti/drivers/utils/List.h>
52 
53 #include <ti/drivers/Power.h>
54 #include <ti/drivers/power/PowerCC32XX.h>
55 
56 #if defined(__IAR_SYSTEMS_ICC__)
57 #include <intrinsics.h>
58 #endif
59 
60 /* driverlib header files */
61 #include <ti/devices/cc32xx/driverlib/rom.h>
62 #include <ti/devices/cc32xx/driverlib/rom_map.h>
63 #include <ti/devices/cc32xx/inc/hw_types.h>
64 #include <ti/devices/cc32xx/inc/hw_gprcm.h>
65 #include <ti/devices/cc32xx/inc/hw_apps_rcm.h>
66 #include <ti/devices/cc32xx/inc/hw_ocp_shared.h>
67 #include <ti/devices/cc32xx/driverlib/prcm.h>
68 #include <ti/devices/cc32xx/inc/hw_nvic.h>
69 #include <ti/devices/cc32xx/inc/hw_memmap.h>
70 #include <ti/devices/cc32xx/inc/hw_ints.h>
71 #include <ti/devices/cc32xx/driverlib/pin.h>
72 #include <ti/devices/cc32xx/driverlib/cpu.h>
73 #include <ti/devices/cc32xx/driverlib/hwspinlock.h>
74 #include <ti/devices/cc32xx/driverlib/spi.h>
75 
76 #define TRUE    1
77 #define FALSE   0
78 #define STATUS_BUSY   0x01
79 
80 #define PowerCC32XX_SSPIReadStatusInstruction   (0x05)
81 #define PowerCC32XX_SSPIPowerDownInstruction    (0xB9)
82 #define PowerCC32XX_SSPISemaphoreTakeTries      (4000000)
83 #define PowerCC32XX_SSPICSDelay                 33
84 #define uSEC_DELAY(x)                           (ROM_UtilsDelayDirect(x*80/3))
85 
86 #define SYNCBARRIER() {          \
87     __asm(" dsb \n"              \
88           " isb \n");            \
89 }
90 
91 /* Externs */
92 extern const PowerCC32XX_ConfigV1 PowerCC32XX_config;
93 
94 /* Module_State */
95 PowerCC32XX_ModuleState PowerCC32XX_module = {
96     { NULL, NULL},  /* list */
97     0,              /* constraintsMask */
98     Power_ACTIVE,   /* state */
99     /* dbRecords */
100     {
101         PRCM_CAMERA,  /* PERIPH_CAMERA */
102         PRCM_I2S,     /* PERIPH_MCASP */
103         PRCM_SDHOST,  /* PERIPH_MMCHS */
104         PRCM_GSPI,    /* PERIPH_MCSPI_A1 */
105         PRCM_LSPI,    /* PERIPH_MCSPI_A2 */
106         PRCM_UDMA,    /* PERIPH_UDMA_A */
107         PRCM_GPIOA0,  /* PERIPH_GPIO_A */
108         PRCM_GPIOA1,  /* PERIPH_GPIO_B */
109         PRCM_GPIOA2,  /* PERIPH_GPIO_C */
110         PRCM_GPIOA3,  /* PERIPH_GPIO_D */
111         PRCM_GPIOA4,  /* PERIPH_GPIO_E */
112         PRCM_WDT,     /* PERIPH_WDOG_A */
113         PRCM_UARTA0,  /* PERIPH_UART_A0 */
114         PRCM_UARTA1,  /* PERIPH_UART_A1 */
115         PRCM_TIMERA0, /* PERIPH_GPT_A0 */
116         PRCM_TIMERA1, /* PERIPH_GPT_A1 */
117         PRCM_TIMERA2, /* PERIPH_GPT_A2 */
118         PRCM_TIMERA3, /* PERIPH_GPT_A3 */
119         PRCM_DTHE,    /* PERIPH_CRYPTO */
120         PRCM_SSPI,    /* PERIPH_MCSPI_S0 */
121         PRCM_I2CA0    /* PERIPH_I2C */
122     },
123     /* enablePolicy */
124     FALSE,
125     /* initialized */
126     FALSE,
127     /* refCount */
128     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
129     /* constraintCounts */
130     { 0, 0 },
131     /* policyFxn */
132     NULL
133 };
134 
135 /* context save variable */
136 PowerCC32XX_SaveRegisters PowerCC32XX_contextSave;
137 
138 typedef void (*LPDSFunc)(void);
139 
140 /* enter LPDS is an assembly function */
141 extern void PowerCC32XX_enterLPDS(LPDSFunc driverlibFunc);
142 
143 /* pin parking functions */
144 void PowerCC32XX_parkPin(PowerCC32XX_Pin pin, PowerCC32XX_ParkState parkState,
145     uint32_t * previousState, uint16_t * previousDirection);
146 void PowerCC32XX_restoreParkedPin(PowerCC32XX_Pin pin, uint32_t type,
147     uint16_t direction);
148 void PowerCC32XX_shutdownSSPI(void);
149 
150 /* internal functions */
151 static int_fast16_t notify(uint_fast16_t eventType);
152 static void restoreNVICRegs(void);
153 static void restorePeriphClocks(void);
154 static void saveNVICRegs(void);
155 static void parkPins(void);
156 static void restoreParkedPins(void);
157 
158 /*
159  *  ======== Power_disablePolicy ========
160  *  Do not run the configured policy
161  */
Power_disablePolicy(void)162 bool Power_disablePolicy(void)
163 {
164     bool enablePolicy = PowerCC32XX_module.enablePolicy;
165     PowerCC32XX_module.enablePolicy = FALSE;
166 
167     DebugP_log0("Power: disable policy");
168 
169     return (enablePolicy);
170 }
171 
172 /*
173  *  ======== Power_enablePolicy ========
174  *  Run the configured policy
175  */
Power_enablePolicy(void)176 void Power_enablePolicy(void)
177 {
178     PowerCC32XX_module.enablePolicy = TRUE;
179 
180     DebugP_log0("Power: enable policy");
181 }
182 
183 /*
184  *  ======== Power_getConstraintMask ========
185  *  Get a bitmask indicating the constraints that have been registered with
186  *  Power.
187  */
Power_getConstraintMask(void)188 uint_fast32_t Power_getConstraintMask(void)
189 {
190     return (PowerCC32XX_module.constraintMask);
191 }
192 
193 /*
194  *  ======== Power_getDependencyCount ========
195  *  Get the count of dependencies that are currently declared upon a resource.
196  */
Power_getDependencyCount(uint_fast16_t resourceId)197 int_fast16_t Power_getDependencyCount(uint_fast16_t resourceId)
198 {
199     int_fast16_t status;
200 
201     if (resourceId >= PowerCC32XX_NUMRESOURCES) {
202         status = Power_EINVALIDINPUT;
203     }
204     else {
205         status = PowerCC32XX_module.refCount[resourceId];
206     }
207 
208     return (status);
209 }
210 
211 /*
212  *  ======== Power_getTransitionLatency ========
213  *  Get the transition latency for a sleep state.  The latency is reported
214  *  in units of microseconds.
215  */
Power_getTransitionLatency(uint_fast16_t sleepState,uint_fast16_t type)216 uint_fast32_t Power_getTransitionLatency(uint_fast16_t sleepState,
217     uint_fast16_t type)
218 {
219     uint32_t latency = 0;
220 
221     if (type == Power_RESUME) {
222         latency = PowerCC32XX_RESUMETIMELPDS;
223     }
224     else {
225         latency = PowerCC32XX_TOTALTIMELPDS;
226     }
227 
228     return (latency);
229 }
230 
231 /*
232  *  ======== Power_getTransitionState ========
233  *  Get the current sleep transition state.
234  */
Power_getTransitionState(void)235 uint_fast16_t Power_getTransitionState(void)
236 {
237     return (PowerCC32XX_module.state);
238 }
239 
240 /*
241  *  ======== Power_idleFunc ========
242  *  Function needs to be plugged into the idle loop.
243  *  It calls the configured policy function if the
244  *  'enablePolicy' flag is set.
245  */
Power_idleFunc()246 void Power_idleFunc()
247 {
248     if (PowerCC32XX_module.enablePolicy) {
249         if (PowerCC32XX_module.policyFxn != NULL) {
250             DebugP_log1("Power: calling policy function (%p)",
251                 (uintptr_t) PowerCC32XX_module.policyFxn);
252             (*(PowerCC32XX_module.policyFxn))();
253         }
254     }
255 }
256 
257 /*
258  *  ======== Power_init ========
259  */
Power_init()260 int_fast16_t Power_init()
261 {
262     /* if this function has already been called, just return */
263     if (PowerCC32XX_module.initialized) {
264         return (Power_SOK);
265     }
266 
267     /* set module state field 'initialized' to true */
268     PowerCC32XX_module.initialized = TRUE;
269 
270     /* set the module state enablePolicy field */
271     PowerCC32XX_module.enablePolicy = PowerCC32XX_config.enablePolicy;
272 
273     /* call the config policy init function if its not null */
274     if (PowerCC32XX_config.policyInitFxn != NULL) {
275         (*(PowerCC32XX_config.policyInitFxn))();
276     }
277 
278     /* copy wakeup settings to module state */
279     PowerCC32XX_module.wakeupConfig.enableGPIOWakeupLPDS =
280         PowerCC32XX_config.enableGPIOWakeupLPDS;
281     PowerCC32XX_module.wakeupConfig.enableGPIOWakeupShutdown =
282         PowerCC32XX_config.enableGPIOWakeupShutdown;
283     PowerCC32XX_module.wakeupConfig.enableNetworkWakeupLPDS =
284         PowerCC32XX_config.enableNetworkWakeupLPDS;
285     PowerCC32XX_module.wakeupConfig.wakeupGPIOSourceLPDS =
286         PowerCC32XX_config.wakeupGPIOSourceLPDS;
287     PowerCC32XX_module.wakeupConfig.wakeupGPIOTypeLPDS =
288         PowerCC32XX_config.wakeupGPIOTypeLPDS;
289     PowerCC32XX_module.wakeupConfig.wakeupGPIOFxnLPDS =
290         PowerCC32XX_config.wakeupGPIOFxnLPDS;
291     PowerCC32XX_module.wakeupConfig.wakeupGPIOFxnLPDSArg =
292         PowerCC32XX_config.wakeupGPIOFxnLPDSArg;
293     PowerCC32XX_module.wakeupConfig.wakeupGPIOSourceShutdown =
294         PowerCC32XX_config.wakeupGPIOSourceShutdown;
295     PowerCC32XX_module.wakeupConfig.wakeupGPIOTypeShutdown =
296         PowerCC32XX_config.wakeupGPIOTypeShutdown;
297 
298     /* now configure these wakeup settings in the device... */
299     PowerCC32XX_configureWakeup(&PowerCC32XX_module.wakeupConfig);
300 
301     /* copy the Power policy function to module state */
302     PowerCC32XX_module.policyFxn = PowerCC32XX_config.policyFxn;
303 
304     /* spin if too many pins were specified in the pin park array */
305     if (PowerCC32XX_config.numPins > PowerCC32XX_NUMPINS) {
306         while(1){}
307     }
308 
309     /* Initialize CLK GPIO */
310     HWREG(OCP_SHARED_BASE + OCP_SHARED_O_GPIO_PAD_CONFIG_18) = 0x281;
311 
312     /* Initialize DOUT GPIO */
313     HWREG(OCP_SHARED_BASE + OCP_SHARED_O_GPIO_PAD_CONFIG_19) = 0x281;
314 
315     return (Power_SOK);
316 }
317 
318 /*
319  *  ======== Power_registerNotify ========
320  *  Register a function to be called on a specific power event.
321  */
Power_registerNotify(Power_NotifyObj * pNotifyObj,uint_fast16_t eventTypes,Power_NotifyFxn notifyFxn,uintptr_t clientArg)322 int_fast16_t Power_registerNotify(Power_NotifyObj * pNotifyObj,
323     uint_fast16_t eventTypes, Power_NotifyFxn notifyFxn, uintptr_t clientArg)
324 {
325     int_fast16_t status = Power_SOK;
326 
327     /* check for NULL pointers  */
328     if ((pNotifyObj == NULL) || (notifyFxn == NULL)) {
329         status = Power_EINVALIDPOINTER;
330     }
331 
332     else {
333         /* fill in notify object elements */
334         pNotifyObj->eventTypes = eventTypes;
335         pNotifyObj->notifyFxn = notifyFxn;
336         pNotifyObj->clientArg = clientArg;
337 
338         /* place notify object on event notification queue */
339         List_put(&PowerCC32XX_module.notifyList, (List_Elem*)pNotifyObj);
340     }
341 
342     DebugP_log3(
343         "Power: register notify (%p), eventTypes (0x%x), notifyFxn (%p)",
344         (uintptr_t) pNotifyObj, eventTypes, (uintptr_t) notifyFxn);
345 
346     return (status);
347 }
348 
349 /*
350  *  ======== Power_releaseConstraint ========
351  *  Release a previously declared constraint.
352  */
Power_releaseConstraint(uint_fast16_t constraintId)353 int_fast16_t Power_releaseConstraint(uint_fast16_t constraintId)
354 {
355     int_fast16_t status = Power_SOK;
356     uintptr_t key;
357     uint8_t count;
358 
359     /* first ensure constraintId is valid */
360     if (constraintId >= PowerCC32XX_NUMCONSTRAINTS) {
361         status = Power_EINVALIDINPUT;
362     }
363 
364     /* if constraintId is OK ... */
365     else {
366 
367         /* disable interrupts */
368         key = HwiP_disable();
369 
370         /* get the count of the constraint */
371         count = PowerCC32XX_module.constraintCounts[constraintId];
372 
373         /* ensure constraint count is not already zero */
374         if (count == 0) {
375             status = Power_EFAIL;
376         }
377 
378         /* if not already zero ... */
379         else {
380             /* decrement the count */
381             count--;
382 
383             /* save the updated count */
384             PowerCC32XX_module.constraintCounts[constraintId] = count;
385 
386             /* if constraint count reaches zero, remove constraint from mask */
387             if (count == 0) {
388                 PowerCC32XX_module.constraintMask &= ~(1 << constraintId);
389             }
390         }
391 
392         /* restore interrupts */
393         HwiP_restore(key);
394 
395         DebugP_log1("Power: release constraint (%d)", constraintId);
396     }
397 
398     return (status);
399 }
400 
401 /*
402  *  ======== Power_releaseDependency ========
403  *  Release a previously declared dependency.
404  */
Power_releaseDependency(uint_fast16_t resourceId)405 int_fast16_t Power_releaseDependency(uint_fast16_t resourceId)
406 {
407     int_fast16_t status = Power_SOK;
408     uint8_t count;
409     uint32_t id;
410     uintptr_t key;
411 
412     /* first check that resourceId is valid */
413     if (resourceId >= PowerCC32XX_NUMRESOURCES) {
414         status = Power_EINVALIDINPUT;
415     }
416 
417     /* if resourceId is OK ... */
418     else {
419 
420         /* disable interrupts */
421         key = HwiP_disable();
422 
423         /* read the reference count */
424         count = PowerCC32XX_module.refCount[resourceId];
425 
426         /* ensure dependency count is not already zero */
427         if (count == 0) {
428             status = Power_EFAIL;
429         }
430 
431         /* if not already zero ... */
432         else {
433 
434             /* decrement the reference count */
435             count--;
436 
437             /* if this was the last dependency being released.., */
438             if (count == 0) {
439                 /* deactivate this resource ... */
440                 id = PowerCC32XX_module.dbRecords[resourceId];
441 
442                 /* disable clk to peripheral */
443                 MAP_PRCMPeripheralClkDisable(id,
444                     PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
445             }
446 
447             /* save the updated count */
448             PowerCC32XX_module.refCount[resourceId] = count;
449         }
450 
451         /* restore interrupts */
452         HwiP_restore(key);
453 
454         DebugP_log1("Power: release dependency (%d)", resourceId);
455     }
456 
457     return (status);
458 }
459 
460 /*
461  *  ======== Power_setConstraint ========
462  *  Declare an operational constraint.
463  */
Power_setConstraint(uint_fast16_t constraintId)464 int_fast16_t Power_setConstraint(uint_fast16_t constraintId)
465 {
466     int_fast16_t status = Power_SOK;
467     uintptr_t key;
468 
469     /* ensure that constraintId is valid */
470     if (constraintId >= PowerCC32XX_NUMCONSTRAINTS) {
471         status = Power_EINVALIDINPUT;
472     }
473 
474     else {
475 
476         /* disable interrupts */
477         key = HwiP_disable();
478 
479         /* set the specified constraint in the constraintMask */
480         PowerCC32XX_module.constraintMask |= 1 << constraintId;
481 
482         /* increment the specified constraint count */
483         PowerCC32XX_module.constraintCounts[constraintId]++;
484 
485         /* restore interrupts */
486         HwiP_restore(key);
487 
488         DebugP_log1("Power: set constraint (%d)", constraintId);
489     }
490 
491     return (status);
492 }
493 
494 /*
495  *  ======== Power_setDependency ========
496  *  Declare a dependency upon a resource.
497  */
Power_setDependency(uint_fast16_t resourceId)498 int_fast16_t Power_setDependency(uint_fast16_t resourceId)
499 {
500     int_fast16_t status = Power_SOK;
501     uint8_t count;
502     uint32_t id;
503     uintptr_t key;
504 
505     /* ensure resourceId is valid */
506     if (resourceId >= PowerCC32XX_NUMRESOURCES) {
507         status = Power_EINVALIDINPUT;
508     }
509 
510     /* resourceId is OK ... */
511     else {
512 
513         /* disable interrupts */
514         key = HwiP_disable();
515 
516         /* read and increment reference count */
517         count = PowerCC32XX_module.refCount[resourceId]++;
518 
519         /* if resource was NOT activated previously ... */
520         if (count == 0) {
521             /* now activate this resource ... */
522             id = PowerCC32XX_module.dbRecords[resourceId];
523 
524             /*
525              * When the periphery is LSPI, choose PLL or XTAL according
526              * to the generation of the NWP
527              */
528             if(id == PowerCC32XX_PERIPH_LSPI)
529             {
530                  /* Check NWP generation */
531                  if((HWREG(GPRCM_BASE + GPRCM_O_GPRCM_DIEID_READ_REG4) >> 24) & 0x02)
532                  {
533                      /* Configure PLL and divide the speed by 8 for LSPI */
534                      HWREG(ARCM_BASE + APPS_RCM_O_MCSPI_A2_CLK_GEN) = 0x10303;
535                  }
536                  else
537                  {
538                      /* Configure XTAL for LSPI */
539                      HWREG(ARCM_BASE + APPS_RCM_O_MCSPI_A2_CLK_GEN) = 0x00;
540                  }
541             }
542 
543             /* enable the peripheral clock to the resource */
544             MAP_PRCMPeripheralClkEnable(id,
545                 PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
546 
547             /* spin here until status returns TRUE */
548             while(!MAP_PRCMPeripheralStatusGet(id)) {
549             }
550         }
551 
552         /* restore interrupts */
553         HwiP_restore(key);
554         DebugP_log1("Power: set dependency (%d)", resourceId);
555     }
556 
557     return (status);
558 }
559 
560 /*
561  *  ======== Power_setPolicy ========
562  *  Set the Power policy function
563  */
Power_setPolicy(Power_PolicyFxn policy)564 void Power_setPolicy(Power_PolicyFxn policy)
565 {
566     PowerCC32XX_module.policyFxn = policy;
567 }
568 
569 /*
570  *  ======== Power_shutdown ========
571  */
Power_shutdown(uint_fast16_t shutdownState,uint_fast32_t shutdownTime)572 int_fast16_t Power_shutdown(uint_fast16_t shutdownState,
573                             uint_fast32_t shutdownTime)
574 {
575     int_fast16_t status = Power_EFAIL;
576     uint32_t constraints;
577     uintptr_t hwiKey;
578     uint64_t counts;
579 
580     /* disable interrupts */
581     hwiKey = HwiP_disable();
582 
583     /* make sure shutdown request doesn't violate a constraint */
584     constraints = Power_getConstraintMask();
585     if (constraints & (1 << PowerCC32XX_DISALLOW_SHUTDOWN)) {
586         status = Power_ECHANGE_NOT_ALLOWED;
587     }
588     else {
589         if (PowerCC32XX_module.state == Power_ACTIVE) {
590             /* set new transition state to entering shutdown */
591             PowerCC32XX_module.state = Power_ENTERING_SHUTDOWN;
592 
593             /* signal all clients registered for pre-shutdown notification */
594             status = notify(PowerCC32XX_ENTERING_SHUTDOWN);
595             /* check for timeout or any other error */
596             if (status != Power_SOK) {
597                 PowerCC32XX_module.state = Power_ACTIVE;
598                 HwiP_restore(hwiKey);
599                 return (status);
600             }
601             /* shutdown the flash */
602             PowerCC32XX_shutdownSSPI();
603             /* if shutdown wakeup time was configured to be large enough */
604             if (shutdownTime > (PowerCC32XX_TOTALTIMESHUTDOWN / 1000)) {
605                 /* calculate the wakeup time for hibernate in RTC counts */
606                 counts =
607                     (((uint64_t)(shutdownTime -
608                                 (PowerCC32XX_TOTALTIMESHUTDOWN / 1000))
609                                 * 32768) / 1000);
610 
611                 /* set the hibernate wakeup time */
612                 MAP_PRCMHibernateIntervalSet(counts);
613 
614                 /* enable the wake source to be RTC */
615                 MAP_PRCMHibernateWakeupSourceEnable(PRCM_HIB_SLOW_CLK_CTR);
616             }
617 
618             /* enable IO retention */
619             if (PowerCC32XX_config.ioRetentionShutdown) {
620                 MAP_PRCMIORetentionEnable(
621                     PowerCC32XX_config.ioRetentionShutdown);
622             }
623 
624             DebugP_log2(
625                 "Power: entering shutdown state (%d), shutdownTime (%d)",
626                 shutdownState, shutdownTime);
627 
628             /* enter hibernate - we should never return from here */
629             MAP_PRCMHibernateEnter();
630         }
631         else {
632             status = Power_EBUSY;
633         }
634     }
635 
636     /* set state to Power_ACTIVE */
637     PowerCC32XX_module.state = Power_ACTIVE;
638 
639     /* re-enable interrupts */
640     HwiP_restore(hwiKey);
641 
642     /* if get here, failed to shutdown, return error code */
643     return (status);
644 }
645 
646 /*
647  *  ======== Power_sleep ========
648  */
Power_sleep(uint_fast16_t sleepState)649 int_fast16_t Power_sleep(uint_fast16_t sleepState)
650 {
651     int_fast16_t status = Power_SOK;
652     uint32_t romMajorVer;
653     uint32_t romMinorVer;
654     uint32_t preEvent;
655     uint32_t postEvent;
656     uint32_t semBits;
657     bool earlyPG = true;
658 
659     /* first validate the sleep state */
660     if (sleepState != PowerCC32XX_LPDS) {
661         status = Power_EINVALIDINPUT;
662     }
663 
664     else if (PowerCC32XX_module.state == Power_ACTIVE) {
665 
666         /* set transition state to entering sleep */
667         PowerCC32XX_module.state = Power_ENTERING_SLEEP;
668 
669         /* setup sleep vars */
670         preEvent = PowerCC32XX_ENTERING_LPDS;
671         postEvent = PowerCC32XX_AWAKE_LPDS;
672 
673         /* signal all clients registered for pre-sleep notification */
674         status = notify(preEvent);
675 
676         /* check for timeout or any other error */
677         if (status != Power_SOK) {
678             PowerCC32XX_module.state = Power_ACTIVE;
679             return (status);
680         }
681 
682         /* indicate to the MAC layer through register that the
683            APPS layer is going to sleep this is needed because
684            the MAC cannot do DC2DC clock sync when the application
685            processor waking up from sleep and running through its
686            ROM bootloader because it is also touching the DC2DC
687            of the top die FLASH                                */
688 
689         HWREG(OCP_SHARED_BASE + OCP_SHARED_O_ALT_PC_VAL_APPS) = 1;
690 
691         DebugP_log1("Power: sleep, sleepState (%d)", sleepState);
692 
693         /* invoke specific sequence to activate LPDS ...*/
694 
695         /* enable RAM retention */
696         MAP_PRCMSRAMRetentionEnable(
697             PowerCC32XX_config.ramRetentionMaskLPDS,
698             PRCM_SRAM_LPDS_RET);
699 
700         /* call the enter LPDS hook function if configured */
701         if (PowerCC32XX_config.enterLPDSHookFxn != NULL) {
702             (*(PowerCC32XX_config.enterLPDSHookFxn))();
703         }
704 
705         /* park pins, based upon board file definitions */
706         if (PowerCC32XX_config.pinParkDefs != NULL) {
707             parkPins();
708         }
709 
710         /* save the NVIC registers */
711         saveNVICRegs();
712 
713         /* check if PG >= 2.01 */
714         romMajorVer = HWREG(0x00000400) & 0xFFFF;
715         romMinorVer = HWREG(0x00000400) >> 16;
716         if ((romMajorVer >= 3) || ((romMajorVer == 2) && (romMinorVer >= 1))) {
717             earlyPG = false;
718         }
719 
720         /* call sync barrier */
721         SYNCBARRIER();
722 
723         /* now enter LPDS - function does not return... */
724         if (PowerCC32XX_config.keepDebugActiveDuringLPDS == TRUE) {
725             if (earlyPG) {
726                 PowerCC32XX_enterLPDS(PRCMLPDSEnterKeepDebugIf);
727             }
728             else {
729                 PowerCC32XX_enterLPDS(ROM_PRCMLPDSEnterKeepDebugIfDirect);
730             }
731         }
732         else {
733             if (earlyPG) {
734                 PowerCC32XX_enterLPDS(PRCMLPDSEnter);
735             }
736             else {
737                 PowerCC32XX_enterLPDS(ROM_PRCMLPDSEnterDirect);
738             }
739         }
740 
741         /* return here after reset, from Power_resumeLPDS() */
742 
743         /* restore NVIC registers */
744         restoreNVICRegs();
745 
746         /* restore clock to those peripherals with dependecy set */
747         restorePeriphClocks();
748 
749         /* call PRCMCC3200MCUInit() for any necessary post-LPDS restore */
750         MAP_PRCMCC3200MCUInit();
751 
752         /* take the GPIO semaphore bits for the MCU */
753         semBits = HWREG(0x400F703C);
754         semBits = (semBits & ~0x3FF) | 0x155;
755         HWREG(0x400F703C) = semBits;
756 
757         /* call the resume LPDS hook function if configured */
758         if (PowerCC32XX_config.resumeLPDSHookFxn != NULL) {
759             (*(PowerCC32XX_config.resumeLPDSHookFxn))();
760         }
761 
762         /* re-enable Slow Clock Counter Interrupt */
763         MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
764 
765         /* set transition state to EXITING_SLEEP */
766         PowerCC32XX_module.state = Power_EXITING_SLEEP;
767 
768         /* indicate to the MAC layer that the application processor is
769            up and running                                             */
770         HWREG(OCP_SHARED_BASE + OCP_SHARED_O_ALT_PC_VAL_APPS) = 0;
771 
772         /*
773          * signal clients registered for post-sleep notification; for example,
774          * a driver that needs to reinitialize its peripheral state, that was
775          * lost during LPDS
776          */
777         status = notify(postEvent);
778 
779         /* restore pins parked before LPDS to their previous states */
780         if (PowerCC32XX_config.pinParkDefs != NULL) {
781             restoreParkedPins();
782         }
783 
784         /* if wake source was GPIO, optionally call wakeup function */
785         if (MAP_PRCMLPDSWakeupCauseGet() == PRCM_LPDS_GPIO) {
786             if (PowerCC32XX_module.wakeupConfig.wakeupGPIOFxnLPDS != NULL) {
787                 (*(PowerCC32XX_module.wakeupConfig.wakeupGPIOFxnLPDS))
788                   (PowerCC32XX_module.wakeupConfig.wakeupGPIOFxnLPDSArg);
789             }
790         }
791 
792         /* now clear the transition state before re-enabling scheduler */
793         PowerCC32XX_module.state = Power_ACTIVE;
794     }
795     else {
796         status = Power_EBUSY;
797     }
798 
799     return (status);
800 }
801 
802 /*
803  *  ======== Power_unregisterNotify ========
804  *  Unregister for a power notification.
805  *
806  */
Power_unregisterNotify(Power_NotifyObj * pNotifyObj)807 void Power_unregisterNotify(Power_NotifyObj * pNotifyObj)
808 {
809     uintptr_t key;
810 
811     /* disable interrupts */
812     key = HwiP_disable();
813 
814     /* remove notify object from its event queue */
815     List_remove(&PowerCC32XX_module.notifyList, (List_Elem *)pNotifyObj);
816 
817     /* re-enable interrupts */
818     HwiP_restore(key);
819 
820     DebugP_log1("Power: unregister notify (%p)", (uintptr_t) pNotifyObj);
821 }
822 
823 /*********************** CC32XX-specific functions **************************/
824 
825 /*
826  *  ======== PowerCC32XX_configureWakeup ========
827  *  Configure LPDS and shutdown wakeups; copy settings into driver state
828  */
PowerCC32XX_configureWakeup(PowerCC32XX_Wakeup * wakeup)829 void PowerCC32XX_configureWakeup(PowerCC32XX_Wakeup *wakeup)
830 {
831     /* configure network (Host IRQ) as wakeup source for LPDS */
832     if (wakeup->enableNetworkWakeupLPDS) {
833         MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_HOST_IRQ);
834     }
835     else {
836         MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_HOST_IRQ);
837     }
838     PowerCC32XX_module.wakeupConfig.enableNetworkWakeupLPDS =
839         wakeup->enableNetworkWakeupLPDS;
840 
841     /* configure GPIO as wakeup source for LPDS */
842     if (wakeup->enableGPIOWakeupLPDS) {
843         MAP_PRCMLPDSWakeUpGPIOSelect(
844             wakeup->wakeupGPIOSourceLPDS,
845             wakeup->wakeupGPIOTypeLPDS);
846         MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_GPIO);
847     }
848     else {
849         MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_GPIO);
850     }
851     PowerCC32XX_module.wakeupConfig.enableGPIOWakeupLPDS =
852         wakeup->enableGPIOWakeupLPDS;
853     PowerCC32XX_module.wakeupConfig.wakeupGPIOSourceLPDS =
854         wakeup->wakeupGPIOSourceLPDS;
855     PowerCC32XX_module.wakeupConfig.wakeupGPIOTypeLPDS =
856         wakeup->wakeupGPIOTypeLPDS;
857 
858     /* configure GPIO as wakeup source for Shutdown */
859     if (wakeup->enableGPIOWakeupShutdown) {
860         MAP_PRCMHibernateWakeUpGPIOSelect(
861             wakeup->wakeupGPIOSourceShutdown,
862             wakeup->wakeupGPIOTypeShutdown);
863         MAP_PRCMHibernateWakeupSourceEnable(
864             wakeup->wakeupGPIOSourceShutdown);
865     }
866     else {
867         MAP_PRCMHibernateWakeupSourceDisable(
868             wakeup->wakeupGPIOSourceShutdown);
869     }
870     PowerCC32XX_module.wakeupConfig.enableGPIOWakeupShutdown =
871         wakeup->enableGPIOWakeupShutdown;
872     PowerCC32XX_module.wakeupConfig.wakeupGPIOSourceShutdown =
873         wakeup->wakeupGPIOSourceShutdown;
874     PowerCC32XX_module.wakeupConfig.wakeupGPIOTypeShutdown =
875         wakeup->wakeupGPIOTypeShutdown;
876 
877     /* copy the LPDS GPIO wakeup function and arg to module state */
878     PowerCC32XX_module.wakeupConfig.wakeupGPIOFxnLPDS =
879         wakeup->wakeupGPIOFxnLPDS;
880     PowerCC32XX_module.wakeupConfig.wakeupGPIOFxnLPDSArg =
881         wakeup->wakeupGPIOFxnLPDSArg;
882 }
883 
884 /*
885  *  ======== PowerCC32XX_disableIORetention ========
886  *  Disable IO retention and unlock pins after exit from Shutdown
887  */
PowerCC32XX_disableIORetention(unsigned long groupFlags)888 void PowerCC32XX_disableIORetention(unsigned long groupFlags)
889 {
890     MAP_PRCMIORetentionDisable(groupFlags);
891 }
892 
893 /*
894  *  ======== PowerCC32XX_getParkState ========
895  *  Get the current LPDS park state for a pin
896  */
PowerCC32XX_getParkState(PowerCC32XX_Pin pin)897 PowerCC32XX_ParkState PowerCC32XX_getParkState(PowerCC32XX_Pin pin)
898 {
899     PowerCC32XX_ParkInfo parkInfo;
900     PowerCC32XX_ParkState state = PowerCC32XX_DONT_PARK;
901     uint32_t i;
902 
903     DebugP_assert(PowerCC32XX_config.numPins < PowerCC32XX_NUMPINS + 1);
904 
905     /* step thru the pin park array until find the pin */
906     for (i = 0; i < PowerCC32XX_config.numPins; i++) {
907 
908         parkInfo = PowerCC32XX_config.pinParkDefs[i];
909 
910         /* if this is the pin to be checked... */
911         if (parkInfo.pin == pin) {
912             state = (PowerCC32XX_ParkState) parkInfo.parkState;
913             break;
914         }
915     }
916 
917     return (state);
918 }
919 
920 /*
921  *  ======== PowerCC32XX_getWakeup ========
922  *  Get the current LPDS and shutdown wakeup configuration
923  */
PowerCC32XX_getWakeup(PowerCC32XX_Wakeup * wakeup)924 void PowerCC32XX_getWakeup(PowerCC32XX_Wakeup *wakeup)
925 {
926     *wakeup = PowerCC32XX_module.wakeupConfig;
927 }
928 
929 /*
930  *  ======== PowerCC32XX_parkPin ========
931  *  Park a device pin in preparation for LPDS
932  */
PowerCC32XX_parkPin(PowerCC32XX_Pin pin,PowerCC32XX_ParkState parkState,uint32_t * previousType,uint16_t * previousDirection)933 void PowerCC32XX_parkPin(PowerCC32XX_Pin pin, PowerCC32XX_ParkState parkState,
934     uint32_t * previousType, uint16_t * previousDirection)
935 {
936     unsigned long strength;
937     unsigned long type;
938 
939     /* get the current pin configuration */
940     MAP_PinConfigGet(pin, &strength, &type);
941 
942     /* stash the current pin type */
943     *previousType = type;
944 
945     /* get and stash the current pin direction */
946     *previousDirection = (uint16_t)MAP_PinDirModeGet(pin);
947 
948     /* set pin type to the parking state */
949     MAP_PinConfigSet(pin, strength, (unsigned long) parkState);
950 
951     /* set pin direction to input to HiZ the pin */
952     MAP_PinDirModeSet(pin, PIN_DIR_MODE_IN);
953 }
954 
955 /*
956  *  ======== PowerCC32XX_restoreParkedPin ========
957  *  Restore a pin that was previously parked with PowerCC32XX_parkPin
958  */
PowerCC32XX_restoreParkedPin(PowerCC32XX_Pin pin,uint32_t type,uint16_t direction)959 void PowerCC32XX_restoreParkedPin(PowerCC32XX_Pin pin, uint32_t type,
960     uint16_t direction)
961 {
962     unsigned long strength;
963     unsigned long currentType;
964 
965     /* get the current pin configuration */
966     MAP_PinConfigGet(pin, &strength, &currentType);
967 
968     /* restore the pin type */
969     MAP_PinConfigSet(pin, strength, type);
970 
971     /* restore the pin direction */
972     MAP_PinDirModeSet(pin, (unsigned long)direction);
973 }
974 
975 /*
976  *  ======== PowerCC32XX_restoreParkState ========
977  *  Restore the LPDS park state for a pin
978  */
PowerCC32XX_restoreParkState(PowerCC32XX_Pin pin,PowerCC32XX_ParkState state)979 void PowerCC32XX_restoreParkState(PowerCC32XX_Pin pin,
980     PowerCC32XX_ParkState state)
981 {
982     PowerCC32XX_ParkInfo parkInfo;
983     uint32_t i;
984 
985     DebugP_assert(PowerCC32XX_config.numPins < PowerCC32XX_NUMPINS + 1);
986 
987     /* step thru the park array until find the pin to be updated */
988     for (i = 0; i < PowerCC32XX_config.numPins; i++) {
989 
990         parkInfo = PowerCC32XX_config.pinParkDefs[i];
991 
992         /* if this is the pin to be restored... */
993         if (parkInfo.pin == pin) {
994             parkInfo.parkState = state;
995             PowerCC32XX_config.pinParkDefs[i] = parkInfo;
996             break;
997         }
998     }
999 }
1000 
1001 /*
1002  *  ======== PowerCC32XX_setParkState ========
1003  *  Set a new LPDS park state for a pin
1004  */
PowerCC32XX_setParkState(PowerCC32XX_Pin pin,uint32_t level)1005 void PowerCC32XX_setParkState(PowerCC32XX_Pin pin, uint32_t level)
1006 {
1007     PowerCC32XX_ParkInfo parkInfo;
1008     PowerCC32XX_ParkState state;
1009     uint32_t i;
1010 
1011     DebugP_assert(PowerCC32XX_config.numPins < PowerCC32XX_NUMPINS + 1);
1012 
1013     /* first check if level indicates "don't park" */
1014     if (level == ~1) {
1015         state = PowerCC32XX_DONT_PARK;
1016     }
1017 
1018     /* else, check device revision to choose park state */
1019     /* if ES2.00 or later, drive the pin */
1020     else if((HWREG(0x00000400) & 0xFFFF) >= 2) {
1021         state = (level) ? PowerCC32XX_DRIVE_HIGH : PowerCC32XX_DRIVE_LOW;
1022     }
1023     /* else, for earlier devices use the weak pull resistor */
1024     else {
1025         state = (level) ? PowerCC32XX_WEAK_PULL_UP_STD :
1026                 PowerCC32XX_WEAK_PULL_DOWN_STD;
1027     }
1028 
1029     /* step thru the park array until find the pin to be updated */
1030     for (i = 0; i < PowerCC32XX_config.numPins; i++) {
1031 
1032         parkInfo = PowerCC32XX_config.pinParkDefs[i];
1033 
1034         /* if this is the pin to be updated... */
1035         if (parkInfo.pin == pin) {
1036             parkInfo.parkState = state;
1037             PowerCC32XX_config.pinParkDefs[i] = parkInfo;
1038             break;
1039         }
1040     }
1041 }
1042 
1043 /*
1044  *  ======== PowerCC32XX_shutdownSSPI ========
1045  *  Put SPI flash into Deep Power Down mode
1046  */
PowerCC32XX_shutdownSSPI(void)1047 void PowerCC32XX_shutdownSSPI(void)
1048 {
1049     unsigned long status = 0;
1050 
1051     /* Acquire SSPI HwSpinlock. */
1052     if (0 != MAP_HwSpinLockTryAcquire(HWSPINLOCK_SSPI, PowerCC32XX_SSPISemaphoreTakeTries)){
1053         return;
1054     }
1055 
1056     /* Gate MCSPI clock */
1057     HWREG(ARCM_BASE + APPS_RCM_O_MCSPI_S0_CLK_GATING) = 0x0;
1058 
1059     /* Enable clock for SSPI module */
1060     MAP_PRCMPeripheralClkEnable(PRCM_SSPI, PRCM_RUN_MODE_CLK);
1061 
1062     /* Reset SSPI at PRCM level and wait for reset to complete */
1063     MAP_PRCMPeripheralReset(PRCM_SSPI);
1064     while(MAP_PRCMPeripheralStatusGet(PRCM_SSPI)== false){
1065     }
1066 
1067     /* Reset SSPI at module level */
1068     MAP_SPIReset(SSPI_BASE);
1069 
1070     /* Configure SSPI module */
1071     MAP_SPIConfigSetExpClk(SSPI_BASE,PRCMPeripheralClockGet(PRCM_SSPI),
1072                     20000000,SPI_MODE_MASTER,SPI_SUB_MODE_0,
1073                     (SPI_SW_CTRL_CS |
1074                     SPI_4PIN_MODE |
1075                     SPI_TURBO_OFF |
1076                     SPI_CS_ACTIVELOW |
1077                     SPI_WL_8));
1078 
1079     /* Enable SSPI module */
1080     MAP_SPIEnable(SSPI_BASE);
1081 
1082     /* Ungate MCSPI clock */
1083     HWREG(ARCM_BASE + APPS_RCM_O_MCSPI_S0_CLK_GATING) = 0x1;
1084 
1085     /* Allow settling before enabling chip select */
1086     uSEC_DELAY(PowerCC32XX_SSPICSDelay);
1087 
1088     /* Enable chip select for the spi flash. */
1089     MAP_SPICSEnable(SSPI_BASE);
1090 
1091     /* Wait for spi flash. */
1092     do{
1093         /* Send status register read instruction and read back a dummy byte. */
1094         MAP_SPIDataPut(SSPI_BASE,PowerCC32XX_SSPIReadStatusInstruction);
1095         MAP_SPIDataGet(SSPI_BASE,&status);
1096 
1097         /* Write a dummy byte then read back the actual status. */
1098         MAP_SPIDataPut(SSPI_BASE,0xFF);
1099         MAP_SPIDataGet(SSPI_BASE,&status);
1100     } while((status & 0xFF )== STATUS_BUSY);
1101 
1102     /* Disable chip select for the spi flash. */
1103     MAP_SPICSDisable(SSPI_BASE);
1104 
1105     /* Start another CS enable sequence for Power down command. */
1106     MAP_SPICSEnable(SSPI_BASE);
1107 
1108     /* Send Deep Power Down command to spi flash */
1109     MAP_SPIDataPut(SSPI_BASE,PowerCC32XX_SSPIPowerDownInstruction);
1110 
1111     /* Disable chip select for the spi flash. */
1112     MAP_SPICSDisable(SSPI_BASE);
1113 
1114     /* Release SSPI HwSpinlock. */
1115     MAP_HwSpinLockRelease(HWSPINLOCK_SSPI);
1116 
1117     return;
1118 }
1119 
1120 /*
1121  *  ======== PowerCC32XX_reset ========
1122  *  Software reset of specific peripheral.
1123  */
PowerCC32XX_reset(uint_fast16_t resourceId)1124 int_fast16_t PowerCC32XX_reset(uint_fast16_t resourceId)
1125 {
1126     int_fast16_t status = Power_SOK;
1127     uint32_t id;
1128 
1129     /* Ensure resourceId is valid */
1130     if (resourceId >= PowerCC32XX_NUMRESOURCES) {
1131         status = Power_EINVALIDINPUT;
1132     }
1133 
1134     /* resourceId is OK ... */
1135     else {
1136 
1137         id = PowerCC32XX_module.dbRecords[resourceId];
1138         /* Reset the peripheral */
1139         MAP_PRCMPeripheralReset(id);
1140     }
1141     return (status);
1142 }
1143 
1144 /*************************internal functions ****************************/
1145 
1146 /*
1147  *  ======== notify ========
1148  *  Note: When this function is called hardware interrupts are disabled
1149  */
notify(uint_fast16_t eventType)1150 static int_fast16_t notify(uint_fast16_t eventType)
1151 {
1152     int_fast16_t notifyStatus;
1153     Power_NotifyFxn notifyFxn;
1154     uintptr_t clientArg;
1155     List_Elem *elem;
1156 
1157     /* if queue is empty, return immediately */
1158     if (!List_empty(&PowerCC32XX_module.notifyList)) {
1159         /* point to first client notify object */
1160         elem = List_head(&PowerCC32XX_module.notifyList);
1161 
1162         /* walk the queue and notify each registered client of the event */
1163         do {
1164             if (((Power_NotifyObj *)elem)->eventTypes & eventType) {
1165                 /* pull params from notify object */
1166                 notifyFxn = ((Power_NotifyObj *)elem)->notifyFxn;
1167                 clientArg = ((Power_NotifyObj *)elem)->clientArg;
1168 
1169                 /* call the client's notification function */
1170                 notifyStatus = (int_fast16_t) (*(Power_NotifyFxn)notifyFxn)(
1171                     eventType, 0, clientArg);
1172 
1173                 /* if client declared error stop all further notifications */
1174                 if (notifyStatus != Power_NOTIFYDONE) {
1175                     return (Power_EFAIL);
1176                 }
1177             }
1178 
1179             /* get next element in the notification queue */
1180             elem = List_next(elem);
1181 
1182         } while (elem != NULL);
1183     }
1184 
1185     return (Power_SOK);
1186 }
1187 
1188 /*
1189  *  ======== restoreNVICRegs ========
1190  *  Restore the NVIC registers
1191  */
restoreNVICRegs(void)1192 static void restoreNVICRegs(void)
1193 {
1194     uint32_t i;
1195     uint32_t *base_reg_addr;
1196 
1197     /* Restore the NVIC control registers */
1198     HWREG(NVIC_VTABLE) = PowerCC32XX_contextSave.nvicRegs.vectorTable;
1199     HWREG(NVIC_ACTLR) = PowerCC32XX_contextSave.nvicRegs.auxCtrl;
1200     HWREG(NVIC_APINT) = PowerCC32XX_contextSave.nvicRegs.appInt;
1201     HWREG(NVIC_INT_CTRL) = PowerCC32XX_contextSave.nvicRegs.intCtrlState;
1202     HWREG(NVIC_SYS_CTRL) = PowerCC32XX_contextSave.nvicRegs.sysCtrl;
1203     HWREG(NVIC_CFG_CTRL) = PowerCC32XX_contextSave.nvicRegs.configCtrl;
1204     HWREG(NVIC_SYS_PRI1) = PowerCC32XX_contextSave.nvicRegs.sysPri1;
1205     HWREG(NVIC_SYS_PRI2) = PowerCC32XX_contextSave.nvicRegs.sysPri2;
1206     HWREG(NVIC_SYS_PRI3) = PowerCC32XX_contextSave.nvicRegs.sysPri3;
1207     HWREG(NVIC_SYS_HND_CTRL) = PowerCC32XX_contextSave.nvicRegs.sysHcrs;
1208 
1209     /* Systick registers */
1210     HWREG(NVIC_ST_CTRL) = PowerCC32XX_contextSave.nvicRegs.systickCtrl;
1211     HWREG(NVIC_ST_RELOAD) = PowerCC32XX_contextSave.nvicRegs.systickReload;
1212     HWREG(NVIC_ST_CAL) = PowerCC32XX_contextSave.nvicRegs.systickCalib;
1213 
1214     /* Restore the interrupt priority registers */
1215     base_reg_addr = (uint32_t *)NVIC_PRI0;
1216     for(i = 0; i < PowerCC32XX_numNVICIntPriority; i++) {
1217         base_reg_addr[i] = PowerCC32XX_contextSave.nvicRegs.intPriority[i];
1218     }
1219 
1220     /* Restore the interrupt enable registers */
1221     base_reg_addr = (uint32_t *)NVIC_EN0;
1222     for(i = 0; i < PowerCC32XX_numNVICSetEnableRegs; i++) {
1223         base_reg_addr[i] = PowerCC32XX_contextSave.nvicRegs.intSetEn[i];
1224     }
1225 
1226     /* Data and instruction sync barriers */
1227     SYNCBARRIER();
1228 }
1229 
1230 /*
1231  *  ======== restorePeriphClocks ========
1232  *  Restores the peripheral clocks that had dependency set
1233  */
restorePeriphClocks(void)1234 static void restorePeriphClocks(void)
1235 {
1236     uint32_t dependCount;
1237     uint32_t i;
1238 
1239     /* need to re-enable peripheral clocks to those with set dependency */
1240     for (i = 0; i < PowerCC32XX_NUMRESOURCES; i++) {
1241         dependCount = Power_getDependencyCount(i);
1242         if (dependCount > 0) {
1243             MAP_PRCMPeripheralClkEnable(PowerCC32XX_module.dbRecords[i],
1244                 PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
1245 
1246             while(!MAP_PRCMPeripheralStatusGet(PowerCC32XX_module.dbRecords[i])) {
1247             }
1248         }
1249     }
1250 }
1251 
1252 /*
1253  *  ======== saveNVICRegs ========
1254  *  Save away the NVIC registers for LPDS mode.
1255  */
saveNVICRegs(void)1256 static void saveNVICRegs(void)
1257 {
1258     uint32_t i;
1259     uint32_t *base_reg_addr;
1260 
1261     /* Save the NVIC control registers */
1262     PowerCC32XX_contextSave.nvicRegs.vectorTable = HWREG(NVIC_VTABLE);
1263     PowerCC32XX_contextSave.nvicRegs.auxCtrl = HWREG(NVIC_ACTLR);
1264     PowerCC32XX_contextSave.nvicRegs.intCtrlState = HWREG(NVIC_INT_CTRL);
1265     PowerCC32XX_contextSave.nvicRegs.appInt = HWREG(NVIC_APINT);
1266     PowerCC32XX_contextSave.nvicRegs.sysCtrl = HWREG(NVIC_SYS_CTRL);
1267     PowerCC32XX_contextSave.nvicRegs.configCtrl = HWREG(NVIC_CFG_CTRL);
1268     PowerCC32XX_contextSave.nvicRegs.sysPri1 = HWREG(NVIC_SYS_PRI1);
1269     PowerCC32XX_contextSave.nvicRegs.sysPri2 = HWREG(NVIC_SYS_PRI2);
1270     PowerCC32XX_contextSave.nvicRegs.sysPri3 = HWREG(NVIC_SYS_PRI3);
1271     PowerCC32XX_contextSave.nvicRegs.sysHcrs = HWREG(NVIC_SYS_HND_CTRL);
1272 
1273     /* Systick registers */
1274     PowerCC32XX_contextSave.nvicRegs.systickCtrl = HWREG(NVIC_ST_CTRL);
1275     PowerCC32XX_contextSave.nvicRegs.systickReload = HWREG(NVIC_ST_RELOAD);
1276     PowerCC32XX_contextSave.nvicRegs.systickCalib = HWREG(NVIC_ST_CAL);
1277 
1278     /* Save the interrupt enable registers */
1279     base_reg_addr = (uint32_t *)NVIC_EN0;
1280     for (i = 0; i < PowerCC32XX_numNVICSetEnableRegs; i++) {
1281         PowerCC32XX_contextSave.nvicRegs.intSetEn[i] = base_reg_addr[i];
1282     }
1283 
1284     /* Save the interrupt priority registers */
1285     base_reg_addr = (uint32_t *)NVIC_PRI0;
1286     for (i = 0; i < PowerCC32XX_numNVICIntPriority; i++) {
1287         PowerCC32XX_contextSave.nvicRegs.intPriority[i] = base_reg_addr[i];
1288     }
1289 }
1290 
1291 /*
1292  *  ======== parkPins ========
1293  */
parkPins(void)1294 static void parkPins(void)
1295 {
1296     PowerCC32XX_ParkInfo parkInfo;
1297     uint32_t antpadreg;
1298     uint32_t i;
1299 
1300     DebugP_assert(PowerCC32XX_config.numPins < PowerCC32XX_NUMPINS + 1);
1301 
1302     /* for each pin in the park array ... */
1303     for (i = 0; i < PowerCC32XX_config.numPins; i++) {
1304 
1305         parkInfo = PowerCC32XX_config.pinParkDefs[i];
1306 
1307         /* skip this pin if "don't park" is specified */
1308         if (parkInfo.parkState == PowerCC32XX_DONT_PARK) {
1309             continue;
1310         }
1311 
1312         /* if this is a special antenna select pin, stash current pad state */
1313         if (parkInfo.pin == PowerCC32XX_PIN29) {
1314             antpadreg = 0x4402E108;
1315             PowerCC32XX_module.stateAntPin29 = (uint16_t) HWREG(antpadreg);
1316         }
1317         else if (parkInfo.pin == PowerCC32XX_PIN30) {
1318             antpadreg = 0x4402E10C;
1319             PowerCC32XX_module.stateAntPin30 = (uint16_t) HWREG(antpadreg);
1320         }
1321         else {
1322             antpadreg = 0;
1323         }
1324 
1325         /* if this is antenna select pin, park via direct writes to pad reg */
1326         if (antpadreg != 0) {
1327             HWREG(antpadreg) &= 0xFFFFF0EF;     /* first clear bits 4, 8-11 */
1328             if (parkInfo.parkState == PowerCC32XX_NO_PULL_HIZ) {
1329                 HWREG(antpadreg) |= 0x00000C00;
1330             }
1331             else if (parkInfo.parkState == PowerCC32XX_WEAK_PULL_UP_STD) {
1332                 HWREG(antpadreg) |= 0x00000D00;
1333             }
1334             else if (parkInfo.parkState == PowerCC32XX_WEAK_PULL_DOWN_STD) {
1335                 HWREG(antpadreg) |= 0x00000E00;
1336             }
1337             else if (parkInfo.parkState == PowerCC32XX_WEAK_PULL_UP_OPENDRAIN) {
1338                 HWREG(antpadreg) |= 0x00000D10;
1339             }
1340             else if (parkInfo.parkState ==
1341                 PowerCC32XX_WEAK_PULL_DOWN_OPENDRAIN) {
1342                 HWREG(antpadreg) |= 0x00000E10;
1343             }
1344         }
1345 
1346         /* else, for all other pins */
1347         else {
1348 
1349             /* if pin is NOT to be driven, park it to the specified state... */
1350             if ((parkInfo.parkState != PowerCC32XX_DRIVE_LOW) &&
1351                 (parkInfo.parkState != PowerCC32XX_DRIVE_HIGH)) {
1352 
1353                 PowerCC32XX_parkPin(
1354                     (PowerCC32XX_Pin)parkInfo.pin,
1355                     (PowerCC32XX_ParkState)parkInfo.parkState,
1356                     &PowerCC32XX_module.pinType[i],
1357                     &PowerCC32XX_module.pinDir[i]);
1358             }
1359 
1360             /*
1361              * else, now check if the pin CAN be driven (pins 45, 53, and 55
1362              * can't be driven)
1363              */
1364             else if ((parkInfo.pin != PowerCC32XX_PIN45) &&
1365                      (parkInfo.pin != PowerCC32XX_PIN53) &&
1366                      (parkInfo.pin != PowerCC32XX_PIN55)){
1367 
1368                 /*
1369                  * must ensure pin mode is zero; first get/stash current mode,
1370                  * then set mode to zero
1371                  */
1372                 PowerCC32XX_module.pinMode[i] =
1373                     (uint8_t)MAP_PinModeGet(parkInfo.pin);
1374                 MAP_PinModeSet(parkInfo.pin, 0);
1375 
1376                 /* if pin is to be driven low, set the lock level to 0 */
1377                 if (parkInfo.parkState == PowerCC32XX_DRIVE_LOW) {
1378                     MAP_PinLockLevelSet((PowerCC32XX_Pin)parkInfo.pin, 0);
1379                     PowerCC32XX_module.pinLockMask |= 1 <<
1380                         PinToPadGet(parkInfo.pin);
1381                 }
1382 
1383                 /* else, pin to be driven high, set lock level to 1 */
1384                 else {
1385                     MAP_PinLockLevelSet((PowerCC32XX_Pin)parkInfo.pin, 1);
1386                     PowerCC32XX_module.pinLockMask |= 1 <<
1387                         PinToPadGet(parkInfo.pin);
1388                 }
1389             }
1390         }
1391     }
1392 
1393     /* if any pins are to be driven, lock them now */
1394     if (PowerCC32XX_module.pinLockMask) {
1395         MAP_PinLock(PowerCC32XX_module.pinLockMask);
1396     }
1397 }
1398 
1399 /*
1400  *  ======== restoreParkedPins ========
1401  */
restoreParkedPins(void)1402 static void restoreParkedPins(void)
1403 {
1404     PowerCC32XX_ParkInfo parkInfo;
1405     uint32_t i;
1406 
1407     DebugP_assert(PowerCC32XX_config.numPins < PowerCC32XX_NUMPINS + 1);
1408 
1409     /* first, unlock any locked pins (that were driven high or low) */
1410     if (PowerCC32XX_module.pinLockMask) {
1411         MAP_PinUnlock();
1412     }
1413 
1414     /* now, for each pin in the park array ... */
1415     for (i = 0; i < PowerCC32XX_config.numPins; i++) {
1416 
1417         parkInfo = PowerCC32XX_config.pinParkDefs[i];
1418 
1419         /* skip this pin if "don't park" is specified */
1420         if (parkInfo.parkState == PowerCC32XX_DONT_PARK) {
1421             continue;
1422         }
1423 
1424         /* if this is special antenna select pin: restore the saved pad state */
1425         if (parkInfo.pin == PowerCC32XX_PIN29) {
1426             HWREG(0x4402E108) = ((HWREG(0x4402E108) & 0xFFFFF000) |
1427                   (PowerCC32XX_module.stateAntPin29 & 0x00000FFF));
1428         }
1429 
1430         else if (parkInfo.pin == PowerCC32XX_PIN30) {
1431             HWREG(0x4402E10C) = ((HWREG(0x4402E10C) & 0xFFFFF000) |
1432                   (PowerCC32XX_module.stateAntPin30 & 0x00000FFF));
1433         }
1434 
1435         /* else if pin was driven during LPDS, restore the pin mode */
1436         else if ((parkInfo.parkState == PowerCC32XX_DRIVE_LOW) ||
1437             (parkInfo.parkState == PowerCC32XX_DRIVE_HIGH)) {
1438             MAP_PinModeSet(parkInfo.pin,
1439                 (unsigned long)PowerCC32XX_module.pinMode[i]);
1440         }
1441 
1442         /* else, restore all others */
1443         else {
1444             /* if pin parked in a non-driven state, restore type & direction */
1445             if ((parkInfo.parkState != PowerCC32XX_DRIVE_LOW) &&
1446                 (parkInfo.parkState != PowerCC32XX_DRIVE_HIGH)) {
1447 
1448                 PowerCC32XX_restoreParkedPin(
1449                     (PowerCC32XX_Pin)parkInfo.pin,
1450                     PowerCC32XX_module.pinType[i],
1451                     PowerCC32XX_module.pinDir[i]);
1452             }
1453         }
1454     }
1455 }
1456