| /****************************************************************************** |
| * |
| * (C)Copyright 2013 - 2014 Marvell. All Rights Reserved. |
| * |
| * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MARVELL. |
| * The copyright notice above does not evidence any actual or intended |
| * publication of such source code. |
| * This Module contains Proprietary Information of Marvell and should be |
| * treated as Confidential. |
| * The information in this file is provided for the exclusive use of the |
| * licensees of Marvell. |
| * Such users have the right to use, modify, and incorporate this code into |
| * products for purposes authorized by the license agreement provided they |
| * include this notice and the associated copyright notice with any such |
| * product. |
| * The information in this file is provided "AS IS" without warranty. |
| * |
| ******************************************************************************/ |
| |
| |
| #include "Typedef.h" |
| #include "misc.h" |
| #include "timer.h" |
| #include "usb_descriptors.h" |
| #include "usbapi.h" |
| #include "usb2_main.h" |
| #include "usb2_memory.h" |
| #include "usb2_enumeration.h" |
| #include "ProtocolManager.h" |
| //#include "USB2.h" |
| #include "snps_usb.h" |
| |
| #define CIU_REG_CHIPID (0xD4282C00) |
| |
| #define USB_ENABLE_DEBUG 1 |
| #ifdef USB_ENABLE_DEBUG |
| #define NR_LOGGING_ARRAY (32) |
| #define USB_CMD_PASS (0) |
| #define USB_CMD_FAIL1 (1) |
| #define USB_CMD_FAIL2 (2) |
| #define USB_CMD_FAIL3 (3) |
| #define USB_CMD_FAIL4 (4) |
| #define USB_CMD_FAIL5 (5) |
| //32*32 =1024 |
| struct usb_cmd_params usbcmd_logging_array[NR_LOGGING_ARRAY]; |
| int usbcmd_logging_ptr = 0; |
| //char usbsend_len_table[NR_LOGGING_ARRAY]; |
| //int usbsend_len_ptr = 0; |
| USHORT usbrecv_len_table[NR_LOGGING_ARRAY]; |
| int usbrecv_len_ptr = 0; |
| struct usb_trb_params usbep0_trb_table[NR_LOGGING_ARRAY]; |
| int usbep0_trb_ptr = 0; |
| struct usb_trb_params usbep1_trb_table[NR_LOGGING_ARRAY]; |
| int usbep1_trb_ptr = 0; |
| char usbep0_nrdy_table[NR_LOGGING_ARRAY]; |
| int usbep0_nrdy_ptr = 0; |
| short usbcmd_cur_cmd_result = 0; |
| short usbep1_data_count = 0; |
| short usbcmd_setlink_count = 0; |
| short usbcmd_setlink_fail_count = 0; |
| short usbep0_nrdy_fail_count = 0; |
| short usbep0_data_nrdy_count = 0; |
| #endif |
| |
| static int IS_PTRB_OK(UINT_T ptrb) |
| { |
| if (ptrb >= 0x000000 && ptrb < 0xc0000000) |
| return 1; |
| else |
| return 0; |
| } |
| |
| int DWC3_SET_LINK_STATE(enum dwc3_link_state state) |
| { |
| int retries = 10000; |
| UINT reg; |
| |
| /* |
| * Wait until device controller is ready. Only applies to 1.94a and |
| * later RTL. |
| */ |
| while (--retries) { |
| reg = DWC3_REG_READ(DWC3_DSTS); |
| bbu_printf("%s: DWC3_DSTS: 0x%x\n\r", __func__, reg); |
| if (!(reg & DWC3_DSTS_DCNRD)) |
| break; |
| Delay(5); |
| } |
| |
| if (retries <= 0) |
| return -1; |
| |
| reg = DWC3_REG_READ(DWC3_DCTL); |
| reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK; |
| |
| /* set requested state */ |
| reg |= DWC3_DCTL_ULSTCHNGREQ(state); |
| DWC3_REG_WRITE(DWC3_DCTL, reg); |
| |
| bbu_printf("%s: retries: %d DWC3_DCTL: 0x%x\n\r", __func__, retries, reg); |
| return 0; |
| } |
| |
| static int DO_DWC3_GADGET_WAKEUP(void) |
| { |
| int retries; |
| int ret; |
| UINT reg; |
| UINT link_state; |
| |
| reg = DWC3_REG_READ(DWC3_DSTS); |
| bbu_printf("%s: DWC3_DSTS: 0x%x\n\r", __func__, reg); |
| link_state = DWC3_DSTS_USBLNKST(reg); |
| |
| switch (link_state) { |
| case DWC3_LINK_STATE_RESET: |
| case DWC3_LINK_STATE_RX_DET: /* in HS, means Early Suspend */ |
| case DWC3_LINK_STATE_U3: /* in HS, means SUSPEND */ |
| case DWC3_LINK_STATE_RESUME: |
| break; |
| default: |
| return -1; |
| } |
| |
| ret = DWC3_SET_LINK_STATE(DWC3_LINK_STATE_RECOV); |
| if (ret < 0) { |
| bbu_printf("failed to put link in Recovery\n\r"); |
| return ret; |
| } |
| |
| #ifdef USB_ENABLE_DEBUG |
| usbcmd_setlink_count++; |
| #endif |
| |
| /* poll until Link State changes to ON */ |
| retries = 10000; |
| while (retries--) { |
| reg = DWC3_REG_READ(DWC3_DSTS); |
| |
| /* in HS, means ON */ |
| if (DWC3_DSTS_USBLNKST(reg) == DWC3_LINK_STATE_U0) |
| break; |
| Delay(5); |
| } |
| |
| if (DWC3_DSTS_USBLNKST(reg) != DWC3_LINK_STATE_U0) { |
| #ifdef USB_ENABLE_DEBUG |
| usbcmd_setlink_fail_count++; |
| #endif |
| bbu_printf("failed to send remote wakeup\n\r"); |
| return -1; |
| } |
| |
| bbu_printf("%s: DWC3_DSTS: 0x%x\n\r", __func__, reg); |
| return 0; |
| } |
| |
| int DWC3_SEND_EP_CMD(P_DC_Properties_T pDCProps, UINT cmd, |
| struct dwc3_gadget_ep_cmd_params *params, UINT ep_num) |
| { |
| UINT timeout = 100000; |
| UINT reg; |
| UINT link_state; |
| int cmd_status = 0; |
| int ret = 0; |
| int needs_wakeup; |
| #ifdef USB_ENABLE_DEBUG |
| struct dwc3_trb * ptrb; |
| #endif |
| |
| reg = DWC3_REG_READ(DWC3_DSTS); |
| link_state = DWC3_DSTS_USBLNKST(reg); |
| bbu_printf("%s: DWC3_DSTS: 0x%x\n\r", __func__, reg); |
| |
| if (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_STARTTRANSFER) { |
| needs_wakeup = (link_state == DWC3_LINK_STATE_U1 || |
| link_state == DWC3_LINK_STATE_U2 || |
| link_state == DWC3_LINK_STATE_U3); |
| |
| if (needs_wakeup) { |
| bbu_printf("%s:do wakeup\n\r", __func__); |
| DO_DWC3_GADGET_WAKEUP(); |
| } |
| } |
| |
| #ifdef USB_ENABLE_DEBUG |
| usbcmd_logging_array[usbcmd_logging_ptr%NR_LOGGING_ARRAY].param0 = params->param0; |
| usbcmd_logging_array[usbcmd_logging_ptr%NR_LOGGING_ARRAY].param1 = params->param1; |
| usbcmd_logging_array[usbcmd_logging_ptr%NR_LOGGING_ARRAY].param2 = params->param2; |
| usbcmd_logging_array[usbcmd_logging_ptr%NR_LOGGING_ARRAY].cmd |
| = ((pDCProps->link_state << 16) | ((reg & DWC3_DSTS_CONNECTSPD) << 12) |
| | (link_state << 8) | (ep_num << 4) | cmd); |
| ptrb = params->param1; |
| if ((cmd == DWC3_DEPCMD_STARTTRANSFER) && IS_PTRB_OK((UINT_T)ptrb)) { |
| usbcmd_logging_array[usbcmd_logging_ptr%NR_LOGGING_ARRAY].param0 = ptrb->size; |
| usbcmd_logging_array[usbcmd_logging_ptr%NR_LOGGING_ARRAY].param2 = ptrb->ctrl; |
| } |
| usbcmd_logging_ptr++; |
| usbcmd_cur_cmd_result = USB_CMD_FAIL1; |
| #endif |
| |
| DWC3_REG_WRITE((DWC3_DEP_BASE(ep_num)+DWC3_DEPCMDPAR0), params->param0); |
| DWC3_REG_WRITE((DWC3_DEP_BASE(ep_num)+DWC3_DEPCMDPAR1), params->param1); |
| DWC3_REG_WRITE((DWC3_DEP_BASE(ep_num)+DWC3_DEPCMDPAR2), params->param2); |
| cmd |= DWC3_DEPCMD_CMDACT; |
| __asm__ __volatile__("dsb" : : : "memory"); |
| |
| DWC3_REG_WRITE((DWC3_DEP_BASE(ep_num)+DWC3_DEPCMD), cmd); |
| |
| bbu_printf("%s:param0: 0x%x\n\r", __func__, params->param0); |
| bbu_printf("%s:param1: 0x%x\n\r", __func__, params->param1); |
| bbu_printf("%s:param2: 0x%x\n\r", __func__, params->param2); |
| bbu_printf("%s:cmd: 0x%x\n\r", __func__, cmd); |
| do { |
| reg = DWC3_REG_READ((DWC3_DEP_BASE(ep_num)+DWC3_DEPCMD)); |
| if (!(reg & DWC3_DEPCMD_CMDACT)) { |
| cmd_status = DWC3_DEPCMD_STATUS(reg); |
| |
| switch (cmd_status) { |
| case 0: |
| ret = 0; |
| break; |
| case DEPEVT_TRANSFER_NO_RESOURCE: |
| case DEPEVT_TRANSFER_BUS_EXPIRY: |
| default: |
| ret = -cmd_status; |
| break; |
| } |
| break; |
| } |
| } while (--timeout); |
| |
| if (timeout == 0) { |
| ret = -1; |
| bbu_printf("%s: cmd 0x%x timeout: %d, cmd_status: 0x%x\n\r", __func__, cmd, timeout, cmd_status); |
| } |
| |
| #ifdef USB_ENABLE_DEBUG |
| usbcmd_cur_cmd_result = ret; |
| #endif |
| if (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_STARTTRANSFER) { |
| reg = DWC3_REG_READ((DWC3_DEP_BASE(ep_num)+DWC3_DEPCMD)); |
| pDCProps->ep0to3_resource_idx[ep_num] = DWC3_DEPCMD_GET_RSC_IDX(reg); |
| } |
| |
| return ret; |
| } |
| |
| static void DWC3_STOP_ACTIVE_XFER(P_DC_Properties_T pDCProps, UINT ep_num, UCHAR resource_idx) |
| { |
| struct dwc3_gadget_ep_cmd_params params; |
| UINT cmd; |
| |
| if (resource_idx == 0) |
| return; |
| |
| cmd = DWC3_DEPCMD_ENDTRANSFER; |
| cmd |= DWC3_DEPCMD_HIPRI_FORCERM; |
| cmd |= DWC3_DEPCMD_PARAM(resource_idx); |
| memset(¶ms, 0, sizeof(params)); |
| DWC3_SEND_EP_CMD(pDCProps, cmd, ¶ms, ep_num); |
| Delay(100); |
| pDCProps->ep0to3_resource_idx[ep_num] = 0x0; |
| } |
| |
| void DWC3_EP0_OUT_START(P_DC_Properties_T pDCProps) |
| { |
| bbu_printf("%s: buffer: 0x%x\n\r", __func__, pDCProps->ep0_out_buffer); |
| USB2D_Endpoint0Transmit(pDCProps, USB_ENDPOINT_0, USB_OUT, |
| pDCProps->ep0_out_buffer, 0x8, DWC3_TRBCTL_CONTROL_SETUP); |
| } |
| |
| void DWC3_EP0_STALL_AND_RESTART(P_DC_Properties_T pDCProps) |
| { |
| struct dwc3_gadget_ep_cmd_params params; |
| int ret; |
| |
| memset(¶ms, 0x00, sizeof(params)); |
| ret = DWC3_SEND_EP_CMD(pDCProps, DWC3_DEPCMD_SETSTALL, ¶ms, 0); |
| if (ret) { |
| bbu_printf("failed to set STALL on ep0\n\r"); |
| return; |
| } |
| |
| pDCProps->ep0state = EP0_SETUP_PHASE; |
| DWC3_EP0_OUT_START(pDCProps); |
| } |
| |
| static void DWC3_EP0_HANDLE_SETUP(P_DC_Properties_T pDCProps, |
| struct dwc3_event_depevt *event) |
| { |
| UCHAR epnum; |
| P_dQH_T pQH; |
| XLLP_USB_SETUP_DATA_T *usb_ctrl_p; |
| |
| epnum = event->endpoint_number; |
| if (epnum > 1) |
| return; |
| |
| pQH = &pDCProps->pdQHHead[epnum]; |
| |
| ReleasetrbChain((struct dwc3_trb *)(pQH->initial_trb)); |
| pQH->initial_trb = NULL; |
| |
| usb_ctrl_p = pDCProps->ep0_out_buffer; |
| if (usb_ctrl_p->wLength == 0) { |
| pDCProps->ctrl_direction = USB_IN; |
| pDCProps->ctrl_stages = 2; |
| pDCProps->ep0_next_event = DWC3_EP0_NRDY_STATUS; |
| pDCProps->ep0_expect_in = 0x0; |
| } else { |
| pDCProps->ctrl_direction = !(usb_ctrl_p->bmRequestType & 0x80); |
| pDCProps->ctrl_stages = 3; |
| pDCProps->ep0_next_event = DWC3_EP0_NRDY_DATA; |
| pDCProps->ep0_expect_in = !(pDCProps->ctrl_direction); |
| } |
| |
| USB2D_EnumerationHandler(pDCProps, (XLLP_USB_SETUP_DATA_T *)pDCProps->ep0_out_buffer); |
| } |
| |
| static void DWC3_EP0_COMPLETE_DATA(P_DC_Properties_T pDCProps, |
| struct dwc3_event_depevt *event) |
| { |
| |
| UCHAR epnum; |
| UINT count; |
| struct dwc3_trb * ptrb; |
| P_dQH_T pQH; |
| |
| epnum = event->endpoint_number; |
| if (epnum > 1) |
| return; |
| |
| pDCProps->ep0_next_event = DWC3_EP0_NRDY_STATUS; |
| |
| pQH = &pDCProps->pdQHHead[epnum]; |
| ptrb = pQH->initial_trb; |
| //remaining bytes |
| count = ptrb->size & DWC3_TRB_SIZE_MASK; |
| |
| bbu_printf("%s: ptrb->ctrl: 0x%x, event->status 0x%x\n\r", |
| __func__, ptrb->ctrl, event->status); |
| |
| //update size counter for the last packet being a short packet |
| pQH->tot_size -= count; |
| |
| ReleasetrbChain((struct dwc3_trb *)(pQH->initial_trb)); |
| pQH->initial_trb = NULL; |
| //OUT EP |
| if ((epnum & 0x1) == 0) { |
| memcpy(pQH->buffer, pDCProps->ep0_out_buffer, pQH->tot_size); |
| //TODO: invoke callback to handle buffer |
| } |
| } |
| |
| static void DWC3_EP0_COMPLETE_STATUS(P_DC_Properties_T pDCProps, |
| struct dwc3_event_depevt *event) |
| { |
| UCHAR epnum; |
| P_dQH_T pQH; |
| |
| epnum = event->endpoint_number; |
| if (epnum > 1) |
| return; |
| |
| pQH = &pDCProps->pdQHHead[epnum]; |
| |
| pDCProps->ep0state = EP0_SETUP_PHASE; |
| ReleasetrbChain((struct dwc3_trb *)(pQH->initial_trb)); |
| pQH->initial_trb = NULL; |
| |
| bbu_printf("%s\n\r", __func__); |
| DWC3_EP0_OUT_START(pDCProps); |
| } |
| |
| |
| static void DWC3_EP0_XFERNOTREADY(P_DC_Properties_T pDCProps, |
| struct dwc3_event_depevt *event) |
| { |
| UINT ep_num; |
| |
| if (event->endpoint_number > 1) { |
| bbu_printf("%s ep_num: %d\n\r", __func__, event->endpoint_number); |
| return; |
| } |
| |
| ep_num = !!event->endpoint_number; |
| |
| switch (event->status) { |
| case DEPEVT_STATUS_CONTROL_DATA: |
| //do noting |
| bbu_printf("DEPEVT_STATUS_CONTROL_DATA nothing\n\r"); |
| if (pDCProps->ep0_expect_in != event->endpoint_number) { |
| usbep0_data_nrdy_count++; |
| } |
| break; |
| |
| case DEPEVT_STATUS_CONTROL_STATUS: |
| bbu_printf("DEPEVT_STATUS_CONTROL_STATUS\n\r"); |
| |
| if (pDCProps->ep0_next_event != DWC3_EP0_NRDY_STATUS) { |
| bbu_printf("DEPEVT_STATUS_CONTROL_STATUS nothing\n\r"); |
| #ifdef USB_ENABLE_DEBUG |
| usbep0_nrdy_fail_count++; |
| #endif |
| return; |
| } |
| |
| //STATUS BASED ON STAGE/DIRECTION |
| if (pDCProps->ctrl_stages == 2) |
| USB2D_Endpoint0Transmit(pDCProps, USB_ENDPOINT_0, |
| /*pDCProps->ctrl_direction*/ep_num, |
| pDCProps->BufferSpace2, 0, DWC3_TRBCTL_CONTROL_STATUS2); |
| else |
| USB2D_Endpoint0Transmit(pDCProps, USB_ENDPOINT_0, |
| /*pDCProps->ctrl_direction*/ep_num, |
| pDCProps->BufferSpace2, 0, DWC3_TRBCTL_CONTROL_STATUS3); |
| #ifdef USB_ENABLE_DEBUG |
| if (pDCProps->ctrl_stages == 2) |
| usbep0_nrdy_table[usbep0_nrdy_ptr%NR_LOGGING_ARRAY] = DWC3_TRBCTL_CONTROL_STATUS2 | ep_num; |
| else |
| usbep0_nrdy_table[usbep0_nrdy_ptr%NR_LOGGING_ARRAY] = DWC3_TRBCTL_CONTROL_STATUS3 | ep_num; |
| usbep0_nrdy_ptr++; |
| #endif |
| break; |
| default: |
| break; |
| } |
| } |
| |
| static void DWC3_EP0_XFER_COMPLETE(P_DC_Properties_T pDCProps, |
| struct dwc3_event_depevt *event) |
| { |
| UCHAR epnum; |
| struct dwc3_trb * ptrb; |
| |
| epnum = event->endpoint_number; |
| if (epnum > 1) |
| return; |
| pDCProps->ep0to3_resource_idx[epnum] = 0x0; |
| #ifdef USB_ENABLE_DEBUG |
| ptrb = pDCProps->pdQHHead[(epnum & 0x1)].initial_trb; |
| if (IS_PTRB_OK((UINT_T)ptrb)) { |
| usbep0_trb_table[usbep0_trb_ptr%NR_LOGGING_ARRAY].size = ptrb->size; |
| usbep0_trb_table[usbep0_trb_ptr%NR_LOGGING_ARRAY].ctrl= (ptrb->ctrl | (epnum << 16)); |
| } else { |
| usbep0_trb_table[usbep0_trb_ptr%NR_LOGGING_ARRAY].size = 0; |
| usbep0_trb_table[usbep0_trb_ptr%NR_LOGGING_ARRAY].ctrl= (epnum << 16); |
| } |
| usbep0_trb_ptr++; |
| #endif |
| |
| switch (pDCProps->ep0state) { |
| case EP0_SETUP_PHASE: |
| bbu_printf("%s: setup\n\r", __func__); |
| DWC3_EP0_HANDLE_SETUP(pDCProps, event); |
| break; |
| |
| case EP0_DATA_PHASE: |
| bbu_printf("%s: data\n\r", __func__); |
| DWC3_EP0_COMPLETE_DATA(pDCProps, event); |
| #ifndef DWC3_ENABLE_XFERNOTREADY |
| //STATUS BASED ON STAGE/DIRECTION |
| //2stage xfer status is handled in out pkt |
| if (pDCProps->ctrl_stages == 2) |
| USB2D_Endpoint0Transmit(pDCProps, USB_ENDPOINT_0, pDCProps->ctrl_direction, |
| pDCProps->BufferSpace2, 0, DWC3_TRBCTL_CONTROL_STATUS2); |
| else |
| USB2D_Endpoint0Transmit(pDCProps, USB_ENDPOINT_0, pDCProps->ctrl_direction, |
| pDCProps->BufferSpace2, 0, DWC3_TRBCTL_CONTROL_STATUS3); |
| #endif |
| break; |
| |
| case EP0_STATUS_PHASE: |
| bbu_printf("%s: status\n\r", __func__); |
| DWC3_EP0_COMPLETE_STATUS(pDCProps, event); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| void DWC3_EP0_INT(P_DC_Properties_T pDCProps, struct dwc3_event_depevt *event) |
| { |
| switch (event->endpoint_event) { |
| case DWC3_DEPEVT_XFERCOMPLETE: |
| bbu_printf("DWC3_DEPEVT_XFERCOMPLETE\n\r"); |
| DWC3_EP0_XFER_COMPLETE(pDCProps, event); |
| break; |
| |
| case DWC3_DEPEVT_XFERNOTREADY: |
| bbu_printf("DWC3_DEPEVT_XFERNOTREADY ep%d\n\r", event->endpoint_number); |
| DWC3_EP0_XFERNOTREADY(pDCProps, event); |
| break; |
| |
| case DWC3_DEPEVT_XFERINPROGRESS: |
| case DWC3_DEPEVT_RXTXFIFOEVT: |
| case DWC3_DEPEVT_STREAMEVT: |
| break; |
| case DWC3_DEPEVT_EPCMDCMPLT: |
| break; |
| } |
| } |
| |
| int DWC3_GET_CONN_SPEED(void) |
| { |
| UINT reg; |
| UCHAR speed; |
| |
| reg = DWC3_REG_READ(DWC3_DSTS); |
| speed = reg & DWC3_DSTS_CONNECTSPD; |
| switch (speed) { |
| case DWC3_DSTS_HIGHSPEED: |
| return USB_MODE_HS; |
| case DWC3_DSTS_FULLSPEED: |
| return USB_MODE_FS; |
| /*case DWC3_DSTS_SUPERSPEED: |
| return USB_MODE_SS; |
| case DWC3_DSTS_SUPERSPEED_PLUS: |
| return USB_MODE_SS_PLUS; |
| case DWC3_DSTS_LOWSPEED: |
| return USB_MODE_LS;*/ |
| default: |
| return USB_MODE_HS; |
| } |
| } |
| |
| static int DWC3_EP_SET_XFER_RESOURCE(P_DC_Properties_T pDCProps, UINT ep_num) |
| { |
| struct dwc3_gadget_ep_cmd_params params; |
| UINT cmd; |
| int ret; |
| |
| //prepare cmd parameters |
| params.param1 = 0x0; |
| params.param2 = 0x0; |
| params.param0 = DWC3_DEPXFERCFG_NUM_XFER_RES(1); |
| cmd = DWC3_DEPCMD_SETTRANSFRESOURCE; |
| |
| ret = DWC3_SEND_EP_CMD(pDCProps, cmd, ¶ms, ep_num); |
| return ret; |
| } |
| |
| static int DWC3_EP_START_CFG(P_DC_Properties_T pDCProps, UINT ep_num) |
| { |
| struct dwc3_gadget_ep_cmd_params params; |
| UINT cmd; |
| int ret; |
| |
| //prepare cmd parameters |
| params.param0 = 0x0; |
| params.param1 = 0x0; |
| params.param2 = 0x0; |
| cmd = DWC3_DEPCMD_DEPSTARTCFG; |
| |
| ret = DWC3_SEND_EP_CMD(pDCProps, cmd, ¶ms, ep_num); |
| return ret; |
| } |
| |
| static int DWC3_EP_SET_CFG(P_DC_Properties_T pDCProps, UINT ep_num, UINT modify) |
| { |
| struct dwc3_gadget_ep_cmd_params params; |
| UINT cmd; |
| int ret, usb_speed_mode; |
| |
| usb_speed_mode = DWC3_GET_CONN_SPEED(); |
| //prepare cmd parameters |
| params.param0 = 0x0; |
| params.param1 = 0x0; |
| params.param2 = 0x0; |
| |
| if (ep_num == 0 || ep_num == 1) |
| { |
| //CONTROL EP AND MAXPACKET SIZE |
| params.param0 = DWC3_DEPCFG_EP_TYPE(USB_CNTRL) |
| | DWC3_DEPCFG_MAX_PACKET_SIZE(USB_MPS_CNTRL_64); |
| } else { |
| if(usb_speed_mode == USB_MODE_FS) |
| //CONTROL EP AND MAXPACKET SIZE |
| params.param0 = DWC3_DEPCFG_EP_TYPE(USB_BULK) |
| | DWC3_DEPCFG_MAX_PACKET_SIZE(USB_MPS_BULK_64); |
| else |
| params.param0 = DWC3_DEPCFG_EP_TYPE(USB_BULK) |
| | DWC3_DEPCFG_MAX_PACKET_SIZE(USB_MPS_BULK_512); |
| } |
| |
| if (modify) { |
| params.param0 |= DWC3_DEPCFG_ACTION_MODIFY; |
| } else { |
| params.param0 |= DWC3_DEPCFG_ACTION_INIT; |
| } |
| params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN; |
| |
| #ifdef DWC3_ENABLE_XFERNOTREADY |
| if (ep_num <= 1) |
| params.param1 |= DWC3_DEPCFG_XFER_NOT_READY_EN; |
| #endif |
| |
| /* |
| * We are doing 1:1 mapping for endpoints, meaning |
| * Physical Endpoints 2 maps to Logical Endpoint 2 and |
| * so on. We consider the direction bit as part of the physical |
| * endpoint number. So USB endpoint 0x81 is 0x03. |
| */ |
| params.param1 |= DWC3_DEPCFG_EP_NUMBER(ep_num); |
| |
| /* |
| * We must use the lower 16 TX FIFOs even though |
| * HW might have more |
| */ |
| if (ep_num & 0x1) |
| params.param0 |= DWC3_DEPCFG_FIFO_NUMBER((ep_num >> 1)); |
| |
| cmd = DWC3_DEPCMD_SETEPCONFIG; |
| ret = DWC3_SEND_EP_CMD(pDCProps, cmd, ¶ms, ep_num); |
| return ret; |
| } |
| |
| UINT_T USB2D_Initialize(UINT base_address, UINT int_number, int param) |
| { |
| P_DC_Properties_T pDCProps; |
| UINT_T regval; |
| |
| //Try and get a new USB 2 'Object' |
| pDCProps = Allocate_USB2_Device(int_number); |
| //Check for error |
| if(pDCProps == NULL) { |
| bbu_printf("%s:line:%d\n\r", __func__, __LINE__); |
| return NotFoundError; //mdb make new error code |
| } |
| |
| //reset and restore the controller |
| DWC3_Controller_Setup(pDCProps, param); |
| |
| //setup EP 0 |
| USB2D_Endpoint_Setup(pDCProps, USB_ENDPOINT_0, USB_OUT, USB_CNTRL); |
| USB2D_Endpoint_Setup(pDCProps, USB_ENDPOINT_0, USB_IN, USB_CNTRL); |
| |
| pDCProps->link_state = DWC3_LINK_STATE_SS_DIS; |
| |
| /* begin to receive SETUP packets */ |
| pDCProps->ep0state = EP0_SETUP_PHASE; |
| DWC3_EP0_OUT_START(pDCProps); |
| __asm__ __volatile__("dsb" : : : "memory"); |
| |
| //ENABLE USB RUN BIT |
| bbu_printf("%s start usb now\n\r", __func__); |
| regval = DWC3_REG_READ(DWC3_DCTL); |
| regval |= DWC3_DCTL_RUN_STOP; |
| DWC3_REG_WRITE(DWC3_DCTL, regval); |
| bbu_printf("%s start usb done\n\r", __func__); |
| return NoError; |
| } |
| |
| void USB2D_Shutdown(UINT intnum) |
| { |
| UINT32 regval, count; |
| P_DC_Properties_T pDCProps = Get_DC_Properties(intnum); |
| |
| if (pDCProps == NULL) |
| return; |
| |
| //First wait a short time for the last transfers to complete |
| Delay((30 * 1000)); |
| |
| DWC3_STOP_ACTIVE_XFER(pDCProps, 3, pDCProps->ep0to3_resource_idx[3]); |
| DWC3_STOP_ACTIVE_XFER(pDCProps, 2, pDCProps->ep0to3_resource_idx[2]); |
| DWC3_STOP_ACTIVE_XFER(pDCProps, 1, pDCProps->ep0to3_resource_idx[1]); |
| |
| //Disable all EVENTS |
| DWC3_REG_WRITE(DWC3_DEVTEN, 0x0); |
| __asm__ __volatile__("dsb" : : : "memory"); |
| |
| //Clear any pending events |
| count = DWC3_REG_READ(DWC3_GEVNTCOUNT(0)); |
| count &= 0xFFFF; |
| DWC3_REG_WRITE(DWC3_GEVNTCOUNT(0), count); |
| __asm__ __volatile__("dsb" : : : "memory"); |
| |
| //lastly, shut off the controller |
| regval = DWC3_REG_READ(DWC3_DCTL); |
| regval &= ~DWC3_DCTL_RUN_STOP; |
| DWC3_REG_WRITE(DWC3_DCTL, regval); |
| Delay(50); |
| } |
| |
| static void DWC3_DISCONNECT_INT(P_DC_Properties_T pDCProps) |
| { |
| UINT reg; |
| |
| bbu_printf("%s\n\r", __func__); |
| reg = DWC3_REG_READ(DWC3_DCTL); |
| reg &= ~DWC3_DCTL_INITU1ENA; |
| reg &= ~DWC3_DCTL_INITU2ENA; |
| DWC3_REG_WRITE(DWC3_DCTL, reg); |
| pDCProps->dev_state = USB_STATE_NOTATTACHED; |
| } |
| |
| static void DWC3_RESET_INT(P_DC_Properties_T pDCProps) |
| { |
| UINT reg; |
| |
| bbu_printf("%s\n\r", __func__); |
| reg = DWC3_REG_READ(DWC3_DCTL); |
| reg &= ~DWC3_DCTL_TSTCTRL_MASK; |
| DWC3_REG_WRITE(DWC3_DCTL, reg); |
| |
| //stop any pending transfers |
| DWC3_STOP_ACTIVE_XFER(pDCProps, 3, pDCProps->ep0to3_resource_idx[3]); |
| DWC3_STOP_ACTIVE_XFER(pDCProps, 2, pDCProps->ep0to3_resource_idx[2]); |
| |
| /* Reset device address to zero */ |
| reg = DWC3_REG_READ(DWC3_DCFG); |
| reg &= ~(DWC3_DCFG_DEVADDR_MASK); |
| DWC3_REG_WRITE(DWC3_DCFG, reg); |
| } |
| |
| static void DWC3_CONNDONE_INT(P_DC_Properties_T pDCProps) |
| { |
| UINT reg; |
| UCHAR speed; |
| INT usb_real_speed_mode; |
| |
| reg = DWC3_REG_READ(DWC3_DSTS); |
| speed = reg & DWC3_DSTS_CONNECTSPD; |
| bbu_printf("%s:DWC3_DSTS = 0x%x\n\r", __func__, reg); |
| |
| usb_real_speed_mode = DWC3_GET_CONN_SPEED(); |
| /* |
| * real speed != pre-set speed |
| * need to care about second time link |
| */ |
| if ((get_usb_speed_mode() == USB_MODE_HS) |
| && (usb_real_speed_mode != get_usb_speed_mode())) { |
| //update EP config |
| //update USB DESC |
| UpdateUSBDeviceConfigDesc(usb_real_speed_mode); |
| DWC3_EP_SET_CFG(pDCProps, 0, 1); |
| DWC3_EP_SET_CFG(pDCProps, 1, 1); |
| } |
| |
| reg = DWC3_REG_READ(DWC3_DCFG); |
| reg |= DWC3_DCFG_LPM_CAP; |
| DWC3_REG_WRITE(DWC3_DCFG, reg); |
| |
| reg = DWC3_REG_READ(DWC3_DCTL); |
| reg &= ~(DWC3_DCTL_HIRD_THRES_MASK | DWC3_DCTL_L1_HIBER_EN); |
| DWC3_REG_WRITE(DWC3_DCTL, reg); |
| } |
| |
| static void DWC3_WAKEUP_INT(P_DC_Properties_T pDCProps) |
| { |
| bbu_printf("%s\n\r", __func__); |
| } |
| |
| static void DWC3_LINKSTS_CHANGE_INT(P_DC_Properties_T pDCProps, |
| unsigned int evtinfo) |
| { |
| bbu_printf("%s\n\r", __func__); |
| pDCProps->link_state = evtinfo & DWC3_LINK_STATE_MASK; |
| } |
| |
| static void DWC3_SUSPEND_INT(P_DC_Properties_T pDCProps, |
| unsigned int evtinfo) |
| { |
| bbu_printf("%s\n\r", __func__); |
| pDCProps->link_state = evtinfo & DWC3_LINK_STATE_MASK; |
| } |
| |
| static void DWC3_DEV_INT(P_DC_Properties_T pDCProps, |
| struct dwc3_event_devt *event) |
| { |
| bbu_printf("%s\n\r", __func__); |
| switch (event->type) { |
| case DWC3_DEVICE_EVENT_DISCONNECT: |
| DWC3_DISCONNECT_INT(pDCProps); |
| break; |
| case DWC3_DEVICE_EVENT_RESET: |
| DWC3_RESET_INT(pDCProps); |
| break; |
| case DWC3_DEVICE_EVENT_CONNECT_DONE: |
| DWC3_CONNDONE_INT(pDCProps); |
| break; |
| case DWC3_DEVICE_EVENT_WAKEUP: |
| DWC3_WAKEUP_INT(pDCProps); |
| break; |
| case DWC3_DEVICE_EVENT_HIBER_REQ: |
| //do nothing |
| break; |
| case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE: |
| DWC3_LINKSTS_CHANGE_INT(pDCProps, event->event_info); |
| break; |
| case DWC3_DEVICE_EVENT_EOPF: |
| if (pDCProps->dev_state >= USB_STATE_CONFIGURED) |
| DWC3_SUSPEND_INT(pDCProps, event->event_info); |
| break; |
| case DWC3_DEVICE_EVENT_SOF: |
| case DWC3_DEVICE_EVENT_ERRATIC_ERROR: |
| case DWC3_DEVICE_EVENT_CMD_CMPL: |
| case DWC3_DEVICE_EVENT_OVERFLOW: |
| break; |
| default: |
| break; |
| } |
| } |
| |
| //endpoint complete interrupt handler - means a trb finish (IOC bit) |
| void DWC3_Complete_Int(P_DC_Properties_T pDCProps, UINT ep_num, struct dwc3_event_depevt *event) |
| { |
| UINT count, s_pkt; |
| struct dwc3_trb * ptrb; |
| P_dQH_T pQH; |
| |
| pDCProps->ep0to3_resource_idx[ep_num] = 0x0; |
| pQH = &pDCProps->pdQHHead[ep_num]; |
| ptrb = pQH->initial_trb; |
| //remaining bytes |
| count = ptrb->size & DWC3_TRB_SIZE_MASK; |
| |
| #ifdef USB_ENABLE_DEBUG |
| if (IS_PTRB_OK((UINT_T)ptrb)) { |
| usbep1_trb_table[usbep1_trb_ptr%NR_LOGGING_ARRAY].size = ptrb->size; |
| usbep1_trb_table[usbep1_trb_ptr%NR_LOGGING_ARRAY].ctrl= (ptrb->ctrl | (ep_num << 16)); |
| } else { |
| usbep1_trb_table[usbep1_trb_ptr%NR_LOGGING_ARRAY].size = 0; |
| usbep1_trb_table[usbep1_trb_ptr%NR_LOGGING_ARRAY].ctrl= (ep_num << 16); |
| } |
| usbep1_trb_ptr++; |
| #endif |
| |
| bbu_printf("%s: --ptrb->ctrl: 0x%x, event->status 0x%x ep %d, cn: %d\n\r", |
| __func__, ptrb->ctrl, event->status, ep_num, count); |
| |
| //OUT EP |
| if ((ep_num & 0x1) == 0) { |
| if (count && (event->status & DEPEVT_STATUS_SHORT)) |
| s_pkt = 1; |
| } |
| |
| if (s_pkt) |
| goto giveback; |
| |
| if ((event->status & DEPEVT_STATUS_LST) && |
| (ptrb->ctrl & (DWC3_TRB_CTRL_LST | |
| DWC3_TRB_CTRL_HWO))) |
| goto giveback; |
| |
| if ((event->status & DEPEVT_STATUS_IOC) && |
| (ptrb->ctrl & DWC3_TRB_CTRL_IOC)) |
| goto giveback; |
| |
| //TODO: |
| return; |
| |
| giveback: |
| #ifdef USB_ENABLE_DEBUG |
| usbep1_data_count++; |
| #endif |
| ReleasetrbChain((struct dwc3_trb *)(pQH->initial_trb)); |
| pQH->initial_trb = NULL; |
| //update size counter for the last packet being a short packet |
| pQH->tot_size -= count; |
| bbu_printf("%s: tot_size: %d\n\r", __func__, pQH->tot_size); |
| //Endpoint 2 RX serve call here |
| if(ep_num == 2) { |
| USB2D_PM_Call(pDCProps); |
| } |
| } |
| |
| static void DWC3_EP_INT(P_DC_Properties_T pDCProps, struct dwc3_event_depevt *event) |
| { |
| UCHAR epnum = event->endpoint_number; |
| |
| if (epnum == 0 || epnum == 1) { |
| DWC3_EP0_INT(pDCProps, event); |
| return; |
| } |
| |
| //TODO: only 4 eps in bootrom |
| if (epnum > 3) |
| return; |
| |
| switch (event->endpoint_event) { |
| case DWC3_DEPEVT_XFERCOMPLETE: |
| DWC3_Complete_Int(pDCProps, epnum, event); |
| break; |
| case DWC3_DEPEVT_XFERINPROGRESS: |
| break; |
| case DWC3_DEPEVT_XFERNOTREADY: |
| break; |
| case DWC3_DEPEVT_STREAMEVT: |
| case DWC3_DEPEVT_EPCMDCMPLT: |
| case DWC3_DEPEVT_RXTXFIFOEVT: |
| break; |
| default: |
| break; |
| } |
| } |
| |
| static void DWC3_PROCESS_EVENT_ENTRY(P_DC_Properties_T pDCProps, |
| union dwc3_event *event) |
| { |
| if (!event->type.is_devspec) |
| DWC3_EP_INT(pDCProps, &event->depevt); |
| else if (event->type.type == DWC3_EVENT_TYPE_DEV) |
| DWC3_DEV_INT(pDCProps, &event->devt); |
| } |
| |
| void USB2D_ISR(UINT intnum) |
| { |
| UINT count; |
| UINT reg; |
| int left; |
| union dwc3_event event; |
| |
| P_DC_Properties_T pDCProps = Get_DC_Properties(intnum); |
| |
| //bogus input. caller screwed up. return |
| if (pDCProps == NULL) { |
| bbu_printf("%s:line:%d pDCProps = NULL\n\r", __func__, __LINE__); |
| return; |
| } |
| count = DWC3_REG_READ(DWC3_GEVNTCOUNT(0)); |
| count &= DWC3_GEVNTCOUNT_MASK; |
| if (!count) { |
| return; |
| } |
| |
| /* Mask interrupt */ |
| reg = DWC3_REG_READ(DWC3_GEVNTSIZ(0)); |
| reg |= DWC3_GEVNTSIZ_INTMASK; |
| DWC3_REG_WRITE(DWC3_GEVNTSIZ(0), reg); |
| bbu_printf("%s event count: %d, pos: %d\n\r", __func__, count, pDCProps->evt_pos); |
| #if 0 |
| amount = MIN(count, pDCProps->evt_length - pDCProps->evt_pos); |
| memcpy(pDCProps->event_buff_cache + pDCProps->evt_pos, |
| pDCProps->event_buff + pDCProps->evt_pos, amount); |
| |
| if (amount < count) |
| memcpy(pDCProps->event_buff_cache, pDCProps->event_buff, count - amount); |
| |
| DWC3_REG_WRITE(DWC3_GEVNTCOUNT(0), count); |
| #endif |
| |
| left = (int)count; |
| while (left > 0) { |
| #if 0 |
| event.raw = *(UINT *) (pDCProps->event_buff_cache + pDCProps->evt_pos); |
| #endif |
| event.raw = *(UINT *) (pDCProps->event_buff + pDCProps->evt_pos); |
| bbu_printf("==>handle pos: %d event: 0x%x\n\r", pDCProps->evt_pos, event.raw); |
| DWC3_PROCESS_EVENT_ENTRY(pDCProps, &event); |
| |
| pDCProps->evt_pos = (pDCProps->evt_pos + 4) % pDCProps->evt_length; |
| left -= 4; |
| } |
| |
| #if 1 |
| //clear the event count |
| DWC3_REG_WRITE(DWC3_GEVNTCOUNT(0), count); |
| #endif |
| |
| bbu_printf("####last pos: %d\n\r", pDCProps->evt_pos); |
| /* Unmask interrupt */ |
| reg = DWC3_REG_READ(DWC3_GEVNTSIZ(0)); |
| reg &= ~DWC3_GEVNTSIZ_INTMASK; |
| DWC3_REG_WRITE(DWC3_GEVNTSIZ(0), reg); |
| } |
| |
| |
| void DWC3_Controller_Setup(P_DC_Properties_T pDCProps, int param) |
| { |
| UINT regval, chipid = 0x1901; |
| int usb_speed_mode; |
| UINT32 timeout; |
| |
| usb_speed_mode = get_usb_speed_mode(); |
| |
| //SOFT RESET CONTROLLER |
| regval = DWC3_REG_READ(DWC3_DCTL); |
| regval |= DWC3_DCTL_CSFTRST; |
| DWC3_REG_WRITE(DWC3_DCTL, regval); |
| //worst case: delay 200ms to align with code in linux |
| timeout = 50000; |
| do { |
| regval = DWC3_REG_READ(DWC3_DCTL); |
| if (!(regval & DWC3_DCTL_CSFTRST)) |
| break; |
| Delay(4); |
| } while (--timeout); |
| //make sure 3 phy clk delay before accessing phy |
| Delay(5); |
| bbu_printf("%s: timeout: 0x%x\n\r", __func__, timeout); |
| |
| //use mac2_clk as mac3_clk |
| regval = DWC3_REG_READ(DWC3_GUCTL1); |
| regval |= BIT(26); |
| //regval = 0x0104198a; |
| DWC3_REG_WRITE(DWC3_GUCTL1, regval); |
| |
| //TODO: 16bits phy on FPGA, 8bits PHY for silicon chip |
| //SET USB2PHYCFG0, use 8bits utim phy |
| //on FPGA the chipid[26:24] is force to 0x1 |
| //FPGA-1, ZEBU-2, silicon-0 |
| chipid = BU_REG_READ(CIU_REG_CHIPID); |
| if (((chipid >> 24) & 0x7) == 0x1) |
| regval = (0x40002407|(1<<3)); |
| else |
| regval = 0x40002407; |
| DWC3_REG_WRITE(DWC3_GUSB2PHYCFG(0), regval); |
| |
| //dwc3_core_setup_global_control |
| //BIT[13:12]-10: SET AS DEVICE MODE |
| regval = (1625<<19)|(0x2204); |
| //regval = 0x32c92004; |
| DWC3_REG_WRITE(DWC3_GCTL, regval); |
| |
| //Program DCFG |
| //bit0~2 0->HS 1->FS 4->SS |
| //regval = 0x480804;//(regval & (~(0x3<<0))) | (0<<0); //SS mode |
| regval = DWC3_REG_READ(DWC3_DCFG); |
| if (usb_speed_mode == USB_MODE_FS) |
| regval = 0x480801;//(regval & (~(0x3<<0))) | (0<<0); //FS mode |
| else if (usb_speed_mode == USB_MODE_HS) |
| regval = 0x480800;//(regval & (~(0x3<<0))) | (0<<0); //HS mode |
| else |
| regval = 0x480801;//(regval & (~(0x3<<0))) | (0<<0); //FS mode |
| DWC3_REG_WRITE(DWC3_DCFG, regval); |
| |
| //CONFIG EVENT BUFFERS |
| pDCProps->evt_pos = 0; |
| DWC3_REG_WRITE(DWC3_GEVNTADRLO(0), pDCProps->event_buff); |
| DWC3_REG_WRITE(DWC3_GEVNTADRHI(0), 0x0); |
| DWC3_REG_WRITE(DWC3_GEVNTSIZ(0), DWC3_GEVNTSIZ_SIZE(pDCProps->evt_length)); |
| DWC3_REG_WRITE(DWC3_GEVNTCOUNT(0), 0); |
| bbu_printf("event buffer: 0x%x\n\r", pDCProps->event_buff); |
| |
| //bbu_printf("event buffer cache: 0x%x\n\r", pDCProps->event_buff_cache); |
| //dwc3_gadget_enable_irq |
| //#define DWC3_DEVTEN_WKUPEVTEN BIT(4) |
| //#define DWC3_DEVTEN_ULSTCNGEN BIT(3) |
| //#define DWC3_DEVTEN_CONNECTDONEEN BIT(2) |
| //#define DWC3_DEVTEN_USBRSTEN BIT(1) |
| //#define DWC3_DEVTEN_DISCONNEVTEN BIT(0) |
| regval = DWC3_REG_READ(DWC3_DEVTEN); |
| regval |= 0x1f; |
| DWC3_REG_WRITE(DWC3_DEVTEN, regval); |
| |
| return; |
| } |
| |
| |
| //Configures an endpoint |
| void USB2D_Endpoint_Setup(P_DC_Properties_T pDCProps, XLLP_USB_ENDPOINT_ID_T ep_num, XLLP_USB_EP_DIR_T direction, XLLP_USB_EP_TYPE_T type) |
| { |
| UINT hw_ep_num, reg; |
| |
| hw_ep_num = ep_num*2+direction; |
| |
| //TODO: IS THERE ANY SEQUENCE ISSUE? |
| if (hw_ep_num == 0) { |
| DWC3_EP_START_CFG(pDCProps, hw_ep_num); |
| #if 1 |
| //only 4 eps are used in bootrom |
| DWC3_EP_SET_XFER_RESOURCE(pDCProps, 0); |
| DWC3_EP_SET_XFER_RESOURCE(pDCProps, 1); |
| DWC3_EP_SET_XFER_RESOURCE(pDCProps, 2); |
| DWC3_EP_SET_XFER_RESOURCE(pDCProps, 3); |
| #endif |
| } |
| |
| DWC3_EP_SET_CFG(pDCProps, hw_ep_num, 0); |
| |
| reg = DWC3_REG_READ(DWC3_DALEPENA); |
| reg |= DWC3_DALEPENA_EP(hw_ep_num); |
| DWC3_REG_WRITE(DWC3_DALEPENA, reg); |
| } |
| |
| void USB2D_PM_Call(P_DC_Properties_T pDCProps) |
| { |
| UINT bytes, buffer; |
| P_USBAPI_T pUsbApi; |
| |
| //grab info from the last RECEIVE operation |
| pUsbApi = GetUSBAPIhandle_InterruptNum(pDCProps->InterruptNum); |
| if (pUsbApi != NULL) |
| { |
| bytes = pDCProps->pdQHHead[USB_ENDPOINT_A*2].tot_size; |
| buffer = pDCProps->pdQHHead[USB_ENDPOINT_A*2].buffer; |
| |
| //call into Protocol Manager |
| PM_ISR(pUsbApi, bytes, (UINT*)buffer); |
| } |
| } |
| |
| void USB2D_SendWrapper(UINT *buffer, UINT size, void * pUSBAPI) |
| { |
| P_DC_Properties_T pDCProps; |
| |
| //get the correct structure |
| pDCProps = Get_DC_Properties(((P_USBAPI_T)pUSBAPI)->interruptNum); |
| if (pDCProps != NULL) |
| { |
| #ifdef USB_ENABLE_DEBUG |
| //usbsend_len_table[usbsend_len_ptr%NR_LOGGING_ARRAY] = size; |
| //usbsend_len_ptr++; |
| //usbsend_buff_table[usbsend_buff_ptr%NR_LOGGING_ARRAY] = buffer; |
| //usbsend_buff_ptr++; |
| #endif |
| //call the trasmit routine |
| USB2D_EndpointTransmit(pDCProps, USB_ENDPOINT_A, USB_IN, (UINT)(buffer), size); |
| } |
| return; |
| } |
| |
| void USB2D_RecieveWrapper(UINT *buffer, UINT size, void * pUSBAPI) |
| { |
| P_DC_Properties_T pDCProps; |
| |
| //get the correct structure |
| pDCProps = Get_DC_Properties(((P_USBAPI_T)pUSBAPI)->interruptNum); |
| if (pDCProps != NULL) |
| { |
| #ifdef USB_ENABLE_DEBUG |
| usbrecv_len_table[usbrecv_len_ptr%NR_LOGGING_ARRAY] = size; |
| usbrecv_len_ptr++; |
| //usbrecv_buff_table[usbrecv_buff_ptr%NR_LOGGING_ARRAY] = buffer; |
| //usbrecv_buff_ptr++; |
| #endif |
| //round up the size to mutiples of 512 for hs mode, N *64 for FS mode |
| //should be round up to mutiples of 1024 for usb3 |
| if (USB_MODE_FS == DWC3_GET_CONN_SPEED()) |
| size = (((size + 63) >> 6) << 6); |
| else |
| size = (((size + 511) >> 9) << 9); |
| //call the trasmit routine |
| #ifdef USB_ENABLE_DEBUG |
| //usbrecv_rdlen_table[usbrecv_rdlogging_ptr%NR_LOGGING_ARRAY] = size; |
| //usbrecv_rdlogging_ptr++; |
| #endif |
| USB2D_EndpointTransmit(pDCProps, USB_ENDPOINT_A, USB_OUT, (UINT)(buffer), size); |
| } |
| return; |
| } |
| |
| void USB2D_Endpoint0Transmit(P_DC_Properties_T pDCProps, XLLP_USB_ENDPOINT_ID_T ep_num, XLLP_USB_EP_DIR_T direction, UINT buffer, UINT size, UINT type) |
| { |
| UINT qh_index, cmd; |
| struct dwc3_trb * ptrb, *ptrb_first; |
| struct dwc3_gadget_ep_cmd_params params; |
| INT ret = 0; |
| |
| //calculate which Queue Head to service |
| qh_index = ep_num*2+direction; |
| |
| //grab an initial trb |
| ptrb_first = ptrb = get_trb_ep0(); |
| |
| //check for memory shortage |
| if(ptrb == NULL) { |
| bbu_printf("---%s: trb is NULL\n\r",__func__); |
| return; |
| } |
| #ifdef USB_ENABLE_DEBUG |
| //usbtrb0_table[usbtrb0_logging_ptr%NR_LOGGING_ARRAY] = ptrb; |
| //usbtrb0_logging_ptr++; |
| #endif |
| bbu_printf("====%s: trb: 0x%x buffer: 0x%x size: 0x%x\n\r",__func__, ptrb, buffer, size); |
| //save off info for software cleanup later on |
| pDCProps->pdQHHead[qh_index].initial_trb = (UINT)(ptrb_first); |
| pDCProps->pdQHHead[qh_index].buffer = (UINT)buffer; |
| pDCProps->pdQHHead[qh_index].tot_size = size; |
| |
| //parepare data trb |
| ptrb->size = size; |
| //USE the fixed buffer to OUT DATA |
| if ((type == DWC3_TRBCTL_CONTROL_DATA) && (USB_OUT == direction)) |
| ptrb->bpl = pDCProps->ep0_out_buffer; |
| else |
| ptrb->bpl = buffer; |
| ptrb->bph = 0x0; |
| ptrb->ctrl = type; |
| |
| //data phase |
| if (type == DWC3_TRBCTL_CONTROL_DATA) |
| pDCProps->ep0state = EP0_DATA_PHASE; |
| |
| if ((type == DWC3_TRBCTL_CONTROL_STATUS3) || |
| type == DWC3_TRBCTL_CONTROL_STATUS2) |
| pDCProps->ep0state = EP0_STATUS_PHASE; |
| |
| /* |
| * Enable ISP on OUT packet |
| */ |
| ptrb->ctrl |= DWC3_TRB_CTRL_ISP_IMI; |
| ptrb->ctrl |= DWC3_TRB_CTRL_IOC; |
| ptrb->ctrl |= DWC3_TRB_CTRL_HWO; |
| ptrb->ctrl |= DWC3_TRB_CTRL_LST; |
| |
| //store the last trb pointer to allow us to monitor completion |
| pDCProps->pdQHHead[qh_index].last_trb = (UINT)(ptrb); |
| |
| //prepare cmd parameters |
| params.param0 = 0x0; |
| params.param1 = ptrb; |
| params.param2 = 0x0; |
| cmd = DWC3_DEPCMD_STARTTRANSFER | |
| DWC3_DEPCMD_PARAM(0x0); |
| |
| ret = DWC3_SEND_EP_CMD(pDCProps, cmd, ¶ms, qh_index); |
| pDCProps->ep0_next_event = DWC3_EP0_COMPLETE; |
| } |
| |
| void USB2D_EndpointTransmit(P_DC_Properties_T pDCProps, XLLP_USB_ENDPOINT_ID_T ep_num, XLLP_USB_EP_DIR_T direction, UINT buffer, UINT size) |
| { |
| UINT qh_index, cmd; |
| struct dwc3_trb * ptrb, *ptrb_first; |
| struct dwc3_gadget_ep_cmd_params params; |
| INT ret = 0; |
| |
| //calculate which Queue Head to service |
| qh_index = ep_num*2+direction; |
| |
| //grab an initial trb |
| ptrb_first = ptrb = get_trb(); |
| |
| //check for memory shortage |
| if(ptrb == NULL) { |
| return; |
| } |
| #ifdef USB_ENABLE_DEBUG |
| //usbtrb_table[usbtrb_logging_ptr%NR_LOGGING_ARRAY] = ptrb; |
| //usbtrb_logging_ptr++; |
| #endif |
| bbu_printf("===%s: trb: 0x%x buffer: 0x%x size: 0x%x\n\r",__func__, ptrb, buffer, size); |
| //save off info for software cleanup later on |
| pDCProps->pdQHHead[qh_index].initial_trb = (UINT)(ptrb_first); |
| pDCProps->pdQHHead[qh_index].buffer = (UINT)buffer; |
| pDCProps->pdQHHead[qh_index].tot_size = size; |
| |
| //parepare data trb |
| ptrb->size = size; |
| ptrb->bpl = buffer; |
| |
| ptrb->bph = 0x0; |
| ptrb->ctrl = DWC3_TRBCTL_NORMAL; |
| /* |
| * Enable ISP on OUT packet |
| */ |
| if (USB_OUT == direction) { |
| ptrb->ctrl |= DWC3_TRB_CTRL_ISP_IMI; |
| } |
| ptrb->ctrl |= DWC3_TRB_CTRL_IOC; |
| ptrb->ctrl |= DWC3_TRB_CTRL_HWO; |
| ptrb->ctrl |= DWC3_TRB_CTRL_LST; |
| |
| //store the last trb pointer to allow us to monitor completion |
| pDCProps->pdQHHead[qh_index].last_trb = (UINT)(ptrb); |
| |
| //prepare cmd parameters |
| params.param0 = 0x0; |
| params.param1 = ptrb; |
| params.param2 = 0x0; |
| cmd = DWC3_DEPCMD_STARTTRANSFER | |
| DWC3_DEPCMD_PARAM(0x0); |
| |
| ret = DWC3_SEND_EP_CMD(pDCProps, cmd, ¶ms, qh_index); |
| } |
| |
| |