blob: 1cb92c033870887939ee40915ce8af4562f8847b [file] [log] [blame]
Alexey Brodkin90fbb282015-12-02 12:32:02 +03001/*
2 * Copyright (C) 2015 Alexey Brodkin <abrodkin@synopsys.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 */
6
7#include <common.h>
Masahiro Yamada4feefdc2016-01-25 15:00:36 +09008#include <clk.h>
Patrice Chotarda1cee8e2017-07-18 11:57:10 +02009#include <dm/ofnode.h>
Patrice Chotard0d0ba1a2017-07-18 11:57:11 +020010#include <generic-phy.h>
Masahiro Yamada8824cfc2016-09-21 11:29:02 +090011#include <reset.h>
Marek Vasut643cacb2016-01-23 21:04:46 +010012#include <asm/io.h>
Alexey Brodkin90fbb282015-12-02 12:32:02 +030013#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 */
21struct generic_ehci {
22 struct ehci_ctrl ctrl;
Patrice Chotarda1cee8e2017-07-18 11:57:10 +020023 struct clk *clocks;
24 struct reset_ctl *resets;
Patrice Chotard0d0ba1a2017-07-18 11:57:11 +020025 struct phy phy;
Patrice Chotarda1cee8e2017-07-18 11:57:10 +020026 int clock_count;
27 int reset_count;
Alexey Brodkin90fbb282015-12-02 12:32:02 +030028};
29
30static int ehci_usb_probe(struct udevice *dev)
31{
Patrice Chotarda1cee8e2017-07-18 11:57:10 +020032 struct generic_ehci *priv = dev_get_priv(dev);
Marek Vasut643cacb2016-01-23 21:04:46 +010033 struct ehci_hccr *hccr;
Alexey Brodkin90fbb282015-12-02 12:32:02 +030034 struct ehci_hcor *hcor;
Patrice Chotarda1cee8e2017-07-18 11:57:10 +020035 int i, err, ret, clock_nb, reset_nb;
Masahiro Yamada4feefdc2016-01-25 15:00:36 +090036
Patrice Chotarda1cee8e2017-07-18 11:57:10 +020037 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;
Masahiro Yamada4feefdc2016-01-25 15:00:36 +090046
Patrice Chotarda1cee8e2017-07-18 11:57:10 +020047 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) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +090054 pr_err("failed to enable clock %d\n", i);
Patrice Chotarda1cee8e2017-07-18 11:57:10 +020055 clk_free(&priv->clocks[i]);
56 goto clk_err;
57 }
58 priv->clock_count++;
59 }
60 } else {
61 if (clock_nb != -ENOENT) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +090062 pr_err("failed to get clock phandle(%d)\n", clock_nb);
Patrice Chotarda1cee8e2017-07-18 11:57:10 +020063 return clock_nb;
64 }
Masahiro Yamada4feefdc2016-01-25 15:00:36 +090065 }
Alexey Brodkin90fbb282015-12-02 12:32:02 +030066
Patrice Chotarda1cee8e2017-07-18 11:57:10 +020067 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;
Masahiro Yamada8824cfc2016-09-21 11:29:02 +090076
Patrice Chotarda1cee8e2017-07-18 11:57:10 +020077 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])) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +090083 pr_err("failed to deassert reset %d\n", i);
Patrice Chotarda1cee8e2017-07-18 11:57:10 +020084 reset_free(&priv->resets[i]);
85 goto reset_err;
86 }
87 priv->reset_count++;
88 }
89 } else {
90 if (reset_nb != -ENOENT) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +090091 pr_err("failed to get reset phandle(%d)\n", reset_nb);
Patrice Chotarda1cee8e2017-07-18 11:57:10 +020092 goto clk_err;
93 }
Masahiro Yamada8824cfc2016-09-21 11:29:02 +090094 }
95
Patrice Chotard0d0ba1a2017-07-18 11:57:11 +020096 err = generic_phy_get_by_index(dev, 0, &priv->phy);
97 if (err) {
98 if (err != -ENOENT) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +090099 pr_err("failed to get usb phy\n");
Patrice Chotard0d0ba1a2017-07-18 11:57:11 +0200100 goto reset_err;
101 }
Patrice Chotard4b3928a2017-07-24 17:07:04 +0200102 } else {
Patrice Chotard0d0ba1a2017-07-18 11:57:11 +0200103
Patrice Chotard4b3928a2017-07-24 17:07:04 +0200104 err = generic_phy_init(&priv->phy);
105 if (err) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900106 pr_err("failed to init usb phy\n");
Patrice Chotard4b3928a2017-07-24 17:07:04 +0200107 goto reset_err;
108 }
Patrice Chotard0d0ba1a2017-07-18 11:57:11 +0200109 }
110
Philipp Tomsich6e652e32017-09-12 17:32:28 +0200111 hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE);
Alexey Brodkin90fbb282015-12-02 12:32:02 +0300112 hcor = (struct ehci_hcor *)((uintptr_t)hccr +
113 HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
114
Patrice Chotarda1cee8e2017-07-18 11:57:10 +0200115 err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
116 if (err)
Patrice Chotard0d0ba1a2017-07-18 11:57:11 +0200117 goto phy_err;
Patrice Chotarda1cee8e2017-07-18 11:57:10 +0200118
119 return 0;
120
Patrice Chotard0d0ba1a2017-07-18 11:57:11 +0200121phy_err:
122 if (generic_phy_valid(&priv->phy)) {
123 ret = generic_phy_exit(&priv->phy);
124 if (ret)
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900125 pr_err("failed to release phy\n");
Patrice Chotard0d0ba1a2017-07-18 11:57:11 +0200126 }
127
Patrice Chotarda1cee8e2017-07-18 11:57:10 +0200128reset_err:
129 ret = reset_release_all(priv->resets, priv->reset_count);
130 if (ret)
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900131 pr_err("failed to assert all resets\n");
Patrice Chotarda1cee8e2017-07-18 11:57:10 +0200132clk_err:
133 ret = clk_release_all(priv->clocks, priv->clock_count);
134 if (ret)
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900135 pr_err("failed to disable all clocks\n");
Patrice Chotarda1cee8e2017-07-18 11:57:10 +0200136
137 return err;
138}
139
140static int ehci_usb_remove(struct udevice *dev)
141{
142 struct generic_ehci *priv = dev_get_priv(dev);
143 int ret;
144
145 ret = ehci_deregister(dev);
146 if (ret)
147 return ret;
148
Patrice Chotard0d0ba1a2017-07-18 11:57:11 +0200149 if (generic_phy_valid(&priv->phy)) {
150 ret = generic_phy_exit(&priv->phy);
151 if (ret)
152 return ret;
153 }
154
Patrice Chotarda1cee8e2017-07-18 11:57:10 +0200155 ret = reset_release_all(priv->resets, priv->reset_count);
156 if (ret)
157 return ret;
158
159 return clk_release_all(priv->clocks, priv->clock_count);
Alexey Brodkin90fbb282015-12-02 12:32:02 +0300160}
161
Alexey Brodkin90fbb282015-12-02 12:32:02 +0300162static const struct udevice_id ehci_usb_ids[] = {
163 { .compatible = "generic-ehci" },
164 { }
165};
166
167U_BOOT_DRIVER(ehci_generic) = {
168 .name = "ehci_generic",
169 .id = UCLASS_USB,
170 .of_match = ehci_usb_ids,
171 .probe = ehci_usb_probe,
Patrice Chotarda1cee8e2017-07-18 11:57:10 +0200172 .remove = ehci_usb_remove,
Alexey Brodkin90fbb282015-12-02 12:32:02 +0300173 .ops = &ehci_usb_ops,
174 .priv_auto_alloc_size = sizeof(struct generic_ehci),
175 .flags = DM_FLAG_ALLOC_PRIV_DMA,
176};