xref: /openbmc/u-boot/drivers/usb/host/xhci-fsl.c (revision 707c866f)
1ba92ee06SRamneek Mehresh /*
2*707c866fSRajesh Bhagat  * Copyright 2015,2016 Freescale Semiconductor, Inc.
3ba92ee06SRamneek Mehresh  *
4ba92ee06SRamneek Mehresh  * FSL USB HOST xHCI Controller
5ba92ee06SRamneek Mehresh  *
6ba92ee06SRamneek Mehresh  * Author: Ramneek Mehresh<ramneek.mehresh@freescale.com>
7ba92ee06SRamneek Mehresh  *
8ba92ee06SRamneek Mehresh  * SPDX-License-Identifier:	GPL-2.0+
9ba92ee06SRamneek Mehresh  */
10ba92ee06SRamneek Mehresh 
11ba92ee06SRamneek Mehresh #include <common.h>
12ba92ee06SRamneek Mehresh #include <usb.h>
13ba92ee06SRamneek Mehresh #include <asm-generic/errno.h>
14ba92ee06SRamneek Mehresh #include <linux/compat.h>
15ba92ee06SRamneek Mehresh #include <linux/usb/xhci-fsl.h>
16ba92ee06SRamneek Mehresh #include <linux/usb/dwc3.h>
17ba92ee06SRamneek Mehresh #include "xhci.h"
18ef53b8c4SSriram Dash #include <fsl_errata.h>
19ef53b8c4SSriram Dash #include <fsl_usb.h>
20*707c866fSRajesh Bhagat #include <dm.h>
21ba92ee06SRamneek Mehresh 
22ba92ee06SRamneek Mehresh /* Declare global data pointer */
23ba92ee06SRamneek Mehresh DECLARE_GLOBAL_DATA_PTR;
24ba92ee06SRamneek Mehresh 
25*707c866fSRajesh Bhagat #ifndef CONFIG_DM_USB
26ba92ee06SRamneek Mehresh static struct fsl_xhci fsl_xhci;
27ba92ee06SRamneek Mehresh unsigned long ctr_addr[] = FSL_USB_XHCI_ADDR;
28*707c866fSRajesh Bhagat #else
29*707c866fSRajesh Bhagat struct xhci_fsl_priv {
30*707c866fSRajesh Bhagat 	struct xhci_ctrl xhci;
31*707c866fSRajesh Bhagat 	fdt_addr_t hcd_base;
32*707c866fSRajesh Bhagat 	struct fsl_xhci ctx;
33*707c866fSRajesh Bhagat };
34*707c866fSRajesh Bhagat #endif
35ba92ee06SRamneek Mehresh 
36ba92ee06SRamneek Mehresh __weak int __board_usb_init(int index, enum usb_init_type init)
37ba92ee06SRamneek Mehresh {
38ba92ee06SRamneek Mehresh 	return 0;
39ba92ee06SRamneek Mehresh }
40ba92ee06SRamneek Mehresh 
41ef53b8c4SSriram Dash static int erratum_a008751(void)
42ef53b8c4SSriram Dash {
43ef53b8c4SSriram Dash #if defined(CONFIG_TARGET_LS2080AQDS) || defined(CONFIG_TARGET_LS2080ARDB)
44ef53b8c4SSriram Dash 	u32 __iomem *scfg = (u32 __iomem *)SCFG_BASE;
45ef53b8c4SSriram Dash 	writel(SCFG_USB3PRM1CR_INIT, scfg + SCFG_USB3PRM1CR / 4);
46ef53b8c4SSriram Dash 	return 0;
47ef53b8c4SSriram Dash #endif
48ef53b8c4SSriram Dash 	return 1;
49ef53b8c4SSriram Dash }
50ef53b8c4SSriram Dash 
51ef53b8c4SSriram Dash static void fsl_apply_xhci_errata(void)
52ef53b8c4SSriram Dash {
53ef53b8c4SSriram Dash 	int ret;
54ef53b8c4SSriram Dash 	if (has_erratum_a008751()) {
55ef53b8c4SSriram Dash 		ret = erratum_a008751();
56ef53b8c4SSriram Dash 		if (ret != 0)
57ef53b8c4SSriram Dash 			puts("Failed to apply erratum a008751\n");
58ef53b8c4SSriram Dash 	}
59ef53b8c4SSriram Dash }
60ef53b8c4SSriram Dash 
61ba92ee06SRamneek Mehresh static int fsl_xhci_core_init(struct fsl_xhci *fsl_xhci)
62ba92ee06SRamneek Mehresh {
63ba92ee06SRamneek Mehresh 	int ret = 0;
64ba92ee06SRamneek Mehresh 
65ba92ee06SRamneek Mehresh 	ret = dwc3_core_init(fsl_xhci->dwc3_reg);
66ba92ee06SRamneek Mehresh 	if (ret) {
67ba92ee06SRamneek Mehresh 		debug("%s:failed to initialize core\n", __func__);
68ba92ee06SRamneek Mehresh 		return ret;
69ba92ee06SRamneek Mehresh 	}
70ba92ee06SRamneek Mehresh 
71ba92ee06SRamneek Mehresh 	/* We are hard-coding DWC3 core to Host Mode */
72ba92ee06SRamneek Mehresh 	dwc3_set_mode(fsl_xhci->dwc3_reg, DWC3_GCTL_PRTCAP_HOST);
73ba92ee06SRamneek Mehresh 
74667f4dd9SNikhil Badola 	/* Set GFLADJ_30MHZ as 20h as per XHCI spec default value */
75667f4dd9SNikhil Badola 	dwc3_set_fladj(fsl_xhci->dwc3_reg, GFLADJ_30MHZ_DEFAULT);
76667f4dd9SNikhil Badola 
77ba92ee06SRamneek Mehresh 	return ret;
78ba92ee06SRamneek Mehresh }
79ba92ee06SRamneek Mehresh 
80ba92ee06SRamneek Mehresh static int fsl_xhci_core_exit(struct fsl_xhci *fsl_xhci)
81ba92ee06SRamneek Mehresh {
82ba92ee06SRamneek Mehresh 	/*
83ba92ee06SRamneek Mehresh 	 * Currently fsl socs do not support PHY shutdown from
84ba92ee06SRamneek Mehresh 	 * sw. But this support may be added in future socs.
85ba92ee06SRamneek Mehresh 	 */
86ba92ee06SRamneek Mehresh 	return 0;
87ba92ee06SRamneek Mehresh }
88ba92ee06SRamneek Mehresh 
89*707c866fSRajesh Bhagat #ifdef CONFIG_DM_USB
90*707c866fSRajesh Bhagat static int xhci_fsl_probe(struct udevice *dev)
91*707c866fSRajesh Bhagat {
92*707c866fSRajesh Bhagat 	struct xhci_fsl_priv *priv = dev_get_priv(dev);
93*707c866fSRajesh Bhagat 	struct xhci_hccr *hccr;
94*707c866fSRajesh Bhagat 	struct xhci_hcor *hcor;
95*707c866fSRajesh Bhagat 
96*707c866fSRajesh Bhagat 	int ret = 0;
97*707c866fSRajesh Bhagat 
98*707c866fSRajesh Bhagat 	/*
99*707c866fSRajesh Bhagat 	 * Get the base address for XHCI controller from the device node
100*707c866fSRajesh Bhagat 	 */
101*707c866fSRajesh Bhagat 	priv->hcd_base = dev_get_addr(dev);
102*707c866fSRajesh Bhagat 	if (priv->hcd_base == FDT_ADDR_T_NONE) {
103*707c866fSRajesh Bhagat 		debug("Can't get the XHCI register base address\n");
104*707c866fSRajesh Bhagat 		return -ENXIO;
105*707c866fSRajesh Bhagat 	}
106*707c866fSRajesh Bhagat 	priv->ctx.hcd = (struct xhci_hccr *)priv->hcd_base;
107*707c866fSRajesh Bhagat 	priv->ctx.dwc3_reg = (struct dwc3 *)((char *)(priv->hcd_base) +
108*707c866fSRajesh Bhagat 			  DWC3_REG_OFFSET);
109*707c866fSRajesh Bhagat 
110*707c866fSRajesh Bhagat 	fsl_apply_xhci_errata();
111*707c866fSRajesh Bhagat 
112*707c866fSRajesh Bhagat 	ret = fsl_xhci_core_init(&priv->ctx);
113*707c866fSRajesh Bhagat 	if (ret < 0) {
114*707c866fSRajesh Bhagat 		puts("Failed to initialize xhci\n");
115*707c866fSRajesh Bhagat 		return ret;
116*707c866fSRajesh Bhagat 	}
117*707c866fSRajesh Bhagat 
118*707c866fSRajesh Bhagat 	hccr = (struct xhci_hccr *)(priv->ctx.hcd);
119*707c866fSRajesh Bhagat 	hcor = (struct xhci_hcor *)((uintptr_t) hccr
120*707c866fSRajesh Bhagat 				+ HC_LENGTH(xhci_readl(&hccr->cr_capbase)));
121*707c866fSRajesh Bhagat 
122*707c866fSRajesh Bhagat 	debug("xhci-fsl: init hccr %lx and hcor %lx hc_length %lx\n",
123*707c866fSRajesh Bhagat 	      (uintptr_t)hccr, (uintptr_t)hcor,
124*707c866fSRajesh Bhagat 	      (uintptr_t)HC_LENGTH(xhci_readl(&hccr->cr_capbase)));
125*707c866fSRajesh Bhagat 
126*707c866fSRajesh Bhagat 	return xhci_register(dev, hccr, hcor);
127*707c866fSRajesh Bhagat }
128*707c866fSRajesh Bhagat 
129*707c866fSRajesh Bhagat static int xhci_fsl_remove(struct udevice *dev)
130*707c866fSRajesh Bhagat {
131*707c866fSRajesh Bhagat 	struct xhci_fsl_priv *priv = dev_get_priv(dev);
132*707c866fSRajesh Bhagat 	int ret;
133*707c866fSRajesh Bhagat 
134*707c866fSRajesh Bhagat 	fsl_xhci_core_exit(&priv->ctx);
135*707c866fSRajesh Bhagat 
136*707c866fSRajesh Bhagat 	ret = xhci_deregister(dev);
137*707c866fSRajesh Bhagat 	if (ret)
138*707c866fSRajesh Bhagat 		return ret;
139*707c866fSRajesh Bhagat 
140*707c866fSRajesh Bhagat 	return 0;
141*707c866fSRajesh Bhagat }
142*707c866fSRajesh Bhagat 
143*707c866fSRajesh Bhagat static const struct udevice_id xhci_usb_ids[] = {
144*707c866fSRajesh Bhagat 	{ .compatible = "fsl,layerscape-dwc3", },
145*707c866fSRajesh Bhagat 	{ }
146*707c866fSRajesh Bhagat };
147*707c866fSRajesh Bhagat 
148*707c866fSRajesh Bhagat U_BOOT_DRIVER(xhci_fsl) = {
149*707c866fSRajesh Bhagat 	.name	= "xhci_fsl",
150*707c866fSRajesh Bhagat 	.id	= UCLASS_USB,
151*707c866fSRajesh Bhagat 	.of_match = xhci_usb_ids,
152*707c866fSRajesh Bhagat 	.probe = xhci_fsl_probe,
153*707c866fSRajesh Bhagat 	.remove = xhci_fsl_remove,
154*707c866fSRajesh Bhagat 	.ops	= &xhci_usb_ops,
155*707c866fSRajesh Bhagat 	.platdata_auto_alloc_size = sizeof(struct usb_platdata),
156*707c866fSRajesh Bhagat 	.priv_auto_alloc_size = sizeof(struct xhci_fsl_priv),
157*707c866fSRajesh Bhagat 	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
158*707c866fSRajesh Bhagat };
159*707c866fSRajesh Bhagat #else
160ba92ee06SRamneek Mehresh int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
161ba92ee06SRamneek Mehresh {
162ba92ee06SRamneek Mehresh 	struct fsl_xhci *ctx = &fsl_xhci;
163ba92ee06SRamneek Mehresh 	int ret = 0;
164ba92ee06SRamneek Mehresh 
165ba92ee06SRamneek Mehresh 	ctx->hcd = (struct xhci_hccr *)ctr_addr[index];
166ba92ee06SRamneek Mehresh 	ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET);
167ba92ee06SRamneek Mehresh 
168ba92ee06SRamneek Mehresh 	ret = board_usb_init(index, USB_INIT_HOST);
169ba92ee06SRamneek Mehresh 	if (ret != 0) {
170ba92ee06SRamneek Mehresh 		puts("Failed to initialize board for USB\n");
171ba92ee06SRamneek Mehresh 		return ret;
172ba92ee06SRamneek Mehresh 	}
173ba92ee06SRamneek Mehresh 
174ef53b8c4SSriram Dash 	fsl_apply_xhci_errata();
175ef53b8c4SSriram Dash 
176ba92ee06SRamneek Mehresh 	ret = fsl_xhci_core_init(ctx);
177ba92ee06SRamneek Mehresh 	if (ret < 0) {
178ba92ee06SRamneek Mehresh 		puts("Failed to initialize xhci\n");
179ba92ee06SRamneek Mehresh 		return ret;
180ba92ee06SRamneek Mehresh 	}
181ba92ee06SRamneek Mehresh 
182ba92ee06SRamneek Mehresh 	*hccr = (struct xhci_hccr *)ctx->hcd;
1837e5a32fcSNikhil Badola 	*hcor = (struct xhci_hcor *)((uintptr_t) *hccr
184ba92ee06SRamneek Mehresh 				+ HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
185ba92ee06SRamneek Mehresh 
1867e5a32fcSNikhil Badola 	debug("fsl-xhci: init hccr %lx and hcor %lx hc_length %lx\n",
1877e5a32fcSNikhil Badola 	      (uintptr_t)*hccr, (uintptr_t)*hcor,
1887e5a32fcSNikhil Badola 	      (uintptr_t)HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
189ba92ee06SRamneek Mehresh 
190ba92ee06SRamneek Mehresh 	return ret;
191ba92ee06SRamneek Mehresh }
192ba92ee06SRamneek Mehresh 
193ba92ee06SRamneek Mehresh void xhci_hcd_stop(int index)
194ba92ee06SRamneek Mehresh {
195ba92ee06SRamneek Mehresh 	struct fsl_xhci *ctx = &fsl_xhci;
196ba92ee06SRamneek Mehresh 
197ba92ee06SRamneek Mehresh 	fsl_xhci_core_exit(ctx);
198ba92ee06SRamneek Mehresh }
199*707c866fSRajesh Bhagat #endif
200