xref: /openbmc/qemu/hw/usb/hcd-uhci-pci.c (revision 27af7e00)
1*27af7e00SGuenter Roeck /*
2*27af7e00SGuenter Roeck  * USB UHCI controller emulation
3*27af7e00SGuenter Roeck  * PCI code
4*27af7e00SGuenter Roeck  *
5*27af7e00SGuenter Roeck  * Copyright (c) 2005 Fabrice Bellard
6*27af7e00SGuenter Roeck  *
7*27af7e00SGuenter Roeck  * Copyright (c) 2008 Max Krasnyansky
8*27af7e00SGuenter Roeck  *     Magor rewrite of the UHCI data structures parser and frame processor
9*27af7e00SGuenter Roeck  *     Support for fully async operation and multiple outstanding transactions
10*27af7e00SGuenter Roeck  *
11*27af7e00SGuenter Roeck  * Permission is hereby granted, free of charge, to any person obtaining a copy
12*27af7e00SGuenter Roeck  * of this software and associated documentation files (the "Software"), to deal
13*27af7e00SGuenter Roeck  * in the Software without restriction, including without limitation the rights
14*27af7e00SGuenter Roeck  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15*27af7e00SGuenter Roeck  * copies of the Software, and to permit persons to whom the Software is
16*27af7e00SGuenter Roeck  * furnished to do so, subject to the following conditions:
17*27af7e00SGuenter Roeck  *
18*27af7e00SGuenter Roeck  * The above copyright notice and this permission notice shall be included in
19*27af7e00SGuenter Roeck  * all copies or substantial portions of the Software.
20*27af7e00SGuenter Roeck  *
21*27af7e00SGuenter Roeck  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22*27af7e00SGuenter Roeck  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23*27af7e00SGuenter Roeck  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24*27af7e00SGuenter Roeck  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25*27af7e00SGuenter Roeck  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26*27af7e00SGuenter Roeck  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27*27af7e00SGuenter Roeck  * THE SOFTWARE.
28*27af7e00SGuenter Roeck  */
29*27af7e00SGuenter Roeck 
30*27af7e00SGuenter Roeck #include "qemu/osdep.h"
31*27af7e00SGuenter Roeck #include "hw/irq.h"
32*27af7e00SGuenter Roeck #include "hw/usb.h"
33*27af7e00SGuenter Roeck #include "migration/vmstate.h"
34*27af7e00SGuenter Roeck #include "hw/pci/pci.h"
35*27af7e00SGuenter Roeck #include "hw/qdev-properties.h"
36*27af7e00SGuenter Roeck #include "qapi/error.h"
37*27af7e00SGuenter Roeck #include "qemu/main-loop.h"
38*27af7e00SGuenter Roeck #include "qemu/module.h"
39*27af7e00SGuenter Roeck #include "qom/object.h"
40*27af7e00SGuenter Roeck #include "hcd-uhci-pci.h"
41*27af7e00SGuenter Roeck 
42*27af7e00SGuenter Roeck struct UHCIPCIDeviceClass {
43*27af7e00SGuenter Roeck     PCIDeviceClass parent_class;
44*27af7e00SGuenter Roeck     UHCIPCIInfo info;
45*27af7e00SGuenter Roeck };
46*27af7e00SGuenter Roeck 
47*27af7e00SGuenter Roeck static const VMStateDescription vmstate_uhci = {
48*27af7e00SGuenter Roeck     .name = "pci_uhci",
49*27af7e00SGuenter Roeck     .version_id = 1,
50*27af7e00SGuenter Roeck     .minimum_version_id = 1,
51*27af7e00SGuenter Roeck     .fields = (const VMStateField[]) {
52*27af7e00SGuenter Roeck         VMSTATE_PCI_DEVICE(dev, UHCIPCIState),
53*27af7e00SGuenter Roeck         VMSTATE_STRUCT(state, UHCIPCIState, 1, vmstate_uhci_state, UHCIState),
54*27af7e00SGuenter Roeck         VMSTATE_END_OF_LIST()
55*27af7e00SGuenter Roeck     }
56*27af7e00SGuenter Roeck };
57*27af7e00SGuenter Roeck 
uhci_pci_reset(UHCIState * uhci)58*27af7e00SGuenter Roeck static void uhci_pci_reset(UHCIState *uhci)
59*27af7e00SGuenter Roeck {
60*27af7e00SGuenter Roeck     UHCIPCIState *pstate = container_of(uhci, UHCIPCIState, state);
61*27af7e00SGuenter Roeck     PCIDevice *d = &pstate->dev;
62*27af7e00SGuenter Roeck 
63*27af7e00SGuenter Roeck     d->config[0x6a] = 0x01; /* usb clock */
64*27af7e00SGuenter Roeck     d->config[0x6b] = 0x00;
65*27af7e00SGuenter Roeck 
66*27af7e00SGuenter Roeck     uhci_state_reset(uhci);
67*27af7e00SGuenter Roeck }
68*27af7e00SGuenter Roeck 
usb_uhci_common_realize_pci(PCIDevice * dev,Error ** errp)69*27af7e00SGuenter Roeck void usb_uhci_common_realize_pci(PCIDevice *dev, Error **errp)
70*27af7e00SGuenter Roeck {
71*27af7e00SGuenter Roeck     Error *err = NULL;
72*27af7e00SGuenter Roeck     UHCIPCIDeviceClass *u = UHCI_PCI_GET_CLASS(dev);
73*27af7e00SGuenter Roeck     UHCIPCIState *uhci = UHCI_PCI(dev);
74*27af7e00SGuenter Roeck     UHCIState *s = &uhci->state;
75*27af7e00SGuenter Roeck     uint8_t *pci_conf = dev->config;
76*27af7e00SGuenter Roeck 
77*27af7e00SGuenter Roeck     pci_conf[PCI_CLASS_PROG] = 0x00;
78*27af7e00SGuenter Roeck     /* TODO: reset value should be 0. */
79*27af7e00SGuenter Roeck     pci_conf[USB_SBRN] = USB_RELEASE_1; /* release number */
80*27af7e00SGuenter Roeck     pci_config_set_interrupt_pin(pci_conf, u->info.irq_pin + 1);
81*27af7e00SGuenter Roeck 
82*27af7e00SGuenter Roeck     s->irq = pci_allocate_irq(dev);
83*27af7e00SGuenter Roeck     s->masterbus = uhci->masterbus;
84*27af7e00SGuenter Roeck     s->firstport = uhci->firstport;
85*27af7e00SGuenter Roeck     s->maxframes = uhci->maxframes;
86*27af7e00SGuenter Roeck     s->frame_bandwidth = uhci->frame_bandwidth;
87*27af7e00SGuenter Roeck     s->as = pci_get_address_space(dev);
88*27af7e00SGuenter Roeck     s->uhci_reset = uhci_pci_reset;
89*27af7e00SGuenter Roeck 
90*27af7e00SGuenter Roeck     usb_uhci_init(s, DEVICE(dev), &err);
91*27af7e00SGuenter Roeck 
92*27af7e00SGuenter Roeck     /*
93*27af7e00SGuenter Roeck      * Use region 4 for consistency with real hardware.  BSD guests seem
94*27af7e00SGuenter Roeck      * to rely on this.
95*27af7e00SGuenter Roeck      */
96*27af7e00SGuenter Roeck     pci_register_bar(dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &s->mem);
97*27af7e00SGuenter Roeck }
98*27af7e00SGuenter Roeck 
uhci_pci_reset_pci(DeviceState * dev)99*27af7e00SGuenter Roeck static void uhci_pci_reset_pci(DeviceState *dev)
100*27af7e00SGuenter Roeck {
101*27af7e00SGuenter Roeck     PCIDevice *d = PCI_DEVICE(dev);
102*27af7e00SGuenter Roeck     UHCIPCIState *uhci = UHCI_PCI(d);
103*27af7e00SGuenter Roeck 
104*27af7e00SGuenter Roeck     uhci_pci_reset(&uhci->state);
105*27af7e00SGuenter Roeck }
106*27af7e00SGuenter Roeck 
usb_uhci_pci_exit(PCIDevice * dev)107*27af7e00SGuenter Roeck static void usb_uhci_pci_exit(PCIDevice *dev)
108*27af7e00SGuenter Roeck {
109*27af7e00SGuenter Roeck     UHCIPCIState *uhci = UHCI_PCI(dev);
110*27af7e00SGuenter Roeck     UHCIState *s = &uhci->state;
111*27af7e00SGuenter Roeck 
112*27af7e00SGuenter Roeck     usb_uhci_exit(s);
113*27af7e00SGuenter Roeck 
114*27af7e00SGuenter Roeck     qemu_free_irq(s->irq);
115*27af7e00SGuenter Roeck }
116*27af7e00SGuenter Roeck 
117*27af7e00SGuenter Roeck static Property uhci_properties_companion[] = {
118*27af7e00SGuenter Roeck     DEFINE_PROP_STRING("masterbus", UHCIPCIState, masterbus),
119*27af7e00SGuenter Roeck     DEFINE_PROP_UINT32("firstport", UHCIPCIState, firstport, 0),
120*27af7e00SGuenter Roeck     DEFINE_PROP_UINT32("bandwidth", UHCIPCIState, frame_bandwidth, 1280),
121*27af7e00SGuenter Roeck     DEFINE_PROP_UINT32("maxframes", UHCIPCIState, maxframes, 128),
122*27af7e00SGuenter Roeck     DEFINE_PROP_END_OF_LIST(),
123*27af7e00SGuenter Roeck };
124*27af7e00SGuenter Roeck static Property uhci_properties_standalone[] = {
125*27af7e00SGuenter Roeck     DEFINE_PROP_UINT32("bandwidth", UHCIPCIState, frame_bandwidth, 1280),
126*27af7e00SGuenter Roeck     DEFINE_PROP_UINT32("maxframes", UHCIPCIState, maxframes, 128),
127*27af7e00SGuenter Roeck     DEFINE_PROP_END_OF_LIST(),
128*27af7e00SGuenter Roeck };
129*27af7e00SGuenter Roeck 
uhci_pci_class_init(ObjectClass * klass,void * data)130*27af7e00SGuenter Roeck static void uhci_pci_class_init(ObjectClass *klass, void *data)
131*27af7e00SGuenter Roeck {
132*27af7e00SGuenter Roeck     DeviceClass *dc = DEVICE_CLASS(klass);
133*27af7e00SGuenter Roeck     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
134*27af7e00SGuenter Roeck 
135*27af7e00SGuenter Roeck     k->class_id  = PCI_CLASS_SERIAL_USB;
136*27af7e00SGuenter Roeck     dc->vmsd = &vmstate_uhci;
137*27af7e00SGuenter Roeck     device_class_set_legacy_reset(dc, uhci_pci_reset_pci);
138*27af7e00SGuenter Roeck     set_bit(DEVICE_CATEGORY_USB, dc->categories);
139*27af7e00SGuenter Roeck }
140*27af7e00SGuenter Roeck 
141*27af7e00SGuenter Roeck static const TypeInfo uhci_pci_type_info = {
142*27af7e00SGuenter Roeck     .name = TYPE_UHCI_PCI,
143*27af7e00SGuenter Roeck     .parent = TYPE_PCI_DEVICE,
144*27af7e00SGuenter Roeck     .instance_size = sizeof(UHCIPCIState),
145*27af7e00SGuenter Roeck     .class_size    = sizeof(UHCIPCIDeviceClass),
146*27af7e00SGuenter Roeck     .class_init    = uhci_pci_class_init,
147*27af7e00SGuenter Roeck     .interfaces = (InterfaceInfo[]) {
148*27af7e00SGuenter Roeck         { INTERFACE_CONVENTIONAL_PCI_DEVICE },
149*27af7e00SGuenter Roeck         { },
150*27af7e00SGuenter Roeck     },
151*27af7e00SGuenter Roeck };
152*27af7e00SGuenter Roeck 
uhci_pci_data_class_init(ObjectClass * klass,void * data)153*27af7e00SGuenter Roeck void uhci_pci_data_class_init(ObjectClass *klass, void *data)
154*27af7e00SGuenter Roeck {
155*27af7e00SGuenter Roeck     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
156*27af7e00SGuenter Roeck     DeviceClass *dc = DEVICE_CLASS(klass);
157*27af7e00SGuenter Roeck     UHCIPCIDeviceClass *u = UHCI_PCI_CLASS(klass);
158*27af7e00SGuenter Roeck     UHCIPCIInfo *info = data;
159*27af7e00SGuenter Roeck 
160*27af7e00SGuenter Roeck     k->realize = info->realize ? info->realize : usb_uhci_common_realize_pci;
161*27af7e00SGuenter Roeck     k->exit = info->unplug ? usb_uhci_pci_exit : NULL;
162*27af7e00SGuenter Roeck     k->vendor_id = info->vendor_id;
163*27af7e00SGuenter Roeck     k->device_id = info->device_id;
164*27af7e00SGuenter Roeck     k->revision  = info->revision;
165*27af7e00SGuenter Roeck     if (!info->unplug) {
166*27af7e00SGuenter Roeck         /* uhci controllers in companion setups can't be hotplugged */
167*27af7e00SGuenter Roeck         dc->hotpluggable = false;
168*27af7e00SGuenter Roeck         device_class_set_props(dc, uhci_properties_companion);
169*27af7e00SGuenter Roeck     } else {
170*27af7e00SGuenter Roeck         device_class_set_props(dc, uhci_properties_standalone);
171*27af7e00SGuenter Roeck     }
172*27af7e00SGuenter Roeck     if (info->notuser) {
173*27af7e00SGuenter Roeck         dc->user_creatable = false;
174*27af7e00SGuenter Roeck     }
175*27af7e00SGuenter Roeck     u->info = *info;
176*27af7e00SGuenter Roeck }
177*27af7e00SGuenter Roeck 
178*27af7e00SGuenter Roeck static UHCIPCIInfo uhci_pci_info[] = {
179*27af7e00SGuenter Roeck     {
180*27af7e00SGuenter Roeck         .name      = TYPE_PIIX3_USB_UHCI,
181*27af7e00SGuenter Roeck         .vendor_id = PCI_VENDOR_ID_INTEL,
182*27af7e00SGuenter Roeck         .device_id = PCI_DEVICE_ID_INTEL_82371SB_2,
183*27af7e00SGuenter Roeck         .revision  = 0x01,
184*27af7e00SGuenter Roeck         .irq_pin   = 3,
185*27af7e00SGuenter Roeck         .unplug    = true,
186*27af7e00SGuenter Roeck     },{
187*27af7e00SGuenter Roeck         .name      = TYPE_PIIX4_USB_UHCI,
188*27af7e00SGuenter Roeck         .vendor_id = PCI_VENDOR_ID_INTEL,
189*27af7e00SGuenter Roeck         .device_id = PCI_DEVICE_ID_INTEL_82371AB_2,
190*27af7e00SGuenter Roeck         .revision  = 0x01,
191*27af7e00SGuenter Roeck         .irq_pin   = 3,
192*27af7e00SGuenter Roeck         .unplug    = true,
193*27af7e00SGuenter Roeck     },{
194*27af7e00SGuenter Roeck         .name      = TYPE_ICH9_USB_UHCI(1), /* 00:1d.0 */
195*27af7e00SGuenter Roeck         .vendor_id = PCI_VENDOR_ID_INTEL,
196*27af7e00SGuenter Roeck         .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1,
197*27af7e00SGuenter Roeck         .revision  = 0x03,
198*27af7e00SGuenter Roeck         .irq_pin   = 0,
199*27af7e00SGuenter Roeck         .unplug    = false,
200*27af7e00SGuenter Roeck     },{
201*27af7e00SGuenter Roeck         .name      = TYPE_ICH9_USB_UHCI(2), /* 00:1d.1 */
202*27af7e00SGuenter Roeck         .vendor_id = PCI_VENDOR_ID_INTEL,
203*27af7e00SGuenter Roeck         .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI2,
204*27af7e00SGuenter Roeck         .revision  = 0x03,
205*27af7e00SGuenter Roeck         .irq_pin   = 1,
206*27af7e00SGuenter Roeck         .unplug    = false,
207*27af7e00SGuenter Roeck     },{
208*27af7e00SGuenter Roeck         .name      = TYPE_ICH9_USB_UHCI(3), /* 00:1d.2 */
209*27af7e00SGuenter Roeck         .vendor_id = PCI_VENDOR_ID_INTEL,
210*27af7e00SGuenter Roeck         .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI3,
211*27af7e00SGuenter Roeck         .revision  = 0x03,
212*27af7e00SGuenter Roeck         .irq_pin   = 2,
213*27af7e00SGuenter Roeck         .unplug    = false,
214*27af7e00SGuenter Roeck     },{
215*27af7e00SGuenter Roeck         .name      = TYPE_ICH9_USB_UHCI(4), /* 00:1a.0 */
216*27af7e00SGuenter Roeck         .vendor_id = PCI_VENDOR_ID_INTEL,
217*27af7e00SGuenter Roeck         .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI4,
218*27af7e00SGuenter Roeck         .revision  = 0x03,
219*27af7e00SGuenter Roeck         .irq_pin   = 0,
220*27af7e00SGuenter Roeck         .unplug    = false,
221*27af7e00SGuenter Roeck     },{
222*27af7e00SGuenter Roeck         .name      = TYPE_ICH9_USB_UHCI(5), /* 00:1a.1 */
223*27af7e00SGuenter Roeck         .vendor_id = PCI_VENDOR_ID_INTEL,
224*27af7e00SGuenter Roeck         .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI5,
225*27af7e00SGuenter Roeck         .revision  = 0x03,
226*27af7e00SGuenter Roeck         .irq_pin   = 1,
227*27af7e00SGuenter Roeck         .unplug    = false,
228*27af7e00SGuenter Roeck     },{
229*27af7e00SGuenter Roeck         .name      = TYPE_ICH9_USB_UHCI(6), /* 00:1a.2 */
230*27af7e00SGuenter Roeck         .vendor_id = PCI_VENDOR_ID_INTEL,
231*27af7e00SGuenter Roeck         .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI6,
232*27af7e00SGuenter Roeck         .revision  = 0x03,
233*27af7e00SGuenter Roeck         .irq_pin   = 2,
234*27af7e00SGuenter Roeck         .unplug    = false,
235*27af7e00SGuenter Roeck     }
236*27af7e00SGuenter Roeck };
237*27af7e00SGuenter Roeck 
uhci_pci_register_types(void)238*27af7e00SGuenter Roeck static void uhci_pci_register_types(void)
239*27af7e00SGuenter Roeck {
240*27af7e00SGuenter Roeck     TypeInfo type_info = {
241*27af7e00SGuenter Roeck         .parent        = TYPE_UHCI_PCI,
242*27af7e00SGuenter Roeck         .class_init    = uhci_pci_data_class_init,
243*27af7e00SGuenter Roeck     };
244*27af7e00SGuenter Roeck     int i;
245*27af7e00SGuenter Roeck 
246*27af7e00SGuenter Roeck     type_register_static(&uhci_pci_type_info);
247*27af7e00SGuenter Roeck 
248*27af7e00SGuenter Roeck     for (i = 0; i < ARRAY_SIZE(uhci_pci_info); i++) {
249*27af7e00SGuenter Roeck         type_info.name = uhci_pci_info[i].name;
250*27af7e00SGuenter Roeck         type_info.class_data = uhci_pci_info + i;
251*27af7e00SGuenter Roeck         type_register(&type_info);
252*27af7e00SGuenter Roeck     }
253*27af7e00SGuenter Roeck }
254*27af7e00SGuenter Roeck 
255*27af7e00SGuenter Roeck type_init(uhci_pci_register_types)
256