jtaglib: proper device identification

This commit is contained in:
Triss 2022-07-24 16:30:24 +02:00
parent ddfffa06fb
commit 9809da335e
5 changed files with 186 additions and 45 deletions

View File

@ -34,7 +34,9 @@
* jtag_write_reg corrected
*/
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "jtaglib.h"
#include "jtaglib_defs.h"
@ -303,16 +305,16 @@ static const struct jtaglib_funcs* get_jlf(struct jtdev *p)
printc_err("jtaglib: ERROR: no JTAG ID set!\n");
__builtin_trap();
return NULL;
} else if (p->jtag_id == JTAG_ID_CPU16) {
return &jlf_cpu16;
} else if (JTAG_ID_IS_XV2(p->jtag_id)) {
return &jlf_cpuxv2;
} else {
// Here, it's hard to predict whether the target is CPUX or Xv2
// Here, it's hard to predict whether the target is CPUX or regular
// from the JTAG ID alone. However, this is only needed relatively
// little as the actual MCU ID should be read from info memory
// after connecting, so let's just assume Xv2 here, and add some
// after connecting, so let's just assume old here, and add some
// extra care to the few functions that will be called before the
// ID readout happens to make it all work
return &jlf_cpuxv2;
return &jlf_cpu16;
}
}
}
@ -329,14 +331,6 @@ unsigned int jtag_get_device(struct jtdev *p)
return r;
}
unsigned int jtag_chip_id(struct jtdev *p)
{
// NOTE: this is one of the special functions that have to be called early
// on before chip ID stuff is done
return get_jlf(p)->jlf_chip_id(p);
}
/* Reads one byte/word from a given address */
uint16_t jtag_read_mem(struct jtdev *p, unsigned int format, address_t address)
{
@ -452,6 +446,9 @@ unsigned int jtag_cpu_state(struct jtdev *p)
}
int jtag_get_config_fuses(struct jtdev *p)
{
// NOTE: this is one of the special functions that have to be called early
// on before chip ID stuff is done
return get_jlf(p)->jlf_get_config_fuses(p);
}
@ -729,16 +726,174 @@ int jtag_dev_getconfigfuses(device_t dev_base) {
return jtag_get_config_fuses(p);
}
int jtag_dev_init(struct jtdev *p) {
unsigned int jtagid = jtag_init(p);
if (p->failed) return -1;
/* ------------------------------------------------------------------------- */
printc("JTAG ID: 0x%02x\n", jtagid);
// TODO: validate JTAG ID in a better way!
if (jtagid != 0x89 && jtagid != 0x91) {
printc_err("mehfet: unexpected JTAG ID: 0x%02x\n", jtagid);
jtag_release_device(p, 0xfffe);
return -1;
static uint8_t jtag_ids_known[] = {
0x89, 0x8D, 0x91, 0x95, 0x98, 0x99
};
static int idproc_89(struct jtdev *p, uint32_t id_data_addr, struct chipinfo_id *id)
{
uint16_t iddata[8];
printc_dbg("Identify (89)...\n");
printc_dbg("Read device ID bytes at 0x%05x...\n", id_data_addr);
memset(iddata, 0, sizeof iddata);
// read 8 words starting at id_data_addr
// don't use read_mem_quick because we want to minimize the number of
// functions that need special care before the device ID is read
for (int i = 0; i < sizeof(iddata)/sizeof(*iddata); ++i) {
iddata[i] = jtag_read_mem(p, 16, id_data_addr + i*2);
}
id->ver_id = iddata[0];
id->ver_sub_id = 0;
id->revision = iddata[1];
id->fab = iddata[1] >> 8;
id->self = iddata[2];
id->config = (iddata[6]>>8) & 0x7f;
if (get_jlf(p)->jlf_get_config_fuses) {
id->fuses = jtag_get_config_fuses(p);
} else {
id->fuses = 0x55;
}
return 0;
}
static int idproc_9x(struct jtdev *p, uint32_t dev_id_ptr, struct chipinfo_id *id)
{
uint16_t iddata[8];
uint8_t info_len;
int tlv_size;
printc_dbg("Identify (9x)...\n");
printc_dbg("Read device ID bytes at 0x%05x...\n", dev_id_ptr);
memset(iddata, 0, sizeof iddata);
// read 8 words starting at dev_id_ptr
// don't use read_mem_quick because we want to minimize the number of
// functions that need special care before the device ID is read
for (int i = 0; i < sizeof(iddata)/sizeof(*iddata); ++i) {
iddata[i] = jtag_read_mem(p, 16, dev_id_ptr + i*2);
}
info_len = iddata[0] & 0xff;
id->ver_id = iddata[2];
id->revision = iddata[3]&0xff;
id->config = iddata[3]>>8;
id->fab = 0x55;
id->self = 0x5555;
id->fuses = 0x55;
if (info_len < 1 || info_len > 11) {
printc_dbg("jtaglib: idproc_9x: invalid info length %d\n", info_len);
return 0;
}
printc_dbg("Read TLV...\n");
tlv_size = ((1 << info_len) - 2) << 2;
uint8_t *tlvdata = (uint8_t*)malloc(tlv_size);
if (!tlvdata) {
printc_err("jtaglib: idproc_9x: can't allocate %d bytes of memory for TLV\n",
tlv_size);
return -1;
}
for (int i = 0; i < (tlv_size >> 1); ++i) {
w16le(&tlvdata[i*2], jtag_read_mem(p, 16, dev_id_ptr + i*2));
}
/* search TLV for sub-ID */
for (int i = 8; i + 3 < tlv_size; ) {
uint8_t tag = tlvdata[i]; ++i;
uint8_t len = tlvdata[i]; ++i;
if (tag == 0xff) break;
if (tag == 0x14 && len >= 2) {
id->ver_sub_id = r16le(&tlvdata[i]);
break;
}
i += len;
}
return 0;
}
int jtag_dev_init(struct jtdev *p) {
unsigned int jtagid;
uint32_t dev_id_addr;
struct chipinfo_id id;
const struct chipinfo *chip;
jtagid = jtag_init(p);
if (p->failed) return -1;
memset(&id, 0, sizeof id);
printc("JTAG ID: 0x%02x\n", jtagid);
bool found = false;
for (int i = 0; i < sizeof(jtag_ids_known)/sizeof(*jtag_ids_known); ++i) {
if (jtagid == jtag_ids_known[i]) {
found = true;
break;
}
}
if (!found) {
printc_err("jtaglib: unknown JTAG ID: 0x%02x\n", jtagid);
jtag_release_device(p, 0xfffe);
return -1;
}
if (JTAG_ID_IS_XV2(jtagid)) {
uint16_t core_ip_id;
unsigned int device_id;
jtag_ir_shift(p, IR_COREIP_ID);
core_ip_id = jtag_dr_shift_16(p, 0);
if (jtagid == 0x95) delay_ms(1500);
jtag_ir_shift(p, IR_DEVICE_ID);
device_id = jtag_dr_shift_20(p, 0);
device_id = ((device_id & 0xffff) << 4) | (device_id >> 16);
printc_dbg("jtaglib: Xv2: core IP ID=%04x, device ID=%06x\n",
core_ip_id, device_id);
if (device_id != 0) return device_id + 4;
else return 0x0ff0; // ???
} else {
dev_id_addr = 0x0ff0;
}
if (!JTAG_ID_IS_XV2(jtagid)) {
if (idproc_89(p, dev_id_addr, &id) < 0)
return -1;
} else {
if (idproc_9x(p, dev_id_addr, &id) < 0)
return -1;
}
printc_dbg(" ver_id: %04x\n", id.ver_id);
printc_dbg(" ver_sub_id: %04x\n", id.ver_sub_id);
printc_dbg(" revision: %02x\n", id.revision);
printc_dbg(" fab: %02x\n", id.fab);
printc_dbg(" self: %04x\n", id.self);
printc_dbg(" config: %02x\n", id.config);
printc_dbg(" fuses: %02x\n", id.fuses);
//printc_dbg(" activation_key: %08x\n", id.activation_key);
chip = chipinfo_find_by_id(&id);
if (!chip) {
printc_err("jtaglib: unknown chip ID\n");
} else {
p->base.chip = chip;
}
return 0;

View File

@ -44,7 +44,6 @@
* CPU types (that is, 16-bit vs CPUX vs Xv2) */
struct jtaglib_funcs {
unsigned int (*jlf_get_device)(struct jtdev *p);
unsigned int (*jlf_chip_id)(struct jtdev *p);
uint16_t (*jlf_read_mem)(struct jtdev *p, unsigned int format, address_t address);
void (*jlf_read_mem_quick)(struct jtdev *p, address_t start_address,

View File

@ -174,22 +174,6 @@ static unsigned int jlf16_get_device(struct jtdev *p)
return jtag_id;
}
/* Read the target chip id.
* return: chip id
*/
static unsigned int jlf16_chip_id(struct jtdev *p)
{
unsigned short chip_id;
/* Read id from address 0x0ff0 */
chip_id = jtag_read_mem(p, 16, 0x0FF0);
/* High / low byte are stored in reverse order */
chip_id = (chip_id << 8) + (chip_id >> 8);
return chip_id;
}
/* Reads one byte/word from a given address
* format : 8-byte, 16-word
* address: address of memory
@ -804,7 +788,6 @@ static int jlf16_get_config_fuses( struct jtdev *p )
const struct jtaglib_funcs jlf_cpu16 = {
.jlf_get_device = jlf16_get_device,
.jlf_chip_id = jlf16_chip_id,
.jlf_read_mem = jlf16_read_mem,
.jlf_read_mem_quick = jlf16_read_mem_quick,

View File

@ -7,15 +7,14 @@
#define JTAG_ERASE_MAIN 0xA504
#define JTAG_ERASE_SGMT 0xA502
/* JTAG identification value for all existing Flash-based MSP430 devices
*/
#define JTAG_ID_CPU16 0x89
#define JTAG_ID_IS_XV2(x) ((x)==0x91||(x)==0x95||(x)==0x98||(x)==0x99)
/* Instructions for the JTAG control signal register in reverse bit order
*/
#define IR_CNTRL_SIG_16BIT 0xC8 /* 0x13 */
#define IR_CNTRL_SIG_CAPTURE 0x28 /* 0x14 */
#define IR_CNTRL_SIG_RELEASE 0xA8 /* 0x15 */
#define IR_COREIP_ID 0xE8 /* 0x17 */
/* Instructions for the JTAG data register */
#define IR_DATA_16BIT 0x82 /* 0x41 */
#define IR_DATA_CAPTURE 0x42 /* 0x42 */
@ -24,6 +23,7 @@
#define IR_ADDR_16BIT 0xC1 /* 0x83 */
#define IR_ADDR_CAPTURE 0x21 /* 0x84 */
#define IR_DATA_TO_ADDR 0xA1 /* 0x85 */
#define IR_DEVICE_ID 0xE1 /* 0x87 */
/* Instructions for the JTAG PSA mode */
#define IR_DATA_PSA 0x22 /* 0x44 */
#define IR_SHIFT_OUT_PSA 0x62 /* 0x46 */
@ -60,6 +60,7 @@
#define jtag_ir_shift(p, ir) p->f->jtdev_ir_shift(p, ir)
#define jtag_dr_shift_8(p, dr) p->f->jtdev_dr_shift_8(p, dr)
#define jtag_dr_shift_16(p, dr) p->f->jtdev_dr_shift_16(p, dr)
#define jtag_dr_shift_20(p, dr) p->f->jtdev_dr_shift_20(p, dr)
#define jtag_tms_sequence(p, bits, tms) p->f->jtdev_tms_sequence(p, bits, tms)
#define jtag_init_dap(p) p->f->jtdev_init_dap(p)

View File

@ -1121,8 +1121,11 @@ static int idproc_9x(struct v3hil *fet, uint32_t dev_id_ptr,
if (tag == 0xff)
break;
if ((tag == 0x14) && (len >= 2))
if ((tag == 0x14) && (len >= 2)) {
// FIXME: this looks like it's reading from the wrong address?
id->ver_sub_id = r16le(fet->hal.payload);
// FIXME: break here?
}
i += len;
}