From: "andrzej zaborowski" <balrog@zabor.org>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH] Memory mapped OHCI host with PXA-specific bits.
Date: Fri, 16 Mar 2007 22:09:10 +0100 [thread overview]
Message-ID: <fb249edb0703161409k6d3fb767g110688f56a143c6a@mail.gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 399 bytes --]
This reuses the PCI OHCI code for a IO memory-mapped OHCI host (this
is what Intel PXA and Samsung S3C processors have). Also adds
PXA-specific things in the controller, in particular four additional
registers.
I renamed usb_ohci_init to usb_ohci_init_pci for consistency. Also
includes the OHCI remote-wakeup interrupt change that was posted to
the list earlier (numerous times?).
Cheers,
Andrew
[-- Attachment #2: 0006-Memory-mapped-OHCI-host-with-PXA-specific-bits.txt --]
[-- Type: text/plain, Size: 11230 bytes --]
From 554663523c5f44d8d06e8cce79b784900f92036e Mon Sep 17 00:00:00 2001
From: Andrzej Zaborowski <balrog@zabor.org>
Date: Fri, 16 Mar 2007 16:25:13 +0100
Subject: [PATCH] Memory mapped OHCI host with PXA-specific bits.
---
hw/ppc_chrp.c | 2 +-
hw/ppc_prep.c | 2 +-
hw/realview.c | 2 +-
hw/usb-ohci.c | 142 +++++++++++++++++++++++++++++++++++++++++------------
hw/usb.h | 4 +-
hw/versatilepb.c | 2 +-
6 files changed, 117 insertions(+), 37 deletions(-)
diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c
index 937be15..b1199e2 100644
--- a/hw/ppc_chrp.c
+++ b/hw/ppc_chrp.c
@@ -501,7 +501,7 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device,
}
if (usb_enabled) {
- usb_ohci_init(pci_bus, 3, -1);
+ usb_ohci_init_pci(pci_bus, 3, -1);
}
if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8)
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 27d3d48..32a3e52 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -666,7 +666,7 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device,
#endif
if (usb_enabled) {
- usb_ohci_init(pci_bus, 3, -1);
+ usb_ohci_init_pci(pci_bus, 3, -1);
}
nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE, 59);
diff --git a/hw/realview.c b/hw/realview.c
index 619739c..a5607e7 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -57,7 +57,7 @@ static void realview_init(int ram_size, int vga_ram_size, int boot_device,
pci_bus = pci_vpb_init(pic, 48, 1);
if (usb_enabled) {
- usb_ohci_init(pci_bus, 3, -1);
+ usb_ohci_init_pci(pci_bus, 3, -1);
}
scsi_hba = lsi_scsi_init(pci_bus, -1);
for (n = 0; n < MAX_DISKS; n++) {
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index de113e9..c03e8e7 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -2,6 +2,7 @@
* QEMU USB OHCI Emulation
* Copyright (c) 2004 Gianni Tedesco
* Copyright (c) 2006 CodeSourcery
+ * Copyright (c) 2006 Openedhand Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -52,11 +53,16 @@ typedef struct OHCIPort {
uint32_t ctrl;
} OHCIPort;
+typedef void (*ohci_irq_service_t)(void *opaque, int irq, int level);
+
typedef struct {
- struct PCIDevice pci_dev;
+ void *pic;
+ int irq;
+ ohci_irq_service_t set_irq;
target_phys_addr_t mem_base;
int mem;
int num_ports;
+ const char *name;
QEMUTimer *eof_timer;
int64_t sof_time;
@@ -90,6 +96,12 @@ typedef struct {
uint32_t rhstatus;
OHCIPort rhport[OHCI_MAX_PORTS];
+ /* PXA27x Non-OHCI events */
+ uint32_t hstatus;
+ uint32_t hmask;
+ uint32_t hreset;
+ uint32_t htest;
+
/* Active packets. */
uint32_t old_ctl;
USBPacket usb_packet;
@@ -256,6 +268,8 @@ struct ohci_td {
#define OHCI_CC_BUFFEROVERRUN 0xc
#define OHCI_CC_BUFFERUNDERRUN 0xd
+#define OHCI_HRESET_FSBIR (1 << 0)
+
/* Update IRQ levels */
static inline void ohci_intr_update(OHCIState *ohci)
{
@@ -265,7 +279,7 @@ static inline void ohci_intr_update(OHCIState *ohci)
(ohci->intr_status & ohci->intr))
level = 1;
- pci_set_irq(&ohci->pci_dev, 0, level);
+ ohci->set_irq(ohci->pic, ohci->irq, level);
}
/* Set an interrupt */
@@ -295,6 +309,11 @@ static void ohci_attach(USBPort *port1, USBDevice *dev)
else
port->ctrl &= ~OHCI_PORT_LSDA;
port->port.dev = dev;
+
+ /* notify of remote-wakeup */
+ if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND)
+ ohci_set_interrupt(s, OHCI_INTR_RD);
+
/* send the attach message */
usb_send_msg(dev, USB_MSG_ATTACH);
dprintf("usb-ohci: Attached port %d\n", port1->index);
@@ -367,7 +386,7 @@ static void ohci_reset(OHCIState *ohci)
usb_cancel_packet(&ohci->usb_packet);
ohci->async_td = 0;
}
- dprintf("usb-ohci: Reset %s\n", ohci->pci_dev.name);
+ dprintf("usb-ohci: Reset %s\n", ohci->name);
}
/* Get an array of dwords from main memory */
@@ -795,13 +814,12 @@ static int ohci_bus_start(OHCIState *ohci)
ohci);
if (ohci->eof_timer == NULL) {
- fprintf(stderr, "usb-ohci: %s: qemu_new_timer failed\n",
- ohci->pci_dev.name);
+ fprintf(stderr, "usb-ohci: %s: qemu_new_timer failed\n", ohci->name);
/* TODO: Signal unrecoverable error */
return 0;
}
- dprintf("usb-ohci: %s: USB Operational\n", ohci->pci_dev.name);
+ dprintf("usb-ohci: %s: USB Operational\n", ohci->name);
ohci_sof(ohci);
@@ -854,7 +872,7 @@ static void ohci_set_frame_interval(OHCIState *ohci, uint16_t val)
if (val != ohci->fi) {
dprintf("usb-ohci: %s: FrameInterval = 0x%x (%u)\n",
- ohci->pci_dev.name, ohci->fi, ohci->fi);
+ ohci->name, ohci->fi, ohci->fi);
}
ohci->fi = val;
@@ -892,13 +910,13 @@ static void ohci_set_ctl(OHCIState *ohci, uint32_t val)
break;
case OHCI_USB_SUSPEND:
ohci_bus_stop(ohci);
- dprintf("usb-ohci: %s: USB Suspended\n", ohci->pci_dev.name);
+ dprintf("usb-ohci: %s: USB Suspended\n", ohci->name);
break;
case OHCI_USB_RESUME:
- dprintf("usb-ohci: %s: USB Resume\n", ohci->pci_dev.name);
+ dprintf("usb-ohci: %s: USB Resume\n", ohci->name);
break;
case OHCI_USB_RESET:
- dprintf("usb-ohci: %s: USB Reset\n", ohci->pci_dev.name);
+ dprintf("usb-ohci: %s: USB Reset\n", ohci->name);
break;
}
}
@@ -1086,6 +1104,19 @@ static uint32_t ohci_mem_read(void *ptr, target_phys_addr_t addr)
case 20: /* HcRhStatus */
return ohci->rhstatus;
+ /* PXA27x specific registers */
+ case 24: /* HcStatus */
+ return ohci->hstatus & ohci->hmask;
+
+ case 25: /* HcHReset */
+ return ohci->hreset;
+
+ case 26: /* HcHInterruptEnable */
+ return ohci->hmask;
+
+ case 27: /* HcHInterruptTest */
+ return ohci->htest;
+
default:
fprintf(stderr, "ohci_read: Bad offset %x\n", (int)addr);
return 0xffffffff;
@@ -1187,6 +1218,24 @@ static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val)
ohci_set_hub_status(ohci, val);
break;
+ /* PXA27x specific registers */
+ case 24: /* HcStatus */
+ ohci->hstatus &= ~(val & ohci->hmask);
+
+ case 25: /* HcHReset */
+ ohci->hreset = val & ~OHCI_HRESET_FSBIR;
+ if (val & OHCI_HRESET_FSBIR)
+ ohci_reset(ohci);
+ break;
+
+ case 26: /* HcHInterruptEnable */
+ ohci->hmask = val;
+ break;
+
+ case 27: /* HcHInterruptTest */
+ ohci->htest = val;
+ break;
+
default:
fprintf(stderr, "ohci_write: Bad offset %x\n", (int)addr);
break;
@@ -1207,22 +1256,11 @@ static CPUWriteMemoryFunc *ohci_writefn[3]={
ohci_mem_write
};
-static void ohci_mapfunc(PCIDevice *pci_dev, int i,
- uint32_t addr, uint32_t size, int type)
-{
- OHCIState *ohci = (OHCIState *)pci_dev;
- ohci->mem_base = addr;
- cpu_register_physical_memory(addr, size, ohci->mem);
-}
-
-void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn)
+static void usb_ohci_init(OHCIState *ohci, int num_ports, int devfn,
+ void *pic, int irq, ohci_irq_service_t set_irq, const char *name)
{
- OHCIState *ohci;
- int vid = 0x106b;
- int did = 0x003f;
int i;
-
if (usb_frame_time == 0) {
#if OHCI_TIME_WARP
usb_frame_time = ticks_per_sec;
@@ -1239,8 +1277,43 @@ void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn)
usb_frame_time, usb_bit_time);
}
- ohci = (OHCIState *)pci_register_device(bus, "OHCI USB", sizeof(*ohci),
- devfn, NULL, NULL);
+ ohci->mem = cpu_register_io_memory(0, ohci_readfn, ohci_writefn, ohci);
+ ohci->name = name;
+
+ ohci->pic = pic;
+ ohci->irq = irq;
+ ohci->set_irq = set_irq;
+
+ ohci->num_ports = num_ports;
+ for (i = 0; i < num_ports; i++) {
+ qemu_register_usb_port(&ohci->rhport[i].port, ohci, i, ohci_attach);
+ }
+
+ ohci->async_td = 0;
+ ohci_reset(ohci);
+}
+
+typedef struct {
+ PCIDevice pci_dev;
+ OHCIState state;
+} OHCIPCIState;
+
+static void ohci_mapfunc(PCIDevice *pci_dev, int i,
+ uint32_t addr, uint32_t size, int type)
+{
+ OHCIPCIState *ohci = (OHCIPCIState *)pci_dev;
+ ohci->state.mem_base = addr;
+ cpu_register_physical_memory(addr, size, ohci->state.mem);
+}
+
+void usb_ohci_init_pci(struct PCIBus *bus, int num_ports, int devfn)
+{
+ OHCIPCIState *ohci;
+ int vid = 0x106b;
+ int did = 0x003f;
+
+ ohci = (OHCIPCIState *)pci_register_device(bus, "OHCI USB", sizeof(*ohci),
+ devfn, NULL, NULL);
if (ohci == NULL) {
fprintf(stderr, "usb-ohci: Failed to register PCI device\n");
return;
@@ -1255,16 +1328,21 @@ void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn)
ohci->pci_dev.config[0x0b] = 0xc;
ohci->pci_dev.config[0x3d] = 0x01; /* interrupt pin 1 */
- ohci->mem = cpu_register_io_memory(0, ohci_readfn, ohci_writefn, ohci);
+ usb_ohci_init(&ohci->state, num_ports, devfn, &ohci->pci_dev,
+ 0, (ohci_irq_service_t) pci_set_irq, ohci->pci_dev.name);
pci_register_io_region((struct PCIDevice *)ohci, 0, 256,
PCI_ADDRESS_SPACE_MEM, ohci_mapfunc);
+}
- ohci->num_ports = num_ports;
- for (i = 0; i < num_ports; i++) {
- qemu_register_usb_port(&ohci->rhport[i].port, ohci, i, ohci_attach);
- }
+void usb_ohci_init_memio(target_phys_addr_t base, int num_ports, int devfn,
+ void *pic, int irq)
+{
+ OHCIState *ohci = (OHCIState *)qemu_mallocz(sizeof(OHCIState));
- ohci->async_td = 0;
- ohci_reset(ohci);
+ usb_ohci_init(ohci, num_ports, devfn, pic, irq,
+ pic_set_irq_new, "OHCI USB");
+ ohci->mem_base = base;
+
+ cpu_register_physical_memory(ohci->mem_base, 0xfff, ohci->mem);
}
diff --git a/hw/usb.h b/hw/usb.h
index a6d0ae6..aa57f01 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -206,7 +206,9 @@ USBDevice *usb_hub_init(int nb_ports);
void usb_uhci_init(PCIBus *bus, int devfn);
/* usb-ohci.c */
-void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn);
+void usb_ohci_init_pci(struct PCIBus *bus, int num_ports, int devfn);
+void usb_ohci_init_memio(target_phys_addr_t base, int num_ports, int devfn,
+ void *pic, int irq);
/* usb-linux.c */
USBDevice *usb_host_device_open(const char *devname);
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index 050878d..5d3e857 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -195,7 +195,7 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device,
}
}
if (usb_enabled) {
- usb_ohci_init(pci_bus, 3, -1);
+ usb_ohci_init_pci(pci_bus, 3, -1);
}
scsi_hba = lsi_scsi_init(pci_bus, -1);
for (n = 0; n < MAX_DISKS; n++) {
--
1.4.4.3
reply other threads:[~2007-03-16 21:10 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=fb249edb0703161409k6d3fb767g110688f56a143c6a@mail.gmail.com \
--to=balrog@zabor.org \
--cc=balrogg@gmail.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).