1 //*****************************************************************************
2 //
3 //  am_hal_sysctrl.c
4 //! @file
5 //!
6 //! @brief Functions for interfacing with the M4F system control registers
7 //!
8 //! @addtogroup sysctrl2 System Control (SYSCTRL)
9 //! @ingroup apollo2hal
10 //! @{
11 //
12 //*****************************************************************************
13 
14 //*****************************************************************************
15 //
16 // Copyright (c) 2017, Ambiq Micro
17 // All rights reserved.
18 //
19 // Redistribution and use in source and binary forms, with or without
20 // modification, are permitted provided that the following conditions are met:
21 //
22 // 1. Redistributions of source code must retain the above copyright notice,
23 // this list of conditions and the following disclaimer.
24 //
25 // 2. Redistributions in binary form must reproduce the above copyright
26 // notice, this list of conditions and the following disclaimer in the
27 // documentation and/or other materials provided with the distribution.
28 //
29 // 3. Neither the name of the copyright holder nor the names of its
30 // contributors may be used to endorse or promote products derived from this
31 // software without specific prior written permission.
32 //
33 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
34 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
37 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
38 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
39 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
40 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
41 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
43 // POSSIBILITY OF SUCH DAMAGE.
44 //
45 // This is part of revision 1.2.11 of the AmbiqSuite Development Package.
46 //
47 //*****************************************************************************
48 
49 #include <stdint.h>
50 #include <stdbool.h>
51 #include "am_mcu_apollo.h"
52 
53 //*****************************************************************************
54 //
55 //  Local macro constants
56 //
57 //*****************************************************************************
58 //
59 // Define ZX workaround values.
60 // These values are defined by the factory.
61 //
62 #define COREZXVALUE         0x07
63 #define MEMZXVALUE          0x07
64 
65 //
66 // Define values for g_ui32CoreBuck, which indicates which timer carries
67 // the signal for the CORE Buck, and which also implies that the other timer
68 // carries the signal for the MEM buck.
69 //
70 #define COREBUCK_TIMERA     1       // Core buck signal comes in on timer A
71 #define COREBUCK_TIMERB     2       // Core buck signal comes in on timer B
72 
73 //
74 // Define the bit values for static function g_buckZX_chk;
75 //
76 #define CHKBUCKZX_BUCKS     0x01    // The bucks are enabled
77 #define CHKBUCKZX_REV       0x02    // This chip rev needs the workaround
78 #define CHKBUCKZX_TIMER     0x04    // A valid timer has been allocated
79 #define CHKBUCKZX_DEVEN     0x08    // Devices are powered up and enabled
80 
81 //*****************************************************************************
82 //
83 //  Prototypes
84 //
85 //*****************************************************************************
86 static void am_hal_sysctrl_buckA_ctimer_isr(void);
87 static void am_hal_sysctrl_buckB_ctimer_isr(void);
88 
89 //*****************************************************************************
90 //
91 //  Globals
92 //
93 //*****************************************************************************
94 static volatile uint32_t g_ui32BuckTimer = 0;
95 static volatile uint32_t g_ui32BuckInputs = 0;
96 static volatile bool     g_bBuckRestoreComplete = false;
97 static volatile bool     g_bBuckTimed = false;
98 static          uint32_t g_ui32SaveCoreBuckZX, g_ui32SaveMemBuckZX;
99 static          uint32_t g_buckZX_chk = 0;
100 static volatile uint32_t g_ui32CoreBuck;
101 
102 //
103 // Timer configuration for BUCK inputs.
104 //
105 static const am_hal_ctimer_config_t g_sBuckTimer =
106 {
107     // Don't link timers.
108     0,
109 
110     // Set up Timer0A.
111     (AM_HAL_CTIMER_FN_ONCE      |
112      AM_HAL_CTIMER_INT_ENABLE   |
113      AM_HAL_CTIMER_BUCK),
114 
115     // Set up Timer0B.
116     (AM_HAL_CTIMER_FN_ONCE      |
117      AM_HAL_CTIMER_INT_ENABLE   |
118      AM_HAL_CTIMER_BUCK),
119 };
120 
121 //*****************************************************************************
122 //
123 // Determine if we need to do the zero cross workaround on this device.
124 // Three criteria are used.  All three must be true.
125 //  1. Are the bucks enabled?
126 //  2. Is the chip rev appropriate for the workaround?
127 //  3. Has a timer been allocated to do the workaround?
128 //  4. Are certain peripherals powered up?
129 //
130 // Saves the bitmask to the global g_buckZX_chk.
131 // Bitmask bits are defined as: CHKBUCKZX_BUCKS, CHKBUCKZX_REV, CHKBUCKZX_TIMER.
132 //
133 // Returns true if all criteria are met, false otherwise.
134 // g_buckZX_chk can be probed to determine which criteria passed or failed.
135 //
136 //*****************************************************************************
137 static bool
buckZX_chk(void)138 buckZX_chk(void)
139 {
140     uint32_t ui32SupplySrc;
141 
142     //
143     // Is this chip rev appropriate to do the workaround?
144     //
145     g_buckZX_chk = AM_BFM(MCUCTRL, CHIPREV, REVMAJ) == AM_REG_MCUCTRL_CHIPREV_REVMAJ_B ?
146                    CHKBUCKZX_REV : 0x0;
147 
148     //
149     // Has a timer been configured to handle the workaround?
150     //
151     g_buckZX_chk |= ( g_ui32BuckTimer - 1 ) <= BUCK_TIMER_MAX ?
152                     CHKBUCKZX_TIMER : 0x0;
153 
154     //
155     // Are either or both of the bucks actually enabled?
156     //
157     ui32SupplySrc = AM_REG(PWRCTRL, SUPPLYSRC);
158 
159     g_buckZX_chk |= (ui32SupplySrc &
160                     (AM_REG_PWRCTRL_SUPPLYSRC_COREBUCKEN_M  |
161                      AM_REG_PWRCTRL_SUPPLYSRC_MEMBUCKEN_M) ) ?
162                      CHKBUCKZX_BUCKS : 0x0;
163 
164     //
165     // Finally, if any peripheral is already powered up, we don't need to do the
166     //  ZX workaround because in this case the bucks remain in active mode.
167     //
168     ui32SupplySrc = AM_REG(PWRCTRL, DEVICEEN);
169 
170     g_buckZX_chk |= ( ui32SupplySrc &
171             (AM_REG_PWRCTRL_DEVICEEN_PDM_M          |
172              AM_REG_PWRCTRL_DEVICEEN_UART1_M        |
173              AM_REG_PWRCTRL_DEVICEEN_UART0_M        |
174              AM_REG_PWRCTRL_DEVICEEN_IO_MASTER5_M   |
175              AM_REG_PWRCTRL_DEVICEEN_IO_MASTER4_M   |
176              AM_REG_PWRCTRL_DEVICEEN_IO_MASTER3_M   |
177              AM_REG_PWRCTRL_DEVICEEN_IO_MASTER2_M   |
178              AM_REG_PWRCTRL_DEVICEEN_IO_MASTER1_M   |
179              AM_REG_PWRCTRL_DEVICEEN_IO_MASTER0_M   |
180              AM_REG_PWRCTRL_DEVICEEN_IO_SLAVE_M) )      ?
181                 0x0 : CHKBUCKZX_DEVEN;
182 
183     //
184     // If all 4 criteria were met, we're good to do the workaround.
185     //
186     return ( g_buckZX_chk ==
187              (CHKBUCKZX_BUCKS | CHKBUCKZX_REV |
188               CHKBUCKZX_TIMER | CHKBUCKZX_DEVEN) ) ? true : false;
189 }
190 
191 //*****************************************************************************
192 //
193 // Set the buck zero cross settings to the values given.
194 //
195 // ui32Flags, one or more of the following:
196 //  SETBUCKZX_USE_PROVIDED_SETTINGS - Use the values provided in the parameters
197 //                                    to set the trim value(s).
198 //  SETBUCKZX_USE_SAVED_SETTINGS    - Use the values that were previously saved
199 //                                    to set the trim value(s).
200 //  SETBUCKZX_SAVE_CURR_SETTINGS    - Save the current trim values before
201 //                                    setting the new ones.
202 //  SETBUCKZX_RESTORE_CORE_ONLY     - Restore the Core trim and save the current
203 //                                    value of the core buck trim iff
204 //                                    SETBUCKZX_SAVE_CURR_SETTINGS is set.
205 //  SETBUCKZX_RESTORE_MEM_ONLY      - Restore the Mem trim and save the current
206 //                                    value of the mem buck trim iff
207 //                                    SETBUCKZX_SAVE_CURR_SETTINGS is set.
208 //  SETBUCKZX_RESTORE_BOTH          - Restore both buck trims and save the
209 //                                    current value of both iff
210 //                                    SETBUCKZX_SAVE_CURR_SETTINGS is set.
211 //
212 //*****************************************************************************
213 #define SETBUCKZX_USE_PROVIDED_SETTINGS 0x01
214 #define SETBUCKZX_USE_SAVED_SETTINGS    0x02
215 #define SETBUCKZX_SAVE_CURR_SETTINGS    0x04
216 #define SETBUCKZX_RESTORE_CORE_ONLY     0x10
217 #define SETBUCKZX_RESTORE_MEM_ONLY      0x20
218 #define SETBUCKZX_RESTORE_BOTH          ( SETBUCKZX_RESTORE_CORE_ONLY |     \
219                                           SETBUCKZX_RESTORE_MEM_ONLY )
220 static void
setBuckZX(uint32_t ui32CoreBuckZX,uint32_t ui32MemBuckZX,uint32_t ui32Flags)221 setBuckZX(uint32_t ui32CoreBuckZX, uint32_t ui32MemBuckZX, uint32_t ui32Flags)
222 {
223     uint32_t ui32SaveCore, ui32SaveMem, ui32NewCore, ui32NewMem;
224     bool bDoRestore = false;
225 
226     //
227     // Begin critical section.
228     //
229     AM_CRITICAL_BEGIN_ASM
230 
231     //
232     // Get the current zero cross trim values.
233     //
234     ui32SaveCore = AM_BFR(MCUCTRL, BUCK3, COREBUCKZXTRIM);
235     ui32SaveMem  = AM_BFR(MCUCTRL, BUCK3, MEMBUCKZXTRIM);
236 
237     //
238     // Determine which values will be restored.
239     //
240     if ( ui32Flags & SETBUCKZX_USE_SAVED_SETTINGS )
241     {
242         //
243         // Use saved settings
244         //
245         ui32NewCore = g_ui32SaveCoreBuckZX;
246         ui32NewMem  = g_ui32SaveMemBuckZX;
247         bDoRestore = true;
248     }
249     else if ( ui32Flags & SETBUCKZX_USE_PROVIDED_SETTINGS )
250     {
251         //
252         // Use settings provided in the call parameters
253         //
254         ui32NewCore = ui32CoreBuckZX;
255         ui32NewMem  = ui32MemBuckZX;
256         bDoRestore = true;
257     }
258 
259     //
260     // Restore the buck Core and Mem trim registers.
261     //
262     if ( bDoRestore )
263     {
264         if ( ui32Flags & SETBUCKZX_RESTORE_CORE_ONLY )
265         {
266             AM_BFW(MCUCTRL, BUCK3, COREBUCKZXTRIM, ui32NewCore);
267         }
268 
269         if ( ui32Flags & SETBUCKZX_RESTORE_MEM_ONLY )
270         {
271             AM_BFW(MCUCTRL, BUCK3, MEMBUCKZXTRIM,  ui32NewMem);
272         }
273     }
274 
275     if ( ui32Flags & SETBUCKZX_SAVE_CURR_SETTINGS )
276     {
277         //
278         // Save off the zero cross values as read on entry to the function.
279         //
280         if ( ui32Flags & SETBUCKZX_RESTORE_CORE_ONLY )
281         {
282             g_ui32SaveCoreBuckZX = ui32SaveCore;
283         }
284 
285         if ( ui32Flags & SETBUCKZX_RESTORE_MEM_ONLY )
286         {
287             g_ui32SaveMemBuckZX  = ui32SaveMem;
288         }
289     }
290 
291     //
292     // Done with critical section.
293     //
294     AM_CRITICAL_END_ASM
295 }
296 
297 //*****************************************************************************
298 //
299 //! @brief Place the core into sleep or deepsleep.
300 //!
301 //! @param bSleepDeep - False for Normal or True Deep sleep.
302 //!
303 //! This function puts the MCU to sleep or deepsleep depending on bSleepDeep.
304 //!
305 //! Valid values for bSleepDeep are:
306 //!
307 //!     AM_HAL_SYSCTRL_SLEEP_NORMAL
308 //!     AM_HAL_SYSCTRL_SLEEP_DEEP
309 //!
310 //! @return None.
311 //
312 //*****************************************************************************
313 void
am_hal_sysctrl_sleep(bool bSleepDeep)314 am_hal_sysctrl_sleep(bool bSleepDeep)
315 {
316     uint32_t ui32Critical;
317 //  uint32_t ui32DebugGpioSleep = g_ui32DebugGpioSleep - 1;
318     bool bBuckZX_chk;
319     volatile uint32_t ui32BuckTimer;
320 
321     //
322     // Disable interrupts and save the previous interrupt state.
323     //
324     ui32Critical = am_hal_interrupt_master_disable();
325 
326     //
327     // If the user selected DEEPSLEEP and the TPIU is off, attempt to enter
328     // DEEP SLEEP.
329     //
330     if ((bSleepDeep == AM_HAL_SYSCTRL_SLEEP_DEEP) &&
331         (AM_BFM(MCUCTRL, TPIUCTRL, ENABLE) == AM_REG_MCUCTRL_TPIUCTRL_ENABLE_DIS))
332     {
333         //
334         // Prepare the core for deepsleep (write 1 to the DEEPSLEEP bit).
335         //
336         AM_BFW(SYSCTRL, SCR, SLEEPDEEP, 1);
337 
338         //
339         // Check if special buck handling is needed
340         //
341         bBuckZX_chk = buckZX_chk();
342 
343         if ( bBuckZX_chk )
344         {
345             ui32BuckTimer = g_ui32BuckTimer - 1;
346 
347             //
348             // Before going to sleep, clear the buck timers.
349             // This will also handle the case where we're going back to
350             // sleep before the buck sequence has even completed.
351             //
352             am_hal_ctimer_clear(ui32BuckTimer, AM_HAL_CTIMER_BOTH);
353 
354             //
355             // Set CMPR0 of both timerA and timerB to the period value
356             //
357             #define     TIMER_PERIOD_BUCKS  1
358             am_hal_ctimer_period_set(ui32BuckTimer,
359                                      AM_HAL_CTIMER_BOTH,
360                                      TIMER_PERIOD_BUCKS |
361                                      (TIMER_PERIOD_BUCKS << 16),
362                                      0);
363 
364             //
365             // Disable bucks before going to sleep.
366             //
367             am_hal_pwrctrl_bucks_disable();
368         }
369 
370         //
371         // Execute the sleep instruction.
372         //
373         AM_ASM_WFI;
374 
375         //
376         // Return from sleep
377         //
378         if ( bBuckZX_chk )
379         {
380             //
381             // Adjust the core and mem trims
382             //
383             setBuckZX(COREZXVALUE, MEMZXVALUE,
384                       SETBUCKZX_USE_PROVIDED_SETTINGS   |
385                       SETBUCKZX_RESTORE_BOTH );
386 
387             //
388             // Delay for 2us before enabling bucks.
389             //
390             am_hal_flash_delay( FLASH_CYCLES_US(2) );
391 
392             //
393             // Turn on the bucks
394             //
395             am_hal_pwrctrl_bucks_enable();
396 
397             //
398             // Get the actual timer number
399             //
400             ui32BuckTimer = g_ui32BuckTimer - 1;
401 
402             //
403             // Initialize the complete flag
404             //
405             g_bBuckRestoreComplete = false;
406 
407             //
408             // Initialize the input flags
409             //
410             g_ui32BuckInputs = 0;
411 
412             //
413             // Delay for 5us to make sure we're receiving clean buck signals.
414             //
415             am_hal_flash_delay( FLASH_CYCLES_US(5) );
416 
417             //
418             // Start timers (set the enable bit, clear the clear bit)
419             //
420             am_hal_ctimer_start(ui32BuckTimer, AM_HAL_CTIMER_BOTH);
421         }
422         else
423         {
424             //
425             // Since we're not doing anything, we're done, so set the done flag.
426             //
427             g_bBuckRestoreComplete = true;
428         }
429     }
430     else
431     {
432         //
433         // Prepare the core for normal sleep (write 0 to the DEEPSLEEP bit).
434         //
435         AM_BFW(SYSCTRL, SCR, SLEEPDEEP, 0);
436 
437         //
438         // Go to sleep.
439         //
440         AM_ASM_WFI;
441     }
442 
443     //
444     // Restore the interrupt state.
445     //
446     am_hal_interrupt_master_set(ui32Critical);
447 }
448 
449 //*****************************************************************************
450 //
451 //! @brief Enable the floating point module.
452 //!
453 //! Call this function to enable the ARM hardware floating point module.
454 //!
455 //! @return None.
456 //
457 //*****************************************************************************
458 void
am_hal_sysctrl_fpu_enable(void)459 am_hal_sysctrl_fpu_enable(void)
460 {
461     //
462     // Enable access to the FPU in both privileged and user modes.
463     // NOTE: Write 0s to all reserved fields in this register.
464     //
465     AM_REG(SYSCTRL, CPACR) = (AM_REG_SYSCTRL_CPACR_CP11(0x3) |
466                              AM_REG_SYSCTRL_CPACR_CP10(0x3));
467 }
468 
469 //*****************************************************************************
470 //
471 //! @brief Disable the floating point module.
472 //!
473 //! Call this function to disable the ARM hardware floating point module.
474 //!
475 //! @return None.
476 //
477 //*****************************************************************************
478 void
am_hal_sysctrl_fpu_disable(void)479 am_hal_sysctrl_fpu_disable(void)
480 {
481     //
482     // Disable access to the FPU in both privileged and user modes.
483     // NOTE: Write 0s to all reserved fields in this register.
484     //
485     AM_REG(SYSCTRL, CPACR) = 0x00000000                     &
486                           ~(AM_REG_SYSCTRL_CPACR_CP11(0x3) |
487                             AM_REG_SYSCTRL_CPACR_CP10(0x3));
488 }
489 
490 //*****************************************************************************
491 //
492 //! @brief Enable stacking of FPU registers on exception entry.
493 //!
494 //! @param bLazy - Set to "true" to enable "lazy stacking".
495 //!
496 //! This function allows the core to save floating-point information to the
497 //! stack on exception entry. Setting the bLazy option enables "lazy stacking"
498 //! for interrupt handlers.  Normally, mixing floating-point code and interrupt
499 //! driven routines causes increased interrupt latency, because the core must
500 //! save extra information to the stack upon exception entry. With the lazy
501 //! stacking option enabled, the core will skip the saving of floating-point
502 //! registers when possible, reducing average interrupt latency.
503 //!
504 //! @note This function should be called before the floating-point module is
505 //! used in interrupt-driven code. If it is not called, the core will not have
506 //! any way to save context information for floating-point variables on
507 //! exception entry.
508 //!
509 //! @return None.
510 //
511 //*****************************************************************************
512 void
am_hal_sysctrl_fpu_stacking_enable(bool bLazy)513 am_hal_sysctrl_fpu_stacking_enable(bool bLazy)
514 {
515     if ( bLazy )
516     {
517         //
518         // Enable automatic saving of FPU registers on exception entry, using lazy
519         // context saving.
520         //
521         AM_REG(SYSCTRL, FPCCR) |= (AM_REG_SYSCTRL_FPCCR_ASPEN(0x1) |
522                                    AM_REG_SYSCTRL_FPCCR_LSPEN(0x1));
523     }
524     else
525     {
526         //
527         // Enable automatic saving of FPU registers on exception entry.
528         //
529         AM_REG(SYSCTRL, FPCCR) |= AM_REG_SYSCTRL_FPCCR_ASPEN(0x1);
530     }
531 }
532 
533 //*****************************************************************************
534 //
535 //! @brief Disable FPU register stacking on exception entry.
536 //!
537 //! This function disables all stacking of floating point registers for
538 //! interrupt handlers.
539 //!
540 //! @return None.
541 //
542 //*****************************************************************************
543 void
am_hal_sysctrl_fpu_stacking_disable(void)544 am_hal_sysctrl_fpu_stacking_disable(void)
545 {
546     //
547     // Enable automatic saving of FPU registers on exception entry, using lazy
548     // context saving.
549     //
550     AM_REG(SYSCTRL, FPCCR) &= ~(AM_REG_SYSCTRL_FPCCR_ASPEN(0x1) |
551                                 AM_REG_SYSCTRL_FPCCR_LSPEN(0x1));
552 }
553 
554 //*****************************************************************************
555 //
556 //! @brief Issue a system wide reset using the AIRCR bit in the M4 system ctrl.
557 //!
558 //! This function issues a system wide reset (Apollo POR level reset).
559 //!
560 //! @return None.
561 //
562 //*****************************************************************************
563 void
am_hal_sysctrl_aircr_reset(void)564 am_hal_sysctrl_aircr_reset(void)
565 {
566     //
567     // Set the system reset bit in the AIRCR register
568     //
569     AM_REG(SYSCTRL, AIRCR) = AM_REG_SYSCTRL_AIRCR_VECTKEY(0x5FA) |
570                              AM_REG_SYSCTRL_AIRCR_SYSRESETREQ(1);
571 }
572 
573 //*****************************************************************************
574 //
575 //! @brief Buck CTimer ISR initializer.
576 //!
577 //! @param ui32BuckTimerNumber - Timer number to be used for handling the buck.
578 //!                              Must be 0-3.
579 //!
580 //! If called with an invalid timer (that is, not 0 - 3, or greater than
581 //! BUCK_TIMER_MAX), then the workaround will not be enabled.
582 //!
583 //! Instead, the bucks will be initialized with a value that will avoid the
584 //! issues described in the Errata (ERR019).  However, this will cause a
585 //! less efficient energy usage condtion.
586 //!
587 //! @return 0.
588 //
589 //*****************************************************************************
590 uint32_t
am_hal_sysctrl_buck_ctimer_isr_init(uint32_t ui32BuckTimerNumber)591 am_hal_sysctrl_buck_ctimer_isr_init(uint32_t ui32BuckTimerNumber)
592 {
593     uint32_t ui32RetVal = 0;
594 
595     //
596     // Initialize the input flags
597     //
598     g_ui32BuckInputs = 0;
599 
600     //
601     // Initialize operation complete flag
602     //
603     g_bBuckRestoreComplete = false;
604 
605     //
606     // Initialize to assume there is no valid timer.
607     //
608     g_ui32BuckTimer = 0;
609 
610     if ( ui32BuckTimerNumber > BUCK_TIMER_MAX )
611     {
612         if ( ( ui32BuckTimerNumber & 0xFFFF0000 ) ==
613              AM_HAL_SYSCTRL_BUCK_CTIMER_ZX_CONSTANT )
614         {
615             //
616             // The caller is asking for the hard option, which changes the
617             //  settings to the more noise-immune, if less efficient, settings.
618             // While we're at it, go ahead and save off the current settings.
619             //
620             if ( (ui32BuckTimerNumber & 0x0000FFFF) == 0 )
621             {
622                 setBuckZX(COREZXVALUE, MEMZXVALUE,
623                           SETBUCKZX_USE_PROVIDED_SETTINGS   |
624                           SETBUCKZX_SAVE_CURR_SETTINGS      |
625                           SETBUCKZX_RESTORE_BOTH );
626             }
627             else
628             {
629                 uint32_t ui32Core, ui32Mem;
630 
631                 //
632                 // Use the setting provided in the parameter.
633                 //
634                 ui32Core = (((ui32BuckTimerNumber & 0x001F) >> 0) - 1) & 0xF;
635                 ui32Mem  = (((ui32BuckTimerNumber & 0x1F00) >> 8) - 1) & 0xF;
636 
637                 setBuckZX(ui32Core, ui32Mem,
638                           SETBUCKZX_USE_PROVIDED_SETTINGS   |
639                           SETBUCKZX_SAVE_CURR_SETTINGS      |
640                           SETBUCKZX_RESTORE_BOTH );
641             }
642         }
643     }
644     else
645     {
646         //
647         // Save off the current trim settings (but don't change any settings).
648         //
649         setBuckZX(0, 0, SETBUCKZX_SAVE_CURR_SETTINGS | SETBUCKZX_RESTORE_BOTH);
650 
651         //
652         // The timer number will be maintained as (n + 1).  Therefore, a value
653         // of 0 saved in the global is an invalid timer.  1=timer0, 2=timer1...
654         //
655         g_ui32BuckTimer = ui32BuckTimerNumber + 1;
656 
657         //
658         // Register the timer ISRs
659         //
660         am_hal_ctimer_int_register( AM_HAL_CTIMER_INT_TIMERA0C0 <<
661                                     (ui32BuckTimerNumber * 2),
662                                      am_hal_sysctrl_buckA_ctimer_isr );
663 
664         am_hal_ctimer_int_register( AM_HAL_CTIMER_INT_TIMERB0C0 <<
665                                     (ui32BuckTimerNumber * 2),
666                                      am_hal_sysctrl_buckB_ctimer_isr );
667 
668         //
669         // Determine which timer input (A or B) is core buck and which is mem
670         // buck based on the timer number.
671         //  For CTIMER 0 & 1: Timer A is mem  buck, Timer B is core buck
672         //  For CTIMER 2 & 3: Timer A is core buck, Timer B is mem  buck
673         //
674         if ( (ui32BuckTimerNumber == 0)  ||  (ui32BuckTimerNumber == 1) )
675         {
676             //
677             // Indicate that TimerB is core buck.
678             //
679             g_ui32CoreBuck = COREBUCK_TIMERB;
680         }
681         else
682         {
683             //
684             // Indicate that TimerA is core buck
685             //
686             g_ui32CoreBuck = COREBUCK_TIMERA;
687         }
688 
689         //
690         // Clear and configure the timers
691         //
692         am_hal_ctimer_clear(ui32BuckTimerNumber, AM_HAL_CTIMER_BOTH);
693 
694         am_hal_ctimer_config(ui32BuckTimerNumber,
695                              (am_hal_ctimer_config_t*)&g_sBuckTimer);
696 
697         //
698         // Enable the interrupts for timers A and B
699         //
700         am_hal_ctimer_int_enable( (AM_HAL_CTIMER_INT_TIMERA0C0 |
701                                    AM_HAL_CTIMER_INT_TIMERB0C0 ) <<
702                                    (ui32BuckTimerNumber * 2) );
703 
704         //
705         // Enable the timer interrupt in the NVIC.
706         //
707         am_hal_interrupt_enable(AM_HAL_INTERRUPT_CTIMER);
708     }
709 
710     return ui32RetVal;
711 }
712 
713 //*****************************************************************************
714 //
715 // Get buck update complete status.
716 //
717 //*****************************************************************************
718 bool
am_hal_sysctrl_buck_update_complete(void)719 am_hal_sysctrl_buck_update_complete(void)
720 {
721     return g_bBuckRestoreComplete;
722 }
723 
724 //*****************************************************************************
725 //
726 // Buck CTIMER ISR (for handling buck switching via TimerA).
727 //
728 // Note: This handler assumes that the interrupt is cleared in am_ctimer_isr().
729 //
730 //*****************************************************************************
731 static void
am_hal_sysctrl_buckA_ctimer_isr(void)732 am_hal_sysctrl_buckA_ctimer_isr(void)
733 {
734     //
735     // Begin critical section.
736     // Although a relatively long time, the following 2us delay is critically
737     // timed for re-trimming the buck and thus cannot be extended.  Therefore,
738     // we must keep it inside the critical section.
739     //
740     AM_CRITICAL_BEGIN_ASM
741 
742     //
743     // Delay for 2us.
744     //
745     am_hal_flash_delay( FLASH_CYCLES_US(2) );
746 
747     //
748     // Determine which buck (core or mem) needs to be updated.
749     //
750     if ( g_ui32CoreBuck == COREBUCK_TIMERA )
751     {
752         //
753         // Timer A buck signal is the CORE buck.
754         // Restore the core buck.
755         //
756         setBuckZX(0, 0, SETBUCKZX_RESTORE_CORE_ONLY |
757                         SETBUCKZX_USE_SAVED_SETTINGS );
758     }
759     else
760     {
761         //
762         // Timer A buck signal is the MEM buck.
763         // Restore the mem buck.
764         //
765         setBuckZX(0, 0, SETBUCKZX_RESTORE_MEM_ONLY  |
766                         SETBUCKZX_USE_SAVED_SETTINGS );
767     }
768 
769     g_ui32BuckInputs |= 0x1;
770 
771     if ( g_ui32BuckInputs == 0x3 )
772     {
773         g_bBuckRestoreComplete = true;
774         g_ui32BuckInputs = 0;
775     }
776 
777     //
778     // End critical section.
779     //
780     AM_CRITICAL_END_ASM
781 }
782 
783 //*****************************************************************************
784 //
785 // Buck CTIMER ISR (for handling buck switching via TimerB).
786 //
787 // Note: This handler assumes that the interrupt is cleared in am_ctimer_isr().
788 //
789 //*****************************************************************************
790 static void
am_hal_sysctrl_buckB_ctimer_isr(void)791 am_hal_sysctrl_buckB_ctimer_isr(void)
792 {
793     //
794     // Begin critical section.
795     // Although a relatively long time, the following 2us delay is critically
796     // timed for re-trimming the buck and thus cannot be extended.  Therefore,
797     // we must keep it inside the critical section.
798     //
799     AM_CRITICAL_BEGIN_ASM
800 
801     //
802     // Delay for 2us.
803     //
804     am_hal_flash_delay( FLASH_CYCLES_US(2) );
805 
806     //
807     // Determine which buck (core or mem) needs to be updated.
808     //
809     if ( g_ui32CoreBuck == COREBUCK_TIMERB )
810     {
811         //
812         // Timer B buck signal is the CORE buck.
813         // Restore the core buck.
814         //
815         setBuckZX(0, 0, SETBUCKZX_RESTORE_CORE_ONLY |
816                         SETBUCKZX_USE_SAVED_SETTINGS );
817     }
818     else
819     {
820         //
821         // Timer B buck signal is the MEM buck.
822         // Restore the mem buck.
823         //
824         setBuckZX(0, 0, SETBUCKZX_RESTORE_MEM_ONLY  |
825                         SETBUCKZX_USE_SAVED_SETTINGS );
826     }
827 
828     g_ui32BuckInputs |= 0x2;
829 
830     if ( g_ui32BuckInputs == 0x3 )
831     {
832         g_bBuckRestoreComplete = true;
833         g_ui32BuckInputs = 0;
834     }
835 
836     //
837     // End critical section.
838     //
839     AM_CRITICAL_END_ASM
840 }
841 
842 //*****************************************************************************
843 //
844 // End Doxygen group.
845 //! @}
846 //
847 //*****************************************************************************
848