[PATCH] update PCI early-handoff handling for OHCI
[linux-flexiantxendom0.git] / drivers / usb / host / pci-quirks.c
1 /*
2  * This file contains code to reset and initialize USB host controllers.
3  * Some of it includes work-arounds for PCI hardware and BIOS quirks.
4  * It may need to run early during booting -- before USB would normally
5  * initialize -- to ensure that Linux doesn't use any legacy modes.
6  *
7  *  Copyright (c) 1999 Martin Mares <mj@ucw.cz>
8  *  (and others)
9  */
10
11 #include <linux/config.h>
12 #include <linux/types.h>
13 #include <linux/kernel.h>
14 #include <linux/pci.h>
15 #include <linux/init.h>
16 #include <linux/delay.h>
17 #include <linux/acpi.h>
18
19
20 /*
21  * PIIX3 USB: We have to disable USB interrupts that are
22  * hardwired to PIRQD# and may be shared with an
23  * external device.
24  *
25  * Legacy Support Register (LEGSUP):
26  *     bit13:  USB PIRQ Enable (USBPIRQDEN),
27  *     bit4:   Trap/SMI On IRQ Enable (USBSMIEN).
28  *
29  * We mask out all r/wc bits, too.
30  */
31 static void __devinit quirk_piix3_usb(struct pci_dev *dev)
32 {
33         u16 legsup;
34
35         pci_read_config_word(dev, 0xc0, &legsup);
36         legsup &= 0x50ef;
37         pci_write_config_word(dev, 0xc0, legsup);
38 }
39 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371SB_2,  quirk_piix3_usb );
40 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371AB_2,  quirk_piix3_usb );
41
42
43 /* FIXME these should be the guts of hcd->reset() methods; resolve all
44  * the differences between this version and the HCD's version.
45  */
46
47 #define UHCI_USBLEGSUP          0xc0            /* legacy support */
48 #define UHCI_USBCMD             0               /* command register */
49 #define UHCI_USBSTS             2               /* status register */
50 #define UHCI_USBINTR            4               /* interrupt register */
51 #define UHCI_USBLEGSUP_DEFAULT  0x2000          /* only PIRQ enable set */
52 #define UHCI_USBCMD_RUN         (1 << 0)        /* RUN/STOP bit */
53 #define UHCI_USBCMD_GRESET      (1 << 2)        /* Global reset */
54 #define UHCI_USBCMD_CONFIGURE   (1 << 6)        /* config semaphore */
55 #define UHCI_USBSTS_HALTED      (1 << 5)        /* HCHalted bit */
56
57 #define OHCI_CONTROL            0x04
58 #define OHCI_CMDSTATUS          0x08
59 #define OHCI_INTRSTATUS         0x0c
60 #define OHCI_INTRENABLE         0x10
61 #define OHCI_INTRDISABLE        0x14
62 #define OHCI_OCR                (1 << 3)        /* ownership change request */
63 #define OHCI_CTRL_RWC           (1 << 9)        /* remote wakeup connected */
64 #define OHCI_CTRL_IR            (1 << 8)        /* interrupt routing */
65 #define OHCI_INTR_OC            (1 << 30)       /* ownership change */
66
67 #define EHCI_HCC_PARAMS         0x08            /* extended capabilities */
68 #define EHCI_USBCMD             0               /* command register */
69 #define EHCI_USBCMD_RUN         (1 << 0)        /* RUN/STOP bit */
70 #define EHCI_USBSTS             4               /* status register */
71 #define EHCI_USBSTS_HALTED      (1 << 12)       /* HCHalted bit */
72 #define EHCI_USBINTR            8               /* interrupt register */
73 #define EHCI_USBLEGSUP          0               /* legacy support register */
74 #define EHCI_USBLEGSUP_BIOS     (1 << 16)       /* BIOS semaphore */
75 #define EHCI_USBLEGSUP_OS       (1 << 24)       /* OS semaphore */
76 #define EHCI_USBLEGCTLSTS       4               /* legacy control/status */
77 #define EHCI_USBLEGCTLSTS_SOOE  (1 << 13)       /* SMI on ownership change */
78
79 int usb_early_handoff __devinitdata = 0;
80 static int __init usb_handoff_early(char *str)
81 {
82         usb_early_handoff = 1;
83         return 0;
84 }
85 __setup("usb-handoff", usb_handoff_early);
86
87 static void __devinit quirk_usb_handoff_uhci(struct pci_dev *pdev)
88 {
89         unsigned long base = 0;
90         int wait_time, delta;
91         u16 val, sts;
92         int i;
93
94         for (i = 0; i < PCI_ROM_RESOURCE; i++)
95                 if ((pci_resource_flags(pdev, i) & IORESOURCE_IO)) {
96                         base = pci_resource_start(pdev, i);
97                         break;
98                 }
99
100         if (!base)
101                 return;
102
103         /*
104          * stop controller
105          */
106         sts = inw(base + UHCI_USBSTS);
107         val = inw(base + UHCI_USBCMD);
108         val &= ~(u16)(UHCI_USBCMD_RUN | UHCI_USBCMD_CONFIGURE);
109         outw(val, base + UHCI_USBCMD);
110
111         /*
112          * wait while it stops if it was running
113          */
114         if ((sts & UHCI_USBSTS_HALTED) == 0)
115         {
116                 wait_time = 1000;
117                 delta = 100;
118
119                 do {
120                         outw(0x1f, base + UHCI_USBSTS);
121                         udelay(delta);
122                         wait_time -= delta;
123                         val = inw(base + UHCI_USBSTS);
124                         if (val & UHCI_USBSTS_HALTED)
125                                 break;
126                 } while (wait_time > 0);
127         }
128
129         /*
130          * disable interrupts & legacy support
131          */
132         outw(0, base + UHCI_USBINTR);
133         outw(0x1f, base + UHCI_USBSTS);
134         pci_read_config_word(pdev, UHCI_USBLEGSUP, &val);
135         if (val & 0xbf)
136                 pci_write_config_word(pdev, UHCI_USBLEGSUP, UHCI_USBLEGSUP_DEFAULT);
137
138 }
139
140 static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
141 {
142         void __iomem *base;
143         int wait_time;
144         u32 control;
145
146         base = ioremap_nocache(pci_resource_start(pdev, 0),
147                                      pci_resource_len(pdev, 0));
148         if (base == NULL) return;
149
150 /* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */
151 #ifndef __hppa__
152         control = readl(base + OHCI_CONTROL);
153         if (control & OHCI_CTRL_IR) {
154                 wait_time = 500; /* arbitrary; 5 seconds */
155                 writel(OHCI_INTR_OC, base + OHCI_INTRENABLE);
156                 writel(OHCI_OCR, base + OHCI_CMDSTATUS);
157                 while (wait_time > 0 &&
158                                 readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) {
159                         wait_time -= 10;
160                         msleep(10);
161                 }
162                 if (wait_time <= 0)
163                         printk(KERN_WARNING "%s %s: early BIOS handoff "
164                                         "failed (BIOS bug ?)\n",
165                                         pdev->dev.bus_id, "OHCI");
166
167                 /* reset controller, preserving RWC */
168                 writel(control & OHCI_CTRL_RWC, base + OHCI_CONTROL);
169         }
170 #endif
171
172         /*
173          * disable interrupts
174          */
175         writel(~(u32)0, base + OHCI_INTRDISABLE);
176         writel(~(u32)0, base + OHCI_INTRSTATUS);
177
178         iounmap(base);
179 }
180
181 static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
182 {
183         int wait_time, delta;
184         void __iomem *base, *op_reg_base;
185         u32 hcc_params, val, temp;
186         u8 cap_length;
187
188         base = ioremap_nocache(pci_resource_start(pdev, 0),
189                                 pci_resource_len(pdev, 0));
190         if (base == NULL) return;
191
192         cap_length = readb(base);
193         op_reg_base = base + cap_length;
194         hcc_params = readl(base + EHCI_HCC_PARAMS);
195         hcc_params = (hcc_params >> 8) & 0xff;
196         if (hcc_params) {
197                 pci_read_config_dword(pdev,
198                                         hcc_params + EHCI_USBLEGSUP,
199                                         &val);
200                 if (((val & 0xff) == 1) && (val & EHCI_USBLEGSUP_BIOS)) {
201                         /*
202                          * Ok, BIOS is in smm mode, try to hand off...
203                          */
204                         pci_read_config_dword(pdev,
205                                                 hcc_params + EHCI_USBLEGCTLSTS,
206                                                 &temp);
207                         pci_write_config_dword(pdev,
208                                                 hcc_params + EHCI_USBLEGCTLSTS,
209                                                 temp | EHCI_USBLEGCTLSTS_SOOE);
210                         val |= EHCI_USBLEGSUP_OS;
211                         pci_write_config_dword(pdev,
212                                                 hcc_params + EHCI_USBLEGSUP,
213                                                 val);
214
215                         wait_time = 500;
216                         do {
217                                 msleep(10);
218                                 wait_time -= 10;
219                                 pci_read_config_dword(pdev,
220                                                 hcc_params + EHCI_USBLEGSUP,
221                                                 &val);
222                         } while (wait_time && (val & EHCI_USBLEGSUP_BIOS));
223                         if (!wait_time) {
224                                 /*
225                                  * well, possibly buggy BIOS...
226                                  */
227                                 printk(KERN_WARNING "%s %s: early BIOS handoff "
228                                                 "failed (BIOS bug ?)\n",
229                                         pdev->dev.bus_id, "EHCI");
230                                 pci_write_config_dword(pdev,
231                                                 hcc_params + EHCI_USBLEGSUP,
232                                                 EHCI_USBLEGSUP_OS);
233                                 pci_write_config_dword(pdev,
234                                                 hcc_params + EHCI_USBLEGCTLSTS,
235                                                 0);
236                         }
237                 }
238         }
239
240         /*
241          * halt EHCI & disable its interrupts in any case
242          */
243         val = readl(op_reg_base + EHCI_USBSTS);
244         if ((val & EHCI_USBSTS_HALTED) == 0) {
245                 val = readl(op_reg_base + EHCI_USBCMD);
246                 val &= ~EHCI_USBCMD_RUN;
247                 writel(val, op_reg_base + EHCI_USBCMD);
248
249                 wait_time = 2000;
250                 delta = 100;
251                 do {
252                         writel(0x3f, op_reg_base + EHCI_USBSTS);
253                         udelay(delta);
254                         wait_time -= delta;
255                         val = readl(op_reg_base + EHCI_USBSTS);
256                         if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) {
257                                 break;
258                         }
259                 } while (wait_time > 0);
260         }
261         writel(0, op_reg_base + EHCI_USBINTR);
262         writel(0x3f, op_reg_base + EHCI_USBSTS);
263
264         iounmap(base);
265
266         return;
267 }
268
269
270
271 static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
272 {
273         if (!usb_early_handoff)
274                 return;
275
276         if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x00)) { /* UHCI */
277                 quirk_usb_handoff_uhci(pdev);
278         } else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x10)) { /* OHCI */
279                 quirk_usb_handoff_ohci(pdev);
280         } else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x20)) { /* EHCI */
281                 quirk_usb_disable_ehci(pdev);
282         }
283
284         return;
285 }
286 DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);