Commit 70514bd0 authored by Ye Li's avatar Ye Li

MLK-17821-1 USB: gadget: Add the cadence USB3 gadget driver

Porting the cadence USB3 (CDNS3) driver from kernel to u-boot. We only support
the gadget (device mode), while the host mode is not supported. Users remains
to use xhci-imx8 driver for host mode.

Some changes in the CDNS3 driver porting:

1. Add match_ep call back to usb_gadget_ops. The CDNS3 gadget driver replies
   on this operation to bind the usb_ep/usb_ss_ep with the endpoint descriptor
   when function layer uses usb_ep_autoconfig to add endpoint descriptors to gadget.
   So that CDNS3 driver can know the EP information and configure the EP once the
   set configuration request is received.

2. U-boot does not have CMA, so it won't allocate uncached memory. Need to flush
   TRB and its DMA buffer before prime to usb controller and after complete transfer.

3. In core.c, we add functions to hook with u-boot. It needs uplayer like
   to pass the register base address of each part of the USB controller.

4. Force the CDNS3 gadget max speed to HS. The SuperSpeed is not supported by u-boot,
   so disable it in gadget driver. A configuration USB_CDNS3_GADGET_FORCE_HIGHSPEED is
   selected.

5. Added gadget_is_cdns3 checking to provide bcdUSB value in device descriptor.

6. Moved some new fields in usb_ep structure to usb_ss_ep, since u-boot does not have them.

7. Remove host part codes as it is not supported by this driver.
Signed-off-by: 's avatarYe Li <ye.li@nxp.com>
Acked-by: 's avatarPeter Chen <peter.chen@nxp.com>
parent 2fd813fc
......@@ -675,6 +675,7 @@ libs-$(CONFIG_SYS_FSL_DDR) += drivers/ddr/fsl/
libs-$(CONFIG_SYS_FSL_MMDC) += drivers/ddr/fsl/
libs-$(CONFIG_ALTERA_SDRAM) += drivers/ddr/altera/
libs-y += drivers/serial/
libs-y += drivers/usb/cdns3/
libs-y += drivers/usb/dwc3/
libs-y += drivers/usb/common/
libs-y += drivers/usb/emul/
......
......@@ -51,6 +51,8 @@ source "drivers/usb/host/Kconfig"
source "drivers/usb/dwc3/Kconfig"
source "drivers/usb/cdns3/Kconfig"
source "drivers/usb/musb-new/Kconfig"
source "drivers/usb/emul/Kconfig"
......
config USB_CDNS3
tristate "Cadence USB3 Dual-Role Controller"
depends on (USB && USB_GADGET)
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_FORCE_HIGHSPEED
bool
config USB_CDNS3_GADGET
bool "Cadence USB3 device controller"
depends on USB_GADGET
select USB_GADGET_DUALSPEED
select USB_CDNS3_GADGET_FORCE_HIGHSPEED
help
Say Y here to enable device controller functionality of the
cadence usb3 driver.
endif
obj-$(CONFIG_USB_CDNS3) += cdns3.o
cdns3-y := core.o
cdns3-$(CONFIG_USB_CDNS3_GADGET) += gadget.o
/*
* Copyright 2018 NXP
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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 SW_RESET_MASK (0x3f << 26)
#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 MDCTRL_CLK_SEL (1 << 7)
#define MODE_STRAP_MASK (0x7)
#define DEV_MODE (1 << 2)
#define HOST_MODE (1 << 1)
#define OTG_MODE (1 << 0)
/* USB3_INT_REG */
#define CLK_125_REQ (1 << 29)
#define LPM_CLK_REQ (1 << 28)
#define DEVU3_WAEKUP_EN (1 << 14)
#define OTG_WAKEUP_EN (1 << 12)
#define DEV_INT_EN (3 << 8) /* DEV INT b9:8 */
#define HOST_INT1_EN (1 << 0) /* HOST INT b7:0 */
/* USB3_CORE_STATUS */
#define MDCTRL_CLK_STATUS (1 << 15)
#define DEV_POWER_ON_READY (1 << 13)
#define HOST_POWER_ON_READY (1 << 12)
/* USB3_SSPHY_STATUS */
#define PHY_REFCLK_REQ (1 << 0)
/* 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)
#define TB_ADDR_TX_RCVDETSC_CTRL (0x4124 * 4)
/* Register bits definition */
/* TB_ADDR_TX_RCVDETSC_CTRL */
#define RXDET_IN_P3_32KHZ (1 << 0)
/* OTG registers definition */
#define OTGSTS 0x4
#define OTGREFCLK 0xc
/* Register bits definition */
/* OTGSTS */
#define OTG_NRDY (1 << 11)
/* OTGREFCLK */
#define OTG_STB_CLK_SWITCH_EN (1 << 31)
/* xHCI registers definition */
#define XECP_PORT_CAP_REG 0x8000
#define XECP_PM_PMCSR 0x8018
#define XECP_AUX_CTRL_REG1 0x8120
/* Register bits definition */
/* XECP_PORT_CAP_REG */
#define LPM_2_STB_SWITCH_EN (1 << 25)
/* XECP_AUX_CTRL_REG1 */
#define CFG_RXDET_P3_EN (1 << 15)
/* XECP_PM_PMCSR */
#define PS_D0 (1 << 0)
#endif /* __DRIVERS_USB_CDNS3_NXP_H */
/*
* Copyright (C) 2016 Cadence Design Systems - https://www.cadence.com/
* Copyright 2018 NXP
*
* SPDX-License-Identifier: GPL-2.0
*/
#include <common.h>
#include <malloc.h>
#include <asm/dma-mapping.h>
#include <asm/io.h>
#include <linux/bug.h>
#include <linux/list.h>
#include <linux/compat.h>
#include <cdns3-uboot.h>
#include "linux-compat.h"
#include "cdns3-nxp-reg-def.h"
#include "core.h"
#include "gadget-export.h"
static LIST_HEAD(cdns3_list);
/* Need SoC level to implement the clock */
__weak int cdns3_enable_clks(int index)
{
return 0;
}
__weak int cdns3_disable_clks(int index)
{
return 0;
}
static void cdns3_usb_phy_init(void __iomem *regs)
{
u32 value;
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(0x509b, 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);
/* RXDET_IN_P3_32KHZ, Receiver detect slow clock enable */
value = readl(regs + TB_ADDR_TX_RCVDETSC_CTRL);
value |= RXDET_IN_P3_32KHZ;
writel(value, regs + TB_ADDR_TX_RCVDETSC_CTRL);
udelay(10);
pr_debug("end of %s\n", __func__);
}
static void cdns3_reset_core(struct cdns3 *cdns)
{
u32 value;
value = readl(cdns->none_core_regs + USB3_CORE_CTRL1);
value |= ALL_SW_RESET;
writel(value, cdns->none_core_regs + USB3_CORE_CTRL1);
udelay(1);
}
static void cdns3_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);
/* Force B Session Valid as 1 */
writel(0x0060, cdns->phy_regs + 0x380a4);
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);
/* Force B Session Valid as 1 */
writel(0x0060, cdns->phy_regs + 0x380a4);
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)
{
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, enum usb_dr_mode dr_mode)
{
cdns->role = CDNS3_ROLE_END;
if (dr_mode == USB_DR_MODE_UNKNOWN)
dr_mode = USB_DR_MODE_OTG;
/* Currently, only support gadget mode */
if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) {
dev_err(cdns->dev, "doesn't support host and OTG, only for gadget\n");
return -EPERM;
}
if (dr_mode == USB_DR_MODE_PERIPHERAL) {
if (cdns3_gadget_init(cdns))
dev_info(cdns->dev, "doesn't support gadget\n");
}
if (!cdns->roles[CDNS3_ROLE_HOST] && !cdns->roles[CDNS3_ROLE_GADGET]) {
dev_err(cdns->dev, "no supported roles\n");
return -ENODEV;
}
return 0;
}
static void cdns3_remove_roles(struct cdns3 *cdns)
{
/* Only support gadget */
cdns3_gadget_remove(cdns);
}
int cdns3_uboot_init(struct cdns3_device *cdns3_dev)
{
struct device *dev = NULL;
struct cdns3 *cdns;
int ret;
cdns = devm_kzalloc(dev, sizeof(*cdns), GFP_KERNEL);
if (!cdns)
return -ENOMEM;
cdns->dev = dev;
/*
* Request memory region
* region-0: nxp wrap registers
* region-1: xHCI
* region-2: Peripheral
* region-3: PHY registers
* region-4: OTG registers
*/
cdns->none_core_regs = (void __iomem *)cdns3_dev->none_core_base;
cdns->xhci_regs = (void __iomem *)cdns3_dev->xhci_base;
cdns->dev_regs = (void __iomem *)cdns3_dev->dev_base;
cdns->phy_regs = (void __iomem *)cdns3_dev->phy_base;
cdns->otg_regs = (void __iomem *)cdns3_dev->otg_base;
cdns->index = cdns3_dev->index;
ret = cdns3_enable_clks(cdns->index);
if (ret)
return ret;
ret = cdns3_core_init_role(cdns, cdns3_dev->dr_mode);
if (ret)
goto err1;
cdns->role = cdns3_get_role(cdns);
dev_dbg(dev, "the init role is %d\n", cdns->role);
cdns3_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 err2;
}
dev_dbg(dev, "Cadence USB3 core: probe succeed\n");
list_add_tail(&cdns->list, &cdns3_list);
return 0;
err2:
cdns3_remove_roles(cdns);
err1:
cdns3_disable_clks(cdns->index);
return ret;
}
void cdns3_uboot_exit(int index)
{
struct cdns3 *cdns;
list_for_each_entry(cdns, &cdns3_list, list) {
if (cdns->index != index)
continue;
cdns3_role_stop(cdns);
cdns3_remove_roles(cdns);
cdns3_reset_core(cdns);
cdns3_disable_clks(index);
list_del(&cdns->list);
kfree(cdns);
break;
}
}
void cdns3_uboot_handle_interrupt(int index)
{
struct cdns3 *cdns = NULL;
list_for_each_entry(cdns, &cdns3_list, list) {
if (cdns->index != index)
continue;
cdns3_role_irq_handler(cdns);
break;
}
}
/*
* Copyright 2018 NXP
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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
* @suspend: suspend callback for this role
* @resume: resume callback for 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 *);
int (*suspend)(struct cdns3 *, bool do_wakeup);
int (*resume)(struct cdns3 *, bool hibernated);
int (*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
* @otg_regs: pointer to base of otg 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
* @in_lpm: the controller in low power mode
* @wakeup_int: the wakeup interrupt
*/
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;
void __iomem *phy_regs;
void __iomem *otg_regs;
int irq;
struct cdns3_role_driver *roles[CDNS3_ROLE_END];
enum cdns3_roles role;
struct device *host_dev;
struct device *gadget_dev;
struct clk *cdns3_clks[CDNS3_NUM_OF_CLKS];
int index;
struct list_head list;
};
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)
{
if (role >= CDNS3_ROLE_END)
return 0;
if (!cdns->roles[role])
return -ENXIO;
cdns->role = role;
return cdns->roles[role]->start(cdns);
}
static inline void cdns3_role_stop(struct cdns3 *cdns)
{
enum cdns3_roles role = cdns->role;
if (role == CDNS3_ROLE_END)
return;
cdns->roles[role]->stop(cdns);
cdns->role = CDNS3_ROLE_END;
}
static inline void cdns3_role_irq_handler(struct cdns3 *cdns)
{
enum cdns3_roles role = cdns->role;
if (role == CDNS3_ROLE_END)
return;
cdns->roles[role]->irq(cdns);
}
#endif /* __DRIVERS_USB_CDNS3_CORE_H */
/*
* Copyright (C) 2016 Cadence Design Systems - http://www.cadence.com
* Copyright 2018 NXP
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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__DEVDS__MASK 0x00008000U
#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 */