xref: /rk3399_rockchip-uboot/drivers/usb/host/ehci-generic.c (revision a1cee8e808042e2597d162b1687fdb470634271e)
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