]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
5f0ffea4 | 2 | /* |
7590d3ce | 3 | * SAMSUNG EXYNOS USB HOST EHCI Controller |
5f0ffea4 RS |
4 | * |
5 | * Copyright (C) 2012 Samsung Electronics Co.Ltd | |
6 | * Vivek Gautam <[email protected]> | |
5f0ffea4 RS |
7 | */ |
8 | ||
aae04d07 | 9 | #include <dm.h> |
e18bf1f9 | 10 | #include <fdtdec.h> |
f7ae49fc | 11 | #include <log.h> |
401d1c4f | 12 | #include <asm/global_data.h> |
c05ed00a | 13 | #include <linux/delay.h> |
b08c8c48 | 14 | #include <linux/libfdt.h> |
e18bf1f9 | 15 | #include <malloc.h> |
5f0ffea4 RS |
16 | #include <usb.h> |
17 | #include <asm/arch/cpu.h> | |
7590d3ce | 18 | #include <asm/arch/ehci.h> |
71045da8 | 19 | #include <asm/arch/system.h> |
c48ac113 | 20 | #include <asm/arch/power.h> |
4a271cb1 | 21 | #include <asm/gpio.h> |
5d97dff0 | 22 | #include <linux/errno.h> |
e18bf1f9 | 23 | #include <linux/compat.h> |
5f0ffea4 | 24 | #include "ehci.h" |
5f0ffea4 | 25 | |
e18bf1f9 RS |
26 | /* Declare global data pointer */ |
27 | DECLARE_GLOBAL_DATA_PTR; | |
28 | ||
8a8d24bd SG |
29 | struct exynos_ehci_plat { |
30 | struct usb_plat usb_plat; | |
aae04d07 SG |
31 | fdt_addr_t hcd_base; |
32 | fdt_addr_t phy_base; | |
33 | struct gpio_desc vbus_gpio; | |
34 | }; | |
aae04d07 | 35 | |
e18bf1f9 RS |
36 | /** |
37 | * Contains pointers to register base addresses | |
38 | * for the usb controller. | |
39 | */ | |
40 | struct exynos_ehci { | |
aae04d07 | 41 | struct ehci_ctrl ctrl; |
e18bf1f9 | 42 | struct exynos_usb_phy *usb; |
24a4775f | 43 | struct ehci_hccr *hcd; |
e18bf1f9 RS |
44 | }; |
45 | ||
d1998a9f | 46 | static int ehci_usb_of_to_plat(struct udevice *dev) |
aae04d07 | 47 | { |
8a8d24bd | 48 | struct exynos_ehci_plat *plat = dev_get_plat(dev); |
aae04d07 SG |
49 | const void *blob = gd->fdt_blob; |
50 | unsigned int node; | |
51 | int depth; | |
52 | ||
53 | /* | |
54 | * Get the base address for XHCI controller from the device node | |
55 | */ | |
2548493a | 56 | plat->hcd_base = dev_read_addr(dev); |
aae04d07 SG |
57 | if (plat->hcd_base == FDT_ADDR_T_NONE) { |
58 | debug("Can't get the XHCI register base address\n"); | |
59 | return -ENXIO; | |
60 | } | |
61 | ||
62 | depth = 0; | |
e160f7d4 | 63 | node = fdtdec_next_compatible_subnode(blob, dev_of_offset(dev), |
aae04d07 SG |
64 | COMPAT_SAMSUNG_EXYNOS_USB_PHY, &depth); |
65 | if (node <= 0) { | |
66 | debug("XHCI: Can't get device node for usb3-phy controller\n"); | |
67 | return -ENODEV; | |
68 | } | |
69 | ||
70 | /* | |
71 | * Get the base address for usbphy from the device node | |
72 | */ | |
73 | plat->phy_base = fdtdec_get_addr(blob, node, "reg"); | |
74 | if (plat->phy_base == FDT_ADDR_T_NONE) { | |
75 | debug("Can't get the usbphy register address\n"); | |
76 | return -ENXIO; | |
77 | } | |
78 | ||
79 | /* Vbus gpio */ | |
80 | gpio_request_by_name(dev, "samsung,vbus-gpio", 0, | |
81 | &plat->vbus_gpio, GPIOD_IS_OUT); | |
82 | ||
83 | return 0; | |
84 | } | |
e18bf1f9 | 85 | |
6a23c653 | 86 | static void exynos5_setup_usb_phy(struct exynos_usb_phy *usb) |
5f0ffea4 | 87 | { |
16f9480d IS |
88 | u32 hsic_ctrl; |
89 | ||
5f0ffea4 RS |
90 | clrbits_le32(&usb->usbphyctrl0, |
91 | HOST_CTRL0_FSEL_MASK | | |
92 | HOST_CTRL0_COMMONON_N | | |
93 | /* HOST Phy setting */ | |
94 | HOST_CTRL0_PHYSWRST | | |
95 | HOST_CTRL0_PHYSWRSTALL | | |
96 | HOST_CTRL0_SIDDQ | | |
97 | HOST_CTRL0_FORCESUSPEND | | |
98 | HOST_CTRL0_FORCESLEEP); | |
99 | ||
100 | setbits_le32(&usb->usbphyctrl0, | |
101 | /* Setting up the ref freq */ | |
102 | (CLK_24MHZ << 16) | | |
103 | /* HOST Phy setting */ | |
104 | HOST_CTRL0_LINKSWRST | | |
105 | HOST_CTRL0_UTMISWRST); | |
106 | udelay(10); | |
107 | clrbits_le32(&usb->usbphyctrl0, | |
108 | HOST_CTRL0_LINKSWRST | | |
109 | HOST_CTRL0_UTMISWRST); | |
16f9480d IS |
110 | |
111 | /* HSIC Phy Setting */ | |
112 | hsic_ctrl = (HSIC_CTRL_FORCESUSPEND | | |
113 | HSIC_CTRL_FORCESLEEP | | |
114 | HSIC_CTRL_SIDDQ); | |
115 | ||
116 | clrbits_le32(&usb->hsicphyctrl1, hsic_ctrl); | |
117 | clrbits_le32(&usb->hsicphyctrl2, hsic_ctrl); | |
118 | ||
119 | hsic_ctrl = (((HSIC_CTRL_REFCLKDIV_12 & HSIC_CTRL_REFCLKDIV_MASK) | |
120 | << HSIC_CTRL_REFCLKDIV_SHIFT) | |
121 | | ((HSIC_CTRL_REFCLKSEL & HSIC_CTRL_REFCLKSEL_MASK) | |
122 | << HSIC_CTRL_REFCLKSEL_SHIFT) | |
123 | | HSIC_CTRL_UTMISWRST); | |
124 | ||
125 | setbits_le32(&usb->hsicphyctrl1, hsic_ctrl); | |
126 | setbits_le32(&usb->hsicphyctrl2, hsic_ctrl); | |
127 | ||
128 | udelay(10); | |
129 | ||
130 | clrbits_le32(&usb->hsicphyctrl1, HSIC_CTRL_PHYSWRST | | |
131 | HSIC_CTRL_UTMISWRST); | |
132 | ||
133 | clrbits_le32(&usb->hsicphyctrl2, HSIC_CTRL_PHYSWRST | | |
134 | HSIC_CTRL_UTMISWRST); | |
135 | ||
5f0ffea4 RS |
136 | udelay(20); |
137 | ||
138 | /* EHCI Ctrl setting */ | |
139 | setbits_le32(&usb->ehcictrl, | |
140 | EHCICTRL_ENAINCRXALIGN | | |
141 | EHCICTRL_ENAINCR4 | | |
142 | EHCICTRL_ENAINCR8 | | |
143 | EHCICTRL_ENAINCR16); | |
144 | } | |
145 | ||
6a23c653 SR |
146 | static void exynos4412_setup_usb_phy(struct exynos4412_usb_phy *usb) |
147 | { | |
148 | writel(CLK_24MHZ, &usb->usbphyclk); | |
149 | ||
150 | clrbits_le32(&usb->usbphyctrl, (PHYPWR_NORMAL_MASK_HSIC0 | | |
151 | PHYPWR_NORMAL_MASK_HSIC1 | PHYPWR_NORMAL_MASK_PHY1 | | |
152 | PHYPWR_NORMAL_MASK_PHY0)); | |
153 | ||
154 | setbits_le32(&usb->usbphyrstcon, (RSTCON_HOSTPHY_SWRST | RSTCON_SWRST)); | |
155 | udelay(10); | |
156 | clrbits_le32(&usb->usbphyrstcon, (RSTCON_HOSTPHY_SWRST | RSTCON_SWRST)); | |
157 | } | |
158 | ||
159 | static void setup_usb_phy(struct exynos_usb_phy *usb) | |
160 | { | |
161 | set_usbhost_mode(USB20_PHY_CFG_HOST_LINK_EN); | |
162 | ||
163 | set_usbhost_phy_ctrl(POWER_USB_HOST_PHY_CTRL_EN); | |
164 | ||
165 | if (cpu_is_exynos5()) | |
166 | exynos5_setup_usb_phy(usb); | |
167 | else if (cpu_is_exynos4()) | |
168 | if (proid_is_exynos4412()) | |
169 | exynos4412_setup_usb_phy((struct exynos4412_usb_phy *) | |
170 | usb); | |
171 | } | |
172 | ||
173 | static void exynos5_reset_usb_phy(struct exynos_usb_phy *usb) | |
5f0ffea4 | 174 | { |
16f9480d IS |
175 | u32 hsic_ctrl; |
176 | ||
5f0ffea4 RS |
177 | /* HOST_PHY reset */ |
178 | setbits_le32(&usb->usbphyctrl0, | |
179 | HOST_CTRL0_PHYSWRST | | |
180 | HOST_CTRL0_PHYSWRSTALL | | |
181 | HOST_CTRL0_SIDDQ | | |
182 | HOST_CTRL0_FORCESUSPEND | | |
183 | HOST_CTRL0_FORCESLEEP); | |
c48ac113 | 184 | |
16f9480d IS |
185 | /* HSIC Phy reset */ |
186 | hsic_ctrl = (HSIC_CTRL_FORCESUSPEND | | |
187 | HSIC_CTRL_FORCESLEEP | | |
188 | HSIC_CTRL_SIDDQ | | |
189 | HSIC_CTRL_PHYSWRST); | |
190 | ||
191 | setbits_le32(&usb->hsicphyctrl1, hsic_ctrl); | |
192 | setbits_le32(&usb->hsicphyctrl2, hsic_ctrl); | |
6a23c653 SR |
193 | } |
194 | ||
195 | static void exynos4412_reset_usb_phy(struct exynos4412_usb_phy *usb) | |
196 | { | |
197 | setbits_le32(&usb->usbphyctrl, (PHYPWR_NORMAL_MASK_HSIC0 | | |
198 | PHYPWR_NORMAL_MASK_HSIC1 | PHYPWR_NORMAL_MASK_PHY1 | | |
199 | PHYPWR_NORMAL_MASK_PHY0)); | |
200 | } | |
201 | ||
202 | /* Reset the EHCI host controller. */ | |
203 | static void reset_usb_phy(struct exynos_usb_phy *usb) | |
204 | { | |
205 | if (cpu_is_exynos5()) | |
206 | exynos5_reset_usb_phy(usb); | |
207 | else if (cpu_is_exynos4()) | |
208 | if (proid_is_exynos4412()) | |
209 | exynos4412_reset_usb_phy((struct exynos4412_usb_phy *) | |
210 | usb); | |
16f9480d | 211 | |
c48ac113 | 212 | set_usbhost_phy_ctrl(POWER_USB_HOST_PHY_CTRL_DISABLE); |
5f0ffea4 RS |
213 | } |
214 | ||
aae04d07 SG |
215 | static int ehci_usb_probe(struct udevice *dev) |
216 | { | |
8a8d24bd | 217 | struct exynos_ehci_plat *plat = dev_get_plat(dev); |
aae04d07 SG |
218 | struct exynos_ehci *ctx = dev_get_priv(dev); |
219 | struct ehci_hcor *hcor; | |
220 | ||
221 | ctx->hcd = (struct ehci_hccr *)plat->hcd_base; | |
222 | ctx->usb = (struct exynos_usb_phy *)plat->phy_base; | |
aae04d07 SG |
223 | |
224 | /* setup the Vbus gpio here */ | |
225 | if (dm_gpio_is_valid(&plat->vbus_gpio)) | |
226 | dm_gpio_set_value(&plat->vbus_gpio, 1); | |
227 | ||
228 | setup_usb_phy(ctx->usb); | |
70cc443d ŁM |
229 | hcor = (struct ehci_hcor *)((uint32_t)ctx->hcd + |
230 | HC_LENGTH(ehci_readl(&ctx->hcd->cr_capbase))); | |
aae04d07 SG |
231 | |
232 | return ehci_register(dev, ctx->hcd, hcor, NULL, 0, USB_INIT_HOST); | |
233 | } | |
234 | ||
235 | static int ehci_usb_remove(struct udevice *dev) | |
236 | { | |
237 | struct exynos_ehci *ctx = dev_get_priv(dev); | |
238 | int ret; | |
239 | ||
240 | ret = ehci_deregister(dev); | |
241 | if (ret) | |
242 | return ret; | |
243 | reset_usb_phy(ctx->usb); | |
244 | ||
245 | return 0; | |
246 | } | |
247 | ||
248 | static const struct udevice_id ehci_usb_ids[] = { | |
249 | { .compatible = "samsung,exynos-ehci" }, | |
250 | { } | |
251 | }; | |
252 | ||
253 | U_BOOT_DRIVER(usb_ehci) = { | |
254 | .name = "ehci_exynos", | |
255 | .id = UCLASS_USB, | |
256 | .of_match = ehci_usb_ids, | |
d1998a9f | 257 | .of_to_plat = ehci_usb_of_to_plat, |
aae04d07 SG |
258 | .probe = ehci_usb_probe, |
259 | .remove = ehci_usb_remove, | |
260 | .ops = &ehci_usb_ops, | |
41575d8e | 261 | .priv_auto = sizeof(struct exynos_ehci), |
8a8d24bd | 262 | .plat_auto = sizeof(struct exynos_ehci_plat), |
aae04d07 SG |
263 | .flags = DM_FLAG_ALLOC_PRIV_DMA, |
264 | }; |