xref: /openbmc/u-boot/drivers/usb/host/ehci-generic.c (revision 4cdeda51)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2015 Alexey Brodkin <abrodkin@synopsys.com>
4  */
5 
6 #include <common.h>
7 #include <clk.h>
8 #include <dm/ofnode.h>
9 #include <generic-phy.h>
10 #include <reset.h>
11 #include <asm/io.h>
12 #include <dm.h>
13 #include "ehci.h"
14 
15 /*
16  * Even though here we don't explicitly use "struct ehci_ctrl"
17  * ehci_register() expects it to be the first thing that resides in
18  * device's private data.
19  */
20 struct generic_ehci {
21 	struct ehci_ctrl ctrl;
22 	struct clk *clocks;
23 	struct reset_ctl *resets;
24 	struct phy phy;
25 	int clock_count;
26 	int reset_count;
27 };
28 
29 static int ehci_usb_probe(struct udevice *dev)
30 {
31 	struct generic_ehci *priv = dev_get_priv(dev);
32 	struct ehci_hccr *hccr;
33 	struct ehci_hcor *hcor;
34 	int i, err, ret, clock_nb, reset_nb;
35 
36 	err = 0;
37 	priv->clock_count = 0;
38 	clock_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "clocks",
39 						  "#clock-cells");
40 	if (clock_nb > 0) {
41 		priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk),
42 					    GFP_KERNEL);
43 		if (!priv->clocks)
44 			return -ENOMEM;
45 
46 		for (i = 0; i < clock_nb; i++) {
47 			err = clk_get_by_index(dev, i, &priv->clocks[i]);
48 
49 			if (err < 0)
50 				break;
51 			err = clk_enable(&priv->clocks[i]);
52 			if (err) {
53 				dev_err(dev, "failed to enable clock %d\n", i);
54 				clk_free(&priv->clocks[i]);
55 				goto clk_err;
56 			}
57 			priv->clock_count++;
58 		}
59 	} else {
60 		if (clock_nb != -ENOENT) {
61 			dev_err(dev, "failed to get clock phandle(%d)\n",
62 				clock_nb);
63 			return clock_nb;
64 		}
65 	}
66 
67 	priv->reset_count = 0;
68 	reset_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "resets",
69 						  "#reset-cells");
70 	if (reset_nb > 0) {
71 		priv->resets = devm_kcalloc(dev, reset_nb,
72 					    sizeof(struct reset_ctl),
73 					    GFP_KERNEL);
74 		if (!priv->resets)
75 			return -ENOMEM;
76 
77 		for (i = 0; i < reset_nb; i++) {
78 			err = reset_get_by_index(dev, i, &priv->resets[i]);
79 			if (err < 0)
80 				break;
81 
82 			if (reset_deassert(&priv->resets[i])) {
83 				dev_err(dev, "failed to deassert reset %d\n",
84 					i);
85 				reset_free(&priv->resets[i]);
86 				goto reset_err;
87 			}
88 			priv->reset_count++;
89 		}
90 	} else {
91 		if (reset_nb != -ENOENT) {
92 			dev_err(dev, "failed to get reset phandle(%d)\n",
93 				reset_nb);
94 			goto clk_err;
95 		}
96 	}
97 
98 	err = ehci_setup_phy(dev, &priv->phy, 0);
99 	if (err)
100 		goto reset_err;
101 
102 	hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE);
103 	hcor = (struct ehci_hcor *)((uintptr_t)hccr +
104 				    HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
105 
106 	err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
107 	if (err)
108 		goto phy_err;
109 
110 	return 0;
111 
112 phy_err:
113 	ret = ehci_shutdown_phy(dev, &priv->phy);
114 	if (ret)
115 		dev_err(dev, "failed to shutdown usb phy\n");
116 
117 reset_err:
118 	ret = reset_release_all(priv->resets, priv->reset_count);
119 	if (ret)
120 		dev_err(dev, "failed to assert all resets\n");
121 clk_err:
122 	ret = clk_release_all(priv->clocks, priv->clock_count);
123 	if (ret)
124 		dev_err(dev, "failed to disable all clocks\n");
125 
126 	return err;
127 }
128 
129 static int ehci_usb_remove(struct udevice *dev)
130 {
131 	struct generic_ehci *priv = dev_get_priv(dev);
132 	int ret;
133 
134 	ret = ehci_deregister(dev);
135 	if (ret)
136 		return ret;
137 
138 	ret = ehci_shutdown_phy(dev, &priv->phy);
139 	if (ret)
140 		return ret;
141 
142 	ret =  reset_release_all(priv->resets, priv->reset_count);
143 	if (ret)
144 		return ret;
145 
146 	return clk_release_all(priv->clocks, priv->clock_count);
147 }
148 
149 static const struct udevice_id ehci_usb_ids[] = {
150 	{ .compatible = "generic-ehci" },
151 	{ }
152 };
153 
154 U_BOOT_DRIVER(ehci_generic) = {
155 	.name	= "ehci_generic",
156 	.id	= UCLASS_USB,
157 	.of_match = ehci_usb_ids,
158 	.probe = ehci_usb_probe,
159 	.remove = ehci_usb_remove,
160 	.ops	= &ehci_usb_ops,
161 	.priv_auto_alloc_size = sizeof(struct generic_ehci),
162 	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
163 };
164