2012-10-11 22:33:20 +00:00
|
|
|
|
/* MSPDebug - debugging tool for MSP430 MCUs
|
|
|
|
|
* Copyright (C) 2009-2012 Daniel Beer
|
2015-02-23 22:58:40 +00:00
|
|
|
|
* Copyright (C) 2012-2015 Peter Bägel
|
2012-10-11 22:33:20 +00:00
|
|
|
|
*
|
|
|
|
|
* 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
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* jtag functions are taken from TIs SLAA149–September 2002
|
2020-06-01 04:56:52 +00:00
|
|
|
|
*
|
2015-02-23 22:58:40 +00:00
|
|
|
|
* breakpoint implementation influenced by a posting of Ruisheng Lin
|
|
|
|
|
* to Travis Goodspeed at 2012-09-20 found at:
|
|
|
|
|
* http://sourceforge.net/p/goodfet/mailman/message/29860790/
|
2012-10-11 22:33:20 +00:00
|
|
|
|
*
|
|
|
|
|
* 2012-10-03 Peter Bägel (DF5EQ)
|
2015-02-23 22:16:46 +00:00
|
|
|
|
* 2012-10-03 initial release Peter Bägel (DF5EQ)
|
|
|
|
|
* 2014-12-26 jtag_single_step added Peter Bägel (DF5EQ)
|
|
|
|
|
* jtag_read_reg corrected
|
|
|
|
|
* jtag_write_reg corrected
|
2015-02-23 22:58:40 +00:00
|
|
|
|
* 2015-02-21 jtag_set_breakpoint added Peter Bägel (DF5EQ)
|
|
|
|
|
* jtag_cpu_state added
|
2020-06-01 04:56:52 +00:00
|
|
|
|
* 2020-06-01 jtag_read_reg corrected Gabor Mayer (HG5OAP)
|
|
|
|
|
* jtag_write_reg corrected
|
2012-10-11 22:33:20 +00:00
|
|
|
|
*/
|
|
|
|
|
|
2022-07-24 14:30:24 +00:00
|
|
|
|
#include <stdbool.h>
|
2012-10-11 22:33:20 +00:00
|
|
|
|
#include <stdlib.h>
|
2022-07-24 14:30:24 +00:00
|
|
|
|
#include <string.h>
|
2022-07-24 13:14:27 +00:00
|
|
|
|
|
2012-10-11 22:33:20 +00:00
|
|
|
|
#include "jtaglib.h"
|
2022-07-24 02:29:48 +00:00
|
|
|
|
#include "jtaglib_defs.h"
|
2021-10-09 21:55:43 +00:00
|
|
|
|
|
2022-07-24 13:14:27 +00:00
|
|
|
|
#include "output.h"
|
|
|
|
|
#include "ctrlc.h"
|
|
|
|
|
#include "device.h"
|
|
|
|
|
|
2012-10-11 22:33:20 +00:00
|
|
|
|
/* Reset target JTAG interface and perform fuse-HW check */
|
2021-10-09 21:55:43 +00:00
|
|
|
|
static void jtag_default_reset_tap(struct jtdev *p)
|
2012-10-11 22:33:20 +00:00
|
|
|
|
{
|
2013-12-12 11:54:37 +00:00
|
|
|
|
int loop_counter;
|
|
|
|
|
|
2021-10-09 21:55:43 +00:00
|
|
|
|
/* TODO: replace with tms_sequence()? */
|
2013-12-12 11:54:37 +00:00
|
|
|
|
jtag_tms_set(p);
|
|
|
|
|
jtag_tck_set(p);
|
|
|
|
|
|
|
|
|
|
/* Perform fuse check */
|
|
|
|
|
jtag_tms_clr(p);
|
|
|
|
|
jtag_tms_set(p);
|
|
|
|
|
jtag_tms_clr(p);
|
|
|
|
|
jtag_tms_set(p);
|
|
|
|
|
|
|
|
|
|
/* Reset JTAG state machine */
|
|
|
|
|
for (loop_counter = 6; loop_counter > 0; loop_counter--) {
|
|
|
|
|
jtag_tck_clr(p);
|
|
|
|
|
jtag_tck_set(p);
|
|
|
|
|
|
|
|
|
|
if (p->failed)
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Set JTAG state machine to Run-Test/IDLE */
|
|
|
|
|
jtag_tck_clr(p);
|
|
|
|
|
jtag_tms_clr(p);
|
|
|
|
|
jtag_tck_set(p);
|
2012-10-11 22:33:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-12 11:54:37 +00:00
|
|
|
|
/* This function sets the target JTAG state machine
|
|
|
|
|
* back into the Run-Test/Idle state after a shift access
|
|
|
|
|
*/
|
2021-10-09 21:55:43 +00:00
|
|
|
|
static void jtag_default_tclk_prep (struct jtdev *p)
|
2012-10-11 22:33:20 +00:00
|
|
|
|
{
|
2013-12-12 11:54:37 +00:00
|
|
|
|
/* JTAG state = Exit-DR */
|
|
|
|
|
jtag_tck_clr(p);
|
|
|
|
|
jtag_tck_set(p);
|
|
|
|
|
|
|
|
|
|
/* JTAG state = Update-DR */
|
|
|
|
|
jtag_tms_clr(p);
|
|
|
|
|
jtag_tck_clr(p);
|
|
|
|
|
jtag_tck_set(p);
|
|
|
|
|
|
|
|
|
|
/* JTAG state = Run-Test/Idle */
|
2012-10-11 22:33:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-12 11:54:37 +00:00
|
|
|
|
/* Shift a value into TDI (MSB first) and simultaneously
|
|
|
|
|
* shift out a value from TDO (MSB first)
|
|
|
|
|
* num_bits: number of bits to shift
|
|
|
|
|
* data_out: data to be shifted out
|
|
|
|
|
* return : scanned TDO value
|
|
|
|
|
*/
|
2021-10-09 21:55:43 +00:00
|
|
|
|
static unsigned int jtag_default_shift( struct jtdev *p,
|
2013-12-12 11:54:37 +00:00
|
|
|
|
unsigned char num_bits,
|
2012-10-11 22:33:20 +00:00
|
|
|
|
unsigned int data_out )
|
|
|
|
|
{
|
2013-12-12 11:54:37 +00:00
|
|
|
|
unsigned int data_in;
|
|
|
|
|
unsigned int mask;
|
|
|
|
|
unsigned int tclk_save;
|
|
|
|
|
|
2015-02-03 18:42:23 +00:00
|
|
|
|
tclk_save = p->f->jtdev_tclk_get(p);
|
2013-12-12 11:54:37 +00:00
|
|
|
|
|
|
|
|
|
data_in = 0;
|
|
|
|
|
for (mask = 0x0001U << (num_bits - 1); mask != 0; mask >>= 1) {
|
|
|
|
|
if ((data_out & mask) != 0)
|
|
|
|
|
jtag_tdi_set(p);
|
|
|
|
|
else
|
|
|
|
|
jtag_tdi_clr(p);
|
|
|
|
|
|
|
|
|
|
if (mask == 1)
|
|
|
|
|
jtag_tms_set(p);
|
|
|
|
|
|
|
|
|
|
jtag_tck_clr(p);
|
|
|
|
|
jtag_tck_set(p);
|
|
|
|
|
|
2015-02-03 18:42:23 +00:00
|
|
|
|
if (p->f->jtdev_tdo_get(p) == 1)
|
2013-12-12 11:54:37 +00:00
|
|
|
|
data_in |= mask;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-03 18:42:23 +00:00
|
|
|
|
p->f->jtdev_tclk(p, tclk_save);
|
2013-12-12 11:54:37 +00:00
|
|
|
|
|
|
|
|
|
/* Set JTAG state back to Run-Test/Idle */
|
2021-10-09 21:55:43 +00:00
|
|
|
|
jtag_default_tclk_prep(p);
|
2013-12-12 11:54:37 +00:00
|
|
|
|
|
|
|
|
|
return data_in;
|
2012-10-11 22:33:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-12 11:54:37 +00:00
|
|
|
|
/* Shifts a new instruction into the JTAG instruction register through TDI
|
|
|
|
|
* MSB first, with interchanged MSB/LSB, to use the shifting function
|
|
|
|
|
* instruction: 8 bit instruction
|
|
|
|
|
* return : scanned TDO value
|
|
|
|
|
*/
|
2021-10-09 21:55:43 +00:00
|
|
|
|
uint8_t jtag_default_ir_shift(struct jtdev *p, uint8_t instruction)
|
2012-10-11 22:33:20 +00:00
|
|
|
|
{
|
2013-12-12 11:54:37 +00:00
|
|
|
|
/* JTAG state = Run-Test/Idle */
|
|
|
|
|
jtag_tms_set(p);
|
|
|
|
|
jtag_tck_clr(p);
|
|
|
|
|
jtag_tck_set(p);
|
|
|
|
|
|
|
|
|
|
/* JTAG state = Select DR-Scan */
|
|
|
|
|
jtag_tck_clr(p);
|
|
|
|
|
jtag_tck_set(p);
|
|
|
|
|
|
|
|
|
|
/* JTAG state = Select IR-Scan */
|
|
|
|
|
jtag_tms_clr(p);
|
|
|
|
|
jtag_tck_clr(p);
|
|
|
|
|
jtag_tck_set(p);
|
|
|
|
|
|
|
|
|
|
/* JTAG state = Capture-IR */
|
|
|
|
|
jtag_tck_clr(p);
|
|
|
|
|
jtag_tck_set(p);
|
|
|
|
|
|
|
|
|
|
/* JTAG state = Shift-IR, Shift in TDI (8-bit) */
|
2021-10-09 21:55:43 +00:00
|
|
|
|
return jtag_default_shift(p, 8, instruction);
|
2013-12-12 11:54:37 +00:00
|
|
|
|
|
|
|
|
|
/* JTAG state = Run-Test/Idle */
|
2012-10-11 22:33:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-06-14 19:28:07 +00:00
|
|
|
|
/* Shifts a given 8-bit byte into the JTAG data register through TDI.
|
|
|
|
|
* data : 8 bit data
|
|
|
|
|
* return: scanned TDO value
|
|
|
|
|
*/
|
2021-10-09 21:55:43 +00:00
|
|
|
|
uint8_t jtag_default_dr_shift_8(struct jtdev *p, uint8_t data)
|
2017-06-14 19:28:07 +00:00
|
|
|
|
{
|
|
|
|
|
/* JTAG state = Run-Test/Idle */
|
|
|
|
|
jtag_tms_set(p);
|
|
|
|
|
jtag_tck_clr(p);
|
|
|
|
|
jtag_tck_set(p);
|
|
|
|
|
|
|
|
|
|
/* JTAG state = Select DR-Scan */
|
|
|
|
|
jtag_tms_clr(p);
|
|
|
|
|
jtag_tck_clr(p);
|
|
|
|
|
jtag_tck_set(p);
|
|
|
|
|
|
|
|
|
|
/* JTAG state = Capture-DR */
|
|
|
|
|
jtag_tck_clr(p);
|
|
|
|
|
jtag_tck_set(p);
|
|
|
|
|
|
|
|
|
|
/* JTAG state = Shift-DR, Shift in TDI (16-bit) */
|
2021-10-09 21:55:43 +00:00
|
|
|
|
return jtag_default_shift(p, 8, data);
|
2017-06-14 19:28:07 +00:00
|
|
|
|
|
|
|
|
|
/* JTAG state = Run-Test/Idle */
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-12 11:54:37 +00:00
|
|
|
|
/* Shifts a given 16-bit word into the JTAG data register through TDI.
|
|
|
|
|
* data : 16 bit data
|
|
|
|
|
* return: scanned TDO value
|
|
|
|
|
*/
|
2021-10-09 21:55:43 +00:00
|
|
|
|
uint16_t jtag_default_dr_shift_16(struct jtdev *p, uint16_t data)
|
2012-10-11 22:33:20 +00:00
|
|
|
|
{
|
2013-12-12 11:54:37 +00:00
|
|
|
|
/* JTAG state = Run-Test/Idle */
|
|
|
|
|
jtag_tms_set(p);
|
|
|
|
|
jtag_tck_clr(p);
|
|
|
|
|
jtag_tck_set(p);
|
|
|
|
|
|
|
|
|
|
/* JTAG state = Select DR-Scan */
|
|
|
|
|
jtag_tms_clr(p);
|
|
|
|
|
jtag_tck_clr(p);
|
|
|
|
|
jtag_tck_set(p);
|
|
|
|
|
|
|
|
|
|
/* JTAG state = Capture-DR */
|
|
|
|
|
jtag_tck_clr(p);
|
|
|
|
|
jtag_tck_set(p);
|
|
|
|
|
|
|
|
|
|
/* JTAG state = Shift-DR, Shift in TDI (16-bit) */
|
2021-10-09 21:55:43 +00:00
|
|
|
|
return jtag_default_shift(p, 16, data);
|
2013-12-12 11:54:37 +00:00
|
|
|
|
|
|
|
|
|
/* JTAG state = Run-Test/Idle */
|
2012-10-11 22:33:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-07-19 23:08:13 +00:00
|
|
|
|
|
|
|
|
|
/* Shifts a given 20-bit word into the JTAG data register through TDI.
|
|
|
|
|
* data : 20 bit data
|
|
|
|
|
* return: scanned TDO value
|
|
|
|
|
*/
|
|
|
|
|
uint32_t jtag_default_dr_shift_20(struct jtdev *p, uint32_t data)
|
|
|
|
|
{
|
|
|
|
|
/* JTAG state = Run-Test/Idle */
|
|
|
|
|
jtag_tms_set(p);
|
|
|
|
|
jtag_tck_clr(p);
|
|
|
|
|
jtag_tck_set(p);
|
|
|
|
|
|
|
|
|
|
/* JTAG state = Select DR-Scan */
|
|
|
|
|
jtag_tms_clr(p);
|
|
|
|
|
jtag_tck_clr(p);
|
|
|
|
|
jtag_tck_set(p);
|
|
|
|
|
|
|
|
|
|
/* JTAG state = Capture-DR */
|
|
|
|
|
jtag_tck_clr(p);
|
|
|
|
|
jtag_tck_set(p);
|
|
|
|
|
|
|
|
|
|
/* JTAG state = Shift-DR, Shift in TDI (20-bit) */
|
|
|
|
|
return jtag_default_shift(p, 20, data);
|
|
|
|
|
|
|
|
|
|
/* JTAG state = Run-Test/Idle */
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-09 21:55:43 +00:00
|
|
|
|
void jtag_default_tms_sequence(struct jtdev *p, int bits, unsigned int value)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < bits; ++i) {
|
|
|
|
|
jtag_tck_clr(p);
|
|
|
|
|
if (value & (1u << i))
|
|
|
|
|
jtag_tms_set(p);
|
2021-10-09 22:00:47 +00:00
|
|
|
|
else
|
2021-10-09 21:55:43 +00:00
|
|
|
|
jtag_tms_clr(p);
|
|
|
|
|
jtag_tck_set(p);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void jtag_default_init_dap(struct jtdev *p)
|
|
|
|
|
{
|
|
|
|
|
jtag_rst_clr(p);
|
|
|
|
|
p->f->jtdev_power_on(p);
|
|
|
|
|
jtag_tdi_set(p);
|
|
|
|
|
jtag_tms_set(p);
|
|
|
|
|
jtag_tck_set(p);
|
|
|
|
|
jtag_tclk_set(p);
|
|
|
|
|
|
|
|
|
|
jtag_rst_set(p);
|
|
|
|
|
jtag_tst_clr(p);
|
|
|
|
|
|
|
|
|
|
jtag_tst_set(p);
|
|
|
|
|
jtag_rst_clr(p);
|
|
|
|
|
jtag_tst_clr(p);
|
|
|
|
|
|
|
|
|
|
jtag_tst_set(p);
|
|
|
|
|
|
|
|
|
|
p->f->jtdev_connect(p);
|
|
|
|
|
jtag_rst_set(p);
|
|
|
|
|
jtag_default_reset_tap(p);
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
/* ------------------------------------------------------------------------- */
|
2013-12-12 11:54:37 +00:00
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
static const struct jtaglib_funcs* get_jlf(struct jtdev *p)
|
2012-10-11 22:33:20 +00:00
|
|
|
|
{
|
2022-07-24 02:29:48 +00:00
|
|
|
|
// FIXME: this function only looks at the chip ID, while the device info DB
|
|
|
|
|
// is more fine-grained about function mapping. so use that instead
|
|
|
|
|
// when possible
|
2013-12-12 11:54:37 +00:00
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
static const struct jtaglib_funcs* lut[] = {
|
|
|
|
|
NULL,
|
|
|
|
|
&jlf_cpu16,
|
|
|
|
|
&jlf_cpux,
|
|
|
|
|
&jlf_cpuxv2
|
|
|
|
|
};
|
2013-12-12 11:54:37 +00:00
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
if (p->cpu_type != 0) {
|
|
|
|
|
if (p->cpu_type < sizeof(lut)/sizeof(*lut)) {
|
|
|
|
|
return lut[p->cpu_type];
|
|
|
|
|
} else {
|
|
|
|
|
printc_err("jtaglib: ERROR: bad CPU type %d\n", p->cpu_type);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (p->jtag_id == 0) {
|
|
|
|
|
printc_err("jtaglib: ERROR: no JTAG ID set!\n");
|
2022-07-24 12:48:10 +00:00
|
|
|
|
__builtin_trap();
|
2022-07-24 02:29:48 +00:00
|
|
|
|
return NULL;
|
2022-07-24 14:30:24 +00:00
|
|
|
|
} else if (JTAG_ID_IS_XV2(p->jtag_id)) {
|
|
|
|
|
return &jlf_cpuxv2;
|
2022-07-24 02:29:48 +00:00
|
|
|
|
} else {
|
2022-07-24 14:30:24 +00:00
|
|
|
|
// Here, it's hard to predict whether the target is CPUX or regular
|
2022-07-24 02:29:48 +00:00
|
|
|
|
// from the JTAG ID alone. However, this is only needed relatively
|
|
|
|
|
// little as the actual MCU ID should be read from info memory
|
2022-07-24 14:30:24 +00:00
|
|
|
|
// after connecting, so let's just assume old here, and add some
|
2022-07-24 02:29:48 +00:00
|
|
|
|
// extra care to the few functions that will be called before the
|
|
|
|
|
// ID readout happens to make it all work
|
2022-07-24 14:30:24 +00:00
|
|
|
|
return &jlf_cpu16;
|
2022-07-24 02:29:48 +00:00
|
|
|
|
}
|
2013-12-12 11:54:37 +00:00
|
|
|
|
}
|
2012-10-11 22:33:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned int jtag_get_device(struct jtdev *p)
|
|
|
|
|
{
|
2022-07-24 02:29:48 +00:00
|
|
|
|
// NOTE: this is one of the special functions that have to be called early
|
|
|
|
|
// on before chip ID stuff is done
|
2013-12-12 11:54:37 +00:00
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
unsigned int r = get_jlf(p)->jlf_get_device(p);
|
2013-12-12 11:54:37 +00:00
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
if (r != 0) jtag_led_green_on(p);
|
2013-12-12 11:54:37 +00:00
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
return r;
|
2012-10-11 22:33:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
/* Reads one byte/word from a given address */
|
|
|
|
|
uint16_t jtag_read_mem(struct jtdev *p, unsigned int format, address_t address)
|
2012-10-11 22:33:20 +00:00
|
|
|
|
{
|
2022-07-24 02:29:48 +00:00
|
|
|
|
// NOTE: this is one of the special functions that have to be called early
|
|
|
|
|
// on before chip ID stuff is done
|
2013-12-12 11:54:37 +00:00
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
return get_jlf(p)->jlf_read_mem(p, format, address);
|
2012-10-11 22:33:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
/* Execute a Power-Up Clear (PUC) using JTAG CNTRL SIG register */
|
|
|
|
|
unsigned int jtag_execute_puc(struct jtdev *p)
|
2012-10-11 22:33:20 +00:00
|
|
|
|
{
|
2022-07-24 02:29:48 +00:00
|
|
|
|
// NOTE: this is one of the special functions that have to be called early
|
|
|
|
|
// on before chip ID stuff is done
|
2013-12-12 11:54:37 +00:00
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
return get_jlf(p)->jlf_execute_puc(p);
|
2012-10-11 22:33:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
/* Reads an array of words from target memory */
|
|
|
|
|
void jtag_read_mem_quick(struct jtdev *p, address_t start_address,
|
|
|
|
|
unsigned int word_count, uint16_t *data)
|
2012-10-11 22:33:20 +00:00
|
|
|
|
{
|
2022-07-24 02:29:48 +00:00
|
|
|
|
get_jlf(p)->jlf_read_mem_quick(p, start_address, word_count, data);
|
2012-10-11 22:33:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
/* Writes one byte/word at a given address */
|
|
|
|
|
void jtag_write_mem(struct jtdev *p, unsigned int format, address_t address,
|
|
|
|
|
uint16_t data)
|
2012-10-11 22:33:20 +00:00
|
|
|
|
{
|
2022-07-24 02:29:48 +00:00
|
|
|
|
get_jlf(p)->jlf_write_mem(p, format, address, data);
|
2012-10-11 22:33:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
/* Writes an array of words into target memory */
|
|
|
|
|
void jtag_write_mem_quick(struct jtdev *p, address_t start_address,
|
|
|
|
|
unsigned int word_count, const uint16_t *data)
|
2012-10-11 22:33:20 +00:00
|
|
|
|
{
|
2022-07-24 02:29:48 +00:00
|
|
|
|
get_jlf(p)->jlf_write_mem_quick(p, start_address, word_count, data);
|
2012-10-11 22:33:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
/* Release the target device from JTAG control */
|
2013-12-12 11:54:37 +00:00
|
|
|
|
void jtag_release_device(struct jtdev *p, address_t address)
|
2012-10-11 22:33:20 +00:00
|
|
|
|
{
|
2013-12-12 11:54:37 +00:00
|
|
|
|
jtag_led_green_off(p);
|
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
get_jlf(p)->jlf_release_device(p, address);
|
2012-10-11 22:33:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-12 11:54:37 +00:00
|
|
|
|
/* Performs a verification over the given memory range
|
|
|
|
|
* return: 1 - verification was successful
|
|
|
|
|
* 0 - otherwise
|
|
|
|
|
*/
|
2022-07-24 02:29:48 +00:00
|
|
|
|
int jtag_verify_mem(struct jtdev *p, address_t start_address,
|
|
|
|
|
unsigned int length, const uint16_t *data)
|
2012-10-11 22:33:20 +00:00
|
|
|
|
{
|
2022-07-24 02:29:48 +00:00
|
|
|
|
return get_jlf(p)->jlf_verify_mem(p, start_address, length, data);
|
2012-10-11 22:33:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-12 11:54:37 +00:00
|
|
|
|
/* Performs an erase check over the given memory range
|
|
|
|
|
* return: 1 - erase check was successful
|
|
|
|
|
* 0 - otherwise
|
|
|
|
|
*/
|
|
|
|
|
int jtag_erase_check(struct jtdev *p,
|
|
|
|
|
address_t start_address,
|
|
|
|
|
unsigned int length)
|
2012-10-11 22:33:20 +00:00
|
|
|
|
{
|
2022-07-24 02:29:48 +00:00
|
|
|
|
return get_jlf(p)->jlf_erase_check(p, start_address, length);
|
2012-10-11 22:33:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
/* Programs/verifies an array of words into a FLASH */
|
|
|
|
|
void jtag_write_flash(struct jtdev *p, address_t start_address,
|
|
|
|
|
unsigned int word_count, const uint16_t *data)
|
2012-10-11 22:33:20 +00:00
|
|
|
|
{
|
2013-12-12 11:54:37 +00:00
|
|
|
|
jtag_led_red_on(p);
|
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
get_jlf(p)->jlf_write_flash(p, start_address, word_count, data);
|
2013-12-12 11:54:37 +00:00
|
|
|
|
|
|
|
|
|
jtag_led_red_off(p);
|
2012-10-11 22:33:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
/* Performs a mass erase or a segment erase of a FLASH module */
|
|
|
|
|
void jtag_erase_flash(struct jtdev *p, unsigned int erase_mode, address_t erase_address)
|
2012-10-11 22:33:20 +00:00
|
|
|
|
{
|
2013-12-12 11:54:37 +00:00
|
|
|
|
jtag_led_red_on(p);
|
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
get_jlf(p)->jlf_erase_flash(p, erase_mode, erase_address);
|
2013-12-12 11:54:37 +00:00
|
|
|
|
|
|
|
|
|
jtag_led_red_off(p);
|
2012-10-11 22:33:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-12 11:54:37 +00:00
|
|
|
|
/* Reads a register from the target CPU */
|
|
|
|
|
address_t jtag_read_reg(struct jtdev *p, int reg)
|
2012-10-11 22:33:20 +00:00
|
|
|
|
{
|
2022-07-24 02:29:48 +00:00
|
|
|
|
return get_jlf(p)->jlf_read_reg(p, reg);
|
2012-10-11 22:33:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-12 11:54:37 +00:00
|
|
|
|
/* Writes a value into a register of the target CPU */
|
|
|
|
|
void jtag_write_reg(struct jtdev *p, int reg, address_t value)
|
2012-10-11 22:33:20 +00:00
|
|
|
|
{
|
2022-07-24 02:29:48 +00:00
|
|
|
|
get_jlf(p)->jlf_write_reg(p, reg, value);
|
|
|
|
|
}
|
|
|
|
|
void jtag_single_step(struct jtdev *p)
|
|
|
|
|
{
|
|
|
|
|
get_jlf(p)->jlf_single_step(p);
|
2015-02-23 22:16:46 +00:00
|
|
|
|
}
|
2022-07-24 02:29:48 +00:00
|
|
|
|
unsigned int jtag_set_breakpoint(struct jtdev *p, int bp_num, address_t bp_addr)
|
|
|
|
|
{
|
|
|
|
|
return get_jlf(p)->jlf_set_breakpoint(p, bp_num, bp_addr);
|
2015-02-23 22:16:46 +00:00
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
}
|
|
|
|
|
unsigned int jtag_cpu_state(struct jtdev *p)
|
2015-02-23 22:16:46 +00:00
|
|
|
|
{
|
2022-07-24 02:29:48 +00:00
|
|
|
|
return get_jlf(p)->jlf_cpu_state(p);
|
|
|
|
|
}
|
|
|
|
|
int jtag_get_config_fuses(struct jtdev *p)
|
|
|
|
|
{
|
2022-07-24 14:30:24 +00:00
|
|
|
|
// NOTE: this is one of the special functions that have to be called early
|
|
|
|
|
// on before chip ID stuff is done
|
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
return get_jlf(p)->jlf_get_config_fuses(p);
|
|
|
|
|
}
|
2015-02-23 22:16:46 +00:00
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
|
|
2022-07-24 12:48:10 +00:00
|
|
|
|
static uint8_t jtag_get_id(struct jtdev *p)
|
|
|
|
|
{
|
|
|
|
|
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
|
|
|
|
|
return jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
/* Take target device under JTAG control.
|
|
|
|
|
* Disable the target watchdog.
|
|
|
|
|
* return: 0 - fuse is blown
|
|
|
|
|
* >0 - jtag id
|
|
|
|
|
*/
|
|
|
|
|
unsigned int jtag_init(struct jtdev *p)
|
|
|
|
|
{
|
2022-07-24 12:48:10 +00:00
|
|
|
|
unsigned int jtag_id, jtag_id_2;
|
2015-02-23 22:16:46 +00:00
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
jtag_init_dap(p);
|
2015-02-23 22:16:46 +00:00
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
/* Check fuse */
|
|
|
|
|
if (jtag_is_fuse_blown(p)) {
|
|
|
|
|
printc_err("jtag_init: fuse is blown\n");
|
2015-02-23 22:16:46 +00:00
|
|
|
|
p->failed = 1;
|
2022-07-24 02:29:48 +00:00
|
|
|
|
return 0;
|
2015-02-23 22:16:46 +00:00
|
|
|
|
}
|
2015-02-23 22:58:40 +00:00
|
|
|
|
|
2022-07-24 12:48:10 +00:00
|
|
|
|
jtag_id = jtag_get_id(p);
|
|
|
|
|
p->jtag_id = jtag_id;
|
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
/* Set device into JTAG mode */
|
2022-07-24 12:48:10 +00:00
|
|
|
|
jtag_id_2 = jtag_get_device(p);
|
|
|
|
|
if (jtag_id_2 == 0) {
|
2022-07-24 02:29:48 +00:00
|
|
|
|
printc_err("jtag_init: invalid jtag_id: 0x%02x\n", jtag_id);
|
2015-02-23 22:58:40 +00:00
|
|
|
|
p->failed = 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2022-07-24 12:48:10 +00:00
|
|
|
|
if (jtag_id != jtag_id_2) {
|
|
|
|
|
printc_err("jtag_init: inconsistent jtag_id: 0x%02x vs 0x%02x\n",
|
|
|
|
|
jtag_id, jtag_id_2);
|
|
|
|
|
p->failed = 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2015-02-23 22:58:40 +00:00
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
/* Perform PUC, includes target watchdog disable */
|
|
|
|
|
if (jtag_execute_puc(p) != jtag_id) {
|
|
|
|
|
printc_err("jtag_init: PUC failed\n");
|
|
|
|
|
p->failed = 1;
|
|
|
|
|
return 0;
|
2015-02-23 22:58:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
return jtag_id;
|
2015-02-23 22:58:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
/* This function checks if the JTAG access security fuse is blown
|
|
|
|
|
* return: 1 - fuse is blown
|
|
|
|
|
* 0 - otherwise
|
|
|
|
|
*/
|
|
|
|
|
int jtag_is_fuse_blown (struct jtdev *p)
|
2015-02-23 22:58:40 +00:00
|
|
|
|
{
|
2022-07-24 02:29:48 +00:00
|
|
|
|
unsigned int loop_counter;
|
2015-02-23 22:58:40 +00:00
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
/* First trial could be wrong */
|
|
|
|
|
for (loop_counter = 3; loop_counter > 0; loop_counter--) {
|
|
|
|
|
jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE);
|
|
|
|
|
if (jtag_dr_shift_16(p, 0xAAAA) == 0x5555)
|
|
|
|
|
/* Fuse is blown */
|
|
|
|
|
return 1;
|
2015-02-23 22:58:40 +00:00
|
|
|
|
}
|
2021-10-09 21:55:43 +00:00
|
|
|
|
|
2022-07-24 02:29:48 +00:00
|
|
|
|
/* Fuse is not blown */
|
|
|
|
|
return 0;
|
2021-10-09 21:55:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
2022-07-24 13:14:27 +00:00
|
|
|
|
int jtag_refresh_bps(device_t dev, struct jtdev *p)
|
2021-10-09 21:55:43 +00:00
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
int ret;
|
|
|
|
|
struct device_breakpoint *bp;
|
|
|
|
|
address_t addr;
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < dev->max_breakpoints; i++) {
|
|
|
|
|
bp = &dev->breakpoints[i];
|
|
|
|
|
|
2022-07-24 13:14:27 +00:00
|
|
|
|
printc_dbg("jtaglib: refresh breakpoint %d: type=%d "
|
|
|
|
|
"addr=%04x flags=%04x\n", i, bp->type, bp->addr, bp->flags);
|
2021-10-09 21:55:43 +00:00
|
|
|
|
|
|
|
|
|
if ( (bp->flags & DEVICE_BP_DIRTY) &&
|
|
|
|
|
(bp->type == DEVICE_BPTYPE_BREAK) ) {
|
|
|
|
|
addr = bp->addr;
|
|
|
|
|
|
|
|
|
|
if ( !(bp->flags & DEVICE_BP_ENABLED) ) {
|
|
|
|
|
addr = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( jtag_set_breakpoint (p, i, addr) == 0) {
|
2022-07-24 13:14:27 +00:00
|
|
|
|
printc_err("jtaglib: failed to refresh breakpoint #%d\n", i);
|
2021-10-09 21:55:43 +00:00
|
|
|
|
ret = -1;
|
|
|
|
|
} else {
|
|
|
|
|
bp->flags &= ~DEVICE_BP_DIRTY;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-06-14 19:28:07 +00:00
|
|
|
|
|
2021-10-09 21:55:43 +00:00
|
|
|
|
return ret;
|
2017-06-14 19:28:07 +00:00
|
|
|
|
}
|
2022-07-24 02:29:48 +00:00
|
|
|
|
|
2022-07-24 13:14:27 +00:00
|
|
|
|
/* ========================================================================= */
|
|
|
|
|
|
|
|
|
|
static int write_ram_word(struct jtdev *p, address_t addr, uint16_t value)
|
|
|
|
|
{
|
|
|
|
|
jtag_write_mem(p, 16, addr, value);
|
|
|
|
|
|
|
|
|
|
return p->failed ? -1 : 0;
|
|
|
|
|
}
|
|
|
|
|
static int write_flash_block(struct jtdev *p, address_t addr,
|
|
|
|
|
address_t len, const uint8_t *data)
|
|
|
|
|
{
|
|
|
|
|
uint16_t* word = malloc( len / 2 * sizeof(*word) );
|
|
|
|
|
if (!word) {
|
|
|
|
|
pr_error("jtaglib: failed to allocate memory");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < len/2; i++) {
|
|
|
|
|
word[i] = data[2*i] + (((uint16_t)data[2*i+1]) << 8);
|
|
|
|
|
}
|
|
|
|
|
jtag_write_flash(p, addr, len/2, word);
|
|
|
|
|
|
|
|
|
|
free(word);
|
|
|
|
|
|
|
|
|
|
return p->failed ? -1 : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int read_words(device_t dev_base, const struct chipinfo_memory *m,
|
|
|
|
|
address_t addr, address_t len, uint8_t *data) {
|
|
|
|
|
struct jtdev *p = (struct jtdev*)dev_base;
|
|
|
|
|
|
|
|
|
|
for (unsigned int index = 0; index < len; index += 2) {
|
|
|
|
|
unsigned int word = jtag_read_mem(p, 16, addr+index);
|
|
|
|
|
data[index ] = word & 0x00ff;
|
|
|
|
|
data[index+1] = (word >> 8) & 0x00ff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return p->failed ? -1 : len;
|
|
|
|
|
}
|
|
|
|
|
static int write_words(device_t dev_base, const struct chipinfo_memory *m,
|
|
|
|
|
address_t addr, address_t len, const uint8_t *data) {
|
|
|
|
|
struct jtdev *p = (struct jtdev*)dev_base;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
if (m->type != CHIPINFO_MEMTYPE_FLASH) {
|
|
|
|
|
len = 2;
|
|
|
|
|
r = write_ram_word(p, addr, r16le(data));
|
|
|
|
|
} else {
|
|
|
|
|
r = write_flash_block(p, addr, len, data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
printc_err("jtaglib: write_words at address 0x%x failed\n", addr);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return len;}
|
|
|
|
|
|
|
|
|
|
int jtag_dev_readmem(device_t dev_base, address_t addr, uint8_t *mem, address_t len) {
|
|
|
|
|
struct jtdev *p = (struct jtdev*)dev_base;
|
|
|
|
|
p->failed = 0;
|
|
|
|
|
return readmem(dev_base, addr, mem, len, read_words);
|
|
|
|
|
}
|
|
|
|
|
int jtag_dev_writemem(device_t dev_base, address_t addr, const uint8_t *mem, address_t len) {
|
|
|
|
|
struct jtdev *p = (struct jtdev*)dev_base;
|
|
|
|
|
p->failed = 0;
|
|
|
|
|
return writemem(dev_base, addr, mem, len, write_words, read_words);
|
|
|
|
|
}
|
|
|
|
|
int jtag_dev_erase(device_t dev_base, device_erase_type_t type, address_t addr) {
|
|
|
|
|
struct jtdev *p = (struct jtdev*)dev_base;
|
|
|
|
|
|
|
|
|
|
p->failed = 0;
|
|
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
|
case DEVICE_ERASE_MAIN:
|
|
|
|
|
jtag_erase_flash(p, JTAG_ERASE_MAIN, addr);
|
|
|
|
|
break;
|
|
|
|
|
case DEVICE_ERASE_ALL:
|
|
|
|
|
jtag_erase_flash(p, JTAG_ERASE_MASS, addr);
|
|
|
|
|
break;
|
|
|
|
|
case DEVICE_ERASE_SEGMENT:
|
|
|
|
|
jtag_erase_flash(p, JTAG_ERASE_SGMT, addr);
|
|
|
|
|
break;
|
|
|
|
|
default: return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return p->failed ? -1 : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int jtag_dev_getregs(device_t dev_base, address_t *regs) {
|
|
|
|
|
struct jtdev *p = (struct jtdev*)dev_base;
|
|
|
|
|
|
|
|
|
|
p->failed = 0;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < DEVICE_NUM_REGS; i++) {
|
|
|
|
|
regs[i] = jtag_read_reg(p, i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return p->failed ? -1 : 0;
|
|
|
|
|
}
|
|
|
|
|
int jtag_dev_setregs(device_t dev_base, const address_t *regs) {
|
|
|
|
|
struct jtdev *p = (struct jtdev*)dev_base;
|
|
|
|
|
|
|
|
|
|
p->failed = 0;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < DEVICE_NUM_REGS; i++) {
|
|
|
|
|
jtag_write_reg(p, i, regs[i]);
|
|
|
|
|
}
|
|
|
|
|
return p->failed ? -1 : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int jtag_dev_ctl(device_t dev_base, device_ctl_t type) {
|
|
|
|
|
struct jtdev *p = (struct jtdev*)dev_base;
|
|
|
|
|
|
|
|
|
|
p->failed = 0;
|
|
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
|
case DEVICE_CTL_RESET:
|
|
|
|
|
/* perform soft reset */
|
|
|
|
|
jtag_execute_puc(p);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DEVICE_CTL_RUN:
|
|
|
|
|
/* transfer changed breakpoints to device */
|
|
|
|
|
if (jtag_refresh_bps(&p->base, p) < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
/* start program execution at current PC */
|
|
|
|
|
jtag_release_device(p, 0xffff);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DEVICE_CTL_HALT:
|
|
|
|
|
/* take device under JTAG control */
|
|
|
|
|
jtag_get_device(p);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DEVICE_CTL_STEP:
|
|
|
|
|
/* execute next instruction at current PC */
|
|
|
|
|
jtag_single_step(p);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
printc_err("mehfet: unsupported operation %d\n", type);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return p->failed ? -1 : 0;
|
|
|
|
|
}
|
|
|
|
|
device_status_t jtag_dev_poll(device_t dev_base) {
|
|
|
|
|
struct jtdev *p = (struct jtdev*)dev_base;
|
|
|
|
|
|
|
|
|
|
if (delay_ms(100) < 0 || ctrlc_check())
|
|
|
|
|
return DEVICE_STATUS_INTR;
|
|
|
|
|
|
|
|
|
|
int r = jtag_cpu_state(p);
|
|
|
|
|
|
|
|
|
|
if (r == 1) return DEVICE_STATUS_HALTED;
|
|
|
|
|
|
|
|
|
|
return DEVICE_STATUS_RUNNING;
|
|
|
|
|
}
|
|
|
|
|
int jtag_dev_getconfigfuses(device_t dev_base) {
|
|
|
|
|
struct jtdev *p = (struct jtdev*)dev_base;
|
|
|
|
|
|
|
|
|
|
return jtag_get_config_fuses(p);
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-24 14:30:24 +00:00
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-24 13:14:27 +00:00
|
|
|
|
int jtag_dev_init(struct jtdev *p) {
|
2022-07-24 14:30:24 +00:00
|
|
|
|
unsigned int jtagid;
|
|
|
|
|
uint32_t dev_id_addr;
|
|
|
|
|
struct chipinfo_id id;
|
|
|
|
|
const struct chipinfo *chip;
|
|
|
|
|
|
|
|
|
|
jtagid = jtag_init(p);
|
2022-07-24 13:14:27 +00:00
|
|
|
|
if (p->failed) return -1;
|
|
|
|
|
|
2022-07-24 14:30:24 +00:00
|
|
|
|
memset(&id, 0, sizeof id);
|
|
|
|
|
|
2022-07-24 13:14:27 +00:00
|
|
|
|
printc("JTAG ID: 0x%02x\n", jtagid);
|
2022-07-24 14:30:24 +00:00
|
|
|
|
|
|
|
|
|
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);
|
2022-07-24 13:14:27 +00:00
|
|
|
|
jtag_release_device(p, 0xfffe);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-24 14:30:24 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-24 13:14:27 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|