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