1 /** @file
2
3 Copyright (c) 2014, Applied Micro Curcuit Corporation. All rights reserved.<BR>
4 Copyright (c) 2015, Hisilicon Limited. All rights reserved.<BR>
5 Copyright (c) 2015, Linaro Limited. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 This driver is called to initialize the FW part of the PHY in preparation
15 for the OS.
16
17 **/
18
19 #include <Guid/ShellVariableGuid.h>
20 #include <Library/UefiRuntimeServicesTableLib.h>
21 #include <Library/DebugLib.h>
22 #include <Library/TimerLib.h>
23
24 #include <PiDxe.h>
25 #include <Guid/EventGroup.h>
26 #include <Protocol/AcpiTable.h>
27 #include <Protocol/FirmwareVolume2.h>
28 #include <Library/BaseLib.h>
29 #include <Library/UefiBootServicesTableLib.h>
30 #include <Protocol/AcpiSystemDescriptionTable.h>
31 #include <Library/DebugLib.h>
32 #include <Library/PcdLib.h>
33 #include <Library/PrintLib.h>
34 #include <Library/DebugLib.h>
35 #include <Library/BaseMemoryLib.h>
36 #include <Library/UefiRuntimeServicesTableLib.h>
37 #include <IndustryStandard/Acpi.h>
38 #include <IndustryStandard/AcpiAml.h>
39
40 #include <Protocol/HisiBoardNicProtocol.h>
41
42 // Turn on debug message by enabling below define
43 //#define ACPI_DEBUG
44
45 #ifdef ACPI_DEBUG
46 #define DBG(arg...) DEBUG((EFI_D_ERROR,## arg))
47 #else
48 #define DBG(arg...)
49 #endif
50
51 #define EFI_ACPI_MAX_NUM_TABLES 20
52 #define DSDT_SIGNATURE 0x54445344
53
54 #define D02_ACPI_ETH_ID "HISI00C1"
55 #define D03_ACPI_ETH_ID "HISI00C2"
56
57 #define ACPI_ETH_MAC_KEY "local-mac-address"
58
59 #define PREFIX_VARIABLE_NAME L"MAC"
60 #define PREFIX_VARIABLE_NAME_COMPAT L"RGMII_MAC"
61 #define MAC_MAX_LEN 30
62
GetEnvMac(IN UINTN MacNextID,IN OUT UINT8 * MacBuffer)63 EFI_STATUS GetEnvMac(
64 IN UINTN MacNextID,
65 IN OUT UINT8 *MacBuffer)
66 {
67 EFI_MAC_ADDRESS Mac;
68 EFI_STATUS Status;
69 HISI_BOARD_NIC_PROTOCOL *OemNic = NULL;
70
71 Status = gBS->LocateProtocol(&gHisiBoardNicProtocolGuid, NULL, (VOID **)&OemNic);
72 if(EFI_ERROR(Status))
73 {
74 DEBUG((EFI_D_ERROR, "[%a]:[%dL] LocateProtocol failed %r\n", __FUNCTION__, __LINE__, Status));
75 return Status;
76 }
77
78 Status = OemNic->GetMac(&Mac, MacNextID);
79 if(EFI_ERROR(Status))
80 {
81 DEBUG((EFI_D_ERROR, "[%a]:[%dL] GetMac failed %r\n", __FUNCTION__, __LINE__, Status));
82 return Status;
83 }
84
85 CopyMem (MacBuffer, &Mac, 6);
86 DEBUG((EFI_D_ERROR, "Port %d MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
87 MacNextID,
88 MacBuffer[0],
89 MacBuffer[1],
90 MacBuffer[2],
91 MacBuffer[3],
92 MacBuffer[4],
93 MacBuffer[5]
94 ));
95
96 return EFI_SUCCESS;
97 }
98
_SearchReplacePackageMACAddress(IN EFI_ACPI_SDT_PROTOCOL * AcpiTableProtocol,IN EFI_ACPI_HANDLE ChildHandle,IN UINTN Level,IN OUT BOOLEAN * Found,IN UINTN MacNextID)99 EFI_STATUS _SearchReplacePackageMACAddress(
100 IN EFI_ACPI_SDT_PROTOCOL *AcpiTableProtocol,
101 IN EFI_ACPI_HANDLE ChildHandle,
102 IN UINTN Level,
103 IN OUT BOOLEAN *Found,
104 IN UINTN MacNextID)
105 {
106 // ASL template for ethernet driver:
107 /*
108 * Name (_DSD, Package () {
109 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
110 * Package () {
111 * Package (2) {"mac-address", Package (6) { 00, 11, 22, 33, 44, 55 }}
112 * Package (2) {"phy-channel", 0},
113 * Package (2) {"phy-mode", "rgmii"},
114 * Package (2) {"max-transfer-unit", 0x5dc}, // MTU of 1500
115 * Package (2) {"max-speed", 0x3e8}, // 1000 Mbps
116 * }
117 * })
118 */
119 EFI_STATUS Status;
120 EFI_ACPI_DATA_TYPE DataType;
121 CONST UINT8 *Data;
122 CONST VOID *Buffer;
123 UINTN DataSize;
124 UINTN Count;
125 EFI_ACPI_HANDLE CurrentHandle;
126 EFI_ACPI_HANDLE NextHandle;
127 UINT8 MACBuffer[MAC_MAX_LEN];
128
129 DBG("In Level:%d\n", Level);
130 Status = EFI_SUCCESS;
131 for (CurrentHandle = NULL; ;) {
132 Status = AcpiTableProtocol->GetChild(ChildHandle, &CurrentHandle);
133 if (Level != 3 && (EFI_ERROR(Status) || CurrentHandle == NULL))
134 break;
135
136 Status = AcpiTableProtocol->GetOption(CurrentHandle, 0, &DataType, &Buffer, &DataSize);
137 Data = Buffer;
138 DBG("_DSD Child Subnode Store Op Code 0x%02X 0x%02X %02X\n",
139 DataSize, Data[0], DataSize > 1 ? Data[1] : 0);
140
141 if (Level < 2 && Data[0] != AML_PACKAGE_OP)
142 continue;
143
144 if (Level == 2 && Data[0] == AML_STRING_PREFIX) {
145 Status = AcpiTableProtocol->GetOption(CurrentHandle, 1, &DataType, &Buffer, &DataSize);
146 if (EFI_ERROR(Status))
147 break;
148
149 DBG(" _DSD Child Subnode Store Op Code 0x%02X 0x%02X %02X\n",
150 DataSize, Data[0], DataSize > 1 ? Data[1] : 0);
151
152 Data = Buffer;
153 if (DataType != EFI_ACPI_DATA_TYPE_STRING
154 || AsciiStrCmp((CHAR8 *) Data, ACPI_ETH_MAC_KEY) != 0)
155 continue;
156
157 DBG("_DSD Key Type %d. Found MAC address key\n", DataType);
158
159 //
160 // We found the node.
161 //
162 *Found = TRUE;
163 continue;
164 }
165
166 if (Level == 3 && *Found) {
167
168 //Update the MAC
169 Status = GetEnvMac(MacNextID, MACBuffer);
170 if (EFI_ERROR(Status))
171 break;
172
173 for (Count = 0; Count < 6; Count++) {
174 Status = AcpiTableProtocol->GetOption(CurrentHandle, 1, &DataType, &Buffer, &DataSize);
175 if (EFI_ERROR(Status))
176 break;
177
178 Data = Buffer;
179 DBG(" _DSD Child Subnode Store Op Code 0x%02X 0x%02X %02X DataType 0x%X\n",
180 DataSize, Data[0], DataSize > 1 ? Data[1] : 0, DataType);
181
182 if (DataType != EFI_ACPI_DATA_TYPE_UINT)
183 break;
184
185 // only need one byte.
186 // FIXME: Assume the CPU is little endian
187 Status = AcpiTableProtocol->SetOption(CurrentHandle, 1, (VOID *)&MACBuffer[Count], sizeof(UINT8));
188 if (EFI_ERROR(Status))
189 break;
190 Status = AcpiTableProtocol->GetChild(ChildHandle, &CurrentHandle);
191 if (EFI_ERROR(Status) || CurrentHandle == NULL)
192 break;
193 }
194 break;
195 }
196
197 if (Level > 3)
198 break;
199
200 //Search next package
201 AcpiTableProtocol->Open((VOID *) Buffer, &NextHandle);
202 Status = _SearchReplacePackageMACAddress(AcpiTableProtocol, NextHandle, Level + 1, Found, MacNextID);
203 AcpiTableProtocol->Close(NextHandle);
204 if (!EFI_ERROR(Status))
205 break;
206 }
207
208 return Status;
209 }
210
SearchReplacePackageMACAddress(IN EFI_ACPI_SDT_PROTOCOL * AcpiTableProtocol,IN EFI_ACPI_HANDLE ChildHandle,IN UINTN MacNextID)211 EFI_STATUS SearchReplacePackageMACAddress(
212 IN EFI_ACPI_SDT_PROTOCOL *AcpiTableProtocol,
213 IN EFI_ACPI_HANDLE ChildHandle,
214 IN UINTN MacNextID)
215 {
216 BOOLEAN Found = FALSE;
217 UINTN Level = 0;
218
219 return _SearchReplacePackageMACAddress(AcpiTableProtocol, ChildHandle, Level, &Found, MacNextID);
220 }
221
222 EFI_STATUS
GetEthID(EFI_ACPI_SDT_PROTOCOL * AcpiTableProtocol,EFI_ACPI_HANDLE ChildHandle,UINTN * EthID)223 GetEthID (
224 EFI_ACPI_SDT_PROTOCOL *AcpiTableProtocol,
225 EFI_ACPI_HANDLE ChildHandle,
226 UINTN *EthID
227 )
228 {
229 EFI_STATUS Status;
230 EFI_ACPI_DATA_TYPE DataType;
231 CHAR8 Data[5];
232 CONST VOID *Buffer;
233 UINTN DataSize;
234
235 // Get NameString ETHx
236 Status = AcpiTableProtocol->GetOption (ChildHandle, 1, &DataType, &Buffer, &DataSize);
237 if (EFI_ERROR (Status)) {
238 DEBUG ((EFI_D_ERROR, "[%a:%d] Get NameString failed: %r\n", __FUNCTION__, __LINE__, Status));
239 return Status;
240 }
241
242 CopyMem (Data, Buffer, 4);
243 DBG("Size %p Data %02x %02x %02x %02x\n", DataSize, Data[0], Data[1], Data[2], Data[3]);
244
245 Data[4] = '\0';
246 if (DataSize != 4 ||
247 AsciiStrnCmp ("ETH", Data, 3) != 0 ||
248 Data[3] > '9' || Data[3] < '0') {
249 DEBUG ((EFI_D_ERROR, "[%a:%d] The NameString %a is not ETHn\n", __FUNCTION__, __LINE__, Data));
250 return EFI_INVALID_PARAMETER;
251 }
252
253 *EthID = Data[3] - '0';
254 return EFI_SUCCESS;
255 }
256
ProcessDSDTDevice(EFI_ACPI_SDT_PROTOCOL * AcpiTableProtocol,EFI_ACPI_HANDLE ChildHandle)257 EFI_STATUS ProcessDSDTDevice (
258 EFI_ACPI_SDT_PROTOCOL *AcpiTableProtocol,
259 EFI_ACPI_HANDLE ChildHandle)
260 {
261 EFI_STATUS Status;
262 EFI_ACPI_DATA_TYPE DataType;
263 CONST UINT8 *Data;
264 CONST VOID *Buffer;
265 UINTN DataSize;
266 EFI_ACPI_HANDLE DevHandle;
267 INTN Found = 0;
268 UINTN MacNextID;
269
270 Status = AcpiTableProtocol->GetOption(ChildHandle, 0, &DataType, &Buffer, &DataSize);
271 if (EFI_ERROR(Status))
272 return EFI_SUCCESS;
273
274 Data = Buffer;
275 //
276 // Skip all non-device type
277 //
278 if (DataSize != 2 || Data[0] != AML_EXT_OP || Data[1] != AML_EXT_DEVICE_OP)
279 return EFI_SUCCESS;
280
281 //
282 // Walk the device type node
283 //
284 for (DevHandle = NULL; ; ) {
285 Status = AcpiTableProtocol->GetChild(ChildHandle, &DevHandle);
286 if (EFI_ERROR(Status) || DevHandle == NULL)
287 break;
288
289 //
290 // Search for _HID with Ethernet ID
291 //
292 Status = AcpiTableProtocol->GetOption(DevHandle, 0, &DataType, &Buffer, &DataSize);
293 if (EFI_ERROR(Status))
294 break;
295
296 Data = Buffer;
297 DBG("Data Type 0x%02X %02X\n", Data[0], DataSize > 1 ? Data[1] : 0);
298 if (DataSize == 1 && Data[0] == AML_NAME_OP) {
299 Status = AcpiTableProtocol->GetOption(DevHandle, 1, &DataType, &Buffer, &DataSize);
300 if (EFI_ERROR(Status))
301 break;
302
303 Data = Buffer;
304 if (DataType == EFI_ACPI_DATA_TYPE_NAME_STRING) {
305 if (AsciiStrnCmp((CHAR8 *) Data, "_HID", 4) == 0) {
306 EFI_ACPI_HANDLE ValueHandle;
307
308 Status = AcpiTableProtocol->GetOption(DevHandle, 2, &DataType, &Buffer, &DataSize);
309 if (EFI_ERROR(Status))
310 break;
311
312 if (DataType != EFI_ACPI_DATA_TYPE_CHILD)
313 continue;
314
315 AcpiTableProtocol->Open((VOID *) Buffer, &ValueHandle);
316 Status = AcpiTableProtocol->GetOption(ValueHandle, 1, &DataType, &Buffer, &DataSize);
317
318 Data = Buffer;
319 DBG("[%a:%d] - _HID = %a\n", __FUNCTION__, __LINE__, Data);
320
321 if (EFI_ERROR(Status) ||
322 DataType != EFI_ACPI_DATA_TYPE_STRING ||
323 ((AsciiStrCmp((CHAR8 *) Data, D02_ACPI_ETH_ID) != 0) &&
324 (AsciiStrCmp((CHAR8 *) Data, D03_ACPI_ETH_ID) != 0))) {
325 AcpiTableProtocol->Close(ValueHandle);
326 Found = 0;
327 continue;
328 }
329
330 DBG("Found Ethernet device\n");
331 AcpiTableProtocol->Close(ValueHandle);
332 Status = GetEthID (AcpiTableProtocol, ChildHandle, &MacNextID);
333 if (EFI_ERROR (Status)) {
334 continue;
335 }
336 Found = 1;
337 } else if (Found == 1 && AsciiStrnCmp((CHAR8 *) Data, "_DSD", 4) == 0) {
338 //
339 // Patch MAC address for open source kernel
340 //
341 EFI_ACPI_HANDLE PkgHandle;
342 Status = AcpiTableProtocol->GetOption(DevHandle, 2, &DataType, &Buffer, &DataSize);
343 if (EFI_ERROR(Status))
344 break;
345
346 if (DataType != EFI_ACPI_DATA_TYPE_CHILD)
347 continue;
348
349 //
350 // Open package data
351 //
352 AcpiTableProtocol->Open((VOID *) Buffer, &PkgHandle);
353 Status = AcpiTableProtocol->GetOption(PkgHandle, 0, &DataType, &Buffer, &DataSize);
354
355 Data = Buffer;
356 DBG("_DSD Subnode Store Op Code 0x%02X %02X\n",
357 Data[0], DataSize > 1 ? Data[1] : 0);
358
359 //
360 // Walk the _DSD node
361 //
362 if (DataSize == 1 && Data[0] == AML_PACKAGE_OP)
363 Status = SearchReplacePackageMACAddress(AcpiTableProtocol, PkgHandle, MacNextID);
364
365 AcpiTableProtocol->Close(PkgHandle);
366 }
367 }
368 }
369 }
370
371 return EFI_SUCCESS;
372 }
373
374
375 BOOLEAN
IsSbScope(EFI_ACPI_SDT_PROTOCOL * AcpiTableProtocol,EFI_ACPI_HANDLE ChildHandle)376 IsSbScope (
377 EFI_ACPI_SDT_PROTOCOL *AcpiTableProtocol,
378 EFI_ACPI_HANDLE ChildHandle
379 )
380 {
381 EFI_STATUS Status;
382 EFI_ACPI_DATA_TYPE DataType;
383 CONST UINT8 *Data;
384 CONST VOID *Buffer;
385 UINTN DataSize;
386
387 Status = AcpiTableProtocol->GetOption (ChildHandle, 0, &DataType, &Buffer, &DataSize);
388 if (EFI_ERROR(Status)) return FALSE;
389
390 Data = Buffer;
391 if (DataSize != 1 || Data[0] != AML_SCOPE_OP) {
392 return FALSE;
393 }
394
395 return TRUE;
396 }
397
ProcessDSDTChild(EFI_ACPI_SDT_PROTOCOL * AcpiTableProtocol,EFI_ACPI_HANDLE ChildHandle)398 EFI_STATUS ProcessDSDTChild(
399 EFI_ACPI_SDT_PROTOCOL *AcpiTableProtocol,
400 EFI_ACPI_HANDLE ChildHandle)
401 {
402 EFI_STATUS Status;
403 EFI_ACPI_HANDLE DevHandle;
404
405 // Check Scope(_SB) at first
406 if (!IsSbScope (AcpiTableProtocol, ChildHandle)) {
407 return ProcessDSDTDevice (AcpiTableProtocol, ChildHandle);
408 }
409
410 for (DevHandle = NULL; ; ) {
411 Status = AcpiTableProtocol->GetChild (ChildHandle, &DevHandle);
412 if (EFI_ERROR(Status) || DevHandle == NULL) {
413 break;
414 }
415
416 ProcessDSDTDevice (AcpiTableProtocol, DevHandle);
417 }
418
419 return EFI_SUCCESS;
420 }
421
ProcessDSDT(EFI_ACPI_SDT_PROTOCOL * AcpiTableProtocol,EFI_ACPI_HANDLE TableHandle)422 static EFI_STATUS ProcessDSDT(
423 EFI_ACPI_SDT_PROTOCOL *AcpiTableProtocol,
424 EFI_ACPI_HANDLE TableHandle)
425 {
426 EFI_STATUS Status;
427 EFI_ACPI_HANDLE ChildHandle;
428 //
429 // Parse table for device type
430 DBG ("[%a:%d] - TableHandle=%p\n", __FUNCTION__, __LINE__, TableHandle);
431 for (ChildHandle = NULL; ; ) {
432 Status = AcpiTableProtocol->GetChild(TableHandle, &ChildHandle);
433 DBG ("[%a:%d] - Child=%p, %r\n", __FUNCTION__, __LINE__, ChildHandle, Status);
434 if (EFI_ERROR(Status))
435 break;
436 if (ChildHandle == NULL)
437 break;
438
439 ProcessDSDTChild(AcpiTableProtocol, ChildHandle);
440 }
441
442 return EFI_SUCCESS;
443 }
444
EthMacInit(void)445 EFI_STATUS EthMacInit(void)
446 {
447 EFI_STATUS Status;
448 EFI_ACPI_SDT_PROTOCOL *AcpiTableProtocol;
449 EFI_ACPI_SDT_HEADER *Table;
450 EFI_ACPI_TABLE_VERSION TableVersion;
451 UINTN TableKey;
452 EFI_ACPI_HANDLE TableHandle;
453 UINTN i;
454
455 DEBUG ((EFI_D_ERROR, "Updating Ethernet MAC in ACPI DSDT...\n"));
456
457 //
458 // Find the AcpiTable protocol
459 Status = gBS->LocateProtocol(&gEfiAcpiSdtProtocolGuid, NULL, (VOID**) &AcpiTableProtocol);
460 if (EFI_ERROR(Status)) {
461 DBG("Unable to locate ACPI table protocol\n");
462 return EFI_SUCCESS;
463 }
464
465 //
466 // Search for DSDT Table
467 for (i = 0; i < EFI_ACPI_MAX_NUM_TABLES; i++) {
468 Status = AcpiTableProtocol->GetAcpiTable(i, &Table, &TableVersion, &TableKey);
469 if (EFI_ERROR(Status))
470 break;
471 if (Table->Signature != DSDT_SIGNATURE)
472 continue;
473
474 Status = AcpiTableProtocol->OpenSdt(TableKey, &TableHandle);
475 if (EFI_ERROR(Status))
476 break;
477
478 ProcessDSDT(AcpiTableProtocol, TableHandle);
479
480 AcpiTableProtocol->Close(TableHandle);
481 }
482
483 return EFI_SUCCESS;
484 }
485