turn off TX FIFO Empty for EPIN if all bytes are written
fix dcd synopsys issue with usbnet #289
This commit is contained in:
		| @@ -291,9 +291,10 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) | |||||||
|  |  | ||||||
|   if(dir == TUSB_DIR_OUT) |   if(dir == TUSB_DIR_OUT) | ||||||
|   { |   { | ||||||
|     out_ep[epnum].DOEPCTL |= (1 << USB_OTG_DOEPCTL_USBAEP_Pos) | \ |     out_ep[epnum].DOEPCTL |= (1 << USB_OTG_DOEPCTL_USBAEP_Pos) | | ||||||
|       desc_edpt->bmAttributes.xfer << USB_OTG_DOEPCTL_EPTYP_Pos | \ |                              (desc_edpt->bmAttributes.xfer << USB_OTG_DOEPCTL_EPTYP_Pos) | | ||||||
|       desc_edpt->wMaxPacketSize.size << USB_OTG_DOEPCTL_MPSIZ_Pos; |                              (desc_edpt->wMaxPacketSize.size << USB_OTG_DOEPCTL_MPSIZ_Pos); | ||||||
|  |  | ||||||
|     dev->DAINTMSK |= (1 << (USB_OTG_DAINTMSK_OEPM_Pos + epnum)); |     dev->DAINTMSK |= (1 << (USB_OTG_DAINTMSK_OEPM_Pos + epnum)); | ||||||
|   } |   } | ||||||
|   else |   else | ||||||
| @@ -321,11 +322,12 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) | |||||||
|     // - Offset: GRXFSIZ + 16 + Size*(epnum-1) |     // - Offset: GRXFSIZ + 16 + Size*(epnum-1) | ||||||
|     // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n". |     // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n". | ||||||
|  |  | ||||||
|     in_ep[epnum].DIEPCTL |= (1 << USB_OTG_DIEPCTL_USBAEP_Pos) | \ |     in_ep[epnum].DIEPCTL |= (1 << USB_OTG_DIEPCTL_USBAEP_Pos) | | ||||||
|       epnum << USB_OTG_DIEPCTL_TXFNUM_Pos | \ |                             (epnum << USB_OTG_DIEPCTL_TXFNUM_Pos) | | ||||||
|       desc_edpt->bmAttributes.xfer << USB_OTG_DIEPCTL_EPTYP_Pos | \ |                             (desc_edpt->bmAttributes.xfer << USB_OTG_DIEPCTL_EPTYP_Pos) | | ||||||
|       (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? USB_OTG_DOEPCTL_SD0PID_SEVNFRM : 0) | \ |                             (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? USB_OTG_DOEPCTL_SD0PID_SEVNFRM : 0) | | ||||||
|       desc_edpt->wMaxPacketSize.size << USB_OTG_DIEPCTL_MPSIZ_Pos; |                             (desc_edpt->wMaxPacketSize.size << USB_OTG_DIEPCTL_MPSIZ_Pos); | ||||||
|  |  | ||||||
|     dev->DAINTMSK |= (1 << (USB_OTG_DAINTMSK_IEPM_Pos + epnum)); |     dev->DAINTMSK |= (1 << (USB_OTG_DAINTMSK_IEPM_Pos + epnum)); | ||||||
|  |  | ||||||
|     // Both TXFD and TXSA are in unit of 32-bit words. |     // Both TXFD and TXSA are in unit of 32-bit words. | ||||||
| @@ -365,21 +367,23 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t | |||||||
|     num_packets++; |     num_packets++; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // IN and OUT endpoint xfers are interrupt-driven, we just schedule them |   // IN and OUT endpoint xfers are interrupt-driven, we just schedule them here. | ||||||
|   // here. |  | ||||||
|   if(dir == TUSB_DIR_IN) { |   if(dir == TUSB_DIR_IN) { | ||||||
|     // A full IN transfer (multiple packets, possibly) triggers XFRC. |     // A full IN transfer (multiple packets, possibly) triggers XFRC. | ||||||
|     in_ep[epnum].DIEPTSIZ = (num_packets << USB_OTG_DIEPTSIZ_PKTCNT_Pos) | \ |     in_ep[epnum].DIEPTSIZ = (num_packets << USB_OTG_DIEPTSIZ_PKTCNT_Pos) | | ||||||
|                             ((total_bytes & USB_OTG_DIEPTSIZ_XFRSIZ_Msk) << USB_OTG_DIEPTSIZ_XFRSIZ_Pos); |                             ((total_bytes & USB_OTG_DIEPTSIZ_XFRSIZ_Msk) << USB_OTG_DIEPTSIZ_XFRSIZ_Pos); | ||||||
|  |  | ||||||
|     in_ep[epnum].DIEPCTL |= USB_OTG_DIEPCTL_EPENA | USB_OTG_DIEPCTL_CNAK; |     in_ep[epnum].DIEPCTL |= USB_OTG_DIEPCTL_EPENA | USB_OTG_DIEPCTL_CNAK; | ||||||
|  |  | ||||||
|     // Enable fifo empty interrupt only if there are something to put in the fifo. |     // Enable fifo empty interrupt only if there are something to put in the fifo. | ||||||
|     if(total_bytes != 0) { |     if(total_bytes != 0) { | ||||||
|       dev->DIEPEMPMSK |= (1 << epnum); |       dev->DIEPEMPMSK |= (1 << epnum); | ||||||
|     } |     } | ||||||
|   } else { |   } else { | ||||||
|     // Each complete packet for OUT xfers triggers XFRC. |     // Each complete packet for OUT xfers triggers XFRC. | ||||||
|     out_ep[epnum].DOEPTSIZ |= (1 << USB_OTG_DOEPTSIZ_PKTCNT_Pos) | \ |     out_ep[epnum].DOEPTSIZ |= (1 << USB_OTG_DOEPTSIZ_PKTCNT_Pos) | | ||||||
|                               ((xfer->max_size & USB_OTG_DOEPTSIZ_XFRSIZ_Msk) << USB_OTG_DOEPTSIZ_XFRSIZ_Pos); |                               ((xfer->max_size & USB_OTG_DOEPTSIZ_XFRSIZ_Msk) << USB_OTG_DOEPTSIZ_XFRSIZ_Pos); | ||||||
|  |  | ||||||
|     out_ep[epnum].DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK; |     out_ep[epnum].DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -535,6 +539,7 @@ static void receive_packet(xfer_ctl_t * xfer, /* USB_OTG_OUTEndpointTypeDef * ou | |||||||
|   xfer->short_packet = (xfer_size < xfer->max_size); |   xfer->short_packet = (xfer_size < xfer->max_size); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // Write a data packet to EPIN FIFO | ||||||
| static void transmit_packet(xfer_ctl_t * xfer, USB_OTG_INEndpointTypeDef * in_ep, uint8_t fifo_num) { | static void transmit_packet(xfer_ctl_t * xfer, USB_OTG_INEndpointTypeDef * in_ep, uint8_t fifo_num) { | ||||||
|   usb_fifo_t tx_fifo = FIFO_BASE(fifo_num); |   usb_fifo_t tx_fifo = FIFO_BASE(fifo_num); | ||||||
|  |  | ||||||
| @@ -658,21 +663,30 @@ static void handle_epout_ints(USB_OTG_DeviceTypeDef * dev, USB_OTG_OUTEndpointTy | |||||||
| static void handle_epin_ints(USB_OTG_DeviceTypeDef * dev, USB_OTG_INEndpointTypeDef * in_ep) { | static void handle_epin_ints(USB_OTG_DeviceTypeDef * dev, USB_OTG_INEndpointTypeDef * in_ep) { | ||||||
|   // DAINT for a given EP clears when DIEPINTx is cleared. |   // DAINT for a given EP clears when DIEPINTx is cleared. | ||||||
|   // IEPINT will be cleared when DAINT's out bits are cleared. |   // IEPINT will be cleared when DAINT's out bits are cleared. | ||||||
|   for(uint8_t n = 0; n < EP_MAX; n++) { |   for ( uint8_t n = 0; n < EP_MAX; n++ ) | ||||||
|  |   { | ||||||
|     xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_IN); |     xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_IN); | ||||||
|  |  | ||||||
|     if(dev->DAINT & (1 << (USB_OTG_DAINT_IEPINT_Pos + n))) { |     if ( dev->DAINT & (1 << (USB_OTG_DAINT_IEPINT_Pos + n)) ) | ||||||
|  |     { | ||||||
|       // IN XFER complete (entire xfer). |       // IN XFER complete (entire xfer). | ||||||
|       if(in_ep[n].DIEPINT & USB_OTG_DIEPINT_XFRC) { |       if ( in_ep[n].DIEPINT & USB_OTG_DIEPINT_XFRC ) | ||||||
|  |       { | ||||||
|         in_ep[n].DIEPINT = USB_OTG_DIEPINT_XFRC; |         in_ep[n].DIEPINT = USB_OTG_DIEPINT_XFRC; | ||||||
|         dev->DIEPEMPMSK &= ~(1 << n); // Turn off TXFE b/c xfer inactive. |  | ||||||
|         dcd_event_xfer_complete(0, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true); |         dcd_event_xfer_complete(0, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true); | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       // XFER FIFO empty |       // XFER FIFO empty | ||||||
|       if(in_ep[n].DIEPINT & USB_OTG_DIEPINT_TXFE) { |       if ( in_ep[n].DIEPINT & USB_OTG_DIEPINT_TXFE ) | ||||||
|  |       { | ||||||
|         in_ep[n].DIEPINT = USB_OTG_DIEPINT_TXFE; |         in_ep[n].DIEPINT = USB_OTG_DIEPINT_TXFE; | ||||||
|         transmit_packet(xfer, &in_ep[n], n); |         transmit_packet(xfer, &in_ep[n], n); | ||||||
|  |  | ||||||
|  |         // Turn off TXFE if all bytes are written. | ||||||
|  |         if (xfer->queued_len == xfer->total_len) | ||||||
|  |         { | ||||||
|  |           dev->DIEPEMPMSK &= ~(1 << n); | ||||||
|  |         } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 hathach
					hathach