mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 00/10] Add Raspberry Pi USB support
@ 2019-12-20 14:32 Sascha Hauer
  2019-12-20 14:32 ` [PATCH 01/10] usb: Make timeout unit clear Sascha Hauer
                   ` (9 more replies)
  0 siblings, 10 replies; 24+ messages in thread
From: Sascha Hauer @ 2019-12-20 14:32 UTC (permalink / raw)
  To: Barebox List

This series adds USB host support for the Raspberry Pi. The dwc2 USB
host driver is ported from U-Boot and tested on a Raspberry Pi 3b with
the USB ethernet adapter found on that board.

Finally we have ethernet support on the Raspberry Pi \o/

Sascha

Sascha Hauer (10):
  usb: Make timeout unit clear
  of: Add of_bus_n_xxx_cells()
  device: Introduce dma_offset
  of: Read dma_offset from device tree
  usb: Add usbroothubdes.h
  regulator: add function to get regulator by its name
  rpi: Enable USB Power domain during startup
  usb: Forward error code from usb_set_configuration
  usb: Add dwc2 host driver
  ARM: rpi_defconfig: Enable networking support

 arch/arm/boards/raspberry-pi/rpi-common.c |   10 +
 arch/arm/configs/rpi_defconfig            |   13 +
 arch/arm/cpu/mmu-common.c                 |   33 +-
 arch/arm/cpu/mmu.c                        |    4 +
 arch/arm/cpu/mmu_64.c                     |    4 +
 drivers/of/address.c                      |  109 ++
 drivers/of/base.c                         |   46 +-
 drivers/of/platform.c                     |   18 +
 drivers/regulator/core.c                  |   30 +-
 drivers/usb/core/usb.c                    |   18 +-
 drivers/usb/host/Kconfig                  |    3 +
 drivers/usb/host/Makefile                 |    1 +
 drivers/usb/host/dwc2.c                   | 1132 +++++++++++++++++++++
 drivers/usb/host/dwc2.h                   |  778 ++++++++++++++
 include/driver.h                          |    2 +
 include/of.h                              |   12 +
 include/of_address.h                      |    9 +
 include/regulator.h                       |    1 +
 include/usb/usb.h                         |    8 +-
 include/usb/usbroothubdes.h               |  128 +++
 20 files changed, 2326 insertions(+), 33 deletions(-)
 create mode 100644 drivers/usb/host/dwc2.c
 create mode 100644 drivers/usb/host/dwc2.h
 create mode 100644 include/usb/usbroothubdes.h

-- 
2.24.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 01/10] usb: Make timeout unit clear
  2019-12-20 14:32 [PATCH 00/10] Add Raspberry Pi USB support Sascha Hauer
@ 2019-12-20 14:32 ` Sascha Hauer
  2019-12-20 14:32 ` [PATCH 02/10] of: Add of_bus_n_xxx_cells() Sascha Hauer
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 24+ messages in thread
From: Sascha Hauer @ 2019-12-20 14:32 UTC (permalink / raw)
  To: Barebox List

The usb_*_msg() functions take a timeout parameter. Make clear which
unit is expected by adding a _ms suffix to the variable name.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/usb/core/usb.c | 8 ++++----
 include/usb/usb.h      | 8 ++++----
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index d29cd1328b..ad3bacf236 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -593,7 +593,7 @@ int usb_submit_int_msg(struct usb_device *dev, unsigned long pipe,
 int usb_control_msg(struct usb_device *dev, unsigned int pipe,
 			unsigned char request, unsigned char requesttype,
 			unsigned short value, unsigned short index,
-			void *data, unsigned short size, int timeout)
+			void *data, unsigned short size, int timeout_ms)
 {
 	struct usb_host *host = dev->host;
 	int ret;
@@ -615,7 +615,7 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe,
 	dev->status = USB_ST_NOT_PROC; /*not yet processed */
 
 	ret = host->submit_control_msg(dev, pipe, data, size, setup_packet,
-			timeout);
+			timeout_ms);
 
 	usb_host_release(host);
 
@@ -631,7 +631,7 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe,
  * synchronous behavior
  */
 int usb_bulk_msg(struct usb_device *dev, unsigned int pipe,
-			void *data, int len, int *actual_length, int timeout)
+			void *data, int len, int *actual_length, int timeout_ms)
 {
 	struct usb_host *host = dev->host;
 	int ret;
@@ -644,7 +644,7 @@ int usb_bulk_msg(struct usb_device *dev, unsigned int pipe,
 		return ret;
 
 	dev->status = USB_ST_NOT_PROC; /* not yet processed */
-	ret = host->submit_bulk_msg(dev, pipe, data, len, timeout);
+	ret = host->submit_bulk_msg(dev, pipe, data, len, timeout_ms);
 
 	usb_host_release(host);
 
diff --git a/include/usb/usb.h b/include/usb/usb.h
index d39de71aff..95dedfd5b7 100644
--- a/include/usb/usb.h
+++ b/include/usb/usb.h
@@ -140,9 +140,9 @@ struct usb_host {
 	int (*init)(struct usb_host *);
 	int (*exit)(struct usb_host *);
 	int (*submit_bulk_msg)(struct usb_device *dev, unsigned long pipe,
-			void *buffer, int transfer_len, int timeout);
+			void *buffer, int transfer_len, int timeout_ms);
 	int (*submit_control_msg)(struct usb_device *dev, unsigned long pipe, void *buffer,
-			int transfer_len, struct devrequest *setup, int timeout);
+			int transfer_len, struct devrequest *setup, int timeout_ms);
 	int (*submit_int_msg)(struct usb_device *dev, unsigned long pipe, void *buffer,
 			int transfer_len, int interval);
 	void (*usb_event_poll)(void);
@@ -167,9 +167,9 @@ int usb_set_idle(struct usb_device *dev, int ifnum, int duration,
 int usb_control_msg(struct usb_device *dev, unsigned int pipe,
 			unsigned char request, unsigned char requesttype,
 			unsigned short value, unsigned short index,
-			void *data, unsigned short size, int timeout);
+			void *data, unsigned short size, int timeout_ms);
 int usb_bulk_msg(struct usb_device *dev, unsigned int pipe,
-			void *data, int len, int *actual_length, int timeout);
+			void *data, int len, int *actual_length, int timeout_ms);
 int usb_submit_int_msg(struct usb_device *dev, unsigned long pipe,
 			void *buffer, int transfer_len, int interval);
 int usb_maxpacket(struct usb_device *dev, unsigned long pipe);
-- 
2.24.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 02/10] of: Add of_bus_n_xxx_cells()
  2019-12-20 14:32 [PATCH 00/10] Add Raspberry Pi USB support Sascha Hauer
  2019-12-20 14:32 ` [PATCH 01/10] usb: Make timeout unit clear Sascha Hauer
@ 2019-12-20 14:32 ` Sascha Hauer
  2019-12-20 14:32 ` [PATCH 03/10] device: Introduce dma_offset Sascha Hauer
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 24+ messages in thread
From: Sascha Hauer @ 2019-12-20 14:32 UTC (permalink / raw)
  To: Barebox List

Added straight from the Kernel.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/of/base.c | 46 ++++++++++++++++++++++++++++------------------
 include/of.h      | 12 ++++++++++++
 2 files changed, 40 insertions(+), 18 deletions(-)

diff --git a/drivers/of/base.c b/drivers/of/base.c
index 80ceeab13b..9ede052274 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -78,36 +78,46 @@ static struct device_node *of_aliases;
 #define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1
 #define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 1
 
-int of_n_addr_cells(struct device_node *np)
+int of_bus_n_addr_cells(struct device_node *np)
 {
-	const __be32 *ip;
+	u32 cells;
+
+	for (; np; np = np->parent)
+		if (!of_property_read_u32(np, "#address-cells", &cells))
+			return cells;
 
-	do {
-		if (np->parent)
-			np = np->parent;
-		ip = of_get_property(np, "#address-cells", NULL);
-		if (ip)
-			return be32_to_cpup(ip);
-	} while (np->parent);
 	/* No #address-cells property for the root node */
 	return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
 }
+
+int of_n_addr_cells(struct device_node *np)
+{
+	if (np->parent)
+		np = np->parent;
+
+	return of_bus_n_addr_cells(np);
+}
 EXPORT_SYMBOL(of_n_addr_cells);
 
-int of_n_size_cells(struct device_node *np)
+int of_bus_n_size_cells(struct device_node *np)
 {
-	const __be32 *ip;
+	u32 cells;
+
+	for (; np; np = np->parent)
+		if (!of_property_read_u32(np, "#size-cells", &cells))
+			return cells;
 
-	do {
-		if (np->parent)
-			np = np->parent;
-		ip = of_get_property(np, "#size-cells", NULL);
-		if (ip)
-			return be32_to_cpup(ip);
-	} while (np->parent);
 	/* No #size-cells property for the root node */
 	return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
 }
+
+int of_n_size_cells(struct device_node *np)
+{
+	if (np->parent)
+		np = np->parent;
+
+	return of_bus_n_size_cells(np);
+}
 EXPORT_SYMBOL(of_n_size_cells);
 
 struct property *of_find_property(const struct device_node *np,
diff --git a/include/of.h b/include/of.h
index f63a3efe13..67601ce80c 100644
--- a/include/of.h
+++ b/include/of.h
@@ -113,7 +113,9 @@ struct device_node *of_unflatten_dtb_const(const void *infdt);
 struct cdev;
 
 #ifdef CONFIG_OFTREE
+extern int of_bus_n_addr_cells(struct device_node *np);
 extern int of_n_addr_cells(struct device_node *np);
+extern int of_bus_n_size_cells(struct device_node *np);
 extern int of_n_size_cells(struct device_node *np);
 
 extern struct property *of_find_property(const struct device_node *np,
@@ -328,11 +330,21 @@ static inline struct device_d *of_platform_device_create(struct device_node *np,
 	return NULL;
 }
 
+static inline int of_bus_n_addr_cells(struct device_node *np)
+{
+	return 0;
+}
+
 static inline int of_n_addr_cells(struct device_node *np)
 {
 	return 0;
 }
 
+static inline int of_bus_n_size_cells(struct device_node *np)
+{
+	return 0;
+}
+
 static inline int of_n_size_cells(struct device_node *np)
 {
 	return 0;
-- 
2.24.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 03/10] device: Introduce dma_offset
  2019-12-20 14:32 [PATCH 00/10] Add Raspberry Pi USB support Sascha Hauer
  2019-12-20 14:32 ` [PATCH 01/10] usb: Make timeout unit clear Sascha Hauer
  2019-12-20 14:32 ` [PATCH 02/10] of: Add of_bus_n_xxx_cells() Sascha Hauer
@ 2019-12-20 14:32 ` Sascha Hauer
  2019-12-20 14:32 ` [PATCH 04/10] of: Read dma_offset from device tree Sascha Hauer
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 24+ messages in thread
From: Sascha Hauer @ 2019-12-20 14:32 UTC (permalink / raw)
  To: Barebox List

For devices that do not have a 1:1 mapping between DMA and CPU we need a
dma_offset. This adds dma_offset to struct device_d and starts honoring
it in ARM dma_(un)map_single(). Also we add some comments to functions
that would normally need a device argument to make the DMA <-> CPU
translations device specific.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/cpu/mmu-common.c | 33 +++++++++++++++++++++++++++++++--
 arch/arm/cpu/mmu.c        |  4 ++++
 arch/arm/cpu/mmu_64.c     |  4 ++++
 include/driver.h          |  2 ++
 4 files changed, 41 insertions(+), 2 deletions(-)

diff --git a/arch/arm/cpu/mmu-common.c b/arch/arm/cpu/mmu-common.c
index aeefbb2daa..287622b203 100644
--- a/arch/arm/cpu/mmu-common.c
+++ b/arch/arm/cpu/mmu-common.c
@@ -11,9 +11,32 @@
 #include "mmu.h"
 
 
+static inline dma_addr_t cpu_to_dma(struct device_d *dev, unsigned long cpu_addr)
+{
+	dma_addr_t dma_addr = cpu_addr;
+
+	if (dev)
+		dma_addr -= dev->dma_offset;
+
+	return dma_addr;
+}
+
+static inline unsigned long dma_to_cpu(struct device_d *dev, dma_addr_t addr)
+{
+	unsigned long cpu_addr = addr;
+
+	if (dev)
+		cpu_addr += dev->dma_offset;
+
+	return cpu_addr;
+}
+
 void dma_sync_single_for_cpu(dma_addr_t address, size_t size,
 			     enum dma_data_direction dir)
 {
+	/*
+	 * FIXME: This function needs a device argument to support non 1:1 mappings
+	 */
 	if (dir != DMA_TO_DEVICE)
 		dma_inv_range((void *)address, size);
 }
@@ -25,12 +48,14 @@ dma_addr_t dma_map_single(struct device_d *dev, void *ptr, size_t size,
 
 	dma_sync_single_for_device(addr, size, dir);
 
-	return addr;
+	return cpu_to_dma(dev, addr);
 }
 
-void dma_unmap_single(struct device_d *dev, dma_addr_t addr, size_t size,
+void dma_unmap_single(struct device_d *dev, dma_addr_t dma_addr, size_t size,
 		      enum dma_data_direction dir)
 {
+	unsigned long addr = dma_to_cpu(dev, dma_addr);
+
 	dma_sync_single_for_cpu(addr, size, dir);
 }
 
@@ -53,6 +78,10 @@ void *dma_alloc_map(size_t size, dma_addr_t *dma_handle, unsigned flags)
 
 void *dma_alloc_coherent(size_t size, dma_addr_t *dma_handle)
 {
+	/*
+	 * FIXME: This function needs a device argument to support non 1:1 mappings
+	 */
+
 	return dma_alloc_map(size, dma_handle, MAP_UNCACHED);
 }
 
diff --git a/arch/arm/cpu/mmu.c b/arch/arm/cpu/mmu.c
index 158b130b57..1f97c28ec6 100644
--- a/arch/arm/cpu/mmu.c
+++ b/arch/arm/cpu/mmu.c
@@ -491,6 +491,10 @@ void *dma_alloc_writecombine(size_t size, dma_addr_t *dma_handle)
 void dma_sync_single_for_device(dma_addr_t address, size_t size,
 				enum dma_data_direction dir)
 {
+	/*
+	 * FIXME: This function needs a device argument to support non 1:1 mappings
+	 */
+
 	if (dir == DMA_FROM_DEVICE) {
 		__dma_inv_range(address, address + size);
 		if (outer_cache.inv_range)
diff --git a/arch/arm/cpu/mmu_64.c b/arch/arm/cpu/mmu_64.c
index f7a13014af..98cd4c754e 100644
--- a/arch/arm/cpu/mmu_64.c
+++ b/arch/arm/cpu/mmu_64.c
@@ -245,6 +245,10 @@ void dma_flush_range(void *ptr, size_t size)
 void dma_sync_single_for_device(dma_addr_t address, size_t size,
                                 enum dma_data_direction dir)
 {
+	/*
+	 * FIXME: This function needs a device argument to support non 1:1 mappings
+	 */
+
 	if (dir == DMA_FROM_DEVICE)
 		v8_inv_dcache_range(address, address + size - 1);
 	else
diff --git a/include/driver.h b/include/driver.h
index ad59ce90c3..74be1b3e8e 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -93,6 +93,8 @@ struct device_d {
 
 	u64 dma_mask;
 
+	unsigned long dma_offset;
+
 	void    (*info) (struct device_d *);
 	/*
 	 * For devices which take longer to probe this is called
-- 
2.24.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 04/10] of: Read dma_offset from device tree
  2019-12-20 14:32 [PATCH 00/10] Add Raspberry Pi USB support Sascha Hauer
                   ` (2 preceding siblings ...)
  2019-12-20 14:32 ` [PATCH 03/10] device: Introduce dma_offset Sascha Hauer
@ 2019-12-20 14:32 ` Sascha Hauer
  2019-12-20 14:32 ` [PATCH 05/10] usb: Add usbroothubdes.h Sascha Hauer
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 24+ messages in thread
From: Sascha Hauer @ 2019-12-20 14:32 UTC (permalink / raw)
  To: Barebox List

This reads the dma-ranges property from the device tree and sets
dma_offset in the devices accordingly. The code is mostly taken
from the Kernel as of v5.5-rc1. of_dma_configure() is trimmed down
to the cases we want to support currently.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/of/address.c  | 109 ++++++++++++++++++++++++++++++++++++++++++
 drivers/of/platform.c |  18 +++++++
 include/of_address.h  |   9 ++++
 3 files changed, 136 insertions(+)

diff --git a/drivers/of/address.c b/drivers/of/address.c
index 4e12522a0a..2020f5b7b1 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -458,6 +458,33 @@ bool of_can_translate_address(struct device_node *dev)
 }
 EXPORT_SYMBOL(of_can_translate_address);
 
+static struct device_node *__of_get_dma_parent(struct device_node *np)
+{
+	struct of_phandle_args args;
+	int ret, index;
+
+	index = of_property_match_string(np, "interconnect-names", "dma-mem");
+	if (index < 0)
+		return of_get_parent(np);
+
+	ret = of_parse_phandle_with_args(np, "interconnects",
+					 "#interconnect-cells",
+					 index, &args);
+	if (ret < 0)
+		return of_get_parent(np);
+
+	return args.np;
+}
+
+static struct device_node *of_get_next_dma_parent(struct device_node *np)
+{
+	struct device_node *parent;
+
+	parent = __of_get_dma_parent(np);
+
+	return parent;
+}
+
 const __be32 *of_get_address(struct device_node *dev, int index, u64 *size,
 		    unsigned int *flags)
 {
@@ -586,3 +613,85 @@ void __iomem *of_iomap(struct device_node *np, int index)
 	return IOMEM(res.start);
 }
 EXPORT_SYMBOL(of_iomap);
+
+/**
+ * of_dma_get_range - Get DMA range info
+ * @np:		device node to get DMA range info
+ * @dma_addr:	pointer to store initial DMA address of DMA range
+ * @paddr:	pointer to store initial CPU address of DMA range
+ * @size:	pointer to store size of DMA range
+ *
+ * Look in bottom up direction for the first "dma-ranges" property
+ * and parse it.
+ *  dma-ranges format:
+ *	DMA addr (dma_addr)	: naddr cells
+ *	CPU addr (phys_addr_t)	: pna cells
+ *	size			: nsize cells
+ *
+ * It returns -ENODEV if "dma-ranges" property was not found
+ * for this device in DT.
+ */
+int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *size)
+{
+	struct device_node *node = np;
+	const __be32 *ranges = NULL;
+	int len, naddr, nsize, pna;
+	int ret = 0;
+	bool found_dma_ranges = false;
+	u64 dmaaddr;
+
+	while (node) {
+		ranges = of_get_property(node, "dma-ranges", &len);
+
+		/* Ignore empty ranges, they imply no translation required */
+		if (ranges && len > 0)
+			break;
+
+		/* Once we find 'dma-ranges', then a missing one is an error */
+		if (found_dma_ranges && !ranges) {
+			ret = -ENODEV;
+			goto out;
+		}
+		found_dma_ranges = true;
+
+		node = of_get_next_dma_parent(node);
+	}
+
+	if (!node || !ranges) {
+		pr_debug("no dma-ranges found for node(%pOF)\n", np);
+		ret = -ENODEV;
+		goto out;
+	}
+
+	naddr = of_bus_n_addr_cells(node);
+	nsize = of_bus_n_size_cells(node);
+	pna = of_n_addr_cells(node);
+	if ((len / sizeof(__be32)) % (pna + naddr + nsize)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* dma-ranges format:
+	 * DMA addr	: naddr cells
+	 * CPU addr	: pna cells
+	 * size		: nsize cells
+	 */
+	dmaaddr = of_read_number(ranges, naddr);
+	*paddr = of_translate_dma_address(node, ranges + naddr);
+	if (*paddr == OF_BAD_ADDR) {
+		pr_err("translation of DMA address(%llx) to CPU address failed node(%pOF)\n",
+		       dmaaddr, np);
+		ret = -EINVAL;
+		goto out;
+	}
+	*dma_addr = dmaaddr;
+
+	*size = of_read_number(ranges + naddr + pna, nsize);
+
+	pr_debug("dma_addr(%llx) cpu_addr(%llx) size(%llx)\n",
+		 *dma_addr, *paddr, *size);
+
+out:
+
+	return ret;
+}
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index d3795d799a..b1a7eb6730 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -74,6 +74,22 @@ static void of_device_make_bus_id(struct device_d *dev)
 	}
 }
 
+static void of_dma_configure(struct device_d *dev, struct device_node *np)
+{
+	u64 dma_addr, paddr, size = 0;
+	unsigned long offset;
+	int ret;
+
+	ret = of_dma_get_range(np, &dma_addr, &paddr, &size);
+	if (ret < 0) {
+		dma_addr = offset = 0;
+	} else {
+		offset = paddr - dma_addr;
+	}
+
+	dev->dma_offset = offset;
+}
+
 /**
  * of_platform_device_create - Alloc, initialize and register an of_device
  * @np: pointer to node to create device for
@@ -148,6 +164,8 @@ struct device_d *of_platform_device_create(struct device_node *np,
 	dev->num_resources = num_reg;
 	of_device_make_bus_id(dev);
 
+	of_dma_configure(dev, np);
+
 	resinval = (-1);
 
 	debug("%s: register device %s, io=%pa\n",
diff --git a/include/of_address.h b/include/of_address.h
index ebf3ec2a24..350ecaec82 100644
--- a/include/of_address.h
+++ b/include/of_address.h
@@ -56,6 +56,9 @@ extern struct device_node *of_find_matching_node_by_address(
 	u64 base_address);
 extern void __iomem *of_iomap(struct device_node *np, int index);
 
+extern int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr,
+			    u64 *size);
+
 #else /* CONFIG_OFTREE */
 
 static inline u64 of_translate_address(struct device_node *dev,
@@ -99,6 +102,12 @@ static inline void __iomem *of_iomap(struct device_node *np, int index)
 	return NULL;
 }
 
+static inline int of_dma_get_range(struct device_node *np, u64 *dma_addr,
+				   u64 *paddr, u64 *size)
+{
+	return -ENOSYS;
+}
+
 #endif /* CONFIG_OFTREE */
 
 #ifdef CONFIG_OF_PCI
-- 
2.24.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 05/10] usb: Add usbroothubdes.h
  2019-12-20 14:32 [PATCH 00/10] Add Raspberry Pi USB support Sascha Hauer
                   ` (3 preceding siblings ...)
  2019-12-20 14:32 ` [PATCH 04/10] of: Read dma_offset from device tree Sascha Hauer
@ 2019-12-20 14:32 ` Sascha Hauer
  2019-12-20 14:32 ` [PATCH 06/10] regulator: add function to get regulator by its name Sascha Hauer
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 24+ messages in thread
From: Sascha Hauer @ 2019-12-20 14:32 UTC (permalink / raw)
  To: Barebox List

Taken from U-Boot, needed for the upcoming dwc2 driver.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 include/usb/usbroothubdes.h | 128 ++++++++++++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 include/usb/usbroothubdes.h

diff --git a/include/usb/usbroothubdes.h b/include/usb/usbroothubdes.h
new file mode 100644
index 0000000000..e743555d8e
--- /dev/null
+++ b/include/usb/usbroothubdes.h
@@ -0,0 +1,128 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * USB virtual root hub descriptors
+ *
+ * (C) Copyright 2014
+ * Stephen Warren swarren@wwwdotorg.org
+ *
+ * Based on ohci-hcd.c
+ */
+
+#ifndef __USBROOTHUBDES_H__
+#define __USBROOTHUBDES_H__
+
+/* Device descriptor */
+static __u8 root_hub_dev_des[] = {
+	0x12,		/* __u8  bLength; */
+	0x01,		/* __u8  bDescriptorType; Device */
+	0x10,		/* __u16 bcdUSB; v1.1 */
+	0x01,
+	0x09,		/* __u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,		/* __u8  bDeviceSubClass; */
+	0x00,		/* __u8  bDeviceProtocol; */
+	0x08,		/* __u8  bMaxPacketSize0; 8 Bytes */
+	0x00,		/* __u16 idVendor; */
+	0x00,
+	0x00,		/* __u16 idProduct; */
+	0x00,
+	0x00,		/* __u16 bcdDevice; */
+	0x00,
+	0x00,		/* __u8  iManufacturer; */
+	0x01,		/* __u8  iProduct; */
+	0x00,		/* __u8  iSerialNumber; */
+	0x01,		/* __u8  bNumConfigurations; */
+};
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] = {
+	0x09,		/* __u8  bLength; */
+	0x02,		/* __u8  bDescriptorType; Configuration */
+	0x19,		/* __u16 wTotalLength; */
+	0x00,
+	0x01,		/* __u8  bNumInterfaces; */
+	0x01,		/* __u8  bConfigurationValue; */
+	0x00,		/* __u8  iConfiguration; */
+	0x40,		/* __u8  bmAttributes;
+			 *       Bit 7: Bus-powered
+			 *       6: Self-powered,
+			 *       5 Remote-wakwup,
+			 *       4..0: resvd
+			 */
+	0x00,		/* __u8  MaxPower; */
+	/* interface */
+	0x09,		/* __u8  if_bLength; */
+	0x04,		/* __u8  if_bDescriptorType; Interface */
+	0x00,		/* __u8  if_bInterfaceNumber; */
+	0x00,		/* __u8  if_bAlternateSetting; */
+	0x01,		/* __u8  if_bNumEndpoints; */
+	0x09,		/* __u8  if_bInterfaceClass; HUB_CLASSCODE */
+	0x00,		/* __u8  if_bInterfaceSubClass; */
+	0x00,		/* __u8  if_bInterfaceProtocol; */
+	0x00,		/* __u8  if_iInterface; */
+	/* endpoint */
+	0x07,		/* __u8  ep_bLength; */
+	0x05,		/* __u8  ep_bDescriptorType; Endpoint */
+	0x81,		/* __u8  ep_bEndpointAddress; IN Endpoint 1 */
+	0x03,		/* __u8  ep_bmAttributes; Interrupt */
+	0x02,		/* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
+	0x00,
+	0xff,		/* __u8  ep_bInterval; 255 ms */
+};
+
+#ifdef WANT_USB_ROOT_HUB_HUB_DES
+static unsigned char root_hub_hub_des[] = {
+	0x09,		/* __u8  bLength; */
+	0x29,		/* __u8  bDescriptorType; Hub-descriptor */
+	0x02,		/* __u8  bNbrPorts; */
+	0x00,		/* __u16 wHubCharacteristics; */
+	0x00,
+	0x01,		/* __u8  bPwrOn2pwrGood; 2ms */
+	0x00,		/* __u8  bHubContrCurrent; 0 mA */
+	0x00,		/* __u8  DeviceRemovable; *** 7 Ports max *** */
+	0xff,		/* __u8  PortPwrCtrlMask; *** 7 ports max *** */
+};
+#endif
+
+static unsigned char root_hub_str_index0[] = {
+	0x04,		/* __u8  bLength; */
+	0x03,		/* __u8  bDescriptorType; String-descriptor */
+	0x09,		/* __u8  lang ID */
+	0x04,		/* __u8  lang ID */
+};
+
+static unsigned char root_hub_str_index1[] = {
+	32,		/* __u8  bLength; */
+	0x03,		/* __u8  bDescriptorType; String-descriptor */
+	'U',		/* __u8  Unicode */
+	0,		/* __u8  Unicode */
+	'-',		/* __u8  Unicode */
+	0,		/* __u8  Unicode */
+	'B',		/* __u8  Unicode */
+	0,		/* __u8  Unicode */
+	'o',		/* __u8  Unicode */
+	0,		/* __u8  Unicode */
+	'o',		/* __u8  Unicode */
+	0,		/* __u8  Unicode */
+	't',		/* __u8  Unicode */
+	0,		/* __u8  Unicode */
+	' ',		/* __u8  Unicode */
+	0,		/* __u8  Unicode */
+	'R',		/* __u8  Unicode */
+	0,		/* __u8  Unicode */
+	'o',		/* __u8  Unicode */
+	0,		/* __u8  Unicode */
+	'o',		/* __u8  Unicode */
+	0,		/* __u8  Unicode */
+	't',		/* __u8  Unicode */
+	0,		/* __u8  Unicode */
+	' ',		/* __u8  Unicode */
+	0,		/* __u8  Unicode */
+	'H',		/* __u8  Unicode */
+	0,		/* __u8  Unicode */
+	'u',		/* __u8  Unicode */
+	0,		/* __u8  Unicode */
+	'b',		/* __u8  Unicode */
+	0,		/* __u8  Unicode */
+};
+
+#endif
-- 
2.24.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 06/10] regulator: add function to get regulator by its name
  2019-12-20 14:32 [PATCH 00/10] Add Raspberry Pi USB support Sascha Hauer
                   ` (4 preceding siblings ...)
  2019-12-20 14:32 ` [PATCH 05/10] usb: Add usbroothubdes.h Sascha Hauer
@ 2019-12-20 14:32 ` Sascha Hauer
  2019-12-20 14:32 ` [PATCH 07/10] rpi: Enable USB Power domain during startup Sascha Hauer
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 24+ messages in thread
From: Sascha Hauer @ 2019-12-20 14:32 UTC (permalink / raw)
  To: Barebox List

Useful for getting regulators that are not correctly associated with a
device.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/regulator/core.c | 30 +++++++++++++++++++++++++++++-
 include/regulator.h      |  1 +
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 4ca035ae94..f0de7a52e3 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -327,6 +327,34 @@ struct regulator *regulator_get(struct device_d *dev, const char *supply)
 	return r;
 }
 
+static struct regulator_internal *regulator_by_name(const char *name)
+{
+	struct regulator_internal *ri;
+
+	list_for_each_entry(ri, &regulator_list, list)
+		if (ri->name && !strcmp(ri->name, name))
+			return ri;
+
+	return NULL;
+}
+
+struct regulator *regulator_get_name(const char *name)
+{
+	struct regulator_internal *ri;
+	struct regulator *r;
+
+	ri = regulator_by_name(name);
+	if (!ri)
+		return ERR_PTR(-ENODEV);
+
+	r = xzalloc(sizeof(*r));
+	r->ri = ri;
+
+	list_add_tail(&r->list, &ri->consumer_list);
+
+	return r;
+}
+
 /*
  * regulator_enable - enable a regulator.
  * @r:		the regulator to enable
@@ -379,7 +407,7 @@ static void regulator_print_one(struct regulator_internal *ri)
 		printf(" consumers:\n");
 
 		list_for_each_entry(r, &ri->consumer_list, list)
-			printf("   %s\n", dev_name(r->dev));
+			printf("   %s\n", r->dev ? dev_name(r->dev) : "none");
 	}
 }
 
diff --git a/include/regulator.h b/include/regulator.h
index 156acb82f8..a445c5c3d1 100644
--- a/include/regulator.h
+++ b/include/regulator.h
@@ -116,6 +116,7 @@ void regulators_print(void);
 #ifdef CONFIG_REGULATOR
 
 struct regulator *regulator_get(struct device_d *, const char *);
+struct regulator *regulator_get_name(const char *name);
 int regulator_enable(struct regulator *);
 int regulator_disable(struct regulator *);
 int regulator_is_enabled_regmap(struct regulator_dev *);
-- 
2.24.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 07/10] rpi: Enable USB Power domain during startup
  2019-12-20 14:32 [PATCH 00/10] Add Raspberry Pi USB support Sascha Hauer
                   ` (5 preceding siblings ...)
  2019-12-20 14:32 ` [PATCH 06/10] regulator: add function to get regulator by its name Sascha Hauer
@ 2019-12-20 14:32 ` Sascha Hauer
  2019-12-20 14:32 ` [PATCH 08/10] usb: Forward error code from usb_set_configuration Sascha Hauer
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 24+ messages in thread
From: Sascha Hauer @ 2019-12-20 14:32 UTC (permalink / raw)
  To: Barebox List

Enable the USB Power domain during startup. The power domain is
abstracted as a regulator in barebox, but modelled as a power domain in
the device tree. Until this is sorted out just enable the power domain
or regulator in the board code.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/boards/raspberry-pi/rpi-common.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm/boards/raspberry-pi/rpi-common.c b/arch/arm/boards/raspberry-pi/rpi-common.c
index acb26f6a64..45961b52ee 100644
--- a/arch/arm/boards/raspberry-pi/rpi-common.c
+++ b/arch/arm/boards/raspberry-pi/rpi-common.c
@@ -21,6 +21,7 @@
 #include <linux/clk.h>
 #include <linux/clkdev.h>
 #include <envfs.h>
+#include <regulator.h>
 #include <malloc.h>
 #include <libfile.h>
 #include <gpio.h>
@@ -462,11 +463,20 @@ static void rpi_vc_fdt(void)
 
 static int rpi_devices_init(void)
 {
+	struct regulator *reg;
+
 	rpi_model_init();
 	bcm2835_register_fb();
 	armlinux_set_architecture(MACH_TYPE_BCM2708);
 	rpi_env_init();
 	rpi_vc_fdt();
+
+	reg = regulator_get_name("bcm2835_usb");
+	if (IS_ERR(reg))
+		return PTR_ERR(reg);
+
+	regulator_enable(reg);
+
 	return 0;
 }
 late_initcall(rpi_devices_init);
-- 
2.24.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 08/10] usb: Forward error code from usb_set_configuration
  2019-12-20 14:32 [PATCH 00/10] Add Raspberry Pi USB support Sascha Hauer
                   ` (6 preceding siblings ...)
  2019-12-20 14:32 ` [PATCH 07/10] rpi: Enable USB Power domain during startup Sascha Hauer
@ 2019-12-20 14:32 ` Sascha Hauer
  2019-12-20 14:32 ` [PATCH 09/10] usb: Add dwc2 host driver Sascha Hauer
  2019-12-20 14:32 ` [PATCH 10/10] ARM: rpi_defconfig: Enable networking support Sascha Hauer
  9 siblings, 0 replies; 24+ messages in thread
From: Sascha Hauer @ 2019-12-20 14:32 UTC (permalink / raw)
  To: Barebox List

Instead of returning -1 forward the error code and take the opportunity
to print the error string.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/usb/core/usb.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index ad3bacf236..1c3dcb79a8 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -124,7 +124,7 @@ static int usb_set_configuration(struct usb_device *dev, int configuration)
 		dev->toggle[1] = 0;
 		return 0;
 	} else
-		return -1;
+		return res;
 }
 
 /* The routine usb_set_maxpacket_ep() is extracted from the loop of routine
@@ -412,9 +412,11 @@ int usb_new_device(struct usb_device *dev)
 	usb_parse_config(dev, buf, 0);
 	usb_set_maxpacket(dev);
 	/* we set the default configuration here */
-	if (usb_set_configuration(dev, dev->config.desc.bConfigurationValue)) {
-		printf("failed to set default configuration " \
-			"len %d, status %lX\n", dev->act_len, dev->status);
+	err = usb_set_configuration(dev, dev->config.desc.bConfigurationValue);
+	if (err) {
+		printf("Setting default configuration failed with: %s\n" \
+			"len %d, status %lX\n", strerror(-err),
+		       dev->act_len, dev->status);
 		goto err_out;
 	}
 	pr_debug("new device: Mfr=%d, Product=%d, SerialNumber=%d\n",
-- 
2.24.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 09/10] usb: Add dwc2 host driver
  2019-12-20 14:32 [PATCH 00/10] Add Raspberry Pi USB support Sascha Hauer
                   ` (7 preceding siblings ...)
  2019-12-20 14:32 ` [PATCH 08/10] usb: Forward error code from usb_set_configuration Sascha Hauer
@ 2019-12-20 14:32 ` Sascha Hauer
  2020-01-14 13:21   ` [RFC PATCH 0/7] usb: " Jules Maselbas
  2019-12-20 14:32 ` [PATCH 10/10] ARM: rpi_defconfig: Enable networking support Sascha Hauer
  9 siblings, 1 reply; 24+ messages in thread
From: Sascha Hauer @ 2019-12-20 14:32 UTC (permalink / raw)
  To: Barebox List

This adds a driver for the dwc2 controller in host mode. The driver is
taken from U-Boot-2019.10 and tested on a Raspberry Pi 3.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/usb/host/Kconfig  |    3 +
 drivers/usb/host/Makefile |    1 +
 drivers/usb/host/dwc2.c   | 1132 +++++++++++++++++++++++++++++++++++++
 drivers/usb/host/dwc2.h   |  778 +++++++++++++++++++++++++
 4 files changed, 1914 insertions(+)
 create mode 100644 drivers/usb/host/dwc2.c
 create mode 100644 drivers/usb/host/dwc2.h

diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index d2029bc7d7..b0f32faee9 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -21,6 +21,9 @@ config USB_OHCI_AT91
 	depends on ARCH_AT91
 	bool "AT91 OHCI driver"
 
+config USB_DWC2_HOST
+	bool "DWC2 Host driver"
+
 config USB_XHCI
 	bool "xHCI driver"
 	depends on HAS_DMA
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 0478d34272..fa042e9a54 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -3,5 +3,6 @@ obj-$(CONFIG_USB_EHCI_OMAP)	+= ehci-omap.o
 obj-$(CONFIG_USB_EHCI_ATMEL)	+= ehci-atmel.o
 obj-$(CONFIG_USB_OHCI)		+= ohci-hcd.o
 obj-$(CONFIG_USB_OHCI_AT91)	+= ohci-at91.o
+obj-$(CONFIG_USB_DWC2_HOST)	+= dwc2.o
 obj-$(CONFIG_USB_XHCI)		+= xhci-hcd.o xhci-hub.o
 obj-$(CONFIG_USB_XHCI_PCI)	+= xhci-pci.o
diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c
new file mode 100644
index 0000000000..1df1149686
--- /dev/null
+++ b/drivers/usb/host/dwc2.c
@@ -0,0 +1,1132 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
+ * Copyright (C) 2014 Marek Vasut <marex@denx.de>
+ */
+
+#include <common.h>
+#include <usb/usb.h>
+#include <usb/usbroothubdes.h>
+#include <malloc.h>
+#include <init.h>
+#include <io.h>
+#include <of.h>
+#include <linux/iopoll.h>
+#include <dma.h>
+
+#include "dwc2.h"
+
+/* Use only HC channel 0. */
+#define DWC2_HC_CHANNEL			0
+
+#define DWC2_STATUS_BUF_SIZE		64
+#define DWC2_DATA_BUF_SIZE		(16 * 1024)
+
+#define MAX_DEVICE			16
+#define MAX_ENDPOINT			16
+
+struct dwc2_priv {
+	struct device_d *dev;
+	struct usb_host host;
+	uint8_t *dmabuf;
+
+	u8 in_data_toggle[MAX_DEVICE][MAX_ENDPOINT];
+	u8 out_data_toggle[MAX_DEVICE][MAX_ENDPOINT];
+	struct dwc2_core_regs *regs;
+	int root_hub_devnum;
+	bool ext_vbus;
+	/*
+	 * The hnp/srp capability must be disabled if the platform
+	 * does't support hnp/srp. Otherwise the force mode can't work.
+	 */
+	bool hnp_srp_disable;
+	bool oc_disable;
+};
+
+/*
+ * Initializes the FSLSPClkSel field of the HCFG register
+ * depending on the PHY type.
+ */
+static void init_fslspclksel(struct dwc2_priv *priv)
+{
+	struct dwc2_core_regs *regs = priv->regs;
+	uint32_t phyclk;
+
+	phyclk = DWC2_HCFG_FSLSPCLKSEL_48_MHZ;	/* Full speed PHY */
+
+	clrsetbits_le32(&regs->host_regs.hcfg,
+			DWC2_HCFG_FSLSPCLKSEL_MASK,
+			phyclk << DWC2_HCFG_FSLSPCLKSEL_OFFSET);
+}
+
+/*
+ * Flush a Tx FIFO.
+ *
+ * @param regs Programming view of DWC_otg controller.
+ * @param num Tx FIFO to flush.
+ */
+static void dwc_otg_flush_tx_fifo(struct dwc2_priv *priv, const int num)
+{
+	struct dwc2_core_regs *regs = priv->regs;
+	struct device_d *dev = priv->dev;
+	int ret;
+	uint32_t val;
+
+	writel(DWC2_GRSTCTL_TXFFLSH | (num << DWC2_GRSTCTL_TXFNUM_OFFSET),
+	       &regs->grstctl);
+	ret = readl_poll_timeout(&regs->grstctl, val, !(val & DWC2_GRSTCTL_TXFFLSH),
+				 1000000);
+	if (ret)
+		dev_err(dev, "%s: Timeout!\n", __func__);
+
+	/* Wait for 3 PHY Clocks */
+	udelay(1);
+}
+
+/*
+ * Flush Rx FIFO.
+ *
+ * @param regs Programming view of DWC_otg controller.
+ */
+static void dwc_otg_flush_rx_fifo(struct dwc2_priv *priv)
+{
+	struct dwc2_core_regs *regs = priv->regs;
+	struct device_d *dev = priv->dev;
+	int ret;
+	uint32_t val;
+
+	writel(DWC2_GRSTCTL_RXFFLSH, &regs->grstctl);
+	ret = readl_poll_timeout(&regs->grstctl, val, !(val & DWC2_GRSTCTL_RXFFLSH),
+				 1000000);
+	if (ret)
+		dev_err(dev, "%s: Timeout!\n", __func__);
+
+	/* Wait for 3 PHY Clocks */
+	udelay(1);
+}
+
+/*
+ * Do core a soft reset of the core.  Be careful with this because it
+ * resets all the internal state machines of the core.
+ */
+static void dwc_otg_core_reset(struct dwc2_priv *priv)
+{
+	struct dwc2_core_regs *regs = priv->regs;
+	struct device_d *dev = priv->dev;
+	uint32_t val;
+	int ret;
+
+	/* Wait for AHB master IDLE state. */
+	ret = readl_poll_timeout(&regs->grstctl, val, val & DWC2_GRSTCTL_AHBIDLE,
+				 1000000);
+	if (ret)
+		dev_err(dev, "%s: Timeout!\n", __func__);
+
+	/* Core Soft Reset */
+	writel(DWC2_GRSTCTL_CSFTRST, &regs->grstctl);
+	ret = readl_poll_timeout(&regs->grstctl, val, !(val & DWC2_GRSTCTL_CSFTRST),
+				 1000000);
+	if (ret)
+		dev_err(dev, "%s: Timeout!\n", __func__);
+
+	/*
+	 * Wait for core to come out of reset.
+	 * NOTE: This long sleep is _very_ important, otherwise the core will
+	 *       not stay in host mode after a connector ID change!
+	 */
+	mdelay(100);
+}
+
+/*
+ * This function initializes the DWC_otg controller registers for
+ * host mode.
+ *
+ * This function flushes the Tx and Rx FIFOs and it flushes any entries in the
+ * request queues. Host channels are reset to ensure that they are ready for
+ * performing transfers.
+ *
+ * @param dev USB Device (NULL if driver model is not being used)
+ * @param regs Programming view of DWC_otg controller
+ *
+ */
+static void dwc_otg_core_host_init(struct dwc2_priv *priv)
+{
+	struct dwc2_core_regs *regs = priv->regs;
+	struct device_d *dev = priv->dev;
+	uint32_t nptxfifosize = 0;
+	uint32_t ptxfifosize = 0;
+	uint32_t hprt0 = 0;
+	uint32_t val;
+	int i, ret, num_channels;
+
+	/* Restart the Phy Clock */
+	writel(0, &regs->pcgcctl);
+
+	/* Initialize Host Configuration Register */
+	init_fslspclksel(priv);
+
+	/* Configure data FIFO sizes */
+	if (readl(&regs->ghwcfg2) & DWC2_HWCFG2_DYNAMIC_FIFO) {
+		/* Rx FIFO */
+		writel(CONFIG_DWC2_HOST_RX_FIFO_SIZE, &regs->grxfsiz);
+
+		/* Non-periodic Tx FIFO */
+		nptxfifosize |= CONFIG_DWC2_HOST_NPERIO_TX_FIFO_SIZE <<
+				DWC2_FIFOSIZE_DEPTH_OFFSET;
+		nptxfifosize |= CONFIG_DWC2_HOST_RX_FIFO_SIZE <<
+				DWC2_FIFOSIZE_STARTADDR_OFFSET;
+		writel(nptxfifosize, &regs->gnptxfsiz);
+
+		/* Periodic Tx FIFO */
+		ptxfifosize |= CONFIG_DWC2_HOST_PERIO_TX_FIFO_SIZE <<
+				DWC2_FIFOSIZE_DEPTH_OFFSET;
+		ptxfifosize |= (CONFIG_DWC2_HOST_RX_FIFO_SIZE +
+				CONFIG_DWC2_HOST_NPERIO_TX_FIFO_SIZE) <<
+				DWC2_FIFOSIZE_STARTADDR_OFFSET;
+		writel(ptxfifosize, &regs->hptxfsiz);
+	}
+
+	/* Clear Host Set HNP Enable in the OTG Control Register */
+	clrbits_le32(&regs->gotgctl, DWC2_GOTGCTL_HSTSETHNPEN);
+
+	/* Make sure the FIFOs are flushed. */
+	dwc_otg_flush_tx_fifo(priv, 0x10);	/* All Tx FIFOs */
+	dwc_otg_flush_rx_fifo(priv);
+
+	/* Flush out any leftover queued requests. */
+	num_channels = readl(&regs->ghwcfg2);
+	num_channels &= DWC2_HWCFG2_NUM_HOST_CHAN_MASK;
+	num_channels >>= DWC2_HWCFG2_NUM_HOST_CHAN_OFFSET;
+	num_channels += 1;
+
+	for (i = 0; i < num_channels; i++)
+		clrsetbits_le32(&regs->hc_regs[i].hcchar,
+				DWC2_HCCHAR_CHEN | DWC2_HCCHAR_EPDIR,
+				DWC2_HCCHAR_CHDIS);
+
+	/* Halt all channels to put them into a known state. */
+	for (i = 0; i < num_channels; i++) {
+		clrsetbits_le32(&regs->hc_regs[i].hcchar,
+				DWC2_HCCHAR_EPDIR,
+				DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS);
+		ret = readl_poll_timeout(&regs->hc_regs[i].hcchar, val,
+				 !(val & DWC2_HCCHAR_CHEN),
+				 1000000);
+		if (ret)
+			dev_err(dev, "%s: Timeout!\n", __func__);
+	}
+
+	/* Turn on the vbus power. */
+	if (readl(&regs->gintsts) & DWC2_GINTSTS_CURMODE_HOST) {
+		hprt0 = readl(&regs->hprt0);
+		hprt0 &= ~(DWC2_HPRT0_PRTENA | DWC2_HPRT0_PRTCONNDET);
+		hprt0 &= ~(DWC2_HPRT0_PRTENCHNG | DWC2_HPRT0_PRTOVRCURRCHNG);
+		if (!(hprt0 & DWC2_HPRT0_PRTPWR)) {
+			hprt0 |= DWC2_HPRT0_PRTPWR;
+			writel(hprt0, &regs->hprt0);
+		}
+	}
+}
+
+/*
+ * This function initializes the DWC_otg controller registers and
+ * prepares the core for device mode or host mode operation.
+ *
+ * @param regs Programming view of the DWC_otg controller
+ */
+static void dwc_otg_core_init(struct dwc2_priv *priv)
+{
+	struct dwc2_core_regs *regs = priv->regs;
+	uint32_t ahbcfg = 0;
+	uint32_t usbcfg = 0;
+	uint8_t brst_sz = 32;
+
+	/* Common Initialization */
+	usbcfg = readl(&regs->gusbcfg);
+
+	/* Program the ULPI External VBUS bit if needed */
+	if (priv->ext_vbus) {
+		usbcfg |= DWC2_GUSBCFG_ULPI_EXT_VBUS_DRV;
+		if (!priv->oc_disable) {
+			usbcfg |= DWC2_GUSBCFG_ULPI_INT_VBUS_INDICATOR |
+				  DWC2_GUSBCFG_INDICATOR_PASSTHROUGH;
+		}
+	} else {
+		usbcfg &= ~DWC2_GUSBCFG_ULPI_EXT_VBUS_DRV;
+	}
+
+	/* Set external TS Dline pulsing */
+	usbcfg &= ~DWC2_GUSBCFG_TERM_SEL_DL_PULSE;
+	writel(usbcfg, &regs->gusbcfg);
+
+	/* Reset the Controller */
+	dwc_otg_core_reset(priv);
+
+	/* High speed PHY. */
+
+	/*
+	 * HS PHY parameters. These parameters are preserved during
+	 * soft reset so only program the first time. Do a soft reset
+	 * immediately after setting phyif.
+	 */
+	usbcfg &= ~(DWC2_GUSBCFG_ULPI_UTMI_SEL | DWC2_GUSBCFG_PHYIF);
+	usbcfg |= CONFIG_DWC2_PHY_TYPE << DWC2_GUSBCFG_ULPI_UTMI_SEL_OFFSET;
+
+	if (usbcfg & DWC2_GUSBCFG_ULPI_UTMI_SEL) /* ULPI interface */
+		usbcfg &= ~DWC2_GUSBCFG_DDRSEL;
+
+	writel(usbcfg, &regs->gusbcfg);
+
+	/* Reset after setting the PHY parameters */
+	dwc_otg_core_reset(priv);
+
+	usbcfg = readl(&regs->gusbcfg);
+	usbcfg &= ~(DWC2_GUSBCFG_ULPI_FSLS | DWC2_GUSBCFG_ULPI_CLK_SUS_M);
+
+	if (priv->hnp_srp_disable)
+		usbcfg |= DWC2_GUSBCFG_FORCEHOSTMODE;
+
+	writel(usbcfg, &regs->gusbcfg);
+
+	/* Program the GAHBCFG Register. */
+	switch (readl(&regs->ghwcfg2) & DWC2_HWCFG2_ARCHITECTURE_MASK) {
+	case DWC2_HWCFG2_ARCHITECTURE_SLAVE_ONLY:
+		break;
+	case DWC2_HWCFG2_ARCHITECTURE_EXT_DMA:
+		while (brst_sz > 1) {
+			ahbcfg |= ahbcfg + (1 << DWC2_GAHBCFG_HBURSTLEN_OFFSET);
+			ahbcfg &= DWC2_GAHBCFG_HBURSTLEN_MASK;
+			brst_sz >>= 1;
+		}
+
+		ahbcfg |= DWC2_GAHBCFG_DMAENABLE;
+		break;
+
+	case DWC2_HWCFG2_ARCHITECTURE_INT_DMA:
+		ahbcfg |= DWC2_GAHBCFG_HBURSTLEN_INCR4;
+		ahbcfg |= DWC2_GAHBCFG_DMAENABLE;
+		break;
+	}
+
+	writel(ahbcfg, &regs->gahbcfg);
+
+	/* Program the capabilities in GUSBCFG Register */
+	usbcfg = 0;
+
+	if (!priv->hnp_srp_disable)
+		usbcfg |= DWC2_GUSBCFG_HNPCAP | DWC2_GUSBCFG_SRPCAP;
+
+	setbits_le32(&regs->gusbcfg, usbcfg);
+}
+
+/*
+ * Prepares a host channel for transferring packets to/from a specific
+ * endpoint. The HCCHARn register is set up with the characteristics specified
+ * in _hc. Host channel interrupts that may need to be serviced while this
+ * transfer is in progress are enabled.
+ *
+ * @param regs Programming view of DWC_otg controller
+ * @param hc Information needed to initialize the host channel
+ */
+static void dwc_otg_hc_init(struct dwc2_core_regs *regs, uint8_t hc_num,
+		struct usb_device *dev, uint8_t dev_addr, uint8_t ep_num,
+		uint8_t ep_is_in, uint8_t ep_type, uint16_t max_packet)
+{
+	struct dwc2_hc_regs *hc_regs = &regs->hc_regs[hc_num];
+	uint32_t hcchar = (dev_addr << DWC2_HCCHAR_DEVADDR_OFFSET) |
+			  (ep_num << DWC2_HCCHAR_EPNUM_OFFSET) |
+			  (ep_is_in << DWC2_HCCHAR_EPDIR_OFFSET) |
+			  (ep_type << DWC2_HCCHAR_EPTYPE_OFFSET) |
+			  (max_packet << DWC2_HCCHAR_MPS_OFFSET);
+
+	if (dev->speed == USB_SPEED_LOW)
+		hcchar |= DWC2_HCCHAR_LSPDDEV;
+
+	/*
+	 * Program the HCCHARn register with the endpoint characteristics
+	 * for the current transfer.
+	 */
+	writel(hcchar, &hc_regs->hcchar);
+
+	/* Program the HCSPLIT register, default to no SPLIT */
+	writel(0, &hc_regs->hcsplt);
+}
+
+static void dwc_otg_hc_init_split(struct dwc2_hc_regs *hc_regs,
+				  uint8_t hub_devnum, uint8_t hub_port)
+{
+	uint32_t hcsplt = 0;
+
+	hcsplt = DWC2_HCSPLT_SPLTENA;
+	hcsplt |= hub_devnum << DWC2_HCSPLT_HUBADDR_OFFSET;
+	hcsplt |= hub_port << DWC2_HCSPLT_PRTADDR_OFFSET;
+
+	/* Program the HCSPLIT register for SPLITs */
+	writel(hcsplt, &hc_regs->hcsplt);
+}
+
+/*
+ * DWC2 to USB API interface
+ */
+/* Direction: In ; Request: Status */
+static int dwc_otg_submit_rh_msg_in_status(struct dwc2_core_regs *regs,
+					   struct usb_device *dev, void *buffer,
+					   int txlen, struct devrequest *cmd)
+{
+	uint32_t hprt0 = 0;
+	uint32_t port_status = 0;
+	uint32_t port_change = 0;
+	int len = 0;
+	int stat = 0;
+
+	switch (cmd->requesttype & ~USB_DIR_IN) {
+	case 0:
+		*(uint16_t *)buffer = cpu_to_le16(1);
+		len = 2;
+		break;
+	case USB_RECIP_INTERFACE:
+	case USB_RECIP_ENDPOINT:
+		*(uint16_t *)buffer = cpu_to_le16(0);
+		len = 2;
+		break;
+	case USB_TYPE_CLASS:
+		*(uint32_t *)buffer = cpu_to_le32(0);
+		len = 4;
+		break;
+	case USB_RECIP_OTHER | USB_TYPE_CLASS:
+		hprt0 = readl(&regs->hprt0);
+		if (hprt0 & DWC2_HPRT0_PRTCONNSTS)
+			port_status |= USB_PORT_STAT_CONNECTION;
+		if (hprt0 & DWC2_HPRT0_PRTENA)
+			port_status |= USB_PORT_STAT_ENABLE;
+		if (hprt0 & DWC2_HPRT0_PRTSUSP)
+			port_status |= USB_PORT_STAT_SUSPEND;
+		if (hprt0 & DWC2_HPRT0_PRTOVRCURRACT)
+			port_status |= USB_PORT_STAT_OVERCURRENT;
+		if (hprt0 & DWC2_HPRT0_PRTRST)
+			port_status |= USB_PORT_STAT_RESET;
+		if (hprt0 & DWC2_HPRT0_PRTPWR)
+			port_status |= USB_PORT_STAT_POWER;
+
+		if ((hprt0 & DWC2_HPRT0_PRTSPD_MASK) == DWC2_HPRT0_PRTSPD_LOW)
+			port_status |= USB_PORT_STAT_LOW_SPEED;
+		else if ((hprt0 & DWC2_HPRT0_PRTSPD_MASK) ==
+			 DWC2_HPRT0_PRTSPD_HIGH)
+			port_status |= USB_PORT_STAT_HIGH_SPEED;
+
+		if (hprt0 & DWC2_HPRT0_PRTENCHNG)
+			port_change |= USB_PORT_STAT_C_ENABLE;
+		if (hprt0 & DWC2_HPRT0_PRTCONNDET)
+			port_change |= USB_PORT_STAT_C_CONNECTION;
+		if (hprt0 & DWC2_HPRT0_PRTOVRCURRCHNG)
+			port_change |= USB_PORT_STAT_C_OVERCURRENT;
+
+		*(uint32_t *)buffer = cpu_to_le32(port_status |
+					(port_change << 16));
+		len = 4;
+		break;
+	default:
+		pr_err("%s: unsupported root hub command\n", __func__);
+		stat = USB_ST_STALLED;
+	}
+
+	dev->act_len = min(len, txlen);
+	dev->status = stat;
+
+	return stat;
+}
+
+/* Direction: In ; Request: Descriptor */
+static int dwc_otg_submit_rh_msg_in_descriptor(struct usb_device *dev,
+					       void *buffer, int txlen,
+					       struct devrequest *cmd)
+{
+	unsigned char data[32];
+	uint32_t dsc;
+	int len = 0;
+	int stat = 0;
+	uint16_t wValue = cpu_to_le16(cmd->value);
+	uint16_t wLength = cpu_to_le16(cmd->length);
+
+	switch (cmd->requesttype & ~USB_DIR_IN) {
+	case 0:
+		switch (wValue & 0xff00) {
+		case 0x0100:	/* device descriptor */
+			len = min3(txlen, (int)sizeof(root_hub_dev_des), (int)wLength);
+			memcpy(buffer, root_hub_dev_des, len);
+			break;
+		case 0x0200:	/* configuration descriptor */
+			len = min3(txlen, (int)sizeof(root_hub_config_des), (int)wLength);
+			memcpy(buffer, root_hub_config_des, len);
+			break;
+		case 0x0300:	/* string descriptors */
+			switch (wValue & 0xff) {
+			case 0x00:
+				len = min3(txlen, (int)sizeof(root_hub_str_index0),
+					   (int)wLength);
+				memcpy(buffer, root_hub_str_index0, len);
+				break;
+			case 0x01:
+				len = min3(txlen, (int)sizeof(root_hub_str_index1),
+					   (int)wLength);
+				memcpy(buffer, root_hub_str_index1, len);
+				break;
+			}
+			break;
+		default:
+			stat = USB_ST_STALLED;
+		}
+		break;
+
+	case USB_TYPE_CLASS:
+		/* Root port config, set 1 port and nothing else. */
+		dsc = 0x00000001;
+
+		data[0] = 9;		/* min length; */
+		data[1] = 0x29;
+		data[2] = dsc & RH_A_NDP;
+		data[3] = 0;
+		if (dsc & RH_A_PSM)
+			data[3] |= 0x1;
+		if (dsc & RH_A_NOCP)
+			data[3] |= 0x10;
+		else if (dsc & RH_A_OCPM)
+			data[3] |= 0x8;
+
+		/* corresponds to data[4-7] */
+		data[5] = (dsc & RH_A_POTPGT) >> 24;
+		data[7] = dsc & RH_B_DR;
+		if (data[2] < 7) {
+			data[8] = 0xff;
+		} else {
+			data[0] += 2;
+			data[8] = (dsc & RH_B_DR) >> 8;
+			data[9] = 0xff;
+			data[10] = data[9];
+		}
+
+		len = min3(txlen, (int)data[0], (int)wLength);
+		memcpy(buffer, data, len);
+		break;
+	default:
+		pr_err("%s: unsupported root hub command\n", __func__);
+		stat = USB_ST_STALLED;
+	}
+
+	dev->act_len = min(len, txlen);
+	dev->status = stat;
+
+	return stat;
+}
+
+/* Direction: In ; Request: Configuration */
+static int dwc_otg_submit_rh_msg_in_configuration(struct usb_device *dev,
+						  void *buffer, int txlen,
+						  struct devrequest *cmd)
+{
+	int len = 0;
+	int stat = 0;
+
+	switch (cmd->requesttype & ~USB_DIR_IN) {
+	case 0:
+		*(uint8_t *)buffer = 0x01;
+		len = 1;
+		break;
+	default:
+		pr_err("%s: unsupported root hub command\n", __func__);
+		stat = USB_ST_STALLED;
+	}
+
+	dev->act_len = min(len, txlen);
+	dev->status = stat;
+
+	return stat;
+}
+
+/* Direction: In */
+static int dwc_otg_submit_rh_msg_in(struct dwc2_priv *priv,
+				    struct usb_device *dev, void *buffer,
+				    int txlen, struct devrequest *cmd)
+{
+	switch (cmd->request) {
+	case USB_REQ_GET_STATUS:
+		return dwc_otg_submit_rh_msg_in_status(priv->regs, dev, buffer,
+						       txlen, cmd);
+	case USB_REQ_GET_DESCRIPTOR:
+		return dwc_otg_submit_rh_msg_in_descriptor(dev, buffer,
+							   txlen, cmd);
+	case USB_REQ_GET_CONFIGURATION:
+		return dwc_otg_submit_rh_msg_in_configuration(dev, buffer,
+							      txlen, cmd);
+	default:
+		pr_err("%s: unsupported root hub command\n", __func__);
+		return USB_ST_STALLED;
+	}
+}
+
+/* Direction: Out */
+static int dwc_otg_submit_rh_msg_out(struct dwc2_priv *priv,
+				     struct usb_device *dev,
+				     void *buffer, int txlen,
+				     struct devrequest *cmd)
+{
+	struct dwc2_core_regs *regs = priv->regs;
+	int len = 0;
+	int stat = 0;
+	uint16_t bmrtype_breq = cmd->requesttype | (cmd->request << 8);
+	uint16_t wValue = cpu_to_le16(cmd->value);
+
+	switch (bmrtype_breq & ~USB_DIR_IN) {
+	case (USB_REQ_CLEAR_FEATURE << 8) | USB_RECIP_ENDPOINT:
+	case (USB_REQ_CLEAR_FEATURE << 8) | USB_TYPE_CLASS:
+		break;
+
+	case (USB_REQ_CLEAR_FEATURE << 8) | USB_RECIP_OTHER | USB_TYPE_CLASS:
+		switch (wValue) {
+		case USB_PORT_FEAT_C_CONNECTION:
+			setbits_le32(&regs->hprt0, DWC2_HPRT0_PRTCONNDET);
+			break;
+		}
+		break;
+
+	case (USB_REQ_SET_FEATURE << 8) | USB_RECIP_OTHER | USB_TYPE_CLASS:
+		switch (wValue) {
+		case USB_PORT_FEAT_SUSPEND:
+			break;
+
+		case USB_PORT_FEAT_RESET:
+			clrsetbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA |
+					DWC2_HPRT0_PRTCONNDET |
+					DWC2_HPRT0_PRTENCHNG |
+					DWC2_HPRT0_PRTOVRCURRCHNG,
+					DWC2_HPRT0_PRTRST);
+			mdelay(50);
+			clrbits_le32(&regs->hprt0, DWC2_HPRT0_PRTRST);
+			break;
+
+		case USB_PORT_FEAT_POWER:
+			clrsetbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA |
+					DWC2_HPRT0_PRTCONNDET |
+					DWC2_HPRT0_PRTENCHNG |
+					DWC2_HPRT0_PRTOVRCURRCHNG,
+					DWC2_HPRT0_PRTRST);
+			break;
+
+		case USB_PORT_FEAT_ENABLE:
+			break;
+		}
+		break;
+	case (USB_REQ_SET_ADDRESS << 8):
+		priv->root_hub_devnum = wValue;
+		break;
+	case (USB_REQ_SET_CONFIGURATION << 8):
+		break;
+	default:
+		pr_err("%s: unsupported root hub command\n", __func__);
+		stat = USB_ST_STALLED;
+	}
+
+	len = min(len, txlen);
+
+	dev->act_len = len;
+	dev->status = stat;
+
+	return stat;
+}
+
+static int dwc_otg_submit_rh_msg(struct dwc2_priv *priv, struct usb_device *dev,
+				 unsigned long pipe, void *buffer, int txlen,
+				 struct devrequest *cmd)
+{
+	int stat = 0;
+
+	if (usb_pipeint(pipe)) {
+		pr_err("Root-Hub submit IRQ: NOT implemented\n");
+		return 0;
+	}
+
+	if (cmd->requesttype & USB_DIR_IN)
+		stat = dwc_otg_submit_rh_msg_in(priv, dev, buffer, txlen, cmd);
+	else
+		stat = dwc_otg_submit_rh_msg_out(priv, dev, buffer, txlen, cmd);
+
+	mdelay(1);
+
+	return stat;
+}
+
+static int wait_for_chhltd(struct dwc2_priv *priv, uint32_t *sub,
+			   u8 *toggle, int timeout_ms)
+{
+	struct dwc2_core_regs *regs = priv->regs;
+	struct dwc2_hc_regs *hc_regs = &regs->hc_regs[DWC2_HC_CHANNEL];
+	struct device_d *dev = priv->dev;
+	int ret;
+	uint32_t hcint, hctsiz;
+	uint32_t val;
+	int timeout_us = timeout_ms * 1000;
+
+	ret = readl_poll_timeout(&hc_regs->hcint, val,
+				 val & DWC2_HCINT_CHHLTD, timeout_us);
+	if (ret) {
+		clrsetbits_le32(&hc_regs->hcchar, 0, DWC2_HCCHAR_CHDIS);
+		readl_poll_timeout(&hc_regs->hcint, val,
+					 val & DWC2_HCINT_CHHLTD, 10000);
+
+		return ret;
+	}
+
+	hcint = readl(&hc_regs->hcint);
+	hctsiz = readl(&hc_regs->hctsiz);
+	*sub = (hctsiz & DWC2_HCTSIZ_XFERSIZE_MASK) >>
+		DWC2_HCTSIZ_XFERSIZE_OFFSET;
+	*toggle = (hctsiz & DWC2_HCTSIZ_PID_MASK) >> DWC2_HCTSIZ_PID_OFFSET;
+
+	dev_dbg(dev, "%s: HCINT=%08x sub=%u toggle=%d\n", __func__, hcint, *sub,
+	      *toggle);
+
+	if (hcint & DWC2_HCINT_XFERCOMP)
+		return 0;
+
+	if (hcint & (DWC2_HCINT_NAK | DWC2_HCINT_FRMOVRUN))
+		return -EAGAIN;
+
+	dev_dbg(dev, "%s: Error (HCINT=%08x)\n", __func__, hcint);
+
+	return -EINVAL;
+}
+
+static int dwc2_eptype[] = {
+	DWC2_HCCHAR_EPTYPE_ISOC,
+	DWC2_HCCHAR_EPTYPE_INTR,
+	DWC2_HCCHAR_EPTYPE_CONTROL,
+	DWC2_HCCHAR_EPTYPE_BULK,
+};
+
+static int transfer_chunk(struct dwc2_priv *priv, u8 *pid, int in, void *buffer,
+			  int num_packets, int xfer_len, int *actual_len,
+			  int odd_frame, int timeout_ms)
+{
+	struct dwc2_core_regs *regs = priv->regs;
+	struct dwc2_hc_regs *hc_regs = &regs->hc_regs[DWC2_HC_CHANNEL];
+	int ret = 0;
+	uint32_t sub = 0;
+	enum dma_data_direction dir;
+	dma_addr_t dma = 0;
+
+	dev_dbg(priv->dev, "%s: chunk: pid %d xfer_len %u pkts %u\n",
+		__func__, *pid, xfer_len, num_packets);
+
+	writel((xfer_len << DWC2_HCTSIZ_XFERSIZE_OFFSET) |
+	       (num_packets << DWC2_HCTSIZ_PKTCNT_OFFSET) |
+	       (*pid << DWC2_HCTSIZ_PID_OFFSET),
+	       &hc_regs->hctsiz);
+
+	if (xfer_len) {
+		if (in) {
+			dir = DMA_FROM_DEVICE;
+		} else {
+			memcpy(priv->dmabuf, buffer, xfer_len);
+			dir = DMA_TO_DEVICE;
+		}
+		dma = dma_map_single(priv->dev, priv->dmabuf, xfer_len, dir);
+	}
+
+	writel(dma, &hc_regs->hcdma);
+
+	/* Clear old interrupt conditions for this host channel. */
+	writel(0x3fff, &hc_regs->hcint);
+
+	/* Set host channel enable after all other setup is complete. */
+	clrsetbits_le32(&hc_regs->hcchar, DWC2_HCCHAR_MULTICNT_MASK |
+			DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS |
+			DWC2_HCCHAR_ODDFRM,
+			(1 << DWC2_HCCHAR_MULTICNT_OFFSET) |
+			(odd_frame << DWC2_HCCHAR_ODDFRM_OFFSET) |
+			DWC2_HCCHAR_CHEN);
+
+	ret = wait_for_chhltd(priv, &sub, pid, timeout_ms);
+
+	if (xfer_len)
+		dma_unmap_single(priv->dev, dma, xfer_len, dir);
+
+	if (in) {
+		xfer_len -= sub;
+
+		memcpy(buffer, priv->dmabuf, xfer_len);
+	}
+
+	if (!ret)
+		*actual_len = xfer_len;
+
+	return ret;
+}
+
+static int usb_find_usb2_hub_address_port(struct usb_device *udev,
+                               uint8_t *hub_address, uint8_t *hub_port)
+{
+	/* Find out the nearest parent which is high speed */
+	while (udev->parent->parent) {
+		if (udev->parent->speed != USB_SPEED_HIGH) {
+			udev = udev->parent;
+		} else {
+			*hub_address = udev->parent->devnum;
+			*hub_port = udev->portnr;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int chunk_msg(struct dwc2_priv *priv, struct usb_device *dev,
+	      unsigned long pipe, u8 *pid, int in, void *buffer, int len,
+	      int timeout_ms)
+{
+	struct dwc2_core_regs *regs = priv->regs;
+	struct dwc2_hc_regs *hc_regs = &regs->hc_regs[DWC2_HC_CHANNEL];
+	struct dwc2_host_regs *host_regs = &regs->host_regs;
+	int devnum = usb_pipedevice(pipe);
+	int ep = usb_pipeendpoint(pipe);
+	int max = usb_maxpacket(dev, pipe);
+	int eptype = dwc2_eptype[usb_pipetype(pipe)];
+	int done = 0;
+	int ret = 0;
+	int do_split = 0;
+	int complete_split = 0;
+	uint32_t xfer_len;
+	uint32_t num_packets;
+	int stop_transfer = 0;
+	uint32_t max_xfer_len;
+	int ssplit_frame_num = 0;
+
+	dev_dbg(priv->dev, "%s: msg: pipe %lx pid %d in %d len %d\n",
+		__func__, pipe, *pid, in, len);
+
+	max_xfer_len = CONFIG_DWC2_MAX_PACKET_COUNT * max;
+	if (max_xfer_len > CONFIG_DWC2_MAX_TRANSFER_SIZE)
+		max_xfer_len = CONFIG_DWC2_MAX_TRANSFER_SIZE;
+	if (max_xfer_len > DWC2_DATA_BUF_SIZE)
+		max_xfer_len = DWC2_DATA_BUF_SIZE;
+
+	/* Make sure that max_xfer_len is a multiple of max packet size. */
+	num_packets = max_xfer_len / max;
+	max_xfer_len = num_packets * max;
+
+	/* Initialize channel */
+	dwc_otg_hc_init(regs, DWC2_HC_CHANNEL, dev, devnum, ep, in,
+			eptype, max);
+
+	/* Check if the target is a FS/LS device behind a HS hub */
+	if (dev->speed != USB_SPEED_HIGH) {
+		uint8_t hub_addr;
+		uint8_t hub_port;
+		uint32_t hprt0 = readl(&regs->hprt0);
+
+		if ((hprt0 & DWC2_HPRT0_PRTSPD_MASK) == DWC2_HPRT0_PRTSPD_HIGH) {
+			ret = usb_find_usb2_hub_address_port(dev, &hub_addr,
+						       &hub_port);
+			if (ret)
+				return ret;
+			dwc_otg_hc_init_split(hc_regs, hub_addr, hub_port);
+
+			do_split = 1;
+			num_packets = 1;
+			max_xfer_len = max;
+		}
+	}
+
+	do {
+		int actual_len = 0;
+		uint32_t hcint;
+		int odd_frame = 0;
+		xfer_len = len - done;
+
+		if (xfer_len > max_xfer_len)
+			xfer_len = max_xfer_len;
+		else if (xfer_len > max)
+			num_packets = (xfer_len + max - 1) / max;
+		else
+			num_packets = 1;
+
+		if (complete_split)
+			setbits_le32(&hc_regs->hcsplt, DWC2_HCSPLT_COMPSPLT);
+		else if (do_split)
+			clrbits_le32(&hc_regs->hcsplt, DWC2_HCSPLT_COMPSPLT);
+
+		if (eptype == DWC2_HCCHAR_EPTYPE_INTR) {
+			int uframe_num = readl(&host_regs->hfnum);
+			if (!(uframe_num & 0x1))
+				odd_frame = 1;
+		}
+
+		ret = transfer_chunk(priv, pid, in, (char *)buffer + done,
+				     num_packets, xfer_len, &actual_len,
+				     odd_frame, timeout_ms);
+
+		hcint = readl(&hc_regs->hcint);
+		if (complete_split) {
+			stop_transfer = 0;
+			if (hcint & DWC2_HCINT_NYET) {
+				int frame_num = DWC2_HFNUM_MAX_FRNUM &
+						readl(&host_regs->hfnum);
+				ret = 0;
+				if (((frame_num - ssplit_frame_num) &
+				    DWC2_HFNUM_MAX_FRNUM) > 4)
+					ret = -EAGAIN;
+			} else
+				complete_split = 0;
+		} else if (do_split) {
+			if (hcint & DWC2_HCINT_ACK) {
+				ssplit_frame_num = DWC2_HFNUM_MAX_FRNUM &
+						   readl(&host_regs->hfnum);
+				ret = 0;
+				complete_split = 1;
+			}
+		}
+
+		if (ret)
+			break;
+
+		if (actual_len < xfer_len)
+			stop_transfer = 1;
+
+		done += actual_len;
+
+	/*
+	 * Transactions are done when when either all data is transferred or
+	 * there is a short transfer. In case of a SPLIT make sure the CSPLIT
+	 * is executed.
+	 */
+	} while (((done < len) && !stop_transfer) || complete_split);
+
+	writel(0, &hc_regs->hcintmsk);
+	writel(0xFFFFFFFF, &hc_regs->hcint);
+
+	dev->status = 0;
+	dev->act_len = done;
+
+	return ret;
+}
+
+#define to_dwc2(ptr) container_of(ptr, struct dwc2_priv, host)
+
+static int dwc2_init_common(struct usb_host *host)
+{
+	struct dwc2_priv *priv = to_dwc2(host);
+	struct dwc2_core_regs *regs = priv->regs;
+	int i, j;
+
+	priv->ext_vbus = 0;
+
+	dwc_otg_core_init(priv);
+	dwc_otg_core_host_init(priv);
+
+	clrsetbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA |
+			DWC2_HPRT0_PRTCONNDET | DWC2_HPRT0_PRTENCHNG |
+			DWC2_HPRT0_PRTOVRCURRCHNG,
+			DWC2_HPRT0_PRTRST);
+	mdelay(50);
+	clrbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA | DWC2_HPRT0_PRTCONNDET |
+		     DWC2_HPRT0_PRTENCHNG | DWC2_HPRT0_PRTOVRCURRCHNG |
+		     DWC2_HPRT0_PRTRST);
+
+	for (i = 0; i < MAX_DEVICE; i++) {
+		for (j = 0; j < MAX_ENDPOINT; j++) {
+			priv->in_data_toggle[i][j] = DWC2_HC_PID_DATA0;
+			priv->out_data_toggle[i][j] = DWC2_HC_PID_DATA0;
+		}
+	}
+
+	return 0;
+}
+
+static void dwc2_uninit_common(struct dwc2_core_regs *regs)
+{
+	/* Put everything in reset. */
+	clrsetbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA |
+			DWC2_HPRT0_PRTCONNDET | DWC2_HPRT0_PRTENCHNG |
+			DWC2_HPRT0_PRTOVRCURRCHNG,
+			DWC2_HPRT0_PRTRST);
+}
+
+static int dwc2_submit_control_msg(struct usb_device *udev,
+				   unsigned long pipe, void *buffer, int len,
+				   struct devrequest *setup, int timeout_ms)
+{
+	struct usb_host *host = udev->host;
+	struct dwc2_priv *priv = to_dwc2(host);
+	int devnum = usb_pipedevice(pipe);
+	int ret, act_len;
+	u8 pid;
+	/* For CONTROL endpoint pid should start with DATA1 */
+	int status_direction;
+
+	if (devnum == priv->root_hub_devnum) {
+		udev->status = 0;
+		udev->speed = USB_SPEED_HIGH;
+		return dwc_otg_submit_rh_msg(priv, udev, pipe, buffer, len,
+					     setup);
+	}
+
+	/* SETUP stage */
+	pid = DWC2_HC_PID_SETUP;
+	do {
+		ret = chunk_msg(priv, udev, pipe, &pid, 0, setup, 8, timeout_ms);
+	} while (ret == -EAGAIN);
+
+	if (ret)
+		return ret;
+
+	/* DATA stage */
+	act_len = 0;
+	if (buffer) {
+		pid = DWC2_HC_PID_DATA1;
+		do {
+			ret = chunk_msg(priv, udev, pipe, &pid, usb_pipein(pipe),
+					buffer, len, timeout_ms);
+			act_len += udev->act_len;
+			buffer += udev->act_len;
+			len -= udev->act_len;
+		} while (ret == -EAGAIN);
+		if (ret)
+			return ret;
+		status_direction = usb_pipeout(pipe);
+	} else {
+		/* No-data CONTROL always ends with an IN transaction */
+		status_direction = 1;
+	}
+
+	/* STATUS stage */
+	pid = DWC2_HC_PID_DATA1;
+	do {
+		ret = chunk_msg(priv, udev, pipe, &pid, status_direction,
+				NULL, 0, timeout_ms);
+	} while (ret == -EAGAIN);
+
+	if (ret)
+		return ret;
+
+	udev->act_len = act_len;
+
+	return 0;
+}
+
+static int dwc2_submit_bulk_msg(struct usb_device *udev, unsigned long pipe,
+				void *buffer, int len, int timeout_ms)
+{
+	struct usb_host *host = udev->host;
+	struct dwc2_priv *priv = to_dwc2(host);
+	int devnum = usb_pipedevice(pipe);
+	int ep = usb_pipeendpoint(pipe);
+	u8* pid;
+
+	if ((devnum >= MAX_DEVICE) || (devnum == priv->root_hub_devnum)) {
+		udev->status = 0;
+		return -EINVAL;
+	}
+
+	if (usb_pipein(pipe))
+		pid = &priv->in_data_toggle[devnum][ep];
+	else
+		pid = &priv->out_data_toggle[devnum][ep];
+
+	return chunk_msg(priv, udev, pipe, pid, usb_pipein(pipe), buffer, len,
+			 timeout_ms);
+}
+
+static int dwc2_submit_int_msg(struct usb_device *udev, unsigned long pipe,
+			       void *buffer, int len, int interval)
+{
+	uint64_t start;
+	int ret;
+
+	start = get_time_ns();
+
+	while (1) {
+		ret = dwc2_submit_bulk_msg(udev, pipe, buffer, len, 0);
+		if (ret != -EAGAIN)
+			return ret;
+		if (is_timeout(start, USB_CNTL_TIMEOUT * MSECOND))
+			return -ETIMEDOUT;
+	}
+}
+
+static int dwc2_detect(struct device_d *dev)
+{
+	struct dwc2_priv *priv = dev->priv;
+
+        return usb_host_detect(&priv->host);
+}
+
+static int dwc2_probe(struct device_d *dev)
+{
+	struct resource *iores;
+	struct dwc2_priv *priv;
+	struct usb_host *host;
+	struct device_node *np = dev->device_node;
+	int ret;
+	uint32_t snpsid;
+
+	priv = xzalloc(sizeof(*priv));
+
+	iores = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(iores))
+		return PTR_ERR(iores);
+
+	priv->regs = IOMEM(iores->start);
+	priv->dev = dev;
+
+	snpsid = readl(&priv->regs->gsnpsid);
+	dev_info(dev, "Core Release: %x.%03x\n",
+		 snpsid >> 12 & 0xf, snpsid & 0xfff);
+
+	if ((snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_2xx &&
+	    (snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_3xx) {
+		dev_info(dev, "SNPSID invalid (not DWC2 OTG device): %08x\n",
+			 snpsid);
+		return -ENODEV;
+	}
+
+	priv->oc_disable = of_property_read_bool(np, "disable-over-current");
+	priv->hnp_srp_disable = of_property_read_bool(np, "hnp-srp-disable");
+	priv->dmabuf = dma_alloc(DWC2_DATA_BUF_SIZE);
+
+	host = &priv->host;
+
+	host->init = dwc2_init_common;
+	host->submit_int_msg = dwc2_submit_int_msg;
+	host->submit_control_msg = dwc2_submit_control_msg;
+	host->submit_bulk_msg = dwc2_submit_bulk_msg;
+
+	dev->priv = priv;
+	dev->detect = dwc2_detect;
+
+	ret = usb_register_host(host);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void dwc2_remove(struct device_d *dev)
+{
+	struct dwc2_priv *priv = dev->priv;
+
+	dwc2_uninit_common(priv->regs);
+}
+
+static const struct of_device_id dwc2_dt_ids[] = {
+	{ .compatible = "brcm,bcm2835-usb" },
+	{ .compatible = "brcm,bcm2708-usb" },
+	{ .compatible = "snps,dwc2" },
+	{ /* sentinel */ }
+};
+
+static struct driver_d dwc2_driver = {
+	.name = "dwc2",
+	.probe = dwc2_probe,
+	.remove = dwc2_remove,
+	.of_compatible = DRV_OF_COMPAT(dwc2_dt_ids),
+};
+device_platform_driver(dwc2_driver);
diff --git a/drivers/usb/host/dwc2.h b/drivers/usb/host/dwc2.h
new file mode 100644
index 0000000000..bdf338f1ed
--- /dev/null
+++ b/drivers/usb/host/dwc2.h
@@ -0,0 +1,778 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2014 Marek Vasut <marex@denx.de>
+ */
+
+#ifndef __DWC2_H__
+#define __DWC2_H__
+
+struct dwc2_hc_regs {
+	u32			hcchar;		/* 0x00 */
+	u32			hcsplt;
+	u32			hcint;
+	u32			hcintmsk;
+	u32			hctsiz;		/* 0x10 */
+	u32			hcdma;
+	u32			reserved;
+	u32			hcdmab;
+};
+
+struct dwc2_host_regs {
+	u32			hcfg;		/* 0x00 */
+	u32			hfir;
+	u32			hfnum;
+	u32			_pad_0x40c;
+	u32			hptxsts;	/* 0x10 */
+	u32			haint;
+	u32			haintmsk;
+	u32			hflbaddr;
+};
+
+struct dwc2_core_regs {
+	u32			gotgctl;	/* 0x000 */
+	u32			gotgint;
+	u32			gahbcfg;
+	u32			gusbcfg;
+	u32			grstctl;	/* 0x010 */
+	u32			gintsts;
+	u32			gintmsk;
+	u32			grxstsr;
+	u32			grxstsp;	/* 0x020 */
+	u32			grxfsiz;
+	u32			gnptxfsiz;
+	u32			gnptxsts;
+	u32			gi2cctl;	/* 0x030 */
+	u32			gpvndctl;
+	u32			ggpio;
+	u32			guid;
+	u32			gsnpsid;	/* 0x040 */
+	u32			ghwcfg1;
+	u32			ghwcfg2;
+	u32			ghwcfg3;
+	u32			ghwcfg4;	/* 0x050 */
+	u32			glpmcfg;
+	u32			_pad_0x58_0x9c[42];
+	u32			hptxfsiz;	/* 0x100 */
+	u32			dptxfsiz_dieptxf[15];
+	u32			_pad_0x140_0x3fc[176];
+	struct dwc2_host_regs	host_regs;	/* 0x400 */
+	u32			_pad_0x420_0x43c[8];
+	u32			hprt0;		/* 0x440 */
+	u32			_pad_0x444_0x4fc[47];
+	struct dwc2_hc_regs	hc_regs[16];	/* 0x500 */
+	u32			_pad_0x700_0xe00[448];
+	u32			pcgcctl;	/* 0xe00 */
+};
+
+#define DWC2_GOTGCTL_SESREQSCS				(1 << 0)
+#define DWC2_GOTGCTL_SESREQSCS_OFFSET			0
+#define DWC2_GOTGCTL_SESREQ				(1 << 1)
+#define DWC2_GOTGCTL_SESREQ_OFFSET			1
+#define DWC2_GOTGCTL_HSTNEGSCS				(1 << 8)
+#define DWC2_GOTGCTL_HSTNEGSCS_OFFSET			8
+#define DWC2_GOTGCTL_HNPREQ				(1 << 9)
+#define DWC2_GOTGCTL_HNPREQ_OFFSET			9
+#define DWC2_GOTGCTL_HSTSETHNPEN			(1 << 10)
+#define DWC2_GOTGCTL_HSTSETHNPEN_OFFSET			10
+#define DWC2_GOTGCTL_DEVHNPEN				(1 << 11)
+#define DWC2_GOTGCTL_DEVHNPEN_OFFSET			11
+#define DWC2_GOTGCTL_CONIDSTS				(1 << 16)
+#define DWC2_GOTGCTL_CONIDSTS_OFFSET			16
+#define DWC2_GOTGCTL_DBNCTIME				(1 << 17)
+#define DWC2_GOTGCTL_DBNCTIME_OFFSET			17
+#define DWC2_GOTGCTL_ASESVLD				(1 << 18)
+#define DWC2_GOTGCTL_ASESVLD_OFFSET			18
+#define DWC2_GOTGCTL_BSESVLD				(1 << 19)
+#define DWC2_GOTGCTL_BSESVLD_OFFSET			19
+#define DWC2_GOTGCTL_OTGVER				(1 << 20)
+#define DWC2_GOTGCTL_OTGVER_OFFSET			20
+#define DWC2_GOTGINT_SESENDDET				(1 << 2)
+#define DWC2_GOTGINT_SESENDDET_OFFSET			2
+#define DWC2_GOTGINT_SESREQSUCSTSCHNG			(1 << 8)
+#define DWC2_GOTGINT_SESREQSUCSTSCHNG_OFFSET		8
+#define DWC2_GOTGINT_HSTNEGSUCSTSCHNG			(1 << 9)
+#define DWC2_GOTGINT_HSTNEGSUCSTSCHNG_OFFSET		9
+#define DWC2_GOTGINT_RESERVER10_16_MASK			(0x7F << 10)
+#define DWC2_GOTGINT_RESERVER10_16_OFFSET		10
+#define DWC2_GOTGINT_HSTNEGDET				(1 << 17)
+#define DWC2_GOTGINT_HSTNEGDET_OFFSET			17
+#define DWC2_GOTGINT_ADEVTOUTCHNG			(1 << 18)
+#define DWC2_GOTGINT_ADEVTOUTCHNG_OFFSET		18
+#define DWC2_GOTGINT_DEBDONE				(1 << 19)
+#define DWC2_GOTGINT_DEBDONE_OFFSET			19
+#define DWC2_GAHBCFG_GLBLINTRMSK			(1 << 0)
+#define DWC2_GAHBCFG_GLBLINTRMSK_OFFSET			0
+#define DWC2_GAHBCFG_HBURSTLEN_SINGLE			(0 << 1)
+#define DWC2_GAHBCFG_HBURSTLEN_INCR			(1 << 1)
+#define DWC2_GAHBCFG_HBURSTLEN_INCR4			(3 << 1)
+#define DWC2_GAHBCFG_HBURSTLEN_INCR8			(5 << 1)
+#define DWC2_GAHBCFG_HBURSTLEN_INCR16			(7 << 1)
+#define DWC2_GAHBCFG_HBURSTLEN_MASK			(0xF << 1)
+#define DWC2_GAHBCFG_HBURSTLEN_OFFSET			1
+#define DWC2_GAHBCFG_DMAENABLE				(1 << 5)
+#define DWC2_GAHBCFG_DMAENABLE_OFFSET			5
+#define DWC2_GAHBCFG_NPTXFEMPLVL_TXFEMPLVL		(1 << 7)
+#define DWC2_GAHBCFG_NPTXFEMPLVL_TXFEMPLVL_OFFSET	7
+#define DWC2_GAHBCFG_PTXFEMPLVL				(1 << 8)
+#define DWC2_GAHBCFG_PTXFEMPLVL_OFFSET			8
+#define DWC2_GUSBCFG_TOUTCAL_MASK			(0x7 << 0)
+#define DWC2_GUSBCFG_TOUTCAL_OFFSET			0
+#define DWC2_GUSBCFG_PHYIF				(1 << 3)
+#define DWC2_GUSBCFG_PHYIF_OFFSET			3
+#define DWC2_GUSBCFG_ULPI_UTMI_SEL			(1 << 4)
+#define DWC2_GUSBCFG_ULPI_UTMI_SEL_OFFSET		4
+#define DWC2_GUSBCFG_FSINTF				(1 << 5)
+#define DWC2_GUSBCFG_FSINTF_OFFSET			5
+#define DWC2_GUSBCFG_PHYSEL				(1 << 6)
+#define DWC2_GUSBCFG_PHYSEL_OFFSET			6
+#define DWC2_GUSBCFG_DDRSEL				(1 << 7)
+#define DWC2_GUSBCFG_DDRSEL_OFFSET			7
+#define DWC2_GUSBCFG_SRPCAP				(1 << 8)
+#define DWC2_GUSBCFG_SRPCAP_OFFSET			8
+#define DWC2_GUSBCFG_HNPCAP				(1 << 9)
+#define DWC2_GUSBCFG_HNPCAP_OFFSET			9
+#define DWC2_GUSBCFG_USBTRDTIM_MASK			(0xF << 10)
+#define DWC2_GUSBCFG_USBTRDTIM_OFFSET			10
+#define DWC2_GUSBCFG_NPTXFRWNDEN			(1 << 14)
+#define DWC2_GUSBCFG_NPTXFRWNDEN_OFFSET			14
+#define DWC2_GUSBCFG_PHYLPWRCLKSEL			(1 << 15)
+#define DWC2_GUSBCFG_PHYLPWRCLKSEL_OFFSET		15
+#define DWC2_GUSBCFG_OTGUTMIFSSEL			(1 << 16)
+#define DWC2_GUSBCFG_OTGUTMIFSSEL_OFFSET		16
+#define DWC2_GUSBCFG_ULPI_FSLS				(1 << 17)
+#define DWC2_GUSBCFG_ULPI_FSLS_OFFSET			17
+#define DWC2_GUSBCFG_ULPI_AUTO_RES			(1 << 18)
+#define DWC2_GUSBCFG_ULPI_AUTO_RES_OFFSET		18
+#define DWC2_GUSBCFG_ULPI_CLK_SUS_M			(1 << 19)
+#define DWC2_GUSBCFG_ULPI_CLK_SUS_M_OFFSET		19
+#define DWC2_GUSBCFG_ULPI_EXT_VBUS_DRV			(1 << 20)
+#define DWC2_GUSBCFG_ULPI_EXT_VBUS_DRV_OFFSET		20
+#define DWC2_GUSBCFG_ULPI_INT_VBUS_INDICATOR		(1 << 21)
+#define DWC2_GUSBCFG_ULPI_INT_VBUS_INDICATOR_OFFSET	21
+#define DWC2_GUSBCFG_TERM_SEL_DL_PULSE			(1 << 22)
+#define DWC2_GUSBCFG_TERM_SEL_DL_PULSE_OFFSET		22
+#define DWC2_GUSBCFG_INDICATOR_PASSTHROUGH		(1 << 24)
+#define DWC2_GUSBCFG_INDICATOR_PASSTHROUGH_OFFSET	24
+#define DWC2_GUSBCFG_IC_USB_CAP				(1 << 26)
+#define DWC2_GUSBCFG_IC_USB_CAP_OFFSET			26
+#define DWC2_GUSBCFG_IC_TRAFFIC_PULL_REMOVE		(1 << 27)
+#define DWC2_GUSBCFG_IC_TRAFFIC_PULL_REMOVE_OFFSET	27
+#define DWC2_GUSBCFG_TX_END_DELAY			(1 << 28)
+#define DWC2_GUSBCFG_TX_END_DELAY_OFFSET		28
+#define DWC2_GUSBCFG_FORCEHOSTMODE			(1 << 29)
+#define DWC2_GUSBCFG_FORCEHOSTMODE_OFFSET		29
+#define DWC2_GUSBCFG_FORCEDEVMODE			(1 << 30)
+#define DWC2_GUSBCFG_FORCEDEVMODE_OFFSET		30
+#define DWC2_GLPMCTL_LPM_CAP_EN				(1 << 0)
+#define DWC2_GLPMCTL_LPM_CAP_EN_OFFSET			0
+#define DWC2_GLPMCTL_APPL_RESP				(1 << 1)
+#define DWC2_GLPMCTL_APPL_RESP_OFFSET			1
+#define DWC2_GLPMCTL_HIRD_MASK				(0xF << 2)
+#define DWC2_GLPMCTL_HIRD_OFFSET			2
+#define DWC2_GLPMCTL_REM_WKUP_EN			(1 << 6)
+#define DWC2_GLPMCTL_REM_WKUP_EN_OFFSET			6
+#define DWC2_GLPMCTL_EN_UTMI_SLEEP			(1 << 7)
+#define DWC2_GLPMCTL_EN_UTMI_SLEEP_OFFSET		7
+#define DWC2_GLPMCTL_HIRD_THRES_MASK			(0x1F << 8)
+#define DWC2_GLPMCTL_HIRD_THRES_OFFSET			8
+#define DWC2_GLPMCTL_LPM_RESP_MASK			(0x3 << 13)
+#define DWC2_GLPMCTL_LPM_RESP_OFFSET			13
+#define DWC2_GLPMCTL_PRT_SLEEP_STS			(1 << 15)
+#define DWC2_GLPMCTL_PRT_SLEEP_STS_OFFSET		15
+#define DWC2_GLPMCTL_SLEEP_STATE_RESUMEOK		(1 << 16)
+#define DWC2_GLPMCTL_SLEEP_STATE_RESUMEOK_OFFSET	16
+#define DWC2_GLPMCTL_LPM_CHAN_INDEX_MASK		(0xF << 17)
+#define DWC2_GLPMCTL_LPM_CHAN_INDEX_OFFSET		17
+#define DWC2_GLPMCTL_RETRY_COUNT_MASK			(0x7 << 21)
+#define DWC2_GLPMCTL_RETRY_COUNT_OFFSET			21
+#define DWC2_GLPMCTL_SEND_LPM				(1 << 24)
+#define DWC2_GLPMCTL_SEND_LPM_OFFSET			24
+#define DWC2_GLPMCTL_RETRY_COUNT_STS_MASK		(0x7 << 25)
+#define DWC2_GLPMCTL_RETRY_COUNT_STS_OFFSET		25
+#define DWC2_GLPMCTL_HSIC_CONNECT			(1 << 30)
+#define DWC2_GLPMCTL_HSIC_CONNECT_OFFSET		30
+#define DWC2_GLPMCTL_INV_SEL_HSIC			(1 << 31)
+#define DWC2_GLPMCTL_INV_SEL_HSIC_OFFSET		31
+#define DWC2_GRSTCTL_CSFTRST				(1 << 0)
+#define DWC2_GRSTCTL_CSFTRST_OFFSET			0
+#define DWC2_GRSTCTL_HSFTRST				(1 << 1)
+#define DWC2_GRSTCTL_HSFTRST_OFFSET			1
+#define DWC2_GRSTCTL_HSTFRM				(1 << 2)
+#define DWC2_GRSTCTL_HSTFRM_OFFSET			2
+#define DWC2_GRSTCTL_INTKNQFLSH				(1 << 3)
+#define DWC2_GRSTCTL_INTKNQFLSH_OFFSET			3
+#define DWC2_GRSTCTL_RXFFLSH				(1 << 4)
+#define DWC2_GRSTCTL_RXFFLSH_OFFSET			4
+#define DWC2_GRSTCTL_TXFFLSH				(1 << 5)
+#define DWC2_GRSTCTL_TXFFLSH_OFFSET			5
+#define DWC2_GRSTCTL_TXFNUM_MASK			(0x1F << 6)
+#define DWC2_GRSTCTL_TXFNUM_OFFSET			6
+#define DWC2_GRSTCTL_DMAREQ				(1 << 30)
+#define DWC2_GRSTCTL_DMAREQ_OFFSET			30
+#define DWC2_GRSTCTL_AHBIDLE				(1 << 31)
+#define DWC2_GRSTCTL_AHBIDLE_OFFSET			31
+#define DWC2_GINTMSK_MODEMISMATCH			(1 << 1)
+#define DWC2_GINTMSK_MODEMISMATCH_OFFSET		1
+#define DWC2_GINTMSK_OTGINTR				(1 << 2)
+#define DWC2_GINTMSK_OTGINTR_OFFSET			2
+#define DWC2_GINTMSK_SOFINTR				(1 << 3)
+#define DWC2_GINTMSK_SOFINTR_OFFSET			3
+#define DWC2_GINTMSK_RXSTSQLVL				(1 << 4)
+#define DWC2_GINTMSK_RXSTSQLVL_OFFSET			4
+#define DWC2_GINTMSK_NPTXFEMPTY				(1 << 5)
+#define DWC2_GINTMSK_NPTXFEMPTY_OFFSET			5
+#define DWC2_GINTMSK_GINNAKEFF				(1 << 6)
+#define DWC2_GINTMSK_GINNAKEFF_OFFSET			6
+#define DWC2_GINTMSK_GOUTNAKEFF				(1 << 7)
+#define DWC2_GINTMSK_GOUTNAKEFF_OFFSET			7
+#define DWC2_GINTMSK_I2CINTR				(1 << 9)
+#define DWC2_GINTMSK_I2CINTR_OFFSET			9
+#define DWC2_GINTMSK_ERLYSUSPEND			(1 << 10)
+#define DWC2_GINTMSK_ERLYSUSPEND_OFFSET			10
+#define DWC2_GINTMSK_USBSUSPEND				(1 << 11)
+#define DWC2_GINTMSK_USBSUSPEND_OFFSET			11
+#define DWC2_GINTMSK_USBRESET				(1 << 12)
+#define DWC2_GINTMSK_USBRESET_OFFSET			12
+#define DWC2_GINTMSK_ENUMDONE				(1 << 13)
+#define DWC2_GINTMSK_ENUMDONE_OFFSET			13
+#define DWC2_GINTMSK_ISOOUTDROP				(1 << 14)
+#define DWC2_GINTMSK_ISOOUTDROP_OFFSET			14
+#define DWC2_GINTMSK_EOPFRAME				(1 << 15)
+#define DWC2_GINTMSK_EOPFRAME_OFFSET			15
+#define DWC2_GINTMSK_EPMISMATCH				(1 << 17)
+#define DWC2_GINTMSK_EPMISMATCH_OFFSET			17
+#define DWC2_GINTMSK_INEPINTR				(1 << 18)
+#define DWC2_GINTMSK_INEPINTR_OFFSET			18
+#define DWC2_GINTMSK_OUTEPINTR				(1 << 19)
+#define DWC2_GINTMSK_OUTEPINTR_OFFSET			19
+#define DWC2_GINTMSK_INCOMPLISOIN			(1 << 20)
+#define DWC2_GINTMSK_INCOMPLISOIN_OFFSET		20
+#define DWC2_GINTMSK_INCOMPLISOOUT			(1 << 21)
+#define DWC2_GINTMSK_INCOMPLISOOUT_OFFSET		21
+#define DWC2_GINTMSK_PORTINTR				(1 << 24)
+#define DWC2_GINTMSK_PORTINTR_OFFSET			24
+#define DWC2_GINTMSK_HCINTR				(1 << 25)
+#define DWC2_GINTMSK_HCINTR_OFFSET			25
+#define DWC2_GINTMSK_PTXFEMPTY				(1 << 26)
+#define DWC2_GINTMSK_PTXFEMPTY_OFFSET			26
+#define DWC2_GINTMSK_LPMTRANRCVD			(1 << 27)
+#define DWC2_GINTMSK_LPMTRANRCVD_OFFSET			27
+#define DWC2_GINTMSK_CONIDSTSCHNG			(1 << 28)
+#define DWC2_GINTMSK_CONIDSTSCHNG_OFFSET		28
+#define DWC2_GINTMSK_DISCONNECT				(1 << 29)
+#define DWC2_GINTMSK_DISCONNECT_OFFSET			29
+#define DWC2_GINTMSK_SESSREQINTR			(1 << 30)
+#define DWC2_GINTMSK_SESSREQINTR_OFFSET			30
+#define DWC2_GINTMSK_WKUPINTR				(1 << 31)
+#define DWC2_GINTMSK_WKUPINTR_OFFSET			31
+#define DWC2_GINTSTS_CURMODE_DEVICE			(0 << 0)
+#define DWC2_GINTSTS_CURMODE_HOST			(1 << 0)
+#define DWC2_GINTSTS_CURMODE				(1 << 0)
+#define DWC2_GINTSTS_CURMODE_OFFSET			0
+#define DWC2_GINTSTS_MODEMISMATCH			(1 << 1)
+#define DWC2_GINTSTS_MODEMISMATCH_OFFSET		1
+#define DWC2_GINTSTS_OTGINTR				(1 << 2)
+#define DWC2_GINTSTS_OTGINTR_OFFSET			2
+#define DWC2_GINTSTS_SOFINTR				(1 << 3)
+#define DWC2_GINTSTS_SOFINTR_OFFSET			3
+#define DWC2_GINTSTS_RXSTSQLVL				(1 << 4)
+#define DWC2_GINTSTS_RXSTSQLVL_OFFSET			4
+#define DWC2_GINTSTS_NPTXFEMPTY				(1 << 5)
+#define DWC2_GINTSTS_NPTXFEMPTY_OFFSET			5
+#define DWC2_GINTSTS_GINNAKEFF				(1 << 6)
+#define DWC2_GINTSTS_GINNAKEFF_OFFSET			6
+#define DWC2_GINTSTS_GOUTNAKEFF				(1 << 7)
+#define DWC2_GINTSTS_GOUTNAKEFF_OFFSET			7
+#define DWC2_GINTSTS_I2CINTR				(1 << 9)
+#define DWC2_GINTSTS_I2CINTR_OFFSET			9
+#define DWC2_GINTSTS_ERLYSUSPEND			(1 << 10)
+#define DWC2_GINTSTS_ERLYSUSPEND_OFFSET			10
+#define DWC2_GINTSTS_USBSUSPEND				(1 << 11)
+#define DWC2_GINTSTS_USBSUSPEND_OFFSET			11
+#define DWC2_GINTSTS_USBRESET				(1 << 12)
+#define DWC2_GINTSTS_USBRESET_OFFSET			12
+#define DWC2_GINTSTS_ENUMDONE				(1 << 13)
+#define DWC2_GINTSTS_ENUMDONE_OFFSET			13
+#define DWC2_GINTSTS_ISOOUTDROP				(1 << 14)
+#define DWC2_GINTSTS_ISOOUTDROP_OFFSET			14
+#define DWC2_GINTSTS_EOPFRAME				(1 << 15)
+#define DWC2_GINTSTS_EOPFRAME_OFFSET			15
+#define DWC2_GINTSTS_INTOKENRX				(1 << 16)
+#define DWC2_GINTSTS_INTOKENRX_OFFSET			16
+#define DWC2_GINTSTS_EPMISMATCH				(1 << 17)
+#define DWC2_GINTSTS_EPMISMATCH_OFFSET			17
+#define DWC2_GINTSTS_INEPINT				(1 << 18)
+#define DWC2_GINTSTS_INEPINT_OFFSET			18
+#define DWC2_GINTSTS_OUTEPINTR				(1 << 19)
+#define DWC2_GINTSTS_OUTEPINTR_OFFSET			19
+#define DWC2_GINTSTS_INCOMPLISOIN			(1 << 20)
+#define DWC2_GINTSTS_INCOMPLISOIN_OFFSET		20
+#define DWC2_GINTSTS_INCOMPLISOOUT			(1 << 21)
+#define DWC2_GINTSTS_INCOMPLISOOUT_OFFSET		21
+#define DWC2_GINTSTS_PORTINTR				(1 << 24)
+#define DWC2_GINTSTS_PORTINTR_OFFSET			24
+#define DWC2_GINTSTS_HCINTR				(1 << 25)
+#define DWC2_GINTSTS_HCINTR_OFFSET			25
+#define DWC2_GINTSTS_PTXFEMPTY				(1 << 26)
+#define DWC2_GINTSTS_PTXFEMPTY_OFFSET			26
+#define DWC2_GINTSTS_LPMTRANRCVD			(1 << 27)
+#define DWC2_GINTSTS_LPMTRANRCVD_OFFSET			27
+#define DWC2_GINTSTS_CONIDSTSCHNG			(1 << 28)
+#define DWC2_GINTSTS_CONIDSTSCHNG_OFFSET		28
+#define DWC2_GINTSTS_DISCONNECT				(1 << 29)
+#define DWC2_GINTSTS_DISCONNECT_OFFSET			29
+#define DWC2_GINTSTS_SESSREQINTR			(1 << 30)
+#define DWC2_GINTSTS_SESSREQINTR_OFFSET			30
+#define DWC2_GINTSTS_WKUPINTR				(1 << 31)
+#define DWC2_GINTSTS_WKUPINTR_OFFSET			31
+#define DWC2_GRXSTS_EPNUM_MASK				(0xF << 0)
+#define DWC2_GRXSTS_EPNUM_OFFSET			0
+#define DWC2_GRXSTS_BCNT_MASK				(0x7FF << 4)
+#define DWC2_GRXSTS_BCNT_OFFSET				4
+#define DWC2_GRXSTS_DPID_MASK				(0x3 << 15)
+#define DWC2_GRXSTS_DPID_OFFSET				15
+#define DWC2_GRXSTS_PKTSTS_MASK				(0xF << 17)
+#define DWC2_GRXSTS_PKTSTS_OFFSET			17
+#define DWC2_GRXSTS_FN_MASK				(0xF << 21)
+#define DWC2_GRXSTS_FN_OFFSET				21
+#define DWC2_FIFOSIZE_STARTADDR_MASK			(0xFFFF << 0)
+#define DWC2_FIFOSIZE_STARTADDR_OFFSET			0
+#define DWC2_FIFOSIZE_DEPTH_MASK			(0xFFFF << 16)
+#define DWC2_FIFOSIZE_DEPTH_OFFSET			16
+#define DWC2_GNPTXSTS_NPTXFSPCAVAIL_MASK		(0xFFFF << 0)
+#define DWC2_GNPTXSTS_NPTXFSPCAVAIL_OFFSET		0
+#define DWC2_GNPTXSTS_NPTXQSPCAVAIL_MASK		(0xFF << 16)
+#define DWC2_GNPTXSTS_NPTXQSPCAVAIL_OFFSET		16
+#define DWC2_GNPTXSTS_NPTXQTOP_TERMINATE		(1 << 24)
+#define DWC2_GNPTXSTS_NPTXQTOP_TERMINATE_OFFSET		24
+#define DWC2_GNPTXSTS_NPTXQTOP_TOKEN_MASK		(0x3 << 25)
+#define DWC2_GNPTXSTS_NPTXQTOP_TOKEN_OFFSET		25
+#define DWC2_GNPTXSTS_NPTXQTOP_CHNEP_MASK		(0xF << 27)
+#define DWC2_GNPTXSTS_NPTXQTOP_CHNEP_OFFSET		27
+#define DWC2_DTXFSTS_TXFSPCAVAIL_MASK			(0xFFFF << 0)
+#define DWC2_DTXFSTS_TXFSPCAVAIL_OFFSET			0
+#define DWC2_GI2CCTL_RWDATA_MASK			(0xFF << 0)
+#define DWC2_GI2CCTL_RWDATA_OFFSET			0
+#define DWC2_GI2CCTL_REGADDR_MASK			(0xFF << 8)
+#define DWC2_GI2CCTL_REGADDR_OFFSET			8
+#define DWC2_GI2CCTL_ADDR_MASK				(0x7F << 16)
+#define DWC2_GI2CCTL_ADDR_OFFSET			16
+#define DWC2_GI2CCTL_I2CEN				(1 << 23)
+#define DWC2_GI2CCTL_I2CEN_OFFSET			23
+#define DWC2_GI2CCTL_ACK				(1 << 24)
+#define DWC2_GI2CCTL_ACK_OFFSET				24
+#define DWC2_GI2CCTL_I2CSUSPCTL				(1 << 25)
+#define DWC2_GI2CCTL_I2CSUSPCTL_OFFSET			25
+#define DWC2_GI2CCTL_I2CDEVADDR_MASK			(0x3 << 26)
+#define DWC2_GI2CCTL_I2CDEVADDR_OFFSET			26
+#define DWC2_GI2CCTL_RW					(1 << 30)
+#define DWC2_GI2CCTL_RW_OFFSET				30
+#define DWC2_GI2CCTL_BSYDNE				(1 << 31)
+#define DWC2_GI2CCTL_BSYDNE_OFFSET			31
+#define DWC2_HWCFG1_EP_DIR0_MASK			(0x3 << 0)
+#define DWC2_HWCFG1_EP_DIR0_OFFSET			0
+#define DWC2_HWCFG1_EP_DIR1_MASK			(0x3 << 2)
+#define DWC2_HWCFG1_EP_DIR1_OFFSET			2
+#define DWC2_HWCFG1_EP_DIR2_MASK			(0x3 << 4)
+#define DWC2_HWCFG1_EP_DIR2_OFFSET			4
+#define DWC2_HWCFG1_EP_DIR3_MASK			(0x3 << 6)
+#define DWC2_HWCFG1_EP_DIR3_OFFSET			6
+#define DWC2_HWCFG1_EP_DIR4_MASK			(0x3 << 8)
+#define DWC2_HWCFG1_EP_DIR4_OFFSET			8
+#define DWC2_HWCFG1_EP_DIR5_MASK			(0x3 << 10)
+#define DWC2_HWCFG1_EP_DIR5_OFFSET			10
+#define DWC2_HWCFG1_EP_DIR6_MASK			(0x3 << 12)
+#define DWC2_HWCFG1_EP_DIR6_OFFSET			12
+#define DWC2_HWCFG1_EP_DIR7_MASK			(0x3 << 14)
+#define DWC2_HWCFG1_EP_DIR7_OFFSET			14
+#define DWC2_HWCFG1_EP_DIR8_MASK			(0x3 << 16)
+#define DWC2_HWCFG1_EP_DIR8_OFFSET			16
+#define DWC2_HWCFG1_EP_DIR9_MASK			(0x3 << 18)
+#define DWC2_HWCFG1_EP_DIR9_OFFSET			18
+#define DWC2_HWCFG1_EP_DIR10_MASK			(0x3 << 20)
+#define DWC2_HWCFG1_EP_DIR10_OFFSET			20
+#define DWC2_HWCFG1_EP_DIR11_MASK			(0x3 << 22)
+#define DWC2_HWCFG1_EP_DIR11_OFFSET			22
+#define DWC2_HWCFG1_EP_DIR12_MASK			(0x3 << 24)
+#define DWC2_HWCFG1_EP_DIR12_OFFSET			24
+#define DWC2_HWCFG1_EP_DIR13_MASK			(0x3 << 26)
+#define DWC2_HWCFG1_EP_DIR13_OFFSET			26
+#define DWC2_HWCFG1_EP_DIR14_MASK			(0x3 << 28)
+#define DWC2_HWCFG1_EP_DIR14_OFFSET			28
+#define DWC2_HWCFG1_EP_DIR15_MASK			(0x3 << 30)
+#define DWC2_HWCFG1_EP_DIR15_OFFSET			30
+#define DWC2_HWCFG2_OP_MODE_MASK			(0x7 << 0)
+#define DWC2_HWCFG2_OP_MODE_OFFSET			0
+#define DWC2_HWCFG2_ARCHITECTURE_SLAVE_ONLY		(0x0 << 3)
+#define DWC2_HWCFG2_ARCHITECTURE_EXT_DMA		(0x1 << 3)
+#define DWC2_HWCFG2_ARCHITECTURE_INT_DMA		(0x2 << 3)
+#define DWC2_HWCFG2_ARCHITECTURE_MASK			(0x3 << 3)
+#define DWC2_HWCFG2_ARCHITECTURE_OFFSET			3
+#define DWC2_HWCFG2_POINT2POINT				(1 << 5)
+#define DWC2_HWCFG2_POINT2POINT_OFFSET			5
+#define DWC2_HWCFG2_HS_PHY_TYPE_MASK			(0x3 << 6)
+#define DWC2_HWCFG2_HS_PHY_TYPE_OFFSET			6
+#define DWC2_HWCFG2_FS_PHY_TYPE_MASK			(0x3 << 8)
+#define DWC2_HWCFG2_FS_PHY_TYPE_OFFSET			8
+#define DWC2_HWCFG2_NUM_DEV_EP_MASK			(0xF << 10)
+#define DWC2_HWCFG2_NUM_DEV_EP_OFFSET			10
+#define DWC2_HWCFG2_NUM_HOST_CHAN_MASK			(0xF << 14)
+#define DWC2_HWCFG2_NUM_HOST_CHAN_OFFSET		14
+#define DWC2_HWCFG2_PERIO_EP_SUPPORTED			(1 << 18)
+#define DWC2_HWCFG2_PERIO_EP_SUPPORTED_OFFSET		18
+#define DWC2_HWCFG2_DYNAMIC_FIFO			(1 << 19)
+#define DWC2_HWCFG2_DYNAMIC_FIFO_OFFSET			19
+#define DWC2_HWCFG2_MULTI_PROC_INT			(1 << 20)
+#define DWC2_HWCFG2_MULTI_PROC_INT_OFFSET		20
+#define DWC2_HWCFG2_NONPERIO_TX_Q_DEPTH_MASK		(0x3 << 22)
+#define DWC2_HWCFG2_NONPERIO_TX_Q_DEPTH_OFFSET		22
+#define DWC2_HWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK		(0x3 << 24)
+#define DWC2_HWCFG2_HOST_PERIO_TX_Q_DEPTH_OFFSET	24
+#define DWC2_HWCFG2_DEV_TOKEN_Q_DEPTH_MASK		(0x1F << 26)
+#define DWC2_HWCFG2_DEV_TOKEN_Q_DEPTH_OFFSET		26
+#define DWC2_HWCFG3_XFER_SIZE_CNTR_WIDTH_MASK		(0xF << 0)
+#define DWC2_HWCFG3_XFER_SIZE_CNTR_WIDTH_OFFSET		0
+#define DWC2_HWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK		(0x7 << 4)
+#define DWC2_HWCFG3_PACKET_SIZE_CNTR_WIDTH_OFFSET	4
+#define DWC2_HWCFG3_OTG_FUNC				(1 << 7)
+#define DWC2_HWCFG3_OTG_FUNC_OFFSET			7
+#define DWC2_HWCFG3_I2C					(1 << 8)
+#define DWC2_HWCFG3_I2C_OFFSET				8
+#define DWC2_HWCFG3_VENDOR_CTRL_IF			(1 << 9)
+#define DWC2_HWCFG3_VENDOR_CTRL_IF_OFFSET		9
+#define DWC2_HWCFG3_OPTIONAL_FEATURES			(1 << 10)
+#define DWC2_HWCFG3_OPTIONAL_FEATURES_OFFSET		10
+#define DWC2_HWCFG3_SYNCH_RESET_TYPE			(1 << 11)
+#define DWC2_HWCFG3_SYNCH_RESET_TYPE_OFFSET		11
+#define DWC2_HWCFG3_OTG_ENABLE_IC_USB			(1 << 12)
+#define DWC2_HWCFG3_OTG_ENABLE_IC_USB_OFFSET		12
+#define DWC2_HWCFG3_OTG_ENABLE_HSIC			(1 << 13)
+#define DWC2_HWCFG3_OTG_ENABLE_HSIC_OFFSET		13
+#define DWC2_HWCFG3_OTG_LPM_EN				(1 << 15)
+#define DWC2_HWCFG3_OTG_LPM_EN_OFFSET			15
+#define DWC2_HWCFG3_DFIFO_DEPTH_MASK			(0xFFFF << 16)
+#define DWC2_HWCFG3_DFIFO_DEPTH_OFFSET			16
+#define DWC2_HWCFG4_NUM_DEV_PERIO_IN_EP_MASK		(0xF << 0)
+#define DWC2_HWCFG4_NUM_DEV_PERIO_IN_EP_OFFSET		0
+#define DWC2_HWCFG4_POWER_OPTIMIZ			(1 << 4)
+#define DWC2_HWCFG4_POWER_OPTIMIZ_OFFSET		4
+#define DWC2_HWCFG4_MIN_AHB_FREQ_MASK			(0x1FF << 5)
+#define DWC2_HWCFG4_MIN_AHB_FREQ_OFFSET			5
+#define DWC2_HWCFG4_UTMI_PHY_DATA_WIDTH_MASK		(0x3 << 14)
+#define DWC2_HWCFG4_UTMI_PHY_DATA_WIDTH_OFFSET		14
+#define DWC2_HWCFG4_NUM_DEV_MODE_CTRL_EP_MASK		(0xF << 16)
+#define DWC2_HWCFG4_NUM_DEV_MODE_CTRL_EP_OFFSET		16
+#define DWC2_HWCFG4_IDDIG_FILT_EN			(1 << 20)
+#define DWC2_HWCFG4_IDDIG_FILT_EN_OFFSET		20
+#define DWC2_HWCFG4_VBUS_VALID_FILT_EN			(1 << 21)
+#define DWC2_HWCFG4_VBUS_VALID_FILT_EN_OFFSET		21
+#define DWC2_HWCFG4_A_VALID_FILT_EN			(1 << 22)
+#define DWC2_HWCFG4_A_VALID_FILT_EN_OFFSET		22
+#define DWC2_HWCFG4_B_VALID_FILT_EN			(1 << 23)
+#define DWC2_HWCFG4_B_VALID_FILT_EN_OFFSET		23
+#define DWC2_HWCFG4_SESSION_END_FILT_EN			(1 << 24)
+#define DWC2_HWCFG4_SESSION_END_FILT_EN_OFFSET		24
+#define DWC2_HWCFG4_DED_FIFO_EN				(1 << 25)
+#define DWC2_HWCFG4_DED_FIFO_EN_OFFSET			25
+#define DWC2_HWCFG4_NUM_IN_EPS_MASK			(0xF << 26)
+#define DWC2_HWCFG4_NUM_IN_EPS_OFFSET			26
+#define DWC2_HWCFG4_DESC_DMA				(1 << 30)
+#define DWC2_HWCFG4_DESC_DMA_OFFSET			30
+#define DWC2_HWCFG4_DESC_DMA_DYN			(1 << 31)
+#define DWC2_HWCFG4_DESC_DMA_DYN_OFFSET			31
+#define DWC2_HCFG_FSLSPCLKSEL_30_60_MHZ			0
+#define DWC2_HCFG_FSLSPCLKSEL_48_MHZ			1
+#define DWC2_HCFG_FSLSPCLKSEL_6_MHZ			2
+#define DWC2_HCFG_FSLSPCLKSEL_MASK			(0x3 << 0)
+#define DWC2_HCFG_FSLSPCLKSEL_OFFSET			0
+#define DWC2_HCFG_FSLSSUPP				(1 << 2)
+#define DWC2_HCFG_FSLSSUPP_OFFSET			2
+#define DWC2_HCFG_DESCDMA				(1 << 23)
+#define DWC2_HCFG_DESCDMA_OFFSET			23
+#define DWC2_HCFG_FRLISTEN_MASK				(0x3 << 24)
+#define DWC2_HCFG_FRLISTEN_OFFSET			24
+#define DWC2_HCFG_PERSCHEDENA				(1 << 26)
+#define DWC2_HCFG_PERSCHEDENA_OFFSET			26
+#define DWC2_HCFG_PERSCHEDSTAT				(1 << 27)
+#define DWC2_HCFG_PERSCHEDSTAT_OFFSET			27
+#define DWC2_HFIR_FRINT_MASK				(0xFFFF << 0)
+#define DWC2_HFIR_FRINT_OFFSET				0
+#define DWC2_HFNUM_FRNUM_MASK				(0xFFFF << 0)
+#define DWC2_HFNUM_FRNUM_OFFSET				0
+#define DWC2_HFNUM_FRREM_MASK				(0xFFFF << 16)
+#define DWC2_HFNUM_FRREM_OFFSET				16
+#define DWC2_HFNUM_MAX_FRNUM				0x3FFF
+#define DWC2_HPTXSTS_PTXFSPCAVAIL_MASK			(0xFFFF << 0)
+#define DWC2_HPTXSTS_PTXFSPCAVAIL_OFFSET		0
+#define DWC2_HPTXSTS_PTXQSPCAVAIL_MASK			(0xFF << 16)
+#define DWC2_HPTXSTS_PTXQSPCAVAIL_OFFSET		16
+#define DWC2_HPTXSTS_PTXQTOP_TERMINATE			(1 << 24)
+#define DWC2_HPTXSTS_PTXQTOP_TERMINATE_OFFSET		24
+#define DWC2_HPTXSTS_PTXQTOP_TOKEN_MASK			(0x3 << 25)
+#define DWC2_HPTXSTS_PTXQTOP_TOKEN_OFFSET		25
+#define DWC2_HPTXSTS_PTXQTOP_CHNUM_MASK			(0xF << 27)
+#define DWC2_HPTXSTS_PTXQTOP_CHNUM_OFFSET		27
+#define DWC2_HPTXSTS_PTXQTOP_ODD			(1 << 31)
+#define DWC2_HPTXSTS_PTXQTOP_ODD_OFFSET			31
+#define DWC2_HPRT0_PRTCONNSTS				(1 << 0)
+#define DWC2_HPRT0_PRTCONNSTS_OFFSET			0
+#define DWC2_HPRT0_PRTCONNDET				(1 << 1)
+#define DWC2_HPRT0_PRTCONNDET_OFFSET			1
+#define DWC2_HPRT0_PRTENA				(1 << 2)
+#define DWC2_HPRT0_PRTENA_OFFSET			2
+#define DWC2_HPRT0_PRTENCHNG				(1 << 3)
+#define DWC2_HPRT0_PRTENCHNG_OFFSET			3
+#define DWC2_HPRT0_PRTOVRCURRACT			(1 << 4)
+#define DWC2_HPRT0_PRTOVRCURRACT_OFFSET			4
+#define DWC2_HPRT0_PRTOVRCURRCHNG			(1 << 5)
+#define DWC2_HPRT0_PRTOVRCURRCHNG_OFFSET		5
+#define DWC2_HPRT0_PRTRES				(1 << 6)
+#define DWC2_HPRT0_PRTRES_OFFSET			6
+#define DWC2_HPRT0_PRTSUSP				(1 << 7)
+#define DWC2_HPRT0_PRTSUSP_OFFSET			7
+#define DWC2_HPRT0_PRTRST				(1 << 8)
+#define DWC2_HPRT0_PRTRST_OFFSET			8
+#define DWC2_HPRT0_PRTLNSTS_MASK			(0x3 << 10)
+#define DWC2_HPRT0_PRTLNSTS_OFFSET			10
+#define DWC2_HPRT0_PRTPWR				(1 << 12)
+#define DWC2_HPRT0_PRTPWR_OFFSET			12
+#define DWC2_HPRT0_PRTTSTCTL_MASK			(0xF << 13)
+#define DWC2_HPRT0_PRTTSTCTL_OFFSET			13
+#define DWC2_HPRT0_PRTSPD_HIGH				(0 << 17)
+#define DWC2_HPRT0_PRTSPD_FULL				(1 << 17)
+#define DWC2_HPRT0_PRTSPD_LOW				(2 << 17)
+#define DWC2_HPRT0_PRTSPD_MASK				(0x3 << 17)
+#define DWC2_HPRT0_PRTSPD_OFFSET			17
+#define DWC2_HAINT_CH0					(1 << 0)
+#define DWC2_HAINT_CH0_OFFSET				0
+#define DWC2_HAINT_CH1					(1 << 1)
+#define DWC2_HAINT_CH1_OFFSET				1
+#define DWC2_HAINT_CH2					(1 << 2)
+#define DWC2_HAINT_CH2_OFFSET				2
+#define DWC2_HAINT_CH3					(1 << 3)
+#define DWC2_HAINT_CH3_OFFSET				3
+#define DWC2_HAINT_CH4					(1 << 4)
+#define DWC2_HAINT_CH4_OFFSET				4
+#define DWC2_HAINT_CH5					(1 << 5)
+#define DWC2_HAINT_CH5_OFFSET				5
+#define DWC2_HAINT_CH6					(1 << 6)
+#define DWC2_HAINT_CH6_OFFSET				6
+#define DWC2_HAINT_CH7					(1 << 7)
+#define DWC2_HAINT_CH7_OFFSET				7
+#define DWC2_HAINT_CH8					(1 << 8)
+#define DWC2_HAINT_CH8_OFFSET				8
+#define DWC2_HAINT_CH9					(1 << 9)
+#define DWC2_HAINT_CH9_OFFSET				9
+#define DWC2_HAINT_CH10					(1 << 10)
+#define DWC2_HAINT_CH10_OFFSET				10
+#define DWC2_HAINT_CH11					(1 << 11)
+#define DWC2_HAINT_CH11_OFFSET				11
+#define DWC2_HAINT_CH12					(1 << 12)
+#define DWC2_HAINT_CH12_OFFSET				12
+#define DWC2_HAINT_CH13					(1 << 13)
+#define DWC2_HAINT_CH13_OFFSET				13
+#define DWC2_HAINT_CH14					(1 << 14)
+#define DWC2_HAINT_CH14_OFFSET				14
+#define DWC2_HAINT_CH15					(1 << 15)
+#define DWC2_HAINT_CH15_OFFSET				15
+#define DWC2_HAINT_CHINT_MASK				0xffff
+#define DWC2_HAINT_CHINT_OFFSET				0
+#define DWC2_HAINTMSK_CH0				(1 << 0)
+#define DWC2_HAINTMSK_CH0_OFFSET			0
+#define DWC2_HAINTMSK_CH1				(1 << 1)
+#define DWC2_HAINTMSK_CH1_OFFSET			1
+#define DWC2_HAINTMSK_CH2				(1 << 2)
+#define DWC2_HAINTMSK_CH2_OFFSET			2
+#define DWC2_HAINTMSK_CH3				(1 << 3)
+#define DWC2_HAINTMSK_CH3_OFFSET			3
+#define DWC2_HAINTMSK_CH4				(1 << 4)
+#define DWC2_HAINTMSK_CH4_OFFSET			4
+#define DWC2_HAINTMSK_CH5				(1 << 5)
+#define DWC2_HAINTMSK_CH5_OFFSET			5
+#define DWC2_HAINTMSK_CH6				(1 << 6)
+#define DWC2_HAINTMSK_CH6_OFFSET			6
+#define DWC2_HAINTMSK_CH7				(1 << 7)
+#define DWC2_HAINTMSK_CH7_OFFSET			7
+#define DWC2_HAINTMSK_CH8				(1 << 8)
+#define DWC2_HAINTMSK_CH8_OFFSET			8
+#define DWC2_HAINTMSK_CH9				(1 << 9)
+#define DWC2_HAINTMSK_CH9_OFFSET			9
+#define DWC2_HAINTMSK_CH10				(1 << 10)
+#define DWC2_HAINTMSK_CH10_OFFSET			10
+#define DWC2_HAINTMSK_CH11				(1 << 11)
+#define DWC2_HAINTMSK_CH11_OFFSET			11
+#define DWC2_HAINTMSK_CH12				(1 << 12)
+#define DWC2_HAINTMSK_CH12_OFFSET			12
+#define DWC2_HAINTMSK_CH13				(1 << 13)
+#define DWC2_HAINTMSK_CH13_OFFSET			13
+#define DWC2_HAINTMSK_CH14				(1 << 14)
+#define DWC2_HAINTMSK_CH14_OFFSET			14
+#define DWC2_HAINTMSK_CH15				(1 << 15)
+#define DWC2_HAINTMSK_CH15_OFFSET			15
+#define DWC2_HAINTMSK_CHINT_MASK			0xffff
+#define DWC2_HAINTMSK_CHINT_OFFSET			0
+#define DWC2_HCCHAR_MPS_MASK				(0x7FF << 0)
+#define DWC2_HCCHAR_MPS_OFFSET				0
+#define DWC2_HCCHAR_EPNUM_MASK				(0xF << 11)
+#define DWC2_HCCHAR_EPNUM_OFFSET			11
+#define DWC2_HCCHAR_EPDIR				(1 << 15)
+#define DWC2_HCCHAR_EPDIR_OFFSET			15
+#define DWC2_HCCHAR_LSPDDEV				(1 << 17)
+#define DWC2_HCCHAR_LSPDDEV_OFFSET			17
+#define DWC2_HCCHAR_EPTYPE_CONTROL			0
+#define DWC2_HCCHAR_EPTYPE_ISOC				1
+#define DWC2_HCCHAR_EPTYPE_BULK				2
+#define DWC2_HCCHAR_EPTYPE_INTR				3
+#define DWC2_HCCHAR_EPTYPE_MASK				(0x3 << 18)
+#define DWC2_HCCHAR_EPTYPE_OFFSET			18
+#define DWC2_HCCHAR_MULTICNT_MASK			(0x3 << 20)
+#define DWC2_HCCHAR_MULTICNT_OFFSET			20
+#define DWC2_HCCHAR_DEVADDR_MASK			(0x7F << 22)
+#define DWC2_HCCHAR_DEVADDR_OFFSET			22
+#define DWC2_HCCHAR_ODDFRM				(1 << 29)
+#define DWC2_HCCHAR_ODDFRM_OFFSET			29
+#define DWC2_HCCHAR_CHDIS				(1 << 30)
+#define DWC2_HCCHAR_CHDIS_OFFSET			30
+#define DWC2_HCCHAR_CHEN				(1 << 31)
+#define DWC2_HCCHAR_CHEN_OFFSET				31
+#define DWC2_HCSPLT_PRTADDR_MASK			(0x7F << 0)
+#define DWC2_HCSPLT_PRTADDR_OFFSET			0
+#define DWC2_HCSPLT_HUBADDR_MASK			(0x7F << 7)
+#define DWC2_HCSPLT_HUBADDR_OFFSET			7
+#define DWC2_HCSPLT_XACTPOS_MASK			(0x3 << 14)
+#define DWC2_HCSPLT_XACTPOS_OFFSET			14
+#define DWC2_HCSPLT_COMPSPLT				(1 << 16)
+#define DWC2_HCSPLT_COMPSPLT_OFFSET			16
+#define DWC2_HCSPLT_SPLTENA				(1 << 31)
+#define DWC2_HCSPLT_SPLTENA_OFFSET			31
+#define DWC2_HCINT_XFERCOMP				(1 << 0)
+#define DWC2_HCINT_XFERCOMP_OFFSET			0
+#define DWC2_HCINT_CHHLTD				(1 << 1)
+#define DWC2_HCINT_CHHLTD_OFFSET			1
+#define DWC2_HCINT_AHBERR				(1 << 2)
+#define DWC2_HCINT_AHBERR_OFFSET			2
+#define DWC2_HCINT_STALL				(1 << 3)
+#define DWC2_HCINT_STALL_OFFSET				3
+#define DWC2_HCINT_NAK					(1 << 4)
+#define DWC2_HCINT_NAK_OFFSET				4
+#define DWC2_HCINT_ACK					(1 << 5)
+#define DWC2_HCINT_ACK_OFFSET				5
+#define DWC2_HCINT_NYET					(1 << 6)
+#define DWC2_HCINT_NYET_OFFSET				6
+#define DWC2_HCINT_XACTERR				(1 << 7)
+#define DWC2_HCINT_XACTERR_OFFSET			7
+#define DWC2_HCINT_BBLERR				(1 << 8)
+#define DWC2_HCINT_BBLERR_OFFSET			8
+#define DWC2_HCINT_FRMOVRUN				(1 << 9)
+#define DWC2_HCINT_FRMOVRUN_OFFSET			9
+#define DWC2_HCINT_DATATGLERR				(1 << 10)
+#define DWC2_HCINT_DATATGLERR_OFFSET			10
+#define DWC2_HCINT_BNA					(1 << 11)
+#define DWC2_HCINT_BNA_OFFSET				11
+#define DWC2_HCINT_XCS_XACT				(1 << 12)
+#define DWC2_HCINT_XCS_XACT_OFFSET			12
+#define DWC2_HCINT_FRM_LIST_ROLL			(1 << 13)
+#define DWC2_HCINT_FRM_LIST_ROLL_OFFSET			13
+#define DWC2_HCINTMSK_XFERCOMPL				(1 << 0)
+#define DWC2_HCINTMSK_XFERCOMPL_OFFSET			0
+#define DWC2_HCINTMSK_CHHLTD				(1 << 1)
+#define DWC2_HCINTMSK_CHHLTD_OFFSET			1
+#define DWC2_HCINTMSK_AHBERR				(1 << 2)
+#define DWC2_HCINTMSK_AHBERR_OFFSET			2
+#define DWC2_HCINTMSK_STALL				(1 << 3)
+#define DWC2_HCINTMSK_STALL_OFFSET			3
+#define DWC2_HCINTMSK_NAK				(1 << 4)
+#define DWC2_HCINTMSK_NAK_OFFSET			4
+#define DWC2_HCINTMSK_ACK				(1 << 5)
+#define DWC2_HCINTMSK_ACK_OFFSET			5
+#define DWC2_HCINTMSK_NYET				(1 << 6)
+#define DWC2_HCINTMSK_NYET_OFFSET			6
+#define DWC2_HCINTMSK_XACTERR				(1 << 7)
+#define DWC2_HCINTMSK_XACTERR_OFFSET			7
+#define DWC2_HCINTMSK_BBLERR				(1 << 8)
+#define DWC2_HCINTMSK_BBLERR_OFFSET			8
+#define DWC2_HCINTMSK_FRMOVRUN				(1 << 9)
+#define DWC2_HCINTMSK_FRMOVRUN_OFFSET			9
+#define DWC2_HCINTMSK_DATATGLERR			(1 << 10)
+#define DWC2_HCINTMSK_DATATGLERR_OFFSET			10
+#define DWC2_HCINTMSK_BNA				(1 << 11)
+#define DWC2_HCINTMSK_BNA_OFFSET			11
+#define DWC2_HCINTMSK_XCS_XACT				(1 << 12)
+#define DWC2_HCINTMSK_XCS_XACT_OFFSET			12
+#define DWC2_HCINTMSK_FRM_LIST_ROLL			(1 << 13)
+#define DWC2_HCINTMSK_FRM_LIST_ROLL_OFFSET		13
+#define DWC2_HCTSIZ_XFERSIZE_MASK			0x7ffff
+#define DWC2_HCTSIZ_XFERSIZE_OFFSET			0
+#define DWC2_HCTSIZ_SCHINFO_MASK			0xff
+#define DWC2_HCTSIZ_SCHINFO_OFFSET			0
+#define DWC2_HCTSIZ_NTD_MASK				(0xff << 8)
+#define DWC2_HCTSIZ_NTD_OFFSET				8
+#define DWC2_HCTSIZ_PKTCNT_MASK				(0x3ff << 19)
+#define DWC2_HCTSIZ_PKTCNT_OFFSET			19
+#define DWC2_HCTSIZ_PID_MASK				(0x3 << 29)
+#define DWC2_HCTSIZ_PID_OFFSET				29
+#define DWC2_HCTSIZ_DOPNG				(1 << 31)
+#define DWC2_HCTSIZ_DOPNG_OFFSET			31
+#define DWC2_HCDMA_CTD_MASK				(0xFF << 3)
+#define DWC2_HCDMA_CTD_OFFSET				3
+#define DWC2_HCDMA_DMA_ADDR_MASK			(0x1FFFFF << 11)
+#define DWC2_HCDMA_DMA_ADDR_OFFSET			11
+#define DWC2_PCGCCTL_STOPPCLK				(1 << 0)
+#define DWC2_PCGCCTL_STOPPCLK_OFFSET			0
+#define DWC2_PCGCCTL_GATEHCLK				(1 << 1)
+#define DWC2_PCGCCTL_GATEHCLK_OFFSET			1
+#define DWC2_PCGCCTL_PWRCLMP				(1 << 2)
+#define DWC2_PCGCCTL_PWRCLMP_OFFSET			2
+#define DWC2_PCGCCTL_RSTPDWNMODULE			(1 << 3)
+#define DWC2_PCGCCTL_RSTPDWNMODULE_OFFSET		3
+#define DWC2_PCGCCTL_PHYSUSPENDED			(1 << 4)
+#define DWC2_PCGCCTL_PHYSUSPENDED_OFFSET		4
+#define DWC2_PCGCCTL_ENBL_SLEEP_GATING			(1 << 5)
+#define DWC2_PCGCCTL_ENBL_SLEEP_GATING_OFFSET		5
+#define DWC2_PCGCCTL_PHY_IN_SLEEP			(1 << 6)
+#define DWC2_PCGCCTL_PHY_IN_SLEEP_OFFSET		6
+#define DWC2_PCGCCTL_DEEP_SLEEP				(1 << 7)
+#define DWC2_PCGCCTL_DEEP_SLEEP_OFFSET			7
+#define DWC2_SNPSID_DEVID_VER_2xx			(0x4f542 << 12)
+#define DWC2_SNPSID_DEVID_VER_3xx			(0x4f543 << 12)
+#define DWC2_SNPSID_DEVID_MASK				(0xfffff << 12)
+#define DWC2_SNPSID_DEVID_OFFSET			12
+
+/* Host controller specific */
+#define DWC2_HC_PID_DATA0		0
+#define DWC2_HC_PID_DATA2		1
+#define DWC2_HC_PID_DATA1		2
+#define DWC2_HC_PID_MDATA		3
+#define DWC2_HC_PID_SETUP		3
+
+/* roothub.a masks */
+#define RH_A_NDP	(0xff << 0)	/* number of downstream ports */
+#define RH_A_PSM	(1 << 8)	/* power switching mode */
+#define RH_A_NPS	(1 << 9)	/* no power switching */
+#define RH_A_DT		(1 << 10)	/* device type (mbz) */
+#define RH_A_OCPM	(1 << 11)	/* over current protection mode */
+#define RH_A_NOCP	(1 << 12)	/* no over current protection */
+#define RH_A_POTPGT	(0xff << 24)	/* power on to power good time */
+
+/* roothub.b masks */
+#define RH_B_DR		0x0000ffff	/* device removable flags */
+#define RH_B_PPCM	0xffff0000	/* port power control mask */
+
+/* Default driver configuration */
+#define CONFIG_DWC2_MAX_CHANNELS		16	/* Max # of EPs */
+#define CONFIG_DWC2_HOST_RX_FIFO_SIZE		(516 + CONFIG_DWC2_MAX_CHANNELS)
+#define CONFIG_DWC2_HOST_NPERIO_TX_FIFO_SIZE	0x100	/* nPeriodic TX FIFO */
+#define CONFIG_DWC2_HOST_PERIO_TX_FIFO_SIZE	0x200	/* Periodic TX FIFO */
+#define CONFIG_DWC2_MAX_TRANSFER_SIZE		65535
+#define CONFIG_DWC2_MAX_PACKET_COUNT		511
+
+#define DWC2_PHY_TYPE_FS		0
+#define DWC2_PHY_TYPE_UTMI		1
+#define DWC2_PHY_TYPE_ULPI		2
+#define CONFIG_DWC2_PHY_TYPE		DWC2_PHY_TYPE_UTMI	/* PHY type */
+#define CONFIG_DWC2_UTMI_WIDTH		8	/* UTMI bus width (8/16) */
+
+#define CONFIG_DWC2_PHY_ULPI_EXT_VBUS		/* ULPI PHY controls VBUS */
+#define CONFIG_DWC2_TX_THR_LENGTH		64
+
+#endif	/* __DWC2_H__ */
-- 
2.24.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 10/10] ARM: rpi_defconfig: Enable networking support
  2019-12-20 14:32 [PATCH 00/10] Add Raspberry Pi USB support Sascha Hauer
                   ` (8 preceding siblings ...)
  2019-12-20 14:32 ` [PATCH 09/10] usb: Add dwc2 host driver Sascha Hauer
@ 2019-12-20 14:32 ` Sascha Hauer
  9 siblings, 0 replies; 24+ messages in thread
From: Sascha Hauer @ 2019-12-20 14:32 UTC (permalink / raw)
  To: Barebox List

Now that we have USB support for the Raspberry Pi enable USB and USB
network support.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/configs/rpi_defconfig | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/arch/arm/configs/rpi_defconfig b/arch/arm/configs/rpi_defconfig
index 0ae0c42b12..9603a0fa30 100644
--- a/arch/arm/configs/rpi_defconfig
+++ b/arch/arm/configs/rpi_defconfig
@@ -22,9 +22,12 @@ CONFIG_BOOTM_OFTREE=y
 CONFIG_BLSPEC=y
 CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y
 CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/raspberry-pi/env"
+CONFIG_CMD_DMESG=y
 CONFIG_LONGHELP=y
 CONFIG_CMD_IOMEM=y
+CONFIG_CMD_IMD=y
 CONFIG_CMD_MEMINFO=y
+CONFIG_CMD_REGULATOR=y
 CONFIG_CMD_GO=y
 CONFIG_CMD_LOADB=y
 CONFIG_CMD_LOADY=y
@@ -43,6 +46,9 @@ CONFIG_CMD_UNCOMPRESS=y
 CONFIG_CMD_LET=y
 CONFIG_CMD_MSLEEP=y
 CONFIG_CMD_SLEEP=y
+CONFIG_CMD_DHCP=y
+CONFIG_CMD_MIITOOL=y
+CONFIG_CMD_PING=y
 CONFIG_CMD_ECHO_E=y
 CONFIG_CMD_EDIT=y
 CONFIG_CMD_LOGIN=y
@@ -62,8 +68,13 @@ CONFIG_CMD_OF_NODE=y
 CONFIG_CMD_OF_PROPERTY=y
 CONFIG_CMD_OFTREE=y
 CONFIG_CMD_TIME=y
+CONFIG_NET=y
 CONFIG_SERIAL_AMBA_PL011=y
 CONFIG_DRIVER_SERIAL_NS16550=y
+CONFIG_NET_USB=y
+CONFIG_NET_USB_SMSC95XX=y
+CONFIG_USB_HOST=y
+CONFIG_USB_DWC2_HOST=y
 CONFIG_MCI=y
 CONFIG_MCI_BCM283X=y
 CONFIG_MCI_BCM283X_SDHOST=y
@@ -75,6 +86,8 @@ CONFIG_WATCHDOG_BCM2835=y
 CONFIG_PINCTRL_BCM283X=y
 CONFIG_REGULATOR=y
 CONFIG_FS_EXT4=y
+CONFIG_FS_TFTP=y
+CONFIG_FS_NFS=y
 CONFIG_FS_FAT=y
 CONFIG_FS_FAT_WRITE=y
 CONFIG_FS_FAT_LFN=y
-- 
2.24.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC PATCH 0/7] usb: dwc2 host driver
  2019-12-20 14:32 ` [PATCH 09/10] usb: Add dwc2 host driver Sascha Hauer
@ 2020-01-14 13:21   ` Jules Maselbas
  2020-01-14 13:21     ` [RFC PATCH 1/7] usb: dwc2: Add host controller driver Jules Maselbas
                       ` (7 more replies)
  0 siblings, 8 replies; 24+ messages in thread
From: Jules Maselbas @ 2020-01-14 13:21 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: Barebox List, Jules Maselbas

Hi Sascha,

I've been working on a driver for the dwc2 otg controller, for both host
and device mode.  Like you I've started from U-Boot driver and I mixed
it with some part from Linux.  For instance I've removed the register
structs and I've been using the same defines for register bit-fields as
in Linux.

I would like to share my version of the host driver, as the gadget driver
one still requires some cleanup.  This series is not to be applied on the
driver you proposed. However I am willing to propose a new series that can
be applied on the driver you proposed.  What do you think?

Cheers,
Jules

---

Jules Maselbas (7):
  usb: dwc2: Add host controller driver
  usb: dwc2: host: Handle dma mapping errors
  usb: dwc2: Dynamic fifo size support from Linux
  usb: dwc2: Rework roothub interface
  HACK: usb: dwc2: Fix toggle reset
  usb: dwc2: Rewrite dwc2_hc_init
  usb: dwc2: Read dr_mode from device tree

 drivers/usb/Kconfig       |   2 +
 drivers/usb/Makefile      |   1 +
 drivers/usb/dwc2/Kconfig  |   4 +
 drivers/usb/dwc2/Makefile |   1 +
 drivers/usb/dwc2/core.c   | 703 ++++++++++++++++++++++++++++++++
 drivers/usb/dwc2/core.h   | 546 +++++++++++++++++++++++++
 drivers/usb/dwc2/dwc2.c   | 103 +++++
 drivers/usb/dwc2/dwc2.h   |  42 ++
 drivers/usb/dwc2/host.c   | 749 ++++++++++++++++++++++++++++++++++
 drivers/usb/dwc2/regs.h   | 839 ++++++++++++++++++++++++++++++++++++++
 drivers/usb/dwc2/rhub.c   | 384 +++++++++++++++++
 11 files changed, 3374 insertions(+)
 create mode 100644 drivers/usb/dwc2/Kconfig
 create mode 100644 drivers/usb/dwc2/Makefile
 create mode 100644 drivers/usb/dwc2/core.c
 create mode 100644 drivers/usb/dwc2/core.h
 create mode 100644 drivers/usb/dwc2/dwc2.c
 create mode 100644 drivers/usb/dwc2/dwc2.h
 create mode 100644 drivers/usb/dwc2/host.c
 create mode 100644 drivers/usb/dwc2/regs.h
 create mode 100644 drivers/usb/dwc2/rhub.c

-- 
2.21.0.196.g041f5ea


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC PATCH 1/7] usb: dwc2: Add host controller driver
  2020-01-14 13:21   ` [RFC PATCH 0/7] usb: " Jules Maselbas
@ 2020-01-14 13:21     ` Jules Maselbas
  2020-01-14 13:21     ` [RFC PATCH 2/7] usb: dwc2: host: Handle dma mapping errors Jules Maselbas
                       ` (6 subsequent siblings)
  7 siblings, 0 replies; 24+ messages in thread
From: Jules Maselbas @ 2020-01-14 13:21 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: Barebox List, Jules Maselbas

The host driver is mostly taken from U-Boot, other part are from Linux

Signed-off-by: Jules Maselbas <jmaselbas@kalray.eu>
---
 drivers/usb/Kconfig       |   2 +
 drivers/usb/Makefile      |   1 +
 drivers/usb/dwc2/Kconfig  |   4 +
 drivers/usb/dwc2/Makefile |   1 +
 drivers/usb/dwc2/core.c   | 614 +++++++++++++++++++++++++++
 drivers/usb/dwc2/core.h   | 546 ++++++++++++++++++++++++
 drivers/usb/dwc2/dwc2.c   | 101 +++++
 drivers/usb/dwc2/dwc2.h   |  41 ++
 drivers/usb/dwc2/host.c   | 618 +++++++++++++++++++++++++++
 drivers/usb/dwc2/regs.h   | 847 ++++++++++++++++++++++++++++++++++++++
 drivers/usb/dwc2/rhub.c   | 418 +++++++++++++++++++
 11 files changed, 3193 insertions(+)
 create mode 100644 drivers/usb/dwc2/Kconfig
 create mode 100644 drivers/usb/dwc2/Makefile
 create mode 100644 drivers/usb/dwc2/core.c
 create mode 100644 drivers/usb/dwc2/core.h
 create mode 100644 drivers/usb/dwc2/dwc2.c
 create mode 100644 drivers/usb/dwc2/dwc2.h
 create mode 100644 drivers/usb/dwc2/host.c
 create mode 100644 drivers/usb/dwc2/regs.h
 create mode 100644 drivers/usb/dwc2/rhub.c

diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 99eff1c8d..aab1564ab 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -9,6 +9,8 @@ if USB_HOST
 
 source "drivers/usb/imx/Kconfig"
 
+source "drivers/usb/dwc2/Kconfig"
+
 source "drivers/usb/dwc3/Kconfig"
 
 source "drivers/usb/host/Kconfig"
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 9e9809950..ecd7ad1d3 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -1,5 +1,6 @@
 obj-$(CONFIG_USB)		+= core/
 obj-$(CONFIG_USB_IMX_CHIPIDEA)	+= imx/
+obj-$(CONFIG_USB_DWC2)		+= dwc2/
 obj-$(CONFIG_USB_DWC3)		+= dwc3/
 obj-$(CONFIG_USB_MUSB)		+= musb/
 obj-$(CONFIG_USB_GADGET)	+= gadget/
diff --git a/drivers/usb/dwc2/Kconfig b/drivers/usb/dwc2/Kconfig
new file mode 100644
index 000000000..c88134cbb
--- /dev/null
+++ b/drivers/usb/dwc2/Kconfig
@@ -0,0 +1,4 @@
+config USB_DWC2
+	bool "DWC2 driver"
+	help
+	  DesignWare Core USB2 OTG driver.
diff --git a/drivers/usb/dwc2/Makefile b/drivers/usb/dwc2/Makefile
new file mode 100644
index 000000000..3b922c282
--- /dev/null
+++ b/drivers/usb/dwc2/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_USB_DWC2)		+= dwc2.o core.o host.o rhub.o
diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
new file mode 100644
index 000000000..9a36b0904
--- /dev/null
+++ b/drivers/usb/dwc2/core.c
@@ -0,0 +1,614 @@
+// SPDX-License-Identifier: GPL-2.0+
+#include "dwc2.h"
+
+void dwc2_set_param_otg_cap(struct dwc2 *dwc2)
+{
+	u8 val;
+
+	switch (dwc2->hw_params.op_mode) {
+	case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE:
+		val = DWC2_CAP_PARAM_HNP_SRP_CAPABLE;
+		break;
+	case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE:
+	case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE:
+	case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST:
+		val = DWC2_CAP_PARAM_SRP_ONLY_CAPABLE;
+		break;
+	default:
+		val = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
+		break;
+	}
+
+	dwc2->params.otg_cap = val;
+}
+
+void dwc2_set_param_phy_type(struct dwc2 *dwc2)
+{
+	u8 val;
+
+	switch (dwc2->hw_params.hs_phy_type) {
+	case GHWCFG2_HS_PHY_TYPE_UTMI:
+	case GHWCFG2_HS_PHY_TYPE_UTMI_ULPI:
+		val = DWC2_PHY_TYPE_PARAM_UTMI;
+		break;
+	case GHWCFG2_HS_PHY_TYPE_ULPI:
+		val = DWC2_PHY_TYPE_PARAM_ULPI;
+		break;
+	case GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED:
+		val = DWC2_PHY_TYPE_PARAM_FS;
+		break;
+	}
+
+	dwc2->params.phy_type = val;
+}
+
+void dwc2_set_param_speed(struct dwc2 *dwc2)
+{
+	if (dwc2->params.phy_type == DWC2_PHY_TYPE_PARAM_FS)
+		dwc2->params.speed = DWC2_SPEED_PARAM_FULL;
+	else
+		dwc2->params.speed = DWC2_SPEED_PARAM_HIGH;
+}
+
+void dwc2_set_param_phy_utmi_width(struct dwc2 *dwc2)
+{
+	int val;
+
+	val = (dwc2->hw_params.utmi_phy_data_width ==
+	       GHWCFG4_UTMI_PHY_DATA_WIDTH_8) ? 8 : 16;
+
+	dwc2->params.phy_utmi_width = val;
+}
+
+/**
+ * dwc2_set_default_params() - Set all core parameters to their
+ * auto-detected default values.
+ *
+ * @dwc2: Programming view of the DWC2 controller
+ *
+ */
+void dwc2_set_default_params(struct dwc2 *dwc2)
+{
+	struct dwc2_hw_params *hw = &dwc2->hw_params;
+	struct dwc2_core_params *p = &dwc2->params;
+	bool dma_capable = !(hw->arch == GHWCFG2_SLAVE_ONLY_ARCH);
+
+	dwc2_set_param_otg_cap(dwc2);
+	dwc2_set_param_phy_type(dwc2);
+	dwc2_set_param_speed(dwc2);
+	dwc2_set_param_phy_utmi_width(dwc2);
+	p->phy_ulpi_ddr = false;
+	p->phy_ulpi_ext_vbus = false;
+
+	p->enable_dynamic_fifo = hw->enable_dynamic_fifo;
+	p->en_multiple_tx_fifo = hw->en_multiple_tx_fifo;
+	p->i2c_enable = hw->i2c_enable;
+	p->acg_enable = hw->acg_enable;
+	p->ulpi_fs_ls = false;
+	p->ts_dline = false;
+	p->reload_ctl = (hw->snpsid >= DWC2_CORE_REV_2_92a);
+	p->uframe_sched = true;
+	p->external_id_pin_ctl = false;
+	p->lpm = true;
+	p->lpm_clock_gating = true;
+	p->besl = true;
+	p->hird_threshold_en = true;
+	p->hird_threshold = 4;
+	p->ipg_isoc_en = false;
+	p->max_packet_count = hw->max_packet_count;
+	p->max_transfer_size = hw->max_transfer_size;
+	p->ahbcfg = GAHBCFG_HBSTLEN_INCR << GAHBCFG_HBSTLEN_SHIFT;
+
+	p->dma = dma_capable;
+	p->dma_desc = false;
+
+	if (dwc2->dr_mode == USB_DR_MODE_HOST ||
+	    dwc2->dr_mode == USB_DR_MODE_OTG) {
+		p->host_support_fs_ls_low_power = false;
+		p->host_ls_low_power_phy_clk = false;
+		p->host_channels = hw->host_channels;
+		p->host_rx_fifo_size = hw->rx_fifo_size;
+		p->host_nperio_tx_fifo_size = hw->host_nperio_tx_fifo_size;
+		p->host_perio_tx_fifo_size = hw->host_perio_tx_fifo_size;
+	}
+}
+
+int dwc2_core_snpsid(struct dwc2 *dwc2)
+{
+	struct dwc2_hw_params *hw = &dwc2->hw_params;
+
+	hw->snpsid = dwc2_readl(dwc2, GSNPSID);
+
+	/*
+	 * Attempt to ensure this device is really a DWC2 Controller.
+	 * Read and verify the GSNPSID register contents. The value should be
+	 * 0x4f54xxxx, 0x5531xxxx or 0x5532xxxx
+	 */
+	hw->snpsid = dwc2_readl(dwc2, GSNPSID);
+	if ((hw->snpsid & GSNPSID_ID_MASK) != DWC2_OTG_ID &&
+	    (hw->snpsid & GSNPSID_ID_MASK) != DWC2_FS_IOT_ID &&
+	    (hw->snpsid & GSNPSID_ID_MASK) != DWC2_HS_IOT_ID) {
+		dwc2_err(dwc2, "Bad value for GSNPSID: 0x%08x\n",
+			hw->snpsid);
+		return -ENODEV;
+	}
+
+	dwc2_dbg(dwc2, "Core Release: %1x.%1x%1x%1x (snpsid=%x)\n",
+		hw->snpsid >> 12 & 0xf, hw->snpsid >> 8 & 0xf,
+		hw->snpsid >> 4 & 0xf, hw->snpsid & 0xf, hw->snpsid);
+
+	return 0;
+}
+
+/**
+ * During device initialization, read various hardware configuration
+ * registers and interpret the contents.
+ *
+ * @dwc2: Programming view of the DWC2 controller
+ *
+ */
+void dwc2_get_hwparams(struct dwc2 *dwc2)
+{
+	struct dwc2_hw_params *hw = &dwc2->hw_params;
+	unsigned int width;
+	u32 hwcfg1, hwcfg2, hwcfg3, hwcfg4;
+	u32 grxfsiz;
+
+	hwcfg1 = dwc2_readl(dwc2, GHWCFG1);
+	hwcfg2 = dwc2_readl(dwc2, GHWCFG2);
+	hwcfg3 = dwc2_readl(dwc2, GHWCFG3);
+	hwcfg4 = dwc2_readl(dwc2, GHWCFG4);
+	grxfsiz = dwc2_readl(dwc2, GRXFSIZ);
+
+	/* hwcfg1 */
+	hw->dev_ep_dirs = hwcfg1;
+
+	/* hwcfg2 */
+	hw->op_mode = (hwcfg2 & GHWCFG2_OP_MODE_MASK) >>
+		      GHWCFG2_OP_MODE_SHIFT;
+	hw->arch = (hwcfg2 & GHWCFG2_ARCHITECTURE_MASK) >>
+		   GHWCFG2_ARCHITECTURE_SHIFT;
+	hw->enable_dynamic_fifo = !!(hwcfg2 & GHWCFG2_DYNAMIC_FIFO);
+	hw->host_channels = 1 + ((hwcfg2 & GHWCFG2_NUM_HOST_CHAN_MASK) >>
+				GHWCFG2_NUM_HOST_CHAN_SHIFT);
+	hw->hs_phy_type = (hwcfg2 & GHWCFG2_HS_PHY_TYPE_MASK) >>
+			  GHWCFG2_HS_PHY_TYPE_SHIFT;
+	hw->fs_phy_type = (hwcfg2 & GHWCFG2_FS_PHY_TYPE_MASK) >>
+			  GHWCFG2_FS_PHY_TYPE_SHIFT;
+	hw->num_dev_ep = (hwcfg2 & GHWCFG2_NUM_DEV_EP_MASK) >>
+			 GHWCFG2_NUM_DEV_EP_SHIFT;
+	hw->nperio_tx_q_depth =
+		(hwcfg2 & GHWCFG2_NONPERIO_TX_Q_DEPTH_MASK) >>
+		GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT << 1;
+	hw->host_perio_tx_q_depth =
+		(hwcfg2 & GHWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK) >>
+		GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT << 1;
+	hw->dev_token_q_depth =
+		(hwcfg2 & GHWCFG2_DEV_TOKEN_Q_DEPTH_MASK) >>
+		GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT;
+
+	/* hwcfg3 */
+	width = (hwcfg3 & GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK) >>
+		GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT;
+	hw->max_transfer_size = (1 << (width + 11)) - 1;
+	width = (hwcfg3 & GHWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK) >>
+		GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT;
+	hw->max_packet_count = (1 << (width + 4)) - 1;
+	hw->i2c_enable = !!(hwcfg3 & GHWCFG3_I2C);
+	hw->total_fifo_size = (hwcfg3 & GHWCFG3_DFIFO_DEPTH_MASK) >>
+			      GHWCFG3_DFIFO_DEPTH_SHIFT;
+	hw->lpm_mode = !!(hwcfg3 & GHWCFG3_OTG_LPM_EN);
+
+	/* hwcfg4 */
+	hw->en_multiple_tx_fifo = !!(hwcfg4 & GHWCFG4_DED_FIFO_EN);
+	hw->num_dev_perio_in_ep = (hwcfg4 & GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK) >>
+				  GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT;
+	hw->num_dev_in_eps = (hwcfg4 & GHWCFG4_NUM_IN_EPS_MASK) >>
+			     GHWCFG4_NUM_IN_EPS_SHIFT;
+	hw->dma_desc_enable = !!(hwcfg4 & GHWCFG4_DESC_DMA);
+	hw->power_optimized = !!(hwcfg4 & GHWCFG4_POWER_OPTIMIZ);
+	hw->hibernation = !!(hwcfg4 & GHWCFG4_HIBER);
+	hw->utmi_phy_data_width = (hwcfg4 & GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK) >>
+				  GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT;
+	hw->acg_enable = !!(hwcfg4 & GHWCFG4_ACG_SUPPORTED);
+	hw->ipg_isoc_en = !!(hwcfg4 & GHWCFG4_IPG_ISOC_SUPPORTED);
+
+	/* fifo sizes */
+	hw->rx_fifo_size = (grxfsiz & GRXFSIZ_DEPTH_MASK) >>
+				GRXFSIZ_DEPTH_SHIFT;
+}
+
+/*
+ * Initializes the FSLSPClkSel field of the HCFG register depending on the
+ * PHY type
+ */
+void dwc2_init_fs_ls_pclk_sel(struct dwc2 *dwc2)
+{
+	u32 hcfg, val;
+
+	if ((dwc2->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
+	     dwc2->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED &&
+	     dwc2->params.ulpi_fs_ls) ||
+	    dwc2->params.phy_type == DWC2_PHY_TYPE_PARAM_FS) {
+		/* Full speed PHY */
+		val = HCFG_FSLSPCLKSEL_48_MHZ;
+	} else {
+		/* High speed PHY running at full speed or high speed */
+		val = HCFG_FSLSPCLKSEL_30_60_MHZ;
+	}
+
+	dwc2_dbg(dwc2, "Initializing HCFG.FSLSPClkSel to %08x\n", val);
+	hcfg = dwc2_readl(dwc2, HCFG);
+	hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
+	hcfg |= val << HCFG_FSLSPCLKSEL_SHIFT;
+	dwc2_writel(dwc2, hcfg, HCFG);
+}
+
+void dwc2_flush_all_fifo(struct dwc2 *dwc2)
+{
+	uint32_t greset;
+
+	/* Wait for AHB master IDLE state */
+	if (dwc2_wait_bit_set(dwc2, GRSTCTL, GRSTCTL_AHBIDLE, 100)) {
+		dwc2_err(dwc2, "%s: Timeout waiting for AHB Idle\n", __func__);
+		return;
+	}
+
+	greset = GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH;
+	/* TXFNUM of 0x10 is to flush all TX FIFO */
+	dwc2_writel(dwc2, greset | GRSTCTL_TXFNUM(0x10), GRSTCTL);
+
+	/* Wait for TxFIFO and RxFIFO flush done */
+	if (dwc2_wait_bit_clear(dwc2, GRSTCTL, greset, 100))
+		dwc2_err(dwc2, "Timeout flushing fifos (GRSTCTL=%08x)\n",
+			 dwc2_readl(dwc2, GRSTCTL));
+
+	/* Wait for 3 PHY Clocks */
+	udelay(1);
+}
+
+static int dwc2_fs_phy_init(struct dwc2 *dwc2, bool select_phy)
+{
+	u32 usbcfg, ggpio, i2cctl;
+	int retval = 0;
+
+	/*
+	 * core_init() is now called on every switch so only call the
+	 * following for the first time through
+	 */
+	if (select_phy) {
+		dwc2_dbg(dwc2, "FS PHY selected\n");
+
+		usbcfg = dwc2_readl(dwc2, GUSBCFG);
+		if (!(usbcfg & GUSBCFG_PHYSEL)) {
+			usbcfg |= GUSBCFG_PHYSEL;
+			dwc2_writel(dwc2, usbcfg, GUSBCFG);
+
+			/* Reset after a PHY select */
+			retval = dwc2_core_reset(dwc2);
+
+			if (retval) {
+				dwc2_err(dwc2,
+					"%s: Reset failed, aborting", __func__);
+				return retval;
+			}
+		}
+
+		if (dwc2->params.activate_stm_fs_transceiver) {
+			ggpio = dwc2_readl(dwc2, GGPIO);
+			if (!(ggpio & GGPIO_STM32_OTG_GCCFG_PWRDWN)) {
+				dwc2_dbg(dwc2, "Activating transceiver\n");
+				/*
+				 * STM32F4x9 uses the GGPIO register as general
+				 * core configuration register.
+				 */
+				ggpio |= GGPIO_STM32_OTG_GCCFG_PWRDWN;
+				dwc2_writel(dwc2, ggpio, GGPIO);
+			}
+		}
+	}
+
+	if (dwc2->params.i2c_enable) {
+		dwc2_dbg(dwc2, "FS PHY enabling I2C\n");
+
+		/* Program GUSBCFG.OtgUtmiFsSel to I2C */
+		usbcfg = dwc2_readl(dwc2, GUSBCFG);
+		usbcfg |= GUSBCFG_OTG_UTMI_FS_SEL;
+		dwc2_writel(dwc2, usbcfg, GUSBCFG);
+
+		/* Program GI2CCTL.I2CEn */
+		i2cctl = dwc2_readl(dwc2, GI2CCTL);
+		i2cctl &= ~GI2CCTL_I2CDEVADDR_MASK;
+		i2cctl |= 1 << GI2CCTL_I2CDEVADDR_SHIFT;
+		i2cctl &= ~GI2CCTL_I2CEN;
+		dwc2_writel(dwc2, i2cctl, GI2CCTL);
+		i2cctl |= GI2CCTL_I2CEN;
+		dwc2_writel(dwc2, i2cctl, GI2CCTL);
+	}
+
+	return retval;
+}
+
+static int dwc2_hs_phy_init(struct dwc2 *dwc2, bool select_phy)
+{
+	u32 usbcfg, usbcfg_old;
+	int retval = 0;
+
+	if (!select_phy)
+		return 0;
+
+	usbcfg = dwc2_readl(dwc2, GUSBCFG);
+	usbcfg_old = usbcfg;
+
+	/*
+	 * HS PHY parameters. These parameters are preserved during soft reset
+	 * so only program the first time. Do a soft reset immediately after
+	 * setting phyif.
+	 */
+	switch (dwc2->params.phy_type) {
+	case DWC2_PHY_TYPE_PARAM_ULPI:
+		/* ULPI interface */
+		dwc2_dbg(dwc2, "HS ULPI PHY selected\n");
+		usbcfg |= GUSBCFG_ULPI_UTMI_SEL;
+		usbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL | GUSBCFG_PHYSEL);
+		if (dwc2->params.phy_ulpi_ddr)
+			usbcfg |= GUSBCFG_DDRSEL;
+
+		/* Set external VBUS indicator as needed. */
+		if (dwc2->params.phy_ulpi_ext_vbus_ind) {
+			dwc2_dbg(dwc2, "Use external VBUS indicator\n");
+			usbcfg |= GUSBCFG_ULPI_EXT_VBUS_IND;
+			usbcfg &= ~GUSBCFG_INDICATORCOMPLEMENT;
+			usbcfg &= ~GUSBCFG_INDICATORPASSTHROUGH;
+
+			if (dwc2->params.phy_ulpi_ext_vbus_ind_complement)
+				usbcfg |= GUSBCFG_INDICATORCOMPLEMENT;
+			if (dwc2->params.phy_ulpi_ext_vbus_ind_passthrough)
+				usbcfg |= GUSBCFG_INDICATORPASSTHROUGH;
+		}
+		break;
+	case DWC2_PHY_TYPE_PARAM_UTMI:
+		/* UTMI+ interface */
+		dwc2_dbg(dwc2, "HS UTMI+ PHY selected\n");
+		usbcfg &= ~(GUSBCFG_ULPI_UTMI_SEL | GUSBCFG_PHYIF16);
+		if (dwc2->params.phy_utmi_width == 16)
+			usbcfg |= GUSBCFG_PHYIF16;
+		break;
+	default:
+		dwc2_err(dwc2, "FS PHY selected at HS!\n");
+		break;
+	}
+
+	if (usbcfg != usbcfg_old) {
+		dwc2_writel(dwc2, usbcfg, GUSBCFG);
+
+		/* Reset after setting the PHY parameters */
+		retval = dwc2_core_reset(dwc2);
+		if (retval) {
+			dwc2_err(dwc2,
+				"%s: Reset failed, aborting", __func__);
+			return retval;
+		}
+	}
+
+	return retval;
+}
+
+int dwc2_phy_init(struct dwc2 *dwc2, bool select_phy)
+{
+	u32 usbcfg;
+	int retval = 0;
+
+	if ((dwc2->params.speed == DWC2_SPEED_PARAM_FULL ||
+	     dwc2->params.speed == DWC2_SPEED_PARAM_LOW) &&
+	    dwc2->params.phy_type == DWC2_PHY_TYPE_PARAM_FS) {
+		/* If FS/LS mode with FS/LS PHY */
+		retval = dwc2_fs_phy_init(dwc2, select_phy);
+		if (retval)
+			return retval;
+	} else {
+		/* High speed PHY */
+		retval = dwc2_hs_phy_init(dwc2, select_phy);
+		if (retval)
+			return retval;
+	}
+
+	usbcfg = dwc2_readl(dwc2, GUSBCFG);
+	usbcfg &= ~GUSBCFG_ULPI_FS_LS;
+	usbcfg &= ~GUSBCFG_ULPI_CLK_SUSP_M;
+	if (dwc2->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
+	    dwc2->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED &&
+	    dwc2->params.ulpi_fs_ls) {
+		dwc2_dbg(dwc2, "Setting ULPI FSLS\n");
+		usbcfg |= GUSBCFG_ULPI_FS_LS;
+		usbcfg |= GUSBCFG_ULPI_CLK_SUSP_M;
+	}
+	dwc2_writel(dwc2, usbcfg, GUSBCFG);
+
+	return retval;
+}
+
+int dwc2_gahbcfg_init(struct dwc2 *dwc2)
+{
+	u32 ahbcfg = dwc2_readl(dwc2, GAHBCFG);
+
+	switch (dwc2->hw_params.arch) {
+	case GHWCFG2_EXT_DMA_ARCH:
+		dwc2_err(dwc2, "External DMA Mode not supported\n");
+		return -EINVAL;
+
+	case GHWCFG2_INT_DMA_ARCH:
+		dwc2_dbg(dwc2, "Internal DMA Mode\n");
+		if (dwc2->params.ahbcfg != -1) {
+			ahbcfg &= GAHBCFG_CTRL_MASK;
+			ahbcfg |= dwc2->params.ahbcfg &
+				  ~GAHBCFG_CTRL_MASK;
+		}
+		break;
+
+	case GHWCFG2_SLAVE_ONLY_ARCH:
+	default:
+		dwc2_dbg(dwc2, "Slave Only Mode\n");
+		break;
+	}
+
+	if (dwc2->params.dma)
+		ahbcfg |= GAHBCFG_DMA_EN;
+	else
+		dwc2->params.dma_desc = false;
+
+	dwc2_writel(dwc2, ahbcfg, GAHBCFG);
+
+	return 0;
+}
+
+void dwc2_gusbcfg_init(struct dwc2 *dwc2)
+{
+	u32 usbcfg;
+
+	usbcfg = dwc2_readl(dwc2, GUSBCFG);
+	usbcfg &= ~(GUSBCFG_HNPCAP | GUSBCFG_SRPCAP);
+
+	switch (dwc2->hw_params.op_mode) {
+	case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE:
+		if (dwc2->params.otg_cap ==
+				DWC2_CAP_PARAM_HNP_SRP_CAPABLE)
+			usbcfg |= GUSBCFG_HNPCAP;
+
+	case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE:
+	case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE:
+	case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST:
+		if (dwc2->params.otg_cap !=
+				DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE)
+			usbcfg |= GUSBCFG_SRPCAP;
+		break;
+
+	case GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE:
+	case GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE:
+	case GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST:
+	default:
+		break;
+	}
+
+	dwc2_writel(dwc2, usbcfg, GUSBCFG);
+}
+
+/*
+ * Do core a soft reset of the core.  Be careful with this because it
+ * resets all the internal state machines of the core.
+ */
+int dwc2_core_reset(struct dwc2 *dwc2)
+{
+	bool wait_for_host_mode = false;
+	uint32_t greset;
+	int ret;
+
+	dwc2_dbg(dwc2, "%s(%p)\n", __func__, dwc2);
+
+	/* Wait for AHB master IDLE state. */
+	ret = dwc2_wait_bit_set(dwc2, GRSTCTL, GRSTCTL_AHBIDLE, 10000);
+	if (ret) {
+		pr_info("%s: Timeout! Waiting for AHB master IDLE state\n",
+			__func__);
+		return ret;
+	}
+
+	/*
+	 * If the current mode is host, either due to the force mode
+	 * bit being set (which persists after core reset) or the
+	 * connector id pin, a core soft reset will temporarily reset
+	 * the mode to device. A delay from the IDDIG debounce filter
+	 * will occur before going back to host mode.
+	 *
+	 * Determine whether we will go back into host mode after a
+	 * reset and account for this delay after the reset.
+	 */
+	{
+	u32 gotgctl = dwc2_readl(dwc2, GOTGCTL);
+	u32 gusbcfg = dwc2_readl(dwc2, GUSBCFG);
+
+	if (!(gotgctl & GOTGCTL_CONID_B) ||
+	    (gusbcfg & GUSBCFG_FORCEHOSTMODE)) {
+		dwc2_dbg(dwc2, "HOST MODE\n");
+		wait_for_host_mode = true;
+	}
+	}
+	/* Core Soft Reset */
+	greset = dwc2_readl(dwc2, GRSTCTL);
+	greset |= GRSTCTL_CSFTRST;
+	dwc2_writel(dwc2, greset, GRSTCTL);
+
+	ret = dwc2_wait_bit_clear(dwc2, GRSTCTL, GRSTCTL_CSFTRST, 10000);
+	if (ret) {
+		pr_info("%s: Timeout! Waiting for Core Soft Reset\n", __func__);
+		return ret;
+	}
+
+	/*
+	 * Wait for core to come out of reset.
+	 * NOTE: This long sleep is _very_ important, otherwise the core will
+	 *       not stay in host mode after a connector ID change!
+	 */
+	mdelay(100);
+
+	return 0;
+}
+
+/*
+ * This function initializes the DWC2 controller registers and
+ * prepares the core for device mode or host mode operation.
+ *
+ * @param regs Programming view of the DWC2 controller
+ */
+void dwc2_core_init(struct dwc2 *dwc2)
+{
+	uint32_t otgctl = 0;
+	uint32_t usbcfg = 0;
+	int retval;
+
+	dwc2_dbg(dwc2, "%s(%p)\n", __func__, dwc2);
+
+	/* Common Initialization */
+	usbcfg = dwc2_readl(dwc2, GUSBCFG);
+
+	/* Set ULPI External VBUS bit if needed */
+	usbcfg &= ~GUSBCFG_ULPI_EXT_VBUS_DRV;
+	if (dwc2->params.phy_ulpi_ext_vbus)
+		usbcfg |= GUSBCFG_ULPI_EXT_VBUS_DRV;
+
+	/* Set external TS Dline pulsing bit if needed */
+	usbcfg &= ~GUSBCFG_TERMSELDLPULSE;
+	if (dwc2->params.ts_dline)
+		usbcfg |= GUSBCFG_TERMSELDLPULSE;
+
+	dwc2_writel(dwc2, usbcfg, GUSBCFG);
+
+	/* Reset the Controller */
+	dwc2_core_reset(dwc2);
+
+	/*
+	 * This programming sequence needs to happen in FS mode before
+	 * any other programming occurs
+	 */
+	retval = dwc2_phy_init(dwc2, true);
+	if (retval)
+		return;
+
+	/* Program the GAHBCFG Register */
+	retval = dwc2_gahbcfg_init(dwc2);
+	if (retval)
+		return;
+
+	/* Program the GUSBCFG register */
+	dwc2_gusbcfg_init(dwc2);
+
+	/* Program the GOTGCTL register */
+	otgctl = dwc2_readl(dwc2, GOTGCTL);
+	otgctl &= ~GOTGCTL_OTGVER;
+	dwc2_writel(dwc2, otgctl, GOTGCTL);
+
+	if (dwc2_is_host_mode(dwc2))
+		dwc2_dbg(dwc2, "Host Mode\n");
+	else
+		dwc2_dbg(dwc2, "Device Mode\n");
+}
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
new file mode 100644
index 000000000..0c89217c5
--- /dev/null
+++ b/drivers/usb/dwc2/core.h
@@ -0,0 +1,546 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Maximum number of Endpoints/HostChannels */
+#define DWC2_MAX_EPS_CHANNELS	16
+
+/**
+ * struct dwc2_core_params - Parameters for configuring the core
+ *
+ * @otg_cap:            Specifies the OTG capabilities.
+ *                       0 - HNP and SRP capable
+ *                       1 - SRP Only capable
+ *                       2 - No HNP/SRP capable (always available)
+ *                      Defaults to best available option (0, 1, then 2)
+ * @host_dma:           Specifies whether to use slave or DMA mode for accessing
+ *                      the data FIFOs. The driver will automatically detect the
+ *                      value for this parameter if none is specified.
+ *                       0 - Slave (always available)
+ *                       1 - DMA (default, if available)
+ * @dma_desc_enable:    When DMA mode is enabled, specifies whether to use
+ *                      address DMA mode or descriptor DMA mode for accessing
+ *                      the data FIFOs. The driver will automatically detect the
+ *                      value for this if none is specified.
+ *                       0 - Address DMA
+ *                       1 - Descriptor DMA (default, if available)
+ * @dma_desc_fs_enable: When DMA mode is enabled, specifies whether to use
+ *                      address DMA mode or descriptor DMA mode for accessing
+ *                      the data FIFOs in Full Speed mode only. The driver
+ *                      will automatically detect the value for this if none is
+ *                      specified.
+ *                       0 - Address DMA
+ *                       1 - Descriptor DMA in FS (default, if available)
+ * @speed:              Specifies the maximum speed of operation in host and
+ *                      device mode. The actual speed depends on the speed of
+ *                      the attached device and the value of phy_type.
+ *                       0 - High Speed
+ *                           (default when phy_type is UTMI+ or ULPI)
+ *                       1 - Full Speed
+ *                           (default when phy_type is Full Speed)
+ * @enable_dynamic_fifo: 0 - Use coreConsultant-specified FIFO size parameters
+ *                       1 - Allow dynamic FIFO sizing (default, if available)
+ * @en_multiple_tx_fifo: Specifies whether dedicated per-endpoint transmit FIFOs
+ *                      are enabled for non-periodic IN endpoints in device
+ *                      mode.
+ * @host_rx_fifo_size:  Number of 4-byte words in the Rx FIFO in host mode when
+ *                      dynamic FIFO sizing is enabled
+ *                       16 to 32768
+ *                      Actual maximum value is autodetected and also
+ *                      the default.
+ * @host_nperio_tx_fifo_size: Number of 4-byte words in the non-periodic Tx FIFO
+ *                      in host mode when dynamic FIFO sizing is enabled
+ *                       16 to 32768
+ *                      Actual maximum value is autodetected and also
+ *                      the default.
+ * @host_perio_tx_fifo_size: Number of 4-byte words in the periodic Tx FIFO in
+ *                      host mode when dynamic FIFO sizing is enabled
+ *                       16 to 32768
+ *                      Actual maximum value is autodetected and also
+ *                      the default.
+ * @max_transfer_size:  The maximum transfer size supported, in bytes
+ *                       2047 to 65,535
+ *                      Actual maximum value is autodetected and also
+ *                      the default.
+ * @max_packet_count:   The maximum number of packets in a transfer
+ *                       15 to 511
+ *                      Actual maximum value is autodetected and also
+ *                      the default.
+ * @host_channels:      The number of host channel registers to use
+ *                       1 to 16
+ *                      Actual maximum value is autodetected and also
+ *                      the default.
+ * @phy_type:           Specifies the type of PHY interface to use. By default,
+ *                      the driver will automatically detect the phy_type.
+ *                       0 - Full Speed Phy
+ *                       1 - UTMI+ Phy
+ *                       2 - ULPI Phy
+ *                      Defaults to best available option (2, 1, then 0)
+ * @phy_utmi_width:     Specifies the UTMI+ Data Width (in bits). This parameter
+ *                      is applicable for a phy_type of UTMI+ or ULPI. (For a
+ *                      ULPI phy_type, this parameter indicates the data width
+ *                      between the MAC and the ULPI Wrapper.) Also, this
+ *                      parameter is applicable only if the OTG_HSPHY_WIDTH cC
+ *                      parameter was set to "8 and 16 bits", meaning that the
+ *                      core has been configured to work at either data path
+ *                      width.
+ *                       8 or 16 (default 16 if available)
+ * @phy_ulpi_ddr:       Specifies whether the ULPI operates at double or single
+ *                      data rate. This parameter is only applicable if phy_type
+ *                      is ULPI.
+ *                       0 - single data rate ULPI interface with 8 bit wide
+ *                           data bus (default)
+ *                       1 - double data rate ULPI interface with 4 bit wide
+ *                           data bus
+ * @phy_ulpi_ext_vbus:  For a ULPI phy, specifies whether to use the internal or
+ *                      external supply to drive the VBus
+ *                       0 - Internal supply (default)
+ *                       1 - External supply
+ * @i2c_enable:         Specifies whether to use the I2Cinterface for a full
+ *                      speed PHY. This parameter is only applicable if phy_type
+ *                      is FS.
+ *                       0 - No (default)
+ *                       1 - Yes
+ * @ipg_isoc_en:        Indicates the IPG supports is enabled or disabled.
+ *                       0 - Disable (default)
+ *                       1 - Enable
+ * @acg_enable:		For enabling Active Clock Gating in the controller
+ *                       0 - No
+ *                       1 - Yes
+ * @ulpi_fs_ls:         Make ULPI phy operate in FS/LS mode only
+ *                       0 - No (default)
+ *                       1 - Yes
+ * @host_support_fs_ls_low_power: Specifies whether low power mode is supported
+ *                      when attached to a Full Speed or Low Speed device in
+ *                      host mode.
+ *                       0 - Don't support low power mode (default)
+ *                       1 - Support low power mode
+ * @host_ls_low_power_phy_clk: Specifies the PHY clock rate in low power mode
+ *                      when connected to a Low Speed device in host
+ *                      mode. This parameter is applicable only if
+ *                      host_support_fs_ls_low_power is enabled.
+ *                       0 - 48 MHz
+ *                           (default when phy_type is UTMI+ or ULPI)
+ *                       1 - 6 MHz
+ *                           (default when phy_type is Full Speed)
+ * @oc_disable:		Flag to disable overcurrent condition.
+ *			0 - Allow overcurrent condition to get detected
+ *			1 - Disable overcurrent condtion to get detected
+ * @ts_dline:           Enable Term Select Dline pulsing
+ *                       0 - No (default)
+ *                       1 - Yes
+ * @reload_ctl:         Allow dynamic reloading of HFIR register during runtime
+ *                       0 - No (default for core < 2.92a)
+ *                       1 - Yes (default for core >= 2.92a)
+ * @ahbcfg:             This field allows the default value of the GAHBCFG
+ *                      register to be overridden
+ *                       -1         - GAHBCFG value will be set to 0x06
+ *                                    (INCR, default)
+ *                       all others - GAHBCFG value will be overridden with
+ *                                    this value
+ *                      Not all bits can be controlled like this, the
+ *                      bits defined by GAHBCFG_CTRL_MASK are controlled
+ *                      by the driver and are ignored in this
+ *                      configuration value.
+ * @uframe_sched:       True to enable the microframe scheduler
+ * @external_id_pin_ctl: Specifies whether ID pin is handled externally.
+ *                      Disable CONIDSTSCHNG controller interrupt in such
+ *                      case.
+ *                      0 - No (default)
+ *                      1 - Yes
+ * @power_down:         Specifies whether the controller support power_down.
+ *			If power_down is enabled, the controller will enter
+ *			power_down in both peripheral and host mode when
+ *			needed.
+ *			0 - No (default)
+ *			1 - Partial power down
+ *			2 - Hibernation
+ * @lpm:		Enable LPM support.
+ *			0 - No
+ *			1 - Yes
+ * @lpm_clock_gating:		Enable core PHY clock gating.
+ *			0 - No
+ *			1 - Yes
+ * @besl:		Enable LPM Errata support.
+ *			0 - No
+ *			1 - Yes
+ * @hird_threshold_en:	HIRD or HIRD Threshold enable.
+ *			0 - No
+ *			1 - Yes
+ * @hird_threshold:	Value of BESL or HIRD Threshold.
+ * @activate_stm_fs_transceiver: Activate internal transceiver using GGPIO
+ *			register.
+ *			0 - Deactivate the transceiver (default)
+ *			1 - Activate the transceiver
+ * @g_dma:              Enables gadget dma usage (default: autodetect).
+ * @g_dma_desc:         Enables gadget descriptor DMA (default: autodetect).
+ * @g_rx_fifo_size:	The periodic rx fifo size for the device, in
+ *			DWORDS from 16-32768 (default: 2048 if
+ *			possible, otherwise autodetect).
+ * @g_np_tx_fifo_size:	The non-periodic tx fifo size for the device in
+ *			DWORDS from 16-32768 (default: 1024 if
+ *			possible, otherwise autodetect).
+ * @g_tx_fifo_size:	An array of TX fifo sizes in dedicated fifo
+ *			mode. Each value corresponds to one EP
+ *			starting from EP1 (max 15 values). Sizes are
+ *			in DWORDS with possible values from from
+ *			16-32768 (default: 256, 256, 256, 256, 768,
+ *			768, 768, 768, 0, 0, 0, 0, 0, 0, 0).
+ * @change_speed_quirk: Change speed configuration to DWC2_SPEED_PARAM_FULL
+ *                      while full&low speed device connect. And change speed
+ *                      back to DWC2_SPEED_PARAM_HIGH while device is gone.
+ *			0 - No (default)
+ *			1 - Yes
+ *
+ * The following parameters may be specified when starting the module. These
+ * parameters define how the DWC_otg controller should be configured. A
+ * value of -1 (or any other out of range value) for any parameter means
+ * to read the value from hardware (if possible) or use the builtin
+ * default described above.
+ */
+struct dwc2_core_params {
+	u8 otg_cap;
+#define DWC2_CAP_PARAM_HNP_SRP_CAPABLE		0
+#define DWC2_CAP_PARAM_SRP_ONLY_CAPABLE		1
+#define DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE	2
+
+	u8 phy_type;
+#define DWC2_PHY_TYPE_PARAM_FS		0
+#define DWC2_PHY_TYPE_PARAM_UTMI	1
+#define DWC2_PHY_TYPE_PARAM_ULPI	2
+
+	u8 speed;
+#define DWC2_SPEED_PARAM_HIGH	0
+#define DWC2_SPEED_PARAM_FULL	1
+#define DWC2_SPEED_PARAM_LOW	2
+
+	u8 phy_utmi_width;
+	bool phy_ulpi_ddr;
+	bool phy_ulpi_ext_vbus;
+	bool phy_ulpi_ext_vbus_ind;
+	bool phy_ulpi_ext_vbus_ind_complement;
+	bool phy_ulpi_ext_vbus_ind_passthrough;
+
+	bool enable_dynamic_fifo;
+	bool en_multiple_tx_fifo;
+	bool i2c_enable;
+	bool acg_enable;
+	bool ulpi_fs_ls;
+	bool ts_dline;
+	bool reload_ctl;
+	bool uframe_sched;
+	bool external_id_pin_ctl;
+
+	int power_down;
+#define DWC2_POWER_DOWN_PARAM_NONE		0
+#define DWC2_POWER_DOWN_PARAM_PARTIAL		1
+#define DWC2_POWER_DOWN_PARAM_HIBERNATION	2
+
+	bool lpm;
+	bool lpm_clock_gating;
+	bool besl;
+	bool hird_threshold_en;
+	u8 hird_threshold;
+	bool activate_stm_fs_transceiver;
+	bool ipg_isoc_en;
+	u16 max_packet_count;
+	u32 max_transfer_size;
+	u32 ahbcfg;
+
+	bool dma;
+	bool dma_desc;
+
+	/* Host parameters */
+	bool host_support_fs_ls_low_power;
+	bool host_ls_low_power_phy_clk;
+
+	u8 host_channels;
+	u16 host_rx_fifo_size;
+	u16 host_nperio_tx_fifo_size;
+	u16 host_perio_tx_fifo_size;
+
+	/* Gadget parameters */
+	u32 g_rx_fifo_size;
+	u32 g_np_tx_fifo_size;
+	u32 g_tx_fifo_size[DWC2_MAX_EPS_CHANNELS];
+
+	bool change_speed_quirk;
+};
+
+/**
+ * struct dwc2_hw_params - Autodetected parameters.
+ *
+ * These parameters are the various parameters read from hardware
+ * registers during initialization. They typically contain the best
+ * supported or maximum value that can be configured in the
+ * corresponding dwc2_core_params value.
+ *
+ * The values that are not in dwc2_core_params are documented below.
+ *
+ * @op_mode:             Mode of Operation
+ *                       0 - HNP- and SRP-Capable OTG (Host & Device)
+ *                       1 - SRP-Capable OTG (Host & Device)
+ *                       2 - Non-HNP and Non-SRP Capable OTG (Host & Device)
+ *                       3 - SRP-Capable Device
+ *                       4 - Non-OTG Device
+ *                       5 - SRP-Capable Host
+ *                       6 - Non-OTG Host
+ * @arch:                Architecture
+ *                       0 - Slave only
+ *                       1 - External DMA
+ *                       2 - Internal DMA
+ * @ipg_isoc_en:        This feature indicates that the controller supports
+ *                      the worst-case scenario of Rx followed by Rx
+ *                      Interpacket Gap (IPG) (32 bitTimes) as per the utmi
+ *                      specification for any token following ISOC OUT token.
+ *                       0 - Don't support
+ *                       1 - Support
+ * @power_optimized:    Are power optimizations enabled?
+ * @num_dev_ep:         Number of device endpoints available
+ * @num_dev_in_eps:     Number of device IN endpoints available
+ * @num_dev_perio_in_ep: Number of device periodic IN endpoints
+ *                       available
+ * @dev_token_q_depth:  Device Mode IN Token Sequence Learning Queue
+ *                      Depth
+ *                       0 to 30
+ * @host_perio_tx_q_depth:
+ *                      Host Mode Periodic Request Queue Depth
+ *                       2, 4 or 8
+ * @nperio_tx_q_depth:
+ *                      Non-Periodic Request Queue Depth
+ *                       2, 4 or 8
+ * @hs_phy_type:         High-speed PHY interface type
+ *                       0 - High-speed interface not supported
+ *                       1 - UTMI+
+ *                       2 - ULPI
+ *                       3 - UTMI+ and ULPI
+ * @fs_phy_type:         Full-speed PHY interface type
+ *                       0 - Full speed interface not supported
+ *                       1 - Dedicated full speed interface
+ *                       2 - FS pins shared with UTMI+ pins
+ *                       3 - FS pins shared with ULPI pins
+ * @total_fifo_size:    Total internal RAM for FIFOs (bytes)
+ * @hibernation:	Is hibernation enabled?
+ * @utmi_phy_data_width: UTMI+ PHY data width
+ *                       0 - 8 bits
+ *                       1 - 16 bits
+ *                       2 - 8 or 16 bits
+ * @snpsid:             Value from SNPSID register
+ * @dev_ep_dirs:        Direction of device endpoints (GHWCFG1)
+ * @g_tx_fifo_size:	Power-on values of TxFIFO sizes
+ * @dma_desc_enable:    When DMA mode is enabled, specifies whether to use
+ *                      address DMA mode or descriptor DMA mode for accessing
+ *                      the data FIFOs. The driver will automatically detect the
+ *                      value for this if none is specified.
+ *                       0 - Address DMA
+ *                       1 - Descriptor DMA (default, if available)
+ * @enable_dynamic_fifo: 0 - Use coreConsultant-specified FIFO size parameters
+ *                       1 - Allow dynamic FIFO sizing (default, if available)
+ * @en_multiple_tx_fifo: Specifies whether dedicated per-endpoint transmit FIFOs
+ *                      are enabled for non-periodic IN endpoints in device
+ *                      mode.
+ * @host_nperio_tx_fifo_size: Number of 4-byte words in the non-periodic Tx FIFO
+ *                      in host mode when dynamic FIFO sizing is enabled
+ *                       16 to 32768
+ *                      Actual maximum value is autodetected and also
+ *                      the default.
+ * @host_perio_tx_fifo_size: Number of 4-byte words in the periodic Tx FIFO in
+ *                      host mode when dynamic FIFO sizing is enabled
+ *                       16 to 32768
+ *                      Actual maximum value is autodetected and also
+ *                      the default.
+ * @max_transfer_size:  The maximum transfer size supported, in bytes
+ *                       2047 to 65,535
+ *                      Actual maximum value is autodetected and also
+ *                      the default.
+ * @max_packet_count:   The maximum number of packets in a transfer
+ *                       15 to 511
+ *                      Actual maximum value is autodetected and also
+ *                      the default.
+ * @host_channels:      The number of host channel registers to use
+ *                       1 to 16
+ *                      Actual maximum value is autodetected and also
+ *                      the default.
+ * @dev_nperio_tx_fifo_size: Number of 4-byte words in the non-periodic Tx FIFO
+ *			     in device mode when dynamic FIFO sizing is enabled
+ *			     16 to 32768
+ *			     Actual maximum value is autodetected and also
+ *			     the default.
+ * @i2c_enable:         Specifies whether to use the I2Cinterface for a full
+ *                      speed PHY. This parameter is only applicable if phy_type
+ *                      is FS.
+ *                       0 - No (default)
+ *                       1 - Yes
+ * @acg_enable:		For enabling Active Clock Gating in the controller
+ *                       0 - Disable
+ *                       1 - Enable
+ * @lpm_mode:		For enabling Link Power Management in the controller
+ *                       0 - Disable
+ *                       1 - Enable
+ * @rx_fifo_size:	Number of 4-byte words in the  Rx FIFO when dynamic
+ *			FIFO sizing is enabled 16 to 32768
+ *			Actual maximum value is autodetected and also
+ *			the default.
+ */
+struct dwc2_hw_params {
+	unsigned op_mode:3;
+	unsigned arch:2;
+	unsigned dma_desc_enable:1;
+	unsigned enable_dynamic_fifo:1;
+	unsigned en_multiple_tx_fifo:1;
+	unsigned rx_fifo_size:16;
+	unsigned host_nperio_tx_fifo_size:16;
+	unsigned dev_nperio_tx_fifo_size:16;
+	unsigned host_perio_tx_fifo_size:16;
+	unsigned nperio_tx_q_depth:3;
+	unsigned host_perio_tx_q_depth:3;
+	unsigned dev_token_q_depth:5;
+	unsigned max_transfer_size:26;
+	unsigned max_packet_count:11;
+	unsigned host_channels:5;
+	unsigned hs_phy_type:2;
+	unsigned fs_phy_type:2;
+	unsigned i2c_enable:1;
+	unsigned acg_enable:1;
+	unsigned num_dev_ep:4;
+	unsigned num_dev_in_eps:4;
+	unsigned num_dev_perio_in_ep:4;
+	unsigned total_fifo_size:16;
+	unsigned power_optimized:1;
+	unsigned hibernation:1;
+	unsigned utmi_phy_data_width:2;
+	unsigned lpm_mode:1;
+	unsigned ipg_isoc_en:1;
+	u32 snpsid;
+	u32 dev_ep_dirs;
+	u32 g_tx_fifo_size[DWC2_MAX_EPS_CHANNELS];
+};
+
+#define MAX_DEVICE			16
+#define MAX_ENDPOINT DWC2_MAX_EPS_CHANNELS
+
+struct dwc2 {
+	struct device_d *dev;
+	struct usb_host host;
+	struct usb_gadget gadget;
+	struct dwc2_hw_params hw_params;
+	struct dwc2_core_params params;
+
+	u8 in_data_toggle[MAX_DEVICE][MAX_ENDPOINT];
+	u8 out_data_toggle[MAX_DEVICE][MAX_ENDPOINT];
+	void __iomem *regs;
+	int root_hub_devnum;
+
+	enum usb_dr_mode dr_mode;
+};
+
+#define host_to_dwc2(ptr) container_of(ptr, struct dwc2, host)
+#define gadget_to_dwc2(ptr) container_of(ptr, struct dwc2, gadget)
+
+#define dwc2_err(d, arg...) dev_err((d)->dev, ## arg)
+#define dwc2_warn(d, arg...) dev_err((d)->dev, ## arg)
+#define dwc2_info(d, arg...) dev_info((d)->dev, ## arg)
+#define dwc2_dbg(d, arg...) dev_dbg((d)->dev, ## arg)
+#define dwc2_vdbg(d, arg...) dev_vdbg((d)->dev, ## arg)
+
+static inline u32 dwc2_readl(struct dwc2 *dwc2, u32 offset)
+{
+	u32 val;
+
+	val = readl(dwc2->regs + offset);
+
+	return val;
+}
+
+static inline void dwc2_writel(struct dwc2 *dwc2, u32 value, u32 offset)
+{
+	writel(value, dwc2->regs + offset);
+}
+
+/**
+ * dwc2_wait_bit_set - Waits for bit to be set.
+ * @dwc2: Programming view of DWC2 controller.
+ * @offset: Register's offset where bit/bits must be set.
+ * @mask: Mask of the bit/bits which must be set.
+ * @timeout: Timeout to wait.
+ *
+ * Return: 0 if bit/bits are set or -ETIMEDOUT in case of timeout.
+ */
+static inline int dwc2_wait_bit_set(struct dwc2 *dwc2, u32 offset, u32 mask,
+			    u32 timeout)
+{
+	u32 i;
+
+	for (i = 0; i < timeout; i++) {
+		if (dwc2_readl(dwc2, offset) & mask)
+			return 0;
+		udelay(1);
+	}
+
+	return -ETIMEDOUT;
+}
+
+/**
+ * dwc2_wait_bit_clear - Waits for bit to be clear.
+ * @dwc2: Programming view of DWC2 controller.
+ * @offset: Register's offset where bit/bits must be set.
+ * @mask: Mask of the bit/bits which must be set.
+ * @timeout: Timeout to wait.
+ *
+ * Return: 0 if bit/bits are set or -ETIMEDOUT in case of timeout.
+ */
+static inline int dwc2_wait_bit_clear(struct dwc2 *dwc2, u32 offset, u32 mask,
+			    u32 timeout)
+{
+	u32 i;
+
+	for (i = 0; i < timeout; i++) {
+		if (!(dwc2_readl(dwc2, offset) & mask))
+			return 0;
+		udelay(1);
+	}
+
+	return -ETIMEDOUT;
+}
+
+/*
+ * Returns the mode of operation, host or device
+ */
+static inline int dwc2_is_host_mode(struct dwc2 *dwc2)
+{
+	return (dwc2_readl(dwc2, GINTSTS) & GINTSTS_CURMODE_HOST) != 0;
+}
+
+static inline int dwc2_is_device_mode(struct dwc2 *dwc2)
+{
+	return (dwc2_readl(dwc2, GINTSTS) & GINTSTS_CURMODE_HOST) == 0;
+}
+
+static inline int phy_read(struct dwc2 *dwc2, u8 addr)
+{
+	u32 gpvndctl = 0;
+
+	gpvndctl |= (addr & 0x3f) << GPVNDCTL_REGADDR_SHIFT;
+	gpvndctl &= ~GPVNDCTL_REGWR; /* read */
+	gpvndctl |= GPVNDCTL_NEWREGREQ;
+
+	dwc2_writel(dwc2, gpvndctl, GPVNDCTL);
+
+	if (dwc2_wait_bit_set(dwc2, GPVNDCTL, GPVNDCTL_VSTSDONE, 10000))
+		pr_err("Timeout: Waiting for phy read to complete\n");
+
+	gpvndctl = dwc2_readl(dwc2, GPVNDCTL) >> GPVNDCTL_REGDATA_SHIFT;
+	return gpvndctl & GPVNDCTL_REGDATA_MASK;
+}
+
+static inline void phy_write(struct dwc2 *dwc2, u8 val, u8 addr)
+{
+	u32 gpvndctl = 0;
+
+	gpvndctl |= (addr & 0x3f) << GPVNDCTL_REGADDR_SHIFT;
+	gpvndctl |= (val  & 0xff) << GPVNDCTL_REGDATA_SHIFT;
+	gpvndctl |= GPVNDCTL_REGWR; /* write */
+	gpvndctl |= GPVNDCTL_NEWREGREQ;
+
+	dwc2_writel(dwc2, gpvndctl, GPVNDCTL);
+
+	if (dwc2_wait_bit_set(dwc2, GPVNDCTL, GPVNDCTL_VSTSDONE, 10000))
+		pr_err("Timeout: Waiting for phy write to complete\n");
+}
diff --git a/drivers/usb/dwc2/dwc2.c b/drivers/usb/dwc2/dwc2.c
new file mode 100644
index 000000000..893f573bc
--- /dev/null
+++ b/drivers/usb/dwc2/dwc2.c
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
+ * Copyright (C) 2014 Marek Vasut <marex@denx.de>
+ *
+ * Copied from u-Boot
+ */
+
+#define DEBUG
+
+#include <common.h>
+#include <of.h>
+#include <dma.h>
+#include <init.h>
+#include <errno.h>
+#include <driver.h>
+#include <linux/clk.h>
+
+#include "dwc2.h"
+
+static void dwc2_uninit_common(struct dwc2 *dwc2)
+{
+	uint32_t hprt0;
+
+	hprt0 = dwc2_readl(dwc2, HPRT0);
+
+	/* Put everything in reset. */
+	hprt0 &= ~(HPRT0_ENA | HPRT0_ENACHG | HPRT0_CONNDET | HPRT0_OVRCURRCHG);
+	hprt0 |= HPRT0_RST;
+
+	dwc2_writel(dwc2, hprt0, HPRT0);
+}
+
+static int dwc2_probe(struct device_d *dev)
+{
+	struct resource *iores;
+	struct usb_host *host;
+	struct dwc2 *dwc2;
+	int retval;
+
+	dwc2 = xzalloc(sizeof(struct dwc2));
+	dev->priv = dwc2;
+	dwc2->dev = dev;
+
+	iores = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(iores))
+		return PTR_ERR(iores);
+	dwc2->regs = IOMEM(iores->start);
+
+	retval = dwc2_core_snpsid(dwc2);
+	if (retval)
+		goto error;
+
+	/*
+	 * Reset before dwc2_get_hwparams() then it could get power-on real
+	 * reset value form registers.
+	 */
+	retval = dwc2_core_reset(dwc2);
+	if (retval)
+		goto error;
+
+	/* Detect config values from hardware */
+	dwc2_get_hwparams(dwc2);
+
+	dwc2_set_default_params(dwc2);
+
+	dma_set_mask(dev, DMA_BIT_MASK(32));
+
+	host = &dwc2->host;
+	host->hw_dev = dev;
+	host->init = dwc2_host_init;
+	host->submit_bulk_msg = dwc2_submit_bulk_msg;
+	host->submit_control_msg = dwc2_submit_control_msg;
+	host->submit_int_msg = dwc2_submit_int_msg;
+	retval = usb_register_host(host);
+
+error:
+	return retval;
+}
+
+static void dwc2_remove(struct device_d *dev)
+{
+	struct dwc2 *dwc2 = dev->priv;
+
+	dwc2_uninit_common(dwc2);
+}
+
+static const struct of_device_id dwc2_platform_dt_ids[] = {
+	{ .compatible = "brcm,bcm2835-usb", },
+	{ .compatible = "brcm,bcm2708-usb", },
+	{ .compatible = "snps,dwc2", },
+	{ }
+};
+
+static struct driver_d dwc2_driver = {
+	.name	= "dwc2",
+	.probe	= dwc2_probe,
+	.remove = dwc2_remove,
+	.of_compatible = DRV_OF_COMPAT(dwc2_platform_dt_ids),
+};
+device_platform_driver(dwc2_driver);
diff --git a/drivers/usb/dwc2/dwc2.h b/drivers/usb/dwc2/dwc2.h
new file mode 100644
index 000000000..0ac4b40fc
--- /dev/null
+++ b/drivers/usb/dwc2/dwc2.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+#include <usb/usb.h>
+#include <usb/usb_defs.h>
+#include <usb/gadget.h>
+
+#include "regs.h"
+#include "core.h"
+
+/* Core functions */
+void dwc2_set_param_otg_cap(struct dwc2 *dwc2);
+void dwc2_set_param_phy_type(struct dwc2 *dwc2);
+void dwc2_set_param_speed(struct dwc2 *dwc2);
+void dwc2_set_param_phy_utmi_width(struct dwc2 *dwc2);
+void dwc2_set_default_params(struct dwc2 *dwc2);
+int dwc2_core_snpsid(struct dwc2 *dwc2);
+void dwc2_get_hwparams(struct dwc2 *dwc2);
+
+void dwc2_init_fs_ls_pclk_sel(struct dwc2 *dwc2);
+void dwc2_flush_all_fifo(struct dwc2 *dwc2);
+
+int dwc2_phy_init(struct dwc2 *dwc2, bool select_phy);
+int dwc2_gahbcfg_init(struct dwc2 *dwc2);
+void dwc2_gusbcfg_init(struct dwc2 *dwc2);
+
+int dwc2_core_reset(struct dwc2 *dwc2);
+void dwc2_core_init(struct dwc2 *dwc2);
+
+/* Host functions */
+int dwc2_submit_control_msg(struct usb_device *dev, unsigned long pipe,
+				   void *buffer, int transfer_len,
+			    struct devrequest *setup, int timeout);
+int dwc2_submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
+			 void *buffer, int transfer_len, int timeout);
+int dwc2_submit_int_msg(struct usb_device *dev, unsigned long pipe,
+			void *buffer, int transfer_len, int interval);
+int dwc2_host_init(struct usb_host *host);
+
+int dwc2_submit_rh_msg(struct dwc2 *dwc2, struct usb_device *dev,
+		unsigned long pipe, void *buf, int len,
+		struct devrequest *setup);
+
diff --git a/drivers/usb/dwc2/host.c b/drivers/usb/dwc2/host.c
new file mode 100644
index 000000000..4137dd3cb
--- /dev/null
+++ b/drivers/usb/dwc2/host.c
@@ -0,0 +1,618 @@
+// SPDX-License-Identifier: GPL-2.0+
+#include <dma.h>
+#include "dwc2.h"
+
+#define to_dwc2 host_to_dwc2
+
+/* Use only HC channel 0. */
+#define DWC2_HC_CHANNEL			0
+
+static int dwc2_eptype[] = {
+	DXEPCTL_EPTYPE_ISO,
+	DXEPCTL_EPTYPE_INTERRUPT,
+	DXEPCTL_EPTYPE_CONTROL,
+	DXEPCTL_EPTYPE_BULK,
+};
+
+static int dwc2_do_split(struct dwc2 *dwc2, struct usb_device *dev)
+{
+	uint32_t hprt0 = dwc2_readl(dwc2, HPRT0);
+	uint32_t prtspd = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
+
+	return prtspd == HPRT0_SPD_HIGH_SPEED && dev->speed != USB_SPEED_HIGH;
+}
+
+static void dwc2_host_hub_info(struct dwc2 *dwc2, struct usb_device *dev,
+			       uint8_t *hub_addr, uint8_t *hub_port)
+{
+	*hub_addr = dev->devnum;
+	*hub_port = dev->portnr;
+
+	for (; dev->parent; dev = dev->parent) {
+		if (dev->parent->descriptor->bDeviceClass == USB_CLASS_HUB) {
+			*hub_addr = dev->parent->devnum;
+			*hub_port = dev->parent->portnr;
+			break;
+		}
+	}
+}
+
+static void dwc2_hc_init_split(struct dwc2 *dwc2, struct usb_device *dev,
+			       uint8_t hc)
+{
+	uint8_t hub_addr, hub_port;
+	uint32_t hcsplt = 0;
+
+	dwc2_host_hub_info(dwc2, dev, &hub_addr, &hub_port);
+
+	hcsplt = HCSPLT_SPLTENA;
+	hcsplt |= hub_addr << HCSPLT_HUBADDR_SHIFT;
+	hcsplt |= hub_port << HCSPLT_PRTADDR_SHIFT;
+
+	/* Program the HCSPLIT register for SPLITs */
+	dwc2_writel(dwc2, hcsplt, HCSPLT(hc));
+}
+
+static void dwc2_hc_enable_ints(struct dwc2 *dwc2, uint8_t hc)
+{
+	uint32_t intmsk;
+	uint32_t hcintmsk = HCINTMSK_CHHLTD;
+
+	dwc2_writel(dwc2, hcintmsk, HCINTMSK(hc));
+
+	/* Enable the top level host channel interrupt */
+	intmsk = dwc2_readl(dwc2, HAINTMSK);
+	intmsk |= 1 << hc;
+	dwc2_writel(dwc2, intmsk, HAINTMSK);
+
+	/* Make sure host channel interrupts are enabled */
+	intmsk = dwc2_readl(dwc2, GINTMSK);
+	intmsk |= GINTSTS_HCHINT;
+	dwc2_writel(dwc2, intmsk, GINTMSK);
+}
+
+/**
+ * Prepares a host channel for transferring packets to/from a specific
+ * endpoint. The HCCHARn register is set up with the characteristics specified
+ * in _hc. Host channel interrupts that may need to be serviced while this
+ * transfer is in progress are enabled.
+ *
+ * @param regs Programming view of DWC2 controller
+ * @param hc Information needed to initialize the host channel
+ */
+static void dwc2_hc_init(struct dwc2 *dwc2, uint8_t hc,
+		struct usb_device *dev, uint8_t dev_addr, uint8_t ep_num,
+		uint8_t ep_is_in, uint32_t ep_type, uint16_t max_packet)
+{
+	uint32_t hcchar = (dev_addr << HCCHAR_DEVADDR_SHIFT) |
+			  (ep_num << HCCHAR_EPNUM_SHIFT) |
+			  (ep_is_in ? HCCHAR_EPDIR : 0) |
+			  ep_type |
+			  (max_packet << HCCHAR_MPS_SHIFT);
+
+	if (dev->speed == USB_SPEED_LOW)
+		hcchar |= HCCHAR_LSPDDEV;
+
+	/* Clear old interrupt conditions for this dwc2 channel */
+	dwc2_writel(dwc2, ~HCINTMSK_RESERVED14_31, HCINT(hc));
+
+	/* Enable channel interrupts required for this transfer */
+	dwc2_hc_enable_ints(dwc2, hc);
+
+	/*
+	 * Program the HCCHARn register with the endpoint characteristics
+	 * for the current transfer.
+	 */
+	dwc2_writel(dwc2, hcchar, HCCHAR(hc));
+
+	/* Program the HCSPLIT register, default to no SPLIT */
+	dwc2_writel(dwc2, 0, HCSPLT(hc));
+}
+
+static int wait_for_chhltd(struct dwc2 *dwc2, u8 hc, uint32_t *sub, u8 *tgl)
+{
+	int ret;
+	uint32_t hcint, hctsiz;
+
+	ret = dwc2_wait_bit_set(dwc2, HCINT(hc), HCINTMSK_CHHLTD, 10000);
+	if (ret) {
+		dwc2_err(dwc2, "%s: Timeout! Channel not halted\n", __func__);
+	}
+
+	hcint = dwc2_readl(dwc2, HCINT(hc));
+
+	if (hcint & HCINTMSK_AHBERR)
+		dwc2_err(dwc2, "%s: AHB error during internal DMA access\n",
+			   __func__);
+
+	if (hcint & HCINTMSK_XFERCOMPL) {
+		hctsiz = dwc2_readl(dwc2, HCTSIZ(hc));
+		*sub = (hctsiz & TSIZ_XFERSIZE_MASK) >> TSIZ_XFERSIZE_SHIFT;
+		*tgl = (hctsiz & TSIZ_SC_MC_PID_MASK) >> TSIZ_SC_MC_PID_SHIFT;
+
+		dwc2_dbg(dwc2, "%s: HCINT=%08x sub=%u toggle=%d\n", __func__,
+			 hcint, *sub, *tgl);
+		return 0;
+	}
+
+	if (hcint & (HCINTMSK_NAK | HCINTMSK_FRMOVRUN))
+		return -EAGAIN;
+
+	dwc2_dbg(dwc2, "%s: Unknown channel status: (HCINT=%08x)\n", __func__,
+		 hcint);
+	return -EINVAL;
+}
+
+static int transfer_chunk(struct dwc2 *dwc2, u8 hc,
+			  u8 *pid, int in, void *buffer, int num_packets,
+			  int xfer_len, int *actual_len, int odd_frame)
+{
+	uint32_t hctsiz, hcchar, sub;
+	dma_addr_t dma_addr;
+	int ret = 0;
+
+	dma_addr = dma_map_single(dwc2->dev, buffer, xfer_len,
+				  in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+
+	dwc2_dbg(dwc2, "chunk: pid=%d xfer_len=%u pkts=%u dma_addr=%llx\n",
+			*pid, xfer_len, num_packets, dma_addr);
+
+	if (!in)
+		dma_sync_single_for_device(dma_addr, xfer_len, DMA_TO_DEVICE);
+
+	dwc2_writel(dwc2, dma_addr, HCDMA(hc));
+
+	hctsiz = (xfer_len << TSIZ_XFERSIZE_SHIFT)
+		| (1 << TSIZ_PKTCNT_SHIFT)
+		| (*pid << TSIZ_SC_MC_PID_SHIFT);
+
+	dwc2_writel(dwc2, hctsiz, HCTSIZ(hc));
+
+	/* Clear old interrupt conditions for this dwc2 channel. */
+	dwc2_writel(dwc2, 0x3fff, HCINT(hc));
+
+	/* Set dwc2 channel enable after all other setup is complete. */
+	hcchar = dwc2_readl(dwc2, HCCHAR(hc));
+	hcchar &= ~(HCCHAR_MULTICNT_MASK | HCCHAR_CHDIS);
+	hcchar |= (1 << HCCHAR_MULTICNT_SHIFT) | HCCHAR_CHENA;
+	if (odd_frame)
+		hcchar |= HCCHAR_ODDFRM;
+	else
+		hcchar &= ~HCCHAR_ODDFRM;
+	dwc2_writel(dwc2, hcchar, HCCHAR(hc));
+
+	ret = wait_for_chhltd(dwc2, hc, &sub, pid);
+	if (ret < 0)
+		goto exit;
+
+	if (in) {
+		xfer_len -= sub;
+		dma_sync_single_for_cpu(dma_addr, xfer_len, DMA_FROM_DEVICE);
+	}
+	*actual_len = xfer_len;
+
+exit:
+	dma_unmap_single(dwc2->dev, dma_addr, xfer_len,
+				  in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+
+	return ret;
+}
+
+static int dwc2_submit_packet(struct dwc2 *dwc2, struct usb_device *dev,
+			      unsigned long pipe, u8 *pid, int in, void *buf,
+			      int len)
+{
+	int devnum = usb_pipedevice(pipe);
+	int ep = usb_pipeendpoint(pipe);
+	int mps = usb_maxpacket(dev, pipe);
+	int eptype = dwc2_eptype[usb_pipetype(pipe)];
+	int do_split = dwc2_do_split(dwc2, dev);
+	int complete_split = 0;
+	int done = 0;
+	int ret = 0;
+	uint32_t xfer_len;
+	uint32_t num_packets;
+	int stop_transfer = 0;
+	uint32_t max_xfer_len;
+	int ssplit_frame_num = 0;
+
+	max_xfer_len = dwc2->params.max_packet_count * mps;
+
+	if (max_xfer_len > dwc2->params.max_transfer_size)
+		max_xfer_len = dwc2->params.max_transfer_size;
+
+	/* Make sure that max_xfer_len is a multiple of max packet size. */
+	num_packets = max_xfer_len / mps;
+	max_xfer_len = num_packets * mps;
+
+	/* Initialize channel */
+	dwc2_hc_init(dwc2, DWC2_HC_CHANNEL, dev, devnum, ep, in, eptype, mps);
+
+	/* Check if the target is a FS/LS device behind a HS hub */
+	if (do_split) {
+		dwc2_hc_init_split(dwc2, dev, DWC2_HC_CHANNEL);
+		num_packets = 1;
+		max_xfer_len = mps;
+	}
+	do {
+		int actual_len = 0;
+		uint32_t hcint, hcsplt;
+		int odd_frame = 0;
+
+		xfer_len = len - done;
+
+		if (xfer_len > max_xfer_len)
+			xfer_len = max_xfer_len;
+		else if (xfer_len > mps)
+			num_packets = (xfer_len + mps - 1) / mps;
+		else
+			num_packets = 1;
+
+		if (complete_split || do_split) {
+			hcsplt = dwc2_readl(dwc2, HCSPLT(DWC2_HC_CHANNEL));
+			if (complete_split)
+				hcsplt |= HCSPLT_COMPSPLT;
+			else if (do_split)
+				hcsplt &= ~HCSPLT_COMPSPLT;
+			dwc2_writel(dwc2, hcsplt, HCSPLT(DWC2_HC_CHANNEL));
+		}
+
+		if (eptype == DXEPCTL_EPTYPE_INTERRUPT) {
+			int uframe_num = dwc2_readl(dwc2, HFNUM);
+
+			if (!(uframe_num & 0x1))
+				odd_frame = 1;
+		}
+
+		ret = transfer_chunk(dwc2, DWC2_HC_CHANNEL, pid,
+				     in, (char *)buf + done, num_packets,
+				     xfer_len, &actual_len, odd_frame);
+
+		hcint = dwc2_readl(dwc2, HCINT(DWC2_HC_CHANNEL));
+		if (complete_split) {
+			stop_transfer = 0;
+			if (hcint & HCINTMSK_NYET) {
+				int frame_num = HFNUM_MAX_FRNUM &
+					dwc2_readl(dwc2, HFNUM);
+
+				ret = 0;
+				if (((frame_num - ssplit_frame_num) &
+				    HFNUM_MAX_FRNUM) > 4)
+					ret = -EAGAIN;
+			} else {
+				complete_split = 0;
+			}
+		} else if (do_split) {
+			if (hcint & HCINTMSK_ACK) {
+				ssplit_frame_num = HFNUM_MAX_FRNUM &
+					dwc2_readl(dwc2, HFNUM);
+				ret = 0;
+				complete_split = 1;
+			}
+		}
+
+		if (ret)
+			break;
+
+		if (actual_len < xfer_len)
+			stop_transfer = 1;
+
+		done += actual_len;
+
+	/* Transactions are done when when either all data is transferred or
+	 * there is a short transfer. In case of a SPLIT make sure the CSPLIT
+	 * is executed.
+	 */
+	} while (((done < len) && !stop_transfer) || complete_split);
+
+	dwc2_writel(dwc2, 0, HCINTMSK(DWC2_HC_CHANNEL));
+	dwc2_writel(dwc2, 0xFFFFFFFF, HCINT(DWC2_HC_CHANNEL));
+
+	dev->status = 0;
+	dev->act_len = done;
+
+	return ret;
+}
+
+int dwc2_submit_control_msg(struct usb_device *udev,
+			    unsigned long pipe, void *buffer, int len,
+			    struct devrequest *setup, int timeout)
+{
+	struct usb_host *host = udev->host;
+	struct dwc2 *dwc2 = to_dwc2(host);
+	int devnum = usb_pipedevice(pipe);
+	int ret, act_len;
+	u8 pid;
+	/* For CONTROL endpoint pid should start with DATA1 */
+	int status_direction;
+
+	if (devnum == dwc2->root_hub_devnum) {
+		udev->status = 0;
+		udev->speed = USB_SPEED_HIGH;
+		return dwc2_submit_rh_msg(dwc2, udev, pipe, buffer, len, setup);
+	}
+
+	/* SETUP stage */
+	pid = TSIZ_SC_MC_PID_SETUP;
+	do {
+		ret = dwc2_submit_packet(dwc2, udev, pipe, &pid, 0, setup, 8);
+	} while (ret == -EAGAIN);
+	if (ret)
+		return ret;
+
+	/* DATA stage */
+	act_len = 0;
+	if (buffer) {
+		pid = TSIZ_SC_MC_PID_DATA1;
+		do {
+			ret = dwc2_submit_packet(dwc2, udev, pipe, &pid,
+						 usb_pipein(pipe), buffer, len);
+			act_len += udev->act_len;
+			buffer += udev->act_len;
+			len -= udev->act_len;
+		} while (ret == -EAGAIN);
+		if (ret)
+			return ret;
+		status_direction = usb_pipeout(pipe);
+	} else {
+		/* No-data CONTROL always ends with an IN transaction */
+		status_direction = 1;
+	}
+
+	/* STATUS stage */
+	pid = TSIZ_SC_MC_PID_DATA1;
+	do {
+		ret = dwc2_submit_packet(dwc2, udev, pipe, &pid,
+					 status_direction, NULL, 0);
+	} while (ret == -EAGAIN);
+	if (ret)
+		return ret;
+
+	udev->act_len = act_len;
+
+	return 0;
+}
+
+int dwc2_submit_bulk_msg(struct usb_device *udev, unsigned long pipe,
+				void *buffer, int len, int timeout)
+{
+	struct usb_host *host = udev->host;
+	struct dwc2 *dwc2 = to_dwc2(host);
+	int devnum = usb_pipedevice(pipe);
+	int ep = usb_pipeendpoint(pipe);
+	int in = usb_pipein(pipe);
+	u8 *pid;
+
+	if ((devnum >= MAX_DEVICE) || (devnum == dwc2->root_hub_devnum)) {
+		udev->status = 0;
+		return -EINVAL;
+	}
+
+	if (in)
+		pid = &dwc2->in_data_toggle[devnum][ep];
+	else
+		pid = &dwc2->out_data_toggle[devnum][ep];
+
+	return dwc2_submit_packet(dwc2, udev, pipe, pid, in, buffer, len);
+}
+
+int dwc2_submit_int_msg(struct usb_device *udev, unsigned long pipe,
+				void *buffer, int len, int interval)
+{
+	struct usb_host *host = udev->host;
+	struct dwc2 *dwc2 = to_dwc2(host);
+	int devnum = usb_pipedevice(pipe);
+	int ep = usb_pipeendpoint(pipe);
+	int in = usb_pipein(pipe);
+	u8 *pid;
+	uint64_t start;
+	int ret;
+
+	if ((devnum >= MAX_DEVICE) || (devnum == dwc2->root_hub_devnum)) {
+		udev->status = 0;
+		return -EINVAL;
+	}
+
+	if (usb_pipein(pipe))
+		pid = &dwc2->in_data_toggle[devnum][ep];
+	else
+		pid = &dwc2->out_data_toggle[devnum][ep];
+
+	start = get_time_ns();
+
+	while (1) {
+		ret = dwc2_submit_packet(dwc2, udev, pipe, pid, in,
+					 buffer, len);
+		if (ret != -EAGAIN)
+			return ret;
+		if (is_timeout(start, USB_CNTL_TIMEOUT * MSECOND)) {
+			dwc2_err(dwc2, "Timeout on interrupt endpoint\n");
+			return -ETIMEDOUT;
+		}
+	}
+}
+
+/*
+ * This function initializes the DWC2 controller registers for
+ * host mode.
+ *
+ * This function flushes the Tx and Rx FIFOs and it flushes any entries in the
+ * request queues. Host channels are reset to ensure that they are ready for
+ * performing transfers.
+ *
+ * @param dev USB Device (NULL if driver model is not being used)
+ * @param regs Programming view of DWC2 controller
+ *
+ */
+static void dwc2_core_host_init(struct device_d *dev,
+				   struct dwc2 *dwc2)
+{
+	uint32_t nptxfifosize = 0;
+	uint32_t ptxfifosize = 0;
+	uint32_t hcchar, hcfg, hprt0, hotgctl, usbcfg;
+	int i, ret, num_channels;
+
+	dwc2_dbg(dwc2, "%s(%p)\n", __func__, dwc2);
+
+	/* Set HS/FS Timeout Calibration to 7 (max available value).
+	 * The number of PHY clocks that the application programs in
+	 * this field is added to the high/full speed interpacket timeout
+	 * duration in the core to account for any additional delays
+	 * introduced by the PHY. This can be required, because the delay
+	 * introduced by the PHY in generating the linestate condition
+	 * can vary from one PHY to another.
+	 */
+	usbcfg = dwc2_readl(dwc2, GUSBCFG);
+	usbcfg |= GUSBCFG_TOUTCAL(7);
+	dwc2_writel(dwc2, usbcfg, GUSBCFG);
+
+	/* Restart the Phy Clock */
+	dwc2_writel(dwc2, 0, PCGCTL);
+
+	/* Initialize Host Configuration Register */
+	dwc2_init_fs_ls_pclk_sel(dwc2);
+	if (dwc2->params.speed == DWC2_SPEED_PARAM_FULL ||
+	    dwc2->params.speed == DWC2_SPEED_PARAM_LOW) {
+		hcfg = dwc2_readl(dwc2, HCFG);
+		hcfg |= HCFG_FSLSSUPP;
+		dwc2_writel(dwc2, hcfg, HCFG);
+	}
+
+	if (dwc2->params.dma_desc) {
+		u32 op_mode = dwc2->hw_params.op_mode;
+
+		if (dwc2->hw_params.snpsid < DWC2_CORE_REV_2_90a ||
+		    !dwc2->hw_params.dma_desc_enable ||
+		    op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE ||
+		    op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE ||
+		    op_mode == GHWCFG2_OP_MODE_UNDEFINED) {
+			dwc2_err(dwc2, "Descriptor DMA not suppported\n");
+			dwc2_err(dwc2, "falling back to buffer DMA mode.\n");
+			dwc2->params.dma_desc = false;
+		} else {
+			hcfg = dwc2_readl(dwc2, HCFG);
+			hcfg |= HCFG_DESCDMA;
+			dwc2_writel(dwc2, hcfg, HCFG);
+		}
+	}
+
+	/* Configure data FIFO sizes */
+	if (dwc2_readl(dwc2, GHWCFG2) & GHWCFG2_DYNAMIC_FIFO) {
+		/* Rx FIFO */
+		dwc2_writel(dwc2, CONFIG_DWC2_HOST_RX_FIFO_SIZE, GRXFSIZ);
+
+		/* Non-periodic Tx FIFO */
+		nptxfifosize |= CONFIG_DWC2_HOST_NPERIO_TX_FIFO_SIZE <<
+				FIFOSIZE_DEPTH_SHIFT;
+		nptxfifosize |= CONFIG_DWC2_HOST_RX_FIFO_SIZE <<
+				FIFOSIZE_STARTADDR_SHIFT;
+		dwc2_writel(dwc2, nptxfifosize, GNPTXFSIZ);
+
+		/* Periodic Tx FIFO */
+		ptxfifosize |= CONFIG_DWC2_HOST_PERIO_TX_FIFO_SIZE <<
+				FIFOSIZE_DEPTH_SHIFT;
+		ptxfifosize |= (CONFIG_DWC2_HOST_RX_FIFO_SIZE +
+				CONFIG_DWC2_HOST_NPERIO_TX_FIFO_SIZE) <<
+				FIFOSIZE_STARTADDR_SHIFT;
+		dwc2_writel(dwc2, ptxfifosize, HPTXFSIZ);
+	}
+
+	/* Clear Host Set HNP Enable in the OTG Control Register */
+	hotgctl = dwc2_readl(dwc2, GOTGCTL);
+	hotgctl &= ~GOTGCTL_HSTSETHNPEN;
+	dwc2_writel(dwc2, hotgctl, GOTGCTL);
+
+	/* Make sure the FIFOs are flushed. */
+	dwc2_flush_all_fifo(dwc2);
+
+	/* Flush out any leftover queued requests. */
+	num_channels = dwc2->params.host_channels;
+	for (i = 0; i < num_channels; i++) {
+		hcchar = dwc2_readl(dwc2, HCCHAR(i));
+		if (!(hcchar & HCCHAR_CHENA))
+			continue;
+		hcchar |= HCCHAR_CHDIS;
+		hcchar &= ~(HCCHAR_CHENA | HCCHAR_EPDIR);
+		dwc2_writel(dwc2, hcchar, HCCHAR(i));
+	}
+
+	/* Halt all channels to put them into a known state. */
+	for (i = 0; i < num_channels; i++) {
+		hcchar = dwc2_readl(dwc2, HCCHAR(i));
+		if (!(hcchar & HCCHAR_CHENA))
+			continue;
+		hcchar |= HCCHAR_CHENA | HCCHAR_CHDIS;
+		hcchar &= ~HCCHAR_EPDIR;
+
+		dwc2_writel(dwc2, hcchar, HCCHAR(i));
+		ret = dwc2_wait_bit_clear(dwc2, HCCHAR(i), HCCHAR_CHENA, 10000);
+		if (ret)
+			dwc2_warn(dwc2, "%s: Timeout! Reseting channel %d\n",
+				  __func__, i);
+	}
+
+	/* Turn on the vbus power */
+	if (dwc2_is_host_mode(dwc2)) {
+		hprt0 = dwc2_readl(dwc2, HPRT0);
+		hprt0 &= ~(HPRT0_ENA | HPRT0_CONNDET);
+		hprt0 &= ~(HPRT0_ENACHG | HPRT0_OVRCURRCHG);
+		if (!(hprt0 & HPRT0_PWR)) {
+			hprt0 |= HPRT0_PWR;
+			dwc2_writel(dwc2, hprt0, HPRT0);
+		}
+	}
+
+	/* Disable all interrupts */
+	dwc2_writel(dwc2, 0, GINTMSK);
+	dwc2_writel(dwc2, 0, HAINTMSK);
+}
+
+int dwc2_host_init(struct usb_host *host)
+{
+	struct dwc2 *dwc2 = to_dwc2(host);
+	struct device_d *dev = dwc2->dev;
+	uint32_t hprt0, gusbcfg;
+	int i, j;
+
+	/* Force Host mode in case the dwc2 controller is otg,
+	 * otherwise the mode selection is dictated by the id
+	 * pin, thus will require a otg A cable to be plugged-in.
+	 */
+	gusbcfg = dwc2_readl(dwc2, GUSBCFG) | GUSBCFG_FORCEHOSTMODE;
+	dwc2_writel(dwc2, gusbcfg, GUSBCFG);
+	mdelay(25);
+
+	dwc2_core_init(dwc2);
+	dwc2_core_host_init(dev, dwc2);
+
+	hprt0 = dwc2_readl(dwc2, HPRT0);
+	hprt0 &= ~(HPRT0_ENA | HPRT0_CONNDET);
+	/* clear HPRT0_ENACHG and HPRT0_OVRCURRCHG by writing 1 */
+	hprt0 |= HPRT0_ENACHG | HPRT0_OVRCURRCHG;
+	hprt0 |= HPRT0_RST;
+	dwc2_writel(dwc2, hprt0, HPRT0);
+
+	mdelay(50);
+
+	hprt0 = dwc2_readl(dwc2, HPRT0);
+	hprt0 &= ~(HPRT0_ENA | HPRT0_CONNDET | HPRT0_RST);
+	dwc2_writel(dwc2, hprt0, HPRT0);
+
+	for (i = 0; i < MAX_DEVICE; i++) {
+		for (j = 0; j < MAX_ENDPOINT; j++) {
+			dwc2->in_data_toggle[i][j] = TSIZ_SC_MC_PID_DATA0;
+			dwc2->out_data_toggle[i][j] = TSIZ_SC_MC_PID_DATA0;
+		}
+	}
+
+	/*
+	 * Add a 1 second delay here. This gives the host controller
+	 * a bit time before the comminucation with the USB devices
+	 * is started (the bus is scanned) and  fixes the USB detection
+	 * problems with some problematic USB keys.
+	 */
+	if (dwc2_is_host_mode(dwc2))
+		mdelay(1000);
+
+	return 0;
+}
diff --git a/drivers/usb/dwc2/regs.h b/drivers/usb/dwc2/regs.h
new file mode 100644
index 000000000..b2b312e1b
--- /dev/null
+++ b/drivers/usb/dwc2/regs.h
@@ -0,0 +1,847 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2014 Marek Vasut <marex@denx.de>
+ */
+
+#ifndef __DWC2_H__
+#define __DWC2_H__
+
+#define HSOTG_REG(x)	(x)
+
+#define GOTGCTL				HSOTG_REG(0x000)
+#define GOTGCTL_CHIRPEN			BIT(27)
+#define GOTGCTL_MULT_VALID_BC_MASK	(0x1f << 22)
+#define GOTGCTL_MULT_VALID_BC_SHIFT	22
+#define GOTGCTL_CURMODE			BIT(21) /* was missing wtf ? */
+#define GOTGCTL_OTGVER			BIT(20)
+#define GOTGCTL_BSESVLD			BIT(19)
+#define GOTGCTL_ASESVLD			BIT(18)
+#define GOTGCTL_DBNC_SHORT		BIT(17)
+#define GOTGCTL_CONID_B			BIT(16)
+#define GOTGCTL_DBNCE_FLTR_BYPASS	BIT(15)
+#define GOTGCTL_EMBHOSTEN		BIT(12)
+#define GOTGCTL_DEVHNPEN		BIT(11)
+#define GOTGCTL_HSTSETHNPEN		BIT(10)
+#define GOTGCTL_HNPREQ			BIT(9)
+#define GOTGCTL_HSTNEGSCS		BIT(8)
+#define GOTGCTL_SESREQ			BIT(1)
+#define GOTGCTL_SESREQSCS		BIT(0)
+
+#define GOTGINT				HSOTG_REG(0x004)
+#define GOTGINT_DBNCE_DONE		BIT(19)
+#define GOTGINT_A_DEV_TOUT_CHG		BIT(18)
+#define GOTGINT_HST_NEG_DET		BIT(17)
+#define GOTGINT_HST_NEG_SUC_STS_CHNG	BIT(9)
+#define GOTGINT_SES_REQ_SUC_STS_CHNG	BIT(8)
+#define GOTGINT_SES_END_DET		BIT(2)
+
+#define GAHBCFG				HSOTG_REG(0x008)
+#define GAHBCFG_AHB_SINGLE		BIT(23)
+#define GAHBCFG_NOTI_ALL_DMA_WRIT	BIT(22)
+#define GAHBCFG_REM_MEM_SUPP		BIT(21)
+#define GAHBCFG_P_TXF_EMP_LVL		BIT(8)
+#define GAHBCFG_NP_TXF_EMP_LVL		BIT(7)
+#define GAHBCFG_DMA_EN			BIT(5)
+#define GAHBCFG_HBSTLEN_MASK		(0xf << 1)
+#define GAHBCFG_HBSTLEN_SHIFT		1
+#define GAHBCFG_HBSTLEN_SINGLE		0
+#define GAHBCFG_HBSTLEN_INCR		1
+#define GAHBCFG_HBSTLEN_INCR4		3
+#define GAHBCFG_HBSTLEN_INCR8		5
+#define GAHBCFG_HBSTLEN_INCR16		7
+#define GAHBCFG_GLBL_INTR_EN		BIT(0)
+#define GAHBCFG_CTRL_MASK		(GAHBCFG_P_TXF_EMP_LVL | \
+					 GAHBCFG_NP_TXF_EMP_LVL | \
+					 GAHBCFG_DMA_EN | \
+					 GAHBCFG_GLBL_INTR_EN)
+
+#define GUSBCFG				HSOTG_REG(0x00C)
+#define GUSBCFG_FORCEDEVMODE		BIT(30)
+#define GUSBCFG_FORCEHOSTMODE		BIT(29)
+#define GUSBCFG_TXENDDELAY		BIT(28)
+#define GUSBCFG_ICTRAFFICPULLREMOVE	BIT(27)
+#define GUSBCFG_ICUSBCAP		BIT(26)
+#define GUSBCFG_ULPI_INT_PROT_DIS	BIT(25)
+#define GUSBCFG_INDICATORPASSTHROUGH	BIT(24)
+#define GUSBCFG_INDICATORCOMPLEMENT	BIT(23)
+#define GUSBCFG_TERMSELDLPULSE		BIT(22)
+#define GUSBCFG_ULPI_EXT_VBUS_IND	BIT(21)
+#define GUSBCFG_ULPI_EXT_VBUS_DRV	BIT(20)
+#define GUSBCFG_ULPI_CLK_SUSP_M		BIT(19)
+#define GUSBCFG_ULPI_AUTO_RES		BIT(18)
+#define GUSBCFG_ULPI_FS_LS		BIT(17)
+#define GUSBCFG_OTG_UTMI_FS_SEL		BIT(16)
+#define GUSBCFG_PHY_LP_CLK_SEL		BIT(15)
+#define GUSBCFG_USBTRDTIM_MASK		(0xf << 10)
+#define GUSBCFG_USBTRDTIM_SHIFT		10
+#define GUSBCFG_HNPCAP			BIT(9)
+#define GUSBCFG_SRPCAP			BIT(8)
+#define GUSBCFG_DDRSEL			BIT(7)
+#define GUSBCFG_PHYSEL			BIT(6)
+#define GUSBCFG_FSINTF			BIT(5)
+#define GUSBCFG_ULPI_UTMI_SEL		BIT(4)
+#define GUSBCFG_PHYIF16			BIT(3)
+#define GUSBCFG_PHYIF8			(0 << 3)
+#define GUSBCFG_TOUTCAL_MASK		(0x7 << 0)
+#define GUSBCFG_TOUTCAL_SHIFT		0
+#define GUSBCFG_TOUTCAL_LIMIT		0x7
+#define GUSBCFG_TOUTCAL(_x)		((_x) << 0)
+
+#define GRSTCTL				HSOTG_REG(0x010)
+#define GRSTCTL_AHBIDLE			BIT(31)
+#define GRSTCTL_DMAREQ			BIT(30)
+#define GRSTCTL_TXFNUM_MASK		(0x1f << 6)
+#define GRSTCTL_TXFNUM_SHIFT		6
+#define GRSTCTL_TXFNUM_LIMIT		0x1f
+#define GRSTCTL_TXFNUM(_x)		((_x) << 6)
+#define GRSTCTL_TXFFLSH			BIT(5)
+#define GRSTCTL_RXFFLSH			BIT(4)
+#define GRSTCTL_IN_TKNQ_FLSH		BIT(3)
+#define GRSTCTL_FRMCNTRRST		BIT(2)
+#define GRSTCTL_HSFTRST			BIT(1)
+#define GRSTCTL_CSFTRST			BIT(0)
+
+#define GINTSTS				HSOTG_REG(0x014)
+#define GINTMSK				HSOTG_REG(0x018)
+#define GINTSTS_WKUPINT			BIT(31)
+#define GINTSTS_SESSREQINT		BIT(30)
+#define GINTSTS_DISCONNINT		BIT(29)
+#define GINTSTS_CONIDSTSCHNG		BIT(28)
+#define GINTSTS_LPMTRANRCVD		BIT(27)
+#define GINTSTS_PTXFEMP			BIT(26)
+#define GINTSTS_HCHINT			BIT(25)
+#define GINTSTS_PRTINT			BIT(24)
+#define GINTSTS_RESETDET		BIT(23)
+#define GINTSTS_FET_SUSP		BIT(22)
+#define GINTSTS_INCOMPL_IP		BIT(21)
+#define GINTSTS_INCOMPL_SOOUT		BIT(21)
+#define GINTSTS_INCOMPL_SOIN		BIT(20)
+#define GINTSTS_OEPINT			BIT(19)
+#define GINTSTS_IEPINT			BIT(18)
+#define GINTSTS_EPMIS			BIT(17)
+#define GINTSTS_RESTOREDONE		BIT(16)
+#define GINTSTS_EOPF			BIT(15)
+#define GINTSTS_ISOUTDROP		BIT(14)
+#define GINTSTS_ENUMDONE		BIT(13)
+#define GINTSTS_USBRST			BIT(12)
+#define GINTSTS_USBSUSP			BIT(11)
+#define GINTSTS_ERLYSUSP		BIT(10)
+#define GINTSTS_I2CINT			BIT(9)
+#define GINTSTS_ULPI_CK_INT		BIT(8)
+#define GINTSTS_GOUTNAKEFF		BIT(7)
+#define GINTSTS_GINNAKEFF		BIT(6)
+#define GINTSTS_NPTXFEMP		BIT(5)
+#define GINTSTS_RXFLVL			BIT(4)
+#define GINTSTS_SOF			BIT(3)
+#define GINTSTS_OTGINT			BIT(2)
+#define GINTSTS_MODEMIS			BIT(1)
+#define GINTSTS_CURMODE_HOST		BIT(0)
+
+#define GRXSTSR				HSOTG_REG(0x01C)
+#define GRXSTSP				HSOTG_REG(0x020)
+#define GRXSTS_FN_MASK			(0x7f << 25)
+#define GRXSTS_FN_SHIFT			25
+#define GRXSTS_PKTSTS_MASK		(0xf << 17)
+#define GRXSTS_PKTSTS_SHIFT		17
+#define GRXSTS_PKTSTS_GLOBALOUTNAK	1
+#define GRXSTS_PKTSTS_OUTRX		2
+#define GRXSTS_PKTSTS_HCHIN		2
+#define GRXSTS_PKTSTS_OUTDONE		3
+#define GRXSTS_PKTSTS_HCHIN_XFER_COMP	3
+#define GRXSTS_PKTSTS_SETUPDONE		4
+#define GRXSTS_PKTSTS_DATATOGGLEERR	5
+#define GRXSTS_PKTSTS_SETUPRX		6
+#define GRXSTS_PKTSTS_HCHHALTED		7
+#define GRXSTS_HCHNUM_MASK		(0xf << 0)
+#define GRXSTS_HCHNUM_SHIFT		0
+#define GRXSTS_DPID_MASK		(0x3 << 15)
+#define GRXSTS_DPID_SHIFT		15
+#define GRXSTS_BYTECNT_MASK		(0x7ff << 4)
+#define GRXSTS_BYTECNT_SHIFT		4
+#define GRXSTS_EPNUM_MASK		(0xf << 0)
+#define GRXSTS_EPNUM_SHIFT		0
+
+#define GRXFSIZ				HSOTG_REG(0x024)
+#define GRXFSIZ_DEPTH_MASK		(0xffff << 0)
+#define GRXFSIZ_DEPTH_SHIFT		0
+
+#define GNPTXFSIZ			HSOTG_REG(0x028)
+/* Use FIFOSIZE_* constants to access this register */
+
+#define GNPTXSTS			HSOTG_REG(0x02C)
+#define GNPTXSTS_NP_TXQ_TOP_MASK		(0x7f << 24)
+#define GNPTXSTS_NP_TXQ_TOP_SHIFT		24
+#define GNPTXSTS_NP_TXQ_SPC_AVAIL_MASK		(0xff << 16)
+#define GNPTXSTS_NP_TXQ_SPC_AVAIL_SHIFT		16
+#define GNPTXSTS_NP_TXQ_SPC_AVAIL_GET(_v)	(((_v) >> 16) & 0xff)
+#define GNPTXSTS_NP_TXF_SPC_AVAIL_MASK		(0xffff << 0)
+#define GNPTXSTS_NP_TXF_SPC_AVAIL_SHIFT		0
+#define GNPTXSTS_NP_TXF_SPC_AVAIL_GET(_v)	(((_v) >> 0) & 0xffff)
+
+#define GI2CCTL				HSOTG_REG(0x0030)
+#define GI2CCTL_BSYDNE			BIT(31)
+#define GI2CCTL_RW			BIT(30)
+#define GI2CCTL_I2CDATSE0		BIT(28)
+#define GI2CCTL_I2CDEVADDR_MASK		(0x3 << 26)
+#define GI2CCTL_I2CDEVADDR_SHIFT	26
+#define GI2CCTL_I2CSUSPCTL		BIT(25)
+#define GI2CCTL_ACK			BIT(24)
+#define GI2CCTL_I2CEN			BIT(23)
+#define GI2CCTL_ADDR_MASK		(0x7f << 16)
+#define GI2CCTL_ADDR_SHIFT		16
+#define GI2CCTL_REGADDR_MASK		(0xff << 8)
+#define GI2CCTL_REGADDR_SHIFT		8
+#define GI2CCTL_RWDATA_MASK		(0xff << 0)
+#define GI2CCTL_RWDATA_SHIFT		0
+
+#define GPVNDCTL			HSOTG_REG(0x0034)
+#define GPVNDCTL_REGWR			BIT(22)
+#define GPVNDCTL_NEWREGREQ		BIT(25)
+#define GPVNDCTL_VSTSDONE		BIT(27)
+#define GPVNDCTL_REGADDR_SHIFT		16
+#define GPVNDCTL_REGDATA_SHIFT		0
+#define GPVNDCTL_REGDATA_MASK		0xff
+
+#define GGPIO				HSOTG_REG(0x0038)
+#define GGPIO_STM32_OTG_GCCFG_PWRDWN	BIT(16)
+
+#define GUID				HSOTG_REG(0x003c)
+#define GSNPSID				HSOTG_REG(0x0040)
+#define GHWCFG1				HSOTG_REG(0x0044)
+#define GSNPSID_ID_MASK			GENMASK(31, 16)
+
+#define GHWCFG2				HSOTG_REG(0x0048)
+#define GHWCFG2_OTG_ENABLE_IC_USB		BIT(31)
+#define GHWCFG2_DEV_TOKEN_Q_DEPTH_MASK		(0x1f << 26)
+#define GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT		26
+#define GHWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK	(0x3 << 24)
+#define GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT	24
+#define GHWCFG2_NONPERIO_TX_Q_DEPTH_MASK	(0x3 << 22)
+#define GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT	22
+#define GHWCFG2_MULTI_PROC_INT			BIT(20)
+#define GHWCFG2_DYNAMIC_FIFO			BIT(19)
+#define GHWCFG2_PERIO_EP_SUPPORTED		BIT(18)
+#define GHWCFG2_NUM_HOST_CHAN_MASK		(0xf << 14)
+#define GHWCFG2_NUM_HOST_CHAN_SHIFT		14
+#define GHWCFG2_NUM_DEV_EP_MASK			(0xf << 10)
+#define GHWCFG2_NUM_DEV_EP_SHIFT		10
+#define GHWCFG2_FS_PHY_TYPE_MASK		(0x3 << 8)
+#define GHWCFG2_FS_PHY_TYPE_SHIFT		8
+#define GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED	0
+#define GHWCFG2_FS_PHY_TYPE_DEDICATED		1
+#define GHWCFG2_FS_PHY_TYPE_SHARED_UTMI		2
+#define GHWCFG2_FS_PHY_TYPE_SHARED_ULPI		3
+#define GHWCFG2_HS_PHY_TYPE_MASK		(0x3 << 6)
+#define GHWCFG2_HS_PHY_TYPE_SHIFT		6
+#define GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED	0
+#define GHWCFG2_HS_PHY_TYPE_UTMI		1
+#define GHWCFG2_HS_PHY_TYPE_ULPI		2
+#define GHWCFG2_HS_PHY_TYPE_UTMI_ULPI		3
+#define GHWCFG2_POINT2POINT			BIT(5)
+#define GHWCFG2_ARCHITECTURE_MASK		(0x3 << 3)
+#define GHWCFG2_ARCHITECTURE_SHIFT		3
+#define GHWCFG2_SLAVE_ONLY_ARCH			0
+#define GHWCFG2_EXT_DMA_ARCH			1
+#define GHWCFG2_INT_DMA_ARCH			2
+#define GHWCFG2_OP_MODE_MASK			(0x7 << 0)
+#define GHWCFG2_OP_MODE_SHIFT			0
+#define GHWCFG2_OP_MODE_HNP_SRP_CAPABLE		0
+#define GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE	1
+#define GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE	2
+#define GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE	3
+#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE	4
+#define GHWCFG2_OP_MODE_SRP_CAPABLE_HOST	5
+#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST	6
+#define GHWCFG2_OP_MODE_UNDEFINED		7
+
+#define GHWCFG3				HSOTG_REG(0x004c)
+#define GHWCFG3_DFIFO_DEPTH_MASK		(0xffff << 16)
+#define GHWCFG3_DFIFO_DEPTH_SHIFT		16
+#define GHWCFG3_OTG_LPM_EN			BIT(15)
+#define GHWCFG3_BC_SUPPORT			BIT(14)
+#define GHWCFG3_OTG_ENABLE_HSIC			BIT(13)
+#define GHWCFG3_ADP_SUPP			BIT(12)
+#define GHWCFG3_SYNCH_RESET_TYPE		BIT(11)
+#define GHWCFG3_OPTIONAL_FEATURES		BIT(10)
+#define GHWCFG3_VENDOR_CTRL_IF			BIT(9)
+#define GHWCFG3_I2C				BIT(8)
+#define GHWCFG3_OTG_FUNC			BIT(7)
+#define GHWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK	(0x7 << 4)
+#define GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT	4
+#define GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK	(0xf << 0)
+#define GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT	0
+
+#define GHWCFG4				HSOTG_REG(0x0050)
+#define GHWCFG4_DESC_DMA_DYN			BIT(31)
+#define GHWCFG4_DESC_DMA			BIT(30)
+#define GHWCFG4_NUM_IN_EPS_MASK			(0xf << 26)
+#define GHWCFG4_NUM_IN_EPS_SHIFT		26
+#define GHWCFG4_DED_FIFO_EN			BIT(25)
+#define GHWCFG4_DED_FIFO_SHIFT		25
+#define GHWCFG4_SESSION_END_FILT_EN		BIT(24)
+#define GHWCFG4_B_VALID_FILT_EN			BIT(23)
+#define GHWCFG4_A_VALID_FILT_EN			BIT(22)
+#define GHWCFG4_VBUS_VALID_FILT_EN		BIT(21)
+#define GHWCFG4_IDDIG_FILT_EN			BIT(20)
+#define GHWCFG4_NUM_DEV_MODE_CTRL_EP_MASK	(0xf << 16)
+#define GHWCFG4_NUM_DEV_MODE_CTRL_EP_SHIFT	16
+#define GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK	(0x3 << 14)
+#define GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT	14
+#define GHWCFG4_ACG_SUPPORTED			BIT(12)
+#define GHWCFG4_IPG_ISOC_SUPPORTED		BIT(11)
+#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8		0
+#define GHWCFG4_UTMI_PHY_DATA_WIDTH_16		1
+#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16	2
+#define GHWCFG4_XHIBER				BIT(7)
+#define GHWCFG4_HIBER				BIT(6)
+#define GHWCFG4_MIN_AHB_FREQ			BIT(5)
+#define GHWCFG4_POWER_OPTIMIZ			BIT(4)
+#define GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK	(0xf << 0)
+#define GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT	0
+
+#define GLPMCFG				HSOTG_REG(0x0054)
+#define GLPMCFG_INVSELHSIC		BIT(31)
+#define GLPMCFG_HSICCON			BIT(30)
+#define GLPMCFG_RSTRSLPSTS		BIT(29)
+#define GLPMCFG_ENBESL			BIT(28)
+#define GLPMCFG_LPM_RETRYCNT_STS_MASK	(0x7 << 25)
+#define GLPMCFG_LPM_RETRYCNT_STS_SHIFT	25
+#define GLPMCFG_SNDLPM			BIT(24)
+#define GLPMCFG_RETRY_CNT_MASK		(0x7 << 21)
+#define GLPMCFG_RETRY_CNT_SHIFT		21
+#define GLPMCFG_LPM_CHNL_INDX_MASK	(0xf << 17)
+#define GLPMCFG_LPM_CHNL_INDX_SHIFT	17
+#define GLPMCFG_L1RESUMEOK		BIT(16)
+#define GLPMCFG_SLPSTS			BIT(15)
+#define GLPMCFG_COREL1RES_MASK		(0x3 << 13)
+#define GLPMCFG_COREL1RES_SHIFT		13
+#define GLPMCFG_HIRD_THRES_MASK		(0x1f << 8)
+#define GLPMCFG_HIRD_THRES_SHIFT	8
+#define GLPMCFG_HIRD_THRES_EN		(0x10 << 8)
+#define GLPMCFG_ENBLSLPM		BIT(7)
+#define GLPMCFG_BREMOTEWAKE		BIT(6)
+#define GLPMCFG_HIRD_MASK		(0xf << 2)
+#define GLPMCFG_HIRD_SHIFT		2
+#define GLPMCFG_APPL1RES		BIT(1)
+#define GLPMCFG_LPMCAP			BIT(0)
+
+#define GPWRDN				HSOTG_REG(0x0058)
+#define GPWRDN_MULT_VAL_ID_BC_MASK	(0x1f << 24)
+#define GPWRDN_MULT_VAL_ID_BC_SHIFT	24
+#define GPWRDN_ADP_INT			BIT(23)
+#define GPWRDN_BSESSVLD			BIT(22)
+#define GPWRDN_IDSTS			BIT(21)
+#define GPWRDN_LINESTATE_MASK		(0x3 << 19)
+#define GPWRDN_LINESTATE_SHIFT		19
+#define GPWRDN_STS_CHGINT_MSK		BIT(18)
+#define GPWRDN_STS_CHGINT		BIT(17)
+#define GPWRDN_SRP_DET_MSK		BIT(16)
+#define GPWRDN_SRP_DET			BIT(15)
+#define GPWRDN_CONNECT_DET_MSK		BIT(14)
+#define GPWRDN_CONNECT_DET		BIT(13)
+#define GPWRDN_DISCONN_DET_MSK		BIT(12)
+#define GPWRDN_DISCONN_DET		BIT(11)
+#define GPWRDN_RST_DET_MSK		BIT(10)
+#define GPWRDN_RST_DET			BIT(9)
+#define GPWRDN_LNSTSCHG_MSK		BIT(8)
+#define GPWRDN_LNSTSCHG			BIT(7)
+#define GPWRDN_DIS_VBUS			BIT(6)
+#define GPWRDN_PWRDNSWTCH		BIT(5)
+#define GPWRDN_PWRDNRSTN		BIT(4)
+#define GPWRDN_PWRDNCLMP		BIT(3)
+#define GPWRDN_RESTORE			BIT(2)
+#define GPWRDN_PMUACTV			BIT(1)
+#define GPWRDN_PMUINTSEL		BIT(0)
+
+#define GDFIFOCFG			HSOTG_REG(0x005c)
+#define GDFIFOCFG_EPINFOBASE_MASK	(0xffff << 16)
+#define GDFIFOCFG_EPINFOBASE_SHIFT	16
+#define GDFIFOCFG_GDFIFOCFG_MASK	(0xffff << 0)
+#define GDFIFOCFG_GDFIFOCFG_SHIFT	0
+
+#define ADPCTL				HSOTG_REG(0x0060)
+#define ADPCTL_AR_MASK			(0x3 << 27)
+#define ADPCTL_AR_SHIFT			27
+#define ADPCTL_ADP_TMOUT_INT_MSK	BIT(26)
+#define ADPCTL_ADP_SNS_INT_MSK		BIT(25)
+#define ADPCTL_ADP_PRB_INT_MSK		BIT(24)
+#define ADPCTL_ADP_TMOUT_INT		BIT(23)
+#define ADPCTL_ADP_SNS_INT		BIT(22)
+#define ADPCTL_ADP_PRB_INT		BIT(21)
+#define ADPCTL_ADPENA			BIT(20)
+#define ADPCTL_ADPRES			BIT(19)
+#define ADPCTL_ENASNS			BIT(18)
+#define ADPCTL_ENAPRB			BIT(17)
+#define ADPCTL_RTIM_MASK		(0x7ff << 6)
+#define ADPCTL_RTIM_SHIFT		6
+#define ADPCTL_PRB_PER_MASK		(0x3 << 4)
+#define ADPCTL_PRB_PER_SHIFT		4
+#define ADPCTL_PRB_DELTA_MASK		(0x3 << 2)
+#define ADPCTL_PRB_DELTA_SHIFT		2
+#define ADPCTL_PRB_DSCHRG_MASK		(0x3 << 0)
+#define ADPCTL_PRB_DSCHRG_SHIFT		0
+
+#define HPTXFSIZ			HSOTG_REG(0x100)
+/* Use FIFOSIZE_* constants to access this register */
+
+#define DPTXFSIZN(_a)			HSOTG_REG(0x104 + (((_a) - 1) * 4))
+/* Use FIFOSIZE_* constants to access this register */
+
+/* These apply to the GNPTXFSIZ, HPTXFSIZ and DPTXFSIZN registers */
+#define FIFOSIZE_DEPTH_MASK		(0xffff << 16)
+#define FIFOSIZE_DEPTH_SHIFT		16
+#define FIFOSIZE_STARTADDR_MASK		(0xffff << 0)
+#define FIFOSIZE_STARTADDR_SHIFT	0
+#define FIFOSIZE_DEPTH_GET(_x)		(((_x) >> 16) & 0xffff)
+
+/* Device mode registers */
+
+#define DCFG				HSOTG_REG(0x800)
+#define DCFG_DESCDMA_EN			BIT(23)
+#define DCFG_EPMISCNT_MASK		(0x1f << 18)
+#define DCFG_EPMISCNT_SHIFT		18
+#define DCFG_EPMISCNT_LIMIT		0x1f
+#define DCFG_EPMISCNT(_x)		((_x) << 18)
+#define DCFG_IPG_ISOC_SUPPORDED		BIT(17)
+#define DCFG_PERFRINT_MASK		(0x3 << 11)
+#define DCFG_PERFRINT_SHIFT		11
+#define DCFG_PERFRINT_LIMIT		0x3
+#define DCFG_PERFRINT(_x)		((_x) << 11)
+#define DCFG_DEVADDR_MASK		(0x7f << 4)
+#define DCFG_DEVADDR_SHIFT		4
+#define DCFG_DEVADDR_LIMIT		0x7f
+#define DCFG_DEVADDR(_x)		((_x) << 4)
+#define DCFG_NZ_STS_OUT_HSHK		BIT(2)
+#define DCFG_DEVSPD_MASK		(0x3 << 0)
+#define DCFG_DEVSPD_SHIFT		0
+#define DCFG_DEVSPD_HS			0
+#define DCFG_DEVSPD_FS			1
+#define DCFG_DEVSPD_LS			2
+#define DCFG_DEVSPD_FS48		3
+
+#define DCTL				HSOTG_REG(0x804)
+#define DCTL_PWRONPRGDONE		BIT(11)
+#define DCTL_CGOUTNAK			BIT(10)
+#define DCTL_SGOUTNAK			BIT(9)
+#define DCTL_CGNPINNAK			BIT(8)
+#define DCTL_SGNPINNAK			BIT(7)
+#define DCTL_TSTCTL_MASK		(0x7 << 4)
+#define DCTL_TSTCTL_SHIFT		4
+#define DCTL_GOUTNAKSTS			BIT(3)
+#define DCTL_GNPINNAKSTS		BIT(2)
+#define DCTL_SFTDISCON			BIT(1)
+#define DCTL_RMTWKUPSIG			BIT(0)
+
+#define DSTS				HSOTG_REG(0x808)
+#define DSTS_SOFFN_MASK			(0x3fff << 8)
+#define DSTS_SOFFN_SHIFT		8
+#define DSTS_SOFFN_LIMIT		0x3fff
+#define DSTS_SOFFN(_x)			((_x) << 8)
+#define DSTS_ERRATICERR			BIT(3)
+#define DSTS_ENUMSPD_MASK		(0x3 << 1)
+#define DSTS_ENUMSPD_SHIFT		1
+#define DSTS_ENUMSPD_HS			0
+#define DSTS_ENUMSPD_FS			1
+#define DSTS_ENUMSPD_LS			2
+#define DSTS_ENUMSPD_FS48		3
+#define DSTS_SUSPSTS			BIT(0)
+
+#define DIEPMSK				HSOTG_REG(0x810)
+#define DIEPMSK_NAKMSK			BIT(13)
+#define DIEPMSK_BNAININTRMSK		BIT(9)
+#define DIEPMSK_TXFIFOUNDRNMSK		BIT(8)
+#define DIEPMSK_TXFIFOEMPTY		BIT(7)
+#define DIEPMSK_INEPNAKEFFMSK		BIT(6)
+#define DIEPMSK_INTKNEPMISMSK		BIT(5)
+#define DIEPMSK_INTKNTXFEMPMSK		BIT(4)
+#define DIEPMSK_TIMEOUTMSK		BIT(3)
+#define DIEPMSK_AHBERRMSK		BIT(2)
+#define DIEPMSK_EPDISBLDMSK		BIT(1)
+#define DIEPMSK_XFERCOMPLMSK		BIT(0)
+
+#define DOEPMSK				HSOTG_REG(0x814)
+#define DOEPMSK_BNAMSK			BIT(9)
+#define DOEPMSK_BACK2BACKSETUP		BIT(6)
+#define DOEPMSK_STSPHSERCVDMSK		BIT(5)
+#define DOEPMSK_OUTTKNEPDISMSK		BIT(4)
+#define DOEPMSK_SETUPMSK		BIT(3)
+#define DOEPMSK_AHBERRMSK		BIT(2)
+#define DOEPMSK_EPDISBLDMSK		BIT(1)
+#define DOEPMSK_XFERCOMPLMSK		BIT(0)
+
+#define DAINT				HSOTG_REG(0x818)
+#define DAINTMSK			HSOTG_REG(0x81C)
+#define DAINT_OUTEP_SHIFT		16
+#define DAINT_OUTEP(_x)			(1 << ((_x) + 16))
+#define DAINT_INEP(_x)			(1 << (_x))
+
+#define DTKNQR1				HSOTG_REG(0x820)
+#define DTKNQR2				HSOTG_REG(0x824)
+#define DTKNQR3				HSOTG_REG(0x830)
+#define DTKNQR4				HSOTG_REG(0x834)
+#define DIEPEMPMSK			HSOTG_REG(0x834)
+
+#define DVBUSDIS			HSOTG_REG(0x828)
+#define DVBUSPULSE			HSOTG_REG(0x82C)
+
+#define DIEPCTL0			HSOTG_REG(0x900)
+#define DIEPCTL(_a)			HSOTG_REG(0x900 + ((_a) * 0x20))
+
+#define DOEPCTL0			HSOTG_REG(0xB00)
+#define DOEPCTL(_a)			HSOTG_REG(0xB00 + ((_a) * 0x20))
+
+/* EP0 specialness:
+ * bits[29..28] - reserved (no SetD0PID, SetD1PID)
+ * bits[25..22] - should always be zero, this isn't a periodic endpoint
+ * bits[10..0]  - MPS setting different for EP0
+ */
+#define D0EPCTL_MPS_MASK		(0x3 << 0)
+#define D0EPCTL_MPS_SHIFT		0
+#define D0EPCTL_MPS_64			0
+#define D0EPCTL_MPS_32			1
+#define D0EPCTL_MPS_16			2
+#define D0EPCTL_MPS_8			3
+
+#define DXEPCTL_EPENA			BIT(31)
+#define DXEPCTL_EPDIS			BIT(30)
+#define DXEPCTL_SETD1PID		BIT(29)
+#define DXEPCTL_SETODDFR		BIT(29)
+#define DXEPCTL_SETD0PID		BIT(28)
+#define DXEPCTL_SETEVENFR		BIT(28)
+#define DXEPCTL_SNAK			BIT(27)
+#define DXEPCTL_CNAK			BIT(26)
+#define DXEPCTL_TXFNUM_MASK		(0xf << 22)
+#define DXEPCTL_TXFNUM_SHIFT		22
+#define DXEPCTL_TXFNUM_LIMIT		0xf
+#define DXEPCTL_TXFNUM(_x)		((_x) << 22)
+#define DXEPCTL_STALL			BIT(21)
+#define DXEPCTL_SNP			BIT(20)
+#define DXEPCTL_EPTYPE_MASK		(0x3 << 18)
+#define DXEPCTL_EPTYPE_CONTROL		(0x0 << 18)
+#define DXEPCTL_EPTYPE_ISO		(0x1 << 18)
+#define DXEPCTL_EPTYPE_BULK		(0x2 << 18)
+#define DXEPCTL_EPTYPE_INTERRUPT	(0x3 << 18)
+
+#define DXEPCTL_NAKSTS			BIT(17)
+#define DXEPCTL_DPID			BIT(16)
+#define DXEPCTL_EOFRNUM			BIT(16)
+#define DXEPCTL_USBACTEP		BIT(15)
+#define DXEPCTL_NEXTEP_MASK		(0xf << 11)
+#define DXEPCTL_NEXTEP_SHIFT		11
+#define DXEPCTL_NEXTEP_LIMIT		0xf
+#define DXEPCTL_NEXTEP(_x)		((_x) << 11)
+#define DXEPCTL_MPS_MASK		(0x7ff << 0)
+#define DXEPCTL_MPS_SHIFT		0
+#define DXEPCTL_MPS_LIMIT		0x7ff
+#define DXEPCTL_MPS(_x)			((_x) << 0)
+
+#define DIEPINT(_a)			HSOTG_REG(0x908 + ((_a) * 0x20))
+#define DOEPINT(_a)			HSOTG_REG(0xB08 + ((_a) * 0x20))
+#define DXEPINT_SETUP_RCVD		BIT(15)
+#define DXEPINT_NYETINTRPT		BIT(14)
+#define DXEPINT_NAKINTRPT		BIT(13)
+#define DXEPINT_BBLEERRINTRPT		BIT(12)
+#define DXEPINT_PKTDRPSTS		BIT(11)
+#define DXEPINT_BNAINTR			BIT(9)
+#define DXEPINT_TXFIFOUNDRN		BIT(8)
+#define DXEPINT_OUTPKTERR		BIT(8)
+#define DXEPINT_TXFEMP			BIT(7)
+#define DXEPINT_INEPNAKEFF		BIT(6)
+#define DXEPINT_BACK2BACKSETUP		BIT(6)
+#define DXEPINT_INTKNEPMIS		BIT(5)
+#define DXEPINT_STSPHSERCVD		BIT(5)
+#define DXEPINT_INTKNTXFEMP		BIT(4)
+#define DXEPINT_OUTTKNEPDIS		BIT(4)
+#define DXEPINT_TIMEOUT			BIT(3)
+#define DXEPINT_SETUP			BIT(3)
+#define DXEPINT_AHBERR			BIT(2)
+#define DXEPINT_EPDISBLD		BIT(1)
+#define DXEPINT_XFERCOMPL		BIT(0)
+
+#define DIEPTSIZ0			HSOTG_REG(0x910)
+#define DIEPTSIZ0_PKTCNT_MASK		(0x3 << 19)
+#define DIEPTSIZ0_PKTCNT_SHIFT		19
+#define DIEPTSIZ0_PKTCNT_LIMIT		0x3
+#define DIEPTSIZ0_PKTCNT(_x)		((_x) << 19)
+#define DIEPTSIZ0_XFERSIZE_MASK		(0x7f << 0)
+#define DIEPTSIZ0_XFERSIZE_SHIFT	0
+#define DIEPTSIZ0_XFERSIZE_LIMIT	0x7f
+#define DIEPTSIZ0_XFERSIZE(_x)		((_x) << 0)
+
+#define DOEPTSIZ0			HSOTG_REG(0xB10)
+#define DOEPTSIZ0_SUPCNT_MASK		(0x3 << 29)
+#define DOEPTSIZ0_SUPCNT_SHIFT		29
+#define DOEPTSIZ0_SUPCNT_LIMIT		0x3
+#define DOEPTSIZ0_SUPCNT(_x)		((_x) << 29)
+#define DOEPTSIZ0_PKTCNT		BIT(19)
+#define DOEPTSIZ0_XFERSIZE_MASK		(0x7f << 0)
+#define DOEPTSIZ0_XFERSIZE_SHIFT	0
+
+#define DIEPTSIZ(_a)			HSOTG_REG(0x910 + ((_a) * 0x20))
+#define DOEPTSIZ(_a)			HSOTG_REG(0xB10 + ((_a) * 0x20))
+#define DXEPTSIZ_MC_MASK		(0x3 << 29)
+#define DXEPTSIZ_MC_SHIFT		29
+#define DXEPTSIZ_MC_LIMIT		0x3
+#define DXEPTSIZ_MC(_x)			((_x) << 29)
+#define DXEPTSIZ_PKTCNT_MASK		(0x3ff << 19)
+#define DXEPTSIZ_PKTCNT_SHIFT		19
+#define DXEPTSIZ_PKTCNT_LIMIT		0x3ff
+#define DXEPTSIZ_PKTCNT_GET(_v)		(((_v) >> 19) & 0x3ff)
+#define DXEPTSIZ_PKTCNT(_x)		((_x) << 19)
+#define DXEPTSIZ_XFERSIZE_MASK		(0x7ffff << 0)
+#define DXEPTSIZ_XFERSIZE_SHIFT		0
+#define DXEPTSIZ_XFERSIZE_LIMIT		0x7ffff
+#define DXEPTSIZ_XFERSIZE_GET(_v)	(((_v) >> 0) & 0x7ffff)
+#define DXEPTSIZ_XFERSIZE(_x)		((_x) << 0)
+
+#define DIEPDMA(_a)			HSOTG_REG(0x914 + ((_a) * 0x20))
+#define DOEPDMA(_a)			HSOTG_REG(0xB14 + ((_a) * 0x20))
+
+#define DTXFSTS(_a)			HSOTG_REG(0x918 + ((_a) * 0x20))
+
+#define PCGCTL				HSOTG_REG(0x0e00)
+#define PCGCTL_IF_DEV_MODE		BIT(31)
+#define PCGCTL_P2HD_PRT_SPD_MASK	(0x3 << 29)
+#define PCGCTL_P2HD_PRT_SPD_SHIFT	29
+#define PCGCTL_P2HD_DEV_ENUM_SPD_MASK	(0x3 << 27)
+#define PCGCTL_P2HD_DEV_ENUM_SPD_SHIFT	27
+#define PCGCTL_MAC_DEV_ADDR_MASK	(0x7f << 20)
+#define PCGCTL_MAC_DEV_ADDR_SHIFT	20
+#define PCGCTL_MAX_TERMSEL		BIT(19)
+#define PCGCTL_MAX_XCVRSELECT_MASK	(0x3 << 17)
+#define PCGCTL_MAX_XCVRSELECT_SHIFT	17
+#define PCGCTL_PORT_POWER		BIT(16)
+#define PCGCTL_PRT_CLK_SEL_MASK		(0x3 << 14)
+#define PCGCTL_PRT_CLK_SEL_SHIFT	14
+#define PCGCTL_ESS_REG_RESTORED		BIT(13)
+#define PCGCTL_EXTND_HIBER_SWITCH	BIT(12)
+#define PCGCTL_EXTND_HIBER_PWRCLMP	BIT(11)
+#define PCGCTL_ENBL_EXTND_HIBER		BIT(10)
+#define PCGCTL_RESTOREMODE		BIT(9)
+#define PCGCTL_RESETAFTSUSP		BIT(8)
+#define PCGCTL_DEEP_SLEEP		BIT(7)
+#define PCGCTL_PHY_IN_SLEEP		BIT(6)
+#define PCGCTL_ENBL_SLEEP_GATING	BIT(5)
+#define PCGCTL_RSTPDWNMODULE		BIT(3)
+#define PCGCTL_PWRCLMP			BIT(2)
+#define PCGCTL_GATEHCLK			BIT(1)
+#define PCGCTL_STOPPCLK			BIT(0)
+
+#define PCGCCTL1			HSOTG_REG(0xe04)
+#define PCGCCTL1_TIMER			(0x3 << 1)
+#define PCGCCTL1_GATEEN			BIT(0)
+
+#define EPFIFO(_a)			HSOTG_REG(0x1000 + ((_a) * 0x1000))
+
+/* Host Mode Registers */
+
+#define HCFG				HSOTG_REG(0x0400)
+#define HCFG_MODECHTIMEN		BIT(31)
+#define HCFG_PERSCHEDENA		BIT(26)
+#define HCFG_FRLISTEN_MASK		(0x3 << 24)
+#define HCFG_FRLISTEN_SHIFT		24
+#define HCFG_FRLISTEN_8				(0 << 24)
+#define FRLISTEN_8_SIZE				8
+#define HCFG_FRLISTEN_16			BIT(24)
+#define FRLISTEN_16_SIZE			16
+#define HCFG_FRLISTEN_32			(2 << 24)
+#define FRLISTEN_32_SIZE			32
+#define HCFG_FRLISTEN_64			(3 << 24)
+#define FRLISTEN_64_SIZE			64
+#define HCFG_DESCDMA			BIT(23)
+#define HCFG_RESVALID_MASK		(0xff << 8)
+#define HCFG_RESVALID_SHIFT		8
+#define HCFG_ENA32KHZ			BIT(7)
+#define HCFG_FSLSSUPP			BIT(2)
+#define HCFG_FSLSPCLKSEL_MASK		(0x3 << 0)
+#define HCFG_FSLSPCLKSEL_SHIFT		0
+#define HCFG_FSLSPCLKSEL_30_60_MHZ	0
+#define HCFG_FSLSPCLKSEL_48_MHZ		1
+#define HCFG_FSLSPCLKSEL_6_MHZ		2
+
+#define HFIR				HSOTG_REG(0x0404)
+#define HFIR_FRINT_MASK			(0xffff << 0)
+#define HFIR_FRINT_SHIFT		0
+#define HFIR_RLDCTRL			BIT(16)
+
+#define HFNUM				HSOTG_REG(0x0408)
+#define HFNUM_FRREM_MASK		(0xffff << 16)
+#define HFNUM_FRREM_SHIFT		16
+#define HFNUM_FRNUM_MASK		(0xffff << 0)
+#define HFNUM_FRNUM_SHIFT		0
+#define HFNUM_MAX_FRNUM			0x3fff
+
+#define HPTXSTS				HSOTG_REG(0x0410)
+#define TXSTS_QTOP_ODD			BIT(31)
+#define TXSTS_QTOP_CHNEP_MASK		(0xf << 27)
+#define TXSTS_QTOP_CHNEP_SHIFT		27
+#define TXSTS_QTOP_TOKEN_MASK		(0x3 << 25)
+#define TXSTS_QTOP_TOKEN_SHIFT		25
+#define TXSTS_QTOP_TERMINATE		BIT(24)
+#define TXSTS_QSPCAVAIL_MASK		(0xff << 16)
+#define TXSTS_QSPCAVAIL_SHIFT		16
+#define TXSTS_FSPCAVAIL_MASK		(0xffff << 0)
+#define TXSTS_FSPCAVAIL_SHIFT		0
+
+#define HAINT				HSOTG_REG(0x0414)
+#define HAINTMSK			HSOTG_REG(0x0418)
+#define HFLBADDR			HSOTG_REG(0x041c)
+
+#define HPRT0				HSOTG_REG(0x0440)
+#define HPRT0_SPD_MASK			(0x3 << 17)
+#define HPRT0_SPD_SHIFT			17
+#define HPRT0_SPD_HIGH_SPEED		0
+#define HPRT0_SPD_FULL_SPEED		1
+#define HPRT0_SPD_LOW_SPEED		2
+#define HPRT0_TSTCTL_MASK		(0xf << 13)
+#define HPRT0_TSTCTL_SHIFT		13
+#define HPRT0_PWR			BIT(12)
+#define HPRT0_LNSTS_MASK		(0x3 << 10)
+#define HPRT0_LNSTS_SHIFT		10
+#define HPRT0_RST			BIT(8)
+#define HPRT0_SUSP			BIT(7)
+#define HPRT0_RES			BIT(6)
+#define HPRT0_OVRCURRCHG		BIT(5)
+#define HPRT0_OVRCURRACT		BIT(4)
+#define HPRT0_ENACHG			BIT(3)
+#define HPRT0_ENA			BIT(2)
+#define HPRT0_CONNDET			BIT(1)
+#define HPRT0_CONNSTS			BIT(0)
+
+#define HCCHAR(_ch)			HSOTG_REG(0x0500 + 0x20 * (_ch))
+#define HCCHAR_CHENA			BIT(31)
+#define HCCHAR_CHDIS			BIT(30)
+#define HCCHAR_ODDFRM			BIT(29)
+#define HCCHAR_DEVADDR_MASK		(0x7f << 22)
+#define HCCHAR_DEVADDR_SHIFT		22
+#define HCCHAR_MULTICNT_MASK		(0x3 << 20)
+#define HCCHAR_MULTICNT_SHIFT		20
+#define HCCHAR_EPTYPE_MASK		(0x3 << 18)
+#define HCCHAR_EPTYPE_SHIFT		18
+#define HCCHAR_LSPDDEV			BIT(17)
+#define HCCHAR_EPDIR			BIT(15)
+#define HCCHAR_EPNUM_MASK		(0xf << 11)
+#define HCCHAR_EPNUM_SHIFT		11
+#define HCCHAR_MPS_MASK			(0x7ff << 0)
+#define HCCHAR_MPS_SHIFT		0
+
+#define HCSPLT(_ch)			HSOTG_REG(0x0504 + 0x20 * (_ch))
+#define HCSPLT_SPLTENA			BIT(31)
+#define HCSPLT_COMPSPLT			BIT(16)
+#define HCSPLT_XACTPOS_MASK		(0x3 << 14)
+#define HCSPLT_XACTPOS_SHIFT		14
+#define HCSPLT_XACTPOS_MID		0
+#define HCSPLT_XACTPOS_END		1
+#define HCSPLT_XACTPOS_BEGIN		2
+#define HCSPLT_XACTPOS_ALL		3
+#define HCSPLT_HUBADDR_MASK		(0x7f << 7)
+#define HCSPLT_HUBADDR_SHIFT		7
+#define HCSPLT_PRTADDR_MASK		(0x7f << 0)
+#define HCSPLT_PRTADDR_SHIFT		0
+
+#define HCINT(_ch)			HSOTG_REG(0x0508 + 0x20 * (_ch))
+#define HCINTMSK(_ch)			HSOTG_REG(0x050c + 0x20 * (_ch))
+#define HCINTMSK_RESERVED14_31		(0x3ffff << 14)
+#define HCINTMSK_FRM_LIST_ROLL		BIT(13)
+#define HCINTMSK_XCS_XACT		BIT(12)
+#define HCINTMSK_BNA			BIT(11)
+#define HCINTMSK_DATATGLERR		BIT(10)
+#define HCINTMSK_FRMOVRUN		BIT(9)
+#define HCINTMSK_BBLERR			BIT(8)
+#define HCINTMSK_XACTERR		BIT(7)
+#define HCINTMSK_NYET			BIT(6)
+#define HCINTMSK_ACK			BIT(5)
+#define HCINTMSK_NAK			BIT(4)
+#define HCINTMSK_STALL			BIT(3)
+#define HCINTMSK_AHBERR			BIT(2)
+#define HCINTMSK_CHHLTD			BIT(1)
+#define HCINTMSK_XFERCOMPL		BIT(0)
+
+#define HCTSIZ(_ch)			HSOTG_REG(0x0510 + 0x20 * (_ch))
+#define TSIZ_DOPNG			BIT(31)
+#define TSIZ_SC_MC_PID_MASK		(0x3 << 29)
+#define TSIZ_SC_MC_PID_SHIFT		29
+#define TSIZ_SC_MC_PID_DATA0		0
+#define TSIZ_SC_MC_PID_DATA2		1
+#define TSIZ_SC_MC_PID_DATA1		2
+#define TSIZ_SC_MC_PID_MDATA		3
+#define TSIZ_SC_MC_PID_SETUP		3
+#define TSIZ_PKTCNT_MASK		(0x3ff << 19)
+#define TSIZ_PKTCNT_SHIFT		19
+#define TSIZ_NTD_MASK			(0xff << 8)
+#define TSIZ_NTD_SHIFT			8
+#define TSIZ_SCHINFO_MASK		(0xff << 0)
+#define TSIZ_SCHINFO_SHIFT		0
+#define TSIZ_XFERSIZE_MASK		(0x7ffff << 0)
+#define TSIZ_XFERSIZE_SHIFT		0
+
+#define HCDMA(_ch)			HSOTG_REG(0x0514 + 0x20 * (_ch))
+
+#define HCDMAB(_ch)			HSOTG_REG(0x051c + 0x20 * (_ch))
+
+#define HCFIFO(_ch)			HSOTG_REG(0x1000 + 0x1000 * (_ch))
+
+/**
+ * struct dwc2_dma_desc - DMA descriptor structure,
+ * used for both host and gadget modes
+ *
+ * @status: DMA descriptor status quadlet
+ * @buf:    DMA descriptor data buffer pointer
+ *
+ * DMA Descriptor structure contains two quadlets:
+ * Status quadlet and Data buffer pointer.
+ */
+struct dwc2_dma_desc {
+	u32 status;
+	u32 buf;
+} __packed;
+
+/* Host Mode DMA descriptor status quadlet */
+
+#define HOST_DMA_A			BIT(31)
+#define HOST_DMA_STS_MASK		(0x3 << 28)
+#define HOST_DMA_STS_SHIFT		28
+#define HOST_DMA_STS_PKTERR		BIT(28)
+#define HOST_DMA_EOL			BIT(26)
+#define HOST_DMA_IOC			BIT(25)
+#define HOST_DMA_SUP			BIT(24)
+#define HOST_DMA_ALT_QTD		BIT(23)
+#define HOST_DMA_QTD_OFFSET_MASK	(0x3f << 17)
+#define HOST_DMA_QTD_OFFSET_SHIFT	17
+#define HOST_DMA_ISOC_NBYTES_MASK	(0xfff << 0)
+#define HOST_DMA_ISOC_NBYTES_SHIFT	0
+#define HOST_DMA_NBYTES_MASK		(0x1ffff << 0)
+#define HOST_DMA_NBYTES_SHIFT		0
+#define HOST_DMA_NBYTES_LIMIT		131071
+
+#define MAX_DMA_DESC_NUM_GENERIC	64
+#define MAX_DMA_DESC_NUM_HS_ISOC	256
+
+	/* DWC OTG HW Release versions */
+#define DWC2_CORE_REV_2_71a	0x4f54271a
+#define DWC2_CORE_REV_2_72a     0x4f54272a
+#define DWC2_CORE_REV_2_80a	0x4f54280a
+#define DWC2_CORE_REV_2_90a	0x4f54290a
+#define DWC2_CORE_REV_2_91a	0x4f54291a
+#define DWC2_CORE_REV_2_92a	0x4f54292a
+#define DWC2_CORE_REV_2_94a	0x4f54294a
+#define DWC2_CORE_REV_3_00a	0x4f54300a
+#define DWC2_CORE_REV_3_10a	0x4f54310a
+#define DWC2_CORE_REV_4_00a	0x4f54400a
+#define DWC2_FS_IOT_REV_1_00a	0x5531100a
+#define DWC2_HS_IOT_REV_1_00a	0x5532100a
+
+	/* DWC OTG HW Core ID */
+#define DWC2_OTG_ID		0x4f540000
+#define DWC2_FS_IOT_ID		0x55310000
+#define DWC2_HS_IOT_ID		0x55320000
+
+/* ==== u-boot ==== */
+
+/* Default driver configuration */
+#define CONFIG_DWC2_MAX_CHANNELS		DWC2_MAX_EPS_CHANNELS	/* Max # of EPs */
+#define CONFIG_DWC2_HOST_RX_FIFO_SIZE		(516 + CONFIG_DWC2_MAX_CHANNELS)
+#define CONFIG_DWC2_HOST_NPERIO_TX_FIFO_SIZE	0x100	/* nPeriodic TX FIFO */
+#define CONFIG_DWC2_HOST_PERIO_TX_FIFO_SIZE	0x200	/* Periodic TX FIFO */
+
+#endif	/* __DWC2_H__ */
diff --git a/drivers/usb/dwc2/rhub.c b/drivers/usb/dwc2/rhub.c
new file mode 100644
index 000000000..b94723d7b
--- /dev/null
+++ b/drivers/usb/dwc2/rhub.c
@@ -0,0 +1,418 @@
+#include "dwc2.h"
+
+static struct descriptor {
+	struct usb_hub_descriptor hub;
+	struct usb_device_descriptor device;
+	struct usb_config_descriptor config;
+	struct usb_interface_descriptor interface;
+	struct usb_endpoint_descriptor endpoint;
+}  __attribute__ ((packed)) descriptor = {
+	.hub = {
+		.bLength		= USB_DT_HUB_NONVAR_SIZE +
+					  ((USB_MAXCHILDREN + 1 + 7) / 8),
+		.bDescriptorType	= USB_DT_HUB,
+		.bNbrPorts		= 1,	/* runtime modified */
+		.wHubCharacteristics	= 0,
+		.bPwrOn2PwrGood		= 0,
+		.bHubContrCurrent	= 0,
+		.u.hs.DeviceRemovable	= {0xff},
+		.u.hs.PortPwrCtrlMask	= {}
+	},
+	.device = {
+		.bLength		= USB_DT_DEVICE_SIZE,
+		.bDescriptorType	= USB_DT_DEVICE,
+		.bcdUSB			= __constant_cpu_to_le16(2), /* v2.0 */
+		.bDeviceClass		= USB_CLASS_HUB,
+		.bDeviceSubClass	= 0,
+		.bDeviceProtocol	= USB_HUB_PR_HS_NO_TT,
+		.bMaxPacketSize0	= 64,
+		.idVendor		= 0x0000,
+		.idProduct		= 0x0000,
+		.bcdDevice		= 0x0000,
+		.iManufacturer		= 1,
+		.iProduct		= 2,
+		.iSerialNumber		= 0,
+		.bNumConfigurations	= 1
+	},
+	.config = {
+		.bLength		= USB_DT_CONFIG_SIZE,
+		.bDescriptorType	= USB_DT_CONFIG,
+		.wTotalLength		= __constant_cpu_to_le16(
+						USB_DT_CONFIG_SIZE +
+						USB_DT_INTERFACE_SIZE +
+						USB_DT_ENDPOINT_SIZE),
+		.bNumInterfaces		= 1,
+		.bConfigurationValue	= 1,
+		.iConfiguration		= 0,
+		.bmAttributes		= USB_CONFIG_ATT_SELFPOWER,
+		.bMaxPower		= 0
+	},
+	.interface = {
+		.bLength		= USB_DT_INTERFACE_SIZE,
+		.bDescriptorType	= USB_DT_INTERFACE,
+		.bInterfaceNumber	= 0,
+		.bAlternateSetting	= 0,
+		.bNumEndpoints		= 1,
+		.bInterfaceClass	= USB_CLASS_HUB,
+		.bInterfaceSubClass	= 0,
+		.bInterfaceProtocol	= 0,
+		.iInterface		= 0
+	},
+	.endpoint = {
+		.bLength		= USB_DT_ENDPOINT_SIZE,
+		.bDescriptorType	= USB_DT_ENDPOINT,
+		.bEndpointAddress	= 1 | USB_DIR_IN, /* 0x81 */
+		.bmAttributes		= USB_ENDPOINT_XFER_INT,
+		.wMaxPacketSize		= __constant_cpu_to_le16(
+						(USB_MAXCHILDREN + 1 + 7) / 8),
+		.bInterval		= 255
+	},
+};
+
+static char *language_string = "\x09\x04";
+static char *vendor_string = "u-boot";
+static char *product_string = "DWC2 root hub";
+
+/*
+ * DWC2 to USB API interface
+ */
+static int dwc2_submit_rh_msg_in_status(struct dwc2 *dwc2,
+					   struct usb_device *dev, void *buffer,
+					   int txlen, struct devrequest *cmd)
+{
+	struct usb_port_status *portsts;
+	uint32_t hprt0 = 0;
+	uint32_t port_status = 0;
+	uint32_t port_change = 0;
+	int len = 0;
+	int speed;
+
+	switch (cmd->requesttype & (USB_TYPE_MASK | USB_RECIP_MASK)) {
+	case USB_TYPE_STANDARD | USB_RECIP_DEVICE:
+		*(uint16_t *)buffer = cpu_to_le16(1);
+		len = 2;
+		break;
+	case USB_TYPE_STANDARD | USB_RECIP_INTERFACE:
+	case USB_TYPE_STANDARD | USB_RECIP_ENDPOINT:
+		*(uint16_t *)buffer = cpu_to_le16(0);
+		len = 2;
+		break;
+	case USB_RT_HUB:	/* USB_TYPE_CLASS | USB_RECIP_DEVICE */
+		*(uint32_t *)buffer = cpu_to_le32(0);
+		len = 4;
+		break;
+	case USB_RT_PORT:	/* USB_TYPE_CLASS | USB_RECIP_OTHER */
+		hprt0 = dwc2_readl(dwc2, HPRT0);
+
+		if (hprt0 & HPRT0_CONNSTS)
+			port_status |= USB_PORT_STAT_CONNECTION;
+		if (hprt0 & HPRT0_ENA)
+			port_status |= USB_PORT_STAT_ENABLE;
+		if (hprt0 & HPRT0_SUSP)
+			port_status |= USB_PORT_STAT_SUSPEND;
+		if (hprt0 & HPRT0_OVRCURRACT)
+			port_status |= USB_PORT_STAT_OVERCURRENT;
+		if (hprt0 & HPRT0_RST)
+			port_status |= USB_PORT_STAT_RESET;
+		if (hprt0 & HPRT0_PWR)
+			port_status |= USB_PORT_STAT_POWER;
+
+		speed = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
+		if (speed == HPRT0_SPD_HIGH_SPEED)
+			port_status |= USB_PORT_STAT_HIGH_SPEED;
+		else if (speed == HPRT0_SPD_LOW_SPEED)
+			port_status |= USB_PORT_STAT_LOW_SPEED;
+
+		if (hprt0 & HPRT0_ENACHG)
+			port_change |= USB_PORT_STAT_C_ENABLE;
+		if (hprt0 & HPRT0_CONNDET)
+			port_change |= USB_PORT_STAT_C_CONNECTION;
+		if (hprt0 & HPRT0_OVRCURRCHG)
+			port_change |= USB_PORT_STAT_C_OVERCURRENT;
+
+		portsts = buffer;
+		portsts->wPortStatus = cpu_to_le16(port_status);
+		portsts->wPortChange = cpu_to_le16(port_change);
+		len = sizeof(*portsts);
+
+		break;
+	default:
+		goto unknown;
+	}
+
+	dev->act_len = min(len, txlen);
+	dev->status = 0;
+
+	return 0;
+
+unknown:
+	dev->act_len = 0;
+	dev->status = USB_ST_STALLED;
+
+	return -1;
+}
+
+static void strtodesc(char *dest, char *src, size_t n)
+{
+	unsigned int i;
+
+	dest[0] = n;
+	dest[1] = 0x3;
+	for (i = 2; i < n && *src != '\0'; i += 2) {
+		dest[i] = *(src++);
+		dest[i + 1] = 0;
+	}
+}
+
+/* Direction: In ; Request: Descriptor */
+static int dwc2_submit_rh_msg_in_descriptor(struct usb_device *dev,
+					       void *buffer, int txlen,
+					       struct devrequest *cmd)
+{
+	int len = 0;
+	char *src;
+	uint16_t wValue = le16_to_cpu(cmd->value);
+	uint16_t wLength = le16_to_cpu(cmd->length);
+
+	switch (cmd->requesttype & (USB_TYPE_MASK | USB_RECIP_MASK)) {
+	case USB_TYPE_STANDARD | USB_RECIP_DEVICE:
+		switch (wValue >> 8) {
+		case USB_DT_DEVICE:
+			debug("USB_DT_DEVICE request\n");
+			len = min3(txlen, (int)descriptor.device.bLength, (int)wLength);
+			memcpy(buffer, &descriptor.device, len);
+			break;
+		case USB_DT_CONFIG:
+			debug("USB_DT_CONFIG config\n");
+			len = min3(txlen, (int)descriptor.config.wTotalLength, (int)wLength);
+			memcpy(buffer, &descriptor.config, len);
+			break;
+		case USB_DT_STRING:
+			debug("USB_DT_STRING: %#x\n", wValue);
+			switch (wValue & 0xff) {
+			case 0: /* Language */
+				src = language_string;
+				len = strlen(src) + 2;
+				((char *)buffer)[0] = len;
+				((char *)buffer)[1] = 0x03;
+				memcpy(buffer + 2, src, strlen(src));
+				break;
+			case 1: /* Vendor */
+				src = vendor_string;
+				len = 2 * strlen(src) + 2;
+				strtodesc(buffer, src, len);
+				break;
+			case 2: /* Product */
+				src = product_string;
+				len = 2 * strlen(src) + 2;
+				strtodesc(buffer, src, len);
+				break;
+			default:
+				debug("%s(): unknown string index 0x%x\n", __func__, wValue & 0xff);
+				goto unknown;
+			}
+			len = min3(txlen, len, (int)wLength);
+			break;
+		default:
+			debug("%s(): unknown requesttype: 0x%x\n", __func__,
+			       cmd->requesttype & (USB_TYPE_MASK | USB_RECIP_MASK));
+			goto unknown;
+		}
+		break;
+
+	case USB_RT_HUB:	/* USB_TYPE_CLASS | USB_RECIP_DEVICE */
+		debug("USB_RT_HUB\n");
+
+		len = min3(txlen, (int)descriptor.hub.bLength, (int)wLength);
+		memcpy(buffer, &descriptor.hub, len);
+		break;
+	default:
+		goto unknown;
+	}
+
+	dev->act_len = len;
+	dev->status = 0;
+
+	return 0;
+
+unknown:
+	dev->act_len = 0;
+	dev->status = USB_ST_STALLED;
+
+	return -1;
+}
+
+/* Direction: In ; Request: Configuration */
+static int dwc2_submit_rh_msg_in_configuration(struct usb_device *dev,
+					       void *buffer, int txlen,
+					       struct devrequest *cmd)
+{
+	int len = 0;
+
+	switch (cmd->requesttype & (USB_TYPE_MASK | USB_RECIP_MASK)) {
+	case USB_TYPE_STANDARD | USB_RECIP_DEVICE:
+		*(uint8_t *)buffer = 0x01;
+		len = min(txlen, 1);
+		break;
+	default:
+		goto unknown;
+	}
+
+	dev->act_len = len;
+	dev->status = 0;
+
+	return 0;
+
+unknown:
+	dev->act_len = 0;
+	dev->status = USB_ST_STALLED;
+
+	return -1;
+}
+
+/* Direction: In */
+static int dwc2_submit_rh_msg_in(struct dwc2 *dwc2,
+				 struct usb_device *dev, void *buffer,
+				 int txlen, struct devrequest *cmd)
+{
+	switch (cmd->request) {
+	case USB_REQ_GET_STATUS:
+		return dwc2_submit_rh_msg_in_status(dwc2, dev, buffer,
+						       txlen, cmd);
+	case USB_REQ_GET_DESCRIPTOR:
+		return dwc2_submit_rh_msg_in_descriptor(dev, buffer,
+							   txlen, cmd);
+	case USB_REQ_GET_CONFIGURATION:
+		return dwc2_submit_rh_msg_in_configuration(dev, buffer,
+							      txlen, cmd);
+	default:
+		dev->act_len = 0;
+		dev->status = USB_ST_STALLED;
+
+		return -1;
+	}
+}
+
+/* Direction: Out */
+static int dwc2_submit_rh_msg_out(struct dwc2 *dwc2,
+				  struct usb_device *dev,
+				  void *buffer, int txlen,
+				  struct devrequest *cmd)
+{
+	uint16_t wValue = le16_to_cpu(cmd->value);
+	uint32_t hprt0;
+
+	switch (cmd->requesttype & (USB_TYPE_MASK | USB_RECIP_MASK)) {
+	case USB_TYPE_STANDARD | USB_RECIP_DEVICE:
+		switch (cmd->request) {
+		case USB_REQ_SET_ADDRESS:
+			dwc2_dbg(dwc2, "set root hub addr %d\n", wValue);
+			dwc2->root_hub_devnum = wValue;
+			break;
+		case USB_REQ_SET_CONFIGURATION:
+			break;
+		default:
+			goto unknown;
+		}
+		break;
+	case USB_TYPE_STANDARD | USB_RECIP_ENDPOINT:
+	case USB_RT_HUB:	/* USB_TYPE_CLASS | USB_RECIP_DEVICE */
+		switch (cmd->request) {
+		case USB_REQ_CLEAR_FEATURE:
+			break;
+		}
+		break;
+	case USB_RT_PORT:	/* USB_TYPE_CLASS | USB_RECIP_OTHER */
+		switch (cmd->request) {
+		case USB_REQ_CLEAR_FEATURE:
+			hprt0 = dwc2_readl(dwc2, HPRT0);
+			hprt0 &= ~(HPRT0_ENA | HPRT0_CONNDET
+				   | HPRT0_ENACHG | HPRT0_OVRCURRCHG);
+			switch (wValue) {
+			case USB_PORT_FEAT_ENABLE:
+				hprt0 |= HPRT0_ENA;
+				break;
+			case USB_PORT_FEAT_SUSPEND:
+				break;
+			case USB_PORT_FEAT_POWER:
+				break;
+			case USB_PORT_FEAT_C_CONNECTION:
+				hprt0 |= HPRT0_CONNDET;
+				break;
+			case USB_PORT_FEAT_C_ENABLE:
+				hprt0 |= HPRT0_ENACHG;
+				break;
+			case USB_PORT_FEAT_C_OVER_CURRENT:
+				hprt0 |= HPRT0_OVRCURRCHG;
+				break;
+			default:
+				dwc2_dbg(dwc2, "unknown feature 0x%x\n", wValue);
+				goto unknown;
+			}
+			dwc2_writel(dwc2, hprt0, HPRT0);
+			break;
+		case USB_REQ_SET_FEATURE:
+			hprt0 = dwc2_readl(dwc2, HPRT0);
+			hprt0 &= ~(HPRT0_ENA | HPRT0_CONNDET
+				   | HPRT0_ENACHG | HPRT0_OVRCURRCHG);
+			switch (wValue) {
+			case USB_PORT_FEAT_SUSPEND:
+				break;
+			case USB_PORT_FEAT_RESET:
+				hprt0 |= HPRT0_RST;
+				dwc2_writel(dwc2, hprt0, HPRT0);
+
+				mdelay(60);
+
+				hprt0 = dwc2_readl(dwc2, HPRT0);
+				hprt0 &= ~HPRT0_RST;
+				dwc2_writel(dwc2, hprt0, HPRT0);
+				break;
+			case USB_PORT_FEAT_POWER:
+				break;
+			case USB_PORT_FEAT_ENABLE:
+				/* Set by the core after a reset */
+				break;
+			default:
+				dwc2_dbg(dwc2, "unknown feature 0x%x\n", wValue);
+				goto unknown;
+			}
+			break;
+		default: goto unknown;
+		}
+		break;
+	default:
+		goto unknown;
+	}
+
+	dev->act_len = 0;
+	dev->status = 0;
+
+	return 0;
+
+unknown:
+	dev->act_len = 0;
+	dev->status = USB_ST_STALLED;
+	return -1;
+}
+
+int
+dwc2_submit_rh_msg(struct dwc2 *dwc2, struct usb_device *dev,
+				 unsigned long pipe, void *buffer, int txlen,
+				 struct devrequest *cmd)
+{
+	int stat = 0;
+
+	if (usb_pipeint(pipe)) {
+		dwc2_err(dwc2, "Root-Hub submit IRQ: NOT implemented\n");
+		return 0;
+	}
+
+	if (cmd->requesttype & USB_DIR_IN)
+		stat = dwc2_submit_rh_msg_in(dwc2, dev, buffer, txlen, cmd);
+	else
+		stat = dwc2_submit_rh_msg_out(dwc2, dev, buffer, txlen, cmd);
+
+	mdelay(1);
+	return stat;
+}
-- 
2.21.0.196.g041f5ea


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC PATCH 2/7] usb: dwc2: host: Handle dma mapping errors
  2020-01-14 13:21   ` [RFC PATCH 0/7] usb: " Jules Maselbas
  2020-01-14 13:21     ` [RFC PATCH 1/7] usb: dwc2: Add host controller driver Jules Maselbas
@ 2020-01-14 13:21     ` Jules Maselbas
  2020-01-14 13:21     ` [RFC PATCH 3/7] usb: dwc2: Dynamic fifo size support from Linux Jules Maselbas
                       ` (5 subsequent siblings)
  7 siblings, 0 replies; 24+ messages in thread
From: Jules Maselbas @ 2020-01-14 13:21 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: Barebox List, Jules Maselbas

Signed-off-by: Jules Maselbas <jmaselbas@kalray.eu>
---
 drivers/usb/dwc2/host.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/usb/dwc2/host.c b/drivers/usb/dwc2/host.c
index 4137dd3cb..a1f2e3ea1 100644
--- a/drivers/usb/dwc2/host.c
+++ b/drivers/usb/dwc2/host.c
@@ -154,6 +154,11 @@ static int transfer_chunk(struct dwc2 *dwc2, u8 hc,
 	dma_addr = dma_map_single(dwc2->dev, buffer, xfer_len,
 				  in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 
+	if (dma_mapping_error(dwc2->dev, dma_addr)) {
+		dwc2_err(dwc2, "Failed to map buffer@0x%p for dma\n", buffer);
+		return -EFAULT;
+	}
+
 	dwc2_dbg(dwc2, "chunk: pid=%d xfer_len=%u pkts=%u dma_addr=%llx\n",
 			*pid, xfer_len, num_packets, dma_addr);
 
-- 
2.21.0.196.g041f5ea


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC PATCH 3/7] usb: dwc2: Dynamic fifo size support from Linux
  2020-01-14 13:21   ` [RFC PATCH 0/7] usb: " Jules Maselbas
  2020-01-14 13:21     ` [RFC PATCH 1/7] usb: dwc2: Add host controller driver Jules Maselbas
  2020-01-14 13:21     ` [RFC PATCH 2/7] usb: dwc2: host: Handle dma mapping errors Jules Maselbas
@ 2020-01-14 13:21     ` Jules Maselbas
  2020-01-14 13:21     ` [RFC PATCH 4/7] usb: dwc2: Rework roothub interface Jules Maselbas
                       ` (4 subsequent siblings)
  7 siblings, 0 replies; 24+ messages in thread
From: Jules Maselbas @ 2020-01-14 13:21 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: Barebox List, Jules Maselbas

Signed-off-by: Jules Maselbas <jmaselbas@kalray.eu>
---
 drivers/usb/dwc2/host.c | 146 ++++++++++++++++++++++++++++++++++------
 drivers/usb/dwc2/regs.h |   8 ---
 2 files changed, 124 insertions(+), 30 deletions(-)

diff --git a/drivers/usb/dwc2/host.c b/drivers/usb/dwc2/host.c
index a1f2e3ea1..84eb9b627 100644
--- a/drivers/usb/dwc2/host.c
+++ b/drivers/usb/dwc2/host.c
@@ -437,6 +437,129 @@ int dwc2_submit_int_msg(struct usb_device *udev, unsigned long pipe,
 	}
 }
 
+/*
+ * dwc2_calculate_dynamic_fifo() - Calculates the default fifo size
+ * For system that have a total fifo depth that is smaller than the default
+ * RX + TX fifo size.
+ *
+ * @dwc2: Programming view of DWC_otg controller
+ */
+static void dwc2_calculate_dynamic_fifo(struct dwc2 *dwc2)
+{
+	struct dwc2_core_params *params = &dwc2->params;
+	struct dwc2_hw_params *hw = &dwc2->hw_params;
+	u32 rxfsiz, nptxfsiz, ptxfsiz, total_fifo_size;
+
+	total_fifo_size = hw->total_fifo_size;
+	rxfsiz = params->host_rx_fifo_size;
+	nptxfsiz = params->host_nperio_tx_fifo_size;
+	ptxfsiz = params->host_perio_tx_fifo_size;
+
+	/*
+	 * Will use Method 2 defined in the DWC2 spec: minimum FIFO depth
+	 * allocation with support for high bandwidth endpoints. Synopsys
+	 * defines MPS(Max Packet size) for a periodic EP=1024, and for
+	 * non-periodic as 512.
+	 */
+	if (total_fifo_size < (rxfsiz + nptxfsiz + ptxfsiz)) {
+		/*
+		 * For Buffer DMA mode/Scatter Gather DMA mode
+		 * 2 * ((Largest Packet size / 4) + 1 + 1) + n
+		 * with n = number of host channel.
+		 * 2 * ((1024/4) + 2) = 516
+		 */
+		rxfsiz = 516 + hw->host_channels;
+
+		/*
+		 * min non-periodic tx fifo depth
+		 * 2 * (largest non-periodic USB packet used / 4)
+		 * 2 * (512/4) = 256
+		 */
+		nptxfsiz = 256;
+
+		/*
+		 * min periodic tx fifo depth
+		 * (largest packet size*MC)/4
+		 * (1024 * 3)/4 = 768
+		 */
+		ptxfsiz = 768;
+	}
+
+	params->host_rx_fifo_size = rxfsiz;
+	params->host_nperio_tx_fifo_size = nptxfsiz;
+	params->host_perio_tx_fifo_size = ptxfsiz;
+
+	/*
+	 * If the summation of RX, NPTX and PTX fifo sizes is still
+	 * bigger than the total_fifo_size, then we have a problem.
+	 *
+	 * We won't be able to allocate as many endpoints. Right now,
+	 * we're just printing an error message, but ideally this FIFO
+	 * allocation algorithm would be improved in the future.
+	 *
+	 * FIXME improve this FIFO allocation algorithm.
+	 */
+	if (unlikely(total_fifo_size < (rxfsiz + nptxfsiz + ptxfsiz)))
+		dwc2_err(dwc2, "invalid fifo sizes\n");
+}
+
+static void dwc2_config_fifos(struct dwc2 *dwc2)
+{
+	struct dwc2_core_params *params = &dwc2->params;
+	u32 nptxfsiz, hptxfsiz, dfifocfg, grxfsiz;
+
+	if (!params->enable_dynamic_fifo)
+		return;
+
+	dwc2_calculate_dynamic_fifo(dwc2);
+
+	/* Rx FIFO */
+	grxfsiz = dwc2_readl(dwc2, GRXFSIZ);
+	dwc2_dbg(dwc2, "initial grxfsiz=%08x\n", grxfsiz);
+	grxfsiz &= ~GRXFSIZ_DEPTH_MASK;
+	grxfsiz |= params->host_rx_fifo_size <<
+		   GRXFSIZ_DEPTH_SHIFT & GRXFSIZ_DEPTH_MASK;
+	dwc2_writel(dwc2, grxfsiz, GRXFSIZ);
+	dwc2_dbg(dwc2, "new grxfsiz=%08x\n", dwc2_readl(dwc2, GRXFSIZ));
+
+	/* Non-periodic Tx FIFO */
+	dwc2_dbg(dwc2, "initial gnptxfsiz=%08x\n", dwc2_readl(dwc2, GNPTXFSIZ));
+	nptxfsiz = params->host_nperio_tx_fifo_size <<
+		   FIFOSIZE_DEPTH_SHIFT & FIFOSIZE_DEPTH_MASK;
+	nptxfsiz |= params->host_rx_fifo_size <<
+		    FIFOSIZE_STARTADDR_SHIFT & FIFOSIZE_STARTADDR_MASK;
+	dwc2_writel(dwc2, nptxfsiz, GNPTXFSIZ);
+	dwc2_dbg(dwc2, "new gnptxfsiz=%08x\n", dwc2_readl(dwc2, GNPTXFSIZ));
+
+	/* Periodic Tx FIFO */
+	dwc2_dbg(dwc2, "initial hptxfsiz=%08x\n", dwc2_readl(dwc2, HPTXFSIZ));
+	hptxfsiz = params->host_perio_tx_fifo_size <<
+		   FIFOSIZE_DEPTH_SHIFT & FIFOSIZE_DEPTH_MASK;
+	hptxfsiz |= (params->host_rx_fifo_size +
+		     params->host_nperio_tx_fifo_size) <<
+		    FIFOSIZE_STARTADDR_SHIFT & FIFOSIZE_STARTADDR_MASK;
+	dwc2_writel(dwc2, hptxfsiz, HPTXFSIZ);
+	dwc2_dbg(dwc2, "new hptxfsiz=%08x\n", dwc2_readl(dwc2, HPTXFSIZ));
+
+	if (dwc2->params.en_multiple_tx_fifo &&
+	    dwc2->hw_params.snpsid >= DWC2_CORE_REV_2_91a) {
+		/*
+		 * This feature was implemented in 2.91a version
+		 * Global DFIFOCFG calculation for Host mode -
+		 * include RxFIFO, NPTXFIFO and HPTXFIFO
+		 */
+		dfifocfg = dwc2_readl(dwc2, GDFIFOCFG);
+		dfifocfg &= ~GDFIFOCFG_EPINFOBASE_MASK;
+		dfifocfg |= (params->host_rx_fifo_size +
+			     params->host_nperio_tx_fifo_size +
+			     params->host_perio_tx_fifo_size) <<
+			    GDFIFOCFG_EPINFOBASE_SHIFT &
+			    GDFIFOCFG_EPINFOBASE_MASK;
+		dwc2_writel(dwc2, dfifocfg, GDFIFOCFG);
+		dwc2_dbg(dwc2, "new dfifocfg=%08x\n", dfifocfg);
+	}
+}
+
 /*
  * This function initializes the DWC2 controller registers for
  * host mode.
@@ -452,8 +575,6 @@ int dwc2_submit_int_msg(struct usb_device *udev, unsigned long pipe,
 static void dwc2_core_host_init(struct device_d *dev,
 				   struct dwc2 *dwc2)
 {
-	uint32_t nptxfifosize = 0;
-	uint32_t ptxfifosize = 0;
 	uint32_t hcchar, hcfg, hprt0, hotgctl, usbcfg;
 	int i, ret, num_channels;
 
@@ -501,26 +622,7 @@ static void dwc2_core_host_init(struct device_d *dev,
 		}
 	}
 
-	/* Configure data FIFO sizes */
-	if (dwc2_readl(dwc2, GHWCFG2) & GHWCFG2_DYNAMIC_FIFO) {
-		/* Rx FIFO */
-		dwc2_writel(dwc2, CONFIG_DWC2_HOST_RX_FIFO_SIZE, GRXFSIZ);
-
-		/* Non-periodic Tx FIFO */
-		nptxfifosize |= CONFIG_DWC2_HOST_NPERIO_TX_FIFO_SIZE <<
-				FIFOSIZE_DEPTH_SHIFT;
-		nptxfifosize |= CONFIG_DWC2_HOST_RX_FIFO_SIZE <<
-				FIFOSIZE_STARTADDR_SHIFT;
-		dwc2_writel(dwc2, nptxfifosize, GNPTXFSIZ);
-
-		/* Periodic Tx FIFO */
-		ptxfifosize |= CONFIG_DWC2_HOST_PERIO_TX_FIFO_SIZE <<
-				FIFOSIZE_DEPTH_SHIFT;
-		ptxfifosize |= (CONFIG_DWC2_HOST_RX_FIFO_SIZE +
-				CONFIG_DWC2_HOST_NPERIO_TX_FIFO_SIZE) <<
-				FIFOSIZE_STARTADDR_SHIFT;
-		dwc2_writel(dwc2, ptxfifosize, HPTXFSIZ);
-	}
+	dwc2_config_fifos(dwc2);
 
 	/* Clear Host Set HNP Enable in the OTG Control Register */
 	hotgctl = dwc2_readl(dwc2, GOTGCTL);
diff --git a/drivers/usb/dwc2/regs.h b/drivers/usb/dwc2/regs.h
index b2b312e1b..0dee1813d 100644
--- a/drivers/usb/dwc2/regs.h
+++ b/drivers/usb/dwc2/regs.h
@@ -836,12 +836,4 @@ struct dwc2_dma_desc {
 #define DWC2_FS_IOT_ID		0x55310000
 #define DWC2_HS_IOT_ID		0x55320000
 
-/* ==== u-boot ==== */
-
-/* Default driver configuration */
-#define CONFIG_DWC2_MAX_CHANNELS		DWC2_MAX_EPS_CHANNELS	/* Max # of EPs */
-#define CONFIG_DWC2_HOST_RX_FIFO_SIZE		(516 + CONFIG_DWC2_MAX_CHANNELS)
-#define CONFIG_DWC2_HOST_NPERIO_TX_FIFO_SIZE	0x100	/* nPeriodic TX FIFO */
-#define CONFIG_DWC2_HOST_PERIO_TX_FIFO_SIZE	0x200	/* Periodic TX FIFO */
-
 #endif	/* __DWC2_H__ */
-- 
2.21.0.196.g041f5ea


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC PATCH 4/7] usb: dwc2: Rework roothub interface
  2020-01-14 13:21   ` [RFC PATCH 0/7] usb: " Jules Maselbas
                       ` (2 preceding siblings ...)
  2020-01-14 13:21     ` [RFC PATCH 3/7] usb: dwc2: Dynamic fifo size support from Linux Jules Maselbas
@ 2020-01-14 13:21     ` Jules Maselbas
  2020-01-14 13:21     ` [RFC PATCH 5/7] HACK: usb: dwc2: Fix toggle reset Jules Maselbas
                       ` (3 subsequent siblings)
  7 siblings, 0 replies; 24+ messages in thread
From: Jules Maselbas @ 2020-01-14 13:21 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: Barebox List, Jules Maselbas

Roothub requests are now decoded in one place.

Signed-off-by: Jules Maselbas <jmaselbas@kalray.eu>
---
 drivers/usb/dwc2/dwc2.h |   2 +-
 drivers/usb/dwc2/host.c |   4 +-
 drivers/usb/dwc2/rhub.c | 520 +++++++++++++++++++---------------------
 3 files changed, 246 insertions(+), 280 deletions(-)

diff --git a/drivers/usb/dwc2/dwc2.h b/drivers/usb/dwc2/dwc2.h
index 0ac4b40fc..0a4323ab4 100644
--- a/drivers/usb/dwc2/dwc2.h
+++ b/drivers/usb/dwc2/dwc2.h
@@ -35,7 +35,7 @@ int dwc2_submit_int_msg(struct usb_device *dev, unsigned long pipe,
 			void *buffer, int transfer_len, int interval);
 int dwc2_host_init(struct usb_host *host);
 
-int dwc2_submit_rh_msg(struct dwc2 *dwc2, struct usb_device *dev,
+int dwc2_submit_roothub(struct dwc2 *dwc2, struct usb_device *dev,
 		unsigned long pipe, void *buf, int len,
 		struct devrequest *setup);
 
diff --git a/drivers/usb/dwc2/host.c b/drivers/usb/dwc2/host.c
index 84eb9b627..2cde5977b 100644
--- a/drivers/usb/dwc2/host.c
+++ b/drivers/usb/dwc2/host.c
@@ -332,9 +332,9 @@ int dwc2_submit_control_msg(struct usb_device *udev,
 	int status_direction;
 
 	if (devnum == dwc2->root_hub_devnum) {
-		udev->status = 0;
 		udev->speed = USB_SPEED_HIGH;
-		return dwc2_submit_rh_msg(dwc2, udev, pipe, buffer, len, setup);
+		ret = dwc2_submit_roothub(dwc2, udev, pipe, buffer, len, setup);
+		return ret;
 	}
 
 	/* SETUP stage */
diff --git a/drivers/usb/dwc2/rhub.c b/drivers/usb/dwc2/rhub.c
index b94723d7b..cc733f34e 100644
--- a/drivers/usb/dwc2/rhub.c
+++ b/drivers/usb/dwc2/rhub.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 #include "dwc2.h"
 
 static struct descriptor {
@@ -6,7 +7,7 @@ static struct descriptor {
 	struct usb_config_descriptor config;
 	struct usb_interface_descriptor interface;
 	struct usb_endpoint_descriptor endpoint;
-}  __attribute__ ((packed)) descriptor = {
+}  __packed descriptor = {
 	.hub = {
 		.bLength		= USB_DT_HUB_NONVAR_SIZE +
 					  ((USB_MAXCHILDREN + 1 + 7) / 8),
@@ -21,7 +22,7 @@ static struct descriptor {
 	.device = {
 		.bLength		= USB_DT_DEVICE_SIZE,
 		.bDescriptorType	= USB_DT_DEVICE,
-		.bcdUSB			= __constant_cpu_to_le16(2), /* v2.0 */
+		.bcdUSB			= cpu_to_le16(2), /* v2.0 */
 		.bDeviceClass		= USB_CLASS_HUB,
 		.bDeviceSubClass	= 0,
 		.bDeviceProtocol	= USB_HUB_PR_HS_NO_TT,
@@ -37,7 +38,7 @@ static struct descriptor {
 	.config = {
 		.bLength		= USB_DT_CONFIG_SIZE,
 		.bDescriptorType	= USB_DT_CONFIG,
-		.wTotalLength		= __constant_cpu_to_le16(
+		.wTotalLength		= cpu_to_le16(
 						USB_DT_CONFIG_SIZE +
 						USB_DT_INTERFACE_SIZE +
 						USB_DT_ENDPOINT_SIZE),
@@ -63,356 +64,321 @@ static struct descriptor {
 		.bDescriptorType	= USB_DT_ENDPOINT,
 		.bEndpointAddress	= 1 | USB_DIR_IN, /* 0x81 */
 		.bmAttributes		= USB_ENDPOINT_XFER_INT,
-		.wMaxPacketSize		= __constant_cpu_to_le16(
+		.wMaxPacketSize		= cpu_to_le16(
 						(USB_MAXCHILDREN + 1 + 7) / 8),
 		.bInterval		= 255
 	},
 };
 
-static char *language_string = "\x09\x04";
-static char *vendor_string = "u-boot";
-static char *product_string = "DWC2 root hub";
-
-/*
- * DWC2 to USB API interface
- */
-static int dwc2_submit_rh_msg_in_status(struct dwc2 *dwc2,
-					   struct usb_device *dev, void *buffer,
-					   int txlen, struct devrequest *cmd)
+static int dwc2_get_port_status(struct dwc2 *dwc2, struct usb_device *dev,
+		void *buf, int len)
 {
 	struct usb_port_status *portsts;
-	uint32_t hprt0 = 0;
-	uint32_t port_status = 0;
-	uint32_t port_change = 0;
-	int len = 0;
+	uint32_t hprt0;
+	uint32_t status = 0;
+	uint32_t change = 0;
 	int speed;
 
-	switch (cmd->requesttype & (USB_TYPE_MASK | USB_RECIP_MASK)) {
-	case USB_TYPE_STANDARD | USB_RECIP_DEVICE:
-		*(uint16_t *)buffer = cpu_to_le16(1);
-		len = 2;
-		break;
-	case USB_TYPE_STANDARD | USB_RECIP_INTERFACE:
-	case USB_TYPE_STANDARD | USB_RECIP_ENDPOINT:
-		*(uint16_t *)buffer = cpu_to_le16(0);
-		len = 2;
-		break;
-	case USB_RT_HUB:	/* USB_TYPE_CLASS | USB_RECIP_DEVICE */
-		*(uint32_t *)buffer = cpu_to_le32(0);
-		len = 4;
-		break;
-	case USB_RT_PORT:	/* USB_TYPE_CLASS | USB_RECIP_OTHER */
-		hprt0 = dwc2_readl(dwc2, HPRT0);
+	if (!buf || len < sizeof(*portsts))
+		return -1;
 
-		if (hprt0 & HPRT0_CONNSTS)
-			port_status |= USB_PORT_STAT_CONNECTION;
-		if (hprt0 & HPRT0_ENA)
-			port_status |= USB_PORT_STAT_ENABLE;
-		if (hprt0 & HPRT0_SUSP)
-			port_status |= USB_PORT_STAT_SUSPEND;
-		if (hprt0 & HPRT0_OVRCURRACT)
-			port_status |= USB_PORT_STAT_OVERCURRENT;
-		if (hprt0 & HPRT0_RST)
-			port_status |= USB_PORT_STAT_RESET;
-		if (hprt0 & HPRT0_PWR)
-			port_status |= USB_PORT_STAT_POWER;
-
-		speed = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
-		if (speed == HPRT0_SPD_HIGH_SPEED)
-			port_status |= USB_PORT_STAT_HIGH_SPEED;
-		else if (speed == HPRT0_SPD_LOW_SPEED)
-			port_status |= USB_PORT_STAT_LOW_SPEED;
-
-		if (hprt0 & HPRT0_ENACHG)
-			port_change |= USB_PORT_STAT_C_ENABLE;
-		if (hprt0 & HPRT0_CONNDET)
-			port_change |= USB_PORT_STAT_C_CONNECTION;
-		if (hprt0 & HPRT0_OVRCURRCHG)
-			port_change |= USB_PORT_STAT_C_OVERCURRENT;
-
-		portsts = buffer;
-		portsts->wPortStatus = cpu_to_le16(port_status);
-		portsts->wPortChange = cpu_to_le16(port_change);
-		len = sizeof(*portsts);
+	hprt0 = dwc2_readl(dwc2, HPRT0);
+
+	if (hprt0 & HPRT0_CONNSTS)
+		status |= USB_PORT_STAT_CONNECTION;
+	if (hprt0 & HPRT0_ENA)
+		status |= USB_PORT_STAT_ENABLE;
+	if (hprt0 & HPRT0_SUSP)
+		status |= USB_PORT_STAT_SUSPEND;
+	if (hprt0 & HPRT0_OVRCURRACT)
+		status |= USB_PORT_STAT_OVERCURRENT;
+	if (hprt0 & HPRT0_RST)
+		status |= USB_PORT_STAT_RESET;
+	if (hprt0 & HPRT0_PWR)
+		status |= USB_PORT_STAT_POWER;
+
+	speed = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
+	if (speed == HPRT0_SPD_HIGH_SPEED)
+		status |= USB_PORT_STAT_HIGH_SPEED;
+	else if (speed == HPRT0_SPD_LOW_SPEED)
+		status |= USB_PORT_STAT_LOW_SPEED;
+
+	if (hprt0 & HPRT0_ENACHG)
+		change |= USB_PORT_STAT_C_ENABLE;
+	if (hprt0 & HPRT0_CONNDET)
+		change |= USB_PORT_STAT_C_CONNECTION;
+	if (hprt0 & HPRT0_OVRCURRCHG)
+		change |= USB_PORT_STAT_C_OVERCURRENT;
+
+	portsts = buf;
+	portsts->wPortStatus = cpu_to_le16(status);
+	portsts->wPortChange = cpu_to_le16(change);
+
+	dev->act_len = sizeof(*portsts);
+	dev->status = 0;
 
-		break;
-	default:
-		goto unknown;
-	}
+	return 0;
+}
 
-	dev->act_len = min(len, txlen);
-	dev->status = 0;
+static int dwc2_get_hub_status(struct dwc2 *dwc2, struct usb_device *dev,
+		void *buf, int len)
+{
+	if (!buf || len < 4)
+		return -1;
+
+	*(uint32_t *)buf = 0;
+	dev->act_len = 4;
+	dev->status  = 0;
 
 	return 0;
+}
 
-unknown:
-	dev->act_len = 0;
-	dev->status = USB_ST_STALLED;
+static int dwc2_get_hub_descriptor(struct dwc2 *dwc2, struct usb_device *dev,
+		void *buf, int len)
+{
+	if (!buf)
+		return -1;
+
+	dev->act_len = min_t(int, len, descriptor.hub.bLength);
+	dev->status = 0;
+	memcpy(buf, &descriptor.hub, dev->act_len);
 
-	return -1;
+	return 0;
 }
 
-static void strtodesc(char *dest, char *src, size_t n)
+static void strle16(__le16 *dest, char *src, size_t n)
 {
 	unsigned int i;
 
-	dest[0] = n;
-	dest[1] = 0x3;
-	for (i = 2; i < n && *src != '\0'; i += 2) {
-		dest[i] = *(src++);
-		dest[i + 1] = 0;
-	}
+	for (i = 0; i < n && *src != '\0'; i++, src++)
+		dest[i] = cpu_to_le16(*src);
 }
 
-/* Direction: In ; Request: Descriptor */
-static int dwc2_submit_rh_msg_in_descriptor(struct usb_device *dev,
-					       void *buffer, int txlen,
-					       struct devrequest *cmd)
+static int dwc2_get_string_descriptor(struct dwc2 *dwc2, struct usb_device *dev,
+			       void *buf, int len, int index)
 {
-	int len = 0;
-	char *src;
-	uint16_t wValue = le16_to_cpu(cmd->value);
-	uint16_t wLength = le16_to_cpu(cmd->length);
-
-	switch (cmd->requesttype & (USB_TYPE_MASK | USB_RECIP_MASK)) {
-	case USB_TYPE_STANDARD | USB_RECIP_DEVICE:
-		switch (wValue >> 8) {
-		case USB_DT_DEVICE:
-			debug("USB_DT_DEVICE request\n");
-			len = min3(txlen, (int)descriptor.device.bLength, (int)wLength);
-			memcpy(buffer, &descriptor.device, len);
-			break;
-		case USB_DT_CONFIG:
-			debug("USB_DT_CONFIG config\n");
-			len = min3(txlen, (int)descriptor.config.wTotalLength, (int)wLength);
-			memcpy(buffer, &descriptor.config, len);
-			break;
-		case USB_DT_STRING:
-			debug("USB_DT_STRING: %#x\n", wValue);
-			switch (wValue & 0xff) {
-			case 0: /* Language */
-				src = language_string;
-				len = strlen(src) + 2;
-				((char *)buffer)[0] = len;
-				((char *)buffer)[1] = 0x03;
-				memcpy(buffer + 2, src, strlen(src));
-				break;
-			case 1: /* Vendor */
-				src = vendor_string;
-				len = 2 * strlen(src) + 2;
-				strtodesc(buffer, src, len);
-				break;
-			case 2: /* Product */
-				src = product_string;
-				len = 2 * strlen(src) + 2;
-				strtodesc(buffer, src, len);
-				break;
-			default:
-				debug("%s(): unknown string index 0x%x\n", __func__, wValue & 0xff);
-				goto unknown;
-			}
-			len = min3(txlen, len, (int)wLength);
-			break;
-		default:
-			debug("%s(): unknown requesttype: 0x%x\n", __func__,
-			       cmd->requesttype & (USB_TYPE_MASK | USB_RECIP_MASK));
-			goto unknown;
-		}
-		break;
+	char *src, *str = buf;
+	__le16 *le16 = (__le16 *)(str + 2);
+	int size;
+
+	if (!buf || len < 2)
+		return -1;
 
-	case USB_RT_HUB:	/* USB_TYPE_CLASS | USB_RECIP_DEVICE */
-		debug("USB_RT_HUB\n");
+	switch (index) {
+	case 0: /* Language */
+		src = "\x09\x04";
+		size = strlen(src) + 2;
+		len = min_t(int, len, size);
 
-		len = min3(txlen, (int)descriptor.hub.bLength, (int)wLength);
-		memcpy(buffer, &descriptor.hub, len);
+		str[0] = size;
+		str[1] = 0x03;
+		memcpy(str + 2, src, len - 2);
+		break;
+	case 1: /* Vendor */
+		src = "u-boot";
+		size = 2 * strlen(src) + 2;
+		len = min_t(int, len, size);
+
+		str[0] = size;
+		str[1] = 0x03;
+		strle16(le16, src, (len - 2) / 2);
+		break;
+	case 2: /* Product */
+		src = "DWC2 root hub";
+		size = 2 * strlen(src) + 2;
+		len = min_t(int, len, size);
+
+		str[0] = size;
+		str[1] = 0x03;
+		strle16(le16, src, (len - 2) / 2);
 		break;
 	default:
-		goto unknown;
+		dwc2_err(dwc2, "roothub: unknown string descriptor: 0x%x\n",
+				index);
+		return -1;
 	}
 
 	dev->act_len = len;
 	dev->status = 0;
 
 	return 0;
-
-unknown:
-	dev->act_len = 0;
-	dev->status = USB_ST_STALLED;
-
-	return -1;
 }
 
-/* Direction: In ; Request: Configuration */
-static int dwc2_submit_rh_msg_in_configuration(struct usb_device *dev,
-					       void *buffer, int txlen,
-					       struct devrequest *cmd)
+static int dwc2_get_descriptor(struct dwc2 *dwc2, struct usb_device *dev,
+			       void *buf, int len, int value)
 {
-	int len = 0;
+	int index = value >> 8;
+
+	if (!buf || len < 0)
+		return -1;
 
-	switch (cmd->requesttype & (USB_TYPE_MASK | USB_RECIP_MASK)) {
-	case USB_TYPE_STANDARD | USB_RECIP_DEVICE:
-		*(uint8_t *)buffer = 0x01;
-		len = min(txlen, 1);
+	switch (index) {
+	case USB_DT_DEVICE:
+		len = min(len, (int)descriptor.device.bLength);
+		memcpy(buf, &descriptor.device, len);
 		break;
+	case USB_DT_CONFIG:
+		len = min(len, (int)descriptor.config.wTotalLength);
+		memcpy(buf, &descriptor.config, len);
+		break;
+	case USB_DT_STRING:
+		value &= 0xff;
+		return dwc2_get_string_descriptor(dwc2, dev, buf, len, value);
 	default:
-		goto unknown;
+		dwc2_err(dwc2, "roothub: unknown descriptor: 0x%x\n", index);
+		return -1;
 	}
 
 	dev->act_len = len;
 	dev->status = 0;
 
 	return 0;
-
-unknown:
-	dev->act_len = 0;
-	dev->status = USB_ST_STALLED;
-
-	return -1;
 }
 
-/* Direction: In */
-static int dwc2_submit_rh_msg_in(struct dwc2 *dwc2,
-				 struct usb_device *dev, void *buffer,
-				 int txlen, struct devrequest *cmd)
+static int dwc2_set_port_feature(struct dwc2 *dwc2, struct usb_device *dev,
+		int feature)
 {
-	switch (cmd->request) {
-	case USB_REQ_GET_STATUS:
-		return dwc2_submit_rh_msg_in_status(dwc2, dev, buffer,
-						       txlen, cmd);
-	case USB_REQ_GET_DESCRIPTOR:
-		return dwc2_submit_rh_msg_in_descriptor(dev, buffer,
-							   txlen, cmd);
-	case USB_REQ_GET_CONFIGURATION:
-		return dwc2_submit_rh_msg_in_configuration(dev, buffer,
-							      txlen, cmd);
-	default:
-		dev->act_len = 0;
-		dev->status = USB_ST_STALLED;
+	uint32_t hprt0;
+
+	hprt0 = dwc2_readl(dwc2, HPRT0);
+	hprt0 &= ~(HPRT0_ENA | HPRT0_CONNDET | HPRT0_ENACHG | HPRT0_OVRCURRCHG);
+
+	switch (feature) {
+	case USB_PORT_FEAT_SUSPEND:
+		break;
+	case USB_PORT_FEAT_RESET:
+		hprt0 |= HPRT0_RST;
+		dwc2_writel(dwc2, hprt0, HPRT0);
+
+		mdelay(60);
 
+		hprt0 = dwc2_readl(dwc2, HPRT0);
+		hprt0 &= ~HPRT0_RST;
+		dwc2_writel(dwc2, hprt0, HPRT0);
+		break;
+	case USB_PORT_FEAT_POWER:
+		break;
+	case USB_PORT_FEAT_ENABLE:
+		/* Set by the core after a reset */
+		break;
+	default:
+		dwc2_dbg(dwc2, "roothub: unsupported set port feature 0x%x\n",
+				feature);
 		return -1;
 	}
+
+	dev->act_len = 0;
+	dev->status = 0;
+
+	return 0;
 }
 
-/* Direction: Out */
-static int dwc2_submit_rh_msg_out(struct dwc2 *dwc2,
-				  struct usb_device *dev,
-				  void *buffer, int txlen,
-				  struct devrequest *cmd)
+static int dwc2_clear_port_feature(struct dwc2 *dwc2, struct usb_device *dev,
+		int feature)
 {
-	uint16_t wValue = le16_to_cpu(cmd->value);
 	uint32_t hprt0;
 
-	switch (cmd->requesttype & (USB_TYPE_MASK | USB_RECIP_MASK)) {
-	case USB_TYPE_STANDARD | USB_RECIP_DEVICE:
-		switch (cmd->request) {
-		case USB_REQ_SET_ADDRESS:
-			dwc2_dbg(dwc2, "set root hub addr %d\n", wValue);
-			dwc2->root_hub_devnum = wValue;
-			break;
-		case USB_REQ_SET_CONFIGURATION:
-			break;
-		default:
-			goto unknown;
-		}
+	hprt0 = dwc2_readl(dwc2, HPRT0);
+	hprt0 &= ~(HPRT0_ENA | HPRT0_CONNDET | HPRT0_ENACHG | HPRT0_OVRCURRCHG);
+
+	switch (feature) {
+	case USB_PORT_FEAT_ENABLE:
+		hprt0 |= HPRT0_ENA;
+		break;
+	case USB_PORT_FEAT_SUSPEND:
+		break;
+	case USB_PORT_FEAT_POWER:
 		break;
-	case USB_TYPE_STANDARD | USB_RECIP_ENDPOINT:
-	case USB_RT_HUB:	/* USB_TYPE_CLASS | USB_RECIP_DEVICE */
-		switch (cmd->request) {
-		case USB_REQ_CLEAR_FEATURE:
-			break;
-		}
+	case USB_PORT_FEAT_C_CONNECTION:
+		hprt0 |= HPRT0_CONNDET;
 		break;
-	case USB_RT_PORT:	/* USB_TYPE_CLASS | USB_RECIP_OTHER */
-		switch (cmd->request) {
-		case USB_REQ_CLEAR_FEATURE:
-			hprt0 = dwc2_readl(dwc2, HPRT0);
-			hprt0 &= ~(HPRT0_ENA | HPRT0_CONNDET
-				   | HPRT0_ENACHG | HPRT0_OVRCURRCHG);
-			switch (wValue) {
-			case USB_PORT_FEAT_ENABLE:
-				hprt0 |= HPRT0_ENA;
-				break;
-			case USB_PORT_FEAT_SUSPEND:
-				break;
-			case USB_PORT_FEAT_POWER:
-				break;
-			case USB_PORT_FEAT_C_CONNECTION:
-				hprt0 |= HPRT0_CONNDET;
-				break;
-			case USB_PORT_FEAT_C_ENABLE:
-				hprt0 |= HPRT0_ENACHG;
-				break;
-			case USB_PORT_FEAT_C_OVER_CURRENT:
-				hprt0 |= HPRT0_OVRCURRCHG;
-				break;
-			default:
-				dwc2_dbg(dwc2, "unknown feature 0x%x\n", wValue);
-				goto unknown;
-			}
-			dwc2_writel(dwc2, hprt0, HPRT0);
-			break;
-		case USB_REQ_SET_FEATURE:
-			hprt0 = dwc2_readl(dwc2, HPRT0);
-			hprt0 &= ~(HPRT0_ENA | HPRT0_CONNDET
-				   | HPRT0_ENACHG | HPRT0_OVRCURRCHG);
-			switch (wValue) {
-			case USB_PORT_FEAT_SUSPEND:
-				break;
-			case USB_PORT_FEAT_RESET:
-				hprt0 |= HPRT0_RST;
-				dwc2_writel(dwc2, hprt0, HPRT0);
-
-				mdelay(60);
-
-				hprt0 = dwc2_readl(dwc2, HPRT0);
-				hprt0 &= ~HPRT0_RST;
-				dwc2_writel(dwc2, hprt0, HPRT0);
-				break;
-			case USB_PORT_FEAT_POWER:
-				break;
-			case USB_PORT_FEAT_ENABLE:
-				/* Set by the core after a reset */
-				break;
-			default:
-				dwc2_dbg(dwc2, "unknown feature 0x%x\n", wValue);
-				goto unknown;
-			}
-			break;
-		default: goto unknown;
-		}
+	case USB_PORT_FEAT_C_ENABLE:
+		hprt0 |= HPRT0_ENACHG;
+		break;
+	case USB_PORT_FEAT_C_OVER_CURRENT:
+		hprt0 |= HPRT0_OVRCURRCHG;
 		break;
 	default:
-		goto unknown;
+		dwc2_dbg(dwc2, "roothub: unsupported clear port feature 0x%x\n",
+				feature);
+		return -1;
 	}
 
+	dwc2_writel(dwc2, hprt0, HPRT0);
+
 	dev->act_len = 0;
 	dev->status = 0;
 
 	return 0;
+}
+
+static int dwc2_set_address(struct dwc2 *dwc2, struct usb_device *dev, int addr)
+{
+	dwc2_dbg(dwc2, "roothub: set address to %d\n", addr);
+	dwc2->root_hub_devnum = addr;
 
-unknown:
 	dev->act_len = 0;
-	dev->status = USB_ST_STALLED;
-	return -1;
+	dev->status = 0;
+
+	return 0;
 }
 
-int
-dwc2_submit_rh_msg(struct dwc2 *dwc2, struct usb_device *dev,
-				 unsigned long pipe, void *buffer, int txlen,
-				 struct devrequest *cmd)
+int dwc2_submit_roothub(struct dwc2 *dwc2, struct usb_device *dev,
+		unsigned long pipe, void *buf, int len,
+		struct devrequest *setup)
 {
-	int stat = 0;
+	unsigned char reqtype = setup->requesttype;
+	unsigned char request = setup->request;
+	unsigned short value = le16_to_cpu(setup->value);
+	unsigned short size  = le16_to_cpu(setup->length);
+	int minlen = min_t(int, len, size);
 
 	if (usb_pipeint(pipe)) {
-		dwc2_err(dwc2, "Root-Hub submit IRQ: NOT implemented\n");
+		dwc2_err(dwc2, "roothub: submit IRQ NOT implemented\n");
 		return 0;
 	}
 
-	if (cmd->requesttype & USB_DIR_IN)
-		stat = dwc2_submit_rh_msg_in(dwc2, dev, buffer, txlen, cmd);
-	else
-		stat = dwc2_submit_rh_msg_out(dwc2, dev, buffer, txlen, cmd);
+	dev->act_len = 0;
+	dev->status = USB_ST_STALLED;
+
+#define REQ(l, u) ((l) | ((u) << 8))
+
+	switch (REQ(request, reqtype)) {
+	case REQ(USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB):
+		return dwc2_get_hub_descriptor(dwc2, dev, buf, minlen);
+
+	case REQ(USB_REQ_GET_DESCRIPTOR, USB_DIR_IN):
+		return dwc2_get_descriptor(dwc2, dev, buf, minlen, value);
+
+	case REQ(USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB):
+		return dwc2_get_hub_status(dwc2, dev, buf, len);
+
+	case REQ(USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT):
+		return dwc2_get_port_status(dwc2, dev, buf, len);
 
-	mdelay(1);
-	return stat;
+	case REQ(USB_REQ_SET_FEATURE, USB_DIR_OUT | USB_RT_PORT):
+		return dwc2_set_port_feature(dwc2, dev, value);
+
+	case REQ(USB_REQ_CLEAR_FEATURE, USB_DIR_OUT | USB_RT_PORT):
+		return dwc2_clear_port_feature(dwc2, dev, value);
+
+	case REQ(USB_REQ_SET_ADDRESS, USB_DIR_OUT):
+		return dwc2_set_address(dwc2, dev, value);
+
+	case REQ(USB_REQ_SET_CONFIGURATION, USB_DIR_OUT):
+		dev->act_len = 0;
+		dev->status = 0;
+		return 0;
+
+	case REQ(USB_REQ_GET_CONFIGURATION, USB_DIR_IN):
+		*(char *)buf = 1;
+		dev->act_len = 1;
+		dev->status = 0;
+		return 0;
+	}
+
+	dwc2_err(dwc2, "roothub: unsupported request 0x%x requesttype 0x%x\n",
+		 request, reqtype);
+
+	return 0;
 }
-- 
2.21.0.196.g041f5ea


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC PATCH 5/7] HACK: usb: dwc2: Fix toggle reset
  2020-01-14 13:21   ` [RFC PATCH 0/7] usb: " Jules Maselbas
                       ` (3 preceding siblings ...)
  2020-01-14 13:21     ` [RFC PATCH 4/7] usb: dwc2: Rework roothub interface Jules Maselbas
@ 2020-01-14 13:21     ` Jules Maselbas
  2020-01-14 13:21     ` [RFC PATCH 6/7] usb: dwc2: Rewrite dwc2_hc_init Jules Maselbas
                       ` (2 subsequent siblings)
  7 siblings, 0 replies; 24+ messages in thread
From: Jules Maselbas @ 2020-01-14 13:21 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: Barebox List, Jules Maselbas

From USB 2.0 specification, section 9.4.5:
ClearFeature(ENDPOINT_HALT) request always results in
the data toggle being reinitialized to DATA0.

Signed-off-by: Jules Maselbas <jmaselbas@kalray.eu>
---
 drivers/usb/dwc2/host.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/drivers/usb/dwc2/host.c b/drivers/usb/dwc2/host.c
index 2cde5977b..a97c7dac5 100644
--- a/drivers/usb/dwc2/host.c
+++ b/drivers/usb/dwc2/host.c
@@ -373,7 +373,24 @@ int dwc2_submit_control_msg(struct usb_device *udev,
 	if (ret)
 		return ret;
 
+	if (setup->requesttype == USB_RECIP_ENDPOINT
+	    && setup->request == USB_REQ_CLEAR_FEATURE) {
+		/* From USB 2.0, section 9.4.5:
+		 * ClearFeature(ENDPOINT_HALT) request always results
+		 * in the data toggle being reinitialized to DATA0.
+		 */
+		int ep = le16_to_cpu(setup->index & 0x7f);
+		int in = le16_to_cpu(setup->index & 0x80);
+		int data0 = TSIZ_SC_MC_PID_DATA0;
+
+		if (in)
+			dwc2->in_data_toggle[devnum][ep] = data0;
+		else
+			dwc2->out_data_toggle[devnum][ep] = data0;
+	}
+
 	udev->act_len = act_len;
+	udev->status = 0;
 
 	return 0;
 }
-- 
2.21.0.196.g041f5ea


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC PATCH 6/7] usb: dwc2: Rewrite dwc2_hc_init
  2020-01-14 13:21   ` [RFC PATCH 0/7] usb: " Jules Maselbas
                       ` (4 preceding siblings ...)
  2020-01-14 13:21     ` [RFC PATCH 5/7] HACK: usb: dwc2: Fix toggle reset Jules Maselbas
@ 2020-01-14 13:21     ` Jules Maselbas
  2020-01-14 13:21     ` [RFC PATCH 7/7] usb: dwc2: Read dr_mode from device tree Jules Maselbas
  2020-01-14 14:27     ` [RFC PATCH 0/7] usb: dwc2 host driver Sascha Hauer
  7 siblings, 0 replies; 24+ messages in thread
From: Jules Maselbas @ 2020-01-14 13:21 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: Barebox List, Jules Maselbas

Removed the uses of a table to convert the usb endpoint type for
the controller.

Signed-off-by: Jules Maselbas <jmaselbas@kalray.eu>
---
 drivers/usb/dwc2/host.c | 47 +++++++++++++++++++++++------------------
 1 file changed, 27 insertions(+), 20 deletions(-)

diff --git a/drivers/usb/dwc2/host.c b/drivers/usb/dwc2/host.c
index a97c7dac5..083c964e8 100644
--- a/drivers/usb/dwc2/host.c
+++ b/drivers/usb/dwc2/host.c
@@ -7,13 +7,6 @@
 /* Use only HC channel 0. */
 #define DWC2_HC_CHANNEL			0
 
-static int dwc2_eptype[] = {
-	DXEPCTL_EPTYPE_ISO,
-	DXEPCTL_EPTYPE_INTERRUPT,
-	DXEPCTL_EPTYPE_CONTROL,
-	DXEPCTL_EPTYPE_BULK,
-};
-
 static int dwc2_do_split(struct dwc2 *dwc2, struct usb_device *dev)
 {
 	uint32_t hprt0 = dwc2_readl(dwc2, HPRT0);
@@ -80,15 +73,32 @@ static void dwc2_hc_enable_ints(struct dwc2 *dwc2, uint8_t hc)
  * @param regs Programming view of DWC2 controller
  * @param hc Information needed to initialize the host channel
  */
-static void dwc2_hc_init(struct dwc2 *dwc2, uint8_t hc,
-		struct usb_device *dev, uint8_t dev_addr, uint8_t ep_num,
-		uint8_t ep_is_in, uint32_t ep_type, uint16_t max_packet)
+static void dwc2_hc_init(struct dwc2 *dwc2, struct usb_device *dev, u8 hc,
+			 unsigned long pipe, int is_in)
 {
-	uint32_t hcchar = (dev_addr << HCCHAR_DEVADDR_SHIFT) |
-			  (ep_num << HCCHAR_EPNUM_SHIFT) |
-			  (ep_is_in ? HCCHAR_EPDIR : 0) |
-			  ep_type |
-			  (max_packet << HCCHAR_MPS_SHIFT);
+	int addr = usb_pipedevice(pipe);
+	int endp = usb_pipeendpoint(pipe);
+	int type = usb_pipetype(pipe);
+	int mps = usb_maxpacket(dev, pipe);
+	uint32_t hcchar = (addr << HCCHAR_DEVADDR_SHIFT) |
+			  (endp << HCCHAR_EPNUM_SHIFT) |
+			  (is_in ? HCCHAR_EPDIR : 0) |
+			  (mps << HCCHAR_MPS_SHIFT);
+
+	switch (type) {
+	case PIPE_ISOCHRONOUS:
+		hcchar |= DXEPCTL_EPTYPE_ISO;
+		break;
+	case PIPE_INTERRUPT:
+		hcchar |= DXEPCTL_EPTYPE_INTERRUPT;
+		break;
+	case PIPE_CONTROL:
+		hcchar |= DXEPCTL_EPTYPE_CONTROL;
+		break;
+	case PIPE_BULK:
+		hcchar |= DXEPCTL_EPTYPE_BULK;
+		break;
+	}
 
 	if (dev->speed == USB_SPEED_LOW)
 		hcchar |= HCCHAR_LSPDDEV;
@@ -207,10 +217,7 @@ static int dwc2_submit_packet(struct dwc2 *dwc2, struct usb_device *dev,
 			      unsigned long pipe, u8 *pid, int in, void *buf,
 			      int len)
 {
-	int devnum = usb_pipedevice(pipe);
-	int ep = usb_pipeendpoint(pipe);
 	int mps = usb_maxpacket(dev, pipe);
-	int eptype = dwc2_eptype[usb_pipetype(pipe)];
 	int do_split = dwc2_do_split(dwc2, dev);
 	int complete_split = 0;
 	int done = 0;
@@ -231,7 +238,7 @@ static int dwc2_submit_packet(struct dwc2 *dwc2, struct usb_device *dev,
 	max_xfer_len = num_packets * mps;
 
 	/* Initialize channel */
-	dwc2_hc_init(dwc2, DWC2_HC_CHANNEL, dev, devnum, ep, in, eptype, mps);
+	dwc2_hc_init(dwc2, dev, DWC2_HC_CHANNEL, pipe, in);
 
 	/* Check if the target is a FS/LS device behind a HS hub */
 	if (do_split) {
@@ -262,7 +269,7 @@ static int dwc2_submit_packet(struct dwc2 *dwc2, struct usb_device *dev,
 			dwc2_writel(dwc2, hcsplt, HCSPLT(DWC2_HC_CHANNEL));
 		}
 
-		if (eptype == DXEPCTL_EPTYPE_INTERRUPT) {
+		if (usb_pipeint(pipe)) {
 			int uframe_num = dwc2_readl(dwc2, HFNUM);
 
 			if (!(uframe_num & 0x1))
-- 
2.21.0.196.g041f5ea


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC PATCH 7/7] usb: dwc2: Read dr_mode from device tree
  2020-01-14 13:21   ` [RFC PATCH 0/7] usb: " Jules Maselbas
                       ` (5 preceding siblings ...)
  2020-01-14 13:21     ` [RFC PATCH 6/7] usb: dwc2: Rewrite dwc2_hc_init Jules Maselbas
@ 2020-01-14 13:21     ` Jules Maselbas
  2020-01-14 14:27     ` [RFC PATCH 0/7] usb: dwc2 host driver Sascha Hauer
  7 siblings, 0 replies; 24+ messages in thread
From: Jules Maselbas @ 2020-01-14 13:21 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: Barebox List, Jules Maselbas

Signed-off-by: Jules Maselbas <jmaselbas@kalray.eu>
---
 drivers/usb/dwc2/core.c | 89 +++++++++++++++++++++++++++++++++++++++++
 drivers/usb/dwc2/dwc2.c |  2 +
 drivers/usb/dwc2/dwc2.h |  1 +
 3 files changed, 92 insertions(+)

diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
index 9a36b0904..94ff977bb 100644
--- a/drivers/usb/dwc2/core.c
+++ b/drivers/usb/dwc2/core.c
@@ -1,6 +1,33 @@
 // SPDX-License-Identifier: GPL-2.0+
 #include "dwc2.h"
 
+/* Returns the controller's GHWCFG2.OTG_MODE. */
+static unsigned int dwc2_op_mode(struct dwc2 *dwc2)
+{
+	u32 ghwcfg2 = dwc2_readl(dwc2, GHWCFG2);
+
+	return (ghwcfg2 & GHWCFG2_OP_MODE_MASK) >>
+		GHWCFG2_OP_MODE_SHIFT;
+}
+
+/* Returns true if the controller is host-only. */
+static bool dwc2_hw_is_host(struct dwc2 *dwc2)
+{
+	unsigned int op_mode = dwc2_op_mode(dwc2);
+
+	return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_HOST) ||
+		(op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST);
+}
+
+/* Returns true if the controller is device-only. */
+static bool dwc2_hw_is_device(struct dwc2 *dwc2)
+{
+	unsigned int op_mode = dwc2_op_mode(dwc2);
+
+	return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) ||
+		(op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE);
+}
+
 void dwc2_set_param_otg_cap(struct dwc2 *dwc2)
 {
 	u8 val;
@@ -493,6 +520,68 @@ void dwc2_gusbcfg_init(struct dwc2 *dwc2)
 	dwc2_writel(dwc2, usbcfg, GUSBCFG);
 }
 
+/*
+ * Check the dr_mode against the module configuration and hardware
+ * capabilities.
+ *
+ * The hardware, module, and dr_mode, can each be set to host, device,
+ * or otg. Check that all these values are compatible and adjust the
+ * value of dr_mode if possible.
+ *
+ *                      actual
+ *    HW  MOD dr_mode   dr_mode
+ *  ------------------------------
+ *   HST  HST  any    :  HST
+ *   HST  DEV  any    :  ---
+ *   HST  OTG  any    :  HST
+ *
+ *   DEV  HST  any    :  ---
+ *   DEV  DEV  any    :  DEV
+ *   DEV  OTG  any    :  DEV
+ *
+ *   OTG  HST  any    :  HST
+ *   OTG  DEV  any    :  DEV
+ *   OTG  OTG  any    :  dr_mode
+ */
+int dwc2_get_dr_mode(struct dwc2 *dwc2)
+{
+	enum usb_dr_mode mode;
+
+	mode = of_usb_get_dr_mode(dwc2->dev->device_node, NULL);
+	dwc2->dr_mode = mode;
+
+	if (dwc2_hw_is_device(dwc2)) {
+		if (IS_ENABLED(CONFIG_USB_DWC2_HOST)) {
+			dwc2_err(dwc2,
+				"Controller does not support host mode.\n");
+			return -EINVAL;
+		}
+		mode = USB_DR_MODE_PERIPHERAL;
+	} else if (dwc2_hw_is_host(dwc2)) {
+		if (IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL)) {
+			dwc2_err(dwc2,
+				"Controller does not support device mode.\n");
+			return -EINVAL;
+		}
+		mode = USB_DR_MODE_HOST;
+	} else {
+		if (IS_ENABLED(CONFIG_USB_DWC2_HOST))
+			mode = USB_DR_MODE_HOST;
+		else if (IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL))
+			mode = USB_DR_MODE_PERIPHERAL;
+	}
+
+	if (mode != dwc2->dr_mode) {
+		dwc2_warn(dwc2,
+			 "Configuration mismatch. dr_mode forced to %s\n",
+			mode == USB_DR_MODE_HOST ? "host" : "device");
+
+		dwc2->dr_mode = mode;
+	}
+
+	return 0;
+}
+
 /*
  * Do core a soft reset of the core.  Be careful with this because it
  * resets all the internal state machines of the core.
diff --git a/drivers/usb/dwc2/dwc2.c b/drivers/usb/dwc2/dwc2.c
index 893f573bc..1df393e77 100644
--- a/drivers/usb/dwc2/dwc2.c
+++ b/drivers/usb/dwc2/dwc2.c
@@ -62,6 +62,8 @@ static int dwc2_probe(struct device_d *dev)
 	/* Detect config values from hardware */
 	dwc2_get_hwparams(dwc2);
 
+	dwc2_get_dr_mode(dwc2);
+
 	dwc2_set_default_params(dwc2);
 
 	dma_set_mask(dev, DMA_BIT_MASK(32));
diff --git a/drivers/usb/dwc2/dwc2.h b/drivers/usb/dwc2/dwc2.h
index 0a4323ab4..35ba00660 100644
--- a/drivers/usb/dwc2/dwc2.h
+++ b/drivers/usb/dwc2/dwc2.h
@@ -21,6 +21,7 @@ void dwc2_flush_all_fifo(struct dwc2 *dwc2);
 int dwc2_phy_init(struct dwc2 *dwc2, bool select_phy);
 int dwc2_gahbcfg_init(struct dwc2 *dwc2);
 void dwc2_gusbcfg_init(struct dwc2 *dwc2);
+int dwc2_get_dr_mode(struct dwc2 *dwc2);
 
 int dwc2_core_reset(struct dwc2 *dwc2);
 void dwc2_core_init(struct dwc2 *dwc2);
-- 
2.21.0.196.g041f5ea


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC PATCH 0/7] usb: dwc2 host driver
  2020-01-14 13:21   ` [RFC PATCH 0/7] usb: " Jules Maselbas
                       ` (6 preceding siblings ...)
  2020-01-14 13:21     ` [RFC PATCH 7/7] usb: dwc2: Read dr_mode from device tree Jules Maselbas
@ 2020-01-14 14:27     ` Sascha Hauer
  2020-01-14 17:12       ` Jules Maselbas
  7 siblings, 1 reply; 24+ messages in thread
From: Sascha Hauer @ 2020-01-14 14:27 UTC (permalink / raw)
  To: Jules Maselbas; +Cc: Barebox List

Hi Jules,

On Tue, Jan 14, 2020 at 02:21:05PM +0100, Jules Maselbas wrote:
> Hi Sascha,
> 
> I've been working on a driver for the dwc2 otg controller, for both host
> and device mode.  Like you I've started from U-Boot driver and I mixed
> it with some part from Linux.  For instance I've removed the register
> structs and I've been using the same defines for register bit-fields as
> in Linux.
> 
> I would like to share my version of the host driver, as the gadget driver
> one still requires some cleanup.  This series is not to be applied on the
> driver you proposed. However I am willing to propose a new series that can
> be applied on the driver you proposed.  What do you think?

The dwc2 driver was a quick shot, I am all in for improvements. Removing
the register structs is very nice and I would be interested in gadget
support as well.

What SoC are you using the driver on?

I am not sure if it makes sense to rebase your patches on my driver. If
you can convince me that yours is better then we could just remove mine
and merge yours instead.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC PATCH 0/7] usb: dwc2 host driver
  2020-01-14 14:27     ` [RFC PATCH 0/7] usb: dwc2 host driver Sascha Hauer
@ 2020-01-14 17:12       ` Jules Maselbas
  2020-01-16  6:50         ` Sascha Hauer
  0 siblings, 1 reply; 24+ messages in thread
From: Jules Maselbas @ 2020-01-14 17:12 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: Barebox List

On Tue, Jan 14, 2020 at 03:27:04PM +0100, Sascha Hauer wrote:
> Hi Jules,
> 
> On Tue, Jan 14, 2020 at 02:21:05PM +0100, Jules Maselbas wrote:
> > Hi Sascha,
> > 
> > I've been working on a driver for the dwc2 otg controller, for both host
> > and device mode.  Like you I've started from U-Boot driver and I mixed
> > it with some part from Linux.  For instance I've removed the register
> > structs and I've been using the same defines for register bit-fields as
> > in Linux.
> > 
> > I would like to share my version of the host driver, as the gadget driver
> > one still requires some cleanup.  This series is not to be applied on the
> > driver you proposed. However I am willing to propose a new series that can
> > be applied on the driver you proposed.  What do you think?
> 
> The dwc2 driver was a quick shot, I am all in for improvements. Removing
> the register structs is very nice and I would be interested in gadget
> support as well.
The gadget support is almost ready, I got the dfu gadget working. :) 
 
> What SoC are you using the driver on?
I am using this driver on our custom SoC, the Kalray Coolidge MPPA (k1c).
I didn't tried on other SoC.

> I am not sure if it makes sense to rebase your patches on my driver. If
> you can convince me that yours is better then we could just remove mine
> and merge yours instead.
I don't have a strong argument in favor of my version. Except that I have
already made some changes over the original U-Boot version: 

I've tried to improve the roothub interface making it easier to decode
new requests.

I have removed the memcpy done in transfer_chunk between the usb data
buffer and the dma buffer :/
However this mean that all buffer used for usb tranfert must be dma
capable.  Not all usb transfers use dma_alloc for it's buffers but
sometime they are allocated on the stack, this can be problematic if
the stack cannot be used by DMA.

I also have fixed an error in the handling of the toggle bit, but I
think the solution is a bit hacky. I think the driver should rather
use the toggle bit stored in the usb_device structure, but this will
require more rework.

If theses changes make sense then let's use this version.

Best,
Jules

> Sascha
> 
> -- 
> Pengutronix e.K.                           |                             |
> Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
> 31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC PATCH 0/7] usb: dwc2 host driver
  2020-01-14 17:12       ` Jules Maselbas
@ 2020-01-16  6:50         ` Sascha Hauer
  2020-01-16 17:25           ` Jules Maselbas
  0 siblings, 1 reply; 24+ messages in thread
From: Sascha Hauer @ 2020-01-16  6:50 UTC (permalink / raw)
  To: Matthias Mann; +Cc: Barebox List

On Tue, Jan 14, 2020 at 06:12:26PM +0100, Jules Maselbas wrote:
> On Tue, Jan 14, 2020 at 03:27:04PM +0100, Sascha Hauer wrote:
> > Hi Jules,
> > 
> > On Tue, Jan 14, 2020 at 02:21:05PM +0100, Jules Maselbas wrote:
> > > Hi Sascha,
> > > 
> > > I've been working on a driver for the dwc2 otg controller, for both host
> > > and device mode.  Like you I've started from U-Boot driver and I mixed
> > > it with some part from Linux.  For instance I've removed the register
> > > structs and I've been using the same defines for register bit-fields as
> > > in Linux.
> > > 
> > > I would like to share my version of the host driver, as the gadget driver
> > > one still requires some cleanup.  This series is not to be applied on the
> > > driver you proposed. However I am willing to propose a new series that can
> > > be applied on the driver you proposed.  What do you think?
> > 
> > The dwc2 driver was a quick shot, I am all in for improvements. Removing
> > the register structs is very nice and I would be interested in gadget
> > support as well.
> The gadget support is almost ready, I got the dfu gadget working. :)

Well, USB gadget support would be a strong argument for your version ;)

>  
> > What SoC are you using the driver on?
> I am using this driver on our custom SoC, the Kalray Coolidge MPPA (k1c).
> I didn't tried on other SoC.
> 
> > I am not sure if it makes sense to rebase your patches on my driver. If
> > you can convince me that yours is better then we could just remove mine
> > and merge yours instead.
> I don't have a strong argument in favor of my version. Except that I have
> already made some changes over the original U-Boot version: 
> 
> I've tried to improve the roothub interface making it easier to decode
> new requests.
> 
> I have removed the memcpy done in transfer_chunk between the usb data
> buffer and the dma buffer :/
> However this mean that all buffer used for usb tranfert must be dma
> capable.  Not all usb transfers use dma_alloc for it's buffers but
> sometime they are allocated on the stack, this can be problematic if
> the stack cannot be used by DMA.

We do this on other controllers as well, so this shouldn't be a problem.
The day will come we either have to fix the callers or create some
bounce buffer implementation for non DMA capable memory.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC PATCH 0/7] usb: dwc2 host driver
  2020-01-16  6:50         ` Sascha Hauer
@ 2020-01-16 17:25           ` Jules Maselbas
  2020-01-21 13:32             ` Michael Grzeschik
  0 siblings, 1 reply; 24+ messages in thread
From: Jules Maselbas @ 2020-01-16 17:25 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: Barebox List, Matthias Mann

On Thu, Jan 16, 2020 at 07:50:27AM +0100, Sascha Hauer wrote:
> 
> Well, USB gadget support would be a strong argument for your version ;)
I am going to send a new version for the host driver alongside the gadget
support. I've made few cleanup (in both host and gadget driver). Although
there is still some stub functions in the gadget driver, I think is this
a good start.

cheers,
Jules

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC PATCH 0/7] usb: dwc2 host driver
  2020-01-16 17:25           ` Jules Maselbas
@ 2020-01-21 13:32             ` Michael Grzeschik
  0 siblings, 0 replies; 24+ messages in thread
From: Michael Grzeschik @ 2020-01-21 13:32 UTC (permalink / raw)
  To: Jules Maselbas; +Cc: Barebox List, Matthias Mann


[-- Attachment #1.1: Type: text/plain, Size: 1077 bytes --]

Hi Jules,

On Thu, Jan 16, 2020 at 06:25:08PM +0100, Jules Maselbas wrote:
> On Thu, Jan 16, 2020 at 07:50:27AM +0100, Sascha Hauer wrote:
> > 
> > Well, USB gadget support would be a strong argument for your version ;)
> I am going to send a new version for the host driver alongside the gadget
> support. I've made few cleanup (in both host and gadget driver). Although
> there is still some stub functions in the gadget driver, I think is this
> a good start.

I did not get this conversation and also started the gadget support on
dwc2. My target machine is stm32, so my work includes also the internal
stm32 phy and some regulators, to get this done. I could rework this on
top of your patches, if you send them on the list.

Regards,
Michael

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

[-- Attachment #2: Type: text/plain, Size: 149 bytes --]

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2020-01-21 13:32 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-12-20 14:32 [PATCH 00/10] Add Raspberry Pi USB support Sascha Hauer
2019-12-20 14:32 ` [PATCH 01/10] usb: Make timeout unit clear Sascha Hauer
2019-12-20 14:32 ` [PATCH 02/10] of: Add of_bus_n_xxx_cells() Sascha Hauer
2019-12-20 14:32 ` [PATCH 03/10] device: Introduce dma_offset Sascha Hauer
2019-12-20 14:32 ` [PATCH 04/10] of: Read dma_offset from device tree Sascha Hauer
2019-12-20 14:32 ` [PATCH 05/10] usb: Add usbroothubdes.h Sascha Hauer
2019-12-20 14:32 ` [PATCH 06/10] regulator: add function to get regulator by its name Sascha Hauer
2019-12-20 14:32 ` [PATCH 07/10] rpi: Enable USB Power domain during startup Sascha Hauer
2019-12-20 14:32 ` [PATCH 08/10] usb: Forward error code from usb_set_configuration Sascha Hauer
2019-12-20 14:32 ` [PATCH 09/10] usb: Add dwc2 host driver Sascha Hauer
2020-01-14 13:21   ` [RFC PATCH 0/7] usb: " Jules Maselbas
2020-01-14 13:21     ` [RFC PATCH 1/7] usb: dwc2: Add host controller driver Jules Maselbas
2020-01-14 13:21     ` [RFC PATCH 2/7] usb: dwc2: host: Handle dma mapping errors Jules Maselbas
2020-01-14 13:21     ` [RFC PATCH 3/7] usb: dwc2: Dynamic fifo size support from Linux Jules Maselbas
2020-01-14 13:21     ` [RFC PATCH 4/7] usb: dwc2: Rework roothub interface Jules Maselbas
2020-01-14 13:21     ` [RFC PATCH 5/7] HACK: usb: dwc2: Fix toggle reset Jules Maselbas
2020-01-14 13:21     ` [RFC PATCH 6/7] usb: dwc2: Rewrite dwc2_hc_init Jules Maselbas
2020-01-14 13:21     ` [RFC PATCH 7/7] usb: dwc2: Read dr_mode from device tree Jules Maselbas
2020-01-14 14:27     ` [RFC PATCH 0/7] usb: dwc2 host driver Sascha Hauer
2020-01-14 17:12       ` Jules Maselbas
2020-01-16  6:50         ` Sascha Hauer
2020-01-16 17:25           ` Jules Maselbas
2020-01-21 13:32             ` Michael Grzeschik
2019-12-20 14:32 ` [PATCH 10/10] ARM: rpi_defconfig: Enable networking support Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox