summaryrefslogtreecommitdiff
path: root/sys/arch/arm
diff options
context:
space:
mode:
authorUwe Stuehler <uwe@cvs.openbsd.org>2006-11-25 18:10:30 +0000
committerUwe Stuehler <uwe@cvs.openbsd.org>2006-11-25 18:10:30 +0000
commit7535b19446bafa37c29fe0cefdcfcc8d3b16b636 (patch)
tree662c9086944bcef9e54324a114e21553093f6535 /sys/arch/arm
parent2db0b8cf67297a6807a655929b526c916d9bbb9b (diff)
Initial USB device controller (UDC) and USB CDC Ethernet function support
for PXA27x/Zaurus, not enabled yet; for dlg and dale :)
Diffstat (limited to 'sys/arch/arm')
-rw-r--r--sys/arch/arm/xscale/files.pxa2x04
-rw-r--r--sys/arch/arm/xscale/pxa27x_udc.c817
-rw-r--r--sys/arch/arm/xscale/pxa27x_udcreg.h21
3 files changed, 795 insertions, 47 deletions
diff --git a/sys/arch/arm/xscale/files.pxa2x0 b/sys/arch/arm/xscale/files.pxa2x0
index d37eb8edc0a..ec2b493eb36 100644
--- a/sys/arch/arm/xscale/files.pxa2x0
+++ b/sys/arch/arm/xscale/files.pxa2x0
@@ -1,4 +1,4 @@
-# $OpenBSD: files.pxa2x0,v 1.18 2005/12/20 02:37:09 drahn Exp $
+# $OpenBSD: files.pxa2x0,v 1.19 2006/11/25 18:10:29 uwe Exp $
# $NetBSD: files.pxa2x0,v 1.6 2004/05/01 19:09:14 thorpej Exp $
#
# Configuration info for Intel PXA2[51]0 CPU support
@@ -46,7 +46,7 @@ file arch/arm/xscale/pxa2x0_a4x_space.c com_pxaip
file arch/arm/xscale/pxa2x0_a4x_io.S com_pxaip
# PXA27x USB Device Controller
-device pxaudc
+device pxaudc: usbdev
attach pxaudc at pxaip
file arch/arm/xscale/pxa27x_udc.c pxaudc
diff --git a/sys/arch/arm/xscale/pxa27x_udc.c b/sys/arch/arm/xscale/pxa27x_udc.c
index 94f843422e2..e802860af51 100644
--- a/sys/arch/arm/xscale/pxa27x_udc.c
+++ b/sys/arch/arm/xscale/pxa27x_udc.c
@@ -1,7 +1,8 @@
-/* $OpenBSD: pxa27x_udc.c,v 1.5 2005/03/30 14:24:39 dlg Exp $ */
+/* $OpenBSD: pxa27x_udc.c,v 1.6 2006/11/25 18:10:29 uwe Exp $ */
/*
* Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
+ * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -20,31 +21,98 @@
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/kernel.h>
+#include <sys/malloc.h>
#include <machine/intr.h>
#include <machine/bus.h>
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdivar.h>
+#include <dev/usb/usbf.h>
+#include <dev/usb/usbfvar.h>
+
#include <arm/xscale/pxa2x0reg.h>
#include <arm/xscale/pxa2x0var.h>
#include <arm/xscale/pxa2x0_gpio.h>
#include <arm/xscale/pxa27x_udcreg.h>
+#define PXAUDC_EP0MAXP 16 /* XXX */
+#define PXAUDC_NEP 24 /* total number of endpoints */
-int pxaudc_match(struct device *, void *, void *);
-void pxaudc_attach(struct device *, struct device *, void *);
-int pxaudc_detach(struct device *, int);
-void pxaudc_power(int, void *);
+#include <machine/zaurus_reg.h> /* XXX */
-struct pxaudc_softc {
- struct device sc_dev;
- bus_space_tag_t sc_iot;
- bus_space_handle_t sc_ioh;
- bus_size_t sc_size;
+struct pxaudc_xfer {
+ struct usbf_xfer xfer;
+ u_int16_t frmlen;
+};
+struct pxaudc_pipe {
+ struct usbf_pipe pipe;
+ LIST_ENTRY(pxaudc_pipe) list;
+};
+
+struct pxaudc_softc {
+ struct usbf_bus sc_bus;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+ bus_size_t sc_size;
+ void *sc_ih;
+ void *sc_conn_ih;
void *sc_powerhook;
+ SIMPLEQ_HEAD(,usbf_xfer) sc_free_xfers; /* recycled xfers */
+ u_int32_t sc_icr0; /* enabled EP interrupts */
+ u_int32_t sc_icr1; /* enabled EP interrupts */
+ enum {
+ EP0_SETUP,
+ EP0_IN
+ } sc_ep0state;
+ u_int32_t sc_isr0; /* XXX deferred interrupts */
+ u_int32_t sc_isr1; /* XXX deferred interrupts */
+ u_int32_t sc_otgisr; /* XXX deferred interrupts */
+ struct pxaudc_pipe *sc_pipe[PXAUDC_NEP];
};
-void pxaudc_enable(struct pxaudc_softc *);
+int pxaudc_match(struct device *, void *, void *);
+void pxaudc_attach(struct device *, struct device *, void *);
+int pxaudc_detach(struct device *, int);
+void pxaudc_power(int, void *);
+
+int pxaudc_is_host(void);
+int pxaudc_is_device(void);
+void pxaudc_setup(struct pxaudc_softc *);
+void pxaudc_hide(struct pxaudc_softc *);
+void pxaudc_show(struct pxaudc_softc *);
+
+void pxaudc_enable(struct pxaudc_softc *);
+void pxaudc_disable(struct pxaudc_softc *);
+void pxaudc_read_ep0(struct pxaudc_softc *, usbf_xfer_handle);
+void pxaudc_write_ep0(struct pxaudc_softc *, usbf_xfer_handle);
+void pxaudc_write(struct pxaudc_softc *, usbf_xfer_handle);
+
+int pxaudc_connect_intr(void *);
+int pxaudc_intr(void *);
+void pxaudc_intr1(struct pxaudc_softc *);
+void pxaudc_ep0_intr(struct pxaudc_softc *);
+
+usbf_status pxaudc_open(struct usbf_pipe *);
+void pxaudc_softintr(void *);
+usbf_status pxaudc_allocm(struct usbf_bus *, usb_dma_t *, u_int32_t);
+void pxaudc_freem(struct usbf_bus *, usb_dma_t *);
+usbf_xfer_handle pxaudc_allocx(struct usbf_bus *);
+void pxaudc_freex(struct usbf_bus *, usbf_xfer_handle);
+
+usbf_status pxaudc_ctrl_transfer(usbf_xfer_handle);
+usbf_status pxaudc_ctrl_start(usbf_xfer_handle);
+void pxaudc_ctrl_abort(usbf_xfer_handle);
+void pxaudc_ctrl_done(usbf_xfer_handle);
+void pxaudc_ctrl_close(usbf_pipe_handle);
+
+usbf_status pxaudc_bulk_transfer(usbf_xfer_handle);
+usbf_status pxaudc_bulk_start(usbf_xfer_handle);
+void pxaudc_bulk_abort(usbf_xfer_handle);
+void pxaudc_bulk_done(usbf_xfer_handle);
+void pxaudc_bulk_close(usbf_pipe_handle);
struct cfattach pxaudc_ca = {
sizeof(struct pxaudc_softc), pxaudc_match, pxaudc_attach,
@@ -55,6 +123,52 @@ struct cfdriver pxaudc_cd = {
NULL, "pxaudc", DV_DULL
};
+struct usbf_bus_methods pxaudc_bus_methods = {
+ pxaudc_open,
+ pxaudc_softintr,
+ pxaudc_allocm,
+ pxaudc_freem,
+ pxaudc_allocx,
+ pxaudc_freex
+};
+
+struct usbf_pipe_methods pxaudc_ctrl_methods = {
+ pxaudc_ctrl_transfer,
+ pxaudc_ctrl_start,
+ pxaudc_ctrl_abort,
+ pxaudc_ctrl_done,
+ pxaudc_ctrl_close
+};
+
+struct usbf_pipe_methods pxaudc_bulk_methods = {
+ pxaudc_bulk_transfer,
+ pxaudc_bulk_start,
+ pxaudc_bulk_abort,
+ pxaudc_bulk_done,
+ pxaudc_bulk_close
+};
+
+#define DEVNAME(sc) USBDEVNAME((sc)->sc_bus.bdev)
+
+#define CSR_READ_4(sc, reg) \
+ bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))
+#define CSR_WRITE_4(sc, reg, val) \
+ bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
+#define CSR_WRITE_1(sc, reg, val) \
+ bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
+#define CSR_SET_4(sc, reg, val) \
+ CSR_WRITE_4((sc), (reg), CSR_READ_4((sc), (reg)) | (val))
+#define CSR_CLR_4(sc, reg, val) \
+ CSR_WRITE_4((sc), (reg), CSR_READ_4((sc), (reg)) & ~(val))
+
+#define PXAUDC_DEBUG
+#ifndef PXAUDC_DEBUG
+#define DPRINTF(l, x) do {} while (0)
+#else
+int pxaudcdebug = 0;
+#define DPRINTF(l, x) if ((l) <= pxaudcdebug) printf x; else {}
+#endif
+
int
pxaudc_match(struct device *parent, void *match, void *aux)
{
@@ -71,9 +185,6 @@ pxaudc_attach(struct device *parent, struct device *self, void *aux)
struct pxaip_attach_args *pxa = aux;
sc->sc_iot = pxa->pxa_iot;
- sc->sc_size = 0;
- sc->sc_powerhook = NULL;
-
if (bus_space_map(sc->sc_iot, PXA2X0_USBDC_BASE, PXA2X0_USBDC_SIZE, 0,
&sc->sc_ioh)) {
printf(": cannot map mem space\n");
@@ -86,18 +197,51 @@ pxaudc_attach(struct device *parent, struct device *self, void *aux)
bus_space_barrier(sc->sc_iot, sc->sc_ioh, 0, sc->sc_size,
BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
- pxa2x0_gpio_set_function(35, GPIO_ALT_FN_2_IN); /* USB_P2_1 */
- pxa2x0_gpio_set_function(37, GPIO_ALT_FN_1_OUT); /* USB_P2_8 */
- pxa2x0_gpio_set_function(41, GPIO_ALT_FN_2_IN); /* USB_P2_7 */
- pxa2x0_gpio_set_function(89, GPIO_ALT_FN_2_OUT); /* USBHPEN<1> */
- pxa2x0_gpio_set_function(120, GPIO_ALT_FN_2_OUT); /* USBHPEN<2> */
+ /* Set up GPIO pins and disable the controller. */
+ pxaudc_setup(sc);
+ pxaudc_disable(sc);
- pxa2x0_clkman_config(CKEN_USBDC, 0);
- pxaudc_enable(sc);
+ /* Establish USB device interrupt. */
+ sc->sc_ih = pxa2x0_intr_establish(PXA2X0_INT_USB, IPL_USB,
+ pxaudc_intr, sc, DEVNAME(sc));
+ if (sc->sc_ih == NULL) {
+ printf(": unable to establish interrupt\n");
+ bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
+ sc->sc_size = 0;
+ return;
+ }
- pxa2x0_gpio_set_bit(37); /* USB_P2_8 */
+ /* Establish device connect interrupt. */
+#if 0
+ sc->sc_conn_ih = pxa2x0_gpio_intr_establish(C3000_USB_DEVICE_PIN, /* XXX */
+ IST_EDGE_BOTH, IPL_USB, pxaudc_connect_intr, sc, "usbc");
+#endif
+ sc->sc_conn_ih = pxa2x0_gpio_intr_establish(C3000_USB_CONNECT_PIN,
+ IST_EDGE_BOTH, IPL_USB, pxaudc_connect_intr, sc, "usbc");
+ if (sc->sc_conn_ih == NULL) {
+ printf(": unable to establish connect interrupt\n");
+ pxa2x0_intr_disestablish(sc->sc_ih);
+ bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
+ sc->sc_ioh = NULL;
+ sc->sc_size = 0;
+ return;
+ }
sc->sc_powerhook = powerhook_establish(pxaudc_power, sc);
+
+ /* Set up the bus struct. */
+ sc->sc_bus.methods = &pxaudc_bus_methods;
+ sc->sc_bus.pipe_size = sizeof(struct pxaudc_pipe);
+ sc->sc_bus.ep0_maxp = PXAUDC_EP0MAXP;
+ sc->sc_bus.usbrev = USBREV_1_1;
+ sc->sc_bus.dmatag = pxa->pxa_dmat;
+
+ /* Attach logical device and function. */
+ (void)config_found(self, &sc->sc_bus, NULL);
+
+ /* Enable the controller unless we're now acting as a host. */
+ if (!pxaudc_is_host())
+ pxaudc_enable(sc);
}
int
@@ -108,6 +252,12 @@ pxaudc_detach(struct device *self, int flags)
if (sc->sc_powerhook != NULL)
powerhook_disestablish(sc->sc_powerhook);
+ if (sc->sc_conn_ih != NULL)
+ pxa2x0_gpio_intr_disestablish(sc->sc_conn_ih);
+
+ if (sc->sc_ih != NULL)
+ pxa2x0_intr_disestablish(sc->sc_ih);
+
if (sc->sc_size) {
bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
sc->sc_size = 0;
@@ -121,32 +271,611 @@ pxaudc_power(int why, void *arg)
{
struct pxaudc_softc *sc = (struct pxaudc_softc *)arg;
- if (why == PWR_RESUME)
+ switch (why) {
+ case PWR_SUSPEND:
+ case PWR_STANDBY:
+ pxaudc_disable(sc);
+ break;
+
+ case PWR_RESUME:
pxaudc_enable(sc);
+ break;
+ }
+}
+
+/*
+ * Machine-specific functions
+ */
+
+/* XXX move to machine-specific file */
+
+int
+pxaudc_is_host(void)
+{
+ return (!pxa2x0_gpio_get_bit(C3000_USB_CONNECT_PIN) &&
+ !pxa2x0_gpio_get_bit(C3000_USB_DEVICE_PIN));
+}
+
+int
+pxaudc_is_device(void)
+{
+ return (pxa2x0_gpio_get_bit(C3000_USB_CONNECT_PIN) &&
+ pxa2x0_gpio_get_bit(C3000_USB_DEVICE_PIN));
+}
+
+void
+pxaudc_setup(struct pxaudc_softc *sc)
+{
+ pxa2x0_gpio_set_function(45, GPIO_OUT);
+ pxa2x0_gpio_set_function(C3000_USB_CONNECT_PIN, GPIO_IN); /* 41 */
+ pxa2x0_gpio_set_function(40, GPIO_OUT);
+ pxa2x0_gpio_set_function(39, GPIO_IN);
+ pxa2x0_gpio_set_function(38, GPIO_IN);
+ pxa2x0_gpio_set_function(37, GPIO_OUT);
+ pxa2x0_gpio_set_function(36, GPIO_IN);
+ pxa2x0_gpio_set_function(C3000_USB_DEVICE_PIN, GPIO_IN); /* 35 */
+ pxa2x0_gpio_set_function(34, GPIO_IN);
+ pxa2x0_gpio_set_function(89, GPIO_OUT);
+ pxa2x0_gpio_set_function(120, GPIO_OUT);
+}
+
+/* Hide us from the host. */
+void
+pxaudc_hide(struct pxaudc_softc *sc)
+{
+ pxa2x0_gpio_clear_bit(C3000_USB_PULLUP_PIN);
+}
+
+/* Show us to the host. */
+void
+pxaudc_show(struct pxaudc_softc *sc)
+{
+ pxa2x0_gpio_set_bit(C3000_USB_PULLUP_PIN);
+}
+
+/*
+ * Register manipulation
+ */
+
+#if 0
+static void
+pxaudc_dump_regs(struct pxaudc_softc *sc)
+{
+ printf("UDCCR\t%b\n", CSR_READ_4(sc, USBDC_UDCCR),
+ USBDC_UDCCR_BITS);
+ printf("UDCICR0\t%b\n", CSR_READ_4(sc, USBDC_UDCICR0),
+ USBDC_UDCISR0_BITS);
+ printf("UDCICR1\t%b\n", CSR_READ_4(sc, USBDC_UDCICR1),
+ USBDC_UDCISR1_BITS);
+ printf("OTGICR\t%b\n", CSR_READ_4(sc, USBDC_UDCOTGICR),
+ USBDC_UDCOTGISR_BITS);
}
+#endif
void
pxaudc_enable(struct pxaudc_softc *sc)
{
- u_int32_t hr;
-
- /* disable the controller */
- hr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, USBDC_UDCCR);
- bus_space_write_4(sc->sc_iot, sc->sc_ioh, USBDC_UDCCR,
- hr & ~USBDC_UDCCR_UDE);
-
- hr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, USBDC_UDCICR1);
- bus_space_write_4(sc->sc_iot, sc->sc_ioh, USBDC_UDCICR1,
- hr | USBDC_UDCICR1_IERS);
-
- bus_space_write_4(sc->sc_iot, sc->sc_ioh, USBDC_UP2OCR, 0);
- hr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, USBDC_UP2OCR);
- bus_space_write_4(sc->sc_iot, sc->sc_ioh, USBDC_UP2OCR,
- hr | USBDC_UP2OCR_HXS);
- hr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, USBDC_UP2OCR);
- bus_space_write_4(sc->sc_iot, sc->sc_ioh, USBDC_UP2OCR,
- hr | USBDC_UP2OCR_HXOE);
- hr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, USBDC_UP2OCR);
- bus_space_write_4(sc->sc_iot, sc->sc_ioh, USBDC_UP2OCR,
- hr | USBDC_UP2OCR_DPPDE|USBDC_UP2OCR_DMPDE);
+ DPRINTF(0,("pxaudc_enable\n"));
+
+ /* Start the clocks. */
+ pxa2x0_clkman_config(CKEN_USBDC, 1);
+
+ /* Configure Port 2 for USB device. */
+ CSR_WRITE_4(sc, USBDC_UP2OCR, USBDC_UP2OCR_DMPUE |
+ USBDC_UP2OCR_DPPUE | USBDC_UP2OCR_HXOE);
+
+ /* Enable interrupts for configured endpoints. */
+ CSR_SET_4(sc, USBDC_UDCICR0, USBDC_UDCICR0_IE(0) |
+ sc->sc_icr0);
+ CSR_SET_4(sc, USBDC_UDCICR1, USBDC_UDCICR1_IERS |
+ USBDC_UDCICR1_IECC | sc->sc_icr1);
+
+ /* XXX */
+ CSR_WRITE_4(sc, USBDC_UDCICR0, 0x00000C3F);
+ CSR_WRITE_4(sc, USBDC_UDCECR(1), 0x0200D103);
+ CSR_WRITE_4(sc, USBDC_UDCECR(2), 0x02014103);
+ CSR_WRITE_4(sc, USBDC_UDCECR(3), 0x0201B403);
+ CSR_WRITE_4(sc, USBDC_UDCECR(4), 0x02022403);
+ CSR_WRITE_4(sc, USBDC_UDCECR(5), 0x0202F021);
+
+ /* Enable the controller. */
+ CSR_CLR_4(sc, USBDC_UDCCR, USBDC_UDCCR_EMCE);
+ CSR_SET_4(sc, USBDC_UDCCR, USBDC_UDCCR_UDE);
+
+ /* Enable USB client on port 2. */
+ pxa2x0_gpio_clear_bit(37); /* USB_P2_8 */
+}
+
+void
+pxaudc_disable(struct pxaudc_softc *sc)
+{
+ DPRINTF(0,("pxaudc_disable\n"));
+
+ /* Disable the controller. */
+ CSR_CLR_4(sc, USBDC_UDCCR, USBDC_UDCCR_UDE);
+
+ /* Disable all interrupts. */
+ CSR_WRITE_4(sc, USBDC_UDCICR0, 0);
+ CSR_WRITE_4(sc, USBDC_UDCICR1, 0);
+ CSR_WRITE_4(sc, USBDC_UDCOTGICR, 0);
+
+ /* Set Port 2 output to "Non-OTG Host with Differential Port". */
+ CSR_WRITE_4(sc, USBDC_UP2OCR, USBDC_UP2OCR_HXS |
+ USBDC_UP2OCR_HXOE);
+
+ /* Set "Host Port 2 Transceiver D­ Pull Down Enable". */
+ CSR_SET_4(sc, USBDC_UP2OCR, USBDC_UP2OCR_DMPDE);
+
+ /* Stop the clocks. */
+ pxa2x0_clkman_config(CKEN_USBDC, 0);
+
+ /* Enable USB host on port 2. */
+ pxa2x0_gpio_set_bit(37); /* USB_P2_8 */
+}
+
+/*
+ * Endpoint FIFO handling
+ */
+
+void
+pxaudc_read_ep0(struct pxaudc_softc *sc, usbf_xfer_handle xfer)
+{
+ size_t len;
+ u_int8_t *p;
+
+ xfer->actlen = CSR_READ_4(sc, USBDC_UDCBCR(0));
+ len = MIN(xfer->actlen, xfer->length);
+ p = xfer->buffer;
+
+ while (CSR_READ_4(sc, USBDC_UDCCSR0) & USBDC_UDCCSR0_RNE) {
+ u_int32_t v = CSR_READ_4(sc, USBDC_UDCDR(0));
+
+ if (len > 0) {
+ if (((unsigned)p & 0x3) == 0)
+ *(u_int32_t *)p = v;
+ else {
+ *(p+0) = v & 0xff;
+ *(p+1) = (v >> 8) & 0xff;
+ *(p+2) = (v >> 16) & 0xff;
+ *(p+3) = (v >> 24) & 0xff;
+ }
+ p += 4;
+ len -= 4;
+ }
+ }
+
+ CSR_WRITE_4(sc, USBDC_UDCCSR0, USBDC_UDCCSR0_SA | USBDC_UDCCSR0_OPC);
+
+ xfer->status = USBF_NORMAL_COMPLETION;
+ usbf_transfer_complete(xfer);
+}
+
+void
+pxaudc_write_ep0(struct pxaudc_softc *sc, usbf_xfer_handle xfer)
+{
+ struct pxaudc_xfer *lxfer = (struct pxaudc_xfer *)xfer;
+ u_int32_t len;
+ u_int8_t *p;
+
+ if (lxfer->frmlen > 0) {
+ xfer->actlen += lxfer->frmlen;
+ lxfer->frmlen = 0;
+ }
+
+ DPRINTF(1,("%s: ep0 ctrl-in, xfer=%p, len=%u, actlen=%u\n",
+ DEVNAME(sc), xfer, xfer->length, xfer->actlen));
+
+ if (xfer->actlen >= xfer->length) {
+ sc->sc_ep0state = EP0_SETUP;
+ usbf_transfer_complete(xfer);
+ return;
+ }
+
+ sc->sc_ep0state = EP0_IN;
+
+ p = (u_char *)xfer->buffer + xfer->actlen;
+ len = xfer->length - xfer->actlen;
+ len = MIN(len, PXAUDC_EP0MAXP);
+ lxfer->frmlen = len;
+
+ while (len >= 4) {
+ u_int32_t v;
+
+ if (((unsigned)p & 0x3) == 0)
+ v = *(u_int32_t *)p;
+ else {
+ v = *(p+0);
+ v |= *(p+1) << 8;
+ v |= *(p+2) << 16;
+ v |= *(p+3) << 24;
+ }
+
+ CSR_WRITE_4(sc, USBDC_UDCDR(0), v);
+ len -= 4;
+ p += 4;
+ }
+
+ while (len > 0) {
+ CSR_WRITE_1(sc, USBDC_UDCDR(0), *p);
+ len--;
+ p++;
+ }
+
+ /* (12.6.7) Set IPR only for short packets. */
+ if (lxfer->frmlen < PXAUDC_EP0MAXP)
+ CSR_SET_4(sc, USBDC_UDCCSR0, USBDC_UDCCSR0_IPR);
+}
+
+void
+pxaudc_write(struct pxaudc_softc *sc, usbf_xfer_handle xfer)
+{
+ printf("pxaudc_write: XXX\n");
+}
+
+/*
+ * Interrupt handling
+ */
+
+int
+pxaudc_connect_intr(void *v)
+{
+ struct pxaudc_softc *sc = v;
+
+ DPRINTF(0,("pxaudc_connect_intr: connect=%d device=%d\n",
+ pxa2x0_gpio_get_bit(C3000_USB_CONNECT_PIN),
+ pxa2x0_gpio_get_bit(C3000_USB_DEVICE_PIN)));
+
+ /* XXX only set a flag here */
+ if (pxaudc_is_host()) {
+ pxaudc_disable(sc);
+ } else {
+ pxaudc_enable(sc);
+ }
+
+ /* Claim this interrupt. */
+ return 1;
+}
+
+int
+pxaudc_intr(void *v)
+{
+ struct pxaudc_softc *sc = v;
+ u_int32_t isr0, isr1, otgisr;
+
+ isr0 = CSR_READ_4(sc, USBDC_UDCISR0);
+ isr1 = CSR_READ_4(sc, USBDC_UDCISR1);
+ otgisr = CSR_READ_4(sc, USBDC_UDCOTGISR);
+
+ DPRINTF(1,("pxaudc_intr: isr0=%b, isr1=%b, otgisr=%b\n",
+ isr0, USBDC_UDCISR0_BITS, isr1, USBDC_UDCISR1_BITS,
+ otgisr, USBDC_UDCOTGISR_BITS));
+
+ if (isr0 || isr1 || otgisr) {
+ sc->sc_isr0 |= isr0;
+ sc->sc_isr1 |= isr1;
+ sc->sc_otgisr |= otgisr;
+
+ //usbf_schedsoftintr(&sc->sc_bus);
+ pxaudc_intr1(sc); /* XXX */
+ }
+
+ CSR_WRITE_4(sc, USBDC_UDCISR0, isr0);
+ CSR_WRITE_4(sc, USBDC_UDCISR1, isr1);
+ CSR_WRITE_4(sc, USBDC_UDCOTGISR, otgisr);
+
+ /* Claim this interrupt. */
+ return 1;
+}
+
+void
+pxaudc_intr1(struct pxaudc_softc *sc)
+{
+ u_int32_t isr0, isr1, otgisr;
+ //int s;
+
+ //s = splhardusb();
+ isr0 = sc->sc_isr0;
+ isr1 = sc->sc_isr1;
+ otgisr = sc->sc_otgisr;
+ sc->sc_isr0 = 0;
+ sc->sc_isr1 = 0;
+ sc->sc_otgisr = 0;
+ //splx(s);
+
+ sc->sc_bus.intr_context++;
+
+ /* Handle USB RESET condition. */
+ if (isr1 & USBDC_UDCISR1_IRRS) {
+ sc->sc_ep0state = EP0_SETUP;
+ usbf_host_reset(&sc->sc_bus);
+ /* Discard all other interrupts. */
+ goto ret;
+ }
+
+ /* Service control pipe interrupts. */
+ if (isr0 & USBDC_UDCISR0_IR(0))
+ pxaudc_ep0_intr(sc);
+
+ret:
+ sc->sc_bus.intr_context--;
+}
+
+void
+pxaudc_ep0_intr(struct pxaudc_softc *sc)
+{
+ struct pxaudc_pipe *ppipe;
+ usbf_pipe_handle pipe = NULL;
+ usbf_xfer_handle xfer = NULL;
+ u_int32_t csr0;
+
+ csr0 = CSR_READ_4(sc, USBDC_UDCCSR0);
+ DPRINTF(1,("pxaudc_ep0_intr: csr0=%b\n", csr0, USBDC_UDCCSR0_BITS));
+
+ ppipe = sc->sc_pipe[0];
+ if (ppipe != NULL) {
+ pipe = &ppipe->pipe;
+ xfer = SIMPLEQ_FIRST(&pipe->queue);
+ }
+
+ if (sc->sc_ep0state == EP0_SETUP && (csr0 & USBDC_UDCCSR0_OPC)) {
+ if (pipe == NULL) {
+ DPRINTF(0,("pxaudc_ep0_intr: no control pipe\n"));
+ return;
+ }
+
+ if (xfer == NULL) {
+ DPRINTF(0,("pxaudc_ep0_intr: no xfer\n"));
+ return;
+ }
+
+ pxaudc_read_ep0(sc, xfer);
+ } else if (sc->sc_ep0state == EP0_IN &&
+ (csr0 & USBDC_UDCCSR0_IPR) == 0 && xfer) {
+ pxaudc_write_ep0(sc, xfer);
+ }
+}
+
+/*
+ * Bus methods
+ */
+
+usbf_status
+pxaudc_open(struct usbf_pipe *pipe)
+{
+ struct pxaudc_softc *sc = (struct pxaudc_softc *)pipe->device->bus;
+ struct pxaudc_pipe *ppipe = (struct pxaudc_pipe *)pipe;
+ int s;
+
+ if (usbf_endpoint_index(pipe->endpoint) >= PXAUDC_NEP)
+ return USBF_BAD_ADDRESS;
+
+ DPRINTF(1,("pxaudc_open\n"));
+ s = splhardusb();
+
+ switch (usbf_endpoint_type(pipe->endpoint)) {
+ case UE_CONTROL:
+ pipe->methods = &pxaudc_ctrl_methods;
+ break;
+
+ case UE_BULK:
+ pipe->methods = &pxaudc_bulk_methods;
+ break;
+
+ case UE_ISOCHRONOUS:
+ case UE_INTERRUPT:
+ default:
+ /* XXX */
+ splx(s);
+ return USBF_BAD_ADDRESS;
+ }
+
+ sc->sc_pipe[usbf_endpoint_index(pipe->endpoint)] = ppipe;
+
+ splx(s);
+ return USBF_NORMAL_COMPLETION;
+}
+
+void
+pxaudc_softintr(void *v)
+{
+ struct pxaudc_softc *sc = v;
+
+ pxaudc_intr1(sc);
+}
+
+usbf_status
+pxaudc_allocm(struct usbf_bus *bus, usb_dma_t *dmap, u_int32_t size)
+{
+ return usbf_allocmem(bus, size, 0, dmap);
+}
+
+void
+pxaudc_freem(struct usbf_bus *bus, usb_dma_t *dmap)
+{
+ usbf_freemem(bus, dmap);
+}
+
+usbf_xfer_handle
+pxaudc_allocx(struct usbf_bus *bus)
+{
+ struct pxaudc_softc *sc = (struct pxaudc_softc *)bus;
+ usbf_xfer_handle xfer;
+
+ xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers);
+ if (xfer != NULL)
+ SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next);
+ else
+ xfer = malloc(sizeof(struct pxaudc_xfer), M_USB, M_NOWAIT);
+ if (xfer != NULL)
+ bzero(xfer, sizeof(struct pxaudc_xfer));
+ return xfer;
+}
+
+void
+pxaudc_freex(struct usbf_bus *bus, usbf_xfer_handle xfer)
+{
+ struct pxaudc_softc *sc = (struct pxaudc_softc *)bus;
+
+ SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next);
+}
+
+/*
+ * Control pipe methods
+ */
+
+usbf_status
+pxaudc_ctrl_transfer(usbf_xfer_handle xfer)
+{
+ usbf_status err;
+
+ /* Insert last in queue. */
+ err = usbf_insert_transfer(xfer);
+ if (err)
+ return err;
+
+ /*
+ * Pipe isn't running (otherwise err would be USBF_IN_PROGRESS),
+ * so start first.
+ */
+ return pxaudc_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue));
+}
+
+usbf_status
+pxaudc_ctrl_start(usbf_xfer_handle xfer)
+{
+ struct usbf_pipe *pipe = xfer->pipe;
+ struct pxaudc_softc *sc = (struct pxaudc_softc *)pipe->device->bus;
+ int iswrite = !(xfer->rqflags & URQ_REQUEST);
+ int s;
+
+ s = splusb();
+ xfer->status = USBF_IN_PROGRESS;
+ if (iswrite)
+ pxaudc_write_ep0(sc, xfer);
+ else {
+ /* XXX boring message, this case is normally reached if
+ * XXX the xfer for a device request is being queued. */
+ DPRINTF(0,("%s: ep0 ctrl-out, xfer=%p, len=%u, "
+ "actlen=%u\n", DEVNAME(sc), xfer, xfer->length,
+ xfer->actlen));
+ }
+ splx(s);
+ return USBF_IN_PROGRESS;
+}
+
+/* (also used by bulk pipes) */
+void
+pxaudc_ctrl_abort(usbf_xfer_handle xfer)
+{
+ struct usbf_pipe *pipe = xfer->pipe;
+ struct pxaudc_softc *sc = (struct pxaudc_softc *)pipe->device->bus;
+ int s;
+#ifdef PXAUDC_DEBUG
+ int index = usbf_endpoint_index(pipe->endpoint);
+ int dir = usbf_endpoint_dir(pipe->endpoint);
+ int type = usbf_endpoint_type(pipe->endpoint);
+#endif
+
+ DPRINTF(0,("%s: ep%d %s-%s abort, xfer=%p\n", DEVNAME(sc), index,
+ type == UE_CONTROL ? "ctrl" : "bulk", dir == UE_DIR_IN ?
+ "in" : "out", xfer));
+
+ /*
+ * Step 1: Make soft interrupt routine and hardware ignore the xfer.
+ */
+ s = splusb();
+ xfer->status = USBF_CANCELLED;
+ usb_uncallout(xfer->timeout_handle, pxaudc_timeout, NULL);
+ splx(s);
+
+ /*
+ * Step 2: Make sure hardware has finished any possible use of the
+ * xfer and the soft interrupt routine has run.
+ */
+ s = splusb();
+ /* XXX this does not seem right, what if there
+ * XXX are two xfers in the FIFO and we only want to
+ * XXX ignore one? */
+#ifdef notyet
+ pxaudc_flush(sc, usbf_endpoint_address(pipe->endpoint));
+#endif
+ /* XXX we're not doing DMA and the soft interrupt routine does not
+ XXX need to clean up anything. */
+ splx(s);
+
+ /*
+ * Step 3: Execute callback.
+ */
+ s = splusb();
+ usbf_transfer_complete(xfer);
+ splx(s);
+}
+
+void
+pxaudc_ctrl_done(usbf_xfer_handle xfer)
+{
+}
+
+void
+pxaudc_ctrl_close(usbf_pipe_handle pipe)
+{
+ /* XXX */
+}
+
+/*
+ * Bulk pipe methods
+ */
+
+usbf_status
+pxaudc_bulk_transfer(usbf_xfer_handle xfer)
+{
+ usbf_status err;
+
+ /* Insert last in queue. */
+ err = usbf_insert_transfer(xfer);
+ if (err)
+ return err;
+
+ /*
+ * Pipe isn't running (otherwise err would be USBF_IN_PROGRESS),
+ * so start first.
+ */
+ return pxaudc_bulk_start(SIMPLEQ_FIRST(&xfer->pipe->queue));
+}
+
+usbf_status
+pxaudc_bulk_start(usbf_xfer_handle xfer)
+{
+ struct usbf_pipe *pipe = xfer->pipe;
+ struct pxaudc_softc *sc = (struct pxaudc_softc *)pipe->device->bus;
+ int iswrite = usbf_endpoint_dir(pipe->endpoint) == UE_DIR_IN;
+ int s;
+
+ DPRINTF(1,("%s: ep%d bulk-%s start, xfer=%p, len=%u\n", DEVNAME(sc),
+ usbf_endpoint_index(pipe->endpoint), iswrite ? "in" : "out",
+ xfer, xfer->length));
+
+ s = splusb();
+ xfer->status = USBF_IN_PROGRESS;
+ if (iswrite)
+ pxaudc_write(sc, xfer);
+ splx(s);
+ return USBF_IN_PROGRESS;
+}
+
+void
+pxaudc_bulk_abort(usbf_xfer_handle xfer)
+{
+ pxaudc_ctrl_abort(xfer);
+}
+
+void
+pxaudc_bulk_done(usbf_xfer_handle xfer)
+{
+}
+
+void
+pxaudc_bulk_close(usbf_pipe_handle pipe)
+{
+ /* XXX */
}
diff --git a/sys/arch/arm/xscale/pxa27x_udcreg.h b/sys/arch/arm/xscale/pxa27x_udcreg.h
index f54a0e42296..b9e2e4ad76b 100644
--- a/sys/arch/arm/xscale/pxa27x_udcreg.h
+++ b/sys/arch/arm/xscale/pxa27x_udcreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pxa27x_udcreg.h,v 1.1 2005/02/17 22:10:35 dlg Exp $ */
+/* $OpenBSD: pxa27x_udcreg.h,v 1.2 2006/11/25 18:10:29 uwe Exp $ */
/*
* Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
@@ -149,4 +149,23 @@
#define USBDC_UDCECR_IN (7<<22) /* Interface Number */
#define USBDC_UDCECR_CN (3<<25) /* Configuration Number */
+#define USBDC_UDCCR_BITS \
+ "\20\001UDE\002UDA\003UDR\004EMCE\005SMAC\021DWRE" \
+ "\035BHNP\036AHNP\037OEN"
+#define USBDC_UDCISR0_BITS \
+ "\20\0010P\0020F\003AP\004AF\005BP\006BF\007CP\010CF" \
+ "\011DP\012DF\013EP\014EF\015FP\016FF\017GP\020GF" \
+ "\031HP\032HF\033IP\034IF\035JP\036JF\037KP\030KF" \
+ "\041LP\042LF\043MP\044MF\045NP\046NF\047PP\040PF"
+#define USBDC_UDCISR1_BITS \
+ "\20\001QP\002QF\003RP\004RF\005SP\006SF\007TP\010TF" \
+ "\011UP\012UF\013VP\014VF\015WP\016WF\017XP\020XF" \
+ "\034RS\035SU\036RU\037SOF\040CC"
+#define USBDC_UDCOTGISR_BITS \
+ "\20\001IRIDF\002IRIDR\003IRSDF\004IRSDR\005IRSVF\006IRSVR" \
+ "\007IRVV44F\010IRVV44R\011IRVV40F\012IRVV40R"
+#define USBDC_UDCCSR0_BITS \
+ "\20\001OPC\002IPR\003FTF\004DME\005SST\006FST\007RNE" \
+ "\010SA\011AREN\012ACM"
+
#endif /* _ARM_XSCALE_PXA27X_UDCREG_H_ */