PERFORCE change 181646 for review
Hans Petter Selasky
hselasky at FreeBSD.org
Sat Jul 31 14:55:00 UTC 2010
http://p4web.freebsd.org/@@181646?ac=10
Change 181646 by hselasky at hselasky_laptop001 on 2010/07/31 14:53:59
USB controller (XHCI):
- add more initialisation logic and register definitions
Affected files ...
.. //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#3 edit
.. //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#5 edit
.. //depot/projects/usb/src/sys/dev/usb/controller/xhcireg.h#6 edit
Differences ...
==== //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#3 (text+ko) ====
@@ -112,29 +112,187 @@
void
xhci_iterate_hw_softc(struct usb_bus *bus, usb_bus_mem_sub_cb_t *cb)
{
+ struct xhci_softc *sc = XHCI_BUS2SC(bus);
+ cb(bus, &sc->sc_hw.root_pc, &sc->sc_hw.root_pg,
+ sizeof(struct xhci_hw_root), XHCI_PAGE_SIZE);
+ cb(bus, &sc->sc_ctx.root_pc, &sc->sc_ctx.root_pg,
+ sizeof(struct xhci_ctx_root), XHCI_PAGE_SIZE);
}
-usb_error_t
-xhci_reset(struct xhci_softc *sc)
+static usb_error_t
+xhci_start_controller(struct xhci_softc *sc)
{
+ struct usb_page_search buf_res;
+ struct xhci_hw_root *phwr;
+ struct xhci_ctx_root *pctxr;
+ uint64_t addr;
+ uint32_t temp;
+ uint16_t i;
+
+ DPRINTF("\n");
+
+ sc->sc_capa_off = 0;
+ sc->sc_oper_off = XREAD4(sc, capa, XHCI_CAPLENGTH);
+ sc->sc_runt_off = XREAD4(sc, capa, XHCI_RTSOFF) & ~0xF;
+ sc->sc_door_off = XREAD4(sc, capa, XHCI_DBOFF) & ~0x3;
+
+ DPRINTF("xHCI version = 0x%04x\n", XREAD2(sc, capa, XHCI_HCIVERSION));
+
+ /* Reset controller */
+ XWRITE4(sc, oper, XHCI_USBCMD, XHCI_CMD_HCRST);
+
+ for (i = 0; i != 100; i++) {
+ usb_pause_mtx(NULL, hz / 1000);
+ temp = XREAD4(sc, XHCI_USBCMD) & XHCI_CMD_HCRST;
+ if (!temp)
+ break;
+ }
+
+ if (temp) {
+ device_printf(sc->sc_bus.bdev, "Controller reset timeout.\n");
+ return (USB_ERR_IOERROR);
+ }
+
+ if (!(XREAD4(sc, oper, XHCI_PAGESIZE) & XHCI_PAGESIZE_4K)) {
+ device_printf(sc->sc_bus.bdev, "Controller does not support 4K page size.\n");
+ return (USB_ERR_IOERROR);
+ }
+
+ temp = XREAD4(sc, oper, XHCI_USBSTS);
+
+ /* clear interrupts */
+ XWRITE4(sc, oper, XHCI_USBSTS, status);
+
+ /* disable all device notifications */
+ XWRITE4(sc, oper, XHCI_DNCTRL, 0);
+
+ /* setup device context base address */
+
+ usbd_get_page(&sc->sc_hw.ctx_pc, 0, &buf_res);
+
+ addr = buf_res.physaddr;
+ pctxr = buf_res.ptr;
+
+ memset(pctxr, 0, sizeof(*pctxr));
+
+ XWRITE4(sc, oper, XHCI_DCBAAP_LO, (uint32_t)addr);
+ XWRITE4(sc, oper, XHCI_DCBAAP_HI, (uint32_t)(addr >> 32));
+
+ /* setup number of device slots */
+
+ XWRITE4(sc, oper, XHCI_CONFIG, XHCI_MAX_DEVICES);
+
+ /* Setup interrupter registers */
+
+ temp = XREAD4(sc, runt, XHCI_IMAN(0));
+ temp |= XHCI_IMAN_IE_BIT | XHCI_IMAN_IP_BIT;
+ XWRITE4(sc, runt, XHCI_IMAN(0));
+
+ /* Setup interrupt rate */
+
+ XWRITE4(sc, runt, XHCI_IMOD, XHCI_IMOD_DEFAULT);
+
+ usbd_get_page(&sc->sc_hw.root_pc, 0, &buf_res);
+
+ phwr = buf_res.ptr;
+ addr = (uint64_t)buf_res.physaddr + (uintptr_t)&((struct xhci_hw_root *)0)->hwr_events[0];
+
+ /* reset hardware root structure */
+
+ memset(phwr, 0, sizeof(*phwr));
+
+ phwr->hwr_ring_seg[0].qwEvrsTablePtr = htole64(addr);
+ phwr->hwr_ring_seg[0].dwEvrsTableSize = htole32(XHCI_MAX_EVENTS);
+
+ /* Setup event table size */
+
+ temp = XREAD4(sc, capa, XHCI_HCSPARAMS2);
+
+ DPRINTF("hcsparams2=0x%08x\n", temp);
+
+ temp = XHCI_HCS2_ERST_MAX(temp);
+ temp = 1U << temp;
+ if (temp > XHCI_MAX_RSEG)
+ temp = XHCI_MAX_RSEG;
+
+ sc->sc_erst_max = temp;
+
+ XWRITE4(sc, runt, XHCI_ERSTSZ(0), temp);
+
+ XWRITE4(sc, oper, XHCI_ERDP_LO(0), (uint32_t)addr);
+ XWRITE4(sc, oper, XHCI_ERDP_HI(0), (uint32_t)(addr >> 32));
+
+ addr = (uint64_t)buf_res.physaddr;
+
+ XWRITE4(sc, oper, XHCI_ERSTBA_LO(0), (uint32_t)addr);
+ XWRITE4(sc, oper, XHCI_ERSTBA_HI(0), (uint32_t)(addr >> 32));
+
+ /* setup command ring control base address */
+
+ addr = (uint64_t)buf_res.physaddr + (uintptr_t)&((struct xhci_hw_root *)0)->hwr_commands[0];
+
+ XWRITE4(sc, oper, XHCI_CRCR_LO, (uint32_t)addr);
+ XWRITE4(sc, oper, XHCI_CRCR_HI, (uint32_t)(addr >> 32));
+
+ usb_bus_mem_flush_all(&sc->sc_bus, &ehci_iterate_hw_softc);
+
+ /* Go! */
+ XWRITE4(sc, oper, XHCI_USBCMD, XHCI_CMD_RS | XHCI_CMD_INTE | XHCI_CMD_HSEE);
+
+ for (i = 0; i != 100; i++) {
+ usb_pause_mtx(NULL, hz / 1000);
+ temp = XREAD4(sc, oper, XHCI_USBSTS) & XHCI_STS_HCH;
+ if (!temp)
+ break;
+ }
+ if (temp) {
+ device_printf(sc->sc_bus.bdev, "Run timeout.\n");
+ return (USB_ERR_IOERROR);
+ }
+ /* catch any lost interrupts */
+ xhci_do_poll(&sc->sc_bus);
+ return (0);
}
static usb_error_t
-xhci_hcreset(struct xhci_softc *sc)
+xhci_halt_controller(struct xhci_softc *sc)
{
+ uint32_t temp;
+ uint16_t i;
+
+ DPRINTF("\n");
+ /* Halt controller */
+ XWRITE4(sc, oper, XHCI_USBCMD, 0);
+
+ for (i = 0; i != 100; i++) {
+ usb_pause_mtx(NULL, hz / 1000);
+ temp = XREAD4(sc, oper, XHCI_USBSTS) & XHCI_STS_HCH;
+ if (temp)
+ break;
+ }
+ if (!temp) {
+ device_printf(sc->sc_bus.bdev, "Controller halt timeout.\n");
+ return (USB_ERR_IOERROR);
+ }
+ return (0);
}
usb_error_t
xhci_init(struct xhci_softc *sc)
{
+ /* set the bus revision */
+ sc->sc_bus.usbrev = USB_REV_3_0;
+ /* set up the bus struct */
+ sc->sc_bus.methods = &ehci_bus_methods;
+ return (0);
}
void
@@ -165,17 +323,6 @@
}
-static void
-xhci_transfer_intr_enqueue(struct usb_xfer *xfer)
-{
- /* check for early completion */
- if (xhci_check_transfer(xfer))
- return;
-
- /* put transfer on interrupt queue */
- usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer);
-}
-
static usb_error_t
xhci_generic_done_sub(struct usb_xfer *xfer)
{
@@ -377,12 +524,6 @@
}
static void
-xhci_pcd_enable(struct xhci_softc *sc)
-{
-
-}
-
-static void
xhci_interrupt_poll(struct xhci_softc *sc)
{
struct usb_xfer *xfer;
@@ -405,8 +546,40 @@
void
xhci_interrupt(struct xhci_softc *sc)
{
+ uint32_t status;
+
+ USB_BUS_LOCK(&sc->sc_bus);
+
+ DPRINTFN(16, "real interrupt\n");
+
+ status = XREAD4(sc, oper, XHCI_USBSTS);
+
+ if (status & XHCI_STS_PCD) {
+ xhci_root_intr(sc);
+ }
+
+ if (status & XHCI_STS_HCH) {
+ printf("%s: host controller halted\n",
+ __FUNCTION__);
+ }
+ if (status & XHCI_STS_HSE) {
+ printf("%s: host system error\n",
+ __FUNCTION__);
+ }
+ if (status & XHCI_STS_HCE) {
+ printf("%s: host controller error\n",
+ __FUNCTION__);
+ }
+
+ /* acknowledge interrupts */
+
+ XWRITE4(sc, oper, XHCI_USBSTS, status);
+
+ xhci_interrupt_poll(sc);
+
+ USB_BUS_UNLOCK(&sc->sc_bus);
}
/*------------------------------------------------------------------------*
@@ -873,7 +1046,26 @@
static void
xhci_root_intr(struct xhci_softc *sc)
{
+ uint16_t i;
+
+ USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED);
+ /* clear any old interrupt data */
+ memset(sc->sc_hub_idata, 0, sizeof(sc->sc_hub_idata));
+
+ for (i = 1; i <= sc->sc_noport; i++) {
+ /* pick out CHANGE bits from the status register */
+ if (XREAD4(sc, oper, XHCI_PORTSC(i)) & (
+ XHCI_PS_CSC | XHCI_PS_PEC |
+ XHCI_PS_OCC | XHCI_PS_WRC |
+ XHCI_PS_PRC | XHCI_PS_PLC |
+ XHCI_PS_CEC)) {
+ sc->sc_hub_idata[i / 8] |= 1 << (i % 8);
+ DPRINTF("port %d changed\n", i);
+ }
+ }
+ uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata,
+ sizeof(sc->sc_hub_idata));
}
/*------------------------------------------------------------------------*
@@ -918,7 +1110,7 @@
xhci_setup_generic_chain(xfer);
/* put transfer on interrupt queue */
- xhci_transfer_intr_enqueue(xfer);
+ usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer);
}
static void
@@ -986,8 +1178,8 @@
.bmAttributes = XXX,
HSETW(.wSpeedsSupported, 0x000C),
.bFunctionalitySupport = 8,
- .bU1DevExitLat = 128, /* dummy - not used */
- .bU2DevExitLat = 128, /* dummy - not used */
+ .bU1DevExitLat = 255, /* dummy - not used */
+ .bU2DevExitLat = 255, /* dummy - not used */
},
.cidd = {
.bLength = sizeof(xhci_bosd.cidd),
==== //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#5 (text+ko) ====
@@ -31,6 +31,7 @@
#define XHCI_MAX_SCRATCHPADS 32
#define XHCI_MAX_EVENTS (16 * 7)
#define XHCI_MAX_COMMANDS (16 * 7)
+#define XHCI_MAX_RSEG 1
#define XHCI_DEV_CTX_ADDR_ALIGN 64 /* bytes */
#define XHCI_DEV_CTX_ALIGN 64 /* bytes */
@@ -46,6 +47,7 @@
#define XHCI_TRB_ALIGN 16 /* bytes */
#define XHCI_QH_ALIGN 16 /* bytes */
#define XHCI_TD_ALIGN 16 /* bytes */
+#define XHCI_PAGE_SIZE 4096 /* bytes */
struct xhci_dev_ctx_addr {
volatile uint64_t qwBaaDevCtxAddr;
@@ -318,11 +320,16 @@
};
struct xhci_hw_root {
- struct xhci_event_ring_seg hwr_ring_seg[4];
+ struct xhci_event_ring_seg hwr_ring_seg[XHCI_MAX_RSEG];
+ volatile uint64_t hwr_padding[2];
struct xhci_trb hwr_events[XHCI_MAX_EVENTS];
struct xhci_trb hwr_commands[XHCI_MAX_COMMANDS];
};
+struct xhci_ctx_root {
+ volatile uint64_t ctxr_ptr[XHCI_MAX_DEVICES];
+};
+
struct xhci_endpoint_ext {
TAILQ_HEAD(, xhci_qh) head;
@@ -335,16 +342,24 @@
uint8_t pstreams;
};
+struct xhci_hw_dev {
+ struct usb_page_cache device_pc;
+ struct usb_page_cache input_pc;
+ struct usb_page_cache scratch_pc[XHCI_MAX_SCRATCHPADS];
+
+ struct usb_page device_pg;
+ struct usb_page input_pg;
+ struct usb_page scratch_pg[XHCI_MAX_SCRATCHPADS];
+};
+
struct xhci_hw_softc {
struct usb_page_cache root_pc;
- struct usb_page_cache device_pc[XHCI_MAX_DEVICES];
- struct usb_page_cache device_input_pc[XHCI_MAX_DEVICES];
- struct usb_page_cache device_sp_pc[XHCI_MAX_DEVICES][XHCI_MAX_SCRATCHPADS];
+ struct usb_page_cache ctx_pc;
struct usb_page root_pg;
- struct usb_page device_pg[XHCI_MAX_DEVICES];
- struct usb_page device_input_pg[XHCI_MAX_DEVICES];
- struct usb_page device_sp_pg[XHCI_MAX_DEVICES][XHCI_MAX_SCRATCHPADS];
+ sturct usb_page ctx_pg;
+
+ struct xhci_hw_dev devs[XHCI_MAX_DEVICES];
};
struct xhci_config_desc {
@@ -383,17 +398,15 @@
bus_space_tag_t sc_io_tag;
bus_space_handle_t sc_io_hdl;
- uint32_t sc_eintrs;
- uint32_t sc_cmd; /* shadow of cmd register during
- * suspend */
+ uint32_t sc_cmd; /* copy of cmd register */
+
+ uint32_t sc_oper_off; /* offset to operational registers */
+ uint32_t sc_capa_off; /* offset to capability registers */
+ uint32_t sc_runt_off; /* offset to runtime registers */
+ uint32_t sc_door_off; /* offset to doorbell registers */
uint16_t sc_flags; /* chip specific flags */
-
- uint16_t sc_pcib_off; /* offset to PCI registers */
- uint16_t sc_oper_off; /* offset to operational registers */
- uint16_t sc_capa_off; /* offset to capability registers */
- uint16_t sc_runt_off; /* offset to runtime registers */
- uint16_t sc_door_off; /* offset to doorbell registers */
+ uint16_t sc_erst_max;
uint8_t sc_noport; /* number of ports on root HUB */
uint8_t sc_addr; /* root HUB device address */
==== //depot/projects/usb/src/sys/dev/usb/controller/xhcireg.h#6 (text+ko) ====
@@ -64,9 +64,7 @@
#define XHCI_HCS0_PSA_SZ_MAX(x) (((x) >> 12) & 0xF) /* max pri. stream array size */
#define XHCI_HCS0_XECP(x) (((x) >> 16) & 0xFFFF) /* extended capabilities pointer */
#define XHCI_DBOFF 0x14 /* RO doorbell offset */
-#define XHCI_DBOFF_GET(x) (((x) >> 2) & 0x3FFFFFFF)
#define XHCI_RTSOFF 0x18 /* RO runtime register space offset */
-#define XHCI_RTSOFF_GET(x) (((x) >> 5) & 0x7FFFFFF)
/* XHCI operational registers. Offset given by XHCI_CAPLENGTH register */
#define XHCI_USBCMD 0x00 /* XHCI command */
More information about the p4-projects
mailing list