xref: /openbmc/u-boot/drivers/usb/host/xhci-fsl.c (revision e915716a)
1ba92ee06SRamneek Mehresh /*
2707c866fSRajesh 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>
135d97dff0SMasahiro Yamada #include <linux/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>
20707c866fSRajesh Bhagat #include <dm.h>
21ba92ee06SRamneek Mehresh 
22ba92ee06SRamneek Mehresh /* Declare global data pointer */
23ba92ee06SRamneek Mehresh DECLARE_GLOBAL_DATA_PTR;
24ba92ee06SRamneek Mehresh 
25707c866fSRajesh Bhagat #ifndef CONFIG_DM_USB
26ba92ee06SRamneek Mehresh static struct fsl_xhci fsl_xhci;
27ba92ee06SRamneek Mehresh unsigned long ctr_addr[] = FSL_USB_XHCI_ADDR;
28707c866fSRajesh Bhagat #else
29707c866fSRajesh Bhagat struct xhci_fsl_priv {
30707c866fSRajesh Bhagat 	struct xhci_ctrl xhci;
31707c866fSRajesh Bhagat 	fdt_addr_t hcd_base;
32707c866fSRajesh Bhagat 	struct fsl_xhci ctx;
33707c866fSRajesh Bhagat };
34707c866fSRajesh 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 
61*e915716aSSriram Dash static void fsl_xhci_set_beat_burst_length(struct dwc3 *dwc3_reg)
62*e915716aSSriram Dash {
63*e915716aSSriram Dash 	clrsetbits_le32(&dwc3_reg->g_sbuscfg0, USB3_ENABLE_BEAT_BURST_MASK,
64*e915716aSSriram Dash 			USB3_ENABLE_BEAT_BURST);
65*e915716aSSriram Dash 	setbits_le32(&dwc3_reg->g_sbuscfg1, USB3_SET_BEAT_BURST_LIMIT);
66*e915716aSSriram Dash }
67*e915716aSSriram Dash 
68ba92ee06SRamneek Mehresh static int fsl_xhci_core_init(struct fsl_xhci *fsl_xhci)
69ba92ee06SRamneek Mehresh {
70ba92ee06SRamneek Mehresh 	int ret = 0;
71ba92ee06SRamneek Mehresh 
72ba92ee06SRamneek Mehresh 	ret = dwc3_core_init(fsl_xhci->dwc3_reg);
73ba92ee06SRamneek Mehresh 	if (ret) {
74ba92ee06SRamneek Mehresh 		debug("%s:failed to initialize core\n", __func__);
75ba92ee06SRamneek Mehresh 		return ret;
76ba92ee06SRamneek Mehresh 	}
77ba92ee06SRamneek Mehresh 
78ba92ee06SRamneek Mehresh 	/* We are hard-coding DWC3 core to Host Mode */
79ba92ee06SRamneek Mehresh 	dwc3_set_mode(fsl_xhci->dwc3_reg, DWC3_GCTL_PRTCAP_HOST);
80ba92ee06SRamneek Mehresh 
81667f4dd9SNikhil Badola 	/* Set GFLADJ_30MHZ as 20h as per XHCI spec default value */
82667f4dd9SNikhil Badola 	dwc3_set_fladj(fsl_xhci->dwc3_reg, GFLADJ_30MHZ_DEFAULT);
83667f4dd9SNikhil Badola 
84*e915716aSSriram Dash 	/* Change beat burst and outstanding pipelined transfers requests */
85*e915716aSSriram Dash 	fsl_xhci_set_beat_burst_length(fsl_xhci->dwc3_reg);
86*e915716aSSriram Dash 
87ba92ee06SRamneek Mehresh 	return ret;
88ba92ee06SRamneek Mehresh }
89ba92ee06SRamneek Mehresh 
90ba92ee06SRamneek Mehresh static int fsl_xhci_core_exit(struct fsl_xhci *fsl_xhci)
91ba92ee06SRamneek Mehresh {
92ba92ee06SRamneek Mehresh 	/*
93ba92ee06SRamneek Mehresh 	 * Currently fsl socs do not support PHY shutdown from
94ba92ee06SRamneek Mehresh 	 * sw. But this support may be added in future socs.
95ba92ee06SRamneek Mehresh 	 */
96ba92ee06SRamneek Mehresh 	return 0;
97ba92ee06SRamneek Mehresh }
98ba92ee06SRamneek Mehresh 
99707c866fSRajesh Bhagat #ifdef CONFIG_DM_USB
100707c866fSRajesh Bhagat static int xhci_fsl_probe(struct udevice *dev)
101707c866fSRajesh Bhagat {
102707c866fSRajesh Bhagat 	struct xhci_fsl_priv *priv = dev_get_priv(dev);
103707c866fSRajesh Bhagat 	struct xhci_hccr *hccr;
104707c866fSRajesh Bhagat 	struct xhci_hcor *hcor;
105707c866fSRajesh Bhagat 
106707c866fSRajesh Bhagat 	int ret = 0;
107707c866fSRajesh Bhagat 
108707c866fSRajesh Bhagat 	/*
109707c866fSRajesh Bhagat 	 * Get the base address for XHCI controller from the device node
110707c866fSRajesh Bhagat 	 */
111707c866fSRajesh Bhagat 	priv->hcd_base = dev_get_addr(dev);
112707c866fSRajesh Bhagat 	if (priv->hcd_base == FDT_ADDR_T_NONE) {
113707c866fSRajesh Bhagat 		debug("Can't get the XHCI register base address\n");
114707c866fSRajesh Bhagat 		return -ENXIO;
115707c866fSRajesh Bhagat 	}
116707c866fSRajesh Bhagat 	priv->ctx.hcd = (struct xhci_hccr *)priv->hcd_base;
117707c866fSRajesh Bhagat 	priv->ctx.dwc3_reg = (struct dwc3 *)((char *)(priv->hcd_base) +
118707c866fSRajesh Bhagat 			  DWC3_REG_OFFSET);
119707c866fSRajesh Bhagat 
120707c866fSRajesh Bhagat 	fsl_apply_xhci_errata();
121707c866fSRajesh Bhagat 
122707c866fSRajesh Bhagat 	ret = fsl_xhci_core_init(&priv->ctx);
123707c866fSRajesh Bhagat 	if (ret < 0) {
124707c866fSRajesh Bhagat 		puts("Failed to initialize xhci\n");
125707c866fSRajesh Bhagat 		return ret;
126707c866fSRajesh Bhagat 	}
127707c866fSRajesh Bhagat 
128707c866fSRajesh Bhagat 	hccr = (struct xhci_hccr *)(priv->ctx.hcd);
129707c866fSRajesh Bhagat 	hcor = (struct xhci_hcor *)((uintptr_t) hccr
130707c866fSRajesh Bhagat 				+ HC_LENGTH(xhci_readl(&hccr->cr_capbase)));
131707c866fSRajesh Bhagat 
132707c866fSRajesh Bhagat 	debug("xhci-fsl: init hccr %lx and hcor %lx hc_length %lx\n",
133707c866fSRajesh Bhagat 	      (uintptr_t)hccr, (uintptr_t)hcor,
134707c866fSRajesh Bhagat 	      (uintptr_t)HC_LENGTH(xhci_readl(&hccr->cr_capbase)));
135707c866fSRajesh Bhagat 
136707c866fSRajesh Bhagat 	return xhci_register(dev, hccr, hcor);
137707c866fSRajesh Bhagat }
138707c866fSRajesh Bhagat 
139707c866fSRajesh Bhagat static int xhci_fsl_remove(struct udevice *dev)
140707c866fSRajesh Bhagat {
141707c866fSRajesh Bhagat 	struct xhci_fsl_priv *priv = dev_get_priv(dev);
142707c866fSRajesh Bhagat 
143707c866fSRajesh Bhagat 	fsl_xhci_core_exit(&priv->ctx);
144707c866fSRajesh Bhagat 
1458319aeb1SMasahiro Yamada 	return xhci_deregister(dev);
146707c866fSRajesh Bhagat }
147707c866fSRajesh Bhagat 
148707c866fSRajesh Bhagat static const struct udevice_id xhci_usb_ids[] = {
149707c866fSRajesh Bhagat 	{ .compatible = "fsl,layerscape-dwc3", },
150707c866fSRajesh Bhagat 	{ }
151707c866fSRajesh Bhagat };
152707c866fSRajesh Bhagat 
153707c866fSRajesh Bhagat U_BOOT_DRIVER(xhci_fsl) = {
154707c866fSRajesh Bhagat 	.name	= "xhci_fsl",
155707c866fSRajesh Bhagat 	.id	= UCLASS_USB,
156707c866fSRajesh Bhagat 	.of_match = xhci_usb_ids,
157707c866fSRajesh Bhagat 	.probe = xhci_fsl_probe,
158707c866fSRajesh Bhagat 	.remove = xhci_fsl_remove,
159707c866fSRajesh Bhagat 	.ops	= &xhci_usb_ops,
160707c866fSRajesh Bhagat 	.platdata_auto_alloc_size = sizeof(struct usb_platdata),
161707c866fSRajesh Bhagat 	.priv_auto_alloc_size = sizeof(struct xhci_fsl_priv),
162707c866fSRajesh Bhagat 	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
163707c866fSRajesh Bhagat };
164707c866fSRajesh Bhagat #else
165ba92ee06SRamneek Mehresh int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
166ba92ee06SRamneek Mehresh {
167ba92ee06SRamneek Mehresh 	struct fsl_xhci *ctx = &fsl_xhci;
168ba92ee06SRamneek Mehresh 	int ret = 0;
169ba92ee06SRamneek Mehresh 
170ba92ee06SRamneek Mehresh 	ctx->hcd = (struct xhci_hccr *)ctr_addr[index];
171ba92ee06SRamneek Mehresh 	ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET);
172ba92ee06SRamneek Mehresh 
173ba92ee06SRamneek Mehresh 	ret = board_usb_init(index, USB_INIT_HOST);
174ba92ee06SRamneek Mehresh 	if (ret != 0) {
175ba92ee06SRamneek Mehresh 		puts("Failed to initialize board for USB\n");
176ba92ee06SRamneek Mehresh 		return ret;
177ba92ee06SRamneek Mehresh 	}
178ba92ee06SRamneek Mehresh 
179ef53b8c4SSriram Dash 	fsl_apply_xhci_errata();
180ef53b8c4SSriram Dash 
181ba92ee06SRamneek Mehresh 	ret = fsl_xhci_core_init(ctx);
182ba92ee06SRamneek Mehresh 	if (ret < 0) {
183ba92ee06SRamneek Mehresh 		puts("Failed to initialize xhci\n");
184ba92ee06SRamneek Mehresh 		return ret;
185ba92ee06SRamneek Mehresh 	}
186ba92ee06SRamneek Mehresh 
187ba92ee06SRamneek Mehresh 	*hccr = (struct xhci_hccr *)ctx->hcd;
1887e5a32fcSNikhil Badola 	*hcor = (struct xhci_hcor *)((uintptr_t) *hccr
189ba92ee06SRamneek Mehresh 				+ HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
190ba92ee06SRamneek Mehresh 
1917e5a32fcSNikhil Badola 	debug("fsl-xhci: init hccr %lx and hcor %lx hc_length %lx\n",
1927e5a32fcSNikhil Badola 	      (uintptr_t)*hccr, (uintptr_t)*hcor,
1937e5a32fcSNikhil Badola 	      (uintptr_t)HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
194ba92ee06SRamneek Mehresh 
195ba92ee06SRamneek Mehresh 	return ret;
196ba92ee06SRamneek Mehresh }
197ba92ee06SRamneek Mehresh 
198ba92ee06SRamneek Mehresh void xhci_hcd_stop(int index)
199ba92ee06SRamneek Mehresh {
200ba92ee06SRamneek Mehresh 	struct fsl_xhci *ctx = &fsl_xhci;
201ba92ee06SRamneek Mehresh 
202ba92ee06SRamneek Mehresh 	fsl_xhci_core_exit(ctx);
203ba92ee06SRamneek Mehresh }
204707c866fSRajesh Bhagat #endif
205