Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Jacob Pan <jacob.jun.pan@intel.com>
Signed-off-by: Alek Du <alek.du@intel.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>


authored by

Alek Du and committed by
Greg Kroah-Hartman
331ac6b2 3807e26d

+78 -6
+6
drivers/usb/host/ehci-hcd.c
··· 249 249 retval = handshake (ehci, &ehci->regs->command, 250 250 CMD_RESET, 0, 250 * 1000); 251 251 252 + if (ehci->has_hostpc) { 253 + ehci_writel(ehci, USBMODE_EX_HC | USBMODE_EX_VBPS, 254 + (u32 __iomem *)(((u8 *)ehci->regs) + USBMODE_EX)); 255 + ehci_writel(ehci, TXFIFO_DEFAULT, 256 + (u32 __iomem *)(((u8 *)ehci->regs) + TXFILLTUNING)); 257 + } 252 258 if (retval) 253 259 return retval; 254 260
+57 -5
drivers/usb/host/ehci-hub.c
··· 111 111 struct ehci_hcd *ehci = hcd_to_ehci (hcd); 112 112 int port; 113 113 int mask; 114 + u32 __iomem *hostpc_reg = NULL; 114 115 115 116 ehci_dbg(ehci, "suspend root hub\n"); 116 117 ··· 143 142 u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; 144 143 u32 t2 = t1; 145 144 145 + if (ehci->has_hostpc) 146 + hostpc_reg = (u32 __iomem *)((u8 *)ehci->regs 147 + + HOSTPC0 + 4 * (port & 0xff)); 146 148 /* keep track of which ports we suspend */ 147 149 if (t1 & PORT_OWNER) 148 150 set_bit(port, &ehci->owned_ports); ··· 155 151 } 156 152 157 153 /* enable remote wakeup on all ports */ 158 - if (hcd->self.root_hub->do_remote_wakeup) 159 - t2 |= PORT_WAKE_BITS; 160 - else 154 + if (hcd->self.root_hub->do_remote_wakeup) { 155 + /* only enable appropriate wake bits, otherwise the 156 + * hardware can not go phy low power mode. If a race 157 + * condition happens here(connection change during bits 158 + * set), the port change detection will finally fix it. 159 + */ 160 + if (t1 & PORT_CONNECT) { 161 + t2 |= PORT_WKOC_E | PORT_WKDISC_E; 162 + t2 &= ~PORT_WKCONN_E; 163 + } else { 164 + t2 |= PORT_WKOC_E | PORT_WKCONN_E; 165 + t2 &= ~PORT_WKDISC_E; 166 + } 167 + } else 161 168 t2 &= ~PORT_WAKE_BITS; 162 169 163 170 if (t1 != t2) { 164 171 ehci_vdbg (ehci, "port %d, %08x -> %08x\n", 165 172 port + 1, t1, t2); 166 173 ehci_writel(ehci, t2, reg); 174 + if (hostpc_reg) { 175 + u32 t3; 176 + 177 + msleep(5);/* 5ms for HCD enter low pwr mode */ 178 + t3 = ehci_readl(ehci, hostpc_reg); 179 + ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg); 180 + t3 = ehci_readl(ehci, hostpc_reg); 181 + ehci_dbg(ehci, "Port%d phy low pwr mode %s\n", 182 + port, (t3 & HOSTPC_PHCD) ? 183 + "succeeded" : "failed"); 184 + } 167 185 } 168 186 } 169 187 ··· 589 563 int ports = HCS_N_PORTS (ehci->hcs_params); 590 564 u32 __iomem *status_reg = &ehci->regs->port_status[ 591 565 (wIndex & 0xff) - 1]; 592 - u32 temp, status; 566 + u32 __iomem *hostpc_reg = NULL; 567 + u32 temp, temp1, status; 593 568 unsigned long flags; 594 569 int retval = 0; 595 570 unsigned selector; ··· 602 575 * power, "this is the one", etc. EHCI spec supports this. 603 576 */ 604 577 578 + if (ehci->has_hostpc) 579 + hostpc_reg = (u32 __iomem *)((u8 *)ehci->regs 580 + + HOSTPC0 + 4 * ((wIndex & 0xff) - 1)); 605 581 spin_lock_irqsave (&ehci->lock, flags); 606 582 switch (typeReq) { 607 583 case ClearHubFeature: ··· 803 773 if (temp & PORT_CONNECT) { 804 774 status |= 1 << USB_PORT_FEAT_CONNECTION; 805 775 // status may be from integrated TT 806 - status |= ehci_port_speed(ehci, temp); 776 + if (ehci->has_hostpc) { 777 + temp1 = ehci_readl(ehci, hostpc_reg); 778 + status |= ehci_port_speed(ehci, temp1); 779 + } else 780 + status |= ehci_port_speed(ehci, temp); 807 781 } 808 782 if (temp & PORT_PE) 809 783 status |= 1 << USB_PORT_FEAT_ENABLE; ··· 866 832 || (temp & PORT_RESET) != 0) 867 833 goto error; 868 834 ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); 835 + /* After above check the port must be connected. 836 + * Set appropriate bit thus could put phy into low power 837 + * mode if we have hostpc feature 838 + */ 839 + if (hostpc_reg) { 840 + temp &= ~PORT_WKCONN_E; 841 + temp |= (PORT_WKDISC_E | PORT_WKOC_E); 842 + ehci_writel(ehci, temp | PORT_SUSPEND, 843 + status_reg); 844 + msleep(5);/* 5ms for HCD enter low pwr mode */ 845 + temp1 = ehci_readl(ehci, hostpc_reg); 846 + ehci_writel(ehci, temp1 | HOSTPC_PHCD, 847 + hostpc_reg); 848 + temp1 = ehci_readl(ehci, hostpc_reg); 849 + ehci_dbg(ehci, "Port%d phy low pwr mode %s\n", 850 + wIndex, (temp1 & HOSTPC_PHCD) ? 851 + "succeeded" : "failed"); 852 + } 869 853 set_bit(wIndex, &ehci->suspended_ports); 870 854 break; 871 855 case USB_PORT_FEAT_POWER:
+2 -1
drivers/usb/host/ehci.h
··· 136 136 #define OHCI_HCCTRL_OFFSET 0x4 137 137 #define OHCI_HCCTRL_LEN 0x4 138 138 __hc32 *ohci_hcctrl_reg; 139 + unsigned has_hostpc:1; 139 140 140 141 u8 sbrn; /* packed release number */ 141 142 ··· 549 548 ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc) 550 549 { 551 550 if (ehci_is_TDI(ehci)) { 552 - switch ((portsc>>26)&3) { 551 + switch ((portsc >> (ehci->has_hostpc ? 25 : 26)) & 3) { 553 552 case 0: 554 553 return 0; 555 554 case 1:
+13
include/linux/usb/ehci_def.h
··· 132 132 #define USBMODE_CM_HC (3<<0) /* host controller mode */ 133 133 #define USBMODE_CM_IDLE (0<<0) /* idle state */ 134 134 135 + /* Moorestown has some non-standard registers, partially due to the fact that 136 + * its EHCI controller has both TT and LPM support. HOSTPCx are extentions to 137 + * PORTSCx 138 + */ 139 + #define HOSTPC0 0x84 /* HOSTPC extension */ 140 + #define HOSTPC_PHCD (1<<22) /* Phy clock disable */ 141 + #define HOSTPC_PSPD (3<<25) /* Port speed detection */ 142 + #define USBMODE_EX 0xc8 /* USB Device mode extension */ 143 + #define USBMODE_EX_VBPS (1<<5) /* VBus Power Select On */ 144 + #define USBMODE_EX_HC (3<<0) /* host controller mode */ 145 + #define TXFILLTUNING 0x24 /* TX FIFO Tuning register */ 146 + #define TXFIFO_DEFAULT (8<<16) /* FIFO burst threshold 8 */ 147 + 135 148 /* Appendix C, Debug port ... intended for use with special "debug devices" 136 149 * that can help if there's no serial console. (nonstandard enumeration.) 137 150 */