Просмотр исходного кода

dcd_stm32h7: Merge relevant changes from dcd_stm32f4. USB2 -> USB works as alias.

William D. Jones 6 лет назад
Родитель
Сommit
3efc81b285
1 измененных файлов с 84 добавлено и 73 удалено
  1. 84 73
      src/portable/st/stm32h7/dcd_stm32h7.c

+ 84 - 73
src/portable/st/stm32h7/dcd_stm32h7.c

@@ -1,7 +1,8 @@
 /*
  * The MIT License (MIT)
  *
- * Copyright (c) 2019 William D. Jones for Adafruit Industries
+ * Copyright (c) 2018 Scott Shawcroft, 2019 William D. Jones for Adafruit Industries
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -34,10 +35,15 @@
 /*------------------------------------------------------------------*/
 /* MACRO TYPEDEF CONSTANT ENUM
  *------------------------------------------------------------------*/
-#define DEVICE_BASE (USB_OTG_DeviceTypeDef *) (USB2_OTG_FS_PERIPH_BASE + USB_OTG_DEVICE_BASE)
-#define OUT_EP_BASE (USB_OTG_OUTEndpointTypeDef *) (USB2_OTG_FS_PERIPH_BASE + USB_OTG_OUT_ENDPOINT_BASE)
-#define IN_EP_BASE (USB_OTG_INEndpointTypeDef *) (USB2_OTG_FS_PERIPH_BASE + USB_OTG_IN_ENDPOINT_BASE)
-#define FIFO_BASE(_x) (volatile uint32_t *) (USB2_OTG_FS_PERIPH_BASE + USB_OTG_FIFO_BASE + (_x) * USB_OTG_FIFO_SIZE)
+#define DEVICE_BASE (USB_OTG_DeviceTypeDef *) (USB_OTG_FS_PERIPH_BASE + USB_OTG_DEVICE_BASE)
+#define OUT_EP_BASE (USB_OTG_OUTEndpointTypeDef *) (USB_OTG_FS_PERIPH_BASE + USB_OTG_OUT_ENDPOINT_BASE)
+#define IN_EP_BASE (USB_OTG_INEndpointTypeDef *) (USB_OTG_FS_PERIPH_BASE + USB_OTG_IN_ENDPOINT_BASE)
+#define FIFO_BASE(_x) (volatile uint32_t *) (USB_OTG_FS_PERIPH_BASE + USB_OTG_FIFO_BASE + (_x) * USB_OTG_FIFO_SIZE)
+
+// TODO Merge with OTG_HS
+// Max endpoints for each direction
+#define EP_MAX        8
+#define EP_FIFO_SIZE  4096
 
 static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[6];
 static uint8_t _setup_offs; // We store up to 3 setup packets.
@@ -52,18 +58,16 @@ typedef struct {
 
 typedef volatile uint32_t * usb_fifo_t;
 
-xfer_ctl_t xfer_status[4][2];
+xfer_ctl_t xfer_status[EP_MAX][2];
 #define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir]
 
 
 // Setup the control endpoint 0.
-static void bus_reset(void)
-{
+static void bus_reset(void) {
   USB_OTG_DeviceTypeDef * dev = DEVICE_BASE;
   USB_OTG_OUTEndpointTypeDef * out_ep = OUT_EP_BASE;
 
-  for(int n = 0; n < 4; n++)
-  {
+  for(uint8_t n = 0; n < EP_MAX; n++) {
     out_ep[n].DOEPCTL |= USB_OTG_DOEPCTL_SNAK;
   }
 
@@ -71,45 +75,45 @@ static void bus_reset(void)
   dev->DOEPMSK |= USB_OTG_DOEPMSK_STUPM | USB_OTG_DOEPMSK_XFRCM;
   dev->DIEPMSK |= USB_OTG_DIEPMSK_TOM | USB_OTG_DIEPMSK_XFRCM;
 
-  // Peripheral FIFO architecture (Rev6 RM 56.11.1)
+  // "USB Data FIFOs" section in reference manual
+  // Peripheral FIFO architecture
   //
-  // --------------- 1024 ( 4096 bytes )
-  // | IN FIFO 7  |
+  // --------------- 320 or 1024 ( 1280 or 4096 bytes )
+  // | IN FIFO MAX |
   // ---------------
-  // |    ...     |
+  // |    ...      |
   // --------------- y + x + 16 + GRXFSIZ
-  // | IN FIFO 2  |
+  // | IN FIFO 2   |
   // --------------- x + 16 + GRXFSIZ
-  // | IN FIFO 1  |
+  // | IN FIFO 1   |
   // --------------- 16 + GRXFSIZ
-  // | IN FIFO 0  |
+  // | IN FIFO 0   |
   // --------------- GRXFSIZ
-  // | OUT FIFO   |
-  // | ( Shared ) |
+  // | OUT FIFO    |
+  // | ( Shared )  |
   // --------------- 0
   //
-  // FIFO sizes are set up by the following rules (each word 32-bits):
-  // All EP OUT shared a unique OUT FIFO which uses (based on page 2747 of Rev 6 of reference manual):
-  // * 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).
+  // According to "FIFO RAM allocation" section in RM, FIFO RAM are allocated as follows (each word 32-bits):
+  // - Each EP IN needs at least max packet size, 16 words is sufficient for EP0 IN
   //
-  // It is recommended to allocate 2 times the largest packet size, therefore
-  // Recommended value = 10 + 1 + 2 x (16+2) = 47 --> Let's make it 50
-  USB2_OTG_FS->GRXFSIZ = 50;
+  // - 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 --> Let's make it 52
+  USB_OTG_FS->GRXFSIZ = 52;
 
   // Control IN uses FIFO 0 with 64 bytes ( 16 32-bit word )
-  USB2_OTG_FS->DIEPTXF0_HNPTXFSIZ = (16 << USB_OTG_TX0FD_Pos) | (USB2_OTG_FS->GRXFSIZ & 0x0000ffffUL);
+  USB_OTG_FS->DIEPTXF0_HNPTXFSIZ = (16 << USB_OTG_TX0FD_Pos) | (USB_OTG_FS->GRXFSIZ & 0x0000ffffUL);
 
   out_ep[0].DOEPTSIZ |= (3 << USB_OTG_DOEPTSIZ_STUPCNT_Pos);
 
-  USB2_OTG_FS->GINTMSK |= USB_OTG_GINTMSK_OEPINT | USB_OTG_GINTMSK_IEPINT;
+  USB_OTG_FS->GINTMSK |= USB_OTG_GINTMSK_OEPINT | USB_OTG_GINTMSK_IEPINT;
 }
 
-static void end_of_reset(void)
-{
+static void end_of_reset(void) {
   USB_OTG_DeviceTypeDef * dev = DEVICE_BASE;
   USB_OTG_INEndpointTypeDef * in_ep = IN_EP_BASE;
   // On current silicon on the Full Speed core, speed is fixed to Full Speed.
@@ -139,22 +143,23 @@ void dcd_init (uint8_t rhport)
 {
   (void) rhport;
 
-  // Programming model begins on page 2634 of Rev 6 of reference manual.
-  USB2_OTG_FS->GAHBCFG |= USB_OTG_GAHBCFG_TXFELVL | USB_OTG_GAHBCFG_GINT;
+  // Programming model begins in the last section of the chapter on the USB
+  // peripheral in each Reference Manual.
+  USB_OTG_FS->GAHBCFG |= USB_OTG_GAHBCFG_TXFELVL | USB_OTG_GAHBCFG_GINT;
 
   // No HNP/SRP (no OTG support), program timeout later, turnaround
   // programmed for 32+ MHz.
-  USB2_OTG_FS->GUSBCFG |= (0x06 << USB_OTG_GUSBCFG_TRDT_Pos) | USB_OTG_GUSBCFG_PHYSEL;
+  USB_OTG_FS->GUSBCFG |= (0x06 << USB_OTG_GUSBCFG_TRDT_Pos) | USB_OTG_GUSBCFG_PHYSEL;
 
   // Clear all used interrupts
-  USB2_OTG_FS->GINTSTS |= USB_OTG_GINTSTS_OTGINT | USB_OTG_GINTSTS_MMIS | \
+  USB_OTG_FS->GINTSTS |= USB_OTG_GINTSTS_OTGINT | USB_OTG_GINTSTS_MMIS | \
     USB_OTG_GINTSTS_USBRST | USB_OTG_GINTSTS_ENUMDNE | \
     USB_OTG_GINTSTS_ESUSP | USB_OTG_GINTSTS_USBSUSP | USB_OTG_GINTSTS_SOF;
 
   // Required as part of core initialization. Disable OTGINT as we don't use
   // it right now. TODO: How should mode mismatch be handled? It will cause
   // the core to stop working/require reset.
-  USB2_OTG_FS->GINTMSK |= /* USB_OTG_GINTMSK_OTGINT | */ USB_OTG_GINTMSK_MMISM;
+  USB_OTG_FS->GINTMSK |= /* USB_OTG_GINTMSK_OTGINT | */ USB_OTG_GINTMSK_MMISM;
 
   USB_OTG_DeviceTypeDef * dev = DEVICE_BASE;
 
@@ -162,17 +167,18 @@ void dcd_init (uint8_t rhport)
   // (non zero-length packet), send STALL back and discard. Full speed.
   dev->DCFG |=  USB_OTG_DCFG_NZLSOHSK | (3 << USB_OTG_DCFG_DSPD_Pos);
 
-  USB2_OTG_FS->GINTMSK |= USB_OTG_GINTMSK_USBRST | USB_OTG_GINTMSK_ENUMDNEM | \
+  USB_OTG_FS->GINTMSK |= USB_OTG_GINTMSK_USBRST | USB_OTG_GINTMSK_ENUMDNEM | \
     USB_OTG_GINTMSK_SOFM | USB_OTG_GINTMSK_RXFLVLM /* SB_OTG_GINTMSK_ESUSPM | \
     USB_OTG_GINTMSK_USBSUSPM */;
 
-  // Enable pullup, enable peripheral.
+  // Enable VBUS hardware sensing, enable pullup, enable peripheral.
 #ifdef USB_OTG_GCCFG_VBDEN
-  USB2_OTG_FS->GCCFG |= USB_OTG_GCCFG_VBDEN | USB_OTG_GCCFG_PWRDWN;
+  USB_OTG_FS->GCCFG |= USB_OTG_GCCFG_VBDEN | USB_OTG_GCCFG_PWRDWN;
 #else
-  USB2_OTG_FS->GCCFG |= USB_OTG_GCCFG_VBUSBSEN | USB_OTG_GCCFG_PWRDWN;
+  USB_OTG_FS->GCCFG |= USB_OTG_GCCFG_VBUSBSEN | USB_OTG_GCCFG_PWRDWN;
 #endif
 
+  // Soft Connect -> Enable pullup on D+/D-.
   // This step does not appear to be specified in the programmer's model.
   dev->DCTL &= ~USB_OTG_DCTL_SDIS;
 }
@@ -227,7 +233,7 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
   uint8_t const dir   = tu_edpt_dir(desc_edpt->bEndpointAddress);
 
   // Unsupported endpoint numbers/size.
-  if((desc_edpt->wMaxPacketSize.size > 64) || (epnum > 7)) {
+  if((desc_edpt->wMaxPacketSize.size > 64) || (epnum > EP_MAX)) {
     return false;
   }
 
@@ -240,24 +246,27 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
       desc_edpt->wMaxPacketSize.size << USB_OTG_DOEPCTL_MPSIZ_Pos;
     dev->DAINTMSK |= (1 << (USB_OTG_DAINTMSK_OEPM_Pos + epnum));
   } else {
-    // Peripheral FIFO architecture (Rev6 RM 56.11.1)
+    // "USB Data FIFOs" section in reference manual
+    // Peripheral FIFO architecture
     //
-    // --------------- 1024 ( 4096 bytes )
-    // | IN FIFO 7  |
+    // --------------- 320 or 1024 ( 1280 or 4096 bytes )
+    // | IN FIFO MAX |
     // ---------------
-    // |    ...     |
+    // |    ...      |
     // --------------- y + x + 16 + GRXFSIZ
-    // | IN FIFO 2  |
+    // | IN FIFO 2   |
     // --------------- x + 16 + GRXFSIZ
-    // | IN FIFO 1  |
+    // | IN FIFO 1   |
     // --------------- 16 + GRXFSIZ
-    // | IN FIFO 0  |
+    // | IN FIFO 0   |
     // --------------- GRXFSIZ
-    // | OUT FIFO   |
-    // | ( Shared ) |
+    // | OUT FIFO    |
+    // | ( Shared )  |
     // --------------- 0
     //
-    // Since OUT FIFO = 50, FIFO 0 = 16, average of FIFOx = (1024-50-16) / 7 = 136 ~ 130
+    // 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_ep[epnum].DIEPCTL |= (1 << USB_OTG_DIEPCTL_USBAEP_Pos) | \
       (epnum - 1) << USB_OTG_DIEPCTL_TXFNUM_Pos | \
@@ -267,9 +276,10 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
     dev->DAINTMSK |= (1 << (USB_OTG_DAINTMSK_IEPM_Pos + epnum));
 
     // Both TXFD and TXSA are in unit of 32-bit words
-    uint16_t const fifo_size = 130;
-    uint32_t const fifo_offset = (USB2_OTG_FS->GRXFSIZ & 0x0000ffff) + 16 + fifo_size*(epnum-1);
-    USB2_OTG_FS->DIEPTXF[epnum - 1] = (130 << USB_OTG_DIEPTXF_INEPTXFD_Pos) | fifo_offset;
+    uint16_t const allocated_size = (USB_OTG_FS->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);
+    USB_OTG_FS->DIEPTXF[epnum - 1] = (fifo_size << USB_OTG_DIEPTXF_INEPTXFD_Pos) | fifo_offset;
   }
 
   return true;
@@ -345,9 +355,9 @@ void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
     }
 
     // Flush the FIFO, and wait until we have confirmed it cleared.
-    USB2_OTG_FS->GRSTCTL |= ((epnum - 1) << USB_OTG_GRSTCTL_TXFNUM_Pos);
-    USB2_OTG_FS->GRSTCTL |= USB_OTG_GRSTCTL_TXFFLSH;
-    while((USB2_OTG_FS->GRSTCTL & USB_OTG_GRSTCTL_TXFFLSH_Msk) != 0);
+    USB_OTG_FS->GRSTCTL |= ((epnum - 1) << USB_OTG_GRSTCTL_TXFNUM_Pos);
+    USB_OTG_FS->GRSTCTL |= USB_OTG_GRSTCTL_TXFFLSH;
+    while((USB_OTG_FS->GRSTCTL & USB_OTG_GRSTCTL_TXFFLSH_Msk) != 0);
   } else {
     // Only disable currently enabled non-control endpoint
     if ( (epnum == 0) || !(out_ep[epnum].DOEPCTL & USB_OTG_DOEPCTL_EPENA) ){
@@ -358,7 +368,7 @@ void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
       // anyway, and it can't be cleared by user code. If this while loop never
       // finishes, we have bigger problems than just the stack.
       dev->DCTL |= USB_OTG_DCTL_SGONAK;
-      while((USB2_OTG_FS->GINTSTS & USB_OTG_GINTSTS_BOUTNAKEFF_Msk) == 0);
+      while((USB_OTG_FS->GINTSTS & USB_OTG_GINTSTS_BOUTNAKEFF_Msk) == 0);
 
       // Ditto here- disable the endpoint.
       out_ep[epnum].DOEPCTL |= (USB_OTG_DOEPCTL_STALL | USB_OTG_DOEPCTL_EPDIS);
@@ -512,7 +522,7 @@ static void read_rx_fifo(USB_OTG_OUTEndpointTypeDef * out_ep) {
 
   // Pop control word off FIFO (completed xfers will have 2 control words,
   // we only pop one ctl word each interrupt).
-  uint32_t ctl_word = USB2_OTG_FS->GRXSTSP;
+  uint32_t ctl_word = USB_OTG_FS->GRXSTSP;
   uint8_t pktsts = (ctl_word & USB_OTG_GRXSTSP_PKTSTS_Msk) >> USB_OTG_GRXSTSP_PKTSTS_Pos;
   uint8_t epnum = (ctl_word &  USB_OTG_GRXSTSP_EPNUM_Msk) >>  USB_OTG_GRXSTSP_EPNUM_Pos;
   uint16_t bcnt = (ctl_word & USB_OTG_GRXSTSP_BCNT_Msk) >> USB_OTG_GRXSTSP_BCNT_Pos;
@@ -551,7 +561,7 @@ static void read_rx_fifo(USB_OTG_OUTEndpointTypeDef * out_ep) {
 static void handle_epout_ints(USB_OTG_DeviceTypeDef * dev, USB_OTG_OUTEndpointTypeDef * out_ep) {
   // DAINT for a given EP clears when DOEPINTx is cleared.
   // OEPINT will be cleared when DAINT's out bits are cleared.
-  for(int n = 0; n < 8; n++) {
+  for(uint8_t n = 0; n < EP_MAX; n++) {
     xfer_ctl_t * xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT);
 
     if(dev->DAINT & (1 << (USB_OTG_DAINT_OEPINT_Pos + n))) {
@@ -589,7 +599,7 @@ 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) {
   // DAINT for a given EP clears when DIEPINTx is cleared.
   // IEPINT will be cleared when DAINT's out bits are cleared.
-  for(uint8_t n = 0; n < 8; n++) {
+  for(uint8_t n = 0; n < EP_MAX; n++) {
     xfer_ctl_t * xfer = XFER_CTL_BASE(n, TUSB_DIR_IN);
 
     if(dev->DAINT & (1 << (USB_OTG_DAINT_IEPINT_Pos + n))) {
@@ -609,29 +619,30 @@ static void handle_epin_ints(USB_OTG_DeviceTypeDef * dev, USB_OTG_INEndpointType
   }
 }
 
-void OTG_FS_IRQHandler (void)
-{
+void OTG_FS_IRQHandler(void) {
   USB_OTG_DeviceTypeDef * dev = DEVICE_BASE;
   USB_OTG_OUTEndpointTypeDef * out_ep = OUT_EP_BASE;
   USB_OTG_INEndpointTypeDef * in_ep = IN_EP_BASE;
 
-  uint32_t int_status = USB2_OTG_FS->GINTSTS;
+  uint32_t int_status = USB_OTG_FS->GINTSTS;
 
-  if(int_status & USB_OTG_GINTMSK_USBRST)
-  {
-    USB2_OTG_FS->GINTSTS = USB_OTG_GINTSTS_USBRST;
+  if(int_status & USB_OTG_GINTSTS_USBRST) {
+    // USBRST is start of reset.
+    USB_OTG_FS->GINTSTS = USB_OTG_GINTSTS_USBRST;
     bus_reset();
   }
 
-  if(int_status & USB_OTG_GINTMSK_ENUMDNEM)
-  {
-    USB2_OTG_FS->GINTSTS = USB_OTG_GINTMSK_ENUMDNEM;
+  if(int_status & USB_OTG_GINTSTS_ENUMDNE) {
+    // ENUMDNE detects speed of the link. For full-speed, we
+    // always expect the same value. This interrupt is considered
+    // the end of reset.
+    USB_OTG_FS->GINTSTS = USB_OTG_GINTSTS_ENUMDNE;
     end_of_reset();
     dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true);
   }
 
   if(int_status & USB_OTG_GINTSTS_SOF) {
-    USB2_OTG_FS->GINTSTS = USB_OTG_GINTSTS_SOF;
+    USB_OTG_FS->GINTSTS = USB_OTG_GINTSTS_SOF;
     dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
   }