From 2d4a50313596081a64bd1397017985641fd8cad0 Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Sun, 3 Jan 2021 17:49:28 +0100 Subject: [PATCH] jtag_scan: Rework chain detection Fixme: stlinkv2/hosted probably does only handle STM devices. Check if jtag_devs.c really needed. --- src/Makefile | 1 - src/platforms/hosted/Makefile.inc | 2 +- src/target/adiv5.h | 8 +- src/target/jtag_scan.c | 288 +++++++++++++++--------------- 4 files changed, 152 insertions(+), 147 deletions(-) diff --git a/src/Makefile b/src/Makefile index de05365..188ecfa 100644 --- a/src/Makefile +++ b/src/Makefile @@ -31,7 +31,6 @@ 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 cd0ce56..fcf61ca 100644 --- a/src/platforms/hosted/Makefile.inc +++ b/src/platforms/hosted/Makefile.inc @@ -59,7 +59,7 @@ ifneq ($(HOSTED_BMP_ONLY), 1) endif VPATH += platforms/pc -SRC += timing.c cl_utils.c utils.c +SRC += timing.c cl_utils.c utils.c jtag_devs.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 5a10543..890f824 100644 --- a/src/target/adiv5.h +++ b/src/target/adiv5.h @@ -88,19 +88,23 @@ #define ADIV5_AP_BASE ADIV5_AP_REG(0xF8) #define ADIV5_AP_IDR ADIV5_AP_REG(0xFC) -/* Known designers seen in SYSROM-PIDR. Ignore Bit 0 from - * the designer bits to get JEDEC Ids with bit 7 ignored.*/ +/* 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! + */ #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 88a8a57..d1c7eca 100644 --- a/src/target/jtag_scan.c +++ b/src/target/jtag_scan.c @@ -3,6 +3,7 @@ * * 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 @@ -25,16 +26,14 @@ #include "general.h" #include "jtagtap.h" -#include "jtag_scan.h" #include "target.h" #include "adiv5.h" -#include "jtag_devs.h" struct jtag_dev_s jtag_devs[JTAG_MAX_DEVS+1]; int jtag_dev_count; /* bucket of ones for don't care TDI */ -static const uint8_t ones[] = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"; +static const uint8_t ones[] = {0xff, 0xFF, 0xFF, 0xFF}; #if PC_HOSTED == 0 void jtag_add_device(const int dev_index, const jtag_dev_t *jtag_dev) @@ -47,36 +46,32 @@ 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. * - * 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. + * 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 * * Reset the TAP state machine again. This should load all IRs with IDCODE. - * 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. - */ + * Read 32 bit IDCODE for all devices. + */ + int jtag_scan(const uint8_t *irlens) { int i; - uint32_t j; - + void (*jd_handlers[JTAG_MAX_DEVS])(uint8_t jd_index, uint32_t j_idcode); target_list_free(); - jtag_dev_count = 0; - memset(&jtag_devs, 0, sizeof(jtag_devs)); + memset(jd_handlers, 0, sizeof(jd_handlers)); - /* 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"); @@ -86,139 +81,146 @@ int jtag_scan(const uint8_t *irlens) jtagtap_init(); #endif jtag_proc.jtagtap_reset(); - - 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; - } +#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); } - - 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(); - 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; - - 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; - } - - DEBUG_INFO("Return to Run-Test/Idle\n"); - jtag_proc.jtagtap_next(1, 1); - jtagtap_return_idle(); - if(!jtag_dev_count) { + if (!(ir_chain[0] & 1)) { + DEBUG_WARN("Unexpected IR chain!\n"); return 0; } - - /* Fill in the ir_postscan fields */ - 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 */ + jtagtap_return_idle(); + 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(); - 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; - + 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; + 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) "); + } + jtag_proc.jtagtap_reset(); + /* Fill in the ir_postscan fields */ + for(i = jtag_dev_count - 1; i; i--) { + jtag_devs[i-1].ir_postscan = jtag_devs[i].ir_postscan + + jtag_devs[i].ir_len; } - 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++) - 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"); + platform_add_jtag_dev(i, &jtag_devs[i]); } #endif - /* Check for known devices and handle accordingly */ for(i = 0; i < jtag_dev_count; 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; - } - + /* Call handler to initialise/probe device further */ + if (jd_handlers[i]) + jd_handlers[i](i, jtag_devs[i].jd_idcode); return jtag_dev_count; }