1 /* 2 * Copyright (C) 2015 Alexey Brodkin <abrodkin@synopsys.com> 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <common.h> 8 #include <clk.h> 9 #include <dm/ofnode.h> 10 #include <generic-phy.h> 11 #include <reset.h> 12 #include <asm/io.h> 13 #include <dm.h> 14 #include "ehci.h" 15 16 /* 17 * Even though here we don't explicitly use "struct ehci_ctrl" 18 * ehci_register() expects it to be the first thing that resides in 19 * device's private data. 20 */ 21 struct generic_ehci { 22 struct ehci_ctrl ctrl; 23 struct clk *clocks; 24 struct reset_ctl *resets; 25 struct phy phy; 26 int clock_count; 27 int reset_count; 28 }; 29 30 static int ehci_usb_probe(struct udevice *dev) 31 { 32 struct generic_ehci *priv = dev_get_priv(dev); 33 struct ehci_hccr *hccr; 34 struct ehci_hcor *hcor; 35 int i, err, ret, clock_nb, reset_nb; 36 37 err = 0; 38 priv->clock_count = 0; 39 clock_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "clocks", 40 "#clock-cells"); 41 if (clock_nb > 0) { 42 priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk), 43 GFP_KERNEL); 44 if (!priv->clocks) 45 return -ENOMEM; 46 47 for (i = 0; i < clock_nb; i++) { 48 err = clk_get_by_index(dev, i, &priv->clocks[i]); 49 50 if (err < 0) 51 break; 52 err = clk_enable(&priv->clocks[i]); 53 if (err) { 54 error("failed to enable clock %d\n", i); 55 clk_free(&priv->clocks[i]); 56 goto clk_err; 57 } 58 priv->clock_count++; 59 } 60 } else { 61 if (clock_nb != -ENOENT) { 62 error("failed to get clock phandle(%d)\n", clock_nb); 63 return clock_nb; 64 } 65 } 66 67 priv->reset_count = 0; 68 reset_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "resets", 69 "#reset-cells"); 70 if (reset_nb > 0) { 71 priv->resets = devm_kcalloc(dev, reset_nb, 72 sizeof(struct reset_ctl), 73 GFP_KERNEL); 74 if (!priv->resets) 75 return -ENOMEM; 76 77 for (i = 0; i < reset_nb; i++) { 78 err = reset_get_by_index(dev, i, &priv->resets[i]); 79 if (err < 0) 80 break; 81 82 if (reset_deassert(&priv->resets[i])) { 83 error("failed to deassert reset %d\n", i); 84 reset_free(&priv->resets[i]); 85 goto reset_err; 86 } 87 priv->reset_count++; 88 } 89 } else { 90 if (reset_nb != -ENOENT) { 91 error("failed to get reset phandle(%d)\n", reset_nb); 92 goto clk_err; 93 } 94 } 95 96 err = generic_phy_get_by_index(dev, 0, &priv->phy); 97 if (err) { 98 if (err != -ENOENT) { 99 error("failed to get usb phy\n"); 100 goto reset_err; 101 } 102 } else { 103 104 err = generic_phy_init(&priv->phy); 105 if (err) { 106 error("failed to init usb phy\n"); 107 goto reset_err; 108 } 109 } 110 111 hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE); 112 hcor = (struct ehci_hcor *)((uintptr_t)hccr + 113 HC_LENGTH(ehci_readl(&hccr->cr_capbase))); 114 115 err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST); 116 if (err) 117 goto phy_err; 118 119 return 0; 120 121 phy_err: 122 if (generic_phy_valid(&priv->phy)) { 123 ret = generic_phy_exit(&priv->phy); 124 if (ret) 125 error("failed to release phy\n"); 126 } 127 128 reset_err: 129 ret = reset_release_all(priv->resets, priv->reset_count); 130 if (ret) 131 error("failed to assert all resets\n"); 132 clk_err: 133 ret = clk_release_all(priv->clocks, priv->clock_count); 134 if (ret) 135 error("failed to disable all clocks\n"); 136 137 return err; 138 } 139 140 static int ehci_usb_remove(struct udevice *dev) 141 { 142 struct generic_ehci *priv = dev_get_priv(dev); 143 int ret; 144 145 ret = ehci_deregister(dev); 146 if (ret) 147 return ret; 148 149 if (generic_phy_valid(&priv->phy)) { 150 ret = generic_phy_exit(&priv->phy); 151 if (ret) 152 return ret; 153 } 154 155 ret = reset_release_all(priv->resets, priv->reset_count); 156 if (ret) 157 return ret; 158 159 return clk_release_all(priv->clocks, priv->clock_count); 160 } 161 162 static const struct udevice_id ehci_usb_ids[] = { 163 { .compatible = "generic-ehci" }, 164 { } 165 }; 166 167 U_BOOT_DRIVER(ehci_generic) = { 168 .name = "ehci_generic", 169 .id = UCLASS_USB, 170 .of_match = ehci_usb_ids, 171 .probe = ehci_usb_probe, 172 .remove = ehci_usb_remove, 173 .ops = &ehci_usb_ops, 174 .priv_auto_alloc_size = sizeof(struct generic_ehci), 175 .flags = DM_FLAG_ALLOC_PRIV_DMA, 176 }; 177