ULINK driver: Implement variable TCK frequency in OpenULINK firmware
[openocd.git] / src / jtag / drivers / OpenULINK / src / jtag.c
index cf126ed274344859986e98155e0391630adb8fbe..812d4f73a8cdfbbb0aa0163fb30900ad22373011 100644 (file)
 
 #include <stdbool.h>
 
-/** 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;
@@ -114,6 +122,93 @@ 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.
  *
@@ -121,6 +216,8 @@ void jtag_scan_in(u8 out_offset, u8 in_offset)
  * 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)
@@ -193,6 +290,93 @@ 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.
  *
@@ -200,6 +384,8 @@ void jtag_scan_out(u8 out_offset)
  * 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)
@@ -291,27 +477,155 @@ 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;
 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)