Merge pull request #1020 from hathach/rp2040-disconnect-suspend

Add Rp2040 suspend & resume support
This commit is contained in:
Ha Thach 2021-08-18 16:45:35 +07:00 committed by GitHub
commit 830757d9ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 157 additions and 173 deletions

View File

@ -152,6 +152,7 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff,
void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr); void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr);
// clear stall, data toggle is also reset to DATA0 // clear stall, data toggle is also reset to DATA0
// This API never calls with control endpoints, since it is auto cleared when receiving setup packet
void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr); void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr);
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+

View File

@ -1220,6 +1220,9 @@ bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr)
{ {
(void) rhport; (void) rhport;
// TODO add this check later, also make sure we don't starve an out endpoint while suspending
// TU_VERIFY(tud_ready());
uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr);
@ -1273,6 +1276,9 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr);
// TODO skip ready() check for now since enumeration also use this API
// TU_VERIFY(tud_ready());
TU_LOG2(" Queue EP %02X with %u bytes ...\r\n", ep_addr, total_bytes); TU_LOG2(" Queue EP %02X with %u bytes ...\r\n", ep_addr, total_bytes);
// Attempt to transfer on a busy endpoint, sound like an race condition ! // Attempt to transfer on a busy endpoint, sound like an race condition !

View File

@ -37,6 +37,11 @@
#include "device/dcd.h" #include "device/dcd.h"
// Current implementation force vbus detection as always present, causing device think it is always plugged into host.
// Therefore it cannot detect disconnect event, mistaken it as suspend.
// Note: won't work if change to 0 (for now)
#define FORCE_VBUS_DETECT 1
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
/* Low level controller /* Low level controller
*------------------------------------------------------------------*/ *------------------------------------------------------------------*/
@ -48,27 +53,27 @@
static uint8_t *next_buffer_ptr; static uint8_t *next_buffer_ptr;
// USB_MAX_ENDPOINTS Endpoints, direction TUSB_DIR_OUT for out and TUSB_DIR_IN for in. // USB_MAX_ENDPOINTS Endpoints, direction TUSB_DIR_OUT for out and TUSB_DIR_IN for in.
static struct hw_endpoint hw_endpoints[USB_MAX_ENDPOINTS][2] = {0}; static struct hw_endpoint hw_endpoints[USB_MAX_ENDPOINTS][2];
static inline struct hw_endpoint *hw_endpoint_get_by_num(uint8_t num, tusb_dir_t dir) static inline struct hw_endpoint *hw_endpoint_get_by_num(uint8_t num, tusb_dir_t dir)
{ {
return &hw_endpoints[num][dir]; return &hw_endpoints[num][dir];
} }
static struct hw_endpoint *hw_endpoint_get_by_addr(uint8_t ep_addr) static struct hw_endpoint *hw_endpoint_get_by_addr(uint8_t ep_addr)
{ {
uint8_t num = tu_edpt_number(ep_addr); uint8_t num = tu_edpt_number(ep_addr);
tusb_dir_t dir = tu_edpt_dir(ep_addr); tusb_dir_t dir = tu_edpt_dir(ep_addr);
return hw_endpoint_get_by_num(num, dir); return hw_endpoint_get_by_num(num, dir);
} }
static void _hw_endpoint_alloc(struct hw_endpoint *ep) static void _hw_endpoint_alloc(struct hw_endpoint *ep, uint8_t transfer_type)
{ {
// size must be multiple of 64 // size must be multiple of 64
uint16_t size = tu_div_ceil(ep->wMaxPacketSize, 64) * 64u; uint16_t size = tu_div_ceil(ep->wMaxPacketSize, 64) * 64u;
// double buffered for Control and Bulk endpoint // double buffered Bulk endpoint
if ( ep->transfer_type == TUSB_XFER_CONTROL || ep->transfer_type == TUSB_XFER_BULK) if ( transfer_type == TUSB_XFER_BULK )
{ {
size *= 2u; size *= 2u;
} }
@ -80,81 +85,14 @@ static void _hw_endpoint_alloc(struct hw_endpoint *ep)
uint dpram_offset = hw_data_offset(ep->hw_data_buf); uint dpram_offset = hw_data_offset(ep->hw_data_buf);
assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX); assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX);
pico_info("Alloced %d bytes at offset 0x%x (0x%p) for ep %d %s\n", pico_info(" Alloced %d bytes at offset 0x%x (0x%p)\r\n", size, dpram_offset, ep->hw_data_buf);
size,
dpram_offset,
ep->hw_data_buf,
tu_edpt_number(ep->ep_addr),
ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
// Fill in endpoint control register with buffer offset // Fill in endpoint control register with buffer offset
uint32_t const reg = EP_CTRL_ENABLE_BITS | (ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset; uint32_t const reg = EP_CTRL_ENABLE_BITS | (transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset;
*ep->endpoint_control = reg; *ep->endpoint_control = reg;
} }
static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type)
{
const uint8_t num = tu_edpt_number(ep_addr);
const tusb_dir_t dir = tu_edpt_dir(ep_addr);
ep->ep_addr = ep_addr;
// For device, IN is a tx transfer and OUT is an rx transfer
ep->rx = (dir == TUSB_DIR_OUT);
// Response to a setup packet on EP0 starts with pid of 1
ep->next_pid = num == 0 ? 1u : 0u;
ep->wMaxPacketSize = wMaxPacketSize;
ep->transfer_type = transfer_type;
// Every endpoint has a buffer control register in dpram
if (dir == TUSB_DIR_IN)
{
ep->buffer_control = &usb_dpram->ep_buf_ctrl[num].in;
}
else
{
ep->buffer_control = &usb_dpram->ep_buf_ctrl[num].out;
}
// Clear existing buffer control state
*ep->buffer_control = 0;
if (num == 0)
{
// EP0 has no endpoint control register because
// the buffer offsets are fixed
ep->endpoint_control = NULL;
// Buffer offset is fixed
ep->hw_data_buf = (uint8_t*)&usb_dpram->ep0_buf_a[0];
}
else
{
// Set the endpoint control register (starts at EP1, hence num-1)
if (dir == TUSB_DIR_IN)
{
ep->endpoint_control = &usb_dpram->ep_ctrl[num-1].in;
}
else
{
ep->endpoint_control = &usb_dpram->ep_ctrl[num-1].out;
}
// Now if it hasn't already been done
//alloc a buffer and fill in endpoint control register
// TODO device may change configuration (dynamic), should clear and reallocate
if(!(ep->configured))
{
_hw_endpoint_alloc(ep);
}
}
ep->configured = true;
}
#if 0 // todo unused #if 0 // todo unused
static void _hw_endpoint_close(struct hw_endpoint *ep) static void _hw_endpoint_close(struct hw_endpoint *ep)
{ {
@ -174,10 +112,61 @@ static void hw_endpoint_close(uint8_t ep_addr)
} }
#endif #endif
static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t bmAttributes) 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); struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
_hw_endpoint_init(ep, ep_addr, wMaxPacketSize, bmAttributes);
const uint8_t num = tu_edpt_number(ep_addr);
const tusb_dir_t dir = tu_edpt_dir(ep_addr);
ep->ep_addr = ep_addr;
// For device, IN is a tx transfer and OUT is an rx transfer
ep->rx = (dir == TUSB_DIR_OUT);
// Response to a setup packet on EP0 starts with pid of 1
ep->next_pid = (num == 0 ? 1u : 0u);
ep->wMaxPacketSize = wMaxPacketSize;
ep->transfer_type = transfer_type;
// Every endpoint has a buffer control register in dpram
if ( dir == TUSB_DIR_IN )
{
ep->buffer_control = &usb_dpram->ep_buf_ctrl[num].in;
}
else
{
ep->buffer_control = &usb_dpram->ep_buf_ctrl[num].out;
}
// Clear existing buffer control state
*ep->buffer_control = 0;
if ( num == 0 )
{
// EP0 has no endpoint control register because
// the buffer offsets are fixed
ep->endpoint_control = NULL;
// Buffer offset is fixed (also double buffered)
ep->hw_data_buf = (uint8_t*) &usb_dpram->ep0_buf_a[0];
}
else
{
// Set the endpoint control register (starts at EP1, hence num-1)
if ( dir == TUSB_DIR_IN )
{
ep->endpoint_control = &usb_dpram->ep_ctrl[num - 1].in;
}
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);
}
} }
static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
@ -222,55 +211,22 @@ static void reset_ep0(void)
{ {
struct hw_endpoint *ep = hw_endpoint_get_by_addr(addrs[i]); struct hw_endpoint *ep = hw_endpoint_get_by_addr(addrs[i]);
ep->next_pid = 1u; ep->next_pid = 1u;
ep->stalled = 0;
} }
} }
static void ep0_0len_status(void) static void reset_all_endpoints(void)
{ {
// Send 0len complete response on EP0 IN memset(hw_endpoints, 0, sizeof(hw_endpoints));
reset_ep0(); next_buffer_ptr = &usb_dpram->epx_data[0];
hw_endpoint_xfer(0x80, NULL, 0);
}
static void _hw_endpoint_stall(struct hw_endpoint *ep) // Init Control endpoint out & in
{ hw_endpoint_init(0x0, 64, TUSB_XFER_CONTROL);
assert(!ep->stalled); hw_endpoint_init(0x80, 64, TUSB_XFER_CONTROL);
if (tu_edpt_number(ep->ep_addr) == 0)
{
// A stall on EP0 has to be armed so it can be cleared on the next setup packet
usb_hw_set->ep_stall_arm = (tu_edpt_dir(ep->ep_addr) == TUSB_DIR_IN) ? USB_EP_STALL_ARM_EP0_IN_BITS : USB_EP_STALL_ARM_EP0_OUT_BITS;
}
_hw_endpoint_buffer_control_set_mask32(ep, USB_BUF_CTRL_STALL);
ep->stalled = true;
}
static void hw_endpoint_stall(uint8_t ep_addr)
{
struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
_hw_endpoint_stall(ep);
}
static void _hw_endpoint_clear_stall(struct hw_endpoint *ep)
{
if (tu_edpt_number(ep->ep_addr) == 0)
{
// Probably already been cleared but no harm
usb_hw_clear->ep_stall_arm = (tu_edpt_dir(ep->ep_addr) == TUSB_DIR_IN) ? USB_EP_STALL_ARM_EP0_IN_BITS : USB_EP_STALL_ARM_EP0_OUT_BITS;
}
_hw_endpoint_buffer_control_clear_mask32(ep, USB_BUF_CTRL_STALL);
ep->stalled = false;
}
static void hw_endpoint_clear_stall(uint8_t ep_addr)
{
struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
_hw_endpoint_clear_stall(ep);
} }
static void dcd_rp2040_irq(void) static void dcd_rp2040_irq(void)
{ {
uint32_t status = usb_hw->ints; uint32_t const status = usb_hw->ints;
uint32_t handled = 0; uint32_t handled = 0;
if (status & USB_INTS_SETUP_REQ_BITS) if (status & USB_INTS_SETUP_REQ_BITS)
@ -290,7 +246,9 @@ static void dcd_rp2040_irq(void)
hw_handle_buff_status(); hw_handle_buff_status();
} }
// SE0 for 2 us or more, usually together with Bus Reset #if FORCE_VBUS_DETECT == 0
// Since we force VBUS detect On, device will always think it is connected and
// couldn't distinguish between disconnect and suspend
if (status & USB_INTS_DEV_CONN_DIS_BITS) if (status & USB_INTS_DEV_CONN_DIS_BITS)
{ {
handled |= USB_INTS_DEV_CONN_DIS_BITS; handled |= USB_INTS_DEV_CONN_DIS_BITS;
@ -306,13 +264,17 @@ static void dcd_rp2040_irq(void)
usb_hw_clear->sie_status = USB_SIE_STATUS_CONNECTED_BITS; usb_hw_clear->sie_status = USB_SIE_STATUS_CONNECTED_BITS;
} }
#endif
// SE0 for 2.5 us or more // SE0 for 2.5 us or more (will last at least 10ms)
if (status & USB_INTS_BUS_RESET_BITS) if (status & USB_INTS_BUS_RESET_BITS)
{ {
pico_trace("BUS RESET\n"); pico_trace("BUS RESET\n");
usb_hw->dev_addr_ctrl = 0;
handled |= USB_INTS_BUS_RESET_BITS; handled |= USB_INTS_BUS_RESET_BITS;
usb_hw->dev_addr_ctrl = 0;
reset_all_endpoints();
dcd_event_bus_reset(0, TUSB_SPEED_FULL, true); dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
usb_hw_clear->sie_status = USB_SIE_STATUS_BUS_RESET_BITS; usb_hw_clear->sie_status = USB_SIE_STATUS_BUS_RESET_BITS;
@ -322,9 +284,6 @@ static void dcd_rp2040_irq(void)
#endif #endif
} }
#if 0
// TODO Enable SUSPEND & RESUME interrupt and test later on with/without VBUS detection
/* Note from pico datasheet 4.1.2.6.4 (v1.2) /* Note from pico datasheet 4.1.2.6.4 (v1.2)
* If you enable the suspend interrupt, it is likely you will see a suspend interrupt when * If you enable the suspend interrupt, it is likely you will see a suspend interrupt when
* the device is first connected but the bus is idle. The bus can be idle for a few ms before * the device is first connected but the bus is idle. The bus can be idle for a few ms before
@ -346,7 +305,6 @@ static void dcd_rp2040_irq(void)
dcd_event_bus_signal(0, DCD_EVENT_RESUME, true); dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
usb_hw_clear->sie_status = USB_SIE_STATUS_RESUME_BITS; usb_hw_clear->sie_status = USB_SIE_STATUS_RESUME_BITS;
} }
#endif
if (status ^ handled) if (status ^ handled)
{ {
@ -364,36 +322,38 @@ static void dcd_rp2040_irq(void)
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
/* Controller API /* Controller API
*------------------------------------------------------------------*/ *------------------------------------------------------------------*/
void dcd_init (uint8_t rhport) void dcd_init (uint8_t rhport)
{ {
pico_trace("dcd_init %d\n", rhport); pico_trace("dcd_init %d\n", rhport);
assert(rhport == 0); assert(rhport == 0);
// Reset hardware to default state // Reset hardware to default state
rp2040_usb_init(); rp2040_usb_init();
irq_set_exclusive_handler(USBCTRL_IRQ, dcd_rp2040_irq); #if FORCE_VBUS_DETECT
memset(hw_endpoints, 0, sizeof(hw_endpoints)); // Force VBUS detect so the device thinks it is plugged into a host
next_buffer_ptr = &usb_dpram->epx_data[0]; usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
#endif
// EP0 always exists so init it now irq_set_exclusive_handler(USBCTRL_IRQ, dcd_rp2040_irq);
// EP0 OUT
hw_endpoint_init(0x0, 64, TUSB_XFER_CONTROL);
// EP0 IN
hw_endpoint_init(0x80, 64, TUSB_XFER_CONTROL);
// Initializes the USB peripheral for device mode and enables it. // reset endpoints
// Don't need to enable the pull up here. Force VBUS reset_all_endpoints();
usb_hw->main_ctrl = USB_MAIN_CTRL_CONTROLLER_EN_BITS;
// Enable individual controller IRQS here. Processor interrupt enable will be used // Initializes the USB peripheral for device mode and enables it.
// for the global interrupt enable... // Don't need to enable the pull up here. Force VBUS
// TODO Enable SUSPEND & RESUME interrupt usb_hw->main_ctrl = USB_MAIN_CTRL_CONTROLLER_EN_BITS;
usb_hw->sie_ctrl = USB_SIE_CTRL_EP0_INT_1BUF_BITS;
usb_hw->inte = USB_INTS_BUFF_STATUS_BITS | USB_INTS_BUS_RESET_BITS | USB_INTS_SETUP_REQ_BITS |
USB_INTS_DEV_CONN_DIS_BITS /* | USB_INTS_DEV_SUSPEND_BITS | USB_INTS_DEV_RESUME_FROM_HOST_BITS */ ;
dcd_connect(rhport); // Enable individual controller IRQS here. Processor interrupt enable will be used
// for the global interrupt enable...
// Note: Force VBUS detect cause disconnection not detectable
usb_hw->sie_ctrl = USB_SIE_CTRL_EP0_INT_1BUF_BITS;
usb_hw->inte = USB_INTS_BUFF_STATUS_BITS | USB_INTS_BUS_RESET_BITS | USB_INTS_SETUP_REQ_BITS |
USB_INTS_DEV_SUSPEND_BITS | USB_INTS_DEV_RESUME_FROM_HOST_BITS |
(FORCE_VBUS_DETECT ? 0 : USB_INTS_DEV_CONN_DIS_BITS);
dcd_connect(rhport);
} }
void dcd_int_enable(uint8_t rhport) void dcd_int_enable(uint8_t rhport)
@ -410,11 +370,13 @@ void dcd_int_disable(uint8_t rhport)
void dcd_set_address (uint8_t rhport, uint8_t dev_addr) void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
{ {
pico_trace("dcd_set_address %d %d\n", rhport, dev_addr); pico_trace("dcd_set_address %d %d\n", rhport, dev_addr);
assert(rhport == 0); assert(rhport == 0);
// Can't set device address in hardware until status xfer has complete // Can't set device address in hardware until status xfer has complete
ep0_0len_status(); // Send 0len complete response on EP0 IN
reset_ep0();
hw_endpoint_xfer(0x80, NULL, 0);
} }
void dcd_remote_wakeup(uint8_t rhport) void dcd_remote_wakeup(uint8_t rhport)
@ -461,7 +423,6 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * re
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
{ {
pico_info("dcd_edpt_open %02x\n", desc_edpt->bEndpointAddress);
assert(rhport == 0); assert(rhport == 0);
hw_endpoint_init(desc_edpt->bEndpointAddress, desc_edpt->wMaxPacketSize.size, desc_edpt->bmAttributes.xfer); hw_endpoint_init(desc_edpt->bEndpointAddress, desc_edpt->wMaxPacketSize.size, desc_edpt->bmAttributes.xfer);
return true; return true;
@ -474,20 +435,37 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t
return true; return true;
} }
void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
{ {
pico_trace("dcd_edpt_stall %02x\n", ep_addr); pico_trace("dcd_edpt_stall %02x\n", ep_addr);
assert(rhport == 0); assert(rhport == 0);
hw_endpoint_stall(ep_addr);
if ( tu_edpt_number(ep_addr) == 0 )
{
// A stall on EP0 has to be armed so it can be cleared on the next setup packet
usb_hw_set->ep_stall_arm = (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) ? USB_EP_STALL_ARM_EP0_IN_BITS : USB_EP_STALL_ARM_EP0_OUT_BITS;
}
struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
// TODO check with double buffered
_hw_endpoint_buffer_control_set_mask32(ep, USB_BUF_CTRL_STALL);
} }
void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
{ {
pico_trace("dcd_edpt_clear_stall %02x\n", ep_addr); pico_trace("dcd_edpt_clear_stall %02x\n", ep_addr);
assert(rhport == 0); assert(rhport == 0);
hw_endpoint_clear_stall(ep_addr);
}
if (tu_edpt_number(ep_addr))
{
struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
// clear stall also reset toggle to DATA0
// TODO check with double buffered
_hw_endpoint_buffer_control_clear_mask32(ep, USB_BUF_CTRL_STALL | USB_BUF_CTRL_DATA1_PID);
}
}
void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
{ {
@ -500,8 +478,8 @@ void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
void dcd_int_handler(uint8_t rhport) void dcd_int_handler(uint8_t rhport)
{ {
(void) rhport; (void) rhport;
dcd_rp2040_irq(); dcd_rp2040_irq();
} }
#endif #endif

View File

@ -61,8 +61,8 @@ static struct hw_endpoint ep_pool[1 + PICO_USB_HOST_INTERRUPT_ENDPOINTS];
// Flags we set by default in sie_ctrl (we add other bits on top) // Flags we set by default in sie_ctrl (we add other bits on top)
enum { enum {
SIE_CTRL_BASE = USB_SIE_CTRL_SOF_EN_BITS | USB_SIE_CTRL_KEEP_ALIVE_EN_BITS | SIE_CTRL_BASE = USB_SIE_CTRL_SOF_EN_BITS | USB_SIE_CTRL_KEEP_ALIVE_EN_BITS |
USB_SIE_CTRL_PULLDOWN_EN_BITS | USB_SIE_CTRL_EP0_INT_1BUF_BITS USB_SIE_CTRL_PULLDOWN_EN_BITS | USB_SIE_CTRL_EP0_INT_1BUF_BITS
}; };
static struct hw_endpoint *get_dev_ep(uint8_t dev_addr, uint8_t ep_addr) static struct hw_endpoint *get_dev_ep(uint8_t dev_addr, uint8_t ep_addr)
@ -360,6 +360,9 @@ bool hcd_init(uint8_t rhport)
// Reset any previous state // Reset any previous state
rp2040_usb_init(); rp2040_usb_init();
// Force VBUS detect to always present, for now we assume vbus is always provided (without using VBUS En)
usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
irq_set_exclusive_handler(USBCTRL_IRQ, hcd_rp2040_irq); irq_set_exclusive_handler(USBCTRL_IRQ, hcd_rp2040_irq);
// clear epx and interrupt eps // clear epx and interrupt eps

View File

@ -62,11 +62,7 @@ void rp2040_usb_init(void)
memset(usb_dpram, 0, sizeof(*usb_dpram)); memset(usb_dpram, 0, sizeof(*usb_dpram));
// Mux the controller to the onboard usb phy // Mux the controller to the onboard usb phy
usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS; usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS;
// Force VBUS detect so the device thinks it is plugged into a host
// TODO support VBUs detect
usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
} }
void hw_endpoint_reset_transfer(struct hw_endpoint *ep) void hw_endpoint_reset_transfer(struct hw_endpoint *ep)

View File

@ -42,7 +42,7 @@ struct hw_endpoint
// Buffer pointer in usb dpram // Buffer pointer in usb dpram
uint8_t *hw_data_buf; uint8_t *hw_data_buf;
// Have we been stalled // Have we been stalled TODO remove later
bool stalled; bool stalled;
// Current transfer information // Current transfer information