jtaglib: proper device identification
This commit is contained in:
parent
ddfffa06fb
commit
9809da335e
|
@ -34,7 +34,9 @@
|
||||||
* jtag_write_reg corrected
|
* jtag_write_reg corrected
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "jtaglib.h"
|
#include "jtaglib.h"
|
||||||
#include "jtaglib_defs.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");
|
printc_err("jtaglib: ERROR: no JTAG ID set!\n");
|
||||||
__builtin_trap();
|
__builtin_trap();
|
||||||
return NULL;
|
return NULL;
|
||||||
} else if (p->jtag_id == JTAG_ID_CPU16) {
|
} else if (JTAG_ID_IS_XV2(p->jtag_id)) {
|
||||||
return &jlf_cpu16;
|
return &jlf_cpuxv2;
|
||||||
} else {
|
} 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
|
// from the JTAG ID alone. However, this is only needed relatively
|
||||||
// little as the actual MCU ID should be read from info memory
|
// 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
|
// extra care to the few functions that will be called before the
|
||||||
// ID readout happens to make it all work
|
// 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;
|
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 */
|
/* Reads one byte/word from a given address */
|
||||||
uint16_t jtag_read_mem(struct jtdev *p, unsigned int format, address_t 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)
|
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);
|
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);
|
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);
|
static uint8_t jtag_ids_known[] = {
|
||||||
// TODO: validate JTAG ID in a better way!
|
0x89, 0x8D, 0x91, 0x95, 0x98, 0x99
|
||||||
if (jtagid != 0x89 && jtagid != 0x91) {
|
};
|
||||||
printc_err("mehfet: unexpected JTAG ID: 0x%02x\n", jtagid);
|
|
||||||
jtag_release_device(p, 0xfffe);
|
static int idproc_89(struct jtdev *p, uint32_t id_data_addr, struct chipinfo_id *id)
|
||||||
return -1;
|
{
|
||||||
|
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;
|
return 0;
|
||||||
|
|
|
@ -44,7 +44,6 @@
|
||||||
* CPU types (that is, 16-bit vs CPUX vs Xv2) */
|
* CPU types (that is, 16-bit vs CPUX vs Xv2) */
|
||||||
struct jtaglib_funcs {
|
struct jtaglib_funcs {
|
||||||
unsigned int (*jlf_get_device)(struct jtdev *p);
|
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);
|
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,
|
void (*jlf_read_mem_quick)(struct jtdev *p, address_t start_address,
|
||||||
|
|
|
@ -174,22 +174,6 @@ static unsigned int jlf16_get_device(struct jtdev *p)
|
||||||
return jtag_id;
|
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
|
/* Reads one byte/word from a given address
|
||||||
* format : 8-byte, 16-word
|
* format : 8-byte, 16-word
|
||||||
* address: address of memory
|
* address: address of memory
|
||||||
|
@ -804,7 +788,6 @@ static int jlf16_get_config_fuses( struct jtdev *p )
|
||||||
|
|
||||||
const struct jtaglib_funcs jlf_cpu16 = {
|
const struct jtaglib_funcs jlf_cpu16 = {
|
||||||
.jlf_get_device = jlf16_get_device,
|
.jlf_get_device = jlf16_get_device,
|
||||||
.jlf_chip_id = jlf16_chip_id,
|
|
||||||
|
|
||||||
.jlf_read_mem = jlf16_read_mem,
|
.jlf_read_mem = jlf16_read_mem,
|
||||||
.jlf_read_mem_quick = jlf16_read_mem_quick,
|
.jlf_read_mem_quick = jlf16_read_mem_quick,
|
||||||
|
|
|
@ -7,15 +7,14 @@
|
||||||
#define JTAG_ERASE_MAIN 0xA504
|
#define JTAG_ERASE_MAIN 0xA504
|
||||||
#define JTAG_ERASE_SGMT 0xA502
|
#define JTAG_ERASE_SGMT 0xA502
|
||||||
|
|
||||||
/* JTAG identification value for all existing Flash-based MSP430 devices
|
#define JTAG_ID_IS_XV2(x) ((x)==0x91||(x)==0x95||(x)==0x98||(x)==0x99)
|
||||||
*/
|
|
||||||
#define JTAG_ID_CPU16 0x89
|
|
||||||
|
|
||||||
/* Instructions for the JTAG control signal register in reverse bit order
|
/* Instructions for the JTAG control signal register in reverse bit order
|
||||||
*/
|
*/
|
||||||
#define IR_CNTRL_SIG_16BIT 0xC8 /* 0x13 */
|
#define IR_CNTRL_SIG_16BIT 0xC8 /* 0x13 */
|
||||||
#define IR_CNTRL_SIG_CAPTURE 0x28 /* 0x14 */
|
#define IR_CNTRL_SIG_CAPTURE 0x28 /* 0x14 */
|
||||||
#define IR_CNTRL_SIG_RELEASE 0xA8 /* 0x15 */
|
#define IR_CNTRL_SIG_RELEASE 0xA8 /* 0x15 */
|
||||||
|
#define IR_COREIP_ID 0xE8 /* 0x17 */
|
||||||
/* Instructions for the JTAG data register */
|
/* Instructions for the JTAG data register */
|
||||||
#define IR_DATA_16BIT 0x82 /* 0x41 */
|
#define IR_DATA_16BIT 0x82 /* 0x41 */
|
||||||
#define IR_DATA_CAPTURE 0x42 /* 0x42 */
|
#define IR_DATA_CAPTURE 0x42 /* 0x42 */
|
||||||
|
@ -24,6 +23,7 @@
|
||||||
#define IR_ADDR_16BIT 0xC1 /* 0x83 */
|
#define IR_ADDR_16BIT 0xC1 /* 0x83 */
|
||||||
#define IR_ADDR_CAPTURE 0x21 /* 0x84 */
|
#define IR_ADDR_CAPTURE 0x21 /* 0x84 */
|
||||||
#define IR_DATA_TO_ADDR 0xA1 /* 0x85 */
|
#define IR_DATA_TO_ADDR 0xA1 /* 0x85 */
|
||||||
|
#define IR_DEVICE_ID 0xE1 /* 0x87 */
|
||||||
/* Instructions for the JTAG PSA mode */
|
/* Instructions for the JTAG PSA mode */
|
||||||
#define IR_DATA_PSA 0x22 /* 0x44 */
|
#define IR_DATA_PSA 0x22 /* 0x44 */
|
||||||
#define IR_SHIFT_OUT_PSA 0x62 /* 0x46 */
|
#define IR_SHIFT_OUT_PSA 0x62 /* 0x46 */
|
||||||
|
@ -31,7 +31,7 @@
|
||||||
#define IR_PREPARE_BLOW 0x44 /* 0x22 */
|
#define IR_PREPARE_BLOW 0x44 /* 0x22 */
|
||||||
#define IR_EX_BLOW 0x24 /* 0x24 */
|
#define IR_EX_BLOW 0x24 /* 0x24 */
|
||||||
/* Instructions for the Configuration Fuse */
|
/* Instructions for the Configuration Fuse */
|
||||||
#define IR_CONFIG_FUSES 0x94
|
#define IR_CONFIG_FUSES 0x94
|
||||||
/* Bypass instruction */
|
/* Bypass instruction */
|
||||||
#define IR_BYPASS 0xFF /* 0xFF */
|
#define IR_BYPASS 0xFF /* 0xFF */
|
||||||
/* Instructions for the EEM */
|
/* Instructions for the EEM */
|
||||||
|
@ -60,6 +60,7 @@
|
||||||
#define jtag_ir_shift(p, ir) p->f->jtdev_ir_shift(p, ir)
|
#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_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_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_tms_sequence(p, bits, tms) p->f->jtdev_tms_sequence(p, bits, tms)
|
||||||
#define jtag_init_dap(p) p->f->jtdev_init_dap(p)
|
#define jtag_init_dap(p) p->f->jtdev_init_dap(p)
|
||||||
|
|
||||||
|
|
|
@ -1121,8 +1121,11 @@ static int idproc_9x(struct v3hil *fet, uint32_t dev_id_ptr,
|
||||||
if (tag == 0xff)
|
if (tag == 0xff)
|
||||||
break;
|
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);
|
id->ver_sub_id = r16le(fet->hal.payload);
|
||||||
|
// FIXME: break here?
|
||||||
|
}
|
||||||
|
|
||||||
i += len;
|
i += len;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue