summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhathach <[email protected]>2024-10-29 21:54:21 +0700
committerhathach <[email protected]>2024-10-29 21:54:21 +0700
commit616b5770f279fee1aeec7c94258124762ad0aa65 (patch)
tree9d58f1bfa1fdccf8a681ab2f6e6fce95893276b3 /src
parent074811c2514161972c75337601b915f21828ba91 (diff)
fix pid token calculation, implement hcd_edpt_clear_stall(). msc explorer example read work, but write10 still wip
Diffstat (limited to 'src')
-rw-r--r--src/portable/synopsys/dwc2/dwc2_type.h11
-rw-r--r--src/portable/synopsys/dwc2/hcd_dwc2.c58
2 files changed, 47 insertions, 22 deletions
diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h
index d2ab1e94d..342a4cb2d 100644
--- a/src/portable/synopsys/dwc2/dwc2_type.h
+++ b/src/portable/synopsys/dwc2/dwc2_type.h
@@ -139,10 +139,13 @@ enum {
};
enum {
- HCTSIZ_PID_DATA0 = 0,
- HCTSIZ_PID_DATA2 = 1,
- HCTSIZ_PID_DATA1 = 2,
- HCTSIZ_PID_SETUP = 3,
+ HCTSIZ_PID_DATA0 = 0, // 00b
+ HCTSIZ_PID_DATA2 = 1, // 01b
+ HCTSIZ_PID_DATA1 = 2, // 10b
+ HCTSIZ_PID_SETUP = 3, // 11b
+};
+enum {
+ HCTSIZ_PID_MDATA = 3,
};
enum {
diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c
index 4456955db..d64a95393 100644
--- a/src/portable/synopsys/dwc2/hcd_dwc2.c
+++ b/src/portable/synopsys/dwc2/hcd_dwc2.c
@@ -67,13 +67,14 @@ typedef struct {
dwc2_channel_split_t hcsplt_bm;
};
- uint8_t next_data_toggle;
+ uint8_t next_pid;
// uint8_t resv[3];
} hcd_endpoint_t;
// Additional info for each channel when it is active
typedef struct {
volatile bool allocated;
+ uint8_t ep_id; // associated edpt
uint8_t result;
uint8_t err_count;
uint8_t* buffer;
@@ -125,7 +126,8 @@ 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) {
- _hcd_data.xfer[ch_id].allocated = false;
+ hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
+ xfer->allocated = false;
dwc2->haintmsk &= ~TU_BIT(ch_id);
}
@@ -195,6 +197,14 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t edpt_find_opened(uint8_t dev_addr, u
return TUSB_INDEX_INVALID_8;
}
+TU_ATTR_ALWAYS_INLINE static inline uint8_t cal_next_pid(uint8_t pid, uint8_t packet_count) {
+ if (packet_count & 0x01) {
+ return pid ^ 0x02; // toggle DATA0 and DATA1
+ } else {
+ return pid;
+ }
+}
+
//--------------------------------------------------------------------
//
//--------------------------------------------------------------------
@@ -322,7 +332,7 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
// force host mode and wait for mode switch
dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_FDMOD) | GUSBCFG_FHMOD;
- while( (dwc2->gintsts & GINTSTS_CMOD) != GINTSTS_CMODE_HOST) {}
+ while ((dwc2->gintsts & GINTSTS_CMOD) != GINTSTS_CMODE_HOST) {}
// configure fixed-allocated fifo scheme
dfifo_host_init(rhport);
@@ -438,7 +448,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t*
hcsplt_bm->split_compl = 0;
hcsplt_bm->split_en = 0;
- edpt->next_data_toggle = HCTSIZ_PID_DATA0;
+ edpt->next_pid = HCTSIZ_PID_DATA0;
return true;
}
@@ -448,6 +458,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
const uint8_t ep_num = tu_edpt_number(ep_addr);
const uint8_t ep_dir = tu_edpt_dir(ep_addr);
+
uint8_t ep_id = edpt_find_opened(dev_addr, ep_num, ep_dir);
TU_ASSERT(ep_id < CFG_TUH_DWC2_ENDPOINT_MAX);
hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id];
@@ -456,19 +467,21 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
uint8_t ch_id = channel_alloc(dwc2);
TU_ASSERT(ch_id < 16); // all channel are in used
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
+ xfer->ep_id = ep_id;
+
dwc2_channel_t* channel = &dwc2->channel[ch_id];
uint16_t packet_count = tu_div_ceil(buflen, hcchar_bm->ep_size);
if (packet_count == 0) {
packet_count = 1; // zero length packet still count as 1
}
- channel->hctsiz = (edpt->next_data_toggle << HCTSIZ_PID_Pos) | (packet_count << HCTSIZ_PKTCNT_Pos) | buflen;
+ channel->hctsiz = (edpt->next_pid << HCTSIZ_PID_Pos) | (packet_count << HCTSIZ_PKTCNT_Pos) | buflen;
- // Control transfer always start with DATA1 for data and status stage. May has issue with ZLP
- if (edpt->next_data_toggle == HCTSIZ_PID_DATA0 || ep_num == 0) {
- edpt->next_data_toggle = HCTSIZ_PID_DATA1;
+ // pre-calculate next PID based on packet count, adjusted in transfer complete interrupt if short packet
+ if (ep_num == 0) {
+ edpt->next_pid = HCTSIZ_PID_DATA1; // control data and status stage always start with DATA1
} else {
- edpt->next_data_toggle = HCTSIZ_PID_DATA0;
+ edpt->next_pid = cal_next_pid(edpt->next_pid, packet_count);
}
// TODO support split transaction
@@ -546,7 +559,7 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, const uint8_t setup_packet
uint8_t ep_id = edpt_find_opened(dev_addr, 0, TUSB_DIR_OUT);
TU_ASSERT(ep_id < CFG_TUH_DWC2_ENDPOINT_MAX); // no opened endpoint
hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id];
- edpt->next_data_toggle = HCTSIZ_PID_SETUP;
+ edpt->next_pid = HCTSIZ_PID_SETUP;
return hcd_edpt_xfer(rhport, dev_addr, 0, (uint8_t*)(uintptr_t) setup_packet, 8);
}
@@ -554,10 +567,15 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, const uint8_t setup_packet
// clear stall, data toggle is also reset to DATA0
bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
(void) rhport;
- (void) dev_addr;
- (void) ep_addr;
+ const uint8_t ep_num = tu_edpt_number(ep_addr);
+ const uint8_t ep_dir = tu_edpt_dir(ep_addr);
+ const uint8_t ep_id = edpt_find_opened(dev_addr, ep_num, ep_dir);
+ TU_VERIFY(ep_id < CFG_TUH_DWC2_ENDPOINT_MAX);
+ hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id];
+
+ edpt->next_pid = HCTSIZ_PID_DATA0;
- return false;
+ return true;
}
//--------------------------------------------------------------------
@@ -581,24 +599,28 @@ static void handle_rxflvl_irq(uint8_t rhport) {
dfifo_read_packet(dwc2, xfer->buffer, byte_count);
xfer->buffer += byte_count;
+ const uint16_t remain_bytes = (uint16_t) channel->hctsiz_bm.xfer_size;
+ const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
if (byte_count < channel->hcchar_bm.ep_size) {
// short packet, minus remaining bytes
- const uint16_t remain_bytes = (uint16_t) channel->hctsiz_bm.xfer_size;
xfer->total_bytes -= remain_bytes;
+
+ // update PID since we got short packet
+ TU_ASSERT(xfer->ep_id < CFG_TUH_DWC2_ENDPOINT_MAX,);
+ hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; // update PID
+ edpt->next_pid = cal_next_pid(edpt->next_pid, remain_packets);
} else {
- // still more packet to send
- const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
if (remain_packets) {
+ // still more packet to send
bool const is_period = edpt_is_periodic(channel->hcchar_bm.ep_type);
channel_send_in_token(dwc2, channel, is_period);
}
}
-
break;
}
case GRXSTS_PKTSTS_RX_COMPLETE:
- // In transfer complete: After this entry is popped from the receive FIFO, dwc2 asserts a Transfer Completed
+ // In transfer complete: After this entry is popped from the rx FIFO, dwc2 asserts a Transfer Completed
// interrupt --> handle_channel_irq()
break;