1 /** @file
2 *
3 * Copyright (c) 2017, Linaro. All rights reserved.
4 *
5 * This program and the accompanying materials
6 * are licensed and made available under the terms and conditions of the BSD License
7 * which accompanies this distribution. The full text of the license may be found at
8 * http://opensource.org/licenses/bsd-license.php
9 *
10 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 *
13 **/
14
15 #include <Library/BaseMemoryLib.h>
16 #include <Library/DebugLib.h>
17 #include <Library/DevicePathLib.h>
18 #include <Library/IoLib.h>
19 #include <Library/TimerLib.h>
20 #include <Library/UefiBootServicesTableLib.h>
21 #include <Library/UefiLib.h>
22 #include <Library/UefiRuntimeServicesTableLib.h>
23 #include <Library/UsbSerialNumberLib.h>
24
25 #include <Protocol/BlockIo.h>
26 #include <Protocol/DwUsb.h>
27
28 #include <Hi3660.h>
29
30 #define USB_EYE_PARAM 0x01c466e3
31 #define USB_PHY_TX_VBOOST_LVL 5
32
33 #define DWC3_PHY_RX_OVRD_IN_HI 0x1006
34 #define DWC3_PHY_RX_SCOPE_VDCC 0x1026
35
36 #define RX_SCOPE_LFPS_EN (1 << 0)
37
38 #define TX_VBOOST_LVL_MASK 7
39 #define TX_VBOOST_LVL(x) ((x) & TX_VBOOST_LVL_MASK)
40
41 #define SERIAL_NUMBER_LBA 20
42
43 STATIC EFI_HANDLE mFlashHandle;
44
45 UINTN
HiKey960GetUsbMode(IN VOID)46 HiKey960GetUsbMode (
47 IN VOID
48 )
49 {
50 return USB_DEVICE_MODE;
51 }
52
53 VOID
HiKey960UsbPhyCrWaitAck(VOID)54 HiKey960UsbPhyCrWaitAck (
55 VOID
56 )
57 {
58 INT32 Timeout = 1000;
59 UINT32 Data;
60
61 while (TRUE) {
62 Data = MmioRead32 (USB3OTG_PHY_CR_STS);
63 if ((Data & USB3OTG_PHY_CR_ACK) == USB3OTG_PHY_CR_ACK) {
64 return;
65 }
66 MicroSecondDelay (50);
67 if (Timeout-- <= 0) {
68 DEBUG ((DEBUG_ERROR, "Wait PHY_CR_ACK timeout!\n"));
69 return;
70 }
71 }
72 }
73
74 VOID
HiKey960UsbPhyCrSetAddr(IN UINT32 Addr)75 HiKey960UsbPhyCrSetAddr (
76 IN UINT32 Addr
77 )
78 {
79 // set addr
80 MmioWrite32 (
81 USB3OTG_PHY_CR_CTRL,
82 USB3OTG_PHY_CR_DATA_IN (Addr)
83 );
84 MicroSecondDelay (100);
85 // cap addr
86 MmioOr32 (USB3OTG_PHY_CR_CTRL, USB3OTG_PHY_CR_CAP_ADDR);
87 HiKey960UsbPhyCrWaitAck ();
88 MmioWrite32 (USB3OTG_PHY_CR_CTRL, 0);
89 }
90
91 UINT16
HiKey960UsbPhyCrRead(IN UINT32 Addr)92 HiKey960UsbPhyCrRead (
93 IN UINT32 Addr
94 )
95 {
96 INT32 Timeout = 1000;
97 UINT32 Data;
98
99 HiKey960UsbPhyCrSetAddr (Addr);
100 MmioWrite32 (USB3OTG_PHY_CR_CTRL, USB3OTG_PHY_CR_READ);
101 MicroSecondDelay (100);
102
103 while (TRUE) {
104 Data = MmioRead32 (USB3OTG_PHY_CR_STS);
105 if ((Data & USB3OTG_PHY_CR_ACK) == USB3OTG_PHY_CR_ACK) {
106 DEBUG ((
107 DEBUG_INFO,
108 "Addr 0x%x, Data Out:0x%x\n",
109 Addr,
110 USB3OTG_PHY_CR_DATA_OUT(Data)
111 ));
112 break;
113 }
114 MicroSecondDelay (50);
115 if (Timeout-- <= 0) {
116 DEBUG ((DEBUG_ERROR, "Wait PHY_CR_ACK timeout!\n"));
117 break;
118 }
119 }
120 MmioWrite32 (USB3OTG_PHY_CR_CTRL, 0);
121 return (UINT16)USB3OTG_PHY_CR_DATA_OUT(Data);
122 }
123
124 VOID
HiKey960UsbPhyCrWrite(IN UINT32 Addr,IN UINT32 Value)125 HiKey960UsbPhyCrWrite (
126 IN UINT32 Addr,
127 IN UINT32 Value
128 )
129 {
130 UINT32 Data;
131
132 HiKey960UsbPhyCrSetAddr (Addr);
133 Data = USB3OTG_PHY_CR_DATA_IN(Value);
134 MmioWrite32 (USB3OTG_PHY_CR_CTRL, Data);
135
136 Data = MmioRead32 (USB3OTG_PHY_CR_CTRL);
137 Data |= USB3OTG_PHY_CR_CAP_DATA;
138 MmioWrite32 (USB3OTG_PHY_CR_CTRL, Data);
139 HiKey960UsbPhyCrWaitAck ();
140
141 MmioWrite32 (USB3OTG_PHY_CR_CTRL, 0);
142 MmioWrite32 (USB3OTG_PHY_CR_CTRL, USB3OTG_PHY_CR_WRITE);
143 HiKey960UsbPhyCrWaitAck ();
144 }
145
146 VOID
HiKey960UsbSetEyeDiagramParam(VOID)147 HiKey960UsbSetEyeDiagramParam (
148 VOID
149 )
150 {
151 UINT32 Data;
152
153 /* set eye diagram for usb 2.0 */
154 MmioWrite32 (USB3OTG_CTRL4, USB_EYE_PARAM);
155 /* set eye diagram for usb 3.0 */
156 HiKey960UsbPhyCrRead (DWC3_PHY_RX_OVRD_IN_HI);
157 HiKey960UsbPhyCrWrite (DWC3_PHY_RX_OVRD_IN_HI, BIT11 | BIT9 | BIT8 |BIT7);
158 HiKey960UsbPhyCrRead (DWC3_PHY_RX_OVRD_IN_HI);
159
160 /* enable RX_SCOPE_LFPS_EN for usb 3.0 */
161 Data = HiKey960UsbPhyCrRead (DWC3_PHY_RX_SCOPE_VDCC);
162 Data |= RX_SCOPE_LFPS_EN;
163 HiKey960UsbPhyCrWrite (DWC3_PHY_RX_SCOPE_VDCC, Data);
164 HiKey960UsbPhyCrRead (DWC3_PHY_RX_SCOPE_VDCC);
165
166 Data = MmioRead32 (USB3OTG_CTRL6);
167 Data &= ~TX_VBOOST_LVL_MASK;
168 Data = TX_VBOOST_LVL (USB_PHY_TX_VBOOST_LVL);
169 MmioWrite32 (USB3OTG_CTRL6, Data);
170 DEBUG ((
171 DEBUG_INFO,
172 "set ss phy tx vboost lvl 0x%x\n",
173 MmioRead32 (USB3OTG_CTRL6)
174 ));
175 }
176
177 STATIC
178 VOID
HiKey960UsbReset(VOID)179 HiKey960UsbReset (
180 VOID
181 )
182 {
183 MmioWrite32 (CRG_PERRSTEN4, PERRSTEN4_USB3OTG);
184 MmioWrite32 (CRG_PERRSTEN4, PERRSTEN4_USB3OTGPHY_POR);
185 MmioWrite32 (
186 CRG_PERRSTEN4,
187 PERRSTEN4_USB3OTG_MUX | PERRSTEN4_USB3OTG_AHBIF | PERRSTEN4_USB3OTG_32K
188 );
189 MmioWrite32 (
190 CRG_PERDIS4,
191 PEREN4_GT_ACLK_USB3OTG | PEREN4_GT_CLK_USB3OTG_REF
192 );
193
194 MmioAnd32 (PCTRL_CTRL24, ~PCTRL_CTRL24_USB3PHY_3MUX1_SEL);
195 // disable
196 MmioWrite32 (PCTRL_CTRL3, (PCTRL_CTRL3_USB_TXCO_EN << 16) | 0);
197 MicroSecondDelay (10000);
198 }
199
200 STATIC
201 VOID
HiKey960UsbRelease(VOID)202 HiKey960UsbRelease (
203 VOID
204 )
205 {
206 /* enable USB REFCLK ISO */
207 MmioWrite32 (CRG_ISODIS, PERISOEN_USB_REFCLK_ISO_EN);
208 /* enable USB_TXCO_EN */
209 MmioWrite32 (PCTRL_CTRL3, (PCTRL_CTRL3_USB_TXCO_EN << 16) | PCTRL_CTRL3_USB_TXCO_EN);
210
211 MmioAnd32 (PCTRL_CTRL24, ~PCTRL_CTRL24_USB3PHY_3MUX1_SEL);
212
213 MmioWrite32 (
214 CRG_PEREN4,
215 PEREN4_GT_ACLK_USB3OTG | PEREN4_GT_CLK_USB3OTG_REF
216 );
217 MmioWrite32 (
218 CRG_PERRSTDIS4,
219 PERRSTEN4_USB3OTG_MUX | PERRSTEN4_USB3OTG_AHBIF | PERRSTEN4_USB3OTG_32K
220 );
221
222 MmioWrite32 (CRG_PERRSTEN4, PERRSTEN4_USB3OTG | PERRSTEN4_USB3OTGPHY_POR);
223
224 /* enable PHY REF CLK */
225 MmioOr32 (USB3OTG_CTRL0, USB3OTG_CTRL0_SC_USB3PHY_ABB_GT_EN);
226
227 MmioOr32 (USB3OTG_CTRL7, USB3OTG_CTRL7_REF_SSP_EN);
228
229 /* exit from IDDQ mode */
230 MmioAnd32 (
231 USB3OTG_CTRL2,
232 ~(USB3OTG_CTRL2_TEST_POWERDOWN_SSP | USB3OTG_CTRL2_TEST_POWERDOWN_HSP)
233 );
234 MicroSecondDelay (100000);
235
236 MmioWrite32 (CRG_PERRSTDIS4, PERRSTEN4_USB3OTGPHY_POR);
237 MmioWrite32 (CRG_PERRSTDIS4, PERRSTEN4_USB3OTG);
238 MicroSecondDelay (10000);
239 MmioOr32 (USB3OTG_CTRL3, USB3OTG_CTRL3_VBUSVLDEXT | USB3OTG_CTRL3_VBUSVLDEXTSEL);
240 MicroSecondDelay (100000);
241
242 HiKey960UsbSetEyeDiagramParam ();
243 }
244
245 EFI_STATUS
HiKey960UsbPhyInit(IN UINT8 Mode)246 HiKey960UsbPhyInit (
247 IN UINT8 Mode
248 )
249 {
250 HiKey960UsbReset ();
251 MicroSecondDelay (10000);
252 HiKey960UsbRelease ();
253
254 return EFI_SUCCESS;
255 }
256
257 EFI_STATUS
258 EFIAPI
HiKey960UsbGetLang(OUT CHAR16 * Lang,OUT UINT8 * Length)259 HiKey960UsbGetLang (
260 OUT CHAR16 *Lang,
261 OUT UINT8 *Length
262 )
263 {
264 if ((Lang == NULL) || (Length == NULL)) {
265 return EFI_INVALID_PARAMETER;
266 }
267 Lang[0] = 0x409;
268 *Length = sizeof (CHAR16);
269 return EFI_SUCCESS;
270 }
271
272 EFI_STATUS
273 EFIAPI
HiKey960UsbGetManuFacturer(OUT CHAR16 * ManuFacturer,OUT UINT8 * Length)274 HiKey960UsbGetManuFacturer (
275 OUT CHAR16 *ManuFacturer,
276 OUT UINT8 *Length
277 )
278 {
279 UINTN VariableSize;
280 CHAR16 DataUnicode[MANU_FACTURER_STRING_LENGTH];
281
282 if ((ManuFacturer == NULL) || (Length == NULL)) {
283 return EFI_INVALID_PARAMETER;
284 }
285 VariableSize = MANU_FACTURER_STRING_LENGTH * sizeof (CHAR16);
286 ZeroMem (DataUnicode, MANU_FACTURER_STRING_LENGTH * sizeof(CHAR16));
287 StrCpy (DataUnicode, L"96Boards");
288 CopyMem (ManuFacturer, DataUnicode, VariableSize);
289 *Length = VariableSize;
290 return EFI_SUCCESS;
291 }
292
293 EFI_STATUS
294 EFIAPI
HiKey960UsbGetProduct(OUT CHAR16 * Product,OUT UINT8 * Length)295 HiKey960UsbGetProduct (
296 OUT CHAR16 *Product,
297 OUT UINT8 *Length
298 )
299 {
300 UINTN VariableSize;
301 CHAR16 DataUnicode[PRODUCT_STRING_LENGTH];
302
303 if ((Product == NULL) || (Length == NULL)) {
304 return EFI_INVALID_PARAMETER;
305 }
306 VariableSize = PRODUCT_STRING_LENGTH * sizeof (CHAR16);
307 ZeroMem (DataUnicode, PRODUCT_STRING_LENGTH * sizeof(CHAR16));
308 StrCpy (DataUnicode, L"HiKey960");
309 CopyMem (Product, DataUnicode, VariableSize);
310 *Length = VariableSize;
311 return EFI_SUCCESS;
312 }
313
314 EFI_STATUS
315 EFIAPI
HiKey960UsbGetSerialNo(OUT CHAR16 * SerialNo,OUT UINT8 * Length)316 HiKey960UsbGetSerialNo (
317 OUT CHAR16 *SerialNo,
318 OUT UINT8 *Length
319 )
320 {
321 EFI_STATUS Status;
322 EFI_DEVICE_PATH_PROTOCOL *FlashDevicePath;
323
324 if (mFlashHandle == 0) {
325 FlashDevicePath = ConvertTextToDevicePath ((CHAR16*)FixedPcdGetPtr (PcdAndroidFastbootNvmDevicePath));
326 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &FlashDevicePath, &mFlashHandle);
327 if (EFI_ERROR (Status)) {
328 DEBUG ((DEBUG_ERROR, "Warning: Couldn't locate Android NVM device (status: %r)\n", Status));
329 // Failing to locate partitions should not prevent to do other Android FastBoot actions
330 return EFI_SUCCESS;
331 }
332 }
333
334 if ((SerialNo == NULL) || (Length == NULL)) {
335 return EFI_INVALID_PARAMETER;
336 }
337 Status = LoadSNFromBlock (mFlashHandle, SERIAL_NUMBER_LBA, SerialNo);
338 *Length = StrSize (SerialNo);
339 return Status;
340 }
341
342 DW_USB_PROTOCOL mDwUsbDevice = {
343 HiKey960UsbGetLang,
344 HiKey960UsbGetManuFacturer,
345 HiKey960UsbGetProduct,
346 HiKey960UsbGetSerialNo,
347 HiKey960UsbPhyInit
348 };
349
350 EFI_STATUS
351 EFIAPI
HiKey960UsbEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)352 HiKey960UsbEntryPoint (
353 IN EFI_HANDLE ImageHandle,
354 IN EFI_SYSTEM_TABLE *SystemTable
355 )
356 {
357 return gBS->InstallProtocolInterface (
358 &ImageHandle,
359 &gDwUsbProtocolGuid,
360 EFI_NATIVE_INTERFACE,
361 &mDwUsbDevice
362 );
363 }
364