xref: /rk3399_rockchip-uboot/drivers/usb/host/ehci-generic.c (revision 3d54c05685e3526d0833231d2920a24fe6c8acbc)
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 
3090fbb282SAlexey Brodkin static int ehci_usb_probe(struct udevice *dev)
3190fbb282SAlexey Brodkin {
32a1cee8e8SPatrice Chotard 	struct generic_ehci *priv = dev_get_priv(dev);
33643cacb6SMarek Vasut 	struct ehci_hccr *hccr;
3490fbb282SAlexey Brodkin 	struct ehci_hcor *hcor;
35a1cee8e8SPatrice Chotard 	int i, err, ret, clock_nb, reset_nb;
364feefdcfSMasahiro Yamada 
37a1cee8e8SPatrice Chotard 	err = 0;
38a1cee8e8SPatrice Chotard 	priv->clock_count = 0;
39a1cee8e8SPatrice Chotard 	clock_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "clocks",
40a1cee8e8SPatrice Chotard 						  "#clock-cells");
41a1cee8e8SPatrice Chotard 	if (clock_nb > 0) {
42a1cee8e8SPatrice Chotard 		priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk),
43a1cee8e8SPatrice Chotard 					    GFP_KERNEL);
44a1cee8e8SPatrice Chotard 		if (!priv->clocks)
45a1cee8e8SPatrice Chotard 			return -ENOMEM;
464feefdcfSMasahiro Yamada 
47a1cee8e8SPatrice Chotard 		for (i = 0; i < clock_nb; i++) {
48a1cee8e8SPatrice Chotard 			err = clk_get_by_index(dev, i, &priv->clocks[i]);
49a1cee8e8SPatrice Chotard 
50a1cee8e8SPatrice Chotard 			if (err < 0)
514feefdcfSMasahiro Yamada 				break;
52a1cee8e8SPatrice Chotard 			err = clk_enable(&priv->clocks[i]);
53d2e45d1fSFrank Wang 			if (err && err != -ENOSYS) {
5490aa625cSMasahiro Yamada 				pr_err("failed to enable clock %d\n", i);
55a1cee8e8SPatrice Chotard 				clk_free(&priv->clocks[i]);
56a1cee8e8SPatrice Chotard 				goto clk_err;
57a1cee8e8SPatrice Chotard 			}
58a1cee8e8SPatrice Chotard 			priv->clock_count++;
59a1cee8e8SPatrice Chotard 		}
60a1cee8e8SPatrice Chotard 	} else {
61a1cee8e8SPatrice Chotard 		if (clock_nb != -ENOENT) {
6290aa625cSMasahiro Yamada 			pr_err("failed to get clock phandle(%d)\n", clock_nb);
63a1cee8e8SPatrice Chotard 			return clock_nb;
64a1cee8e8SPatrice Chotard 		}
654feefdcfSMasahiro Yamada 	}
6690fbb282SAlexey Brodkin 
67a1cee8e8SPatrice Chotard 	priv->reset_count = 0;
68a1cee8e8SPatrice Chotard 	reset_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "resets",
69a1cee8e8SPatrice Chotard 						  "#reset-cells");
70a1cee8e8SPatrice Chotard 	if (reset_nb > 0) {
71a1cee8e8SPatrice Chotard 		priv->resets = devm_kcalloc(dev, reset_nb,
72a1cee8e8SPatrice Chotard 					    sizeof(struct reset_ctl),
73a1cee8e8SPatrice Chotard 					    GFP_KERNEL);
74a1cee8e8SPatrice Chotard 		if (!priv->resets)
75a1cee8e8SPatrice Chotard 			return -ENOMEM;
768824cfc1SMasahiro Yamada 
77a1cee8e8SPatrice Chotard 		for (i = 0; i < reset_nb; i++) {
78a1cee8e8SPatrice Chotard 			err = reset_get_by_index(dev, i, &priv->resets[i]);
79a1cee8e8SPatrice Chotard 			if (err < 0)
808824cfc1SMasahiro Yamada 				break;
81a1cee8e8SPatrice Chotard 
82a1cee8e8SPatrice Chotard 			if (reset_deassert(&priv->resets[i])) {
8390aa625cSMasahiro Yamada 				pr_err("failed to deassert reset %d\n", i);
84a1cee8e8SPatrice Chotard 				reset_free(&priv->resets[i]);
85a1cee8e8SPatrice Chotard 				goto reset_err;
86a1cee8e8SPatrice Chotard 			}
87a1cee8e8SPatrice Chotard 			priv->reset_count++;
88a1cee8e8SPatrice Chotard 		}
89a1cee8e8SPatrice Chotard 	} else {
90a1cee8e8SPatrice Chotard 		if (reset_nb != -ENOENT) {
9190aa625cSMasahiro Yamada 			pr_err("failed to get reset phandle(%d)\n", reset_nb);
92a1cee8e8SPatrice Chotard 			goto clk_err;
93a1cee8e8SPatrice Chotard 		}
948824cfc1SMasahiro Yamada 	}
958824cfc1SMasahiro Yamada 
960d0ba1a7SPatrice Chotard 	err = generic_phy_get_by_index(dev, 0, &priv->phy);
970d0ba1a7SPatrice Chotard 	if (err) {
980d0ba1a7SPatrice Chotard 		if (err != -ENOENT) {
9990aa625cSMasahiro Yamada 			pr_err("failed to get usb phy\n");
1000d0ba1a7SPatrice Chotard 			goto reset_err;
1010d0ba1a7SPatrice Chotard 		}
1024b3928a0SPatrice Chotard 	} else {
1030d0ba1a7SPatrice Chotard 
1040d0ba1a7SPatrice Chotard 		err = generic_phy_init(&priv->phy);
1050d0ba1a7SPatrice Chotard 		if (err) {
10690aa625cSMasahiro Yamada 			pr_err("failed to init usb phy\n");
1070d0ba1a7SPatrice Chotard 			goto reset_err;
1080d0ba1a7SPatrice Chotard 		}
109*3d54c056SPatrice Chotard 
110*3d54c056SPatrice Chotard 		err = generic_phy_power_on(&priv->phy);
111*3d54c056SPatrice Chotard 		if (err) {
112*3d54c056SPatrice Chotard 			dev_err(dev, "failed to power on usb phy\n");
113*3d54c056SPatrice Chotard 			goto phy_power_err;
114*3d54c056SPatrice Chotard 		}
1154b3928a0SPatrice Chotard 	}
1160d0ba1a7SPatrice Chotard 
11797ff91faSPhilipp Tomsich 	hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE);
11890fbb282SAlexey Brodkin 	hcor = (struct ehci_hcor *)((uintptr_t)hccr +
11990fbb282SAlexey Brodkin 				    HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
12090fbb282SAlexey Brodkin 
121a1cee8e8SPatrice Chotard 	err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
122a1cee8e8SPatrice Chotard 	if (err)
1230d0ba1a7SPatrice Chotard 		goto phy_err;
124a1cee8e8SPatrice Chotard 
125a1cee8e8SPatrice Chotard 	return 0;
126a1cee8e8SPatrice Chotard 
1270d0ba1a7SPatrice Chotard phy_err:
1280d0ba1a7SPatrice Chotard 	if (generic_phy_valid(&priv->phy)) {
129*3d54c056SPatrice Chotard 		ret = generic_phy_power_off(&priv->phy);
130*3d54c056SPatrice Chotard 		if (ret)
131*3d54c056SPatrice Chotard 			dev_err(dev, "failed to power off usb phy\n");
132*3d54c056SPatrice Chotard 	}
133*3d54c056SPatrice Chotard 
134*3d54c056SPatrice Chotard phy_power_err:
135*3d54c056SPatrice Chotard 	if (generic_phy_valid(&priv->phy)) {
1360d0ba1a7SPatrice Chotard 		ret = generic_phy_exit(&priv->phy);
1370d0ba1a7SPatrice Chotard 		if (ret)
13890aa625cSMasahiro Yamada 			pr_err("failed to release phy\n");
1390d0ba1a7SPatrice Chotard 	}
1400d0ba1a7SPatrice Chotard 
141a1cee8e8SPatrice Chotard reset_err:
142a1cee8e8SPatrice Chotard 	ret = reset_release_all(priv->resets, priv->reset_count);
143a1cee8e8SPatrice Chotard 	if (ret)
14490aa625cSMasahiro Yamada 		pr_err("failed to assert all resets\n");
145a1cee8e8SPatrice Chotard clk_err:
146a1cee8e8SPatrice Chotard 	ret = clk_release_all(priv->clocks, priv->clock_count);
147a1cee8e8SPatrice Chotard 	if (ret)
14890aa625cSMasahiro Yamada 		pr_err("failed to disable all clocks\n");
149a1cee8e8SPatrice Chotard 
150a1cee8e8SPatrice Chotard 	return err;
151a1cee8e8SPatrice Chotard }
152a1cee8e8SPatrice Chotard 
153a1cee8e8SPatrice Chotard static int ehci_usb_remove(struct udevice *dev)
154a1cee8e8SPatrice Chotard {
155a1cee8e8SPatrice Chotard 	struct generic_ehci *priv = dev_get_priv(dev);
156a1cee8e8SPatrice Chotard 	int ret;
157a1cee8e8SPatrice Chotard 
158a1cee8e8SPatrice Chotard 	ret = ehci_deregister(dev);
159a1cee8e8SPatrice Chotard 	if (ret)
160a1cee8e8SPatrice Chotard 		return ret;
161a1cee8e8SPatrice Chotard 
1620d0ba1a7SPatrice Chotard 	if (generic_phy_valid(&priv->phy)) {
163*3d54c056SPatrice Chotard 		ret = generic_phy_power_off(&priv->phy);
164*3d54c056SPatrice Chotard 		if (ret)
165*3d54c056SPatrice Chotard 			return ret;
166*3d54c056SPatrice Chotard 
1670d0ba1a7SPatrice Chotard 		ret = generic_phy_exit(&priv->phy);
1680d0ba1a7SPatrice Chotard 		if (ret)
1690d0ba1a7SPatrice Chotard 			return ret;
1700d0ba1a7SPatrice Chotard 	}
1710d0ba1a7SPatrice Chotard 
172a1cee8e8SPatrice Chotard 	ret =  reset_release_all(priv->resets, priv->reset_count);
173a1cee8e8SPatrice Chotard 	if (ret)
174a1cee8e8SPatrice Chotard 		return ret;
175a1cee8e8SPatrice Chotard 
176a1cee8e8SPatrice Chotard 	return clk_release_all(priv->clocks, priv->clock_count);
17790fbb282SAlexey Brodkin }
17890fbb282SAlexey Brodkin 
17990fbb282SAlexey Brodkin static const struct udevice_id ehci_usb_ids[] = {
18090fbb282SAlexey Brodkin 	{ .compatible = "generic-ehci" },
18190fbb282SAlexey Brodkin 	{ }
18290fbb282SAlexey Brodkin };
18390fbb282SAlexey Brodkin 
18490fbb282SAlexey Brodkin U_BOOT_DRIVER(ehci_generic) = {
18590fbb282SAlexey Brodkin 	.name	= "ehci_generic",
18690fbb282SAlexey Brodkin 	.id	= UCLASS_USB,
18790fbb282SAlexey Brodkin 	.of_match = ehci_usb_ids,
18890fbb282SAlexey Brodkin 	.probe = ehci_usb_probe,
189a1cee8e8SPatrice Chotard 	.remove = ehci_usb_remove,
19090fbb282SAlexey Brodkin 	.ops	= &ehci_usb_ops,
19190fbb282SAlexey Brodkin 	.priv_auto_alloc_size = sizeof(struct generic_ehci),
19290fbb282SAlexey Brodkin 	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
19390fbb282SAlexey Brodkin };
194