9cdf08abef1ad780cffa1f1de0d0d21b477c91e9
[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(" ");
60
61         const struct swd_driver *swd = jtag_interface->swd;
62         assert(swd);
63
64         swd->write_reg(dap, (CMSIS_CMD_DP | CMSIS_CMD_WRITE | CMSIS_CMD_A32(DP_ABORT)),
65                         STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR);
66         return ERROR_OK;
67 }
68
69 static int cmsis_dap_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack)
70 {
71         LOG_DEBUG(" ");
72
73         const struct swd_driver *swd = jtag_interface->swd;
74         assert(swd);
75
76         swd->write_reg(dap, (CMSIS_CMD_DP | CMSIS_CMD_WRITE | CMSIS_CMD_A32(DP_ABORT)),
77                         DAPABORT | STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR);
78         return ERROR_OK;
79 }
80
81 static int cmsis_dap_queue_dp_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data)
82 {
83         LOG_DEBUG("reg = %d", reg);
84
85         const struct swd_driver *swd = jtag_interface->swd;
86         assert(swd);
87
88         swd->read_reg(dap, (CMSIS_CMD_DP | CMSIS_CMD_READ | CMSIS_CMD_A32(reg)), data);
89         return ERROR_OK;
90 }
91
92 static int (cmsis_dap_queue_dp_write)(struct adiv5_dap *dap, unsigned reg, uint32_t data)
93 {
94         LOG_DEBUG("reg = %d, data = 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         const struct swd_driver *swd = jtag_interface->swd;
104         assert(swd);
105
106         swd->write_reg(dap, (CMSIS_CMD_DP | CMSIS_CMD_WRITE | CMSIS_CMD_A32(reg)), data);
107         return ERROR_OK;
108 }
109
110 /** Select the AP register bank matching bits 7:4 of reg. */
111 static int cmsis_dap_ap_q_bankselect(struct adiv5_dap *dap, unsigned reg)
112 {
113         uint32_t select_ap_bank = reg & 0x000000F0;
114
115         if (select_ap_bank == dap->ap_bank_value)
116                 return ERROR_OK;
117
118         dap->ap_bank_value = select_ap_bank;
119         select_ap_bank |= dap->ap_current;
120
121         cmsis_dap_queue_dp_write(dap, DP_SELECT, select_ap_bank);
122         return ERROR_OK;
123 }
124
125 static int (cmsis_dap_queue_ap_read)(struct adiv5_dap *dap, unsigned reg, uint32_t *data)
126 {
127         cmsis_dap_ap_q_bankselect(dap, reg);
128
129         LOG_DEBUG("reg = %d", reg);
130
131         const struct swd_driver *swd = jtag_interface->swd;
132         assert(swd);
133
134         swd->read_reg(dap, (CMSIS_CMD_AP | CMSIS_CMD_READ | CMSIS_CMD_A32(reg)), data);
135
136         return ERROR_OK;
137 }
138
139 static int (cmsis_dap_queue_ap_write)(struct adiv5_dap *dap, unsigned reg, uint32_t data)
140 {
141         /* TODO: CSW_DBGSWENABLE (bit31) causes issues for some targets
142          * disable until we find out why */
143         if (reg == AP_REG_CSW)
144                 data &= ~CSW_DBGSWENABLE;
145
146         cmsis_dap_ap_q_bankselect(dap, reg);
147
148         LOG_DEBUG("reg = %d, data = 0x%08" PRIx32, reg, data);
149
150         const struct swd_driver *swd = jtag_interface->swd;
151         assert(swd);
152
153         swd->write_reg(dap, (CMSIS_CMD_AP | CMSIS_CMD_WRITE | CMSIS_CMD_A32(reg)), data);
154
155         return ERROR_OK;
156 }
157
158 /** Executes all queued DAP operations. */
159 static int cmsis_dap_run(struct adiv5_dap *dap)
160 {
161         LOG_DEBUG(" ");
162         /*
163           Some debug dongles do more than asked for(e.g. EDBG from
164           Atmel) behind the scene and issuing an AP write
165           may result in more than just APACC SWD transaction, which in
166           turn can possibly set sticky error bit in CTRL/STAT register
167           of the DP(an example would be writing SYSRESETREQ to AIRCR).
168           Such adapters may interpret CMSIS-DAP secification
169           differently and not guarantee to be report those failures
170           via status byte of the return USB packet from CMSIS-DAP, so
171           we need to check CTRL/STAT and if that happens to clear it.
172           Note that once the CMSIS-DAP SWD implementation starts queueing
173           transfers this will cause loss of the transfers after the
174           failed one. At least a warning is printed.
175         */
176         uint32_t ctrlstat;
177         cmsis_dap_queue_dp_read(dap, DP_CTRL_STAT, &ctrlstat);
178
179         int retval = jtag_interface->swd->run(dap);
180
181         if (retval == ERROR_OK && (ctrlstat & SSTICKYERR))
182                 LOG_WARNING("Adapter returned success despite SSTICKYERR being set.");
183
184         if (retval != ERROR_OK || (ctrlstat & SSTICKYERR))
185                 cmsis_dap_clear_sticky_errors(dap);
186
187         return retval;
188 }
189
190 const struct dap_ops cmsis_dap_ops = {
191         .is_swd = true,
192         .queue_dp_read       = cmsis_dap_queue_dp_read,
193         .queue_dp_write      = cmsis_dap_queue_dp_write,
194         .queue_ap_read       = cmsis_dap_queue_ap_read,
195         .queue_ap_write      = cmsis_dap_queue_ap_write,
196         .queue_ap_abort      = cmsis_dap_queue_ap_abort,
197         .run = cmsis_dap_run,
198 };
199
200 static const struct command_registration cmsis_dap_commands[] = {
201         {
202         /*
203         * Set up SWD and JTAG targets identically, unless/until
204         * infrastructure improves ...  meanwhile, ignore all
205         * JTAG-specific stuff like IR length for SWD.
206         *
207         * REVISIT can we verify "just one SWD DAP" here/early?
208         */
209                 .name = "newdap",
210                 .jim_handler = jim_jtag_newtap,
211                 .mode = COMMAND_CONFIG,
212                 .help = "declare a new CMSIS-DAP"
213         },
214         COMMAND_REGISTRATION_DONE
215 };
216
217 static const struct command_registration cmsis_dap_handlers[] = {
218         {
219                 .name = "cmsis-dap",
220                 .mode = COMMAND_ANY,
221                 .help = "cmsis_dap command group",
222                 .chain = cmsis_dap_commands,
223         },
224         COMMAND_REGISTRATION_DONE
225 };
226
227 static int cmsis_dap_select(struct command_context *ctx)
228 {
229         LOG_DEBUG("CMSIS-ADI: cmsis_dap_select");
230
231         int retval = register_commands(ctx, NULL, cmsis_dap_handlers);
232
233         if (retval != ERROR_OK)
234                 return retval;
235
236         /* FIXME: This needs a real overhaul!! FIXME
237          * be sure driver is in SWD mode; start
238          * with hardware default TRN (1), it can be changed later
239          * we use a bogus 'swd' driver to implement cmsis-dap as it is quite similar */
240
241         const struct swd_driver *swd = jtag_interface->swd;
242         if (!swd || !swd->read_reg || !swd->write_reg || !swd->init) {
243                 LOG_ERROR("no SWD driver?");
244                 return ERROR_FAIL;
245         }
246
247         retval = swd->init();
248         if (retval != ERROR_OK) {
249                 LOG_ERROR("unable to init CMSIS-DAP driver");
250                 return retval;
251         }
252
253         return retval;
254 }
255
256 static int cmsis_dap_init(struct command_context *ctx)
257 {
258         struct target *target = get_current_target(ctx);
259         struct arm *arm = target_to_arm(target);
260         struct adiv5_dap *dap = arm->dap;
261         uint32_t idcode;
262         int status;
263
264         LOG_DEBUG("CMSIS-ADI init");
265
266         /* Force the DAP's ops vector for CMSIS-DAP mode.
267          * messy - is there a better way? */
268         arm->dap->ops = &cmsis_dap_ops;
269
270         /* FIXME validate transport config ... is the
271          * configured DAP present (check IDCODE)?
272          * Is *only* one DAP configured?
273          *
274          * MUST READ IDCODE
275          */
276
277         /* Note, debugport_init() does setup too */
278
279 #if 0
280         const struct swd_driver *swd = jtag_interface->swd;
281         if (!swd || !swd->read_reg || !swd->write_reg || !swd->init) {
282                 LOG_ERROR("no SWD driver?");
283                 return ERROR_FAIL;
284         }
285
286         int retval = swd->init(1);
287         if (retval != ERROR_OK) {
288                 LOG_ERROR("unable to init CMSIS-DAP driver");
289                 return retval;
290         }
291 #endif
292
293         status = cmsis_dap_queue_dp_read(dap, DP_IDCODE, &idcode);
294
295         if (status == ERROR_OK)
296                 LOG_INFO("IDCODE 0x%08" PRIx32, idcode);
297
298         /* force clear all sticky faults */
299         cmsis_dap_clear_sticky_errors(dap);
300
301         /* this is a workaround to get polling working */
302         jtag_add_reset(0, 0);
303
304         return status;
305 }
306
307 static struct transport cmsis_dap_transport = {
308         .name = "cmsis-dap",
309         .select = cmsis_dap_select,
310         .init = cmsis_dap_init,
311 };
312
313 static void cmsis_dap_constructor(void) __attribute__((constructor));
314 static void cmsis_dap_constructor(void)
315 {
316         transport_register(&cmsis_dap_transport);
317 }
318
319 /** Returns true if the current debug session
320  * is using CMSIS-DAP as its transport.
321  */
322 bool transport_is_cmsis_dap(void)
323 {
324         return get_current_transport() == &cmsis_dap_transport;
325 }