1 //*****************************************************************************
2 //
3 //! @file am_hal_dcu.c
4 //!
5 //! @brief Implementation for Debug Control Unit functionality
6 //!
7 //! @addtogroup dcu_4p DCU - Debug Control Unit
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 #include "am_mcu_apollo.h"
48 
49 #define CRYPTO_CC_IS_IDLE()     while (CRYPTO->HOSTCCISIDLE_b.HOSTCCISIDLE == 0)
50 
51 // Raw offset for 3b value corresponding to DCU value 1
52 uint32_t gStartOff    = 0; // DCU value 1 corresponds to b[2:0]
53 uint64_t gDcuMask     = AM_HAL_DCURAW_MASK;
54 uint64_t gDcuEnable   = AM_HAL_DCURAW_ENABLE;
55 uint64_t gDcuDisable  = AM_HAL_DCURAW_DISABLE;
56 volatile uint32_t *gpDcuEnable = &CRYPTO->HOSTDCUEN2;
57 volatile uint32_t *gpDcuLock   = &CRYPTO->HOSTDCULOCK2;
58 
59 //*****************************************************************************
60 //
61 //! @brief Get the Current RAW DCU Mask
62 //
63 //*****************************************************************************
64 static uint64_t
get_raw_dcu_mask(uint32_t ui32DcuMask,uint8_t threeBitVal)65 get_raw_dcu_mask(uint32_t ui32DcuMask, uint8_t threeBitVal)
66 {
67     uint32_t i = AM_HAL_DCU_NUMDCU;
68     uint64_t ui64Mask = 0;
69     uint32_t offset = gStartOff;
70     ui32DcuMask >>= 1; // DCU value 0 is not defined
71     while ( --i )
72     {
73         if (ui32DcuMask & 0x1)
74         {
75             ui64Mask |= (uint64_t)threeBitVal << offset;
76         }
77         offset += 3;
78         ui32DcuMask >>= 1;
79     }
80     return ui64Mask;
81 }
82 
83 //*****************************************************************************
84 //
85 //! @brief Get the Current DCU Mask
86 //
87 //*****************************************************************************
88 static uint32_t
get_ui32_dcu_mask(uint64_t ui64DcuMask,uint8_t threeBitVal)89 get_ui32_dcu_mask(uint64_t ui64DcuMask, uint8_t threeBitVal)
90 {
91     uint32_t i = AM_HAL_DCU_NUMDCU;
92     uint32_t ui32Mask = 0;
93     ui64DcuMask >>= gStartOff;
94     while ( --i )
95     {
96         if ((ui64DcuMask & AM_HAL_DCURAWVAL_MASK) == threeBitVal)
97         {
98             ui32Mask |= (1 << (AM_HAL_DCU_NUMDCU - i - 1));
99         }
100         ui64DcuMask >>= 3;
101     }
102     return ui32Mask;
103 }
104 
105 //*****************************************************************************
106 //
107 //! @brief Copy words from Register to Register
108 //
109 //*****************************************************************************
110 static void
copy_words(uint32_t * pDst,uint32_t * pSrc,uint32_t numWords)111 copy_words(uint32_t *pDst, uint32_t *pSrc, uint32_t numWords)
112 {
113     while (numWords--)
114     {
115         AM_REGVAL((pDst + numWords)) = AM_REGVAL((pSrc + numWords));
116     }
117 }
118 
119 //*****************************************************************************
120 //
121 //! @brief  Read DCU Lock
122 //!
123 //! @param  pui64Val -  Pointer to double word for returned data
124 //!
125 //! This will retrieve the DCU Lock information
126 //!
127 //! @return Returns AM_HAL_STATUS_SUCCESS on success
128 //
129 //*****************************************************************************
130 static
am_hal_dcu_raw_lock_status_get(uint64_t * pui64Val)131 uint32_t am_hal_dcu_raw_lock_status_get(uint64_t *pui64Val)
132 {
133     copy_words((uint32_t *)pui64Val, (uint32_t *)gpDcuLock, sizeof(uint64_t) / 4);
134     return AM_HAL_STATUS_SUCCESS;
135 }
136 
137 //*****************************************************************************
138 //
139 //! @brief  Read DCU Lock
140 //!
141 //! @param  pui32Val -  Pointer to word for returned data (Qualified DCU Mask)
142 //!
143 //! This will retrieve the DCU Lock information
144 //!
145 //! @return Returns AM_HAL_STATUS_SUCCESS on success
146 //
147 //*****************************************************************************
am_hal_dcu_lock_status_get(uint32_t * pui32Val)148 uint32_t am_hal_dcu_lock_status_get(uint32_t *pui32Val)
149 {
150     uint64_t ui64Lock;
151     uint32_t ui32Status;
152     if ((PWRCTRL->DEVPWRSTATUS_b.PWRSTCRYPTO == 0) || (CRYPTO->HOSTCCISIDLE_b.HOSTCCISIDLE == 0))
153     {
154         // Crypto is not accessible
155         return AM_HAL_STATUS_INVALID_OPERATION;
156     }
157     ui32Status = am_hal_dcu_raw_lock_status_get(&ui64Lock);
158     *pui32Val = get_ui32_dcu_mask(ui64Lock, AM_HAL_DCURAWVAL_MASK);
159     return ui32Status;
160 }
161 
162 //*****************************************************************************
163 //
164 //! @brief  Write DCU Lock
165 //!
166 //! @param  val -  double word for lock values
167 //!
168 //! This will lock the DCU from further changes
169 //!
170 //! @return Returns AM_HAL_STATUS_SUCCESS on success
171 //
172 //*****************************************************************************
173 static
am_hal_dcu_raw_lock(uint64_t ui64Mask)174 uint32_t am_hal_dcu_raw_lock(uint64_t ui64Mask)
175 {
176     //
177     // copy_words((uint32_t *)gpDcuLock, (uint32_t *)&ui64Mask, sizeof(uint64_t) / 4);
178     //
179     // In order to avoid a GCC compiler warning, we'll explicitly handle the
180     // call to copy_words() by replacing it with a couple of direct writes.
181     // Note that the writes are done in the same reverse order as copy_words()
182     // would do it.
183     //
184     gpDcuLock[1] = (uint32_t)(ui64Mask >> 32);
185     gpDcuLock[0] = (uint32_t)(ui64Mask >> 0);
186     CRYPTO_CC_IS_IDLE();
187     return AM_HAL_STATUS_SUCCESS;
188 } // am_hal_dcu_raw_lock()
189 
190 //*****************************************************************************
191 //
192 //! @brief  Write DCU Lock (Qualified Values)
193 //!
194 //! @param  ui32Mask -  Mask for lock values
195 //!
196 //! This will lock the DCU from further changes
197 //!
198 //! @return Returns AM_HAL_STATUS_SUCCESS on success
199 //
200 //*****************************************************************************
am_hal_dcu_lock(uint32_t ui32Mask)201 uint32_t am_hal_dcu_lock(uint32_t ui32Mask)
202 {
203     uint64_t ui64Lock;
204     if ((PWRCTRL->DEVPWRSTATUS_b.PWRSTCRYPTO == 0) || (CRYPTO->HOSTCCISIDLE_b.HOSTCCISIDLE == 0))
205     {
206         // Crypto is not accessible
207         return AM_HAL_STATUS_INVALID_OPERATION;
208     }
209     ui64Lock = get_raw_dcu_mask(ui32Mask, AM_HAL_DCURAWVAL_MASK);
210     return am_hal_dcu_raw_lock(ui64Lock);
211 }
212 
213 //*****************************************************************************
214 //
215 //! @brief  Read DCU Enables
216 //!
217 //! @param  pui64Val -  Pointer to double word for returned data
218 //!
219 //! This will get the current DCU Enable settings
220 //!
221 //! @return Returns AM_HAL_STATUS_SUCCESS on success
222 //
223 //*****************************************************************************
224 static
am_hal_dcu_raw_get(uint64_t * pui64Val)225 uint32_t am_hal_dcu_raw_get(uint64_t *pui64Val)
226 {
227     copy_words((uint32_t *)pui64Val, (uint32_t *)gpDcuEnable, sizeof(uint64_t) / 4);
228     return AM_HAL_STATUS_SUCCESS;
229 }
230 
231 //*****************************************************************************
232 //
233 //! @brief  Read DCU Enables (Qualified Values)
234 //!
235 //! @param  pui32Val -  Pointer to Mask for returned data
236 //!
237 //! This will get the current DCU Enable settings
238 //!
239 //! @return Returns AM_HAL_STATUS_SUCCESS on success
240 //
241 //*****************************************************************************
am_hal_dcu_get(uint32_t * pui32Val)242 uint32_t am_hal_dcu_get(uint32_t *pui32Val)
243 {
244     uint64_t ui64Enable;
245     uint32_t ui32Status;
246     if ((PWRCTRL->DEVPWRSTATUS_b.PWRSTCRYPTO == 0) || (CRYPTO->HOSTCCISIDLE_b.HOSTCCISIDLE == 0))
247     {
248         // Crypto is not accessible
249         return AM_HAL_STATUS_INVALID_OPERATION;
250     }
251     ui32Status = am_hal_dcu_raw_get(&ui64Enable);
252     *pui32Val = get_ui32_dcu_mask(ui64Enable, AM_HAL_DCURAWVAL_ENABLE);
253     return ui32Status;
254 }
255 
256 //*****************************************************************************
257 //
258 //! @brief  Update DCU Enable
259 //!
260 //! @param  ui64Mask -  DCU controls to be modified
261 //! @param  bEnable - Whether to enable or disable
262 //!
263 //! This will update the DCU Enable settings, if not locked
264 //!
265 //! @return Returns AM_HAL_STATUS_SUCCESS on success
266 //
267 //*****************************************************************************
268 static
am_hal_dcu_raw_update(bool bEnable,uint64_t ui64Mask)269 uint32_t am_hal_dcu_raw_update(bool bEnable, uint64_t ui64Mask)
270 {
271     uint64_t dcuVal;
272     uint64_t dcuLock;
273     copy_words((uint32_t *)&dcuLock, (uint32_t *)gpDcuLock, sizeof(uint64_t) / 4);
274     if (ui64Mask & dcuLock)
275     {
276         return AM_HAL_STATUS_INVALID_OPERATION;
277     }
278     copy_words((uint32_t *)&dcuVal, (uint32_t *)gpDcuEnable, sizeof(uint64_t) / 4);
279     if (bEnable)
280     {
281         dcuVal = (dcuVal & ~ui64Mask) | (gDcuEnable & ui64Mask);
282     }
283     else
284     {
285         dcuVal = (dcuVal & ~ui64Mask) | (gDcuDisable & ui64Mask);
286     }
287     copy_words((uint32_t *)gpDcuEnable, (uint32_t *)&dcuVal, sizeof(uint64_t) / 4);
288     CRYPTO_CC_IS_IDLE();
289     return AM_HAL_STATUS_SUCCESS;
290 }
291 
292 //*****************************************************************************
293 //
294 // Update DCU Enable (Qualified Values)
295 //
296 // This will update the DCU Enable settings, if not locked
297 //
298 //*****************************************************************************
am_hal_dcu_update(bool bEnable,uint32_t ui32Mask)299 uint32_t am_hal_dcu_update(bool bEnable, uint32_t ui32Mask)
300 {
301     uint64_t ui64Mask;
302     if ((PWRCTRL->DEVPWRSTATUS_b.PWRSTCRYPTO == 0) || (CRYPTO->HOSTCCISIDLE_b.HOSTCCISIDLE == 0))
303     {
304         // Crypto is not accessible
305         return AM_HAL_STATUS_INVALID_OPERATION;
306     }
307     ui64Mask = get_raw_dcu_mask(ui32Mask, AM_HAL_DCURAWVAL_MASK);
308     return am_hal_dcu_raw_update(bEnable, ui64Mask);
309 }
310 
311 //*****************************************************************************
312 //
313 // DCU Disable - Using MCUCTRL Override
314 //
315 // This will update the MCUCTRL DCU Disable Override settings
316 // This can only further lock things if the corresponding DCU Enable was open
317 //
318 //*****************************************************************************
am_hal_dcu_mcuctrl_override(uint32_t ui32Mask)319 uint32_t am_hal_dcu_mcuctrl_override(uint32_t ui32Mask)
320 {
321     MCUCTRL->DEBUGGER = ui32Mask;
322     return AM_HAL_STATUS_SUCCESS;
323 }
324 
325 
326 //*****************************************************************************
327 //
328 // End Doxygen group.
329 //! @}
330 //
331 //*****************************************************************************
332