xref: /rk3399_rockchip-uboot/drivers/usb/host/ehci-generic.c (revision f06fcfdecf5b05ec6e73a93ee11e215b7c27269d)
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 
30*f06fcfdeSPatrice Chotard static int ehci_setup_phy(struct udevice *dev, int index)
31*f06fcfdeSPatrice Chotard {
32*f06fcfdeSPatrice Chotard 	struct generic_ehci *priv = dev_get_priv(dev);
33*f06fcfdeSPatrice Chotard 	int ret;
34*f06fcfdeSPatrice Chotard 
35*f06fcfdeSPatrice Chotard 	ret = generic_phy_get_by_index(dev, index, &priv->phy);
36*f06fcfdeSPatrice Chotard 	if (ret) {
37*f06fcfdeSPatrice Chotard 		if (ret != -ENOENT) {
38*f06fcfdeSPatrice Chotard 			dev_err(dev, "failed to get usb phy\n");
39*f06fcfdeSPatrice Chotard 			return ret;
40*f06fcfdeSPatrice Chotard 		}
41*f06fcfdeSPatrice Chotard 	} else {
42*f06fcfdeSPatrice Chotard 		ret = generic_phy_init(&priv->phy);
43*f06fcfdeSPatrice Chotard 		if (ret) {
44*f06fcfdeSPatrice Chotard 			dev_err(dev, "failed to init usb phy\n");
45*f06fcfdeSPatrice Chotard 			return ret;
46*f06fcfdeSPatrice Chotard 		}
47*f06fcfdeSPatrice Chotard 
48*f06fcfdeSPatrice Chotard 		ret = generic_phy_power_on(&priv->phy);
49*f06fcfdeSPatrice Chotard 		if (ret) {
50*f06fcfdeSPatrice Chotard 			dev_err(dev, "failed to power on usb phy\n");
51*f06fcfdeSPatrice Chotard 			return generic_phy_exit(&priv->phy);
52*f06fcfdeSPatrice Chotard 		}
53*f06fcfdeSPatrice Chotard 	}
54*f06fcfdeSPatrice Chotard 
55*f06fcfdeSPatrice Chotard 	return 0;
56*f06fcfdeSPatrice Chotard }
57*f06fcfdeSPatrice Chotard 
58*f06fcfdeSPatrice Chotard static int ehci_shutdown_phy(struct udevice *dev)
59*f06fcfdeSPatrice Chotard {
60*f06fcfdeSPatrice Chotard 	struct generic_ehci *priv = dev_get_priv(dev);
61*f06fcfdeSPatrice Chotard 	int ret = 0;
62*f06fcfdeSPatrice Chotard 
63*f06fcfdeSPatrice Chotard 	if (generic_phy_valid(&priv->phy)) {
64*f06fcfdeSPatrice Chotard 		ret = generic_phy_power_off(&priv->phy);
65*f06fcfdeSPatrice Chotard 		if (ret) {
66*f06fcfdeSPatrice Chotard 			dev_err(dev, "failed to power off usb phy\n");
67*f06fcfdeSPatrice Chotard 			return ret;
68*f06fcfdeSPatrice Chotard 		}
69*f06fcfdeSPatrice Chotard 
70*f06fcfdeSPatrice Chotard 		ret = generic_phy_exit(&priv->phy);
71*f06fcfdeSPatrice Chotard 		if (ret) {
72*f06fcfdeSPatrice Chotard 			dev_err(dev, "failed to power off usb phy\n");
73*f06fcfdeSPatrice Chotard 			return ret;
74*f06fcfdeSPatrice Chotard 		}
75*f06fcfdeSPatrice Chotard 	}
76*f06fcfdeSPatrice Chotard 
77*f06fcfdeSPatrice Chotard 	return 0;
78*f06fcfdeSPatrice Chotard }
79*f06fcfdeSPatrice 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]);
103d2e45d1fSFrank Wang 			if (err && err != -ENOSYS) {
10490aa625cSMasahiro Yamada 				pr_err("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) {
11290aa625cSMasahiro Yamada 			pr_err("failed to get clock phandle(%d)\n", clock_nb);
113a1cee8e8SPatrice Chotard 			return clock_nb;
114a1cee8e8SPatrice Chotard 		}
1154feefdcfSMasahiro Yamada 	}
11690fbb282SAlexey Brodkin 
117a1cee8e8SPatrice Chotard 	priv->reset_count = 0;
118a1cee8e8SPatrice Chotard 	reset_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "resets",
119a1cee8e8SPatrice Chotard 						  "#reset-cells");
120a1cee8e8SPatrice Chotard 	if (reset_nb > 0) {
121a1cee8e8SPatrice Chotard 		priv->resets = devm_kcalloc(dev, reset_nb,
122a1cee8e8SPatrice Chotard 					    sizeof(struct reset_ctl),
123a1cee8e8SPatrice Chotard 					    GFP_KERNEL);
124a1cee8e8SPatrice Chotard 		if (!priv->resets)
125a1cee8e8SPatrice Chotard 			return -ENOMEM;
1268824cfc1SMasahiro Yamada 
127a1cee8e8SPatrice Chotard 		for (i = 0; i < reset_nb; i++) {
128a1cee8e8SPatrice Chotard 			err = reset_get_by_index(dev, i, &priv->resets[i]);
129a1cee8e8SPatrice Chotard 			if (err < 0)
1308824cfc1SMasahiro Yamada 				break;
131a1cee8e8SPatrice Chotard 
132a1cee8e8SPatrice Chotard 			if (reset_deassert(&priv->resets[i])) {
13390aa625cSMasahiro Yamada 				pr_err("failed to deassert reset %d\n", i);
134a1cee8e8SPatrice Chotard 				reset_free(&priv->resets[i]);
135a1cee8e8SPatrice Chotard 				goto reset_err;
136a1cee8e8SPatrice Chotard 			}
137a1cee8e8SPatrice Chotard 			priv->reset_count++;
138a1cee8e8SPatrice Chotard 		}
139a1cee8e8SPatrice Chotard 	} else {
140a1cee8e8SPatrice Chotard 		if (reset_nb != -ENOENT) {
14190aa625cSMasahiro Yamada 			pr_err("failed to get reset phandle(%d)\n", reset_nb);
142a1cee8e8SPatrice Chotard 			goto clk_err;
143a1cee8e8SPatrice Chotard 		}
1448824cfc1SMasahiro Yamada 	}
1458824cfc1SMasahiro Yamada 
146*f06fcfdeSPatrice Chotard 	err = ehci_setup_phy(dev, 0);
147*f06fcfdeSPatrice Chotard 	if (err)
1480d0ba1a7SPatrice Chotard 
1490d0ba1a7SPatrice Chotard 		goto reset_err;
1500d0ba1a7SPatrice Chotard 
15197ff91faSPhilipp Tomsich 	hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE);
15290fbb282SAlexey Brodkin 	hcor = (struct ehci_hcor *)((uintptr_t)hccr +
15390fbb282SAlexey Brodkin 				    HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
15490fbb282SAlexey Brodkin 
155a1cee8e8SPatrice Chotard 	err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
156a1cee8e8SPatrice Chotard 	if (err)
1570d0ba1a7SPatrice Chotard 		goto phy_err;
158a1cee8e8SPatrice Chotard 
159a1cee8e8SPatrice Chotard 	return 0;
160a1cee8e8SPatrice Chotard 
1610d0ba1a7SPatrice Chotard phy_err:
162*f06fcfdeSPatrice Chotard 	ret = ehci_shutdown_phy(dev);
1633d54c056SPatrice Chotard 	if (ret)
164*f06fcfdeSPatrice Chotard 		dev_err(dev, "failed to shutdown usb phy\n");
1650d0ba1a7SPatrice Chotard 
166a1cee8e8SPatrice Chotard reset_err:
167a1cee8e8SPatrice Chotard 	ret = reset_release_all(priv->resets, priv->reset_count);
168a1cee8e8SPatrice Chotard 	if (ret)
16990aa625cSMasahiro Yamada 		pr_err("failed to assert all resets\n");
170a1cee8e8SPatrice Chotard clk_err:
171a1cee8e8SPatrice Chotard 	ret = clk_release_all(priv->clocks, priv->clock_count);
172a1cee8e8SPatrice Chotard 	if (ret)
17390aa625cSMasahiro Yamada 		pr_err("failed to disable all clocks\n");
174a1cee8e8SPatrice Chotard 
175a1cee8e8SPatrice Chotard 	return err;
176a1cee8e8SPatrice Chotard }
177a1cee8e8SPatrice Chotard 
178a1cee8e8SPatrice Chotard static int ehci_usb_remove(struct udevice *dev)
179a1cee8e8SPatrice Chotard {
180a1cee8e8SPatrice Chotard 	struct generic_ehci *priv = dev_get_priv(dev);
181a1cee8e8SPatrice Chotard 	int ret;
182a1cee8e8SPatrice Chotard 
183a1cee8e8SPatrice Chotard 	ret = ehci_deregister(dev);
184a1cee8e8SPatrice Chotard 	if (ret)
185a1cee8e8SPatrice Chotard 		return ret;
186a1cee8e8SPatrice Chotard 
187*f06fcfdeSPatrice Chotard 	ret = ehci_shutdown_phy(dev);
1883d54c056SPatrice Chotard 	if (ret)
1893d54c056SPatrice Chotard 		return ret;
1903d54c056SPatrice Chotard 
191a1cee8e8SPatrice Chotard 	ret =  reset_release_all(priv->resets, priv->reset_count);
192a1cee8e8SPatrice Chotard 	if (ret)
193a1cee8e8SPatrice Chotard 		return ret;
194a1cee8e8SPatrice Chotard 
195a1cee8e8SPatrice Chotard 	return clk_release_all(priv->clocks, priv->clock_count);
19690fbb282SAlexey Brodkin }
19790fbb282SAlexey Brodkin 
19890fbb282SAlexey Brodkin static const struct udevice_id ehci_usb_ids[] = {
19990fbb282SAlexey Brodkin 	{ .compatible = "generic-ehci" },
20090fbb282SAlexey Brodkin 	{ }
20190fbb282SAlexey Brodkin };
20290fbb282SAlexey Brodkin 
20390fbb282SAlexey Brodkin U_BOOT_DRIVER(ehci_generic) = {
20490fbb282SAlexey Brodkin 	.name	= "ehci_generic",
20590fbb282SAlexey Brodkin 	.id	= UCLASS_USB,
20690fbb282SAlexey Brodkin 	.of_match = ehci_usb_ids,
20790fbb282SAlexey Brodkin 	.probe = ehci_usb_probe,
208a1cee8e8SPatrice Chotard 	.remove = ehci_usb_remove,
20990fbb282SAlexey Brodkin 	.ops	= &ehci_usb_ops,
21090fbb282SAlexey Brodkin 	.priv_auto_alloc_size = sizeof(struct generic_ehci),
21190fbb282SAlexey Brodkin 	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
21290fbb282SAlexey Brodkin };
213