diff options
Diffstat (limited to 'drivers/usb/host/xhci-pci.c')
-rw-r--r-- | drivers/usb/host/xhci-pci.c | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c new file mode 100644 index 000000000000..1462709e26c0 --- /dev/null +++ b/drivers/usb/host/xhci-pci.c | |||
@@ -0,0 +1,166 @@ | |||
1 | /* | ||
2 | * xHCI host controller driver PCI Bus Glue. | ||
3 | * | ||
4 | * Copyright (C) 2008 Intel Corp. | ||
5 | * | ||
6 | * Author: Sarah Sharp | ||
7 | * Some code borrowed from the Linux EHCI driver. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
15 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
16 | * for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software Foundation, | ||
20 | * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #include <linux/pci.h> | ||
24 | |||
25 | #include "xhci.h" | ||
26 | |||
27 | static const char hcd_name[] = "xhci_hcd"; | ||
28 | |||
29 | /* called after powerup, by probe or system-pm "wakeup" */ | ||
30 | static int xhci_pci_reinit(struct xhci_hcd *xhci, struct pci_dev *pdev) | ||
31 | { | ||
32 | /* | ||
33 | * TODO: Implement finding debug ports later. | ||
34 | * TODO: see if there are any quirks that need to be added to handle | ||
35 | * new extended capabilities. | ||
36 | */ | ||
37 | |||
38 | /* PCI Memory-Write-Invalidate cycle support is optional (uncommon) */ | ||
39 | if (!pci_set_mwi(pdev)) | ||
40 | xhci_dbg(xhci, "MWI active\n"); | ||
41 | |||
42 | xhci_dbg(xhci, "Finished xhci_pci_reinit\n"); | ||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | /* called during probe() after chip reset completes */ | ||
47 | static int xhci_pci_setup(struct usb_hcd *hcd) | ||
48 | { | ||
49 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); | ||
50 | struct pci_dev *pdev = to_pci_dev(hcd->self.controller); | ||
51 | int retval; | ||
52 | |||
53 | xhci->cap_regs = hcd->regs; | ||
54 | xhci->op_regs = hcd->regs + | ||
55 | HC_LENGTH(xhci_readl(xhci, &xhci->cap_regs->hc_capbase)); | ||
56 | xhci->run_regs = hcd->regs + | ||
57 | (xhci_readl(xhci, &xhci->cap_regs->run_regs_off) & RTSOFF_MASK); | ||
58 | /* Cache read-only capability registers */ | ||
59 | xhci->hcs_params1 = xhci_readl(xhci, &xhci->cap_regs->hcs_params1); | ||
60 | xhci->hcs_params2 = xhci_readl(xhci, &xhci->cap_regs->hcs_params2); | ||
61 | xhci->hcs_params3 = xhci_readl(xhci, &xhci->cap_regs->hcs_params3); | ||
62 | xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hcc_params); | ||
63 | xhci_print_registers(xhci); | ||
64 | |||
65 | /* Make sure the HC is halted. */ | ||
66 | retval = xhci_halt(xhci); | ||
67 | if (retval) | ||
68 | return retval; | ||
69 | |||
70 | xhci_dbg(xhci, "Resetting HCD\n"); | ||
71 | /* Reset the internal HC memory state and registers. */ | ||
72 | retval = xhci_reset(xhci); | ||
73 | if (retval) | ||
74 | return retval; | ||
75 | xhci_dbg(xhci, "Reset complete\n"); | ||
76 | |||
77 | xhci_dbg(xhci, "Calling HCD init\n"); | ||
78 | /* Initialize HCD and host controller data structures. */ | ||
79 | retval = xhci_init(hcd); | ||
80 | if (retval) | ||
81 | return retval; | ||
82 | xhci_dbg(xhci, "Called HCD init\n"); | ||
83 | |||
84 | pci_read_config_byte(pdev, XHCI_SBRN_OFFSET, &xhci->sbrn); | ||
85 | xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn); | ||
86 | |||
87 | /* Find any debug ports */ | ||
88 | return xhci_pci_reinit(xhci, pdev); | ||
89 | } | ||
90 | |||
91 | static const struct hc_driver xhci_pci_hc_driver = { | ||
92 | .description = hcd_name, | ||
93 | .product_desc = "xHCI Host Controller", | ||
94 | .hcd_priv_size = sizeof(struct xhci_hcd), | ||
95 | |||
96 | /* | ||
97 | * generic hardware linkage | ||
98 | */ | ||
99 | .irq = xhci_irq, | ||
100 | .flags = HCD_MEMORY | HCD_USB3, | ||
101 | |||
102 | /* | ||
103 | * basic lifecycle operations | ||
104 | */ | ||
105 | .reset = xhci_pci_setup, | ||
106 | .start = xhci_run, | ||
107 | /* suspend and resume implemented later */ | ||
108 | .stop = xhci_stop, | ||
109 | .shutdown = xhci_shutdown, | ||
110 | |||
111 | /* | ||
112 | * managing i/o requests and associated device resources | ||
113 | */ | ||
114 | .urb_enqueue = xhci_urb_enqueue, | ||
115 | .urb_dequeue = xhci_urb_dequeue, | ||
116 | .alloc_dev = xhci_alloc_dev, | ||
117 | .free_dev = xhci_free_dev, | ||
118 | .add_endpoint = xhci_add_endpoint, | ||
119 | .drop_endpoint = xhci_drop_endpoint, | ||
120 | .check_bandwidth = xhci_check_bandwidth, | ||
121 | .reset_bandwidth = xhci_reset_bandwidth, | ||
122 | .address_device = xhci_address_device, | ||
123 | |||
124 | /* | ||
125 | * scheduling support | ||
126 | */ | ||
127 | .get_frame_number = xhci_get_frame, | ||
128 | |||
129 | /* Root hub support */ | ||
130 | .hub_control = xhci_hub_control, | ||
131 | .hub_status_data = xhci_hub_status_data, | ||
132 | }; | ||
133 | |||
134 | /*-------------------------------------------------------------------------*/ | ||
135 | |||
136 | /* PCI driver selection metadata; PCI hotplugging uses this */ | ||
137 | static const struct pci_device_id pci_ids[] = { { | ||
138 | /* handle any USB 3.0 xHCI controller */ | ||
139 | PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_XHCI, ~0), | ||
140 | .driver_data = (unsigned long) &xhci_pci_hc_driver, | ||
141 | }, | ||
142 | { /* end: all zeroes */ } | ||
143 | }; | ||
144 | MODULE_DEVICE_TABLE(pci, pci_ids); | ||
145 | |||
146 | /* pci driver glue; this is a "new style" PCI driver module */ | ||
147 | static struct pci_driver xhci_pci_driver = { | ||
148 | .name = (char *) hcd_name, | ||
149 | .id_table = pci_ids, | ||
150 | |||
151 | .probe = usb_hcd_pci_probe, | ||
152 | .remove = usb_hcd_pci_remove, | ||
153 | /* suspend and resume implemented later */ | ||
154 | |||
155 | .shutdown = usb_hcd_pci_shutdown, | ||
156 | }; | ||
157 | |||
158 | int xhci_register_pci() | ||
159 | { | ||
160 | return pci_register_driver(&xhci_pci_driver); | ||
161 | } | ||
162 | |||
163 | void xhci_unregister_pci() | ||
164 | { | ||
165 | pci_unregister_driver(&xhci_pci_driver); | ||
166 | } | ||