xref: /rk3399_rockchip-uboot/drivers/usb/host/xhci-omap.c (revision 26707d9e6bb0d2e5e6de706cd68bddcea34e731f)
12d2358acSDan Murphy /*
22d2358acSDan Murphy  * OMAP USB HOST xHCI Controller
32d2358acSDan Murphy  *
42d2358acSDan Murphy  * (C) Copyright 2013
52d2358acSDan Murphy  * Texas Instruments, <www.ti.com>
62d2358acSDan Murphy  *
72d2358acSDan Murphy  * Author: Dan Murphy <dmurphy@ti.com>
82d2358acSDan Murphy  *
92d2358acSDan Murphy  * SPDX-License-Identifier:	GPL-2.0+
102d2358acSDan Murphy  */
112d2358acSDan Murphy 
122d2358acSDan Murphy #include <common.h>
132d2358acSDan Murphy #include <usb.h>
142d2358acSDan Murphy #include <asm-generic/errno.h>
152d2358acSDan Murphy #include <asm/omap_common.h>
162d2358acSDan Murphy #include <asm/arch/cpu.h>
172d2358acSDan Murphy #include <asm/arch/sys_proto.h>
182d2358acSDan Murphy 
192d2358acSDan Murphy #include <linux/compat.h>
202d2358acSDan Murphy #include <linux/usb/dwc3.h>
2141b667b8SDan Murphy #include <linux/usb/xhci-omap.h>
222d2358acSDan Murphy 
232d2358acSDan Murphy #include "xhci.h"
242d2358acSDan Murphy 
252d2358acSDan Murphy /* Declare global data pointer */
262d2358acSDan Murphy DECLARE_GLOBAL_DATA_PTR;
272d2358acSDan Murphy 
282d2358acSDan Murphy static struct omap_xhci omap;
292d2358acSDan Murphy 
307e575c46STroy Kisky inline int __board_usb_init(int index, enum usb_init_type init)
312d2358acSDan Murphy {
322d2358acSDan Murphy 	return 0;
332d2358acSDan Murphy }
347e575c46STroy Kisky int board_usb_init(int index, enum usb_init_type init)
35b2168211SDan Murphy 	__attribute__((weak, alias("__board_usb_init")));
362d2358acSDan Murphy 
372d2358acSDan Murphy static void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode)
382d2358acSDan Murphy {
392d2358acSDan Murphy 	clrsetbits_le32(&dwc3_reg->g_ctl,
402d2358acSDan Murphy 			DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG),
412d2358acSDan Murphy 			DWC3_GCTL_PRTCAPDIR(mode));
422d2358acSDan Murphy }
432d2358acSDan Murphy 
442d2358acSDan Murphy static void dwc3_core_soft_reset(struct dwc3 *dwc3_reg)
452d2358acSDan Murphy {
462d2358acSDan Murphy 	/* Before Resetting PHY, put Core in Reset */
472d2358acSDan Murphy 	setbits_le32(&dwc3_reg->g_ctl, DWC3_GCTL_CORESOFTRESET);
482d2358acSDan Murphy 
49ba55453cSDan Murphy 	omap_reset_usb_phy(dwc3_reg);
502d2358acSDan Murphy 
512d2358acSDan Murphy 	/* After PHYs are stable we can take Core out of reset state */
522d2358acSDan Murphy 	clrbits_le32(&dwc3_reg->g_ctl, DWC3_GCTL_CORESOFTRESET);
532d2358acSDan Murphy }
542d2358acSDan Murphy 
552d2358acSDan Murphy static int dwc3_core_init(struct dwc3 *dwc3_reg)
562d2358acSDan Murphy {
572d2358acSDan Murphy 	u32 reg;
582d2358acSDan Murphy 	u32 revision;
592d2358acSDan Murphy 	unsigned int dwc3_hwparams1;
602d2358acSDan Murphy 
612d2358acSDan Murphy 	revision = readl(&dwc3_reg->g_snpsid);
622d2358acSDan Murphy 	/* This should read as U3 followed by revision number */
632d2358acSDan Murphy 	if ((revision & DWC3_GSNPSID_MASK) != 0x55330000) {
642d2358acSDan Murphy 		puts("this is not a DesignWare USB3 DRD Core\n");
652d2358acSDan Murphy 		return -1;
662d2358acSDan Murphy 	}
672d2358acSDan Murphy 
682d2358acSDan Murphy 	dwc3_core_soft_reset(dwc3_reg);
692d2358acSDan Murphy 
702d2358acSDan Murphy 	dwc3_hwparams1 = readl(&dwc3_reg->g_hwparams1);
712d2358acSDan Murphy 
722d2358acSDan Murphy 	reg = readl(&dwc3_reg->g_ctl);
732d2358acSDan Murphy 	reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
742d2358acSDan Murphy 	reg &= ~DWC3_GCTL_DISSCRAMBLE;
752d2358acSDan Murphy 	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc3_hwparams1)) {
762d2358acSDan Murphy 	case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
772d2358acSDan Murphy 		reg &= ~DWC3_GCTL_DSBLCLKGTNG;
782d2358acSDan Murphy 		break;
792d2358acSDan Murphy 	default:
802d2358acSDan Murphy 		debug("No power optimization available\n");
812d2358acSDan Murphy 	}
822d2358acSDan Murphy 
832d2358acSDan Murphy 	/*
842d2358acSDan Murphy 	 * WORKAROUND: DWC3 revisions <1.90a have a bug
852d2358acSDan Murphy 	 * where the device can fail to connect at SuperSpeed
862d2358acSDan Murphy 	 * and falls back to high-speed mode which causes
872d2358acSDan Murphy 	 * the device to enter a Connect/Disconnect loop
882d2358acSDan Murphy 	 */
892d2358acSDan Murphy 	if ((revision & DWC3_REVISION_MASK) < 0x190a)
902d2358acSDan Murphy 		reg |= DWC3_GCTL_U2RSTECN;
912d2358acSDan Murphy 
922d2358acSDan Murphy 	writel(reg, &dwc3_reg->g_ctl);
932d2358acSDan Murphy 
942d2358acSDan Murphy 	return 0;
952d2358acSDan Murphy }
962d2358acSDan Murphy 
972d2358acSDan Murphy static int omap_xhci_core_init(struct omap_xhci *omap)
982d2358acSDan Murphy {
992d2358acSDan Murphy 	int ret = 0;
1002d2358acSDan Murphy 
101*26707d9eSFelipe Balbi 	usb_phy_power(1);
102834e91afSDan Murphy 	omap_enable_phy(omap);
1032d2358acSDan Murphy 
1042d2358acSDan Murphy 	ret = dwc3_core_init(omap->dwc3_reg);
1052d2358acSDan Murphy 	if (ret) {
1062d2358acSDan Murphy 		debug("%s:failed to initialize core\n", __func__);
1072d2358acSDan Murphy 		return ret;
1082d2358acSDan Murphy 	}
1092d2358acSDan Murphy 
1102d2358acSDan Murphy 	/* We are hard-coding DWC3 core to Host Mode */
1112d2358acSDan Murphy 	dwc3_set_mode(omap->dwc3_reg, DWC3_GCTL_PRTCAP_HOST);
1122d2358acSDan Murphy 
1132d2358acSDan Murphy 	return ret;
1142d2358acSDan Murphy }
1152d2358acSDan Murphy 
1162d2358acSDan Murphy static void omap_xhci_core_exit(struct omap_xhci *omap)
1172d2358acSDan Murphy {
118834e91afSDan Murphy 	usb_phy_power(0);
1192d2358acSDan Murphy }
1202d2358acSDan Murphy 
1212d2358acSDan Murphy int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
1222d2358acSDan Murphy {
1232d2358acSDan Murphy 	struct omap_xhci *ctx = &omap;
1242d2358acSDan Murphy 	int ret = 0;
1252d2358acSDan Murphy 
1262d2358acSDan Murphy 	ctx->hcd = (struct xhci_hccr *)OMAP_XHCI_BASE;
1272d2358acSDan Murphy 	ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET);
1282d2358acSDan Murphy 	ctx->usb3_phy = (struct omap_usb3_phy *)OMAP_OCP1_SCP_BASE;
1292d2358acSDan Murphy 	ctx->otg_wrapper = (struct omap_dwc_wrapper *)OMAP_OTG_WRAPPER_BASE;
1302d2358acSDan Murphy 
131b2168211SDan Murphy 	ret = board_usb_init(index, USB_INIT_HOST);
1322d2358acSDan Murphy 	if (ret != 0) {
1332d2358acSDan Murphy 		puts("Failed to initialize board for USB\n");
1342d2358acSDan Murphy 		return ret;
1352d2358acSDan Murphy 	}
1362d2358acSDan Murphy 
1372d2358acSDan Murphy 	ret = omap_xhci_core_init(ctx);
1382d2358acSDan Murphy 	if (ret < 0) {
1392d2358acSDan Murphy 		puts("Failed to initialize xhci\n");
1402d2358acSDan Murphy 		return ret;
1412d2358acSDan Murphy 	}
1422d2358acSDan Murphy 
1432d2358acSDan Murphy 	*hccr = (struct xhci_hccr *)(OMAP_XHCI_BASE);
1442d2358acSDan Murphy 	*hcor = (struct xhci_hcor *)((uint32_t) *hccr
1452d2358acSDan Murphy 				+ HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
1462d2358acSDan Murphy 
1472d2358acSDan Murphy 	debug("omap-xhci: init hccr %x and hcor %x hc_length %d\n",
1482d2358acSDan Murphy 	      (uint32_t)*hccr, (uint32_t)*hcor,
1492d2358acSDan Murphy 	      (uint32_t)HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
1502d2358acSDan Murphy 
1512d2358acSDan Murphy 	return ret;
1522d2358acSDan Murphy }
1532d2358acSDan Murphy 
1542d2358acSDan Murphy void xhci_hcd_stop(int index)
1552d2358acSDan Murphy {
1562d2358acSDan Murphy 	struct omap_xhci *ctx = &omap;
1572d2358acSDan Murphy 
1582d2358acSDan Murphy 	omap_xhci_core_exit(ctx);
1592d2358acSDan Murphy }
160