fw/e1-tracer: Import firmware for the E1 tracer board

Some more code could probably be unified with the "normal" usb E1 adapter
to both reduce code duplication but also offer 'sniff' function to the
E1 adapter.

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
diff --git a/firmware/ice40-riscv/e1-tracer/usb_e1.c b/firmware/ice40-riscv/e1-tracer/usb_e1.c
new file mode 100644
index 0000000..421305b
--- /dev/null
+++ b/firmware/ice40-riscv/e1-tracer/usb_e1.c
@@ -0,0 +1,230 @@
+/*
+ * usb_e1.c
+ *
+ * Copyright (C) 2019-2020  Sylvain Munaut <tnt@246tNt.com>
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <no2usb/usb_hw.h>
+#include <no2usb/usb_priv.h>
+
+#include "console.h"
+#include "e1.h"
+#include "misc.h"
+
+struct {
+	bool running;
+	int in_bdi[2];
+} g_usb_e1;
+
+
+/* Hack */
+unsigned int e1_rx_need_data(int chan, unsigned int usb_addr, unsigned int max_len, unsigned int *pos);
+unsigned int e1_rx_level(int chan);
+uint8_t e1_get_pending_flags(int chan);
+/* ---- */
+
+bool
+usb_ep_boot(const struct usb_intf_desc *intf, uint8_t ep_addr, bool dual_bd);
+
+
+void
+usb_e1_run(void)
+{
+	int chan;
+	int bdi;
+
+	if (!g_usb_e1.running)
+		return;
+
+	/* EP[1-2] IN */
+	for (chan=0; chan<2; chan++)
+	{
+		bdi = g_usb_e1.in_bdi[chan];
+
+		while ((usb_ep_regs[1+chan].in.bd[bdi].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA)
+		{
+			uint32_t ptr = usb_ep_regs[1+chan].in.bd[bdi].ptr;
+			uint32_t hdr;
+			unsigned int pos;
+
+			/* Error check */
+			if ((usb_ep_regs[1+chan].in.bd[bdi].csr & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_ERR)
+				printf("Err EP%d IN\n", 1+chan);
+
+			/* Get some data from E1 */
+			int n = e1_rx_level(chan);
+
+//			if (n > 64)
+//				n = 12;
+//			else if (n > 32)
+//				n = 10;
+//			else if (n > 8)
+//				n = 8;
+			if (n > 12)
+				n = 12;
+			else if (!n)
+				break;
+
+			n = e1_rx_need_data(chan, (ptr >> 2) + 1, n, &pos);
+
+			/* Write header */
+				/* [31:12] (reserved) */
+				/* [11:10] CRC results (first new multiframe present in packet)  */
+				/* [ 9: 8] CRC results (second new multiframe present in packet) */
+				/* [ 7: 5] Multiframe sequence number (first frame of packet)    */
+				/* [ 4: 0] Position in multi-frame    (first frame of packet)    */
+			hdr = (pos & 0xff) | (e1_get_pending_flags(chan) << 24);
+			usb_data_write(ptr, &hdr, 4);
+			usb_ep_regs[1+chan].in.bd[bdi].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN((n * 32) + 4);
+
+			/* Next BDI */
+			bdi ^= 1;
+			g_usb_e1.in_bdi[chan] = bdi;
+		}
+	}
+}
+
+static const struct usb_intf_desc *
+_find_intf(const struct usb_conf_desc *conf, uint8_t idx)
+{
+	const struct usb_intf_desc *intf = NULL;
+	const void *sod, *eod;
+
+	if (!conf)
+		return NULL;
+
+	sod = conf;
+	eod = sod + conf->wTotalLength;
+
+	while (1) {
+		sod = usb_desc_find(sod, eod, USB_DT_INTF);
+		if (!sod)
+			break;
+
+		intf = (void*)sod;
+		if (intf->bInterfaceNumber == idx)
+			return intf;
+
+		sod = usb_desc_next(sod);
+	}
+
+	return NULL;
+}
+enum usb_fnd_resp
+_e1_set_conf(const struct usb_conf_desc *conf)
+{
+	const struct usb_intf_desc *intf;
+
+	printf("e1 set_conf %08x\n", conf);
+	if (!conf)
+		return USB_FND_SUCCESS;
+
+	intf = _find_intf(conf, 0);
+	if (!intf)
+		return USB_FND_ERROR;
+
+	printf("e1 set_conf %08x\n", intf);
+
+	usb_ep_boot(intf, 0x81, true);
+	usb_ep_boot(intf, 0x82, true);
+
+	return USB_FND_SUCCESS;
+}
+
+enum usb_fnd_resp
+_e1_set_intf(const struct usb_intf_desc *base, const struct usb_intf_desc *sel)
+{
+	if (base->bInterfaceNumber != 0)
+		return USB_FND_CONTINUE;
+
+	if (sel->bAlternateSetting == 0)
+	{
+		/* Already stopped ? */
+		if (!g_usb_e1.running)
+			return USB_FND_SUCCESS;
+
+		/* Update state */
+		g_usb_e1.running = false;
+
+		/* Stop E1 */
+		e1_stop();
+
+		/* Disable end-points */
+		usb_ep_regs[1].in.status = 0;
+		usb_ep_regs[2].in.status = 0;
+	}
+	else if (sel->bAlternateSetting == 1)
+	{
+		/* Already running ? */
+		if (g_usb_e1.running)
+			return USB_FND_SUCCESS;
+
+		/* Update state */
+		g_usb_e1.running = true;
+
+		/* Reset buffer pointers */
+		g_usb_e1.in_bdi[0] = 0;
+		g_usb_e1.in_bdi[1] = 0;
+
+		/* Configure EP1 IN / EP2 IN */
+		usb_ep_regs[1].in.status = USB_EP_TYPE_ISOC | USB_EP_BD_DUAL;	/* Type=Isochronous, dual buffered */
+		usb_ep_regs[2].in.status = USB_EP_TYPE_ISOC | USB_EP_BD_DUAL;	/* Type=Isochronous, dual buffered */
+
+		/* EP1 IN: Prepare two buffers */
+		usb_ep_regs[1].in.bd[0].ptr = 256 + 0 * 388;
+		usb_ep_regs[1].in.bd[0].csr = 0;
+
+		usb_ep_regs[1].in.bd[1].ptr = 256 + 1 * 388;
+		usb_ep_regs[1].in.bd[1].csr = 0;
+
+		/* EP2 IN: Prepare two buffers */
+		usb_ep_regs[2].in.bd[0].ptr = 256 + 2 * 388;
+		usb_ep_regs[2].in.bd[0].csr = 0;
+
+		usb_ep_regs[2].in.bd[1].ptr = 256 + 3 * 388;
+		usb_ep_regs[2].in.bd[1].csr = 0;
+
+		/* Start E1 */
+		e1_start();
+	}
+	else
+	{
+		/* Unknown */
+		return USB_FND_ERROR;
+	}
+
+
+	return USB_FND_SUCCESS;
+}
+
+enum usb_fnd_resp
+_e1_get_intf(const struct usb_intf_desc *base, uint8_t *alt)
+{
+	if (base->bInterfaceNumber != 0)
+		return USB_FND_CONTINUE;
+
+	*alt = g_usb_e1.running ? 1 : 0;
+
+	return USB_FND_SUCCESS;
+}
+
+static struct usb_fn_drv _e1_drv = {
+	.set_conf	= _e1_set_conf,
+        .set_intf       = _e1_set_intf,
+        .get_intf       = _e1_get_intf,
+};
+
+void
+usb_e1_init(void)
+{
+	/* Clear state */
+	memset(&g_usb_e1, 0x00, sizeof(g_usb_e1));
+
+	/* Install driver */
+	usb_register_function_driver(&_e1_drv);
+}