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

Commit 331ac6b2 authored by Alek Du's avatar Alek Du Committed by Greg Kroah-Hartman
Browse files

USB: EHCI: Add Intel Moorestown EHCI controller HOSTPCx extensions and support phy low power mode



The Intel Moorestown EHCI controller supports non-standard HOSTPCx register
extension. This register controls the LPM behaviour and controls the behaviour
of each USB port.

Signed-off-by: default avatarJacob Pan <jacob.jun.pan@intel.com>
Signed-off-by: default avatarAlek Du <alek.du@intel.com>
Acked-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 3807e26d
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -249,6 +249,12 @@ static int ehci_reset (struct ehci_hcd *ehci)
	retval = handshake (ehci, &ehci->regs->command,
			    CMD_RESET, 0, 250 * 1000);

	if (ehci->has_hostpc) {
		ehci_writel(ehci, USBMODE_EX_HC | USBMODE_EX_VBPS,
			(u32 __iomem *)(((u8 *)ehci->regs) + USBMODE_EX));
		ehci_writel(ehci, TXFIFO_DEFAULT,
			(u32 __iomem *)(((u8 *)ehci->regs) + TXFILLTUNING));
	}
	if (retval)
		return retval;

+57 −5
Original line number Diff line number Diff line
@@ -111,6 +111,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
	int			port;
	int			mask;
	u32 __iomem		*hostpc_reg = NULL;

	ehci_dbg(ehci, "suspend root hub\n");

@@ -142,6 +143,9 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
		u32		t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
		u32		t2 = t1;

		if (ehci->has_hostpc)
			hostpc_reg = (u32 __iomem *)((u8 *)ehci->regs
				+ HOSTPC0 + 4 * (port & 0xff));
		/* keep track of which ports we suspend */
		if (t1 & PORT_OWNER)
			set_bit(port, &ehci->owned_ports);
@@ -151,15 +155,37 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
		}

		/* enable remote wakeup on all ports */
		if (hcd->self.root_hub->do_remote_wakeup)
			t2 |= PORT_WAKE_BITS;
		else
		if (hcd->self.root_hub->do_remote_wakeup) {
			/* only enable appropriate wake bits, otherwise the
			 * hardware can not go phy low power mode. If a race
			 * condition happens here(connection change during bits
			 * set), the port change detection will finally fix it.
			 */
			if (t1 & PORT_CONNECT) {
				t2 |= PORT_WKOC_E | PORT_WKDISC_E;
				t2 &= ~PORT_WKCONN_E;
			} else {
				t2 |= PORT_WKOC_E | PORT_WKCONN_E;
				t2 &= ~PORT_WKDISC_E;
			}
		} else
			t2 &= ~PORT_WAKE_BITS;

		if (t1 != t2) {
			ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
				port + 1, t1, t2);
			ehci_writel(ehci, t2, reg);
			if (hostpc_reg) {
				u32	t3;

				msleep(5);/* 5ms for HCD enter low pwr mode */
				t3 = ehci_readl(ehci, hostpc_reg);
				ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg);
				t3 = ehci_readl(ehci, hostpc_reg);
				ehci_dbg(ehci, "Port%d phy low pwr mode %s\n",
					port, (t3 & HOSTPC_PHCD) ?
					"succeeded" : "failed");
			}
		}
	}

@@ -563,7 +589,8 @@ static int ehci_hub_control (
	int		ports = HCS_N_PORTS (ehci->hcs_params);
	u32 __iomem	*status_reg = &ehci->regs->port_status[
				(wIndex & 0xff) - 1];
	u32		temp, status;
	u32 __iomem	*hostpc_reg = NULL;
	u32		temp, temp1, status;
	unsigned long	flags;
	int		retval = 0;
	unsigned	selector;
@@ -575,6 +602,9 @@ static int ehci_hub_control (
	 * power, "this is the one", etc.  EHCI spec supports this.
	 */

	if (ehci->has_hostpc)
		hostpc_reg = (u32 __iomem *)((u8 *)ehci->regs
				+ HOSTPC0 + 4 * ((wIndex & 0xff) - 1));
	spin_lock_irqsave (&ehci->lock, flags);
	switch (typeReq) {
	case ClearHubFeature:
@@ -773,6 +803,10 @@ static int ehci_hub_control (
		if (temp & PORT_CONNECT) {
			status |= 1 << USB_PORT_FEAT_CONNECTION;
			// status may be from integrated TT
			if (ehci->has_hostpc) {
				temp1 = ehci_readl(ehci, hostpc_reg);
				status |= ehci_port_speed(ehci, temp1);
			} else
				status |= ehci_port_speed(ehci, temp);
		}
		if (temp & PORT_PE)
@@ -832,6 +866,24 @@ static int ehci_hub_control (
					|| (temp & PORT_RESET) != 0)
				goto error;
			ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
			/* After above check the port must be connected.
			 * Set appropriate bit thus could put phy into low power
			 * mode if we have hostpc feature
			 */
			if (hostpc_reg) {
				temp &= ~PORT_WKCONN_E;
				temp |= (PORT_WKDISC_E | PORT_WKOC_E);
				ehci_writel(ehci, temp | PORT_SUSPEND,
							status_reg);
				msleep(5);/* 5ms for HCD enter low pwr mode */
				temp1 = ehci_readl(ehci, hostpc_reg);
				ehci_writel(ehci, temp1 | HOSTPC_PHCD,
					hostpc_reg);
				temp1 = ehci_readl(ehci, hostpc_reg);
				ehci_dbg(ehci, "Port%d phy low pwr mode %s\n",
					wIndex, (temp1 & HOSTPC_PHCD) ?
					"succeeded" : "failed");
			}
			set_bit(wIndex, &ehci->suspended_ports);
			break;
		case USB_PORT_FEAT_POWER:
+2 −1
Original line number Diff line number Diff line
@@ -136,6 +136,7 @@ struct ehci_hcd { /* one per controller */
	#define OHCI_HCCTRL_OFFSET      0x4
	#define OHCI_HCCTRL_LEN         0x4
	__hc32			*ohci_hcctrl_reg;
	unsigned		has_hostpc:1;

	u8			sbrn;		/* packed release number */

@@ -548,7 +549,7 @@ static inline unsigned int
ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
{
	if (ehci_is_TDI(ehci)) {
		switch ((portsc>>26)&3) {
		switch ((portsc >> (ehci->has_hostpc ? 25 : 26)) & 3) {
		case 0:
			return 0;
		case 1:
+13 −0
Original line number Diff line number Diff line
@@ -132,6 +132,19 @@ struct ehci_regs {
#define USBMODE_CM_HC	(3<<0)		/* host controller mode */
#define USBMODE_CM_IDLE	(0<<0)		/* idle state */

/* Moorestown has some non-standard registers, partially due to the fact that
 * its EHCI controller has both TT and LPM support. HOSTPCx are extentions to
 * PORTSCx
 */
#define HOSTPC0		0x84		/* HOSTPC extension */
#define HOSTPC_PHCD	(1<<22)		/* Phy clock disable */
#define HOSTPC_PSPD	(3<<25)		/* Port speed detection */
#define USBMODE_EX	0xc8		/* USB Device mode extension */
#define USBMODE_EX_VBPS	(1<<5)		/* VBus Power Select On */
#define USBMODE_EX_HC	(3<<0)		/* host controller mode */
#define TXFILLTUNING	0x24		/* TX FIFO Tuning register */
#define TXFIFO_DEFAULT	(8<<16)		/* FIFO burst threshold 8 */

/* Appendix C, Debug port ... intended for use with special "debug devices"
 * that can help if there's no serial console.  (nonstandard enumeration.)
 */