1 //*****************************************************************************
2 //
3 //! @file am_hal_burst.c
4 //!
5 //! @brief Functions for Controlling Burst Mode Operation.
6 //!
7 //! @addtogroup burstmode3p Burst - Burst Mode Functionality
8 //! @ingroup apollo3p_hal
9 //! @{
10 //
11 //*****************************************************************************
12 
13 //*****************************************************************************
14 //
15 // Copyright (c) 2024, Ambiq Micro, Inc.
16 // All rights reserved.
17 //
18 // Redistribution and use in source and binary forms, with or without
19 // modification, are permitted provided that the following conditions are met:
20 //
21 // 1. Redistributions of source code must retain the above copyright notice,
22 // this list of conditions and the following disclaimer.
23 //
24 // 2. Redistributions in binary form must reproduce the above copyright
25 // notice, this list of conditions and the following disclaimer in the
26 // documentation and/or other materials provided with the distribution.
27 //
28 // 3. Neither the name of the copyright holder nor the names of its
29 // contributors may be used to endorse or promote products derived from this
30 // software without specific prior written permission.
31 //
32 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
33 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
36 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
37 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
38 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
39 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
40 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42 // POSSIBILITY OF SUCH DAMAGE.
43 //
44 // This is part of revision release_sdk_3_2_0-dd5f40c14b of the AmbiqSuite Development Package.
45 //
46 //*****************************************************************************
47 
48 #include <stdint.h>
49 #include <stdbool.h>
50 #include "am_mcu_apollo.h"
51 
52 
53 #if AM_HAL_BURST_LDO_WORKAROUND
54 //
55 //! @name Series of defines for the LDO Burst Workaround
56 //!
57 //! @{
58 //
59 #define DELAY_VDDBH_CHARGE_US           10000
60 #define DELAY_BURSTLDO_ACT_US           2
61 #define DELAY_VDDS_CHARGE_US            2000
62 #define DELAY_BLEBUCK_ON_US             10
63 #define DELAY_POWER_DOMAIN_SWITCH_US    1
64 #define DELAY_BLEBUCK_OVER_REMOVAL_US   25
65 //
66 //! @}
67 //
68 #endif // AM_HAL_BURST_LDO_WORKAROUND
69 
70 //
71 //! Globals.
72 //
73 bool    g_am_hal_burst_mode_available = false;
74 #if AM_HAL_BURST_LDO_WORKAROUND
75 static bool g_bEnFromManual = false;
76 static bool g_bDisFromManual = false;
77 #endif // AM_HAL_BURST_LDO_WORKAROUND
78 
79 
80 // ****************************************************************************
81 //
82 //  am_hal_burst_mode_initialize()
83 //  Burst mode initialization function
84 //
85 // ****************************************************************************
86 uint32_t
am_hal_burst_mode_initialize(am_hal_burst_avail_e * peBurstAvail)87 am_hal_burst_mode_initialize(am_hal_burst_avail_e *peBurstAvail)
88 {
89     uint32_t    ui32Status;
90 
91 #if AM_HAL_BURST_LDO_WORKAROUND
92     //
93     // Global VDDF adjustment for VDDF+30mV
94     // Make sure there is no other place in the project VDDF is adjusted!
95     // Make sure SIMOBUCK/LDO mode is already selected before calling this function!
96     // Make sure info1 patch5 is applied, otherwise this action will not work!
97     //
98     if (PWRCTRL->MISC_b.SIMOBUCKEN == 1)
99     {
100         am_hal_pwrctrl_simobuck_vddx_active_trim_adj_default(AM_HAL_BURST_VDDF, AM_HAL_BURST_BUCK_VDDF_ADJ_CODE_30MV);
101     }
102     else
103     {
104         am_hal_pwrctrl_ldo_vddx_active_trim_adj_default(AM_HAL_BURST_VDDF, AM_HAL_BURST_LDO_VDDF_ADJ_CODE_30MV);
105     }
106 #endif // AM_HAL_BURST_LDO_WORKAROUND
107 
108     //
109     // Check if the Burst Mode feature is available based on the SKU.
110     //
111     if ( 0 == MCUCTRL->SKU_b.ALLOWBURST )
112     {
113         //
114         // Burst mode is not available.
115         //
116         g_am_hal_burst_mode_available = false;
117         *peBurstAvail = AM_HAL_BURST_NOTAVAIL;
118         return AM_HAL_STATUS_INVALID_OPERATION;
119     }
120 
121     //
122     // Enable the Burst Feature Event (DEVPWREVENTEN).
123     //
124     PWRCTRL->DEVPWREVENTEN_b.BURSTEVEN = 1;
125 
126     //
127     // Check if CLKGEN->FREQCTRL_b.BURSTREQ is already set.
128     //
129     if ( CLKGEN->FREQCTRL_b.BURSTREQ == 1 )
130     {
131         //
132         // Burst mode is already enabled, we need to turn it off first
133         //
134         AM_CRITICAL_BEGIN
135         am_hal_flash_store_ui32((uint32_t*)&CLKGEN->FREQCTRL, CLKGEN_FREQCTRL_BURSTREQ_DIS);
136         AM_CRITICAL_END
137         ui32Status = am_hal_flash_delay_status_check(10000,
138                         (uint32_t)&CLKGEN->FREQCTRL,
139                         CLKGEN_FREQCTRL_BURSTSTATUS_Msk,
140                         0,
141                         true);
142         //
143         // Something went wrong, return the error.
144         //
145         if ( ui32Status != AM_HAL_STATUS_SUCCESS )
146         {
147             return ui32Status;
148         }
149     }
150 
151     //
152     // Enable the Burst Functionality (FEATUREENABLE).
153     //
154     MCUCTRL->FEATUREENABLE_b.BURSTREQ = 1;
155 
156     ui32Status = am_hal_flash_delay_status_check(10000,
157                             (uint32_t)&MCUCTRL->FEATUREENABLE,
158                             MCUCTRL_FEATUREENABLE_BURSTACK_Msk,
159                             MCUCTRL_FEATUREENABLE_BURSTACK_Msk,
160                             true);
161 
162     if ( ui32Status != AM_HAL_STATUS_SUCCESS )
163     {
164         g_am_hal_burst_mode_available = false;
165         *peBurstAvail = AM_HAL_BURST_NOTAVAIL;
166         return ui32Status;
167     }
168 
169     if ( 0 == MCUCTRL->FEATUREENABLE_b.BURSTAVAIL )
170     {
171         //
172         // Burst mode is not available.
173         //
174         g_am_hal_burst_mode_available = false;
175         *peBurstAvail = AM_HAL_BURST_NOTAVAIL;
176         return AM_HAL_STATUS_INVALID_OPERATION;
177     }
178 
179     //
180     // Check the ACK for the Burst Functionality.
181     //
182     if ( MCUCTRL->FEATUREENABLE_b.BURSTACK == 0 )
183     {
184         //
185         // If NACK, return status.
186         //
187         g_am_hal_burst_mode_available = false;
188         *peBurstAvail = AM_HAL_BURST_NOTAVAIL;
189         return AM_HAL_STATUS_INVALID_OPERATION;
190     }
191 
192     //
193     // Return Availability
194     //
195     g_am_hal_burst_mode_available = true;
196     *peBurstAvail = AM_HAL_BURST_AVAIL;
197     return AM_HAL_STATUS_SUCCESS;
198 }
199 
200 // ****************************************************************************
201 //
202 //  am_hal_burst_mode_enable()
203 //  Burst mode enable function
204 //
205 // ****************************************************************************
206 uint32_t
am_hal_burst_mode_enable(am_hal_burst_mode_e * peBurstStatus)207 am_hal_burst_mode_enable(am_hal_burst_mode_e *peBurstStatus)
208 {
209     uint32_t    ui32Status;
210 
211 #if AM_HAL_BURST_LDO_WORKAROUND
212     //
213     // Burst LDO into Active mode and delay before enabling 96MHz CLK
214     //
215     if ( !g_bEnFromManual )
216     {
217         //
218         // First call the workaround function, then return. (In turn, the
219         // workaround will set the flag and call this enable function.)
220         //
221         return am_hal_burst_mode_enable_w_manual_sequence(peBurstStatus);
222     }
223 #endif // AM_HAL_BURST_LDO_WORKAROUND
224 
225     //
226     // Check if Burst Mode is allowed and return status if it is not.
227     //
228     if (!g_am_hal_burst_mode_available)
229     {
230         *peBurstStatus = AM_HAL_NORMAL_MODE;
231         return AM_HAL_STATUS_INVALID_OPERATION;
232     }
233 
234     //
235     // Request Burst Mode Enable (FREQCTRL)
236     //
237     CLKGEN->FREQCTRL_b.BURSTREQ = CLKGEN_FREQCTRL_BURSTREQ_EN;
238 
239     ui32Status = am_hal_flash_delay_status_check(10000,
240                     (uint32_t)&CLKGEN->FREQCTRL,
241                     CLKGEN_FREQCTRL_BURSTSTATUS_Msk,
242                     CLKGEN_FREQCTRL_BURSTSTATUS_Msk,
243                     true);
244 
245     if ( ui32Status != AM_HAL_STATUS_SUCCESS )
246     {
247         *peBurstStatus = AM_HAL_NORMAL_MODE;
248         return ui32Status;
249     }
250 
251     //
252     // Check that the Burst Request was ACK'd.
253     //
254     if ( 0 == CLKGEN->FREQCTRL_b.BURSTACK )
255     {
256         *peBurstStatus = AM_HAL_NORMAL_MODE;
257         return AM_HAL_STATUS_FAIL;
258     }
259 
260     //
261     // Check the Burst Mode Status (FREQCTRL)
262     //
263     if ( CLKGEN->FREQCTRL_b.BURSTSTATUS > 0)
264     {
265         *peBurstStatus =  AM_HAL_BURST_MODE;
266     }
267     else
268     {
269         *peBurstStatus =  AM_HAL_NORMAL_MODE;
270     }
271 
272     return AM_HAL_STATUS_SUCCESS;
273 }
274 
275 // ****************************************************************************
276 //
277 //  am_hal_burst_mode_disable()
278 //  Burst mode disable function
279 //
280 // ****************************************************************************
281 uint32_t
am_hal_burst_mode_disable(am_hal_burst_mode_e * peBurstStatus)282 am_hal_burst_mode_disable(am_hal_burst_mode_e *peBurstStatus)
283 {
284     uint32_t    ui32Status;
285 
286 #if AM_HAL_BURST_LDO_WORKAROUND
287     //
288     // Burst LDO into Active mode and delay before enabling 96MHz CLK
289     //
290     if ( !g_bDisFromManual )
291     {
292         //
293         // First call the workaround function, then return. (In turn, the
294         // workaround will set the flag and call this disable function.)
295         //
296         return am_hal_burst_mode_disable_w_manual_sequence(peBurstStatus);
297     }
298 #endif // AM_HAL_BURST_LDO_WORKAROUND
299 
300     //
301     // Request Burst Mode Enable (FREQCTRL)
302     //
303     //
304     // Safely disable burst mode.
305     //
306     AM_CRITICAL_BEGIN
307     am_hal_flash_store_ui32((uint32_t*)&CLKGEN->FREQCTRL, CLKGEN_FREQCTRL_BURSTREQ_DIS);
308     AM_CRITICAL_END
309 
310     //
311     // Disable the Burst Feature Event (DEVPWREVENTEN).
312     //
313     PWRCTRL->DEVPWREVENTEN_b.BURSTEVEN = 0;
314 
315     ui32Status = am_hal_flash_delay_status_check(10000,
316                             (uint32_t)&CLKGEN->FREQCTRL,
317                             CLKGEN_FREQCTRL_BURSTSTATUS_Msk,
318                             0,
319                             true);
320 
321     if ( ui32Status != AM_HAL_STATUS_SUCCESS )
322     {
323         *peBurstStatus = AM_HAL_NORMAL_MODE;
324         return ui32Status;
325     }
326 
327     //
328     // Check the Burst Mode Status (FREQCTRL)
329     //
330     if ( CLKGEN->FREQCTRL_b.BURSTSTATUS > 0 )
331     {
332         *peBurstStatus = AM_HAL_BURST_MODE;
333     }
334     else
335     {
336         *peBurstStatus = AM_HAL_NORMAL_MODE;
337     }
338 
339     return AM_HAL_STATUS_SUCCESS;
340 }
341 
342 #if AM_HAL_BURST_LDO_WORKAROUND
343 //****************************************************************************
344 //
345 //  am_hal_burst_ldo_patch_check()
346 //
347 //****************************************************************************
348 bool
am_hal_burst_ldo_patch_check(void)349 am_hal_burst_ldo_patch_check(void)
350 {
351     //
352     // patch tracker bit3 for CV patch
353     //
354     if (AM_REGVAL(0x50023838) & 0x8)
355     {
356         //
357         // cv patch not applied
358         //
359         return false;
360     }
361 
362     //
363     // cv patch applied
364     //
365     return true;
366 } // am_hal_burst_ldo_patch_check
367 
368 //****************************************************************************
369 //
370 //  Burst LDO to charge VDDS cap
371 //
372 //****************************************************************************
373 void
am_hal_burst_ldo_charge(void)374 am_hal_burst_ldo_charge(void)
375 {
376     //
377     // If patch is not applied, the code after this check will FAIL.
378     //
379     if (!am_hal_burst_ldo_patch_check())
380     {
381         return;
382     }
383 
384     //
385     // Burst LDO power init to charge VDDS cap and put Burst LDO into LP mode after chip power up
386     // Put the BLE buck in strong pull-up mode
387     //
388     MCUCTRL->VRCTRL1_b.BLEBUCKPDNB            = 0;
389     MCUCTRL->VRCTRL1_b.BLEBUCKRSTB            = 0;
390     MCUCTRL->VRCTRL1_b.BLEBUCKACTIVE          = 1;
391     MCUCTRL->VRCTRL1_b.BLEBUCKOVER            = 1;
392 
393     //
394     // Delay 10ms for VDDBH rail to charge => we might be able to reduce this time dependent on ramp rate
395     //
396     am_hal_flash_delay(FLASH_CYCLES_US(DELAY_VDDBH_CHARGE_US));
397 
398     //
399     // Power up the Burst LDO to charge VDDS cap
400     //
401     MCUCTRL->VRCTRL2_b.BURSTLDOPDNB           = 1;
402     MCUCTRL->VRCTRL2_b.BURSTLDOCOLDSTARTEN    = 1;
403     MCUCTRL->VRCTRL2_b.BURSTLDOACTIVEEARLY    = 1;
404     MCUCTRL->VRCTRL2_b.BURSTLDOACTIVE         = 0;
405     MCUCTRL->VRCTRL2_b.BURSTLDOOVER           = 1;
406 
407     //
408     // Delay 2us before asserting burst LDO active
409     //
410     am_hal_flash_delay(FLASH_CYCLES_US(DELAY_BURSTLDO_ACT_US));
411     MCUCTRL->VRCTRL2_b.BURSTLDOACTIVE         = 1;
412 
413     //
414     // Delay 2ms for burst LDO to charge VDDS rail
415     //
416     am_hal_flash_delay(FLASH_CYCLES_US(DELAY_VDDS_CHARGE_US));
417 
418     //
419     // Put Burst LDO into LP mode and keep VDDS cap charged
420     //
421     MCUCTRL->VRCTRL2_b.BURSTLDOCOLDSTARTEN    = 0;
422     MCUCTRL->VRCTRL2_b.BURSTLDOACTIVEEARLY    = 0;
423     MCUCTRL->VRCTRL2_b.BURSTLDOACTIVE         = 0;
424 
425     //
426     // Switch BLE buck to weak pull-up mode and disable the override
427     //
428     MCUCTRL->VRCTRL1_b.BLEBUCKACTIVE          = 0;
429     MCUCTRL->VRCTRL1_b.BLEBUCKOVER            = 0;
430 } //am_hal_burst_ldo_charge
431 
432 //****************************************************************************
433 //
434 //  Enable Burst LDO workaround if CV Patch applied
435 //
436 //****************************************************************************
437 uint32_t
am_hal_burst_mode_enable_w_manual_sequence(am_hal_burst_mode_e * peBurstStatus)438 am_hal_burst_mode_enable_w_manual_sequence(am_hal_burst_mode_e *peBurstStatus)
439 {
440     uint32_t ui32Status = AM_HAL_STATUS_SUCCESS;
441 
442     //
443     // Check if Burst Mode is allowed and return status if it is not.
444     //
445     if (!g_am_hal_burst_mode_available)
446     {
447         *peBurstStatus = AM_HAL_NORMAL_MODE;
448         return AM_HAL_STATUS_INVALID_OPERATION;
449     }
450 
451     //
452     // Check if patch applied
453     //
454     if ( !am_hal_burst_ldo_patch_check() )
455     {
456         //
457         // The patch is not installed. Enable burst mode (96MHz) normally without workaround
458         //
459         g_bEnFromManual = true;
460         ui32Status = am_hal_burst_mode_enable(peBurstStatus);
461         g_bEnFromManual = false;
462     }
463     else
464     {
465         //
466         // enter burst mode with workaround
467         //
468         AM_CRITICAL_BEGIN
469 
470         //
471         // restore VDDF setting
472         //
473         am_hal_pwrctrl_wa_vddf_restore();
474 
475         //
476         // Burst mode entry sequence
477         // Turn on BLE buck and release from reset
478         //
479         MCUCTRL->VRCTRL1_b.BLEBUCKPDNB    = 1;
480         MCUCTRL->VRCTRL1_b.BLEBUCKACTIVE  = 1;
481         MCUCTRL->VRCTRL1_b.BLEBUCKRSTB = PWRCTRL->SUPPLYSTATUS_b.BLEBUCKON ? 1 : 0;
482         MCUCTRL->VRCTRL1_b.BLEBUCKOVER    = 1;
483 
484         //
485         // Delay 10us for analog to settle before turning on BLE buck
486         //
487         am_hal_flash_delay(FLASH_CYCLES_US(DELAY_BLEBUCK_ON_US));
488 
489         //
490         // BLEBUCKRSTB = 1 => release BLE buck from reset to start buck operation
491         //
492         MCUCTRL->VRCTRL1_b.BLEBUCKRSTB    = 1;
493 
494         //
495         // Force BLE buck into active mode
496         //
497         PWRCTRL->MISC_b.FORCEBLEBUCKACT   = 1;
498         PWRCTRL->SUPPLYSRC_b.BLEBUCKEN      = 1;
499 
500 
501         if (MCUCTRL->VRCTRL2_b.BURSTLDOOVER == 0)
502         {
503             //
504             // Burstldo override is not set
505             //
506             MCUCTRL->VRCTRL2_b.BURSTLDOPDNB         = 1;
507             MCUCTRL->VRCTRL2_b.BURSTLDOCOLDSTARTEN  = 1;
508             MCUCTRL->VRCTRL2_b.BURSTLDOACTIVEEARLY  = 1;
509             MCUCTRL->VRCTRL2_b.BURSTLDOACTIVE       = 0;
510             MCUCTRL->VRCTRL2_b.BURSTLDOOVER         = 1;
511         }
512         else
513         {
514             //
515             // Burstldo override is set
516             // Put Burst LDO into active mode
517             //
518             MCUCTRL->VRCTRL2_b.BURSTLDOACTIVEEARLY  = 1;
519         }
520 
521         //
522         // Delay 2us before asserting burst LDO active
523         //
524         am_hal_flash_delay(FLASH_CYCLES_US(DELAY_BURSTLDO_ACT_US));
525         MCUCTRL->VRCTRL2_b.BURSTLDOACTIVE         = 1;
526 
527         //
528         // Provide delay for power domain switch
529         //
530         am_hal_flash_delay(FLASH_CYCLES_US(DELAY_POWER_DOMAIN_SWITCH_US));
531 
532         //
533         // Enable burst mode, switch to 96MHz clock
534         //
535         g_bEnFromManual = true;
536         ui32Status = am_hal_burst_mode_enable(peBurstStatus);
537         g_bEnFromManual = false;
538 
539         //
540         // Provide delay for Burst Mode enable (must be 25us or longer)
541         //
542         am_hal_flash_delay(FLASH_CYCLES_US(DELAY_BLEBUCK_OVER_REMOVAL_US));
543 
544         //
545         // Remove BLEBUCK active overrides after entering burst mode
546         //
547         MCUCTRL->VRCTRL1_b.BLEBUCKOVER            = 0;
548         MCUCTRL->VRCTRL1_b.BLEBUCKPDNB            = 0;
549         MCUCTRL->VRCTRL1_b.BLEBUCKACTIVE          = 0;
550         MCUCTRL->VRCTRL1_b.BLEBUCKRSTB            = 0;
551 
552         //
553         // Remove Burstldo coldstart setting
554         //
555         if (MCUCTRL->VRCTRL2_b.BURSTLDOCOLDSTARTEN == 1)
556         {
557             MCUCTRL->VRCTRL2_b.BURSTLDOCOLDSTARTEN  = 0;
558         }
559 
560         // boost vddf again
561         am_hal_pwrctrl_wa_vddf_boost();
562 
563         AM_CRITICAL_END
564     }
565 
566     return ui32Status;
567 } // am_hal_burst_mode_enable_w_manual_sequence
568 
569 //****************************************************************************
570 //
571 //  Disable Burst LDO workaround if CV Patch applied
572 //
573 //****************************************************************************
574 uint32_t
am_hal_burst_mode_disable_w_manual_sequence(am_hal_burst_mode_e * peBurstStatus)575 am_hal_burst_mode_disable_w_manual_sequence(am_hal_burst_mode_e *peBurstStatus)
576 {
577     uint32_t ui32Status = AM_HAL_STATUS_SUCCESS;
578 
579     //
580     // Disable burst mode, switch to 48MHz clock
581     //
582     if (peBurstStatus != NULL)
583     {
584         g_bDisFromManual = true;
585         ui32Status = am_hal_burst_mode_disable(peBurstStatus);
586         g_bDisFromManual = false;
587     }
588     else
589     {
590         ui32Status = AM_HAL_STATUS_INVALID_HANDLE;
591     }
592 
593 
594     if (am_hal_burst_ldo_patch_check())
595     {
596         //
597         // Put Burst LDO back into LP mode => keeps VDDS cap charged and
598         // ready for next burst mode entry
599         //
600         MCUCTRL->VRCTRL2_b.BURSTLDOACTIVEEARLY    = 0;
601         MCUCTRL->VRCTRL2_b.BURSTLDOACTIVE         = 0;
602 
603         //
604         // remove force BLE buck active mode
605         //
606         PWRCTRL->MISC_b.FORCEBLEBUCKACT           = 0;
607     }
608 
609     return ui32Status;
610 } // am_hal_burst_mode_disable_w_manual_sequence
611 
612 #endif //AM_HAL_BURST_LDO_WORKAROUND
613 
614 //*****************************************************************************
615 //
616 // End Doxygen group.
617 //! @}
618 //
619 //*****************************************************************************
620