Enhance EP FIFO allocation for both Fullspeed and Highspeed

- Update shared RX FIFO calculation with FS/HS
- IN FIFO EP
  - Interrupt -> use EPSize
  - Bulk/ISO  -> use  max(EPSize, remaining-fifo / non-opened-EPIN)
This commit is contained in:
hathach 2020-06-15 23:17:49 +07:00
parent e89fea8237
commit 2dd1be13e5
1 changed files with 76 additions and 37 deletions

View File

@ -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;
}