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