aboutsummaryrefslogtreecommitdiff
path: root/contrib/firmware/angie/c/src/protocol.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/firmware/angie/c/src/protocol.c')
-rw-r--r--contrib/firmware/angie/c/src/protocol.c189
1 files changed, 189 insertions, 0 deletions
diff --git a/contrib/firmware/angie/c/src/protocol.c b/contrib/firmware/angie/c/src/protocol.c
new file mode 100644
index 0000000..3f3aaaf
--- /dev/null
+++ b/contrib/firmware/angie/c/src/protocol.c
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/****************************************************************************
+ File : protocol.c *
+ Contents : Jtag commands handling protocol code for NanoXplore *
+ USB-JTAG ANGIE adapter hardware. *
+ Based on openULINK project code by: Martin Schmoelzer. *
+ Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. *
+ <aboudjelida@nanoxplore.com> *
+ <ahmederrachedbjld@gmail.com> *
+*****************************************************************************/
+
+#include "usb.h"
+#include "protocol.h"
+#include "jtag.h"
+#include "delay.h"
+#include "io.h"
+#include "msgtypes.h"
+#include "reg_ezusb.h"
+#include <serial.h>
+#include <stdio.h>
+
+/** Index in EP1 Bulk-OUT data buffer that contains the current command ID */
+volatile uint8_t cmd_id_index;
+
+/** Number of data bytes already in EP1 Bulk-IN buffer */
+volatile uint8_t payload_index_in;
+
+/**
+ * Executes one command and updates global command indexes.
+ *
+ * @return true if this command was the last command.
+ * @return false if there are more commands within the current contents of the
+ * Bulk EP1-OUT data buffer.
+ */
+bool execute_command(void)
+{
+ uint8_t usb_out_bytecount, usb_in_bytecount;
+ uint16_t signal_state = 0;
+ uint16_t count;
+
+ /* Most commands do not transfer IN data. To save code space, we write 0 to
+ * usb_in_bytecount here, then modify it in the switch statement below where
+ * necessary */
+ usb_in_bytecount = 0;
+
+ switch (EP1OUTBUF[cmd_id_index] /* Command ID */) {
+ case CMD_SCAN_IN:
+ usb_out_bytecount = 5;
+ usb_in_bytecount = EP1OUTBUF[cmd_id_index + 1];
+ jtag_scan_in((cmd_id_index + 1), payload_index_in);
+ break;
+ case CMD_SCAN_OUT:
+ usb_out_bytecount = EP1OUTBUF[cmd_id_index + 1] + 5;
+ jtag_scan_out(cmd_id_index + 1);
+ break;
+ case CMD_SCAN_IO:
+ usb_in_bytecount = EP1OUTBUF[cmd_id_index + 1];
+ usb_out_bytecount = usb_in_bytecount + 5;
+ jtag_scan_io((cmd_id_index + 1), payload_index_in);
+ break;
+ case CMD_CLOCK_TMS:
+ usb_out_bytecount = 2;
+ jtag_clock_tms(EP1OUTBUF[cmd_id_index + 1], EP1OUTBUF[cmd_id_index + 2]);
+ break;
+ case CMD_CLOCK_TCK:
+ usb_out_bytecount = 2;
+ count = (uint16_t)EP1OUTBUF[cmd_id_index + 1];
+ count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8;
+ jtag_clock_tck(count);
+ break;
+ case CMD_SLOW_SCAN_IN:
+ usb_out_bytecount = 5;
+ usb_in_bytecount = EP1OUTBUF[cmd_id_index + 1];
+ jtag_slow_scan_in(cmd_id_index + 1, payload_index_in);
+ break;
+ case CMD_SLOW_SCAN_OUT:
+ usb_out_bytecount = EP1OUTBUF[cmd_id_index + 1] + 5;
+ jtag_slow_scan_out(cmd_id_index + 1);
+ break;
+ case CMD_SLOW_SCAN_IO:
+ usb_in_bytecount = EP1OUTBUF[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(EP1OUTBUF[cmd_id_index + 1], EP1OUTBUF[cmd_id_index + 2]);
+ break;
+ case CMD_SLOW_CLOCK_TCK:
+ usb_out_bytecount = 2;
+ count = (uint16_t)EP1OUTBUF[cmd_id_index + 1];
+ count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8;
+ jtag_slow_clock_tck(count);
+ break;
+ case CMD_SLEEP_US:
+ usb_out_bytecount = 2;
+ count = (uint16_t)EP1OUTBUF[cmd_id_index + 1];
+ count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8;
+ delay_us(count);
+ break;
+ case CMD_SLEEP_MS:
+ usb_out_bytecount = 2;
+ count = (uint16_t)EP1OUTBUF[cmd_id_index + 1];
+ count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8;
+ delay_ms(count);
+ break;
+ case CMD_GET_SIGNALS:
+ usb_out_bytecount = 0;
+ usb_in_bytecount = 2;
+ signal_state = jtag_get_signals();
+ EP1INBUF[payload_index_in] = (signal_state >> 8);
+ EP1INBUF[payload_index_in + 1] = (signal_state & 0xFF);
+ break;
+ case CMD_SET_SIGNALS:
+ usb_out_bytecount = 2;
+ jtag_set_signals(EP1OUTBUF[cmd_id_index + 1], EP1OUTBUF[cmd_id_index + 2]);
+ break;
+ case CMD_CONFIGURE_TCK_FREQ:
+ usb_out_bytecount = 5;
+ jtag_configure_tck_delay(EP1OUTBUF[cmd_id_index + 1], /* scan_in */
+ EP1OUTBUF[cmd_id_index + 2], /* scan_out */
+ EP1OUTBUF[cmd_id_index + 3], /* scan_io */
+ EP1OUTBUF[cmd_id_index + 4], /* clock_tck */
+ EP1OUTBUF[cmd_id_index + 5]); /* clock_tms */
+ break;
+ case CMD_TEST:
+ usb_out_bytecount = 1;
+ /* Do nothing... This command is only used to test if the device is ready
+ * to accept new commands */
+ break;
+ default:
+ /* Should never be reached */
+ usb_out_bytecount = 0;
+ break;
+ }
+
+ /* Update EP1 Bulk-IN data byte count */
+ payload_index_in += usb_in_bytecount;
+
+ /* Determine if this was the last command */
+ if ((cmd_id_index + usb_out_bytecount + 1) >= EP1OUTBC) {
+ return true;
+ /* Line between return and else required by checkpatch: */
+ uint8_t a = 0;
+ } else {
+ /* Not the last command, update cmd_id_index */
+ cmd_id_index += (usb_out_bytecount + 1);
+ return false;
+ }
+}
+
+/**
+ * Forever wait for commands and execute them as they arrive.
+ */
+void command_loop(void)
+{
+ bool last_command;
+ while (1) {
+ cmd_id_index = 0;
+ payload_index_in = 0;
+
+ /* Wait until host sends EP1 Bulk-OUT packet */
+ while (!ep1_out)
+ ;
+ ep1_out = false;
+
+ /* Execute the commands */
+ last_command = false;
+ while (!last_command)
+ last_command = execute_command();
+
+ /* Send back EP6 Bulk-IN packet if required */
+ if (payload_index_in > 0) {
+ EP1INBC = payload_index_in;
+ syncdelay(3);
+
+ while (!ep1_in)
+ ;
+ ep1_in = false;
+ }
+
+ /* Re-arm EP1-OUT after command execution */
+ EP1OUTBC = 0;
+ syncdelay(3);
+ EP1OUTBC = 0;
+ syncdelay(3);
+ }
+}