usb: gadget: usbhs: Add Renesas USBHS device driver

Add UDC driver for Renesas USBHS controller found in R-Car Gen3 SoCs.
This is mostly ported from the Linux kernel, with additional porting
glue. The code has been synchronized with 1b4861e32e46 ("Linux 6.9.3")
and cleaned up and ported to DM since the original implementation by
Vitaliy.

Signed-off-by: Vitaliy Vasylskyy <vitaliy.vasylskyy@globallogic.com>
Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
Reviewed-by: Mattijs Korpershoek <mkorpershoek@baylibre.com>
Link: https://lore.kernel.org/r/20240908230654.286062-1-marek.vasut+renesas@mailbox.org
Signed-off-by: Mattijs Korpershoek <mkorpershoek@baylibre.com>
diff --git a/drivers/usb/gadget/rcar/fifo.h b/drivers/usb/gadget/rcar/fifo.h
new file mode 100644
index 0000000..86746ca
--- /dev/null
+++ b/drivers/usb/gadget/rcar/fifo.h
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: GPL-1.0+ */
+/*
+ * Renesas USB driver
+ *
+ * Copyright (C) 2011 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ */
+#ifndef RENESAS_USB_FIFO_H
+#define RENESAS_USB_FIFO_H
+
+#include <dma.h>
+#include "pipe.h"
+
+/*
+ * Drivers, using this library are expected to embed struct shdma_dev,
+ * struct shdma_chan, struct shdma_desc, and struct shdma_slave
+ * in their respective device, channel, descriptor and slave objects.
+ */
+
+struct shdma_slave {
+	int slave_id;
+};
+
+/* Used by slave DMA clients to request DMA to/from a specific peripheral */
+struct sh_dmae_slave {
+	struct shdma_slave		shdma_slave;	/* Set by the platform */
+};
+
+struct usbhs_fifo {
+	char *name;
+	u32 port;	/* xFIFO */
+	u32 sel;	/* xFIFOSEL */
+	u32 ctr;	/* xFIFOCTR */
+
+	struct usbhs_pipe	*pipe;
+
+	struct dma_chan		*tx_chan;
+	struct dma_chan		*rx_chan;
+
+	struct sh_dmae_slave	tx_slave;
+	struct sh_dmae_slave	rx_slave;
+};
+
+#define USBHS_MAX_NUM_DFIFO	4
+struct usbhs_fifo_info {
+	struct usbhs_fifo cfifo;
+	struct usbhs_fifo dfifo[USBHS_MAX_NUM_DFIFO];
+};
+#define usbhsf_get_dnfifo(p, n)	(&((p)->fifo_info.dfifo[n]))
+#define usbhs_for_each_dfifo(priv, dfifo, i)			\
+	for ((i) = 0;						\
+	     ((i) < USBHS_MAX_NUM_DFIFO) &&			\
+		     ((dfifo) = usbhsf_get_dnfifo(priv, (i)));	\
+	     (i)++)
+
+struct usbhs_pkt_handle;
+struct usbhs_pkt {
+	struct list_head node;
+	struct usbhs_pipe *pipe;
+	const struct usbhs_pkt_handle *handler;
+	void (*done)(struct usbhs_priv *priv,
+		     struct usbhs_pkt *pkt);
+	struct work_struct work;
+	dma_addr_t dma;
+	const struct dmaengine_result *dma_result;
+	void *buf;
+	int length;
+	int trans;
+	int actual;
+	int zero;
+	int sequence;
+};
+
+struct usbhs_pkt_handle {
+	int (*prepare)(struct usbhs_pkt *pkt, int *is_done);
+	int (*try_run)(struct usbhs_pkt *pkt, int *is_done);
+	int (*dma_done)(struct usbhs_pkt *pkt, int *is_done);
+};
+
+/*
+ * fifo
+ */
+int usbhs_fifo_probe(struct usbhs_priv *priv);
+void usbhs_fifo_remove(struct usbhs_priv *priv);
+void usbhs_fifo_init(struct usbhs_priv *priv);
+void usbhs_fifo_quit(struct usbhs_priv *priv);
+void usbhs_fifo_clear_dcp(struct usbhs_pipe *pipe);
+
+/*
+ * packet info
+ */
+extern const struct usbhs_pkt_handle usbhs_fifo_pio_push_handler;
+extern const struct usbhs_pkt_handle usbhs_fifo_pio_pop_handler;
+extern const struct usbhs_pkt_handle usbhs_ctrl_stage_end_handler;
+
+extern const struct usbhs_pkt_handle usbhs_fifo_dma_push_handler;
+extern const struct usbhs_pkt_handle usbhs_fifo_dma_pop_handler;
+
+extern const struct usbhs_pkt_handle usbhs_dcp_status_stage_in_handler;
+extern const struct usbhs_pkt_handle usbhs_dcp_status_stage_out_handler;
+
+extern const struct usbhs_pkt_handle usbhs_dcp_data_stage_in_handler;
+extern const struct usbhs_pkt_handle usbhs_dcp_data_stage_out_handler;
+
+void usbhs_pkt_init(struct usbhs_pkt *pkt);
+void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt,
+		    void (*done)(struct usbhs_priv *priv,
+				 struct usbhs_pkt *pkt),
+		    void *buf, int len, int zero, int sequence);
+struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt);
+void usbhs_pkt_start(struct usbhs_pipe *pipe);
+struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe);
+
+#endif /* RENESAS_USB_FIFO_H */