]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.c
ArmPlatformPkg/ArmJunoPkg: Enable PCI and SATA support
[mirror_edk2.git] / ArmPlatformPkg / ArmJunoPkg / Drivers / ArmJunoDxe / ArmJunoDxe.c
1 /** @file
2 *
3 * Copyright (c) 2013-2015, ARM Limited. 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 "ArmJunoDxeInternal.h"
16 #include <ArmPlatform.h>
17
18 #include <Protocol/DevicePathFromText.h>
19 #include <Protocol/PciRootBridgeIo.h>
20
21 #include <Guid/EventGroup.h>
22 #include <Guid/GlobalVariable.h>
23
24 #include <Library/ArmShellCmdLib.h>
25 #include <Library/AcpiLib.h>
26 #include <Library/BaseMemoryLib.h>
27 #include <Library/DevicePathLib.h>
28 #include <Library/MemoryAllocationLib.h>
29 #include <Library/UefiRuntimeServicesTableLib.h>
30 #include <Library/IoLib.h>
31 #include <Library/PrintLib.h>
32
33 //
34 // Size in number of characters of the Linux boot argument
35 // passing the MAC address to be used by the PCI GigaByte
36 // Ethernet device : " sky2.mac_address=0x11,0x22,0x33,0x44,0x55,0x66"
37 //
38 #define SKY2_MAC_ADDRESS_BOOTARG_LEN 47
39
40 //
41 // Hardware platform identifiers
42 //
43 typedef enum {
44 UNKNOWN,
45 JUNO_R0,
46 JUNO_R1
47 } JUNO_REVISION;
48
49 //
50 // Function prototypes
51 //
52 STATIC EFI_STATUS SetJunoR1DefaultBootEntries (
53 VOID
54 );
55
56 // This GUID must match the FILE_GUID in ArmPlatformPkg/ArmJunoPkg/AcpiTables/AcpiTables.inf
57 STATIC CONST EFI_GUID mJunoAcpiTableFile = { 0xa1dd808e, 0x1e95, 0x4399, { 0xab, 0xc0, 0x65, 0x3c, 0x82, 0xe8, 0x53, 0x0c } };
58
59 typedef struct {
60 ACPI_HID_DEVICE_PATH AcpiDevicePath;
61 EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
62 } EFI_PCI_ROOT_BRIDGE_DEVICE_PATH;
63
64 STATIC CONST EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mPciRootComplexDevicePath = {
65 {
66 { ACPI_DEVICE_PATH,
67 ACPI_DP,
68 { (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)),
69 (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8) }
70 },
71 EISA_PNP_ID (0x0A03),
72 0
73 },
74 {
75 END_DEVICE_PATH_TYPE,
76 END_ENTIRE_DEVICE_PATH_SUBTYPE,
77 { END_DEVICE_PATH_LENGTH, 0 }
78 }
79 };
80
81 /**
82 * Build and Set UEFI Variable Boot####
83 *
84 * @param BootVariableName Name of the UEFI Variable
85 * @param Attributes 'Attributes' for the Boot#### variable as per UEFI spec
86 * @param BootDescription Description of the Boot#### variable
87 * @param DevicePath EFI Device Path of the EFI Application to boot
88 * @param OptionalData Parameters to pass to the EFI application
89 * @param OptionalDataSize Size of the parameters to pass to the EFI application
90 *
91 * @return EFI_OUT_OF_RESOURCES A memory allocation failed
92 * @return Return value of RT.SetVariable
93 */
94 STATIC
95 EFI_STATUS
96 BootOptionCreate (
97 IN CHAR16 BootVariableName[9],
98 IN UINT32 Attributes,
99 IN CHAR16* BootDescription,
100 IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
101 IN UINT8* OptionalData,
102 IN UINTN OptionalDataSize
103 )
104 {
105 UINTN VariableSize;
106 UINT8 *Variable;
107 UINT8 *VariablePtr;
108 UINTN FilePathListLength;
109 UINTN BootDescriptionSize;
110
111 FilePathListLength = GetDevicePathSize (DevicePath);
112 BootDescriptionSize = StrSize (BootDescription);
113
114 // Each Boot#### variable is built as follow:
115 // UINT32 Attributes
116 // UINT16 FilePathListLength
117 // CHAR16* Description
118 // EFI_DEVICE_PATH_PROTOCOL FilePathList[]
119 // UINT8 OptionalData[]
120 VariableSize = sizeof (UINT32) + sizeof (UINT16) +
121 BootDescriptionSize + FilePathListLength + OptionalDataSize;
122 Variable = AllocateZeroPool (VariableSize);
123 if (Variable == NULL) {
124 return EFI_OUT_OF_RESOURCES;
125 }
126
127 // 'Attributes' field
128 *(UINT32*)Variable = Attributes;
129 // 'FilePathListLength' field
130 VariablePtr = Variable + sizeof (UINT32);
131 *(UINT16*)VariablePtr = FilePathListLength;
132 // 'Description' field
133 VariablePtr += sizeof (UINT16);
134 CopyMem (VariablePtr, BootDescription, BootDescriptionSize);
135 // 'FilePathList' field
136 VariablePtr += BootDescriptionSize;
137 CopyMem (VariablePtr, DevicePath, FilePathListLength);
138 // 'OptionalData' field
139 VariablePtr += FilePathListLength;
140 CopyMem (VariablePtr, OptionalData, OptionalDataSize);
141
142 return gRT->SetVariable (
143 BootVariableName,
144 &gEfiGlobalVariableGuid,
145 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
146 VariableSize, Variable
147 );
148 }
149
150 /**
151 Notification function of the event defined as belonging to the
152 EFI_END_OF_DXE_EVENT_GROUP_GUID event group that was created in
153 the entry point of the driver.
154
155 This function is called when an event belonging to the
156 EFI_END_OF_DXE_EVENT_GROUP_GUID event group is signalled. Such an
157 event is signalled once at the end of the dispatching of all
158 drivers (end of the so called DXE phase).
159
160 @param[in] Event Event declared in the entry point of the driver whose
161 notification function is being invoked.
162 @param[in] Context NULL
163 **/
164 STATIC
165 VOID
166 OnEndOfDxe (
167 IN EFI_EVENT Event,
168 IN VOID *Context
169 )
170 {
171 EFI_DEVICE_PATH_PROTOCOL* PciRootComplexDevicePath;
172 EFI_HANDLE Handle;
173 EFI_STATUS Status;
174
175 //
176 // PCI Root Complex initialization
177 // At the end of the DXE phase, we should get all the driver dispatched.
178 // Force the PCI Root Complex to be initialized. It allows the OS to skip
179 // this step.
180 //
181 PciRootComplexDevicePath = (EFI_DEVICE_PATH_PROTOCOL*) &mPciRootComplexDevicePath;
182 Status = gBS->LocateDevicePath (&gEfiPciRootBridgeIoProtocolGuid,
183 &PciRootComplexDevicePath,
184 &Handle);
185
186 Status = gBS->ConnectController (Handle, NULL, PciRootComplexDevicePath, FALSE);
187 ASSERT_EFI_ERROR (Status);
188 }
189
190 EFI_STATUS
191 EFIAPI
192 ArmJunoEntryPoint (
193 IN EFI_HANDLE ImageHandle,
194 IN EFI_SYSTEM_TABLE *SystemTable
195 )
196 {
197 EFI_STATUS Status;
198 EFI_PHYSICAL_ADDRESS HypBase;
199 CHAR16 *TextDevicePath;
200 UINTN TextDevicePathSize;
201 VOID *Buffer;
202 UINT32 Midr;
203 UINT32 CpuType;
204 UINT32 CpuRev;
205 JUNO_REVISION JunoRevision;
206
207 JunoRevision = UNKNOWN;
208 Status = PciEmulationEntryPoint ();
209 if (EFI_ERROR (Status)) {
210 return Status;
211 }
212
213 //
214 // If a hypervisor has been declared then we need to make sure its region is protected at runtime
215 //
216 // Note: This code is only a workaround for our dummy hypervisor (ArmPkg/Extra/AArch64ToAArch32Shim/)
217 // that does not set up (yet) the stage 2 translation table to hide its own memory to EL1.
218 //
219 if (FixedPcdGet32 (PcdHypFvSize) != 0) {
220 // Ensure the hypervisor region is strictly contained into a EFI_PAGE_SIZE-aligned region.
221 // The memory must be a multiple of EFI_PAGE_SIZE to ensure we do not reserve more memory than the hypervisor itself.
222 // A UEFI Runtime region size granularity cannot be smaller than EFI_PAGE_SIZE. If the hypervisor size is not rounded
223 // to this size then there is a risk some non-runtime memory could be visible to the OS view.
224 if (((FixedPcdGet32 (PcdHypFvSize) & EFI_PAGE_MASK) == 0) && ((FixedPcdGet32 (PcdHypFvBaseAddress) & EFI_PAGE_MASK) == 0)) {
225 // The memory needs to be declared because the DXE core marked it as reserved and removed it from the memory space
226 // as it contains the Firmware.
227 Status = gDS->AddMemorySpace (
228 EfiGcdMemoryTypeSystemMemory,
229 FixedPcdGet32 (PcdHypFvBaseAddress), FixedPcdGet32 (PcdHypFvSize),
230 EFI_MEMORY_WB | EFI_MEMORY_RUNTIME
231 );
232 if (!EFI_ERROR (Status)) {
233 // We allocate the memory to ensure it is marked as runtime memory
234 HypBase = FixedPcdGet32 (PcdHypFvBaseAddress);
235 Status = gBS->AllocatePages (AllocateAddress, EfiRuntimeServicesCode,
236 EFI_SIZE_TO_PAGES (FixedPcdGet32 (PcdHypFvSize)), &HypBase);
237 }
238 } else {
239 // The hypervisor must be contained into a EFI_PAGE_SIZE-aligned region and its size must also be aligned
240 // on a EFI_PAGE_SIZE boundary (ie: 4KB).
241 Status = EFI_UNSUPPORTED;
242 ASSERT_EFI_ERROR (Status);
243 }
244
245 if (EFI_ERROR (Status)) {
246 return Status;
247 }
248 }
249
250 //
251 // Create an event belonging to the "gEfiEndOfDxeEventGroupGuid" group.
252 // The "OnEndOfDxe()" function is declared as the call back function.
253 // It will be called at the end of the DXE phase when an event of the
254 // same group is signalled to inform about the end of the DXE phase.
255 // Install the INSTALL_FDT_PROTOCOL protocol.
256 //
257 Status = gBS->CreateEventEx (
258 EVT_NOTIFY_SIGNAL,
259 TPL_CALLBACK,
260 OnEndOfDxe,
261 NULL,
262 &gEfiEndOfDxeEventGroupGuid,
263 &EndOfDxeEvent
264 );
265
266 // Install dynamic Shell command to run baremetal binaries.
267 Status = ShellDynCmdRunAxfInstall (ImageHandle);
268 if (EFI_ERROR (Status)) {
269 DEBUG ((EFI_D_ERROR, "ArmJunoDxe: Failed to install ShellDynCmdRunAxf\n"));
270 }
271
272 //
273 // We detect whether we are running on a Juno r0 or Juno r1 board at
274 // runtime by checking the value of the MIDR register.
275 //
276
277 Midr = ArmReadMidr ();
278 CpuType = (Midr >> ARM_CPU_TYPE_SHIFT) & ARM_CPU_TYPE_MASK;
279 CpuRev = Midr & ARM_CPU_REV_MASK;
280
281 switch (CpuType) {
282 case ARM_CPU_TYPE_A53:
283 if (CpuRev == ARM_CPU_REV (0, 0)) {
284 JunoRevision = JUNO_R0;
285 } else if (CpuRev == ARM_CPU_REV (0, 3)) {
286 JunoRevision = JUNO_R1;
287 }
288 break;
289
290 case ARM_CPU_TYPE_A57:
291 if (CpuRev == ARM_CPU_REV (0, 0)) {
292 JunoRevision = JUNO_R0;
293 } else if (CpuRev == ARM_CPU_REV (1, 1)) {
294 JunoRevision = JUNO_R1;
295 }
296 }
297
298 //
299 // Set the R1 two boot options if not already done.
300 //
301
302 if (JunoRevision == JUNO_R1) {
303 Status = SetJunoR1DefaultBootEntries ();
304 if (EFI_ERROR (Status)) {
305 return Status;
306 }
307 }
308
309 //
310 // Set up the device path to the FDT.
311 //
312 switch (JunoRevision) {
313 case JUNO_R0:
314 TextDevicePath = (CHAR16*)FixedPcdGetPtr (PcdJunoR0FdtDevicePath);
315 break;
316
317 case JUNO_R1:
318 TextDevicePath = (CHAR16*)FixedPcdGetPtr (PcdJunoR1A57x2FdtDevicePath);
319 break;
320
321 default:
322 TextDevicePath = NULL;
323 }
324
325 if (TextDevicePath != NULL) {
326 TextDevicePathSize = StrSize (TextDevicePath);
327 Buffer = PcdSetPtr (PcdFdtDevicePaths, &TextDevicePathSize, TextDevicePath);
328 Status = (Buffer != NULL) ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;
329 } else {
330 Status = EFI_NOT_FOUND;
331 }
332
333 if (EFI_ERROR (Status)) {
334 DEBUG (
335 (EFI_D_ERROR,
336 "ArmJunoDxe: Setting of FDT device path in PcdFdtDevicePaths failed - %r\n", Status)
337 );
338 return Status;
339 }
340
341 // Try to install the ACPI Tables
342 Status = LocateAndInstallAcpiFromFv (&mJunoAcpiTableFile);
343
344 return Status;
345 }
346
347 /**
348 * If no boot entry is currently defined, define the two default boot entries
349 * for Juno R1.
350 *
351 * @return EFI_SUCCESS Some boot entries were already defined or
352 * the default boot entries were set successfully.
353 * @return EFI_OUT_OF_RESOURCES A memory allocation failed.
354 * @return EFI_DEVICE_ERROR An UEFI variable could not be saved due to a hardware failure.
355 * @return EFI_WRITE_PROTECTED An UEFI variable is read-only.
356 * @return EFI_SECURITY_VIOLATION An UEFI variable could not be written.
357 */
358 STATIC
359 EFI_STATUS
360 SetJunoR1DefaultBootEntries (
361 VOID
362 )
363 {
364 EFI_STATUS Status;
365 CONST CHAR16* ExtraBootArgument = L" dtb=r1a57a53.dtb";
366 UINTN Size;
367 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol;
368 EFI_DEVICE_PATH* BootDevicePath;
369 UINT32 SysPciGbeL;
370 UINT32 SysPciGbeH;
371 CHAR16* DefaultBootArgument;
372 CHAR16* DefaultBootArgument1;
373 UINTN DefaultBootArgument1Size;
374 CHAR16* DefaultBootArgument2;
375 UINTN DefaultBootArgument2Size;
376 UINT16 BootOrder[2];
377
378 BootDevicePath = NULL;
379 DefaultBootArgument1 = NULL;
380 DefaultBootArgument2 = NULL;
381
382 //
383 // Because the driver has a dependency on gEfiVariable(Write)ArchProtocolGuid
384 // (see [Depex] section of the INF file), we know we can safely access the
385 // UEFI Variable at that stage.
386 //
387 Size = 0;
388 Status = gRT->GetVariable (L"BootOrder", &gEfiGlobalVariableGuid, NULL, &Size, NULL);
389 if (Status != EFI_NOT_FOUND) {
390 return EFI_SUCCESS;
391 }
392
393 Status = gBS->LocateProtocol (
394 &gEfiDevicePathFromTextProtocolGuid,
395 NULL,
396 (VOID **)&EfiDevicePathFromTextProtocol
397 );
398 if (EFI_ERROR (Status)) {
399 //
400 // You must provide an implementation of DevicePathFromTextProtocol
401 // in your firmware (eg: DevicePathDxe)
402 //
403 DEBUG ((EFI_D_ERROR, "Error: Require DevicePathFromTextProtocol\n"));
404 return Status;
405 }
406 //
407 // We use the same default kernel.
408 //
409 BootDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (
410 (CHAR16*)PcdGetPtr (PcdDefaultBootDevicePath)
411 );
412 if (BootDevicePath == NULL) {
413 return EFI_UNSUPPORTED;
414 }
415
416 DefaultBootArgument = (CHAR16*)PcdGetPtr (PcdDefaultBootArgument);
417 DefaultBootArgument1Size = StrSize (DefaultBootArgument) +
418 (SKY2_MAC_ADDRESS_BOOTARG_LEN * sizeof (CHAR16));
419 DefaultBootArgument2Size = DefaultBootArgument1Size + StrSize (ExtraBootArgument);
420
421 Status = EFI_OUT_OF_RESOURCES;
422 DefaultBootArgument1 = AllocatePool (DefaultBootArgument1Size);
423 if (DefaultBootArgument1 == NULL) {
424 goto Error;
425 }
426 DefaultBootArgument2 = AllocatePool (DefaultBootArgument2Size);
427 if (DefaultBootArgument2 == NULL) {
428 goto Error;
429 }
430
431 SysPciGbeL = MmioRead32 (ARM_JUNO_SYS_PCIGBE_L);
432 SysPciGbeH = MmioRead32 (ARM_JUNO_SYS_PCIGBE_H);
433
434 UnicodeSPrint (
435 DefaultBootArgument1,
436 DefaultBootArgument1Size,
437 L"%s sky2.mac_address=0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x",
438 DefaultBootArgument,
439 (SysPciGbeH >> 8 ) & 0xFF, (SysPciGbeH ) & 0xFF,
440 (SysPciGbeL >> 24) & 0xFF, (SysPciGbeL >> 16) & 0xFF,
441 (SysPciGbeL >> 8 ) & 0xFF, (SysPciGbeL ) & 0xFF
442 );
443
444 CopyMem (DefaultBootArgument2, DefaultBootArgument1, DefaultBootArgument1Size);
445 CopyMem (
446 (UINT8*)DefaultBootArgument2 + DefaultBootArgument1Size - sizeof (CHAR16),
447 ExtraBootArgument,
448 StrSize (ExtraBootArgument)
449 );
450
451 //
452 // Create Boot0001 environment variable
453 //
454 Status = BootOptionCreate (
455 L"Boot0001", LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT,
456 L"Linux with A57x2", BootDevicePath,
457 (UINT8*)DefaultBootArgument1, DefaultBootArgument1Size
458 );
459 if (EFI_ERROR (Status)) {
460 ASSERT_EFI_ERROR (Status);
461 goto Error;
462 }
463
464 //
465 // Create Boot0002 environment variable
466 //
467 Status = BootOptionCreate (
468 L"Boot0002", LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT,
469 L"Linux with A57x2_A53x4", BootDevicePath,
470 (UINT8*)DefaultBootArgument2, DefaultBootArgument2Size
471 );
472 if (EFI_ERROR (Status)) {
473 ASSERT_EFI_ERROR (Status);
474 goto Error;
475 }
476
477 //
478 // Add the new Boot Index to the list
479 //
480 BootOrder[0] = 1; // Boot0001
481 BootOrder[1] = 2; // Boot0002
482 Status = gRT->SetVariable (
483 L"BootOrder",
484 &gEfiGlobalVariableGuid,
485 EFI_VARIABLE_NON_VOLATILE |
486 EFI_VARIABLE_BOOTSERVICE_ACCESS |
487 EFI_VARIABLE_RUNTIME_ACCESS,
488 sizeof (BootOrder),
489 BootOrder
490 );
491
492 Error:
493 if (BootDevicePath != NULL) {
494 FreePool (BootDevicePath);
495 }
496 if (DefaultBootArgument1 != NULL) {
497 FreePool (DefaultBootArgument1);
498 }
499 if (DefaultBootArgument2 != NULL) {
500 FreePool (DefaultBootArgument2);
501 }
502
503 if (EFI_ERROR (Status)) {
504 DEBUG ((
505 EFI_D_ERROR,
506 "ArmJunoDxe - The setting of the default boot entries failed - %r\n",
507 Status
508 ));
509 }
510
511 return Status;
512 }