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); }
void usb3_init_eventbuf(usb3_device_t *dev, int size, uint32_t dma_addr) { dwc_writel(dma_addr & 0xffffffffU, &dev->core_global_regs->geventbuf[0].geventadr_lo); dwc_writel(0, &dev->core_global_regs->geventbuf[0].geventadr_hi); dwc_writel(size << 2, &dev->core_global_regs->geventbuf[0].geventsiz); dwc_writel(0, &dev->core_global_regs->geventbuf[0].geventcnt); }
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; }
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 usb3_enable_device_interrupts(usb3_device_t *dev) { /* Clear any pending interrupts */ usb3_dis_flush_eventbuf_intr(dev); /* Enable device interrupts */ dwc_writel(USB3_DEVTEN_CONNDONE_BIT | USB3_DEVTEN_USBRESET_BIT, &dev->pcd.dev_global_regs->devten); }
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); }
/* * ch 9.4.1, 9.4.9 */ static int dwc2_ep0_handle_feature(struct dwc2 *dwc, struct usb_ctrlrequest *ctrl, int set) { struct dwc2_ep *dep; u32 recip; u32 wValue; u32 wIndex; int ret; gotgctl_data_t gotgctl = {.d32 = 0 }; dwc_otg_core_global_regs_t *global_regs = dwc->core_global_regs; wValue = le16_to_cpu(ctrl->wValue); wIndex = le16_to_cpu(ctrl->wIndex); recip = ctrl->bRequestType & USB_RECIP_MASK; switch (recip) { case USB_RECIP_DEVICE: switch (wValue) { case USB_DEVICE_REMOTE_WAKEUP: dwc->remote_wakeup_enable = set; break; case USB_DEVICE_TEST_MODE: if ((wIndex & 0xff) != 0) return -EINVAL; /* 9.4.1: The Test_Mode feature cannot be cleared by the ClearFeature() request. */ if (!set) return -EINVAL; /* * The transition to test mode of an upstream facing port must not * happen until after the status stage of the request. * * NOTE: we do not bother to check if the Test Mode Selector is valid, * the host must take care it!!! */ dwc->test_mode_nr = wIndex >> 8; dwc->test_mode = true; break; case USB_DEVICE_B_HNP_ENABLE: if (set) { dev_info(dwc->dev, "Request B HNP\n"); dwc->b_hnp_enable = 1; // TODO: dwc_otg_pcd_update_otg(dwc, 0); /** * TODO: Is the gotgctl.devhnpen cleared by a USB Reset? */ gotgctl.b.devhnpen = 1; gotgctl.b.hnpreq = 1; dwc_writel(gotgctl.d32, &global_regs->gotgctl); } else return -EINVAL; break; case USB_DEVICE_A_HNP_SUPPORT: if (set) { dwc->a_hnp_support = 1; // TODO: dwc_otg_pcd_update_otg(dwc, 0); } else return -EINVAL; break; case USB_DEVICE_A_ALT_HNP_SUPPORT: if (set) { dwc->a_alt_hnp_support = 1; // dwc_otg_pcd_update_otg(dwc, 0); } else return -EINVAL; break; default: return -EINVAL; } dwc2_ep0_do_status_phase(dwc); break; case USB_RECIP_INTERFACE: /* USB2.0 do not support interface feature */ return -EINVAL; break; case USB_RECIP_ENDPOINT: switch (wValue) { case USB_ENDPOINT_HALT: dep = dwc2_wIndex_to_dep(dwc, wIndex); if (!dep) return -EINVAL; ret = __dwc2_gadget_ep_set_halt(dep, set); if (ret) return -EINVAL; break; default: return -EINVAL; } dwc2_ep0_do_status_phase(dwc); break; default: return -EINVAL; }; return 0; } static int dwc2_ep0_std_request(struct dwc2 *dwc, struct usb_ctrlrequest *ctrl) { int ret; switch (ctrl->bRequest) { case USB_REQ_GET_STATUS: dev_vdbg(dwc->dev, "USB_REQ_GET_STATUS\n"); ret = dwc2_ep0_handle_status(dwc, ctrl); break; case USB_REQ_CLEAR_FEATURE: dev_vdbg(dwc->dev, "USB_REQ_CLEAR_FEATURE\n"); ret = dwc2_ep0_handle_feature(dwc, ctrl, 0); break; case USB_REQ_SET_FEATURE: dev_vdbg(dwc->dev, "USB_REQ_SET_FEATURE\n"); ret = dwc2_ep0_handle_feature(dwc, ctrl, 1); break; case USB_REQ_SET_ADDRESS: dev_vdbg(dwc->dev, "USB_REQ_SET_ADDRESS\n"); ret = dwc2_ep0_set_address(dwc, ctrl); break; case USB_REQ_SET_CONFIGURATION: dev_vdbg(dwc->dev, "USB_REQ_SET_CONFIGURATION\n"); ret = dwc2_ep0_set_config(dwc, ctrl); break; default: dev_vdbg(dwc->dev, "Forwarding to gadget driver\n"); ret = dwc2_ep0_delegate_req(dwc, ctrl); break; }; return ret; }
/** * 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; }
void update_eventbuf_count(usb3_device_t *dev, int cnt) { dwc_writel(cnt, &dev->core_global_regs->geventbuf[0].geventcnt); }