190fbb282SAlexey Brodkin /* 290fbb282SAlexey Brodkin * Copyright (C) 2015 Alexey Brodkin <abrodkin@synopsys.com> 390fbb282SAlexey Brodkin * 490fbb282SAlexey Brodkin * SPDX-License-Identifier: GPL-2.0+ 590fbb282SAlexey Brodkin */ 690fbb282SAlexey Brodkin 790fbb282SAlexey Brodkin #include <common.h> 84feefdcfSMasahiro Yamada #include <clk.h> 9a1cee8e8SPatrice Chotard #include <dm/ofnode.h> 100d0ba1a7SPatrice Chotard #include <generic-phy.h> 118824cfc1SMasahiro Yamada #include <reset.h> 12643cacb6SMarek Vasut #include <asm/io.h> 1390fbb282SAlexey Brodkin #include <dm.h> 1490fbb282SAlexey Brodkin #include "ehci.h" 154e900a7dSPatrice Chotard #include <power/regulator.h> 1690fbb282SAlexey Brodkin 1790fbb282SAlexey Brodkin /* 1890fbb282SAlexey Brodkin * Even though here we don't explicitly use "struct ehci_ctrl" 1990fbb282SAlexey Brodkin * ehci_register() expects it to be the first thing that resides in 2090fbb282SAlexey Brodkin * device's private data. 2190fbb282SAlexey Brodkin */ 2290fbb282SAlexey Brodkin struct generic_ehci { 2390fbb282SAlexey Brodkin struct ehci_ctrl ctrl; 24a1cee8e8SPatrice Chotard struct clk *clocks; 25a1cee8e8SPatrice Chotard struct reset_ctl *resets; 260d0ba1a7SPatrice Chotard struct phy phy; 274e900a7dSPatrice Chotard #ifdef CONFIG_DM_REGULATOR 284e900a7dSPatrice Chotard struct udevice *vbus_supply; 294e900a7dSPatrice Chotard #endif 30a1cee8e8SPatrice Chotard int clock_count; 31a1cee8e8SPatrice Chotard int reset_count; 3290fbb282SAlexey Brodkin }; 3390fbb282SAlexey Brodkin 344e900a7dSPatrice Chotard #ifdef CONFIG_DM_REGULATOR 354e900a7dSPatrice Chotard static int ehci_enable_vbus_supply(struct udevice *dev) 364e900a7dSPatrice Chotard { 374e900a7dSPatrice Chotard struct generic_ehci *priv = dev_get_priv(dev); 384e900a7dSPatrice Chotard int ret; 394e900a7dSPatrice Chotard 404e900a7dSPatrice Chotard ret = device_get_supply_regulator(dev, "vbus-supply", 414e900a7dSPatrice Chotard &priv->vbus_supply); 424e900a7dSPatrice Chotard if (ret && ret != -ENOENT) 434e900a7dSPatrice Chotard return ret; 444e900a7dSPatrice Chotard 454e900a7dSPatrice Chotard if (priv->vbus_supply) { 464e900a7dSPatrice Chotard ret = regulator_set_enable(priv->vbus_supply, true); 474e900a7dSPatrice Chotard if (ret) { 484e900a7dSPatrice Chotard dev_err(dev, "Error enabling VBUS supply\n"); 494e900a7dSPatrice Chotard return ret; 504e900a7dSPatrice Chotard } 514e900a7dSPatrice Chotard } else { 524e900a7dSPatrice Chotard dev_dbg(dev, "No vbus supply\n"); 534e900a7dSPatrice Chotard } 544e900a7dSPatrice Chotard 554e900a7dSPatrice Chotard return 0; 564e900a7dSPatrice Chotard } 574e900a7dSPatrice Chotard 584e900a7dSPatrice Chotard static int ehci_disable_vbus_supply(struct generic_ehci *priv) 594e900a7dSPatrice Chotard { 604e900a7dSPatrice Chotard if (priv->vbus_supply) 614e900a7dSPatrice Chotard return regulator_set_enable(priv->vbus_supply, false); 624e900a7dSPatrice Chotard else 634e900a7dSPatrice Chotard return 0; 644e900a7dSPatrice Chotard } 654e900a7dSPatrice Chotard #else 664e900a7dSPatrice Chotard static int ehci_enable_vbus_supply(struct udevice *dev) 674e900a7dSPatrice Chotard { 684e900a7dSPatrice Chotard return 0; 694e900a7dSPatrice Chotard } 704e900a7dSPatrice Chotard 714e900a7dSPatrice Chotard static int ehci_disable_vbus_supply(struct generic_ehci *priv) 724e900a7dSPatrice Chotard { 734e900a7dSPatrice Chotard return 0; 744e900a7dSPatrice Chotard } 754e900a7dSPatrice Chotard #endif 764e900a7dSPatrice Chotard 7790fbb282SAlexey Brodkin static int ehci_usb_probe(struct udevice *dev) 7890fbb282SAlexey Brodkin { 79a1cee8e8SPatrice Chotard struct generic_ehci *priv = dev_get_priv(dev); 80643cacb6SMarek Vasut struct ehci_hccr *hccr; 8190fbb282SAlexey Brodkin struct ehci_hcor *hcor; 82a1cee8e8SPatrice Chotard int i, err, ret, clock_nb, reset_nb; 834feefdcfSMasahiro Yamada 84a1cee8e8SPatrice Chotard err = 0; 85a1cee8e8SPatrice Chotard priv->clock_count = 0; 86a1cee8e8SPatrice Chotard clock_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "clocks", 87a1cee8e8SPatrice Chotard "#clock-cells"); 88a1cee8e8SPatrice Chotard if (clock_nb > 0) { 89a1cee8e8SPatrice Chotard priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk), 90a1cee8e8SPatrice Chotard GFP_KERNEL); 91a1cee8e8SPatrice Chotard if (!priv->clocks) 92a1cee8e8SPatrice Chotard return -ENOMEM; 934feefdcfSMasahiro Yamada 94a1cee8e8SPatrice Chotard for (i = 0; i < clock_nb; i++) { 95a1cee8e8SPatrice Chotard err = clk_get_by_index(dev, i, &priv->clocks[i]); 96a1cee8e8SPatrice Chotard 97a1cee8e8SPatrice Chotard if (err < 0) 984feefdcfSMasahiro Yamada break; 99a1cee8e8SPatrice Chotard err = clk_enable(&priv->clocks[i]); 100*5311a685SKever Yang if (err && err != -ENOSYS) { 101b653780cSPatrice Chotard dev_err(dev, "failed to enable clock %d\n", i); 102a1cee8e8SPatrice Chotard clk_free(&priv->clocks[i]); 103a1cee8e8SPatrice Chotard goto clk_err; 104a1cee8e8SPatrice Chotard } 105a1cee8e8SPatrice Chotard priv->clock_count++; 106a1cee8e8SPatrice Chotard } 107a1cee8e8SPatrice Chotard } else { 108a1cee8e8SPatrice Chotard if (clock_nb != -ENOENT) { 109b653780cSPatrice Chotard dev_err(dev, "failed to get clock phandle(%d)\n", 110b653780cSPatrice Chotard clock_nb); 111a1cee8e8SPatrice Chotard return clock_nb; 112a1cee8e8SPatrice Chotard } 1134feefdcfSMasahiro Yamada } 11490fbb282SAlexey Brodkin 115a1cee8e8SPatrice Chotard priv->reset_count = 0; 116a1cee8e8SPatrice Chotard reset_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "resets", 117a1cee8e8SPatrice Chotard "#reset-cells"); 118a1cee8e8SPatrice Chotard if (reset_nb > 0) { 119a1cee8e8SPatrice Chotard priv->resets = devm_kcalloc(dev, reset_nb, 120a1cee8e8SPatrice Chotard sizeof(struct reset_ctl), 121a1cee8e8SPatrice Chotard GFP_KERNEL); 122a1cee8e8SPatrice Chotard if (!priv->resets) 123a1cee8e8SPatrice Chotard return -ENOMEM; 1248824cfc1SMasahiro Yamada 125a1cee8e8SPatrice Chotard for (i = 0; i < reset_nb; i++) { 126a1cee8e8SPatrice Chotard err = reset_get_by_index(dev, i, &priv->resets[i]); 127a1cee8e8SPatrice Chotard if (err < 0) 1288824cfc1SMasahiro Yamada break; 129a1cee8e8SPatrice Chotard 130a1cee8e8SPatrice Chotard if (reset_deassert(&priv->resets[i])) { 131b653780cSPatrice Chotard dev_err(dev, "failed to deassert reset %d\n", 132b653780cSPatrice Chotard i); 133a1cee8e8SPatrice Chotard reset_free(&priv->resets[i]); 134a1cee8e8SPatrice Chotard goto reset_err; 135a1cee8e8SPatrice Chotard } 136a1cee8e8SPatrice Chotard priv->reset_count++; 137a1cee8e8SPatrice Chotard } 138a1cee8e8SPatrice Chotard } else { 139a1cee8e8SPatrice Chotard if (reset_nb != -ENOENT) { 140b653780cSPatrice Chotard dev_err(dev, "failed to get reset phandle(%d)\n", 141b653780cSPatrice Chotard reset_nb); 142a1cee8e8SPatrice Chotard goto clk_err; 143a1cee8e8SPatrice Chotard } 1448824cfc1SMasahiro Yamada } 1458824cfc1SMasahiro Yamada 1464e900a7dSPatrice Chotard err = ehci_enable_vbus_supply(dev); 147f06fcfdeSPatrice Chotard if (err) 1480d0ba1a7SPatrice Chotard goto reset_err; 1490d0ba1a7SPatrice Chotard 1504e900a7dSPatrice Chotard err = ehci_setup_phy(dev, &priv->phy, 0); 1514e900a7dSPatrice Chotard if (err) 1524e900a7dSPatrice Chotard goto regulator_err; 1534e900a7dSPatrice Chotard 15497ff91faSPhilipp Tomsich hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE); 15590fbb282SAlexey Brodkin hcor = (struct ehci_hcor *)((uintptr_t)hccr + 15690fbb282SAlexey Brodkin HC_LENGTH(ehci_readl(&hccr->cr_capbase))); 15790fbb282SAlexey Brodkin 158a1cee8e8SPatrice Chotard err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST); 159a1cee8e8SPatrice Chotard if (err) 1600d0ba1a7SPatrice Chotard goto phy_err; 161a1cee8e8SPatrice Chotard 162a1cee8e8SPatrice Chotard return 0; 163a1cee8e8SPatrice Chotard 1640d0ba1a7SPatrice Chotard phy_err: 165f5439a16SMarek Vasut ret = ehci_shutdown_phy(dev, &priv->phy); 1663d54c056SPatrice Chotard if (ret) 167f06fcfdeSPatrice Chotard dev_err(dev, "failed to shutdown usb phy\n"); 1680d0ba1a7SPatrice Chotard 1694e900a7dSPatrice Chotard regulator_err: 1704e900a7dSPatrice Chotard ret = ehci_disable_vbus_supply(priv); 1714e900a7dSPatrice Chotard if (ret) 1724e900a7dSPatrice Chotard dev_err(dev, "failed to disable VBUS supply\n"); 1734e900a7dSPatrice Chotard 174a1cee8e8SPatrice Chotard reset_err: 175a1cee8e8SPatrice Chotard ret = reset_release_all(priv->resets, priv->reset_count); 176a1cee8e8SPatrice Chotard if (ret) 177b653780cSPatrice Chotard dev_err(dev, "failed to assert all resets\n"); 178a1cee8e8SPatrice Chotard clk_err: 179a1cee8e8SPatrice Chotard ret = clk_release_all(priv->clocks, priv->clock_count); 180a1cee8e8SPatrice Chotard if (ret) 181b653780cSPatrice Chotard dev_err(dev, "failed to disable all clocks\n"); 182a1cee8e8SPatrice Chotard 183a1cee8e8SPatrice Chotard return err; 184a1cee8e8SPatrice Chotard } 185a1cee8e8SPatrice Chotard 186a1cee8e8SPatrice Chotard static int ehci_usb_remove(struct udevice *dev) 187a1cee8e8SPatrice Chotard { 188a1cee8e8SPatrice Chotard struct generic_ehci *priv = dev_get_priv(dev); 189a1cee8e8SPatrice Chotard int ret; 190a1cee8e8SPatrice Chotard 191a1cee8e8SPatrice Chotard ret = ehci_deregister(dev); 192a1cee8e8SPatrice Chotard if (ret) 193a1cee8e8SPatrice Chotard return ret; 194a1cee8e8SPatrice Chotard 195f5439a16SMarek Vasut ret = ehci_shutdown_phy(dev, &priv->phy); 1963d54c056SPatrice Chotard if (ret) 1973d54c056SPatrice Chotard return ret; 1983d54c056SPatrice Chotard 1994e900a7dSPatrice Chotard ret = ehci_disable_vbus_supply(priv); 2004e900a7dSPatrice Chotard if (ret) 2014e900a7dSPatrice Chotard return ret; 2024e900a7dSPatrice Chotard 203a1cee8e8SPatrice Chotard ret = reset_release_all(priv->resets, priv->reset_count); 204a1cee8e8SPatrice Chotard if (ret) 205a1cee8e8SPatrice Chotard return ret; 206a1cee8e8SPatrice Chotard 207a1cee8e8SPatrice Chotard return clk_release_all(priv->clocks, priv->clock_count); 20890fbb282SAlexey Brodkin } 20990fbb282SAlexey Brodkin 21090fbb282SAlexey Brodkin static const struct udevice_id ehci_usb_ids[] = { 21190fbb282SAlexey Brodkin { .compatible = "generic-ehci" }, 21290fbb282SAlexey Brodkin { } 21390fbb282SAlexey Brodkin }; 21490fbb282SAlexey Brodkin 21590fbb282SAlexey Brodkin U_BOOT_DRIVER(ehci_generic) = { 21690fbb282SAlexey Brodkin .name = "ehci_generic", 21790fbb282SAlexey Brodkin .id = UCLASS_USB, 21890fbb282SAlexey Brodkin .of_match = ehci_usb_ids, 21990fbb282SAlexey Brodkin .probe = ehci_usb_probe, 220a1cee8e8SPatrice Chotard .remove = ehci_usb_remove, 22190fbb282SAlexey Brodkin .ops = &ehci_usb_ops, 22290fbb282SAlexey Brodkin .priv_auto_alloc_size = sizeof(struct generic_ehci), 22390fbb282SAlexey Brodkin .flags = DM_FLAG_ALLOC_PRIV_DMA, 22490fbb282SAlexey Brodkin }; 225