/* set/clear the stall and toggle bits for non-ep0 */ void mtu3_ep_stall_set(struct mtu3_ep *mep, bool set) { struct mtu3 *mtu = mep->mtu; void __iomem *mbase = mtu->mac_base; u8 epnum = mep->epnum; u32 csr; if (mep->is_in) { /* TX */ csr = mtu3_readl(mbase, MU3D_EP_TXCR0(epnum)) & TX_W1C_BITS; if (set) csr |= TX_SENDSTALL; else csr = (csr & (~TX_SENDSTALL)) | TX_SENTSTALL; mtu3_writel(mbase, MU3D_EP_TXCR0(epnum), csr); } else { /* RX */ csr = mtu3_readl(mbase, MU3D_EP_RXCR0(epnum)) & RX_W1C_BITS; if (set) csr |= RX_SENDSTALL; else csr = (csr & (~RX_SENDSTALL)) | RX_SENTSTALL; mtu3_writel(mbase, MU3D_EP_RXCR0(epnum), csr); } if (!set) { mtu3_ep_reset(mep); mep->flags &= ~MTU3_EP_STALL; } else { mep->flags |= MTU3_EP_STALL; } dev_dbg(mtu->dev, "%s: %s\n", mep->name, set ? "SEND STALL" : "CLEAR STALL, with EP RESET"); }
/* 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 {
/* only port0 supports dual-role mode */ static int ssusb_port0_switch(struct ssusb_mtk *ssusb, int version, bool tohost) { void __iomem *ibase = ssusb->ippc_base; u32 value; dev_dbg(ssusb->dev, "%s (switch u%d port0 to %s)\n", __func__, version, tohost ? "host" : "device"); if (version == USB2_PORT) { /* 1. power off and disable u2 port0 */ value = mtu3_readl(ibase, SSUSB_U2_CTRL(0)); value |= SSUSB_U2_PORT_PDN | SSUSB_U2_PORT_DIS; mtu3_writel(ibase, SSUSB_U2_CTRL(0), value); /* 2. power on, enable u2 port0 and select its mode */ value = mtu3_readl(ibase, SSUSB_U2_CTRL(0)); value &= ~(SSUSB_U2_PORT_PDN | SSUSB_U2_PORT_DIS); value = tohost ? (value | SSUSB_U2_PORT_HOST_SEL) : (value & (~SSUSB_U2_PORT_HOST_SEL)); mtu3_writel(ibase, SSUSB_U2_CTRL(0), value); } else { /* 1. power off and disable u3 port0 */ value = mtu3_readl(ibase, SSUSB_U3_CTRL(0)); value |= SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_DIS; mtu3_writel(ibase, SSUSB_U3_CTRL(0), value); /* 2. power on, enable u3 port0 and select its mode */ value = mtu3_readl(ibase, SSUSB_U3_CTRL(0)); value &= ~(SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_DIS); value = tohost ? (value | SSUSB_U3_PORT_HOST_SEL) : (value & (~SSUSB_U3_PORT_HOST_SEL)); mtu3_writel(ibase, SSUSB_U3_CTRL(0), value); } return 0; }
void mtu3_start(struct mtu3 *mtu) { void __iomem *mbase = mtu->mac_base; dev_dbg(mtu->dev, "%s devctl 0x%x\n", __func__, mtu3_readl(mbase, U3D_DEVICE_CONTROL)); mtu3_clrbits(mtu->ippc_base, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN); /* * When disable U2 port, USB2_CSR's register will be reset to * default value after re-enable it again(HS is enabled by default). * So if force mac to work as FS, disable HS function. */ if (mtu->max_speed == USB_SPEED_FULL) mtu3_clrbits(mbase, U3D_POWER_MANAGEMENT, HS_ENABLE); /* Initialize the default interrupts */ mtu3_intr_enable(mtu); mtu->is_active = 1; if (mtu->softconnect) mtu3_dev_on_off(mtu, 1); }