From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from EUR04-VI1-obe.outbound.protection.outlook.com (EUR04-VI1-obe.outbound.protection.outlook.com [40.107.8.54]) by mx.groups.io with SMTP id smtpd.web11.6355.1636122471044155457 for ; Fri, 05 Nov 2021 07:27:51 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@armh.onmicrosoft.com header.s=selector2-armh-onmicrosoft-com header.b=cPkIcd23; spf=pass (domain: arm.com, ip: 40.107.8.54, mailfrom: sami.mujawar@arm.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=armh.onmicrosoft.com; s=selector2-armh-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=VDsqNbZqTBVtyg4h8iHBhgilzSV7cJBtY08UbiBfzW4=; b=cPkIcd23mTFxAi+KY1kJ9yF7YzPWplQRAglsWoGY7K5j+G8F5ODYEs2dAx3uHJHd6gTjOzkB5zr1p3aJaQfdV+niP1Xtw0tLLFSjev7sSYDtKyMbGr8Yyyb4S3Wr84N+E+8F32SPyLrqKqbIfM7bEXK7FNm9Kw8zaCVsad17HLw= Received: from DB6PR0601CA0005.eurprd06.prod.outlook.com (2603:10a6:4:7b::15) by VI1PR08MB3647.eurprd08.prod.outlook.com (2603:10a6:803:85::22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4649.17; Fri, 5 Nov 2021 14:27:46 +0000 Received: from DB5EUR03FT059.eop-EUR03.prod.protection.outlook.com (2603:10a6:4:7b:cafe::dc) by DB6PR0601CA0005.outlook.office365.com (2603:10a6:4:7b::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4669.10 via Frontend Transport; Fri, 5 Nov 2021 14:27:46 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 63.35.35.123) smtp.mailfrom=arm.com; dkim=pass (signature was verified) header.d=armh.onmicrosoft.com;dmarc=pass action=none header.from=arm.com; Received-SPF: Pass (protection.outlook.com: domain of arm.com designates 63.35.35.123 as permitted sender) receiver=protection.outlook.com; client-ip=63.35.35.123; helo=64aa7808-outbound-1.mta.getcheckrecipient.com; Received: from 64aa7808-outbound-1.mta.getcheckrecipient.com (63.35.35.123) by DB5EUR03FT059.mail.protection.outlook.com (10.152.21.175) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4649.14 via Frontend Transport; Fri, 5 Nov 2021 14:27:46 +0000 Received: ("Tessian outbound d49ee2bec50d:v108"); Fri, 05 Nov 2021 14:27:46 +0000 X-CheckRecipientChecked: true X-CR-MTA-CID: ba38553e782711bf X-CR-MTA-TID: 64aa7808 Received: from 8e47bcdd788b.1 by 64aa7808-outbound-1.mta.getcheckrecipient.com id 19CC5DE7-E98C-436E-A7C1-831EA72CB897.1; Fri, 05 Nov 2021 14:27:39 +0000 Received: from EUR05-DB8-obe.outbound.protection.outlook.com by 64aa7808-outbound-1.mta.getcheckrecipient.com with ESMTPS id 8e47bcdd788b.1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384); Fri, 05 Nov 2021 14:27:39 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=Nwg7uU+1njpmgwtZ/LLhmKPGPLS/oLgcjw6kjKdvofs78kpx1OUOrVqc1BItXRptI8k104maXS4rUWKLbmCUMbVPrQ6Q5DBoJItDO39TCn0Ikv5+LMvCU/1vecEZ0oevgw1gq1YvaZ2vU+AaUBfDWdveXw7XIdnlW+f7vmte3IzuIpK5B8JYlonLwmaNBeUt09qW28jl/eLcwKC7hWjaw0dQJjrEvbeOq8JQUBIj8twarfvGAVdeJv3eIx2SOai0mT5jNEu4dljET/reBknzpCkwf6GKlOd1Lq5XMfv/1TE6xowMXX93V2vbkeSC7HRtfJeHXDOp+6xSqEnbakHOMQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=VDsqNbZqTBVtyg4h8iHBhgilzSV7cJBtY08UbiBfzW4=; b=hcckaufErnLcSQdtDwFaLfEGds0XIoukLsGuM+SbGZWMPRBob100ehhxCTkTfByESyX7bfbdtqseo8YpgYNQoRJnQ2PV2QMndgfhnVdtIoqgIU3dr2p2eRM9heG+YPK7fDjH8Xixl8CFquVHRdeX6ODDVkREPpa+ETrvr5AZ60M/Kki1vXd3yCs9OlM/SY3ZGrizPZQKBxNN3j0rKy9k67BrwCcndOhIOOBdnia3gYJYenxP8l4uIcMV96ivm2oQ7cqXDdIEYTcaDfqw2f6hRr9LXcLr7MLPxeGWcf0U0vlLkBpM31yG+OLAltRgUy/xkuYdTUQpcBEmi2+7UBm5Uw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=arm.com; dmarc=pass action=none header.from=arm.com; dkim=pass header.d=arm.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=armh.onmicrosoft.com; s=selector2-armh-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=VDsqNbZqTBVtyg4h8iHBhgilzSV7cJBtY08UbiBfzW4=; b=cPkIcd23mTFxAi+KY1kJ9yF7YzPWplQRAglsWoGY7K5j+G8F5ODYEs2dAx3uHJHd6gTjOzkB5zr1p3aJaQfdV+niP1Xtw0tLLFSjev7sSYDtKyMbGr8Yyyb4S3Wr84N+E+8F32SPyLrqKqbIfM7bEXK7FNm9Kw8zaCVsad17HLw= Authentication-Results-Original: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=arm.com; Received: from AS8PR08MB6806.eurprd08.prod.outlook.com (2603:10a6:20b:39b::12) by AM6PR08MB4166.eurprd08.prod.outlook.com (2603:10a6:20b:a6::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4669.13; Fri, 5 Nov 2021 14:27:35 +0000 Received: from AS8PR08MB6806.eurprd08.prod.outlook.com ([fe80::54b5:239d:9896:ee65]) by AS8PR08MB6806.eurprd08.prod.outlook.com ([fe80::54b5:239d:9896:ee65%4]) with mapi id 15.20.4669.010; Fri, 5 Nov 2021 14:27:35 +0000 Subject: Re: [PATCH v1 03/14] DynamicTablesPkg: FdtHwInfoParser: Add FDT utility functions To: Pierre.Gondois@arm.com, devel@edk2.groups.io, Alexei Fedorov Cc: Akanksha Jain , Alexandru Elisei , nd References: <20210623123828.23693-1-Pierre.Gondois@arm.com> <20210623123828.23693-4-Pierre.Gondois@arm.com> From: "Sami Mujawar" Message-ID: Date: Fri, 5 Nov 2021 14:27:41 +0000 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Thunderbird/52.0.1 In-Reply-To: <20210623123828.23693-4-Pierre.Gondois@arm.com> X-ClientProxiedBy: LO2P265CA0282.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:a1::30) To AS8PR08MB6806.eurprd08.prod.outlook.com (2603:10a6:20b:39b::12) MIME-Version: 1.0 Received: from [10.1.196.43] (217.140.106.52) by LO2P265CA0282.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:a1::30) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4669.10 via Frontend Transport; Fri, 5 Nov 2021 14:27:35 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 1b7405ee-b0aa-4377-8f8a-08d9a0686fe6 X-MS-TrafficTypeDiagnostic: AM6PR08MB4166:|VI1PR08MB3647: X-Microsoft-Antispam-PRVS: x-checkrecipientrouted: true NoDisclaimer: true X-MS-Oob-TLC-OOBClassifiers: OLM:1417;OLM:1417; X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam-Untrusted: BCL:0; X-Microsoft-Antispam-Message-Info-Original: RpbsCgLFMgzXrFqyt3VNP4xw2mVNss9cEStkoOoU657zs6eT+WBZx6wzloYJmYOTjfSqQrgMfIcvICpFH/ToK2EDJb7hIiMPxAWnefRtrONbizKwmmEmYFq+A+84fzbgcFKRQ+9+D2/3+BCChax51QIEo1aF1yidzTDGY1mdBmRtBqC6fJHbyYPROxUodRdqLTyKKjOkdWvTaInXpmU3d6BJYwVukxzovivGKNzKpNru4UgynLf28il68wg02HD+k9NBceP+t9swJv2GszCTlLKJ7BMulWkpfb5q8JOZfiTChvhheB5YIgjJ4D3xQRfGnIDaV/sWHgAdTbYiwNQlIgNanZd2SjoSCwPidwkDKRv8crrMyvWe2r13+YAEtlJwRq3Z/loWnCtRZ4wDJSjz88CQ3BcJ0HjWs56mbDdFvDMcnwF2PSmitT6N5Oo0zfhXJ0ZvMKN4o6dwedZVGnZLdTtv5X3pJepMq5kTrAHOVdgZ3fuxzYw8RGxdhd9OIlCYWVTwcJBLziWVC5YnWRTjfa+xJeElOalC29VtuBS5+ai4srCrHnj/gHQpaX2nB/EOEoeb9Tq0eFiwQvn8OSiigUlv6y9R5usYHdZgIckjxEPIIv+3DdIGnMj8X8Bd9hYdhZwzsi8JFchPGWC6K8iOJIkucC2p1R4gZFVyF2QeI5dsrHilnjCqKB1gLNzi25oXY2pmTP819J7MnY/DftnHyPKi5WVBtJ92FwlNaumELU/FVEsVKC5BM9ehZVYihDgvVqj6qY8WgAF5hj83HEfWqXuIf4HvvQ/TV9J7cLpeucU= X-Forefront-Antispam-Report-Untrusted: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:AS8PR08MB6806.eurprd08.prod.outlook.com;PTR:;CAT:NONE;SFS:(6029001)(4636009)(366004)(66946007)(31696002)(31686004)(44832011)(36756003)(86362001)(186003)(6862004)(66556008)(8936002)(5660300002)(956004)(6666004)(2616005)(66476007)(30864003)(16576012)(2906002)(4326008)(26005)(6486002)(53546011)(38350700002)(38100700002)(6636002)(8676002)(316002)(508600001)(83380400001)(54906003)(37006003)(52116002)(21314003)(45980500001)(43740500002)(559001)(579004);DIR:OUT;SFP:1101; X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM6PR08MB4166 Original-Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=arm.com; Return-Path: Sami.Mujawar@arm.com X-EOPAttributedMessage: 0 X-MS-Exchange-Transport-CrossTenantHeadersStripped: DB5EUR03FT059.eop-EUR03.prod.protection.outlook.com X-MS-Office365-Filtering-Correlation-Id-Prvs: b94acd68-1f6c-43d6-db61-08d9a068695f X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: iAcssHGF9Myhbs9zz3sns9DDpr+vBC9VNS1jhaSAr21SnczRuxksWXwuHmBFTHTGjubqi8yg++MuFbJqdqr2Xeff4qHW96gm0nBhE0vibKJHCr42oObCfrf3Wh/PLCAhSzklPwJ3183P3S76PAtYJslmpgGRDM5CmF/Qct2a7VmPrP5GpWOYJwhhR7eP/jb/fqwV2CReJ6peMcFp7RCXOdXfEpNxkitZLaGBEuaIsyOmDhzRyMVSLqu55r1sDKg7UPuxTV+8ksoI/oU1aiJv+jFyVxy7UFrxE6HIvyqBiHqOw/A3yCBC8wk5FJZTL9PGAy6HpaNyq9pg54ogUjh2v/ofOOHh5rf0AXb+plGlfiIrrLBDeMh+fl6BK8Nw2b6Ccgyy/qItqi+gsv2CydOZChAzVFN3TMtNsh2HtW7RS4O1vwE9D8gJyUeMq3vrciSjGVQ+rirfF6tpk2ZJqNlbDpPlQPDWC37hadMYnQX6Q8GOj6nitKNp5b7M+IUTerF2x2BqntlTAa294Ezc+lxW/KoXwPQvDD/TU+Ry5/PEE0bd4DeHFdbVOJoPnU6S8RKtgQIe/1C7IgLNRTyrc5qC2Ll6PBmOow9dDhVhMPnPch43EhgUYtrQi9WjgE7o+HuO9qrtHr/7yY5R/+OutdvpSkWPVHA0+eNipznkOzsD679m3/4qzFB+Lau6VcZXjF9u1bNWiVZeccwl8/v2u53NnsNN6r9aSpbVgGETBGOcA2xFT8aF4G6LyRZ3q1jM/+Lu7oWg8+OMF3U7p93mZcSb3Q== X-Forefront-Antispam-Report: CIP:63.35.35.123;CTRY:IE;LANG:en;SCL:1;SRV:;IPV:CAL;SFV:NSPM;H:64aa7808-outbound-1.mta.getcheckrecipient.com;PTR:ec2-63-35-35-123.eu-west-1.compute.amazonaws.com;CAT:NONE;SFS:(6029001)(4636009)(36840700001)(46966006)(8936002)(2616005)(2906002)(86362001)(6636002)(53546011)(316002)(36860700001)(30864003)(44832011)(6862004)(4326008)(5660300002)(54906003)(6486002)(47076005)(186003)(956004)(37006003)(8676002)(83380400001)(31686004)(16576012)(26005)(81166007)(70206006)(508600001)(356005)(36756003)(70586007)(6666004)(31696002)(82310400003)(336012)(21314003)(43740500002)(579004)(559001);DIR:OUT;SFP:1101; X-OriginatorOrg: arm.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 05 Nov 2021 14:27:46.3969 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 1b7405ee-b0aa-4377-8f8a-08d9a0686fe6 X-MS-Exchange-CrossTenant-Id: f34e5979-57d9-4aaa-ad4d-b122a662184d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=f34e5979-57d9-4aaa-ad4d-b122a662184d;Ip=[63.35.35.123];Helo=[64aa7808-outbound-1.mta.getcheckrecipient.com] X-MS-Exchange-CrossTenant-AuthSource: DB5EUR03FT059.eop-EUR03.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: VI1PR08MB3647 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit Content-Language: en-GB Hi Pierre, I have a minor comment, otherwise this patch looks good to me. Regards, Sami Mujawar On 23/06/2021 01:38 PM, Pierre.Gondois@arm.com wrote: > From: Pierre Gondois > > The FdtHwInfoParser parses a platform Device Tree and populates > the Platform Information repository with Configuration Manager > objects. > > Therefore, add a set of helper functions to simplify parsing of > the platform Device Tree. > > Signed-off-by: Pierre Gondois > Signed-off-by: Sami Mujawar > --- > .../Library/FdtHwInfoParserLib/FdtUtility.c | 909 ++++++++++++++++++ > .../Library/FdtHwInfoParserLib/FdtUtility.h | 458 +++++++++ > 2 files changed, 1367 insertions(+) > create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtUtility.c > create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtUtility.h > > diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtUtility.c b/DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtUtility.c > new file mode 100644 > index 000000000000..0fca82aedf9e > --- /dev/null > +++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtUtility.c > @@ -0,0 +1,909 @@ > +/** @file > + Flattened device tree utility. > + > + Copyright (c) 2021, ARM Limited. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > + @par Reference(s): > + - Device tree Specification - Release v0.3 > + - linux/Documentation/devicetree/bindings/interrupt-controller/arm%2Cgic.yaml > + - linux//Documentation/devicetree/bindings/interrupt-controller/arm%2Cgic.yaml > +**/ > + > +#include > +#include "FdtUtility.h" > + > +/** Get the interrupt Id of an interrupt described in a fdt. > + > + Data must describe a GIC interrupt. A GIC interrupt is on at least > + 3 UINT32 cells. > + This function DOES NOT SUPPORT extended SPI range and extended PPI range. > + > + @param [in] Data Pointer to the first cell of an "interrupts" property. > + > + @retval The interrupt id. > +**/ > +UINT32 > +EFIAPI > +FdtGetInterruptId ( > + UINT32 CONST * Data > + ) > +{ > + UINT32 IrqType; > + UINT32 IrqId; > + > + ASSERT (Data != NULL); > + > + IrqType = fdt32_to_cpu (Data[IRQ_TYPE_OFFSET]); > + IrqId = fdt32_to_cpu (Data[IRQ_NUMBER_OFFSET]); > + > + switch (IrqType) { > + case DT_SPI_IRQ: > + IrqId += SPI_OFFSET; > + break; > + > + case DT_PPI_IRQ: > + IrqId += PPI_OFFSET; > + break; > + > + default: > + ASSERT (0); > + IrqId = 0; > + } > + > + return IrqId; > +} > + > +/** Get the ACPI interrupt flags of an interrupt described in a fdt. > + > + Data must describe a GIC interrupt. A GIC interrupt is on at least > + 3 UINT32 cells. > + > + PPI interrupt cpu mask on bits [15:8] are ignored. > + > + @param [in] Data Pointer to the first cell of an "interrupts" property. > + > + @retval The interrupt flags (for ACPI). > +**/ > +UINT32 > +EFIAPI > +FdtGetInterruptFlags ( > + UINT32 CONST * Data > + ) > +{ > + UINT32 IrqFlags; > + UINT32 AcpiIrqFlags; > + > + ASSERT (Data != NULL); > + > + IrqFlags = fdt32_to_cpu (Data[IRQ_FLAGS_OFFSET]); > + > + AcpiIrqFlags = DT_IRQ_IS_EDGE_TRIGGERED (IrqFlags) ? BIT0 : 0; > + AcpiIrqFlags |= DT_IRQ_IS_ACTIVE_LOW (IrqFlags) ? BIT1 : 0; > + > + return AcpiIrqFlags; > +} > + > +/** Check whether a node has the input name. > + > + @param [in] Fdt Pointer to a Flattened Device Tree. > + @param [in] Node Offset of the node to check the name. > + @param [in] SearchName Node name to search. > + This is a NULL terminated string. > + > + @retval True The node has the input name. > + @retval FALSE Otherwise, or error. > +**/ > +STATIC > +BOOLEAN > +EFIAPI > +FdtNodeHasName ( > + IN CONST VOID * Fdt, > + IN INT32 Node, > + IN CONST VOID * SearchName > + ) > +{ > + CONST CHAR8 * NodeName; > + UINT32 Length; > + > + if ((Fdt == NULL) || > + (SearchName == NULL)) { > + ASSERT (0); > + return FALSE; > + } > + > + // Always compare the whole string. Don't stop at the "@" char. > + Length = (UINT32)AsciiStrLen (SearchName); > + > + // Get the address of the node name. > + NodeName = fdt_offset_ptr (Fdt, Node + FDT_TAGSIZE, Length + 1); > + if (NodeName == NULL) { > + return FALSE; > + } > + > + // SearchName must be longer than the node name. > + if (Length > AsciiStrLen (NodeName)) { > + return FALSE; > + } > + > + // Use CompareMem here instead of AsciiStrnCmp as the NodeName [SAMI] I think the comment here needs to be updated. > + // may contain the node name followed by '@'0x. > + if (AsciiStrnCmp (NodeName, SearchName, Length) != 0) { > + return FALSE; > + } > + > + // The name matches perfectly, or > + // the node name is XXX@addr and the XXX matches. > + if ((NodeName[Length] == '\0') || > + (NodeName[Length] == '@')) { > + return TRUE; > + } > + > + return FALSE; > +} > + > +/** Iterate through the list of strings in the Context, > + and check whether at least one string is matching the > + "compatible" property of the node. > + > + @param [in] Fdt Pointer to a Flattened Device Tree. > + @param [in] Node Offset of the node to operate the check on. > + @param [in] CompatInfo COMPATIBILITY_INFO containing the list of compatible > + strings to compare with the "compatible" property > + of the node. > + > + @retval TRUE At least one string matched, the node is compatible. > + @retval FALSE Otherwise, or error. > +**/ > +BOOLEAN > +EFIAPI > +FdtNodeIsCompatible ( > + IN CONST VOID * Fdt, > + IN INT32 Node, > + IN CONST VOID * CompatInfo > + ) > +{ > + UINT32 Index; > + CONST COMPATIBILITY_STR * CompatibleTable; > + UINT32 Count; > + CONST VOID * Prop; > + INT32 PropLen; > + > + if ((Fdt == NULL) || > + (CompatInfo == NULL)) { > + ASSERT (0); > + return FALSE; > + } > + > + Count = ((COMPATIBILITY_INFO*)CompatInfo)->Count; > + CompatibleTable = ((COMPATIBILITY_INFO*)CompatInfo)->CompatTable; > + > + // Get the "compatible" property. > + Prop = fdt_getprop (Fdt, Node, "compatible", &PropLen); > + if ((Prop == NULL) || (PropLen < 0)) { > + return FALSE; > + } > + > + for (Index = 0; Index < Count; Index++) { > + if (fdt_stringlist_contains ( > + Prop, > + PropLen, > + CompatibleTable[Index].CompatStr > + )) { > + return TRUE; > + } > + } // for > + > + return FALSE; > +} > + > +/** Check whether a node has a property. > + > + @param [in] Fdt Pointer to a Flattened Device Tree. > + @param [in] Node Offset of the node to operate the check on. > + @param [in] PropertyName Name of the property to search. > + This is a NULL terminated string. > + > + @retval True The node has the property. > + @retval FALSE Otherwise, or error. > +**/ > +BOOLEAN > +EFIAPI > +FdtNodeHasProperty ( > + IN CONST VOID * Fdt, > + IN INT32 Node, > + IN CONST VOID * PropertyName > + ) > +{ > + INT32 Size; > + CONST VOID * Prop; > + > + if ((Fdt == NULL) || > + (PropertyName == NULL)) { > + ASSERT (0); > + return FALSE; > + } > + > + Prop = fdt_getprop (Fdt, Node, PropertyName, &Size); > + if ((Prop == NULL) || (Size < 0)) { > + return FALSE; > + } > + return TRUE; > +} > + > +/** Get the next node in the whole DT fulfilling a condition. > + > + The condition to fulfill is checked by the NodeChecker function. > + Context is passed to NodeChecker. > + > + The Device tree is traversed in a depth-first search, starting from Node. > + The input Node is skipped. > + > + @param [in] Fdt Pointer to a Flattened Device Tree. > + @param [in, out] Node At entry: Node offset to start the search. > + This first node is skipped. > + Write (-1) to search the whole tree. > + At exit: If success, contains the offset of > + the next node fulfilling the > + condition. > + @param [in, out] Depth Depth is incremented/decremented of the depth > + difference between the input Node and the > + output Node. > + E.g.: If the output Node is a child node > + of the input Node, contains (+1). > + @param [in] NodeChecker Function called to check if the condition > + is fulfilled. > + @param [in] Context Context for the NodeChecker. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_ABORTED An error occurred. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_NOT_FOUND No matching node found. > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +FdtGetNextCondNode ( > + IN CONST VOID * Fdt, > + IN OUT INT32 * Node, > + IN OUT INT32 * Depth, > + IN NODE_CHECKER_FUNC NodeChecker, > + IN CONST VOID * Context > + ) > +{ > + INT32 CurrNode; > + > + if ((Fdt == NULL) || > + (Node == NULL) || > + (Depth == NULL) || > + (NodeChecker == NULL)) { > + ASSERT (0); > + return EFI_INVALID_PARAMETER; > + } > + > + CurrNode = *Node; > + do { > + CurrNode = fdt_next_node (Fdt, CurrNode, Depth); > + if ((CurrNode == -FDT_ERR_NOTFOUND) || > + (*Depth < 0)) { > + // End of the tree, no matching node found. > + return EFI_NOT_FOUND; > + } else if (CurrNode < 0) { > + // An error occurred. > + ASSERT (0); > + return EFI_ABORTED; > + } > + } while (!NodeChecker (Fdt, CurrNode, Context)); > + > + // Matching node found. > + *Node = CurrNode; > + return EFI_SUCCESS; > +} > + > +/** Get the next node in a branch fulfilling a condition. > + > + The condition to fulfill is checked by the NodeChecker function. > + Context is passed to NodeChecker. > + > + The Device tree is traversed in a depth-first search, starting from Node. > + The input Node is skipped. > + > + @param [in] Fdt Pointer to a Flattened Device Tree. > + @param [in] FdtBranch Only search in the sub-nodes of this > + branch. > + Write (-1) to search the whole tree. > + @param [in] NodeChecker Function called to check if the condition > + is fulfilled. > + @param [in] Context Context for the NodeChecker. > + @param [in, out] Node At entry: Node offset to start the search. > + This first node is skipped. > + Write (-1) to search the whole tree. > + At exit: If success, contains the offset > + of the next node in the branch > + fulfilling the condition. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_ABORTED An error occurred. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_NOT_FOUND No matching node found. > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +FdtGetNextCondNodeInBranch ( > + IN CONST VOID * Fdt, > + IN INT32 FdtBranch, > + IN NODE_CHECKER_FUNC NodeChecker, > + IN CONST VOID * Context, > + IN OUT INT32 * Node > + ) > +{ > + EFI_STATUS Status; > + INT32 CurrNode; > + INT32 Depth; > + > + if ((Fdt == NULL) || > + (Node == NULL) || > + (NodeChecker == NULL)) { > + ASSERT (0); > + return EFI_INVALID_PARAMETER; > + } > + > + CurrNode = FdtBranch; > + Depth = 0; > + > + // First, check the Node is in the sub-nodes of the branch. > + // This allows to find the relative depth of Node in the branch. > + if (CurrNode != *Node) { > + for (CurrNode = fdt_next_node (Fdt, CurrNode, &Depth); > + (CurrNode >= 0) && (Depth > 0); > + CurrNode = fdt_next_node (Fdt, CurrNode, &Depth)) { > + if (CurrNode == *Node) { > + // Node found. > + break; > + } > + } // for > + > + if ((CurrNode < 0) || (Depth <= 0)) { > + // Node is not a node in the branch, or an error occurred. > + ASSERT (0); > + return EFI_INVALID_PARAMETER; > + } > + } > + > + // Get the next node in the tree fulfilling the condition, > + // in any branch. > + Status = FdtGetNextCondNode ( > + Fdt, > + Node, > + &Depth, > + NodeChecker, > + Context > + ); > + if (EFI_ERROR (Status)) { > + ASSERT (Status == EFI_NOT_FOUND); > + return Status; > + } > + > + if (Depth <= 0) { > + // The node found is not in the right branch. > + return EFI_NOT_FOUND; > + } > + > + return EFI_SUCCESS; > +} > + > +/** Get the next node in a branch having a matching name. > + > + The Device tree is traversed in a depth-first search, starting from Node. > + The input Node is skipped. > + > + @param [in] Fdt Pointer to a Flattened Device Tree. > + @param [in] FdtBranch Only search in the sub-nodes of this branch. > + Write (-1) to search the whole tree. > + @param [in] NodeName The node name to search. > + This is a NULL terminated string. > + @param [in, out] Node At entry: Node offset to start the search. > + This first node is skipped. > + Write (-1) to search the whole tree. > + At exit: If success, contains the offset of > + the next node in the branch > + having a matching name. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_ABORTED An error occurred. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_NOT_FOUND No matching node found. > +**/ > +EFI_STATUS > +EFIAPI > +FdtGetNextNamedNodeInBranch ( > + IN CONST VOID * Fdt, > + IN INT32 FdtBranch, > + IN CONST CHAR8 * NodeName, > + IN OUT INT32 * Node > + ) > +{ > + return FdtGetNextCondNodeInBranch ( > + Fdt, > + FdtBranch, > + FdtNodeHasName, > + NodeName, > + Node > + ); > +} > + > +/** Get the next node in a branch with at least one compatible property. > + > + The Device tree is traversed in a depth-first search, starting from Node. > + The input Node is skipped. > + > + @param [in] Fdt Pointer to a Flattened Device Tree. > + @param [in] FdtBranch Only search in the sub-nodes of this branch. > + Write (-1) to search the whole tree. > + @param [in] CompatNamesInfo Table of compatible strings to compare with > + the compatible property of the node. > + @param [in, out] Node At entry: Node offset to start the search. > + This first node is skipped. > + Write (-1) to search the whole tree. > + At exit: If success, contains the offset of > + the next node in the branch > + being compatible. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_ABORTED An error occurred. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_NOT_FOUND No matching node found. > +**/ > +EFI_STATUS > +EFIAPI > +FdtGetNextCompatNodeInBranch ( > + IN CONST VOID * Fdt, > + IN INT32 FdtBranch, > + IN CONST COMPATIBILITY_INFO * CompatNamesInfo, > + IN OUT INT32 * Node > + ) > +{ > + return FdtGetNextCondNodeInBranch ( > + Fdt, > + FdtBranch, > + FdtNodeIsCompatible, > + (CONST VOID*)CompatNamesInfo, > + Node > + ); > +} > + > +/** Get the next node in a branch having the PropName property. > + > + The Device tree is traversed in a depth-first search, starting from Node. > + The input Node is skipped. > + > + @param [in] Fdt Pointer to a Flattened Device Tree. > + @param [in] FdtBranch Only search in the sub-nodes of this branch. > + Write (-1) to search the whole tree. > + @param [in] PropName Name of the property to search. > + This is a NULL terminated string. > + @param [in, out] Node At entry: Node offset to start the search. > + This first node is skipped. > + Write (-1) to search the whole tree. > + At exit: If success, contains the offset of > + the next node in the branch > + being compatible. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_ABORTED An error occurred. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_NOT_FOUND No matching node found. > +**/ > +EFI_STATUS > +EFIAPI > +FdtGetNextPropNodeInBranch ( > + IN CONST VOID * Fdt, > + IN INT32 FdtBranch, > + IN CONST CHAR8 * PropName, > + IN OUT INT32 * Node > + ) > +{ > + return FdtGetNextCondNodeInBranch ( > + Fdt, > + FdtBranch, > + FdtNodeHasProperty, > + (CONST VOID*)PropName, > + Node > + ); > +} > + > +/** Count the number of Device Tree nodes fulfilling a condition > + in a Device Tree branch. > + > + The condition to fulfill is checked by the NodeChecker function. > + Context is passed to NodeChecker. > + > + @param [in] Fdt Pointer to a Flattened Device Tree. > + @param [in] FdtBranch Only search in the sub-nodes of this branch. > + Write (-1) to search the whole tree. > + @param [in] NodeChecker Function called to check the condition is > + fulfilled. > + @param [in] Context Context for the NodeChecker. > + @param [out] NodeCount If success, contains the count of nodes > + fulfilling the condition. > + Can be 0. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_ABORTED An error occurred. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +FdtCountCondNodeInBranch ( > + IN CONST VOID * Fdt, > + IN INT32 FdtBranch, > + IN NODE_CHECKER_FUNC NodeChecker, > + IN CONST VOID * Context, > + OUT UINT32 * NodeCount > + ) > +{ > + EFI_STATUS Status; > + INT32 CurrNode; > + > + if ((Fdt == NULL) || > + (NodeChecker == NULL) || > + (NodeCount == NULL)) { > + ASSERT (0); > + return EFI_INVALID_PARAMETER; > + } > + > + *NodeCount = 0; > + CurrNode = FdtBranch; > + while (TRUE) { > + Status = FdtGetNextCondNodeInBranch ( > + Fdt, > + FdtBranch, > + NodeChecker, > + Context, > + &CurrNode > + ); > + if (EFI_ERROR (Status) && > + (Status != EFI_NOT_FOUND)) { > + ASSERT (0); > + return Status; > + } else if (Status == EFI_NOT_FOUND) { > + break; > + } > + (*NodeCount)++; > + } > + return EFI_SUCCESS; > +} > + > +/** Count the number of nodes in a branch with the input name. > + > + @param [in] Fdt Pointer to a Flattened Device Tree. > + @param [in] FdtBranch Only search in the sub-nodes of this branch. > + Write (-1) to search the whole tree. > + @param [in] NodeName Node name to search. > + This is a NULL terminated string. > + @param [out] NodeCount If success, contains the count of nodes > + fulfilling the condition. > + Can be 0. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_ABORTED An error occurred. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > +**/ > +EFI_STATUS > +EFIAPI > +FdtCountNamedNodeInBranch ( > + IN CONST VOID * Fdt, > + IN INT32 FdtBranch, > + IN CONST CHAR8 * NodeName, > + OUT UINT32 * NodeCount > + ) > +{ > + return FdtCountCondNodeInBranch ( > + Fdt, > + FdtBranch, > + FdtNodeHasName, > + NodeName, > + NodeCount > + ); > +} > + > +/** Count the number of nodes in a branch with at least > + one compatible property. > + > + @param [in] Fdt Pointer to a Flattened Device Tree. > + @param [in] FdtBranch Only search in the sub-nodes of this branch. > + Write (-1) to search the whole tree. > + @param [in] CompatNamesInfo Table of compatible strings to > + compare with the compatible property > + of the node. > + @param [out] NodeCount If success, contains the count of nodes > + fulfilling the condition. > + Can be 0. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_ABORTED An error occurred. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > +**/ > +EFI_STATUS > +EFIAPI > +FdtCountCompatNodeInBranch ( > + IN CONST VOID * Fdt, > + IN INT32 FdtBranch, > + IN CONST COMPATIBILITY_INFO * CompatNamesInfo, > + OUT UINT32 * NodeCount > + ) > +{ > + return FdtCountCondNodeInBranch ( > + Fdt, > + FdtBranch, > + FdtNodeIsCompatible, > + CompatNamesInfo, > + NodeCount > + ); > +} > + > +/** Count the number of nodes in a branch having the PropName property. > + > + @param [in] Fdt Pointer to a Flattened Device Tree. > + @param [in] FdtBranch Only search in the sub-nodes of this branch. > + Write (-1) to search the whole tree. > + @param [in] PropName Name of the property to search. > + This is a NULL terminated string. > + @param [out] NodeCount If success, contains the count of nodes > + fulfilling the condition. > + Can be 0. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_ABORTED An error occurred. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > +**/ > +EFI_STATUS > +EFIAPI > +FdtCountPropNodeInBranch ( > + IN CONST VOID * Fdt, > + IN INT32 FdtBranch, > + IN CONST CHAR8 * PropName, > + OUT UINT32 * NodeCount > + ) > +{ > + return FdtCountCondNodeInBranch ( > + Fdt, > + FdtBranch, > + FdtNodeHasProperty, > + PropName, > + NodeCount > + ); > +} > + > +/** Get the interrupt-controller node handling the interrupts of > + the input node. > + > + To do this, recursively search a node with either the "interrupt-controller" > + or the "interrupt-parent" property in the parents of Node. > + > + Devicetree Specification, Release v0.3, > + 2.4.1 "Properties for Interrupt Generating Devices": > + Because the hierarchy of the nodes in the interrupt tree > + might not match the devicetree, the interrupt-parent > + property is available to make the definition of an > + interrupt parent explicit. The value is the phandle to the > + interrupt parent. If this property is missing from a > + device, its interrupt parent is assumed to be its devicetree > + parent. > + > + @param [in] Fdt Pointer to a Flattened Device Tree. > + @param [in] Node Offset of the node to start the search. > + @param [out] IntcNode If success, contains the offset of the > + interrupt-controller node. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_NOT_FOUND No interrupt-controller node found. > + @retval EFI_ABORTED An error occurred. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > +**/ > +EFI_STATUS > +EFIAPI > +FdtGetIntcParentNode ( > + IN CONST VOID * Fdt, > + IN INT32 Node, > + OUT INT32 * IntcNode > + ) > +{ > + CONST UINT32 * PHandle; > + INT32 Size; > + CONST VOID * Prop; > + > + if ((Fdt == NULL) || > + (IntcNode == NULL)) { > + ASSERT (0); > + return EFI_INVALID_PARAMETER; > + } > + > + while (TRUE) { > + // Check whether the node has the "interrupt-controller" property. > + Prop = fdt_getprop (Fdt, Node, "interrupt-controller", &Size); > + if ((Prop != NULL) && (Size >= 0)) { > + // The interrupt-controller has been found. > + *IntcNode = Node; > + return EFI_SUCCESS; > + } else { > + // Check whether the node has the "interrupt-parent" property. > + PHandle = fdt_getprop (Fdt, Node, "interrupt-parent", &Size); > + if ((PHandle != NULL) && (Size == sizeof (UINT32))) { > + // The phandle of the interrupt-controller has been found. > + // Search the node having this phandle and return it. > + Node = fdt_node_offset_by_phandle (Fdt, fdt32_to_cpu (*PHandle)); > + if (Node < 0) { > + ASSERT (0); > + return EFI_ABORTED; > + } > + > + *IntcNode = Node; > + return EFI_SUCCESS; > + } else if (Size != -FDT_ERR_NOTFOUND) { > + ASSERT (0); > + return EFI_ABORTED; > + } > + } > + > + if (Node == 0) { > + // We are at the root of the tree. Not parent available. > + return EFI_NOT_FOUND; > + } > + > + // Get the parent of the node. > + Node = fdt_parent_offset (Fdt, Node); > + if (Node < 0) { > + // An error occurred. > + ASSERT (0); > + return EFI_ABORTED; > + } > + } // while > +} > + > +/** Get the "interrupt-cells" property value of the node. > + > + The "interrupts" property requires to know the number of cells used > + to encode an interrupt. This information is stored in the > + interrupt-controller of the input Node. > + > + @param [in] Fdt Pointer to a Flattened Device Tree (Fdt). > + @param [in] IntcNode Offset of an interrupt-controller node. > + @param [out] IntCells If success, contains the "interrupt-cells" > + property of the IntcNode. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_UNSUPPORTED Unsupported. > +**/ > +EFI_STATUS > +EFIAPI > +FdtGetInterruptCellsInfo ( > + IN CONST VOID * Fdt, > + IN INT32 IntcNode, > + OUT INT32 * IntCells > + ) > +{ > + CONST UINT32 * Data; > + INT32 Size; > + > + if ((Fdt == NULL) || > + (IntCells == NULL)) { > + ASSERT (0); > + return EFI_INVALID_PARAMETER; > + } > + > + Data = fdt_getprop (Fdt, IntcNode, "#interrupt-cells", &Size); > + if ((Data == NULL) || (Size != sizeof (UINT32))) { > + // If error or not on one UINT32 cell. > + ASSERT (0); > + return EFI_ABORTED; > + } > + > + *IntCells = fdt32_to_cpu (*Data); > + > + return EFI_SUCCESS; > +} > + > +/** Get the "#address-cells" and/or "#size-cells" property of the node. > + > + According to the Device Tree specification, s2.3.5 "#address-cells and > + #size-cells": > + "If missing, a client program should assume a default value of 2 for > + #address-cells, and a value of 1 for #size-cells." > + > + @param [in] Fdt Pointer to a Flattened Device Tree. > + @param [in] Node Offset of the node having to get the > + "#address-cells" and "#size-cells" > + properties from. > + @param [out] AddressCells If success, number of address-cells. > + If the property is not available, > + default value is 2. > + @param [out] SizeCells If success, number of size-cells. > + If the property is not available, > + default value is 1. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_ABORTED An error occurred. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > +**/ > +EFI_STATUS > +EFIAPI > +FdtGetAddressInfo ( > + IN CONST VOID * Fdt, > + IN INT32 Node, > + OUT INT32 * AddressCells, OPTIONAL > + OUT INT32 * SizeCells OPTIONAL > + ) > +{ > + if (Fdt == NULL) { > + ASSERT (0); > + return EFI_INVALID_PARAMETER; > + } > + > + if (AddressCells != NULL) { > + *AddressCells = fdt_address_cells (Fdt, Node); > + if (*AddressCells < 0) { > + ASSERT (0); > + return EFI_ABORTED; > + } > + } > + > + if (SizeCells != NULL) { > + *SizeCells = fdt_size_cells (Fdt, Node); > + if (*SizeCells < 0) { > + ASSERT (0); > + return EFI_ABORTED; > + } > + } > + > + return EFI_SUCCESS; > +} > + > +/** Get the "#address-cells" and/or "#size-cells" property of the parent node. > + > + According to the Device Tree specification, s2.3.5 "#address-cells and > + #size-cells": > + "If missing, a client program should assume a default value of 2 for > + #address-cells, and a value of 1 for #size-cells." > + > + @param [in] Fdt Pointer to a Flattened Device Tree. > + @param [in] Node Offset of the node having to get the > + "#address-cells" and "#size-cells" > + properties from its parent. > + @param [out] AddressCells If success, number of address-cells. > + If the property is not available, > + default value is 2. > + @param [out] SizeCells If success, number of size-cells. > + If the property is not available, > + default value is 1. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_ABORTED An error occurred. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > +**/ > +EFI_STATUS > +EFIAPI > +FdtGetParentAddressInfo ( > + IN CONST VOID * Fdt, > + IN INT32 Node, > + OUT INT32 * AddressCells, OPTIONAL > + OUT INT32 * SizeCells OPTIONAL > + ) > +{ > + if (Fdt == NULL) { > + ASSERT (0); > + return EFI_INVALID_PARAMETER; > + } > + > + Node = fdt_parent_offset (Fdt, Node); > + if (Node < 0) { > + // End of the tree, or an error occurred. > + ASSERT (0); > + return EFI_ABORTED; > + } > + > + return FdtGetAddressInfo (Fdt, Node, AddressCells, SizeCells); > +} > diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtUtility.h b/DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtUtility.h > new file mode 100644 > index 000000000000..0076c5066d4c > --- /dev/null > +++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtUtility.h > @@ -0,0 +1,458 @@ > +/** @file > + Flattened device tree utility. > + > + Copyright (c) 2021, ARM Limited. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > + @par Reference(s): > + - Device tree Specification - Release v0.3 > + - linux/Documentation/devicetree/bindings/interrupt-controller/arm%2Cgic.yaml > + - linux//Documentation/devicetree/bindings/interrupt-controller/arm%2Cgic.yaml > +**/ > + > +#ifndef FDT_UTILITY_H_ > +#define FDT_UTILITY_H_ > + > +/** Get the offset of an address in a "reg" Device Tree property. > + > + In a Device Tree, the "reg" property stores address/size couples. > + They are stored on N 32-bits cells. > + Based on the value of the #address-cells, the #size-cells and the > + index in the "reg" property, compute the number of 32-bits cells > + to skip. > + > + @param [in] Index Index in the reg property. > + @param [in] AddrCells Number of cells used to store an address. > + @param [in] SizeCells Number of cells used to store the size of > + an address. > + > + @retval Number of 32-bits cells to skip to access the address. > +*/ > +#define GET_DT_REG_ADDRESS_OFFSET(Index, AddrCells, SizeCells) ( \ > + (Index) * ((AddrCells) + (SizeCells)) \ > + ) > + > +/** Get the offset of an address size in a "reg" Device Tree property. > + > + In a Device Tree, the "reg" property stores address/size couples. > + They are stored on N 32-bits cells. > + Based on the value of the #address-cells, the #size-cells and the > + index in the "reg" property, compute the number of 32-bits cells > + to skip. > + > + @param [in] Index Index in the reg property. > + @param [in] AddrCells Number of cells used to store an address. > + @param [in] SizeCells Number of cells used to store the size of > + an address. > + > + @retval Number of 32-bits cells to skip to access the address size. > +*/ > +#define GET_DT_REG_SIZE_OFFSET(Index, AddrCells, SizeCells) ( \ > + GET_DT_REG_ADDRESS_OFFSET ((Index), (AddrCells), (SizeCells)) + \ > + (SizeCells) \ > + ) > + > +/// Maximum string length for compatible names. > +#define COMPATIBLE_STR_LEN (32U) > + > +/// Interrupt macros > +#define PPI_OFFSET (16U) > +#define SPI_OFFSET (32U) > +#define DT_PPI_IRQ (1U) > +#define DT_SPI_IRQ (0U) > +#define DT_IRQ_IS_EDGE_TRIGGERED(x) ((((x) & (BIT0 | BIT2)) != 0)) > +#define DT_IRQ_IS_ACTIVE_LOW(x) ((((x) & (BIT1 | BIT3)) != 0)) > +#define IRQ_TYPE_OFFSET (0U) > +#define IRQ_NUMBER_OFFSET (1U) > +#define IRQ_FLAGS_OFFSET (2U) > + > +/** Get the interrupt Id of an interrupt described in a fdt. > + > + Data must describe a GIC interrupt. A GIC interrupt is on at least > + 3 UINT32 cells. > + This function DOES NOT SUPPORT extended SPI range and extended PPI range. > + > + @param [in] Data Pointer to the first cell of an "interrupts" property. > + > + @retval The interrupt id. > +**/ > +UINT32 > +EFIAPI > +FdtGetInterruptId ( > + UINT32 CONST * Data > + ); > + > +/** Get the ACPI interrupt flags of an interrupt described in a fdt. > + > + Data must describe a GIC interrupt. A GIC interrupt is on at least > + 3 UINT32 cells. > + > + @param [in] Data Pointer to the first cell of an "interrupts" property. > + > + @retval The interrupt flags (for ACPI). > +**/ > +UINT32 > +EFIAPI > +FdtGetInterruptFlags ( > + UINT32 CONST * Data > + ); > + > +/** A structure describing a compatibility string. > +*/ > +typedef struct CompatStr { > + CONST CHAR8 CompatStr[COMPATIBLE_STR_LEN]; > +} COMPATIBILITY_STR; > + > +/** Structure containing a list of compatible names and their count. > +*/ > +typedef struct CompatibilityInfo { > + /// Count of entries in the NAME_TABLE. > + UINT32 Count; > + > + /// Pointer to a table storing the names. > + CONST COMPATIBILITY_STR * CompatTable; > +} COMPATIBILITY_INFO; > + > +/** Operate a check on a Device Tree node. > + > + @param [in] Fdt Pointer to a Flattened Device Tree. > + @param [in] NodeOffset Offset of the node to compare input string. > + @param [in] Context Context to operate the check on the node. > + > + @retval True The check is correct. > + @retval FALSE Otherwise, or error. > +**/ > +typedef > +BOOLEAN > +(EFIAPI *NODE_CHECKER_FUNC) ( > + IN CONST VOID * Fdt, > + IN INT32 NodeOffset, > + IN CONST VOID * Context > + ); > + > +/** Iterate through the list of strings in the Context, > + and check whether at least one string is matching the > + "compatible" property of the node. > + > + @param [in] Fdt Pointer to a Flattened Device Tree. > + @param [in] Node Offset of the node to operate the check on. > + @param [in] CompatInfo COMPATIBILITY_INFO containing the list of compatible > + strings to compare with the "compatible" property > + of the node. > + > + @retval TRUE At least one string matched, the node is compatible. > + @retval FALSE Otherwise, or error. > +**/ > +BOOLEAN > +EFIAPI > +FdtNodeIsCompatible ( > + IN CONST VOID * Fdt, > + IN INT32 Node, > + IN CONST VOID * CompatInfo > + ); > + > +/** Check whether a node has a property. > + > + @param [in] Fdt Pointer to a Flattened Device Tree. > + @param [in] Node Offset of the node to operate the check on. > + @param [in] PropertyName Name of the property to search. > + This is a NULL terminated string. > + > + @retval True The node has the property. > + @retval FALSE Otherwise, or error. > +**/ > +BOOLEAN > +EFIAPI > +FdtNodeHasProperty ( > + IN CONST VOID * Fdt, > + IN INT32 Node, > + IN CONST VOID * PropertyName > + ); > + > +/** Get the next node in a branch having a matching name. > + > + The Device tree is traversed in a depth-first search, starting from Node. > + The input Node is skipped. > + > + @param [in] Fdt Pointer to a Flattened Device Tree. > + @param [in] FdtBranch Only search in the sub-nodes of this branch. > + Write (-1) to search the whole tree. > + @param [in] NodeName The node name to search. > + This is a NULL terminated string. > + @param [in, out] Node At entry: Node offset to start the search. > + This first node is skipped. > + Write (-1) to search the whole tree. > + At exit: If success, contains the offset of > + the next node in the branch > + having a matching name. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_ABORTED An error occurred. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_NOT_FOUND No matching node found. > +**/ > +EFI_STATUS > +EFIAPI > +FdtGetNextNamedNodeInBranch ( > + IN CONST VOID * Fdt, > + IN INT32 FdtBranch, > + IN CONST CHAR8 * NodeName, > + IN OUT INT32 * Node > + ); > + > +/** Get the next node in a branch with at least one compatible property. > + > + The Device tree is traversed in a depth-first search, starting from Node. > + The input Node is skipped. > + > + @param [in] Fdt Pointer to a Flattened Device Tree. > + @param [in] FdtBranch Only search in the sub-nodes of this branch. > + Write (-1) to search the whole tree. > + @param [in] CompatNamesInfo Table of compatible strings to compare with > + the compatible property of the node. > + @param [in, out] Node At entry: Node offset to start the search. > + This first node is skipped. > + Write (-1) to search the whole tree. > + At exit: If success, contains the offset of > + the next node in the branch > + being compatible. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_ABORTED An error occurred. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_NOT_FOUND No matching node found. > +**/ > +EFI_STATUS > +EFIAPI > +FdtGetNextCompatNodeInBranch ( > + IN CONST VOID * Fdt, > + IN INT32 FdtBranch, > + IN CONST COMPATIBILITY_INFO * CompatNamesInfo, > + IN OUT INT32 * Node > + ); > + > +/** Get the next node in a branch having the PropName property. > + > + The Device tree is traversed in a depth-first search, starting from Node. > + The input Node is skipped. > + > + @param [in] Fdt Pointer to a Flattened Device Tree. > + @param [in] FdtBranch Only search in the sub-nodes of this branch. > + Write (-1) to search the whole tree. > + @param [in] PropName Name of the property to search. > + This is a NULL terminated string. > + @param [in, out] Node At entry: Node offset to start the search. > + This first node is skipped. > + Write (-1) to search the whole tree. > + At exit: If success, contains the offset of > + the next node in the branch > + being compatible. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_ABORTED An error occurred. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_NOT_FOUND No matching node found. > +**/ > +EFI_STATUS > +EFIAPI > +FdtGetNextPropNodeInBranch ( > + IN CONST VOID * Fdt, > + IN INT32 FdtBranch, > + IN CONST CHAR8 * PropName, > + IN OUT INT32 * Node > + ); > + > +/** Count the number of nodes in a branch with the input name. > + > + @param [in] Fdt Pointer to a Flattened Device Tree. > + @param [in] FdtBranch Only search in the sub-nodes of this branch. > + Write (-1) to search the whole tree. > + @param [in] NodeName Node name to search. > + This is a NULL terminated string. > + @param [out] NodeCount If success, contains the count of nodes > + fulfilling the condition. > + Can be 0. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_ABORTED An error occurred. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > +**/ > +EFI_STATUS > +EFIAPI > +FdtCountNamedNodeInBranch ( > + IN CONST VOID * Fdt, > + IN INT32 FdtBranch, > + IN CONST CHAR8 * NodeName, > + OUT UINT32 * NodeCount > + ); > + > +/** Count the number of nodes in a branch with at least > + one compatible property. > + > + @param [in] Fdt Pointer to a Flattened Device Tree. > + @param [in] FdtBranch Only search in the sub-nodes of this branch. > + Write (-1) to search the whole tree. > + @param [in] CompatibleTable Table of compatible strings to > + compare with the compatible property > + of the node. > + @param [out] NodeCount If success, contains the count of nodes > + fulfilling the condition. > + Can be 0. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_ABORTED An error occurred. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > +**/ > +EFI_STATUS > +EFIAPI > +FdtCountCompatNodeInBranch ( > + IN CONST VOID * Fdt, > + IN INT32 FdtBranch, > + IN CONST COMPATIBILITY_INFO * CompatNamesInfo, > + OUT UINT32 * NodeCount > + ); > + > +/** Count the number of nodes in a branch having the PropName property. > + > + @param [in] Fdt Pointer to a Flattened Device Tree. > + @param [in] FdtBranch Only search in the sub-nodes of this branch. > + Write (-1) to search the whole tree. > + @param [in] PropName Name of the property to search. > + This is a NULL terminated string. > + @param [out] NodeCount If success, contains the count of nodes > + fulfilling the condition. > + Can be 0. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_ABORTED An error occurred. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > +**/ > +EFI_STATUS > +EFIAPI > +FdtCountPropNodeInBranch ( > + IN CONST VOID * Fdt, > + IN INT32 FdtBranch, > + IN CONST CHAR8 * PropName, > + OUT UINT32 * NodeCount > + ); > + > +/** Get the interrupt-controller node handling the interrupts of > + the input node. > + > + To do this, recursively search a node with either the "interrupt-controller" > + or the "interrupt-parent" property in the parents of Node. > + > + Devicetree Specification, Release v0.3, > + 2.4.1 "Properties for Interrupt Generating Devices": > + Because the hierarchy of the nodes in the interrupt tree > + might not match the devicetree, the interrupt-parent > + property is available to make the definition of an > + interrupt parent explicit. The value is the phandle to the > + interrupt parent. If this property is missing from a > + device, its interrupt parent is assumed to be its devicetree > + parent. > + > + @param [in] Fdt Pointer to a Flattened Device Tree. > + @param [in] Node Offset of the node to start the search. > + @param [out] IntcNode If success, contains the offset of the > + interrupt-controller node. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_NOT_FOUND No interrupt-controller node found. > + @retval EFI_ABORTED An error occurred. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > +**/ > +EFI_STATUS > +EFIAPI > +FdtGetIntcParentNode ( > + IN CONST VOID * Fdt, > + IN INT32 Node, > + OUT INT32 * IntcNode > + ); > + > +/** Get the "interrupt-cells" property value of the node. > + > + The "interrupts" property requires to know the number of cells used > + to encode an interrupt. This information is stored in the > + interrupt-controller of the input Node. > + > + @param [in] Fdt Pointer to a Flattened Device Tree (Fdt). > + @param [in] IntcNode Offset of an interrupt-controller node. > + @param [out] IntCells If success, contains the "interrupt-cells" > + property of the IntcNode. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_UNSUPPORTED Unsupported. > +**/ > +EFI_STATUS > +EFIAPI > +FdtGetInterruptCellsInfo ( > + IN CONST VOID * Fdt, > + IN INT32 IntcNode, > + OUT INT32 * InterruptCells > + ); > + > +/** Get the "#address-cells" and/or "#size-cells" property of the node. > + > + According to the Device Tree specification, s2.3.5 "#address-cells and > + #size-cells": > + "If missing, a client program should assume a default value of 2 for > + #address-cells, and a value of 1 for #size-cells." > + > + @param [in] Fdt Pointer to a Flattened Device Tree. > + @param [in] Node Offset of the node having to get the > + "#address-cells" and "#size-cells" > + properties from. > + @param [out] AddressCells If success, number of address-cells. > + If the property is not available, > + default value is 2. > + @param [out] SizeCells If success, number of size-cells. > + If the property is not available, > + default value is 1. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_ABORTED An error occurred. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > +**/ > +EFI_STATUS > +EFIAPI > +FdtGetAddressInfo ( > + IN CONST VOID * Fdt, > + IN INT32 Node, > + OUT INT32 * AddressCells, OPTIONAL > + OUT INT32 * SizeCells OPTIONAL > + ); > + > +/** Get the "#address-cells" and/or "#size-cells" property of the parent node. > + > + According to the Device Tree specification, s2.3.5 "#address-cells and > + #size-cells": > + "If missing, a client program should assume a default value of 2 for > + #address-cells, and a value of 1 for #size-cells." > + > + @param [in] Fdt Pointer to a Flattened Device Tree. > + @param [in] Node Offset of the node having to get the > + "#address-cells" and "#size-cells" > + properties from its parent. > + @param [out] AddressCells If success, number of address-cells. > + If the property is not available, > + default value is 2. > + @param [out] SizeCells If success, number of size-cells. > + If the property is not available, > + default value is 1. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_ABORTED An error occurred. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > +**/ > +EFI_STATUS > +EFIAPI > +FdtGetParentAddressInfo ( > + IN CONST VOID * Fdt, > + IN INT32 Node, > + OUT INT32 * AddressCells, OPTIONAL > + OUT INT32 * SizeCells OPTIONAL > + ); > + > +#endif // FDT_UTILITY_H_