/** @file Implementation of XDCI APIs. @copyright INTEL CONFIDENTIAL Copyright 2015 - 2020 Intel Corporation. The source code contained or described herein and all documents related to the source code ("Material") are owned by Intel Corporation or its suppliers or licensors. Title to the Material remains with Intel Corporation or its suppliers and licensors. The Material may contain trade secrets and proprietary and confidential information of Intel Corporation and its suppliers and licensors, and is protected by worldwide copyright and trade secret laws and treaty provisions. No part of the Material may be used, copied, reproduced, modified, published, uploaded, posted, transmitted, distributed, or disclosed in any way without Intel's prior express written permission. No license under any patent, copyright, trade secret or other intellectual property right is granted to or conferred upon you by disclosure or delivery of the Materials, either expressly, by implication, inducement, estoppel or otherwise. Any license under such intellectual property rights must be express and approved by Intel in writing. Unless otherwise agreed by Intel in writing, you may not remove or alter this notice or any other notice embedded in Materials by Intel or Intel's suppliers or licensors in any way. This file contains a 'Sample Driver' and is licensed as such under the terms of your license agreement with Intel or your vendor. This file may be modified by the user, subject to the additional terms of the license agreement. @par Specification Reference: **/ #include "UsbDeviceMode.h" #include "XdciInterface.h" #include "XdciDWC.h" #if defined(_MSC_VER) /* MSVC Compiler section */ #pragma optimize ("", off) #endif UINT32 usb_reg_read ( IN UINTN base, IN UINT32 offset ) { volatile UINT32 *addr = (volatile UINT32 *)(UINTN)(base + offset); return *addr; } VOID usb_reg_write ( IN UINTN base, IN UINT32 offset, IN UINT32 val ) { volatile UINT32 *addr = (volatile UINT32 *)(UINTN)(base + offset); *addr = val; } /** Internal utility function: This function is used to obtain physical endpoint number xDCI needs physical endpoint number for EP registers We also use it to index into our EP array Note: Certain data structures/commands use logical EP numbers as opposed to physical endpoint numbers so one should be careful when interpreting EP numbers @ep_num: Logical endpoint number @ep_dir: Direction for the endpoint **/ STATIC UINT32 dwc_xdci_get_physical_ep_num ( IN UINT32 EndpointNum, IN USB_EP_DIR EndpointDir ) { return EndpointDir? ((EndpointNum << 1) | EndpointDir) : (EndpointNum << 1); } /** Internal utility function: This function is used to obtain the MPS for control transfers based on the speed. If this is called before bus reset completes then it returns MPS based on desired speed. If it is after bus reset then MPS returned is based on actual negotiated speed @core_handle: xDCI controller handle address @mps: address of 32-bit variable to return the MPS **/ STATIC EFI_STATUS dwc_xdci_core_get_ctrl_mps ( IN XDCI_CORE_HANDLE *core_handle, IN UINT32 *mps ) { if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "ERROR: dwc_xdci_core_get_ctrl_mps: INVALID handle\n")); return EFI_DEVICE_ERROR; } if (mps == NULL) { DEBUG ((DEBUG_INFO, "ERROR: dwc_xdci_core_get_ctrl_mps: INVALID parameter\n")); return EFI_INVALID_PARAMETER; } switch (core_handle->actual_speed) { case USB_SPEED_HIGH: *mps = DWC_XDCI_HS_CTRL_EP_MPS; break; case USB_SPEED_FULL: *mps = DWC_XDCI_FS_CTRL_EP_MPS; break; case USB_SPEED_LOW: *mps = DWC_XDCI_LS_CTRL_EP_MPS; break; case USB_SPEED_SUPER: *mps = DWC_XDCI_SS_CTRL_EP_MPS; break; default: *mps = 0; DEBUG ((DEBUG_INFO, "ERROR: dwc_xdci_core_get_ctrl_mps: UNKNOWN speed\n")); break; } return EFI_SUCCESS; } /** Internal utility function: This function is used to initialize the parameters required for executing endpoint command @core_handle: xDCI controller handle address @ep_info: EP info address @config_action: Configuration action specific to EP command @ep_cmd: xDCI EP command for which parameters are initialized @ep_cmd_params: address of struct to return EP params **/ STATIC EFI_STATUS dwc_xdci_core_init_ep_cmd_params ( IN XDCI_CORE_HANDLE *core_handle, IN USB_EP_INFO *ep_info, IN UINT32 config_action, IN DWC_XDCI_ENDPOINT_CMD ep_cmd, IN DWC_XDCI_ENDPOINT_CMD_PARAMS *ep_cmd_params ) { EFI_STATUS status = EFI_SUCCESS; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "ERROR: dwc_xdci_core_init_ep_cmd_params: INVALID handle\n")); return EFI_DEVICE_ERROR; } /* Reset params */ ep_cmd_params->param0 = ep_cmd_params->param1 = ep_cmd_params->param2 = 0; switch (ep_cmd) { case EPCMD_SET_EP_CONFIG: /* Issue DEPCFG command for EP */ /* Issue a DEPCFG (Command 1) command for endpoint */ if (ep_info->max_streams) { ep_cmd_params->param1 = DWC_XDCI_PARAM1_SET_EP_CFG_STRM_CAP_MASK; } if (ep_info->interval) { ep_cmd_params->param1 |= ((ep_info->interval-1) << DWC_XDCI_PARAM1_SET_EP_CFG_BINTM1_BIT_POS); } /* Set EP num */ ep_cmd_params->param1 |= (ep_info->ep_num << DWC_XDCI_PARAM1_SET_EP_CFG_EP_NUM_BIT_POS); /* Set EP direction */ ep_cmd_params->param1 |= (ep_info->ep_dir << DWC_XDCI_PARAM1_SET_EP_CFG_EP_DIR_BIT_POS); /* Set EP-specific Event enable for not ready and * complete events */ ep_cmd_params->param1 &= ~DWC_XDCI_PARAM1_SET_EP_CFG_EVT_EN_MASK; /* Setup the events we want enabled for this EP */ ep_cmd_params->param1 |= (DWC_XDCI_PARAM1_SET_EP_CFG_EVT_XFER_NRDY_MASK | DWC_XDCI_PARAM1_SET_EP_CFG_EVT_XFER_IN_PRG_MASK | DWC_XDCI_PARAM1_SET_EP_CFG_EVT_XFER_CMPLT_MASK); /* We only have one interrupt line for this core. * Set interrupt number to 0 */ ep_cmd_params->param1 &= ~DWC_XDCI_PARAM1_SET_EP_CFG_INTR_NUM_MASK; /* Set FIFOnum = 0 for control EP0 */ ep_cmd_params->param0 &= ~DWC_XDCI_PARAM0_SET_EP_CFG_FIFO_NUM_MASK; /* Program FIFOnum for non-EP0 EPs */ if (ep_info->ep_num && ep_info->ep_dir) { ep_cmd_params->param0 |= (ep_info->ep_num << DWC_XDCI_PARAM0_SET_EP_CFG_FIFO_NUM_BIT_POS); } /* Program max packet size */ ep_cmd_params->param0 &= ~DWC_XDCI_PARAM0_SET_EP_CFG_MPS_MASK; ep_cmd_params->param0 |= (ep_info->max_pkt_size << DWC_XDCI_PARAM0_SET_EP_CFG_MPS_BIT_POS); /* Set Burst size. 0 means burst size of 1 */ ep_cmd_params->param0 &= ~DWC_XDCI_PARAM0_SET_EP_CFG_BRST_SIZE_MASK; ep_cmd_params->param0 |= (ep_info->burst_size << DWC_XDCI_PARAM0_SET_EP_CFG_BRST_SIZE_BIT_POS); /* Set EP type */ ep_cmd_params->param0 &= ~DWC_XDCI_PARAM0_SET_EP_CFG_EP_TYPE_MASK; ep_cmd_params->param0 |= (ep_info->ep_type << DWC_XDCI_PARAM0_SET_EP_CFG_EP_TYPE_BIT_POS); /* Set config action */ ep_cmd_params->param0 &= ~DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_MASK; ep_cmd_params->param0 |= (config_action << DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_BIT_POS); break; case EPCMD_SET_EP_XFER_RES_CONFIG: /* Set param0 to 1. Same for all EPs when resource * configuration is done */ ep_cmd_params->param0 = 1; break; case EPCMD_END_XFER: /* Nothing to set. Already reset params for all cmds */ break; case EPCMD_START_NEW_CONFIG: /* Nothing to set. Already reset params for all cmds */ break; default: status = EFI_INVALID_PARAMETER; DEBUG ((DEBUG_INFO, "\ndwc_xdci_core_init_ep_cmd_params: INVALID Parameter")); break; } return status; } /** Internal utility function: This function is used to issue the xDCI endpoint command @core_handle: xDCI controller handle address @ep_num: Physical EP num @ep_cmd: xDCI EP command @ep_cmd_params: EP command parameters address **/ STATIC EFI_STATUS dwc_xdci_core_issue_ep_cmd ( IN XDCI_CORE_HANDLE *core_handle, IN UINT32 ep_num, IN UINT32 ep_cmd, IN DWC_XDCI_ENDPOINT_CMD_PARAMS *ep_cmd_params ) { UINTN base_addr; UINT32 max_delay_iter = 5000;//DWC_XDCI_MAX_DELAY_ITERATIONS; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "ERROR: dwc_xdci_core_issue_ep_cmd: INVALID handle\n")); return EFI_DEVICE_ERROR; } base_addr = core_handle->base_address; /* Set EP command parameter values */ usb_reg_write ( base_addr, DWC_XDCI_EPCMD_PARAM2_REG(ep_num), ep_cmd_params->param2 ); usb_reg_write ( base_addr, DWC_XDCI_EPCMD_PARAM1_REG(ep_num), ep_cmd_params->param1 ); usb_reg_write ( base_addr, DWC_XDCI_EPCMD_PARAM0_REG(ep_num), ep_cmd_params->param0 ); /* Set the command code and activate it */ usb_reg_write ( base_addr, DWC_XDCI_EPCMD_REG(ep_num), ep_cmd | DWC_XDCI_EPCMD_CMD_ACTIVE_MASK ); /* Wait until command completes */ do { if (!(usb_reg_read (base_addr, DWC_XDCI_EPCMD_REG(ep_num)) & DWC_XDCI_EPCMD_CMD_ACTIVE_MASK)) break; else gBS->Stall (DWC_XDCI_MAX_DELAY_ITERATIONS); } while (--max_delay_iter); if (!max_delay_iter) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_issue_ep_cmd. ERROR: Failed to issue Command 0x%08x\n",\ usb_reg_read (base_addr, DWC_XDCI_EPCMD_REG(ep_num)) )); return EFI_DEVICE_ERROR; } return EFI_SUCCESS; } /** Internal utility function: This function is used to flush all FIFOs @core_handle: xDCI controller handle address **/ STATIC EFI_STATUS dwc_xdci_core_flush_all_fifos ( IN XDCI_CORE_HANDLE *core_handle ) { UINTN base_addr; UINT32 max_delay_iter = DWC_XDCI_MAX_DELAY_ITERATIONS; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "ERROR: dwc_xdci_core_flush_all_fifos: INVALID handle\n")); return EFI_DEVICE_ERROR; } base_addr = core_handle->base_address; /* Write the command to flush all FIFOs */ usb_reg_write( base_addr, DWC_XDCI_DGCMD_REG, (usb_reg_read (base_addr, DWC_XDCI_DGCMD_REG) | DWC_XDCI_DGCMD_CMD_ALL_FIFO_FLUSH | DWC_XDCI_DGCMD_CMD_ACTIVE_MASK) ); /* Wait until command completes */ do { if (!(usb_reg_read (base_addr, DWC_XDCI_DGCMD_REG) & DWC_XDCI_DGCMD_CMD_ACTIVE_MASK)) break; else gBS->Stall (DWC_XDCI_MAX_DELAY_ITERATIONS); } while (--max_delay_iter); if (!max_delay_iter) { DEBUG ((DEBUG_INFO, "Failed to issue Command\n")); return EFI_DEVICE_ERROR; } return EFI_SUCCESS; } /** Internal utility function: This function is used to flush Tx FIFO specific to an endpoint @core_handle: xDCI controller handle address @ep_num: Physical EP num **/ STATIC EFI_STATUS dwc_xdci_core_flush_ep_tx_fifo ( IN XDCI_CORE_HANDLE *core_handle, IN UINT32 ep_num ) { UINTN base_addr; UINT32 max_delay_iter = DWC_XDCI_MAX_DELAY_ITERATIONS; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "ERROR: dwc_xdci_core_flush_ep_tx_fifo: INVALID handle\n")); return EFI_DEVICE_ERROR; } base_addr = core_handle->base_address; /* TODO: Currently we are only using TxFIFO 0. Later map these * Write the FIFO num/dir param for the generic command. */ usb_reg_write ( base_addr, DWC_XDCI_DGCMD_PARAM_REG, ((usb_reg_read (base_addr, DWC_XDCI_DGCMD_PARAM_REG) & ~DWC_XDCI_DGCMD_PARAM_TX_FIFO_NUM_MASK) | DWC_XDCI_DGCMD_PARAM_TX_FIFO_DIR_MASK) ); /* Write the command to flush all FIFOs */ usb_reg_write ( base_addr, DWC_XDCI_DGCMD_REG, (usb_reg_read(base_addr, DWC_XDCI_DGCMD_REG) | DWC_XDCI_DGCMD_CMD_SEL_FIFO_FLUSH | DWC_XDCI_DGCMD_CMD_ACTIVE_MASK) ); /* Wait until command completes */ do { if (!(usb_reg_read(base_addr, DWC_XDCI_DGCMD_REG) & DWC_XDCI_DGCMD_CMD_ACTIVE_MASK)) break; else gBS->Stall (DWC_XDCI_MAX_DELAY_ITERATIONS); } while (--max_delay_iter); if (!max_delay_iter) { DEBUG ((DEBUG_INFO, "Failed to issue Command\n")); return EFI_DEVICE_ERROR; } core_handle->ep_handles[ep_num].state = USB_EP_STATE_ENABLED; return EFI_SUCCESS; } STATIC EFI_STATUS dwc_xdci_core_prepare_one_trb ( IN DWC_XDCI_TRB *trb, IN DWC_XDCI_TRB_CONTROL trb_ctrl, IN UINT32 LastBit, IN UINT32 ChainBit, IN UINT8 *buffer_ptr, IN UINT32 size ) { DEBUG ((DEBUG_INFO, "trb is 0x%x, buffer_ptr is 0x%x, size is 0x%x\n", trb, buffer_ptr, size)); trb->buff_ptr_low = (UINT32)(UINTN)buffer_ptr; trb->buff_ptr_high = 0; trb->len_xfer_params = size; trb->trb_ctrl = trb_ctrl << DWC_XDCI_TRB_CTRL_TYPE_BIT_POS; if (ChainBit) trb->trb_ctrl |= ChainBit << DWC_XDCI_TRB_CTRL_CHAIN_BUFF_BIT_POS; if (LastBit) trb->trb_ctrl |= LastBit << DWC_XDCI_TRB_CTRL_LST_TRB_BIT_POS; trb->trb_ctrl |= DWC_XDCI_TRB_CTRL_IOSP_MISOCH_MASK| DWC_XDCI_TRB_CTRL_HWO_MASK; DEBUG ((DEBUG_INFO, "(dwc_xdci_core_prepare_one_trb) ptr_low = 0x%x, ptr_high = 0x%x, len_params is 0x%x, trb_ctrl is 0x%x\n", trb->buff_ptr_low, trb->buff_ptr_high, trb->len_xfer_params, (UINT32)trb->trb_ctrl)); return EFI_SUCCESS; } /** Internal utility function: This function is used to initialize transfer request block @core_handle: xDCI controller handle address @trb: Address of TRB to initialize @trb_ctrl: TRB control value @buff_ptr: Transfer buffer address @size: Size of the transfer **/ STATIC EFI_STATUS dwc_xdci_core_init_trb ( IN XDCI_CORE_HANDLE *core_handle, IN DWC_XDCI_TRB *trb, IN DWC_XDCI_TRB_CONTROL trb_ctrl, IN UINT8 *buffer_ptr, IN UINT32 size ) { #define ONE_TRB_SIZE (DWC_XDCI_TRB_BUFF_SIZE_MASK & 0x00F00000) UINT8 *TrbBuffer; UINT32 TrbCtrlLast; UINT32 TrbCtrlChain; UINT32 TrbIndex; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "ERROR: dwc_xdci_core_init_trb: INVALID handle\n")); return EFI_DEVICE_ERROR; } if (trb == NULL) { DEBUG ((DEBUG_INFO, "ERROR: dwc_xdci_core_init_trb: INVALID handle\n")); return EFI_INVALID_PARAMETER; } /* Init TRB fields * NOTE: Assuming we are only using 32-bit addresses * TODO: update for 64-bit addresses */ if (size <= DWC_XDCI_TRB_BUFF_SIZE_MASK) { // // Can transfer in one TRB // TrbCtrlChain = 0; TrbCtrlLast = 1; dwc_xdci_core_prepare_one_trb (trb, trb_ctrl, TrbCtrlLast, TrbCtrlChain, buffer_ptr, size); return EFI_SUCCESS; } // // Can't transfer in one TRB. // Seperate it in every ONE_TRB_SIZE of TRB // TrbBuffer = buffer_ptr; TrbIndex = 0; while (size > ONE_TRB_SIZE) { TrbCtrlChain = 1; TrbCtrlLast = 0; dwc_xdci_core_prepare_one_trb (trb, trb_ctrl, TrbCtrlLast, TrbCtrlChain, TrbBuffer, ONE_TRB_SIZE); TrbBuffer += ONE_TRB_SIZE; size -= ONE_TRB_SIZE; trb++; TrbIndex++; if (TrbIndex >= DWC_XDCI_TRB_NUM) return EFI_OUT_OF_RESOURCES; } TrbCtrlChain = 0; TrbCtrlLast = 1; dwc_xdci_core_prepare_one_trb (trb, trb_ctrl, TrbCtrlLast, TrbCtrlChain, TrbBuffer, size); return EFI_SUCCESS; } /** Internal function: This function is used to start a SETUP phase on control endpoint @core_handle: xDCI controller handle address **/ STATIC EFI_STATUS dwc_xdci_core_start_ep0_setup_xfer ( IN XDCI_CORE_HANDLE *core_handle ) { DWC_XDCI_ENDPOINT_CMD_PARAMS ep_cmd_params; EFI_STATUS status = EFI_DEVICE_ERROR; DWC_XDCI_TRB *trb; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "ERROR: dwc_xdci_core_start_ep0_setup_xfer: INVALID handle\n")); return EFI_DEVICE_ERROR; } if (core_handle->ep_handles[0].state == USB_EP_STATE_SETUP) { DEBUG ((DEBUG_INFO, "EP0 was already in SETUP phase\n")); return EFI_SUCCESS; } core_handle->ep_handles[0].state = USB_EP_STATE_SETUP; trb = core_handle->trbs; DEBUG ((DEBUG_INFO, "(dwc_xdci_core_start_ep0_setup_xfer)\n")); status = dwc_xdci_core_init_trb ( core_handle, trb, TRBCTL_SETUP, core_handle->aligned_setup_buffer, 8 ); if (status) return status; // // Issue a DEPSTRTXFER for EP0 // Reset params // ep_cmd_params.param0 = ep_cmd_params.param1 = ep_cmd_params.param2 = 0; // // Init the lower re-bits for TRB address // ep_cmd_params.param1 = (UINT32)(UINTN)trb; // // Issue the command to start transfer on physical // endpoint 0 // status = dwc_xdci_core_issue_ep_cmd ( core_handle, 0, EPCMD_START_XFER, &ep_cmd_params ); /* Save new resource index for this transfer */ core_handle->ep_handles[0].currentXferRscIdx = ((usb_reg_read ( core_handle->base_address, DWC_XDCI_EPCMD_REG(0)) & DWC_XDCI_EPCMD_RES_IDX_MASK) >> DWC_XDCI_EPCMD_RES_IDX_BIT_POS ); return status; } /** Internal function: This function is used to process the state change event @core_handle: xDCI controller handle address @event: device event dword **/ STATIC EFI_STATUS dwc_xdci_process_device_state_change_event ( IN XDCI_CORE_HANDLE *core_handle, IN UINT32 event ) { if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "ERROR: dwc_xdci_process_device_state_change_event: INVALID handle\n")); return EFI_DEVICE_ERROR; } core_handle->hird_val = (event & DWC_XDCI_EVENT_BUFF_DEV_HIRD_MASK) >> DWC_XDCI_EVENT_BUFF_DEV_HIRD_BIT_POS; core_handle->link_state = ((event & DWC_XDCI_EVENT_BUFF_DEV_LINK_STATE_MASK) >> DWC_XDCI_EVENT_BUFF_DEV_LINK_STATE_BIT_POS); if (core_handle->event_callbacks.dev_link_state_callback) { core_handle->event_callbacks.cb_event_params.parent_handle = core_handle->parent_handle; core_handle->event_callbacks.cb_event_params.link_state = core_handle->link_state; core_handle->event_callbacks.cb_event_params.hird = core_handle->hird_val; core_handle->event_callbacks.cb_event_params.ss_event = (event & DWC_XDCI_EVENT_BUFF_DEV_SS_EVENT_MASK) ? 1 : 0; core_handle->event_callbacks.dev_link_state_callback (&core_handle->event_callbacks.cb_event_params); } return EFI_SUCCESS; } /** Internal function: This function is used to issue a command to end transfer @core_handle: xDCI controller handle address @ep_num: Physical EP num for which transfer is to be ended **/ STATIC EFI_STATUS dwc_xdci_end_xfer ( IN XDCI_CORE_HANDLE *core_handle, IN UINT32 ep_num ) { EFI_STATUS status; DWC_XDCI_ENDPOINT_CMD_PARAMS ep_cmd_params; UINT32 cmd_params; DWC_XDCI_TRB *TrbPtr; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "ERROR: dwc_xdci_end_xfer: INVALID handle\n")); return EFI_DEVICE_ERROR; } core_handle->ep_handles[ep_num].CheckFlag = FALSE; /* Issue a DEPENDXFER for EP */ /* Reset params */ ep_cmd_params.param0 = ep_cmd_params.param1 = ep_cmd_params.param2 = 0; cmd_params = ((core_handle->ep_handles[ep_num].currentXferRscIdx << DWC_XDCI_EPCMD_RES_IDX_BIT_POS) | DWC_XDCI_EPCMD_FORCE_RM_MASK); if (core_handle->ep_handles[ep_num].currentXferRscIdx == 0) { return EFI_SUCCESS; } /* Issue the command */ status = dwc_xdci_core_issue_ep_cmd( core_handle, ep_num, cmd_params | DWC_XDCI_EPCMD_END_XFER, &ep_cmd_params ); if (!status) { core_handle->ep_handles[ep_num].currentXferRscIdx = 0; TrbPtr = core_handle->trbs + (ep_num * DWC_XDCI_TRB_NUM); ZeroMem (TrbPtr, DWC_XDCI_TRB_NUM * sizeof (DWC_XDCI_TRB)); } return status; } /** Internal function: This function is used to process bus reset detection event @core_handle: xDCI controller handle address **/ STATIC EFI_STATUS dwc_xdci_process_device_reset_det ( IN XDCI_CORE_HANDLE *core_handle ) { EFI_STATUS status = EFI_SUCCESS; if (core_handle == NULL) { return EFI_DEVICE_ERROR; } /* Flush all FIFOs */ status = dwc_xdci_core_flush_all_fifos(core_handle); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_process_device_reset_det: Failed to flush FIFOs\n")); } /* NOTE: Not treating flush FIFOs status to be fatal */ /* Start SETUP phase on EP0 */ status = dwc_xdci_core_start_ep0_setup_xfer(core_handle); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_process_device_reset_det: Failed to start SETUP phase for EP0\n")); return status; } /* Notify upper layer if a callback is registerd for * this event */ if (core_handle->event_callbacks.dev_bus_reset_callback) { core_handle->event_callbacks.cb_event_params.parent_handle = core_handle->parent_handle; status = core_handle->event_callbacks.dev_bus_reset_callback (&core_handle->event_callbacks.cb_event_params); } return status; } /** Internal function: This function is used to process connection done (means reset complete) event @core_handle: xDCI controller handle address **/ STATIC EFI_STATUS dwc_xdci_process_device_reset_done ( IN XDCI_CORE_HANDLE *core_handle ) { DWC_XDCI_ENDPOINT_CMD_PARAMS ep_cmd_params; UINTN base_addr; EFI_STATUS status = EFI_SUCCESS; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "ERROR: dwc_xdci_process_device_reset_done: INVALID handle\n")); return EFI_DEVICE_ERROR; } base_addr = core_handle->base_address; core_handle->actual_speed = (usb_reg_read (base_addr, DWC_XDCI_DSTS_REG) & DWC_XDCI_DSTS_CONN_SPEED_MASK); DEBUG ((DEBUG_INFO, "dwc_xdci_process_device_reset_done core_handle->actual_speed is %x\n", core_handle->actual_speed)); /* Program MPS based on the negotiated speed */ dwc_xdci_core_get_ctrl_mps (core_handle, &core_handle->ep_handles[0].ep_info.max_pkt_size); dwc_xdci_core_get_ctrl_mps (core_handle, &core_handle->ep_handles[1].ep_info.max_pkt_size); /* Init DEPCFG cmd params for EP0 */ status = dwc_xdci_core_init_ep_cmd_params ( core_handle, &core_handle->ep_handles[0].ep_info, DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_MDFY_STATE, EPCMD_SET_EP_CONFIG, &ep_cmd_params ); if (status) { return status; } /* Issue the command */ status = dwc_xdci_core_issue_ep_cmd ( core_handle, 0, EPCMD_SET_EP_CONFIG, &ep_cmd_params ); if (status) { return status; } /* Init DEPCFG cmd params for EP1 */ status = dwc_xdci_core_init_ep_cmd_params ( core_handle, &core_handle->ep_handles[1].ep_info, DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_MDFY_STATE, EPCMD_SET_EP_CONFIG, &ep_cmd_params ); /* Issue the command */ status = dwc_xdci_core_issue_ep_cmd ( core_handle, 1, EPCMD_SET_EP_CONFIG, &ep_cmd_params ); /* Put the other PHY into suspend */ if (core_handle->actual_speed == USB_SPEED_SUPER) { /* Put HS PHY to suspend */ usb_reg_write ( base_addr, DWC_XDCI_GUSB2PHYCFG_REG (0), (usb_reg_read (base_addr, DWC_XDCI_GUSB2PHYCFG_REG(0)) | DWC_XDCI_GUSB2PHYCFG_SUSPEND_PHY_MASK) ); /* SS PHY's suspend mask */ usb_reg_write ( base_addr, DWC_XDCI_GUSB3PIPECTL_REG (0), (usb_reg_read (base_addr, DWC_XDCI_GUSB3PIPECTL_REG(0)) | DWC_XDCI_GUSB3PIPECTL_SUSPEND_PHY_MASK) ); } else { /* Put SS PHY to suspend */ usb_reg_write ( base_addr, DWC_XDCI_GUSB3PIPECTL_REG(0), (usb_reg_read(base_addr, DWC_XDCI_GUSB3PIPECTL_REG(0)) | DWC_XDCI_GUSB3PIPECTL_SUSPEND_PHY_MASK) ); /* Clear HS PHY's suspend mask */ usb_reg_write ( base_addr, DWC_XDCI_GUSB2PHYCFG_REG(0), (usb_reg_read(base_addr, DWC_XDCI_GUSB2PHYCFG_REG(0)) & ~DWC_XDCI_GUSB2PHYCFG_SUSPEND_PHY_MASK) ); } /* Notify upper layer if callback is registered */ if (core_handle->event_callbacks.dev_reset_done_callback) { core_handle->event_callbacks.cb_event_params.parent_handle = core_handle->parent_handle; core_handle->event_callbacks.cb_event_params.speed = core_handle->actual_speed; core_handle->event_callbacks.dev_reset_done_callback (&core_handle->event_callbacks.cb_event_params); } return status; } /** Internal function: This function is used to process device event @core_handle: xDCI controller handle address @int_line_event_buffer: event buffer pointing to device event @processed_event_size: address of variable to save the size of the event that was processed **/ STATIC EFI_STATUS dwc_xdci_process_device_event ( IN XDCI_CORE_HANDLE *core_handle, IN DWC_XDCI_EVENT_BUFFER *int_line_event_buffer, IN UINT32 *processed_event_size ) { UINT32 event; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "ERROR: dwc_xdci_process_device_event: INVALID handle\n")); return EFI_DEVICE_ERROR; } /* Extract device event */ event = (int_line_event_buffer->event & DWC_XDCI_EVENT_BUFF_DEV_EVT_MASK); event >>= DWC_XDCI_EVENT_BUFF_DEV_EVT_BIT_POS; /* Assume default event size. Change it in switch case if * different */ *processed_event_size = DWC_XDCI_DEV_EVENT_DEFAULT_SIZE_IN_BYTES; switch (event) { case DWC_XDCI_EVENT_BUFF_DEV_DISCONN_EVENT: DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_DISCONN_EVENT\n")); break; case DWC_XDCI_EVENT_BUFF_DEV_USB_RESET_EVENT: DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_USB_RESET_EVENT\n")); dwc_xdci_process_device_reset_det (core_handle); break; case DWC_XDCI_EVENT_BUFF_DEV_CONN_DONE_EVENT: DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_CONN_DONE_EVENT\n")); dwc_xdci_process_device_reset_done (core_handle); break; case DWC_XDCI_EVENT_BUFF_DEV_STATE_CHANGE_EVENT: DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_STATE_CHANGE_EVENT\n")); dwc_xdci_process_device_state_change_event (core_handle, int_line_event_buffer->event); break; case DWC_XDCI_EVENT_BUFF_DEV_WKUP_EVENT: DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_WKUP_EVENT\n")); break; case DWC_XDCI_EVENT_BUFF_DEV_HBRNTN_REQ_EVENT: DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_HBRNTN_REQ_EVENT\n")); break; case DWC_XDCI_EVENT_BUFF_DEV_SOF_EVENT: DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_SOF_EVENT\n")); break; case DWC_XDCI_EVENT_BUFF_DEV_ERRATIC_ERR_EVENT: DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_ERRATIC_ERR_EVENT\n")); break; case DWC_XDCI_EVENT_BUFF_DEV_CMD_CMPLT_EVENT: DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_CMD_CMPLT_EVENT\n")); break; case DWC_XDCI_EVENT_BUFF_DEV_BUFF_OVFL_EVENT: DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_BUFF_OVFL_EVENT\n")); break; case DWC_XDCI_EVENT_BUFF_DEV_TST_LMP_RX_EVENT: DEBUG ((DEBUG_INFO, "Device DWC_XDCI_EVENT_BUFF_DEV_TST_LMP_RX_EVENT\n")); *processed_event_size = DWC_XDCI_DEV_EVENT_TST_LMP_SIZE_IN_BYTES; break; default: DEBUG ((DEBUG_INFO, "dwc_xdci_process_device_event: UNHANDLED device event: %x\n", event)); break; } return EFI_SUCCESS; } /** Internal function: This function is used to process EP not ready for non-control endpoints @core_handle: xDCI controller handle address @ep_num: Physical endpoint number **/ STATIC EFI_STATUS dwc_xdci_process_ep_xfer_not_ready ( IN XDCI_CORE_HANDLE *core_handle, IN UINT32 ep_num ) { /* TODO: Not doing on-demand transfers * Revisit if required for later use */ return EFI_SUCCESS; } /** Internal function: This function is used to process EP not ready for control endpoints @core_handle: xDCI controller handle address @ep_num: Physical endpoint number @data_stage: EP not ready when data stage token was received @status_stage: EP not ready when status stage token was received **/ STATIC EFI_STATUS dwc_xdci_process_ep0_xfer_not_ready ( IN XDCI_CORE_HANDLE *core_handle, IN UINT32 ep_num, IN UINT32 ep_event_status ) { USB_EP_STATE ep_state = USB_EP_STATE_SETUP; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "ERROR: dwc_xdci_process_ep0_xfer_not_ready: INVALID handle\n")); return EFI_DEVICE_ERROR; } /* Is it data stage or status stage */ if (ep_event_status & DWC_XDCI_EVENT_BUFF_EP_CTRL_DATA_REQ_MASK) { ep_state = USB_EP_STATE_DATA; } else if (ep_event_status & DWC_XDCI_EVENT_BUFF_EP_CTRL_STATUS_REQ_MASK) { ep_state = USB_EP_STATE_STATUS; } if ((ep_num == 0) && (ep_state == USB_EP_STATE_STATUS)) { if (ep_event_status & DWC_XDCI_EVENT_BUFF_EP_XFER_ACTIVE_MASK) { DEBUG ((DEBUG_INFO, "XFER_ACTIVE\n")); } else { DEBUG ((DEBUG_INFO, "XFER_NOT_ACTIVE\n")); } dwc_xdci_ep0_receive_status_pkt (core_handle); } /* Notify upper layer if a callback is registered for * this event */ if (core_handle->event_callbacks.dev_xfer_nrdy_callback) { core_handle->event_callbacks.cb_event_params.parent_handle = core_handle->parent_handle; core_handle->event_callbacks.cb_event_params.ep_state = ep_state; core_handle->event_callbacks.dev_xfer_nrdy_callback (&core_handle->event_callbacks.cb_event_params); } return EFI_SUCCESS; } /** Internal function: This function is used to process transfer phone done for EP0 @core_handle: xDCI controller handle address @ep_num: Physical endpoint number (0 for OUT and 1 for IN) **/ STATIC EFI_STATUS dwc_xdci_process_ep0_xfer_phase_done ( IN XDCI_CORE_HANDLE *core_handle, IN UINT32 ep_num ) { DWC_XDCI_ENDPOINT *ep_handle; DWC_XDCI_TRB *trb; EFI_STATUS status = EFI_SUCCESS; UINT32 trb_sts; UINT32 trb_ctrl; UINT32 trb_bufsize; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "ERROR: dwc_xdci_process_ep0_xfer_phase_done: INVALID handle\n")); return EFI_DEVICE_ERROR; } ep_handle = &core_handle->ep_handles[ep_num]; trb = core_handle->trbs + (ep_num * DWC_XDCI_TRB_NUM); DEBUG ((DEBUG_INFO, "(dwc_xdci_process_ep0_xfer_phase_done)ep_num is %d\n", ep_num)); if (trb->trb_ctrl & DWC_XDCI_TRB_CTRL_HWO_MASK) { DEBUG ((DEBUG_INFO, "dwc_xdci_process_ep0_xfer_phase_done. HW owns TRB: %x!!!\n", (UINT32)(UINTN)trb)); } ep_handle->currentXferRscIdx = 0; ep_handle->state = USB_EP_STATE_ENABLED; trb_ctrl = (trb->trb_ctrl & DWC_XDCI_TRB_CTRL_TYPE_MASK) >> DWC_XDCI_TRB_CTRL_TYPE_BIT_POS; trb_sts = (trb->len_xfer_params & DWC_XDCI_TRB_STATUS_MASK) >> DWC_XDCI_TRB_STATUS_BIT_POS; trb_bufsize = trb->len_xfer_params & DWC_XDCI_TRB_BUFF_SIZE_MASK; switch (trb_ctrl) { case DWC_XDCI_TRB_CTRL_TYPE_SETUP: DEBUG ((DEBUG_INFO, "SETUP\n")); if (core_handle->event_callbacks.dev_setup_pkt_received_callback) { core_handle->event_callbacks.cb_event_params.parent_handle = core_handle->parent_handle; core_handle->event_callbacks.cb_event_params.buffer = core_handle->aligned_setup_buffer; status = core_handle->event_callbacks.dev_setup_pkt_received_callback (&core_handle->event_callbacks.cb_event_params); } if (!(core_handle->aligned_setup_buffer[0] & USB_SETUP_DATA_PHASE_DIRECTION_MASK)) { /* Keep a buffer ready for setup phase */ dwc_xdci_core_start_ep0_setup_xfer (core_handle); } break; case DWC_XDCI_TRB_CTRL_TYPE_STATUS2: DEBUG ((DEBUG_INFO, "STATUS2\n")); break; case DWC_XDCI_TRB_CTRL_TYPE_STATUS3: DEBUG ((DEBUG_INFO, "STATUS3\n")); /* Notify upper layer of control transfer completion * if a callback function was registerd */ if (core_handle->event_callbacks.dev_xfer_done_callback) { core_handle->event_callbacks.cb_event_params.parent_handle = core_handle->parent_handle; core_handle->event_callbacks.cb_event_params.ep_num = (ep_num >> 1); core_handle->event_callbacks.cb_event_params.ep_dir = (ep_num & 1); core_handle->event_callbacks.cb_event_params.buffer = (UINT8 *)(UINTN)(trb->buff_ptr_low); core_handle->event_callbacks.dev_xfer_done_callback (&core_handle->event_callbacks.cb_event_params); } /* Status phase done. Queue next SETUP packet */ status = dwc_xdci_core_start_ep0_setup_xfer(core_handle); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_process_ep0_xfer_phase_done: FAILED to queue SETUP\n")); } break; case DWC_XDCI_TRB_CTRL_TYPE_DATA: DEBUG ((DEBUG_INFO, "DATA\n")); if (trb_sts == DWC_XDCI_TRB_STATUS_SETUP_PENDING || trb_bufsize != 0) { DEBUG ((DEBUG_INFO, "ERROR: Control transfert aborted by host: Setup pending\n")); dwc_xdci_core_start_ep0_setup_xfer (core_handle); } if (core_handle->event_callbacks.dev_xfer_done_callback) { core_handle->event_callbacks.cb_event_params.parent_handle = core_handle->parent_handle; core_handle->event_callbacks.cb_event_params.ep_num = (ep_num >> 1); core_handle->event_callbacks.cb_event_params.ep_dir = (ep_num & 1); core_handle->event_callbacks.cb_event_params.buffer = (UINT8 *)(UINTN)(trb->buff_ptr_low); core_handle->event_callbacks.dev_xfer_done_callback (&core_handle->event_callbacks.cb_event_params); } break; default: DEBUG ((DEBUG_INFO, "dwc_xdci_process_ep0_xfer_phase_done: UNHANDLED STATE in TRB\n")); break; } return status; } /** Internal function: This function is used to process transfer done for non-control endpoints @core_handle: xDCI controller handle address @ep_num: Physical endpoint number **/ STATIC EFI_STATUS dwc_xdci_process_ep_xfer_done ( IN XDCI_CORE_HANDLE *core_handle, IN UINT32 ep_num ) { DWC_XDCI_ENDPOINT *ep_handle; DWC_XDCI_TRB *trb; USB_XFER_REQUEST *xfer_req; UINT32 remaining_len; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "ERROR: dwc_xdci_process_ep_xfer_done: INVALID handle\n")); return EFI_DEVICE_ERROR; } ep_handle = &core_handle->ep_handles[ep_num]; ep_handle->currentXferRscIdx = 0; trb = ep_handle->trb; xfer_req = &ep_handle->xfer_handle; // // if transfer done, set CheckFlag to FALSE for allow next transfer request. // ep_handle->CheckFlag = FALSE; if ((trb == NULL) || (xfer_req == NULL)) { DEBUG ((DEBUG_INFO, "ERROR: dwc_xdci_process_ep_xfer_done: INVALID parameter\n")); return EFI_INVALID_PARAMETER; } /* Compute the actual transfer length */ xfer_req->actual_xfer_len = xfer_req->xfer_len; remaining_len = (trb->len_xfer_params & DWC_XDCI_TRB_BUFF_SIZE_MASK); if (remaining_len > xfer_req->xfer_len) { /* Buffer overrun? This should never happen */ DEBUG ((DEBUG_INFO, "ERROR: dwc_xdci_process_ep_xfer_done: Possible buffer overrun\n")); } else { xfer_req->actual_xfer_len -= remaining_len; } /* Notify upper layer of request-specific transfer completion * if there is a callback specifically for this request */ if (xfer_req->xfer_done) { xfer_req->xfer_done(core_handle->parent_handle, xfer_req); } /* Notify upper layer if a callback was registered */ if (core_handle->event_callbacks.dev_xfer_done_callback) { core_handle->event_callbacks.cb_event_params.parent_handle = core_handle->parent_handle; core_handle->event_callbacks.cb_event_params.ep_num = (ep_num >> 1); core_handle->event_callbacks.cb_event_params.ep_dir = (ep_num & 1); core_handle->event_callbacks.cb_event_params.ep_type = ep_handle->ep_info.ep_type; core_handle->event_callbacks.cb_event_params.buffer = (UINT8 *)(UINTN)(ep_handle->trb->buff_ptr_low); core_handle->event_callbacks.dev_xfer_done_callback (&core_handle->event_callbacks.cb_event_params); } return EFI_SUCCESS; } /** Internal function: This function is used to process endpoint events @core_handle: xDCI controller handle address @int_line_event_buffer: address of buffer containing event to process @processed_event_size: address to save the size of event processed **/ STATIC EFI_STATUS dwc_xdci_process_ep_event ( IN XDCI_CORE_HANDLE *core_handle, IN DWC_XDCI_EVENT_BUFFER *int_line_event_buffer, IN UINT32 *processed_event_size ) { UINT32 ep_num; UINT32 ep_event; UINT32 ep_event_status; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "ERROR: dwc_xdci_process_ep_event: INVALID handle\n")); return EFI_DEVICE_ERROR; } ep_event = int_line_event_buffer->event; *processed_event_size = DWC_XDCI_DEV_EVENT_DEFAULT_SIZE_IN_BYTES; /* Get EP num */ ep_num = ((ep_event & DWC_XDCI_EVENT_BUFF_EP_NUM_MASK) >> DWC_XDCI_EVENT_BUFF_EP_NUM_BIT_POS); ep_event_status = (ep_event & DWC_XDCI_EVENT_BUFF_EP_EVENT_STATUS_MASK); /* Interpret event and handle transfer completion here */ ep_event = ((ep_event & DWC_XDCI_EVENT_BUFF_EP_EVENT_MASK) >> DWC_XDCI_EVENT_BUFF_EP_EVENT_BIT_POS); switch (ep_event) { case DWC_XDCI_EVENT_BUFF_EP_XFER_CMPLT: DEBUG ((DEBUG_INFO, "XFER_CMPLT ep %d\n", ep_num)); if (ep_num > 1) { dwc_xdci_process_ep_xfer_done (core_handle, ep_num); } else { dwc_xdci_process_ep0_xfer_phase_done (core_handle, ep_num); } break; case DWC_XDCI_EVENT_BUFF_EP_XFER_IN_PROGRESS: DEBUG ((DEBUG_INFO, "IN_PROGRESS\n")); break; case DWC_XDCI_EVENT_BUFF_EP_XFER_NOT_READY: DEBUG ((DEBUG_INFO, "NOT_READY ep %d\n", ep_num)); if (ep_num > 1) { /* Endpoint transfer is not ready */ dwc_xdci_process_ep_xfer_not_ready (core_handle, ep_num); } else { dwc_xdci_process_ep0_xfer_not_ready (core_handle, ep_num, ep_event_status); } break; default: DEBUG ((DEBUG_INFO, "dwc_xdci_process_ep_event: UNKNOWN EP event\n")); break; } return EFI_SUCCESS; } /** Internal function: This function is used to process events on single interrupt line @core_handle: xDCI controller handle address @event_count: event bytes to process @processed_event_count: address to save the size (in bytes) of event processed processed **/ STATIC EFI_STATUS dwc_xdci_process_interrupt_line_events ( IN XDCI_CORE_HANDLE *core_handle, IN UINT32 event_count, IN UINT32 *processed_event_count ) { UINT32 processed_event_size = 0; UINT32 current_event_addr; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "ERROR: dwc_xdci_process_interrupt_line_events: INVALID handle\n")); return EFI_DEVICE_ERROR; } if (core_handle->current_event_buffer == NULL) { DEBUG ((DEBUG_INFO, "ERROR: dwc_xdci_process_interrupt_line_events: INVALID event buffer\n")); return EFI_INVALID_PARAMETER; } current_event_addr = (UINT32)(UINTN)(core_handle->current_event_buffer); /* Process event_count/event_size number of events * in this run */ while (event_count) { if (core_handle->current_event_buffer->event & DWC_XDCI_EVENT_DEV_MASK) { dwc_xdci_process_device_event ( core_handle, core_handle->current_event_buffer, &processed_event_size ); } else { dwc_xdci_process_ep_event ( core_handle, core_handle->current_event_buffer, &processed_event_size); } event_count -= processed_event_size; *processed_event_count += processed_event_size; if ((current_event_addr + processed_event_size) >= ((UINT32)(UINTN)(core_handle->aligned_event_buffers) + (sizeof(DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER)) ) { current_event_addr = (UINT32)(UINTN)(core_handle->aligned_event_buffers); DEBUG ((DEBUG_INFO, "dwc_xdci_process_interrupt_line_events: Event buffer bound reached\n")); } else { current_event_addr += processed_event_size; } core_handle->current_event_buffer = (DWC_XDCI_EVENT_BUFFER *)(UINTN)current_event_addr; } return EFI_SUCCESS; } /* DWC XDCI APIs */ /** Interface: This function is used to initialize the xDCI core @config_params: Parameters from app to configure the core @device_core_ptr: HW-independent APIs handle for device core @core_handle: xDCI controller handle retured **/ EFI_STATUS EFIAPI dwc_xdci_core_init ( IN USB_DEV_CONFIG_PARAMS *ConfigParams, IN VOID *device_core_ptr, IN VOID **core_handle ) { EFI_STATUS status = EFI_DEVICE_ERROR; UINTN base_addr; XDCI_CORE_HANDLE *local_core_handle; DWC_XDCI_ENDPOINT_CMD_PARAMS ep_cmd_params; UINT32 max_delay_iter = DWC_XDCI_MAX_DELAY_ITERATIONS; UINT8 i; local_core_handle = (XDCI_CORE_HANDLE *)AllocateZeroPool (sizeof(XDCI_CORE_HANDLE)); if (core_handle == NULL) { return EFI_INVALID_PARAMETER; } if (local_core_handle == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_init: Failed to allocate handle for xDCI\n")); return EFI_OUT_OF_RESOURCES; } ZeroMem (local_core_handle, sizeof(XDCI_CORE_HANDLE)); local_core_handle->parent_handle = device_core_ptr; *core_handle = (VOID *)local_core_handle; local_core_handle->id = ConfigParams->ControllerId; local_core_handle->base_address = base_addr = ConfigParams->BaseAddress; local_core_handle->flags = ConfigParams->Flags; local_core_handle->desired_speed = local_core_handle->actual_speed = ConfigParams->Speed; local_core_handle->role = ConfigParams->Role; DEBUG ((DEBUG_INFO, "Resetting the USB core\n")); usb_reg_write ( base_addr, DWC_XDCI_DCTL_REG, usb_reg_read (base_addr, DWC_XDCI_DCTL_REG) | DWC_XDCI_DCTL_CSFTRST_MASK ); /* Wait until core soft reset completes */ do { if (!(usb_reg_read (base_addr, DWC_XDCI_DCTL_REG) & DWC_XDCI_DCTL_CSFTRST_MASK)) { break; } else { gBS->Stall (DWC_XDCI_MAX_DELAY_ITERATIONS); } } while (--max_delay_iter); if (!max_delay_iter) { DEBUG ((DEBUG_INFO, "Failed to reset device controller\n")); return EFI_DEVICE_ERROR; } DEBUG ((DEBUG_INFO, "USB core has been reset\n")); /* All FIFOs are flushed at this point */ /* Ensure we have EP0 Rx/Tx handles initialized */ local_core_handle->ep_handles[0].ep_info.ep_num = 0; local_core_handle->ep_handles[0].ep_info.ep_dir = UsbEpDirOut; local_core_handle->ep_handles[0].ep_info.ep_type = USB_ENDPOINT_CONTROL; local_core_handle->ep_handles[0].ep_info.max_pkt_size = DWC_XDCI_SS_CTRL_EP_MPS; /* 0 means burst size of 1 */ local_core_handle->ep_handles[0].ep_info.burst_size = 0; local_core_handle->ep_handles[1].ep_info.ep_num = 0; local_core_handle->ep_handles[1].ep_info.ep_dir = UsbEpDirIn; local_core_handle->ep_handles[1].ep_info.ep_type = USB_ENDPOINT_CONTROL; local_core_handle->ep_handles[1].ep_info.max_pkt_size = DWC_XDCI_SS_CTRL_EP_MPS; /* 0 means burst size of 1 */ local_core_handle->ep_handles[1].ep_info.burst_size = 0; local_core_handle->dev_state = UsbDevStateDefault; /* Clear KeepConnect bit so we can allow disconnect and * re-connect. Stay in RX_DETECT state */ usb_reg_write ( base_addr, DWC_XDCI_DCTL_REG, usb_reg_read (base_addr, DWC_XDCI_DCTL_REG) & (~DWC_XDCI_DCTL_KEEP_CONNECT_MASK) & ((~DWC_XDCI_DCTL_STATE_CHANGE_REQ_MASK) | (DWC_XDCI_DCTL_STATE_CHANGE_REQ_RX_DETECT << DWC_XDCI_DCTL_STATE_CHANGE_REQ_BIT_POS)) ); DEBUG ((DEBUG_INFO, "Device controller Synopsys ID: %x\n", usb_reg_read (base_addr, DWC_XDCI_GSNPSID_REG))); DEBUG ((DEBUG_INFO, "Default value of xDCI GSBUSCFG0 and GSBUSCFG1: %x, %x\n", usb_reg_read (base_addr, DWC_XDCI_GSBUSCFG0_REG), usb_reg_read (base_addr, DWC_XDCI_GSBUSCFG1_REG))); DEBUG ((DEBUG_INFO, "Default value of xDCI GTXTHRCFG and GRXTHRCFG: %x, %x\n", usb_reg_read (base_addr, DWC_XDCI_GTXTHRCFG_REG), usb_reg_read (base_addr, DWC_XDCI_GRXTHRCFG_REG))); /* Clear ULPI auto-resume bit */ usb_reg_write ( base_addr, DWC_XDCI_GUSB2PHYCFG_REG (0), (usb_reg_read (base_addr, DWC_XDCI_GUSB2PHYCFG_REG (0)) & ~DWC_XDCI_GUSB2PHYCFG_ULPI_AUTO_RESUME_MASK) ); DEBUG ((DEBUG_INFO, "Default value of xDCI GUSB2PHYCFG and GUSB3PIPECTL: %x, %x\n", usb_reg_read (base_addr, DWC_XDCI_GUSB2PHYCFG_REG (0)), usb_reg_read (base_addr, DWC_XDCI_GUSB3PIPECTL_REG (0)))); /* Only one RxFIFO */ DEBUG ((DEBUG_INFO, "Default value of DWC_XDCI_GRXFIFOSIZ: %x\n", usb_reg_read (base_addr, DWC_XDCI_GRXFIFOSIZ_REG (0)))); for (i = 0; i < DWC_XDCI_MAX_ENDPOINTS; i++) { DEBUG ((DEBUG_INFO, "Default value of xDCI DWC_XDCI_GTXFIFOSIZ %d: %x\n", i, usb_reg_read (base_addr, DWC_XDCI_GTXFIFOSIZ_REG (i)))); } /* TODO: Need to check if TxFIFO should start where RxFIFO ends * or default is correct i.e. TxFIFO starts at 0 just like RxFIFO */ /* Allocate and Initialize Event Buffers */ local_core_handle->max_dev_int_lines = ((usb_reg_read (base_addr, DWC_XDCI_GHWPARAMS1_REG) & DWC_XDCI_GHWPARAMS1_NUM_INT_MASK) >> DWC_XDCI_GHWPARAMS1_NUM_INT_BIT_POS); DEBUG ((DEBUG_INFO, "Max dev int lines: %d\n", local_core_handle->max_dev_int_lines)); /* One event buffer per interrupt line. * Need to align it to size of event buffer * Buffer needs to be big enough. Otherwise the core * won't operate */ local_core_handle->aligned_event_buffers = (DWC_XDCI_EVENT_BUFFER *) ((UINT32)(UINTN)(local_core_handle->event_buffers) + ((sizeof (DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER) - (((UINT32)(UINTN)(local_core_handle->event_buffers)) % (sizeof (DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER)))); for (i = 0; i < local_core_handle->max_dev_int_lines; i++) { usb_reg_write ( base_addr, DWC_XDCI_GEVNTADR_REG (i), (UINT32)(UINTN)(local_core_handle->aligned_event_buffers + i * sizeof(DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER) ); // // Clear High 32bit address register, GEVNTADR register is 64-bit register // default is 0xffffffffffffffff // usb_reg_write (base_addr, DWC_XDCI_GEVNTADR_REG (i) + 4, 0x00000000); local_core_handle->current_event_buffer = local_core_handle->aligned_event_buffers; /* Write size and clear the mask */ usb_reg_write ( base_addr, DWC_XDCI_EVNTSIZ_REG (i), sizeof (DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER ); /* Write 0 to the event count register as the last step * for event configuration */ usb_reg_write (base_addr, DWC_XDCI_EVNTCOUNT_REG (i), 0); DEBUG ((DEBUG_INFO, "Value of xDCI Event buffer %d: %x, Size: %x, Count: %x\n", i, usb_reg_read (base_addr, DWC_XDCI_GEVNTADR_REG (i)), usb_reg_read (base_addr, DWC_XDCI_EVNTSIZ_REG (i)), usb_reg_read (base_addr, DWC_XDCI_EVNTCOUNT_REG (i)))); } // /* Program Global Control Register to disable scaledown, // * disable clock gating // */ // usb_reg_write ( // base_addr, // DWC_XDCI_GCTL_REG, // ((usb_reg_read (base_addr, DWC_XDCI_GCTL_REG) & ~DWC_XDCI_GCTL_SCALE_DOWN_MODE_MASK) | DWC_XDCI_GCTL_DISABLE_CLK_GATING_MASK) // ); /* Program Global Control Register to disable scaledown, * disable clock gating */ usb_reg_write ( base_addr, DWC_XDCI_GCTL_REG, ((usb_reg_read(base_addr, DWC_XDCI_GCTL_REG) & //HSLE_DEBUG ~DWC_XDCI_GCTL_SCALE_DOWN_MODE_MASK) | //HSLE_DEBUG DWC_XDCI_GCTL_DISABLE_CLK_GATING_MASK)); ~(DWC_XDCI_GCTL_SCALE_DOWN_MODE_MASK + DWC_XDCI_GCTL_RAMCLKSEL_MASK + DWC_XDCI_GCTL_DISABLE_SCRAMB_MASK)) | DWC_XDCI_GCTL_DISABLE_CLK_GATING_MASK | (DWC_XDCI_GCTL_PRT_CAP_DEVICE << DWC_XDCI_GCTL_PRT_CAP_DIR_BIT_POS))); // // // //HSLE_DEBUG // // // usb_reg_write(base_addr, DWC_XDCI_GCTL_REG, // ((usb_reg_read(base_addr, DWC_XDCI_GCTL_REG) & // ~DWC_XDCI_GCTL_SCALE_DOWN_MODE_MASK) | // DWC_XDCI_GCTL_DISABLE_CLK_GATING_MASK)); DEBUG ((DEBUG_INFO, "Setup value of xDCI DWC_XDCI_GCTL_REG: 0x%x\n", usb_reg_read (base_addr, DWC_XDCI_GCTL_REG))); /* TODO: Program desired speed and set LPM capable * We will do this when Superspeed works. For now, * force into High-speed mode to aVOID anyone trying this * on Super speed port */ #ifdef SUPPORT_SUPER_SPEED usb_reg_write ( base_addr, DWC_XDCI_DCFG_REG, (usb_reg_read (base_addr, DWC_XDCI_DCFG_REG) & ~DWC_XDCI_DCFG_DESIRED_DEV_SPEED_MASK) | local_core_handle->desired_speed ); #else usb_reg_write ( base_addr, DWC_XDCI_DCFG_REG, (usb_reg_read (base_addr, DWC_XDCI_DCFG_REG) & ~DWC_XDCI_DCFG_DESIRED_DEV_SPEED_MASK) | DWC_XDCI_DCFG_DESIRED_HS_SPEED ); #endif DEBUG ((DEBUG_INFO, "Setup value of xDCI DWC_XDCI_DCFG_REG: 0x%x\n", usb_reg_read (base_addr, DWC_XDCI_DCFG_REG))); DEBUG ((DEBUG_INFO, "Setup value of xDCI DWC_XDCI_DSTS_REG: 0x%x\n", usb_reg_read (base_addr, DWC_XDCI_DSTS_REG))); /* Enable Device Interrupt Events */ usb_reg_write ( base_addr, DWC_XDCI_DEVTEN_REG, DWC_XDCI_DEVTEN_DEVICE_INTS ); /* Program the desired role */ usb_reg_write ( base_addr, DWC_XDCI_GCTL_REG, (usb_reg_read (base_addr, DWC_XDCI_GCTL_REG) & ~DWC_XDCI_GCTL_PRT_CAP_DIR_MASK) | (local_core_handle->role << DWC_XDCI_GCTL_PRT_CAP_DIR_BIT_POS) ); /* Clear USB2 suspend for start new config command */ usb_reg_write ( base_addr, DWC_XDCI_GUSB2PHYCFG_REG (0), (usb_reg_read (base_addr, DWC_XDCI_GUSB2PHYCFG_REG(0)) & ~DWC_XDCI_GUSB2PHYCFG_SUSPEND_PHY_MASK) ); /* Clear USB3 suspend for start new config command */ usb_reg_write ( base_addr, DWC_XDCI_GUSB3PIPECTL_REG (0), (usb_reg_read (base_addr, DWC_XDCI_GUSB3PIPECTL_REG(0)) & ~DWC_XDCI_GUSB3PIPECTL_SUSPEND_PHY_MASK) ); /* Issue DEPSTARTCFG command for EP0 */ status = dwc_xdci_core_init_ep_cmd_params ( local_core_handle, &local_core_handle->ep_handles[0].ep_info, DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_NONE, EPCMD_START_NEW_CONFIG, &ep_cmd_params ); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_init: Failed to init params for START_NEW_CONFIG EP command on xDCI\n")); return status; } /* Issue the command */ status = dwc_xdci_core_issue_ep_cmd ( local_core_handle, 0, EPCMD_START_NEW_CONFIG, &ep_cmd_params ); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_init: Failed to issue START_NEW_CONFIG EP command on xDCI\n")); return status; } /* Issue DEPCFG command for EP0 */ status = dwc_xdci_core_init_ep_cmd_params ( local_core_handle, &local_core_handle->ep_handles[0].ep_info, DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_INIT_STATE, EPCMD_SET_EP_CONFIG, &ep_cmd_params ); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_init: Failed to init params for SET_EP_CONFIG command on xDCI for EP0\n")); return status; } /* Issue the command */ status = dwc_xdci_core_issue_ep_cmd ( local_core_handle, 0, EPCMD_SET_EP_CONFIG, &ep_cmd_params); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_init: Failed to issue SET_EP_CONFIG command on xDCI for EP0\n")); return status; } /* Issue DEPCFG command for EP1 */ status = dwc_xdci_core_init_ep_cmd_params ( local_core_handle, &local_core_handle->ep_handles[1].ep_info, DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_INIT_STATE, EPCMD_SET_EP_CONFIG, &ep_cmd_params ); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_init: Failed to init params for SET_EP_CONFIG command on xDCI for EP1\n")); return status; } /* Issue the command */ status = dwc_xdci_core_issue_ep_cmd ( local_core_handle, 1, EPCMD_SET_EP_CONFIG, &ep_cmd_params ); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_init: Failed to issue SET_EP_CONFIG command on xDCI for EP1\n")); return status; } /* Issue DEPXFERCFG command for EP0 */ status = dwc_xdci_core_init_ep_cmd_params ( local_core_handle, &local_core_handle->ep_handles[0].ep_info, DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_NONE, EPCMD_SET_EP_XFER_RES_CONFIG, &ep_cmd_params ); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_init: Failed to init params for EPCMD_SET_EP_XFER_RES_CONFIG command on xDCI for EP0\n")); return status; } /* Issue the command */ status = dwc_xdci_core_issue_ep_cmd ( local_core_handle, 0, EPCMD_SET_EP_XFER_RES_CONFIG, &ep_cmd_params ); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_init: Failed to issue EPCMD_SET_EP_XFER_RES_CONFIG command on xDCI for EP0\n")); return status; } /* Issue DEPXFERCFG command for EP1 */ status = dwc_xdci_core_init_ep_cmd_params ( local_core_handle, &local_core_handle->ep_handles[1].ep_info, DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_NONE, EPCMD_SET_EP_XFER_RES_CONFIG, &ep_cmd_params ); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_init: Failed to init params for EPCMD_SET_EP_XFER_RES_CONFIG command on xDCI for EP1\n")); return status; } /* Issue the command */ status = dwc_xdci_core_issue_ep_cmd ( local_core_handle, 1, EPCMD_SET_EP_XFER_RES_CONFIG, &ep_cmd_params ); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_init: Failed to issue EPCMD_SET_EP_XFER_RES_CONFIG command on xDCI for EP1\n")); return status; } /* Prepare a buffer for SETUP packet */ local_core_handle->trbs = (DWC_XDCI_TRB *)(UINTN)((UINT32)(UINTN) local_core_handle->unaligned_trbs + (DWC_XDCI_TRB_BYTE_ALIGNMENT - ((UINT32)(UINTN)local_core_handle->unaligned_trbs % DWC_XDCI_TRB_BYTE_ALIGNMENT))); DEBUG ((DEBUG_INFO, "(dwc_xdci_core_init)@@@@@@@@@ unaligned_trbs address is 0x%x\n", local_core_handle->unaligned_trbs)); DEBUG ((DEBUG_INFO, "(dwc_xdci_core_init)@@@@@@@@@ TRB address is 0x%x\n", local_core_handle->trbs)); /* Allocate Setup buffer that is 8-byte aligned */ local_core_handle->aligned_setup_buffer = local_core_handle->default_setup_buffer + (DWC_XDCI_SETUP_BUFF_SIZE - ((UINT32)(UINTN)(local_core_handle->default_setup_buffer) % DWC_XDCI_SETUP_BUFF_SIZE)); /* Aligned buffer for status phase */ local_core_handle->aligned_misc_buffer = local_core_handle->misc_buffer + (DWC_XDCI_SETUP_BUFF_SIZE - ((UINT32)(UINTN)(local_core_handle->aligned_misc_buffer) % DWC_XDCI_SETUP_BUFF_SIZE)); /* We will queue SETUP request when we see bus reset */ /* Enable Physical Endpoints 0 */ usb_reg_write ( base_addr, DWC_XDCI_EP_DALEPENA_REG, usb_reg_read (base_addr, DWC_XDCI_EP_DALEPENA_REG) | (1 << 0) ); /* Enable Physical Endpoints 1 */ usb_reg_write ( base_addr, DWC_XDCI_EP_DALEPENA_REG, usb_reg_read (base_addr, DWC_XDCI_EP_DALEPENA_REG) | (1 << 1) ); DEBUG ((DEBUG_INFO, "Default value of xDCI DWC_XDCI_DEVTEN_REG: 0x%x\n", usb_reg_read (base_addr, DWC_XDCI_DEVTEN_REG))); return status; } /** Interface: This function is used to de-initialize the xDCI core @core_handle: xDCI controller handle @flags: Special flags for de-initializing the core in particular way **/ EFI_STATUS EFIAPI dwc_xdci_core_deinit ( IN VOID *core_handle, IN UINT32 flags ) { /* TODO: Need to implement this */ FreePool (core_handle); return EFI_SUCCESS; } /** Interface: This function is used to register event callback function @core_handle: xDCI controller handle @event: Event for which callback is to be registered @callback_fn: Callback function to invoke after event occurs **/ EFI_STATUS EFIAPI dwc_xdci_core_register_callback ( IN VOID *core_handle, IN USB_DEVICE_EVENT_ID event, IN USB_DEVICE_CALLBACK_FUNC CallbackFunc ) { XDCI_CORE_HANDLE *local_core_handle = (XDCI_CORE_HANDLE *)core_handle; if (local_core_handle == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_register_callback: INVALID handle\n")); return EFI_DEVICE_ERROR; } DEBUG ((DEBUG_INFO, "dwc_xdci_core_register_callback: event is %d\n", event)); switch (event) { case USB_DEVICE_DISCONNECT_EVENT: local_core_handle->event_callbacks.dev_disconnect_callback = CallbackFunc; break; case USB_DEVICE_RESET_EVENT: local_core_handle->event_callbacks.dev_bus_reset_callback = CallbackFunc; break; case USB_DEVICE_CONNECTION_DONE: local_core_handle->event_callbacks.dev_reset_done_callback = CallbackFunc; break; case USB_DEVICE_STATE_CHANGE_EVENT: local_core_handle->event_callbacks.dev_link_state_callback = CallbackFunc; break; case USB_DEVICE_WAKEUP_EVENT: local_core_handle->event_callbacks.dev_wakeup_callback = CallbackFunc; break; case USB_DEVICE_HIBERNATION_REQ_EVENT: local_core_handle->event_callbacks.dev_hibernation_callback = CallbackFunc; break; case USB_DEVICE_SOF_EVENT: local_core_handle->event_callbacks.dev_sof_callback = CallbackFunc; break; case USB_DEVICE_ERRATIC_ERR_EVENT: local_core_handle->event_callbacks.dev_erratic_err_callback = CallbackFunc; break; case USB_DEVICE_CMD_CMPLT_EVENT: local_core_handle->event_callbacks.dev_cmd_cmplt_callback = CallbackFunc; break; case USB_DEVICE_BUFF_OVERFLOW_EVENT: local_core_handle->event_callbacks.dev_buff_ovflw_callback = CallbackFunc; break; case USB_DEVICE_TEST_LMP_RX_EVENT: local_core_handle->event_callbacks.dev_test_lmp_rx_callback = CallbackFunc; break; case USB_DEVICE_SETUP_PKT_RECEIVED: local_core_handle->event_callbacks.dev_setup_pkt_received_callback = CallbackFunc; break; case USB_DEVICE_XFER_NRDY: local_core_handle->event_callbacks.dev_xfer_nrdy_callback = CallbackFunc; break; case USB_DEVICE_XFER_DONE: local_core_handle->event_callbacks.dev_xfer_done_callback = CallbackFunc; break; default: break; } return EFI_SUCCESS; } /** Interface: This function is used to unregister event callback function @core_handle: xDCI controller handle @event: Event for which callback function is to be unregistered **/ EFI_STATUS EFIAPI dwc_xdci_core_unregister_callback ( IN VOID *core_handle, IN USB_DEVICE_EVENT_ID event ) { XDCI_CORE_HANDLE *local_core_handle = (XDCI_CORE_HANDLE *)core_handle; if (local_core_handle == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_unregister_callback: INVALID handle\n")); return EFI_DEVICE_ERROR; } switch (event) { case USB_DEVICE_DISCONNECT_EVENT: local_core_handle->event_callbacks.dev_disconnect_callback = NULL; break; case USB_DEVICE_RESET_EVENT: local_core_handle->event_callbacks.dev_bus_reset_callback = NULL; break; case USB_DEVICE_CONNECTION_DONE: local_core_handle->event_callbacks.dev_reset_done_callback = NULL; break; case USB_DEVICE_STATE_CHANGE_EVENT: local_core_handle->event_callbacks.dev_link_state_callback = NULL; break; case USB_DEVICE_WAKEUP_EVENT: local_core_handle->event_callbacks.dev_wakeup_callback = NULL; break; case USB_DEVICE_HIBERNATION_REQ_EVENT: local_core_handle->event_callbacks.dev_hibernation_callback = NULL; break; case USB_DEVICE_SOF_EVENT: local_core_handle->event_callbacks.dev_sof_callback = NULL; break; case USB_DEVICE_ERRATIC_ERR_EVENT: local_core_handle->event_callbacks.dev_erratic_err_callback = NULL; break; case USB_DEVICE_CMD_CMPLT_EVENT: local_core_handle->event_callbacks.dev_cmd_cmplt_callback = NULL; break; case USB_DEVICE_BUFF_OVERFLOW_EVENT: local_core_handle->event_callbacks.dev_buff_ovflw_callback = NULL; break; case USB_DEVICE_TEST_LMP_RX_EVENT: local_core_handle->event_callbacks.dev_test_lmp_rx_callback = NULL; break; case USB_DEVICE_SETUP_PKT_RECEIVED: local_core_handle->event_callbacks.dev_setup_pkt_received_callback = NULL; break; case USB_DEVICE_XFER_NRDY: local_core_handle->event_callbacks.dev_xfer_nrdy_callback = NULL; break; case USB_DEVICE_XFER_DONE: local_core_handle->event_callbacks.dev_xfer_done_callback = NULL; break; default: break; } return EFI_SUCCESS; } /** Interface: This function is used as an interrupt service routine @core_handle: xDCI controller handle **/ EFI_STATUS EFIAPI dwc_xdci_core_isr_routine ( IN VOID *core_handle ) { XDCI_CORE_HANDLE *local_core_handle = (XDCI_CORE_HANDLE *)core_handle; UINTN base_addr; UINT32 event_count; UINT32 processed_event_count; UINT32 i; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_isr_routine: INVALID handle\n")); return EFI_DEVICE_ERROR; } if (local_core_handle->interrup_processing == TRUE) { DEBUG ((DEBUG_INFO, "interrup_processing.........\n")); return EFI_SUCCESS; } base_addr = local_core_handle->base_address; /* Event buffer corresponding to each interrupt line needs * to be processed */ local_core_handle->interrup_processing = TRUE; for (i = 0; i < local_core_handle->max_dev_int_lines; i++) { /* Get the number of events HW has written for this * interrupt line */ event_count = usb_reg_read (base_addr, DWC_XDCI_EVNTCOUNT_REG (i)); event_count &= DWC_XDCI_EVNTCOUNT_MASK; processed_event_count = 0; /* Process interrupt line buffer only if count is non-zero */ if (event_count) { /* Process events in this buffer */ dwc_xdci_process_interrupt_line_events (local_core_handle, event_count, &processed_event_count); /* Write back the processed number of events so HW decrements it from current * event count */ usb_reg_write (base_addr, DWC_XDCI_EVNTCOUNT_REG (i), processed_event_count); } } local_core_handle->interrup_processing = FALSE; return EFI_SUCCESS; } /** Interface: This function is used as an interrupt service routine and it processes only one event at a time. @core_handle: xDCI controller handle **/ EFI_STATUS EFIAPI dwc_xdci_core_isr_routine_timer_based ( IN VOID *core_handle ) { XDCI_CORE_HANDLE *local_core_handle = (XDCI_CORE_HANDLE *)core_handle; UINTN base_addr; UINT32 event_count; UINT32 processed_event_count; UINT32 current_event_addr; UINT32 processed_event_size = 0; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_isr_routine_timer_based: INVALID handle\n")); return EFI_DEVICE_ERROR; } if (local_core_handle->current_event_buffer == NULL) { DEBUG ((DEBUG_INFO, "ERROR: dwc_xdci_core_isr_routine_timer_based: INVALID event buffer\n")); return EFI_INVALID_PARAMETER; } base_addr = local_core_handle->base_address; event_count = usb_reg_read (base_addr, DWC_XDCI_EVNTCOUNT_REG (0)) & DWC_XDCI_EVNTCOUNT_MASK; if (local_core_handle->interrup_processing == TRUE) { DEBUG ((DEBUG_INFO, "interrup_processing.........\n")); return EFI_SUCCESS; } local_core_handle->interrup_processing = TRUE; processed_event_count = 0; current_event_addr = (UINT32)(UINTN)(local_core_handle->current_event_buffer); if (local_core_handle->current_event_buffer->event & DWC_XDCI_EVENT_DEV_MASK) { dwc_xdci_process_device_event ( local_core_handle, local_core_handle->current_event_buffer, &processed_event_size ); } else { dwc_xdci_process_ep_event ( local_core_handle, local_core_handle->current_event_buffer, &processed_event_size); } event_count -= processed_event_size; processed_event_count += processed_event_size; if ((current_event_addr + processed_event_size) >= ((UINT32)(UINTN)(local_core_handle->aligned_event_buffers) + (sizeof(DWC_XDCI_EVENT_BUFFER) * DWC_XDCI_MAX_EVENTS_PER_BUFFER)) ) { current_event_addr = (UINT32)(UINTN)(local_core_handle->aligned_event_buffers); DEBUG ((DEBUG_INFO, "dwc_xdci_process_interrupt_line_events: Event buffer bound reached\n")); } else { current_event_addr += processed_event_size; } local_core_handle->current_event_buffer = (DWC_XDCI_EVENT_BUFFER *)(UINTN)current_event_addr; usb_reg_write (base_addr, DWC_XDCI_EVNTCOUNT_REG (0), processed_event_count); local_core_handle->interrup_processing = FALSE; return EFI_SUCCESS; } /** Interface: This function is used to enable xDCI to connect to the host @core_handle: xDCI controller handle **/ EFI_STATUS EFIAPI dwc_xdci_core_connect ( IN VOID *core_handle ) { XDCI_CORE_HANDLE *local_core_handle = (XDCI_CORE_HANDLE *)core_handle; UINT32 max_delay_iter = DWC_XDCI_MAX_DELAY_ITERATIONS; UINTN base_addr; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_connect: INVALID handle\n")); return EFI_DEVICE_ERROR; } base_addr = local_core_handle->base_address; /* Clear KeepConnect bit so we can allow disconnect and re-connect * Also issue No action on state change to aVOID any link change */ usb_reg_write ( base_addr, DWC_XDCI_DCTL_REG, (usb_reg_read(base_addr, DWC_XDCI_DCTL_REG) & ~DWC_XDCI_DCTL_KEEP_CONNECT_MASK) & ~DWC_XDCI_DCTL_STATE_CHANGE_REQ_MASK ); /* Set Run bit to connect to the host */ usb_reg_write ( base_addr, DWC_XDCI_DCTL_REG, usb_reg_read (base_addr, DWC_XDCI_DCTL_REG) | DWC_XDCI_DCTL_RUN_STOP_MASK ); /* Wait until core starts running */ do { if (!(usb_reg_read (base_addr, DWC_XDCI_DSTS_REG) & DWC_XDCI_DSTS_DEV_CTRL_HALTED_MASK)) { break; } else { gBS->Stall (DWC_XDCI_MAX_DELAY_ITERATIONS); } } while (--max_delay_iter); if (!max_delay_iter) { DEBUG ((DEBUG_INFO, "Failed to run the device controller\n")); return EFI_DEVICE_ERROR; } return EFI_SUCCESS; } /** Interface: This function is used to disconnect xDCI from the host @core_handle: xDCI controller handle **/ EFI_STATUS EFIAPI dwc_xdci_core_disconnect ( IN VOID *core_handle ) { XDCI_CORE_HANDLE *local_core_handle = (XDCI_CORE_HANDLE *)core_handle; UINT32 max_delay_iter = DWC_XDCI_MAX_DELAY_ITERATIONS; UINTN base_addr; UINT32 event_count; UINT32 dsts; UINT32 i; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_disconnect: INVALID handle\n")); return EFI_DEVICE_ERROR; } base_addr = local_core_handle->base_address; event_count = usb_reg_read (base_addr, DWC_XDCI_EVNTCOUNT_REG (0)); event_count &= DWC_XDCI_EVNTCOUNT_MASK; DEBUG ((DEBUG_INFO, "dwc_xdci_core_disconnect: event_count=%d\n", event_count)); while (event_count) { dwc_xdci_core_isr_routine(local_core_handle); event_count = usb_reg_read (base_addr, DWC_XDCI_EVNTCOUNT_REG (0)); event_count &= DWC_XDCI_EVNTCOUNT_MASK; DEBUG ((DEBUG_INFO, "dwc_xdci_core_disconnect: event_count=%d\n", event_count)); } /* Issue DEPENDXFER for active transfers */ for (i = 0; i < DWC_XDCI_MAX_ENDPOINTS; i++){ if (local_core_handle->ep_handles[i].currentXferRscIdx){ dwc_xdci_end_xfer(local_core_handle, i); } } /* Clear Run bit to disconnect from host */ usb_reg_write ( base_addr, DWC_XDCI_DCTL_REG, usb_reg_read(base_addr, DWC_XDCI_DCTL_REG) & ~DWC_XDCI_DCTL_RUN_STOP_MASK); /* Wait until core is halted */ do { // if ((usb_reg_read (base_addr, DWC_XDCI_DSTS_REG) & DWC_XDCI_DSTS_LINK_STATE_MASK) == DWC_XDCI_DSTS_LINK_STATE_DISCONNECT) dsts = usb_reg_read (base_addr, DWC_XDCI_DSTS_REG); DEBUG ((DEBUG_INFO, "dwc_xdci_core_disconnect: waiting halt: DSTS=0x%x\n", dsts)); if ((dsts & DWC_XDCI_DSTS_DEV_CTRL_HALTED_MASK) != 0){ break; } else { gBS->Stall (DWC_XDCI_MAX_DELAY_ITERATIONS); } } while (--max_delay_iter); if (!max_delay_iter) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_disconnect: Failed to halt the device controller\n")); return EFI_DEVICE_ERROR; } return EFI_SUCCESS; } /** Interface: This function is used to obtain current USB bus speed @core_handle: xDCI controller handle @speed: Address of variable to save the speed **/ EFI_STATUS EFIAPI dwc_xdci_core_get_speed ( IN VOID *core_handle, IN USB_SPEED *speed ) { XDCI_CORE_HANDLE *local_core_handle = (XDCI_CORE_HANDLE *)core_handle; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_get_speed: INVALID handle\n")); return EFI_DEVICE_ERROR; } if (speed == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_get_speed: INVALID parameter\n")); return EFI_INVALID_PARAMETER; } *speed = usb_reg_read (local_core_handle->base_address, DWC_XDCI_DSTS_REG) & DWC_XDCI_DSTS_CONN_SPEED_MASK; return EFI_SUCCESS; } /** Interface: This function is used to obtain current USB bus speed @core_handle: xDCI controller handle @address: USB address to set (assigned by USB host) **/ EFI_STATUS EFIAPI dwc_xdci_core_set_address ( IN VOID *core_handle, IN UINT32 address ) { XDCI_CORE_HANDLE *local_core_handle = (XDCI_CORE_HANDLE *)core_handle; UINTN base_addr; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_set_address: INVALID handle\n")); return EFI_DEVICE_ERROR; } base_addr = local_core_handle->base_address; DEBUG ((DEBUG_INFO, "dwc_xdci_core_set_address is 0x%x \n", address)); /* Program USB device address */ usb_reg_write ( base_addr, DWC_XDCI_DCFG_REG, (usb_reg_read(base_addr, DWC_XDCI_DCFG_REG) & ~DWC_XDCI_DCFG_DEV_ADDRESS_MASK) | (address << DWC_XDCI_DCFG_DEV_ADDRESS_BIT_POS) ); local_core_handle->dev_state = UsbDevStateAddress; DEBUG ((DEBUG_INFO, "Setup value of xDCI DWC_XDCI_GCTL_REG: 0x%x\n", usb_reg_read (base_addr, DWC_XDCI_GCTL_REG))); DEBUG ((DEBUG_INFO, "Setup value of xDCI DWC_XDCI_DEVTEN_REG: 0x%x\n", usb_reg_read (base_addr, DWC_XDCI_DEVTEN_REG))); DEBUG ((DEBUG_INFO, "Setup value of xDCI DWC_XDCI_DCFG_REG: 0x%x\n", usb_reg_read (base_addr, DWC_XDCI_DCFG_REG))); DEBUG ((DEBUG_INFO, "Setup value of xDCI DWC_XDCI_DSTS_REG: 0x%x\n", usb_reg_read (base_addr, DWC_XDCI_DSTS_REG))); return EFI_SUCCESS; } /** Interface: This function is used to set configuration @core_handle: xDCI controller handle @config_num: config num to set (assigned by USB host) **/ EFI_STATUS EFIAPI dwc_xdci_core_set_config ( IN VOID *core_handle, IN UINT32 config_num ) { XDCI_CORE_HANDLE *local_core_handle = (XDCI_CORE_HANDLE *)core_handle; DWC_XDCI_ENDPOINT_CMD_PARAMS ep_cmd_params; EFI_STATUS status; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_set_config: INVALID handle\n")); return EFI_DEVICE_ERROR; } /* TODO: Disable all non-CTRL endpoints here if * stack is not doing it */ /* TODO: Cancel all non-CTRL transfers here on all EPs * if stack is not doing it */ /* TODO: Change EP1 TXFIFO allocation if necessary */ /* Re-initialize transfer resource allocation */ /* Issue DEPSTARTCFG command on EP0 (new config for * non-control EPs) */ status = dwc_xdci_core_init_ep_cmd_params ( local_core_handle, &local_core_handle->ep_handles[0].ep_info, DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_NONE, EPCMD_START_NEW_CONFIG, &ep_cmd_params ); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_set_config: Failed to init params for EPCMD_START_NEW_CONFIG command\n")); return status; } /* Issue the command */ status = dwc_xdci_core_issue_ep_cmd ( local_core_handle, 0, (EPCMD_START_NEW_CONFIG | (2 << DWC_XDCI_EPCMD_RES_IDX_BIT_POS)), &ep_cmd_params ); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_set_config: Failed to issue EPCMD_START_NEW_CONFIG command\n")); return status; } return status; } /** Interface: This function is used to set link state @core_handle: xDCI controller handle @state: Desired link state **/ EFI_STATUS EFIAPI dwc_xdci_set_link_state ( IN VOID *core_handle, IN USB_DEVICE_SS_LINK_STATE state ) { XDCI_CORE_HANDLE *local_core_handle = (XDCI_CORE_HANDLE *)core_handle; UINTN base_addr; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_set_link_state: INVALID handle\n")); return EFI_DEVICE_ERROR; } base_addr = local_core_handle->base_address; /* Clear old mask */ usb_reg_write ( base_addr, DWC_XDCI_DCTL_REG, usb_reg_read (base_addr, DWC_XDCI_DCTL_REG) & ~DWC_XDCI_DCTL_STATE_CHANGE_REQ_MASK ); /* Request new state */ usb_reg_write ( base_addr, DWC_XDCI_DCTL_REG, usb_reg_read (base_addr, DWC_XDCI_DCTL_REG) | (state << DWC_XDCI_DCTL_STATE_CHANGE_REQ_BIT_POS) ); return EFI_SUCCESS; } /** Interface: This function is used to initialize endpoint @core_handle: xDCI controller handle @ep_info: Address of structure describing properties of EP to be initialized **/ EFI_STATUS EFIAPI dwc_xdci_init_ep ( IN VOID *core_handle, IN USB_EP_INFO *ep_info ) { XDCI_CORE_HANDLE *local_core_handle = (XDCI_CORE_HANDLE *)core_handle; DWC_XDCI_ENDPOINT_CMD_PARAMS ep_cmd_params; EFI_STATUS status; UINT32 ep_num; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_init_ep: INVALID handle\n")); return EFI_DEVICE_ERROR; } /* Convert to physical endpoint */ ep_num = dwc_xdci_get_physical_ep_num (ep_info->ep_num, ep_info->ep_dir); /* Save EP properties */ CopyMem (&(local_core_handle->ep_handles[ep_num].ep_info), ep_info, sizeof (USB_EP_INFO)); // Init CheckFlag local_core_handle->ep_handles[ep_num].CheckFlag = FALSE; /* Init DEPCFG cmd params for EP */ status = dwc_xdci_core_init_ep_cmd_params ( core_handle, &local_core_handle->ep_handles[ep_num].ep_info, DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_INIT_STATE, EPCMD_SET_EP_CONFIG, &ep_cmd_params ); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_init_ep: Failed to init params for EPCMD_SET_EP_CONFIG command\n")); return status; } /* Issue the command */ status = dwc_xdci_core_issue_ep_cmd ( core_handle, ep_num, EPCMD_SET_EP_CONFIG, &ep_cmd_params ); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_init_ep: Failed to issue EPCMD_SET_EP_CONFIG command\n")); return status; } /* Issue a DEPXFERCFG command for endpoint */ status = dwc_xdci_core_init_ep_cmd_params ( local_core_handle, &local_core_handle->ep_handles[ep_num].ep_info, DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_NONE, EPCMD_SET_EP_XFER_RES_CONFIG, &ep_cmd_params ); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_init_ep: Failed to init params for EPCMD_SET_EP_XFER_RES_CONFIG command\n")); return status; } /* Issue the command */ status = dwc_xdci_core_issue_ep_cmd ( local_core_handle, ep_num, EPCMD_SET_EP_XFER_RES_CONFIG, &ep_cmd_params ); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_init_ep: Failed to issue EPCMD_SET_EP_XFER_RES_CONFIG command\n")); } return status; } /** Interface: This function is used to enable non-Ep0 endpoint @core_handle: xDCI controller handle @ep_info: Address of structure describing properties of EP to be enabled **/ EFI_STATUS EFIAPI dwc_xdci_ep_enable ( IN VOID *core_handle, IN USB_EP_INFO *ep_info ) { XDCI_CORE_HANDLE *local_core_handle = (XDCI_CORE_HANDLE *)core_handle; UINT32 ep_num; UINTN base_addr; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_ep_enable: INVALID handle\n")); return EFI_DEVICE_ERROR; } base_addr = local_core_handle->base_address; /* Convert to physical endpoint */ ep_num = dwc_xdci_get_physical_ep_num (ep_info->ep_num, ep_info->ep_dir); /* Enable Physical Endpoint ep_num */ usb_reg_write ( base_addr, DWC_XDCI_EP_DALEPENA_REG, usb_reg_read (base_addr, DWC_XDCI_EP_DALEPENA_REG) | (1 << ep_num) ); return EFI_SUCCESS; } /** Interface: This function is used to disable non-Ep0 endpoint @core_handle: xDCI controller handle @ep_info: Address of structure describing properties of EP to be enabled **/ EFI_STATUS EFIAPI dwc_xdci_ep_disable ( IN VOID *core_handle, IN USB_EP_INFO *ep_info ) { XDCI_CORE_HANDLE *local_core_handle = (XDCI_CORE_HANDLE *)core_handle; UINT32 ep_num; UINTN base_addr; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_ep_disable: INVALID handle\n")); return EFI_DEVICE_ERROR; } base_addr = local_core_handle->base_address; /* Convert to physical endpoint */ ep_num = dwc_xdci_get_physical_ep_num (ep_info->ep_num, ep_info->ep_dir); /* Disable Physical Endpoint ep_num */ usb_reg_write ( base_addr, DWC_XDCI_EP_DALEPENA_REG, usb_reg_read (base_addr, DWC_XDCI_EP_DALEPENA_REG) & ~(1 << ep_num) ); return EFI_SUCCESS; } /** Interface: This function is used to STALL and endpoint @core_handle: xDCI controller handle @ep_info: Address of structure describing properties of EP to be enabled **/ EFI_STATUS EFIAPI dwc_xdci_ep_stall ( IN VOID *core_handle, IN USB_EP_INFO *ep_info ) { XDCI_CORE_HANDLE *local_core_handle = (XDCI_CORE_HANDLE *)core_handle; DWC_XDCI_ENDPOINT_CMD_PARAMS ep_cmd_params; EFI_STATUS Status; UINT32 ep_num; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_ep_stall: INVALID handle\n")); return EFI_DEVICE_ERROR; } /* Convert to physical endpoint */ ep_num = dwc_xdci_get_physical_ep_num (ep_info->ep_num, ep_info->ep_dir); /* Set Ep State Info */ if (local_core_handle->ep_handles[ep_num].state != USB_EP_STATE_STALLED) { local_core_handle->ep_handles[ep_num].Orgstate = local_core_handle->ep_handles[ep_num].state; local_core_handle->ep_handles[ep_num].state = USB_EP_STATE_STALLED; } /* Issue a DWC_XDCI_EPCMD_SET_STALL for EP */ /* Reset params */ ep_cmd_params.param0 = ep_cmd_params.param1 = ep_cmd_params.param2 = 0; /* Issue the command */ Status = dwc_xdci_core_issue_ep_cmd ( local_core_handle, ep_num, DWC_XDCI_EPCMD_SET_STALL, &ep_cmd_params ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_INFO, "dwc_xdci_ep_stall: Failed to issue EP stall command\n")); } return Status; } /** Interface: This function is used to clear endpoint STALL @core_handle: xDCI controller handle @ep_info: Address of structure describing properties of EP to be enabled **/ EFI_STATUS EFIAPI dwc_xdci_ep_clear_stall ( IN VOID *core_handle, IN USB_EP_INFO *ep_info ) { XDCI_CORE_HANDLE *local_core_handle = (XDCI_CORE_HANDLE *)core_handle; DWC_XDCI_ENDPOINT_CMD_PARAMS ep_cmd_params; EFI_STATUS Status; UINT32 ep_num; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_ep_clear_stall: INVALID handle\n")); return EFI_DEVICE_ERROR; } /* Convert to physical endpoint */ ep_num = dwc_xdci_get_physical_ep_num (ep_info->ep_num, ep_info->ep_dir); /* Set Ep State Info */ local_core_handle->ep_handles[ep_num].state = local_core_handle->ep_handles[ep_num].Orgstate; /* Issue a DWC_XDCI_EPCMD_CLEAR_STALL for EP */ /* Reset params */ ep_cmd_params.param0 = ep_cmd_params.param1 = ep_cmd_params.param2 = 0; /* Issue the command */ Status = dwc_xdci_core_issue_ep_cmd ( local_core_handle, ep_num, DWC_XDCI_EPCMD_CLEAR_STALL, &ep_cmd_params ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_INFO, "dwc_xdci_ep_stall: Failed to issue EP clea stall command\n")); } return Status; } /** Interface: This function is used to set endpoint in NOT READY state @core_handle: xDCI controller handle @ep_info: Address of structure describing properties of EP to be enabled **/ EFI_STATUS EFIAPI dwc_xdci_ep_set_nrdy ( IN VOID *core_handle, IN USB_EP_INFO *ep_info ) { XDCI_CORE_HANDLE *local_core_handle = (XDCI_CORE_HANDLE *)core_handle; UINT32 ep_num; UINTN base_addr; UINT32 max_delay_iter = DWC_XDCI_MAX_DELAY_ITERATIONS; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_ep_set_nrdy: INVALID handle\n")); return EFI_DEVICE_ERROR; } base_addr = local_core_handle->base_address; /* Convert to physical endpoint */ ep_num = dwc_xdci_get_physical_ep_num (ep_info->ep_num, ep_info->ep_dir); /* Program the EP number in command's param reg */ usb_reg_write (base_addr, DWC_XDCI_DGCMD_PARAM_REG, ep_num); /* Issue EP not ready generic device command */ usb_reg_write ( base_addr, DWC_XDCI_DGCMD_REG, (usb_reg_read (base_addr, DWC_XDCI_DGCMD_REG) | DWC_XDCI_DGCMD_CMD_SET_EP_NRDY) ); /* Activate the command */ usb_reg_write ( base_addr, DWC_XDCI_DGCMD_REG, (usb_reg_read (base_addr, DWC_XDCI_DGCMD_REG) | DWC_XDCI_DGCMD_CMD_ACTIVE_MASK) ); /* Wait until command completes */ do { if (!(usb_reg_read (base_addr, DWC_XDCI_DGCMD_REG) & DWC_XDCI_DGCMD_CMD_ACTIVE_MASK)) break; else gBS->Stall (DWC_XDCI_MAX_DELAY_ITERATIONS); } while (--max_delay_iter); if (!max_delay_iter) { DEBUG ((DEBUG_INFO, "Failed to issue Command\n")); return EFI_DEVICE_ERROR; } return EFI_SUCCESS; } /** Interface: This function is used to queue receive SETUP packet request @core_handle: xDCI controller handle @buffer: Address of buffer to receive SETUP packet **/ EFI_STATUS EFIAPI dwc_xdci_ep0_receive_setup_pkt ( IN VOID *core_handle, IN UINT8 *buffer ) { XDCI_CORE_HANDLE *local_core_handle = (XDCI_CORE_HANDLE *)core_handle; DWC_XDCI_ENDPOINT_CMD_PARAMS ep_cmd_params; EFI_STATUS Status = EFI_DEVICE_ERROR; DWC_XDCI_TRB *trb; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_ep0_receive_setup_pkt: INVALID handle\n")); return EFI_DEVICE_ERROR; } local_core_handle->ep_handles[0].ep_info.ep_num = 0; local_core_handle->ep_handles[0].ep_info.ep_dir = 0; local_core_handle->ep_handles[0].state = USB_EP_STATE_SETUP; trb = local_core_handle->trbs; DEBUG ((DEBUG_INFO, "(dwc_xdci_ep0_receive_setup_pkt)\n")); Status = dwc_xdci_core_init_trb ( local_core_handle, trb, TRBCTL_SETUP, buffer, 8 ); if (Status) { DEBUG ((DEBUG_INFO, "dwc_xdci_ep0_receive_setup_pkt: Init TRB Failed \n")); return Status; } /* Issue a DEPSTRTXFER for EP0 */ /* Reset params */ ep_cmd_params.param0 = ep_cmd_params.param1 = ep_cmd_params.param2 = 0; /* Init the lower re-bits for TRB address */ ep_cmd_params.param1 = (UINT32)(UINTN)trb; /* Issue the command */ Status = dwc_xdci_core_issue_ep_cmd ( local_core_handle, 0, EPCMD_START_XFER, &ep_cmd_params ); if (Status) { DEBUG ((DEBUG_INFO, "\ndwc_xdci_ep0_receive_setup_pkt: Failed to issue Start Transfer command")); } /* Save new resource index for this transfer */ local_core_handle->ep_handles[0].currentXferRscIdx = ((usb_reg_read(local_core_handle->base_address, DWC_XDCI_EPCMD_REG(0)) & DWC_XDCI_EPCMD_RES_IDX_MASK) >> DWC_XDCI_EPCMD_RES_IDX_BIT_POS ); return Status; } /** Interface: This function is used to queue receive status packet on EP0 @core_handle: xDCI controller handle **/ EFI_STATUS EFIAPI dwc_xdci_ep0_receive_status_pkt ( IN VOID *core_handle ) { XDCI_CORE_HANDLE *local_core_handle = (XDCI_CORE_HANDLE *)core_handle; DWC_XDCI_TRB *trb; DWC_XDCI_TRB_CONTROL trb_ctrl; DWC_XDCI_ENDPOINT_CMD_PARAMS ep_cmd_params; EFI_STATUS Status; UINTN base_addr; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_ep0_receive_status_pkt: INVALID handle\n")); return EFI_DEVICE_ERROR; } base_addr = local_core_handle->base_address; /* We are receiving on EP0 so physical EP is 0 */ trb = local_core_handle->trbs; DEBUG ((DEBUG_INFO, "(dwc_xdci_ep0_receive_status_pkt)\n")); if (trb->trb_ctrl & DWC_XDCI_TRB_CTRL_HWO_MASK) { DEBUG ((DEBUG_INFO, "status_pkt still not transferred.\n")); return EFI_SUCCESS; } local_core_handle->ep_handles[0].ep_info.ep_num = 0; local_core_handle->ep_handles[0].ep_info.ep_dir = 0; /* OUT data phase for 3-phased control transfer */ trb_ctrl = TRBCTL_3_PHASE; /* Init TRB for the transfer */ Status = dwc_xdci_core_init_trb ( local_core_handle, trb, trb_ctrl, local_core_handle->aligned_setup_buffer, 0 ); if (!Status) { /* Issue a DEPSTRTXFER for EP0 */ /* Reset params */ ep_cmd_params.param0 = ep_cmd_params.param1 = ep_cmd_params.param2 = 0; /* Init the lower bits for TRB address */ ep_cmd_params.param1 = (UINT32)(UINTN)trb; /* Issue the command */ Status = dwc_xdci_core_issue_ep_cmd ( local_core_handle, 0, EPCMD_START_XFER, &ep_cmd_params ); if (Status) { DEBUG ((DEBUG_INFO, "dwc_xdci_ep0_receive_status_pkt: Failed to issue Start Transfer command for EP0\n")); } /* Save new resource index for this transfer */ local_core_handle->ep_handles[0].currentXferRscIdx = ((usb_reg_read(base_addr, DWC_XDCI_EPCMD_REG(0)) & DWC_XDCI_EPCMD_RES_IDX_MASK) >> DWC_XDCI_EPCMD_RES_IDX_BIT_POS); /* TODO: We are not using the EP state for control transfers * right now simply because we're only supporting IN * data phase. For the current use case, we don't * need OUT data phase. We can add that later and we will * add some of the state and SETUP packet awareness code */ local_core_handle->ep_handles[0].state = USB_EP_STATE_STATUS; } return Status; } /** Interface: This function is used to send status packet on EP0 @core_handle: xDCI controller handle **/ EFI_STATUS EFIAPI dwc_xdci_ep0_send_status_pkt ( IN VOID *core_handle ) { XDCI_CORE_HANDLE *local_core_handle = (XDCI_CORE_HANDLE *)core_handle; DWC_XDCI_TRB *trb; DWC_XDCI_ENDPOINT_CMD_PARAMS ep_cmd_params; EFI_STATUS Status; UINTN base_addr; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_ep0_send_status_pkt: INVALID handle\n")); return EFI_DEVICE_ERROR; } base_addr = local_core_handle->base_address; /* We are sending on EP0 so physical EP is 1 */ trb = (local_core_handle->trbs + (1 * DWC_XDCI_TRB_NUM)); DEBUG ((DEBUG_INFO, "(dwc_xdci_ep0_send_status_pkt)\n")); local_core_handle->ep_handles[0].state = USB_EP_STATE_STATUS; Status = dwc_xdci_core_init_trb ( local_core_handle, trb, TRBCTL_2_PHASE, local_core_handle->aligned_misc_buffer, 0 ); if (Status) { DEBUG ((DEBUG_INFO, "dwc_xdci_ep0_send_status_pkt: TRB failed during status phase\n")); return Status; } /* Issue a DEPSTRTXFER for EP1 */ /* Reset params */ ep_cmd_params.param0 = ep_cmd_params.param1 = ep_cmd_params.param2 = 0; /* Init the lower re-bits for TRB address */ ep_cmd_params.param1 = (UINT32)(UINTN)trb; /* Issue the command */ Status = dwc_xdci_core_issue_ep_cmd ( local_core_handle, 1, EPCMD_START_XFER, &ep_cmd_params ); if (Status) { DEBUG ((DEBUG_INFO, "dwc_xdci_ep0_send_status_pkt: Failed to issue Start Transfer on EP0\n")); } /* Save new resource index for this transfer */ local_core_handle->ep_handles[1].currentXferRscIdx = ((usb_reg_read(base_addr, DWC_XDCI_EPCMD_REG(1)) & DWC_XDCI_EPCMD_RES_IDX_MASK) >> DWC_XDCI_EPCMD_RES_IDX_BIT_POS); local_core_handle->ep_handles[0].state = USB_EP_STATE_STATUS; return Status; } /** Interface: This function is used to send data on non-EP0 endpoint @core_handle: xDCI controller handle @ep_info: Address of structure describing properties of EP @buffer: buffer containing data to transmit @size: Size of transfer (in bytes) **/ EFI_STATUS EFIAPI dwc_xdci_ep_tx_data ( IN VOID *core_handle, IN USB_XFER_REQUEST *xfer_req ) { XDCI_CORE_HANDLE *local_core_handle = (XDCI_CORE_HANDLE *)core_handle; DWC_XDCI_ENDPOINT_CMD_PARAMS ep_cmd_params; DWC_XDCI_TRB *trb; DWC_XDCI_TRB_CONTROL trb_ctrl; EFI_STATUS Status; UINT32 ep_num; UINTN base_addr; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_ep_tx_data: INVALID handle\n")); return EFI_DEVICE_ERROR; } if (xfer_req == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_ep_tx_data: INVALID transfer request\n")); return EFI_INVALID_PARAMETER; } base_addr = local_core_handle->base_address; /* Convert to physical endpoint */ ep_num = dwc_xdci_get_physical_ep_num ( xfer_req->ep_info.ep_num, xfer_req->ep_info.ep_dir ); trb = (local_core_handle->trbs + (ep_num * DWC_XDCI_TRB_NUM)); DEBUG ((DEBUG_INFO, "(dwc_xdci_ep_tx_data)ep_num is %d\n", ep_num)); if (ep_num > 1) trb_ctrl = TRBCTL_NORMAL; else trb_ctrl = TRBCTL_CTRL_DATA_PHASE; if (trb->trb_ctrl & DWC_XDCI_TRB_CTRL_HWO_MASK) { Status = dwc_xdci_end_xfer (local_core_handle, ep_num); if (Status) { DEBUG ((DEBUG_INFO, "dwc_xdci_ep_tx_data: Failed to end previous transfer\n")); } Status = dwc_xdci_core_flush_ep_tx_fifo (local_core_handle, ep_num); if (Status) { DEBUG ((DEBUG_INFO, "dwc_xdci_ep_tx_data: Failed to end previous transfer\n")); } } /* Data phase */ // local_core_handle->ep_handles[ep_num].xfer_handle = *xfer_req; CopyMem (&(local_core_handle->ep_handles[ep_num].xfer_handle), xfer_req, sizeof (USB_XFER_REQUEST)); local_core_handle->ep_handles[ep_num].state = USB_EP_STATE_DATA; local_core_handle->ep_handles[ep_num].trb = trb; Status = dwc_xdci_core_init_trb ( local_core_handle, trb, trb_ctrl, xfer_req->xfer_buffer, xfer_req->xfer_len ); if (Status) { DEBUG ((DEBUG_INFO, "dwc_xdci_ep_tx_data: TRB failed\n")); return Status; } /* Issue a DEPSTRTXFER for EP */ /* Reset params */ ep_cmd_params.param0 = ep_cmd_params.param1 = ep_cmd_params.param2 = 0; /* Init the lower re-bits for TRB address */ ep_cmd_params.param1 = (UINT32)(UINTN)trb; /* Issue the command */ Status = dwc_xdci_core_issue_ep_cmd ( local_core_handle, ep_num, EPCMD_START_XFER, &ep_cmd_params ); /* Save new resource index for this transfer */ local_core_handle->ep_handles[ep_num].currentXferRscIdx = ((usb_reg_read (base_addr, DWC_XDCI_EPCMD_REG(ep_num)) & DWC_XDCI_EPCMD_RES_IDX_MASK) >> DWC_XDCI_EPCMD_RES_IDX_BIT_POS); return Status; } /** Interface: This function is used to receive data on non-EP0 endpoint @core_handle: xDCI controller handle @ep_info: Address of structure describing properties of EP @buffer: buffer containing data to transmit @size: Size of transfer (in bytes) **/ EFI_STATUS EFIAPI dwc_xdci_ep_rx_data ( IN VOID *core_handle, IN USB_XFER_REQUEST *xfer_req ) { XDCI_CORE_HANDLE *local_core_handle = (XDCI_CORE_HANDLE *)core_handle; DWC_XDCI_ENDPOINT_CMD_PARAMS ep_cmd_params; DWC_XDCI_TRB *trb; DWC_XDCI_TRB_CONTROL trb_ctrl; EFI_STATUS Status; UINT32 ep_num; UINTN base_addr; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_ep_rx_data: INVALID handle\n")); return EFI_DEVICE_ERROR; } if (xfer_req == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_ep_rx_data: INVALID transfer request\n")); return EFI_INVALID_PARAMETER; } base_addr = local_core_handle->base_address; /* Convert to physical endpoint */ ep_num = dwc_xdci_get_physical_ep_num (xfer_req->ep_info.ep_num, xfer_req->ep_info.ep_dir); trb = (local_core_handle->trbs + (ep_num * DWC_XDCI_TRB_NUM)); DEBUG ((DEBUG_INFO, "(dwc_xdci_ep_rx_data)ep_num is %d\n", ep_num)); if (ep_num > 1) trb_ctrl = TRBCTL_NORMAL; else trb_ctrl = TRBCTL_CTRL_DATA_PHASE; // // If CheckFlag didn't set to FALSE, means the previous transfer request didn't complete, // need to wait the previous request done. // if (local_core_handle->ep_handles[ep_num].CheckFlag == TRUE) { return EFI_NOT_READY; } local_core_handle->ep_handles[ep_num].CheckFlag = TRUE; /* Data phase */ CopyMem (&(local_core_handle->ep_handles[ep_num].xfer_handle), xfer_req, sizeof (USB_XFER_REQUEST)); local_core_handle->ep_handles[ep_num].state = USB_EP_STATE_DATA; local_core_handle->ep_handles[ep_num].trb = trb; DEBUG ((DEBUG_INFO, "(dwc_xdci_ep_rx_data)xfer_req->xfer_len is 0x%x\n", xfer_req->xfer_len)); Status = dwc_xdci_core_init_trb ( local_core_handle, trb, trb_ctrl, xfer_req->xfer_buffer, xfer_req->xfer_len ); if (Status) { DEBUG ((DEBUG_INFO, "dwc_xdci_ep_rx_data: TRB failed\n")); return Status; } /* Issue a DEPSTRTXFER for EP */ /* Reset params */ ep_cmd_params.param0 = ep_cmd_params.param1 = ep_cmd_params.param2 = 0; /* Init the lower re-bits for TRB address */ ep_cmd_params.param1 = (UINT32)(UINTN)trb; /* Issue the command */ Status = dwc_xdci_core_issue_ep_cmd ( local_core_handle, ep_num, EPCMD_START_XFER, &ep_cmd_params ); if (Status) { DEBUG ((DEBUG_INFO, "dwc_xdci_ep_rx_data: Failed to start transfer\n")); } /* Save new resource index for this transfer */ local_core_handle->ep_handles[ep_num].currentXferRscIdx = ((usb_reg_read(base_addr, DWC_XDCI_EPCMD_REG(ep_num)) & DWC_XDCI_EPCMD_RES_IDX_MASK) >> DWC_XDCI_EPCMD_RES_IDX_BIT_POS); return Status; } STATIC EFI_STATUS dwc_xdci_core_flush_ep_fifo ( IN XDCI_CORE_HANDLE *core_handle, IN UINT32 ep_num ) { UINTN base_addr; UINT32 max_delay_iter = DWC_XDCI_MAX_DELAY_ITERATIONS; UINT32 fifo_num; UINT32 Param; UINT32 Cmd; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "ERROR: dwc_xdci_core_flush_ep_tx_fifo: INVALID handle\n")); return EFI_DEVICE_ERROR; } base_addr = core_handle->base_address; /* Translate to FIFOnum * NOTE: Assuming this is a Tx EP */ fifo_num = (ep_num >> 1); /* TODO: Currently we are only using TxFIFO 0. Later map these * Write the FIFO num/dir param for the generic command. */ Param = usb_reg_read (base_addr, DWC_XDCI_DGCMD_PARAM_REG); Param &= ~(DWC_XDCI_DGCMD_PARAM_TX_FIFO_NUM_MASK | DWC_XDCI_DGCMD_PARAM_TX_FIFO_DIR_MASK); if ((ep_num & 0x01) != 0) { Param |= (fifo_num | DWC_XDCI_DGCMD_PARAM_TX_FIFO_DIR_MASK); } else { Param |= fifo_num; } Cmd = usb_reg_read(base_addr, DWC_XDCI_DGCMD_REG) & ~(DWC_XDCI_DGCMD_CMD_TYPE_MASK | DWC_XDCI_DGCMD_CMD_IOC_MASK); DEBUG ((DEBUG_INFO, "USB FU Flash: CMD 0x%08x :: Param 0x%08x\n", (Cmd | DWC_XDCI_DGCMD_CMD_SEL_FIFO_FLUSH | DWC_XDCI_DGCMD_CMD_ACTIVE_MASK), Param)); usb_reg_write ( base_addr, DWC_XDCI_DGCMD_PARAM_REG, Param ); /* Write the command to flush all FIFOs */ usb_reg_write ( base_addr, DWC_XDCI_DGCMD_REG, (Cmd | DWC_XDCI_DGCMD_CMD_SEL_FIFO_FLUSH | DWC_XDCI_DGCMD_CMD_ACTIVE_MASK) ); /* Wait until command completes */ do { if (!(usb_reg_read(base_addr, DWC_XDCI_DGCMD_REG) & DWC_XDCI_DGCMD_CMD_ACTIVE_MASK)) break; else gBS->Stall (DWC_XDCI_MAX_DELAY_ITERATIONS); } while (--max_delay_iter); if (!max_delay_iter) { DEBUG ((DEBUG_INFO, "Failed to issue Command\n")); return EFI_DEVICE_ERROR; } return EFI_SUCCESS; } /** Interface: This function is used to cancel a transfer on non-EP0 endpoint @core_handle: xDCI controller handle @ep_info: Address of structure describing properties of EP **/ EFI_STATUS EFIAPI dwc_xdci_ep_cancel_transfer ( IN VOID *core_handle, IN USB_EP_INFO *ep_info ) { EFI_STATUS Status = EFI_DEVICE_ERROR; UINT32 ep_num; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_ep_cancel_transfer: INVALID handle\n")); return EFI_DEVICE_ERROR; } /* Get physical EP num */ ep_num = dwc_xdci_get_physical_ep_num (ep_info->ep_num, ep_info->ep_dir); Status = dwc_xdci_end_xfer(core_handle, ep_num); dwc_xdci_core_flush_ep_fifo(core_handle, ep_num); return Status; } EFI_STATUS usb_process_device_reset_det ( IN XDCI_CORE_HANDLE *core_handle ) { return dwc_xdci_process_device_reset_det (core_handle); } EFI_STATUS usb_process_device_reset_done ( IN XDCI_CORE_HANDLE *core_handle ) { return dwc_xdci_process_device_reset_done (core_handle); } UINT32 usb_get_physical_ep_num ( IN UINT32 EndpointNum, IN USB_EP_DIR EndpointDir ) { return dwc_xdci_get_physical_ep_num( EndpointNum, EndpointDir ); } EFI_STATUS EFIAPI usb_xdci_core_reinit ( // IN USB_DEV_CONFIG_PARAMS *ConfigParams, // IN VOID *device_core_ptr, IN VOID *core_handle ) { EFI_STATUS status = EFI_DEVICE_ERROR; UINTN base_addr; XDCI_CORE_HANDLE *local_core_handle; DWC_XDCI_ENDPOINT_CMD_PARAMS ep_cmd_params; local_core_handle = core_handle; if (core_handle == NULL) { return EFI_INVALID_PARAMETER; } if (local_core_handle == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_init: Failed to allocate handle for xDCI\n")); return EFI_OUT_OF_RESOURCES; } base_addr = local_core_handle->base_address; /* Issue DEPSTARTCFG command for EP0 */ status = dwc_xdci_core_init_ep_cmd_params ( local_core_handle, &local_core_handle->ep_handles[0].ep_info, DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_NONE, EPCMD_START_NEW_CONFIG, &ep_cmd_params ); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_init: Failed to init params for START_NEW_CONFIG EP command on xDCI\n")); return status; } /* Issue the command */ status = dwc_xdci_core_issue_ep_cmd ( local_core_handle, 0, EPCMD_START_NEW_CONFIG, &ep_cmd_params ); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_init: Failed to issue START_NEW_CONFIG EP command on xDCI\n")); return status; } /* Issue DEPCFG command for EP0 */ status = dwc_xdci_core_init_ep_cmd_params ( local_core_handle, &local_core_handle->ep_handles[0].ep_info, DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_INIT_STATE, EPCMD_SET_EP_CONFIG, &ep_cmd_params ); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_init: Failed to init params for SET_EP_CONFIG command on xDCI for EP0\n")); return status; } /* Issue the command */ status = dwc_xdci_core_issue_ep_cmd ( local_core_handle, 0, EPCMD_SET_EP_CONFIG, &ep_cmd_params); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_init: Failed to issue SET_EP_CONFIG command on xDCI for EP0\n")); return status; } /* Issue DEPCFG command for EP1 */ status = dwc_xdci_core_init_ep_cmd_params ( local_core_handle, &local_core_handle->ep_handles[1].ep_info, DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_INIT_STATE, EPCMD_SET_EP_CONFIG, &ep_cmd_params ); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_init: Failed to init params for SET_EP_CONFIG command on xDCI for EP1\n")); return status; } /* Issue the command */ status = dwc_xdci_core_issue_ep_cmd ( local_core_handle, 1, EPCMD_SET_EP_CONFIG, &ep_cmd_params ); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_init: Failed to issue SET_EP_CONFIG command on xDCI for EP1\n")); return status; } /* Issue DEPXFERCFG command for EP0 */ status = dwc_xdci_core_init_ep_cmd_params ( local_core_handle, &local_core_handle->ep_handles[0].ep_info, DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_NONE, EPCMD_SET_EP_XFER_RES_CONFIG, &ep_cmd_params ); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_init: Failed to init params for EPCMD_SET_EP_XFER_RES_CONFIG command on xDCI for EP0\n")); return status; } /* Issue the command */ status = dwc_xdci_core_issue_ep_cmd ( local_core_handle, 0, EPCMD_SET_EP_XFER_RES_CONFIG, &ep_cmd_params ); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_init: Failed to issue EPCMD_SET_EP_XFER_RES_CONFIG command on xDCI for EP0\n")); return status; } /* Issue DEPXFERCFG command for EP1 */ status = dwc_xdci_core_init_ep_cmd_params ( local_core_handle, &local_core_handle->ep_handles[1].ep_info, DWC_XDCI_PARAM0_SET_EP_CFG_ACTN_NONE, EPCMD_SET_EP_XFER_RES_CONFIG, &ep_cmd_params ); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_init: Failed to init params for EPCMD_SET_EP_XFER_RES_CONFIG command on xDCI for EP1\n")); return status; } /* Issue the command */ status = dwc_xdci_core_issue_ep_cmd ( local_core_handle, 1, EPCMD_SET_EP_XFER_RES_CONFIG, &ep_cmd_params ); if (status) { DEBUG ((DEBUG_INFO, "dwc_xdci_core_init: Failed to issue EPCMD_SET_EP_XFER_RES_CONFIG command on xDCI for EP1\n")); return status; } /* Prepare a buffer for SETUP packet */ local_core_handle->trbs = (DWC_XDCI_TRB *)(UINTN)((UINT32)(UINTN) local_core_handle->unaligned_trbs + (DWC_XDCI_TRB_BYTE_ALIGNMENT - ((UINT32)(UINTN)local_core_handle->unaligned_trbs % DWC_XDCI_TRB_BYTE_ALIGNMENT))); DEBUG ((DEBUG_INFO, "(dwc_xdci_core_init)@@@@@@@@@ unaligned_trbs address is 0x%x\n", local_core_handle->unaligned_trbs)); DEBUG ((DEBUG_INFO, "(dwc_xdci_core_init)@@@@@@@@@ TRB address is 0x%x\n", local_core_handle->trbs)); /* Allocate Setup buffer that is 8-byte aligned */ local_core_handle->aligned_setup_buffer = local_core_handle->default_setup_buffer + (DWC_XDCI_SETUP_BUFF_SIZE - ((UINT32)(UINTN)(local_core_handle->default_setup_buffer) % DWC_XDCI_SETUP_BUFF_SIZE)); /* Aligned buffer for status phase */ local_core_handle->aligned_misc_buffer = local_core_handle->misc_buffer + (DWC_XDCI_SETUP_BUFF_SIZE - ((UINT32)(UINTN)(local_core_handle->aligned_misc_buffer) % DWC_XDCI_SETUP_BUFF_SIZE)); /* We will queue SETUP request when we see bus reset */ /* Enable Physical Endpoints 0 */ usb_reg_write ( base_addr, DWC_XDCI_EP_DALEPENA_REG, usb_reg_read (base_addr, DWC_XDCI_EP_DALEPENA_REG) | (1 << 0) ); /* Enable Physical Endpoints 1 */ usb_reg_write ( base_addr, DWC_XDCI_EP_DALEPENA_REG, usb_reg_read (base_addr, DWC_XDCI_EP_DALEPENA_REG) | (1 << 1) ); DEBUG ((DEBUG_INFO, "Default value of xDCI DWC_XDCI_DEVTEN_REG: 0x%x\n", usb_reg_read (base_addr, DWC_XDCI_DEVTEN_REG))); return status; } EFI_STATUS usb_xdci_core_flush_ep_fifo ( IN VOID *core_handle, IN USB_EP_INFO *ep_info ) { EFI_STATUS Status = EFI_DEVICE_ERROR; UINT32 ep_num; if (core_handle == NULL) { DEBUG ((DEBUG_INFO, "dwc_xdci_ep_cancel_transfer: INVALID handle\n")); return EFI_DEVICE_ERROR; } /* Get physical EP num */ ep_num = dwc_xdci_get_physical_ep_num (ep_info->ep_num, ep_info->ep_dir); dwc_xdci_core_flush_ep_fifo(core_handle, ep_num); return Status; } EFI_STATUS usb_process_device_disconnect ( IN XDCI_CORE_HANDLE *core_handle ) { return dwc_xdci_core_disconnect (core_handle); } #if defined(_MSC_VER) /* MSVC Compiler section */ #pragma optimize ("", on) #endif