xref: /aosp_15_r20/external/coreboot/src/soc/samsung/exynos5420/usb.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
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