| #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); |
| } |