3 * Copyright (c) 2011-2014, ARM Limited. All rights reserved.
4 * Copyright (c) 2014-2020, Linaro Limited. All rights reserved.
6 * SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include <Library/MemoryAllocationLib.h>
13 #include <Library/DebugLib.h>
14 #include <Library/HobLib.h>
15 #include <Library/PcdLib.h>
16 #include <Library/PeiServicesLib.h>
19 #include <Guid/EarlyPL011BaseAddress.h>
20 #include <Guid/FdtHob.h>
22 STATIC CONST EFI_PEI_PPI_DESCRIPTOR mTpm2DiscoveredPpi
= {
23 EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
,
24 &gOvmfTpmDiscoveredPpiGuid
,
28 STATIC CONST EFI_PEI_PPI_DESCRIPTOR mTpm2InitializationDonePpi
= {
29 EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
,
30 &gPeiTpmInitializationDonePpiGuid
,
48 CONST CHAR8
*Compatible
;
49 CONST CHAR8
*CompItem
;
50 CONST CHAR8
*NodeStatus
;
54 CONST UINT64
*RegProp
;
55 CONST UINT32
*RangesProp
;
60 Base
= (VOID
*)(UINTN
)PcdGet64 (PcdDeviceTreeInitialBaseAddress
);
61 ASSERT (Base
!= NULL
);
62 ASSERT (fdt_check_header (Base
) == 0);
64 FdtSize
= fdt_totalsize (Base
) + PcdGet32 (PcdDeviceTreeAllocationPadding
);
65 FdtPages
= EFI_SIZE_TO_PAGES (FdtSize
);
66 NewBase
= AllocatePages (FdtPages
);
67 ASSERT (NewBase
!= NULL
);
68 fdt_open_into (Base
, NewBase
, EFI_PAGES_TO_SIZE (FdtPages
));
70 FdtHobData
= BuildGuidHob (&gFdtHobGuid
, sizeof *FdtHobData
);
71 ASSERT (FdtHobData
!= NULL
);
72 *FdtHobData
= (UINTN
)NewBase
;
74 UartHobData
= BuildGuidHob (&gEarlyPL011BaseAddressGuid
, sizeof *UartHobData
);
75 ASSERT (UartHobData
!= NULL
);
80 for (Prev
= Depth
= 0;; Prev
= Node
) {
81 Node
= fdt_next_node (Base
, Prev
, &Depth
);
90 Compatible
= fdt_getprop (Base
, Node
, "compatible", &Len
);
93 // Iterate over the NULL-separated items in the compatible string
95 for (CompItem
= Compatible
; CompItem
!= NULL
&& CompItem
< Compatible
+ Len
;
96 CompItem
+= 1 + AsciiStrLen (CompItem
)) {
98 if (AsciiStrCmp (CompItem
, "arm,pl011") == 0) {
99 NodeStatus
= fdt_getprop (Base
, Node
, "status", &StatusLen
);
100 if (NodeStatus
!= NULL
&& AsciiStrCmp (NodeStatus
, "okay") != 0) {
104 RegProp
= fdt_getprop (Base
, Node
, "reg", &Len
);
107 UartBase
= fdt64_to_cpu (ReadUnaligned64 (RegProp
));
109 DEBUG ((EFI_D_INFO
, "%a: PL011 UART @ 0x%lx\n", __FUNCTION__
, UartBase
));
111 *UartHobData
= UartBase
;
113 } else if (FeaturePcdGet (PcdTpm2SupportEnabled
) &&
114 AsciiStrCmp (CompItem
, "tcg,tpm-tis-mmio") == 0) {
116 RegProp
= fdt_getprop (Base
, Node
, "reg", &Len
);
117 ASSERT (Len
== 8 || Len
== 16);
119 TpmBase
= fdt32_to_cpu (RegProp
[0]);
120 } else if (Len
== 16) {
121 TpmBase
= fdt64_to_cpu (ReadUnaligned64 ((UINT64
*)RegProp
));
126 // QEMU/mach-virt may put the TPM on the platform bus, in which case
127 // we have to take its 'ranges' property into account to translate the
128 // MMIO address. This consists of a <child base, parent base, size>
129 // tuple, where the child base and the size use the same number of
130 // cells as the 'reg' property above, and the parent base uses 2 cells
132 RangesProp
= fdt_getprop (Base
, Parent
, "ranges", &RangesLen
);
133 ASSERT (RangesProp
!= NULL
);
136 // a plain 'ranges' attribute without a value implies a 1:1 mapping
138 if (RangesLen
!= 0) {
140 // assume a single translated range with 2 cells for the parent base
142 if (RangesLen
!= Len
+ 2 * sizeof (UINT32
)) {
144 "%a: 'ranges' property has unexpected size %d\n",
145 __FUNCTION__
, RangesLen
));
150 TpmBase
-= fdt32_to_cpu (RangesProp
[0]);
152 TpmBase
-= fdt64_to_cpu (ReadUnaligned64 ((UINT64
*)RangesProp
));
156 // advance RangesProp to the parent bus address
158 RangesProp
= (UINT32
*)((UINT8
*)RangesProp
+ Len
/ 2);
159 TpmBase
+= fdt64_to_cpu (ReadUnaligned64 ((UINT64
*)RangesProp
));
167 if (FeaturePcdGet (PcdTpm2SupportEnabled
)) {
169 DEBUG ((DEBUG_INFO
, "%a: TPM @ 0x%lx\n", __FUNCTION__
, TpmBase
));
171 Status
= (EFI_STATUS
)PcdSet64S (PcdTpmBaseAddress
, TpmBase
);
172 ASSERT_EFI_ERROR (Status
);
174 Status
= PeiServicesInstallPpi (&mTpm2DiscoveredPpi
);
176 Status
= PeiServicesInstallPpi (&mTpm2InitializationDonePpi
);
178 ASSERT_EFI_ERROR (Status
);
181 BuildFvHob (PcdGet64 (PcdFvBaseAddress
), PcdGet32 (PcdFvSize
));