diff --git a/bdk/usb/usbd.c b/bdk/usb/usbd.c index 8332d09..ad5fafa 100644 --- a/bdk/usb/usbd.c +++ b/bdk/usb/usbd.c @@ -443,6 +443,11 @@ static void _usb_device_power_down() usb_init_done = false; } +static void _usbd_disable_ep1() +{ + usbd_otg->regs->endptctrl[1] = 0; +} + static void _usbd_stall_reset_ep1(usb_dir_t direction, usb_ep_cfg_t stall) { stall &= 1; @@ -628,19 +633,23 @@ int usbd_flush_endpoint(u32 endpoint) return USB_RES_OK; } +static void _usb_reset_disable_ep1() +{ + usbd_flush_endpoint(USB_EP_ALL); + _usbd_stall_reset_ep1(USB_DIR_OUT, USB_EP_CFG_RESET); // EP1 Bulk OUT. + _usbd_stall_reset_ep1(USB_DIR_IN, USB_EP_CFG_RESET); // EP1 Bulk IN. + _usbd_disable_ep1(); + + usbd_otg->config_num = 0; + usbd_otg->interface_num = 0; + usbd_otg->configuration_set = false; + usbd_otg->max_lun_set = false; +} + void usbd_end(bool reset_ep, bool only_controller) { if (reset_ep) - { - usbd_flush_endpoint(USB_EP_ALL); - _usbd_stall_reset_ep1(USB_DIR_OUT, USB_EP_CFG_RESET); // EP1 Bulk OUT. - _usbd_stall_reset_ep1(USB_DIR_IN, USB_EP_CFG_RESET); // EP1 Bulk IN. - - usbd_otg->config_num = 0; - usbd_otg->interface_num = 0; - usbd_otg->configuration_set = false; - usbd_otg->max_lun_set = false; - } + _usb_reset_disable_ep1(); // Stop device controller. usbd_otg->regs->usbcmd &= ~USB2D_USBCMD_RUN; @@ -762,7 +771,7 @@ static int _usbd_ep_operation(usb_ep_t endpoint, u8 *buf, u32 len, u32 sync_time // Set buffers addresses to all page pointers. u32 dt_buffer_offset = dtd_idx * USB_TD_BUFFER_MAX_SIZE; for (u32 i = 0; i < 4; i++) - usbdaemon->dtds[dtd_ep_idx + dtd_idx].pages[i] = + usbdaemon->dtds[dtd_ep_idx + dtd_idx].pages[i] = !buf ? 0 : (u32)&buf[dt_buffer_offset + (USB_TD_BUFFER_PAGE_SIZE * i)]; //usbdaemon->dtds[dtd_ep_idx + dtd_idx].pages[5] = @@ -825,6 +834,7 @@ out: else if (_usbd_get_ep_status(endpoint) != USB_EP_STATUS_IDLE) res = USB_ERROR_XFER_ERROR; + // Invalidate data after OP is done. if (direction == USB_DIR_OUT) bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false); } diff --git a/bdk/usb/xusbd.c b/bdk/usb/xusbd.c index 394d5c2..ca6cb01 100644 --- a/bdk/usb/xusbd.c +++ b/bdk/usb/xusbd.c @@ -752,6 +752,51 @@ static int _xusbd_ep_initialize(u32 ep_idx) } } +static void _xusbd_ep1_disable(u32 ep_idx) +{ + volatile xusb_ep_ctx_t *ep_ctxt = &xusb_evtq->xusb_ep_ctxt[ep_idx]; + u32 ep_mask = BIT(ep_idx); + + switch (ep_idx) + { + case USB_EP_BULK_OUT: + case USB_EP_BULK_IN: + // Skip if already disabled. + if (!ep_ctxt->ep_state) + return; + + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) |= ep_mask; + + // Set EP state to disabled. + ep_ctxt->ep_state = EP_DISABLED; + + // Clear EP context. + memset((void *)ep_ctxt, 0, sizeof(xusb_ep_ctx_t)); + + // Wait for EP status to change. + _xusb_xhci_mask_wait(XUSB_DEV_XHCI_EP_STCHG, ep_mask, ep_mask, 1000); + + // Clear status change. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_STCHG) = ep_mask; + break; + } +} + +static void _xusb_disable_ep1() +{ + _xusbd_ep1_disable(USB_EP_BULK_OUT); + _xusbd_ep1_disable(USB_EP_BULK_IN); + + // Device mode stop. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_CTRL) &= ~XHCI_CTRL_RUN; + XUSB_DEV_XHCI(XUSB_DEV_XHCI_ST) |= XHCI_ST_RC; + + usbd_xotg->config_num = 0; + usbd_xotg->interface_num = 0; + usbd_xotg->max_lun_set = false; + usbd_xotg->device_state = XUSB_DEFAULT; +} + static void _xusb_init_phy() { // Configure and enable PLLU. @@ -841,11 +886,9 @@ static void _xusbd_init_device_clocks() int xusb_device_init() { - ///////////////////////////////////////////////// + // Disable USB2 device controller clocks. CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_USBD); CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = BIT(CLK_L_USBD); - ///////////////////////////////////////////////// - // Enable XUSB clock and clear Reset to XUSB Pad Control. CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = BIT(CLK_W_XUSB); @@ -927,6 +970,32 @@ int xusb_device_init() return USB_RES_OK; } +//! TODO: Power down more stuff. +static void _xusb_device_power_down() +{ + // Force UTMIP_PLL power down. + CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) |= BIT(4) | BIT(0); // UTMIP_FORCE_PD_SAMP_A/C_POWERDOWN. + + // Force enable UTMIPLL IDDQ. + CLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) |= 3; + + // Disable clocks for XUSB device and Super-Speed logic. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_SET) = BIT(CLK_U_XUSB_DEV); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_CLR) = BIT(CLK_U_XUSB_DEV); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = BIT(CLK_W_XUSB_SS); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = BIT(CLK_W_XUSB_SS); + + // Set XUSB_PADCTL clock reset. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = BIT(CLK_W_XUSB_PADCTL); + + // Disable XUSB clock. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = BIT(CLK_W_XUSB); + CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = BIT(CLK_W_XUSB); + + // Disable PLLU. + clock_disable_pllu(); +} + static int _xusb_queue_trb(u32 ep_idx, void *trb, bool ring_doorbell) { int res = USB_RES_OK; @@ -1903,16 +1972,16 @@ int xusb_device_enumerate(usb_gadget_type gadget) return USB_RES_OK; } -//! TODO: Do a full deinit. void xusb_end(bool reset_ep, bool only_controller) { - CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = BIT(CLK_W_XUSB_SS); - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = BIT(CLK_W_XUSB_SS); - CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_SET) = BIT(CLK_U_XUSB_DEV); - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_CLR) = BIT(CLK_U_XUSB_DEV); - CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = BIT(CLK_W_XUSB_PADCTL); - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = BIT(CLK_W_XUSB); - CLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = BIT(CLK_W_XUSB); + // Disable endpoints and stop device mode operation. + _xusb_disable_ep1(); + + // Disable device mode. + XUSB_DEV_XHCI(XUSB_DEV_XHCI_CTRL) &= ~XHCI_CTRL_ENABLE; + + //! TODO: Add only controller support? + _xusb_device_power_down(); } int xusb_handle_ep0_ctrl_setup()