mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 00/25] i.MX8MQ USB support
@ 2019-02-20  7:29 Andrey Smirnov
  2019-02-20  7:29 ` [PATCH 01/25] usb: xhci-hcd: Tabify the file Andrey Smirnov
                   ` (25 more replies)
  0 siblings, 26 replies; 30+ messages in thread
From: Andrey Smirnov @ 2019-02-20  7:29 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Everyone:

This series contains changes I made while working on adding USB
support for ZII i.MX8MQ boards. There are several distinct parts in
this series:

 1. xHCI fixes, features and improvements
 2. PHY driver deferral support
 3. i.MX8MQ USB PHY driver
 4. DWC3 USB support and related patches
 5. USB251x USB hub and related patches

First four are neccessary for i.MX8MQ in general and last part is ZII
specific only. Hopefully all patches are self explanatory.

Tested on ZII i.MX8MQ boards.

Feedback is welcome!

Thanks,
Andrey Smirnov

Andrey Smirnov (25):
  usb: xhci-hcd: Tabify the file
  usb: xhci-hcd: Do not zero out DMA coherent memory
  usb: xhci-hcd: Cast ~XHCI_IRQS to u32
  usb: xhci-hcd: Make sure to initialize xhci->rings_list
  usb: xhci-hcd: Drop pointless bitwise or
  usb: xhci-hcd: Add support for 64-byte context size
  usb: xhci-hcd: Don't try to DMA sync if buffer is NULL
  usb: xhci-hcd: Always wait for "Response Data" completion
  usb: xhci-hcd: Convert xhci_submit_normal() to use dma_map_single()
  usb: xhci-hcd: Convert xhci_submit_control() to use dma_map_single()
  usb: xhci-hcd: Simplify TRB initialization code
  usb: xhci-hcd: Drop 'dma' field from struct xhci_hcd
  usb: xhci-hcd: Check usb_pipein(pipe) only once in
    xhci_submit_normal()
  usb: xhci-hcd: Initialize TRT flag for xHCI >= 1.0
  usb: xhci-hcd: Simplify route string building loop
  usb: xhci-hcd: Make use of lo_hi_readq/writeq()
  phy: core: Assume EPROBE_DEFER in of_phy_provider_lookup()
  phy: Port i.MX8MQ USB PHY driver from Linux
  clk: Drop separate definitions of clk_put()
  include/usb: Import USB_SPEED_SUPER_PLUS from Linux
  clk: Import a subset of clk_bulk API from Linux
  usb: Import DWC3 USB controller driver from Linux
  lib: Port basic Linux kernel NLS functions
  usb: Port Microchip USB251x USB hub driver from Linux
  usb: usb251xb: add usb data lane port swap feature

 drivers/clk/Makefile                       |    3 +-
 drivers/clk/clk-bulk.c                     |  102 ++
 drivers/clk/clkdev.c                       |    5 -
 drivers/phy/Kconfig                        |    2 +
 drivers/phy/Makefile                       |    1 +
 drivers/phy/freescale/Kconfig              |    4 +
 drivers/phy/freescale/Makefile             |    1 +
 drivers/phy/freescale/phy-fsl-imx8mq-usb.c |  130 ++
 drivers/phy/phy-core.c                     |    4 +-
 drivers/usb/Kconfig                        |    4 +
 drivers/usb/Makefile                       |    2 +
 drivers/usb/dwc3/Kconfig                   |   22 +
 drivers/usb/dwc3/Makefile                  |   10 +
 drivers/usb/dwc3/core.c                    |  740 ++++++++++++
 drivers/usb/dwc3/core.h                    | 1267 ++++++++++++++++++++
 drivers/usb/dwc3/debug.h                   |  664 ++++++++++
 drivers/usb/dwc3/host.c                    |   36 +
 drivers/usb/dwc3/io.h                      |   41 +
 drivers/usb/host/xhci-hcd.c                |  549 +++++----
 drivers/usb/host/xhci.h                    |   51 +-
 drivers/usb/misc/Kconfig                   |   14 +
 drivers/usb/misc/Makefile                  |    6 +
 drivers/usb/misc/usb251xb.c                |  683 +++++++++++
 include/linux/clk.h                        |  107 +-
 include/linux/nls.h                        |   40 +
 include/usb/ch9.h                          |    1 +
 lib/Kconfig                                |    3 +
 lib/Makefile                               |    1 +
 lib/nls_base.c                             |  131 ++
 29 files changed, 4377 insertions(+), 247 deletions(-)
 create mode 100644 drivers/clk/clk-bulk.c
 create mode 100644 drivers/phy/freescale/Kconfig
 create mode 100644 drivers/phy/freescale/Makefile
 create mode 100644 drivers/phy/freescale/phy-fsl-imx8mq-usb.c
 create mode 100644 drivers/usb/dwc3/Kconfig
 create mode 100644 drivers/usb/dwc3/Makefile
 create mode 100644 drivers/usb/dwc3/core.c
 create mode 100644 drivers/usb/dwc3/core.h
 create mode 100644 drivers/usb/dwc3/debug.h
 create mode 100644 drivers/usb/dwc3/host.c
 create mode 100644 drivers/usb/dwc3/io.h
 create mode 100644 drivers/usb/misc/Kconfig
 create mode 100644 drivers/usb/misc/Makefile
 create mode 100644 drivers/usb/misc/usb251xb.c
 create mode 100644 include/linux/nls.h
 create mode 100644 lib/nls_base.c

-- 
2.20.1


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

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

* [PATCH 01/25] usb: xhci-hcd: Tabify the file
  2019-02-20  7:29 [PATCH 00/25] i.MX8MQ USB support Andrey Smirnov
@ 2019-02-20  7:29 ` Andrey Smirnov
  2019-02-20  7:29 ` [PATCH 02/25] usb: xhci-hcd: Do not zero out DMA coherent memory Andrey Smirnov
                   ` (24 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Andrey Smirnov @ 2019-02-20  7:29 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Replace occasional all-whiltespace indentation with tabs for
consistency.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/host/xhci-hcd.c | 136 ++++++++++++++++++------------------
 1 file changed, 68 insertions(+), 68 deletions(-)

diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index 2b808cc87..7cfd74de4 100644
--- a/drivers/usb/host/xhci-hcd.c
+++ b/drivers/usb/host/xhci-hcd.c
@@ -29,10 +29,10 @@
 
 static int xhci_ring_is_last_trb(struct xhci_ring *ring, union xhci_trb *trb)
 {
-        if (ring->type == TYPE_EVENT)
-                return trb == &ring->trbs[NUM_EVENT_TRBS];
-        else
-                return TRB_TYPE_LINK(le32_to_cpu(trb->link.control));
+	if (ring->type == TYPE_EVENT)
+		return trb == &ring->trbs[NUM_EVENT_TRBS];
+	else
+		return TRB_TYPE_LINK(le32_to_cpu(trb->link.control));
 }
 
 static int xhci_ring_increment(struct xhci_ring *ring, bool enqueue)
@@ -41,7 +41,7 @@ static int xhci_ring_increment(struct xhci_ring *ring, bool enqueue)
 
 	(*queue)++;
 
-        if (!xhci_ring_is_last_trb(ring, *queue))
+	if (!xhci_ring_is_last_trb(ring, *queue))
 		return 0;
 
 	if (ring->type == TYPE_EVENT) {
@@ -139,15 +139,15 @@ static unsigned int xhci_get_endpoint_index(u8 epaddress, u8 epattributes)
 {
 	u8 epnum = epaddress & USB_ENDPOINT_NUMBER_MASK;
 	u8 xfer = epattributes & USB_ENDPOINT_XFERTYPE_MASK;
-        unsigned int index;
+	unsigned int index;
 
-        if (xfer == USB_ENDPOINT_XFER_CONTROL)
-                index = (unsigned int)(epnum * 2);
-        else
-                index = (unsigned int)(epnum * 2) +
-                        ((epaddress & USB_DIR_IN) ? 1 : 0) - 1;
+	if (xfer == USB_ENDPOINT_XFER_CONTROL)
+		index = (unsigned int)(epnum * 2);
+	else
+		index = (unsigned int)(epnum * 2) +
+			((epaddress & USB_DIR_IN) ? 1 : 0) - 1;
 
-        return index;
+	return index;
 }
 
 static u8 xhci_get_endpoint_type(u8 epaddress, u8 epattributes)
@@ -341,15 +341,15 @@ int xhci_issue_command(struct xhci_hcd *xhci, union xhci_trb *trb)
 
 static void xhci_set_event_dequeue(struct xhci_hcd *xhci)
 {
-        u64 reg64;
+	u64 reg64;
 
-        reg64 = xhci_read_64(&xhci->ir_set->erst_dequeue);
-        reg64 &= ERST_PTR_MASK;
-        /*
+	reg64 = xhci_read_64(&xhci->ir_set->erst_dequeue);
+	reg64 &= ERST_PTR_MASK;
+	/*
 	 * Don't clear the EHB bit (which is RW1C) because
-         * there might be more events to service.
-         */
-        reg64 &= ~ERST_EHB;
+	 * there might be more events to service.
+	 */
+	reg64 &= ~ERST_EHB;
 	reg64 |= (dma_addr_t)xhci->event_ring.dequeue &
 		~(dma_addr_t)ERST_PTR_MASK;
 
@@ -489,16 +489,16 @@ static void xhci_virtdev_zero_in_ctx(struct xhci_virtual_device *vdev)
 {
 	int i;
 
-        /* When a device's add flag and drop flag are zero, any subsequent
-         * configure endpoint command will leave that endpoint's state
-         * untouched.  Make sure we don't leave any old state in the input
-         * endpoint contexts.
-         */
-        vdev->in_ctx->icc.drop_flags = 0;
-        vdev->in_ctx->icc.add_flags = 0;
-        vdev->in_ctx->slot.dev_info &= cpu_to_le32(~LAST_CTX_MASK);
-        /* Endpoint 0 is always valid */
-        vdev->in_ctx->slot.dev_info |= cpu_to_le32(LAST_CTX(1));
+	/* When a device's add flag and drop flag are zero, any subsequent
+	 * configure endpoint command will leave that endpoint's state
+	 * untouched.  Make sure we don't leave any old state in the input
+	 * endpoint contexts.
+	 */
+	vdev->in_ctx->icc.drop_flags = 0;
+	vdev->in_ctx->icc.add_flags = 0;
+	vdev->in_ctx->slot.dev_info &= cpu_to_le32(~LAST_CTX_MASK);
+	/* Endpoint 0 is always valid */
+	vdev->in_ctx->slot.dev_info |= cpu_to_le32(LAST_CTX(1));
 	for (i = 1; i < 31; i++) {
 		vdev->in_ctx->ep[i].ep_info = 0;
 		vdev->in_ctx->ep[i].ep_info2 = 0;
@@ -522,7 +522,7 @@ static int xhci_virtdev_disable_slot(struct xhci_virtual_device *vdev)
 	ret = xhci_wait_for_event(xhci, TRB_COMPLETION, &trb);
 	xhci_print_trb(xhci, &trb, "Response DisableSlot");
 
-        /* Clear Device Context Base Address Array */
+	/* Clear Device Context Base Address Array */
 	xhci->dcbaa[vdev->slot_id] = 0;
 
 	return ret;
@@ -565,7 +565,7 @@ int xhci_virtdev_reset(struct xhci_virtual_device *vdev)
 	/* If device is not setup, there is no point in resetting it */
 	if (GET_SLOT_STATE(le32_to_cpu(vdev->out_ctx->slot.dev_state)) ==
 	    SLOT_STATE_DISABLED)
-                return 0;
+		return 0;
 
 	memset(&trb, 0, sizeof(union xhci_trb));
 	trb.event_cmd.flags = TRB_TYPE(TRB_RESET_DEV) |
@@ -575,26 +575,26 @@ int xhci_virtdev_reset(struct xhci_virtual_device *vdev)
 	ret = xhci_wait_for_event(xhci, TRB_COMPLETION, &trb);
 	xhci_print_trb(xhci, &trb, "Response Reset");
 
-        /*
+	/*
 	 * The Reset Device command can't fail, according to the 0.95/0.96 spec,
-         * unless we tried to reset a slot ID that wasn't enabled,
-         * or the device wasn't in the addressed or configured state.
-         */
-        switch (GET_COMP_CODE(trb.event_cmd.status)) {
-        case COMP_CMD_ABORT:
-        case COMP_CMD_STOP:
-                dev_warn(xhci->dev, "Timeout waiting for reset device command\n");
-                ret = -ETIMEDOUT;
+	 * unless we tried to reset a slot ID that wasn't enabled,
+	 * or the device wasn't in the addressed or configured state.
+	 */
+	switch (GET_COMP_CODE(trb.event_cmd.status)) {
+	case COMP_CMD_ABORT:
+	case COMP_CMD_STOP:
+		dev_warn(xhci->dev, "Timeout waiting for reset device command\n");
+		ret = -ETIMEDOUT;
+		break;
+	case COMP_EBADSLT: /* 0.95 completion code for bad slot ID */
+	case COMP_CTX_STATE: /* 0.96 completion code for same thing */
+		/* Don't treat this as an error.  May change my mind later. */
+		ret = 0;
+	case COMP_SUCCESS:
 		break;
-        case COMP_EBADSLT: /* 0.95 completion code for bad slot ID */
-        case COMP_CTX_STATE: /* 0.96 completion code for same thing */
-                /* Don't treat this as an error.  May change my mind later. */
-                ret = 0;
-        case COMP_SUCCESS:
-                break;
-        default:
-                ret = -EINVAL;
-        }
+	default:
+		ret = -EINVAL;
+	}
 
 	return ret;
 }
@@ -651,14 +651,14 @@ static int xhci_virtdev_update_hub_device(struct xhci_virtual_device *vdev,
 		if (xhci->hci_version < 0x100 ||
 		    vdev->udev->speed == USB_SPEED_HIGH) {
 			u32 think_time = (hubchar & HUB_CHAR_TTTT) >> 5;
-                        tt_info |= TT_THINK_TIME(think_time);
+			tt_info |= TT_THINK_TIME(think_time);
 		}
-        }
+	}
 	vdev->in_ctx->slot.dev_info = cpu_to_le32(dev_info);
 	vdev->in_ctx->slot.dev_info2 = cpu_to_le32(dev_info2);
 	vdev->in_ctx->slot.tt_info = cpu_to_le32(tt_info);
 
-        /* Issue Configure Endpoint or Evaluate Context Command */
+	/* Issue Configure Endpoint or Evaluate Context Command */
 	memset(&trb, 0, sizeof(union xhci_trb));
 	xhci_write_64((dma_addr_t)vdev->in_ctx, &trb.event_cmd.cmd_trb);
 	trb.event_cmd.flags = SLOT_ID_FOR_TRB(vdev->slot_id);
@@ -782,21 +782,21 @@ static int xhci_virtdev_configure(struct xhci_virtual_device *vdev, int config)
 
 	last_ctx = fls(add_flags) - 1;
 
-        /* See section 4.6.6 - A0 = 1; A1 = D0 = D1 = 0 */
+	/* See section 4.6.6 - A0 = 1; A1 = D0 = D1 = 0 */
 	vdev->in_ctx->icc.add_flags = cpu_to_le32(add_flags);
-        vdev->in_ctx->icc.add_flags |= cpu_to_le32(SLOT_FLAG);
-        vdev->in_ctx->icc.add_flags &= cpu_to_le32(~EP0_FLAG);
-        vdev->in_ctx->icc.drop_flags &= cpu_to_le32(~(SLOT_FLAG | EP0_FLAG));
+	vdev->in_ctx->icc.add_flags |= cpu_to_le32(SLOT_FLAG);
+	vdev->in_ctx->icc.add_flags &= cpu_to_le32(~EP0_FLAG);
+	vdev->in_ctx->icc.drop_flags &= cpu_to_le32(~(SLOT_FLAG | EP0_FLAG));
 
 	/* Don't issue the command if there's no endpoints to update. */
-        if (vdev->in_ctx->icc.add_flags == cpu_to_le32(SLOT_FLAG) &&
-            vdev->in_ctx->icc.drop_flags == 0)
+	if (vdev->in_ctx->icc.add_flags == cpu_to_le32(SLOT_FLAG) &&
+	    vdev->in_ctx->icc.drop_flags == 0)
 		return 0;
 
 	vdev->in_ctx->slot.dev_info &= cpu_to_le32(~LAST_CTX_MASK);
 	vdev->in_ctx->slot.dev_info |= cpu_to_le32(LAST_CTX(last_ctx));
 
-        /* Issue Configure Endpoint Command */
+	/* Issue Configure Endpoint Command */
 	memset(&trb, 0, sizeof(union xhci_trb));
 	xhci_write_64((dma_addr_t)vdev->in_ctx, &trb.event_cmd.cmd_trb);
 	trb.event_cmd.flags = TRB_TYPE(TRB_CONFIG_EP) |
@@ -816,7 +816,7 @@ static int xhci_virtdev_deconfigure(struct xhci_virtual_device *vdev)
 	union xhci_trb trb;
 	int ret;
 
-        /* Issue Deconfigure Endpoint Command */
+	/* Issue Deconfigure Endpoint Command */
 	memset(&trb, 0, sizeof(union xhci_trb));
 	xhci_write_64((dma_addr_t)vdev->in_ctx, &trb.event_cmd.cmd_trb);
 	trb.event_cmd.flags = TRB_TYPE(TRB_CONFIG_EP) | TRB_DC |
@@ -912,7 +912,7 @@ static int xhci_virtdev_init(struct xhci_virtual_device *vdev)
 	vdev->in_ctx->ep[0].deq = cpu_to_le64((dma_addr_t)vdev->ep[0]->enqueue |
 					      vdev->ep[0]->cycle_state);
 
-        /* 4.3.3 6+7) Initalize and Set Device Context Base Address Array */
+	/* 4.3.3 6+7) Initalize and Set Device Context Base Address Array */
 	xhci->dcbaa[vdev->slot_id] = cpu_to_le64((dma_addr_t)vdev->out_ctx);
 
 	return 0;
@@ -952,7 +952,7 @@ static int xhci_virtdev_setup(struct xhci_virtual_device *vdev,
 	vdev->in_ctx->icc.add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG);
 	vdev->in_ctx->icc.drop_flags = 0;
 
-        /* Issue Address Device Command */
+	/* Issue Address Device Command */
 	memset(&trb, 0, sizeof(union xhci_trb));
 	xhci_write_64((dma_addr_t)vdev->in_ctx, &trb.event_cmd.cmd_trb);
 	trb.event_cmd.flags = TRB_TYPE(TRB_ADDR_DEV) |
@@ -970,12 +970,12 @@ static int xhci_virtdev_setup(struct xhci_virtual_device *vdev,
 
 static int xhci_virtdev_set_address(struct xhci_virtual_device *vdev)
 {
-        return xhci_virtdev_setup(vdev, SETUP_CONTEXT_ADDRESS);
+	return xhci_virtdev_setup(vdev, SETUP_CONTEXT_ADDRESS);
 }
 
 static int xhci_virtdev_enable(struct xhci_virtual_device *vdev)
 {
-        return xhci_virtdev_setup(vdev, SETUP_CONTEXT_ONLY);
+	return xhci_virtdev_setup(vdev, SETUP_CONTEXT_ONLY);
 }
 
 static int xhci_virtdev_attach(struct xhci_hcd *xhci, struct usb_device *udev)
@@ -1291,7 +1291,7 @@ static int xhci_reset(struct xhci_hcd *xhci)
 		return ret;
 	}
 
-        return 0;
+	return 0;
 }
 
 static int xhci_start(struct xhci_hcd *xhci)
@@ -1305,8 +1305,8 @@ static int xhci_start(struct xhci_hcd *xhci)
 
 	ret = xhci_handshake(&xhci->op_regs->status,
 			     STS_HALT, 0, XHCI_MAX_HALT_USEC);
-        if (ret) {
-                dev_err(xhci->dev, "failed to start\n");
+	if (ret) {
+		dev_err(xhci->dev, "failed to start\n");
 		return ret;
 	}
 
@@ -1314,7 +1314,7 @@ static int xhci_start(struct xhci_hcd *xhci)
 	for (i = 0; i < xhci->num_usb_ports; i++)
 		xhci_hub_port_power(xhci, i, false);
 
-        return 0;
+	return 0;
 }
 
 static int xhci_init(struct usb_host *host)
-- 
2.20.1


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

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

* [PATCH 02/25] usb: xhci-hcd: Do not zero out DMA coherent memory
  2019-02-20  7:29 [PATCH 00/25] i.MX8MQ USB support Andrey Smirnov
  2019-02-20  7:29 ` [PATCH 01/25] usb: xhci-hcd: Tabify the file Andrey Smirnov
@ 2019-02-20  7:29 ` Andrey Smirnov
  2019-02-20  9:29   ` Yann Sionneau
  2019-02-20  7:29 ` [PATCH 03/25] usb: xhci-hcd: Cast ~XHCI_IRQS to u32 Andrey Smirnov
                   ` (23 subsequent siblings)
  25 siblings, 1 reply; 30+ messages in thread
From: Andrey Smirnov @ 2019-02-20  7:29 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Memory returned by dma_alloc_coherent() should already be zeroed
out, so there's no need to do this explicitly.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/host/xhci-hcd.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index 7cfd74de4..7106a5637 100644
--- a/drivers/usb/host/xhci-hcd.c
+++ b/drivers/usb/host/xhci-hcd.c
@@ -445,7 +445,6 @@ static struct xhci_virtual_device *xhci_alloc_virtdev(struct xhci_hcd *xhci,
 
 	vdev->dma_size = sz_ictx + sz_dctx;
 	p = vdev->dma = dma_alloc_coherent(vdev->dma_size, DMA_ADDRESS_BROKEN);
-	memset(vdev->dma, 0, vdev->dma_size);
 
 	vdev->out_ctx = p; p += sz_dctx;
 	vdev->in_ctx = p; p += sz_ictx;
@@ -1225,7 +1224,6 @@ static void xhci_dma_alloc(struct xhci_hcd *xhci)
 	xhci->dma_size += num_ep * sz_ep;
 
 	p = xhci->dma = dma_alloc_coherent(xhci->dma_size, DMA_ADDRESS_BROKEN);
-	memset(xhci->dma, 0, xhci->dma_size);
 
 	xhci->sp = p; p += sz_sp;
 	xhci->dcbaa = p; p += sz_dca;
-- 
2.20.1


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

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

* [PATCH 03/25] usb: xhci-hcd: Cast ~XHCI_IRQS to u32
  2019-02-20  7:29 [PATCH 00/25] i.MX8MQ USB support Andrey Smirnov
  2019-02-20  7:29 ` [PATCH 01/25] usb: xhci-hcd: Tabify the file Andrey Smirnov
  2019-02-20  7:29 ` [PATCH 02/25] usb: xhci-hcd: Do not zero out DMA coherent memory Andrey Smirnov
@ 2019-02-20  7:29 ` Andrey Smirnov
  2019-02-20  7:29 ` [PATCH 04/25] usb: xhci-hcd: Make sure to initialize xhci->rings_list Andrey Smirnov
                   ` (22 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Andrey Smirnov @ 2019-02-20  7:29 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Cast ~XHCI_IRQS to u32 to avoid getting a warning on 64-bit builds.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/host/xhci-hcd.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index 7106a5637..a01f9fe38 100644
--- a/drivers/usb/host/xhci-hcd.c
+++ b/drivers/usb/host/xhci-hcd.c
@@ -1259,7 +1259,7 @@ static void xhci_dma_alloc(struct xhci_hcd *xhci)
 static int xhci_halt(struct xhci_hcd *xhci)
 {
 	u32 reg = readl(&xhci->op_regs->status);
-	u32 mask = ~XHCI_IRQS;
+	u32 mask = (u32)~XHCI_IRQS;
 
 	if (!(reg & STS_HALT))
 		mask &= ~CMD_RUN;
-- 
2.20.1


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

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

* [PATCH 04/25] usb: xhci-hcd: Make sure to initialize xhci->rings_list
  2019-02-20  7:29 [PATCH 00/25] i.MX8MQ USB support Andrey Smirnov
                   ` (2 preceding siblings ...)
  2019-02-20  7:29 ` [PATCH 03/25] usb: xhci-hcd: Cast ~XHCI_IRQS to u32 Andrey Smirnov
@ 2019-02-20  7:29 ` Andrey Smirnov
  2019-02-20  7:29 ` [PATCH 05/25] usb: xhci-hcd: Drop pointless bitwise or Andrey Smirnov
                   ` (21 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Andrey Smirnov @ 2019-02-20  7:29 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Make sure to initialize xhci->rings_list, otherwise any use of the
driver will result in a crash.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/host/xhci-hcd.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index a01f9fe38..cdce0d5ec 100644
--- a/drivers/usb/host/xhci-hcd.c
+++ b/drivers/usb/host/xhci-hcd.c
@@ -1470,6 +1470,7 @@ int xhci_register(struct device_d *dev, struct xhci_data *data)
 	xhci = xzalloc(sizeof(*xhci));
 	host = &xhci->host;
 	INIT_LIST_HEAD(&xhci->vdev_list);
+	INIT_LIST_HEAD(&xhci->rings_list);
 	xhci->dev = dev;
 	xhci->cap_regs = data->regs;
 	xhci->op_regs = (void __iomem *)xhci->cap_regs +
-- 
2.20.1


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

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

* [PATCH 05/25] usb: xhci-hcd: Drop pointless bitwise or
  2019-02-20  7:29 [PATCH 00/25] i.MX8MQ USB support Andrey Smirnov
                   ` (3 preceding siblings ...)
  2019-02-20  7:29 ` [PATCH 04/25] usb: xhci-hcd: Make sure to initialize xhci->rings_list Andrey Smirnov
@ 2019-02-20  7:29 ` Andrey Smirnov
  2019-02-20  7:29 ` [PATCH 06/25] usb: xhci-hcd: Add support for 64-byte context size Andrey Smirnov
                   ` (20 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Andrey Smirnov @ 2019-02-20  7:29 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

On_hs_hub is a boolean, not a bitfiled, so usage of bitwise or is
unnecessary. Replace it with a regular assignement operator.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/host/xhci-hcd.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index cdce0d5ec..f97a334f0 100644
--- a/drivers/usb/host/xhci-hcd.c
+++ b/drivers/usb/host/xhci-hcd.c
@@ -849,7 +849,7 @@ static int xhci_virtdev_init(struct xhci_virtual_device *vdev)
 		if (top_dev->parent->descriptor->bDeviceClass == USB_CLASS_HUB &&
 		    top_dev->parent->speed != USB_SPEED_LOW &&
 		    top_dev->parent->speed != USB_SPEED_FULL) {
-			on_hs_hub |= true;
+			on_hs_hub = true;
 			if (!hs_slot_id) {
 				struct xhci_virtual_device *vhub =
 					xhci_find_virtdev(xhci, top_dev->parent);
-- 
2.20.1


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

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

* [PATCH 06/25] usb: xhci-hcd: Add support for 64-byte context size
  2019-02-20  7:29 [PATCH 00/25] i.MX8MQ USB support Andrey Smirnov
                   ` (4 preceding siblings ...)
  2019-02-20  7:29 ` [PATCH 05/25] usb: xhci-hcd: Drop pointless bitwise or Andrey Smirnov
@ 2019-02-20  7:29 ` Andrey Smirnov
  2019-02-20  7:29 ` [PATCH 07/25] usb: xhci-hcd: Don't try to DMA sync if buffer is NULL Andrey Smirnov
                   ` (19 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Andrey Smirnov @ 2019-02-20  7:29 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

xHCI spec allows for various context to be either 32 or 64 bytes in
size, so we can't rely on struct definitions to correctly reflect data
layout. Port varios context accessors from Linux kernel and convert
the rest of the code to use them in order to be able to support both
context sizes.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/host/xhci-hcd.c | 233 +++++++++++++++++++++++++-----------
 drivers/usb/host/xhci.h     |  36 ++++--
 2 files changed, 188 insertions(+), 81 deletions(-)

diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index f97a334f0..91ddcbb30 100644
--- a/drivers/usb/host/xhci-hcd.c
+++ b/drivers/usb/host/xhci-hcd.c
@@ -23,6 +23,39 @@
 
 #include "xhci.h"
 
+
+static struct xhci_input_control_ctx *
+xhci_get_input_control_ctx(struct xhci_container_ctx *ctx)
+{
+	if (ctx->type != XHCI_CTX_TYPE_INPUT)
+		return NULL;
+
+	return (struct xhci_input_control_ctx *)ctx->bytes;
+}
+
+static struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci,
+					       struct xhci_container_ctx *ctx)
+{
+	if (ctx->type == XHCI_CTX_TYPE_DEVICE)
+		return (struct xhci_slot_ctx *)ctx->bytes;
+
+	return (struct xhci_slot_ctx *)
+		(ctx->bytes + HCC_CTX_SIZE(xhci->hcc_params));
+}
+
+static struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci,
+					   struct xhci_container_ctx *ctx,
+					   unsigned int ep_index)
+{
+	/* increment ep index by offset of start of ep ctx array */
+	ep_index++;
+	if (ctx->type == XHCI_CTX_TYPE_INPUT)
+		ep_index++;
+
+	return (struct xhci_ep_ctx *)
+		(ctx->bytes + (ep_index * HCC_CTX_SIZE(xhci->hcc_params)));
+}
+
 /*
  * xHCI ring handling
  */
@@ -426,28 +459,48 @@ static struct xhci_virtual_device *xhci_find_virtdev(struct xhci_hcd *xhci,
 	return NULL;
 }
 
+static struct xhci_container_ctx *
+xhci_alloc_container_ctx(struct xhci_hcd *xhci, int type)
+{
+	struct xhci_container_ctx *ctx;
+
+	if ((type != XHCI_CTX_TYPE_DEVICE) && (type != XHCI_CTX_TYPE_INPUT))
+		return NULL;
+
+	ctx = xzalloc(sizeof(*ctx));
+	ctx->type = type;
+	ctx->size = HCC_64BYTE_CONTEXT(xhci->hcc_params) ? 2048 : 1024;
+	if (type == XHCI_CTX_TYPE_INPUT)
+		ctx->size += HCC_CTX_SIZE(xhci->hcc_params);
+
+	ctx->bytes = dma_alloc_coherent(ctx->size, &ctx->dma);
+	if (WARN_ON(!ctx->bytes)) {
+		kfree(ctx);
+		return NULL;
+	}
+	return ctx;
+}
+
+static void xhci_free_container_ctx(struct xhci_hcd *xhci,
+				    struct xhci_container_ctx *ctx)
+{
+	if (!ctx)
+		return;
+	dma_free_coherent(ctx->bytes, ctx->dma, ctx->size);
+	kfree(ctx);
+}
+
 static struct xhci_virtual_device *xhci_alloc_virtdev(struct xhci_hcd *xhci,
 						      struct usb_device *udev)
 {
 	struct xhci_virtual_device *vdev;
-	size_t sz_ctx, sz_ictx, sz_dctx;
-	void *p;
 
 	vdev = xzalloc(sizeof(*vdev));
 	vdev->udev = udev;
 	list_add_tail(&vdev->list, &xhci->vdev_list);
 
-	sz_ctx = HCC_64BYTE_CONTEXT(xhci->hcc_params) ? 2048 : 1024;
-	/* Device Context: 64B aligned */
-	sz_dctx = ALIGN(sz_ctx, 64);
-	/* Input Control Context: 64B aligned */
-	sz_ictx = ALIGN(sz_ctx + HCC_CTX_SIZE(xhci->hcc_params), 64);
-
-	vdev->dma_size = sz_ictx + sz_dctx;
-	p = vdev->dma = dma_alloc_coherent(vdev->dma_size, DMA_ADDRESS_BROKEN);
-
-	vdev->out_ctx = p; p += sz_dctx;
-	vdev->in_ctx = p; p += sz_ictx;
+	vdev->out_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_DEVICE);
+	vdev->in_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_INPUT);
 
 	return vdev;
 }
@@ -462,7 +515,8 @@ static void xhci_free_virtdev(struct xhci_virtual_device *vdev)
 			xhci_put_endpoint_ring(xhci, vdev->ep[i]);
 
 	list_del(&vdev->list);
-	dma_free_coherent(vdev->dma, 0, vdev->dma_size);
+	xhci_free_container_ctx(xhci, vdev->out_ctx);
+	xhci_free_container_ctx(xhci, vdev->in_ctx);
 	free(vdev);
 }
 
@@ -486,23 +540,32 @@ static int xhci_virtdev_issue_transfer(struct xhci_virtual_device *vdev,
 
 static void xhci_virtdev_zero_in_ctx(struct xhci_virtual_device *vdev)
 {
+	struct xhci_hcd *xhci = to_xhci_hcd(vdev->udev->host);
+	struct xhci_input_control_ctx *in_icc;
+	struct xhci_slot_ctx *in_slot;
+	struct xhci_ep_ctx *in_ep;
 	int i;
 
+	in_icc = xhci_get_input_control_ctx(vdev->in_ctx);
+	in_slot = xhci_get_slot_ctx(xhci, vdev->in_ctx);
+
 	/* When a device's add flag and drop flag are zero, any subsequent
 	 * configure endpoint command will leave that endpoint's state
 	 * untouched.  Make sure we don't leave any old state in the input
 	 * endpoint contexts.
 	 */
-	vdev->in_ctx->icc.drop_flags = 0;
-	vdev->in_ctx->icc.add_flags = 0;
-	vdev->in_ctx->slot.dev_info &= cpu_to_le32(~LAST_CTX_MASK);
+	in_icc->drop_flags = 0;
+	in_icc->add_flags = 0;
+	in_slot->dev_info &= cpu_to_le32(~LAST_CTX_MASK);
 	/* Endpoint 0 is always valid */
-	vdev->in_ctx->slot.dev_info |= cpu_to_le32(LAST_CTX(1));
+	in_slot->dev_info |= cpu_to_le32(LAST_CTX(1));
 	for (i = 1; i < 31; i++) {
-		vdev->in_ctx->ep[i].ep_info = 0;
-		vdev->in_ctx->ep[i].ep_info2 = 0;
-		vdev->in_ctx->ep[i].deq = 0;
-		vdev->in_ctx->ep[i].tx_info = 0;
+		in_ep = xhci_get_ep_ctx(xhci, vdev->in_ctx, i);
+
+		in_ep->ep_info = 0;
+		in_ep->ep_info2 = 0;
+		in_ep->deq = 0;
+		in_ep->tx_info = 0;
 	}
 }
 
@@ -558,11 +621,14 @@ static int xhci_virtdev_enable_slot(struct xhci_virtual_device *vdev)
 int xhci_virtdev_reset(struct xhci_virtual_device *vdev)
 {
 	struct xhci_hcd *xhci = to_xhci_hcd(vdev->udev->host);
+	struct xhci_slot_ctx *out_slot;
 	union xhci_trb trb;
 	int ret;
 
+	out_slot = xhci_get_slot_ctx(xhci, vdev->out_ctx);
+
 	/* If device is not setup, there is no point in resetting it */
-	if (GET_SLOT_STATE(le32_to_cpu(vdev->out_ctx->slot.dev_state)) ==
+	if (GET_SLOT_STATE(le32_to_cpu(out_slot->dev_state)) ==
 	    SLOT_STATE_DISABLED)
 		return 0;
 
@@ -607,31 +673,37 @@ static int xhci_virtdev_update_hub_device(struct xhci_virtual_device *vdev,
 {
 	struct xhci_hcd *xhci = to_xhci_hcd(vdev->udev->host);
 	struct usb_hub_descriptor *desc = buffer;
+	struct xhci_input_control_ctx *in_icc;
+	struct xhci_slot_ctx *in_slot, *out_slot;
 	union xhci_trb trb;
 	u32 dev_info, dev_info2, tt_info;
 	u8 maxchild;
 	u16 hubchar;
 	int ret;
 
+	out_slot = xhci_get_slot_ctx(xhci, vdev->out_ctx);
+
 	/* Need at least first byte of wHubCharacteristics */
 	if (length < 4)
 		return 0;
 	/* Skip already configured hub device */
-	if (vdev->out_ctx->slot.dev_info & DEV_HUB)
+	if (out_slot->dev_info & DEV_HUB)
 		return 0;
 
 	maxchild = desc->bNbrPorts;
 	hubchar = le16_to_cpu(desc->wHubCharacteristics);
 
+	in_slot = xhci_get_slot_ctx(xhci, vdev->in_ctx);
+	in_icc = xhci_get_input_control_ctx(vdev->in_ctx);
+
 	/* update slot context */
-	memcpy(&vdev->in_ctx->slot, &vdev->out_ctx->slot,
-	       sizeof(struct xhci_slot_ctx));
-	vdev->in_ctx->icc.add_flags |= cpu_to_le32(SLOT_FLAG);
-	vdev->in_ctx->icc.drop_flags = 0;
-	vdev->in_ctx->slot.dev_state = 0;
-	dev_info = le32_to_cpu(vdev->in_ctx->slot.dev_info);
-	dev_info2 = le32_to_cpu(vdev->in_ctx->slot.dev_info2);
-	tt_info = le32_to_cpu(vdev->in_ctx->slot.tt_info);
+	memcpy(in_slot, out_slot, sizeof(struct xhci_slot_ctx));
+	in_icc->add_flags |= cpu_to_le32(SLOT_FLAG);
+	in_icc->drop_flags = 0;
+	in_slot->dev_state = 0;
+	dev_info = le32_to_cpu(in_slot->dev_info);
+	dev_info2 = le32_to_cpu(in_slot->dev_info2);
+	tt_info = le32_to_cpu(in_slot->tt_info);
 
 	dev_info |= DEV_HUB;
 	/* HS Multi-TT in bDeviceProtocol */
@@ -653,13 +725,13 @@ static int xhci_virtdev_update_hub_device(struct xhci_virtual_device *vdev,
 			tt_info |= TT_THINK_TIME(think_time);
 		}
 	}
-	vdev->in_ctx->slot.dev_info = cpu_to_le32(dev_info);
-	vdev->in_ctx->slot.dev_info2 = cpu_to_le32(dev_info2);
-	vdev->in_ctx->slot.tt_info = cpu_to_le32(tt_info);
+	in_slot->dev_info = cpu_to_le32(dev_info);
+	in_slot->dev_info2 = cpu_to_le32(dev_info2);
+	in_slot->tt_info = cpu_to_le32(tt_info);
 
 	/* Issue Configure Endpoint or Evaluate Context Command */
 	memset(&trb, 0, sizeof(union xhci_trb));
-	xhci_write_64((dma_addr_t)vdev->in_ctx, &trb.event_cmd.cmd_trb);
+	xhci_write_64(vdev->in_ctx->dma, &trb.event_cmd.cmd_trb);
 	trb.event_cmd.flags = SLOT_ID_FOR_TRB(vdev->slot_id);
 	if (xhci->hci_version > 0x95)
 		trb.event_cmd.flags |= TRB_TYPE(TRB_CONFIG_EP);
@@ -695,6 +767,8 @@ static int xhci_virtdev_update_hub_status(struct xhci_virtual_device *vhub,
 static int xhci_virtdev_configure(struct xhci_virtual_device *vdev, int config)
 {
 	struct xhci_hcd *xhci = to_xhci_hcd(vdev->udev->host);
+	struct xhci_input_control_ctx *in_icc;
+	struct xhci_slot_ctx *in_slot;
 	struct usb_device *udev = vdev->udev;
 	union xhci_trb trb;
 	u32 add_flags = 0, last_ctx;
@@ -711,10 +785,12 @@ static int xhci_virtdev_configure(struct xhci_virtual_device *vdev, int config)
 							   ep->bmAttributes);
 			u8 epi = xhci_get_endpoint_index(ep->bEndpointAddress,
 							 ep->bmAttributes);
-			struct xhci_ep_ctx *ctx = &vdev->in_ctx->ep[epi];
+			struct xhci_ep_ctx *ctx;
 			u32 mps, interval, mult, esit, max_packet, max_burst;
 			u32 ep_info, ep_info2, tx_info;
 
+			ctx = xhci_get_ep_ctx(xhci, vdev->in_ctx, epi);
+
 			vdev->ep[epi] = xhci_get_endpoint_ring(xhci);
 			if (!vdev->ep[epi])
 				return -ENOMEM;
@@ -781,23 +857,26 @@ static int xhci_virtdev_configure(struct xhci_virtual_device *vdev, int config)
 
 	last_ctx = fls(add_flags) - 1;
 
+	in_slot = xhci_get_slot_ctx(xhci, vdev->in_ctx);
+	in_icc = xhci_get_input_control_ctx(vdev->in_ctx);
+
 	/* See section 4.6.6 - A0 = 1; A1 = D0 = D1 = 0 */
-	vdev->in_ctx->icc.add_flags = cpu_to_le32(add_flags);
-	vdev->in_ctx->icc.add_flags |= cpu_to_le32(SLOT_FLAG);
-	vdev->in_ctx->icc.add_flags &= cpu_to_le32(~EP0_FLAG);
-	vdev->in_ctx->icc.drop_flags &= cpu_to_le32(~(SLOT_FLAG | EP0_FLAG));
+	in_icc->add_flags = cpu_to_le32(add_flags);
+	in_icc->add_flags |= cpu_to_le32(SLOT_FLAG);
+	in_icc->add_flags &= cpu_to_le32(~EP0_FLAG);
+	in_icc->drop_flags &= cpu_to_le32(~(SLOT_FLAG | EP0_FLAG));
 
 	/* Don't issue the command if there's no endpoints to update. */
-	if (vdev->in_ctx->icc.add_flags == cpu_to_le32(SLOT_FLAG) &&
-	    vdev->in_ctx->icc.drop_flags == 0)
+	if (in_icc->add_flags == cpu_to_le32(SLOT_FLAG) &&
+	    in_icc->drop_flags == 0)
 		return 0;
 
-	vdev->in_ctx->slot.dev_info &= cpu_to_le32(~LAST_CTX_MASK);
-	vdev->in_ctx->slot.dev_info |= cpu_to_le32(LAST_CTX(last_ctx));
+	in_slot->dev_info &= cpu_to_le32(~LAST_CTX_MASK);
+	in_slot->dev_info |= cpu_to_le32(LAST_CTX(last_ctx));
 
 	/* Issue Configure Endpoint Command */
 	memset(&trb, 0, sizeof(union xhci_trb));
-	xhci_write_64((dma_addr_t)vdev->in_ctx, &trb.event_cmd.cmd_trb);
+	xhci_write_64(vdev->in_ctx->dma, &trb.event_cmd.cmd_trb);
 	trb.event_cmd.flags = TRB_TYPE(TRB_CONFIG_EP) |
 		SLOT_ID_FOR_TRB(vdev->slot_id);
 	xhci_print_trb(xhci, &trb, "Request  ConfigureEndpoint");
@@ -817,7 +896,7 @@ static int xhci_virtdev_deconfigure(struct xhci_virtual_device *vdev)
 
 	/* Issue Deconfigure Endpoint Command */
 	memset(&trb, 0, sizeof(union xhci_trb));
-	xhci_write_64((dma_addr_t)vdev->in_ctx, &trb.event_cmd.cmd_trb);
+	xhci_write_64(vdev->in_ctx->dma, &trb.event_cmd.cmd_trb);
 	trb.event_cmd.flags = TRB_TYPE(TRB_CONFIG_EP) | TRB_DC |
 		SLOT_ID_FOR_TRB(vdev->slot_id);
 	xhci_print_trb(xhci, &trb, "Request  DeconfigureEndpoint");
@@ -833,11 +912,16 @@ static int xhci_virtdev_init(struct xhci_virtual_device *vdev)
 {
 	struct xhci_hcd *xhci = to_xhci_hcd(vdev->udev->host);
 	struct usb_device *top_dev;
+	struct xhci_slot_ctx *in_slot;
+	struct xhci_ep_ctx *in_ep;
 	int max_packets;
 	u32 route = 0, dev_info, dev_info2, tt_info, ep_info2, tx_info;
 	bool on_hs_hub = false;
 	int hs_slot_id = 0;
 
+	in_ep = xhci_get_ep_ctx(xhci, vdev->in_ctx, 0);
+	in_slot = xhci_get_slot_ctx(xhci, vdev->in_ctx);
+
 	/*
 	 * Find the root hub port this device is under, also determine SlotID
 	 * of possible external HS hub a LS/FS device could be connected to.
@@ -892,9 +976,9 @@ static int xhci_virtdev_init(struct xhci_virtual_device *vdev)
 		tt_info |= (top_dev->portnr << 8) | hs_slot_id;
 	}
 
-	vdev->in_ctx->slot.dev_info = cpu_to_le32(dev_info);
-	vdev->in_ctx->slot.dev_info2 = cpu_to_le32(dev_info2);
-	vdev->in_ctx->slot.tt_info = cpu_to_le32(tt_info);
+	in_slot->dev_info = cpu_to_le32(dev_info);
+	in_slot->dev_info2 = cpu_to_le32(dev_info2);
+	in_slot->tt_info = cpu_to_le32(tt_info);
 
 	/* 4.3.3 4) Initalize Transfer Ring */
 	vdev->ep[0] = xhci_get_endpoint_ring(xhci);
@@ -906,13 +990,13 @@ static int xhci_virtdev_init(struct xhci_virtual_device *vdev)
 	ep_info2 = EP_TYPE(CTRL_EP) | MAX_BURST(0) | ERROR_COUNT(3);
 	ep_info2 |= MAX_PACKET(max_packets);
 	tx_info = AVG_TRB_LENGTH_FOR_EP(8);
-	vdev->in_ctx->ep[0].ep_info2 = cpu_to_le32(ep_info2);
-	vdev->in_ctx->ep[0].tx_info = cpu_to_le32(tx_info);
-	vdev->in_ctx->ep[0].deq = cpu_to_le64((dma_addr_t)vdev->ep[0]->enqueue |
-					      vdev->ep[0]->cycle_state);
+	in_ep->ep_info2 = cpu_to_le32(ep_info2);
+	in_ep->tx_info = cpu_to_le32(tx_info);
+	in_ep->deq = cpu_to_le64((dma_addr_t)vdev->ep[0]->enqueue |
+				 vdev->ep[0]->cycle_state);
 
 	/* 4.3.3 6+7) Initalize and Set Device Context Base Address Array */
-	xhci->dcbaa[vdev->slot_id] = cpu_to_le64((dma_addr_t)vdev->out_ctx);
+	xhci->dcbaa[vdev->slot_id] = cpu_to_le64(vdev->out_ctx->dma);
 
 	return 0;
 }
@@ -921,39 +1005,46 @@ static int xhci_virtdev_setup(struct xhci_virtual_device *vdev,
 			      enum xhci_setup_dev setup)
 {
 	struct xhci_hcd *xhci = to_xhci_hcd(vdev->udev->host);
+	static struct xhci_input_control_ctx *in_icc;
+	struct xhci_slot_ctx *in_slot;
+	struct xhci_ep_ctx *in_ep;
 	union xhci_trb trb;
 	int ret;
 
+	in_slot = xhci_get_slot_ctx(xhci, vdev->in_ctx);
+	in_icc = xhci_get_input_control_ctx(vdev->in_ctx);
+
 	/*
 	 * If this is the first Set Address since device
 	 * plug-in then initialize Slot Context
 	 */
-	if (!vdev->in_ctx->slot.dev_info)
+	if (!in_slot->dev_info)
 		xhci_virtdev_init(vdev);
 	else {
+		in_ep = xhci_get_ep_ctx(xhci, vdev->in_ctx, 0);
+
 		/* Otherwise, update Control Ring Dequeue pointer */
-		vdev->in_ctx->ep[0].deq =
-			cpu_to_le64((dma_addr_t)vdev->ep[0]->enqueue |
-				    vdev->ep[0]->cycle_state);
+		in_ep->deq = cpu_to_le64((dma_addr_t)vdev->ep[0]->enqueue |
+					 vdev->ep[0]->cycle_state);
 		/*
 		 * FS devices have MaxPacketSize0 of 8 or 64, we start
 		 * with 64. If assumtion was wrong, fix it up here.
 		 */
 		if (vdev->udev->speed == USB_SPEED_FULL &&
 		    vdev->udev->maxpacketsize == PACKET_SIZE_8) {
-			u32 info = le32_to_cpu(vdev->in_ctx->ep[0].ep_info2);
+			u32 info = le32_to_cpu(in_ep->ep_info2);
 			info &= ~MAX_PACKET_MASK;
 			info |= MAX_PACKET(8);
-			vdev->in_ctx->ep[0].ep_info2 = cpu_to_le32(info);
+			in_ep->ep_info2 = cpu_to_le32(info);
 		}
 	}
 
-	vdev->in_ctx->icc.add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG);
-	vdev->in_ctx->icc.drop_flags = 0;
+	in_icc->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG);
+	in_icc->drop_flags = 0;
 
 	/* Issue Address Device Command */
 	memset(&trb, 0, sizeof(union xhci_trb));
-	xhci_write_64((dma_addr_t)vdev->in_ctx, &trb.event_cmd.cmd_trb);
+	xhci_write_64(vdev->in_ctx->dma, &trb.event_cmd.cmd_trb);
 	trb.event_cmd.flags = TRB_TYPE(TRB_ADDR_DEV) |
 		SLOT_ID_FOR_TRB(vdev->slot_id);
 	if (setup == SETUP_CONTEXT_ONLY)
@@ -1008,6 +1099,7 @@ static int xhci_submit_normal(struct usb_device *udev, unsigned long pipe,
 	struct usb_host *host = udev->host;
 	struct xhci_hcd *xhci = to_xhci_hcd(host);
 	struct xhci_virtual_device *vdev;
+	struct xhci_slot_ctx *out_slot;
 	union xhci_trb trb;
 	u8 epaddr = (usb_pipein(pipe) ? USB_DIR_IN : USB_DIR_OUT) |
 		usb_pipeendpoint(pipe);
@@ -1018,10 +1110,12 @@ static int xhci_submit_normal(struct usb_device *udev, unsigned long pipe,
 	if (!vdev)
 		return -ENODEV;
 
+	out_slot = xhci_get_slot_ctx(xhci, vdev->out_ctx);
+
 	dev_dbg(xhci->dev, "%s udev %p vdev %p slot %u state %u epi %u in_ctx %p out_ctx %p\n",
 		__func__, udev, vdev, vdev->slot_id,
-		GET_SLOT_STATE(le32_to_cpu(vdev->out_ctx->slot.dev_state)), epi,
-		vdev->in_ctx, vdev->out_ctx);
+		GET_SLOT_STATE(le32_to_cpu(out_slot->dev_state)), epi,
+		vdev->in_ctx->bytes, vdev->out_ctx->bytes);
 
 	/* pass ownership of data buffer to device */
 	dma_sync_single_for_device((unsigned long)buffer, length,
@@ -1069,6 +1163,7 @@ static int xhci_submit_control(struct usb_device *udev, unsigned long pipe,
 	struct usb_host *host = udev->host;
 	struct xhci_hcd *xhci = to_xhci_hcd(host);
 	struct xhci_virtual_device *vdev;
+	struct xhci_slot_ctx *out_slot;
 	union xhci_trb trb;
 	u16 typeReq = (req->requesttype << 8) | req->request;
 	int ret;
@@ -1090,10 +1185,12 @@ static int xhci_submit_control(struct usb_device *udev, unsigned long pipe,
 	if (!vdev)
 		return -ENODEV;
 
+	out_slot = xhci_get_slot_ctx(xhci, vdev->out_ctx);
+
 	dev_dbg(xhci->dev, "%s udev %p vdev %p slot %u state %u epi %u in_ctx %p out_ctx %p\n",
 		__func__, udev, vdev, vdev->slot_id,
-		GET_SLOT_STATE(le32_to_cpu(vdev->out_ctx->slot.dev_state)), 0,
-		vdev->in_ctx, vdev->out_ctx);
+		GET_SLOT_STATE(le32_to_cpu(out_slot->dev_state)), 0,
+		vdev->in_ctx->bytes, vdev->out_ctx->bytes);
 
 	if (req->request == USB_REQ_SET_ADDRESS)
 		return xhci_virtdev_set_address(vdev);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 078f88118..9f2d57675 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -503,6 +503,27 @@ struct xhci_doorbell_array {
 #define DB_VALUE(ep, stream)	((((ep) + 1) & 0xff) | ((stream) << 16))
 #define DB_VALUE_HOST		0x00000000
 
+/**
+ * struct xhci_container_ctx
+ * @type: Type of context.  Used to calculated offsets to contained contexts.
+ * @size: Size of the context data
+ * @bytes: The raw context data given to HW
+ * @dma: dma address of the bytes
+ *
+ * Represents either a Device or Input context.  Holds a pointer to the raw
+ * memory used for the context (bytes) and dma address of it (dma).
+ */
+struct xhci_container_ctx {
+	unsigned type;
+#define XHCI_CTX_TYPE_DEVICE  0x1
+#define XHCI_CTX_TYPE_INPUT   0x2
+
+	int size;
+
+	u8 *bytes;
+	dma_addr_t dma;
+};
+
 /**
  * struct xhci_slot_ctx
  * @dev_info:	Route string, device speed, hub info, and last valid endpoint
@@ -1183,17 +1204,6 @@ struct xhci_ring {
 	int cycle_state;
 };
 
-struct xhci_device_context {
-	struct xhci_slot_ctx slot;
-	struct xhci_ep_ctx ep[31];
-};
-
-struct xhci_input_context {
-	struct xhci_input_control_ctx icc;
-	struct xhci_slot_ctx slot;
-	struct xhci_ep_ctx ep[31];
-};
-
 struct xhci_virtual_device {
 	struct list_head list;
 	struct usb_device *udev;
@@ -1201,8 +1211,8 @@ struct xhci_virtual_device {
 	size_t dma_size;
 	int slot_id;
 	struct xhci_ring *ep[USB_MAXENDPOINTS];
-	struct xhci_input_context *in_ctx;
-	struct xhci_device_context *out_ctx;
+	struct xhci_container_ctx *in_ctx;
+	struct xhci_container_ctx *out_ctx;
 };
 
 struct usb_root_hub_info {
-- 
2.20.1


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

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

* [PATCH 07/25] usb: xhci-hcd: Don't try to DMA sync if buffer is NULL
  2019-02-20  7:29 [PATCH 00/25] i.MX8MQ USB support Andrey Smirnov
                   ` (5 preceding siblings ...)
  2019-02-20  7:29 ` [PATCH 06/25] usb: xhci-hcd: Add support for 64-byte context size Andrey Smirnov
@ 2019-02-20  7:29 ` Andrey Smirnov
  2019-02-20  7:29 ` [PATCH 08/25] usb: xhci-hcd: Always wait for "Response Data" completion Andrey Smirnov
                   ` (18 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Andrey Smirnov @ 2019-02-20  7:29 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Driver's .submit_control() callback can and will be called with buffer
set to NULL (and length set to 0), so we need to make sure that we
don't try to DMA sync the buffer in that case. Add appropriate gurads
to make sure that doesn't happen.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/host/xhci-hcd.c | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index 91ddcbb30..657a49f8a 100644
--- a/drivers/usb/host/xhci-hcd.c
+++ b/drivers/usb/host/xhci-hcd.c
@@ -1200,10 +1200,12 @@ static int xhci_submit_control(struct usb_device *udev, unsigned long pipe,
 			return ret;
 	}
 
-	/* Pass ownership of data buffer to device */
-	dma_sync_single_for_device((unsigned long)buffer, length,
-				   (req->requesttype & USB_DIR_IN) ?
-				   DMA_FROM_DEVICE : DMA_TO_DEVICE);
+	if (length > 0) {
+		/* Pass ownership of data buffer to device */
+		dma_sync_single_for_device((unsigned long)buffer, length,
+					   (req->requesttype & USB_DIR_IN) ?
+					   DMA_FROM_DEVICE : DMA_TO_DEVICE);
+	}
 
 	/* Setup TRB */
 	memset(&trb, 0, sizeof(union xhci_trb));
@@ -1259,10 +1261,13 @@ static int xhci_submit_control(struct usb_device *udev, unsigned long pipe,
 	xhci_print_trb(xhci, &trb, "Response Status");
 
 dma_regain:
-	/* Regain ownership of data buffer from device */
-	dma_sync_single_for_cpu((unsigned long)buffer, length,
-				(req->requesttype & USB_DIR_IN) ?
-				DMA_FROM_DEVICE : DMA_TO_DEVICE);
+	if (length > 0) {
+		/* Regain ownership of data buffer from device */
+		dma_sync_single_for_cpu((unsigned long)buffer, length,
+					(req->requesttype & USB_DIR_IN) ?
+					DMA_FROM_DEVICE : DMA_TO_DEVICE);
+	}
+
 	if (ret < 0)
 		return ret;
 
-- 
2.20.1


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

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

* [PATCH 08/25] usb: xhci-hcd: Always wait for "Response Data" completion
  2019-02-20  7:29 [PATCH 00/25] i.MX8MQ USB support Andrey Smirnov
                   ` (6 preceding siblings ...)
  2019-02-20  7:29 ` [PATCH 07/25] usb: xhci-hcd: Don't try to DMA sync if buffer is NULL Andrey Smirnov
@ 2019-02-20  7:29 ` Andrey Smirnov
  2019-02-20  7:29 ` [PATCH 09/25] usb: xhci-hcd: Convert xhci_submit_normal() to use dma_map_single() Andrey Smirnov
                   ` (17 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Andrey Smirnov @ 2019-02-20  7:29 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Xhci_submit_control() submits TRB_DATA with TRB_IOC flag regardless of
the vlaue of req->requesttype, so we shouldn't gate waiting for the
event that will result from it with "req->requesttype &
USB_DIR_IN". Failing to do this will result in unstable USB
performance and will eventually cause the controller to fail
completely.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/host/xhci-hcd.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index 657a49f8a..8a00b8854 100644
--- a/drivers/usb/host/xhci-hcd.c
+++ b/drivers/usb/host/xhci-hcd.c
@@ -1248,7 +1248,7 @@ static int xhci_submit_control(struct usb_device *udev, unsigned long pipe,
 	xhci_print_trb(xhci, &trb, "Request  Status");
 	xhci_virtdev_issue_transfer(vdev, 0, &trb, true);
 
-	if (length > 0 && req->requesttype & USB_DIR_IN) {
+	if (length > 0) {
 		ret = xhci_wait_for_event(xhci, TRB_TRANSFER, &trb);
 		xhci_print_trb(xhci, &trb, "Response Data  ");
 		if (ret == -COMP_SHORT_TX)
-- 
2.20.1


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

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

* [PATCH 09/25] usb: xhci-hcd: Convert xhci_submit_normal() to use dma_map_single()
  2019-02-20  7:29 [PATCH 00/25] i.MX8MQ USB support Andrey Smirnov
                   ` (7 preceding siblings ...)
  2019-02-20  7:29 ` [PATCH 08/25] usb: xhci-hcd: Always wait for "Response Data" completion Andrey Smirnov
@ 2019-02-20  7:29 ` Andrey Smirnov
  2019-02-20  7:29 ` [PATCH 10/25] usb: xhci-hcd: Convert xhci_submit_control() " Andrey Smirnov
                   ` (16 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Andrey Smirnov @ 2019-02-20  7:29 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Convert xhci_submit_normal() to use dma_(un)map_single(). These
functions both allow us to handle potential physical/virtual address
differences as well as allowing to drop a number of typecasts.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/host/xhci-hcd.c | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index 8a00b8854..d0b73041d 100644
--- a/drivers/usb/host/xhci-hcd.c
+++ b/drivers/usb/host/xhci-hcd.c
@@ -1100,6 +1100,7 @@ static int xhci_submit_normal(struct usb_device *udev, unsigned long pipe,
 	struct xhci_hcd *xhci = to_xhci_hcd(host);
 	struct xhci_virtual_device *vdev;
 	struct xhci_slot_ctx *out_slot;
+	dma_addr_t buffer_dma;
 	union xhci_trb trb;
 	u8 epaddr = (usb_pipein(pipe) ? USB_DIR_IN : USB_DIR_OUT) |
 		usb_pipeendpoint(pipe);
@@ -1118,13 +1119,15 @@ static int xhci_submit_normal(struct usb_device *udev, unsigned long pipe,
 		vdev->in_ctx->bytes, vdev->out_ctx->bytes);
 
 	/* pass ownership of data buffer to device */
-	dma_sync_single_for_device((unsigned long)buffer, length,
-				   usb_pipein(pipe) ?
-				   DMA_FROM_DEVICE : DMA_TO_DEVICE);
+	buffer_dma = dma_map_single(xhci->dev, buffer, length,
+				    usb_pipein(pipe) ?
+				    DMA_FROM_DEVICE : DMA_TO_DEVICE);
+	if (dma_mapping_error(xhci->dev, buffer_dma))
+		return -EFAULT;
 
 	/* Normal TRB */
 	memset(&trb, 0, sizeof(union xhci_trb));
-	trb.event_cmd.cmd_trb = cpu_to_le64((dma_addr_t)buffer);
+	trb.event_cmd.cmd_trb = cpu_to_le64(buffer_dma);
 	/* FIXME: TD remainder */
 	trb.event_cmd.status = TRB_LEN(length) | TRB_INTR_TARGET(0);
 	trb.event_cmd.flags = TRB_TYPE(TRB_NORMAL) | TRB_IOC;
@@ -1136,9 +1139,9 @@ static int xhci_submit_normal(struct usb_device *udev, unsigned long pipe,
 	xhci_print_trb(xhci, &trb, "Response Normal");
 
 	/* Regain ownership of data buffer from device */
-	dma_sync_single_for_cpu((unsigned long)buffer, length,
-				usb_pipein(pipe) ?
-				DMA_FROM_DEVICE : DMA_TO_DEVICE);
+	dma_unmap_single(xhci->dev, buffer_dma, length,
+			 usb_pipein(pipe) ?
+			 DMA_FROM_DEVICE : DMA_TO_DEVICE);
 
 	switch (ret) {
 	case -COMP_SHORT_TX:
-- 
2.20.1


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

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

* [PATCH 10/25] usb: xhci-hcd: Convert xhci_submit_control() to use dma_map_single()
  2019-02-20  7:29 [PATCH 00/25] i.MX8MQ USB support Andrey Smirnov
                   ` (8 preceding siblings ...)
  2019-02-20  7:29 ` [PATCH 09/25] usb: xhci-hcd: Convert xhci_submit_normal() to use dma_map_single() Andrey Smirnov
@ 2019-02-20  7:29 ` Andrey Smirnov
  2019-02-20  7:29 ` [PATCH 11/25] usb: xhci-hcd: Simplify TRB initialization code Andrey Smirnov
                   ` (15 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Andrey Smirnov @ 2019-02-20  7:29 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Convert xhci_submit_control() to use dma_(un)map_single(). These
functions both allow us to handle potential physical/virtual address
differences as well as allowing to drop a number of typecasts.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/host/xhci-hcd.c | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index d0b73041d..4e28e24c4 100644
--- a/drivers/usb/host/xhci-hcd.c
+++ b/drivers/usb/host/xhci-hcd.c
@@ -1167,6 +1167,7 @@ static int xhci_submit_control(struct usb_device *udev, unsigned long pipe,
 	struct xhci_hcd *xhci = to_xhci_hcd(host);
 	struct xhci_virtual_device *vdev;
 	struct xhci_slot_ctx *out_slot;
+	dma_addr_t buffer_dma = 0;
 	union xhci_trb trb;
 	u16 typeReq = (req->requesttype << 8) | req->request;
 	int ret;
@@ -1205,9 +1206,11 @@ static int xhci_submit_control(struct usb_device *udev, unsigned long pipe,
 
 	if (length > 0) {
 		/* Pass ownership of data buffer to device */
-		dma_sync_single_for_device((unsigned long)buffer, length,
-					   (req->requesttype & USB_DIR_IN) ?
-					   DMA_FROM_DEVICE : DMA_TO_DEVICE);
+		buffer_dma = dma_map_single(xhci->dev, buffer, length,
+					    (req->requesttype & USB_DIR_IN) ?
+					    DMA_FROM_DEVICE : DMA_TO_DEVICE);
+		if (dma_mapping_error(xhci->dev, buffer_dma))
+			return -EFAULT;
 	}
 
 	/* Setup TRB */
@@ -1230,7 +1233,7 @@ static int xhci_submit_control(struct usb_device *udev, unsigned long pipe,
 	/* Data TRB */
 	if (length > 0) {
 		memset(&trb, 0, sizeof(union xhci_trb));
-		trb.event_cmd.cmd_trb = cpu_to_le64((dma_addr_t)buffer);
+		trb.event_cmd.cmd_trb = cpu_to_le64(buffer_dma);
 		/* FIXME: TD remainder */
 		trb.event_cmd.status = TRB_LEN(length) | TRB_INTR_TARGET(0);
 		trb.event_cmd.flags = TRB_TYPE(TRB_DATA) | TRB_IOC;
@@ -1266,9 +1269,9 @@ static int xhci_submit_control(struct usb_device *udev, unsigned long pipe,
 dma_regain:
 	if (length > 0) {
 		/* Regain ownership of data buffer from device */
-		dma_sync_single_for_cpu((unsigned long)buffer, length,
-					(req->requesttype & USB_DIR_IN) ?
-					DMA_FROM_DEVICE : DMA_TO_DEVICE);
+		dma_unmap_single(xhci->dev, buffer_dma, length,
+				 (req->requesttype & USB_DIR_IN) ?
+				 DMA_FROM_DEVICE : DMA_TO_DEVICE);
 	}
 
 	if (ret < 0)
-- 
2.20.1


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

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

* [PATCH 11/25] usb: xhci-hcd: Simplify TRB initialization code
  2019-02-20  7:29 [PATCH 00/25] i.MX8MQ USB support Andrey Smirnov
                   ` (9 preceding siblings ...)
  2019-02-20  7:29 ` [PATCH 10/25] usb: xhci-hcd: Convert xhci_submit_control() " Andrey Smirnov
@ 2019-02-20  7:29 ` Andrey Smirnov
  2019-02-20  7:29 ` [PATCH 12/25] usb: xhci-hcd: Drop 'dma' field from struct xhci_hcd Andrey Smirnov
                   ` (14 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Andrey Smirnov @ 2019-02-20  7:29 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Current TRB initialization code in xHCI driver is:

    a) Somewhat inconsistent in endianness correctness: LE is insured
       in some places whereas in some places it isn't

    b) Somewhat inconsistent in how DMA buffer address is being
       written: some places utilize xhci_write_64, whereas others just
       assing cmd_trb field directly

    c) A bit wasetful since in a number of codepaths where TRB is used
       it is memset to zero first only to have 80+% of its fields
       changed to something else right after.

To fix all of the above introduce xhci_init_event_cmd_trb(), that will
initialize all of the fileds to desired values only once as well as
taking care of endianness.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/host/xhci-hcd.c | 128 ++++++++++++++++++++++--------------
 1 file changed, 78 insertions(+), 50 deletions(-)

diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index 4e28e24c4..b0e9a0c56 100644
--- a/drivers/usb/host/xhci-hcd.c
+++ b/drivers/usb/host/xhci-hcd.c
@@ -569,6 +569,14 @@ static void xhci_virtdev_zero_in_ctx(struct xhci_virtual_device *vdev)
 	}
 }
 
+static void xhci_init_event_cmd_trb(union xhci_trb *trb,
+				    u64 cmd_trb, u32 status, u32 flags)
+{
+	xhci_write_64(cmd_trb, &trb->event_cmd.cmd_trb);
+	writel(status, &trb->event_cmd.status);
+	writel(flags, &trb->event_cmd.flags);
+}
+
 static int xhci_virtdev_disable_slot(struct xhci_virtual_device *vdev)
 {
 	struct xhci_hcd *xhci = to_xhci_hcd(vdev->udev->host);
@@ -576,9 +584,11 @@ static int xhci_virtdev_disable_slot(struct xhci_virtual_device *vdev)
 	int ret;
 
 	/* Issue Disable Slot Command */
-	memset(&trb, 0, sizeof(union xhci_trb));
-	trb.event_cmd.flags = TRB_TYPE(TRB_DISABLE_SLOT) |
-		SLOT_ID_FOR_TRB(vdev->slot_id);
+	xhci_init_event_cmd_trb(&trb,
+				0,
+				0,
+				TRB_TYPE(TRB_DISABLE_SLOT) |
+				SLOT_ID_FOR_TRB(vdev->slot_id));
 	xhci_print_trb(xhci, &trb, "Request  DisableSlot");
 	xhci_issue_command(xhci, &trb);
 	ret = xhci_wait_for_event(xhci, TRB_COMPLETION, &trb);
@@ -598,8 +608,10 @@ static int xhci_virtdev_enable_slot(struct xhci_virtual_device *vdev)
 	int ret;
 
 	/* Issue Enable Slot Command */
-	memset(&trb, 0, sizeof(union xhci_trb));
-	trb.event_cmd.flags = TRB_TYPE(TRB_ENABLE_SLOT);
+	xhci_init_event_cmd_trb(&trb,
+				0,
+				0,
+				TRB_TYPE(TRB_ENABLE_SLOT));
 	xhci_print_trb(xhci, &trb, "Request  EnableSlot");
 	xhci_issue_command(xhci, &trb);
 	ret = xhci_wait_for_event(xhci, TRB_COMPLETION, &trb);
@@ -632,9 +644,11 @@ int xhci_virtdev_reset(struct xhci_virtual_device *vdev)
 	    SLOT_STATE_DISABLED)
 		return 0;
 
-	memset(&trb, 0, sizeof(union xhci_trb));
-	trb.event_cmd.flags = TRB_TYPE(TRB_RESET_DEV) |
-		SLOT_ID_FOR_TRB(vdev->slot_id);
+	xhci_init_event_cmd_trb(&trb,
+				0,
+				0,
+				TRB_TYPE(TRB_RESET_DEV) |
+				SLOT_ID_FOR_TRB(vdev->slot_id));
 	xhci_print_trb(xhci, &trb, "Request  Reset");
 	xhci_issue_command(xhci, &trb);
 	ret = xhci_wait_for_event(xhci, TRB_COMPLETION, &trb);
@@ -679,6 +693,7 @@ static int xhci_virtdev_update_hub_device(struct xhci_virtual_device *vdev,
 	u32 dev_info, dev_info2, tt_info;
 	u8 maxchild;
 	u16 hubchar;
+	u32 flags;
 	int ret;
 
 	out_slot = xhci_get_slot_ctx(xhci, vdev->out_ctx);
@@ -730,13 +745,15 @@ static int xhci_virtdev_update_hub_device(struct xhci_virtual_device *vdev,
 	in_slot->tt_info = cpu_to_le32(tt_info);
 
 	/* Issue Configure Endpoint or Evaluate Context Command */
-	memset(&trb, 0, sizeof(union xhci_trb));
-	xhci_write_64(vdev->in_ctx->dma, &trb.event_cmd.cmd_trb);
-	trb.event_cmd.flags = SLOT_ID_FOR_TRB(vdev->slot_id);
+	flags = SLOT_ID_FOR_TRB(vdev->slot_id);
 	if (xhci->hci_version > 0x95)
-		trb.event_cmd.flags |= TRB_TYPE(TRB_CONFIG_EP);
+		flags |= TRB_TYPE(TRB_CONFIG_EP);
 	else
-		trb.event_cmd.flags |= TRB_TYPE(TRB_EVAL_CONTEXT);
+		flags |= TRB_TYPE(TRB_EVAL_CONTEXT);
+	xhci_init_event_cmd_trb(&trb,
+				vdev->in_ctx->dma,
+				0,
+				flags);
 	xhci_print_trb(xhci, &trb, "Request  ConfigureEndpoint");
 	xhci_issue_command(xhci, &trb);
 	ret = xhci_wait_for_event(xhci, TRB_COMPLETION, &trb);
@@ -875,10 +892,11 @@ static int xhci_virtdev_configure(struct xhci_virtual_device *vdev, int config)
 	in_slot->dev_info |= cpu_to_le32(LAST_CTX(last_ctx));
 
 	/* Issue Configure Endpoint Command */
-	memset(&trb, 0, sizeof(union xhci_trb));
-	xhci_write_64(vdev->in_ctx->dma, &trb.event_cmd.cmd_trb);
-	trb.event_cmd.flags = TRB_TYPE(TRB_CONFIG_EP) |
-		SLOT_ID_FOR_TRB(vdev->slot_id);
+	xhci_init_event_cmd_trb(&trb,
+				vdev->in_ctx->dma,
+				0,
+				TRB_TYPE(TRB_CONFIG_EP) |
+				SLOT_ID_FOR_TRB(vdev->slot_id));
 	xhci_print_trb(xhci, &trb, "Request  ConfigureEndpoint");
 	xhci_issue_command(xhci, &trb);
 	ret = xhci_wait_for_event(xhci, TRB_COMPLETION, &trb);
@@ -895,10 +913,11 @@ static int xhci_virtdev_deconfigure(struct xhci_virtual_device *vdev)
 	int ret;
 
 	/* Issue Deconfigure Endpoint Command */
-	memset(&trb, 0, sizeof(union xhci_trb));
-	xhci_write_64(vdev->in_ctx->dma, &trb.event_cmd.cmd_trb);
-	trb.event_cmd.flags = TRB_TYPE(TRB_CONFIG_EP) | TRB_DC |
-		SLOT_ID_FOR_TRB(vdev->slot_id);
+	xhci_init_event_cmd_trb(&trb,
+				vdev->in_ctx->dma,
+				0,
+				TRB_TYPE(TRB_CONFIG_EP) | TRB_DC |
+				SLOT_ID_FOR_TRB(vdev->slot_id));
 	xhci_print_trb(xhci, &trb, "Request  DeconfigureEndpoint");
 	xhci_issue_command(xhci, &trb);
 	ret = xhci_wait_for_event(xhci, TRB_COMPLETION, &trb);
@@ -1009,6 +1028,7 @@ static int xhci_virtdev_setup(struct xhci_virtual_device *vdev,
 	struct xhci_slot_ctx *in_slot;
 	struct xhci_ep_ctx *in_ep;
 	union xhci_trb trb;
+	u32 flags;
 	int ret;
 
 	in_slot = xhci_get_slot_ctx(xhci, vdev->in_ctx);
@@ -1043,12 +1063,14 @@ static int xhci_virtdev_setup(struct xhci_virtual_device *vdev,
 	in_icc->drop_flags = 0;
 
 	/* Issue Address Device Command */
-	memset(&trb, 0, sizeof(union xhci_trb));
-	xhci_write_64(vdev->in_ctx->dma, &trb.event_cmd.cmd_trb);
-	trb.event_cmd.flags = TRB_TYPE(TRB_ADDR_DEV) |
+	flags = TRB_TYPE(TRB_ADDR_DEV) |
 		SLOT_ID_FOR_TRB(vdev->slot_id);
 	if (setup == SETUP_CONTEXT_ONLY)
-		trb.event_cmd.flags |= TRB_BSR;
+		flags |= TRB_BSR;
+	xhci_init_event_cmd_trb(&trb,
+				vdev->in_ctx->dma,
+				0,
+				flags);
 	xhci_print_trb(xhci, &trb, "Request  AddressDevice");
 	xhci_issue_command(xhci, &trb);
 	ret = xhci_wait_for_event(xhci, TRB_COMPLETION, &trb);
@@ -1105,6 +1127,7 @@ static int xhci_submit_normal(struct usb_device *udev, unsigned long pipe,
 	u8 epaddr = (usb_pipein(pipe) ? USB_DIR_IN : USB_DIR_OUT) |
 		usb_pipeendpoint(pipe);
 	u8 epi = xhci_get_endpoint_index(epaddr, usb_pipetype(pipe));
+	u32 flags;
 	int ret;
 
 	vdev = xhci_find_virtdev(xhci, udev);
@@ -1126,13 +1149,14 @@ static int xhci_submit_normal(struct usb_device *udev, unsigned long pipe,
 		return -EFAULT;
 
 	/* Normal TRB */
-	memset(&trb, 0, sizeof(union xhci_trb));
-	trb.event_cmd.cmd_trb = cpu_to_le64(buffer_dma);
 	/* FIXME: TD remainder */
-	trb.event_cmd.status = TRB_LEN(length) | TRB_INTR_TARGET(0);
-	trb.event_cmd.flags = TRB_TYPE(TRB_NORMAL) | TRB_IOC;
+	flags = TRB_TYPE(TRB_NORMAL) | TRB_IOC;
 	if (usb_pipein(pipe))
-		trb.event_cmd.flags |= TRB_ISP;
+		flags |= TRB_ISP;
+	xhci_init_event_cmd_trb(&trb,
+				buffer_dma,
+				TRB_LEN(length) | TRB_INTR_TARGET(0),
+				flags);
 	xhci_print_trb(xhci, &trb, "Request  Normal");
 	xhci_virtdev_issue_transfer(vdev, epi, &trb, true);
 	ret = xhci_wait_for_event(xhci, TRB_TRANSFER, &trb);
@@ -1170,6 +1194,8 @@ static int xhci_submit_control(struct usb_device *udev, unsigned long pipe,
 	dma_addr_t buffer_dma = 0;
 	union xhci_trb trb;
 	u16 typeReq = (req->requesttype << 8) | req->request;
+	u64 field[2];
+	u32 flags;
 	int ret;
 
 	dev_dbg(xhci->dev, "%s req %u (%#x), type %u (%#x), value %u (%#x), index %u (%#x), length %u (%#x)\n",
@@ -1212,45 +1238,47 @@ static int xhci_submit_control(struct usb_device *udev, unsigned long pipe,
 		if (dma_mapping_error(xhci->dev, buffer_dma))
 			return -EFAULT;
 	}
-
 	/* Setup TRB */
-	memset(&trb, 0, sizeof(union xhci_trb));
-	trb.generic.field[0] = le16_to_cpu(req->value) << 16 |
+	field[0] = le16_to_cpu(req->value) << 16 |
 		req->request << 8 | req->requesttype;
-	trb.generic.field[1] = le16_to_cpu(req->length) << 16 |
+	field[1] = le16_to_cpu(req->length) << 16 |
 		le16_to_cpu(req->index);
-	trb.event_cmd.status = TRB_LEN(8) | TRB_INTR_TARGET(0);
-	trb.event_cmd.flags = TRB_TYPE(TRB_SETUP) | TRB_IDT;
+	flags = TRB_TYPE(TRB_SETUP) | TRB_IDT;
 	if (xhci->hci_version == 0x100 && length > 0) {
 		if (req->requesttype & USB_DIR_IN)
-			trb.event_cmd.flags |= TRB_TX_TYPE(TRB_DATA_IN);
+			flags |= TRB_TX_TYPE(TRB_DATA_IN);
 		else
-			trb.event_cmd.flags |= TRB_TX_TYPE(TRB_DATA_OUT);
+			flags |= TRB_TX_TYPE(TRB_DATA_OUT);
 	}
+	xhci_init_event_cmd_trb(&trb,
+				field[1] << 32 | field[0],
+				TRB_LEN(8) | TRB_INTR_TARGET(0),
+				flags);
 	xhci_print_trb(xhci, &trb, "Request  Setup ");
 	xhci_virtdev_issue_transfer(vdev, 0, &trb, false);
 
 	/* Data TRB */
 	if (length > 0) {
-		memset(&trb, 0, sizeof(union xhci_trb));
-		trb.event_cmd.cmd_trb = cpu_to_le64(buffer_dma);
 		/* FIXME: TD remainder */
-		trb.event_cmd.status = TRB_LEN(length) | TRB_INTR_TARGET(0);
-		trb.event_cmd.flags = TRB_TYPE(TRB_DATA) | TRB_IOC;
+		flags = TRB_TYPE(TRB_DATA) | TRB_IOC;
 		if (req->requesttype & USB_DIR_IN)
-			trb.event_cmd.flags |= TRB_ISP | TRB_DIR_IN;
+			flags |= TRB_ISP | TRB_DIR_IN;
+		xhci_init_event_cmd_trb(&trb,
+					buffer_dma,
+					TRB_LEN(length) | TRB_INTR_TARGET(0),
+					flags);
 		xhci_print_trb(xhci, &trb, "Request  Data  ");
 		xhci_virtdev_issue_transfer(vdev, 0, &trb, false);
 	}
 
 	/* Status TRB */
-	memset(&trb, 0, sizeof(union xhci_trb));
-	trb.event_cmd.status = TRB_INTR_TARGET(0);
-	if (length > 0 && req->requesttype & USB_DIR_IN)
-		trb.event_cmd.flags = 0;
-	else
-		trb.event_cmd.flags = TRB_DIR_IN;
-	trb.event_cmd.flags |= TRB_TYPE(TRB_STATUS) | TRB_IOC;
+	flags = TRB_TYPE(TRB_STATUS) | TRB_IOC;
+	if (!(length > 0 && req->requesttype & USB_DIR_IN))
+		flags |= TRB_DIR_IN;
+	xhci_init_event_cmd_trb(&trb,
+				0,
+				TRB_INTR_TARGET(0),
+				flags);
 	xhci_print_trb(xhci, &trb, "Request  Status");
 	xhci_virtdev_issue_transfer(vdev, 0, &trb, true);
 
-- 
2.20.1


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

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

* [PATCH 12/25] usb: xhci-hcd: Drop 'dma' field from struct xhci_hcd
  2019-02-20  7:29 [PATCH 00/25] i.MX8MQ USB support Andrey Smirnov
                   ` (10 preceding siblings ...)
  2019-02-20  7:29 ` [PATCH 11/25] usb: xhci-hcd: Simplify TRB initialization code Andrey Smirnov
@ 2019-02-20  7:29 ` Andrey Smirnov
  2019-02-20  7:29 ` [PATCH 13/25] usb: xhci-hcd: Check usb_pipein(pipe) only once in xhci_submit_normal() Andrey Smirnov
                   ` (13 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Andrey Smirnov @ 2019-02-20  7:29 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Drop 'dma' field from struct xhci_hcd since it is not really used
anywhere.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/host/xhci-hcd.c | 2 +-
 drivers/usb/host/xhci.h     | 1 -
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index b0e9a0c56..6a6291620 100644
--- a/drivers/usb/host/xhci-hcd.c
+++ b/drivers/usb/host/xhci-hcd.c
@@ -1359,7 +1359,7 @@ static void xhci_dma_alloc(struct xhci_hcd *xhci)
 	num_ep = max(MAX_EP_RINGS, MIN_EP_RINGS + num_ep);
 	xhci->dma_size += num_ep * sz_ep;
 
-	p = xhci->dma = dma_alloc_coherent(xhci->dma_size, DMA_ADDRESS_BROKEN);
+	p = dma_alloc_coherent(xhci->dma_size, DMA_ADDRESS_BROKEN);
 
 	xhci->sp = p; p += sz_sp;
 	xhci->dcbaa = p; p += sz_dca;
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 9f2d57675..dfbfe579b 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1242,7 +1242,6 @@ struct xhci_hcd {
 	int num_sp;
 	int page_size;
 	int page_shift;
-	void *dma;
 	size_t dma_size;
 	__le64 *dcbaa;
 	void *sp;
-- 
2.20.1


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

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

* [PATCH 13/25] usb: xhci-hcd: Check usb_pipein(pipe) only once in xhci_submit_normal()
  2019-02-20  7:29 [PATCH 00/25] i.MX8MQ USB support Andrey Smirnov
                   ` (11 preceding siblings ...)
  2019-02-20  7:29 ` [PATCH 12/25] usb: xhci-hcd: Drop 'dma' field from struct xhci_hcd Andrey Smirnov
@ 2019-02-20  7:29 ` Andrey Smirnov
  2019-02-20  7:29 ` [PATCH 14/25] usb: xhci-hcd: Initialize TRT flag for xHCI >= 1.0 Andrey Smirnov
                   ` (12 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Andrey Smirnov @ 2019-02-20  7:29 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Simplfy xhci_submit_normal()'s logic a bit by using helper variables
and making sure that usb_pipein(pipe) is only called once.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/host/xhci-hcd.c | 28 ++++++++++++++++------------
 1 file changed, 16 insertions(+), 12 deletions(-)

diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index 6a6291620..c8327c88f 100644
--- a/drivers/usb/host/xhci-hcd.c
+++ b/drivers/usb/host/xhci-hcd.c
@@ -1120,16 +1120,26 @@ static int xhci_submit_normal(struct usb_device *udev, unsigned long pipe,
 {
 	struct usb_host *host = udev->host;
 	struct xhci_hcd *xhci = to_xhci_hcd(host);
+	enum dma_data_direction dma_direction;
 	struct xhci_virtual_device *vdev;
 	struct xhci_slot_ctx *out_slot;
 	dma_addr_t buffer_dma;
 	union xhci_trb trb;
-	u8 epaddr = (usb_pipein(pipe) ? USB_DIR_IN : USB_DIR_OUT) |
-		usb_pipeendpoint(pipe);
-	u8 epi = xhci_get_endpoint_index(epaddr, usb_pipetype(pipe));
-	u32 flags;
+	u8 epaddr = usb_pipeendpoint(pipe);
+	u8 epi;
+	u32 flags = TRB_TYPE(TRB_NORMAL) | TRB_IOC;
 	int ret;
 
+	if (usb_pipein(pipe)) {
+		epaddr |= USB_DIR_IN;
+		flags |= TRB_ISP;
+		dma_direction = DMA_FROM_DEVICE;
+	} else {
+		epaddr |= USB_DIR_OUT;
+		dma_direction = DMA_TO_DEVICE;
+	}
+
+	epi = xhci_get_endpoint_index(epaddr, usb_pipetype(pipe));
 	vdev = xhci_find_virtdev(xhci, udev);
 	if (!vdev)
 		return -ENODEV;
@@ -1143,16 +1153,12 @@ static int xhci_submit_normal(struct usb_device *udev, unsigned long pipe,
 
 	/* pass ownership of data buffer to device */
 	buffer_dma = dma_map_single(xhci->dev, buffer, length,
-				    usb_pipein(pipe) ?
-				    DMA_FROM_DEVICE : DMA_TO_DEVICE);
+				    dma_direction);
 	if (dma_mapping_error(xhci->dev, buffer_dma))
 		return -EFAULT;
 
 	/* Normal TRB */
 	/* FIXME: TD remainder */
-	flags = TRB_TYPE(TRB_NORMAL) | TRB_IOC;
-	if (usb_pipein(pipe))
-		flags |= TRB_ISP;
 	xhci_init_event_cmd_trb(&trb,
 				buffer_dma,
 				TRB_LEN(length) | TRB_INTR_TARGET(0),
@@ -1164,9 +1170,7 @@ static int xhci_submit_normal(struct usb_device *udev, unsigned long pipe,
 
 	/* Regain ownership of data buffer from device */
 	dma_unmap_single(xhci->dev, buffer_dma, length,
-			 usb_pipein(pipe) ?
-			 DMA_FROM_DEVICE : DMA_TO_DEVICE);
-
+			 dma_direction);
 	switch (ret) {
 	case -COMP_SHORT_TX:
 		udev->status = 0;
-- 
2.20.1


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

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

* [PATCH 14/25] usb: xhci-hcd: Initialize TRT flag for xHCI >= 1.0
  2019-02-20  7:29 [PATCH 00/25] i.MX8MQ USB support Andrey Smirnov
                   ` (12 preceding siblings ...)
  2019-02-20  7:29 ` [PATCH 13/25] usb: xhci-hcd: Check usb_pipein(pipe) only once in xhci_submit_normal() Andrey Smirnov
@ 2019-02-20  7:29 ` Andrey Smirnov
  2019-02-20  7:29 ` [PATCH 15/25] usb: xhci-hcd: Simplify route string building loop Andrey Smirnov
                   ` (11 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Andrey Smirnov @ 2019-02-20  7:29 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Initialize TRT flag for xHCI >= 1.0, not just == 1.0. This is what
Linux xHCI driver does.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/host/xhci-hcd.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index c8327c88f..517446379 100644
--- a/drivers/usb/host/xhci-hcd.c
+++ b/drivers/usb/host/xhci-hcd.c
@@ -1248,7 +1248,7 @@ static int xhci_submit_control(struct usb_device *udev, unsigned long pipe,
 	field[1] = le16_to_cpu(req->length) << 16 |
 		le16_to_cpu(req->index);
 	flags = TRB_TYPE(TRB_SETUP) | TRB_IDT;
-	if (xhci->hci_version == 0x100 && length > 0) {
+	if (xhci->hci_version >= 0x100 && length > 0) {
 		if (req->requesttype & USB_DIR_IN)
 			flags |= TRB_TX_TYPE(TRB_DATA_IN);
 		else
-- 
2.20.1


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

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

* [PATCH 15/25] usb: xhci-hcd: Simplify route string building loop
  2019-02-20  7:29 [PATCH 00/25] i.MX8MQ USB support Andrey Smirnov
                   ` (13 preceding siblings ...)
  2019-02-20  7:29 ` [PATCH 14/25] usb: xhci-hcd: Initialize TRT flag for xHCI >= 1.0 Andrey Smirnov
@ 2019-02-20  7:29 ` Andrey Smirnov
  2019-02-20  7:29 ` [PATCH 16/25] usb: xhci-hcd: Make use of lo_hi_readq/writeq() Andrey Smirnov
                   ` (10 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Andrey Smirnov @ 2019-02-20  7:29 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Simplify route string building loop by avoiding checking
top_dev->parent->descriptor->bDeviceClass twice.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/host/xhci-hcd.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index 517446379..32a6ccd5c 100644
--- a/drivers/usb/host/xhci-hcd.c
+++ b/drivers/usb/host/xhci-hcd.c
@@ -947,10 +947,12 @@ static int xhci_virtdev_init(struct xhci_virtual_device *vdev)
 	 */
 	for (top_dev = vdev->udev; top_dev->parent && top_dev->parent->parent;
 	     top_dev = top_dev->parent) {
-		if (top_dev->parent->descriptor->bDeviceClass == USB_CLASS_HUB)
-			route = (route << 4) | (top_dev->portnr & 0xf);
-		if (top_dev->parent->descriptor->bDeviceClass == USB_CLASS_HUB &&
-		    top_dev->parent->speed != USB_SPEED_LOW &&
+		if (top_dev->parent->descriptor->bDeviceClass != USB_CLASS_HUB)
+			continue;
+
+		route = (route << 4) | (top_dev->portnr & 0xf);
+
+		if (top_dev->parent->speed != USB_SPEED_LOW &&
 		    top_dev->parent->speed != USB_SPEED_FULL) {
 			on_hs_hub = true;
 			if (!hs_slot_id) {
-- 
2.20.1


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

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

* [PATCH 16/25] usb: xhci-hcd: Make use of lo_hi_readq/writeq()
  2019-02-20  7:29 [PATCH 00/25] i.MX8MQ USB support Andrey Smirnov
                   ` (14 preceding siblings ...)
  2019-02-20  7:29 ` [PATCH 15/25] usb: xhci-hcd: Simplify route string building loop Andrey Smirnov
@ 2019-02-20  7:29 ` Andrey Smirnov
  2019-02-20  7:29 ` [PATCH 17/25] phy: core: Assume EPROBE_DEFER in of_phy_provider_lookup() Andrey Smirnov
                   ` (9 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Andrey Smirnov @ 2019-02-20  7:29 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Make use of lo_hi_readq/writeq() to implement xhci_read/write_64()
helpers, same as it is done in the Linux kernel.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/host/xhci.h | 14 ++++----------
 1 file changed, 4 insertions(+), 10 deletions(-)

diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index dfbfe579b..84a14dd1f 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -24,6 +24,8 @@
 #ifndef __XHCI_H
 #define __XHCI_H
 
+#include <io-64-nonatomic-lo-hi.h>
+
 #define NUM_COMMAND_TRBS	8
 #define NUM_TRANSFER_TRBS	8
 #define NUM_EVENT_SEGM		1	/* only one supported */
@@ -1165,19 +1167,11 @@ struct xhci_erst_entry {
  */
 static inline u64 xhci_read_64(__le64 __iomem *regs)
 {
-	__u32 __iomem *ptr = (__u32 __iomem *)regs;
-	u64 val_lo = readl(ptr);
-	u64 val_hi = readl(ptr + 1);
-	return val_lo + (val_hi << 32);
+	return lo_hi_readq(regs);
 }
 static inline void xhci_write_64(const u64 val, __le64 __iomem *regs)
 {
-	__u32 __iomem *ptr = (__u32 __iomem *)regs;
-	u32 val_lo = lower_32_bits(val);
-	u32 val_hi = upper_32_bits(val);
-
-	writel(val_lo, ptr);
-	writel(val_hi, ptr + 1);
+	lo_hi_writeq(val, regs);
 }
 
 /*
-- 
2.20.1


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

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

* [PATCH 17/25] phy: core: Assume EPROBE_DEFER in of_phy_provider_lookup()
  2019-02-20  7:29 [PATCH 00/25] i.MX8MQ USB support Andrey Smirnov
                   ` (15 preceding siblings ...)
  2019-02-20  7:29 ` [PATCH 16/25] usb: xhci-hcd: Make use of lo_hi_readq/writeq() Andrey Smirnov
@ 2019-02-20  7:29 ` Andrey Smirnov
  2019-02-20  7:29 ` [PATCH 18/25] phy: Port i.MX8MQ USB PHY driver from Linux Andrey Smirnov
                   ` (8 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Andrey Smirnov @ 2019-02-20  7:29 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

In order to support PHY driver probe deferral change the code to
assume EPROBE_DEFER instead of ENODEV when requested PHY is missing
from phy_provider_list.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/phy/phy-core.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index 9d6288fc0..066a887a2 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -227,7 +227,7 @@ static struct phy_provider *of_phy_provider_lookup(struct device_node *node)
 				return phy_provider;
 	}
 
-	return ERR_PTR(-ENODEV);
+	return ERR_PTR(-EPROBE_DEFER);
 }
 
 /**
@@ -254,7 +254,7 @@ static struct phy *_of_phy_get(struct device_node *np, int index)
 
 	phy_provider = of_phy_provider_lookup(args.np);
 	if (IS_ERR(phy_provider)) {
-		return ERR_PTR(-ENODEV);
+		return ERR_CAST(phy_provider);
 	}
 
 	return phy_provider->of_xlate(phy_provider->dev, &args);
-- 
2.20.1


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

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

* [PATCH 18/25] phy: Port i.MX8MQ USB PHY driver from Linux
  2019-02-20  7:29 [PATCH 00/25] i.MX8MQ USB support Andrey Smirnov
                   ` (16 preceding siblings ...)
  2019-02-20  7:29 ` [PATCH 17/25] phy: core: Assume EPROBE_DEFER in of_phy_provider_lookup() Andrey Smirnov
@ 2019-02-20  7:29 ` Andrey Smirnov
  2019-02-20  7:29 ` [PATCH 19/25] clk: Drop separate definitions of clk_put() Andrey Smirnov
                   ` (7 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Andrey Smirnov @ 2019-02-20  7:29 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Port i.MX8MQ USB PHY driver from Linux.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/phy/Kconfig                        |   2 +
 drivers/phy/Makefile                       |   1 +
 drivers/phy/freescale/Kconfig              |   4 +
 drivers/phy/freescale/Makefile             |   1 +
 drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 130 +++++++++++++++++++++
 5 files changed, 138 insertions(+)
 create mode 100644 drivers/phy/freescale/Kconfig
 create mode 100644 drivers/phy/freescale/Makefile
 create mode 100644 drivers/phy/freescale/phy-fsl-imx8mq-usb.c

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index b0c8b9bf0..b5cefb2ff 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -22,4 +22,6 @@ config USB_NOP_XCEIV
 	  built-in with usb ip or which are autonomous and doesn't require any
 	  phy programming such as ISP1x04 etc.
 
+source "drivers/phy/freescale/Kconfig"
+
 endif
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 8fc85953b..179c55e60 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -4,3 +4,4 @@
 
 obj-$(CONFIG_GENERIC_PHY)		+= phy-core.o
 obj-$(CONFIG_USB_NOP_XCEIV)		+= usb-nop-xceiv.o
+obj-y					+= freescale/
diff --git a/drivers/phy/freescale/Kconfig b/drivers/phy/freescale/Kconfig
new file mode 100644
index 000000000..8e56dd7e7
--- /dev/null
+++ b/drivers/phy/freescale/Kconfig
@@ -0,0 +1,4 @@
+config PHY_FSL_IMX8MQ_USB
+	bool "Freescale i.MX8M USB3 PHY"
+	default SOC_IMX8MQ
+
diff --git a/drivers/phy/freescale/Makefile b/drivers/phy/freescale/Makefile
new file mode 100644
index 000000000..dc2b3f1f2
--- /dev/null
+++ b/drivers/phy/freescale/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_PHY_FSL_IMX8MQ_USB)	+= phy-fsl-imx8mq-usb.o
diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
new file mode 100644
index 000000000..1aef2b300
--- /dev/null
+++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (c) 2017 NXP. */
+
+#include <common.h>
+#include <init.h>
+#include <io.h>
+#include <of.h>
+#include <errno.h>
+#include <driver.h>
+#include <malloc.h>
+#include <usb/phy.h>
+#include <linux/phy/phy.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+
+#define PHY_CTRL0			0x0
+#define PHY_CTRL0_REF_SSP_EN		BIT(2)
+
+#define PHY_CTRL1			0x4
+#define PHY_CTRL1_RESET			BIT(0)
+#define PHY_CTRL1_COMMONONN		BIT(1)
+#define PHY_CTRL1_ATERESET		BIT(3)
+#define PHY_CTRL1_VDATSRCENB0		BIT(19)
+#define PHY_CTRL1_VDATDETENB0		BIT(20)
+
+#define PHY_CTRL2			0x8
+#define PHY_CTRL2_TXENABLEN0		BIT(8)
+
+struct imx8mq_usb_phy {
+	struct phy *phy;
+	struct clk *clk;
+	void __iomem *base;
+};
+
+static int imx8mq_usb_phy_init(struct phy *phy)
+{
+	struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
+	u32 value;
+
+	value = readl(imx_phy->base + PHY_CTRL1);
+	value &= ~(PHY_CTRL1_VDATSRCENB0 | PHY_CTRL1_VDATDETENB0 |
+		   PHY_CTRL1_COMMONONN);
+	value |= PHY_CTRL1_RESET | PHY_CTRL1_ATERESET;
+	writel(value, imx_phy->base + PHY_CTRL1);
+
+	value = readl(imx_phy->base + PHY_CTRL0);
+	value |= PHY_CTRL0_REF_SSP_EN;
+	writel(value, imx_phy->base + PHY_CTRL0);
+
+	value = readl(imx_phy->base + PHY_CTRL2);
+	value |= PHY_CTRL2_TXENABLEN0;
+	writel(value, imx_phy->base + PHY_CTRL2);
+
+	value = readl(imx_phy->base + PHY_CTRL1);
+	value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET);
+	writel(value, imx_phy->base + PHY_CTRL1);
+
+	return 0;
+}
+
+static int imx8mq_phy_power_on(struct phy *phy)
+{
+	struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
+
+	return clk_enable(imx_phy->clk);
+}
+
+static int imx8mq_phy_power_off(struct phy *phy)
+{
+	struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
+
+	clk_disable(imx_phy->clk);
+
+	return 0;
+}
+
+static struct phy_ops imx8mq_usb_phy_ops = {
+	.init		= imx8mq_usb_phy_init,
+	.power_on	= imx8mq_phy_power_on,
+	.power_off	= imx8mq_phy_power_off,
+};
+
+static struct phy *imx8mq_usb_phy_xlate(struct device_d *dev,
+					struct of_phandle_args *args)
+{
+	struct imx8mq_usb_phy *imx_phy = dev->priv;
+
+	return imx_phy->phy;
+}
+
+static int imx8mq_usb_phy_probe(struct device_d *dev)
+{
+	struct phy_provider *phy_provider;
+	struct imx8mq_usb_phy *imx_phy;
+
+	imx_phy = xzalloc(sizeof(*imx_phy));
+
+	dev->priv = imx_phy;
+
+	imx_phy->clk = clk_get(dev, "phy");
+	if (IS_ERR(imx_phy->clk))
+		return PTR_ERR(imx_phy->clk);
+
+	imx_phy->base = dev_get_mem_region(dev, 0);
+	if (IS_ERR(imx_phy->base))
+		return PTR_ERR(imx_phy->base);
+
+	imx_phy->phy = phy_create(dev, NULL, &imx8mq_usb_phy_ops, NULL);
+	if (IS_ERR(imx_phy->phy))
+		return PTR_ERR(imx_phy->phy);
+
+	phy_set_drvdata(imx_phy->phy, imx_phy);
+
+	phy_provider = of_phy_provider_register(dev, imx8mq_usb_phy_xlate);
+
+	return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id imx8mq_usb_phy_of_match[] = {
+	{.compatible = "fsl,imx8mq-usb-phy",},
+	{ },
+};
+
+static struct driver_d imx8mq_usb_phy_driver = {
+	.name	= "imx8mq-usb-phy",
+	.probe	= imx8mq_usb_phy_probe,
+	.of_compatible = DRV_OF_COMPAT(imx8mq_usb_phy_of_match),
+};
+device_platform_driver(imx8mq_usb_phy_driver);
-- 
2.20.1


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

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

* [PATCH 19/25] clk: Drop separate definitions of clk_put()
  2019-02-20  7:29 [PATCH 00/25] i.MX8MQ USB support Andrey Smirnov
                   ` (17 preceding siblings ...)
  2019-02-20  7:29 ` [PATCH 18/25] phy: Port i.MX8MQ USB PHY driver from Linux Andrey Smirnov
@ 2019-02-20  7:29 ` Andrey Smirnov
  2019-02-20  7:29 ` [PATCH 20/25] include/usb: Import USB_SPEED_SUPER_PLUS from Linux Andrey Smirnov
                   ` (6 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Andrey Smirnov @ 2019-02-20  7:29 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Regardless of the value of CONFIG_HAVE_CLK, clk_put() implementation
is always a no-op. Move the definition to linux/clk.h and drop the
rest of the code implementing it.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/clk/clkdev.c |  5 -----
 include/linux/clk.h  | 21 ++++-----------------
 2 files changed, 4 insertions(+), 22 deletions(-)

diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index abdc41527..f67a5c4d9 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -189,11 +189,6 @@ struct clk *clk_get(struct device_d *dev, const char *con_id)
 }
 EXPORT_SYMBOL(clk_get);
 
-void clk_put(struct clk *clk)
-{
-}
-EXPORT_SYMBOL(clk_put);
-
 void clkdev_add(struct clk_lookup *cl)
 {
 	if (cl->dev_id)
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 978a0a8a9..38c86e0b4 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -75,19 +75,6 @@ void clk_disable(struct clk *clk);
  */
 unsigned long clk_get_rate(struct clk *clk);
 
-/**
- * clk_put	- "free" the clock source
- * @clk: clock source
- *
- * Note: drivers must ensure that all clk_enable calls made on this
- * clock source are balanced by clk_disable calls prior to calling
- * this function.
- *
- * clk_put should not be called from within interrupt context.
- */
-void clk_put(struct clk *clk);
-
-
 /*
  * The remaining APIs are optional for machine class support.
  */
@@ -180,10 +167,6 @@ static inline unsigned long clk_get_rate(struct clk *clk)
 	return 0;
 }
 
-static inline void clk_put(struct clk *clk)
-{
-}
-
 static inline long clk_round_rate(struct clk *clk, unsigned long rate)
 {
 	return 0;
@@ -195,6 +178,10 @@ static inline int clk_set_rate(struct clk *clk, unsigned long rate)
 }
 #endif
 
+static inline void clk_put(struct clk *clk)
+{
+}
+
 #ifdef CONFIG_COMMON_CLK
 
 #include <linux/list.h>
-- 
2.20.1


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

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

* [PATCH 20/25] include/usb: Import USB_SPEED_SUPER_PLUS from Linux
  2019-02-20  7:29 [PATCH 00/25] i.MX8MQ USB support Andrey Smirnov
                   ` (18 preceding siblings ...)
  2019-02-20  7:29 ` [PATCH 19/25] clk: Drop separate definitions of clk_put() Andrey Smirnov
@ 2019-02-20  7:29 ` Andrey Smirnov
  2019-02-20  7:29 ` [PATCH 21/25] clk: Import a subset of clk_bulk API " Andrey Smirnov
                   ` (5 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Andrey Smirnov @ 2019-02-20  7:29 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Import USB_SPEED_SUPER_PLUS constant from Linux to support porting
kernel code that uses it.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 include/usb/ch9.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/usb/ch9.h b/include/usb/ch9.h
index b44d41e85..89d83e0d0 100644
--- a/include/usb/ch9.h
+++ b/include/usb/ch9.h
@@ -913,6 +913,7 @@ enum usb_device_speed {
 	USB_SPEED_HIGH,				/* usb 2.0 */
 	USB_SPEED_WIRELESS,			/* wireless (usb 2.5) */
 	USB_SPEED_SUPER,			/* usb 3.0 */
+	USB_SPEED_SUPER_PLUS,			/* usb 3.1 */
 };
 
 
-- 
2.20.1


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

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

* [PATCH 21/25] clk: Import a subset of clk_bulk API from Linux
  2019-02-20  7:29 [PATCH 00/25] i.MX8MQ USB support Andrey Smirnov
                   ` (19 preceding siblings ...)
  2019-02-20  7:29 ` [PATCH 20/25] include/usb: Import USB_SPEED_SUPER_PLUS from Linux Andrey Smirnov
@ 2019-02-20  7:29 ` Andrey Smirnov
  2019-02-20  7:29 ` [PATCH 22/25] usb: Import DWC3 USB controller driver " Andrey Smirnov
                   ` (4 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Andrey Smirnov @ 2019-02-20  7:29 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Import a subset of clk_bulk API from Linux to support porting kernel
code that uses it.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/clk/Makefile   |   3 +-
 drivers/clk/clk-bulk.c | 102 +++++++++++++++++++++++++++++++++++++++++
 include/linux/clk.h    |  98 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 202 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/clk-bulk.c

diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index cd4026c94..34c44fff9 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -1,7 +1,8 @@
 obj-$(CONFIG_COMMON_CLK)	+= clk.o clk-fixed.o clk-divider.o clk-fixed-factor.o \
 				clk-mux.o clk-gate.o clk-composite.o \
 				clk-fractional-divider.o clk-conf.o \
-				clk-gate-shared.o clk-gpio.o
+				clk-gate-shared.o clk-gpio.o \
+				clk-bulk.o
 obj-$(CONFIG_CLKDEV_LOOKUP)	+= clkdev.o
 
 obj-$(CONFIG_ARCH_MVEBU)	+= mvebu/
diff --git a/drivers/clk/clk-bulk.c b/drivers/clk/clk-bulk.c
new file mode 100644
index 000000000..ddbe32f9c
--- /dev/null
+++ b/drivers/clk/clk-bulk.c
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2017 NXP
+ *
+ * Dong Aisheng <aisheng.dong@nxp.com>
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <malloc.h>
+#include <stringlist.h>
+#include <complete.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/clk/clk-conf.h>
+
+void clk_bulk_put(int num_clks, struct clk_bulk_data *clks)
+{
+	while (--num_clks >= 0) {
+		clk_put(clks[num_clks].clk);
+		clks[num_clks].clk = NULL;
+	}
+}
+EXPORT_SYMBOL_GPL(clk_bulk_put);
+
+int __must_check clk_bulk_get(struct device_d *dev, int num_clks,
+			      struct clk_bulk_data *clks)
+{
+	int ret;
+	int i;
+
+	for (i = 0; i < num_clks; i++)
+		clks[i].clk = NULL;
+
+	for (i = 0; i < num_clks; i++) {
+		clks[i].clk = clk_get(dev, clks[i].id);
+		if (IS_ERR(clks[i].clk)) {
+			ret = PTR_ERR(clks[i].clk);
+			if (ret != -EPROBE_DEFER)
+				dev_err(dev, "Failed to get clk '%s': %d\n",
+					clks[i].id, ret);
+			clks[i].clk = NULL;
+			goto err;
+		}
+	}
+
+	return 0;
+
+err:
+	clk_bulk_put(i, clks);
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_bulk_get);
+
+/**
+ * clk_bulk_disable - gate a set of clocks
+ * @num_clks: the number of clk_bulk_data
+ * @clks: the clk_bulk_data table being gated
+ *
+ * clk_bulk_disable must not sleep, which differentiates it from
+ * clk_bulk_unprepare. clk_bulk_disable must be called before
+ * clk_bulk_unprepare.
+ */
+void clk_bulk_disable(int num_clks, const struct clk_bulk_data *clks)
+{
+
+	while (--num_clks >= 0)
+		clk_disable(clks[num_clks].clk);
+}
+EXPORT_SYMBOL_GPL(clk_bulk_disable);
+
+/**
+ * clk_bulk_enable - ungate a set of clocks
+ * @num_clks: the number of clk_bulk_data
+ * @clks: the clk_bulk_data table being ungated
+ *
+ * clk_bulk_enable must not sleep
+ * Returns 0 on success, -EERROR otherwise.
+ */
+int __must_check clk_bulk_enable(int num_clks, const struct clk_bulk_data *clks)
+{
+	int ret;
+	int i;
+
+	for (i = 0; i < num_clks; i++) {
+		ret = clk_enable(clks[i].clk);
+		if (ret) {
+			pr_err("Failed to enable clk '%s': %d\n",
+				clks[i].id, ret);
+			goto err;
+		}
+	}
+
+	return 0;
+
+err:
+	clk_bulk_disable(i, clks);
+
+	return  ret;
+}
+EXPORT_SYMBOL_GPL(clk_bulk_enable);
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 38c86e0b4..961fc89ba 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -25,6 +25,22 @@ struct device_d;
  */
 struct clk;
 
+/**
+ * struct clk_bulk_data - Data used for bulk clk operations.
+ *
+ * @id: clock consumer ID
+ * @clk: struct clk * to store the associated clock
+ *
+ * The CLK APIs provide a series of clk_bulk_() API calls as
+ * a convenience to consumers which require multiple clks.  This
+ * structure is used to manage data for these calls.
+ */
+struct clk_bulk_data {
+	const char		*id;
+	struct clk		*clk;
+};
+
+
 #ifdef CONFIG_HAVE_CLK
 
 /**
@@ -44,6 +60,29 @@ struct clk;
  */
 struct clk *clk_get(struct device_d *dev, const char *id);
 
+/**
+ * clk_bulk_get - lookup and obtain a number of references to clock producer.
+ * @dev: device for clock "consumer"
+ * @num_clks: the number of clk_bulk_data
+ * @clks: the clk_bulk_data table of consumer
+ *
+ * This helper function allows drivers to get several clk consumers in one
+ * operation. If any of the clk cannot be acquired then any clks
+ * that were obtained will be freed before returning to the caller.
+ *
+ * Returns 0 if all clocks specified in clk_bulk_data table are obtained
+ * successfully, or valid IS_ERR() condition containing errno.
+ * The implementation uses @dev and @clk_bulk_data.id to determine the
+ * clock consumer, and thereby the clock producer.
+ * The clock returned is stored in each @clk_bulk_data.clk field.
+ *
+ * Drivers must assume that the clock source is not enabled.
+ *
+ * clk_bulk_get should not be called from within interrupt context.
+ */
+int __must_check clk_bulk_get(struct device_d *dev, int num_clks,
+			      struct clk_bulk_data *clks);
+
 /**
  * clk_enable - inform the system when the clock source should be running.
  * @clk: clock source
@@ -54,6 +93,18 @@ struct clk *clk_get(struct device_d *dev, const char *id);
  */
 int clk_enable(struct clk *clk);
 
+/**
+ * clk_bulk_enable - inform the system when the set of clks should be running.
+ * @num_clks: the number of clk_bulk_data
+ * @clks: the clk_bulk_data table of consumer
+ *
+ * May be called from atomic contexts.
+ *
+ * Returns success (0) or negative errno.
+ */
+int __must_check clk_bulk_enable(int num_clks,
+				 const struct clk_bulk_data *clks);
+
 /**
  * clk_disable - inform the system when the clock source is no longer required.
  * @clk: clock source
@@ -68,6 +119,24 @@ int clk_enable(struct clk *clk);
  */
 void clk_disable(struct clk *clk);
 
+/**
+ * clk_bulk_disable - inform the system when the set of clks is no
+ *		      longer required.
+ * @num_clks: the number of clk_bulk_data
+ * @clks: the clk_bulk_data table of consumer
+ *
+ * Inform the system that a set of clks is no longer required by
+ * a driver and may be shut down.
+ *
+ * May be called from atomic contexts.
+ *
+ * Implementation detail: if the set of clks is shared between
+ * multiple drivers, clk_bulk_enable() calls must be balanced by the
+ * same number of clk_bulk_disable() calls for the clock source to be
+ * disabled.
+ */
+void clk_bulk_disable(int num_clks, const struct clk_bulk_data *clks);
+
 /**
  * clk_get_rate - obtain the current clock rate (in Hz) for a clock source.
  *		  This is only valid once the clock source has been enabled.
@@ -75,6 +144,19 @@ void clk_disable(struct clk *clk);
  */
 unsigned long clk_get_rate(struct clk *clk);
 
+/**
+ * clk_bulk_put	- "free" the clock source
+ * @num_clks: the number of clk_bulk_data
+ * @clks: the clk_bulk_data table of consumer
+ *
+ * Note: drivers must ensure that all clk_bulk_enable calls made on this
+ * clock source are balanced by clk_bulk_disable calls prior to calling
+ * this function.
+ *
+ * clk_bulk_put should not be called from within interrupt context.
+ */
+void clk_bulk_put(int num_clks, struct clk_bulk_data *clks);
+
 /*
  * The remaining APIs are optional for machine class support.
  */
@@ -153,15 +235,31 @@ static inline struct clk *clk_get(struct device_d *dev, const char *id)
 	return NULL;
 }
 
+static inline int __must_check clk_bulk_get(struct device_d *dev, int num_clks,
+					    struct clk_bulk_data *clks)
+{
+	return 0;
+}
+
+static inline void clk_bulk_put(int num_clks, struct clk_bulk_data *clks) {}
+
 static inline int clk_enable(struct clk *clk)
 {
 	return 0;
 }
 
+static inline int __must_check clk_bulk_enable(int num_clks, struct clk_bulk_data *clks)
+{
+	return 0;
+}
+
 static inline void clk_disable(struct clk *clk)
 {
 }
 
+static inline void clk_bulk_disable(int num_clks,
+				    struct clk_bulk_data *clks) {}
+
 static inline unsigned long clk_get_rate(struct clk *clk)
 {
 	return 0;
-- 
2.20.1


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

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

* [PATCH 22/25] usb: Import DWC3 USB controller driver from Linux
  2019-02-20  7:29 [PATCH 00/25] i.MX8MQ USB support Andrey Smirnov
                   ` (20 preceding siblings ...)
  2019-02-20  7:29 ` [PATCH 21/25] clk: Import a subset of clk_bulk API " Andrey Smirnov
@ 2019-02-20  7:29 ` Andrey Smirnov
  2019-02-20  7:29 ` [PATCH 23/25] lib: Port basic Linux kernel NLS functions Andrey Smirnov
                   ` (3 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Andrey Smirnov @ 2019-02-20  7:29 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Import DWC3 USB controller driver from Linux. This is a bare minimum
port of the code needed to support USB host functionality on
i.MX8MQ. No other use-case is explicitly supported.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/Kconfig       |    2 +
 drivers/usb/Makefile      |    1 +
 drivers/usb/dwc3/Kconfig  |   22 +
 drivers/usb/dwc3/Makefile |   10 +
 drivers/usb/dwc3/core.c   |  740 ++++++++++++++++++++++
 drivers/usb/dwc3/core.h   | 1267 +++++++++++++++++++++++++++++++++++++
 drivers/usb/dwc3/debug.h  |  664 +++++++++++++++++++
 drivers/usb/dwc3/host.c   |   36 ++
 drivers/usb/dwc3/io.h     |   41 ++
 9 files changed, 2783 insertions(+)
 create mode 100644 drivers/usb/dwc3/Kconfig
 create mode 100644 drivers/usb/dwc3/Makefile
 create mode 100644 drivers/usb/dwc3/core.c
 create mode 100644 drivers/usb/dwc3/core.h
 create mode 100644 drivers/usb/dwc3/debug.h
 create mode 100644 drivers/usb/dwc3/host.c
 create mode 100644 drivers/usb/dwc3/io.h

diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 8520a2fd9..ee33e0f28 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -9,6 +9,8 @@ if USB_HOST
 
 source drivers/usb/imx/Kconfig
 
+source "drivers/usb/dwc3/Kconfig"
+
 source drivers/usb/host/Kconfig
 
 source drivers/usb/otg/Kconfig
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 047f18480..13fca2cbd 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_DWC3)		+= dwc3/
 obj-$(CONFIG_USB_MUSB)		+= musb/
 obj-$(CONFIG_USB_GADGET)	+= gadget/
 obj-$(CONFIG_USB_STORAGE)	+= storage/
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
new file mode 100644
index 000000000..c91fd36a9
--- /dev/null
+++ b/drivers/usb/dwc3/Kconfig
@@ -0,0 +1,22 @@
+config USB_DWC3
+	tristate "DesignWare USB3 DRD Core Support"
+	depends on USB && HAS_DMA
+	select USB_XHCI
+	select USB_DWC3_HOST	# Remove this once we support more
+				# than USB host
+	help
+	  Say Y or M here if your system has a Dual Role SuperSpeed
+	  USB controller based on the DesignWare USB3 IP Core.
+
+	  If you choose to build this driver is a dynamically linked
+	  module, the module will be called dwc3.ko.
+
+if USB_DWC3
+
+config USB_DWC3_HOST
+	bool "Host only mode"
+	help
+	  Select this when you want to use DWC3 in host mode only,
+	  thereby the gadget feature will be regressed.
+
+endif
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
new file mode 100644
index 000000000..d43b23eb2
--- /dev/null
+++ b/drivers/usb/dwc3/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_USB_DWC3)			+= dwc3.o
+
+dwc3-y					:= core.o
+
+ifneq ($(filter y,$(CONFIG_USB_DWC3_HOST)),)
+	dwc3-y				+= host.o
+endif
+
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
new file mode 100644
index 000000000..2e7031a34
--- /dev/null
+++ b/drivers/usb/dwc3/core.c
@@ -0,0 +1,740 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * core.c - DesignWare USB3 DRD Controller Core file
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ */
+
+#include <common.h>
+#include <linux/clk.h>
+#include <linux/phy/phy.h>
+#include <driver.h>
+#include <init.h>
+
+#include "core.h"
+#include "io.h"
+
+
+#define DWC3_DEFAULT_AUTOSUSPEND_DELAY	5000 /* ms */
+
+void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
+{
+	u32 reg;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+	reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
+	reg |= DWC3_GCTL_PRTCAPDIR(mode);
+	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
+	dwc->current_dr_role = mode;
+}
+
+/**
+ * dwc3_core_soft_reset - Issues core soft reset and PHY reset
+ * @dwc: pointer to our context structure
+ */
+static int dwc3_core_soft_reset(struct dwc3 *dwc)
+{
+	u32		reg;
+	int		retries = 1000;
+	int		ret;
+
+	ret = phy_init(dwc->usb2_generic_phy);
+	if (ret < 0)
+		return ret;
+
+	ret = phy_init(dwc->usb3_generic_phy);
+	if (ret < 0) {
+		phy_exit(dwc->usb2_generic_phy);
+		return ret;
+	}
+
+	/*
+	 * We're resetting only the device side because, if we're in host mode,
+	 * XHCI driver will reset the host block. If dwc3 was configured for
+	 * host-only mode, then we can return early.
+	 */
+	if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST)
+		return 0;
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+	reg |= DWC3_DCTL_CSFTRST;
+	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+	do {
+		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+		if (!(reg & DWC3_DCTL_CSFTRST))
+			goto done;
+
+		udelay(1);
+	} while (--retries);
+
+	phy_exit(dwc->usb3_generic_phy);
+	phy_exit(dwc->usb2_generic_phy);
+
+	return -ETIMEDOUT;
+
+done:
+	/*
+	 * For DWC_usb31 controller, once DWC3_DCTL_CSFTRST bit is cleared,
+	 * we must wait at least 50ms before accessing the PHY domain
+	 * (synchronization delay). DWC_usb31 programming guide section 1.3.2.
+	 */
+	if (dwc3_is_usb31(dwc))
+		mdelay(50);
+
+	return 0;
+}
+
+static const struct clk_bulk_data dwc3_core_clks[] = {
+	{ .id = "ref" },
+	{ .id = "bus_early" },
+	{ .id = "suspend" },
+};
+
+/*
+ * dwc3_frame_length_adjustment - Adjusts frame length if required
+ * @dwc3: Pointer to our controller context structure
+ */
+static void dwc3_frame_length_adjustment(struct dwc3 *dwc)
+{
+	u32 reg;
+	u32 dft;
+
+	if (dwc->revision < DWC3_REVISION_250A)
+		return;
+
+	if (dwc->fladj == 0)
+		return;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GFLADJ);
+	dft = reg & DWC3_GFLADJ_30MHZ_MASK;
+	if (!WARN(dft == dwc->fladj,
+	    "request value same as default, ignoring\n")) {
+		reg &= ~DWC3_GFLADJ_30MHZ_MASK;
+		reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | dwc->fladj;
+		dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
+	}
+}
+
+static void dwc3_core_num_eps(struct dwc3 *dwc)
+{
+	struct dwc3_hwparams	*parms = &dwc->hwparams;
+
+	dwc->num_eps = DWC3_NUM_EPS(parms);
+}
+
+static void dwc3_cache_hwparams(struct dwc3 *dwc)
+{
+	struct dwc3_hwparams	*parms = &dwc->hwparams;
+
+	parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0);
+	parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1);
+	parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2);
+	parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3);
+	parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4);
+	parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5);
+	parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
+	parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7);
+	parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
+}
+
+/**
+ * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core
+ * @dwc: Pointer to our controller context structure
+ *
+ * Returns 0 on success. The USB PHY interfaces are configured but not
+ * initialized. The PHY interfaces and the PHYs get initialized together with
+ * the core in dwc3_core_init.
+ */
+static int dwc3_phy_setup(struct dwc3 *dwc)
+{
+	u32 reg;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+
+	/*
+	 * Make sure UX_EXIT_PX is cleared as that causes issues with some
+	 * PHYs. Also, this bit is not supposed to be used in normal operation.
+	 */
+	reg &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX;
+
+	/*
+	 * Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY
+	 * to '0' during coreConsultant configuration. So default value
+	 * will be '0' when the core is reset. Application needs to set it
+	 * to '1' after the core initialization is completed.
+	 */
+	if (dwc->revision > DWC3_REVISION_194A)
+		reg |= DWC3_GUSB3PIPECTL_SUSPHY;
+
+	if (dwc->u2ss_inp3_quirk)
+		reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK;
+
+	if (dwc->dis_rxdet_inp3_quirk)
+		reg |= DWC3_GUSB3PIPECTL_DISRXDETINP3;
+
+	if (dwc->req_p1p2p3_quirk)
+		reg |= DWC3_GUSB3PIPECTL_REQP1P2P3;
+
+	if (dwc->del_p1p2p3_quirk)
+		reg |= DWC3_GUSB3PIPECTL_DEP1P2P3_EN;
+
+	if (dwc->del_phy_power_chg_quirk)
+		reg |= DWC3_GUSB3PIPECTL_DEPOCHANGE;
+
+	if (dwc->lfps_filter_quirk)
+		reg |= DWC3_GUSB3PIPECTL_LFPSFILT;
+
+	if (dwc->rx_detect_poll_quirk)
+		reg |= DWC3_GUSB3PIPECTL_RX_DETOPOLL;
+
+	if (dwc->tx_de_emphasis_quirk)
+		reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis);
+
+	if (dwc->dis_u3_susphy_quirk)
+		reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
+
+	if (dwc->dis_del_phy_power_chg_quirk)
+		reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE;
+
+	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+
+	/* Select the HS PHY interface */
+	switch (DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3)) {
+	case DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI:
+		if (dwc->hsphy_interface &&
+				!strncmp(dwc->hsphy_interface, "utmi", 4)) {
+			reg &= ~DWC3_GUSB2PHYCFG_ULPI_UTMI;
+			break;
+		} else if (dwc->hsphy_interface &&
+				!strncmp(dwc->hsphy_interface, "ulpi", 4)) {
+			reg |= DWC3_GUSB2PHYCFG_ULPI_UTMI;
+			dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+		} else {
+			/* Relying on default value. */
+			if (!(reg & DWC3_GUSB2PHYCFG_ULPI_UTMI))
+				break;
+		}
+		/* FALLTHROUGH */
+	case DWC3_GHWPARAMS3_HSPHY_IFC_ULPI:
+		/* FALLTHROUGH */
+	default:
+		break;
+	}
+
+	/*
+	 * Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to
+	 * '0' during coreConsultant configuration. So default value will
+	 * be '0' when the core is reset. Application needs to set it to
+	 * '1' after the core initialization is completed.
+	 */
+	if (dwc->revision > DWC3_REVISION_194A)
+		reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+
+	if (dwc->dis_u2_susphy_quirk)
+		reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
+
+	if (dwc->dis_enblslpm_quirk)
+		reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
+	else
+		reg |= DWC3_GUSB2PHYCFG_ENBLSLPM;
+
+	if (dwc->dis_u2_freeclk_exists_quirk)
+		reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS;
+
+	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+
+	return 0;
+}
+
+static void dwc3_core_exit(struct dwc3 *dwc)
+{
+	phy_exit(dwc->usb2_generic_phy);
+	phy_exit(dwc->usb3_generic_phy);
+
+	phy_power_off(dwc->usb2_generic_phy);
+	phy_power_off(dwc->usb3_generic_phy);
+	clk_bulk_disable(dwc->num_clks, dwc->clks);
+}
+
+static bool dwc3_core_is_valid(struct dwc3 *dwc)
+{
+	u32 reg;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
+
+	/* This should read as U3 followed by revision number */
+	if ((reg & DWC3_GSNPSID_MASK) == 0x55330000) {
+		/* Detected DWC_usb3 IP */
+		dwc->revision = reg;
+	} else if ((reg & DWC3_GSNPSID_MASK) == 0x33310000) {
+		/* Detected DWC_usb31 IP */
+		dwc->revision = dwc3_readl(dwc->regs, DWC3_VER_NUMBER);
+		dwc->revision |= DWC3_REVISION_IS_DWC31;
+		dwc->version_type = dwc3_readl(dwc->regs, DWC3_VER_TYPE);
+	} else {
+		return false;
+	}
+
+	return true;
+}
+
+static void dwc3_core_setup_global_control(struct dwc3 *dwc)
+{
+	u32 hwparams4 = dwc->hwparams.hwparams4;
+	u32 reg;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+	reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
+
+	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
+	case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
+		/**
+		 * WORKAROUND: DWC3 revisions between 2.10a and 2.50a have an
+		 * issue which would cause xHCI compliance tests to fail.
+		 *
+		 * Because of that we cannot enable clock gating on such
+		 * configurations.
+		 *
+		 * Refers to:
+		 *
+		 * STAR#9000588375: Clock Gating, SOF Issues when ref_clk-Based
+		 * SOF/ITP Mode Used
+		 */
+		if ((dwc->dr_mode == USB_DR_MODE_HOST ||
+				dwc->dr_mode == USB_DR_MODE_OTG) &&
+				(dwc->revision >= DWC3_REVISION_210A &&
+				dwc->revision <= DWC3_REVISION_250A))
+			reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC;
+		else
+			reg &= ~DWC3_GCTL_DSBLCLKGTNG;
+		break;
+	case DWC3_GHWPARAMS1_EN_PWROPT_HIB:
+		/* enable hibernation here */
+		dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4);
+
+		/*
+		 * REVISIT Enabling this bit so that host-mode hibernation
+		 * will work. Device-mode hibernation is not yet implemented.
+		 */
+		reg |= DWC3_GCTL_GBLHIBERNATIONEN;
+		break;
+	default:
+		/* nothing */
+		break;
+	}
+
+	/* check if current dwc3 is on simulation board */
+	if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) {
+		dev_info(dwc->dev, "Running with FPGA optimizations\n");
+		dwc->is_fpga = true;
+	}
+
+	WARN(dwc->disable_scramble_quirk && !dwc->is_fpga,
+	     "disable_scramble cannot be used on non-FPGA builds\n");
+
+	if (dwc->disable_scramble_quirk && dwc->is_fpga)
+		reg |= DWC3_GCTL_DISSCRAMBLE;
+	else
+		reg &= ~DWC3_GCTL_DISSCRAMBLE;
+
+	if (dwc->u2exit_lfps_quirk)
+		reg |= DWC3_GCTL_U2EXIT_LFPS;
+
+	/*
+	 * WORKAROUND: DWC3 revisions <1.90a have a bug
+	 * where the device can fail to connect at SuperSpeed
+	 * and falls back to high-speed mode which causes
+	 * the device to enter a Connect/Disconnect loop
+	 */
+	if (dwc->revision < DWC3_REVISION_190A)
+		reg |= DWC3_GCTL_U2RSTECN;
+
+	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+}
+
+static int dwc3_core_get_phy(struct dwc3 *dwc);
+
+/**
+ * dwc3_core_init - Low-level initialization of DWC3 Core
+ * @dwc: Pointer to our controller context structure
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+static int dwc3_core_init(struct dwc3 *dwc)
+{
+	u32			reg;
+	int			ret;
+
+	if (!dwc3_core_is_valid(dwc)) {
+		dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
+		ret = -ENODEV;
+		goto err0;
+	}
+
+	/*
+	 * Write Linux Version Code to our GUID register so it's easy to figure
+	 * out which kernel version a bug was found.
+	 */
+	dwc3_writel(dwc->regs, DWC3_GUID, 0xdeadbeef);
+
+	/* Handle USB2.0-only core configuration */
+	if (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
+			DWC3_GHWPARAMS3_SSPHY_IFC_DIS) {
+		if (dwc->maximum_speed == USB_SPEED_SUPER)
+			dwc->maximum_speed = USB_SPEED_HIGH;
+	}
+
+	ret = dwc3_phy_setup(dwc);
+	if (ret)
+		goto err0;
+
+	if (!dwc->phys_ready) {
+		ret = dwc3_core_get_phy(dwc);
+		if (ret)
+			goto err0a;
+		dwc->phys_ready = true;
+	}
+
+	ret = dwc3_core_soft_reset(dwc);
+	if (ret)
+		goto err0a;
+
+	dwc3_core_setup_global_control(dwc);
+	dwc3_core_num_eps(dwc);
+
+	/* Adjust Frame Length */
+	dwc3_frame_length_adjustment(dwc);
+
+	ret = phy_power_on(dwc->usb2_generic_phy);
+	if (ret < 0)
+		goto err2;
+
+	ret = phy_power_on(dwc->usb3_generic_phy);
+	if (ret < 0)
+		goto err3;
+	/*
+	 * ENDXFER polling is available on version 3.10a and later of
+	 * the DWC_usb3 controller. It is NOT available in the
+	 * DWC_usb31 controller.
+	 */
+	if (!dwc3_is_usb31(dwc) && dwc->revision >= DWC3_REVISION_310A) {
+		reg = dwc3_readl(dwc->regs, DWC3_GUCTL2);
+		reg |= DWC3_GUCTL2_RST_ACTBITLATER;
+		dwc3_writel(dwc->regs, DWC3_GUCTL2, reg);
+	}
+
+	if (dwc->revision >= DWC3_REVISION_250A) {
+		reg = dwc3_readl(dwc->regs, DWC3_GUCTL1);
+
+		/*
+		 * Enable hardware control of sending remote wakeup
+		 * in HS when the device is in the L1 state.
+		 */
+		if (dwc->revision >= DWC3_REVISION_290A)
+			reg |= DWC3_GUCTL1_DEV_L1_EXIT_BY_HW;
+
+		if (dwc->dis_tx_ipgap_linecheck_quirk)
+			reg |= DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS;
+
+		dwc3_writel(dwc->regs, DWC3_GUCTL1, reg);
+	}
+
+	if (dwc->dr_mode == USB_DR_MODE_HOST ||
+	    dwc->dr_mode == USB_DR_MODE_OTG) {
+		reg = dwc3_readl(dwc->regs, DWC3_GUCTL);
+
+		/*
+		 * Enable Auto retry Feature to make the controller operating in
+		 * Host mode on seeing transaction errors(CRC errors or internal
+		 * overrun scenerios) on IN transfers to reply to the device
+		 * with a non-terminating retry ACK (i.e, an ACK transcation
+		 * packet with Retry=1 & Nump != 0)
+		 */
+		reg |= DWC3_GUCTL_HSTINAUTORETRY;
+
+		dwc3_writel(dwc->regs, DWC3_GUCTL, reg);
+	}
+
+	/*
+	 * Must config both number of packets and max burst settings to enable
+	 * RX and/or TX threshold.
+	 */
+	if (dwc3_is_usb31(dwc) && dwc->dr_mode == USB_DR_MODE_HOST) {
+		u8 rx_thr_num = dwc->rx_thr_num_pkt_prd;
+		u8 rx_maxburst = dwc->rx_max_burst_prd;
+		u8 tx_thr_num = dwc->tx_thr_num_pkt_prd;
+		u8 tx_maxburst = dwc->tx_max_burst_prd;
+
+		if (rx_thr_num && rx_maxburst) {
+			reg = dwc3_readl(dwc->regs, DWC3_GRXTHRCFG);
+			reg |= DWC31_RXTHRNUMPKTSEL_PRD;
+
+			reg &= ~DWC31_RXTHRNUMPKT_PRD(~0);
+			reg |= DWC31_RXTHRNUMPKT_PRD(rx_thr_num);
+
+			reg &= ~DWC31_MAXRXBURSTSIZE_PRD(~0);
+			reg |= DWC31_MAXRXBURSTSIZE_PRD(rx_maxburst);
+
+			dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg);
+		}
+
+		if (tx_thr_num && tx_maxburst) {
+			reg = dwc3_readl(dwc->regs, DWC3_GTXTHRCFG);
+			reg |= DWC31_TXTHRNUMPKTSEL_PRD;
+
+			reg &= ~DWC31_TXTHRNUMPKT_PRD(~0);
+			reg |= DWC31_TXTHRNUMPKT_PRD(tx_thr_num);
+
+			reg &= ~DWC31_MAXTXBURSTSIZE_PRD(~0);
+			reg |= DWC31_MAXTXBURSTSIZE_PRD(tx_maxburst);
+
+			dwc3_writel(dwc->regs, DWC3_GTXTHRCFG, reg);
+		}
+	}
+
+	return 0;
+
+/* err4: */
+	/* phy_power_off(dwc->usb3_generic_phy); */
+err3:
+	phy_power_off(dwc->usb2_generic_phy);
+err2:
+/* err1: */
+	phy_exit(dwc->usb2_generic_phy);
+	phy_exit(dwc->usb3_generic_phy);
+err0a:
+err0:
+	return ret;
+}
+
+static int dwc3_core_get_phy(struct dwc3 *dwc)
+{
+	struct device_d		*dev = dwc->dev;
+	int ret;
+
+	dwc->usb2_generic_phy = phy_get(dev, "usb2-phy");
+	if (IS_ERR(dwc->usb2_generic_phy)) {
+		ret = PTR_ERR(dwc->usb2_generic_phy);
+		if (ret == -ENOSYS || ret == -ENODEV) {
+			dev_err(dev, "no usb2 phy configured\n");
+			dwc->usb2_generic_phy = NULL;
+		} else if (ret == -EPROBE_DEFER) {
+			return ret;
+		} else {
+			dev_err(dev, "no usb2 phy configured\n");
+			return ret;
+		}
+	}
+
+	dwc->usb3_generic_phy = phy_get(dev, "usb3-phy");
+	if (IS_ERR(dwc->usb3_generic_phy)) {
+		ret = PTR_ERR(dwc->usb3_generic_phy);
+		if (ret == -ENOSYS || ret == -ENODEV) {
+			dev_err(dev, "no usb2 phy configured\n");
+			dwc->usb3_generic_phy = NULL;
+		} else if (ret == -EPROBE_DEFER) {
+			return ret;
+		} else {
+			dev_err(dev, "no usb3 phy configured\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int dwc3_core_init_mode(struct dwc3 *dwc)
+{
+	struct device_d *dev = dwc->dev;
+	int ret;
+
+	switch (dwc->dr_mode) {
+	case USB_DR_MODE_HOST:
+		dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
+
+		ret = dwc3_host_init(dwc);
+		if (ret) {
+			if (ret != -EPROBE_DEFER)
+				dev_err(dev, "failed to initialize host\n");
+			return ret;
+		}
+		break;
+	default:
+		dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void dwc3_get_properties(struct dwc3 *dwc)
+{
+	struct device_d		*dev = dwc->dev;
+	u8			lpm_nyet_threshold;
+	u8			tx_de_emphasis;
+	u8			hird_threshold;
+
+	/* default to highest possible threshold */
+	lpm_nyet_threshold = 0xff;
+
+	/* default to -3.5dB de-emphasis */
+	tx_de_emphasis = 1;
+
+	/*
+	 * default to assert utmi_sleep_n and use maximum allowed HIRD
+	 * threshold value of 0b1100
+	 */
+	hird_threshold = 12;
+
+	dwc->maximum_speed = of_usb_get_maximum_speed(dev->device_node, NULL);
+	dwc->dr_mode = of_usb_get_dr_mode(dev->device_node, NULL);
+
+	dwc->lpm_nyet_threshold = lpm_nyet_threshold;
+	dwc->tx_de_emphasis = tx_de_emphasis;
+
+	dwc->hird_threshold = hird_threshold
+		| (dwc->is_utmi_l1_suspend << 4);
+
+	dwc->imod_interval = 0;
+}
+
+/* check whether the core supports IMOD */
+bool dwc3_has_imod(struct dwc3 *dwc)
+{
+	return ((dwc3_is_usb3(dwc) &&
+		 dwc->revision >= DWC3_REVISION_300A) ||
+		(dwc3_is_usb31(dwc) &&
+		 dwc->revision >= DWC3_USB31_REVISION_120A));
+}
+
+static void dwc3_check_params(struct dwc3 *dwc)
+{
+	struct device_d *dev = dwc->dev;
+
+	/* Check for proper value of imod_interval */
+	if (dwc->imod_interval && !dwc3_has_imod(dwc)) {
+		dev_warn(dwc->dev, "Interrupt moderation not supported\n");
+		dwc->imod_interval = 0;
+	}
+
+	/*
+	 * Workaround for STAR 9000961433 which affects only version
+	 * 3.00a of the DWC_usb3 core. This prevents the controller
+	 * interrupt from being masked while handling events. IMOD
+	 * allows us to work around this issue. Enable it for the
+	 * affected version.
+	 */
+	if (!dwc->imod_interval &&
+	    (dwc->revision == DWC3_REVISION_300A))
+		dwc->imod_interval = 1;
+
+	/* Check the maximum_speed parameter */
+	switch (dwc->maximum_speed) {
+	case USB_SPEED_LOW:
+	case USB_SPEED_FULL:
+	case USB_SPEED_HIGH:
+	case USB_SPEED_SUPER:
+	case USB_SPEED_SUPER_PLUS:
+		break;
+	default:
+		dev_err(dev, "invalid maximum_speed parameter %d\n",
+			dwc->maximum_speed);
+		/* fall through */
+	case USB_SPEED_UNKNOWN:
+		/* default to superspeed */
+		dwc->maximum_speed = USB_SPEED_SUPER;
+
+		/*
+		 * default to superspeed plus if we are capable.
+		 */
+		if (dwc3_is_usb31(dwc) &&
+		    (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
+		     DWC3_GHWPARAMS3_SSPHY_IFC_GEN2))
+			dwc->maximum_speed = USB_SPEED_SUPER_PLUS;
+
+		break;
+	}
+}
+
+static int dwc3_probe(struct device_d *dev)
+{
+	struct dwc3		*dwc;
+	int			ret;
+
+	dwc = xzalloc(sizeof(*dwc));
+	dev->priv = dwc;
+
+	dwc->clks = xmemdup(dwc3_core_clks, sizeof(dwc3_core_clks));
+	dwc->dev = dev;
+	dwc->regs = dev_get_mem_region(dwc->dev, 0) + DWC3_GLOBALS_REGS_START;
+
+	dwc3_get_properties(dwc);
+
+	if (dev->device_node) {
+		dwc->num_clks = ARRAY_SIZE(dwc3_core_clks);
+
+		ret = clk_bulk_get(dev, dwc->num_clks, dwc->clks);
+		if (ret == -EPROBE_DEFER)
+			return ret;
+		/*
+		 * Clocks are optional, but new DT platforms should support all
+		 * clocks as required by the DT-binding.
+		 */
+		if (ret)
+			dwc->num_clks = 0;
+	}
+
+	ret = clk_bulk_enable(dwc->num_clks, dwc->clks);
+	if (ret)
+		return ret;
+
+	dwc3_cache_hwparams(dwc);
+
+	ret = dwc3_core_init(dwc);
+	if (ret) {
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "failed to initialize core: %d\n", ret);
+		return ret;
+	}
+
+	dwc3_check_params(dwc);
+
+	ret = dwc3_core_init_mode(dwc);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void dwc3_remove(struct device_d *dev)
+{
+	struct dwc3 *dwc = dev->priv;
+
+	dwc3_core_exit(dwc);
+	clk_bulk_put(dwc->num_clks, dwc->clks);
+}
+
+static const struct of_device_id of_dwc3_match[] = {
+	{
+		.compatible = "snps,dwc3"
+	},
+	{
+		.compatible = "synopsys,dwc3"
+	},
+	{ },
+};
+
+static struct driver_d dwc3_driver = {
+	.probe = dwc3_probe,
+	.remove	= dwc3_remove,
+	.name = "dwc3",
+	.of_compatible = DRV_OF_COMPAT(of_dwc3_match),
+};
+device_platform_driver(dwc3_driver);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
new file mode 100644
index 000000000..a404e4cd6
--- /dev/null
+++ b/drivers/usb/dwc3/core.h
@@ -0,0 +1,1267 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * core.h - DesignWare USB3 DRD Core Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ */
+
+#ifndef __DRIVERS_USB_DWC3_CORE_H
+#define __DRIVERS_USB_DWC3_CORE_H
+
+#include <usb/usb.h>
+
+#define DWC3_MSG_MAX	500
+
+/* Global constants */
+#define DWC3_PULL_UP_TIMEOUT	500	/* ms */
+#define DWC3_BOUNCE_SIZE	1024	/* size of a superspeed bulk */
+#define DWC3_EP0_SETUP_SIZE	512
+#define DWC3_ENDPOINTS_NUM	32
+#define DWC3_XHCI_RESOURCES_NUM	2
+#define DWC3_ISOC_MAX_RETRIES	5
+
+#define DWC3_SCRATCHBUF_SIZE	4096	/* each buffer is assumed to be 4KiB */
+#define DWC3_EVENT_BUFFERS_SIZE	4096
+#define DWC3_EVENT_TYPE_MASK	0xfe
+
+#define DWC3_EVENT_TYPE_DEV	0
+#define DWC3_EVENT_TYPE_CARKIT	3
+#define DWC3_EVENT_TYPE_I2C	4
+
+#define DWC3_DEVICE_EVENT_DISCONNECT		0
+#define DWC3_DEVICE_EVENT_RESET			1
+#define DWC3_DEVICE_EVENT_CONNECT_DONE		2
+#define DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE	3
+#define DWC3_DEVICE_EVENT_WAKEUP		4
+#define DWC3_DEVICE_EVENT_HIBER_REQ		5
+#define DWC3_DEVICE_EVENT_EOPF			6
+#define DWC3_DEVICE_EVENT_SOF			7
+#define DWC3_DEVICE_EVENT_ERRATIC_ERROR		9
+#define DWC3_DEVICE_EVENT_CMD_CMPL		10
+#define DWC3_DEVICE_EVENT_OVERFLOW		11
+
+/* Controller's role while using the OTG block */
+#define DWC3_OTG_ROLE_IDLE	0
+#define DWC3_OTG_ROLE_HOST	1
+#define DWC3_OTG_ROLE_DEVICE	2
+
+#define DWC3_GEVNTCOUNT_MASK	0xfffc
+#define DWC3_GEVNTCOUNT_EHB	BIT(31)
+#define DWC3_GSNPSID_MASK	0xffff0000
+#define DWC3_GSNPSREV_MASK	0xffff
+
+/* DWC3 registers memory space boundries */
+#define DWC3_XHCI_REGS_START		0x0
+#define DWC3_XHCI_REGS_END		0x7fff
+#define DWC3_GLOBALS_REGS_START		0xc100
+#define DWC3_GLOBALS_REGS_END		0xc6ff
+#define DWC3_DEVICE_REGS_START		0xc700
+#define DWC3_DEVICE_REGS_END		0xcbff
+#define DWC3_OTG_REGS_START		0xcc00
+#define DWC3_OTG_REGS_END		0xccff
+
+/* Global Registers */
+#define DWC3_GSBUSCFG0		0xc100
+#define DWC3_GSBUSCFG1		0xc104
+#define DWC3_GTXTHRCFG		0xc108
+#define DWC3_GRXTHRCFG		0xc10c
+#define DWC3_GCTL		0xc110
+#define DWC3_GEVTEN		0xc114
+#define DWC3_GSTS		0xc118
+#define DWC3_GUCTL1		0xc11c
+#define DWC3_GSNPSID		0xc120
+#define DWC3_GGPIO		0xc124
+#define DWC3_GUID		0xc128
+#define DWC3_GUCTL		0xc12c
+#define DWC3_GBUSERRADDR0	0xc130
+#define DWC3_GBUSERRADDR1	0xc134
+#define DWC3_GPRTBIMAP0		0xc138
+#define DWC3_GPRTBIMAP1		0xc13c
+#define DWC3_GHWPARAMS0		0xc140
+#define DWC3_GHWPARAMS1		0xc144
+#define DWC3_GHWPARAMS2		0xc148
+#define DWC3_GHWPARAMS3		0xc14c
+#define DWC3_GHWPARAMS4		0xc150
+#define DWC3_GHWPARAMS5		0xc154
+#define DWC3_GHWPARAMS6		0xc158
+#define DWC3_GHWPARAMS7		0xc15c
+#define DWC3_GDBGFIFOSPACE	0xc160
+#define DWC3_GDBGLTSSM		0xc164
+#define DWC3_GDBGBMU		0xc16c
+#define DWC3_GDBGLSPMUX		0xc170
+#define DWC3_GDBGLSP		0xc174
+#define DWC3_GDBGEPINFO0	0xc178
+#define DWC3_GDBGEPINFO1	0xc17c
+#define DWC3_GPRTBIMAP_HS0	0xc180
+#define DWC3_GPRTBIMAP_HS1	0xc184
+#define DWC3_GPRTBIMAP_FS0	0xc188
+#define DWC3_GPRTBIMAP_FS1	0xc18c
+#define DWC3_GUCTL2		0xc19c
+
+#define DWC3_VER_NUMBER		0xc1a0
+#define DWC3_VER_TYPE		0xc1a4
+
+#define DWC3_GUSB2PHYCFG(n)	(0xc200 + ((n) * 0x04))
+#define DWC3_GUSB2I2CCTL(n)	(0xc240 + ((n) * 0x04))
+
+#define DWC3_GUSB2PHYACC(n)	(0xc280 + ((n) * 0x04))
+
+#define DWC3_GUSB3PIPECTL(n)	(0xc2c0 + ((n) * 0x04))
+
+#define DWC3_GTXFIFOSIZ(n)	(0xc300 + ((n) * 0x04))
+#define DWC3_GRXFIFOSIZ(n)	(0xc380 + ((n) * 0x04))
+
+#define DWC3_GEVNTADRLO(n)	(0xc400 + ((n) * 0x10))
+#define DWC3_GEVNTADRHI(n)	(0xc404 + ((n) * 0x10))
+#define DWC3_GEVNTSIZ(n)	(0xc408 + ((n) * 0x10))
+#define DWC3_GEVNTCOUNT(n)	(0xc40c + ((n) * 0x10))
+
+#define DWC3_GHWPARAMS8		0xc600
+#define DWC3_GFLADJ		0xc630
+
+/* Device Registers */
+#define DWC3_DCFG		0xc700
+#define DWC3_DCTL		0xc704
+#define DWC3_DEVTEN		0xc708
+#define DWC3_DSTS		0xc70c
+#define DWC3_DGCMDPAR		0xc710
+#define DWC3_DGCMD		0xc714
+#define DWC3_DALEPENA		0xc720
+
+#define DWC3_DEP_BASE(n)	(0xc800 + ((n) * 0x10))
+#define DWC3_DEPCMDPAR2		0x00
+#define DWC3_DEPCMDPAR1		0x04
+#define DWC3_DEPCMDPAR0		0x08
+#define DWC3_DEPCMD		0x0c
+
+#define DWC3_DEV_IMOD(n)	(0xca00 + ((n) * 0x4))
+
+/* OTG Registers */
+#define DWC3_OCFG		0xcc00
+#define DWC3_OCTL		0xcc04
+#define DWC3_OEVT		0xcc08
+#define DWC3_OEVTEN		0xcc0C
+#define DWC3_OSTS		0xcc10
+
+/* Bit fields */
+
+/* Global SoC Bus Configuration INCRx Register 0 */
+#define DWC3_GSBUSCFG0_INCR256BRSTENA	(1 << 7) /* INCR256 burst */
+#define DWC3_GSBUSCFG0_INCR128BRSTENA	(1 << 6) /* INCR128 burst */
+#define DWC3_GSBUSCFG0_INCR64BRSTENA	(1 << 5) /* INCR64 burst */
+#define DWC3_GSBUSCFG0_INCR32BRSTENA	(1 << 4) /* INCR32 burst */
+#define DWC3_GSBUSCFG0_INCR16BRSTENA	(1 << 3) /* INCR16 burst */
+#define DWC3_GSBUSCFG0_INCR8BRSTENA	(1 << 2) /* INCR8 burst */
+#define DWC3_GSBUSCFG0_INCR4BRSTENA	(1 << 1) /* INCR4 burst */
+#define DWC3_GSBUSCFG0_INCRBRSTENA	(1 << 0) /* undefined length enable */
+#define DWC3_GSBUSCFG0_INCRBRST_MASK	0xff
+
+/* Global Debug LSP MUX Select */
+#define DWC3_GDBGLSPMUX_ENDBC		BIT(15)	/* Host only */
+#define DWC3_GDBGLSPMUX_HOSTSELECT(n)	((n) & 0x3fff)
+#define DWC3_GDBGLSPMUX_DEVSELECT(n)	(((n) & 0xf) << 4)
+#define DWC3_GDBGLSPMUX_EPSELECT(n)	((n) & 0xf)
+
+/* Global Debug Queue/FIFO Space Available Register */
+#define DWC3_GDBGFIFOSPACE_NUM(n)	((n) & 0x1f)
+#define DWC3_GDBGFIFOSPACE_TYPE(n)	(((n) << 5) & 0x1e0)
+#define DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(n) (((n) >> 16) & 0xffff)
+
+#define DWC3_TXFIFO		0
+#define DWC3_RXFIFO		1
+#define DWC3_TXREQQ		2
+#define DWC3_RXREQQ		3
+#define DWC3_RXINFOQ		4
+#define DWC3_PSTATQ		5
+#define DWC3_DESCFETCHQ		6
+#define DWC3_EVENTQ		7
+#define DWC3_AUXEVENTQ		8
+
+/* Global RX Threshold Configuration Register */
+#define DWC3_GRXTHRCFG_MAXRXBURSTSIZE(n) (((n) & 0x1f) << 19)
+#define DWC3_GRXTHRCFG_RXPKTCNT(n) (((n) & 0xf) << 24)
+#define DWC3_GRXTHRCFG_PKTCNTSEL BIT(29)
+
+/* Global RX Threshold Configuration Register for DWC_usb31 only */
+#define DWC31_GRXTHRCFG_MAXRXBURSTSIZE(n)	(((n) & 0x1f) << 16)
+#define DWC31_GRXTHRCFG_RXPKTCNT(n)		(((n) & 0x1f) << 21)
+#define DWC31_GRXTHRCFG_PKTCNTSEL		BIT(26)
+#define DWC31_RXTHRNUMPKTSEL_HS_PRD		BIT(15)
+#define DWC31_RXTHRNUMPKT_HS_PRD(n)		(((n) & 0x3) << 13)
+#define DWC31_RXTHRNUMPKTSEL_PRD		BIT(10)
+#define DWC31_RXTHRNUMPKT_PRD(n)		(((n) & 0x1f) << 5)
+#define DWC31_MAXRXBURSTSIZE_PRD(n)		((n) & 0x1f)
+
+/* Global TX Threshold Configuration Register for DWC_usb31 only */
+#define DWC31_GTXTHRCFG_MAXTXBURSTSIZE(n)	(((n) & 0x1f) << 16)
+#define DWC31_GTXTHRCFG_TXPKTCNT(n)		(((n) & 0x1f) << 21)
+#define DWC31_GTXTHRCFG_PKTCNTSEL		BIT(26)
+#define DWC31_TXTHRNUMPKTSEL_HS_PRD		BIT(15)
+#define DWC31_TXTHRNUMPKT_HS_PRD(n)		(((n) & 0x3) << 13)
+#define DWC31_TXTHRNUMPKTSEL_PRD		BIT(10)
+#define DWC31_TXTHRNUMPKT_PRD(n)		(((n) & 0x1f) << 5)
+#define DWC31_MAXTXBURSTSIZE_PRD(n)		((n) & 0x1f)
+
+/* Global Configuration Register */
+#define DWC3_GCTL_PWRDNSCALE(n)	((n) << 19)
+#define DWC3_GCTL_U2RSTECN	BIT(16)
+#define DWC3_GCTL_RAMCLKSEL(x)	(((x) & DWC3_GCTL_CLK_MASK) << 6)
+#define DWC3_GCTL_CLK_BUS	(0)
+#define DWC3_GCTL_CLK_PIPE	(1)
+#define DWC3_GCTL_CLK_PIPEHALF	(2)
+#define DWC3_GCTL_CLK_MASK	(3)
+
+#define DWC3_GCTL_PRTCAP(n)	(((n) & (3 << 12)) >> 12)
+#define DWC3_GCTL_PRTCAPDIR(n)	((n) << 12)
+#define DWC3_GCTL_PRTCAP_HOST	1
+#define DWC3_GCTL_PRTCAP_DEVICE	2
+#define DWC3_GCTL_PRTCAP_OTG	3
+
+#define DWC3_GCTL_CORESOFTRESET		BIT(11)
+#define DWC3_GCTL_SOFITPSYNC		BIT(10)
+#define DWC3_GCTL_SCALEDOWN(n)		((n) << 4)
+#define DWC3_GCTL_SCALEDOWN_MASK	DWC3_GCTL_SCALEDOWN(3)
+#define DWC3_GCTL_DISSCRAMBLE		BIT(3)
+#define DWC3_GCTL_U2EXIT_LFPS		BIT(2)
+#define DWC3_GCTL_GBLHIBERNATIONEN	BIT(1)
+#define DWC3_GCTL_DSBLCLKGTNG		BIT(0)
+
+/* Global User Control Register */
+#define DWC3_GUCTL_HSTINAUTORETRY	BIT(14)
+
+/* Global User Control 1 Register */
+#define DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS	BIT(28)
+#define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW	BIT(24)
+
+/* Global Status Register */
+#define DWC3_GSTS_OTG_IP	BIT(10)
+#define DWC3_GSTS_BC_IP		BIT(9)
+#define DWC3_GSTS_ADP_IP	BIT(8)
+#define DWC3_GSTS_HOST_IP	BIT(7)
+#define DWC3_GSTS_DEVICE_IP	BIT(6)
+#define DWC3_GSTS_CSR_TIMEOUT	BIT(5)
+#define DWC3_GSTS_BUS_ERR_ADDR_VLD	BIT(4)
+#define DWC3_GSTS_CURMOD(n)	((n) & 0x3)
+#define DWC3_GSTS_CURMOD_DEVICE	0
+#define DWC3_GSTS_CURMOD_HOST	1
+
+/* Global USB2 PHY Configuration Register */
+#define DWC3_GUSB2PHYCFG_PHYSOFTRST	BIT(31)
+#define DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS	BIT(30)
+#define DWC3_GUSB2PHYCFG_SUSPHY		BIT(6)
+#define DWC3_GUSB2PHYCFG_ULPI_UTMI	BIT(4)
+#define DWC3_GUSB2PHYCFG_ENBLSLPM	BIT(8)
+#define DWC3_GUSB2PHYCFG_PHYIF(n)	(n << 3)
+#define DWC3_GUSB2PHYCFG_PHYIF_MASK	DWC3_GUSB2PHYCFG_PHYIF(1)
+#define DWC3_GUSB2PHYCFG_USBTRDTIM(n)	(n << 10)
+#define DWC3_GUSB2PHYCFG_USBTRDTIM_MASK	DWC3_GUSB2PHYCFG_USBTRDTIM(0xf)
+#define USBTRDTIM_UTMI_8_BIT		9
+#define USBTRDTIM_UTMI_16_BIT		5
+#define UTMI_PHYIF_16_BIT		1
+#define UTMI_PHYIF_8_BIT		0
+
+/* Global USB2 PHY Vendor Control Register */
+#define DWC3_GUSB2PHYACC_NEWREGREQ	BIT(25)
+#define DWC3_GUSB2PHYACC_BUSY		BIT(23)
+#define DWC3_GUSB2PHYACC_WRITE		BIT(22)
+#define DWC3_GUSB2PHYACC_ADDR(n)	(n << 16)
+#define DWC3_GUSB2PHYACC_EXTEND_ADDR(n)	(n << 8)
+#define DWC3_GUSB2PHYACC_DATA(n)	(n & 0xff)
+
+/* Global USB3 PIPE Control Register */
+#define DWC3_GUSB3PIPECTL_PHYSOFTRST	BIT(31)
+#define DWC3_GUSB3PIPECTL_U2SSINP3OK	BIT(29)
+#define DWC3_GUSB3PIPECTL_DISRXDETINP3	BIT(28)
+#define DWC3_GUSB3PIPECTL_UX_EXIT_PX	BIT(27)
+#define DWC3_GUSB3PIPECTL_REQP1P2P3	BIT(24)
+#define DWC3_GUSB3PIPECTL_DEP1P2P3(n)	((n) << 19)
+#define DWC3_GUSB3PIPECTL_DEP1P2P3_MASK	DWC3_GUSB3PIPECTL_DEP1P2P3(7)
+#define DWC3_GUSB3PIPECTL_DEP1P2P3_EN	DWC3_GUSB3PIPECTL_DEP1P2P3(1)
+#define DWC3_GUSB3PIPECTL_DEPOCHANGE	BIT(18)
+#define DWC3_GUSB3PIPECTL_SUSPHY	BIT(17)
+#define DWC3_GUSB3PIPECTL_LFPSFILT	BIT(9)
+#define DWC3_GUSB3PIPECTL_RX_DETOPOLL	BIT(8)
+#define DWC3_GUSB3PIPECTL_TX_DEEPH_MASK	DWC3_GUSB3PIPECTL_TX_DEEPH(3)
+#define DWC3_GUSB3PIPECTL_TX_DEEPH(n)	((n) << 1)
+
+/* Global TX Fifo Size Register */
+#define DWC31_GTXFIFOSIZ_TXFRAMNUM	BIT(15)		/* DWC_usb31 only */
+#define DWC31_GTXFIFOSIZ_TXFDEF(n)	((n) & 0x7fff)	/* DWC_usb31 only */
+#define DWC3_GTXFIFOSIZ_TXFDEF(n)	((n) & 0xffff)
+#define DWC3_GTXFIFOSIZ_TXFSTADDR(n)	((n) & 0xffff0000)
+
+/* Global Event Size Registers */
+#define DWC3_GEVNTSIZ_INTMASK		BIT(31)
+#define DWC3_GEVNTSIZ_SIZE(n)		((n) & 0xffff)
+
+/* Global HWPARAMS0 Register */
+#define DWC3_GHWPARAMS0_MODE(n)		((n) & 0x3)
+#define DWC3_GHWPARAMS0_MODE_GADGET	0
+#define DWC3_GHWPARAMS0_MODE_HOST	1
+#define DWC3_GHWPARAMS0_MODE_DRD	2
+#define DWC3_GHWPARAMS0_MBUS_TYPE(n)	(((n) >> 3) & 0x7)
+#define DWC3_GHWPARAMS0_SBUS_TYPE(n)	(((n) >> 6) & 0x3)
+#define DWC3_GHWPARAMS0_MDWIDTH(n)	(((n) >> 8) & 0xff)
+#define DWC3_GHWPARAMS0_SDWIDTH(n)	(((n) >> 16) & 0xff)
+#define DWC3_GHWPARAMS0_AWIDTH(n)	(((n) >> 24) & 0xff)
+
+/* Global HWPARAMS1 Register */
+#define DWC3_GHWPARAMS1_EN_PWROPT(n)	(((n) & (3 << 24)) >> 24)
+#define DWC3_GHWPARAMS1_EN_PWROPT_NO	0
+#define DWC3_GHWPARAMS1_EN_PWROPT_CLK	1
+#define DWC3_GHWPARAMS1_EN_PWROPT_HIB	2
+#define DWC3_GHWPARAMS1_PWROPT(n)	((n) << 24)
+#define DWC3_GHWPARAMS1_PWROPT_MASK	DWC3_GHWPARAMS1_PWROPT(3)
+#define DWC3_GHWPARAMS1_ENDBC		BIT(31)
+
+/* Global HWPARAMS3 Register */
+#define DWC3_GHWPARAMS3_SSPHY_IFC(n)		((n) & 3)
+#define DWC3_GHWPARAMS3_SSPHY_IFC_DIS		0
+#define DWC3_GHWPARAMS3_SSPHY_IFC_GEN1		1
+#define DWC3_GHWPARAMS3_SSPHY_IFC_GEN2		2 /* DWC_usb31 only */
+#define DWC3_GHWPARAMS3_HSPHY_IFC(n)		(((n) & (3 << 2)) >> 2)
+#define DWC3_GHWPARAMS3_HSPHY_IFC_DIS		0
+#define DWC3_GHWPARAMS3_HSPHY_IFC_UTMI		1
+#define DWC3_GHWPARAMS3_HSPHY_IFC_ULPI		2
+#define DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI	3
+#define DWC3_GHWPARAMS3_FSPHY_IFC(n)		(((n) & (3 << 4)) >> 4)
+#define DWC3_GHWPARAMS3_FSPHY_IFC_DIS		0
+#define DWC3_GHWPARAMS3_FSPHY_IFC_ENA		1
+
+/* Global HWPARAMS4 Register */
+#define DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(n)	(((n) & (0x0f << 13)) >> 13)
+#define DWC3_MAX_HIBER_SCRATCHBUFS		15
+
+/* Global HWPARAMS6 Register */
+#define DWC3_GHWPARAMS6_BCSUPPORT		BIT(14)
+#define DWC3_GHWPARAMS6_OTG3SUPPORT		BIT(13)
+#define DWC3_GHWPARAMS6_ADPSUPPORT		BIT(12)
+#define DWC3_GHWPARAMS6_HNPSUPPORT		BIT(11)
+#define DWC3_GHWPARAMS6_SRPSUPPORT		BIT(10)
+#define DWC3_GHWPARAMS6_EN_FPGA			BIT(7)
+
+/* Global HWPARAMS7 Register */
+#define DWC3_GHWPARAMS7_RAM1_DEPTH(n)	((n) & 0xffff)
+#define DWC3_GHWPARAMS7_RAM2_DEPTH(n)	(((n) >> 16) & 0xffff)
+
+/* Global Frame Length Adjustment Register */
+#define DWC3_GFLADJ_30MHZ_SDBND_SEL		BIT(7)
+#define DWC3_GFLADJ_30MHZ_MASK			0x3f
+
+/* Global User Control Register 2 */
+#define DWC3_GUCTL2_RST_ACTBITLATER		BIT(14)
+
+/* Device Configuration Register */
+#define DWC3_DCFG_DEVADDR(addr)	((addr) << 3)
+#define DWC3_DCFG_DEVADDR_MASK	DWC3_DCFG_DEVADDR(0x7f)
+
+#define DWC3_DCFG_SPEED_MASK	(7 << 0)
+#define DWC3_DCFG_SUPERSPEED_PLUS (5 << 0)  /* DWC_usb31 only */
+#define DWC3_DCFG_SUPERSPEED	(4 << 0)
+#define DWC3_DCFG_HIGHSPEED	(0 << 0)
+#define DWC3_DCFG_FULLSPEED	BIT(0)
+#define DWC3_DCFG_LOWSPEED	(2 << 0)
+
+#define DWC3_DCFG_NUMP_SHIFT	17
+#define DWC3_DCFG_NUMP(n)	(((n) >> DWC3_DCFG_NUMP_SHIFT) & 0x1f)
+#define DWC3_DCFG_NUMP_MASK	(0x1f << DWC3_DCFG_NUMP_SHIFT)
+#define DWC3_DCFG_LPM_CAP	BIT(22)
+
+/* Device Control Register */
+#define DWC3_DCTL_RUN_STOP	BIT(31)
+#define DWC3_DCTL_CSFTRST	BIT(30)
+#define DWC3_DCTL_LSFTRST	BIT(29)
+
+#define DWC3_DCTL_HIRD_THRES_MASK	(0x1f << 24)
+#define DWC3_DCTL_HIRD_THRES(n)	((n) << 24)
+
+#define DWC3_DCTL_APPL1RES	BIT(23)
+
+/* These apply for core versions 1.87a and earlier */
+#define DWC3_DCTL_TRGTULST_MASK		(0x0f << 17)
+#define DWC3_DCTL_TRGTULST(n)		((n) << 17)
+#define DWC3_DCTL_TRGTULST_U2		(DWC3_DCTL_TRGTULST(2))
+#define DWC3_DCTL_TRGTULST_U3		(DWC3_DCTL_TRGTULST(3))
+#define DWC3_DCTL_TRGTULST_SS_DIS	(DWC3_DCTL_TRGTULST(4))
+#define DWC3_DCTL_TRGTULST_RX_DET	(DWC3_DCTL_TRGTULST(5))
+#define DWC3_DCTL_TRGTULST_SS_INACT	(DWC3_DCTL_TRGTULST(6))
+
+/* These apply for core versions 1.94a and later */
+#define DWC3_DCTL_LPM_ERRATA_MASK	DWC3_DCTL_LPM_ERRATA(0xf)
+#define DWC3_DCTL_LPM_ERRATA(n)		((n) << 20)
+
+#define DWC3_DCTL_KEEP_CONNECT		BIT(19)
+#define DWC3_DCTL_L1_HIBER_EN		BIT(18)
+#define DWC3_DCTL_CRS			BIT(17)
+#define DWC3_DCTL_CSS			BIT(16)
+
+#define DWC3_DCTL_INITU2ENA		BIT(12)
+#define DWC3_DCTL_ACCEPTU2ENA		BIT(11)
+#define DWC3_DCTL_INITU1ENA		BIT(10)
+#define DWC3_DCTL_ACCEPTU1ENA		BIT(9)
+#define DWC3_DCTL_TSTCTRL_MASK		(0xf << 1)
+
+#define DWC3_DCTL_ULSTCHNGREQ_MASK	(0x0f << 5)
+#define DWC3_DCTL_ULSTCHNGREQ(n) (((n) << 5) & DWC3_DCTL_ULSTCHNGREQ_MASK)
+
+#define DWC3_DCTL_ULSTCHNG_NO_ACTION	(DWC3_DCTL_ULSTCHNGREQ(0))
+#define DWC3_DCTL_ULSTCHNG_SS_DISABLED	(DWC3_DCTL_ULSTCHNGREQ(4))
+#define DWC3_DCTL_ULSTCHNG_RX_DETECT	(DWC3_DCTL_ULSTCHNGREQ(5))
+#define DWC3_DCTL_ULSTCHNG_SS_INACTIVE	(DWC3_DCTL_ULSTCHNGREQ(6))
+#define DWC3_DCTL_ULSTCHNG_RECOVERY	(DWC3_DCTL_ULSTCHNGREQ(8))
+#define DWC3_DCTL_ULSTCHNG_COMPLIANCE	(DWC3_DCTL_ULSTCHNGREQ(10))
+#define DWC3_DCTL_ULSTCHNG_LOOPBACK	(DWC3_DCTL_ULSTCHNGREQ(11))
+
+/* Device Event Enable Register */
+#define DWC3_DEVTEN_VNDRDEVTSTRCVEDEN	BIT(12)
+#define DWC3_DEVTEN_EVNTOVERFLOWEN	BIT(11)
+#define DWC3_DEVTEN_CMDCMPLTEN		BIT(10)
+#define DWC3_DEVTEN_ERRTICERREN		BIT(9)
+#define DWC3_DEVTEN_SOFEN		BIT(7)
+#define DWC3_DEVTEN_EOPFEN		BIT(6)
+#define DWC3_DEVTEN_HIBERNATIONREQEVTEN	BIT(5)
+#define DWC3_DEVTEN_WKUPEVTEN		BIT(4)
+#define DWC3_DEVTEN_ULSTCNGEN		BIT(3)
+#define DWC3_DEVTEN_CONNECTDONEEN	BIT(2)
+#define DWC3_DEVTEN_USBRSTEN		BIT(1)
+#define DWC3_DEVTEN_DISCONNEVTEN	BIT(0)
+
+/* Device Status Register */
+#define DWC3_DSTS_DCNRD			BIT(29)
+
+/* This applies for core versions 1.87a and earlier */
+#define DWC3_DSTS_PWRUPREQ		BIT(24)
+
+/* These apply for core versions 1.94a and later */
+#define DWC3_DSTS_RSS			BIT(25)
+#define DWC3_DSTS_SSS			BIT(24)
+
+#define DWC3_DSTS_COREIDLE		BIT(23)
+#define DWC3_DSTS_DEVCTRLHLT		BIT(22)
+
+#define DWC3_DSTS_USBLNKST_MASK		(0x0f << 18)
+#define DWC3_DSTS_USBLNKST(n)		(((n) & DWC3_DSTS_USBLNKST_MASK) >> 18)
+
+#define DWC3_DSTS_RXFIFOEMPTY		BIT(17)
+
+#define DWC3_DSTS_SOFFN_MASK		(0x3fff << 3)
+#define DWC3_DSTS_SOFFN(n)		(((n) & DWC3_DSTS_SOFFN_MASK) >> 3)
+
+#define DWC3_DSTS_CONNECTSPD		(7 << 0)
+
+#define DWC3_DSTS_SUPERSPEED_PLUS	(5 << 0) /* DWC_usb31 only */
+#define DWC3_DSTS_SUPERSPEED		(4 << 0)
+#define DWC3_DSTS_HIGHSPEED		(0 << 0)
+#define DWC3_DSTS_FULLSPEED		BIT(0)
+#define DWC3_DSTS_LOWSPEED		(2 << 0)
+
+/* Device Generic Command Register */
+#define DWC3_DGCMD_SET_LMP		0x01
+#define DWC3_DGCMD_SET_PERIODIC_PAR	0x02
+#define DWC3_DGCMD_XMIT_FUNCTION	0x03
+
+/* These apply for core versions 1.94a and later */
+#define DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO	0x04
+#define DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI	0x05
+
+#define DWC3_DGCMD_SELECTED_FIFO_FLUSH	0x09
+#define DWC3_DGCMD_ALL_FIFO_FLUSH	0x0a
+#define DWC3_DGCMD_SET_ENDPOINT_NRDY	0x0c
+#define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK	0x10
+
+#define DWC3_DGCMD_STATUS(n)		(((n) >> 12) & 0x0F)
+#define DWC3_DGCMD_CMDACT		BIT(10)
+#define DWC3_DGCMD_CMDIOC		BIT(8)
+
+/* Device Generic Command Parameter Register */
+#define DWC3_DGCMDPAR_FORCE_LINKPM_ACCEPT	BIT(0)
+#define DWC3_DGCMDPAR_FIFO_NUM(n)		((n) << 0)
+#define DWC3_DGCMDPAR_RX_FIFO			(0 << 5)
+#define DWC3_DGCMDPAR_TX_FIFO			BIT(5)
+#define DWC3_DGCMDPAR_LOOPBACK_DIS		(0 << 0)
+#define DWC3_DGCMDPAR_LOOPBACK_ENA		BIT(0)
+
+/* Device Endpoint Command Register */
+#define DWC3_DEPCMD_PARAM_SHIFT		16
+#define DWC3_DEPCMD_PARAM(x)		((x) << DWC3_DEPCMD_PARAM_SHIFT)
+#define DWC3_DEPCMD_GET_RSC_IDX(x)	(((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
+#define DWC3_DEPCMD_STATUS(x)		(((x) >> 12) & 0x0F)
+#define DWC3_DEPCMD_HIPRI_FORCERM	BIT(11)
+#define DWC3_DEPCMD_CLEARPENDIN		BIT(11)
+#define DWC3_DEPCMD_CMDACT		BIT(10)
+#define DWC3_DEPCMD_CMDIOC		BIT(8)
+
+#define DWC3_DEPCMD_DEPSTARTCFG		(0x09 << 0)
+#define DWC3_DEPCMD_ENDTRANSFER		(0x08 << 0)
+#define DWC3_DEPCMD_UPDATETRANSFER	(0x07 << 0)
+#define DWC3_DEPCMD_STARTTRANSFER	(0x06 << 0)
+#define DWC3_DEPCMD_CLEARSTALL		(0x05 << 0)
+#define DWC3_DEPCMD_SETSTALL		(0x04 << 0)
+/* This applies for core versions 1.90a and earlier */
+#define DWC3_DEPCMD_GETSEQNUMBER	(0x03 << 0)
+/* This applies for core versions 1.94a and later */
+#define DWC3_DEPCMD_GETEPSTATE		(0x03 << 0)
+#define DWC3_DEPCMD_SETTRANSFRESOURCE	(0x02 << 0)
+#define DWC3_DEPCMD_SETEPCONFIG		(0x01 << 0)
+
+#define DWC3_DEPCMD_CMD(x)		((x) & 0xf)
+
+/* The EP number goes 0..31 so ep0 is always out and ep1 is always in */
+#define DWC3_DALEPENA_EP(n)		BIT(n)
+
+#define DWC3_DEPCMD_TYPE_CONTROL	0
+#define DWC3_DEPCMD_TYPE_ISOC		1
+#define DWC3_DEPCMD_TYPE_BULK		2
+#define DWC3_DEPCMD_TYPE_INTR		3
+
+#define DWC3_DEV_IMOD_COUNT_SHIFT	16
+#define DWC3_DEV_IMOD_COUNT_MASK	(0xffff << 16)
+#define DWC3_DEV_IMOD_INTERVAL_SHIFT	0
+#define DWC3_DEV_IMOD_INTERVAL_MASK	(0xffff << 0)
+
+/* OTG Configuration Register */
+#define DWC3_OCFG_DISPWRCUTTOFF		BIT(5)
+#define DWC3_OCFG_HIBDISMASK		BIT(4)
+#define DWC3_OCFG_SFTRSTMASK		BIT(3)
+#define DWC3_OCFG_OTGVERSION		BIT(2)
+#define DWC3_OCFG_HNPCAP		BIT(1)
+#define DWC3_OCFG_SRPCAP		BIT(0)
+
+/* OTG CTL Register */
+#define DWC3_OCTL_OTG3GOERR		BIT(7)
+#define DWC3_OCTL_PERIMODE		BIT(6)
+#define DWC3_OCTL_PRTPWRCTL		BIT(5)
+#define DWC3_OCTL_HNPREQ		BIT(4)
+#define DWC3_OCTL_SESREQ		BIT(3)
+#define DWC3_OCTL_TERMSELIDPULSE	BIT(2)
+#define DWC3_OCTL_DEVSETHNPEN		BIT(1)
+#define DWC3_OCTL_HSTSETHNPEN		BIT(0)
+
+/* OTG Event Register */
+#define DWC3_OEVT_DEVICEMODE		BIT(31)
+#define DWC3_OEVT_XHCIRUNSTPSET		BIT(27)
+#define DWC3_OEVT_DEVRUNSTPSET		BIT(26)
+#define DWC3_OEVT_HIBENTRY		BIT(25)
+#define DWC3_OEVT_CONIDSTSCHNG		BIT(24)
+#define DWC3_OEVT_HRRCONFNOTIF		BIT(23)
+#define DWC3_OEVT_HRRINITNOTIF		BIT(22)
+#define DWC3_OEVT_ADEVIDLE		BIT(21)
+#define DWC3_OEVT_ADEVBHOSTEND		BIT(20)
+#define DWC3_OEVT_ADEVHOST		BIT(19)
+#define DWC3_OEVT_ADEVHNPCHNG		BIT(18)
+#define DWC3_OEVT_ADEVSRPDET		BIT(17)
+#define DWC3_OEVT_ADEVSESSENDDET	BIT(16)
+#define DWC3_OEVT_BDEVBHOSTEND		BIT(11)
+#define DWC3_OEVT_BDEVHNPCHNG		BIT(10)
+#define DWC3_OEVT_BDEVSESSVLDDET	BIT(9)
+#define DWC3_OEVT_BDEVVBUSCHNG		BIT(8)
+#define DWC3_OEVT_BSESSVLD		BIT(3)
+#define DWC3_OEVT_HSTNEGSTS		BIT(2)
+#define DWC3_OEVT_SESREQSTS		BIT(1)
+#define DWC3_OEVT_ERROR			BIT(0)
+
+/* OTG Event Enable Register */
+#define DWC3_OEVTEN_XHCIRUNSTPSETEN	BIT(27)
+#define DWC3_OEVTEN_DEVRUNSTPSETEN	BIT(26)
+#define DWC3_OEVTEN_HIBENTRYEN		BIT(25)
+#define DWC3_OEVTEN_CONIDSTSCHNGEN	BIT(24)
+#define DWC3_OEVTEN_HRRCONFNOTIFEN	BIT(23)
+#define DWC3_OEVTEN_HRRINITNOTIFEN	BIT(22)
+#define DWC3_OEVTEN_ADEVIDLEEN		BIT(21)
+#define DWC3_OEVTEN_ADEVBHOSTENDEN	BIT(20)
+#define DWC3_OEVTEN_ADEVHOSTEN		BIT(19)
+#define DWC3_OEVTEN_ADEVHNPCHNGEN	BIT(18)
+#define DWC3_OEVTEN_ADEVSRPDETEN	BIT(17)
+#define DWC3_OEVTEN_ADEVSESSENDDETEN	BIT(16)
+#define DWC3_OEVTEN_BDEVBHOSTENDEN	BIT(11)
+#define DWC3_OEVTEN_BDEVHNPCHNGEN	BIT(10)
+#define DWC3_OEVTEN_BDEVSESSVLDDETEN	BIT(9)
+#define DWC3_OEVTEN_BDEVVBUSCHNGEN	BIT(8)
+
+/* OTG Status Register */
+#define DWC3_OSTS_DEVRUNSTP		BIT(13)
+#define DWC3_OSTS_XHCIRUNSTP		BIT(12)
+#define DWC3_OSTS_PERIPHERALSTATE	BIT(4)
+#define DWC3_OSTS_XHCIPRTPOWER		BIT(3)
+#define DWC3_OSTS_BSESVLD		BIT(2)
+#define DWC3_OSTS_VBUSVLD		BIT(1)
+#define DWC3_OSTS_CONIDSTS		BIT(0)
+
+/* Structures */
+
+struct dwc3_trb;
+
+#define DWC3_EP_FLAG_STALLED	BIT(0)
+#define DWC3_EP_FLAG_WEDGED	BIT(1)
+
+#define DWC3_EP_DIRECTION_TX	true
+#define DWC3_EP_DIRECTION_RX	false
+
+#define DWC3_TRB_NUM		256
+
+enum dwc3_phy {
+	DWC3_PHY_UNKNOWN = 0,
+	DWC3_PHY_USB3,
+	DWC3_PHY_USB2,
+};
+
+enum dwc3_ep0_next {
+	DWC3_EP0_UNKNOWN = 0,
+	DWC3_EP0_COMPLETE,
+	DWC3_EP0_NRDY_DATA,
+	DWC3_EP0_NRDY_STATUS,
+};
+
+enum dwc3_ep0_state {
+	EP0_UNCONNECTED		= 0,
+	EP0_SETUP_PHASE,
+	EP0_DATA_PHASE,
+	EP0_STATUS_PHASE,
+};
+
+enum dwc3_link_state {
+	/* In SuperSpeed */
+	DWC3_LINK_STATE_U0		= 0x00, /* in HS, means ON */
+	DWC3_LINK_STATE_U1		= 0x01,
+	DWC3_LINK_STATE_U2		= 0x02, /* in HS, means SLEEP */
+	DWC3_LINK_STATE_U3		= 0x03, /* in HS, means SUSPEND */
+	DWC3_LINK_STATE_SS_DIS		= 0x04,
+	DWC3_LINK_STATE_RX_DET		= 0x05, /* in HS, means Early Suspend */
+	DWC3_LINK_STATE_SS_INACT	= 0x06,
+	DWC3_LINK_STATE_POLL		= 0x07,
+	DWC3_LINK_STATE_RECOV		= 0x08,
+	DWC3_LINK_STATE_HRESET		= 0x09,
+	DWC3_LINK_STATE_CMPLY		= 0x0a,
+	DWC3_LINK_STATE_LPBK		= 0x0b,
+	DWC3_LINK_STATE_RESET		= 0x0e,
+	DWC3_LINK_STATE_RESUME		= 0x0f,
+	DWC3_LINK_STATE_MASK		= 0x0f,
+};
+
+/* TRB Length, PCM and Status */
+#define DWC3_TRB_SIZE_MASK	(0x00ffffff)
+#define DWC3_TRB_SIZE_LENGTH(n)	((n) & DWC3_TRB_SIZE_MASK)
+#define DWC3_TRB_SIZE_PCM1(n)	(((n) & 0x03) << 24)
+#define DWC3_TRB_SIZE_TRBSTS(n)	(((n) & (0x0f << 28)) >> 28)
+
+#define DWC3_TRBSTS_OK			0
+#define DWC3_TRBSTS_MISSED_ISOC		1
+#define DWC3_TRBSTS_SETUP_PENDING	2
+#define DWC3_TRB_STS_XFER_IN_PROG	4
+
+/* TRB Control */
+#define DWC3_TRB_CTRL_HWO		BIT(0)
+#define DWC3_TRB_CTRL_LST		BIT(1)
+#define DWC3_TRB_CTRL_CHN		BIT(2)
+#define DWC3_TRB_CTRL_CSP		BIT(3)
+#define DWC3_TRB_CTRL_TRBCTL(n)		(((n) & 0x3f) << 4)
+#define DWC3_TRB_CTRL_ISP_IMI		BIT(10)
+#define DWC3_TRB_CTRL_IOC		BIT(11)
+#define DWC3_TRB_CTRL_SID_SOFN(n)	(((n) & 0xffff) << 14)
+#define DWC3_TRB_CTRL_GET_SID_SOFN(n)	(((n) & (0xffff << 14)) >> 14)
+
+#define DWC3_TRBCTL_TYPE(n)		((n) & (0x3f << 4))
+#define DWC3_TRBCTL_NORMAL		DWC3_TRB_CTRL_TRBCTL(1)
+#define DWC3_TRBCTL_CONTROL_SETUP	DWC3_TRB_CTRL_TRBCTL(2)
+#define DWC3_TRBCTL_CONTROL_STATUS2	DWC3_TRB_CTRL_TRBCTL(3)
+#define DWC3_TRBCTL_CONTROL_STATUS3	DWC3_TRB_CTRL_TRBCTL(4)
+#define DWC3_TRBCTL_CONTROL_DATA	DWC3_TRB_CTRL_TRBCTL(5)
+#define DWC3_TRBCTL_ISOCHRONOUS_FIRST	DWC3_TRB_CTRL_TRBCTL(6)
+#define DWC3_TRBCTL_ISOCHRONOUS		DWC3_TRB_CTRL_TRBCTL(7)
+#define DWC3_TRBCTL_LINK_TRB		DWC3_TRB_CTRL_TRBCTL(8)
+
+/**
+ * struct dwc3_trb - transfer request block (hw format)
+ * @bpl: DW0-3
+ * @bph: DW4-7
+ * @size: DW8-B
+ * @ctrl: DWC-F
+ */
+struct dwc3_trb {
+	u32		bpl;
+	u32		bph;
+	u32		size;
+	u32		ctrl;
+} __packed;
+
+/**
+ * struct dwc3_hwparams - copy of HWPARAMS registers
+ * @hwparams0: GHWPARAMS0
+ * @hwparams1: GHWPARAMS1
+ * @hwparams2: GHWPARAMS2
+ * @hwparams3: GHWPARAMS3
+ * @hwparams4: GHWPARAMS4
+ * @hwparams5: GHWPARAMS5
+ * @hwparams6: GHWPARAMS6
+ * @hwparams7: GHWPARAMS7
+ * @hwparams8: GHWPARAMS8
+ */
+struct dwc3_hwparams {
+	u32	hwparams0;
+	u32	hwparams1;
+	u32	hwparams2;
+	u32	hwparams3;
+	u32	hwparams4;
+	u32	hwparams5;
+	u32	hwparams6;
+	u32	hwparams7;
+	u32	hwparams8;
+};
+
+/* HWPARAMS0 */
+#define DWC3_MODE(n)		((n) & 0x7)
+
+#define DWC3_MDWIDTH(n)		(((n) & 0xff00) >> 8)
+
+/* HWPARAMS1 */
+#define DWC3_NUM_INT(n)		(((n) & (0x3f << 15)) >> 15)
+
+/* HWPARAMS3 */
+#define DWC3_NUM_IN_EPS_MASK	(0x1f << 18)
+#define DWC3_NUM_EPS_MASK	(0x3f << 12)
+#define DWC3_NUM_EPS(p)		(((p)->hwparams3 &		\
+			(DWC3_NUM_EPS_MASK)) >> 12)
+#define DWC3_NUM_IN_EPS(p)	(((p)->hwparams3 &		\
+			(DWC3_NUM_IN_EPS_MASK)) >> 18)
+
+/* HWPARAMS7 */
+#define DWC3_RAM1_DEPTH(n)	((n) & 0xffff)
+
+/**
+ * struct dwc3 - representation of our controller
+ * @drd_work: workqueue used for role swapping
+ * @ep0_trb: trb which is used for the ctrl_req
+ * @bounce: address of bounce buffer
+ * @scratchbuf: address of scratch buffer
+ * @setup_buf: used while precessing STD USB requests
+ * @ep0_trb_addr: dma address of @ep0_trb
+ * @bounce_addr: dma address of @bounce
+ * @ep0_usb_req: dummy req used while handling STD USB requests
+ * @scratch_addr: dma address of scratchbuf
+ * @ep0_in_setup: one control transfer is completed and enter setup phase
+ * @lock: for synchronizing
+ * @dev: pointer to our struct device
+ * @sysdev: pointer to the DMA-capable device
+ * @xhci: pointer to our xHCI child
+ * @xhci_resources: struct resources for our @xhci child
+ * @ev_buf: struct dwc3_event_buffer pointer
+ * @eps: endpoint array
+ * @gadget: device side representation of the peripheral controller
+ * @gadget_driver: pointer to the gadget driver
+ * @clks: array of clocks
+ * @num_clks: number of clocks
+ * @reset: reset control
+ * @regs: base address for our registers
+ * @regs_size: address space size
+ * @fladj: frame length adjustment
+ * @irq_gadget: peripheral controller's IRQ number
+ * @otg_irq: IRQ number for OTG IRQs
+ * @current_otg_role: current role of operation while using the OTG block
+ * @desired_otg_role: desired role of operation while using the OTG block
+ * @otg_restart_host: flag that OTG controller needs to restart host
+ * @nr_scratch: number of scratch buffers
+ * @u1u2: only used on revisions <1.83a for workaround
+ * @maximum_speed: maximum speed requested (mainly for testing purposes)
+ * @revision: revision register contents
+ * @version_type: VERSIONTYPE register contents, a sub release of a revision
+ * @dr_mode: requested mode of operation
+ * @current_dr_role: current role of operation when in dual-role mode
+ * @desired_dr_role: desired role of operation when in dual-role mode
+ * @edev: extcon handle
+ * @edev_nb: extcon notifier
+ * @hsphy_mode: UTMI phy mode, one of following:
+ *		- USBPHY_INTERFACE_MODE_UTMI
+ *		- USBPHY_INTERFACE_MODE_UTMIW
+ * @usb2_phy: pointer to USB2 PHY
+ * @usb3_phy: pointer to USB3 PHY
+ * @usb2_generic_phy: pointer to USB2 PHY
+ * @usb3_generic_phy: pointer to USB3 PHY
+ * @phys_ready: flag to indicate that PHYs are ready
+ * @ulpi: pointer to ulpi interface
+ * @ulpi_ready: flag to indicate that ULPI is initialized
+ * @u2sel: parameter from Set SEL request.
+ * @u2pel: parameter from Set SEL request.
+ * @u1sel: parameter from Set SEL request.
+ * @u1pel: parameter from Set SEL request.
+ * @num_eps: number of endpoints
+ * @ep0_next_event: hold the next expected event
+ * @ep0state: state of endpoint zero
+ * @link_state: link state
+ * @speed: device speed (super, high, full, low)
+ * @hwparams: copy of hwparams registers
+ * @root: debugfs root folder pointer
+ * @regset: debugfs pointer to regdump file
+ * @dbg_lsp_select: current debug lsp mux register selection
+ * @test_mode: true when we're entering a USB test mode
+ * @test_mode_nr: test feature selector
+ * @lpm_nyet_threshold: LPM NYET response threshold
+ * @hird_threshold: HIRD threshold
+ * @rx_thr_num_pkt_prd: periodic ESS receive packet count
+ * @rx_max_burst_prd: max periodic ESS receive burst size
+ * @tx_thr_num_pkt_prd: periodic ESS transmit packet count
+ * @tx_max_burst_prd: max periodic ESS transmit burst size
+ * @hsphy_interface: "utmi" or "ulpi"
+ * @connected: true when we're connected to a host, false otherwise
+ * @delayed_status: true when gadget driver asks for delayed status
+ * @ep0_bounced: true when we used bounce buffer
+ * @ep0_expect_in: true when we expect a DATA IN transfer
+ * @has_hibernation: true when dwc3 was configured with Hibernation
+ * @sysdev_is_parent: true when dwc3 device has a parent driver
+ * @has_lpm_erratum: true when core was configured with LPM Erratum. Note that
+ *			there's now way for software to detect this in runtime.
+ * @is_utmi_l1_suspend: the core asserts output signal
+ * 	0	- utmi_sleep_n
+ * 	1	- utmi_l1_suspend_n
+ * @is_fpga: true when we are using the FPGA board
+ * @pending_events: true when we have pending IRQs to be handled
+ * @pullups_connected: true when Run/Stop bit is set
+ * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
+ * @three_stage_setup: set if we perform a three phase setup
+ * @dis_start_transfer_quirk: set if start_transfer failure SW workaround is
+ *			not needed for DWC_usb31 version 1.70a-ea06 and below
+ * @usb3_lpm_capable: set if hadrware supports Link Power Management
+ * @usb2_lpm_disable: set to disable usb2 lpm
+ * @disable_scramble_quirk: set if we enable the disable scramble quirk
+ * @u2exit_lfps_quirk: set if we enable u2exit lfps quirk
+ * @u2ss_inp3_quirk: set if we enable P3 OK for U2/SS Inactive quirk
+ * @req_p1p2p3_quirk: set if we enable request p1p2p3 quirk
+ * @del_p1p2p3_quirk: set if we enable delay p1p2p3 quirk
+ * @del_phy_power_chg_quirk: set if we enable delay phy power change quirk
+ * @lfps_filter_quirk: set if we enable LFPS filter quirk
+ * @rx_detect_poll_quirk: set if we enable rx_detect to polling lfps quirk
+ * @dis_u3_susphy_quirk: set if we disable usb3 suspend phy
+ * @dis_u2_susphy_quirk: set if we disable usb2 suspend phy
+ * @dis_enblslpm_quirk: set if we clear enblslpm in GUSB2PHYCFG,
+ *                      disabling the suspend signal to the PHY.
+ * @dis_rxdet_inp3_quirk: set if we disable Rx.Detect in P3
+ * @dis_u2_freeclk_exists_quirk : set if we clear u2_freeclk_exists
+ *			in GUSB2PHYCFG, specify that USB2 PHY doesn't
+ *			provide a free-running PHY clock.
+ * @dis_del_phy_power_chg_quirk: set if we disable delay phy power
+ *			change quirk.
+ * @dis_tx_ipgap_linecheck_quirk: set if we disable u2mac linestate
+ *			check during HS transmit.
+ * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk
+ * @tx_de_emphasis: Tx de-emphasis value
+ * 	0	- -6dB de-emphasis
+ * 	1	- -3.5dB de-emphasis
+ * 	2	- No de-emphasis
+ * 	3	- Reserved
+ * @dis_metastability_quirk: set to disable metastability quirk.
+ * @imod_interval: set the interrupt moderation interval in 250ns
+ *                 increments or 0 to disable.
+ */
+struct dwc3 {
+	struct device_d		*dev;
+	struct device_d		*xhci;
+
+	struct clk_bulk_data	*clks;
+	int			num_clks;
+
+	struct phy		*usb2_generic_phy;
+	struct phy		*usb3_generic_phy;
+
+	bool			phys_ready;
+
+	void __iomem		*regs;
+
+	enum usb_dr_mode	dr_mode;
+	u32			current_dr_role;
+	u32			desired_dr_role;
+
+	u32			fladj;
+	u32			irq_gadget;
+	u32			otg_irq;
+	u32			current_otg_role;
+	u32			desired_otg_role;
+	bool			otg_restart_host;
+	u32			nr_scratch;
+	u32			u1u2;
+	u32			maximum_speed;
+
+	/*
+	 * All 3.1 IP version constants are greater than the 3.0 IP
+	 * version constants. This works for most version checks in
+	 * dwc3. However, in the future, this may not apply as
+	 * features may be developed on newer versions of the 3.0 IP
+	 * that are not in the 3.1 IP.
+	 */
+	u32			revision;
+
+#define DWC3_REVISION_173A	0x5533173a
+#define DWC3_REVISION_175A	0x5533175a
+#define DWC3_REVISION_180A	0x5533180a
+#define DWC3_REVISION_183A	0x5533183a
+#define DWC3_REVISION_185A	0x5533185a
+#define DWC3_REVISION_187A	0x5533187a
+#define DWC3_REVISION_188A	0x5533188a
+#define DWC3_REVISION_190A	0x5533190a
+#define DWC3_REVISION_194A	0x5533194a
+#define DWC3_REVISION_200A	0x5533200a
+#define DWC3_REVISION_202A	0x5533202a
+#define DWC3_REVISION_210A	0x5533210a
+#define DWC3_REVISION_220A	0x5533220a
+#define DWC3_REVISION_230A	0x5533230a
+#define DWC3_REVISION_240A	0x5533240a
+#define DWC3_REVISION_250A	0x5533250a
+#define DWC3_REVISION_260A	0x5533260a
+#define DWC3_REVISION_270A	0x5533270a
+#define DWC3_REVISION_280A	0x5533280a
+#define DWC3_REVISION_290A	0x5533290a
+#define DWC3_REVISION_300A	0x5533300a
+#define DWC3_REVISION_310A	0x5533310a
+#define DWC3_REVISION_330A	0x5533330a
+
+/*
+ * NOTICE: we're using bit 31 as a "is usb 3.1" flag. This is really
+ * just so dwc31 revisions are always larger than dwc3.
+ */
+#define DWC3_REVISION_IS_DWC31		0x80000000
+#define DWC3_USB31_REVISION_110A	(0x3131302a | DWC3_REVISION_IS_DWC31)
+#define DWC3_USB31_REVISION_120A	(0x3132302a | DWC3_REVISION_IS_DWC31)
+#define DWC3_USB31_REVISION_160A	(0x3136302a | DWC3_REVISION_IS_DWC31)
+#define DWC3_USB31_REVISION_170A	(0x3137302a | DWC3_REVISION_IS_DWC31)
+
+	u32			version_type;
+
+#define DWC31_VERSIONTYPE_EA01		0x65613031
+#define DWC31_VERSIONTYPE_EA02		0x65613032
+#define DWC31_VERSIONTYPE_EA03		0x65613033
+#define DWC31_VERSIONTYPE_EA04		0x65613034
+#define DWC31_VERSIONTYPE_EA05		0x65613035
+#define DWC31_VERSIONTYPE_EA06		0x65613036
+
+	u16			u2sel;
+	u16			u2pel;
+	u8			u1sel;
+	u8			u1pel;
+
+	u8			speed;
+
+	u8			num_eps;
+
+	struct dwc3_hwparams	hwparams;
+
+	u32			dbg_lsp_select;
+
+	u8			test_mode;
+	u8			test_mode_nr;
+	u8			lpm_nyet_threshold;
+	u8			hird_threshold;
+	u8			rx_thr_num_pkt_prd;
+	u8			rx_max_burst_prd;
+	u8			tx_thr_num_pkt_prd;
+	u8			tx_max_burst_prd;
+
+	const char		*hsphy_interface;
+
+	unsigned		connected:1;
+	unsigned		delayed_status:1;
+	unsigned		ep0_bounced:1;
+	unsigned		ep0_expect_in:1;
+	unsigned		has_hibernation:1;
+	unsigned		sysdev_is_parent:1;
+	unsigned		has_lpm_erratum:1;
+	unsigned		is_utmi_l1_suspend:1;
+	unsigned		is_fpga:1;
+	unsigned		pending_events:1;
+	unsigned		pullups_connected:1;
+	unsigned		setup_packet_pending:1;
+	unsigned		three_stage_setup:1;
+	unsigned		dis_start_transfer_quirk:1;
+	unsigned		usb3_lpm_capable:1;
+	unsigned		usb2_lpm_disable:1;
+
+	unsigned		disable_scramble_quirk:1;
+	unsigned		u2exit_lfps_quirk:1;
+	unsigned		u2ss_inp3_quirk:1;
+	unsigned		req_p1p2p3_quirk:1;
+	unsigned                del_p1p2p3_quirk:1;
+	unsigned		del_phy_power_chg_quirk:1;
+	unsigned		lfps_filter_quirk:1;
+	unsigned		rx_detect_poll_quirk:1;
+	unsigned		dis_u3_susphy_quirk:1;
+	unsigned		dis_u2_susphy_quirk:1;
+	unsigned		dis_enblslpm_quirk:1;
+	unsigned		dis_rxdet_inp3_quirk:1;
+	unsigned		dis_u2_freeclk_exists_quirk:1;
+	unsigned		dis_del_phy_power_chg_quirk:1;
+	unsigned		dis_tx_ipgap_linecheck_quirk:1;
+
+	unsigned		tx_de_emphasis_quirk:1;
+	unsigned		tx_de_emphasis:2;
+
+	unsigned		dis_metastability_quirk:1;
+
+	u16			imod_interval;
+};
+
+#define INCRX_BURST_MODE 0
+#define INCRX_UNDEF_LENGTH_BURST_MODE 1
+
+#define work_to_dwc(w)		(container_of((w), struct dwc3, drd_work))
+
+/* -------------------------------------------------------------------------- */
+
+struct dwc3_event_type {
+	u32	is_devspec:1;
+	u32	type:7;
+	u32	reserved8_31:24;
+} __packed;
+
+#define DWC3_DEPEVT_XFERCOMPLETE	0x01
+#define DWC3_DEPEVT_XFERINPROGRESS	0x02
+#define DWC3_DEPEVT_XFERNOTREADY	0x03
+#define DWC3_DEPEVT_RXTXFIFOEVT		0x04
+#define DWC3_DEPEVT_STREAMEVT		0x06
+#define DWC3_DEPEVT_EPCMDCMPLT		0x07
+
+/**
+ * struct dwc3_event_depvt - Device Endpoint Events
+ * @one_bit: indicates this is an endpoint event (not used)
+ * @endpoint_number: number of the endpoint
+ * @endpoint_event: The event we have:
+ *	0x00	- Reserved
+ *	0x01	- XferComplete
+ *	0x02	- XferInProgress
+ *	0x03	- XferNotReady
+ *	0x04	- RxTxFifoEvt (IN->Underrun, OUT->Overrun)
+ *	0x05	- Reserved
+ *	0x06	- StreamEvt
+ *	0x07	- EPCmdCmplt
+ * @reserved11_10: Reserved, don't use.
+ * @status: Indicates the status of the event. Refer to databook for
+ *	more information.
+ * @parameters: Parameters of the current event. Refer to databook for
+ *	more information.
+ */
+struct dwc3_event_depevt {
+	u32	one_bit:1;
+	u32	endpoint_number:5;
+	u32	endpoint_event:4;
+	u32	reserved11_10:2;
+	u32	status:4;
+
+/* Within XferNotReady */
+#define DEPEVT_STATUS_TRANSFER_ACTIVE	BIT(3)
+
+/* Within XferComplete or XferInProgress */
+#define DEPEVT_STATUS_BUSERR	BIT(0)
+#define DEPEVT_STATUS_SHORT	BIT(1)
+#define DEPEVT_STATUS_IOC	BIT(2)
+#define DEPEVT_STATUS_LST	BIT(3) /* XferComplete */
+#define DEPEVT_STATUS_MISSED_ISOC BIT(3) /* XferInProgress */
+
+/* Stream event only */
+#define DEPEVT_STREAMEVT_FOUND		1
+#define DEPEVT_STREAMEVT_NOTFOUND	2
+
+/* Control-only Status */
+#define DEPEVT_STATUS_CONTROL_DATA	1
+#define DEPEVT_STATUS_CONTROL_STATUS	2
+#define DEPEVT_STATUS_CONTROL_PHASE(n)	((n) & 3)
+
+/* In response to Start Transfer */
+#define DEPEVT_TRANSFER_NO_RESOURCE	1
+#define DEPEVT_TRANSFER_BUS_EXPIRY	2
+
+	u32	parameters:16;
+
+/* For Command Complete Events */
+#define DEPEVT_PARAMETER_CMD(n)	(((n) & (0xf << 8)) >> 8)
+} __packed;
+
+/**
+ * struct dwc3_event_devt - Device Events
+ * @one_bit: indicates this is a non-endpoint event (not used)
+ * @device_event: indicates it's a device event. Should read as 0x00
+ * @type: indicates the type of device event.
+ *	0	- DisconnEvt
+ *	1	- USBRst
+ *	2	- ConnectDone
+ *	3	- ULStChng
+ *	4	- WkUpEvt
+ *	5	- Reserved
+ *	6	- EOPF
+ *	7	- SOF
+ *	8	- Reserved
+ *	9	- ErrticErr
+ *	10	- CmdCmplt
+ *	11	- EvntOverflow
+ *	12	- VndrDevTstRcved
+ * @reserved15_12: Reserved, not used
+ * @event_info: Information about this event
+ * @reserved31_25: Reserved, not used
+ */
+struct dwc3_event_devt {
+	u32	one_bit:1;
+	u32	device_event:7;
+	u32	type:4;
+	u32	reserved15_12:4;
+	u32	event_info:9;
+	u32	reserved31_25:7;
+} __packed;
+
+/**
+ * struct dwc3_event_gevt - Other Core Events
+ * @one_bit: indicates this is a non-endpoint event (not used)
+ * @device_event: indicates it's (0x03) Carkit or (0x04) I2C event.
+ * @phy_port_number: self-explanatory
+ * @reserved31_12: Reserved, not used.
+ */
+struct dwc3_event_gevt {
+	u32	one_bit:1;
+	u32	device_event:7;
+	u32	phy_port_number:4;
+	u32	reserved31_12:20;
+} __packed;
+
+/**
+ * union dwc3_event - representation of Event Buffer contents
+ * @raw: raw 32-bit event
+ * @type: the type of the event
+ * @depevt: Device Endpoint Event
+ * @devt: Device Event
+ * @gevt: Global Event
+ */
+union dwc3_event {
+	u32				raw;
+	struct dwc3_event_type		type;
+	struct dwc3_event_depevt	depevt;
+	struct dwc3_event_devt		devt;
+	struct dwc3_event_gevt		gevt;
+};
+
+/**
+ * struct dwc3_gadget_ep_cmd_params - representation of endpoint command
+ * parameters
+ * @param2: third parameter
+ * @param1: second parameter
+ * @param0: first parameter
+ */
+struct dwc3_gadget_ep_cmd_params {
+	u32	param2;
+	u32	param1;
+	u32	param0;
+};
+
+/*
+ * DWC3 Features to be used as Driver Data
+ */
+
+#define DWC3_HAS_PERIPHERAL		BIT(0)
+#define DWC3_HAS_XHCI			BIT(1)
+#define DWC3_HAS_OTG			BIT(3)
+
+/* prototypes */
+void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode);
+void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
+
+/* check whether we are on the DWC_usb3 core */
+static inline bool dwc3_is_usb3(struct dwc3 *dwc)
+{
+	return !(dwc->revision & DWC3_REVISION_IS_DWC31);
+}
+
+/* check whether we are on the DWC_usb31 core */
+static inline bool dwc3_is_usb31(struct dwc3 *dwc)
+{
+	return !!(dwc->revision & DWC3_REVISION_IS_DWC31);
+}
+
+bool dwc3_has_imod(struct dwc3 *dwc);
+
+int dwc3_event_buffers_setup(struct dwc3 *dwc);
+void dwc3_event_buffers_cleanup(struct dwc3 *dwc);
+
+#if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
+int dwc3_host_init(struct dwc3 *dwc);
+#else
+static inline int dwc3_host_init(struct dwc3 *dwc)
+{ return 0; }
+#endif
+
+#if IS_ENABLED(CONFIG_USB_DWC3_GADGET) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
+int dwc3_gadget_init(struct dwc3 *dwc);
+void dwc3_gadget_exit(struct dwc3 *dwc);
+int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode);
+int dwc3_gadget_get_link_state(struct dwc3 *dwc);
+int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state);
+int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd,
+		struct dwc3_gadget_ep_cmd_params *params);
+int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param);
+#else
+static inline int dwc3_gadget_init(struct dwc3 *dwc)
+{ return 0; }
+static inline void dwc3_gadget_exit(struct dwc3 *dwc)
+{ }
+static inline int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode)
+{ return 0; }
+static inline int dwc3_gadget_get_link_state(struct dwc3 *dwc)
+{ return 0; }
+static inline int dwc3_gadget_set_link_state(struct dwc3 *dwc,
+		enum dwc3_link_state state)
+{ return 0; }
+
+static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc,
+		int cmd, u32 param)
+{ return 0; }
+#endif
+
+#if IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
+int dwc3_drd_init(struct dwc3 *dwc);
+void dwc3_drd_exit(struct dwc3 *dwc);
+void dwc3_otg_init(struct dwc3 *dwc);
+void dwc3_otg_exit(struct dwc3 *dwc);
+void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus);
+void dwc3_otg_host_init(struct dwc3 *dwc);
+#else
+static inline int dwc3_drd_init(struct dwc3 *dwc)
+{ return 0; }
+static inline void dwc3_drd_exit(struct dwc3 *dwc)
+{ }
+static inline void dwc3_otg_init(struct dwc3 *dwc)
+{ }
+static inline void dwc3_otg_exit(struct dwc3 *dwc)
+{ }
+static inline void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus)
+{ }
+static inline void dwc3_otg_host_init(struct dwc3 *dwc)
+{ }
+#endif
+
+/* power management interface */
+#if !IS_ENABLED(CONFIG_USB_DWC3_HOST)
+int dwc3_gadget_suspend(struct dwc3 *dwc);
+int dwc3_gadget_resume(struct dwc3 *dwc);
+void dwc3_gadget_process_pending_events(struct dwc3 *dwc);
+#else
+static inline int dwc3_gadget_suspend(struct dwc3 *dwc)
+{
+	return 0;
+}
+
+static inline int dwc3_gadget_resume(struct dwc3 *dwc)
+{
+	return 0;
+}
+
+static inline void dwc3_gadget_process_pending_events(struct dwc3 *dwc)
+{
+}
+#endif /* !IS_ENABLED(CONFIG_USB_DWC3_HOST) */
+
+#if IS_ENABLED(CONFIG_USB_DWC3_ULPI)
+int dwc3_ulpi_init(struct dwc3 *dwc);
+void dwc3_ulpi_exit(struct dwc3 *dwc);
+#else
+static inline int dwc3_ulpi_init(struct dwc3 *dwc)
+{ return 0; }
+static inline void dwc3_ulpi_exit(struct dwc3 *dwc)
+{ }
+#endif
+
+#endif /* __DRIVERS_USB_DWC3_CORE_H */
diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h
new file mode 100644
index 000000000..4f75ab350
--- /dev/null
+++ b/drivers/usb/dwc3/debug.h
@@ -0,0 +1,664 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * debug.h - DesignWare USB3 DRD Controller Debug Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ */
+
+#ifndef __DWC3_DEBUG_H
+#define __DWC3_DEBUG_H
+
+#include "core.h"
+
+/**
+ * dwc3_gadget_ep_cmd_string - returns endpoint command string
+ * @cmd: command code
+ */
+static inline const char *
+dwc3_gadget_ep_cmd_string(u8 cmd)
+{
+	switch (cmd) {
+	case DWC3_DEPCMD_DEPSTARTCFG:
+		return "Start New Configuration";
+	case DWC3_DEPCMD_ENDTRANSFER:
+		return "End Transfer";
+	case DWC3_DEPCMD_UPDATETRANSFER:
+		return "Update Transfer";
+	case DWC3_DEPCMD_STARTTRANSFER:
+		return "Start Transfer";
+	case DWC3_DEPCMD_CLEARSTALL:
+		return "Clear Stall";
+	case DWC3_DEPCMD_SETSTALL:
+		return "Set Stall";
+	case DWC3_DEPCMD_GETEPSTATE:
+		return "Get Endpoint State";
+	case DWC3_DEPCMD_SETTRANSFRESOURCE:
+		return "Set Endpoint Transfer Resource";
+	case DWC3_DEPCMD_SETEPCONFIG:
+		return "Set Endpoint Configuration";
+	default:
+		return "UNKNOWN command";
+	}
+}
+
+/**
+ * dwc3_gadget_generic_cmd_string - returns generic command string
+ * @cmd: command code
+ */
+static inline const char *
+dwc3_gadget_generic_cmd_string(u8 cmd)
+{
+	switch (cmd) {
+	case DWC3_DGCMD_SET_LMP:
+		return "Set LMP";
+	case DWC3_DGCMD_SET_PERIODIC_PAR:
+		return "Set Periodic Parameters";
+	case DWC3_DGCMD_XMIT_FUNCTION:
+		return "Transmit Function Wake Device Notification";
+	case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO:
+		return "Set Scratchpad Buffer Array Address Lo";
+	case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI:
+		return "Set Scratchpad Buffer Array Address Hi";
+	case DWC3_DGCMD_SELECTED_FIFO_FLUSH:
+		return "Selected FIFO Flush";
+	case DWC3_DGCMD_ALL_FIFO_FLUSH:
+		return "All FIFO Flush";
+	case DWC3_DGCMD_SET_ENDPOINT_NRDY:
+		return "Set Endpoint NRDY";
+	case DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK:
+		return "Run SoC Bus Loopback Test";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+/**
+ * dwc3_gadget_link_string - returns link name
+ * @link_state: link state code
+ */
+static inline const char *
+dwc3_gadget_link_string(enum dwc3_link_state link_state)
+{
+	switch (link_state) {
+	case DWC3_LINK_STATE_U0:
+		return "U0";
+	case DWC3_LINK_STATE_U1:
+		return "U1";
+	case DWC3_LINK_STATE_U2:
+		return "U2";
+	case DWC3_LINK_STATE_U3:
+		return "U3";
+	case DWC3_LINK_STATE_SS_DIS:
+		return "SS.Disabled";
+	case DWC3_LINK_STATE_RX_DET:
+		return "RX.Detect";
+	case DWC3_LINK_STATE_SS_INACT:
+		return "SS.Inactive";
+	case DWC3_LINK_STATE_POLL:
+		return "Polling";
+	case DWC3_LINK_STATE_RECOV:
+		return "Recovery";
+	case DWC3_LINK_STATE_HRESET:
+		return "Hot Reset";
+	case DWC3_LINK_STATE_CMPLY:
+		return "Compliance";
+	case DWC3_LINK_STATE_LPBK:
+		return "Loopback";
+	case DWC3_LINK_STATE_RESET:
+		return "Reset";
+	case DWC3_LINK_STATE_RESUME:
+		return "Resume";
+	default:
+		return "UNKNOWN link state\n";
+	}
+}
+
+/**
+ * dwc3_gadget_hs_link_string - returns highspeed and below link name
+ * @link_state: link state code
+ */
+static inline const char *
+dwc3_gadget_hs_link_string(enum dwc3_link_state link_state)
+{
+	switch (link_state) {
+	case DWC3_LINK_STATE_U0:
+		return "On";
+	case DWC3_LINK_STATE_U2:
+		return "Sleep";
+	case DWC3_LINK_STATE_U3:
+		return "Suspend";
+	case DWC3_LINK_STATE_SS_DIS:
+		return "Disconnected";
+	case DWC3_LINK_STATE_RX_DET:
+		return "Early Suspend";
+	case DWC3_LINK_STATE_RECOV:
+		return "Recovery";
+	case DWC3_LINK_STATE_RESET:
+		return "Reset";
+	case DWC3_LINK_STATE_RESUME:
+		return "Resume";
+	default:
+		return "UNKNOWN link state\n";
+	}
+}
+
+/**
+ * dwc3_trb_type_string - returns TRB type as a string
+ * @type: the type of the TRB
+ */
+static inline const char *dwc3_trb_type_string(unsigned int type)
+{
+	switch (type) {
+	case DWC3_TRBCTL_NORMAL:
+		return "normal";
+	case DWC3_TRBCTL_CONTROL_SETUP:
+		return "setup";
+	case DWC3_TRBCTL_CONTROL_STATUS2:
+		return "status2";
+	case DWC3_TRBCTL_CONTROL_STATUS3:
+		return "status3";
+	case DWC3_TRBCTL_CONTROL_DATA:
+		return "data";
+	case DWC3_TRBCTL_ISOCHRONOUS_FIRST:
+		return "isoc-first";
+	case DWC3_TRBCTL_ISOCHRONOUS:
+		return "isoc";
+	case DWC3_TRBCTL_LINK_TRB:
+		return "link";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+static inline const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)
+{
+	switch (state) {
+	case EP0_UNCONNECTED:
+		return "Unconnected";
+	case EP0_SETUP_PHASE:
+		return "Setup Phase";
+	case EP0_DATA_PHASE:
+		return "Data Phase";
+	case EP0_STATUS_PHASE:
+		return "Status Phase";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+/**
+ * dwc3_gadget_event_string - returns event name
+ * @event: the event code
+ */
+static inline const char *
+dwc3_gadget_event_string(char *str, const struct dwc3_event_devt *event)
+{
+	enum dwc3_link_state state = event->event_info & DWC3_LINK_STATE_MASK;
+
+	switch (event->type) {
+	case DWC3_DEVICE_EVENT_DISCONNECT:
+		sprintf(str, "Disconnect: [%s]",
+				dwc3_gadget_link_string(state));
+		break;
+	case DWC3_DEVICE_EVENT_RESET:
+		sprintf(str, "Reset [%s]", dwc3_gadget_link_string(state));
+		break;
+	case DWC3_DEVICE_EVENT_CONNECT_DONE:
+		sprintf(str, "Connection Done [%s]",
+				dwc3_gadget_link_string(state));
+		break;
+	case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
+		sprintf(str, "Link Change [%s]",
+				dwc3_gadget_link_string(state));
+		break;
+	case DWC3_DEVICE_EVENT_WAKEUP:
+		sprintf(str, "WakeUp [%s]", dwc3_gadget_link_string(state));
+		break;
+	case DWC3_DEVICE_EVENT_EOPF:
+		sprintf(str, "End-Of-Frame [%s]",
+				dwc3_gadget_link_string(state));
+		break;
+	case DWC3_DEVICE_EVENT_SOF:
+		sprintf(str, "Start-Of-Frame [%s]",
+				dwc3_gadget_link_string(state));
+		break;
+	case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
+		sprintf(str, "Erratic Error [%s]",
+				dwc3_gadget_link_string(state));
+		break;
+	case DWC3_DEVICE_EVENT_CMD_CMPL:
+		sprintf(str, "Command Complete [%s]",
+				dwc3_gadget_link_string(state));
+		break;
+	case DWC3_DEVICE_EVENT_OVERFLOW:
+		sprintf(str, "Overflow [%s]", dwc3_gadget_link_string(state));
+		break;
+	default:
+		sprintf(str, "UNKNOWN");
+	}
+
+	return str;
+}
+
+static inline void dwc3_decode_get_status(__u8 t, __u16 i, __u16 l, char *str)
+{
+	switch (t & USB_RECIP_MASK) {
+	case USB_RECIP_INTERFACE:
+		sprintf(str, "Get Interface Status(Intf = %d, Length = %d)",
+			i, l);
+		break;
+	case USB_RECIP_ENDPOINT:
+		sprintf(str, "Get Endpoint Status(ep%d%s)",
+			i & ~USB_DIR_IN,
+			i & USB_DIR_IN ? "in" : "out");
+		break;
+	}
+}
+
+static inline void dwc3_decode_set_clear_feature(__u8 t, __u8 b, __u16 v,
+						 __u16 i, char *str)
+{
+	switch (t & USB_RECIP_MASK) {
+	case USB_RECIP_DEVICE:
+		sprintf(str, "%s Device Feature(%s%s)",
+			b == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set",
+			({char *s;
+				switch (v) {
+				case USB_DEVICE_SELF_POWERED:
+					s = "Self Powered";
+					break;
+				case USB_DEVICE_REMOTE_WAKEUP:
+					s = "Remote Wakeup";
+					break;
+				case USB_DEVICE_TEST_MODE:
+					s = "Test Mode";
+					break;
+				case USB_DEVICE_U1_ENABLE:
+					s = "U1 Enable";
+					break;
+				case USB_DEVICE_U2_ENABLE:
+					s = "U2 Enable";
+					break;
+				case USB_DEVICE_LTM_ENABLE:
+					s = "LTM Enable";
+					break;
+				default:
+					s = "UNKNOWN";
+				} s; }),
+			v == USB_DEVICE_TEST_MODE ?
+			({ char *s;
+				switch (i) {
+				case TEST_J:
+					s = ": TEST_J";
+					break;
+				case TEST_K:
+					s = ": TEST_K";
+					break;
+				case TEST_SE0_NAK:
+					s = ": TEST_SE0_NAK";
+					break;
+				case TEST_PACKET:
+					s = ": TEST_PACKET";
+					break;
+				case TEST_FORCE_EN:
+					s = ": TEST_FORCE_EN";
+					break;
+				default:
+					s = ": UNKNOWN";
+				} s; }) : "");
+		break;
+	case USB_RECIP_INTERFACE:
+		sprintf(str, "%s Interface Feature(%s)",
+			b == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set",
+			v == USB_INTRF_FUNC_SUSPEND ?
+			"Function Suspend" : "UNKNOWN");
+		break;
+	case USB_RECIP_ENDPOINT:
+		sprintf(str, "%s Endpoint Feature(%s ep%d%s)",
+			b == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set",
+			v == USB_ENDPOINT_HALT ? "Halt" : "UNKNOWN",
+			i & ~USB_DIR_IN,
+			i & USB_DIR_IN ? "in" : "out");
+		break;
+	}
+}
+
+static inline void dwc3_decode_set_address(__u16 v, char *str)
+{
+	sprintf(str, "Set Address(Addr = %02x)", v);
+}
+
+static inline void dwc3_decode_get_set_descriptor(__u8 t, __u8 b, __u16 v,
+						  __u16 i, __u16 l, char *str)
+{
+	sprintf(str, "%s %s Descriptor(Index = %d, Length = %d)",
+		b == USB_REQ_GET_DESCRIPTOR ? "Get" : "Set",
+		({ char *s;
+			switch (v >> 8) {
+			case USB_DT_DEVICE:
+				s = "Device";
+				break;
+			case USB_DT_CONFIG:
+				s = "Configuration";
+				break;
+			case USB_DT_STRING:
+				s = "String";
+				break;
+			case USB_DT_INTERFACE:
+				s = "Interface";
+				break;
+			case USB_DT_ENDPOINT:
+				s = "Endpoint";
+				break;
+			case USB_DT_DEVICE_QUALIFIER:
+				s = "Device Qualifier";
+				break;
+			case USB_DT_OTHER_SPEED_CONFIG:
+				s = "Other Speed Config";
+				break;
+			case USB_DT_INTERFACE_POWER:
+				s = "Interface Power";
+				break;
+			case USB_DT_OTG:
+				s = "OTG";
+				break;
+			case USB_DT_DEBUG:
+				s = "Debug";
+				break;
+			case USB_DT_INTERFACE_ASSOCIATION:
+				s = "Interface Association";
+				break;
+			case USB_DT_BOS:
+				s = "BOS";
+				break;
+			case USB_DT_DEVICE_CAPABILITY:
+				s = "Device Capability";
+				break;
+			case USB_DT_PIPE_USAGE:
+				s = "Pipe Usage";
+				break;
+			case USB_DT_SS_ENDPOINT_COMP:
+				s = "SS Endpoint Companion";
+				break;
+			case USB_DT_SSP_ISOC_ENDPOINT_COMP:
+				s = "SSP Isochronous Endpoint Companion";
+				break;
+			default:
+				s = "UNKNOWN";
+				break;
+			} s; }), v & 0xff, l);
+}
+
+
+static inline void dwc3_decode_get_configuration(__u16 l, char *str)
+{
+	sprintf(str, "Get Configuration(Length = %d)", l);
+}
+
+static inline void dwc3_decode_set_configuration(__u8 v, char *str)
+{
+	sprintf(str, "Set Configuration(Config = %d)", v);
+}
+
+static inline void dwc3_decode_get_intf(__u16 i, __u16 l, char *str)
+{
+	sprintf(str, "Get Interface(Intf = %d, Length = %d)", i, l);
+}
+
+static inline void dwc3_decode_set_intf(__u8 v, __u16 i, char *str)
+{
+	sprintf(str, "Set Interface(Intf = %d, Alt.Setting = %d)", i, v);
+}
+
+static inline void dwc3_decode_synch_frame(__u16 i, __u16 l, char *str)
+{
+	sprintf(str, "Synch Frame(Endpoint = %d, Length = %d)", i, l);
+}
+
+static inline void dwc3_decode_set_sel(__u16 l, char *str)
+{
+	sprintf(str, "Set SEL(Length = %d)", l);
+}
+
+static inline void dwc3_decode_set_isoch_delay(__u8 v, char *str)
+{
+	sprintf(str, "Set Isochronous Delay(Delay = %d ns)", v);
+}
+
+/**
+ * dwc3_decode_ctrl - returns a string represetion of ctrl request
+ */
+static inline const char *dwc3_decode_ctrl(char *str, __u8 bRequestType,
+		__u8 bRequest, __u16 wValue, __u16 wIndex, __u16 wLength)
+{
+	switch (bRequest) {
+	case USB_REQ_GET_STATUS:
+		dwc3_decode_get_status(bRequestType, wIndex, wLength, str);
+		break;
+	case USB_REQ_CLEAR_FEATURE:
+	case USB_REQ_SET_FEATURE:
+		dwc3_decode_set_clear_feature(bRequestType, bRequest, wValue,
+					      wIndex, str);
+		break;
+	case USB_REQ_SET_ADDRESS:
+		dwc3_decode_set_address(wValue, str);
+		break;
+	case USB_REQ_GET_DESCRIPTOR:
+	case USB_REQ_SET_DESCRIPTOR:
+		dwc3_decode_get_set_descriptor(bRequestType, bRequest, wValue,
+					       wIndex, wLength, str);
+		break;
+	case USB_REQ_GET_CONFIGURATION:
+		dwc3_decode_get_configuration(wLength, str);
+		break;
+	case USB_REQ_SET_CONFIGURATION:
+		dwc3_decode_set_configuration(wValue, str);
+		break;
+	case USB_REQ_GET_INTERFACE:
+		dwc3_decode_get_intf(wIndex, wLength, str);
+		break;
+	case USB_REQ_SET_INTERFACE:
+		dwc3_decode_set_intf(wValue, wIndex, str);
+		break;
+	case USB_REQ_SYNCH_FRAME:
+		dwc3_decode_synch_frame(wIndex, wLength, str);
+		break;
+	case USB_REQ_SET_SEL:
+		dwc3_decode_set_sel(wLength, str);
+		break;
+	case USB_REQ_SET_ISOCH_DELAY:
+		dwc3_decode_set_isoch_delay(wValue, str);
+		break;
+	default:
+		sprintf(str, "%02x %02x %02x %02x %02x %02x %02x %02x",
+			bRequestType, bRequest,
+			cpu_to_le16(wValue) & 0xff,
+			cpu_to_le16(wValue) >> 8,
+			cpu_to_le16(wIndex) & 0xff,
+			cpu_to_le16(wIndex) >> 8,
+			cpu_to_le16(wLength) & 0xff,
+			cpu_to_le16(wLength) >> 8);
+	}
+
+	return str;
+}
+
+/**
+ * dwc3_ep_event_string - returns event name
+ * @event: then event code
+ */
+static inline const char *
+dwc3_ep_event_string(char *str, const struct dwc3_event_depevt *event,
+		     u32 ep0state)
+{
+	u8 epnum = event->endpoint_number;
+	size_t len;
+	int status;
+	int ret;
+
+	ret = sprintf(str, "ep%d%s: ", epnum >> 1,
+			(epnum & 1) ? "in" : "out");
+	if (ret < 0)
+		return "UNKNOWN";
+
+	status = event->status;
+
+	switch (event->endpoint_event) {
+	case DWC3_DEPEVT_XFERCOMPLETE:
+		len = strlen(str);
+		sprintf(str + len, "Transfer Complete (%c%c%c)",
+				status & DEPEVT_STATUS_SHORT ? 'S' : 's',
+				status & DEPEVT_STATUS_IOC ? 'I' : 'i',
+				status & DEPEVT_STATUS_LST ? 'L' : 'l');
+
+		len = strlen(str);
+
+		if (epnum <= 1)
+			sprintf(str + len, " [%s]", dwc3_ep0_state_string(ep0state));
+		break;
+	case DWC3_DEPEVT_XFERINPROGRESS:
+		len = strlen(str);
+
+		sprintf(str + len, "Transfer In Progress [%d] (%c%c%c)",
+				event->parameters,
+				status & DEPEVT_STATUS_SHORT ? 'S' : 's',
+				status & DEPEVT_STATUS_IOC ? 'I' : 'i',
+				status & DEPEVT_STATUS_LST ? 'M' : 'm');
+		break;
+	case DWC3_DEPEVT_XFERNOTREADY:
+		len = strlen(str);
+
+		sprintf(str + len, "Transfer Not Ready [%d]%s",
+				event->parameters,
+				status & DEPEVT_STATUS_TRANSFER_ACTIVE ?
+				" (Active)" : " (Not Active)");
+
+		/* Control Endpoints */
+		if (epnum <= 1) {
+			int phase = DEPEVT_STATUS_CONTROL_PHASE(event->status);
+
+			switch (phase) {
+			case DEPEVT_STATUS_CONTROL_DATA:
+				strcat(str, " [Data Phase]");
+				break;
+			case DEPEVT_STATUS_CONTROL_STATUS:
+				strcat(str, " [Status Phase]");
+			}
+		}
+		break;
+	case DWC3_DEPEVT_RXTXFIFOEVT:
+		strcat(str, "FIFO");
+		break;
+	case DWC3_DEPEVT_STREAMEVT:
+		status = event->status;
+
+		switch (status) {
+		case DEPEVT_STREAMEVT_FOUND:
+			sprintf(str + ret, " Stream %d Found",
+					event->parameters);
+			break;
+		case DEPEVT_STREAMEVT_NOTFOUND:
+		default:
+			strcat(str, " Stream Not Found");
+			break;
+		}
+
+		break;
+	case DWC3_DEPEVT_EPCMDCMPLT:
+		strcat(str, "Endpoint Command Complete");
+		break;
+	default:
+		sprintf(str, "UNKNOWN");
+	}
+
+	return str;
+}
+
+/**
+ * dwc3_gadget_event_type_string - return event name
+ * @event: the event code
+ */
+static inline const char *dwc3_gadget_event_type_string(u8 event)
+{
+	switch (event) {
+	case DWC3_DEVICE_EVENT_DISCONNECT:
+		return "Disconnect";
+	case DWC3_DEVICE_EVENT_RESET:
+		return "Reset";
+	case DWC3_DEVICE_EVENT_CONNECT_DONE:
+		return "Connect Done";
+	case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
+		return "Link Status Change";
+	case DWC3_DEVICE_EVENT_WAKEUP:
+		return "Wake-Up";
+	case DWC3_DEVICE_EVENT_HIBER_REQ:
+		return "Hibernation";
+	case DWC3_DEVICE_EVENT_EOPF:
+		return "End of Periodic Frame";
+	case DWC3_DEVICE_EVENT_SOF:
+		return "Start of Frame";
+	case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
+		return "Erratic Error";
+	case DWC3_DEVICE_EVENT_CMD_CMPL:
+		return "Command Complete";
+	case DWC3_DEVICE_EVENT_OVERFLOW:
+		return "Overflow";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+static inline const char *dwc3_decode_event(char *str, u32 event, u32 ep0state)
+{
+	const union dwc3_event evt = (union dwc3_event) event;
+
+	if (evt.type.is_devspec)
+		return dwc3_gadget_event_string(str, &evt.devt);
+	else
+		return dwc3_ep_event_string(str, &evt.depevt, ep0state);
+}
+
+static inline const char *dwc3_ep_cmd_status_string(int status)
+{
+	switch (status) {
+	case -ETIMEDOUT:
+		return "Timed Out";
+	case 0:
+		return "Successful";
+	case DEPEVT_TRANSFER_NO_RESOURCE:
+		return "No Resource";
+	case DEPEVT_TRANSFER_BUS_EXPIRY:
+		return "Bus Expiry";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+static inline const char *dwc3_gadget_generic_cmd_status_string(int status)
+{
+	switch (status) {
+	case -ETIMEDOUT:
+		return "Timed Out";
+	case 0:
+		return "Successful";
+	case 1:
+		return "Error";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+
+#ifdef CONFIG_DEBUG_FS
+extern void dwc3_debugfs_init(struct dwc3 *);
+extern void dwc3_debugfs_exit(struct dwc3 *);
+#else
+static inline void dwc3_debugfs_init(struct dwc3 *d)
+{  }
+static inline void dwc3_debugfs_exit(struct dwc3 *d)
+{  }
+#endif
+#endif /* __DWC3_DEBUG_H */
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
new file mode 100644
index 000000000..0f2341cdd
--- /dev/null
+++ b/drivers/usb/dwc3/host.c
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * host.c - DesignWare USB3 DRD Controller Host Glue
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <init.h>
+
+#include "core.h"
+
+int dwc3_host_init(struct dwc3 *dwc)
+{
+	struct resource *io;
+	struct device_d *dev = dwc->dev;
+
+	io = dev_get_resource(dev, IORESOURCE_MEM, 0);
+	if (IS_ERR(io)) {
+		dev_err(dev, "Failed to get IORESOURCE_MEM\n");
+		return PTR_ERR(io);
+	}
+
+	dwc->xhci = add_generic_device("xHCI", DEVICE_ID_DYNAMIC, NULL,
+				       io->start, resource_size(io),
+				       IORESOURCE_MEM, NULL);
+	if (!dwc->xhci) {
+		dev_err(dev, "Failed to register xHCI deivce\n");
+		return -ENODEV;
+	}
+	
+	return 0;
+}
diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h
new file mode 100644
index 000000000..f87b173e9
--- /dev/null
+++ b/drivers/usb/dwc3/io.h
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * io.h - DesignWare USB3 DRD IO Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ */
+
+#ifndef __DRIVERS_USB_DWC3_IO_H
+#define __DRIVERS_USB_DWC3_IO_H
+
+#include <io.h>
+#include "core.h"
+
+static inline u32 dwc3_readl(void __iomem *base, u32 offset)
+{
+	u32 value;
+
+	/*
+	 * We requested the mem region starting from the Globals address
+	 * space, see dwc3_probe in core.c.
+	 * However, the offsets are given starting from xHCI address space.
+	 */
+	value = readl(base + offset - DWC3_GLOBALS_REGS_START);
+
+	return value;
+}
+
+static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
+{
+	/*
+	 * We requested the mem region starting from the Globals address
+	 * space, see dwc3_probe in core.c.
+	 * However, the offsets are given starting from xHCI address space.
+	 */
+	writel(value, base + offset - DWC3_GLOBALS_REGS_START);
+}
+
+#endif /* __DRIVERS_USB_DWC3_IO_H */
-- 
2.20.1


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

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

* [PATCH 23/25] lib: Port basic Linux kernel NLS functions
  2019-02-20  7:29 [PATCH 00/25] i.MX8MQ USB support Andrey Smirnov
                   ` (21 preceding siblings ...)
  2019-02-20  7:29 ` [PATCH 22/25] usb: Import DWC3 USB controller driver " Andrey Smirnov
@ 2019-02-20  7:29 ` Andrey Smirnov
  2019-02-20  7:29 ` [PATCH 24/25] usb: Port Microchip USB251x USB hub driver from Linux Andrey Smirnov
                   ` (2 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Andrey Smirnov @ 2019-02-20  7:29 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Port basic Linux kernel NLS functions: utf8_to_utf32() and
utf8s_to_utf16s() in order to support porting kernel code that uses
them.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 include/linux/nls.h |  40 ++++++++++++++
 lib/Kconfig         |   3 +
 lib/Makefile        |   1 +
 lib/nls_base.c      | 131 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 175 insertions(+)
 create mode 100644 include/linux/nls.h
 create mode 100644 lib/nls_base.c

diff --git a/include/linux/nls.h b/include/linux/nls.h
new file mode 100644
index 000000000..62fb7b5a9
--- /dev/null
+++ b/include/linux/nls.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_NLS_H
+#define _LINUX_NLS_H
+
+/* Unicode has changed over the years.  Unicode code points no longer
+ * fit into 16 bits; as of Unicode 5 valid code points range from 0
+ * to 0x10ffff (17 planes, where each plane holds 65536 code points).
+ *
+ * The original decision to represent Unicode characters as 16-bit
+ * wchar_t values is now outdated.  But plane 0 still includes the
+ * most commonly used characters, so we will retain it.  The newer
+ * 32-bit unicode_t type can be used when it is necessary to
+ * represent the full Unicode character set.
+ */
+
+/* Plane-0 Unicode character */
+typedef u16 wchar_t;
+#define MAX_WCHAR_T	0xffff
+
+/* Arbitrary Unicode character */
+typedef u32 unicode_t;
+
+/* this value hold the maximum octet of charset */
+#define NLS_MAX_CHARSET_SIZE 6 /* for UTF-8 */
+
+/* Byte order for UTF-16 strings */
+enum utf16_endian {
+	UTF16_HOST_ENDIAN,
+	UTF16_LITTLE_ENDIAN,
+	UTF16_BIG_ENDIAN
+};
+
+/* nls_base.c */
+
+extern int utf8_to_utf32(const u8 *s, int len, unicode_t *pu);
+extern int utf8s_to_utf16s(const u8 *s, int len,
+		enum utf16_endian endian, wchar_t *pwcs, int maxlen);
+
+#endif /* _LINUX_NLS_H */
+
diff --git a/lib/Kconfig b/lib/Kconfig
index e048aded8..44f30d824 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -148,4 +148,7 @@ config GENERIC_LIB_LSHRDI3
 config GENERIC_LIB_MULDI3
 	bool
 
+config NLS
+        bool "Native language support"
+
 endmenu
diff --git a/lib/Makefile b/lib/Makefile
index e72aa6655..763516d41 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -67,6 +67,7 @@ obj-y			+= parseopt.o
 obj-y			+= clz_ctz.o
 obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o
 obj-$(CONFIG_CRC8)	+= crc8.o
+obj-$(CONFIG_NLS)	+= nls_base.o
 
 # GCC library routines
 obj-$(CONFIG_GENERIC_LIB_ASHLDI3) += ashldi3.o
diff --git a/lib/nls_base.c b/lib/nls_base.c
new file mode 100644
index 000000000..cd6a5ff12
--- /dev/null
+++ b/lib/nls_base.c
@@ -0,0 +1,131 @@
+/*
+ * linux/fs/nls/nls_base.c
+ *
+ * Native language support--charsets and unicode translations.
+ * By Gordon Chaffee 1996, 1997
+ *
+ * Unicode based case conversion 1999 by Wolfram Pienkoss
+ *
+ */
+#include <common.h>
+#include <linux/nls.h>
+
+/*
+ * Sample implementation from Unicode home page.
+ * http://www.stonehand.com/unicode/standard/fss-utf.html
+ */
+struct utf8_table {
+	int     cmask;
+	int     cval;
+	int     shift;
+	long    lmask;
+	long    lval;
+};
+
+static const struct utf8_table utf8_table[] =
+{
+    {0x80,  0x00,   0*6,    0x7F,           0,         /* 1 byte sequence */},
+    {0xE0,  0xC0,   1*6,    0x7FF,          0x80,      /* 2 byte sequence */},
+    {0xF0,  0xE0,   2*6,    0xFFFF,         0x800,     /* 3 byte sequence */},
+    {0xF8,  0xF0,   3*6,    0x1FFFFF,       0x10000,   /* 4 byte sequence */},
+    {0xFC,  0xF8,   4*6,    0x3FFFFFF,      0x200000,  /* 5 byte sequence */},
+    {0xFE,  0xFC,   5*6,    0x7FFFFFFF,     0x4000000, /* 6 byte sequence */},
+    {0,						       /* end of table    */}
+};
+
+#define UNICODE_MAX	0x0010ffff
+#define PLANE_SIZE	0x00010000
+
+#define SURROGATE_MASK	0xfffff800
+#define SURROGATE_PAIR	0x0000d800
+#define SURROGATE_LOW	0x00000400
+#define SURROGATE_BITS	0x000003ff
+
+int utf8_to_utf32(const u8 *s, int inlen, unicode_t *pu)
+{
+	unsigned long l;
+	int c0, c, nc;
+	const struct utf8_table *t;
+
+	nc = 0;
+	c0 = *s;
+	l = c0;
+	for (t = utf8_table; t->cmask; t++) {
+		nc++;
+		if ((c0 & t->cmask) == t->cval) {
+			l &= t->lmask;
+			if (l < t->lval || l > UNICODE_MAX ||
+					(l & SURROGATE_MASK) == SURROGATE_PAIR)
+				return -1;
+			*pu = (unicode_t) l;
+			return nc;
+		}
+		if (inlen <= nc)
+			return -1;
+		s++;
+		c = (*s ^ 0x80) & 0xFF;
+		if (c & 0xC0)
+			return -1;
+		l = (l << 6) | c;
+	}
+	return -1;
+}
+EXPORT_SYMBOL(utf8_to_utf32);
+
+static inline void put_utf16(wchar_t *s, unsigned c, enum utf16_endian endian)
+{
+	switch (endian) {
+	default:
+		*s = (wchar_t) c;
+		break;
+	case UTF16_LITTLE_ENDIAN:
+		*s = __cpu_to_le16(c);
+		break;
+	case UTF16_BIG_ENDIAN:
+		*s = __cpu_to_be16(c);
+		break;
+	}
+}
+
+int utf8s_to_utf16s(const u8 *s, int inlen, enum utf16_endian endian,
+		wchar_t *pwcs, int maxout)
+{
+	u16 *op;
+	int size;
+	unicode_t u;
+
+	op = pwcs;
+	while (inlen > 0 && maxout > 0 && *s) {
+		if (*s & 0x80) {
+			size = utf8_to_utf32(s, inlen, &u);
+			if (size < 0)
+				return -EINVAL;
+			s += size;
+			inlen -= size;
+
+			if (u >= PLANE_SIZE) {
+				if (maxout < 2)
+					break;
+				u -= PLANE_SIZE;
+				put_utf16(op++, SURROGATE_PAIR |
+						((u >> 10) & SURROGATE_BITS),
+						endian);
+				put_utf16(op++, SURROGATE_PAIR |
+						SURROGATE_LOW |
+						(u & SURROGATE_BITS),
+						endian);
+				maxout -= 2;
+			} else {
+				put_utf16(op++, u, endian);
+				maxout--;
+			}
+		} else {
+			put_utf16(op++, *s++, endian);
+			inlen--;
+			maxout--;
+		}
+	}
+	return op - pwcs;
+}
+EXPORT_SYMBOL(utf8s_to_utf16s);
+
-- 
2.20.1


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

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

* [PATCH 24/25] usb: Port Microchip USB251x USB hub driver from Linux
  2019-02-20  7:29 [PATCH 00/25] i.MX8MQ USB support Andrey Smirnov
                   ` (22 preceding siblings ...)
  2019-02-20  7:29 ` [PATCH 23/25] lib: Port basic Linux kernel NLS functions Andrey Smirnov
@ 2019-02-20  7:29 ` Andrey Smirnov
  2019-02-20  7:29 ` [PATCH 25/25] usb: usb251xb: add usb data lane port swap feature Andrey Smirnov
  2019-02-22  7:27 ` [PATCH 00/25] i.MX8MQ USB support Sascha Hauer
  25 siblings, 0 replies; 30+ messages in thread
From: Andrey Smirnov @ 2019-02-20  7:29 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Port Microchip USB251x USB hub driver from Linux. Needed by ZII's
i.MX8MQ boards.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/Kconfig         |   2 +
 drivers/usb/Makefile        |   1 +
 drivers/usb/misc/Kconfig    |  14 +
 drivers/usb/misc/Makefile   |   6 +
 drivers/usb/misc/usb251xb.c | 672 ++++++++++++++++++++++++++++++++++++
 5 files changed, 695 insertions(+)
 create mode 100644 drivers/usb/misc/Kconfig
 create mode 100644 drivers/usb/misc/Makefile
 create mode 100644 drivers/usb/misc/usb251xb.c

diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index ee33e0f28..8ff3d18d4 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -17,6 +17,8 @@ source drivers/usb/otg/Kconfig
 
 source drivers/usb/storage/Kconfig
 
+source "drivers/usb/misc/Kconfig"
+
 endif
 
 source drivers/usb/gadget/Kconfig
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 13fca2cbd..9e9809950 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -6,4 +6,5 @@ obj-$(CONFIG_USB_GADGET)	+= gadget/
 obj-$(CONFIG_USB_STORAGE)	+= storage/
 obj-y += host/
 obj-y += otg/
+obj-$(CONFIG_USB)		+= misc/
 
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
new file mode 100644
index 000000000..7d6c9da59
--- /dev/null
+++ b/drivers/usb/misc/Kconfig
@@ -0,0 +1,14 @@
+#
+# USB Miscellaneous driver configuration
+#
+comment "USB Miscellaneous drivers"
+
+config USB_HUB_USB251XB
+	bool "USB251XB Hub Controller Configuration Driver"
+	depends on I2C
+	select NLS
+	help
+	  This option enables support for configuration via SMBus of the
+	  Microchip USB251x/xBi USB 2.0 Hub Controller series. Configuration
+	  parameters may be set in devicetree or platform data.
+	  Say Y or M here if you need to configure such a device via SMBus.
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
new file mode 100644
index 000000000..fb69c454b
--- /dev/null
+++ b/drivers/usb/misc/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the rest of the USB drivers
+# (the ones that don't fit into any other categories)
+#
+obj-$(CONFIG_USB_HUB_USB251XB)		+= usb251xb.o
diff --git a/drivers/usb/misc/usb251xb.c b/drivers/usb/misc/usb251xb.c
new file mode 100644
index 000000000..0b721f6d4
--- /dev/null
+++ b/drivers/usb/misc/usb251xb.c
@@ -0,0 +1,672 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for Microchip USB251xB USB 2.0 Hi-Speed Hub Controller
+ * Configuration via SMBus.
+ *
+ * Copyright (c) 2017 SKIDATA AG
+ *
+ * This work is based on the USB3503 driver by Dongjin Kim and
+ * a not-accepted patch by Fabien Lahoudere, see:
+ * https://patchwork.kernel.org/patch/9257715/
+ */
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <i2c/i2c.h>
+#include <of.h>
+#include <gpio.h>
+#include <of_gpio.h>
+#include <of_device.h>
+
+#include <linux/nls.h>
+
+/* Internal Register Set Addresses & Default Values acc. to DS00001692C */
+#define USB251XB_ADDR_VENDOR_ID_LSB	0x00
+#define USB251XB_ADDR_VENDOR_ID_MSB	0x01
+#define USB251XB_DEF_VENDOR_ID		0x0424
+
+#define USB251XB_ADDR_PRODUCT_ID_LSB	0x02
+#define USB251XB_ADDR_PRODUCT_ID_MSB	0x03
+#define USB251XB_DEF_PRODUCT_ID_12	0x2512 /* USB2512B/12Bi */
+#define USB251XB_DEF_PRODUCT_ID_13	0x2513 /* USB2513B/13Bi */
+#define USB251XB_DEF_PRODUCT_ID_14	0x2514 /* USB2514B/14Bi */
+#define USB251XB_DEF_PRODUCT_ID_17	0x2517 /* USB2517/17i */
+
+#define USB251XB_ADDR_DEVICE_ID_LSB	0x04
+#define USB251XB_ADDR_DEVICE_ID_MSB	0x05
+#define USB251XB_DEF_DEVICE_ID		0x0BB3
+
+#define USB251XB_ADDR_CONFIG_DATA_1	0x06
+#define USB251XB_DEF_CONFIG_DATA_1	0x9B
+#define USB251XB_ADDR_CONFIG_DATA_2	0x07
+#define USB251XB_DEF_CONFIG_DATA_2	0x20
+#define USB251XB_ADDR_CONFIG_DATA_3	0x08
+#define USB251XB_DEF_CONFIG_DATA_3	0x02
+
+#define USB251XB_ADDR_NON_REMOVABLE_DEVICES	0x09
+#define USB251XB_DEF_NON_REMOVABLE_DEVICES	0x00
+
+#define USB251XB_ADDR_PORT_DISABLE_SELF	0x0A
+#define USB251XB_DEF_PORT_DISABLE_SELF	0x00
+#define USB251XB_ADDR_PORT_DISABLE_BUS	0x0B
+#define USB251XB_DEF_PORT_DISABLE_BUS	0x00
+
+#define USB251XB_ADDR_MAX_POWER_SELF	0x0C
+#define USB251XB_DEF_MAX_POWER_SELF	0x01
+#define USB251XB_ADDR_MAX_POWER_BUS	0x0D
+#define USB251XB_DEF_MAX_POWER_BUS	0x32
+
+#define USB251XB_ADDR_MAX_CURRENT_SELF	0x0E
+#define USB251XB_DEF_MAX_CURRENT_SELF	0x01
+#define USB251XB_ADDR_MAX_CURRENT_BUS	0x0F
+#define USB251XB_DEF_MAX_CURRENT_BUS	0x32
+
+#define USB251XB_ADDR_POWER_ON_TIME	0x10
+#define USB251XB_DEF_POWER_ON_TIME	0x32
+
+#define USB251XB_ADDR_LANGUAGE_ID_HIGH	0x11
+#define USB251XB_ADDR_LANGUAGE_ID_LOW	0x12
+#define USB251XB_DEF_LANGUAGE_ID	0x0000
+
+#define USB251XB_STRING_BUFSIZE			62
+#define USB251XB_ADDR_MANUFACTURER_STRING_LEN	0x13
+#define USB251XB_ADDR_MANUFACTURER_STRING	0x16
+#define USB251XB_DEF_MANUFACTURER_STRING	"Microchip"
+
+#define USB251XB_ADDR_PRODUCT_STRING_LEN	0x14
+#define USB251XB_ADDR_PRODUCT_STRING		0x54
+#define USB251XB_DEF_PRODUCT_STRING		"USB251xB/xBi/7i"
+
+#define USB251XB_ADDR_SERIAL_STRING_LEN		0x15
+#define USB251XB_ADDR_SERIAL_STRING		0x92
+#define USB251XB_DEF_SERIAL_STRING		""
+
+#define USB251XB_ADDR_BATTERY_CHARGING_ENABLE	0xD0
+#define USB251XB_DEF_BATTERY_CHARGING_ENABLE	0x00
+
+#define USB251XB_ADDR_BOOST_UP	0xF6
+#define USB251XB_DEF_BOOST_UP	0x00
+#define USB251XB_ADDR_BOOST_57	0xF7
+#define USB251XB_DEF_BOOST_57	0x00
+#define USB251XB_ADDR_BOOST_14	0xF8
+#define USB251XB_DEF_BOOST_14	0x00
+
+#define USB251XB_ADDR_PORT_SWAP	0xFA
+#define USB251XB_DEF_PORT_SWAP	0x00
+
+#define USB251XB_ADDR_PORT_MAP_12	0xFB
+#define USB251XB_DEF_PORT_MAP_12	0x00
+#define USB251XB_ADDR_PORT_MAP_34	0xFC
+#define USB251XB_DEF_PORT_MAP_34	0x00 /* USB251{3B/i,4B/i,7/i} only */
+#define USB251XB_ADDR_PORT_MAP_56	0xFD
+#define USB251XB_DEF_PORT_MAP_56	0x00 /* USB2517/i only */
+#define USB251XB_ADDR_PORT_MAP_7	0xFE
+#define USB251XB_DEF_PORT_MAP_7		0x00 /* USB2517/i only */
+
+#define USB251XB_ADDR_STATUS_COMMAND		0xFF
+#define USB251XB_STATUS_COMMAND_SMBUS_DOWN	0x04
+#define USB251XB_STATUS_COMMAND_RESET		0x02
+#define USB251XB_STATUS_COMMAND_ATTACH		0x01
+
+#define USB251XB_I2C_REG_SZ	0x100
+#define USB251XB_I2C_WRITE_SZ	0x10
+
+#define DRIVER_NAME	"usb251xb"
+#define DRIVER_DESC	"Microchip USB 2.0 Hi-Speed Hub Controller"
+
+struct usb251xb {
+	struct device_d *dev;
+	struct i2c_client *i2c;
+	u8 skip_config;
+	int gpio_reset;
+	u16 vendor_id;
+	u16 product_id;
+	u16 device_id;
+	u8  conf_data1;
+	u8  conf_data2;
+	u8  conf_data3;
+	u8  non_rem_dev;
+	u8  port_disable_sp;
+	u8  port_disable_bp;
+	u8  max_power_sp;
+	u8  max_power_bp;
+	u8  max_current_sp;
+	u8  max_current_bp;
+	u8  power_on_time;
+	u16 lang_id;
+	u8 manufacturer_len;
+	u8 product_len;
+	u8 serial_len;
+	char manufacturer[USB251XB_STRING_BUFSIZE];
+	char product[USB251XB_STRING_BUFSIZE];
+	char serial[USB251XB_STRING_BUFSIZE];
+	u8  bat_charge_en;
+	u8  boost_up;
+	u8  boost_57;
+	u8  boost_14;
+	u8  port_swap;
+	u8  port_map12;
+	u8  port_map34;
+	u8  port_map56;
+	u8  port_map7;
+	u8  status;
+};
+
+struct usb251xb_data {
+	u16 product_id;
+	u8 port_cnt;
+	bool led_support;
+	bool bat_support;
+	char product_str[USB251XB_STRING_BUFSIZE / 2]; /* ASCII string */
+};
+
+static const struct usb251xb_data usb2512b_data = {
+	.product_id = 0x2512,
+	.port_cnt = 2,
+	.led_support = false,
+	.bat_support = true,
+	.product_str = "USB2512B",
+};
+
+static const struct usb251xb_data usb2512bi_data = {
+	.product_id = 0x2512,
+	.port_cnt = 2,
+	.led_support = false,
+	.bat_support = true,
+	.product_str = "USB2512Bi",
+};
+
+static const struct usb251xb_data usb2513b_data = {
+	.product_id = 0x2513,
+	.port_cnt = 3,
+	.led_support = false,
+	.bat_support = true,
+	.product_str = "USB2513B",
+};
+
+static const struct usb251xb_data usb2513bi_data = {
+	.product_id = 0x2513,
+	.port_cnt = 3,
+	.led_support = false,
+	.bat_support = true,
+	.product_str = "USB2513Bi",
+};
+
+static const struct usb251xb_data usb2514b_data = {
+	.product_id = 0x2514,
+	.port_cnt = 4,
+	.led_support = false,
+	.bat_support = true,
+	.product_str = "USB2514B",
+};
+
+static const struct usb251xb_data usb2514bi_data = {
+	.product_id = 0x2514,
+	.port_cnt = 4,
+	.led_support = false,
+	.bat_support = true,
+	.product_str = "USB2514Bi",
+};
+
+static const struct usb251xb_data usb2517_data = {
+	.product_id = 0x2517,
+	.port_cnt = 7,
+	.led_support = true,
+	.bat_support = false,
+	.product_str = "USB2517",
+};
+
+static const struct usb251xb_data usb2517i_data = {
+	.product_id = 0x2517,
+	.port_cnt = 7,
+	.led_support = true,
+	.bat_support = false,
+	.product_str = "USB2517i",
+};
+
+static void usb251xb_reset(struct usb251xb *hub, int state)
+{
+	if (!gpio_is_valid(hub->gpio_reset))
+		return;
+
+	gpio_set_active(hub->gpio_reset, state);
+
+	/* wait for hub recovery/stabilization */
+	if (!state)
+		udelay(750);	/* >=500us at power on */
+	else
+		udelay(10);	/* >=1us at power down */
+}
+
+static int usb251xb_connect(struct usb251xb *hub)
+{
+	struct device_d *dev = hub->dev;
+	int err, i;
+	char i2c_wb[USB251XB_I2C_REG_SZ];
+
+	memset(i2c_wb, 0, USB251XB_I2C_REG_SZ);
+
+	if (hub->skip_config) {
+		dev_info(dev, "Skip hub configuration, only attach.\n");
+		i2c_wb[0] = 0x01;
+		i2c_wb[1] = USB251XB_STATUS_COMMAND_ATTACH;
+
+		usb251xb_reset(hub, 0);
+
+		err = i2c_smbus_write_i2c_block_data(hub->i2c,
+				USB251XB_ADDR_STATUS_COMMAND, 2, i2c_wb);
+		if (err) {
+			dev_err(dev, "attaching hub failed: %d\n", err);
+			return err;
+		}
+		return 0;
+	}
+
+	i2c_wb[USB251XB_ADDR_VENDOR_ID_MSB]     = (hub->vendor_id >> 8) & 0xFF;
+	i2c_wb[USB251XB_ADDR_VENDOR_ID_LSB]     = hub->vendor_id & 0xFF;
+	i2c_wb[USB251XB_ADDR_PRODUCT_ID_MSB]    = (hub->product_id >> 8) & 0xFF;
+	i2c_wb[USB251XB_ADDR_PRODUCT_ID_LSB]    = hub->product_id & 0xFF;
+	i2c_wb[USB251XB_ADDR_DEVICE_ID_MSB]     = (hub->device_id >> 8) & 0xFF;
+	i2c_wb[USB251XB_ADDR_DEVICE_ID_LSB]     = hub->device_id & 0xFF;
+	i2c_wb[USB251XB_ADDR_CONFIG_DATA_1]     = hub->conf_data1;
+	i2c_wb[USB251XB_ADDR_CONFIG_DATA_2]     = hub->conf_data2;
+	i2c_wb[USB251XB_ADDR_CONFIG_DATA_3]     = hub->conf_data3;
+	i2c_wb[USB251XB_ADDR_NON_REMOVABLE_DEVICES] = hub->non_rem_dev;
+	i2c_wb[USB251XB_ADDR_PORT_DISABLE_SELF] = hub->port_disable_sp;
+	i2c_wb[USB251XB_ADDR_PORT_DISABLE_BUS]  = hub->port_disable_bp;
+	i2c_wb[USB251XB_ADDR_MAX_POWER_SELF]    = hub->max_power_sp;
+	i2c_wb[USB251XB_ADDR_MAX_POWER_BUS]     = hub->max_power_bp;
+	i2c_wb[USB251XB_ADDR_MAX_CURRENT_SELF]  = hub->max_current_sp;
+	i2c_wb[USB251XB_ADDR_MAX_CURRENT_BUS]   = hub->max_current_bp;
+	i2c_wb[USB251XB_ADDR_POWER_ON_TIME]     = hub->power_on_time;
+	i2c_wb[USB251XB_ADDR_LANGUAGE_ID_HIGH]  = (hub->lang_id >> 8) & 0xFF;
+	i2c_wb[USB251XB_ADDR_LANGUAGE_ID_LOW]   = hub->lang_id & 0xFF;
+	i2c_wb[USB251XB_ADDR_MANUFACTURER_STRING_LEN] = hub->manufacturer_len;
+	i2c_wb[USB251XB_ADDR_PRODUCT_STRING_LEN]      = hub->product_len;
+	i2c_wb[USB251XB_ADDR_SERIAL_STRING_LEN]       = hub->serial_len;
+	memcpy(&i2c_wb[USB251XB_ADDR_MANUFACTURER_STRING], hub->manufacturer,
+	       USB251XB_STRING_BUFSIZE);
+	memcpy(&i2c_wb[USB251XB_ADDR_SERIAL_STRING], hub->serial,
+	       USB251XB_STRING_BUFSIZE);
+	memcpy(&i2c_wb[USB251XB_ADDR_PRODUCT_STRING], hub->product,
+	       USB251XB_STRING_BUFSIZE);
+	i2c_wb[USB251XB_ADDR_BATTERY_CHARGING_ENABLE] = hub->bat_charge_en;
+	i2c_wb[USB251XB_ADDR_BOOST_UP]          = hub->boost_up;
+	i2c_wb[USB251XB_ADDR_BOOST_57]          = hub->boost_57;
+	i2c_wb[USB251XB_ADDR_BOOST_14]          = hub->boost_14;
+	i2c_wb[USB251XB_ADDR_PORT_SWAP]         = hub->port_swap;
+	i2c_wb[USB251XB_ADDR_PORT_MAP_12]       = hub->port_map12;
+	i2c_wb[USB251XB_ADDR_PORT_MAP_34]       = hub->port_map34;
+	i2c_wb[USB251XB_ADDR_PORT_MAP_56]       = hub->port_map56;
+	i2c_wb[USB251XB_ADDR_PORT_MAP_7]        = hub->port_map7;
+	i2c_wb[USB251XB_ADDR_STATUS_COMMAND] = USB251XB_STATUS_COMMAND_ATTACH;
+
+	usb251xb_reset(hub, 0);
+
+	/* write registers */
+	for (i = 0; i < (USB251XB_I2C_REG_SZ / USB251XB_I2C_WRITE_SZ); i++) {
+		int offset = i * USB251XB_I2C_WRITE_SZ;
+		char wbuf[USB251XB_I2C_WRITE_SZ + 1];
+
+		/* The first data byte transferred tells the hub how many data
+		 * bytes will follow (byte count).
+		 */
+		wbuf[0] = USB251XB_I2C_WRITE_SZ;
+		memcpy(&wbuf[1], &i2c_wb[offset], USB251XB_I2C_WRITE_SZ);
+
+		dev_dbg(dev, "writing %d byte block %d to 0x%02X\n",
+			USB251XB_I2C_WRITE_SZ, i, offset);
+
+		err = i2c_smbus_write_i2c_block_data(hub->i2c, offset,
+						     USB251XB_I2C_WRITE_SZ + 1,
+						     wbuf);
+		if (err)
+			goto out_err;
+	}
+
+	dev_info(dev, "Hub configuration was successful.\n");
+	return 0;
+
+out_err:
+	dev_err(dev, "configuring block %d failed: %d\n", i, err);
+	return err;
+}
+
+#ifdef CONFIG_OFDEVICE
+static int usb251xb_get_ofdata(struct usb251xb *hub,
+			       struct usb251xb_data *data)
+{
+	struct device_d *dev = hub->dev;
+	struct device_node *np = dev->device_node;
+	int len, err, i;
+	u32 property_u32 = 0;
+	const u32 *cproperty_u32;
+	const char *cproperty_char;
+	enum of_gpio_flags of_flags;
+	unsigned long flags = GPIOF_OUT_INIT_ACTIVE;
+	char str[USB251XB_STRING_BUFSIZE / 2];
+
+	if (!np) {
+		dev_err(dev, "failed to get ofdata\n");
+		return -ENODEV;
+	}
+
+	if (of_get_property(np, "skip-config", NULL))
+		hub->skip_config = 1;
+	else
+		hub->skip_config = 0;
+
+	hub->gpio_reset = of_get_named_gpio_flags(np, "reset-gpios", 0,
+						  &of_flags);
+	if (gpio_is_valid(hub->gpio_reset)) {
+		char *name;
+		int ret;
+
+		if (of_flags & OF_GPIO_ACTIVE_LOW)
+			flags |= GPIOF_ACTIVE_LOW;
+
+		name = basprintf("%s reset", dev_name(dev));
+		ret  = gpio_request_one(hub->gpio_reset, flags, name);
+		if (ret < 0)
+			return ret;
+	} else if (hub->gpio_reset == -EPROBE_DEFER) {
+		return -EPROBE_DEFER;
+	} else {
+		err = hub->gpio_reset;
+		dev_err(dev, "unable to request GPIO reset pin (%d)\n", err);
+		return err;
+	}
+
+	if (of_property_read_u16_array(np, "vendor-id", &hub->vendor_id, 1))
+		hub->vendor_id = USB251XB_DEF_VENDOR_ID;
+
+	if (of_property_read_u16_array(np, "product-id",
+				       &hub->product_id, 1))
+		hub->product_id = data->product_id;
+
+	if (of_property_read_u16_array(np, "device-id", &hub->device_id, 1))
+		hub->device_id = USB251XB_DEF_DEVICE_ID;
+
+	hub->conf_data1 = USB251XB_DEF_CONFIG_DATA_1;
+	if (of_get_property(np, "self-powered", NULL)) {
+		hub->conf_data1 |= BIT(7);
+
+		/* Configure Over-Current sens when self-powered */
+		hub->conf_data1 &= ~BIT(2);
+		if (of_get_property(np, "ganged-sensing", NULL))
+			hub->conf_data1 &= ~BIT(1);
+		else if (of_get_property(np, "individual-sensing", NULL))
+			hub->conf_data1 |= BIT(1);
+	} else if (of_get_property(np, "bus-powered", NULL)) {
+		hub->conf_data1 &= ~BIT(7);
+
+		/* Disable Over-Current sense when bus-powered */
+		hub->conf_data1 |= BIT(2);
+	}
+
+	if (of_get_property(np, "disable-hi-speed", NULL))
+		hub->conf_data1 |= BIT(5);
+
+	if (of_get_property(np, "multi-tt", NULL))
+		hub->conf_data1 |= BIT(4);
+	else if (of_get_property(np, "single-tt", NULL))
+		hub->conf_data1 &= ~BIT(4);
+
+	if (of_get_property(np, "disable-eop", NULL))
+		hub->conf_data1 |= BIT(3);
+
+	if (of_get_property(np, "individual-port-switching", NULL))
+		hub->conf_data1 |= BIT(0);
+	else if (of_get_property(np, "ganged-port-switching", NULL))
+		hub->conf_data1 &= ~BIT(0);
+
+	hub->conf_data2 = USB251XB_DEF_CONFIG_DATA_2;
+	if (of_get_property(np, "dynamic-power-switching", NULL))
+		hub->conf_data2 |= BIT(7);
+
+	if (!of_property_read_u32(np, "oc-delay-us", &property_u32)) {
+		if (property_u32 == 100) {
+			/* 100 us*/
+			hub->conf_data2 &= ~BIT(5);
+			hub->conf_data2 &= ~BIT(4);
+		} else if (property_u32 == 4000) {
+			/* 4 ms */
+			hub->conf_data2 &= ~BIT(5);
+			hub->conf_data2 |= BIT(4);
+		} else if (property_u32 == 16000) {
+			/* 16 ms */
+			hub->conf_data2 |= BIT(5);
+			hub->conf_data2 |= BIT(4);
+		} else {
+			/* 8 ms (DEFAULT) */
+			hub->conf_data2 |= BIT(5);
+			hub->conf_data2 &= ~BIT(4);
+		}
+	}
+
+	if (of_get_property(np, "compound-device", NULL))
+		hub->conf_data2 |= BIT(3);
+
+	hub->conf_data3 = USB251XB_DEF_CONFIG_DATA_3;
+	if (of_get_property(np, "port-mapping-mode", NULL))
+		hub->conf_data3 |= BIT(3);
+
+	if (data->led_support && of_get_property(np, "led-usb-mode", NULL))
+		hub->conf_data3 &= ~BIT(1);
+
+	if (of_get_property(np, "string-support", NULL))
+		hub->conf_data3 |= BIT(0);
+
+	hub->non_rem_dev = USB251XB_DEF_NON_REMOVABLE_DEVICES;
+	cproperty_u32 = of_get_property(np, "non-removable-ports", &len);
+	if (cproperty_u32 && (len / sizeof(u32)) > 0) {
+		for (i = 0; i < len / sizeof(u32); i++) {
+			u32 port = be32_to_cpu(cproperty_u32[i]);
+
+			if ((port >= 1) && (port <= data->port_cnt))
+				hub->non_rem_dev |= BIT(port);
+			else
+				dev_warn(dev, "NRD port %u doesn't exist\n",
+					port);
+		}
+	}
+
+	hub->port_disable_sp = USB251XB_DEF_PORT_DISABLE_SELF;
+	cproperty_u32 = of_get_property(np, "sp-disabled-ports", &len);
+	if (cproperty_u32 && (len / sizeof(u32)) > 0) {
+		for (i = 0; i < len / sizeof(u32); i++) {
+			u32 port = be32_to_cpu(cproperty_u32[i]);
+
+			if ((port >= 1) && (port <= data->port_cnt))
+				hub->port_disable_sp |= BIT(port);
+			else
+				dev_warn(dev, "PDS port %u doesn't exist\n",
+					port);
+		}
+	}
+
+	hub->port_disable_bp = USB251XB_DEF_PORT_DISABLE_BUS;
+	cproperty_u32 = of_get_property(np, "bp-disabled-ports", &len);
+	if (cproperty_u32 && (len / sizeof(u32)) > 0) {
+		for (i = 0; i < len / sizeof(u32); i++) {
+			u32 port = be32_to_cpu(cproperty_u32[i]);
+
+			if ((port >= 1) && (port <= data->port_cnt))
+				hub->port_disable_bp |= BIT(port);
+			else
+				dev_warn(dev, "PDB port %u doesn't exist\n",
+					port);
+		}
+	}
+
+	hub->max_power_sp = USB251XB_DEF_MAX_POWER_SELF;
+	if (!of_property_read_u32(np, "sp-max-total-current-microamp",
+	    &property_u32))
+		hub->max_power_sp = min_t(u8, property_u32 / 2000, 50);
+
+	hub->max_power_bp = USB251XB_DEF_MAX_POWER_BUS;
+	if (!of_property_read_u32(np, "bp-max-total-current-microamp",
+	    &property_u32))
+		hub->max_power_bp = min_t(u8, property_u32 / 2000, 255);
+
+	hub->max_current_sp = USB251XB_DEF_MAX_CURRENT_SELF;
+	if (!of_property_read_u32(np, "sp-max-removable-current-microamp",
+	    &property_u32))
+		hub->max_current_sp = min_t(u8, property_u32 / 2000, 50);
+
+	hub->max_current_bp = USB251XB_DEF_MAX_CURRENT_BUS;
+	if (!of_property_read_u32(np, "bp-max-removable-current-microamp",
+	    &property_u32))
+		hub->max_current_bp = min_t(u8, property_u32 / 2000, 255);
+
+	hub->power_on_time = USB251XB_DEF_POWER_ON_TIME;
+	if (!of_property_read_u32(np, "power-on-time-ms", &property_u32))
+		hub->power_on_time = min_t(u8, property_u32 / 2, 255);
+
+	if (of_property_read_u16_array(np, "language-id", &hub->lang_id, 1))
+		hub->lang_id = USB251XB_DEF_LANGUAGE_ID;
+
+	cproperty_char = of_get_property(np, "manufacturer", NULL);
+	strlcpy(str, cproperty_char ? : USB251XB_DEF_MANUFACTURER_STRING,
+		sizeof(str));
+	hub->manufacturer_len = strlen(str) & 0xFF;
+	memset(hub->manufacturer, 0, USB251XB_STRING_BUFSIZE);
+	len = min_t(size_t, USB251XB_STRING_BUFSIZE / 2, strlen(str));
+	len = utf8s_to_utf16s(str, len, UTF16_LITTLE_ENDIAN,
+			      (wchar_t *)hub->manufacturer,
+			      USB251XB_STRING_BUFSIZE);
+
+	cproperty_char = of_get_property(np, "product", NULL);
+	strlcpy(str, cproperty_char ? : data->product_str, sizeof(str));
+	hub->product_len = strlen(str) & 0xFF;
+	memset(hub->product, 0, USB251XB_STRING_BUFSIZE);
+	len = min_t(size_t, USB251XB_STRING_BUFSIZE / 2, strlen(str));
+	len = utf8s_to_utf16s(str, len, UTF16_LITTLE_ENDIAN,
+			      (wchar_t *)hub->product,
+			      USB251XB_STRING_BUFSIZE);
+
+	cproperty_char = of_get_property(np, "serial", NULL);
+	strlcpy(str, cproperty_char ? : USB251XB_DEF_SERIAL_STRING,
+		sizeof(str));
+	hub->serial_len = strlen(str) & 0xFF;
+	memset(hub->serial, 0, USB251XB_STRING_BUFSIZE);
+	len = min_t(size_t, USB251XB_STRING_BUFSIZE / 2, strlen(str));
+	len = utf8s_to_utf16s(str, len, UTF16_LITTLE_ENDIAN,
+			      (wchar_t *)hub->serial,
+			      USB251XB_STRING_BUFSIZE);
+
+	/* The following parameters are currently not exposed to devicetree, but
+	 * may be as soon as needed.
+	 */
+	hub->bat_charge_en = USB251XB_DEF_BATTERY_CHARGING_ENABLE;
+	hub->boost_up = USB251XB_DEF_BOOST_UP;
+	hub->boost_57 = USB251XB_DEF_BOOST_57;
+	hub->boost_14 = USB251XB_DEF_BOOST_14;
+	hub->port_swap = USB251XB_DEF_PORT_SWAP;
+	hub->port_map12 = USB251XB_DEF_PORT_MAP_12;
+	hub->port_map34 = USB251XB_DEF_PORT_MAP_34;
+	hub->port_map56 = USB251XB_DEF_PORT_MAP_56;
+	hub->port_map7  = USB251XB_DEF_PORT_MAP_7;
+
+	return 0;
+}
+
+static const struct of_device_id usb251xb_of_match[] = {
+	{
+		.compatible = "microchip,usb2512b",
+		.data = &usb2512b_data,
+	}, {
+		.compatible = "microchip,usb2512bi",
+		.data = &usb2512bi_data,
+	}, {
+		.compatible = "microchip,usb2513b",
+		.data = &usb2513b_data,
+	}, {
+		.compatible = "microchip,usb2513bi",
+		.data = &usb2513bi_data,
+	}, {
+		.compatible = "microchip,usb2514b",
+		.data = &usb2514b_data,
+	}, {
+		.compatible = "microchip,usb2514bi",
+		.data = &usb2514bi_data,
+	}, {
+		.compatible = "microchip,usb2517",
+		.data = &usb2517_data,
+	}, {
+		.compatible = "microchip,usb2517i",
+		.data = &usb2517i_data,
+	}, {
+		/* sentinel */
+	}
+};
+#else /* CONFIG_OF */
+static int usb251xb_get_ofdata(struct usb251xb *hub,
+			       struct usb251xb_data *data)
+{
+	return 0;
+}
+#endif /* CONFIG_OF */
+
+static int usb251xb_probe(struct usb251xb *hub)
+{
+	struct device_d *dev = hub->dev;
+	struct device_node *np = dev->device_node;
+	const struct of_device_id *of_id = of_match_device(usb251xb_of_match,
+							   dev);
+	int err;
+
+	if (np) {
+		err = usb251xb_get_ofdata(hub,
+					  (struct usb251xb_data *)of_id->data);
+		if (err) {
+			dev_err(dev, "failed to get ofdata: %d\n", err);
+			return err;
+		}
+	}
+
+	err = usb251xb_connect(hub);
+	if (err) {
+		dev_err(dev, "Failed to connect hub (%d)\n", err);
+		return err;
+	}
+
+	dev_info(dev, "Hub probed successfully\n");
+
+	return 0;
+}
+
+static int usb251xb_i2c_probe(struct device_d *dev)
+{
+	struct i2c_client *i2c = to_i2c_client(dev);
+	struct usb251xb *hub;
+
+	hub = xzalloc(sizeof(struct usb251xb));
+
+	i2c_set_clientdata(i2c, hub);
+	hub->dev = &i2c->dev;
+	hub->i2c = i2c;
+
+	return usb251xb_probe(hub);
+}
+
+static const struct platform_device_id usb251xb_id[] = {
+	{ "usb2512b", 0 },
+	{ "usb2512bi", 0 },
+	{ "usb2513b", 0 },
+	{ "usb2513bi", 0 },
+	{ "usb2514b", 0 },
+	{ "usb2514bi", 0 },
+	{ "usb2517", 0 },
+	{ "usb2517i", 0 },
+	{ /* sentinel */ }
+};
+
+static struct driver_d usb251xb_i2c_driver = {
+	.name = DRIVER_NAME,
+	.probe    = usb251xb_i2c_probe,
+	.id_table = usb251xb_id,
+	.of_compatible = DRV_OF_COMPAT(usb251xb_of_match),
+};
+device_i2c_driver(usb251xb_i2c_driver);
-- 
2.20.1


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

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

* [PATCH 25/25] usb: usb251xb: add usb data lane port swap feature
  2019-02-20  7:29 [PATCH 00/25] i.MX8MQ USB support Andrey Smirnov
                   ` (23 preceding siblings ...)
  2019-02-20  7:29 ` [PATCH 24/25] usb: Port Microchip USB251x USB hub driver from Linux Andrey Smirnov
@ 2019-02-20  7:29 ` Andrey Smirnov
  2019-02-22  7:27 ` [PATCH 00/25] i.MX8MQ USB support Sascha Hauer
  25 siblings, 0 replies; 30+ messages in thread
From: Andrey Smirnov @ 2019-02-20  7:29 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Port of Linux patch https://patchwork.kernel.org/patch/10766235/

  The HW can swap the USB differential-pair (D+/D-) for each port
  separately. So the USB signals can be re-aligned with a misplaced
  USB connector on the PCB.

  Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
  Reviewed-by: Richard Leitner <richard.leitner@skidata.com>

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/misc/usb251xb.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/misc/usb251xb.c b/drivers/usb/misc/usb251xb.c
index 0b721f6d4..97f55efa8 100644
--- a/drivers/usb/misc/usb251xb.c
+++ b/drivers/usb/misc/usb251xb.c
@@ -340,12 +340,14 @@ static int usb251xb_get_ofdata(struct usb251xb *hub,
 	struct device_d *dev = hub->dev;
 	struct device_node *np = dev->device_node;
 	int len, err, i;
-	u32 property_u32 = 0;
+	u32 port, property_u32 = 0;
 	const u32 *cproperty_u32;
 	const char *cproperty_char;
 	enum of_gpio_flags of_flags;
 	unsigned long flags = GPIOF_OUT_INIT_ACTIVE;
 	char str[USB251XB_STRING_BUFSIZE / 2];
+	struct property *prop;
+	const __be32 *p;
 
 	if (!np) {
 		dev_err(dev, "failed to get ofdata\n");
@@ -556,6 +558,16 @@ static int usb251xb_get_ofdata(struct usb251xb *hub,
 			      (wchar_t *)hub->serial,
 			      USB251XB_STRING_BUFSIZE);
 
+	/*
+	 * The datasheet documents the register as 'Port Swap' but the register
+	 * controls the USB DP/DM signal swapping
+	 */
+	hub->port_swap = USB251XB_DEF_PORT_SWAP;
+	of_property_for_each_u32(np, "swap-dx-lanes", prop, p, port) {
+		if ((port >= 0) && (port <= data->port_cnt))
+			hub->port_swap |= BIT(port);
+	}
+
 	/* The following parameters are currently not exposed to devicetree, but
 	 * may be as soon as needed.
 	 */
@@ -563,7 +575,6 @@ static int usb251xb_get_ofdata(struct usb251xb *hub,
 	hub->boost_up = USB251XB_DEF_BOOST_UP;
 	hub->boost_57 = USB251XB_DEF_BOOST_57;
 	hub->boost_14 = USB251XB_DEF_BOOST_14;
-	hub->port_swap = USB251XB_DEF_PORT_SWAP;
 	hub->port_map12 = USB251XB_DEF_PORT_MAP_12;
 	hub->port_map34 = USB251XB_DEF_PORT_MAP_34;
 	hub->port_map56 = USB251XB_DEF_PORT_MAP_56;
-- 
2.20.1


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

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

* Re: [PATCH 02/25] usb: xhci-hcd: Do not zero out DMA coherent memory
  2019-02-20  7:29 ` [PATCH 02/25] usb: xhci-hcd: Do not zero out DMA coherent memory Andrey Smirnov
@ 2019-02-20  9:29   ` Yann Sionneau
  2019-02-20 18:54     ` Andrey Smirnov
  2019-02-23 10:16     ` Sam Ravnborg
  0 siblings, 2 replies; 30+ messages in thread
From: Yann Sionneau @ 2019-02-20  9:29 UTC (permalink / raw)
  To: Andrey Smirnov, barebox

I'm not sure dma_alloc_coherent() should return zeroed out memory.

I'm pretty sure it does not.

mips arch seems to memset it to 0, but not all arch do that.

On 2/20/19 8:29 AM, Andrey Smirnov wrote:
> Memory returned by dma_alloc_coherent() should already be zeroed
> out, so there's no need to do this explicitly.
>
> Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> ---
>   drivers/usb/host/xhci-hcd.c | 2 --
>   1 file changed, 2 deletions(-)
>
> diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
> index 7cfd74de4..7106a5637 100644
> --- a/drivers/usb/host/xhci-hcd.c
> +++ b/drivers/usb/host/xhci-hcd.c
> @@ -445,7 +445,6 @@ static struct xhci_virtual_device *xhci_alloc_virtdev(struct xhci_hcd *xhci,
>   
>   	vdev->dma_size = sz_ictx + sz_dctx;
>   	p = vdev->dma = dma_alloc_coherent(vdev->dma_size, DMA_ADDRESS_BROKEN);
> -	memset(vdev->dma, 0, vdev->dma_size);
>   
>   	vdev->out_ctx = p; p += sz_dctx;
>   	vdev->in_ctx = p; p += sz_ictx;
> @@ -1225,7 +1224,6 @@ static void xhci_dma_alloc(struct xhci_hcd *xhci)
>   	xhci->dma_size += num_ep * sz_ep;
>   
>   	p = xhci->dma = dma_alloc_coherent(xhci->dma_size, DMA_ADDRESS_BROKEN);
> -	memset(xhci->dma, 0, xhci->dma_size);
>   
>   	xhci->sp = p; p += sz_sp;
>   	xhci->dcbaa = p; p += sz_dca;

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

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

* Re: [PATCH 02/25] usb: xhci-hcd: Do not zero out DMA coherent memory
  2019-02-20  9:29   ` Yann Sionneau
@ 2019-02-20 18:54     ` Andrey Smirnov
  2019-02-23 10:16     ` Sam Ravnborg
  1 sibling, 0 replies; 30+ messages in thread
From: Andrey Smirnov @ 2019-02-20 18:54 UTC (permalink / raw)
  To: Yann Sionneau; +Cc: Barebox List

On Wed, Feb 20, 2019 at 1:29 AM Yann Sionneau <ysionneau@kalray.eu> wrote:
>
> I'm not sure dma_alloc_coherent() should return zeroed out memory.
>
> I'm pretty sure it does not.
>
> mips arch seems to memset it to 0, but not all arch do that.
>

It is definitely the semantics in latest kernel code, see e.g. here:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?h=v5.0-rc7&id=dfd32cad146e3624970eee9329e99d2c6ef751b3

As for Barebox, currently there are three architectures that select
HAS_DMA to indicate that they implement said DMA functions: MIPS, ARM
and ARM64. As you mentioned before MIPS already does the right thing
and a series to do the same on ARM/ARM64 was recently merged into
"next" as well, specifically this patch:

https://git.pengutronix.de/cgit/barebox/commit/arch/arm/cpu/mmu-common.c?h=next&id=7179471fd7651e8ddd7758d2c3c94928421e5493

I think this should cover all of the bases as far as xHCI is concerned.

Having looked at it againg, the only two "non-zeroing" cases that I
can see in the codebase are:

1. Nios II which, AFAICT, only uses DMA functions in
drivers/net/altera_tse.c. Since it doesn't select HAS_DMA and is
pretty self-contained, I don't think there's any reason to worry about
leaving it as it is.

2. No MMU case on ARM/ARM64, I doubt there are many users of that
combination, but it is definitely something that should be fixed. I'll
submit a separate series for that.

Thanks,
Andrey Smirnov

> On 2/20/19 8:29 AM, Andrey Smirnov wrote:
> > Memory returned by dma_alloc_coherent() should already be zeroed
> > out, so there's no need to do this explicitly.
> >
> > Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> > ---
> >   drivers/usb/host/xhci-hcd.c | 2 --
> >   1 file changed, 2 deletions(-)
> >
> > diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
> > index 7cfd74de4..7106a5637 100644
> > --- a/drivers/usb/host/xhci-hcd.c
> > +++ b/drivers/usb/host/xhci-hcd.c
> > @@ -445,7 +445,6 @@ static struct xhci_virtual_device *xhci_alloc_virtdev(struct xhci_hcd *xhci,
> >
> >       vdev->dma_size = sz_ictx + sz_dctx;
> >       p = vdev->dma = dma_alloc_coherent(vdev->dma_size, DMA_ADDRESS_BROKEN);
> > -     memset(vdev->dma, 0, vdev->dma_size);
> >
> >       vdev->out_ctx = p; p += sz_dctx;
> >       vdev->in_ctx = p; p += sz_ictx;
> > @@ -1225,7 +1224,6 @@ static void xhci_dma_alloc(struct xhci_hcd *xhci)
> >       xhci->dma_size += num_ep * sz_ep;
> >
> >       p = xhci->dma = dma_alloc_coherent(xhci->dma_size, DMA_ADDRESS_BROKEN);
> > -     memset(xhci->dma, 0, xhci->dma_size);
> >
> >       xhci->sp = p; p += sz_sp;
> >       xhci->dcbaa = p; p += sz_dca;

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

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

* Re: [PATCH 00/25] i.MX8MQ USB support
  2019-02-20  7:29 [PATCH 00/25] i.MX8MQ USB support Andrey Smirnov
                   ` (24 preceding siblings ...)
  2019-02-20  7:29 ` [PATCH 25/25] usb: usb251xb: add usb data lane port swap feature Andrey Smirnov
@ 2019-02-22  7:27 ` Sascha Hauer
  25 siblings, 0 replies; 30+ messages in thread
From: Sascha Hauer @ 2019-02-22  7:27 UTC (permalink / raw)
  To: Andrey Smirnov; +Cc: barebox

On Tue, Feb 19, 2019 at 11:29:05PM -0800, Andrey Smirnov wrote:
> Everyone:
> 
> This series contains changes I made while working on adding USB
> support for ZII i.MX8MQ boards. There are several distinct parts in
> this series:
> 
>  1. xHCI fixes, features and improvements
>  2. PHY driver deferral support
>  3. i.MX8MQ USB PHY driver
>  4. DWC3 USB support and related patches
>  5. USB251x USB hub and related patches
> 
> First four are neccessary for i.MX8MQ in general and last part is ZII
> specific only. Hopefully all patches are self explanatory.
> 
> Tested on ZII i.MX8MQ boards.
> 
> Feedback is welcome!

Nice work. That'll safe me some time when adding USB support for
Layerscape ;)

Applied, thanks

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 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] 30+ messages in thread

* Re: [PATCH 02/25] usb: xhci-hcd: Do not zero out DMA coherent memory
  2019-02-20  9:29   ` Yann Sionneau
  2019-02-20 18:54     ` Andrey Smirnov
@ 2019-02-23 10:16     ` Sam Ravnborg
  1 sibling, 0 replies; 30+ messages in thread
From: Sam Ravnborg @ 2019-02-23 10:16 UTC (permalink / raw)
  To: Yann Sionneau; +Cc: Andrey Smirnov, barebox

On Wed, Feb 20, 2019 at 10:29:49AM +0100, Yann Sionneau wrote:
> I'm not sure dma_alloc_coherent() should return zeroed out memory.
> 
> I'm pretty sure it does not.
> 
> mips arch seems to memset it to 0, but not all arch do that.

Christoph Hellwig had a patch series that zeroed memory for
all archs on dma_alloc_coherent() and friends.
https://lkml.org/lkml/2018/12/14/103

barebox should do the same as I see it.

I recall the patch series is applied but I did not check.

	Sam

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

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

end of thread, other threads:[~2019-02-23 10:18 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-02-20  7:29 [PATCH 00/25] i.MX8MQ USB support Andrey Smirnov
2019-02-20  7:29 ` [PATCH 01/25] usb: xhci-hcd: Tabify the file Andrey Smirnov
2019-02-20  7:29 ` [PATCH 02/25] usb: xhci-hcd: Do not zero out DMA coherent memory Andrey Smirnov
2019-02-20  9:29   ` Yann Sionneau
2019-02-20 18:54     ` Andrey Smirnov
2019-02-23 10:16     ` Sam Ravnborg
2019-02-20  7:29 ` [PATCH 03/25] usb: xhci-hcd: Cast ~XHCI_IRQS to u32 Andrey Smirnov
2019-02-20  7:29 ` [PATCH 04/25] usb: xhci-hcd: Make sure to initialize xhci->rings_list Andrey Smirnov
2019-02-20  7:29 ` [PATCH 05/25] usb: xhci-hcd: Drop pointless bitwise or Andrey Smirnov
2019-02-20  7:29 ` [PATCH 06/25] usb: xhci-hcd: Add support for 64-byte context size Andrey Smirnov
2019-02-20  7:29 ` [PATCH 07/25] usb: xhci-hcd: Don't try to DMA sync if buffer is NULL Andrey Smirnov
2019-02-20  7:29 ` [PATCH 08/25] usb: xhci-hcd: Always wait for "Response Data" completion Andrey Smirnov
2019-02-20  7:29 ` [PATCH 09/25] usb: xhci-hcd: Convert xhci_submit_normal() to use dma_map_single() Andrey Smirnov
2019-02-20  7:29 ` [PATCH 10/25] usb: xhci-hcd: Convert xhci_submit_control() " Andrey Smirnov
2019-02-20  7:29 ` [PATCH 11/25] usb: xhci-hcd: Simplify TRB initialization code Andrey Smirnov
2019-02-20  7:29 ` [PATCH 12/25] usb: xhci-hcd: Drop 'dma' field from struct xhci_hcd Andrey Smirnov
2019-02-20  7:29 ` [PATCH 13/25] usb: xhci-hcd: Check usb_pipein(pipe) only once in xhci_submit_normal() Andrey Smirnov
2019-02-20  7:29 ` [PATCH 14/25] usb: xhci-hcd: Initialize TRT flag for xHCI >= 1.0 Andrey Smirnov
2019-02-20  7:29 ` [PATCH 15/25] usb: xhci-hcd: Simplify route string building loop Andrey Smirnov
2019-02-20  7:29 ` [PATCH 16/25] usb: xhci-hcd: Make use of lo_hi_readq/writeq() Andrey Smirnov
2019-02-20  7:29 ` [PATCH 17/25] phy: core: Assume EPROBE_DEFER in of_phy_provider_lookup() Andrey Smirnov
2019-02-20  7:29 ` [PATCH 18/25] phy: Port i.MX8MQ USB PHY driver from Linux Andrey Smirnov
2019-02-20  7:29 ` [PATCH 19/25] clk: Drop separate definitions of clk_put() Andrey Smirnov
2019-02-20  7:29 ` [PATCH 20/25] include/usb: Import USB_SPEED_SUPER_PLUS from Linux Andrey Smirnov
2019-02-20  7:29 ` [PATCH 21/25] clk: Import a subset of clk_bulk API " Andrey Smirnov
2019-02-20  7:29 ` [PATCH 22/25] usb: Import DWC3 USB controller driver " Andrey Smirnov
2019-02-20  7:29 ` [PATCH 23/25] lib: Port basic Linux kernel NLS functions Andrey Smirnov
2019-02-20  7:29 ` [PATCH 24/25] usb: Port Microchip USB251x USB hub driver from Linux Andrey Smirnov
2019-02-20  7:29 ` [PATCH 25/25] usb: usb251xb: add usb data lane port swap feature Andrey Smirnov
2019-02-22  7:27 ` [PATCH 00/25] i.MX8MQ USB 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