Module Name:    src
Committed By:   skrll
Date:           Sun Feb 14 10:53:30 UTC 2016

Modified Files:
        src/sys/external/bsd/dwc2/dist: dwc2_core.c dwc2_core.h dwc2_coreintr.c
            dwc2_hcd.c dwc2_hcd.h dwc2_hcdddma.c dwc2_hcdintr.c dwc2_hcdqueue.c
            dwc2_hw.h

Log Message:
Merge conflicts


To generate a diff of this commit:
cvs rdiff -u -r1.10 -r1.11 src/sys/external/bsd/dwc2/dist/dwc2_core.c
cvs rdiff -u -r1.6 -r1.7 src/sys/external/bsd/dwc2/dist/dwc2_core.h \
    src/sys/external/bsd/dwc2/dist/dwc2_hcdddma.c
cvs rdiff -u -r1.9 -r1.10 src/sys/external/bsd/dwc2/dist/dwc2_coreintr.c
cvs rdiff -u -r1.17 -r1.18 src/sys/external/bsd/dwc2/dist/dwc2_hcd.c
cvs rdiff -u -r1.11 -r1.12 src/sys/external/bsd/dwc2/dist/dwc2_hcd.h
cvs rdiff -u -r1.12 -r1.13 src/sys/external/bsd/dwc2/dist/dwc2_hcdintr.c
cvs rdiff -u -r1.13 -r1.14 src/sys/external/bsd/dwc2/dist/dwc2_hcdqueue.c
cvs rdiff -u -r1.3 -r1.4 src/sys/external/bsd/dwc2/dist/dwc2_hw.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/external/bsd/dwc2/dist/dwc2_core.c
diff -u src/sys/external/bsd/dwc2/dist/dwc2_core.c:1.10 src/sys/external/bsd/dwc2/dist/dwc2_core.c:1.11
--- src/sys/external/bsd/dwc2/dist/dwc2_core.c:1.10	Tue Sep  1 14:03:00 2015
+++ src/sys/external/bsd/dwc2/dist/dwc2_core.c	Sun Feb 14 10:53:30 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: dwc2_core.c,v 1.10 2015/09/01 14:03:00 skrll Exp $	*/
+/*	$NetBSD: dwc2_core.c,v 1.11 2016/02/14 10:53:30 skrll Exp $	*/
 
 /*
  * core.c - DesignWare HS OTG Controller common routines
@@ -43,7 +43,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dwc2_core.c,v 1.10 2015/09/01 14:03:00 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dwc2_core.c,v 1.11 2016/02/14 10:53:30 skrll Exp $");
 
 #include <sys/types.h>
 #include <sys/bus.h>
@@ -127,6 +127,7 @@ static int dwc2_restore_host_registers(s
 
 	DWC2_WRITE_4(hsotg, HPRT0, hr->hprt0);
 	DWC2_WRITE_4(hsotg, HFIR, hr->hfir);
+	hsotg->frame_number = 0;
 
 	return 0;
 }
@@ -408,6 +409,12 @@ int dwc2_enter_hibernation(struct dwc2_h
 		}
 	}
 
+	/*
+	 * Clear any pending interrupts since dwc2 will not be able to
+	 * clear them after entering hibernation.
+	 */
+	DWC2_WRITE_4(hsotg, GINTSTS, 0xffffffff);
+
 	/* Put the controller in low power state */
 	pcgcctl = DWC2_READ_4(hsotg, PCGCTL);
 
@@ -485,64 +492,166 @@ static void dwc2_init_fs_ls_pclk_sel(str
  * Do core a soft reset of the core.  Be careful with this because it
  * resets all the internal state machines of the core.
  */
-static int dwc2_core_reset(struct dwc2_hsotg *hsotg)
+int dwc2_core_reset(struct dwc2_hsotg *hsotg)
 {
 	u32 greset;
 	int count = 0;
-	u32 gusbcfg;
 
 	dev_vdbg(hsotg->dev, "%s()\n", __func__);
 
-	/* Wait for AHB master IDLE state */
+	/* Core Soft Reset */
+	greset = DWC2_READ_4(hsotg, GRSTCTL);
+	greset |= GRSTCTL_CSFTRST;
+	DWC2_WRITE_4(hsotg, GRSTCTL, greset);
 	do {
-		usleep_range(20000, 40000);
+		udelay(1);
 		greset = DWC2_READ_4(hsotg, GRSTCTL);
 		if (++count > 50) {
 			dev_warn(hsotg->dev,
-				 "%s() HANG! AHB Idle GRSTCTL=%0x\n",
+				 "%s() HANG! Soft Reset GRSTCTL=%0x\n",
 				 __func__, greset);
 			return -EBUSY;
 		}
-	} while (!(greset & GRSTCTL_AHBIDLE));
+	} while (greset & GRSTCTL_CSFTRST);
 
-	/* Core Soft Reset */
+	/* Wait for AHB master IDLE state */
 	count = 0;
-	greset |= GRSTCTL_CSFTRST;
-	DWC2_WRITE_4(hsotg, GRSTCTL, greset);
 	do {
-		usleep_range(20000, 40000);
+		udelay(1);
 		greset = DWC2_READ_4(hsotg, GRSTCTL);
 		if (++count > 50) {
 			dev_warn(hsotg->dev,
-				 "%s() HANG! Soft Reset GRSTCTL=%0x\n",
+				 "%s() HANG! AHB Idle GRSTCTL=%0x\n",
 				 __func__, greset);
 			return -EBUSY;
 		}
-	} while (greset & GRSTCTL_CSFTRST);
+	} while (!(greset & GRSTCTL_AHBIDLE));
+
+	return 0;
+}
 
-	if (hsotg->dr_mode == USB_DR_MODE_HOST) {
-		gusbcfg = DWC2_READ_4(hsotg, GUSBCFG);
-		gusbcfg &= ~GUSBCFG_FORCEDEVMODE;
-		gusbcfg |= GUSBCFG_FORCEHOSTMODE;
-		DWC2_WRITE_4(hsotg, GUSBCFG, gusbcfg);
-	} else if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) {
-		gusbcfg = DWC2_READ_4(hsotg, GUSBCFG);
-		gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
-		gusbcfg |= GUSBCFG_FORCEDEVMODE;
-		DWC2_WRITE_4(hsotg, GUSBCFG, gusbcfg);
-	} else if (hsotg->dr_mode == USB_DR_MODE_OTG) {
-		gusbcfg = DWC2_READ_4(hsotg, GUSBCFG);
-		gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
-		gusbcfg &= ~GUSBCFG_FORCEDEVMODE;
-		DWC2_WRITE_4(hsotg, GUSBCFG, gusbcfg);
+/*
+ * Force the mode of the controller.
+ *
+ * Forcing the mode is needed for two cases:
+ *
+ * 1) If the dr_mode is set to either HOST or PERIPHERAL we force the
+ * controller to stay in a particular mode regardless of ID pin
+ * changes. We do this usually after a core reset.
+ *
+ * 2) During probe we want to read reset values of the hw
+ * configuration registers that are only available in either host or
+ * device mode. We may need to force the mode if the current mode does
+ * not allow us to access the register in the mode that we want.
+ *
+ * In either case it only makes sense to force the mode if the
+ * controller hardware is OTG capable.
+ *
+ * Checks are done in this function to determine whether doing a force
+ * would be valid or not.
+ *
+ * If a force is done, it requires a 25ms delay to take effect.
+ *
+ * Returns true if the mode was forced.
+ */
+static bool dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host)
+{
+	u32 gusbcfg;
+	u32 set;
+	u32 clear;
+
+	dev_dbg(hsotg->dev, "Forcing mode to %s\n", host ? "host" : "device");
+
+	/*
+	 * Force mode has no effect if the hardware is not OTG.
+	 */
+	if (!dwc2_hw_is_otg(hsotg))
+		return false;
+
+	/*
+	 * If dr_mode is either peripheral or host only, there is no
+	 * need to ever force the mode to the opposite mode.
+	 */
+	if (host && hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) {
+		WARN_ON(1);
+		return false;
 	}
 
+	if (!host && hsotg->dr_mode == USB_DR_MODE_HOST) {
+		WARN_ON(1);
+		return false;
+	}
+
+	gusbcfg = DWC2_READ_4(hsotg, GUSBCFG);
+
+	set = host ? GUSBCFG_FORCEHOSTMODE : GUSBCFG_FORCEDEVMODE;
+	clear = host ? GUSBCFG_FORCEDEVMODE : GUSBCFG_FORCEHOSTMODE;
+
+	gusbcfg &= ~clear;
+	gusbcfg |= set;
+	DWC2_WRITE_4(hsotg, GUSBCFG, gusbcfg);
+
+	msleep(25);
+	return true;
+}
+
+/*
+ * Clears the force mode bits.
+ */
+static void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg)
+{
+	u32 gusbcfg;
+
+	gusbcfg = DWC2_READ_4(hsotg, GUSBCFG);
+	gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
+	gusbcfg &= ~GUSBCFG_FORCEDEVMODE;
+	DWC2_WRITE_4(hsotg, GUSBCFG, gusbcfg);
+
 	/*
 	 * NOTE: This long sleep is _very_ important, otherwise the core will
 	 * not stay in host mode after a connector ID change!
 	 */
-	usleep_range(150000, 200000);
+	msleep(25);
+}
+
+/*
+ * Sets or clears force mode based on the dr_mode parameter.
+ */
+void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg)
+{
+	switch (hsotg->dr_mode) {
+	case USB_DR_MODE_HOST:
+		dwc2_force_mode(hsotg, true);
+		break;
+	case USB_DR_MODE_PERIPHERAL:
+		dwc2_force_mode(hsotg, false);
+		break;
+	case USB_DR_MODE_OTG:
+		dwc2_clear_force_mode(hsotg);
+		break;
+	default:
+		dev_warn(hsotg->dev, "%s() Invalid dr_mode=%d\n",
+			 __func__, hsotg->dr_mode);
+		break;
+	}
+}
+
+/*
+ * Do core a soft reset of the core.  Be careful with this because it
+ * resets all the internal state machines of the core.
+ *
+ * Additionally this will apply force mode as per the hsotg->dr_mode
+ * parameter.
+ */
+int dwc2_core_reset_and_force_dr_mode(struct dwc2_hsotg *hsotg)
+{
+	int retval;
 
+	retval = dwc2_core_reset(hsotg);
+	if (retval)
+		return retval;
+
+	dwc2_force_dr_mode(hsotg);
 	return 0;
 }
 
@@ -557,16 +666,20 @@ static int dwc2_fs_phy_init(struct dwc2_
 	 */
 	if (select_phy) {
 		dev_dbg(hsotg->dev, "FS PHY selected\n");
-		usbcfg = DWC2_READ_4(hsotg, GUSBCFG);
-		usbcfg |= GUSBCFG_PHYSEL;
-		DWC2_WRITE_4(hsotg, GUSBCFG, usbcfg);
 
-		/* Reset after a PHY select */
-		retval = dwc2_core_reset(hsotg);
-		if (retval) {
-			dev_err(hsotg->dev, "%s() Reset failed, aborting",
-					__func__);
-			return retval;
+		usbcfg = DWC2_READ_4(hsotg, GUSBCFG);
+		if (!(usbcfg & GUSBCFG_PHYSEL)) {
+			usbcfg |= GUSBCFG_PHYSEL;
+			DWC2_WRITE_4(hsotg, GUSBCFG, usbcfg);
+
+			/* Reset after a PHY select */
+			retval = dwc2_core_reset_and_force_dr_mode(hsotg);
+
+			if (retval) {
+				dev_err(hsotg->dev,
+					"%s: Reset failed, aborting", __func__);
+				return retval;
+			}
 		}
 	}
 
@@ -601,13 +714,13 @@ static int dwc2_fs_phy_init(struct dwc2_
 
 static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
 {
-	u32 usbcfg;
+	u32 usbcfg, usbcfg_old;
 	int retval = 0;
 
 	if (!select_phy)
 		return 0;
 
-	usbcfg = DWC2_READ_4(hsotg, GUSBCFG);
+	usbcfg = usbcfg_old = DWC2_READ_4(hsotg, GUSBCFG);
 
 	/*
 	 * HS PHY parameters. These parameters are preserved during soft reset
@@ -635,14 +748,16 @@ static int dwc2_hs_phy_init(struct dwc2_
 		break;
 	}
 
-	DWC2_WRITE_4(hsotg, GUSBCFG, usbcfg);
+	if (usbcfg != usbcfg_old) {
+		DWC2_WRITE_4(hsotg, GUSBCFG, usbcfg);
 
-	/* Reset after setting the PHY parameters */
-	retval = dwc2_core_reset(hsotg);
-	if (retval) {
-		dev_err(hsotg->dev, "%s() Reset failed, aborting",
-				__func__);
-		return retval;
+		/* Reset after setting the PHY parameters */
+		retval = dwc2_core_reset_and_force_dr_mode(hsotg);
+		if (retval) {
+			dev_err(hsotg->dev,
+				"%s: Reset failed, aborting", __func__);
+			return retval;
+		}
 	}
 
 	return retval;
@@ -779,11 +894,10 @@ static void dwc2_gusbcfg_init(struct dwc
  * dwc2_core_init() - Initializes the DWC_otg controller registers and
  * prepares the core for device mode or host mode operation
  *
- * @hsotg:      Programming view of the DWC_otg controller
- * @select_phy: If true then also set the Phy type
- * @irq:        If >= 0, the irq to register
+ * @hsotg:         Programming view of the DWC_otg controller
+ * @initial_setup: If true then this is the first init for this instance.
  */
-int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy)
+int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup)
 {
 	u32 usbcfg, otgctl;
 	int retval;
@@ -805,18 +919,26 @@ int dwc2_core_init(struct dwc2_hsotg *hs
 
 	DWC2_WRITE_4(hsotg, GUSBCFG, usbcfg);
 
-	/* Reset the Controller */
-	retval = dwc2_core_reset(hsotg);
-	if (retval) {
-		dev_err(hsotg->dev, "%s(): Reset failed, aborting\n",
-				__func__);
-		return retval;
+	/*
+	 * Reset the Controller
+	 *
+	 * We only need to reset the controller if this is a re-init.
+	 * For the first init we know for sure that earlier code reset us (it
+	 * needed to in order to properly detect various parameters).
+	 */
+	if (!initial_setup) {
+		retval = dwc2_core_reset_and_force_dr_mode(hsotg);
+		if (retval) {
+			dev_err(hsotg->dev, "%s(): Reset failed, aborting\n",
+					__func__);
+			return retval;
+		}
 	}
 
 	/*
 	 * This needs to happen in FS mode before any other programming occurs
 	 */
-	retval = dwc2_phy_init(hsotg, select_phy);
+	retval = dwc2_phy_init(hsotg, initial_setup);
 	if (retval)
 		return retval;
 
@@ -892,7 +1014,7 @@ void dwc2_disable_host_interrupts(struct
 
 	/* Disable host mode interrupts without disturbing common interrupts */
 	intmsk &= ~(GINTSTS_SOF | GINTSTS_PRTINT | GINTSTS_HCHINT |
-		    GINTSTS_PTXFEMP | GINTSTS_NPTXFEMP);
+		    GINTSTS_PTXFEMP | GINTSTS_NPTXFEMP | GINTSTS_DISCONNINT);
 	DWC2_WRITE_4(hsotg, GINTMSK, intmsk);
 }
 
@@ -979,7 +1101,8 @@ static void dwc2_config_fifos(struct dwc
 	grxfsiz |= params->host_rx_fifo_size <<
 		   GRXFSIZ_DEPTH_SHIFT & GRXFSIZ_DEPTH_MASK;
 	DWC2_WRITE_4(hsotg, GRXFSIZ, grxfsiz);
-	dev_dbg(hsotg->dev, "new grxfsiz=%08x\n", DWC2_READ_4(hsotg, GRXFSIZ));
+	dev_dbg(hsotg->dev, "new grxfsiz=%08x\n",
+		DWC2_READ_4(hsotg, GRXFSIZ));
 
 	/* Non-periodic Tx FIFO */
 	dev_dbg(hsotg->dev, "initial gnptxfsiz=%08x\n",
@@ -1720,6 +1843,7 @@ void dwc2_hc_start_transfer(struct dwc2_
 	u32 hcchar;
 	u32 hctsiz = 0;
 	u16 num_packets;
+	u32 ec_mc;
 
 	if (dbg_hc(chan))
 		dev_vdbg(hsotg->dev, "%s()\n", __func__);
@@ -1756,6 +1880,13 @@ void dwc2_hc_start_transfer(struct dwc2_
 
 		hctsiz |= chan->xfer_len << TSIZ_XFERSIZE_SHIFT &
 			  TSIZ_XFERSIZE_MASK;
+
+		/* For split set ec_mc for immediate retries */
+		if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
+		    chan->ep_type == USB_ENDPOINT_XFER_ISOC)
+			ec_mc = 3;
+		else
+			ec_mc = 1;
 	} else {
 		if (dbg_hc(chan))
 			dev_vdbg(hsotg->dev, "no split\n");
@@ -1818,6 +1949,9 @@ void dwc2_hc_start_transfer(struct dwc2_
 
 		hctsiz |= chan->xfer_len << TSIZ_XFERSIZE_SHIFT &
 			  TSIZ_XFERSIZE_MASK;
+
+		/* The ec_mc gets the multi_count for non-split */
+		ec_mc = chan->multi_count;
 	}
 
 	chan->start_pkt_count = num_packets;
@@ -1876,8 +2010,7 @@ void dwc2_hc_start_transfer(struct dwc2_
 
 	hcchar = DWC2_READ_4(hsotg, HCCHAR(chan->hc_num));
 	hcchar &= ~HCCHAR_MULTICNT_MASK;
-	hcchar |= chan->multi_count << HCCHAR_MULTICNT_SHIFT &
-		  HCCHAR_MULTICNT_MASK;
+	hcchar |= (ec_mc << HCCHAR_MULTICNT_SHIFT) & HCCHAR_MULTICNT_MASK;
 	dwc2_hc_set_even_odd_frame(hsotg, chan, &hcchar);
 
 	if (hcchar & HCCHAR_CHDIS)
@@ -1926,7 +2059,6 @@ void dwc2_hc_start_transfer_ddma(struct 
 				 struct dwc2_host_chan *chan)
 {
 	u32 hcchar;
-	u32 hc_dma;
 	u32 hctsiz = 0;
 
 	if (chan->do_ping)
@@ -1955,15 +2087,22 @@ void dwc2_hc_start_transfer_ddma(struct 
 
 	DWC2_WRITE_4(hsotg, HCTSIZ(chan->hc_num), hctsiz);
 
-	hc_dma = (u32)chan->desc_list_addr & HCDMA_DMA_ADDR_MASK;
-
-	/* Always start from first descriptor */
-	hc_dma &= ~HCDMA_CTD_MASK;
-	DWC2_WRITE_4(hsotg, HCDMA(chan->hc_num), hc_dma);
-	if (dbg_hc(chan))
-		dev_vdbg(hsotg->dev, "Wrote %08x to HCDMA(%d)\n",
-			 hc_dma, chan->hc_num);
+	usb_syncmem(&chan->desc_list_usbdma, 0, chan->desc_list_sz,
+	    BUS_DMASYNC_PREWRITE);
 
+	if (hsotg->hsotg_sc->sc_set_dma_addr == NULL) {
+		DWC2_WRITE_4(hsotg, HCDMA(chan->hc_num), chan->desc_list_addr);
+		if (dbg_hc(chan))
+			dev_vdbg(hsotg->dev, "Wrote %pad to HCDMA(%d)\n",
+				&chan->desc_list_addr, chan->hc_num);
+	} else {
+		(void)(*hsotg->hsotg_sc->sc_set_dma_addr)(
+		    hsotg->dev, chan->desc_list_addr, chan->hc_num);
+		if (dbg_hc(chan))
+			dev_vdbg(hsotg->dev, "Wrote %pad to ext dma(%d)\n",
+				&chan->desc_list_addr, chan->hc_num);
+	}
+	
 	hcchar = DWC2_READ_4(hsotg, HCCHAR(chan->hc_num));
 	hcchar &= ~HCCHAR_MULTICNT_MASK;
 	hcchar |= chan->multi_count << HCCHAR_MULTICNT_SHIFT &
@@ -2505,6 +2644,29 @@ void dwc2_set_param_dma_desc_enable(stru
 	hsotg->core_params->dma_desc_enable = val;
 }
 
+void dwc2_set_param_dma_desc_fs_enable(struct dwc2_hsotg *hsotg, int val)
+{
+	int valid = 1;
+
+	if (val > 0 && (hsotg->core_params->dma_enable <= 0 ||
+			!hsotg->hw_params.dma_desc_enable))
+		valid = 0;
+	if (val < 0)
+		valid = 0;
+
+	if (!valid) {
+		if (val >= 0)
+			dev_err(hsotg->dev,
+				"%d invalid for dma_desc_fs_enable parameter. Check HW configuration.\n",
+				val);
+		val = (hsotg->core_params->dma_enable > 0 &&
+			hsotg->hw_params.dma_desc_enable);
+	}
+
+	hsotg->core_params->dma_desc_fs_enable = val;
+	dev_dbg(hsotg->dev, "Setting dma_desc_fs_enable to %d\n", val);
+}
+
 void dwc2_set_param_host_support_fs_ls_low_power(struct dwc2_hsotg *hsotg,
 						 int val)
 {
@@ -3036,6 +3198,7 @@ void dwc2_set_parameters(struct dwc2_hso
 	dwc2_set_param_otg_cap(hsotg, params->otg_cap);
 	dwc2_set_param_dma_enable(hsotg, params->dma_enable);
 	dwc2_set_param_dma_desc_enable(hsotg, params->dma_desc_enable);
+	dwc2_set_param_dma_desc_fs_enable(hsotg, params->dma_desc_fs_enable);
 	dwc2_set_param_host_support_fs_ls_low_power(hsotg,
 			params->host_support_fs_ls_low_power);
 	dwc2_set_param_enable_dynamic_fifo(hsotg,
@@ -3072,6 +3235,79 @@ void dwc2_set_parameters(struct dwc2_hso
 	dwc2_set_param_hibernation(hsotg, params->hibernation);
 }
 
+/*
+ * Forces either host or device mode if the controller is not
+ * currently in that mode.
+ *
+ * Returns true if the mode was forced.
+ */
+static bool dwc2_force_mode_if_needed(struct dwc2_hsotg *hsotg, bool host)
+{
+	if (host && dwc2_is_host_mode(hsotg))
+		return false;
+	else if (!host && dwc2_is_device_mode(hsotg))
+		return false;
+
+	return dwc2_force_mode(hsotg, host);
+}
+
+/*
+ * Gets host hardware parameters. Forces host mode if not currently in
+ * host mode. Should be called immediately after a core soft reset in
+ * order to get the reset values.
+ */
+static void dwc2_get_host_hwparams(struct dwc2_hsotg *hsotg)
+{
+	struct dwc2_hw_params *hw = &hsotg->hw_params;
+	u32 gnptxfsiz;
+	u32 hptxfsiz;
+	bool forced;
+
+	if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)
+		return;
+
+	forced = dwc2_force_mode_if_needed(hsotg, true);
+
+	gnptxfsiz = DWC2_READ_4(hsotg, GNPTXFSIZ);
+	hptxfsiz = DWC2_READ_4(hsotg, HPTXFSIZ);
+	dev_dbg(hsotg->dev, "gnptxfsiz=%08x\n", gnptxfsiz);
+	dev_dbg(hsotg->dev, "hptxfsiz=%08x\n", hptxfsiz);
+
+	if (forced)
+		dwc2_clear_force_mode(hsotg);
+
+	hw->host_nperio_tx_fifo_size = (gnptxfsiz & FIFOSIZE_DEPTH_MASK) >>
+				       FIFOSIZE_DEPTH_SHIFT;
+	hw->host_perio_tx_fifo_size = (hptxfsiz & FIFOSIZE_DEPTH_MASK) >>
+				      FIFOSIZE_DEPTH_SHIFT;
+}
+
+/*
+ * Gets device hardware parameters. Forces device mode if not
+ * currently in device mode. Should be called immediately after a core
+ * soft reset in order to get the reset values.
+ */
+static void dwc2_get_dev_hwparams(struct dwc2_hsotg *hsotg)
+{
+	struct dwc2_hw_params *hw = &hsotg->hw_params;
+	bool forced;
+	u32 gnptxfsiz;
+
+	if (hsotg->dr_mode == USB_DR_MODE_HOST)
+		return;
+
+	forced = dwc2_force_mode_if_needed(hsotg, false);
+
+	gnptxfsiz = DWC2_READ_4(hsotg, GNPTXFSIZ);
+	dev_dbg(hsotg->dev, "gnptxfsiz=%08x\n", gnptxfsiz);
+
+	if (forced)
+		dwc2_clear_force_mode(hsotg);
+
+	hw->dev_nperio_tx_fifo_size = (gnptxfsiz & FIFOSIZE_DEPTH_MASK) >>
+				       FIFOSIZE_DEPTH_SHIFT;
+}
+
 /**
  * During device initialization, read various hardware configuration
  * registers and interpret the contents.
@@ -3080,9 +3316,8 @@ int dwc2_get_hwparams(struct dwc2_hsotg 
 {
 	struct dwc2_hw_params *hw = &hsotg->hw_params;
 	unsigned width;
-	u32 hwcfg2, hwcfg3, hwcfg4;
-	u32 hptxfsiz, grxfsiz, gnptxfsiz;
-	u32 gusbcfg;
+	u32 hwcfg1, hwcfg2, hwcfg3, hwcfg4;
+	u32 grxfsiz;
 
 	/*
 	 * Attempt to ensure this device is really a DWC_otg Controller.
@@ -3102,31 +3337,28 @@ int dwc2_get_hwparams(struct dwc2_hsotg 
 		hw->snpsid >> 12 & 0xf, hw->snpsid >> 8 & 0xf,
 		hw->snpsid >> 4 & 0xf, hw->snpsid & 0xf, hw->snpsid);
 
+	hwcfg1 = DWC2_READ_4(hsotg, GHWCFG1);
 	hwcfg2 = DWC2_READ_4(hsotg, GHWCFG2);
 	hwcfg3 = DWC2_READ_4(hsotg, GHWCFG3);
 	hwcfg4 = DWC2_READ_4(hsotg, GHWCFG4);
 	grxfsiz = DWC2_READ_4(hsotg, GRXFSIZ);
 
-	dev_dbg(hsotg->dev, "hwcfg1=%08x\n", DWC2_READ_4(hsotg, GHWCFG1));
+	dev_dbg(hsotg->dev, "hwcfg1=%08x\n", hwcfg1);
 	dev_dbg(hsotg->dev, "hwcfg2=%08x\n", hwcfg2);
 	dev_dbg(hsotg->dev, "hwcfg3=%08x\n", hwcfg3);
 	dev_dbg(hsotg->dev, "hwcfg4=%08x\n", hwcfg4);
 	dev_dbg(hsotg->dev, "grxfsiz=%08x\n", grxfsiz);
 
-	/* Force host mode to get HPTXFSIZ / GNPTXFSIZ exact power on value */
-	gusbcfg = DWC2_READ_4(hsotg, GUSBCFG);
-	gusbcfg |= GUSBCFG_FORCEHOSTMODE;
-	DWC2_WRITE_4(hsotg, GUSBCFG, gusbcfg);
-	usleep_range(100000, 150000);
+	/*
+	 * Host specific hardware parameters. Reading these parameters
+	 * requires the controller to be in host mode. The mode will
+	 * be forced, if necessary, to read these values.
+	 */
+	dwc2_get_host_hwparams(hsotg);
+	dwc2_get_dev_hwparams(hsotg);
 
-	gnptxfsiz = DWC2_READ_4(hsotg, GNPTXFSIZ);
-	hptxfsiz = DWC2_READ_4(hsotg, HPTXFSIZ);
-	dev_dbg(hsotg->dev, "gnptxfsiz=%08x\n", gnptxfsiz);
-	dev_dbg(hsotg->dev, "hptxfsiz=%08x\n", hptxfsiz);
-	gusbcfg = DWC2_READ_4(hsotg, GUSBCFG);
-	gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
-	DWC2_WRITE_4(hsotg, GUSBCFG, gusbcfg);
-	usleep_range(100000, 150000);
+	/* hwcfg1 */
+	hw->dev_ep_dirs = hwcfg1;
 
 	/* hwcfg2 */
 	hw->op_mode = (hwcfg2 & GHWCFG2_OP_MODE_MASK) >>
@@ -3182,10 +3414,6 @@ int dwc2_get_hwparams(struct dwc2_hsotg 
 	/* fifo sizes */
 	hw->host_rx_fifo_size = (grxfsiz & GRXFSIZ_DEPTH_MASK) >>
 				GRXFSIZ_DEPTH_SHIFT;
-	hw->host_nperio_tx_fifo_size = (gnptxfsiz & FIFOSIZE_DEPTH_MASK) >>
-				       FIFOSIZE_DEPTH_SHIFT;
-	hw->host_perio_tx_fifo_size = (hptxfsiz & FIFOSIZE_DEPTH_MASK) >>
-				      FIFOSIZE_DEPTH_SHIFT;
 
 	dev_dbg(hsotg->dev, "Detected values from hardware:\n");
 	dev_dbg(hsotg->dev, "  op_mode=%d\n",
@@ -3202,7 +3430,7 @@ int dwc2_get_hwparams(struct dwc2_hsotg 
 		hw->hs_phy_type);
 	dev_dbg(hsotg->dev, "  fs_phy_type=%d\n",
 		hw->fs_phy_type);
-	dev_dbg(hsotg->dev, "  utmi_phy_data_wdith=%d\n",
+	dev_dbg(hsotg->dev, "  utmi_phy_data_width=%d\n",
 		hw->utmi_phy_data_width);
 	dev_dbg(hsotg->dev, "  num_dev_ep=%d\n",
 		hw->num_dev_ep);
@@ -3293,3 +3521,40 @@ void dwc2_disable_global_interrupts(stru
 	ahbcfg &= ~GAHBCFG_GLBL_INTR_EN;
 	DWC2_WRITE_4(hsotg, GAHBCFG, ahbcfg);
 }
+
+/* Returns the controller's GHWCFG2.OTG_MODE. */
+unsigned dwc2_op_mode(struct dwc2_hsotg *hsotg)
+{
+	u32 ghwcfg2 = DWC2_READ_4(hsotg, GHWCFG2);
+
+	return (ghwcfg2 & GHWCFG2_OP_MODE_MASK) >>
+		GHWCFG2_OP_MODE_SHIFT;
+}
+
+/* Returns true if the controller is capable of DRD. */
+bool dwc2_hw_is_otg(struct dwc2_hsotg *hsotg)
+{
+	unsigned op_mode = dwc2_op_mode(hsotg);
+
+	return (op_mode == GHWCFG2_OP_MODE_HNP_SRP_CAPABLE) ||
+		(op_mode == GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE) ||
+		(op_mode == GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE);
+}
+
+/* Returns true if the controller is host-only. */
+bool dwc2_hw_is_host(struct dwc2_hsotg *hsotg)
+{
+	unsigned op_mode = dwc2_op_mode(hsotg);
+
+	return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_HOST) ||
+		(op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST);
+}
+
+/* Returns true if the controller is device-only. */
+bool dwc2_hw_is_device(struct dwc2_hsotg *hsotg)
+{
+	unsigned op_mode = dwc2_op_mode(hsotg);
+
+	return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) ||
+		(op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE);
+}

Index: src/sys/external/bsd/dwc2/dist/dwc2_core.h
diff -u src/sys/external/bsd/dwc2/dist/dwc2_core.h:1.6 src/sys/external/bsd/dwc2/dist/dwc2_core.h:1.7
--- src/sys/external/bsd/dwc2/dist/dwc2_core.h:1.6	Sun Aug 30 12:59:59 2015
+++ src/sys/external/bsd/dwc2/dist/dwc2_core.h	Sun Feb 14 10:53:30 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: dwc2_core.h,v 1.6 2015/08/30 12:59:59 skrll Exp $	*/
+/*	$NetBSD: dwc2_core.h,v 1.7 2016/02/14 10:53:30 skrll Exp $	*/
 
 /*
  * core.h - DesignWare HS OTG Controller common declarations
@@ -55,8 +55,8 @@
 
 #if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
 
-/* s3c-hsotg declarations */
-static const char * const s3c_hsotg_supply_names[] = {
+/* dwc2-hsotg declarations */
+static const char * const dwc2_hsotg_supply_names[] = {
 	"vusb_d",               /* digital USB supply, 1.2V */
 	"vusb_a",               /* analog USB supply, 1.1V */
 };
@@ -82,10 +82,10 @@ static const char * const s3c_hsotg_supp
 #define EP0_MPS_LIMIT   64
 
 struct dwc2_hsotg;
-struct s3c_hsotg_req;
+struct dwc2_hsotg_req;
 
 /**
- * struct s3c_hsotg_ep - driver endpoint definition.
+ * struct dwc2_hsotg_ep - driver endpoint definition.
  * @ep: The gadget layer representation of the endpoint.
  * @name: The driver generated name for the endpoint.
  * @queue: Queue of requests for this endpoint.
@@ -124,11 +124,11 @@ struct s3c_hsotg_req;
  * as in shared-fifo mode periodic in acts like a single-frame packet
  * buffer than a fifo)
  */
-struct s3c_hsotg_ep {
+struct dwc2_hsotg_ep {
 	struct usb_ep           ep;
 	struct list_head        queue;
 	struct dwc2_hsotg       *parent;
-	struct s3c_hsotg_req    *req;
+	struct dwc2_hsotg_req    *req;
 	struct dentry           *debugfs;
 
 	unsigned long           total_data;
@@ -147,17 +147,18 @@ struct s3c_hsotg_ep {
 	unsigned int            periodic:1;
 	unsigned int            isochronous:1;
 	unsigned int            send_zlp:1;
+	unsigned int            has_correct_parity:1;
 
 	char                    name[10];
 };
 
 /**
- * struct s3c_hsotg_req - data transfer request
+ * struct dwc2_hsotg_req - data transfer request
  * @req: The USB gadget request
  * @queue: The list of requests for the endpoint this is queued for.
  * @saved_req_buf: variable to save req.buf when bounce buffers are used.
  */
-struct s3c_hsotg_req {
+struct dwc2_hsotg_req {
 	struct usb_request      req;
 	struct list_head        queue;
 	void *saved_req_buf;
@@ -225,6 +226,13 @@ enum dwc2_ep0_state {
  *                      value for this if none is specified.
  *                       0 - Address DMA
  *                       1 - Descriptor DMA (default, if available)
+ * @dma_desc_fs_enable: When DMA mode is enabled, specifies whether to use
+ *                      address DMA mode or descriptor DMA mode for accessing
+ *                      the data FIFOs in Full Speed mode only. The driver
+ *                      will automatically detect the value for this if none is
+ *                      specified.
+ *                       0 - Address DMA
+ *                       1 - Descriptor DMA in FS (default, if available)
  * @speed:              Specifies the maximum speed of operation in host and
  *                      device mode. The actual speed depends on the speed of
  *                      the attached device and the value of phy_type.
@@ -354,6 +362,7 @@ struct dwc2_core_params {
 	int otg_ver;
 	int dma_enable;
 	int dma_desc_enable;
+	int dma_desc_fs_enable;
 	int speed;
 	int enable_dynamic_fifo;
 	int en_multiple_tx_fifo;
@@ -430,15 +439,18 @@ struct dwc2_core_params {
  *                       1 - 16 bits
  *                       2 - 8 or 16 bits
  * @snpsid:             Value from SNPSID register
+ * @dev_ep_dirs:        Direction of device endpoints (GHWCFG1)
  */
 struct dwc2_hw_params {
 	unsigned op_mode:3;
 	unsigned arch:2;
 	unsigned dma_desc_enable:1;
+	unsigned dma_desc_fs_enable:1;
 	unsigned enable_dynamic_fifo:1;
 	unsigned en_multiple_tx_fifo:1;
 	unsigned host_rx_fifo_size:16;
 	unsigned host_nperio_tx_fifo_size:16;
+	unsigned dev_nperio_tx_fifo_size:16;
 	unsigned host_perio_tx_fifo_size:16;
 	unsigned nperio_tx_q_depth:3;
 	unsigned host_perio_tx_q_depth:3;
@@ -455,6 +467,7 @@ struct dwc2_hw_params {
 	unsigned power_optimized:1;
 	unsigned utmi_phy_data_width:2;
 	u32 snpsid;
+	u32 dev_ep_dirs;
 };
 
 /* Size of control and EP0 buffers */
@@ -558,6 +571,15 @@ struct dwc2_hregs_backup {
  *                      - USB_DR_MODE_PERIPHERAL
  *                      - USB_DR_MODE_HOST
  *                      - USB_DR_MODE_OTG
+ * @hcd_enabled		Host mode sub-driver initialization indicator.
+ * @gadget_enabled	Peripheral mode sub-driver initialization indicator.
+ * @ll_hw_enabled	Status of low-level hardware resources.
+ * @phy:                The otg phy transceiver structure for phy control.
+ * @uphy:               The otg phy transceiver structure for old USB phy control.
+ * @plat:               The platform specific configuration data. This can be removed once
+ *                      all SoCs support usb transceiver.
+ * @supplies:           Definition of USB power supplies
+ * @phyif:              PHY interface width
  * @lock:		Spinlock that protects all the driver data structures
  * @priv:		Stores a pointer to the struct usb_hcd
  * @queuing_high_bandwidth: True if multiple packets of a high-bandwidth
@@ -646,16 +668,13 @@ struct dwc2_hregs_backup {
  * @otg_port:           OTG port number
  * @frame_list:         Frame list
  * @frame_list_dma:     Frame list DMA address
+ * @frame_list_sz:      Frame list size
+ * @desc_gen_cache:     Kmem cache for generic descriptors
+ * @desc_hsisoc_cache:  Kmem cache for hs isochronous descriptors
  *
  * These are for peripheral mode:
  *
  * @driver:             USB gadget driver
- * @phy:                The otg phy transceiver structure for phy control.
- * @uphy:               The otg phy transceiver structure for old USB phy control.
- * @plat:               The platform specific configuration data. This can be removed once
- *                      all SoCs support usb transceiver.
- * @supplies:           Definition of USB power supplies
- * @phyif:              PHY interface width
  * @dedicated_fifos:    Set if the hardware has dedicated IN-EP fifos.
  * @num_of_eps:         Number of available EPs (excluding EP0)
  * @debug_root:         Root directrory for debugfs.
@@ -668,7 +687,6 @@ struct dwc2_hregs_backup {
  * @ctrl_req:           Request for EP0 control packets.
  * @ep0_state:          EP0 control transfers state
  * @test_mode:          USB test mode requested by the host
- * @last_rst:           Time of last reset
  * @eps:                The endpoints being supplied to the gadget framework
  * @g_using_dma:          Indicate if dma usage is enabled
  * @g_rx_fifo_sz:         Contains rx fifo size value
@@ -686,15 +704,18 @@ struct dwc2_hsotg {
 	enum usb_dr_mode dr_mode;
 	unsigned int hcd_enabled:1;
 	unsigned int gadget_enabled:1;
+	unsigned int ll_hw_enabled:1;
 
 	spinlock_t lock;
 	void *priv;
 	struct usb_phy *uphy;
 #if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
 	struct phy *phy;
-	struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsotg_supply_names)];
+	struct usb_phy *uphy;
+	struct dwc2_hsotg_plat *plat;
+	struct regulator_bulk_data supplies[ARRAY_SIZE(dwc2_hsotg_supply_names)];
+	u32 phyif;
 
-	struct mutex init_mutex;
 	int     irq;
 	struct clk *clk;
 #endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */
@@ -746,6 +767,8 @@ struct dwc2_hsotg {
 	u16 frame_usecs[8];
 	u16 frame_number;
 	u16 periodic_qh_count;
+	bool bus_suspended;
+	bool new_connection;
 
 #ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
 #define FRAME_NUM_ARRAY_SIZE 1000
@@ -772,6 +795,9 @@ struct dwc2_hsotg {
 	usb_dma_t frame_list_usbdma;
 	u32 *frame_list;
 	dma_addr_t frame_list_dma;
+	u32 frame_list_sz;
+	struct kmem_cache *desc_gen_cache;
+	struct kmem_cache *desc_hsisoc_cache;
 
 #ifdef DEBUG
 	u32 frrem_samples;
@@ -796,9 +822,6 @@ struct dwc2_hsotg {
 #if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
 	/* Gadget structures */
 	struct usb_gadget_driver *driver;
-	struct s3c_hsotg_plat *plat;
-
-	u32 phyif;
 	int fifo_mem;
 	unsigned int dedicated_fifos:1;
 	unsigned char num_of_eps;
@@ -814,9 +837,8 @@ struct dwc2_hsotg {
 	struct usb_gadget gadget;
 	unsigned int enabled:1;
 	unsigned int connected:1;
-	unsigned long last_rst;
-	struct s3c_hsotg_ep *eps_in[MAX_EPS_CHANNELS];
-	struct s3c_hsotg_ep *eps_out[MAX_EPS_CHANNELS];
+	struct dwc2_hsotg_ep *eps_in[MAX_EPS_CHANNELS];
+	struct dwc2_hsotg_ep *eps_out[MAX_EPS_CHANNELS];
 	u32 g_using_dma;
 	u32 g_rx_fifo_sz;
 	u32 g_np_g_tx_fifo_sz;
@@ -846,10 +868,14 @@ enum dwc2_halt_status {
  * The following functions support initialization of the core driver component
  * and the DWC_otg controller
  */
+extern int dwc2_core_reset(struct dwc2_hsotg *hsotg);
+extern int dwc2_core_reset_and_force_dr_mode(struct dwc2_hsotg *hsotg);
 extern void dwc2_core_host_init(struct dwc2_hsotg *hsotg);
 extern int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg);
 extern int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore);
 
+void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg);
+
 /*
  * Host core Functions.
  * The following functions support managing the DWC_otg controller in host
@@ -883,7 +909,7 @@ extern void dwc2_read_packet(struct dwc2
 extern void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num);
 extern void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg);
 
-extern int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy);
+extern int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup);
 extern void dwc2_enable_global_interrupts(struct dwc2_hsotg *hcd);
 extern void dwc2_disable_global_interrupts(struct dwc2_hsotg *hcd);
 
@@ -924,6 +950,16 @@ extern void dwc2_set_param_dma_enable(st
 extern void dwc2_set_param_dma_desc_enable(struct dwc2_hsotg *hsotg, int val);
 
 /*
+ * When DMA mode is enabled specifies whether to use
+ * address DMA or DMA Descritor mode with full speed devices
+ * for accessing the data FIFOs in host mode.
+ * 0 - address DMA
+ * 1 - FS DMA Descriptor(default, if available)
+ */
+extern void dwc2_set_param_dma_desc_fs_enable(struct dwc2_hsotg *hsotg,
+					      int val);
+
+/*
  * Specifies the maximum speed of operation in host and device mode.
  * The actual speed depends on the speed of the attached device and
  * the value of phy_type. The actual speed depends on the speed of the
@@ -1088,7 +1124,34 @@ extern void dwc2_set_all_params(struct d
 
 extern int dwc2_get_hwparams(struct dwc2_hsotg *hsotg);
 
+extern int dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg);
+extern int dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg);
+
+/*
+ * The following functions check the controller's OTG operation mode
+ * capability (GHWCFG2.OTG_MODE).
+ *
+ * These functions can be used before the internal hsotg->hw_params
+ * are read in and cached so they always read directly from the
+ * GHWCFG2 register.
+ */
+unsigned dwc2_op_mode(struct dwc2_hsotg *hsotg);
+bool dwc2_hw_is_otg(struct dwc2_hsotg *hsotg);
+bool dwc2_hw_is_host(struct dwc2_hsotg *hsotg);
+bool dwc2_hw_is_device(struct dwc2_hsotg *hsotg);
+
+/*
+ * Returns the mode of operation, host or device
+ */
+static inline int dwc2_is_host_mode(struct dwc2_hsotg *hsotg)
+{
+	return (DWC2_READ_4(hsotg, GINTSTS) & GINTSTS_CURMODE_HOST) != 0;
+}
 
+static inline int dwc2_is_device_mode(struct dwc2_hsotg *hsotg)
+{
+	return (DWC2_READ_4(hsotg, GINTSTS) & GINTSTS_CURMODE_HOST) == 0;
+}
 
 /*
  * Dump core registers and SPRAM
@@ -1104,30 +1167,30 @@ extern u16 dwc2_get_otg_version(struct d
 
 /* Gadget defines */
 #if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
-extern int s3c_hsotg_remove(struct dwc2_hsotg *hsotg);
-extern int s3c_hsotg_suspend(struct dwc2_hsotg *dwc2);
-extern int s3c_hsotg_resume(struct dwc2_hsotg *dwc2);
+extern int dwc2_hsotg_remove(struct dwc2_hsotg *hsotg);
+extern int dwc2_hsotg_suspend(struct dwc2_hsotg *dwc2);
+extern int dwc2_hsotg_resume(struct dwc2_hsotg *dwc2);
 extern int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq);
-extern void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
+extern void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
 		bool reset);
-extern void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg);
-extern void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2);
-extern int s3c_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode);
+extern void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg);
+extern void dwc2_hsotg_disconnect(struct dwc2_hsotg *dwc2);
+extern int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode);
 #define dwc2_is_device_connected(hsotg) (hsotg->connected)
 #else
-static inline int s3c_hsotg_remove(struct dwc2_hsotg *dwc2)
+static inline int dwc2_hsotg_remove(struct dwc2_hsotg *dwc2)
 { return 0; }
-static inline int s3c_hsotg_suspend(struct dwc2_hsotg *dwc2)
+static inline int dwc2_hsotg_suspend(struct dwc2_hsotg *dwc2)
 { return 0; }
-static inline int s3c_hsotg_resume(struct dwc2_hsotg *dwc2)
+static inline int dwc2_hsotg_resume(struct dwc2_hsotg *dwc2)
 { return 0; }
 static inline int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
 { return 0; }
-static inline void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
+static inline void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
 		bool reset) {}
-static inline void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg) {}
-static inline void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2) {}
-static inline int s3c_hsotg_set_test_mode(struct dwc2_hsotg *hsotg,
+static inline void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg) {}
+static inline void dwc2_hsotg_disconnect(struct dwc2_hsotg *dwc2) {}
+static inline int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg,
 							int testmode)
 { return 0; }
 #define dwc2_is_device_connected(hsotg) (0)
@@ -1135,12 +1198,14 @@ static inline int s3c_hsotg_set_test_mod
 
 #if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
 extern int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg);
-extern void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg);
+extern void dwc2_hcd_connect(struct dwc2_hsotg *hsotg);
+extern void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force);
 extern void dwc2_hcd_start(struct dwc2_hsotg *hsotg);
 #else
 static inline int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg)
 { return 0; }
-static inline void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg) {}
+static inline void dwc2_hcd_connect(struct dwc2_hsotg *hsotg) {}
+static inline void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force) {}
 static inline void dwc2_hcd_start(struct dwc2_hsotg *hsotg) {}
 static inline void dwc2_hcd_remove(struct dwc2_hsotg *hsotg) {}
 static inline int dwc2_hcd_init(struct dwc2_hsotg *hsotg)
Index: src/sys/external/bsd/dwc2/dist/dwc2_hcdddma.c
diff -u src/sys/external/bsd/dwc2/dist/dwc2_hcdddma.c:1.6 src/sys/external/bsd/dwc2/dist/dwc2_hcdddma.c:1.7
--- src/sys/external/bsd/dwc2/dist/dwc2_hcdddma.c:1.6	Thu Apr  3 06:34:58 2014
+++ src/sys/external/bsd/dwc2/dist/dwc2_hcdddma.c	Sun Feb 14 10:53:30 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: dwc2_hcdddma.c,v 1.6 2014/04/03 06:34:58 skrll Exp $	*/
+/*	$NetBSD: dwc2_hcdddma.c,v 1.7 2016/02/14 10:53:30 skrll Exp $	*/
 
 /*
  * hcd_ddma.c - DesignWare HS OTG Controller descriptor DMA routines
@@ -40,7 +40,7 @@
  * This file contains the Descriptor DMA implementation for Host mode
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dwc2_hcdddma.c,v 1.6 2014/04/03 06:34:58 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dwc2_hcdddma.c,v 1.7 2016/02/14 10:53:30 skrll Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -102,20 +102,17 @@ static int dwc2_desc_list_alloc(struct d
 	KASSERT(!cpu_intr_p() && !cpu_softintr_p());
 
 	qh->desc_list = NULL;
-	err = usb_allocmem(&hsotg->hsotg_sc->sc_bus,
-	    sizeof(struct dwc2_hcd_dma_desc) * dwc2_max_desc_num(qh), 0,
-	    &qh->desc_list_usbdma);
+	qh->desc_list_sz = sizeof(struct dwc2_hcd_dma_desc) *
+						dwc2_max_desc_num(qh);
 
-	if (!err) {
-		qh->desc_list = KERNADDR(&qh->desc_list_usbdma, 0);
-		qh->desc_list_dma = DMAADDR(&qh->desc_list_usbdma, 0);
-	}
+	err = usb_allocmem(&hsotg->hsotg_sc->sc_bus, qh->desc_list_sz, 0,
+	    &qh->desc_list_usbdma);
 
-	if (!qh->desc_list)
+	if (err)
 		return -ENOMEM;
 
-	memset(qh->desc_list, 0,
-	       sizeof(struct dwc2_hcd_dma_desc) * dwc2_max_desc_num(qh));
+	qh->desc_list = KERNADDR(&qh->desc_list_usbdma, 0);
+	qh->desc_list_dma = DMAADDR(&qh->desc_list_usbdma, 0);
 
 	qh->n_bytes = kmem_zalloc(sizeof(u32) * dwc2_max_desc_num(qh), KM_SLEEP);
 	if (!qh->n_bytes) {
@@ -129,6 +126,7 @@ static int dwc2_desc_list_alloc(struct d
 
 static void dwc2_desc_list_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
 {
+
 	if (qh->desc_list) {
 		usb_freemem(&hsotg->hsotg_sc->sc_bus, &qh->desc_list_usbdma);
 		qh->desc_list = NULL;
@@ -146,8 +144,9 @@ static int dwc2_frame_list_alloc(struct 
 		return 0;
 
 	/* XXXNH - pool_cache_t */
+	hsotg->frame_list_sz = 4 * FRLISTEN_64_SIZE;
 	hsotg->frame_list = NULL;
-	err = usb_allocmem(&hsotg->hsotg_sc->sc_bus, 4 * FRLISTEN_64_SIZE,
+	err = usb_allocmem(&hsotg->hsotg_sc->sc_bus, hsotg->frame_list_sz,
 	    0, &hsotg->frame_list_usbdma);
 
 	if (!err) {
@@ -158,7 +157,6 @@ static int dwc2_frame_list_alloc(struct 
 	if (!hsotg->frame_list)
 		return -ENOMEM;
 
-	memset(hsotg->frame_list, 0, 4 * FRLISTEN_64_SIZE);
 	return 0;
 }
 
@@ -269,6 +267,13 @@ static void dwc2_update_frame_list(struc
 		j = (j + inc) & (FRLISTEN_64_SIZE - 1);
 	} while (j != i);
 
+	/*
+	 * Sync frame list since controller will access it if periodic
+	 * channel is currently enabled.
+	 */
+	usb_syncmem(&hsotg->frame_list_usbdma, 0, hsotg->frame_list_sz,
+	    BUS_DMASYNC_PREWRITE);
+
 	if (!enable)
 		return;
 
@@ -298,6 +303,7 @@ static void dwc2_release_channel_ddma(st
 			hsotg->non_periodic_channels--;
 	} else {
 		dwc2_update_frame_list(hsotg, qh, 0);
+		hsotg->available_host_channels++;
 	}
 
 	/*
@@ -380,6 +386,8 @@ err0:
  */
 void dwc2_hcd_qh_free_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
 {
+	unsigned long flags;
+
 	dwc2_desc_list_free(hsotg, qh);
 
 	/*
@@ -389,8 +397,10 @@ void dwc2_hcd_qh_free_ddma(struct dwc2_h
 	 * when it comes here from endpoint disable routine
 	 * channel remains assigned.
 	 */
+	spin_lock_irqsave(&hsotg->lock, flags);
 	if (qh->channel)
 		dwc2_release_channel_ddma(hsotg, qh);
+	spin_unlock_irqrestore(&hsotg->lock, flags);
 
 	if ((qh->ep_type == USB_ENDPOINT_XFER_ISOC ||
 	     qh->ep_type == USB_ENDPOINT_XFER_INT) &&
@@ -544,14 +554,22 @@ static void dwc2_fill_host_isoc_dma_desc
 	dma_desc->status = qh->n_bytes[idx] << HOST_DMA_ISOC_NBYTES_SHIFT &
 			   HOST_DMA_ISOC_NBYTES_MASK;
 
+	/* Set active bit */
+	dma_desc->status |= HOST_DMA_A;
+
+	qh->ntd++;
+	qtd->isoc_frame_index_last++;
+
 #ifdef ISOC_URB_GIVEBACK_ASAP
 	/* Set IOC for each descriptor corresponding to last frame of URB */
 	if (qtd->isoc_frame_index_last == qtd->urb->packet_count)
 		dma_desc->status |= HOST_DMA_IOC;
 #endif
 
-	qh->ntd++;
-	qtd->isoc_frame_index_last++;
+	usb_syncmem(&qh->desc_list_usbdma, 
+	    (idx * sizeof(struct dwc2_hcd_dma_desc)),
+	    sizeof(struct dwc2_hcd_dma_desc),
+	    BUS_DMASYNC_PREWRITE);
 }
 
 static void dwc2_init_isoc_dma_desc(struct dwc2_hsotg *hsotg,
@@ -559,11 +577,32 @@ static void dwc2_init_isoc_dma_desc(stru
 {
 	struct dwc2_qtd *qtd;
 	u32 max_xfer_size;
-	u16 idx, inc, n_desc, ntd_max = 0;
+	u16 idx, inc, n_desc = 0, ntd_max = 0;
+	u16 cur_idx;
+	u16 next_idx;
 
 	idx = qh->td_last;
 	inc = qh->interval;
-	n_desc = 0;
+	hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg);
+	cur_idx = dwc2_frame_list_idx(hsotg->frame_number);
+	next_idx = dwc2_desclist_idx_inc(qh->td_last, inc, qh->dev_speed);
+
+	/*
+	 * Ensure current frame number didn't overstep last scheduled
+	 * descriptor. If it happens, the only way to recover is to move
+	 * qh->td_last to current frame number + 1.
+	 * So that next isoc descriptor will be scheduled on frame number + 1
+	 * and not on a past frame.
+	 */
+	if (dwc2_frame_idx_num_gt(cur_idx, next_idx) || (cur_idx == next_idx)) {
+		if (inc < 32) {
+			dev_vdbg(hsotg->dev,
+				 "current frame number overstep last descriptor\n");
+			qh->td_last = dwc2_desclist_idx_inc(cur_idx, inc,
+							    qh->dev_speed);
+			idx = qh->td_last;
+		}
+	}
 
 	if (qh->interval) {
 		ntd_max = (dwc2_max_desc_num(qh) + qh->interval - 1) /
@@ -576,15 +615,20 @@ static void dwc2_init_isoc_dma_desc(stru
 			MAX_ISOC_XFER_SIZE_HS : MAX_ISOC_XFER_SIZE_FS;
 
 	list_for_each_entry(qtd, &qh->qtd_list, qtd_list_entry) {
+		if (qtd->in_process &&
+		    qtd->isoc_frame_index_last ==
+		    qtd->urb->packet_count)
+			continue;
+
+		qtd->isoc_td_first = idx;
 		while (qh->ntd < ntd_max && qtd->isoc_frame_index_last <
 						qtd->urb->packet_count) {
-			if (n_desc > 1)
-				qh->desc_list[n_desc - 1].status |= HOST_DMA_A;
 			dwc2_fill_host_isoc_dma_desc(hsotg, qtd, qh,
 						     max_xfer_size, idx);
 			idx = dwc2_desclist_idx_inc(idx, inc, qh->dev_speed);
 			n_desc++;
 		}
+		qtd->isoc_td_last = idx;
 		qtd->in_process = 1;
 	}
 
@@ -595,6 +639,11 @@ static void dwc2_init_isoc_dma_desc(stru
 	if (qh->ntd == ntd_max) {
 		idx = dwc2_desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
 		qh->desc_list[idx].status |= HOST_DMA_IOC;
+
+		usb_syncmem(&qh->desc_list_usbdma, 
+		    (idx * sizeof(struct dwc2_hcd_dma_desc)),
+		    sizeof(struct dwc2_hcd_dma_desc),
+		    BUS_DMASYNC_PREWRITE);
 	}
 #else
 	/*
@@ -624,13 +673,11 @@ static void dwc2_init_isoc_dma_desc(stru
 		idx = dwc2_desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
 
 	qh->desc_list[idx].status |= HOST_DMA_IOC;
+	usb_syncmem(&qh->desc_list_usbdma, 
+	    (idx * sizeof(struct dwc2_hcd_dma_desc)),
+	    sizeof(struct dwc2_hcd_dma_desc),
+	    BUS_DMASYNC_PREWRITE);
 #endif
-
-	if (n_desc) {
-		qh->desc_list[n_desc - 1].status |= HOST_DMA_A;
-		if (n_desc > 1)
-			qh->desc_list[0].status |= HOST_DMA_A;
-	}
 }
 
 static void dwc2_fill_host_dma_desc(struct dwc2_hsotg *hsotg,
@@ -667,6 +714,11 @@ static void dwc2_fill_host_dma_desc(stru
 
 	dma_desc->buf = (u32)chan->xfer_dma;
 
+	usb_syncmem(&qh->desc_list_usbdma, 
+	    (n_desc * sizeof(struct dwc2_hcd_dma_desc)),
+	    sizeof(struct dwc2_hcd_dma_desc),
+	    BUS_DMASYNC_PREWRITE);
+
 	/*
 	 * Last (or only) descriptor of IN transfer with actual size less
 	 * than MaxPacket
@@ -717,6 +769,11 @@ static void dwc2_init_non_isoc_dma_desc(
 					 "set A bit in desc %d (%p)\n",
 					 n_desc - 1,
 					 &qh->desc_list[n_desc - 1]);
+				usb_syncmem(&qh->desc_list_usbdma, 
+				    ((n_desc - 1) *
+				    sizeof(struct dwc2_hcd_dma_desc)),
+				    sizeof(struct dwc2_hcd_dma_desc),
+				    BUS_DMASYNC_PREWRITE);
 			}
 			dwc2_fill_host_dma_desc(hsotg, chan, qtd, qh, n_desc);
 			dev_vdbg(hsotg->dev,
@@ -742,10 +799,17 @@ static void dwc2_init_non_isoc_dma_desc(
 				HOST_DMA_IOC | HOST_DMA_EOL | HOST_DMA_A;
 		dev_vdbg(hsotg->dev, "set IOC/EOL/A bits in desc %d (%p)\n",
 			 n_desc - 1, &qh->desc_list[n_desc - 1]);
+		usb_syncmem(&qh->desc_list_usbdma, 
+		    ((n_desc - 1) * sizeof(struct dwc2_hcd_dma_desc)),
+		    sizeof(struct dwc2_hcd_dma_desc),
+		    BUS_DMASYNC_PREWRITE);
 		if (n_desc > 1) {
 			qh->desc_list[0].status |= HOST_DMA_A;
 			dev_vdbg(hsotg->dev, "set A bit in desc 0 (%p)\n",
 				 &qh->desc_list[0]);
+			usb_syncmem(&qh->desc_list_usbdma, 0,
+			    sizeof(struct dwc2_hcd_dma_desc),
+			    BUS_DMASYNC_PREWRITE);
 		}
 		chan->ntd = n_desc;
 	}
@@ -820,7 +884,7 @@ static int dwc2_cmpl_host_isoc_dma_desc(
 					struct dwc2_qtd *qtd,
 					struct dwc2_qh *qh, u16 idx)
 {
-	struct dwc2_hcd_dma_desc *dma_desc = &qh->desc_list[idx];
+	struct dwc2_hcd_dma_desc *dma_desc;
 	struct dwc2_hcd_iso_packet_desc *frame_desc;
 	u16 remain = 0;
 	int rc = 0;
@@ -828,6 +892,13 @@ static int dwc2_cmpl_host_isoc_dma_desc(
 	if (!qtd->urb)
 		return -EINVAL;
 
+	usb_syncmem(&qh->desc_list_usbdma,
+	    (idx * sizeof(struct dwc2_hcd_dma_desc)),
+	    sizeof(struct dwc2_hcd_dma_desc),
+	    BUS_DMASYNC_POSTREAD);
+	
+	dma_desc = &qh->desc_list[idx];
+
 	frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last];
 	dma_desc->buf = (u32)(DMAADDR(qtd->urb->usbdma, frame_desc->offset));
 	if (chan->ep_is_in)
@@ -931,17 +1002,51 @@ static void dwc2_complete_isoc_xfer_ddma
 	list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
 		if (!qtd->in_process)
 			break;
+
+		/*
+		 * Ensure idx corresponds to descriptor where first urb of this
+		 * qtd was added. In fact, during isoc desc init, dwc2 may skip
+		 * an index if current frame number is already over this index.
+		 */
+		if (idx != qtd->isoc_td_first) {
+			dev_vdbg(hsotg->dev,
+				 "try to complete %d instead of %d\n",
+				 idx, qtd->isoc_td_first);
+			idx = qtd->isoc_td_first;
+		}
+
 		do {
+			struct dwc2_qtd *qtd_next;
+			u16 cur_idx;
+
 			rc = dwc2_cmpl_host_isoc_dma_desc(hsotg, chan, qtd, qh,
 							  idx);
 			if (rc < 0)
 				return;
 			idx = dwc2_desclist_idx_inc(idx, qh->interval,
 						    chan->speed);
-			if (rc == DWC2_CMPL_STOP)
-				goto stop_scan;
+			if (!rc)
+				continue;
+
 			if (rc == DWC2_CMPL_DONE)
 				break;
+
+			/* rc == DWC2_CMPL_STOP */
+
+			if (qh->interval >= 32)
+				goto stop_scan;
+
+			qh->td_first = idx;
+			cur_idx = dwc2_frame_list_idx(hsotg->frame_number);
+			qtd_next = list_first_entry(&qh->qtd_list,
+						    struct dwc2_qtd,
+						    qtd_list_entry);
+			if (dwc2_frame_idx_num_gt(cur_idx,
+						  qtd_next->isoc_td_last))
+				break;
+
+			goto stop_scan;
+
 		} while (idx != qh->td_first);
 	}
 
@@ -1049,6 +1154,11 @@ static int dwc2_process_non_isoc_desc(st
 	if (!urb)
 		return -EINVAL;
 
+	usb_syncmem(&qh->desc_list_usbdma, 
+	    (desc_num * sizeof(struct dwc2_hcd_dma_desc)),
+	    sizeof(struct dwc2_hcd_dma_desc),
+	    BUS_DMASYNC_POSTREAD);
+
 	dma_desc = &qh->desc_list[desc_num];
 	n_bytes = qh->n_bytes[desc_num];
 	dev_vdbg(hsotg->dev,
@@ -1057,7 +1167,10 @@ static int dwc2_process_non_isoc_desc(st
 	failed = dwc2_update_non_isoc_urb_state_ddma(hsotg, chan, qtd, dma_desc,
 						     halt_status, n_bytes,
 						     xfer_done);
-	if (failed || (*xfer_done && urb->status != -EINPROGRESS)) {
+	if (*xfer_done && urb->status != -EINPROGRESS)
+		failed = 1;
+
+	if (failed) {
 		dwc2_host_complete(hsotg, qtd, urb->status);
 		dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
 		dev_vdbg(hsotg->dev, "failed=%1x xfer_done=%1x status=%08x\n",
@@ -1185,6 +1298,21 @@ void dwc2_hcd_complete_xfer_ddma(struct 
 		/* Release the channel if halted or session completed */
 		if (halt_status != DWC2_HC_XFER_COMPLETE ||
 		    list_empty(&qh->qtd_list)) {
+			struct dwc2_qtd *qtd, *qtd_tmp;
+
+			/*
+			 * Kill all remainings QTDs since channel has been
+			 * halted.
+			 */
+			list_for_each_entry_safe(qtd, qtd_tmp,
+						 &qh->qtd_list,
+						 qtd_list_entry) {
+				dwc2_host_complete(hsotg, qtd,
+						   -ECONNRESET);
+				dwc2_hcd_qtd_unlink_and_free(hsotg,
+							     qtd, qh);
+			}
+
 			/* Halt the channel if session completed */
 			if (halt_status == DWC2_HC_XFER_COMPLETE)
 				dwc2_hc_halt(hsotg, chan, halt_status);
@@ -1194,7 +1322,12 @@ void dwc2_hcd_complete_xfer_ddma(struct 
 			/* Keep in assigned schedule to continue transfer */
 			list_move(&qh->qh_list_entry,
 				  &hsotg->periodic_sched_assigned);
-			continue_isoc_xfer = 1;
+			/*
+			 * If channel has been halted during giveback of urb
+			 * then prevent any new scheduling.
+			 */
+			if (!chan->halt_status)
+				continue_isoc_xfer = 1;
 		}
 		/*
 		 * Todo: Consider the case when period exceeds FrameList size.

Index: src/sys/external/bsd/dwc2/dist/dwc2_coreintr.c
diff -u src/sys/external/bsd/dwc2/dist/dwc2_coreintr.c:1.9 src/sys/external/bsd/dwc2/dist/dwc2_coreintr.c:1.10
--- src/sys/external/bsd/dwc2/dist/dwc2_coreintr.c:1.9	Sun Aug 30 12:59:59 2015
+++ src/sys/external/bsd/dwc2/dist/dwc2_coreintr.c	Sun Feb 14 10:53:30 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: dwc2_coreintr.c,v 1.9 2015/08/30 12:59:59 skrll Exp $	*/
+/*	$NetBSD: dwc2_coreintr.c,v 1.10 2016/02/14 10:53:30 skrll Exp $	*/
 
 /*
  * core_intr.c - DesignWare HS OTG Controller common interrupt handling
@@ -41,7 +41,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dwc2_coreintr.c,v 1.9 2015/08/30 12:59:59 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dwc2_coreintr.c,v 1.10 2016/02/14 10:53:30 skrll Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -100,9 +100,6 @@ static void dwc2_handle_usb_port_intr(st
 		hprt0 &= ~HPRT0_ENA;
 		DWC2_WRITE_4(hsotg, HPRT0, hprt0);
 	}
-
-	/* Clear interrupt */
-	DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_PRTINT);
 }
 
 /**
@@ -112,11 +109,11 @@ static void dwc2_handle_usb_port_intr(st
  */
 static void dwc2_handle_mode_mismatch_intr(struct dwc2_hsotg *hsotg)
 {
-	dev_warn(hsotg->dev, "Mode Mismatch Interrupt: currently in %s mode\n",
-		 dwc2_is_host_mode(hsotg) ? "Host" : "Device");
-
 	/* Clear interrupt */
 	DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_MODEMIS);
+
+	dev_warn(hsotg->dev, "Mode Mismatch Interrupt: currently in %s mode\n",
+		 dwc2_is_host_mode(hsotg) ? "Host" : "Device");
 }
 
 /**
@@ -143,7 +140,7 @@ static void dwc2_handle_otg_intr(struct 
 		gotgctl = DWC2_READ_4(hsotg, GOTGCTL);
 
 		if (dwc2_is_device_mode(hsotg))
-			s3c_hsotg_disconnect(hsotg);
+			dwc2_hsotg_disconnect(hsotg);
 
 		if (hsotg->op_state == OTG_STATE_B_HOST) {
 			hsotg->op_state = OTG_STATE_B_PERIPHERAL;
@@ -253,7 +250,7 @@ static void dwc2_handle_otg_intr(struct 
 			dev_dbg(hsotg->dev, "a_suspend->a_peripheral (%d)\n",
 				hsotg->op_state);
 			spin_unlock(&hsotg->lock);
-			dwc2_hcd_disconnect(hsotg);
+			dwc2_hcd_disconnect(hsotg, false);
 			spin_lock(&hsotg->lock);
 			hsotg->op_state = OTG_STATE_A_PERIPHERAL;
 		} else {
@@ -290,9 +287,13 @@ static void dwc2_handle_otg_intr(struct 
  */
 static void dwc2_handle_conn_id_status_change_intr(struct dwc2_hsotg *hsotg)
 {
-	u32 gintmsk = DWC2_READ_4(hsotg, GINTMSK);
+	u32 gintmsk;
+
+	/* Clear interrupt */
+	DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_CONIDSTSCHNG);
 
 	/* Need to disable SOF interrupt immediately */
+	gintmsk = DWC2_READ_4(hsotg, GINTMSK);
 	gintmsk &= ~GINTSTS_SOF;
 	DWC2_WRITE_4(hsotg, GINTMSK, gintmsk);
 
@@ -309,9 +310,6 @@ static void dwc2_handle_conn_id_status_c
 		workqueue_enqueue(hsotg->wq_otg, &hsotg->wf_otg, NULL);
 		spin_lock(&hsotg->lock);
 	}
-
-	/* Clear interrupt */
-	DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_CONIDSTSCHNG);
 }
 
 /**
@@ -327,16 +325,28 @@ static void dwc2_handle_conn_id_status_c
  */
 static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
 {
-	dev_dbg(hsotg->dev, "++Session Request Interrupt++\n");
+	int ret;
 
 	/* Clear interrupt */
 	DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_SESSREQINT);
 
-	/*
-	 * Report disconnect if there is any previous session established
-	 */
-	if (dwc2_is_device_mode(hsotg))
-		s3c_hsotg_disconnect(hsotg);
+	dev_dbg(hsotg->dev, "Session request interrupt - lx_state=%d\n",
+							hsotg->lx_state);
+
+	if (dwc2_is_device_mode(hsotg)) {
+		if (hsotg->lx_state == DWC2_L2) {
+			ret = dwc2_exit_hibernation(hsotg, true);
+			if (ret && (ret != -ENOTSUPP))
+				dev_err(hsotg->dev,
+					"exit hibernation failed\n");
+		}
+
+		/*
+		 * Report disconnect if there is any previous session
+		 * established
+		 */
+		dwc2_hsotg_disconnect(hsotg);
+	}
 }
 
 /*
@@ -349,6 +359,10 @@ static void dwc2_handle_session_req_intr
 static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
 {
 	int ret;
+
+	/* Clear interrupt */
+	DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_WKUPINT);
+
 	dev_dbg(hsotg->dev, "++Resume or Remote Wakeup Detected Interrupt++\n");
 	dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state);
 
@@ -369,6 +383,9 @@ static void dwc2_handle_wakeup_detected_
 		/* Change to L0 state */
 		hsotg->lx_state = DWC2_L0;
 	} else {
+		if (hsotg->core_params->hibernation)
+			return;
+
 		if (hsotg->lx_state != DWC2_L1) {
 			u32 pcgcctl = DWC2_READ_4(hsotg, PCGCTL);
 
@@ -382,9 +399,6 @@ static void dwc2_handle_wakeup_detected_
 			hsotg->lx_state = DWC2_L0;
 		}
 	}
-
-	/* Clear interrupt */
-	DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_WKUPINT);
 }
 
 /*
@@ -393,17 +407,14 @@ static void dwc2_handle_wakeup_detected_
  */
 static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg)
 {
+	DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_DISCONNINT);
+
 	dev_dbg(hsotg->dev, "++Disconnect Detected Interrupt++ (%s) %s\n",
 		dwc2_is_host_mode(hsotg) ? "Host" : "Device",
 		dwc2_op_state_str(hsotg));
 
 	if (hsotg->op_state == OTG_STATE_A_HOST)
-		dwc2_hcd_disconnect(hsotg);
-
-	/* Change to L3 (OFF) state */
-	hsotg->lx_state = DWC2_L3;
-
-	DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_DISCONNINT);
+		dwc2_hcd_disconnect(hsotg, false);
 }
 
 /*
@@ -419,6 +430,9 @@ static void dwc2_handle_usb_suspend_intr
 	u32 dsts;
 	int ret;
 
+	/* Clear interrupt */
+	DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_USBSUSP);
+
 	dev_dbg(hsotg->dev, "USB SUSPEND\n");
 
 	if (dwc2_is_device_mode(hsotg)) {
@@ -437,7 +451,7 @@ static void dwc2_handle_usb_suspend_intr
 			if (!dwc2_is_device_connected(hsotg)) {
 				dev_dbg(hsotg->dev,
 						"ignore suspend request before enumeration\n");
-				goto clear_int;
+				return;
 			}
 
 			ret = dwc2_enter_hibernation(hsotg);
@@ -476,10 +490,6 @@ skip_power_saving:
 			hsotg->op_state = OTG_STATE_A_HOST;
 		}
 	}
-
-clear_int:
-	/* Clear interrupt */
-	DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_USBSUSP);
 }
 
 #define GINTMSK_COMMON	(GINTSTS_WKUPINT | GINTSTS_SESSREQINT |		\

Index: src/sys/external/bsd/dwc2/dist/dwc2_hcd.c
diff -u src/sys/external/bsd/dwc2/dist/dwc2_hcd.c:1.17 src/sys/external/bsd/dwc2/dist/dwc2_hcd.c:1.18
--- src/sys/external/bsd/dwc2/dist/dwc2_hcd.c:1.17	Tue Dec 22 14:29:28 2015
+++ src/sys/external/bsd/dwc2/dist/dwc2_hcd.c	Sun Feb 14 10:53:30 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: dwc2_hcd.c,v 1.17 2015/12/22 14:29:28 skrll Exp $	*/
+/*	$NetBSD: dwc2_hcd.c,v 1.18 2016/02/14 10:53:30 skrll Exp $	*/
 
 /*
  * hcd.c - DesignWare HS OTG Controller host-mode routines
@@ -42,7 +42,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dwc2_hcd.c,v 1.17 2015/12/22 14:29:28 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dwc2_hcd.c,v 1.18 2016/02/14 10:53:30 skrll Exp $");
 
 #include <sys/types.h>
 #include <sys/kmem.h>
@@ -145,7 +145,7 @@ static void dwc2_kill_urbs_in_qh_list(st
 	list_for_each_entry_safe(qh, qh_tmp, qh_list, qh_list_entry) {
 		list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list,
 					 qtd_list_entry) {
-			dwc2_host_complete(hsotg, qtd, -ETIMEDOUT);
+			dwc2_host_complete(hsotg, qtd, -ECONNRESET);
 			dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
 		}
 	}
@@ -279,15 +279,33 @@ static void dwc2_hcd_cleanup_channels(st
 }
 
 /**
+ * dwc2_hcd_connect() - Handles connect of the HCD
+ *
+ * @hsotg: Pointer to struct dwc2_hsotg
+ *
+ * Must be called with interrupt disabled and spinlock held
+ */
+void dwc2_hcd_connect(struct dwc2_hsotg *hsotg)
+{
+	if (hsotg->lx_state != DWC2_L0)
+		usb_hcd_resume_root_hub(hsotg->priv);
+
+	hsotg->flags.b.port_connect_status_change = 1;
+	hsotg->flags.b.port_connect_status = 1;
+}
+
+/**
  * dwc2_hcd_disconnect() - Handles disconnect of the HCD
  *
  * @hsotg: Pointer to struct dwc2_hsotg
+ * @force: If true, we won't try to reconnect even if we see device connected.
  *
  * Must be called with interrupt disabled and spinlock held
  */
-void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg)
+void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force)
 {
 	u32 intr;
+	u32 hprt0;
 
 	/* Set status flags for the hub driver */
 	hsotg->flags.b.port_connect_status_change = 1;
@@ -328,6 +346,24 @@ void dwc2_hcd_disconnect(struct dwc2_hso
 	dwc2_host_disconnect(hsotg);
 
 	dwc2_root_intr(hsotg->hsotg_sc);
+
+	/*
+	 * Add an extra check here to see if we're actually connected but
+	 * we don't have a detection interrupt pending.  This can happen if:
+	 *   1. hardware sees connect
+	 *   2. hardware sees disconnect
+	 *   3. hardware sees connect
+	 *   4. dwc2_port_intr() - clears connect interrupt
+	 *   5. dwc2_handle_common_intr() - calls here
+	 *
+	 * Without the extra check here we will end calling disconnect
+	 * and won't get any future interrupts to handle the connect.
+	 */
+	if (!force) {
+		hprt0 = DWC2_READ_4(hsotg, HPRT0);
+		if (!(hprt0 & HPRT0_CONNDET) && (hprt0 & HPRT0_CONNSTS))
+			dwc2_hcd_connect(hsotg);
+	}
 }
 
 /**
@@ -337,13 +373,14 @@ void dwc2_hcd_disconnect(struct dwc2_hso
  */
 static void dwc2_hcd_rem_wakeup(struct dwc2_hsotg *hsotg)
 {
-	if (hsotg->lx_state == DWC2_L2) {
+	if (hsotg->bus_suspended) {
 		hsotg->flags.b.port_suspend_change = 1;
 		usb_hcd_resume_root_hub(hsotg->priv);
-	} else {
-		hsotg->flags.b.port_l1_change = 1;
 	}
 
+	if (hsotg->lx_state == DWC2_L1)
+		hsotg->flags.b.port_l1_change = 1;
+
 	dwc2_root_intr(hsotg->hsotg_sc);
 }
 
@@ -840,8 +877,11 @@ static int dwc2_assign_and_init_hc(struc
 		 */
 		chan->multi_count = dwc2_hb_mult(qh->maxp);
 
-	if (hsotg->core_params->dma_desc_enable > 0)
+	if (hsotg->core_params->dma_desc_enable > 0) {
+		chan->desc_list_usbdma = qh->desc_list_usbdma;
 		chan->desc_list_addr = qh->desc_list_dma;
+		chan->desc_list_sz = qh->desc_list_sz;
+	}
 
 	dwc2_hc_init(hsotg, chan);
 	chan->qh = qh;
@@ -1332,6 +1372,7 @@ dwc2_conn_id_status_change(struct work *
 						wf_otg);
 	u32 count = 0;
 	u32 gotgctl;
+	unsigned long flags;
 
 	dev_dbg(hsotg->dev, "%s()\n", __func__);
 
@@ -1359,8 +1400,10 @@ dwc2_conn_id_status_change(struct work *
 		hsotg->op_state = OTG_STATE_B_PERIPHERAL;
 		dwc2_core_init(hsotg, false);
 		dwc2_enable_global_interrupts(hsotg);
-		s3c_hsotg_core_init_disconnected(hsotg, false);
-		s3c_hsotg_core_connect(hsotg);
+		spin_lock_irqsave(&hsotg->lock, flags);
+		dwc2_hsotg_core_init_disconnected(hsotg, false);
+		spin_unlock_irqrestore(&hsotg->lock, flags);
+		dwc2_hsotg_core_connect(hsotg);
 	} else {
 		/* A-Device connector (Host Mode) */
 		dev_dbg(hsotg->dev, "connId A\n");
@@ -1403,6 +1446,7 @@ void dwc2_wakeup_detected(void * data)
 		DWC2_READ_4(hsotg, HPRT0));
 
 	dwc2_hcd_rem_wakeup(hsotg);
+	hsotg->bus_suspended = 0;
 
 	/* Change to L0 state */
 	hsotg->lx_state = DWC2_L0;
@@ -1431,14 +1475,19 @@ static void dwc2_port_suspend(struct dwc
 	hprt0 |= HPRT0_SUSP;
 	DWC2_WRITE_4(hsotg, HPRT0, hprt0);
 
-	/* Update lx_state */
-	hsotg->lx_state = DWC2_L2;
+	hsotg->bus_suspended = 1;
 
-	/* Suspend the Phy Clock */
-	pcgctl = DWC2_READ_4(hsotg, PCGCTL);
-	pcgctl |= PCGCTL_STOPPCLK;
-	DWC2_WRITE_4(hsotg, PCGCTL, pcgctl);
-	udelay(10);
+	/*
+	 * If hibernation is supported, Phy clock will be suspended
+	 * after registers are backuped.
+	 */
+	if (!hsotg->core_params->hibernation) {
+		/* Suspend the Phy Clock */
+		pcgctl = DWC2_READ_4(hsotg, PCGCTL);
+		pcgctl |= PCGCTL_STOPPCLK;
+		DWC2_WRITE_4(hsotg, PCGCTL, pcgctl);
+		udelay(10);
+	}
 
 	/* For HNP the bus must be suspended for at least 200ms */
 	if (dwc2_host_is_b_hnp_enabled(hsotg)) {
@@ -1454,6 +1503,44 @@ static void dwc2_port_suspend(struct dwc
 	}
 }
 
+/* Must NOT be called with interrupt disabled or spinlock held */
+static void dwc2_port_resume(struct dwc2_hsotg *hsotg)
+{
+	unsigned long flags;
+	u32 hprt0;
+	u32 pcgctl;
+
+	spin_lock_irqsave(&hsotg->lock, flags);
+
+	/*
+	 * If hibernation is supported, Phy clock is already resumed
+	 * after registers restore.
+	 */
+	if (!hsotg->core_params->hibernation) {
+		pcgctl = DWC2_READ_4(hsotg, PCGCTL);
+		pcgctl &= ~PCGCTL_STOPPCLK;
+		DWC2_WRITE_4(hsotg, PCGCTL, pcgctl);
+		spin_unlock_irqrestore(&hsotg->lock, flags);
+		usleep_range(20000, 40000);
+		spin_lock_irqsave(&hsotg->lock, flags);
+	}
+
+	hprt0 = dwc2_read_hprt0(hsotg);
+	hprt0 |= HPRT0_RES;
+	hprt0 &= ~HPRT0_SUSP;
+	DWC2_WRITE_4(hsotg, HPRT0, hprt0);
+	spin_unlock_irqrestore(&hsotg->lock, flags);
+
+	msleep(USB_RESUME_TIMEOUT);
+
+	spin_lock_irqsave(&hsotg->lock, flags);
+	hprt0 = dwc2_read_hprt0(hsotg);
+	hprt0 &= ~(HPRT0_RES | HPRT0_SUSP);
+	DWC2_WRITE_4(hsotg, HPRT0, hprt0);
+	hsotg->bus_suspended = 0;
+	spin_unlock_irqrestore(&hsotg->lock, flags);
+}
+
 /* Handles hub class-specific requests */
 int
 dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
@@ -1501,17 +1588,8 @@ dwc2_hcd_hub_control(struct dwc2_hsotg *
 		case USB_PORT_FEAT_SUSPEND:
 			dev_dbg(hsotg->dev,
 				"ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
-			DWC2_WRITE_4(hsotg, PCGCTL, 0);
-			usleep_range(20000, 40000);
-
-			hprt0 = dwc2_read_hprt0(hsotg);
-			hprt0 |= HPRT0_RES;
-			DWC2_WRITE_4(hsotg, HPRT0, hprt0);
-			hprt0 &= ~HPRT0_SUSP;
-			msleep(USB_RESUME_TIMEOUT);
-
-			hprt0 &= ~HPRT0_RES;
-			DWC2_WRITE_4(hsotg, HPRT0, hprt0);
+			if (hsotg->bus_suspended)
+				dwc2_port_resume(hsotg);
 			break;
 
 		case USB_PORT_FEAT_POWER:
@@ -1670,6 +1748,27 @@ dwc2_hcd_hub_control(struct dwc2_hsotg *
 		/* USB_PORT_FEAT_INDICATOR unsupported always 0 */
 		USETW(ps.wPortStatus, port_status);
 
+		if (hsotg->core_params->dma_desc_fs_enable) {
+			/*
+			 * Enable descriptor DMA only if a full speed
+			 * device is connected.
+			 */
+			if (hsotg->new_connection &&
+			    ((port_status &
+			      (USB_PORT_STAT_CONNECTION |
+			       USB_PORT_STAT_HIGH_SPEED |
+			       USB_PORT_STAT_LOW_SPEED)) ==
+			       USB_PORT_STAT_CONNECTION)) {
+				u32 hcfg;
+
+				dev_info(hsotg->dev, "Enabling descriptor DMA mode\n");
+				hsotg->core_params->dma_desc_enable = 1;
+				hcfg = DWC2_READ_4(hsotg, HCFG);
+				hcfg |= HCFG_DESCDMA;
+				DWC2_WRITE_4(hsotg, HCFG, hcfg);
+				hsotg->new_connection = false;
+			}
+		}
 		dev_vdbg(hsotg->dev, "wPortStatus=%04x\n", port_status);
 		memcpy(buf, &ps, sizeof(ps));
 		break;
@@ -2055,7 +2154,6 @@ void dwc2_host_disconnect(struct dwc2_hs
 //	hcd->self.is_b_host = 0;
 }
 
-
 /*
  * Work queue function for starting the HCD when A-Cable is connected
  */
@@ -2077,15 +2175,21 @@ dwc2_hcd_reset_func(struct work *work)
 {
 	struct dwc2_hsotg *hsotg = container_of(work, struct dwc2_hsotg,
 						reset_work.work);
+	unsigned long flags;
 	u32 hprt0;
 
 	dev_dbg(hsotg->dev, "USB RESET function called\n");
+
+	spin_lock_irqsave(&hsotg->lock, flags);
+
 	hprt0 = dwc2_read_hprt0(hsotg);
 	hprt0 &= ~HPRT0_RST;
 	DWC2_WRITE_4(hsotg, HPRT0, hprt0);
 	hsotg->flags.b.port_reset_change = 1;
 
 	dwc2_root_intr(hsotg->hsotg_sc);
+
+	spin_unlock_irqrestore(&hsotg->lock, flags);
 }
 
 /*
@@ -2342,6 +2446,7 @@ void dwc2_hcd_remove(struct dwc2_hsotg *
 		return;
 	}
 	hsotg->priv = NULL;
+
 	dwc2_hcd_release(hsotg);
 
 #ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS

Index: src/sys/external/bsd/dwc2/dist/dwc2_hcd.h
diff -u src/sys/external/bsd/dwc2/dist/dwc2_hcd.h:1.11 src/sys/external/bsd/dwc2/dist/dwc2_hcd.h:1.12
--- src/sys/external/bsd/dwc2/dist/dwc2_hcd.h:1.11	Sun Feb 14 10:34:09 2016
+++ src/sys/external/bsd/dwc2/dist/dwc2_hcd.h	Sun Feb 14 10:53:30 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: dwc2_hcd.h,v 1.11 2016/02/14 10:34:09 skrll Exp $	*/
+/*	$NetBSD: dwc2_hcd.h,v 1.12 2016/02/14 10:53:30 skrll Exp $	*/
 
 /*
  * hcd.h - DesignWare HS OTG Controller host-mode declarations
@@ -109,6 +109,7 @@ struct dwc2_qh;
  * @qh:                 QH for the transfer being processed by this channel
  * @hc_list_entry:      For linking to list of host channels
  * @desc_list_addr:     Current QH's descriptor list DMA address
+ * @desc_list_sz:       Current QH's descriptor list size
  *
  * This structure represents the state of a single host channel when acting in
  * host mode. It contains the data items needed to transfer packets to an
@@ -161,7 +162,9 @@ struct dwc2_host_chan {
 	u32 hcint;
 	struct dwc2_qh *qh;
 	struct list_head hc_list_entry;
+	usb_dma_t desc_list_usbdma;
 	dma_addr_t desc_list_addr;
+	u32 desc_list_sz;
 };
 
 struct dwc2_hcd_pipe_info {
@@ -257,6 +260,7 @@ enum dwc2_transaction_type {
  *                      schedule
  * @desc_list:          List of transfer descriptors
  * @desc_list_dma:      Physical address of desc_list
+ * @desc_list_sz:       Size of descriptors list
  * @n_bytes:            Xfer Bytes array. Each element corresponds to a transfer
  *                      descriptor and indicates original XferSize value for the
  *                      descriptor
@@ -293,6 +297,7 @@ struct dwc2_qh {
 	usb_dma_t desc_list_usbdma;
 	struct dwc2_hcd_dma_desc *desc_list;
 	dma_addr_t desc_list_dma;
+	u32 desc_list_sz;
 	u32 *n_bytes;
 	unsigned tt_buffer_dirty:1;
 };
@@ -349,6 +354,8 @@ struct dwc2_qtd {
 	u8 isoc_split_pos;
 	u16 isoc_frame_index;
 	u16 isoc_split_offset;
+	u16 isoc_td_last;
+	u16 isoc_td_first;
 	u32 ssplit_out_xfer_count;
 	u8 error_count;
 	u8 n_desc;
@@ -387,19 +394,6 @@ static inline void disable_hc_int(struct
 }
 
 /*
- * Returns the mode of operation, host or device
- */
-static inline int dwc2_is_host_mode(struct dwc2_hsotg *hsotg)
-{
-	return (DWC2_READ_4(hsotg, GINTSTS) & GINTSTS_CURMODE_HOST) != 0;
-}
-
-static inline int dwc2_is_device_mode(struct dwc2_hsotg *hsotg)
-{
-	return (DWC2_READ_4(hsotg, GINTSTS) & GINTSTS_CURMODE_HOST) == 0;
-}
-
-/*
  * Reads HPRT0 in preparation to modify. It keeps the WC bits 0 so that if they
  * are read as 1, they won't clear when written back.
  */
@@ -535,6 +529,19 @@ static inline bool dbg_perio(void) { ret
 #define dwc2_max_packet(wmaxpacketsize) ((wmaxpacketsize) & 0x07ff)
 
 /*
+ * Returns true if frame1 index is greater than frame2 index. The comparison
+ * is done modulo FRLISTEN_64_SIZE. This accounts for the rollover of the
+ * frame number when the max index frame number is reached.
+ */
+static inline bool dwc2_frame_idx_num_gt(u16 fr_idx1, u16 fr_idx2)
+{
+	u16 diff = fr_idx1 - fr_idx2;
+	u16 sign = diff & (FRLISTEN_64_SIZE >> 1);
+
+	return diff && !sign;
+}
+
+/*
  * Returns true if frame1 is less than or equal to frame2. The comparison is
  * done modulo HFNUM_MAX_FRNUM. This accounts for the rollover of the
  * frame number when the max frame number is reached.

Index: src/sys/external/bsd/dwc2/dist/dwc2_hcdintr.c
diff -u src/sys/external/bsd/dwc2/dist/dwc2_hcdintr.c:1.12 src/sys/external/bsd/dwc2/dist/dwc2_hcdintr.c:1.13
--- src/sys/external/bsd/dwc2/dist/dwc2_hcdintr.c:1.12	Sun Aug 30 12:59:59 2015
+++ src/sys/external/bsd/dwc2/dist/dwc2_hcdintr.c	Sun Feb 14 10:53:30 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: dwc2_hcdintr.c,v 1.12 2015/08/30 12:59:59 skrll Exp $	*/
+/*	$NetBSD: dwc2_hcdintr.c,v 1.13 2016/02/14 10:53:30 skrll Exp $	*/
 
 /*
  * hcd_intr.c - DesignWare HS OTG Controller host-mode interrupt handling
@@ -40,7 +40,7 @@
  * This file contains the interrupt handlers for Host mode
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dwc2_hcdintr.c,v 1.12 2015/08/30 12:59:59 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dwc2_hcdintr.c,v 1.13 2016/02/14 10:53:30 skrll Exp $");
 
 #include <sys/types.h>
 #include <sys/pool.h>
@@ -125,6 +125,9 @@ static void dwc2_sof_intr(struct dwc2_hs
 	struct dwc2_qh *qh;
 	enum dwc2_transaction_type tr_type;
 
+	/* Clear interrupt */
+	DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_SOF);
+
 #ifdef DEBUG_SOF
 	dev_vdbg(hsotg->dev, "--Start of Frame Interrupt--\n");
 #endif
@@ -149,9 +152,6 @@ static void dwc2_sof_intr(struct dwc2_hs
 	tr_type = dwc2_hcd_select_transactions(hsotg);
 	if (tr_type != DWC2_TRANSACTION_NONE)
 		dwc2_hcd_queue_transactions(hsotg, tr_type);
-
-	/* Clear interrupt */
-	DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_SOF);
 }
 
 /*
@@ -317,6 +317,7 @@ static void dwc2_hprt0_enable(struct dwc
 
 	if (do_reset) {
 		*hprt0_modify |= HPRT0_RST;
+		DWC2_WRITE_4(hsotg, HPRT0, *hprt0_modify);
 		queue_delayed_work(hsotg->wq_otg, &hsotg->reset_work,
 				   msecs_to_jiffies(60));
 	} else {
@@ -354,15 +355,12 @@ static void dwc2_port_intr(struct dwc2_h
 	 * Set flag and clear if detected
 	 */
 	if (hprt0 & HPRT0_CONNDET) {
+		DWC2_WRITE_4(hsotg, HPRT0, hprt0_modify | HPRT0_CONNDET);
+
 		dev_vdbg(hsotg->dev,
 			 "--Port Interrupt HPRT0=0x%08x Port Connect Detected--\n",
 			 hprt0);
-		if (hsotg->lx_state != DWC2_L0)
-			usb_hcd_resume_root_hub(hsotg->priv);
-
-		hsotg->flags.b.port_connect_status_change = 1;
-		hsotg->flags.b.port_connect_status = 1;
-		hprt0_modify |= HPRT0_CONNDET;
+		dwc2_hcd_connect(hsotg);
 
 		/*
 		 * The Hub driver asserts a reset when it sees port connect
@@ -375,28 +373,36 @@ static void dwc2_port_intr(struct dwc2_h
 	 * Clear if detected - Set internal flag if disabled
 	 */
 	if (hprt0 & HPRT0_ENACHG) {
+		DWC2_WRITE_4(hsotg, HPRT0, hprt0_modify | HPRT0_ENACHG);
 		dev_vdbg(hsotg->dev,
 			 "  --Port Interrupt HPRT0=0x%08x Port Enable Changed (now %d)--\n",
 			 hprt0, !!(hprt0 & HPRT0_ENA));
-		hprt0_modify |= HPRT0_ENACHG;
-		if (hprt0 & HPRT0_ENA)
+		if (hprt0 & HPRT0_ENA) {
+			hsotg->new_connection = true;
 			dwc2_hprt0_enable(hsotg, hprt0, &hprt0_modify);
-		else
+		} else {
 			hsotg->flags.b.port_enable_change = 1;
+			if (hsotg->core_params->dma_desc_fs_enable) {
+				u32 hcfg;
+
+				hsotg->core_params->dma_desc_enable = 0;
+				hsotg->new_connection = false;
+				hcfg = DWC2_READ_4(hsotg, HCFG);
+				hcfg &= ~HCFG_DESCDMA;
+				DWC2_WRITE_4(hsotg, HCFG, hcfg);
+			}
+		}
 	}
 
 	/* Overcurrent Change Interrupt */
 	if (hprt0 & HPRT0_OVRCURRCHG) {
+		DWC2_WRITE_4(hsotg, HPRT0, hprt0_modify | HPRT0_OVRCURRCHG);
 		dev_vdbg(hsotg->dev,
 			 "  --Port Interrupt HPRT0=0x%08x Port Overcurrent Changed--\n",
 			 hprt0);
 		hsotg->flags.b.port_over_current_change = 1;
-		hprt0_modify |= HPRT0_OVRCURRCHG;
 	}
 
-	/* Clear Port Interrupts */
-	DWC2_WRITE_4(hsotg, HPRT0, hprt0_modify);
-
 	if (hsotg->flags.b.port_connect_status_change ||
 	    hsotg->flags.b.port_enable_change ||
 	    hsotg->flags.b.port_over_current_change)
@@ -1984,6 +1990,24 @@ static void dwc2_hc_chhltd_intr(struct d
 	}
 }
 
+/*
+ * Check if the given qtd is still the top of the list (and thus valid).
+ *
+ * If dwc2_hcd_qtd_unlink_and_free() has been called since we grabbed
+ * the qtd from the top of the list, this will return false (otherwise true).
+ */
+static bool dwc2_check_qtd_still_ok(struct dwc2_qtd *qtd, struct dwc2_qh *qh)
+{
+	struct dwc2_qtd *cur_head;
+
+	if (qh == NULL)
+		return false;
+
+	cur_head = list_first_entry(&qh->qtd_list, struct dwc2_qtd,
+				    qtd_list_entry);
+	return (cur_head == qtd);
+}
+
 /* Handles interrupt for a specific Host Channel */
 static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
 {
@@ -2066,27 +2090,59 @@ static void dwc2_hc_n_intr(struct dwc2_h
 		 */
 		hcint &= ~HCINTMSK_NYET;
 	}
-	if (hcint & HCINTMSK_CHHLTD)
+
+	if (hcint & HCINTMSK_CHHLTD) {
 		dwc2_hc_chhltd_intr(hsotg, chan, chnum, qtd);
-	if (hcint & HCINTMSK_AHBERR)
+		if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
+			goto exit;
+	}
+	if (hcint & HCINTMSK_AHBERR) {
 		dwc2_hc_ahberr_intr(hsotg, chan, chnum, qtd);
-	if (hcint & HCINTMSK_STALL)
+		if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
+			goto exit;
+	}
+	if (hcint & HCINTMSK_STALL) {
 		dwc2_hc_stall_intr(hsotg, chan, chnum, qtd);
-	if (hcint & HCINTMSK_NAK)
+		if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
+			goto exit;
+	}
+	if (hcint & HCINTMSK_NAK) {
 		dwc2_hc_nak_intr(hsotg, chan, chnum, qtd);
-	if (hcint & HCINTMSK_ACK)
+		if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
+			goto exit;
+	}
+	if (hcint & HCINTMSK_ACK) {
 		dwc2_hc_ack_intr(hsotg, chan, chnum, qtd);
-	if (hcint & HCINTMSK_NYET)
+		if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
+			goto exit;
+	}
+	if (hcint & HCINTMSK_NYET) {
 		dwc2_hc_nyet_intr(hsotg, chan, chnum, qtd);
-	if (hcint & HCINTMSK_XACTERR)
+		if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
+			goto exit;
+	}
+	if (hcint & HCINTMSK_XACTERR) {
 		dwc2_hc_xacterr_intr(hsotg, chan, chnum, qtd);
-	if (hcint & HCINTMSK_BBLERR)
+		if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
+			goto exit;
+	}
+	if (hcint & HCINTMSK_BBLERR) {
 		dwc2_hc_babble_intr(hsotg, chan, chnum, qtd);
-	if (hcint & HCINTMSK_FRMOVRUN)
+		if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
+			goto exit;
+	}
+	if (hcint & HCINTMSK_FRMOVRUN) {
 		dwc2_hc_frmovrun_intr(hsotg, chan, chnum, qtd);
-	if (hcint & HCINTMSK_DATATGLERR)
+		if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
+			goto exit;
+	}
+	if (hcint & HCINTMSK_DATATGLERR) {
 		dwc2_hc_datatglerr_intr(hsotg, chan, chnum, qtd);
+		if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
+			goto exit;
+	}
 
+exit:
 	chan->hcint = 0;
 }
 

Index: src/sys/external/bsd/dwc2/dist/dwc2_hcdqueue.c
diff -u src/sys/external/bsd/dwc2/dist/dwc2_hcdqueue.c:1.13 src/sys/external/bsd/dwc2/dist/dwc2_hcdqueue.c:1.14
--- src/sys/external/bsd/dwc2/dist/dwc2_hcdqueue.c:1.13	Mon Aug 31 06:12:55 2015
+++ src/sys/external/bsd/dwc2/dist/dwc2_hcdqueue.c	Sun Feb 14 10:53:30 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: dwc2_hcdqueue.c,v 1.13 2015/08/31 06:12:55 uebayasi Exp $	*/
+/*	$NetBSD: dwc2_hcdqueue.c,v 1.14 2016/02/14 10:53:30 skrll Exp $	*/
 
 /*
  * hcd_queue.c - DesignWare HS OTG Controller host queuing routines
@@ -42,7 +42,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dwc2_hcdqueue.c,v 1.13 2015/08/31 06:12:55 uebayasi Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dwc2_hcdqueue.c,v 1.14 2016/02/14 10:53:30 skrll Exp $");
 
 #include <sys/types.h>
 #include <sys/kmem.h>
@@ -118,6 +118,9 @@ static void dwc2_qh_init(struct dwc2_hso
 				USB_SPEED_HIGH : dev_speed, qh->ep_is_in,
 				qh->ep_type == USB_ENDPOINT_XFER_ISOC,
 				bytecount);
+
+		/* Ensure frame_number corresponds to the reality */
+		hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg);
 		/* Start in a slightly future (micro)frame */
 		qh->sched_frame = dwc2_frame_num_inc(hsotg->frame_number,
 						     SCHEDULE_SLOP);
@@ -247,8 +250,7 @@ struct dwc2_qh *dwc2_hcd_qh_create(struc
 void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
 {
 	struct dwc2_softc *sc = hsotg->hsotg_sc;
-
-	if (hsotg->core_params->dma_desc_enable > 0) {
+	if (qh->desc_list) {
 		dwc2_hcd_qh_free_ddma(hsotg, qh);
 	} else if (qh->dw_align_buf) {
 		usb_freemem(&sc->sc_bus, &qh->dw_align_buf_usbdma);
@@ -602,6 +604,14 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *h
 		/* QH already in a schedule */
 		return 0;
 
+	if (!dwc2_frame_num_le(qh->sched_frame, hsotg->frame_number) &&
+			!hsotg->frame_number) {
+		dev_dbg(hsotg->dev,
+				"reset frame number counter\n");
+		qh->sched_frame = dwc2_frame_num_inc(hsotg->frame_number,
+				SCHEDULE_SLOP);
+	}
+
 	/* Add the new QH to the appropriate schedule */
 	if (dwc2_qh_is_non_per(qh)) {
 		/* Always start in inactive schedule */

Index: src/sys/external/bsd/dwc2/dist/dwc2_hw.h
diff -u src/sys/external/bsd/dwc2/dist/dwc2_hw.h:1.3 src/sys/external/bsd/dwc2/dist/dwc2_hw.h:1.4
--- src/sys/external/bsd/dwc2/dist/dwc2_hw.h:1.3	Sun Aug 30 12:59:59 2015
+++ src/sys/external/bsd/dwc2/dist/dwc2_hw.h	Sun Feb 14 10:53:30 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: dwc2_hw.h,v 1.3 2015/08/30 12:59:59 skrll Exp $	*/
+/*	$NetBSD: dwc2_hw.h,v 1.4 2016/02/14 10:53:30 skrll Exp $	*/
 
 /*
  * hw.h - DesignWare HS OTG Controller hardware definitions
@@ -144,6 +144,7 @@
 #define GINTSTS_RESETDET		(1 << 23)
 #define GINTSTS_FET_SUSP		(1 << 22)
 #define GINTSTS_INCOMPL_IP		(1 << 21)
+#define GINTSTS_INCOMPL_SOOUT		(1 << 21)
 #define GINTSTS_INCOMPL_SOIN		(1 << 20)
 #define GINTSTS_OEPINT			(1 << 19)
 #define GINTSTS_IEPINT			(1 << 18)
@@ -770,10 +771,6 @@
 #define TSIZ_XFERSIZE_SHIFT		0
 
 #define HCDMA(_ch)			HSOTG_REG(0x0514 + 0x20 * (_ch))
-#define HCDMA_DMA_ADDR_MASK		(0x1fffff << 11)
-#define HCDMA_DMA_ADDR_SHIFT		11
-#define HCDMA_CTD_MASK			(0xff << 3)
-#define HCDMA_CTD_SHIFT			3
 
 #define HCDMAB(_ch)			HSOTG_REG(0x051c + 0x20 * (_ch))
 

Reply via email to