ArmGicCParser.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903
  1. /** @file
  2. Arm Gic cpu parser.
  3. Copyright (c) 2021 - 2022, Arm Limited. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. @par Reference(s):
  6. - linux/Documentation/devicetree/bindings/arm/cpus.yaml
  7. - linux/Documentation/devicetree/bindings/interrupt-controller/arm,gic.yaml
  8. - linux/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
  9. - linux/Documentation/devicetree/bindings/arm/pmu.yaml
  10. **/
  11. #include "FdtHwInfoParser.h"
  12. #include "CmObjectDescUtility.h"
  13. #include "Gic/ArmGicCParser.h"
  14. #include "Gic/ArmGicDispatcher.h"
  15. /** List of "compatible" property values for CPU nodes.
  16. Any other "compatible" value is not supported by this module.
  17. */
  18. STATIC CONST COMPATIBILITY_STR CpuCompatibleStr[] = {
  19. { "arm,arm-v7" },
  20. { "arm,arm-v8" },
  21. { "arm,armv8" },
  22. { "arm,cortex-a15" },
  23. { "arm,cortex-a7" },
  24. { "arm,cortex-a57" }
  25. };
  26. /** COMPATIBILITY_INFO structure for CPU nodes.
  27. */
  28. STATIC CONST COMPATIBILITY_INFO CpuCompatibleInfo = {
  29. ARRAY_SIZE (CpuCompatibleStr),
  30. CpuCompatibleStr
  31. };
  32. /** Pmu compatible strings.
  33. Any other "compatible" value is not supported by this module.
  34. */
  35. STATIC CONST COMPATIBILITY_STR PmuCompatibleStr[] = {
  36. { "arm,armv8-pmuv3" }
  37. };
  38. /** COMPATIBILITY_INFO structure for the PmuCompatibleStr.
  39. */
  40. CONST COMPATIBILITY_INFO PmuCompatibleInfo = {
  41. ARRAY_SIZE (PmuCompatibleStr),
  42. PmuCompatibleStr
  43. };
  44. /** Parse a "cpu" node.
  45. @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
  46. @param [in] CpuNode Offset of a cpu node.
  47. @param [in] GicVersion Version of the GIC.
  48. @param [in] AddressCells Number of address cells used for the reg
  49. property.
  50. @param [out] GicCInfo CM_ARM_GICC_INFO structure to populate.
  51. @retval EFI_SUCCESS The function completed successfully.
  52. @retval EFI_ABORTED An error occurred.
  53. @retval EFI_INVALID_PARAMETER Invalid parameter.
  54. @retval EFI_UNSUPPORTED Unsupported.
  55. **/
  56. STATIC
  57. EFI_STATUS
  58. EFIAPI
  59. CpuNodeParser (
  60. IN CONST VOID *Fdt,
  61. IN INT32 CpuNode,
  62. IN UINT32 GicVersion,
  63. IN UINT32 AddressCells,
  64. OUT CM_ARM_GICC_INFO *GicCInfo
  65. )
  66. {
  67. CONST UINT8 *Data;
  68. INT32 DataSize;
  69. UINT32 ProcUid;
  70. UINT64 MpIdr;
  71. UINT64 CheckAffMask;
  72. MpIdr = 0;
  73. CheckAffMask = ARM_CORE_AFF0 | ARM_CORE_AFF1 | ARM_CORE_AFF2;
  74. if (GicCInfo == NULL) {
  75. ASSERT (0);
  76. return EFI_INVALID_PARAMETER;
  77. }
  78. Data = fdt_getprop (Fdt, CpuNode, "reg", &DataSize);
  79. if ((Data == NULL) ||
  80. ((DataSize != sizeof (UINT32)) &&
  81. (DataSize != sizeof (UINT64))))
  82. {
  83. ASSERT (0);
  84. return EFI_ABORTED;
  85. }
  86. /* If cpus node's #address-cells property is set to 2
  87. The first reg cell bits [7:0] must be set to
  88. bits [39:32] of MPIDR_EL1.
  89. The second reg cell bits [23:0] must be set to
  90. bits [23:0] of MPIDR_EL1.
  91. */
  92. if (AddressCells == 2) {
  93. MpIdr = fdt64_to_cpu (*((UINT64 *)Data));
  94. CheckAffMask |= ARM_CORE_AFF3;
  95. } else {
  96. MpIdr = fdt32_to_cpu (*((UINT32 *)Data));
  97. }
  98. if ((MpIdr & ~CheckAffMask) != 0) {
  99. ASSERT (0);
  100. return EFI_INVALID_PARAMETER;
  101. }
  102. // To fit the Affinity [0-3] a 32bits value, place the Aff3 on bits
  103. // [31:24] instead of their original place ([39:32]).
  104. ProcUid = MpIdr | ((MpIdr & ARM_CORE_AFF3) >> 8);
  105. /* ACPI 6.3, s5.2.12.14 GIC CPU Interface (GICC) Structure:
  106. GIC 's CPU Interface Number. In GICv1/v2 implementations,
  107. this value matches the bit index of the associated processor
  108. in the GIC distributor's GICD_ITARGETSR register. For
  109. GICv3/4 implementations this field must be provided by the
  110. platform, if compatibility mode is supported. If it is not supported
  111. by the implementation, then this field must be zero.
  112. Note: We do not support compatibility mode for GicV3
  113. */
  114. if (GicVersion == 2) {
  115. GicCInfo->CPUInterfaceNumber = ProcUid;
  116. } else {
  117. GicCInfo->CPUInterfaceNumber = 0;
  118. }
  119. GicCInfo->AcpiProcessorUid = ProcUid;
  120. GicCInfo->Flags = EFI_ACPI_6_3_GIC_ENABLED;
  121. GicCInfo->MPIDR = MpIdr;
  122. return EFI_SUCCESS;
  123. }
  124. /** Parse a "cpus" node and its children "cpu" nodes.
  125. Create as many CM_ARM_GICC_INFO structures as "cpu" nodes.
  126. @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
  127. @param [in] CpusNode Offset of a cpus node.
  128. @param [in] GicVersion Version of the GIC.
  129. @param [out] NewGicCmObjDesc If success, CM_OBJ_DESCRIPTOR containing
  130. all the created CM_ARM_GICC_INFO.
  131. @retval EFI_SUCCESS The function completed successfully.
  132. @retval EFI_ABORTED An error occurred.
  133. @retval EFI_INVALID_PARAMETER Invalid parameter.
  134. @retval EFI_UNSUPPORTED Unsupported.
  135. **/
  136. STATIC
  137. EFI_STATUS
  138. EFIAPI
  139. CpusNodeParser (
  140. IN CONST VOID *Fdt,
  141. IN INT32 CpusNode,
  142. IN UINT32 GicVersion,
  143. OUT CM_OBJ_DESCRIPTOR **NewGicCmObjDesc
  144. )
  145. {
  146. EFI_STATUS Status;
  147. INT32 CpuNode;
  148. UINT32 CpuNodeCount;
  149. INT32 AddressCells;
  150. UINT32 Index;
  151. CM_ARM_GICC_INFO *GicCInfoBuffer;
  152. UINT32 GicCInfoBufferSize;
  153. if (NewGicCmObjDesc == NULL) {
  154. ASSERT (0);
  155. return EFI_INVALID_PARAMETER;
  156. }
  157. AddressCells = fdt_address_cells (Fdt, CpusNode);
  158. if (AddressCells < 0) {
  159. ASSERT (0);
  160. return EFI_ABORTED;
  161. }
  162. // Count the number of "cpu" nodes under the "cpus" node.
  163. Status = FdtCountNamedNodeInBranch (Fdt, CpusNode, "cpu", &CpuNodeCount);
  164. if (EFI_ERROR (Status)) {
  165. ASSERT (0);
  166. return Status;
  167. }
  168. if (CpuNodeCount == 0) {
  169. ASSERT (0);
  170. return EFI_NOT_FOUND;
  171. }
  172. // Allocate memory for CpuNodeCount CM_ARM_GICC_INFO structures.
  173. GicCInfoBufferSize = CpuNodeCount * sizeof (CM_ARM_GICC_INFO);
  174. GicCInfoBuffer = AllocateZeroPool (GicCInfoBufferSize);
  175. if (GicCInfoBuffer == NULL) {
  176. ASSERT (0);
  177. return EFI_OUT_OF_RESOURCES;
  178. }
  179. CpuNode = CpusNode;
  180. for (Index = 0; Index < CpuNodeCount; Index++) {
  181. Status = FdtGetNextNamedNodeInBranch (Fdt, CpusNode, "cpu", &CpuNode);
  182. if (EFI_ERROR (Status)) {
  183. ASSERT (0);
  184. if (Status == EFI_NOT_FOUND) {
  185. // Should have found the node.
  186. Status = EFI_ABORTED;
  187. }
  188. goto exit_handler;
  189. }
  190. // Parse the "cpu" node.
  191. if (!FdtNodeIsCompatible (Fdt, CpuNode, &CpuCompatibleInfo)) {
  192. ASSERT (0);
  193. Status = EFI_UNSUPPORTED;
  194. goto exit_handler;
  195. }
  196. Status = CpuNodeParser (
  197. Fdt,
  198. CpuNode,
  199. GicVersion,
  200. AddressCells,
  201. &GicCInfoBuffer[Index]
  202. );
  203. if (EFI_ERROR (Status)) {
  204. ASSERT (0);
  205. goto exit_handler;
  206. }
  207. } // for
  208. Status = CreateCmObjDesc (
  209. CREATE_CM_ARM_OBJECT_ID (EArmObjGicCInfo),
  210. CpuNodeCount,
  211. GicCInfoBuffer,
  212. GicCInfoBufferSize,
  213. NewGicCmObjDesc
  214. );
  215. ASSERT_EFI_ERROR (Status);
  216. exit_handler:
  217. FreePool (GicCInfoBuffer);
  218. return Status;
  219. }
  220. /** Parse a Gic compatible interrupt-controller node,
  221. extracting GicC information generic to Gic v2 and v3.
  222. This function modifies a CM_OBJ_DESCRIPTOR object.
  223. The following CM_ARM_GICC_INFO fields are patched:
  224. - VGICMaintenanceInterrupt;
  225. - Flags;
  226. @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
  227. @param [in] GicIntcNode Offset of a Gic compatible
  228. interrupt-controller node.
  229. @param [in, out] GicCCmObjDesc The CM_ARM_GICC_INFO to patch.
  230. @retval EFI_SUCCESS The function completed successfully.
  231. @retval EFI_ABORTED An error occurred.
  232. @retval EFI_INVALID_PARAMETER Invalid parameter.
  233. **/
  234. STATIC
  235. EFI_STATUS
  236. EFIAPI
  237. GicCIntcNodeParser (
  238. IN CONST VOID *Fdt,
  239. IN INT32 GicIntcNode,
  240. IN OUT CM_OBJ_DESCRIPTOR *GicCCmObjDesc
  241. )
  242. {
  243. EFI_STATUS Status;
  244. INT32 IntCells;
  245. CM_ARM_GICC_INFO *GicCInfo;
  246. CONST UINT8 *Data;
  247. INT32 DataSize;
  248. if (GicCCmObjDesc == NULL) {
  249. ASSERT (0);
  250. return EFI_INVALID_PARAMETER;
  251. }
  252. // Get the number of cells used to encode an interrupt.
  253. Status = FdtGetInterruptCellsInfo (Fdt, GicIntcNode, &IntCells);
  254. if (EFI_ERROR (Status)) {
  255. ASSERT (0);
  256. return Status;
  257. }
  258. // Get the GSIV maintenance interrupt.
  259. // According to the DT bindings, this could be the:
  260. // "Interrupt source of the parent interrupt controller on secondary GICs"
  261. // but it is assumed that only one Gic is available.
  262. Data = fdt_getprop (Fdt, GicIntcNode, "interrupts", &DataSize);
  263. if ((Data != NULL) && (DataSize == (IntCells * sizeof (UINT32)))) {
  264. GicCInfo = (CM_ARM_GICC_INFO *)GicCCmObjDesc->Data;
  265. GicCInfo->VGICMaintenanceInterrupt =
  266. FdtGetInterruptId ((CONST UINT32 *)Data);
  267. GicCInfo->Flags = DT_IRQ_IS_EDGE_TRIGGERED (
  268. fdt32_to_cpu (((UINT32 *)Data)[IRQ_FLAGS_OFFSET])
  269. ) ?
  270. EFI_ACPI_6_3_VGIC_MAINTENANCE_INTERRUPT_MODE_FLAGS :
  271. 0;
  272. return Status;
  273. } else if (DataSize < 0) {
  274. // This property is optional and was not found. Just return.
  275. return Status;
  276. }
  277. // The property exists and its size doesn't match for one interrupt.
  278. ASSERT (0);
  279. return EFI_ABORTED;
  280. }
  281. /** Parse a Gic compatible interrupt-controller node,
  282. extracting GicCv2 information.
  283. This function modifies a CM_OBJ_DESCRIPTOR object.
  284. The following CM_ARM_GICC_INFO fields are patched:
  285. - PhysicalAddress;
  286. - GICH;
  287. - GICV;
  288. @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
  289. @param [in] Gicv2IntcNode Offset of a Gicv2 compatible
  290. interrupt-controller node.
  291. @param [in, out] GicCCmObjDesc The CM_ARM_GICC_INFO to patch.
  292. @retval EFI_SUCCESS The function completed successfully.
  293. @retval EFI_ABORTED An error occurred.
  294. @retval EFI_INVALID_PARAMETER Invalid parameter.
  295. **/
  296. STATIC
  297. EFI_STATUS
  298. EFIAPI
  299. GicCv2IntcNodeParser (
  300. IN CONST VOID *Fdt,
  301. IN INT32 Gicv2IntcNode,
  302. IN OUT CM_OBJ_DESCRIPTOR *GicCCmObjDesc
  303. )
  304. {
  305. EFI_STATUS Status;
  306. UINT32 Index;
  307. CM_ARM_GICC_INFO *GicCInfo;
  308. INT32 AddressCells;
  309. INT32 SizeCells;
  310. CONST UINT8 *GicCValue;
  311. CONST UINT8 *GicVValue;
  312. CONST UINT8 *GicHValue;
  313. CONST UINT8 *Data;
  314. INT32 DataSize;
  315. UINT32 RegSize;
  316. UINT32 RegCount;
  317. if (GicCCmObjDesc == NULL) {
  318. ASSERT (0);
  319. return EFI_INVALID_PARAMETER;
  320. }
  321. GicCInfo = (CM_ARM_GICC_INFO *)GicCCmObjDesc->Data;
  322. GicVValue = NULL;
  323. GicHValue = NULL;
  324. // Get the #address-cells and #size-cells property values.
  325. Status = FdtGetParentAddressInfo (
  326. Fdt,
  327. Gicv2IntcNode,
  328. &AddressCells,
  329. &SizeCells
  330. );
  331. if (EFI_ERROR (Status)) {
  332. ASSERT (0);
  333. return Status;
  334. }
  335. // Don't support more than 64 bits and less than 32 bits addresses.
  336. if ((AddressCells < 1) ||
  337. (AddressCells > 2) ||
  338. (SizeCells < 1) ||
  339. (SizeCells > 2))
  340. {
  341. ASSERT (0);
  342. return EFI_ABORTED;
  343. }
  344. RegSize = (AddressCells + SizeCells) * sizeof (UINT32);
  345. Data = fdt_getprop (Fdt, Gicv2IntcNode, "reg", &DataSize);
  346. if ((Data == NULL) ||
  347. (DataSize < 0) ||
  348. ((DataSize % RegSize) != 0))
  349. {
  350. // If error or wrong size.
  351. ASSERT (0);
  352. return EFI_ABORTED;
  353. }
  354. RegCount = DataSize/RegSize;
  355. switch (RegCount) {
  356. case 4:
  357. {
  358. // GicV is at index 3 in the reg property. GicV is optional.
  359. GicVValue = Data + (sizeof (UINT32) *
  360. GET_DT_REG_ADDRESS_OFFSET (3, AddressCells, SizeCells));
  361. // fall-through.
  362. }
  363. case 3:
  364. {
  365. // GicH is at index 2 in the reg property. GicH is optional.
  366. GicHValue = Data + (sizeof (UINT32) *
  367. GET_DT_REG_ADDRESS_OFFSET (2, AddressCells, SizeCells));
  368. // fall-through.
  369. }
  370. case 2:
  371. {
  372. // GicC is at index 1 in the reg property. GicC is mandatory.
  373. GicCValue = Data + (sizeof (UINT32) *
  374. GET_DT_REG_ADDRESS_OFFSET (1, AddressCells, SizeCells));
  375. break;
  376. }
  377. default:
  378. {
  379. // Not enough or too much information.
  380. ASSERT (0);
  381. return EFI_ABORTED;
  382. }
  383. }
  384. // Patch the relevant fields of the CM_ARM_GICC_INFO objects.
  385. for (Index = 0; Index < GicCCmObjDesc->Count; Index++) {
  386. if (AddressCells == 2) {
  387. GicCInfo[Index].PhysicalBaseAddress = fdt64_to_cpu (*(UINT64 *)GicCValue);
  388. GicCInfo[Index].GICH = (GicHValue == NULL) ? 0 :
  389. fdt64_to_cpu (*(UINT64 *)GicHValue);
  390. GicCInfo[Index].GICV = (GicVValue == NULL) ? 0 :
  391. fdt64_to_cpu (*(UINT64 *)GicVValue);
  392. } else {
  393. GicCInfo[Index].PhysicalBaseAddress = fdt32_to_cpu (*(UINT32 *)GicCValue);
  394. GicCInfo[Index].GICH = (GicHValue == NULL) ? 0 :
  395. fdt32_to_cpu (*(UINT32 *)GicHValue);
  396. GicCInfo[Index].GICV = (GicVValue == NULL) ? 0 :
  397. fdt32_to_cpu (*(UINT32 *)GicVValue);
  398. }
  399. } // for
  400. return EFI_SUCCESS;
  401. }
  402. /** Parse a Gic compatible interrupt-controller node,
  403. extracting GicCv3 information.
  404. This function modifies a CM_OBJ_DESCRIPTOR object.
  405. The following CM_ARM_GICC_INFO fields are patched:
  406. - PhysicalAddress;
  407. - GICH;
  408. - GICV;
  409. @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
  410. @param [in] Gicv3IntcNode Offset of a Gicv3 compatible
  411. interrupt-controller node.
  412. @param [in, out] GicCCmObjDesc The CM_ARM_GICC_INFO to patch.
  413. @retval EFI_SUCCESS The function completed successfully.
  414. @retval EFI_ABORTED An error occurred.
  415. @retval EFI_INVALID_PARAMETER Invalid parameter.
  416. **/
  417. STATIC
  418. EFI_STATUS
  419. EFIAPI
  420. GicCv3IntcNodeParser (
  421. IN CONST VOID *Fdt,
  422. IN INT32 Gicv3IntcNode,
  423. IN OUT CM_OBJ_DESCRIPTOR *GicCCmObjDesc
  424. )
  425. {
  426. EFI_STATUS Status;
  427. UINT32 Index;
  428. CM_ARM_GICC_INFO *GicCInfo;
  429. INT32 AddressCells;
  430. INT32 SizeCells;
  431. UINT32 AdditionalRedistReg;
  432. CONST UINT8 *GicCValue;
  433. CONST UINT8 *GicVValue;
  434. CONST UINT8 *GicHValue;
  435. CONST UINT8 *Data;
  436. INT32 DataSize;
  437. UINT32 RegSize;
  438. UINT32 RegCount;
  439. if (GicCCmObjDesc == NULL) {
  440. ASSERT (0);
  441. return EFI_INVALID_PARAMETER;
  442. }
  443. GicCInfo = (CM_ARM_GICC_INFO *)GicCCmObjDesc->Data;
  444. GicCValue = NULL;
  445. GicVValue = NULL;
  446. GicHValue = NULL;
  447. // Get the #address-cells and #size-cells property values.
  448. Status = FdtGetParentAddressInfo (
  449. Fdt,
  450. Gicv3IntcNode,
  451. &AddressCells,
  452. &SizeCells
  453. );
  454. if (EFI_ERROR (Status)) {
  455. ASSERT (0);
  456. return Status;
  457. }
  458. // Don't support more than 64 bits and less than 32 bits addresses.
  459. if ((AddressCells < 1) ||
  460. (AddressCells > 2) ||
  461. (SizeCells < 1) ||
  462. (SizeCells > 2))
  463. {
  464. ASSERT (0);
  465. return EFI_ABORTED;
  466. }
  467. // The "#redistributor-regions" property is optional.
  468. Data = fdt_getprop (Fdt, Gicv3IntcNode, "#redistributor-regions", &DataSize);
  469. if ((Data != NULL) && (DataSize == sizeof (UINT32))) {
  470. ASSERT (fdt32_to_cpu (*(UINT32 *)Data) > 1);
  471. AdditionalRedistReg = fdt32_to_cpu (*(UINT32 *)Data) - 1;
  472. } else {
  473. AdditionalRedistReg = 0;
  474. }
  475. RegSize = (AddressCells + SizeCells) * sizeof (UINT32);
  476. /*
  477. Ref: linux/blob/master/Documentation/devicetree/bindings/
  478. interrupt-controller/arm%2Cgic-v3.yaml
  479. reg:
  480. description: |
  481. Specifies base physical address(s) and size of the GIC
  482. registers, in the following order:
  483. - GIC Distributor interface (GICD)
  484. - GIC Redistributors (GICR), one range per redistributor region
  485. - GIC CPU interface (GICC)
  486. - GIC Hypervisor interface (GICH)
  487. - GIC Virtual CPU interface (GICV)
  488. GICC, GICH and GICV are optional.
  489. minItems: 2
  490. maxItems: 4096
  491. */
  492. Data = fdt_getprop (Fdt, Gicv3IntcNode, "reg", &DataSize);
  493. if ((Data == NULL) ||
  494. (DataSize < 0) ||
  495. ((DataSize % RegSize) != 0))
  496. {
  497. // If error or wrong size.
  498. ASSERT (0);
  499. return EFI_ABORTED;
  500. }
  501. RegCount = (DataSize / RegSize) - AdditionalRedistReg;
  502. // The GicD and GicR info is mandatory.
  503. switch (RegCount) {
  504. case 5:
  505. {
  506. // GicV is at index 4 in the reg property. GicV is optional.
  507. GicVValue = Data + (sizeof (UINT32) *
  508. GET_DT_REG_ADDRESS_OFFSET (
  509. 4 + AdditionalRedistReg,
  510. AddressCells,
  511. SizeCells
  512. ));
  513. // fall-through.
  514. }
  515. case 4:
  516. {
  517. // GicH is at index 3 in the reg property. GicH is optional.
  518. GicHValue = Data + (sizeof (UINT32) *
  519. GET_DT_REG_ADDRESS_OFFSET (
  520. 3 + AdditionalRedistReg,
  521. AddressCells,
  522. SizeCells
  523. ));
  524. // fall-through.
  525. }
  526. case 3:
  527. {
  528. // GicC is at index 2 in the reg property. GicC is optional.
  529. // Even though GicC is optional, it is made mandatory in this parser.
  530. GicCValue = Data + (sizeof (UINT32) *
  531. GET_DT_REG_ADDRESS_OFFSET (
  532. 2 + AdditionalRedistReg,
  533. AddressCells,
  534. SizeCells
  535. ));
  536. // fall-through
  537. }
  538. case 2:
  539. {
  540. // GicR is discribed by the CM_ARM_GIC_REDIST_INFO object.
  541. // GicD is described by the CM_ARM_GICD_INFO object.
  542. break;
  543. }
  544. default:
  545. {
  546. // Not enough or too much information.
  547. ASSERT (0);
  548. return EFI_ABORTED;
  549. }
  550. }
  551. // Patch the relevant fields of the CM_ARM_GICC_INFO objects.
  552. if (AddressCells == 2) {
  553. for (Index = 0; Index < GicCCmObjDesc->Count; Index++) {
  554. // GicR is discribed by the CM_ARM_GIC_REDIST_INFO object.
  555. GicCInfo[Index].GICRBaseAddress = 0;
  556. GicCInfo[Index].PhysicalBaseAddress = (GicCValue == NULL) ? 0 :
  557. fdt64_to_cpu (*(UINT64 *)GicCValue);
  558. GicCInfo[Index].GICH = (GicHValue == NULL) ? 0 :
  559. fdt64_to_cpu (*(UINT64 *)GicHValue);
  560. GicCInfo[Index].GICV = (GicVValue == NULL) ? 0 :
  561. fdt64_to_cpu (*(UINT64 *)GicVValue);
  562. }
  563. } else {
  564. for (Index = 0; Index < GicCCmObjDesc->Count; Index++) {
  565. // GicR is discribed by the CM_ARM_GIC_REDIST_INFO object.
  566. GicCInfo[Index].GICRBaseAddress = 0;
  567. GicCInfo[Index].PhysicalBaseAddress = (GicCValue == NULL) ? 0 :
  568. fdt32_to_cpu (*(UINT32 *)GicCValue);
  569. GicCInfo[Index].GICH = (GicHValue == NULL) ? 0 :
  570. fdt32_to_cpu (*(UINT32 *)GicHValue);
  571. GicCInfo[Index].GICV = (GicVValue == NULL) ? 0 :
  572. fdt32_to_cpu (*(UINT32 *)GicVValue);
  573. }
  574. }
  575. return EFI_SUCCESS;
  576. }
  577. /** Parse a Pmu compatible node, extracting Pmu information.
  578. This function modifies a CM_OBJ_DESCRIPTOR object.
  579. The following CM_ARM_GICC_INFO fields are patched:
  580. - PerformanceInterruptGsiv;
  581. @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
  582. @param [in] GicIntcNode Offset of a Gic compatible
  583. interrupt-controller node.
  584. @param [in, out] GicCCmObjDesc The CM_ARM_GICC_INFO to patch.
  585. @retval EFI_SUCCESS The function completed successfully.
  586. @retval EFI_ABORTED An error occurred.
  587. @retval EFI_INVALID_PARAMETER Invalid parameter.
  588. **/
  589. STATIC
  590. EFI_STATUS
  591. EFIAPI
  592. GicCPmuNodeParser (
  593. IN CONST VOID *Fdt,
  594. IN INT32 GicIntcNode,
  595. IN OUT CM_OBJ_DESCRIPTOR *GicCCmObjDesc
  596. )
  597. {
  598. EFI_STATUS Status;
  599. INT32 IntCells;
  600. INT32 PmuNode;
  601. UINT32 PmuNodeCount;
  602. UINT32 PmuIrq;
  603. UINT32 Index;
  604. CM_ARM_GICC_INFO *GicCInfo;
  605. CONST UINT8 *Data;
  606. INT32 DataSize;
  607. if (GicCCmObjDesc == NULL) {
  608. ASSERT (GicCCmObjDesc != NULL);
  609. return EFI_INVALID_PARAMETER;
  610. }
  611. GicCInfo = (CM_ARM_GICC_INFO *)GicCCmObjDesc->Data;
  612. PmuNode = 0;
  613. // Count the number of pmu nodes.
  614. Status = FdtCountCompatNodeInBranch (
  615. Fdt,
  616. 0,
  617. &PmuCompatibleInfo,
  618. &PmuNodeCount
  619. );
  620. if (EFI_ERROR (Status)) {
  621. ASSERT_EFI_ERROR (Status);
  622. return Status;
  623. }
  624. if (PmuNodeCount == 0) {
  625. return EFI_NOT_FOUND;
  626. }
  627. Status = FdtGetNextCompatNodeInBranch (
  628. Fdt,
  629. 0,
  630. &PmuCompatibleInfo,
  631. &PmuNode
  632. );
  633. if (EFI_ERROR (Status)) {
  634. ASSERT_EFI_ERROR (Status);
  635. if (Status == EFI_NOT_FOUND) {
  636. // Should have found the node.
  637. Status = EFI_ABORTED;
  638. }
  639. }
  640. // Get the number of cells used to encode an interrupt.
  641. Status = FdtGetInterruptCellsInfo (Fdt, GicIntcNode, &IntCells);
  642. if (EFI_ERROR (Status)) {
  643. ASSERT_EFI_ERROR (Status);
  644. return Status;
  645. }
  646. Data = fdt_getprop (Fdt, PmuNode, "interrupts", &DataSize);
  647. if ((Data == NULL) || (DataSize != (IntCells * sizeof (UINT32)))) {
  648. // If error or not 1 interrupt.
  649. ASSERT (Data != NULL);
  650. ASSERT (DataSize == (IntCells * sizeof (UINT32)));
  651. return EFI_ABORTED;
  652. }
  653. PmuIrq = FdtGetInterruptId ((CONST UINT32 *)Data);
  654. // Only supports PPI 23 for now.
  655. // According to BSA 1.0 s3.6 PPI assignments, PMU IRQ ID is 23. A non BSA
  656. // compliant system may assign a different IRQ for the PMU, however this
  657. // is not implemented for now.
  658. if (PmuIrq != BSA_PMU_IRQ) {
  659. ASSERT (PmuIrq == BSA_PMU_IRQ);
  660. return EFI_ABORTED;
  661. }
  662. for (Index = 0; Index < GicCCmObjDesc->Count; Index++) {
  663. GicCInfo[Index].PerformanceInterruptGsiv = PmuIrq;
  664. }
  665. return EFI_SUCCESS;
  666. }
  667. /** CM_ARM_GICC_INFO parser function.
  668. This parser expects FdtBranch to be the "\cpus" node node.
  669. At most one CmObj is created.
  670. The following structure is populated:
  671. typedef struct CmArmGicCInfo {
  672. UINT32 CPUInterfaceNumber; // {Populated}
  673. UINT32 AcpiProcessorUid; // {Populated}
  674. UINT32 Flags; // {Populated}
  675. UINT32 ParkingProtocolVersion; // {default = 0}
  676. UINT32 PerformanceInterruptGsiv; // {Populated}
  677. UINT64 ParkedAddress; // {default = 0}
  678. UINT64 PhysicalBaseAddress; // {Populated}
  679. UINT64 GICV; // {Populated}
  680. UINT64 GICH; // {Populated}
  681. UINT32 VGICMaintenanceInterrupt; // {Populated}
  682. UINT64 GICRBaseAddress; // {default = 0}
  683. UINT64 MPIDR; // {Populated}
  684. UINT8 ProcessorPowerEfficiencyClass; // {default = 0}
  685. UINT16 SpeOverflowInterrupt; // {default = 0}
  686. UINT32 ProximityDomain; // {default = 0}
  687. UINT32 ClockDomain; // {default = 0}
  688. UINT32 AffinityFlags; // {default = 0}
  689. } CM_ARM_GICC_INFO;
  690. A parser parses a Device Tree to populate a specific CmObj type. None,
  691. one or many CmObj can be created by the parser.
  692. The created CmObj are then handed to the parser's caller through the
  693. HW_INFO_ADD_OBJECT interface.
  694. This can also be a dispatcher. I.e. a function that not parsing a
  695. Device Tree but calling other parsers.
  696. @param [in] FdtParserHandle A handle to the parser instance.
  697. @param [in] FdtBranch When searching for DT node name, restrict
  698. the search to this Device Tree branch.
  699. @retval EFI_SUCCESS The function completed successfully.
  700. @retval EFI_ABORTED An error occurred.
  701. @retval EFI_INVALID_PARAMETER Invalid parameter.
  702. @retval EFI_NOT_FOUND Not found.
  703. @retval EFI_UNSUPPORTED Unsupported.
  704. **/
  705. EFI_STATUS
  706. EFIAPI
  707. ArmGicCInfoParser (
  708. IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
  709. IN INT32 FdtBranch
  710. )
  711. {
  712. EFI_STATUS Status;
  713. INT32 IntcNode;
  714. UINT32 GicVersion;
  715. CM_OBJ_DESCRIPTOR *NewCmObjDesc;
  716. VOID *Fdt;
  717. if (FdtParserHandle == NULL) {
  718. ASSERT (0);
  719. return EFI_INVALID_PARAMETER;
  720. }
  721. Fdt = FdtParserHandle->Fdt;
  722. NewCmObjDesc = NULL;
  723. // The FdtBranch points to the Cpus Node.
  724. // Get the interrupt-controller node associated to the "cpus" node.
  725. Status = FdtGetIntcParentNode (Fdt, FdtBranch, &IntcNode);
  726. if (EFI_ERROR (Status)) {
  727. ASSERT (0);
  728. if (Status == EFI_NOT_FOUND) {
  729. // Should have found the node.
  730. Status = EFI_ABORTED;
  731. }
  732. return Status;
  733. }
  734. Status = GetGicVersion (Fdt, IntcNode, &GicVersion);
  735. if (EFI_ERROR (Status)) {
  736. ASSERT (0);
  737. return Status;
  738. }
  739. // Parse the "cpus" nodes and its children "cpu" nodes,
  740. // and create a CM_OBJ_DESCRIPTOR.
  741. Status = CpusNodeParser (Fdt, FdtBranch, GicVersion, &NewCmObjDesc);
  742. if (EFI_ERROR (Status)) {
  743. ASSERT (0);
  744. return Status;
  745. }
  746. // Parse the interrupt-controller node according to the Gic version.
  747. switch (GicVersion) {
  748. case 2:
  749. {
  750. Status = GicCv2IntcNodeParser (Fdt, IntcNode, NewCmObjDesc);
  751. break;
  752. }
  753. case 3:
  754. {
  755. Status = GicCv3IntcNodeParser (Fdt, IntcNode, NewCmObjDesc);
  756. break;
  757. }
  758. default:
  759. {
  760. // Unsupported Gic version.
  761. ASSERT (0);
  762. Status = EFI_UNSUPPORTED;
  763. }
  764. }
  765. if (EFI_ERROR (Status)) {
  766. ASSERT (0);
  767. goto exit_handler;
  768. }
  769. // Parse the Gic information common to Gic v2 and v3.
  770. Status = GicCIntcNodeParser (Fdt, IntcNode, NewCmObjDesc);
  771. if (EFI_ERROR (Status)) {
  772. ASSERT (0);
  773. goto exit_handler;
  774. }
  775. // Parse the Pmu Interrupt.
  776. Status = GicCPmuNodeParser (Fdt, IntcNode, NewCmObjDesc);
  777. if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
  778. ASSERT_EFI_ERROR (Status);
  779. goto exit_handler;
  780. }
  781. // Add all the CmObjs to the Configuration Manager.
  782. Status = AddMultipleCmObj (FdtParserHandle, NewCmObjDesc, 0, NULL);
  783. if (EFI_ERROR (Status)) {
  784. ASSERT (0);
  785. goto exit_handler;
  786. }
  787. exit_handler:
  788. FreeCmObjDesc (NewCmObjDesc);
  789. return Status;
  790. }