blob: a950bc802f404d0b56524245bb7819275752d50f [file] [log] [blame]
/******************************************************************************
*
* (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(&params, 0, sizeof(params));
DWC3_SEND_EP_CMD(pDCProps, cmd, &params, 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(&params, 0x00, sizeof(params));
ret = DWC3_SEND_EP_CMD(pDCProps, DWC3_DEPCMD_SETSTALL, &params, 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, &params, 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, &params, 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, &params, 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, &params, 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, &params, qh_index);
}