openocd: fix SPDX tag format for files .c
[fw/openocd] / src / target / armv7m_trace.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4  *   Copyright (C) 2015  Paul Fertser <fercerpav@gmail.com>                *
5  ***************************************************************************/
6
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10
11 #include <target/target.h>
12 #include <target/armv7m.h>
13 #include <target/cortex_m.h>
14 #include <target/armv7m_trace.h>
15 #include <jtag/interface.h>
16 #include <helper/time_support.h>
17
18 int armv7m_trace_itm_config(struct target *target)
19 {
20         struct armv7m_common *armv7m = target_to_armv7m(target);
21         struct armv7m_trace_config *trace_config = &armv7m->trace_config;
22         int retval;
23
24         retval = target_write_u32(target, ITM_LAR, ITM_LAR_KEY);
25         if (retval != ERROR_OK)
26                 return retval;
27
28         /* pg315 of CoreSight Components
29          * It is recommended that the ITMEn bit is cleared and waits for the
30          * ITMBusy bit to be cleared, before changing any fields in the
31          * Control Register, otherwise the behavior can be unpredictable.
32          */
33         uint32_t itm_tcr;
34         retval = target_read_u32(target, ITM_TCR, &itm_tcr);
35         if (retval != ERROR_OK)
36                 return retval;
37         retval = target_write_u32(target,
38                         ITM_TCR,
39                         itm_tcr & ~ITM_TCR_ITMENA_BIT
40                         );
41         if (retval != ERROR_OK)
42                 return retval;
43
44         int64_t then = timeval_ms() + 1000;
45         do {
46                 retval = target_read_u32(target, ITM_TCR, &itm_tcr);
47                 if (retval != ERROR_OK)
48                         return retval;
49                 if (timeval_ms() > then) {
50                         LOG_ERROR("timeout waiting for ITM_TCR_BUSY_BIT");
51                         return ERROR_FAIL;
52                 }
53         } while (itm_tcr & ITM_TCR_BUSY_BIT);
54
55         /* Enable ITM, TXENA, set TraceBusID and other parameters */
56         retval = target_write_u32(target, ITM_TCR, (1 << 0) | (1 << 3) |
57                                   (trace_config->itm_diff_timestamps << 1) |
58                                   (trace_config->itm_synchro_packets << 2) |
59                                   (trace_config->itm_async_timestamps << 4) |
60                                   (trace_config->itm_ts_prescale << 8) |
61                                   (trace_config->trace_bus_id << 16));
62         if (retval != ERROR_OK)
63                 return retval;
64
65         for (unsigned int i = 0; i < 8; i++) {
66                 retval = target_write_u32(target, ITM_TER0 + i * 4,
67                                           trace_config->itm_ter[i]);
68                 if (retval != ERROR_OK)
69                         return retval;
70         }
71
72         return ERROR_OK;
73 }
74
75 COMMAND_HANDLER(handle_itm_port_command)
76 {
77         struct target *target = get_current_target(CMD_CTX);
78         struct armv7m_common *armv7m = target_to_armv7m(target);
79         unsigned int reg_idx;
80         uint8_t port;
81         bool enable;
82
83         if (CMD_ARGC != 2)
84                 return ERROR_COMMAND_SYNTAX_ERROR;
85
86         COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], port);
87         COMMAND_PARSE_ON_OFF(CMD_ARGV[1], enable);
88         reg_idx = port / 32;
89         port = port % 32;
90         if (enable)
91                 armv7m->trace_config.itm_ter[reg_idx] |= (1 << port);
92         else
93                 armv7m->trace_config.itm_ter[reg_idx] &= ~(1 << port);
94
95         if (CMD_CTX->mode == COMMAND_EXEC)
96                 return armv7m_trace_itm_config(target);
97
98         armv7m->trace_config.itm_deferred_config = true;
99         return ERROR_OK;
100 }
101
102 COMMAND_HANDLER(handle_itm_ports_command)
103 {
104         struct target *target = get_current_target(CMD_CTX);
105         struct armv7m_common *armv7m = target_to_armv7m(target);
106         bool enable;
107
108         if (CMD_ARGC != 1)
109                 return ERROR_COMMAND_SYNTAX_ERROR;
110
111         COMMAND_PARSE_ON_OFF(CMD_ARGV[0], enable);
112         memset(armv7m->trace_config.itm_ter, enable ? 0xff : 0,
113                sizeof(armv7m->trace_config.itm_ter));
114
115         if (CMD_CTX->mode == COMMAND_EXEC)
116                 return armv7m_trace_itm_config(target);
117
118         armv7m->trace_config.itm_deferred_config = true;
119         return ERROR_OK;
120 }
121
122 static const struct command_registration itm_command_handlers[] = {
123         {
124                 .name = "port",
125                 .handler = handle_itm_port_command,
126                 .mode = COMMAND_ANY,
127                 .help = "Enable or disable ITM stimulus port",
128                 .usage = "<port> (0|1|on|off)",
129         },
130         {
131                 .name = "ports",
132                 .handler = handle_itm_ports_command,
133                 .mode = COMMAND_ANY,
134                 .help = "Enable or disable all ITM stimulus ports",
135                 .usage = "(0|1|on|off)",
136         },
137         COMMAND_REGISTRATION_DONE
138 };
139
140 const struct command_registration armv7m_trace_command_handlers[] = {
141         {
142                 .name = "itm",
143                 .mode = COMMAND_ANY,
144                 .help = "itm command group",
145                 .usage = "",
146                 .chain = itm_command_handlers,
147         },
148         COMMAND_REGISTRATION_DONE
149 };