rp2040 enable suspend and resume interrupt

This commit is contained in:
hathach 2021-08-11 20:06:57 +07:00
parent a5b464c5ca
commit f3a6e564ee
No known key found for this signature in database
GPG Key ID: 2FA891220FBFD581
3 changed files with 52 additions and 35 deletions

View File

@ -37,6 +37,14 @@
#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)
//
// Note: Line state when disconnected is very sensitive, in actual testing,
// it can toggles between J-state (idle) and SE1 if cable still connected to rp2040 (not connected to host)
#define FORCE_VBUS_DETECT 1
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
/* Low level controller /* Low level controller
*------------------------------------------------------------------*/ *------------------------------------------------------------------*/
@ -52,14 +60,14 @@ static struct hw_endpoint hw_endpoints[USB_MAX_ENDPOINTS][2] = {0};
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)
@ -290,7 +298,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,6 +316,7 @@ 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
if (status & USB_INTS_BUS_RESET_BITS) if (status & USB_INTS_BUS_RESET_BITS)
@ -322,7 +333,7 @@ static void dcd_rp2040_irq(void)
#endif #endif
} }
#if 0 #if 1
// TODO Enable SUSPEND & RESUME interrupt and test later on with/without VBUS detection // 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)
@ -364,36 +375,43 @@ 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 memset(hw_endpoints, 0, sizeof(hw_endpoints));
hw_endpoint_init(0x0, 64, TUSB_XFER_CONTROL); next_buffer_ptr = &usb_dpram->epx_data[0];
// EP0 IN
hw_endpoint_init(0x80, 64, TUSB_XFER_CONTROL);
// Initializes the USB peripheral for device mode and enables it. // EP0 always exists so init it now
// Don't need to enable the pull up here. Force VBUS // EP0 OUT
usb_hw->main_ctrl = USB_MAIN_CTRL_CONTROLLER_EN_BITS; hw_endpoint_init(0x0, 64, TUSB_XFER_CONTROL);
// EP0 IN
hw_endpoint_init(0x80, 64, TUSB_XFER_CONTROL);
// 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)

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)