blob: 5a56f66cfaa6ff942e108f933d32cef2b4e21231 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Alexey Brodkin90fbb282015-12-02 12:32:02 +03002/*
3 * Copyright (C) 2015 Alexey Brodkin <abrodkin@synopsys.com>
Alexey Brodkin90fbb282015-12-02 12:32:02 +03004 */
5
6#include <common.h>
Masahiro Yamada4feefdc2016-01-25 15:00:36 +09007#include <clk.h>
Patrice Chotarda1cee8e2017-07-18 11:57:10 +02008#include <dm/ofnode.h>
Patrice Chotard0d0ba1a2017-07-18 11:57:11 +02009#include <generic-phy.h>
Masahiro Yamada8824cfc2016-09-21 11:29:02 +090010#include <reset.h>
Marek Vasut643cacb2016-01-23 21:04:46 +010011#include <asm/io.h>
Alexey Brodkin90fbb282015-12-02 12:32:02 +030012#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 */
20struct generic_ehci {
21 struct ehci_ctrl ctrl;
Patrice Chotarda1cee8e2017-07-18 11:57:10 +020022 struct clk *clocks;
23 struct reset_ctl *resets;
Patrice Chotard0d0ba1a2017-07-18 11:57:11 +020024 struct phy phy;
Patrice Chotarda1cee8e2017-07-18 11:57:10 +020025 int clock_count;
26 int reset_count;
Alexey Brodkin90fbb282015-12-02 12:32:02 +030027};
28
Patrice Chotard20f06a42018-03-14 17:48:54 +010029static int ehci_setup_phy(struct udevice *dev, int index)
30{
31 struct generic_ehci *priv = dev_get_priv(dev);
32 int ret;
33
34 ret = generic_phy_get_by_index(dev, index, &priv->phy);
35 if (ret) {
36 if (ret != -ENOENT) {
37 dev_err(dev, "failed to get usb phy\n");
38 return ret;
39 }
40 } else {
41 ret = generic_phy_init(&priv->phy);
42 if (ret) {
43 dev_err(dev, "failed to init usb phy\n");
44 return ret;
45 }
46
47 ret = generic_phy_power_on(&priv->phy);
48 if (ret) {
49 dev_err(dev, "failed to power on usb phy\n");
50 return generic_phy_exit(&priv->phy);
51 }
52 }
53
54 return 0;
55}
56
57static int ehci_shutdown_phy(struct udevice *dev)
58{
59 struct generic_ehci *priv = dev_get_priv(dev);
60 int ret = 0;
61
62 if (generic_phy_valid(&priv->phy)) {
63 ret = generic_phy_power_off(&priv->phy);
64 if (ret) {
65 dev_err(dev, "failed to power off usb phy\n");
66 return ret;
67 }
68
69 ret = generic_phy_exit(&priv->phy);
70 if (ret) {
71 dev_err(dev, "failed to power off usb phy\n");
72 return ret;
73 }
74 }
75
76 return 0;
77}
78
Alexey Brodkin90fbb282015-12-02 12:32:02 +030079static int ehci_usb_probe(struct udevice *dev)
80{
Patrice Chotarda1cee8e2017-07-18 11:57:10 +020081 struct generic_ehci *priv = dev_get_priv(dev);
Marek Vasut643cacb2016-01-23 21:04:46 +010082 struct ehci_hccr *hccr;
Alexey Brodkin90fbb282015-12-02 12:32:02 +030083 struct ehci_hcor *hcor;
Patrice Chotarda1cee8e2017-07-18 11:57:10 +020084 int i, err, ret, clock_nb, reset_nb;
Masahiro Yamada4feefdc2016-01-25 15:00:36 +090085
Patrice Chotarda1cee8e2017-07-18 11:57:10 +020086 err = 0;
87 priv->clock_count = 0;
88 clock_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "clocks",
89 "#clock-cells");
90 if (clock_nb > 0) {
91 priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk),
92 GFP_KERNEL);
93 if (!priv->clocks)
94 return -ENOMEM;
Masahiro Yamada4feefdc2016-01-25 15:00:36 +090095
Patrice Chotarda1cee8e2017-07-18 11:57:10 +020096 for (i = 0; i < clock_nb; i++) {
97 err = clk_get_by_index(dev, i, &priv->clocks[i]);
98
99 if (err < 0)
100 break;
101 err = clk_enable(&priv->clocks[i]);
102 if (err) {
Patrice Chotarddf7777a2018-03-14 17:48:55 +0100103 dev_err(dev, "failed to enable clock %d\n", i);
Patrice Chotarda1cee8e2017-07-18 11:57:10 +0200104 clk_free(&priv->clocks[i]);
105 goto clk_err;
106 }
107 priv->clock_count++;
108 }
109 } else {
110 if (clock_nb != -ENOENT) {
Patrice Chotarddf7777a2018-03-14 17:48:55 +0100111 dev_err(dev, "failed to get clock phandle(%d)\n",
112 clock_nb);
Patrice Chotarda1cee8e2017-07-18 11:57:10 +0200113 return clock_nb;
114 }
Masahiro Yamada4feefdc2016-01-25 15:00:36 +0900115 }
Alexey Brodkin90fbb282015-12-02 12:32:02 +0300116
Patrice Chotarda1cee8e2017-07-18 11:57:10 +0200117 priv->reset_count = 0;
118 reset_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "resets",
119 "#reset-cells");
120 if (reset_nb > 0) {
121 priv->resets = devm_kcalloc(dev, reset_nb,
122 sizeof(struct reset_ctl),
123 GFP_KERNEL);
124 if (!priv->resets)
125 return -ENOMEM;
Masahiro Yamada8824cfc2016-09-21 11:29:02 +0900126
Patrice Chotarda1cee8e2017-07-18 11:57:10 +0200127 for (i = 0; i < reset_nb; i++) {
128 err = reset_get_by_index(dev, i, &priv->resets[i]);
129 if (err < 0)
130 break;
131
132 if (reset_deassert(&priv->resets[i])) {
Patrice Chotarddf7777a2018-03-14 17:48:55 +0100133 dev_err(dev, "failed to deassert reset %d\n",
134 i);
Patrice Chotarda1cee8e2017-07-18 11:57:10 +0200135 reset_free(&priv->resets[i]);
136 goto reset_err;
137 }
138 priv->reset_count++;
139 }
140 } else {
141 if (reset_nb != -ENOENT) {
Patrice Chotarddf7777a2018-03-14 17:48:55 +0100142 dev_err(dev, "failed to get reset phandle(%d)\n",
143 reset_nb);
Patrice Chotarda1cee8e2017-07-18 11:57:10 +0200144 goto clk_err;
145 }
Masahiro Yamada8824cfc2016-09-21 11:29:02 +0900146 }
147
Patrice Chotard20f06a42018-03-14 17:48:54 +0100148 err = ehci_setup_phy(dev, 0);
149 if (err)
Patrice Chotard20f06a42018-03-14 17:48:54 +0100150 goto reset_err;
Patrice Chotard0d0ba1a2017-07-18 11:57:11 +0200151
Philipp Tomsich6e652e32017-09-12 17:32:28 +0200152 hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE);
Alexey Brodkin90fbb282015-12-02 12:32:02 +0300153 hcor = (struct ehci_hcor *)((uintptr_t)hccr +
154 HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
155
Patrice Chotarda1cee8e2017-07-18 11:57:10 +0200156 err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
157 if (err)
Patrice Chotard0d0ba1a2017-07-18 11:57:11 +0200158 goto phy_err;
Patrice Chotarda1cee8e2017-07-18 11:57:10 +0200159
160 return 0;
161
Patrice Chotard0d0ba1a2017-07-18 11:57:11 +0200162phy_err:
Patrice Chotard20f06a42018-03-14 17:48:54 +0100163 ret = ehci_shutdown_phy(dev);
164 if (ret)
165 dev_err(dev, "failed to shutdown usb phy\n");
Patrice Chotard0d0ba1a2017-07-18 11:57:11 +0200166
Patrice Chotarda1cee8e2017-07-18 11:57:10 +0200167reset_err:
168 ret = reset_release_all(priv->resets, priv->reset_count);
169 if (ret)
Patrice Chotarddf7777a2018-03-14 17:48:55 +0100170 dev_err(dev, "failed to assert all resets\n");
Patrice Chotarda1cee8e2017-07-18 11:57:10 +0200171clk_err:
172 ret = clk_release_all(priv->clocks, priv->clock_count);
173 if (ret)
Patrice Chotarddf7777a2018-03-14 17:48:55 +0100174 dev_err(dev, "failed to disable all clocks\n");
Patrice Chotarda1cee8e2017-07-18 11:57:10 +0200175
176 return err;
177}
178
179static int ehci_usb_remove(struct udevice *dev)
180{
181 struct generic_ehci *priv = dev_get_priv(dev);
182 int ret;
183
184 ret = ehci_deregister(dev);
185 if (ret)
186 return ret;
187
Patrice Chotard20f06a42018-03-14 17:48:54 +0100188 ret = ehci_shutdown_phy(dev);
189 if (ret)
190 return ret;
Patrice Chotard0d0ba1a2017-07-18 11:57:11 +0200191
Patrice Chotarda1cee8e2017-07-18 11:57:10 +0200192 ret = reset_release_all(priv->resets, priv->reset_count);
193 if (ret)
194 return ret;
195
196 return clk_release_all(priv->clocks, priv->clock_count);
Alexey Brodkin90fbb282015-12-02 12:32:02 +0300197}
198
Alexey Brodkin90fbb282015-12-02 12:32:02 +0300199static const struct udevice_id ehci_usb_ids[] = {
200 { .compatible = "generic-ehci" },
201 { }
202};
203
204U_BOOT_DRIVER(ehci_generic) = {
205 .name = "ehci_generic",
206 .id = UCLASS_USB,
207 .of_match = ehci_usb_ids,
208 .probe = ehci_usb_probe,
Patrice Chotarda1cee8e2017-07-18 11:57:10 +0200209 .remove = ehci_usb_remove,
Alexey Brodkin90fbb282015-12-02 12:32:02 +0300210 .ops = &ehci_usb_ops,
211 .priv_auto_alloc_size = sizeof(struct generic_ehci),
212 .flags = DM_FLAG_ALLOC_PRIV_DMA,
213};