static void dwc2_ep0_start_out_transfer(struct dwc2 *dwc, struct dwc2_request *req) { dwc_otg_dev_out_ep_regs_t *out_regs = dwc->dev_if.out_ep_regs[0]; depctl_data_t depctl; struct dwc2_ep *dep = req->dwc2_ep; deptsiz0_data_t deptsiz; deptsiz.d32 = dwc_readl(&out_regs->doeptsiz); deptsiz.b.xfersize = dep->maxp; deptsiz.b.supcnt = 0; deptsiz.b.pktcnt = 1; req->xfersize = dep->maxp; req->pktcnt = 1; DWC2_EP0_DEBUG_MSG("OUT: next_dma_addr = 0x%08x\n", req->next_dma_addr); if (dwc->dma_enable) { if (!dwc->dma_desc_enable) { dwc_writel(deptsiz.d32, &out_regs->doeptsiz); dwc_writel(req->next_dma_addr, &out_regs->doepdma); } else { /* TODO: Scatter/Gather DMA Mode here */ } } else { dwc_writel(deptsiz.d32, &out_regs->doeptsiz); } /* EP enable */ dep->flags |= DWC2_EP_BUSY; depctl.d32 = dwc_readl(&out_regs->doepctl); depctl.b.epena = 1; depctl.b.cnak = 1; dwc_writel(depctl.d32, &out_regs->doepctl); }
static void dwc2_ep0_start_in_transfer(struct dwc2 *dwc, struct dwc2_request *req) { dwc_otg_dev_in_ep_regs_t *in_regs = dwc->dev_if.in_ep_regs[0]; struct dwc2_ep *dep = req->dwc2_ep; depctl_data_t depctl; deptsiz0_data_t deptsiz; deptsiz.d32 = dwc_readl(&in_regs->dieptsiz); if (req->trans_count_left == 0) { /* Zero Packet */ DWC2_EP0_DEBUG_MSG("IN zero packet\n"); req->zlp_transfered = 1; deptsiz.b.xfersize = 0; } else { if (req->trans_count_left > dep->maxp) { deptsiz.b.xfersize = dep->maxp; } else { deptsiz.b.xfersize = req->trans_count_left; } } deptsiz.b.pktcnt = 1; req->xfersize = deptsiz.b.xfersize; req->pktcnt = 1; DWC2_EP0_DEBUG_MSG("IN: xfersize = %d next_dma_addr = 0x%08x zlp_transfered = %d dep->maxp = %d\n", req->xfersize, req->next_dma_addr, req->zlp_transfered, dep->maxp); /* Write the DMA register */ if (dwc->dma_enable) { if (!dwc->dma_desc_enable) { dwc_writel(req->next_dma_addr, &in_regs->diepdma); dwc_writel(deptsiz.d32, &in_regs->dieptsiz); } else { /* TODO: Scatter/Gather DMA mode here */ } } else { dwc_writel(deptsiz.d32, &in_regs->dieptsiz); } /* EP enable, IN data in FIFO */ dep->flags |= DWC2_EP_BUSY; depctl.d32 = dwc_readl(&in_regs->diepctl); depctl.b.epena = 1; depctl.b.cnak = 1; dwc_writel(depctl.d32, &in_regs->diepctl); }
static void dwc2_ep0_complete_status(struct dwc2 *dwc) { struct dwc2_ep *ep0 = dwc2_ep0_get_ep0(dwc); struct dwc2_request *curr_req; dctl_data_t dctl; /* enter test mode if needed (exit by reset) */ if (dwc->test_mode) { /* * The transition to test mode must be complete no later than 3 ms * after the completion of the status stage of the request. */ dctl.d32 = dwc_readl(&dwc->dev_if.dev_global_regs->dctl); dctl.b.tstctl = dwc->test_mode_nr; dwc_writel(dctl.d32, &dwc->dev_if.dev_global_regs->dctl); } /* * prepare to receive SETUP again to ensure we are prepared!!! */ dwc2_ep0_out_start(dwc); curr_req = next_request(&ep0->request_list); if (curr_req) { dwc2_gadget_giveback(ep0, curr_req, 0); } if (dwc->test_mode) dev_info(dwc->dev, "entering Test Mode(%d)\n", dwc->test_mode_nr); dwc->ep0state = EP0_SETUP_PHASE; }
int get_eventbuf_count(usb3_device_t *dev) { uint32_t cnt; cnt = dwc_readl(&dev->core_global_regs->geventbuf[0].geventcnt); return cnt & USB3_EVENTCNT_CNT_BITS; }
void usb3_dis_flush_eventbuf_intr(usb3_device_t *dev) { uint32_t cnt; dis_eventbuf_intr(dev); cnt = dwc_readl(&dev->core_global_regs->geventbuf[0].geventcnt); dwc_writel(cnt, &dev->core_global_regs->geventbuf[0].geventcnt); }
void ena_eventbuf_intr(usb3_device_t *dev) { uint32_t eventsiz; eventsiz = dwc_readl(&dev->core_global_regs->geventbuf[0].geventsiz); eventsiz &= ~USB3_EVENTSIZ_INT_MSK_BIT; dwc_writel(eventsiz, &dev->core_global_regs->geventbuf[0].geventsiz); }
static void dwc2_ep0_out_complete_data(struct dwc2 *dwc) { struct dwc2_ep *ep0 = dwc2_ep0_get_ep0(dwc); struct dwc2_dev_if *dev_if = &dwc->dev_if; struct dwc2_request *curr_req; deptsiz0_data_t deptsiz; int trans_count = 0; curr_req = next_request(&ep0->request_list); if (curr_req == NULL) { return; } if (dwc->dma_enable) { if (dwc->dma_desc_enable) { /* TODO: Scatter/Gather DMA Mode here! */ } else { deptsiz.d32 = dwc_readl(&dev_if->out_ep_regs[0]->doeptsiz); /* The Programming Guide said xfercompl raised when xfersize and pktcnt gets zero */ WARN(deptsiz.b.xfersize, "%s: xfersize not zero when transfer complete\n", __func__); trans_count = curr_req->xfersize - deptsiz.b.xfersize; } curr_req->trans_count_left -= trans_count; if (curr_req->trans_count_left < 0) { curr_req->trans_count_left = 0; } //curr_req->next_dma_addr += trans_count; curr_req->request.actual += trans_count; /* copy from shadow buffer to real buffer */ if (curr_req->request.length != 0) { int offset = curr_req->request.actual; u32 buf_addr = (u32)curr_req->request.buf; memcpy( (void *)(buf_addr + offset), (void *)dwc->ep0out_shadow_uncached, trans_count); } /* if xfersize is not zero, we receive an short packet, the transfer is complete */ if (!deptsiz.b.xfersize && (curr_req->trans_count_left || need_send_zlp(curr_req))) { dwc2_ep0_start_transfer(dwc, curr_req); } else { dwc2_ep0_do_status_phase(dwc); } } else { /* TODO: PIOMode */ } }
static void dwc2_ep0_in_complete_data(struct dwc2 *dwc) { struct dwc2_ep *ep0 = dwc2_ep0_get_ep0(dwc); struct dwc2_dev_if *dev_if = &dwc->dev_if; struct dwc2_request *curr_req; deptsiz0_data_t deptsiz; int trans_count = 0; curr_req = next_request(&ep0->request_list); if (curr_req == NULL) { return; } if (dwc->dma_enable) { if (dwc->dma_desc_enable) { /* TODO: Scatter/Gather DMA Mode here! */ } else { deptsiz.d32 = dwc_readl(&dev_if->in_ep_regs[0]->dieptsiz); /* The Programming Guide said xfercompl raised when xfersize and pktcnt gets zero */ WARN(deptsiz.b.xfersize, "%s: xfersize not zero when transfer complete\n", __func__); trans_count = curr_req->xfersize - deptsiz.b.xfersize; } curr_req->trans_count_left -= trans_count; if (curr_req->trans_count_left < 0) curr_req->trans_count_left = 0; curr_req->next_dma_addr += trans_count; if (curr_req->trans_count_left || need_send_zlp(curr_req)) { DWC2_EP0_DEBUG_MSG("req 0x%p continue transfer, is_in = %d\n", curr_req, curr_req->dwc2_ep->is_in); dwc2_ep0_start_transfer(dwc, curr_req); } else { DWC2_EP0_DEBUG_MSG("req 0x%p done, do %s status phase\n", curr_req, dwc->ep0_expect_in ? "OUT" : "IN"); dwc2_ep0_do_status_phase(dwc); } } else { /* TODO: PIO Mode */ } }
/** * This function configures EPO to receive SETUP packets. * * Priciple: prepare to receive as sooooooon as the OUT ep is idle! */ void dwc2_ep0_out_start(struct dwc2 *dwc) { struct dwc2_dev_if *dev_if = &dwc->dev_if; deptsiz0_data_t doeptsize0 = {.d32 = 0 }; depctl_data_t doepctl = {.d32 = 0 }; doepmsk_data_t doepmsk; doepint_data_t doepint; u32 doepdma; doepctl.d32 = dwc_readl(&dev_if->out_ep_regs[0]->doepctl); doeptsize0.d32 = dwc_readl(&dev_if->out_ep_regs[0]->doeptsiz); doepdma = dwc_readl(&dev_if->out_ep_regs[0]->doepdma); if (dwc->setup_prepared) { if (!doepctl.b.epena) { DWC2_EP0_DEBUG_MSG("setup prepared but ep0out is stoped by someone! " "doeptsize0 = 0x%08x doepdma = 0x%08x\n", doeptsize0.d32, doepdma); } else { DWC2_EP0_DEBUG_MSG("setup already prepared and ep0out is running! " "doeptsize0 = 0x%08x doepdma = 0x%08x\n", doeptsize0.d32, doepdma); } return; } if (unlikely(doepctl.b.epena)) { DWC2_EP0_DEBUG_MSG("ep0 is already enabled! doeptsize0 = 0x%08x\n", doeptsize0.d32); return; } doepmsk.d32 = dwc_readl(&dev_if->dev_global_regs->doepmsk); doepint.d32 = dwc_readl(&dev_if->out_ep_regs[0]->doepint) & doepmsk.d32; if (unlikely(doepint.b.setup)) { DWC2_EP0_DEBUG_MSG("%s: a setup packet is already pending\n", __func__); return; } dwc->setup_prepared = 1; doeptsize0.b.supcnt = 3; doeptsize0.b.pktcnt = 1; doeptsize0.b.xfersize = 8 * 3; if (dwc->dma_enable) { if (!dwc->dma_desc_enable) { /* TODO: if the endpoint is just transfering a SETUP packet, * and we change these registers, what will happend? * * But how do we know that the core is just transfering a SETUP packet? */ dwc_writel(doeptsize0.d32, &dev_if->out_ep_regs[0]->doeptsiz); dwc_writel(dwc->ctrl_req_addr, &dev_if->out_ep_regs[0]->doepdma); } else { /* TODO: Scatter/Gather DMA here */ } } else { dwc_writel(doeptsize0.d32, &dev_if->out_ep_regs[0]->doeptsiz); } DWC2_EP0_DEBUG_MSG("dwc2_ep0_out_start(0x%08x)\n", dwc->ctrl_req_addr); doepctl.b.cnak = 1; doepctl.b.epena = 1; dwc_writel(doepctl.d32, &dev_if->out_ep_regs[0]->doepctl); } static void dwc2_ep0_status_cmpl(struct usb_ep *ep, struct usb_request *req) { /* do nothing */ } static void dwc2_ep0_start_transfer(struct dwc2 *dwc, struct dwc2_request *req); /** * Problem: as soon as we receive the xfercompl intr for status phase, * a new SETUP packet may comming, so we must prepare this. * * Solution: when do OUT status phase, call dwc2_ep0_out_start() instead, * * when do IN status phase, firstly call dwc2_ep0_out_start(), * then do a ZPL IN status transfer */ static int dwc2_ep0_do_status_phase(struct dwc2 *dwc) { unsigned is_in = !dwc->ep0_expect_in; dwc->ep0state = EP0_STATUS_PHASE; dwc2_ep0_out_start(dwc); if (!is_in) { /* OUT status phase */ return 0; } else { dwc->ep0_usb_req.dwc2_ep = dwc2_ep0_get_in_ep(dwc); dwc->ep0_usb_req.request.length = 0; dwc->ep0_usb_req.request.buf = (void *)0xFFFFFFFF; dwc->ep0_usb_req.request.complete = dwc2_ep0_status_cmpl; dwc2_ep0_start_transfer(dwc, &dwc->ep0_usb_req); return 0; } } /* * ch 9.4.6, the spec said: * The USB device does not change its device address until after * the Status stage of this request is completed successfully * TODO: do we need to set address after status stage compl? */ static int dwc2_ep0_set_address(struct dwc2 *dwc, struct usb_ctrlrequest *ctrl) { dcfg_data_t dcfg; u32 addr; addr = le16_to_cpu(ctrl->wValue); if (addr > 127) { dev_dbg(dwc->dev, "invalid device address %d\n", addr); return -EINVAL; } if (dwc->dev_state == DWC2_CONFIGURED_STATE) { dev_dbg(dwc->dev, "trying to set address when configured\n"); return -EINVAL; } dcfg.d32 = dwc_readl(&dwc->dev_if.dev_global_regs->dcfg); dcfg.b.devaddr = addr; dwc_writel(dcfg.d32, &dwc->dev_if.dev_global_regs->dcfg); if (addr) dwc->dev_state = DWC2_ADDRESS_STATE; else dwc->dev_state = DWC2_DEFAULT_STATE; dwc2_ep0_do_status_phase(dwc); return 0; }