diff --git a/src/portable/st/synopsys/dcd_synopsys.c b/src/portable/st/synopsys/dcd_synopsys.c index 24cfadfe..030c089a 100644 --- a/src/portable/st/synopsys/dcd_synopsys.c +++ b/src/portable/st/synopsys/dcd_synopsys.c @@ -116,7 +116,6 @@ enum DCD_FULL_SPEED = 3, // Full speed with internal PHY }; - /*------------------------------------------------------------------*/ /* MACRO TYPEDEF CONSTANT ENUM *------------------------------------------------------------------*/ @@ -138,6 +137,8 @@ typedef volatile uint32_t * usb_fifo_t; xfer_ctl_t xfer_status[EP_MAX][2]; #define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir] +// FIFO RAM allocation so far in words +static uint16_t _allocated_fifo_words; // Setup the control endpoint 0. static void bus_reset(uint8_t rhport) @@ -147,6 +148,8 @@ static void bus_reset(uint8_t rhport) USB_OTG_OUTEndpointTypeDef * out_ep = OUT_EP_BASE(rhport); USB_OTG_INEndpointTypeDef * in_ep = IN_EP_BASE(rhport); + tu_memclr(xfer_status, sizeof(xfer_status)); + for(uint8_t n = 0; n < EP_MAX; n++) { out_ep[n].DOEPCTL |= USB_OTG_DOEPCTL_SNAK; } @@ -177,17 +180,36 @@ static void bus_reset(uint8_t rhport) // - Each EP IN needs at least max packet size, 16 words is sufficient for EP0 IN // // - All EP OUT shared a unique OUT FIFO which uses - // * 10 locations in hardware for setup packets + setup control words (up to 3 setup packets). - // * 2 locations for OUT endpoint control words. - // * 16 for largest packet size of 64 bytes. ( TODO Highspeed is 512 bytes) - // * 1 location for global NAK (not required/used here). - // * It is recommended to allocate 2 times the largest packet size, therefore - // Recommended value = 10 + 1 + 2 x (16+2) = 47. To make it scale better with large FIFO size - // and work better with Highspeed. We use 1/5 of total FIFO size - usb_otg->GRXFSIZ = (EP_FIFO_SIZE/4)/5; + // - 13 for setup packets + control words (up to 3 setup packets). + // - 1 for global NAK (not required/used here). + // - Largest-EPsize / 4 + 1. ( FS: 64 bytes, HS: 512 bytes). Recommended is "2 x (Largest-EPsize/4) + 1" + // - 2 for each used OUT endpoint + // + // Therefore GRXFSIZ = 13 + 1 + 1 + 2 x (Largest-EPsize/4) + 2 x EPOUTnum + // - FullSpeed (64 Bytes ): GRXFSIZ = 15 + 2 x 16 + 2 x EP_MAX = 47 + 2 x EP_MAX + // - Highspeed (512 bytes): GRXFSIZ = 15 + 2 x 128 + 2 x EP_MAX = 271 + 2 x EP_MAX + // + // NOTE: Largest-EPsize & EPOUTnum is actual used endpoints in configuration. Since DCD has no knowledge + // of the overall picture yet. We will use the worst scenario: largest possible + EP_MAX + // + // FIXME: for Isochronous, largest EP size can be 1023/1024 for FS/HS respectively. In addition if multiple ISO + // are enabled at least "2 x (Largest-EPsize/4) + 1" are recommended. Maybe provide a macro for application to + // overwrite this. + +#if TUD_OPT_HIGH_SPEED + _allocated_fifo_words = 271 + 2*EP_MAX; +#else + _allocated_fifo_words = 47 + 2*EP_MAX; +#endif + + usb_otg->GRXFSIZ = _allocated_fifo_words; // Control IN uses FIFO 0 with 64 bytes ( 16 32-bit word ) - usb_otg->DIEPTXF0_HNPTXFSIZ = (16 << USB_OTG_TX0FD_Pos) | (usb_otg->GRXFSIZ & 0x0000ffffUL); + usb_otg->DIEPTXF0_HNPTXFSIZ = (16 << USB_OTG_TX0FD_Pos) | _allocated_fifo_words; + + _allocated_fifo_words += 16; + + // TU_LOG2_INT(_allocated_fifo_words); // Fixed control EP0 size to 64 bytes in_ep[0].DIEPCTL &= ~(0x03 << USB_OTG_DIEPCTL_MPSIZ_Pos); @@ -221,7 +243,6 @@ static tusb_speed_t get_speed(USB_OTG_DeviceTypeDef* dev) return (enum_spd == DCD_HIGH_SPEED) ? TUSB_SPEED_HIGH : TUSB_SPEED_FULL; } - /*------------------------------------------------------------------*/ /* Controller API *------------------------------------------------------------------*/ @@ -242,9 +263,11 @@ void dcd_init (uint8_t rhport) usb_otg->GCCFG &= ~USB_OTG_GCCFG_PWRDWN; // On selected MCUs HS port1 can be used with external PHY via ULPI interface - // Select ULPI highspeed PHY with default external VBUS Indicator and Drive - usb_otg->GUSBCFG &= ~(USB_OTG_GUSBCFG_TSDPS | USB_OTG_GUSBCFG_ULPIFSLS | USB_OTG_GUSBCFG_PHYSEL | - USB_OTG_GUSBCFG_ULPIEVBUSD | USB_OTG_GUSBCFG_ULPIEVBUSI); + // Init ULPI Interface + usb_otg->GUSBCFG &= ~(USB_OTG_GUSBCFG_TSDPS | USB_OTG_GUSBCFG_ULPIFSLS | USB_OTG_GUSBCFG_PHYSEL); + + // Select default internal VBUS Indicator and Drive for ULPI + usb_otg->GUSBCFG &= ~(USB_OTG_GUSBCFG_ULPIEVBUSD | USB_OTG_GUSBCFG_ULPIEVBUSI); set_turnaround(usb_otg, TUSB_SPEED_HIGH); } @@ -303,7 +326,6 @@ void dcd_init (uint8_t rhport) USB_OTG_GINTMSK_USBSUSPM | USB_OTG_GINTMSK_WUIM | USB_OTG_GINTMSK_RXFLVLM | (USE_SOF ? USB_OTG_GINTMSK_SOFM : 0); - // Enable global interrupt usb_otg->GAHBCFG |= USB_OTG_GAHBCFG_GINT; } @@ -397,10 +419,40 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) // | ( Shared ) | // --------------- 0 // - // Since OUT FIFO = GRXFSIZ, FIFO 0 = 16, for simplicity, we equally allocated for the rest of endpoints - // - Size : (FIFO_SIZE/4 - GRXFSIZ - 16) / (EP_MAX-1) - // - Offset: GRXFSIZ + 16 + Size*(epnum-1) + // In FIFO is allocated by following rules: // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n". + // - Offset: allocated so far + // - Size + // - Interrupt is EPSize + // - Bulk/ISO is max(EPSize, remaining-fifo / non-opened-EPIN) + + uint16_t const fifo_remaining = EP_FIFO_SIZE/4 - _allocated_fifo_words; + uint16_t fifo_size = desc_edpt->wMaxPacketSize.size / 4; + + if ( desc_edpt->bmAttributes.xfer != TUSB_XFER_INTERRUPT ) + { + uint8_t opened = 0; + for(uint8_t i = 0; i < EP_MAX; i++) + { + if ( (i != epnum) && (xfer_status[i][TUSB_DIR_IN].max_size > 0) ) opened++; + } + + // EP Size or equally divided of remaining whichever is larger + fifo_size = tu_max16(fifo_size, fifo_remaining / (EP_MAX - opened)); + } + + + // FIFO overflows, we probably need a better allocating scheme + TU_ASSERT(fifo_size <= fifo_remaining); + + // DIEPTXF starts at FIFO #1. + // Both TXFD and TXSA are in unit of 32-bit words. + usb_otg->DIEPTXF[epnum - 1] = (fifo_size << USB_OTG_DIEPTXF_INEPTXFD_Pos) | _allocated_fifo_words; + + _allocated_fifo_words += fifo_size; + + //TU_LOG2_INT(fifo_size); + //TU_LOG2_INT(_allocated_fifo_words); in_ep[epnum].DIEPCTL |= (1 << USB_OTG_DIEPCTL_USBAEP_Pos) | (epnum << USB_OTG_DIEPCTL_TXFNUM_Pos) | @@ -409,15 +461,6 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) (desc_edpt->wMaxPacketSize.size << USB_OTG_DIEPCTL_MPSIZ_Pos); dev->DAINTMSK |= (1 << (USB_OTG_DAINTMSK_IEPM_Pos + epnum)); - - // Both TXFD and TXSA are in unit of 32-bit words. - // IN FIFO 0 was configured during enumeration, hence the "+ 16". - uint16_t const allocated_size = (usb_otg->GRXFSIZ & 0x0000ffff) + 16; - uint16_t const fifo_size = (EP_FIFO_SIZE/4 - allocated_size) / (EP_MAX-1); - uint32_t const fifo_offset = allocated_size + fifo_size*(epnum-1); - - // DIEPTXF starts at FIFO #1. - usb_otg->DIEPTXF[epnum - 1] = (fifo_size << USB_OTG_DIEPTXF_INEPTXFD_Pos) | fifo_offset; } return true; @@ -433,8 +476,8 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t uint8_t const dir = tu_edpt_dir(ep_addr); xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); - xfer->buffer = buffer; - xfer->total_len = total_bytes; + xfer->buffer = buffer; + xfer->total_len = total_bytes; uint16_t num_packets = (total_bytes / xfer->max_size); uint8_t short_packet_size = total_bytes % xfer->max_size; @@ -533,20 +576,16 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) if(dir == TUSB_DIR_IN) { in_ep[epnum].DIEPCTL &= ~USB_OTG_DIEPCTL_STALL; - uint8_t eptype = (in_ep[epnum].DIEPCTL & USB_OTG_DIEPCTL_EPTYP_Msk) >> \ - USB_OTG_DIEPCTL_EPTYP_Pos; - // Required by USB spec to reset DATA toggle bit to DATA0 on interrupt - // and bulk endpoints. + uint8_t eptype = (in_ep[epnum].DIEPCTL & USB_OTG_DIEPCTL_EPTYP_Msk) >> USB_OTG_DIEPCTL_EPTYP_Pos; + // Required by USB spec to reset DATA toggle bit to DATA0 on interrupt and bulk endpoints. if(eptype == 2 || eptype == 3) { in_ep[epnum].DIEPCTL |= USB_OTG_DIEPCTL_SD0PID_SEVNFRM; } } else { out_ep[epnum].DOEPCTL &= ~USB_OTG_DOEPCTL_STALL; - uint8_t eptype = (out_ep[epnum].DOEPCTL & USB_OTG_DOEPCTL_EPTYP_Msk) >> \ - USB_OTG_DOEPCTL_EPTYP_Pos; - // Required by USB spec to reset DATA toggle bit to DATA0 on interrupt - // and bulk endpoints. + uint8_t eptype = (out_ep[epnum].DOEPCTL & USB_OTG_DOEPCTL_EPTYP_Msk) >> USB_OTG_DOEPCTL_EPTYP_Pos; + // Required by USB spec to reset DATA toggle bit to DATA0 on interrupt and bulk endpoints. if(eptype == 2 || eptype == 3) { out_ep[epnum].DOEPCTL |= USB_OTG_DOEPCTL_SD0PID_SEVNFRM; }