diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 72eb3e41e3b6..5e810e2ae7df 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -125,6 +125,8 @@ source "drivers/usb/chipidea/Kconfig"
source "drivers/usb/isp1760/Kconfig"
+source "drivers/usb/cdns3/Kconfig"
+
comment "USB port drivers"
if USB
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 060643a1b5c8..4a96f18a616f 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_USB_SUPPORT) += phy/
obj-$(CONFIG_USB_DWC3) += dwc3/
obj-$(CONFIG_USB_DWC2) += dwc2/
obj-$(CONFIG_USB_ISP1760) += isp1760/
+obj-$(CONFIG_USB_CDNS3) += cdns3/
obj-$(CONFIG_USB_MON) += mon/
obj-$(CONFIG_USB_MTU3) += mtu3/
diff --git a/drivers/usb/cdns3/Kconfig b/drivers/usb/cdns3/Kconfig
new file mode 100644
index 000000000000..165afdb99d15
--- /dev/null
+++ b/drivers/usb/cdns3/Kconfig
@@ -0,0 +1,26 @@
+config USB_CDNS3
+ tristate "Cadence USB3 Dual-Role Controller"
+ depends on ((USB_XHCI_HCD && USB_GADGET) || (USB_XHCI_HCD && !USB_GADGET) || (!USB_XHCI_HCD && USB_GADGET)) && HAS_DMA
+ select EXTCON
+ help
+ Say Y here if your system has a cadence USB3 dual-role controller.
+ It supports: dual-role switch Host-only, and Peripheral-only.
+
+ When compiled dynamically, the module will be called cdns3.ko.
+
+if USB_CDNS3
+
+config USB_CDNS3_GADGET
+ bool "Cadence USB3 device controller"
+ depends on USB_GADGET
+ help
+ Say Y here to enable device controller functionality of the
+ cadence usb3 driver.
+
+config USB_CDNS3_HOST
+ bool "Cadence USB3 host controller"
+ depends on USB_XHCI_HCD
+ help
+ Say Y here to enable host controller functionality of the
+ cadence usb3 driver.
+endif
diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile
new file mode 100644
index 000000000000..7328cb9fcc89
--- /dev/null
+++ b/drivers/usb/cdns3/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_USB_CDNS3) += cdns3.o
+
+cdns3-y := core.o
+cdns3-$(CONFIG_USB_CDNS3_GADGET) += gadget.o
+cdns3-$(CONFIG_USB_CDNS3_HOST) += host.o
diff --git a/drivers/usb/cdns3/cdns3-nxp-reg-def.h b/drivers/usb/cdns3/cdns3-nxp-reg-def.h
new file mode 100644
index 000000000000..2a07e8f2784c
--- /dev/null
+++ b/drivers/usb/cdns3/cdns3-nxp-reg-def.h
@@ -0,0 +1,132 @@
+/**
+ * cdns3-nxp-reg-def.h - nxp wrap layer register definition
+ *
+ * Copyright 2017 NXP
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef __DRIVERS_USB_CDNS3_NXP_H
+#define __DRIVERS_USB_CDNS3_NXP_H
+
+#define USB3_CORE_CTRL1 0x00
+#define USB3_CORE_CTRL2 0x04
+#define USB3_INT_REG 0x08
+#define USB3_CORE_STATUS 0x0c
+#define XHCI_DEBUG_LINK_ST 0x10
+#define XHCI_DEBUG_BUS 0x14
+#define USB3_SSPHY_CTRL1 0x40
+#define USB3_SSPHY_CTRL2 0x44
+#define USB3_SSPHY_STATUS 0x4c
+#define USB2_PHY_CTRL1 0x50
+#define USB2_PHY_CTRL2 0x54
+#define USB2_PHY_STATUS 0x5c
+
+/* Register bits definition */
+
+/* USB3_CORE_CTRL1 */
+#define PWR_SW_RESET (1 << 31)
+#define APB_SW_RESET (1 << 30)
+#define AXI_SW_RESET (1 << 29)
+#define RW_SW_RESET (1 << 28)
+#define PHY_SW_RESET (1 << 27)
+#define PHYAHB_SW_RESET (1 << 26)
+#define ALL_SW_RESET (PWR_SW_RESET | APB_SW_RESET | AXI_SW_RESET | \
+ RW_SW_RESET | PHY_SW_RESET | PHYAHB_SW_RESET)
+#define OC_DISABLE (1 << 9)
+#define MODE_STRAP_MASK (0x7)
+#define DEV_MODE (1 << 2)
+#define HOST_MODE (1 << 1)
+#define OTG_MODE (1 << 0)
+
+/* USB3_INT_REG */
+#define HOST_INT1_EN (1 << 0) /* HOST INT b7:0 */
+#define DEV_INT_EN (3 << 8) /* DEV INT b9:8 */
+
+/* USB3_CORE_STATUS */
+#define DEV_POWER_ON_READY (1 << 13)
+#define HOST_POWER_ON_READY (1 << 12)
+
+
+/* PHY register definition */
+#define PHY_PMA_CMN_CTRL1 (0xC800 * 4)
+#define TB_ADDR_CMN_DIAG_HSCLK_SEL (0x01e0 * 4)
+#define TB_ADDR_CMN_PLL0_VCOCAL_INIT_TMR (0x0084 * 4)
+#define TB_ADDR_CMN_PLL0_VCOCAL_ITER_TMR (0x0085 * 4)
+#define TB_ADDR_CMN_PLL0_INTDIV (0x0094 * 4)
+#define TB_ADDR_CMN_PLL0_FRACDIV (0x0095 * 4)
+#define TB_ADDR_CMN_PLL0_HIGH_THR (0x0096 * 4)
+#define TB_ADDR_CMN_PLL0_SS_CTRL1 (0x0098 * 4)
+#define TB_ADDR_CMN_PLL0_SS_CTRL2 (0x0099 * 4)
+#define TB_ADDR_CMN_PLL0_DSM_DIAG (0x0097 * 4)
+#define TB_ADDR_CMN_DIAG_PLL0_OVRD (0x01c2 * 4)
+#define TB_ADDR_CMN_DIAG_PLL0_FBH_OVRD (0x01c0 * 4)
+#define TB_ADDR_CMN_DIAG_PLL0_FBL_OVRD (0x01c1 * 4)
+#define TB_ADDR_CMN_DIAG_PLL0_V2I_TUNE (0x01C5 * 4)
+#define TB_ADDR_CMN_DIAG_PLL0_CP_TUNE (0x01C6 * 4)
+#define TB_ADDR_CMN_DIAG_PLL0_LF_PROG (0x01C7 * 4)
+#define TB_ADDR_CMN_DIAG_PLL0_TEST_MODE (0x01c4 * 4)
+#define TB_ADDR_CMN_PSM_CLK_CTRL (0x0061 * 4)
+#define TB_ADDR_XCVR_DIAG_RX_LANE_CAL_RST_TMR (0x40ea * 4)
+#define TB_ADDR_XCVR_PSM_RCTRL (0x4001 * 4)
+#define TB_ADDR_TX_PSC_A0 (0x4100 * 4)
+#define TB_ADDR_TX_PSC_A1 (0x4101 * 4)
+#define TB_ADDR_TX_PSC_A2 (0x4102 * 4)
+#define TB_ADDR_TX_PSC_A3 (0x4103 * 4)
+#define TB_ADDR_TX_DIAG_ECTRL_OVRD (0x41f5 * 4)
+#define TB_ADDR_TX_PSC_CAL (0x4106 * 4)
+#define TB_ADDR_TX_PSC_RDY (0x4107 * 4)
+#define TB_ADDR_RX_PSC_A0 (0x8000 * 4)
+#define TB_ADDR_RX_PSC_A1 (0x8001 * 4)
+#define TB_ADDR_RX_PSC_A2 (0x8002 * 4)
+#define TB_ADDR_RX_PSC_A3 (0x8003 * 4)
+#define TB_ADDR_RX_PSC_CAL (0x8006 * 4)
+#define TB_ADDR_RX_PSC_RDY (0x8007 * 4)
+#define TB_ADDR_TX_TXCC_MGNLS_MULT_000 (0x4058 * 4)
+#define TB_ADDR_TX_DIAG_BGREF_PREDRV_DELAY (0x41e7 * 4)
+#define TB_ADDR_RX_SLC_CU_ITER_TMR (0x80e3 * 4)
+#define TB_ADDR_RX_SIGDET_HL_FILT_TMR (0x8090 * 4)
+#define TB_ADDR_RX_SAMP_DAC_CTRL (0x8058 * 4)
+#define TB_ADDR_RX_DIAG_SIGDET_TUNE (0x81dc * 4)
+#define TB_ADDR_RX_DIAG_LFPSDET_TUNE2 (0x81df * 4)
+#define TB_ADDR_RX_DIAG_BS_TM (0x81f5 * 4)
+#define TB_ADDR_RX_DIAG_DFE_CTRL1 (0x81d3 * 4)
+#define TB_ADDR_RX_DIAG_ILL_IQE_TRIM4 (0x81c7 * 4)
+#define TB_ADDR_RX_DIAG_ILL_E_TRIM0 (0x81c2 * 4)
+#define TB_ADDR_RX_DIAG_ILL_IQ_TRIM0 (0x81c1 * 4)
+#define TB_ADDR_RX_DIAG_ILL_IQE_TRIM6 (0x81c9 * 4)
+#define TB_ADDR_RX_DIAG_RXFE_TM3 (0x81f8 * 4)
+#define TB_ADDR_RX_DIAG_RXFE_TM4 (0x81f9 * 4)
+#define TB_ADDR_RX_DIAG_LFPSDET_TUNE (0x81dd * 4)
+#define TB_ADDR_RX_DIAG_DFE_CTRL3 (0x81d5 * 4)
+#define TB_ADDR_RX_DIAG_SC2C_DELAY (0x81e1 * 4)
+#define TB_ADDR_RX_REE_VGA_GAIN_NODFE (0x81bf * 4)
+#define TB_ADDR_XCVR_PSM_CAL_TMR (0x4002 * 4)
+#define TB_ADDR_XCVR_PSM_A0BYP_TMR (0x4004 * 4)
+#define TB_ADDR_XCVR_PSM_A0IN_TMR (0x4003 * 4)
+#define TB_ADDR_XCVR_PSM_A1IN_TMR (0x4005 * 4)
+#define TB_ADDR_XCVR_PSM_A2IN_TMR (0x4006 * 4)
+#define TB_ADDR_XCVR_PSM_A3IN_TMR (0x4007 * 4)
+#define TB_ADDR_XCVR_PSM_A4IN_TMR (0x4008 * 4)
+#define TB_ADDR_XCVR_PSM_A5IN_TMR (0x4009 * 4)
+#define TB_ADDR_XCVR_PSM_A0OUT_TMR (0x400a * 4)
+#define TB_ADDR_XCVR_PSM_A1OUT_TMR (0x400b * 4)
+#define TB_ADDR_XCVR_PSM_A2OUT_TMR (0x400c * 4)
+#define TB_ADDR_XCVR_PSM_A3OUT_TMR (0x400d * 4)
+#define TB_ADDR_XCVR_PSM_A4OUT_TMR (0x400e * 4)
+#define TB_ADDR_XCVR_PSM_A5OUT_TMR (0x400f * 4)
+#define TB_ADDR_TX_RCVDET_EN_TMR (0x4122 * 4)
+#define TB_ADDR_TX_RCVDET_ST_TMR (0x4123 * 4)
+#define TB_ADDR_XCVR_DIAG_LANE_FCM_EN_MGN_TMR (0x40f2 * 4)
+
+#endif /* __DRIVERS_USB_CDNS3_NXP_H */
diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c
new file mode 100644
index 000000000000..675cb3aefaf5
--- /dev/null
+++ b/drivers/usb/cdns3/core.c
@@ -0,0 +1,620 @@
+/**
+ * core.c - Cadence USB3 DRD Controller Core file
+ *
+ * Copyright 2017 NXP
+ *
+ * Authors: Peter Chen
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "cdns3-nxp-reg-def.h"
+#include "core.h"
+#include "host-export.h"
+#include "gadget-export.h"
+
+static void cdns3_usb_phy_init(void __iomem *regs)
+{
+ pr_debug("begin of %s\n", __func__);
+
+ writel(0x0830, regs + PHY_PMA_CMN_CTRL1);
+ writel(0x10, regs + TB_ADDR_CMN_DIAG_HSCLK_SEL);
+ writel(0x00F0, regs + TB_ADDR_CMN_PLL0_VCOCAL_INIT_TMR);
+ writel(0x0018, regs + TB_ADDR_CMN_PLL0_VCOCAL_ITER_TMR);
+ writel(0x00D0, regs + TB_ADDR_CMN_PLL0_INTDIV);
+ writel(0x4aaa, regs + TB_ADDR_CMN_PLL0_FRACDIV);
+ writel(0x0034, regs + TB_ADDR_CMN_PLL0_HIGH_THR);
+ writel(0x1ee, regs + TB_ADDR_CMN_PLL0_SS_CTRL1);
+ writel(0x7F03, regs + TB_ADDR_CMN_PLL0_SS_CTRL2);
+ writel(0x0020, regs + TB_ADDR_CMN_PLL0_DSM_DIAG);
+ writel(0x0000, regs + TB_ADDR_CMN_DIAG_PLL0_OVRD);
+ writel(0x0000, regs + TB_ADDR_CMN_DIAG_PLL0_FBH_OVRD);
+ writel(0x0000, regs + TB_ADDR_CMN_DIAG_PLL0_FBL_OVRD);
+ writel(0x0007, regs + TB_ADDR_CMN_DIAG_PLL0_V2I_TUNE);
+ writel(0x0027, regs + TB_ADDR_CMN_DIAG_PLL0_CP_TUNE);
+ writel(0x0008, regs + TB_ADDR_CMN_DIAG_PLL0_LF_PROG);
+ writel(0x0022, regs + TB_ADDR_CMN_DIAG_PLL0_TEST_MODE);
+ writel(0x000a, regs + TB_ADDR_CMN_PSM_CLK_CTRL);
+ writel(0x139, regs + TB_ADDR_XCVR_DIAG_RX_LANE_CAL_RST_TMR);
+ writel(0xbefc, regs + TB_ADDR_XCVR_PSM_RCTRL);
+
+ writel(0x7799, regs + TB_ADDR_TX_PSC_A0);
+ writel(0x7798, regs + TB_ADDR_TX_PSC_A1);
+ writel(0x509b, regs + TB_ADDR_TX_PSC_A2);
+ writel(0x3, regs + TB_ADDR_TX_DIAG_ECTRL_OVRD);
+ writel(0x5098, regs + TB_ADDR_TX_PSC_A3);
+ writel(0x2090, regs + TB_ADDR_TX_PSC_CAL);
+ writel(0x2090, regs + TB_ADDR_TX_PSC_RDY);
+
+ writel(0xA6FD, regs + TB_ADDR_RX_PSC_A0);
+ writel(0xA6FD, regs + TB_ADDR_RX_PSC_A1);
+ writel(0xA410, regs + TB_ADDR_RX_PSC_A2);
+ writel(0x2410, regs + TB_ADDR_RX_PSC_A3);
+
+ writel(0x23FF, regs + TB_ADDR_RX_PSC_CAL);
+ writel(0x2010, regs + TB_ADDR_RX_PSC_RDY);
+
+ writel(0x0020, regs + TB_ADDR_TX_TXCC_MGNLS_MULT_000);
+ writel(0x00ff, regs + TB_ADDR_TX_DIAG_BGREF_PREDRV_DELAY);
+ writel(0x0002, regs + TB_ADDR_RX_SLC_CU_ITER_TMR);
+ writel(0x0013, regs + TB_ADDR_RX_SIGDET_HL_FILT_TMR);
+ writel(0x0000, regs + TB_ADDR_RX_SAMP_DAC_CTRL);
+ writel(0x1004, regs + TB_ADDR_RX_DIAG_SIGDET_TUNE);
+ writel(0x4041, regs + TB_ADDR_RX_DIAG_LFPSDET_TUNE2);
+ writel(0x0480, regs + TB_ADDR_RX_DIAG_BS_TM);
+ writel(0x8006, regs + TB_ADDR_RX_DIAG_DFE_CTRL1);
+ writel(0x003f, regs + TB_ADDR_RX_DIAG_ILL_IQE_TRIM4);
+ writel(0x543f, regs + TB_ADDR_RX_DIAG_ILL_E_TRIM0);
+ writel(0x543f, regs + TB_ADDR_RX_DIAG_ILL_IQ_TRIM0);
+ writel(0x0000, regs + TB_ADDR_RX_DIAG_ILL_IQE_TRIM6);
+ writel(0x8000, regs + TB_ADDR_RX_DIAG_RXFE_TM3);
+ writel(0x0003, regs + TB_ADDR_RX_DIAG_RXFE_TM4);
+ writel(0x2408, regs + TB_ADDR_RX_DIAG_LFPSDET_TUNE);
+ writel(0x05ca, regs + TB_ADDR_RX_DIAG_DFE_CTRL3);
+ writel(0x0258, regs + TB_ADDR_RX_DIAG_SC2C_DELAY);
+ writel(0x1fff, regs + TB_ADDR_RX_REE_VGA_GAIN_NODFE);
+
+ writel(0x02c6, regs + TB_ADDR_XCVR_PSM_CAL_TMR);
+ writel(0x0002, regs + TB_ADDR_XCVR_PSM_A0BYP_TMR);
+ writel(0x02c6, regs + TB_ADDR_XCVR_PSM_A0IN_TMR);
+ writel(0x0010, regs + TB_ADDR_XCVR_PSM_A1IN_TMR);
+ writel(0x0010, regs + TB_ADDR_XCVR_PSM_A2IN_TMR);
+ writel(0x0010, regs + TB_ADDR_XCVR_PSM_A3IN_TMR);
+ writel(0x0010, regs + TB_ADDR_XCVR_PSM_A4IN_TMR);
+ writel(0x0010, regs + TB_ADDR_XCVR_PSM_A5IN_TMR);
+
+ writel(0x0002, regs + TB_ADDR_XCVR_PSM_A0OUT_TMR);
+ writel(0x0002, regs + TB_ADDR_XCVR_PSM_A1OUT_TMR);
+ writel(0x0002, regs + TB_ADDR_XCVR_PSM_A2OUT_TMR);
+ writel(0x0002, regs + TB_ADDR_XCVR_PSM_A3OUT_TMR);
+ writel(0x0002, regs + TB_ADDR_XCVR_PSM_A4OUT_TMR);
+ writel(0x0002, regs + TB_ADDR_XCVR_PSM_A5OUT_TMR);
+
+ /* Change rx detect parameter */
+ writel(0x960, regs + TB_ADDR_TX_RCVDET_EN_TMR);
+ writel(0x01e0, regs + TB_ADDR_TX_RCVDET_ST_TMR);
+ writel(0x0090, regs + TB_ADDR_XCVR_DIAG_LANE_FCM_EN_MGN_TMR);
+
+ /* Force B Session Valid as 1 */
+ writel(0x0060, regs + 0x380a4);
+
+ udelay(10);
+
+ pr_debug("end of %s\n", __func__);
+}
+
+static void cdns_set_role(struct cdns3 *cdns, enum cdns3_roles role)
+{
+ u32 value;
+ int timeout_us = 100000;
+
+ if (role == CDNS3_ROLE_END)
+ return;
+
+ /* Wait clk value */
+ value = readl(cdns->none_core_regs + USB3_SSPHY_STATUS);
+ writel(value, cdns->none_core_regs + USB3_SSPHY_STATUS);
+ udelay(1);
+ value = readl(cdns->none_core_regs + USB3_SSPHY_STATUS);
+ while ((value & 0xf0000000) != 0xf0000000 && timeout_us-- > 0) {
+ value = readl(cdns->none_core_regs + USB3_SSPHY_STATUS);
+ dev_dbg(cdns->dev, "clkvld:0x%x\n", value);
+ udelay(1);
+ }
+
+ if (timeout_us <= 0)
+ dev_err(cdns->dev, "wait clkvld timeout\n");
+
+ /* Set all Reset bits */
+ value = readl(cdns->none_core_regs + USB3_CORE_CTRL1);
+ value |= ALL_SW_RESET;
+ writel(value, cdns->none_core_regs + USB3_CORE_CTRL1);
+ udelay(1);
+
+ if (role == CDNS3_ROLE_HOST) {
+ value = readl(cdns->none_core_regs + USB3_CORE_CTRL1);
+ value = (value & ~MODE_STRAP_MASK) | HOST_MODE | OC_DISABLE;
+ writel(value, cdns->none_core_regs + USB3_CORE_CTRL1);
+ value &= ~PHYAHB_SW_RESET;
+ writel(value, cdns->none_core_regs + USB3_CORE_CTRL1);
+ mdelay(1);
+ cdns3_usb_phy_init(cdns->phy_regs);
+ mdelay(1);
+
+ value = readl(cdns->none_core_regs + USB3_INT_REG);
+ value |= HOST_INT1_EN;
+ writel(value, cdns->none_core_regs + USB3_INT_REG);
+
+ value = readl(cdns->none_core_regs + USB3_CORE_CTRL1);
+ value &= ~ALL_SW_RESET;
+ writel(value, cdns->none_core_regs + USB3_CORE_CTRL1);
+
+ dev_dbg(cdns->dev, "wait xhci_power_on_ready\n");
+
+ value = readl(cdns->none_core_regs + USB3_CORE_STATUS);
+ timeout_us = 100000;
+ while (!(value & HOST_POWER_ON_READY) && timeout_us-- > 0) {
+ value = readl(cdns->none_core_regs + USB3_CORE_STATUS);
+ udelay(1);
+ }
+
+ if (timeout_us <= 0)
+ dev_err(cdns->dev, "wait xhci_power_on_ready timeout\n");
+
+ mdelay(1);
+
+ dev_dbg(cdns->dev, "switch to host role successfully\n");
+ } else { /* gadget mode */
+ value = readl(cdns->none_core_regs + USB3_CORE_CTRL1);
+ value = (value & ~MODE_STRAP_MASK) | DEV_MODE;
+ writel(value, cdns->none_core_regs + USB3_CORE_CTRL1);
+ value &= ~PHYAHB_SW_RESET;
+ writel(value, cdns->none_core_regs + USB3_CORE_CTRL1);
+
+ cdns3_usb_phy_init(cdns->phy_regs);
+ value = readl(cdns->none_core_regs + USB3_INT_REG);
+ value |= DEV_INT_EN;
+ writel(value, cdns->none_core_regs + USB3_INT_REG);
+
+ value = readl(cdns->none_core_regs + USB3_CORE_CTRL1);
+ value &= ~ALL_SW_RESET;
+ writel(value, cdns->none_core_regs + USB3_CORE_CTRL1);
+
+ dev_dbg(cdns->dev, "wait gadget_power_on_ready\n");
+
+ value = readl(cdns->none_core_regs + USB3_CORE_STATUS);
+ timeout_us = 100000;
+ while (!(value & DEV_POWER_ON_READY) && timeout_us-- > 0) {
+ value = readl(cdns->none_core_regs + USB3_CORE_STATUS);
+ udelay(1);
+ }
+
+ if (timeout_us <= 0)
+ dev_err(cdns->dev,
+ "wait gadget_power_on_ready timeout\n");
+
+ mdelay(1);
+
+ dev_dbg(cdns->dev, "switch to gadget role successfully\n");
+ }
+}
+
+static enum cdns3_roles cdns3_get_role(struct cdns3 *cdns)
+{
+ if (cdns->roles[CDNS3_ROLE_HOST] && cdns->roles[CDNS3_ROLE_GADGET]) {
+ if (extcon_get_state(cdns->extcon, EXTCON_USB_HOST))
+ return CDNS3_ROLE_HOST;
+ else if (extcon_get_state(cdns->extcon, EXTCON_USB))
+ return CDNS3_ROLE_GADGET;
+ else
+ return CDNS3_ROLE_END;
+ } else {
+ return cdns->roles[CDNS3_ROLE_HOST]
+ ? CDNS3_ROLE_HOST
+ : CDNS3_ROLE_GADGET;
+ }
+}
+
+/**
+ * cdns3_core_init_role - initialize role of operation
+ * @cdns: Pointer to cdns3 structure
+ *
+ * Returns 0 on success otherwise negative errno
+ */
+static int cdns3_core_init_role(struct cdns3 *cdns)
+{
+ struct device *dev = cdns->dev;
+ enum usb_dr_mode dr_mode = usb_get_dr_mode(dev);
+
+ cdns->role = CDNS3_ROLE_END;
+ if (dr_mode == USB_DR_MODE_UNKNOWN)
+ dr_mode = USB_DR_MODE_OTG;
+
+ if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) {
+ if (cdns3_host_init(cdns))
+ dev_info(dev, "doesn't support host\n");
+ }
+
+ if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) {
+ if (cdns3_gadget_init(cdns))
+ dev_info(dev, "doesn't support gadget\n");
+ }
+
+ if (!cdns->roles[CDNS3_ROLE_HOST] && !cdns->roles[CDNS3_ROLE_GADGET]) {
+ dev_err(dev, "no supported roles\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/**
+ * cdns3_irq - interrupt handler for cdns3 core device
+ *
+ * @irq: irq number for cdns3 core device
+ * @data: structure of cdns3
+ *
+ * Returns IRQ_HANDLED or IRQ_NONE
+ */
+static irqreturn_t cdns3_irq(int irq, void *data)
+{
+ struct cdns3 *cdns = data;
+ irqreturn_t ret = IRQ_NONE;
+
+ /* Handle device/host interrupt */
+ if (cdns->role != CDNS3_ROLE_END)
+ ret = cdns3_role(cdns)->irq(cdns);
+
+ return ret;
+}
+
+static int cdns3_get_clks(struct device *dev)
+{
+ struct cdns3 *cdns = dev_get_drvdata(dev);
+ int ret = 0;
+
+ cdns->cdns3_clks[0] = devm_clk_get(dev, "usb3_lpm_clk");
+ if (IS_ERR(cdns->cdns3_clks[0])) {
+ ret = PTR_ERR(cdns->cdns3_clks[0]);
+ dev_err(dev, "Failed to get usb3_lpm_clk, err=%d\n", ret);
+ return ret;
+ }
+
+ cdns->cdns3_clks[1] = devm_clk_get(dev, "usb3_bus_clk");
+ if (IS_ERR(cdns->cdns3_clks[1])) {
+ ret = PTR_ERR(cdns->cdns3_clks[1]);
+ dev_err(dev, "Failed to get usb3_bus_clk, err=%d\n", ret);
+ return ret;
+ }
+
+ cdns->cdns3_clks[2] = devm_clk_get(dev, "usb3_aclk");
+ if (IS_ERR(cdns->cdns3_clks[2])) {
+ ret = PTR_ERR(cdns->cdns3_clks[2]);
+ dev_err(dev, "Failed to get usb3_aclk, err=%d\n", ret);
+ return ret;
+ }
+
+ cdns->cdns3_clks[3] = devm_clk_get(dev, "usb3_ipg_clk");
+ if (IS_ERR(cdns->cdns3_clks[3])) {
+ ret = PTR_ERR(cdns->cdns3_clks[3]);
+ dev_err(dev, "Failed to get usb3_ipg_clk, err=%d\n", ret);
+ return ret;
+ }
+
+ cdns->cdns3_clks[4] = devm_clk_get(dev, "usb3_core_pclk");
+ if (IS_ERR(cdns->cdns3_clks[4])) {
+ ret = PTR_ERR(cdns->cdns3_clks[4]);
+ dev_err(dev, "Failed to get usb3_core_pclk, err=%d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int cdns3_prepare_enable_clks(struct device *dev)
+{
+ struct cdns3 *cdns = dev_get_drvdata(dev);
+ int i, j, ret = 0;
+
+ for (i = 0; i < CDNS3_NUM_OF_CLKS; i++) {
+ ret = clk_prepare_enable(cdns->cdns3_clks[i]);
+ if (ret) {
+ dev_err(dev,
+ "Failed to prepare/enable cdns3 clk, err=%d\n",
+ ret);
+ goto err;
+ }
+ }
+
+ return ret;
+err:
+ for (j = i; j > 0; j--)
+ clk_disable_unprepare(cdns->cdns3_clks[j - 1]);
+
+ return ret;
+}
+
+static void cdns3_disable_unprepare_clks(struct device *dev)
+{
+ struct cdns3 *cdns = dev_get_drvdata(dev);
+ int i;
+
+ for (i = CDNS3_NUM_OF_CLKS - 1; i >= 0; i--)
+ clk_disable_unprepare(cdns->cdns3_clks[i]);
+}
+
+static void cdns3_remove_roles(struct cdns3 *cdns)
+{
+ cdns3_gadget_remove(cdns);
+ cdns3_host_remove(cdns);
+}
+
+static int cdsn3_do_role_switch(struct cdns3 *cdns, enum cdns3_roles role)
+{
+ dev_dbg(cdns->dev, "current role is %d, switch to %d\n",
+ cdns->role, role);
+
+ if (cdns->role == role)
+ return 0;
+
+ cdns3_role_stop(cdns);
+ if (role == CDNS3_ROLE_END)
+ return 0;
+
+ cdns_set_role(cdns, role);
+ return cdns3_role_start(cdns, role);
+}
+
+/**
+ * cdns3_role_switch - work queue handler for role switch
+ *
+ * @work: work queue item structure
+ *
+ */
+static void cdns3_role_switch(struct work_struct *work)
+{
+ struct cdns3 *cdns = container_of(work, struct cdns3,
+ role_switch_wq);
+ bool is_device, is_host;
+
+ is_device = extcon_get_state(cdns->extcon, EXTCON_USB_HOST);
+ is_host = extcon_get_state(cdns->extcon, EXTCON_USB);
+
+ disable_irq(cdns->irq);
+ if (is_device)
+ cdsn3_do_role_switch(cdns, CDNS3_ROLE_HOST);
+ else if (is_host)
+ cdsn3_do_role_switch(cdns, CDNS3_ROLE_GADGET);
+ else
+ cdsn3_do_role_switch(cdns, CDNS3_ROLE_END);
+ enable_irq(cdns->irq);
+}
+
+static int cdns3_extcon_notifier(struct notifier_block *nb, unsigned long event,
+ void *ptr)
+{
+ struct cdns3 *cdns = container_of(nb, struct cdns3, extcon_nb);
+
+ queue_work(system_power_efficient_wq, &cdns->role_switch_wq);
+
+ return NOTIFY_DONE;
+}
+
+static int cdns3_register_extcon(struct cdns3 *cdns)
+{
+ struct extcon_dev *extcon;
+ struct device *dev = cdns->dev;
+ int ret;
+
+ if (of_property_read_bool(dev->of_node, "extcon")) {
+ extcon = extcon_get_edev_by_phandle(dev, 0);
+ if (IS_ERR(extcon))
+ return PTR_ERR(extcon);
+
+ ret = devm_extcon_register_notifier(dev, extcon,
+ EXTCON_USB_HOST, &cdns->extcon_nb);
+ if (ret < 0) {
+ dev_err(dev, "register Host Connector failed\n");
+ return ret;
+ }
+
+ ret = devm_extcon_register_notifier(dev, extcon,
+ EXTCON_USB, &cdns->extcon_nb);
+ if (ret < 0) {
+ dev_err(dev, "register Device Connector failed\n");
+ return ret;
+ }
+
+ cdns->extcon = extcon;
+ cdns->extcon_nb.notifier_call = cdns3_extcon_notifier;
+ }
+
+ return 0;
+}
+
+/**
+ * cdns3_probe - probe for cdns3 core device
+ * @pdev: Pointer to cdns3 core platform device
+ *
+ * Returns 0 on success otherwise negative errno
+ */
+static int cdns3_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ struct cdns3 *cdns;
+ void __iomem *regs;
+ int ret;
+
+ cdns = devm_kzalloc(dev, sizeof(*cdns), GFP_KERNEL);
+ if (!cdns)
+ return -ENOMEM;
+
+ cdns->dev = dev;
+ platform_set_drvdata(pdev, cdns);
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(dev, "missing IRQ\n");
+ return -ENODEV;
+ }
+ cdns->irq = res->start;
+
+ /*
+ * Request memory region
+ * region-0: nxp wrap registers
+ * region-1: xHCI
+ * region-2: Peripheral
+ * region-3: PHY registers
+ */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+ cdns->none_core_regs = regs;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+ cdns->xhci_regs = regs;
+ cdns->xhci_res = res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+ cdns->dev_regs = regs;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+ regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+ cdns->phy_regs = regs;
+
+ ret = cdns3_get_clks(dev);
+ if (ret)
+ return ret;
+
+ ret = cdns3_prepare_enable_clks(dev);
+ if (ret)
+ return ret;
+
+ cdns->usbphy = devm_usb_get_phy_by_phandle(dev, "cdns3,usbphy", 0);
+ if (IS_ERR(cdns->usbphy)) {
+ ret = PTR_ERR(cdns->usbphy);
+ if (ret == -ENODEV)
+ ret = -EINVAL;
+ goto err1;
+ }
+
+ ret = usb_phy_init(cdns->usbphy);
+ if (ret)
+ goto err1;
+
+ ret = cdns3_register_extcon(cdns);
+ if (ret)
+ goto err2;
+
+ ret = cdns3_core_init_role(cdns);
+ if (ret)
+ goto err2;
+
+ cdns->role = cdns3_get_role(cdns);
+ dev_dbg(dev, "the init role is %d\n", cdns->role);
+ cdns_set_role(cdns, cdns->role);
+ ret = cdns3_role_start(cdns, cdns->role);
+ if (ret) {
+ dev_err(dev, "can't start %s role\n",
+ cdns3_role(cdns)->name);
+ goto err3;
+ }
+
+ ret = devm_request_irq(dev, cdns->irq, cdns3_irq, IRQF_SHARED,
+ dev_name(dev), cdns);
+ if (ret)
+ goto err4;
+
+ INIT_WORK(&cdns->role_switch_wq, cdns3_role_switch);
+ dev_dbg(dev, "Cadence USB3 core: probe succeed\n");
+
+ return 0;
+
+err4:
+ cdns3_role_stop(cdns);
+err3:
+ cdns3_remove_roles(cdns);
+err2:
+ usb_phy_shutdown(cdns->usbphy);
+err1:
+ cdns3_disable_unprepare_clks(dev);
+ return ret;
+}
+
+/**
+ * cdns3_remove - unbind our drd driver and clean up
+ * @pdev: Pointer to Linux platform device
+ *
+ * Returns 0 on success otherwise negative errno
+ */
+static int cdns3_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id of_cdns3_match[] = {
+ { .compatible = "Cadence,usb3" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, of_cdns3_match);
+#endif
+
+static struct platform_driver cdns3_driver = {
+ .probe = cdns3_probe,
+ .remove = cdns3_remove,
+ .driver = {
+ .name = "cdns-usb3",
+ .of_match_table = of_match_ptr(of_cdns3_match),
+ },
+};
+
+static int __init cdns3_driver_platform_register(void)
+{
+ cdns3_host_driver_init();
+ return platform_driver_register(&cdns3_driver);
+}
+module_init(cdns3_driver_platform_register);
+
+static void __exit cdns3_driver_platform_unregister(void)
+{
+ platform_driver_unregister(&cdns3_driver);
+}
+module_exit(cdns3_driver_platform_unregister);
+
+MODULE_ALIAS("platform:cdns3");
+MODULE_AUTHOR("Peter Chen ");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Cadence USB3 DRD Controller Driver");
diff --git a/drivers/usb/cdns3/core.h b/drivers/usb/cdns3/core.h
new file mode 100644
index 000000000000..793d5ccc6b4c
--- /dev/null
+++ b/drivers/usb/cdns3/core.h
@@ -0,0 +1,119 @@
+/**
+ * core.h - Cadence USB3 DRD Controller Core header file
+ *
+ * Copyright 2017 NXP
+ *
+ * Authors: Peter Chen
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef __DRIVERS_USB_CDNS3_CORE_H
+#define __DRIVERS_USB_CDNS3_CORE_H
+
+struct cdns3;
+enum cdns3_roles {
+ CDNS3_ROLE_HOST = 0,
+ CDNS3_ROLE_GADGET,
+ CDNS3_ROLE_END,
+};
+
+/**
+ * struct cdns3_role_driver - host/gadget role driver
+ * @start: start this role
+ * @stop: stop this role
+ * @irq: irq handler for this role
+ * @name: role name string (host/gadget)
+ */
+struct cdns3_role_driver {
+ int (*start)(struct cdns3 *);
+ void (*stop)(struct cdns3 *);
+ irqreturn_t (*irq)(struct cdns3 *);
+ const char *name;
+};
+
+#define CDNS3_NUM_OF_CLKS 5
+/**
+ * struct cdns3 - Representation of Cadence USB3 DRD controller.
+ * @dev: pointer to Cadence device struct
+ * @xhci_regs: pointer to base of xhci registers
+ * @xhci_res: the resource for xhci
+ * @dev_regs: pointer to base of dev registers
+ * @none_core_regs: pointer to base of nxp wrapper registers
+ * @phy_regs: pointer to base of phy registers
+ * @irq: irq number for controller
+ * @roles: array of supported roles for this controller
+ * @role: current role
+ * @host_dev: the child host device pointer for cdns3 core
+ * @gadget_dev: the child gadget device pointer for cdns3 core
+ * @usbphy: usbphy for this controller
+ * @cdns3_clks: Clock pointer array for cdns3 core
+ * @extcon: Type-C extern connector
+ * @extcon_nb: notifier block for Type-C extern connector
+ * @role_switch_wq: work queue item for role switch
+ */
+struct cdns3 {
+ struct device *dev;
+ void __iomem *xhci_regs;
+ struct resource *xhci_res;
+ struct usbss_dev_register_block_type __iomem *dev_regs;
+ void __iomem *none_core_regs;
+ int irq;
+ struct cdns3_role_driver *roles[CDNS3_ROLE_END];
+ enum cdns3_roles role;
+ struct device *host_dev;
+ struct device *gadget_dev;
+ void __iomem *phy_regs;
+ struct usb_phy *usbphy;
+ struct clk *cdns3_clks[CDNS3_NUM_OF_CLKS];
+ struct extcon_dev *extcon;
+ struct notifier_block extcon_nb;
+ struct work_struct role_switch_wq;
+};
+
+static inline struct cdns3_role_driver *cdns3_role(struct cdns3 *cdns)
+{
+ WARN_ON(cdns->role >= CDNS3_ROLE_END || !cdns->roles[cdns->role]);
+ return cdns->roles[cdns->role];
+}
+
+static inline int cdns3_role_start(struct cdns3 *cdns, enum cdns3_roles role)
+{
+ int ret;
+
+ if (role >= CDNS3_ROLE_END)
+ return 0;
+
+ if (!cdns->roles[role])
+ return -ENXIO;
+
+ ret = cdns->roles[role]->start(cdns);
+ if (!ret)
+ cdns->role = role;
+
+ return ret;
+}
+
+static inline void cdns3_role_stop(struct cdns3 *cdns)
+{
+ enum cdns3_roles role = cdns->role;
+
+ if (role == CDNS3_ROLE_END)
+ return;
+
+ cdns->role = CDNS3_ROLE_END;
+
+ cdns->roles[role]->stop(cdns);
+}
+
+#endif /* __DRIVERS_USB_CDNS3_CORE_H */
diff --git a/drivers/usb/cdns3/dev-regs-macro.h b/drivers/usb/cdns3/dev-regs-macro.h
new file mode 100644
index 000000000000..e87e05352965
--- /dev/null
+++ b/drivers/usb/cdns3/dev-regs-macro.h
@@ -0,0 +1,891 @@
+/**
+ * dev-regs-macro.h - Cadence USB3 Device register definition
+ *
+ * Copyright (C) 2016 Cadence Design Systems - http://www.cadence.com
+ * Copyright 2017 NXP
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __REG_USBSS_DEV_ADDR_MAP_MACRO_H__
+#define __REG_USBSS_DEV_ADDR_MAP_MACRO_H__
+
+
+/* macros for BlueprintGlobalNameSpace::USB_CONF */
+#ifndef __USB_CONF_MACRO__
+#define __USB_CONF_MACRO__
+
+/* macros for field CFGRST */
+#define USB_CONF__CFGRST__MASK 0x00000001U
+#define USB_CONF__CFGSET__MASK 0x00000002U
+#define USB_CONF__USB3DIS__MASK 0x00000008U
+#define USB_CONF__DEVEN__MASK 0x00004000U
+#define USB_CONF__L1EN__MASK 0x00010000U
+#define USB_CONF__L1DS__MASK 0x00020000U
+#define USB_CONF__CLK2OFFDS__MASK 0x00080000U
+#define USB_CONF__U1EN__MASK 0x01000000U
+#define USB_CONF__U1DS__MASK 0x02000000U
+#define USB_CONF__U2EN__MASK 0x04000000U
+#define USB_CONF__U2DS__MASK 0x08000000U
+#endif /* __USB_CONF_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_conf */
+#ifndef __USB_STS_MACRO__
+#define __USB_STS_MACRO__
+
+/* macros for field CFGSTS */
+#define USB_STS__CFGSTS__MASK 0x00000001U
+#define USB_STS__USBSPEED__READ(src) (((uint32_t)(src) & 0x00000070U) >> 4)
+
+/* macros for field ENDIAN_MIRROR */
+#define USB_STS__LPMST__READ(src) (((uint32_t)(src) & 0x000c0000U) >> 18)
+
+/* macros for field USB2CONS */
+#define USB_STS__U1ENS__MASK 0x01000000U
+#define USB_STS__U2ENS__MASK 0x02000000U
+#define USB_STS__LST__READ(src) (((uint32_t)(src) & 0x3c000000U) >> 26)
+
+/* macros for field DMAOFF */
+#endif /* __USB_STS_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_sts */
+#ifndef __USB_CMD_MACRO__
+#define __USB_CMD_MACRO__
+
+/* macros for field SET_ADDR */
+#define USB_CMD__SET_ADDR__MASK 0x00000001U
+#define USB_CMD__FADDR__WRITE(src) (((uint32_t)(src) << 1) & 0x000000feU)
+#endif /* __USB_CMD_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_cmd */
+#ifndef __USB_ITPN_MACRO__
+#define __USB_ITPN_MACRO__
+
+/* macros for field ITPN */
+#endif /* __USB_ITPN_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_iptn */
+#ifndef __USB_LPM_MACRO__
+#define __USB_LPM_MACRO__
+
+/* macros for field HIRD */
+#endif /* __USB_LPM_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_lpm */
+#ifndef __USB_IEN_MACRO__
+#define __USB_IEN_MACRO__
+
+/* macros for field CONIEN */
+#define USB_IEN__CONIEN__MASK 0x00000001U
+#define USB_IEN__DISIEN__MASK 0x00000002U
+#define USB_IEN__UWRESIEN__MASK 0x00000004U
+#define USB_IEN__UHRESIEN__MASK 0x00000008U
+#define USB_IEN__U3EXTIEN__MASK 0x00000020U
+#define USB_IEN__CON2IEN__MASK 0x00010000U
+#define USB_IEN__U2RESIEN__MASK 0x00040000U
+#define USB_IEN__L2ENTIEN__MASK 0x00100000U
+#define USB_IEN__L2EXTIEN__MASK 0x00200000U
+#endif /* __USB_IEN_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_ien */
+#ifndef __USB_ISTS_MACRO__
+#define __USB_ISTS_MACRO__
+
+/* macros for field CONI */
+#define USB_ISTS__CONI__SHIFT 0
+#define USB_ISTS__DISI__SHIFT 1
+#define USB_ISTS__UWRESI__SHIFT 2
+#define USB_ISTS__UHRESI__SHIFT 3
+#define USB_ISTS__U3EXTI__SHIFT 5
+#define USB_ISTS__CON2I__SHIFT 16
+#define USB_ISTS__DIS2I__SHIFT 17
+#define USB_ISTS__DIS2I__MASK 0x00020000U
+#define USB_ISTS__U2RESI__SHIFT 18
+#define USB_ISTS__L2ENTI__SHIFT 20
+#define USB_ISTS__L2EXTI__SHIFT 21
+#endif /* __USB_ISTS_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_ists */
+#ifndef __EP_SEL_MACRO__
+#define __EP_SEL_MACRO__
+
+/* macros for field EPNO */
+#endif /* __EP_SEL_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.ep_sel */
+#ifndef __EP_TRADDR_MACRO__
+#define __EP_TRADDR_MACRO__
+
+/* macros for field TRADDR */
+#define EP_TRADDR__TRADDR__WRITE(src) ((uint32_t)(src) & 0xffffffffU)
+#endif /* __EP_TRADDR_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.ep_traddr */
+#ifndef __EP_CFG_MACRO__
+#define __EP_CFG_MACRO__
+
+/* macros for field ENABLE */
+#define EP_CFG__ENABLE__MASK 0x00000001U
+#define EP_CFG__EPTYPE__WRITE(src) (((uint32_t)(src) << 1) & 0x00000006U)
+#define EP_CFG__MAXBURST__WRITE(src) (((uint32_t)(src) << 8) & 0x00000f00U)
+#define EP_CFG__MAXPKTSIZE__WRITE(src) (((uint32_t)(src) << 16) & 0x07ff0000U)
+#define EP_CFG__BUFFERING__WRITE(src) (((uint32_t)(src) << 27) & 0xf8000000U)
+#endif /* __EP_CFG_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.ep_cfg */
+#ifndef __EP_CMD_MACRO__
+#define __EP_CMD_MACRO__
+
+/* macros for field EPRST */
+#define EP_CMD__EPRST__MASK 0x00000001U
+#define EP_CMD__SSTALL__MASK 0x00000002U
+#define EP_CMD__CSTALL__MASK 0x00000004U
+#define EP_CMD__ERDY__MASK 0x00000008U
+#define EP_CMD__REQ_CMPL__MASK 0x00000020U
+#define EP_CMD__DRDY__MASK 0x00000040U
+#define EP_CMD__DFLUSH__MASK 0x00000080U
+#endif /* __EP_CMD_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.ep_cmd */
+#ifndef __EP_STS_MACRO__
+#define __EP_STS_MACRO__
+
+/* macros for field SETUP */
+#define EP_STS__SETUP__MASK 0x00000001U
+#define EP_STS__STALL__MASK 0x00000002U
+#define EP_STS__IOC__MASK 0x00000004U
+#define EP_STS__ISP__MASK 0x00000008U
+#define EP_STS__DESCMIS__MASK 0x00000010U
+#define EP_STS__TRBERR__MASK 0x00000080U
+#define EP_STS__NRDY__MASK 0x00000100U
+#define EP_STS__DBUSY__MASK 0x00000200U
+#define EP_STS__OUTSMM__MASK 0x00004000U
+#define EP_STS__ISOERR__MASK 0x00008000U
+#endif /* __EP_STS_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.ep_sts */
+#ifndef __EP_STS_SID_MACRO__
+#define __EP_STS_SID_MACRO__
+
+/* macros for field SID */
+#endif /* __EP_STS_SID_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.ep_sts_sid */
+#ifndef __EP_STS_EN_MACRO__
+#define __EP_STS_EN_MACRO__
+
+/* macros for field SETUPEN */
+#define EP_STS_EN__SETUPEN__MASK 0x00000001U
+#define EP_STS_EN__DESCMISEN__MASK 0x00000010U
+#define EP_STS_EN__TRBERREN__MASK 0x00000080U
+#endif /* __EP_STS_EN_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.ep_sts_en */
+#ifndef __DRBL_MACRO__
+#define __DRBL_MACRO__
+
+/* macros for field DRBL0O */
+#endif /* __DRBL_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.drbl */
+#ifndef __EP_IEN_MACRO__
+#define __EP_IEN_MACRO__
+
+/* macros for field EOUTEN0 */
+#define EP_IEN__EOUTEN0__MASK 0x00000001U
+#define EP_IEN__EINEN0__MASK 0x00010000U
+#endif /* __EP_IEN_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.ep_ien */
+#ifndef __EP_ISTS_MACRO__
+#define __EP_ISTS_MACRO__
+
+/* macros for field EOUT0 */
+#define EP_ISTS__EOUT0__MASK 0x00000001U
+#define EP_ISTS__EIN0__MASK 0x00010000U
+#endif /* __EP_ISTS_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.ep_ists */
+#ifndef __USB_PWR_MACRO__
+#define __USB_PWR_MACRO__
+
+/* macros for field PSO_EN */
+#endif /* __USB_PWR_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_pwr */
+#ifndef __USB_CONF2_MACRO__
+#define __USB_CONF2_MACRO__
+
+/* macros for field AHB_RETRY_EN */
+#endif /* __USB_CONF2_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_conf2 */
+#ifndef __USB_CAP1_MACRO__
+#define __USB_CAP1_MACRO__
+
+/* macros for field SFR_TYPE */
+#endif /* __USB_CAP1_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_cap1 */
+#ifndef __USB_CAP2_MACRO__
+#define __USB_CAP2_MACRO__
+
+/* macros for field ACTUAL_MEM_SIZE */
+#endif /* __USB_CAP2_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_cap2 */
+#ifndef __USB_CAP3_MACRO__
+#define __USB_CAP3_MACRO__
+
+/* macros for field EPOUT_N */
+#endif /* __USB_CAP3_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_cap3 */
+#ifndef __USB_CAP4_MACRO__
+#define __USB_CAP4_MACRO__
+
+/* macros for field EPOUTI_N */
+#endif /* __USB_CAP4_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_cap4 */
+#ifndef __USB_CAP5_MACRO__
+#define __USB_CAP5_MACRO__
+
+/* macros for field EPOUTI_N */
+#endif /* __USB_CAP5_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_cap5 */
+#ifndef __USB_CAP6_MACRO__
+#define __USB_CAP6_MACRO__
+
+/* macros for field VERSION */
+#endif /* __USB_CAP6_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_cap6 */
+#ifndef __USB_CPKT1_MACRO__
+#define __USB_CPKT1_MACRO__
+
+/* macros for field CPKT1 */
+#endif /* __USB_CPKT1_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_cpkt1 */
+#ifndef __USB_CPKT2_MACRO__
+#define __USB_CPKT2_MACRO__
+
+/* macros for field CPKT2 */
+#endif /* __USB_CPKT2_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_cpkt2 */
+#ifndef __USB_CPKT3_MACRO__
+#define __USB_CPKT3_MACRO__
+
+/* macros for field CPKT3 */
+#endif /* __USB_CPKT3_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_cpkt3 */
+#ifndef __CFG_REG1_MACRO__
+#define __CFG_REG1_MACRO__
+
+/* macros for field DEBOUNCER_CNT */
+#endif /* __CFG_REG1_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg1 */
+#ifndef __DBG_LINK1_MACRO__
+#define __DBG_LINK1_MACRO__
+
+/* macros for field LFPS_MIN_DET_U1_EXIT */
+#define DBG_LINK1__LFPS_MIN_GEN_U1_EXIT__WRITE(src) \
+ (((uint32_t)(src)\
+ << 8) & 0x0000ff00U)
+#define DBG_LINK1__LFPS_MIN_GEN_U1_EXIT_SET__MASK 0x02000000U
+#endif /* __DBG_LINK1_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.dbg_link1 */
+#ifndef __DBG_LINK2_MACRO__
+#define __DBG_LINK2_MACRO__
+
+/* macros for field RXEQTR_AVAL */
+#endif /* __DBG_LINK2_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.dbg_link2 */
+#ifndef __CFG_REG4_MACRO__
+#define __CFG_REG4_MACRO__
+
+/* macros for field RXDETECT_QUIET_TIMEOUT */
+#endif /* __CFG_REG4_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg4 */
+#ifndef __CFG_REG5_MACRO__
+#define __CFG_REG5_MACRO__
+
+/* macros for field U3_HDSK_FAIL_TIMEOUT */
+#endif /* __CFG_REG5_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg5 */
+#ifndef __CFG_REG6_MACRO__
+#define __CFG_REG6_MACRO__
+
+/* macros for field SSINACTIVE_QUIET_TIMEOUT */
+#endif /* __CFG_REG6_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg6 */
+#ifndef __CFG_REG7_MACRO__
+#define __CFG_REG7_MACRO__
+
+/* macros for field POLLING_LFPS_TIMEOUT */
+#endif /* __CFG_REG7_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg7 */
+#ifndef __CFG_REG8_MACRO__
+#define __CFG_REG8_MACRO__
+
+/* macros for field POLLING_ACTIVE_TIMEOUT */
+#endif /* __CFG_REG8_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg8 */
+#ifndef __CFG_REG9_MACRO__
+#define __CFG_REG9_MACRO__
+
+/* macros for field POLLING_IDLE_TIMEOUT */
+#endif /* __CFG_REG9_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg9 */
+#ifndef __CFG_REG10_MACRO__
+#define __CFG_REG10_MACRO__
+
+/* macros for field POLLING_CONF_TIMEOUT */
+#endif /* __CFG_REG10_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg10 */
+#ifndef __CFG_REG11_MACRO__
+#define __CFG_REG11_MACRO__
+
+/* macros for field RECOVERY_ACTIVE_TIMEOUT */
+#endif /* __CFG_REG11_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg11 */
+#ifndef __CFG_REG12_MACRO__
+#define __CFG_REG12_MACRO__
+
+/* macros for field RECOVERY_CONF_TIMEOUT */
+#endif /* __CFG_REG12_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg12 */
+#ifndef __CFG_REG13_MACRO__
+#define __CFG_REG13_MACRO__
+
+/* macros for field RECOVERY_IDLE_TIMEOUT */
+#endif /* __CFG_REG13_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg13 */
+#ifndef __CFG_REG14_MACRO__
+#define __CFG_REG14_MACRO__
+
+/* macros for field HOTRESET_ACTIVE_TIMEOUT */
+#endif /* __CFG_REG14_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg14 */
+#ifndef __CFG_REG15_MACRO__
+#define __CFG_REG15_MACRO__
+
+/* macros for field HOTRESET_EXIT_TIMEOUT */
+#endif /* __CFG_REG15_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg15 */
+#ifndef __CFG_REG16_MACRO__
+#define __CFG_REG16_MACRO__
+
+/* macros for field LFPS_PING_REPEAT */
+#endif /* __CFG_REG16_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg16 */
+#ifndef __CFG_REG17_MACRO__
+#define __CFG_REG17_MACRO__
+
+/* macros for field PENDING_HP_TIMEOUT */
+#endif /* __CFG_REG17_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg17 */
+#ifndef __CFG_REG18_MACRO__
+#define __CFG_REG18_MACRO__
+
+/* macros for field CREDIT_HP_TIMEOUT */
+#endif /* __CFG_REG18_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg18 */
+#ifndef __CFG_REG19_MACRO__
+#define __CFG_REG19_MACRO__
+
+/* macros for field LUP_TIMEOUT */
+#endif /* __CFG_REG19_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg19 */
+#ifndef __CFG_REG20_MACRO__
+#define __CFG_REG20_MACRO__
+
+/* macros for field LDN_TIMEOUT */
+#endif /* __CFG_REG20_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg20 */
+#ifndef __CFG_REG21_MACRO__
+#define __CFG_REG21_MACRO__
+
+/* macros for field PM_LC_TIMEOUT */
+#endif /* __CFG_REG21_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg21 */
+#ifndef __CFG_REG22_MACRO__
+#define __CFG_REG22_MACRO__
+
+/* macros for field PM_ENTRY_TIMEOUT */
+#endif /* __CFG_REG22_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg22 */
+#ifndef __CFG_REG23_MACRO__
+#define __CFG_REG23_MACRO__
+
+/* macros for field UX_EXIT_TIMEOUT */
+#endif /* __CFG_REG23_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg23 */
+#ifndef __CFG_REG24_MACRO__
+#define __CFG_REG24_MACRO__
+
+/* macros for field LFPS_DET_RESET_MIN */
+#endif /* __CFG_REG24_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg24 */
+#ifndef __CFG_REG25_MACRO__
+#define __CFG_REG25_MACRO__
+
+/* macros for field LFPS_DET_RESET_MAX */
+#endif /* __CFG_REG25_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg25 */
+#ifndef __CFG_REG26_MACRO__
+#define __CFG_REG26_MACRO__
+
+/* macros for field LFPS_DET_POLLING_MIN */
+#endif /* __CFG_REG26_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg26 */
+#ifndef __CFG_REG27_MACRO__
+#define __CFG_REG27_MACRO__
+
+/* macros for field LFPS_DET_POLLING_MAX */
+#endif /* __CFG_REG27_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg27 */
+#ifndef __CFG_REG28_MACRO__
+#define __CFG_REG28_MACRO__
+
+/* macros for field LFPS_DET_PING_MIN */
+#endif /* __CFG_REG28_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg28 */
+#ifndef __CFG_REG29_MACRO__
+#define __CFG_REG29_MACRO__
+
+/* macros for field LFPS_DET_PING_MAX */
+#endif /* __CFG_REG29_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg29 */
+#ifndef __CFG_REG30_MACRO__
+#define __CFG_REG30_MACRO__
+
+/* macros for field LFPS_DET_U1EXIT_MIN */
+#endif /* __CFG_REG30_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg30 */
+#ifndef __CFG_REG31_MACRO__
+#define __CFG_REG31_MACRO__
+
+/* macros for field LFPS_DET_U1EXIT_MAX */
+#endif /* __CFG_REG31_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg31 */
+#ifndef __CFG_REG32_MACRO__
+#define __CFG_REG32_MACRO__
+
+/* macros for field LFPS_DET_U2EXIT_MIN */
+#endif /* __CFG_REG32_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg32 */
+#ifndef __CFG_REG33_MACRO__
+#define __CFG_REG33_MACRO__
+
+/* macros for field LFPS_DET_U2EXIT_MAX */
+#endif /* __CFG_REG33_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg33 */
+#ifndef __CFG_REG34_MACRO__
+#define __CFG_REG34_MACRO__
+
+/* macros for field LFPS_DET_U3EXIT_MIN */
+#endif /* __CFG_REG34_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg34 */
+#ifndef __CFG_REG35_MACRO__
+#define __CFG_REG35_MACRO__
+
+/* macros for field LFPS_DET_U3EXIT_MAX */
+#endif /* __CFG_REG35_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg35 */
+#ifndef __CFG_REG36_MACRO__
+#define __CFG_REG36_MACRO__
+
+/* macros for field LFPS_GEN_PING */
+#endif /* __CFG_REG36_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg36 */
+#ifndef __CFG_REG37_MACRO__
+#define __CFG_REG37_MACRO__
+
+/* macros for field LFPS_GEN_POLLING */
+#endif /* __CFG_REG37_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg37 */
+#ifndef __CFG_REG38_MACRO__
+#define __CFG_REG38_MACRO__
+
+/* macros for field LFPS_GEN_U1EXIT */
+#endif /* __CFG_REG38_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg38 */
+#ifndef __CFG_REG39_MACRO__
+#define __CFG_REG39_MACRO__
+
+/* macros for field LFPS_GEN_U3EXIT */
+#endif /* __CFG_REG39_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg39 */
+#ifndef __CFG_REG40_MACRO__
+#define __CFG_REG40_MACRO__
+
+/* macros for field LFPS_MIN_GEN_U1EXIT */
+#endif /* __CFG_REG40_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg40 */
+#ifndef __CFG_REG41_MACRO__
+#define __CFG_REG41_MACRO__
+
+/* macros for field LFPS_MIN_GEN_U2EXIT */
+#endif /* __CFG_REG41_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg41 */
+#ifndef __CFG_REG42_MACRO__
+#define __CFG_REG42_MACRO__
+
+/* macros for field LFPS_POLLING_REPEAT */
+#endif /* __CFG_REG42_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg42 */
+#ifndef __CFG_REG43_MACRO__
+#define __CFG_REG43_MACRO__
+
+/* macros for field LFPS_POLLING_MAX_TREPEAT */
+#endif /* __CFG_REG43_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg43 */
+#ifndef __CFG_REG44_MACRO__
+#define __CFG_REG44_MACRO__
+
+/* macros for field LFPS_POLLING_MIN_TREPEAT */
+#endif /* __CFG_REG44_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg44 */
+#ifndef __CFG_REG45_MACRO__
+#define __CFG_REG45_MACRO__
+
+/* macros for field ITP_WAKEUP_TIMEOUT */
+#endif /* __CFG_REG45_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg45 */
+#ifndef __CFG_REG46_MACRO__
+#define __CFG_REG46_MACRO__
+
+/* macros for field TSEQ_QUANTITY */
+#endif /* __CFG_REG46_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg46 */
+#ifndef __CFG_REG47_MACRO__
+#define __CFG_REG47_MACRO__
+
+/* macros for field ERDY_TIMEOUT_CNT */
+#endif /* __CFG_REG47_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg47 */
+#ifndef __CFG_REG48_MACRO__
+#define __CFG_REG48_MACRO__
+
+/* macros for field TWTRSTFS_J_CNT */
+#endif /* __CFG_REG48_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg48 */
+#ifndef __CFG_REG49_MACRO__
+#define __CFG_REG49_MACRO__
+
+/* macros for field TUCH_CNT */
+#endif /* __CFG_REG49_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg49 */
+#ifndef __CFG_REG50_MACRO__
+#define __CFG_REG50_MACRO__
+
+/* macros for field TWAITCHK_CNT */
+#endif /* __CFG_REG50_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg50 */
+#ifndef __CFG_REG51_MACRO__
+#define __CFG_REG51_MACRO__
+
+/* macros for field TWTFS_CNT */
+#endif /* __CFG_REG51_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg51 */
+#ifndef __CFG_REG52_MACRO__
+#define __CFG_REG52_MACRO__
+
+/* macros for field TWTREV_CNT */
+#endif /* __CFG_REG52_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg52 */
+#ifndef __CFG_REG53_MACRO__
+#define __CFG_REG53_MACRO__
+
+/* macros for field TWTRSTHS_CNT */
+#endif /* __CFG_REG53_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg53 */
+#ifndef __CFG_REG54_MACRO__
+#define __CFG_REG54_MACRO__
+
+/* macros for field TWTRSM_CNT */
+#endif /* __CFG_REG54_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg54 */
+#ifndef __CFG_REG55_MACRO__
+#define __CFG_REG55_MACRO__
+
+/* macros for field TDRSMUP_CNT */
+#endif /* __CFG_REG55_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg55 */
+#ifndef __CFG_REG56_MACRO__
+#define __CFG_REG56_MACRO__
+
+/* macros for field TOUTHS_CNT */
+#endif /* __CFG_REG56_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg56 */
+#ifndef __CFG_REG57_MACRO__
+#define __CFG_REG57_MACRO__
+
+/* macros for field LFPS_DEB_WIDTH */
+#endif /* __CFG_REG57_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg57 */
+#ifndef __CFG_REG58_MACRO__
+#define __CFG_REG58_MACRO__
+
+/* macros for field LFPS_GEN_U2EXIT */
+#endif /* __CFG_REG58_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg58 */
+#ifndef __CFG_REG59_MACRO__
+#define __CFG_REG59_MACRO__
+
+/* macros for field LFPS_MIN_GEN_U3EXIT */
+#endif /* __CFG_REG59_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg59 */
+#ifndef __CFG_REG60_MACRO__
+#define __CFG_REG60_MACRO__
+
+/* macros for field PORT_CONFIG_TIMEOUT */
+#endif /* __CFG_REG60_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg60 */
+#ifndef __CFG_REG61_MACRO__
+#define __CFG_REG61_MACRO__
+
+/* macros for field LFPS_POL_LFPS_TO_RXEQ */
+#endif /* __CFG_REG61_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg61 */
+#ifndef __CFG_REG62_MACRO__
+#define __CFG_REG62_MACRO__
+
+/* macros for field PHY_TX_LATENCY */
+#endif /* __CFG_REG62_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg62 */
+#ifndef __CFG_REG63_MACRO__
+#define __CFG_REG63_MACRO__
+
+/* macros for field U2_INACTIVITY_TMOUT */
+#endif /* __CFG_REG63_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg63 */
+#ifndef __CFG_REG64_MACRO__
+#define __CFG_REG64_MACRO__
+
+/* macros for field TFILTSE0 */
+#endif /* __CFG_REG64_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg64 */
+#ifndef __CFG_REG65_MACRO__
+#define __CFG_REG65_MACRO__
+
+/* macros for field TFILT */
+#endif /* __CFG_REG65_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg65 */
+#ifndef __CFG_REG66_MACRO__
+#define __CFG_REG66_MACRO__
+
+/* macros for field TWTRSTFS_SE0 */
+#endif /* __CFG_REG66_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg66 */
+#ifndef __DMA_AXI_CTRL_MACRO__
+#define __DMA_AXI_CTRL_MACRO__
+
+/* macros for field MAWPROT */
+#endif /* __DMA_AXI_CTRL_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.dma_axi_ctrl */
+#ifndef __DMA_AXI_ID_MACRO__
+#define __DMA_AXI_ID_MACRO__
+
+/* macros for field MAW_ID */
+#endif /* __DMA_AXI_ID_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.dma_axi_id */
+#ifndef __DMA_AXI_CAP_MACRO__
+#define __DMA_AXI_CAP_MACRO__
+
+/* macros for field RESERVED0 */
+#endif /* __DMA_AXI_CAP_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.dma_axi_cap */
+#ifndef __DMA_AXI_CTRL0_MACRO__
+#define __DMA_AXI_CTRL0_MACRO__
+
+/* macros for field B_MAX */
+#endif /* __DMA_AXI_CTRL0_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.dma_axi_ctrl0 */
+#ifndef __DMA_AXI_CTRL1_MACRO__
+#define __DMA_AXI_CTRL1_MACRO__
+
+/* macros for field ROT */
+#endif /* __DMA_AXI_CTRL1_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.dma_axi_ctrl1 */
+#endif /* __REG_USBSS_DEV_ADDR_MAP_MACRO_H__ */
diff --git a/drivers/usb/cdns3/dev-regs-map.h b/drivers/usb/cdns3/dev-regs-map.h
new file mode 100644
index 000000000000..ef9cfe2ff342
--- /dev/null
+++ b/drivers/usb/cdns3/dev-regs-map.h
@@ -0,0 +1,126 @@
+/**
+ * dev-regs-map.h - Cadence USB3 Device register map definition
+ *
+ * Copyright (C) 2016 Cadence Design Systems - http://www.cadence.com
+ * Copyright 2017 NXP
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+
+#ifndef __REG_USBSS_DEV_ADDR_MAP_H__
+#define __REG_USBSS_DEV_ADDR_MAP_H__
+
+#include "dev-regs-macro.h"
+
+struct usbss_dev_register_block_type {
+ uint32_t usb_conf; /* 0x0 - 0x4 */
+ uint32_t usb_sts; /* 0x4 - 0x8 */
+ uint32_t usb_cmd; /* 0x8 - 0xc */
+ uint32_t usb_iptn; /* 0xc - 0x10 */
+ uint32_t usb_lpm; /* 0x10 - 0x14 */
+ uint32_t usb_ien; /* 0x14 - 0x18 */
+ uint32_t usb_ists; /* 0x18 - 0x1c */
+ uint32_t ep_sel; /* 0x1c - 0x20 */
+ uint32_t ep_traddr; /* 0x20 - 0x24 */
+ uint32_t ep_cfg; /* 0x24 - 0x28 */
+ uint32_t ep_cmd; /* 0x28 - 0x2c */
+ uint32_t ep_sts; /* 0x2c - 0x30 */
+ uint32_t ep_sts_sid; /* 0x30 - 0x34 */
+ uint32_t ep_sts_en; /* 0x34 - 0x38 */
+ uint32_t drbl; /* 0x38 - 0x3c */
+ uint32_t ep_ien; /* 0x3c - 0x40 */
+ uint32_t ep_ists; /* 0x40 - 0x44 */
+ uint32_t usb_pwr; /* 0x44 - 0x48 */
+ uint32_t usb_conf2; /* 0x48 - 0x4c */
+ uint32_t usb_cap1; /* 0x4c - 0x50 */
+ uint32_t usb_cap2; /* 0x50 - 0x54 */
+ uint32_t usb_cap3; /* 0x54 - 0x58 */
+ uint32_t usb_cap4; /* 0x58 - 0x5c */
+ uint32_t usb_cap5; /* 0x5c - 0x60 */
+ uint32_t PAD2_73; /* 0x60 - 0x64 */
+ uint32_t usb_cpkt1; /* 0x64 - 0x68 */
+ uint32_t usb_cpkt2; /* 0x68 - 0x6c */
+ uint32_t usb_cpkt3; /* 0x6c - 0x70 */
+ char pad__0[0x90]; /* 0x70 - 0x100 */
+ uint32_t PAD2_78; /* 0x100 - 0x104 */
+ uint32_t dbg_link1; /* 0x104 - 0x108 */
+ uint32_t PAD2_80; /* 0x108 - 0x10c */
+ uint32_t PAD2_81; /* 0x10c - 0x110 */
+ uint32_t PAD2_82; /* 0x110 - 0x114 */
+ uint32_t PAD2_83; /* 0x114 - 0x118 */
+ uint32_t PAD2_84; /* 0x118 - 0x11c */
+ uint32_t PAD2_85; /* 0x11c - 0x120 */
+ uint32_t PAD2_86; /* 0x120 - 0x124 */
+ uint32_t PAD2_87; /* 0x124 - 0x128 */
+ uint32_t PAD2_88; /* 0x128 - 0x12c */
+ uint32_t PAD2_89; /* 0x12c - 0x130 */
+ uint32_t PAD2_90; /* 0x130 - 0x134 */
+ uint32_t PAD2_91; /* 0x134 - 0x138 */
+ uint32_t PAD2_92; /* 0x138 - 0x13c */
+ uint32_t PAD2_93; /* 0x13c - 0x140 */
+ uint32_t PAD2_94; /* 0x140 - 0x144 */
+ uint32_t PAD2_95; /* 0x144 - 0x148 */
+ uint32_t PAD2_96; /* 0x148 - 0x14c */
+ uint32_t PAD2_97; /* 0x14c - 0x150 */
+ uint32_t PAD2_98; /* 0x150 - 0x154 */
+ uint32_t PAD2_99; /* 0x154 - 0x158 */
+ uint32_t PAD2_100; /* 0x158 - 0x15c */
+ uint32_t PAD2_101; /* 0x15c - 0x160 */
+ uint32_t PAD2_102; /* 0x160 - 0x164 */
+ uint32_t PAD2_103; /* 0x164 - 0x168 */
+ uint32_t PAD2_104; /* 0x168 - 0x16c */
+ uint32_t PAD2_105; /* 0x16c - 0x170 */
+ uint32_t PAD2_106; /* 0x170 - 0x174 */
+ uint32_t PAD2_107; /* 0x174 - 0x178 */
+ uint32_t PAD2_108; /* 0x178 - 0x17c */
+ uint32_t PAD2_109; /* 0x17c - 0x180 */
+ uint32_t PAD2_110; /* 0x180 - 0x184 */
+ uint32_t PAD2_111; /* 0x184 - 0x188 */
+ uint32_t PAD2_112; /* 0x188 - 0x18c */
+ char pad__1[0x20]; /* 0x18c - 0x1ac */
+ uint32_t PAD2_114; /* 0x1ac - 0x1b0 */
+ uint32_t PAD2_115; /* 0x1b0 - 0x1b4 */
+ uint32_t PAD2_116; /* 0x1b4 - 0x1b8 */
+ uint32_t PAD2_117; /* 0x1b8 - 0x1bc */
+ uint32_t PAD2_118; /* 0x1bc - 0x1c0 */
+ uint32_t PAD2_119; /* 0x1c0 - 0x1c4 */
+ uint32_t PAD2_120; /* 0x1c4 - 0x1c8 */
+ uint32_t PAD2_121; /* 0x1c8 - 0x1cc */
+ uint32_t PAD2_122; /* 0x1cc - 0x1d0 */
+ uint32_t PAD2_123; /* 0x1d0 - 0x1d4 */
+ uint32_t PAD2_124; /* 0x1d4 - 0x1d8 */
+ uint32_t PAD2_125; /* 0x1d8 - 0x1dc */
+ uint32_t PAD2_126; /* 0x1dc - 0x1e0 */
+ uint32_t PAD2_127; /* 0x1e0 - 0x1e4 */
+ uint32_t PAD2_128; /* 0x1e4 - 0x1e8 */
+ uint32_t PAD2_129; /* 0x1e8 - 0x1ec */
+ uint32_t PAD2_130; /* 0x1ec - 0x1f0 */
+ uint32_t PAD2_131; /* 0x1f0 - 0x1f4 */
+ uint32_t PAD2_132; /* 0x1f4 - 0x1f8 */
+ uint32_t PAD2_133; /* 0x1f8 - 0x1fc */
+ uint32_t PAD2_134; /* 0x1fc - 0x200 */
+ uint32_t PAD2_135; /* 0x200 - 0x204 */
+ uint32_t PAD2_136; /* 0x204 - 0x208 */
+ uint32_t PAD2_137; /* 0x208 - 0x20c */
+ uint32_t PAD2_138; /* 0x20c - 0x210 */
+ uint32_t PAD2_139; /* 0x210 - 0x214 */
+ uint32_t PAD2_140; /* 0x214 - 0x218 */
+ uint32_t PAD2_141; /* 0x218 - 0x21c */
+ uint32_t PAD2_142; /* 0x21c - 0x220 */
+ uint32_t PAD2_143; /* 0x220 - 0x224 */
+ uint32_t PAD2_144; /* 0x224 - 0x228 */
+ char pad__2[0xd8]; /* 0x228 - 0x300 */
+ uint32_t dma_axi_ctrl; /* 0x300 - 0x304 */
+ uint32_t PAD2_147; /* 0x304 - 0x308 */
+ uint32_t PAD2_148; /* 0x308 - 0x30c */
+ uint32_t PAD2_149; /* 0x30c - 0x310 */
+ uint32_t PAD2_150; /* 0x310 - 0x314 */
+};
+
+#endif /* __REG_USBSS_DEV_ADDR_MAP_H__ */
diff --git a/drivers/usb/cdns3/gadget-export.h b/drivers/usb/cdns3/gadget-export.h
new file mode 100644
index 000000000000..e085ed38ea05
--- /dev/null
+++ b/drivers/usb/cdns3/gadget-export.h
@@ -0,0 +1,36 @@
+/*
+ * gadget-export.h - Gadget Export APIs
+ *
+ * Copyright 2017 NXP
+ * Authors: Peter Chen
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __CDNS3_GADGET_EXPORT_H
+#define __CDNS3_GADGET_EXPORT_H
+
+#ifdef CONFIG_USB_CDNS3_GADGET
+
+int cdns3_gadget_init(struct cdns3 *cdns);
+void cdns3_gadget_remove(struct cdns3 *cdns);
+#else
+
+static inline int cdns3_gadget_init(struct cdns3 *cdns)
+{
+ return -ENXIO;
+}
+
+static inline void cdns3_gadget_remove(struct cdns3 *cdns)
+{
+
+}
+
+#endif
+
+#endif /* __CDNS3_GADGET_EXPORT_H */
diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c
new file mode 100644
index 000000000000..0936336504da
--- /dev/null
+++ b/drivers/usb/cdns3/gadget.c
@@ -0,0 +1,2184 @@
+/**
+ * gadget.c - Cadence USB3 Device Core file
+ *
+ * Copyright (C) 2016 Cadence Design Systems - http://www.cadence.com
+ * Copyright 2017 NXP
+ *
+ * Authors: Pawel Jez ,
+ * Konrad Kociolek
+ * Peter Chen
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "core.h"
+#include "gadget-export.h"
+#include "gadget.h"
+#include "io.h"
+
+/*-------------------------------------------------------------------------*/
+/* Function declarations */
+
+static void select_ep(struct usb_ss_dev *usb_ss, u32 ep);
+static int usb_ss_allocate_trb_pool(struct usb_ss_endpoint *usb_ss_ep);
+static void cdns_ep_stall_flush(struct usb_ss_endpoint *usb_ss_ep);
+static void cdns_ep0_config(struct usb_ss_dev *usb_ss);
+static void cdns_gadget_unconfig(struct usb_ss_dev *usb_ss);
+static void cdns_ep0_run_transfer(struct usb_ss_dev *usb_ss,
+ dma_addr_t dma_addr, unsigned int length, int erdy);
+static int cdns_ep_run_transfer(struct usb_ss_endpoint *usb_ss_ep);
+static int cdns_get_setup_ret(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req);
+static int cdns_req_ep0_set_address(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req);
+static int cdns_req_ep0_get_status(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req);
+static int cdns_req_ep0_handle_feature(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req, int set);
+static int cdns_req_ep0_set_sel(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req);
+static int cdns_req_ep0_set_isoch_delay(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req);
+static int cdns_req_ep0_set_configuration(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req);
+static int cdns_ep0_standard_request(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req);
+static void cdns_ep0_setup_phase(struct usb_ss_dev *usb_ss);
+static int cdns_check_ep_interrupt_proceed(struct usb_ss_endpoint *usb_ss_ep);
+static void cdns_check_ep0_interrupt_proceed(struct usb_ss_dev *usb_ss,
+ int dir);
+static void cdns_check_usb_interrupt_proceed(struct usb_ss_dev *usb_ss,
+ u32 usb_ists);
+#ifdef CDNS_THREADED_IRQ_HANDLING
+static irqreturn_t cdns_irq_handler(int irq, void *_usb_ss);
+#endif
+static int usb_ss_gadget_ep0_enable(struct usb_ep *ep,
+ const struct usb_endpoint_descriptor *desc);
+static int usb_ss_gadget_ep0_disable(struct usb_ep *ep);
+static int usb_ss_gadget_ep0_set_halt(struct usb_ep *ep, int value);
+static int usb_ss_gadget_ep0_queue(struct usb_ep *ep,
+ struct usb_request *request, gfp_t gfp_flags);
+static void cdns_ep_config(struct usb_ss_endpoint *usb_ss_ep, int index);
+static int usb_ss_gadget_ep_enable(struct usb_ep *ep,
+ const struct usb_endpoint_descriptor *desc);
+static int usb_ss_gadget_ep_disable(struct usb_ep *ep);
+static struct usb_request *usb_ss_gadget_ep_alloc_request(struct usb_ep *ep,
+ gfp_t gfp_flags);
+static void usb_ss_gadget_ep_free_request(struct usb_ep *ep,
+ struct usb_request *request);
+static int usb_ss_gadget_ep_queue(struct usb_ep *ep,
+ struct usb_request *request, gfp_t gfp_flags);
+static int usb_ss_gadget_ep_dequeue(struct usb_ep *ep,
+ struct usb_request *request);
+static int usb_ss_gadget_ep_set_halt(struct usb_ep *ep, int value);
+static int usb_ss_gadget_ep_set_wedge(struct usb_ep *ep);
+static int usb_ss_gadget_get_frame(struct usb_gadget *gadget);
+static int usb_ss_gadget_wakeup(struct usb_gadget *gadget);
+static int usb_ss_gadget_set_selfpowered(struct usb_gadget *gadget,
+ int is_selfpowered);
+static int usb_ss_gadget_pullup(struct usb_gadget *gadget, int is_on);
+static int usb_ss_gadget_udc_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
+static int usb_ss_gadget_udc_stop(struct usb_gadget *gadget);
+static int usb_ss_init_ep(struct usb_ss_dev *usb_ss);
+static int usb_ss_init_ep0(struct usb_ss_dev *usb_ss);
+
+static u32 gadget_readl(struct usb_ss_dev *usb_ss, uint32_t __iomem *reg)
+{
+ return cdns_readl(reg);
+}
+
+static void gadget_writel(struct usb_ss_dev *usb_ss,
+ uint32_t __iomem *reg, u32 value)
+{
+ cdns_writel(reg, value);
+}
+
+/**
+ * next_request - returns next request from list
+ * @list: list containing requests
+ *
+ * Retuns request or NULL if no requests in list
+ */
+static struct usb_request *next_request(struct list_head *list)
+{
+ if (list_empty(list))
+ return NULL;
+ return list_first_entry(list, struct usb_request, list);
+}
+
+/**
+ * select_ep - selects endpoint
+ * @usb_ss: extended gadget object
+ * @ep: endpoint address
+ */
+static void select_ep(struct usb_ss_dev *usb_ss, u32 ep)
+{
+ if (!usb_ss || !usb_ss->regs) {
+ dev_err(&usb_ss->dev, "Failed to select endpoint!\n");
+ return;
+ }
+
+ gadget_writel(usb_ss, &usb_ss->regs->ep_sel, ep);
+}
+
+/**
+ *usb_ss_allocate_trb_pool - Allocates TRB's pool for selected endpoint
+ * @usb_ss_ep: extended endpoint object
+ *
+ * Function will return 0 on success or -ENOMEM on allocation error
+ */
+static int usb_ss_allocate_trb_pool(struct usb_ss_endpoint *usb_ss_ep)
+{
+ struct usb_ss_dev *usb_ss = usb_ss_ep->usb_ss;
+
+ if (usb_ss_ep->trb_pool)
+ return 0;
+
+ usb_ss_ep->trb_pool = dma_zalloc_coherent(usb_ss->sysdev,
+ sizeof(struct usb_ss_trb) * USB_SS_TRBS_NUM,
+ &usb_ss_ep->trb_pool_dma, GFP_DMA);
+
+ if (!usb_ss_ep->trb_pool) {
+ dev_err(&usb_ss->dev,
+ "Failed to allocate TRB pool for endpoint %s\n",
+ usb_ss_ep->name);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/**
+ * cdns_ep_stall_flush - Stalls and flushes selected endpoint
+ * @usb_ss_ep: extended endpoint object
+ *
+ * Endpoint must be selected before call to this function
+ */
+static void cdns_ep_stall_flush(struct usb_ss_endpoint *usb_ss_ep)
+{
+ struct usb_ss_dev *usb_ss = usb_ss_ep->usb_ss;
+
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__DFLUSH__MASK | EP_CMD__ERDY__MASK |
+ EP_CMD__SSTALL__MASK);
+
+ /* wait for DFLUSH cleared */
+ while (gadget_readl(usb_ss,
+ &usb_ss->regs->ep_cmd) & EP_CMD__DFLUSH__MASK)
+ ;
+
+ usb_ss_ep->stalled_flag = 1;
+}
+
+/**
+ * cdns_ep0_config - Configures default endpoint
+ * @usb_ss: extended gadget object
+ *
+ * Functions sets parameters: maximal packet size and enables interrupts
+ */
+static void cdns_ep0_config(struct usb_ss_dev *usb_ss)
+{
+ u32 max_packet_size = 0;
+
+ switch (usb_ss->gadget.speed) {
+ case USB_SPEED_UNKNOWN:
+ max_packet_size = ENDPOINT_MAX_PACKET_SIZE_0;
+ break;
+
+ case USB_SPEED_LOW:
+ max_packet_size = ENDPOINT_MAX_PACKET_SIZE_8;
+ break;
+
+ case USB_SPEED_FULL:
+ max_packet_size = ENDPOINT_MAX_PACKET_SIZE_64;
+ break;
+
+ case USB_SPEED_HIGH:
+ max_packet_size = ENDPOINT_MAX_PACKET_SIZE_64;
+ break;
+
+ case USB_SPEED_WIRELESS:
+ max_packet_size = ENDPOINT_MAX_PACKET_SIZE_64;
+ break;
+
+ case USB_SPEED_SUPER:
+ max_packet_size = ENDPOINT_MAX_PACKET_SIZE_512;
+ break;
+
+ case USB_SPEED_SUPER_PLUS:
+ dev_warn(&usb_ss->dev, "USB 3.1 is not supported\n");
+ max_packet_size = ENDPOINT_MAX_PACKET_SIZE_512;
+ break;
+ }
+
+ /* init ep out */
+ select_ep(usb_ss, USB_DIR_OUT);
+
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cfg,
+ EP_CFG__ENABLE__MASK |
+ EP_CFG__MAXPKTSIZE__WRITE(max_packet_size));
+ gadget_writel(usb_ss, &usb_ss->regs->ep_sts_en,
+ EP_STS_EN__SETUPEN__MASK |
+ EP_STS_EN__DESCMISEN__MASK |
+ EP_STS_EN__TRBERREN__MASK);
+
+ /* init ep in */
+ select_ep(usb_ss, USB_DIR_IN);
+
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cfg,
+ EP_CFG__ENABLE__MASK |
+ EP_CFG__MAXPKTSIZE__WRITE(max_packet_size));
+ gadget_writel(usb_ss, &usb_ss->regs->ep_sts_en,
+ EP_STS_EN__SETUPEN__MASK |
+ EP_STS_EN__TRBERREN__MASK);
+}
+
+/**
+ * cdns_gadget_unconfig - Unconfigures device controller
+ * @usb_ss: extended gadget object
+ */
+static void cdns_gadget_unconfig(struct usb_ss_dev *usb_ss)
+{
+ /* RESET CONFIGURATION */
+ gadget_writel(usb_ss, &usb_ss->regs->usb_conf,
+ USB_CONF__CFGRST__MASK);
+
+ usb_ss->hw_configured_flag = 0;
+}
+
+/**
+ * cdns_ep0_run_transfer - Do transfer on default endpoint hardware
+ * @usb_ss: extended gadget object
+ * @dma_addr: physical address where data is/will be stored
+ * @length: data length
+ * @erdy: set it to 1 when ERDY packet should be sent -
+ * exit from flow control state
+ */
+static void cdns_ep0_run_transfer(struct usb_ss_dev *usb_ss,
+ dma_addr_t dma_addr, unsigned int length, int erdy)
+{
+ usb_ss->trb_ep0[0] = TRB_SET_DATA_BUFFER_POINTER(dma_addr);
+ usb_ss->trb_ep0[1] = TRB_SET_TRANSFER_LENGTH((u32)length);
+ usb_ss->trb_ep0[2] = TRB_SET_CYCLE_BIT |
+ TRB_SET_INT_ON_COMPLETION | TRB_TYPE_NORMAL;
+
+ dev_dbg(&usb_ss->dev, "DRBL(%02X)\n",
+ usb_ss->ep0_data_dir ? USB_DIR_IN : USB_DIR_OUT);
+
+ select_ep(usb_ss, usb_ss->ep0_data_dir
+ ? USB_DIR_IN : USB_DIR_OUT);
+
+ gadget_writel(usb_ss, &usb_ss->regs->ep_traddr,
+ EP_TRADDR__TRADDR__WRITE(usb_ss->trb_ep0_dma));
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__DRDY__MASK); /* drbl */
+
+ if (erdy)
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__ERDY__MASK);
+}
+
+/**
+ * cdns_ep_run_transfer - Do transfer on no-default endpoint hardware
+ * @usb_ss: extended gadget object
+ */
+static int cdns_ep_run_transfer(struct usb_ss_endpoint *usb_ss_ep)
+{
+ dma_addr_t trb_dma;
+ struct usb_request *request = next_request(&usb_ss_ep->request_list);
+ struct usb_ss_dev *usb_ss = usb_ss_ep->usb_ss;
+ int sg_iter = 0;
+ struct usb_ss_trb *trb;
+
+ if (request == NULL)
+ return -EINVAL;
+
+ if (request->num_sgs > USB_SS_TRBS_NUM)
+ return -EINVAL;
+
+ dev_dbg(&usb_ss->dev, "DRBL(%02X)\n",
+ usb_ss_ep->endpoint.desc->bEndpointAddress);
+
+ usb_ss_ep->hw_pending_flag = 1;
+ trb_dma = request->dma;
+
+ /* must allocate buffer aligned to 8 */
+ if (request->dma % ADDR_MODULO_8) {
+ memcpy(usb_ss_ep->cpu_addr, request->buf, request->length);
+ trb_dma = usb_ss_ep->dma_addr;
+ }
+
+ trb = usb_ss_ep->trb_pool;
+
+ do {
+ /* fill TRB */
+ trb->offset0 = TRB_SET_DATA_BUFFER_POINTER(request->num_sgs == 0
+ ? trb_dma : request->sg[sg_iter].dma_address);
+
+ trb->offset4 = TRB_SET_BURST_LENGTH(16) |
+ TRB_SET_TRANSFER_LENGTH(request->num_sgs == 0 ?
+ request->length : request->sg[sg_iter].length);
+
+ trb->offset8 = TRB_SET_CYCLE_BIT
+ | TRB_SET_INT_ON_COMPLETION
+ | TRB_SET_INT_ON_SHORT_PACKET
+ | TRB_TYPE_NORMAL;
+
+ ++sg_iter;
+ ++trb;
+
+ } while (sg_iter < request->num_sgs);
+
+ /* arm transfer on selected endpoint */
+ select_ep(usb_ss_ep->usb_ss,
+ usb_ss_ep->endpoint.desc->bEndpointAddress);
+
+ gadget_writel(usb_ss, &usb_ss->regs->ep_traddr,
+ EP_TRADDR__TRADDR__WRITE(usb_ss_ep->trb_pool_dma));
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__DRDY__MASK); /* DRDY */
+ return 0;
+}
+
+/**
+ * cdns_get_setup_ret - Returns status of handling setup packet
+ * Setup is handled by gadget driver
+ * @usb_ss: extended gadget object
+ * @ctrl_req: pointer to received setup packet
+ */
+static int cdns_get_setup_ret(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req)
+{
+ int ret;
+
+ spin_unlock(&usb_ss->lock);
+ usb_ss->setup_pending = 1;
+ ret = usb_ss->gadget_driver->setup(&usb_ss->gadget, ctrl_req);
+ usb_ss->setup_pending = 0;
+ spin_lock(&usb_ss->lock);
+ return ret;
+}
+
+/**
+ * cdns_req_ep0_set_address - Handling of SET_ADDRESS standard USB request
+ * @usb_ss: extended gadget object
+ * @ctrl_req: pointer to received setup packet
+ *
+ * Returns 0 if success, error code on error
+ */
+static int cdns_req_ep0_set_address(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req)
+{
+ enum usb_device_state device_state = usb_ss->gadget.state;
+ u32 reg;
+ u32 addr;
+
+ addr = le16_to_cpu(ctrl_req->wValue);
+
+ if (addr > DEVICE_ADDRESS_MAX) {
+ dev_err(&usb_ss->dev,
+ "Device address (%d) cannot be greater than %d\n",
+ addr, DEVICE_ADDRESS_MAX);
+ return -EINVAL;
+ }
+
+ if (device_state == USB_STATE_CONFIGURED) {
+ dev_err(&usb_ss->dev, "USB device already configured\n");
+ return -EINVAL;
+ }
+
+ reg = gadget_readl(usb_ss, &usb_ss->regs->usb_cmd);
+
+ gadget_writel(usb_ss, &usb_ss->regs->usb_cmd, reg
+ | USB_CMD__FADDR__WRITE(addr)
+ | USB_CMD__SET_ADDR__MASK);
+
+ usb_gadget_set_state(&usb_ss->gadget,
+ (addr ? USB_STATE_ADDRESS : USB_STATE_DEFAULT));
+
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__ERDY__MASK | EP_CMD__REQ_CMPL__MASK);
+ return 0;
+}
+
+/**
+ * cdns_req_ep0_set_address - Handling of GET_STATUS standard USB request
+ * @usb_ss: extended gadget object
+ * @ctrl_req: pointer to received setup packet
+ *
+ * Returns 0 if success, error code on error
+ */
+static int cdns_req_ep0_get_status(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req)
+{
+ u16 usb_status = 0;
+ unsigned int length = 2;
+ u32 recip = ctrl_req->bRequestType & USB_RECIP_MASK;
+ u32 reg;
+
+ switch (recip) {
+
+ case USB_RECIP_DEVICE:
+ /* handling otg features */
+ if (ctrl_req->wIndex == OTG_STS_SELECTOR) {
+ length = 1;
+ usb_status = usb_ss->gadget.host_request_flag;
+ } else {
+
+ reg = gadget_readl(usb_ss, &usb_ss->regs->usb_sts);
+
+ if (reg & USB_STS__U1ENS__MASK)
+ usb_status |= 1uL << USB_DEV_STAT_U1_ENABLED;
+
+ if (reg & USB_STS__U2ENS__MASK)
+ usb_status |= 1uL << USB_DEV_STAT_U2_ENABLED;
+
+ if (usb_ss->wake_up_flag)
+ usb_status |= 1uL << USB_DEVICE_REMOTE_WAKEUP;
+
+ /* self powered */
+ usb_status |= 1uL << USB_DEVICE_SELF_POWERED;
+ }
+ break;
+
+ case USB_RECIP_INTERFACE:
+ return cdns_get_setup_ret(usb_ss, ctrl_req);
+
+ case USB_RECIP_ENDPOINT:
+ /* check if endpoint is stalled */
+ select_ep(usb_ss, ctrl_req->wIndex);
+ if (gadget_readl(usb_ss, &usb_ss->regs->ep_sts)
+ & EP_STS__STALL__MASK)
+ usb_status = 1;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ *(u16 *)usb_ss->setup = cpu_to_le16(usb_status);
+
+ usb_ss->actual_ep0_request = NULL;
+ cdns_ep0_run_transfer(usb_ss, usb_ss->setup_dma, length, 1);
+ return 0;
+}
+
+/**
+ * cdns_req_ep0_set_address - Handling of GET/SET_FEATURE standard USB request
+ * @usb_ss: extended gadget object
+ * @ctrl_req: pointer to received setup packet
+ * @set: must be set to 1 for SET_FEATURE request
+ *
+ * Returns 0 if success, error code on error
+ */
+static int cdns_req_ep0_handle_feature(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req, int set)
+{
+ u32 recip = ctrl_req->bRequestType & USB_RECIP_MASK;
+ struct usb_ss_endpoint *usb_ss_ep;
+ u32 reg;
+
+ switch (recip) {
+
+ case USB_RECIP_DEVICE:
+
+ switch (ctrl_req->wValue) {
+
+ case USB_DEVICE_U1_ENABLE:
+ if (usb_ss->gadget.state != USB_STATE_CONFIGURED)
+ return -EINVAL;
+ if (usb_ss->gadget.speed != USB_SPEED_SUPER)
+ return -EINVAL;
+
+ reg = gadget_readl(usb_ss, &usb_ss->regs->usb_conf);
+ if (set)
+ /* set U1EN */
+ reg |= USB_CONF__U1EN__MASK;
+ else
+ /* set U1 disable */
+ reg |= USB_CONF__U1DS__MASK;
+ gadget_writel(usb_ss, &usb_ss->regs->usb_conf, reg);
+ break;
+
+ case USB_DEVICE_U2_ENABLE:
+ if (usb_ss->gadget.state != USB_STATE_CONFIGURED)
+ return -EINVAL;
+ if (usb_ss->gadget.speed != USB_SPEED_SUPER)
+ return -EINVAL;
+
+ reg = gadget_readl(usb_ss, &usb_ss->regs->usb_conf);
+ if (set)
+ /* set U2EN */
+ reg |= USB_CONF__U2EN__MASK;
+ else
+ /* set U2 disable */
+ reg |= USB_CONF__U2DS__MASK;
+ gadget_writel(usb_ss, &usb_ss->regs->usb_conf, reg);
+ break;
+
+ case USB_DEVICE_A_ALT_HNP_SUPPORT:
+ break;
+
+ case USB_DEVICE_A_HNP_SUPPORT:
+ break;
+
+ case USB_DEVICE_B_HNP_ENABLE:
+ if (!usb_ss->gadget.b_hnp_enable && set)
+ usb_ss->gadget.b_hnp_enable = 1;
+ break;
+
+ case USB_DEVICE_REMOTE_WAKEUP:
+ usb_ss->wake_up_flag = !!set;
+ break;
+
+ default:
+ return -EINVAL;
+
+ }
+ break;
+
+ case USB_RECIP_INTERFACE:
+ return cdns_get_setup_ret(usb_ss, ctrl_req);
+
+ case USB_RECIP_ENDPOINT:
+ select_ep(usb_ss, ctrl_req->wIndex);
+
+ if (set) {
+ /* set stall */
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__SSTALL__MASK);
+
+ /* handle non zero endpoint software endpoint */
+ if (ctrl_req->wIndex & 0x7F) {
+ usb_ss_ep = usb_ss->eps[CAST_EP_ADDR_TO_INDEX(
+ ctrl_req->wIndex)];
+ usb_ss_ep->stalled_flag = 1;
+ }
+ } else {
+ struct usb_request *request;
+
+ if (ctrl_req->wIndex & 0x7F) {
+ if (usb_ss->eps[CAST_EP_ADDR_TO_INDEX(
+ ctrl_req->wIndex)]->wedge_flag)
+ goto jmp_wedge;
+ }
+
+ /* clear stall */
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__CSTALL__MASK | EP_CMD__EPRST__MASK);
+ /* wait for EPRST cleared */
+ while (gadget_readl(usb_ss, &usb_ss->regs->ep_cmd)
+ & EP_CMD__EPRST__MASK)
+ ;
+
+ /* handle non zero endpoint software endpoint */
+ if (ctrl_req->wIndex & 0x7F) {
+ usb_ss_ep = usb_ss->eps[CAST_EP_ADDR_TO_INDEX(
+ ctrl_req->wIndex)];
+ usb_ss_ep->stalled_flag = 0;
+
+ request = next_request(
+ &usb_ss_ep->request_list);
+ if (request)
+ cdns_ep_run_transfer(usb_ss_ep);
+ }
+ }
+jmp_wedge:
+ select_ep(usb_ss, 0x00);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__ERDY__MASK | EP_CMD__REQ_CMPL__MASK);
+
+ return 0;
+}
+
+/**
+ * cdns_req_ep0_set_sel - Handling of SET_SEL standard USB request
+ * @usb_ss: extended gadget object
+ * @ctrl_req: pointer to received setup packet
+ *
+ * Returns 0 if success, error code on error
+ */
+static int cdns_req_ep0_set_sel(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req)
+{
+ if (usb_ss->gadget.state < USB_STATE_ADDRESS)
+ return -EINVAL;
+
+ if (ctrl_req->wLength != 6) {
+ dev_err(&usb_ss->dev, "Set SEL should be 6 bytes, got %d\n",
+ ctrl_req->wLength);
+ return -EINVAL;
+ }
+
+ usb_ss->ep0_data_dir = 0;
+ usb_ss->actual_ep0_request = NULL;
+ cdns_ep0_run_transfer(usb_ss, usb_ss->setup_dma, 6, 1);
+
+ return 0;
+}
+
+/**
+ * cdns_req_ep0_set_isoch_delay -
+ * Handling of GET_ISOCH_DELAY standard USB request
+ * @usb_ss: extended gadget object
+ * @ctrl_req: pointer to received setup packet
+ *
+ * Returns 0 if success, error code on error
+ */
+static int cdns_req_ep0_set_isoch_delay(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req)
+{
+ if (ctrl_req->wIndex || ctrl_req->wLength)
+ return -EINVAL;
+
+ usb_ss->isoch_delay = ctrl_req->wValue;
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__ERDY__MASK | EP_CMD__REQ_CMPL__MASK);
+ return 0;
+}
+
+/**
+ * cdns_req_ep0_set_configuration - Handling of SET_CONFIG standard USB request
+ * @usb_ss: extended gadget object
+ * @ctrl_req: pointer to received setup packet
+ *
+ * Returns 0 if success, 0x7FFF on deferred status stage, error code on error
+ */
+static int cdns_req_ep0_set_configuration(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req)
+{
+ enum usb_device_state device_state = usb_ss->gadget.state;
+ u32 config = le16_to_cpu(ctrl_req->wValue);
+ struct usb_ep *ep;
+ int i, result = 0;
+
+ switch (device_state) {
+
+ case USB_STATE_ADDRESS:
+
+ if (config) {
+ for (i = 0; i < usb_ss->ep_nums; i++)
+ cdns_ep_config(usb_ss->eps[i], i);
+ }
+#ifdef CDNS_THREADED_IRQ_HANDLING
+ usb_ss->ep_ien = gadget_readl(usb_ss, &usb_ss->regs->ep_ien)
+ | EP_IEN__EOUTEN0__MASK | EP_IEN__EINEN0__MASK;
+#endif
+ result = cdns_get_setup_ret(usb_ss, ctrl_req);
+
+ if (result != 0)
+ return result;
+
+ if (config) {
+
+ if (!usb_ss->hw_configured_flag) {
+ /* SET CONFIGURATION */
+ gadget_writel(usb_ss, &usb_ss->regs->usb_conf,
+ USB_CONF__CFGSET__MASK);
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__ERDY__MASK |
+ EP_CMD__REQ_CMPL__MASK);
+ /* wait until configuration set */
+ while (!(gadget_readl(usb_ss,
+ &usb_ss->regs->usb_sts)
+ & USB_STS__CFGSTS__MASK))
+ ;
+ usb_ss->hw_configured_flag = 1;
+
+ list_for_each_entry(ep,
+ &usb_ss->gadget.ep_list,
+ ep_list) {
+ if (ep->enabled)
+ cdns_ep_run_transfer(
+ to_usb_ss_ep(ep));
+ }
+ }
+ } else {
+ cdns_gadget_unconfig(usb_ss);
+ for (i = 0; i < usb_ss->ep_nums; i++)
+ usb_ss->eps[i]->endpoint.enabled = 0;
+ usb_gadget_set_state(&usb_ss->gadget,
+ USB_STATE_ADDRESS);
+ }
+ break;
+
+ case USB_STATE_CONFIGURED:
+ result = cdns_get_setup_ret(usb_ss, ctrl_req);
+ if (!config && !result) {
+ cdns_gadget_unconfig(usb_ss);
+ for (i = 0; i < usb_ss->ep_nums; i++)
+ usb_ss->eps[i]->endpoint.enabled = 0;
+ usb_gadget_set_state(&usb_ss->gadget,
+ USB_STATE_ADDRESS);
+ }
+ break;
+
+ default:
+ result = -EINVAL;
+ }
+
+ return result;
+}
+
+/**
+ * cdns_ep0_standard_request - Handling standard USB requests
+ * @usb_ss: extended gadget object
+ * @ctrl_req: pointer to received setup packet
+ */
+static int cdns_ep0_standard_request(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req)
+{
+ switch (ctrl_req->bRequest) {
+ case USB_REQ_SET_ADDRESS:
+ return cdns_req_ep0_set_address(usb_ss, ctrl_req);
+ case USB_REQ_SET_CONFIGURATION:
+ return cdns_req_ep0_set_configuration(usb_ss, ctrl_req);
+ case USB_REQ_GET_STATUS:
+ return cdns_req_ep0_get_status(usb_ss, ctrl_req);
+ case USB_REQ_CLEAR_FEATURE:
+ return cdns_req_ep0_handle_feature(usb_ss, ctrl_req, 0);
+ case USB_REQ_SET_FEATURE:
+ return cdns_req_ep0_handle_feature(usb_ss, ctrl_req, 1);
+ case USB_REQ_SET_SEL:
+ return cdns_req_ep0_set_sel(usb_ss, ctrl_req);
+ case USB_REQ_SET_ISOCH_DELAY:
+ return cdns_req_ep0_set_isoch_delay(usb_ss, ctrl_req);
+ default:
+ return cdns_get_setup_ret(usb_ss, ctrl_req);
+ }
+}
+
+/**
+ * cdns_ep0_setup_phase - Handling setup USB requests
+ * @usb_ss: extended gadget object
+ */
+static void cdns_ep0_setup_phase(struct usb_ss_dev *usb_ss)
+{
+ int result;
+ struct usb_ctrlrequest *ctrl_req =
+ (struct usb_ctrlrequest *)usb_ss->setup;
+
+ if ((ctrl_req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
+ result = cdns_ep0_standard_request(usb_ss, ctrl_req);
+ else
+ result = cdns_get_setup_ret(usb_ss, ctrl_req);
+
+ if (result != 0 && result != USB_GADGET_DELAYED_STATUS) {
+ dev_dbg(&usb_ss->dev, "STALL(00) %d\n", result);
+
+ /* set_stall on ep0 */
+ select_ep(usb_ss, 0x00);
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__SSTALL__MASK);
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__ERDY__MASK | EP_CMD__REQ_CMPL__MASK);
+ return;
+ }
+}
+
+/**
+ * cdns_check_ep_interrupt_proceed - Processes interrupt related to endpoint
+ * @usb_ss_ep: extended endpoint object
+ */
+static int cdns_check_ep_interrupt_proceed(struct usb_ss_endpoint *usb_ss_ep)
+{
+ struct usb_ss_dev *usb_ss = usb_ss_ep->usb_ss;
+ struct usb_request *request;
+ u32 ep_sts_reg;
+
+ select_ep(usb_ss, usb_ss_ep->endpoint.address);
+ ep_sts_reg = gadget_readl(usb_ss, &usb_ss->regs->ep_sts);
+
+ dev_dbg(&usb_ss->dev, "EP_STS: %08X\n", ep_sts_reg);
+
+ if (ep_sts_reg & EP_STS__TRBERR__MASK) {
+ gadget_writel(usb_ss,
+ &usb_ss->regs->ep_sts, EP_STS__TRBERR__MASK);
+
+ dev_dbg(&usb_ss->dev, "TRBERR(%02X)\n",
+ usb_ss_ep->endpoint.desc->bEndpointAddress);
+ }
+
+ if (ep_sts_reg & EP_STS__ISOERR__MASK) {
+ gadget_writel(usb_ss,
+ &usb_ss->regs->ep_sts, EP_STS__ISOERR__MASK);
+ dev_dbg(&usb_ss->dev, "ISOERR(%02X)\n",
+ usb_ss_ep->endpoint.desc->bEndpointAddress);
+ }
+
+ if (ep_sts_reg & EP_STS__OUTSMM__MASK) {
+ gadget_writel(usb_ss, &usb_ss->regs->ep_sts,
+ EP_STS__OUTSMM__MASK);
+ dev_dbg(&usb_ss->dev, "OUTSMM(%02X)\n",
+ usb_ss_ep->endpoint.desc->bEndpointAddress);
+ }
+
+ if (ep_sts_reg & EP_STS__NRDY__MASK) {
+ gadget_writel(usb_ss,
+ &usb_ss->regs->ep_sts, EP_STS__NRDY__MASK);
+ dev_dbg(&usb_ss->dev, "NRDY(%02X)\n",
+ usb_ss_ep->endpoint.desc->bEndpointAddress);
+ }
+
+ if ((ep_sts_reg & EP_STS__IOC__MASK)
+ || (ep_sts_reg & EP_STS__ISP__MASK)) {
+ gadget_writel(usb_ss, &usb_ss->regs->ep_sts,
+ EP_STS__IOC__MASK | EP_STS__ISP__MASK);
+
+ /* get just completed request */
+ request = next_request(&usb_ss_ep->request_list);
+ usb_gadget_unmap_request_by_dev(usb_ss->sysdev, request,
+ usb_ss_ep->endpoint.desc->bEndpointAddress
+ & ENDPOINT_DIR_MASK);
+
+ request->status = 0;
+ request->actual =
+ le32_to_cpu(((u32 *) usb_ss_ep->trb_pool)[1])
+ & ACTUAL_TRANSFERRED_BYTES_MASK;
+
+ dev_dbg(&usb_ss->dev, "IOC(%02X) %d\n",
+ usb_ss_ep->endpoint.desc->bEndpointAddress,
+ request->actual);
+
+ list_del(&request->list);
+
+ usb_ss_ep->hw_pending_flag = 0;
+ if (request->complete) {
+ spin_unlock(&usb_ss->lock);
+ usb_gadget_giveback_request(&usb_ss_ep->endpoint,
+ request);
+ spin_lock(&usb_ss->lock);
+ }
+
+ /* handle deferred STALL */
+ if (usb_ss_ep->stalled_flag) {
+ cdns_ep_stall_flush(usb_ss_ep);
+ return 0;
+ }
+
+ /* exit if hardware transfer already started */
+ if (usb_ss_ep->hw_pending_flag)
+ return 0;
+
+ /* if any request queued run it! */
+ if (!list_empty(&usb_ss_ep->request_list))
+ cdns_ep_run_transfer(usb_ss_ep);
+ }
+
+ if (ep_sts_reg & EP_STS__DESCMIS__MASK) {
+ gadget_writel(usb_ss,
+ &usb_ss->regs->ep_sts, EP_STS__DESCMIS__MASK);
+ dev_dbg(&usb_ss->dev, "DESCMIS(%02X)\n",
+ usb_ss_ep->endpoint.desc->bEndpointAddress);
+ }
+
+ return 0;
+}
+
+/**
+ * cdns_check_ep0_interrupt_proceed - Processes interrupt related to endpoint 0
+ * @usb_ss: extended gadget object
+ * @dir: 1 for IN direction, 0 for OUT direction
+ */
+static void cdns_check_ep0_interrupt_proceed(struct usb_ss_dev *usb_ss, int dir)
+{
+ u32 ep_sts_reg;
+ int i;
+
+ select_ep(usb_ss, 0 | (dir ? USB_DIR_IN : USB_DIR_OUT));
+ ep_sts_reg = gadget_readl(usb_ss, &usb_ss->regs->ep_sts);
+
+ dev_dbg(&usb_ss->dev, "EP_STS: %08X\n", ep_sts_reg);
+
+ if ((ep_sts_reg & EP_STS__SETUP__MASK) && (dir == 0)) {
+ dev_dbg(&usb_ss->dev, "SETUP(%02X)\n", 0x00);
+
+ gadget_writel(usb_ss, &usb_ss->regs->ep_sts,
+ EP_STS__SETUP__MASK |
+ EP_STS__IOC__MASK | EP_STS__ISP__MASK);
+
+ dev_dbg(&usb_ss->dev, "SETUP: ");
+ for (i = 0; i < 8; i++)
+ dev_dbg(&usb_ss->dev, "%02X ", usb_ss->setup[i]);
+ dev_dbg(&usb_ss->dev, "\nSTATE: %d\n", usb_ss->gadget.state);
+ usb_ss->ep0_data_dir = usb_ss->setup[0] & USB_DIR_IN;
+ cdns_ep0_setup_phase(usb_ss);
+ ep_sts_reg &= ~(EP_STS__SETUP__MASK |
+ EP_STS__IOC__MASK |
+ EP_STS__ISP__MASK);
+ }
+
+ if (ep_sts_reg & EP_STS__TRBERR__MASK) {
+ gadget_writel(usb_ss,
+ &usb_ss->regs->ep_sts, EP_STS__TRBERR__MASK);
+ dev_dbg(&usb_ss->dev, "TRBERR(%02X)\n",
+ dir ? USB_DIR_IN : USB_DIR_OUT);
+ }
+
+ if (ep_sts_reg & EP_STS__DESCMIS__MASK) {
+ gadget_writel(usb_ss,
+ &usb_ss->regs->ep_sts, EP_STS__DESCMIS__MASK);
+
+ dev_dbg(&usb_ss->dev, "DESCMIS(%02X)\n",
+ dir ? USB_DIR_IN : USB_DIR_OUT);
+
+ if (dir == 0 && !usb_ss->setup_pending) {
+ usb_ss->ep0_data_dir = 0;
+ cdns_ep0_run_transfer(usb_ss,
+ usb_ss->setup_dma, 8, 0);
+ }
+ }
+
+ if ((ep_sts_reg & EP_STS__IOC__MASK)
+ || (ep_sts_reg & EP_STS__ISP__MASK)) {
+ gadget_writel(usb_ss,
+ &usb_ss->regs->ep_sts, EP_STS__IOC__MASK);
+ gadget_writel(usb_ss,
+ &usb_ss->regs->ep_cmd, EP_CMD__REQ_CMPL__MASK);
+
+ if (usb_ss->actual_ep0_request) {
+ usb_gadget_unmap_request_by_dev(usb_ss->sysdev,
+ usb_ss->actual_ep0_request,
+ usb_ss->ep0_data_dir);
+
+ usb_ss->actual_ep0_request->actual =
+ le32_to_cpu((usb_ss->trb_ep0)[1])
+ & ACTUAL_TRANSFERRED_BYTES_MASK;
+
+ dev_dbg(&usb_ss->dev, "IOC(%02X) %d\n",
+ dir ? USB_DIR_IN : USB_DIR_OUT,
+ usb_ss->actual_ep0_request->actual);
+ }
+
+ if (usb_ss->actual_ep0_request
+ && usb_ss->actual_ep0_request->complete) {
+ spin_unlock(&usb_ss->lock);
+ usb_ss->actual_ep0_request->complete(usb_ss->gadget.ep0,
+ usb_ss->actual_ep0_request);
+ spin_lock(&usb_ss->lock);
+ }
+ }
+}
+
+/**
+ * cdns_check_usb_interrupt_proceed - Processes interrupt related to device
+ * @usb_ss: extended gadget object
+ * @usb_ists: bitmap representation of device's reported interrupts
+ * (usb_ists register value)
+ */
+static void cdns_check_usb_interrupt_proceed(struct usb_ss_dev *usb_ss,
+ u32 usb_ists)
+{
+ int interrupt_bit = ffs(usb_ists) - 1;
+ int speed;
+ u32 val;
+
+ dev_dbg(&usb_ss->dev, "USB interrupt detected\n");
+
+ switch (interrupt_bit) {
+ case USB_ISTS__CON2I__SHIFT:
+ /* FS/HS Connection detected */
+ dev_dbg(&usb_ss->dev,
+ "[Interrupt] FS/HS Connection detected\n");
+ val = gadget_readl(usb_ss, &usb_ss->regs->usb_sts);
+ speed = USB_STS__USBSPEED__READ(val);
+ if (speed == USB_SPEED_WIRELESS)
+ speed = USB_SPEED_SUPER;
+ dev_dbg(&usb_ss->dev, "Speed value: %s (%d), usbsts:0x%x\n",
+ usb_speed_string(speed), speed, val);
+ usb_ss->gadget.speed = speed;
+ usb_ss->is_connected = 1;
+ usb_gadget_set_state(&usb_ss->gadget, USB_STATE_POWERED);
+ cdns_ep0_config(usb_ss);
+ break;
+
+ case USB_ISTS__CONI__SHIFT:
+ /* SS Connection detected */
+ dev_dbg(&usb_ss->dev, "[Interrupt] SS Connection detected\n");
+ val = gadget_readl(usb_ss, &usb_ss->regs->usb_sts);
+ speed = USB_STS__USBSPEED__READ(val);
+ if (speed == USB_SPEED_WIRELESS)
+ speed = USB_SPEED_SUPER;
+ dev_dbg(&usb_ss->dev, "Speed value: %s (%d), usbsts:0x%x\n",
+ usb_speed_string(speed), speed, val);
+ usb_ss->gadget.speed = speed;
+ usb_ss->is_connected = 1;
+ usb_gadget_set_state(&usb_ss->gadget, USB_STATE_POWERED);
+ cdns_ep0_config(usb_ss);
+ break;
+
+ case USB_ISTS__DIS2I__SHIFT:
+ case USB_ISTS__DISI__SHIFT:
+ /* SS Disconnection detected */
+ val = gadget_readl(usb_ss, &usb_ss->regs->usb_sts);
+ dev_dbg(&usb_ss->dev,
+ "[Interrupt] Disconnection detected: usbsts:0x%x\n",
+ val);
+ if (usb_ss->gadget_driver
+ && usb_ss->gadget_driver->disconnect) {
+
+ spin_unlock(&usb_ss->lock);
+ usb_ss->gadget_driver->disconnect(&usb_ss->gadget);
+ spin_lock(&usb_ss->lock);
+ }
+ usb_ss->gadget.speed = USB_SPEED_UNKNOWN;
+ usb_gadget_set_state(&usb_ss->gadget, USB_STATE_NOTATTACHED);
+ usb_ss->is_connected = 0;
+ cdns_gadget_unconfig(usb_ss);
+ break;
+
+ case USB_ISTS__L2ENTI__SHIFT:
+ dev_dbg(&usb_ss->dev,
+ "[Interrupt] Device suspended\n");
+ break;
+
+ case USB_ISTS__L2EXTI__SHIFT:
+ dev_dbg(&usb_ss->dev, "[Interrupt] L2 exit detected\n");
+ /*
+ * Exit from standby mode
+ * on L2 exit (Suspend in HS/FS or SS)
+ */
+ break;
+ case USB_ISTS__U3EXTI__SHIFT:
+ /*
+ * Exit from standby mode
+ * on U3 exit (Suspend in HS/FS or SS)
+ */
+ dev_dbg(&usb_ss->dev, "[Interrupt] U3 exit detected\n");
+ break;
+
+ /* resets cases */
+ case USB_ISTS__UWRESI__SHIFT:
+ case USB_ISTS__UHRESI__SHIFT:
+ case USB_ISTS__U2RESI__SHIFT:
+ dev_dbg(&usb_ss->dev, "[Interrupt] Reset detected\n");
+ speed = USB_STS__USBSPEED__READ(
+ gadget_readl(usb_ss, &usb_ss->regs->usb_sts));
+ if (speed == USB_SPEED_WIRELESS)
+ speed = USB_SPEED_SUPER;
+ usb_gadget_set_state(&usb_ss->gadget, USB_STATE_DEFAULT);
+ usb_ss->gadget.speed = speed;
+ cdns_gadget_unconfig(usb_ss);
+ cdns_ep0_config(usb_ss);
+ break;
+ default:
+ break;
+ }
+
+ /* Clear interrupt bit */
+ gadget_writel(usb_ss, &usb_ss->regs->usb_ists, (1uL << interrupt_bit));
+}
+
+#ifdef CDNS_THREADED_IRQ_HANDLING
+static irqreturn_t cdns_irq_handler(int irq, void *_usb_ss)
+{
+ struct usb_ss_dev *usb_ss = _usb_ss;
+
+ usb_ss->usb_ien = gadget_readl(usb_ss, &usb_ss->regs->usb_ien);
+ usb_ss->ep_ien = gadget_readl(usb_ss, &usb_ss->regs->ep_ien);
+
+ if (!gadget_readl(usb_ss, &usb_ss->regs->usb_ists)
+ && !gadget_readl(usb_ss, &usb_ss->regs->ep_ists)) {
+ dev_dbg(&usb_ss->dev, "--BUBBLE INTERRUPT 0 !!!\n");
+ if (gadget_readl(usb_ss, &usb_ss->regs->usb_sts) &
+ USB_STS__CFGSTS__MASK)
+ return IRQ_HANDLED;
+ return IRQ_NONE;
+ }
+
+ gadget_writel(usb_ss, &usb_ss->regs->usb_ien, 0);
+ gadget_writel(usb_ss, &usb_ss->regs->ep_ien, 0);
+
+ gadget_readl(usb_ss, &usb_ss->regs->dma_axi_ctrl);
+ return IRQ_WAKE_THREAD;
+}
+#endif
+
+/**
+ * cdns_irq_handler - irq line interrupt handler
+ * @irq: interrupt line number
+ * @_usb_ss: pointer to extended gadget object
+ *
+ * Returns IRQ_HANDLED when interrupt raised by USBSS_DEV,
+ * IRQ_NONE when interrupt raised by other device connected
+ * to the irq line
+ */
+static irqreturn_t cdns_irq_handler_thread(struct cdns3 *cdns)
+{
+ struct usb_ss_dev *usb_ss =
+ container_of(cdns->gadget_dev, struct usb_ss_dev, dev);
+ u32 reg;
+ enum irqreturn ret = IRQ_NONE;
+ unsigned long flags;
+
+ spin_lock_irqsave(&usb_ss->lock, flags);
+
+ /* check USB device interrupt */
+ reg = gadget_readl(usb_ss, &usb_ss->regs->usb_ists);
+ if (reg) {
+ dev_dbg(&usb_ss->dev, "usb_ists: %08X\n", reg);
+ cdns_check_usb_interrupt_proceed(usb_ss, reg);
+ ret = IRQ_HANDLED;
+ }
+
+ /* check endpoint interrupt */
+ reg = gadget_readl(usb_ss, &usb_ss->regs->ep_ists);
+ if (reg != 0) {
+ dev_dbg(&usb_ss->dev, "ep_ists: %08X\n", reg);
+ } else {
+ if (gadget_readl(usb_ss, &usb_ss->regs->usb_sts) &
+ USB_STS__CFGSTS__MASK)
+ ret = IRQ_HANDLED;
+ goto irqend;
+ }
+
+ /* handle default endpoint OUT */
+ if (reg & EP_ISTS__EOUT0__MASK) {
+ cdns_check_ep0_interrupt_proceed(usb_ss, 0);
+ ret = IRQ_HANDLED;
+ }
+
+ /* handle default endpoint IN */
+ if (reg & EP_ISTS__EIN0__MASK) {
+ cdns_check_ep0_interrupt_proceed(usb_ss, 1);
+ ret = IRQ_HANDLED;
+ }
+
+ /* check if interrupt from non default endpoint, if no exit */
+ reg &= ~(EP_ISTS__EOUT0__MASK | EP_ISTS__EIN0__MASK);
+ if (!reg)
+ goto irqend;
+
+ do {
+ unsigned int bit_pos = ffs(reg);
+ u32 bit_mask = 1 << (bit_pos - 1);
+
+ dev_dbg(&usb_ss->dev, "Interrupt on index: %d bitmask %08X\n",
+ CAST_EP_REG_POS_TO_INDEX(bit_pos), bit_mask);
+ cdns_check_ep_interrupt_proceed(
+ usb_ss->eps[CAST_EP_REG_POS_TO_INDEX(bit_pos)]);
+ reg &= ~bit_mask;
+ } while (reg);
+
+irqend:
+
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+#ifdef CDNS_THREADED_IRQ_HANDLING
+ local_irq_save(flags);
+ gadget_writel(usb_ss, &usb_ss->regs->usb_ien, usb_ss->usb_ien);
+ gadget_writel(usb_ss, &usb_ss->regs->ep_ien, usb_ss->ep_ien);
+ local_irq_restore(flags);
+#endif
+ return ret;
+}
+
+/**
+ * usb_ss_gadget_ep0_enable
+ * Function shouldn't be called by gadget driver,
+ * endpoint 0 is allways active
+ */
+static int usb_ss_gadget_ep0_enable(struct usb_ep *ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ return -EINVAL;
+}
+
+/**
+ * usb_ss_gadget_ep0_disable
+ * Function shouldn't be called by gadget driver,
+ * endpoint 0 is allways active
+ */
+static int usb_ss_gadget_ep0_disable(struct usb_ep *ep)
+{
+ return -EINVAL;
+}
+
+/**
+ * usb_ss_gadget_ep0_set_halt
+ * @ep: pointer to endpoint zero object
+ * @value: 1 for set stall, 0 for clear stall
+ *
+ * Returns 0
+ */
+static int usb_ss_gadget_ep0_set_halt(struct usb_ep *ep, int value)
+{
+ /* TODO */
+ return 0;
+}
+
+/**
+ * usb_ss_gadget_ep0_queue Transfer data on endpoint zero
+ * @ep: pointer to endpoint zero object
+ * @request: pointer to request object
+ * @gfp_flags: gfp flags
+ *
+ * Returns 0 on success, error code elsewhere
+ */
+static int usb_ss_gadget_ep0_queue(struct usb_ep *ep,
+ struct usb_request *request, gfp_t gfp_flags)
+{
+ int ret;
+ unsigned long flags;
+ int erdy_sent = 0;
+ /* get extended endpoint */
+ struct usb_ss_endpoint *usb_ss_ep =
+ to_usb_ss_ep(ep);
+ struct usb_ss_dev *usb_ss = usb_ss_ep->usb_ss;
+
+ dev_dbg(&usb_ss->dev, "QUEUE(%02X) %d\n",
+ usb_ss->ep0_data_dir ? USB_DIR_IN : USB_DIR_OUT,
+ request->length);
+
+ /* send STATUS stage */
+ if (request->length == 0 && request->zero == 0) {
+ spin_lock_irqsave(&usb_ss->lock, flags);
+ select_ep(usb_ss, 0x00);
+ if (!usb_ss->hw_configured_flag) {
+
+ gadget_writel(usb_ss, &usb_ss->regs->usb_conf,
+ USB_CONF__CFGSET__MASK); /* SET CONFIGURATION */
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__ERDY__MASK | EP_CMD__REQ_CMPL__MASK);
+ /* wait until configuration set */
+ while (!(gadget_readl(usb_ss, &usb_ss->regs->usb_sts)
+ & USB_STS__CFGSTS__MASK))
+ ;
+ erdy_sent = 1;
+ usb_ss->hw_configured_flag = 1;
+
+ list_for_each_entry(ep,
+ &usb_ss->gadget.ep_list,
+ ep_list) {
+
+ if (ep->enabled)
+ cdns_ep_run_transfer(
+ to_usb_ss_ep(ep));
+ }
+ }
+ if (!erdy_sent)
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__ERDY__MASK | EP_CMD__REQ_CMPL__MASK);
+ if (request->complete)
+ request->complete(usb_ss->gadget.ep0, request);
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+ return 0;
+ }
+
+ spin_lock_irqsave(&usb_ss->lock, flags);
+ ret = usb_gadget_map_request_by_dev(usb_ss->sysdev, request,
+ usb_ss->ep0_data_dir);
+ if (ret) {
+ dev_err(&usb_ss->dev, "failed to map request\n");
+ return -EINVAL;
+ }
+
+ usb_ss->actual_ep0_request = request;
+ cdns_ep0_run_transfer(usb_ss, request->dma, request->length, 1);
+
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+
+ return 0;
+}
+
+/**
+ * cdns_ep_config Configure hardware endpoint
+ * @usb_ss_ep: extended endpoint object
+ * @index: index for endpoints
+ */
+static void cdns_ep_config(struct usb_ss_endpoint *usb_ss_ep, int index)
+{
+ struct usb_ss_dev *usb_ss = usb_ss_ep->usb_ss;
+ u32 ep_cfg = 0;
+ u32 max_packet_size = 0;
+ u32 bEndpointAddress = (u32)CAST_INDEX_TO_EP_ADDR(index);
+ u32 interrupt_mask = 0;
+
+ usb_ss_ep->endpoint.address = bEndpointAddress;
+ if (usb_ss_ep->is_iso_flag) {
+ ep_cfg = EP_CFG__EPTYPE__WRITE(USB_ENDPOINT_XFER_ISOC);
+ interrupt_mask = INTERRUPT_MASK;
+ } else {
+ ep_cfg = EP_CFG__EPTYPE__WRITE(USB_ENDPOINT_XFER_BULK);
+ }
+
+ switch (usb_ss->gadget.speed) {
+ case USB_SPEED_UNKNOWN:
+ max_packet_size = ENDPOINT_MAX_PACKET_SIZE_0;
+ break;
+
+ case USB_SPEED_LOW:
+ max_packet_size = ENDPOINT_MAX_PACKET_SIZE_8;
+ break;
+
+ case USB_SPEED_FULL:
+ max_packet_size = (usb_ss_ep->is_iso_flag ?
+ ENDPOINT_MAX_PACKET_SIZE_1023 :
+ ENDPOINT_MAX_PACKET_SIZE_64);
+ break;
+
+ case USB_SPEED_HIGH:
+ max_packet_size = (usb_ss_ep->is_iso_flag ?
+ ENDPOINT_MAX_PACKET_SIZE_1024 :
+ ENDPOINT_MAX_PACKET_SIZE_512);
+ break;
+
+ case USB_SPEED_WIRELESS:
+ max_packet_size = ENDPOINT_MAX_PACKET_SIZE_512;
+ break;
+
+ case USB_SPEED_SUPER:
+ max_packet_size = ENDPOINT_MAX_PACKET_SIZE_1024;
+ break;
+
+ case USB_SPEED_SUPER_PLUS:
+ dev_warn(&usb_ss->dev, "USB 3.1 is not supported\n");
+ max_packet_size = ENDPOINT_MAX_PACKET_SIZE_1024;
+ break;
+ }
+
+ ep_cfg |= EP_CFG__MAXPKTSIZE__WRITE(max_packet_size);
+
+ if (usb_ss_ep->is_iso_flag) {
+ ep_cfg |= EP_CFG__BUFFERING__WRITE(1);
+ ep_cfg |= EP_CFG__MAXBURST__WRITE(0);
+ } else {
+ ep_cfg |= EP_CFG__BUFFERING__WRITE(3);
+ ep_cfg |= EP_CFG__MAXBURST__WRITE(15);
+ }
+
+ ep_cfg |= EP_CFG__ENABLE__MASK;
+
+ select_ep(usb_ss, bEndpointAddress);
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cfg, ep_cfg);
+ gadget_writel(usb_ss, &usb_ss->regs->ep_sts_en,
+ EP_STS_EN__TRBERREN__MASK | interrupt_mask);
+
+ /* enable interrupt for selected endpoint */
+ ep_cfg = gadget_readl(usb_ss, &usb_ss->regs->ep_ien);
+ ep_cfg |= CAST_EP_ADDR_TO_BIT_POS(bEndpointAddress);
+ gadget_writel(usb_ss, &usb_ss->regs->ep_ien, ep_cfg);
+}
+
+/**
+ * usb_ss_gadget_ep_enable Enable endpoint
+ * @ep: endpoint object
+ * @desc: endpoint descriptor
+ *
+ * Returns 0 on success, error code elsewhere
+ */
+static int usb_ss_gadget_ep_enable(struct usb_ep *ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct usb_ss_endpoint *usb_ss_ep;
+ struct usb_ss_dev *usb_ss;
+ unsigned long flags;
+ int ret;
+
+ usb_ss_ep = to_usb_ss_ep(ep);
+ usb_ss = usb_ss_ep->usb_ss;
+
+ if (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) {
+ dev_err(&usb_ss->dev, "usb-ss: invalid parameters\n");
+ return -EINVAL;
+ }
+
+ if (!desc->wMaxPacketSize) {
+ dev_err(&usb_ss->dev, "usb-ss: missing wMaxPacketSize\n");
+ return -EINVAL;
+ }
+
+ ret = usb_ss_allocate_trb_pool(usb_ss_ep);
+ if (ret)
+ return ret;
+
+ if (!usb_ss_ep->cpu_addr) {
+ usb_ss_ep->cpu_addr = dma_alloc_coherent(usb_ss->sysdev, 4096,
+ &usb_ss_ep->dma_addr, GFP_DMA);
+
+ if (!usb_ss_ep->cpu_addr)
+ return -ENOMEM;
+ }
+
+ spin_lock_irqsave(&usb_ss->lock, flags);
+ dev_dbg(&usb_ss->dev, "Enabling endpoint: %s\n", ep->name);
+ ep->enabled = 1;
+ usb_ss_ep->hw_pending_flag = 0;
+ usb_ss_ep->endpoint.desc = desc;
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+
+ return 0;
+}
+
+/**
+ * usb_ss_gadget_ep_disable Disable endpoint
+ * @ep: endpoint object
+ *
+ * Returns 0 on success, error code elsewhere
+ */
+static int usb_ss_gadget_ep_disable(struct usb_ep *ep)
+{
+ struct usb_ss_endpoint *usb_ss_ep;
+ struct usb_ss_dev *usb_ss;
+ unsigned long flags;
+ int ret = 0;
+ struct usb_request *request;
+
+ if (!ep) {
+ pr_debug("usb-ss: invalid parameters\n");
+ return -EINVAL;
+ }
+
+ usb_ss_ep = to_usb_ss_ep(ep);
+ usb_ss = usb_ss_ep->usb_ss;
+
+ spin_lock_irqsave(&usb_ss->lock, flags);
+ dev_dbg(&usb_ss->dev,
+ "Disabling endpoint: %s\n", ep->name);
+ select_ep(usb_ss, ep->desc->bEndpointAddress);
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__EPRST__MASK);
+ while (gadget_readl(usb_ss,
+ &usb_ss->regs->ep_cmd) & EP_CMD__EPRST__MASK)
+ ;
+
+ while (!list_empty(&usb_ss_ep->request_list)) {
+
+ request = next_request(&usb_ss_ep->request_list);
+ usb_gadget_unmap_request_by_dev(usb_ss->sysdev, request,
+ ep->desc->bEndpointAddress & USB_DIR_IN);
+ request->status = -ESHUTDOWN;
+ list_del(&request->list);
+ spin_unlock(&usb_ss->lock);
+ usb_gadget_giveback_request(ep, request);
+ spin_lock(&usb_ss->lock);
+ }
+
+ ep->desc = NULL;
+ ep->enabled = 0;
+
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+
+ return ret;
+}
+
+/**
+ * usb_ss_gadget_ep_alloc_request Allocates request
+ * @ep: endpoint object associated with request
+ * @gfp_flags: gfp flags
+ *
+ * Returns allocated request address, NULL on allocation error
+ */
+static struct usb_request *usb_ss_gadget_ep_alloc_request(struct usb_ep *ep,
+ gfp_t gfp_flags)
+{
+ struct usb_request *request;
+
+ request = kzalloc(sizeof(struct usb_request), gfp_flags);
+ if (!request)
+ return NULL;
+
+ return request;
+}
+
+/**
+ * usb_ss_gadget_ep_free_request Free memory occupied by request
+ * @ep: endpoint object associated with request
+ * @request: request to free memory
+ */
+static void usb_ss_gadget_ep_free_request(struct usb_ep *ep,
+ struct usb_request *request)
+{
+ kfree(request);
+}
+
+/**
+ * usb_ss_gadget_ep_queue Transfer data on endpoint
+ * @ep: endpoint object
+ * @request: request object
+ * @gfp_flags: gfp flags
+ *
+ * Returns 0 on success, error code elsewhere
+ */
+static int usb_ss_gadget_ep_queue(struct usb_ep *ep,
+ struct usb_request *request, gfp_t gfp_flags)
+{
+ struct usb_ss_endpoint *usb_ss_ep =
+ to_usb_ss_ep(ep);
+ struct usb_ss_dev *usb_ss = usb_ss_ep->usb_ss;
+ unsigned long flags;
+ int ret = 0;
+ int empty_list = 0;
+
+ spin_lock_irqsave(&usb_ss->lock, flags);
+
+ request->actual = 0;
+ request->status = -EINPROGRESS;
+
+ dev_dbg(&usb_ss->dev,
+ "Queuing endpoint: %s\n", usb_ss_ep->name);
+
+ dev_dbg(&usb_ss->dev, "QUEUE(%02X) %d\n",
+ ep->desc->bEndpointAddress, request->length);
+
+ ret = usb_gadget_map_request_by_dev(usb_ss->sysdev, request,
+ ep->desc->bEndpointAddress & USB_DIR_IN);
+
+ if (ret) {
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+ return ret;
+ }
+
+ empty_list = list_empty(&usb_ss_ep->request_list);
+ list_add_tail(&request->list, &usb_ss_ep->request_list);
+
+ if (!usb_ss->hw_configured_flag) {
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+ return 0;
+ }
+
+ if (empty_list) {
+ if (!usb_ss_ep->stalled_flag)
+ cdns_ep_run_transfer(usb_ss_ep);
+ }
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+
+ return ret;
+}
+
+/**
+ * usb_ss_gadget_ep_dequeue Remove request from transfer queue
+ * @ep: endpoint object associated with request
+ * @request: request object
+ *
+ * Returns 0 on success, error code elsewhere
+ */
+static int usb_ss_gadget_ep_dequeue(struct usb_ep *ep,
+ struct usb_request *request)
+{
+ struct usb_ss_endpoint *usb_ss_ep =
+ to_usb_ss_ep(ep);
+ struct usb_ss_dev *usb_ss = usb_ss_ep->usb_ss;
+ unsigned long flags;
+
+ spin_lock_irqsave(&usb_ss->lock, flags);
+ dev_dbg(&usb_ss->dev, "DEQUEUE(%02X) %d\n",
+ ep->address, request->length);
+ usb_gadget_unmap_request_by_dev(usb_ss->sysdev, request,
+ ep->address & USB_DIR_IN);
+ request->status = -ECONNRESET;
+
+ if (ep->address)
+ list_del(&request->list);
+
+ if (request->complete) {
+ spin_unlock(&usb_ss->lock);
+ request->complete(ep, request);
+ spin_lock(&usb_ss->lock);
+ }
+
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+ return 0;
+}
+
+/**
+ * usb_ss_gadget_ep_set_halt Sets/clears stall on selected endpoint
+ * @ep: endpoint object to set/clear stall on
+ * @value: 1 for set stall, 0 for clear stall
+ *
+ * Returns 0 on success, error code elsewhere
+ */
+static int usb_ss_gadget_ep_set_halt(struct usb_ep *ep, int value)
+{
+ struct usb_ss_endpoint *usb_ss_ep =
+ to_usb_ss_ep(ep);
+ struct usb_ss_dev *usb_ss = usb_ss_ep->usb_ss;
+ unsigned long flags;
+
+ /* return error when endpoint disabled */
+ if (!ep->enabled)
+ return -EPERM;
+
+ /* if actual transfer is pending defer setting stall on this endpoint */
+ if (usb_ss_ep->hw_pending_flag && value) {
+ usb_ss_ep->stalled_flag = 1;
+ return 0;
+ }
+
+ dev_dbg(&usb_ss->dev, "HALT(%02X) %d\n", ep->address, value);
+
+ spin_lock_irqsave(&usb_ss->lock, flags);
+
+ select_ep(usb_ss, ep->desc->bEndpointAddress);
+ if (value) {
+ cdns_ep_stall_flush(usb_ss_ep);
+ } else {
+ /*
+ * TODO:
+ * epp->wedgeFlag = 0;
+ */
+ usb_ss_ep->wedge_flag = 0;
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__CSTALL__MASK | EP_CMD__EPRST__MASK);
+ /* wait for EPRST cleared */
+ while (gadget_readl(usb_ss,
+ &usb_ss->regs->ep_cmd) & EP_CMD__EPRST__MASK)
+ ;
+ usb_ss_ep->stalled_flag = 0;
+ }
+ usb_ss_ep->hw_pending_flag = 0;
+
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+
+ return 0;
+}
+
+/**
+ * usb_ss_gadget_ep_set_wedge Set wedge on selected endpoint
+ * @ep: endpoint object
+ *
+ * Returns 0 on success, error code elsewhere
+ */
+static int usb_ss_gadget_ep_set_wedge(struct usb_ep *ep)
+{
+ struct usb_ss_endpoint *usb_ss_ep = to_usb_ss_ep(ep);
+ struct usb_ss_dev *usb_ss = usb_ss_ep->usb_ss;
+
+ dev_dbg(&usb_ss->dev, "WEDGE(%02X)\n", ep->address);
+ usb_ss_gadget_ep_set_halt(ep, 1);
+ usb_ss_ep->wedge_flag = 1;
+ return 0;
+}
+
+static const struct usb_ep_ops usb_ss_gadget_ep0_ops = {
+ .enable = usb_ss_gadget_ep0_enable,
+ .disable = usb_ss_gadget_ep0_disable,
+ .alloc_request = usb_ss_gadget_ep_alloc_request,
+ .free_request = usb_ss_gadget_ep_free_request,
+ .queue = usb_ss_gadget_ep0_queue,
+ .dequeue = usb_ss_gadget_ep_dequeue,
+ .set_halt = usb_ss_gadget_ep0_set_halt,
+ .set_wedge = usb_ss_gadget_ep_set_wedge,
+};
+
+static const struct usb_ep_ops usb_ss_gadget_ep_ops = {
+ .enable = usb_ss_gadget_ep_enable,
+ .disable = usb_ss_gadget_ep_disable,
+ .alloc_request = usb_ss_gadget_ep_alloc_request,
+ .free_request = usb_ss_gadget_ep_free_request,
+ .queue = usb_ss_gadget_ep_queue,
+ .dequeue = usb_ss_gadget_ep_dequeue,
+ .set_halt = usb_ss_gadget_ep_set_halt,
+ .set_wedge = usb_ss_gadget_ep_set_wedge,
+};
+
+/**
+ * usb_ss_gadget_get_frame Returns number of actual ITP frame
+ * @gadget: gadget object
+ *
+ * Returns number of actual ITP frame
+ */
+static int usb_ss_gadget_get_frame(struct usb_gadget *gadget)
+{
+ struct usb_ss_dev *usb_ss = gadget_to_usb_ss(gadget);
+
+ dev_dbg(&usb_ss->dev, "usb_ss_gadget_get_frame\n");
+ return gadget_readl(usb_ss, &usb_ss->regs->usb_iptn);
+}
+
+static int usb_ss_gadget_wakeup(struct usb_gadget *gadget)
+{
+ struct usb_ss_dev *usb_ss = gadget_to_usb_ss(gadget);
+
+ dev_dbg(&usb_ss->dev, "usb_ss_gadget_wakeup\n");
+ return 0;
+}
+
+static int usb_ss_gadget_set_selfpowered(struct usb_gadget *gadget,
+ int is_selfpowered)
+{
+ struct usb_ss_dev *usb_ss = gadget_to_usb_ss(gadget);
+
+ dev_dbg(&usb_ss->dev, "usb_ss_gadget_set_selfpowered: %d\n",
+ is_selfpowered);
+ return 0;
+}
+
+static int usb_ss_gadget_pullup(struct usb_gadget *gadget, int is_on)
+{
+ struct usb_ss_dev *usb_ss = gadget_to_usb_ss(gadget);
+
+ dev_dbg(&usb_ss->dev, "usb_ss_gadget_pullup: %d\n", is_on);
+ return 0;
+}
+
+/**
+ * usb_ss_gadget_udc_start Gadget start
+ * @gadget: gadget object
+ * @driver: driver which operates on this gadget
+ *
+ * Returns 0 on success, error code elsewhere
+ */
+static int usb_ss_gadget_udc_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
+{
+ struct usb_ss_dev *usb_ss = gadget_to_usb_ss(gadget);
+ unsigned long flags;
+
+ if (usb_ss->gadget_driver) {
+ dev_err(&usb_ss->dev, "%s is already bound to %s\n",
+ usb_ss->gadget.name,
+ usb_ss->gadget_driver->driver.name);
+ return -EBUSY;
+ }
+
+ dev_dbg(&usb_ss->dev, "%s begins\n", __func__);
+
+ spin_lock_irqsave(&usb_ss->lock, flags);
+ usb_ss->gadget_driver = driver;
+ if (!usb_ss->start_gadget) {
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+ return 0;
+ }
+
+ /* configure endpoint 0 hardware */
+ cdns_ep0_config(usb_ss);
+
+ /* enable interrupts for endpoint 0 (in and out) */
+ gadget_writel(usb_ss, &usb_ss->regs->ep_ien,
+ EP_IEN__EOUTEN0__MASK | EP_IEN__EINEN0__MASK);
+
+ /* enable interrupt for device */
+ gadget_writel(usb_ss, &usb_ss->regs->usb_ien,
+ USB_IEN__U2RESIEN__MASK
+ | USB_ISTS__DIS2I__MASK
+ | USB_IEN__CON2IEN__MASK
+ | USB_IEN__UHRESIEN__MASK
+ | USB_IEN__UWRESIEN__MASK
+ | USB_IEN__DISIEN__MASK
+ | USB_IEN__CONIEN__MASK
+ | USB_IEN__U3EXTIEN__MASK
+ | USB_IEN__L2ENTIEN__MASK
+ | USB_IEN__L2EXTIEN__MASK);
+
+ gadget_writel(usb_ss, &usb_ss->regs->usb_conf,
+ USB_CONF__CLK2OFFDS__MASK
+ /* | USB_CONF__USB3DIS__MASK */
+ | USB_CONF__L1DS__MASK);
+
+ gadget_writel(usb_ss, &usb_ss->regs->usb_conf,
+ USB_CONF__DEVEN__MASK
+ | USB_CONF__U1DS__MASK
+ | USB_CONF__U2DS__MASK
+ /*
+ * TODO:
+ * | USB_CONF__L1EN__MASK
+ */
+ );
+
+ gadget_writel(usb_ss, &usb_ss->regs->usb_conf,
+ USB_CONF__DEVEN__MASK
+ | USB_CONF__U1DS__MASK
+ | USB_CONF__U2DS__MASK
+ /*
+ * TODO:
+ * | USB_CONF__L1EN__MASK
+ */
+ );
+
+ gadget_writel(usb_ss, &usb_ss->regs->dbg_link1,
+ DBG_LINK1__LFPS_MIN_GEN_U1_EXIT_SET__MASK |
+ DBG_LINK1__LFPS_MIN_GEN_U1_EXIT__WRITE(0x3C));
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+ dev_dbg(&usb_ss->dev, "%s ends\n", __func__);
+
+ return 0;
+}
+
+/**
+ * usb_ss_gadget_udc_stop Stops gadget
+ * @gadget: gadget object
+ *
+ * Returns 0
+ */
+static int usb_ss_gadget_udc_stop(struct usb_gadget *gadget)
+{
+ struct usb_ss_dev *usb_ss = gadget_to_usb_ss(gadget);
+ unsigned long flags;
+
+ spin_lock_irqsave(&usb_ss->lock, flags);
+ usb_ss->gadget_driver = NULL;
+ /* disable interrupt for device */
+ gadget_writel(usb_ss, &usb_ss->regs->usb_ien, 0);
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+
+ return 0;
+}
+
+static const struct usb_gadget_ops usb_ss_gadget_ops = {
+ .get_frame = usb_ss_gadget_get_frame,
+ .wakeup = usb_ss_gadget_wakeup,
+ .set_selfpowered = usb_ss_gadget_set_selfpowered,
+ .pullup = usb_ss_gadget_pullup,
+ .udc_start = usb_ss_gadget_udc_start,
+ .udc_stop = usb_ss_gadget_udc_stop,
+};
+
+/**
+ * usb_ss_init_ep Initializes software endpoints of gadget
+ * @gadget: gadget object
+ *
+ * Returns 0 on success, error code elsewhere
+ */
+static int usb_ss_init_ep(struct usb_ss_dev *usb_ss)
+{
+ struct usb_ss_endpoint *usb_ss_ep;
+ u32 ep_enabled_reg, iso_ep_reg, bulk_ep_reg;
+ int i;
+ int ep_reg_pos, ep_dir, ep_number;
+ int found_endpoints = 0;
+
+ /* Read it from USB_CAP3 to USB_CAP5 */
+ ep_enabled_reg = 0x00ff00ff;
+ iso_ep_reg = 0x00fe00fe;
+ bulk_ep_reg = 0x00fe00fe;
+
+ dev_dbg(&usb_ss->dev, "Initializing non-zero endpoints\n");
+ dev_dbg(&usb_ss->dev,
+ "ep_enabled_reg: 0x%x, iso_ep_reg: 0x%x, bulk_ep_reg:0x%x\n",
+ ep_enabled_reg, iso_ep_reg, bulk_ep_reg);
+
+ for (i = 0; i < USB_SS_ENDPOINTS_MAX_COUNT; i++) {
+ ep_number = (i / 2) + 1;
+ ep_dir = i % 2;
+ ep_reg_pos = (16 * ep_dir) + ep_number;
+
+ if (!(ep_enabled_reg & (1uL << ep_reg_pos)))
+ continue;
+
+ /* create empty endpoint object */
+ usb_ss_ep = devm_kzalloc(&usb_ss->dev, sizeof(*usb_ss_ep),
+ GFP_KERNEL);
+ if (!usb_ss_ep)
+ return -ENOMEM;
+
+ /* set parent of endpoint object */
+ usb_ss_ep->usb_ss = usb_ss;
+
+ /* set index of endpoint in endpoints container */
+ usb_ss->eps[found_endpoints++] = usb_ss_ep;
+
+ /* set name of endpoint */
+ snprintf(usb_ss_ep->name, sizeof(usb_ss_ep->name), "ep%d%s",
+ ep_number, !!ep_dir ? "in" : "out");
+ usb_ss_ep->endpoint.name = usb_ss_ep->name;
+ dev_dbg(&usb_ss->dev, "Initializing endpoint: %s\n",
+ usb_ss_ep->name);
+
+ usb_ep_set_maxpacket_limit(&usb_ss_ep->endpoint,
+ ENDPOINT_MAX_PACKET_LIMIT);
+ usb_ss_ep->endpoint.max_streams = ENDPOINT_MAX_STREAMS;
+ usb_ss_ep->endpoint.ops = &usb_ss_gadget_ep_ops;
+ if (ep_dir)
+ usb_ss_ep->endpoint.caps.dir_in = 1;
+ else
+ usb_ss_ep->endpoint.caps.dir_out = 1;
+
+ /* check endpoint type */
+ if (iso_ep_reg & (1uL << ep_reg_pos)) {
+ usb_ss_ep->endpoint.caps.type_iso = 1;
+ usb_ss_ep->is_iso_flag = 1;
+ }
+
+ if (bulk_ep_reg & (1uL << ep_reg_pos)) {
+ usb_ss_ep->endpoint.caps.type_bulk = 1;
+ usb_ss_ep->endpoint.caps.type_int = 1;
+ usb_ss_ep->endpoint.maxburst = 15;
+ }
+
+ list_add_tail(&usb_ss_ep->endpoint.ep_list,
+ &usb_ss->gadget.ep_list);
+ INIT_LIST_HEAD(&usb_ss_ep->request_list);
+ }
+ usb_ss->ep_nums = found_endpoints;
+ return 0;
+}
+
+/**
+ * usb_ss_init_ep0 Initializes software endpoint 0 of gadget
+ * @gadget: gadget object
+ *
+ * Returns 0 on success, error code elsewhere
+ */
+static int usb_ss_init_ep0(struct usb_ss_dev *usb_ss)
+{
+ struct usb_ss_endpoint *ep0;
+
+ dev_dbg(&usb_ss->dev, "Initializing EP0\n");
+ ep0 = devm_kzalloc(&usb_ss->dev, sizeof(struct usb_ss_endpoint),
+ GFP_KERNEL);
+
+ if (!ep0)
+ return -ENOMEM;
+
+ /* fill CDNS fields */
+ ep0->usb_ss = usb_ss;
+ sprintf(ep0->name, "ep0");
+
+ /* fill linux fields */
+ ep0->endpoint.ops = &usb_ss_gadget_ep0_ops;
+ ep0->endpoint.maxburst = 1;
+ usb_ep_set_maxpacket_limit(&ep0->endpoint, ENDPOINT0_MAX_PACKET_LIMIT);
+ ep0->endpoint.address = 0;
+ ep0->endpoint.enabled = 1;
+ ep0->endpoint.caps.type_control = 1;
+ ep0->endpoint.caps.dir_in = 1;
+ ep0->endpoint.caps.dir_out = 1;
+ ep0->endpoint.name = ep0->name;
+
+ usb_ss->gadget.ep0 = &ep0->endpoint;
+
+ return 0;
+}
+
+static void cdns3_gadget_release(struct device *dev)
+{
+ struct usb_ss_dev *usb_ss = container_of(dev, struct usb_ss_dev, dev);
+
+ dev_dbg(dev, "releasing '%s'\n", dev_name(dev));
+ kfree(usb_ss);
+}
+
+static int __cdns3_gadget_init(struct cdns3 *cdns)
+{
+ struct usb_ss_dev *usb_ss;
+ int ret;
+ struct device *dev;
+
+ usb_ss = kzalloc(sizeof(*usb_ss), GFP_KERNEL);
+ if (!usb_ss)
+ return -ENOMEM;
+
+ dev = &usb_ss->dev;
+ dev->release = cdns3_gadget_release;
+ dev->parent = cdns->dev;
+ dev_set_name(dev, "gadget-cdns3");
+ cdns->gadget_dev = dev;
+ usb_ss->sysdev = cdns->dev;
+ ret = device_register(dev);
+ if (ret)
+ goto err1;
+
+ usb_ss->regs = cdns->dev_regs;
+
+ /* fill gadget fields */
+ usb_ss->gadget.ops = &usb_ss_gadget_ops;
+ usb_ss->gadget.max_speed = USB_SPEED_SUPER;
+ usb_ss->gadget.speed = USB_SPEED_UNKNOWN;
+ usb_ss->gadget.name = "usb-ss-gadget";
+ usb_ss->gadget.sg_supported = 1;
+ usb_ss->is_connected = 0;
+
+ usb_ss->in_standby_mode = 1;
+
+ /* initialize endpoint container */
+ INIT_LIST_HEAD(&usb_ss->gadget.ep_list);
+ ret = usb_ss_init_ep0(usb_ss);
+ if (ret) {
+ dev_err(dev, "Failed to create endpoint 0\n");
+ ret = -ENOMEM;
+ goto err2;
+ }
+
+ ret = usb_ss_init_ep(usb_ss);
+ if (ret) {
+ dev_err(dev, "Failed to create non zero endpoints\n");
+ ret = -ENOMEM;
+ goto err2;
+ }
+
+ /* allocate memory for default endpoint TRB */
+ usb_ss->trb_ep0 = (u32 *)dma_alloc_coherent(usb_ss->sysdev, 20,
+ &usb_ss->trb_ep0_dma, GFP_DMA);
+ if (!usb_ss->trb_ep0) {
+ dev_err(dev, "Failed to allocate memory for ep0 TRB\n");
+ ret = -ENOMEM;
+ goto err2;
+ }
+
+ /* allocate memory for setup packet buffer */
+ usb_ss->setup = (u8 *)dma_alloc_coherent(usb_ss->sysdev, 8,
+ &usb_ss->setup_dma,
+ GFP_DMA);
+ if (!usb_ss->setup) {
+ dev_err(dev, "Failed to allocate memory for SETUP buffer\n");
+ ret = -ENOMEM;
+ goto err3;
+ }
+
+ /* add USB gadget device */
+ ret = usb_add_gadget_udc(&usb_ss->dev, &usb_ss->gadget);
+ if (ret < 0) {
+ dev_err(dev, "Failed to register USB device controller\n");
+ goto err4;
+ }
+
+ return 0;
+
+err4:
+ dma_free_coherent(usb_ss->sysdev, 8, usb_ss->setup,
+ usb_ss->setup_dma);
+err3:
+ dma_free_coherent(usb_ss->sysdev, 20, usb_ss->trb_ep0,
+ usb_ss->trb_ep0_dma);
+err2:
+ device_del(dev);
+err1:
+ put_device(dev);
+ cdns->gadget_dev = NULL;
+
+ return ret;
+}
+
+/**
+ * cdns3_gadget_remove: parent remove must call this to remove UDC
+ *
+ * cdns: cdns3 instance
+ *
+ */
+void cdns3_gadget_remove(struct cdns3 *cdns)
+{
+ struct usb_ss_dev *usb_ss;
+
+ if (!cdns->roles[CDNS3_ROLE_GADGET])
+ return;
+
+ usb_ss = container_of(cdns->gadget_dev, struct usb_ss_dev, dev);
+ usb_del_gadget_udc(&usb_ss->gadget);
+ dma_free_coherent(usb_ss->sysdev, 8, usb_ss->setup, usb_ss->setup_dma);
+ dma_free_coherent(usb_ss->sysdev, 20, usb_ss->trb_ep0,
+ usb_ss->trb_ep0_dma);
+ device_unregister(cdns->gadget_dev);
+ cdns->gadget_dev = NULL;
+}
+
+static int cdns3_gadget_start(struct cdns3 *cdns)
+{
+ struct usb_ss_dev *usb_ss = container_of(cdns->gadget_dev,
+ struct usb_ss_dev, dev);
+ unsigned long flags;
+
+ dev_dbg(&usb_ss->dev, "%s begins\n", __func__);
+
+ spin_lock_irqsave(&usb_ss->lock, flags);
+ usb_ss->start_gadget = 1;
+ if (!usb_ss->gadget_driver) {
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+ return 0;
+ }
+
+ /* configure endpoint 0 hardware */
+ cdns_ep0_config(usb_ss);
+
+ /* enable interrupts for endpoint 0 (in and out) */
+ gadget_writel(usb_ss, &usb_ss->regs->ep_ien,
+ EP_IEN__EOUTEN0__MASK | EP_IEN__EINEN0__MASK);
+
+ /* enable interrupt for device */
+ gadget_writel(usb_ss, &usb_ss->regs->usb_ien,
+ USB_IEN__U2RESIEN__MASK
+ | USB_ISTS__DIS2I__MASK
+ | USB_IEN__CON2IEN__MASK
+ | USB_IEN__UHRESIEN__MASK
+ | USB_IEN__UWRESIEN__MASK
+ | USB_IEN__DISIEN__MASK
+ | USB_IEN__CONIEN__MASK
+ | USB_IEN__U3EXTIEN__MASK
+ | USB_IEN__L2ENTIEN__MASK
+ | USB_IEN__L2EXTIEN__MASK);
+
+ gadget_writel(usb_ss, &usb_ss->regs->usb_conf,
+ USB_CONF__CLK2OFFDS__MASK
+ /* | USB_CONF__USB3DIS__MASK */
+ | USB_CONF__L1DS__MASK);
+
+ gadget_writel(usb_ss, &usb_ss->regs->usb_conf,
+ USB_CONF__U1DS__MASK
+ | USB_CONF__U2DS__MASK
+ /*
+ * TODO:
+ * | USB_CONF__L1EN__MASK
+ */
+ );
+
+ gadget_writel(usb_ss, &usb_ss->regs->usb_conf, USB_CONF__DEVEN__MASK);
+
+ gadget_writel(usb_ss, &usb_ss->regs->dbg_link1,
+ DBG_LINK1__LFPS_MIN_GEN_U1_EXIT_SET__MASK |
+ DBG_LINK1__LFPS_MIN_GEN_U1_EXIT__WRITE(0x3C));
+ usb_ss->in_standby_mode = 0;
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+ dev_dbg(&usb_ss->dev, "%s ends\n", __func__);
+
+ return 0;
+}
+
+static void cdns3_gadget_stop(struct cdns3 *cdns)
+{
+ struct usb_ss_dev *usb_ss;
+ unsigned long flags;
+
+ usb_ss = container_of(cdns->gadget_dev, struct usb_ss_dev, dev);
+ spin_lock_irqsave(&usb_ss->lock, flags);
+
+ /* disable interrupt for device */
+ gadget_writel(usb_ss, &usb_ss->regs->usb_ien, 0);
+ usb_ss->start_gadget = 0;
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+}
+
+/**
+ * cdns3_gadget_init - initialize device structure
+ *
+ * cdns: cdns3 instance
+ *
+ * This function initializes the gadget.
+ */
+int cdns3_gadget_init(struct cdns3 *cdns)
+{
+ struct cdns3_role_driver *rdrv;
+
+ rdrv = devm_kzalloc(cdns->dev, sizeof(*rdrv), GFP_KERNEL);
+ if (!rdrv)
+ return -ENOMEM;
+
+ rdrv->start = cdns3_gadget_start;
+ rdrv->stop = cdns3_gadget_stop;
+ rdrv->irq = cdns_irq_handler_thread;
+ rdrv->name = "gadget";
+ cdns->roles[CDNS3_ROLE_GADGET] = rdrv;
+ return __cdns3_gadget_init(cdns);
+}
diff --git a/drivers/usb/cdns3/gadget.h b/drivers/usb/cdns3/gadget.h
new file mode 100644
index 000000000000..6ecf380672e9
--- /dev/null
+++ b/drivers/usb/cdns3/gadget.h
@@ -0,0 +1,208 @@
+/**
+ * gadget.h - Cadence USB3 device Controller Core file
+ *
+ * Copyright (C) 2016 Cadence Design Systems - http://www.cadence.com
+ * Copyright 2017 NXP
+ *
+ * Authors: Pawel Jez ,
+ * Konrad Kociolek ,
+ * Peter Chen
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __DRIVERS_CDNS3_GADGET
+#define __DRIVERS_CDNS3_GADGET
+
+#include "dev-regs-map.h"
+
+#if IS_ENABLED(CONFIG_USB_CDNS_MISC)
+#include "cdns_misc.h"
+#endif
+
+#define gadget_to_usb_ss(g) \
+ (container_of(g, struct usb_ss_dev, gadget))
+
+#define to_usb_ss_ep(ep) \
+ (container_of(ep, struct usb_ss_endpoint, endpoint))
+
+#define ep_to_usb_ss_ep(ep) \
+ (container_of(ep, struct usb_ss_endpoint, endpoint))
+
+/*-------------------------------------------------------------------------*/
+/* TRB macros */
+
+/* Common TRB fields */
+#define TRB_SET_CYCLE_BIT 1uL
+#define TRB_SET_CHAIN_BIT 0x10
+
+/* offset 0 */
+#define TRB_DATA_BUFFER_POINTER_MASK 0xFFFFFFFF
+#define TRB_SET_DATA_BUFFER_POINTER(p) (p & TRB_DATA_BUFFER_POINTER_MASK)
+
+/* offset 4 */
+#define TRB_TRANSFER_LENGTH_MASK 0x1FFFF
+#define TRB_SET_TRANSFER_LENGTH(l) (l & TRB_TRANSFER_LENGTH_MASK)
+
+#define TRB_BURST_LENGTH_MASK 0xFF
+#define TRB_SET_BURST_LENGTH(l) ((l & TRB_BURST_LENGTH_MASK) << 24)
+
+/* offset 8 */
+#define TRB_SET_INT_ON_SHORT_PACKET 0x04
+#define TRB_SET_FIFO_MODE 0x08
+#define TRB_SET_INT_ON_COMPLETION 0x20
+
+#define TRB_TYPE_NORMAL 0x400
+
+#define TRB_STREAM_ID_MASK 0xFFFF
+#define TRB_SET_STREAM_ID(sid) ((sid & TRB_STREAM_ID_MASK) << 16)
+
+/*-------------------------------------------------------------------------*/
+/* Driver numeric constants */
+
+
+#define DEVICE_ADDRESS_MAX 127
+
+/* Endpoint init values */
+#define ENDPOINT_MAX_PACKET_LIMIT 1024
+#define ENDPOINT_MAX_STREAMS 15
+
+#define ENDPOINT0_MAX_PACKET_LIMIT 512
+
+/* All endpoints except EP0 */
+#define USB_SS_ENDPOINTS_MAX_COUNT 30
+
+#define USB_SS_TRBS_NUM 32
+
+/* Standby mode */
+#define STB_CLK_SWITCH_DONE_MASK 0x200
+#define STB_CLK_SWITCH_EN_MASK 0x100
+#define STB_CLK_SWITCH_EN_SHIFT 8
+
+#define ENDPOINT_MAX_PACKET_SIZE_0 0
+#define ENDPOINT_MAX_PACKET_SIZE_8 8
+#define ENDPOINT_MAX_PACKET_SIZE_64 64
+#define ENDPOINT_MAX_PACKET_SIZE_512 512
+#define ENDPOINT_MAX_PACKET_SIZE_1023 1023
+#define ENDPOINT_MAX_PACKET_SIZE_1024 1024
+
+#define SS_LINK_STATE_U3 3
+#define FSHS_LPM_STATE_L2 2
+
+#define ADDR_MODULO_8 8
+
+#define INTERRUPT_MASK 0xFFFFFFFF
+
+#define ACTUAL_TRANSFERRED_BYTES_MASK 0x1FFFF
+
+#define ENDPOINT_DIR_MASK 0x80
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * IS_REG_REQUIRING_ACTIVE_REF_CLOCK - Macro checks if desired
+ * register requires active clock, it involves such registers as:
+ * EP_CFG, EP_TR_ADDR, EP_CMD, EP_SEL, USB_CONF
+ * @usb_ss: extended gadget object
+ * @reg: register address
+ */
+#define IS_REG_REQUIRING_ACTIVE_REF_CLOCK(usb_ss, reg) (!reg || \
+ (reg >= &usb_ss->regs->ep_sel && reg <= &usb_ss->regs->ep_cmd))
+
+/**
+ * CAST_EP_REG_POS_TO_INDEX - Macro converts bit position of ep_ists register to
+ * index of endpoint object in usb_ss_dev.eps[] container
+ * @i: bit position of endpoint for which endpoint object is required
+ *
+ * Remember that endpoint container doesn't contain default endpoint
+ */
+#define CAST_EP_REG_POS_TO_INDEX(i) (((i) / 16) + ((((i) % 16) - 2) * 2))
+
+/**
+ * CAST_EP_ADDR_TO_INDEX - Macro converts endpoint address to
+ * index of endpoint object in usb_ss_dev.eps[] container
+ * @ep_addr: endpoint address for which endpoint object is required
+ *
+ * Remember that endpoint container doesn't contain default endpoint
+ */
+#define CAST_EP_ADDR_TO_INDEX(ep_addr) \
+ (((ep_addr & 0x7F) - 1) + ((ep_addr & 0x80) ? 1 : 0))
+
+/**
+ * CAST_EP_ADDR_TO_BIT_POS - Macro converts endpoint address to
+ * bit position in ep_ists register
+ * @ep_addr: endpoint address for which bit position is required
+ *
+ * Remember that endpoint container doesn't contain default endpoint
+ */
+#define CAST_EP_ADDR_TO_BIT_POS(ep_addr) \
+ (((uint32_t)1 << (ep_addr & 0x7F)) << ((ep_addr & 0x80) ? 16 : 0))
+
+
+#define CAST_INDEX_TO_EP_ADDR(index) \
+ ((index / 2 + 1) | ((index % 2) ? 0x80 : 0x00))
+
+/*-------------------------------------------------------------------------*/
+/* Used structs */
+
+struct usb_ss_trb {
+ u32 offset0;
+ u32 offset4;
+ u32 offset8;
+};
+
+struct usb_ss_dev;
+
+struct usb_ss_endpoint {
+ struct usb_ep endpoint;
+ struct list_head request_list;
+
+ struct usb_ss_trb *trb_pool;
+ dma_addr_t trb_pool_dma;
+
+ struct usb_ss_dev *usb_ss;
+ char name[20];
+ int hw_pending_flag;
+ int stalled_flag;
+ int is_iso_flag;
+ int wedge_flag;
+ void *cpu_addr;
+ dma_addr_t dma_addr;
+};
+
+struct usb_ss_dev {
+ struct device dev;
+ struct usbss_dev_register_block_type __iomem *regs;
+
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *gadget_driver;
+
+ dma_addr_t setup_dma;
+ dma_addr_t trb_ep0_dma;
+ u32 *trb_ep0;
+ u8 *setup;
+
+ struct usb_ss_endpoint *eps[USB_SS_ENDPOINTS_MAX_COUNT];
+ int ep_nums;
+ struct usb_request *actual_ep0_request;
+ int ep0_data_dir;
+ int hw_configured_flag;
+ int wake_up_flag;
+ u16 isoch_delay;
+ spinlock_t lock;
+
+ unsigned is_connected:1;
+ unsigned in_standby_mode:1;
+
+ u32 usb_ien;
+ u32 ep_ien;
+ int setup_pending;
+ struct device *sysdev;
+ bool start_gadget; /* The device mode is enabled */
+};
+
+#endif /* __DRIVERS_CDNS3_GADGET */
diff --git a/drivers/usb/cdns3/host-export.h b/drivers/usb/cdns3/host-export.h
new file mode 100644
index 000000000000..a981d5cf3658
--- /dev/null
+++ b/drivers/usb/cdns3/host-export.h
@@ -0,0 +1,43 @@
+/*
+ * host-export.h - Host Export APIs
+ *
+ * Copyright 2017 NXP
+ * Authors: Peter Chen
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __DRIVERS_USB_CDNS3_HOST_H
+#define __DRIVERS_USB_CDNS3_HOST_H
+
+#ifdef CONFIG_USB_CDNS3_HOST
+
+int cdns3_host_init(struct cdns3 *cdns);
+void cdns3_host_remove(struct cdns3 *cdns);
+void cdns3_host_driver_init(void);
+
+#else
+
+static inline int cdns3_host_init(struct cdns3 *cdns)
+{
+ return -ENXIO;
+}
+
+static inline void cdns3_host_remove(struct cdns3 *cdns)
+{
+
+}
+
+static inline void cdns3_host_driver_init(void)
+{
+
+}
+
+#endif /* CONFIG_USB_CDNS3_HOST */
+
+#endif /* __DRIVERS_USB_CDNS3_HOST_H */
diff --git a/drivers/usb/cdns3/host.c b/drivers/usb/cdns3/host.c
new file mode 100644
index 000000000000..26cd76f088d0
--- /dev/null
+++ b/drivers/usb/cdns3/host.c
@@ -0,0 +1,211 @@
+/*
+ * host.c - Cadence USB3 host controller driver
+ *
+ * Copyright 2017 NXP
+ * Authors: Peter Chen
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "../host/xhci.h"
+
+#include "core.h"
+#include "host-export.h"
+
+static struct hc_driver __read_mostly xhci_cdns3_hc_driver;
+
+static void xhci_cdns3_quirks(struct device *dev, struct xhci_hcd *xhci)
+{
+ /*
+ * As of now platform drivers don't provide MSI support so we ensure
+ * here that the generic code does not try to make a pci_dev from our
+ * dev struct in order to setup MSI
+ */
+ xhci->quirks |= XHCI_PLAT;
+}
+
+static int xhci_cdns3_setup(struct usb_hcd *hcd)
+{
+ return xhci_gen_setup(hcd, xhci_cdns3_quirks);
+}
+
+static const struct xhci_driver_overrides xhci_cdns3_overrides __initconst = {
+ .extra_priv_size = sizeof(struct xhci_hcd),
+ .reset = xhci_cdns3_setup,
+};
+
+struct cdns3_host {
+ struct device dev;
+ struct usb_hcd *hcd;
+};
+
+static irqreturn_t cdns3_host_irq(struct cdns3 *cdns)
+{
+ struct device *dev = cdns->host_dev;
+ struct usb_hcd *hcd;
+
+ if (dev)
+ hcd = dev_get_drvdata(dev);
+ else
+ return IRQ_NONE;
+
+ if (hcd)
+ return usb_hcd_irq(cdns->irq, hcd);
+ else
+ return IRQ_NONE;
+}
+
+static void cdns3_host_release(struct device *dev)
+{
+ struct cdns3_host *host = container_of(dev, struct cdns3_host, dev);
+
+ dev_dbg(dev, "releasing '%s'\n", dev_name(dev));
+ kfree(host);
+}
+
+static int cdns3_host_start(struct cdns3 *cdns)
+{
+ struct cdns3_host *host;
+ struct device *dev;
+ struct device *sysdev;
+ struct xhci_hcd *xhci;
+ int ret;
+
+ host = kzalloc(sizeof(*host), GFP_KERNEL);
+ if (!host)
+ return -ENOMEM;
+
+ dev = &host->dev;
+ dev->release = cdns3_host_release;
+ dev->parent = cdns->dev;
+ dev_set_name(dev, "xhci-cdns3");
+ cdns->host_dev = dev;
+ ret = device_register(dev);
+ if (ret)
+ goto err1;
+
+ sysdev = cdns->dev;
+ /* Try to set 64-bit DMA first */
+ if (WARN_ON(!sysdev->dma_mask))
+ /* Platform did not initialize dma_mask */
+ ret = dma_coerce_mask_and_coherent(sysdev,
+ DMA_BIT_MASK(64));
+ else
+ ret = dma_set_mask_and_coherent(sysdev, DMA_BIT_MASK(64));
+
+ /* If setting 64-bit DMA mask fails, fall back to 32-bit DMA mask */
+ if (ret) {
+ ret = dma_set_mask_and_coherent(sysdev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+ }
+ dev_info(dev, "%s begins create hcd\n", __func__);
+
+ host->hcd = __usb_create_hcd(&xhci_cdns3_hc_driver, sysdev, dev,
+ dev_name(dev), NULL);
+ if (!host->hcd) {
+ ret = -ENOMEM;
+ goto err2;
+ }
+
+ host->hcd->regs = cdns->xhci_regs;
+ host->hcd->rsrc_start = cdns->xhci_res->start;
+ host->hcd->rsrc_len = resource_size(cdns->xhci_res);
+
+ device_wakeup_enable(host->hcd->self.controller);
+
+ xhci = hcd_to_xhci(host->hcd);
+
+ xhci->main_hcd = host->hcd;
+ xhci->shared_hcd = __usb_create_hcd(&xhci_cdns3_hc_driver, sysdev, dev,
+ dev_name(dev), host->hcd);
+ if (!xhci->shared_hcd) {
+ ret = -ENOMEM;
+ goto err3;
+ }
+
+ ret = usb_add_hcd(host->hcd, 0, IRQF_SHARED);
+ if (ret)
+ goto err4;
+
+ ret = usb_add_hcd(xhci->shared_hcd, 0, IRQF_SHARED);
+ if (ret)
+ goto err5;
+
+ dev_dbg(dev, "%s ends\n", __func__);
+ return 0;
+
+err5:
+ usb_remove_hcd(host->hcd);
+err4:
+ usb_put_hcd(xhci->shared_hcd);
+err3:
+ usb_put_hcd(host->hcd);
+err2:
+ device_del(dev);
+err1:
+ put_device(dev);
+ cdns->host_dev = NULL;
+ return ret;
+}
+
+static void cdns3_host_stop(struct cdns3 *cdns)
+{
+ struct device *dev = cdns->host_dev;
+ struct usb_hcd *hcd;
+ struct xhci_hcd *xhci;
+
+ if (dev) {
+ hcd = dev_get_drvdata(dev);
+ xhci = hcd_to_xhci(hcd);
+ usb_remove_hcd(hcd);
+ usb_remove_hcd(xhci->shared_hcd);
+ cdns->role = CDNS3_ROLE_END;
+ synchronize_irq(cdns->irq);
+ usb_put_hcd(hcd);
+ usb_put_hcd(xhci->shared_hcd);
+ cdns->host_dev = NULL;
+ device_del(dev);
+ put_device(dev);
+ }
+}
+
+int cdns3_host_init(struct cdns3 *cdns)
+{
+ struct cdns3_role_driver *rdrv;
+
+ rdrv = devm_kzalloc(cdns->dev, sizeof(*rdrv), GFP_KERNEL);
+ if (!rdrv)
+ return -ENOMEM;
+
+ rdrv->start = cdns3_host_start;
+ rdrv->stop = cdns3_host_stop;
+ rdrv->irq = cdns3_host_irq;
+ rdrv->name = "host";
+ cdns->roles[CDNS3_ROLE_HOST] = rdrv;
+
+ return 0;
+}
+
+void cdns3_host_remove(struct cdns3 *cdns)
+{
+ cdns3_host_stop(cdns);
+}
+
+void __init cdns3_host_driver_init(void)
+{
+ xhci_init_driver(&xhci_cdns3_hc_driver, &xhci_cdns3_overrides);
+}
diff --git a/drivers/usb/cdns3/io.h b/drivers/usb/cdns3/io.h
new file mode 100644
index 000000000000..c16edbf54b8b
--- /dev/null
+++ b/drivers/usb/cdns3/io.h
@@ -0,0 +1,35 @@
+/**
+ * io.h - Cadence USB3 IO Header
+ *
+ * Copyright (C) 2016 Cadence Design Systems - https://www.cadence.com/
+ *
+ * Authors: Rafal Ozieblo ,
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __DRIVERS_USB_CDNS_IO_H
+#define __DRIVERS_USB_CDNS_IO_H
+
+#include
+
+static inline u32 cdns_readl(uint32_t __iomem *reg)
+{
+ u32 value = 0;
+
+ value = readl(reg);
+ return value;
+}
+
+static inline void cdns_writel(uint32_t __iomem *reg, u32 value)
+{
+ writel(value, reg);
+}
+
+
+#endif /* __DRIVERS_USB_CDNS_IO_H */