arm_adi_v5.c 53.6 KB
Newer Older
1
2
3
4
5
6
7
8
9
/***************************************************************************
 *   Copyright (C) 2006 by Magnus Lundin                                   *
 *   lundin@mlu.mine.nu                                                    *
 *                                                                         *
 *   Copyright (C) 2008 by Spencer Oliver                                  *
 *   spen@spen-soft.co.uk                                                  *
 *                                                                         *
 *   Copyright (C) 2009 by Oyvind Harboe                                   *
 *   oyvind.harboe@zylin.com                                               *
10
 *                                                                         *
11
12
 *   Copyright (C) 2009-2010 by David Brownell                             *
 *                                                                         *
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

/**
 * @file
 * This file implements support for the ARM Debug Interface version 5 (ADIv5)
 * debugging architecture.  Compared with previous versions, this includes
 * a low pin-count Serial Wire Debug (SWD) alternative to JTAG for message
 * transport, and focusses on memory mapped resources as defined by the
 * CoreSight architecture.
 *
 * A key concept in ADIv5 is the Debug Access Port, or DAP.  A DAP has two
 * basic components:  a Debug Port (DP) transporting messages to and from a
 * debugger, and an Access Port (AP) accessing resources.  Three types of DP
 * are defined.  One uses only JTAG for communication, and is called JTAG-DP.
 * One uses only SWD for communication, and is called SW-DP.  The third can
 * use either SWD or JTAG, and is called SWJ-DP.  The most common type of AP
 * is used to access memory mapped resources and is called a MEM-AP.  Also a
 * JTAG-AP is also defined, bridging to JTAG resources; those are uncommon.
David Brownell's avatar
David Brownell committed
45
 *
46
47
48
49
50
51
52
53
54
55
 * This programming interface allows DAP pipelined operations through a
 * transaction queue.  This primarily affects AP operations (such as using
 * a MEM-AP to access memory or registers).  If the current transaction has
 * not finished by the time the next one must begin, and the ORUNDETECT bit
 * is set in the DP_CTRL_STAT register, the SSTICKYORUN status is set and
 * further AP operations will fail.  There are two basic methods to avoid
 * such overrun errors.  One involves polling for status instead of using
 * transaction piplining.  The other involves adding delays to ensure the
 * AP has enough time to complete one operation before starting the next
 * one.  (For JTAG these delays are controlled by memaccess_tck.)
56
57
58
59
60
61
62
63
64
65
66
 */

/*
 * Relevant specifications from ARM include:
 *
 * ARM(tm) Debug Interface v5 Architecture Specification    ARM IHI 0031A
 * CoreSight(tm) v1.0 Architecture Specification            ARM IHI 0029B
 *
 * CoreSight(tm) DAP-Lite TRM, ARM DDI 0316D
 * Cortex-M3(tm) TRM, ARM DDI 0337G
 */
67
68
69
70
71
72

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "arm_adi_v5.h"
73
#include <helper/time_support.h>
74

75
76
77
78

/* ARM ADI Specification requires at least 10 bits used for TAR autoincrement  */

/*
79
	uint32_t tar_block_size(uint32_t address)
80
81
	Return the largest block starting at address that does not cross a tar block size alignment boundary
*/
82
static uint32_t max_tar_block_size(uint32_t tar_autoincr_block, uint32_t address)
83
84
85
86
{
	return (tar_autoincr_block - ((tar_autoincr_block - 1) & address)) >> 2;
}

87
88
89
90
91
92
/***************************************************************************
 *                                                                         *
 * DPACC and APACC scanchain access through JTAG-DP                        *
 *                                                                         *
***************************************************************************/

David Brownell's avatar
David Brownell committed
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/**
 * Scan DPACC or APACC using target ordered uint8_t buffers.  No endianness
 * conversions are performed.  See section 4.4.3 of the ADIv5 spec, which
 * discusses operations which access these registers.
 *
 * Note that only one scan is performed.  If RnW is set, a separate scan
 * will be needed to collect the data which was read; the "invalue" collects
 * the posted result of a preceding operation, not the current one.
 *
 * @param swjdp the DAP
 * @param instr JTAG_DP_APACC (AP access) or JTAG_DP_DPACC (DP access)
 * @param reg_addr two significant bits; A[3:2]; for APACC access, the
 *	SELECT register has more addressing bits.
 * @param RnW false iff outvalue will be written to the DP or AP
 * @param outvalue points to a 32-bit (little-endian) integer
 * @param invalue NULL, or points to a 32-bit (little-endian) integer
 * @param ack points to where the three bit JTAG_ACK_* code will be stored
 */
David Brownell's avatar
David Brownell committed
111
112
113
static int adi_jtag_dp_scan(struct swjdp_common *swjdp,
		uint8_t instr, uint8_t reg_addr, uint8_t RnW,
		uint8_t *outvalue, uint8_t *invalue, uint8_t *ack)
114
{
115
	struct arm_jtag *jtag_info = swjdp->jtag_info;
116
	struct scan_field fields[2];
117
	uint8_t out_addr_buf;
118

119
	jtag_set_end_state(TAP_IDLE);
120
121
	arm_jtag_set_instr(jtag_info, instr, NULL);

David Brownell's avatar
David Brownell committed
122
123
124
	/* Scan out a read or write operation using some DP or AP register.
	 * For APACC access with any sticky error flag set, this is discarded.
	 */
125
126
127
128
129
	fields[0].tap = jtag_info->tap;
	fields[0].num_bits = 3;
	buf_set_u32(&out_addr_buf, 0, 3, ((reg_addr >> 1) & 0x6) | (RnW & 0x1));
	fields[0].out_value = &out_addr_buf;
	fields[0].in_value = ack;
oharboe's avatar
oharboe committed
130

David Brownell's avatar
David Brownell committed
131
132
133
134
135
	/* NOTE: if we receive JTAG_ACK_WAIT, the previous operation did not
	 * complete; data we write is discarded, data we read is unpredictable.
	 * When overrun detect is active, STICKYORUN is set.
	 */

136
137
138
139
140
	fields[1].tap = jtag_info->tap;
	fields[1].num_bits = 32;
	fields[1].out_value = outvalue;
	fields[1].in_value = invalue;

141
	jtag_add_dr_scan(2, fields, jtag_get_end_state());
142

143
144
145
146
147
148
149
150
151
152
153
154
	/* Add specified number of tck clocks after starting memory bus
	 * access, giving the hardware time to complete the access.
	 * They provide more time for the (MEM) AP to complete the read ...
	 * See "Minimum Response Time" for JTAG-DP, in the ADIv5 spec.
	 */
	if ((instr == JTAG_DP_APACC)
			&& ((reg_addr == AP_REG_DRW)
				|| ((reg_addr & 0xF0) == AP_REG_BD0))
			&& (swjdp->memaccess_tck != 0))
		jtag_add_runtest(swjdp->memaccess_tck,
				jtag_set_end_state(TAP_IDLE));

155
	return jtag_get_error();
156
157
}

158
159
160
161
162
163
/**
 * Scan DPACC or APACC out and in from host ordered uint32_t buffers.
 * This is exactly like adi_jtag_dp_scan(), except that endianness
 * conversions are performed (so the types of invalue and outvalue
 * must be different).
 */
David Brownell's avatar
David Brownell committed
164
165
166
static int adi_jtag_dp_scan_u32(struct swjdp_common *swjdp,
		uint8_t instr, uint8_t reg_addr, uint8_t RnW,
		uint32_t outvalue, uint32_t *invalue, uint8_t *ack)
167
{
168
	uint8_t out_value_buf[4];
169
	int retval;
170

171
	buf_set_u32(out_value_buf, 0, 32, outvalue);
oharboe's avatar
oharboe committed
172

173
174
175
176
	retval = adi_jtag_dp_scan(swjdp, instr, reg_addr, RnW,
			out_value_buf, (uint8_t *)invalue, ack);
	if (retval != ERROR_OK)
		return retval;
177

178
179
180
	if (invalue)
		jtag_add_callback(arm_le_to_h_u32,
				(jtag_callback_data_t) invalue);
181

182
	return retval;
183
184
}

David Brownell's avatar
David Brownell committed
185
186
187
/**
 * Utility to write AP registers.
 */
188
static inline int adi_jtag_ap_write_check(struct swjdp_common *dap,
David Brownell's avatar
David Brownell committed
189
		uint8_t reg_addr, uint8_t *outvalue)
190
{
191
	return adi_jtag_dp_scan(dap, JTAG_DP_APACC, reg_addr, DPAP_WRITE,
David Brownell's avatar
David Brownell committed
192
			outvalue, NULL, NULL);
193
194
}

195
static int adi_jtag_scan_inout_check_u32(struct swjdp_common *swjdp,
David Brownell's avatar
David Brownell committed
196
197
		uint8_t instr, uint8_t reg_addr, uint8_t RnW,
		uint32_t outvalue, uint32_t *invalue)
198
{
199
200
	int retval;

201
	/* Issue the read or write */
202
203
204
205
	retval = adi_jtag_dp_scan_u32(swjdp, instr, reg_addr,
			RnW, outvalue, NULL, NULL);
	if (retval != ERROR_OK)
		return retval;
206

207
208
209
	/* For reads,  collect posted value; RDBUFF has no other effect.
	 * Assumes read gets acked with OK/FAULT, and CTRL_STAT says "OK".
	 */
zwelch's avatar
zwelch committed
210
	if ((RnW == DPAP_READ) && (invalue != NULL))
211
		retval = adi_jtag_dp_scan_u32(swjdp, JTAG_DP_DPACC,
212
				DP_RDBUFF, DPAP_READ, 0, invalue, &swjdp->ack);
213
	return retval;
214
215
}

216
static int jtagdp_transaction_endcheck(struct swjdp_common *swjdp)
217
218
{
	int retval;
219
	uint32_t ctrlstat;
220
221
222
223
224

	/* too expensive to call keep_alive() here */

#if 0
	/* Danger!!!! BROKEN!!!! */
225
	adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
226
			DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
227
228
229
230
231
232
	/* Danger!!!! BROKEN!!!! Why will jtag_execute_queue() fail here????
	R956 introduced the check on return value here and now Michael Schwingen reports
	that this code no longer works....

	https://lists.berlios.de/pipermail/openocd-development/2008-September/003107.html
	*/
zwelch's avatar
zwelch committed
233
	if ((retval = jtag_execute_queue()) != ERROR_OK)
234
235
236
237
238
239
	{
		LOG_ERROR("BUG: Why does this fail the first time????");
	}
	/* Why??? second time it works??? */
#endif

240
241
242
	/* Post CTRL/STAT read; discard any previous posted read value
	 * but collect its ACK status.
	 */
243
	adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
244
			DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
zwelch's avatar
zwelch committed
245
	if ((retval = jtag_execute_queue()) != ERROR_OK)
246
247
248
249
		return retval;

	swjdp->ack = swjdp->ack & 0x7;

250
251
	/* common code path avoids calling timeval_ms() */
	if (swjdp->ack != JTAG_ACK_OK_FAULT)
252
	{
zwelch's avatar
zwelch committed
253
		long long then = timeval_ms();
254
255

		while (swjdp->ack != JTAG_ACK_OK_FAULT)
256
		{
257
			if (swjdp->ack == JTAG_ACK_WAIT)
258
259
260
			{
				if ((timeval_ms()-then) > 1000)
				{
261
262
263
264
265
266
					/* NOTE:  this would be a good spot
					 * to use JTAG_DP_ABORT.
					 */
					LOG_WARNING("Timeout (1000ms) waiting "
						"for ACK=OK/FAULT "
						"in JTAG-DP transaction");
267
268
269
270
271
					return ERROR_JTAG_DEVICE_ERROR;
				}
			}
			else
			{
David Brownell's avatar
David Brownell committed
272
				LOG_WARNING("Invalid ACK %#x "
David Brownell's avatar
David Brownell committed
273
274
						"in JTAG-DP transaction",
						swjdp->ack);
275
276
277
				return ERROR_JTAG_DEVICE_ERROR;
			}

278
			adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
279
					DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
280
			if ((retval = dap_run(swjdp)) != ERROR_OK)
281
282
283
284
285
				return retval;
			swjdp->ack = swjdp->ack & 0x7;
		}
	}

286
287
	/* REVISIT also STICKYCMP, for pushed comparisons (nyet used) */

288
289
290
	/* Check for STICKYERR and STICKYORUN */
	if (ctrlstat & (SSTICKYORUN | SSTICKYERR))
	{
291
		LOG_DEBUG("jtag-dp: CTRL/STAT error, 0x%" PRIx32, ctrlstat);
292
293
294
295
296
		/* Check power to debug regions */
		if ((ctrlstat & 0xf0000000) != 0xf0000000)
			 ahbap_debugport_init(swjdp);
		else
		{
297
			uint32_t mem_ap_csw, mem_ap_tar;
298

299
300
301
302
			/* Maybe print information about last intended
			 * MEM-AP access; but not if autoincrementing.
			 * *Real* CSW and TAR values are always shown.
			 */
303
304
305
306
307
			if (swjdp->ap_tar_value != (uint32_t) -1)
				LOG_DEBUG("MEM-AP Cached values: "
					"ap_bank 0x%" PRIx32
					", ap_csw 0x%" PRIx32
					", ap_tar 0x%" PRIx32,
308
					swjdp->ap_bank_value,
309
310
311
					swjdp->ap_csw_value,
					swjdp->ap_tar_value);

312
			if (ctrlstat & SSTICKYORUN)
313
314
				LOG_ERROR("JTAG-DP OVERRUN - check clock, "
					"memaccess, or reduce jtag speed");
315
316

			if (ctrlstat & SSTICKYERR)
317
				LOG_ERROR("JTAG-DP STICKY ERROR");
318
319

			/* Clear Sticky Error Bits */
320
			adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
321
322
323
					DP_CTRL_STAT, DPAP_WRITE,
					swjdp->dp_ctrl_stat | SSTICKYORUN
						| SSTICKYERR, NULL);
324
			adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
325
					DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
326
			if ((retval = dap_run(swjdp)) != ERROR_OK)
327
328
				return retval;

329
			LOG_DEBUG("jtag-dp: CTRL/STAT 0x%" PRIx32, ctrlstat);
330

331
332
333
334
335
336
337
338
339
340
			retval = dap_queue_ap_read(swjdp,
					AP_REG_CSW, &mem_ap_csw);
			if (retval != ERROR_OK)
				return retval;

			retval = dap_queue_ap_read(swjdp,
					AP_REG_TAR, &mem_ap_tar);
			if (retval != ERROR_OK)
				return retval;

341
			if ((retval = dap_run(swjdp)) != ERROR_OK)
342
				return retval;
343
344
			LOG_ERROR("MEM_AP_CSW 0x%" PRIx32 ", MEM_AP_TAR 0x%"
					PRIx32, mem_ap_csw, mem_ap_tar);
345
346

		}
347
		if ((retval = dap_run(swjdp)) != ERROR_OK)
348
349
350
351
352
353
354
355
356
357
358
359
360
			return retval;
		return ERROR_JTAG_DEVICE_ERROR;
	}

	return ERROR_OK;
}

/***************************************************************************
 *                                                                         *
 * DP and MEM-AP  register access  through APACC and DPACC                 *
 *                                                                         *
***************************************************************************/

David Brownell's avatar
David Brownell committed
361
362
363
364
365
366
367
368
369
370
/**
 * Select one of the APs connected to the specified DAP.  The
 * selection is implicitly used with future AP transactions.
 * This is a NOP if the specified AP is already selected.
 *
 * @param swjdp The DAP
 * @param apsel Number of the AP to (implicitly) use with further
 *	transactions.  This normally identifies a MEM-AP.
 */
void dap_ap_select(struct swjdp_common *swjdp,uint8_t apsel)
371
{
372
	uint32_t select = (apsel << 24) & 0xFF000000;
373
374
375
376

	if (select != swjdp->apsel)
	{
		swjdp->apsel = select;
377
378
379
380
		/* Switching AP invalidates cached values.
		 * Values MUST BE UPDATED BEFORE AP ACCESS.
		 */
		swjdp->ap_bank_value = -1;
381
382
383
384
385
		swjdp->ap_csw_value = -1;
		swjdp->ap_tar_value = -1;
	}
}

386
/**
387
388
 * Queue transactions setting up transfer parameters for the
 * currently selected MEM-AP.
David Brownell's avatar
David Brownell committed
389
 *
390
391
392
393
394
395
396
397
398
399
400
401
 * Subsequent transfers using registers like AP_REG_DRW or AP_REG_BD2
 * initiate data reads or writes using memory or peripheral addresses.
 * If the CSW is configured for it, the TAR may be automatically
 * incremented after each transfer.
 *
 * @todo Rename to reflect it being specifically a MEM-AP function.
 *
 * @param swjdp The DAP connected to the MEM-AP.
 * @param csw MEM-AP Control/Status Word (CSW) register to assign.  If this
 *	matches the cached value, the register is not changed.
 * @param tar MEM-AP Transfer Address Register (TAR) to assign.  If this
 *	matches the cached address, the register is not changed.
David Brownell's avatar
David Brownell committed
402
 *
403
 * @return ERROR_OK if the transaction was properly queued, else a fault code.
404
 */
405
int dap_setup_accessport(struct swjdp_common *swjdp, uint32_t csw, uint32_t tar)
406
{
407
408
	int retval;

409
410
411
	csw = csw | CSW_DBGSWENABLE | CSW_MASTER_DEBUG | CSW_HPROT;
	if (csw != swjdp->ap_csw_value)
	{
412
		/* LOG_DEBUG("DAP: Set CSW %x",csw); */
413
		retval = dap_queue_ap_write(swjdp, AP_REG_CSW, csw);
414
415
		if (retval != ERROR_OK)
			return retval;
416
417
418
419
		swjdp->ap_csw_value = csw;
	}
	if (tar != swjdp->ap_tar_value)
	{
420
		/* LOG_DEBUG("DAP: Set TAR %x",tar); */
421
		retval = dap_queue_ap_write(swjdp, AP_REG_TAR, tar);
422
423
		if (retval != ERROR_OK)
			return retval;
424
425
		swjdp->ap_tar_value = tar;
	}
426
	/* Disable TAR cache when autoincrementing */
427
428
429
430
431
	if (csw & CSW_ADDRINC_MASK)
		swjdp->ap_tar_value = -1;
	return ERROR_OK;
}

David Brownell's avatar
David Brownell committed
432
433
434
435
436
437
438
439
440
441
442
443
444
/**
 * Asynchronous (queued) read of a word from memory or a system register.
 *
 * @param swjdp The DAP connected to the MEM-AP performing the read.
 * @param address Address of the 32-bit word to read; it must be
 *	readable by the currently selected MEM-AP.
 * @param value points to where the word will be stored when the
 *	transaction queue is flushed (assuming no errors).
 *
 * @return ERROR_OK for success.  Otherwise a fault code.
 */
int mem_ap_read_u32(struct swjdp_common *swjdp, uint32_t address,
		uint32_t *value)
445
{
446
447
	int retval;

David Brownell's avatar
David Brownell committed
448
449
450
	/* Use banked addressing (REG_BDx) to avoid some link traffic
	 * (updating TAR) when reading several consecutive addresses.
	 */
451
	retval = dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF,
David Brownell's avatar
David Brownell committed
452
			address & 0xFFFFFFF0);
453
454
	if (retval != ERROR_OK)
		return retval;
455

456
	return dap_queue_ap_read(swjdp, AP_REG_BD0 | (address & 0xC), value);
457
458
}

David Brownell's avatar
David Brownell committed
459
460
461
462
463
464
465
466
467
468
469
470
471
472
/**
 * Synchronous read of a word from memory or a system register.
 * As a side effect, this flushes any queued transactions.
 *
 * @param swjdp The DAP connected to the MEM-AP performing the read.
 * @param address Address of the 32-bit word to read; it must be
 *	readable by the currently selected MEM-AP.
 * @param value points to where the result will be stored.
 *
 * @return ERROR_OK for success; *value holds the result.
 * Otherwise a fault code.
 */
int mem_ap_read_atomic_u32(struct swjdp_common *swjdp, uint32_t address,
		uint32_t *value)
473
{
474
475
476
477
478
	int retval;

	retval = mem_ap_read_u32(swjdp, address, value);
	if (retval != ERROR_OK)
		return retval;
479

480
	return dap_run(swjdp);
481
482
}

David Brownell's avatar
David Brownell committed
483
484
485
486
487
488
489
490
491
492
493
494
495
/**
 * Asynchronous (queued) write of a word to memory or a system register.
 *
 * @param swjdp The DAP connected to the MEM-AP.
 * @param address Address to be written; it must be writable by
 *	the currently selected MEM-AP.
 * @param value Word that will be written to the address when transaction
 *	queue is flushed (assuming no errors).
 *
 * @return ERROR_OK for success.  Otherwise a fault code.
 */
int mem_ap_write_u32(struct swjdp_common *swjdp, uint32_t address,
		uint32_t value)
496
{
497
498
	int retval;

David Brownell's avatar
David Brownell committed
499
500
501
	/* Use banked addressing (REG_BDx) to avoid some link traffic
	 * (updating TAR) when writing several consecutive addresses.
	 */
502
	retval = dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF,
David Brownell's avatar
David Brownell committed
503
			address & 0xFFFFFFF0);
504
505
	if (retval != ERROR_OK)
		return retval;
506

507
	return dap_queue_ap_write(swjdp, AP_REG_BD0 | (address & 0xC),
508
			value);
509
510
}

David Brownell's avatar
David Brownell committed
511
512
513
514
515
516
517
518
519
520
521
522
523
/**
 * Synchronous write of a word to memory or a system register.
 * As a side effect, this flushes any queued transactions.
 *
 * @param swjdp The DAP connected to the MEM-AP.
 * @param address Address to be written; it must be writable by
 *	the currently selected MEM-AP.
 * @param value Word that will be written.
 *
 * @return ERROR_OK for success; the data was written.  Otherwise a fault code.
 */
int mem_ap_write_atomic_u32(struct swjdp_common *swjdp, uint32_t address,
		uint32_t value)
524
{
525
526
527
528
	int retval = mem_ap_write_u32(swjdp, address, value);

	if (retval != ERROR_OK)
		return retval;
529

530
	return dap_run(swjdp);
531
532
533
534
}

/*****************************************************************************
*                                                                            *
535
* mem_ap_write_buf(struct swjdp_common *swjdp, uint8_t *buffer, int count, uint32_t address) *
536
537
538
539
*                                                                            *
* Write a buffer in target order (little endian)                             *
*                                                                            *
*****************************************************************************/
540
int mem_ap_write_buf_u32(struct swjdp_common *swjdp, uint8_t *buffer, int count, uint32_t address)
541
542
{
	int wcount, blocksize, writecount, errorcount = 0, retval = ERROR_OK;
543
	uint32_t adr = address;
544
	uint8_t* pBuffer = buffer;
545
546
547
548
549
550
551
552
553
554

	count >>= 2;
	wcount = count;

	/* if we have an unaligned access - reorder data */
	if (adr & 0x3u)
	{
		for (writecount = 0; writecount < count; writecount++)
		{
			int i;
555
556
			uint32_t outvalue;
			memcpy(&outvalue, pBuffer, sizeof(uint32_t));
557

558
			for (i = 0; i < 4; i++)
559
			{
560
				*((uint8_t*)pBuffer + (adr & 0x3)) = outvalue;
561
562
563
				outvalue >>= 8;
				adr++;
			}
564
			pBuffer += sizeof(uint32_t);
565
566
567
568
569
		}
	}

	while (wcount > 0)
	{
570
571
		/* Adjust to write blocks within boundaries aligned to the TAR autoincremnent size*/
		blocksize = max_tar_block_size(swjdp->tar_autoincr_block, address);
572
573
574
575
576
577
578
579
580
581
582
		if (wcount < blocksize)
			blocksize = wcount;

		/* handle unaligned data at 4k boundary */
		if (blocksize == 0)
			blocksize = 1;

		dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE, address);

		for (writecount = 0; writecount < blocksize; writecount++)
		{
583
584
585
586
			retval = dap_queue_ap_write(swjdp, AP_REG_DRW,
				*(uint32_t *) (buffer + 4 * writecount));
			if (retval != ERROR_OK)
				break;
587
588
		}

589
		if (dap_run(swjdp) == ERROR_OK)
590
591
592
593
594
595
596
597
598
599
600
601
		{
			wcount = wcount - blocksize;
			address = address + 4 * blocksize;
			buffer = buffer + 4 * blocksize;
		}
		else
		{
			errorcount++;
		}

		if (errorcount > 1)
		{
duane's avatar
duane committed
602
			LOG_WARNING("Block write error address 0x%" PRIx32 ", wcount 0x%x", address, wcount);
603
			/* REVISIT return the *actual* fault code */
604
605
606
607
608
609
610
			return ERROR_JTAG_DEVICE_ERROR;
		}
	}

	return retval;
}

David Brownell's avatar
David Brownell committed
611
612
static int mem_ap_write_buf_packed_u16(struct swjdp_common *swjdp,
		uint8_t *buffer, int count, uint32_t address)
613
614
615
616
617
618
619
620
621
622
{
	int retval = ERROR_OK;
	int wcount, blocksize, writecount, i;

	wcount = count >> 1;

	while (wcount > 0)
	{
		int nbytes;

623
624
		/* Adjust to write blocks within boundaries aligned to the TAR autoincremnent size*/
		blocksize = max_tar_block_size(swjdp->tar_autoincr_block, address);
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639

		if (wcount < blocksize)
			blocksize = wcount;

		/* handle unaligned data at 4k boundary */
		if (blocksize == 0)
			blocksize = 1;

		dap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_PACKED, address);
		writecount = blocksize;

		do
		{
			nbytes = MIN((writecount << 1), 4);

640
			if (nbytes < 4)
641
			{
642
643
				if (mem_ap_write_buf_u16(swjdp, buffer,
						nbytes, address) != ERROR_OK)
644
				{
645
646
647
					LOG_WARNING("Block write error address "
						"0x%" PRIx32 ", count 0x%x",
						address, count);
648
649
650
651
652
653
654
					return ERROR_JTAG_DEVICE_ERROR;
				}

				address += nbytes >> 1;
			}
			else
			{
655
656
				uint32_t outvalue;
				memcpy(&outvalue, buffer, sizeof(uint32_t));
657

658
				for (i = 0; i < nbytes; i++)
659
				{
660
					*((uint8_t*)buffer + (address & 0x3)) = outvalue;
661
662
663
664
					outvalue >>= 8;
					address++;
				}

665
				memcpy(&outvalue, buffer, sizeof(uint32_t));
666
667
668
669
670
				retval = dap_queue_ap_write(swjdp,
						AP_REG_DRW, outvalue);
				if (retval != ERROR_OK)
					break;

671
				if (dap_run(swjdp) != ERROR_OK)
672
				{
673
674
675
					LOG_WARNING("Block write error address "
						"0x%" PRIx32 ", count 0x%x",
						address, count);
676
					/* REVISIT return *actual* fault code */
677
678
679
680
681
682
683
684
685
686
687
688
689
690
					return ERROR_JTAG_DEVICE_ERROR;
				}
			}

			buffer += nbytes >> 1;
			writecount -= nbytes >> 1;

		} while (writecount);
		wcount -= blocksize;
	}

	return retval;
}

691
int mem_ap_write_buf_u16(struct swjdp_common *swjdp, uint8_t *buffer, int count, uint32_t address)
692
693
694
695
696
697
698
699
700
{
	int retval = ERROR_OK;

	if (count >= 4)
		return mem_ap_write_buf_packed_u16(swjdp, buffer, count, address);

	while (count > 0)
	{
		dap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_SINGLE, address);
zwelch's avatar
zwelch committed
701
702
		uint16_t svalue;
		memcpy(&svalue, buffer, sizeof(uint16_t));
703
		uint32_t outvalue = (uint32_t)svalue << 8 * (address & 0x3);
704
705
706
707
		retval = dap_queue_ap_write(swjdp, AP_REG_DRW, outvalue);
		if (retval != ERROR_OK)
			break;

708
709
710
711
		retval = dap_run(swjdp);
		if (retval != ERROR_OK)
			break;

712
713
714
715
716
717
718
719
		count -= 2;
		address += 2;
		buffer += 2;
	}

	return retval;
}

David Brownell's avatar
David Brownell committed
720
721
static int mem_ap_write_buf_packed_u8(struct swjdp_common *swjdp,
		uint8_t *buffer, int count, uint32_t address)
722
723
724
725
726
727
728
729
730
731
{
	int retval = ERROR_OK;
	int wcount, blocksize, writecount, i;

	wcount = count;

	while (wcount > 0)
	{
		int nbytes;

732
733
		/* Adjust to write blocks within boundaries aligned to the TAR autoincremnent size*/
		blocksize = max_tar_block_size(swjdp->tar_autoincr_block, address);
734
735
736
737
738
739
740
741
742
743
744

		if (wcount < blocksize)
			blocksize = wcount;

		dap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_PACKED, address);
		writecount = blocksize;

		do
		{
			nbytes = MIN(writecount, 4);

745
			if (nbytes < 4)
746
747
748
			{
				if (mem_ap_write_buf_u8(swjdp, buffer, nbytes, address) != ERROR_OK)
				{
749
750
751
					LOG_WARNING("Block write error address "
						"0x%" PRIx32 ", count 0x%x",
						address, count);
752
753
754
755
756
757
758
					return ERROR_JTAG_DEVICE_ERROR;
				}

				address += nbytes;
			}
			else
			{
759
760
				uint32_t outvalue;
				memcpy(&outvalue, buffer, sizeof(uint32_t));
761

762
				for (i = 0; i < nbytes; i++)
763
				{
764
					*((uint8_t*)buffer + (address & 0x3)) = outvalue;
765
766
767
768
					outvalue >>= 8;
					address++;
				}

769
				memcpy(&outvalue, buffer, sizeof(uint32_t));
770
771
772
773
774
				retval = dap_queue_ap_write(swjdp,
						AP_REG_DRW, outvalue);
				if (retval != ERROR_OK)
					break;

775
				if (dap_run(swjdp) != ERROR_OK)
776
				{
777
778
779
					LOG_WARNING("Block write error address "
						"0x%" PRIx32 ", count 0x%x",
						address, count);
780
					/* REVISIT return *actual* fault code */
781
782
783
784
785
786
787
788
789
790
791
792
793
794
					return ERROR_JTAG_DEVICE_ERROR;
				}
			}

			buffer += nbytes;
			writecount -= nbytes;

		} while (writecount);
		wcount -= blocksize;
	}

	return retval;
}

795
int mem_ap_write_buf_u8(struct swjdp_common *swjdp, uint8_t *buffer, int count, uint32_t address)
796
797
798
799
800
801
802
803
804
{
	int retval = ERROR_OK;

	if (count >= 4)
		return mem_ap_write_buf_packed_u8(swjdp, buffer, count, address);

	while (count > 0)
	{
		dap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address);
805
		uint32_t outvalue = (uint32_t)*buffer << 8 * (address & 0x3);
806
807
808
809
		retval = dap_queue_ap_write(swjdp, AP_REG_DRW, outvalue);
		if (retval != ERROR_OK)
			break;

810
811
812
813
		retval = dap_run(swjdp);
		if (retval != ERROR_OK)
			break;

814
815
816
817
818
819
820
821
		count--;
		address++;
		buffer++;
	}

	return retval;
}

David Brownell's avatar
David Brownell committed
822
823
824
825
826
827
828
829
830
831
/**
 * Synchronously read a block of 32-bit words into a buffer
 * @param swjdp The DAP connected to the MEM-AP.
 * @param buffer where the words will be stored (in host byte order).
 * @param count How many words to read.
 * @param address Memory address from which to read words; all the
 *	words must be readable by the currently selected MEM-AP.
 */
int mem_ap_read_buf_u32(struct swjdp_common *swjdp, uint8_t *buffer,
		int count, uint32_t address)
832
833
{
	int wcount, blocksize, readcount, errorcount = 0, retval = ERROR_OK;
834
	uint32_t adr = address;
835
	uint8_t* pBuffer = buffer;
836
837
838
839
840
841

	count >>= 2;
	wcount = count;

	while (wcount > 0)
	{
David Brownell's avatar
David Brownell committed
842
843
844
845
846
847
		/* Adjust to read blocks within boundaries aligned to the
		 * TAR autoincrement size (at least 2^10).  Autoincrement
		 * mode avoids an extra per-word roundtrip to update TAR.
		 */
		blocksize = max_tar_block_size(swjdp->tar_autoincr_block,
				address);
848
849
850
851
852
853
854
		if (wcount < blocksize)
			blocksize = wcount;

		/* handle unaligned data at 4k boundary */
		if (blocksize == 0)
			blocksize = 1;

David Brownell's avatar
David Brownell committed
855
856
		dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE,
				address);
857

858
859
860
861
862
863
864
		/* FIXME remove these three calls to adi_jtag_dp_scan(),
		 * so this routine becomes transport-neutral.  Be careful
		 * not to cause performance problems with JTAG; would it
		 * suffice to loop over dap_queue_ap_read(), or would that
		 * be slower when JTAG is the chosen transport?
		 */

865
		/* Scan out first read */
866
867
		adi_jtag_dp_scan(swjdp, JTAG_DP_APACC, AP_REG_DRW,
				DPAP_READ, 0, NULL, NULL);
868
869
		for (readcount = 0; readcount < blocksize - 1; readcount++)
		{
870
871
872
873
			/* Scan out next read; scan in posted value for the
			 * previous one.  Assumes read is acked "OK/FAULT",
			 * and CTRL_STAT says that meant "OK".
			 */
874
875
876
			adi_jtag_dp_scan(swjdp, JTAG_DP_APACC, AP_REG_DRW,
					DPAP_READ, 0, buffer + 4 * readcount,
					&swjdp->ack);
877
878
		}

879
880
881
		/* Scan in last posted value; RDBUFF has no other effect,
		 * assuming ack is OK/FAULT and CTRL_STAT says "OK".
		 */
882
883
884
		adi_jtag_dp_scan(swjdp, JTAG_DP_DPACC, DP_RDBUFF,
				DPAP_READ, 0, buffer + 4 * readcount,
				&swjdp->ack);
885
		if (dap_run(swjdp) == ERROR_OK)
886
887
888
889
890
891
892
893
894
895
896
897
		{
			wcount = wcount - blocksize;
			address += 4 * blocksize;
			buffer += 4 * blocksize;
		}
		else
		{
			errorcount++;
		}

		if (errorcount > 1)
		{
David Brownell's avatar
David Brownell committed
898
899
			LOG_WARNING("Block read error address 0x%" PRIx32
				", count 0x%x", address, count);
900
			/* REVISIT return the *actual* fault code */
901
902
903
904
905
906
907
908
909
910
			return ERROR_JTAG_DEVICE_ERROR;
		}
	}

	/* if we have an unaligned access - reorder data */
	if (adr & 0x3u)
	{
		for (readcount = 0; readcount < count; readcount++)
		{
			int i;
911
912
			uint32_t data;
			memcpy(&data, pBuffer, sizeof(uint32_t));
913

914
			for (i = 0; i < 4; i++)
915
			{
David Brownell's avatar
David Brownell committed
916
917
				*((uint8_t*)pBuffer) =
						(data >> 8 * (adr & 0x3));
918
919
920
921
922
923
924
925
926
				pBuffer++;
				adr++;
			}
		}
	}

	return retval;
}

David Brownell's avatar
David Brownell committed
927
928
static int mem_ap_read_buf_packed_u16(struct swjdp_common *swjdp,
		uint8_t *buffer, int count, uint32_t address)
929
{
930
	uint32_t invalue;
931
932
933
934
935
936
937
938
939
	int retval = ERROR_OK;
	int wcount, blocksize, readcount, i;

	wcount = count >> 1;

	while (wcount > 0)
	{
		int nbytes;

940
941
		/* Adjust to read blocks within boundaries aligned to the TAR autoincremnent size*/
		blocksize = max_tar_block_size(swjdp->tar_autoincr_block, address);
942
943
944
945
946
947
948
949
950
951
952
953
		if (wcount < blocksize)
			blocksize = wcount;

		dap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_PACKED, address);

		/* handle unaligned data at 4k boundary */
		if (blocksize == 0)
			blocksize = 1;
		readcount = blocksize;

		do
		{
954
			retval = dap_queue_ap_read(swjdp, AP_REG_DRW, &invalue);
955
			if (dap_run(swjdp) != ERROR_OK)
956
			{
duane's avatar
duane committed
957
				LOG_WARNING("Block read error address 0x%" PRIx32 ", count 0x%x", address, count);
958
				/* REVISIT return the *actual* fault code */
959
960
961
962
963
				return ERROR_JTAG_DEVICE_ERROR;
			}

			nbytes = MIN((readcount << 1), 4);

964
			for (i = 0; i < nbytes; i++)
965
			{
966
				*((uint8_t*)buffer) = (invalue >> 8 * (address & 0x3));
967
968
969
970
971
972
973
974
975
976
977
978
				buffer++;
				address++;
			}

			readcount -= (nbytes >> 1);
		} while (readcount);
		wcount -= blocksize;
	}

	return retval;
}

David Brownell's avatar
David Brownell committed
979
980
981
982
983
984
985
986
987
988
/**
 * Synchronously read a block of 16-bit halfwords into a buffer
 * @param swjdp The DAP connected to the MEM-AP.
 * @param buffer where the halfwords will be stored (in host byte order).
 * @param count How many halfwords to read.
 * @param address Memory address from which to read words; all the
 *	words must be readable by the currently selected MEM-AP.
 */
int mem_ap_read_buf_u16(struct swjdp_common *swjdp, uint8_t *buffer,
		int count, uint32_t address)
989
{
990
	uint32_t invalue, i;
991
992
993
994
995
996
997
998
	int retval = ERROR_OK;

	if (count >= 4)
		return mem_ap_read_buf_packed_u16(swjdp, buffer, count, address);

	while (count > 0)
	{
		dap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_SINGLE, address);
999
1000
		retval = dap_queue_ap_read(swjdp, AP_REG_DRW, &invalue);
		if (retval != ERROR_OK)
For faster browsing, not all history is shown. View entire blame