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> 9*a1cee8e8SPatrice Chotard #include <dm/ofnode.h> 108824cfc1SMasahiro Yamada #include <reset.h> 11643cacb6SMarek Vasut #include <asm/io.h> 1290fbb282SAlexey Brodkin #include <dm.h> 1390fbb282SAlexey Brodkin #include "ehci.h" 1490fbb282SAlexey Brodkin 1590fbb282SAlexey Brodkin /* 1690fbb282SAlexey Brodkin * Even though here we don't explicitly use "struct ehci_ctrl" 1790fbb282SAlexey Brodkin * ehci_register() expects it to be the first thing that resides in 1890fbb282SAlexey Brodkin * device's private data. 1990fbb282SAlexey Brodkin */ 2090fbb282SAlexey Brodkin struct generic_ehci { 2190fbb282SAlexey Brodkin struct ehci_ctrl ctrl; 22*a1cee8e8SPatrice Chotard struct clk *clocks; 23*a1cee8e8SPatrice Chotard struct reset_ctl *resets; 24*a1cee8e8SPatrice Chotard int clock_count; 25*a1cee8e8SPatrice Chotard int reset_count; 2690fbb282SAlexey Brodkin }; 2790fbb282SAlexey Brodkin 2890fbb282SAlexey Brodkin static int ehci_usb_probe(struct udevice *dev) 2990fbb282SAlexey Brodkin { 30*a1cee8e8SPatrice Chotard struct generic_ehci *priv = dev_get_priv(dev); 31643cacb6SMarek Vasut struct ehci_hccr *hccr; 3290fbb282SAlexey Brodkin struct ehci_hcor *hcor; 33*a1cee8e8SPatrice Chotard int i, err, ret, clock_nb, reset_nb; 344feefdcfSMasahiro Yamada 35*a1cee8e8SPatrice Chotard err = 0; 36*a1cee8e8SPatrice Chotard priv->clock_count = 0; 37*a1cee8e8SPatrice Chotard clock_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "clocks", 38*a1cee8e8SPatrice Chotard "#clock-cells"); 39*a1cee8e8SPatrice Chotard if (clock_nb > 0) { 40*a1cee8e8SPatrice Chotard priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk), 41*a1cee8e8SPatrice Chotard GFP_KERNEL); 42*a1cee8e8SPatrice Chotard if (!priv->clocks) 43*a1cee8e8SPatrice Chotard return -ENOMEM; 444feefdcfSMasahiro Yamada 45*a1cee8e8SPatrice Chotard for (i = 0; i < clock_nb; i++) { 46*a1cee8e8SPatrice Chotard err = clk_get_by_index(dev, i, &priv->clocks[i]); 47*a1cee8e8SPatrice Chotard 48*a1cee8e8SPatrice Chotard if (err < 0) 494feefdcfSMasahiro Yamada break; 50*a1cee8e8SPatrice Chotard err = clk_enable(&priv->clocks[i]); 51*a1cee8e8SPatrice Chotard if (err) { 5210bb775eSPatrice Chotard error("failed to enable clock %d\n", i); 53*a1cee8e8SPatrice Chotard clk_free(&priv->clocks[i]); 54*a1cee8e8SPatrice Chotard goto clk_err; 55*a1cee8e8SPatrice Chotard } 56*a1cee8e8SPatrice Chotard priv->clock_count++; 57*a1cee8e8SPatrice Chotard } 58*a1cee8e8SPatrice Chotard } else { 59*a1cee8e8SPatrice Chotard if (clock_nb != -ENOENT) { 60*a1cee8e8SPatrice Chotard error("failed to get clock phandle(%d)\n", clock_nb); 61*a1cee8e8SPatrice Chotard return clock_nb; 62*a1cee8e8SPatrice Chotard } 634feefdcfSMasahiro Yamada } 6490fbb282SAlexey Brodkin 65*a1cee8e8SPatrice Chotard priv->reset_count = 0; 66*a1cee8e8SPatrice Chotard reset_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "resets", 67*a1cee8e8SPatrice Chotard "#reset-cells"); 68*a1cee8e8SPatrice Chotard if (reset_nb > 0) { 69*a1cee8e8SPatrice Chotard priv->resets = devm_kcalloc(dev, reset_nb, 70*a1cee8e8SPatrice Chotard sizeof(struct reset_ctl), 71*a1cee8e8SPatrice Chotard GFP_KERNEL); 72*a1cee8e8SPatrice Chotard if (!priv->resets) 73*a1cee8e8SPatrice Chotard return -ENOMEM; 748824cfc1SMasahiro Yamada 75*a1cee8e8SPatrice Chotard for (i = 0; i < reset_nb; i++) { 76*a1cee8e8SPatrice Chotard err = reset_get_by_index(dev, i, &priv->resets[i]); 77*a1cee8e8SPatrice Chotard if (err < 0) 788824cfc1SMasahiro Yamada break; 79*a1cee8e8SPatrice Chotard 80*a1cee8e8SPatrice Chotard if (reset_deassert(&priv->resets[i])) { 8110bb775eSPatrice Chotard error("failed to deassert reset %d\n", i); 82*a1cee8e8SPatrice Chotard reset_free(&priv->resets[i]); 83*a1cee8e8SPatrice Chotard goto reset_err; 84*a1cee8e8SPatrice Chotard } 85*a1cee8e8SPatrice Chotard priv->reset_count++; 86*a1cee8e8SPatrice Chotard } 87*a1cee8e8SPatrice Chotard } else { 88*a1cee8e8SPatrice Chotard if (reset_nb != -ENOENT) { 89*a1cee8e8SPatrice Chotard error("failed to get reset phandle(%d)\n", reset_nb); 90*a1cee8e8SPatrice Chotard goto clk_err; 91*a1cee8e8SPatrice Chotard } 928824cfc1SMasahiro Yamada } 938824cfc1SMasahiro Yamada 94a821c4afSSimon Glass hccr = map_physmem(devfdt_get_addr(dev), 0x100, MAP_NOCACHE); 9590fbb282SAlexey Brodkin hcor = (struct ehci_hcor *)((uintptr_t)hccr + 9690fbb282SAlexey Brodkin HC_LENGTH(ehci_readl(&hccr->cr_capbase))); 9790fbb282SAlexey Brodkin 98*a1cee8e8SPatrice Chotard err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST); 99*a1cee8e8SPatrice Chotard if (err) 100*a1cee8e8SPatrice Chotard goto reset_err; 101*a1cee8e8SPatrice Chotard 102*a1cee8e8SPatrice Chotard return 0; 103*a1cee8e8SPatrice Chotard 104*a1cee8e8SPatrice Chotard reset_err: 105*a1cee8e8SPatrice Chotard ret = reset_release_all(priv->resets, priv->reset_count); 106*a1cee8e8SPatrice Chotard if (ret) 107*a1cee8e8SPatrice Chotard error("failed to assert all resets\n"); 108*a1cee8e8SPatrice Chotard clk_err: 109*a1cee8e8SPatrice Chotard ret = clk_release_all(priv->clocks, priv->clock_count); 110*a1cee8e8SPatrice Chotard if (ret) 111*a1cee8e8SPatrice Chotard error("failed to disable all clocks\n"); 112*a1cee8e8SPatrice Chotard 113*a1cee8e8SPatrice Chotard return err; 114*a1cee8e8SPatrice Chotard } 115*a1cee8e8SPatrice Chotard 116*a1cee8e8SPatrice Chotard static int ehci_usb_remove(struct udevice *dev) 117*a1cee8e8SPatrice Chotard { 118*a1cee8e8SPatrice Chotard struct generic_ehci *priv = dev_get_priv(dev); 119*a1cee8e8SPatrice Chotard int ret; 120*a1cee8e8SPatrice Chotard 121*a1cee8e8SPatrice Chotard ret = ehci_deregister(dev); 122*a1cee8e8SPatrice Chotard if (ret) 123*a1cee8e8SPatrice Chotard return ret; 124*a1cee8e8SPatrice Chotard 125*a1cee8e8SPatrice Chotard ret = reset_release_all(priv->resets, priv->reset_count); 126*a1cee8e8SPatrice Chotard if (ret) 127*a1cee8e8SPatrice Chotard return ret; 128*a1cee8e8SPatrice Chotard 129*a1cee8e8SPatrice Chotard return clk_release_all(priv->clocks, priv->clock_count); 13090fbb282SAlexey Brodkin } 13190fbb282SAlexey Brodkin 13290fbb282SAlexey Brodkin static const struct udevice_id ehci_usb_ids[] = { 13390fbb282SAlexey Brodkin { .compatible = "generic-ehci" }, 13490fbb282SAlexey Brodkin { } 13590fbb282SAlexey Brodkin }; 13690fbb282SAlexey Brodkin 13790fbb282SAlexey Brodkin U_BOOT_DRIVER(ehci_generic) = { 13890fbb282SAlexey Brodkin .name = "ehci_generic", 13990fbb282SAlexey Brodkin .id = UCLASS_USB, 14090fbb282SAlexey Brodkin .of_match = ehci_usb_ids, 14190fbb282SAlexey Brodkin .probe = ehci_usb_probe, 142*a1cee8e8SPatrice Chotard .remove = ehci_usb_remove, 14390fbb282SAlexey Brodkin .ops = &ehci_usb_ops, 14490fbb282SAlexey Brodkin .priv_auto_alloc_size = sizeof(struct generic_ehci), 14590fbb282SAlexey Brodkin .flags = DM_FLAG_ALLOC_PRIV_DMA, 14690fbb282SAlexey Brodkin }; 147