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