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 3090fbb282SAlexey Brodkin static int ehci_usb_probe(struct udevice *dev) 3190fbb282SAlexey Brodkin { 32a1cee8e8SPatrice Chotard struct generic_ehci *priv = dev_get_priv(dev); 33643cacb6SMarek Vasut struct ehci_hccr *hccr; 3490fbb282SAlexey Brodkin struct ehci_hcor *hcor; 35a1cee8e8SPatrice Chotard int i, err, ret, clock_nb, reset_nb; 364feefdcfSMasahiro Yamada 37a1cee8e8SPatrice Chotard err = 0; 38a1cee8e8SPatrice Chotard priv->clock_count = 0; 39a1cee8e8SPatrice Chotard clock_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "clocks", 40a1cee8e8SPatrice Chotard "#clock-cells"); 41a1cee8e8SPatrice Chotard if (clock_nb > 0) { 42a1cee8e8SPatrice Chotard priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk), 43a1cee8e8SPatrice Chotard GFP_KERNEL); 44a1cee8e8SPatrice Chotard if (!priv->clocks) 45a1cee8e8SPatrice Chotard return -ENOMEM; 464feefdcfSMasahiro Yamada 47a1cee8e8SPatrice Chotard for (i = 0; i < clock_nb; i++) { 48a1cee8e8SPatrice Chotard err = clk_get_by_index(dev, i, &priv->clocks[i]); 49a1cee8e8SPatrice Chotard 50a1cee8e8SPatrice Chotard if (err < 0) 514feefdcfSMasahiro Yamada break; 52a1cee8e8SPatrice Chotard err = clk_enable(&priv->clocks[i]); 53d2e45d1fSFrank Wang if (err && err != -ENOSYS) { 5490aa625cSMasahiro Yamada pr_err("failed to enable clock %d\n", i); 55a1cee8e8SPatrice Chotard clk_free(&priv->clocks[i]); 56a1cee8e8SPatrice Chotard goto clk_err; 57a1cee8e8SPatrice Chotard } 58a1cee8e8SPatrice Chotard priv->clock_count++; 59a1cee8e8SPatrice Chotard } 60a1cee8e8SPatrice Chotard } else { 61a1cee8e8SPatrice Chotard if (clock_nb != -ENOENT) { 6290aa625cSMasahiro Yamada pr_err("failed to get clock phandle(%d)\n", clock_nb); 63a1cee8e8SPatrice Chotard return clock_nb; 64a1cee8e8SPatrice Chotard } 654feefdcfSMasahiro Yamada } 6690fbb282SAlexey Brodkin 67a1cee8e8SPatrice Chotard priv->reset_count = 0; 68a1cee8e8SPatrice Chotard reset_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "resets", 69a1cee8e8SPatrice Chotard "#reset-cells"); 70a1cee8e8SPatrice Chotard if (reset_nb > 0) { 71a1cee8e8SPatrice Chotard priv->resets = devm_kcalloc(dev, reset_nb, 72a1cee8e8SPatrice Chotard sizeof(struct reset_ctl), 73a1cee8e8SPatrice Chotard GFP_KERNEL); 74a1cee8e8SPatrice Chotard if (!priv->resets) 75a1cee8e8SPatrice Chotard return -ENOMEM; 768824cfc1SMasahiro Yamada 77a1cee8e8SPatrice Chotard for (i = 0; i < reset_nb; i++) { 78a1cee8e8SPatrice Chotard err = reset_get_by_index(dev, i, &priv->resets[i]); 79a1cee8e8SPatrice Chotard if (err < 0) 808824cfc1SMasahiro Yamada break; 81a1cee8e8SPatrice Chotard 82a1cee8e8SPatrice Chotard if (reset_deassert(&priv->resets[i])) { 8390aa625cSMasahiro Yamada pr_err("failed to deassert reset %d\n", i); 84a1cee8e8SPatrice Chotard reset_free(&priv->resets[i]); 85a1cee8e8SPatrice Chotard goto reset_err; 86a1cee8e8SPatrice Chotard } 87a1cee8e8SPatrice Chotard priv->reset_count++; 88a1cee8e8SPatrice Chotard } 89a1cee8e8SPatrice Chotard } else { 90a1cee8e8SPatrice Chotard if (reset_nb != -ENOENT) { 9190aa625cSMasahiro Yamada pr_err("failed to get reset phandle(%d)\n", reset_nb); 92a1cee8e8SPatrice Chotard goto clk_err; 93a1cee8e8SPatrice Chotard } 948824cfc1SMasahiro Yamada } 958824cfc1SMasahiro Yamada 960d0ba1a7SPatrice Chotard err = generic_phy_get_by_index(dev, 0, &priv->phy); 970d0ba1a7SPatrice Chotard if (err) { 980d0ba1a7SPatrice Chotard if (err != -ENOENT) { 9990aa625cSMasahiro Yamada pr_err("failed to get usb phy\n"); 1000d0ba1a7SPatrice Chotard goto reset_err; 1010d0ba1a7SPatrice Chotard } 1024b3928a0SPatrice Chotard } else { 1030d0ba1a7SPatrice Chotard 1040d0ba1a7SPatrice Chotard err = generic_phy_init(&priv->phy); 1050d0ba1a7SPatrice Chotard if (err) { 10690aa625cSMasahiro Yamada pr_err("failed to init usb phy\n"); 1070d0ba1a7SPatrice Chotard goto reset_err; 1080d0ba1a7SPatrice Chotard } 109*3d54c056SPatrice Chotard 110*3d54c056SPatrice Chotard err = generic_phy_power_on(&priv->phy); 111*3d54c056SPatrice Chotard if (err) { 112*3d54c056SPatrice Chotard dev_err(dev, "failed to power on usb phy\n"); 113*3d54c056SPatrice Chotard goto phy_power_err; 114*3d54c056SPatrice Chotard } 1154b3928a0SPatrice Chotard } 1160d0ba1a7SPatrice Chotard 11797ff91faSPhilipp Tomsich hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE); 11890fbb282SAlexey Brodkin hcor = (struct ehci_hcor *)((uintptr_t)hccr + 11990fbb282SAlexey Brodkin HC_LENGTH(ehci_readl(&hccr->cr_capbase))); 12090fbb282SAlexey Brodkin 121a1cee8e8SPatrice Chotard err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST); 122a1cee8e8SPatrice Chotard if (err) 1230d0ba1a7SPatrice Chotard goto phy_err; 124a1cee8e8SPatrice Chotard 125a1cee8e8SPatrice Chotard return 0; 126a1cee8e8SPatrice Chotard 1270d0ba1a7SPatrice Chotard phy_err: 1280d0ba1a7SPatrice Chotard if (generic_phy_valid(&priv->phy)) { 129*3d54c056SPatrice Chotard ret = generic_phy_power_off(&priv->phy); 130*3d54c056SPatrice Chotard if (ret) 131*3d54c056SPatrice Chotard dev_err(dev, "failed to power off usb phy\n"); 132*3d54c056SPatrice Chotard } 133*3d54c056SPatrice Chotard 134*3d54c056SPatrice Chotard phy_power_err: 135*3d54c056SPatrice Chotard if (generic_phy_valid(&priv->phy)) { 1360d0ba1a7SPatrice Chotard ret = generic_phy_exit(&priv->phy); 1370d0ba1a7SPatrice Chotard if (ret) 13890aa625cSMasahiro Yamada pr_err("failed to release phy\n"); 1390d0ba1a7SPatrice Chotard } 1400d0ba1a7SPatrice Chotard 141a1cee8e8SPatrice Chotard reset_err: 142a1cee8e8SPatrice Chotard ret = reset_release_all(priv->resets, priv->reset_count); 143a1cee8e8SPatrice Chotard if (ret) 14490aa625cSMasahiro Yamada pr_err("failed to assert all resets\n"); 145a1cee8e8SPatrice Chotard clk_err: 146a1cee8e8SPatrice Chotard ret = clk_release_all(priv->clocks, priv->clock_count); 147a1cee8e8SPatrice Chotard if (ret) 14890aa625cSMasahiro Yamada pr_err("failed to disable all clocks\n"); 149a1cee8e8SPatrice Chotard 150a1cee8e8SPatrice Chotard return err; 151a1cee8e8SPatrice Chotard } 152a1cee8e8SPatrice Chotard 153a1cee8e8SPatrice Chotard static int ehci_usb_remove(struct udevice *dev) 154a1cee8e8SPatrice Chotard { 155a1cee8e8SPatrice Chotard struct generic_ehci *priv = dev_get_priv(dev); 156a1cee8e8SPatrice Chotard int ret; 157a1cee8e8SPatrice Chotard 158a1cee8e8SPatrice Chotard ret = ehci_deregister(dev); 159a1cee8e8SPatrice Chotard if (ret) 160a1cee8e8SPatrice Chotard return ret; 161a1cee8e8SPatrice Chotard 1620d0ba1a7SPatrice Chotard if (generic_phy_valid(&priv->phy)) { 163*3d54c056SPatrice Chotard ret = generic_phy_power_off(&priv->phy); 164*3d54c056SPatrice Chotard if (ret) 165*3d54c056SPatrice Chotard return ret; 166*3d54c056SPatrice Chotard 1670d0ba1a7SPatrice Chotard ret = generic_phy_exit(&priv->phy); 1680d0ba1a7SPatrice Chotard if (ret) 1690d0ba1a7SPatrice Chotard return ret; 1700d0ba1a7SPatrice Chotard } 1710d0ba1a7SPatrice Chotard 172a1cee8e8SPatrice Chotard ret = reset_release_all(priv->resets, priv->reset_count); 173a1cee8e8SPatrice Chotard if (ret) 174a1cee8e8SPatrice Chotard return ret; 175a1cee8e8SPatrice Chotard 176a1cee8e8SPatrice Chotard return clk_release_all(priv->clocks, priv->clock_count); 17790fbb282SAlexey Brodkin } 17890fbb282SAlexey Brodkin 17990fbb282SAlexey Brodkin static const struct udevice_id ehci_usb_ids[] = { 18090fbb282SAlexey Brodkin { .compatible = "generic-ehci" }, 18190fbb282SAlexey Brodkin { } 18290fbb282SAlexey Brodkin }; 18390fbb282SAlexey Brodkin 18490fbb282SAlexey Brodkin U_BOOT_DRIVER(ehci_generic) = { 18590fbb282SAlexey Brodkin .name = "ehci_generic", 18690fbb282SAlexey Brodkin .id = UCLASS_USB, 18790fbb282SAlexey Brodkin .of_match = ehci_usb_ids, 18890fbb282SAlexey Brodkin .probe = ehci_usb_probe, 189a1cee8e8SPatrice Chotard .remove = ehci_usb_remove, 19090fbb282SAlexey Brodkin .ops = &ehci_usb_ops, 19190fbb282SAlexey Brodkin .priv_auto_alloc_size = sizeof(struct generic_ehci), 19290fbb282SAlexey Brodkin .flags = DM_FLAG_ALLOC_PRIV_DMA, 19390fbb282SAlexey Brodkin }; 194