@@ -62,6 +62,8 @@ enum dwc2_drv_event_type {
6262 */
6363#define UDC_DWC2_FIFO0_DEPTH (2 * 16U)
6464
65+ #define UDC_DWC2_TARGET_FRAME_INITIAL UINT16_MAX
66+
6567/* Get Data FIFO access register */
6668#define UDC_DWC2_EP_FIFO (base , idx ) ((mem_addr_t)base + 0x1000 * (idx + 1))
6769
@@ -138,6 +140,8 @@ struct udc_dwc2_data {
138140 /* Number of OUT endpoints including control endpoint */
139141 uint8_t outeps ;
140142 uint8_t setup [8 ];
143+ /* Target frame numbers for isochronous endpoints */
144+ uint16_t target_frames [32 ];
141145};
142146
143147#if defined(CONFIG_PINCTRL )
@@ -381,6 +385,21 @@ static bool dwc2_ep_is_periodic(struct udc_ep_config *const cfg)
381385 }
382386}
383387
388+ static void dwc2_ep_next_target_frame (const struct device * dev , struct udc_ep_config * const cfg ) {
389+ struct udc_dwc2_data * const priv = udc_get_private (dev );
390+ uint8_t ep_idx = USB_EP_GET_IDX (cfg -> addr );
391+ uint16_t limit = USB_DWC2_DSTS_SOFFN_LIMIT ;
392+
393+ if ((priv -> enumspd != USB_DWC2_DSTS_ENUMSPD_HS3060 ) {
394+ limit >>= 3 ;
395+ }
396+
397+ priv -> target_frames [ep_idx ] += cfg -> interval ;
398+ if (priv -> target_frames [ep_idx ] > limit ) {
399+ priv -> target_frames [ep_idx ] &= limit ;
400+ }
401+ }
402+
384403static bool dwc2_ep_is_iso (struct udc_ep_config * const cfg )
385404{
386405 return (cfg -> attributes & USB_EP_TRANSFER_TYPE_MASK ) == USB_EP_TYPE_ISO ;
@@ -566,13 +585,12 @@ static int dwc2_tx_fifo_write(const struct device *dev,
566585 }
567586
568587 if (is_iso ) {
569- /* Queue transfer on next SOF. TODO: allow stack to explicitly
570- * specify on which (micro-)frame the data should be sent.
571- */
572- if (priv -> sof_num & 1 ) {
573- diepctl |= USB_DWC2_DEPCTL_SETEVENFR ;
574- } else {
575- diepctl |= USB_DWC2_DEPCTL_SETODDFR ;
588+ if (cfg -> interval == 1 ) {
589+ if (priv -> target_frames [ep_idx ] & 1 ) {
590+ diepctl |= USB_DWC2_DEPCTL_SETODDFR ;
591+ } else {
592+ diepctl |= USB_DWC2_DEPCTL_SETEVENFR ;
593+ }
576594 }
577595 }
578596
@@ -706,10 +724,12 @@ static void dwc2_prep_rx(const struct device *dev, struct net_buf *buf,
706724 }
707725
708726 /* Set the Even/Odd (micro-)frame appropriately */
709- if (priv -> sof_num & 1 ) {
710- doepctl |= USB_DWC2_DEPCTL_SETEVENFR ;
711- } else {
712- doepctl |= USB_DWC2_DEPCTL_SETODDFR ;
727+ if (cfg -> interval == 1 ) {
728+ if (priv -> target_frames [ep_idx ] & 1 ) {
729+ diepctl |= USB_DWC2_DEPCTL_SETODDFR ;
730+ } else {
731+ diepctl |= USB_DWC2_DEPCTL_SETEVENFR ;
732+ }
713733 }
714734 } else {
715735 xfersize = net_buf_tailroom (buf );
@@ -1363,6 +1383,7 @@ static int dwc2_set_dedicated_fifo(const struct device *dev,
13631383static int dwc2_ep_control_enable (const struct device * dev ,
13641384 struct udc_ep_config * const cfg )
13651385{
1386+ struct udc_dwc2_data * const priv = udc_get_private (dev );
13661387 mem_addr_t dxepctl0_reg ;
13671388 uint32_t dxepctl0 ;
13681389
@@ -1395,6 +1416,11 @@ static int dwc2_ep_control_enable(const struct device *dev,
13951416 dwc2_flush_tx_fifo (dev , 0 );
13961417 }
13971418
1419+ if (dwc2_ep_is_iso (cfg )) {
1420+ const uint8_t ep_idx = USB_EP_GET_IDX (ep ) + (USB_EP_DIR_IS_IN (ep ) ? 0U : 16U );
1421+ priv -> target_frames [ep_idx ] = UDC_DWC2_TARGET_FRAME_INITIAL ;
1422+ }
1423+
13981424 sys_write32 (dxepctl0 , dxepctl0_reg );
13991425 dwc2_set_epint (dev , cfg , true);
14001426
@@ -2417,6 +2443,7 @@ static void dwc2_on_bus_reset(const struct device *dev)
24172443 uint32_t doepmsk ;
24182444
24192445 /* Set the NAK bit for all OUT endpoints */
2446+ sys_clear_bits ((mem_addr_t )& base -> diepmsk , USB_DWC2_DIEPINT_NAKINTRPT );
24202447 for (uint8_t i = 0U ; i < priv -> numdeveps ; i ++ ) {
24212448 uint32_t epdir = usb_dwc2_get_ghwcfg1_epdir (priv -> ghwcfg1 , i );
24222449 mem_addr_t doepctl_reg ;
@@ -2435,7 +2462,7 @@ static void dwc2_on_bus_reset(const struct device *dev)
24352462 }
24362463
24372464 sys_write32 (doepmsk , (mem_addr_t )& base -> doepmsk );
2438- sys_set_bits ((mem_addr_t )& base -> diepmsk , USB_DWC2_DIEPINT_XFERCOMPL );
2465+ sys_set_bits ((mem_addr_t )& base -> diepmsk , USB_DWC2_DIEPINT_XFERCOMPL | USB_DWC2_DIEPINT_NAKINTRPT );
24392466
24402467 /* Software has to handle RxFLvl interrupt only in Completer mode */
24412468 if (dwc2_in_completer_mode (dev )) {
@@ -2562,6 +2589,38 @@ static inline void dwc2_handle_in_xfercompl(const struct device *dev,
25622589 k_event_post (& priv -> drv_evt , BIT (DWC2_DRV_EVT_EP_FINISHED ));
25632590}
25642591
2592+ static inline void dwc2_handle_in_nakintrpt (const struct device * dev ,
2593+ const uint8_t ep_idx )
2594+ {
2595+ struct udc_dwc2_data * const priv = udc_get_private (dev );
2596+ /* TODO: use dwc2_get_dxepctl_reg() */
2597+ mem_addr_t diepctl_reg = (mem_addr_t )& base -> in_ep [ep_idx ].diepctl ;
2598+ struct udc_ep_config * ep_cfg = udc_get_ep_cfg (dev , ep_idx | USB_EP_DIR_IN );
2599+ uint32_t diepctl ;
2600+
2601+ if (!dwc2_ep_is_iso (ep_cfg )) {
2602+ return ;
2603+ }
2604+
2605+ if (priv -> target_frames [ep_idx ] == UDC_DWC2_TARGET_FRAME_INITIAL ) {
2606+ priv -> target_frames [ep_idx ] = priv -> sof_num ;
2607+ if (cfg -> interval > 1 ) {
2608+ diepctl = sys_read32 (diepctl_reg );
2609+ if (priv -> target_frames [ep_idx ] & 1 ) {
2610+ diepctl |= USB_DWC2_DEPCTL_SETODDFR ;
2611+ } else {
2612+ diepctl |= USB_DWC2_DEPCTL_SETEVENFR ;
2613+ }
2614+
2615+ sys_write32 (diepctl , diepctl_reg );
2616+ }
2617+ }
2618+
2619+ // TODO this holy fuck
2620+ diepctl = sys_read32 (diepctl_reg );
2621+ if (diepctl )
2622+ }
2623+
25652624static inline void dwc2_handle_iepint (const struct device * dev )
25662625{
25672626 struct usb_dwc2_reg * const base = dwc2_get_base (dev );
@@ -2590,6 +2649,9 @@ static inline void dwc2_handle_iepint(const struct device *dev)
25902649 dwc2_handle_in_xfercompl (dev , n );
25912650 }
25922651
2652+ if (status & USB_DWC2_DIEPINT_NAKINTRPT ) {
2653+ dwc2_handle_in_nakintrpt (dev , n );
2654+ }
25932655 }
25942656 }
25952657
0 commit comments