diff options
| author | HiFiPhile <[email protected]> | 2024-05-31 12:38:18 +0200 |
|---|---|---|
| committer | HiFiPhile <[email protected]> | 2024-05-31 12:38:18 +0200 |
| commit | b0f5422262a26fb1ab496e33bb8009efb6660788 (patch) | |
| tree | dfd2570838592e9b822e701097f18b753f32bca6 /src | |
| parent | 67456357c54ee81e8418a9e814df774b1a3dee85 (diff) | |
| parent | d10b65ada4be7d5754b3128e80a9b4db72bdb23f (diff) | |
Merge branch 'master' of https://github.com/hathach/tinyusb into rx_fb
Diffstat (limited to 'src')
22 files changed, 1738 insertions, 831 deletions
diff --git a/src/common/tusb_compiler.h b/src/common/tusb_compiler.h index 0d5570b1c..ce5566ffe 100644 --- a/src/common/tusb_compiler.h +++ b/src/common/tusb_compiler.h @@ -128,6 +128,7 @@ #define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name))) #define TU_ATTR_PACKED __attribute__ ((packed)) #define TU_ATTR_WEAK __attribute__ ((weak)) + // #define TU_ATTR_WEAK_ALIAS(f) __attribute__ ((weak, alias(#f)) #ifndef TU_ATTR_ALWAYS_INLINE // allow to override for debug #define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline)) #endif diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index 4e3b89262..c66996c4f 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -195,6 +195,7 @@ #elif TU_CHECK_MCU(OPT_MCU_STM32F4) #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_STM32 + #define TUP_USBIP_DWC2_TEST_MODE // For most mcu, FS has 4, HS has 6. TODO 446/469/479 HS has 9 #define TUP_DCD_ENDPOINT_MAX 6 @@ -209,6 +210,7 @@ // MCU with on-chip HS Phy #if defined(STM32F723xx) || defined(STM32F730xx) || defined(STM32F733xx) #define TUP_RHPORT_HIGHSPEED 1 // Port0: FS, Port1: HS + #define TUP_USBIP_DWC2_TEST_MODE #endif #elif TU_CHECK_MCU(OPT_MCU_STM32H7) @@ -277,6 +279,7 @@ defined(STM32U5F7xx) || defined(STM32U5F9xx) || defined(STM32U5G7xx) || defined(STM32U5G9xx) #define TUP_DCD_ENDPOINT_MAX 9 #define TUP_RHPORT_HIGHSPEED 1 + #define TUP_USBIP_DWC2_TEST_MODE #else #define TUP_DCD_ENDPOINT_MAX 6 #endif @@ -329,7 +332,7 @@ #define TUP_USBIP_DWC2 #define TUP_DCD_ENDPOINT_MAX 6 -#elif TU_CHECK_MCU(OPT_MCU_ESP32) && (CFG_TUD_ENABLED || !(defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421)) +#elif TU_CHECK_MCU(OPT_MCU_ESP32, OPT_MCU_ESP32C2, OPT_MCU_ESP32C3, OPT_MCU_ESP32C6, OPT_MCU_ESP32H2) && (CFG_TUD_ENABLED || !(defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421)) #error "MCUs are only supported with CFG_TUH_MAX3421 enabled" //--------------------------------------------------------------------+ @@ -399,16 +402,57 @@ #elif TU_CHECK_MCU(OPT_MCU_F1C100S) #define TUP_DCD_ENDPOINT_MAX 4 -//------------- WCH -------------// +//--------------------------------------------------------------------+ +// WCH +//--------------------------------------------------------------------+ +#elif TU_CHECK_MCU(OPT_MCU_CH32F20X) + #define TUP_USBIP_WCH_USBHS + #define TUP_USBIP_WCH_USBFS + + #if !defined(CFG_TUD_WCH_USBIP_USBFS) + #define CFG_TUD_WCH_USBIP_USBFS 0 + #endif + + #if !defined(CFG_TUD_WCH_USBIP_USBHS) + #define CFG_TUD_WCH_USBIP_USBHS (CFG_TUD_WCH_USBIP_USBFS ? 0 : 1) + #endif + + #define TUP_RHPORT_HIGHSPEED CFG_TUD_WCH_USBIP_USBHS + #define TUP_DCD_ENDPOINT_MAX (CFG_TUD_WCH_USBIP_USBHS ? 16 : 8) + +#elif TU_CHECK_MCU(OPT_MCU_CH32V20X) + // v20x support both FSDEV (USBD) and USBFS, default to FSDEV + #define TUP_USBIP_WCH_USBFS + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_CH32 + + #if !defined(CFG_TUD_WCH_USBIP_USBFS) + #define CFG_TUD_WCH_USBIP_USBFS 0 + #endif + + #if !defined(CFG_TUD_WCH_USBIP_FSDEV) + #define CFG_TUD_WCH_USBIP_FSDEV (CFG_TUD_WCH_USBIP_USBFS ? 0 : 1) + #endif + + #define TUP_DCD_ENDPOINT_MAX 8 + #elif TU_CHECK_MCU(OPT_MCU_CH32V307) - #define TUP_DCD_ENDPOINT_MAX 16 - #define TUP_RHPORT_HIGHSPEED 1 + // v307 support both FS and HS, default to HS + #define TUP_USBIP_WCH_USBHS + #define TUP_USBIP_WCH_USBFS -#elif TU_CHECK_MCU(OPT_MCU_CH32F20X) - #define TUP_DCD_ENDPOINT_MAX 16 - #define TUP_RHPORT_HIGHSPEED 1 -#endif + #if !defined(CFG_TUD_WCH_USBIP_USBFS) + #define CFG_TUD_WCH_USBIP_USBFS 0 + #endif + #if !defined(CFG_TUD_WCH_USBIP_USBHS) + #define CFG_TUD_WCH_USBIP_USBHS (CFG_TUD_WCH_USBIP_USBFS ? 0 : 1) + #endif + + #define TUP_RHPORT_HIGHSPEED CFG_TUD_WCH_USBIP_USBHS + #define TUP_DCD_ENDPOINT_MAX (CFG_TUD_WCH_USBIP_USBHS ? 16 : 8) + +#endif //--------------------------------------------------------------------+ // External USB controller diff --git a/src/device/dcd.h b/src/device/dcd.h index d4f105aa3..f6735b077 100644 --- a/src/device/dcd.h +++ b/src/device/dcd.h @@ -24,8 +24,8 @@ * This file is part of the TinyUSB stack. */ -#ifndef _TUSB_DCD_H_ -#define _TUSB_DCD_H_ +#ifndef TUSB_DCD_H_ +#define TUSB_DCD_H_ #include "common/tusb_common.h" #include "osal/osal.h" @@ -36,14 +36,6 @@ #endif //--------------------------------------------------------------------+ -// Configuration -//--------------------------------------------------------------------+ - -#ifndef CFG_TUD_ENDPPOINT_MAX - #define CFG_TUD_ENDPPOINT_MAX TUP_DCD_ENDPOINT_MAX -#endif - -//--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF PROTYPES //--------------------------------------------------------------------+ @@ -97,6 +89,14 @@ typedef struct TU_ATTR_ALIGNED(4) { }; } dcd_event_t; +typedef enum { + TEST_J = 1, + TEST_K, + TEST_SE0_NAK, + TEST_PACKET, + TEST_FORCE_ENABLE, +} test_mode_t; + //TU_VERIFY_STATIC(sizeof(dcd_event_t) <= 12, "size is not correct"); //--------------------------------------------------------------------+ @@ -141,14 +141,21 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr); void dcd_remote_wakeup(uint8_t rhport); // Connect by enabling internal pull-up resistor on D+/D- -void dcd_connect(uint8_t rhport) TU_ATTR_WEAK; +void dcd_connect(uint8_t rhport); // Disconnect by disabling internal pull-up resistor on D+/D- -void dcd_disconnect(uint8_t rhport) TU_ATTR_WEAK; +void dcd_disconnect(uint8_t rhport); // Enable/Disable Start-of-frame interrupt. Default is disabled void dcd_sof_enable(uint8_t rhport, bool en); +#if CFG_TUD_TEST_MODE +// Check if the test mode is supported, returns true is test mode selector is supported +bool dcd_check_test_mode_support(test_mode_t test_selector) TU_ATTR_WEAK; + +// Put device into a test mode (needs power cycle to quit) +void dcd_enter_test_mode(uint8_t rhport, test_mode_t test_selector) TU_ATTR_WEAK; +#endif //--------------------------------------------------------------------+ // Endpoint API //--------------------------------------------------------------------+ @@ -239,4 +246,4 @@ TU_ATTR_ALWAYS_INLINE static inline void dcd_event_sof(uint8_t rhport, uint32_t } #endif -#endif /* _TUSB_DCD_H_ */ +#endif diff --git a/src/device/usbd.c b/src/device/usbd.c index e33f39bcf..800d9c824 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -45,11 +45,6 @@ //--------------------------------------------------------------------+ // Weak stubs: invoked if no strong implementation is available //--------------------------------------------------------------------+ -TU_ATTR_WEAK bool dcd_deinit(uint8_t rhport) { - (void) rhport; - return false; -} - TU_ATTR_WEAK void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr) { (void)rhport; (void)eventid; @@ -60,6 +55,19 @@ TU_ATTR_WEAK void tud_sof_cb(uint32_t frame_count) { (void)frame_count; } +TU_ATTR_WEAK bool dcd_deinit(uint8_t rhport) { + (void) rhport; + return false; +} + +TU_ATTR_WEAK void dcd_connect(uint8_t rhport) { + (void) rhport; +} + +TU_ATTR_WEAK void dcd_disconnect(uint8_t rhport) { + (void) rhport; +} + //--------------------------------------------------------------------+ // Device Data //--------------------------------------------------------------------+ @@ -313,7 +321,9 @@ TU_ATTR_ALWAYS_INLINE static inline bool queue_event(dcd_event_t const * event, static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request); static bool process_set_config(uint8_t rhport, uint8_t cfg_num); static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request); - +#if CFG_TUD_TEST_MODE +static bool process_test_mode_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); +#endif // from usbd_control.c void usbd_control_reset(void); void usbd_control_set_request(tusb_control_request_t const *request); @@ -377,21 +387,17 @@ bool tud_remote_wakeup(void) { } bool tud_disconnect(void) { - TU_VERIFY(dcd_disconnect); dcd_disconnect(_usbd_rhport); return true; } bool tud_connect(void) { - TU_VERIFY(dcd_connect); dcd_connect(_usbd_rhport); return true; } -bool tud_sof_cb_enable(bool en) -{ +void tud_sof_cb_enable(bool en) { usbd_sof_enable(_usbd_rhport, SOF_CONSUMER_USER, en); - return true; } //--------------------------------------------------------------------+ @@ -405,7 +411,7 @@ bool tud_init(uint8_t rhport) { // skip if already initialized if (tud_inited()) return true; - TU_LOG_USBD("USBD init on controller %u\r\n", rhport); + TU_LOG_USBD("USBD init on controller %u, Highspeed = %u\r\n", rhport, TUD_OPT_HIGH_SPEED); TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(usbd_device_t)); TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(dcd_event_t)); TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(tu_fifo_t)); @@ -753,14 +759,47 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const break; case TUSB_REQ_SET_FEATURE: - // Only support remote wakeup for device feature - TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue); + // Handle the feature selector + switch(p_request->wValue) + { + // Support for remote wakeup + case TUSB_REQ_FEATURE_REMOTE_WAKEUP: + TU_LOG_USBD(" Enable Remote Wakeup\r\n"); - TU_LOG_USBD(" Enable Remote Wakeup\r\n"); + // Host may enable remote wake up before suspending especially HID device + _usbd_dev.remote_wakeup_en = true; + tud_control_status(rhport, p_request); + break; - // Host may enable remote wake up before suspending especially HID device - _usbd_dev.remote_wakeup_en = true; - tud_control_status(rhport, p_request); +#if CFG_TUD_TEST_MODE + // Support for TEST_MODE + case TUSB_REQ_FEATURE_TEST_MODE: { + // Only handle the test mode if supported and valid + TU_VERIFY(dcd_enter_test_mode && dcd_check_test_mode_support && 0 == tu_u16_low(p_request->wIndex)); + + uint8_t selector = tu_u16_high(p_request->wIndex); + + // Stall request if the selected test mode isn't supported + if (!dcd_check_test_mode_support((test_mode_t)selector)) + { + TU_LOG_USBD(" Unsupported Test Mode (test selector index: %d)\r\n", selector); + + return false; + } + + // Acknowledge request + tud_control_status(rhport, p_request); + + TU_LOG_USBD(" Enter Test Mode (test selector index: %d)\r\n", selector); + + usbd_control_set_complete_callback(process_test_mode_cb); + break; + } +#endif /* CFG_TUD_TEST_MODE */ + + // Stall unsupported feature selector + default: return false; + } break; case TUSB_REQ_CLEAR_FEATURE: @@ -1088,6 +1127,20 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const } } +#if CFG_TUD_TEST_MODE +static bool process_test_mode_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + // At this point it should already be ensured that dcd_enter_test_mode() is defined + + // Only enter the test mode after the request for it has completed + TU_VERIFY(CONTROL_STAGE_ACK == stage); + + dcd_enter_test_mode(rhport, (test_mode_t)tu_u16_high(request->wIndex)); + + return true; +} +#endif /* CFG_TUD_TEST_MODE */ + //--------------------------------------------------------------------+ // DCD Event Handler //--------------------------------------------------------------------+ @@ -1140,7 +1193,7 @@ TU_ATTR_FAST_FUNC void dcd_event_handler(dcd_event_t const* event, bool in_isr) } if (tu_bit_test(_usbd_dev.sof_consumer, SOF_CONSUMER_USER)) { - dcd_event_t const event_sof = {.rhport = event->rhport, .event_id = DCD_EVENT_SOF}; + dcd_event_t const event_sof = {.rhport = event->rhport, .event_id = DCD_EVENT_SOF, .sof.frame_count = event->sof.frame_count}; queue_event(&event_sof, in_isr); } break; diff --git a/src/device/usbd.h b/src/device/usbd.h index 6216d97ac..26e857d36 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -60,7 +60,7 @@ void tud_task (void) { // Check if there is pending events need processing by tud_task() bool tud_task_event_ready(void); -#ifndef _TUSB_DCD_H_ +#ifndef TUSB_DCD_H_ extern void dcd_int_handler(uint8_t rhport); #endif @@ -98,7 +98,7 @@ bool tud_disconnect(void); bool tud_connect(void); // Enable or disable the Start Of Frame callback support -bool tud_sof_cb_enable(bool en); +void tud_sof_cb_enable(bool en); // Carry out Data and Status stage of control transfer // - If len = 0, it is equivalent to sending status only diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index 4dc93d2d8..d9b8e1fc3 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -174,7 +174,8 @@ enum { enum { EP_STATE_IDLE = 0, EP_STATE_COMPLETE = 1, - EP_STATE_ATTEMPT_1 = 2, // pending 1st attempt + EP_STATE_ABORTING = 2, + EP_STATE_ATTEMPT_1 = 3, // pending 1st attempt EP_STATE_ATTEMPT_MAX = 15 }; @@ -459,6 +460,7 @@ bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) { tuh_configure_param_t const* cfg = (tuh_configure_param_t const*) cfg_param; _tuh_cfg = cfg->max3421; + _tuh_cfg.max_nak = tu_min8(_tuh_cfg.max_nak, EP_STATE_ATTEMPT_MAX-EP_STATE_ATTEMPT_1); return true; } @@ -678,7 +680,6 @@ static void xact_generic(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) { uint8_t const ep_num = tu_edpt_number(ep_addr); uint8_t const ep_dir = (uint8_t) tu_edpt_dir(ep_addr); - max3421_ep_t* ep = find_opened_ep(daddr, ep_num, ep_dir); TU_VERIFY(ep); @@ -702,14 +703,19 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf return true; } -// Abort a queued transfer. Note: it can only abort transfer that has not been started -// Return true if a queued transfer is aborted, false if there is no transfer to abort -bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { - (void) rhport; - (void) dev_addr; - (void) ep_addr; +bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) { + uint8_t const ep_num = tu_edpt_number(ep_addr); + uint8_t const ep_dir = (uint8_t) tu_edpt_dir(ep_addr); + max3421_ep_t* ep = find_opened_ep(daddr, ep_num, ep_dir); + TU_VERIFY(ep); - return false; + if (EP_STATE_ATTEMPT_1 <= ep->state && ep->state < EP_STATE_ATTEMPT_MAX) { + hcd_int_disable(rhport); + ep->state = EP_STATE_ABORTING; + hcd_int_enable(rhport); + } + + return true; } // Submit a special transfer to send 8-byte Setup Packet, when complete hcd_event_xfer_complete() must be invoked @@ -819,7 +825,6 @@ static void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t re static void handle_xfer_done(uint8_t rhport, bool in_isr) { uint8_t const hrsl = reg_read(rhport, HRSL_ADDR, in_isr); uint8_t const hresult = hrsl & HRSL_RESULT_MASK; - uint8_t const ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK; uint8_t const hxfr_type = _hcd_data.hxfr & 0xf0; uint8_t const ep_dir = ((hxfr_type & HXFR_SETUP) || (hxfr_type & HXFR_OUT_NIN)) ? 0 : 1; @@ -829,34 +834,30 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) { xfer_result_t xfer_result; switch(hresult) { - case HRSL_SUCCESS: - xfer_result = XFER_RESULT_SUCCESS; - break; - - case HRSL_STALL: - xfer_result = XFER_RESULT_STALLED; - break; - case HRSL_NAK: - if (ep_num == 0) { - // control endpoint -> retry immediately - hxfr_write(rhport, _hcd_data.hxfr, in_isr); + if (ep->state == EP_STATE_ABORTING) { + ep->state = EP_STATE_IDLE; } else { - if (ep->state < EP_STATE_ATTEMPT_MAX) { + if (ep_num == 0) { + // control endpoint -> retry immediately and return + hxfr_write(rhport, _hcd_data.hxfr, in_isr); + return; + } else if (EP_STATE_ATTEMPT_1 <= ep->state && ep->state < EP_STATE_ATTEMPT_MAX) { ep->state++; } + } - max3421_ep_t * next_ep = find_next_pending_ep(ep); - if (ep == next_ep) { - // this endpoint is only one pending -> retry immediately - hxfr_write(rhport, _hcd_data.hxfr, in_isr); - } else if (next_ep) { - // switch to next pending endpoint TODO could have issue with double buffered if not clear previously out data - xact_generic(rhport, next_ep, true, in_isr); - } else { - // no more pending in this frame -> clear busy - atomic_flag_clear(&_hcd_data.busy); - } + max3421_ep_t * next_ep = find_next_pending_ep(ep); + if (ep == next_ep) { + // this endpoint is only one pending -> retry immediately + hxfr_write(rhport, _hcd_data.hxfr, in_isr); + } else if (next_ep) { + // switch to next pending endpoint + // TODO could have issue with double buffered if not clear previously out data + xact_generic(rhport, next_ep, true, in_isr); + } else { + // no more pending in this frame -> clear busy + atomic_flag_clear(&_hcd_data.busy); } return; @@ -864,6 +865,14 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) { // occurred when initialized without any pending transfer. Skip for now return; + case HRSL_SUCCESS: + xfer_result = XFER_RESULT_SUCCESS; + break; + + case HRSL_STALL: + xfer_result = XFER_RESULT_STALLED; + break; + default: TU_LOG3("HRSL: %02X\r\n", hrsl); xfer_result = XFER_RESULT_FAILED; @@ -942,9 +951,8 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) { if (hirq & HIRQ_FRAME_IRQ) { _hcd_data.frame_count++; + // reset all endpoints nak counter, retry with 1st pending ep. max3421_ep_t* ep_retry = NULL; - - // reset all endpoints attempt counter for (size_t i = 0; i < CFG_TUH_MAX3421_ENDPOINT_TOTAL; i++) { max3421_ep_t* ep = &_hcd_data.ep[i]; if (ep->packet_size && ep->state > EP_STATE_ATTEMPT_1) { @@ -1004,7 +1012,7 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) { // clear all interrupt except SNDBAV_IRQ (never clear by us). Note RCVDAV_IRQ, HXFRDN_IRQ already clear while processing hirq &= (uint8_t) ~HIRQ_SNDBAV_IRQ; - if ( hirq ) { + if (hirq) { hirq_write(rhport, hirq, in_isr); } } diff --git a/src/portable/chipidea/ci_hs/dcd_ci_hs.c b/src/portable/chipidea/ci_hs/dcd_ci_hs.c index f9ec666e5..93e1d78dd 100644 --- a/src/portable/chipidea/ci_hs/dcd_ci_hs.c +++ b/src/portable/chipidea/ci_hs/dcd_ci_hs.c @@ -309,10 +309,12 @@ void dcd_disconnect(uint8_t rhport) void dcd_sof_enable(uint8_t rhport, bool en) { - (void) rhport; - (void) en; - - // TODO implement later + ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport); + if (en) { + dcd_reg->USBINTR |= INTR_SOF; + } else { + dcd_reg->USBINTR &= ~INTR_SOF; + } } //--------------------------------------------------------------------+ @@ -679,7 +681,8 @@ void dcd_int_handler(uint8_t rhport) if (int_status & INTR_SOF) { - dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true); + const uint32_t frame = dcd_reg->FRINDEX; + dcd_event_sof(rhport, frame, true); } } diff --git a/src/portable/espressif/esp32sx/dcd_esp32sx.c b/src/portable/espressif/esp32sx/dcd_esp32sx.c index bfc0baa56..f912bef89 100644 --- a/src/portable/espressif/esp32sx/dcd_esp32sx.c +++ b/src/portable/espressif/esp32sx/dcd_esp32sx.c @@ -31,7 +31,8 @@ #if (((CFG_TUSB_MCU == OPT_MCU_ESP32S2) || (CFG_TUSB_MCU == OPT_MCU_ESP32S3)) && CFG_TUD_ENABLED) // Espressif -#include "xtensa_api.h" +#include "xtensa/xtensa_api.h" + #include "esp_intr_alloc.h" #include "esp_log.h" #include "soc/dport_reg.h" diff --git a/src/portable/microchip/samd/dcd_samd.c b/src/portable/microchip/samd/dcd_samd.c index 976d3dfd0..005b63faf 100644 --- a/src/portable/microchip/samd/dcd_samd.c +++ b/src/portable/microchip/samd/dcd_samd.c @@ -183,9 +183,12 @@ void dcd_connect(uint8_t rhport) void dcd_sof_enable(uint8_t rhport, bool en) { (void) rhport; - (void) en; - // TODO implement later + if (en) { + USB->DEVICE.INTENSET.bit.SOF = 1; + } else { + USB->DEVICE.INTENCLR.bit.SOF = 1; + } } /*------------------------------------------------------------------*/ @@ -374,7 +377,9 @@ void dcd_int_handler (uint8_t rhport) if ( int_status & USB_DEVICE_INTFLAG_SOF ) { USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_SOF; - dcd_event_bus_signal(0, DCD_EVENT_SOF, true); + const uint32_t frame = USB->DEVICE.FNUM.bit.FNUM; + dcd_event_sof(0, frame, true); + //dcd_event_bus_signal(0, DCD_EVENT_SOF, true); } // SAMD doesn't distinguish between Suspend and Disconnect state. diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c index 2fe721d6b..abce35245 100644 --- a/src/portable/nordic/nrf5x/dcd_nrf5x.c +++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c @@ -120,6 +120,9 @@ static struct { // nRF can only carry one DMA at a time, this is used to guard the access to EasyDMA atomic_flag dma_running; + + // Track whether sof has been manually enabled + bool sof_enabled; } _dcd; /*------------------------------------------------------------------*/ @@ -147,7 +150,7 @@ static void start_dma(volatile uint32_t* reg_startep) { static void edpt_dma_start(volatile uint32_t* reg_startep) { if (atomic_flag_test_and_set(&_dcd.dma_running)) { - usbd_defer_func((osal_task_func_t)(uintptr_t ) edpt_dma_start, (void*) (uintptr_t) reg_startep, true); + usbd_defer_func((osal_task_func_t)(uintptr_t ) edpt_dma_start, (void*) (uintptr_t) reg_startep, is_in_isr()); } else { start_dma(reg_startep); } @@ -283,9 +286,13 @@ void dcd_connect(uint8_t rhport) { void dcd_sof_enable(uint8_t rhport, bool en) { (void) rhport; - (void) en; - - // TODO implement later + if (en) { + _dcd.sof_enabled = true; + NRF_USBD->INTENSET = USBD_INTENSET_SOF_Msk; + } else { + _dcd.sof_enabled = false; + NRF_USBD->INTENCLR = USBD_INTENCLR_SOF_Msk; + } } //--------------------------------------------------------------------+ @@ -607,13 +614,16 @@ void dcd_int_handler(uint8_t rhport) { } } - if (!iso_enabled) { - // ISO endpoint is not used, SOF is only enabled one-time for remote wakeup - // so we disable it now - NRF_USBD->INTENCLR = USBD_INTENSET_SOF_Msk; + if (!iso_enabled && !_dcd.sof_enabled) { + // SOF interrupt not manually enabled and ISO endpoint is not used, + // SOF is only enabled one-time for remote wakeup so we disable it now + + NRF_USBD->INTENCLR = USBD_INTENCLR_SOF_Msk; } - dcd_event_bus_signal(0, DCD_EVENT_SOF, true); + const uint32_t frame = NRF_USBD->FRAMECNTR; + dcd_event_sof(0, frame, true); + //dcd_event_bus_signal(0, DCD_EVENT_SOF, true); } if (int_status & USBD_INTEN_USBEVENT_Msk) { diff --git a/src/portable/renesas/rusb2/dcd_rusb2.c b/src/portable/renesas/rusb2/dcd_rusb2.c index 50400d1f5..7c6044ca0 100644 --- a/src/portable/renesas/rusb2/dcd_rusb2.c +++ b/src/portable/renesas/rusb2/dcd_rusb2.c @@ -29,10 +29,6 @@ #if CFG_TUD_ENABLED && defined(TUP_USBIP_RUSB2) -// Since TinyUSB doesn't use SOF for now, and this interrupt too often (1ms interval) -// We disable SOF for now until needed later on -#define USE_SOF 0 - #include "device/dcd.h" #include "rusb2_type.h" @@ -74,6 +70,8 @@ typedef struct { pipe_state_t pipe[PIPE_COUNT]; uint8_t ep[2][16]; /* a lookup table for a pipe index from an endpoint address */ + // Track whether sof has been manually enabled + bool sof_enabled; } dcd_data_t; static dcd_data_t _dcd; @@ -664,6 +662,10 @@ void dcd_init(uint8_t rhport) rusb2_reg_t* rusb = RUSB2_REG(rhport); rusb2_module_start(rhport, true); +// We disable SOF for now until needed later on. +// Since TinyUSB doesn't use SOF for now, and this interrupt often (1ms interval) +_dcd.sof_enabled = false; + #ifdef RUSB2_SUPPORT_HIGHSPEED if ( rusb2_is_highspeed_rhport(rhport) ) { rusb->SYSCFG_b.HSE = 1; @@ -708,7 +710,7 @@ void dcd_init(uint8_t rhport) rusb->INTSTS0 = 0; rusb->INTENB0 = RUSB2_INTSTS0_VBINT_Msk | RUSB2_INTSTS0_BRDY_Msk | RUSB2_INTSTS0_BEMP_Msk | - RUSB2_INTSTS0_DVST_Msk | RUSB2_INTSTS0_CTRT_Msk | (USE_SOF ? RUSB2_INTSTS0_SOFR_Msk : 0) | + RUSB2_INTSTS0_DVST_Msk | RUSB2_INTSTS0_CTRT_Msk | (_dcd.sof_enabled ? RUSB2_INTSTS0_SOFR_Msk : 0) | RUSB2_INTSTS0_RESM_Msk; rusb->BEMPENB = 1; rusb->BRDYENB = 1; @@ -756,10 +758,9 @@ void dcd_disconnect(uint8_t rhport) void dcd_sof_enable(uint8_t rhport, bool en) { - (void) rhport; - (void) en; - - // TODO implement later + rusb2_reg_t* rusb = RUSB2_REG(rhport); + _dcd.sof_enabled = en; + rusb->INTENB0_b.SOFE = en ? 1: 0; } //--------------------------------------------------------------------+ @@ -949,18 +950,19 @@ void dcd_int_handler(uint8_t rhport) // Resumed if ( is0 & RUSB2_INTSTS0_RESM_Msk ) { dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true); -#if (0 == USE_SOF) - rusb->INTENB0_b.SOFE = 0; -#endif + if (!_dcd.sof_enabled) { + rusb->INTENB0_b.SOFE = 0; + } } // SOF received if ( (is0 & RUSB2_INTSTS0_SOFR_Msk) && rusb->INTENB0_b.SOFE ) { // USBD will exit suspended mode when SOF event is received - dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true); -#if (0 == USE_SOF) - rusb->INTENB0_b.SOFE = 0; -#endif + const uint32_t frame = rusb->FRMNUM_b.FRNM; + dcd_event_sof(rhport, frame, true); + if (!_dcd.sof_enabled) { + rusb->INTENB0_b.SOFE = 0; + } } // Device state changes @@ -979,9 +981,9 @@ void dcd_int_handler(uint8_t rhport) case RUSB2_INTSTS0_DVSQ_STATE_SUSP2: case RUSB2_INTSTS0_DVSQ_STATE_SUSP3: dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true); -#if (0 == USE_SOF) - rusb->INTENB0_b.SOFE = 1; -#endif + if (!_dcd.sof_enabled) { + rusb->INTENB0_b.SOFE = 1; + } default: break; } diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index a26c66892..9ce37f992 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -102,25 +102,29 @@ #include "tusb_option.h" -#if CFG_TUD_ENABLED && defined(TUP_USBIP_FSDEV) +#if CFG_TUD_ENABLED && defined(TUP_USBIP_FSDEV) && \ + !(defined(TUP_USBIP_FSDEV_CH32) && CFG_TUD_WCH_USBIP_FSDEV == 0) #include "device/dcd.h" -#ifdef TUP_USBIP_FSDEV_STM32 -// Undefine to reduce the dependence on HAL -#undef USE_HAL_DRIVER -#include "portable/st/stm32_fsdev/dcd_stm32_fsdev.h" +#if defined(TUP_USBIP_FSDEV_STM32) + // Undefine to reduce the dependence on HAL + #undef USE_HAL_DRIVER + #include "fsdev_stm32.h" +#elif defined(TUP_USBIP_FSDEV_CH32) + #include "fsdev_ch32.h" +#else + #error "Unknown USB IP" #endif -/***************************************************** - * Configuration - *****************************************************/ +#include "fsdev_common.h" -// HW supports max of 8 bidirectional endpoints, but this can be reduced to save RAM -// (8u here would mean 8 IN and 8 OUT) -#ifndef MAX_EP_COUNT -#define MAX_EP_COUNT 8U -#endif +//--------------------------------------------------------------------+ +// Configuration +//--------------------------------------------------------------------+ + +// hardware limit endpoint +#define FSDEV_EP_COUNT 8 // If sharing with CAN, one can set this to be non-zero to give CAN space where it wants it // Both of these MUST be a multiple of 2, and are in byte units. @@ -132,11 +136,6 @@ #define DCD_STM32_BTABLE_SIZE (FSDEV_PMA_SIZE - DCD_STM32_BTABLE_BASE) #endif -/*************************************************** - * Checks, structs, defines, function definitions, etc. - */ - -TU_VERIFY_STATIC((MAX_EP_COUNT) <= STFSDEV_EP_COUNT, "Only 8 endpoints supported on the hardware"); TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) + (DCD_STM32_BTABLE_SIZE)) <= (FSDEV_PMA_SIZE), "BTABLE does not fit in PMA RAM"); TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) % 8) == 0, "BTABLE base must be aligned to 8 bytes"); @@ -162,9 +161,9 @@ typedef struct { bool allocated[2]; } ep_alloc_t; -static xfer_ctl_t xfer_status[MAX_EP_COUNT][2]; +static xfer_ctl_t xfer_status[CFG_TUD_ENDPPOINT_MAX][2]; -static ep_alloc_t ep_alloc_status[STFSDEV_EP_COUNT]; +static ep_alloc_t ep_alloc_status[FSDEV_EP_COUNT]; static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[6]; @@ -199,7 +198,7 @@ TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t *xfer_ctl_ptr(uint32_t ep_addr) uint8_t epnum = tu_edpt_number(ep_addr); uint8_t dir = tu_edpt_dir(ep_addr); // Fix -Werror=null-dereference - TU_ASSERT(epnum < MAX_EP_COUNT, &xfer_status[0][0]); + TU_ASSERT(epnum < CFG_TUD_ENDPPOINT_MAX, &xfer_status[0][0]); return &xfer_status[epnum][dir]; } @@ -239,7 +238,7 @@ void dcd_init(uint8_t rhport) USB->ISTR = 0; // Clear pending interrupts // Reset endpoints to disabled - for (uint32_t i = 0; i < STFSDEV_EP_COUNT; i++) { + for (uint32_t i = 0; i < FSDEV_EP_COUNT; i++) { // This doesn't clear all bits since some bits are "toggle", but does set the type to DISABLED. pcd_set_endpoint(USB, i, 0u); } @@ -248,43 +247,9 @@ void dcd_init(uint8_t rhport) dcd_handle_bus_reset(); // Enable pull-up if supported - if (dcd_connect) { - dcd_connect(rhport); - } + dcd_connect(rhport); } -// Define only on MCU with internal pull-up. BSP can define on MCU without internal PU. -#if defined(USB_BCDR_DPPU) - -// Disable internal D+ PU -void dcd_disconnect(uint8_t rhport) -{ - (void)rhport; - USB->BCDR &= ~(USB_BCDR_DPPU); -} - -// Enable internal D+ PU -void dcd_connect(uint8_t rhport) -{ - (void)rhport; - USB->BCDR |= USB_BCDR_DPPU; -} - -#elif defined(SYSCFG_PMC_USB_PU) // works e.g. on STM32L151 -// Disable internal D+ PU -void dcd_disconnect(uint8_t rhport) -{ - (void)rhport; - SYSCFG->PMC &= ~(SYSCFG_PMC_USB_PU); -} - -// Enable internal D+ PU -void dcd_connect(uint8_t rhport) -{ - (void)rhport; - SYSCFG->PMC |= SYSCFG_PMC_USB_PU; -} -#endif void dcd_sof_enable(uint8_t rhport, bool en) { @@ -298,126 +263,6 @@ void dcd_sof_enable(uint8_t rhport, bool en) } } -// Enable device interrupt -void dcd_int_enable(uint8_t rhport) -{ - (void)rhport; - // Member here forces write to RAM before allowing ISR to execute - __DSB(); - __ISB(); -#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 || CFG_TUSB_MCU == OPT_MCU_STM32L4 - NVIC_EnableIRQ(USB_IRQn); - -#elif CFG_TUSB_MCU == OPT_MCU_STM32L1 - NVIC_EnableIRQ(USB_LP_IRQn); - -#elif CFG_TUSB_MCU == OPT_MCU_STM32F3 -// Some STM32F302/F303 devices allow to remap the USB interrupt vectors from -// shared USB/CAN IRQs to separate CAN and USB IRQs. -// This dynamically checks if this remap is active to enable the right IRQs. -#ifdef SYSCFG_CFGR1_USB_IT_RMP - if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) { - NVIC_EnableIRQ(USB_HP_IRQn); - NVIC_EnableIRQ(USB_LP_IRQn); - NVIC_EnableIRQ(USBWakeUp_RMP_IRQn); - } else -#endif - { - NVIC_EnableIRQ(USB_HP_CAN_TX_IRQn); - NVIC_EnableIRQ(USB_LP_CAN_RX0_IRQn); - NVIC_EnableIRQ(USBWakeUp_IRQn); - } -#elif CFG_TUSB_MCU == OPT_MCU_STM32F1 - NVIC_EnableIRQ(USB_HP_CAN1_TX_IRQn); - NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn); - NVIC_EnableIRQ(USBWakeUp_IRQn); - -#elif CFG_TUSB_MCU == OPT_MCU_STM32G4 - NVIC_EnableIRQ(USB_HP_IRQn); - NVIC_EnableIRQ(USB_LP_IRQn); - NVIC_EnableIRQ(USBWakeUp_IRQn); - -#elif CFG_TUSB_MCU == OPT_MCU_STM32G0 -#ifdef STM32G0B0xx - NVIC_EnableIRQ(USB_IRQn); -#else - NVIC_EnableIRQ(USB_UCPD1_2_IRQn); -#endif - -#elif CFG_TUSB_MCU == OPT_MCU_STM32H5 - NVIC_EnableIRQ(USB_DRD_FS_IRQn); - -#elif CFG_TUSB_MCU == OPT_MCU_STM32WB - NVIC_EnableIRQ(USB_HP_IRQn); - NVIC_EnableIRQ(USB_LP_IRQn); - -#elif CFG_TUSB_MCU == OPT_MCU_STM32L5 - NVIC_EnableIRQ(USB_FS_IRQn); - -#else -#error Unknown arch in USB driver -#endif -} - -// Disable device interrupt -void dcd_int_disable(uint8_t rhport) -{ - (void)rhport; - -#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 || CFG_TUSB_MCU == OPT_MCU_STM32L4 - NVIC_DisableIRQ(USB_IRQn); -#elif CFG_TUSB_MCU == OPT_MCU_STM32L1 - NVIC_DisableIRQ(USB_LP_IRQn); -#elif CFG_TUSB_MCU == OPT_MCU_STM32F3 -// Some STM32F302/F303 devices allow to remap the USB interrupt vectors from -// shared USB/CAN IRQs to separate CAN and USB IRQs. -// This dynamically checks if this remap is active to disable the right IRQs. -#ifdef SYSCFG_CFGR1_USB_IT_RMP - if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) { - NVIC_DisableIRQ(USB_HP_IRQn); - NVIC_DisableIRQ(USB_LP_IRQn); - NVIC_DisableIRQ(USBWakeUp_RMP_IRQn); - } else -#endif - { - NVIC_DisableIRQ(USB_HP_CAN_TX_IRQn); - NVIC_DisableIRQ(USB_LP_CAN_RX0_IRQn); - NVIC_DisableIRQ(USBWakeUp_IRQn); - } -#elif CFG_TUSB_MCU == OPT_MCU_STM32F1 - NVIC_DisableIRQ(USB_HP_CAN1_TX_IRQn); - NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn); - NVIC_DisableIRQ(USBWakeUp_IRQn); - -#elif CFG_TUSB_MCU == OPT_MCU_STM32G4 - NVIC_DisableIRQ(USB_HP_IRQn); - NVIC_DisableIRQ(USB_LP_IRQn); - NVIC_DisableIRQ(USBWakeUp_IRQn); - -#elif CFG_TUSB_MCU == OPT_MCU_STM32G0 -#ifdef STM32G0B0xx - NVIC_DisableIRQ(USB_IRQn); -#else - NVIC_DisableIRQ(USB_UCPD1_2_IRQn); -#endif - -#elif CFG_TUSB_MCU == OPT_MCU_STM32H5 - NVIC_DisableIRQ(USB_DRD_FS_IRQn); - -#elif CFG_TUSB_MCU == OPT_MCU_STM32WB - NVIC_DisableIRQ(USB_HP_IRQn); - NVIC_DisableIRQ(USB_LP_IRQn); - -#elif CFG_TUSB_MCU == OPT_MCU_STM32L5 - NVIC_DisableIRQ(USB_FS_IRQn); - -#else -#error Unknown arch in USB driver -#endif - - // CMSIS has a membar after disabling interrupts -} - // Receive Set Address request, mcu port must also include status IN response void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { @@ -461,7 +306,7 @@ static void dcd_handle_bus_reset(void) { USB->DADDR = 0u; // disable USB peripheral by clearing the EF flag - for (uint32_t i = 0; i < STFSDEV_EP_COUNT; i++) { + for (uint32_t i = 0; i < FSDEV_EP_COUNT; i++) { // Clear EP allocation status ep_alloc_status[i].ep_num = 0xFF; ep_alloc_status[i].ep_type = 0xFF; @@ -470,7 +315,7 @@ static void dcd_handle_bus_reset(void) } // Reset PMA allocation - ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8 * MAX_EP_COUNT; + ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8 * CFG_TUD_ENDPPOINT_MAX; dcd_edpt_open(0, &ep0OUT_desc); dcd_edpt_open(0, &ep0IN_desc); @@ -653,7 +498,6 @@ static void dcd_ep_ctr_handler(void) void dcd_int_handler(uint8_t rhport) { - (void)rhport; uint32_t int_status = USB->ISTR; @@ -774,7 +618,7 @@ static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type) uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); - for (uint8_t i = 0; i < STFSDEV_EP_COUNT; i++) { + for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) { // Check if already allocated if (ep_alloc_status[i].allocated[dir] && ep_alloc_status[i].ep_type == ep_type && @@ -818,7 +662,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc) uint16_t pma_addr; uint32_t wType; - TU_ASSERT(ep_idx < STFSDEV_EP_COUNT); + TU_ASSERT(ep_idx < FSDEV_EP_COUNT); TU_ASSERT(buffer_size <= 64); // Set type @@ -865,7 +709,7 @@ void dcd_edpt_close_all(uint8_t rhport) { (void)rhport; - for (uint32_t i = 1; i < STFSDEV_EP_COUNT; i++) { + for (uint32_t i = 1; i < FSDEV_EP_COUNT; i++) { // Reset endpoint pcd_set_endpoint(USB, i, 0); // Clear EP allocation status @@ -876,7 +720,7 @@ void dcd_edpt_close_all(uint8_t rhport) } // Reset PMA allocation - ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8 * MAX_EP_COUNT + 2 * CFG_TUD_ENDPOINT0_SIZE; + ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8 * CFG_TUD_ENDPPOINT_MAX + 2 * CFG_TUD_ENDPOINT0_SIZE; } /** @@ -1155,7 +999,7 @@ static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, ui } if (wNBytes) { - temp1 = *srcVal; + temp1 = (uint16_t) *srcVal; *pdwVal = temp1; } diff --git a/src/portable/st/stm32_fsdev/fsdev_ch32.h b/src/portable/st/stm32_fsdev/fsdev_ch32.h new file mode 100644 index 000000000..85fe3266c --- /dev/null +++ b/src/portable/st/stm32_fsdev/fsdev_ch32.h @@ -0,0 +1,232 @@ +/* +* The MIT License (MIT) + * + * Copyright (c) 2024, hathach (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 + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +/** <h2><center>© Copyright (c) 2016 STMicroelectronics. + * All rights reserved.</center></h2> + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + */ + +#ifndef TUSB_FSDEV_CH32_H +#define TUSB_FSDEV_CH32_H + +#include "common/tusb_compiler.h" + +#if CFG_TUSB_MCU == OPT_MCU_CH32V20X + #include <ch32v20x.h> + +#elif CFG_TUSB_MCU == OPT_MCU_CH32F20X + #include <ch32f20x.h> +#endif + +#define FSDEV_PMA_SIZE (512u) + +// volatile 32-bit aligned +#define _va32 volatile TU_ATTR_ALIGNED(4) + +typedef struct { + _va32 uint16_t EP0R; // 00: USB Endpoint 0 register + _va32 uint16_t EP1R; // 04: USB Endpoint 1 register + _va32 uint16_t EP2R; // 08: USB Endpoint 2 register + _va32 uint16_t EP3R; // 0C: USB Endpoint 3 register + _va32 uint16_t EP4R; // 10: USB Endpoint 4 register + _va32 uint16_t EP5R; // 14: USB Endpoint 5 register + _va32 uint16_t EP6R; // 18: USB Endpoint 6 register + _va32 uint16_t EP7R; // 1C: USB Endpoint 7 register + _va32 uint16_t RESERVED7[16]; // Reserved + _va32 uint16_t CNTR; // 40: Control register + _va32 uint16_t ISTR; // 44: Interrupt status register + _va32 uint16_t FNR; // 48: Frame number register + _va32 uint16_t DADDR; // 4C: Device address register + _va32 uint16_t BTABLE; // 50: Buffer Table address register +} USB_TypeDef; + +TU_VERIFY_STATIC(sizeof(USB_TypeDef) == 0x54, "Size is not correct"); +TU_VERIFY_STATIC(offsetof(USB_TypeDef, CNTR) == 0x40, "Wrong offset"); + +#define USB_BASE (APB1PERIPH_BASE + 0x00005C00UL) /*!< USB_IP Peripheral Registers base address */ +#define USB_PMAADDR (APB1PERIPH_BASE + 0x00006000UL) /*!< USB_IP Packet Memory Area base address */ +#define USB ((USB_TypeDef *)USB_BASE) + +/******************************************************************************/ +/* */ +/* USB Device General registers */ +/* */ +/******************************************************************************/ +#define USB_CNTR (USB_BASE + 0x40U) /*!< Control register */ +#define USB_ISTR (USB_BASE + 0x44U) /*!< Interrupt status register */ +#define USB_FNR (USB_BASE + 0x48U) /*!< Frame number register */ +#define USB_DADDR (USB_BASE + 0x4CU) /*!< Device address register */ +#define USB_BTABLE (USB_BASE + 0x50U) /*!< Buffer Table address register */ + +/**************************** ISTR interrupt events *************************/ +#define USB_ISTR_CTR ((uint16_t)0x8000U) /*!< Correct TRansfer (clear-only bit) */ +#define USB_ISTR_PMAOVR ((uint16_t)0x4000U) /*!< DMA OVeR/underrun (clear-only bit) */ +#define USB_ISTR_ERR ((uint16_t)0x2000U) /*!< ERRor (clear-only bit) */ +#define USB_ISTR_WKUP ((uint16_t)0x1000U) /*!< WaKe UP (clear-only bit) */ +#define USB_ISTR_SUSP ((uint16_t)0x0800U) /*!< SUSPend (clear-only bit) */ +#define USB_ISTR_RESET ((uint16_t)0x0400U) /*!< RESET (clear-only bit) */ +#define USB_ISTR_SOF ((uint16_t)0x0200U) /*!< Start Of Frame (clear-only bit) */ +#define USB_ISTR_ESOF ((uint16_t)0x0100U) /*!< Expected Start Of Frame (clear-only bit) */ +#define USB_ISTR_DIR ((uint16_t)0x0010U) /*!< DIRection of transaction (read-only bit) */ +#define USB_ISTR_EP_ID ((uint16_t)0x000FU) /*!< EndPoint IDentifier (read-only bit) */ + +/* Legacy defines */ +#define USB_ISTR_PMAOVRM USB_ISTR_PMAOVR + +#define USB_CLR_CTR (~USB_ISTR_CTR) /*!< clear Correct TRansfer bit */ +#define USB_CLR_PMAOVR (~USB_ISTR_PMAOVR) /*!< clear DMA OVeR/underrun bit*/ +#define USB_CLR_ERR (~USB_ISTR_ERR) /*!< clear ERRor bit */ +#define USB_CLR_WKUP (~USB_ISTR_WKUP) /*!< clear WaKe UP bit */ +#define USB_CLR_SUSP (~USB_ISTR_SUSP) /*!< clear SUSPend bit */ +#define USB_CLR_RESET (~USB_ISTR_RESET) /*!< clear RESET bit */ +#define USB_CLR_SOF (~USB_ISTR_SOF) /*!< clear Start Of Frame bit */ +#define USB_CLR_ESOF (~USB_ISTR_ESOF) /*!< clear Expected Start Of Frame bit */ + +/* Legacy defines */ +#define USB_CLR_PMAOVRM USB_CLR_PMAOVR + +/************************* CNTR control register bits definitions ***********/ +#define USB_CNTR_CTRM ((uint16_t)0x8000U) /*!< Correct TRansfer Mask */ +#define USB_CNTR_PMAOVR ((uint16_t)0x4000U) /*!< DMA OVeR/underrun Mask */ +#define USB_CNTR_ERRM ((uint16_t)0x2000U) /*!< ERRor Mask */ +#define USB_CNTR_WKUPM ((uint16_t)0x1000U) /*!< WaKe UP Mask */ +#define USB_CNTR_SUSPM ((uint16_t)0x0800U) /*!< SUSPend Mask */ +#define USB_CNTR_RESETM ((uint16_t)0x0400U) /*!< RESET Mask */ +#define USB_CNTR_SOFM ((uint16_t)0x0200U) /*!< Start Of Frame Mask */ +#define USB_CNTR_ESOFM ((uint16_t)0x0100U) /*!< Expected Start Of Frame Mask */ +#define USB_CNTR_RESUME ((uint16_t)0x0010U) /*!< RESUME request */ +#define USB_CNTR_FSUSP ((uint16_t)0x0008U) /*!< Force SUSPend */ +#define USB_CNTR_LPMODE ((uint16_t)0x0004U) /*!< Low-power MODE */ +#define USB_CNTR_PDWN ((uint16_t)0x0002U) /*!< Power DoWN */ +#define USB_CNTR_FRES ((uint16_t)0x0001U) /*!< Force USB RESet */ + +/* Legacy defines */ +#define USB_CNTR_PMAOVRM USB_CNTR_PMAOVR +#define USB_CNTR_LP_MODE USB_CNTR_LPMODE + +/******************** FNR Frame Number Register bit definitions ************/ +#define USB_FNR_RXDP ((uint16_t)0x8000U) /*!< status of D+ data line */ +#define USB_FNR_RXDM ((uint16_t)0x4000U) /*!< status of D- data line */ +#define USB_FNR_LCK ((uint16_t)0x2000U) /*!< LoCKed */ +#define USB_FNR_LSOF ((uint16_t)0x1800U) /*!< Lost SOF */ +#define USB_FNR_FN ((uint16_t)0x07FFU) /*!< Frame Number */ + +/******************** DADDR Device ADDRess bit definitions ****************/ +#define USB_DADDR_EF ((uint8_t)0x80U) /*!< USB device address Enable Function */ +#define USB_DADDR_ADD ((uint8_t)0x7FU) /*!< USB device address */ + +/****************************** Endpoint register *************************/ +#define USB_EP0R USB_BASE /*!< endpoint 0 register address */ +#define USB_EP1R (USB_BASE + 0x04U) /*!< endpoint 1 register address */ +#define USB_EP2R (USB_BASE + 0x08U) /*!< endpoint 2 register address */ +#define USB_EP3R (USB_BASE + 0x0CU) /*!< endpoint 3 register address */ +#define USB_EP4R (USB_BASE + 0x10U) /*!< endpoint 4 register address */ +#define USB_EP5R (USB_BASE + 0x14U) /*!< endpoint 5 register address */ +#define USB_EP6R (USB_BASE + 0x18U) /*!< endpoint 6 register address */ +#define USB_EP7R (USB_BASE + 0x1CU) /*!< endpoint 7 register address */ +/* bit positions */ +#define USB_EP_CTR_RX ((uint16_t)0x8000U) /*!< EndPoint Correct TRansfer RX */ +#define USB_EP_DTOG_RX ((uint16_t)0x4000U) /*!< EndPoint Data TOGGLE RX */ +#define USB_EPRX_STAT ((uint16_t)0x3000U) /*!< EndPoint RX STATus bit field */ +#define USB_EP_SETUP ((uint16_t)0x0800U) /*!< EndPoint SETUP */ +#define USB_EP_T_FIELD ((uint16_t)0x0600U) /*!< EndPoint TYPE */ +#define USB_EP_KIND ((uint16_t)0x0100U) /*!< EndPoint KIND */ +#define USB_EP_CTR_TX ((uint16_t)0x0080U) /*!< EndPoint Correct TRansfer TX */ +#define USB_EP_DTOG_TX ((uint16_t)0x0040U) /*!< EndPoint Data TOGGLE TX */ +#define USB_EPTX_STAT ((uint16_t)0x0030U) /*!< EndPoint TX STATus bit field */ +#define USB_EPADDR_FIELD ((uint16_t)0x000FU) /*!< EndPoint ADDRess FIELD */ + +/* EndPoint REGister MASK (no toggle fields) */ +#define USB_EPREG_MASK (USB_EP_CTR_RX|USB_EP_SETUP|USB_EP_T_FIELD|USB_EP_KIND|USB_EP_CTR_TX|USB_EPADDR_FIELD) + /*!< EP_TYPE[1:0] EndPoint TYPE */ +#define USB_EP_TYPE_MASK ((uint16_t)0x0600U) /*!< EndPoint TYPE Mask */ +#define USB_EP_BULK ((uint16_t)0x0000U) /*!< EndPoint BULK */ +#define USB_EP_CONTROL ((uint16_t)0x0200U) /*!< EndPoint CONTROL */ +#define USB_EP_ISOCHRONOUS ((uint16_t)0x0400U) /*!< EndPoint ISOCHRONOUS */ +#define USB_EP_INTERRUPT ((uint16_t)0x0600U) /*!< EndPoint INTERRUPT */ +#define USB_EP_T_MASK ((uint16_t) ~USB_EP_T_FIELD & USB_EPREG_MASK) + +#define USB_EPKIND_MASK ((uint16_t) ~USB_EP_KIND & USB_EPREG_MASK) /*!< EP_KIND EndPoint KIND */ + /*!< STAT_TX[1:0] STATus for TX transfer */ +#define USB_EP_TX_DIS ((uint16_t)0x0000U) /*!< EndPoint TX DISabled */ +#define USB_EP_TX_STALL ((uint16_t)0x0010U) /*!< EndPoint TX STALLed */ +#define USB_EP_TX_NAK ((uint16_t)0x0020U) /*!< EndPoint TX NAKed */ +#define USB_EP_TX_VALID ((uint16_t)0x0030U) /*!< EndPoint TX VALID */ +#define USB_EPTX_DTOG1 ((uint16_t)0x0010U) /*!< EndPoint TX Data TOGgle bit1 */ +#define USB_EPTX_DTOG2 ((uint16_t)0x0020U) /*!< EndPoint TX Data TOGgle bit2 */ +#define USB_EPTX_DTOGMASK (USB_EPTX_STAT|USB_EPREG_MASK) + /*!< STAT_RX[1:0] STATus for RX transfer */ +#define USB_EP_RX_DIS ((uint16_t)0x0000U) /*!< EndPoint RX DISabled */ +#define USB_EP_RX_STALL ((uint16_t)0x1000U) /*!< EndPoint RX STALLed */ +#define USB_EP_RX_NAK ((uint16_t)0x2000U) /*!< EndPoint RX NAKed */ +#define USB_EP_RX_VALID ((uint16_t)0x3000U) /*!< EndPoint RX VALID */ +#define USB_EPRX_DTOG1 ((uint16_t)0x1000U) /*!< EndPoint RX Data TOGgle bit1 */ +#define USB_EPRX_DTOG2 ((uint16_t)0x2000U) /*!< EndPoint RX Data TOGgle bit1 */ +#define USB_EPRX_DTOGMASK (USB_EPRX_STAT|USB_EPREG_MASK) + + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ + +#if CFG_TUSB_MCU == OPT_MCU_CH32V20X +static const IRQn_Type fsdev_irq[] = { + USB_HP_CAN1_TX_IRQn, + USB_LP_CAN1_RX0_IRQn, + USBWakeUp_IRQn +}; +enum { FSDEV_IRQ_NUM = TU_ARRAY_SIZE(fsdev_irq) }; +#else + #error "Unsupported MCU" +#endif + +void dcd_int_enable(uint8_t rhport) { + (void)rhport; + for(uint8_t i=0; i < FSDEV_IRQ_NUM; i++) { + NVIC_EnableIRQ(fsdev_irq[i]); + } +} + +void dcd_int_disable(uint8_t rhport) { + (void)rhport; + for(uint8_t i=0; i < FSDEV_IRQ_NUM; i++) { + NVIC_DisableIRQ(fsdev_irq[i]); + } +} + +void dcd_disconnect(uint8_t rhport) { + (void) rhport; + EXTEN->EXTEN_CTR &= ~EXTEN_USBD_PU_EN; +} + +void dcd_connect(uint8_t rhport) { + (void) rhport; + EXTEN->EXTEN_CTR |= EXTEN_USBD_PU_EN; +} + +#endif diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.h b/src/portable/st/stm32_fsdev/fsdev_common.h index 7992f34a1..af5d8afab 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.h +++ b/src/portable/st/stm32_fsdev/fsdev_common.h @@ -1,174 +1,43 @@ /* + * The MIT License (MIT) + * * Copyright(c) 2016 STMicroelectronics * Copyright(c) N Conrad - * Copyright (c) 2019 Ha Thach (tinyusb.org) + * Copyright (c) 2024, hathach (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 + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. * - * This file is part of the TinyUSB stack. */ -// This file contains source copied from ST's HAL, and thus should have their copyright statement. +#ifndef TUSB_FSDEV_COMMON_H +#define TUSB_FSDEV_COMMON_H + +#ifdef __cplusplus + extern "C" { +#endif + +#include "stdint.h" // FSDEV_PMA_SIZE is PMA buffer size in bytes. // On 512-byte devices, access with a stride of two words (use every other 16-bit address) // On 1024-byte devices, access with a stride of one word (use every 16-bit address) -#ifndef PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_ -#define PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_ - -#if CFG_TUSB_MCU == OPT_MCU_STM32F0 - #include "stm32f0xx.h" - #define FSDEV_PMA_SIZE (1024u) - // F0x2 models are crystal-less - // All have internal D+ pull-up - // 070RB: 2 x 16 bits/word memory LPM Support, BCD Support - // PMA dedicated to USB (no sharing with CAN) - -#elif CFG_TUSB_MCU == OPT_MCU_STM32F1 - #include "stm32f1xx.h" - #define FSDEV_PMA_SIZE (512u) - // NO internal Pull-ups - // *B, and *C: 2 x 16 bits/word - - // F1 names this differently from the rest - #define USB_CNTR_LPMODE USB_CNTR_LP_MODE - -#elif defined(STM32F302xB) || defined(STM32F302xC) || \ - defined(STM32F303xB) || defined(STM32F303xC) || \ - defined(STM32F373xC) - #include "stm32f3xx.h" - #define FSDEV_PMA_SIZE (512u) - // NO internal Pull-ups - // *B, and *C: 1 x 16 bits/word - // PMA dedicated to USB (no sharing with CAN) - -#elif defined(STM32F302x6) || defined(STM32F302x8) || \ - defined(STM32F302xD) || defined(STM32F302xE) || \ - defined(STM32F303xD) || defined(STM32F303xE) - #include "stm32f3xx.h" - #define FSDEV_PMA_SIZE (1024u) - // NO internal Pull-ups - // *6, *8, *D, and *E: 2 x 16 bits/word LPM Support - // When CAN clock is enabled, USB can use first 768 bytes ONLY. - -#elif CFG_TUSB_MCU == OPT_MCU_STM32L0 - #include "stm32l0xx.h" - #define FSDEV_PMA_SIZE (1024u) - -#elif CFG_TUSB_MCU == OPT_MCU_STM32L1 - #include "stm32l1xx.h" - #define FSDEV_PMA_SIZE (512u) - -#elif CFG_TUSB_MCU == OPT_MCU_STM32G4 - #include "stm32g4xx.h" - #define FSDEV_PMA_SIZE (1024u) - -#elif CFG_TUSB_MCU == OPT_MCU_STM32G0 - #include "stm32g0xx.h" - #define FSDEV_BUS_32BIT - #define FSDEV_PMA_SIZE (2048u) - #undef USB_PMAADDR - #define USB_PMAADDR USB_DRD_PMAADDR - #define USB_TypeDef USB_DRD_TypeDef - #define EP0R CHEP0R - #define USB_EP_CTR_RX USB_EP_VTRX - #define USB_EP_CTR_TX USB_EP_VTTX - #define USB_EP_T_FIELD USB_CHEP_UTYPE - #define USB_EPREG_MASK USB_CHEP_REG_MASK - #define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK - #define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK - #define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1 - #define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2 - #define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1 - #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2 - #define USB_EPRX_STAT USB_CH_RX_VALID - #define USB_EPKIND_MASK USB_EP_KIND_MASK - #define USB USB_DRD_FS - #define USB_CNTR_FRES USB_CNTR_USBRST - #define USB_CNTR_RESUME USB_CNTR_L2RES - #define USB_ISTR_EP_ID USB_ISTR_IDN - #define USB_EPADDR_FIELD USB_CHEP_ADDR - #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY - #define USB_CNTR_FSUSP USB_CNTR_SUSPEN - -#elif CFG_TUSB_MCU == OPT_MCU_STM32H5 - #include "stm32h5xx.h" - #define FSDEV_BUS_32BIT - - #if !defined(USB_DRD_BASE) && defined(USB_DRD_FS_BASE) - #define USB_DRD_BASE USB_DRD_FS_BASE - #endif - - #define FSDEV_PMA_SIZE (2048u) - #undef USB_PMAADDR - #define USB_PMAADDR USB_DRD_PMAADDR - #define USB_TypeDef USB_DRD_TypeDef - #define EP0R CHEP0R - #define USB_EP_CTR_RX USB_EP_VTRX - #define USB_EP_CTR_TX USB_EP_VTTX - #define USB_EP_T_FIELD USB_CHEP_UTYPE - #define USB_EPREG_MASK USB_CHEP_REG_MASK - #define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK - #define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK - #define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1 - #define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2 - #define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1 - #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2 - #define USB_EPRX_STAT USB_CH_RX_VALID - #define USB_EPKIND_MASK USB_EP_KIND_MASK - #define USB USB_DRD_FS - #define USB_CNTR_FRES USB_CNTR_USBRST - #define USB_CNTR_RESUME USB_CNTR_L2RES - #define USB_ISTR_EP_ID USB_ISTR_IDN - #define USB_EPADDR_FIELD USB_CHEP_ADDR - #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY - #define USB_CNTR_FSUSP USB_CNTR_SUSPEN - -#elif CFG_TUSB_MCU == OPT_MCU_STM32WB - #include "stm32wbxx.h" - #define FSDEV_PMA_SIZE (1024u) - /* ST provided header has incorrect value */ - #undef USB_PMAADDR - #define USB_PMAADDR USB1_PMAADDR - -#elif CFG_TUSB_MCU == OPT_MCU_STM32L4 - #include "stm32l4xx.h" - #define FSDEV_PMA_SIZE (1024u) - -#elif CFG_TUSB_MCU == OPT_MCU_STM32L5 - #include "stm32l5xx.h" - #define FSDEV_PMA_SIZE (1024u) - - #ifndef USB_PMAADDR - #define USB_PMAADDR (USB_BASE + (USB_PMAADDR_NS - USB_BASE_NS)) - #endif - -#else - #error You are using an untested or unimplemented STM32 variant. Please update the driver. - // This includes L1x0, L1x1, L1x2, L4x2 and L4x3, G1x1, G1x3, and G1x4 -#endif - // For purposes of accessing the packet #if ((FSDEV_PMA_SIZE) == 512u) #define FSDEV_PMA_STRIDE (2u) @@ -181,24 +50,24 @@ // The compiler should warn us if we cast it to a non-volatile type? #ifdef FSDEV_BUS_32BIT typedef uint32_t fsdev_bus_t; -static __IO uint32_t * const pma32 = (__IO uint32_t*)USB_PMAADDR; +static volatile uint32_t * const pma32 = (volatile uint32_t*)USB_PMAADDR; #else typedef uint16_t fsdev_bus_t; // Volatile is also needed to prevent the optimizer from changing access to 32-bit (as 32-bit access is forbidden) -static __IO uint16_t * const pma = (__IO uint16_t*)USB_PMAADDR; +static volatile uint16_t * const pma = (volatile uint16_t*)USB_PMAADDR; -TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x) { +TU_ATTR_ALWAYS_INLINE static inline volatile uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x) { size_t total_word_offset = (((USBx)->BTABLE)>>1) + x; total_word_offset *= FSDEV_PMA_STRIDE; return &(pma[total_word_offset]); } -TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) { +TU_ATTR_ALWAYS_INLINE static inline volatile uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) { return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 1u); } -TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) { +TU_ATTR_ALWAYS_INLINE static inline volatile uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) { return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 3u); } #endif @@ -218,10 +87,10 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_aligned_buffer_size(uint16_t si TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wRegValue) { #ifdef FSDEV_BUS_32BIT (void) USBx; - __O uint32_t *reg = (__O uint32_t *)(USB_DRD_BASE + bEpIdx*4); + volatile uint32_t *reg = (volatile uint32_t *)(USB_DRD_BASE + bEpIdx*4); *reg = wRegValue; #else - __O uint16_t *reg = (__O uint16_t *)((&USBx->EP0R) + bEpIdx*2u); + volatile uint16_t *reg = (volatile uint16_t *)((&USBx->EP0R) + bEpIdx*2u); *reg = (uint16_t)wRegValue; #endif } @@ -229,9 +98,9 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, ui TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx) { #ifdef FSDEV_BUS_32BIT (void) USBx; - __I uint32_t *reg = (__I uint32_t *)(USB_DRD_BASE + bEpIdx*4); + volatile const uint32_t *reg = (volatile const uint32_t *)(USB_DRD_BASE + bEpIdx*4); #else - __I uint16_t *reg = (__I uint16_t *)((&USBx->EP0R) + bEpIdx*2u); + volatile const uint16_t *reg = (volatile const uint16_t *)((&USBx->EP0R) + bEpIdx*2u); #endif return *reg; } @@ -283,7 +152,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USB (void) USBx; return (pma32[2*bEpIdx] & 0x03FF0000) >> 16; #else - __I uint16_t *regPtr = pcd_ep_tx_cnt_ptr(USBx, bEpIdx); + volatile const uint16_t *regPtr = pcd_ep_tx_cnt_ptr(USBx, bEpIdx); return *regPtr & 0x3ffU; #endif } @@ -293,7 +162,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USB (void) USBx; return (pma32[2*bEpIdx + 1] & 0x03FF0000) >> 16; #else - __I uint16_t *regPtr = pcd_ep_rx_cnt_ptr(USBx, bEpIdx); + volatile const uint16_t *regPtr = pcd_ep_rx_cnt_ptr(USBx, bEpIdx); return *regPtr & 0x3ffU; #endif } @@ -363,7 +232,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, u (void) USBx; pma32[2*bEpIdx] = (pma32[2*bEpIdx] & ~0x03FF0000u) | ((wCount & 0x3FFu) << 16); #else - __IO uint16_t * reg = pcd_ep_tx_cnt_ptr(USBx, bEpIdx); + volatile uint16_t * reg = pcd_ep_tx_cnt_ptr(USBx, bEpIdx); *reg = (uint16_t) (*reg & (uint16_t) ~0x3FFU) | (wCount & 0x3FFU); #endif } @@ -375,7 +244,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_dbuf1_cnt(USB_TypeDef * U (void) USBx; pma32[2*bEpIdx + 1] = (pma32[2*bEpIdx + 1] & ~0x03FF0000u) | ((wCount & 0x3FFu) << 16); #else - __IO uint16_t * reg = pcd_ep_rx_cnt_ptr(USBx, bEpIdx); + volatile uint16_t * reg = pcd_ep_rx_cnt_ptr(USBx, bEpIdx); *reg = (uint16_t) (*reg & (uint16_t) ~0x3FFU) | (wCount & 0x3FFU); #endif } @@ -387,7 +256,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_blsize_num_blocks(USB_TypeDe (void) USBx; pma32[rxtx_idx] = (pma32[rxtx_idx] & 0x0000FFFFu) | (blocksize << 31) | ((numblocks - blocksize) << 26); #else - __IO uint16_t *pdwReg = pcd_btable_word_ptr(USBx, rxtx_idx*2u + 1u); + volatile uint16_t *pdwReg = pcd_btable_word_ptr(USBx, rxtx_idx*2u + 1u); *pdwReg = (blocksize << 15) | ((numblocks - blocksize) << 10); #endif } @@ -472,13 +341,6 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * return (regVal & USB_EPRX_STAT) >> (12u); } - -/** - * @brief Toggles DTOG_RX / DTOG_TX bit in the endpoint register. - * @param USBx USB peripheral instance register address. - * @param bEpIdx Endpoint Number. - * @retval None - */ TU_ATTR_ALWAYS_INLINE static inline void pcd_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal &= USB_EPREG_MASK; @@ -493,12 +355,6 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32 pcd_set_endpoint(USBx, bEpIdx, regVal); } -/** - * @brief Clears DTOG_RX / DTOG_TX bit in the endpoint register. - * @param USBx USB peripheral instance register address. - * @param bEpIdx Endpoint Number. - * @retval None - */ TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); if((regVal & USB_EP_DTOG_RX) != 0) { @@ -513,12 +369,6 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx, } } -/** - * @brief set & clear EP_KIND bit. - * @param USBx USB peripheral instance register address. - * @param bEpIdx Endpoint Number. - * @retval None - */ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) { uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); regVal |= USB_EP_KIND; @@ -534,18 +384,8 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_ep_kind(USB_TypeDef * USBx, u pcd_set_endpoint(USBx, bEpIdx, regVal); } -// This checks if the device has "LPM" -#if defined(USB_ISTR_L1REQ) -#define USB_ISTR_L1REQ_FORCED (USB_ISTR_L1REQ) -#else -#define USB_ISTR_L1REQ_FORCED ((uint16_t)0x0000U) +#ifdef __cplusplus + } #endif -#define USB_ISTR_ALL_EVENTS (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_WKUP | USB_ISTR_SUSP | \ - USB_ISTR_RESET | USB_ISTR_SOF | USB_ISTR_ESOF | USB_ISTR_L1REQ_FORCED ) - -// Number of endpoints in hardware -// TODO should use TUP_DCD_ENDPOINT_MAX -#define STFSDEV_EP_COUNT (8u) - -#endif /* PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_ */ +#endif diff --git a/src/portable/st/stm32_fsdev/fsdev_stm32.h b/src/portable/st/stm32_fsdev/fsdev_stm32.h new file mode 100644 index 000000000..b3fa11b88 --- /dev/null +++ b/src/portable/st/stm32_fsdev/fsdev_stm32.h @@ -0,0 +1,292 @@ +/* + * The MIT License (MIT) + * + * Copyright(c) N Conrad + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef TUSB_FSDEV_STM32_H +#define TUSB_FSDEV_STM32_H + +#if CFG_TUSB_MCU == OPT_MCU_STM32F0 + #include "stm32f0xx.h" + #define FSDEV_PMA_SIZE (1024u) + // F0x2 models are crystal-less + // All have internal D+ pull-up + // 070RB: 2 x 16 bits/word memory LPM Support, BCD Support + // PMA dedicated to USB (no sharing with CAN) + +#elif CFG_TUSB_MCU == OPT_MCU_STM32F1 + #include "stm32f1xx.h" + #define FSDEV_PMA_SIZE (512u) + // NO internal Pull-ups + // *B, and *C: 2 x 16 bits/word + + // F1 names this differently from the rest + #define USB_CNTR_LPMODE USB_CNTR_LP_MODE + +#elif defined(STM32F302xB) || defined(STM32F302xC) || \ + defined(STM32F303xB) || defined(STM32F303xC) || \ + defined(STM32F373xC) + #include "stm32f3xx.h" + #define FSDEV_PMA_SIZE (512u) + // NO internal Pull-ups + // *B, and *C: 1 x 16 bits/word + // PMA dedicated to USB (no sharing with CAN) + +#elif defined(STM32F302x6) || defined(STM32F302x8) || \ + defined(STM32F302xD) || defined(STM32F302xE) || \ + defined(STM32F303xD) || defined(STM32F303xE) + #include "stm32f3xx.h" + #define FSDEV_PMA_SIZE (1024u) + // NO internal Pull-ups + // *6, *8, *D, and *E: 2 x 16 bits/word LPM Support + // When CAN clock is enabled, USB can use first 768 bytes ONLY. + +#elif CFG_TUSB_MCU == OPT_MCU_STM32L0 + #include "stm32l0xx.h" + #define FSDEV_PMA_SIZE (1024u) + +#elif CFG_TUSB_MCU == OPT_MCU_STM32L1 + #include "stm32l1xx.h" + #define FSDEV_PMA_SIZE (512u) + +#elif CFG_TUSB_MCU == OPT_MCU_STM32G4 + #include "stm32g4xx.h" + #define FSDEV_PMA_SIZE (1024u) + +#elif CFG_TUSB_MCU == OPT_MCU_STM32G0 + #include "stm32g0xx.h" + #define FSDEV_BUS_32BIT + #define FSDEV_PMA_SIZE (2048u) + #undef USB_PMAADDR + #define USB_PMAADDR USB_DRD_PMAADDR + #define USB_TypeDef USB_DRD_TypeDef + #define EP0R CHEP0R + #define USB_EP_CTR_RX USB_EP_VTRX + #define USB_EP_CTR_TX USB_EP_VTTX + #define USB_EP_T_FIELD USB_CHEP_UTYPE + #define USB_EPREG_MASK USB_CHEP_REG_MASK + #define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK + #define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK + #define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1 + #define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2 + #define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1 + #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2 + #define USB_EPRX_STAT USB_CH_RX_VALID + #define USB_EPKIND_MASK USB_EP_KIND_MASK + #define USB USB_DRD_FS + #define USB_CNTR_FRES USB_CNTR_USBRST + #define USB_CNTR_RESUME USB_CNTR_L2RES + #define USB_ISTR_EP_ID USB_ISTR_IDN + #define USB_EPADDR_FIELD USB_CHEP_ADDR + #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY + #define USB_CNTR_FSUSP USB_CNTR_SUSPEN + +#elif CFG_TUSB_MCU == OPT_MCU_STM32H5 + #include "stm32h5xx.h" + #define FSDEV_BUS_32BIT + + #if !defined(USB_DRD_BASE) && defined(USB_DRD_FS_BASE) + #define USB_DRD_BASE USB_DRD_FS_BASE + #endif + + #define FSDEV_PMA_SIZE (2048u) + #undef USB_PMAADDR + #define USB_PMAADDR USB_DRD_PMAADDR + #define USB_TypeDef USB_DRD_TypeDef + #define EP0R CHEP0R + #define USB_EP_CTR_RX USB_EP_VTRX + #define USB_EP_CTR_TX USB_EP_VTTX + #define USB_EP_T_FIELD USB_CHEP_UTYPE + #define USB_EPREG_MASK USB_CHEP_REG_MASK + #define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK + #define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK + #define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1 + #define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2 + #define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1 + #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2 + #define USB_EPRX_STAT USB_CH_RX_VALID + #define USB_EPKIND_MASK USB_EP_KIND_MASK + #define USB USB_DRD_FS + #define USB_CNTR_FRES USB_CNTR_USBRST + #define USB_CNTR_RESUME USB_CNTR_L2RES + #define USB_ISTR_EP_ID USB_ISTR_IDN + #define USB_EPADDR_FIELD USB_CHEP_ADDR + #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY + #define USB_CNTR_FSUSP USB_CNTR_SUSPEN + +#elif CFG_TUSB_MCU == OPT_MCU_STM32WB + #include "stm32wbxx.h" + #define FSDEV_PMA_SIZE (1024u) + /* ST provided header has incorrect value */ + #undef USB_PMAADDR + #define USB_PMAADDR USB1_PMAADDR + +#elif CFG_TUSB_MCU == OPT_MCU_STM32L4 + #include "stm32l4xx.h" + #define FSDEV_PMA_SIZE (1024u) + +#elif CFG_TUSB_MCU == OPT_MCU_STM32L5 + #include "stm32l5xx.h" + #define FSDEV_PMA_SIZE (1024u) + + #ifndef USB_PMAADDR + #define USB_PMAADDR (USB_BASE + (USB_PMAADDR_NS - USB_BASE_NS)) + #endif + +#else + #error You are using an untested or unimplemented STM32 variant. Please update the driver. + // This includes L1x0, L1x1, L1x2, L4x2 and L4x3, G1x1, G1x3, and G1x4 +#endif + +// This checks if the device has "LPM" +#if defined(USB_ISTR_L1REQ) +#define USB_ISTR_L1REQ_FORCED (USB_ISTR_L1REQ) +#else +#define USB_ISTR_L1REQ_FORCED ((uint16_t)0x0000U) +#endif + +#define USB_ISTR_ALL_EVENTS (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_WKUP | USB_ISTR_SUSP | \ + USB_ISTR_RESET | USB_ISTR_SOF | USB_ISTR_ESOF | USB_ISTR_L1REQ_FORCED ) + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ + +#if TU_CHECK_MCU(OPT_MCU_STM32L1) && !defined(USBWakeUp_IRQn) + #define USBWakeUp_IRQn USB_FS_WKUP_IRQn +#endif + +static const IRQn_Type fsdev_irq[] = { + #if TU_CHECK_MCU(OPT_MCU_STM32F0, OPT_MCU_STM32L0, OPT_MCU_STM32L4) + USB_IRQn, + #elif CFG_TUSB_MCU == OPT_MCU_STM32F1 + USB_HP_CAN1_TX_IRQn, + USB_LP_CAN1_RX0_IRQn, + USBWakeUp_IRQn, + #elif CFG_TUSB_MCU == OPT_MCU_STM32F3 + // USB remap handles dcd functions + USB_HP_CAN_TX_IRQn, + USB_LP_CAN_RX0_IRQn, + USBWakeUp_IRQn, + #elif CFG_TUSB_MCU == OPT_MCU_STM32G0 + #ifdef STM32G0B0xx + USB_IRQn, + #else + USB_UCPD1_2_IRQn, + #endif + #elif TU_CHECK_MCU(OPT_MCU_STM32G4, OPT_MCU_STM32L1) + USB_HP_IRQn, + USB_LP_IRQn, + USBWakeUp_IRQn, + #elif CFG_TUSB_MCU == OPT_MCU_STM32H5 + USB_DRD_FS_IRQn, + #elif CFG_TUSB_MCU == OPT_MCU_STM32L5 + USB_FS_IRQn, + #elif CFG_TUSB_MCU == OPT_MCU_STM32WB + USB_HP_IRQn, + USB_LP_IRQn, + #else + #error Unknown arch in USB driver + #endif +}; +enum { FSDEV_IRQ_NUM = TU_ARRAY_SIZE(fsdev_irq) }; + +void dcd_int_enable(uint8_t rhport) { + (void)rhport; + + // forces write to RAM before allowing ISR to execute + __DSB(); __ISB(); + + #if CFG_TUSB_MCU == OPT_MCU_STM32F3 && defined(SYSCFG_CFGR1_USB_IT_RMP) + // Some STM32F302/F303 devices allow to remap the USB interrupt vectors from + // shared USB/CAN IRQs to separate CAN and USB IRQs. + // This dynamically checks if this remap is active to enable the right IRQs. + if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) { + NVIC_EnableIRQ(USB_HP_IRQn); + NVIC_EnableIRQ(USB_LP_IRQn); + NVIC_EnableIRQ(USBWakeUp_RMP_IRQn); + } else + #endif + { + for (uint8_t i = 0; i < FSDEV_IRQ_NUM; i++) { + NVIC_EnableIRQ(fsdev_irq[i]); + } + } +} + +void dcd_int_disable(uint8_t rhport) { + (void)rhport; + + #if CFG_TUSB_MCU == OPT_MCU_STM32F3 && defined(SYSCFG_CFGR1_USB_IT_RMP) + // Some STM32F302/F303 devices allow to remap the USB interrupt vectors from + // shared USB/CAN IRQs to separate CAN and USB IRQs. + // This dynamically checks if this remap is active to enable the right IRQs. + if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) { + NVIC_DisableIRQ(USB_HP_IRQn); + NVIC_DisableIRQ(USB_LP_IRQn); + NVIC_DisableIRQ(USBWakeUp_RMP_IRQn); + } else + #endif + { + for (uint8_t i = 0; i < FSDEV_IRQ_NUM; i++) { + NVIC_DisableIRQ(fsdev_irq[i]); + } + } + + // CMSIS has a membar after disabling interrupts +} + +// Define only on MCU with internal pull-up. BSP can define on MCU without internal PU. +#if defined(USB_BCDR_DPPU) + +void dcd_disconnect(uint8_t rhport) { + (void)rhport; + USB->BCDR &= ~(USB_BCDR_DPPU); +} + +void dcd_connect(uint8_t rhport) { + (void)rhport; + USB->BCDR |= USB_BCDR_DPPU; +} + +#elif defined(SYSCFG_PMC_USB_PU) // works e.g. on STM32L151 + +void dcd_disconnect(uint8_t rhport) { + (void)rhport; + SYSCFG->PMC &= ~(SYSCFG_PMC_USB_PU); +} + +void dcd_connect(uint8_t rhport) { + (void)rhport; + SYSCFG->PMC |= SYSCFG_PMC_USB_PU; +} +#endif + + +#endif /* TUSB_FSDEV_STM32_H */ diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index 692096fc8..dbcd586c5 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -1195,4 +1195,25 @@ void dcd_int_handler(uint8_t rhport) { // } } +#if defined(TUP_USBIP_DWC2_TEST_MODE) && CFG_TUD_TEST_MODE + +bool dcd_check_test_mode_support(test_mode_t test_selector) { + // Check if test mode selector is unsupported + if (TEST_FORCE_ENABLE < test_selector || TEST_J > test_selector) { + return false; + } + + return true; +} + +void dcd_enter_test_mode(uint8_t rhport, test_mode_t test_selector) { + // Get port address... + dwc2_regs_t* dwc2 = DWC2_REG(rhport); + + // Enable the test mode + dwc2->dctl = (dwc2->dctl & ~DCTL_TCTL_Msk) | (test_selector << DCTL_TCTL_Pos); +} + +#endif /* TUP_USBIP_DWC2_TEST_MODE && CFG_TUD_TEST_MODE */ + #endif diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h index c15771237..cb694b326 100644 --- a/src/portable/synopsys/dwc2/dwc2_type.h +++ b/src/portable/synopsys/dwc2/dwc2_type.h @@ -1,17 +1,34 @@ -/** - * @author MCD Application Team - * Ha Thach (tinyusb.org) - * - * @attention - * - * <h2><center>© Copyright (c) 2019 STMicroelectronics. +/* + * The MIT License (MIT) + * + * Copyright (c) 2024, hathach (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 + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +/** <h2><center>© Copyright (c) 2019 STMicroelectronics. * All rights reserved.</center></h2> * * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause - * */ #ifndef _TUSB_DWC2_TYPES_H_ diff --git a/src/portable/wch/ch32_usbfs_reg.h b/src/portable/wch/ch32_usbfs_reg.h new file mode 100644 index 000000000..0a50a6169 --- /dev/null +++ b/src/portable/wch/ch32_usbfs_reg.h @@ -0,0 +1,111 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Matthew Tran + * Copyright (c) 2024 hathach + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef USB_CH32_USBFS_REG_H +#define USB_CH32_USBFS_REG_H + +#if CFG_TUSB_MCU == OPT_MCU_CH32V307 + #include <ch32v30x.h> + #define USBHD_IRQn OTG_FS_IRQn + +#elif CFG_TUSB_MCU == OPT_MCU_CH32V20X + #include <ch32v20x.h> + +#elif CFG_TUSB_MCU == OPT_MCU_CH32F20X + #include <ch32f20x.h> +#endif + +// CTRL +#define USBFS_CTRL_DMA_EN (1 << 0) +#define USBFS_CTRL_CLR_ALL (1 << 1) +#define USBFS_CTRL_RESET_SIE (1 << 2) +#define USBFS_CTRL_INT_BUSY (1 << 3) +#define USBFS_CTRL_SYS_CTRL (1 << 4) +#define USBFS_CTRL_DEV_PUEN (1 << 5) +#define USBFS_CTRL_LOW_SPEED (1 << 6) +#define USBFS_CTRL_HOST_MODE (1 << 7) + +// INT_EN +#define USBFS_INT_EN_BUS_RST (1 << 0) +#define USBFS_INT_EN_DETECT (1 << 0) +#define USBFS_INT_EN_TRANSFER (1 << 1) +#define USBFS_INT_EN_SUSPEND (1 << 2) +#define USBFS_INT_EN_HST_SOF (1 << 3) +#define USBFS_INT_EN_FIFO_OV (1 << 4) +#define USBFS_INT_EN_DEV_NAK (1 << 6) +#define USBFS_INT_EN_DEV_SOF (1 << 7) + +// INT_FG +#define USBFS_INT_FG_BUS_RST (1 << 0) +#define USBFS_INT_FG_DETECT (1 << 0) +#define USBFS_INT_FG_TRANSFER (1 << 1) +#define USBFS_INT_FG_SUSPEND (1 << 2) +#define USBFS_INT_FG_HST_SOF (1 << 3) +#define USBFS_INT_FG_FIFO_OV (1 << 4) +#define USBFS_INT_FG_SIE_FREE (1 << 5) +#define USBFS_INT_FG_TOG_OK (1 << 6) +#define USBFS_INT_FG_IS_NAK (1 << 7) + +// INT_ST +#define USBFS_INT_ST_MASK_UIS_ENDP(x) (((x) >> 0) & 0x0F) +#define USBFS_INT_ST_MASK_UIS_TOKEN(x) (((x) >> 4) & 0x03) + +// UDEV_CTRL +#define USBFS_UDEV_CTRL_PORT_EN (1 << 0) +#define USBFS_UDEV_CTRL_GP_BIT (1 << 1) +#define USBFS_UDEV_CTRL_LOW_SPEED (1 << 2) +#define USBFS_UDEV_CTRL_DM_PIN (1 << 4) +#define USBFS_UDEV_CTRL_DP_PIN (1 << 5) +#define USBFS_UDEV_CTRL_PD_DIS (1 << 7) + +// TX_CTRL +#define USBFS_EP_T_RES_MASK (3 << 0) +#define USBFS_EP_T_TOG (1 << 2) +#define USBFS_EP_T_AUTO_TOG (1 << 3) + +#define USBFS_EP_T_RES_ACK (0 << 0) +#define USBFS_EP_T_RES_NYET (1 << 0) +#define USBFS_EP_T_RES_NAK (2 << 0) +#define USBFS_EP_T_RES_STALL (3 << 0) + +// RX_CTRL +#define USBFS_EP_R_RES_MASK (3 << 0) +#define USBFS_EP_R_TOG (1 << 2) +#define USBFS_EP_R_AUTO_TOG (1 << 3) + +#define USBFS_EP_R_RES_ACK (0 << 0) +#define USBFS_EP_R_RES_NYET (1 << 0) +#define USBFS_EP_R_RES_NAK (2 << 0) +#define USBFS_EP_R_RES_STALL (3 << 0) + +// token PID +#define PID_OUT 0 +#define PID_SOF 1 +#define PID_IN 2 +#define PID_SETUP 3 + +#endif // USB_CH32_USBFS_REG_H diff --git a/src/portable/wch/ch32_usbhs_reg.h b/src/portable/wch/ch32_usbhs_reg.h index 9b956231f..130e4f223 100644 --- a/src/portable/wch/ch32_usbhs_reg.h +++ b/src/portable/wch/ch32_usbhs_reg.h @@ -1,10 +1,37 @@ -#ifndef _USB_CH32_USBHS_REG_H -#define _USB_CH32_USBHS_REG_H +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Matthew Tran + * Copyright (c) 2024 hathach + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ -#if (CFG_TUSB_MCU == OPT_MCU_CH32V307) -#include <ch32v30x.h> -#elif (CFG_TUSB_MCU == OPT_MCU_CH32F20X) -#include <ch32f20x.h> +#ifndef USB_CH32_USBHS_REG_H +#define USB_CH32_USBHS_REG_H + +#if CFG_TUSB_MCU == OPT_MCU_CH32V307 + #include <ch32v30x.h> +#elif CFG_TUSB_MCU == OPT_MCU_CH32F20X + #include <ch32f20x.h> #endif /******************* GLOBAL ******************/ @@ -36,8 +63,13 @@ // USB DEV AD #define USBHS_DEV_AD_OFFSET 0x03 + // USB FRAME_NO #define USBHS_FRAME_NO_OFFSET 0x04 +#define USBHS_FRAME_NO_NUM_MASK (0x7FF) +#define USBHS_FRAME_NO_MICROFRAME_SHIFT (11) +#define USBHS_FRAME_NO_MICROFRAME_MASK (0x7 << USBHS_FRAME_NO_MICROFRAME_SHIFT) + // USB SUSPEND #define USBHS_SUSPEND_OFFSET 0x06 #define USBHS_DEV_REMOTE_WAKEUP (1 << 2) @@ -47,7 +79,10 @@ // USB SPEED TYPE #define USBHS_SPEED_TYPE_OFFSET 0x08 -#define USBSPEED_MASK (0x03) +#define USBHS_SPEED_TYPE_MASK 0x03 +#define USBHS_SPEED_TYPE_FULL 0 +#define USBHS_SPEED_TYPE_HIGH 1 +#define USBHS_SPEED_TYPE_LOW 2 // USB_MIS_ST #define USBHS_MIS_ST_OFFSET 0x09 @@ -72,12 +107,16 @@ #define USBHS_ISO_ACT_FLAG (1 << 6) // INT_ST -#define USBHS_INT_ST_OFFSET 0x0B -#define USBHS_DEV_UIS_IS_NAK (1 << 7) -#define USBHS_DEV_UIS_TOG_OK (1 << 6) -#define MASK_UIS_TOKEN (3 << 4) -#define MASK_UIS_ENDP (0x0F) -#define MASK_UIS_H_RES (0x0F) +#define USBHS_INT_ST_OFFSET 0x0B +#define USBHS_DEV_UIS_IS_NAK (1 << 7) +#define USBHS_DEV_UIS_TOG_OK (1 << 6) +#define MASK_UIS_TOKEN (3 << 4) +#define USBHS_TOKEN_PID_OUT (0 << 4) +#define USBHS_TOKEN_PID_SOF (1 << 4) +#define USBHS_TOKEN_PID_IN (2 << 4) +#define USBHS_TOKEN_PID_SETUP (3 << 4) +#define MASK_UIS_ENDP (0x0F) +#define MASK_UIS_H_RES (0x0F) #define USBHS_TOGGLE_OK (0x40) #define USBHS_HOST_RES (0x0f) @@ -340,10 +379,5 @@ #define USBHS_UH_T_TOG_AUTO (1 << 5) #define USBHS_UH_T_DATA_NO (1 << 6) -// 00: OUT, 01:SOF, 10:IN, 11:SETUP -#define PID_OUT 0 -#define PID_SOF 1 -#define PID_IN 2 -#define PID_SETUP 3 #endif diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c new file mode 100644 index 000000000..9ed370b40 --- /dev/null +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -0,0 +1,344 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Matthew Tran + * Copyright (c) 2024 hathach + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if CFG_TUD_ENABLED && defined(TUP_USBIP_WCH_USBFS) && CFG_TUD_WCH_USBIP_USBFS + +#include "device/dcd.h" +#include "ch32_usbfs_reg.h" + +/* private defines */ +#define EP_MAX (8) + +#define EP_DMA(ep) ((&USBOTG_FS->UEP0_DMA)[ep]) +#define EP_TX_LEN(ep) ((&USBOTG_FS->UEP0_TX_LEN)[2 * ep]) +#define EP_TX_CTRL(ep) ((&USBOTG_FS->UEP0_TX_CTRL)[4 * ep]) +#define EP_RX_CTRL(ep) ((&USBOTG_FS->UEP0_RX_CTRL)[4 * ep]) + +/* private data */ +struct usb_xfer { + bool valid; + uint8_t* buffer; + size_t len; + size_t processed_len; + size_t max_size; +}; + +static struct { + bool ep0_tog; + bool isochronous[EP_MAX]; + struct usb_xfer xfer[EP_MAX][2]; + TU_ATTR_ALIGNED(4) uint8_t buffer[EP_MAX][2][64]; + TU_ATTR_ALIGNED(4) struct { + // OUT transfers >64 bytes will overwrite queued IN data! + uint8_t out[64]; + uint8_t in[1023]; + uint8_t pad; + } ep3_buffer; +} data; + +/* private helpers */ +static void update_in(uint8_t rhport, uint8_t ep, bool force) { + struct usb_xfer* xfer = &data.xfer[ep][TUSB_DIR_IN]; + if (xfer->valid) { + if (force || xfer->len) { + size_t len = TU_MIN(xfer->max_size, xfer->len); + if (ep == 0) { + memcpy(data.buffer[ep][TUSB_DIR_OUT], xfer->buffer, len); // ep0 uses same chunk + } else if (ep == 3) { + memcpy(data.ep3_buffer.in, xfer->buffer, len); + } else { + memcpy(data.buffer[ep][TUSB_DIR_IN], xfer->buffer, len); + } + xfer->buffer += len; + xfer->len -= len; + xfer->processed_len += len; + + EP_TX_LEN(ep) = len; + if (ep == 0) { + EP_TX_CTRL(0) = USBFS_EP_T_RES_ACK | (data.ep0_tog ? USBFS_EP_T_TOG : 0); + data.ep0_tog = !data.ep0_tog; + } else if (data.isochronous[ep]) { + EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_NYET; + } else { + EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_ACK; + } + } else { + xfer->valid = false; + EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_NAK; + dcd_event_xfer_complete( + rhport, ep | TUSB_DIR_IN_MASK, xfer->processed_len, + XFER_RESULT_SUCCESS, true); + } + } +} + +static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { + struct usb_xfer* xfer = &data.xfer[ep][TUSB_DIR_OUT]; + if (xfer->valid) { + size_t len = TU_MIN(xfer->max_size, TU_MIN(xfer->len, rx_len)); + if (ep == 3) { + memcpy(xfer->buffer, data.ep3_buffer.out, len); + } else { + memcpy(xfer->buffer, data.buffer[ep][TUSB_DIR_OUT], len); + } + xfer->buffer += len; + xfer->len -= len; + xfer->processed_len += len; + + if (xfer->len == 0 || len < xfer->max_size) { + xfer->valid = false; + dcd_event_xfer_complete(rhport, ep, xfer->processed_len, XFER_RESULT_SUCCESS, true); + } + + if (ep == 0) { + EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; + } + } +} + +/* public functions */ +void dcd_init(uint8_t rhport) { + // init registers + USBOTG_FS->BASE_CTRL = USBFS_CTRL_SYS_CTRL | USBFS_CTRL_INT_BUSY | USBFS_CTRL_DMA_EN; + USBOTG_FS->UDEV_CTRL = USBFS_UDEV_CTRL_PD_DIS | USBFS_UDEV_CTRL_PORT_EN; + USBOTG_FS->DEV_ADDR = 0x00; + + USBOTG_FS->INT_FG = 0xFF; + USBOTG_FS->INT_EN = USBFS_INT_EN_BUS_RST | USBFS_INT_EN_TRANSFER | USBFS_INT_EN_SUSPEND; + + // setup endpoint 0 + EP_DMA(0) = (uint32_t) &data.buffer[0][0]; + EP_TX_LEN(0) = 0; + EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK; + EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; + + // enable other endpoints but NAK everything + USBOTG_FS->UEP4_1_MOD = 0xCC; + USBOTG_FS->UEP2_3_MOD = 0xCC; + USBOTG_FS->UEP5_6_MOD = 0xCC; + USBOTG_FS->UEP7_MOD = 0x0C; + + for (uint8_t ep = 1; ep < EP_MAX; ep++) { + EP_DMA(ep) = (uint32_t) &data.buffer[ep][0]; + EP_TX_LEN(ep) = 0; + EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK; + EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NAK; + } + EP_DMA(3) = (uint32_t) &data.ep3_buffer.out[0]; + + dcd_connect(rhport); +} + +void dcd_int_handler(uint8_t rhport) { + (void) rhport; + uint8_t status = USBOTG_FS->INT_FG; + if (status & USBFS_INT_FG_TRANSFER) { + uint8_t ep = USBFS_INT_ST_MASK_UIS_ENDP(USBOTG_FS->INT_ST); + uint8_t token = USBFS_INT_ST_MASK_UIS_TOKEN(USBOTG_FS->INT_ST); + + switch (token) { + case PID_OUT: { + uint16_t rx_len = USBOTG_FS->RX_LEN; + update_out(rhport, ep, rx_len); + break; + } + + case PID_IN: + update_in(rhport, ep, false); + break; + + case PID_SETUP: + // setup clears stall + EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK; + EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; + + data.ep0_tog = true; + dcd_event_setup_received(rhport, &data.buffer[0][TUSB_DIR_OUT][0], true); + break; + } + + USBOTG_FS->INT_FG = USBFS_INT_FG_TRANSFER; + } else if (status & USBFS_INT_FG_BUS_RST) { + data.ep0_tog = true; + data.xfer[0][TUSB_DIR_OUT].max_size = 64; + data.xfer[0][TUSB_DIR_IN].max_size = 64; + + dcd_event_bus_signal(rhport, DCD_EVENT_BUS_RESET, true); + + USBOTG_FS->DEV_ADDR = 0x00; + EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; + + USBOTG_FS->INT_FG = USBFS_INT_FG_BUS_RST; + } else if (status & USBFS_INT_FG_SUSPEND) { + dcd_event_t event = {.rhport = rhport, .event_id = DCD_EVENT_SUSPEND}; + dcd_event_handler(&event, true); + USBOTG_FS->INT_FG = USBFS_INT_FG_SUSPEND; + } +} + +void dcd_int_enable(uint8_t rhport) { + (void) rhport; + NVIC_EnableIRQ(USBHD_IRQn); +} + +void dcd_int_disable(uint8_t rhport) { + (void) rhport; + NVIC_DisableIRQ(USBHD_IRQn); +} + +void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { + (void) dev_addr; + dcd_edpt_xfer(rhport, 0x80, NULL, 0); // zlp status response +} + +void dcd_remote_wakeup(uint8_t rhport) { + (void) rhport; + // TODO optional +} + +void dcd_connect(uint8_t rhport) { + (void) rhport; + USBOTG_FS->BASE_CTRL |= USBFS_CTRL_DEV_PUEN; +} + +void dcd_disconnect(uint8_t rhport) { + (void) rhport; + USBOTG_FS->BASE_CTRL &= ~USBFS_CTRL_DEV_PUEN; +} + +void dcd_sof_enable(uint8_t rhport, bool en) { + (void) rhport; + (void) en; + + // TODO implement later +} + +void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* request) { + (void) rhport; + if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE && + request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && + request->bRequest == TUSB_REQ_SET_ADDRESS) { + USBOTG_FS->DEV_ADDR = (uint8_t) request->wValue; + } + EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK; + EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; +} + +bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) { + (void) rhport; + uint8_t ep = tu_edpt_number(desc_ep->bEndpointAddress); + uint8_t dir = tu_edpt_dir(desc_ep->bEndpointAddress); + TU_ASSERT(ep < EP_MAX); + + data.isochronous[ep] = desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS; + data.xfer[ep][dir].max_size = tu_edpt_packet_size(desc_ep); + + if (ep != 0) { + if (dir == TUSB_DIR_OUT) { + if (data.isochronous[ep]) { + EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NYET; + } else { + EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_ACK; + } + } else { + EP_TX_LEN(ep) = 0; + EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK; + } + } + return true; +} + +void dcd_edpt_close_all(uint8_t rhport) { + (void) rhport; + // TODO optional +} + +void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { + (void) rhport; + (void) ep_addr; + // TODO optional +} + +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) { + (void) rhport; + uint8_t ep = tu_edpt_number(ep_addr); + uint8_t dir = tu_edpt_dir(ep_addr); + + struct usb_xfer* xfer = &data.xfer[ep][dir]; + dcd_int_disable(rhport); + xfer->valid = true; + xfer->buffer = buffer; + xfer->len = total_bytes; + xfer->processed_len = 0; + dcd_int_enable(rhport); + + if (dir == TUSB_DIR_IN) { + update_in(rhport, ep, true); + } + return true; +} + +void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { + (void) rhport; + uint8_t ep = tu_edpt_number(ep_addr); + uint8_t dir = tu_edpt_dir(ep_addr); + if (ep == 0) { + if (dir == TUSB_DIR_OUT) { + EP_RX_CTRL(0) = USBFS_EP_R_RES_STALL; + } else { + EP_TX_LEN(0) = 0; + EP_TX_CTRL(0) = USBFS_EP_T_RES_STALL; + } + } else { + if (dir == TUSB_DIR_OUT) { + EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | USBFS_EP_R_RES_STALL; + } else { + EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~USBFS_EP_T_RES_MASK) | USBFS_EP_T_RES_STALL; + } + } +} + +void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { + (void) rhport; + uint8_t ep = tu_edpt_number(ep_addr); + uint8_t dir = tu_edpt_dir(ep_addr); + if (ep == 0) { + if (dir == TUSB_DIR_OUT) { + EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; + } + } else { + if (dir == TUSB_DIR_OUT) { + EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~(USBFS_EP_R_RES_MASK | USBFS_EP_R_TOG)) | USBFS_EP_R_RES_ACK; + } else { + EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK | USBFS_EP_T_TOG)) | USBFS_EP_T_RES_NAK; + } + } +} + +#endif diff --git a/src/portable/wch/dcd_ch32_usbhs.c b/src/portable/wch/dcd_ch32_usbhs.c index 68e2179e9..622f9c508 100644 --- a/src/portable/wch/dcd_ch32_usbhs.c +++ b/src/portable/wch/dcd_ch32_usbhs.c @@ -2,6 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2022 Greg Davill + * Copyright (c) 2023 Denis Krasutski * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,379 +27,394 @@ #include "tusb_option.h" -#if CFG_TUD_ENABLED && ((CFG_TUSB_MCU == OPT_MCU_CH32V307) || (CFG_TUSB_MCU == OPT_MCU_CH32F20X)) -#include "device/dcd.h" - +#if CFG_TUD_ENABLED && defined(TUP_USBIP_WCH_USBHS) && CFG_TUD_WCH_USBIP_USBHS #include "ch32_usbhs_reg.h" +#include "device/dcd.h" // Max number of bi-directional endpoints including EP0 -#define EP_MAX 16 +#define EP_MAX 16 typedef struct { - uint8_t *buffer; - // tu_fifo_t * ff; // TODO support dcd_edpt_xfer_fifo API - uint16_t total_len; - uint16_t queued_len; - uint16_t max_size; - bool short_packet; + uint8_t* buffer; + uint16_t total_len; + uint16_t queued_len; + uint16_t max_size; + bool is_last_packet; + bool is_iso; } xfer_ctl_t; +typedef enum { + EP_RESPONSE_ACK, + EP_RESPONSE_NAK, +} ep_response_list_t; + #define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir] static xfer_ctl_t xfer_status[EP_MAX][2]; -#define EP_TX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_TX_LEN) + (ep)*2) -#define EP_TX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_TX_CTRL) + (ep)*4) -#define EP_RX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_RX_CTRL) + (ep)*4) -#define EP_RX_MAX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_MAX_LEN) + (ep)*2) +#define EP_TX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_TX_LEN) + (ep) * 2) +#define EP_TX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_TX_CTRL) + (ep) * 4) +#define EP_RX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_RX_CTRL) + (ep) * 4) +#define EP_RX_MAX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_MAX_LEN) + (ep) * 2) #define EP_TX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_TX_DMA) + (ep - 1)) #define EP_RX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_RX_DMA) + (ep - 1)) /* Endpoint Buffer */ -TU_ATTR_ALIGNED(4) uint8_t EP0_DatabufHD[64]; // ep0(64) +TU_ATTR_ALIGNED(4) static uint8_t ep0_buffer[CFG_TUD_ENDPOINT0_SIZE]; + +static void ep_set_response_and_toggle(uint8_t ep_num, tusb_dir_t ep_dir, ep_response_list_t response_type) { + if (ep_dir == TUSB_DIR_IN) { + uint8_t response = (response_type == EP_RESPONSE_ACK) ? USBHS_EP_T_RES_ACK : USBHS_EP_T_RES_NAK; + if (ep_num == 0) { + if (response_type == EP_RESPONSE_ACK) { + if (EP_TX_LEN(ep_num) == 0) { + EP_TX_CTRL(ep_num) |= USBHS_EP_T_TOG_1; + } else { + EP_TX_CTRL(ep_num) ^= USBHS_EP_T_TOG_1; + } + } + } + if (xfer_status[ep_num][TUSB_DIR_IN].is_iso == true) { + EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG; + } else { + EP_TX_CTRL(ep_num) = (EP_TX_CTRL(ep_num) & ~(USBHS_EP_T_RES_MASK)) | response; + } + } else { + uint8_t response = (response_type == EP_RESPONSE_ACK) ? USBHS_EP_R_RES_ACK : USBHS_EP_R_RES_NAK; + if (ep_num == 0) { + if (response_type == EP_RESPONSE_ACK) { + if (xfer_status[ep_num][TUSB_DIR_OUT].queued_len == 0) { + EP_RX_CTRL(ep_num) |= USBHS_EP_R_TOG_1; + } + } else { + EP_RX_CTRL(ep_num) ^= USBHS_EP_R_TOG_1; + } + } + EP_RX_CTRL(ep_num) = (EP_RX_CTRL(ep_num) & ~(USBHS_EP_R_RES_MASK)) | response; + } +} + +static void xfer_data_packet(uint8_t ep_num, tusb_dir_t ep_dir, xfer_ctl_t* xfer) { + if (ep_dir == TUSB_DIR_IN) { + uint16_t remaining = xfer->total_len - xfer->queued_len; + uint16_t next_tx_size = TU_MIN(remaining, xfer->max_size); + + if (ep_num == 0) { + memcpy(ep0_buffer, &xfer->buffer[xfer->queued_len], next_tx_size); + } else { + EP_TX_DMA_ADDR(ep_num) = (uint32_t) &xfer->buffer[xfer->queued_len]; + } + + EP_TX_LEN(ep_num) = next_tx_size; + xfer->queued_len += next_tx_size; + if (xfer->queued_len == xfer->total_len) { + xfer->is_last_packet = true; + } + if (xfer->is_iso == true) { + /* Enable EP to generate ISA_ACT interrupt */ + USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << ep_num); + } + } else { /* TUSB_DIR_OUT */ + uint16_t left_to_receive = xfer->total_len - xfer->queued_len; + uint16_t max_possible_rx_size = TU_MIN(xfer->max_size, left_to_receive); -volatile uint8_t USBHS_Dev_Endp0_Tog = 0x01; + if (max_possible_rx_size == left_to_receive) { + xfer->is_last_packet = true; + } + + if (ep_num > 0) { + EP_RX_DMA_ADDR(ep_num) = (uint32_t) &xfer->buffer[xfer->queued_len]; + EP_RX_MAX_LEN(ep_num) = max_possible_rx_size; + } + } + ep_set_response_and_toggle(ep_num, ep_dir, USBHS_EP_R_RES_ACK); +} void dcd_init(uint8_t rhport) { - (void)rhport; + (void) rhport; - memset(&xfer_status, 0, sizeof(xfer_status)); + memset(&xfer_status, 0, sizeof(xfer_status)); - USBHSD->HOST_CTRL = 0x00; - USBHSD->HOST_CTRL = USBHS_PHY_SUSPENDM; + USBHSD->HOST_CTRL = 0x00; + USBHSD->HOST_CTRL = USBHS_PHY_SUSPENDM; - USBHSD->CONTROL = 0; + USBHSD->CONTROL = 0; #if TUD_OPT_HIGH_SPEED - USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_HIGH_SPEED; + USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_HIGH_SPEED; #else - #error OPT_MODE_FULL_SPEED not currently supported on CH32 - USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_FULL_SPEED; + #error OPT_MODE_FULL_SPEED not currently supported on CH32 + USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_FULL_SPEED; #endif - USBHSD->INT_EN = 0; - USBHSD->INT_EN = USBHS_SETUP_ACT_EN | USBHS_TRANSFER_EN | USBHS_DETECT_EN | USBHS_SUSPEND_EN; - - /* ALL endpoint enable */ - USBHSD->ENDP_CONFIG = 0xffffffff; - - USBHSD->ENDP_CONFIG = USBHS_EP0_T_EN | USBHS_EP0_R_EN; - USBHSD->ENDP_TYPE = 0x00; - USBHSD->BUF_MODE = 0x00; + USBHSD->INT_EN = 0; + USBHSD->INT_EN = USBHS_SETUP_ACT_EN | USBHS_TRANSFER_EN | USBHS_BUS_RST_EN | USBHS_SUSPEND_EN | USBHS_ISO_ACT_EN; - USBHSD->UEP0_MAX_LEN = 64; + USBHSD->ENDP_CONFIG = USBHS_EP0_T_EN | USBHS_EP0_R_EN; + USBHSD->ENDP_TYPE = 0x00; + USBHSD->BUF_MODE = 0x00; - USBHSD->UEP0_DMA = (uint32_t)EP0_DatabufHD; + for (int ep = 0; ep < EP_MAX; ep++) { + EP_TX_LEN(ep) = 0; + EP_TX_CTRL(ep) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK; + EP_RX_CTRL(ep) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK; - USBHSD->UEP0_TX_LEN = 0; - USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_NAK; - USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK; + EP_RX_MAX_LEN(ep) = 0; + } - for (int ep = 1; ep < EP_MAX; ep++) { - EP_TX_LEN(ep) = 0; - EP_TX_CTRL(ep) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK; - EP_RX_CTRL(ep) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK; + USBHSD->UEP0_DMA = (uint32_t) ep0_buffer; + USBHSD->UEP0_MAX_LEN = CFG_TUD_ENDPOINT0_SIZE; + xfer_status[0][TUSB_DIR_OUT].max_size = CFG_TUD_ENDPOINT0_SIZE; + xfer_status[0][TUSB_DIR_IN].max_size = CFG_TUD_ENDPOINT0_SIZE; - EP_RX_MAX_LEN(ep) = 512; - } - - USBHSD->DEV_AD = 0; - USBHSD->CONTROL |= USBHS_DEV_PU_EN; + USBHSD->DEV_AD = 0; + USBHSD->CONTROL |= USBHS_DEV_PU_EN; } void dcd_int_enable(uint8_t rhport) { - (void)rhport; - - NVIC_EnableIRQ(USBHS_IRQn); + (void) rhport; + NVIC_EnableIRQ(USBHS_IRQn); } void dcd_int_disable(uint8_t rhport) { - (void)rhport; - - NVIC_DisableIRQ(USBHS_IRQn); + (void) rhport; + NVIC_DisableIRQ(USBHS_IRQn); } void dcd_edpt_close_all(uint8_t rhport) { - (void)rhport; + (void) rhport; + + for (size_t ep = 1; ep < EP_MAX; ep++) { + EP_TX_LEN(ep) = 0; + EP_TX_CTRL(ep) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK; + EP_RX_CTRL(ep) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK; + + EP_RX_MAX_LEN(ep) = 0; + } + + USBHSD->ENDP_CONFIG = USBHS_EP0_T_EN | USBHS_EP0_R_EN; } void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { - (void)dev_addr; + (void) dev_addr; - // Response with zlp status - dcd_edpt_xfer(rhport, 0x80, NULL, 0); + // Response with zlp status + dcd_edpt_xfer(rhport, 0x80, NULL, 0); } -void dcd_remote_wakeup(uint8_t rhport) -{ +void dcd_remote_wakeup(uint8_t rhport) { (void) rhport; } -void dcd_sof_enable(uint8_t rhport, bool en) -{ - (void) rhport; - if (en) { - USBHSD->INT_EN |= USBHS_SOF_ACT_EN; - } else { - USBHSD->INT_EN &= ~(USBHS_SOF_ACT_EN); - } +void dcd_sof_enable(uint8_t rhport, bool en) { + (void) rhport; + if (en) { + USBHSD->INT_EN |= USBHS_SOF_ACT_EN; + } else { + USBHSD->INT_EN &= ~(USBHS_SOF_ACT_EN); + } } -void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *request) { - (void)rhport; +void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* request) { + (void) rhport; - if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE && - request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && - request->bRequest == TUSB_REQ_SET_ADDRESS) { - USBHSD->DEV_AD = (uint8_t)request->wValue; - } + if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE && + request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && + request->bRequest == TUSB_REQ_SET_ADDRESS) { + USBHSD->DEV_AD = (uint8_t) request->wValue; + } - EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK; - EP_RX_CTRL(0) = USBHS_EP_R_RES_ACK; + EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; + EP_RX_CTRL(0) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0; } -bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_edpt) { - (void)rhport; - - uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress); - uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress); +bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) { + (void) rhport; - TU_ASSERT(epnum < EP_MAX); + uint8_t const ep_num = tu_edpt_number(desc_edpt->bEndpointAddress); + tusb_dir_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress); - xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, dir); - xfer->max_size = tu_edpt_packet_size(desc_edpt); - - if (epnum != 0) { - if (tu_edpt_dir(desc_edpt->bEndpointAddress) == TUSB_DIR_OUT) { - EP_RX_CTRL(epnum) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_ACK; - } else { - EP_TX_LEN(epnum) = 0; - EP_TX_CTRL(epnum) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; - } - } + TU_ASSERT(ep_num < EP_MAX); + if (ep_num == 0) { return true; -} - -int usbd_ep_close(const uint8_t ep) { - (void)ep; - - return 0; -} -void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { - (void)rhport; + } - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + xfer_ctl_t* xfer = XFER_CTL_BASE(ep_num, dir); + xfer->max_size = tu_edpt_packet_size(desc_edpt); - if (epnum == 0) { - if (dir == TUSB_DIR_OUT) { - USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_STALL; - } else { - USBHSD->UEP0_TX_LEN = 0; - USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_STALL; - } - } else { - if (dir == TUSB_DIR_OUT) { - EP_RX_CTRL(epnum) = (EP_RX_CTRL(epnum) & ~USBHS_EP_R_RES_MASK) | USBHS_EP_R_RES_STALL; - - } else { - EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~USBHS_EP_T_RES_MASK) | USBHS_EP_T_RES_STALL; - } + xfer->is_iso = (desc_edpt->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS); + if (dir == TUSB_DIR_OUT) { + USBHSD->ENDP_CONFIG |= (USBHS_EP0_R_EN << ep_num); + EP_RX_CTRL(ep_num) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK; + if (xfer->is_iso == true) { + USBHSD->ENDP_TYPE |= (USBHS_EP0_R_TYP << ep_num); } -} - -void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { - (void)rhport; - - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); - - if (epnum == 0) { - if (dir == TUSB_DIR_OUT) { - USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK; - } else { - } + EP_RX_MAX_LEN(ep_num) = xfer->max_size; + } else { + if (xfer->is_iso == true) { + USBHSD->ENDP_TYPE |= (USBHS_EP0_T_TYP << ep_num); } else { - if (dir == TUSB_DIR_OUT) { - EP_RX_CTRL(epnum) = (EP_RX_CTRL(epnum) & ~(USBHS_EP_R_RES_MASK | USBHS_EP_T_TOG_MASK)) | USBHS_EP_T_RES_ACK; - - } else { - EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~(USBHS_EP_T_RES_MASK | USBHS_EP_T_TOG_MASK)) | USBHS_EP_T_RES_NAK; - } + /* Enable all types except Isochronous to avoid ISO_ACT interrupt generation */ + USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << ep_num); } -} - -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) { - (void)rhport; - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + EP_TX_LEN(ep_num) = 0; + EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; + } - xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, dir); - xfer->buffer = buffer; - // xfer->ff = NULL; // TODO support dcd_edpt_xfer_fifo API - xfer->total_len = total_bytes; - xfer->queued_len = 0; - xfer->short_packet = false; + return true; +} - // uint16_t num_packets = (total_bytes / xfer->max_size); - uint16_t short_packet_size = total_bytes % (xfer->max_size + 1); +void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { + (void) rhport; - // Zero-size packet is special case. - if (short_packet_size == 0 || (total_bytes == 0)) { - xfer->short_packet = true; - } + uint8_t const ep_num = tu_edpt_number(ep_addr); + tusb_dir_t const dir = tu_edpt_dir(ep_addr); - if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) { - if (!total_bytes) { - xfer->short_packet = true; - if (epnum == 0) { - USBHSD->UEP0_TX_LEN = 0; - USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_ACK | (USBHS_Dev_Endp0_Tog ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0); - USBHS_Dev_Endp0_Tog ^= 1; - } else { - EP_TX_LEN(epnum) = 0; - EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_ACK; - } - } else { - if (epnum == 0) { - xfer->queued_len += short_packet_size; - memcpy(&EP0_DatabufHD[0], buffer, short_packet_size); + if (dir == TUSB_DIR_OUT) { + EP_RX_CTRL(ep_num) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK; + EP_RX_MAX_LEN(ep_num) = 0; + USBHSD->ENDP_TYPE &= ~(USBHS_EP0_R_TYP << ep_num); + USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_R_EN << ep_num); + } else { // TUSB_DIR_IN + EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; + EP_TX_LEN(ep_num) = 0; + USBHSD->ENDP_TYPE &= ~(USBHS_EP0_T_TYP << ep_num); + USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_T_EN << ep_num); + } +} - USBHSD->UEP0_TX_LEN = short_packet_size; - USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_ACK | (USBHS_Dev_Endp0_Tog ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0); - USBHS_Dev_Endp0_Tog ^= 1; - } else { - xfer->queued_len += short_packet_size; +void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { + (void) rhport; - EP_TX_DMA_ADDR(epnum) = (uint32_t)buffer; - USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << epnum); - EP_TX_LEN(epnum) = short_packet_size; - EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_ACK; - } - } - } else { /* TUSB_DIR_OUT */ - if (epnum == 0) { - uint32_t read_count = USBHSD->RX_LEN; - read_count = TU_MIN(read_count, total_bytes); + uint8_t const ep_num = tu_edpt_number(ep_addr); + tusb_dir_t const dir = tu_edpt_dir(ep_addr); - if ((total_bytes == 8)) { - read_count = 8; - memcpy(buffer, &EP0_DatabufHD[0], 8); - } else { - memcpy(buffer, &EP0_DatabufHD[0], read_count); - } - } else { - EP_RX_DMA_ADDR(epnum) = (uint32_t)xfer->buffer; - USBHSD->ENDP_CONFIG |= (USBHS_EP0_R_EN << epnum); - } - - // usbd_ep_read(ep_addr, buffer, total_bytes, &ret_bytes); - } - return true; + if (dir == TUSB_DIR_OUT) { + EP_RX_CTRL(ep_num) = USBHS_EP_R_RES_STALL; + } else { + EP_TX_LEN(0) = 0; + EP_TX_CTRL(ep_num) = USBHS_EP_T_RES_STALL; + } } +void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { + (void) rhport; -static void receive_packet(xfer_ctl_t *xfer, uint16_t xfer_size) { - // xfer->queued_len = xfer->total_len - remaining; + uint8_t const ep_num = tu_edpt_number(ep_addr); + tusb_dir_t const dir = tu_edpt_dir(ep_addr); - uint16_t remaining = xfer->total_len - xfer->queued_len; - uint16_t to_recv_size; + if (dir == TUSB_DIR_OUT) { + EP_RX_CTRL(ep_num) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK; + } else { + EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG | USBHS_EP_R_RES_NAK; + } +} - if (remaining <= xfer->max_size) { - // Avoid buffer overflow. - to_recv_size = (xfer_size > remaining) ? remaining : xfer_size; - } else { - // Room for full packet, choose recv_size based on what the microcontroller - // claims. - to_recv_size = (xfer_size > xfer->max_size) ? xfer->max_size : xfer_size; - } +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) { + (void) rhport; + uint8_t const ep_num = tu_edpt_number(ep_addr); + tusb_dir_t const dir = tu_edpt_dir(ep_addr); - if (to_recv_size) { - } + xfer_ctl_t* xfer = XFER_CTL_BASE(ep_num, dir); + xfer->buffer = buffer; + xfer->total_len = total_bytes; + xfer->queued_len = 0; + xfer->is_last_packet = false; - xfer->queued_len += xfer_size; + xfer_data_packet(ep_num, dir, xfer); - // Per USB spec, a short OUT packet (including length 0) is always - // indicative of the end of a transfer (at least for ctl, bulk, int). - xfer->short_packet = (xfer_size < xfer->max_size); + return true; } void dcd_int_handler(uint8_t rhport) { - (void)rhport; - - uint32_t end_num, rx_token; - uint8_t intflag = 0; - - intflag = USBHSD->INT_FG; - - if (intflag & USBHS_TRANSFER_FLAG) { - - end_num = (USBHSD->INT_ST) & MASK_UIS_ENDP; - rx_token = (((USBHSD->INT_ST) & MASK_UIS_TOKEN) >> 4) & 0x03; - - uint8_t endp = end_num | (rx_token == PID_IN ? TUSB_DIR_IN_MASK : 0); - - xfer_ctl_t *xfer = XFER_CTL_BASE(end_num, tu_edpt_dir(endp)); - - if (rx_token == PID_SOF) { - dcd_event_sof(rhport, USBHSD->FRAME_NO, true); - - } else if (rx_token == PID_OUT) { - uint16_t rx_len = USBHSD->RX_LEN; - - receive_packet(xfer, rx_len); + (void) rhport; - if (xfer->short_packet || (xfer->queued_len == xfer->total_len)) { - xfer->short_packet = false; + uint8_t int_flag = USBHSD->INT_FG; + uint8_t int_status = USBHSD->INT_ST; - dcd_event_xfer_complete(0, endp, xfer->queued_len, XFER_RESULT_SUCCESS, true); - } + if (int_flag & (USBHS_ISO_ACT_FLAG | USBHS_TRANSFER_FLAG)) { + uint8_t const token = int_status & MASK_UIS_TOKEN; - if (end_num == 0) { - USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0; - } + if (token == USBHS_TOKEN_PID_SOF) { + uint32_t frame_count = USBHSD->FRAME_NO & USBHS_FRAME_NO_NUM_MASK; + dcd_event_sof(rhport, frame_count, true); + }else { + uint8_t const ep_num = int_status & MASK_UIS_ENDP; + tusb_dir_t const ep_dir = (token == USBHS_TOKEN_PID_IN) ? TUSB_DIR_IN : TUSB_DIR_OUT; + uint8_t const ep_addr = tu_edpt_addr(ep_num, ep_dir); + xfer_ctl_t* xfer = XFER_CTL_BASE(ep_num, ep_dir); - } else if (rx_token == PID_IN) { - if (xfer->short_packet || (xfer->queued_len == xfer->total_len)) { - xfer->short_packet = false; - xfer->total_len = 0; - dcd_event_xfer_complete(0, endp, xfer->queued_len, XFER_RESULT_SUCCESS, true); + if (token == USBHS_TOKEN_PID_OUT) { + uint16_t rx_len = USBHSD->RX_LEN; - EP_TX_CTRL(end_num) = (EP_TX_CTRL(end_num) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_NAK; + if (ep_num == 0) { + memcpy(&xfer->buffer[xfer->queued_len], ep0_buffer, rx_len); + } - if (end_num == 0) { - } - } else { - dcd_edpt_xfer(0, endp, xfer->buffer + xfer->queued_len, xfer->total_len - xfer->queued_len); - } + xfer->queued_len += rx_len; + if (rx_len < xfer->max_size) { + xfer->is_last_packet = true; + } + } else if (token == USBHS_TOKEN_PID_IN) { + if (xfer->is_iso && xfer->is_last_packet) { + /* Disable EP to avoid ISO_ACT interrupt generation */ + USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_T_EN << ep_num); + } else { + // Do nothing, no need to update xfer->is_last_packet, it is already updated in xfer_data_packet } + } - USBHSD->INT_FG = USBHS_TRANSFER_FLAG; /* Clear flag */ - } else if (intflag & USBHS_SETUP_FLAG) { - USBHS_Dev_Endp0_Tog = 1; - dcd_event_setup_received(0, EP0_DatabufHD, true); + if (xfer->is_last_packet == true) { + ep_set_response_and_toggle(ep_num, ep_dir, EP_RESPONSE_NAK); + dcd_event_xfer_complete(0, ep_addr, xfer->queued_len, XFER_RESULT_SUCCESS, true); + } else { + /* prepare next part of packet to xref */ + xfer_data_packet(ep_num, ep_dir, xfer); + } + } - USBHSD->INT_FG = USBHS_SETUP_FLAG; /* Clear flag */ - } else if (intflag & USBHS_DETECT_FLAG) { - USBHS_Dev_Endp0_Tog = 1; + USBHSD->INT_FG = (int_flag & (USBHS_ISO_ACT_FLAG | USBHS_TRANSFER_FLAG)); /* Clear flag */ + } else if (int_flag & USBHS_SETUP_FLAG) { + ep_set_response_and_toggle(0, TUSB_DIR_IN, EP_RESPONSE_NAK); + ep_set_response_and_toggle(0, TUSB_DIR_OUT, EP_RESPONSE_NAK); + dcd_event_setup_received(0, ep0_buffer, true); - xfer_status[0][TUSB_DIR_OUT].max_size = 64; - xfer_status[0][TUSB_DIR_IN].max_size = 64; + USBHSD->INT_FG = USBHS_SETUP_FLAG; /* Clear flag */ + } else if (int_flag & USBHS_BUS_RST_FLAG) { + // TODO CH32 does not detect actual speed at this time (should be known at end of reset) + // This interrupt probably triggered at start of bus reset +// tusb_speed_t actual_speed; +// switch(USBHSD->SPEED_TYPE & USBHS_SPEED_TYPE_MASK){ +// case USBHS_SPEED_TYPE_HIGH: +// actual_speed = TUSB_SPEED_HIGH; +// break; +// case USBHS_SPEED_TYPE_FULL: +// actual_speed = TUSB_SPEED_FULL; +// break; +// case USBHS_SPEED_TYPE_LOW: +// actual_speed = TUSB_SPEED_LOW; +// break; +// default: +// TU_ASSERT(0,); +// break; +// } +// dcd_event_bus_reset(0, actual_speed, true); - dcd_event_bus_reset(0, TUSB_SPEED_HIGH, true); + dcd_event_bus_reset(0, TUSB_SPEED_HIGH, true); - USBHSD->DEV_AD = 0; - USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0; + USBHSD->DEV_AD = 0; + EP_RX_CTRL(0) = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0; + EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; - USBHSD->INT_FG = USBHS_DETECT_FLAG; /* Clear flag */ - } else if (intflag & USBHS_SUSPEND_FLAG) { - dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SUSPEND }; - dcd_event_handler(&event, true); + USBHSD->INT_FG = USBHS_BUS_RST_FLAG; /* Clear flag */ + } else if (int_flag & USBHS_SUSPEND_FLAG) { + dcd_event_t event = {.rhport = rhport, .event_id = DCD_EVENT_SUSPEND}; + dcd_event_handler(&event, true); - USBHSD->INT_FG = USBHS_SUSPEND_FLAG; /* Clear flag */ - } + USBHSD->INT_FG = USBHS_SUSPEND_FLAG; /* Clear flag */ + } } #endif diff --git a/src/tusb_option.h b/src/tusb_option.h index 8d5527936..db8b94580 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -29,14 +29,12 @@ #include "common/tusb_compiler.h" -// Version is release as major.minor.revision eg 1.0.0. though there could be notable APIs before a new release. -// For notable API changes within a release, we increase the build number. +// Version is release as major.minor.revision eg 1.0.0 #define TUSB_VERSION_MAJOR 0 -#define TUSB_VERSION_MINOR 16 +#define TUSB_VERSION_MINOR 17 #define TUSB_VERSION_REVISION 0 -#define TUSB_VERSION_BUILD 3 -#define TUSB_VERSION_NUMBER (TUSB_VERSION_MAJOR << 24 | TUSB_VERSION_MINOR << 16 | TUSB_VERSION_REVISION << 8 | TUSB_VERSION_BUILD) +#define TUSB_VERSION_NUMBER (TUSB_VERSION_MAJOR * 10000 + TUSB_VERSION_MINOR * 100 + TUSB_VERSION_REVISION) #define TUSB_VERSION_STRING TU_STRING(TUSB_VERSION_MAJOR) "." TU_STRING(TUSB_VERSION_MINOR) "." TU_STRING(TUSB_VERSION_REVISION) //--------------------------------------------------------------------+ @@ -123,6 +121,8 @@ #define OPT_MCU_ESP32 902 ///< Espressif ESP32 (for host max3421e) #define OPT_MCU_ESP32C3 903 ///< Espressif ESP32-C3 #define OPT_MCU_ESP32C6 904 ///< Espressif ESP32-C6 +#define OPT_MCU_ESP32C2 905 ///< Espressif ESP32-C2 +#define OPT_MCU_ESP32H2 906 ///< Espressif ESP32-H2 #define TUP_MCU_ESPRESSIF (CFG_TUSB_MCU >= 900 && CFG_TUSB_MCU < 1000) // check if Espressif MCU // Dialog @@ -181,6 +181,7 @@ // WCH #define OPT_MCU_CH32V307 2200 ///< WCH CH32V307 #define OPT_MCU_CH32F20X 2210 ///< WCH CH32F20x +#define OPT_MCU_CH32V20X 2220 ///< WCH CH32V20X // NXP LPC MCX @@ -204,19 +205,9 @@ #define OPT_OS_RTTHREAD 6 ///< RT-Thread #define OPT_OS_RTX4 7 ///< Keil RTX 4 -// Allow to use command line to change the config name/location -#ifdef CFG_TUSB_CONFIG_FILE - #include CFG_TUSB_CONFIG_FILE -#else - #include "tusb_config.h" -#endif - -#include "common/tusb_mcu.h" - -//-------------------------------------------------------------------- -// RootHub Mode Configuration -// CFG_TUSB_RHPORTx_MODE contains operation mode and speed for that port -//-------------------------------------------------------------------- +//--------------------------------------------------------------------+ +// Mode and Speed +//--------------------------------------------------------------------+ // Low byte is operational mode #define OPT_MODE_NONE 0x0000 ///< Disabled @@ -230,7 +221,24 @@ #define OPT_MODE_HIGH_SPEED 0x0400 ///< High Speed #define OPT_MODE_SPEED_MASK 0xff00 -//------------- Roothub as Device -------------// +//--------------------------------------------------------------------+ +// Include tusb_config.h and tusb_mcu.h +//--------------------------------------------------------------------+ + +// Allow to use command line to change the config name/location +#ifdef CFG_TUSB_CONFIG_FILE + #include CFG_TUSB_CONFIG_FILE +#else + #include "tusb_config.h" +#endif + +#include "common/tusb_mcu.h" + +//-------------------------------------------------------------------- +// RootHub Mode detection +//-------------------------------------------------------------------- + +//------------- Root hub as Device -------------// #if defined(CFG_TUSB_RHPORT0_MODE) && ((CFG_TUSB_RHPORT0_MODE) & OPT_MODE_DEVICE) #define TUD_RHPORT_MODE (CFG_TUSB_RHPORT0_MODE) @@ -258,7 +266,7 @@ // highspeed support indicator #define TUD_OPT_HIGH_SPEED (CFG_TUD_MAX_SPEED ? (CFG_TUD_MAX_SPEED & OPT_MODE_HIGH_SPEED) : TUP_RHPORT_HIGHSPEED) -//------------- Roothub as Host -------------// +//------------- Root hub as Host -------------// #if defined(CFG_TUSB_RHPORT0_MODE) && ((CFG_TUSB_RHPORT0_MODE) & OPT_MODE_HOST) #define TUH_RHPORT_MODE (CFG_TUSB_RHPORT0_MODE) @@ -364,6 +372,20 @@ #define CFG_TUD_INTERFACE_MAX 16 #endif +// default to max hardware endpoint, but can be smaller to save RAM +#ifndef CFG_TUD_ENDPPOINT_MAX + #define CFG_TUD_ENDPPOINT_MAX TUP_DCD_ENDPOINT_MAX +#endif + +#if CFG_TUD_ENDPPOINT_MAX > TUP_DCD_ENDPOINT_MAX + #error "CFG_TUD_ENDPPOINT_MAX must be less than or equal to TUP_DCD_ENDPOINT_MAX" +#endif + +// USB 2.0 compliance test mode support +#ifndef CFG_TUD_TEST_MODE + #define CFG_TUD_TEST_MODE 0 +#endif + //------------- Device Class Driver -------------// #ifndef CFG_TUD_BTH #define CFG_TUD_BTH 0 @@ -459,26 +481,26 @@ #define CFG_TUH_CDC 0 #endif +// FTDI is not part of CDC class, only to re-use CDC driver API #ifndef CFG_TUH_CDC_FTDI - // FTDI is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_CDC_FTDI 0 #endif +// List of product IDs that can use the FTDI CDC driver. 0x0403 is FTDI's VID #ifndef CFG_TUH_CDC_FTDI_VID_PID_LIST - // List of product IDs that can use the FTDI CDC driver. 0x0403 is FTDI's VID #define CFG_TUH_CDC_FTDI_VID_PID_LIST \ {0x0403, 0x6001}, {0x0403, 0x6006}, {0x0403, 0x6010}, {0x0403, 0x6011}, \ {0x0403, 0x6014}, {0x0403, 0x6015}, {0x0403, 0x8372}, {0x0403, 0xFBFA}, \ {0x0403, 0xCD18} #endif +// CP210X is not part of CDC class, only to re-use CDC driver API #ifndef CFG_TUH_CDC_CP210X - // CP210X is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_CDC_CP210X 0 #endif +// List of product IDs that can use the CP210X CDC driver. 0x10C4 is Silicon Labs' VID #ifndef CFG_TUH_CDC_CP210X_VID_PID_LIST - // List of product IDs that can use the CP210X CDC driver. 0x10C4 is Silicon Labs' VID #define CFG_TUH_CDC_CP210X_VID_PID_LIST \ {0x10C4, 0xEA60}, {0x10C4, 0xEA70} #endif @@ -488,8 +510,8 @@ #define CFG_TUH_CDC_CH34X 0 #endif +// List of product IDs that can use the CH34X CDC driver #ifndef CFG_TUH_CDC_CH34X_VID_PID_LIST - // List of product IDs that can use the CH34X CDC driver #define CFG_TUH_CDC_CH34X_VID_PID_LIST \ { 0x1a86, 0x5523 }, /* ch341 chip */ \ { 0x1a86, 0x7522 }, /* ch340k chip */ \ |
