1 //*****************************************************************************
2 //
3 //! @file am_hal_mram.c
4 //!
5 //! @brief BootROM Helper Function Table
6 //!
7 //! @addtogroup mram4_4p MRAM Functionality
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 #define HLPRFNC_MAXSRC_ADDR     0x101D7FFC // Maximum src size for Apollo4 Plus
55 
56 //#define INFO_ACCESS_WA
57 
58 
59 #define MRAM_OVERRIDE()
60 #define MRAM_REVERT()
61 #define MRAM_RECOVER()
62 
63 
64 //*****************************************************************************
65 //
66 // This programs up to N words of the Main MRAM
67 //
68 //*****************************************************************************
69 int
am_hal_mram_main_words_program(uint32_t ui32ProgramKey,uint32_t * pui32Src,uint32_t * pui32Dst,uint32_t ui32NumWords)70 am_hal_mram_main_words_program(uint32_t ui32ProgramKey, uint32_t *pui32Src,
71                                uint32_t *pui32Dst, uint32_t ui32NumWords)
72 {
73     //
74     // Use the new helper function to efficiently program the data in MRAM.
75     //
76 
77 #ifndef AM_HAL_DISABLE_API_VALIDATION
78     //
79     // Check the Source to ensure proper location.
80     //
81     if ( ((uint32_t)pui32Src & 0xFF000000) == SRAM_BASEADDR )
82     {
83         //
84         // Check that the source buffer is within bounds (see errata ERR122)
85         //
86         if ( ((uint32_t)pui32Src + (ui32NumWords * 4)) > HLPRFNC_MAXSRC_ADDR )
87         {
88             return AM_HAL_STATUS_OUT_OF_RANGE;
89         }
90     }
91 #endif // AM_HAL_DISABLE_API_VALIDATION
92 
93     if ( (uint32_t)pui32Dst <= AM_HAL_MRAM_LARGEST_VALID_ADDR )
94     {
95         //
96         // This helper function requires a word offset rather than an actual
97         // address. Since MRAM addresses start at 0x0, we can convert the addr
98         // into a word offset by simply dividing the destination address by 4.
99         //
100         pui32Dst = (uint32_t*)((uint32_t)pui32Dst / 4);
101     }
102 
103     return g_am_hal_bootrom_helper.nv_program_main2(ui32ProgramKey, 1,
104                                                     (uint32_t)pui32Src,
105                                                     (uint32_t)pui32Dst,
106                                                     ui32NumWords);
107 }
108 
109 //*****************************************************************************
110 //
111 // This programs up to N words of the Main MRAM
112 //
113 //*****************************************************************************
114 int
am_hal_mram_main_program(uint32_t ui32ProgramKey,uint32_t * pui32Src,uint32_t * pui32Dst,uint32_t ui32NumWords)115 am_hal_mram_main_program(uint32_t ui32ProgramKey, uint32_t *pui32Src,
116                          uint32_t *pui32Dst, uint32_t ui32NumWords)
117 {
118     //
119     // Check for pui32Dst & ui32NumWords
120     //
121     if (((uint32_t)pui32Dst & 0xf) || (ui32NumWords & 0x3))
122     {
123         return -1;
124     }
125 
126     return am_hal_mram_main_words_program(ui32ProgramKey, pui32Src,
127                                           pui32Dst, ui32NumWords);
128 }
129 
130 //*****************************************************************************
131 //
132 // This Fills up to N words of the Main MRAM
133 //
134 //*****************************************************************************
135 int
am_hal_mram_main_fill(uint32_t ui32ProgramKey,uint32_t ui32Value,uint32_t * pui32Dst,uint32_t ui32NumWords)136 am_hal_mram_main_fill(uint32_t ui32ProgramKey, uint32_t ui32Value,
137                       uint32_t *pui32Dst, uint32_t ui32NumWords)
138 {
139     //
140     // Check for pui32Dst & ui32NumWords
141     //
142     if (((uint32_t)pui32Dst & 0xf) || (ui32NumWords & 0x3))
143     {
144         return -1;
145     }
146 
147     //
148     // Use the new helper function to efficiently fill MRAM with a value.
149     //
150 
151     if ( (uint32_t)pui32Dst <= AM_HAL_MRAM_LARGEST_VALID_ADDR )
152     {
153         //
154         // This helper function requires a word offset rather than an actual
155         // address. Since MRAM addresses start at 0x0, we can convert the addr
156         // into a word offset by simply dividing the destination address by 4.
157         //
158         pui32Dst = (uint32_t*)((uint32_t)pui32Dst / 4);
159     }
160 
161     return g_am_hal_bootrom_helper.nv_program_main2(ui32ProgramKey, 0,
162                                                     (uint32_t)ui32Value,
163                                                     (uint32_t)pui32Dst,
164                                                     ui32NumWords);
165 }
166 
167 //*****************************************************************************
168 //
169 // This programs up to N words of the Main array on one MRAM.
170 //
171 //*****************************************************************************
172 int
am_hal_mram_info_program(uint32_t ui32InfoKey,uint32_t * pui32Src,uint32_t ui32Offset,uint32_t ui32NumWords)173 am_hal_mram_info_program(uint32_t ui32InfoKey, uint32_t *pui32Src,
174                          uint32_t ui32Offset, uint32_t ui32NumWords)
175 {
176     int retval;
177 
178 #ifndef AM_HAL_DISABLE_API_VALIDATION
179     //
180     // Check the Source to ensure proper location.
181     //
182     if ( ((uint32_t)pui32Src & 0xFF000000) == SRAM_BASEADDR )
183     {
184         //
185         // Check that the source buffer is within bounds (see errata ERR122)
186         //
187         if ( ((uint32_t)pui32Src + (ui32NumWords * 4)) > HLPRFNC_MAXSRC_ADDR )
188         {
189             return AM_HAL_STATUS_OUT_OF_RANGE;
190         }
191     }
192 #endif // AM_HAL_DISABLE_API_VALIDATION
193 
194     MRAM_OVERRIDE();
195 
196     retval = g_am_hal_bootrom_helper.nv_program_info_area(ui32InfoKey,
197                                 pui32Src, ui32Offset, ui32NumWords);
198 
199     MRAM_REVERT();
200 
201     return retval;
202 }
203 
204 #ifdef INFO_ACCESS_WA
205 
206 //*****************************************************************************
207 //
208 //! @brief This function erases main MRAM + customer INFO space
209 //!
210 //! @param ui32BrickKey - The Brick key.
211 //!
212 //! This function erases main MRAM and customer INFOinstance
213 //! even if the customer INFO space is programmed to not be erasable. This
214 //! function completely erases the MRAM main and info instance and wipes the
215 //! SRAM. Upon completion of the erasure operations, it does a POI (power on
216 //! initialization) reset.
217 //!
218 //! @note This function enforces 128 bit customer key lock. The caller needs to assert
219 //! the Recovery Lock using am_hal_security_set_key() providing appropriate key.
220 //! Otherwise, the function will fail.  Therefore, always check for a return code.
221 //! If the function returns, a failure has occured.
222 //!
223 //! @return Does not return if successful.  Returns failure code otherwise.
224 //!     Failing return code indicates:
225 //!     0x00000001  ui32BrickKey is invalid.
226 //!     0x00000002  Recovery key lock not set.
227 //!     Other values indicate Internal error.
228 //
229 //*****************************************************************************
230 int
am_hal_mram_recovery(uint32_t ui32BrickKey)231 am_hal_mram_recovery(uint32_t ui32BrickKey)
232 {
233     return g_am_hal_bootrom_helper.nv_recovery(ui32BrickKey);
234 }
235 #endif
236 
237 //*****************************************************************************
238 //
239 // Read INFO data.
240 //
241 //*****************************************************************************
242 int
am_hal_mram_info_read(uint32_t ui32InfoSpace,uint32_t ui32WordOffset,uint32_t ui32NumWords,uint32_t * pui32Dst)243 am_hal_mram_info_read(uint32_t ui32InfoSpace,
244                       uint32_t ui32WordOffset,
245                       uint32_t ui32NumWords,
246                       uint32_t *pui32Dst)
247 {
248     int retval = 0;
249     uint32_t ux;
250     uint32_t *pui32Info;
251 
252     if ( ui32InfoSpace == 0 )
253     {
254         if ( (ui32WordOffset >= (AM_HAL_INFO0_SIZE_BYTES / 4)) || ((ui32WordOffset + ui32NumWords) > (AM_HAL_INFO0_SIZE_BYTES / 4))  )
255         {
256             return 2;
257         }
258         pui32Info = (uint32_t*)(AM_REG_INFO0_BASEADDR + (ui32WordOffset * 4));
259     }
260     else if ( ui32InfoSpace == 1 )
261     {
262         if ( (ui32WordOffset < (AM_HAL_INFO1_VISIBLE_OFFSET / 4)) || (ui32WordOffset >= (AM_HAL_INFO1_SIZE_BYTES / 4)) || ((ui32WordOffset + ui32NumWords) > (AM_HAL_INFO1_SIZE_BYTES / 4))  )
263         {
264             return 2;
265         }
266         pui32Info = (uint32_t*)(AM_REG_INFO1_BASEADDR + (ui32WordOffset * 4));
267     }
268     else
269     {
270         return 1;
271     }
272 
273 #ifdef INFO_ACCESS_WA
274     MRAM_OVERRIDE();
275 
276     //
277     // Start a critical section.
278     //
279     AM_CRITICAL_BEGIN
280 
281     for (ux = 0; ux < ui32NumWords; ux++ )
282     {
283         // INFO read should use the util function - to ensure the code is not running from MRAM
284         *pui32Dst++ = am_hal_load_ui32(pui32Info++);
285     }
286 
287     //
288     // End the critical section.
289     //
290     AM_CRITICAL_END
291 
292     MRAM_REVERT();
293 #else
294     for (ux = 0; ux < ui32NumWords; ux++ )
295     {
296         *pui32Dst++ = AM_REGVAL(pui32Info++);
297     }
298 #endif
299 
300     return retval;
301 }
302 
303 //*****************************************************************************
304 //
305 // Initialize MRAM for DeepSleep.
306 //
307 //*****************************************************************************
308 int
am_hal_mram_ds_init(void)309 am_hal_mram_ds_init(void)
310 {
311     MRAM_RECOVER();
312     return 0;
313 }
314 
315 //*****************************************************************************
316 //
317 // End Doxygen group.
318 //! @}
319 //
320 //*****************************************************************************
321