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