From patchwork Wed Apr 27 12:58:29 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 66786 Delivered-To: patch@linaro.org Received: by 10.140.93.198 with SMTP id d64csp2172696qge; Wed, 27 Apr 2016 05:58:42 -0700 (PDT) X-Received: by 10.98.103.28 with SMTP id b28mr11705653pfc.155.1461761922228; Wed, 27 Apr 2016 05:58:42 -0700 (PDT) Return-Path: Received: from ml01.01.org (ml01.01.org. [2001:19d0:306:5::1]) by mx.google.com with ESMTPS id s16si4107153pfi.193.2016.04.27.05.58.41 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 27 Apr 2016 05:58:42 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 2001:19d0:306:5::1 as permitted sender) client-ip=2001:19d0:306:5::1; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org; spf=pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 2001:19d0:306:5::1 as permitted sender) smtp.mailfrom=edk2-devel-bounces@lists.01.org; dmarc=fail (p=NONE dis=NONE) header.from=linaro.org Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 8D3181A1EDD; Wed, 27 Apr 2016 05:58:41 -0700 (PDT) X-Original-To: edk2-devel@lists.01.org Delivered-To: edk2-devel@lists.01.org Received: from mail-wm0-x229.google.com (mail-wm0-x229.google.com [IPv6:2a00:1450:400c:c09::229]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 35E171A1EDC for ; Wed, 27 Apr 2016 05:58:39 -0700 (PDT) Received: by mail-wm0-x229.google.com with SMTP id e201so37677845wme.0 for ; Wed, 27 Apr 2016 05:58:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id; bh=GmTb5q6FiU61el5kUFrhUfAJUiSn/cVNQNP4cmNZ+Bs=; b=aVLh+zaf03jb1+IrxCzrIMPAaO/ySh3zJ+O73NXlwt2K8I1CzaL+1xGF29Q4DeT3Pp 9qzPSoW+e55wGjNG1OQyXKtH3WQMOnsm7plV624wkvqEhGOeBsHk7tWOdB0ZcGy9s1v7 4cX0cIfY8X8qz31ZdMDIliI4D9iD8Tdzv4ItU= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=GmTb5q6FiU61el5kUFrhUfAJUiSn/cVNQNP4cmNZ+Bs=; b=Es0KyBYzhOh12lTGahlGgC3LvP+ECAifAOVoonF3KWEMx05NgDQYEymqQcThBsDeu+ HUYqTsN5PPomHdNvv6U831nmbdo44pBd88z7ret4yrJ3Fbdw5VgCPF6+qx6n32EIH/YE 4hs4Si9pYABnk+94G2dtouQMZWGkNFcrNo0GIsrNRHlCXbIoS8ULUM2b1dHEe9e1lLP1 zDEcDRCzfqCir2P95aS490j1T1XdmYjjr9XrIJhhCum0I7fgRBHeGKfblIF1PYvm1XLs 5qQogKsv2beSucniW2X8gvoF+rj6iNEC7fBQf5jxbX2VyLuPVsiWOYGjCFe1TQMxpF3E lbJA== X-Gm-Message-State: AOPr4FXLDViC0uiZM6wkOIxx5oAFAaEV/LadiNZ/DBGFdF11KsraLfHPsvg4kjr1dQGAUjir X-Received: by 10.194.81.135 with SMTP id a7mr9087252wjy.170.1461761916110; Wed, 27 Apr 2016 05:58:36 -0700 (PDT) Received: from localhost.localdomain ([195.55.142.58]) by smtp.gmail.com with ESMTPSA id u187sm18132866wmu.21.2016.04.27.05.58.33 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 27 Apr 2016 05:58:35 -0700 (PDT) From: Ard Biesheuvel To: edk2-devel@lists.01.org, leif.lindholm@linaro.org Date: Wed, 27 Apr 2016 14:58:29 +0200 Message-Id: <1461761909-22398-1-git-send-email-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.7.4 Subject: [edk2] [PATCH] ArmPlatformPkg: implement CpuIo2 protocol driver specific for PCI X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Ard Biesheuvel MIME-Version: 1.0 Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" The CpuIo2 protocol is required by the generic PciHostBridgeDxe driver, which relies on it to back its own I/O and MMIO operations. Since ARM has no native I/O port equivalent, such accesses can only originate from PCI drivers, and the PCI I/O space is translated to MMIO in this case. So we can implement this protocol using MMIO operations only, and take the PCI I/O translation offset into account when performing I/O port accesses. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel --- We will need this on Seattle to support PCI devices with I/O BARs when we move to the generic PciHostBridgeDxe driver. ArmPlatformPkg/Drivers/CpuIo2Dxe/ArmPciCpuIo2Dxe.c | 559 ++++++++++++++++++++ ArmPlatformPkg/Drivers/CpuIo2Dxe/ArmPciCpuIo2Dxe.inf | 53 ++ 2 files changed, 612 insertions(+) -- 2.7.4 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel diff --git a/ArmPlatformPkg/Drivers/CpuIo2Dxe/ArmPciCpuIo2Dxe.c b/ArmPlatformPkg/Drivers/CpuIo2Dxe/ArmPciCpuIo2Dxe.c new file mode 100644 index 000000000000..fecf6a87adce --- /dev/null +++ b/ArmPlatformPkg/Drivers/CpuIo2Dxe/ArmPciCpuIo2Dxe.c @@ -0,0 +1,559 @@ +/** @file + Produces the CPU I/O 2 Protocol. + +Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.
+Copyright (c) 2016, Linaro Ltd. All rights reserved.
+ +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include + +#include +#include +#include +#include +#include + +#define MAX_IO_PORT_ADDRESS 0xFFFF + +// +// Handle for the CPU I/O 2 Protocol +// +STATIC EFI_HANDLE mHandle = NULL; + +// +// Lookup table for increment values based on transfer widths +// +STATIC CONST UINT8 mInStride[] = { + 1, // EfiCpuIoWidthUint8 + 2, // EfiCpuIoWidthUint16 + 4, // EfiCpuIoWidthUint32 + 8, // EfiCpuIoWidthUint64 + 0, // EfiCpuIoWidthFifoUint8 + 0, // EfiCpuIoWidthFifoUint16 + 0, // EfiCpuIoWidthFifoUint32 + 0, // EfiCpuIoWidthFifoUint64 + 1, // EfiCpuIoWidthFillUint8 + 2, // EfiCpuIoWidthFillUint16 + 4, // EfiCpuIoWidthFillUint32 + 8 // EfiCpuIoWidthFillUint64 +}; + +// +// Lookup table for increment values based on transfer widths +// +STATIC CONST UINT8 mOutStride[] = { + 1, // EfiCpuIoWidthUint8 + 2, // EfiCpuIoWidthUint16 + 4, // EfiCpuIoWidthUint32 + 8, // EfiCpuIoWidthUint64 + 1, // EfiCpuIoWidthFifoUint8 + 2, // EfiCpuIoWidthFifoUint16 + 4, // EfiCpuIoWidthFifoUint32 + 8, // EfiCpuIoWidthFifoUint64 + 0, // EfiCpuIoWidthFillUint8 + 0, // EfiCpuIoWidthFillUint16 + 0, // EfiCpuIoWidthFillUint32 + 0 // EfiCpuIoWidthFillUint64 +}; + +/** + Check parameters to a CPU I/O 2 Protocol service request. + + The I/O operations are carried out exactly as requested. The caller is responsible + for satisfying any alignment and I/O width restrictions that a PI System on a + platform might require. For example on some platforms, width requests of + EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will + be handled by the driver. + + @param[in] MmioOperation TRUE for an MMIO operation, FALSE for I/O Port operation. + @param[in] Width Signifies the width of the I/O or Memory operation. + @param[in] Address The base address of the I/O operation. + @param[in] Count The number of I/O operations to perform. The number of + bytes moved is Width size * Count, starting at Address. + @param[in] Buffer For read operations, the destination buffer to store the results. + For write operations, the source buffer from which to write data. + + @retval EFI_SUCCESS The parameters for this request pass the checks. + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width. + @retval EFI_UNSUPPORTED The address range specified by Address, Width, + and Count is not valid for this PI system. + +**/ +STATIC +EFI_STATUS +CpuIoCheckParameter ( + IN BOOLEAN MmioOperation, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ) +{ + UINT64 MaxCount; + UINT64 Limit; + + // + // Check to see if Buffer is NULL + // + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Check to see if Width is in the valid range + // + if ((UINT32)Width >= EfiCpuIoWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + // + // For FIFO type, the target address won't increase during the access, + // so treat Count as 1 + // + if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) { + Count = 1; + } + + // + // Check to see if Width is in the valid range for I/O Port operations + // + Width = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03); + if (!MmioOperation && (Width == EfiCpuIoWidthUint64)) { + return EFI_INVALID_PARAMETER; + } + + // + // Check to see if Address is aligned + // + if ((Address & (UINT64)(mInStride[Width] - 1)) != 0) { + return EFI_UNSUPPORTED; + } + + // + // Check to see if any address associated with this transfer exceeds the maximum + // allowed address. The maximum address implied by the parameters passed in is + // Address + Size * Count. If the following condition is met, then the transfer + // is not supported. + // + // Address + Size * Count > (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS) + 1 + // + // Since MAX_ADDRESS can be the maximum integer value supported by the CPU and Count + // can also be the maximum integer value supported by the CPU, this range + // check must be adjusted to avoid all oveflow conditions. + // + // The following form of the range check is equivalent but assumes that + // MAX_ADDRESS and MAX_IO_PORT_ADDRESS are of the form (2^n - 1). + // + Limit = (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS); + if (Count == 0) { + if (Address > Limit) { + return EFI_UNSUPPORTED; + } + } else { + MaxCount = RShiftU64 (Limit, Width); + if (MaxCount < (Count - 1)) { + return EFI_UNSUPPORTED; + } + if (Address > LShiftU64 (MaxCount - Count + 1, Width)) { + return EFI_UNSUPPORTED; + } + } + + // + // Check to see if Buffer is aligned + // + if (((UINTN)Buffer & ((MIN (sizeof (UINTN), mInStride[Width]) - 1))) != 0) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +/** + Reads memory-mapped registers. + + The I/O operations are carried out exactly as requested. The caller is responsible + for satisfying any alignment and I/O width restrictions that a PI System on a + platform might require. For example on some platforms, width requests of + EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will + be handled by the driver. + + If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32, + or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for + each of the Count operations that is performed. + + If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16, + EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is + incremented for each of the Count operations that is performed. The read or + write operation is performed Count times on the same Address. + + If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16, + EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is + incremented for each of the Count operations that is performed. The read or + write operation is performed Count times from the first element of Buffer. + + @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance. + @param[in] Width Signifies the width of the I/O or Memory operation. + @param[in] Address The base address of the I/O operation. + @param[in] Count The number of I/O operations to perform. The number of + bytes moved is Width size * Count, starting at Address. + @param[out] Buffer For read operations, the destination buffer to store the results. + For write operations, the source buffer from which to write data. + + @retval EFI_SUCCESS The data was read from or written to the PI system. + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width. + @retval EFI_UNSUPPORTED The address range specified by Address, Width, + and Count is not valid for this PI system. + +**/ +STATIC +EFI_STATUS +EFIAPI +CpuMemoryServiceRead ( + IN EFI_CPU_IO2_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINT8 InStride; + UINT8 OutStride; + EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth; + UINT8 *Uint8Buffer; + + Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Select loop based on the width of the transfer + // + InStride = mInStride[Width]; + OutStride = mOutStride[Width]; + OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03); + for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) { + if (OperationWidth == EfiCpuIoWidthUint8) { + *Uint8Buffer = MmioRead8 ((UINTN)Address); + } else if (OperationWidth == EfiCpuIoWidthUint16) { + *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address); + } else if (OperationWidth == EfiCpuIoWidthUint32) { + *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address); + } else if (OperationWidth == EfiCpuIoWidthUint64) { + *((UINT64 *)Uint8Buffer) = MmioRead64 ((UINTN)Address); + } + } + return EFI_SUCCESS; +} + +/** + Writes memory-mapped registers. + + The I/O operations are carried out exactly as requested. The caller is responsible + for satisfying any alignment and I/O width restrictions that a PI System on a + platform might require. For example on some platforms, width requests of + EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will + be handled by the driver. + + If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32, + or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for + each of the Count operations that is performed. + + If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16, + EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is + incremented for each of the Count operations that is performed. The read or + write operation is performed Count times on the same Address. + + If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16, + EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is + incremented for each of the Count operations that is performed. The read or + write operation is performed Count times from the first element of Buffer. + + @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance. + @param[in] Width Signifies the width of the I/O or Memory operation. + @param[in] Address The base address of the I/O operation. + @param[in] Count The number of I/O operations to perform. The number of + bytes moved is Width size * Count, starting at Address. + @param[in] Buffer For read operations, the destination buffer to store the results. + For write operations, the source buffer from which to write data. + + @retval EFI_SUCCESS The data was read from or written to the PI system. + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width. + @retval EFI_UNSUPPORTED The address range specified by Address, Width, + and Count is not valid for this PI system. + +**/ +STATIC +EFI_STATUS +EFIAPI +CpuMemoryServiceWrite ( + IN EFI_CPU_IO2_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ) +{ + EFI_STATUS Status; + UINT8 InStride; + UINT8 OutStride; + EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth; + UINT8 *Uint8Buffer; + + Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Select loop based on the width of the transfer + // + InStride = mInStride[Width]; + OutStride = mOutStride[Width]; + OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03); + for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) { + if (OperationWidth == EfiCpuIoWidthUint8) { + MmioWrite8 ((UINTN)Address, *Uint8Buffer); + } else if (OperationWidth == EfiCpuIoWidthUint16) { + MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer)); + } else if (OperationWidth == EfiCpuIoWidthUint32) { + MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer)); + } else if (OperationWidth == EfiCpuIoWidthUint64) { + MmioWrite64 ((UINTN)Address, *((UINT64 *)Uint8Buffer)); + } + } + return EFI_SUCCESS; +} + +/** + Reads I/O registers. + + The I/O operations are carried out exactly as requested. The caller is responsible + for satisfying any alignment and I/O width restrictions that a PI System on a + platform might require. For example on some platforms, width requests of + EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will + be handled by the driver. + + If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32, + or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for + each of the Count operations that is performed. + + If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16, + EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is + incremented for each of the Count operations that is performed. The read or + write operation is performed Count times on the same Address. + + If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16, + EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is + incremented for each of the Count operations that is performed. The read or + write operation is performed Count times from the first element of Buffer. + + @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance. + @param[in] Width Signifies the width of the I/O or Memory operation. + @param[in] Address The base address of the I/O operation. + @param[in] Count The number of I/O operations to perform. The number of + bytes moved is Width size * Count, starting at Address. + @param[out] Buffer For read operations, the destination buffer to store the results. + For write operations, the source buffer from which to write data. + + @retval EFI_SUCCESS The data was read from or written to the PI system. + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width. + @retval EFI_UNSUPPORTED The address range specified by Address, Width, + and Count is not valid for this PI system. + +**/ +STATIC +EFI_STATUS +EFIAPI +CpuIoServiceRead ( + IN EFI_CPU_IO2_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINT8 InStride; + UINT8 OutStride; + EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth; + UINT8 *Uint8Buffer; + + Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer); + if (EFI_ERROR (Status)) { + return Status; + } + + Address += PcdGet64 (PcdPciIoTranslation); + + // + // Select loop based on the width of the transfer + // + InStride = mInStride[Width]; + OutStride = mOutStride[Width]; + OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03); + + for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) { + if (OperationWidth == EfiCpuIoWidthUint8) { + *Uint8Buffer = MmioRead8 ((UINTN)Address); + } else if (OperationWidth == EfiCpuIoWidthUint16) { + *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address); + } else if (OperationWidth == EfiCpuIoWidthUint32) { + *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address); + } + } + + return EFI_SUCCESS; +} + +/** + Write I/O registers. + + The I/O operations are carried out exactly as requested. The caller is responsible + for satisfying any alignment and I/O width restrictions that a PI System on a + platform might require. For example on some platforms, width requests of + EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will + be handled by the driver. + + If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32, + or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for + each of the Count operations that is performed. + + If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16, + EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is + incremented for each of the Count operations that is performed. The read or + write operation is performed Count times on the same Address. + + If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16, + EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is + incremented for each of the Count operations that is performed. The read or + write operation is performed Count times from the first element of Buffer. + + @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance. + @param[in] Width Signifies the width of the I/O or Memory operation. + @param[in] Address The base address of the I/O operation. + @param[in] Count The number of I/O operations to perform. The number of + bytes moved is Width size * Count, starting at Address. + @param[in] Buffer For read operations, the destination buffer to store the results. + For write operations, the source buffer from which to write data. + + @retval EFI_SUCCESS The data was read from or written to the PI system. + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width. + @retval EFI_UNSUPPORTED The address range specified by Address, Width, + and Count is not valid for this PI system. + +**/ +STATIC +EFI_STATUS +EFIAPI +CpuIoServiceWrite ( + IN EFI_CPU_IO2_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN VOID *Buffer + ) +{ + EFI_STATUS Status; + UINT8 InStride; + UINT8 OutStride; + EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth; + UINT8 *Uint8Buffer; + + // + // Make sure the parameters are valid + // + Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer); + if (EFI_ERROR (Status)) { + return Status; + } + + Address += PcdGet64 (PcdPciIoTranslation); + + // + // Select loop based on the width of the transfer + // + InStride = mInStride[Width]; + OutStride = mOutStride[Width]; + OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03); + + for (Uint8Buffer = (UINT8 *)Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) { + if (OperationWidth == EfiCpuIoWidthUint8) { + MmioWrite8 ((UINTN)Address, *Uint8Buffer); + } else if (OperationWidth == EfiCpuIoWidthUint16) { + MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer)); + } else if (OperationWidth == EfiCpuIoWidthUint32) { + MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer)); + } + } + + return EFI_SUCCESS; +} + +// +// CPU I/O 2 Protocol instance +// +STATIC EFI_CPU_IO2_PROTOCOL mCpuIo2 = { + { + CpuMemoryServiceRead, + CpuMemoryServiceWrite + }, + { + CpuIoServiceRead, + CpuIoServiceWrite + } +}; + + +/** + The user Entry Point for module CpuIo2Dxe. The user code starts with this function. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +ArmPciCpuIo2Initialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiCpuIo2ProtocolGuid); + Status = gBS->InstallMultipleProtocolInterfaces ( + &mHandle, + &gEfiCpuIo2ProtocolGuid, &mCpuIo2, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/ArmPlatformPkg/Drivers/CpuIo2Dxe/ArmPciCpuIo2Dxe.inf b/ArmPlatformPkg/Drivers/CpuIo2Dxe/ArmPciCpuIo2Dxe.inf new file mode 100644 index 000000000000..6513e9843121 --- /dev/null +++ b/ArmPlatformPkg/Drivers/CpuIo2Dxe/ArmPciCpuIo2Dxe.inf @@ -0,0 +1,53 @@ +## @file +# Produces the CPU I/O 2 Protocol by using the services of the I/O Library. +# +# Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
+# Copyright (c) 2016, Linaro Ltd. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = ArmPciCpuIo2Dxe + FILE_GUID = 168D1A6E-F4A5-448A-9E95-795661BB3067 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = ArmPciCpuIo2Initialize + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = ARM AARCH64 +# + +[Sources] + ArmPciCpuIo2Dxe.c + +[Packages] + MdePkg/MdePkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + BaseLib + DebugLib + IoLib + PcdLib + UefiBootServicesTableLib + +[Pcd] + gArmPlatformTokenSpaceGuid.PcdPciIoTranslation + +[Protocols] + gEfiCpuIo2ProtocolGuid ## PRODUCES + +[Depex] + TRUE