• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * phy-hi3556av100-usb.c
4  *
5  * usb phy driver special for hi3556av100
6  *
7  * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
8  *
9  * This program is free software; you can redistribute  it and/or modify it
10  * under  the terms of  the GNU General  Public License as published by the
11  * Free Software Foundation;  either version 2 of the  License, or (at your
12  * option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23 #include <asm/arch-hi3556av100/platform.h>
24 #include <dm.h>
25 #include <usb.h>
26 #include <usb/xhci.h>
27 #include "phy-hisi-usb.h"
28 
29 /* offset 0x184 */
30 #define USB2_PHY0_CKEN		(0x1 << 5)
31 #define USB2_PHY1_CKEN		(0x1 << 4)
32 #define USB2_PHY0_PORT_TREQ	(0x1 << 3)
33 #define USB2_PHY1_PORT_TREQ	(0x1 << 2)
34 #define USB2_PHY0_REQ		(0x1 << 1)
35 #define USB2_PHY1_REQ		(0x1 << 0)
36 
37 /* offset 0x188 */
38 #define COMBPHY0_REF_CKEN	(0x1 << 8)
39 #define COMBPHY_SRST_REQ	(0x1 << 0)
40 
41 /* offset 0x190 */
42 #define USB3_PCLK_OCC_SEL	(0x1 << 30)
43 #define USB3_UTMI_CKSEL		(0x1 << 29)
44 #define USB3_VCC_SRST_REQ	(0x1 << 16)
45 #define USB2_UTMI_CKSEL		(0x1 << 13)
46 #define USB2_VCC_SRST_REQ	(0x1 << 0)
47 
48 #define USB_PORT0			0x38
49 #define U3_PORT_DISABLE		(0x1 << 3)
50 
51 #define GTXTHRCFG			0xc108
52 #define GRXTHRCFG			0xc10c
53 #define REG_GCTL			0xc110
54 
55 #define PORT_CAP_DIR		(0x3 << 12)
56 #define DEFAULT_HOST_MOD	(0x1 << 12)
57 
58 #define PERI_USB3_GTXTHRCFG	0x2310000
59 
60 #define REG_GUSB3PIPECTL0	0xc2c0
61 #define PCS_SSP_SOFT_RESET	(0x1 << 31)
62 #define SUSPEND_USB3_SS_PHY	(0x1 << 17)
63 #define USB3_TX_MARGIN		(0x7 << 3)
64 #define USB3_TX_MARGIN_VAL	(0x2 << 3)
65 
66 #define USB2_PHY0				0x24
67 #define USB2_PHY0_TXVREFTUNE	(0xf << 4)
68 #define USB2_PHY0_VREF_VAL		(0x5 << 4)
69 #define USB2_PHY0_TXPRE			(0x3 << 12)
70 #define USB2_PHY0_PRE_VAL		(0x1 << 12)
71 
72 #define USB2_PHY1				0x30
73 #define USB2_PHY1_TXVREFTUNE	(0xf << 4)
74 #define USB2_PHY1_VREF_VAL		(0x5 << 4)
75 #define USB2_PHY1_TXPRE			(0x3 << 12)
76 #define USB2_PHY1_PRE_VAL		(0x1 << 12)
77 
78 #define USB3_DEF_CRG		0x1f010000
79 #define USB3_DEF_CFG_MASK	0xffff0000
80 #define USB2_DEF_CRG		0x00001301
81 #define USB2_DEF_CFG_MASK	0x0000ffff
82 
83 #define PCIE_USB3_MASK		(0x3 << 12)
84 #define get_combphy_mode(p)	(((p) & PCIE_USB3_MASK) >> 12)
85 #define USB3				0x1
86 #define PCIE_X1				0x0
87 
88 static uintptr_t xhci_base = 0;
89 
xhci_hcd_init(int index,struct xhci_hccr ** hccr,struct xhci_hcor ** hcor)90 int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
91 {
92 	if ((hccr == NULL) || (hcor == NULL))
93 		return -EINVAL;
94 
95 	if (index == 0)
96 		xhci_base = USB3_CTRL_REG_BASE;
97 	if (index == 1)
98 		xhci_base = USB2_CTRL_REG_BASE;
99 
100 	*hccr = (struct xhci_hccr *)(xhci_base);
101 	*hcor = (struct xhci_hcor *)((uintptr_t) *hccr +
102 					HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
103 
104 	return 0;
105 }
106 
hisi_usb_eye_config(void)107 void hisi_usb_eye_config(void)
108 {
109 	unsigned int reg;
110 
111 	/* port0 phy high-spped DC adjust: 0% --> 4% */
112 	/* port0 pre elec adjust: 0 --> 1x */
113 	reg = readl(MISC_REG_BASE + USB2_PHY0);
114 	reg &= ~USB2_PHY0_TXVREFTUNE;
115 	reg &= ~USB2_PHY0_TXPRE;
116 	reg |= USB2_PHY0_VREF_VAL;
117 	reg |= USB2_PHY0_PRE_VAL;
118 	writel(reg, MISC_REG_BASE + USB2_PHY0);
119 	udelay(U_LEVEL5);
120 
121 	/* port1 phy high-spped DC adjust: 0% --> 4% */
122 	/* port1 pre elec adjust: 0 --> 1x */
123 	reg = readl(MISC_REG_BASE + USB2_PHY1);
124 	reg &= ~USB2_PHY1_TXVREFTUNE;
125 	reg &= ~USB2_PHY1_TXPRE;
126 	reg |= USB2_PHY1_VREF_VAL;
127 	reg |= USB2_PHY1_PRE_VAL;
128 	writel(reg, MISC_REG_BASE + USB2_PHY1);
129 	udelay(U_LEVEL5);
130 
131 	/* usb3 Tx margin adjust: 0 --> 900mv */
132 	reg = readl(USB3_CTRL_REG_BASE + REG_GUSB3PIPECTL0);
133 	reg &= ~USB3_TX_MARGIN;
134 	reg |= USB3_TX_MARGIN_VAL;
135 	writel(reg, USB3_CTRL_REG_BASE + REG_GUSB3PIPECTL0);
136 }
137 
hisi_usb_config(void)138 void hisi_usb_config(void)
139 {
140 	unsigned int reg;
141 
142 	/* set usb2 CRG default val */
143 	reg = readl(USB3_CTRL_CFG);
144 	reg &= ~(USB2_DEF_CFG_MASK);
145 	reg |= USB2_DEF_CRG;
146 	writel(reg, USB3_CTRL_CFG);
147 	udelay(U_LEVEL6);
148 
149 	/* U2 vcc reset */
150 	reg = readl(USB3_CTRL_CFG);
151 	reg |= USB2_VCC_SRST_REQ;
152 	writel(reg, USB3_CTRL_CFG);
153 	udelay(U_LEVEL5);
154 
155 	/* release TPOR default release */
156 	reg = readl(USB2_PHY_CFG);
157 	reg &= ~USB2_PHY1_PORT_TREQ;
158 	writel(reg, USB2_PHY_CFG);
159 	udelay(U_LEVEL6);
160 
161 	/* utmi clock sel */
162 	reg = readl(USB3_CTRL_CFG);
163 	reg &= ~USB2_UTMI_CKSEL;
164 	writel(reg, USB3_CTRL_CFG);
165 	udelay(U_LEVEL6);
166 
167 	/* open phy ref clk default open */
168 	reg = readl(USB2_PHY_CFG);
169 	reg |= USB2_PHY1_CKEN;
170 	writel(reg, USB2_PHY_CFG);
171 	udelay(U_LEVEL6);
172 
173 	/* U2 phy reset release */
174 	reg = readl(USB2_PHY_CFG);
175 	reg &= ~USB2_PHY1_REQ;
176 	writel(reg, USB2_PHY_CFG);
177 	udelay(U_LEVEL6);
178 
179 	/* onfig U2 Controller release */
180 	reg = readl(USB3_CTRL_CFG);
181 	reg &= ~USB2_VCC_SRST_REQ;
182 	writel(reg, USB3_CTRL_CFG);
183 	udelay(U_LEVEL5);
184 
185 	/* u2 port default host */
186 	reg = readl(USB2_CTRL_REG_BASE + REG_GCTL);
187 	reg &= ~PORT_CAP_DIR;
188 	reg |= DEFAULT_HOST_MOD;
189 	writel(reg, USB2_CTRL_REG_BASE + REG_GCTL);
190 	udelay(U_LEVEL2);
191 }
192 
hisi_usb3_init_crg_clk(void)193 void hisi_usb3_init_crg_clk(void)
194 {
195 	unsigned int reg;
196 	/* set usb3 CRG default val */
197 	reg = readl(USB3_CTRL_CFG);
198 	reg &= ~(USB3_DEF_CFG_MASK);
199 	reg |= USB3_DEF_CRG;
200 	writel(reg, USB3_CTRL_CFG);
201 	udelay(U_LEVEL6);
202 
203 	/* disable port0 ss */
204 	reg = readl(MISC_REG_BASE + USB_PORT0);
205 	reg |= U3_PORT_DISABLE;
206 	writel(reg, MISC_REG_BASE + USB_PORT0);
207 
208 	/*
209 	 * According to description of SYSSYAT register, different
210 	 * HW modes of COMBPHY require specific configurations.
211 	 */
212 	reg = readl(REG_BASE_SCTL + REG_SYSSTAT);
213 	if (get_combphy_mode(reg) == USB3) {
214 		/* combphy reset in USB3 mode */
215 		reg = readl(USB3_COMBPHY_CFG);
216 		reg |= COMBPHY_SRST_REQ;
217 		writel(reg, USB3_COMBPHY_CFG);
218 		udelay(U_LEVEL5);
219 	} else if (get_combphy_mode(reg) == PCIE_X1) {
220 		/* Choose clock from CRG in PCIE X1 mode */
221 		reg = readl(USB3_CTRL_CFG);
222 		reg |= USB3_PCLK_OCC_SEL;
223 		writel(reg, USB3_CTRL_CFG);
224 		udelay(U_LEVEL5);
225 	}
226 
227 	/* release TPOR default release */
228 	reg = readl(USB2_PHY_CFG);
229 	reg &= ~USB2_PHY0_PORT_TREQ;
230 	writel(reg, USB2_PHY_CFG);
231 	udelay(U_LEVEL6);
232 
233 	/* utmi clock sel */
234 	reg = readl(USB3_CTRL_CFG);
235 	reg &= ~USB3_UTMI_CKSEL;
236 	writel(reg, USB3_CTRL_CFG);
237 	udelay(U_LEVEL6);
238 
239 	/* open phy ref clk default open */
240 	reg = readl(USB2_PHY_CFG);
241 	reg |= USB2_PHY0_CKEN;
242 	writel(reg, USB2_PHY_CFG);
243 	udelay(U_LEVEL6);
244 }
245 
hisi_usb3_config(void)246 void hisi_usb3_config(void)
247 {
248 	unsigned int reg;
249 
250 	/* init crg and clk */
251 	hisi_usb3_init_crg_clk();
252 
253 	/* U2 phy reset release */
254 	reg = readl(USB2_PHY_CFG);
255 	reg &= ~USB2_PHY0_REQ;
256 	writel(reg, USB2_PHY_CFG);
257 	udelay(U_LEVEL6);
258 
259 	/* Release the specific configuration of COMBPHY. */
260 	reg = readl(REG_BASE_SCTL + REG_SYSSTAT);
261 	if (get_combphy_mode(reg) == USB3) {
262 		/* open ref CKEN */
263 		reg = readl(USB3_COMBPHY_CFG);
264 		reg |= COMBPHY0_REF_CKEN;
265 		writel(reg, USB3_COMBPHY_CFG);
266 		udelay(U_LEVEL5);
267 
268 		reg = readl(USB3_COMBPHY_CFG);
269 		reg &= ~COMBPHY_SRST_REQ;
270 		writel(reg, USB3_COMBPHY_CFG);
271 		udelay(U_LEVEL5);
272 	}
273 
274 	/* config U3 Controller USB3_0 PHY OUTPUT */
275 	reg = readl(USB3_CTRL_CFG);
276 	reg &= ~USB3_VCC_SRST_REQ;
277 	writel(reg, USB3_CTRL_CFG);
278 	udelay(U_LEVEL6);
279 
280 	reg = readl(USB3_CTRL_REG_BASE + REG_GUSB3PIPECTL0);
281 	reg |= PCS_SSP_SOFT_RESET;
282 	writel(reg, USB3_CTRL_REG_BASE + REG_GUSB3PIPECTL0);
283 	udelay(U_LEVEL6);
284 
285 	/* u3 port default host */
286 	reg = readl(USB3_CTRL_REG_BASE + REG_GCTL);
287 	reg &= ~PORT_CAP_DIR;
288 	reg |= DEFAULT_HOST_MOD;
289 	writel(reg, USB3_CTRL_REG_BASE + REG_GCTL);
290 	udelay(U_LEVEL2);
291 
292 	reg = readl(USB3_CTRL_REG_BASE + REG_GUSB3PIPECTL0);
293 	reg &= ~PCS_SSP_SOFT_RESET;
294 	reg &= ~SUSPEND_USB3_SS_PHY; /* disable suspend */
295 	writel(reg, USB3_CTRL_REG_BASE + REG_GUSB3PIPECTL0);
296 	udelay(U_LEVEL2);
297 
298 	writel(PERI_USB3_GTXTHRCFG, USB3_CTRL_REG_BASE + GTXTHRCFG);
299 	udelay(U_LEVEL2);
300 }
301 
phy_hiusb_init(int index)302 void phy_hiusb_init(int index)
303 {
304 	if (index)
305 		hisi_usb_config();
306 	else
307 		hisi_usb3_config();
308 
309 	hisi_usb_eye_config();
310 }
311 EXPORT_SYMBOL(phy_hiusb_init);
312 
xhci_hcd_stop(int index)313 void xhci_hcd_stop(int index)
314 {
315 	unsigned int reg;
316 
317 	/* U2 vcc reset */
318 	reg = readl(USB3_CTRL_CFG);
319 	reg |= USB2_VCC_SRST_REQ;
320 	writel(reg, USB3_CTRL_CFG);
321 	udelay(U_LEVEL5);
322 
323 	/* U3 vcc reset */
324 	reg = readl(USB3_CTRL_CFG);
325 	reg |= USB3_VCC_SRST_REQ;
326 	writel(reg, USB3_CTRL_CFG);
327 	udelay(U_LEVEL5);
328 
329 	reg = readl(REG_BASE_SCTL + REG_SYSSTAT);
330 	if (get_combphy_mode(reg) == USB3) {
331 		/* combphy reset */
332 		reg = readl(USB3_COMBPHY_CFG);
333 		reg |= COMBPHY_SRST_REQ;
334 		writel(reg, USB3_COMBPHY_CFG);
335 		udelay(U_LEVEL5);
336 	}
337 }
338 EXPORT_SYMBOL(xhci_hcd_stop);
339