From nobody Wed May 15 04:43:31 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+109900+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+109900+1787277+3901457@groups.io ARC-Seal: i=1; a=rsa-sha256; t=1698045617; cv=none; d=zohomail.com; s=zohoarc; b=nOI/ONUw1bUfQbJmiLi7svXQn6CSlXmtae8xn+Txm+yuFfpGb7rVrJtwPyhW99fDsEK3a6EMQC8e6uRaUJhDuZaEhNTIE5kbMyKQfMgrTHlja55MFtuurfyMB0ChqdqfUgIR9e7GzPoj35nl39/RbcPqDJ1kdm6eOdtzmDup2aM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1698045617; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=f5oK+l/0e9eT4BK8nidOhsioJ/8VsuG3Jx4Sbziajjo=; b=dqg7GNJf5QTYgoSD9qvWmTlzYdPoGpMyBgqAbgoScdCoMbG1SgWkcrouvL7RRwHz9Reckr5ifOZASPnk2ZaNIx6GIBseTcHNMkrsXQ/K6KmU+GYx3hQqfsr6OsC7EFKzxu5C8eIDQ3icfvZXavmAxI1yssNNXD+3/TH/oB7GNIc= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+109900+1787277+3901457@groups.io Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1698045617079563.3867991923523; Mon, 23 Oct 2023 00:20:17 -0700 (PDT) Return-Path: DKIM-Signature: a=rsa-sha256; bh=KRLEpHNGqpJhj43p1tU9NUeNy/Onqnyk3MMDbDpTwG4=; c=relaxed/simple; d=groups.io; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References:MIME-Version:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Transfer-Encoding:Content-Type; s=20140610; t=1698045616; v=1; b=TYYuAVMlrKoFWlihE5WYCbcgvs3DHISJM0oCKqk/y2Gq9fFS2oXl7gsPCdev3URgIC80dU+K HBey222h8bPzqw6UOXRYA8VrptHQDSp7VOg/NmrOe8JxhLcBafKhjYtKhMjoUgZEvk00aZx09BZ K944mDEUf9EdY2NYRnxHY+AU= X-Received: by 127.0.0.2 with SMTP id 822oYY1788612xZ1WR9Rhqov; Mon, 23 Oct 2023 00:20:16 -0700 X-Received: from ex01.ufhost.com (ex01.ufhost.com [61.152.239.75]) by mx.groups.io with SMTP id smtpd.web11.115587.1698045586233178930 for ; Mon, 23 Oct 2023 00:20:16 -0700 X-Received: from EXMBX166.cuchost.com (unknown [175.102.18.54]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "EXMBX166", Issuer "EXMBX166" (not verified)) by ex01.ufhost.com (Postfix) with ESMTP id 1F6AC24E20F; Mon, 23 Oct 2023 15:19:26 +0800 (CST) X-Received: from EXMBX073.cuchost.com (172.16.6.83) by EXMBX166.cuchost.com (172.16.6.76) with Microsoft SMTP Server (TLS) id 15.0.1497.42; Mon, 23 Oct 2023 15:19:26 +0800 X-Received: from localhost.localdomain (202.188.176.82) by EXMBX073.cuchost.com (172.16.6.83) with Microsoft SMTP Server (TLS) id 15.0.1497.42; Mon, 23 Oct 2023 15:19:22 +0800 From: "John Chew" To: CC: mindachen1987 , Sunil V L , Leif Lindholm , Michael D Kinney , "Cc : Li Yong" , John Chew Subject: [edk2-devel] [PATCH v2 1/4] StarFive/JH7110Pkg: Add Pci controller driver Date: Mon, 23 Oct 2023 15:18:48 +0800 Message-ID: <20231023071851.813-2-yuinyee.chew@starfivetech.com> In-Reply-To: <20231023071851.813-1-yuinyee.chew@starfivetech.com> References: <20231023071851.813-1-yuinyee.chew@starfivetech.com> MIME-Version: 1.0 X-Originating-IP: [202.188.176.82] X-ClientProxiedBy: EXCAS066.cuchost.com (172.16.6.26) To EXMBX073.cuchost.com (172.16.6.83) X-YovoleRuleAgent: yovoleflag Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,yuinyee.chew@starfivetech.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: ZW399IQ3RZLmsuiawv2uBYGax1787277AA= Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1698045618767100001 Content-Type: text/plain; charset="utf-8" From: mindachen1987 v2: - Change Bus, IO, Mem and MemAbove4G "#define" into PCDs [John Chew] v1: - Implement Pci Host Bridge and Pci Segment driver: - JH7110 SoC contains two PCI segment: - PCI Segment 0 (USB): 32-bit Memory: 0x3000_0000 ~ 0x3FFF_FFFF 64-bit Memory: 0x9_0000_0000 ~0x9_4000_0000 - PCI Segment 1 (NVME): 32-bit Memory: 0x3800_0000 ~ 0x37FF_FFFF 64-bit Memory: 0x9_8000_0000 ~0x9_C000_0000 - Non-prefetachable memory is not used in this configuration. Cc: Sunil V L Cc: Leif Lindholm Cc: Michael D Kinney Cc: Cc: Li Yong Co-authored-by: John Chew Signed-off-by: mindachen1987 --- Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.c = | 263 ++++ Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf = | 61 + Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLibConstr= uctor.c | 406 ++++++ Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.c = | 1460 ++++++++++++++++++++ Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.inf = | 33 + 5 files changed, 2223 insertions(+) diff --git a/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBri= dgeLib.c b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridg= eLib.c new file mode 100644 index 000000000000..8b46f6ff58e5 --- /dev/null +++ b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.c @@ -0,0 +1,263 @@ +/** @file + * + * PCI Host Bridge Library instance for StarFive JH7110 SOC + * + * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<= BR> + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma pack(1) + +typedef PACKED struct { + ACPI_HID_DEVICE_PATH AcpiDevicePath; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH; + +#pragma pack () + +STATIC CONST EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mEfiPciRootBridgeDevicePath[= ] =3D { + { + { + { + ACPI_DEVICE_PATH, + ACPI_DP, + { + (UINT8)(sizeof (ACPI_HID_DEVICE_PATH)), + (UINT8)(sizeof (ACPI_HID_DEVICE_PATH) >> 8) + } + }, + EISA_PNP_ID (0x0A08), // PCI Express + 0 + }, + + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + END_DEVICE_PATH_LENGTH, + 0 + } + } + }, + + { + { + { + ACPI_DEVICE_PATH, + ACPI_DP, + { + (UINT8)(sizeof (ACPI_HID_DEVICE_PATH)), + (UINT8)(sizeof (ACPI_HID_DEVICE_PATH) >> 8) + } + }, + EISA_PNP_ID (0x0A08), // PCI Express + 1 + }, + + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + END_DEVICE_PATH_LENGTH, + 0 + } + } + }, +}; + +GLOBAL_REMOVE_IF_UNREFERENCED +CHAR16 *mPciHostBridgeLibAcpiAddressSpaceTypeStr[] =3D { + L"Mem", L"I/O", L"Bus" +}; + +// +// See description in MdeModulePkg/Include/Library/PciHostBridgeLib.h +// +PCI_ROOT_BRIDGE mPciRootBridges[] =3D { + { + 0, // Segment + 0, // Supports + 0, // Attributes + FALSE, // DmaAbove4G + FALSE, // NoExtendedConfigSpace (true= =3D256 byte config, false=3D4k) + FALSE, // ResourceAssigned + EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM | + EFI_PCI_HOST_BRIDGE_MEM64_DECODE, // AllocationAttributes + { + // Bus + FixedPcdGet32 (PcdPciBusMin), + FixedPcdGet32 (PcdPciBusMax) + }, { + // Io + FixedPcdGet64 (PcdPciIoBase), + FixedPcdGet64 (PcdPciIoBase) + FixedPcdGet64 (PcdPciIoSize) - 1, + MAX_UINT64 - FixedPcdGet64 (PcdPciIoOffset) + 1 + }, { + // Mem + FixedPcdGet32 (PcdPci0Mmio32Base), + FixedPcdGet32 (PcdPci0Mmio32Base) + FixedPcdGet32 (PcdPci0Mmio32Size= ) - 1 + }, { + // MemAbove4G + FixedPcdGet64 (PcdPci0Mmio64Base), + FixedPcdGet64 (PcdPci0Mmio64Base) + FixedPcdGet64 (PcdPci0Mmio64Size= ) - 1 + }, + { + // Pefetchable Mem + MAX_UINT32, + 0x0 + }, { + // Pefetchable MemAbove4G + MAX_UINT64, + 0x0 + }, + (EFI_DEVICE_PATH_PROTOCOL *)&mEfiPciRootBridgeDevicePath[0] + }, + { + 1, // Segment + 0, // Supports + 0, // Attributes + FALSE, // DmaAbove4G + FALSE, // NoExtendedConfigSpace (true=3D2= 56 byte config, false=3D4k) + FALSE, // ResourceAssigned + EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM | + EFI_PCI_HOST_BRIDGE_MEM64_DECODE, // AllocationAttributes + { + // Bus + FixedPcdGet32 (PcdPciBusMin), + FixedPcdGet32 (PcdPciBusMax) + }, { + // Io + FixedPcdGet64 (PcdPciIoBase), + FixedPcdGet64 (PcdPciIoBase) + FixedPcdGet64 (PcdPciIoSize) - 1, + MAX_UINT64 - FixedPcdGet64 (PcdPciIoOffset) + 1 + }, { + // Mem + FixedPcdGet32 (PcdPci1Mmio32Base), + FixedPcdGet32 (PcdPci1Mmio32Base) + FixedPcdGet32 (PcdPci1Mmio32Size= ) - 1 + }, { + // MemAbove4G + FixedPcdGet64 (PcdPci1Mmio64Base), + FixedPcdGet64 (PcdPci1Mmio64Base) + FixedPcdGet64 (PcdPci1Mmio64Size= ) - 1 + }, + { + // Pefetchable Mem + MAX_UINT32, + 0x0 + }, { + // Pefetchable MemAbove4G + MAX_UINT64, + 0x0 + }, + (EFI_DEVICE_PATH_PROTOCOL *)&mEfiPciRootBridgeDevicePath[1] + } +}; + +/** + Return all the root bridge instances in an array. + + @param Count Return the count of root bridge instances. + + @return All the root bridge instances in an array. + The array should be passed into PciHostBridgeFreeRootBridges() + when it's not used. +**/ +PCI_ROOT_BRIDGE * +EFIAPI +PciHostBridgeGetRootBridges ( + OUT UINTN *Count + ) +{ + *Count =3D ARRAY_SIZE (mPciRootBridges); + return mPciRootBridges; +} + +/** + Free the root bridge instances array returned from PciHostBridgeGetRootB= ridges(). + + @param Bridges The root bridge instances array. + @param Count The count of the array. +**/ +VOID +EFIAPI +PciHostBridgeFreeRootBridges ( + PCI_ROOT_BRIDGE *Bridges, + UINTN Count + ) +{ +} + +/** + Inform the platform that the resource conflict happens. + + @param HostBridgeHandle Handle of the Host Bridge. + @param Configuration Pointer to PCI I/O and PCI memory resource + descriptors. The Configuration contains the reso= urces + for all the root bridges. The resource for each = root + bridge is terminated with END descriptor and an + additional END is appended indicating the end of= the + entire resources. The resource descriptor field + values follow the description in + EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL + .SubmitResources(). +**/ +VOID +EFIAPI +PciHostBridgeResourceConflict ( + EFI_HANDLE HostBridgeHandle, + VOID *Configuration + ) +{ + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor; + UINTN RootBridgeIndex; + + DEBUG ((DEBUG_ERROR, "PciHostBridge: Resource conflict happens!\n")); + + RootBridgeIndex =3D 0; + Descriptor =3D (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Configuration; + while (Descriptor->Desc =3D=3D ACPI_ADDRESS_SPACE_DESCRIPTOR) { + DEBUG ((DEBUG_ERROR, "RootBridge[%d]:\n", RootBridgeIndex++)); + for ( ; Descriptor->Desc =3D=3D ACPI_ADDRESS_SPACE_DESCRIPTOR; Descrip= tor++) { + ASSERT ( + Descriptor->ResType < + ARRAY_SIZE (mPciHostBridgeLibAcpiAddressSpaceTypeStr) + ); + DEBUG ( + (DEBUG_ERROR, " %s: Length/Alignment =3D 0x%lx / 0x%lx\n", + mPciHostBridgeLibAcpiAddressSpaceTypeStr[Descriptor->ResType= ], + Descriptor->AddrLen, Descriptor->AddrRangeMax + ) + ); + if (Descriptor->ResType =3D=3D ACPI_ADDRESS_SPACE_TYPE_MEM) { + DEBUG ( + (DEBUG_ERROR, " Granularity/SpecificFlag =3D %ld / %02x= %s\n", + Descriptor->AddrSpaceGranularity, Descriptor->SpecificFlag, + ((Descriptor->SpecificFlag & + EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETC= HABLE + ) !=3D 0) ? L" (Prefetchable)" : L"" + ) + ); + } + } + + // + // Skip the END descriptor for root bridge + // + ASSERT (Descriptor->Desc =3D=3D ACPI_END_TAG_DESCRIPTOR); + Descriptor =3D (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)( + (EFI_ACPI_END_TAG_D= ESCRIPTOR *)Descriptor + 1 + ); + } +} diff --git a/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBri= dgeLib.inf b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBri= dgeLib.inf new file mode 100644 index 000000000000..e18e8e57829f --- /dev/null +++ b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.= inf @@ -0,0 +1,61 @@ +## @file +# +# PCI Host Bridge Library instance for StarFive JH7110 SOC +# Liberally borrowed from the SynQuacer +# +# Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<= BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x00010019 + BASE_NAME =3D PciHostBridgeLib + FILE_GUID =3D 606d906f-eba7-d5c6-fcf0-6aeedea00193 + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + LIBRARY_CLASS =3D PciHostBridgeLib|DXE_DRIVER + CONSTRUCTOR =3D JH7110PciHostBridgeLibConstructor + +# +# The following information is for reference only and not required by the = build +# tools. +# +# VALID_ARCHITECTURES =3D ARM AARCH64 RISCV64 +# + +[Sources] + PciHostBridgeLib.c + PciHostBridgeLibConstructor.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec + +[LibraryClasses] + DebugLib + DevicePathLib + MemoryAllocationLib + PcdLib + UefiBootServicesTableLib + +[FixedPcd] + gJH7110TokenSpaceGuid.PcdPciRegBase + gJH7110TokenSpaceGuid.PcdPciBusMmioAdr + gJH7110TokenSpaceGuid.PcdPciBusMmioLen + gJH7110TokenSpaceGuid.PcdPciCpuMmioAdr + gJH7110TokenSpaceGuid.PcdPciBusMin + gJH7110TokenSpaceGuid.PcdPciBusMax + gJH7110TokenSpaceGuid.PcdPciIoBase + gJH7110TokenSpaceGuid.PcdPciIoSize + gJH7110TokenSpaceGuid.PcdPciIoOffset + gJH7110TokenSpaceGuid.PcdPci0Mmio32Base + gJH7110TokenSpaceGuid.PcdPci0Mmio32Size + gJH7110TokenSpaceGuid.PcdPci0Mmio64Base + gJH7110TokenSpaceGuid.PcdPci0Mmio64Size + gJH7110TokenSpaceGuid.PcdPci1Mmio32Base + gJH7110TokenSpaceGuid.PcdPci1Mmio32Size + gJH7110TokenSpaceGuid.PcdPci1Mmio64Base + gJH7110TokenSpaceGuid.PcdPci1Mmio64Size diff --git a/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBri= dgeLibConstructor.c b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/P= ciHostBridgeLibConstructor.c new file mode 100644 index 000000000000..cc505f2723d1 --- /dev/null +++ b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLibC= onstructor.c @@ -0,0 +1,406 @@ +/** @file + * + * PCI Host Bridge Library instance for StarFive JH7110 SOC + * + * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<= BR> + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + * This module initializes the Pci as close to a standard + * PCI root complex as possible. The general information + * for this driver was sourced from. + * + * + **/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RegWrite(addr, data) MmioWrite32((addr), (data)) +#define RegRead(addr, data) ((data) =3D MmioRead32 (addr)) + +#define STG_SYSCON_BASE 0x10240000 + +#define STG_SYSCON_K_RP_NEP_MASK (1 << 8) +#define STG_SYSCON_CKREF_SRC_SHIFT 18 +#define STG_SYSCON_CKREF_SRC_MASK (0x3 << 18) +#define STG_SYSCON_CLKREQ_MASK (1 << 22) +#define STG_SYSCON_BASE 0x10240000 +#define SYS_CLK_BASE 0x13020000 +#define STG_CLK_BASE 0x10230000 +#define SYS_CLK_NOC_OFFSET 0x98 +#define STG_PCIE_CLK_OFFSET 0x20 +#define STG_PCIE_CLKS 0xc +#define STG_PCIE_RESET_OFFSET 0x74 +#define SYS_GPIO_BASE 0x13040000 + +#define PREF_MEM_WIN_64_SUPPORT (1 << 3) +#define PMSG_LTR_SUPPORT (1 << 2) +#define PDLA_LINK_SPEED_GEN2 (1 << 12) +#define PLDA_FUNCTION_DIS (1 << 15) +#define PLDA_FUNC_NUM 4 +#define PLDA_PHY_FUNC_SHIFT 9 +#define PLDA_RP_ENABLE 1 + +#define PCIE_BASIC_STATUS 0x018 +#define PCIE_CFGNUM 0x140 +#define IMASK_LOCAL 0x180 +#define ISTATUS_LOCAL 0x184 +#define IMSI_ADDR 0x190 +#define ISTATUS_MSI 0x194 +#define CFG_SPACE 0x1000 +#define GEN_SETTINGS 0x80 +#define PCIE_PCI_IDS 0x9C +#define PCIE_WINROM 0xFC +#define PMSG_SUPPORT_RX 0x3F0 +#define PCI_MISC 0xB4 + +#define STG_SYSCON_AXI4_SLVL_ARFUNC_MASK 0x7FFF00 +#define STG_SYSCON_AXI4_SLVL_ARFUNC_SHIFT 0x8 +#define STG_SYSCON_AXI4_SLVL_AWFUNC_MASK 0x7FFF +#define STG_SYSCON_AXI4_SLVL_AWFUNC_SHIFT 0x0 + +#define XR3PCI_ATR_AXI4_SLV0 0x800 +#define XR3PCI_ATR_SRC_ADDR_LOW 0x0 +#define XR3PCI_ATR_SRC_ADDR_HIGH 0x4 +#define XR3PCI_ATR_TRSL_ADDR_LOW 0x8 +#define XR3PCI_ATR_TRSL_ADDR_HIGH 0xc +#define XR3PCI_ATR_TRSL_PARAM 0x10 +#define XR3PCI_ATR_TABLE_OFFSET 0x20 +#define XR3PCI_ATR_MAX_TABLE_NUM 8 + +#define XR3PCI_ATR_SRC_ADDR_MASK 0xfffff000 +#define XR3PCI_ATR_TRSL_ADDR_MASK 0xfffff000 +#define XR3PCI_ATR_SRC_WIN_SIZE_SHIFT 1 +#define XR3_PCI_ECAM_SIZE 28 + +#define IDS_PCI_TO_PCI_BRIDGE 0x060400 +#define IDS_CLASS_CODE_SHIFT 8 +#define SYS_GPIO_OUTPUT_OFF 0x40 + +UINT32 AtrTableNum; +UINT64 PCIE_CFG_BASE[2] =3D { FixedPcdGet32 (PcdPci0Mmio64Base) + Fi= xedPcdGet32 (PcdPci0Mmio64Size), + FixedPcdGet32 (PcdPci1Mmio64Base) + Fixe= dPcdGet32 (PcdPci1Mmio64Size) }; +UINT64 PCI_MEMREGION_32[2] =3D { FixedPcdGet32 (PcdPci0Mmio32Base), Fix= edPcdGet32 (PcdPci1Mmio32Base) }; +UINT64 PCI_MEMREGION_64[2] =3D { FixedPcdGet32 (PcdPci0Mmio64Base), Fix= edPcdGet32 (PcdPci1Mmio64Base) }; +UINT64 PCI_MEMREGION_SIZE[2] =3D { 27, 30 }; +UINT32 STG_ARFUNC_OFFSET[2] =3D { 0xc0, 0x270 }; +UINT32 STG_AWFUNC_OFFSET[2] =3D { 0xc4, 0x274 }; +UINT32 STG_RP_REP_OFFSET[2] =3D { 0x130, 0x2e0 }; +UINT32 PCIE_GPIO[2] =3D { 26, 28 }; + +STATIC inline UINT64 +GetPcieRegBase ( + IN UINT32 Port + ) +{ + return PCIE_REG_BASE + Port * 0x1000000; +} + +VOID +PcieRegWrite ( + IN UINT32 Port, + IN UINTN Offset, + IN UINT32 Value + ) +{ + UINT64 Base =3D GetPcieRegBase (Port); + + RegWrite ((UINT64)Base + Offset, Value); +} + +UINT32 +PcieRegRead ( + IN UINT32 Port, + IN UINTN Offset + ) +{ + UINT32 Value =3D 0; + UINT64 Base =3D GetPcieRegBase (Port); + + RegRead ((UINT64)Base + Offset, Value); + return Value; +} + +STATIC VOID +PcieUpdatebits ( + IN UINT64 Base, + IN UINTN Offset, + IN UINT32 Mask, + IN UINT32 val + ) +{ + UINT32 Value =3D 0; + + Value =3D MmioRead32 ((UINT64)Base + Offset); + Value &=3D ~Mask; + Value |=3D val; + MmioWrite32 ((UINT64)Base + Offset, Value); +} + +STATIC +VOID +PcieFuncSet ( + IN UINT32 Port + ) +{ + INTN i; + UINT32 Value; + UINT64 Base =3D GetPcieRegBase (Port); + + /* Disable physical functions except #0 */ + for (i =3D 1; i < PLDA_FUNC_NUM; i++) { + PcieUpdatebits ( + STG_SYSCON_BASE, + STG_ARFUNC_OFFSET[Port], + STG_SYSCON_AXI4_SLVL_ARFUNC_MASK, + (i << PLDA_PHY_FUNC_SHIFT) << + STG_SYSCON_AXI4_SLVL_ARFUNC_SHIFT + ); + PcieUpdatebits ( + STG_SYSCON_BASE, + STG_AWFUNC_OFFSET[Port], + STG_SYSCON_AXI4_SLVL_AWFUNC_MASK, + (i << PLDA_PHY_FUNC_SHIFT) << + STG_SYSCON_AXI4_SLVL_AWFUNC_SHIFT + ); + PcieUpdatebits ( + Base, + PCI_MISC, + PLDA_FUNCTION_DIS, + PLDA_FUNCTION_DIS + ); + } + + PcieUpdatebits ( + STG_SYSCON_BASE, + STG_ARFUNC_OFFSET[Port], + STG_SYSCON_AXI4_SLVL_ARFUNC_MASK, + 0 + ); + PcieUpdatebits ( + STG_SYSCON_BASE, + STG_AWFUNC_OFFSET[Port], + STG_SYSCON_AXI4_SLVL_AWFUNC_MASK, + 0 + ); + + /* Enable root port*/ + PcieUpdatebits ( + Base, + GEN_SETTINGS, + PLDA_RP_ENABLE, + PLDA_RP_ENABLE + ); + + Value =3D (IDS_PCI_TO_PCI_BRIDGE << IDS_CLASS_CODE_SHIFT); + PcieRegWrite (Port, PCIE_PCI_IDS, Value); + + PcieUpdatebits ( + Base, + PMSG_SUPPORT_RX, + PMSG_LTR_SUPPORT, + 0 + ); + + /* Prefetchable memory window 64-bit addressing support */ + PcieUpdatebits ( + Base, + PCIE_WINROM, + PREF_MEM_WIN_64_SUPPORT, + PREF_MEM_WIN_64_SUPPORT + ); +} + +STATIC +VOID +PcieSTGInit ( + IN UINT32 Port + ) +{ + PcieUpdatebits ( + STG_SYSCON_BASE, + STG_RP_REP_OFFSET[Port], + STG_SYSCON_K_RP_NEP_MASK, + STG_SYSCON_K_RP_NEP_MASK + ); + PcieUpdatebits ( + STG_SYSCON_BASE, + STG_AWFUNC_OFFSET[Port], + STG_SYSCON_CKREF_SRC_MASK, + 2 << STG_SYSCON_CKREF_SRC_SHIFT + ); + PcieUpdatebits ( + STG_SYSCON_BASE, + STG_AWFUNC_OFFSET[Port], + STG_SYSCON_CLKREQ_MASK, + STG_SYSCON_CLKREQ_MASK + ); +} + +STATIC +VOID +PcieClockInit ( + IN UINT32 Port + ) +{ + RegWrite ( + STG_CLK_BASE + STG_PCIE_CLK_OFFSET + + Port * STG_PCIE_CLKS, + 1 << 31 + ); /*axi mst0*/ + RegWrite ( + STG_CLK_BASE + STG_PCIE_CLK_OFFSET + + Port * STG_PCIE_CLKS + 4, + 1 << 31 + ); /* apb */ + RegWrite ( + STG_CLK_BASE + STG_PCIE_CLK_OFFSET + + Port * STG_PCIE_CLKS + 8, + 1 << 31 + ); /* tl0 */ +} + +STATIC +VOID +PcieResetDeassert ( + IN UINT32 Port + ) +{ + UINT32 PortOffset =3D Port * 6 + 11; + + PcieUpdatebits ( + STG_CLK_BASE, + STG_PCIE_RESET_OFFSET, + 0x3f << (PortOffset), + 0 + ); /*reset all*/ +} + +VOID +PcieResetAssert ( + IN UINT32 Port + ) +{ + UINT32 PortOffset =3D Port * 6 + 11; + + PcieUpdatebits ( + STG_CLK_BASE, + STG_PCIE_RESET_OFFSET, + 0x3f << (PortOffset), + 0x3f << (PortOffset) + ); /*axi mst0*/ +} + +STATIC +VOID +PcieGpioResetSet ( + IN UINT32 Port, + IN UINT32 Value + ) +{ + UINT32 Remain, Mask; + + Remain =3D PCIE_GPIO[Port] & 0x3; + Mask =3D 0xff << (Remain * 8); + PcieUpdatebits ( + SYS_GPIO_BASE, + SYS_GPIO_OUTPUT_OFF + (PCIE_GPIO[Port] & 0xfffc), + Mask, + Value << (Remain * 8) + ); +} + +STATIC +VOID +PcieAtrInit ( + IN UINT32 Port, + IN UINT64 SrcAddr, + IN UINT64 TrslAddr, + IN UINT32 WinSize, + IN UINT32 Config + ) +{ + UINT64 Base =3D GetPcieRegBase (Port) + XR3PCI_ATR_AXI4_SLV0; + UINT32 Value; + + Base +=3D XR3PCI_ATR_TABLE_OFFSET * AtrTableNum; + AtrTableNum++; + + /* X3PCI_ATR_SRC_ADDR_LOW: + * - bit 0: enable entry, + * - bits 1-6: ATR window size: total size in bytes: 2^(ATR_WSIZE + 1) + * - bits 7-11: reserved + * - bits 12-31: start of source address + */ + Value =3D SrcAddr; + + RegWrite ( + Base + XR3PCI_ATR_SRC_ADDR_LOW, + (Value & XR3PCI_ATR_SRC_ADDR_MASK) | ((WinSize - 1) << 1) | 0x1 + ); + Value =3D SrcAddr >> 32; + + RegWrite (Base + XR3PCI_ATR_SRC_ADDR_HIGH, Value); + Value =3D TrslAddr; + RegWrite (Base + XR3PCI_ATR_TRSL_ADDR_LOW, Value); + Value =3D TrslAddr >> 32; + RegWrite (Base + XR3PCI_ATR_TRSL_ADDR_HIGH, Value); + RegWrite (Base + XR3PCI_ATR_TRSL_PARAM, Config); +} + +EFI_STATUS +EFIAPI +JH7110PciHostBridgeLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + UINT32 PortIndex; + + DEBUG ((DEBUG_ERROR, "PCIe RootBridge constructor\n")); + for (PortIndex =3D 0; PortIndex < 2; PortIndex++) { + PcieSTGInit (PortIndex); + RegWrite (SYS_CLK_BASE + SYS_CLK_NOC_OFFSET, 1 << 31); + PcieClockInit (PortIndex); + PcieResetDeassert (PortIndex); + PcieGpioResetSet (PortIndex, 0); + PcieFuncSet (PortIndex); + + PcieAtrInit ( + PortIndex, + PCIE_CFG_BASE[PortIndex], + 0, + XR3_PCI_ECAM_SIZE, + 1 + ); + PcieAtrInit ( + PortIndex, + PCI_MEMREGION_32[PortIndex], + PCI_MEMREGION_32[PortIndex], + PCI_MEMREGION_SIZE[0], + 0 + ); + PcieAtrInit ( + PortIndex, + PCI_MEMREGION_64[PortIndex], + PCI_MEMREGION_64[PortIndex], + PCI_MEMREGION_SIZE[1], + 0 + ); + PcieGpioResetSet (PortIndex, 1); + MicroSecondDelay (300); + + DEBUG ((DEBUG_ERROR, "PCIe port %d init\n", PortIndex)); + } + + return EFI_SUCCESS; +} diff --git a/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib= .c b/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.c new file mode 100644 index 000000000000..43dca2a6236a --- /dev/null +++ b/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.c @@ -0,0 +1,1460 @@ +/** @file + * + * PCI Segment Library for StarFive JH7110 SoC + * + * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<= BR> + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef enum { + PciCfgWidthUint8 =3D 0, + PciCfgWidthUint16, + PciCfgWidthUint32, + PciCfgWidthMax +} PCI_CFG_WIDTH; + +/* + * This PCIe config space is unusual... + * The root port is the first bytes of the register space (offset 0) + * The individual devices are then selected by computing their BDF index + * and writing that into the CFG_INDEX register (offset 0x9000) + * the "ECAM" data is then read/writeable at CFG_DATA (offset 0x8000) + */ + +#define EFI_PCI_ADDR_BUS(bus) ((bus >> 20) & 0xFF) /* Note PCI_SEGMENT_= LIB_ADDRESS */ +#define EFI_PCI_ADDR_DEV(dev) ((dev >> 15) & 0x1F) +#define EFI_PCI_ADDR_FUN(fun) ((fun >> 12) & 0x07) + +/** + Assert the validity of a PCI Segment address. + A valid PCI Segment address should not contain 1's in bits 28..31 and 48= ..63 + + @param A The address to validate. + @param M Additional bits to assert to be zero. + +**/ +#define ASSERT_INVALID_PCI_SEGMENT_ADDRESS(A, M) \ + ASSERT (((A) & (0xffff0000f0000000ULL | (M))) =3D=3D 0) + +/** + Given the nature of how we access PCI devices, we ensure that + read/write accesses are serialized through the use of a lock. +**/ +STATIC +EFI_LOCK mPciSegmentReadWriteLock =3D EFI_INITIALIZE_LOCK_VARIABLE (TPL_H= IGH_LEVEL); + +// STATIC UINT64 mPciSegmentLastAccess; /* Avoid repeat CFG_INDEX upda= tes */ + +/** + Internal worker function to obtain config space base address. + + @param Address The address that encodes the PCI Bus, Device, Function a= nd + Register. + + @return The value read from the PCI configuration register. + +**/ +STATIC +UINT64 +PciSegmentLibGetConfigBase ( + IN UINT64 Address, + IN UINT16 Segment, + IN UINT32 Write + ) +{ + UINT64 Base; + UINT64 Offset; + UINT32 Dev; + UINT32 Bus; + + Base =3D PCIE_CONFIG_BASE; + Offset =3D Address & 0xFFF; /* Pick off the 4k register offset */ + Address &=3D 0xFFFF000; /* Clear the offset leave only the BD= F */ + + /* The root port is at the base of the PCIe register space */ + if (Address !=3D 0) { + Dev =3D EFI_PCI_ADDR_DEV (Address); + Bus =3D EFI_PCI_ADDR_BUS (Address); + + /* + * There can only be a single device on bus 1 (downstream of root). + * Subsequent busses (behind a PCIe switch) can have more. + */ + if (Dev > 0) { + return 0xFFFFFFFF; + } + + return Base + Segment * 0x80000000 + Address + Offset; + } else { + if (Write && ((Offset =3D=3D 0x10) || (Offset =3D=3D 0x14))) { + return 0xFFFFFFFF; + } + } + + return Base + Segment * 0x80000000 + Offset; +} + +/** + Internal worker function to read a PCI configuration register. + + @param Address The address that encodes the PCI Bus, Device, Function a= nd + Register. + @param Width The width of data to read + + @return The value read from the PCI configuration register. + +**/ +STATIC +UINT32 +PciSegmentLibReadWorker ( + IN UINT64 Address, + IN PCI_CFG_WIDTH Width + ) +{ + UINT64 Base; + UINT32 Ret; + UINT16 Segment =3D (Address >> 32); + + EfiAcquireLock (&mPciSegmentReadWriteLock); + Base =3D PciSegmentLibGetConfigBase (Address, Segment, 0); + + if (Base =3D=3D 0xFFFFFFFF) { + EfiReleaseLock (&mPciSegmentReadWriteLock); + return Base; + } + + switch (Width) { + case PciCfgWidthUint8: + Ret =3D MmioRead8 (Base); + break; + case PciCfgWidthUint16: + Ret =3D MmioRead16 (Base); + break; + case PciCfgWidthUint32: + Ret =3D MmioRead32 (Base); + break; + default: + ASSERT (FALSE); + Ret =3D 0; + } + + EfiReleaseLock (&mPciSegmentReadWriteLock); + // DEBUG ((DEBUG_ERROR, "PCIe seg read Address %lx %lx width %d val %x S= egment %d\n", Base, Address, Width, Ret, Segment)); + return Ret; +} + +/** + Internal worker function to writes a PCI configuration register. + + @param Address The address that encodes the PCI Bus, Device, Function a= nd + Register. + @param Width The width of data to write + @param Data The value to write. + + @return The value written to the PCI configuration register. + +**/ +STATIC +UINT32 +PciSegmentLibWriteWorker ( + IN UINT64 Address, + IN PCI_CFG_WIDTH Width, + IN UINT32 Data + ) +{ + UINT64 Base; + UINT16 Segment =3D (Address >> 32); + + EfiAcquireLock (&mPciSegmentReadWriteLock); + Base =3D PciSegmentLibGetConfigBase (Address, Segment, 1); + + if (Base =3D=3D 0xFFFFFFFF) { + EfiReleaseLock (&mPciSegmentReadWriteLock); + return Data; + } + + switch (Width) { + case PciCfgWidthUint8: + MmioWrite8 (Base, Data); + break; + case PciCfgWidthUint16: + MmioWrite16 (Base, Data); + break; + case PciCfgWidthUint32: + MmioWrite32 (Base, Data); + break; + default: + ASSERT (FALSE); + } + + EfiReleaseLock (&mPciSegmentReadWriteLock); + return Data; +} + +/** + Register a PCI device so PCI configuration registers may be accessed aft= er + SetVirtualAddressMap(). + + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Bus, Device, Function a= nd + Register. + + @retval RETURN_SUCCESS The PCI device was registered for runti= me access. + @retval RETURN_UNSUPPORTED An attempt was made to call this functi= on + after ExitBootServices(). + @retval RETURN_UNSUPPORTED The resources required to access the PC= I device + at runtime could not be mapped. + @retval RETURN_OUT_OF_RESOURCES There are not enough resources availabl= e to + complete the registration. + +**/ +RETURN_STATUS +EFIAPI +PciSegmentRegisterForRuntimeAccess ( + IN UINTN Address + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0); + return RETURN_UNSUPPORTED; +} + +/** + Reads an 8-bit PCI configuration register. + + Reads and returns the 8-bit PCI configuration register specified by Addr= ess. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device,= Function, + and Register. + + @return The 8-bit PCI configuration register specified by Address. + +**/ +UINT8 +EFIAPI +PciSegmentRead8 ( + IN UINT64 Address + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0); + + return (UINT8)PciSegmentLibReadWorker (Address, PciCfgWidthUint8); +} + +/** + Writes an 8-bit PCI configuration register. + + Writes the 8-bit PCI configuration register specified by Address with th= e value specified by Value. + Value is returned. This function must guarantee that all PCI read and w= rite operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Devic= e, Function, and Register. + @param Value The value to write. + + @return The value written to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentWrite8 ( + IN UINT64 Address, + IN UINT8 Value + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0); + + return (UINT8)PciSegmentLibWriteWorker (Address, PciCfgWidthUint8, Value= ); +} + +/** + Performs a bitwise OR of an 8-bit PCI configuration register with an 8-b= it value. + + Reads the 8-bit PCI configuration register specified by Address, + performs a bitwise OR between the read result and the value specified by= OrData, + and writes the result to the 8-bit PCI configuration register specified = by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device,= Function, and Register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentOr8 ( + IN UINT64 Address, + IN UINT8 OrData + ) +{ + return PciSegmentWrite8 (Address, (UINT8)(PciSegmentRead8 (Address) | Or= Data)); +} + +/** + Performs a bitwise AND of an 8-bit PCI configuration register with an 8-= bit value. + + Reads the 8-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified b= y AndData, + and writes the result to the 8-bit PCI configuration register specified = by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are = serialized. + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device,= Function, and Register. + @param AndData The value to AND with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentAnd8 ( + IN UINT64 Address, + IN UINT8 AndData + ) +{ + return PciSegmentWrite8 (Address, (UINT8)(PciSegmentRead8 (Address) & An= dData)); +} + +/** + Performs a bitwise AND of an 8-bit PCI configuration register with an 8-= bit value, + followed a bitwise OR with another 8-bit value. + + Reads the 8-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified b= y AndData, + performs a bitwise OR between the result of the AND operation and the va= lue specified by OrData, + and writes the result to the 8-bit PCI configuration register specified = by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device,= Function, and Register. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentAndThenOr8 ( + IN UINT64 Address, + IN UINT8 AndData, + IN UINT8 OrData + ) +{ + return PciSegmentWrite8 (Address, (UINT8)((PciSegmentRead8 (Address) & A= ndData) | OrData)); +} + +/** + Reads a bit field of a PCI configuration register. + + Reads the bit field in an 8-bit PCI configuration register. The bit fiel= d is + specified by the StartBit and the EndBit. The value of the bit field is + returned. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 7, then ASSERT(). + If EndBit is greater than 7, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + + @param Address The PCI configuration register to read. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..7. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..7. + + @return The value of the bit field read from the PCI configuration regis= ter. + +**/ +UINT8 +EFIAPI +PciSegmentBitFieldRead8 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit + ) +{ + return BitFieldRead8 (PciSegmentRead8 (Address), StartBit, EndBit); +} + +/** + Writes a bit field to a PCI configuration register. + + Writes Value to the bit field of the PCI configuration register. The bit + field is specified by the StartBit and the EndBit. All other bits in the + destination PCI configuration register are preserved. The new value of t= he + 8-bit register is returned. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 7, then ASSERT(). + If EndBit is greater than 7, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If Value is larger than the bitmask value range specified by StartBit an= d EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..7. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..7. + @param Value The new value of the bit field. + + @return The value written back to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentBitFieldWrite8 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT8 Value + ) +{ + return PciSegmentWrite8 ( + Address, + BitFieldWrite8 (PciSegmentRead8 (Address), Star= tBit, EndBit, Value) + ); +} + +/** + Reads a bit field in an 8-bit PCI configuration, performs a bitwise OR, = and + writes the result back to the bit field in the 8-bit port. + + Reads the 8-bit PCI configuration register specified by Address, perform= s a + bitwise OR between the read result and the value specified by + OrData, and writes the result to the 8-bit PCI configuration register + specified by Address. The value written to the PCI configuration registe= r is + returned. This function must guarantee that all PCI read and write opera= tions + are serialized. Extra left bits in OrData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 7, then ASSERT(). + If EndBit is greater than 7, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit a= nd EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..7. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..7. + @param OrData The value to OR with the PCI configuration register. + + @return The value written back to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentBitFieldOr8 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT8 OrData + ) +{ + return PciSegmentWrite8 ( + Address, + BitFieldOr8 (PciSegmentRead8 (Address), StartBi= t, EndBit, OrData) + ); +} + +/** + Reads a bit field in an 8-bit PCI configuration register, performs a bit= wise + AND, and writes the result back to the bit field in the 8-bit register. + + Reads the 8-bit PCI configuration register specified by Address, perform= s a + bitwise AND between the read result and the value specified by AndData, = and + writes the result to the 8-bit PCI configuration register specified by + Address. The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are + serialized. Extra left bits in AndData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 7, then ASSERT(). + If EndBit is greater than 7, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit = and EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..7. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..7. + @param AndData The value to AND with the PCI configuration register. + + @return The value written back to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentBitFieldAnd8 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT8 AndData + ) +{ + return PciSegmentWrite8 ( + Address, + BitFieldAnd8 (PciSegmentRead8 (Address), StartB= it, EndBit, AndData) + ); +} + +/** + Reads a bit field in an 8-bit port, performs a bitwise AND followed by a + bitwise OR, and writes the result back to the bit field in the + 8-bit port. + + Reads the 8-bit PCI configuration register specified by Address, perform= s a + bitwise AND followed by a bitwise OR between the read result and + the value specified by AndData, and writes the result to the 8-bit PCI + configuration register specified by Address. The value written to the PCI + configuration register is returned. This function must guarantee that al= l PCI + read and write operations are serialized. Extra left bits in both AndDat= a and + OrData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 7, then ASSERT(). + If EndBit is greater than 7, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit = and EndBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit a= nd EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..7. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..7. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the result of the AND operation. + + @return The value written back to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentBitFieldAndThenOr8 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT8 AndData, + IN UINT8 OrData + ) +{ + return PciSegmentWrite8 ( + Address, + BitFieldAndThenOr8 (PciSegmentRead8 (Address), = StartBit, EndBit, AndData, OrData) + ); +} + +/** + Reads a 16-bit PCI configuration register. + + Reads and returns the 16-bit PCI configuration register specified by Add= ress. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device,= Function, and Register. + + @return The 16-bit PCI configuration register specified by Address. + +**/ +UINT16 +EFIAPI +PciSegmentRead16 ( + IN UINT64 Address + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 1); + + return (UINT16)PciSegmentLibReadWorker (Address, PciCfgWidthUint16); +} + +/** + Writes a 16-bit PCI configuration register. + + Writes the 16-bit PCI configuration register specified by Address with t= he value specified by Value. + Value is returned. This function must guarantee that all PCI read and w= rite operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Devic= e, Function, and Register. + @param Value The value to write. + + @return The parameter of Value. + +**/ +UINT16 +EFIAPI +PciSegmentWrite16 ( + IN UINT64 Address, + IN UINT16 Value + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 1); + + return (UINT16)PciSegmentLibWriteWorker (Address, PciCfgWidthUint16, Val= ue); +} + +/** + Performs a bitwise OR of a 16-bit PCI configuration register with + a 16-bit value. + + Reads the 16-bit PCI configuration register specified by Address, perfor= ms a + bitwise OR between the read result and the value specified by + OrData, and writes the result to the 16-bit PCI configuration register + specified by Address. The value written to the PCI configuration registe= r is + returned. This function must guarantee that all PCI read and write opera= tions + are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, F= unction and + Register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written back to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentOr16 ( + IN UINT64 Address, + IN UINT16 OrData + ) +{ + return PciSegmentWrite16 (Address, (UINT16)(PciSegmentRead16 (Address) |= OrData)); +} + +/** + Performs a bitwise AND of a 16-bit PCI configuration register with a 16-= bit value. + + Reads the 16-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified b= y AndData, + and writes the result to the 16-bit PCI configuration register specified= by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device,= Function, and Register. + @param AndData The value to AND with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentAnd16 ( + IN UINT64 Address, + IN UINT16 AndData + ) +{ + return PciSegmentWrite16 (Address, (UINT16)(PciSegmentRead16 (Address) &= AndData)); +} + +/** + Performs a bitwise AND of a 16-bit PCI configuration register with a 16-= bit value, + followed a bitwise OR with another 16-bit value. + + Reads the 16-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified b= y AndData, + performs a bitwise OR between the result of the AND operation and the va= lue specified by OrData, + and writes the result to the 16-bit PCI configuration register specified= by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device,= Function, and Register. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentAndThenOr16 ( + IN UINT64 Address, + IN UINT16 AndData, + IN UINT16 OrData + ) +{ + return PciSegmentWrite16 (Address, (UINT16)((PciSegmentRead16 (Address) = & AndData) | OrData)); +} + +/** + Reads a bit field of a PCI configuration register. + + Reads the bit field in a 16-bit PCI configuration register. The bit fiel= d is + specified by the StartBit and the EndBit. The value of the bit field is + returned. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + If StartBit is greater than 15, then ASSERT(). + If EndBit is greater than 15, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + + @param Address The PCI configuration register to read. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..15. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..15. + + @return The value of the bit field read from the PCI configuration regis= ter. + +**/ +UINT16 +EFIAPI +PciSegmentBitFieldRead16 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit + ) +{ + return BitFieldRead16 (PciSegmentRead16 (Address), StartBit, EndBit); +} + +/** + Writes a bit field to a PCI configuration register. + + Writes Value to the bit field of the PCI configuration register. The bit + field is specified by the StartBit and the EndBit. All other bits in the + destination PCI configuration register are preserved. The new value of t= he + 16-bit register is returned. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + If StartBit is greater than 15, then ASSERT(). + If EndBit is greater than 15, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If Value is larger than the bitmask value range specified by StartBit an= d EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..15. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..15. + @param Value The new value of the bit field. + + @return The value written back to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentBitFieldWrite16 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT16 Value + ) +{ + return PciSegmentWrite16 ( + Address, + BitFieldWrite16 (PciSegmentRead16 (Address), S= tartBit, EndBit, Value) + ); +} + +/** + Reads the 16-bit PCI configuration register specified by Address, + performs a bitwise OR between the read result and the value specified by= OrData, + and writes the result to the 16-bit PCI configuration register specified= by Address. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + If StartBit is greater than 15, then ASSERT(). + If EndBit is greater than 15, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit a= nd EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..15. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..15. + @param OrData The value to OR with the PCI configuration register. + + @return The value written back to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentBitFieldOr16 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT16 OrData + ) +{ + return PciSegmentWrite16 ( + Address, + BitFieldOr16 (PciSegmentRead16 (Address), Star= tBit, EndBit, OrData) + ); +} + +/** + Reads a bit field in a 16-bit PCI configuration, performs a bitwise OR, + and writes the result back to the bit field in the 16-bit port. + + Reads the 16-bit PCI configuration register specified by Address, + performs a bitwise OR between the read result and the value specified by= OrData, + and writes the result to the 16-bit PCI configuration register specified= by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are = serialized. + Extra left bits in OrData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + If StartBit is greater than 7, then ASSERT(). + If EndBit is greater than 7, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit = and EndBit, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device,= Function, and Register. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + The ordinal of the least significant bit in a byte is = bit 0. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + The ordinal of the most significant bit in a byte is b= it 7. + @param AndData The value to AND with the read value from the PCI conf= iguration register. + + @return The value written to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentBitFieldAnd16 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT16 AndData + ) +{ + return PciSegmentWrite16 ( + Address, + BitFieldAnd16 (PciSegmentRead16 (Address), Sta= rtBit, EndBit, AndData) + ); +} + +/** + Reads a bit field in a 16-bit port, performs a bitwise AND followed by a + bitwise OR, and writes the result back to the bit field in the + 16-bit port. + + Reads the 16-bit PCI configuration register specified by Address, perfor= ms a + bitwise AND followed by a bitwise OR between the read result and + the value specified by AndData, and writes the result to the 16-bit PCI + configuration register specified by Address. The value written to the PCI + configuration register is returned. This function must guarantee that al= l PCI + read and write operations are serialized. Extra left bits in both AndDat= a and + OrData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 15, then ASSERT(). + If EndBit is greater than 15, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit = and EndBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit a= nd EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..15. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..15. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the result of the AND operation. + + @return The value written back to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentBitFieldAndThenOr16 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT16 AndData, + IN UINT16 OrData + ) +{ + return PciSegmentWrite16 ( + Address, + BitFieldAndThenOr16 (PciSegmentRead16 (Address= ), StartBit, EndBit, AndData, OrData) + ); +} + +/** + Reads a 32-bit PCI configuration register. + + Reads and returns the 32-bit PCI configuration register specified by Add= ress. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device,= Function, + and Register. + + @return The 32-bit PCI configuration register specified by Address. + +**/ +UINT32 +EFIAPI +PciSegmentRead32 ( + IN UINT64 Address + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3); + + return PciSegmentLibReadWorker (Address, PciCfgWidthUint32); +} + +/** + Writes a 32-bit PCI configuration register. + + Writes the 32-bit PCI configuration register specified by Address with t= he value specified by Value. + Value is returned. This function must guarantee that all PCI read and w= rite operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Devic= e, + Function, and Register. + @param Value The value to write. + + @return The parameter of Value. + +**/ +UINT32 +EFIAPI +PciSegmentWrite32 ( + IN UINT64 Address, + IN UINT32 Value + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3); + + return PciSegmentLibWriteWorker (Address, PciCfgWidthUint32, Value); +} + +/** + Performs a bitwise OR of a 32-bit PCI configuration register with a 32-b= it value. + + Reads the 32-bit PCI configuration register specified by Address, + performs a bitwise OR between the read result and the value specified by= OrData, + and writes the result to the 32-bit PCI configuration register specified= by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device,= Function, and Register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentOr32 ( + IN UINT64 Address, + IN UINT32 OrData + ) +{ + return PciSegmentWrite32 (Address, PciSegmentRead32 (Address) | OrData); +} + +/** + Performs a bitwise AND of a 32-bit PCI configuration register with a 32-= bit value. + + Reads the 32-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified b= y AndData, + and writes the result to the 32-bit PCI configuration register specified= by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device,= Function, + and Register. + @param AndData The value to AND with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentAnd32 ( + IN UINT64 Address, + IN UINT32 AndData + ) +{ + return PciSegmentWrite32 (Address, PciSegmentRead32 (Address) & AndData); +} + +/** + Performs a bitwise AND of a 32-bit PCI configuration register with a 32-= bit value, + followed a bitwise OR with another 32-bit value. + + Reads the 32-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified b= y AndData, + performs a bitwise OR between the result of the AND operation and the va= lue specified by OrData, + and writes the result to the 32-bit PCI configuration register specified= by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are = serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device,= Function, + and Register. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentAndThenOr32 ( + IN UINT64 Address, + IN UINT32 AndData, + IN UINT32 OrData + ) +{ + return PciSegmentWrite32 (Address, (PciSegmentRead32 (Address) & AndData= ) | OrData); +} + +/** + Reads a bit field of a PCI configuration register. + + Reads the bit field in a 32-bit PCI configuration register. The bit fiel= d is + specified by the StartBit and the EndBit. The value of the bit field is + returned. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + If StartBit is greater than 31, then ASSERT(). + If EndBit is greater than 31, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + + @param Address The PCI configuration register to read. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..31. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..31. + + @return The value of the bit field read from the PCI configuration regis= ter. + +**/ +UINT32 +EFIAPI +PciSegmentBitFieldRead32 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit + ) +{ + return BitFieldRead32 (PciSegmentRead32 (Address), StartBit, EndBit); +} + +/** + Writes a bit field to a PCI configuration register. + + Writes Value to the bit field of the PCI configuration register. The bit + field is specified by the StartBit and the EndBit. All other bits in the + destination PCI configuration register are preserved. The new value of t= he + 32-bit register is returned. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + If StartBit is greater than 31, then ASSERT(). + If EndBit is greater than 31, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If Value is larger than the bitmask value range specified by StartBit an= d EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..31. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..31. + @param Value The new value of the bit field. + + @return The value written back to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentBitFieldWrite32 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT32 Value + ) +{ + return PciSegmentWrite32 ( + Address, + BitFieldWrite32 (PciSegmentRead32 (Address), S= tartBit, EndBit, Value) + ); +} + +/** + Reads a bit field in a 32-bit PCI configuration, performs a bitwise OR, = and + writes the result back to the bit field in the 32-bit port. + + Reads the 32-bit PCI configuration register specified by Address, perfor= ms a + bitwise OR between the read result and the value specified by + OrData, and writes the result to the 32-bit PCI configuration register + specified by Address. The value written to the PCI configuration registe= r is + returned. This function must guarantee that all PCI read and write opera= tions + are serialized. Extra left bits in OrData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 31, then ASSERT(). + If EndBit is greater than 31, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit a= nd EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..31. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..31. + @param OrData The value to OR with the PCI configuration register. + + @return The value written back to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentBitFieldOr32 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT32 OrData + ) +{ + return PciSegmentWrite32 ( + Address, + BitFieldOr32 (PciSegmentRead32 (Address), Star= tBit, EndBit, OrData) + ); +} + +/** + Reads a bit field in a 32-bit PCI configuration register, performs a bit= wise + AND, and writes the result back to the bit field in the 32-bit register. + + + Reads the 32-bit PCI configuration register specified by Address, perfor= ms a bitwise + AND between the read result and the value specified by AndData, and writ= es the result + to the 32-bit PCI configuration register specified by Address. The value= written to + the PCI configuration register is returned. This function must guarante= e that all PCI + read and write operations are serialized. Extra left bits in AndData ar= e stripped. + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + If StartBit is greater than 31, then ASSERT(). + If EndBit is greater than 31, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit = and EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..31. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..31. + @param AndData The value to AND with the PCI configuration register. + + @return The value written back to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentBitFieldAnd32 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT32 AndData + ) +{ + return PciSegmentWrite32 ( + Address, + BitFieldAnd32 (PciSegmentRead32 (Address), Sta= rtBit, EndBit, AndData) + ); +} + +/** + Reads a bit field in a 32-bit port, performs a bitwise AND followed by a + bitwise OR, and writes the result back to the bit field in the + 32-bit port. + + Reads the 32-bit PCI configuration register specified by Address, perfor= ms a + bitwise AND followed by a bitwise OR between the read result and + the value specified by AndData, and writes the result to the 32-bit PCI + configuration register specified by Address. The value written to the PCI + configuration register is returned. This function must guarantee that al= l PCI + read and write operations are serialized. Extra left bits in both AndDat= a and + OrData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 31, then ASSERT(). + If EndBit is greater than 31, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit = and EndBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit a= nd EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit fi= eld. + Range 0..31. + @param EndBit The ordinal of the most significant bit in the bit fie= ld. + Range 0..31. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the result of the AND operation. + + @return The value written back to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentBitFieldAndThenOr32 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT32 AndData, + IN UINT32 OrData + ) +{ + return PciSegmentWrite32 ( + Address, + BitFieldAndThenOr32 (PciSegmentRead32 (Address= ), StartBit, EndBit, AndData, OrData) + ); +} + +/** + Reads a range of PCI configuration registers into a caller supplied buff= er. + + Reads the range of PCI configuration registers specified by StartAddress= and + Size into the buffer specified by Buffer. This function only allows the = PCI + configuration registers from a single PCI function to be read. Size is + returned. When possible 32-bit PCI configuration read cycles are used to= read + from StartAdress to StartAddress + Size. Due to alignment restrictions, = 8-bit + and 16-bit PCI configuration read cycles may be used at the beginning an= d the + end of the range. + + If any reserved bits in StartAddress are set, then ASSERT(). + If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT(). + If Size > 0 and Buffer is NULL, then ASSERT(). + + @param StartAddress The starting address that encodes the PCI Segment,= Bus, + Device, Function and Register. + @param Size The size in bytes of the transfer. + @param Buffer The pointer to a buffer receiving the data read. + + @return Size + +**/ +UINTN +EFIAPI +PciSegmentReadBuffer ( + IN UINT64 StartAddress, + IN UINTN Size, + OUT VOID *Buffer + ) +{ + UINTN ReturnValue; + + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (StartAddress, 0); + ASSERT (((StartAddress & 0xFFF) + Size) <=3D 0x1000); + + if (Size =3D=3D 0) { + return Size; + } + + ASSERT (Buffer !=3D NULL); + + // + // Save Size for return + // + ReturnValue =3D Size; + + if ((StartAddress & BIT0) !=3D 0) { + // + // Read a byte if StartAddress is byte aligned + // + *(volatile UINT8 *)Buffer =3D PciSegmentRead8 (StartAddress); + StartAddress +=3D sizeof (UINT8); + Size -=3D sizeof (UINT8); + Buffer =3D (UINT8 *)Buffer + 1; + } + + if ((Size >=3D sizeof (UINT16)) && ((StartAddress & BIT1) !=3D 0)) { + // + // Read a word if StartAddress is word aligned + // + WriteUnaligned16 (Buffer, PciSegmentRead16 (StartAddress)); + StartAddress +=3D sizeof (UINT16); + Size -=3D sizeof (UINT16); + Buffer =3D (UINT16 *)Buffer + 1; + } + + while (Size >=3D sizeof (UINT32)) { + // + // Read as many double words as possible + // + WriteUnaligned32 (Buffer, PciSegmentRead32 (StartAddress)); + StartAddress +=3D sizeof (UINT32); + Size -=3D sizeof (UINT32); + Buffer =3D (UINT32 *)Buffer + 1; + } + + if (Size >=3D sizeof (UINT16)) { + // + // Read the last remaining word if exist + // + WriteUnaligned16 (Buffer, PciSegmentRead16 (StartAddress)); + StartAddress +=3D sizeof (UINT16); + Size -=3D sizeof (UINT16); + Buffer =3D (UINT16 *)Buffer + 1; + } + + if (Size >=3D sizeof (UINT8)) { + // + // Read the last remaining byte if exist + // + *(volatile UINT8 *)Buffer =3D PciSegmentRead8 (StartAddress); + } + + return ReturnValue; +} + +/** + Copies the data in a caller supplied buffer to a specified range of PCI + configuration space. + + Writes the range of PCI configuration registers specified by StartAddres= s and + Size from the buffer specified by Buffer. This function only allows the = PCI + configuration registers from a single PCI function to be written. Size is + returned. When possible 32-bit PCI configuration write cycles are used to + write from StartAdress to StartAddress + Size. Due to alignment restrict= ions, + 8-bit and 16-bit PCI configuration write cycles may be used at the begin= ning + and the end of the range. + + If any reserved bits in StartAddress are set, then ASSERT(). + If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT(). + If Size > 0 and Buffer is NULL, then ASSERT(). + + @param StartAddress The starting address that encodes the PCI Segment,= Bus, + Device, Function and Register. + @param Size The size in bytes of the transfer. + @param Buffer The pointer to a buffer containing the data to wri= te. + + @return The parameter of Size. + +**/ +UINTN +EFIAPI +PciSegmentWriteBuffer ( + IN UINT64 StartAddress, + IN UINTN Size, + IN VOID *Buffer + ) +{ + UINTN ReturnValue; + + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (StartAddress, 0); + ASSERT (((StartAddress & 0xFFF) + Size) <=3D 0x1000); + + if (Size =3D=3D 0) { + return 0; + } + + ASSERT (Buffer !=3D NULL); + + // The Bcm/Rpi has a single cfg which can be mapped + // to any given device on the bus, which means we need to remap + // it basically everytime a new config access is done + + // + // Save Size for return + // + ReturnValue =3D Size; + + if ((StartAddress & BIT0) !=3D 0) { + // + // Write a byte if StartAddress is byte aligned + // + PciSegmentWrite8 (StartAddress, *(UINT8 *)Buffer); + StartAddress +=3D sizeof (UINT8); + Size -=3D sizeof (UINT8); + Buffer =3D (UINT8 *)Buffer + 1; + } + + if ((Size >=3D sizeof (UINT16)) && ((StartAddress & BIT1) !=3D 0)) { + // + // Write a word if StartAddress is word aligned + // + PciSegmentWrite16 (StartAddress, ReadUnaligned16 (Buffer)); + StartAddress +=3D sizeof (UINT16); + Size -=3D sizeof (UINT16); + Buffer =3D (UINT16 *)Buffer + 1; + } + + while (Size >=3D sizeof (UINT32)) { + // + // Write as many double words as possible + // + PciSegmentWrite32 (StartAddress, ReadUnaligned32 (Buffer)); + StartAddress +=3D sizeof (UINT32); + Size -=3D sizeof (UINT32); + Buffer =3D (UINT32 *)Buffer + 1; + } + + if (Size >=3D sizeof (UINT16)) { + // + // Write the last remaining word if exist + // + PciSegmentWrite16 (StartAddress, ReadUnaligned16 (Buffer)); + StartAddress +=3D sizeof (UINT16); + Size -=3D sizeof (UINT16); + Buffer =3D (UINT16 *)Buffer + 1; + } + + if (Size >=3D sizeof (UINT8)) { + // + // Write the last remaining byte if exist + // + PciSegmentWrite8 (StartAddress, *(UINT8 *)Buffer); + } + + return ReturnValue; +} diff --git a/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib= .inf b/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.inf new file mode 100644 index 000000000000..063c85ebc428 --- /dev/null +++ b/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.inf @@ -0,0 +1,33 @@ +## @file +# PCI Segment Library for StarFive JH7110 SoC +# +# Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x0001001B + BASE_NAME =3D PciSegmentLib + FILE_GUID =3D 832163a2-41f5-c529-3f02-77fb68abbc2c + MODULE_TYPE =3D BASE + VERSION_STRING =3D 1.0 + LIBRARY_CLASS =3D PciSegmentLib + +[Sources] + PciSegmentLib.c + +[Packages] + MdePkg/MdePkg.dec + Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec + +[LibraryClasses] + BaseLib + DebugLib + IoLib + PcdLib + UefiLib + +[FixedPcd] + gJH7110TokenSpaceGuid.PcdPciConfigRegBase --=20 2.34.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#109900): https://edk2.groups.io/g/devel/message/109900 Mute This Topic: https://groups.io/mt/102130712/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- From nobody Wed May 15 04:43:31 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+109897+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+109897+1787277+3901457@groups.io ARC-Seal: i=1; a=rsa-sha256; t=1698045579; cv=none; d=zohomail.com; s=zohoarc; b=JK0id7bIM/Gc497gGkVNfvVITIcTj6EeHr++H9lfEcLXgXnWYqt1zM3vtJ9Vd3muCS2OttrVV/XLRaWRWzNFCXgBpdOg8kzm2ltgsEptTpp5oqAP+aPIqR/56maziLjT+fRufKJb409muR7h8M0rDaF6DESiR7x65+KvSjyfQck= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1698045579; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=hop5Y+vE9Zl2Q5nVD+hwK3NnRPf3hHHxR6eE/U4LVW0=; b=MiYzpjccNSA6pDNjRymo+XNeE86Jx1nZRInC33r3qKbp6biprupWfsc1ERfktEv2aN6aJVmaZraVi0cajqlroBjqm72xRiNwiWIW/jm6Ymj5WumVQDXEUHL0gk+S+qo8ms2+FbptmAf/f808ar9+vfBmVVwcKP9lxlxIOrifiVo= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+109897+1787277+3901457@groups.io Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1698045579088580.5787670784712; Mon, 23 Oct 2023 00:19:39 -0700 (PDT) Return-Path: DKIM-Signature: a=rsa-sha256; bh=QRQq87qQEE800ItIwlUwqrGPSPFlzLuGf9BmWUiaTD4=; c=relaxed/simple; d=groups.io; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References:MIME-Version:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Transfer-Encoding:Content-Type; s=20140610; t=1698045578; v=1; b=kut6S8CH6bWOgzQqgkYb+ieT92rjSN+4IxwHty9PlzhRVdBmD2ehlpPQY/O/Jf0GP4+Zibms AXi//tK7zfeCNIku+o9jcGRCxPJc4NTxWa+sqhdH/KN7oqE6Mf77gfv2I/iWZFZa9kQGrUrgWpe ATsR8wKLubOiuAxZjrCNOHf8= X-Received: by 127.0.0.2 with SMTP id uRBpYY1788612xIxPISbNLOt; Mon, 23 Oct 2023 00:19:38 -0700 X-Received: from ex01.ufhost.com (ex01.ufhost.com [61.152.239.75]) by mx.groups.io with SMTP id smtpd.web10.115226.1698045576155116285 for ; Mon, 23 Oct 2023 00:19:38 -0700 X-Received: from EXMBX165.cuchost.com (unknown [175.102.18.54]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "EXMBX165", Issuer "EXMBX165" (not verified)) by ex01.ufhost.com (Postfix) with ESMTP id 9204224E383; Mon, 23 Oct 2023 15:19:34 +0800 (CST) X-Received: from EXMBX073.cuchost.com (172.16.6.83) by EXMBX165.cuchost.com (172.16.6.75) with Microsoft SMTP Server (TLS) id 15.0.1497.42; Mon, 23 Oct 2023 15:19:34 +0800 X-Received: from localhost.localdomain (202.188.176.82) by EXMBX073.cuchost.com (172.16.6.83) with Microsoft SMTP Server (TLS) id 15.0.1497.42; Mon, 23 Oct 2023 15:19:31 +0800 From: "John Chew" To: CC: John Chew , Sunil V L , Leif Lindholm , Michael D Kinney , "Cc : Li Yong" Subject: [edk2-devel] [PATCH v2 2/4] StarFive/JH7110Pkg: Add SPI protocol and driver support Date: Mon, 23 Oct 2023 15:18:49 +0800 Message-ID: <20231023071851.813-3-yuinyee.chew@starfivetech.com> In-Reply-To: <20231023071851.813-1-yuinyee.chew@starfivetech.com> References: <20231023071851.813-1-yuinyee.chew@starfivetech.com> MIME-Version: 1.0 X-Originating-IP: [202.188.176.82] X-ClientProxiedBy: EXCAS066.cuchost.com (172.16.6.26) To EXMBX073.cuchost.com (172.16.6.83) X-YovoleRuleAgent: yovoleflag Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,yuinyee.chew@starfivetech.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: r5siCEPtFvl5bZJoHWIYckIIx1787277AA= Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1698045580621100003 Content-Type: text/plain; charset="utf-8" This patch include QSPI driver and Flash driver protocol. QSPI driver: 1. Used indirect read/write 2. Master mode only 3. Require to setup qspi driver after located protocol 4. Require to free device if no longer needed 5. Support command read/write & data read/write Flash driver: 1. Require QSPI protocol as prerequisite 2. Support for flash read/write/update/erase 3. Require to init flash driver after allocated protocol Cc: Sunil V L Cc: Leif Lindholm Cc: Michael D Kinney Cc: Cc: Li Yong Signed-off-by: John Chew --- Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.c = | 893 ++++++++++++++++++++ Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.h = | 188 +++++ Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.inf = | 52 ++ Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDx= e.c | 571 +++++++++++++ Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDx= e.h | 35 + Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDx= e.inf | 44 + Silicon/StarFive/JH7110Pkg/Include/Protocol/Spi.h = | 163 ++++ Silicon/StarFive/JH7110Pkg/Include/Protocol/SpiFlash.h = | 88 ++ 8 files changed, 2034 insertions(+) diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/Spi= Dxe.c b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.c new file mode 100755 index 000000000000..c345556f8abf --- /dev/null +++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.c @@ -0,0 +1,893 @@ +/** @file + * + * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.=
+ * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "SpiDxe.h" + +SPI_MASTER *mSpiMasterInstance; + +STATIC +VOID +SpiControllerEnable ( + IN UINT32 RegBase + ) +{ + UINT32 Reg; + + Reg =3D MmioRead32 (RegBase + SPI_REG_CONFIG); + Reg |=3D SPI_REG_CONFIG_ENABLE; + MmioWrite32 (RegBase + SPI_REG_CONFIG, Reg); +} + +STATIC +VOID +SpiControllerDisable ( + IN UINT32 RegBase + ) +{ + UINT32 Reg; + + Reg =3D MmioRead32 (RegBase + SPI_REG_CONFIG); + Reg &=3D ~SPI_REG_CONFIG_ENABLE; + MmioWrite32 (RegBase + SPI_REG_CONFIG, Reg); +} + +STATIC +VOID +SpiWriteSpeed ( + IN SPI_DEVICE_PARAMS *Slave, + IN UINT32 SclkHz, + IN SPI_TIMING_PARAMS *Timing + ) +{ + UINT32 Reg, Div, RefClkNs, SclkNs; + UINT32 Tshsl, Tchsh, Tslch, Tsd2d; + + SpiControllerDisable (Slave->RegBase); + + /* Configure baudrate */ + Reg =3D MmioRead32 (Slave->RegBase + SPI_REG_CONFIG); + Reg &=3D ~(SPI_REG_CONFIG_BAUD_MASK << SPI_REG_CONFIG_BAUD_LSB); + + Div =3D DIV_ROUND_UP (Timing->RefClkHz, SclkHz * 2) - 1; + + if (Div > SPI_REG_CONFIG_BAUD_MASK) { + Div =3D SPI_REG_CONFIG_BAUD_MASK; + } + + DEBUG ( + (DEBUG_INFO, "%a(): RefClk %dHz sclk %dHz Div 0x%x, actual %dHz\n= ", __func__, + Timing->RefClkHz, SclkHz, Div, Timing->RefClkHz / (2 * (Div + 1)= )) + ); + + Reg |=3D (Div << SPI_REG_CONFIG_BAUD_LSB); + MmioWrite32 (Slave->RegBase + SPI_REG_CONFIG, Reg); + + /* Configure delay timing */ + RefClkNs =3D DIV_ROUND_UP (1000000000, Timing->RefClkHz); + SclkNs =3D DIV_ROUND_UP (1000000000, SclkHz); + + if (Timing->TshslNs >=3D SclkNs + RefClkNs) { + Timing->TshslNs -=3D SclkNs + RefClkNs; + } + + if (Timing->TchshNs >=3D SclkNs + 3 * RefClkNs) { + Timing->TchshNs -=3D SclkNs + 3 * RefClkNs; + } + + Tshsl =3D DIV_ROUND_UP (Timing->TshslNs, RefClkNs); + Tchsh =3D DIV_ROUND_UP (Timing->TchshNs, RefClkNs); + Tslch =3D DIV_ROUND_UP (Timing->TslchNs, RefClkNs); + Tsd2d =3D DIV_ROUND_UP (Timing->Tsd2dNs, RefClkNs); + + Reg =3D ((Tshsl & SPI_REG_DELAY_TSHSL_MASK) + << SPI_REG_DELAY_TSHSL_LSB); + Reg |=3D ((Tchsh & SPI_REG_DELAY_TCHSH_MASK) + << SPI_REG_DELAY_TCHSH_LSB); + Reg |=3D ((Tslch & SPI_REG_DELAY_TSLCH_MASK) + << SPI_REG_DELAY_TSLCH_LSB); + Reg |=3D ((Tsd2d & SPI_REG_DELAY_TSD2D_MASK) + << SPI_REG_DELAY_TSD2D_LSB); + MmioWrite32 (Slave->RegBase + SPI_REG_DELAY, Reg); + + SpiControllerEnable (Slave->RegBase); +} + +STATIC +EFI_STATUS +SpiWaitIdle ( + IN UINT32 RegBase + ) +{ + BOOLEAN IsIdle; + UINT32 Count =3D 0; + UINT32 TimeoutMs =3D 5000000; + + do { + IsIdle =3D (BOOLEAN)((MmioRead32(RegBase + SPI_REG_CONFIG) >> + SPI_REG_CONFIG_IDLE_LSB) & 0x1); + Count =3D (IsIdle) ? (Count+1) : 0; + + /* + * Make sure the QSPI controller is in really idle + * for n period of time before proceed + */ + if (Count >=3D SPI_POLL_IDLE_RETRY) { + return EFI_SUCCESS; + } + + gBS->Stall (1); + } while (TimeoutMs); + + return EFI_TIMEOUT; +} + +STATIC +EFI_STATUS +SpiExecFlashCmd ( + IN UINT32 RegBase, + IN UINT32 Reg + ) +{ + EFI_STATUS Status; + UINT32 Retry =3D SPI_REG_RETRY; + + /* Write the CMDCTRL without start execution */ + MmioWrite32 (RegBase + SPI_REG_CMDCTRL, Reg); + /* Start execute */ + Reg |=3D SPI_REG_CMDCTRL_EXECUTE; + MmioWrite32 (RegBase + SPI_REG_CMDCTRL, Reg); + + while (Retry--) { + Reg =3D MmioRead32 (RegBase + SPI_REG_CMDCTRL); + if ((Reg & SPI_REG_CMDCTRL_INPROGRESS) =3D=3D 0) { + break; + } + gBS->Stall (1); + } + + if (!Retry) { + DEBUG ((DEBUG_ERROR, "%a(): flash command execution Timeout\n", __func= __)); + return EFI_TIMEOUT; + } + + /* Polling QSPI idle status */ + Status =3D SpiWaitIdle (RegBase); + if (EFI_ERROR (Status)) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +/* For command RDID, RDSR. */ +EFI_STATUS +SpiCommandRead ( + IN SPI_MASTER_PROTOCOL *This, + IN SPI_DEVICE_PARAMS *Slave, + IN OUT SPI_OP_PARAMS *Cmds + ) +{ + UINT32 Reg; + UINT32 ReadLen; + EFI_STATUS Status; + SPI_MASTER *SpiMaster; + UINT32 RxLen =3D Cmds->Data.NBytes; + VOID *RxBuf =3D Cmds->Data.Buf.In; + + SpiMaster =3D SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This); + if (!EfiAtRuntime ()) { + EfiAcquireLock (&SpiMaster->Lock); + } + + if ((RxLen > SPI_STIG_DATA_LEN_MAX) || !RxBuf) { + DEBUG ((DEBUG_ERROR, "%a(): Invalid input arguments RxLen %d\n", __fun= c__, RxLen)); + Status =3D EFI_INVALID_PARAMETER; + goto Fail; + } + + Reg =3D Cmds->Cmd.OpCode << SPI_REG_CMDCTRL_OPCODE_LSB; + Reg |=3D (0x1 << SPI_REG_CMDCTRL_RD_EN_LSB); + + /* 0 means 1 byte */ + Reg |=3D (((RxLen - 1) & SPI_REG_CMDCTRL_RD_BYTES_MASK) + << SPI_REG_CMDCTRL_RD_BYTES_LSB); + Status =3D SpiExecFlashCmd (Slave->RegBase, Reg); + if (EFI_ERROR (Status)) { + goto Fail; + } + + Reg =3D MmioRead32 (Slave->RegBase + SPI_REG_CMDREADDATALOWER); + + /* Put the read value into rx_buf */ + ReadLen =3D (RxLen > 4) ? 4 : RxLen; + CopyMem (RxBuf, &Reg, ReadLen); + RxBuf +=3D ReadLen; + + if (RxLen > 4) { + Reg =3D MmioRead32 (Slave->RegBase + SPI_REG_CMDREADDATAUPPER); + + ReadLen =3D RxLen - ReadLen; + CopyMem (RxBuf, &Reg, ReadLen); + } + + if (!EfiAtRuntime ()) { + EfiReleaseLock (&SpiMaster->Lock); + } + return EFI_SUCCESS; + +Fail: + if (!EfiAtRuntime ()) { + EfiReleaseLock (&SpiMaster->Lock); + } + return Status; +} + +STATIC +EFI_STATUS +SpiGetReadSramLevel ( + IN UINT32 RegBase, + OUT UINT16 *SramLvl + ) +{ + UINT32 Reg =3D MmioRead32 (RegBase + SPI_REG_SDRAMLEVEL); + Reg >>=3D SPI_REG_SDRAMLEVEL_RD_LSB; + *SramLvl =3D (UINT16)(Reg & SPI_REG_SDRAMLEVEL_RD_MASK); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +SpiWaitForData ( + IN UINT32 RegBase, + UINT16 *SramLvl + ) +{ + UINT32 Timeout =3D 10000; + + while (Timeout--) { + SpiGetReadSramLevel (RegBase, SramLvl); + if (SramLvl !=3D 0) { + return EFI_SUCCESS; + } + gBS->Stall (1); + } + + return EFI_TIMEOUT; +} + +STATIC +EFI_STATUS +SpiWaitForBitLe32 ( + IN INT32 Reg, + IN CONST UINT32 Mask, + IN CONST BOOLEAN Set, + IN CONST UINT32 TimeoutMs + ) +{ + UINT32 Val; + UINTN Start =3D TimeoutMs*1000; + + while(1) { + Val =3D MmioRead32 (Reg); + + if (!Set) { + Val =3D ~Val; + } + + if ((Val & Mask) =3D=3D Mask) { + return EFI_SUCCESS; + } + + if (Start =3D=3D 0) { + break; + } else { + Start--; + } + + gBS->Stall (1); + } + + DEBUG ((DEBUG_ERROR, "Timeout (Reg=3D%lx Mask=3D%x wait_set=3D%d)\n", Re= g, Mask, Set)); + + return EFI_TIMEOUT; +} + +STATIC +VOID +SpiReadByte ( + IN VOID *Addr, + IN VOID *Data, + IN UINT16 ByteLen + ) +{ + UINT8 *AddrPtr; + UINT8 *DataPtr; + + AddrPtr =3D (UINT8 *)Addr; + DataPtr =3D (UINT8 *)Data; + + while (ByteLen) { + *DataPtr =3D *AddrPtr; + DataPtr++; + ByteLen--; + } +} + +STATIC +VOID +SpiReadLong ( + VOID *Addr, + VOID *Data, + UINT16 LongLen + ) +{ + UINT32 *AddrPtr; + UINT32 *DataPtr; + + AddrPtr =3D (UINT32 *)Addr; + DataPtr =3D (UINT32 *)Data; + + while (LongLen) { + *DataPtr =3D *AddrPtr; + DataPtr++; + LongLen--; + } +} + +EFI_STATUS +SpiDataRead ( + IN SPI_MASTER_PROTOCOL *This, + IN SPI_DEVICE_PARAMS *Slave, + IN OUT SPI_OP_PARAMS *Cmds + ) +{ + SPI_MASTER *SpiMaster; + UINT8 *RxBuf =3D Cmds->Data.Buf.In; + UINT32 Remaining =3D Cmds->Data.NBytes; + UINT16 BytesToRead =3D 0; + EFI_STATUS Status; + UINT32 Reg; + + SpiMaster =3D SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This); + if (!EfiAtRuntime ()) { + EfiAcquireLock (&SpiMaster->Lock); + } + + if (!Cmds->Addr.NBytes) { + Status =3D EFI_ABORTED; + goto Fail; + } + + /* Setup the indirect trigger start address */ + MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTRDSTARTADDR, Cmds->Addr.Va= l); + + /* Register command */ + Reg =3D Cmds->Cmd.OpCode << SPI_REG_RD_INSTR_OPCODE_LSB; + MmioWrite32 (Slave->RegBase + SPI_REG_RD_INSTR, Reg); + + /* Set device size */ + Reg =3D MmioRead32 (Slave->RegBase + SPI_REG_SIZE); + Reg &=3D ~SPI_REG_SIZE_ADDRESS_MASK; + Reg |=3D (Cmds->Addr.NBytes - 1); + MmioWrite32 (Slave->RegBase + SPI_REG_SIZE, Reg); + + /* Setup indirect read bytes */ + MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTRDBYTES, Remaining); + + /* Start the indirect read transfer */ + MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTRD, SPI_REG_INDIRECTRD_STA= RT); + + while (Remaining > 0) { + Status =3D SpiWaitForData (Slave->RegBase, &BytesToRead); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Indirect write timed out\n", __func__)); + goto Fail; + } + + while (BytesToRead !=3D 0) { + BytesToRead *=3D Slave->FifoWidth; + if (BytesToRead > Remaining) { + BytesToRead =3D Remaining; + } + + if (((UINTN)RxBuf % 4) || (BytesToRead % 4)) { + SpiReadByte (Slave->AhbBase, RxBuf, BytesToRead); + } else { + SpiReadLong (Slave->AhbBase, RxBuf, BytesToRead >> 2); + } + + RxBuf +=3D BytesToRead; + Remaining -=3D BytesToRead; + SpiGetReadSramLevel (Slave->RegBase, &BytesToRead); + } + } + + /* Check indirect done status */ + Status =3D SpiWaitForBitLe32 ( + Slave->RegBase + SPI_REG_INDIRECTRD, + SPI_REG_INDIRECTRD_DONE, + 1, + 10 + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Indirect read completion error\n")); + goto Fail; + } + + /* Clear indirect completion status */ + MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTRD, SPI_REG_INDIRECTRD_DON= E); + + if (!EfiAtRuntime ()) { + EfiReleaseLock (&SpiMaster->Lock); + } + return EFI_SUCCESS; + +Fail: + MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTRD, SPI_REG_INDIRECTRD_CAN= CEL); + if (!EfiAtRuntime ()) { + EfiReleaseLock (&SpiMaster->Lock); + } + return EFI_ABORTED; +} + +/* For commands: WRSR, WREN, WRDI, CHIP_ERASE, BE, etc. */ +EFI_STATUS +SpiCommandWrite ( + IN SPI_MASTER_PROTOCOL *This, + IN SPI_DEVICE_PARAMS *Slave, + IN OUT SPI_OP_PARAMS *Cmds + ) +{ + UINT32 Reg; + UINT32 WriteData; + UINT32 WriteLen; + SPI_MASTER *SpiMaster; + UINT32 TxLen =3D Cmds->Data.NBytes; + CONST VOID *TxBuf =3D Cmds->Data.Buf.Out; + UINT32 Addr; + EFI_STATUS Status; + + SpiMaster =3D SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This); + if (!EfiAtRuntime ()) { + EfiAcquireLock (&SpiMaster->Lock); + } + + /* Reorder address to SPI bus order if only transferring address */ + if (!TxLen) { + Addr =3D SwapBytes32 (Cmds->Addr.Val); + if (Cmds->Addr.NBytes =3D=3D 3) { + Addr >>=3D 8; + } + + TxBuf =3D &Addr; + TxLen =3D Cmds->Addr.NBytes; + } + + if (TxLen > SPI_STIG_DATA_LEN_MAX) { + DEBUG ((DEBUG_ERROR, "QSPI: Invalid input arguments TxLen %d\n", TxLen= )); + Status =3D EFI_INVALID_PARAMETER; + goto Fail; + } + + Reg =3D Cmds->Cmd.OpCode << SPI_REG_CMDCTRL_OPCODE_LSB; + + if (TxLen) { + Reg |=3D (0x1 << SPI_REG_CMDCTRL_WR_EN_LSB); + Reg |=3D ((TxLen - 1) & SPI_REG_CMDCTRL_WR_BYTES_MASK) + << SPI_REG_CMDCTRL_WR_BYTES_LSB; + + WriteLen =3D TxLen > 4 ? 4 : TxLen; + CopyMem (&WriteData, TxBuf, WriteLen); + MmioWrite32 (Slave->RegBase + SPI_REG_CMDWRITEDATALOWER, WriteData); + + if (TxLen > 4) { + TxBuf +=3D WriteLen; + WriteLen =3D TxLen - WriteLen; + CopyMem (&WriteData, TxBuf, WriteLen); + MmioWrite32 (Slave->RegBase + SPI_REG_CMDWRITEDATAUPPER, WriteData); + } + } + + Status =3D SpiExecFlashCmd (Slave->RegBase, Reg); + if (EFI_ERROR (Status)) { + goto Fail; + } + + if (!EfiAtRuntime ()) { + EfiReleaseLock (&SpiMaster->Lock); + } + return EFI_SUCCESS; + +Fail: + if (!EfiAtRuntime ()) { + EfiReleaseLock (&SpiMaster->Lock); + } + return Status; +} + +STATIC +VOID +SpiDelayNanoSec ( + IN UINTN nsec + ) +{ + UINT32 Timeout =3D DIV_ROUND_UP (nsec, 1000); + + do { + Timeout--; + gBS->Stall (1); + } while (Timeout); +} + +STATIC +VOID +SpiWriteLong ( + IN VOID *Addr, + IN CONST VOID *Data, + IN INTN LongLen + ) +{ + UINT32 *AddrPtr; + UINT32 *DataPtr; + + AddrPtr =3D (UINT32 *)Addr; + DataPtr =3D (UINT32 *)Data; + + while (LongLen) { + *AddrPtr =3D *DataPtr; + DataPtr++; + LongLen--; + } +} + +STATIC +VOID +SpiWriteByte ( + IN VOID *Addr, + IN CONST VOID *Data, + IN INTN ByteLen + ) +{ + UINT8 *AddrPtr; + UINT8 *DataPtr; + + AddrPtr =3D (UINT8 *)Addr; + DataPtr =3D (UINT8 *)Data; + + while (ByteLen) { + *AddrPtr =3D *DataPtr; + DataPtr++; + ByteLen--; + } +} + +EFI_STATUS +SpiDataWrite ( + IN SPI_MASTER_PROTOCOL *This, + IN SPI_DEVICE_PARAMS *Slave, + IN OUT SPI_OP_PARAMS *Cmds + ) +{ + UINT32 Reg; + SPI_MASTER *SpiMaster; + UINT32 PageSize =3D Slave->Info->PageSize; + UINT32 Remaining =3D Cmds->Data.NBytes; + CONST UINT8 *TxBuf =3D Cmds->Data.Buf.Out; + UINT32 WriteBytes; + EFI_STATUS Status; + + SpiMaster =3D SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This); + if (!EfiAtRuntime ()) { + EfiAcquireLock (&SpiMaster->Lock); + } + + if (!Cmds->Addr.NBytes) { + return EFI_ABORTED; + } + + /* Write opcode to write instruction register */ + Reg =3D Cmds->Cmd.OpCode << SPI_REG_WR_INSTR_OPCODE_LSB; + MmioWrite32 (Slave->RegBase + SPI_REG_WR_INSTR, Reg); + + /* Set buffer address */ + MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTWRSTARTADDR, Cmds->Addr.Va= l); + + /* Configure device size */ + Reg =3D MmioRead32 (Slave->RegBase + SPI_REG_SIZE); + Reg &=3D ~SPI_REG_SIZE_ADDRESS_MASK; + Reg |=3D (Cmds->Addr.NBytes - 1); + MmioWrite32 (Slave->RegBase + SPI_REG_SIZE, Reg); + + /* Configure the indirect read transfer bytes */ + MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTWRBYTES, Remaining); + + /* Start the indirect write transfer */ + MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTWR, SPI_REG_INDIRECTWR_STA= RT); + + /* Delay is required for QSPI module to synchronized internally */ + SpiDelayNanoSec (Slave->WriteDelay); + + while (Remaining > 0) { + WriteBytes =3D Remaining > PageSize ? PageSize : Remaining; + SpiWriteLong (Slave->AhbBase, TxBuf, WriteBytes >> 2); + if (WriteBytes % 4) { + SpiWriteByte ( + Slave->AhbBase, + TxBuf + ROUND_DOWN (WriteBytes, 4), + WriteBytes % 4 + ); + } + + Status =3D SpiWaitForBitLe32 ( + Slave->RegBase + SPI_REG_SDRAMLEVEL, + SPI_REG_SDRAMLEVEL_WR_MASK << + SPI_REG_SDRAMLEVEL_WR_LSB, + 0, + 10 + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Indirect write timed out (%d)\n", __func= __, Status)); + goto FailWrite; + } + + TxBuf +=3D WriteBytes; + Remaining -=3D WriteBytes; + } + + /* Check indirect done status */ + Status =3D SpiWaitForBitLe32 ( + Slave->RegBase + SPI_REG_INDIRECTWR, + SPI_REG_INDIRECTWR_DONE, + 1, + 10 + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Indirect write completion error (%d)\n", Status)= ); + goto FailWrite; + } + + /* Clear indirect completion status */ + MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTWR, SPI_REG_INDIRECTWR_DON= E); + if (!EfiAtRuntime ()) { + EfiReleaseLock (&SpiMaster->Lock); + } + return EFI_SUCCESS; + +FailWrite: + MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTWR, SPI_REG_INDIRECTWR_CAN= CEL); + if (!EfiAtRuntime ()) { + EfiReleaseLock (&SpiMaster->Lock); + } + return Status; +} + +STATIC +VOID +SpiConfigGetDataCapture ( + IN UINT32 RegBase, + IN UINT32 ByPass, + IN UINT32 Delay + ) +{ + UINT32 Reg; + + SpiControllerDisable (RegBase); + + Reg =3D MmioRead32 (RegBase + SPI_REG_RD_DATA_CAPTURE); + + if (ByPass) { + Reg |=3D SPI_REG_RD_DATA_CAPTURE_BYPASS; + } else { + Reg &=3D ~SPI_REG_RD_DATA_CAPTURE_BYPASS; + } + + Reg &=3D ~(SPI_REG_RD_DATA_CAPTURE_DELAY_MASK + << SPI_REG_RD_DATA_CAPTURE_DELAY_LSB); + + Reg |=3D (Delay & SPI_REG_RD_DATA_CAPTURE_DELAY_MASK) + << SPI_REG_RD_DATA_CAPTURE_DELAY_LSB; + + MmioWrite32 (RegBase + SPI_REG_RD_DATA_CAPTURE, Reg); + + SpiControllerEnable (RegBase); +} + +STATIC +EFI_STATUS +SpiSpeedCalibration ( + IN SPI_MASTER_PROTOCOL *This, + IN SPI_DEVICE_PARAMS *Slave, + IN SPI_TIMING_PARAMS *Timing + ) +{ + UINT8 IdLen =3D 3; + UINT32 IdInit =3D 0, IdCali =3D 0; + INTN RangeLow =3D -1, RangeHigh =3D -1; + SPI_OP_PARAMS CmdsInitialId =3D SPI_READID_OP ((UINT8 *)&IdInit, IdLen); + SPI_OP_PARAMS CmdsCalibrateId =3D SPI_READID_OP ((UINT8 *)&IdCali, IdLe= n); + EFI_STATUS Status; + + /* Start calibration with slowest clock speed at 1 MHz */ + SpiWriteSpeed (Slave, SPI_MIN_HZ, Timing); + + /* Set the read data capture delay register to 0 */ + SpiConfigGetDataCapture (Slave->RegBase, 1, 0); + + /* Get flash ID value as reference */ + Status =3D SpiCommandRead (This, Slave, &CmdsInitialId); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Spi: Calibration failed (read id)\n")); + return EFI_ABORTED; + } + + /* Use the input speed */ + SpiWriteSpeed (Slave, SPI_MAX_HZ, Timing); + + /* Find high and low range */ + for (UINT8 i =3D 0; i < SPI_READ_CAPTURE_MAX_DELAY; i++) { + /* Change the read data capture delay register */ + SpiConfigGetDataCapture (Slave->RegBase, 1, i); + + /* Read flash ID for comparison later */ + Status =3D SpiCommandRead (This, Slave, &CmdsCalibrateId); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Spi: Calibration failed (read)\n")); + return EFI_ABORTED; + } + + /* Verify low range */ + if ((RangeLow =3D=3D -1) && (IdCali =3D=3D IdInit)) { + RangeLow =3D i; + continue; + } + + /* Verify high range */ + if ((RangeLow !=3D -1) && (IdCali !=3D IdInit)) { + RangeHigh =3D i - 1; + break; + } + + RangeHigh =3D i; + } + + if (RangeLow =3D=3D -1) { + DEBUG ((DEBUG_ERROR, "Spi: Calibration failed\n")); + return EFI_ABORTED; + } + + /* + * Set the final value for read data capture delay register based + * on the calibrated value + */ + SpiConfigGetDataCapture (Slave->RegBase, 1, (RangeHigh + RangeLow) / 2); + DEBUG ( + (DEBUG_INFO, "Spi: Read data capture delay calibrated to %d (%d -= %d)\n", + (RangeHigh + RangeLow) / 2, RangeLow, RangeHigh) + ); + + return EFI_SUCCESS; +} + +EFI_STATUS +SpiSetupDevice ( + IN SPI_MASTER_PROTOCOL *This, + OUT SPI_DEVICE_PARAMS *Slave + ) +{ + SPI_TIMING_PARAMS *Timing; + EFI_STATUS Status; + + if (!Slave) { + Slave =3D AllocateZeroPool (sizeof (SPI_DEVICE_PARAMS)); + if (Slave =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory Slave\n", __func_= _)); + Status =3D EFI_OUT_OF_RESOURCES; + goto Fail; + } + } + + if (!Slave->Info) { + Slave->Info =3D AllocateZeroPool (sizeof (NOR_FLASH_INFO)); + if (Slave->Info =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory Slave->Info\n", _= _func__)); + Status =3D EFI_OUT_OF_RESOURCES; + goto Fail; + } + } + + Timing =3D AllocateZeroPool (sizeof (SPI_TIMING_PARAMS)); + if (Timing =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory Timing\n", __func__= )); + FreePool(Slave); + Status =3D EFI_OUT_OF_RESOURCES; + goto Fail; + } + + Slave->RegBase =3D PcdGet32 (PcdSpiFlashRegBase); + Slave->AhbBase =3D (VOID *)(UINTN)PcdGet64 (PcdSpiFlashAhbBase); + Slave->FifoWidth =3D PcdGet8 (PcdSpiFlashFifoWidth); + Timing->RefClkHz =3D PcdGet32 (PcdSpiFlashRefClkHz); + Timing->TshslNs =3D PcdGet32 (PcdSpiFlashTshslNs); + Timing->Tsd2dNs =3D PcdGet32 (PcdSpiFlashTsd2dNs); + Timing->TchshNs =3D PcdGet32 (PcdSpiFlashTchshNs); + Timing->TslchNs =3D PcdGet32 (PcdSpiFlashTslchNs); + + Slave->WriteDelay =3D 50 * DIV_ROUND_UP (NSEC_PER_SEC, Timing->RefClkHz); + + Status =3D SpiSpeedCalibration (This, Slave, Timing); + if (EFI_ERROR (Status)) { + goto Fail; + } + + FreePool(Timing); + return EFI_SUCCESS; + +Fail: + FreePool(Slave); + FreePool(Timing); + return Status; +} + +EFI_STATUS +SpiFreeDevice ( + IN SPI_DEVICE_PARAMS *Slave + ) +{ + FreePool (Slave); + + return EFI_SUCCESS; +} + +EFI_STATUS +SpiMasterInitProtocol ( + IN SPI_MASTER_PROTOCOL *SpiMasterProtocol + ) +{ + SpiMasterProtocol->SetupDevice =3D SpiSetupDevice; + SpiMasterProtocol->FreeDevice =3D SpiFreeDevice; + SpiMasterProtocol->CmdRead =3D SpiCommandRead; + SpiMasterProtocol->DataRead =3D SpiDataRead; + SpiMasterProtocol->CmdWrite =3D SpiCommandWrite; + SpiMasterProtocol->DataWrite =3D SpiDataWrite; + + return EFI_SUCCESS; +} + +EFI_STATUS +SpiEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + mSpiMasterInstance =3D AllocateRuntimeZeroPool (sizeof (SPI_MASTER)); + if (mSpiMasterInstance =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + EfiInitializeLock (&mSpiMasterInstance->Lock, TPL_NOTIFY); + + SpiMasterInitProtocol (&mSpiMasterInstance->SpiMasterProtocol); + + mSpiMasterInstance->Signature =3D SPI_MASTER_SIGNATURE; + + Status =3D gBS->InstallMultipleProtocolInterfaces ( + &(mSpiMasterInstance->H= andle), + &gJH7110SpiMasterProtoc= olGuid, + &(mSpiMasterInstance->S= piMasterProtocol), + NULL + ); + if (EFI_ERROR (Status)) { + FreePool (mSpiMasterInstance); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/Spi= Dxe.h b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.h new file mode 100644 index 000000000000..804ee29c5ff1 --- /dev/null +++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.h @@ -0,0 +1,188 @@ +/** @file + * + * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.=
+ * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __SPI_DXE_H__ +#define __SPI_DXE_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define SPI_MASTER_SIGNATURE SIGNATURE_32 ('M', 'S', = 'P', 'I') +#define SPI_MASTER_FROM_SPI_MASTER_PROTOCOL(a) CR (a, SPI_MASTER, SpiMast= erProtocol, SPI_MASTER_SIGNATURE) + +#ifndef BIT +#define BIT(nr) (1 << (nr)) +#endif + +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) +#define ROUND_DOWN(x, y) (\ +{ \ + typeof(x) __x =3D (x); \ + __x - (__x % (y)); \ +} \ +) +#define NSEC_PER_SEC 1000000000L + +/* Configs */ +#define SPI_READ_CAPTURE_MAX_DELAY 16 +#define SPI_REG_RETRY 10000 +#define SPI_POLL_IDLE_RETRY 3 +#define SPI_STIG_DATA_LEN_MAX 8 +#define SPI_MIN_HZ 1000000 +#define SPI_MAX_HZ 100000000 + +/* +* QSPI controller's config and status register (offset from QSPI_BASE) +*/ +#define SPI_REG_CONFIG 0x00 +#define SPI_REG_CONFIG_ENABLE BIT(0) +#define SPI_REG_CONFIG_CLK_POL BIT(1) +#define SPI_REG_CONFIG_CLK_PHA BIT(2) +#define SPI_REG_CONFIG_DIRECT BIT(7) +#define SPI_REG_CONFIG_DECODE BIT(9) +#define SPI_REG_CONFIG_XIP_IMM BIT(18) +#define SPI_REG_CONFIG_CHIPSELECT_LSB 10 +#define SPI_REG_CONFIG_BAUD_LSB 19 +#define SPI_REG_CONFIG_DTR_PROTO BIT(24) +#define SPI_REG_CONFIG_DUAL_OPCODE BIT(30) +#define SPI_REG_CONFIG_IDLE_LSB 31 +#define SPI_REG_CONFIG_CHIPSELECT_MASK 0xF +#define SPI_REG_CONFIG_BAUD_MASK 0xF + +#define SPI_REG_RD_INSTR 0x04 +#define SPI_REG_RD_INSTR_OPCODE_LSB 0 +#define SPI_REG_RD_INSTR_TYPE_INSTR_LSB 8 +#define SPI_REG_RD_INSTR_TYPE_ADDR_LSB 12 +#define SPI_REG_RD_INSTR_TYPE_DATA_LSB 16 +#define SPI_REG_RD_INSTR_MODE_EN_LSB 20 +#define SPI_REG_RD_INSTR_DUMMY_LSB 24 +#define SPI_REG_RD_INSTR_TYPE_INSTR_MASK 0x3 +#define SPI_REG_RD_INSTR_TYPE_ADDR_MASK 0x3 +#define SPI_REG_RD_INSTR_TYPE_DATA_MASK 0x3 +#define SPI_REG_RD_INSTR_DUMMY_MASK 0x1F + +#define SPI_REG_WR_INSTR 0x08 +#define SPI_REG_WR_INSTR_OPCODE_LSB 0 +#define SPI_REG_WR_INSTR_TYPE_ADDR_LSB 12 +#define SPI_REG_WR_INSTR_TYPE_DATA_LSB 16 + +#define SPI_REG_DELAY 0x0C +#define SPI_REG_DELAY_TSLCH_LSB 0 +#define SPI_REG_DELAY_TCHSH_LSB 8 +#define SPI_REG_DELAY_TSD2D_LSB 16 +#define SPI_REG_DELAY_TSHSL_LSB 24 +#define SPI_REG_DELAY_TSLCH_MASK 0xFF +#define SPI_REG_DELAY_TCHSH_MASK 0xFF +#define SPI_REG_DELAY_TSD2D_MASK 0xFF +#define SPI_REG_DELAY_TSHSL_MASK 0xFF + +#define SPI_REG_RD_DATA_CAPTURE 0x10 +#define SPI_REG_RD_DATA_CAPTURE_BYPASS BIT(0) +#define SPI_REG_RD_DATA_CAPTURE_DELAY_LSB 1 +#define SPI_REG_RD_DATA_CAPTURE_DELAY_MASK 0xF + +#define SPI_REG_SIZE 0x14 +#define SPI_REG_SIZE_ADDRESS_LSB 0 +#define SPI_REG_SIZE_PAGE_LSB 4 +#define SPI_REG_SIZE_BLOCK_LSB 16 +#define SPI_REG_SIZE_ADDRESS_MASK 0xF +#define SPI_REG_SIZE_PAGE_MASK 0xFFF +#define SPI_REG_SIZE_BLOCK_MASK 0x3F + +#define SPI_REG_SRAMPARTITION 0x18 +#define SPI_REG_INDIRECTTRIGGER 0x1C + +#define SPI_REG_REMAP 0x24 +#define SPI_REG_MODE_BIT 0x28 + +#define SPI_REG_SDRAMLEVEL 0x2C +#define SPI_REG_SDRAMLEVEL_RD_LSB 0 +#define SPI_REG_SDRAMLEVEL_WR_LSB 16 +#define SPI_REG_SDRAMLEVEL_RD_MASK 0xFFFF +#define SPI_REG_SDRAMLEVEL_WR_MASK 0xFFFF + +#define SPI_REG_WR_COMPLETION_CTRL 0x38 +#define SPI_REG_WR_DISABLE_AUTO_POLL BIT(14) + +#define SPI_REG_IRQSTATUS 0x40 +#define SPI_REG_IRQMASK 0x44 + +#define SPI_REG_INDIRECTRD 0x60 +#define SPI_REG_INDIRECTRD_START BIT(0) +#define SPI_REG_INDIRECTRD_CANCEL BIT(1) +#define SPI_REG_INDIRECTRD_INPROGRESS BIT(2) +#define SPI_REG_INDIRECTRD_DONE BIT(5) + +#define SPI_REG_INDIRECTRDWATERMARK 0x64 +#define SPI_REG_INDIRECTRDSTARTADDR 0x68 +#define SPI_REG_INDIRECTRDBYTES 0x6C + +#define SPI_REG_CMDCTRL 0x90 +#define SPI_REG_CMDCTRL_EXECUTE BIT(0) +#define SPI_REG_CMDCTRL_INPROGRESS BIT(1) +#define SPI_REG_CMDCTRL_DUMMY_LSB 7 +#define SPI_REG_CMDCTRL_WR_BYTES_LSB 12 +#define SPI_REG_CMDCTRL_WR_EN_LSB 15 +#define SPI_REG_CMDCTRL_ADD_BYTES_LSB 16 +#define SPI_REG_CMDCTRL_ADDR_EN_LSB 19 +#define SPI_REG_CMDCTRL_RD_BYTES_LSB 20 +#define SPI_REG_CMDCTRL_RD_EN_LSB 23 +#define SPI_REG_CMDCTRL_OPCODE_LSB 24 +#define SPI_REG_CMDCTRL_DUMMY_MASK 0x1F +#define SPI_REG_CMDCTRL_WR_BYTES_MASK 0x7 +#define SPI_REG_CMDCTRL_ADD_BYTES_MASK 0x3 +#define SPI_REG_CMDCTRL_RD_BYTES_MASK 0x7 +#define SPI_REG_CMDCTRL_OPCODE_MASK 0xFF + +#define SPI_REG_INDIRECTWR 0x70 +#define SPI_REG_INDIRECTWR_START BIT(0) +#define SPI_REG_INDIRECTWR_CANCEL BIT(1) +#define SPI_REG_INDIRECTWR_INPROGRESS BIT(2) +#define SPI_REG_INDIRECTWR_DONE BIT(5) + +#define SPI_REG_INDIRECTWRWATERMARK 0x74 +#define SPI_REG_INDIRECTWRSTARTADDR 0x78 +#define SPI_REG_INDIRECTWRBYTES 0x7C + +#define SPI_REG_CMDADDRESS 0x94 +#define SPI_REG_CMDREADDATALOWER 0xA0 +#define SPI_REG_CMDREADDATAUPPER 0xA4 +#define SPI_REG_CMDWRITEDATALOWER 0xA8 +#define SPI_REG_CMDWRITEDATAUPPER 0xAC + +#define SPI_REG_OP_EXT_LOWER 0xE0 +#define SPI_REG_OP_EXT_READ_LSB 24 +#define SPI_REG_OP_EXT_WRITE_LSB 16 +#define SPI_REG_OP_EXT_STIG_LSB 0 + +typedef struct { + SPI_MASTER_PROTOCOL SpiMasterProtocol; + UINTN Signature; + EFI_HANDLE Handle; + EFI_LOCK Lock; +} SPI_MASTER; + +typedef struct { + UINT32 RefClkHz; + UINT32 TshslNs; + UINT32 TchshNs; + UINT32 TslchNs; + UINT32 Tsd2dNs; +}SPI_TIMING_PARAMS; + +#endif //__SPI_DXE_H__ diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/Spi= Dxe.inf b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe= .inf new file mode 100644 index 000000000000..ed3f639346b2 --- /dev/null +++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.inf @@ -0,0 +1,52 @@ +## @file +# +# Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<= BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D SpiDxe + FILE_GUID =3D 2FBD9E55-9BC7-4EEF-BF93-0D5582FE647B + MODULE_TYPE =3D DXE_RUNTIME_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D SpiEntryPoint + +[Sources] + SpiDxe.c + SpiDxe.h + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec + +[LibraryClasses] + DebugLib + DxeServicesTableLib + IoLib + MemoryAllocationLib + NorFlashInfoLib + TimerLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + UefiRuntimeLib + +[FixedPcd] + gJH7110TokenSpaceGuid.PcdSpiFlashRegBase + gJH7110TokenSpaceGuid.PcdSpiFlashAhbBase + gJH7110TokenSpaceGuid.PcdSpiFlashFifoWidth + gJH7110TokenSpaceGuid.PcdSpiFlashRefClkHz + gJH7110TokenSpaceGuid.PcdSpiFlashTshslNs + gJH7110TokenSpaceGuid.PcdSpiFlashTsd2dNs + gJH7110TokenSpaceGuid.PcdSpiFlashTchshNs + gJH7110TokenSpaceGuid.PcdSpiFlashTslchNs + +[Protocols] + gJH7110SpiMasterProtocolGuid + +[Depex] + TRUE diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDx= e/SpiFlashDxe.c b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFl= ashDxe/SpiFlashDxe.c new file mode 100755 index 000000000000..cd508e53eb06 --- /dev/null +++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFl= ashDxe.c @@ -0,0 +1,571 @@ +/** @file + * + * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.=
+ * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include "SpiFlashDxe.h" + +SPI_MASTER_PROTOCOL *SpiMasterProtocol; +SPI_FLASH_INSTANCE *mSpiFlashInstance; + +STATIC +EFI_STATUS +SpiFlashWriteEnableCmd ( + IN SPI_DEVICE_PARAMS *Slave + ) +{ + EFI_STATUS Status; + SPI_OP_PARAMS Op =3D SPI_WRITE_EN_OP(); + + /* Send write enable command */ + Status =3D SpiMasterProtocol->CmdWrite (SpiMasterProtocol, Slave, &Op); + + return Status; +} + +STATIC +EFI_STATUS +SpiFlashWriteDisableCmd ( + IN SPI_DEVICE_PARAMS *Slave + ) +{ + EFI_STATUS Status; + SPI_OP_PARAMS Op =3D SPI_WRITE_DIS_OP(); + + /* Send write disable command */ + Status =3D SpiMasterProtocol->CmdWrite (SpiMasterProtocol, Slave, &Op); + + return Status; +} + +STATIC +EFI_STATUS +SpiFlashPoll ( + IN SPI_DEVICE_PARAMS *Slave +) +{ + EFI_STATUS Status; + UINT16 State; + UINT32 Counter =3D 0xFFFFF; + UINT8 ReadLength =3D 2; + + SPI_OP_PARAMS OpRdSts =3D SPI_OP ( + SPI_OP_CMD (SPI_CMD_READ_STATUS), + SPI_OP_NO_ADDR, + SPI_OP_NO_DUMMY, + SPI_OP_DATA_IN (ReadLength, (VOID *)&Sta= te) + ); + + Status =3D SpiMasterProtocol->CmdRead (SpiMasterProtocol, Slave, &OpRdSt= s); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Spi error while reading status\n", __func_= _)); + return Status; + } + + do { + Status =3D SpiMasterProtocol->CmdRead (SpiMasterProtocol, Slave, &OpRd= Sts); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Spi error while reading status\n", __fun= c__)); + return Status; + } + + Counter--; + if (!(State & STATUS_REG_POLL_WIP_MSK)) { + break; + } + } while (Counter > 0); + + if (Counter =3D=3D 0) { + DEBUG ((DEBUG_ERROR, "%a(): Timeout while writing to spi flash\n", __f= unc__)); + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +SpiFlashErase ( + IN SPI_DEVICE_PARAMS *Slave, + IN UINT32 Offset, + IN UINTN Length + ) +{ + EFI_STATUS Status; + UINT32 EraseAddr; + UINTN EraseSize; + UINT8 EraseCmd; + + if (Slave->Info->Flags & NOR_FLASH_ERASE_4K) { + EraseCmd =3D SPI_CMD_ERASE_4K; + EraseSize =3D SIZE_4KB; + } else if (Slave->Info->Flags & NOR_FLASH_ERASE_32K) { + EraseCmd =3D SPI_CMD_ERASE_32K; + EraseSize =3D SIZE_32KB; + } else { + EraseCmd =3D SPI_CMD_ERASE_64K; + EraseSize =3D Slave->Info->SectorSize; + } + + /* Verify input parameters */ + if (Offset % EraseSize || Length % EraseSize) { + DEBUG ( + (DEBUG_ERROR, "%a(): Either erase offset or length " + "is not multiple of erase size\n, __func__") + ); + return EFI_DEVICE_ERROR; + } + + Status =3D SpiFlashWriteEnableCmd (Slave); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Error while setting write_enable\n", __fun= c__)); + return Status; + } + + while (Length) { + EraseAddr =3D Offset; + + SPI_OP_PARAMS OpErase =3D SPI_OP ( + SPI_OP_CMD (EraseCmd), + SPI_OP_ADDR (3, EraseAddr), + SPI_OP_NO_DUMMY, + SPI_OP_NO_DATA + ); + + Status =3D SpiMasterProtocol->CmdWrite (SpiMasterProtocol, Slave, &OpE= rase); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Spi erase fail\n", __func__)); + return Status; + } + + Status =3D SpiFlashPoll(Slave); + if (EFI_ERROR (Status)) { + return Status; + } + + Offset +=3D EraseSize; + Length -=3D EraseSize; + } + + Status =3D SpiFlashWriteDisableCmd (Slave); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Error while setting write_disable\n", __fu= nc__)); + return Status; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +SpiFlashRead ( + IN SPI_DEVICE_PARAMS *Slave, + IN UINT32 Offset, + IN UINTN Length, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINTN ReadAddr, ReadLength, RemainLength; + UINT32 FlashSize; + + FlashSize =3D Slave->Info->PageSize * Slave->Info->SectorSize; + + /* Current handling is only limit for single flash Bank */ + while (Length) { + ReadAddr =3D Offset; + + RemainLength =3D (FlashSize - Offset); + if (Length < RemainLength) { + ReadLength =3D Length; + } else { + ReadLength =3D RemainLength; + } + + /* Send read command */ + SPI_OP_PARAMS OpRead =3D SPI_OP ( + SPI_OP_CMD (SPI_CMD_READ_DATA), + SPI_OP_ADDR (Slave->AddrSize, ReadAddr), + SPI_OP_NO_DUMMY, + SPI_OP_DATA_IN (ReadLength, Buffer) + ); + + Status =3D SpiMasterProtocol->DataRead (SpiMasterProtocol, Slave, &OpR= ead); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Spi error while reading data\n", __func_= _)); + return Status; + } + + Offset +=3D ReadLength; + Length -=3D ReadLength; + Buffer =3D (VOID *)((UINTN)Buffer + ReadLength); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +SpiFlashWrite ( + IN SPI_DEVICE_PARAMS *Slave, + IN UINT32 Offset, + IN UINTN Length, + IN VOID *Buffer + ) +{ + EFI_STATUS Status; + UINTN ByteAddr, ChunkLength, ActualIndex, PageSize; + UINT32 WriteAddr; + + PageSize =3D Slave->Info->PageSize; + + Status =3D SpiFlashWriteEnableCmd (Slave); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Error while setting write enable\n", __fun= c__)); + return Status; + } + + for (ActualIndex =3D 0; ActualIndex < Length; ActualIndex +=3D ChunkLeng= th) { + WriteAddr =3D Offset; + + ByteAddr =3D Offset % PageSize; + ChunkLength =3D MIN (Length - ActualIndex, (UINT64)(PageSize - ByteAdd= r)); + + SPI_OP_PARAMS OpPgProg =3D SPI_OP ( + SPI_OP_CMD (SPI_CMD_PAGE_PROGRAM), + SPI_OP_ADDR (3, WriteAddr), + SPI_OP_NO_DUMMY, + SPI_OP_DATA_OUT (ChunkLength, (VOID = *)((UINTN)Buffer + ActualIndex)) + ); + + Status =3D SpiMasterProtocol->DataWrite (SpiMasterProtocol, Slave, &Op= PgProg); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Error while programming write address\n"= , __func__)); + return Status; + } + + Status =3D SpiFlashPoll(Slave); + if (EFI_ERROR (Status)) { + return Status; + } + + Offset +=3D ChunkLength; + } + + Status =3D SpiFlashWriteDisableCmd (Slave); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Error while setting write disable\n", __fu= nc__)); + return Status; + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +SpiFlashUpdateBlock ( + IN SPI_DEVICE_PARAMS *Slave, + IN UINT32 Offset, + IN UINTN ToUpdate, + IN UINT8 *Buffer, + IN UINT8 *TmpBuf, + IN UINTN EraseSize + ) +{ + EFI_STATUS Status; + + /* Read backup */ + Status =3D SpiFlashRead (Slave, Offset, EraseSize, TmpBuf); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "%a(): Update: Error while reading old data\n", = __func__)); + return Status; + } + + /* Erase entire sector */ + Status =3D SpiFlashErase (Slave, Offset, EraseSize); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "%a(): Update: Error while erasing block\n", __f= unc__)); + return Status; + } + + /* Write new data */ + SpiFlashWrite (Slave, Offset, ToUpdate, Buffer); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "%a(): Update: Error while writing new data\n", = __func__)); + return Status; + } + + /* Write backup */ + if (ToUpdate !=3D EraseSize) { + Status =3D SpiFlashWrite (Slave, Offset + ToUpdate, EraseSize - ToUpda= te, + &TmpBuf[ToUpdate]); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "%a(): Update: Error while writing backup\n", __= func__)); + return Status; + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +SpiFlashUpdate ( + IN SPI_DEVICE_PARAMS *Slave, + IN UINT32 Offset, + IN UINTN ByteCount, + IN UINT8 *Buffer + ) +{ + EFI_STATUS Status; + UINT64 SectorSize, ToUpdate, Scale =3D 1; + UINT8 *TmpBuf, *End; + + SectorSize =3D Slave->Info->SectorSize; + + End =3D Buffer + ByteCount; + + TmpBuf =3D (UINT8 *)AllocateZeroPool (SectorSize); + if (TmpBuf =3D=3D NULL) { + DEBUG((DEBUG_ERROR, "%a(): Cannot allocate memory\n", __func__)); + return EFI_OUT_OF_RESOURCES; + } + + if (End - Buffer >=3D 200) + Scale =3D (End - Buffer) / 100; + + for (; Buffer < End; Buffer +=3D ToUpdate, Offset +=3D ToUpdate) { + ToUpdate =3D MIN((UINT64)(End - Buffer), SectorSize); + Print (L" \rUpdating, %d%%", 100 - (End - Buffer) / Scale); + Status =3D SpiFlashUpdateBlock (Slave, Offset, ToUpdate, Buffer, TmpBu= f, SectorSize); + + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "%a(): Error while updating\n", __func__)); + return Status; + } + } + + Print(L"\n"); + FreePool (TmpBuf); + + return EFI_SUCCESS; +} + +EFI_STATUS +SpiFlashUpdateWithProgress ( + IN SPI_DEVICE_PARAMS *Slave, + IN UINT32 Offset, + IN UINTN ByteCount, + IN UINT8 *Buffer, + IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress, OPTIO= NAL + IN UINTN StartPercentage, + IN UINTN EndPercentage + ) +{ + EFI_STATUS Status; + UINTN SectorSize; + UINTN SectorNum; + UINTN ToUpdate; + UINTN Index; + UINT8 *TmpBuf; + + SectorSize =3D Slave->Info->SectorSize; + SectorNum =3D (ByteCount / SectorSize) + 1; + ToUpdate =3D SectorSize; + + TmpBuf =3D (UINT8 *)AllocateZeroPool (SectorSize); + if (TmpBuf =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory\n", __func__)); + return EFI_OUT_OF_RESOURCES; + } + + for (Index =3D 0; Index < SectorNum; Index++) { + if (Progress !=3D NULL) { + Progress (StartPercentage + + ((Index * (EndPercentage - StartPercentage)) / SectorNum)); + } + + /* In the last chunk update only an actual number of remaining bytes */ + if (Index + 1 =3D=3D SectorNum) { + ToUpdate =3D ByteCount % SectorSize; + } + + Status =3D SpiFlashUpdateBlock (Slave, + Offset + Index * SectorSize, + ToUpdate, + Buffer + Index * SectorSize, + TmpBuf, + SectorSize); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Error while updating\n", __func__)); + return Status; + } + } + FreePool (TmpBuf); + + if (Progress !=3D NULL) { + Progress (EndPercentage); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +SpiFlashReadId ( + IN SPI_DEVICE_PARAMS *Slave, + IN BOOLEAN UseInRuntime + ) +{ + EFI_STATUS Status; + UINT8 IdLen =3D 3; + UINT8 Id[IdLen]; + + SPI_OP_PARAMS Op =3D SPI_READID_OP (Id, IdLen); + + Status =3D SpiMasterProtocol->CmdRead (SpiMasterProtocol, Slave, &Op); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Spi error while reading id\n", __func__)); + return Status; + } + + Status =3D NorFlashGetInfo (Id, &Slave->Info, UseInRuntime); + + if (EFI_ERROR (Status)) { + DEBUG ( + (DEBUG_ERROR, + "%a: Unrecognized JEDEC Id bytes: 0x%02x%02x%02x\n", + __func__, + Id[0], + Id[1], + Id[2]) + ); + return Status; + } + + NorFlashPrintInfo (Slave->Info); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +SpiFlashInit ( + IN SPI_FLASH_PROTOCOL *This, + IN SPI_DEVICE_PARAMS *Slave + ) +{ + EFI_STATUS Status; + UINT8 StatusRegister; + + Slave->AddrSize =3D (Slave->Info->Flags & NOR_FLASH_4B_ADDR) ? 4 : 3; + + Status =3D SpiFlashWriteEnableCmd (Slave); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Error while setting write enable\n", __fun= c__)); + return Status; + } + + if (Slave->AddrSize =3D=3D 4) { + + /* Enable 4byte addressing */ + SPI_OP_PARAMS Op4BAddEn =3D SPI_OP ( + SPI_OP_CMD (SPI_CMD_4B_ADDR_ENABLE= ), + SPI_OP_NO_ADDR, + SPI_OP_NO_DUMMY, + SPI_OP_NO_DATA + ); + Status =3D SpiMasterProtocol->CmdWrite (SpiMasterProtocol, Slave, &Op4= BAddEn); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Error while setting 4B address\n", __fun= c__)); + return Status; + } + } + + /* Initialize flash status register */ + StatusRegister =3D 0x0; + SPI_OP_PARAMS OpWrSts =3D SPI_OP ( + SPI_OP_CMD (SPI_CMD_WRITE_STATUS_REG), + SPI_OP_NO_ADDR, + SPI_OP_NO_DUMMY, + SPI_OP_DATA_OUT (1, (VOID *)&StatusReg= ister) + ); + + Status =3D SpiMasterProtocol->CmdWrite (SpiMasterProtocol, Slave, &OpWrS= ts); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Error while writing status register\n", __= func__)); + return Status; + } + + Status =3D SpiFlashWriteDisableCmd (Slave); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Error while setting write disable\n", __fu= nc__)); + return Status; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +SpiFlashInitProtocol ( + IN SPI_FLASH_PROTOCOL *SpiFlashProtocol + ) +{ + SpiFlashProtocol->Read =3D SpiFlashRead; + SpiFlashProtocol->Write =3D SpiFlashWrite; + SpiFlashProtocol->Update =3D SpiFlashUpdate; + SpiFlashProtocol->UpdateWithProgress =3D SpiFlashUpdateWithProgress; + SpiFlashProtocol->Erase =3D SpiFlashErase; + SpiFlashProtocol->ReadId =3D SpiFlashReadId; + SpiFlashProtocol->Init =3D SpiFlashInit; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +SpiFlashEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status =3D gBS->LocateProtocol ( + &gJH7110SpiMasterProtocolGuid, + NULL, + (VOID **)&SpiMasterProtocol + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Cannot locate SPI Master protocol\n", __fu= nc__)); + return EFI_DEVICE_ERROR; + } + + mSpiFlashInstance =3D AllocateRuntimeZeroPool (sizeof (SPI_FLASH_INSTANC= E)); + if (mSpiFlashInstance =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory\n", __func__)); + return EFI_OUT_OF_RESOURCES; + } + + SpiFlashInitProtocol (&mSpiFlashInstance->SpiFlashProtocol); + + mSpiFlashInstance->Signature =3D SPI_FLASH_SIGNATURE; + + Status =3D gBS->InstallMultipleProtocolInterfaces ( + &(mSpiFlashInstance->Ha= ndle), + &gJH7110SpiFlashProtoco= lGuid, + &(mSpiFlashInstance->Sp= iFlashProtocol), + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Cannot install SPI flash protocol\n", __fu= nc__)); + goto ErrorInstallProto; + } + + return EFI_SUCCESS; + +ErrorInstallProto: + FreePool (mSpiFlashInstance); + + return EFI_SUCCESS; +} diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDx= e/SpiFlashDxe.h b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFl= ashDxe/SpiFlashDxe.h new file mode 100755 index 000000000000..f3bb300334c0 --- /dev/null +++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFl= ashDxe.h @@ -0,0 +1,35 @@ +/** @file + * + * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.=
+ * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __SPI_FLASH_DXE_H__ +#define __SPI_FLASH_DXE_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define SPI_FLASH_SIGNATURE SIGNATURE_32 ('F', 'S', 'P', 'I') + +#define STATUS_REG_POLL_WIP_MSK (1 << 0) + +typedef struct { + SPI_FLASH_PROTOCOL SpiFlashProtocol; + UINTN Signature; + EFI_HANDLE Handle; +} SPI_FLASH_INSTANCE; + +#endif //__SPI_FLASH_DXE_H__ diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDx= e/SpiFlashDxe.inf b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/Spi= FlashDxe/SpiFlashDxe.inf new file mode 100644 index 000000000000..3ca429fdc2dd --- /dev/null +++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFl= ashDxe.inf @@ -0,0 +1,44 @@ +## @file +# +# Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<= BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D SpiFlashDxe + FILE_GUID =3D D3DF07BE-3810-4521-89EF-C4E22E0B2484 + MODULE_TYPE =3D DXE_RUNTIME_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D SpiFlashEntryPoint + +[Sources] + SpiFlashDxe.c + SpiFlashDxe.h + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec + +[LibraryClasses] + DebugLib + MemoryAllocationLib + NorFlashInfoLib + TimerLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + UefiRuntimeLib + +[Guids] + gEfiEventVirtualAddressChangeGuid + +[Protocols] + gJH7110SpiFlashProtocolGuid + gJH7110SpiMasterProtocolGuid + +[Depex] + gJH7110SpiMasterProtocolGuid diff --git a/Silicon/StarFive/JH7110Pkg/Include/Protocol/Spi.h b/Silicon/St= arFive/JH7110Pkg/Include/Protocol/Spi.h new file mode 100644 index 000000000000..b8db3ad4c5b0 --- /dev/null +++ b/Silicon/StarFive/JH7110Pkg/Include/Protocol/Spi.h @@ -0,0 +1,163 @@ +/** @file + * + * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.=
+ * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __SPI_MASTER_PROTOCOL_H__ +#define __SPI_MASTER_PROTOCOL_H__ + +#include + +typedef struct _SPI_MASTER_PROTOCOL SPI_MASTER_PROTOCOL; + + +#define SPI_CMD_WRITE_STATUS_REG 0x01 +#define SPI_CMD_PAGE_PROGRAM 0x02 +#define SPI_CMD_READ_DATA 0x03 +#define SPI_CMD_WRITE_DISABLE 0x04 +#define SPI_CMD_READ_STATUS 0x05 +#define SPI_CMD_WRITE_ENABLE 0x06 +#define SPI_CMD_READ_ARRAY_FAST 0x0b +#define SPI_CMD_BANKADDR_BRWR 0x17 +#define SPI_CMD_ERASE_4K 0x20 +#define SPI_CMD_ERASE_32K 0x52 +#define SPI_CMD_FLAG_STATUS 0x70 +#define SPI_CMD_READ_ID 0x9f +#define SPI_CMD_4B_ADDR_ENABLE 0xb7 +#define SPI_CMD_BANK_WRITE 0xc5 +#define SPI_CMD_ERASE_64K 0xd8 + + + +#define SPI_OP_CMD(__OpCode) \ + { \ + .OpCode =3D __OpCode, \ + .NBytes =3D 1, \ + } + +#define SPI_OP_ADDR(__NBytes, __Val) \ + { \ + .NBytes =3D __NBytes, \ + .Val =3D __Val, \ + } + +#define SPI_OP_NO_ADDR { } + +#define SPI_OP_DUMMY(__NBytes) \ + { \ + .NBytes =3D __NBytes, \ + } + +#define SPI_OP_NO_DUMMY { } + +#define SPI_OP_DATA_IN(__NBytes, __Buf) \ + { \ + .NBytes =3D __NBytes, \ + .Buf.In =3D __Buf, \ + } + +#define SPI_OP_DATA_OUT(__NBytes, __Buf) \ + { \ + .NBytes =3D __NBytes, \ + .Buf.Out =3D __Buf, \ + } + +#define SPI_OP_NO_DATA { } + +#define SPI_OP(__Cmd, __Addr, __Dummy, __Data) \ + { \ + .Cmd =3D __Cmd, \ + .Addr =3D __Addr, \ + .Dummy =3D __Dummy, \ + .Data =3D __Data, \ + } + +/** + * Standard SPI NOR flash operations + */ +#define SPI_WRITE_EN_OP() \ + SPI_OP(SPI_OP_CMD(SPI_CMD_WRITE_ENABLE), \ + SPI_OP_NO_ADDR, \ + SPI_OP_NO_DUMMY, \ + SPI_OP_NO_DATA) + +#define SPI_WRITE_DIS_OP() \ + SPI_OP(SPI_OP_CMD(SPI_CMD_WRITE_DISABLE), \ + SPI_OP_NO_ADDR, \ + SPI_OP_NO_DUMMY, \ + SPI_OP_NO_DATA) + +#define SPI_READID_OP(Buf, Len) \ + SPI_OP(SPI_OP_CMD(SPI_CMD_READ_ID), \ + SPI_OP_NO_ADDR, \ + SPI_OP_NO_DUMMY, \ + SPI_OP_DATA_IN(Len, Buf)) + +typedef struct { + struct { + UINT8 NBytes; + UINT16 OpCode; + } Cmd; + + struct { + UINT8 NBytes; + UINT64 Val; + } Addr; + + struct { + UINT8 NBytes; + } Dummy; + + struct { + UINT32 NBytes; + union { + VOID *In; + CONST VOID *Out; + } Buf; + } Data; +} SPI_OP_PARAMS; + +typedef struct { + UINT32 AddrSize; + NOR_FLASH_INFO *Info; + UINT32 RegBase; + VOID *AhbBase; + UINT8 FifoWidth; + UINT32 WriteDelay; +} SPI_DEVICE_PARAMS; + +typedef + EFI_STATUS +(EFIAPI *SPI_DEVICE_SETUP)( + IN SPI_MASTER_PROTOCOL *This, + OUT SPI_DEVICE_PARAMS *Slave + ); + +typedef + EFI_STATUS +(EFIAPI *SPI_DEVICE_FREE)( + IN SPI_DEVICE_PARAMS *Slave + ); + + +typedef + EFI_STATUS +(EFIAPI *SPI_EXECUTE_RW)( + IN SPI_MASTER_PROTOCOL *This, + IN SPI_DEVICE_PARAMS *Slave, + IN OUT SPI_OP_PARAMS *Cmds + ); + +struct _SPI_MASTER_PROTOCOL { + SPI_DEVICE_SETUP SetupDevice; + SPI_DEVICE_FREE FreeDevice; + SPI_EXECUTE_RW CmdRead; + SPI_EXECUTE_RW DataRead; + SPI_EXECUTE_RW CmdWrite; + SPI_EXECUTE_RW DataWrite; +}; + +#endif // __SPI_MASTER_PROTOCOL_H__ diff --git a/Silicon/StarFive/JH7110Pkg/Include/Protocol/SpiFlash.h b/Silic= on/StarFive/JH7110Pkg/Include/Protocol/SpiFlash.h new file mode 100644 index 000000000000..cdbe4d0b6b67 --- /dev/null +++ b/Silicon/StarFive/JH7110Pkg/Include/Protocol/SpiFlash.h @@ -0,0 +1,88 @@ +/** @file + * + * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.=
+ * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __SPI_FLASH_PROTOCOL_H__ +#define __SPI_FLASH_PROTOCOL_H__ + +#include +#include + +typedef struct _SPI_FLASH_PROTOCOL SPI_FLASH_PROTOCOL; + +typedef + EFI_STATUS +(EFIAPI *SPI_FLASH_INIT) ( + IN SPI_FLASH_PROTOCOL *This, + IN SPI_DEVICE_PARAMS *SpiDev + ); + +typedef + EFI_STATUS +(EFIAPI *SPI_FLASH_READ_ID) ( + IN SPI_DEVICE_PARAMS *Slave, + IN BOOLEAN UseInRuntime + ); + +typedef + EFI_STATUS +(EFIAPI *SPI_FLASH_READ) ( + IN SPI_DEVICE_PARAMS *Slave, + IN UINT32 Offset, + IN UINTN Length, + OUT VOID *Buffer + ); + +typedef + EFI_STATUS +(EFIAPI *SPI_FLASH_WRITE) ( + IN SPI_DEVICE_PARAMS *Slave, + IN UINT32 Offset, + IN UINTN Length, + IN VOID *Buffer + ); + +typedef + EFI_STATUS +(EFIAPI *SPI_FLASH_ERASE) ( + IN SPI_DEVICE_PARAMS *Slave, + IN UINT32 Offset, + IN UINTN Length + ); + +typedef + EFI_STATUS +(EFIAPI *SPI_FLASH_UPDATE) ( + IN SPI_DEVICE_PARAMS *Slave, + IN UINT32 Address, + IN UINTN DataByteCount, + IN UINT8 *Buffer + ); + +typedef + EFI_STATUS +(EFIAPI *SPI_FLASH_UPDATE_WITH_PROGRESS) ( + IN SPI_DEVICE_PARAMS *Slave, + IN UINT32 Offset, + IN UINTN ByteCount, + IN UINT8 *Buffer, + IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress, OPTIONAL + IN UINTN StartPercentage, + IN UINTN EndPercentage + ); + +struct _SPI_FLASH_PROTOCOL { + SPI_FLASH_INIT Init; + SPI_FLASH_READ_ID ReadId; + SPI_FLASH_READ Read; + SPI_FLASH_WRITE Write; + SPI_FLASH_ERASE Erase; + SPI_FLASH_UPDATE Update; + SPI_FLASH_UPDATE_WITH_PROGRESS UpdateWithProgress; +}; + +#endif // __SPI_FLASH_PROTOCOL_H__ --=20 2.34.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#109897): https://edk2.groups.io/g/devel/message/109897 Mute This Topic: https://groups.io/mt/102130703/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- From nobody Wed May 15 04:43:31 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+109898+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+109898+1787277+3901457@groups.io ARC-Seal: i=1; a=rsa-sha256; t=1698045591; cv=none; d=zohomail.com; s=zohoarc; b=Lham3i/jth4arLkZnrW2Ib3tBkN82ISz5ZQIpNK+1zQSDnVeCbfqIiQlb+6hc3Txg/ad0bha7dAxqsx4eiFJ2SkSSkG9ZAxrDuieh2VGcV/VXkWuahobnghd4KaP8icPU9Q0jbBB0pwRCy/K7k/SQGWrkOFACZxskl78Bzph7f0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1698045591; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=sHwllZgthwZajGH66ZPgVQhpCBdqtiu8e2gMutj7JhA=; b=CgIK/wd1vIkut5caseJmNPFICuPyxcE/fWBVYw+/uPYDXDdeOE5R82Oc+NUEyjy95k3fGUWQa5CQxJACUcFomcFZY0d5M8Kzr7vD/G7sKCeVUkS+M9cGCmwF3OgGtDp/283GMZEcB0i0pt1QqJ/E4uVpzdVl8RwIpjMfvjpvd8U= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+109898+1787277+3901457@groups.io Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1698045591673249.50102278194788; Mon, 23 Oct 2023 00:19:51 -0700 (PDT) Return-Path: DKIM-Signature: a=rsa-sha256; bh=OxF//kb+jMO7L4I0h6+LhksG7cdgDzsgZmwyOmdJ8c8=; c=relaxed/simple; d=groups.io; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References:MIME-Version:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Transfer-Encoding:Content-Type; s=20140610; t=1698045591; v=1; b=n+VL5NKlYQLnlgNWPQjeNZfbZm8vA4lFXxncbUkWIB9/e4HzTj8bJoYK1sMl/mhVnc5ovxlW xQl6suAZWKVJsWZJSePspJEUgupjQ7AF8Hmv4QteqHU2eAqcCysFIVeghgLhmoXImW4MkABIA63 NmJEyr1z/oXCxx6M3En2hJXk= X-Received: by 127.0.0.2 with SMTP id UvorYY1788612xRu34fTvY1g; Mon, 23 Oct 2023 00:19:51 -0700 X-Received: from ex01.ufhost.com (ex01.ufhost.com [61.152.239.75]) by mx.groups.io with SMTP id smtpd.web10.115228.1698045582214444831 for ; Mon, 23 Oct 2023 00:19:50 -0700 X-Received: from EXMBX166.cuchost.com (unknown [175.102.18.54]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "EXMBX166", Issuer "EXMBX166" (not verified)) by ex01.ufhost.com (Postfix) with ESMTP id 7BD7A24E383; Mon, 23 Oct 2023 15:19:38 +0800 (CST) X-Received: from EXMBX073.cuchost.com (172.16.6.83) by EXMBX166.cuchost.com (172.16.6.76) with Microsoft SMTP Server (TLS) id 15.0.1497.42; Mon, 23 Oct 2023 15:19:38 +0800 X-Received: from localhost.localdomain (202.188.176.82) by EXMBX073.cuchost.com (172.16.6.83) with Microsoft SMTP Server (TLS) id 15.0.1497.42; Mon, 23 Oct 2023 15:19:35 +0800 From: "John Chew" To: CC: John Chew , Sunil V L , Leif Lindholm , Michael D Kinney , "Cc : Li Yong" Subject: [edk2-devel] [PATCH v2 3/4] StarFive/JH7110Pkg: Add firmware volume block protocol Date: Mon, 23 Oct 2023 15:18:50 +0800 Message-ID: <20231023071851.813-4-yuinyee.chew@starfivetech.com> In-Reply-To: <20231023071851.813-1-yuinyee.chew@starfivetech.com> References: <20231023071851.813-1-yuinyee.chew@starfivetech.com> MIME-Version: 1.0 X-Originating-IP: [202.188.176.82] X-ClientProxiedBy: EXCAS066.cuchost.com (172.16.6.26) To EXMBX073.cuchost.com (172.16.6.83) X-YovoleRuleAgent: yovoleflag Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,yuinyee.chew@starfivetech.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: L2hwwqtQljEF8h24TwSDKThwx1787277AA= Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1698045592643100003 Content-Type: text/plain; charset="utf-8" Support for efi variable to store in QSPI flash. This driver is responsible to initialize both QSPI and Flash driver. Firmware Volume(FV) Initialization: 1. Copy flash content into allocated shadow buffer (RAM) 2. Check FV header validity 3. If not valid, erase flash based on the region defined in PCDs , else skip 4. If erased, write flash with new FV header, else skip EFI Variable read: 1. Read anbd return the content from the shadow buffer (RAM) EFI Variable write: 1. Write the data into flash 2. Update shadow buffer (RAM) Cc: Sunil V L Cc: Leif Lindholm Cc: Michael D Kinney Cc: Cc: Li Yong Signed-off-by: John Chew --- Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.c | 90= 9 ++++++++++++++++++++ Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.h | 13= 8 +++ Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.inf | 7= 0 ++ 3 files changed, 1117 insertions(+) diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/Fvb= Dxe.c b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.c new file mode 100644 index 000000000000..c30e82ed0871 --- /dev/null +++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.c @@ -0,0 +1,909 @@ +/** @file + * + * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.=
+ * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "FvbDxe.h" + +STATIC FVB_DEVICE *mFvbDevice; + +STATIC CONST FVB_DEVICE mFvbFlashInstanceTemplate =3D { + { + 0, /* AddrSize ... NEED TO BE FILLED */ + NULL, /* Read from NOR FLASH ... NEED TO BE FILLED */ + 0, /* RegBase ... NEED TO BE FILLED */ + 0, /* AbhBase ... NEED TO BE FILLED */ + 0, /* FifoWidth ... NEED TO BE FILLED */ + 0, /* WriteDelay ... NEED TO BE FILLED */ + }, /* SPI_DEVICE_PARAMS */ + + NULL, /* SpiFlashProtocol ... NEED TO BE FILLED */ + NULL, /* SpiMasterProtocol ... NEED TO BE FILLED */ + NULL, /* Handle ... NEED TO BE FILLED */ + + FVB_FLASH_SIGNATURE, /* Signature ... NEED TO BE FILLED */ + + 0, /* ShadowBufBaseAddr ... NEED TO BE FILLED */ + 0, /* ShadowBufSize ... NEED TO BE FILLED */ + 0, /* FvbFlashVarOffset ... NEED TO BE FILLED */ + 0, /* FvbFlashVarSize ... NEED TO BE FILLED */ + 0, /* BlockSize ... NEED TO BE FILLED */ + 0, /* LastBlock ... NEED TO BE FILLED */ + 0, /* StartLba */ + + { + FvbGetAttributes, /* GetAttributes */ + FvbSetAttributes, /* SetAttributes */ + FvbGetPhysicalAddress, /* GetPhysicalAddress */ + FvbGetBlockSize, /* GetBlockSize */ + FvbRead, /* Read */ + FvbWrite, /* Write */ + FvbEraseBlocks, /* EraseBlocks */ + NULL, /* ParentHandle */ + }, /* EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL */ + + { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8)sizeof (VENDOR_DEVICE_PATH), + (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8) + } + }, + { 0xfc0cb972, 0x21df, 0x44d2, { 0x92, 0xa5, 0x78, 0x98, 0x99, 0xcb, = 0xf6, 0x61 } + } + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } + } + } /* FVB_DEVICE_PATH */ +}; + +STATIC +EFI_STATUS +FvbInitFvAndVariableStoreHeaders ( + IN FVB_DEVICE *FlashInstance + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *FirmwareVolumeHeader; + VARIABLE_STORE_HEADER *VariableStoreHeader; + EFI_STATUS Status; + VOID *Headers; + UINTN HeadersLength; + UINTN BlockSize; + + HeadersLength =3D sizeof (EFI_FIRMWARE_VOLUME_HEADER) + + sizeof (EFI_FV_BLOCK_MAP_ENTRY) + + sizeof (VARIABLE_STORE_HEADER); + Headers =3D AllocateZeroPool (HeadersLength); + + BlockSize =3D FlashInstance->BlockSize; + + /* VariableBase -> FtwWOrkingBase -> FtwSpareBase are declared + * consecutively in contiguous memory + */ + ASSERT ( + PcdGet64 (PcdFlashNvStorageVariableBase64) + + PcdGet32 (PcdFlashNvStorageVariableSize) =3D=3D + PcdGet64 (PcdFlashNvStorageFtwWorkingBase64) + ); + ASSERT ( + PcdGet64 (PcdFlashNvStorageFtwWorkingBase64) + + PcdGet32 (PcdFlashNvStorageFtwWorkingSize) =3D=3D + PcdGet64 (PcdFlashNvStorageFtwSpareBase64) + ); + + /* Ensure the size of the variable area is at least one block size */ + ASSERT ( + (PcdGet32 (PcdFlashNvStorageVariableSize) > 0) && + (PcdGet32 (PcdFlashNvStorageVariableSize) / BlockSize > 0) + ); + ASSERT ( + (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) > 0) && + (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) / BlockSize > 0) + ); + ASSERT ( + (PcdGet32 (PcdFlashNvStorageFtwSpareSize) > 0) && + (PcdGet32 (PcdFlashNvStorageFtwSpareSize) / BlockSize > 0) + ); + + /* Ensure the Variable areas are aligned on block size boundaries */ + ASSERT ((PcdGet64 (PcdFlashNvStorageVariableBase64) % BlockSize) =3D=3D = 0); + ASSERT ((PcdGet64 (PcdFlashNvStorageFtwWorkingBase64) % BlockSize) =3D= =3D 0); + ASSERT ((PcdGet64 (PcdFlashNvStorageFtwSpareBase64) % BlockSize) =3D=3D = 0); + + /* --------------------------------------------- + * | Firmware Volume Header | | + * -------------------------- Non-Volatile | + * | Variable Store Header | Storage Variable | + * -------------------------- Region | + * | Variables | | + * --------------------------------------------- + */ + + /* Prepare Firmware Volume Header */ + FirmwareVolumeHeader =3D (EFI_FIRMWARE_VOLUME_HEADER *)Headers; + CopyGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid= ); + FirmwareVolumeHeader->FvLength =3D FlashInstance->FvbFlashVarSize; + FirmwareVolumeHeader->Signature =3D EFI_FVH_SIGNATURE; + FirmwareVolumeHeader->Attributes =3D EFI_FVB2_READ_ENABLED_CAP | /* Read= s may be enabled */ + EFI_FVB2_READ_STATUS | /* Reads = are currently enabled */ + EFI_FVB2_STICKY_WRITE | /* A bloc= k erase is required to flip bits into EFI_FVB2_ERASE_POLARITY */ + EFI_FVB2_ERASE_POLARITY | /* After = erasure all bits take this value (i.e. '1') */ + EFI_FVB2_WRITE_STATUS | /* Writes= are currently enabled */ + EFI_FVB2_WRITE_ENABLED_CAP; /* Writes= may be enabled */ + + FirmwareVolumeHeader->HeaderLength =3D sizeof (EFI_FIRMWARE_VOLUME_HEADE= R) + + sizeof (EFI_FV_BLOCK_MAP_ENTRY); + FirmwareVolumeHeader->Revision =3D EFI_FVH_REVISION; + FirmwareVolumeHeader->BlockMap[0].NumBlocks =3D FlashInstance->LastBlock= + 1; + FirmwareVolumeHeader->BlockMap[0].Length =3D FlashInstance->BlockSize; + FirmwareVolumeHeader->BlockMap[1].NumBlocks =3D 0; + FirmwareVolumeHeader->BlockMap[1].Length =3D 0; + FirmwareVolumeHeader->Checksum =3D CalculateCheckSum16 ( + (UINT= 16 *)FirmwareVolumeHeader, + Firmw= areVolumeHeader->HeaderLength + ); + + /* Prepare Variable Store Header */ + VariableStoreHeader =3D (VOID *)((UINTN)Headers + + FirmwareVolumeHeader->HeaderLength); + CopyGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGui= d); + VariableStoreHeader->Size =3D PcdGet32 (PcdFlashNvStorageVariableSize) - + FirmwareVolumeHeader->HeaderLength; + VariableStoreHeader->Format =3D VARIABLE_STORE_FORMATTED; + VariableStoreHeader->State =3D VARIABLE_STORE_HEALTHY; + + /* Write both header to the flash device on the base address of the + * declared variable base address in the flash. CAUTIONS! This will + * replace the existing firmware volume and variable header or possibly + * cause data corruption. Make sure the declared base address and size + * in the flash is only use for EFI Variable Storage. + * Offset =3D 0, LastBlockAdress =3D 0; + */ + Status =3D FvbWrite (&FlashInstance->FvbProtocol, 0, 0, &HeadersLength, = Headers); + + FreePool (Headers); + + return Status; +} + +STATIC +EFI_STATUS +FvbValidateFvHeader ( + IN FVB_DEVICE *FlashInstance + ) +{ + UINT16 Checksum; + EFI_FIRMWARE_VOLUME_HEADER *FirmwareVolumeHeader; + VARIABLE_STORE_HEADER *VariableStoreHeader; + UINTN VariableStoreLength; + + FirmwareVolumeHeader =3D (EFI_FIRMWARE_VOLUME_HEADER *)FlashInstance->Sh= adowBufBaseAddr; + + /* Verify the header revision, header signature, length from the flash */ + if ((FirmwareVolumeHeader->Revision !=3D EFI_FVH_REVISION) || + (FirmwareVolumeHeader->Signature !=3D EFI_FVH_SIGNATURE) || + (FirmwareVolumeHeader->FvLength !=3D FlashInstance->FvbFlashVarSize= )) + { + DEBUG ( + (DEBUG_ERROR, + "%a(): No Firmware Volume header present\n", + __func__) + ); + return EFI_NOT_FOUND; + } + + /* Verify the Firmware Volume Guid from the flash */ + if (!CompareGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDa= taFvGuid)) { + DEBUG ( + (DEBUG_ERROR, + "%a(): Firmware Volume Guid non-compatible\n", + __func__) + ); + return EFI_NOT_FOUND; + } + + /* Verify the header checksum from the flash */ + Checksum =3D CalculateSum16 ((UINT16 *)FirmwareVolumeHeader, FirmwareVol= umeHeader->HeaderLength); + if (Checksum !=3D 0) { + DEBUG ( + (DEBUG_ERROR, + "%a(): FV checksum is invalid (Checksum:0x%x)\n", + __func__, + Checksum) + ); + return EFI_NOT_FOUND; + } + + VariableStoreHeader =3D (VOID *)((UINTN)FirmwareVolumeHeader + FirmwareV= olumeHeader->HeaderLength); + + /* Verify the Variable Store Guid */ + if (!CompareGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid) && + !CompareGuid ( + &VariableStoreHeader->Signature, + &gEfiAuthenticatedVariableGuid + )) + { + DEBUG ( + (DEBUG_ERROR, + "%a(): Variable Store Guid non-compatible\n", + __func__) + ); + return EFI_NOT_FOUND; + } + + /* Verify the actual Variable Store length with declare size in header*/ + VariableStoreLength =3D PcdGet32 (PcdFlashNvStorageVariableSize) - + FirmwareVolumeHeader->HeaderLength; + if (VariableStoreHeader->Size !=3D VariableStoreLength) { + DEBUG ( + (DEBUG_ERROR, + "%a(): Variable Store Length does not match\n", + __func__) + ); + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +FvbGetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *FirmwareVolumeHeader; + EFI_FVB_ATTRIBUTES_2 *FlashFvbAttributes; + FVB_DEVICE *FlashInstance; + + FlashInstance =3D INSTANCE_FROM_FVB_THIS (This); + + FirmwareVolumeHeader =3D (EFI_FIRMWARE_VOLUME_HEADER *)FlashInsta= nce->ShadowBufBaseAddr; + FlashFvbAttributes =3D (EFI_FVB_ATTRIBUTES_2 *)&(FirmwareVolumeHeader->A= ttributes); + + *Attributes =3D *FlashFvbAttributes; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +FvbSetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ) +{ + EFI_FVB_ATTRIBUTES_2 OldAttributes; + EFI_FVB_ATTRIBUTES_2 FlashFvbAttributes; + EFI_FVB_ATTRIBUTES_2 UnchangedAttributes; + FVB_DEVICE *FlashInstance; + UINT32 Capabilities; + UINT32 OldStatus; + UINT32 NewStatus; + + FlashInstance =3D INSTANCE_FROM_FVB_THIS (This); + + /* Read current attribute from the Frimware Volume Header */ + FvbGetAttributes (This, &FlashFvbAttributes); + + OldAttributes =3D FlashFvbAttributes; + Capabilities =3D OldAttributes & EFI_FVB2_CAPABILITIES; + OldStatus =3D OldAttributes & EFI_FVB2_STATUS; + NewStatus =3D *Attributes & EFI_FVB2_STATUS; + + UnchangedAttributes =3D EFI_FVB2_READ_DISABLED_CAP | \ + EFI_FVB2_READ_ENABLED_CAP | \ + EFI_FVB2_WRITE_DISABLED_CAP | \ + EFI_FVB2_WRITE_ENABLED_CAP | \ + EFI_FVB2_LOCK_CAP | \ + EFI_FVB2_STICKY_WRITE | \ + EFI_FVB2_ERASE_POLARITY | \ + EFI_FVB2_READ_LOCK_CAP | \ + EFI_FVB2_WRITE_LOCK_CAP | \ + EFI_FVB2_ALIGNMENT; + + /* Some attributes of FV is read only can *not* be set */ + if ((OldAttributes & UnchangedAttributes) ^ + (*Attributes & UnchangedAttributes)) + { + return EFI_INVALID_PARAMETER; + } + + /* If firmware volume is locked, no status bit can be updated */ + if (OldAttributes & EFI_FVB2_LOCK_STATUS) { + if (OldStatus ^ NewStatus) { + return EFI_ACCESS_DENIED; + } + } + + /* Test read disable */ + if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) =3D=3D 0) { + if ((NewStatus & EFI_FVB2_READ_STATUS) =3D=3D 0) { + return EFI_INVALID_PARAMETER; + } + } + + /* Test read enable */ + if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) =3D=3D 0) { + if (NewStatus & EFI_FVB2_READ_STATUS) { + return EFI_INVALID_PARAMETER; + } + } + + /* Test write disable */ + if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) =3D=3D 0) { + if ((NewStatus & EFI_FVB2_WRITE_STATUS) =3D=3D 0) { + return EFI_INVALID_PARAMETER; + } + } + + /* Test write enable */ + if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) =3D=3D 0) { + if (NewStatus & EFI_FVB2_WRITE_STATUS) { + return EFI_INVALID_PARAMETER; + } + } + + /* Test lock */ + if ((Capabilities & EFI_FVB2_LOCK_CAP) =3D=3D 0) { + if (NewStatus & EFI_FVB2_LOCK_STATUS) { + return EFI_INVALID_PARAMETER; + } + } + + FlashFvbAttributes =3D FlashFvbAttributes & (0xFFFFFFFF & (~EFI_FVB2_STA= TUS)); + FlashFvbAttributes =3D FlashFvbAttributes | NewStatus; + *Attributes =3D FlashFvbAttributes; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +FvbGetPhysicalAddress ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + OUT EFI_PHYSICAL_ADDRESS *Address + ) +{ + FVB_DEVICE *FlashInstance; + + ASSERT (Address !=3D NULL); + + FlashInstance =3D INSTANCE_FROM_FVB_THIS (This); + + /* Do not support MMIO, return the shadow buffer instead */ + *Address =3D FlashInstance->ShadowBufBaseAddr; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +FvbGetBlockSize ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumberOfBlocks + ) +{ + FVB_DEVICE *FlashInstance; + + FlashInstance =3D INSTANCE_FROM_FVB_THIS (This); + + if (Lba > FlashInstance->LastBlock) { + DEBUG ( + (DEBUG_ERROR, + "%a(): Error: Requested LBA %ld is beyond the last available L= BA (%ld).\n", + __func__, + Lba, + FlashInstance->LastBlock) + ); + return EFI_INVALID_PARAMETER; + } else { + /* Assume equal sized blocks in all flash devices */ + *BlockSize =3D (UINTN)FlashInstance->BlockSize; + *NumberOfBlocks =3D (UINTN)(FlashInstance->LastBlock - Lba + 1); + + return EFI_SUCCESS; + } +} + +EFI_STATUS +EFIAPI +FvbRead ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN OUT UINT8 *Buffer + ) +{ + FVB_DEVICE *FlashInstance; + UINTN BlockSize; + UINTN DataOffset; + + FlashInstance =3D INSTANCE_FROM_FVB_THIS (This); + + /* Cache the block size to avoid de-referencing pointers all the time */ + BlockSize =3D FlashInstance->BlockSize; + + /* Offset + byte have to be within the define block size. + * The read must not span block boundaries. We need to + * check each variable individually because adding two + * large values together migght cause overflows. + */ + if ((Offset >=3D BlockSize) || + (*NumBytes > BlockSize) || + ((Offset + *NumBytes) > BlockSize)) + { + DEBUG ( + (DEBUG_ERROR, + "%a(): Wrong buffer size: (Offset=3D0x%x + NumBytes=3D0x%x) > = BlockSize=3D0x%x\n", + __func__, + Offset, + *NumBytes, + BlockSize) + ); + return EFI_BAD_BUFFER_SIZE; + } + + /* No bytes to read */ + if (*NumBytes =3D=3D 0) { + return EFI_SUCCESS; + } + + DataOffset =3D GET_DATA_OFFSET ( + FlashInstance->ShadowBufBaseAddr + Offset, + FlashInstance->StartLba + Lba, + FlashInstance->BlockSize + ); + + /* Copy variable from the shadow buffer */ + CopyMem (Buffer, (UINTN *)DataOffset, *NumBytes); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +FvbWrite ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +{ + EFI_STATUS Status; + FVB_DEVICE *FlashInstance; + UINTN DataOffset; + + FlashInstance =3D INSTANCE_FROM_FVB_THIS (This); + + DataOffset =3D GET_DATA_OFFSET ( + FlashInstance->FvbFlashVarOffset + Offset, + FlashInstance->StartLba + Lba, + FlashInstance->BlockSize + ); + + Status =3D FlashInstance->SpiFlashProtocol->Write ( + &FlashInstance->SpiDevi= ce, + DataOffset, + *NumBytes, + Buffer + ); + if (EFI_ERROR (Status)) { + DEBUG ( + (DEBUG_ERROR, + "%a(): Failed to write to Spi device\n", + __func__) + ); + return Status; + } + + DataOffset =3D GET_DATA_OFFSET ( + FlashInstance->ShadowBufBaseAddr + Offset, + FlashInstance->StartLba + Lba, + FlashInstance->BlockSize + ); + + /* Update shadow buffer */ + CopyMem ((UINTN *)DataOffset, Buffer, *NumBytes); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +FvbEraseBlocks ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + ... + ) +{ + EFI_FVB_ATTRIBUTES_2 FlashFvbAttributes; + FVB_DEVICE *FlashInstance; + EFI_STATUS Status; + VA_LIST Args; + UINTN BlockAddress; /* Physical address of Lba to erase= */ + EFI_LBA StartingLba; /* Lba from which we start erasing = */ + UINTN NumOfLba; /* Number of Lba blocks to erase */ + + FlashInstance =3D INSTANCE_FROM_FVB_THIS (This); + + Status =3D EFI_SUCCESS; + + /* Detect WriteDisabled state */ + FvbGetAttributes (This, &FlashFvbAttributes); + if ((FlashFvbAttributes & EFI_FVB2_WRITE_STATUS) =3D=3D 0) { + DEBUG ( + (DEBUG_ERROR, + "%a(): Device is in WriteDisabled state.\n", + __func__) + ); + return EFI_ACCESS_DENIED; + } + + /* + * Before erasing, check the entire list of parameters to ensure + * all specified blocks are valid. + */ + VA_START (Args, This); + do { + /* Get the Lba from which we start erasing */ + StartingLba =3D VA_ARG (Args, EFI_LBA); + + /* Have we reached the end of the list? */ + if (StartingLba =3D=3D EFI_LBA_LIST_TERMINATOR) { + break; + } + + /* How many Lba blocks are we requested to erase? */ + NumOfLba =3D VA_ARG (Args, UINT32); + + /* All blocks must be within range */ + if ((NumOfLba =3D=3D 0) || + ((FlashInstance->StartLba + StartingLba + NumOfLba - 1) > + FlashInstance->LastBlock)) + { + DEBUG ( + (DEBUG_ERROR, + "%a(): Error: Requested LBA are beyond the last available LB= A (%ld).\n", + __func__, + FlashInstance->LastBlock) + ); + + VA_END (Args); + + return EFI_INVALID_PARAMETER; + } + } while (TRUE); + + VA_END (Args); + + /* Start erasing */ + VA_START (Args, This); + do { + /* Get the Lba from which we start erasing */ + StartingLba =3D VA_ARG (Args, EFI_LBA); + + /* Have we reached the end of the list? */ + if (StartingLba =3D=3D EFI_LBA_LIST_TERMINATOR) { + break; + } + + /* How many Lba blocks are we requested to erase? */ + NumOfLba =3D VA_ARG (Args, UINT32); + + /* Go through each requested block and erase it */ + while (NumOfLba > 0) { + /* Get the offset address of Lba to erase */ + BlockAddress =3D GET_DATA_OFFSET ( + FlashInstance->FvbFlashVarOffset, + FlashInstance->StartLba + StartingLb= a, + FlashInstance->BlockSize + ); + + /* Erase single block */ + Status =3D FlashInstance->SpiFlashProtocol->Erase ( + &FlashInstance->Spi= Device, + BlockAddress, + FlashInstance->Bloc= kSize + ); + if (EFI_ERROR (Status)) { + VA_END (Args); + return EFI_DEVICE_ERROR; + } + + StartingLba++; + NumOfLba--; + } + } while (TRUE); + + VA_END (Args); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +FvbFlashProbe ( + IN FVB_DEVICE *FlashInstance + ) +{ + SPI_FLASH_PROTOCOL *SpiFlashProtocol; + EFI_STATUS Status; + + SpiFlashProtocol =3D FlashInstance->SpiFlashProtocol; + + /* Read SPI flash ID */ + Status =3D SpiFlashProtocol->ReadId (&FlashInstance->SpiDevice, TRUE); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + Status =3D SpiFlashProtocol->Init (SpiFlashProtocol, &FlashInstance->Spi= Device); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Cannot initialize flash device\n", __func_= _)); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +FvbPrepareFvHeader ( + IN FVB_DEVICE *FlashInstance + ) +{ + EFI_BOOT_MODE BootMode; + EFI_STATUS Status; + + /* Check if it is required to use default environment */ + BootMode =3D GetBootModeHob (); + if (BootMode =3D=3D BOOT_WITH_DEFAULT_SETTINGS) { + Status =3D EFI_INVALID_PARAMETER; + } else { + /* Validate header at the beginning of FV region */ + Status =3D FvbValidateFvHeader (FlashInstance); + } + + /* Install the default FVB header if required */ + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): The FVB Header is not valid.\n", __func__)= ); + DEBUG ( + (DEBUG_ERROR, + "%a(): Installing a correct one for this volume.\n", + __func__) + ); + + /* Erase entire region that is reserved for variable storage in flash = */ + Status =3D FlashInstance->SpiFlashProtocol->Erase ( + &FlashInstance->SpiDe= vice, + FlashInstance->FvbFla= shVarOffset, + FlashInstance->FvbFla= shVarSize + ); + if (EFI_ERROR (Status)) { + return Status; + } + + /* Write a new firmware volume and varaible storage headers */ + Status =3D FvbInitFvAndVariableStoreHeaders (FlashInstance); + if (EFI_ERROR (Status)) { + return Status; + } + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +FvbConfigureFlashInstance ( + IN OUT FVB_DEVICE *FlashInstance + ) +{ + EFI_STATUS Status; + UINTN DataOffset; + UINTN VariableSize, FtwWorkingSize, FtwSpareSize, MemorySize; + + Status =3D gBS->LocateProtocol ( + &gJH7110SpiFlashProtocolGuid, + NULL, + (VOID **)&FlashInstance->SpiFlashProtocol + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Cannot locate SpiFlash protocol\n", __func= __)); + return Status; + } + + Status =3D gBS->LocateProtocol ( + &gJH7110SpiMasterProtocolGuid, + NULL, + (VOID **)&FlashInstance->SpiMasterProtocol + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Cannot locate SpiMaster protocol\n", __fun= c__)); + return Status; + } + + /* Setup and probe SPI flash */ + FlashInstance->SpiMasterProtocol->SetupDevice ( + FlashInstance->SpiMasterP= rotocol, + &FlashInstance->SpiDevice + ); + Status =3D FvbFlashProbe (FlashInstance); + if (EFI_ERROR (Status)) { + DEBUG ( + (DEBUG_ERROR, + "%a(): Error while performing SPI flash probe\n", + __func__) + ); + return Status; + } + + /* Fill remaining flash description */ + VariableSize =3D PcdGet32 (PcdFlashNvStorageVariableSize); + FtwWorkingSize =3D PcdGet32 (PcdFlashNvStorageFtwWorkingSize); + FtwSpareSize =3D PcdGet32 (PcdFlashNvStorageFtwSpareSize); + + FlashInstance->FvbFlashVarSize =3D VariableSize + FtwWorkingSize + Ft= wSpareSize; + FlashInstance->FvbFlashVarOffset =3D PcdGet32(PcdJH7110FlashVarOffset); + FlashInstance->BlockSize =3D FlashInstance->SpiDevice.Info->SectorSize; + FlashInstance->LastBlock =3D (FlashInstance->FvbFlashVarSize / + FlashInstance->BlockSize) - 1; + FlashInstance->ShadowBufSize =3D FlashInstance->FvbFlashVarSize; + + /* Allocate memory for shadow buffer */ + MemorySize =3D EFI_SIZE_TO_PAGES (FlashInstance->FvbFlashVarSize); + + /* FaultTolerantWriteDxe requires memory to be aligned to FtwWorkingSize= */ + FlashInstance->ShadowBufBaseAddr =3D (UINTN)AllocateAlignedRuntimePages ( + = MemorySize, + = SIZE_64KB + = ); + if (FlashInstance->ShadowBufBaseAddr =3D=3D (UINTN)NULL) { + return EFI_OUT_OF_RESOURCES; + } + + /* Update PCDs value according to allocated memory */ + Status =3D PcdSet64S ( + PcdFlashNvStorageVariableBase64, + (UINT64)FlashInstance->ShadowBufBaseAddr + ); + ASSERT_EFI_ERROR (Status); + Status =3D PcdSet64S ( + PcdFlashNvStorageFtwWorkingBase64, + (UINT64)FlashInstance->ShadowBufBaseAddr + + VariableSize + ); + ASSERT_EFI_ERROR (Status); + Status =3D PcdSet64S ( + PcdFlashNvStorageFtwSpareBase64, + (UINT64)FlashInstance->ShadowBufBaseAddr + + VariableSize + + FtwWorkingSize + ); + ASSERT_EFI_ERROR (Status); + + /* ill the shadow buffer with data from flash */ + DataOffset =3D GET_DATA_OFFSET ( + FlashInstance->FvbFlashVarOffset, + FlashInstance->StartLba, + FlashInstance->BlockSize + ); + Status =3D FlashInstance->SpiFlashProtocol->Read ( + &FlashInstance->SpiDevic= e, + DataOffset, + FlashInstance->FvbFlashV= arSize, + (VOID *)FlashInstance->S= hadowBufBaseAddr + ); + if (EFI_ERROR (Status)) { + goto ErrorFreeAllocatedPages; + } + + Status =3D gBS->InstallMultipleProtocolInterfaces ( + &FlashInstance->Handle, + &gEfiDevicePathProtocol= Guid, + &FlashInstance->DeviceP= ath, + &gEfiFirmwareVolumeBloc= kProtocolGuid, + &FlashInstance->FvbProt= ocol, + NULL + ); + if (EFI_ERROR (Status)) { + goto ErrorFreeAllocatedPages; + } + + Status =3D FvbPrepareFvHeader (FlashInstance); + if (EFI_ERROR (Status)) { + goto ErrorPrepareFvbHeader; + } + + return EFI_SUCCESS; + +ErrorPrepareFvbHeader: + gBS->UninstallMultipleProtocolInterfaces ( + &FlashInstance->Handle, + &gEfiDevicePathProtocolGuid, + &gEfiFirmwareVolumeBlockProtoc= olGuid, + NULL + ); + +ErrorFreeAllocatedPages: + FreeAlignedPages ( + (VOID *)FlashInstance->ShadowBufBaseAddr, + MemorySize + ); + + return Status; +} + +EFI_STATUS +EFIAPI +FvbEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + /* Allocate memory for FVB flash device*/ + mFvbDevice =3D AllocateRuntimeCopyPool ( + sizeof (mFvbFlashInstanceTemplate), + &mFvbFlashInstanceTemplate + ); + if (mFvbDevice =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory\n", __func__)); + return EFI_OUT_OF_RESOURCES; + } + + /* Detect and configure flash device */ + Status =3D FvbConfigureFlashInstance (mFvbDevice); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Fail to configure Fvb SPI device\n", __fun= c__)); + goto ErrorConfigureFlash; + } + + /* The driver implementing the variable read service can now be dispatch= ed; + * the varstore headers are in place. + */ + Status =3D gBS->InstallProtocolInterface ( + &gImageHandle, + &gEdkiiNvVarStoreFormattedGuid, + EFI_NATIVE_INTERFACE, + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG ( + (DEBUG_ERROR, + "%a(): Failed to install gEdkiiNvVarStoreFormattedGuid\n", + __func__) + ); + goto ErrorInstallNvVarStoreFormatted; + } + + return Status; + +ErrorInstallNvVarStoreFormatted: + gBS->UninstallMultipleProtocolInterfaces ( + &mFvbDevice->Handle, + &gEfiDevicePathProtocolGuid, + &gEfiFirmwareVolumeBlockProtoc= olGuid, + NULL + ); + +ErrorConfigureFlash: + FreePool (mFvbDevice); + + return Status; +} diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/Fvb= Dxe.h b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.h new file mode 100644 index 000000000000..6b0450b17275 --- /dev/null +++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.h @@ -0,0 +1,138 @@ +/** @file + * + * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.=
+ * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __FVB_DXE_H__ +#define __FVB_DXE_H__ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#define GET_DATA_OFFSET(BaseAddr, Lba, LbaSize) ((BaseAddr) + (UINTN)((Lb= a) * (LbaSize))) + +#define FVB_FLASH_SIGNATURE SIGNATURE_32('S', 'n', 'o', 'r') +#define INSTANCE_FROM_FVB_THIS(a) CR(a, FVB_DEVICE, FvbProtocol, FVB_FLAS= H_SIGNATURE) + +// +// Define two helper macro to extract the Capability field or Status field= in FVB +// bit fields. +// +#define EFI_FVB2_CAPABILITIES (EFI_FVB2_READ_DISABLED_CAP |\ + EFI_FVB2_READ_ENABLED_CAP | \ + EFI_FVB2_WRITE_DISABLED_CAP | \ + EFI_FVB2_WRITE_ENABLED_CAP | \ + EFI_FVB2_LOCK_CAP) + +#define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | \ + EFI_FVB2_WRITE_STATUS | \ + EFI_FVB2_LOCK_STATUS) + +typedef struct { + VENDOR_DEVICE_PATH Vendor; + EFI_DEVICE_PATH_PROTOCOL End; +} FVB_DEVICE_PATH; + +typedef struct { + SPI_DEVICE_PARAMS SpiDevice; + + SPI_FLASH_PROTOCOL *SpiFlashProtocol; + SPI_MASTER_PROTOCOL *SpiMasterProtocol; + + EFI_HANDLE Handle; + + UINT32 Signature; + + UINTN ShadowBufBaseAddr; + UINTN ShadowBufSize; + UINTN FvbFlashVarOffset; + UINTN FvbFlashVarSize; + UINTN BlockSize; + UINTN LastBlock; + EFI_LBA StartLba; + + EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL FvbProtocol; + + FVB_DEVICE_PATH DevicePath; +} FVB_DEVICE; + +EFI_STATUS +EFIAPI +FvbGetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ); + +EFI_STATUS +EFIAPI +FvbSetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ); + +EFI_STATUS +EFIAPI +FvbGetPhysicalAddress ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + OUT EFI_PHYSICAL_ADDRESS *Address + ); + +EFI_STATUS +EFIAPI +FvbGetBlockSize ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumberOfBlocks + ); + +EFI_STATUS +EFIAPI +FvbRead ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN OUT UINT8 *Buffer + ); + +EFI_STATUS +EFIAPI +FvbWrite ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ); + +EFI_STATUS +EFIAPI +FvbEraseBlocks ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + ... + ); + +#endif //__FVB_DXE_H__ diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/Fvb= Dxe.inf b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe= .inf new file mode 100644 index 000000000000..715989bfcc2b --- /dev/null +++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.inf @@ -0,0 +1,70 @@ +## @file +# +# Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<= BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x0001001A + BASE_NAME =3D FvbDxe + FILE_GUID =3D DB8BFC83-6DEA-4AD1-AD3D-FDC579430233 + MODULE_TYPE =3D DXE_RUNTIME_DRIVER + VERSION_STRING =3D 0.1 + ENTRY_POINT =3D FvbEntryPoint + +[Sources] + FvbDxe.c + +[Packages] + ArmPlatformPkg/ArmPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + DevicePathLib + DxeServicesTableLib + HobLib + IoLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + UefiRuntimeLib + UefiRuntimeServicesTableLib + +[Guids] + gEdkiiNvVarStoreFormattedGuid + gEfiAuthenticatedVariableGuid + gEfiEventVirtualAddressChangeGuid + gEfiSystemNvDataFvGuid + gEfiVariableGuid + +[Protocols] + gEfiDevicePathProtocolGuid + gEfiFirmwareVolumeBlockProtocolGuid + gJH7110SpiFlashProtocolGuid + gJH7110SpiMasterProtocolGuid + +[FixedPcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize + gJH7110TokenSpaceGuid.PcdJH7110FlashVarOffset + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64 + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64 + +[Depex] + gEfiCpuArchProtocolGuid AND + gJH7110SpiMasterProtocolGuid AND + gJH7110SpiFlashProtocolGuid --=20 2.34.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#109898): https://edk2.groups.io/g/devel/message/109898 Mute This Topic: https://groups.io/mt/102130707/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- From nobody Wed May 15 04:43:31 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+109899+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+109899+1787277+3901457@groups.io ARC-Seal: i=1; a=rsa-sha256; t=1698045595; cv=none; d=zohomail.com; s=zohoarc; b=YSd4D8fqcSsVPGIFIc8v7TgxryDq6NnR9oc5g0CL43IsQMVQD/nVxU2Zca1LQ5vARQdJ8b7QSwTiigPzZ1AOp3byoV8mTMFNgBc9k5ONoB0lvuHhOymiAcW9VY2QHLkDQ76MXBwO7nnn7+5RYyQ1VJaWFEtOMXF9Xz6Pu6HfKzg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1698045595; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=5syEnf2unBceGLA5snpG0RQPUGbcN+abxuscmKDkm7c=; b=T0/TGlzNcA5P/qT2RFBTiwW9UR/ULp6FSwo1ZTaYj6u90MJOH6Jqpp3I3O2VE5qfFCDXqD2ESNi9p7vDu+itwNwZbzWq9bNCCZ16lm8RLy4Db/BvqONXc9wp8cusA6vuw3rvzkP1Tjf0s8fn2pQkZSwcul7z2VucbKGQe3dKoTw= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+109899+1787277+3901457@groups.io Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1698045595432836.6092152365841; Mon, 23 Oct 2023 00:19:55 -0700 (PDT) Return-Path: DKIM-Signature: a=rsa-sha256; bh=b/YjdSI1g+hejux5QlGeww7Au211Si1J/sx6q5KVkNU=; c=relaxed/simple; d=groups.io; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References:MIME-Version:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Transfer-Encoding:Content-Type; s=20140610; t=1698045595; v=1; b=o60AJ2QopS62L+y8sbF/iZOIhkr2uYZMaFMK89DlHpILyj1ZgtYwDsouES6B2txv0DYT4MKK 1r2+Q9674VDRg1C3gRAVtgvyWC+5A7qanFvFQc+6Tx6bSwHSG7q9ab2/szYVoLPvTZTc+hrITzp x7Q3JQnqV7lh1oM4yKp1etCM= X-Received: by 127.0.0.2 with SMTP id ANKlYY1788612xKwNl5S0eOf; Mon, 23 Oct 2023 00:19:55 -0700 X-Received: from ex01.ufhost.com (ex01.ufhost.com [61.152.239.75]) by mx.groups.io with SMTP id smtpd.web11.115589.1698045593502738413 for ; Mon, 23 Oct 2023 00:19:54 -0700 X-Received: from EXMBX165.cuchost.com (unknown [175.102.18.54]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "EXMBX165", Issuer "EXMBX165" (not verified)) by ex01.ufhost.com (Postfix) with ESMTP id F3C5D24E389; Mon, 23 Oct 2023 15:19:42 +0800 (CST) X-Received: from EXMBX073.cuchost.com (172.16.6.83) by EXMBX165.cuchost.com (172.16.6.75) with Microsoft SMTP Server (TLS) id 15.0.1497.42; Mon, 23 Oct 2023 15:19:42 +0800 X-Received: from localhost.localdomain (202.188.176.82) by EXMBX073.cuchost.com (172.16.6.83) with Microsoft SMTP Server (TLS) id 15.0.1497.42; Mon, 23 Oct 2023 15:19:39 +0800 From: "John Chew" To: CC: mindachen1987 , Sunil V L , Leif Lindholm , Michael D Kinney , "Cc : Li Yong" , John Chew Subject: [edk2-devel] [PATCH v2 4/4] StarFive/JH7110Pkg: Add JH7110 Silicon Package Date: Mon, 23 Oct 2023 15:18:51 +0800 Message-ID: <20231023071851.813-5-yuinyee.chew@starfivetech.com> In-Reply-To: <20231023071851.813-1-yuinyee.chew@starfivetech.com> References: <20231023071851.813-1-yuinyee.chew@starfivetech.com> MIME-Version: 1.0 X-Originating-IP: [202.188.176.82] X-ClientProxiedBy: EXCAS066.cuchost.com (172.16.6.26) To EXMBX073.cuchost.com (172.16.6.83) X-YovoleRuleAgent: yovoleflag Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,yuinyee.chew@starfivetech.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: 8IPaaGblcOvEQhhDIXr6gTPPx1787277AA= Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1698045596616100003 Content-Type: text/plain; charset="utf-8" From: mindachen1987 v2: - Remove redundant commented PCDs [Sunil] - Remove unused PCD: PcdJH7110RegistersAddress [John Chew] - Added PCIE PCDs: PcdPciBusMin, PcdPciBusMax, PcdPciBusMax, PcdPciIoSize, PcdPciIoOffset, PcdPci0Mmio32Base, PcdPci0Mmio32Size, PcdPci0Mmio64Base, PcdPci0Mmio64Size, PcdPci1Mmio32Base, PcdPci1Mmio32Size, PcdPci1Mmio64Base, PcdPci1Mmio64Size [John Chew] v1: - Add a new JH7110 silicon package. - These files Contain platfrom specific Guids, PCDs and defines used for JH7110 SoC. Cc: Sunil V L Cc: Leif Lindholm Cc: Michael D Kinney Cc: Cc: Li Yong Co-authored-by: John Chew Signed-off-by: mindachen1987 --- Silicon/StarFive/JH7110Pkg/Include/IndustryStandard/JH7110.h | 21 ++++++++ Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec | 57 ++++++++= ++++++++++++ 2 files changed, 78 insertions(+) diff --git a/Silicon/StarFive/JH7110Pkg/Include/IndustryStandard/JH7110.h b= /Silicon/StarFive/JH7110Pkg/Include/IndustryStandard/JH7110.h new file mode 100644 index 000000000000..142e7be10c48 --- /dev/null +++ b/Silicon/StarFive/JH7110Pkg/Include/IndustryStandard/JH7110.h @@ -0,0 +1,21 @@ +/** @file + * + * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.=
+ * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef JH7110_H__ +#define JH7110_H__ + +/* Generic PCI addresses */ +#define PCIE_TOP_OF_MEM_WIN (FixedPcdGet64 (PcdPciBusMmioAdr)) +#define PCIE_CPU_MMIO_WINDOW (FixedPcdGet64 (PcdPciCpuMmioAdr)) +#define PCIE_BRIDGE_MMIO_LEN (FixedPcdGet32 (PcdPciBusMmioLen)) + +/* PCI root bridge control registers location */ +#define PCIE_REG_BASE (FixedPcdGet64 (PcdPciRegBase)) +#define PCIE_CONFIG_BASE (FixedPcdGet64 (PcdPciConfigRegBase)) + +#endif /* JH7110_H__ */ diff --git a/Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec b/Silicon/StarFive/JH= 7110Pkg/JH7110Pkg.dec new file mode 100644 index 000000000000..f9dc5ab3781d --- /dev/null +++ b/Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec @@ -0,0 +1,57 @@ +## @file +# +# Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<= BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + DEC_SPECIFICATION =3D 0x0001001A + PACKAGE_NAME =3D JH7110Pkg + PACKAGE_GUID =3D D4B585C5-EBCA-4779-B974-05A3CF2F10C4 + PACKAGE_VERSION =3D 1.0 + +[Includes] + Include + +[Guids] + gJH7110TokenSpaceGuid =3D {0x44045e56, 0x7056, 0x4be6, {0x88, 0xc0, 0x49= , 0x0c, 0x67, 0x90, 0x2f, 0xba}} + +[PcdsFixedAtBuild.common] +# Memory map + gJH7110TokenSpaceGuid.PcdJH7110FlashVarOffset|0x0|UINT32|0x00000001 + +# PCIe + gJH7110TokenSpaceGuid.PcdPciRegBase|0x2b000000|UINT64|0x00000002 + gJH7110TokenSpaceGuid.PcdPciBusMmioAdr|0x0|UINT64|0x00000003 + gJH7110TokenSpaceGuid.PcdPciBusMmioLen|0x0|UINT32|0x00000004 + gJH7110TokenSpaceGuid.PcdPciCpuMmioAdr|0x0|UINT64|0x00000005 + gJH7110TokenSpaceGuid.PcdPciConfigRegBase|0x940000000|UINT64|0x00000006 + gJH7110TokenSpaceGuid.PcdPciBusMin|0x0|UINT32|0x10000007 + gJH7110TokenSpaceGuid.PcdPciBusMax|0x0|UINT32|0x10000008 + gJH7110TokenSpaceGuid.PcdPciIoBase|0x0|UINT64|0x10000009 + gJH7110TokenSpaceGuid.PcdPciIoSize|0x0|UINT64|0x1000000A + gJH7110TokenSpaceGuid.PcdPciIoOffset|0x0|UINT64|0x1000000B + gJH7110TokenSpaceGuid.PcdPci0Mmio32Base|0x0|UINT32|0x1000000C + gJH7110TokenSpaceGuid.PcdPci0Mmio32Size|0x0|UINT32|0x1000000D + gJH7110TokenSpaceGuid.PcdPci0Mmio64Base|0x0|UINT64|0x1000000E + gJH7110TokenSpaceGuid.PcdPci0Mmio64Size|0x0|UINT64|0x1000000F + gJH7110TokenSpaceGuid.PcdPci1Mmio32Base|0x0|UINT32|0x10000010 + gJH7110TokenSpaceGuid.PcdPci1Mmio32Size|0x0|UINT32|0x1000011 + gJH7110TokenSpaceGuid.PcdPci1Mmio64Base|0x0|UINT64|0x1000012 + gJH7110TokenSpaceGuid.PcdPci1Mmio64Size|0x0|UINT64|0x1000013 + +# SPI + gJH7110TokenSpaceGuid.PcdSpiFlashRegBase|0|UINT32|0x1000014 + gJH7110TokenSpaceGuid.PcdSpiFlashAhbBase|0|UINT64|0x1000015 + gJH7110TokenSpaceGuid.PcdSpiFlashFifoWidth|0|UINT8|0x10000016 + gJH7110TokenSpaceGuid.PcdSpiFlashRefClkHz|0|UINT32|0x10000017 + gJH7110TokenSpaceGuid.PcdSpiFlashTshslNs|0|UINT32|0x10000018 + gJH7110TokenSpaceGuid.PcdSpiFlashTsd2dNs|0|UINT32|0x1000019 + gJH7110TokenSpaceGuid.PcdSpiFlashTchshNs|0|UINT32|0x100001A + gJH7110TokenSpaceGuid.PcdSpiFlashTslchNs|0|UINT32|0x100001B + +[Protocols] + gJH7110SpiMasterProtocolGuid =3D { 0xA33C46E0, 0x4FB6, 0x4AA3, { 0x8E, 0= x66, 0x00, 0x06, 0x9F, 0x3A, 0x11, 0x81 }} + gJH7110SpiFlashProtocolGuid =3D { 0x5ECECDF6, 0x81DA, 0x4E10, { 0x9D, 0= x4B, 0x26, 0x65, 0x8C, 0x03, 0xAB, 0xBC }} --=20 2.34.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#109899): https://edk2.groups.io/g/devel/message/109899 Mute This Topic: https://groups.io/mt/102130708/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-