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

Commit e3c6043d authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "USB: dwc3: Implement revised initialization sequence"

parents e1e2e536 6378d95f
Loading
Loading
Loading
Loading
+61 −62
Original line number Diff line number Diff line
@@ -111,20 +111,16 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
}

/**
 * dwc3_core_soft_reset_after_phy_init - Issues core soft reset
 * and PHY reset for HW versions which require core reset after
 * PHY initialization and reset
 * Peforms initialization of HS and SS PHYs.
 * If used as a part of POR or init sequence it is recommended
 * that we should perform hard reset of the PHYs prior to invoking
 * this function.
 * @dwc: pointer to our context structure
*/
static int dwc3_core_soft_reset_after_phy_init(struct dwc3 *dwc)
static int dwc3_init_usb_phys(struct dwc3 *dwc)
{
	u32		reg;
	int		ret;

	/* Reset PHYs */
	usb_phy_reset(dwc->usb3_phy);
	usb_phy_reset(dwc->usb2_phy);

	/* Bring up PHYs */
	ret = usb_phy_init(dwc->usb2_phy);
	if (ret) {
@@ -139,85 +135,90 @@ static int dwc3_core_soft_reset_after_phy_init(struct dwc3 *dwc)
		return ret;
	}

	/* Put Core in Reset */
	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
	reg |= DWC3_GCTL_CORESOFTRESET;
	dwc3_writel(dwc->regs, DWC3_GCTL, reg);

	dwc3_notify_event(dwc, DWC3_CONTROLLER_RESET_EVENT);

	/* Take Core out of reset state */
	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
	reg &= ~DWC3_GCTL_CORESOFTRESET;
	dwc3_writel(dwc->regs, DWC3_GCTL, reg);

	dwc3_notify_event(dwc, DWC3_CONTROLLER_POST_RESET_EVENT);

	return 0;
}

/**
 * dwc3_core_soft_reset - Issues core soft reset and PHY reset
 * Peforms core soft reset and PHY soft reset of HS and SS PHYs.
 * If used as a part of POR or init sequence it is recommended
 * that we should perform hard reset and init of the PHYs prior
 * to invoking this function.
 * @dwc: pointer to our context structure
*/
static int dwc3_core_soft_reset(struct dwc3 *dwc)
static void dwc3_core_and_phy_soft_reset(struct dwc3 *dwc)
{
	u32		reg;
	int		ret;

	if (dwc->core_reset_after_phy_init)
		return dwc3_core_soft_reset_after_phy_init(dwc);

	/* Before Resetting PHY, put Core in Reset */
	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
	reg |= DWC3_GCTL_CORESOFTRESET;
	dwc3_writel(dwc->regs, DWC3_GCTL, reg);

	/* Bring up PHYs */
	ret = usb_phy_init(dwc->usb2_phy);
	if (ret) {
		pr_err("%s: usb_phy_init(dwc->usb2_phy) returned %d\n",
				__func__, ret);
		return ret;
	}
	ret = usb_phy_init(dwc->usb3_phy);
	if (ret) {
		pr_err("%s: usb_phy_init(dwc->usb3_phy) returned %d\n",
				__func__, ret);
		return ret;
	}

	dwc3_notify_event(dwc, DWC3_CONTROLLER_RESET_EVENT);

	/* Assert USB3 PHY reset */
	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
	reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);

	/* Assert USB2 PHY reset */
	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
	reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);

	mdelay(100);
	msleep(100);

	/* Clear USB3 PHY reset */
	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
	reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);

	if (dwc->revision >= DWC3_REVISION_270A) {
		reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
		reg |= DWC3_GUSB3PIPECTL_DELAYP1TRANS;
		dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
	}

	/* Assert USB2 PHY reset */
	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
	reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);

	msleep(100);

	/* Clear USB2 PHY reset */
	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
	reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);

	mdelay(100);
	msleep(100);

	/* After PHYs are stable we can take Core out of reset state */
	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
	reg &= ~DWC3_GCTL_CORESOFTRESET;
	dwc3_writel(dwc->regs, DWC3_GCTL, reg);

	msleep(100);
}

/**
 * dwc3_core_soft_reset - Issues core soft reset and PHY reset
 * @dwc: pointer to our context structure
 */
static int dwc3_core_reset(struct dwc3 *dwc)
{
	int		ret;

	/* Reset PHYs */
	usb_phy_reset(dwc->usb2_phy);
	usb_phy_reset(dwc->usb3_phy);

	/* Initialize PHYs */
	ret = dwc3_init_usb_phys(dwc);
	if (ret) {
		pr_err("%s: dwc3_init_phys returned %d\n",
				__func__, ret);
		return ret;
	}

	dwc3_notify_event(dwc, DWC3_CONTROLLER_RESET_EVENT);

	/* Perform core and PHY soft reset */
	dwc3_core_and_phy_soft_reset(dwc);

	dwc3_notify_event(dwc, DWC3_CONTROLLER_POST_RESET_EVENT);

	return 0;
@@ -400,7 +401,7 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc)
 *
 * Returns 0 on success otherwise negative errno.
 */
static int dwc3_core_init(struct dwc3 *dwc)
int dwc3_core_init(struct dwc3 *dwc)
{
	unsigned long		timeout;
	u32			reg;
@@ -415,6 +416,11 @@ static int dwc3_core_init(struct dwc3 *dwc)
	}
	dwc->revision = reg;


	ret = dwc3_core_reset(dwc);
	if (ret)
		goto err0;

	/* issue device SoftReset too */
	timeout = jiffies + msecs_to_jiffies(500);
	dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
@@ -432,10 +438,6 @@ static int dwc3_core_init(struct dwc3 *dwc)
		cpu_relax();
	} while (true);

	ret = dwc3_core_soft_reset(dwc);
	if (ret)
		goto err0;

	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
	reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
	reg &= ~DWC3_GCTL_DISSCRAMBLE;
@@ -619,9 +621,6 @@ static int dwc3_probe(struct platform_device *pdev)
		return -ENOMEM;
	}

	dwc->core_reset_after_phy_init =
		of_property_read_bool(node, "snps,core-reset-after-phy-init");

	dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
	host_only_mode = of_property_read_bool(node, "snps,host-only-mode");
	dwc->ssphy_clear_auto_suspend_on_disconnect =
+7 −1
Original line number Diff line number Diff line
@@ -165,6 +165,10 @@

/* Bit fields */

/* Global SoC Bus Configuration Register 1 */
#define DWC3_GSBUSCFG1_PIPETRANSLIMIT_MASK	(0x0f << 8)
#define DWC3_GSBUSCFG1_PIPETRANSLIMIT(n)	((n) << 8)

/* Global Configuration Register */
#define DWC3_GCTL_PWRDNSCALE(n)	((n) << 19)
#define DWC3_GCTL_PWRDNSCALEMASK (0xFFF80000)
@@ -205,6 +209,7 @@
#define DWC3_GUSB3PIPECTL_PHYSOFTRST	(1 << 31)
#define DWC3_GUSB3PIPECTL_SUSPHY	(1 << 17)
#define DWC3_GUSB3PIPECTL_DELAY_P1P2P3	(7 << 19)
#define DWC3_GUSB3PIPECTL_DELAYP1TRANS  (1 << 18)
#define DWC3_GUSB3PIPECTL_DIS_RXDET_U3_RXDET (1 << 22)
#define DWC3_GUSB3PIPECTL_ELASTIC_BUF_MODE	(1 << 0)

@@ -845,6 +850,7 @@ struct dwc3 {
#define DWC3_REVISION_230A	0x5533230a
#define DWC3_REVISION_240A	0x5533240a
#define DWC3_REVISION_250A	0x5533250a
#define DWC3_REVISION_270A	0x5533270a

	unsigned		is_selfpowered:1;
	unsigned		three_stage_setup:1;
@@ -891,7 +897,6 @@ struct dwc3 {
	bool			tx_fifo_reduced;

	bool			nominal_elastic_buffer;
	bool			core_reset_after_phy_init;
	bool			err_evt_seen;
	bool			ssphy_clear_auto_suspend_on_disconnect;
	bool			usb3_u1u2_disable;
@@ -1098,6 +1103,7 @@ static void dwc3_gadget_usb3_phy_suspend(struct dwc3 *dwc, int suspend) { }
#endif /* !IS_ENABLED(CONFIG_USB_DWC3_HOST) */

void dwc3_gadget_restart(struct dwc3 *dwc);
int dwc3_core_init(struct dwc3 *dwc);
void dwc3_post_host_reset_core_init(struct dwc3 *dwc);
int dwc3_event_buffers_setup(struct dwc3 *dwc);

+23 −40
Original line number Diff line number Diff line
@@ -1028,6 +1028,8 @@ static int dwc3_msm_link_clk_reset(struct dwc3_msm *mdwc, bool assert)
		dev_dbg(mdwc->dev, "block_reset ASSERT\n");
		clk_disable_unprepare(mdwc->ref_clk);
		clk_disable_unprepare(mdwc->iface_clk);
		clk_disable_unprepare(mdwc->utmi_clk);
		clk_disable_unprepare(mdwc->sleep_clk);
		clk_disable_unprepare(mdwc->core_clk);
		ret = clk_reset(mdwc->core_clk, CLK_RESET_ASSERT);
		if (ret)
@@ -1037,6 +1039,8 @@ static int dwc3_msm_link_clk_reset(struct dwc3_msm *mdwc, bool assert)
		ret = clk_reset(mdwc->core_clk, CLK_RESET_DEASSERT);
		ndelay(200);
		clk_prepare_enable(mdwc->core_clk);
		clk_prepare_enable(mdwc->sleep_clk);
		clk_prepare_enable(mdwc->utmi_clk);
		clk_prepare_enable(mdwc->ref_clk);
		clk_prepare_enable(mdwc->iface_clk);
		if (ret)
@@ -1450,46 +1454,8 @@ static void dwc3_start_chg_det(struct dwc3_charger *charger, bool start)

static void dwc3_msm_power_collapse_por(struct dwc3_msm *mdwc)
{
	u32		reg;
	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);

	/* Put Core in Reset */
	reg = dwc3_msm_read_reg(mdwc->base, DWC3_GCTL);
	reg |= DWC3_GCTL_CORESOFTRESET;
	dwc3_msm_write_reg(mdwc->base, DWC3_GCTL, reg);

	usb_phy_init(dwc->usb2_phy);

	/* Assert USB3 PHY reset */
	reg = dwc3_msm_read_reg(mdwc->base, DWC3_GUSB3PIPECTL(0));
	reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
	dwc3_msm_write_reg(mdwc->base, DWC3_GUSB3PIPECTL(0), reg);

	/* Assert USB2 PHY reset */
	reg = dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0));
	reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
	dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0), reg);

	udelay(100);

	/* Clear USB3 PHY reset */
	reg = dwc3_msm_read_reg(mdwc->base, DWC3_GUSB3PIPECTL(0));
	reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
	dwc3_msm_write_reg(mdwc->base, DWC3_GUSB3PIPECTL(0), reg);

	/* Clear USB2 PHY reset */
	reg = dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0));
	reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
	dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0), reg);

	udelay(100);
	/* After PHYs are stable we can take Core out of reset state */
	reg = dwc3_msm_read_reg(mdwc->base, DWC3_GCTL);
	reg &= ~DWC3_GCTL_CORESOFTRESET;
	dwc3_msm_write_reg(mdwc->base, DWC3_GCTL, reg);

	udelay(100);

	dwc3_core_init(dwc);
	/* Re-configure event buffers */
	dwc3_event_buffers_setup(dwc);
}
@@ -1714,6 +1680,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
		mdwc->lpm_flags |= MDWC3_POWER_COLLAPSE;
		dev_dbg(mdwc->dev, "%s: power collapse\n", __func__);
		dwc3_msm_config_gdsc(mdwc, 0);
		clk_disable_unprepare(mdwc->sleep_clk);
	}

	clk_disable_unprepare(mdwc->iface_clk);
@@ -1832,7 +1799,6 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc)
			clk_reset(mdwc->phy_com_reset, CLK_RESET_DEASSERT);
	}

	clk_prepare_enable(mdwc->utmi_clk);

	if (mdwc->lpm_flags & MDWC3_PHY_REF_CLK_OFF) {
		clk_prepare_enable(mdwc->ref_clk);
@@ -1848,6 +1814,11 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc)
		mdwc->lpm_flags &= ~MDWC3_CORECLK_OFF;
	}

	clk_prepare_enable(mdwc->utmi_clk);

	if (mdwc->lpm_flags & MDWC3_POWER_COLLAPSE)
		clk_prepare_enable(mdwc->sleep_clk);

	usb_phy_set_suspend(mdwc->hs_phy, 0);

	/* Recover from controller power collapse */
@@ -1862,6 +1833,13 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc)
			return ret;
		}

		/* Reset SS PHY */
		ret = usb_phy_reset(mdwc->ss_phy);
		if (ret) {
			dev_err(mdwc->dev, "ssphy reset failed\n");
			return ret;
		}

		ret = dwc3_msm_restore_sec_config(mdwc->scm_dev_id);
		if (ret)
			return ret;
@@ -3146,6 +3124,11 @@ static int dwc3_msm_probe(struct platform_device *pdev)
		}
	}

	/* Perform controller GCC reset */
	dwc3_msm_link_clk_reset(mdwc, 1);
	msleep(20);
	dwc3_msm_link_clk_reset(mdwc, 0);

	ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
	if (ret) {
		dev_err(&pdev->dev,
+10 −0
Original line number Diff line number Diff line
@@ -2107,6 +2107,16 @@ static int __dwc3_gadget_start(struct dwc3 *dwc)
	}
	dwc3_writel(dwc->regs, DWC3_DCFG, reg);

	/* Programs the number of outstanding pipelined transfer requests
	 * the AXI master pushes to the AXI slave.
	 */
	if (dwc->revision >= DWC3_REVISION_270A) {
		reg = dwc3_readl(dwc->regs, DWC3_GSBUSCFG1);
		reg &= ~DWC3_GSBUSCFG1_PIPETRANSLIMIT_MASK;
		reg |= DWC3_GSBUSCFG1_PIPETRANSLIMIT(0xe);
		dwc3_writel(dwc->regs, DWC3_GSBUSCFG1, reg);
	}

	dwc->start_config_issued = false;

	/* Start with SuperSpeed Default */