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" 1590fbb282SAlexey Brodkin 1690fbb282SAlexey Brodkin /* 1790fbb282SAlexey Brodkin * Even though here we don't explicitly use "struct ehci_ctrl" 1890fbb282SAlexey Brodkin * ehci_register() expects it to be the first thing that resides in 1990fbb282SAlexey Brodkin * device's private data. 2090fbb282SAlexey Brodkin */ 2190fbb282SAlexey Brodkin struct generic_ehci { 2290fbb282SAlexey Brodkin struct ehci_ctrl ctrl; 23a1cee8e8SPatrice Chotard struct clk *clocks; 24a1cee8e8SPatrice Chotard struct reset_ctl *resets; 250d0ba1a7SPatrice Chotard struct phy phy; 26a1cee8e8SPatrice Chotard int clock_count; 27a1cee8e8SPatrice Chotard int reset_count; 2890fbb282SAlexey Brodkin }; 2990fbb282SAlexey Brodkin 30*f06fcfdeSPatrice Chotard static int ehci_setup_phy(struct udevice *dev, int index) 31*f06fcfdeSPatrice Chotard { 32*f06fcfdeSPatrice Chotard struct generic_ehci *priv = dev_get_priv(dev); 33*f06fcfdeSPatrice Chotard int ret; 34*f06fcfdeSPatrice Chotard 35*f06fcfdeSPatrice Chotard ret = generic_phy_get_by_index(dev, index, &priv->phy); 36*f06fcfdeSPatrice Chotard if (ret) { 37*f06fcfdeSPatrice Chotard if (ret != -ENOENT) { 38*f06fcfdeSPatrice Chotard dev_err(dev, "failed to get usb phy\n"); 39*f06fcfdeSPatrice Chotard return ret; 40*f06fcfdeSPatrice Chotard } 41*f06fcfdeSPatrice Chotard } else { 42*f06fcfdeSPatrice Chotard ret = generic_phy_init(&priv->phy); 43*f06fcfdeSPatrice Chotard if (ret) { 44*f06fcfdeSPatrice Chotard dev_err(dev, "failed to init usb phy\n"); 45*f06fcfdeSPatrice Chotard return ret; 46*f06fcfdeSPatrice Chotard } 47*f06fcfdeSPatrice Chotard 48*f06fcfdeSPatrice Chotard ret = generic_phy_power_on(&priv->phy); 49*f06fcfdeSPatrice Chotard if (ret) { 50*f06fcfdeSPatrice Chotard dev_err(dev, "failed to power on usb phy\n"); 51*f06fcfdeSPatrice Chotard return generic_phy_exit(&priv->phy); 52*f06fcfdeSPatrice Chotard } 53*f06fcfdeSPatrice Chotard } 54*f06fcfdeSPatrice Chotard 55*f06fcfdeSPatrice Chotard return 0; 56*f06fcfdeSPatrice Chotard } 57*f06fcfdeSPatrice Chotard 58*f06fcfdeSPatrice Chotard static int ehci_shutdown_phy(struct udevice *dev) 59*f06fcfdeSPatrice Chotard { 60*f06fcfdeSPatrice Chotard struct generic_ehci *priv = dev_get_priv(dev); 61*f06fcfdeSPatrice Chotard int ret = 0; 62*f06fcfdeSPatrice Chotard 63*f06fcfdeSPatrice Chotard if (generic_phy_valid(&priv->phy)) { 64*f06fcfdeSPatrice Chotard ret = generic_phy_power_off(&priv->phy); 65*f06fcfdeSPatrice Chotard if (ret) { 66*f06fcfdeSPatrice Chotard dev_err(dev, "failed to power off usb phy\n"); 67*f06fcfdeSPatrice Chotard return ret; 68*f06fcfdeSPatrice Chotard } 69*f06fcfdeSPatrice Chotard 70*f06fcfdeSPatrice Chotard ret = generic_phy_exit(&priv->phy); 71*f06fcfdeSPatrice Chotard if (ret) { 72*f06fcfdeSPatrice Chotard dev_err(dev, "failed to power off usb phy\n"); 73*f06fcfdeSPatrice Chotard return ret; 74*f06fcfdeSPatrice Chotard } 75*f06fcfdeSPatrice Chotard } 76*f06fcfdeSPatrice Chotard 77*f06fcfdeSPatrice Chotard return 0; 78*f06fcfdeSPatrice Chotard } 79*f06fcfdeSPatrice Chotard 8090fbb282SAlexey Brodkin static int ehci_usb_probe(struct udevice *dev) 8190fbb282SAlexey Brodkin { 82a1cee8e8SPatrice Chotard struct generic_ehci *priv = dev_get_priv(dev); 83643cacb6SMarek Vasut struct ehci_hccr *hccr; 8490fbb282SAlexey Brodkin struct ehci_hcor *hcor; 85a1cee8e8SPatrice Chotard int i, err, ret, clock_nb, reset_nb; 864feefdcfSMasahiro Yamada 87a1cee8e8SPatrice Chotard err = 0; 88a1cee8e8SPatrice Chotard priv->clock_count = 0; 89a1cee8e8SPatrice Chotard clock_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "clocks", 90a1cee8e8SPatrice Chotard "#clock-cells"); 91a1cee8e8SPatrice Chotard if (clock_nb > 0) { 92a1cee8e8SPatrice Chotard priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk), 93a1cee8e8SPatrice Chotard GFP_KERNEL); 94a1cee8e8SPatrice Chotard if (!priv->clocks) 95a1cee8e8SPatrice Chotard return -ENOMEM; 964feefdcfSMasahiro Yamada 97a1cee8e8SPatrice Chotard for (i = 0; i < clock_nb; i++) { 98a1cee8e8SPatrice Chotard err = clk_get_by_index(dev, i, &priv->clocks[i]); 99a1cee8e8SPatrice Chotard 100a1cee8e8SPatrice Chotard if (err < 0) 1014feefdcfSMasahiro Yamada break; 102a1cee8e8SPatrice Chotard err = clk_enable(&priv->clocks[i]); 103d2e45d1fSFrank Wang if (err && err != -ENOSYS) { 10490aa625cSMasahiro Yamada pr_err("failed to enable clock %d\n", i); 105a1cee8e8SPatrice Chotard clk_free(&priv->clocks[i]); 106a1cee8e8SPatrice Chotard goto clk_err; 107a1cee8e8SPatrice Chotard } 108a1cee8e8SPatrice Chotard priv->clock_count++; 109a1cee8e8SPatrice Chotard } 110a1cee8e8SPatrice Chotard } else { 111a1cee8e8SPatrice Chotard if (clock_nb != -ENOENT) { 11290aa625cSMasahiro Yamada pr_err("failed to get clock phandle(%d)\n", clock_nb); 113a1cee8e8SPatrice Chotard return clock_nb; 114a1cee8e8SPatrice Chotard } 1154feefdcfSMasahiro Yamada } 11690fbb282SAlexey Brodkin 117a1cee8e8SPatrice Chotard priv->reset_count = 0; 118a1cee8e8SPatrice Chotard reset_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "resets", 119a1cee8e8SPatrice Chotard "#reset-cells"); 120a1cee8e8SPatrice Chotard if (reset_nb > 0) { 121a1cee8e8SPatrice Chotard priv->resets = devm_kcalloc(dev, reset_nb, 122a1cee8e8SPatrice Chotard sizeof(struct reset_ctl), 123a1cee8e8SPatrice Chotard GFP_KERNEL); 124a1cee8e8SPatrice Chotard if (!priv->resets) 125a1cee8e8SPatrice Chotard return -ENOMEM; 1268824cfc1SMasahiro Yamada 127a1cee8e8SPatrice Chotard for (i = 0; i < reset_nb; i++) { 128a1cee8e8SPatrice Chotard err = reset_get_by_index(dev, i, &priv->resets[i]); 129a1cee8e8SPatrice Chotard if (err < 0) 1308824cfc1SMasahiro Yamada break; 131a1cee8e8SPatrice Chotard 132a1cee8e8SPatrice Chotard if (reset_deassert(&priv->resets[i])) { 13390aa625cSMasahiro Yamada pr_err("failed to deassert reset %d\n", i); 134a1cee8e8SPatrice Chotard reset_free(&priv->resets[i]); 135a1cee8e8SPatrice Chotard goto reset_err; 136a1cee8e8SPatrice Chotard } 137a1cee8e8SPatrice Chotard priv->reset_count++; 138a1cee8e8SPatrice Chotard } 139a1cee8e8SPatrice Chotard } else { 140a1cee8e8SPatrice Chotard if (reset_nb != -ENOENT) { 14190aa625cSMasahiro Yamada pr_err("failed to get reset phandle(%d)\n", reset_nb); 142a1cee8e8SPatrice Chotard goto clk_err; 143a1cee8e8SPatrice Chotard } 1448824cfc1SMasahiro Yamada } 1458824cfc1SMasahiro Yamada 146*f06fcfdeSPatrice Chotard err = ehci_setup_phy(dev, 0); 147*f06fcfdeSPatrice Chotard if (err) 1480d0ba1a7SPatrice Chotard 1490d0ba1a7SPatrice Chotard goto reset_err; 1500d0ba1a7SPatrice Chotard 15197ff91faSPhilipp Tomsich hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE); 15290fbb282SAlexey Brodkin hcor = (struct ehci_hcor *)((uintptr_t)hccr + 15390fbb282SAlexey Brodkin HC_LENGTH(ehci_readl(&hccr->cr_capbase))); 15490fbb282SAlexey Brodkin 155a1cee8e8SPatrice Chotard err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST); 156a1cee8e8SPatrice Chotard if (err) 1570d0ba1a7SPatrice Chotard goto phy_err; 158a1cee8e8SPatrice Chotard 159a1cee8e8SPatrice Chotard return 0; 160a1cee8e8SPatrice Chotard 1610d0ba1a7SPatrice Chotard phy_err: 162*f06fcfdeSPatrice Chotard ret = ehci_shutdown_phy(dev); 1633d54c056SPatrice Chotard if (ret) 164*f06fcfdeSPatrice Chotard dev_err(dev, "failed to shutdown usb phy\n"); 1650d0ba1a7SPatrice Chotard 166a1cee8e8SPatrice Chotard reset_err: 167a1cee8e8SPatrice Chotard ret = reset_release_all(priv->resets, priv->reset_count); 168a1cee8e8SPatrice Chotard if (ret) 16990aa625cSMasahiro Yamada pr_err("failed to assert all resets\n"); 170a1cee8e8SPatrice Chotard clk_err: 171a1cee8e8SPatrice Chotard ret = clk_release_all(priv->clocks, priv->clock_count); 172a1cee8e8SPatrice Chotard if (ret) 17390aa625cSMasahiro Yamada pr_err("failed to disable all clocks\n"); 174a1cee8e8SPatrice Chotard 175a1cee8e8SPatrice Chotard return err; 176a1cee8e8SPatrice Chotard } 177a1cee8e8SPatrice Chotard 178a1cee8e8SPatrice Chotard static int ehci_usb_remove(struct udevice *dev) 179a1cee8e8SPatrice Chotard { 180a1cee8e8SPatrice Chotard struct generic_ehci *priv = dev_get_priv(dev); 181a1cee8e8SPatrice Chotard int ret; 182a1cee8e8SPatrice Chotard 183a1cee8e8SPatrice Chotard ret = ehci_deregister(dev); 184a1cee8e8SPatrice Chotard if (ret) 185a1cee8e8SPatrice Chotard return ret; 186a1cee8e8SPatrice Chotard 187*f06fcfdeSPatrice Chotard ret = ehci_shutdown_phy(dev); 1883d54c056SPatrice Chotard if (ret) 1893d54c056SPatrice Chotard return ret; 1903d54c056SPatrice Chotard 191a1cee8e8SPatrice Chotard ret = reset_release_all(priv->resets, priv->reset_count); 192a1cee8e8SPatrice Chotard if (ret) 193a1cee8e8SPatrice Chotard return ret; 194a1cee8e8SPatrice Chotard 195a1cee8e8SPatrice Chotard return clk_release_all(priv->clocks, priv->clock_count); 19690fbb282SAlexey Brodkin } 19790fbb282SAlexey Brodkin 19890fbb282SAlexey Brodkin static const struct udevice_id ehci_usb_ids[] = { 19990fbb282SAlexey Brodkin { .compatible = "generic-ehci" }, 20090fbb282SAlexey Brodkin { } 20190fbb282SAlexey Brodkin }; 20290fbb282SAlexey Brodkin 20390fbb282SAlexey Brodkin U_BOOT_DRIVER(ehci_generic) = { 20490fbb282SAlexey Brodkin .name = "ehci_generic", 20590fbb282SAlexey Brodkin .id = UCLASS_USB, 20690fbb282SAlexey Brodkin .of_match = ehci_usb_ids, 20790fbb282SAlexey Brodkin .probe = ehci_usb_probe, 208a1cee8e8SPatrice Chotard .remove = ehci_usb_remove, 20990fbb282SAlexey Brodkin .ops = &ehci_usb_ops, 21090fbb282SAlexey Brodkin .priv_auto_alloc_size = sizeof(struct generic_ehci), 21190fbb282SAlexey Brodkin .flags = DM_FLAG_ALLOC_PRIV_DMA, 21290fbb282SAlexey Brodkin }; 213