1 /* SPDX-License-Identifier: GPL-2.0-only */
2
3 #include <device/mmio.h>
4 #include <console/console.h>
5 #include <delay.h>
6 #include <device/device.h>
7 #include <soc/gpio.h>
8 #include <soc/power.h>
9 #include <soc/sysreg.h>
10 #include <soc/usb.h>
11
reset_dwc3(struct exynos5_usb_drd_dwc3 * dwc3)12 static void reset_dwc3(struct exynos5_usb_drd_dwc3 *dwc3)
13 {
14 setbits32(&dwc3->ctl, 0x1 << 11); /* core soft reset */
15 setbits32(&dwc3->usb3pipectl, 0x1 << 31); /* PHY soft reset */
16 setbits32(&dwc3->usb2phycfg, 0x1 << 31); /* PHY soft reset */
17 }
18
reset_usb_drd0_dwc3(void)19 void reset_usb_drd0_dwc3(void)
20 {
21 printk(BIOS_DEBUG, "Starting DWC3 reset for USB DRD0\n");
22 reset_dwc3(exynos_usb_drd0_dwc3);
23 }
24
reset_usb_drd1_dwc3(void)25 void reset_usb_drd1_dwc3(void)
26 {
27 printk(BIOS_DEBUG, "Starting DWC3 reset for USB DRD1\n");
28 reset_dwc3(exynos_usb_drd1_dwc3);
29 }
30
setup_dwc3(struct exynos5_usb_drd_dwc3 * dwc3)31 static void setup_dwc3(struct exynos5_usb_drd_dwc3 *dwc3)
32 {
33 if (!(dwc3->ctl & 0x1 << 11) ||
34 !(dwc3->usb3pipectl & 0x1 << 31) ||
35 !(dwc3->usb2phycfg & 0x1 << 31)) {
36 printk(BIOS_ERR, "DWC3 at %p not in reset (you need to call "
37 "reset_usb_drdX_dwc3() first)!\n", dwc3);
38 }
39
40 /* Set relevant registers to default values (clearing all reset bits) */
41
42 write32(&dwc3->usb3pipectl,
43 0x1 << 24 | /* activate PHY low power states */
44 0x4 << 19 | /* low power delay value */
45 0x1 << 18 | /* activate PHY low power delay */
46 0x1 << 17 | /* enable SuperSpeed PHY suspend */
47 0x1 << 1); /* default Tx deemphasis value */
48
49 /* Configure PHY clock turnaround for 8-bit UTMI+, disable suspend */
50 write32(&dwc3->usb2phycfg,
51 0x9 << 10 | /* PHY clock turnaround for 8-bit UTMI+ */
52 0x1 << 8 | /* enable PHY sleep in L1 */
53 0x1 << 6); /* enable PHY suspend */
54
55 write32(&dwc3->ctl,
56 0x5dc << 19 | /* suspend clock scale for 24MHz */
57 0x1 << 16 | /* retry SS three times (bugfix from U-Boot) */
58 0x1 << 12); /* port capability HOST */
59 }
60
setup_usb_drd0_dwc3(void)61 void setup_usb_drd0_dwc3(void)
62 {
63 setup_dwc3(exynos_usb_drd0_dwc3);
64 printk(BIOS_DEBUG, "DWC3 setup for USB DRD0 finished\n");
65 }
66
setup_usb_drd1_dwc3(void)67 void setup_usb_drd1_dwc3(void)
68 {
69 setup_dwc3(exynos_usb_drd1_dwc3);
70 printk(BIOS_DEBUG, "DWC3 setup for USB DRD1 finished\n");
71 }
72
setup_drd_phy(struct exynos5_usb_drd_phy * phy)73 static void setup_drd_phy(struct exynos5_usb_drd_phy *phy)
74 {
75 /* Set all PHY registers to default values */
76
77 /* XHCI Version 1.0, Frame Length adjustment 30 MHz */
78 setbits32(&phy->linksystem, 0x1 << 27 | 0x20 << 1);
79
80 /* Disable OTG, ID0 and DRVVBUS, do not force sleep/suspend */
81 write32(&phy->utmi, 1 << 6);
82
83 write32(&phy->clkrst,
84 0x88 << 23 | /* spread spectrum refclk selector */
85 0x1 << 20 | /* enable spread spectrum */
86 0x1 << 19 | /* enable prescaler refclk */
87 0x68 << 11 | /* multiplier for 24MHz refclk */
88 0x5 << 5 | /* select 24MHz refclk (weird, from U-Boot) */
89 0x1 << 4 | /* power supply in normal operating mode */
90 0x3 << 2 | /* use external refclk (undocumented on 5420?)*/
91 0x1 << 1 | /* force port reset */
92 0x1 << 0); /* normal operating mode */
93
94 write32(&phy->param0,
95 0x9 << 26 | /* LOS level */
96 0x3 << 22 | /* TX VREF tune */
97 0x1 << 20 | /* TX rise tune */
98 0x1 << 18 | /* TX res tune */
99 0x3 << 13 | /* TX HS X Vtune */
100 0x3 << 9 | /* TX FS/LS tune */
101 0x3 << 6 | /* SQRX tune */
102 0x4 << 3 | /* OTG tune */
103 0x4 << 0); /* comp disc tune */
104
105 write32(&phy->param1,
106 0x7f << 19 | /* reserved */
107 0x7f << 12 | /* Tx launch amplitude */
108 0x20 << 6 | /* Tx deemphasis 6dB */
109 0x1c << 0); /* Tx deemphasis 3.5dB (value from U-Boot) */
110
111 /* disable all test features */
112 write32(&phy->test, 0);
113
114 /* UTMI clock select? ("must be 0x1") */
115 write32(&phy->utmiclksel, 0x1 << 2);
116
117 /* Samsung magic, undocumented (from U-Boot) */
118 write32(&phy->resume, 0x0);
119
120 udelay(10);
121 clrbits32(&phy->clkrst, 0x1 << 1); /* deassert port reset */
122 }
123
setup_usb_drd0_phy(void)124 void setup_usb_drd0_phy(void)
125 {
126 printk(BIOS_DEBUG, "Powering up USB DRD0 PHY\n");
127 setbits32(&exynos_power->usb_drd0_phy_ctrl, POWER_USB_PHY_CTRL_EN);
128 setup_drd_phy(exynos_usb_drd0_phy);
129 }
130
setup_usb_drd1_phy(void)131 void setup_usb_drd1_phy(void)
132 {
133 printk(BIOS_DEBUG, "Powering up USB DRD1 PHY\n");
134 setbits32(&exynos_power->usb_drd1_phy_ctrl, POWER_USB_PHY_CTRL_EN);
135 setup_drd_phy(exynos_usb_drd1_phy);
136 }
137
setup_usb_host_phy(int hsic_gpio)138 void setup_usb_host_phy(int hsic_gpio)
139 {
140 unsigned int hostphy_ctrl0;
141
142 setbits32(&exynos_sysreg->usb20_phy_cfg, USB20_PHY_CFG_EN);
143 setbits32(&exynos_power->usb_host_phy_ctrl, POWER_USB_PHY_CTRL_EN);
144
145 printk(BIOS_DEBUG, "Powering up USB HOST PHY (%s HSIC)\n",
146 hsic_gpio ? "with" : "without");
147
148 hostphy_ctrl0 = read32(&exynos_usb_host_phy->usbphyctrl0);
149 hostphy_ctrl0 &= ~(HOST_CTRL0_FSEL_MASK |
150 HOST_CTRL0_COMMONON_N |
151 /* HOST Phy setting */
152 HOST_CTRL0_PHYSWRST |
153 HOST_CTRL0_PHYSWRSTALL |
154 HOST_CTRL0_SIDDQ |
155 HOST_CTRL0_FORCESUSPEND |
156 HOST_CTRL0_FORCESLEEP);
157 hostphy_ctrl0 |= (/* Setting up the ref freq */
158 CLK_24MHZ << 16 |
159 /* HOST Phy setting */
160 HOST_CTRL0_LINKSWRST |
161 HOST_CTRL0_UTMISWRST);
162 write32(&exynos_usb_host_phy->usbphyctrl0, hostphy_ctrl0);
163 udelay(10);
164 clrbits32(&exynos_usb_host_phy->usbphyctrl0,
165 HOST_CTRL0_LINKSWRST |
166 HOST_CTRL0_UTMISWRST);
167 udelay(20);
168
169 /* EHCI Ctrl setting */
170 setbits32(&exynos_usb_host_phy->ehcictrl,
171 EHCICTRL_ENAINCRXALIGN |
172 EHCICTRL_ENAINCR4 |
173 EHCICTRL_ENAINCR8 |
174 EHCICTRL_ENAINCR16);
175
176 /* HSIC USB Hub initialization. */
177 if (hsic_gpio) {
178 gpio_direction_output(hsic_gpio, 0);
179 udelay(100);
180 gpio_direction_output(hsic_gpio, 1);
181 udelay(5000);
182
183 clrbits32(&exynos_usb_host_phy->hsicphyctrl1,
184 HOST_CTRL0_SIDDQ |
185 HOST_CTRL0_FORCESLEEP |
186 HOST_CTRL0_FORCESUSPEND);
187 setbits32(&exynos_usb_host_phy->hsicphyctrl1,
188 HOST_CTRL0_PHYSWRST);
189 udelay(10);
190 clrbits32(&exynos_usb_host_phy->hsicphyctrl1,
191 HOST_CTRL0_PHYSWRST);
192 }
193
194 /* At this point we need to wait for 50ms before talking to
195 * the USB controller (PHY clock and power setup time)
196 * By the time we are actually in the payload, these 50ms
197 * will have passed.
198 */
199 }
200