Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6d23ee9c authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

Merge tag 'usb-for-v4.17' of...

Merge tag 'usb-for-v4.17' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-testing

Felipe writes:

usb: changes for v4.17 merge window

Quite a lot happened in this cycle, with a total of 95 non-merge
commits. The most interesting parts are listed below:

Synopsys has been adding better support for USB 3.1 to dwc3. The same
series also sets g_mass_storage's max speed to SSP.

Roger Quadros (TI) added support for dual-role using the OTG block
available in some dwc3 implementations, this makes sure that AM437x
can swap roles in runtime.

We have a new SoC supported in dwc3 now - Amlogic Meson GX - thanks to
the work of Martin Blumenstingl.

We also have a ton of changes in dwc2 (51% of all changes, in
fact). The most interesting part there is the support for
Hibernation (a Synopsys PM feature).

Apart from these, we have our regular set of non-critical fixes all
over the place.
parents 6555ad13 aaeab02d
Loading
Loading
Loading
Loading
+42 −0
Original line number Diff line number Diff line
Amlogic Meson GX DWC3 USB SoC controller

Required properties:
- compatible:	depending on the SoC this should contain one of:
			* amlogic,meson-axg-dwc3
			* amlogic,meson-gxl-dwc3
- clocks:	a handle for the "USB general" clock
- clock-names:	must be "usb_general"
- resets:	a handle for the shared "USB OTG" reset line
- reset-names:	must be "usb_otg"

Required child node:
A child node must exist to represent the core DWC3 IP block. The name of
the node is not important. The content of the node is defined in dwc3.txt.

PHY documentation is provided in the following places:
- Documentation/devicetree/bindings/phy/meson-gxl-usb2-phy.txt
- Documentation/devicetree/bindings/phy/meson-gxl-usb3-phy.txt

Example device nodes:
		usb0: usb@ff500000 {
			compatible = "amlogic,meson-axg-dwc3";
			#address-cells = <2>;
			#size-cells = <2>;
			ranges;

			clocks = <&clkc CLKID_USB>;
			clock-names = "usb_general";
			resets = <&reset RESET_USB_OTG>;
			reset-names = "usb_otg";

			dwc3: dwc3@ff500000 {
				compatible = "snps,dwc3";
				reg = <0x0 0xff500000 0x0 0x100000>;
				interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
				dr_mode = "host";
				maximum-speed = "high-speed";
				snps,dis_u2_susphy_quirk;
				phys = <&usb3_phy>, <&usb2_phy0>;
				phy-names = "usb2-phy", "usb3-phy";
			};
		};
+16 −0
Original line number Diff line number Diff line
@@ -57,6 +57,22 @@ Optional properties:
 - snps,quirk-frame-length-adjustment: Value for GFLADJ_30MHZ field of GFLADJ
	register for post-silicon frame length adjustment when the
	fladj_30mhz_sdbnd signal is invalid or incorrect.
 - snps,rx-thr-num-pkt-prd: periodic ESS RX packet threshold count - host mode
			only. Set this and rx-max-burst-prd to a valid,
			non-zero value 1-16 (DWC_usb31 programming guide
			section 1.2.4) to enable periodic ESS RX threshold.
 - snps,rx-max-burst-prd: max periodic ESS RX burst size - host mode only. Set
			this and rx-thr-num-pkt-prd to a valid, non-zero value
			1-16 (DWC_usb31 programming guide section 1.2.4) to
			enable periodic ESS RX threshold.
 - snps,tx-thr-num-pkt-prd: periodic ESS TX packet threshold count - host mode
			only. Set this and tx-max-burst-prd to a valid,
			non-zero value 1-16 (DWC_usb31 programming guide
			section 1.2.3) to enable periodic ESS TX threshold.
 - snps,tx-max-burst-prd: max periodic ESS TX burst size - host mode only. Set
			this and tx-thr-num-pkt-prd to a valid, non-zero value
			1-16 (DWC_usb31 programming guide section 1.2.3) to
			enable periodic ESS TX threshold.

 - <DEPRECATED> tx-fifo-resize: determines if the FIFO *has* to be reallocated.

+291 −104
Original line number Diff line number Diff line
@@ -64,10 +64,11 @@
 *
 * @hsotg: Programming view of the DWC_otg controller
 */
static int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg)
int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg)
{
	struct dwc2_gregs_backup *gr;
	int i;

	dev_dbg(hsotg->dev, "%s\n", __func__);

	/* Backup global regs */
	gr = &hsotg->gr_backup;
@@ -78,10 +79,11 @@ static int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg)
	gr->gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
	gr->grxfsiz = dwc2_readl(hsotg->regs + GRXFSIZ);
	gr->gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ);
	gr->hptxfsiz = dwc2_readl(hsotg->regs + HPTXFSIZ);
	gr->gdfifocfg = dwc2_readl(hsotg->regs + GDFIFOCFG);
	for (i = 0; i < MAX_EPS_CHANNELS; i++)
		gr->dtxfsiz[i] = dwc2_readl(hsotg->regs + DPTXFSIZN(i));
	gr->pcgcctl1 = dwc2_readl(hsotg->regs + PCGCCTL1);
	gr->glpmcfg = dwc2_readl(hsotg->regs + GLPMCFG);
	gr->gi2cctl = dwc2_readl(hsotg->regs + GI2CCTL);
	gr->pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);

	gr->valid = true;
	return 0;
@@ -94,10 +96,9 @@ static int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg)
 *
 * @hsotg: Programming view of the DWC_otg controller
 */
static int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg)
int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg)
{
	struct dwc2_gregs_backup *gr;
	int i;

	dev_dbg(hsotg->dev, "%s\n", __func__);

@@ -117,26 +118,27 @@ static int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg)
	dwc2_writel(gr->gahbcfg, hsotg->regs + GAHBCFG);
	dwc2_writel(gr->grxfsiz, hsotg->regs + GRXFSIZ);
	dwc2_writel(gr->gnptxfsiz, hsotg->regs + GNPTXFSIZ);
	dwc2_writel(gr->hptxfsiz, hsotg->regs + HPTXFSIZ);
	dwc2_writel(gr->gdfifocfg, hsotg->regs + GDFIFOCFG);
	for (i = 0; i < MAX_EPS_CHANNELS; i++)
		dwc2_writel(gr->dtxfsiz[i], hsotg->regs + DPTXFSIZN(i));
	dwc2_writel(gr->pcgcctl1, hsotg->regs + PCGCCTL1);
	dwc2_writel(gr->glpmcfg, hsotg->regs + GLPMCFG);
	dwc2_writel(gr->pcgcctl, hsotg->regs + PCGCTL);
	dwc2_writel(gr->gi2cctl, hsotg->regs + GI2CCTL);

	return 0;
}

/**
 * dwc2_exit_hibernation() - Exit controller from Partial Power Down.
 * dwc2_exit_partial_power_down() - Exit controller from Partial Power Down.
 *
 * @hsotg: Programming view of the DWC_otg controller
 * @restore: Controller registers need to be restored
 */
int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore)
int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore)
{
	u32 pcgcctl;
	int ret = 0;

	if (!hsotg->params.hibernation)
	if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL)
		return -ENOTSUPP;

	pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
@@ -167,7 +169,7 @@ int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore)
				return ret;
			}
		} else {
			ret = dwc2_restore_device_registers(hsotg);
			ret = dwc2_restore_device_registers(hsotg, 0);
			if (ret) {
				dev_err(hsotg->dev, "%s: failed to restore device registers\n",
					__func__);
@@ -180,16 +182,16 @@ int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore)
}

/**
 * dwc2_enter_hibernation() - Put controller in Partial Power Down.
 * dwc2_enter_partial_power_down() - Put controller in Partial Power Down.
 *
 * @hsotg: Programming view of the DWC_otg controller
 */
int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg)
int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg)
{
	u32 pcgcctl;
	int ret = 0;

	if (!hsotg->params.hibernation)
	if (!hsotg->params.power_down)
		return -ENOTSUPP;

	/* Backup all registers */
@@ -218,7 +220,7 @@ int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg)

	/*
	 * Clear any pending interrupts since dwc2 will not be able to
	 * clear them after entering hibernation.
	 * clear them after entering partial_power_down.
	 */
	dwc2_writel(0xffffffff, hsotg->regs + GINTSTS);

@@ -239,6 +241,142 @@ int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg)
	return ret;
}

/**
 * dwc2_restore_essential_regs() - Restore essiential regs of core.
 *
 * @hsotg: Programming view of the DWC_otg controller
 * @rmode: Restore mode, enabled in case of remote-wakeup.
 * @is_host: Host or device mode.
 */
static void dwc2_restore_essential_regs(struct dwc2_hsotg *hsotg, int rmode,
					int is_host)
{
	u32 pcgcctl;
	struct dwc2_gregs_backup *gr;
	struct dwc2_dregs_backup *dr;
	struct dwc2_hregs_backup *hr;

	gr = &hsotg->gr_backup;
	dr = &hsotg->dr_backup;
	hr = &hsotg->hr_backup;

	dev_dbg(hsotg->dev, "%s: restoring essential regs\n", __func__);

	/* Load restore values for [31:14] bits */
	pcgcctl = (gr->pcgcctl & 0xffffc000);
	/* If High Speed */
	if (is_host) {
		if (!(pcgcctl & PCGCTL_P2HD_PRT_SPD_MASK))
			pcgcctl |= BIT(17);
	} else {
		if (!(pcgcctl & PCGCTL_P2HD_DEV_ENUM_SPD_MASK))
			pcgcctl |= BIT(17);
	}
	dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);

	/* Umnask global Interrupt in GAHBCFG and restore it */
	dwc2_writel(gr->gahbcfg | GAHBCFG_GLBL_INTR_EN, hsotg->regs + GAHBCFG);

	/* Clear all pending interupts */
	dwc2_writel(0xffffffff, hsotg->regs + GINTSTS);

	/* Unmask restore done interrupt */
	dwc2_writel(GINTSTS_RESTOREDONE, hsotg->regs + GINTMSK);

	/* Restore GUSBCFG and HCFG/DCFG */
	dwc2_writel(gr->gusbcfg, hsotg->regs + GUSBCFG);

	if (is_host) {
		dwc2_writel(hr->hcfg, hsotg->regs + HCFG);
		if (rmode)
			pcgcctl |= PCGCTL_RESTOREMODE;
		dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
		udelay(10);

		pcgcctl |= PCGCTL_ESS_REG_RESTORED;
		dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
		udelay(10);
	} else {
		dwc2_writel(dr->dcfg, hsotg->regs + DCFG);
		if (!rmode)
			pcgcctl |= PCGCTL_RESTOREMODE | PCGCTL_RSTPDWNMODULE;
		dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
		udelay(10);

		pcgcctl |= PCGCTL_ESS_REG_RESTORED;
		dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
		udelay(10);
	}
}

/**
 * dwc2_hib_restore_common() - Common part of restore routine.
 *
 * @hsotg: Programming view of the DWC_otg controller
 * @rem_wakeup: Remote-wakeup, enabled in case of remote-wakeup.
 * @is_host: Host or device mode.
 */
void dwc2_hib_restore_common(struct dwc2_hsotg *hsotg, int rem_wakeup,
			     int is_host)
{
	u32 gpwrdn;

	/* Switch-on voltage to the core */
	gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
	gpwrdn &= ~GPWRDN_PWRDNSWTCH;
	dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
	udelay(10);

	/* Reset core */
	gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
	gpwrdn &= ~GPWRDN_PWRDNRSTN;
	dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
	udelay(10);

	/* Enable restore from PMU */
	gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
	gpwrdn |= GPWRDN_RESTORE;
	dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
	udelay(10);

	/* Disable Power Down Clamp */
	gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
	gpwrdn &= ~GPWRDN_PWRDNCLMP;
	dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
	udelay(50);

	if (!is_host && rem_wakeup)
		udelay(70);

	/* Deassert reset core */
	gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
	gpwrdn |= GPWRDN_PWRDNRSTN;
	dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
	udelay(10);

	/* Disable PMU interrupt */
	gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
	gpwrdn &= ~GPWRDN_PMUINTSEL;
	dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
	udelay(10);

	/* Set Restore Essential Regs bit in PCGCCTL register */
	dwc2_restore_essential_regs(hsotg, rem_wakeup, is_host);

	/*
	 * Wait For Restore_done Interrupt. This mechanism of polling the
	 * interrupt is introduced to avoid any possible race conditions
	 */
	if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, GINTSTS_RESTOREDONE,
				    20000)) {
		dev_dbg(hsotg->dev,
			"%s: Restore Done wan't generated here\n",
			__func__);
	} else {
		dev_dbg(hsotg->dev, "restore done  generated here\n");
	}
}

/**
 * dwc2_wait_for_mode() - Waits for the controller mode.
 * @hsotg:	Programming view of the DWC_otg controller.
@@ -310,6 +448,44 @@ static bool dwc2_iddig_filter_enabled(struct dwc2_hsotg *hsotg)
	return true;
}

/*
 * dwc2_enter_hibernation() - Common function to enter hibernation.
 *
 * @hsotg: Programming view of the DWC_otg controller
 * @is_host: True if core is in host mode.
 *
 * Return: 0 if successful, negative error code otherwise
 */
int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg, int is_host)
{
	if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_HIBERNATION)
		return -ENOTSUPP;

	if (is_host)
		return dwc2_host_enter_hibernation(hsotg);
	else
		return dwc2_gadget_enter_hibernation(hsotg);
}

/*
 * dwc2_exit_hibernation() - Common function to exit from hibernation.
 *
 * @hsotg: Programming view of the DWC_otg controller
 * @rem_wakeup: Remote-wakeup, enabled in case of remote-wakeup.
 * @reset: Enabled in case of restore with reset.
 * @is_host: True if core is in host mode.
 *
 * Return: 0 if successful, negative error code otherwise
 */
int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup,
			  int reset, int is_host)
{
	if (is_host)
		return dwc2_host_exit_hibernation(hsotg, rem_wakeup, reset);
	else
		return dwc2_gadget_exit_hibernation(hsotg, rem_wakeup, reset);
}

/*
 * Do core a soft reset of the core.  Be careful with this because it
 * resets all the internal state machines of the core.
@@ -317,7 +493,6 @@ static bool dwc2_iddig_filter_enabled(struct dwc2_hsotg *hsotg)
int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
{
	u32 greset;
	int count = 0;
	bool wait_for_host_mode = false;

	dev_vdbg(hsotg->dev, "%s()\n", __func__);
@@ -346,29 +521,19 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
	greset = dwc2_readl(hsotg->regs + GRSTCTL);
	greset |= GRSTCTL_CSFTRST;
	dwc2_writel(greset, hsotg->regs + GRSTCTL);
	do {
		udelay(1);
		greset = dwc2_readl(hsotg->regs + GRSTCTL);
		if (++count > 50) {
			dev_warn(hsotg->dev,
				 "%s() HANG! Soft Reset GRSTCTL=%0x\n",
				 __func__, greset);

	if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_CSFTRST, 50)) {
		dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL GRSTCTL_CSFTRST\n",
			 __func__);
		return -EBUSY;
	}
	} while (greset & GRSTCTL_CSFTRST);

	/* Wait for AHB master IDLE state */
	count = 0;
	do {
		udelay(1);
		greset = dwc2_readl(hsotg->regs + GRSTCTL);
		if (++count > 50) {
			dev_warn(hsotg->dev,
				 "%s() HANG! AHB Idle GRSTCTL=%0x\n",
				 __func__, greset);
	if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 50)) {
		dev_warn(hsotg->dev, "%s: HANG! AHB Idle timeout GRSTCTL GRSTCTL_AHBIDLE\n",
			 __func__);
		return -EBUSY;
	}
	} while (!(greset & GRSTCTL_AHBIDLE));

	if (wait_for_host_mode && !skip_wait)
		dwc2_wait_for_mode(hsotg, true);
@@ -376,14 +541,14 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
	return 0;
}

/*
 * Force the mode of the controller.
/**
 * dwc2_force_mode() - 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.
 * changes. We do this once during probe.
 *
 * 2) During probe we want to read reset values of the hw
 * configuration registers that are only available in either host or
@@ -400,7 +565,7 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
 * the filter is configured and enabled. We poll the current mode of
 * the controller to account for this delay.
 */
static bool dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host)
void dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host)
{
	u32 gusbcfg;
	u32 set;
@@ -412,17 +577,17 @@ static bool dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host)
	 * Force mode has no effect if the hardware is not OTG.
	 */
	if (!dwc2_hw_is_otg(hsotg))
		return false;
		return;

	/*
	 * If dr_mode is either peripheral or host only, there is no
	 * need to ever force the mode to the opposite mode.
	 */
	if (WARN_ON(host && hsotg->dr_mode == USB_DR_MODE_PERIPHERAL))
		return false;
		return;

	if (WARN_ON(!host && hsotg->dr_mode == USB_DR_MODE_HOST))
		return false;
		return;

	gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);

@@ -434,7 +599,7 @@ static bool dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host)
	dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);

	dwc2_wait_for_mode(hsotg, host);
	return true;
	return;
}

/**
@@ -446,10 +611,15 @@ static bool dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host)
 * the force mode. We only need to call this once during probe if
 * dr_mode == OTG.
 */
void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg)
static void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg)
{
	u32 gusbcfg;

	if (!dwc2_hw_is_otg(hsotg))
		return;

	dev_dbg(hsotg->dev, "Clearing force mode bits\n");

	gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
	gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
	gusbcfg &= ~GUSBCFG_FORCEDEVMODE;
@@ -464,16 +634,13 @@ void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg)
 */
void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg)
{
	bool ret;

	switch (hsotg->dr_mode) {
	case USB_DR_MODE_HOST:
		ret = dwc2_force_mode(hsotg, true);
		/*
		 * NOTE: This is required for some rockchip soc based
		 * platforms on their host-only dwc2.
		 */
		if (!ret)
		if (!dwc2_hw_is_otg(hsotg))
			msleep(50);

		break;
@@ -491,22 +658,17 @@ void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg)
}

/*
 * 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.
 * dwc2_enable_acg - enable active clock gating feature
 */
int dwc2_core_reset_and_force_dr_mode(struct dwc2_hsotg *hsotg)
void dwc2_enable_acg(struct dwc2_hsotg *hsotg)
{
	int retval;

	retval = dwc2_core_reset(hsotg, false);
	if (retval)
		return retval;
	if (hsotg->params.acg_enable) {
		u32 pcgcctl1 = dwc2_readl(hsotg->regs + PCGCCTL1);

	dwc2_force_dr_mode(hsotg);
	return 0;
		dev_dbg(hsotg->dev, "Enabling Active Clock Gating\n");
		pcgcctl1 |= PCGCCTL1_GATEEN;
		dwc2_writel(pcgcctl1, hsotg->regs + PCGCCTL1);
	}
}

/**
@@ -683,25 +845,21 @@ void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg)
void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num)
{
	u32 greset;
	int count = 0;

	dev_vdbg(hsotg->dev, "Flush Tx FIFO %d\n", num);

	/* Wait for AHB master IDLE state */
	if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 10000))
		dev_warn(hsotg->dev, "%s:  HANG! AHB Idle GRSCTL\n",
			 __func__);

	greset = GRSTCTL_TXFFLSH;
	greset |= num << GRSTCTL_TXFNUM_SHIFT & GRSTCTL_TXFNUM_MASK;
	dwc2_writel(greset, hsotg->regs + GRSTCTL);

	do {
		greset = dwc2_readl(hsotg->regs + GRSTCTL);
		if (++count > 10000) {
			dev_warn(hsotg->dev,
				 "%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n",
				 __func__, greset,
				 dwc2_readl(hsotg->regs + GNPTXSTS));
			break;
		}
		udelay(1);
	} while (greset & GRSTCTL_TXFFLSH);
	if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_TXFFLSH, 10000))
		dev_warn(hsotg->dev, "%s:  HANG! timeout GRSTCTL GRSTCTL_TXFFLSH\n",
			 __func__);

	/* Wait for at least 3 PHY Clocks */
	udelay(1);
@@ -715,43 +873,26 @@ void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num)
void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg)
{
	u32 greset;
	int count = 0;

	dev_vdbg(hsotg->dev, "%s()\n", __func__);

	/* Wait for AHB master IDLE state */
	if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 10000))
		dev_warn(hsotg->dev, "%s:  HANG! AHB Idle GRSCTL\n",
			 __func__);

	greset = GRSTCTL_RXFFLSH;
	dwc2_writel(greset, hsotg->regs + GRSTCTL);

	do {
		greset = dwc2_readl(hsotg->regs + GRSTCTL);
		if (++count > 10000) {
			dev_warn(hsotg->dev, "%s() HANG! GRSTCTL=%0x\n",
				 __func__, greset);
			break;
		}
		udelay(1);
	} while (greset & GRSTCTL_RXFFLSH);
	/* Wait for RxFIFO flush done */
	if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_RXFFLSH, 10000))
		dev_warn(hsotg->dev, "%s: HANG! timeout GRSTCTL GRSTCTL_RXFFLSH\n",
			 __func__);

	/* Wait for at least 3 PHY Clocks */
	udelay(1);
}

/*
 * Forces either host or device mode if the controller is not
 * currently in that mode.
 *
 * Returns true if the mode was forced.
 */
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);
}

bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg)
{
	if (dwc2_readl(hsotg->regs + GSNPSID) == 0xffffffff)
@@ -825,6 +966,52 @@ bool dwc2_hw_is_device(struct dwc2_hsotg *hsotg)
		(op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE);
}

/**
 * dwc2_hsotg_wait_bit_set - Waits for bit to be set.
 * @hsotg: Programming view of DWC_otg controller.
 * @offset: Register's offset where bit/bits must be set.
 * @mask: Mask of the bit/bits which must be set.
 * @timeout: Timeout to wait.
 *
 * Return: 0 if bit/bits are set or -ETIMEDOUT in case of timeout.
 */
int dwc2_hsotg_wait_bit_set(struct dwc2_hsotg *hsotg, u32 offset, u32 mask,
			    u32 timeout)
{
	u32 i;

	for (i = 0; i < timeout; i++) {
		if (dwc2_readl(hsotg->regs + offset) & mask)
			return 0;
		udelay(1);
	}

	return -ETIMEDOUT;
}

/**
 * dwc2_hsotg_wait_bit_clear - Waits for bit to be clear.
 * @hsotg: Programming view of DWC_otg controller.
 * @offset: Register's offset where bit/bits must be set.
 * @mask: Mask of the bit/bits which must be set.
 * @timeout: Timeout to wait.
 *
 * Return: 0 if bit/bits are set or -ETIMEDOUT in case of timeout.
 */
int dwc2_hsotg_wait_bit_clear(struct dwc2_hsotg *hsotg, u32 offset, u32 mask,
			      u32 timeout)
{
	u32 i;

	for (i = 0; i < timeout; i++) {
		if (!(dwc2_readl(hsotg->regs + offset) & mask))
			return 0;
		udelay(1);
	}

	return -ETIMEDOUT;
}

MODULE_DESCRIPTION("DESIGNWARE HS OTG Core");
MODULE_AUTHOR("Synopsys, Inc.");
MODULE_LICENSE("Dual BSD/GPL");
+99 −37

File changed.

Preview size limit exceeded, changes collapsed.

+278 −26

File changed.

Preview size limit exceeded, changes collapsed.

Loading