e830089f478ec70f240bbc457431df685d921fed
[fw/openocd] / src / target / adi_v5_cmsis_dap.c
1 /***************************************************************************
2  *   Copyright (C) 2013 by mike brown                                      *
3  *   mike@theshedworks.org.uk                                              *
4  *                                                                         *
5  *   Copyright (C) 2013 by Spencer Oliver                                  *
6  *   spen@spen-soft.co.uk                                                  *
7  *                                                                         *
8  *   This program is free software; you can redistribute it and/or modify  *
9  *   it under the terms of the GNU General Public License as published by  *
10  *   the Free Software Foundation; either version 2 of the License, or     *
11  *   (at your option) any later version.                                   *
12  *                                                                         *
13  *   This program is distributed in the hope that it will be useful,       *
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
16  *   GNU General Public License for more details.                          *
17  *                                                                         *
18  *   You should have received a copy of the GNU General Public License     *
19  *   along with this program; if not, write to the                         *
20  *   Free Software Foundation, Inc.,                                       *
21  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
22  ***************************************************************************/
23
24 /**
25  * @file
26  * Utilities to support ARM "CMSIS-DAP", The CoreSight Debug Access Port.
27  * This is coupled to recent versions of ARM's "CoreSight" debug framework.
28  * This specific code is a transport level interface, with
29  * "target/arm_adi_v5.[hc]" code understanding operation semantics,
30  * shared with the SWD & JTAG transports.
31  */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #include "arm.h"
38 #include "arm_adi_v5.h"
39 #include <helper/time_support.h>
40
41 #include <transport/transport.h>
42 #include <jtag/interface.h>
43
44 #include <jtag/swd.h>
45
46 #define CMSIS_CMD_DP            (0   << 0)    /* set only for AP access */
47 #define CMSIS_CMD_AP            (1   << 0)    /* set only for AP access */
48 #define CMSIS_CMD_READ          (1   << 1)    /* set only for read access */
49 #define CMSIS_CMD_WRITE         (0   << 1)    /* set only for read access */
50 #define CMSIS_CMD_A32(n)        ((n)&0x0C)    /* bits A[3:2] of register addr */
51 #define CMSIS_CMD_VAL_MATCH     (1   << 4)    /* Value Match */
52 #define CMSIS_CMD_MATCH_MSK     (1   << 5)    /* Match Mask */
53
54 /* YUK! - but this is currently a global.... */
55 extern struct jtag_interface *jtag_interface;
56
57 static int cmsis_dap_clear_sticky_errors(struct adiv5_dap *dap)
58 {
59         LOG_DEBUG("CMSIS-ADI: %s", __func__);
60
61         const struct swd_driver *swd = jtag_interface->swd;
62         assert(swd);
63
64         return swd->write_reg(swd_cmd(false,  false, DP_ABORT),
65                               STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR);
66 }
67
68 static int cmsis_dap_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack)
69 {
70         LOG_DEBUG("CMSIS-ADI: %s", __func__);
71
72         const struct swd_driver *swd = jtag_interface->swd;
73         assert(swd);
74
75         return swd->write_reg(swd_cmd(false,  false, DP_ABORT),
76                               DAPABORT | STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR);
77 }
78
79 static int cmsis_dap_queue_dp_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data)
80 {
81         LOG_DEBUG("CMSIS-ADI: cmsis_dap_queue_dp_read %d", reg);
82
83         int retval = jtag_interface->swd->read_reg(
84                         (CMSIS_CMD_DP | CMSIS_CMD_READ | CMSIS_CMD_A32(reg)), data);
85
86         if (retval != ERROR_OK)
87                 cmsis_dap_clear_sticky_errors(dap);
88
89         return retval;
90 }
91
92 static int (cmsis_dap_queue_dp_write)(struct adiv5_dap *dap, unsigned reg, uint32_t data)
93 {
94         LOG_DEBUG("CMSIS-ADI: cmsis_dap_queue_dp_write %d 0x%08" PRIx32, reg, data);
95
96         /* setting the ORUNDETECT bit causes issues for some targets,
97          * disable until we find out why */
98         if (reg == DP_CTRL_STAT) {
99                 LOG_DEBUG("disabling overrun detection");
100                 data &= ~CORUNDETECT;
101         }
102
103         int retval = jtag_interface->swd->write_reg(
104                         (CMSIS_CMD_DP | CMSIS_CMD_WRITE | CMSIS_CMD_A32(reg)), data);
105
106         if (retval != ERROR_OK)
107                 cmsis_dap_clear_sticky_errors(dap);
108
109         return retval;
110 }
111
112 /** Select the AP register bank matching bits 7:4 of reg. */
113 static int cmsis_dap_ap_q_bankselect(struct adiv5_dap *dap, unsigned reg)
114 {
115         uint32_t select_ap_bank = reg & 0x000000F0;
116
117         if (select_ap_bank == dap->ap_bank_value)
118                 return ERROR_OK;
119
120         dap->ap_bank_value = select_ap_bank;
121         select_ap_bank |= dap->ap_current;
122
123         return cmsis_dap_queue_dp_write(dap, DP_SELECT, select_ap_bank);
124 }
125
126 static int (cmsis_dap_queue_ap_read)(struct adiv5_dap *dap, unsigned reg, uint32_t *data)
127 {
128         int retval = cmsis_dap_ap_q_bankselect(dap, reg);
129         if (retval != ERROR_OK)
130                 return retval;
131
132         LOG_DEBUG("CMSIS-ADI: cmsis_dap_queue_ap_read %d", reg);
133
134         retval = jtag_interface->swd->read_reg(
135                         (CMSIS_CMD_AP | CMSIS_CMD_READ | CMSIS_CMD_A32(reg)), data);
136
137         if (retval != ERROR_OK)
138                 cmsis_dap_clear_sticky_errors(dap);
139
140         return retval;
141 }
142
143 static int (cmsis_dap_queue_ap_write)(struct adiv5_dap *dap, unsigned reg, uint32_t data)
144 {
145
146
147         /* TODO: CSW_DBGSWENABLE (bit31) causes issues for some targets
148          * disable until we find out why */
149         if (reg == AP_REG_CSW)
150                 data &= ~CSW_DBGSWENABLE;
151
152         int retval = cmsis_dap_ap_q_bankselect(dap, reg);
153         if (retval != ERROR_OK)
154                 return retval;
155
156         LOG_DEBUG("CMSIS-ADI: cmsis_dap_queue_ap_write %d 0x%08" PRIx32, reg, data);
157
158         retval = jtag_interface->swd->write_reg(
159                         (CMSIS_CMD_AP | CMSIS_CMD_WRITE | CMSIS_CMD_A32(reg)), data);
160
161         if (retval != ERROR_OK)
162                 cmsis_dap_clear_sticky_errors(dap);
163
164         return retval;
165 }
166
167 /** Executes all queued DAP operations. */
168 static int cmsis_dap_run(struct adiv5_dap *dap)
169 {
170         LOG_DEBUG("CMSIS-ADI: cmsis_dap_run");
171         /* FIXME: for now the CMSIS-DAP interface hard-wires a zero-size queue. */
172
173         return ERROR_OK;
174 }
175
176 const struct dap_ops cmsis_dap_ops = {
177         .is_swd = true,
178         .queue_dp_read       = cmsis_dap_queue_dp_read,
179         .queue_dp_write      = cmsis_dap_queue_dp_write,
180         .queue_ap_read       = cmsis_dap_queue_ap_read,
181         .queue_ap_write      = cmsis_dap_queue_ap_write,
182         .queue_ap_abort      = cmsis_dap_queue_ap_abort,
183         .run = cmsis_dap_run,
184 };
185
186 static const struct command_registration cmsis_dap_commands[] = {
187         {
188         /*
189         * Set up SWD and JTAG targets identically, unless/until
190         * infrastructure improves ...  meanwhile, ignore all
191         * JTAG-specific stuff like IR length for SWD.
192         *
193         * REVISIT can we verify "just one SWD DAP" here/early?
194         */
195                 .name = "newdap",
196                 .jim_handler = jim_jtag_newtap,
197                 .mode = COMMAND_CONFIG,
198                 .help = "declare a new CMSIS-DAP"
199         },
200         COMMAND_REGISTRATION_DONE
201 };
202
203 static const struct command_registration cmsis_dap_handlers[] = {
204         {
205                 .name = "cmsis-dap",
206                 .mode = COMMAND_ANY,
207                 .help = "cmsis_dap command group",
208                 .chain = cmsis_dap_commands,
209         },
210         COMMAND_REGISTRATION_DONE
211 };
212
213 static int cmsis_dap_select(struct command_context *ctx)
214 {
215         LOG_DEBUG("CMSIS-ADI: cmsis_dap_select");
216
217         int retval = register_commands(ctx, NULL, cmsis_dap_handlers);
218
219         if (retval != ERROR_OK)
220                 return retval;
221
222         /* FIXME: This needs a real overhaul!! FIXME
223          * be sure driver is in SWD mode; start
224          * with hardware default TRN (1), it can be changed later
225          * we use a bogus 'swd' driver to implement cmsis-dap as it is quite similar */
226
227         const struct swd_driver *swd = jtag_interface->swd;
228         if (!swd || !swd->read_reg || !swd->write_reg || !swd->init) {
229                 LOG_ERROR("no SWD driver?");
230                 return ERROR_FAIL;
231         }
232
233         retval = swd->init(1);
234         if (retval != ERROR_OK) {
235                 LOG_ERROR("unable to init CMSIS-DAP driver");
236                 return retval;
237         }
238
239         return retval;
240 }
241
242 static int cmsis_dap_init(struct command_context *ctx)
243 {
244         struct target *target = get_current_target(ctx);
245         struct arm *arm = target_to_arm(target);
246         struct adiv5_dap *dap = arm->dap;
247         uint32_t idcode;
248         int status;
249
250         LOG_DEBUG("CMSIS-ADI: cmsis_dap_init");
251
252         /* Force the DAP's ops vector for CMSIS-DAP mode.
253          * messy - is there a better way? */
254         arm->dap->ops = &cmsis_dap_ops;
255
256         /* FIXME validate transport config ... is the
257          * configured DAP present (check IDCODE)?
258          * Is *only* one DAP configured?
259          *
260          * MUST READ IDCODE
261          */
262
263         /* Note, debugport_init() does setup too */
264
265 #if 0
266         const struct swd_driver *swd = jtag_interface->swd;
267         if (!swd || !swd->read_reg || !swd->write_reg || !swd->init) {
268                 LOG_ERROR("no SWD driver?");
269                 return ERROR_FAIL;
270         }
271
272         int retval = swd->init(1);
273         if (retval != ERROR_OK) {
274                 LOG_ERROR("unable to init CMSIS-DAP driver");
275                 return retval;
276         }
277 #endif
278
279         status = cmsis_dap_queue_dp_read(dap, DP_IDCODE, &idcode);
280
281         if (status == ERROR_OK)
282                 LOG_INFO("IDCODE 0x%08" PRIx32, idcode);
283
284         /* force clear all sticky faults */
285         cmsis_dap_clear_sticky_errors(dap);
286
287         /* this is a workaround to get polling working */
288         jtag_add_reset(0, 0);
289
290         return status;
291 }
292
293 static struct transport cmsis_dap_transport = {
294         .name = "cmsis-dap",
295         .select = cmsis_dap_select,
296         .init = cmsis_dap_init,
297 };
298
299 static void cmsis_dap_constructor(void) __attribute__((constructor));
300 static void cmsis_dap_constructor(void)
301 {
302         transport_register(&cmsis_dap_transport);
303 }
304
305 /** Returns true if the current debug session
306  * is using CMSIS-DAP as its transport.
307  */
308 bool transport_is_cmsis_dap(void)
309 {
310         return get_current_transport() == &cmsis_dap_transport;
311 }