xref: /openbmc/u-boot/drivers/usb/host/xhci-fsl.c (revision 9450ab2b)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2ba92ee06SRamneek Mehresh /*
3707c866fSRajesh Bhagat  * Copyright 2015,2016 Freescale Semiconductor, Inc.
4ba92ee06SRamneek Mehresh  *
5ba92ee06SRamneek Mehresh  * FSL USB HOST xHCI Controller
6ba92ee06SRamneek Mehresh  *
7ba92ee06SRamneek Mehresh  * Author: Ramneek Mehresh<ramneek.mehresh@freescale.com>
8ba92ee06SRamneek Mehresh  */
9ba92ee06SRamneek Mehresh 
10ba92ee06SRamneek Mehresh #include <common.h>
11ba92ee06SRamneek Mehresh #include <usb.h>
125d97dff0SMasahiro Yamada #include <linux/errno.h>
13ba92ee06SRamneek Mehresh #include <linux/compat.h>
14ba92ee06SRamneek Mehresh #include <linux/usb/xhci-fsl.h>
15ba92ee06SRamneek Mehresh #include <linux/usb/dwc3.h>
16ba92ee06SRamneek Mehresh #include "xhci.h"
17ef53b8c4SSriram Dash #include <fsl_errata.h>
18ef53b8c4SSriram Dash #include <fsl_usb.h>
19707c866fSRajesh Bhagat #include <dm.h>
20ba92ee06SRamneek Mehresh 
21ba92ee06SRamneek Mehresh /* Declare global data pointer */
22*fd09c205SSven Schwermer #if !CONFIG_IS_ENABLED(DM_USB)
23ba92ee06SRamneek Mehresh static struct fsl_xhci fsl_xhci;
24ba92ee06SRamneek Mehresh unsigned long ctr_addr[] = FSL_USB_XHCI_ADDR;
25707c866fSRajesh Bhagat #else
26707c866fSRajesh Bhagat struct xhci_fsl_priv {
27707c866fSRajesh Bhagat 	struct xhci_ctrl xhci;
28707c866fSRajesh Bhagat 	fdt_addr_t hcd_base;
29707c866fSRajesh Bhagat 	struct fsl_xhci ctx;
30707c866fSRajesh Bhagat };
31707c866fSRajesh Bhagat #endif
32ba92ee06SRamneek Mehresh 
__board_usb_init(int index,enum usb_init_type init)33ba92ee06SRamneek Mehresh __weak int __board_usb_init(int index, enum usb_init_type init)
34ba92ee06SRamneek Mehresh {
35ba92ee06SRamneek Mehresh 	return 0;
36ba92ee06SRamneek Mehresh }
37ba92ee06SRamneek Mehresh 
erratum_a008751(void)38ef53b8c4SSriram Dash static int erratum_a008751(void)
39ef53b8c4SSriram Dash {
403049a583SPriyanka Jain #if defined(CONFIG_TARGET_LS2080AQDS) || defined(CONFIG_TARGET_LS2080ARDB) ||\
413049a583SPriyanka Jain 					defined(CONFIG_TARGET_LS2080AQDS)
42ef53b8c4SSriram Dash 	u32 __iomem *scfg = (u32 __iomem *)SCFG_BASE;
43ef53b8c4SSriram Dash 	writel(SCFG_USB3PRM1CR_INIT, scfg + SCFG_USB3PRM1CR / 4);
44ef53b8c4SSriram Dash 	return 0;
45ef53b8c4SSriram Dash #endif
46ef53b8c4SSriram Dash 	return 1;
47ef53b8c4SSriram Dash }
48ef53b8c4SSriram Dash 
fsl_apply_xhci_errata(void)49ef53b8c4SSriram Dash static void fsl_apply_xhci_errata(void)
50ef53b8c4SSriram Dash {
51ef53b8c4SSriram Dash 	int ret;
52ef53b8c4SSriram Dash 	if (has_erratum_a008751()) {
53ef53b8c4SSriram Dash 		ret = erratum_a008751();
54ef53b8c4SSriram Dash 		if (ret != 0)
55ef53b8c4SSriram Dash 			puts("Failed to apply erratum a008751\n");
56ef53b8c4SSriram Dash 	}
57ef53b8c4SSriram Dash }
58ef53b8c4SSriram Dash 
fsl_xhci_set_beat_burst_length(struct dwc3 * dwc3_reg)59e915716aSSriram Dash static void fsl_xhci_set_beat_burst_length(struct dwc3 *dwc3_reg)
60e915716aSSriram Dash {
61e915716aSSriram Dash 	clrsetbits_le32(&dwc3_reg->g_sbuscfg0, USB3_ENABLE_BEAT_BURST_MASK,
62e915716aSSriram Dash 			USB3_ENABLE_BEAT_BURST);
63e915716aSSriram Dash 	setbits_le32(&dwc3_reg->g_sbuscfg1, USB3_SET_BEAT_BURST_LIMIT);
64e915716aSSriram Dash }
65e915716aSSriram Dash 
fsl_xhci_core_init(struct fsl_xhci * fsl_xhci)66ba92ee06SRamneek Mehresh static int fsl_xhci_core_init(struct fsl_xhci *fsl_xhci)
67ba92ee06SRamneek Mehresh {
68ba92ee06SRamneek Mehresh 	int ret = 0;
69ba92ee06SRamneek Mehresh 
70ba92ee06SRamneek Mehresh 	ret = dwc3_core_init(fsl_xhci->dwc3_reg);
71ba92ee06SRamneek Mehresh 	if (ret) {
72ba92ee06SRamneek Mehresh 		debug("%s:failed to initialize core\n", __func__);
73ba92ee06SRamneek Mehresh 		return ret;
74ba92ee06SRamneek Mehresh 	}
75ba92ee06SRamneek Mehresh 
76ba92ee06SRamneek Mehresh 	/* We are hard-coding DWC3 core to Host Mode */
77ba92ee06SRamneek Mehresh 	dwc3_set_mode(fsl_xhci->dwc3_reg, DWC3_GCTL_PRTCAP_HOST);
78ba92ee06SRamneek Mehresh 
79667f4dd9SNikhil Badola 	/* Set GFLADJ_30MHZ as 20h as per XHCI spec default value */
80667f4dd9SNikhil Badola 	dwc3_set_fladj(fsl_xhci->dwc3_reg, GFLADJ_30MHZ_DEFAULT);
81667f4dd9SNikhil Badola 
82e915716aSSriram Dash 	/* Change beat burst and outstanding pipelined transfers requests */
83e915716aSSriram Dash 	fsl_xhci_set_beat_burst_length(fsl_xhci->dwc3_reg);
84e915716aSSriram Dash 
854c043712SSriram Dash 	/*
864c043712SSriram Dash 	 * A-010151: The dwc3 phy TSMC 28-nm HPM 0.9/1.8 V does not
874c043712SSriram Dash 	 * reliably support Rx Detect in P3 mode(P3 is the default
884c043712SSriram Dash 	 * setting). Therefore, some USB3.0 devices may not be detected
894c043712SSriram Dash 	 * reliably in Super Speed mode. So, USB controller to configure
904c043712SSriram Dash 	 * USB in P2 mode whenever the Receive Detect feature is required.
914c043712SSriram Dash 	 * whenever the Receive Detect feature is required.
924c043712SSriram Dash 	 */
934c043712SSriram Dash 	if (has_erratum_a010151())
944c043712SSriram Dash 		clrsetbits_le32(&fsl_xhci->dwc3_reg->g_usb3pipectl[0],
954c043712SSriram Dash 				DWC3_GUSB3PIPECTL_DISRXDETP3,
964c043712SSriram Dash 				DWC3_GUSB3PIPECTL_DISRXDETP3);
974c043712SSriram Dash 
98ba92ee06SRamneek Mehresh 	return ret;
99ba92ee06SRamneek Mehresh }
100ba92ee06SRamneek Mehresh 
fsl_xhci_core_exit(struct fsl_xhci * fsl_xhci)101ba92ee06SRamneek Mehresh static int fsl_xhci_core_exit(struct fsl_xhci *fsl_xhci)
102ba92ee06SRamneek Mehresh {
103ba92ee06SRamneek Mehresh 	/*
104ba92ee06SRamneek Mehresh 	 * Currently fsl socs do not support PHY shutdown from
105ba92ee06SRamneek Mehresh 	 * sw. But this support may be added in future socs.
106ba92ee06SRamneek Mehresh 	 */
107ba92ee06SRamneek Mehresh 	return 0;
108ba92ee06SRamneek Mehresh }
109ba92ee06SRamneek Mehresh 
110*fd09c205SSven Schwermer #if CONFIG_IS_ENABLED(DM_USB)
xhci_fsl_probe(struct udevice * dev)111707c866fSRajesh Bhagat static int xhci_fsl_probe(struct udevice *dev)
112707c866fSRajesh Bhagat {
113707c866fSRajesh Bhagat 	struct xhci_fsl_priv *priv = dev_get_priv(dev);
114707c866fSRajesh Bhagat 	struct xhci_hccr *hccr;
115707c866fSRajesh Bhagat 	struct xhci_hcor *hcor;
116707c866fSRajesh Bhagat 
117707c866fSRajesh Bhagat 	int ret = 0;
118707c866fSRajesh Bhagat 
119707c866fSRajesh Bhagat 	/*
120707c866fSRajesh Bhagat 	 * Get the base address for XHCI controller from the device node
121707c866fSRajesh Bhagat 	 */
122a821c4afSSimon Glass 	priv->hcd_base = devfdt_get_addr(dev);
123707c866fSRajesh Bhagat 	if (priv->hcd_base == FDT_ADDR_T_NONE) {
124707c866fSRajesh Bhagat 		debug("Can't get the XHCI register base address\n");
125707c866fSRajesh Bhagat 		return -ENXIO;
126707c866fSRajesh Bhagat 	}
127707c866fSRajesh Bhagat 	priv->ctx.hcd = (struct xhci_hccr *)priv->hcd_base;
128707c866fSRajesh Bhagat 	priv->ctx.dwc3_reg = (struct dwc3 *)((char *)(priv->hcd_base) +
129707c866fSRajesh Bhagat 			  DWC3_REG_OFFSET);
130707c866fSRajesh Bhagat 
131707c866fSRajesh Bhagat 	fsl_apply_xhci_errata();
132707c866fSRajesh Bhagat 
133707c866fSRajesh Bhagat 	ret = fsl_xhci_core_init(&priv->ctx);
134707c866fSRajesh Bhagat 	if (ret < 0) {
135707c866fSRajesh Bhagat 		puts("Failed to initialize xhci\n");
136707c866fSRajesh Bhagat 		return ret;
137707c866fSRajesh Bhagat 	}
138707c866fSRajesh Bhagat 
139707c866fSRajesh Bhagat 	hccr = (struct xhci_hccr *)(priv->ctx.hcd);
140707c866fSRajesh Bhagat 	hcor = (struct xhci_hcor *)((uintptr_t) hccr
141707c866fSRajesh Bhagat 				+ HC_LENGTH(xhci_readl(&hccr->cr_capbase)));
142707c866fSRajesh Bhagat 
143707c866fSRajesh Bhagat 	debug("xhci-fsl: init hccr %lx and hcor %lx hc_length %lx\n",
144707c866fSRajesh Bhagat 	      (uintptr_t)hccr, (uintptr_t)hcor,
145707c866fSRajesh Bhagat 	      (uintptr_t)HC_LENGTH(xhci_readl(&hccr->cr_capbase)));
146707c866fSRajesh Bhagat 
147707c866fSRajesh Bhagat 	return xhci_register(dev, hccr, hcor);
148707c866fSRajesh Bhagat }
149707c866fSRajesh Bhagat 
xhci_fsl_remove(struct udevice * dev)150707c866fSRajesh Bhagat static int xhci_fsl_remove(struct udevice *dev)
151707c866fSRajesh Bhagat {
152707c866fSRajesh Bhagat 	struct xhci_fsl_priv *priv = dev_get_priv(dev);
153707c866fSRajesh Bhagat 
154707c866fSRajesh Bhagat 	fsl_xhci_core_exit(&priv->ctx);
155707c866fSRajesh Bhagat 
1568319aeb1SMasahiro Yamada 	return xhci_deregister(dev);
157707c866fSRajesh Bhagat }
158707c866fSRajesh Bhagat 
159707c866fSRajesh Bhagat static const struct udevice_id xhci_usb_ids[] = {
160707c866fSRajesh Bhagat 	{ .compatible = "fsl,layerscape-dwc3", },
161707c866fSRajesh Bhagat 	{ }
162707c866fSRajesh Bhagat };
163707c866fSRajesh Bhagat 
164707c866fSRajesh Bhagat U_BOOT_DRIVER(xhci_fsl) = {
165707c866fSRajesh Bhagat 	.name	= "xhci_fsl",
166707c866fSRajesh Bhagat 	.id	= UCLASS_USB,
167707c866fSRajesh Bhagat 	.of_match = xhci_usb_ids,
168707c866fSRajesh Bhagat 	.probe = xhci_fsl_probe,
169707c866fSRajesh Bhagat 	.remove = xhci_fsl_remove,
170707c866fSRajesh Bhagat 	.ops	= &xhci_usb_ops,
171707c866fSRajesh Bhagat 	.platdata_auto_alloc_size = sizeof(struct usb_platdata),
172707c866fSRajesh Bhagat 	.priv_auto_alloc_size = sizeof(struct xhci_fsl_priv),
173707c866fSRajesh Bhagat 	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
174707c866fSRajesh Bhagat };
175707c866fSRajesh Bhagat #else
xhci_hcd_init(int index,struct xhci_hccr ** hccr,struct xhci_hcor ** hcor)176ba92ee06SRamneek Mehresh int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
177ba92ee06SRamneek Mehresh {
178ba92ee06SRamneek Mehresh 	struct fsl_xhci *ctx = &fsl_xhci;
179ba92ee06SRamneek Mehresh 	int ret = 0;
180ba92ee06SRamneek Mehresh 
181ba92ee06SRamneek Mehresh 	ctx->hcd = (struct xhci_hccr *)ctr_addr[index];
182ba92ee06SRamneek Mehresh 	ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET);
183ba92ee06SRamneek Mehresh 
184ba92ee06SRamneek Mehresh 	ret = board_usb_init(index, USB_INIT_HOST);
185ba92ee06SRamneek Mehresh 	if (ret != 0) {
186ba92ee06SRamneek Mehresh 		puts("Failed to initialize board for USB\n");
187ba92ee06SRamneek Mehresh 		return ret;
188ba92ee06SRamneek Mehresh 	}
189ba92ee06SRamneek Mehresh 
190ef53b8c4SSriram Dash 	fsl_apply_xhci_errata();
191ef53b8c4SSriram Dash 
192ba92ee06SRamneek Mehresh 	ret = fsl_xhci_core_init(ctx);
193ba92ee06SRamneek Mehresh 	if (ret < 0) {
194ba92ee06SRamneek Mehresh 		puts("Failed to initialize xhci\n");
195ba92ee06SRamneek Mehresh 		return ret;
196ba92ee06SRamneek Mehresh 	}
197ba92ee06SRamneek Mehresh 
198ba92ee06SRamneek Mehresh 	*hccr = (struct xhci_hccr *)ctx->hcd;
1997e5a32fcSNikhil Badola 	*hcor = (struct xhci_hcor *)((uintptr_t) *hccr
200ba92ee06SRamneek Mehresh 				+ HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
201ba92ee06SRamneek Mehresh 
2027e5a32fcSNikhil Badola 	debug("fsl-xhci: init hccr %lx and hcor %lx hc_length %lx\n",
2037e5a32fcSNikhil Badola 	      (uintptr_t)*hccr, (uintptr_t)*hcor,
2047e5a32fcSNikhil Badola 	      (uintptr_t)HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
205ba92ee06SRamneek Mehresh 
206ba92ee06SRamneek Mehresh 	return ret;
207ba92ee06SRamneek Mehresh }
208ba92ee06SRamneek Mehresh 
xhci_hcd_stop(int index)209ba92ee06SRamneek Mehresh void xhci_hcd_stop(int index)
210ba92ee06SRamneek Mehresh {
211ba92ee06SRamneek Mehresh 	struct fsl_xhci *ctx = &fsl_xhci;
212ba92ee06SRamneek Mehresh 
213ba92ee06SRamneek Mehresh 	fsl_xhci_core_exit(ctx);
214ba92ee06SRamneek Mehresh }
215707c866fSRajesh Bhagat #endif
216