190 lines
5.4 KiB
C
190 lines
5.4 KiB
C
// 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);
|
|
}
|
|
}
|