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

Commit 55db16ad authored by Jack Pham's avatar Jack Pham
Browse files

usb: dwc3: Enable newer refclk-based SOF/ITP generation



Add support for refclk-based SOF and ITP generation, which is
present on DWC3 cores starting in revision 2.50a. This supersedes
the functionality provided by GCTL.SOFTITPSYNC which handled ITP
generation only. This introduces the new GFLADJ register and
writes its fields based on the reference clock period to the
core, which can now be specified as a device tree parameter.

Change-Id: I2c57586cd8b5275b77ebe64cf0835617f0340b62
Signed-off-by: default avatarJack Pham <jackp@codeaurora.org>
parent c255ffa1
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -44,6 +44,8 @@ Optional properties :
  passed to secure channel manager(scm) driver. scm driver uses this device
  id to restore USB controller related security configuration after coming
  out of the controller power collapse.
- qti,ref-clk-rate: Indicates refclk frequency (in Hz) to the core. If not
  specified, default of 19.2MHz is assumed.

Sub nodes:
- Sub node for "DWC3- USB3 controller".
+20 −10
Original line number Diff line number Diff line
@@ -75,22 +75,32 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
	 * if it failed previously to operate in SS mode.
	 */
	reg |= DWC3_GCTL_U2RSTECN;
	if (mode == DWC3_GCTL_PRTCAP_HOST) {
	reg &= ~(DWC3_GCTL_SOFITPSYNC);
	reg &= ~(DWC3_GCTL_PWRDNSCALEMASK);
	reg |= DWC3_GCTL_PWRDNSCALE(2);
	reg |= DWC3_GCTL_U2EXIT_LFPS;
	dwc3_writel(dwc->regs, DWC3_GCTL, reg);

	if (mode == DWC3_GCTL_PRTCAP_OTG || mode == DWC3_GCTL_PRTCAP_HOST) {
		/*
		 * Allow ITP generated off of ref clk based counter instead
		 * of UTMI/ULPI clk based counter, when superspeed only is
		 * active so that UTMI/ULPI PHY can be suspened.
		 *
		 * Starting with revision 2.50A, GFLADJ_REFCLK_LPM_SEL is used
		 * instead.
		 */
		if (dwc->revision < DWC3_REVISION_250A) {
			reg = dwc3_readl(dwc->regs, DWC3_GCTL);
			reg |= DWC3_GCTL_SOFITPSYNC;
		reg &= ~(DWC3_GCTL_PWRDNSCALEMASK);
		reg |= DWC3_GCTL_PWRDNSCALE(2);
	} else if (mode == DWC3_GCTL_PRTCAP_DEVICE) {
		reg &= ~(DWC3_GCTL_PWRDNSCALEMASK);
		reg |= DWC3_GCTL_PWRDNSCALE(2);
		reg &= ~(DWC3_GCTL_SOFITPSYNC);
	}
	reg |= DWC3_GCTL_U2EXIT_LFPS;
			dwc3_writel(dwc->regs, DWC3_GCTL, reg);
		} else {
			reg = dwc3_readl(dwc->regs, DWC3_GFLADJ);
			reg |= DWC3_GFLADJ_REFCLK_LPM_SEL;
			dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
		}
	}

	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
	reg |= DWC3_GUSB3PIPECTL_SUSPHY;
	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+7 −0
Original line number Diff line number Diff line
@@ -138,6 +138,7 @@
#define DWC3_GEVNTCOUNT(n)	(0xc40c + (n * 0x10))

#define DWC3_GHWPARAMS8		0xc600
#define DWC3_GFLADJ		0xc630

/* Device Registers */
#define DWC3_DCFG		0xc700
@@ -219,6 +220,12 @@
/* Global HWPARAMS6 Register */
#define DWC3_GHWPARAMS6_SRP_SUPPORT	(1 << 10)

/* Global Frame Length Adjustment Register */
#define DWC3_GFLADJ_REFCLK_240MHZDECR_PLS1	(1 << 31)
#define DWC3_GFLADJ_REFCLK_240MHZ_DECR		(0x7F << 24)
#define DWC3_GFLADJ_REFCLK_LPM_SEL		(1 << 23)
#define DWC3_GFLADJ_REFCLK_FLADJ		(0x3FFF << 8)

/* Device Configuration Register */
#define DWC3_DCFG_LPM_CAP	(1 << 22)
#define DWC3_DCFG_DEVADDR(addr)	((addr) << 3)
+1 −0
Original line number Diff line number Diff line
@@ -231,6 +231,7 @@ static const struct debugfs_reg32 dwc3_regs[] = {
	dump_register(GEVNTCOUNT(0)),

	dump_register(GHWPARAMS8),
	dump_register(GFLADJ),
	dump_register(DCFG),
	dump_register(DCTL),
	dump_register(DEVTEN),
+49 −1
Original line number Diff line number Diff line
@@ -196,6 +196,7 @@ struct dwc3_msm {
	struct clk		*sleep_clk;
	struct clk		*hsphy_sleep_clk;
	struct clk		*utmi_clk;
	unsigned long		ref_clk_rate;
	struct regulator	*dwc3_gdsc;

	struct usb_phy		*hs_phy, *ss_phy;
@@ -1159,6 +1160,48 @@ static int dwc3_msm_link_clk_reset(struct dwc3_msm *mdwc, bool assert)
	return ret;
}

static void dwc3_msm_update_ref_clk(struct dwc3_msm *mdwc)
{
	u32 guctl, gfladj = 0;

	guctl = dwc3_msm_read_reg(mdwc->base, DWC3_GUCTL);
	guctl &= ~DWC3_GUCTL_REFCLKPER;

	/* GFLADJ register is used starting with revision 2.50a */
	if (dwc3_msm_read_reg(mdwc->base, DWC3_GSNPSID) >= DWC3_REVISION_250A) {
		gfladj = dwc3_msm_read_reg(mdwc->base, DWC3_GFLADJ);
		gfladj &= ~DWC3_GFLADJ_REFCLK_240MHZDECR_PLS1;
		gfladj &= ~DWC3_GFLADJ_REFCLK_240MHZ_DECR;
		gfladj &= ~DWC3_GFLADJ_REFCLK_LPM_SEL;
		gfladj &= ~DWC3_GFLADJ_REFCLK_FLADJ;
	}

	/* Refer to SNPS Databook Table 6-55 for calculations used */
	switch (mdwc->ref_clk_rate) {
	case 19200000:
		guctl |= 52 << __ffs(DWC3_GUCTL_REFCLKPER);
		gfladj |= 12 << __ffs(DWC3_GFLADJ_REFCLK_240MHZ_DECR);
		gfladj |= DWC3_GFLADJ_REFCLK_240MHZDECR_PLS1;
		gfladj |= DWC3_GFLADJ_REFCLK_LPM_SEL;
		gfladj |= 200 << __ffs(DWC3_GFLADJ_REFCLK_FLADJ);
		break;
	case 24000000:
		guctl |= 41 << __ffs(DWC3_GUCTL_REFCLKPER);
		gfladj |= 10 << __ffs(DWC3_GFLADJ_REFCLK_240MHZ_DECR);
		gfladj |= DWC3_GFLADJ_REFCLK_LPM_SEL;
		gfladj |= 2032 << __ffs(DWC3_GFLADJ_REFCLK_FLADJ);
		break;
	default:
		dev_warn(mdwc->dev, "Unsupported ref_clk_rate: %lu\n",
				mdwc->ref_clk_rate);
		break;
	}

	dwc3_msm_write_reg(mdwc->base, DWC3_GUCTL, guctl);
	if (gfladj)
		dwc3_msm_write_reg(mdwc->base, DWC3_GFLADJ, gfladj);
}

/* Initialize QSCRATCH registers for HSPHY and SSPHY operation */
static void dwc3_msm_qscratch_reg_init(struct dwc3_msm *mdwc)
{
@@ -1210,6 +1253,7 @@ static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned event)
				"DWC3_CONTROLLER_POST_RESET_EVENT received\n");
		/* Re-initialize SSPHY after reset */
		usb_phy_set_params(mdwc->ss_phy);
		dwc3_msm_update_ref_clk(mdwc);
		dwc3_msm_restore_sec_config(mdwc->scm_dev_id);
		dwc->tx_fifo_size = mdwc->tx_fifo_size;
		break;
@@ -2452,7 +2496,11 @@ static int dwc3_msm_probe(struct platform_device *pdev)
		ret = PTR_ERR(mdwc->ref_clk);
		goto disable_utmi_clk;
	}
	clk_set_rate(mdwc->ref_clk, 19200000);
	ret = of_property_read_u32(node, "qti,ref-clk-rate",
				   (u32 *)&mdwc->ref_clk_rate);
	if (ret)
		mdwc->ref_clk_rate = 19200000;
	clk_set_rate(mdwc->ref_clk, mdwc->ref_clk_rate);
	clk_prepare_enable(mdwc->ref_clk);

	mdwc->id_state = mdwc->ext_xceiv.id = DWC3_ID_FLOAT;