Commit e24ad6f140f23e1edc1646ea248819698b77f0e2
1 parent
60a9f9ec
OHCI USB PXA support (Andrzej Zaborowski).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2490 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
6 changed files
with
123 additions
and
37 deletions
hw/ppc_chrp.c
... | ... | @@ -501,7 +501,7 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, |
501 | 501 | } |
502 | 502 | |
503 | 503 | if (usb_enabled) { |
504 | - usb_ohci_init(pci_bus, 3, -1); | |
504 | + usb_ohci_init_pci(pci_bus, 3, -1); | |
505 | 505 | } |
506 | 506 | |
507 | 507 | if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8) | ... | ... |
hw/ppc_prep.c
... | ... | @@ -666,7 +666,7 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, |
666 | 666 | #endif |
667 | 667 | |
668 | 668 | if (usb_enabled) { |
669 | - usb_ohci_init(pci_bus, 3, -1); | |
669 | + usb_ohci_init_pci(pci_bus, 3, -1); | |
670 | 670 | } |
671 | 671 | |
672 | 672 | nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE, 59); | ... | ... |
hw/realview.c
... | ... | @@ -57,7 +57,7 @@ static void realview_init(int ram_size, int vga_ram_size, int boot_device, |
57 | 57 | |
58 | 58 | pci_bus = pci_vpb_init(pic, 48, 1); |
59 | 59 | if (usb_enabled) { |
60 | - usb_ohci_init(pci_bus, 3, -1); | |
60 | + usb_ohci_init_pci(pci_bus, 3, -1); | |
61 | 61 | } |
62 | 62 | scsi_hba = lsi_scsi_init(pci_bus, -1); |
63 | 63 | for (n = 0; n < MAX_DISKS; n++) { | ... | ... |
hw/usb-ohci.c
... | ... | @@ -2,6 +2,7 @@ |
2 | 2 | * QEMU USB OHCI Emulation |
3 | 3 | * Copyright (c) 2004 Gianni Tedesco |
4 | 4 | * Copyright (c) 2006 CodeSourcery |
5 | + * Copyright (c) 2006 Openedhand Ltd. | |
5 | 6 | * |
6 | 7 | * This library is free software; you can redistribute it and/or |
7 | 8 | * modify it under the terms of the GNU Lesser General Public |
... | ... | @@ -52,11 +53,19 @@ typedef struct OHCIPort { |
52 | 53 | uint32_t ctrl; |
53 | 54 | } OHCIPort; |
54 | 55 | |
56 | +enum ohci_type { | |
57 | + OHCI_TYPE_PCI, | |
58 | + OHCI_TYPE_PXA | |
59 | +}; | |
60 | + | |
55 | 61 | typedef struct { |
56 | - struct PCIDevice pci_dev; | |
62 | + void *pic; | |
63 | + int irq; | |
64 | + enum ohci_type type; | |
57 | 65 | target_phys_addr_t mem_base; |
58 | 66 | int mem; |
59 | 67 | int num_ports; |
68 | + const char *name; | |
60 | 69 | |
61 | 70 | QEMUTimer *eof_timer; |
62 | 71 | int64_t sof_time; |
... | ... | @@ -90,6 +99,12 @@ typedef struct { |
90 | 99 | uint32_t rhstatus; |
91 | 100 | OHCIPort rhport[OHCI_MAX_PORTS]; |
92 | 101 | |
102 | + /* PXA27x Non-OHCI events */ | |
103 | + uint32_t hstatus; | |
104 | + uint32_t hmask; | |
105 | + uint32_t hreset; | |
106 | + uint32_t htest; | |
107 | + | |
93 | 108 | /* Active packets. */ |
94 | 109 | uint32_t old_ctl; |
95 | 110 | USBPacket usb_packet; |
... | ... | @@ -256,6 +271,8 @@ struct ohci_td { |
256 | 271 | #define OHCI_CC_BUFFEROVERRUN 0xc |
257 | 272 | #define OHCI_CC_BUFFERUNDERRUN 0xd |
258 | 273 | |
274 | +#define OHCI_HRESET_FSBIR (1 << 0) | |
275 | + | |
259 | 276 | /* Update IRQ levels */ |
260 | 277 | static inline void ohci_intr_update(OHCIState *ohci) |
261 | 278 | { |
... | ... | @@ -265,7 +282,10 @@ static inline void ohci_intr_update(OHCIState *ohci) |
265 | 282 | (ohci->intr_status & ohci->intr)) |
266 | 283 | level = 1; |
267 | 284 | |
268 | - pci_set_irq(&ohci->pci_dev, 0, level); | |
285 | + if (ohci->type == OHCI_TYPE_PCI) | |
286 | + pci_set_irq((PCIDevice *)ohci->pic, ohci->irq, level); | |
287 | + else | |
288 | + pic_set_irq_new(ohci->pic, ohci->irq, level); | |
269 | 289 | } |
270 | 290 | |
271 | 291 | /* Set an interrupt */ |
... | ... | @@ -295,6 +315,11 @@ static void ohci_attach(USBPort *port1, USBDevice *dev) |
295 | 315 | else |
296 | 316 | port->ctrl &= ~OHCI_PORT_LSDA; |
297 | 317 | port->port.dev = dev; |
318 | + | |
319 | + /* notify of remote-wakeup */ | |
320 | + if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) | |
321 | + ohci_set_interrupt(s, OHCI_INTR_RD); | |
322 | + | |
298 | 323 | /* send the attach message */ |
299 | 324 | usb_send_msg(dev, USB_MSG_ATTACH); |
300 | 325 | dprintf("usb-ohci: Attached port %d\n", port1->index); |
... | ... | @@ -367,7 +392,7 @@ static void ohci_reset(OHCIState *ohci) |
367 | 392 | usb_cancel_packet(&ohci->usb_packet); |
368 | 393 | ohci->async_td = 0; |
369 | 394 | } |
370 | - dprintf("usb-ohci: Reset %s\n", ohci->pci_dev.name); | |
395 | + dprintf("usb-ohci: Reset %s\n", ohci->name); | |
371 | 396 | } |
372 | 397 | |
373 | 398 | /* Get an array of dwords from main memory */ |
... | ... | @@ -795,13 +820,12 @@ static int ohci_bus_start(OHCIState *ohci) |
795 | 820 | ohci); |
796 | 821 | |
797 | 822 | if (ohci->eof_timer == NULL) { |
798 | - fprintf(stderr, "usb-ohci: %s: qemu_new_timer failed\n", | |
799 | - ohci->pci_dev.name); | |
823 | + fprintf(stderr, "usb-ohci: %s: qemu_new_timer failed\n", ohci->name); | |
800 | 824 | /* TODO: Signal unrecoverable error */ |
801 | 825 | return 0; |
802 | 826 | } |
803 | 827 | |
804 | - dprintf("usb-ohci: %s: USB Operational\n", ohci->pci_dev.name); | |
828 | + dprintf("usb-ohci: %s: USB Operational\n", ohci->name); | |
805 | 829 | |
806 | 830 | ohci_sof(ohci); |
807 | 831 | |
... | ... | @@ -854,7 +878,7 @@ static void ohci_set_frame_interval(OHCIState *ohci, uint16_t val) |
854 | 878 | |
855 | 879 | if (val != ohci->fi) { |
856 | 880 | dprintf("usb-ohci: %s: FrameInterval = 0x%x (%u)\n", |
857 | - ohci->pci_dev.name, ohci->fi, ohci->fi); | |
881 | + ohci->name, ohci->fi, ohci->fi); | |
858 | 882 | } |
859 | 883 | |
860 | 884 | ohci->fi = val; |
... | ... | @@ -892,13 +916,13 @@ static void ohci_set_ctl(OHCIState *ohci, uint32_t val) |
892 | 916 | break; |
893 | 917 | case OHCI_USB_SUSPEND: |
894 | 918 | ohci_bus_stop(ohci); |
895 | - dprintf("usb-ohci: %s: USB Suspended\n", ohci->pci_dev.name); | |
919 | + dprintf("usb-ohci: %s: USB Suspended\n", ohci->name); | |
896 | 920 | break; |
897 | 921 | case OHCI_USB_RESUME: |
898 | - dprintf("usb-ohci: %s: USB Resume\n", ohci->pci_dev.name); | |
922 | + dprintf("usb-ohci: %s: USB Resume\n", ohci->name); | |
899 | 923 | break; |
900 | 924 | case OHCI_USB_RESET: |
901 | - dprintf("usb-ohci: %s: USB Reset\n", ohci->pci_dev.name); | |
925 | + dprintf("usb-ohci: %s: USB Reset\n", ohci->name); | |
902 | 926 | break; |
903 | 927 | } |
904 | 928 | } |
... | ... | @@ -1086,6 +1110,19 @@ static uint32_t ohci_mem_read(void *ptr, target_phys_addr_t addr) |
1086 | 1110 | case 20: /* HcRhStatus */ |
1087 | 1111 | return ohci->rhstatus; |
1088 | 1112 | |
1113 | + /* PXA27x specific registers */ | |
1114 | + case 24: /* HcStatus */ | |
1115 | + return ohci->hstatus & ohci->hmask; | |
1116 | + | |
1117 | + case 25: /* HcHReset */ | |
1118 | + return ohci->hreset; | |
1119 | + | |
1120 | + case 26: /* HcHInterruptEnable */ | |
1121 | + return ohci->hmask; | |
1122 | + | |
1123 | + case 27: /* HcHInterruptTest */ | |
1124 | + return ohci->htest; | |
1125 | + | |
1089 | 1126 | default: |
1090 | 1127 | fprintf(stderr, "ohci_read: Bad offset %x\n", (int)addr); |
1091 | 1128 | return 0xffffffff; |
... | ... | @@ -1187,6 +1224,24 @@ static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val) |
1187 | 1224 | ohci_set_hub_status(ohci, val); |
1188 | 1225 | break; |
1189 | 1226 | |
1227 | + /* PXA27x specific registers */ | |
1228 | + case 24: /* HcStatus */ | |
1229 | + ohci->hstatus &= ~(val & ohci->hmask); | |
1230 | + | |
1231 | + case 25: /* HcHReset */ | |
1232 | + ohci->hreset = val & ~OHCI_HRESET_FSBIR; | |
1233 | + if (val & OHCI_HRESET_FSBIR) | |
1234 | + ohci_reset(ohci); | |
1235 | + break; | |
1236 | + | |
1237 | + case 26: /* HcHInterruptEnable */ | |
1238 | + ohci->hmask = val; | |
1239 | + break; | |
1240 | + | |
1241 | + case 27: /* HcHInterruptTest */ | |
1242 | + ohci->htest = val; | |
1243 | + break; | |
1244 | + | |
1190 | 1245 | default: |
1191 | 1246 | fprintf(stderr, "ohci_write: Bad offset %x\n", (int)addr); |
1192 | 1247 | break; |
... | ... | @@ -1207,22 +1262,11 @@ static CPUWriteMemoryFunc *ohci_writefn[3]={ |
1207 | 1262 | ohci_mem_write |
1208 | 1263 | }; |
1209 | 1264 | |
1210 | -static void ohci_mapfunc(PCIDevice *pci_dev, int i, | |
1211 | - uint32_t addr, uint32_t size, int type) | |
1212 | -{ | |
1213 | - OHCIState *ohci = (OHCIState *)pci_dev; | |
1214 | - ohci->mem_base = addr; | |
1215 | - cpu_register_physical_memory(addr, size, ohci->mem); | |
1216 | -} | |
1217 | - | |
1218 | -void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn) | |
1265 | +static void usb_ohci_init(OHCIState *ohci, int num_ports, int devfn, | |
1266 | + void *pic, int irq, enum ohci_type type, const char *name) | |
1219 | 1267 | { |
1220 | - OHCIState *ohci; | |
1221 | - int vid = 0x106b; | |
1222 | - int did = 0x003f; | |
1223 | 1268 | int i; |
1224 | 1269 | |
1225 | - | |
1226 | 1270 | if (usb_frame_time == 0) { |
1227 | 1271 | #if OHCI_TIME_WARP |
1228 | 1272 | usb_frame_time = ticks_per_sec; |
... | ... | @@ -1239,8 +1283,43 @@ void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn) |
1239 | 1283 | usb_frame_time, usb_bit_time); |
1240 | 1284 | } |
1241 | 1285 | |
1242 | - ohci = (OHCIState *)pci_register_device(bus, "OHCI USB", sizeof(*ohci), | |
1243 | - devfn, NULL, NULL); | |
1286 | + ohci->mem = cpu_register_io_memory(0, ohci_readfn, ohci_writefn, ohci); | |
1287 | + ohci->name = name; | |
1288 | + | |
1289 | + ohci->pic = pic; | |
1290 | + ohci->irq = irq; | |
1291 | + ohci->type = type; | |
1292 | + | |
1293 | + ohci->num_ports = num_ports; | |
1294 | + for (i = 0; i < num_ports; i++) { | |
1295 | + qemu_register_usb_port(&ohci->rhport[i].port, ohci, i, ohci_attach); | |
1296 | + } | |
1297 | + | |
1298 | + ohci->async_td = 0; | |
1299 | + ohci_reset(ohci); | |
1300 | +} | |
1301 | + | |
1302 | +typedef struct { | |
1303 | + PCIDevice pci_dev; | |
1304 | + OHCIState state; | |
1305 | +} OHCIPCIState; | |
1306 | + | |
1307 | +static void ohci_mapfunc(PCIDevice *pci_dev, int i, | |
1308 | + uint32_t addr, uint32_t size, int type) | |
1309 | +{ | |
1310 | + OHCIPCIState *ohci = (OHCIPCIState *)pci_dev; | |
1311 | + ohci->state.mem_base = addr; | |
1312 | + cpu_register_physical_memory(addr, size, ohci->state.mem); | |
1313 | +} | |
1314 | + | |
1315 | +void usb_ohci_init_pci(struct PCIBus *bus, int num_ports, int devfn) | |
1316 | +{ | |
1317 | + OHCIPCIState *ohci; | |
1318 | + int vid = 0x106b; | |
1319 | + int did = 0x003f; | |
1320 | + | |
1321 | + ohci = (OHCIPCIState *)pci_register_device(bus, "OHCI USB", sizeof(*ohci), | |
1322 | + devfn, NULL, NULL); | |
1244 | 1323 | if (ohci == NULL) { |
1245 | 1324 | fprintf(stderr, "usb-ohci: Failed to register PCI device\n"); |
1246 | 1325 | return; |
... | ... | @@ -1255,16 +1334,21 @@ void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn) |
1255 | 1334 | ohci->pci_dev.config[0x0b] = 0xc; |
1256 | 1335 | ohci->pci_dev.config[0x3d] = 0x01; /* interrupt pin 1 */ |
1257 | 1336 | |
1258 | - ohci->mem = cpu_register_io_memory(0, ohci_readfn, ohci_writefn, ohci); | |
1337 | + usb_ohci_init(&ohci->state, num_ports, devfn, &ohci->pci_dev, | |
1338 | + 0, OHCI_TYPE_PCI, ohci->pci_dev.name); | |
1259 | 1339 | |
1260 | 1340 | pci_register_io_region((struct PCIDevice *)ohci, 0, 256, |
1261 | 1341 | PCI_ADDRESS_SPACE_MEM, ohci_mapfunc); |
1342 | +} | |
1262 | 1343 | |
1263 | - ohci->num_ports = num_ports; | |
1264 | - for (i = 0; i < num_ports; i++) { | |
1265 | - qemu_register_usb_port(&ohci->rhport[i].port, ohci, i, ohci_attach); | |
1266 | - } | |
1344 | +void usb_ohci_init_pxa(target_phys_addr_t base, int num_ports, int devfn, | |
1345 | + void *pic, int irq) | |
1346 | +{ | |
1347 | + OHCIState *ohci = (OHCIState *)qemu_mallocz(sizeof(OHCIState)); | |
1267 | 1348 | |
1268 | - ohci->async_td = 0; | |
1269 | - ohci_reset(ohci); | |
1349 | + usb_ohci_init(ohci, num_ports, devfn, pic, irq, | |
1350 | + OHCI_TYPE_PXA, "OHCI USB"); | |
1351 | + ohci->mem_base = base; | |
1352 | + | |
1353 | + cpu_register_physical_memory(ohci->mem_base, 0xfff, ohci->mem); | |
1270 | 1354 | } | ... | ... |
hw/usb.h
... | ... | @@ -206,7 +206,9 @@ USBDevice *usb_hub_init(int nb_ports); |
206 | 206 | void usb_uhci_init(PCIBus *bus, int devfn); |
207 | 207 | |
208 | 208 | /* usb-ohci.c */ |
209 | -void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn); | |
209 | +void usb_ohci_init_pci(struct PCIBus *bus, int num_ports, int devfn); | |
210 | +void usb_ohci_init_pxa(target_phys_addr_t base, int num_ports, int devfn, | |
211 | + void *pic, int irq); | |
210 | 212 | |
211 | 213 | /* usb-linux.c */ |
212 | 214 | USBDevice *usb_host_device_open(const char *devname); | ... | ... |
hw/versatilepb.c
... | ... | @@ -195,7 +195,7 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device, |
195 | 195 | } |
196 | 196 | } |
197 | 197 | if (usb_enabled) { |
198 | - usb_ohci_init(pci_bus, 3, -1); | |
198 | + usb_ohci_init_pci(pci_bus, 3, -1); | |
199 | 199 | } |
200 | 200 | scsi_hba = lsi_scsi_init(pci_bus, -1); |
201 | 201 | for (n = 0; n < MAX_DISKS; n++) { | ... | ... |