From c9c13497736d8be077663f4458948f7bd526841b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Sat, 28 Apr 2012 15:49:31 -0400 Subject: [PATCH] usb-s3c6400: merge the 2 drivers Player-specific code remaining: usb_drv_(init,exit) The iPods lack a MMU, so: - physical, virtual, and uncached addresses are identical - since we can't access uncached memory we discard caches when receiving data Still not quite reliable on nano2g Change-Id: Iebb79df64818b9ae3b68eccb8be8975ebd6c21ea --- firmware/export/config/ipod6g.h | 2 +- firmware/export/config/ipodnano2g.h | 2 +- firmware/target/arm/as3525/system-as3525.c | 4 +- firmware/target/arm/usb-s3c6400x.c | 575 +++++++-------------- 4 files changed, 185 insertions(+), 398 deletions(-) diff --git a/firmware/export/config/ipod6g.h b/firmware/export/config/ipod6g.h index 7e6faf8d6d..4cace1a2cf 100644 --- a/firmware/export/config/ipod6g.h +++ b/firmware/export/config/ipod6g.h @@ -239,7 +239,7 @@ #define CONFIG_USBOTG USBOTG_S3C6400X #define USB_VENDOR_ID 0x05AC #define USB_PRODUCT_ID 0x1261 -#define USB_NUM_ENDPOINTS 5 +#define USB_NUM_ENDPOINTS 6 #define USE_ROCKBOX_USB #define USB_DEVBSS_ATTR __attribute__((aligned(16))) diff --git a/firmware/export/config/ipodnano2g.h b/firmware/export/config/ipodnano2g.h index 9b34e6a204..9163915198 100644 --- a/firmware/export/config/ipodnano2g.h +++ b/firmware/export/config/ipodnano2g.h @@ -227,7 +227,7 @@ #define CONFIG_USBOTG USBOTG_S3C6400X #define USB_VENDOR_ID 0x05AC #define USB_PRODUCT_ID 0x1260 -#define USB_NUM_ENDPOINTS 5 +#define USB_NUM_ENDPOINTS 6 #define USE_ROCKBOX_USB #define USB_DEVBSS_ATTR __attribute__((aligned(16))) diff --git a/firmware/target/arm/as3525/system-as3525.c b/firmware/target/arm/as3525/system-as3525.c index f0ed75d2bd..65ad5f4d07 100644 --- a/firmware/target/arm/as3525/system-as3525.c +++ b/firmware/target/arm/as3525/system-as3525.c @@ -57,7 +57,7 @@ void fiq_handler(void) __attribute__((interrupt ("FIQ"))); default_interrupt(INT_WATCHDOG); default_interrupt(INT_TIMER1); default_interrupt(INT_TIMER2); -default_interrupt(INT_USB); +default_interrupt(INT_USB_FUNC); default_interrupt(INT_DMAC); default_interrupt(INT_NAND); default_interrupt(INT_IDE); @@ -134,7 +134,7 @@ static const struct { int source; void (*isr) (void); } vec_int_srcs[] = #if (defined HAVE_MULTIDRIVE && CONFIG_CPU == AS3525) { INT_SRC_MCI0, INT_MCI0 }, #endif - { INT_SRC_USB, INT_USB, }, + { INT_SRC_USB, INT_USB_FUNC, }, { INT_SRC_TIMER1, INT_TIMER1 }, { INT_SRC_TIMER2, INT_TIMER2 }, { INT_SRC_I2C_AUDIO, INT_I2C_AUDIO }, diff --git a/firmware/target/arm/usb-s3c6400x.c b/firmware/target/arm/usb-s3c6400x.c index 7bcfcedc89..48521aa622 100644 --- a/firmware/target/arm/usb-s3c6400x.c +++ b/firmware/target/arm/usb-s3c6400x.c @@ -39,6 +39,16 @@ //#define LOGF_ENABLE #include "logf.h" +#if CONFIG_CPU == AS3525v2 +#define UNCACHED_ADDR AS3525_UNCACHED_ADDR +#define PHYSICAL_ADDR AS3525_PHYSICAL_ADDR +static inline void discard_dma_buffer_cache(void) {} +#else +#define UNCACHED_ADDR +#define PHYSICAL_ADDR +static inline void discard_dma_buffer_cache(void) { commit_discard_dcache(); } +#endif + /* store per endpoint, per direction, information */ struct ep_type { @@ -50,6 +60,46 @@ struct ep_type bool busy; /* true is a transfer is pending */ }; +static const uint8_t in_ep_list[] = {0, 1, 3, 5}; +static const uint8_t out_ep_list[] = {0, 2, 4}; + +/* state of EP0 (to correctly schedule setup packet enqueing) */ +enum ep0state +{ + /* Setup packet is enqueud, waiting for actual data */ + EP0_WAIT_SETUP = 0, + /* Waiting for ack (either IN or OUT) */ + EP0_WAIT_ACK = 1, + /* Ack complete, waiting for data (either IN or OUT) + * This state is necessary because if both ack and data complete in the + * same interrupt, we might process data completion before ack completion + * so we need this bizarre state */ + EP0_WAIT_DATA = 2, + /* Setup packet complete, waiting for ack and data */ + EP0_WAIT_DATA_ACK = 3, +}; + +/* endpoints[ep_num][DIR_IN/DIR_OUT] */ +static struct ep_type endpoints[USB_NUM_ENDPOINTS][2]; +/* setup packet for EP0 */ + +/* USB control requests may be up to 64 bytes in size. + Even though we never use anything more than the 8 header bytes, + we are required to accept request packets of up to 64 bytes size. + Provide buffer space for these additional payload bytes so that + e.g. write descriptor requests (which are rejected by us, but the + payload is transferred anyway) do not cause memory corruption. + Fixes FS#12310. -- Michael Sparmann (theseven) */ +static union { + struct usb_ctrlrequest header; /* 8 bytes */ + unsigned char payload[64]; +} _ep0_setup_pkt USB_DEVBSS_ATTR; + +static struct usb_ctrlrequest *ep0_setup_pkt = UNCACHED_ADDR(&_ep0_setup_pkt.header); + +/* state of EP0 */ +static enum ep0state ep0_state; + bool usb_drv_stalled(int endpoint, bool in) { return DEPCTL(endpoint, !in) & DEPCTL_stall; @@ -72,7 +122,40 @@ void usb_drv_set_address(int address) into the USB core, which will then call this dummy function. */ } -static void ep_transfer(int ep, void *ptr, int length, bool out); +static void ep_transfer(int ep, void *ptr, int len, bool out) +{ + /* disable interrupts to avoid any race */ + int oldlevel = disable_irq_save(); + + struct ep_type *endpoint = &endpoints[ep][out ? DIR_OUT : DIR_IN]; + endpoint->busy = true; + endpoint->size = len; + endpoint->status = -1; + + if (out) + DEPCTL(ep, out) &= ~DEPCTL_stall; + + int mps = usb_drv_port_speed() ? 512 : 64; + int nb_packets = (len + mps - 1) / mps; + if (nb_packets == 0) + nb_packets = 1; + + DEPDMA(ep, out) = len ? (void*)PHYSICAL_ADDR(ptr) : NULL; + DEPTSIZ(ep, out) = (nb_packets << DEPTSIZ_pkcnt_bitp) | len; + if(out) + discard_dcache_range(ptr, len); + else + commit_dcache_range(ptr, len); + + logf("pkt=%d dma=%lx", nb_packets, DEPDMA(ep, out)); + +// if (!out) while (((GNPTXSTS & 0xffff) << 2) < MIN(mps, length)); + + DEPCTL(ep, out) |= DEPCTL_epena | DEPCTL_cnak; + + restore_irq(oldlevel); +} + int usb_drv_send_nonblocking(int endpoint, void *ptr, int length) { ep_transfer(EP_NUM(endpoint), ptr, length, false); @@ -109,55 +192,15 @@ void usb_drv_set_test_mode(int mode) DCTL = (DCTL & ~bitm(DCTL, tstctl)) | (mode << DCTL_tstctl_bitp); } -#if CONFIG_CPU == AS3525v2 /* FIXME FIXME FIXME */ -static const uint8_t in_ep_list[] = {0, 1, 3, 5}; -static const uint8_t out_ep_list[] = {0, 2, 4}; - -/* state of EP0 (to correctly schedule setup packet enqueing) */ -enum ep0state -{ - /* Setup packet is enqueud, waiting for actual data */ - EP0_WAIT_SETUP = 0, - /* Waiting for ack (either IN or OUT) */ - EP0_WAIT_ACK = 1, - /* Ack complete, waiting for data (either IN or OUT) - * This state is necessary because if both ack and data complete in the - * same interrupt, we might process data completion before ack completion - * so we need this bizarre state */ - EP0_WAIT_DATA = 2, - /* Setup packet complete, waiting for ack and data */ - EP0_WAIT_DATA_ACK = 3, -}; - -/* endpoints[ep_num][DIR_IN/DIR_OUT] */ -static struct ep_type endpoints[USB_NUM_ENDPOINTS][2]; -/* setup packet for EP0 */ - -/* USB control requests may be up to 64 bytes in size. - Even though we never use anything more than the 8 header bytes, - we are required to accept request packets of up to 64 bytes size. - Provide buffer space for these additional payload bytes so that - e.g. write descriptor requests (which are rejected by us, but the - payload is transferred anyway) do not cause memory corruption. - Fixes FS#12310. -- Michael Sparmann (theseven) */ -static union { - struct usb_ctrlrequest header; /* 8 bytes */ - unsigned char payload[64]; -} _ep0_setup_pkt USB_DEVBSS_ATTR; - -static struct usb_ctrlrequest *ep0_setup_pkt = AS3525_UNCACHED_ADDR(&_ep0_setup_pkt.header); - -/* state of EP0 */ -static enum ep0state ep0_state; - void usb_attach(void) { + usb_enable(true); // s5l only ? /* Nothing to do */ } static void prepare_setup_ep0(void) { - DEPDMA(0, true) = (void*)AS3525_PHYSICAL_ADDR(&_ep0_setup_pkt); + DEPDMA(0, true) = (void*)PHYSICAL_ADDR(&_ep0_setup_pkt); DEPTSIZ(0, true) = (1 << DEPTSIZ0_supcnt_bitp) | (1 << DEPTSIZ0_pkcnt_bitp) | 8; @@ -183,7 +226,7 @@ static void reset_endpoints(void) endpoint->active = false; endpoint->busy = false; endpoint->status = -1; - endpoint->done = false; + endpoint->done = true; semaphore_release(&endpoint->complete); if (i != 0) @@ -222,6 +265,7 @@ static void cancel_all_transfers(bool cancel_ep0) restore_irq(flags); } +#if CONFIG_CPU == AS3525v2 void usb_drv_init(void) { for (int i = 0; i < USB_NUM_ENDPOINTS; i++) @@ -311,10 +355,89 @@ void usb_drv_exit(void) CGU_USB = 0; bitclr32(&CGU_PERI, CGU_USB_CLOCK_ENABLE); } +#elif CONFIG_CPU == S5L8701 || CONFIG_CPU == S5L8702 +static void usb_reset(void) +{ + DCTL = DCTL_pwronprgdone | DCTL_sftdiscon; + + OPHYPWR = 0; /* PHY: Power up */ + udelay(10); + OPHYUNK1 = 1; + OPHYUNK2 = 0xE3F; + ORSTCON = 1; /* PHY: Assert Software Reset */ + udelay(10); + ORSTCON = 0; /* PHY: Deassert Software Reset */ + OPHYUNK3 = 0x600; + OPHYCLK = SYNOPSYSOTG_CLOCK; + udelay(400); + + GRSTCTL = GRSTCTL_csftrst; /* OTG: Assert Software Reset */ + while (GRSTCTL & GRSTCTL_csftrst); /* Wait for OTG to ack reset */ + while (!(GRSTCTL & GRSTCTL_ahbidle)); /* Wait for OTG AHB master idle */ + + GRXFSIZ = 1024; + GNPTXFSIZ = (256 << 16) | 1024; + + GAHBCFG = SYNOPSYSOTG_AHBCFG; + GUSBCFG = (1 << 12) | (1 << 10) | GUSBCFG_phy_if; /* OTG: 16bit PHY and some reserved bits */ + + DCFG = DCFG_nzstsouthshk; /* Address 0 */ + DCTL = DCTL_pwronprgdone; /* Soft Reconnect */ + DIEPMSK = DIEPINT_timeout | DEPINT_ahberr | DEPINT_xfercompl; + DOEPMSK = DOEPINT_setup | DEPINT_ahberr | DEPINT_xfercompl; + DAINTMSK = 0xFFFFFFFF; /* Enable interrupts on all endpoints */ + GINTMSK = GINTMSK_outepintr | GINTMSK_inepintr | GINTMSK_usbreset | GINTMSK_enumdone; + + reset_endpoints(); +} + +void usb_drv_init(void) +{ + for (unsigned i = 0; i < sizeof(endpoints)/(2*sizeof(struct ep_type)); i++) + for (unsigned dir = 0; dir < 2; dir++) + semaphore_init(&endpoints[i][dir].complete, 1, 0); + + /* Enable USB clock */ +#if CONFIG_CPU==S5L8701 + PWRCON &= ~0x4000; + PWRCONEXT &= ~0x800; + INTMSK |= INTMSK_USB_OTG; +#elif CONFIG_CPU==S5L8702 + PWRCON(0) &= ~0x4; + PWRCON(1) &= ~0x8; + VIC0INTENABLE |= 1 << 19; +#endif + PCGCCTL = 0; + + /* reset the beast */ + usb_reset(); +} + +void usb_drv_exit(void) +{ + DCTL = DCTL_pwronprgdone | DCTL_sftdiscon; + + OPHYPWR = 0xF; /* PHY: Power down */ + udelay(10); + ORSTCON = 7; /* Put the PHY into reset (needed to get current down) */ + udelay(10); + PCGCCTL = 1; /* Shut down PHY clock */ + +#if CONFIG_CPU==S5L8701 + PWRCON |= 0x4000; + PWRCONEXT |= 0x800; +#elif CONFIG_CPU==S5L8702 + PWRCON(0) |= 0x4; + PWRCON(1) |= 0x8; +#endif +} +#endif static void handle_ep_int(int ep, bool out) { unsigned long sts = DEPINT(ep, out); + struct ep_type *endpoint = &endpoints[ep][out ? DIR_OUT : DIR_IN]; + logf("%s(%d %s): sts = 0x%lx", __func__, ep, out?"OUT":"IN", sts); if(sts & DEPINT_ahberr) @@ -322,7 +445,7 @@ static void handle_ep_int(int ep, bool out) if(sts & DEPINT_xfercompl) { - struct ep_type *endpoint = &endpoints[ep][out ? DIR_OUT : DIR_IN]; + discard_dma_buffer_cache(); if(endpoint->busy) { endpoint->busy = false; @@ -357,11 +480,19 @@ static void handle_ep_int(int ep, bool out) } } - if(!out && (sts & DIEPINT_timeout)) - panicf("usb-drv: timeout on EP%d IN", ep); + if(!out && (sts & DIEPINT_timeout)) { + if (endpoint->busy) + { + endpoint->busy = false; + endpoint->status = 1; + endpoint->done = true; + semaphore_release(&endpoint->complete); + } + } if(out && (sts & DOEPINT_setup)) { + discard_dma_buffer_cache(); if(ep != 0) panicf("usb-drv: setup not on EP0, this is impossible"); if((DEPTSIZ(ep, true) & DEPTSIZ_xfersize_bits) != 0) @@ -390,7 +521,7 @@ static void handle_ep_int(int ep, bool out) DEPINT(ep, out) = sts; } -void INT_USB(void) +void INT_USB_FUNC(void) { /* some bits in GINTSTS can be set even though we didn't enable the interrupt source * so AND it with the actual mask */ @@ -461,6 +592,8 @@ int usb_drv_request_endpoint(int type, int dir) void usb_drv_release_endpoint(int ep) { + if ((ep & 0x7f) == 0) + return; endpoints[EP_NUM(ep)][EP_DIR(ep)].active = false; } @@ -469,39 +602,6 @@ void usb_drv_cancel_all_transfers() cancel_all_transfers(false); } -static void ep_transfer(int ep, void *ptr, int len, bool out) -{ - /* disable interrupts to avoid any race */ - int oldlevel = disable_irq_save(); - - struct ep_type *endpoint = &endpoints[ep][out ? DIR_OUT : DIR_IN]; - endpoint->busy = true; - endpoint->size = len; - endpoint->status = -1; - - if (out) - DEPCTL(ep, out) &= ~DEPCTL_stall; - - int mps = usb_drv_port_speed() ? 512 : 64; - int nb_packets = (len + mps - 1) / mps; - if (nb_packets == 0) - nb_packets = 1; - - DEPDMA(ep, out) = len ? (void*)AS3525_PHYSICAL_ADDR(ptr) : NULL; - DEPTSIZ(ep, out) = (nb_packets << DEPTSIZ_pkcnt_bitp) | len; - if(out) - discard_dcache_range(ptr, len); - else - commit_dcache_range(ptr, len); - - logf("pkt=%d dma=%lx", nb_packets, DEPDMA(ep, out)); - -// if (!out) while (((GNPTXSTS & 0xffff) << 2) < MIN(mps, length)); - - DEPCTL(ep, out) |= DEPCTL_epena | DEPCTL_cnak; - - restore_irq(oldlevel); -} int usb_drv_send(int ep, void *ptr, int len) { @@ -513,316 +613,3 @@ int usb_drv_send(int ep, void *ptr, int len) semaphore_wait(&endpoint->complete, TIMEOUT_BLOCK); return endpoint->status; } -#else - -static struct ep_type endpoints[USB_NUM_ENDPOINTS][2]; - -/* USB control requests may be up to 64 bytes in size. - Even though we never use anything more than the 8 header bytes, - we are required to accept request packets of up to 64 bytes size. - Provide buffer space for these additional payload bytes so that - e.g. write descriptor requests (which are rejected by us, but the - payload is transferred anyway) do not cause memory corruption. - Fixes FS#12310. -- Michael Sparmann (theseven) */ -static union -{ - struct usb_ctrlrequest header; /* 8 bytes */ - unsigned char payload[64]; -} ctrlreq USB_DEVBSS_ATTR; - -static volatile bool inflight = false; -static volatile bool plugged = false; - -static void reset_endpoints(int reinit) -{ - for (unsigned i = 0; i < sizeof(endpoints)/(2*sizeof(struct ep_type)); i++) - for (unsigned dir = 0; dir < 2; dir++) - { - if (reinit) endpoints[i][dir].active = false; - endpoints[i][dir].busy = false; - endpoints[i][dir].status = -1; - endpoints[i][dir].done = true; - semaphore_release(&endpoints[i][dir].complete); - } - - DEPCTL(0, false) = DEPCTL_usbactep | (1 << DEPCTL_nextep_bitp); - DEPCTL(0, true) = DEPCTL_usbactep; - DEPTSIZ(0, true) = (1 << DEPTSIZ_pkcnt_bitp) | (1 << DEPTSIZ0_supcnt_bitp) | 64; - - DEPDMA(0, true) = &ctrlreq; - DEPCTL(0, true) |= DEPCTL_epena | DEPCTL_cnak; - /* HACK: Enable all endpoints here, because we have no other chance to do it */ - if (reinit) - { - /* The size is getting set to zero, because we don't know - whether we are Full Speed or High Speed at this stage */ - DEPCTL(1, false) = DEPCTL_usbactep | DEPCTL_setd0pid | (3 << DEPCTL_nextep_bitp); - DEPCTL(2, true) = DEPCTL_usbactep | DEPCTL_setd0pid; - DEPCTL(3, false) = DEPCTL_usbactep | DEPCTL_setd0pid | (0 << DEPCTL_nextep_bitp); - DEPCTL(4, true) = DEPCTL_usbactep | DEPCTL_setd0pid; - } - else - { - DEPCTL(1, false) = DEPCTL(1, false) | DEPCTL_usbactep | DEPCTL_setd0pid; - DEPCTL(2, true) = DEPCTL(2, true) | DEPCTL_usbactep | DEPCTL_setd0pid; - DEPCTL(3, false) = DEPCTL(3, false) | DEPCTL_usbactep | DEPCTL_setd0pid; - DEPCTL(4, true) = DEPCTL(4, true) | DEPCTL_usbactep | DEPCTL_setd0pid; - } - DAINTMSK = 0xFFFFFFFF; /* Enable interrupts on all EPs */ - inflight = false; -} - -int usb_drv_request_endpoint(int type, int dir) -{ - bool out = dir == USB_DIR_OUT; - for(size_t ep = out ? 2 : 1; ep < USB_NUM_ENDPOINTS; ep += 2) { - if (!endpoints[ep][out ? DIR_OUT : DIR_IN].active) - { - endpoints[ep][out ? DIR_OUT : DIR_IN].active = true; - DEPCTL(ep, out) = (DEPCTL(ep, out) & ~(DEPCTL_eptype_bits << DEPCTL_eptype_bitp)) | - (type << DEPCTL_eptype_bitp); - return ep | dir; - } - } - - return -1; -} - -void usb_drv_release_endpoint(int ep) -{ - bool out = !(ep & USB_DIR_IN); - ep = ep & 0x7f; - - if (ep < 1 || ep > USB_NUM_ENDPOINTS) - return; - - endpoints[ep][out ? DIR_OUT : DIR_IN].active = false; -} - -static void usb_reset(void) -{ - DCTL = DCTL_pwronprgdone | DCTL_sftdiscon; - - OPHYPWR = 0; /* PHY: Power up */ - udelay(10); - OPHYUNK1 = 1; - OPHYUNK2 = 0xE3F; - ORSTCON = 1; /* PHY: Assert Software Reset */ - udelay(10); - ORSTCON = 0; /* PHY: Deassert Software Reset */ - OPHYUNK3 = 0x600; - OPHYCLK = SYNOPSYSOTG_CLOCK; - udelay(400); - - GRSTCTL = GRSTCTL_csftrst; /* OTG: Assert Software Reset */ - while (GRSTCTL & GRSTCTL_csftrst); /* Wait for OTG to ack reset */ - while (!(GRSTCTL & GRSTCTL_ahbidle)); /* Wait for OTG AHB master idle */ - - GRXFSIZ = 1024; - GNPTXFSIZ = (256 << 16) | 1024; - - GAHBCFG = SYNOPSYSOTG_AHBCFG; - GUSBCFG = (1 << 12) | (1 << 10) | GUSBCFG_phy_if; /* OTG: 16bit PHY and some reserved bits */ - - DCFG = DCFG_nzstsouthshk; /* Address 0 */ - DCTL = DCTL_pwronprgdone; /* Soft Reconnect */ - DIEPMSK = DIEPINT_timeout | DEPINT_ahberr | DEPINT_xfercompl; - DOEPMSK = DOEPINT_setup | DEPINT_ahberr | DEPINT_xfercompl; - DAINTMSK = 0xFFFFFFFF; /* Enable interrupts on all endpoints */ - GINTMSK = GINTMSK_outepintr | GINTMSK_inepintr | GINTMSK_usbreset | GINTMSK_enumdone; - - reset_endpoints(1); -} - -static void handle_ep_int(bool out) -{ - static const uint8_t eps[2][3] = { /* IN */ {0, 1, 3}, /* OUT */ {0, 2, 4}}; - for (int i = 0; i < 3; i++) - { - int ep = eps[!!out][i]; - uint32_t epints = DEPINT(ep, out); - if (!epints) - continue; - - if (epints & DEPINT_xfercompl) - { - if (!out) inflight = false; - commit_discard_dcache(); - int bytes = endpoints[ep][out ? DIR_OUT : DIR_IN].size - (DEPTSIZ(ep, out) & (DEPTSIZ_xfersize_bits < DEPTSIZ_xfersize_bitp)); - if (endpoints[ep][out ? DIR_OUT : DIR_IN].busy) - { - endpoints[ep][out ? DIR_OUT : DIR_IN].busy = false; - endpoints[ep][out ? DIR_OUT : DIR_IN].status = 0; - endpoints[ep][out ? DIR_OUT : DIR_IN].done = true; - usb_core_transfer_complete(ep, out ? USB_DIR_OUT : USB_DIR_IN, 0, bytes); - semaphore_release(&endpoints[ep][out ? DIR_OUT : DIR_IN].complete); - } - } - - if (epints & DEPINT_ahberr) - panicf("USB: AHB error on EP%d (dir %d)", ep, out); - - if (!out && (epints & DIEPINT_timeout)) - { - if (endpoints[ep][out ? DIR_OUT : DIR_IN].busy) - { - endpoints[ep][out ? DIR_OUT : DIR_IN].busy = false; - endpoints[ep][out ? DIR_OUT : DIR_IN].status = 1; - endpoints[ep][out ? DIR_OUT : DIR_IN].done = true; - semaphore_release(&endpoints[ep][out ? DIR_OUT : DIR_IN].complete); - } - } - - if (out && (epints & DOEPINT_setup)) - { - commit_discard_dcache(); - if (ep != 0) - panicf("USB: SETUP done on OUT EP%d!?", ep); - - /* Set the new address here, before passing the packet to the core. - See usb_drv_set_address() for details. */ - if (ctrlreq.header.bRequest == USB_REQ_SET_ADDRESS) - DCFG = (DCFG & ~(DCFG_devadr_bits << DCFG_devadr_bitp)) - | (ctrlreq.header.wValue << DCFG_devadr_bitp); - - usb_core_control_request(&ctrlreq.header); - } - - /* Make sure EP0 OUT is set up to accept the next request */ - if (out && ep == 0) - { - DEPTSIZ(0, true) = (1 << DEPTSIZ0_supcnt_bitp) | (1 << DEPTSIZ0_pkcnt_bitp) | 64; - DEPDMA(0, true) = &ctrlreq; - DEPCTL(0, true) |= DEPCTL_epena | DEPCTL_cnak; - } - DEPINT(ep, out) = epints; - } -} - -/* IRQ handler */ -void INT_USB_FUNC(void) -{ - uint32_t ints = GINTSTS; - if (ints & GINTMSK_usbreset) - { - DCFG = DCFG_nzstsouthshk; /* Address 0 */ - reset_endpoints(1); - usb_core_bus_reset(); - } - - if (ints & GINTMSK_enumdone) /* enumeration done, we now know the speed */ - { - /* Set up the maximum packet sizes accordingly */ - uint32_t maxpacket = (usb_drv_port_speed() ? 512 : 64) << DEPCTL_mps_bitp; - DEPCTL(1, false) = (DEPCTL(1, false) & ~(DEPCTL_mps_bits << DEPCTL_mps_bitp)) | maxpacket; - DEPCTL(2, true) = (DEPCTL(2, true) & ~(DEPCTL_mps_bits << DEPCTL_mps_bitp)) | maxpacket; - DEPCTL(3, false) = (DEPCTL(3, false) & ~(DEPCTL_mps_bits << DEPCTL_mps_bitp)) | maxpacket; - DEPCTL(4, true) = (DEPCTL(4, true) & ~(DEPCTL_mps_bits << DEPCTL_mps_bitp)) | maxpacket; - } - - if (ints & GINTMSK_inepintr) - handle_ep_int(false); - - if (ints & GINTMSK_outepintr) - handle_ep_int(true); - - GINTSTS = ints; -} - -static void ep_transfer(int ep, void *ptr, int len, bool out) -{ - while (!out && inflight && plugged); - if (!plugged) return; - - /* disable interrupts to avoid any race */ - int oldlevel = disable_irq_save(); - if (!out) inflight = true; - endpoints[ep][out ? DIR_OUT : DIR_IN].busy = true; - endpoints[ep][out ? DIR_OUT : DIR_IN].size = len; - - if (out) DEPCTL(ep, out) &= ~DEPCTL_stall; - - - int mps = usb_drv_port_speed() ? 512 : 64; - int nb_packets = (len + mps - 1) / mps; - if (nb_packets == 0) - nb_packets = 1; - - DEPDMA(ep, out) = len ? ptr : NULL; - DEPTSIZ(ep, out) = (nb_packets << DEPTSIZ_pkcnt_bitp) | len; - - if(out) discard_dcache_range(ptr, len); - else commit_dcache_range(ptr, len); - - logf("pkt=%d dma=%lx", nb_packets, DEPDMA(ep, out)); - - DEPCTL(ep, out) |= DEPCTL_epena | DEPCTL_cnak; - - restore_irq(oldlevel); -} - -int usb_drv_send(int endpoint, void *ptr, int length) -{ - endpoint = EP_NUM(endpoint); - endpoints[endpoint][1].done = false; - ep_transfer(endpoint, ptr, length, false); - while (!endpoints[endpoint][1].done && endpoints[endpoint][1].busy) - semaphore_wait(&endpoints[endpoint][1].complete, TIMEOUT_BLOCK); - return endpoints[endpoint][1].status; -} - -void usb_drv_cancel_all_transfers(void) -{ - int flags = disable_irq_save(); - reset_endpoints(0); - restore_irq(flags); -} - -void usb_drv_init(void) -{ - for (unsigned i = 0; i < sizeof(endpoints)/(2*sizeof(struct ep_type)); i++) - for (unsigned dir = 0; dir < 2; dir++) - semaphore_init(&endpoints[i][dir].complete, 1, 0); - - /* Enable USB clock */ -#if CONFIG_CPU==S5L8701 - PWRCON &= ~0x4000; - PWRCONEXT &= ~0x800; - INTMSK |= INTMSK_USB_OTG; -#elif CONFIG_CPU==S5L8702 - PWRCON(0) &= ~0x4; - PWRCON(1) &= ~0x8; - VIC0INTENABLE |= 1 << 19; -#endif - PCGCCTL = 0; - - /* reset the beast */ - plugged = true; - usb_reset(); -} - -void usb_drv_exit(void) -{ - plugged = false; - DCTL = DCTL_pwronprgdone | DCTL_sftdiscon; - - OPHYPWR = 0xF; /* PHY: Power down */ - udelay(10); - ORSTCON = 7; /* Put the PHY into reset (needed to get current down) */ - udelay(10); - PCGCCTL = 1; /* Shut down PHY clock */ - -#if CONFIG_CPU==S5L8701 - PWRCON |= 0x4000; - PWRCONEXT |= 0x800; -#elif CONFIG_CPU==S5L8702 - PWRCON(0) |= 0x4; - PWRCON(1) |= 0x8; -#endif -} - -void usb_attach(void) -{ - usb_enable(true); -} -#endif // CONFIG_CPU == AS3525v2 /* FIXME FIXME FIXME */