From 6446dbaacbf7c0607ea571ed7f5a4f32745544eb Mon Sep 17 00:00:00 2001 From: =?utf8?q?Martin=20Schm=C3=B6lzer?= Date: Mon, 4 Jul 2011 19:03:29 +0200 Subject: [PATCH] ULINK driver: Implement variable TCK frequency in OpenULINK firmware MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Also, speed up jtag_clock_tck() significantly (150 kHz -> 375 kHz) Signed-off-by: Martin Schmölzer --- src/jtag/drivers/OpenULINK/include/jtag.h | 14 +- src/jtag/drivers/OpenULINK/include/msgtypes.h | 25 +- src/jtag/drivers/OpenULINK/src/jtag.c | 370 ++++++++++++++++++++++++-- src/jtag/drivers/OpenULINK/src/protocol.c | 33 +++ 4 files changed, 408 insertions(+), 34 deletions(-) diff --git a/src/jtag/drivers/OpenULINK/include/jtag.h b/src/jtag/drivers/OpenULINK/include/jtag.h index 93ecfb0a9..cef5f426a 100644 --- a/src/jtag/drivers/OpenULINK/include/jtag.h +++ b/src/jtag/drivers/OpenULINK/include/jtag.h @@ -26,21 +26,23 @@ #define NOP {__asm nop __endasm;} void jtag_scan_in(u8 out_offset, u8 in_offset); +void jtag_slow_scan_in(u8 out_offset, u8 in_offset); + void jtag_scan_out(u8 out_offset); -void jtag_scan_io(u8 out_offset, u8 in_offset); +void jtag_slow_scan_out(u8 out_offset); -void jtag_slow_scan_in(u8 scan_size_bytes, u8 tdo_index, u8 scan_options); -void jtag_slow_scan_out(u8 scan_size_bytes, u8 tdi_index, u8 scan_options); -void jtag_slow_scan_io(u8 scan_size_bytes, u8 tdi_index, u8 tdo_index, - u8 scan_options); +void jtag_scan_io(u8 out_offset, u8 in_offset); +void jtag_slow_scan_io(u8 out_offset, u8 in_offset); void jtag_clock_tck(u16 count); +void jtag_slow_clock_tck(u16 count); void jtag_clock_tms(u8 count, u8 sequence); void jtag_slow_clock_tms(u8 count, u8 sequence); u16 jtag_get_signals(void); void jtag_set_signals(u8 low, u8 high); -void jtag_configure_tck_delay(u8 scan, u8 tck, u8 tms); +void jtag_configure_tck_delay(u8 scan_in, u8 scan_out, u8 scan_io, u8 tck, + u8 tms); #endif diff --git a/src/jtag/drivers/OpenULINK/include/msgtypes.h b/src/jtag/drivers/OpenULINK/include/msgtypes.h index e3afb670f..cb356128a 100644 --- a/src/jtag/drivers/OpenULINK/include/msgtypes.h +++ b/src/jtag/drivers/OpenULINK/include/msgtypes.h @@ -75,7 +75,7 @@ * offset 1: tms_count * * offset 2: tms_sequence * **************************************************************************** - * CMD_CLOCK_TCK: * + * CMD_CLOCK_TCK, CMD_SLOW_CLOCK_TCK: * * * * OUT: * * offset 1: low byte of tck_count * @@ -108,9 +108,11 @@ * CMD_CONFIGURE_TCK_FREQ: * * * * OUT: * - * offset 1: delay value for scan functions * - * offset 2: delay value for clock_tck function * - * offset 3: delay value for clock_tms function * + * offset 1: delay value for scan_in function * + * offset 2: delay value for scan_out function * + * offset 3: delay value for scan_io function * + * offset 4: delay value for clock_tck function * + * offset 5: delay value for clock_tms function * **************************************************************************** * CMD_SET_LEDS: * * * @@ -155,13 +157,14 @@ #define CMD_CLOCK_TMS 0x20 #define CMD_SLOW_CLOCK_TMS 0x21 #define CMD_CLOCK_TCK 0x22 -#define CMD_SLEEP_US 0x23 -#define CMD_SLEEP_MS 0x24 -#define CMD_GET_SIGNALS 0x25 -#define CMD_SET_SIGNALS 0x26 -#define CMD_CONFIGURE_TCK_FREQ 0x27 -#define CMD_SET_LEDS 0x28 -#define CMD_TEST 0x29 +#define CMD_SLOW_CLOCK_TCK 0x23 +#define CMD_SLEEP_US 0x24 +#define CMD_SLEEP_MS 0x25 +#define CMD_GET_SIGNALS 0x26 +#define CMD_SET_SIGNALS 0x27 +#define CMD_CONFIGURE_TCK_FREQ 0x28 +#define CMD_SET_LEDS 0x29 +#define CMD_TEST 0x2A /* JTAG signal definition for jtag_get_signals() -- Input signals! */ #define SIGNAL_TDO (1<<0) diff --git a/src/jtag/drivers/OpenULINK/src/jtag.c b/src/jtag/drivers/OpenULINK/src/jtag.c index cf126ed27..812d4f73a 100644 --- a/src/jtag/drivers/OpenULINK/src/jtag.c +++ b/src/jtag/drivers/OpenULINK/src/jtag.c @@ -26,10 +26,16 @@ #include -/** Delay value for SCAN operations with less than maximum TCK frequency */ -u8 delay_scan = 0; +/** Delay value for SCAN_IN operations with less than maximum TCK frequency */ +u8 delay_scan_in = 0; -/** Delay value for CLOCK_TCK operations */ +/** Delay value for SCAN_OUT operations with less than maximum TCK frequency */ +u8 delay_scan_out = 0; + +/** Delay value for SCAN_IO operations with less than maximum TCK frequency */ +u8 delay_scan_io = 0; + +/** Delay value for CLOCK_TCK operations with less than maximum frequency */ u8 delay_tck = 0; /** Delay value for CLOCK_TMS operations with less than maximum frequency */ @@ -41,6 +47,8 @@ u8 delay_tms = 0; * Dummy data is shifted into the JTAG chain via TDI, TDO data is sampled and * stored in the EP2 IN buffer. * + * Maximum achievable TCK frequency is 182 kHz for ULINK clocked at 24 MHz. + * * @param out_offset offset in OUT2BUF where payload data starts */ void jtag_scan_in(u8 out_offset, u8 in_offset) @@ -72,8 +80,8 @@ void jtag_scan_in(u8 out_offset, u8 in_offset) for (j = 0; j < 8; j++) { OUTB = outb_buffer; /* TCK changes here */ - OUTB = (outb_buffer | PIN_TCK); tdo_data = tdo_data >> 1; + OUTB = (outb_buffer | PIN_TCK); if (GET_TDO()) { tdo_data |= 0x80; @@ -96,8 +104,8 @@ void jtag_scan_in(u8 out_offset, u8 in_offset) } OUTB = outb_buffer; /* TCK change here */ - OUTB = (outb_buffer | PIN_TCK); tdo_data = tdo_data >> 1; + OUTB = (outb_buffer | PIN_TCK); if (GET_TDO()) { tdo_data |= 0x80; @@ -115,12 +123,101 @@ void jtag_scan_in(u8 out_offset, u8 in_offset) } /** + * Perform JTAG SCAN-IN operation at variable TCK frequency. + * + * Dummy data is shifted into the JTAG chain via TDI, TDO data is sampled and + * stored in the EP2 IN buffer. + * + * Maximum achievable TCK frequency is 113 kHz for ULINK clocked at 24 MHz. + * + * @param out_offset offset in OUT2BUF where payload data starts + */ +void jtag_slow_scan_in(u8 out_offset, u8 in_offset) +{ + u8 scan_size_bytes, bits_last_byte; + u8 tms_count_start, tms_count_end; + u8 tms_sequence_start, tms_sequence_end; + u8 tdo_data, i, j, k; + + u8 outb_buffer; + + /* Get parameters from OUT2BUF */ + scan_size_bytes = OUT2BUF[out_offset]; + bits_last_byte = OUT2BUF[out_offset + 1]; + tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F; + tms_count_end = OUT2BUF[out_offset + 2] & 0x0F; + tms_sequence_start = OUT2BUF[out_offset + 3]; + tms_sequence_end = OUT2BUF[out_offset + 4]; + + if (tms_count_start > 0) { + jtag_slow_clock_tms(tms_count_start, tms_sequence_start); + } + + outb_buffer = OUTB & ~(PIN_TDI | PIN_TCK | PIN_TMS); + + /* Shift all bytes except the last byte */ + for (i = 0; i < scan_size_bytes - 1; i++) { + tdo_data = 0; + + for (j = 0; j < 8; j++) { + OUTB = outb_buffer; /* TCK changes here */ + for (k = 0; k < delay_scan_in; k++); + tdo_data = tdo_data >> 1; + + OUTB = (outb_buffer | PIN_TCK); + for (k = 0; k < delay_scan_in; k++); + + if (GET_TDO()) { + tdo_data |= 0x80; + } + } + + /* Copy TDO data to IN2BUF */ + IN2BUF[i + in_offset] = tdo_data; + } + + tdo_data = 0; + + /* Shift the last byte */ + for (j = 0; j < bits_last_byte; j++) { + /* Assert TMS signal if requested and this is the last bit */ + if ((j == bits_last_byte - 1) && (tms_count_end > 0)) { + outb_buffer |= PIN_TMS; + tms_count_end--; + tms_sequence_end = tms_sequence_end >> 1; + } + + OUTB = outb_buffer; /* TCK change here */ + for (k = 0; k < delay_scan_in; k++); + tdo_data = tdo_data >> 1; + + OUTB = (outb_buffer | PIN_TCK); + for (k = 0; k < delay_scan_in; k++); + + if (GET_TDO()) { + tdo_data |= 0x80; + } + } + tdo_data = tdo_data >> (8 - bits_last_byte); + + /* Copy TDO data to IN2BUF */ + IN2BUF[i + in_offset] = tdo_data; + + /* Move to correct end state */ + if (tms_count_end > 0) { + jtag_slow_clock_tms(tms_count_end, tms_sequence_end); + } +} + +/** * Perform JTAG SCAN-OUT operation at maximum TCK frequency. * * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO * data is not sampled. * The TAP-FSM state is alyways left in the PAUSE-DR/PAUSE-IR state. * + * Maximum achievable TCK frequency is 142 kHz for ULINK clocked at 24 MHz. + * * @param out_offset offset in OUT2BUF where payload data starts */ void jtag_scan_out(u8 out_offset) @@ -194,12 +291,101 @@ void jtag_scan_out(u8 out_offset) } /** + * Perform JTAG SCAN-OUT operation at maximum TCK frequency. + * + * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO + * data is not sampled. + * The TAP-FSM state is alyways left in the PAUSE-DR/PAUSE-IR state. + * + * Maximum achievable TCK frequency is 97 kHz for ULINK clocked at 24 MHz. + * + * @param out_offset offset in OUT2BUF where payload data starts + */ +void jtag_slow_scan_out(u8 out_offset) +{ + u8 scan_size_bytes, bits_last_byte; + u8 tms_count_start, tms_count_end; + u8 tms_sequence_start, tms_sequence_end; + u8 tdi_data, i, j, k; + + u8 outb_buffer; + + /* Get parameters from OUT2BUF */ + scan_size_bytes = OUT2BUF[out_offset]; + bits_last_byte = OUT2BUF[out_offset + 1]; + tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F; + tms_count_end = OUT2BUF[out_offset + 2] & 0x0F; + tms_sequence_start = OUT2BUF[out_offset + 3]; + tms_sequence_end = OUT2BUF[out_offset + 4]; + + if (tms_count_start > 0) { + jtag_slow_clock_tms(tms_count_start, tms_sequence_start); + } + + outb_buffer = OUTB & ~(PIN_TCK | PIN_TMS); + + /* Shift all bytes except the last byte */ + for (i = 0; i < scan_size_bytes - 1; i++) { + tdi_data = OUT2BUF[i + out_offset + 5]; + + for (j = 0; j < 8; j++) { + if (tdi_data & 0x01) { + outb_buffer |= PIN_TDI; + } + else { + outb_buffer &= ~PIN_TDI; + } + + OUTB = outb_buffer; /* TDI and TCK change here */ + for (k = 0; k < delay_scan_out; k++); + tdi_data = tdi_data >> 1; + + OUTB = (outb_buffer | PIN_TCK); + for (k = 0; k < delay_scan_out; k++); + } + } + + tdi_data = OUT2BUF[i + out_offset + 5]; + + /* Shift the last byte */ + for (j = 0; j < bits_last_byte; j++) { + if (tdi_data & 0x01) { + outb_buffer |= PIN_TDI; + } + else { + outb_buffer &= ~PIN_TDI; + } + + /* Assert TMS signal if requested and this is the last bit */ + if ((j == bits_last_byte - 1) && (tms_count_end > 0)) { + outb_buffer |= PIN_TMS; + tms_count_end--; + tms_sequence_end = tms_sequence_end >> 1; + } + + OUTB = outb_buffer; /* TDI and TCK change here */ + for (k = 0; k < delay_scan_out; k++); + tdi_data = tdi_data >> 1; + + OUTB = (outb_buffer | PIN_TCK); + for (k = 0; k < delay_scan_out; k++); + } + + /* Move to correct end state */ + if (tms_count_end > 0) { + jtag_slow_clock_tms(tms_count_end, tms_sequence_end); + } +} + +/** * Perform bidirectional JTAG SCAN operation at maximum TCK frequency. * * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO * data is sampled and stored in the EP2 IN buffer. * The TAP-FSM state is alyways left in the PAUSE-DR/PAUSE-IR state. * + * Maximum achievable TCK frequency is 100 kHz for ULINK clocked at 24 MHz. + * * @param out_offset offset in OUT2BUF where payload data starts */ void jtag_scan_io(u8 out_offset, u8 in_offset) @@ -292,26 +478,154 @@ void jtag_scan_io(u8 out_offset, u8 in_offset) } /** + * Perform bidirectional JTAG SCAN operation at maximum TCK frequency. + * + * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO + * data is sampled and stored in the EP2 IN buffer. + * The TAP-FSM state is alyways left in the PAUSE-DR/PAUSE-IR state. + * + * Maximum achievable TCK frequency is 78 kHz for ULINK clocked at 24 MHz. + * + * @param out_offset offset in OUT2BUF where payload data starts + */ +void jtag_slow_scan_io(u8 out_offset, u8 in_offset) +{ + u8 scan_size_bytes, bits_last_byte; + u8 tms_count_start, tms_count_end; + u8 tms_sequence_start, tms_sequence_end; + u8 tdi_data, tdo_data, i, j, k; + + u8 outb_buffer; + + /* Get parameters from OUT2BUF */ + scan_size_bytes = OUT2BUF[out_offset]; + bits_last_byte = OUT2BUF[out_offset + 1]; + tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F; + tms_count_end = OUT2BUF[out_offset + 2] & 0x0F; + tms_sequence_start = OUT2BUF[out_offset + 3]; + tms_sequence_end = OUT2BUF[out_offset + 4]; + + if (tms_count_start > 0) { + jtag_slow_clock_tms(tms_count_start, tms_sequence_start); + } + + outb_buffer = OUTB & ~(PIN_TCK | PIN_TMS); + + /* Shift all bytes except the last byte */ + for (i = 0; i < scan_size_bytes - 1; i++) { + tdi_data = OUT2BUF[i + out_offset + 5]; + tdo_data = 0; + + for (j = 0; j < 8; j++) { + if (tdi_data & 0x01) { + outb_buffer |= PIN_TDI; + } + else { + outb_buffer &= ~PIN_TDI; + } + + OUTB = outb_buffer; /* TDI and TCK change here */ + for (k = 0; k < delay_scan_io; k++); + tdi_data = tdi_data >> 1; + + OUTB = (outb_buffer | PIN_TCK); + for (k = 0; k < delay_scan_io; k++); + tdo_data = tdo_data >> 1; + + if (GET_TDO()) { + tdo_data |= 0x80; + } + } + + /* Copy TDO data to IN2BUF */ + IN2BUF[i + in_offset] = tdo_data; + } + + tdi_data = OUT2BUF[i + out_offset + 5]; + tdo_data = 0; + + /* Shift the last byte */ + for (j = 0; j < bits_last_byte; j++) { + if (tdi_data & 0x01) { + outb_buffer |= PIN_TDI; + } + else { + outb_buffer &= ~PIN_TDI; + } + + /* Assert TMS signal if requested and this is the last bit */ + if ((j == bits_last_byte - 1) && (tms_count_end > 0)) { + outb_buffer |= PIN_TMS; + tms_count_end--; + tms_sequence_end = tms_sequence_end >> 1; + } + + OUTB = outb_buffer; /* TDI and TCK change here */ + for (k = 0; k < delay_scan_io; k++); + tdi_data = tdi_data >> 1; + + OUTB = (outb_buffer | PIN_TCK); + for (k = 0; k < delay_scan_io; k++); + tdo_data = tdo_data >> 1; + + if (GET_TDO()) { + tdo_data |= 0x80; + } + } + tdo_data = tdo_data >> (8 - bits_last_byte); + + /* Copy TDO data to IN2BUF */ + IN2BUF[i + in_offset] = tdo_data; + + /* Move to correct end state */ + if (tms_count_end > 0) { + jtag_slow_clock_tms(tms_count_end, tms_sequence_end); + } +} + +/** * Generate TCK clock cycles. * + * Maximum achievable TCK frequency is 375 kHz for ULINK clocked at 24 MHz. + * * @param count number of TCK clock cyclces to generate. */ void jtag_clock_tck(u16 count) { u16 i; - u8 j; + u8 outb_buffer = OUTB & ~(PIN_TCK); for ( i = 0; i < count; i++ ) { - SET_TCK_LOW(); - for(j = 0; j < delay_tck; j++); + OUTB = outb_buffer; + OUTB = outb_buffer | PIN_TCK; + } +} + +/** + * Generate TCK clock cycles at variable frequency. + * + * Maximum achieveable TCK frequency is 166.6 kHz for ULINK clocked at 24 MHz. + * + * @param count number of TCK clock cyclces to generate. + */ +void jtag_slow_clock_tck(u16 count) +{ + u16 i; + u8 j; + u8 outb_buffer = OUTB & ~(PIN_TCK); - SET_TCK_HIGH(); - for(j = 0; j < delay_tck; j++); + for ( i = 0; i < count; i++ ) { + OUTB = outb_buffer; + for (j = 0; j < delay_tck; j++); + OUTB = outb_buffer | PIN_TCK; + for (j = 0; j < delay_tck; j++); } } /** - * Perform TAP-FSM state transitions at maximum TCK frequency. + * Perform TAP FSM state transitions at maximum TCK frequency. + * + * Maximum achievable TCK frequency is 176 kHz for ULINK clocked at 24 MHz. * * @param count the number of state transitions to perform. * @param sequence the TMS pin levels for each state transition, starting with @@ -319,11 +633,9 @@ void jtag_clock_tck(u16 count) */ void jtag_clock_tms(u8 count, u8 sequence) { - volatile u8 outb_buffer; + u8 outb_buffer = OUTB & ~(PIN_TCK); u8 i; - outb_buffer = OUTB & ~(PIN_TCK); - for ( i = 0; i < count; i++ ) { /* Set TMS pin according to sequence parameter */ if ( sequence & 0x1 ) { @@ -342,13 +654,32 @@ void jtag_clock_tms(u8 count, u8 sequence) /** * Perform TAP-FSM state transitions at less than maximum TCK frequency. * + * Maximum achievable TCK frequency is 117 kHz for ULINK clocked at 24 MHz. + * * @param count the number of state transitions to perform. * @param sequence the TMS pin levels for each state transition, starting with * the least-significant bit. */ void jtag_slow_clock_tms(u8 count, u8 sequence) { + u8 outb_buffer = OUTB & ~(PIN_TCK); + u8 i, j; + + for (i = 0; i < count; i++) { + /* Set TMS pin according to sequence parameter */ + if ( sequence & 0x1 ) { + outb_buffer |= PIN_TMS; + } + else { + outb_buffer &= ~PIN_TMS; + } + OUTB = outb_buffer; + for (j = 0; j < delay_tms; j++); + sequence = sequence >> 1; + OUTB = outb_buffer | PIN_TCK; + for (j = 0; j < delay_tms; j++); + } } /** @@ -402,13 +733,18 @@ void jtag_set_signals(u8 low, u8 high) /** * Configure TCK delay parameters. * - * @param scan number of delay cycles in shift operations. + * @param scan_in number of delay cycles in scan_in operations. + * @param scan_out number of delay cycles in scan_out operations. + * @param scan_io number of delay cycles in scan_io operations. * @param tck number of delay cycles in clock_tck operations. * @param tms number of delay cycles in clock_tms operations. */ -void jtag_configure_tck_delay(u8 scan, u8 tck, u8 tms) +void jtag_configure_tck_delay(u8 scan_in, u8 scan_out, u8 scan_io, u8 tck, + u8 tms) { - delay_scan = scan; + delay_scan_in = scan_in; + delay_scan_out = scan_out; + delay_scan_io = scan_io; delay_tck = tck; delay_tms = tms; } diff --git a/src/jtag/drivers/OpenULINK/src/protocol.c b/src/jtag/drivers/OpenULINK/src/protocol.c index 05929d0f9..6e33ec711 100644 --- a/src/jtag/drivers/OpenULINK/src/protocol.c +++ b/src/jtag/drivers/OpenULINK/src/protocol.c @@ -121,6 +121,30 @@ bool execute_command(void) count |= ((u16)OUT2BUF[cmd_id_index + 2]) << 8; jtag_clock_tck(count); break; + case CMD_SLOW_SCAN_IN: + usb_out_bytecount = 5; + usb_in_bytecount = OUT2BUF[cmd_id_index + 1]; + jtag_slow_scan_in(cmd_id_index + 1, payload_index_in); + break; + case CMD_SLOW_SCAN_OUT: + usb_out_bytecount = OUT2BUF[cmd_id_index + 1] + 5; + jtag_slow_scan_out(cmd_id_index + 1); + break; + case CMD_SLOW_SCAN_IO: + usb_in_bytecount = OUT2BUF[cmd_id_index + 1]; + usb_out_bytecount = usb_in_bytecount + 5; + jtag_slow_scan_io(cmd_id_index + 1, payload_index_in); + break; + case CMD_SLOW_CLOCK_TMS: + usb_out_bytecount = 2; + jtag_slow_clock_tms(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]); + break; + case CMD_SLOW_CLOCK_TCK: + usb_out_bytecount = 2; + count = (u16)OUT2BUF[cmd_id_index + 1]; + count |= ((u16)OUT2BUF[cmd_id_index + 2]) << 8; + jtag_slow_clock_tck(count); + break; case CMD_SLEEP_US: usb_out_bytecount = 2; count = (u16)OUT2BUF[cmd_id_index + 1]; @@ -144,6 +168,15 @@ bool execute_command(void) usb_out_bytecount = 2; jtag_set_signals(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]); break; + case CMD_CONFIGURE_TCK_FREQ: + usb_out_bytecount = 5; + jtag_configure_tck_delay( + OUT2BUF[cmd_id_index + 1], /* scan_in */ + OUT2BUF[cmd_id_index + 2], /* scan_out */ + OUT2BUF[cmd_id_index + 3], /* scan_io */ + OUT2BUF[cmd_id_index + 4], /* clock_tck */ + OUT2BUF[cmd_id_index + 5]); /* clock_tms */ + break; case CMD_SET_LEDS: usb_out_bytecount = 1; execute_set_led_command(); -- 2.11.4.GIT