Merge branch 'master' of git://git.denx.de/u-boot-usb
[oweals/u-boot.git] / drivers / usb / host / ohci-sunxi.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Sunxi ohci glue
4  *
5  * Copyright (C) 2015 Hans de Goede <hdegoede@redhat.com>
6  *
7  * Based on code from
8  * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
9  */
10
11 #include <common.h>
12 #include <asm/arch/clock.h>
13 #include <asm/io.h>
14 #include <dm.h>
15 #include <usb.h>
16 #include "ohci.h"
17 #include <generic-phy.h>
18
19 #ifdef CONFIG_SUNXI_GEN_SUN4I
20 #define BASE_DIST               0x8000
21 #define AHB_CLK_DIST            2
22 #else
23 #define BASE_DIST               0x1000
24 #define AHB_CLK_DIST            1
25 #endif
26
27 #define SUN6I_AHB_RESET0_CFG_OFFSET 0x2c0
28 #define SUN9I_AHB_RESET0_CFG_OFFSET 0x5a0
29
30 struct ohci_sunxi_cfg {
31         bool has_reset;
32         u32 extra_ahb_gate_mask;
33         u32 extra_usb_gate_mask;
34         u32 reset0_cfg_offset;
35 };
36
37 struct ohci_sunxi_priv {
38         ohci_t ohci;
39         struct sunxi_ccm_reg *ccm;
40         u32 *reset0_cfg;
41         int ahb_gate_mask; /* Mask of ahb_gate0 clk gate bits for this hcd */
42         int usb_gate_mask; /* Mask of usb_clk_cfg clk gate bits for this hcd */
43         struct phy phy;
44         const struct ohci_sunxi_cfg *cfg;
45 };
46
47 static fdt_addr_t last_ohci_addr = 0;
48
49 static int ohci_usb_probe(struct udevice *dev)
50 {
51         struct usb_bus_priv *bus_priv = dev_get_uclass_priv(dev);
52         struct ohci_sunxi_priv *priv = dev_get_priv(dev);
53         struct ohci_regs *regs = (struct ohci_regs *)devfdt_get_addr(dev);
54         int extra_ahb_gate_mask = 0;
55         u8 reg_mask = 0;
56         int phys, ret;
57
58         if ((fdt_addr_t)regs > last_ohci_addr)
59                 last_ohci_addr = (fdt_addr_t)regs;
60
61         priv->cfg = (const struct ohci_sunxi_cfg *)dev_get_driver_data(dev);
62         priv->ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
63         if (IS_ERR(priv->ccm))
64                 return PTR_ERR(priv->ccm);
65
66         priv->reset0_cfg = (void *)priv->ccm +
67                                    priv->cfg->reset0_cfg_offset;
68
69         phys = dev_count_phandle_with_args(dev, "phys", "#phy-cells");
70         if (phys < 0) {
71                 phys = 0;
72                 goto no_phy;
73         }
74
75         ret = generic_phy_get_by_name(dev, "usb", &priv->phy);
76         if (ret) {
77                 pr_err("failed to get %s usb PHY\n", dev->name);
78                 return ret;
79         }
80
81         ret = generic_phy_init(&priv->phy);
82         if (ret) {
83                 pr_err("failed to init %s USB PHY\n", dev->name);
84                 return ret;
85         }
86
87         ret = generic_phy_power_on(&priv->phy);
88         if (ret) {
89                 pr_err("failed to power on %s USB PHY\n", dev->name);
90                 return ret;
91         }
92
93 no_phy:
94         bus_priv->companion = true;
95
96         /*
97          * This should go away once we've moved to the driver model for
98          * clocks resp. phys.
99          */
100         reg_mask = ((uintptr_t)regs - (SUNXI_USB1_BASE + 0x400)) / BASE_DIST;
101         priv->ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_OHCI0;
102         extra_ahb_gate_mask = priv->cfg->extra_ahb_gate_mask;
103         priv->usb_gate_mask = CCM_USB_CTRL_OHCI0_CLK;
104         priv->ahb_gate_mask <<= reg_mask * AHB_CLK_DIST;
105         extra_ahb_gate_mask <<= reg_mask * AHB_CLK_DIST;
106         priv->usb_gate_mask <<= reg_mask;
107
108         setbits_le32(&priv->ccm->ahb_gate0,
109                      priv->ahb_gate_mask | extra_ahb_gate_mask);
110         setbits_le32(&priv->ccm->usb_clk_cfg,
111                      priv->usb_gate_mask | priv->cfg->extra_usb_gate_mask);
112         if (priv->cfg->has_reset)
113                 setbits_le32(priv->reset0_cfg,
114                              priv->ahb_gate_mask | extra_ahb_gate_mask);
115
116         return ohci_register(dev, regs);
117 }
118
119 static int ohci_usb_remove(struct udevice *dev)
120 {
121         struct ohci_sunxi_priv *priv = dev_get_priv(dev);
122         fdt_addr_t base_addr = devfdt_get_addr(dev);
123         int ret;
124
125         if (generic_phy_valid(&priv->phy)) {
126                 ret = generic_phy_exit(&priv->phy);
127                 if (ret) {
128                         pr_err("failed to exit %s USB PHY\n", dev->name);
129                         return ret;
130                 }
131         }
132
133         ret = ohci_deregister(dev);
134         if (ret)
135                 return ret;
136
137         if (priv->cfg->has_reset)
138                 clrbits_le32(priv->reset0_cfg, priv->ahb_gate_mask);
139         /*
140          * On the A64 CLK_USB_OHCI0 is the parent of CLK_USB_OHCI1, so
141          * we have to wait with bringing down any clock until the last
142          * OHCI controller is removed.
143          */
144         if (!priv->cfg->extra_usb_gate_mask || base_addr == last_ohci_addr) {
145                 u32 usb_gate_mask = priv->usb_gate_mask;
146
147                 usb_gate_mask |= priv->cfg->extra_usb_gate_mask;
148                 clrbits_le32(&priv->ccm->usb_clk_cfg, usb_gate_mask);
149         }
150
151         clrbits_le32(&priv->ccm->ahb_gate0, priv->ahb_gate_mask);
152
153         return 0;
154 }
155
156 static const struct ohci_sunxi_cfg sun4i_a10_cfg = {
157         .has_reset = false,
158 };
159
160 static const struct ohci_sunxi_cfg sun6i_a31_cfg = {
161         .has_reset = true,
162         .reset0_cfg_offset = SUN6I_AHB_RESET0_CFG_OFFSET,
163 };
164
165 static const struct ohci_sunxi_cfg sun8i_h3_cfg = {
166         .has_reset = true,
167         .extra_ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0,
168         .reset0_cfg_offset = SUN6I_AHB_RESET0_CFG_OFFSET,
169 };
170
171 static const struct ohci_sunxi_cfg sun9i_a80_cfg = {
172         .has_reset = true,
173         .reset0_cfg_offset = SUN9I_AHB_RESET0_CFG_OFFSET,
174 };
175
176 static const struct ohci_sunxi_cfg sun50i_a64_cfg = {
177         .has_reset = true,
178         .extra_ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0,
179         .extra_usb_gate_mask = CCM_USB_CTRL_OHCI0_CLK,
180         .reset0_cfg_offset = SUN6I_AHB_RESET0_CFG_OFFSET,
181 };
182
183 static const struct udevice_id ohci_usb_ids[] = {
184         {
185                 .compatible = "allwinner,sun4i-a10-ohci",
186                 .data = (ulong)&sun4i_a10_cfg,
187         },
188         {
189                 .compatible = "allwinner,sun5i-a13-ohci",
190                 .data = (ulong)&sun4i_a10_cfg,
191         },
192         {
193                 .compatible = "allwinner,sun6i-a31-ohci",
194                 .data = (ulong)&sun6i_a31_cfg,
195         },
196         {
197                 .compatible = "allwinner,sun7i-a20-ohci",
198                 .data = (ulong)&sun4i_a10_cfg,
199         },
200         {
201                 .compatible = "allwinner,sun8i-a23-ohci",
202                 .data = (ulong)&sun6i_a31_cfg,
203         },
204         {
205                 .compatible = "allwinner,sun8i-a83t-ohci",
206                 .data = (ulong)&sun6i_a31_cfg,
207         },
208         {
209                 .compatible = "allwinner,sun8i-h3-ohci",
210                 .data = (ulong)&sun8i_h3_cfg,
211         },
212         {
213                 .compatible = "allwinner,sun9i-a80-ohci",
214                 .data = (ulong)&sun9i_a80_cfg,
215         },
216         {
217                 .compatible = "allwinner,sun50i-a64-ohci",
218                 .data = (ulong)&sun50i_a64_cfg,
219         },
220         { /* sentinel */ }
221 };
222
223 U_BOOT_DRIVER(usb_ohci) = {
224         .name   = "ohci_sunxi",
225         .id     = UCLASS_USB,
226         .of_match = ohci_usb_ids,
227         .probe = ohci_usb_probe,
228         .remove = ohci_usb_remove,
229         .ops    = &ohci_usb_ops,
230         .platdata_auto_alloc_size = sizeof(struct usb_platdata),
231         .priv_auto_alloc_size = sizeof(struct ohci_sunxi_priv),
232         .flags  = DM_FLAG_ALLOC_PRIV_DMA,
233 };