xref: /rk3399_rockchip-uboot/drivers/usb/host/ehci-generic.c (revision 1a4f6af8bfd44c8ae6e87a81ff125eed47042cc5)
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"
154e900a7dSPatrice Chotard #include <power/regulator.h>
1690fbb282SAlexey Brodkin 
1790fbb282SAlexey Brodkin /*
1890fbb282SAlexey Brodkin  * Even though here we don't explicitly use "struct ehci_ctrl"
1990fbb282SAlexey Brodkin  * ehci_register() expects it to be the first thing that resides in
2090fbb282SAlexey Brodkin  * device's private data.
2190fbb282SAlexey Brodkin  */
2290fbb282SAlexey Brodkin struct generic_ehci {
2390fbb282SAlexey Brodkin 	struct ehci_ctrl ctrl;
24a1cee8e8SPatrice Chotard 	struct clk *clocks;
25a1cee8e8SPatrice Chotard 	struct reset_ctl *resets;
260d0ba1a7SPatrice Chotard 	struct phy phy;
274e900a7dSPatrice Chotard #ifdef CONFIG_DM_REGULATOR
284e900a7dSPatrice Chotard 	struct udevice *vbus_supply;
294e900a7dSPatrice Chotard #endif
30a1cee8e8SPatrice Chotard 	int clock_count;
31a1cee8e8SPatrice Chotard 	int reset_count;
3290fbb282SAlexey Brodkin };
3390fbb282SAlexey Brodkin 
344e900a7dSPatrice Chotard #ifdef CONFIG_DM_REGULATOR
ehci_enable_vbus_supply(struct udevice * dev)354e900a7dSPatrice Chotard static int ehci_enable_vbus_supply(struct udevice *dev)
364e900a7dSPatrice Chotard {
374e900a7dSPatrice Chotard 	struct generic_ehci *priv = dev_get_priv(dev);
384e900a7dSPatrice Chotard 	int ret;
394e900a7dSPatrice Chotard 
404e900a7dSPatrice Chotard 	ret = device_get_supply_regulator(dev, "vbus-supply",
414e900a7dSPatrice Chotard 					  &priv->vbus_supply);
424e900a7dSPatrice Chotard 	if (ret && ret != -ENOENT)
434e900a7dSPatrice Chotard 		return ret;
444e900a7dSPatrice Chotard 
454e900a7dSPatrice Chotard 	if (priv->vbus_supply) {
464e900a7dSPatrice Chotard 		ret = regulator_set_enable(priv->vbus_supply, true);
474e900a7dSPatrice Chotard 		if (ret) {
484e900a7dSPatrice Chotard 			dev_err(dev, "Error enabling VBUS supply\n");
494e900a7dSPatrice Chotard 			return ret;
504e900a7dSPatrice Chotard 		}
514e900a7dSPatrice Chotard 	} else {
524e900a7dSPatrice Chotard 		dev_dbg(dev, "No vbus supply\n");
534e900a7dSPatrice Chotard 	}
544e900a7dSPatrice Chotard 
554e900a7dSPatrice Chotard 	return 0;
564e900a7dSPatrice Chotard }
574e900a7dSPatrice Chotard 
ehci_disable_vbus_supply(struct generic_ehci * priv)584e900a7dSPatrice Chotard static int ehci_disable_vbus_supply(struct generic_ehci *priv)
594e900a7dSPatrice Chotard {
604e900a7dSPatrice Chotard 	if (priv->vbus_supply)
614e900a7dSPatrice Chotard 		return regulator_set_enable(priv->vbus_supply, false);
624e900a7dSPatrice Chotard 	else
634e900a7dSPatrice Chotard 		return 0;
644e900a7dSPatrice Chotard }
654e900a7dSPatrice Chotard #else
ehci_enable_vbus_supply(struct udevice * dev)664e900a7dSPatrice Chotard static int ehci_enable_vbus_supply(struct udevice *dev)
674e900a7dSPatrice Chotard {
684e900a7dSPatrice Chotard 	return 0;
694e900a7dSPatrice Chotard }
704e900a7dSPatrice Chotard 
ehci_disable_vbus_supply(struct generic_ehci * priv)714e900a7dSPatrice Chotard static int ehci_disable_vbus_supply(struct generic_ehci *priv)
724e900a7dSPatrice Chotard {
734e900a7dSPatrice Chotard 	return 0;
744e900a7dSPatrice Chotard }
754e900a7dSPatrice Chotard #endif
764e900a7dSPatrice Chotard 
ehci_usb_probe(struct udevice * dev)7790fbb282SAlexey Brodkin static int ehci_usb_probe(struct udevice *dev)
7890fbb282SAlexey Brodkin {
79a1cee8e8SPatrice Chotard 	struct generic_ehci *priv = dev_get_priv(dev);
80643cacb6SMarek Vasut 	struct ehci_hccr *hccr;
8190fbb282SAlexey Brodkin 	struct ehci_hcor *hcor;
82a1cee8e8SPatrice Chotard 	int i, err, ret, clock_nb, reset_nb;
834feefdcfSMasahiro Yamada 
84a1cee8e8SPatrice Chotard 	err = 0;
85a1cee8e8SPatrice Chotard 	priv->clock_count = 0;
86a1cee8e8SPatrice Chotard 	clock_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "clocks",
87a1cee8e8SPatrice Chotard 						  "#clock-cells");
88a1cee8e8SPatrice Chotard 	if (clock_nb > 0) {
89a1cee8e8SPatrice Chotard 		priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk),
90a1cee8e8SPatrice Chotard 					    GFP_KERNEL);
91a1cee8e8SPatrice Chotard 		if (!priv->clocks)
92a1cee8e8SPatrice Chotard 			return -ENOMEM;
934feefdcfSMasahiro Yamada 
94a1cee8e8SPatrice Chotard 		for (i = 0; i < clock_nb; i++) {
95a1cee8e8SPatrice Chotard 			err = clk_get_by_index(dev, i, &priv->clocks[i]);
96a1cee8e8SPatrice Chotard 
97a1cee8e8SPatrice Chotard 			if (err < 0)
984feefdcfSMasahiro Yamada 				break;
99a1cee8e8SPatrice Chotard 			err = clk_enable(&priv->clocks[i]);
100*5311a685SKever Yang 			if (err && err != -ENOSYS) {
101b653780cSPatrice Chotard 				dev_err(dev, "failed to enable clock %d\n", i);
102a1cee8e8SPatrice Chotard 				clk_free(&priv->clocks[i]);
103a1cee8e8SPatrice Chotard 				goto clk_err;
104a1cee8e8SPatrice Chotard 			}
105a1cee8e8SPatrice Chotard 			priv->clock_count++;
106a1cee8e8SPatrice Chotard 		}
107a1cee8e8SPatrice Chotard 	} else {
108a1cee8e8SPatrice Chotard 		if (clock_nb != -ENOENT) {
109b653780cSPatrice Chotard 			dev_err(dev, "failed to get clock phandle(%d)\n",
110b653780cSPatrice Chotard 				clock_nb);
111a1cee8e8SPatrice Chotard 			return clock_nb;
112a1cee8e8SPatrice Chotard 		}
1134feefdcfSMasahiro Yamada 	}
11490fbb282SAlexey Brodkin 
115a1cee8e8SPatrice Chotard 	priv->reset_count = 0;
116a1cee8e8SPatrice Chotard 	reset_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "resets",
117a1cee8e8SPatrice Chotard 						  "#reset-cells");
118a1cee8e8SPatrice Chotard 	if (reset_nb > 0) {
119a1cee8e8SPatrice Chotard 		priv->resets = devm_kcalloc(dev, reset_nb,
120a1cee8e8SPatrice Chotard 					    sizeof(struct reset_ctl),
121a1cee8e8SPatrice Chotard 					    GFP_KERNEL);
122a1cee8e8SPatrice Chotard 		if (!priv->resets)
123a1cee8e8SPatrice Chotard 			return -ENOMEM;
1248824cfc1SMasahiro Yamada 
125a1cee8e8SPatrice Chotard 		for (i = 0; i < reset_nb; i++) {
126a1cee8e8SPatrice Chotard 			err = reset_get_by_index(dev, i, &priv->resets[i]);
127a1cee8e8SPatrice Chotard 			if (err < 0)
1288824cfc1SMasahiro Yamada 				break;
129a1cee8e8SPatrice Chotard 
130a1cee8e8SPatrice Chotard 			if (reset_deassert(&priv->resets[i])) {
131b653780cSPatrice Chotard 				dev_err(dev, "failed to deassert reset %d\n",
132b653780cSPatrice Chotard 					i);
133a1cee8e8SPatrice Chotard 				reset_free(&priv->resets[i]);
134a1cee8e8SPatrice Chotard 				goto reset_err;
135a1cee8e8SPatrice Chotard 			}
136a1cee8e8SPatrice Chotard 			priv->reset_count++;
137a1cee8e8SPatrice Chotard 		}
138a1cee8e8SPatrice Chotard 	} else {
139a1cee8e8SPatrice Chotard 		if (reset_nb != -ENOENT) {
140b653780cSPatrice Chotard 			dev_err(dev, "failed to get reset phandle(%d)\n",
141b653780cSPatrice Chotard 				reset_nb);
142a1cee8e8SPatrice Chotard 			goto clk_err;
143a1cee8e8SPatrice Chotard 		}
1448824cfc1SMasahiro Yamada 	}
1458824cfc1SMasahiro Yamada 
1464e900a7dSPatrice Chotard 	err = ehci_enable_vbus_supply(dev);
147f06fcfdeSPatrice Chotard 	if (err)
1480d0ba1a7SPatrice Chotard 		goto reset_err;
1490d0ba1a7SPatrice Chotard 
1504e900a7dSPatrice Chotard 	err = ehci_setup_phy(dev, &priv->phy, 0);
1514e900a7dSPatrice Chotard 	if (err)
1524e900a7dSPatrice Chotard 		goto regulator_err;
1534e900a7dSPatrice Chotard 
15497ff91faSPhilipp Tomsich 	hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE);
15590fbb282SAlexey Brodkin 	hcor = (struct ehci_hcor *)((uintptr_t)hccr +
15690fbb282SAlexey Brodkin 				    HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
15790fbb282SAlexey Brodkin 
158a1cee8e8SPatrice Chotard 	err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
159a1cee8e8SPatrice Chotard 	if (err)
1600d0ba1a7SPatrice Chotard 		goto phy_err;
161a1cee8e8SPatrice Chotard 
162a1cee8e8SPatrice Chotard 	return 0;
163a1cee8e8SPatrice Chotard 
1640d0ba1a7SPatrice Chotard phy_err:
165f5439a16SMarek Vasut 	ret = ehci_shutdown_phy(dev, &priv->phy);
1663d54c056SPatrice Chotard 	if (ret)
167f06fcfdeSPatrice Chotard 		dev_err(dev, "failed to shutdown usb phy\n");
1680d0ba1a7SPatrice Chotard 
1694e900a7dSPatrice Chotard regulator_err:
1704e900a7dSPatrice Chotard 	ret = ehci_disable_vbus_supply(priv);
1714e900a7dSPatrice Chotard 	if (ret)
1724e900a7dSPatrice Chotard 		dev_err(dev, "failed to disable VBUS supply\n");
1734e900a7dSPatrice Chotard 
174a1cee8e8SPatrice Chotard reset_err:
175a1cee8e8SPatrice Chotard 	ret = reset_release_all(priv->resets, priv->reset_count);
176a1cee8e8SPatrice Chotard 	if (ret)
177b653780cSPatrice Chotard 		dev_err(dev, "failed to assert all resets\n");
178a1cee8e8SPatrice Chotard clk_err:
179a1cee8e8SPatrice Chotard 	ret = clk_release_all(priv->clocks, priv->clock_count);
180a1cee8e8SPatrice Chotard 	if (ret)
181b653780cSPatrice Chotard 		dev_err(dev, "failed to disable all clocks\n");
182a1cee8e8SPatrice Chotard 
183a1cee8e8SPatrice Chotard 	return err;
184a1cee8e8SPatrice Chotard }
185a1cee8e8SPatrice Chotard 
ehci_usb_remove(struct udevice * dev)186a1cee8e8SPatrice Chotard static int ehci_usb_remove(struct udevice *dev)
187a1cee8e8SPatrice Chotard {
188a1cee8e8SPatrice Chotard 	struct generic_ehci *priv = dev_get_priv(dev);
189a1cee8e8SPatrice Chotard 	int ret;
190a1cee8e8SPatrice Chotard 
191a1cee8e8SPatrice Chotard 	ret = ehci_deregister(dev);
192a1cee8e8SPatrice Chotard 	if (ret)
193a1cee8e8SPatrice Chotard 		return ret;
194a1cee8e8SPatrice Chotard 
195f5439a16SMarek Vasut 	ret = ehci_shutdown_phy(dev, &priv->phy);
1963d54c056SPatrice Chotard 	if (ret)
1973d54c056SPatrice Chotard 		return ret;
1983d54c056SPatrice Chotard 
1994e900a7dSPatrice Chotard 	ret = ehci_disable_vbus_supply(priv);
2004e900a7dSPatrice Chotard 	if (ret)
2014e900a7dSPatrice Chotard 		return ret;
2024e900a7dSPatrice Chotard 
203a1cee8e8SPatrice Chotard 	ret =  reset_release_all(priv->resets, priv->reset_count);
204a1cee8e8SPatrice Chotard 	if (ret)
205a1cee8e8SPatrice Chotard 		return ret;
206a1cee8e8SPatrice Chotard 
207a1cee8e8SPatrice Chotard 	return clk_release_all(priv->clocks, priv->clock_count);
20890fbb282SAlexey Brodkin }
20990fbb282SAlexey Brodkin 
21090fbb282SAlexey Brodkin static const struct udevice_id ehci_usb_ids[] = {
21190fbb282SAlexey Brodkin 	{ .compatible = "generic-ehci" },
21290fbb282SAlexey Brodkin 	{ }
21390fbb282SAlexey Brodkin };
21490fbb282SAlexey Brodkin 
21590fbb282SAlexey Brodkin U_BOOT_DRIVER(ehci_generic) = {
21690fbb282SAlexey Brodkin 	.name	= "ehci_generic",
21790fbb282SAlexey Brodkin 	.id	= UCLASS_USB,
21890fbb282SAlexey Brodkin 	.of_match = ehci_usb_ids,
21990fbb282SAlexey Brodkin 	.probe = ehci_usb_probe,
220a1cee8e8SPatrice Chotard 	.remove = ehci_usb_remove,
22190fbb282SAlexey Brodkin 	.ops	= &ehci_usb_ops,
22290fbb282SAlexey Brodkin 	.priv_auto_alloc_size = sizeof(struct generic_ehci),
22390fbb282SAlexey Brodkin 	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
22490fbb282SAlexey Brodkin };
225