]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.c
47ff5871e30f869aaad69b3c7c1b47adec84a8da
[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 <IndustryStandard/Pci.h>
19 #include <Protocol/DevicePathFromText.h>
20 #include <Protocol/PciIo.h>
21 #include <Protocol/PciRootBridgeIo.h>
22
23 #include <Guid/EventGroup.h>
24 #include <Guid/GlobalVariable.h>
25
26 #include <Library/ArmShellCmdLib.h>
27 #include <Library/AcpiLib.h>
28 #include <Library/BaseMemoryLib.h>
29 #include <Library/DevicePathLib.h>
30 #include <Library/MemoryAllocationLib.h>
31 #include <Library/UefiRuntimeServicesTableLib.h>
32 #include <Library/IoLib.h>
33 #include <Library/PrintLib.h>
34
35
36 // This GUID must match the FILE_GUID in ArmPlatformPkg/ArmJunoPkg/AcpiTables/AcpiTables.inf
37 STATIC CONST EFI_GUID mJunoAcpiTableFile = { 0xa1dd808e, 0x1e95, 0x4399, { 0xab, 0xc0, 0x65, 0x3c, 0x82, 0xe8, 0x53, 0x0c } };
38
39 typedef struct {
40 ACPI_HID_DEVICE_PATH AcpiDevicePath;
41 PCI_DEVICE_PATH PciDevicePath;
42 EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
43 } EFI_PCI_ROOT_BRIDGE_DEVICE_PATH;
44
45 STATIC CONST EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mPciRootComplexDevicePath = {
46 {
47 { ACPI_DEVICE_PATH,
48 ACPI_DP,
49 { (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)),
50 (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8) }
51 },
52 EISA_PNP_ID (0x0A03),
53 0
54 },
55 {
56 { HARDWARE_DEVICE_PATH,
57 HW_PCI_DP,
58 { (UINT8) (sizeof (PCI_DEVICE_PATH)),
59 (UINT8) ((sizeof (PCI_DEVICE_PATH)) >> 8) }
60 },
61 0,
62 0
63 },
64 {
65 END_DEVICE_PATH_TYPE,
66 END_ENTIRE_DEVICE_PATH_SUBTYPE,
67 { END_DEVICE_PATH_LENGTH, 0 }
68 }
69 };
70
71 EFI_EVENT mAcpiRegistration = NULL;
72
73 /**
74 This function reads PCI ID of the controller.
75
76 @param[in] PciIo PCI IO protocol handle
77 @param[in] PciId Looking for specified PCI ID Vendor/Device
78 **/
79 STATIC
80 EFI_STATUS
81 ReadMarvellYoukonPciId (
82 IN EFI_PCI_IO_PROTOCOL *PciIo,
83 IN UINT32 PciId
84 )
85 {
86 UINT32 DevicePciId;
87 EFI_STATUS Status;
88
89 Status = PciIo->Pci.Read (
90 PciIo,
91 EfiPciIoWidthUint32,
92 PCI_VENDOR_ID_OFFSET,
93 1,
94 &DevicePciId);
95 if (EFI_ERROR (Status)) {
96 return Status;
97 }
98
99 if (DevicePciId != PciId) {
100 return EFI_NOT_FOUND;
101 }
102
103 return EFI_SUCCESS;
104 }
105
106 /**
107 This function searches for Marvell Yukon NIC on the Juno
108 platform and returns PCI IO protocol handle for the controller.
109
110 @param[out] PciIo PCI IO protocol handle
111 **/
112 STATIC
113 EFI_STATUS
114 GetMarvellYukonPciIoProtocol (
115 OUT EFI_PCI_IO_PROTOCOL **PciIo
116 )
117 {
118 UINTN HandleCount;
119 EFI_HANDLE *HandleBuffer;
120 UINTN HIndex;
121 EFI_STATUS Status;
122
123 Status = gBS->LocateHandleBuffer (
124 ByProtocol,
125 &gEfiPciIoProtocolGuid,
126 NULL,
127 &HandleCount,
128 &HandleBuffer);
129 if (EFI_ERROR (Status)) {
130 return (Status);
131 }
132
133 for (HIndex = 0; HIndex < HandleCount; ++HIndex) {
134 // If PciIo opened with EFI_OPEN_PROTOCOL_GET_PROTOCOL, the CloseProtocol() is not required
135 Status = gBS->OpenProtocol (
136 HandleBuffer[HIndex],
137 &gEfiPciIoProtocolGuid,
138 (VOID **) PciIo,
139 NULL,
140 NULL,
141 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
142 if (EFI_ERROR (Status)) {
143 continue;
144 }
145
146 Status = ReadMarvellYoukonPciId (*PciIo, JUNO_MARVELL_YUKON_ID);
147 if (EFI_ERROR (Status)) {
148 continue;
149 } else {
150 break;
151 }
152 }
153
154 gBS->FreePool (HandleBuffer);
155
156 return Status;
157 }
158
159 /**
160 This function restore the original controller attributes
161
162 @param[in] PciIo PCI IO protocol handle
163 @param[in] PciAttr PCI controller attributes.
164 @param[in] AcpiResDescriptor ACPI 2.0 resource descriptors for the BAR
165 **/
166 STATIC
167 VOID
168 RestorePciDev (
169 IN EFI_PCI_IO_PROTOCOL *PciIo,
170 IN UINT64 PciAttr
171 )
172 {
173 PciIo->Attributes (
174 PciIo,
175 EfiPciIoAttributeOperationSet,
176 PciAttr,
177 NULL
178 );
179 }
180
181 /**
182 This function returns PCI MMIO base address for a controller
183
184 @param[in] PciIo PCI IO protocol handle
185 @param[out] PciRegBase PCI base MMIO address
186 **/
187 STATIC
188 EFI_STATUS
189 BarIsDeviceMemory (
190 IN EFI_PCI_IO_PROTOCOL *PciIo,
191 OUT UINT32 *PciRegBase
192 )
193 {
194 EFI_STATUS Status;
195 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AcpiResDescriptor;
196 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AcpiCurrentDescriptor;
197
198 // Marvell Yukon's Bar0 provides base memory address for control registers
199 Status = PciIo->GetBarAttributes (PciIo, PCI_BAR_IDX0, NULL, (VOID**)&AcpiResDescriptor);
200 if (EFI_ERROR (Status)) {
201 return Status;
202 }
203
204 AcpiCurrentDescriptor = AcpiResDescriptor;
205
206 // Search for a memory type descriptor
207 while (AcpiCurrentDescriptor->Desc != ACPI_END_TAG_DESCRIPTOR) {
208
209 // Check if Bar is memory type one and fetch a base address
210 if (AcpiCurrentDescriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR &&
211 AcpiCurrentDescriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM &&
212 !(AcpiCurrentDescriptor->SpecificFlag & ACPI_SPECFLAG_PREFETCHABLE)) {
213 *PciRegBase = AcpiCurrentDescriptor->AddrRangeMin;
214 break;
215 } else {
216 Status = EFI_UNSUPPORTED;
217 }
218
219 AcpiCurrentDescriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) (AcpiCurrentDescriptor + 1);
220 }
221
222 gBS->FreePool (AcpiResDescriptor);
223
224 return Status;
225 }
226
227 /**
228 This function provides PCI MMIO base address, old PCI controller attributes.
229
230 @param[in] PciIo PCI IO protocol handle
231 @param[out] PciRegBase PCI base MMIO address
232 @param[out] OldPciAttr Old PCI controller attributes.
233 **/
234 STATIC
235 EFI_STATUS
236 InitPciDev (
237 IN EFI_PCI_IO_PROTOCOL *PciIo,
238 OUT UINT32 *PciRegBase,
239 OUT UINT64 *OldPciAttr
240 )
241 {
242 UINT64 AttrSupports;
243 EFI_STATUS Status;
244
245 // Get controller's current attributes
246 Status = PciIo->Attributes (
247 PciIo,
248 EfiPciIoAttributeOperationGet,
249 0,
250 OldPciAttr);
251 if (EFI_ERROR (Status)) {
252 return Status;
253 }
254
255 // Fetch supported attributes
256 Status = PciIo->Attributes (
257 PciIo,
258 EfiPciIoAttributeOperationSupported,
259 0,
260 &AttrSupports);
261 if (EFI_ERROR (Status)) {
262 return Status;
263 }
264
265 // Enable EFI_PCI_IO_ATTRIBUTE_IO, EFI_PCI_IO_ATTRIBUTE_MEMORY and
266 // EFI_PCI_IO_ATTRIBUTE_BUS_MASTER bits in the PCI Config Header
267 AttrSupports &= EFI_PCI_DEVICE_ENABLE;
268 Status = PciIo->Attributes (
269 PciIo,
270 EfiPciIoAttributeOperationEnable,
271 AttrSupports,
272 NULL);
273 if (EFI_ERROR (Status)) {
274 return Status;
275 }
276
277 Status = BarIsDeviceMemory (PciIo, PciRegBase);
278 if (EFI_ERROR (Status)) {
279 RestorePciDev (PciIo, *OldPciAttr);
280 }
281
282 return Status;
283 }
284
285 /**
286 This function reads MAC address from IOFPGA and writes it to Marvell Yukon NIC
287
288 @param[in] PciRegBase PCI base MMIO address
289 **/
290 STATIC
291 EFI_STATUS
292 WriteMacAddress (
293 IN UINT32 PciRegBase
294 )
295 {
296 UINT32 MacHigh;
297 UINT32 MacLow;
298
299 // Read MAC address from IOFPGA
300 MacHigh= MmioRead32 (ARM_JUNO_SYS_PCIGBE_H);
301 MacLow = MmioRead32 (ARM_JUNO_SYS_PCIGBE_L);
302
303 // Set software reset control register to protect from deactivation
304 // the config write state
305 MmioWrite16 (PciRegBase + R_CONTROL_STATUS, CS_RESET_CLR);
306
307 // Convert to Marvell MAC Address register format
308 MacHigh = SwapBytes32 ((MacHigh & 0xFFFF) << 16 |
309 (MacLow & 0xFFFF0000) >> 16);
310 MacLow = SwapBytes32 (MacLow) >> 16;
311
312 // Set MAC Address
313 MmioWrite8 (PciRegBase + R_TST_CTRL_1, TST_CFG_WRITE_ENABLE);
314 MmioWrite32 (PciRegBase + R_MAC, MacHigh);
315 MmioWrite32 (PciRegBase + R_MAC_MAINT, MacHigh);
316 MmioWrite32 (PciRegBase + R_MAC + R_MAC_LOW, MacLow);
317 MmioWrite32 (PciRegBase + R_MAC_MAINT + R_MAC_LOW, MacLow);
318 MmioWrite8 (PciRegBase + R_TST_CTRL_1, TST_CFG_WRITE_DISABLE);
319
320 // Initiate device reset
321 MmioWrite16 (PciRegBase + R_CONTROL_STATUS, CS_RESET_SET);
322 MmioWrite16 (PciRegBase + R_CONTROL_STATUS, CS_RESET_CLR);
323
324 return EFI_SUCCESS;
325 }
326
327 /**
328 The function reads MAC address from Juno IOFPGA registers and writes it
329 into Marvell Yukon NIC.
330 **/
331 STATIC
332 EFI_STATUS
333 ArmJunoSetNicMacAddress ()
334 {
335 UINT64 OldPciAttr;
336 EFI_PCI_IO_PROTOCOL* PciIo;
337 UINT32 PciRegBase;
338 EFI_STATUS Status;
339
340 Status = GetMarvellYukonPciIoProtocol (&PciIo);
341 if (EFI_ERROR (Status)) {
342 return Status;
343 }
344
345 Status = InitPciDev (PciIo, &PciRegBase, &OldPciAttr);
346 if (EFI_ERROR (Status)) {
347 return Status;
348 }
349
350 Status = WriteMacAddress (PciRegBase);
351
352 RestorePciDev (PciIo, OldPciAttr);
353
354 return EFI_SUCCESS;
355 }
356
357 /**
358 Notification function of the event defined as belonging to the
359 EFI_END_OF_DXE_EVENT_GROUP_GUID event group that was created in
360 the entry point of the driver.
361
362 This function is called when an event belonging to the
363 EFI_END_OF_DXE_EVENT_GROUP_GUID event group is signalled. Such an
364 event is signalled once at the end of the dispatching of all
365 drivers (end of the so called DXE phase).
366
367 @param[in] Event Event declared in the entry point of the driver whose
368 notification function is being invoked.
369 @param[in] Context NULL
370 **/
371 STATIC
372 VOID
373 OnEndOfDxe (
374 IN EFI_EVENT Event,
375 IN VOID *Context
376 )
377 {
378 EFI_DEVICE_PATH_PROTOCOL* PciRootComplexDevicePath;
379 EFI_HANDLE Handle;
380 EFI_STATUS Status;
381
382 //
383 // PCI Root Complex initialization
384 // At the end of the DXE phase, we should get all the driver dispatched.
385 // Force the PCI Root Complex to be initialized. It allows the OS to skip
386 // this step.
387 //
388 PciRootComplexDevicePath = (EFI_DEVICE_PATH_PROTOCOL*) &mPciRootComplexDevicePath;
389 Status = gBS->LocateDevicePath (&gEfiPciRootBridgeIoProtocolGuid,
390 &PciRootComplexDevicePath,
391 &Handle);
392
393 Status = gBS->ConnectController (Handle, NULL, PciRootComplexDevicePath, FALSE);
394 ASSERT_EFI_ERROR (Status);
395
396 Status = ArmJunoSetNicMacAddress ();
397 ASSERT_EFI_ERROR (Status);
398 }
399
400 STATIC
401 BOOLEAN
402 AcpiTableJunoR0Check (
403 IN EFI_ACPI_DESCRIPTION_HEADER *AcpiHeader
404 )
405 {
406 return TRUE;
407 }
408
409 STATIC
410 BOOLEAN
411 AcpiTableJunoR1Check (
412 IN EFI_ACPI_DESCRIPTION_HEADER *AcpiHeader
413 )
414 {
415 return TRUE;
416 }
417
418 STATIC
419 BOOLEAN
420 AcpiTableJunoR2Check (
421 IN EFI_ACPI_DESCRIPTION_HEADER *AcpiHeader
422 )
423 {
424 return TRUE;
425 }
426
427
428 EFI_STATUS
429 EFIAPI
430 ArmJunoEntryPoint (
431 IN EFI_HANDLE ImageHandle,
432 IN EFI_SYSTEM_TABLE *SystemTable
433 )
434 {
435 EFI_STATUS Status;
436 EFI_PHYSICAL_ADDRESS HypBase;
437 CHAR16 *TextDevicePath;
438 UINTN TextDevicePathSize;
439 VOID *Buffer;
440 UINT32 JunoRevision;
441 EFI_EVENT EndOfDxeEvent;
442
443 Status = PciEmulationEntryPoint ();
444 if (EFI_ERROR (Status)) {
445 return Status;
446 }
447
448 //
449 // If a hypervisor has been declared then we need to make sure its region is protected at runtime
450 //
451 // Note: This code is only a workaround for our dummy hypervisor (ArmPkg/Extra/AArch64ToAArch32Shim/)
452 // that does not set up (yet) the stage 2 translation table to hide its own memory to EL1.
453 //
454 if (FixedPcdGet32 (PcdHypFvSize) != 0) {
455 // Ensure the hypervisor region is strictly contained into a EFI_PAGE_SIZE-aligned region.
456 // The memory must be a multiple of EFI_PAGE_SIZE to ensure we do not reserve more memory than the hypervisor itself.
457 // A UEFI Runtime region size granularity cannot be smaller than EFI_PAGE_SIZE. If the hypervisor size is not rounded
458 // to this size then there is a risk some non-runtime memory could be visible to the OS view.
459 if (((FixedPcdGet32 (PcdHypFvSize) & EFI_PAGE_MASK) == 0) && ((FixedPcdGet32 (PcdHypFvBaseAddress) & EFI_PAGE_MASK) == 0)) {
460 // The memory needs to be declared because the DXE core marked it as reserved and removed it from the memory space
461 // as it contains the Firmware.
462 Status = gDS->AddMemorySpace (
463 EfiGcdMemoryTypeSystemMemory,
464 FixedPcdGet32 (PcdHypFvBaseAddress), FixedPcdGet32 (PcdHypFvSize),
465 EFI_MEMORY_WB | EFI_MEMORY_RUNTIME
466 );
467 if (!EFI_ERROR (Status)) {
468 // We allocate the memory to ensure it is marked as runtime memory
469 HypBase = FixedPcdGet32 (PcdHypFvBaseAddress);
470 Status = gBS->AllocatePages (AllocateAddress, EfiRuntimeServicesCode,
471 EFI_SIZE_TO_PAGES (FixedPcdGet32 (PcdHypFvSize)), &HypBase);
472 }
473 } else {
474 // The hypervisor must be contained into a EFI_PAGE_SIZE-aligned region and its size must also be aligned
475 // on a EFI_PAGE_SIZE boundary (ie: 4KB).
476 Status = EFI_UNSUPPORTED;
477 ASSERT_EFI_ERROR (Status);
478 }
479
480 if (EFI_ERROR (Status)) {
481 return Status;
482 }
483 }
484
485 //
486 // Create an event belonging to the "gEfiEndOfDxeEventGroupGuid" group.
487 // The "OnEndOfDxe()" function is declared as the call back function.
488 // It will be called at the end of the DXE phase when an event of the
489 // same group is signalled to inform about the end of the DXE phase.
490 // Install the INSTALL_FDT_PROTOCOL protocol.
491 //
492 Status = gBS->CreateEventEx (
493 EVT_NOTIFY_SIGNAL,
494 TPL_CALLBACK,
495 OnEndOfDxe,
496 NULL,
497 &gEfiEndOfDxeEventGroupGuid,
498 &EndOfDxeEvent
499 );
500
501 // Install dynamic Shell command to run baremetal binaries.
502 Status = ShellDynCmdRunAxfInstall (ImageHandle);
503 if (EFI_ERROR (Status)) {
504 DEBUG ((EFI_D_ERROR, "ArmJunoDxe: Failed to install ShellDynCmdRunAxf\n"));
505 }
506
507 GetJunoRevision(JunoRevision);
508
509 //
510 // Try to install the ACPI Tables
511 //
512 if (JunoRevision == JUNO_REVISION_R0) {
513 Status = LocateAndInstallAcpiFromFvConditional (&mJunoAcpiTableFile, AcpiTableJunoR0Check);
514 } else if (JunoRevision == JUNO_REVISION_R1) {
515 Status = LocateAndInstallAcpiFromFvConditional (&mJunoAcpiTableFile, AcpiTableJunoR1Check);
516 } else if (JunoRevision == JUNO_REVISION_R2) {
517 Status = LocateAndInstallAcpiFromFvConditional (&mJunoAcpiTableFile, AcpiTableJunoR2Check);
518 }
519
520 ASSERT_EFI_ERROR (Status);
521
522 //
523 // Setup R1/R2 options if not already done.
524 //
525 if (JunoRevision != JUNO_REVISION_R0) {
526 // Enable PCI enumeration
527 PcdSetBool (PcdPciDisableBusEnumeration, FALSE);
528
529 // Declare the related ACPI Tables
530 EfiCreateProtocolNotifyEvent (
531 &gEfiAcpiTableProtocolGuid,
532 TPL_CALLBACK,
533 AcpiPciNotificationEvent,
534 NULL,
535 &mAcpiRegistration
536 );
537 }
538
539 //
540 // Set up the device path to the FDT.
541 //
542 TextDevicePath = (CHAR16*)FixedPcdGetPtr (PcdJunoFdtDevicePath);
543 if (TextDevicePath != NULL) {
544 TextDevicePathSize = StrSize (TextDevicePath);
545 Buffer = PcdSetPtr (PcdFdtDevicePaths, &TextDevicePathSize, TextDevicePath);
546 Status = (Buffer != NULL) ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;
547 } else {
548 Status = EFI_NOT_FOUND;
549 }
550
551 if (EFI_ERROR (Status)) {
552 DEBUG (
553 (EFI_D_ERROR,
554 "ArmJunoDxe: Setting of FDT device path in PcdFdtDevicePaths failed - %r\n", Status)
555 );
556 return Status;
557 }
558
559 return Status;
560 }