blob: fce81de6d8344381855098bf5e61a912f93ec2dc [file] [log] [blame]
#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 BULK_MPS USB_PACKET_512
#define BULK_MPS_FS USB_PACKET_64
enum usb_err_status {
USB_PROP_NOT_FOUND = (0x1 << 0),
USB_API_NOT_FOUND = (0x1 << 1),
USB_PROP_ALLOC_ERR = (0x1 << 2),
USB_EP0_RX_ALIGN_ERR = (0x1 << 3),
USB_EP0_TX_ALIGN_ERR = (0x1 << 4),
USB_EP1_RX_ALIGN_ERR = (0x1 << 5),
USB_EP1_TX_ALIGN_ERR = (0x1 << 6),
USB_EP0_XMIT_ERR = (0x1 << 7),
USB_RXFIFO_TOUT_ERR = (0x1 << 8),
USB_TXFIFO_TOUT_ERR = (0x1 << 9),
USB_AHBIDLE_TOUT_ERR = (0x1 << 10),
USB_CRST_TOUT_ERR = (0x1 << 11),
};
enum usb_tx_status {
DWC2_TX_STAGE1 = 1,
DWC2_TX_STAGE2,
DWC2_TX_STAGE3,
};
UINT_T dwc2_debug_tx1 = 0;
UINT_T dwc2_debug_tx2 = 0;
static P_DC_Properties_T g_pDCProps;
static void usb_flush_tx_fifo(unsigned num);
static void usb_report_err_status(UINT_T err_status)
{
if (g_pDCProps)
g_pDCProps->dwc_usb2_err_status |= err_status;
}
/* get usb speed mode */
UINT_T dwc2_get_usb_speed(void)
{
volatile UINT_T dsts;
dsts = dwc_read_reg32(USB_DSTS);
if (DSTS_ENUMSPD_HS == ((dsts & DSTS_ENUMSPD_MASK) >> DSTS_ENUMSPD_SHIFT))
return USB_MODE_HS;
else
return USB_MODE_FS;
}
/* receive setup and status */
static int usb_ep0_rx_setup(P_DC_Properties_T pDCProps, INT is_dma, UINT_T * buffer)
{
volatile depctl_data_t depctl;
volatile deptsiz0_data_t deptsiz;
depctl.d32 = dwc_read_reg32(USB_DOEP0CTL);
deptsiz.d32 = dwc_read_reg32(USB_DOEP0TSIZ);
/* xfersize = 8 bytes * 3 packet*/
deptsiz.b.xfersize = 24;
deptsiz.b.pktcnt = 1;
deptsiz.b.supcnt = 3;
dwc_write_reg32(USB_DOEP0TSIZ, deptsiz.d32);
/* buffer is not 4bytes aligned */
if (((UINT_T)buffer) & 0x3)
usb_report_err_status(USB_EP0_RX_ALIGN_ERR);
if (is_dma) {
dwc_write_reg32(USB_DOEPDMA(0), (UINT_T)buffer);
}
if (pDCProps) {
pDCProps->ep0_data_len_array[pDCProps->ep0_rcd_idx] = 24;
pDCProps->ep0_rcd_idx++;
pDCProps->ep0_rcd_idx = pDCProps->ep0_rcd_idx % EP0_DATA_RCD_NUM;
}
depctl.b.cnak = 1;
depctl.b.epena = 1;
dwc_write_reg32(USB_DOEP0CTL, depctl.d32);
return 0;
}
static void usb_ep0_tx(P_DC_Properties_T pDCProps, UINT_T transfer_size, UINT_T packet_count,
INT is_dma, UINT_T * buffer)
{
volatile depctl_data_t depctl;
volatile deptsiz0_data_t deptsiz;
usb_flush_tx_fifo(0);
/* buffer is not 4bytes alinged */
if (((UINT_T)buffer) & 0x3)
usb_report_err_status(USB_EP0_TX_ALIGN_ERR);
depctl.d32 = dwc_read_reg32(USB_DIEP0CTL);
deptsiz.d32 = dwc_read_reg32(USB_DIEP0TSIZ);
deptsiz.b.xfersize = transfer_size;
deptsiz.b.pktcnt = packet_count;
dwc_write_reg32(USB_DIEP0TSIZ, deptsiz.d32);
if (is_dma) {
dwc_write_reg32(USB_DIEPDMA(0), (UINT_T) buffer);
}
depctl.b.txfnum = 0;
depctl.b.cnak = 1;
depctl.b.epena = 1;
dwc_write_reg32(USB_DIEP0CTL, depctl.d32);
dwc2_debug_tx1 = DWC2_TX_STAGE1;
while (1) {
deptsiz.d32 = dwc_read_reg32(USB_DIEP0TSIZ);
if (deptsiz.d32 == 0)
break;
#if defined(PLATFORM_AQUILA_MODEL)
Delay(1);
#endif
dwc2_debug_tx1 = DWC2_TX_STAGE2;
}
dwc2_debug_tx1 = DWC2_TX_STAGE3;
}
static void usb_active_ep(XLLP_USB_ENDPOINT_ID_T ep_num, XLLP_USB_EP_DIR_T dir)
{
volatile depctl_data_t doepctl = {.d32 = 0 };
volatile depctl_data_t diepctl = {.d32 = 0 };
volatile doepmsk_data_t doepmsk = {.d32 = 0 };
if (dir == USB_OUT) {
doepctl.d32= dwc_read_reg32(USB_DOEPCTL(ep_num));
doepctl.b.usbactep = 0x1;
dwc_write_reg32(USB_DOEPCTL(ep_num), doepctl.d32);
doepmsk.d32= dwc_read_reg32(USB_DOEPMSK);
doepmsk.b.xfercompl = 1;
doepmsk.b.setup = 1;
doepmsk.b.babble = 1;
doepmsk.b.nak = 1;
dwc_write_reg32(USB_DOEPMSK, doepmsk.d32);
} else {
diepctl.d32= dwc_read_reg32(USB_DIEPCTL(ep_num));
diepctl.b.usbactep = 0x1;
dwc_write_reg32(USB_DIEPCTL(ep_num), diepctl.d32);
dwc_write_reg32(USB_DIEPMSK, 0xffffffff);
}
}
static void usb_config_ep(XLLP_USB_ENDPOINT_ID_T ep_num, USB_EP_TYPE_E ep_type,
XLLP_USB_EP_DIR_T dir, UINT_T mps)
{
volatile depctl_data_t doepctl = {.d32 = 0 };
volatile depctl_data_t diepctl = {.d32 = 0 };
if (dir == USB_OUT) {
doepctl.d32= dwc_read_reg32(USB_DOEPCTL(ep_num));
doepctl.b.eptype = ep_type;
doepctl.b.mps = mps;
doepctl.b.snak = 0x1;
dwc_write_reg32(USB_DOEPCTL(ep_num), doepctl.d32);
} else {
diepctl.d32= dwc_read_reg32(USB_DIEPCTL(ep_num));
diepctl.b.eptype = ep_type;
diepctl.b.mps = mps;
diepctl.b.snak = 0x1;
dwc_write_reg32(USB_DIEPCTL(ep_num), diepctl.d32);
}
}
static void usb_start_transfer(XLLP_USB_ENDPOINT_ID_T ep_num, XLLP_USB_EP_DIR_T dir,
UINT_T transfer_size, INT is_dma,
UINT_T * buffer)
{
volatile depctl_data_t depctl;
volatile deptsiz_data_t deptsiz;
UINT_T packet_count = 0;
if (dir == USB_OUT) {
depctl.d32 = dwc_read_reg32(USB_DOEPCTL(ep_num));
deptsiz.d32 = dwc_read_reg32(USB_DOEPTSIZ(ep_num));
deptsiz.b.xfersize = transfer_size;
packet_count =
(transfer_size + depctl.b.mps -
1) / depctl.b.mps;
deptsiz.b.pktcnt = packet_count;
dwc_write_reg32(USB_DOEPTSIZ(ep_num), deptsiz.d32);
if (is_dma) {
dwc_write_reg32(USB_DOEPDMA(ep_num), (UINT_T)buffer);
}
depctl.b.cnak = 1;
depctl.b.epena = 1;
dwc_write_reg32(USB_DOEPCTL(ep_num), depctl.d32);
} else {
depctl.d32 = dwc_read_reg32(USB_DIEPCTL(ep_num));
deptsiz.d32 = dwc_read_reg32(USB_DIEPTSIZ(ep_num));
deptsiz.b.xfersize = transfer_size;
packet_count =
(transfer_size + depctl.b.mps -
1) / depctl.b.mps;
deptsiz.b.pktcnt = packet_count;
dwc_write_reg32(USB_DIEPTSIZ(ep_num), deptsiz.d32);
if (is_dma) {
dwc_write_reg32(USB_DIEPDMA(ep_num), (UINT_T)buffer);
}
/*txfifo number*/
depctl.b.txfnum = ep_num;
depctl.b.cnak = 1;
depctl.b.epena = 1;
dwc_write_reg32(USB_DIEPCTL(ep_num), depctl.d32);
}
}
/**
* Set the EP STALL.
*
*/
void dwc_otg_ep_set_stall(XLLP_USB_ENDPOINT_ID_T ep_num, XLLP_USB_EP_DIR_T dir)
{
volatile depctl_data_t depctl;
UINT_T depctl_addr;
if (dir == USB_IN) {
depctl_addr = USB_DIEPCTL(ep_num);
depctl.d32 = dwc_read_reg32(depctl_addr);
/* set the disable and stall bits */
if (depctl.b.epena) {
depctl.b.epdis = 1;
}
depctl.b.stall = 1;
dwc_write_reg32(depctl_addr, depctl.d32);
} else {
depctl_addr = USB_DOEPCTL(ep_num);
depctl.d32 = dwc_read_reg32(depctl_addr);
/* set the stall bit */
depctl.b.stall = 1;
dwc_write_reg32(depctl_addr, depctl.d32);
}
if (g_pDCProps)
g_pDCProps->nr_ep0_stall++;
bbu_printf("DEPCTL=0x%x\n\r", dwc_read_reg32(depctl_addr));
return;
}
/**
* This funcion stalls EP0.
*/
static inline void ep0_do_stall(P_DC_Properties_T pDCProps)
{
bbu_printf("ep0 protocol STALL\n\r");
dwc_otg_ep_set_stall(0, USB_OUT);
dwc_otg_ep_set_stall(0, USB_IN);
usb_ep0_rx_setup(pDCProps, 1, (UINT_T *)pDCProps->ep0_out_buff_ptr);
}
#if 0
/**
* This function process the CLEAR_FEATURE Setup Commands.
*/
static void usb_clear_feature(UCHAR epno)
{
/**
* In fact the CLEAR_FEATURE Setup Commands don't do these things, but can avoid some issue.
*/
depctl_data_t doepctl = {.d32 = 0 };
depctl_data_t diepctl = {.d32 = 0 };
UCHAR ep_num = epno & 0x7F;
if (ep_num == 0) {
return;
}
if ((epno & 0x80) == 0) {
doepctl.d32 = dwc_read_reg32(USB_DOEPCTL(ep_num));
doepctl.b.setd0pid = 1;
dwc_write_reg32(USB_DOEPCTL(ep_num), doepctl.d32);
} else {
diepctl.d32 = dwc_read_reg32(USB_DIEPCTL(ep_num));
diepctl.b.setd0pid = 1;
dwc_write_reg32(USB_DIEPCTL(ep_num), diepctl.d32);
}
}
static void usb_set_feature(P_DC_Properties_T pDCProps)
{
dctl_data_t dctl ;
depctl_data_t doep0ctl;
usb_device_request_t *ctrl;
int testmode;
ctrl = (usb_device_request_t *)pDCProps->ep0_out_buff_ptr;
testmode = UGETW(ctrl->wIndex) >> 8;
usb_ep0_tx(0x0, 0x1, 0, NULL);
/* wait packet count is zero*/
while (dwc_read_reg32(USB_DIEP0TSIZ)) {};
/*clear ep out nak*/
doep0ctl.d32 = dwc_read_reg32(USB_DOEP0CTL);
doep0ctl.b.cnak= 1;
dwc_write_reg32(USB_DOEP0CTL, doep0ctl.d32);
switch (UT_GET_RECIPIENT(ctrl->bmRequestType)) {
case UT_DEVICE:
switch (UGETW(ctrl->wValue)) {
case 1:
break;
case 2:
dctl.d32 = dwc_read_reg32(USB_DCTL);
/* Setup the Test Mode test J, test K ...... */
switch (testmode) {
case TEST_J:
dctl.b.tstctl = testmode;
break;
case TEST_K:
dctl.b.tstctl = testmode;
break;
case TEST_SE0_NAK:
dctl.b.tstctl = testmode;
break;
case TEST_PACKET:
dctl.b.tstctl = testmode;
break;
case TEST_FORCE_EN:
dctl.b.tstctl = testmode;
break;
}
dwc_write_reg32(USB_DCTL, dctl.d32);
break;
}
break;
case UT_INTERFACE:
break;
case UT_ENDPOINT:
/*do endpoint stall */
break;
}
}
#endif
#if 0
static void usb_setup_handle(P_DC_Properties_T pDCProps)
{
UINT_T vendor_ack = 0;
volatile dcfg_data_t *dcfg_ptr = (dcfg_data_t *) USB_DCFG;
usb_device_request_t *ctrl_request;
ctrl_request = (usb_device_request_t *) pDCProps->ep0_out_buff_ptr;
bbu_printf("setup= 0x%x 0x%x\n",pDCProps->ep0_out_buff_ptr[0],pDCProps->ep0_out_buff_ptr[1]);
switch (UT_GET_TYPE(ctrl_request->bmRequestType)) {
case UT_STANDARD:
switch (UT_GET_RECIPIENT(ctrl_request->bmRequestType)) {
case UT_DEVICE:
switch (ctrl_request->bRequest) {
case USB_REQUEST_SET_FEATURE:
usb_set_feature();
break;
case USB_REQUEST_SET_ADDRESS:
dcfg_ptr->b.devaddr =
UGETW(ctrl_request->wValue);
usb_ep0_tx(0, 1, 0, NULL);
break;
case USB_REQUEST_GET_DESCRIPTOR:
usb_get_descriptor(ctrl_request);
break;
case USB_REQUEST_SET_CONFIGURATION: //0x00 0x09
g_udc_configuration =
UGETW(ctrl_request->wValue);
usb_ep0_tx(0, 1, 0, NULL);
if (g_set_config_flag == 0) {
usb_active_ep(USB_ENDPOINT_A, USB_IN);
usb_active_ep(USB_ENDPOINT_A, USB_OUT);
g_set_config_flag = 1;
}
break;
case USB_REQUEST_GET_CONFIGURATION:
usb_ep0_tx(UGETW(ctrl_request->wLength), 1,
1, &g_udc_configuration);
break;
case USB_REQUEST_SET_INTERFACE:
usb_ep0_tx(0, 1, 0, NULL);
break;
case USB_REQUEST_CLEAR_FEATURE:
usb_ep0_tx(0, 1, 0, NULL);
break;
default:
usb_ep0_tx(0, 1, 1, &vendor_ack);
break;
}
break;
case UT_INTERFACE:
switch (ctrl_request->bRequest) {
case USB_REQUEST_SET_INTERFACE: //0x01 0x0b
g_udc_interface = UGETW(ctrl_request->wValue);
usb_ep0_tx(0, 1, 0, NULL);
break;
case USB_REQUEST_GET_INTERFACE: //0x81 0x0a
usb_ep0_tx(UGETW(ctrl_request->wLength), 1,
1, &g_udc_interface);
break;
}
break;
case UT_ENDPOINT:
switch (ctrl_request->bRequest) {
case USB_REQUEST_GET_STATUS: //0x82 0x00
usb_ep0_tx(UGETW(ctrl_request->wLength), 1,
1, &g_udc_state);
break;
case USB_REQUEST_SET_FEATURE: //0x02 0x03
g_udc_state = 1;
usb_set_feature();
break;
case USB_REQUEST_CLEAR_FEATURE: //0x02 0x01
usb_clear_feature(UGETW(ctrl_request->wIndex));
usb_ep0_tx(0, 1, 0, NULL);
g_udc_state = 0;
break;
default:
break;
}
}
break;
case UT_CLASS:
usb_ep0_tx(0, 1, 1, NULL);
break;
case UT_VENDOR:
usb_ep0_tx(4, 1, 1, &vendor_ack);
break;
default:
usb_ep0_tx(0, 1, 1, NULL);
break;
}
}
#else
static void usb_setup_handle(P_DC_Properties_T pDCProps)
{
bbu_printf("setup= 0x%x 0x%x\n",pDCProps->ep0_out_buff_ptr[0], pDCProps->ep0_out_buff_ptr[1]);
if (pDCProps) {
pDCProps->ep0rx_data_len_array[pDCProps->ep0rx_rcd_idx] = 8;
pDCProps->ep0rx_rcd_idx++;
pDCProps->ep0rx_rcd_idx = pDCProps->ep0rx_rcd_idx % EP0_DATA_RCD_NUM;
}
USB2D_EnumerationHandler(pDCProps, (XLLP_USB_SETUP_DATA_T *)pDCProps->ep0_out_buff_ptr);
}
#endif
/**
* Flush a Tx FIFO.
*/
static void usb_flush_tx_fifo(unsigned num)
{
volatile grstctl_t greset = {.d32 = 0 };
int count = 0;
greset.b.txfflsh = 1;
greset.b.txfnum = num;
dwc_write_reg32(USB_GRSTCTL, greset.d32);
do {
greset.d32 = dwc_read_reg32(USB_GRSTCTL);
if (++count > 100000) {
bbu_printf("USB HANG! GRSTCTL=0x%x GNPTXSTS=0x%x\n\r",
greset.d32, dwc_read_reg32(USB_GNPTXSTS));
usb_report_err_status(USB_TXFIFO_TOUT_ERR);
break;
}
Delay(1);
} while (greset.b.txfflsh == 1);
/* Wait for 3 PHY Clocks */
Delay(1);
}
/**
* Flush Rx FIFO.
*/
void usb_flush_rx_fifo(void)
{
volatile grstctl_t greset = {.d32 = 0 };
int count = 0;
greset.b.rxfflsh = 1;
dwc_write_reg32(USB_GRSTCTL, greset.d32);
do {
greset.d32 = dwc_read_reg32(USB_GRSTCTL);
if (++count > 100000) {
bbu_printf("USB HANG! GRSTCTL=0x%x\n\r", greset.d32);
usb_report_err_status(USB_RXFIFO_TOUT_ERR);
break;
}
Delay(1);
} while (greset.b.rxfflsh == 1);
/* Wait for 3 PHY Clocks */
Delay(1);
}
static void usb_reset_intr(P_DC_Properties_T pDCProps)
{
int i;
volatile dcfg_data_t dcfg = {.d32 = 0 };
volatile depctl_data_t doepctl = {.d32 = 0 };
volatile daint_data_t daintmsk = {.d32 = 0 };
volatile doepmsk_data_t doepmsk = {.d32 = 0 };
volatile diepmsk_data_t diepmsk = {.d32 = 0 };
volatile gintmsk_data_t gintmsk = {.d32 = 0};
volatile gintsts_data_t gintsts = {.d32 = 0};
bbu_printf("usb rst\r\n");
/* disable reset interrupt */
gintmsk.b.usbreset = 1;
dwc_modify_reg32(USB_GINTMSK, gintmsk.d32, 0);
/* Set NAK for all OUT EPs */
doepctl.b.snak = 1;
for (i = 0; i <16; i++) {
dwc_write_reg32(USB_DOEPCTL(i), doepctl.d32);
}
daintmsk.b.inep0 = 1;
daintmsk.b.outep0 = 1;
daintmsk.b.outep1 = 1;
dwc_write_reg32(USB_DAINTMSK, daintmsk.d32);
doepmsk.b.setup = 1;
doepmsk.b.xfercompl = 1;
doepmsk.b.ahberr = 1;
doepmsk.b.epdisabled = 1;
dwc_write_reg32(USB_DOEPMSK, doepmsk.d32);
diepmsk.b.xfercompl = 1;
diepmsk.b.timeout = 1;
diepmsk.b.epdisabled = 1;
diepmsk.b.ahberr = 1;
diepmsk.b.intknepmis = 1;
dwc_write_reg32(USB_DIEPMSK, diepmsk.d32);
usb_flush_tx_fifo(0x10);
usb_flush_rx_fifo();
/* Reset Device Address */
dcfg.d32 = dwc_read_reg32(USB_DCFG);
dcfg.b.devaddr = 0;
dwc_write_reg32(USB_DCFG, dcfg.d32);
usb_ep0_rx_setup(pDCProps, 1, (UINT_T *)pDCProps->ep0_out_buff_ptr);
/* enable reset interrupt */
dwc_modify_reg32(USB_GINTMSK, 0, gintmsk.d32);
/* Clear interrupt */
gintsts.d32 = 0;
gintsts.b.usbreset = 1;
dwc_write_reg32(USB_GINTSTS, gintsts.d32);
}
static void usb_enum_done_intr(P_DC_Properties_T pDCProps)
{
volatile dctl_data_t dctl;
volatile gintsts_data_t ginsts;
volatile depctl_data_t diep0ctl;
bbu_printf("enum: DSTS = %x\r\n", dwc_read_reg32(USB_DSTS));
diep0ctl.d32 = dwc_read_reg32(USB_DIEP0CTL);
diep0ctl.b.mps = DWC_DEP0CTL_MPS_64;
dwc_write_reg32(USB_DIEP0CTL, diep0ctl.d32);
/* usb set as HS mode but real usb mode is full speed mode */
pDCProps->usb_speed_mode = dwc2_get_usb_speed();
if ((get_usb_speed_mode() == USB_MODE_HS)
&& (pDCProps->usb_speed_mode != USB_MODE_HS)) {
//update USB DESC
UpdateUSBDeviceConfigDesc(pDCProps->usb_speed_mode);
}
if (USB_MODE_FS == pDCProps->usb_speed_mode) {
usb_config_ep(USB_ENDPOINT_A, USB_EP_TYPE_BULK, USB_OUT, BULK_MPS_FS);
usb_config_ep(USB_ENDPOINT_A, USB_EP_TYPE_BULK, USB_IN, BULK_MPS_FS);
} else {
usb_config_ep(USB_ENDPOINT_A, USB_EP_TYPE_BULK, USB_OUT, BULK_MPS);
usb_config_ep(USB_ENDPOINT_A, USB_EP_TYPE_BULK, USB_IN, BULK_MPS);
}
usb_ep0_rx_setup(pDCProps, 1, (UINT_T *)pDCProps->ep0_out_buff_ptr);
dctl.d32 = dwc_read_reg32(USB_DCTL);
dctl.b.cgnpinnak = 1;
dwc_write_reg32(USB_DCTL, dctl.d32);
ginsts.d32 = 0;
ginsts.b.enumdone = 1;
dwc_write_reg32(USB_GINTSTS, ginsts.d32);
}
static void usb_ep0_out_handle(P_DC_Properties_T pDCProps)
{
volatile doepint_data_t doepint;
volatile depctl_data_t doep0ctl;
doepint.d32 = dwc_read_reg32(USB_DOEPINT(0));
dwc_write_reg32(USB_DOEPINT(0), doepint.d32);
if (doepint.b.setup) {
usb_setup_handle(pDCProps);
}
if (doepint.b.xfercompl) {
doep0ctl.d32 = dwc_read_reg32(USB_DOEP0CTL);
doep0ctl.b.snak= 1;
dwc_write_reg32(USB_DOEP0CTL, doep0ctl.d32);
}
usb_ep0_rx_setup(pDCProps, 1, (UINT_T *)pDCProps->ep0_out_buff_ptr);
}
static void usb_ep1_out_handle(P_DC_Properties_T pDCProps)
{
volatile doepint_data_t doepint;
volatile depctl_data_t doep1ctl;
volatile deptsiz_data_t deptsiz;
P_dQH_T pQH;
doepint.d32 = dwc_read_reg32(USB_DOEPINT(USB_ENDPOINT_A));
dwc_write_reg32(USB_DOEPINT(USB_ENDPOINT_A), doepint.d32);
if (doepint.b.xfercompl) {
doep1ctl.d32 = dwc_read_reg32(USB_DOEPCTL(USB_ENDPOINT_A));
doep1ctl.b.snak= 1;
dwc_write_reg32(USB_DOEPCTL(USB_ENDPOINT_A), doep1ctl.d32);
pQH = &pDCProps->pdQHHead[USB_ENDPOINT_A*2];
deptsiz.d32 = dwc_read_reg32(USB_DOEPTSIZ(USB_ENDPOINT_A));
/* xfersize is the left size */
pQH->tot_size -= deptsiz.b.xfersize;
if (pDCProps) {
pDCProps->ep1rx_data_len_array[pDCProps->ep1rx_rcd_idx] = pQH->tot_size;
pDCProps->ep1rx_rcd_idx++;
pDCProps->ep1rx_rcd_idx = pDCProps->ep1rx_rcd_idx % EP1OUT_DATA_RCD_NUM;
}
USB2D_PM_Call(pDCProps);
} else {
if (pDCProps) {
pDCProps->ep1rx_ncomp_reg_array[pDCProps->ep1rx_ncomp_rcd_idx] = doepint.d32;
pDCProps->ep1rx_ncomp_rcd_idx++;
pDCProps->ep1rx_ncomp_rcd_idx = pDCProps->ep1rx_ncomp_rcd_idx % EP1OUT_NCOPM_DATA_RCD_NUM;
}
}
}
static void usb_ep_out_handle(P_DC_Properties_T pDCProps)
{
volatile daint_data_t daint;
daint.d32 = dwc_read_reg32(USB_DAINT);
if (daint.b.outep0) {
usb_ep0_out_handle(pDCProps);
}
if (daint.b.outep1) {
usb_ep1_out_handle(pDCProps);
}
}
/* handle ep0 only */
static void usb_ep_in_handle(P_DC_Properties_T pDCProps)
{
volatile diepint_data_t diepint;
volatile daint_data_t daint;
daint.d32 = dwc_read_reg32(USB_DAINT);
if (daint.b.inep0) {
diepint.d32 = dwc_read_reg32(USB_DIEPINT(0));
dwc_write_reg32(USB_DIEPINT(0), diepint.d32);
}
}
/* handle reset/enumdone/outep int */
static void usb_irq_handler(P_DC_Properties_T pDCProps)
{
volatile gintsts_data_t usb_int;
usb_int.d32 = dwc_read_reg32(USB_GINTSTS);
if (pDCProps) {
pDCProps->usb_int_reg_array[pDCProps->usb_int_rcd_idx] = usb_int.d32;
pDCProps->usb_int_rcd_idx++;
pDCProps->usb_int_rcd_idx = pDCProps->usb_int_rcd_idx % USB_INT_REG_RCD_NUM;
}
if (usb_int.b.inepint) {
bbu_printf("%s : iepint\n\r", __func__);
usb_ep_in_handle(pDCProps);
}
if (usb_int.b.outepintr) {
bbu_printf("%s : oepint\n\r", __func__);
usb_ep_out_handle(pDCProps);
}
if (usb_int.b.enumdone) {
bbu_printf("%s : enumdone\n\r", __func__);
usb_enum_done_intr(pDCProps);
}
if (usb_int.b.usbreset) {
bbu_printf("%s : usbrst\n\r", __func__);
usb_reset_intr(pDCProps);
}
}
#if 0
static UINT_T __usb_read(UCHAR * pBuf, UINT_T len)
{
volatile doepint_data_t *doepint_ptr =
(doepint_data_t *) USB_DOEPINT(USB_ENDPOINT_A);
if (doepint_ptr->b.xfercompl == 1)
doepint_ptr->b.xfercompl = 1;
usb_start_transfer(USB_ENDPOINT_A, USB_OUT, len, 1,
(UINT_T *) pBuf);
while (doepint_ptr->b.xfercompl == 0) {
doepint_ptr = (doepint_data_t *) USB_DOEPINT(USB_ENDPOINT_A);
usb_irq_handler();
}
doepint_ptr->b.xfercompl = 1;
return len;
}
#endif
static UINT_T __usb_intr_read(UCHAR * pBuf, UINT_T len)
{
volatile doepint_data_t *doepint_ptr =
(doepint_data_t *) USB_DOEPINT(USB_ENDPOINT_A);
if (doepint_ptr->b.xfercompl == 1)
doepint_ptr->b.xfercompl = 1;
usb_start_transfer(USB_ENDPOINT_A, USB_OUT, len, 1,
(UINT_T *) pBuf);
return len;
}
/* TODO: close interrupt? */
static UINT_T __usb_write(UCHAR * pBuf, UINT_T len)
{
volatile diepint_data_t *diepint_ptr =
(diepint_data_t *) USB_DIEPINT(USB_ENDPOINT_A);
//TODO
if (diepint_ptr->b.xfercompl == 1) {
diepint_ptr->b.xfercompl = 1;
}
usb_start_transfer((XLLP_USB_ENDPOINT_ID_T) USB_ENDPOINT_A, USB_IN,
len, 1,
(UINT_T *) pBuf);
dwc2_debug_tx2 = DWC2_TX_STAGE1;
do {
diepint_ptr = (diepint_data_t *) USB_DIEPINT(USB_ENDPOINT_A);
/* TODO */
/* usb_irq_handler(); */
dwc2_debug_tx2 = DWC2_TX_STAGE2;
} while (diepint_ptr->b.xfercompl == 0);
diepint_ptr->b.xfercompl = 1;
dwc2_debug_tx2 = DWC2_TX_STAGE3;
return len;
}
#define CIU_REG_CHIPID (0xD4282C00)
static void usb_core_init(P_DC_Properties_T pDCProps)
{
UINT_T count = 0;
UINT_T chipid;
volatile grstctl_t greset = {.d32 = 0};
volatile gahbcfg_data_t gahbcfg = {.d32 = 0};
volatile gusbcfg_data_t gusbcfg = {.d32 = 0};
volatile gintmsk_data_t gintmsk = {.d32 = 0};
volatile dctl_data_t dctl = {.d32 = 0};
volatile dcfg_data_t dcfg = {.d32 = 0};
volatile gotgctl_data_t gotgctl = {.d32 = 0 };
count = 0;
do {
greset.d32 = dwc_read_reg32(USB_GRSTCTL);
if (++count > 100000) {
usb_report_err_status(USB_AHBIDLE_TOUT_ERR);
break;
}
Delay(1); /* 1us */
} while (greset.b.ahbidle == 0);
if (g_pDCProps)
g_pDCProps->dwc_ahbidle_tout = count;
count = 0;
greset.b.csftrst = 1;
dwc_write_reg32(USB_GRSTCTL, greset.d32);
do {
greset.d32 = dwc_read_reg32(USB_GRSTCTL);
if (++count > 100000) {
usb_report_err_status(USB_CRST_TOUT_ERR);
break;
}
Delay(1); /* 1us */
} while (greset.b.csftrst == 1);
if (g_pDCProps)
g_pDCProps->dwc_crst_tout = count;
/* force dev mode */
gusbcfg.d32 = dwc_read_reg32(USB_GUSBCFG);
gusbcfg.b.force_dev_mode = 1;
dwc_write_reg32(USB_GUSBCFG, gusbcfg.d32);
/* bvalid override to 1 */
gotgctl.d32 = dwc_read_reg32(USB_GOTGCTL);
gotgctl.b.bvalidoven = 1;
gotgctl.b.bvalidovval = 1;
dwc_write_reg32(USB_GOTGCTL, gotgctl.d32);
gahbcfg.d32 = dwc_read_reg32(USB_GAHBCFG);
gahbcfg.b.glblintrmsk = 1;
/*burst length should be ?*/
gahbcfg.b.hburstlen = DWC_GAHBCFG_INT_DMA_BURST_INCR4;
gahbcfg.b.dmaenable = 1;
dwc_write_reg32(USB_GAHBCFG, gahbcfg.d32);
//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);
/* FPGA */
if ((chipid & 0x700FFFF) == 0x1001806) {
gusbcfg.d32 = dwc_read_reg32(USB_GUSBCFG);
/*HS/FS time out calibration*/
gusbcfg.b.toutcal = 0;
/*USB2.0 HS UTMI+ or ULPI PHY*/
gusbcfg.b.physel = 0;
/*PHY Interface bit, 16 bit*/
gusbcfg.b.phyif = 1;
/*ULPI or UTMI+ selection bit, UTMI+ interface*/
gusbcfg.b.ulpi_utmi_sel = 0;
/*ULPI FS/LS Select*/
gusbcfg.b.ulpi_fsls = 0;
/*4'h5: When the MAC interface is 16-bit UTMI+*/
gusbcfg.b.usbtrdtim = 5;
dwc_write_reg32(USB_GUSBCFG, gusbcfg.d32);
} else {
gusbcfg.d32 = dwc_read_reg32(USB_GUSBCFG);
/*HS/FS time out calibration*/
gusbcfg.b.toutcal = 0;
/*USB2.0 HS UTMI+ or ULPI PHY*/
gusbcfg.b.physel = 0;
/*PHY Interface bit, 8 bit*/
gusbcfg.b.phyif = 0;
/*ULPI or UTMI+ selection bit, UTMI+ interface*/
gusbcfg.b.ulpi_utmi_sel = 0;
/*ULPI FS/LS Select*/
gusbcfg.b.ulpi_fsls = 0;
/*4'h9: When the MAC interface is 8-bit UTMI+*/
gusbcfg.b.usbtrdtim = 9;
dwc_write_reg32(USB_GUSBCFG, gusbcfg.d32);
}
dcfg.d32 = dwc_read_reg32(USB_DCFG);
if (USB_MODE_HS == get_usb_speed_mode())
dcfg.b.devspd = 0;
else
dcfg.b.devspd = 1;
dcfg.b.nzstsouthshk = 0;
dcfg.b.perfrint = DWC_DCFG_FRAME_INTERVAL_80;
dwc_write_reg32(USB_DCFG, dcfg.d32);
/**config the Rx/Tx FIFO size*/
/* TODO: How about EP0 FIFO SIZE?? */
dwc_write_reg32(USB_GRXFSIZ, 0x200);
dwc_write_reg32(USB_GNPTXFSIZ, 0x0200200);
dwc_write_reg32(USB_DIEPTXF(1), 0x2000220);
dwc_write_reg32(USB_DIEPTXF(2), 0x2000420);
dwc_write_reg32(USB_DIEPTXF(3), 0x2000620);
dwc_write_reg32(USB_DIEPTXF(4), 0x2000820);
dwc_write_reg32(USB_DIEPTXF(5), 0x2000A20);
dwc_write_reg32(USB_DIEPTXF(6), 0x2000C20);
dwc_write_reg32(USB_DIEPTXF(7), 0x1000E20);
dwc_write_reg32(USB_DIEPTXF(8), 0x1000F20);
dwc_write_reg32(USB_DIEPTXF(9), 0x1001020);
dwc_write_reg32(USB_DIEPTXF(10), 0x1001120);
dwc_write_reg32(USB_DIEPTXF(11), 0x1001220);
dwc_write_reg32(USB_DIEPTXF(12), 0x1001320);
dwc_write_reg32(USB_DIEPTXF(13), 0x1001420);
dwc_write_reg32(USB_DIEPTXF(14), 0x1001520);
dwc_write_reg32(USB_DIEPTXF(15), 0x1001620);
dwc_write_reg32(USB_GINTMSK, 0);
dwc_write_reg32(USB_GINTSTS, 0xffffffff);
gintmsk.b.usbreset = 1;
gintmsk.b.enumdone = 1;
gintmsk.b.inepintr = 1;
gintmsk.b.outepintr = 1;
dwc_write_reg32(USB_GINTMSK, gintmsk.d32);
}
/* kick off the usb controller */
static void usb_controller_run(P_DC_Properties_T pDCProps)
{
volatile dctl_data_t dctl = {.d32 = 0};
dctl.d32 = dwc_read_reg32(USB_DCTL);
dctl.b.sftdiscon = 0;
dwc_write_reg32(USB_DCTL, dctl.d32);
}
void usb_init(P_DC_Properties_T pDCProps)
{
/* only in bootrom need usb_init to enumrate a device, in SDL can not do init again */
bbu_printf("%s : enter\n\r", __func__);
usb_core_init(pDCProps);
}
static int dwc_otg_wait_bit_set(volatile UINT_T reg, UINT_T bit, UINT_T timeout, UINT_T *timeout_left)
{
UINT_T i;
for (i = 0; i < timeout; i++) {
if (dwc_read_reg32(reg) & bit) {
*timeout_left = timeout - i;
return 0;
}
Delay(1);
}
return -1;
}
static void dwc_otg_ep_stop_xfer(XLLP_USB_ENDPOINT_ID_T ep_num, XLLP_USB_EP_DIR_T dir)
{
volatile depctl_data_t depctl = {.d32 = 0 };
volatile gintsts_data_t gintsts = {.d32 = 0};
volatile dctl_data_t dctl = {.d32 = 0};
UINT_T timeout_left;
bbu_printf("%s: ep_num:%d dir:%d\n\r", __func__,ep_num,dir);
if (dir == USB_OUT){
gintsts.d32 = dwc_read_reg32(USB_GINTSTS);
/* set gnak */
if (gintsts.b.goutnakeff == 0) {
dctl.d32 = dwc_read_reg32(USB_DCTL);
dctl.b.sgoutnak = 1;
dwc_write_reg32(USB_DCTL, dctl.d32);
}
/* Wait for global nak to take effect, timeout: 1000ms */
if (dwc_otg_wait_bit_set(USB_GINTSTS, GINTSTS_GOUTNAKEFF, 1000, &timeout_left))
bbu_printf("%s: timeout GINTSTS.GINNAKEFF\n\r", __func__);
else if (g_pDCProps)
g_pDCProps->stop_timeout1 = timeout_left;
/* set nak and disable the ep */
depctl.d32 = dwc_read_reg32(USB_DOEPCTL(ep_num));
depctl.b.epdis = 1;
depctl.b.snak = 1;
dwc_write_reg32(USB_DOEPCTL(ep_num), depctl.d32);
/* Wait for ep to be disabled, timeout: 1000ms */
if (dwc_otg_wait_bit_set(USB_DOEPINT(ep_num), DXEPINT_EPDISBLD, 1000, &timeout_left))
bbu_printf("%s: timeout DOEPCTL.EPDisable\n\r", __func__);
else if (g_pDCProps)
g_pDCProps->stop_timeout2 = timeout_left;
/* Remove global NAKs */
dctl.d32 = dwc_read_reg32(USB_DCTL);
dctl.b.cgoutnak = 1;
dwc_write_reg32(USB_DCTL, dctl.d32);
}
else {
bbu_printf("%s: 0x%x val=0x%x 0x%x val=0x%x\n\r", __func__,USB_DIEPINT(ep_num),*(volatile unsigned int *)(USB_DIEPINT(ep_num)),USB_DIEPCTL(ep_num),*(volatile unsigned int *)(USB_DIEPCTL(ep_num)));
gintsts.d32 = dwc_read_reg32(USB_GINTSTS);
if (gintsts.b.ginnakeff == 0) {
dctl.d32 = dwc_read_reg32(USB_DCTL);
dctl.b.sgnpinnak = 1;
dwc_write_reg32(USB_DCTL, dctl.d32);
}
/* Wait for global nak to take effect */
if (dwc_otg_wait_bit_set(USB_GINTSTS, GINTSTS_GINNAKEFF, 1000, &timeout_left))
bbu_printf("%s: timeout GINTSTS.GINNAKEFF\n\r", __func__);
else if (g_pDCProps)
g_pDCProps->stop_timeout3 = timeout_left;
bbu_printf("%s: 0x%x val=0x%x 0x%x val=0x%x\n\r", __func__,USB_DIEPINT(ep_num),*(volatile unsigned int *)(USB_DIEPINT(ep_num)),USB_DIEPCTL(ep_num),*(volatile unsigned int *)(USB_DIEPCTL(ep_num)));
depctl.d32 = dwc_read_reg32(USB_DIEPCTL(ep_num));
depctl.b.snak = 1;
dwc_write_reg32(USB_DIEPCTL(ep_num), depctl.d32);
/* Wait for Nak effect */
if (dwc_otg_wait_bit_set(USB_DIEPINT(ep_num), DXEPINT_INEPNAKEFF, 1000, &timeout_left))
bbu_printf("%s: timeout DIEPINT.NAKEFF\n\r", __func__);
else if (g_pDCProps)
g_pDCProps->stop_timeout4 = timeout_left;
/* set nak and disable the ep */
depctl.d32 = dwc_read_reg32(USB_DIEPCTL(ep_num));
if((0 == (DXEPCTL_NAKSTS & depctl.d32)) || (DXEPCTL_EPENA & depctl.d32))
{
depctl.b.epdis = 1;
depctl.b.snak = 1;
dwc_write_reg32(USB_DIEPCTL(ep_num), depctl.d32);
/* Wait for ep to be disabled */
if (dwc_otg_wait_bit_set(USB_DIEPINT(ep_num), DXEPINT_EPDISBLD, 1000, &timeout_left))
bbu_printf("%s: timeout DIEPCTL.EPDisable\n\r", __func__);
else if (g_pDCProps)
g_pDCProps->stop_timeout5 = timeout_left;
}
usb_flush_tx_fifo(0x10);
}
}
void usb_deinit(P_DC_Properties_T pDCProps)
{
volatile dctl_data_t dctl = {.d32 = 0};
/* delay for the last xfer to be finished */
Delay(5 * 1000);
dwc_otg_ep_stop_xfer(USB_ENDPOINT_A, USB_OUT);
dwc_otg_ep_stop_xfer(USB_ENDPOINT_A, USB_IN);
dctl.d32 = dwc_read_reg32((UINT_T)USB_DCTL);
dctl.b.sftdiscon = 1;
dwc_write_reg32((UINT_T)USB_DCTL, dctl.d32);
/* delay for host to handle disconnection */
Delay(500);
}
extern UINT_T USB2D_Get_Speed_Mode(void)
{
return dwc2_get_usb_speed();
}
void USB2D_EP0_STALL_AND_RESTART(P_DC_Properties_T pDCProps)
{
ep0_do_stall(pDCProps);
}
void USB2D_ISR(UINT intnum)
{
P_DC_Properties_T pDCProps = Get_DC_Properties(intnum);
if (pDCProps)
usb_irq_handler(pDCProps);
else
usb_report_err_status(USB_PROP_NOT_FOUND);
}
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);
} else
usb_report_err_status(USB_API_NOT_FOUND);
}
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)
{
//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 == dwc2_get_usb_speed())
size = (((size + 63) >> 6) << 6);
else
size = (((size + 511) >> 9) << 9);
//call the trasmit routine
USB2D_EndpointTransmit(pDCProps, USB_ENDPOINT_A, USB_OUT, (UINT_T)(buffer), size);
} else
usb_report_err_status(USB_API_NOT_FOUND);
return;
}
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)
{
//call the trasmit routine
USB2D_EndpointTransmit(pDCProps, USB_ENDPOINT_A, USB_IN, (UINT_T)(buffer), size);
} else
usb_report_err_status(USB_API_NOT_FOUND);
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 qh_index;
UINT_T local_buffer;
//calculate which Queue Head to service
qh_index = ep_num*2+direction;
bbu_printf("====%s: buffer: 0x%x size: 0x%x\n\r",__func__, buffer, size);
/* buffer is not 4bytes aligned */
if (((UINT_T)buffer) & 0x3) {
if (direction) {
memcpy(pDCProps->ep0_in_buff_ptr, buffer, size);
local_buffer = pDCProps->ep0_in_buff_ptr;
usb_report_err_status(USB_EP0_TX_ALIGN_ERR);
} else {
local_buffer = pDCProps->ep0_out_buff_ptr;
usb_report_err_status(USB_EP0_RX_ALIGN_ERR);
}
} else {
local_buffer = buffer;
}
//save off info for software cleanup later on
pDCProps->pdQHHead[qh_index].buffer = (UINT)local_buffer;
pDCProps->pdQHHead[qh_index].tot_size = size;
pDCProps->ep0_data_len_array[pDCProps->ep0_rcd_idx] = size;
pDCProps->ep0_rcd_idx++;
pDCProps->ep0_rcd_idx = pDCProps->ep0_rcd_idx % EP0_DATA_RCD_NUM;
if (direction) {
if (size)
usb_ep0_tx(pDCProps, size, 1, 1, local_buffer);
else
usb_ep0_tx(pDCProps, size, 1, 0, local_buffer);
} else {
usb_report_err_status(USB_EP0_XMIT_ERR);
}
}
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;
UINT_T local_buffer;
//calculate which Queue Head to service
qh_index = ep_num*2+direction;
bbu_printf("====%s: buffer: 0x%x size: 0x%x\n\r",__func__, buffer, size);
/* buffer is not 4bytes aligned */
if (((UINT_T)buffer) & 0x3) {
if (direction) {
memcpy(pDCProps->data_in_buff_ptr, buffer, size);
local_buffer = pDCProps->data_in_buff_ptr;
usb_report_err_status(USB_EP1_TX_ALIGN_ERR);
} else {
local_buffer = pDCProps->data_out_buff_ptr;
usb_report_err_status(USB_EP1_RX_ALIGN_ERR);
}
} else {
local_buffer = buffer;
}
//save off info for software cleanup later on
pDCProps->pdQHHead[qh_index].buffer = (UINT)local_buffer;
pDCProps->pdQHHead[qh_index].tot_size = size;
if (direction) {
pDCProps->ep1in_data_len_array[pDCProps->ep1in_rcd_idx] = size;
pDCProps->ep1in_rcd_idx++;
pDCProps->ep1in_rcd_idx = pDCProps->ep1in_rcd_idx % EP1IN_DATA_RCD_NUM;
__usb_write(local_buffer, size);
} else {
pDCProps->ep1out_data_len_array[pDCProps->ep1out_rcd_idx] = size;
pDCProps->ep1out_rcd_idx++;
pDCProps->ep1out_rcd_idx = pDCProps->ep1out_rcd_idx % EP1OUT_DATA_RCD_NUM;
__usb_intr_read(local_buffer, size);
}
}
//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)
{
usb_active_ep(ep_num, direction);
}
void USB2D_Shutdown(UINT intnum)
{
usb_deinit(g_pDCProps);
}
UINT_T USB2D_Initialize(UINT base_address, UINT int_number, int param)
{
P_DC_Properties_T pDCProps;
//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
}
g_pDCProps = pDCProps;
//reset and config the controller, but not start running up
usb_init(pDCProps);
//setup EP0?
/* begin to receive SETUP packets */
__asm__ __volatile__("dsb" : : : "memory");
//RUN UP USB
bbu_printf("%s start usb now\n\r", __func__);
usb_controller_run(pDCProps);
bbu_printf("%s start usb done\n\r", __func__);
return NoError;
}
void USB2D_Set_Addr(UINT16_T Addr)
{
volatile dcfg_data_t *dcfg_ptr = (dcfg_data_t *) USB_DCFG;
/* 7 bits address */
dcfg_ptr->b.devaddr = (Addr & 0x7f);
}