kinetis: Revise CPU un-securing code
[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_queue_ap_abort)(struct adiv5_dap *dap, uint8_t *ack)
58 {
59         LOG_DEBUG("CMSIS-ADI: cmsis_dap_queue_ap_abort");
60
61         /* FIXME: implement this properly cmsis-dap has DAP_WriteABORT()
62          * for now just hack @ everything */
63         return jtag_interface->swd->write_reg(
64                         (CMSIS_CMD_DP | CMSIS_CMD_WRITE | CMSIS_CMD_A32(DP_ABORT)), 0x1e);
65 }
66
67 static int cmsis_dap_queue_dp_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data)
68 {
69         LOG_DEBUG("CMSIS-ADI: cmsis_dap_queue_dp_read %d", reg);
70
71         int retval = jtag_interface->swd->read_reg(
72                         (CMSIS_CMD_DP | CMSIS_CMD_READ | CMSIS_CMD_A32(reg)), data);
73
74         if (retval != ERROR_OK) {
75                 /* fault response */
76                 uint8_t ack = retval & 0xff;
77                 cmsis_dap_queue_ap_abort(dap, &ack);
78         }
79
80         return retval;
81 }
82
83 static int cmsis_dap_queue_idcode_read(struct adiv5_dap *dap, uint8_t *ack, uint32_t *data)
84 {
85         LOG_DEBUG("CMSIS-ADI: cmsis_dap_queue_idcode_read");
86
87         int retval = cmsis_dap_queue_dp_read(dap, DP_IDCODE, data);
88         if (retval != ERROR_OK)
89                 return retval;
90
91         *ack = retval;
92
93         return ERROR_OK;
94 }
95
96 static int (cmsis_dap_queue_dp_write)(struct adiv5_dap *dap, unsigned reg, uint32_t data)
97 {
98         LOG_DEBUG("CMSIS-ADI: cmsis_dap_queue_dp_write %d 0x%08" PRIx32, reg, data);
99
100         /* setting the ORUNDETECT bit causes issues for some targets,
101          * disable until we find out why */
102         if (reg == DP_CTRL_STAT) {
103                 LOG_DEBUG("disabling overrun detection");
104                 data &= ~CORUNDETECT;
105         }
106
107         int retval = jtag_interface->swd->write_reg(
108                         (CMSIS_CMD_DP | CMSIS_CMD_WRITE | CMSIS_CMD_A32(reg)), data);
109
110         if (retval != ERROR_OK) {
111                 /* fault response */
112                 uint8_t ack = retval & 0xff;
113                 cmsis_dap_queue_ap_abort(dap, &ack);
114         }
115
116         return retval;
117 }
118
119 /** Select the AP register bank matching bits 7:4 of reg. */
120 static int cmsis_dap_ap_q_bankselect(struct adiv5_dap *dap, unsigned reg)
121 {
122         uint32_t select_ap_bank = reg & 0x000000F0;
123
124         if (select_ap_bank == dap->ap_bank_value)
125                 return ERROR_OK;
126
127         dap->ap_bank_value = select_ap_bank;
128         select_ap_bank |= dap->ap_current;
129
130         return cmsis_dap_queue_dp_write(dap, DP_SELECT, select_ap_bank);
131 }
132
133 static int (cmsis_dap_queue_ap_read)(struct adiv5_dap *dap, unsigned reg, uint32_t *data)
134 {
135         LOG_DEBUG("CMSIS-ADI: cmsis_dap_queue_ap_read %d", reg);
136
137         int retval = cmsis_dap_ap_q_bankselect(dap, reg);
138         if (retval != ERROR_OK)
139                 return retval;
140
141         retval = jtag_interface->swd->read_reg(
142                         (CMSIS_CMD_AP | CMSIS_CMD_READ | CMSIS_CMD_A32(reg)), data);
143
144         if (retval != ERROR_OK) {
145                 /* fault response */
146                 uint8_t ack = retval & 0xff;
147                 cmsis_dap_queue_ap_abort(dap, &ack);
148         }
149
150         return retval;
151 }
152
153 static int (cmsis_dap_queue_ap_write)(struct adiv5_dap *dap, unsigned reg, uint32_t data)
154 {
155         LOG_DEBUG("CMSIS-ADI: cmsis_dap_queue_ap_write %d 0x%08" PRIx32, reg, data);
156
157         /* TODO: CSW_DBGSWENABLE (bit31) causes issues for some targets
158          * disable until we find out why */
159         if (reg == AP_REG_CSW)
160                 data &= ~CSW_DBGSWENABLE;
161
162         int retval = cmsis_dap_ap_q_bankselect(dap, reg);
163         if (retval != ERROR_OK)
164                 return retval;
165
166         retval = jtag_interface->swd->write_reg(
167                         (CMSIS_CMD_AP | CMSIS_CMD_WRITE | CMSIS_CMD_A32(reg)), data);
168
169         if (retval != ERROR_OK) {
170                 /* fault response */
171                 uint8_t ack = retval & 0xff;
172                 cmsis_dap_queue_ap_abort(dap, &ack);
173         }
174
175         return retval;
176 }
177
178 static int (cmsis_dap_queue_ap_read_block)(struct adiv5_dap *dap, unsigned reg,
179                 uint32_t blocksize, uint8_t *buffer)
180 {
181         LOG_DEBUG("CMSIS-ADI: cmsis_dap_queue_ap_read_block 0x%08" PRIx32, blocksize);
182
183         int retval = jtag_interface->swd->read_block(
184                         (CMSIS_CMD_AP | CMSIS_CMD_READ | CMSIS_CMD_A32(AP_REG_DRW)),
185                         blocksize, buffer);
186
187         if (retval != ERROR_OK) {
188                 /* fault response */
189                 uint8_t ack = retval & 0xff;
190                 cmsis_dap_queue_ap_abort(dap, &ack);
191         }
192
193         return retval;
194 }
195
196 /** Executes all queued DAP operations. */
197 static int cmsis_dap_run(struct adiv5_dap *dap)
198 {
199         LOG_DEBUG("CMSIS-ADI: cmsis_dap_run");
200         /* FIXME: for now the CMSIS-DAP interface hard-wires a zero-size queue. */
201
202         return ERROR_OK;
203 }
204
205 const struct dap_ops cmsis_dap_ops = {
206         .is_swd = true,
207         .queue_idcode_read   = cmsis_dap_queue_idcode_read,
208         .queue_dp_read       = cmsis_dap_queue_dp_read,
209         .queue_dp_write      = cmsis_dap_queue_dp_write,
210         .queue_ap_read       = cmsis_dap_queue_ap_read,
211         .queue_ap_write      = cmsis_dap_queue_ap_write,
212         .queue_ap_read_block = cmsis_dap_queue_ap_read_block,
213         .queue_ap_abort      = cmsis_dap_queue_ap_abort,
214         .run = cmsis_dap_run,
215 };
216
217 static const struct command_registration cmsis_dap_commands[] = {
218         {
219         /*
220         * Set up SWD and JTAG targets identically, unless/until
221         * infrastructure improves ...  meanwhile, ignore all
222         * JTAG-specific stuff like IR length for SWD.
223         *
224         * REVISIT can we verify "just one SWD DAP" here/early?
225         */
226                 .name = "newdap",
227                 .jim_handler = jim_jtag_newtap,
228                 .mode = COMMAND_CONFIG,
229                 .help = "declare a new CMSIS-DAP"
230         },
231         COMMAND_REGISTRATION_DONE
232 };
233
234 static const struct command_registration cmsis_dap_handlers[] = {
235         {
236                 .name = "cmsis-dap",
237                 .mode = COMMAND_ANY,
238                 .help = "cmsis_dap command group",
239                 .chain = cmsis_dap_commands,
240         },
241         COMMAND_REGISTRATION_DONE
242 };
243
244 static int cmsis_dap_select(struct command_context *ctx)
245 {
246         LOG_DEBUG("CMSIS-ADI: cmsis_dap_select");
247
248         int retval = register_commands(ctx, NULL, cmsis_dap_handlers);
249
250         if (retval != ERROR_OK)
251                 return retval;
252
253         /* FIXME: This needs a real overhaul!! FIXME
254          * be sure driver is in SWD mode; start
255          * with hardware default TRN (1), it can be changed later
256          * we use a bogus 'swd' driver to implement cmsis-dap as it is quite similar */
257
258         const struct swd_driver *swd = jtag_interface->swd;
259         if (!swd || !swd->read_reg || !swd->write_reg || !swd->init) {
260                 LOG_ERROR("no SWD driver?");
261                 return ERROR_FAIL;
262         }
263
264         retval = swd->init(1);
265         if (retval != ERROR_OK) {
266                 LOG_ERROR("unable to init CMSIS-DAP driver");
267                 return retval;
268         }
269
270         return retval;
271 }
272
273 static int cmsis_dap_init(struct command_context *ctx)
274 {
275         struct target *target = get_current_target(ctx);
276         struct arm *arm = target_to_arm(target);
277         struct adiv5_dap *dap = arm->dap;
278         uint32_t idcode;
279         int status;
280
281         LOG_DEBUG("CMSIS-ADI: cmsis_dap_init");
282
283         /* Force the DAP's ops vector for CMSIS-DAP mode.
284          * messy - is there a better way? */
285         arm->dap->ops = &cmsis_dap_ops;
286
287         /* FIXME validate transport config ... is the
288          * configured DAP present (check IDCODE)?
289          * Is *only* one DAP configured?
290          *
291          * MUST READ IDCODE
292          */
293
294         /* Note, debugport_init() does setup too */
295
296 #if 0
297         const struct swd_driver *swd = jtag_interface->swd;
298         if (!swd || !swd->read_reg || !swd->write_reg || !swd->init) {
299                 LOG_ERROR("no SWD driver?");
300                 return ERROR_FAIL;
301         }
302
303         int retval = swd->init(1);
304         if (retval != ERROR_OK) {
305                 LOG_ERROR("unable to init CMSIS-DAP driver");
306                 return retval;
307         }
308 #endif
309
310         uint8_t ack;
311
312         status = cmsis_dap_queue_idcode_read(dap, &ack, &idcode);
313
314         if (status == ERROR_OK)
315                 LOG_INFO("IDCODE 0x%08" PRIx32, idcode);
316
317         /* force clear all sticky faults */
318         cmsis_dap_queue_ap_abort(dap, &ack);
319
320         /* this is a workaround to get polling working */
321         jtag_add_reset(0, 0);
322
323         return status;
324 }
325
326 static struct transport cmsis_dap_transport = {
327         .name = "cmsis-dap",
328         .select = cmsis_dap_select,
329         .init = cmsis_dap_init,
330 };
331
332 static void cmsis_dap_constructor(void) __attribute__((constructor));
333 static void cmsis_dap_constructor(void)
334 {
335         transport_register(&cmsis_dap_transport);
336 }
337
338 /** Returns true if the current debug session
339  * is using CMSIS-DAP as its transport.
340  */
341 bool transport_is_cmsis_dap(void)
342 {
343         return get_current_transport() == &cmsis_dap_transport;
344 }