xscale.c 102 KB
Newer Older
1 2 3 4
/***************************************************************************
 *   Copyright (C) 2006, 2007 by Dominic Rath                              *
 *   Dominic.Rath@gmx.de                                                   *
 *                                                                         *
5
 *   Copyright (C) 2007,2008 Øyvind Harboe                                 *
6 7
 *   oyvind.harboe@zylin.com                                               *
 *                                                                         *
8 9 10
 *   Copyright (C) 2009 Michael Schwingen                                  *
 *   michael@schwingen.org                                                 *
 *                                                                         *
11 12 13 14 15 16 17 18 19 20 21
 *   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     *
22
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
23
 ***************************************************************************/
24

25 26 27 28
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

29
#include "breakpoints.h"
30
#include "xscale.h"
31
#include "target_type.h"
32
#include "arm_jtag.h"
33 34
#include "arm_simulator.h"
#include "arm_disassembler.h"
35
#include <helper/time_support.h>
36
#include "register.h"
37
#include "image.h"
38
#include "arm_opcodes.h"
39
#include "armv4_5.h"
40

David Brownell's avatar
David Brownell committed
41 42 43 44 45 46
/*
 * Important XScale documents available as of October 2009 include:
 *
 *  Intel XScale® Core Developer’s Manual, January 2004
 *		Order Number: 273473-002
 *	This has a chapter detailing debug facilities, and punts some
47
 *	details to chip-specific microarchitecture documents.
David Brownell's avatar
David Brownell committed
48 49 50 51 52 53 54 55 56 57 58 59
 *
 *  Hot-Debug for Intel XScale® Core Debug White Paper, May 2005
 *		Document Number: 273539-005
 *	Less detailed than the developer's manual, but summarizes those
 *	missing details (for most XScales) and gives LOTS of notes about
 *	debugger/handler interaction issues.  Presents a simpler reset
 *	and load-handler sequence than the arch doc.  (Note, OpenOCD
 *	doesn't currently support "Hot-Debug" as defined there.)
 *
 * Chip-specific microarchitecture documents may also be useful.
 */

60
/* forward declarations */
Zachary T Welch's avatar
Zachary T Welch committed
61
static int xscale_resume(struct target *, int current,
62
	target_addr_t address, int handle_breakpoints, int debug_execution);
Zachary T Welch's avatar
Zachary T Welch committed
63
static int xscale_debug_entry(struct target *);
64
static int xscale_restore_banked(struct target *);
Zachary T Welch's avatar
Zachary T Welch committed
65 66
static int xscale_get_reg(struct reg *reg);
static int xscale_set_reg(struct reg *reg, uint8_t *buf);
Zachary T Welch's avatar
Zachary T Welch committed
67 68 69 70
static int xscale_set_breakpoint(struct target *, struct breakpoint *);
static int xscale_set_watchpoint(struct target *, struct watchpoint *);
static int xscale_unset_breakpoint(struct target *, struct breakpoint *);
static int xscale_read_trace(struct target *);
71

72 73 74
/* This XScale "debug handler" is loaded into the processor's
 * mini-ICache, which is 2K of code writable only via JTAG.
 */
75
static const uint8_t xscale_debug_handler[] = {
76
#include "../../contrib/loaders/debug/xscale/debug_handler.inc"
77
};
78

Spencer Oliver's avatar
Spencer Oliver committed
79
static const char *const xscale_reg_list[] = {
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
	"XSCALE_MAINID",		/* 0 */
	"XSCALE_CACHETYPE",
	"XSCALE_CTRL",
	"XSCALE_AUXCTRL",
	"XSCALE_TTB",
	"XSCALE_DAC",
	"XSCALE_FSR",
	"XSCALE_FAR",
	"XSCALE_PID",
	"XSCALE_CPACCESS",
	"XSCALE_IBCR0",			/* 10 */
	"XSCALE_IBCR1",
	"XSCALE_DBR0",
	"XSCALE_DBR1",
	"XSCALE_DBCON",
	"XSCALE_TBREG",
	"XSCALE_CHKPT0",
	"XSCALE_CHKPT1",
	"XSCALE_DCSR",
	"XSCALE_TX",
	"XSCALE_RX",			/* 20 */
	"XSCALE_TXRXCTRL",
};

104
static const struct xscale_reg xscale_reg_arch_info[] = {
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
	{XSCALE_MAINID, NULL},
	{XSCALE_CACHETYPE, NULL},
	{XSCALE_CTRL, NULL},
	{XSCALE_AUXCTRL, NULL},
	{XSCALE_TTB, NULL},
	{XSCALE_DAC, NULL},
	{XSCALE_FSR, NULL},
	{XSCALE_FAR, NULL},
	{XSCALE_PID, NULL},
	{XSCALE_CPACCESS, NULL},
	{XSCALE_IBCR0, NULL},
	{XSCALE_IBCR1, NULL},
	{XSCALE_DBR0, NULL},
	{XSCALE_DBR1, NULL},
	{XSCALE_DBCON, NULL},
	{XSCALE_TBREG, NULL},
	{XSCALE_CHKPT0, NULL},
	{XSCALE_CHKPT1, NULL},
123 124 125 126
	{XSCALE_DCSR, NULL},	/* DCSR accessed via JTAG or SW */
	{-1, NULL},	/* TX accessed via JTAG */
	{-1, NULL},	/* RX accessed via JTAG */
	{-1, NULL},	/* TXRXCTRL implicit access via JTAG */
127 128
};

David Brownell's avatar
David Brownell committed
129
/* convenience wrapper to access XScale specific registers */
Zachary T Welch's avatar
Zachary T Welch committed
130
static int xscale_set_reg_u32(struct reg *reg, uint32_t value)
David Brownell's avatar
David Brownell committed
131 132 133 134
{
	uint8_t buf[4];

	buf_set_u32(buf, 0, 32, value);
135

David Brownell's avatar
David Brownell committed
136 137 138
	return xscale_set_reg(reg, buf);
}

139
static const char xscale_not[] = "target is not an XScale";
David Brownell's avatar
David Brownell committed
140

141
static int xscale_verify_pointer(struct command_context *cmd_ctx,
142
	struct xscale_common *xscale)
143
{
144 145 146
	if (xscale->common_magic != XSCALE_COMMON_MAGIC) {
		command_print(cmd_ctx, xscale_not);
		return ERROR_TARGET_INVALID;
147 148 149 150
	}
	return ERROR_OK;
}

151
static int xscale_jtag_set_instr(struct jtag_tap *tap, uint32_t new_instr, tap_state_t end_state)
152
{
153
	assert(tap != NULL);
154

155
	if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr) {
156
		struct scan_field field;
157
		uint8_t scratch[4];
158

159
		memset(&field, 0, sizeof field);
160
		field.num_bits = tap->ir_length;
161
		field.out_value = scratch;
162
		buf_set_u32(scratch, 0, field.num_bits, new_instr);
oharboe's avatar
oharboe committed
163

164
		jtag_add_ir_scan(tap, &field, end_state);
165 166 167 168 169
	}

	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
170
static int xscale_read_dcsr(struct target *target)
171
{
172
	struct xscale_common *xscale = target_to_xscale(target);
173
	int retval;
174
	struct scan_field fields[3];
175 176 177 178 179 180
	uint8_t field0 = 0x0;
	uint8_t field0_check_value = 0x2;
	uint8_t field0_check_mask = 0x7;
	uint8_t field2 = 0x0;
	uint8_t field2_check_value = 0x0;
	uint8_t field2_check_mask = 0x1;
181

Marek Vasut's avatar
Marek Vasut committed
182
	xscale_jtag_set_instr(target->tap,
183 184
		XSCALE_SELDCSR << xscale->xscale_variant,
		TAP_DRPAUSE);
185 186 187 188

	buf_set_u32(&field0, 1, 1, xscale->hold_rst);
	buf_set_u32(&field0, 2, 1, xscale->external_debug_break);

189 190
	memset(&fields, 0, sizeof fields);

191 192
	fields[0].num_bits = 3;
	fields[0].out_value = &field0;
193
	uint8_t tmp;
oharboe's avatar
oharboe committed
194
	fields[0].in_value = &tmp;
195 196 197

	fields[1].num_bits = 32;
	fields[1].in_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value;
198

199 200
	fields[2].num_bits = 1;
	fields[2].out_value = &field2;
201
	uint8_t tmp2;
oharboe's avatar
oharboe committed
202
	fields[2].in_value = &tmp2;
203

204
	jtag_add_dr_scan(target->tap, 3, fields, TAP_DRPAUSE);
205

zwelch's avatar
zwelch committed
206 207
	jtag_check_value_mask(fields + 0, &field0_check_value, &field0_check_mask);
	jtag_check_value_mask(fields + 2, &field2_check_value, &field2_check_mask);
oharboe's avatar
oharboe committed
208

209 210
	retval = jtag_execute_queue();
	if (retval != ERROR_OK) {
211
		LOG_ERROR("JTAG error while reading DCSR");
212 213 214
		return retval;
	}

215 216
	xscale->reg_cache->reg_list[XSCALE_DCSR].dirty = false;
	xscale->reg_cache->reg_list[XSCALE_DCSR].valid = true;
217 218 219 220 221 222 223 224

	/* write the register with the value we just read
	 * on this second pass, only the first bit of field0 is guaranteed to be 0)
	 */
	field0_check_mask = 0x1;
	fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value;
	fields[1].in_value = NULL;

225
	jtag_add_dr_scan(target->tap, 3, fields, TAP_DRPAUSE);
226

227 228 229
	/* DANGER!!! this must be here. It will make sure that the arguments
	 * to jtag_set_check_value() does not go out of scope! */
	return jtag_execute_queue();
230 231
}

232

233
static void xscale_getbuf(jtag_callback_data_t arg)
234
{
David Brownell's avatar
David Brownell committed
235
	uint8_t *in = (uint8_t *)arg;
236
	*((uint32_t *)arg) = buf_get_u32(in, 0, 32);
237 238
}

Zachary T Welch's avatar
Zachary T Welch committed
239
static int xscale_receive(struct target *target, uint32_t *buffer, int num_words)
240
{
zwelch's avatar
zwelch committed
241
	if (num_words == 0)
242
		return ERROR_COMMAND_SYNTAX_ERROR;
243

Marek Vasut's avatar
Marek Vasut committed
244
	struct xscale_common *xscale = target_to_xscale(target);
zwelch's avatar
zwelch committed
245
	int retval = ERROR_OK;
246
	tap_state_t path[3];
247
	struct scan_field fields[3];
248 249 250
	uint8_t *field0 = malloc(num_words * 1);
	uint8_t field0_check_value = 0x2;
	uint8_t field0_check_mask = 0x6;
251
	uint32_t *field1 = malloc(num_words * 4);
252 253
	uint8_t field2_check_value = 0x0;
	uint8_t field2_check_mask = 0x1;
254 255 256 257
	int words_done = 0;
	int words_scheduled = 0;
	int i;

258 259 260
	path[0] = TAP_DRSELECT;
	path[1] = TAP_DRCAPTURE;
	path[2] = TAP_DRSHIFT;
261

262 263
	memset(&fields, 0, sizeof fields);

264
	fields[0].num_bits = 3;
265 266
	uint8_t tmp;
	fields[0].in_value = &tmp;
oharboe's avatar
oharboe committed
267 268
	fields[0].check_value = &field0_check_value;
	fields[0].check_mask = &field0_check_mask;
269 270 271 272

	fields[1].num_bits = 32;

	fields[2].num_bits = 1;
273 274
	uint8_t tmp2;
	fields[2].in_value = &tmp2;
oharboe's avatar
oharboe committed
275 276
	fields[2].check_value = &field2_check_value;
	fields[2].check_mask = &field2_check_mask;
277

Marek Vasut's avatar
Marek Vasut committed
278
	xscale_jtag_set_instr(target->tap,
279 280
		XSCALE_DBGTX << xscale->xscale_variant,
		TAP_IDLE);
281 282
	jtag_add_runtest(1, TAP_IDLE);	/* ensures that we're in the TAP_IDLE state as the above
					 *could be a no-op */
283 284

	/* repeat until all words have been collected */
zwelch's avatar
zwelch committed
285
	int attempts = 0;
286
	while (words_done < num_words) {
287 288
		/* schedule reads */
		words_scheduled = 0;
289
		for (i = words_done; i < num_words; i++) {
290 291 292
			fields[0].in_value = &field0[i];

			jtag_add_pathmove(3, path);
293

zwelch's avatar
zwelch committed
294
			fields[1].in_value = (uint8_t *)(field1 + i);
295

296
			jtag_add_dr_scan_check(target->tap, 3, fields, TAP_IDLE);
oharboe's avatar
oharboe committed
297

zwelch's avatar
zwelch committed
298
			jtag_add_callback(xscale_getbuf, (jtag_callback_data_t)(field1 + i));
oharboe's avatar
oharboe committed
299

300 301 302
			words_scheduled++;
		}

303 304
		retval = jtag_execute_queue();
		if (retval != ERROR_OK) {
305
			LOG_ERROR("JTAG error while receiving data from debug handler");
306 307 308 309
			break;
		}

		/* examine results */
310 311
		for (i = words_done; i < num_words; i++) {
			if (!(field0[i] & 1)) {
312 313
				/* move backwards if necessary */
				int j;
314
				for (j = i; j < num_words - 1; j++) {
zwelch's avatar
zwelch committed
315 316
					field0[j] = field0[j + 1];
					field1[j] = field1[j + 1];
317 318 319 320
				}
				words_scheduled--;
			}
		}
321 322 323 324
		if (words_scheduled == 0) {
			if (attempts++ == 1000) {
				LOG_ERROR(
					"Failed to receiving data from debug handler after 1000 attempts");
zwelch's avatar
zwelch committed
325
				retval = ERROR_TARGET_TIMEOUT;
326 327 328
				break;
			}
		}
329

330 331 332 333
		words_done += words_scheduled;
	}

	for (i = 0; i < num_words; i++)
334
		*(buffer++) = buf_get_u32((uint8_t *)&field1[i], 0, 32);
335 336 337 338 339 340

	free(field1);

	return retval;
}

Zachary T Welch's avatar
Zachary T Welch committed
341
static int xscale_read_tx(struct target *target, int consume)
342
{
343
	struct xscale_common *xscale = target_to_xscale(target);
344 345
	tap_state_t path[3];
	tap_state_t noconsume_path[6];
346 347
	int retval;
	struct timeval timeout, now;
348
	struct scan_field fields[3];
349 350 351 352 353
	uint8_t field0_in = 0x0;
	uint8_t field0_check_value = 0x2;
	uint8_t field0_check_mask = 0x6;
	uint8_t field2_check_value = 0x0;
	uint8_t field2_check_mask = 0x1;
354

Marek Vasut's avatar
Marek Vasut committed
355
	xscale_jtag_set_instr(target->tap,
356 357
		XSCALE_DBGTX << xscale->xscale_variant,
		TAP_IDLE);
358

359 360 361
	path[0] = TAP_DRSELECT;
	path[1] = TAP_DRCAPTURE;
	path[2] = TAP_DRSHIFT;
362

363 364 365 366 367 368
	noconsume_path[0] = TAP_DRSELECT;
	noconsume_path[1] = TAP_DRCAPTURE;
	noconsume_path[2] = TAP_DREXIT1;
	noconsume_path[3] = TAP_DRPAUSE;
	noconsume_path[4] = TAP_DREXIT2;
	noconsume_path[5] = TAP_DRSHIFT;
369

370 371
	memset(&fields, 0, sizeof fields);

372 373 374 375 376
	fields[0].num_bits = 3;
	fields[0].in_value = &field0_in;

	fields[1].num_bits = 32;
	fields[1].in_value = xscale->reg_cache->reg_list[XSCALE_TX].value;
377

378
	fields[2].num_bits = 1;
379
	uint8_t tmp;
oharboe's avatar
oharboe committed
380
	fields[2].in_value = &tmp;
381 382

	gettimeofday(&timeout, NULL);
oharboe's avatar
oharboe committed
383
	timeval_add_time(&timeout, 1, 0);
384

385
	for (;; ) {
386 387 388 389 390 391 392
		/* if we want to consume the register content (i.e. clear TX_READY),
		 * we have to go straight from Capture-DR to Shift-DR
		 * otherwise, we go from Capture-DR to Exit1-DR to Pause-DR
		*/
		if (consume)
			jtag_add_pathmove(3, path);
		else
Zachary T Welch's avatar
Zachary T Welch committed
393
			jtag_add_pathmove(ARRAY_SIZE(noconsume_path), noconsume_path);
394

395
		jtag_add_dr_scan(target->tap, 3, fields, TAP_IDLE);
396

zwelch's avatar
zwelch committed
397 398
		jtag_check_value_mask(fields + 0, &field0_check_value, &field0_check_mask);
		jtag_check_value_mask(fields + 2, &field2_check_value, &field2_check_mask);
oharboe's avatar
oharboe committed
399

400 401
		retval = jtag_execute_queue();
		if (retval != ERROR_OK) {
402 403 404 405 406
			LOG_ERROR("JTAG error while reading TX");
			return ERROR_TARGET_TIMEOUT;
		}

		gettimeofday(&now, NULL);
Christopher Head's avatar
Christopher Head committed
407
		if (timeval_compare(&now, &timeout) > 0) {
408 409 410 411 412
			LOG_ERROR("time out reading TX register");
			return ERROR_TARGET_TIMEOUT;
		}
		if (!((!(field0_in & 1)) && consume))
			goto done;
413
		if (debug_level >= 3) {
414
			LOG_DEBUG("waiting 100ms");
415
			alive_sleep(100);	/* avoid flooding the logs */
416 417
		} else
			keep_alive();
418
	}
419
done:
420 421 422 423 424 425 426

	if (!(field0_in & 1))
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;

	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
427
static int xscale_write_rx(struct target *target)
428
{
429
	struct xscale_common *xscale = target_to_xscale(target);
430 431
	int retval;
	struct timeval timeout, now;
432
	struct scan_field fields[3];
433 434 435 436 437 438 439
	uint8_t field0_out = 0x0;
	uint8_t field0_in = 0x0;
	uint8_t field0_check_value = 0x2;
	uint8_t field0_check_mask = 0x6;
	uint8_t field2 = 0x0;
	uint8_t field2_check_value = 0x0;
	uint8_t field2_check_mask = 0x1;
440

Marek Vasut's avatar
Marek Vasut committed
441
	xscale_jtag_set_instr(target->tap,
442 443
		XSCALE_DBGRX << xscale->xscale_variant,
		TAP_IDLE);
444

445 446
	memset(&fields, 0, sizeof fields);

447 448 449 450 451 452
	fields[0].num_bits = 3;
	fields[0].out_value = &field0_out;
	fields[0].in_value = &field0_in;

	fields[1].num_bits = 32;
	fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_RX].value;
453

454 455
	fields[2].num_bits = 1;
	fields[2].out_value = &field2;
456
	uint8_t tmp;
oharboe's avatar
oharboe committed
457
	fields[2].in_value = &tmp;
458 459

	gettimeofday(&timeout, NULL);
oharboe's avatar
oharboe committed
460
	timeval_add_time(&timeout, 1, 0);
461 462

	/* poll until rx_read is low */
463
	LOG_DEBUG("polling RX");
464
	for (;;) {
465
		jtag_add_dr_scan(target->tap, 3, fields, TAP_IDLE);
466

zwelch's avatar
zwelch committed
467 468
		jtag_check_value_mask(fields + 0, &field0_check_value, &field0_check_mask);
		jtag_check_value_mask(fields + 2, &field2_check_value, &field2_check_mask);
oharboe's avatar
oharboe committed
469

470 471
		retval = jtag_execute_queue();
		if (retval != ERROR_OK) {
472 473 474 475 476
			LOG_ERROR("JTAG error while writing RX");
			return retval;
		}

		gettimeofday(&now, NULL);
477 478
		if ((now.tv_sec > timeout.tv_sec) ||
			((now.tv_sec == timeout.tv_sec) && (now.tv_usec > timeout.tv_usec))) {
479 480 481 482 483
			LOG_ERROR("time out writing RX register");
			return ERROR_TARGET_TIMEOUT;
		}
		if (!(field0_in & 1))
			goto done;
484
		if (debug_level >= 3) {
485
			LOG_DEBUG("waiting 100ms");
486
			alive_sleep(100);	/* avoid flooding the logs */
487 488
		} else
			keep_alive();
489
	}
490
done:
491

492 493
	/* set rx_valid */
	field2 = 0x1;
494
	jtag_add_dr_scan(target->tap, 3, fields, TAP_IDLE);
495

496 497
	retval = jtag_execute_queue();
	if (retval != ERROR_OK) {
498
		LOG_ERROR("JTAG error while writing RX");
499 500 501 502 503 504 505
		return retval;
	}

	return ERROR_OK;
}

/* send count elements of size byte to the debug handler */
506
static int xscale_send(struct target *target, const uint8_t *buffer, int count, int size)
507
{
Marek Vasut's avatar
Marek Vasut committed
508
	struct xscale_common *xscale = target_to_xscale(target);
509 510
	int retval;
	int done_count = 0;
511

Marek Vasut's avatar
Marek Vasut committed
512
	xscale_jtag_set_instr(target->tap,
513 514
		XSCALE_DBGRX << xscale->xscale_variant,
		TAP_IDLE);
515

Andreas Fritiofson's avatar
Andreas Fritiofson committed
516 517 518 519 520 521 522 523 524
	static const uint8_t t0;
	uint8_t t1[4];
	static const uint8_t t2 = 1;
	struct scan_field fields[3] = {
			{ .num_bits = 3, .out_value = &t0 },
			{ .num_bits = 32, .out_value = t1 },
			{ .num_bits = 1, .out_value = &t2 },
	};

525
	int endianness = target->endianness;
526
	while (done_count++ < count) {
Andreas Fritiofson's avatar
Andreas Fritiofson committed
527 528
		uint32_t t;

529 530 531
		switch (size) {
			case 4:
				if (endianness == TARGET_LITTLE_ENDIAN)
Andreas Fritiofson's avatar
Andreas Fritiofson committed
532
					t = le_to_h_u32(buffer);
533
				else
Andreas Fritiofson's avatar
Andreas Fritiofson committed
534
					t = be_to_h_u32(buffer);
535 536 537
				break;
			case 2:
				if (endianness == TARGET_LITTLE_ENDIAN)
Andreas Fritiofson's avatar
Andreas Fritiofson committed
538
					t = le_to_h_u16(buffer);
539
				else
Andreas Fritiofson's avatar
Andreas Fritiofson committed
540
					t = be_to_h_u16(buffer);
541 542
				break;
			case 1:
Andreas Fritiofson's avatar
Andreas Fritiofson committed
543
				t = buffer[0];
544 545 546 547
				break;
			default:
				LOG_ERROR("BUG: size neither 4, 2 nor 1");
				return ERROR_COMMAND_SYNTAX_ERROR;
548
		}
Andreas Fritiofson's avatar
Andreas Fritiofson committed
549 550 551 552

		buf_set_u32(t1, 0, 32, t);

		jtag_add_dr_scan(target->tap,
553
			3,
Andreas Fritiofson's avatar
Andreas Fritiofson committed
554
			fields,
555
			TAP_IDLE);
556
		buffer += size;
557 558
	}

559 560
	retval = jtag_execute_queue();
	if (retval != ERROR_OK) {
561
		LOG_ERROR("JTAG error while sending data to debug handler");
562 563 564 565 566 567
		return retval;
	}

	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
568
static int xscale_send_u32(struct target *target, uint32_t value)
569
{
570
	struct xscale_common *xscale = target_to_xscale(target);
571 572 573 574 575

	buf_set_u32(xscale->reg_cache->reg_list[XSCALE_RX].value, 0, 32, value);
	return xscale_write_rx(target);
}

Zachary T Welch's avatar
Zachary T Welch committed
576
static int xscale_write_dcsr(struct target *target, int hold_rst, int ext_dbg_brk)
577
{
578
	struct xscale_common *xscale = target_to_xscale(target);
579
	int retval;
580
	struct scan_field fields[3];
581 582 583 584 585 586
	uint8_t field0 = 0x0;
	uint8_t field0_check_value = 0x2;
	uint8_t field0_check_mask = 0x7;
	uint8_t field2 = 0x0;
	uint8_t field2_check_value = 0x0;
	uint8_t field2_check_mask = 0x1;
587 588 589 590 591 592 593

	if (hold_rst != -1)
		xscale->hold_rst = hold_rst;

	if (ext_dbg_brk != -1)
		xscale->external_debug_break = ext_dbg_brk;

Marek Vasut's avatar
Marek Vasut committed
594
	xscale_jtag_set_instr(target->tap,
595 596
		XSCALE_SELDCSR << xscale->xscale_variant,
		TAP_IDLE);
597 598 599 600

	buf_set_u32(&field0, 1, 1, xscale->hold_rst);
	buf_set_u32(&field0, 2, 1, xscale->external_debug_break);

601 602
	memset(&fields, 0, sizeof fields);

603 604
	fields[0].num_bits = 3;
	fields[0].out_value = &field0;
605
	uint8_t tmp;
oharboe's avatar
oharboe committed
606
	fields[0].in_value = &tmp;
607 608 609

	fields[1].num_bits = 32;
	fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value;
610

611 612
	fields[2].num_bits = 1;
	fields[2].out_value = &field2;
613
	uint8_t tmp2;
oharboe's avatar
oharboe committed
614
	fields[2].in_value = &tmp2;
615

616
	jtag_add_dr_scan(target->tap, 3, fields, TAP_IDLE);
617

zwelch's avatar
zwelch committed
618 619
	jtag_check_value_mask(fields + 0, &field0_check_value, &field0_check_mask);
	jtag_check_value_mask(fields + 2, &field2_check_value, &field2_check_mask);
oharboe's avatar
oharboe committed
620

621 622
	retval = jtag_execute_queue();
	if (retval != ERROR_OK) {
623
		LOG_ERROR("JTAG error while writing DCSR");
624 625 626
		return retval;
	}

627 628
	xscale->reg_cache->reg_list[XSCALE_DCSR].dirty = false;
	xscale->reg_cache->reg_list[XSCALE_DCSR].valid = true;
629 630 631 632 633

	return ERROR_OK;
}

/* parity of the number of bits 0 if even; 1 if odd. for 32 bit words */
634
static unsigned int parity(unsigned int v)
635
{
636
	/* unsigned int ov = v; */
637 638 639 640
	v ^= v >> 16;
	v ^= v >> 8;
	v ^= v >> 4;
	v &= 0xf;
641
	/* LOG_DEBUG("parity of 0x%x is %i", ov, (0x6996 >> v) & 1); */
642 643 644
	return (0x6996 >> v) & 1;
}

Zachary T Welch's avatar
Zachary T Welch committed
645
static int xscale_load_ic(struct target *target, uint32_t va, uint32_t buffer[8])
646
{
Marek Vasut's avatar
Marek Vasut committed
647
	struct xscale_common *xscale = target_to_xscale(target);
648 649
	uint8_t packet[4];
	uint8_t cmd;
650
	int word;
651
	struct scan_field fields[2];
652

duane's avatar
duane committed
653
	LOG_DEBUG("loading miniIC at 0x%8.8" PRIx32 "", va);
654

David Brownell's avatar
David Brownell committed
655
	/* LDIC into IR */
Marek Vasut's avatar
Marek Vasut committed
656
	xscale_jtag_set_instr(target->tap,
657 658
		XSCALE_LDIC << xscale->xscale_variant,
		TAP_IDLE);
659

David Brownell's avatar
David Brownell committed
660 661 662 663 664
	/* CMD is b011 to load a cacheline into the Mini ICache.
	 * Loading into the main ICache is deprecated, and unused.
	 * It's followed by three zero bits, and 27 address bits.
	 */
	buf_set_u32(&cmd, 0, 6, 0x3);
665 666 667 668

	/* virtual address of desired cache line */
	buf_set_u32(packet, 0, 27, va >> 5);

669 670
	memset(&fields, 0, sizeof fields);

671 672
	fields[0].num_bits = 6;
	fields[0].out_value = &cmd;
oharboe's avatar
oharboe committed
673

674 675
	fields[1].num_bits = 27;
	fields[1].out_value = packet;
oharboe's avatar
oharboe committed
676

677
	jtag_add_dr_scan(target->tap, 2, fields, TAP_IDLE);
678

David Brownell's avatar
David Brownell committed
679
	/* rest of packet is a cacheline: 8 instructions, with parity */
680 681 682 683 684 685
	fields[0].num_bits = 32;
	fields[0].out_value = packet;

	fields[1].num_bits = 1;
	fields[1].out_value = &cmd;

686
	for (word = 0; word < 8; word++) {
687
		buf_set_u32(packet, 0, 32, buffer[word]);
688

689 690
		uint32_t value;
		memcpy(&value, packet, sizeof(uint32_t));
691 692
		cmd = parity(value);

693
		jtag_add_dr_scan(target->tap, 2, fields, TAP_IDLE);
694 695
	}

David Brownell's avatar
David Brownell committed
696
	return jtag_execute_queue();
697 698
}

Zachary T Welch's avatar
Zachary T Welch committed
699
static int xscale_invalidate_ic_line(struct target *target, uint32_t va)
700
{
Marek Vasut's avatar
Marek Vasut committed
701
	struct xscale_common *xscale = target_to_xscale(target);
702 703
	uint8_t packet[4];
	uint8_t cmd;
704
	struct scan_field fields[2];
705

Marek Vasut's avatar
Marek Vasut committed
706
	xscale_jtag_set_instr(target->tap,
707 708
		XSCALE_LDIC << xscale->xscale_variant,
		TAP_IDLE);
709 710 711 712 713 714 715

	/* CMD for invalidate IC line b000, bits [6:4] b000 */
	buf_set_u32(&cmd, 0, 6, 0x0);

	/* virtual address of desired cache line */
	buf_set_u32(packet, 0, 27, va >> 5);

716 717
	memset(&fields, 0, sizeof fields);

718 719
	fields[0].num_bits = 6;
	fields[0].out_value = &cmd;
oharboe's avatar
oharboe committed
720

721 722
	fields[1].num_bits = 27;
	fields[1].out_value = packet;
oharboe's avatar
oharboe committed
723

724
	jtag_add_dr_scan(target->tap, 2, fields, TAP_IDLE);
725 726 727 728

	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
729
static int xscale_update_vectors(struct target *target)
730
{
731
	struct xscale_common *xscale = target_to_xscale(target);
732
	int i;
733
	int retval;
734

735
	uint32_t low_reset_branch, high_reset_branch;
736

737
	for (i = 1; i < 8; i++) {
738 739 740
		/* if there's a static vector specified for this exception, override */
		if (xscale->static_high_vectors_set & (1 << i))
			xscale->high_vectors[i] = xscale->static_high_vectors[i];
741
		else {
zwelch's avatar
zwelch committed
742
			retval = target_read_u32(target, 0xffff0000 + 4*i, &xscale->high_vectors[i]);
743 744
			if (retval == ERROR_TARGET_TIMEOUT)
				return retval;
745
			if (retval != ERROR_OK) {
746
				/* Some of these reads will fail as part of normal execution */
747 748 749 750 751
				xscale->high_vectors[i] = ARMV4_5_B(0xfffffe, 0);
			}
		}
	}

752
	for (i = 1; i < 8; i++) {
753 754
		if (xscale->static_low_vectors_set & (1 << i))
			xscale->low_vectors[i] = xscale->static_low_vectors[i];
755
		else {
zwelch's avatar
zwelch committed
756
			retval = target_read_u32(target, 0x0 + 4*i, &xscale->low_vectors[i]);
757 758
			if (retval == ERROR_TARGET_TIMEOUT)
				return retval;
759
			if (retval != ERROR_OK) {
760
				/* Some of these reads will fail as part of normal execution */
761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776
				xscale->low_vectors[i] = ARMV4_5_B(0xfffffe, 0);
			}
		}
	}

	/* calculate branches to debug handler */
	low_reset_branch = (xscale->handler_address + 0x20 - 0x0 - 0x8) >> 2;
	high_reset_branch = (xscale->handler_address + 0x20 - 0xffff0000 - 0x8) >> 2;

	xscale->low_vectors[0] = ARMV4_5_B((low_reset_branch & 0xffffff), 0);
	xscale->high_vectors[0] = ARMV4_5_B((high_reset_branch & 0xffffff), 0);

	/* invalidate and load exception vectors in mini i-cache */
	xscale_invalidate_ic_line(target, 0x0);
	xscale_invalidate_ic_line(target, 0xffff0000);

David Brownell's avatar
David Brownell committed
777 778
	xscale_load_ic(target, 0x0, xscale->low_vectors);
	xscale_load_ic(target, 0xffff0000, xscale->high_vectors);
779 780 781 782

	return ERROR_OK;
}

Zachary T Welch's avatar
Zachary T Welch committed
783
static int xscale_arch_state(struct target *target)
784
{
785
	struct xscale_common *xscale = target_to_xscale(target);
786
	struct arm *arm = &xscale->arm;
787

788
	static const char *state[] = {
789 790 791
		"disabled", "enabled"
	};

792
	static const char *arch_dbg_reason[] = {
793 794 795
		"", "\n(processor reset)", "\n(trace buffer full)"
	};

796
	if (arm->common_magic != ARM_COMMON_MAGIC) {