blob: cc2f33826a3bf19a545960843f2c4597a2cd8946 [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
29static int ehci_usb_probe(struct udevice *dev)
30{
Patrice Chotarda1cee8e2017-07-18 11:57:10 +020031 struct generic_ehci *priv = dev_get_priv(dev);
Marek Vasut643cacb2016-01-23 21:04:46 +010032 struct ehci_hccr *hccr;
Alexey Brodkin90fbb282015-12-02 12:32:02 +030033 struct ehci_hcor *hcor;
Patrice Chotarda1cee8e2017-07-18 11:57:10 +020034 int i, err, ret, clock_nb, reset_nb;
Masahiro Yamada4feefdc2016-01-25 15:00:36 +090035
Patrice Chotarda1cee8e2017-07-18 11:57:10 +020036 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;
Masahiro Yamada4feefdc2016-01-25 15:00:36 +090045
Patrice Chotarda1cee8e2017-07-18 11:57:10 +020046 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) {
Patrice Chotarddf7777a2018-03-14 17:48:55 +010053 dev_err(dev, "failed to enable clock %d\n", i);
Patrice Chotarda1cee8e2017-07-18 11:57:10 +020054 clk_free(&priv->clocks[i]);
55 goto clk_err;
56 }
57 priv->clock_count++;
58 }
59 } else {
60 if (clock_nb != -ENOENT) {
Patrice Chotarddf7777a2018-03-14 17:48:55 +010061 dev_err(dev, "failed to get clock phandle(%d)\n",
62 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])) {
Patrice Chotarddf7777a2018-03-14 17:48:55 +010083 dev_err(dev, "failed to deassert reset %d\n",
84 i);
Patrice Chotarda1cee8e2017-07-18 11:57:10 +020085 reset_free(&priv->resets[i]);
86 goto reset_err;
87 }
88 priv->reset_count++;
89 }
90 } else {
91 if (reset_nb != -ENOENT) {
Patrice Chotarddf7777a2018-03-14 17:48:55 +010092 dev_err(dev, "failed to get reset phandle(%d)\n",
93 reset_nb);
Patrice Chotarda1cee8e2017-07-18 11:57:10 +020094 goto clk_err;
95 }
Masahiro Yamada8824cfc2016-09-21 11:29:02 +090096 }
97
Marek Vasutb43cdf92018-08-08 14:29:55 +020098 err = ehci_setup_phy(dev, &priv->phy, 0);
Patrice Chotard20f06a42018-03-14 17:48:54 +010099 if (err)
Patrice Chotard20f06a42018-03-14 17:48:54 +0100100 goto reset_err;
Patrice Chotard0d0ba1a2017-07-18 11:57:11 +0200101
Philipp Tomsich6e652e32017-09-12 17:32:28 +0200102 hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE);
Alexey Brodkin90fbb282015-12-02 12:32:02 +0300103 hcor = (struct ehci_hcor *)((uintptr_t)hccr +
104 HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
105
Patrice Chotarda1cee8e2017-07-18 11:57:10 +0200106 err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
107 if (err)
Patrice Chotard0d0ba1a2017-07-18 11:57:11 +0200108 goto phy_err;
Patrice Chotarda1cee8e2017-07-18 11:57:10 +0200109
110 return 0;
111
Patrice Chotard0d0ba1a2017-07-18 11:57:11 +0200112phy_err:
Marek Vasutb43cdf92018-08-08 14:29:55 +0200113 ret = ehci_shutdown_phy(dev, &priv->phy);
Patrice Chotard20f06a42018-03-14 17:48:54 +0100114 if (ret)
115 dev_err(dev, "failed to shutdown usb phy\n");
Patrice Chotard0d0ba1a2017-07-18 11:57:11 +0200116
Patrice Chotarda1cee8e2017-07-18 11:57:10 +0200117reset_err:
118 ret = reset_release_all(priv->resets, priv->reset_count);
119 if (ret)
Patrice Chotarddf7777a2018-03-14 17:48:55 +0100120 dev_err(dev, "failed to assert all resets\n");
Patrice Chotarda1cee8e2017-07-18 11:57:10 +0200121clk_err:
122 ret = clk_release_all(priv->clocks, priv->clock_count);
123 if (ret)
Patrice Chotarddf7777a2018-03-14 17:48:55 +0100124 dev_err(dev, "failed to disable all clocks\n");
Patrice Chotarda1cee8e2017-07-18 11:57:10 +0200125
126 return err;
127}
128
129static 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
Marek Vasutb43cdf92018-08-08 14:29:55 +0200138 ret = ehci_shutdown_phy(dev, &priv->phy);
Patrice Chotard20f06a42018-03-14 17:48:54 +0100139 if (ret)
140 return ret;
Patrice Chotard0d0ba1a2017-07-18 11:57:11 +0200141
Patrice Chotarda1cee8e2017-07-18 11:57:10 +0200142 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);
Alexey Brodkin90fbb282015-12-02 12:32:02 +0300147}
148
Alexey Brodkin90fbb282015-12-02 12:32:02 +0300149static const struct udevice_id ehci_usb_ids[] = {
150 { .compatible = "generic-ehci" },
151 { }
152};
153
154U_BOOT_DRIVER(ehci_generic) = {
155 .name = "ehci_generic",
156 .id = UCLASS_USB,
157 .of_match = ehci_usb_ids,
158 .probe = ehci_usb_probe,
Patrice Chotarda1cee8e2017-07-18 11:57:10 +0200159 .remove = ehci_usb_remove,
Alexey Brodkin90fbb282015-12-02 12:32:02 +0300160 .ops = &ehci_usb_ops,
161 .priv_auto_alloc_size = sizeof(struct generic_ehci),
162 .flags = DM_FLAG_ALLOC_PRIV_DMA,
163};