Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 63 additions & 13 deletions os/hal/ports/NUMICRO/LLD/USBv2/hal_usb_lld.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
#define NUC126_USBD_CFG_OUT (1UL << USBD_CFG_STATE_Pos)
#define NUC126_USBD_CFG_IN (2UL << USBD_CFG_STATE_Pos)

#define NUC126_USBD_INTSTS_EPEVT_Msk (0xFFUL << USBD_INTSTS_EPEVT0_Pos)

#define USBD_SRAM_BASE ((volatile uint8_t*)(USBD_BASE + 0x100))

#define NUC126_USBD_BUSSTATUS_INACK 0UL
Expand Down Expand Up @@ -100,6 +102,12 @@ static const USBEndpointConfig ep0config = {USB_EP_MODE_TYPE_CTRL,
*/
static uint32_t sram_free_dword_offset = 1UL;

/**
* @brief OUT endpoints whose last accepted packet was DATA1, one bit per
* logical endpoint. The hardware ACKs a repeated packet as new data.
*/
static uint32_t out_last_data1;

/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
Expand Down Expand Up @@ -187,6 +195,23 @@ size_t usb_memcpy(volatile void* destination, const volatile void* source,
static void usb_serve_out_endpoint(uint32_t epn)
{
USBDriver *const usbp = &USBD1;
uint32_t epsts = (USBD->EPSTS >> (USBD_EPSTS_EPSTS0_Pos + 3 * _HW_OUT_EPN(epn))) & 0x7UL;

if ((epsts == NUC126_USBD_BUSSTATUS_OUTDATA0ACK) ||
(epsts == NUC126_USBD_BUSSTATUS_OUTDATA1ACK)) {
uint32_t data1 = (epsts == NUC126_USBD_BUSSTATUS_OUTDATA1ACK) ? 1UL : 0UL;

/* Same toggle as the last accepted packet: a repeat (USB 2.0 8.6.4),
drop it and receive again into the same place */
if (((out_last_data1 >> epn) & 1UL) == data1) {
HW_OUT_EP(epn)->MXPLD = min(usbp->epc[epn]->out_maxsize,
usbp->epc[epn]->out_state->rxsize -
usbp->epc[epn]->out_state->rxcnt);
return;
}
out_last_data1 ^= (1UL << epn);
}

uint32_t mxpld = HW_OUT_EP(epn)->MXPLD;
uint32_t rxsize_actual = min(mxpld, usbp->epc[epn]->out_state->rxsize - usbp->epc[epn]->out_state->rxcnt);

Expand Down Expand Up @@ -270,6 +295,9 @@ static void usb_lld_serve_interrupt(USBDriver* usbp)
/* Bus reset */
USBD->ATTR |= (USBD_ATTR_PHYEN_Msk | USBD_ATTR_USBEN_Msk);
_usb_reset(usbp);
/* EP events read with the reset happened before it: drop them */
USBD->INTSTS = intsts & NUC126_USBD_INTSTS_EPEVT_Msk;
intsts &= ~NUC126_USBD_INTSTS_EPEVT_Msk;
}
if (bussts & USBD_ATTR_SUSPEND_Msk) {
/* Enable USB but disable PHY */
Expand All @@ -284,19 +312,8 @@ static void usb_lld_serve_interrupt(USBDriver* usbp)
}

if (intsts & USBD_INTSTS_USBIF_Msk) {
if (intsts & USBD_INTSTS_SETUP_Msk) {
/* Clear event flag */
USBD->INTSTS = USBD_INTSTS_SETUP_Msk;

/* Clear the data IN/OUT ready flag of control end-points */
HW_IN_EP(0)->CFGP |= USBD_CFGP_CLRRDY_Msk;
HW_OUT_EP(0)->CFGP |= USBD_CFGP_CLRRDY_Msk;

HW_IN_EP(0)->CFG |= USBD_CFG_DSQSYNC_Msk;
_usb_isr_invoke_setup_cb(&USBD1, 0);
}

/* EP events */
/* EP events, served before a SETUP of the same read because they belong
to the transfers before it */
if (intsts & USBD_INTSTS_EPEVT0_Msk) {
/* Clear event flag */
USBD->INTSTS = USBD_INTSTS_EPEVT0_Msk;
Expand Down Expand Up @@ -344,6 +361,20 @@ static void usb_lld_serve_interrupt(USBDriver* usbp)
USBD->INTSTS = (USBD_INTSTS_EPEVT7_Msk);
usb_serve_in_endpoint(LOGICAL_EPN(7));
}

if (intsts & USBD_INTSTS_SETUP_Msk) {
/* Clear event flag */
USBD->INTSTS = USBD_INTSTS_SETUP_Msk;

/* Clear the data IN/OUT ready flag and the STALL of control end-points */
HW_IN_EP(0)->CFGP = USBD_CFGP_CLRRDY_Msk;
HW_OUT_EP(0)->CFGP = USBD_CFGP_CLRRDY_Msk;

HW_IN_EP(0)->CFG |= USBD_CFG_DSQSYNC_Msk;
/* The data stage starts with DATA1 */
out_last_data1 &= ~1UL;
_usb_isr_invoke_setup_cb(&USBD1, 0);
}
}
}

Expand Down Expand Up @@ -479,6 +510,13 @@ void usb_lld_stop(USBDriver* usbp)
*/
void usb_lld_reset(USBDriver* usbp)
{
/* Disable every endpoint and clear its ready state, STALL and data
toggle */
for (uint8_t i = 0; i < NUC126_USB_HW_ENDPOINTS; ++i) {
USBD->EP[i].CFGP = USBD_CFGP_CLRRDY_Msk;
USBD->EP[i].CFG = 0;
}

sram_free_dword_offset = 1UL;
USBD->FADDR = 0;
/* EP0 initialization.*/
Expand Down Expand Up @@ -515,6 +553,13 @@ void usb_lld_init_endpoint(USBDriver* usbp, usbep_t ep)
"isochronous EP cannot be IN and OUT");
}

/* Cancel any ready transaction and clear the STALL: the Halt feature is
reset by SET_CONFIGURATION */
HW_OUT_EP(ep)->CFGP = USBD_CFGP_CLRRDY_Msk;
HW_IN_EP(ep)->CFGP = USBD_CFGP_CLRRDY_Msk;
/* The first OUT packet is DATA0 */
out_last_data1 |= (1UL << ep);

/* If the out logical endpoint is used */
if (usbp->epc[ep]->out_state) {
switch (usbp->epc[ep]->ep_mode) {
Expand Down Expand Up @@ -769,6 +814,9 @@ void usb_lld_clear_out(USBDriver* usbp, usbep_t ep)
{
(void)usbp;
HW_OUT_EP(ep)->CFGP &= ~USBD_CFGP_SSTALL_Msk;
/* The first packet after a halt is DATA0 */
HW_OUT_EP(ep)->CFG &= ~USBD_CFG_DSQSYNC_Msk;
out_last_data1 |= (1UL << ep);
}

/**
Expand All @@ -783,6 +831,8 @@ void usb_lld_clear_in(USBDriver* usbp, usbep_t ep)
{
(void)usbp;
HW_IN_EP(ep)->CFGP &= ~USBD_CFGP_SSTALL_Msk;
/* The first packet after a halt is DATA0 */
HW_IN_EP(ep)->CFG &= ~USBD_CFG_DSQSYNC_Msk;
}

#endif /* HAL_USE_USB */
Expand Down
3 changes: 2 additions & 1 deletion os/hal/ports/NUMICRO/LLD/USBv2/hal_usb_lld.h
Original file line number Diff line number Diff line change
Expand Up @@ -391,15 +391,16 @@ struct USBDriver {

/**
* @brief Start of host wake-up procedure.
* @note The PHY is off since SUSPEND. The RESUME bus event ends suspend.
*
* @notapi
*/
#define usb_lld_wakeup_host(usbp) \
do { \
USBD->ATTR |= USBD_ATTR_PHYEN_Msk; \
USBD->ATTR |= USBD_ATTR_RWAKEUP_Msk; \
osalThreadSleepMilliseconds(10); \
USBD->ATTR &= ~USBD_ATTR_RWAKEUP_Msk; \
_usb_wakeup(&USBD1); \
} while (0)

/*===========================================================================*/
Expand Down