diff --git a/drivers/jtaglib.c b/drivers/jtaglib.c index 77ecb19..5616523 100644 --- a/drivers/jtaglib.c +++ b/drivers/jtaglib.c @@ -22,885 +22,962 @@ * 2012-10-03 Peter Bägel (DF5EQ) */ -/*===== includes =============================================================*/ - #include #include "jtaglib.h" #include "output.h" -/* JTAG identification value for all */ -/* existing Flash-based MSP430 devices */ +/* JTAG identification value for all existing Flash-based MSP430 devices + */ #define JTAG_ID 0x89 -/* 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 */ +/* 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 */ /* Instructions for the JTAG data register */ -#define IR_DATA_16BIT 0x82 /* 0x41 */ -#define IR_DATA_CAPTURE 0x42 /* 0x42 */ -#define IR_DATA_QUICK 0xC2 /* 0x43 */ +#define IR_DATA_16BIT 0x82 /* 0x41 */ +#define IR_DATA_CAPTURE 0x42 /* 0x42 */ +#define IR_DATA_QUICK 0xC2 /* 0x43 */ /* Instructions for the JTAG address register */ -#define IR_ADDR_16BIT 0xC1 /* 0x83 */ -#define IR_ADDR_CAPTURE 0x21 /* 0x84 */ -#define IR_DATA_TO_ADDR 0xA1 /* 0x85 */ +#define IR_ADDR_16BIT 0xC1 /* 0x83 */ +#define IR_ADDR_CAPTURE 0x21 /* 0x84 */ +#define IR_DATA_TO_ADDR 0xA1 /* 0x85 */ /* Instructions for the JTAG PSA mode */ -#define IR_DATA_PSA 0x22 /* 0x44 */ -#define IR_SHIFT_OUT_PSA 0x62 /* 0x46 */ +#define IR_DATA_PSA 0x22 /* 0x44 */ +#define IR_SHIFT_OUT_PSA 0x62 /* 0x46 */ /* Instructions for the JTAG Fuse */ -#define IR_PREPARE_BLOW 0x44 /* 0x22 */ -#define IR_EX_BLOW 0x24 /* 0x24 */ +#define IR_PREPARE_BLOW 0x44 /* 0x22 */ +#define IR_EX_BLOW 0x24 /* 0x24 */ /* Bypass instruction */ -#define IR_BYPASS 0xFF /* 0xFF */ +#define IR_BYPASS 0xFF /* 0xFF */ -#define jtag_tms_set(p) jtdev_tms(p, 1) -#define jtag_tms_clr(p) jtdev_tms(p, 0) -#define jtag_tck_set(p) jtdev_tck(p, 1) -#define jtag_tck_clr(p) jtdev_tck(p, 0) -#define jtag_tdi_set(p) jtdev_tdi(p, 1) -#define jtag_tdi_clr(p) jtdev_tdi(p, 0) -#define jtag_tclk_set(p) jtdev_tclk(p, 1) -#define jtag_tclk_clr(p) jtdev_tclk(p, 0) -#define jtag_rst_set(p) jtdev_rst(p, 1) -#define jtag_rst_clr(p) jtdev_rst(p, 0) -#define jtag_tst_set(p) jtdev_tst(p, 1) -#define jtag_tst_clr(p) jtdev_tst(p, 0) +#define jtag_tms_set(p) jtdev_tms(p, 1) +#define jtag_tms_clr(p) jtdev_tms(p, 0) +#define jtag_tck_set(p) jtdev_tck(p, 1) +#define jtag_tck_clr(p) jtdev_tck(p, 0) +#define jtag_tdi_set(p) jtdev_tdi(p, 1) +#define jtag_tdi_clr(p) jtdev_tdi(p, 0) +#define jtag_tclk_set(p) jtdev_tclk(p, 1) +#define jtag_tclk_clr(p) jtdev_tclk(p, 0) +#define jtag_rst_set(p) jtdev_rst(p, 1) +#define jtag_rst_clr(p) jtdev_rst(p, 0) +#define jtag_tst_set(p) jtdev_tst(p, 1) +#define jtag_tst_clr(p) jtdev_tst(p, 0) -#define jtag_led_green_on(p) jtdev_led_green(p, 1) -#define jtag_led_green_off(p) jtdev_led_green(p, 0) -#define jtag_led_red_on(p) jtdev_led_red(p, 1) -#define jtag_led_red_off(p) jtdev_led_red(p, 0) +#define jtag_led_green_on(p) jtdev_led_green(p, 1) +#define jtag_led_green_off(p) jtdev_led_green(p, 0) +#define jtag_led_red_on(p) jtdev_led_red(p, 1) +#define jtag_led_red_off(p) jtdev_led_red(p, 0) -/*----------------------------------------------------------------------------*/ -static void jtag_reset_tap(struct jtdev *p) /* Reset target JTAG interface and perform fuse-HW check */ +static void jtag_reset_tap(struct jtdev *p) { - int loop_counter; + int loop_counter; - 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); + 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); } -/*----------------------------------------------------------------------------*/ +/* This function sets the target JTAG state machine + * back into the Run-Test/Idle state after a shift access + */ static void jtag_tclk_prep (struct jtdev *p) -/* This function sets the target JTAG state machine */ -/* back into the Run-Test/Idle state after a shift access */ { - /* 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 */ + /* 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 */ } -/*----------------------------------------------------------------------------*/ +/* 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 + */ static unsigned int jtag_shift( struct jtdev *p, - unsigned char number_of_bits, + unsigned char num_bits, unsigned int data_out ) -/* shift a value into TDI (MSB first) and simultaneously */ -/* shift out a value from TDO (MSB first) */ -/* number_of_bits: number of bits to shift */ -/* data_out : data to be shifted out */ -/* return : scanned TDO value */ { - unsigned int data_in; - unsigned int mask; - unsigned int tclk_save; + unsigned int data_in; + unsigned int mask; + unsigned int tclk_save; - tclk_save = jtdev_tclk_get(p); + tclk_save = jtdev_tclk_get(p); - data_in = 0; - for (mask = (unsigned int)0x0001 << (number_of_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); - if (jtdev_tdo_get(p) == 1) { - data_in |= mask; - } - } + 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); - jtdev_tclk(p, tclk_save); + if (mask == 1) + jtag_tms_set(p); - /* Set JTAG state back to Run-Test/Idle */ - jtag_tclk_prep(p); - return data_in; + jtag_tck_clr(p); + jtag_tck_set(p); + + if (jtdev_tdo_get(p) == 1) + data_in |= mask; + } + + jtdev_tclk(p, tclk_save); + + /* Set JTAG state back to Run-Test/Idle */ + jtag_tclk_prep(p); + + return data_in; } -/*----------------------------------------------------------------------------*/ +/* 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 + */ static unsigned int jtag_ir_shift(struct jtdev *p, unsigned int instruction) -/* 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 */ { - /* 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) */ - return jtag_shift(p, 8, instruction); - /* JTAG state = Run-Test/Idle */ + /* 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) */ + return jtag_shift(p, 8, instruction); + + /* JTAG state = Run-Test/Idle */ } -/*----------------------------------------------------------------------------*/ -static unsigned int jtag_dr_shift( struct jtdev *p, unsigned int data ) -/* shifts a given 16-bit word into the JTAG data register through TDI. */ -/* data : 16 bit data */ -/* return: scanned TDO value */ +/* Shifts a given 16-bit word into the JTAG data register through TDI. + * data : 16 bit data + * return: scanned TDO value + */ +static unsigned int jtag_dr_shift(struct jtdev *p, unsigned int 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 (16-bit) */ - return jtag_shift(p, 16, data); - /* JTAG state = Run-Test/Idle */ + /* 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) */ + return jtag_shift(p, 16, data); + + /* JTAG state = Run-Test/Idle */ } -/*----------------------------------------------------------------------------*/ +/* Set target CPU JTAG state machine into the instruction fetch state + * return: 1 - instruction fetch was set + * 0 - otherwise + */ static int jtag_set_instruction_fetch(struct jtdev *p) -/* set target CPU JTAG state machine into the instruction fetch state */ -/* return: 1 - instruction fetch was set */ -/* 0 - otherwise */ { - unsigned int loop_counter; + unsigned int loop_counter; - jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE); - /* wait until CPU is in instruction fetch state */ - /* timeout after limited attempts */ - for (loop_counter = 50; loop_counter > 0; loop_counter--) { - if ((jtag_dr_shift(p, 0x0000) & 0x0080) == 0x0080) { - return 1; - } - jtag_tclk_clr(p); /* the TCLK pulse befor jtag_dr_shift leads to */ - jtag_tclk_set(p); /* problems at MEM_QUICK_READ, it's from SLAU265 */ - } - printc_err("jtag_set_instruction_fetch: failed\n"); - p->failed = 1; - return 0; + jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE); + /* Wait until CPU is in instruction fetch state + * timeout after limited attempts + */ + for (loop_counter = 50; loop_counter > 0; loop_counter--) { + if ((jtag_dr_shift(p, 0x0000) & 0x0080) == 0x0080) + return 1; + + jtag_tclk_clr(p); /* The TCLK pulse befor jtag_dr_shift leads to */ + jtag_tclk_set(p); /* problems at MEM_QUICK_READ, it's from SLAU265 */ + } + + printc_err("jtag_set_instruction_fetch: failed\n"); + p->failed = 1; + + return 0; } -/*----------------------------------------------------------------------------*/ +/* Set the CPU into a controlled stop state */ static void jtag_halt_cpu(struct jtdev *p) -/* set the CPU into a controlled stop state */ { - /* set CPU into instruction fetch mode */ - jtag_set_instruction_fetch(p); - /* set device into JTAG mode + read */ - jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); - jtag_dr_shift(p, 0x2401); - /* send JMP $ instruction to keep CPU from changing the state */ - jtag_ir_shift(p, IR_DATA_16BIT); - jtag_dr_shift(p, 0x3FFF); - jtag_tclk_set(p); - jtag_tclk_clr(p); - /* set JTAG_HALT bit */ - jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); - jtag_dr_shift(p, 0x2409); - jtag_tclk_set(p); + /* Set CPU into instruction fetch mode */ + jtag_set_instruction_fetch(p); + + /* Set device into JTAG mode + read */ + jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); + jtag_dr_shift(p, 0x2401); + + /* Send JMP $ instruction to keep CPU from changing the state */ + jtag_ir_shift(p, IR_DATA_16BIT); + jtag_dr_shift(p, 0x3FFF); + jtag_tclk_set(p); + jtag_tclk_clr(p); + + /* Set JTAG_HALT bit */ + jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); + jtag_dr_shift(p, 0x2409); + jtag_tclk_set(p); } -/*----------------------------------------------------------------------------*/ +/* Release the target CPU from the controlled stop state */ static void jtag_release_cpu(struct jtdev *p) -/* release the target CPU from the controlled stop state */ { - jtag_tclk_clr(p); - /* clear the HALT_JTAG bit */ - jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); - jtag_dr_shift(p, 0x2401); - jtag_ir_shift(p, IR_ADDR_CAPTURE); - jtag_tclk_set(p); + jtag_tclk_clr(p); + + /* clear the HALT_JTAG bit */ + jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); + jtag_dr_shift(p, 0x2401); + jtag_ir_shift(p, IR_ADDR_CAPTURE); + jtag_tclk_set(p); } -/*----------------------------------------------------------------------------*/ -static int jtag_verify_psa( struct jtdev *p, - unsigned int start_address, - unsigned int length, - const uint16_t *data ) -/* compares the computed PSA (Pseudo Signature Analysis) value to the PSA */ -/* value shifted out from the target device. It is used for very fast data */ -/* block write or erasure verification. */ -/* start_address: start of data */ -/* length : number of data */ -/* data : pointer to data, 0 for erase check */ -/* RETURN : 1 - comparison was successful */ -/* 0 - otherwise */ +/* Compares the computed PSA (Pseudo Signature Analysis) value to the PSA + * value shifted out from the target device. It is used for very fast data + * block write or erasure verification. + * start_address: start of data + * length : number of data + * data : pointer to data, 0 for erase check + * RETURN : 1 - comparison was successful + * 0 - otherwise + */ +static int jtag_verify_psa(struct jtdev *p, + unsigned int start_address, + unsigned int length, + const uint16_t *data) { - unsigned int psa_value; - unsigned int index; + unsigned int psa_value; + unsigned int index; - /* Polynom value for PSA calculation */ - unsigned int polynom = 0x0805; - /* Start value for PSA calculation */ - unsigned int psa_crc = start_address-2; + /* Polynom value for PSA calculation */ + unsigned int polynom = 0x0805; + /* Start value for PSA calculation */ + unsigned int psa_crc = start_address-2; - jtag_execute_puc(p); - jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); - jtag_dr_shift(p, 0x2401); - jtag_set_instruction_fetch(p); - jtag_ir_shift(p, IR_DATA_16BIT); - jtag_dr_shift(p, 0x4030); - jtag_tclk_set(p); - jtag_tclk_clr(p); - jtag_dr_shift(p, start_address-2); - jtag_tclk_set(p); - jtag_tclk_clr(p); - jtag_tclk_set(p); - jtag_tclk_clr(p); - jtag_tclk_set(p); - jtag_tclk_clr(p); - jtag_ir_shift(p, IR_ADDR_CAPTURE); - jtag_dr_shift(p, 0x0000); - jtag_ir_shift(p, IR_DATA_PSA); - for (index = 0; index < length; index++) { - /* Calculate the PSA value */ - if ((psa_crc & 0x8000) == 0x8000) { - psa_crc ^= polynom; - psa_crc <<= 1; - psa_crc |= 0x0001; - } else { - psa_crc <<= 1; - } - if ( data == 0) { - /* use erase check mask */ - psa_crc ^= 0xFFFF; - } else { - /* use data */ - psa_crc ^= data[index]; - } - /* Clock through the PSA */ - jtag_tclk_set(p); - jtag_tck_clr(p); - jtag_tms_set(p); - jtag_tck_set(p); /* select DR scan */ - jtag_tck_clr(p); - jtag_tms_clr(p); - jtag_tck_set(p); /* capture DR */ - jtag_tck_clr(p); - jtag_tck_set(p); /* shift DR */ - jtag_tck_clr(p); - jtag_tms_set(p); - jtag_tck_set(p); /* exit DR */ - jtag_tck_clr(p); - jtag_tck_set(p); - jtag_tms_clr(p); - jtag_tck_clr(p); - jtag_tck_set(p); - jtag_tclk_clr(p); - } - /* read out the PSA value */ - jtag_ir_shift(p, IR_SHIFT_OUT_PSA); - psa_value = jtag_dr_shift(p, 0x0000); - jtag_tclk_set(p); - return (psa_value == psa_crc) ? 1 : 0; + jtag_execute_puc(p); + jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); + jtag_dr_shift(p, 0x2401); + jtag_set_instruction_fetch(p); + jtag_ir_shift(p, IR_DATA_16BIT); + jtag_dr_shift(p, 0x4030); + jtag_tclk_set(p); + jtag_tclk_clr(p); + jtag_dr_shift(p, start_address-2); + jtag_tclk_set(p); + jtag_tclk_clr(p); + jtag_tclk_set(p); + jtag_tclk_clr(p); + jtag_tclk_set(p); + jtag_tclk_clr(p); + jtag_ir_shift(p, IR_ADDR_CAPTURE); + jtag_dr_shift(p, 0x0000); + jtag_ir_shift(p, IR_DATA_PSA); + + for (index = 0; index < length; index++) { + /* Calculate the PSA value */ + if ((psa_crc & 0x8000) == 0x8000) { + psa_crc ^= polynom; + psa_crc <<= 1; + psa_crc |= 0x0001; + } else + psa_crc <<= 1; + + if (data == 0) + /* use erase check mask */ + psa_crc ^= 0xFFFF; + else + /* use data */ + psa_crc ^= data[index]; + + /* Clock through the PSA */ + jtag_tclk_set(p); + jtag_tck_clr(p); + jtag_tms_set(p); + jtag_tck_set(p); /* Select DR scan */ + jtag_tck_clr(p); + jtag_tms_clr(p); + jtag_tck_set(p); /* Capture DR */ + jtag_tck_clr(p); + jtag_tck_set(p); /* Shift DR */ + jtag_tck_clr(p); + jtag_tms_set(p); + jtag_tck_set(p); /* Exit DR */ + jtag_tck_clr(p); + jtag_tck_set(p); + jtag_tms_clr(p); + jtag_tck_clr(p); + jtag_tck_set(p); + jtag_tclk_clr(p); + } + + /* Read out the PSA value */ + jtag_ir_shift(p, IR_SHIFT_OUT_PSA); + psa_value = jtag_dr_shift(p, 0x0000); + jtag_tclk_set(p); + + return (psa_value == psa_crc) ? 1 : 0; } -/*===== public functions =====================================================*/ - -unsigned int jtag_init (struct jtdev *p) -/* Take target device under JTAG control. */ -/* Disable the target watchdog. */ -/* return: 0 - fuse is blown */ -/* >0 - jtag id */ +/* 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) { - unsigned int jtag_id; + unsigned int jtag_id; - jtag_rst_clr(p); - jtdev_power_on(p); - jtag_tst_set(p); - jtag_tdi_set(p); - jtag_tms_set(p); - jtag_tck_set(p); - jtag_tclk_set(p); - jtag_rst_clr(p); - jtdev_connect(p); - jtag_rst_set(p); - jtag_reset_tap(p); - /* check fuse */ - if (jtag_is_fuse_blown(p)) { - printc_err("jtag_init: fuse is blown\n"); - p->failed = 1; - return 0; - } - /* Set device into JTAG mode */ - jtag_id = jtag_get_device(p); - if ( jtag_id == 0 ) { - printc_err("jtag_init: invalid jtag_id: 0x%02x\n", jtag_id); - p->failed = 1; - return 0; - } - /* 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; - } - return jtag_id; + jtag_rst_clr(p); + jtdev_power_on(p); + jtag_tst_set(p); + jtag_tdi_set(p); + jtag_tms_set(p); + jtag_tck_set(p); + jtag_tclk_set(p); + jtag_rst_clr(p); + jtdev_connect(p); + jtag_rst_set(p); + jtag_reset_tap(p); + + /* Check fuse */ + if (jtag_is_fuse_blown(p)) { + printc_err("jtag_init: fuse is blown\n"); + p->failed = 1; + return 0; + } + + /* Set device into JTAG mode */ + jtag_id = jtag_get_device(p); + if (jtag_id == 0) { + printc_err("jtag_init: invalid jtag_id: 0x%02x\n", jtag_id); + p->failed = 1; + return 0; + } + + /* 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; + } + + return jtag_id; } -/*----------------------------------------------------------------------------*/ unsigned int jtag_get_device(struct jtdev *p) { - unsigned int jtag_id = 0; - unsigned int loop_counter; + unsigned int jtag_id = 0; + unsigned int loop_counter; - /* Set device into JTAG mode + read */ - jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); - jtag_dr_shift(p, 0x2401); - /* Wait until CPU is synchronized, */ - /* timeout after a limited number of attempts */ - jtag_id = jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE); - for ( loop_counter = 50; - loop_counter > 0 && ((jtag_dr_shift(p, 0x0000) & 0x0200) != 0x0200); - loop_counter--); - if (loop_counter == 0){ - printc_err("jtag_get_device: timed out\n"); - p->failed = 1; - /* timeout reached */ - return 0; - } - jtag_led_green_on(p); - return jtag_id; + /* Set device into JTAG mode + read */ + jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); + jtag_dr_shift(p, 0x2401); + + /* Wait until CPU is synchronized, + * timeout after a limited number of attempts + */ + jtag_id = jtag_ir_shift(p, IR_CNTRL_SIG_CAPTURE); + for (loop_counter = 50; + loop_counter > 0 && ((jtag_dr_shift(p, 0x0000) & 0x0200) != 0x0200); + loop_counter--); + + if (loop_counter == 0) { + printc_err("jtag_get_device: timed out\n"); + p->failed = 1; + /* timeout reached */ + return 0; + } + + jtag_led_green_on(p); + return jtag_id; } -/*----------------------------------------------------------------------------*/ +/* Read the target chip id. + * return: chip id + */ unsigned int jtag_chip_id(struct jtdev *p) -/* Read the target chip id. */ -/* return: chip id */ { - unsigned short chip_id; + 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; + /* 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; } -/*----------------------------------------------------------------------------*/ -uint16_t jtag_read_mem( struct jtdev *p, - unsigned int format, - address_t address ) -/* reads one byte/word from a given address */ -/* format : 8-byte, 16-word */ -/* address: address of memory */ -/* return : content of memory */ +/* Reads one byte/word from a given address + * format : 8-byte, 16-word + * address: address of memory + * return : content of memory + */ +uint16_t jtag_read_mem(struct jtdev *p, + unsigned int format, + address_t address) { - uint16_t content; + uint16_t content; - jtag_halt_cpu(p); - jtag_tclk_clr(p); - jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); - if (format == 16) { - /* set word read */ - jtag_dr_shift(p, 0x2409); - } - else { - /* set byte read */ - jtag_dr_shift(p, 0x2419); - } - /* set address */ - jtag_ir_shift(p, IR_ADDR_16BIT); - jtag_dr_shift(p, address); - jtag_ir_shift(p, IR_DATA_TO_ADDR); - jtag_tclk_set(p); - jtag_tclk_clr(p); - /* shift out 16 bits */ - content = jtag_dr_shift(p, 0x0000); - jtag_tclk_set(p); /* is also the first instruction in jtag_release_cpu() */ - jtag_release_cpu(p); - if (format == 8) { - content &= 0x00ff; - } - return content; + jtag_halt_cpu(p); + jtag_tclk_clr(p); + jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); + if (format == 16) { + /* set word read */ + jtag_dr_shift(p, 0x2409); + } else { + /* set byte read */ + jtag_dr_shift(p, 0x2419); + } + /* set address */ + jtag_ir_shift(p, IR_ADDR_16BIT); + jtag_dr_shift(p, address); + jtag_ir_shift(p, IR_DATA_TO_ADDR); + jtag_tclk_set(p); + jtag_tclk_clr(p); + + /* shift out 16 bits */ + content = jtag_dr_shift(p, 0x0000); + jtag_tclk_set(p); /* is also the first instruction in jtag_release_cpu() */ + jtag_release_cpu(p); + if (format == 8) + content &= 0x00ff; + + return content; } -/*----------------------------------------------------------------------------*/ -void jtag_read_mem_quick( struct jtdev *p, +/* Reads an array of words from target memory + * address: address to read from + * length : number of word to read + * data : memory to write to + */ +void jtag_read_mem_quick(struct jtdev *p, + address_t address, + unsigned int length, + uint16_t *data) +{ + unsigned int index; + + /* Initialize reading: */ + jtag_write_reg(p, 0,address-4); + jtag_halt_cpu(p); + jtag_tclk_clr(p); + + /* set RW to read */ + jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); + jtag_dr_shift(p, 0x2409); + jtag_ir_shift(p, IR_DATA_QUICK); + + for (index = 0; index < length; index++) { + jtag_tclk_set(p); + jtag_tclk_clr(p); + /* shift out the data from the target */ + data[index] = jtag_dr_shift(p, 0x0000); + } + + jtag_tclk_set(p); + jtag_release_cpu(p); +} + +/* Writes one byte/word at a given address + * format : 8-byte, 16-word + * address: address to be written + * data : data to write + */ +void jtag_write_mem(struct jtdev *p, + unsigned int format, + address_t address, + uint16_t data) +{ + jtag_halt_cpu(p); + jtag_tclk_clr(p); + jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); + + if (format == 16) + /* Set word write */ + jtag_dr_shift(p, 0x2408); + else + /* Set byte write */ + jtag_dr_shift(p, 0x2418); + + jtag_ir_shift(p, IR_ADDR_16BIT); + + /* Set addr */ + jtag_dr_shift(p, address); + jtag_ir_shift(p, IR_DATA_TO_ADDR); + + /* Shift in 16 bits */ + jtag_dr_shift(p, data); + jtag_tclk_set(p); + jtag_release_cpu(p); +} + +/* Writes an array of words into target memory + * address: address to write to + * length : number of word to write + * data : data to write + */ +void jtag_write_mem_quick(struct jtdev *p, address_t address, unsigned int length, - uint16_t *data ) -/* reads an array of words from target memory */ -/* address: address to read from */ -/* length : number of word to read */ -/* data : memory to write to */ + const uint16_t *data) { - unsigned int index; + unsigned int index; - /* Initialize reading: */ - jtag_write_reg(p, 0,address-4); - jtag_halt_cpu(p); - jtag_tclk_clr(p); - /* set RW to read */ - jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); - jtag_dr_shift(p, 0x2409); - jtag_ir_shift(p, IR_DATA_QUICK); - for (index = 0; index < length; index++) { - jtag_tclk_set(p); - jtag_tclk_clr(p); - /* shift out the data from the target */ - data[index] = jtag_dr_shift(p, 0x0000); - } - jtag_tclk_set(p); - jtag_release_cpu(p); + /* Initialize writing */ + jtag_write_reg(p, 0, address-4); + jtag_halt_cpu(p); + jtag_tclk_clr(p); + jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); + + /* Set RW to write */ + jtag_dr_shift(p, 0x2408); + jtag_ir_shift(p, IR_DATA_QUICK); + + for (index = 0; index < length; index++) { + /* Write data */ + jtag_dr_shift(p, data[index]); + + /* Increment PC by 2 */ + jtag_tclk_set(p); + jtag_tclk_clr(p); + } + + jtag_tclk_set(p); + jtag_release_cpu(p); } -/*----------------------------------------------------------------------------*/ -void jtag_write_mem( struct jtdev *p, - unsigned int format, - address_t address, - uint16_t data ) -/* writes one byte/word at a given address */ -/* format : 8-byte, 16-word */ -/* address: address to be written */ -/* data : data to write */ -{ - jtag_halt_cpu(p); - jtag_tclk_clr(p); - jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); - if (format == 16) { - /* set word write */ - jtag_dr_shift(p, 0x2408); - } - else { - /* set byte write */ - jtag_dr_shift(p, 0x2418); - } - jtag_ir_shift(p, IR_ADDR_16BIT); - /* set addr */ - jtag_dr_shift(p, address); - jtag_ir_shift(p, IR_DATA_TO_ADDR); - /* shift in 16 bits */ - jtag_dr_shift(p, data); - jtag_tclk_set(p); - jtag_release_cpu(p); -} - -/*----------------------------------------------------------------------------*/ -void jtag_write_mem_quick( struct jtdev *p, - address_t address, - unsigned int length, - const uint16_t *data ) -/* writes an array of words into target memory */ -/* address: address to write to */ -/* length : number of word to write */ -/* data : data to write */ -{ - unsigned int index; - - /* Initialize writing: */ - jtag_write_reg(p, 0, address-4); - jtag_halt_cpu(p); - jtag_tclk_clr(p); - jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); - /* set RW to write */ - jtag_dr_shift(p, 0x2408); - jtag_ir_shift(p, IR_DATA_QUICK); - for (index = 0; index < length; index++) { - /* write data */ - jtag_dr_shift(p, data[index]); - /* increment PC by 2 */ - jtag_tclk_set(p); - jtag_tclk_clr(p); - } - jtag_tclk_set(p); - jtag_release_cpu(p); -} - -/*----------------------------------------------------------------------------*/ +/* 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) -/* This function checks if the JTAG access security fuse is blown */ -/* return: 1 - fuse is blown */ -/* 0 - otherwise */ { - unsigned int loop_counter; + unsigned int loop_counter; - /* 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(p, 0xAAAA) == 0x5555) { - /* Fuse is blown */ - return 1; - } - } - /* fuse is not blown */ - return 0; + /* 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(p, 0xAAAA) == 0x5555) + /* Fuse is blown */ + return 1; + } + + /* Fuse is not blown */ + return 0; } -/*----------------------------------------------------------------------------*/ +/* Execute a Power-Up Clear (PUC) using JTAG CNTRL SIG register + * return: JTAG ID + */ unsigned int jtag_execute_puc(struct jtdev *p) -/* execute a Power-Up Clear (PUC) using JTAG CNTRL SIG register */ -/* return: JTAG ID */ { - unsigned int jtag_id; + unsigned int jtag_id; - jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); - /* apply and remove reset */ - jtag_dr_shift(p, 0x2C01); - jtag_dr_shift(p, 0x2401); - jtag_tclk_clr(p); - jtag_tclk_set(p); - jtag_tclk_clr(p); - jtag_tclk_set(p); - jtag_tclk_clr(p); - jtag_tclk_set(p); - /* read jtag id */ - jtag_id = jtag_ir_shift(p, IR_ADDR_CAPTURE); - /* disable watchdog on target device */ - jtag_write_mem(p, 16, 0x0120, 0x5A80); - return jtag_id; + jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); + + /* Apply and remove reset */ + jtag_dr_shift(p, 0x2C01); + jtag_dr_shift(p, 0x2401); + jtag_tclk_clr(p); + jtag_tclk_set(p); + jtag_tclk_clr(p); + jtag_tclk_set(p); + jtag_tclk_clr(p); + jtag_tclk_set(p); + + /* Read jtag id */ + jtag_id = jtag_ir_shift(p, IR_ADDR_CAPTURE); + + /* Disable watchdog on target device */ + jtag_write_mem(p, 16, 0x0120, 0x5A80); + + return jtag_id; } -/*----------------------------------------------------------------------------*/ -void jtag_release_device( struct jtdev *p, address_t address ) -/* release the target device from JTAG control */ -/* address: 0xFFFE - perform Reset, */ -/* load Reset Vector into PC */ -/* 0xFFFF - start execution at current */ -/* PC position */ -/* other - load Address into PC */ +/* Release the target device from JTAG control + * address: 0xFFFE - perform Reset, + * load Reset Vector into PC + * 0xFFFF - start execution at current + * PC position + * other - load Address into PC + */ +void jtag_release_device(struct jtdev *p, address_t address) { - jtag_led_green_off(p); - switch (address) { - case 0xffff: /* nothing to do */ - break; - case 0xfffe: /* perform reset */ - jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); - jtag_dr_shift(p, 0x2C01); - jtag_dr_shift(p, 0x2401); - break; - default: /* set target CPU's PC */ - jtag_write_reg(p, 0, address); - break; - } - jtag_ir_shift(p, IR_CNTRL_SIG_RELEASE); + jtag_led_green_off(p); + + switch (address) { + case 0xffff: /* Nothing to do */ + break; + case 0xfffe: /* Perform reset */ + jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); + jtag_dr_shift(p, 0x2C01); + jtag_dr_shift(p, 0x2401); + break; + default: /* Set target CPU's PC */ + jtag_write_reg(p, 0, address); + break; + } + + jtag_ir_shift(p, IR_CNTRL_SIG_RELEASE); } -/*----------------------------------------------------------------------------*/ -int jtag_verify_mem( struct jtdev *p, +/* Performs a verification over the given memory range + * return: 1 - verification was successful + * 0 - otherwise + */ +int jtag_verify_mem(struct jtdev *p, + address_t start_address, + unsigned int length, + const uint16_t *data) +{ + return jtag_verify_psa(p, start_address, length, data); +} + +/* 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, - const uint16_t *data ) -/* performs a verification over the given memory range */ -/* return: 1 - verification was successful */ -/* 0 - otherwise */ + unsigned int length) { - return jtag_verify_psa( p, start_address, length, data ); + return jtag_verify_psa(p, start_address, length, NULL); } -/*----------------------------------------------------------------------------*/ -int jtag_erase_check( struct jtdev *p, +/* Programs/verifies an array of words into a FLASH by using the + * FLASH controller. The JTAG FLASH register isn't needed. + * start_address: start in FLASH + * length : number of words + * data : pointer to data + */ +void jtag_write_flash(struct jtdev *p, address_t start_address, - unsigned int length ) -/* performs an erase check over the given memory range */ -/* return: 1 - erase check was successful */ -/* 0 - otherwise */ + unsigned int length, + const uint16_t *data) { - return jtag_verify_psa (p, start_address, length, NULL); + unsigned int index; + unsigned int address; + + jtag_led_red_on(p); + + address = start_address; + jtag_halt_cpu(p); + jtag_tclk_clr(p); + + /* Set RW to write */ + jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); + jtag_dr_shift(p, 0x2408); + + /* FCTL1 register */ + jtag_ir_shift(p, IR_ADDR_16BIT); + jtag_dr_shift(p, 0x0128); + + /* Enable FLASH write */ + jtag_ir_shift(p, IR_DATA_TO_ADDR); + jtag_dr_shift(p, 0xA540); + jtag_tclk_set(p); + jtag_tclk_clr(p); + + /* FCTL2 register */ + jtag_ir_shift(p, IR_ADDR_16BIT); + jtag_dr_shift(p, 0x012A); + + /* Select MCLK as source, DIV=1 */ + jtag_ir_shift(p, IR_DATA_TO_ADDR); + jtag_dr_shift(p, 0xA540); + jtag_tclk_set(p); + jtag_tclk_clr(p); + + /* FCTL3 register */ + jtag_ir_shift(p, IR_ADDR_16BIT); + jtag_dr_shift(p, 0x012C); + + /* Clear FCTL3 register */ + jtag_ir_shift(p, IR_DATA_TO_ADDR); + jtag_dr_shift(p, 0xA500); + jtag_tclk_set(p); + jtag_tclk_clr(p); + + for (index = 0; index < length; index++) { + /* Set RW to write */ + jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); + jtag_dr_shift(p, 0x2408); + + /* Set address */ + jtag_ir_shift(p, IR_ADDR_16BIT); + jtag_dr_shift(p, address); + + /* Set data */ + jtag_ir_shift(p, IR_DATA_TO_ADDR); + jtag_dr_shift(p, data[index]); + jtag_tclk_set(p); + jtag_tclk_clr(p); + + /* Set RW to read */ + jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); + jtag_dr_shift(p, 0x2409); + + /* provide TCLKs + * min. 33 for F149 and F449 + */ + jtdev_tclk_strobe(p, 35); + address += 2; + + if (p->failed) + break; + } + + /* Set RW to write */ + jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); + jtag_dr_shift(p, 0x2408); + + /* FCTL1 register */ + jtag_ir_shift(p, IR_ADDR_16BIT); + jtag_dr_shift(p, 0x0128); + + /* Disable FLASH write */ + jtag_ir_shift(p, IR_DATA_TO_ADDR); + jtag_dr_shift(p, 0xA500); + jtag_tclk_set(p); + jtag_release_cpu(p); + + jtag_led_red_off(p); } -/*----------------------------------------------------------------------------*/ -void jtag_write_flash( struct jtdev *p, - address_t start_address, - unsigned int length, - const uint16_t *data ) -/* programs/verifies an array of words into a FLASH by using the */ -/* FLASH controller. The JTAG FLASH register isn't needed. */ -/* start_address: start in FLASH */ -/* length : number of words */ -/* data : pointer to data */ +/* Performs a mass erase (with and w/o info memory) or a segment erase of a + * FLASH module specified by the given mode and address. Large memory devices + * get additional mass erase operations to meet the spec. + * erase_mode : ERASE_MASS, ERASE_MAIN, ERASE_SGMT + * erase_address: address within the selected segment + */ +void jtag_erase_flash(struct jtdev *p, + unsigned int erase_mode, + address_t erase_address) { - unsigned int index; - unsigned int address; + unsigned int number_of_strobes = 4820; /* default for segment erase */ + unsigned int loop_counter; + unsigned int max_loop_count = 1; /* erase cycle repeating for mass erase */ - jtag_led_red_on(p); + jtag_led_red_on(p); - address = start_address; - jtag_halt_cpu(p); - jtag_tclk_clr(p); - /* set RW to write */ - jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); - jtag_dr_shift(p, 0x2408); - /* FCTL1 register */ - jtag_ir_shift(p, IR_ADDR_16BIT); - jtag_dr_shift(p, 0x0128); - /* enable FLASH write */ - jtag_ir_shift(p, IR_DATA_TO_ADDR); - jtag_dr_shift(p, 0xA540); - jtag_tclk_set(p); - jtag_tclk_clr(p); - /* FCTL2 register */ - jtag_ir_shift(p, IR_ADDR_16BIT); - jtag_dr_shift(p, 0x012A); - /* select MCLK as source, DIV=1 */ - jtag_ir_shift(p, IR_DATA_TO_ADDR); - jtag_dr_shift(p, 0xA540); - jtag_tclk_set(p); - jtag_tclk_clr(p); - /* FCTL3 register */ - jtag_ir_shift(p, IR_ADDR_16BIT); - jtag_dr_shift(p, 0x012C); - /* clear FCTL3 register */ - jtag_ir_shift(p, IR_DATA_TO_ADDR); - jtag_dr_shift(p, 0xA500); - jtag_tclk_set(p); - jtag_tclk_clr(p); - for (index = 0; index < length; index++) { - /* set RW to write */ - jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); - jtag_dr_shift(p, 0x2408); - /* set address */ - jtag_ir_shift(p, IR_ADDR_16BIT); - jtag_dr_shift(p, address); - /* set data */ - jtag_ir_shift(p, IR_DATA_TO_ADDR); - jtag_dr_shift(p, data[index]); - jtag_tclk_set(p); - jtag_tclk_clr(p); - /* set RW to read */ - jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); - jtag_dr_shift(p, 0x2409); - /* provide TCLKs */ - /* min. 33 for F149 and F449 */ - jtdev_tclk_strobe(p, 35); - address += 2; + if ((erase_mode == JTAG_ERASE_MASS) || + (erase_mode == JTAG_ERASE_MAIN)) { + number_of_strobes = 5300; /* Larger Flash memories require */ + max_loop_count = 19; /* additional cycles for erase. */ + erase_address = 0xfffe; /* overwrite given address */ + } - if (p->failed) - break; - } - /* set RW to write */ - jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); - jtag_dr_shift(p, 0x2408); - /* FCTL1 register */ - jtag_ir_shift(p, IR_ADDR_16BIT); - jtag_dr_shift(p, 0x0128); - /* disable FLASH write */ - jtag_ir_shift(p, IR_DATA_TO_ADDR); - jtag_dr_shift(p, 0xA500); - jtag_tclk_set(p); - jtag_release_cpu(p); + for (loop_counter = max_loop_count; loop_counter > 0; loop_counter--) { + jtag_halt_cpu(p); + jtag_tclk_clr(p); - jtag_led_red_off(p); + /* Set RW to write */ + jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); + jtag_dr_shift(p, 0x2408); + + /* FCTL1 address */ + jtag_ir_shift(p, IR_ADDR_16BIT); + jtag_dr_shift(p, 0x0128); + + /* Enable erase mode */ + jtag_ir_shift(p, IR_DATA_TO_ADDR); + jtag_dr_shift(p, erase_mode); + jtag_tclk_set(p); + jtag_tclk_clr(p); + + /* FCTL2 address */ + jtag_ir_shift(p, IR_ADDR_16BIT); + jtag_dr_shift(p, 0x012A); + + /* MCLK is source, DIV=1 */ + jtag_ir_shift(p, IR_DATA_TO_ADDR); + jtag_dr_shift(p, 0xA540); + jtag_tclk_set(p); + jtag_tclk_clr(p); + + /* FCTL3 address */ + jtag_ir_shift(p, IR_ADDR_16BIT); + jtag_dr_shift(p, 0x012C); + + /* Clear FCTL3 */ + jtag_ir_shift(p, IR_DATA_TO_ADDR); + jtag_dr_shift(p, 0xA500); + jtag_tclk_set(p); + jtag_tclk_clr(p); + + /* Set erase address */ + jtag_ir_shift(p, IR_ADDR_16BIT); + jtag_dr_shift(p, erase_address); + + /* Dummy write to start erase */ + jtag_ir_shift(p, IR_DATA_TO_ADDR); + jtag_dr_shift(p, 0x55AA); + jtag_tclk_set(p); + jtag_tclk_clr(p); + + /* Set RW to read */ + jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); + jtag_dr_shift(p, 0x2409); + + /* provide TCLKs */ + jtdev_tclk_strobe(p, number_of_strobes); + + /* Set RW to write */ + jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); + jtag_dr_shift(p, 0x2408); + + /* FCTL1 address */ + jtag_ir_shift(p, IR_ADDR_16BIT); + jtag_dr_shift(p, 0x0128); + + /* Disable erase */ + jtag_ir_shift(p, IR_DATA_TO_ADDR); + jtag_dr_shift(p, 0xA500); + jtag_tclk_set(p); + jtag_release_cpu(p); + } + + jtag_led_red_off(p); } -/*----------------------------------------------------------------------------*/ -void jtag_erase_flash( struct jtdev *p, unsigned int erase_mode, - address_t erase_address ) -/* performs a mass erase (with and w/o info memory) or a segment erase of a */ -/* FLASH module specified by the given mode and address. Large memory devices */ -/* get additional mass erase operations to meet the spec. */ -/* erase_mode : ERASE_MASS, ERASE_MAIN, ERASE_SGMT */ -/* erase_address: address within the selected segment */ +/* Reads a register from the target CPU */ +address_t jtag_read_reg(struct jtdev *p, int reg) { - unsigned int number_of_strobes = 4820; /* default for segment erase */ - unsigned int loop_counter; - unsigned int max_loop_count = 1; /* erase cycle repeating for mass erase */ + unsigned int value; - jtag_led_red_on(p); + /* CPU controls RW & BYTE */ + jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); + jtag_dr_shift(p, 0x3401); - if ((erase_mode == JTAG_ERASE_MASS) || - (erase_mode == JTAG_ERASE_MAIN)) { - number_of_strobes = 5300; /* Larger Flash memories require */ - max_loop_count = 19; /* additional cycles for erase. */ - erase_address = 0xfffe; /* overwrite given address */ - } - for (loop_counter = max_loop_count; loop_counter > 0; loop_counter--) { - jtag_halt_cpu(p); - jtag_tclk_clr(p); - /* set RW to write */ - jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); - jtag_dr_shift(p, 0x2408); - /* FCTL1 address */ - jtag_ir_shift(p, IR_ADDR_16BIT); - jtag_dr_shift(p, 0x0128); - /* enable erase mode */ - jtag_ir_shift(p, IR_DATA_TO_ADDR); - jtag_dr_shift(p, erase_mode); - jtag_tclk_set(p); - jtag_tclk_clr(p); - /* FCTL2 address */ - jtag_ir_shift(p, IR_ADDR_16BIT); - jtag_dr_shift(p, 0x012A); - /* MCLK is source, DIV=1 */ - jtag_ir_shift(p, IR_DATA_TO_ADDR); - jtag_dr_shift(p, 0xA540); - jtag_tclk_set(p); - jtag_tclk_clr(p); - /* FCTL3 address */ - jtag_ir_shift(p, IR_ADDR_16BIT); - jtag_dr_shift(p, 0x012C); - /* clear FCTL3 */ - jtag_ir_shift(p, IR_DATA_TO_ADDR); - jtag_dr_shift(p, 0xA500); - jtag_tclk_set(p); - jtag_tclk_clr(p); - /* set erase address */ - jtag_ir_shift(p, IR_ADDR_16BIT); - jtag_dr_shift(p, erase_address); - /* dummy write to start erase */ - jtag_ir_shift(p, IR_DATA_TO_ADDR); - jtag_dr_shift(p, 0x55AA); - jtag_tclk_set(p); - jtag_tclk_clr(p); - /* set RW to read */ - jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); - jtag_dr_shift(p, 0x2409); - /* provide TCLKs */ - jtdev_tclk_strobe(p, number_of_strobes); - /* set RW to write */ - jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); - jtag_dr_shift(p, 0x2408); - /* FCTL1 address */ - jtag_ir_shift(p, IR_ADDR_16BIT); - jtag_dr_shift(p, 0x0128); - /* disable erase */ - jtag_ir_shift(p, IR_DATA_TO_ADDR); - jtag_dr_shift(p, 0xA500); - jtag_tclk_set(p); - jtag_release_cpu(p); - } - jtag_led_red_off(p); + /* Set CPU into instruction fetch mode */ + jtag_set_instruction_fetch(p); + + jtag_ir_shift(p, IR_DATA_16BIT); + /* "sub #8,PC" instruction + * PC - 8 -> PC + * PC is advanced 4 bytes by this instruction + * needs 3 clock cycles + */ + jtag_dr_shift(p, 0x8030); + jtag_tclk_set(p); + jtag_tclk_clr(p); + jtag_dr_shift(p, 0x0008); + jtag_tclk_set(p); + jtag_tclk_clr(p); + jtag_tclk_set(p); + jtag_tclk_clr(p); + + /* "mov Rn,&0x01fe" instruction + * Rn -> &0x01fe + * PC is advanced 4 bytes by this instruction + * needs 4 clock cycles + * it's a ROM address, write has no effect, but + * the registers value is placed on the databus + */ + jtag_dr_shift(p, 0x4082 | (((unsigned int)reg << 8) & 0x0f00) ); + jtag_tclk_set(p); + jtag_tclk_clr(p); + jtag_dr_shift(p, 0x01fe); + jtag_tclk_set(p); + jtag_tclk_clr(p); + jtag_tclk_set(p); + jtag_tclk_clr(p); + jtag_tclk_set(p); + jtag_tclk_clr(p); + + /* Read databus which contains the registers value */ + jtag_ir_shift(p, IR_DATA_CAPTURE); + value = jtag_dr_shift(p, 0x0000); + + /* JTAG controls RW & BYTE */ + jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); + jtag_dr_shift(p, 0x2401); + + /* Return value read from register */ + return value; } -/*----------------------------------------------------------------------------*/ -address_t jtag_read_reg( struct jtdev *p, int reg ) -/* reads a register from the target CPU */ +/* Writes a value into a register of the target CPU */ +void jtag_write_reg(struct jtdev *p, int reg, address_t value) { - unsigned int value; + /* CPU controls RW & BYTE */ + jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); + jtag_dr_shift(p, 0x3401); - /* CPU controls RW & BYTE */ - jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); - jtag_dr_shift(p, 0x3401); + /* Set CPU into instruction fetch mode */ + jtag_set_instruction_fetch(p); - /* set CPU into instruction fetch mode */ - jtag_set_instruction_fetch(p); + jtag_ir_shift(p, IR_DATA_16BIT); + /* "sub #8,PC" instruction + * PC-8 -> PC + * PC is advanced 4 bytes by this instruction + * needs 3 clock cycles + */ + jtag_dr_shift(p, 0x8030); + jtag_tclk_set(p); + jtag_tclk_clr(p); + jtag_dr_shift(p, 0x0008); + jtag_tclk_set(p); + jtag_tclk_clr(p); + jtag_tclk_set(p); + jtag_tclk_clr(p); - jtag_ir_shift(p, IR_DATA_16BIT); - /* "sub #8,PC" instruction */ - /* PC - 8 -> PC */ - /* PC is advanced 4 bytes by this instruction */ - /* needs 3 clock cycles */ - jtag_dr_shift(p, 0x8030); - jtag_tclk_set(p); - jtag_tclk_clr(p); - jtag_dr_shift(p, 0x0008); - jtag_tclk_set(p); - jtag_tclk_clr(p); - jtag_tclk_set(p); - jtag_tclk_clr(p); - /* "mov Rn,&0x01fe" instruction */ - /* Rn -> &0x01fe */ - /* PC is advanced 4 bytes by this instruction */ - /* needs 4 clock cycles */ - /* it's a ROM address, write has no effect, but */ - /* the registers value is placed on the databus */ - jtag_dr_shift(p, 0x4082 | (((unsigned int)reg << 8) & 0x0f00) ); - jtag_tclk_set(p); - jtag_tclk_clr(p); - jtag_dr_shift(p, 0x01fe); - jtag_tclk_set(p); - jtag_tclk_clr(p); - jtag_tclk_set(p); - jtag_tclk_clr(p); - jtag_tclk_set(p); - jtag_tclk_clr(p); + /* "mov #value,Rn" instruction + * value -> Rn + * PC is advanced 4 bytes by this instruction + * needs 2 clock cycles + */ + jtag_dr_shift(p, 0x4030 | (reg & 0x000f) ); + jtag_tclk_set(p); + jtag_tclk_clr(p); + jtag_dr_shift(p, reg==0 ? value-4 : value ); + jtag_tclk_set(p); + jtag_tclk_clr(p); - /* read databus which contains the registers value */ - jtag_ir_shift(p, IR_DATA_CAPTURE); - value = jtag_dr_shift(p, 0x0000); - - /* JTAG controls RW & BYTE */ - jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); - jtag_dr_shift(p, 0x2401); - - /* return value read from register */ - return value; + /* JTAG controls RW & BYTE */ + jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); + jtag_dr_shift(p, 0x2401); } - -/*----------------------------------------------------------------------------*/ -void jtag_write_reg( struct jtdev *p, int reg, address_t value ) -/* writes a value into a register of the target CPU */ -{ - /* CPU controls RW & BYTE */ - jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); - jtag_dr_shift(p, 0x3401); - - /* set CPU into instruction fetch mode */ - jtag_set_instruction_fetch(p); - - jtag_ir_shift(p, IR_DATA_16BIT); - /* "sub #8,PC" instruction */ - /* PC-8 -> PC */ - /* PC is advanced 4 bytes by this instruction */ - /* needs 3 clock cycles */ - jtag_dr_shift(p, 0x8030); - jtag_tclk_set(p); - jtag_tclk_clr(p); - jtag_dr_shift(p, 0x0008); - jtag_tclk_set(p); - jtag_tclk_clr(p); - jtag_tclk_set(p); - jtag_tclk_clr(p); - /* "mov #value,Rn" instruction */ - /* value -> Rn */ - /* PC is advanced 4 bytes by this instruction */ - /* needs 2 clock cycles */ - jtag_dr_shift(p, 0x4030 | (reg & 0x000f) ); - jtag_tclk_set(p); - jtag_tclk_clr(p); - jtag_dr_shift(p, reg==0 ? value-4 : value ); - jtag_tclk_set(p); - jtag_tclk_clr(p); - - /* JTAG controls RW & BYTE */ - jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); - jtag_dr_shift(p, 0x2401); -} - diff --git a/drivers/jtaglib.h b/drivers/jtaglib.h index 6ef0167..47645c3 100644 --- a/drivers/jtaglib.h +++ b/drivers/jtaglib.h @@ -26,44 +26,81 @@ #define JTAGLIB_H_ #include + #include "jtdev.h" #include "util.h" -/*===== public symbols ====================================================== */ - -/* flash erasing modes */ +/* Flash erasing modes */ #define JTAG_ERASE_MASS 0xA506 #define JTAG_ERASE_MAIN 0xA504 #define JTAG_ERASE_SGMT 0xA502 -/*===== public functions =====================================================*/ +/* Take target device under JTAG control. */ +unsigned int jtag_init(struct jtdev *p); -unsigned int jtag_init (struct jtdev *p); -unsigned int jtag_get_device (struct jtdev *p); -unsigned int jtag_chip_id (struct jtdev *p); -uint16_t jtag_read_mem (struct jtdev *p, unsigned int format, - address_t address); -void jtag_read_mem_quick (struct jtdev *p, address_t start_address, - unsigned int word_count, uint16_t *data); -void jtag_write_mem (struct jtdev *p, unsigned int format, - address_t address, uint16_t data); -void jtag_write_mem_quick(struct jtdev *p, address_t start_address, - unsigned int word_count, - const uint16_t *data); -int jtag_is_fuse_blown (struct jtdev *p); -unsigned int jtag_execute_puc (struct jtdev *p); -void jtag_release_device (struct jtdev *p, address_t address); -int jtag_verify_mem (struct jtdev *p, address_t start_address, - unsigned int word_count, - const uint16_t *data); -int jtag_erase_check (struct jtdev *p, address_t start_address, - unsigned int word_count); -void jtag_write_flash (struct jtdev *p, address_t start_address, - unsigned int word_count, - const uint16_t *data); -void jtag_erase_flash (struct jtdev *p, unsigned int erase_mode, - address_t erase_address); -address_t jtag_read_reg (struct jtdev *p, int reg); -void jtag_write_reg (struct jtdev *p, int reg, address_t value); +unsigned int jtag_get_device(struct jtdev *p); + +/* Read the target chip id. */ +unsigned int jtag_chip_id(struct jtdev *p); + +/* Reads one byte/word from a given address */ +uint16_t jtag_read_mem(struct jtdev *p, + unsigned int format, + address_t address); + +/* 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); + +/* Writes one byte/word at a given address */ +void jtag_write_mem(struct jtdev *p, + unsigned int format, + address_t address, + uint16_t data); + +/* 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); + +/* This function checks if the JTAG access security fuse is blown */ +int jtag_is_fuse_blown(struct jtdev *p); + +/* Execute a Power-Up Clear (PUC) using JTAG CNTRL SIG register */ +unsigned int jtag_execute_puc(struct jtdev *p); + +/* Release the target device from JTAG control */ +void jtag_release_device(struct jtdev *p, address_t address); + +/* Performs a verification over the given memory range */ +int jtag_verify_mem(struct jtdev *p, + address_t start_address, + unsigned int word_count, + const uint16_t *data); + +/* Performs an erase check over the given memory range */ +int jtag_erase_check(struct jtdev *p, + address_t start_address, + unsigned int word_count); + +/* 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); + +/* 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); + +/* Reads a register from the target CPU */ +address_t jtag_read_reg(struct jtdev *p, int reg); + +/* Writes a value into a register of the target CPU */ +void jtag_write_reg(struct jtdev *p, int reg, address_t value); #endif