1 /* 2 * Copyright (C) 2012 Sughosh Ganu <urwithsughosh@gmail.com> 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <common.h> 8 #include <asm/io.h> 9 #include <clk.h> 10 #include <dm.h> 11 #include <dm/ofnode.h> 12 #include <generic-phy.h> 13 #include <reset.h> 14 #include "ohci.h" 15 #include <asm/arch/da8xx-usb.h> 16 17 struct da8xx_ohci { 18 ohci_t ohci; 19 struct clk *clocks; /* clock list */ 20 struct phy phy; 21 int clock_count; /* number of clock in clock list */ 22 }; 23 24 static int usb_phy_on(void) 25 { 26 unsigned long timeout; 27 28 clrsetbits_le32(&davinci_syscfg_regs->cfgchip2, 29 (CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN | 30 CFGCHIP2_OTGPWRDN | CFGCHIP2_OTGMODE | 31 CFGCHIP2_REFFREQ | CFGCHIP2_USB1PHYCLKMUX), 32 (CFGCHIP2_SESENDEN | CFGCHIP2_VBDTCTEN | 33 CFGCHIP2_PHY_PLLON | CFGCHIP2_REFFREQ_24MHZ | 34 CFGCHIP2_USB2PHYCLKMUX | CFGCHIP2_USB1SUSPENDM)); 35 36 /* wait until the usb phy pll locks */ 37 timeout = get_timer(0); 38 while (get_timer(timeout) < 10) { 39 if (readl(&davinci_syscfg_regs->cfgchip2) & CFGCHIP2_PHYCLKGD) 40 return 1; 41 } 42 43 /* USB phy was not turned on */ 44 return 0; 45 } 46 47 static void usb_phy_off(void) 48 { 49 /* Power down the on-chip PHY. */ 50 clrsetbits_le32(&davinci_syscfg_regs->cfgchip2, 51 CFGCHIP2_PHY_PLLON | CFGCHIP2_USB1SUSPENDM, 52 CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN | 53 CFGCHIP2_RESET); 54 } 55 56 int usb_cpu_init(void) 57 { 58 /* enable psc for usb2.0 */ 59 lpsc_on(DAVINCI_LPSC_USB20); 60 61 /* enable psc for usb1.0 */ 62 lpsc_on(DAVINCI_LPSC_USB11); 63 64 /* start the on-chip usb phy and its pll */ 65 if (usb_phy_on()) 66 return 0; 67 68 return 1; 69 } 70 71 int usb_cpu_stop(void) 72 { 73 usb_phy_off(); 74 75 /* turn off the usb clock and assert the module reset */ 76 lpsc_disable(DAVINCI_LPSC_USB11); 77 lpsc_disable(DAVINCI_LPSC_USB20); 78 79 return 0; 80 } 81 82 int usb_cpu_init_fail(void) 83 { 84 return usb_cpu_stop(); 85 } 86 87 #if CONFIG_IS_ENABLED(DM_USB) 88 static int ohci_da8xx_probe(struct udevice *dev) 89 { 90 struct ohci_regs *regs = (struct ohci_regs *)devfdt_get_addr(dev); 91 struct da8xx_ohci *priv = dev_get_priv(dev); 92 int i, err, ret, clock_nb; 93 94 err = 0; 95 priv->clock_count = 0; 96 clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells"); 97 if (clock_nb > 0) { 98 priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk), 99 GFP_KERNEL); 100 if (!priv->clocks) 101 return -ENOMEM; 102 103 for (i = 0; i < clock_nb; i++) { 104 err = clk_get_by_index(dev, i, &priv->clocks[i]); 105 if (err < 0) 106 break; 107 108 err = clk_enable(&priv->clocks[i]); 109 if (err) { 110 dev_err(dev, "failed to enable clock %d\n", i); 111 clk_free(&priv->clocks[i]); 112 goto clk_err; 113 } 114 priv->clock_count++; 115 } 116 } else if (clock_nb != -ENOENT) { 117 dev_err(dev, "failed to get clock phandle(%d)\n", clock_nb); 118 return clock_nb; 119 } 120 121 err = usb_cpu_init(); 122 123 if (err) 124 goto clk_err; 125 126 err = ohci_register(dev, regs); 127 if (err) 128 goto phy_err; 129 130 return 0; 131 132 phy_err: 133 ret = usb_cpu_stop(); 134 if (ret) 135 dev_err(dev, "failed to shutdown usb phy\n"); 136 137 clk_err: 138 ret = clk_release_all(priv->clocks, priv->clock_count); 139 if (ret) 140 dev_err(dev, "failed to disable all clocks\n"); 141 142 return err; 143 } 144 145 static int ohci_da8xx_remove(struct udevice *dev) 146 { 147 struct da8xx_ohci *priv = dev_get_priv(dev); 148 int ret; 149 150 ret = ohci_deregister(dev); 151 if (ret) 152 return ret; 153 154 ret = usb_cpu_stop(); 155 if (ret) 156 return ret; 157 158 return clk_release_all(priv->clocks, priv->clock_count); 159 } 160 161 static const struct udevice_id da8xx_ohci_ids[] = { 162 { .compatible = "ti,da830-ohci" }, 163 { } 164 }; 165 166 U_BOOT_DRIVER(ohci_generic) = { 167 .name = "ohci-da8xx", 168 .id = UCLASS_USB, 169 .of_match = da8xx_ohci_ids, 170 .probe = ohci_da8xx_probe, 171 .remove = ohci_da8xx_remove, 172 .ops = &ohci_usb_ops, 173 .priv_auto_alloc_size = sizeof(struct da8xx_ohci), 174 .flags = DM_FLAG_ALLOC_PRIV_DMA, 175 }; 176 #endif 177