/* 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"); }
/* enable system global interrupt */ static void mtu3_intr_enable(struct mtu3 *mtu) { void __iomem *mbase = mtu->mac_base; u32 value; /*Enable level 1 interrupts (BMU, QMU, MAC3, DMA, MAC2, EPCTL) */ value = BMU_INTR | QMU_INTR | MAC3_INTR | MAC2_INTR | EP_CTRL_INTR; mtu3_writel(mbase, U3D_LV1IESR, value); /* Enable U2 common USB interrupts */ value = SUSPEND_INTR | RESUME_INTR | RESET_INTR | LPM_RESUME_INTR; mtu3_writel(mbase, U3D_COMMON_USB_INTR_ENABLE, value); if (mtu->is_u3_ip) { /* Enable U3 LTSSM interrupts */ value = HOT_RST_INTR | WARM_RST_INTR | VBUS_RISE_INTR | VBUS_FALL_INTR | ENTER_U3_INTR | EXIT_U3_INTR; mtu3_writel(mbase, U3D_LTSSM_INTR_ENABLE, value); } /* Enable QMU interrupts. */ value = TXQ_CSERR_INT | TXQ_LENERR_INT | RXQ_CSERR_INT | RXQ_LENERR_INT | RXQ_ZLPERR_INT; mtu3_writel(mbase, U3D_QIESR1, value); /* Enable speed change interrupt */ mtu3_writel(mbase, U3D_DEV_LINK_INTR_ENABLE, SSUSB_DEV_SPEED_CHG_INTR); }
/* disable all interrupts */ static void mtu3_intr_disable(struct mtu3 *mtu) { void __iomem *mbase = mtu->mac_base; /* Disable level 1 interrupts */ mtu3_writel(mbase, U3D_LV1IECR, ~0x0); /* Disable endpoint interrupts */ mtu3_writel(mbase, U3D_EPIECR, ~0x0); }
/* 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 {
static void mtu3_intr_status_clear(struct mtu3 *mtu) { void __iomem *mbase = mtu->mac_base; /* Clear EP0 and Tx/Rx EPn interrupts status */ mtu3_writel(mbase, U3D_EPISR, ~0x0); /* Clear U2 USB common interrupts status */ mtu3_writel(mbase, U3D_COMMON_USB_INTR, ~0x0); /* Clear U3 LTSSM interrupts status */ mtu3_writel(mbase, U3D_LTSSM_INTR, ~0x0); /* Clear speed change interrupt status */ mtu3_writel(mbase, U3D_DEV_LINK_INTR, ~0x0); }
/* 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; }