1 //*****************************************************************************
2 //
3 //! @file am_hal_utils.c
4 //!
5 //! @brief HAL Utility Functions
6 //!
7 //! @addtogroup utils4_4p Utils - HAL Utility Functions
8 //! @ingroup apollo4p_hal
9 //! @{
10 //
11 //*****************************************************************************
12 
13 //*****************************************************************************
14 //
15 // Copyright (c) 2023, 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_4_4_0-3c5977e664 of the AmbiqSuite Development Package.
45 //
46 //*****************************************************************************
47 
48 #include <stdint.h>
49 #include <stdbool.h>
50 #include "am_mcu_apollo.h"
51 #include "am_hal_bootrom_helper.h"
52 
53 //*****************************************************************************
54 //
55 //! Mode - the result of a change request.
56 //
57 //*****************************************************************************
58 typedef enum
59 {
60     AM_HAL_BURST_MODE,
61     AM_HAL_NORMAL_MODE,
62 } am_hal_burst_mode_e;
63 
64 //*****************************************************************************
65 //
66 //! @brief Return current burst mode state
67 //!
68 //! Implemented as a macro, this function returns the current burst mode state.
69 //!     AM_HAL_BURST_MODE
70 //!     AM_HAL_NORMAL_MODE
71 //
72 //*****************************************************************************
73 #define am_hal_burst_mode_status()  AM_HAL_NORMAL_MODE
74 
75 //*****************************************************************************
76 //
77 //! @brief Given an integer number of microseconds, convert to a value representing
78 //! the number of cycles that will provide that amount
79 //! of delay.  This macro is designed to take into account some of the call
80 //! overhead and latencies.
81 //! The BOOTROM_CYCLES_US macro assumes:
82 //!  - Burst or normal mode operation.
83 //!  - If cache is not enabled, use BOOTROM_CYCLES_US_NOCACHE() instead.
84 //!
85 //! @name BootROM_CYCLES
86 //! @{
87 //
88 //*****************************************************************************
89 #define CYCLESPERITER                 (AM_HAL_CLKGEN_FREQ_MAX_MHZ / 3)
90 #define BOOTROM_CYCLES_US(n)          (((n) * CYCLESPERITER) + 0)
91 #define BOOTROM_CYCLES_US_NOCACHE(n)  ( (n == 0) ? 0 : (n * CYCLESPERITER) - 5)
92 //! @}
93 
94 //*****************************************************************************
95 //
96 // Use the bootrom to implement a spin loop.
97 //
98 //*****************************************************************************
99 void
am_hal_delay_us(uint32_t ui32us)100 am_hal_delay_us(uint32_t ui32us)
101 {
102 
103     register uint32_t ui32Iterations = BOOTROM_CYCLES_US(ui32us);
104     register uint32_t ui32CycleCntAdj;
105 
106     //
107     // Check for LP (96MHz) vs. HP (192MHz) mode and create the adjustment accordingly.
108     //
109     if (PWRCTRL->MCUPERFREQ_b.MCUPERFSTATUS == AM_HAL_PWRCTRL_MCU_MODE_HIGH_PERFORMANCE)
110     {
111         ui32Iterations <<= 1;
112 
113         //
114         // There's an additional shift to account for.
115         //
116         ui32CycleCntAdj = ((13 * 2) + 37) / 3;
117     }
118     else
119     {
120         ui32CycleCntAdj = ((13 * 1) + 32) / 3;
121     }
122 
123     //
124     // Allow for the overhead of the burst-mode check and these comparisons
125     // by eliminating an appropriate number of iterations.
126     //
127     if ( ui32Iterations > ui32CycleCntAdj )
128     {
129         ui32Iterations -= ui32CycleCntAdj;
130 
131         g_am_hal_bootrom_helper.bootrom_delay_cycles(ui32Iterations);
132     }
133 
134 } // am_hal_delay_us()
135 
136 //*****************************************************************************
137 //
138 // Delays for a desired amount of cycles while also waiting for a
139 // status to change a value.
140 //
141 //*****************************************************************************
142 uint32_t
am_hal_delay_us_status_change(uint32_t ui32usMaxDelay,uint32_t ui32Address,uint32_t ui32Mask,uint32_t ui32Value)143 am_hal_delay_us_status_change(uint32_t ui32usMaxDelay, uint32_t ui32Address,
144                               uint32_t ui32Mask, uint32_t ui32Value)
145 {
146     while ( 1 )
147     {
148         //
149         // Check the status
150         //
151         if ( ( AM_REGVAL(ui32Address) & ui32Mask ) == ui32Value )
152         {
153             return AM_HAL_STATUS_SUCCESS;
154         }
155 
156         if (ui32usMaxDelay--)
157         {
158             //
159             // Call the BOOTROM cycle function to delay for about 1 microsecond.
160             //
161             am_hal_delay_us(1);
162         }
163         else
164         {
165             break;
166         }
167     }
168 
169     return AM_HAL_STATUS_TIMEOUT;
170 
171 } // am_hal_delay_us_status_change()
172 
173 //*****************************************************************************
174 //
175 // Delays for a desired amount of cycles while also waiting for a
176 // status to equal OR not-equal to a value.
177 //
178 //*****************************************************************************
179 uint32_t
am_hal_delay_us_status_check(uint32_t ui32usMaxDelay,uint32_t ui32Address,uint32_t ui32Mask,uint32_t ui32Value,bool bIsEqual)180 am_hal_delay_us_status_check(uint32_t ui32usMaxDelay, uint32_t ui32Address,
181                              uint32_t ui32Mask, uint32_t ui32Value,
182                              bool bIsEqual)
183 {
184     while ( 1 )
185     {
186         //
187         // Check the status
188         //
189         if ( bIsEqual )
190         {
191             if ( ( AM_REGVAL(ui32Address) & ui32Mask ) == ui32Value )
192             {
193                 return AM_HAL_STATUS_SUCCESS;
194             }
195         }
196         else
197         {
198             if ( ( AM_REGVAL(ui32Address) & ui32Mask ) != ui32Value )
199             {
200                 return AM_HAL_STATUS_SUCCESS;
201             }
202         }
203 
204         if ( ui32usMaxDelay-- )
205         {
206             //
207             // Call the BOOTROM cycle function to delay for about 1 microsecond.
208             //
209             am_hal_delay_us(1);
210         }
211         else
212         {
213             break;
214         }
215     }
216 
217     return AM_HAL_STATUS_TIMEOUT;
218 
219 } // am_hal_delay_us_status_check()
220 
221 //*****************************************************************************
222 //
223 // Read a uint32 value from a valid memory or peripheral location.
224 //
225 //*****************************************************************************
226 uint32_t
am_hal_load_ui32(uint32_t * pui32Address)227 am_hal_load_ui32(uint32_t *pui32Address)
228 {
229     return g_am_hal_bootrom_helper.bootrom_util_read_word(pui32Address);
230 } // am_hal_load_ui32()
231 
232 //*****************************************************************************
233 //
234 // Use the bootrom to write to a location in SRAM or the system bus.
235 //
236 //*****************************************************************************
237 void
am_hal_store_ui32(uint32_t * pui32Address,uint32_t ui32Data)238 am_hal_store_ui32(uint32_t *pui32Address, uint32_t ui32Data)
239 {
240     g_am_hal_bootrom_helper.bootrom_util_write_word(pui32Address, ui32Data);
241 } // am_hal_store_ui32()
242 
243 //*****************************************************************************
244 //
245 // End Doxygen group.
246 //! @}
247 //
248 //*****************************************************************************
249