firmware/ice40-riscv: Import common parts to all iCE40/RISC-V firmwares

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
diff --git a/firmware/ice40-riscv/common/dma.c b/firmware/ice40-riscv/common/dma.c
new file mode 100644
index 0000000..a2c81cc
--- /dev/null
+++ b/firmware/ice40-riscv/common/dma.c
@@ -0,0 +1,69 @@
+/*
+ * dma.c
+ *
+ * Copyright (C) 2019-2020  Sylvain Munaut <tnt@246tNt.com>
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "config.h"
+#include "dma.h"
+
+
+struct dma {
+	uint32_t csr;
+	uint32_t _rsvd;
+	uint32_t addr_e1;
+	uint32_t addr_usb;
+} __attribute__((packed,aligned(4)));
+
+#define DMA_CSR_GO		(1 << 15)
+#define DMA_CSR_BUSY		(1 << 15)
+#define DMA_DIR_E1_TO_USB	(0 << 14)
+#define DMA_DIR_USB_TO_E1	(1 << 14)
+#define DMA_CSR_LEN(x)		(((x)-2) & 0x1fff)
+
+static volatile struct dma * const dma_regs = (void*)(DMA_BASE);
+
+static struct {
+	bool pending;
+	dma_cb cb_fn;
+	void *cb_data;
+} g_dma;
+
+
+bool
+dma_ready(void)
+{
+	return !(dma_regs->csr & DMA_CSR_BUSY);
+}
+
+void
+dma_exec(unsigned addr_e1, unsigned addr_usb, unsigned len, bool dir,
+         dma_cb cb_fn, void *cb_data)
+{
+	dma_regs->addr_e1  = addr_e1;
+	dma_regs->addr_usb = addr_usb;
+	dma_regs->csr =
+		DMA_CSR_GO |
+		(dir ? DMA_DIR_USB_TO_E1 : DMA_DIR_E1_TO_USB) |
+		DMA_CSR_LEN(len);
+
+	g_dma.pending = true;
+	g_dma.cb_fn = cb_fn;
+	g_dma.cb_data = cb_data;
+}
+
+bool
+dma_poll(void)
+{
+	if (g_dma.pending && dma_ready()) {
+		g_dma.pending = false;
+		if (g_dma.cb_fn)
+			g_dma.cb_fn(g_dma.cb_data);
+	}
+
+	return g_dma.pending;
+}