1 //*****************************************************************************
2 //
3 //! @file am_hal_tpiu.c
4 //!
5 //! @brief Support functions for the ARM TPIU module
6 //!
7 //! Provides support functions for configuring the ARM TPIU module
8 //!
9 //! @addtogroup tpiu3 TPIU - Trace Port Interface Unit
10 //! @ingroup apollo3_hal
11 //! @{
12 //
13 //*****************************************************************************
14 
15 //*****************************************************************************
16 //
17 // Copyright (c) 2024, Ambiq Micro, Inc.
18 // All rights reserved.
19 //
20 // Redistribution and use in source and binary forms, with or without
21 // modification, are permitted provided that the following conditions are met:
22 //
23 // 1. Redistributions of source code must retain the above copyright notice,
24 // this list of conditions and the following disclaimer.
25 //
26 // 2. Redistributions in binary form must reproduce the above copyright
27 // notice, this list of conditions and the following disclaimer in the
28 // documentation and/or other materials provided with the distribution.
29 //
30 // 3. Neither the name of the copyright holder nor the names of its
31 // contributors may be used to endorse or promote products derived from this
32 // software without specific prior written permission.
33 //
34 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
35 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
38 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
39 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
40 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
41 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
42 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
43 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
44 // POSSIBILITY OF SUCH DAMAGE.
45 //
46 // This is part of revision release_sdk_3_2_0-dd5f40c14b of the AmbiqSuite Development Package.
47 //
48 //*****************************************************************************
49 
50 #include <stdint.h>
51 #include <stdbool.h>
52 #include "am_mcu_apollo.h"
53 
54 //*****************************************************************************
55 //
56 // @brief Enable the clock to the TPIU module.
57 //
58 // This function enables the clock to the TPIU module.
59 //
60 //*****************************************************************************
61 void
am_hal_tpiu_clock_enable(void)62 am_hal_tpiu_clock_enable(void)
63 {
64     //
65     // Enable the TPIU clock
66     //
67     MCUCTRL->TPIUCTRL |= MCUCTRL_TPIUCTRL_ENABLE_Msk;
68 }
69 
70 //*****************************************************************************
71 //
72 // @brief Disable the clock to the TPIU module.
73 //
74 // This function disables the clock to the TPIU module.
75 //
76 //*****************************************************************************
77 void
am_hal_tpiu_clock_disable(void)78 am_hal_tpiu_clock_disable(void)
79 {
80     //
81     // Disable the TPIU clock
82     //
83     MCUCTRL->TPIUCTRL &= ~MCUCTRL_TPIUCTRL_ENABLE_Msk;
84 }
85 
86 //*****************************************************************************
87 //
88 // @brief Set the output port width of the TPIU
89 //
90 // @param ui32PortWidth - The desired port width (in bits)
91 //
92 // This function uses the TPIU_CSPSR register to set the desired output port
93 // width of the TPIU.
94 //
95 //*****************************************************************************
96 void
am_hal_tpiu_port_width_set(uint32_t ui32PortWidth)97 am_hal_tpiu_port_width_set(uint32_t ui32PortWidth)
98 {
99     TPI->CSPSR = 1 << (ui32PortWidth - 1);
100 }
101 
102 //*****************************************************************************
103 //
104 // @brief Read the supported_output port width of the TPIU
105 //
106 // This function uses the \e TPIU_SSPSR register to set the supported output
107 // port widths of the TPIU.
108 //
109 // @return Current width of the TPIU output port
110 //
111 //*****************************************************************************
112 uint32_t
am_hal_tpiu_supported_port_width_get(void)113 am_hal_tpiu_supported_port_width_get(void)
114 {
115     uint32_t i, ui32WidthValue;
116 
117     //
118     // Read the supported width register.
119     //
120     ui32WidthValue = TPI->SSPSR;
121 
122     //
123     // The register value is encoded in a one-hot format, so the position of
124     // the single set bit determines the actual width of the port.
125     //
126     for (i = 1; i < 32; i++)
127     {
128         //
129         // Check each bit for a '1'. When we find it, our current loop index
130         // will be equal to the port width.
131         //
132         if (ui32WidthValue == (0x1 << (i - 1)))
133         {
134             return i;
135         }
136     }
137 
138     //
139     // We should never get here, but if we do, just return the smallest
140     // possible value for a supported trace port width.
141     //
142     return 1;
143 }
144 
145 //*****************************************************************************
146 //
147 // @brief Read the output port width of the TPIU
148 //
149 // This function uses the \e TPIU_CSPSR register to set the desired output
150 // port width of the TPIU.
151 //
152 // @return Current width of the TPIU output port
153 //
154 //*****************************************************************************
155 uint32_t
am_hal_tpiu_port_width_get(void)156 am_hal_tpiu_port_width_get(void)
157 {
158     uint32_t ui32Temp;
159     uint32_t ui32Width;
160 
161     ui32Width = 1;
162     ui32Temp = TPI->CSPSR;
163 
164     while ( !(ui32Temp & 1) )
165     {
166         ui32Temp = ui32Temp >> 1;
167         ui32Width++;
168 
169         if (ui32Width > 32)
170         {
171             ui32Width = 0;
172             break;
173         }
174     }
175 
176     //
177     // Current width of the TPIU output port.
178     //
179     return ui32Width;
180 }
181 
182 //*****************************************************************************
183 //
184 // @brief Configure the TPIU based on the values in the configuration struct.
185 //
186 // @param psConfig - pointer to an am_hal_tpiu_config_t structure containing
187 // the desired configuration information.
188 //
189 // This function reads the provided configuration structure, and sets the
190 // relevant TPIU registers to achieve the desired configuration.
191 //
192 //*****************************************************************************
193 void
am_hal_tpiu_configure(am_hal_tpiu_config_t * psConfig)194 am_hal_tpiu_configure(am_hal_tpiu_config_t *psConfig)
195 {
196     //
197     // Set the clock freq in the MCUCTRL register.
198     //
199     MCUCTRL->TPIUCTRL |= psConfig->ui32TraceClkIn;
200 
201     //
202     // Set the desired protocol.
203     //
204     TPI->SPPR = psConfig->ui32PinProtocol;
205 
206     //
207     // Set the parallel port width. This may be redundant if the user has
208     // selected a serial protocol, but we'll set it anyway.
209     //
210     TPI->CSPSR = (1 << (psConfig->ui32ParallelPortSize - 1));
211 
212     //
213     // Set the clock prescaler.
214     //
215     TPI->ACPR = psConfig->ui32ClockPrescaler;
216 }
217 
218 //*****************************************************************************
219 //
220 // @brief Enables the TPIU
221 //
222 // This function enables the ARM TPIU by setting the TPIU registers and then
223 // enabling the TPIU clock source in MCU control register.
224 //
225 // @param psConfig - structure for configuration.
226 //     If ui32SetItmBaud, the other structure members are used to set the
227 //      TPIU configuration.
228 //     But for simplicity, ui32SetItmBaud can be set to one of the
229 //      following, in which case all other structure members are ignored.
230 //      In this case, the given BAUD rate is based on a div-by-8 HFRC clock.
231 //         AM_HAL_TPIU_BAUD_57600
232 //         AM_HAL_TPIU_BAUD_115200
233 //         AM_HAL_TPIU_BAUD_230400
234 //         AM_HAL_TPIU_BAUD_460800
235 //         AM_HAL_TPIU_BAUD_500000
236 //         AM_HAL_TPIU_BAUD_1M
237 //
238 //*****************************************************************************
239 void
am_hal_tpiu_enable(am_hal_tpiu_config_t * psConfig)240 am_hal_tpiu_enable(am_hal_tpiu_config_t *psConfig)
241 {
242     am_hal_clkgen_status_t sClkGenStatus;
243     uint32_t ui32HFRC, ui32SWOscaler, ui32ITMbitrate;
244 
245     ui32ITMbitrate = psConfig->ui32SetItmBaud;
246 
247     //
248     // TPIU formatter & flush control register.
249     //
250     TPI->FFCR = 0;
251 
252     if ( ui32ITMbitrate )
253     {
254         //
255         // Set the Current Parallel Port Size (note - only 1 bit can be set).
256         //
257         TPI->CSPSR = TPI_CSPSR_CWIDTH_1BIT;
258 
259         //
260         // Use some default assumptions to set the ITM frequency.
261         //
262         if ( (ui32ITMbitrate < AM_HAL_TPIU_BAUD_57600 )  ||
263              (ui32ITMbitrate > AM_HAL_TPIU_BAUD_2M ) )
264         {
265             ui32ITMbitrate = AM_HAL_TPIU_BAUD_DEFAULT;
266         }
267 
268         //
269         // Get the current HFRC frequency.
270         //
271         am_hal_clkgen_status_get(&sClkGenStatus);
272         ui32HFRC = sClkGenStatus.ui32SysclkFreq;
273 
274         //
275         // Compute the SWO scaler value.
276         //
277         if ( ui32HFRC != 0xFFFFFFFF )
278         {
279             ui32SWOscaler = ((ui32HFRC / 8) / ui32ITMbitrate) - 1;
280         }
281         else
282         {
283             ui32SWOscaler = ( (AM_HAL_CLKGEN_FREQ_MAX_HZ / 8) /
284                               AM_HAL_TPIU_BAUD_DEFAULT ) - 1;
285         }
286 
287         //
288         // Set the scaler value.
289         //
290         TPI->ACPR = _VAL2FLD(TPI_ACPR_SWOSCALER, ui32SWOscaler);
291 
292         //
293         // Set for UART mode
294         //
295         TPI->SPPR = _VAL2FLD( TPI_SPPR_TXMODE, TPI_SPPR_TXMODE_UART);
296 
297         //
298         // Make sure we are not in test mode (important for proper deep sleep
299         // operation).
300         //
301         TPI->ITCTRL = _VAL2FLD(TPI_ITCTRL_Mode, TPI_ITCTRL_Mode_NORMAL);
302 
303         //
304         // Enable the TPIU clock source in MCU control.
305         // Set TPIU clock for HFRC/8 (6MHz) operation.
306         //
307         MCUCTRL->TPIUCTRL =
308             _VAL2FLD(MCUCTRL_TPIUCTRL_CLKSEL, MCUCTRL_TPIUCTRL_CLKSEL_HFRCDIV8) |
309             _VAL2FLD(MCUCTRL_TPIUCTRL_ENABLE, MCUCTRL_TPIUCTRL_ENABLE_EN);
310     }
311     else
312     {
313         //
314         // Set the configuration according to the structure values.
315         //
316 
317         //
318         // Set the Asynchronous Clock Prescaler Register.
319         //
320         TPI->ACPR = psConfig->ui32ClockPrescaler;
321 
322         //
323         // Set the Selected Pin Protocol Register.
324         //  e.g. AM_REG_TPIU_SPPR_TXMODE_UART
325         //
326         TPI->SPPR = psConfig->ui32PinProtocol;
327 
328         //
329         // Set the Current Parallel Port Size (note - only 1 bit can be set).
330         // This may be redundant if the user has selected a serial protocol,
331         // but we'll set it anyway.
332         //
333         TPI->CSPSR = (1 << (psConfig->ui32ParallelPortSize - 1));
334 
335         //
336         // Make sure we are not in test mode (important for proper deep sleep
337         // operation).
338         //
339         TPI->ITCTRL = _VAL2FLD(TPI_ITCTRL_Mode, TPI_ITCTRL_Mode_NORMAL);
340 
341         //
342         // Set the clock freq and enable fields in the MCUCTRL register.
343         //
344         MCUCTRL->TPIUCTRL = psConfig->ui32TraceClkIn;
345     }
346 
347     //
348     // Wait for 50us for the data to flush out.
349     //
350     am_hal_flash_delay(FLASH_CYCLES_US(50));
351 }
352 
353 //*****************************************************************************
354 //
355 // @brief Disables the TPIU
356 //
357 // This function disables the ARM TPIU by disabling the TPIU clock source
358 //
359 //*****************************************************************************
360 void
am_hal_tpiu_disable(void)361 am_hal_tpiu_disable(void)
362 {
363     //
364     // Disable the TPIU clock source in MCU control.
365     //
366     MCUCTRL->TPIUCTRL =
367         _VAL2FLD(MCUCTRL_TPIUCTRL_CLKSEL, MCUCTRL_TPIUCTRL_CLKSEL_LOWPWR) |
368         _VAL2FLD(MCUCTRL_TPIUCTRL_ENABLE, MCUCTRL_TPIUCTRL_ENABLE_DIS);
369 }
370 
371 //*****************************************************************************
372 //
373 // End Doxygen group.
374 //! @}
375 //
376 //*****************************************************************************
377