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) {
76 if (!HCD_IS_RUNNING(ohci->hcd.state))
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_NPS) /* no power switching? */
133 if (rh & RH_A_PSM) /* per-port power switching? */
135 if (rh & RH_A_NOCP) /* no overcurrent reporting? */
137 else if (rh & RH_A_OCPM) /* per-port overcurrent reporting? */
139 desc->wHubCharacteristics = cpu_to_le16 (temp);
141 /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */
142 rh = roothub_b (ohci);
143 desc->bitmap [0] = rh & RH_B_DR;
145 desc->bitmap [1] = (rh & RH_B_DR) >> 8;
146 desc->bitmap [2] = desc->bitmap [3] = 0xff;
148 desc->bitmap [1] = 0xff;
151 /*-------------------------------------------------------------------------*/
153 static int ohci_hub_control (
161 struct ohci_hcd *ohci = hcd_to_ohci (hcd);
162 int ports = hcd_to_bus (hcd)->root_hub->maxchild;
167 case ClearHubFeature:
169 case C_HUB_OVER_CURRENT:
170 writel (RH_HS_OCIC, &ohci->regs->roothub.status);
171 case C_HUB_LOCAL_POWER:
177 case ClearPortFeature:
178 if (!wIndex || wIndex > ports)
183 case USB_PORT_FEAT_ENABLE:
186 case USB_PORT_FEAT_C_ENABLE:
189 case USB_PORT_FEAT_SUSPEND:
192 case USB_PORT_FEAT_C_SUSPEND:
195 case USB_PORT_FEAT_POWER:
198 case USB_PORT_FEAT_C_CONNECTION:
201 case USB_PORT_FEAT_C_OVER_CURRENT:
204 case USB_PORT_FEAT_C_RESET:
210 writel (temp, &ohci->regs->roothub.portstatus [wIndex]);
211 // readl (&ohci->regs->roothub.portstatus [wIndex]);
213 case GetHubDescriptor:
214 ohci_hub_descriptor (ohci, (struct usb_hub_descriptor *) buf);
217 temp = roothub_status (ohci) & ~(RH_HS_CRWE | RH_HS_DRWE);
218 *(u32 *) buf = cpu_to_le32 (temp);
221 if (!wIndex || wIndex > ports)
224 temp = roothub_portstatus (ohci, wIndex);
225 *(u32 *) buf = cpu_to_le32 (temp);
227 #ifndef OHCI_VERBOSE_DEBUG
228 if (*(u16*)(buf+2)) /* only if wPortChange is interesting */
230 dbg_port (ohci, "GetStatus", wIndex + 1, temp);
234 case C_HUB_OVER_CURRENT:
235 // FIXME: this can be cleared, yes?
236 case C_HUB_LOCAL_POWER:
243 if (!wIndex || wIndex > ports)
247 case USB_PORT_FEAT_SUSPEND:
249 &ohci->regs->roothub.portstatus [wIndex]);
251 case USB_PORT_FEAT_POWER:
253 &ohci->regs->roothub.portstatus [wIndex]);
255 case USB_PORT_FEAT_RESET:
256 temp = readl (&ohci->regs->roothub.portstatus [wIndex]);
257 if (temp & RH_PS_CCS)
259 &ohci->regs->roothub.portstatus [wIndex]);
268 /* "protocol stall" on error */