• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * phy-hi3516cv500-usb.c
4  *
5  * usb phy driver special for hi3516cv500
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 
24 #include <asm/arch-hi3516cv500/platform.h>
25 #include <dm.h>
26 #include <usb.h>
27 #include <usb/xhci.h>
28 #include "phy-hisi-usb.h"
29 
30 /* offset 0x140 */
31 #define USB2_UTMI_PCTRL			(0x1 << 15)
32 #define USB2_PHY_TEST_SRST_REQ	(0x1 << 14)
33 #define USB2_UTMI_CKSEL			(0x1 << 13)
34 #define USB2_UTMI_CKEN			(0x1 << 12)
35 #define USB2_REF_CKEN			(0x1 << 9)
36 #define USB2_BUS_CKEN			(0x1 << 8)
37 #define USB2_VCC_SRST_REQ		(0x1 << 3)
38 #define USB2_PHY_CKEN			(0x1 << 2)
39 #define USB2_PHY_PORT_TREQ		(0x1 << 1)
40 #define USB2_PHY_REQ			(0x1 << 0)
41 
42 #define REG_GUSB3PIPECTL0		0xc2c0
43 #define PCS_SSP_SOFT_RESET		(0x1 << 31)
44 #define PORT_DISABLE_SUSPEND	(0x1 << 17)
45 
46 #define REG_GCTL				0xc110
47 #define PORT_CAP_DIR			(0x3 << 12)
48 #define PORT_SET_HOST			(0x1 << 12)
49 
50 #define GTXTHRCFG				0xc108
51 #define	USB2_G_TXTHRCFG			0x23100000
52 
53 #define GRXTHRCFG				0xc10c
54 #define	USB2_G_RXTHRCFG			0x23100000
55 
56 #define USB2_INNO_PHY_BASE_REG	0x10110000
57 #define	USB2_PHY_CLK_OUTPUT_REG	0x18
58 #define	USB2_PHY_CLK_OUTPUT_VAL	0x0c
59 
60 #define	USB2_VBUS_IO_BASE_REG	0x10ff0000
61 #define	USB2_VBUS_IO_OFFSET		0x40
62 #define	USB2_VBUS_IO_VAL		0x431
63 
64 #define	HS_HIGH_HEIGHT_TUNING_OFFSET	0x8
65 #define HS_HIGH_HEIGHT_TUNING_MASK	(0x7 << 4)
66 #define HS_HIGH_HEIGHT_TUNING_VAL	(0x5 << 4)
67 
68 #define PRE_EMPHASIS_TUNING_OFFSET	0x0
69 #define PRE_EMPHASIS_TUNING_MASK	(0x7 << 0)
70 #define	PRE_EMPHASIS_TUNING_VAL		(0x7 << 0)
71 
72 #define PRE_EMPHASIS_STRENGTH_OFFSET	0x14
73 #define PRE_EMPHASIS_STRENGTH_MASK	(0x7 << 2)
74 #define PRE_EMPHASIS_STRENGTH_VAL	(0x3 << 2)
75 
76 #define HS_SLEW_RATE_TUNING_OFFSET	0x74
77 #define HS_SLEW_RATE_TUNING_MASK	(0x7 << 1)
78 #define HS_SLEW_RATE_TUNING_VAL		(0x7 << 1)
79 
80 #define DISCONNECT_TRIGGER_OFFSET	0x10
81 #define DISCONNECT_TRIGGER_MASK		(0xf << 4)
82 #define DISCONNECT_TRIGGER_VAL		(0xd << 4)
83 
84 static uintptr_t xhci_base = 0;
85 
xhci_hcd_init(int index,struct xhci_hccr ** hccr,struct xhci_hcor ** hcor)86 int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
87 {
88 	if ((hccr == NULL) || (hcor == NULL))
89 		return -EINVAL;
90 
91 	xhci_base = USB3_CTRL_REG_BASE;
92 
93 	*hccr = (struct xhci_hccr *)(xhci_base);
94 	*hcor = (struct xhci_hcor *)((uintptr_t) *hccr +
95 				HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
96 
97 	return 0;
98 }
99 
usb2_eye_config(void)100 void usb2_eye_config(void)
101 {
102 	unsigned int reg;
103 
104 	/* HS eye height tuning */
105 	reg = readl(USB2_INNO_PHY_BASE_REG + HS_HIGH_HEIGHT_TUNING_OFFSET);
106 	reg &= ~HS_HIGH_HEIGHT_TUNING_MASK;
107 	reg |= HS_HIGH_HEIGHT_TUNING_VAL;
108 	writel(reg, USB2_INNO_PHY_BASE_REG + HS_HIGH_HEIGHT_TUNING_OFFSET);
109 
110 	/* Pre-emphasis tuning */
111 	reg = readl(USB2_INNO_PHY_BASE_REG + PRE_EMPHASIS_TUNING_OFFSET);
112 	reg &= ~PRE_EMPHASIS_TUNING_MASK;
113 	reg |= PRE_EMPHASIS_TUNING_VAL;
114 	writel(reg, USB2_INNO_PHY_BASE_REG + PRE_EMPHASIS_TUNING_OFFSET);
115 
116 	/* Pre-emphasis strength */
117 	reg = readl(USB2_INNO_PHY_BASE_REG + PRE_EMPHASIS_STRENGTH_OFFSET);
118 	reg &= ~PRE_EMPHASIS_STRENGTH_MASK;
119 	reg |= PRE_EMPHASIS_STRENGTH_VAL;
120 	writel(reg, USB2_INNO_PHY_BASE_REG + PRE_EMPHASIS_STRENGTH_OFFSET);
121 
122 	/* HS driver slew rate tunning */
123 	reg = readl(USB2_INNO_PHY_BASE_REG + HS_SLEW_RATE_TUNING_OFFSET);
124 	reg &= ~HS_SLEW_RATE_TUNING_MASK;
125 	reg |= HS_SLEW_RATE_TUNING_VAL;
126 	writel(reg, USB2_INNO_PHY_BASE_REG + HS_SLEW_RATE_TUNING_OFFSET);
127 
128 	/* HOST disconnects detection trigger point */
129 	reg = readl(USB2_INNO_PHY_BASE_REG + DISCONNECT_TRIGGER_OFFSET);
130 	reg &= ~DISCONNECT_TRIGGER_MASK;
131 	reg |= DISCONNECT_TRIGGER_VAL;
132 	writel(reg, USB2_INNO_PHY_BASE_REG + DISCONNECT_TRIGGER_OFFSET);
133 }
134 
phy_hiusb_init_clk(int index)135 void phy_hiusb_init_clk(int index)
136 {
137 	unsigned int reg;
138 
139 	/* set inno phy output clock */
140 	writel(USB2_PHY_CLK_OUTPUT_VAL, USB2_INNO_PHY_BASE_REG +
141 			USB2_PHY_CLK_OUTPUT_REG);
142 	udelay(U_LEVEL1);
143 
144 	/* open phy ref cken */
145 	reg = readl(CRG_REG_BASE + REG_CRG80);
146 	reg |= USB2_PHY_CKEN;
147 	writel(reg, CRG_REG_BASE + REG_CRG80);
148 	udelay(U_LEVEL1);
149 
150 	/* open utmi pctrl */
151 	reg = readl(CRG_REG_BASE + REG_CRG80);
152 	reg &= ~USB2_UTMI_PCTRL;
153 	writel(reg, CRG_REG_BASE + REG_CRG80);
154 	udelay(U_LEVEL1);
155 
156 	/* open utmi cksel */
157 	reg = readl(CRG_REG_BASE + REG_CRG80);
158 	reg &= ~USB2_UTMI_CKSEL;
159 	writel(reg, CRG_REG_BASE + REG_CRG80);
160 	udelay(U_LEVEL1);
161 
162 	/* open utmi cken */
163 	reg = readl(CRG_REG_BASE + REG_CRG80);
164 	reg |= USB2_UTMI_CKEN;
165 	writel(reg, CRG_REG_BASE + REG_CRG80);
166 	udelay(U_LEVEL1);
167 
168 	/* open controller ref cken */
169 	reg = readl(CRG_REG_BASE + REG_CRG80);
170 	reg |= USB2_REF_CKEN;
171 	writel(reg, CRG_REG_BASE + REG_CRG80);
172 	udelay(U_LEVEL1);
173 
174 	/* open bus cken */
175 	reg = readl(CRG_REG_BASE + REG_CRG80);
176 	reg |= USB2_BUS_CKEN;
177 	writel(reg, CRG_REG_BASE + REG_CRG80);
178 	udelay(U_LEVEL6);
179 
180 	/* cancel POR reset */
181 	reg = readl(CRG_REG_BASE + REG_CRG80);
182 	reg &= ~USB2_PHY_REQ;
183 	writel(reg, CRG_REG_BASE + REG_CRG80);
184 	udelay(U_LEVEL6);
185 
186 	/* cancel TPOR reset */
187 	reg = readl(CRG_REG_BASE + REG_CRG80);
188 	reg &= ~USB2_PHY_PORT_TREQ;
189 	writel(reg, CRG_REG_BASE + REG_CRG80);
190 	udelay(U_LEVEL6);
191 }
192 
phy_hiusb_init(int index)193 void phy_hiusb_init(int index)
194 {
195 	unsigned int reg;
196 
197 	/* usb phy reset */
198 	reg = readl(CRG_REG_BASE + REG_CRG80);
199 	reg |= USB2_PHY_TEST_SRST_REQ;
200 	writel(reg, CRG_REG_BASE + REG_CRG80);
201 	udelay(U_LEVEL5);
202 
203 	/* cancel usb phy srst */
204 	reg = readl(CRG_REG_BASE + REG_CRG80);
205 	reg &= ~USB2_PHY_TEST_SRST_REQ;
206 	writel(reg, CRG_REG_BASE + REG_CRG80);
207 	udelay(U_LEVEL2);
208 
209 	/* usb2 vcc reset */
210 	reg = readl(CRG_REG_BASE + REG_CRG80);
211 	reg |= USB2_VCC_SRST_REQ;
212 	writel(reg, CRG_REG_BASE + REG_CRG80);
213 	udelay(U_LEVEL6);
214 
215 	phy_hiusb_init_clk(index);
216 
217 	/* cancel vcc reset */
218 	reg = readl(CRG_REG_BASE + REG_CRG80);
219 	reg &= ~USB2_VCC_SRST_REQ;
220 	writel(reg, CRG_REG_BASE + REG_CRG80);
221 	udelay(U_LEVEL6);
222 
223 	/* usb2 test vbus using gpio */
224 	writel(USB2_VBUS_IO_VAL, USB2_VBUS_IO_BASE_REG + USB2_VBUS_IO_OFFSET);
225 	udelay(U_LEVEL2);
226 
227 	/* USB2 Controller configs */
228 	reg = readl(USB3_CTRL_REG_BASE + REG_GUSB3PIPECTL0);
229 	reg |= PCS_SSP_SOFT_RESET;
230 	writel(reg, USB3_CTRL_REG_BASE + REG_GUSB3PIPECTL0);
231 	udelay(U_LEVEL2);
232 
233 	reg = readl(USB3_CTRL_REG_BASE + REG_GCTL);
234 	reg &= ~PORT_CAP_DIR;
235 	reg |= PORT_SET_HOST; /* [13:12] 01: Host; 10: Device; 11: OTG */
236 	writel(reg, USB3_CTRL_REG_BASE + REG_GCTL);
237 	udelay(U_LEVEL2);
238 
239 	reg = readl(USB3_CTRL_REG_BASE + REG_GUSB3PIPECTL0);
240 	reg &= ~PCS_SSP_SOFT_RESET;
241 	reg &= ~PORT_DISABLE_SUSPEND; /* disable suspend */
242 	writel(reg, USB3_CTRL_REG_BASE + REG_GUSB3PIPECTL0);
243 	udelay(U_LEVEL2);
244 
245 	writel(USB2_G_TXTHRCFG, USB3_CTRL_REG_BASE + GTXTHRCFG);
246 	writel(USB2_G_RXTHRCFG, USB3_CTRL_REG_BASE + GRXTHRCFG);
247 	udelay(U_LEVEL2);
248 
249 	/*  USB2 eye config */
250 	usb2_eye_config();
251 }
252 EXPORT_SYMBOL(phy_hiusb_init);
253 
xhci_hcd_stop(int index)254 void xhci_hcd_stop(int index)
255 {
256 	unsigned int reg;
257 
258 	/* usb2 vcc reset */
259 	reg = readl(CRG_REG_BASE + REG_CRG80);
260 	reg |= USB2_VCC_SRST_REQ;
261 	writel(reg, CRG_REG_BASE + REG_CRG80);
262 	udelay(U_LEVEL6);
263 }
264 EXPORT_SYMBOL(xhci_hcd_stop);
265