2 * OHCI HCD (Host Controller Driver) for USB.
4 * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
5 * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
7 * This file is licenced under GPL
10 /*-------------------------------------------------------------------------*/
13 * OHCI Root Hub ... the nonsharable stuff
15 * Registers don't need cpu_to_le32, that happens transparently
18 /* AMD-756 (D2 rev) reports corrupt register contents in some cases.
19 * The erratum (#4) description is incorrect. AMD's workaround waits
20 * till some bits (mostly reserved) are clear; ok for all revs.
22 #define read_roothub(hc, register, mask) ({ \
23 u32 temp = readl (&hc->regs->roothub.register); \
26 else if (hc->flags & OHCI_QUIRK_AMD756) \
28 temp = readl (&hc->regs->roothub.register); \
31 static u32
roothub_a (struct ohci_hcd
*hc
)
32 { return read_roothub (hc
, a
, 0xfc0fe000); }
33 static inline u32
roothub_b (struct ohci_hcd
*hc
)
34 { return readl (&hc
->regs
->roothub
.b
); }
35 static inline u32
roothub_status (struct ohci_hcd
*hc
)
36 { return readl (&hc
->regs
->roothub
.status
); }
37 static u32
roothub_portstatus (struct ohci_hcd
*hc
, int i
)
38 { return read_roothub (hc
, portstatus
[i
], 0xffe0fce0); }
40 /*-------------------------------------------------------------------------*/
42 #define dbg_port(hc,label,num,value) \
44 "%s roothub.portstatus [%d] " \
45 "= 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s\n", \
47 (temp & RH_PS_PRSC) ? " PRSC" : "", \
48 (temp & RH_PS_OCIC) ? " OCIC" : "", \
49 (temp & RH_PS_PSSC) ? " PSSC" : "", \
50 (temp & RH_PS_PESC) ? " PESC" : "", \
51 (temp & RH_PS_CSC) ? " CSC" : "", \
53 (temp & RH_PS_LSDA) ? " LSDA" : "", \
54 (temp & RH_PS_PPS) ? " PPS" : "", \
55 (temp & RH_PS_PRS) ? " PRS" : "", \
56 (temp & RH_PS_POCI) ? " POCI" : "", \
57 (temp & RH_PS_PSS) ? " PSS" : "", \
59 (temp & RH_PS_PES) ? " PES" : "", \
60 (temp & RH_PS_CCS) ? " CCS" : "" \
64 /*-------------------------------------------------------------------------*/
66 /* build "status change" packet (one or two bytes) from HC registers */
69 ohci_hub_status_data (struct usb_hcd
*hcd
, char *buf
)
71 struct ohci_hcd
*ohci
= hcd_to_ohci (hcd
);
72 int ports
, i
, changed
= 0, length
= 1;
74 ports
= roothub_a (ohci
) & RH_A_NDP
;
75 if (ports
> MAX_ROOT_PORTS
) {
78 ohci_err (ohci
, "bogus NDP=%d, rereads as NDP=%d\n",
79 ports
, readl (&ohci
->regs
->roothub
.a
) & RH_A_NDP
);
80 /* retry later; "should not happen" */
85 if (roothub_status (ohci
) & (RH_HS_LPSC
| RH_HS_OCIC
))
86 buf
[0] = changed
= 1;
94 /* look at each port */
95 for (i
= 0; i
< ports
; i
++) {
96 u32 status
= roothub_portstatus (ohci
, i
);
98 status
&= RH_PS_CSC
| RH_PS_PESC
| RH_PS_PSSC
99 | RH_PS_OCIC
| RH_PS_PRSC
;
103 buf
[0] |= 1 << (i
+ 1);
105 buf
[1] |= 1 << (i
- 7);
108 return changed
? length
: 0;
111 /*-------------------------------------------------------------------------*/
114 ohci_hub_descriptor (
115 struct ohci_hcd
*ohci
,
116 struct usb_hub_descriptor
*desc
118 u32 rh
= roothub_a (ohci
);
119 int ports
= rh
& RH_A_NDP
;
122 desc
->bDescriptorType
= 0x29;
123 desc
->bPwrOn2PwrGood
= (rh
& RH_A_POTPGT
) >> 24;
124 desc
->bHubContrCurrent
= 0;
126 desc
->bNbrPorts
= ports
;
127 temp
= 1 + (ports
/ 8);
128 desc
->bDescLength
= 7 + 2 * temp
;
131 if (rh
& RH_A_PSM
) /* per-port power switching? */
133 if (rh
& RH_A_NOCP
) /* no overcurrent reporting? */
135 else if (rh
& RH_A_OCPM
) /* per-port overcurrent reporting? */
137 desc
->wHubCharacteristics
= cpu_to_le16 (temp
);
139 /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */
140 rh
= roothub_b (ohci
);
141 desc
->bitmap
[0] = rh
& RH_B_DR
;
143 desc
->bitmap
[1] = (rh
& RH_B_DR
) >> 8;
144 desc
->bitmap
[2] = desc
->bitmap
[3] = 0xff;
146 desc
->bitmap
[1] = 0xff;
149 /*-------------------------------------------------------------------------*/
151 static int ohci_hub_control (
159 struct ohci_hcd
*ohci
= hcd_to_ohci (hcd
);
160 int ports
= hcd_to_bus (hcd
)->root_hub
->maxchild
;
165 case ClearHubFeature
:
167 case C_HUB_OVER_CURRENT
:
168 writel (RH_HS_OCIC
, &ohci
->regs
->roothub
.status
);
169 case C_HUB_LOCAL_POWER
:
175 case ClearPortFeature
:
176 if (!wIndex
|| wIndex
> ports
)
181 case USB_PORT_FEAT_ENABLE
:
184 case USB_PORT_FEAT_C_ENABLE
:
187 case USB_PORT_FEAT_SUSPEND
:
190 case USB_PORT_FEAT_C_SUSPEND
:
193 case USB_PORT_FEAT_POWER
:
196 case USB_PORT_FEAT_C_CONNECTION
:
199 case USB_PORT_FEAT_C_OVER_CURRENT
:
202 case USB_PORT_FEAT_C_RESET
:
208 writel (temp
, &ohci
->regs
->roothub
.portstatus
[wIndex
]);
209 // readl (&ohci->regs->roothub.portstatus [wIndex]);
211 case GetHubDescriptor
:
212 ohci_hub_descriptor (ohci
, (struct usb_hub_descriptor
*) buf
);
215 temp
= roothub_status (ohci
) & ~(RH_HS_CRWE
| RH_HS_DRWE
);
216 *(u32
*) buf
= cpu_to_le32 (temp
);
219 if (!wIndex
|| wIndex
> ports
)
222 temp
= roothub_portstatus (ohci
, wIndex
);
223 *(u32
*) buf
= cpu_to_le32 (temp
);
225 #ifndef OHCI_VERBOSE_DEBUG
226 if (*(u16
*)(buf
+2)) /* only if wPortChange is interesting */
228 dbg_port (ohci
, "GetStatus", wIndex
+ 1, temp
);
232 case C_HUB_OVER_CURRENT
:
233 // FIXME: this can be cleared, yes?
234 case C_HUB_LOCAL_POWER
:
241 if (!wIndex
|| wIndex
> ports
)
245 case USB_PORT_FEAT_SUSPEND
:
247 &ohci
->regs
->roothub
.portstatus
[wIndex
]);
249 case USB_PORT_FEAT_POWER
:
251 &ohci
->regs
->roothub
.portstatus
[wIndex
]);
253 case USB_PORT_FEAT_RESET
:
254 temp
= readl (&ohci
->regs
->roothub
.portstatus
[wIndex
]);
255 if (temp
& RH_PS_CCS
)
257 &ohci
->regs
->roothub
.portstatus
[wIndex
]);
266 /* "protocol stall" on error */