125f8bf6eSSughosh Ganu /*
225f8bf6eSSughosh Ganu * Copyright (C) 2012 Sughosh Ganu <urwithsughosh@gmail.com>
325f8bf6eSSughosh Ganu *
41a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+
525f8bf6eSSughosh Ganu */
625f8bf6eSSughosh Ganu
725f8bf6eSSughosh Ganu #include <common.h>
8dff9f0f7SAdam Ford #include <asm/io.h>
9dff9f0f7SAdam Ford #include <clk.h>
10dff9f0f7SAdam Ford #include <dm.h>
11dff9f0f7SAdam Ford #include <dm/ofnode.h>
12dff9f0f7SAdam Ford #include <generic-phy.h>
13dff9f0f7SAdam Ford #include <reset.h>
14dff9f0f7SAdam Ford #include "ohci.h"
1525f8bf6eSSughosh Ganu #include <asm/arch/da8xx-usb.h>
1625f8bf6eSSughosh Ganu
17dff9f0f7SAdam Ford struct da8xx_ohci {
18dff9f0f7SAdam Ford ohci_t ohci;
19dff9f0f7SAdam Ford struct clk *clocks; /* clock list */
20dff9f0f7SAdam Ford struct phy phy;
21dff9f0f7SAdam Ford int clock_count; /* number of clock in clock list */
22dff9f0f7SAdam Ford };
23dff9f0f7SAdam Ford
usb_phy_on(void)24dff9f0f7SAdam Ford static int usb_phy_on(void)
25dff9f0f7SAdam Ford {
26dff9f0f7SAdam Ford unsigned long timeout;
27dff9f0f7SAdam Ford
28dff9f0f7SAdam Ford clrsetbits_le32(&davinci_syscfg_regs->cfgchip2,
29dff9f0f7SAdam Ford (CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN |
30dff9f0f7SAdam Ford CFGCHIP2_OTGPWRDN | CFGCHIP2_OTGMODE |
31dff9f0f7SAdam Ford CFGCHIP2_REFFREQ | CFGCHIP2_USB1PHYCLKMUX),
32dff9f0f7SAdam Ford (CFGCHIP2_SESENDEN | CFGCHIP2_VBDTCTEN |
33dff9f0f7SAdam Ford CFGCHIP2_PHY_PLLON | CFGCHIP2_REFFREQ_24MHZ |
34dff9f0f7SAdam Ford CFGCHIP2_USB2PHYCLKMUX | CFGCHIP2_USB1SUSPENDM));
35dff9f0f7SAdam Ford
36dff9f0f7SAdam Ford /* wait until the usb phy pll locks */
37dff9f0f7SAdam Ford timeout = get_timer(0);
38dff9f0f7SAdam Ford while (get_timer(timeout) < 10) {
39dff9f0f7SAdam Ford if (readl(&davinci_syscfg_regs->cfgchip2) & CFGCHIP2_PHYCLKGD)
40dff9f0f7SAdam Ford return 1;
41dff9f0f7SAdam Ford }
42dff9f0f7SAdam Ford
43dff9f0f7SAdam Ford /* USB phy was not turned on */
44dff9f0f7SAdam Ford return 0;
45dff9f0f7SAdam Ford }
46dff9f0f7SAdam Ford
usb_phy_off(void)47dff9f0f7SAdam Ford static void usb_phy_off(void)
48dff9f0f7SAdam Ford {
49dff9f0f7SAdam Ford /* Power down the on-chip PHY. */
50dff9f0f7SAdam Ford clrsetbits_le32(&davinci_syscfg_regs->cfgchip2,
51dff9f0f7SAdam Ford CFGCHIP2_PHY_PLLON | CFGCHIP2_USB1SUSPENDM,
52dff9f0f7SAdam Ford CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN |
53dff9f0f7SAdam Ford CFGCHIP2_RESET);
54dff9f0f7SAdam Ford }
55dff9f0f7SAdam Ford
usb_cpu_init(void)5625f8bf6eSSughosh Ganu int usb_cpu_init(void)
5725f8bf6eSSughosh Ganu {
5825f8bf6eSSughosh Ganu /* enable psc for usb2.0 */
5925f8bf6eSSughosh Ganu lpsc_on(DAVINCI_LPSC_USB20);
6025f8bf6eSSughosh Ganu
6125f8bf6eSSughosh Ganu /* enable psc for usb1.0 */
6225f8bf6eSSughosh Ganu lpsc_on(DAVINCI_LPSC_USB11);
6325f8bf6eSSughosh Ganu
6425f8bf6eSSughosh Ganu /* start the on-chip usb phy and its pll */
6525f8bf6eSSughosh Ganu if (usb_phy_on())
6625f8bf6eSSughosh Ganu return 0;
6725f8bf6eSSughosh Ganu
6825f8bf6eSSughosh Ganu return 1;
6925f8bf6eSSughosh Ganu }
7025f8bf6eSSughosh Ganu
usb_cpu_stop(void)7125f8bf6eSSughosh Ganu int usb_cpu_stop(void)
7225f8bf6eSSughosh Ganu {
7325f8bf6eSSughosh Ganu usb_phy_off();
7425f8bf6eSSughosh Ganu
7525f8bf6eSSughosh Ganu /* turn off the usb clock and assert the module reset */
7625f8bf6eSSughosh Ganu lpsc_disable(DAVINCI_LPSC_USB11);
7725f8bf6eSSughosh Ganu lpsc_disable(DAVINCI_LPSC_USB20);
7825f8bf6eSSughosh Ganu
7925f8bf6eSSughosh Ganu return 0;
8025f8bf6eSSughosh Ganu }
8125f8bf6eSSughosh Ganu
usb_cpu_init_fail(void)8225f8bf6eSSughosh Ganu int usb_cpu_init_fail(void)
8325f8bf6eSSughosh Ganu {
8425f8bf6eSSughosh Ganu return usb_cpu_stop();
8525f8bf6eSSughosh Ganu }
86dff9f0f7SAdam Ford
87dff9f0f7SAdam Ford #if CONFIG_IS_ENABLED(DM_USB)
ohci_da8xx_probe(struct udevice * dev)88dff9f0f7SAdam Ford static int ohci_da8xx_probe(struct udevice *dev)
89dff9f0f7SAdam Ford {
90dff9f0f7SAdam Ford struct ohci_regs *regs = (struct ohci_regs *)devfdt_get_addr(dev);
91dff9f0f7SAdam Ford struct da8xx_ohci *priv = dev_get_priv(dev);
92dff9f0f7SAdam Ford int i, err, ret, clock_nb;
93dff9f0f7SAdam Ford
94dff9f0f7SAdam Ford err = 0;
95dff9f0f7SAdam Ford priv->clock_count = 0;
96dff9f0f7SAdam Ford clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells");
97*0620c8adSAdam Ford
98*0620c8adSAdam Ford if (clock_nb < 0)
99*0620c8adSAdam Ford return clock_nb;
100*0620c8adSAdam Ford
101dff9f0f7SAdam Ford if (clock_nb > 0) {
102dff9f0f7SAdam Ford priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk),
103dff9f0f7SAdam Ford GFP_KERNEL);
104dff9f0f7SAdam Ford if (!priv->clocks)
105dff9f0f7SAdam Ford return -ENOMEM;
106dff9f0f7SAdam Ford
107dff9f0f7SAdam Ford for (i = 0; i < clock_nb; i++) {
108dff9f0f7SAdam Ford err = clk_get_by_index(dev, i, &priv->clocks[i]);
109dff9f0f7SAdam Ford if (err < 0)
110dff9f0f7SAdam Ford break;
111dff9f0f7SAdam Ford
112dff9f0f7SAdam Ford err = clk_enable(&priv->clocks[i]);
113dff9f0f7SAdam Ford if (err) {
114dff9f0f7SAdam Ford dev_err(dev, "failed to enable clock %d\n", i);
115dff9f0f7SAdam Ford clk_free(&priv->clocks[i]);
116dff9f0f7SAdam Ford goto clk_err;
117dff9f0f7SAdam Ford }
118dff9f0f7SAdam Ford priv->clock_count++;
119dff9f0f7SAdam Ford }
120dff9f0f7SAdam Ford }
121dff9f0f7SAdam Ford
122dff9f0f7SAdam Ford err = usb_cpu_init();
123dff9f0f7SAdam Ford
124dff9f0f7SAdam Ford if (err)
125dff9f0f7SAdam Ford goto clk_err;
126dff9f0f7SAdam Ford
127dff9f0f7SAdam Ford err = ohci_register(dev, regs);
128dff9f0f7SAdam Ford if (err)
129dff9f0f7SAdam Ford goto phy_err;
130dff9f0f7SAdam Ford
131dff9f0f7SAdam Ford return 0;
132dff9f0f7SAdam Ford
133dff9f0f7SAdam Ford phy_err:
134dff9f0f7SAdam Ford ret = usb_cpu_stop();
135dff9f0f7SAdam Ford if (ret)
136dff9f0f7SAdam Ford dev_err(dev, "failed to shutdown usb phy\n");
137dff9f0f7SAdam Ford
138dff9f0f7SAdam Ford clk_err:
139dff9f0f7SAdam Ford ret = clk_release_all(priv->clocks, priv->clock_count);
140dff9f0f7SAdam Ford if (ret)
141dff9f0f7SAdam Ford dev_err(dev, "failed to disable all clocks\n");
142dff9f0f7SAdam Ford
143dff9f0f7SAdam Ford return err;
144dff9f0f7SAdam Ford }
145dff9f0f7SAdam Ford
ohci_da8xx_remove(struct udevice * dev)146dff9f0f7SAdam Ford static int ohci_da8xx_remove(struct udevice *dev)
147dff9f0f7SAdam Ford {
148dff9f0f7SAdam Ford struct da8xx_ohci *priv = dev_get_priv(dev);
149dff9f0f7SAdam Ford int ret;
150dff9f0f7SAdam Ford
151dff9f0f7SAdam Ford ret = ohci_deregister(dev);
152dff9f0f7SAdam Ford if (ret)
153dff9f0f7SAdam Ford return ret;
154dff9f0f7SAdam Ford
155dff9f0f7SAdam Ford ret = usb_cpu_stop();
156dff9f0f7SAdam Ford if (ret)
157dff9f0f7SAdam Ford return ret;
158dff9f0f7SAdam Ford
159dff9f0f7SAdam Ford return clk_release_all(priv->clocks, priv->clock_count);
160dff9f0f7SAdam Ford }
161dff9f0f7SAdam Ford
162dff9f0f7SAdam Ford static const struct udevice_id da8xx_ohci_ids[] = {
163dff9f0f7SAdam Ford { .compatible = "ti,da830-ohci" },
164dff9f0f7SAdam Ford { }
165dff9f0f7SAdam Ford };
166dff9f0f7SAdam Ford
167dff9f0f7SAdam Ford U_BOOT_DRIVER(ohci_generic) = {
168dff9f0f7SAdam Ford .name = "ohci-da8xx",
169dff9f0f7SAdam Ford .id = UCLASS_USB,
170dff9f0f7SAdam Ford .of_match = da8xx_ohci_ids,
171dff9f0f7SAdam Ford .probe = ohci_da8xx_probe,
172dff9f0f7SAdam Ford .remove = ohci_da8xx_remove,
173dff9f0f7SAdam Ford .ops = &ohci_usb_ops,
174dff9f0f7SAdam Ford .priv_auto_alloc_size = sizeof(struct da8xx_ohci),
175*0620c8adSAdam Ford .flags = DM_FLAG_ALLOC_PRIV_DMA | DM_FLAG_OS_PREPARE,
176dff9f0f7SAdam Ford };
177dff9f0f7SAdam Ford #endif
178