1df2069acSChunfeng Yun /* 2df2069acSChunfeng Yun * mtu3_core.c - hardware access layer and gadget init/exit of 3df2069acSChunfeng Yun * MediaTek usb3 Dual-Role Controller Driver 4df2069acSChunfeng Yun * 5df2069acSChunfeng Yun * Copyright (C) 2016 MediaTek Inc. 6df2069acSChunfeng Yun * 7df2069acSChunfeng Yun * Author: Chunfeng Yun <chunfeng.yun@mediatek.com> 8df2069acSChunfeng Yun * 9df2069acSChunfeng Yun * This software is licensed under the terms of the GNU General Public 10df2069acSChunfeng Yun * License version 2, as published by the Free Software Foundation, and 11df2069acSChunfeng Yun * may be copied, distributed, and modified under those terms. 12df2069acSChunfeng Yun * 13df2069acSChunfeng Yun * This program is distributed in the hope that it will be useful, 14df2069acSChunfeng Yun * but WITHOUT ANY WARRANTY; without even the implied warranty of 15df2069acSChunfeng Yun * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16df2069acSChunfeng Yun * GNU General Public License for more details. 17df2069acSChunfeng Yun * 18df2069acSChunfeng Yun */ 19df2069acSChunfeng Yun 201a46dfeaSChunfeng Yun #include <linux/dma-mapping.h> 21df2069acSChunfeng Yun #include <linux/kernel.h> 22df2069acSChunfeng Yun #include <linux/module.h> 23df2069acSChunfeng Yun #include <linux/of_address.h> 24df2069acSChunfeng Yun #include <linux/of_irq.h> 25df2069acSChunfeng Yun #include <linux/platform_device.h> 26df2069acSChunfeng Yun 27df2069acSChunfeng Yun #include "mtu3.h" 28df2069acSChunfeng Yun 29df2069acSChunfeng Yun static int ep_fifo_alloc(struct mtu3_ep *mep, u32 seg_size) 30df2069acSChunfeng Yun { 31df2069acSChunfeng Yun struct mtu3_fifo_info *fifo = mep->fifo; 32df2069acSChunfeng Yun u32 num_bits = DIV_ROUND_UP(seg_size, MTU3_EP_FIFO_UNIT); 33df2069acSChunfeng Yun u32 start_bit; 34df2069acSChunfeng Yun 35df2069acSChunfeng Yun /* ensure that @mep->fifo_seg_size is power of two */ 36df2069acSChunfeng Yun num_bits = roundup_pow_of_two(num_bits); 37df2069acSChunfeng Yun if (num_bits > fifo->limit) 38df2069acSChunfeng Yun return -EINVAL; 39df2069acSChunfeng Yun 40df2069acSChunfeng Yun mep->fifo_seg_size = num_bits * MTU3_EP_FIFO_UNIT; 41df2069acSChunfeng Yun num_bits = num_bits * (mep->slot + 1); 42df2069acSChunfeng Yun start_bit = bitmap_find_next_zero_area(fifo->bitmap, 43df2069acSChunfeng Yun fifo->limit, 0, num_bits, 0); 44df2069acSChunfeng Yun if (start_bit >= fifo->limit) 45df2069acSChunfeng Yun return -EOVERFLOW; 46df2069acSChunfeng Yun 47df2069acSChunfeng Yun bitmap_set(fifo->bitmap, start_bit, num_bits); 48df2069acSChunfeng Yun mep->fifo_size = num_bits * MTU3_EP_FIFO_UNIT; 49df2069acSChunfeng Yun mep->fifo_addr = fifo->base + MTU3_EP_FIFO_UNIT * start_bit; 50df2069acSChunfeng Yun 51df2069acSChunfeng Yun dev_dbg(mep->mtu->dev, "%s fifo:%#x/%#x, start_bit: %d\n", 52df2069acSChunfeng Yun __func__, mep->fifo_seg_size, mep->fifo_size, start_bit); 53df2069acSChunfeng Yun 54df2069acSChunfeng Yun return mep->fifo_addr; 55df2069acSChunfeng Yun } 56df2069acSChunfeng Yun 57df2069acSChunfeng Yun static void ep_fifo_free(struct mtu3_ep *mep) 58df2069acSChunfeng Yun { 59df2069acSChunfeng Yun struct mtu3_fifo_info *fifo = mep->fifo; 60df2069acSChunfeng Yun u32 addr = mep->fifo_addr; 61df2069acSChunfeng Yun u32 bits = mep->fifo_size / MTU3_EP_FIFO_UNIT; 62df2069acSChunfeng Yun u32 start_bit; 63df2069acSChunfeng Yun 64df2069acSChunfeng Yun if (unlikely(addr < fifo->base || bits > fifo->limit)) 65df2069acSChunfeng Yun return; 66df2069acSChunfeng Yun 67df2069acSChunfeng Yun start_bit = (addr - fifo->base) / MTU3_EP_FIFO_UNIT; 68df2069acSChunfeng Yun bitmap_clear(fifo->bitmap, start_bit, bits); 69df2069acSChunfeng Yun mep->fifo_size = 0; 70df2069acSChunfeng Yun mep->fifo_seg_size = 0; 71df2069acSChunfeng Yun 72df2069acSChunfeng Yun dev_dbg(mep->mtu->dev, "%s size:%#x/%#x, start_bit: %d\n", 73df2069acSChunfeng Yun __func__, mep->fifo_seg_size, mep->fifo_size, start_bit); 74df2069acSChunfeng Yun } 75df2069acSChunfeng Yun 76a29de31bSChunfeng Yun /* enable/disable U3D SS function */ 77a29de31bSChunfeng Yun static inline void mtu3_ss_func_set(struct mtu3 *mtu, bool enable) 78a29de31bSChunfeng Yun { 79a29de31bSChunfeng Yun /* If usb3_en==0, LTSSM will go to SS.Disable state */ 80a29de31bSChunfeng Yun if (enable) 81a29de31bSChunfeng Yun mtu3_setbits(mtu->mac_base, U3D_USB3_CONFIG, USB3_EN); 82a29de31bSChunfeng Yun else 83a29de31bSChunfeng Yun mtu3_clrbits(mtu->mac_base, U3D_USB3_CONFIG, USB3_EN); 84a29de31bSChunfeng Yun 85a29de31bSChunfeng Yun dev_dbg(mtu->dev, "USB3_EN = %d\n", !!enable); 86a29de31bSChunfeng Yun } 87a29de31bSChunfeng Yun 88df2069acSChunfeng Yun /* set/clear U3D HS device soft connect */ 89a29de31bSChunfeng Yun static inline void mtu3_hs_softconn_set(struct mtu3 *mtu, bool enable) 90df2069acSChunfeng Yun { 91df2069acSChunfeng Yun if (enable) { 92df2069acSChunfeng Yun mtu3_setbits(mtu->mac_base, U3D_POWER_MANAGEMENT, 93df2069acSChunfeng Yun SOFT_CONN | SUSPENDM_ENABLE); 94df2069acSChunfeng Yun } else { 95df2069acSChunfeng Yun mtu3_clrbits(mtu->mac_base, U3D_POWER_MANAGEMENT, 96df2069acSChunfeng Yun SOFT_CONN | SUSPENDM_ENABLE); 97df2069acSChunfeng Yun } 98df2069acSChunfeng Yun dev_dbg(mtu->dev, "SOFTCONN = %d\n", !!enable); 99df2069acSChunfeng Yun } 100df2069acSChunfeng Yun 101df2069acSChunfeng Yun /* only port0 of U2/U3 supports device mode */ 102df2069acSChunfeng Yun static int mtu3_device_enable(struct mtu3 *mtu) 103df2069acSChunfeng Yun { 104df2069acSChunfeng Yun void __iomem *ibase = mtu->ippc_base; 105df2069acSChunfeng Yun u32 check_clk = 0; 106df2069acSChunfeng Yun 107df2069acSChunfeng Yun mtu3_clrbits(ibase, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN); 108a29de31bSChunfeng Yun 109a29de31bSChunfeng Yun if (mtu->is_u3_ip) { 110a29de31bSChunfeng Yun check_clk = SSUSB_U3_MAC_RST_B_STS; 111a29de31bSChunfeng Yun mtu3_clrbits(ibase, SSUSB_U3_CTRL(0), 112a29de31bSChunfeng Yun (SSUSB_U3_PORT_DIS | SSUSB_U3_PORT_PDN | 113a29de31bSChunfeng Yun SSUSB_U3_PORT_HOST_SEL)); 114a29de31bSChunfeng Yun } 115df2069acSChunfeng Yun mtu3_clrbits(ibase, SSUSB_U2_CTRL(0), 116df2069acSChunfeng Yun (SSUSB_U2_PORT_DIS | SSUSB_U2_PORT_PDN | 117df2069acSChunfeng Yun SSUSB_U2_PORT_HOST_SEL)); 118df2069acSChunfeng Yun mtu3_setbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_OTG_SEL); 119df2069acSChunfeng Yun 120b3f4e727SChunfeng Yun return ssusb_check_clocks(mtu->ssusb, check_clk); 121df2069acSChunfeng Yun } 122df2069acSChunfeng Yun 123df2069acSChunfeng Yun static void mtu3_device_disable(struct mtu3 *mtu) 124df2069acSChunfeng Yun { 125df2069acSChunfeng Yun void __iomem *ibase = mtu->ippc_base; 126df2069acSChunfeng Yun 127a29de31bSChunfeng Yun if (mtu->is_u3_ip) 128a29de31bSChunfeng Yun mtu3_setbits(ibase, SSUSB_U3_CTRL(0), 129a29de31bSChunfeng Yun (SSUSB_U3_PORT_DIS | SSUSB_U3_PORT_PDN)); 130a29de31bSChunfeng Yun 131df2069acSChunfeng Yun mtu3_setbits(ibase, SSUSB_U2_CTRL(0), 132df2069acSChunfeng Yun SSUSB_U2_PORT_DIS | SSUSB_U2_PORT_PDN); 133df2069acSChunfeng Yun mtu3_clrbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_OTG_SEL); 134df2069acSChunfeng Yun mtu3_setbits(ibase, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN); 135df2069acSChunfeng Yun } 136df2069acSChunfeng Yun 137df2069acSChunfeng Yun /* reset U3D's device module. */ 138df2069acSChunfeng Yun static void mtu3_device_reset(struct mtu3 *mtu) 139df2069acSChunfeng Yun { 140df2069acSChunfeng Yun void __iomem *ibase = mtu->ippc_base; 141df2069acSChunfeng Yun 142df2069acSChunfeng Yun mtu3_setbits(ibase, U3D_SSUSB_DEV_RST_CTRL, SSUSB_DEV_SW_RST); 143df2069acSChunfeng Yun udelay(1); 144df2069acSChunfeng Yun mtu3_clrbits(ibase, U3D_SSUSB_DEV_RST_CTRL, SSUSB_DEV_SW_RST); 145df2069acSChunfeng Yun } 146df2069acSChunfeng Yun 147df2069acSChunfeng Yun /* disable all interrupts */ 148df2069acSChunfeng Yun static void mtu3_intr_disable(struct mtu3 *mtu) 149df2069acSChunfeng Yun { 150df2069acSChunfeng Yun void __iomem *mbase = mtu->mac_base; 151df2069acSChunfeng Yun 152df2069acSChunfeng Yun /* Disable level 1 interrupts */ 153df2069acSChunfeng Yun mtu3_writel(mbase, U3D_LV1IECR, ~0x0); 154df2069acSChunfeng Yun /* Disable endpoint interrupts */ 155df2069acSChunfeng Yun mtu3_writel(mbase, U3D_EPIECR, ~0x0); 156df2069acSChunfeng Yun } 157df2069acSChunfeng Yun 158df2069acSChunfeng Yun static void mtu3_intr_status_clear(struct mtu3 *mtu) 159df2069acSChunfeng Yun { 160df2069acSChunfeng Yun void __iomem *mbase = mtu->mac_base; 161df2069acSChunfeng Yun 162df2069acSChunfeng Yun /* Clear EP0 and Tx/Rx EPn interrupts status */ 163df2069acSChunfeng Yun mtu3_writel(mbase, U3D_EPISR, ~0x0); 164df2069acSChunfeng Yun /* Clear U2 USB common interrupts status */ 165df2069acSChunfeng Yun mtu3_writel(mbase, U3D_COMMON_USB_INTR, ~0x0); 166a29de31bSChunfeng Yun /* Clear U3 LTSSM interrupts status */ 167a29de31bSChunfeng Yun mtu3_writel(mbase, U3D_LTSSM_INTR, ~0x0); 168df2069acSChunfeng Yun /* Clear speed change interrupt status */ 169df2069acSChunfeng Yun mtu3_writel(mbase, U3D_DEV_LINK_INTR, ~0x0); 170df2069acSChunfeng Yun } 171df2069acSChunfeng Yun 172df2069acSChunfeng Yun /* enable system global interrupt */ 173df2069acSChunfeng Yun static void mtu3_intr_enable(struct mtu3 *mtu) 174df2069acSChunfeng Yun { 175df2069acSChunfeng Yun void __iomem *mbase = mtu->mac_base; 176df2069acSChunfeng Yun u32 value; 177df2069acSChunfeng Yun 178df2069acSChunfeng Yun /*Enable level 1 interrupts (BMU, QMU, MAC3, DMA, MAC2, EPCTL) */ 179a29de31bSChunfeng Yun value = BMU_INTR | QMU_INTR | MAC3_INTR | MAC2_INTR | EP_CTRL_INTR; 180df2069acSChunfeng Yun mtu3_writel(mbase, U3D_LV1IESR, value); 181df2069acSChunfeng Yun 182df2069acSChunfeng Yun /* Enable U2 common USB interrupts */ 183df2069acSChunfeng Yun value = SUSPEND_INTR | RESUME_INTR | RESET_INTR; 184df2069acSChunfeng Yun mtu3_writel(mbase, U3D_COMMON_USB_INTR_ENABLE, value); 185df2069acSChunfeng Yun 186a29de31bSChunfeng Yun if (mtu->is_u3_ip) { 187a29de31bSChunfeng Yun /* Enable U3 LTSSM interrupts */ 188a29de31bSChunfeng Yun value = HOT_RST_INTR | WARM_RST_INTR | VBUS_RISE_INTR | 189a29de31bSChunfeng Yun VBUS_FALL_INTR | ENTER_U3_INTR | EXIT_U3_INTR; 190a29de31bSChunfeng Yun mtu3_writel(mbase, U3D_LTSSM_INTR_ENABLE, value); 191a29de31bSChunfeng Yun } 192a29de31bSChunfeng Yun 193df2069acSChunfeng Yun /* Enable QMU interrupts. */ 194df2069acSChunfeng Yun value = TXQ_CSERR_INT | TXQ_LENERR_INT | RXQ_CSERR_INT | 195df2069acSChunfeng Yun RXQ_LENERR_INT | RXQ_ZLPERR_INT; 196df2069acSChunfeng Yun mtu3_writel(mbase, U3D_QIESR1, value); 197df2069acSChunfeng Yun 198df2069acSChunfeng Yun /* Enable speed change interrupt */ 199df2069acSChunfeng Yun mtu3_writel(mbase, U3D_DEV_LINK_INTR_ENABLE, SSUSB_DEV_SPEED_CHG_INTR); 200df2069acSChunfeng Yun } 201df2069acSChunfeng Yun 202df2069acSChunfeng Yun /* set/clear the stall and toggle bits for non-ep0 */ 203df2069acSChunfeng Yun void mtu3_ep_stall_set(struct mtu3_ep *mep, bool set) 204df2069acSChunfeng Yun { 205df2069acSChunfeng Yun struct mtu3 *mtu = mep->mtu; 206df2069acSChunfeng Yun void __iomem *mbase = mtu->mac_base; 207df2069acSChunfeng Yun u8 epnum = mep->epnum; 208df2069acSChunfeng Yun u32 csr; 209df2069acSChunfeng Yun 210df2069acSChunfeng Yun if (mep->is_in) { /* TX */ 211df2069acSChunfeng Yun csr = mtu3_readl(mbase, MU3D_EP_TXCR0(epnum)) & TX_W1C_BITS; 212df2069acSChunfeng Yun if (set) 213df2069acSChunfeng Yun csr |= TX_SENDSTALL; 214df2069acSChunfeng Yun else 215df2069acSChunfeng Yun csr = (csr & (~TX_SENDSTALL)) | TX_SENTSTALL; 216df2069acSChunfeng Yun mtu3_writel(mbase, MU3D_EP_TXCR0(epnum), csr); 217df2069acSChunfeng Yun } else { /* RX */ 218df2069acSChunfeng Yun csr = mtu3_readl(mbase, MU3D_EP_RXCR0(epnum)) & RX_W1C_BITS; 219df2069acSChunfeng Yun if (set) 220df2069acSChunfeng Yun csr |= RX_SENDSTALL; 221df2069acSChunfeng Yun else 222df2069acSChunfeng Yun csr = (csr & (~RX_SENDSTALL)) | RX_SENTSTALL; 223df2069acSChunfeng Yun mtu3_writel(mbase, MU3D_EP_RXCR0(epnum), csr); 224df2069acSChunfeng Yun } 225df2069acSChunfeng Yun 226df2069acSChunfeng Yun if (!set) { 227df2069acSChunfeng Yun mtu3_setbits(mbase, U3D_EP_RST, EP_RST(mep->is_in, epnum)); 228df2069acSChunfeng Yun mtu3_clrbits(mbase, U3D_EP_RST, EP_RST(mep->is_in, epnum)); 229df2069acSChunfeng Yun mep->flags &= ~MTU3_EP_STALL; 230df2069acSChunfeng Yun } else { 231df2069acSChunfeng Yun mep->flags |= MTU3_EP_STALL; 232df2069acSChunfeng Yun } 233df2069acSChunfeng Yun 234df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s: %s\n", mep->name, 235df2069acSChunfeng Yun set ? "SEND STALL" : "CLEAR STALL, with EP RESET"); 236df2069acSChunfeng Yun } 237df2069acSChunfeng Yun 238a29de31bSChunfeng Yun void mtu3_dev_on_off(struct mtu3 *mtu, int is_on) 239a29de31bSChunfeng Yun { 2404d79e042SChunfeng Yun if (mtu->is_u3_ip && mtu->max_speed >= USB_SPEED_SUPER) 241a29de31bSChunfeng Yun mtu3_ss_func_set(mtu, is_on); 242a29de31bSChunfeng Yun else 243a29de31bSChunfeng Yun mtu3_hs_softconn_set(mtu, is_on); 244a29de31bSChunfeng Yun 245a29de31bSChunfeng Yun dev_info(mtu->dev, "gadget (%s) pullup D%s\n", 246a29de31bSChunfeng Yun usb_speed_string(mtu->max_speed), is_on ? "+" : "-"); 247a29de31bSChunfeng Yun } 248a29de31bSChunfeng Yun 249df2069acSChunfeng Yun void mtu3_start(struct mtu3 *mtu) 250df2069acSChunfeng Yun { 251df2069acSChunfeng Yun void __iomem *mbase = mtu->mac_base; 252df2069acSChunfeng Yun 253df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s devctl 0x%x\n", __func__, 254df2069acSChunfeng Yun mtu3_readl(mbase, U3D_DEVICE_CONTROL)); 255df2069acSChunfeng Yun 256df2069acSChunfeng Yun mtu3_clrbits(mtu->ippc_base, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN); 257df2069acSChunfeng Yun 258a29de31bSChunfeng Yun /* 259a29de31bSChunfeng Yun * When disable U2 port, USB2_CSR's register will be reset to 260a29de31bSChunfeng Yun * default value after re-enable it again(HS is enabled by default). 261a29de31bSChunfeng Yun * So if force mac to work as FS, disable HS function. 262a29de31bSChunfeng Yun */ 263a29de31bSChunfeng Yun if (mtu->max_speed == USB_SPEED_FULL) 264a29de31bSChunfeng Yun mtu3_clrbits(mbase, U3D_POWER_MANAGEMENT, HS_ENABLE); 265a29de31bSChunfeng Yun 266df2069acSChunfeng Yun /* Initialize the default interrupts */ 267df2069acSChunfeng Yun mtu3_intr_enable(mtu); 268df2069acSChunfeng Yun mtu->is_active = 1; 269df2069acSChunfeng Yun 270df2069acSChunfeng Yun if (mtu->softconnect) 271a29de31bSChunfeng Yun mtu3_dev_on_off(mtu, 1); 272df2069acSChunfeng Yun } 273df2069acSChunfeng Yun 274df2069acSChunfeng Yun void mtu3_stop(struct mtu3 *mtu) 275df2069acSChunfeng Yun { 276df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s\n", __func__); 277df2069acSChunfeng Yun 278df2069acSChunfeng Yun mtu3_intr_disable(mtu); 279df2069acSChunfeng Yun mtu3_intr_status_clear(mtu); 280df2069acSChunfeng Yun 281df2069acSChunfeng Yun if (mtu->softconnect) 282a29de31bSChunfeng Yun mtu3_dev_on_off(mtu, 0); 283df2069acSChunfeng Yun 284df2069acSChunfeng Yun mtu->is_active = 0; 285df2069acSChunfeng Yun mtu3_setbits(mtu->ippc_base, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN); 286df2069acSChunfeng Yun } 287df2069acSChunfeng Yun 288df2069acSChunfeng Yun /* for non-ep0 */ 289df2069acSChunfeng Yun int mtu3_config_ep(struct mtu3 *mtu, struct mtu3_ep *mep, 290df2069acSChunfeng Yun int interval, int burst, int mult) 291df2069acSChunfeng Yun { 292df2069acSChunfeng Yun void __iomem *mbase = mtu->mac_base; 293df2069acSChunfeng Yun int epnum = mep->epnum; 294df2069acSChunfeng Yun u32 csr0, csr1, csr2; 295df2069acSChunfeng Yun int fifo_sgsz, fifo_addr; 296df2069acSChunfeng Yun int num_pkts; 297df2069acSChunfeng Yun 298df2069acSChunfeng Yun fifo_addr = ep_fifo_alloc(mep, mep->maxp); 299df2069acSChunfeng Yun if (fifo_addr < 0) { 300df2069acSChunfeng Yun dev_err(mtu->dev, "alloc ep fifo failed(%d)\n", mep->maxp); 301df2069acSChunfeng Yun return -ENOMEM; 302df2069acSChunfeng Yun } 303df2069acSChunfeng Yun fifo_sgsz = ilog2(mep->fifo_seg_size); 304df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s fifosz: %x(%x/%x)\n", __func__, fifo_sgsz, 305df2069acSChunfeng Yun mep->fifo_seg_size, mep->fifo_size); 306df2069acSChunfeng Yun 307df2069acSChunfeng Yun if (mep->is_in) { 308df2069acSChunfeng Yun csr0 = TX_TXMAXPKTSZ(mep->maxp); 309df2069acSChunfeng Yun csr0 |= TX_DMAREQEN; 310df2069acSChunfeng Yun 311df2069acSChunfeng Yun num_pkts = (burst + 1) * (mult + 1) - 1; 312df2069acSChunfeng Yun csr1 = TX_SS_BURST(burst) | TX_SLOT(mep->slot); 313df2069acSChunfeng Yun csr1 |= TX_MAX_PKT(num_pkts) | TX_MULT(mult); 314df2069acSChunfeng Yun 315df2069acSChunfeng Yun csr2 = TX_FIFOADDR(fifo_addr >> 4); 316df2069acSChunfeng Yun csr2 |= TX_FIFOSEGSIZE(fifo_sgsz); 317df2069acSChunfeng Yun 318df2069acSChunfeng Yun switch (mep->type) { 319df2069acSChunfeng Yun case USB_ENDPOINT_XFER_BULK: 320df2069acSChunfeng Yun csr1 |= TX_TYPE(TYPE_BULK); 321df2069acSChunfeng Yun break; 322df2069acSChunfeng Yun case USB_ENDPOINT_XFER_ISOC: 323df2069acSChunfeng Yun csr1 |= TX_TYPE(TYPE_ISO); 324df2069acSChunfeng Yun csr2 |= TX_BINTERVAL(interval); 325df2069acSChunfeng Yun break; 326df2069acSChunfeng Yun case USB_ENDPOINT_XFER_INT: 327df2069acSChunfeng Yun csr1 |= TX_TYPE(TYPE_INT); 328df2069acSChunfeng Yun csr2 |= TX_BINTERVAL(interval); 329df2069acSChunfeng Yun break; 330df2069acSChunfeng Yun } 331df2069acSChunfeng Yun 332df2069acSChunfeng Yun /* Enable QMU Done interrupt */ 333df2069acSChunfeng Yun mtu3_setbits(mbase, U3D_QIESR0, QMU_TX_DONE_INT(epnum)); 334df2069acSChunfeng Yun 335df2069acSChunfeng Yun mtu3_writel(mbase, MU3D_EP_TXCR0(epnum), csr0); 336df2069acSChunfeng Yun mtu3_writel(mbase, MU3D_EP_TXCR1(epnum), csr1); 337df2069acSChunfeng Yun mtu3_writel(mbase, MU3D_EP_TXCR2(epnum), csr2); 338df2069acSChunfeng Yun 339df2069acSChunfeng Yun dev_dbg(mtu->dev, "U3D_TX%d CSR0:%#x, CSR1:%#x, CSR2:%#x\n", 340df2069acSChunfeng Yun epnum, mtu3_readl(mbase, MU3D_EP_TXCR0(epnum)), 341df2069acSChunfeng Yun mtu3_readl(mbase, MU3D_EP_TXCR1(epnum)), 342df2069acSChunfeng Yun mtu3_readl(mbase, MU3D_EP_TXCR2(epnum))); 343df2069acSChunfeng Yun } else { 344df2069acSChunfeng Yun csr0 = RX_RXMAXPKTSZ(mep->maxp); 345df2069acSChunfeng Yun csr0 |= RX_DMAREQEN; 346df2069acSChunfeng Yun 347df2069acSChunfeng Yun num_pkts = (burst + 1) * (mult + 1) - 1; 348df2069acSChunfeng Yun csr1 = RX_SS_BURST(burst) | RX_SLOT(mep->slot); 349df2069acSChunfeng Yun csr1 |= RX_MAX_PKT(num_pkts) | RX_MULT(mult); 350df2069acSChunfeng Yun 351df2069acSChunfeng Yun csr2 = RX_FIFOADDR(fifo_addr >> 4); 352df2069acSChunfeng Yun csr2 |= RX_FIFOSEGSIZE(fifo_sgsz); 353df2069acSChunfeng Yun 354df2069acSChunfeng Yun switch (mep->type) { 355df2069acSChunfeng Yun case USB_ENDPOINT_XFER_BULK: 356df2069acSChunfeng Yun csr1 |= RX_TYPE(TYPE_BULK); 357df2069acSChunfeng Yun break; 358df2069acSChunfeng Yun case USB_ENDPOINT_XFER_ISOC: 359df2069acSChunfeng Yun csr1 |= RX_TYPE(TYPE_ISO); 360df2069acSChunfeng Yun csr2 |= RX_BINTERVAL(interval); 361df2069acSChunfeng Yun break; 362df2069acSChunfeng Yun case USB_ENDPOINT_XFER_INT: 363df2069acSChunfeng Yun csr1 |= RX_TYPE(TYPE_INT); 364df2069acSChunfeng Yun csr2 |= RX_BINTERVAL(interval); 365df2069acSChunfeng Yun break; 366df2069acSChunfeng Yun } 367df2069acSChunfeng Yun 368df2069acSChunfeng Yun /*Enable QMU Done interrupt */ 369df2069acSChunfeng Yun mtu3_setbits(mbase, U3D_QIESR0, QMU_RX_DONE_INT(epnum)); 370df2069acSChunfeng Yun 371df2069acSChunfeng Yun mtu3_writel(mbase, MU3D_EP_RXCR0(epnum), csr0); 372df2069acSChunfeng Yun mtu3_writel(mbase, MU3D_EP_RXCR1(epnum), csr1); 373df2069acSChunfeng Yun mtu3_writel(mbase, MU3D_EP_RXCR2(epnum), csr2); 374df2069acSChunfeng Yun 375df2069acSChunfeng Yun dev_dbg(mtu->dev, "U3D_RX%d CSR0:%#x, CSR1:%#x, CSR2:%#x\n", 376df2069acSChunfeng Yun epnum, mtu3_readl(mbase, MU3D_EP_RXCR0(epnum)), 377df2069acSChunfeng Yun mtu3_readl(mbase, MU3D_EP_RXCR1(epnum)), 378df2069acSChunfeng Yun mtu3_readl(mbase, MU3D_EP_RXCR2(epnum))); 379df2069acSChunfeng Yun } 380df2069acSChunfeng Yun 381df2069acSChunfeng Yun dev_dbg(mtu->dev, "csr0:%#x, csr1:%#x, csr2:%#x\n", csr0, csr1, csr2); 382df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s: %s, fifo-addr:%#x, fifo-size:%#x(%#x/%#x)\n", 383df2069acSChunfeng Yun __func__, mep->name, mep->fifo_addr, mep->fifo_size, 384df2069acSChunfeng Yun fifo_sgsz, mep->fifo_seg_size); 385df2069acSChunfeng Yun 386df2069acSChunfeng Yun return 0; 387df2069acSChunfeng Yun } 388df2069acSChunfeng Yun 389df2069acSChunfeng Yun /* for non-ep0 */ 390df2069acSChunfeng Yun void mtu3_deconfig_ep(struct mtu3 *mtu, struct mtu3_ep *mep) 391df2069acSChunfeng Yun { 392df2069acSChunfeng Yun void __iomem *mbase = mtu->mac_base; 393df2069acSChunfeng Yun int epnum = mep->epnum; 394df2069acSChunfeng Yun 395df2069acSChunfeng Yun if (mep->is_in) { 396df2069acSChunfeng Yun mtu3_writel(mbase, MU3D_EP_TXCR0(epnum), 0); 397df2069acSChunfeng Yun mtu3_writel(mbase, MU3D_EP_TXCR1(epnum), 0); 398df2069acSChunfeng Yun mtu3_writel(mbase, MU3D_EP_TXCR2(epnum), 0); 399df2069acSChunfeng Yun mtu3_setbits(mbase, U3D_QIECR0, QMU_TX_DONE_INT(epnum)); 400df2069acSChunfeng Yun } else { 401df2069acSChunfeng Yun mtu3_writel(mbase, MU3D_EP_RXCR0(epnum), 0); 402df2069acSChunfeng Yun mtu3_writel(mbase, MU3D_EP_RXCR1(epnum), 0); 403df2069acSChunfeng Yun mtu3_writel(mbase, MU3D_EP_RXCR2(epnum), 0); 404df2069acSChunfeng Yun mtu3_setbits(mbase, U3D_QIECR0, QMU_RX_DONE_INT(epnum)); 405df2069acSChunfeng Yun } 406df2069acSChunfeng Yun 407df2069acSChunfeng Yun ep_fifo_free(mep); 408df2069acSChunfeng Yun 409df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s: %s\n", __func__, mep->name); 410df2069acSChunfeng Yun } 411df2069acSChunfeng Yun 412df2069acSChunfeng Yun /* 413a29de31bSChunfeng Yun * Two scenarios: 414a29de31bSChunfeng Yun * 1. when device IP supports SS, the fifo of EP0, TX EPs, RX EPs 415a29de31bSChunfeng Yun * are separated; 416a29de31bSChunfeng Yun * 2. when supports only HS, the fifo is shared for all EPs, and 417df2069acSChunfeng Yun * the capability registers of @EPNTXFFSZ or @EPNRXFFSZ indicate 418df2069acSChunfeng Yun * the total fifo size of non-ep0, and ep0's is fixed to 64B, 419df2069acSChunfeng Yun * so the total fifo size is 64B + @EPNTXFFSZ; 420df2069acSChunfeng Yun * Due to the first 64B should be reserved for EP0, non-ep0's fifo 421df2069acSChunfeng Yun * starts from offset 64 and are divided into two equal parts for 422df2069acSChunfeng Yun * TX or RX EPs for simplification. 423df2069acSChunfeng Yun */ 424df2069acSChunfeng Yun static void get_ep_fifo_config(struct mtu3 *mtu) 425df2069acSChunfeng Yun { 426df2069acSChunfeng Yun struct mtu3_fifo_info *tx_fifo; 427df2069acSChunfeng Yun struct mtu3_fifo_info *rx_fifo; 428df2069acSChunfeng Yun u32 fifosize; 429df2069acSChunfeng Yun 430a29de31bSChunfeng Yun if (mtu->is_u3_ip) { 431a29de31bSChunfeng Yun fifosize = mtu3_readl(mtu->mac_base, U3D_CAP_EPNTXFFSZ); 432a29de31bSChunfeng Yun tx_fifo = &mtu->tx_fifo; 433a29de31bSChunfeng Yun tx_fifo->base = 0; 434a29de31bSChunfeng Yun tx_fifo->limit = fifosize / MTU3_EP_FIFO_UNIT; 435a29de31bSChunfeng Yun bitmap_zero(tx_fifo->bitmap, MTU3_FIFO_BIT_SIZE); 436a29de31bSChunfeng Yun 437a29de31bSChunfeng Yun fifosize = mtu3_readl(mtu->mac_base, U3D_CAP_EPNRXFFSZ); 438a29de31bSChunfeng Yun rx_fifo = &mtu->rx_fifo; 439a29de31bSChunfeng Yun rx_fifo->base = 0; 440a29de31bSChunfeng Yun rx_fifo->limit = fifosize / MTU3_EP_FIFO_UNIT; 441a29de31bSChunfeng Yun bitmap_zero(rx_fifo->bitmap, MTU3_FIFO_BIT_SIZE); 442a29de31bSChunfeng Yun mtu->slot = MTU3_U3_IP_SLOT_DEFAULT; 443a29de31bSChunfeng Yun } else { 444df2069acSChunfeng Yun fifosize = mtu3_readl(mtu->mac_base, U3D_CAP_EPNTXFFSZ); 445df2069acSChunfeng Yun tx_fifo = &mtu->tx_fifo; 446df2069acSChunfeng Yun tx_fifo->base = MTU3_U2_IP_EP0_FIFO_SIZE; 447df2069acSChunfeng Yun tx_fifo->limit = (fifosize / MTU3_EP_FIFO_UNIT) >> 1; 448df2069acSChunfeng Yun bitmap_zero(tx_fifo->bitmap, MTU3_FIFO_BIT_SIZE); 449df2069acSChunfeng Yun 450df2069acSChunfeng Yun rx_fifo = &mtu->rx_fifo; 451df2069acSChunfeng Yun rx_fifo->base = 452df2069acSChunfeng Yun tx_fifo->base + tx_fifo->limit * MTU3_EP_FIFO_UNIT; 453df2069acSChunfeng Yun rx_fifo->limit = tx_fifo->limit; 454df2069acSChunfeng Yun bitmap_zero(rx_fifo->bitmap, MTU3_FIFO_BIT_SIZE); 455df2069acSChunfeng Yun mtu->slot = MTU3_U2_IP_SLOT_DEFAULT; 456a29de31bSChunfeng Yun } 457df2069acSChunfeng Yun 458df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s, TX: base-%d, limit-%d; RX: base-%d, limit-%d\n", 459df2069acSChunfeng Yun __func__, tx_fifo->base, tx_fifo->limit, 460df2069acSChunfeng Yun rx_fifo->base, rx_fifo->limit); 461df2069acSChunfeng Yun } 462df2069acSChunfeng Yun 463df2069acSChunfeng Yun void mtu3_ep0_setup(struct mtu3 *mtu) 464df2069acSChunfeng Yun { 465df2069acSChunfeng Yun u32 maxpacket = mtu->g.ep0->maxpacket; 466df2069acSChunfeng Yun u32 csr; 467df2069acSChunfeng Yun 468df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s maxpacket: %d\n", __func__, maxpacket); 469df2069acSChunfeng Yun 470df2069acSChunfeng Yun csr = mtu3_readl(mtu->mac_base, U3D_EP0CSR); 471df2069acSChunfeng Yun csr &= ~EP0_MAXPKTSZ_MSK; 472df2069acSChunfeng Yun csr |= EP0_MAXPKTSZ(maxpacket); 473df2069acSChunfeng Yun csr &= EP0_W1C_BITS; 474df2069acSChunfeng Yun mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr); 475df2069acSChunfeng Yun 476df2069acSChunfeng Yun /* Enable EP0 interrupt */ 477df2069acSChunfeng Yun mtu3_writel(mtu->mac_base, U3D_EPIESR, EP0ISR); 478df2069acSChunfeng Yun } 479df2069acSChunfeng Yun 480df2069acSChunfeng Yun static int mtu3_mem_alloc(struct mtu3 *mtu) 481df2069acSChunfeng Yun { 482df2069acSChunfeng Yun void __iomem *mbase = mtu->mac_base; 483df2069acSChunfeng Yun struct mtu3_ep *ep_array; 484df2069acSChunfeng Yun int in_ep_num, out_ep_num; 485220d88eaSChunfeng Yun u32 cap_epinfo; 486df2069acSChunfeng Yun int ret; 487df2069acSChunfeng Yun int i; 488df2069acSChunfeng Yun 489df2069acSChunfeng Yun cap_epinfo = mtu3_readl(mbase, U3D_CAP_EPINFO); 490df2069acSChunfeng Yun in_ep_num = CAP_TX_EP_NUM(cap_epinfo); 491df2069acSChunfeng Yun out_ep_num = CAP_RX_EP_NUM(cap_epinfo); 492df2069acSChunfeng Yun 493df2069acSChunfeng Yun dev_info(mtu->dev, "fifosz/epnum: Tx=%#x/%d, Rx=%#x/%d\n", 494df2069acSChunfeng Yun mtu3_readl(mbase, U3D_CAP_EPNTXFFSZ), in_ep_num, 495df2069acSChunfeng Yun mtu3_readl(mbase, U3D_CAP_EPNRXFFSZ), out_ep_num); 496df2069acSChunfeng Yun 497df2069acSChunfeng Yun /* one for ep0, another is reserved */ 498df2069acSChunfeng Yun mtu->num_eps = min(in_ep_num, out_ep_num) + 1; 499df2069acSChunfeng Yun ep_array = kcalloc(mtu->num_eps * 2, sizeof(*ep_array), GFP_KERNEL); 500df2069acSChunfeng Yun if (ep_array == NULL) 501df2069acSChunfeng Yun return -ENOMEM; 502df2069acSChunfeng Yun 503df2069acSChunfeng Yun mtu->ep_array = ep_array; 504df2069acSChunfeng Yun mtu->in_eps = ep_array; 505df2069acSChunfeng Yun mtu->out_eps = &ep_array[mtu->num_eps]; 506df2069acSChunfeng Yun /* ep0 uses in_eps[0], out_eps[0] is reserved */ 507df2069acSChunfeng Yun mtu->ep0 = mtu->in_eps; 508df2069acSChunfeng Yun mtu->ep0->mtu = mtu; 509df2069acSChunfeng Yun mtu->ep0->epnum = 0; 510df2069acSChunfeng Yun 511df2069acSChunfeng Yun for (i = 1; i < mtu->num_eps; i++) { 512df2069acSChunfeng Yun struct mtu3_ep *mep = mtu->in_eps + i; 513df2069acSChunfeng Yun 514df2069acSChunfeng Yun mep->fifo = &mtu->tx_fifo; 515df2069acSChunfeng Yun mep = mtu->out_eps + i; 516df2069acSChunfeng Yun mep->fifo = &mtu->rx_fifo; 517df2069acSChunfeng Yun } 518df2069acSChunfeng Yun 519df2069acSChunfeng Yun get_ep_fifo_config(mtu); 520df2069acSChunfeng Yun 521df2069acSChunfeng Yun ret = mtu3_qmu_init(mtu); 522df2069acSChunfeng Yun if (ret) 523df2069acSChunfeng Yun kfree(mtu->ep_array); 524df2069acSChunfeng Yun 525df2069acSChunfeng Yun return ret; 526df2069acSChunfeng Yun } 527df2069acSChunfeng Yun 528df2069acSChunfeng Yun static void mtu3_mem_free(struct mtu3 *mtu) 529df2069acSChunfeng Yun { 530df2069acSChunfeng Yun mtu3_qmu_exit(mtu); 531df2069acSChunfeng Yun kfree(mtu->ep_array); 532df2069acSChunfeng Yun } 533df2069acSChunfeng Yun 534a29de31bSChunfeng Yun static void mtu3_set_speed(struct mtu3 *mtu) 535a29de31bSChunfeng Yun { 536a29de31bSChunfeng Yun void __iomem *mbase = mtu->mac_base; 537a29de31bSChunfeng Yun 538a29de31bSChunfeng Yun if (!mtu->is_u3_ip && (mtu->max_speed > USB_SPEED_HIGH)) 539a29de31bSChunfeng Yun mtu->max_speed = USB_SPEED_HIGH; 540a29de31bSChunfeng Yun 541a29de31bSChunfeng Yun if (mtu->max_speed == USB_SPEED_FULL) { 542a29de31bSChunfeng Yun /* disable U3 SS function */ 543a29de31bSChunfeng Yun mtu3_clrbits(mbase, U3D_USB3_CONFIG, USB3_EN); 544a29de31bSChunfeng Yun /* disable HS function */ 545a29de31bSChunfeng Yun mtu3_clrbits(mbase, U3D_POWER_MANAGEMENT, HS_ENABLE); 546a29de31bSChunfeng Yun } else if (mtu->max_speed == USB_SPEED_HIGH) { 547a29de31bSChunfeng Yun mtu3_clrbits(mbase, U3D_USB3_CONFIG, USB3_EN); 548a29de31bSChunfeng Yun /* HS/FS detected by HW */ 549a29de31bSChunfeng Yun mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, HS_ENABLE); 5504d79e042SChunfeng Yun } else if (mtu->max_speed == USB_SPEED_SUPER) { 5514d79e042SChunfeng Yun mtu3_clrbits(mtu->ippc_base, SSUSB_U3_CTRL(0), 5524d79e042SChunfeng Yun SSUSB_U3_PORT_SSP_SPEED); 553a29de31bSChunfeng Yun } 554d0ed062aSChunfeng Yun 555a29de31bSChunfeng Yun dev_info(mtu->dev, "max_speed: %s\n", 556a29de31bSChunfeng Yun usb_speed_string(mtu->max_speed)); 557a29de31bSChunfeng Yun } 558a29de31bSChunfeng Yun 559df2069acSChunfeng Yun static void mtu3_regs_init(struct mtu3 *mtu) 560df2069acSChunfeng Yun { 561df2069acSChunfeng Yun 562df2069acSChunfeng Yun void __iomem *mbase = mtu->mac_base; 563df2069acSChunfeng Yun 564df2069acSChunfeng Yun /* be sure interrupts are disabled before registration of ISR */ 565df2069acSChunfeng Yun mtu3_intr_disable(mtu); 566df2069acSChunfeng Yun mtu3_intr_status_clear(mtu); 567df2069acSChunfeng Yun 568a29de31bSChunfeng Yun if (mtu->is_u3_ip) { 569a29de31bSChunfeng Yun /* disable LGO_U1/U2 by default */ 570a29de31bSChunfeng Yun mtu3_clrbits(mbase, U3D_LINK_POWER_CONTROL, 571a29de31bSChunfeng Yun SW_U1_ACCEPT_ENABLE | SW_U2_ACCEPT_ENABLE | 572a29de31bSChunfeng Yun SW_U1_REQUEST_ENABLE | SW_U2_REQUEST_ENABLE); 573a29de31bSChunfeng Yun /* device responses to u3_exit from host automatically */ 574a29de31bSChunfeng Yun mtu3_clrbits(mbase, U3D_LTSSM_CTRL, SOFT_U3_EXIT_EN); 575c7d4abbcSChunfeng Yun /* automatically build U2 link when U3 detect fail */ 576c7d4abbcSChunfeng Yun mtu3_setbits(mbase, U3D_USB2_TEST_MODE, U2U3_AUTO_SWITCH); 577a29de31bSChunfeng Yun } 578a29de31bSChunfeng Yun 579a29de31bSChunfeng Yun mtu3_set_speed(mtu); 580df2069acSChunfeng Yun 581df2069acSChunfeng Yun /* delay about 0.1us from detecting reset to send chirp-K */ 582df2069acSChunfeng Yun mtu3_clrbits(mbase, U3D_LINK_RESET_INFO, WTCHRP_MSK); 583df2069acSChunfeng Yun /* U2/U3 detected by HW */ 584df2069acSChunfeng Yun mtu3_writel(mbase, U3D_DEVICE_CONF, 0); 585df2069acSChunfeng Yun /* enable QMU 16B checksum */ 586df2069acSChunfeng Yun mtu3_setbits(mbase, U3D_QCR0, QMU_CS16B_EN); 587df2069acSChunfeng Yun /* vbus detected by HW */ 588df2069acSChunfeng Yun mtu3_clrbits(mbase, U3D_MISC_CTRL, VBUS_FRC_EN | VBUS_ON); 589df2069acSChunfeng Yun } 590df2069acSChunfeng Yun 591df2069acSChunfeng Yun static irqreturn_t mtu3_link_isr(struct mtu3 *mtu) 592df2069acSChunfeng Yun { 593df2069acSChunfeng Yun void __iomem *mbase = mtu->mac_base; 594df2069acSChunfeng Yun enum usb_device_speed udev_speed; 595df2069acSChunfeng Yun u32 maxpkt = 64; 596df2069acSChunfeng Yun u32 link; 597df2069acSChunfeng Yun u32 speed; 598df2069acSChunfeng Yun 599df2069acSChunfeng Yun link = mtu3_readl(mbase, U3D_DEV_LINK_INTR); 600df2069acSChunfeng Yun link &= mtu3_readl(mbase, U3D_DEV_LINK_INTR_ENABLE); 601df2069acSChunfeng Yun mtu3_writel(mbase, U3D_DEV_LINK_INTR, link); /* W1C */ 602df2069acSChunfeng Yun dev_dbg(mtu->dev, "=== LINK[%x] ===\n", link); 603df2069acSChunfeng Yun 604df2069acSChunfeng Yun if (!(link & SSUSB_DEV_SPEED_CHG_INTR)) 605df2069acSChunfeng Yun return IRQ_NONE; 606df2069acSChunfeng Yun 607df2069acSChunfeng Yun speed = SSUSB_DEV_SPEED(mtu3_readl(mbase, U3D_DEVICE_CONF)); 608df2069acSChunfeng Yun 609df2069acSChunfeng Yun switch (speed) { 610df2069acSChunfeng Yun case MTU3_SPEED_FULL: 611df2069acSChunfeng Yun udev_speed = USB_SPEED_FULL; 612df2069acSChunfeng Yun /*BESLCK = 4 < BESLCK_U3 = 10 < BESLDCK = 15 */ 613df2069acSChunfeng Yun mtu3_writel(mbase, U3D_USB20_LPM_PARAMETER, LPM_BESLDCK(0xf) 614df2069acSChunfeng Yun | LPM_BESLCK(4) | LPM_BESLCK_U3(0xa)); 615df2069acSChunfeng Yun mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, 616df2069acSChunfeng Yun LPM_BESL_STALL | LPM_BESLD_STALL); 617df2069acSChunfeng Yun break; 618df2069acSChunfeng Yun case MTU3_SPEED_HIGH: 619df2069acSChunfeng Yun udev_speed = USB_SPEED_HIGH; 620df2069acSChunfeng Yun /*BESLCK = 4 < BESLCK_U3 = 10 < BESLDCK = 15 */ 621df2069acSChunfeng Yun mtu3_writel(mbase, U3D_USB20_LPM_PARAMETER, LPM_BESLDCK(0xf) 622df2069acSChunfeng Yun | LPM_BESLCK(4) | LPM_BESLCK_U3(0xa)); 623df2069acSChunfeng Yun mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, 624df2069acSChunfeng Yun LPM_BESL_STALL | LPM_BESLD_STALL); 625df2069acSChunfeng Yun break; 626a29de31bSChunfeng Yun case MTU3_SPEED_SUPER: 627a29de31bSChunfeng Yun udev_speed = USB_SPEED_SUPER; 628a29de31bSChunfeng Yun maxpkt = 512; 629a29de31bSChunfeng Yun break; 6304d79e042SChunfeng Yun case MTU3_SPEED_SUPER_PLUS: 6314d79e042SChunfeng Yun udev_speed = USB_SPEED_SUPER_PLUS; 6324d79e042SChunfeng Yun maxpkt = 512; 6334d79e042SChunfeng Yun break; 634df2069acSChunfeng Yun default: 635df2069acSChunfeng Yun udev_speed = USB_SPEED_UNKNOWN; 636df2069acSChunfeng Yun break; 637df2069acSChunfeng Yun } 638df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s: %s\n", __func__, usb_speed_string(udev_speed)); 639df2069acSChunfeng Yun 640df2069acSChunfeng Yun mtu->g.speed = udev_speed; 641df2069acSChunfeng Yun mtu->g.ep0->maxpacket = maxpkt; 642df2069acSChunfeng Yun mtu->ep0_state = MU3D_EP0_STATE_SETUP; 643df2069acSChunfeng Yun 644df2069acSChunfeng Yun if (udev_speed == USB_SPEED_UNKNOWN) 645df2069acSChunfeng Yun mtu3_gadget_disconnect(mtu); 646df2069acSChunfeng Yun else 647df2069acSChunfeng Yun mtu3_ep0_setup(mtu); 648df2069acSChunfeng Yun 649df2069acSChunfeng Yun return IRQ_HANDLED; 650df2069acSChunfeng Yun } 651df2069acSChunfeng Yun 652a29de31bSChunfeng Yun static irqreturn_t mtu3_u3_ltssm_isr(struct mtu3 *mtu) 653a29de31bSChunfeng Yun { 654a29de31bSChunfeng Yun void __iomem *mbase = mtu->mac_base; 655a29de31bSChunfeng Yun u32 ltssm; 656a29de31bSChunfeng Yun 657a29de31bSChunfeng Yun ltssm = mtu3_readl(mbase, U3D_LTSSM_INTR); 658a29de31bSChunfeng Yun ltssm &= mtu3_readl(mbase, U3D_LTSSM_INTR_ENABLE); 659a29de31bSChunfeng Yun mtu3_writel(mbase, U3D_LTSSM_INTR, ltssm); /* W1C */ 660a29de31bSChunfeng Yun dev_dbg(mtu->dev, "=== LTSSM[%x] ===\n", ltssm); 661a29de31bSChunfeng Yun 662a29de31bSChunfeng Yun if (ltssm & (HOT_RST_INTR | WARM_RST_INTR)) 663a29de31bSChunfeng Yun mtu3_gadget_reset(mtu); 664a29de31bSChunfeng Yun 665a29de31bSChunfeng Yun if (ltssm & VBUS_FALL_INTR) 666a29de31bSChunfeng Yun mtu3_ss_func_set(mtu, false); 667a29de31bSChunfeng Yun 668a29de31bSChunfeng Yun if (ltssm & VBUS_RISE_INTR) 669a29de31bSChunfeng Yun mtu3_ss_func_set(mtu, true); 670a29de31bSChunfeng Yun 671a29de31bSChunfeng Yun if (ltssm & EXIT_U3_INTR) 672a29de31bSChunfeng Yun mtu3_gadget_resume(mtu); 673a29de31bSChunfeng Yun 674a29de31bSChunfeng Yun if (ltssm & ENTER_U3_INTR) 675a29de31bSChunfeng Yun mtu3_gadget_suspend(mtu); 676a29de31bSChunfeng Yun 677a29de31bSChunfeng Yun return IRQ_HANDLED; 678a29de31bSChunfeng Yun } 679a29de31bSChunfeng Yun 680df2069acSChunfeng Yun static irqreturn_t mtu3_u2_common_isr(struct mtu3 *mtu) 681df2069acSChunfeng Yun { 682df2069acSChunfeng Yun void __iomem *mbase = mtu->mac_base; 683df2069acSChunfeng Yun u32 u2comm; 684df2069acSChunfeng Yun 685df2069acSChunfeng Yun u2comm = mtu3_readl(mbase, U3D_COMMON_USB_INTR); 686df2069acSChunfeng Yun u2comm &= mtu3_readl(mbase, U3D_COMMON_USB_INTR_ENABLE); 687df2069acSChunfeng Yun mtu3_writel(mbase, U3D_COMMON_USB_INTR, u2comm); /* W1C */ 688df2069acSChunfeng Yun dev_dbg(mtu->dev, "=== U2COMM[%x] ===\n", u2comm); 689df2069acSChunfeng Yun 690df2069acSChunfeng Yun if (u2comm & SUSPEND_INTR) 691df2069acSChunfeng Yun mtu3_gadget_suspend(mtu); 692df2069acSChunfeng Yun 693df2069acSChunfeng Yun if (u2comm & RESUME_INTR) 694df2069acSChunfeng Yun mtu3_gadget_resume(mtu); 695df2069acSChunfeng Yun 696df2069acSChunfeng Yun if (u2comm & RESET_INTR) 697df2069acSChunfeng Yun mtu3_gadget_reset(mtu); 698df2069acSChunfeng Yun 699df2069acSChunfeng Yun return IRQ_HANDLED; 700df2069acSChunfeng Yun } 701df2069acSChunfeng Yun 702a8bac371SSudip Mukherjee static irqreturn_t mtu3_irq(int irq, void *data) 703df2069acSChunfeng Yun { 704df2069acSChunfeng Yun struct mtu3 *mtu = (struct mtu3 *)data; 705df2069acSChunfeng Yun unsigned long flags; 706df2069acSChunfeng Yun u32 level1; 707df2069acSChunfeng Yun 708df2069acSChunfeng Yun spin_lock_irqsave(&mtu->lock, flags); 709df2069acSChunfeng Yun 710df2069acSChunfeng Yun /* U3D_LV1ISR is RU */ 711df2069acSChunfeng Yun level1 = mtu3_readl(mtu->mac_base, U3D_LV1ISR); 712df2069acSChunfeng Yun level1 &= mtu3_readl(mtu->mac_base, U3D_LV1IER); 713df2069acSChunfeng Yun 714df2069acSChunfeng Yun if (level1 & EP_CTRL_INTR) 715df2069acSChunfeng Yun mtu3_link_isr(mtu); 716df2069acSChunfeng Yun 717df2069acSChunfeng Yun if (level1 & MAC2_INTR) 718df2069acSChunfeng Yun mtu3_u2_common_isr(mtu); 719df2069acSChunfeng Yun 720a29de31bSChunfeng Yun if (level1 & MAC3_INTR) 721a29de31bSChunfeng Yun mtu3_u3_ltssm_isr(mtu); 722a29de31bSChunfeng Yun 723df2069acSChunfeng Yun if (level1 & BMU_INTR) 724df2069acSChunfeng Yun mtu3_ep0_isr(mtu); 725df2069acSChunfeng Yun 726df2069acSChunfeng Yun if (level1 & QMU_INTR) 727df2069acSChunfeng Yun mtu3_qmu_isr(mtu); 728df2069acSChunfeng Yun 729df2069acSChunfeng Yun spin_unlock_irqrestore(&mtu->lock, flags); 730df2069acSChunfeng Yun 731df2069acSChunfeng Yun return IRQ_HANDLED; 732df2069acSChunfeng Yun } 733df2069acSChunfeng Yun 734df2069acSChunfeng Yun static int mtu3_hw_init(struct mtu3 *mtu) 735df2069acSChunfeng Yun { 736220d88eaSChunfeng Yun u32 cap_dev; 737df2069acSChunfeng Yun int ret; 738df2069acSChunfeng Yun 739220d88eaSChunfeng Yun mtu->hw_version = mtu3_readl(mtu->ippc_base, U3D_SSUSB_HW_ID); 740220d88eaSChunfeng Yun 741220d88eaSChunfeng Yun cap_dev = mtu3_readl(mtu->ippc_base, U3D_SSUSB_IP_DEV_CAP); 742220d88eaSChunfeng Yun mtu->is_u3_ip = !!SSUSB_IP_DEV_U3_PORT_NUM(cap_dev); 743220d88eaSChunfeng Yun 744220d88eaSChunfeng Yun dev_info(mtu->dev, "IP version 0x%x(%s IP)\n", mtu->hw_version, 745220d88eaSChunfeng Yun mtu->is_u3_ip ? "U3" : "U2"); 746220d88eaSChunfeng Yun 747df2069acSChunfeng Yun mtu3_device_reset(mtu); 748df2069acSChunfeng Yun 749df2069acSChunfeng Yun ret = mtu3_device_enable(mtu); 750df2069acSChunfeng Yun if (ret) { 751df2069acSChunfeng Yun dev_err(mtu->dev, "device enable failed %d\n", ret); 752df2069acSChunfeng Yun return ret; 753df2069acSChunfeng Yun } 754df2069acSChunfeng Yun 755df2069acSChunfeng Yun ret = mtu3_mem_alloc(mtu); 756df2069acSChunfeng Yun if (ret) 757df2069acSChunfeng Yun return -ENOMEM; 758df2069acSChunfeng Yun 759df2069acSChunfeng Yun mtu3_regs_init(mtu); 760df2069acSChunfeng Yun 761df2069acSChunfeng Yun return 0; 762df2069acSChunfeng Yun } 763df2069acSChunfeng Yun 764df2069acSChunfeng Yun static void mtu3_hw_exit(struct mtu3 *mtu) 765df2069acSChunfeng Yun { 766df2069acSChunfeng Yun mtu3_device_disable(mtu); 767df2069acSChunfeng Yun mtu3_mem_free(mtu); 768df2069acSChunfeng Yun } 769df2069acSChunfeng Yun 7701a46dfeaSChunfeng Yun /** 7711a46dfeaSChunfeng Yun * we set 32-bit DMA mask by default, here check whether the controller 7721a46dfeaSChunfeng Yun * supports 36-bit DMA or not, if it does, set 36-bit DMA mask. 7731a46dfeaSChunfeng Yun */ 7741a46dfeaSChunfeng Yun static int mtu3_set_dma_mask(struct mtu3 *mtu) 7751a46dfeaSChunfeng Yun { 7761a46dfeaSChunfeng Yun struct device *dev = mtu->dev; 7771a46dfeaSChunfeng Yun bool is_36bit = false; 7781a46dfeaSChunfeng Yun int ret = 0; 7791a46dfeaSChunfeng Yun u32 value; 7801a46dfeaSChunfeng Yun 7811a46dfeaSChunfeng Yun value = mtu3_readl(mtu->mac_base, U3D_MISC_CTRL); 7821a46dfeaSChunfeng Yun if (value & DMA_ADDR_36BIT) { 7831a46dfeaSChunfeng Yun is_36bit = true; 7841a46dfeaSChunfeng Yun ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(36)); 7851a46dfeaSChunfeng Yun /* If set 36-bit DMA mask fails, fall back to 32-bit DMA mask */ 7861a46dfeaSChunfeng Yun if (ret) { 7871a46dfeaSChunfeng Yun is_36bit = false; 7881a46dfeaSChunfeng Yun ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); 7891a46dfeaSChunfeng Yun } 7901a46dfeaSChunfeng Yun } 7911a46dfeaSChunfeng Yun dev_info(dev, "dma mask: %s bits\n", is_36bit ? "36" : "32"); 7921a46dfeaSChunfeng Yun 7931a46dfeaSChunfeng Yun return ret; 7941a46dfeaSChunfeng Yun } 795df2069acSChunfeng Yun 796b3f4e727SChunfeng Yun int ssusb_gadget_init(struct ssusb_mtk *ssusb) 797df2069acSChunfeng Yun { 798b3f4e727SChunfeng Yun struct device *dev = ssusb->dev; 799b3f4e727SChunfeng Yun struct platform_device *pdev = to_platform_device(dev); 800b3f4e727SChunfeng Yun struct mtu3 *mtu = NULL; 801b3f4e727SChunfeng Yun struct resource *res; 802b3f4e727SChunfeng Yun int ret = -ENOMEM; 803df2069acSChunfeng Yun 804b3f4e727SChunfeng Yun mtu = devm_kzalloc(dev, sizeof(struct mtu3), GFP_KERNEL); 805b3f4e727SChunfeng Yun if (mtu == NULL) 806b3f4e727SChunfeng Yun return -ENOMEM; 807b3f4e727SChunfeng Yun 808b3f4e727SChunfeng Yun mtu->irq = platform_get_irq(pdev, 0); 809c162ff0aSChunfeng Yun if (mtu->irq < 0) { 810b3f4e727SChunfeng Yun dev_err(dev, "fail to get irq number\n"); 811c162ff0aSChunfeng Yun return mtu->irq; 812b3f4e727SChunfeng Yun } 813b3f4e727SChunfeng Yun dev_info(dev, "irq %d\n", mtu->irq); 814b3f4e727SChunfeng Yun 815b3f4e727SChunfeng Yun res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mac"); 816b3f4e727SChunfeng Yun mtu->mac_base = devm_ioremap_resource(dev, res); 817b3f4e727SChunfeng Yun if (IS_ERR(mtu->mac_base)) { 818b3f4e727SChunfeng Yun dev_err(dev, "error mapping memory for dev mac\n"); 819b3f4e727SChunfeng Yun return PTR_ERR(mtu->mac_base); 820b3f4e727SChunfeng Yun } 821b3f4e727SChunfeng Yun 822b3f4e727SChunfeng Yun spin_lock_init(&mtu->lock); 823b3f4e727SChunfeng Yun mtu->dev = dev; 824b3f4e727SChunfeng Yun mtu->ippc_base = ssusb->ippc_base; 825b3f4e727SChunfeng Yun ssusb->mac_base = mtu->mac_base; 826b3f4e727SChunfeng Yun ssusb->u3d = mtu; 827b3f4e727SChunfeng Yun mtu->ssusb = ssusb; 828a29de31bSChunfeng Yun mtu->max_speed = usb_get_maximum_speed(dev); 829a29de31bSChunfeng Yun 830a29de31bSChunfeng Yun /* check the max_speed parameter */ 831a29de31bSChunfeng Yun switch (mtu->max_speed) { 832a29de31bSChunfeng Yun case USB_SPEED_FULL: 833a29de31bSChunfeng Yun case USB_SPEED_HIGH: 834a29de31bSChunfeng Yun case USB_SPEED_SUPER: 8354d79e042SChunfeng Yun case USB_SPEED_SUPER_PLUS: 836a29de31bSChunfeng Yun break; 837a29de31bSChunfeng Yun default: 838a29de31bSChunfeng Yun dev_err(dev, "invalid max_speed: %s\n", 839a29de31bSChunfeng Yun usb_speed_string(mtu->max_speed)); 840a29de31bSChunfeng Yun /* fall through */ 841a29de31bSChunfeng Yun case USB_SPEED_UNKNOWN: 8424d79e042SChunfeng Yun /* default as SSP */ 8434d79e042SChunfeng Yun mtu->max_speed = USB_SPEED_SUPER_PLUS; 844a29de31bSChunfeng Yun break; 845a29de31bSChunfeng Yun } 846a29de31bSChunfeng Yun 847a29de31bSChunfeng Yun dev_dbg(dev, "mac_base=0x%p, ippc_base=0x%p\n", 848a29de31bSChunfeng Yun mtu->mac_base, mtu->ippc_base); 849a29de31bSChunfeng Yun 850df2069acSChunfeng Yun ret = mtu3_hw_init(mtu); 851df2069acSChunfeng Yun if (ret) { 852df2069acSChunfeng Yun dev_err(dev, "mtu3 hw init failed:%d\n", ret); 853df2069acSChunfeng Yun return ret; 854df2069acSChunfeng Yun } 855df2069acSChunfeng Yun 8561a46dfeaSChunfeng Yun ret = mtu3_set_dma_mask(mtu); 8571a46dfeaSChunfeng Yun if (ret) { 8581a46dfeaSChunfeng Yun dev_err(dev, "mtu3 set dma_mask failed:%d\n", ret); 8591a46dfeaSChunfeng Yun goto dma_mask_err; 8601a46dfeaSChunfeng Yun } 8611a46dfeaSChunfeng Yun 862df2069acSChunfeng Yun ret = devm_request_irq(dev, mtu->irq, mtu3_irq, 0, dev_name(dev), mtu); 863df2069acSChunfeng Yun if (ret) { 864df2069acSChunfeng Yun dev_err(dev, "request irq %d failed!\n", mtu->irq); 865df2069acSChunfeng Yun goto irq_err; 866df2069acSChunfeng Yun } 867df2069acSChunfeng Yun 868df2069acSChunfeng Yun device_init_wakeup(dev, true); 869df2069acSChunfeng Yun 870df2069acSChunfeng Yun ret = mtu3_gadget_setup(mtu); 871df2069acSChunfeng Yun if (ret) { 872df2069acSChunfeng Yun dev_err(dev, "mtu3 gadget init failed:%d\n", ret); 873df2069acSChunfeng Yun goto gadget_err; 874df2069acSChunfeng Yun } 875df2069acSChunfeng Yun 876d0ed062aSChunfeng Yun /* init as host mode, power down device IP for power saving */ 877d0ed062aSChunfeng Yun if (mtu->ssusb->dr_mode == USB_DR_MODE_OTG) 878d0ed062aSChunfeng Yun mtu3_stop(mtu); 879d0ed062aSChunfeng Yun 880df2069acSChunfeng Yun dev_dbg(dev, " %s() done...\n", __func__); 881df2069acSChunfeng Yun 882df2069acSChunfeng Yun return 0; 883df2069acSChunfeng Yun 884df2069acSChunfeng Yun gadget_err: 885df2069acSChunfeng Yun device_init_wakeup(dev, false); 886df2069acSChunfeng Yun 8871a46dfeaSChunfeng Yun dma_mask_err: 888df2069acSChunfeng Yun irq_err: 889df2069acSChunfeng Yun mtu3_hw_exit(mtu); 890b3f4e727SChunfeng Yun ssusb->u3d = NULL; 891df2069acSChunfeng Yun dev_err(dev, " %s() fail...\n", __func__); 892df2069acSChunfeng Yun 893df2069acSChunfeng Yun return ret; 894df2069acSChunfeng Yun } 895df2069acSChunfeng Yun 896b3f4e727SChunfeng Yun void ssusb_gadget_exit(struct ssusb_mtk *ssusb) 897df2069acSChunfeng Yun { 898b3f4e727SChunfeng Yun struct mtu3 *mtu = ssusb->u3d; 899b3f4e727SChunfeng Yun 900df2069acSChunfeng Yun mtu3_gadget_cleanup(mtu); 901b3f4e727SChunfeng Yun device_init_wakeup(ssusb->dev, false); 902df2069acSChunfeng Yun mtu3_hw_exit(mtu); 903df2069acSChunfeng Yun } 904