summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhathach <[email protected]>2024-10-29 16:06:44 +0700
committerhathach <[email protected]>2024-10-29 16:06:44 +0700
commit1e164412bf791cb682c386f9d1e8e3b806faf72a (patch)
tree707adffaccd559694c99b600de5b76e33609a48b /src
parentcef9bab4b54ec038636738cf0969800ac7dd19fe (diff)
split handle channel slave out/in
Diffstat (limited to 'src')
-rw-r--r--src/portable/synopsys/dwc2/dwc2_type.h6
-rw-r--r--src/portable/synopsys/dwc2/hcd_dwc2.c154
2 files changed, 95 insertions, 65 deletions
diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h
index 7296475cf..d2ab1e94d 100644
--- a/src/portable/synopsys/dwc2/dwc2_type.h
+++ b/src/portable/synopsys/dwc2/dwc2_type.h
@@ -1846,9 +1846,9 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
#define HCINT_XFER_COMPLETE_Pos (0U)
#define HCINT_XFER_COMPLETE_Msk (0x1UL << HCINT_XFER_COMPLETE_Pos) // 0x00000001
#define HCINT_XFER_COMPLETE HCINT_XFER_COMPLETE_Msk // Transfer completed
-#define HCINT_CHANNEL_HALTED_Pos (1U)
-#define HCINT_CHANNEL_HALTED_Msk (0x1UL << HCINT_CHANNEL_HALTED_Pos) // 0x00000002
-#define HCINT_CHANNEL_HALTED HCINT_CHANNEL_HALTED_Msk // Channel halted
+#define HCINT_HALTED_Pos (1U)
+#define HCINT_HALTED_Msk (0x1UL << HCINT_HALTED_Pos) // 0x00000002
+#define HCINT_HALTED HCINT_HALTED_Msk // Channel halted
#define HCINT_AHB_ERR_Pos (2U)
#define HCINT_AHB_ERR_Msk (0x1UL << HCINT_AHB_ERR_Pos) // 0x00000004
#define HCINT_AHB_ERR HCINT_AHB_ERR_Msk // AHB error
diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c
index ce5d34cb7..568ce0c1f 100644
--- a/src/portable/synopsys/dwc2/hcd_dwc2.c
+++ b/src/portable/synopsys/dwc2/hcd_dwc2.c
@@ -55,7 +55,7 @@ enum {
enum {
HCD_XFER_STATE_UNALLOCATED = 0,
HCD_XFER_STATE_ACTIVE = 1,
- HCD_XFER_STATE_DISABLING = 2,
+ HCD_XFER_STATE_DONE = 2,
};
//--------------------------------------------------------------------
@@ -138,8 +138,16 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t channel_alloc(dwc2_regs_t* dwc2) {
}
TU_ATTR_ALWAYS_INLINE static inline void channel_dealloc(dwc2_regs_t* dwc2, uint8_t ch_id) {
- (void) dwc2;
_hcd_data.xfer[ch_id].state = HCD_XFER_STATE_UNALLOCATED;
+ dwc2->haintmsk &= ~TU_BIT(ch_id);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void channel_disable(dwc2_channel_t* channel) {
+ channel->hcintmsk |= HCINT_HALTED;
+
+ uint32_t hcchar = channel->hcchar & ~HCCHAR_CHENA; // skip w1s enabled bit
+ hcchar |= HCCHAR_CHDIS;
+ channel->hcchar = hcchar;
}
// Find currently enabled channel. Note: EP0 is bidirectional
@@ -661,10 +669,79 @@ TU_ATTR_ALWAYS_INLINE static inline void handle_hprt_irq(uint8_t rhport, bool in
dwc2->hprt = hprt; // clear interrupt
}
-// DMA related error: HCINT_BUFFER_NA | HCINT_DESC_ROLLOVER
-// if (hcint & (HCINT_BUFFER_NA | HCINT_DESC_ROLLOVER)) {
-// result = XFER_RESULT_FAILED;
-// }
+xfer_result_t handle_channel_slave_in(dwc2_regs_t* dwc2, uint8_t ch_id, bool is_period, uint32_t hcint) {
+ hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
+ dwc2_channel_t* channel = &dwc2->channel[ch_id];
+ xfer_result_t result = XFER_RESULT_INVALID;
+
+ if (hcint & HCINT_XFER_COMPLETE) {
+ result = XFER_RESULT_SUCCESS;
+ channel_disable(channel);
+ channel->hcintmsk &= ~HCINT_ACK;
+ } else if (hcint & (HCINT_XACT_ERR | HCINT_BABBLE_ERR | HCINT_STALL)) {
+ channel_disable(channel);
+ if (hcint & HCINT_XACT_ERR) {
+ xfer->err_count++;
+ channel->hcintmsk |= HCINT_ACK;
+ }
+ } else if (hcint & HCINT_HALTED) {
+ channel->hcintmsk &= ~HCINT_HALTED;
+ if (channel->hcchar_bm.err_multi_count == HCD_XFER_ERROR_MAX) {
+ channel_dealloc(dwc2, ch_id);
+ } else {
+ // Re-initialize Channel
+ }
+ } else if (hcint & HCINT_ACK) {
+ xfer->err_count = 0;
+ channel->hcintmsk &= ~HCINT_ACK;
+ } else if (hcint & HCINT_DATATOGGLE_ERR) {
+ xfer->err_count = 0;
+ } else if (hcint & HCINT_NAK) {
+ // NAK received, re-enable channel if request queue is available
+ TU_ASSERT(request_queue_avail(dwc2, is_period), XFER_RESULT_INVALID);
+ channel->hcchar |= HCCHAR_CHENA;
+ }
+
+ return result;
+}
+
+xfer_result_t handle_channel_slave_out(dwc2_regs_t* dwc2, uint8_t ch_id, bool is_period, uint32_t hcint) {
+ (void) is_period;
+ hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
+ dwc2_channel_t* channel = &dwc2->channel[ch_id];
+ xfer_result_t result = XFER_RESULT_INVALID;
+
+ if (hcint & HCINT_XFER_COMPLETE) {
+ result = XFER_RESULT_SUCCESS;
+ channel->hcintmsk &= ~HCINT_ACK;
+ channel_dealloc(dwc2, ch_id);
+ } else if (hcint & HCINT_STALL) {
+ xfer->state = HCD_XFER_STATE_DONE;
+ channel_disable(channel);
+ } else if (hcint & (HCINT_NAK | HCINT_XACT_ERR | HCINT_NYET)) {
+ channel_disable(channel);
+ if (hcint & HCINT_XACT_ERR) {
+ xfer->err_count++;
+ channel->hcintmsk |= HCINT_ACK;
+ } else {
+ xfer->err_count = 0;
+ }
+ } else if (hcint & HCINT_HALTED) {
+ channel->hcintmsk &= ~HCINT_HALTED;
+ if (xfer->state == HCD_XFER_STATE_DONE || channel->hcchar_bm.err_multi_count == HCD_XFER_ERROR_MAX) {
+ result = (xfer->state == HCD_XFER_STATE_DONE ? XFER_RESULT_STALLED : XFER_RESULT_FAILED);
+ channel_dealloc(dwc2, ch_id);
+ } else {
+ // Re-initialize Channel (Do ping protocol for HS)
+ }
+ } else if (hcint & HCINT_ACK) {
+ xfer->err_count = 0;
+ channel->hcintmsk &= ~HCINT_ACK;
+ }
+
+ return result;
+}
+
void handle_channel_irq(uint8_t rhport, bool in_isr) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
const bool is_dma = dma_host_enabled(dwc2);
@@ -674,75 +751,28 @@ void handle_channel_irq(uint8_t rhport, bool in_isr) {
if (tu_bit_test(dwc2->haint, ch_id)) {
dwc2_channel_t* channel = &dwc2->channel[ch_id];
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
+ dwc2_channel_char_t hcchar_bm = channel->hcchar_bm;
+ const bool is_period = edpt_is_periodic(hcchar_bm.ep_type);
uint32_t hcint = channel->hcint;
hcint &= channel->hcintmsk;
- dwc2_channel_char_t hcchar_bm = channel->hcchar_bm;
- xfer_result_t result = XFER_RESULT_INVALID; // invalid means not DONE
-
if (is_dma) {
} else {
- if (hcint & HCINT_XFER_COMPLETE) {
- result = XFER_RESULT_SUCCESS;
- channel->hcintmsk &= ~HCINT_ACK;
- channel_dealloc(dwc2, ch_id);
- } else if (hcint & HCINT_STALL) {
- result = XFER_RESULT_STALLED;
- channel->hcintmsk |= HCINT_CHANNEL_HALTED;
- channel->hcchar_bm.disable = 1;
- } else if (hcint & (HCINT_NAK | HCINT_XACT_ERR | HCINT_NYET)) {
- if (hcchar_bm.ep_dir == TUSB_DIR_OUT) {
- // rewind buffer
- } else {
- if (hcint & HCINT_NAK) {
- // NAK received, re-enable channel if request queue is available
- TU_ASSERT(request_queue_avail(dwc2, edpt_is_periodic(hcchar_bm.ep_type)), );
- channel->hcchar |= HCCHAR_CHENA;
- }
- }
-
- // unmask halted
- // disable channel
- if (hcint & HCINT_XACT_ERR) {
- xfer->err_count++;
- channel->hcintmsk |= HCINT_ACK;
- }else {
- xfer->err_count = 0;
- }
- } else if (hcint & HCINT_CHANNEL_HALTED) {
- if (channel->hcchar_bm.err_multi_count == HCD_XFER_ERROR_MAX) {
+ xfer_result_t result;
- } else {
- // Re-initialize Channel (Do ping protocol for HS)
- }
- } else if (hcint & HCINT_ACK) {
- // ACK received, reset error count
- xfer->err_count = 0;
- channel->hcintmsk &= ~HCINT_ACK;
+ if (hcchar_bm.ep_dir == TUSB_DIR_OUT) {
+ result = handle_channel_slave_out(dwc2, ch_id, is_period, hcint);
+ } else {
+ result = handle_channel_slave_in(dwc2, ch_id, is_period, hcint);
}
- // const uint32_t xact_err = hcint & (HCINT_AHB_ERR | HCINT_XACT_ERR | HCINT_BABBLE_ERR |
- // HCINT_DATATOGGLE_ERR | HCINT_XCS_XACT_ERR);
- // if (xact_err) {
- // result = XFER_RESULT_FAILED;
- // }
- // if (!xact_err && (hcint & HCINT_CHANNEL_HALTED)) {
- // // Channel halted without error, this is a response to channel disable
- // result = XFER_RESULT_INVALID;
- // }
-
-
// Transfer is complete (success, stalled, failed) or channel is disabled
- if (result != XFER_RESULT_INVALID || (hcint & HCINT_CHANNEL_HALTED)) {
- dwc2->haintmsk &= ~TU_BIT(ch_id); // de-allocate channel
-
+ if (result != XFER_RESULT_INVALID ) {
// notify usbh if transfer is complete (skip if channel is disabled)
const uint8_t ep_addr = tu_edpt_addr(hcchar_bm.ep_num, hcchar_bm.ep_dir);
- if (result != XFER_RESULT_INVALID) {
- hcd_event_xfer_complete(hcchar_bm.dev_addr, ep_addr, 0, result, in_isr);
- }
+ hcd_event_xfer_complete(hcchar_bm.dev_addr, ep_addr, xfer->total_bytes, result, in_isr);
}
}