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

Commit 802fde98 authored by Paul Zimmerman's avatar Paul Zimmerman Committed by Felipe Balbi
Browse files

usb: dwc3: support new revisions of DWC3 core



Recent cores (>= 1.94a) have a set of new features,
commands and a slightly different programming model.

This patch aims to support those changes.

Signed-off-by: default avatarPaul Zimmerman <paulz@synopsys.com>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent d7a46a8d
Loading
Loading
Loading
Loading
+70 −13
Original line number Diff line number Diff line
@@ -100,6 +100,23 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
	int		retries = 10000;
	u32		reg;

	/*
	 * Wait until device controller is ready. Only applies to 1.94a and
	 * later RTL.
	 */
	if (dwc->revision >= DWC3_REVISION_194A) {
		while (--retries) {
			reg = dwc3_readl(dwc->regs, DWC3_DSTS);
			if (reg & DWC3_DSTS_DCNRD)
				udelay(5);
			else
				break;
		}

		if (retries <= 0)
			return -ETIMEDOUT;
	}

	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
	reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;

@@ -107,6 +124,13 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
	reg |= DWC3_DCTL_ULSTCHNGREQ(state);
	dwc3_writel(dwc->regs, DWC3_DCTL, reg);

	/*
	 * The following code is racy when called from dwc3_gadget_wakeup,
	 * and is not needed, at least on newer versions
	 */
	if (dwc->revision >= DWC3_REVISION_194A)
		return 0;

	/* wait for a change in DSTS */
	retries = 10000;
	while (--retries) {
@@ -266,8 +290,8 @@ static const char *dwc3_gadget_ep_cmd_string(u8 cmd)
		return "Clear Stall";
	case DWC3_DEPCMD_SETSTALL:
		return "Set Stall";
	case DWC3_DEPCMD_GETSEQNUMBER:
		return "Get Data Sequence Number";
	case DWC3_DEPCMD_GETEPSTATE:
		return "Get Endpoint State";
	case DWC3_DEPCMD_SETTRANSFRESOURCE:
		return "Set Endpoint Transfer Resource";
	case DWC3_DEPCMD_SETEPCONFIG:
@@ -1280,9 +1304,12 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
		goto out;
	}

	/* Recent versions do this automatically */
	if (dwc->revision < DWC3_REVISION_194A) {
		/* write zeroes to Link Change Request */
		reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
	}

	/* poll until Link State changes to ON */
	timeout = jiffies + msecs_to_jiffies(100);
@@ -1326,9 +1353,14 @@ static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)

	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
	if (is_on) {
		if (dwc->revision <= DWC3_REVISION_187A) {
			reg &= ~DWC3_DCTL_TRGTULST_MASK;
		reg |= (DWC3_DCTL_RUN_STOP
				| DWC3_DCTL_TRGTULST_RX_DET);
			reg |= DWC3_DCTL_TRGTULST_RX_DET;
		}

		if (dwc->revision >= DWC3_REVISION_194A)
			reg &= ~DWC3_DCTL_KEEP_CONNECT;
		reg |= DWC3_DCTL_RUN_STOP;
	} else {
		reg &= ~DWC3_DCTL_RUN_STOP;
	}
@@ -1468,6 +1500,7 @@ static int dwc3_gadget_stop(struct usb_gadget *g,

	return 0;
}

static const struct usb_gadget_ops dwc3_gadget_ops = {
	.get_frame		= dwc3_gadget_get_frame,
	.wakeup			= dwc3_gadget_wakeup,
@@ -1962,9 +1995,12 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
	/* after reset -> Default State */
	dwc->dev_state = DWC3_DEFAULT_STATE;

	/* Recent versions support automatic phy suspend and don't need this */
	if (dwc->revision < DWC3_REVISION_194A) {
		/* Resume PHYs */
		dwc3_gadget_usb2_phy_suspend(dwc, false);
		dwc3_gadget_usb3_phy_suspend(dwc, false);
	}

	if (dwc->gadget.speed != USB_SPEED_UNKNOWN)
		dwc3_disconnect_gadget(dwc);
@@ -2082,8 +2118,11 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
		break;
	}

	/* Suspend unneded PHY */
	/* Recent versions support automatic phy suspend and don't need this */
	if (dwc->revision < DWC3_REVISION_194A) {
		/* Suspend unneeded PHY */
		dwc3_gadget_phy_suspend(dwc, dwc->gadget.speed);
	}

	dep = dwc->eps[0];
	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
@@ -2389,6 +2428,24 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
			DWC3_DEVTEN_DISCONNEVTEN);
	dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);

	/* Enable USB2 LPM and automatic phy suspend only on recent versions */
	if (dwc->revision >= DWC3_REVISION_194A) {
		reg = dwc3_readl(dwc->regs, DWC3_DCFG);
		reg |= DWC3_DCFG_LPM_CAP;
		dwc3_writel(dwc->regs, DWC3_DCFG, reg);

		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
		reg &= ~(DWC3_DCTL_HIRD_THRES_MASK | DWC3_DCTL_L1_HIBER_EN);

		/* TODO: This should be configurable */
		reg |= DWC3_DCTL_HIRD_THRES(31);

		dwc3_writel(dwc->regs, DWC3_DCTL, reg);

		dwc3_gadget_usb2_phy_suspend(dwc, true);
		dwc3_gadget_usb3_phy_suspend(dwc, true);
	}

	ret = device_register(&dwc->gadget.dev);
	if (ret) {
		dev_err(dwc->dev, "failed to register gadget device\n");