diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 6183b80c75..2ac3efaa26 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -63,6 +63,6 @@ obj-$(CONFIG_USB_XHCI_FSL) += xhci-fsl.o obj-$(CONFIG_USB_XHCI_OMAP) += xhci-omap.o obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o obj-$(CONFIG_USB_XHCI_UNIPHIER) += xhci-uniphier.o - +obj-$(CONFIG_IPQ40XX_USB) += xhci-ipq40xx.o # designware obj-$(CONFIG_USB_DWC2) += dwc2.o diff --git a/drivers/usb/host/xhci-ipq40xx.c b/drivers/usb/host/xhci-ipq40xx.c new file mode 100644 index 0000000000..7f84942763 --- /dev/null +++ b/drivers/usb/host/xhci-ipq40xx.c @@ -0,0 +1,232 @@ +/* + * Copyright 2015 Freescale Semiconductor, Inc. + * + * DWC3 controller driver + * + * Author: Ramneek Mehresh + * + * SPDX-License-Identifier: GPL-2.0+ + + * Copyright (c) 2014, 2015 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include "xhci.h" + +#define IPQ_XHCI_COUNT 0x2 +#define IPQ_XHCI_BASE_1 0x8A00000 +#define IPQ_XHCI_BASE_2 0x6000000 +#define GCC_USB_RST_CTRL_1 0x181E038 +#define GCC_USB_RST_CTRL_2 0x181E01C + +struct ipq_xhci { + struct xhci_hccr *hcd; + struct dwc3 *dwc3_reg; + unsigned int *gcc_rst_ctrl; +}; +static struct ipq_xhci ipq[IPQ_XHCI_COUNT]; + +inline int __board_usb_init(int index, enum usb_init_type init) +{ + return 0; +} + +int board_usb_init(int index, enum usb_init_type init) + __attribute__((weak, alias("__board_usb_init"))); + +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)); +} + +void ipq_reset_usb_phy(unsigned int *gcc_rst_ctrl) +{ + /* assert HS PHY POR reset */ + setbits_le32(gcc_rst_ctrl, 0x10); + mdelay(10); + + /* assert HS PHY SRIF reset */ + setbits_le32(gcc_rst_ctrl, 0x4); + mdelay(10); + + /* deassert HS PHY SRIF reset and program HS PHY registers */ + clrbits_le32(gcc_rst_ctrl, 0x4); + mdelay(10); + + /* de-assert USB3 HS PHY POR reset */ + clrbits_le32(gcc_rst_ctrl, 0x10); + mdelay(10); + + if (gcc_rst_ctrl == (unsigned int*)GCC_USB_RST_CTRL_1) { + /* assert SS PHY POR reset */ + setbits_le32(gcc_rst_ctrl, 0x20); + mdelay(10); + + /* deassert SS PHY POR reset */ + clrbits_le32(gcc_rst_ctrl, 0x20); + } +} + +void dwc3_reset_usb_phy(struct dwc3 *dwc3_reg, unsigned int *gcc_rst_ctrl) +{ + /* Assert USB3 PHY reset */ + setbits_le32(&dwc3_reg->g_usb3pipectl[0], DWC3_GUSB3PIPECTL_PHYSOFTRST); + + /* Assert USB2 PHY reset */ + setbits_le32(&dwc3_reg->g_usb2phycfg, DWC3_GUSB2PHYCFG_PHYSOFTRST); + + mdelay(100); + + ipq_reset_usb_phy(gcc_rst_ctrl); + + 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, DWC3_GUSB2PHYCFG_PHYSOFTRST); +} + +static void dwc3_core_soft_reset(struct dwc3 *dwc3_reg, unsigned int *gcc_rst_ctrl) +{ + /* Before Resetting PHY, put Core in Reset */ + setbits_le32(&dwc3_reg->g_ctl, DWC3_GCTL_CORESOFTRESET); + + dwc3_reset_usb_phy(dwc3_reg, gcc_rst_ctrl); + + /* 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, unsigned int *gcc_rst_ctrl) +{ + u32 reg; + u32 revision; + 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 -1; + } + + dwc3_core_soft_reset(dwc3_reg, gcc_rst_ctrl); + + dwc3_hwparams1 = readl(&dwc3_reg->g_hwparams1); + + reg = readl(&dwc3_reg->g_ctl); + reg &= ~DWC3_GCTL_SCALEDOWN_MASK; + reg &= ~DWC3_GCTL_DISSCRAMBLE; + switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc3_hwparams1)) { + case DWC3_GHWPARAMS1_EN_PWROPT_CLK: + reg &= ~DWC3_GCTL_DSBLCLKGTNG; + break; + default: + debug("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) + reg |= DWC3_GCTL_U2RSTECN; + + writel(reg, &dwc3_reg->g_ctl); + + return 0; +} + +static int ipq_xhci_core_init(struct ipq_xhci *ipq, unsigned int ipq_base) +{ + int ret = 0; + + ret = dwc3_core_init(ipq->dwc3_reg, ipq->gcc_rst_ctrl); + if (ret) { + debug("%s:failed to initialize core\n", __func__); + return ret; + } + + /* We are hard-coding DWC3 core to Host Mode */ + dwc3_set_mode(ipq->dwc3_reg, DWC3_GCTL_PRTCAP_HOST); + + return ret; +} + +static void ipq_xhci_core_exit(struct ipq_xhci *ipq) +{ + +} + +int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor) +{ + struct ipq_xhci *ctx; + unsigned int ipq_base; + int ret = 0; + + if (index >= IPQ_XHCI_COUNT) + return -1; + + if (index == 0) { + ctx = &ipq[0]; + ipq_base = IPQ_XHCI_BASE_1; + ctx->gcc_rst_ctrl = (unsigned int*)GCC_USB_RST_CTRL_1; + } else { + ctx = &ipq[1]; + ipq_base = IPQ_XHCI_BASE_2; + ctx->gcc_rst_ctrl = (unsigned int*)GCC_USB_RST_CTRL_2; + } + + ctx->hcd = (struct xhci_hccr *)ipq_base; + ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET); + + ret = board_usb_init(index, USB_INIT_HOST); + if (ret != 0) { + puts("Failed to initialize board for USB\n"); + return ret; + } + + ret = ipq_xhci_core_init(ctx, ipq_base); + if (ret < 0) { + puts("Failed to initialize xhci\n"); + return ret; + } + + *hccr = (struct xhci_hccr *)(ipq_base); + *hcor = (struct xhci_hcor *)((uint32_t) *hccr + + HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase))); + + debug("ipq-xhci: init hccr %x and hcor %x hc_length %d\n", + (uint32_t)*hccr, (uint32_t)*hcor, + (uint32_t)HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase))); + + return ret; +} + +void xhci_hcd_stop(int index) +{ + if (index >= IPQ_XHCI_COUNT) { + debug("ipq-xhci: index greater than xhci count\n"); + return; + } + + ipq_xhci_core_exit(&ipq[index]); +} diff --git a/include/configs/ipq40xx.h b/include/configs/ipq40xx.h index 8ab9e2c1e3..1434437dd5 100644 --- a/include/configs/ipq40xx.h +++ b/include/configs/ipq40xx.h @@ -30,7 +30,6 @@ #define CONFIG_SYS_CACHELINE_SIZE 64 #define CONFIG_SKIP_LOWLEVEL_INIT #define CONFIG_SYS_HZ 1000 - #define CONFIG_IPQ40XX_UART #define CONFIG_CONS_INDEX 1 @@ -43,6 +42,7 @@ #define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + \ sizeof(CONFIG_SYS_PROMPT) + 16) +#define HAVE_BLOCK_DEVICE #define CONFIG_SYS_SDRAM_BASE 0x80000000 #define CONFIG_SYS_TEXT_BASE 0x87300000 #define CONFIG_SYS_SDRAM_SIZE 0x10000000 @@ -110,6 +110,16 @@ typedef struct { #define CONFIG_SYS_HUSH_PARSER #define CONFIG_SYS_NULLDEV +#define CONFIG_IPQ40XX_USB +#ifdef CONFIG_IPQ40XX_USB +#define CONFIG_USB_XHCI +#define CONFIG_CMD_USB +#define CONFIG_DOS_PARTITION +#define CONFIG_USB_STORAGE +#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 2 +#define CONFIG_USB_MAX_CONTROLLER_COUNT 2 +#endif + /* L1 cache line size is 64 bytes, L2 cache line size is 128 bytes * Cache flush and invalidation based on L1 cache, so the cache line * size is configured to 64 */ diff --git a/include/configs/ipq807x.h b/include/configs/ipq807x.h index 30cd2958b7..31a13d56ac 100644 --- a/include/configs/ipq807x.h +++ b/include/configs/ipq807x.h @@ -42,6 +42,7 @@ #define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE_MAX + (256 << 10)) #define CONFIG_ENV_IS_NOWHERE 1 +#define HAVE_BLOCK_DEVICE /* * Size of malloc() pool */ @@ -145,6 +146,16 @@ #define CONFIG_CMD_BOOTZ +#define CONFIG_IPQ40XX_USB +#ifdef CONFIG_IPQ40XX_USB +#define CONFIG_USB_XHCI +#define CONFIG_CMD_USB +#define CONFIG_DOS_PARTITION +#define CONFIG_USB_STORAGE +#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 2 +#define CONFIG_USB_MAX_CONTROLLER_COUNT 2 +#endif + /* L1 cache line size is 64 bytes, L2 cache line size is 128 bytes * Cache flush and invalidation based on L1 cache, so the cache line * size is configured to 64 */