riscv-openocd/contrib/firmware/angie/c/src/protocol.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);
}
}