1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Qualcomm EHCI driver
4  *
5  * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
6  *
7  * Based on Linux driver
8  */
9 
10 #include <clk.h>
11 #include <dm.h>
12 #include <dm/device_compat.h>
13 #include <dm/lists.h>
14 #include <errno.h>
15 #include <usb.h>
16 #include <usb/ehci-ci.h>
17 #include <usb/ulpi.h>
18 #include <wait_bit.h>
19 #include <asm/gpio.h>
20 #include <asm/io.h>
21 #include <linux/compat.h>
22 #include "ehci.h"
23 
24 struct msm_ehci_priv {
25 	struct ehci_ctrl ctrl; /* Needed by EHCI */
26 	struct usb_ehci *ehci; /* Start of IP core*/
27 	struct ulpi_viewport ulpi_vp; /* ULPI Viewport */
28 	struct phy phy;
29 	struct clk iface_clk;
30 	struct clk core_clk;
31 };
32 
msm_init_after_reset(struct ehci_ctrl * dev)33 static int msm_init_after_reset(struct ehci_ctrl *dev)
34 {
35 	struct msm_ehci_priv *p = container_of(dev, struct msm_ehci_priv, ctrl);
36 	struct usb_ehci *ehci = p->ehci;
37 
38 	generic_phy_reset(&p->phy);
39 
40 	/* set mode to host controller */
41 	writel(CM_HOST, &ehci->usbmode);
42 
43 	return 0;
44 }
45 
46 static const struct ehci_ops msm_ehci_ops = {
47 	.init_after_reset = msm_init_after_reset
48 };
49 
ehci_usb_probe(struct udevice * dev)50 static int ehci_usb_probe(struct udevice *dev)
51 {
52 	struct msm_ehci_priv *p = dev_get_priv(dev);
53 	struct usb_ehci *ehci = p->ehci;
54 	struct usb_plat *plat = dev_get_plat(dev);
55 	struct ehci_hccr *hccr;
56 	struct ehci_hcor *hcor;
57 	int ret;
58 
59 	ret = clk_get_by_name(dev, "core", &p->core_clk);
60 	if (ret) {
61 		dev_err(dev, "Failed to get core clock: %d\n", ret);
62 		return ret;
63 	}
64 
65 	ret = clk_get_by_name(dev, "iface", &p->iface_clk);
66 	if (ret) {
67 		dev_err(dev, "Failed to get iface clock: %d\n", ret);
68 		return ret;
69 	}
70 
71 	ret = clk_prepare_enable(&p->core_clk);
72 	if (ret)
73 		return ret;
74 
75 	ret = clk_prepare_enable(&p->iface_clk);
76 	if (ret)
77 		goto cleanup_core;
78 
79 	hccr = (struct ehci_hccr *)((phys_addr_t)&ehci->caplength);
80 	hcor = (struct ehci_hcor *)((phys_addr_t)hccr +
81 			HC_LENGTH(ehci_readl(&(hccr)->cr_capbase)));
82 
83 	ret = generic_setup_phy(dev, &p->phy, 0, PHY_MODE_USB_HOST, 0);
84 	if (ret)
85 		goto cleanup_iface;
86 
87 	ret = board_usb_init(0, plat->init_type);
88 	if (ret < 0)
89 		goto cleanup_iface;
90 
91 	return ehci_register(dev, hccr, hcor, &msm_ehci_ops, 0,
92 			     plat->init_type);
93 
94 cleanup_iface:
95 	clk_disable_unprepare(&p->iface_clk);
96 cleanup_core:
97 	clk_disable_unprepare(&p->core_clk);
98 	return ret;
99 }
100 
ehci_usb_remove(struct udevice * dev)101 static int ehci_usb_remove(struct udevice *dev)
102 {
103 	struct msm_ehci_priv *p = dev_get_priv(dev);
104 	struct usb_ehci *ehci = p->ehci;
105 	int ret;
106 
107 	ret = ehci_deregister(dev);
108 	if (ret)
109 		return ret;
110 
111 	/* Stop controller. */
112 	clrbits_le32(&ehci->usbcmd, CMD_RUN);
113 
114 	clk_disable_unprepare(&p->iface_clk);
115 	clk_disable_unprepare(&p->core_clk);
116 
117 	ret = generic_shutdown_phy(&p->phy);
118 	if (ret)
119 		return ret;
120 
121 	ret = board_usb_init(0, USB_INIT_DEVICE); /* Board specific hook */
122 	if (ret < 0)
123 		return ret;
124 
125 	/* Reset controller */
126 	setbits_le32(&ehci->usbcmd, CMD_RESET);
127 
128 	/* Wait for reset */
129 	if (wait_for_bit_le32(&ehci->usbcmd, CMD_RESET, false, 30, false)) {
130 		printf("Stuck on USB reset.\n");
131 		return -ETIMEDOUT;
132 	}
133 
134 	return 0;
135 }
136 
ehci_usb_of_to_plat(struct udevice * dev)137 static int ehci_usb_of_to_plat(struct udevice *dev)
138 {
139 	struct msm_ehci_priv *priv = dev_get_priv(dev);
140 
141 	priv->ulpi_vp.port_num = 0;
142 	priv->ehci = dev_read_addr_ptr(dev);
143 
144 	if (priv->ehci == (void *)FDT_ADDR_T_NONE)
145 		return -EINVAL;
146 
147 	/* Warning: this will not work if viewport address is > 64 bit due to
148 	 * ULPI design.
149 	 */
150 	priv->ulpi_vp.viewport_addr = (phys_addr_t)&priv->ehci->ulpi_viewpoint;
151 
152 	return 0;
153 }
154 
ehci_usb_of_bind(struct udevice * dev)155 static int ehci_usb_of_bind(struct udevice *dev)
156 {
157 	ofnode ulpi_node = ofnode_first_subnode(dev_ofnode(dev));
158 	ofnode phy_node;
159 
160 	if (!ofnode_valid(ulpi_node))
161 		return 0;
162 
163 	phy_node = ofnode_first_subnode(ulpi_node);
164 	if (!ofnode_valid(phy_node)) {
165 		printf("%s: ulpi subnode with no phy\n", __func__);
166 		return -ENOENT;
167 	}
168 
169 	return device_bind_driver_to_node(dev, "msm8916_usbphy", "msm8916_usbphy",
170 					  phy_node, NULL);
171 }
172 
173 #if defined(CONFIG_CI_UDC)
174 /* Little quirk that MSM needs with Chipidea controller
175  * Must reinit phy after reset
176  */
ci_init_after_reset(struct ehci_ctrl * ctrl)177 void ci_init_after_reset(struct ehci_ctrl *ctrl)
178 {
179 	struct msm_ehci_priv *p = ctrl->priv;
180 
181 	generic_phy_reset(&p->phy);
182 }
183 #endif
184 
185 static const struct udevice_id ehci_usb_ids[] = {
186 	{ .compatible = "qcom,ci-hdrc", },
187 	{ }
188 };
189 
190 U_BOOT_DRIVER(usb_ehci) = {
191 	.name	= "ehci_msm",
192 	.id	= UCLASS_USB,
193 	.of_match = ehci_usb_ids,
194 	.of_to_plat = ehci_usb_of_to_plat,
195 	.bind = ehci_usb_of_bind,
196 	.probe = ehci_usb_probe,
197 	.remove = ehci_usb_remove,
198 	.ops	= &ehci_usb_ops,
199 	.priv_auto	= sizeof(struct msm_ehci_priv),
200 	.plat_auto	= sizeof(struct usb_plat),
201 	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
202 };
203