diff options
| author | HiFiPhile <[email protected]> | 2025-04-18 11:13:15 +0200 |
|---|---|---|
| committer | HiFiPhile <[email protected]> | 2025-04-18 11:13:15 +0200 |
| commit | b6abc9022a4beae98cc206d8fbeefb4700deef2f (patch) | |
| tree | bdd12bb710caa9d161edc1488a37911de0931a3d /src/portable/raspberrypi | |
| parent | 713410997326269b4072dce906933f8f44fd0efe (diff) | |
| parent | 865e3488f99209c57b73953428dccf2bc666f0be (diff) | |
Merge remote-tracking branch 'upstream/master' into hcd-template-comments
Signed-off-by: HiFiPhile <[email protected]>
Diffstat (limited to 'src/portable/raspberrypi')
| -rw-r--r-- | src/portable/raspberrypi/pio_usb/dcd_pio_usb.c | 7 | ||||
| -rw-r--r-- | src/portable/raspberrypi/pio_usb/hcd_pio_usb.c | 8 | ||||
| -rw-r--r-- | src/portable/raspberrypi/rp2040/dcd_rp2040.c | 159 | ||||
| -rw-r--r-- | src/portable/raspberrypi/rp2040/hcd_rp2040.c | 56 | ||||
| -rw-r--r-- | src/portable/raspberrypi/rp2040/rp2040_usb.c | 2 |
5 files changed, 131 insertions, 101 deletions
diff --git a/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c b/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c index e6daf6827..60afbd435 100644 --- a/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c +++ b/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c @@ -50,12 +50,13 @@ static usb_descriptor_buffers_t desc; *------------------------------------------------------------------*/ // Initialize controller to device mode -void dcd_init (uint8_t rhport) -{ +bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { (void) rhport; - + (void) rh_init; static pio_usb_configuration_t config = PIO_USB_DEFAULT_CONFIG; usb_device = pio_usb_device_init(&config, &desc); + + return true; } // Enable device interrupt diff --git a/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c index f4de3c51d..225a44dcf 100644 --- a/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c +++ b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c @@ -55,8 +55,9 @@ bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void *cfg_param) { return true; } -bool hcd_init(uint8_t rhport) { +bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { (void) rhport; + (void) rh_init; // To run USB SOF interrupt in core1, call this init in core1 pio_usb_host_init(&pio_host_cfg); @@ -121,6 +122,11 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const return pio_usb_host_endpoint_open(pio_rhport, dev_addr, (uint8_t const *) desc_ep, need_pre); } +bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) { + uint8_t const pio_rhport = RHPORT_PIO(rhport); + return pio_usb_host_endpoint_close(pio_rhport, daddr, ep_addr); +} + bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen) { uint8_t const pio_rhport = RHPORT_PIO(rhport); return pio_usb_host_endpoint_transfer(pio_rhport, dev_addr, ep_addr, buffer, buflen); diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c index bc0deee32..358ce84bc 100644 --- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c @@ -46,7 +46,6 @@ /*------------------------------------------------------------------*/ /* Low level controller *------------------------------------------------------------------*/ - // Init these in dcd_init static uint8_t* next_buffer_ptr; @@ -66,58 +65,31 @@ TU_ATTR_ALWAYS_INLINE static inline struct hw_endpoint* hw_endpoint_get_by_addr( return hw_endpoint_get_by_num(num, dir); } -static void _hw_endpoint_alloc(struct hw_endpoint* ep, uint8_t transfer_type) { - // size must be multiple of 64 - uint size = tu_div_ceil(ep->wMaxPacketSize, 64) * 64u; +// Allocate from the USB buffer space (max 3840 bytes) +static void hw_endpoint_alloc(struct hw_endpoint* ep, size_t size) { + // round up size to multiple of 64 + size = tu_round_up(ep->wMaxPacketSize, 64); // double buffered Bulk endpoint - if (transfer_type == TUSB_XFER_BULK) { + if (ep->transfer_type == TUSB_XFER_BULK) { size *= 2u; } + // assign buffer ep->hw_data_buf = next_buffer_ptr; next_buffer_ptr += size; - assert(((uintptr_t) next_buffer_ptr & 0b111111u) == 0); - uint dpram_offset = hw_data_offset(ep->hw_data_buf); - hard_assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX); - - pico_info(" Allocated %d bytes at offset 0x%x (0x%p)\r\n", size, dpram_offset, ep->hw_data_buf); - - // Fill in endpoint control register with buffer offset - uint32_t const reg = EP_CTRL_ENABLE_BITS | ((uint) transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset; - - *ep->endpoint_control = reg; + hard_assert(next_buffer_ptr < usb_dpram->epx_data + sizeof(usb_dpram->epx_data)); + pico_info(" Allocated %d bytes (0x%p)\r\n", size, ep->hw_data_buf); } -static void _hw_endpoint_close(struct hw_endpoint* ep) { - // Clear hardware registers and then zero the struct - // Clears endpoint enable - *ep->endpoint_control = 0; - // Clears buffer available, etc - *ep->buffer_control = 0; - // Clear any endpoint state - memset(ep, 0, sizeof(struct hw_endpoint)); - - // Reclaim buffer space if all endpoints are closed - bool reclaim_buffers = true; - for (uint8_t i = 1; i < USB_MAX_ENDPOINTS; i++) { - if (hw_endpoint_get_by_num(i, TUSB_DIR_OUT)->hw_data_buf != NULL || - hw_endpoint_get_by_num(i, TUSB_DIR_IN)->hw_data_buf != NULL) { - reclaim_buffers = false; - break; - } - } - if (reclaim_buffers) { - next_buffer_ptr = &usb_dpram->epx_data[0]; - } -} - -static void hw_endpoint_close(uint8_t ep_addr) { - struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr); - _hw_endpoint_close(ep); +// Enable endpoint +TU_ATTR_ALWAYS_INLINE static inline void hw_endpoint_enable(struct hw_endpoint* ep) { + uint32_t const reg = EP_CTRL_ENABLE_BITS | ((uint) ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | hw_data_offset(ep->hw_data_buf); + *ep->endpoint_control = reg; } +// main processing for dcd_edpt_iso_activate static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type) { struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr); @@ -156,9 +128,18 @@ static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t t } else { ep->endpoint_control = &usb_dpram->ep_ctrl[num - 1].out; } + } +} - // alloc a buffer and fill in endpoint control register - _hw_endpoint_alloc(ep, transfer_type); +// Init, allocate buffer and enable endpoint +static void hw_endpoint_open(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type) { + struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr); + hw_endpoint_init(ep_addr, wMaxPacketSize, transfer_type); + const uint8_t num = tu_edpt_number(ep_addr); + if (num != 0) { + // EP0 is already enabled + hw_endpoint_alloc(ep, ep->wMaxPacketSize); + hw_endpoint_enable(ep); } } @@ -167,6 +148,32 @@ static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t* buffer, uint16_t total_by hw_endpoint_xfer_start(ep, buffer, total_bytes); } +static void hw_endpoint_abort_xfer(struct hw_endpoint* ep) { + // Abort any pending transfer + // Due to Errata RP2040-E2: ABORT flag is only applicable for B2 and later (unusable for B0, B1). + // Which means we are not guaranteed to safely abort pending transfer on B0 and B1. + const uint8_t dir = tu_edpt_dir(ep->ep_addr); + const uint8_t epnum = tu_edpt_number(ep->ep_addr); + const uint32_t abort_mask = TU_BIT((epnum << 1) | (dir ? 0 : 1)); + if (rp2040_chip_version() >= 2) { + usb_hw_set->abort = abort_mask; + while ((usb_hw->abort_done & abort_mask) != abort_mask) {} + } + + uint32_t buf_ctrl = USB_BUF_CTRL_SEL; // reset to buffer 0 + if (ep->next_pid) { + buf_ctrl |= USB_BUF_CTRL_DATA1_PID; + } + + _hw_endpoint_buffer_control_set_value32(ep, buf_ctrl); + hw_endpoint_reset_transfer(ep); + + if (rp2040_chip_version() >= 2) { + usb_hw_clear->abort_done = abort_mask; + usb_hw_clear->abort = abort_mask; + } +} + static void __tusb_irq_path_func(hw_handle_buff_status)(void) { uint32_t remaining_buffers = usb_hw->buf_status; pico_trace("buf_status = 0x%08lx\r\n", remaining_buffers); @@ -197,25 +204,10 @@ TU_ATTR_ALWAYS_INLINE static inline void reset_ep0(void) { // setup transfer. Also clear a stall in case for (uint8_t dir = 0; dir < 2; dir++) { struct hw_endpoint* ep = hw_endpoint_get_by_num(0, dir); + ep->next_pid = 1u; if (ep->active) { - // Abort any pending transfer from a prior control transfer per USB specs - // Due to Errata RP2040-E2: ABORT flag is only applicable for B2 and later (unusable for B0, B1). - // Which means we are not guaranteed to safely abort pending transfer on B0 and B1. - uint32_t const abort_mask = (dir ? USB_EP_ABORT_EP0_IN_BITS : USB_EP_ABORT_EP0_OUT_BITS); - if (rp2040_chip_version() >= 2) { - usb_hw_set->abort = abort_mask; - while ((usb_hw->abort_done & abort_mask) != abort_mask) {} - } - - _hw_endpoint_buffer_control_set_value32(ep, USB_BUF_CTRL_DATA1_PID | USB_BUF_CTRL_SEL); - hw_endpoint_reset_transfer(ep); - - if (rp2040_chip_version() >= 2) { - usb_hw_clear->abort_done = abort_mask; - usb_hw_clear->abort = abort_mask; - } + hw_endpoint_abort_xfer(ep); // Abort any pending transfer per USB specs } - ep->next_pid = 1u; } } @@ -369,7 +361,8 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void) { #define PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY 0xff #endif -void dcd_init(uint8_t rhport) { +bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { + (void) rh_init; assert(rhport == 0); TU_LOG(2, "Chip Version B%u\r\n", rp2040_chip_version()); @@ -386,8 +379,8 @@ void dcd_init(uint8_t rhport) { // Init control endpoints tu_memclr(hw_endpoints[0], 2 * sizeof(hw_endpoint_t)); - hw_endpoint_init(0x0, 64, TUSB_XFER_CONTROL); - hw_endpoint_init(0x80, 64, TUSB_XFER_CONTROL); + hw_endpoint_open(0x0, 64, TUSB_XFER_CONTROL); + hw_endpoint_open(0x80, 64, TUSB_XFER_CONTROL); // Init non-control endpoints reset_non_control_endpoints(); @@ -405,6 +398,7 @@ void dcd_init(uint8_t rhport) { (FORCE_VBUS_DETECT ? 0 : USB_INTS_DEV_CONN_DIS_BITS); dcd_connect(rhport); + return true; } bool dcd_deinit(uint8_t rhport) { @@ -491,9 +485,36 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* req } } -bool dcd_edpt_open(__unused uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) { - assert(rhport == 0); - hw_endpoint_init(desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt), desc_edpt->bmAttributes.xfer); +bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) { + (void) rhport; + const uint8_t xfer_type = desc_edpt->bmAttributes.xfer; + TU_VERIFY(xfer_type != TUSB_XFER_ISOCHRONOUS); + hw_endpoint_open(desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt), xfer_type); + return true; +} + +// New API: Allocate packet buffer used by ISO endpoints +// Some MCU need manual packet buffer allocation, we allocate the largest size to avoid clustering +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { + (void) rhport; + struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr); + hw_endpoint_init(ep_addr, largest_packet_size, TUSB_XFER_ISOCHRONOUS); + hw_endpoint_alloc(ep, largest_packet_size); + return true; +} + +// New API: Configure and enable an ISO endpoint according to descriptor +bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) { + (void) rhport; + struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_desc->bEndpointAddress); + TU_ASSERT(ep->hw_data_buf != NULL); // must be inited and allocated previously + + if (ep->active) { + hw_endpoint_abort_xfer(ep); // abort any pending transfer + } + + ep->wMaxPacketSize = ep_desc->wMaxPacketSize; + hw_endpoint_enable(ep); return true; } @@ -538,12 +559,6 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { } } -void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { - (void) rhport; - pico_trace("dcd_edpt_close %02x\r\n", ep_addr); - hw_endpoint_close(ep_addr); -} - void __tusb_irq_path_func(dcd_int_handler)(uint8_t rhport) { (void) rhport; dcd_rp2040_irq(); diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c index 222dbbbf0..cd8c905d5 100644 --- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c @@ -375,9 +375,9 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t //--------------------------------------------------------------------+ // HCD API //--------------------------------------------------------------------+ -bool hcd_init(uint8_t rhport) -{ +bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { (void) rhport; + (void) rh_init; pico_trace("hcd_init %d\n", rhport); assert(rhport == 0); @@ -459,28 +459,33 @@ tusb_speed_t hcd_port_speed_get(uint8_t rhport) } // Close all opened endpoint belong to this device -void hcd_device_close(uint8_t rhport, uint8_t dev_addr) -{ +void hcd_device_close(uint8_t rhport, uint8_t dev_addr) { pico_trace("hcd_device_close %d\n", dev_addr); (void) rhport; - if (dev_addr == 0) return; - - for (size_t i = 1; i < TU_ARRAY_SIZE(ep_pool); i++) - { - hw_endpoint_t* ep = &ep_pool[i]; + // reset epx if it is currently active with unplugged device + if (epx.configured && epx.active && epx.dev_addr == dev_addr) { + epx.configured = false; + *epx.endpoint_control = 0; + *epx.buffer_control = 0; + hw_endpoint_reset_transfer(&epx); + } - if (ep->dev_addr == dev_addr && ep->configured) - { - // in case it is an interrupt endpoint, disable it - usb_hw_clear->int_ep_ctrl = (1 << (ep->interrupt_num + 1)); - usb_hw->int_ep_addr_ctrl[ep->interrupt_num] = 0; + // dev0 only has ep0 + if (dev_addr != 0) { + for (size_t i = 1; i < TU_ARRAY_SIZE(ep_pool); i++) { + hw_endpoint_t *ep = &ep_pool[i]; + if (ep->dev_addr == dev_addr && ep->configured) { + // in case it is an interrupt endpoint, disable it + usb_hw_clear->int_ep_ctrl = (1 << (ep->interrupt_num + 1)); + usb_hw->int_ep_addr_ctrl[ep->interrupt_num] = 0; - // unconfigure the endpoint - ep->configured = false; - *ep->endpoint_control = 0; - *ep->buffer_control = 0; - hw_endpoint_reset_transfer(ep); + // unconfigure the endpoint + ep->configured = false; + *ep->endpoint_control = 0; + *ep->buffer_control = 0; + hw_endpoint_reset_transfer(ep); + } } } } @@ -509,7 +514,6 @@ void hcd_int_disable(uint8_t rhport) //--------------------------------------------------------------------+ // Endpoint API //--------------------------------------------------------------------+ - bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc) { (void) rhport; @@ -530,6 +534,11 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const return true; } +bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) { + (void) rhport; (void) daddr; (void) ep_addr; + return false; // TODO not implemented yet +} + bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) { (void) rhport; @@ -557,7 +566,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * } // If a normal transfer (non-interrupt) then initiate using - // sie ctrl registers. Otherwise interrupt ep registers should + // sie ctrl registers. Otherwise, interrupt ep registers should // already be configured if ( ep == &epx ) { @@ -597,13 +606,12 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet (void) rhport; // Copy data into setup packet buffer - for ( uint8_t i = 0; i < 8; i++ ) - { + for (uint8_t i = 0; i < 8; i++) { usbh_dpram->setup_packet[i] = setup_packet[i]; } // Configure EP0 struct with setup info for the trans complete - struct hw_endpoint * ep = _hw_endpoint_allocate(0); + struct hw_endpoint * ep = _hw_endpoint_allocate( (uint8_t) TUSB_XFER_CONTROL); TU_ASSERT(ep); // EPX should be inactive diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c index 43f48da39..9d0bd762d 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.c +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c @@ -110,7 +110,7 @@ void __tusb_irq_path_func(_hw_endpoint_buffer_control_update32)(struct hw_endpoi *ep->buffer_control = value & ~USB_BUF_CTRL_AVAIL; // 4.1.2.5.1 Con-current access: 12 cycles (should be good for 48*12Mhz = 576Mhz) after write to buffer control // Don't need delay in host mode as host is in charge - if ( !is_host_mode()) { + if (!is_host_mode()) { busy_wait_at_least_cycles(12); } } |
