From patchwork Thu Aug 28 19:55:32 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ivan Khoronzhuk X-Patchwork-Id: 384012 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id A456F140086 for ; Fri, 29 Aug 2014 05:55:56 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id CF93FA7400; Thu, 28 Aug 2014 21:55:54 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id aupPZ3IzVfDc; Thu, 28 Aug 2014 21:55:54 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id EC967A7418; Thu, 28 Aug 2014 21:55:51 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id D7F46A7418 for ; Thu, 28 Aug 2014 21:55:46 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id KuVEYniZBlok for ; Thu, 28 Aug 2014 21:55:43 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from devils.ext.ti.com (devils.ext.ti.com [198.47.26.153]) by theia.denx.de (Postfix) with ESMTPS id 4B69CA7400 for ; Thu, 28 Aug 2014 21:55:39 +0200 (CEST) Received: from dflxv15.itg.ti.com ([128.247.5.124]) by devils.ext.ti.com (8.13.7/8.13.7) with ESMTP id s7SJtb3k025450 for ; Thu, 28 Aug 2014 14:55:37 -0500 Received: from DLEE70.ent.ti.com (dlee70.ent.ti.com [157.170.170.113]) by dflxv15.itg.ti.com (8.14.3/8.13.8) with ESMTP id s7SJtbUI019667 for ; Thu, 28 Aug 2014 14:55:37 -0500 Received: from dflp32.itg.ti.com (10.64.6.15) by DLEE70.ent.ti.com (157.170.170.113) with Microsoft SMTP Server id 14.3.174.1; Thu, 28 Aug 2014 14:55:37 -0500 Received: from khorivan.itg.ti.com (incasgf5a_e1_2.itg.ti.com [10.167.216.36]) by dflp32.itg.ti.com (8.14.3/8.13.8) with ESMTP id s7SJtZXU026480; Thu, 28 Aug 2014 14:55:35 -0500 From: Ivan Khoronzhuk To: , Date: Thu, 28 Aug 2014 22:55:32 +0300 Message-ID: <1409255732-28428-1-git-send-email-ivan.khoronzhuk@ti.com> X-Mailer: git-send-email 1.8.3.2 MIME-Version: 1.0 Cc: WingMan Kwok Subject: [U-Boot] [U-boot] [Patch] keystone: usb: add support of usb xhci X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de From: WingMan Kwok Add support of usb xhci. xHCI controls all USB speeds of the Host mode, that is, the SS through the SS PHY, as well as the HS, FS, and LS through the USB2 PHY. xHCI replaces and supersedes all previous host HCIs (HS-only EHCI, FS/LS OHCI and UHCI), and is therefore not backwards compatible with any of them. The USB3SS’s USB Controller is fully compliant with xHC. Acked-by: Vitaly Andrianov Signed-off-by: WingMan Kwok Signed-off-by: Ivan Khoronzhuk --- Based on the series: "[U-boot] [Patch 0/4] keystone2: generalize navigator driver usage" https://www.mail-archive.com/u-boot@lists.denx.de/msg146007.html arch/arm/include/asm/arch-keystone/hardware.h | 6 + arch/arm/include/asm/arch-keystone/xhci-keystone.h | 21 ++ drivers/usb/host/Makefile | 1 + drivers/usb/host/xhci-keystone.c | 329 +++++++++++++++++++++ include/configs/ks2_evm.h | 15 + include/linux/usb/dwc3.h | 8 +- 6 files changed, 379 insertions(+), 1 deletion(-) create mode 100644 arch/arm/include/asm/arch-keystone/xhci-keystone.h create mode 100644 drivers/usb/host/xhci-keystone.c diff --git a/arch/arm/include/asm/arch-keystone/hardware.h b/arch/arm/include/asm/arch-keystone/hardware.h index c3f0f46..fdffb87 100644 --- a/arch/arm/include/asm/arch-keystone/hardware.h +++ b/arch/arm/include/asm/arch-keystone/hardware.h @@ -161,6 +161,12 @@ typedef volatile unsigned int *dv_reg_p; /* MSMC control */ #define KS2_MSMC_CTRL_BASE 0x0bc00000 +/* USB */ +#define KS2_USB_SS_BASE 0x02680000 +#define KS2_USB_HOST_XHCI_BASE (KS2_USB_SS_BASE + 0x10000) +#define KS2_DEV_USB_PHY_BASE 0x02620738 +#define KS2_USB_PHY_CFG_BASE 0x02630000 + #ifdef CONFIG_SOC_K2HK #include #endif diff --git a/arch/arm/include/asm/arch-keystone/xhci-keystone.h b/arch/arm/include/asm/arch-keystone/xhci-keystone.h new file mode 100644 index 0000000..3aab4e0 --- /dev/null +++ b/arch/arm/include/asm/arch-keystone/xhci-keystone.h @@ -0,0 +1,21 @@ +/* + * USB 3.0 DRD Controller + * + * (C) Copyright 2012-2014 + * Texas Instruments Incorporated, + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#define USB3_PHY_REF_SSP_EN BIT(29) +#define USB3_PHY_OTG_VBUSVLDECTSEL BIT(16) + +/* KEYSTONE2 XHCI PHY register structure */ +struct keystone_xhci_phy { + unsigned int phy_utmi; /* ctl0 */ + unsigned int phy_pipe; /* ctl1 */ + unsigned int phy_param_ctrl_1; /* ctl2 */ + unsigned int phy_param_ctrl_2; /* ctl3 */ + unsigned int phy_clock; /* ctl4 */ + unsigned int phy_pll; /* ctl5 */ +}; diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index c4f5157..3d3a0c4 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -43,5 +43,6 @@ obj-$(CONFIG_USB_EHCI_ZYNQ) += ehci-zynq.o # xhci obj-$(CONFIG_USB_XHCI) += xhci.o xhci-mem.o xhci-ring.o +obj-$(CONFIG_USB_XHCI_KEYSTONE) += xhci-keystone.o obj-$(CONFIG_USB_XHCI_EXYNOS) += xhci-exynos5.o obj-$(CONFIG_USB_XHCI_OMAP) += xhci-omap.o diff --git a/drivers/usb/host/xhci-keystone.c b/drivers/usb/host/xhci-keystone.c new file mode 100644 index 0000000..05d338f --- /dev/null +++ b/drivers/usb/host/xhci-keystone.c @@ -0,0 +1,329 @@ +/* + * USB 3.0 DRD Controller + * + * (C) Copyright 2012-2014 + * Texas Instruments Incorporated, + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xhci.h" + +struct kdwc3_irq_regs { + u32 revision; /* 0x000 */ + u32 rsvd0[3]; + u32 sysconfig; /* 0x010 */ + u32 rsvd1[1]; + u32 irq_eoi; + u32 rsvd2[1]; + struct { + u32 raw_status; + u32 status; + u32 enable_set; + u32 enable_clr; + } irqs[16]; +}; + +struct keystone_xhci { + struct xhci_hccr *hcd; + struct dwc3 *dwc3_reg; + struct xhci_hcor *hcor; + struct kdwc3_irq_regs *usbss; + struct keystone_xhci_phy *phy; +}; + +struct keystone_xhci keystone; + +static void keystone_xhci_phy_set(struct keystone_xhci_phy *phy) +{ + u32 val; + + /* + * VBUSVLDEXTSEL has a default value of 1 in BootCfg but shouldn't. + * It should always be cleared because our USB PHY has an onchip VBUS + * analog comparator. + */ + val = readl(&phy->phy_clock); + /* quit selecting the vbusvldextsel by default! */ + val &= ~USB3_PHY_OTG_VBUSVLDECTSEL; + writel(val, &phy->phy_clock); +} + +static void keystone_xhci_phy_unset(struct keystone_xhci_phy *phy) +{ + u32 val; + + /* Disable the PHY REFCLK clock gate */ + val = readl(&phy->phy_clock); + val &= ~USB3_PHY_REF_SSP_EN; + writel(val, &phy->phy_clock); +} + +static void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode) +{ + clrsetbits_le32(&dwc3_reg->g_ctl, + DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG), + DWC3_GCTL_PRTCAPDIR(mode)); +} + +static void dwc3_core_soft_reset(struct dwc3 *dwc3_reg) +{ + /* Before Resetting PHY, put Core in Reset */ + setbits_le32(&dwc3_reg->g_ctl, DWC3_GCTL_CORESOFTRESET); + + /* Assert USB3 PHY reset */ + setbits_le32(&dwc3_reg->g_usb3pipectl[0], DWC3_GUSB3PIPECTL_PHYSOFTRST); + + /* Assert USB2 PHY reset */ + setbits_le32(&dwc3_reg->g_usb2phycfg[0], DWC3_GUSB2PHYCFG_PHYSOFTRST); + + mdelay(100); + + /* Clear USB3 PHY reset */ + clrbits_le32(&dwc3_reg->g_usb3pipectl[0], DWC3_GUSB3PIPECTL_PHYSOFTRST); + + /* Clear USB2 PHY reset */ + clrbits_le32(&dwc3_reg->g_usb2phycfg[0], DWC3_GUSB2PHYCFG_PHYSOFTRST); + + /* After PHYs are stable we can take Core out of reset state */ + clrbits_le32(&dwc3_reg->g_ctl, DWC3_GCTL_CORESOFTRESET); +} + +static int dwc3_core_init(struct dwc3 *dwc3_reg) +{ + u32 revision, val; + unsigned long t_rst; + unsigned int dwc3_hwparams1; + + revision = readl(&dwc3_reg->g_snpsid); + /* This should read as U3 followed by revision number */ + if ((revision & DWC3_GSNPSID_MASK) != 0x55330000) { + puts("this is not a DesignWare USB3 DRD Core\n"); + return -EINVAL; + } + + /* issue device SoftReset too */ + writel(DWC3_DCTL_CSFTRST, &dwc3_reg->d_ctl); + + t_rst = get_timer(0); + do { + val = readl(&dwc3_reg->d_ctl); + if (!(val & DWC3_DCTL_CSFTRST)) + break; + WATCHDOG_RESET(); + } while (get_timer(t_rst) < 500); + + if (val & DWC3_DCTL_CSFTRST) { + debug("Reset timed out\n"); + return -2; + } + + dwc3_core_soft_reset(dwc3_reg); + + dwc3_hwparams1 = readl(&dwc3_reg->g_hwparams1); + + val = readl(&dwc3_reg->g_ctl); + val &= ~DWC3_GCTL_SCALEDOWN_MASK; + val &= ~DWC3_GCTL_DISSCRAMBLE; + switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc3_hwparams1)) { + case DWC3_GHWPARAMS1_EN_PWROPT_CLK: + val &= ~DWC3_GCTL_DSBLCLKGTNG; + break; + default: + printf("No power optimization available\n"); + } + + /* + * WORKAROUND: DWC3 revisions <1.90a have a bug + * where the device can fail to connect at SuperSpeed + * and falls back to high-speed mode which causes + * the device to enter a Connect/Disconnect loop + */ + if ((revision & DWC3_REVISION_MASK) < 0x190a) + val |= DWC3_GCTL_U2RSTECN; + + writel(val, &dwc3_reg->g_ctl); + + return 0; +} + +static int keystone_xhci_core_init(struct dwc3 *dwc3_reg) +{ + int ret; + + ret = dwc3_core_init(dwc3_reg); + if (ret) { + debug("failed to initialize core\n"); + return -EINVAL; + } + + /* We are hard-coding DWC3 core to Host Mode */ + dwc3_set_mode(dwc3_reg, DWC3_GCTL_PRTCAP_HOST); + + return 0; +} + +int xhci_hcd_init(int index, + struct xhci_hccr **ret_hccr, struct xhci_hcor **ret_hcor) +{ + u32 val; + int ret; + struct xhci_hccr *hcd; + struct xhci_hcor *hcor; + struct kdwc3_irq_regs *usbss; + struct keystone_xhci_phy *phy; + + usbss = (struct kdwc3_irq_regs *)CONFIG_USB_SS_BASE; + phy = (struct keystone_xhci_phy *)CONFIG_DEV_USB_PHY_BASE; + + /* Enable the PHY REFCLK clock gate with phy_ref_ssp_en = 1 */ + val = readl(&(phy->phy_clock)); + val |= USB3_PHY_REF_SSP_EN; + writel(val, &phy->phy_clock); + + mdelay(100); + + /* Release USB from reset */ + ret = psc_enable_module(KS2_LPSC_USB); + if (ret) { + puts("Cannot enable USB module"); + return -1; + } + + mdelay(100); + + /* Initialize usb phy */ + keystone_xhci_phy_set(phy); + + /* soft reset usbss */ + writel(1, &usbss->sysconfig); + while (readl(&usbss->sysconfig) & 1) + ; + + val = readl(&usbss->revision); + debug("usbss revision %x\n", val); + + /* Initialize usb core */ + hcd = (struct xhci_hccr *)CONFIG_USB_HOST_XHCI_BASE; + keystone.dwc3_reg = (struct dwc3 *)(CONFIG_USB_HOST_XHCI_BASE + + DWC3_REG_OFFSET); + + keystone_xhci_core_init(keystone.dwc3_reg); + + /* set register addresses */ + hcor = (struct xhci_hcor *)((uint32_t)hcd + + HC_LENGTH(readl(&hcd->cr_capbase))); + + debug("Keystone2-xhci: init hccr %08x and hcor %08x hc_length %d\n", + (u32)hcd, (u32)hcor, + (u32)HC_LENGTH(xhci_readl(&hcd->cr_capbase))); + + keystone.usbss = usbss; + keystone.phy = phy; + keystone.hcd = hcd; + keystone.hcor = hcor; + + *ret_hccr = hcd; + *ret_hcor = hcor; + + return 0; +} + +static int keystone_xhci_phy_suspend(void) +{ + int loop_cnt = 0; + struct xhci_hcor *hcor; + uint32_t *portsc_1 = NULL; + uint32_t *portsc_2 = NULL; + u32 val, usb2_pls, usb3_pls, event_q; + struct dwc3 *dwc3_reg = keystone.dwc3_reg; + + /* set register addresses */ + hcor = keystone.hcor; + + /* Bypass Scrambling and Set Shorter Training sequence for simulation */ + val = DWC3_GCTL_PWRDNSCALE(0x4b0) | DWC3_GCTL_PRTCAPDIR(0x2); + writel(val, &dwc3_reg->g_ctl); + + /* GUSB2PHYCFG */ + val = readl(&dwc3_reg->g_usb2phycfg[0]); + + /* assert bit 6 (SusPhy) */ + val |= DWC3_GUSB2PHYCFG_SUSPHY; + writel(val, &dwc3_reg->g_usb2phycfg[0]); + + /* GUSB3PIPECTL */ + val = readl(&dwc3_reg->g_usb3pipectl[0]); + + /* + * assert bit 29 to allow PHY to go to suspend when idle + * and cause the USB3 SS PHY to enter suspend mode + */ + val |= (BIT(29) | DWC3_GUSB3PIPECTL_SUSPHY); + writel(val, &dwc3_reg->g_usb3pipectl[0]); + + /* + * Steps necessary to allow controller to suspend even when + * VBUS is HIGH: + * - Init DCFG[2:0] (DevSpd) to: 1=FS + * - Init GEVNTADR0 to point to an eventQ + * - Init GEVNTSIZ0 to 0x0100 to specify the size of the eventQ + * - Init DCTL::Run_nStop = 1 + */ + writel(0x00020001, &dwc3_reg->d_cfg); + /* TODO: local2global( (Uint32) eventQ )? */ + writel((u32)&event_q, &dwc3_reg->g_evnt_buf[0].g_evntadrlo); + writel(0, &dwc3_reg->g_evnt_buf[0].g_evntadrhi); + writel(0x4, &dwc3_reg->g_evnt_buf[0].g_evntsiz); + /* Run */ + writel(DWC3_DCTL_RUN_STOP, &dwc3_reg->d_ctl); + + mdelay(100); + + /* Wait for USB2 & USB3 PORTSC::PortLinkState to indicate suspend */ + portsc_1 = (uint32_t *)(&hcor->portregs[0].or_portsc); + portsc_2 = (uint32_t *)(&hcor->portregs[1].or_portsc); + usb2_pls = 0; + usb3_pls = 0; + do { + ++loop_cnt; + usb2_pls = (readl(portsc_1) & PORT_PLS_MASK) >> 5; + usb3_pls = (readl(portsc_2) & PORT_PLS_MASK) >> 5; + } while (((usb2_pls != 0x4) || (usb3_pls != 0x4)) && loop_cnt < 1000); + + if (usb2_pls != 0x4 || usb3_pls != 0x4) { + debug("USB suspend failed - PLS USB2=%02x, USB3=%02x\n", + usb2_pls, usb3_pls); + return -1; + } + + debug("USB2 and USB3 PLS - Disabled, loop_cnt=%d\n", loop_cnt); + return 0; +} + +void xhci_hcd_stop(int index) +{ + /* Disable USB */ + if (keystone_xhci_phy_suspend()) + return; + + if (psc_disable_module(KS2_LPSC_USB)) { + debug("PSC disable module USB failed!\n"); + return; + } + + /* Disable PHY */ + keystone_xhci_phy_unset(keystone.phy); + +/* memset(&keystone, 0, sizeof(struct keystone_xhci)); */ + debug("xhci_hcd_stop OK.\n"); +} diff --git a/include/configs/ks2_evm.h b/include/configs/ks2_evm.h index ef513d4..639f119 100644 --- a/include/configs/ks2_evm.h +++ b/include/configs/ks2_evm.h @@ -185,6 +185,20 @@ "1024k(bootloader)ro,512k(params)ro," \ "-(ubifs)" +/* USB Configuration */ +#define CONFIG_USB_XHCI +#define CONFIG_USB_XHCI_KEYSTONE +#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 2 +#define CONFIG_USB_STORAGE +#define CONFIG_DOS_PARTITION +#define CONFIG_EFI_PARTITION +#define CONFIG_FS_FAT +#define CONFIG_SYS_CACHELINE_SIZE 64 +#define CONFIG_USB_SS_BASE KS2_USB_SS_BASE +#define CONFIG_USB_HOST_XHCI_BASE KS2_USB_HOST_XHCI_BASE +#define CONFIG_DEV_USB_PHY_BASE KS2_DEV_USB_PHY_BASE +#define CONFIG_USB_PHY_CFG_BASE KS2_USB_PHY_CFG_BASE + /* U-Boot command configuration */ #include #define CONFIG_CMD_ASKENV @@ -198,6 +212,7 @@ #define CONFIG_CMD_UBIFS #define CONFIG_CMD_SF #define CONFIG_CMD_EEPROM +#define CONFIG_CMD_USB /* U-Boot general configuration */ #define CONFIG_SYS_GENERIC_BOARD diff --git a/include/linux/usb/dwc3.h b/include/linux/usb/dwc3.h index 97d179a..7edc760 100644 --- a/include/linux/usb/dwc3.h +++ b/include/linux/usb/dwc3.h @@ -41,7 +41,8 @@ #define DWC3_REG_OFFSET 0xC100 struct g_event_buffer { - u64 g_evntadr; + u32 g_evntadrlo; + u32 g_evntadrhi; u32 g_evntsiz; u32 g_evntcount; }; @@ -185,4 +186,9 @@ struct dwc3 { /* offset: 0xC100 */ #define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff) #define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000) +/* Device Control Register */ +#define DWC3_DCTL_RUN_STOP (1 << 31) +#define DWC3_DCTL_CSFTRST (1 << 30) +#define DWC3_DCTL_LSFTRST (1 << 29) + #endif /* __DWC3_H_ */