// 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. * * * *****************************************************************************/ #include "usb.h" #include "protocol.h" #include "jtag.h" #include "delay.h" #include "io.h" #include "msgtypes.h" #include "reg_ezusb.h" #include #include /** 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); } }