static void dwc3_otg_set_hsphy_auto_suspend(struct dwc3_otg *dotg, bool susp) { struct dwc3 *dwc = dotg->dwc; u32 reg; reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); if (susp) reg |= DWC3_GUSB2PHYCFG_SUSPHY; else reg &= ~(DWC3_GUSB2PHYCFG_SUSPHY); dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); }
static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) { enum usb_device_state state = dwc->gadget.state; u32 cfg; int ret; u32 reg; dwc->start_config_issued = false; cfg = le16_to_cpu(ctrl->wValue); switch (state) { case USB_STATE_DEFAULT: return -EINVAL; case USB_STATE_ADDRESS: ret = dwc3_ep0_delegate_req(dwc, ctrl); /* if the cfg matches and the cfg is non zero */ if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) { /* * only change state if set_config has already * been processed. If gadget driver returns * USB_GADGET_DELAYED_STATUS, we will wait * to change the state on the next usb_ep_queue() */ if (ret == 0) usb_gadget_set_state(&dwc->gadget, USB_STATE_CONFIGURED); /* * Enable transition to U1/U2 state when * nothing is pending from application. */ reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA); dwc3_writel(dwc->regs, DWC3_DCTL, reg); dwc->resize_fifos = true; dev_dbg(dwc->dev, "resize FIFOs flag SET"); } break; case USB_STATE_CONFIGURED: ret = dwc3_ep0_delegate_req(dwc, ctrl); if (!cfg && !ret) usb_gadget_set_state(&dwc->gadget, USB_STATE_ADDRESS); break; default: ret = -EINVAL; } return ret; }
/** * dwc3_otg_set_host_regs - reset dwc3 otg registers to host operation. * * This function sets the OTG registers to work in A-Device host mode. * This function should be called just before entering to A-Device mode. * * @w: Pointer to the dwc3 otg struct */ static void dwc3_otg_set_host_regs(struct dwc3_otg *dotg) { u32 reg; struct dwc3 *dwc = dotg->dwc; struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv; #ifdef CONFIG_MACH_LGE /* use default qcom,dwc-hsphy-init value for Host Mode */ reg = dwc3_readl(dwc->regs, PARAMETER_OVERRIDE_X_REG); reg &= ~(0x03FFFFFF); reg |= (DEFAULT_HSPHY_INIT & 0x03FFFFFF); dwc3_writel(dwc->regs, PARAMETER_OVERRIDE_X_REG, reg); #endif if (ext_xceiv && !ext_xceiv->otg_capability) { /* Set OCTL[6](PeriMode) to 0 (host) */ reg = dwc3_readl(dotg->regs, DWC3_OCTL); reg &= ~DWC3_OTG_OCTL_PERIMODE; dwc3_writel(dotg->regs, DWC3_OCTL, reg); } else { reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)); reg |= DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_HOST); /* * Allow ITP generated off of ref clk based counter instead * of UTMI/ULPI clk based counter, when superspeed only is * active so that UTMI/ULPI can be suspened. */ reg |= DWC3_GCTL_SOFITPSYNC; /* * Set this bit so that device attempts three more times at SS, * even if it failed previously to operate in SS mode. */ reg |= DWC3_GCTL_U2RSTECN; reg &= ~(DWC3_GCTL_PWRDNSCALEMASK); reg |= DWC3_GCTL_PWRDNSCALE(2); dwc3_writel(dwc->regs, DWC3_GCTL, reg); } }
static void dwc3_otg_set_peripheral_mode(struct dwc3_otg *dotg) { struct dwc3 *dwc = dotg->dwc; u32 reg; if (dotg->regs) { reg = dwc3_readl(dotg->regs, DWC3_OCTL); reg |= DWC3_OTG_OCTL_PERIMODE; dwc3_writel(dotg->regs, DWC3_OCTL, reg); } else { dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); } }
static void dwc3_otg_set_host_mode(struct dwc3_otg *dotg) { struct dwc3 *dwc = dotg->dwc; u32 reg; if (dotg->regs) { reg = dwc3_readl(dotg->regs, DWC3_OCTL); reg &= ~DWC3_OTG_OCTL_PERIMODE; dwc3_writel(dotg->regs, DWC3_OCTL, reg); } else { dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); } }
/** * dwc3_event_buffers_setup - setup our allocated event buffers * @dwc: pointer to our controller context structure * * Returns 0 on success otherwise negative errno. */ static int __devinit dwc3_event_buffers_setup(struct dwc3 *dwc) { struct dwc3_event_buffer *evt; int n; for (n = 0; n < dwc->num_event_buffers; n++) { evt = dwc->ev_buffs[n]; dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n", evt->buf, (unsigned long long) evt->dma, evt->length); dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), lower_32_bits(evt->dma)); dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), upper_32_bits(evt->dma)); dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), evt->length & 0xffff); dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0); } return 0; }
u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type) { struct dwc3 *dwc = dep->dwc; u32 reg; dwc3_writel(dwc->regs, DWC3_GDBGFIFOSPACE, DWC3_GDBGFIFOSPACE_NUM(dep->number) | DWC3_GDBGFIFOSPACE_TYPE(type)); reg = dwc3_readl(dwc->regs, DWC3_GDBGFIFOSPACE); return DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(reg); }
/** * dwc3_otg_set_peripheral_regs - reset dwc3 otg registers to peripheral operation. * * This function sets the OTG registers to work in B-Device peripheral mode. * This function should be called just before entering to B-Device mode. * * @w: Pointer to the dwc3 otg workqueue. */ static void dwc3_otg_set_peripheral_regs(struct dwc3_otg *dotg) { u32 reg; struct dwc3 *dwc = dotg->dwc; struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv; if (ext_xceiv && !ext_xceiv->otg_capability) { /* Set OCTL[6](PeriMode) to 1 (peripheral) */ reg = dwc3_readl(dotg->regs, DWC3_OCTL); reg |= DWC3_OTG_OCTL_PERIMODE; dwc3_writel(dotg->regs, DWC3_OCTL, reg); /* * TODO: add more OTG registers writes for PERIPHERAL mode here, * see figure 12-19 B-device flow in dwc3 Synopsis spec */ } else { reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)); reg |= DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_DEVICE); dwc3_writel(dwc->regs, DWC3_GCTL, reg); } }
void dwc3_set_mode(struct dwc3 *dwc, u32 mode) { u32 reg; reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)); reg |= DWC3_GCTL_PRTCAPDIR(mode); /* * Set this bit so that device attempts three more times at SS, even * if it failed previously to operate in SS mode. */ reg |= DWC3_GCTL_U2RSTECN; reg &= ~(DWC3_GCTL_SOFITPSYNC); reg &= ~(DWC3_GCTL_PWRDNSCALEMASK); reg |= DWC3_GCTL_PWRDNSCALE(2); reg |= DWC3_GCTL_U2EXIT_LFPS; dwc3_writel(dwc->regs, DWC3_GCTL, reg); if (mode == DWC3_GCTL_PRTCAP_OTG || mode == DWC3_GCTL_PRTCAP_HOST) { /* * Allow ITP generated off of ref clk based counter instead * of UTMI/ULPI clk based counter, when superspeed only is * active so that UTMI/ULPI PHY can be suspened. * * Starting with revision 2.50A, GFLADJ_REFCLK_LPM_SEL is used * instead. */ if (dwc->revision < DWC3_REVISION_250A) { reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg |= DWC3_GCTL_SOFITPSYNC; dwc3_writel(dwc->regs, DWC3_GCTL, reg); } else { reg = dwc3_readl(dwc->regs, DWC3_GFLADJ); reg |= DWC3_GFLADJ_REFCLK_LPM_SEL; dwc3_writel(dwc->regs, DWC3_GFLADJ, reg); } } }
/** * dwc3_otg_set_host_regs - reset dwc3 otg registers to host operation. * * This function sets the OTG registers to work in A-Device host mode. * This function should be called just before entering to A-Device mode. * * @w: Pointer to the dwc3 otg workqueue. */ static void dwc3_otg_set_host_regs(struct dwc3_otg *dotg) { u32 octl; /* Set OCTL[6](PeriMode) to 0 (host) */ octl = dwc3_readl(dotg->regs, DWC3_OCTL); octl &= ~DWC3_OTG_OCTL_PERIMODE; dwc3_writel(dotg->regs, DWC3_OCTL, octl); /* * TODO: add more OTG registers writes for HOST mode here, * see figure 12-10 A-device flow in dwc3 Synopsis spec */ }
/** * dwc3_otg_set_peripheral_regs - reset dwc3 otg registers to peripheral operation. * * This function sets the OTG registers to work in B-Device peripheral mode. * This function should be called just before entering to B-Device mode. * * @w: Pointer to the dwc3 otg workqueue. */ static void dwc3_otg_set_peripheral_regs(struct dwc3_otg *dotg) { u32 octl; /* Set OCTL[6](PeriMode) to 1 (peripheral) */ octl = dwc3_readl(dotg->regs, DWC3_OCTL); octl |= DWC3_OTG_OCTL_PERIMODE; dwc3_writel(dotg->regs, DWC3_OCTL, octl); /* * TODO: add more OTG registers writes for PERIPHERAL mode here, * see figure 12-19 B-device flow in dwc3 Synopsis spec */ }
/** * dwc3_otg_reset - reset dwc3 otg registers. * * @w: Pointer to the dwc3 otg workqueue */ static void dwc3_otg_reset(struct dwc3_otg *dotg) { static int once; struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv; /* * OCFG[2] - OTG-Version = 1 * OCFG[1] - HNPCap = 0 * OCFG[0] - SRPCap = 0 */ if (ext_xceiv && !ext_xceiv->otg_capability) dwc3_writel(dotg->regs, DWC3_OCFG, 0x4); /* * OCTL[6] - PeriMode = 1 * OCTL[5] - PrtPwrCtl = 0 * OCTL[4] - HNPReq = 0 * OCTL[3] - SesReq = 0 * OCTL[2] - TermSelDLPulse = 0 * OCTL[1] - DevSetHNPEn = 0 * OCTL[0] - HstSetHNPEn = 0 */ if (!once) { if (ext_xceiv && !ext_xceiv->otg_capability) dwc3_writel(dotg->regs, DWC3_OCTL, 0x40); once++; } /* Clear all otg events (interrupts) indications */ dwc3_writel(dotg->regs, DWC3_OEVT, 0xFFFF); /* Enable ID/BSV StsChngEn event*/ if (ext_xceiv && !ext_xceiv->otg_capability) dwc3_writel(dotg->regs, DWC3_OEVTEN, DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT | DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT); }
static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) { enum usb_device_state state = dwc->gadget.state; u32 cfg; int ret; u32 reg; dwc->start_config_issued = false; cfg = le16_to_cpu(ctrl->wValue); switch (state) { case USB_STATE_DEFAULT: return -EINVAL; break; case USB_STATE_ADDRESS: ret = dwc3_ep0_delegate_req(dwc, ctrl); /* if the cfg matches and the cfg is non zero */ if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) { usb_gadget_set_state(&dwc->gadget, USB_STATE_CONFIGURED); /* * Enable transition to U1/U2 state when * nothing is pending from application. */ if (!dwc->is_ebc) { reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA); dwc3_writel(dwc->regs, DWC3_DCTL, reg); } dwc->resize_fifos = true; dev_dbg(dwc->dev, "resize fifos flag SET\n"); } break; case USB_STATE_CONFIGURED: ret = dwc3_ep0_delegate_req(dwc, ctrl); if (!cfg) usb_gadget_set_state(&dwc->gadget, USB_STATE_ADDRESS); break; default: ret = -EINVAL; } return ret; }
/** * dwc3_otg_reset - reset dwc3 otg registers. * * @dotg: Pointer to dwc3 otg context structure. */ static void dwc3_otg_reset(struct dwc3_otg *dotg) { /* * OCFG[2] - OTG-Version = 0 * OCFG[1] - HNPCap = 0 * OCFG[0] - SRPCap = 0 */ dwc3_writel(dotg->regs, DWC3_OCFG, 0x0); /* * OCTL[6] - PeriMode = 1 * OCTL[5] - PrtPwrCtl = 0 * OCTL[4] - HNPReq = 0 * OCTL[3] - SesReq = 0 * OCTL[2] - TermSelDLPulse = 0 * OCTL[1] - DevSetHNPEn = 0 * OCTL[0] - HstSetHNPEn = 0 */ dwc3_writel(dotg->regs, DWC3_OCTL, DWC3_OTG_OCTL_PERIMODE); /* Clear all otg events (interrupts) indications */ dwc3_writel(dotg->regs, DWC3_OEVT, DWC3_OEVT_CLEAR_ALL); }
/** * dwc3_core_init - Low-level initialization of DWC3 Core * @dwc: Pointer to our controller context structure * * Returns 0 on success otherwise negative errno. */ int dwc3_core_init(struct dwc3 *dwc) { unsigned long timeout; u32 reg; int ret; reg = dwc3_readl(dwc->regs, DWC3_GSNPSID); /* This should read as U3 followed by revision number */ if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) { dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); ret = -ENODEV; goto err0; } dwc->revision = reg & DWC3_GSNPSREV_MASK; dwc3_core_soft_reset(dwc); /* issue device SoftReset too */ timeout = jiffies + msecs_to_jiffies(500); dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST); do { reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (!(reg & DWC3_DCTL_CSFTRST)) break; if (time_after(jiffies, timeout)) { dev_err(dwc->dev, "Reset Timed Out\n"); ret = -ETIMEDOUT; goto err0; } cpu_relax(); } while (true); ret = dwc3_event_buffers_setup(dwc); if (ret) { dev_err(dwc->dev, "failed to setup event buffers\n"); goto err0; } dwc3_cache_hwparams(dwc); return 0; err0: return ret; }
static int dwc3_resume(struct device *dev) { struct dwc3 *dwc = dev_get_drvdata(dev); unsigned long flags; int ret; /* Check if platform glue driver handling PM, if not then handle here */ if(!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT)) return 0; ret = usb_phy_init(dwc->usb3_phy); if (ret) { pr_err("%s: usb_phy_init(dwc->usb3_phy) returned %d\n", __func__, ret); return ret; } ret = usb_phy_init(dwc->usb2_phy); if (ret) { pr_err("%s: usb_phy_init(dwc->usb2_phy) returned %d\n", __func__, ret); return ret; } msleep(100); spin_lock_irqsave(&dwc->lock, flags); dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl); switch (dwc->mode) { case DWC3_MODE_DEVICE: case DWC3_MODE_DRD: dwc3_gadget_resume(dwc); /* FALLTHROUGH */ case DWC3_MODE_HOST: default: /* do nothing */ break; } spin_unlock_irqrestore(&dwc->lock, flags); pm_runtime_disable(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); return 0; }
static int dwc3_resume(struct device *dev) { struct dwc3 *dwc = dev_get_drvdata(dev); unsigned long flags; int ret; pinctrl_pm_select_default_state(dev); usb_phy_init(dwc->usb3_phy); usb_phy_init(dwc->usb2_phy); ret = phy_init(dwc->usb2_generic_phy); if (ret < 0) return ret; ret = phy_init(dwc->usb3_generic_phy); if (ret < 0) goto err_usb2phy_init; spin_lock_irqsave(&dwc->lock, flags); dwc3_event_buffers_setup(dwc); dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl); switch (dwc->dr_mode) { case USB_DR_MODE_PERIPHERAL: case USB_DR_MODE_OTG: dwc3_gadget_resume(dwc); /* FALLTHROUGH */ case USB_DR_MODE_HOST: default: /* do nothing */ break; } spin_unlock_irqrestore(&dwc->lock, flags); pm_runtime_disable(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); return 0; err_usb2phy_init: phy_exit(dwc->usb2_generic_phy); return ret; }
/** * dwc3_otg_interrupt - interrupt handler for dwc3 otg events. * @_dotg: Pointer to out controller context structure * * Returns IRQ_HANDLED on success otherwise IRQ_NONE. */ static irqreturn_t dwc3_otg_interrupt(int irq, void *_dotg) { struct dwc3_otg *dotg = (struct dwc3_otg *)_dotg; u32 osts, oevt_reg; int ret = IRQ_NONE; int handled_irqs = 0; oevt_reg = dwc3_readl(dotg->regs, DWC3_OEVT); if (!(oevt_reg & DWC3_OEVT_MASK)) return IRQ_NONE; osts = dwc3_readl(dotg->regs, DWC3_OSTS); if ((oevt_reg & DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT) || (oevt_reg & DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT)) { /* * ID sts has changed, set inputs later, in the workqueue * function, switch from A to B or from B to A. */ if (osts & DWC3_OTG_OSTS_CONIDSTS) set_bit(ID, &dotg->inputs); else clear_bit(ID, &dotg->inputs); if (osts & DWC3_OTG_OSTS_BSESVALID) set_bit(B_SESS_VLD, &dotg->inputs); else clear_bit(B_SESS_VLD, &dotg->inputs); schedule_work(&dotg->sm_work); handled_irqs |= (oevt_reg & DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT) ? DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT : 0; handled_irqs |= (oevt_reg & DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT) ? DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT : 0; ret = IRQ_HANDLED; /* Clear the interrupts we handled */ dwc3_writel(dotg->regs, DWC3_OEVT, handled_irqs); } return ret; }
static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) { u32 cfg; int ret; #ifndef CONFIG_PANTECH_SIO_TEMP u32 reg; #endif dwc->start_config_issued = false; cfg = le16_to_cpu(ctrl->wValue); switch (dwc->dev_state) { case DWC3_DEFAULT_STATE: return -EINVAL; break; case DWC3_ADDRESS_STATE: ret = dwc3_ep0_delegate_req(dwc, ctrl); /* if the cfg matches and the cfg is non zero */ if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) { dwc->dev_state = DWC3_CONFIGURED_STATE; #ifndef CONFIG_PANTECH_SIO_TEMP /* * Enable transition to U1/U2 state when * nothing is pending from application. */ reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA); dwc3_writel(dwc->regs, DWC3_DCTL, reg); #endif dwc->resize_fifos = true; dev_dbg(dwc->dev, "resize fifos flag SET\n"); } break; case DWC3_CONFIGURED_STATE: ret = dwc3_ep0_delegate_req(dwc, ctrl); if (!cfg) dwc->dev_state = DWC3_ADDRESS_STATE; break; default: ret = -EINVAL; } return ret; }
/** * dwc3_core_soft_reset - Issues core soft reset and PHY reset * @dwc: pointer to our context structure */ static int dwc3_core_soft_reset(struct dwc3 *dwc) { u32 reg; int ret; /* Before Resetting PHY, put Core in Reset */ reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg |= DWC3_GCTL_CORESOFTRESET; dwc3_writel(dwc->regs, DWC3_GCTL, reg); /* Assert USB3 PHY reset */ reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST; dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); /* Assert USB2 PHY reset */ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); usb_phy_init(dwc->usb2_phy); usb_phy_init(dwc->usb3_phy); ret = phy_init(dwc->usb2_generic_phy); if (ret < 0) return ret; ret = phy_init(dwc->usb3_generic_phy); if (ret < 0) { phy_exit(dwc->usb2_generic_phy); return ret; } mdelay(100); /* Clear USB3 PHY reset */ reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST; dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); /* Clear USB2 PHY reset */ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); mdelay(100); /* After PHYs are stable we can take Core out of reset state */ reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg &= ~DWC3_GCTL_CORESOFTRESET; dwc3_writel(dwc->regs, DWC3_GCTL, reg); return 0; }
/** * Peforms core soft reset and PHY soft reset of HS and SS PHYs. * If used as a part of POR or init sequence it is recommended * that we should perform hard reset and init of the PHYs prior * to invoking this function. * @dwc: pointer to our context structure */ static void dwc3_core_and_phy_soft_reset(struct dwc3 *dwc) { u32 reg; /* Before Resetting PHY, put Core in Reset */ reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg |= DWC3_GCTL_CORESOFTRESET; dwc3_writel(dwc->regs, DWC3_GCTL, reg); /* Assert USB3 PHY reset */ reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST; dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); usleep_range(1000, 1200); /* Clear USB3 PHY reset */ reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST; dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); reg &= ~DWC3_GUSB3PIPECTL_DELAYP1TRANS; dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); /* Assert USB2 PHY reset */ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); usleep_range(1000, 1200); /* Clear USB2 PHY reset */ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); usleep_range(200, 500); /* After PHYs are stable we can take Core out of reset state */ reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg &= ~DWC3_GCTL_CORESOFTRESET; dwc3_writel(dwc->regs, DWC3_GCTL, reg); usleep_range(1000, 1200); }
static int dwc3_ep0_handle_u1(struct dwc3 *dwc, enum usb_device_state state, int set) { u32 reg; if (state != USB_STATE_CONFIGURED) return -EINVAL; if ((dwc->speed != DWC3_DSTS_SUPERSPEED) && (dwc->speed != DWC3_DSTS_SUPERSPEED_PLUS)) return -EINVAL; reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (set) reg |= DWC3_DCTL_INITU1ENA; else reg &= ~DWC3_DCTL_INITU1ENA; dwc3_writel(dwc->regs, DWC3_DCTL, reg); return 0; }
/* * dwc3_frame_length_adjustment - Adjusts frame length if required * @dwc3: Pointer to our controller context structure */ static void dwc3_frame_length_adjustment(struct dwc3 *dwc) { u32 reg; u32 dft; if (dwc->revision < DWC3_REVISION_250A) return; if (dwc->fladj == 0) return; reg = dwc3_readl(dwc->regs, DWC3_GFLADJ); dft = reg & DWC3_GFLADJ_30MHZ_MASK; if (!dev_WARN_ONCE(dwc->dev, dft == dwc->fladj, "request value same as default, ignoring\n")) { reg &= ~DWC3_GFLADJ_30MHZ_MASK; reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | dwc->fladj; dwc3_writel(dwc->regs, DWC3_GFLADJ, reg); } }
/** * dwc3_core_soft_reset - Issues core soft reset and PHY reset * @dwc: pointer to our context structure */ static void dwc3_core_soft_reset(struct dwc3 *dwc) { u32 reg; if (dwc->core_reset_after_phy_init) return dwc3_core_soft_reset_after_phy_init(dwc); /* Before Resetting PHY, put Core in Reset */ reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg |= DWC3_GCTL_CORESOFTRESET; dwc3_writel(dwc->regs, DWC3_GCTL, reg); /* Bring up PHYs */ usb_phy_init(dwc->usb2_phy); usb_phy_init(dwc->usb3_phy); dwc3_notify_event(dwc, DWC3_CONTROLLER_RESET_EVENT); /* Assert USB3 PHY reset */ reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST; dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); /* Assert USB2 PHY reset */ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); mdelay(100); /* Clear USB3 PHY reset */ reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST; dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); /* Clear USB2 PHY reset */ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); mdelay(100); /* After PHYs are stable we can take Core out of reset state */ reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg &= ~DWC3_GCTL_CORESOFTRESET; dwc3_writel(dwc->regs, DWC3_GCTL, reg); dwc3_notify_event(dwc, DWC3_CONTROLLER_POST_RESET_EVENT); }
static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) { u32 addr; u32 reg; addr = le16_to_cpu(ctrl->wValue); if (addr > 127) return -EINVAL; reg = dwc3_readl(dwc->regs, DWC3_DCFG); reg &= ~(DWC3_DCFG_DEVADDR_MASK); reg |= DWC3_DCFG_DEVADDR(addr); dwc3_writel(dwc->regs, DWC3_DCFG, reg); if (addr) dwc->dev_state = DWC3_ADDRESS_STATE; else dwc->dev_state = DWC3_DEFAULT_STATE; return 0; }
/** * dwc3_core_soft_reset - Issues core soft reset and PHY reset * @dwc: pointer to our context structure */ static int dwc3_core_soft_reset(struct dwc3 *dwc) { u32 reg; int retries = 1000; int ret; usb_phy_init(dwc->usb2_phy); usb_phy_init(dwc->usb3_phy); ret = phy_init(dwc->usb2_generic_phy); if (ret < 0) return ret; ret = phy_init(dwc->usb3_generic_phy); if (ret < 0) { phy_exit(dwc->usb2_generic_phy); return ret; } /* * We're resetting only the device side because, if we're in host mode, * XHCI driver will reset the host block. If dwc3 was configured for * host-only mode, then we can return early. */ if (dwc->dr_mode == USB_DR_MODE_HOST) return 0; reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg |= DWC3_DCTL_CSFTRST; dwc3_writel(dwc->regs, DWC3_DCTL, reg); do { reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (!(reg & DWC3_DCTL_CSFTRST)) return 0; udelay(1); } while (--retries); return -ETIMEDOUT; }
/** * dwc3_soft_reset - Issue soft reset * @dwc: Pointer to our controller context structure */ static int dwc3_soft_reset(struct dwc3 *dwc) { unsigned long timeout; u32 reg; timeout = jiffies + msecs_to_jiffies(500); dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST); do { reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (!(reg & DWC3_DCTL_CSFTRST)) break; if (time_after(jiffies, timeout)) { dev_err(dwc->dev, "Reset Timed Out\n"); return -ETIMEDOUT; } cpu_relax(); } while (true); return 0; }
static int dwc3_config_soc_bus(struct dwc3 *dwc) { int ret; /* * Check if CCI is enabled for USB. Returns true * if the node has property 'dma-coherent'. Otherwise * returns false. */ if (of_dma_is_coherent(dwc->dev->of_node)) { u32 reg; reg = dwc3_readl(dwc->regs, DWC3_GSBUSCFG0); reg |= DWC3_GSBUSCFG0_DATRDREQINFO | DWC3_GSBUSCFG0_DESRDREQINFO | DWC3_GSBUSCFG0_DATWRREQINFO | DWC3_GSBUSCFG0_DESWRREQINFO; dwc3_writel(dwc->regs, DWC3_GSBUSCFG0, reg); } /* * This routes the usb dma traffic to go through CCI path instead * of reaching DDR directly. This traffic routing is needed to * to make SMMU and CCI work with USB dma. */ if (of_dma_is_coherent(dwc->dev->of_node) || dwc->dev->iommu_group) { ret = dwc3_enable_hw_coherency(dwc->dev); if (ret) return ret; } /* Send struct dwc3 to dwc3-of-simple for configuring VBUS * during suspend/resume */ dwc3_set_simple_data(dwc); return 0; }
static void dwc3_core_soft_reset(struct dwc3 *dwc) { u32 reg; reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg |= DWC3_GCTL_CORESOFTRESET; dwc3_writel(dwc->regs, DWC3_GCTL, reg); dwc3_notify_event(dwc, DWC3_CONTROLLER_RESET_EVENT); reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST; dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); mdelay(10); reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST; dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); mdelay(10); reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg &= ~DWC3_GCTL_CORESOFTRESET; dwc3_writel(dwc->regs, DWC3_GCTL, reg); dwc3_notify_event(dwc, DWC3_CONTROLLER_POST_RESET_EVENT); }
/** * dwc3_core_soft_reset - Issues core soft reset and PHY reset * @dwc: pointer to our context structure */ static void dwc3_core_soft_reset(struct dwc3 *dwc) { u32 reg; /* Before Resetting PHY, put Core in Reset */ reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg |= DWC3_GCTL_CORESOFTRESET; dwc3_writel(dwc->regs, DWC3_GCTL, reg); /* Assert USB3 PHY reset */ reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST; dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); /* Assert USB2 PHY reset */ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); //usb_phy_init(dwc->usb3_phy); dwc_usb3_phy_init(); mdelay(100); /* Clear USB3 PHY reset */ reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST; dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); /* Clear USB2 PHY reset */ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); mdelay(100); /* After PHYs are stable we can take Core out of reset state */ reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg &= ~DWC3_GCTL_CORESOFTRESET; dwc3_writel(dwc->regs, DWC3_GCTL, reg); }