diff --git a/src/Makefile b/src/Makefile index 188ecfa..de05365 100644 --- a/src/Makefile +++ b/src/Makefile @@ -31,6 +31,7 @@ SRC = \ gdb_hostio.c \ gdb_packet.c \ hex_utils.c \ + jtag_devs.c \ jtag_scan.c \ lmi.c \ lpc_common.c \ diff --git a/src/platforms/hosted/Makefile.inc b/src/platforms/hosted/Makefile.inc index f3e3248..6ba2d78 100644 --- a/src/platforms/hosted/Makefile.inc +++ b/src/platforms/hosted/Makefile.inc @@ -73,7 +73,7 @@ ifneq ($(HOSTED_BMP_ONLY), 1) endif VPATH += platforms/pc -SRC += timing.c cl_utils.c utils.c jtag_devs.c +SRC += timing.c cl_utils.c utils.c SRC += bmp_remote.c remote_swdptap.c remote_jtagtap.c ifneq ($(HOSTED_BMP_ONLY), 1) SRC += bmp_libusb.c stlinkv2.c diff --git a/src/target/adiv5.h b/src/target/adiv5.h index 95c62f6..bd0985e 100644 --- a/src/target/adiv5.h +++ b/src/target/adiv5.h @@ -89,23 +89,19 @@ #define ADIV5_AP_BASE ADIV5_AP_REG(0xF8) #define ADIV5_AP_IDR ADIV5_AP_REG(0xFC) -/* Known designers seen in SYSROM-PIDR and JTAG IDCode. - * Ignore Bit 0 from the designer bits to get JEDEC Ids. - * Should get it's one file as not only related to Adiv5! - */ +/* Known designers seen in SYSROM-PIDR. Ignore Bit 0 from + * the designer bits to get JEDEC Ids with bit 7 ignored.*/ #define AP_DESIGNER_FREESCALE 0x00e #define AP_DESIGNER_TEXAS 0x017 #define AP_DESIGNER_ATMEL 0x01f #define AP_DESIGNER_STM 0x020 #define AP_DESIGNER_CYPRESS 0x034 #define AP_DESIGNER_INFINEON 0x041 -#define DESIGNER_XILINX 0x049 #define AP_DESIGNER_NORDIC 0x244 #define AP_DESIGNER_ARM 0x43b /*LPC845 with designer 501. Strange!? */ #define AP_DESIGNER_SPECULAR 0x501 #define AP_DESIGNER_CS 0x555 -#define DESIGNER_XAMBALA 0x61e #define AP_DESIGNER_ENERGY_MICRO 0x673 #define AP_DESIGNER_GIGADEVICE 0x751 #define AP_DESIGNER_RASPBERRY 0x927 diff --git a/src/target/jtag_scan.c b/src/target/jtag_scan.c index eb1efc8..04a8cca 100644 --- a/src/target/jtag_scan.c +++ b/src/target/jtag_scan.c @@ -3,7 +3,6 @@ * * Copyright (C) 2011 Black Sphere Technologies Ltd. * Written by Gareth McMullin - * Copyright (C) 2021 Uwe Bonnes(bon@elektron.ikp.physik.tu-darmstadt.de) * * 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 @@ -26,14 +25,16 @@ #include "general.h" #include "jtagtap.h" +#include "jtag_scan.h" #include "target.h" #include "adiv5.h" +#include "jtag_devs.h" jtag_dev_t jtag_devs[JTAG_MAX_DEVS+1]; int jtag_dev_count; /* bucket of ones for don't care TDI */ -static const uint8_t ones[] = {0xff, 0xFF, 0xFF, 0xFF}; +static const uint8_t ones[] = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"; #if PC_HOSTED == 0 void jtag_add_device(const int dev_index, const jtag_dev_t *jtag_dev) @@ -46,32 +47,36 @@ void jtag_add_device(const int dev_index, const jtag_dev_t *jtag_dev) #endif /* Scan JTAG chain for devices, store IR length and IDCODE (if present). + * Reset TAP state machine. + * Select Shift-IR state. + * Each device is assumed to shift out IR at 0x01. (this may not always be true) + * Shift in ones until we read two consecutive ones, then we have shifted out the + * IRs of all devices. * - * https://www.fpga4fun.com/JTAG3.html - * Count the number of devices in the JTAG chain - * - * shift enough ones in IR - * shift enough zeros in DR - * Now shift out ones and stop if first '1' is seen. This gets the number - * of devices - * - * Assume max 32 devices with max IR len 16 = 512 bits = 16 loops * 32 bit + * After this process all the IRs are loaded with the BYPASS command. + * Select Shift-DR state. + * Shift in ones and count zeros shifted out. Should be one for each device. + * Check this against device count obtained by IR scan above. * * Reset the TAP state machine again. This should load all IRs with IDCODE. - * Read 32 bit IDCODE for all devices. - */ - + * For each device, shift out one bit. If this is zero IDCODE isn't present, + * continue to next device. If this is one shift out the remaining 31 bits + * of the IDCODE register. + */ int jtag_scan(const uint8_t *irlens) { int i; - void (*jd_handlers[JTAG_MAX_DEVS])(jtag_dev_t *jd); + uint32_t j; + target_list_free(); - memset(jd_handlers, 0, sizeof(jd_handlers)); + jtag_dev_count = 0; + memset(&jtag_devs, 0, sizeof(jtag_devs)); - /* Run throught the SWD to JTAG sequence for the case where an - * attached SWJ-DP is in SW-DP mode. + /* Run throught the SWD to JTAG sequence for the case where an attached SWJ-DP is + * in SW-DP mode. */ + DEBUG_INFO("Resetting TAP\n"); #if PC_HOSTED == 1 if (platform_jtagtap_init()) { DEBUG_WARN("JTAG not available\n"); @@ -81,146 +86,139 @@ int jtag_scan(const uint8_t *irlens) jtagtap_init(); #endif jtag_proc.jtagtap_reset(); -#define LOOPS 16 - jtagtap_shift_ir(); - i = LOOPS; - uint8_t ir_chain[64], *din = ir_chain; - while (i--) { - jtag_proc.jtagtap_tdi_tdo_seq(din, (i == 0) ? 1 : 0, ones, - sizeof(ones) * 8); - din += sizeof(ones); - } - if (!(ir_chain[0] & 1)) { - DEBUG_WARN("Unexpected IR chain!\n"); - return 0; + + if (irlens) { + DEBUG_WARN("Given list of IR lengths, skipping probe\n"); + DEBUG_INFO("Change state to Shift-IR\n"); + jtagtap_shift_ir(); + j = 0; + while((jtag_dev_count <= JTAG_MAX_DEVS) && + (jtag_devs[jtag_dev_count].ir_len <= JTAG_MAX_IR_LEN)) { + uint32_t irout; + if(*irlens == 0) + break; + jtag_proc.jtagtap_tdi_tdo_seq((uint8_t*)&irout, 0, ones, *irlens); + if (!(irout & 1)) { + DEBUG_WARN("check failed: IR[0] != 1\n"); + return -1; + } + jtag_devs[jtag_dev_count].ir_len = *irlens; + jtag_devs[jtag_dev_count].ir_prescan = j; + jtag_devs[jtag_dev_count].jd_dev = jtag_dev_count; + j += *irlens; + irlens++; + jtag_dev_count++; + } + } else { + DEBUG_INFO("Change state to Shift-IR\n"); + jtagtap_shift_ir(); + + DEBUG_INFO("Scanning out IRs\n"); + if(!jtag_proc.jtagtap_next(0, 1)) { + DEBUG_WARN("jtag_scan: Sanity check failed: IR[0] shifted out " + "as 0\n"); + jtag_dev_count = -1; + return -1; /* must be 1 */ + } + jtag_devs[0].ir_len = 1; j = 1; + while((jtag_dev_count <= JTAG_MAX_DEVS) && + (jtag_devs[jtag_dev_count].ir_len <= JTAG_MAX_IR_LEN)) { + if(jtag_proc.jtagtap_next(0, 1)) { + if(jtag_devs[jtag_dev_count].ir_len == 1) break; + jtag_devs[++jtag_dev_count].ir_len = 1; + jtag_devs[jtag_dev_count].ir_prescan = j; + jtag_devs[jtag_dev_count].jd_dev = jtag_dev_count; + } else jtag_devs[jtag_dev_count].ir_len++; + j++; + } + if(jtag_dev_count > JTAG_MAX_DEVS) { + DEBUG_WARN("jtag_scan: Maximum device count exceeded\n"); + jtag_dev_count = -1; + return -1; + } + if(jtag_devs[jtag_dev_count].ir_len > JTAG_MAX_IR_LEN) { + DEBUG_WARN("jtag_scan: Maximum IR length exceeded\n"); + jtag_dev_count = -1; + return -1; + } } + + DEBUG_INFO("Return to Run-Test/Idle\n"); + jtag_proc.jtagtap_next(1, 1); jtagtap_return_idle(); + + /* All devices should be in BYPASS now */ + + /* Count device on chain */ + DEBUG_INFO("Change state to Shift-DR\n"); jtagtap_shift_dr(); - i = LOOPS; - uint8_t zeros[] = {0, 0, 0, 0}; - while(i--) { - jtag_proc.jtagtap_tdi_seq(0, zeros, sizeof(zeros) * 8); - } - int num_devices = 0; - while (!jtag_proc.jtagtap_next(0,1) && (i++ < 6)) - num_devices++; - jtag_proc.jtagtap_reset(); - jtagtap_shift_dr(); - jtag_dev_count = num_devices; - if (!num_devices) - return 0; - DEBUG_TARGET("Found %d devices\n", num_devices); - int irbit = 1; - int j = 0; - for (i = 0; i < num_devices; i++) { - uint8_t id[4]; - jtag_proc.jtagtap_tdi_tdo_seq(id, 0, ones, 32); - if (!(id[0] & 1)) { - DEBUG_WARN("Invalid IDCode!\n"); - return 0; - } - uint32_t idcode = id[3] << 24 | id[2] << 16 | id[1] << 8 | id[0]; - unsigned int designer = ((id[1] & 0xf) << 8) | (id[0] >> 1); - unsigned int product = id[2] | ((id[3] & 0xf) << 8); - unsigned int expected_irlen = 0; - switch (designer) { - case AP_DESIGNER_ARM: - switch (product) { - case 0xba0: - jtag_devs[i].jd_descr = "ADIv5 JTAG-DP port"; - jd_handlers[i] = adiv5_jtag_dp_handler; - expected_irlen = 4; - break; - default: - jtag_devs[i].jd_descr = "ARM"; - } - break; - case AP_DESIGNER_STM: - expected_irlen = 5; - jtag_devs[i].jd_descr = "STM32 BSD"; - break; - case AP_DESIGNER_ATMEL: - if ((product >= 0x940) & (product < 0x990)) { - jtag_devs[i].jd_descr = "ATMEL AVR8"; - expected_irlen = 4; - break; - } - jtag_devs[i].jd_descr = "ATMEL"; - break; - case DESIGNER_XILINX: - if (!irlens) { - /* Guessed irlen for XILINX devices is wrong. - * IR data contains status bits! - */ - DEBUG_WARN("Please provide irlens as chain contains XILINX devices!\n"); - return 0; - } - jtag_devs[i].jd_descr = "XILINX"; - break; - case DESIGNER_XAMBALA: - expected_irlen = 5; - jtag_devs[i].jd_descr = "RVDBG013"; - break; - case AP_DESIGNER_GIGADEVICE: - expected_irlen = 5; - jtag_devs[i].jd_descr = "GIGADEVICE BSD"; - break; - } - if (!jtag_devs[i].jd_descr) { - DEBUG_WARN("Unhandled designer %x\n", designer); - jtag_devs[i].jd_descr = "Unknow"; - } - bool bit; - int guessed_irlen = 0; - int advance = irbit; - do { - /* Guess IR length from the IR scan after JTAG Reset - * First bit should be '1', following bits are '0', if not used - * for instruction capture, as for Xilinx parts. - */ - bit = (ir_chain[advance / 8] & (1 << (advance & 7))); - guessed_irlen++; - advance++; - } while (!bit && (advance < (JTAG_MAX_DEVS * 16))); - if (irlens) { /* Allow to overwrite from the command line!*/ - if (*irlens != guessed_irlen) { - DEBUG_TARGET("Provides irlen %d vs guessed %d for device %d\n", - *irlens, guessed_irlen, i + 1); - } - expected_irlen = *irlens++; - } - if (!expected_irlen) { - expected_irlen = guessed_irlen++; - } - jtag_devs[i].ir_len = expected_irlen; - jtag_devs[i].ir_prescan = j; - jtag_devs[i].jd_dev = i; - jtag_devs[i].jd_idcode = idcode; + for(i = 0; (jtag_proc.jtagtap_next(0, 1) == 0) && (i <= jtag_dev_count); i++) jtag_devs[i].dr_postscan = jtag_dev_count - i - 1; - jtag_devs[i].current_ir = -1; - j += expected_irlen; - irbit += expected_irlen; - DEBUG_INFO("%2d: IDCODE: 0x%08" PRIx32 ", IR len %d %s%s\n", i + 1, - idcode,jtag_devs[i].ir_len, jtag_devs[i].jd_descr, - (jd_handlers[i]) ? "" : " (Unhandled) "); + + if(i != jtag_dev_count) { + DEBUG_WARN("jtag_scan: Sanity check failed: " + "BYPASS dev count doesn't match IR scan\n"); + jtag_dev_count = -1; + return -1; } - jtag_proc.jtagtap_reset(); + + DEBUG_INFO("Return to Run-Test/Idle\n"); + jtag_proc.jtagtap_next(1, 1); + jtagtap_return_idle(); + if(!jtag_dev_count) { + return 0; + } + /* Fill in the ir_postscan fields */ - for(i = jtag_dev_count - 1; i; i--) { + for(i = jtag_dev_count - 1; i; i--) jtag_devs[i-1].ir_postscan = jtag_devs[i].ir_postscan + jtag_devs[i].ir_len; + + /* Reset jtagtap: should take all devs to IDCODE */ + jtag_proc.jtagtap_reset(); + jtagtap_shift_dr(); + for(i = 0; i < jtag_dev_count; i++) { + if(!jtag_proc.jtagtap_next(0, 1)) continue; + jtag_devs[i].jd_idcode = 1; + for(j = 2; j; j <<= 1) + if(jtag_proc.jtagtap_next(0, 1)) jtag_devs[i].jd_idcode |= j; + } + DEBUG_INFO("Return to Run-Test/Idle\n"); + jtag_proc.jtagtap_next(1, 1); + jtagtap_return_idle(); #if PC_HOSTED == 1 /*Transfer needed device information to firmware jtag_devs*/ - for(i = 0; i < jtag_dev_count; i++) { + for(i = 0; i < jtag_dev_count; i++) platform_add_jtag_dev(i, &jtag_devs[i]); + for(i = 0; i < jtag_dev_count; i++) { + DEBUG_INFO("Idcode 0x%08" PRIx32, jtag_devs[i].jd_idcode); + for(j = 0; dev_descr[j].idcode; j++) { + if((jtag_devs[i].jd_idcode & dev_descr[j].idmask) == + dev_descr[j].idcode) { + DEBUG_INFO(": %s", + (dev_descr[j].descr) ? dev_descr[j].descr : "unknown"); + break; + } + } + DEBUG_INFO("\n"); } #endif + /* Check for known devices and handle accordingly */ for(i = 0; i < jtag_dev_count; i++) - /* Call handler to initialise/probe device further */ - if (jd_handlers[i]) - jd_handlers[i](&jtag_devs[i]); + for(j = 0; dev_descr[j].idcode; j++) + if((jtag_devs[i].jd_idcode & dev_descr[j].idmask) == + dev_descr[j].idcode) { + jtag_devs[i].current_ir = -1; + /* Save description in table */ + jtag_devs[i].jd_descr = dev_descr[j].descr; + /* Call handler to initialise/probe device further */ + if(dev_descr[j].handler) + dev_descr[j].handler(i, jtag_devs[i].jd_idcode); + break; + } + return jtag_dev_count; }