From 402a5fee90b9c45f960ff67356a60cc475f6b04a Mon Sep 17 00:00:00 2001
From: hathach <thach@tinyusb.org>
Date: Thu, 29 Nov 2018 12:56:02 +0700
Subject: [PATCH] dcd lpc17xx enable EpIntEn for non-control IN after DMA
 complete

all transfer work well
---
 src/portable/nxp/lpc17xx/dcd_lpc175x_6x.c | 149 ++++++++++++++--------
 1 file changed, 94 insertions(+), 55 deletions(-)

diff --git a/src/portable/nxp/lpc17xx/dcd_lpc175x_6x.c b/src/portable/nxp/lpc17xx/dcd_lpc175x_6x.c
index c0275abb2..31d2bb822 100644
--- a/src/portable/nxp/lpc17xx/dcd_lpc175x_6x.c
+++ b/src/portable/nxp/lpc17xx/dcd_lpc175x_6x.c
@@ -60,6 +60,7 @@ typedef struct ATTR_ALIGNED(4)
   uint16_t                 : 1; ///< reserved
   uint16_t isochronous     : 1; // is an iso endpoint
   uint16_t max_packet_size : 11;
+
   volatile uint16_t buflen; // bytes for non-iso, number of packets for iso endpoint
 
   //------------- Word 2 -------------//
@@ -73,6 +74,7 @@ typedef struct ATTR_ALIGNED(4)
   volatile uint16_t atle_msb_extracted     : 1;	// used in ATLE mode
   volatile uint16_t atle_mess_len_position : 6; // used in ATLE mode
   uint16_t                                 : 2;
+
   volatile uint16_t present_count;  // For non-iso : The number of bytes transferred by the DMA engine
                                     // For iso : number of packets
 
@@ -151,7 +153,7 @@ static void set_ep_size(uint8_t ep_id, uint16_t max_packet_size)
   LPC_USB->USBEpInd    = ep_id; // select index before setting packet size
   LPC_USB->USBMaxPSize = max_packet_size;
 
-  while ((LPC_USB->USBDevIntSt & DEV_INT_ENDPOINT_REALIZED_MASK) == 0) {} // TODO can be omitted
+  while ((LPC_USB->USBDevIntSt & DEV_INT_ENDPOINT_REALIZED_MASK) == 0) {}
   LPC_USB->USBDevIntClr = DEV_INT_ENDPOINT_REALIZED_MASK;
 }
 
@@ -162,10 +164,10 @@ static void set_ep_size(uint8_t ep_id, uint16_t max_packet_size)
 static void bus_reset(void)
 {
   // step 7 : slave mode set up
-  LPC_USB->USBEpIntClr     = 0xFFFFFFFF;          // clear all pending interrupt
-  LPC_USB->USBDevIntClr    = 0xFFFFFFFF;          // clear all pending interrupt
-  LPC_USB->USBEpIntEn      = (uint32_t) BIN8(11); // control endpoint cannot use DMA, non-control all use DMA
-  LPC_USB->USBEpIntPri     = 0;                   // same priority for all endpoint
+  LPC_USB->USBEpIntClr     = 0xFFFFFFFF; // clear all pending interrupt
+  LPC_USB->USBDevIntClr    = 0xFFFFFFFF; // clear all pending interrupt
+  LPC_USB->USBEpIntEn      = 0x03UL;     // control endpoint cannot use DMA, non-control all use DMA
+  LPC_USB->USBEpIntPri     = 0;          // same priority for all endpoint
 
   // step 8 : DMA set up
   LPC_USB->USBEpDMADis     = 0xFFFFFFFF; // firstly disable all dma
@@ -190,7 +192,7 @@ bool dcd_init(uint8_t rhport)
 
   LPC_USB->USBDevIntEn = (DEV_INT_DEVICE_STATUS_MASK | DEV_INT_ENDPOINT_SLOW_MASK | DEV_INT_ERROR_MASK);
   LPC_USB->USBUDCAH = (uint32_t) _dcd.udca;
-  LPC_USB->USBDMAIntEn = (DMA_INT_END_OF_XFER_MASK | DMA_INT_ERROR_MASK);
+  LPC_USB->USBDMAIntEn = (DMA_INT_END_OF_XFER_MASK /*| DMA_INT_NEW_DD_REQUEST_MASK*/ | DMA_INT_ERROR_MASK);
 
   sie_write(SIE_CMDCODE_DEVICE_STATUS, 1, 1);    // connect
 
@@ -308,6 +310,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
 
   dd->isochronous = (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) ? 1 : 0;
   dd->max_packet_size = p_endpoint_desc->wMaxPacketSize.size;
+  dd->retired = 1; // invalid at first
 
   sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS + ep_id, 1, 0);    // clear all endpoint status
 
@@ -392,8 +395,8 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t t
     uint8_t ep_id = ep_addr2idx(ep_addr);
     dma_desc_t* dd = &_dcd.dd[ep_id];
 
-    // Isochronous & max packet size must be preserved
-    // Other fields of dd should be clear
+    // Prepare DMA descriptor
+    // Isochronous & max packet size must be preserved, Other fields of dd should be clear
     uint16_t const ep_size = dd->max_packet_size;
     uint8_t  is_iso = dd->isochronous;
 
@@ -405,13 +408,18 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t t
 
     _dcd.udca[ep_id] = dd;
 
-    // Enable DMA
-    LPC_USB->USBEpDMAEn = BIT_(ep_id);
-
     if ( ep_id % 2 )
     {
+      // Clear EP interrupt before Enable DMA
+      LPC_USB->USBEpIntEn &= ~BIT_(ep_id);
+      LPC_USB->USBEpDMAEn = BIT_(ep_id);
+
       // endpoint IN need to actively raise DMA request
       LPC_USB->USBDMARSet = BIT_(ep_id);
+    }else
+    {
+      // Enable DMA
+      LPC_USB->USBEpDMAEn = BIT_(ep_id);
     }
 
     return true;
@@ -421,26 +429,36 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t t
 //--------------------------------------------------------------------+
 // ISR
 //--------------------------------------------------------------------+
+static void dd_complete_isr(uint8_t rhport, uint8_t ep_id)
+{
+  dma_desc_t* const dd = &_dcd.dd[ep_id];
+  uint8_t result = (dd->status == DD_STATUS_NORMAL || dd->status == DD_STATUS_DATA_UNDERUN) ? XFER_RESULT_SUCCESS : XFER_RESULT_FAILED;
+  uint8_t const ep_addr = (ep_id / 2) | ((ep_id & 0x01) ? TUSB_DIR_IN_MASK : 0);
+
+  dcd_event_xfer_complete(rhport, ep_addr, dd->present_count, result, true);
+}
+
 static void normal_xfer_isr (uint8_t rhport, uint32_t eot_int)
 {
   for ( uint8_t ep_id = 2; ep_id < DCD_ENDPOINT_MAX; ep_id++ )
   {
     if ( BIT_TEST_(eot_int, ep_id) )
     {
-      dma_desc_t* const dd = &_dcd.dd[ep_id];
-      uint8_t result = (dd->status == DD_STATUS_NORMAL || dd->status == DD_STATUS_DATA_UNDERUN) ? XFER_RESULT_SUCCESS : XFER_RESULT_FAILED;
-      uint8_t const ep_addr = (ep_id / 2) | ((ep_id & 0x01) ? TUSB_DIR_IN_MASK : 0);
-
-      dcd_event_xfer_complete(rhport, ep_addr, dd->present_count, result, true);
+      if ( ep_id & 0x01 )
+      {
+        // IN
+        LPC_USB->USBEpIntEn |= BIT_(ep_id);
+      }else
+      {
+        // OUT
+        dd_complete_isr(rhport, ep_id);
+      }
     }
   }
 }
 
-static void control_xfer_isr(uint8_t rhport)
+static void control_xfer_isr(uint8_t rhport, uint32_t ep_int_status)
 {
-  uint32_t const ep_int_status = LPC_USB->USBEpIntSt & LPC_USB->USBEpIntEn;
-//  LPC_USB->USBEpIntClr = ep_int_status; // acknowledge interrupt TODO cannot immediately acknowledge setup packet
-
   // Control out complete
   if ( ep_int_status & BIT_(0) )
   {
@@ -470,13 +488,40 @@ static void control_xfer_isr(uint8_t rhport)
     }
   }
 
-    // Control In complete
+  // Control In complete
   if ( ep_int_status & BIT_(1) )
   {
     dcd_event_xfer_complete(rhport, TUSB_DIR_IN_MASK, _dcd.control.in_bytes, XFER_RESULT_SUCCESS, true);
   }
+}
 
-  LPC_USB->USBEpIntClr = ep_int_status; // acknowledge interrupt TODO cannot immediately acknowledge setup packet
+static void bus_event_isr(uint8_t rhport)
+{
+  uint8_t const dev_status = sie_read(SIE_CMDCODE_DEVICE_STATUS, 1);
+  if (dev_status & SIE_DEV_STATUS_RESET_MASK)
+  {
+    bus_reset();
+    dcd_event_bus_signal(rhport, DCD_EVENT_BUS_RESET, true);
+  }
+
+  if (dev_status & SIE_DEV_STATUS_CONNECT_CHANGE_MASK)
+  {
+    // device is disconnected, require using VBUS (P1_30)
+    dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
+  }
+
+  if (dev_status & SIE_DEV_STATUS_SUSPEND_CHANGE_MASK)
+  {
+    if (dev_status & SIE_DEV_STATUS_SUSPEND_MASK)
+    {
+      dcd_event_bus_signal(rhport, DCD_EVENT_SUSPENDED, true);
+    }
+    //        else
+    //      { // resume signal
+    //        dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+    //      }
+    //    }
+  }
 }
 
 void hal_dcd_isr(uint8_t rhport)
@@ -487,55 +532,49 @@ void hal_dcd_isr(uint8_t rhport)
   // Bus event
   if (dev_int_status & DEV_INT_DEVICE_STATUS_MASK)
   {
-    uint8_t const dev_status = sie_read(SIE_CMDCODE_DEVICE_STATUS, 1);
-    if (dev_status & SIE_DEV_STATUS_RESET_MASK)
-    {
-      bus_reset();
-      dcd_event_bus_signal(rhport, DCD_EVENT_BUS_RESET, true);
-    }
-
-    if (dev_status & SIE_DEV_STATUS_CONNECT_CHANGE_MASK)
-    {
-      // device is disconnected, require using VBUS (P1_30)
-      dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
-    }
-
-    if (dev_status & SIE_DEV_STATUS_SUSPEND_CHANGE_MASK)
-    {
-      if (dev_status & SIE_DEV_STATUS_SUSPEND_MASK)
-      {
-        dcd_event_bus_signal(rhport, DCD_EVENT_SUSPENDED, true);
-      }
-//        else
-//      { // resume signal
-//        dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
-//      }
-//    }
-    }
+    bus_event_isr(rhport);
   }
 
-  // Control Endpoint
+  // Control Endpoint and Non-control IN transfer complete
   if (dev_int_status & DEV_INT_ENDPOINT_SLOW_MASK)
   {
-    control_xfer_isr(rhport);
+    uint32_t const ep_int_status = LPC_USB->USBEpIntSt & LPC_USB->USBEpIntEn;
+
+    control_xfer_isr(rhport, ep_int_status);
+
+    // Note clear USBEpIntClr will also clear the setup received bit --> clear after handle setup packet
+    LPC_USB->USBEpIntClr = ep_int_status;
+
+    for ( uint8_t ep_id = 3; ep_id < DCD_ENDPOINT_MAX; ep_id += 2 )
+    {
+      if ( BIT_TEST_(ep_int_status, ep_id) )
+      {
+        // Clear Ep interrupt for next DMA
+        LPC_USB->USBEpIntEn &= ~BIT_(ep_id);
+
+        dd_complete_isr(rhport, ep_id);
+      }
+    }
   }
 
-  // Non-Control Endpoint (DMA Mode)
+  // DMA transfer complete (RAM <-> EP) for Non-Control
+  // OUT: USB transfer is complete
+  // IN : UBS transfer is on-going -> enable EpIntEn to know when it is complete
   uint32_t const dma_int_status = LPC_USB->USBDMAIntSt & LPC_USB->USBDMAIntEn;
-
   if (dma_int_status & DMA_INT_END_OF_XFER_MASK)
   {
-    uint32_t const eot_int = LPC_USB->USBEoTIntSt;
-    LPC_USB->USBEoTIntClr = eot_int; // acknowledge interrupt source
+    uint32_t const eot = LPC_USB->USBEoTIntSt;
+    LPC_USB->USBEoTIntClr = eot; // acknowledge interrupt source
 
-    normal_xfer_isr(rhport, eot_int);
+    normal_xfer_isr(rhport, eot);
   }
 
+  // Errors
   if ( (dev_int_status & DEV_INT_ERROR_MASK) || (dma_int_status & DMA_INT_ERROR_MASK) )
   {
     uint32_t error_status = sie_read(SIE_CMDCODE_READ_ERROR_STATUS, 1);
     (void) error_status;
-//    TU_ASSERT(false, (void) 0);
+    TU_BREAKPOINT();
   }
 }