static void toggle_opstate(struct ssusb_mtk *ssusb) { if (!ssusb->otg_switch.is_u3_drd) { mtu3_setbits(ssusb->mac_base, U3D_DEVICE_CONTROL, DC_SESSION); mtu3_setbits(ssusb->mac_base, U3D_POWER_MANAGEMENT, SOFT_CONN); } }
/* only port0 of U2/U3 supports device mode */ static int mtu3_device_enable(struct mtu3 *mtu) { void __iomem *ibase = mtu->ippc_base; u32 check_clk = 0; mtu3_clrbits(ibase, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN); if (mtu->is_u3_ip) { check_clk = SSUSB_U3_MAC_RST_B_STS; mtu3_clrbits(ibase, SSUSB_U3_CTRL(0), (SSUSB_U3_PORT_DIS | SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_HOST_SEL)); } mtu3_clrbits(ibase, SSUSB_U2_CTRL(0), (SSUSB_U2_PORT_DIS | SSUSB_U2_PORT_PDN | SSUSB_U2_PORT_HOST_SEL)); if (mtu->ssusb->dr_mode == USB_DR_MODE_OTG) { mtu3_setbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_OTG_SEL); if (mtu->is_u3_ip) mtu3_setbits(ibase, SSUSB_U3_CTRL(0), SSUSB_U3_PORT_DUAL_MODE); } return ssusb_check_clocks(mtu->ssusb, check_clk); }
static void ssusb_ip_sw_reset(struct ssusb_mtk *ssusb) { /* reset whole ip (xhci & u3d) */ mtu3_setbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST); udelay(1); mtu3_clrbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST); /* * device ip may be powered on in firmware/BROM stage before entering * kernel stage; * power down device ip, otherwise ip-sleep will fail when working as * host only mode */ mtu3_setbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN); }
static void mtu3_device_disable(struct mtu3 *mtu) { void __iomem *ibase = mtu->ippc_base; if (mtu->is_u3_ip) mtu3_setbits(ibase, SSUSB_U3_CTRL(0), (SSUSB_U3_PORT_DIS | SSUSB_U3_PORT_PDN)); mtu3_setbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_DIS | SSUSB_U2_PORT_PDN); if (mtu->ssusb->dr_mode == USB_DR_MODE_OTG) mtu3_clrbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_OTG_SEL); mtu3_setbits(ibase, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN); }
static void ssusb_ip_sw_reset(struct ssusb_mtk *ssusb) { /* reset whole ip (xhci & u3d) */ mtu3_setbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST); udelay(1); mtu3_clrbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST); }
/* reset: u2 - data toggle, u3 - SeqN, flow control status etc */ static void mtu3_ep_reset(struct mtu3_ep *mep) { struct mtu3 *mtu = mep->mtu; u32 rst_bit = EP_RST(mep->is_in, mep->epnum); mtu3_setbits(mtu->mac_base, U3D_EP_RST, rst_bit); mtu3_clrbits(mtu->mac_base, U3D_EP_RST, rst_bit); }
/* reset U3D's device module. */ static void mtu3_device_reset(struct mtu3 *mtu) { void __iomem *ibase = mtu->ippc_base; mtu3_setbits(ibase, U3D_SSUSB_DEV_RST_CTRL, SSUSB_DEV_SW_RST); udelay(1); mtu3_clrbits(ibase, U3D_SSUSB_DEV_RST_CTRL, SSUSB_DEV_SW_RST); }
/* enable/disable U3D SS function */ static inline void mtu3_ss_func_set(struct mtu3 *mtu, bool enable) { /* If usb3_en==0, LTSSM will go to SS.Disable state */ if (enable) mtu3_setbits(mtu->mac_base, U3D_USB3_CONFIG, USB3_EN); else mtu3_clrbits(mtu->mac_base, U3D_USB3_CONFIG, USB3_EN); dev_dbg(mtu->dev, "USB3_EN = %d\n", !!enable); }
/* for non-ep0 */ int mtu3_config_ep(struct mtu3 *mtu, struct mtu3_ep *mep, int interval, int burst, int mult) { void __iomem *mbase = mtu->mac_base; int epnum = mep->epnum; u32 csr0, csr1, csr2; int fifo_sgsz, fifo_addr; int num_pkts; fifo_addr = ep_fifo_alloc(mep, mep->maxp); if (fifo_addr < 0) { dev_err(mtu->dev, "alloc ep fifo failed(%d)\n", mep->maxp); return -ENOMEM; } fifo_sgsz = ilog2(mep->fifo_seg_size); dev_dbg(mtu->dev, "%s fifosz: %x(%x/%x)\n", __func__, fifo_sgsz, mep->fifo_seg_size, mep->fifo_size); if (mep->is_in) { csr0 = TX_TXMAXPKTSZ(mep->maxp); csr0 |= TX_DMAREQEN; num_pkts = (burst + 1) * (mult + 1) - 1; csr1 = TX_SS_BURST(burst) | TX_SLOT(mep->slot); csr1 |= TX_MAX_PKT(num_pkts) | TX_MULT(mult); csr2 = TX_FIFOADDR(fifo_addr >> 4); csr2 |= TX_FIFOSEGSIZE(fifo_sgsz); switch (mep->type) { case USB_ENDPOINT_XFER_BULK: csr1 |= TX_TYPE(TYPE_BULK); break; case USB_ENDPOINT_XFER_ISOC: csr1 |= TX_TYPE(TYPE_ISO); csr2 |= TX_BINTERVAL(interval); break; case USB_ENDPOINT_XFER_INT: csr1 |= TX_TYPE(TYPE_INT); csr2 |= TX_BINTERVAL(interval); break; } /* Enable QMU Done interrupt */ mtu3_setbits(mbase, U3D_QIESR0, QMU_TX_DONE_INT(epnum)); mtu3_writel(mbase, MU3D_EP_TXCR0(epnum), csr0); mtu3_writel(mbase, MU3D_EP_TXCR1(epnum), csr1); mtu3_writel(mbase, MU3D_EP_TXCR2(epnum), csr2); dev_dbg(mtu->dev, "U3D_TX%d CSR0:%#x, CSR1:%#x, CSR2:%#x\n", epnum, mtu3_readl(mbase, MU3D_EP_TXCR0(epnum)), mtu3_readl(mbase, MU3D_EP_TXCR1(epnum)), mtu3_readl(mbase, MU3D_EP_TXCR2(epnum))); } else {
/* set/clear U3D HS device soft connect */ static inline void mtu3_hs_softconn_set(struct mtu3 *mtu, bool enable) { if (enable) { mtu3_setbits(mtu->mac_base, U3D_POWER_MANAGEMENT, SOFT_CONN | SUSPENDM_ENABLE); } else { mtu3_clrbits(mtu->mac_base, U3D_POWER_MANAGEMENT, SOFT_CONN | SUSPENDM_ENABLE); } dev_dbg(mtu->dev, "SOFTCONN = %d\n", !!enable); }
void mtu3_stop(struct mtu3 *mtu) { dev_dbg(mtu->dev, "%s\n", __func__); mtu3_intr_disable(mtu); mtu3_intr_status_clear(mtu); if (mtu->softconnect) mtu3_dev_on_off(mtu, 0); mtu->is_active = 0; mtu3_setbits(mtu->ippc_base, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN); }