xref: /rk3399_rockchip-uboot/drivers/usb/host/ehci-msm.c (revision 5a8221181edca991f7cfbf90b7f60ebf3c0b4970)
1*5a822118SMateusz Kulikowski /*
2*5a822118SMateusz Kulikowski  * Qualcomm EHCI driver
3*5a822118SMateusz Kulikowski  *
4*5a822118SMateusz Kulikowski  * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
5*5a822118SMateusz Kulikowski  *
6*5a822118SMateusz Kulikowski  * Based on Linux driver
7*5a822118SMateusz Kulikowski  *
8*5a822118SMateusz Kulikowski  * SPDX-License-Identifier:	GPL-2.0+
9*5a822118SMateusz Kulikowski  */
10*5a822118SMateusz Kulikowski 
11*5a822118SMateusz Kulikowski #include <common.h>
12*5a822118SMateusz Kulikowski #include <dm.h>
13*5a822118SMateusz Kulikowski #include <errno.h>
14*5a822118SMateusz Kulikowski #include <fdtdec.h>
15*5a822118SMateusz Kulikowski #include <libfdt.h>
16*5a822118SMateusz Kulikowski #include <usb.h>
17*5a822118SMateusz Kulikowski #include <usb/ehci-ci.h>
18*5a822118SMateusz Kulikowski #include <usb/ulpi.h>
19*5a822118SMateusz Kulikowski #include <wait_bit.h>
20*5a822118SMateusz Kulikowski #include <asm/gpio.h>
21*5a822118SMateusz Kulikowski #include <asm/io.h>
22*5a822118SMateusz Kulikowski #include <linux/compat.h>
23*5a822118SMateusz Kulikowski #include "ehci.h"
24*5a822118SMateusz Kulikowski 
25*5a822118SMateusz Kulikowski /* PHY viewport regs */
26*5a822118SMateusz Kulikowski #define ULPI_MISC_A_READ         0x96
27*5a822118SMateusz Kulikowski #define ULPI_MISC_A_SET          0x97
28*5a822118SMateusz Kulikowski #define ULPI_MISC_A_CLEAR        0x98
29*5a822118SMateusz Kulikowski #define ULPI_MISC_A_VBUSVLDEXTSEL    (1 << 1)
30*5a822118SMateusz Kulikowski #define ULPI_MISC_A_VBUSVLDEXT       (1 << 0)
31*5a822118SMateusz Kulikowski 
32*5a822118SMateusz Kulikowski #define GEN2_SESS_VLD_CTRL_EN (1 << 7)
33*5a822118SMateusz Kulikowski 
34*5a822118SMateusz Kulikowski #define SESS_VLD_CTRL         (1 << 25)
35*5a822118SMateusz Kulikowski 
36*5a822118SMateusz Kulikowski struct msm_ehci_priv {
37*5a822118SMateusz Kulikowski 	struct ehci_ctrl ctrl; /* Needed by EHCI */
38*5a822118SMateusz Kulikowski 	struct usb_ehci *ehci; /* Start of IP core*/
39*5a822118SMateusz Kulikowski 	struct ulpi_viewport ulpi_vp; /* ULPI Viewport */
40*5a822118SMateusz Kulikowski };
41*5a822118SMateusz Kulikowski 
42*5a822118SMateusz Kulikowski int __weak board_prepare_usb(enum usb_init_type type)
43*5a822118SMateusz Kulikowski {
44*5a822118SMateusz Kulikowski 	return 0;
45*5a822118SMateusz Kulikowski }
46*5a822118SMateusz Kulikowski 
47*5a822118SMateusz Kulikowski static void setup_usb_phy(struct msm_ehci_priv *priv)
48*5a822118SMateusz Kulikowski {
49*5a822118SMateusz Kulikowski 	/* Select and enable external configuration with USB PHY */
50*5a822118SMateusz Kulikowski 	ulpi_write(&priv->ulpi_vp, (u8 *)ULPI_MISC_A_SET,
51*5a822118SMateusz Kulikowski 		   ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT);
52*5a822118SMateusz Kulikowski }
53*5a822118SMateusz Kulikowski 
54*5a822118SMateusz Kulikowski static void reset_usb_phy(struct msm_ehci_priv *priv)
55*5a822118SMateusz Kulikowski {
56*5a822118SMateusz Kulikowski 	/* Disable VBUS mimicing in the controller. */
57*5a822118SMateusz Kulikowski 	ulpi_write(&priv->ulpi_vp, (u8 *)ULPI_MISC_A_CLEAR,
58*5a822118SMateusz Kulikowski 		   ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT);
59*5a822118SMateusz Kulikowski }
60*5a822118SMateusz Kulikowski 
61*5a822118SMateusz Kulikowski 
62*5a822118SMateusz Kulikowski static int msm_init_after_reset(struct ehci_ctrl *dev)
63*5a822118SMateusz Kulikowski {
64*5a822118SMateusz Kulikowski 	struct msm_ehci_priv *p = container_of(dev, struct msm_ehci_priv, ctrl);
65*5a822118SMateusz Kulikowski 	struct usb_ehci *ehci = p->ehci;
66*5a822118SMateusz Kulikowski 
67*5a822118SMateusz Kulikowski 	/* select ULPI phy */
68*5a822118SMateusz Kulikowski 	writel(PORT_PTS_ULPI, &ehci->portsc);
69*5a822118SMateusz Kulikowski 	setup_usb_phy(p);
70*5a822118SMateusz Kulikowski 
71*5a822118SMateusz Kulikowski 	/* Enable sess_vld */
72*5a822118SMateusz Kulikowski 	setbits_le32(&ehci->genconfig2, GEN2_SESS_VLD_CTRL_EN);
73*5a822118SMateusz Kulikowski 
74*5a822118SMateusz Kulikowski 	/* Enable external vbus configuration in the LINK */
75*5a822118SMateusz Kulikowski 	setbits_le32(&ehci->usbcmd, SESS_VLD_CTRL);
76*5a822118SMateusz Kulikowski 
77*5a822118SMateusz Kulikowski 	/* USB_OTG_HS_AHB_BURST */
78*5a822118SMateusz Kulikowski 	writel(0x0, &ehci->sbuscfg);
79*5a822118SMateusz Kulikowski 
80*5a822118SMateusz Kulikowski 	/* USB_OTG_HS_AHB_MODE: HPROT_MODE */
81*5a822118SMateusz Kulikowski 	/* Bus access related config. */
82*5a822118SMateusz Kulikowski 	writel(0x08, &ehci->sbusmode);
83*5a822118SMateusz Kulikowski 
84*5a822118SMateusz Kulikowski 	/* set mode to host controller */
85*5a822118SMateusz Kulikowski 	writel(CM_HOST, &ehci->usbmode);
86*5a822118SMateusz Kulikowski 
87*5a822118SMateusz Kulikowski 	return 0;
88*5a822118SMateusz Kulikowski }
89*5a822118SMateusz Kulikowski 
90*5a822118SMateusz Kulikowski static const struct ehci_ops msm_ehci_ops = {
91*5a822118SMateusz Kulikowski 	.init_after_reset = msm_init_after_reset
92*5a822118SMateusz Kulikowski };
93*5a822118SMateusz Kulikowski 
94*5a822118SMateusz Kulikowski static int ehci_usb_probe(struct udevice *dev)
95*5a822118SMateusz Kulikowski {
96*5a822118SMateusz Kulikowski 	struct msm_ehci_priv *p = dev_get_priv(dev);
97*5a822118SMateusz Kulikowski 	struct usb_ehci *ehci = p->ehci;
98*5a822118SMateusz Kulikowski 	struct ehci_hccr *hccr;
99*5a822118SMateusz Kulikowski 	struct ehci_hcor *hcor;
100*5a822118SMateusz Kulikowski 	int ret;
101*5a822118SMateusz Kulikowski 
102*5a822118SMateusz Kulikowski 	hccr = (struct ehci_hccr *)((phys_addr_t)&ehci->caplength);
103*5a822118SMateusz Kulikowski 	hcor = (struct ehci_hcor *)((phys_addr_t)hccr +
104*5a822118SMateusz Kulikowski 			HC_LENGTH(ehci_readl(&(hccr)->cr_capbase)));
105*5a822118SMateusz Kulikowski 
106*5a822118SMateusz Kulikowski 	ret = board_prepare_usb(USB_INIT_HOST);
107*5a822118SMateusz Kulikowski 	if (ret < 0)
108*5a822118SMateusz Kulikowski 		return ret;
109*5a822118SMateusz Kulikowski 
110*5a822118SMateusz Kulikowski 	return ehci_register(dev, hccr, hcor, &msm_ehci_ops, 0, USB_INIT_HOST);
111*5a822118SMateusz Kulikowski }
112*5a822118SMateusz Kulikowski 
113*5a822118SMateusz Kulikowski static int ehci_usb_remove(struct udevice *dev)
114*5a822118SMateusz Kulikowski {
115*5a822118SMateusz Kulikowski 	struct msm_ehci_priv *p = dev_get_priv(dev);
116*5a822118SMateusz Kulikowski 	struct usb_ehci *ehci = p->ehci;
117*5a822118SMateusz Kulikowski 	int ret;
118*5a822118SMateusz Kulikowski 
119*5a822118SMateusz Kulikowski 	ret = ehci_deregister(dev);
120*5a822118SMateusz Kulikowski 	if (ret)
121*5a822118SMateusz Kulikowski 		return ret;
122*5a822118SMateusz Kulikowski 
123*5a822118SMateusz Kulikowski 	/* Stop controller. */
124*5a822118SMateusz Kulikowski 	clrbits_le32(&ehci->usbcmd, CMD_RUN);
125*5a822118SMateusz Kulikowski 
126*5a822118SMateusz Kulikowski 	reset_usb_phy(p);
127*5a822118SMateusz Kulikowski 
128*5a822118SMateusz Kulikowski 	ret = board_prepare_usb(USB_INIT_DEVICE); /* Board specific hook */
129*5a822118SMateusz Kulikowski 	if (ret < 0)
130*5a822118SMateusz Kulikowski 		return ret;
131*5a822118SMateusz Kulikowski 
132*5a822118SMateusz Kulikowski 	/* Reset controller */
133*5a822118SMateusz Kulikowski 	setbits_le32(&ehci->usbcmd, CMD_RESET);
134*5a822118SMateusz Kulikowski 
135*5a822118SMateusz Kulikowski 	/* Wait for reset */
136*5a822118SMateusz Kulikowski 	if (wait_for_bit(__func__, &ehci->usbcmd, CMD_RESET, false, 30,
137*5a822118SMateusz Kulikowski 			 false)) {
138*5a822118SMateusz Kulikowski 		printf("Stuck on USB reset.\n");
139*5a822118SMateusz Kulikowski 		return -ETIMEDOUT;
140*5a822118SMateusz Kulikowski 	}
141*5a822118SMateusz Kulikowski 
142*5a822118SMateusz Kulikowski 	return 0;
143*5a822118SMateusz Kulikowski }
144*5a822118SMateusz Kulikowski 
145*5a822118SMateusz Kulikowski static int ehci_usb_ofdata_to_platdata(struct udevice *dev)
146*5a822118SMateusz Kulikowski {
147*5a822118SMateusz Kulikowski 	struct msm_ehci_priv *priv = dev_get_priv(dev);
148*5a822118SMateusz Kulikowski 
149*5a822118SMateusz Kulikowski 	priv->ulpi_vp.port_num = 0;
150*5a822118SMateusz Kulikowski 	priv->ehci = (void *)dev_get_addr(dev);
151*5a822118SMateusz Kulikowski 
152*5a822118SMateusz Kulikowski 	if (priv->ehci == (void *)FDT_ADDR_T_NONE)
153*5a822118SMateusz Kulikowski 		return -EINVAL;
154*5a822118SMateusz Kulikowski 
155*5a822118SMateusz Kulikowski 	/* Warning: this will not work if viewport address is > 64 bit due to
156*5a822118SMateusz Kulikowski 	 * ULPI design.
157*5a822118SMateusz Kulikowski 	 */
158*5a822118SMateusz Kulikowski 	priv->ulpi_vp.viewport_addr = (phys_addr_t)&priv->ehci->ulpi_viewpoint;
159*5a822118SMateusz Kulikowski 
160*5a822118SMateusz Kulikowski 	return 0;
161*5a822118SMateusz Kulikowski }
162*5a822118SMateusz Kulikowski 
163*5a822118SMateusz Kulikowski static const struct udevice_id ehci_usb_ids[] = {
164*5a822118SMateusz Kulikowski 	{ .compatible = "qcom,ehci-host", },
165*5a822118SMateusz Kulikowski 	{ }
166*5a822118SMateusz Kulikowski };
167*5a822118SMateusz Kulikowski 
168*5a822118SMateusz Kulikowski U_BOOT_DRIVER(usb_ehci) = {
169*5a822118SMateusz Kulikowski 	.name	= "ehci_msm",
170*5a822118SMateusz Kulikowski 	.id	= UCLASS_USB,
171*5a822118SMateusz Kulikowski 	.of_match = ehci_usb_ids,
172*5a822118SMateusz Kulikowski 	.ofdata_to_platdata = ehci_usb_ofdata_to_platdata,
173*5a822118SMateusz Kulikowski 	.probe = ehci_usb_probe,
174*5a822118SMateusz Kulikowski 	.remove = ehci_usb_remove,
175*5a822118SMateusz Kulikowski 	.ops	= &ehci_usb_ops,
176*5a822118SMateusz Kulikowski 	.priv_auto_alloc_size = sizeof(struct msm_ehci_priv),
177*5a822118SMateusz Kulikowski 	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
178*5a822118SMateusz Kulikowski };
179