xref: /rk3399_rockchip-uboot/drivers/usb/host/ehci-generic.c (revision b653780c2135093a5cc09169bce5b4e9c6d59b46)
190fbb282SAlexey Brodkin /*
290fbb282SAlexey Brodkin  * Copyright (C) 2015 Alexey Brodkin <abrodkin@synopsys.com>
390fbb282SAlexey Brodkin  *
490fbb282SAlexey Brodkin  * SPDX-License-Identifier:	GPL-2.0+
590fbb282SAlexey Brodkin  */
690fbb282SAlexey Brodkin 
790fbb282SAlexey Brodkin #include <common.h>
84feefdcfSMasahiro Yamada #include <clk.h>
9a1cee8e8SPatrice Chotard #include <dm/ofnode.h>
100d0ba1a7SPatrice Chotard #include <generic-phy.h>
118824cfc1SMasahiro Yamada #include <reset.h>
12643cacb6SMarek Vasut #include <asm/io.h>
1390fbb282SAlexey Brodkin #include <dm.h>
1490fbb282SAlexey Brodkin #include "ehci.h"
1590fbb282SAlexey Brodkin 
1690fbb282SAlexey Brodkin /*
1790fbb282SAlexey Brodkin  * Even though here we don't explicitly use "struct ehci_ctrl"
1890fbb282SAlexey Brodkin  * ehci_register() expects it to be the first thing that resides in
1990fbb282SAlexey Brodkin  * device's private data.
2090fbb282SAlexey Brodkin  */
2190fbb282SAlexey Brodkin struct generic_ehci {
2290fbb282SAlexey Brodkin 	struct ehci_ctrl ctrl;
23a1cee8e8SPatrice Chotard 	struct clk *clocks;
24a1cee8e8SPatrice Chotard 	struct reset_ctl *resets;
250d0ba1a7SPatrice Chotard 	struct phy phy;
26a1cee8e8SPatrice Chotard 	int clock_count;
27a1cee8e8SPatrice Chotard 	int reset_count;
2890fbb282SAlexey Brodkin };
2990fbb282SAlexey Brodkin 
30f06fcfdeSPatrice Chotard static int ehci_setup_phy(struct udevice *dev, int index)
31f06fcfdeSPatrice Chotard {
32f06fcfdeSPatrice Chotard 	struct generic_ehci *priv = dev_get_priv(dev);
33f06fcfdeSPatrice Chotard 	int ret;
34f06fcfdeSPatrice Chotard 
35f06fcfdeSPatrice Chotard 	ret = generic_phy_get_by_index(dev, index, &priv->phy);
36f06fcfdeSPatrice Chotard 	if (ret) {
37f06fcfdeSPatrice Chotard 		if (ret != -ENOENT) {
38f06fcfdeSPatrice Chotard 			dev_err(dev, "failed to get usb phy\n");
39f06fcfdeSPatrice Chotard 			return ret;
40f06fcfdeSPatrice Chotard 		}
41f06fcfdeSPatrice Chotard 	} else {
42f06fcfdeSPatrice Chotard 		ret = generic_phy_init(&priv->phy);
43f06fcfdeSPatrice Chotard 		if (ret) {
44f06fcfdeSPatrice Chotard 			dev_err(dev, "failed to init usb phy\n");
45f06fcfdeSPatrice Chotard 			return ret;
46f06fcfdeSPatrice Chotard 		}
47f06fcfdeSPatrice Chotard 
48f06fcfdeSPatrice Chotard 		ret = generic_phy_power_on(&priv->phy);
49f06fcfdeSPatrice Chotard 		if (ret) {
50f06fcfdeSPatrice Chotard 			dev_err(dev, "failed to power on usb phy\n");
51f06fcfdeSPatrice Chotard 			return generic_phy_exit(&priv->phy);
52f06fcfdeSPatrice Chotard 		}
53f06fcfdeSPatrice Chotard 	}
54f06fcfdeSPatrice Chotard 
55f06fcfdeSPatrice Chotard 	return 0;
56f06fcfdeSPatrice Chotard }
57f06fcfdeSPatrice Chotard 
58f06fcfdeSPatrice Chotard static int ehci_shutdown_phy(struct udevice *dev)
59f06fcfdeSPatrice Chotard {
60f06fcfdeSPatrice Chotard 	struct generic_ehci *priv = dev_get_priv(dev);
61f06fcfdeSPatrice Chotard 	int ret = 0;
62f06fcfdeSPatrice Chotard 
63f06fcfdeSPatrice Chotard 	if (generic_phy_valid(&priv->phy)) {
64f06fcfdeSPatrice Chotard 		ret = generic_phy_power_off(&priv->phy);
65f06fcfdeSPatrice Chotard 		if (ret) {
66f06fcfdeSPatrice Chotard 			dev_err(dev, "failed to power off usb phy\n");
67f06fcfdeSPatrice Chotard 			return ret;
68f06fcfdeSPatrice Chotard 		}
69f06fcfdeSPatrice Chotard 
70f06fcfdeSPatrice Chotard 		ret = generic_phy_exit(&priv->phy);
71f06fcfdeSPatrice Chotard 		if (ret) {
72f06fcfdeSPatrice Chotard 			dev_err(dev, "failed to power off usb phy\n");
73f06fcfdeSPatrice Chotard 			return ret;
74f06fcfdeSPatrice Chotard 		}
75f06fcfdeSPatrice Chotard 	}
76f06fcfdeSPatrice Chotard 
77f06fcfdeSPatrice Chotard 	return 0;
78f06fcfdeSPatrice Chotard }
79f06fcfdeSPatrice Chotard 
8090fbb282SAlexey Brodkin static int ehci_usb_probe(struct udevice *dev)
8190fbb282SAlexey Brodkin {
82a1cee8e8SPatrice Chotard 	struct generic_ehci *priv = dev_get_priv(dev);
83643cacb6SMarek Vasut 	struct ehci_hccr *hccr;
8490fbb282SAlexey Brodkin 	struct ehci_hcor *hcor;
85a1cee8e8SPatrice Chotard 	int i, err, ret, clock_nb, reset_nb;
864feefdcfSMasahiro Yamada 
87a1cee8e8SPatrice Chotard 	err = 0;
88a1cee8e8SPatrice Chotard 	priv->clock_count = 0;
89a1cee8e8SPatrice Chotard 	clock_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "clocks",
90a1cee8e8SPatrice Chotard 						  "#clock-cells");
91a1cee8e8SPatrice Chotard 	if (clock_nb > 0) {
92a1cee8e8SPatrice Chotard 		priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk),
93a1cee8e8SPatrice Chotard 					    GFP_KERNEL);
94a1cee8e8SPatrice Chotard 		if (!priv->clocks)
95a1cee8e8SPatrice Chotard 			return -ENOMEM;
964feefdcfSMasahiro Yamada 
97a1cee8e8SPatrice Chotard 		for (i = 0; i < clock_nb; i++) {
98a1cee8e8SPatrice Chotard 			err = clk_get_by_index(dev, i, &priv->clocks[i]);
99a1cee8e8SPatrice Chotard 
100a1cee8e8SPatrice Chotard 			if (err < 0)
1014feefdcfSMasahiro Yamada 				break;
102a1cee8e8SPatrice Chotard 			err = clk_enable(&priv->clocks[i]);
103*b653780cSPatrice Chotard 			if (err) {
104*b653780cSPatrice Chotard 				dev_err(dev, "failed to enable clock %d\n", i);
105a1cee8e8SPatrice Chotard 				clk_free(&priv->clocks[i]);
106a1cee8e8SPatrice Chotard 				goto clk_err;
107a1cee8e8SPatrice Chotard 			}
108a1cee8e8SPatrice Chotard 			priv->clock_count++;
109a1cee8e8SPatrice Chotard 		}
110a1cee8e8SPatrice Chotard 	} else {
111a1cee8e8SPatrice Chotard 		if (clock_nb != -ENOENT) {
112*b653780cSPatrice Chotard 			dev_err(dev, "failed to get clock phandle(%d)\n",
113*b653780cSPatrice Chotard 				clock_nb);
114a1cee8e8SPatrice Chotard 			return clock_nb;
115a1cee8e8SPatrice Chotard 		}
1164feefdcfSMasahiro Yamada 	}
11790fbb282SAlexey Brodkin 
118a1cee8e8SPatrice Chotard 	priv->reset_count = 0;
119a1cee8e8SPatrice Chotard 	reset_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "resets",
120a1cee8e8SPatrice Chotard 						  "#reset-cells");
121a1cee8e8SPatrice Chotard 	if (reset_nb > 0) {
122a1cee8e8SPatrice Chotard 		priv->resets = devm_kcalloc(dev, reset_nb,
123a1cee8e8SPatrice Chotard 					    sizeof(struct reset_ctl),
124a1cee8e8SPatrice Chotard 					    GFP_KERNEL);
125a1cee8e8SPatrice Chotard 		if (!priv->resets)
126a1cee8e8SPatrice Chotard 			return -ENOMEM;
1278824cfc1SMasahiro Yamada 
128a1cee8e8SPatrice Chotard 		for (i = 0; i < reset_nb; i++) {
129a1cee8e8SPatrice Chotard 			err = reset_get_by_index(dev, i, &priv->resets[i]);
130a1cee8e8SPatrice Chotard 			if (err < 0)
1318824cfc1SMasahiro Yamada 				break;
132a1cee8e8SPatrice Chotard 
133a1cee8e8SPatrice Chotard 			if (reset_deassert(&priv->resets[i])) {
134*b653780cSPatrice Chotard 				dev_err(dev, "failed to deassert reset %d\n",
135*b653780cSPatrice Chotard 					i);
136a1cee8e8SPatrice Chotard 				reset_free(&priv->resets[i]);
137a1cee8e8SPatrice Chotard 				goto reset_err;
138a1cee8e8SPatrice Chotard 			}
139a1cee8e8SPatrice Chotard 			priv->reset_count++;
140a1cee8e8SPatrice Chotard 		}
141a1cee8e8SPatrice Chotard 	} else {
142a1cee8e8SPatrice Chotard 		if (reset_nb != -ENOENT) {
143*b653780cSPatrice Chotard 			dev_err(dev, "failed to get reset phandle(%d)\n",
144*b653780cSPatrice Chotard 				reset_nb);
145a1cee8e8SPatrice Chotard 			goto clk_err;
146a1cee8e8SPatrice Chotard 		}
1478824cfc1SMasahiro Yamada 	}
1488824cfc1SMasahiro Yamada 
149f06fcfdeSPatrice Chotard 	err = ehci_setup_phy(dev, 0);
150f06fcfdeSPatrice Chotard 	if (err)
1510d0ba1a7SPatrice Chotard 		goto reset_err;
1520d0ba1a7SPatrice Chotard 
15397ff91faSPhilipp Tomsich 	hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE);
15490fbb282SAlexey Brodkin 	hcor = (struct ehci_hcor *)((uintptr_t)hccr +
15590fbb282SAlexey Brodkin 				    HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
15690fbb282SAlexey Brodkin 
157a1cee8e8SPatrice Chotard 	err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
158a1cee8e8SPatrice Chotard 	if (err)
1590d0ba1a7SPatrice Chotard 		goto phy_err;
160a1cee8e8SPatrice Chotard 
161a1cee8e8SPatrice Chotard 	return 0;
162a1cee8e8SPatrice Chotard 
1630d0ba1a7SPatrice Chotard phy_err:
164f06fcfdeSPatrice Chotard 	ret = ehci_shutdown_phy(dev);
1653d54c056SPatrice Chotard 	if (ret)
166f06fcfdeSPatrice Chotard 		dev_err(dev, "failed to shutdown usb phy\n");
1670d0ba1a7SPatrice Chotard 
168a1cee8e8SPatrice Chotard reset_err:
169a1cee8e8SPatrice Chotard 	ret = reset_release_all(priv->resets, priv->reset_count);
170a1cee8e8SPatrice Chotard 	if (ret)
171*b653780cSPatrice Chotard 		dev_err(dev, "failed to assert all resets\n");
172a1cee8e8SPatrice Chotard clk_err:
173a1cee8e8SPatrice Chotard 	ret = clk_release_all(priv->clocks, priv->clock_count);
174a1cee8e8SPatrice Chotard 	if (ret)
175*b653780cSPatrice Chotard 		dev_err(dev, "failed to disable all clocks\n");
176a1cee8e8SPatrice Chotard 
177a1cee8e8SPatrice Chotard 	return err;
178a1cee8e8SPatrice Chotard }
179a1cee8e8SPatrice Chotard 
180a1cee8e8SPatrice Chotard static int ehci_usb_remove(struct udevice *dev)
181a1cee8e8SPatrice Chotard {
182a1cee8e8SPatrice Chotard 	struct generic_ehci *priv = dev_get_priv(dev);
183a1cee8e8SPatrice Chotard 	int ret;
184a1cee8e8SPatrice Chotard 
185a1cee8e8SPatrice Chotard 	ret = ehci_deregister(dev);
186a1cee8e8SPatrice Chotard 	if (ret)
187a1cee8e8SPatrice Chotard 		return ret;
188a1cee8e8SPatrice Chotard 
189f06fcfdeSPatrice Chotard 	ret = ehci_shutdown_phy(dev);
1903d54c056SPatrice Chotard 	if (ret)
1913d54c056SPatrice Chotard 		return ret;
1923d54c056SPatrice Chotard 
193a1cee8e8SPatrice Chotard 	ret =  reset_release_all(priv->resets, priv->reset_count);
194a1cee8e8SPatrice Chotard 	if (ret)
195a1cee8e8SPatrice Chotard 		return ret;
196a1cee8e8SPatrice Chotard 
197a1cee8e8SPatrice Chotard 	return clk_release_all(priv->clocks, priv->clock_count);
19890fbb282SAlexey Brodkin }
19990fbb282SAlexey Brodkin 
20090fbb282SAlexey Brodkin static const struct udevice_id ehci_usb_ids[] = {
20190fbb282SAlexey Brodkin 	{ .compatible = "generic-ehci" },
20290fbb282SAlexey Brodkin 	{ }
20390fbb282SAlexey Brodkin };
20490fbb282SAlexey Brodkin 
20590fbb282SAlexey Brodkin U_BOOT_DRIVER(ehci_generic) = {
20690fbb282SAlexey Brodkin 	.name	= "ehci_generic",
20790fbb282SAlexey Brodkin 	.id	= UCLASS_USB,
20890fbb282SAlexey Brodkin 	.of_match = ehci_usb_ids,
20990fbb282SAlexey Brodkin 	.probe = ehci_usb_probe,
210a1cee8e8SPatrice Chotard 	.remove = ehci_usb_remove,
21190fbb282SAlexey Brodkin 	.ops	= &ehci_usb_ops,
21290fbb282SAlexey Brodkin 	.priv_auto_alloc_size = sizeof(struct generic_ehci),
21390fbb282SAlexey Brodkin 	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
21490fbb282SAlexey Brodkin };
215