aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/host/ehci-hcd.c6
-rw-r--r--drivers/usb/host/ehci-hub.c62
-rw-r--r--drivers/usb/host/ehci.h3
-rw-r--r--include/linux/usb/ehci_def.h13
4 files changed, 78 insertions, 6 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 7bee1638dfd7..5fbc67c5a913 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -249,6 +249,12 @@ static int ehci_reset (struct ehci_hcd *ehci)
249 retval = handshake (ehci, &ehci->regs->command, 249 retval = handshake (ehci, &ehci->regs->command,
250 CMD_RESET, 0, 250 * 1000); 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 if (retval) 258 if (retval)
253 return retval; 259 return retval;
254 260
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index f46ad27c9a90..6fef1ee7d101 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -111,6 +111,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
111 struct ehci_hcd *ehci = hcd_to_ehci (hcd); 111 struct ehci_hcd *ehci = hcd_to_ehci (hcd);
112 int port; 112 int port;
113 int mask; 113 int mask;
114 u32 __iomem *hostpc_reg = NULL;
114 115
115 ehci_dbg(ehci, "suspend root hub\n"); 116 ehci_dbg(ehci, "suspend root hub\n");
116 117
@@ -142,6 +143,9 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
142 u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; 143 u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
143 u32 t2 = t1; 144 u32 t2 = t1;
144 145
146 if (ehci->has_hostpc)
147 hostpc_reg = (u32 __iomem *)((u8 *)ehci->regs
148 + HOSTPC0 + 4 * (port & 0xff));
145 /* keep track of which ports we suspend */ 149 /* keep track of which ports we suspend */
146 if (t1 & PORT_OWNER) 150 if (t1 & PORT_OWNER)
147 set_bit(port, &ehci->owned_ports); 151 set_bit(port, &ehci->owned_ports);
@@ -151,15 +155,37 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
151 } 155 }
152 156
153 /* enable remote wakeup on all ports */ 157 /* enable remote wakeup on all ports */
154 if (hcd->self.root_hub->do_remote_wakeup) 158 if (hcd->self.root_hub->do_remote_wakeup) {
155 t2 |= PORT_WAKE_BITS; 159 /* only enable appropriate wake bits, otherwise the
156 else 160 * hardware can not go phy low power mode. If a race
161 * condition happens here(connection change during bits
162 * set), the port change detection will finally fix it.
163 */
164 if (t1 & PORT_CONNECT) {
165 t2 |= PORT_WKOC_E | PORT_WKDISC_E;
166 t2 &= ~PORT_WKCONN_E;
167 } else {
168 t2 |= PORT_WKOC_E | PORT_WKCONN_E;
169 t2 &= ~PORT_WKDISC_E;
170 }
171 } else
157 t2 &= ~PORT_WAKE_BITS; 172 t2 &= ~PORT_WAKE_BITS;
158 173
159 if (t1 != t2) { 174 if (t1 != t2) {
160 ehci_vdbg (ehci, "port %d, %08x -> %08x\n", 175 ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
161 port + 1, t1, t2); 176 port + 1, t1, t2);
162 ehci_writel(ehci, t2, reg); 177 ehci_writel(ehci, t2, reg);
178 if (hostpc_reg) {
179 u32 t3;
180
181 msleep(5);/* 5ms for HCD enter low pwr mode */
182 t3 = ehci_readl(ehci, hostpc_reg);
183 ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg);
184 t3 = ehci_readl(ehci, hostpc_reg);
185 ehci_dbg(ehci, "Port%d phy low pwr mode %s\n",
186 port, (t3 & HOSTPC_PHCD) ?
187 "succeeded" : "failed");
188 }
163 } 189 }
164 } 190 }
165 191
@@ -563,7 +589,8 @@ static int ehci_hub_control (
563 int ports = HCS_N_PORTS (ehci->hcs_params); 589 int ports = HCS_N_PORTS (ehci->hcs_params);
564 u32 __iomem *status_reg = &ehci->regs->port_status[ 590 u32 __iomem *status_reg = &ehci->regs->port_status[
565 (wIndex & 0xff) - 1]; 591 (wIndex & 0xff) - 1];
566 u32 temp, status; 592 u32 __iomem *hostpc_reg = NULL;
593 u32 temp, temp1, status;
567 unsigned long flags; 594 unsigned long flags;
568 int retval = 0; 595 int retval = 0;
569 unsigned selector; 596 unsigned selector;
@@ -575,6 +602,9 @@ static int ehci_hub_control (
575 * power, "this is the one", etc. EHCI spec supports this. 602 * power, "this is the one", etc. EHCI spec supports this.
576 */ 603 */
577 604
605 if (ehci->has_hostpc)
606 hostpc_reg = (u32 __iomem *)((u8 *)ehci->regs
607 + HOSTPC0 + 4 * ((wIndex & 0xff) - 1));
578 spin_lock_irqsave (&ehci->lock, flags); 608 spin_lock_irqsave (&ehci->lock, flags);
579 switch (typeReq) { 609 switch (typeReq) {
580 case ClearHubFeature: 610 case ClearHubFeature:
@@ -773,7 +803,11 @@ static int ehci_hub_control (
773 if (temp & PORT_CONNECT) { 803 if (temp & PORT_CONNECT) {
774 status |= 1 << USB_PORT_FEAT_CONNECTION; 804 status |= 1 << USB_PORT_FEAT_CONNECTION;
775 // status may be from integrated TT 805 // status may be from integrated TT
776 status |= ehci_port_speed(ehci, temp); 806 if (ehci->has_hostpc) {
807 temp1 = ehci_readl(ehci, hostpc_reg);
808 status |= ehci_port_speed(ehci, temp1);
809 } else
810 status |= ehci_port_speed(ehci, temp);
777 } 811 }
778 if (temp & PORT_PE) 812 if (temp & PORT_PE)
779 status |= 1 << USB_PORT_FEAT_ENABLE; 813 status |= 1 << USB_PORT_FEAT_ENABLE;
@@ -832,6 +866,24 @@ static int ehci_hub_control (
832 || (temp & PORT_RESET) != 0) 866 || (temp & PORT_RESET) != 0)
833 goto error; 867 goto error;
834 ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); 868 ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
869 /* After above check the port must be connected.
870 * Set appropriate bit thus could put phy into low power
871 * mode if we have hostpc feature
872 */
873 if (hostpc_reg) {
874 temp &= ~PORT_WKCONN_E;
875 temp |= (PORT_WKDISC_E | PORT_WKOC_E);
876 ehci_writel(ehci, temp | PORT_SUSPEND,
877 status_reg);
878 msleep(5);/* 5ms for HCD enter low pwr mode */
879 temp1 = ehci_readl(ehci, hostpc_reg);
880 ehci_writel(ehci, temp1 | HOSTPC_PHCD,
881 hostpc_reg);
882 temp1 = ehci_readl(ehci, hostpc_reg);
883 ehci_dbg(ehci, "Port%d phy low pwr mode %s\n",
884 wIndex, (temp1 & HOSTPC_PHCD) ?
885 "succeeded" : "failed");
886 }
835 set_bit(wIndex, &ehci->suspended_ports); 887 set_bit(wIndex, &ehci->suspended_ports);
836 break; 888 break;
837 case USB_PORT_FEAT_POWER: 889 case USB_PORT_FEAT_POWER:
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index fa12f20fbfe2..ec3dba6b8e48 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -136,6 +136,7 @@ struct ehci_hcd { /* one per controller */
136 #define OHCI_HCCTRL_OFFSET 0x4 136 #define OHCI_HCCTRL_OFFSET 0x4
137 #define OHCI_HCCTRL_LEN 0x4 137 #define OHCI_HCCTRL_LEN 0x4
138 __hc32 *ohci_hcctrl_reg; 138 __hc32 *ohci_hcctrl_reg;
139 unsigned has_hostpc:1;
139 140
140 u8 sbrn; /* packed release number */ 141 u8 sbrn; /* packed release number */
141 142
@@ -548,7 +549,7 @@ static inline unsigned int
548ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc) 549ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
549{ 550{
550 if (ehci_is_TDI(ehci)) { 551 if (ehci_is_TDI(ehci)) {
551 switch ((portsc>>26)&3) { 552 switch ((portsc >> (ehci->has_hostpc ? 25 : 26)) & 3) {
552 case 0: 553 case 0:
553 return 0; 554 return 0;
554 case 1: 555 case 1:
diff --git a/include/linux/usb/ehci_def.h b/include/linux/usb/ehci_def.h
index 5b88e36c9103..4c4b701ff265 100644
--- a/include/linux/usb/ehci_def.h
+++ b/include/linux/usb/ehci_def.h
@@ -132,6 +132,19 @@ struct ehci_regs {
132#define USBMODE_CM_HC (3<<0) /* host controller mode */ 132#define USBMODE_CM_HC (3<<0) /* host controller mode */
133#define USBMODE_CM_IDLE (0<<0) /* idle state */ 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/* Appendix C, Debug port ... intended for use with special "debug devices" 148/* Appendix C, Debug port ... intended for use with special "debug devices"
136 * that can help if there's no serial console. (nonstandard enumeration.) 149 * that can help if there's no serial console. (nonstandard enumeration.)
137 */ 150 */