From d0912be964679ada052bcd07a03d4689e84dce2e Mon Sep 17 00:00:00 2001 From: Nitin Garg Date: Tue, 27 May 2014 12:11:43 -0500 Subject: ENGR00315499-6 ARM:imx6: Add USB gadget driver imx_udc to support Android fastboot Android fastboot leans on the USB gadget driver to communicate with host. Porting the imx_udc driver from v2009.08 with two changes: adding resource/memory release APIs and replacing the uncached memory with cache flush&invalidate operations. Pins and Clocks initialization are added to support boards: mx6qdlsabresd, mx6qdlsabreauto, mx6slevk Signed-off-by: Ye.Li Signed-off-by: Nitin Garg --- arch/arm/cpu/armv7/mx6/soc.c | 50 ++ arch/arm/imx-common/iomux-v3.c | 15 + arch/arm/include/asm/arch-mx6/crm_regs.h | 5 + arch/arm/include/asm/arch-mx6/imx-regs.h | 6 + arch/arm/include/asm/arch-mx6/mx6_usbphy.h | 480 ++++++++++ arch/arm/include/asm/arch-mx6/mx6sl_pins.h | 1 + arch/arm/include/asm/imx-common/iomux-v3.h | 5 + board/freescale/mx6qsabreauto/mx6qsabreauto.c | 15 + board/freescale/mx6sabresd/mx6sabresd.c | 13 + board/freescale/mx6slevk/mx6slevk.c | 12 + drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/imx_udc.c | 1189 +++++++++++++++++++++++++ include/usb/imx_udc.h | 573 ++++++++++++ 13 files changed, 2365 insertions(+) create mode 100644 arch/arm/include/asm/arch-mx6/mx6_usbphy.h create mode 100644 drivers/usb/gadget/imx_udc.c create mode 100644 include/usb/imx_udc.h diff --git a/arch/arm/cpu/armv7/mx6/soc.c b/arch/arm/cpu/armv7/mx6/soc.c index 20ee264..a386e03 100644 --- a/arch/arm/cpu/armv7/mx6/soc.c +++ b/arch/arm/cpu/armv7/mx6/soc.c @@ -21,6 +21,10 @@ #include #include #include +#ifdef CONFIG_IMX_UDC +#include +#include +#endif enum ldo_reg { LDO_ARM, @@ -653,3 +657,49 @@ void v7_outer_cache_disable(void) clrbits_le32(&pl310->pl310_ctrl, L2X0_CTRL_EN); } #endif /* !CONFIG_SYS_L2CACHE_OFF */ + +#ifdef CONFIG_IMX_UDC +void set_usboh3_clk(void) +{ + udc_pins_setting(); +} + +void set_usb_phy1_clk(void) +{ + /* make sure pll3 is enable here */ + writel((BM_ANADIG_USB1_CHRG_DETECT_EN_B | + BM_ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B), + ANATOP_BASE_ADDR + HW_ANADIG_USB1_CHRG_DETECT_SET); + + writel(BM_ANADIG_USB1_PLL_480_CTRL_EN_USB_CLKS, + ANATOP_BASE_ADDR + HW_ANADIG_USB1_PLL_480_CTRL_SET); +} +void enable_usb_phy1_clk(unsigned char enable) +{ + if (enable) + writel(BM_USBPHY_CTRL_CLKGATE, + USB_PHY0_BASE_ADDR + HW_USBPHY_CTRL_CLR); + else + writel(BM_USBPHY_CTRL_CLKGATE, + USB_PHY0_BASE_ADDR + HW_USBPHY_CTRL_SET); +} + +void reset_usb_phy1(void) +{ + /* Reset USBPHY module */ + u32 temp; + temp = readl(USB_PHY0_BASE_ADDR + HW_USBPHY_CTRL); + temp |= BM_USBPHY_CTRL_SFTRST; + writel(temp, USB_PHY0_BASE_ADDR + HW_USBPHY_CTRL); + udelay(10); + + /* Remove CLKGATE and SFTRST */ + temp = readl(USB_PHY0_BASE_ADDR + HW_USBPHY_CTRL); + temp &= ~(BM_USBPHY_CTRL_CLKGATE | BM_USBPHY_CTRL_SFTRST); + writel(temp, USB_PHY0_BASE_ADDR + HW_USBPHY_CTRL); + udelay(10); + + /* Power up the PHY */ + writel(0, USB_PHY0_BASE_ADDR + HW_USBPHY_PWD); +} +#endif diff --git a/arch/arm/imx-common/iomux-v3.c b/arch/arm/imx-common/iomux-v3.c index b59b802..11cfc33 100644 --- a/arch/arm/imx-common/iomux-v3.c +++ b/arch/arm/imx-common/iomux-v3.c @@ -55,3 +55,18 @@ void imx_iomux_v3_setup_multiple_pads(iomux_v3_cfg_t const *pad_list, for (i = 0; i < count; i++) imx_iomux_v3_setup_pad(*p++); } + +void mxc_iomux_set_gpr_register(int group, int start_bit, + int num_bits, int value) +{ + int i = 0; + u32 reg; + reg = readl(base + group * 4); + while (num_bits) { + reg &= ~(1<<(start_bit + i)); + i++; + num_bits--; + } + reg |= (value << start_bit); + writel(reg, base + group * 4); +} diff --git a/arch/arm/include/asm/arch-mx6/crm_regs.h b/arch/arm/include/asm/arch-mx6/crm_regs.h index 723f498..047a978 100644 --- a/arch/arm/include/asm/arch-mx6/crm_regs.h +++ b/arch/arm/include/asm/arch-mx6/crm_regs.h @@ -615,6 +615,11 @@ struct mxc_ccm_reg { #define BF_ANADIG_PLL_SYS_DIV_SELECT(v) \ (((v) << 0) & BM_ANADIG_PLL_SYS_DIV_SELECT) +#define HW_ANADIG_USB1_PLL_480_CTRL (0x00000010) +#define HW_ANADIG_USB1_PLL_480_CTRL_SET (0x00000014) +#define HW_ANADIG_USB1_PLL_480_CTRL_CLR (0x00000018) +#define HW_ANADIG_USB1_PLL_480_CTRL_TOG (0x0000001c) + #define BM_ANADIG_USB1_PLL_480_CTRL_LOCK 0x80000000 #define BP_ANADIG_USB1_PLL_480_CTRL_RSVD1 17 #define BM_ANADIG_USB1_PLL_480_CTRL_RSVD1 0x7FFE0000 diff --git a/arch/arm/include/asm/arch-mx6/imx-regs.h b/arch/arm/include/asm/arch-mx6/imx-regs.h index 29e969d..30210f2 100644 --- a/arch/arm/include/asm/arch-mx6/imx-regs.h +++ b/arch/arm/include/asm/arch-mx6/imx-regs.h @@ -216,6 +216,12 @@ #define IP2APB_USBPHY1_BASE_ADDR (AIPS2_OFF_BASE_ADDR + 0x78000) #define IP2APB_USBPHY2_BASE_ADDR (AIPS2_OFF_BASE_ADDR + 0x7C000) +#ifdef CONFIG_MX6SL +#define OTG_BASE_ADDR USBO2H_USB_BASE_ADDR +#else +#define OTG_BASE_ADDR USBOH3_USB_BASE_ADDR +#endif + #define CHIP_REV_1_0 0x10 #define CHIP_REV_1_1 0x11 #define CHIP_REV_1_2 0x12 diff --git a/arch/arm/include/asm/arch-mx6/mx6_usbphy.h b/arch/arm/include/asm/arch-mx6/mx6_usbphy.h new file mode 100644 index 0000000..0d9a4f5 --- /dev/null +++ b/arch/arm/include/asm/arch-mx6/mx6_usbphy.h @@ -0,0 +1,480 @@ +/* + * Copyright (C) 2008-2014 Freescale Semiconductor, Inc. All Rights Reserved. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __ASM_ARCH_MX6_MX6_USBPHY_H__ +#define __ASM_ARCH_MX6_MX6_USBPHY_H__ + +#define HW_USBPHY_PWD (0x00000000) +#define HW_USBPHY_PWD_SET (0x00000004) +#define HW_USBPHY_PWD_CLR (0x00000008) +#define HW_USBPHY_PWD_TOG (0x0000000c) + +#define BP_USBPHY_PWD_RSVD2 21 +#define BM_USBPHY_PWD_RSVD2 0xFFE00000 +#define BF_USBPHY_PWD_RSVD2(v) \ + (((v) << 21) & BM_USBPHY_PWD_RSVD2) +#define BM_USBPHY_PWD_RXPWDRX 0x00100000 +#define BM_USBPHY_PWD_RXPWDDIFF 0x00080000 +#define BM_USBPHY_PWD_RXPWD1PT1 0x00040000 +#define BM_USBPHY_PWD_RXPWDENV 0x00020000 +#define BP_USBPHY_PWD_RSVD1 13 +#define BM_USBPHY_PWD_RSVD1 0x0001E000 +#define BF_USBPHY_PWD_RSVD1(v) \ + (((v) << 13) & BM_USBPHY_PWD_RSVD1) +#define BM_USBPHY_PWD_TXPWDV2I 0x00001000 +#define BM_USBPHY_PWD_TXPWDIBIAS 0x00000800 +#define BM_USBPHY_PWD_TXPWDFS 0x00000400 +#define BP_USBPHY_PWD_RSVD0 0 +#define BM_USBPHY_PWD_RSVD0 0x000003FF +#define BF_USBPHY_PWD_RSVD0(v) \ + (((v) << 0) & BM_USBPHY_PWD_RSVD0) + +#define HW_USBPHY_TX (0x00000010) +#define HW_USBPHY_TX_SET (0x00000014) +#define HW_USBPHY_TX_CLR (0x00000018) +#define HW_USBPHY_TX_TOG (0x0000001c) + +#define BP_USBPHY_TX_RSVD5 29 +#define BM_USBPHY_TX_RSVD5 0xE0000000 +#define BF_USBPHY_TX_RSVD5(v) \ + (((v) << 29) & BM_USBPHY_TX_RSVD5) +#define BP_USBPHY_TX_USBPHY_TX_EDGECTRL 26 +#define BM_USBPHY_TX_USBPHY_TX_EDGECTRL 0x1C000000 +#define BF_USBPHY_TX_USBPHY_TX_EDGECTRL(v) \ + (((v) << 26) & BM_USBPHY_TX_USBPHY_TX_EDGECTRL) +#define BM_USBPHY_TX_USBPHY_TX_SYNC_INVERT 0x02000000 +#define BM_USBPHY_TX_USBPHY_TX_SYNC_MUX 0x01000000 +#define BP_USBPHY_TX_RSVD4 22 +#define BM_USBPHY_TX_RSVD4 0x00C00000 +#define BF_USBPHY_TX_RSVD4(v) \ + (((v) << 22) & BM_USBPHY_TX_RSVD4) +#define BM_USBPHY_TX_TXENCAL45DP 0x00200000 +#define BM_USBPHY_TX_RSVD3 0x00100000 +#define BP_USBPHY_TX_TXCAL45DP 16 +#define BM_USBPHY_TX_TXCAL45DP 0x000F0000 +#define BF_USBPHY_TX_TXCAL45DP(v) \ + (((v) << 16) & BM_USBPHY_TX_TXCAL45DP) +#define BP_USBPHY_TX_RSVD2 14 +#define BM_USBPHY_TX_RSVD2 0x0000C000 +#define BF_USBPHY_TX_RSVD2(v) \ + (((v) << 14) & BM_USBPHY_TX_RSVD2) +#define BM_USBPHY_TX_TXENCAL45DN 0x00002000 +#define BM_USBPHY_TX_RSVD1 0x00001000 +#define BP_USBPHY_TX_TXCAL45DN 8 +#define BM_USBPHY_TX_TXCAL45DN 0x00000F00 +#define BF_USBPHY_TX_TXCAL45DN(v) \ + (((v) << 8) & BM_USBPHY_TX_TXCAL45DN) +#define BP_USBPHY_TX_RSVD0 4 +#define BM_USBPHY_TX_RSVD0 0x000000F0 +#define BF_USBPHY_TX_RSVD0(v) \ + (((v) << 4) & BM_USBPHY_TX_RSVD0) +#define BP_USBPHY_TX_D_CAL 0 +#define BM_USBPHY_TX_D_CAL 0x0000000F +#define BF_USBPHY_TX_D_CAL(v) \ + (((v) << 0) & BM_USBPHY_TX_D_CAL) + +#define HW_USBPHY_RX (0x00000020) +#define HW_USBPHY_RX_SET (0x00000024) +#define HW_USBPHY_RX_CLR (0x00000028) +#define HW_USBPHY_RX_TOG (0x0000002c) + +#define BP_USBPHY_RX_RSVD2 23 +#define BM_USBPHY_RX_RSVD2 0xFF800000 +#define BF_USBPHY_RX_RSVD2(v) \ + (((v) << 23) & BM_USBPHY_RX_RSVD2) +#define BM_USBPHY_RX_RXDBYPASS 0x00400000 +#define BP_USBPHY_RX_RSVD1 7 +#define BM_USBPHY_RX_RSVD1 0x003FFF80 +#define BF_USBPHY_RX_RSVD1(v) \ + (((v) << 7) & BM_USBPHY_RX_RSVD1) +#define BP_USBPHY_RX_DISCONADJ 4 +#define BM_USBPHY_RX_DISCONADJ 0x00000070 +#define BF_USBPHY_RX_DISCONADJ(v) \ + (((v) << 4) & BM_USBPHY_RX_DISCONADJ) +#define BM_USBPHY_RX_RSVD0 0x00000008 +#define BP_USBPHY_RX_ENVADJ 0 +#define BM_USBPHY_RX_ENVADJ 0x00000007 +#define BF_USBPHY_RX_ENVADJ(v) \ + (((v) << 0) & BM_USBPHY_RX_ENVADJ) + +#define HW_USBPHY_CTRL (0x00000030) +#define HW_USBPHY_CTRL_SET (0x00000034) +#define HW_USBPHY_CTRL_CLR (0x00000038) +#define HW_USBPHY_CTRL_TOG (0x0000003c) + +#define BM_USBPHY_CTRL_SFTRST 0x80000000 +#define BM_USBPHY_CTRL_CLKGATE 0x40000000 +#define BM_USBPHY_CTRL_UTMI_SUSPENDM 0x20000000 +#define BM_USBPHY_CTRL_HOST_FORCE_LS_SE0 0x10000000 +#define BM_USBPHY_CTRL_OTG_ID_VALUE 0x08000000 +#define BM_USBPHY_CTRL_ENAUTOSET_USBCLKS 0x04000000 +#define BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE 0x02000000 +#define BM_USBPHY_CTRL_FSDLL_RST_EN 0x01000000 +#define BM_USBPHY_CTRL_ENVBUSCHG_WKUP 0x00800000 +#define BM_USBPHY_CTRL_ENIDCHG_WKUP 0x00400000 +#define BM_USBPHY_CTRL_ENDPDMCHG_WKUP 0x00200000 +#define BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD 0x00100000 +#define BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE 0x00080000 +#define BM_USBPHY_CTRL_ENAUTO_PWRON_PLL 0x00040000 +#define BM_USBPHY_CTRL_WAKEUP_IRQ 0x00020000 +#define BM_USBPHY_CTRL_ENIRQWAKEUP 0x00010000 +#define BM_USBPHY_CTRL_ENUTMILEVEL3 0x00008000 +#define BM_USBPHY_CTRL_ENUTMILEVEL2 0x00004000 +#define BM_USBPHY_CTRL_DATA_ON_LRADC 0x00002000 +#define BM_USBPHY_CTRL_DEVPLUGIN_IRQ 0x00001000 +#define BM_USBPHY_CTRL_ENIRQDEVPLUGIN 0x00000800 +#define BM_USBPHY_CTRL_RESUME_IRQ 0x00000400 +#define BM_USBPHY_CTRL_ENIRQRESUMEDETECT 0x00000200 +#define BM_USBPHY_CTRL_RESUMEIRQSTICKY 0x00000100 +#define BM_USBPHY_CTRL_ENOTGIDDETECT 0x00000080 +#define BM_USBPHY_CTRL_OTG_ID_CHG_IRQ 0x00000040 +#define BM_USBPHY_CTRL_DEVPLUGIN_POLARITY 0x00000020 +#define BM_USBPHY_CTRL_ENDEVPLUGINDETECT 0x00000010 +#define BM_USBPHY_CTRL_HOSTDISCONDETECT_IRQ 0x00000008 +#define BM_USBPHY_CTRL_ENIRQHOSTDISCON 0x00000004 +#define BM_USBPHY_CTRL_ENHOSTDISCONDETECT 0x00000002 +#define BM_USBPHY_CTRL_ENOTG_ID_CHG_IRQ 0x00000001 + +#define HW_USBPHY_STATUS (0x00000040) + +#define BP_USBPHY_STATUS_RSVD4 11 +#define BM_USBPHY_STATUS_RSVD4 0xFFFFF800 +#define BF_USBPHY_STATUS_RSVD4(v) \ + (((v) << 11) & BM_USBPHY_STATUS_RSVD4) +#define BM_USBPHY_STATUS_RESUME_STATUS 0x00000400 +#define BM_USBPHY_STATUS_RSVD3 0x00000200 +#define BM_USBPHY_STATUS_OTGID_STATUS 0x00000100 +#define BM_USBPHY_STATUS_RSVD2 0x00000080 +#define BM_USBPHY_STATUS_DEVPLUGIN_STATUS 0x00000040 +#define BP_USBPHY_STATUS_RSVD1 4 +#define BM_USBPHY_STATUS_RSVD1 0x00000030 +#define BF_USBPHY_STATUS_RSVD1(v) \ + (((v) << 4) & BM_USBPHY_STATUS_RSVD1) +#define BM_USBPHY_STATUS_HOSTDISCONDETECT_STATUS 0x00000008 +#define BP_USBPHY_STATUS_RSVD0 0 +#define BM_USBPHY_STATUS_RSVD0 0x00000007 +#define BF_USBPHY_STATUS_RSVD0(v) \ + (((v) << 0) & BM_USBPHY_STATUS_RSVD0) + +#define HW_USBPHY_DEBUG (0x00000050) +#define HW_USBPHY_DEBUG_SET (0x00000054) +#define HW_USBPHY_DEBUG_CLR (0x00000058) +#define HW_USBPHY_DEBUG_TOG (0x0000005c) + +#define BM_USBPHY_DEBUG_RSVD3 0x80000000 +#define BM_USBPHY_DEBUG_CLKGATE 0x40000000 +#define BM_USBPHY_DEBUG_HOST_RESUME_DEBUG 0x20000000 +#define BP_USBPHY_DEBUG_SQUELCHRESETLENGTH 25 +#define BM_USBPHY_DEBUG_SQUELCHRESETLENGTH 0x1E000000 +#define BF_USBPHY_DEBUG_SQUELCHRESETLENGTH(v) \ + (((v) << 25) & BM_USBPHY_DEBUG_SQUELCHRESETLENGTH) +#define BM_USBPHY_DEBUG_ENSQUELCHRESET 0x01000000 +#define BP_USBPHY_DEBUG_RSVD2 21 +#define BM_USBPHY_DEBUG_RSVD2 0x00E00000 +#define BF_USBPHY_DEBUG_RSVD2(v) \ + (((v) << 21) & BM_USBPHY_DEBUG_RSVD2) +#define BP_USBPHY_DEBUG_SQUELCHRESETCOUNT 16 +#define BM_USBPHY_DEBUG_SQUELCHRESETCOUNT 0x001F0000 +#define BF_USBPHY_DEBUG_SQUELCHRESETCOUNT(v) \ + (((v) << 16) & BM_USBPHY_DEBUG_SQUELCHRESETCOUNT) +#define BP_USBPHY_DEBUG_RSVD1 13 +#define BM_USBPHY_DEBUG_RSVD1 0x0000E000 +#define BF_USBPHY_DEBUG_RSVD1(v) \ + (((v) << 13) & BM_USBPHY_DEBUG_RSVD1) +#define BM_USBPHY_DEBUG_ENTX2RXCOUNT 0x00001000 +#define BP_USBPHY_DEBUG_TX2RXCOUNT 8 +#define BM_USBPHY_DEBUG_TX2RXCOUNT 0x00000F00 +#define BF_USBPHY_DEBUG_TX2RXCOUNT(v) \ + (((v) << 8) & BM_USBPHY_DEBUG_TX2RXCOUNT) +#define BP_USBPHY_DEBUG_RSVD0 6 +#define BM_USBPHY_DEBUG_RSVD0 0x000000C0 +#define BF_USBPHY_DEBUG_RSVD0(v) \ + (((v) << 6) & BM_USBPHY_DEBUG_RSVD0) +#define BP_USBPHY_DEBUG_ENHSTPULLDOWN 4 +#define BM_USBPHY_DEBUG_ENHSTPULLDOWN 0x00000030 +#define BF_USBPHY_DEBUG_ENHSTPULLDOWN(v) \ + (((v) << 4) & BM_USBPHY_DEBUG_ENHSTPULLDOWN) +#define BP_USBPHY_DEBUG_HSTPULLDOWN 2 +#define BM_USBPHY_DEBUG_HSTPULLDOWN 0x0000000C +#define BF_USBPHY_DEBUG_HSTPULLDOWN(v) \ + (((v) << 2) & BM_USBPHY_DEBUG_HSTPULLDOWN) +#define BM_USBPHY_DEBUG_DEBUG_INTERFACE_HOLD 0x00000002 +#define BM_USBPHY_DEBUG_OTGIDPIOLOCK 0x00000001 + +#define HW_USBPHY_DEBUG0_STATUS (0x00000060) + +#define BP_USBPHY_DEBUG0_STATUS_SQUELCH_COUNT 26 +#define BM_USBPHY_DEBUG0_STATUS_SQUELCH_COUNT 0xFC000000 +#define BF_USBPHY_DEBUG0_STATUS_SQUELCH_COUNT(v) \ + (((v) << 26) & BM_USBPHY_DEBUG0_STATUS_SQUELCH_COUNT) +#define BP_USBPHY_DEBUG0_STATUS_UTMI_RXERROR_FAIL_COUNT 16 +#define BM_USBPHY_DEBUG0_STATUS_UTMI_RXERROR_FAIL_COUNT 0x03FF0000 +#define BF_USBPHY_DEBUG0_STATUS_UTMI_RXERROR_FAIL_COUNT(v) \ + (((v) << 16) & BM_USBPHY_DEBUG0_STATUS_UTMI_RXERROR_FAIL_COUNT) +#define BP_USBPHY_DEBUG0_STATUS_LOOP_BACK_FAIL_COUNT 0 +#define BM_USBPHY_DEBUG0_STATUS_LOOP_BACK_FAIL_COUNT 0x0000FFFF +#define BF_USBPHY_DEBUG0_STATUS_LOOP_BACK_FAIL_COUNT(v) \ + (((v) << 0) & BM_USBPHY_DEBUG0_STATUS_LOOP_BACK_FAIL_COUNT) + +#define HW_USBPHY_DEBUG1 (0x00000070) +#define HW_USBPHY_DEBUG1_SET (0x00000074) +#define HW_USBPHY_DEBUG1_CLR (0x00000078) +#define HW_USBPHY_DEBUG1_TOG (0x0000007c) + +#define BP_USBPHY_DEBUG1_RSVD1 15 +#define BM_USBPHY_DEBUG1_RSVD1 0xFFFF8000 +#define BF_USBPHY_DEBUG1_RSVD1(v) \ + (((v) << 15) & BM_USBPHY_DEBUG1_RSVD1) +#define BP_USBPHY_DEBUG1_ENTAILADJVD 13 +#define BM_USBPHY_DEBUG1_ENTAILADJVD 0x00006000 +#define BF_USBPHY_DEBUG1_ENTAILADJVD(v) \ + (((v) << 13) & BM_USBPHY_DEBUG1_ENTAILADJVD) +#define BM_USBPHY_DEBUG1_ENTX2TX 0x00001000 +#define BP_USBPHY_DEBUG1_RSVD0 4 +#define BM_USBPHY_DEBUG1_RSVD0 0x00000FF0 +#define BF_USBPHY_DEBUG1_RSVD0(v) \ + (((v) << 4) & BM_USBPHY_DEBUG1_RSVD0) +#define BP_USBPHY_DEBUG1_DBG_ADDRESS 0 +#define BM_USBPHY_DEBUG1_DBG_ADDRESS 0x0000000F +#define BF_USBPHY_DEBUG1_DBG_ADDRESS(v) \ + (((v) << 0) & BM_USBPHY_DEBUG1_DBG_ADDRESS) + +#define HW_USBPHY_VERSION (0x00000080) + +#define BP_USBPHY_VERSION_MAJOR 24 +#define BM_USBPHY_VERSION_MAJOR 0xFF000000 +#define BF_USBPHY_VERSION_MAJOR(v) \ + (((v) << 24) & BM_USBPHY_VERSION_MAJOR) +#define BP_USBPHY_VERSION_MINOR 16 +#define BM_USBPHY_VERSION_MINOR 0x00FF0000 +#define BF_USBPHY_VERSION_MINOR(v) \ + (((v) << 16) & BM_USBPHY_VERSION_MINOR) +#define BP_USBPHY_VERSION_STEP 0 +#define BM_USBPHY_VERSION_STEP 0x0000FFFF +#define BF_USBPHY_VERSION_STEP(v) \ + (((v) << 0) & BM_USBPHY_VERSION_STEP) + +#define HW_USBPHY_IP (0x00000090) +#define HW_USBPHY_IP_SET (0x00000094) +#define HW_USBPHY_IP_CLR (0x00000098) +#define HW_USBPHY_IP_TOG (0x0000009c) + +#define BP_USBPHY_IP_RSVD1 25 +#define BM_USBPHY_IP_RSVD1 0xFE000000 +#define BF_USBPHY_IP_RSVD1(v) \ + (((v) << 25) & BM_USBPHY_IP_RSVD1) +#define BP_USBPHY_IP_DIV_SEL 23 +#define BM_USBPHY_IP_DIV_SEL 0x01800000 +#define BF_USBPHY_IP_DIV_SEL(v) \ + (((v) << 23) & BM_USBPHY_IP_DIV_SEL) +#define BV_USBPHY_IP_DIV_SEL__DEFAULT 0x0 +#define BV_USBPHY_IP_DIV_SEL__LOWER 0x1 +#define BV_USBPHY_IP_DIV_SEL__LOWEST 0x2 +#define BV_USBPHY_IP_DIV_SEL__UNDEFINED 0x3 +#define BP_USBPHY_IP_LFR_SEL 21 +#define BM_USBPHY_IP_LFR_SEL 0x00600000 +#define BF_USBPHY_IP_LFR_SEL(v) \ + (((v) << 21) & BM_USBPHY_IP_LFR_SEL) +#define BV_USBPHY_IP_LFR_SEL__DEFAULT 0x0 +#define BV_USBPHY_IP_LFR_SEL__TIMES_2 0x1 +#define BV_USBPHY_IP_LFR_SEL__TIMES_05 0x2 +#define BV_USBPHY_IP_LFR_SEL__UNDEFINED 0x3 +#define BP_USBPHY_IP_CP_SEL 19 +#define BM_USBPHY_IP_CP_SEL 0x00180000 +#define BF_USBPHY_IP_CP_SEL(v) \ + (((v) << 19) & BM_USBPHY_IP_CP_SEL) +#define BV_USBPHY_IP_CP_SEL__DEFAULT 0x0 +#define BV_USBPHY_IP_CP_SEL__TIMES_2 0x1 +#define BV_USBPHY_IP_CP_SEL__TIMES_05 0x2 +#define BV_USBPHY_IP_CP_SEL__UNDEFINED 0x3 +#define BM_USBPHY_IP_TSTI_TX_DP 0x00040000 +#define BM_USBPHY_IP_TSTI_TX_DM 0x00020000 +#define BM_USBPHY_IP_ANALOG_TESTMODE 0x00010000 +#define BP_USBPHY_IP_RSVD0 3 +#define BM_USBPHY_IP_RSVD0 0x0000FFF8 +#define BF_USBPHY_IP_RSVD0(v) \ + (((v) << 3) & BM_USBPHY_IP_RSVD0) +#define BM_USBPHY_IP_EN_USB_CLKS 0x00000004 +#define BM_USBPHY_IP_PLL_LOCKED 0x00000002 +#define BM_USBPHY_IP_PLL_POWER 0x00000001 + +/* The register definition for usbphy which includes at usb core's register set + * (from USB_CORE_BASE + 0x800) + */ +#define USB_CTRL USBOTHER_REG(0x00) /* USB OTG Control register */ +#define USB_H1_CTRL USBOTHER_REG(0x04) /* USB H1 Control register */ +#define USB_H2_CTRL USBOTHER_REG(0x08) /* USB H2 Control register */ +#define USB_H3_CTRL USBOTHER_REG(0x0c) /* USB H3 Control register */ + +/* USB Host2 HSIC Control Register */ +#define USB_UH2_HSIC_CTRL USBOTHER_REG(0x10) + +/* USB Host3 HSIC Control Register */ +#define USB_UH3_HSIC_CTRL USBOTHER_REG(0x14) + +/* OTG UTMI PHY Control 0 Register */ +#define USB_OTG_PHY_CTRL_0 USBOTHER_REG(0x18) + +/* OTG UTMI PHY Control 1 Register */ +#define USB_H1_PHY_CTRL_0 USBOTHER_REG(0x1c) + +/* USB Host2 HSIC DLL Configuration Register 1 */ +#define USB_UH2_HSIC_DLL_CFG1 USBOTHER_REG(0x20) + +/* USB Host2 HSIC DLL Configuration Register 2 */ +#define USB_UH2_HSIC_DLL_CFG2 USBOTHER_REG(0x24) + +/* USB Host2 HSIC DLL Configuration Register 3 */ +#define USB_UH2_HSIC_DLL_CFG3 USBOTHER_REG(0x28) + +/* USB Host3 HSIC DLL Configuration Register 1 */ +#define USB_UH3_HSIC_DLL_CFG1 USBOTHER_REG(0x30) + +/* USB Host3 HSIC DLL Configuration Register 2 */ +#define USB_UH3_HSIC_DLL_CFG2 USBOTHER_REG(0x34) + +/* USB Host3 HSIC DLL Configuration Register 3 */ +#define USB_UH3_HSIC_DLL_CFG3 USBOTHER_REG(0x38) + +/* + * register bits + */ + +/* USBCTRL */ +#define UCTRL_OSIC_MASK (3 << 29) /* OTG Serial Interface Config: */ +#define UCTRL_OSIC_DU6 (0 << 29) /* Differential/unidirectional 6 wire */ +#define UCTRL_OSIC_DB4 (1 << 29) /* Differential/bidirectional 4 wire */ +#define UCTRL_OSIC_SU6 (2 << 29) /* single-ended/unidirectional 6 wire */ +#define UCTRL_OSIC_SB3 (3 << 29) /* single-ended/bidirectional 3 wire */ +#define UCTRL_OUIE (1 << 28) /* OTG ULPI intr enable */ +#define UCTRL_OBPVAL_RXDP (1 << 26) /* OTG RxDp status in bypass mode */ +#define UCTRL_OBPVAL_RXDM (1 << 25) /* OTG RxDm status in bypass mode */ +#define UCTRL_OPM (1 << 24) /* OTG power mask */ +#define UCTRL_O_PWR_POL (1 << 24) /* OTG power pin polarity */ +#define UCTRL_H2WIR (1 << 17) /* HOST2 wakeup intr request received */ +#define UCTRL_H2SIC_MASK (3 << 21) /* HOST2 Serial Interface Config: */ +#define UCTRL_H2SIC_DU6 (0 << 21) /* Differential/unidirectional 6 wire */ +#define UCTRL_H2SIC_DB4 (1 << 21) /* Differential/bidirectional 4 wire */ +#define UCTRL_H2SIC_SU6 (2 << 21) /* single-ended/unidirectional 6 wire */ +#define UCTRL_H2SIC_SB3 (3 << 21) /* single-ended/bidirectional 3 wire */ +#define UCTRL_H2UIE (1 << 8) /* HOST2 ULPI intr enable */ +#define UCTRL_H2WIE (1 << 7) /* HOST2 wakeup intr enable */ +#define UCTRL_H2PP 0 /* Power Polarity for uh2 */ +#define UCTRL_H2PM (1 << 4) /* HOST2 power mask */ +#define UCTRL_H2OVBWK_EN (1 << 6) /* OTG VBUS Wakeup Enable */ +#define UCTRL_H2OIDWK_EN (1 << 5) /* OTG ID Wakeup Enable */ + +#define UCTRL_H1WIR (1 << 15) /* HOST1 wakeup intr request received */ +#define UCTRL_H1SIC_MASK (3 << 13) /* HOST1 Serial Interface Config: */ +#define UCTRL_H1SIC_DU6 (0 << 13) /* Differential/unidirectional 6 wire */ +#define UCTRL_H1SIC_DB4 (1 << 13) /* Differential/bidirectional 4 wire */ +#define UCTRL_H1SIC_SU6 (2 << 13) /* single-ended/unidirectional 6 wire */ +#define UCTRL_H1SIC_SB3 (3 << 13) /* single-ended/bidirectional 3 wire */ +#define UCTRL_OLOCKD (1 << 13) /* otg lock disable */ +#define UCTRL_H2LOCKD (1 << 12) /* HOST2 lock disable */ +#define UCTRL_H1UIE (1 << 12) /* Host1 ULPI interrupt enable */ + +#define UCTRL_PP (1 << 11) /* power polarity bit */ +#define UCTRL_H1WIE (1 << 11) /* HOST1 wakeup intr enable */ +#define UCTRL_H1BPVAL_RXDP (1 << 10) /* HOST1 RxDp status in bypass mode */ +#define UCTRL_XCSO (1 << 10) /* Xcvr Clock Select for OTG port */ +#define UCTRL_H1BPVAL_RXDM (1 << 9) /* HOST1 RxDm status in bypass mode */ +#define UCTRL_XCSH2 (1 << 9) /* Xcvr Clock Select for Host port */ +#define UCTRL_H1PM (1 << 8) /* HOST1 power mask */ +#define UCTRL_IP_PULIDP (1 << 8) /* Ipp_Puimpel_Pullup_Dp */ + +#define UCTRL_IP_PUE_UP (1 << 7) /* ipp_pue_pullup_dp */ +#define UCTRL_IP_PUE_DOWN (1 << 6) /* ipp_pue_pulldwn_dpdm */ +#define UCTRL_H2DT (1 << 5) /* HOST2 TLL disabled */ +#define UCTRL_H1DT (1 << 4) /* HOST1 TLL disabled */ +#define UCTRL_USBTE (1 << 4) /* USBT Transceiver enable */ +#define UCTRL_OCPOL (1 << 3) /* OverCurrent Polarity */ +#define UCTRL_OCE (1 << 2) /* OverCurrent Enable */ +#define UCTRL_H2OCPOL (1 << 2) /* OverCurrent Polarity of Host2 */ +#define UCTRL_H2OCS (1 << 1) /* Host OverCurrent State */ +#define UCTRL_BPE (1 << 0) /* bypass mode enable */ +#define UCTRL_OTD (1 << 0) /* OTG TLL Disable */ +#define UCTRL_OOCS (1 << 0) /* OTG OverCurrent State */ + +/* OTG_MIRROR */ +#define OTGM_SESEND (1 << 4) /* B device session end */ +#define OTGM_VBUSVAL (1 << 3) /* Vbus valid */ +#define OTGM_BSESVLD (1 << 2) /* B session Valid */ +#define OTGM_ASESVLD (1 << 1) /* A session Valid */ +#define OTGM_IDIDG (1 << 0) /* OTG ID pin status */ + /* 1=high: Operate as B-device */ + /* 0=low : Operate as A-device */ + +/* USB_PHY_CTRL_FUNC */ +/* PHY control0 Register Bit Masks */ +#define USB_UTMI_PHYCTRL_CONF2 (1 << 26) + +#define USB_UTMI_PHYCTRL_UTMI_ENABLE (1 << 24) +#define USB_UTMI_PHYCTRL_CHGRDETEN (1 << 24) /* Enable Charger Detector */ +#define USB_UTMI_PHYCTRL_CHGRDETON (1 << 23) /* Charger Detector Power On Control */ +#define USB_UTMI_PHYCTRL_OC_POL (1 << 9) /* OTG Polarity of Overcurrent */ +#define USB_UTMI_PHYCTRL_OC_DIS (1 << 8) /* OTG Disable Overcurrent Event */ +#define USB_UH1_OC_DIS (1 << 5) /* UH1 Disable Overcurrent Event */ +#define USB_UH1_OC_POL (1 << 6) /* UH1 Polarity of OC,Low active */ +/* USB_PHY_CTRL_FUNC2*/ +#define USB_UTMI_PHYCTRL2_PLLDIV_MASK 0x3 +#define USB_UTMI_PHYCTRL2_PLLDIV_SHIFT 0 +#define USB_UTMI_PHYCTRL2_HSDEVSEL_MASK 0x3 +#define USB_UTMI_PHYCTRL2_HSDEVSEL_SHIFT 19 + +/* USB_CTRL_1 */ +#define USB_CTRL_UH1_EXT_CLK_EN (1 << 25) +#define USB_CTRL_UH2_EXT_CLK_EN (1 << 26) +#define USB_CTRL_UH2_CLK_FROM_ULPI_PHY (1 << 2) +/* ULPIVIEW register bits */ +#define ULPIVW_OFF (0x170) +#define ULPIVW_WU (1 << 31) /* Wakeup */ +#define ULPIVW_RUN (1 << 30) /* read/write run */ +#define ULPIVW_WRITE (1 << 29) /* 0=read 1=write */ +#define ULPIVW_SS (1 << 27) /* SyncState */ +#define ULPIVW_PORT_MASK 0x07 /* Port field */ +#define ULPIVW_PORT_SHIFT 24 +#define ULPIVW_ADDR_MASK 0xFF /* data address field */ +#define ULPIVW_ADDR_SHIFT 16 +#define ULPIVW_RDATA_MASK 0xFF /* read data field */ +#define ULPIVW_RDATA_SHIFT 8 +#define ULPIVW_WDATA_MASK 0xFF /* write data field */ +#define ULPIVW_WDATA_SHIFT 0 + +/* USB Clock on/off Control Register */ +#define OTG_AHBCLK_OFF (0x1<<17) /* 1: OFF */ +#define H1_AHBCLK_OFF (0x1<<18) /* 1: OFF */ + +/* mx6q's register bit begins*/ + +/* OTG CTRL - H3 CTRL */ +#define UCTRL_OWIR (1 << 31) /* OTG wakeup intr request received */ +/* bit 18 - bit 30 is reserved at mx6q */ +#define UCTRL_WKUP_VBUS_EN (1 << 17) /* OTG wake-up on VBUS change enable */ +#define UCTRL_WKUP_ID_EN (1 << 16) /* OTG wake-up on ID change enable */ +#define UCTRL_WKUP_SW (1 << 15) /* OTG Software Wake-up */ +#define UCTRL_WKUP_SW_EN (1 << 14) /* OTG Software Wake-up enable */ +#define UCTRL_UTMI_ON_CLOCK (1 << 13) /* Force OTG UTMI PHY clock output on + even if suspend mode */ +#define UCTRL_SUSPENDM (1 << 12) /* Force OTG UTMI PHY Suspend */ +#define UCTRL_RESET (1 << 11) /* Force OTG UTMI PHY Reset */ +#define UCTRL_OWIE (1 << 10) /* OTG wakeup intr request received */ +#define UCTRL_PM (1 << 9) /* OTG Power Mask */ +#define UCTRL_OVER_CUR_POL (1 << 8) /* OTG Polarity of Overcurrent */ +#define UCTRL_OVER_CUR_DIS (1 << 7) /* Disable OTG Overcurrent Detection */ +/* bit 0 - bit 6 is reserved at mx6q */ + +/* Host2/3 HSIC Ctrl */ +#define CLK_VLD (1 << 31) /* Indicating whether HSIC clock is valid */ +#define HSIC_EN (1 << 12) /* HSIC enable */ +#define HSIC_CLK_ON (1 << 11) /* Force HSIC module 480M clock on, + * even when in Host is in suspend mode + */ +/* OTG/HOST1 Phy Ctrl */ +#define PHY_UTMI_CLK_VLD (1 << 31) /* Indicating whether OTG UTMI PHY Clock Valid */ + +#define NOP_XCVR (0xffffffff) /* Indicate it is no usb phy */ +#endif /* __ARCH_ARM___USBPHY_H */ diff --git a/arch/arm/include/asm/arch-mx6/mx6sl_pins.h b/arch/arm/include/asm/arch-mx6/mx6sl_pins.h index 5f9c90a..774314d 100644 --- a/arch/arm/include/asm/arch-mx6/mx6sl_pins.h +++ b/arch/arm/include/asm/arch-mx6/mx6sl_pins.h @@ -30,5 +30,6 @@ enum { MX6_PAD_FEC_REF_CLK__FEC_REF_OUT = IOMUX_PAD(0x424, 0x134, 0x10, 0x000, 0, 0), MX6_PAD_FEC_RX_ER__GPIO_4_19 = IOMUX_PAD(0x0428, 0x0138, 5, 0x0000, 0, 0), MX6_PAD_FEC_TX_CLK__GPIO_4_21 = IOMUX_PAD(0x0434, 0x0144, 5, 0x0000, 0, 0), + MX6_PAD_EPDC_PWRCOM__ANATOP_USBOTG1_ID = IOMUX_PAD(0x03D0, 0x00E0, 4, 0x05DC, 0, 0), }; #endif /* __ASM_ARCH_MX6_MX6SL_PINS_H__ */ diff --git a/arch/arm/include/asm/imx-common/iomux-v3.h b/arch/arm/include/asm/imx-common/iomux-v3.h index dec11a1..156fb55 100644 --- a/arch/arm/include/asm/imx-common/iomux-v3.h +++ b/arch/arm/include/asm/imx-common/iomux-v3.h @@ -169,5 +169,10 @@ typedef u64 iomux_v3_cfg_t; void imx_iomux_v3_setup_pad(iomux_v3_cfg_t pad); void imx_iomux_v3_setup_multiple_pads(iomux_v3_cfg_t const *pad_list, unsigned count); +/* +* Set bits for general purpose registers +*/ +void mxc_iomux_set_gpr_register(int group, int start_bit, + int num_bits, int value); #endif /* __MACH_IOMUX_V3_H__*/ diff --git a/board/freescale/mx6qsabreauto/mx6qsabreauto.c b/board/freescale/mx6qsabreauto/mx6qsabreauto.c index 1fe13e0..b530fb9 100644 --- a/board/freescale/mx6qsabreauto/mx6qsabreauto.c +++ b/board/freescale/mx6qsabreauto/mx6qsabreauto.c @@ -329,3 +329,18 @@ int checkboard(void) return 0; } + +#ifdef CONFIG_IMX_UDC +iomux_v3_cfg_t const otg_udc_pads[] = { + (MX6_PAD_ENET_RX_ER__USB_OTG_ID | MUX_PAD_CTRL(NO_PAD_CTRL)), +}; +void udc_pins_setting(void) +{ + imx_iomux_v3_setup_multiple_pads(otg_udc_pads, + ARRAY_SIZE(otg_udc_pads)); + + /*set daisy chain for otg_pin_id on 6q. for 6dl, this bit is reserved*/ + mxc_iomux_set_gpr_register(1, 13, 1, 0); +} + +#endif /*CONFIG_IMX_UDC*/ diff --git a/board/freescale/mx6sabresd/mx6sabresd.c b/board/freescale/mx6sabresd/mx6sabresd.c index 722981e..df7df77 100644 --- a/board/freescale/mx6sabresd/mx6sabresd.c +++ b/board/freescale/mx6sabresd/mx6sabresd.c @@ -583,3 +583,16 @@ int checkboard(void) return 0; } +#ifdef CONFIG_IMX_UDC +iomux_v3_cfg_t const otg_udc_pads[] = { + (MX6_PAD_ENET_RX_ER__USB_OTG_ID | MUX_PAD_CTRL(NO_PAD_CTRL)), +}; +void udc_pins_setting(void) +{ + imx_iomux_v3_setup_multiple_pads(otg_udc_pads, + ARRAY_SIZE(otg_udc_pads)); + + /*set daisy chain for otg_pin_id on 6q. for 6dl, this bit is reserved*/ + mxc_iomux_set_gpr_register(1, 13, 1, 0); +} +#endif /*CONFIG_IMX_UDC*/ diff --git a/board/freescale/mx6slevk/mx6slevk.c b/board/freescale/mx6slevk/mx6slevk.c index aeb418b..afd3a06 100644 --- a/board/freescale/mx6slevk/mx6slevk.c +++ b/board/freescale/mx6slevk/mx6slevk.c @@ -190,6 +190,18 @@ u32 get_board_rev(void) return get_cpu_rev(); } + +#ifdef CONFIG_IMX_UDC +iomux_v3_cfg_t const otg_udc_pads[] = { + (MX6_PAD_EPDC_PWRCOM__ANATOP_USBOTG1_ID | MUX_PAD_CTRL(NO_PAD_CTRL)), +}; +void udc_pins_setting(void) +{ + imx_iomux_v3_setup_multiple_pads(otg_udc_pads, + ARRAY_SIZE(otg_udc_pads)); +} +#endif /*CONFIG_IMX_UDC*/ + int checkboard(void) { puts("Board: MX6SLEVK\n"); diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 804a2bd..2d5ae21 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -33,5 +33,6 @@ obj-$(CONFIG_OMAP1510) += omap1510_udc.o obj-$(CONFIG_OMAP1610) += omap1510_udc.o obj-$(CONFIG_MPC885_FAMILY) += mpc8xx_udc.o obj-$(CONFIG_CPU_PXA27X) += pxa27x_udc.o +obj-$(CONFIG_IMX_UDC) += imx_udc.o endif endif diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c new file mode 100644 index 0000000..35fbd14 --- /dev/null +++ b/drivers/usb/gadget/imx_udc.c @@ -0,0 +1,1189 @@ +/* + * Copyright (C) 2010-2014 Freescale Semiconductor, Inc. All Rights Reserved. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ep0.h" + +#ifdef DEBUG +#define DBG(x...) printf(x) +#else +#define DBG(x...) do {} while (0) +#endif + +#define mdelay(n) udelay((n)*1000) + +#define EP_TQ_ITEM_SIZE 16 + +#define inc_index(x) (x = ((x+1) % EP_TQ_ITEM_SIZE)) + +#define ep_is_in(e, tx) ((e == 0) ? (mxc_udc.ep0_dir == USB_DIR_IN) : tx) + +#define USB_RECIP_MASK 0x03 +#define USB_TYPE_MASK (0x03 << 5) +#define USB_MEM_ALIGN_BYTE 4096 +#define USB_DEV_DQH_ALIGN 64 +#define USB_DEV_DTD_ALIGN 64 + +/*fixed the dtd buffer to 4096 bytes, even it could be 20KB*/ +#define USB_DEV_DTD_MAX_BUFFER_SIZE 4096 + +#define CACHE_ALIGNED_END(start, length) \ + (ALIGN((uint32_t)start + length, ARCH_DMA_MINALIGN)) + +struct mxc_ep_t{ + int epnum; + int dir; + int max_pkt_size; + struct usb_endpoint_instance *epi; + struct ep_queue_item *ep_dtd[EP_TQ_ITEM_SIZE]; + int index; /* to index the free tx tqi */ + int done; /* to index the complete rx tqi */ + struct ep_queue_item *tail; /* last item in the dtd chain */ + struct ep_queue_head *ep_qh; +} ; + +struct mxc_udc_ctrl{ + int max_ep; + int ep0_dir; + int setaddr; + struct ep_queue_head *ep_qh; + struct mxc_ep_t *mxc_ep; + u32 qh_unaligned; +}; + +static int usb_highspeed; +static int usb_inited; +static struct mxc_udc_ctrl mxc_udc; +static struct usb_device_instance *udc_device; +static struct urb *ep0_urb; +/* + * malloc an aligned memory + * unaligned_addr: return a unaligned address for memory free + * size : memory size + * align : alignment for this memroy + * return : aligned address(NULL when malloc failt) +*/ +static void *malloc_aligned_buffer(u32 *unaligned_addr, + int size, int align) +{ + int msize = (size + align - 1); + u32 vir, vir_align; + + /* force the allocated memory size to be aligned with min cache operation unit. + * So it is safe to flush/invalidate the cache. + */ + msize = (msize + ARCH_DMA_MINALIGN - 1) / ARCH_DMA_MINALIGN; + msize = msize * ARCH_DMA_MINALIGN; + + vir = (u32)malloc(msize); + memset((void *)vir, 0, msize); + vir_align = (vir + align - 1) & (~(align - 1)); + *unaligned_addr = vir; + + DBG("alloc aligned vir addr %x\n", vir_align); + return (void *)vir_align; +} + +int is_usb_disconnected() +{ + int ret = 0; + + ret = readl(USB_OTGSC) & OTGSC_B_SESSION_VALID ? 0 : 1; + return ret; +} + +static int mxc_init_usb_qh(void) +{ + int size; + memset(&mxc_udc, 0, sizeof(mxc_udc)); + mxc_udc.max_ep = (readl(USB_DCCPARAMS) & DCCPARAMS_DEN_MASK) * 2; + DBG("udc max ep = %d\n", mxc_udc.max_ep); + size = mxc_udc.max_ep * sizeof(struct ep_queue_head); + mxc_udc.ep_qh = malloc_aligned_buffer(&mxc_udc.qh_unaligned, + size, USB_MEM_ALIGN_BYTE); + if (!mxc_udc.ep_qh) { + printf("malloc ep qh dma buffer failure\n"); + return -1; + } + memset(mxc_udc.ep_qh, 0, size); + + /*flush cache to physical memory*/ + flush_dcache_range((unsigned long)mxc_udc.ep_qh, + CACHE_ALIGNED_END(mxc_udc.ep_qh, size)); + + writel(virt_to_phys(mxc_udc.ep_qh) & 0xfffff800, USB_ENDPOINTLISTADDR); + return 0; +} + +static int mxc_destroy_usb_qh(void) +{ + if (mxc_udc.ep_qh && mxc_udc.qh_unaligned) { + free((void *)mxc_udc.qh_unaligned); + mxc_udc.ep_qh = 0; + mxc_udc.qh_unaligned = 0; + mxc_udc.max_ep = 0; + } + + return 0; +} + +static int mxc_init_ep_struct(void) +{ + int i; + + DBG("init mxc ep\n"); + mxc_udc.mxc_ep = malloc(mxc_udc.max_ep * sizeof(struct mxc_ep_t)); + if (!mxc_udc.mxc_ep) { + printf("malloc ep struct failure\n"); + return -1; + } + memset((void *)mxc_udc.mxc_ep, 0, + sizeof(struct mxc_ep_t) * mxc_udc.max_ep); + for (i = 0; i < mxc_udc.max_ep / 2; i++) { + struct mxc_ep_t *ep; + ep = mxc_udc.mxc_ep + i * 2; + ep->epnum = i; + ep->index = ep->done = 0; + ep->dir = USB_RECV; /* data from host to device */ + ep->ep_qh = &mxc_udc.ep_qh[i * 2]; + + ep = mxc_udc.mxc_ep + (i * 2 + 1); + ep->epnum = i; + ep->index = ep->done = 0; + ep->dir = USB_SEND; /* data to host from device */ + ep->ep_qh = &mxc_udc.ep_qh[(i * 2 + 1)]; + } + return 0; +} + +static int mxc_destroy_ep_struct(void) +{ + if (mxc_udc.mxc_ep) { + free(mxc_udc.mxc_ep); + mxc_udc.mxc_ep = 0; + } + return 0; +} + +static int mxc_init_ep_dtd(u8 index) +{ + struct mxc_ep_t *ep; + u32 unaligned_addr; + int i; + + if (index >= mxc_udc.max_ep) + DBG("%s ep %d is not valid\n", __func__, index); + + ep = mxc_udc.mxc_ep + index; + for (i = 0; i < EP_TQ_ITEM_SIZE; i++) { + ep->ep_dtd[i] = malloc_aligned_buffer(&unaligned_addr, + sizeof(struct ep_queue_item), USB_DEV_DTD_ALIGN); + ep->ep_dtd[i]->item_unaligned_addr = unaligned_addr; + + if (NULL == ep->ep_dtd[i]) { + printf("%s malloc tq item failure\n", __func__); + + /*free other already allocated dtd*/ + while (i) { + i--; + free((void *)(ep->ep_dtd[i]->item_unaligned_addr)); + ep->ep_dtd[i] = 0; + } + return -1; + } + } + return 0; +} + +static int mxc_destroy_ep_dtd(u8 index) +{ + struct mxc_ep_t *ep; + int i; + + if (index >= mxc_udc.max_ep) + DBG("%s ep %d is not valid\n", __func__, index); + + ep = mxc_udc.mxc_ep + index; + for (i = 0; i < EP_TQ_ITEM_SIZE; i++) { + if (ep->ep_dtd[i]) { + free((void *)(ep->ep_dtd[i]->item_unaligned_addr)); + ep->ep_dtd[i] = 0; + } + } + + return 0; +} + +static void mxc_ep_qh_setup(u8 ep_num, u8 dir, u8 ep_type, + u32 max_pkt_len, u32 zlt, u8 mult) +{ + struct ep_queue_head *p_qh = mxc_udc.ep_qh + (2 * ep_num + dir); + u32 tmp = 0; + + tmp = max_pkt_len << 16; + switch (ep_type) { + case USB_ENDPOINT_XFER_CONTROL: + tmp |= (1 << 15); + break; + case USB_ENDPOINT_XFER_ISOC: + tmp |= (mult << 30); + break; + case USB_ENDPOINT_XFER_BULK: + case USB_ENDPOINT_XFER_INT: + break; + default: + DBG("error ep type is %d\n", ep_type); + return; + } + if (zlt) + tmp |= (1<<29); + + p_qh->config = tmp; + + /*flush qh's config field to physical memory*/ + flush_dcache_range((unsigned long)p_qh, + CACHE_ALIGNED_END(p_qh, sizeof(struct ep_queue_head))); +} + +static void mxc_ep_setup(u8 ep_num, u8 dir, u8 ep_type) +{ + u32 epctrl = 0; + epctrl = readl(USB_ENDPTCTRL(ep_num)); + if (dir) { + if (ep_num) + epctrl |= EPCTRL_TX_DATA_TOGGLE_RST; + epctrl |= EPCTRL_TX_ENABLE; + epctrl |= ((u32)(ep_type) << EPCTRL_TX_EP_TYPE_SHIFT); + } else { + if (ep_num) + epctrl |= EPCTRL_RX_DATA_TOGGLE_RST; + epctrl |= EPCTRL_RX_ENABLE; + epctrl |= ((u32)(ep_type) << EPCTRL_RX_EP_TYPE_SHIFT); + } + writel(epctrl, USB_ENDPTCTRL(ep_num)); +} + +static void mxc_ep_destroy(u8 ep_num, u8 dir) +{ + u32 epctrl = 0; + epctrl = readl(USB_ENDPTCTRL(ep_num)); + if (dir) + epctrl &= ~EPCTRL_TX_ENABLE; + else + epctrl &= ~EPCTRL_RX_ENABLE; + + writel(epctrl, USB_ENDPTCTRL(ep_num)); +} + + +static void mxc_tqi_init_page(struct ep_queue_item *tqi) +{ + tqi->page0 = virt_to_phys((void *)(tqi->page_vir)); + tqi->page1 = tqi->page0 + 0x1000; + tqi->page2 = tqi->page1 + 0x1000; + tqi->page3 = tqi->page2 + 0x1000; + tqi->page4 = tqi->page3 + 0x1000; +} + +static int mxc_malloc_ep0_ptr(struct mxc_ep_t *ep) +{ + int i; + struct ep_queue_item *tqi; + int max_pkt_size = USB_MAX_CTRL_PAYLOAD; + + ep->max_pkt_size = max_pkt_size; + for (i = 0; i < EP_TQ_ITEM_SIZE; i++) { + tqi = ep->ep_dtd[i]; + tqi->page_vir = (u32)malloc_aligned_buffer(&tqi->page_unaligned, + max_pkt_size, + USB_MEM_ALIGN_BYTE); + if ((void *)tqi->page_vir == NULL) { + printf("malloc ep's dtd bufer failure, i=%d\n", i); + return -1; + } + mxc_tqi_init_page(tqi); + + /*flush dtd's config field to physical memory*/ + flush_dcache_range((unsigned long)tqi, + CACHE_ALIGNED_END(tqi, sizeof(struct ep_queue_item))); + } + return 0; +} + +static int mxc_free_ep0_ptr(struct mxc_ep_t *ep) +{ + int i; + struct ep_queue_item *tqi; + for (i = 0; i < EP_TQ_ITEM_SIZE; i++) { + tqi = ep->ep_dtd[i]; + if (tqi->page_vir) { + free((void *)(tqi->page_unaligned)); + tqi->page_vir = 0; + tqi->page_unaligned = 0; + tqi->page0 = 0; + tqi->page1 = 0; + tqi->page2 = 0; + tqi->page3 = 0; + tqi->page4 = 0; + + /*flush dtd's config field to physical memory*/ + flush_dcache_range((unsigned long)tqi, + CACHE_ALIGNED_END(tqi, sizeof(struct ep_queue_item))); + } + } + + return 0; +} + +static void ep0_setup(void) +{ + mxc_ep_qh_setup(0, USB_RECV, USB_ENDPOINT_XFER_CONTROL, + USB_MAX_CTRL_PAYLOAD, 0, 0); + mxc_ep_qh_setup(0, USB_SEND, USB_ENDPOINT_XFER_CONTROL, + USB_MAX_CTRL_PAYLOAD, 0, 0); + mxc_ep_setup(0, USB_RECV, USB_ENDPOINT_XFER_CONTROL); + mxc_ep_setup(0, USB_SEND, USB_ENDPOINT_XFER_CONTROL); + mxc_init_ep_dtd(0 * 2 + USB_RECV); + mxc_init_ep_dtd(0 * 2 + USB_SEND); + mxc_malloc_ep0_ptr(mxc_udc.mxc_ep + (USB_RECV)); + mxc_malloc_ep0_ptr(mxc_udc.mxc_ep + (USB_SEND)); +} + +static void ep0_destroy(void) +{ + mxc_ep_destroy(0, USB_RECV); + mxc_ep_destroy(0, USB_SEND); + mxc_free_ep0_ptr(mxc_udc.mxc_ep + (USB_RECV)); + mxc_free_ep0_ptr(mxc_udc.mxc_ep + (USB_SEND)); + mxc_destroy_ep_dtd(0 * 2 + USB_RECV); + mxc_destroy_ep_dtd(0 * 2 + USB_SEND); +} + +static int mxc_tqi_is_busy(struct ep_queue_item *tqi) +{ + /* bit 7 is set by software when send, clear by controller + when finish */ + /*Invalidate cache to gain dtd content from physical memory*/ + invalidate_dcache_range((unsigned long)tqi, + CACHE_ALIGNED_END(tqi, sizeof(struct ep_queue_item))); + return tqi->info & (1 << 7); +} + +static int mxc_ep_xfer_is_working(struct mxc_ep_t *ep, u32 in) +{ + /* in: means device -> host */ + u32 bitmask = 1 << (ep->epnum + in * 16); + u32 temp, prime, tstat; + + prime = (bitmask & readl(USB_ENDPTPRIME)); + if (prime) + return 1; + do { + temp = readl(USB_USBCMD); + writel(temp|USB_CMD_ATDTW, USB_USBCMD); + tstat = readl(USB_ENDPTSTAT) & bitmask; + } while (!(readl(USB_USBCMD) & USB_CMD_ATDTW)); + writel(temp & (~USB_CMD_ATDTW), USB_USBCMD); + + if (tstat) + return 1; + return 0; +} + +static void mxc_update_qh(struct mxc_ep_t *ep, + struct ep_queue_item *tqi, u32 in) +{ + /* in: means device -> host */ + struct ep_queue_head *qh = ep->ep_qh; + u32 bitmask = 1 << (ep->epnum + in * 16); + DBG("%s, line %d, epnum=%d, in=%d\n", __func__, + __LINE__, ep->epnum, in); + qh->next_queue_item = virt_to_phys(tqi); + qh->info = 0; + + /*flush qh''s config field to physical memory*/ + flush_dcache_range((unsigned long)qh, + CACHE_ALIGNED_END(qh, sizeof(struct ep_queue_head))); + + writel(bitmask, USB_ENDPTPRIME); +} + +static void _dump_buf(u8 *buf, u32 len) +{ +#ifdef DEBUG + char *data = (char *)buf; + int i; + for (i = 0; i < len; i++) { + printf("0x%02x ", data[i]); + if (i%16 == 15) + printf("\n"); + } + printf("\n"); +#endif +} + +static void mxc_udc_queue_update(u8 epnum, + u8 *data, u32 len, u32 tx) +{ + struct mxc_ep_t *ep; + struct ep_queue_item *tqi, *head, *last; + int send = 0; + int in; + + head = last = NULL; + in = ep_is_in(epnum, tx); + ep = mxc_udc.mxc_ep + (epnum * 2 + in); + DBG("epnum = %d, in = %d\n", epnum, in); + do { + tqi = ep->ep_dtd[ep->index]; + DBG("%s, index = %d, tqi = %p\n", __func__, ep->index, tqi); + while (mxc_tqi_is_busy(tqi)) + ; + mxc_tqi_init_page(tqi); + DBG("%s, line = %d, len = %d\n", __func__, __LINE__, len); + inc_index(ep->index); + send = MIN(len, ep->max_pkt_size); + if (data) { + memcpy((void *)tqi->page_vir, (void *)data, send); + _dump_buf((u8 *)(tqi->page_vir), send); + + flush_dcache_range((unsigned long)(tqi->page_vir), + CACHE_ALIGNED_END(tqi->page_vir, send)); + } + if (!head) + last = head = tqi; + else { + last->next_item_ptr = virt_to_phys(tqi); + last->next_item_vir = tqi; + last = tqi; + } + if (!tx) + tqi->reserved[0] = send; + /* we set IOC for every dtd */ + tqi->info = ((send << 16) | (1 << 15) | (1 << 7)); + data += send; + len -= send; + + flush_dcache_range((unsigned long)tqi, + CACHE_ALIGNED_END(tqi, sizeof(struct ep_queue_item))); + } while (len); + + last->next_item_ptr = 0x1; /* end */ + flush_dcache_range((unsigned long)last, + CACHE_ALIGNED_END(last, sizeof(struct ep_queue_item))); + + if (ep->tail) { + ep->tail->next_item_ptr = virt_to_phys(head); + ep->tail->next_item_vir = head; + flush_dcache_range((unsigned long)(ep->tail), + CACHE_ALIGNED_END(ep->tail, sizeof(struct ep_queue_item))); + + if (mxc_ep_xfer_is_working(ep, in)) { + DBG("ep is working\n"); + goto out; + } + } + mxc_update_qh(ep, head, in); +out: + ep->tail = last; +} + +static void mxc_udc_txqueue_update(u8 ep, u8 *data, u32 len) +{ + printf("[SEND DATA] EP= %d, Len = 0x%x\n", ep, len); + _dump_buf(data, len); + mxc_udc_queue_update(ep, data, len, 1); +} + +void mxc_udc_rxqueue_update(u8 ep, u32 len) +{ + mxc_udc_queue_update(ep, NULL, len, 0); +} + +static void mxc_ep0_stall(void) +{ + u32 temp; + temp = readl(USB_ENDPTCTRL(0)); + temp |= EPCTRL_TX_EP_STALL | EPCTRL_RX_EP_STALL; + writel(temp, USB_ENDPTCTRL(0)); +} + +static void mxc_usb_run(void) +{ + unsigned int temp = 0; + + /* Enable DR irq reg */ + temp = USB_INTR_INT_EN | USB_INTR_ERR_INT_EN + | USB_INTR_PTC_DETECT_EN | USB_INTR_RESET_EN + | USB_INTR_DEVICE_SUSPEND | USB_INTR_SYS_ERR_EN; + + writel(temp, USB_USBINTR); + + /* Set controller to Run */ + temp = readl(USB_USBCMD); + temp |= USB_CMD_RUN_STOP; + writel(temp, USB_USBCMD); +} + +static void mxc_usb_stop(void) +{ + unsigned int temp = 0; + + writel(temp, USB_USBINTR); + + /* Set controller to Stop */ + temp = readl(USB_USBCMD); + temp &= ~USB_CMD_RUN_STOP; + writel(temp, USB_USBCMD); +} + +static void usb_phy_init(void) +{ + u32 temp; + /* select 24M clk */ + temp = readl(USB_PHY1_CTRL); + temp &= ~3; + temp |= 1; + writel(temp, USB_PHY1_CTRL); + /* Config PHY interface */ + temp = readl(USB_PORTSC1); + temp &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH); + temp |= PORTSCX_PTW_16BIT; + writel(temp, USB_PORTSC1); + DBG("Config PHY END\n"); +} + +static void usb_set_mode_device(void) +{ + u32 temp; + + /* Set controller to stop */ + temp = readl(USB_USBCMD); + temp &= ~USB_CMD_RUN_STOP; + writel(temp, USB_USBCMD); + + while (readl(USB_USBCMD) & USB_CMD_RUN_STOP) + ; + /* Do core reset */ + temp = readl(USB_USBCMD); + temp |= USB_CMD_CTRL_RESET; + writel(temp, USB_USBCMD); + while (readl(USB_USBCMD) & USB_CMD_CTRL_RESET) + ; + DBG("DOORE RESET END\n"); + +#if defined(CONFIG_MX6Q) || defined(CONFIG_MX6DL) || defined(CONFIG_MX6SL) + reset_usb_phy1(); +#endif + DBG("init core to device mode\n"); + temp = readl(USB_USBMODE); + temp &= ~USB_MODE_CTRL_MODE_MASK; /* clear mode bits */ + temp |= USB_MODE_CTRL_MODE_DEVICE; + /* Disable Setup Lockout */ + temp |= USB_MODE_SETUP_LOCK_OFF; + writel(temp, USB_USBMODE); + + temp = readl(USB_OTGSC); + temp |= (1<<3); + writel(temp, USB_OTGSC); + DBG("init core to device mode end\n"); +} + +static void usb_init_eps(void) +{ + u32 temp; + DBG("Flush begin\n"); + temp = readl(USB_ENDPTNAKEN); + temp |= 0x10001; /* clear mode bits */ + writel(temp, USB_ENDPTNAKEN); + writel(readl(USB_ENDPTCOMPLETE), USB_ENDPTCOMPLETE); + writel(readl(USB_ENDPTSETUPSTAT), USB_ENDPTSETUPSTAT); + writel(0xffffffff, USB_ENDPTFLUSH); + DBG("FLUSH END\n"); +} + +static void usb_udc_init(void) +{ + DBG("\n************************\n"); + DBG(" usb init start\n"); + DBG("\n************************\n"); + + usb_phy_init(); + usb_set_mode_device(); + mxc_init_usb_qh(); + usb_init_eps(); + mxc_init_ep_struct(); + ep0_setup(); + usb_inited = 1; +} + +static void usb_udc_destroy(void) +{ + usb_set_mode_device(); + + usb_inited = 0; + + ep0_destroy(); + mxc_destroy_ep_struct(); + mxc_destroy_usb_qh(); +} + +void usb_shutdown(void) +{ + u32 temp; + /* disable pullup */ + temp = readl(USB_USBCMD); + temp &= ~USB_CMD_RUN_STOP; + writel(temp, USB_USBCMD); + mdelay(2); +} + +static void ch9getstatus(u8 request_type, + u16 value, u16 index, u16 length) +{ + u16 tmp; + + if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) { + tmp = 1 << 0; /* self powerd */ + tmp |= 0 << 1; /* not remote wakeup able */ + } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) { + tmp = 0; + } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_ENDPOINT) { + tmp = 0; + } + mxc_udc.ep0_dir = USB_DIR_IN; + mxc_udc_queue_update(0, (u8 *)&tmp, 2, 0xffffffff); +} + +static void mxc_udc_read_setup_pkt(struct usb_device_request *s) +{ + u32 temp; + temp = readl(USB_ENDPTSETUPSTAT); + writel(temp, USB_ENDPTSETUPSTAT); + DBG("setup stat %x\n", temp); + do { + temp = readl(USB_USBCMD); + temp |= USB_CMD_SUTW; + writel(temp, USB_USBCMD); + + invalidate_dcache_range((unsigned long)(mxc_udc.mxc_ep[0].ep_qh), + CACHE_ALIGNED_END((mxc_udc.mxc_ep[0].ep_qh), + sizeof(struct ep_queue_head))); + + memcpy((void *)s, + (void *)mxc_udc.mxc_ep[0].ep_qh->setup_data, 8); + } while (!(readl(USB_USBCMD) & USB_CMD_SUTW)); + + DBG("handle_setup s.type=%x req=%x len=%x\n", + s->bmRequestType, s->bRequest, s->wLength); + temp = readl(USB_USBCMD); + temp &= ~USB_CMD_SUTW; + writel(temp, USB_USBCMD); + + DBG("[SETUP] type=%x req=%x val=%x index=%x len=%x\n", + s->bmRequestType, s->bRequest, + s->wValue, s->wIndex, + s->wLength); +} + +static void mxc_udc_recv_setup(void) +{ + struct usb_device_request *s = &ep0_urb->device_request; + + mxc_udc_read_setup_pkt(s); + if (s->wLength) { + /* If has a data phase, + * then prime a dtd for status stage which has zero length DATA0. + * The direction of status stage should oppsite to direction of data phase. + */ + mxc_udc.ep0_dir = (s->bmRequestType & USB_DIR_IN) ? + USB_DIR_OUT : USB_DIR_IN; + mxc_udc_queue_update(0, NULL, 0, 0xffffffff); + } + if (ep0_recv_setup(ep0_urb)) { + mxc_ep0_stall(); + return; + } + switch (s->bRequest) { + case USB_REQ_GET_STATUS: + if ((s->bmRequestType & (USB_DIR_IN | USB_TYPE_MASK)) != + (USB_DIR_IN | USB_TYPE_STANDARD)) + break; + ch9getstatus(s->bmRequestType, s->wValue, + s->wIndex, s->wLength); + + DBG("[SETUP] REQ_GET_STATUS\n"); + return; + case USB_REQ_SET_ADDRESS: + if (s->bmRequestType != (USB_DIR_OUT | + USB_TYPE_STANDARD | USB_RECIP_DEVICE)) + break; + mxc_udc.setaddr = 1; + mxc_udc.ep0_dir = USB_DIR_IN; + mxc_udc_queue_update(0, NULL, 0, 0xffffffff); + usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0); + DBG("[SETUP] REQ_SET_ADDRESS\n"); + return; + case USB_REQ_SET_CONFIGURATION: + usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0); + DBG("[SETUP] REQ_SET_CONFIGURATION\n"); + case USB_REQ_CLEAR_FEATURE: + case USB_REQ_SET_FEATURE: + { + int rc = -1; + if ((s->bmRequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) == + (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) + rc = 0; + else if ((s->bmRequestType & + (USB_RECIP_MASK | USB_TYPE_MASK)) == + (USB_RECIP_DEVICE | USB_TYPE_STANDARD)) + rc = 0; + else + break; + if (rc == 0) { + mxc_udc.ep0_dir = USB_DIR_IN; + mxc_udc_queue_update(0, NULL, 0, 0xffffffff); + } + return; + } + default: + break; + } + if (s->wLength) { + mxc_udc.ep0_dir = (s->bmRequestType & USB_DIR_IN) ? + USB_DIR_IN : USB_DIR_OUT; + mxc_udc_queue_update(0, ep0_urb->buffer, + ep0_urb->actual_length, 0xffffffff); + ep0_urb->actual_length = 0; + } else { + mxc_udc.ep0_dir = USB_DIR_IN; + mxc_udc_queue_update(0, NULL, 0, 0xffffffff); + } +} + +static int mxc_udc_tqi_empty(struct ep_queue_item *tqi) +{ + int ret; + + invalidate_dcache_range((unsigned long)tqi, + CACHE_ALIGNED_END(tqi, sizeof(struct ep_queue_item))); + + ret = tqi->info & (1 << 7); + return ret; +} + +static struct usb_endpoint_instance *mxc_get_epi(u8 epnum) +{ + int i; + for (i = 0; i < udc_device->bus->max_endpoints; i++) { + if ((udc_device->bus->endpoint_array[i].endpoint_address & + USB_ENDPOINT_NUMBER_MASK) == epnum) + return &udc_device->bus->endpoint_array[i]; + } + return NULL; +} + +static u32 _mxc_ep_recv_data(u8 epnum, struct ep_queue_item *tqi) +{ + struct usb_endpoint_instance *epi = mxc_get_epi(epnum); + struct urb *urb; + u32 len = 0; + + if (!epi) + return 0; + + invalidate_dcache_range((unsigned long)tqi, + CACHE_ALIGNED_END(tqi, sizeof(struct ep_queue_item))); + + urb = epi->rcv_urb; + if (urb) { + u8 *data = urb->buffer + urb->actual_length; + int remain_len = (tqi->info >> 16) & (0xefff); + len = tqi->reserved[0] - remain_len; + DBG("recv len %d-%d-%d\n", len, tqi->reserved[0], remain_len); + + + invalidate_dcache_range((unsigned long)tqi->page_vir, + CACHE_ALIGNED_END(tqi->page_vir, len)); + memcpy(data, (void *)tqi->page_vir, len); + + _dump_buf(data, len); + } + return len; +} + +static void mxc_udc_ep_recv(u8 epnum) +{ + struct mxc_ep_t *ep = mxc_udc.mxc_ep + (epnum * 2 + USB_RECV); + struct ep_queue_item *tqi; + while (1) { + u32 nbytes; + tqi = ep->ep_dtd[ep->done]; + if (mxc_udc_tqi_empty(tqi)) + break; + nbytes = _mxc_ep_recv_data(epnum, tqi); + usbd_rcv_complete(ep->epi, nbytes, 0); + inc_index(ep->done); + if (ep->done == ep->index) + break; + } +} + +static void mxc_udc_handle_xfer_complete(void) +{ + int i; + u32 bitpos = readl(USB_ENDPTCOMPLETE); + + writel(bitpos, USB_ENDPTCOMPLETE); + + for (i = 0; i < mxc_udc.max_ep; i++) { + int epnum = i >> 1; + int dir = i % 2; + u32 bitmask = 1 << (epnum + 16 * dir); + if (!(bitmask & bitpos)) + continue; + DBG("ep %d, dir %d, complete\n", epnum, dir); + if (!epnum) { + if (mxc_udc.setaddr) { + writel(udc_device->address << 25, + USB_DEVICEADDR); + mxc_udc.setaddr = 0; + } + continue; + } + DBG("############### dir = %d ***************\n", dir); + if (dir == USB_SEND) + continue; + mxc_udc_ep_recv(epnum); + } +} + +static void usb_dev_hand_usbint(void) +{ + if (readl(USB_ENDPTSETUPSTAT)) { + DBG("recv one setup packet\n"); + mxc_udc_recv_setup(); + } + if (readl(USB_ENDPTCOMPLETE)) { + DBG("Dtd complete irq\n"); + mxc_udc_handle_xfer_complete(); + } +} + +static void usb_dev_hand_reset(void) +{ + u32 temp; + temp = readl(USB_DEVICEADDR); + temp &= ~0xfe000000; + writel(temp, USB_DEVICEADDR); + writel(readl(USB_ENDPTSETUPSTAT), USB_ENDPTSETUPSTAT); + writel(readl(USB_ENDPTCOMPLETE), USB_ENDPTCOMPLETE); + while (readl(USB_ENDPTPRIME)) + ; + writel(0xffffffff, USB_ENDPTFLUSH); + DBG("reset-PORTSC=%x\n", readl(USB_PORTSC1)); + usbd_device_event_irq(udc_device, DEVICE_RESET, 0); +} + +void usb_dev_hand_pci(void) +{ + u32 speed; + while (readl(USB_PORTSC1) & PORTSCX_PORT_RESET) + ; + speed = readl(USB_PORTSC1) & PORTSCX_PORT_SPEED_MASK; + switch (speed) { + case PORTSCX_PORT_SPEED_HIGH: + usb_highspeed = 2; + break; + case PORTSCX_PORT_SPEED_FULL: + usb_highspeed = 1; + break; + case PORTSCX_PORT_SPEED_LOW: + usb_highspeed = 0; + break; + default: + break; + } + DBG("portspeed=%d, speed = %x, PORTSC = %x\n", + usb_highspeed, speed, readl(USB_PORTSC1)); +} + +void usb_dev_hand_suspend(void) +{ +} + +void mxc_irq_poll(void) +{ + unsigned irq_src = readl(USB_USBSTS) & readl(USB_USBINTR); + writel(irq_src, USB_USBSTS); + + if (irq_src == 0) + return; + + if (irq_src & USB_STS_INT) + usb_dev_hand_usbint(); + + if (irq_src & USB_STS_RESET) { + printf("USB_RESET\n"); + usb_dev_hand_reset(); + } + if (irq_src & USB_STS_PORT_CHANGE) { + printf("USB_PORT_CHANGE 0x%x\n", irq_src); + usb_dev_hand_pci(); + } + if (irq_src & USB_STS_SUSPEND) + printf("USB_SUSPEND\n"); + if (irq_src & USB_STS_ERR) + printf("USB_ERR\n"); +} + +void mxc_udc_wait_cable_insert(void) +{ + u32 temp; + int cable_connect = 1; + + do { + udelay(50); + + temp = readl(USB_OTGSC); + if (temp & (OTGSC_B_SESSION_VALID)) { + printf("USB Mini b cable Connected!\n"); + break; + } else if (cable_connect == 1) { + printf("wait usb cable into the connector!\n"); + cable_connect = 0; + } + } while (1); +} + +void udc_disable_over_current(void) +{ + u32 temp; + temp = readl(USB_OTG_CTRL); + temp |= (UCTRL_OVER_CUR_POL); + writel(temp, USB_OTG_CTRL); +} + +/* + * mxc_udc_init function + */ +int mxc_udc_init(void) +{ + udc_pins_setting(); + set_usb_phy1_clk(); + enable_usboh3_clk(1); +#if defined(CONFIG_MX6Q) || defined(CONFIG_MX6DL) || defined(CONFIG_MX6SL) + udc_disable_over_current(); +#endif + enable_usb_phy1_clk(1); + usb_udc_init(); + + return 0; +} + +/* + * mxc_udc_init function + */ +int mxc_udc_destroy(void) +{ + usb_udc_destroy(); + enable_usboh3_clk(0); + enable_usb_phy1_clk(0); + + return 0; +} + +void mxc_udc_poll(void) +{ + mxc_irq_poll(); +} + +/* + * Functions for gadget APIs + */ +int udc_init(void) +{ + mxc_udc_init(); + return 0; +} + +int udc_destroy(void) +{ + udc_disable(); + mxc_udc_destroy(); + return 0; +} + +void udc_setup_ep(struct usb_device_instance *device, u32 index, + struct usb_endpoint_instance *epi) +{ + u8 dir, epnum, zlt, mult; + u8 ep_type; + u32 max_pkt_size; + int ep_addr; + struct mxc_ep_t *ep; + + if (epi) { + zlt = 1; + mult = 0; + ep_addr = epi->endpoint_address; + epnum = ep_addr & USB_ENDPOINT_NUMBER_MASK; + DBG("setup ep %d\n", epnum); + if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { + dir = USB_SEND; + ep_type = epi->tx_attributes; + max_pkt_size = epi->tx_packetSize; + } else { + dir = USB_RECV; + ep_type = epi->rcv_attributes; + max_pkt_size = epi->rcv_packetSize; + } + if (ep_type == USB_ENDPOINT_XFER_ISOC) { + mult = (u32)(1 + ((max_pkt_size >> 11) & 0x03)); + max_pkt_size = max_pkt_size & 0x7ff; + DBG("mult = %d\n", mult); + } + ep = mxc_udc.mxc_ep + (epnum * 2 + dir); + ep->epi = epi; + if (epnum) { + struct ep_queue_item *tqi; + int i; + + mxc_ep_qh_setup(epnum, dir, ep_type, + max_pkt_size, zlt, mult); + mxc_ep_setup(epnum, dir, ep_type); + mxc_init_ep_dtd(epnum * 2 + dir); + + /* malloc endpoint's dtd's data buffer*/ + ep->max_pkt_size = max_pkt_size; + for (i = 0; i < EP_TQ_ITEM_SIZE; i++) { + tqi = ep->ep_dtd[i]; + tqi->page_vir = (u32)malloc_aligned_buffer( + &tqi->page_unaligned, max_pkt_size, + USB_MEM_ALIGN_BYTE); + if ((void *)tqi->page_vir == NULL) { + printf("malloc dtd bufer failure\n"); + return; + } + mxc_tqi_init_page(tqi); + + flush_dcache_range((unsigned long)tqi, + CACHE_ALIGNED_END(tqi, sizeof(struct ep_queue_item))); + } + } + } +} + +void udc_destroy_ep(struct usb_device_instance *device, + struct usb_endpoint_instance *epi) +{ + struct mxc_ep_t *ep; + int ep_addr; + u8 dir, epnum; + + if (epi) { + ep_addr = epi->endpoint_address; + epnum = ep_addr & USB_ENDPOINT_NUMBER_MASK; + + if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) + dir = USB_SEND; + else + dir = USB_RECV; + + ep = mxc_udc.mxc_ep + (epnum * 2 + dir); + ep->epi = 0; + + if (epnum) { + struct ep_queue_item *tqi; + int i; + + for (i = 0; i < EP_TQ_ITEM_SIZE; i++) { + tqi = ep->ep_dtd[i]; + if (tqi->page_vir) { + free((void *)(tqi->page_unaligned)); + tqi->page_unaligned = 0; + tqi->page_vir = 0; + tqi->page0 = 0; + tqi->page1 = 0; + tqi->page2 = 0; + tqi->page3 = 0; + tqi->page4 = 0; + } + } + + mxc_destroy_ep_dtd(epnum * 2 + dir); + mxc_ep_destroy(epnum, dir); + } + } +} + +int udc_endpoint_write(struct usb_endpoint_instance *epi) +{ + struct urb *urb = epi->tx_urb; + int ep_num = epi->endpoint_address & USB_ENDPOINT_NUMBER_MASK; + u8 *data = (u8 *)urb->buffer + epi->sent; + int n = urb->actual_length - epi->sent; + mxc_udc_txqueue_update(ep_num, data, n); + epi->last = n; + + /* usbd_tx_complete will take care of updating 'sent' */ + usbd_tx_complete(epi); + return 0; +} + +void udc_enable(struct usb_device_instance *device) +{ + udc_device = device; + ep0_urb = usbd_alloc_urb(udc_device, udc_device->bus->endpoint_array); +} + +void udc_disable(void) +{ + usbd_dealloc_urb(ep0_urb); + udc_device = NULL; +} + +void udc_startup_events(struct usb_device_instance *device) +{ + usbd_device_event_irq(device, DEVICE_INIT, 0); + usbd_device_event_irq(device, DEVICE_CREATE, 0); + udc_enable(device); +} + +void udc_irq(void) +{ + mxc_irq_poll(); +} + +void udc_connect(void) +{ + mxc_usb_run(); + mxc_udc_wait_cable_insert(); +} + +void udc_disconnect(void) +{ + /* imx6 will hang if access usb register without init oh3 + * clock, so not access it if not init. */ + if (usb_inited) + mxc_usb_stop(); +} + +void udc_set_nak(int epid) +{ +} + +void udc_unset_nak(int epid) +{ +} diff --git a/include/usb/imx_udc.h b/include/usb/imx_udc.h new file mode 100644 index 0000000..870405f --- /dev/null +++ b/include/usb/imx_udc.h @@ -0,0 +1,573 @@ +/* + * Copyright (C) 2010-2014 Freescale Semiconductor, Inc. All Rights Reserved. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _IMX_UDC_H_ +#define _IMX_UDC_H_ + +#include + +#define USB_OTGREGS_BASE (OTG_BASE_ADDR + 0x000) +#define USB_H1REGS_BASE (OTG_BASE_ADDR + 0x200) +#define USB_H2REGS_BASE (OTG_BASE_ADDR + 0x400) +#if (defined CONFIG_MX51 || defined CONFIG_MX50 || defined CONFIG_MX6Q \ + || defined CONFIG_MX53 || defined CONFIG_MX6DL || defined CONFIG_MX6SL) +#define USB_H3REGS_BASE (OTG_BASE_ADDR + 0x600) +#define USB_OTHERREGS_BASE (OTG_BASE_ADDR + 0x800) +#else +#define USB_OTHERREGS_BASE (OTG_BASE_ADDR + 0x600) +#endif + +#define USBOTG_REG32(offset) (USB_OTGREGS_BASE + (offset)) +#define USBOTG_REG16(offset) (USB_OTGREGS_BASE + (offset)) +#define USBOTHER_REG(offset) (USB_OTHERREGS_BASE + (offset)) + +#define USB_ID (OTG_BASE_ADDR + 0x0000) +#define USB_HWGENERAL (OTG_BASE_ADDR + 0x0004) +#define USB_HWHOST (OTG_BASE_ADDR + 0x0008) +#define USB_HWDEVICE (OTG_BASE_ADDR + 0x000C) +#define USB_HWTXBUF (OTG_BASE_ADDR + 0x0010) +#define USB_HWRXBUF (OTG_BASE_ADDR + 0x0014) +#define USB_SBUSCFG (OTG_BASE_ADDR + 0x0090) + +#define USB_CAPLENGTH (OTG_BASE_ADDR + 0x0100) /* 8 bit */ +#define USB_HCIVERSION (OTG_BASE_ADDR + 0x0102) /* 16 bit */ +#define USB_HCSPARAMS (OTG_BASE_ADDR + 0x0104) +#define USB_HCCPARAMS (OTG_BASE_ADDR + 0x0108) +#define USB_DCIVERSION (OTG_BASE_ADDR + 0x0120) /* 16 bit */ +#define USB_DCCPARAMS (OTG_BASE_ADDR + 0x0124) +#define USB_USBCMD (OTG_BASE_ADDR + 0x0140) +#define USB_USBSTS (OTG_BASE_ADDR + 0x0144) +#define USB_USBINTR (OTG_BASE_ADDR + 0x0148) +#define USB_FRINDEX (OTG_BASE_ADDR + 0x014C) +#define USB_DEVICEADDR (OTG_BASE_ADDR + 0x0154) +#define USB_ENDPOINTLISTADDR (OTG_BASE_ADDR + 0x0158) +#define USB_BURSTSIZE (OTG_BASE_ADDR + 0x0160) +#define USB_TXFILLTUNING (OTG_BASE_ADDR + 0x0164) +#define USB_ULPI_VIEWPORT (OTG_BASE_ADDR + 0x0170) +#define USB_ENDPTNAK (OTG_BASE_ADDR + 0x0178) +#define USB_ENDPTNAKEN (OTG_BASE_ADDR + 0x017C) +#define USB_PORTSC1 (OTG_BASE_ADDR + 0x0184) +#define USB_OTGSC (OTG_BASE_ADDR + 0x01A4) +#define USB_USBMODE (OTG_BASE_ADDR + 0x01A8) +#define USB_ENDPTSETUPSTAT (OTG_BASE_ADDR + 0x01AC) +#define USB_ENDPTPRIME (OTG_BASE_ADDR + 0x01B0) +#define USB_ENDPTFLUSH (OTG_BASE_ADDR + 0x01B4) +#define USB_ENDPTSTAT (OTG_BASE_ADDR + 0x01B8) +#define USB_ENDPTCOMPLETE (OTG_BASE_ADDR + 0x01BC) +#define USB_ENDPTCTRL(n) (OTG_BASE_ADDR + 0x01C0 + (4 * (n))) + +/* + * other regs (not part of ARC core) + */ +/* USB Control register */ +#define USBCTRL USBOTHER_REG(0x00) + +/* USB OTG mirror register */ +#define USB_OTG_MIRROR USBOTHER_REG(0x04) + +/* OTG UTMI PHY Function Control register */ +#define USB_PHY_CTR_FUNC USBOTHER_REG(0x08) + +/* OTG UTMI PHY Function Control register */ +#define USB_PHY_CTR_FUNC2 USBOTHER_REG(0x0c) + +#define USB_CTRL_1 USBOTHER_REG(0x10) +#define USBCTRL_HOST2 USBOTHER_REG(0x14) /* USB Cotrol Register 1*/ +#define USBCTRL_HOST3 USBOTHER_REG(0x18) /* USB Cotrol Register 1*/ +#define USBH1_PHY_CTRL0 USBOTHER_REG(0x1c) /* USB Cotrol Register 1*/ +#define USBH1_PHY_CTRL1 USBOTHER_REG(0x20) /* USB Cotrol Register 1*/ + +/* USB Clock on/off Control Register */ +#define USB_CLKONOFF_CTRL USBOTHER_REG(0x24) + +/* mx6x other regs */ +/* USB OTG Control register */ +#define USB_OTG_CTRL USBOTHER_REG(0x00) + +/* USB H1 Control register */ +#define USB_H1_CTRL USBOTHER_REG(0x04) + +/* USB H2 Control register */ +#define USB_H2_CTRL USBOTHER_REG(0x08) + +/* USB H3 Control register */ +#define USB_H3_CTRL USBOTHER_REG(0x0c) + +/* USB Host2 HSIC Control Register */ +#define USB_UH2_HSIC_CTRL USBOTHER_REG(0x10) + +/* USB Host3 HSIC Control Register */ +#define USB_UH3_HSIC_CTRL USBOTHER_REG(0x14) + +/* OTG UTMI PHY Control 0 Register */ +#define USB_OTG_PHY_CTRL_0 USBOTHER_REG(0x18) + +/* OTG UTMI PHY Control 1 Register */ +#define USB_H1_PHY_CTRL_0 USBOTHER_REG(0x1c) + +/* USB Host2 HSIC DLL Configuration Register 1 */ +#define USB_UH2_HSIC_DLL_CFG1 USBOTHER_REG(0x20) + +/* USB Host2 HSIC DLL Configuration Register 2 */ +#define USB_UH2_HSIC_DLL_CFG2 USBOTHER_REG(0x24) + +/* USB Host2 HSIC DLL Configuration Register 3 */ +#define USB_UH2_HSIC_DLL_CFG3 USBOTHER_REG(0x28) + +/* USB Host3 HSIC DLL Configuration Register 1 */ +#define USB_UH3_HSIC_DLL_CFG1 USBOTHER_REG(0x30) + +/* USB Host3 HSIC DLL Configuration Register 2 */ +#define USB_UH3_HSIC_DLL_CFG2 USBOTHER_REG(0x34) + +/* USB Host3 HSIC DLL Configuration Register 3 */ +#define USB_UH3_HSIC_DLL_CFG3 USBOTHER_REG(0x38) + + +#define USB_PHY1_CTRL (OTG_BASE_ADDR + 0x80C) +#define USBCMD_RESET 2 +#define USBCMD_ATTACH 1 + +#define USBMODE_DEVICE 2 +#define USBMODE_HOST 3 + +struct ep_queue_head { + volatile unsigned int config; + volatile unsigned int current; /* read-only */ + + volatile unsigned int next_queue_item; + volatile unsigned int info; + volatile unsigned int page0; + volatile unsigned int page1; + volatile unsigned int page2; + volatile unsigned int page3; + volatile unsigned int page4; + volatile unsigned int reserved_0; + + volatile unsigned char setup_data[8]; + volatile unsigned int reserved[4]; +}; + +#define CONFIG_MAX_PKT(n) ((n) << 16) +#define CONFIG_ZLT (1 << 29) /* stop on zero-len xfer */ +#define CONFIG_IOS (1 << 15) /* IRQ on setup */ + +struct ep_queue_item { + volatile unsigned int next_item_ptr; + volatile unsigned int info; + volatile unsigned int page0; + volatile unsigned int page1; + volatile unsigned int page2; + volatile unsigned int page3; + volatile unsigned int page4; + unsigned int item_unaligned_addr; + unsigned int page_vir; + unsigned int page_unaligned; + struct ep_queue_item *next_item_vir; + volatile unsigned int reserved[5]; +}; + +#define TERMINATE 1 + +#define INFO_BYTES(n) ((n) << 16) +#define INFO_IOC (1 << 15) +#define INFO_ACTIVE (1 << 7) +#define INFO_HALTED (1 << 6) +#define INFO_BUFFER_ERROR (1 << 5) +#define INFO_TX_ERROR (1 << 3) + +/* Device Controller Capability Parameter register */ +#define DCCPARAMS_DC 0x00000080 +#define DCCPARAMS_DEN_MASK 0x0000001f + +/* Frame Index Register Bit Masks */ +#define USB_FRINDEX_MASKS (0x3fff) +/* USB CMD Register Bit Masks */ +#define USB_CMD_RUN_STOP (0x00000001) +#define USB_CMD_CTRL_RESET (0x00000002) +#define USB_CMD_PERIODIC_SCHEDULE_EN (0x00000010) +#define USB_CMD_ASYNC_SCHEDULE_EN (0x00000020) +#define USB_CMD_INT_AA_DOORBELL (0x00000040) +#define USB_CMD_ASP (0x00000300) +#define USB_CMD_ASYNC_SCH_PARK_EN (0x00000800) +#define USB_CMD_SUTW (0x00002000) +#define USB_CMD_ATDTW (0x00004000) +#define USB_CMD_ITC (0x00FF0000) + +/* bit 15,3,2 are frame list size */ +#define USB_CMD_FRAME_SIZE_1024 (0x00000000) +#define USB_CMD_FRAME_SIZE_512 (0x00000004) +#define USB_CMD_FRAME_SIZE_256 (0x00000008) +#define USB_CMD_FRAME_SIZE_128 (0x0000000C) +#define USB_CMD_FRAME_SIZE_64 (0x00008000) +#define USB_CMD_FRAME_SIZE_32 (0x00008004) +#define USB_CMD_FRAME_SIZE_16 (0x00008008) +#define USB_CMD_FRAME_SIZE_8 (0x0000800C) + +/* bit 9-8 are async schedule park mode count */ +#define USB_CMD_ASP_00 (0x00000000) +#define USB_CMD_ASP_01 (0x00000100) +#define USB_CMD_ASP_10 (0x00000200) +#define USB_CMD_ASP_11 (0x00000300) +#define USB_CMD_ASP_BIT_POS (8) + +/* bit 23-16 are interrupt threshold control */ +#define USB_CMD_ITC_NO_THRESHOLD (0x00000000) +#define USB_CMD_ITC_1_MICRO_FRM (0x00010000) +#define USB_CMD_ITC_2_MICRO_FRM (0x00020000) +#define USB_CMD_ITC_4_MICRO_FRM (0x00040000) +#define USB_CMD_ITC_8_MICRO_FRM (0x00080000) +#define USB_CMD_ITC_16_MICRO_FRM (0x00100000) +#define USB_CMD_ITC_32_MICRO_FRM (0x00200000) +#define USB_CMD_ITC_64_MICRO_FRM (0x00400000) +#define USB_CMD_ITC_BIT_POS (16) + +/* USB STS Register Bit Masks */ +#define USB_STS_INT (0x00000001) +#define USB_STS_ERR (0x00000002) +#define USB_STS_PORT_CHANGE (0x00000004) +#define USB_STS_FRM_LST_ROLL (0x00000008) +#define USB_STS_SYS_ERR (0x00000010) +#define USB_STS_IAA (0x00000020) +#define USB_STS_RESET (0x00000040) +#define USB_STS_SOF (0x00000080) +#define USB_STS_SUSPEND (0x00000100) +#define USB_STS_HC_HALTED (0x00001000) +#define USB_STS_RCL (0x00002000) +#define USB_STS_PERIODIC_SCHEDULE (0x00004000) +#define USB_STS_ASYNC_SCHEDULE (0x00008000) + +/* USB INTR Register Bit Masks */ +#define USB_INTR_INT_EN (0x00000001) +#define USB_INTR_ERR_INT_EN (0x00000002) +#define USB_INTR_PTC_DETECT_EN (0x00000004) +#define USB_INTR_FRM_LST_ROLL_EN (0x00000008) +#define USB_INTR_SYS_ERR_EN (0x00000010) +#define USB_INTR_ASYN_ADV_EN (0x00000020) +#define USB_INTR_RESET_EN (0x00000040) +#define USB_INTR_SOF_EN (0x00000080) +#define USB_INTR_DEVICE_SUSPEND (0x00000100) + +/* Device Address bit masks */ +#define USB_DEVICE_ADDRESS_MASK (0xFE000000) +#define USB_DEVICE_ADDRESS_BIT_POS (25) + +/* endpoint list address bit masks */ +#define USB_EP_LIST_ADDRESS_MASK (0xfffff800) + +/* PORTSCX Register Bit Masks */ +#define PORTSCX_CURRENT_CONNECT_STATUS (0x00000001) +#define PORTSCX_CONNECT_STATUS_CHANGE (0x00000002) +#define PORTSCX_PORT_ENABLE (0x00000004) +#define PORTSCX_PORT_EN_DIS_CHANGE (0x00000008) +#define PORTSCX_OVER_CURRENT_ACT (0x00000010) +#define PORTSCX_OVER_CURRENT_CHG (0x00000020) +#define PORTSCX_PORT_FORCE_RESUME (0x00000040) +#define PORTSCX_PORT_SUSPEND (0x00000080) +#define PORTSCX_PORT_RESET (0x00000100) +#define PORTSCX_LINE_STATUS_BITS (0x00000C00) +#define PORTSCX_PORT_POWER (0x00001000) +#define PORTSCX_PORT_INDICTOR_CTRL (0x0000C000) +#define PORTSCX_PORT_TEST_CTRL (0x000F0000) +#define PORTSCX_WAKE_ON_CONNECT_EN (0x00100000) +#define PORTSCX_WAKE_ON_CONNECT_DIS (0x00200000) +#define PORTSCX_WAKE_ON_OVER_CURRENT (0x00400000) +#define PORTSCX_PHY_LOW_POWER_SPD (0x00800000) +#define PORTSCX_PORT_FORCE_FULL_SPEED (0x01000000) +#define PORTSCX_PORT_SPEED_MASK (0x0C000000) +#define PORTSCX_PORT_WIDTH (0x10000000) +#define PORTSCX_PHY_TYPE_SEL (0xC0000000) + +/* bit 11-10 are line status */ +#define PORTSCX_LINE_STATUS_SE0 (0x00000000) +#define PORTSCX_LINE_STATUS_JSTATE (0x00000400) +#define PORTSCX_LINE_STATUS_KSTATE (0x00000800) +#define PORTSCX_LINE_STATUS_UNDEF (0x00000C00) +#define PORTSCX_LINE_STATUS_BIT_POS (10) + +/* bit 15-14 are port indicator control */ +#define PORTSCX_PIC_OFF (0x00000000) +#define PORTSCX_PIC_AMBER (0x00004000) +#define PORTSCX_PIC_GREEN (0x00008000) +#define PORTSCX_PIC_UNDEF (0x0000C000) +#define PORTSCX_PIC_BIT_POS (14) + +/* bit 19-16 are port test control */ +#define PORTSCX_PTC_DISABLE (0x00000000) +#define PORTSCX_PTC_JSTATE (0x00010000) +#define PORTSCX_PTC_KSTATE (0x00020000) +#define PORTSCX_PTC_SEQNAK (0x00030000) +#define PORTSCX_PTC_PACKET (0x00040000) +#define PORTSCX_PTC_FORCE_EN (0x00050000) +#define PORTSCX_PTC_BIT_POS (16) + +/* bit 27-26 are port speed */ +#define PORTSCX_PORT_SPEED_FULL (0x00000000) +#define PORTSCX_PORT_SPEED_LOW (0x04000000) +#define PORTSCX_PORT_SPEED_HIGH (0x08000000) +#define PORTSCX_PORT_SPEED_UNDEF (0x0C000000) +#define PORTSCX_SPEED_BIT_POS (26) + +/* OTGSC Register Bit Masks */ +#define OTGSC_B_SESSION_VALID_IRQ_EN (1 << 27) +#define OTGSC_B_SESSION_VALID_IRQ_STS (1 << 19) +#define OTGSC_B_SESSION_VALID (1 << 11) + +/* bit 28 is parallel transceiver width for UTMI interface */ +#define PORTSCX_PTW (0x10000000) +#define PORTSCX_PTW_8BIT (0x00000000) +#define PORTSCX_PTW_16BIT (0x10000000) + +/* bit 31-30 are port transceiver select */ +#define PORTSCX_PTS_UTMI (0x00000000) +#define PORTSCX_PTS_ULPI (0x80000000) +#define PORTSCX_PTS_FSLS (0xC0000000) +#define PORTSCX_PTS_BIT_POS (30) + +/* USB MODE Register Bit Masks */ +#define USB_MODE_CTRL_MODE_IDLE (0x00000000) +#define USB_MODE_CTRL_MODE_DEVICE (0x00000002) +#define USB_MODE_CTRL_MODE_HOST (0x00000003) +#define USB_MODE_CTRL_MODE_MASK 0x00000003 +#define USB_MODE_CTRL_MODE_RSV (0x00000001) +#define USB_MODE_ES 0x00000004 /* (big) Endian Sel */ +#define USB_MODE_SETUP_LOCK_OFF (0x00000008) +#define USB_MODE_STREAM_DISABLE (0x00000010) +/* Endpoint Flush Register */ +#define EPFLUSH_TX_OFFSET (0x00010000) +#define EPFLUSH_RX_OFFSET (0x00000000) + +/* Endpoint Setup Status bit masks */ +#define EP_SETUP_STATUS_MASK (0x0000003F) +#define EP_SETUP_STATUS_EP0 (0x00000001) + +/* ENDPOINTCTRLx Register Bit Masks */ +#define EPCTRL_TX_ENABLE (0x00800000) +#define EPCTRL_TX_DATA_TOGGLE_RST (0x00400000) /* Not EP0 */ +#define EPCTRL_TX_DATA_TOGGLE_INH (0x00200000) /* Not EP0 */ +#define EPCTRL_TX_TYPE (0x000C0000) +#define EPCTRL_TX_DATA_SOURCE (0x00020000) /* Not EP0 */ +#define EPCTRL_TX_EP_STALL (0x00010000) +#define EPCTRL_RX_ENABLE (0x00000080) +#define EPCTRL_RX_DATA_TOGGLE_RST (0x00000040) /* Not EP0 */ +#define EPCTRL_RX_DATA_TOGGLE_INH (0x00000020) /* Not EP0 */ +#define EPCTRL_RX_TYPE (0x0000000C) +#define EPCTRL_RX_DATA_SINK (0x00000002) /* Not EP0 */ +#define EPCTRL_RX_EP_STALL (0x00000001) + +/* bit 19-18 and 3-2 are endpoint type */ +#define EPCTRL_EP_TYPE_CONTROL (0) +#define EPCTRL_EP_TYPE_ISO (1) +#define EPCTRL_EP_TYPE_BULK (2) +#define EPCTRL_EP_TYPE_INTERRUPT (3) +#define EPCTRL_TX_EP_TYPE_SHIFT (18) +#define EPCTRL_RX_EP_TYPE_SHIFT (2) + +/* SNOOPn Register Bit Masks */ +#define SNOOP_ADDRESS_MASK (0xFFFFF000) +#define SNOOP_SIZE_ZERO (0x00) /* snooping disable */ +#define SNOOP_SIZE_4KB (0x0B) /* 4KB snoop size */ +#define SNOOP_SIZE_8KB (0x0C) +#define SNOOP_SIZE_16KB (0x0D) +#define SNOOP_SIZE_32KB (0x0E) +#define SNOOP_SIZE_64KB (0x0F) +#define SNOOP_SIZE_128KB (0x10) +#define SNOOP_SIZE_256KB (0x11) +#define SNOOP_SIZE_512KB (0x12) +#define SNOOP_SIZE_1MB (0x13) +#define SNOOP_SIZE_2MB (0x14) +#define SNOOP_SIZE_4MB (0x15) +#define SNOOP_SIZE_8MB (0x16) +#define SNOOP_SIZE_16MB (0x17) +#define SNOOP_SIZE_32MB (0x18) +#define SNOOP_SIZE_64MB (0x19) +#define SNOOP_SIZE_128MB (0x1A) +#define SNOOP_SIZE_256MB (0x1B) +#define SNOOP_SIZE_512MB (0x1C) +#define SNOOP_SIZE_1GB (0x1D) +#define SNOOP_SIZE_2GB (0x1E) /* 2GB snoop size */ + +/* pri_ctrl Register Bit Masks */ +#define PRI_CTRL_PRI_LVL1 (0x0000000C) +#define PRI_CTRL_PRI_LVL0 (0x00000003) + +/* si_ctrl Register Bit Masks */ +#define SI_CTRL_ERR_DISABLE (0x00000010) +#define SI_CTRL_IDRC_DISABLE (0x00000008) +#define SI_CTRL_RD_SAFE_EN (0x00000004) +#define SI_CTRL_RD_PREFETCH_DISABLE (0x00000002) +#define SI_CTRL_RD_PREFEFETCH_VAL (0x00000001) + +/* control Register Bit Masks */ +#define USB_CTRL_IOENB (0x00000004) +#define USB_CTRL_ULPI_INT0EN (0x00000001) +#define USB_CTRL_OTG_WUIR (0x80000000) +#define USB_CTRL_OTG_WUIE (0x08000000) +#define USB_CTRL_OTG_VWUE (0x00001000) +#define USB_CTRL_OTG_IWUE (0x00100000) + + + +#define INTR_UE (1 << 0) +#define INTR_UEE (1 << 1) +#define INTR_PCE (1 << 2) +#define INTR_SEE (1 << 4) +#define INTR_URE (1 << 6) +#define INTR_SRE (1 << 7) +#define INTR_SLE (1 << 8) + + +/* bits used in all the endpoint status registers */ +#define EPT_TX(n) (1 << ((n) + 16)) +#define EPT_RX(n) (1 << (n)) + + +#define CTRL_TXE (1 << 23) +#define CTRL_TXR (1 << 22) +#define CTRL_TXI (1 << 21) +#define CTRL_TXD (1 << 17) +#define CTRL_TXS (1 << 16) +#define CTRL_RXE (1 << 7) +#define CTRL_RXR (1 << 6) +#define CTRL_RXI (1 << 5) +#define CTRL_RXD (1 << 1) +#define CTRL_RXS (1 << 0) + +#define CTRL_TXT_CTRL (0 << 18) +#define CTRL_TXT_ISOCH (1 << 18) +#define CTRL_TXT_BULK (2 << 18) +#define CTRL_TXT_INT (3 << 18) + +#define CTRL_RXT_CTRL (0 << 2) +#define CTRL_RXT_ISOCH (1 << 2) +#define CTRL_RXT_BULK (2 << 2) +#define CTRL_RXT_INT (3 << 2) + +#define USB_RECV 0 +#define USB_SEND 1 +#define USB_MAX_CTRL_PAYLOAD 64 + +/* UDC device defines */ +#define EP0_MAX_PACKET_SIZE USB_MAX_CTRL_PAYLOAD +#define UDC_OUT_ENDPOINT 0x02 +#define UDC_OUT_PACKET_SIZE USB_MAX_CTRL_PAYLOAD +#define UDC_IN_ENDPOINT 0x03 +#define UDC_IN_PACKET_SIZE USB_MAX_CTRL_PAYLOAD +#define UDC_INT_ENDPOINT 0x01 +#define UDC_INT_PACKET_SIZE USB_MAX_CTRL_PAYLOAD +#define UDC_BULK_PACKET_SIZE USB_MAX_CTRL_PAYLOAD + +/* mx6q's register bit begins*/ + +/* OTG CTRL - H3 CTRL */ +#define UCTRL_OWIR (1 << 31) /* OTG wakeup intr request received */ +/* bit 18 - bit 30 is reserved at mx6q */ +#define UCTRL_WKUP_VBUS_EN (1 << 17) /* OTG wake-up on VBUS change enable */ +#define UCTRL_WKUP_ID_EN (1 << 16) /* OTG wake-up on ID change enable */ +#define UCTRL_WKUP_SW (1 << 15) /* OTG Software Wake-up */ +#define UCTRL_WKUP_SW_EN (1 << 14) /* OTG Software Wake-up enable */ +#define UCTRL_UTMI_ON_CLOCK (1 << 13) /* Force OTG UTMI PHY clock output + on even if suspend mode */ +#define UCTRL_SUSPENDM (1 << 12) /* Force OTG UTMI PHY Suspend */ +#define UCTRL_RESET (1 << 11) /* Force OTG UTMI PHY Reset */ +#define UCTRL_OWIE (1 << 10) /* OTG wakeup intr request received */ +#define UCTRL_PM (1 << 9) /* OTG Power Mask */ +#define UCTRL_OVER_CUR_POL (1 << 8) /* OTG Polarity of Overcurrent */ +#define UCTRL_OVER_CUR_DIS (1 << 7) /* Disable OTG Overcurrent Detection */ +/* bit 0 - bit 6 is reserved at mx6q */ + +/* Host2/3 HSIC Ctrl */ +#define CLK_VLD (1 << 31) /* Indicating whether HSIC clock is valid */ +#define HSIC_EN (1 << 12) /* HSIC enable */ +#define HSIC_CLK_ON (1 << 11) /* Force HSIC module 480M clock on, + * even when in Host is in suspend mode + */ +/* OTG/HOST1 Phy Ctrl */ +#define PHY_UTMI_CLK_VLD (1 << 31)/* Indicating whether OTG UTMI PHY Clock Valid*/ + +int udc_init(void); + +void udc_enable(struct usb_device_instance *device); +void udc_disable(void); + +void udc_connect(void); +void udc_disconnect(void); + +void udc_startup_events(struct usb_device_instance *device); +void udc_setup_ep(struct usb_device_instance *device, + unsigned int ep, struct usb_endpoint_instance *endpoint); +int udc_endpoint_write(struct usb_endpoint_instance *epi); +void udc_irq(void); +void usb_shutdown(void); +void mxc_udc_rxqueue_update(u8 ep, u32 len); +int is_usb_disconnected(void); +void reset_usb_phy1(void); +void set_usboh3_clk(void); +void set_usb_phy1_clk(void); +void enable_usb_phy1_clk(unsigned char enable); +void enable_usboh3_clk(unsigned char enable); +void udc_pins_setting(void); + +/*destroy functions*/ +void udc_destroy_ep(struct usb_device_instance *device, + struct usb_endpoint_instance *epi); +int udc_destroy(void); + + +#ifdef CONFIG_FASTBOOT + +#define EP0_OUT_INDEX 0 +#define EP0_IN_INDEX 16 +#define EP1_OUT_INDEX 1 +#define EP1_IN_INDEX 17 +#define EP2_OUT_INDEX 2 +#define EP2_IN_INDEX 18 +#define EP3_OUT_INDEX 3 +#define EP3_IN_INDEX 19 +#define EP4_OUT_INDEX 4 +#define EP4_IN_INDEX 20 +#define EP5_OUT_INDEX 5 +#define EP5_IN_INDEX 21 +#define EP6_OUT_INDEX 6 +#define EP6_IN_INDEX 22 +#define EP7_OUT_INDEX 7 +#define EP7_IN_INDEX 23 +#define EP8_OUT_INDEX 8 +#define EP8_IN_INDEX 24 +#define EP9_OUT_INDEX 9 +#define EP9_IN_INDEX 25 +#define EP10_OUT_INDEX 10 +#define EP10_IN_INDEX 26 +#define EP11_OUT_INDEX 11 +#define EP11_IN_INDEX 27 +#define EP12_OUT_INDEX 12 +#define EP12_IN_INDEX 28 +#define EP13_OUT_INDEX 13 +#define EP13_IN_INDEX 29 +#define EP14_OUT_INDEX 14 +#define EP14_IN_INDEX 30 +#define EP15_OUT_INDEX 15 +#define EP15_IN_INDEX 31 + +#define MAX_PAKET_LEN 512 +typedef void (*EP_HANDLER_P)(u32 index, u8 *buf); + +int udc_irq_handler(void); +void udc_hal_data_init(void); +void udc_wait_connect(void); +void udc_run(void); +int udc_recv_data(u32 index, u8 *recvbuf, u32 recvlen, EP_HANDLER_P cb); +int udc_send_data(u32 index, u8 *buf, u32 sendlen, EP_HANDLER_P cb); +void udc_qh_dtd_init(u32 index); +void udc_dtd_setup(u32 index, u8 ep_type); +void udc_qh_setup(u32 index, u8 ep_type, u32 max_pkt_len, u32 zlt, u8 mult); +u8 *udc_get_descriptor(u8 type, u8 *plen); +void udc_set_addr(u8 addr); +void udc_set_configure(u8 config); + +#endif /* CONFIG_FASTBOOT */ + +#endif -- cgit v1.1