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++) { | ... | ... |