183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2f55c1538SÁlvaro Fernández Rojas /*
3*25d8380fSÁlvaro Fernández Rojas  * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
4f55c1538SÁlvaro Fernández Rojas  *
5f55c1538SÁlvaro Fernández Rojas  * Derived from linux/arch/mips/bcm63xx/usb-common.c:
6f55c1538SÁlvaro Fernández Rojas  *	Copyright 2008 Maxime Bizon <mbizon@freebox.fr>
7f55c1538SÁlvaro Fernández Rojas  *	Copyright 2013 Florian Fainelli <florian@openwrt.org>
8f55c1538SÁlvaro Fernández Rojas  */
9f55c1538SÁlvaro Fernández Rojas 
10f55c1538SÁlvaro Fernández Rojas #include <common.h>
11f55c1538SÁlvaro Fernández Rojas #include <clk.h>
12f55c1538SÁlvaro Fernández Rojas #include <dm.h>
13f55c1538SÁlvaro Fernández Rojas #include <generic-phy.h>
14f55c1538SÁlvaro Fernández Rojas #include <power-domain.h>
15f55c1538SÁlvaro Fernández Rojas #include <reset.h>
16f55c1538SÁlvaro Fernández Rojas #include <asm/io.h>
17f55c1538SÁlvaro Fernández Rojas #include <dm/device.h>
18f55c1538SÁlvaro Fernández Rojas 
19f55c1538SÁlvaro Fernández Rojas /* USBH PLL Control register */
20f55c1538SÁlvaro Fernández Rojas #define USBH_PLL_REG		0x18
21f55c1538SÁlvaro Fernández Rojas #define USBH_PLL_IDDQ_PWRDN	BIT(9)
22f55c1538SÁlvaro Fernández Rojas #define USBH_PLL_PWRDN_DELAY	BIT(10)
23f55c1538SÁlvaro Fernández Rojas 
24f55c1538SÁlvaro Fernández Rojas /* USBH Swap Control register */
25f55c1538SÁlvaro Fernández Rojas #define USBH_SWAP_REG		0x1c
26f55c1538SÁlvaro Fernández Rojas #define USBH_SWAP_OHCI_DATA	BIT(0)
27f55c1538SÁlvaro Fernández Rojas #define USBH_SWAP_OHCI_ENDIAN	BIT(1)
28f55c1538SÁlvaro Fernández Rojas #define USBH_SWAP_EHCI_DATA	BIT(3)
29f55c1538SÁlvaro Fernández Rojas #define USBH_SWAP_EHCI_ENDIAN	BIT(4)
30f55c1538SÁlvaro Fernández Rojas 
31f55c1538SÁlvaro Fernández Rojas /* USBH Setup register */
32f55c1538SÁlvaro Fernández Rojas #define USBH_SETUP_REG		0x28
33f55c1538SÁlvaro Fernández Rojas #define USBH_SETUP_IOC		BIT(4)
34f55c1538SÁlvaro Fernández Rojas #define USBH_SETUP_IPP		BIT(5)
35f55c1538SÁlvaro Fernández Rojas 
36f55c1538SÁlvaro Fernández Rojas struct bcm6368_usbh_hw {
37f55c1538SÁlvaro Fernández Rojas 	uint32_t setup_clr;
38f55c1538SÁlvaro Fernández Rojas 	uint32_t pll_clr;
39f55c1538SÁlvaro Fernández Rojas };
40f55c1538SÁlvaro Fernández Rojas 
41f55c1538SÁlvaro Fernández Rojas struct bcm6368_usbh_priv {
42f55c1538SÁlvaro Fernández Rojas 	const struct bcm6368_usbh_hw *hw;
43f55c1538SÁlvaro Fernández Rojas 	void __iomem *regs;
44f55c1538SÁlvaro Fernández Rojas };
45f55c1538SÁlvaro Fernández Rojas 
bcm6368_usbh_init(struct phy * phy)46f55c1538SÁlvaro Fernández Rojas static int bcm6368_usbh_init(struct phy *phy)
47f55c1538SÁlvaro Fernández Rojas {
48f55c1538SÁlvaro Fernández Rojas 	struct bcm6368_usbh_priv *priv = dev_get_priv(phy->dev);
49f55c1538SÁlvaro Fernández Rojas 	const struct bcm6368_usbh_hw *hw = priv->hw;
50f55c1538SÁlvaro Fernández Rojas 
51f55c1538SÁlvaro Fernández Rojas 	/* configure to work in native cpu endian */
52f55c1538SÁlvaro Fernández Rojas 	clrsetbits_be32(priv->regs + USBH_SWAP_REG,
53f55c1538SÁlvaro Fernández Rojas 			USBH_SWAP_EHCI_ENDIAN | USBH_SWAP_OHCI_ENDIAN,
54f55c1538SÁlvaro Fernández Rojas 			USBH_SWAP_EHCI_DATA | USBH_SWAP_OHCI_DATA);
55f55c1538SÁlvaro Fernández Rojas 
56f55c1538SÁlvaro Fernández Rojas 	/* setup config */
57f55c1538SÁlvaro Fernández Rojas 	if (hw->setup_clr)
58f55c1538SÁlvaro Fernández Rojas 		clrbits_be32(priv->regs + USBH_SETUP_REG, hw->setup_clr);
59f55c1538SÁlvaro Fernández Rojas 
60f55c1538SÁlvaro Fernández Rojas 	setbits_be32(priv->regs + USBH_SETUP_REG, USBH_SETUP_IOC);
61f55c1538SÁlvaro Fernández Rojas 
62f55c1538SÁlvaro Fernández Rojas 	/* enable pll control */
63f55c1538SÁlvaro Fernández Rojas 	if (hw->pll_clr)
64f55c1538SÁlvaro Fernández Rojas 		clrbits_be32(priv->regs + USBH_PLL_REG, hw->pll_clr);
65f55c1538SÁlvaro Fernández Rojas 
66f55c1538SÁlvaro Fernández Rojas 	return 0;
67f55c1538SÁlvaro Fernández Rojas }
68f55c1538SÁlvaro Fernández Rojas 
69f55c1538SÁlvaro Fernández Rojas static struct phy_ops bcm6368_usbh_ops = {
70f55c1538SÁlvaro Fernández Rojas 	.init = bcm6368_usbh_init,
71f55c1538SÁlvaro Fernández Rojas };
72f55c1538SÁlvaro Fernández Rojas 
73f55c1538SÁlvaro Fernández Rojas static const struct bcm6368_usbh_hw bcm6328_hw = {
74f55c1538SÁlvaro Fernández Rojas 	.pll_clr = USBH_PLL_IDDQ_PWRDN | USBH_PLL_PWRDN_DELAY,
75f55c1538SÁlvaro Fernández Rojas 	.setup_clr = 0,
76f55c1538SÁlvaro Fernández Rojas };
77f55c1538SÁlvaro Fernández Rojas 
78f55c1538SÁlvaro Fernández Rojas static const struct bcm6368_usbh_hw bcm6362_hw = {
79f55c1538SÁlvaro Fernández Rojas 	.pll_clr = 0,
80f55c1538SÁlvaro Fernández Rojas 	.setup_clr = 0,
81f55c1538SÁlvaro Fernández Rojas };
82f55c1538SÁlvaro Fernández Rojas 
83f55c1538SÁlvaro Fernández Rojas static const struct bcm6368_usbh_hw bcm6368_hw = {
84f55c1538SÁlvaro Fernández Rojas 	.pll_clr = 0,
85f55c1538SÁlvaro Fernández Rojas 	.setup_clr = 0,
86f55c1538SÁlvaro Fernández Rojas };
87f55c1538SÁlvaro Fernández Rojas 
88f55c1538SÁlvaro Fernández Rojas static const struct bcm6368_usbh_hw bcm63268_hw = {
89f55c1538SÁlvaro Fernández Rojas 	.pll_clr = USBH_PLL_IDDQ_PWRDN | USBH_PLL_PWRDN_DELAY,
90f55c1538SÁlvaro Fernández Rojas 	.setup_clr = USBH_SETUP_IPP,
91f55c1538SÁlvaro Fernández Rojas };
92f55c1538SÁlvaro Fernández Rojas 
93f55c1538SÁlvaro Fernández Rojas static const struct udevice_id bcm6368_usbh_ids[] = {
94f55c1538SÁlvaro Fernández Rojas 	{
95f55c1538SÁlvaro Fernández Rojas 		.compatible = "brcm,bcm6328-usbh",
96f55c1538SÁlvaro Fernández Rojas 		.data = (ulong)&bcm6328_hw,
97f55c1538SÁlvaro Fernández Rojas 	}, {
98f55c1538SÁlvaro Fernández Rojas 		.compatible = "brcm,bcm6362-usbh",
99f55c1538SÁlvaro Fernández Rojas 		.data = (ulong)&bcm6362_hw,
100f55c1538SÁlvaro Fernández Rojas 	}, {
101f55c1538SÁlvaro Fernández Rojas 		.compatible = "brcm,bcm6368-usbh",
102f55c1538SÁlvaro Fernández Rojas 		.data = (ulong)&bcm6368_hw,
103f55c1538SÁlvaro Fernández Rojas 	}, {
104f55c1538SÁlvaro Fernández Rojas 		.compatible = "brcm,bcm63268-usbh",
105f55c1538SÁlvaro Fernández Rojas 		.data = (ulong)&bcm63268_hw,
106f55c1538SÁlvaro Fernández Rojas 	}, { /* sentinel */ }
107f55c1538SÁlvaro Fernández Rojas };
108f55c1538SÁlvaro Fernández Rojas 
bcm6368_usbh_probe(struct udevice * dev)109f55c1538SÁlvaro Fernández Rojas static int bcm6368_usbh_probe(struct udevice *dev)
110f55c1538SÁlvaro Fernández Rojas {
111f55c1538SÁlvaro Fernández Rojas 	struct bcm6368_usbh_priv *priv = dev_get_priv(dev);
112f55c1538SÁlvaro Fernández Rojas 	const struct bcm6368_usbh_hw *hw =
113f55c1538SÁlvaro Fernández Rojas 		(const struct bcm6368_usbh_hw *)dev_get_driver_data(dev);
114f55c1538SÁlvaro Fernández Rojas #if defined(CONFIG_POWER_DOMAIN)
115f55c1538SÁlvaro Fernández Rojas 	struct power_domain pwr_dom;
116f55c1538SÁlvaro Fernández Rojas #endif
117f55c1538SÁlvaro Fernández Rojas 	struct reset_ctl rst_ctl;
118f55c1538SÁlvaro Fernández Rojas 	struct clk clk;
119f55c1538SÁlvaro Fernández Rojas 	int ret;
120f55c1538SÁlvaro Fernández Rojas 
121*25d8380fSÁlvaro Fernández Rojas 	priv->regs = dev_remap_addr(dev);
122*25d8380fSÁlvaro Fernández Rojas 	if (!priv->regs)
123f55c1538SÁlvaro Fernández Rojas 		return -EINVAL;
124f55c1538SÁlvaro Fernández Rojas 
125f55c1538SÁlvaro Fernández Rojas 	priv->hw = hw;
126f55c1538SÁlvaro Fernández Rojas 
127f55c1538SÁlvaro Fernández Rojas 	/* enable usbh clock */
128f55c1538SÁlvaro Fernández Rojas 	ret = clk_get_by_name(dev, "usbh", &clk);
129f55c1538SÁlvaro Fernández Rojas 	if (ret < 0)
130f55c1538SÁlvaro Fernández Rojas 		return ret;
131f55c1538SÁlvaro Fernández Rojas 
132f55c1538SÁlvaro Fernández Rojas 	ret = clk_enable(&clk);
133f55c1538SÁlvaro Fernández Rojas 	if (ret < 0)
134f55c1538SÁlvaro Fernández Rojas 		return ret;
135f55c1538SÁlvaro Fernández Rojas 
136f55c1538SÁlvaro Fernández Rojas 	ret = clk_free(&clk);
137f55c1538SÁlvaro Fernández Rojas 	if (ret < 0)
138f55c1538SÁlvaro Fernández Rojas 		return ret;
139f55c1538SÁlvaro Fernández Rojas 
140f55c1538SÁlvaro Fernández Rojas #if defined(CONFIG_POWER_DOMAIN)
141f55c1538SÁlvaro Fernández Rojas 	/* enable power domain */
142f55c1538SÁlvaro Fernández Rojas 	ret = power_domain_get(dev, &pwr_dom);
143f55c1538SÁlvaro Fernández Rojas 	if (ret < 0)
144f55c1538SÁlvaro Fernández Rojas 		return ret;
145f55c1538SÁlvaro Fernández Rojas 
146f55c1538SÁlvaro Fernández Rojas 	ret = power_domain_on(&pwr_dom);
147f55c1538SÁlvaro Fernández Rojas 	if (ret < 0)
148f55c1538SÁlvaro Fernández Rojas 		return ret;
149f55c1538SÁlvaro Fernández Rojas 
150f55c1538SÁlvaro Fernández Rojas 	ret = power_domain_free(&pwr_dom);
151f55c1538SÁlvaro Fernández Rojas 	if (ret < 0)
152f55c1538SÁlvaro Fernández Rojas 		return ret;
153f55c1538SÁlvaro Fernández Rojas #endif
154f55c1538SÁlvaro Fernández Rojas 
155f55c1538SÁlvaro Fernández Rojas 	/* perform reset */
156f55c1538SÁlvaro Fernández Rojas 	ret = reset_get_by_index(dev, 0, &rst_ctl);
157f55c1538SÁlvaro Fernández Rojas 	if (ret < 0)
158f55c1538SÁlvaro Fernández Rojas 		return ret;
159f55c1538SÁlvaro Fernández Rojas 
160f55c1538SÁlvaro Fernández Rojas 	ret = reset_deassert(&rst_ctl);
161f55c1538SÁlvaro Fernández Rojas 	if (ret < 0)
162f55c1538SÁlvaro Fernández Rojas 		return ret;
163f55c1538SÁlvaro Fernández Rojas 
164f55c1538SÁlvaro Fernández Rojas 	ret = reset_free(&rst_ctl);
165f55c1538SÁlvaro Fernández Rojas 	if (ret < 0)
166f55c1538SÁlvaro Fernández Rojas 		return ret;
167f55c1538SÁlvaro Fernández Rojas 
168f55c1538SÁlvaro Fernández Rojas 	/* enable usb_ref clock */
169f55c1538SÁlvaro Fernández Rojas 	ret = clk_get_by_name(dev, "usb_ref", &clk);
170f55c1538SÁlvaro Fernández Rojas 	if (!ret) {
171f55c1538SÁlvaro Fernández Rojas 		ret = clk_enable(&clk);
172f55c1538SÁlvaro Fernández Rojas 		if (ret < 0)
173f55c1538SÁlvaro Fernández Rojas 			return ret;
174f55c1538SÁlvaro Fernández Rojas 
175f55c1538SÁlvaro Fernández Rojas 		ret = clk_free(&clk);
176f55c1538SÁlvaro Fernández Rojas 		if (ret < 0)
177f55c1538SÁlvaro Fernández Rojas 			return ret;
178f55c1538SÁlvaro Fernández Rojas 	}
179f55c1538SÁlvaro Fernández Rojas 
180f55c1538SÁlvaro Fernández Rojas 	mdelay(100);
181f55c1538SÁlvaro Fernández Rojas 
182f55c1538SÁlvaro Fernández Rojas 	return 0;
183f55c1538SÁlvaro Fernández Rojas }
184f55c1538SÁlvaro Fernández Rojas 
185f55c1538SÁlvaro Fernández Rojas U_BOOT_DRIVER(bcm6368_usbh) = {
186f55c1538SÁlvaro Fernández Rojas 	.name = "bcm6368-usbh",
187f55c1538SÁlvaro Fernández Rojas 	.id = UCLASS_PHY,
188f55c1538SÁlvaro Fernández Rojas 	.of_match = bcm6368_usbh_ids,
189f55c1538SÁlvaro Fernández Rojas 	.ops = &bcm6368_usbh_ops,
190f55c1538SÁlvaro Fernández Rojas 	.priv_auto_alloc_size = sizeof(struct bcm6368_usbh_priv),
191f55c1538SÁlvaro Fernández Rojas 	.probe = bcm6368_usbh_probe,
192f55c1538SÁlvaro Fernández Rojas };
193