fw/icE1usb: Import firmware for the icE1usb and icE1usb-proto boards

Currently only the icE1usb-proto is supported. Adaptation for the
final production hardware is yet to be done.

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
diff --git a/firmware/ice40-riscv/icE1usb/fw_app.c b/firmware/ice40-riscv/icE1usb/fw_app.c
new file mode 100644
index 0000000..fe1dd01
--- /dev/null
+++ b/firmware/ice40-riscv/icE1usb/fw_app.c
@@ -0,0 +1,169 @@
+/*
+ * fw_app.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.h>
+#include <no2usb/usb_dfu_rt.h>
+
+#include "config.h"
+
+#include "console.h"
+#include "e1.h"
+#include "led.h"
+#include "misc.h"
+#include "mini-printf.h"
+#include "spi.h"
+#include "utils.h"
+
+
+extern const struct usb_stack_descriptors app_stack_desc;
+
+static void
+serial_no_init()
+{
+	uint8_t buf[8];
+	char *id, *desc;
+	int i;
+
+	flash_manuf_id(buf);
+	printf("Flash Manufacturer : %s\n", hexstr(buf, 3, true));
+
+	flash_unique_id(buf);
+	printf("Flash Unique ID    : %s\n", hexstr(buf, 8, true));
+
+	/* Overwrite descriptor string */
+		/* In theory in rodata ... but nothing is ro here */
+	id = hexstr(buf, 8, false);
+	desc = (char*)app_stack_desc.str[1];
+	for (i=0; i<16; i++)
+		desc[2 + (i << 1)] = id[i];
+}
+
+static void
+boot_dfu(void)
+{
+	/* Force re-enumeration */
+	usb_disconnect();
+
+	/* Boot firmware */
+	volatile uint32_t *boot = (void*)0x80000000;
+	*boot = (1 << 2) | (1 << 0);
+}
+
+void
+usb_dfu_rt_cb_reboot(void)
+{
+        boot_dfu();
+}
+
+
+static volatile uint32_t * const misc_regs = (void*)(MISC_BASE);
+
+void main()
+{
+	bool e1_active = false;
+	int cmd = 0;
+
+	/* Init console IO */
+	console_init();
+	puts("Booting App image..\n");
+
+	/* LED */
+	led_init();
+
+	/* SPI */
+	spi_init();
+
+	/* Setup E1 Vref */
+	int d = 25;
+	pdm_set(PDM_E1_CT, true, 128, false);
+	pdm_set(PDM_E1_P,  true, 128 - d, false);
+	pdm_set(PDM_E1_N,  true, 128 + d, false);
+
+	/* Setup clock tuning */
+	pdm_set(PDM_CLK_HI, true, 2048, false);
+	pdm_set(PDM_CLK_LO, false,   0, false);
+
+	/* Enable USB directly */
+	serial_no_init();
+	usb_init(&app_stack_desc);
+	usb_dfu_rt_init();
+	usb_e1_init();
+
+	/* Start */
+	e1_init(false);		// local tick
+	e1_active = true;
+	led_state(true);
+	usb_connect();
+
+	/* Main loop */
+	while (1)
+	{
+		/* Prompt ? */
+		if (cmd >= 0)
+			printf("Command> ");
+
+		/* Poll for command */
+		cmd = getchar_nowait();
+
+		if (cmd >= 0) {
+			if (cmd > 32 && cmd < 127) {
+				putchar(cmd);
+				putchar('\r');
+				putchar('\n');
+			}
+
+			switch (cmd)
+			{
+			case 'p':
+				usb_debug_print();
+				break;
+			case 'b':
+				boot_dfu();
+				break;
+			case 'o':
+				e1_debug_print(false);
+				break;
+			case 'O':
+				e1_debug_print(true);
+				break;
+			case 't':
+				printf("%08x\n", misc_regs[0]);
+			case 'e':
+				e1_init(true);
+				e1_active = true;
+				led_state(true);
+				break;
+			case 'E':
+				e1_init(false);
+				e1_active = true;
+				led_state(true);
+				break;
+			case 'c':
+				usb_connect();
+				break;
+			case 'd':
+				usb_disconnect();
+				break;
+			default:
+				break;
+			}
+		}
+
+		/* USB poll */
+		usb_poll();
+
+		/* E1 poll */
+		if (e1_active) {
+			e1_poll();
+			usb_e1_run();
+		}
+	}
+}