summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeif Lindholm <leif.lindholm@linaro.org>2017-05-03 17:47:23 +0100
committerLeif Lindholm <leif.lindholm@linaro.org>2017-07-14 22:36:51 +0100
commit0189ff331b9bdd9353624bc7b509e53148976806 (patch)
tree481788a26d43fdad9f762256111ece2926b7835a
parent8322634459ac602d9fbcca30e96b24ff098acb3c (diff)
downloadedk2-platforms-devel-OpenPlatformPkg.tar.xz
Platform: import Marvell Armada supportdevel-OpenPlatformPkg
Import Armada 70x0 suppport from OpenPlatformPkg, together with its documentation and utilities. Imported from commit efd798c1eb of https://git.linaro.org/uefi/OpenPlatformPkg.git Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
-rw-r--r--Platform/Marvell/Applications/EepromCmd/EepromCmd.c397
-rw-r--r--Platform/Marvell/Applications/EepromCmd/EepromCmd.inf71
-rw-r--r--Platform/Marvell/Applications/EepromCmd/EepromCmd.unibin0 -> 6816 bytes
-rw-r--r--Platform/Marvell/Applications/FirmwareUpdate/FUpdate.c413
-rw-r--r--Platform/Marvell/Applications/FirmwareUpdate/FUpdate.inf75
-rw-r--r--Platform/Marvell/Applications/FirmwareUpdate/FUpdate.unibin0 -> 5146 bytes
-rw-r--r--Platform/Marvell/Applications/SpiTool/SpiFlashCmd.c526
-rw-r--r--Platform/Marvell/Applications/SpiTool/SpiFlashCmd.inf75
-rw-r--r--Platform/Marvell/Applications/SpiTool/SpiFlashCmd.unibin0 -> 7216 bytes
-rw-r--r--Platform/Marvell/Armada/Armada.dsc.inc482
-rw-r--r--Platform/Marvell/Armada/Armada70x0.dsc145
-rw-r--r--Platform/Marvell/Armada/Armada70x0.fdf304
-rw-r--r--Platform/Marvell/Armada/Library/Armada70x0Lib/AArch64/ArmPlatformHelper.S50
-rw-r--r--Platform/Marvell/Armada/Library/Armada70x0Lib/Armada70x0Lib.c157
-rw-r--r--Platform/Marvell/Armada/Library/Armada70x0Lib/Armada70x0Lib.inf71
-rw-r--r--Platform/Marvell/Armada/Library/Armada70x0Lib/Armada70x0LibMem.c93
-rw-r--r--Platform/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.c335
-rw-r--r--Platform/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.h50
-rw-r--r--Platform/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.inf52
-rw-r--r--Platform/Marvell/Documentation/Drivers/EepromDriver.txt96
-rw-r--r--Platform/Marvell/Documentation/Drivers/I2cDriver.txt64
-rw-r--r--Platform/Marvell/Documentation/Drivers/SpiDriver.txt116
-rw-r--r--Platform/Marvell/Documentation/PortingGuide/ComPhy.txt45
-rw-r--r--Platform/Marvell/Documentation/PortingGuide/I2c.txt20
-rw-r--r--Platform/Marvell/Documentation/PortingGuide/Mdio.txt7
-rw-r--r--Platform/Marvell/Documentation/PortingGuide/Mpp.txt48
-rw-r--r--Platform/Marvell/Documentation/PortingGuide/PciEmulation.txt31
-rw-r--r--Platform/Marvell/Documentation/PortingGuide/Phy.txt45
-rw-r--r--Platform/Marvell/Documentation/PortingGuide/Pp2.txt59
-rw-r--r--Platform/Marvell/Documentation/PortingGuide/Reset.txt7
-rw-r--r--Platform/Marvell/Documentation/PortingGuide/Spi.txt16
-rw-r--r--Platform/Marvell/Documentation/PortingGuide/SpiFlash.txt23
-rw-r--r--Platform/Marvell/Documentation/PortingGuide/Utmi.txt35
-rw-r--r--Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.c292
-rw-r--r--Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.h103
-rw-r--r--Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.inf70
-rwxr-xr-xPlatform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.c740
-rw-r--r--Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.h269
-rwxr-xr-xPlatform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf75
-rw-r--r--Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.c237
-rw-r--r--Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.h57
-rw-r--r--Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.inf69
-rw-r--r--Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.c438
-rw-r--r--Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.h194
-rw-r--r--Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.inf71
-rw-r--r--Platform/Marvell/Drivers/Net/Pp2Dxe/Mvpp2Lib.c4839
-rw-r--r--Platform/Marvell/Drivers/Net/Pp2Dxe/Mvpp2Lib.h726
-rw-r--r--Platform/Marvell/Drivers/Net/Pp2Dxe/Mvpp2LibHw.h1968
-rw-r--r--Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.c1271
-rw-r--r--Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.h614
-rw-r--r--Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.inf91
-rw-r--r--Platform/Marvell/Drivers/SdMmc/XenonDxe/ComponentName.c211
-rwxr-xr-xPlatform/Marvell/Drivers/SdMmc/XenonDxe/EmmcDevice.c1162
-rw-r--r--Platform/Marvell/Drivers/SdMmc/XenonDxe/SdDevice.c1190
-rw-r--r--Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.c1315
-rw-r--r--Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.h785
-rw-r--r--Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.inf64
-rw-r--r--Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.uni23
-rw-r--r--Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxeExtra.uni19
-rw-r--r--Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHci.c1923
-rw-r--r--Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHci.h546
-rwxr-xr-xPlatform/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.c665
-rw-r--r--Platform/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.h346
-rwxr-xr-xPlatform/Marvell/Drivers/Spi/Devices/MvSpiFlash.c531
-rwxr-xr-xPlatform/Marvell/Drivers/Spi/Devices/MvSpiFlash.h132
-rw-r--r--Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.inf67
-rwxr-xr-xPlatform/Marvell/Drivers/Spi/MvSpiDxe.c379
-rw-r--r--Platform/Marvell/Drivers/Spi/MvSpiDxe.h145
-rw-r--r--Platform/Marvell/Drivers/Spi/MvSpiDxe.inf66
-rw-r--r--Platform/Marvell/Include/Library/MppLib.h42
-rw-r--r--Platform/Marvell/Include/Library/MvComPhyLib.h48
-rw-r--r--Platform/Marvell/Include/Library/MvHwDescLib.h169
-rw-r--r--Platform/Marvell/Include/Library/ParsePcdLib.h46
-rw-r--r--Platform/Marvell/Include/Library/UtmiPhyLib.h43
-rw-r--r--Platform/Marvell/Include/Protocol/Eeprom.h60
-rw-r--r--Platform/Marvell/Include/Protocol/Mdio.h66
-rw-r--r--Platform/Marvell/Include/Protocol/MvPhy.h103
-rw-r--r--Platform/Marvell/Include/Protocol/Spi.h105
-rw-r--r--Platform/Marvell/Include/Protocol/SpiFlash.h113
-rwxr-xr-xPlatform/Marvell/Library/ComPhyLib/ComPhyCp110.c1853
-rw-r--r--Platform/Marvell/Library/ComPhyLib/ComPhyLib.c321
-rw-r--r--Platform/Marvell/Library/ComPhyLib/ComPhyLib.h643
-rw-r--r--Platform/Marvell/Library/ComPhyLib/ComPhyLib.inf84
-rw-r--r--Platform/Marvell/Library/ComPhyLib/ComPhyMux.c132
-rw-r--r--Platform/Marvell/Library/MppLib/MppLib.c216
-rw-r--r--Platform/Marvell/Library/MppLib/MppLib.inf108
-rw-r--r--Platform/Marvell/Library/ParsePcdLib/ParsePcdLib.c228
-rw-r--r--Platform/Marvell/Library/ParsePcdLib/ParsePcdLib.inf50
-rw-r--r--Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.c353
-rw-r--r--Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.h110
-rw-r--r--Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.inf64
-rw-r--r--Platform/Marvell/Marvell.dec204
-rw-r--r--Platform/Marvell/PciEmulation/PciEmulation.c195
-rw-r--r--Platform/Marvell/PciEmulation/PciEmulation.inf61
94 files changed, 31018 insertions, 0 deletions
diff --git a/Platform/Marvell/Applications/EepromCmd/EepromCmd.c b/Platform/Marvell/Applications/EepromCmd/EepromCmd.c
new file mode 100644
index 0000000000..f43e411067
--- /dev/null
+++ b/Platform/Marvell/Applications/EepromCmd/EepromCmd.c
@@ -0,0 +1,397 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#include <Uefi.h>
+
+#include <ShellBase.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/ShellCommandLib.h>
+#include <Library/ShellLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PrintLib.h>
+#include <Library/HiiLib.h>
+
+#include <Library/UefiLib.h>
+#include <Library/ShellCEntryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <Protocol/Eeprom.h>
+
+#define I2C_DEVICE_INDEX(bus, address) (((address) & 0xffff) | (bus) << 16)
+#define I2C_DEVICE_ADDRESS(index) ((index) & 0xffff)
+#define I2C_DEVICE_BUS(index) ((index) >> 16)
+
+CONST CHAR16 ShellEepromFileName[] = L"ShellCommand";
+EFI_HANDLE ShellEepromHiiHandle = NULL;
+
+STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
+ {L"-d", TypeValue},
+ {L"-m", TypeValue},
+ {L"read", TypeFlag},
+ {L"write", TypeFlag},
+ {L"list", TypeFlag},
+ {L"help", TypeFlag},
+ {NULL , TypeMax}
+ };
+
+/**
+ Return the file name of the help text file if not using HII.
+
+ @return The string pointer to the file name.
+**/
+STATIC
+CONST CHAR16*
+EFIAPI
+ShellCommandGetManFileNameEeprom (
+ VOID
+ )
+{
+ return ShellEepromFileName;
+}
+
+STATIC
+VOID
+Usage (
+ VOID
+ )
+{
+ Print (L"Basic EEPROM commands:\n"
+ "eeprom [read] [write] [list] [<Chip>] [<Bus>][<Address>] [<Length>] [-d <Data>] [-m <Source>]\n"
+ "All modes except 'list' require Address, Length and Chip set.\n\n"
+ "read - read from EEPROM\n"
+ "write - write Data to EEPROM, requires -d\n"
+ "list - list available EEPROM devices\n\n"
+ "-m - transfer from/to RAM memory\n\n"
+ "Chip - EEPROM bus address\n"
+ "Bus - I2C bus address\n"
+ "Address - address in EEPROM to read/write\n"
+ "Data - data byte to be written\n"
+ "Length - length of data to read/write/copy\n"
+ "Source - address of data in RAM to be copied\n"
+ "Examples:\n"
+ "List devices:\n"
+ " eeprom list\n"
+ "Read 16 bytes from address 0x0 in chip 0x57:\n"
+ " eeprom read 0x57 0x0 0x0 0x10\n"
+ "Fill 16 bytes with 0xab at address 0x0 in chip 0x57:\n"
+ " eeprom write 0x57 0x0 0x0 0x10 -d 0xab\n"
+ "Copy 32 bytes from 0x2000000 in RAM to EEPROM:\n"
+ " eeprom write 0x57 0x0 0x0 0x20 -m 0x2000000\n"
+ "Copy 32 bytes from EEPROM to RAM:\n"
+ " eeprom read 0x57 0x0 0x0 0x20 -m 0x2000000\n"
+ );
+}
+
+STATIC
+EFI_STATUS
+EepromList (
+ )
+{
+ EFI_HANDLE *HandleBuffer;
+ EFI_STATUS Status;
+ UINTN ProtocolCount;
+ MARVELL_EEPROM_PROTOCOL *EepromProtocol;
+ UINTN i;
+ Status = gBS->LocateHandleBuffer ( ByProtocol,
+ &gMarvellEepromProtocolGuid,
+ NULL,
+ &ProtocolCount,
+ &HandleBuffer
+ );
+ if (ProtocolCount == 0) {
+ Print (L"0 devices found.\n");
+ } else {
+ Print (L"%u devices found: ", ProtocolCount);
+ }
+
+ for (i = 0; i < ProtocolCount; i++) {
+ Status = gBS->OpenProtocol (
+ HandleBuffer[i],
+ &gMarvellEepromProtocolGuid,
+ (VOID **) &EepromProtocol,
+ gImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );
+ Print (L"0x%x at bus %d\n", I2C_DEVICE_ADDRESS(EepromProtocol->Identifier),
+ I2C_DEVICE_BUS(EepromProtocol->Identifier));
+ Status = gBS->CloseProtocol ( HandleBuffer[i],
+ &gMarvellEepromProtocolGuid,
+ gImageHandle,
+ NULL );
+ }
+ Print (L"\n");
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+EepromLocateProtocol (
+ IN UINT32 Identifier,
+ OUT EFI_HANDLE *FoundHandle,
+ OUT MARVELL_EEPROM_PROTOCOL **FoundEepromProtocol
+ )
+{
+ EFI_HANDLE *HandleBuffer;
+ EFI_STATUS Status;
+ UINTN ProtocolCount;
+ MARVELL_EEPROM_PROTOCOL *EepromProtocol;
+ UINTN i;
+ Status = gBS->LocateHandleBuffer ( ByProtocol,
+ &gMarvellEepromProtocolGuid,
+ NULL,
+ &ProtocolCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR(Status))
+ return Status;
+
+ for (i = 0; i < ProtocolCount; i++) {
+ Status = gBS->OpenProtocol (
+ HandleBuffer[i],
+ &gMarvellEepromProtocolGuid,
+ (VOID **) &EepromProtocol,
+ gImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );
+ if (EepromProtocol->Identifier == Identifier) {
+ *FoundEepromProtocol = EepromProtocol;
+ *FoundHandle = HandleBuffer[i];
+ return EFI_SUCCESS;
+ }
+ Status = gBS->CloseProtocol ( HandleBuffer[i],
+ &gMarvellEepromProtocolGuid,
+ gImageHandle,
+ NULL );
+ }
+ *FoundEepromProtocol = NULL;
+ return EFI_UNSUPPORTED;
+}
+
+SHELL_STATUS
+EFIAPI
+ShellCommandRunEeprom (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *CheckPackage;
+ CHAR16 *ProblemParam;
+ CONST CHAR16 *ValueStr;
+ UINTN Address, Length, Chip, Source, Bus;
+ UINT8 Data;
+ UINT8 *Buffer;
+ BOOLEAN ReadMode, MemMode;
+ EFI_HANDLE Handle, ProtHandle;
+ MARVELL_EEPROM_PROTOCOL *EepromProtocol = NULL;
+ UINTN Count, HandleSize;
+
+ Handle = NULL;
+ Source = 0;
+ HandleSize = 2 * sizeof (EFI_HANDLE);
+
+ Status = gBS->LocateHandle (ByProtocol, &gMarvellEepromProtocolGuid, NULL,
+ &HandleSize, &ProtHandle);
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_INFO, "No Eeprom protocol, connect I2C stack\n"));
+ Status = gBS->LocateHandle (ByProtocol, &gEfiI2cMasterProtocolGuid, NULL,
+ &HandleSize, &ProtHandle);
+ if (EFI_ERROR(Status)) {
+ Print (L"Failed to locate I2cMaster protocol, abort!\n");
+ return SHELL_ABORTED;
+ }
+ Status = gBS->ConnectController (ProtHandle, NULL, NULL, TRUE);
+ if (EFI_ERROR(Status)) {
+ Print (L"Cannot connect I2C stack, abort!\n");
+ return SHELL_ABORTED;
+ }
+ }
+
+ Status = ShellInitialize ();
+ if (EFI_ERROR (Status)) {
+ Print (L"Error - failed to initialize shell\n");
+ return SHELL_ABORTED;
+ }
+
+ Status = ShellCommandLineParse (ParamList, &CheckPackage, &ProblemParam, TRUE);
+ if (EFI_ERROR (Status)) {
+ Print (L"Error - failed to parse command line\n");
+ return SHELL_ABORTED;
+ }
+
+ if (ShellCommandLineGetFlag (CheckPackage, L"list")) {
+ EepromList();
+ return SHELL_SUCCESS;
+ }
+
+ if (ShellCommandLineGetFlag (CheckPackage, L"help")) {
+ Usage();
+ return SHELL_SUCCESS;
+ }
+
+ if (ShellCommandLineGetCount(CheckPackage) < 4) {
+ Print (L"Not enough arguments given.\n");
+ Usage();
+ }
+
+ ReadMode = ShellCommandLineGetFlag (CheckPackage, L"read");
+ if (ReadMode == ShellCommandLineGetFlag (CheckPackage, L"write")) {
+ Print (L"Error - type read, write, list or help.\n");
+ return SHELL_INVALID_PARAMETER;
+ }
+
+ MemMode = ShellCommandLineGetFlag (CheckPackage, L"-m");
+ Data = 0;
+ if (!ReadMode && !MemMode) {
+ ValueStr = ShellCommandLineGetValue (CheckPackage, L"-d");
+ if (ValueStr == NULL) {
+ Print (L"Error - no data to write.\n");
+ return SHELL_INVALID_PARAMETER;
+ }
+ Data = ShellHexStrToUintn (ValueStr);
+ }
+
+ ValueStr = ShellCommandLineGetRawValue(CheckPackage, 1);
+ Chip = ShellHexStrToUintn (ValueStr);
+
+ ValueStr = ShellCommandLineGetRawValue(CheckPackage, 2);
+ Bus = ShellHexStrToUintn (ValueStr);
+
+ ValueStr = ShellCommandLineGetRawValue(CheckPackage, 3);
+ Address = ShellHexStrToUintn (ValueStr);
+
+ ValueStr = ShellCommandLineGetRawValue(CheckPackage, 4);
+ Length = ShellHexStrToUintn (ValueStr);
+
+ if (MemMode) {
+ ValueStr = ShellCommandLineGetValue (CheckPackage, L"-m");
+ if (ValueStr == NULL) {
+ Print (L"Error - no memory address given.\n");
+ return SHELL_INVALID_PARAMETER;
+ }
+ Source = ShellHexStrToUintn (ValueStr);
+ }
+
+ EepromLocateProtocol (I2C_DEVICE_INDEX(Bus, Chip), &Handle, &EepromProtocol);
+ if (EepromProtocol == NULL) {
+ Print (L"Failed to locate EEPROM protocol.\n");
+ return SHELL_INVALID_PARAMETER;
+ }
+
+ if (MemMode) {
+ Buffer = (VOID *) Source;
+ } else {
+ Buffer = AllocateZeroPool (Length);
+ if (Buffer == NULL) {
+ Status = SHELL_OUT_OF_RESOURCES;
+ Print (L"Error - out of resources.\n");
+ goto out_close;
+ }
+ if (!ReadMode) {
+ for (Count = 0; Count < Length; Count++)
+ Buffer[Count] = Data;
+ }
+ }
+ EepromProtocol->Transfer(EepromProtocol, Address, Length, Buffer,
+ ReadMode ? EEPROM_READ : EEPROM_WRITE);
+
+ if (MemMode) {
+ Print (L"Transfered succesfully.\n");
+ } else {
+ Print (L"Transfered:\n");
+ for (Count = 0; Count < Length; Count++) {
+ Print(L"0x%x ", Buffer[Count]);
+ if (Count % 8 == 7)
+ Print(L"\n");
+ }
+ Print (L"\n");
+ }
+
+ Status = SHELL_SUCCESS;
+
+ if (!MemMode)
+ FreePool(Buffer);
+out_close:
+ gBS->CloseProtocol ( Handle,
+ &gMarvellEepromProtocolGuid,
+ gImageHandle,
+ NULL );
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+ShellEepromCmdLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+
+ ShellEepromHiiHandle = NULL;
+
+ ShellEepromHiiHandle = HiiAddPackages (
+ &gShellEepromHiiGuid, gImageHandle,
+ UefiShellEepromLibStrings, NULL
+ );
+ if (ShellEepromHiiHandle == NULL) {
+ Print (L"Filed to add Hii package\n");
+ return EFI_DEVICE_ERROR;
+ }
+ ShellCommandRegisterCommandName (
+ L"eeprom", ShellCommandRunEeprom, ShellCommandGetManFileNameEeprom, 0,
+ L"eeprom", TRUE , ShellEepromHiiHandle, STRING_TOKEN (STR_GET_HELP_EEPROM)
+ );
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+ShellEepromCmdLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+
+ if (ShellEepromHiiHandle != NULL) {
+ HiiRemovePackages (ShellEepromHiiHandle);
+ }
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Marvell/Applications/EepromCmd/EepromCmd.inf b/Platform/Marvell/Applications/EepromCmd/EepromCmd.inf
new file mode 100644
index 0000000000..984e60f155
--- /dev/null
+++ b/Platform/Marvell/Applications/EepromCmd/EepromCmd.inf
@@ -0,0 +1,71 @@
+#
+# Marvell BSD License Option
+#
+# If you received this File from Marvell, you may opt to use, redistribute
+# and/or modify this File under the following licensing terms.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Marvell nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+[Defines]
+ INF_VERSION = 0x00010006
+ BASE_NAME = UefiShellEepromLib
+ FILE_GUID = adf4b61c-2ca3-4e1a-9597-99282f5a4aa2
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 0.1
+ LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER
+ CONSTRUCTOR = ShellEepromCmdLibConstructor
+ DESTRUCTOR = ShellEepromCmdLibDestructor
+
+[Sources]
+ EepromCmd.c
+ EepromCmd.uni
+
+[Packages]
+ MdePkg/MdePkg.dec
+ ShellPkg/ShellPkg.dec
+ StdLib/StdLib.dec
+ MdeModulePkg/MdeModulePkg.dec
+ Platform/Marvell/Marvell.dec
+
+[LibraryClasses]
+ UefiLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ ShellCommandLib
+ ShellLib
+ UefiLib
+ UefiRuntimeServicesTableLib
+ PcdLib
+
+[Protocols]
+ gMarvellEepromProtocolGuid
+ gEfiI2cMasterProtocolGuid
+
+[Guids]
+ gShellEepromHiiGuid
diff --git a/Platform/Marvell/Applications/EepromCmd/EepromCmd.uni b/Platform/Marvell/Applications/EepromCmd/EepromCmd.uni
new file mode 100644
index 0000000000..e41c6d812e
--- /dev/null
+++ b/Platform/Marvell/Applications/EepromCmd/EepromCmd.uni
Binary files differ
diff --git a/Platform/Marvell/Applications/FirmwareUpdate/FUpdate.c b/Platform/Marvell/Applications/FirmwareUpdate/FUpdate.c
new file mode 100644
index 0000000000..edb698610d
--- /dev/null
+++ b/Platform/Marvell/Applications/FirmwareUpdate/FUpdate.c
@@ -0,0 +1,413 @@
+/*******************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+#include <ShellBase.h>
+#include <Uefi.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/FileHandleLib.h>
+#include <Library/HiiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+#include <Library/ShellCEntryLib.h>
+#include <Library/ShellCommandLib.h>
+#include <Library/ShellLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Protocol/Spi.h>
+#include <Protocol/SpiFlash.h>
+
+#define CMD_NAME_STRING L"fupdate"
+
+#define MAIN_HDR_MAGIC 0xB105B002
+
+STATIC MARVELL_SPI_FLASH_PROTOCOL *SpiFlashProtocol;
+STATIC MARVELL_SPI_MASTER_PROTOCOL *SpiMasterProtocol;
+
+STATIC CONST CHAR16 gShellFUpdateFileName[] = L"ShellCommands";
+STATIC EFI_HANDLE gShellFUpdateHiiHandle = NULL;
+
+STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
+ {L"help", TypeFlag},
+ {NULL , TypeMax}
+ };
+
+typedef struct { // Bytes
+ UINT32 Magic; // 0-3
+ UINT32 PrologSize; // 4-7
+ UINT32 PrologChecksum; // 8-11
+ UINT32 BootImageSize; // 12-15
+ UINT32 BootImageChecksum; // 16-19
+ UINT32 Reserved0; // 20-23
+ UINT32 LoadAddr; // 24-27
+ UINT32 ExecAddr; // 28-31
+ UINT8 UartConfig; // 32
+ UINT8 Baudrate; // 33
+ UINT8 ExtCount; // 34
+ UINT8 AuxFlags; // 35
+ UINT32 IoArg0; // 36-39
+ UINT32 IoArg1; // 40-43
+ UINT32 IoArg2; // 43-47
+ UINT32 IoArg3; // 48-51
+ UINT32 Reserved1; // 52-55
+ UINT32 Reserved2; // 56-59
+ UINT32 Reserved3; // 60-63
+} MV_FIRMWARE_IMAGE_HEADER;
+
+STATIC
+EFI_STATUS
+SpiFlashProbe (
+ IN SPI_DEVICE *Slave
+ )
+{
+ EFI_STATUS Status;
+ UINT32 IdBuffer, Id, RefId;
+
+ Id = PcdGet32 (PcdSpiFlashId);
+
+ IdBuffer = CMD_READ_ID & 0xff;
+
+ // Read SPI flash ID
+ SpiFlashProtocol->ReadId (Slave, sizeof (UINT32), (UINT8 *)&IdBuffer);
+
+ // Swap and extract 3 bytes of the ID
+ RefId = SwapBytes32 (IdBuffer) >> 8;
+
+ if (RefId == 0) {
+ Print (L"%s: No SPI flash detected");
+ return EFI_DEVICE_ERROR;
+ } else if (RefId != Id) {
+ Print (L"%s: Unsupported SPI flash detected with ID=%2x\n", CMD_NAME_STRING, RefId);
+ return EFI_DEVICE_ERROR;
+ }
+
+ Print (L"%s: Detected supported SPI flash with ID=%3x\n", CMD_NAME_STRING, RefId);
+
+ Status = SpiFlashProtocol->Init (SpiFlashProtocol, Slave);
+ if (EFI_ERROR(Status)) {
+ Print (L"%s: Cannot initialize flash device\n", CMD_NAME_STRING);
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+CheckImageHeader (
+ IN OUT UINTN *ImageHeader
+ )
+{
+ MV_FIRMWARE_IMAGE_HEADER *Header;
+ UINT32 HeaderLength, Checksum, ChecksumBackup;
+
+ Header = (MV_FIRMWARE_IMAGE_HEADER *)ImageHeader;
+ HeaderLength = Header->PrologSize;
+ ChecksumBackup = Header->PrologChecksum;
+
+ // Compare magic number
+ if (Header->Magic != MAIN_HDR_MAGIC) {
+ Print (L"%s: Bad Image magic 0x%08x != 0x%08x\n", CMD_NAME_STRING, Header->Magic, MAIN_HDR_MAGIC);
+ return EFI_DEVICE_ERROR;
+ }
+
+ // The checksum field is discarded from calculation
+ Header->PrologChecksum = 0;
+
+ Checksum = CalculateSum32 ((UINT32 *)Header, HeaderLength);
+ if (Checksum != ChecksumBackup) {
+ Print (L"%s: Bad Image checksum. 0x%x != 0x%x\n", CMD_NAME_STRING, Checksum, ChecksumBackup);
+ return EFI_DEVICE_ERROR;
+ }
+
+ // Restore checksum backup
+ Header->PrologChecksum = ChecksumBackup;
+
+ return 0;
+}
+
+STATIC
+EFI_STATUS
+PrepareFirmwareImage (
+ IN LIST_ENTRY *CheckPackage,
+ IN OUT SHELL_FILE_HANDLE *FileHandle,
+ IN OUT UINTN **FileBuffer,
+ IN OUT UINTN *FileSize
+ )
+{
+ CONST CHAR16 *FileStr;
+ EFI_STATUS Status;
+ UINT64 OpenMode;
+ UINTN *Buffer;
+
+ // Parse string from commandline
+ FileStr = ShellCommandLineGetRawValue (CheckPackage, 1);
+ if (FileStr == NULL) {
+ Print (L"%s: No image specified\n", CMD_NAME_STRING);
+ return EFI_INVALID_PARAMETER;
+ } else {
+ Status = ShellIsFile (FileStr);
+ if (EFI_ERROR(Status)) {
+ Print (L"%s: File not found\n", CMD_NAME_STRING);
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ // Obtain file size
+ OpenMode = EFI_FILE_MODE_READ;
+
+ Status = ShellOpenFileByName (FileStr, FileHandle, OpenMode, 0);
+ if (EFI_ERROR (Status)) {
+ Print (L"%s: Cannot open Image file\n", CMD_NAME_STRING);
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = FileHandleGetSize (*FileHandle, FileSize);
+ if (EFI_ERROR (Status)) {
+ Print (L"%s: Cannot get Image file size\n", CMD_NAME_STRING);
+ }
+
+ // Read Image header into buffer
+ Buffer = AllocateZeroPool (*FileSize);
+
+ Status = FileHandleRead (*FileHandle, FileSize, Buffer);
+ if (EFI_ERROR (Status)) {
+ Print (L"%s: Cannot read Image file header\n", CMD_NAME_STRING);
+ ShellCloseFile (FileHandle);
+ FreePool (Buffer);
+ return EFI_DEVICE_ERROR;
+ }
+
+ *FileBuffer = Buffer;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return the file name of the help text file if not using HII.
+
+ @return The string pointer to the file name.
+**/
+STATIC
+CONST CHAR16*
+EFIAPI
+ShellCommandGetManFileNameFUpdate (
+ VOID
+ )
+{
+ return gShellFUpdateFileName;
+}
+
+STATIC
+VOID
+FUpdateUsage (
+ VOID
+ )
+{
+ Print (L"\nFirmware update command\n"
+ "fupdate <LocalFilePath>\n\n"
+ "LocalFilePath - path to local firmware image file\n"
+ "Example:\n"
+ "Update firmware from file fs2:flash-image.bin\n"
+ " fupdate fs2:flash-image.bin\n"
+ );
+}
+
+STATIC
+SHELL_STATUS
+EFIAPI
+ShellCommandRunFUpdate (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ IN SHELL_FILE_HANDLE FileHandle;
+ SPI_DEVICE *Slave;
+ UINTN FileSize;
+ UINTN *FileBuffer = NULL;
+ CHAR16 *ProblemParam;
+ LIST_ENTRY *CheckPackage;
+ EFI_STATUS Status;
+
+ // Locate SPI protocols
+ Status = gBS->LocateProtocol (
+ &gMarvellSpiFlashProtocolGuid,
+ NULL,
+ (VOID **)&SpiFlashProtocol
+ );
+
+ if (EFI_ERROR(Status)) {
+ Print (L"%s: Cannot locate SpiFlash protocol\n", CMD_NAME_STRING);
+ return SHELL_ABORTED;
+ }
+
+ Status = gBS->LocateProtocol (
+ &gMarvellSpiMasterProtocolGuid,
+ NULL,
+ (VOID **)&SpiMasterProtocol
+ );
+
+ if (EFI_ERROR(Status)) {
+ Print (L"%s: Cannot locate SpiMaster protocol\n", CMD_NAME_STRING);
+ return SHELL_ABORTED;
+ }
+
+ // Parse command line
+ Status = ShellInitialize ();
+ if (EFI_ERROR (Status)) {
+ Print (L"%s: Error while initializing Shell\n", CMD_NAME_STRING);
+ ASSERT_EFI_ERROR (Status);
+ return SHELL_ABORTED;
+ }
+
+ Status = ShellCommandLineParse (ParamList, &CheckPackage, &ProblemParam, TRUE);
+ if (EFI_ERROR (Status)) {
+ Print (L"%s: Invalid parameter\n", CMD_NAME_STRING);
+ return SHELL_ABORTED;
+ }
+
+ if (ShellCommandLineGetFlag (CheckPackage, L"help")) {
+ FUpdateUsage();
+ return EFI_SUCCESS;
+ }
+
+ // Prepare local file to be burned into flash
+ Status = PrepareFirmwareImage (CheckPackage, &FileHandle, &FileBuffer, &FileSize);
+ if (EFI_ERROR(Status)) {
+ return SHELL_ABORTED;
+ }
+
+ // Check image checksum and magic
+ Status = CheckImageHeader (FileBuffer);
+ if (EFI_ERROR(Status)) {
+ goto HeaderError;
+ }
+
+ // Setup and probe SPI flash
+ Slave = SpiMasterProtocol->SetupDevice (SpiMasterProtocol, 0, 0);
+ if (Slave == NULL) {
+ Print(L"%s: Cannot allocate SPI device!\n", CMD_NAME_STRING);
+ goto HeaderError;
+ }
+
+ Status = SpiFlashProbe (Slave);
+ if (EFI_ERROR(Status)) {
+ Print (L"%s: Error while performing SPI flash probe\n", CMD_NAME_STRING);
+ goto FlashProbeError;
+ }
+
+ // Update firmware image in flash at offset 0x0
+ Status = SpiFlashProtocol->Update (Slave, 0, FileSize, (UINT8 *)FileBuffer);
+
+ // Release resources
+ SpiMasterProtocol->FreeDevice(Slave);
+ FreePool (FileBuffer);
+ ShellCloseFile (&FileHandle);
+
+ if (EFI_ERROR(Status)) {
+ Print (L"%s: Error while performing flash update\n", CMD_NAME_STRING);
+ return SHELL_ABORTED;
+ }
+
+ Print (L"%s: Update %d bytes at offset 0x0 succeeded!\n", CMD_NAME_STRING, FileSize);
+
+ return EFI_SUCCESS;
+
+FlashProbeError:
+ SpiMasterProtocol->FreeDevice(Slave);
+HeaderError:
+ FreePool (FileBuffer);
+ ShellCloseFile (&FileHandle);
+
+ return SHELL_ABORTED;
+}
+
+EFI_STATUS
+EFIAPI
+ShellFUpdateCommandConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ gShellFUpdateHiiHandle = NULL;
+
+ gShellFUpdateHiiHandle = HiiAddPackages (
+ &gShellFUpdateHiiGuid,
+ gImageHandle,
+ UefiShellFUpdateCommandLibStrings,
+ NULL
+ );
+
+ if (gShellFUpdateHiiHandle == NULL) {
+ Print (L"%s: Cannot add Hii package\n", CMD_NAME_STRING);
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = ShellCommandRegisterCommandName (
+ CMD_NAME_STRING,
+ ShellCommandRunFUpdate,
+ ShellCommandGetManFileNameFUpdate,
+ 0,
+ CMD_NAME_STRING,
+ TRUE,
+ gShellFUpdateHiiHandle,
+ STRING_TOKEN (STR_GET_HELP_FUPDATE)
+ );
+
+ if (EFI_ERROR(Status)) {
+ Print (L"%s: Error while registering command\n", CMD_NAME_STRING);
+ return SHELL_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+ShellFUpdateCommandDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+
+ if (gShellFUpdateHiiHandle != NULL) {
+ HiiRemovePackages (gShellFUpdateHiiHandle);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Marvell/Applications/FirmwareUpdate/FUpdate.inf b/Platform/Marvell/Applications/FirmwareUpdate/FUpdate.inf
new file mode 100644
index 0000000000..92c3333137
--- /dev/null
+++ b/Platform/Marvell/Applications/FirmwareUpdate/FUpdate.inf
@@ -0,0 +1,75 @@
+#
+# Marvell BSD License Option
+#
+# If you received this File from Marvell, you may opt to use, redistribute
+# and/or modify this File under the following licensing terms.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Marvell nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+[Defines]
+ INF_VERSION = 0x00010019
+ BASE_NAME = UefiShellFUpdateCommandLib
+ FILE_GUID = 470292b2-926b-4ed8-8080-be7a260db627
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 0.1
+ LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER
+ CONSTRUCTOR = ShellFUpdateCommandConstructor
+ DESTRUCTOR = ShellFUpdateCommandDestructor
+
+[Sources]
+ FUpdate.c
+ FUpdate.uni
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Platform/Marvell/Marvell.dec
+ ShellPkg/ShellPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ FileHandleLib
+ HiiLib
+ MemoryAllocationLib
+ PcdLib
+ ShellCommandLib
+ ShellLib
+ UefiBootServicesTableLib
+ UefiLib
+ UefiLib
+ UefiRuntimeServicesTableLib
+
+[Pcd]
+ gMarvellTokenSpaceGuid.PcdSpiFlashId
+
+[Protocols]
+ gMarvellSpiFlashProtocolGuid
+ gMarvellSpiMasterProtocolGuid
+
+[Guids]
+ gShellFUpdateHiiGuid
diff --git a/Platform/Marvell/Applications/FirmwareUpdate/FUpdate.uni b/Platform/Marvell/Applications/FirmwareUpdate/FUpdate.uni
new file mode 100644
index 0000000000..9d52e590c6
--- /dev/null
+++ b/Platform/Marvell/Applications/FirmwareUpdate/FUpdate.uni
Binary files differ
diff --git a/Platform/Marvell/Applications/SpiTool/SpiFlashCmd.c b/Platform/Marvell/Applications/SpiTool/SpiFlashCmd.c
new file mode 100644
index 0000000000..184e3d7f54
--- /dev/null
+++ b/Platform/Marvell/Applications/SpiTool/SpiFlashCmd.c
@@ -0,0 +1,526 @@
+/*******************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+#include <Uefi.h>
+#include <ShellBase.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/ShellCommandLib.h>
+#include <Library/ShellLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PrintLib.h>
+#include <Library/ShellCEntryLib.h>
+#include <Library/HiiLib.h>
+#include <Library/FileHandleLib.h>
+
+#include <Protocol/Spi.h>
+#include <Protocol/SpiFlash.h>
+
+MARVELL_SPI_FLASH_PROTOCOL *SpiFlashProtocol;
+MARVELL_SPI_MASTER_PROTOCOL *SpiMasterProtocol;
+
+CONST CHAR16 gShellSpiFlashFileName[] = L"ShellCommand";
+EFI_HANDLE gShellSfHiiHandle = NULL;
+
+BOOLEAN InitFlag = 1;
+
+STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
+ {L"read", TypeFlag},
+ {L"readfile", TypeFlag},
+ {L"write", TypeFlag},
+ {L"writefile", TypeFlag},
+ {L"erase", TypeFlag},
+ {L"update", TypeFlag},
+ {L"updatefile", TypeFlag},
+ {L"probe", TypeFlag},
+ {L"help", TypeFlag},
+ {NULL , TypeMax}
+ };
+
+typedef enum {
+ PROBE = 1,
+ READ = 2,
+ READ_FILE = 4,
+ WRITE = 8,
+ WRITE_FILE = 16,
+ ERASE = 32,
+ UPDATE = 64,
+ UPDATE_FILE = 128,
+} Flags;
+
+/**
+ Return the file name of the help text file if not using HII.
+
+ @return The string pointer to the file name.
+**/
+CONST CHAR16*
+EFIAPI
+ShellCommandGetManFileNameSpiFlash (
+ VOID
+ )
+{
+
+ return gShellSpiFlashFileName;
+}
+
+VOID
+SfUsage (
+ VOID
+ )
+{
+ Print (L"\nBasic SPI command\n"
+ "sf [probe | read | readfile | write | writefile | erase |"
+ "update | updatefile]"
+ "[<Address> | <FilePath>] <Offset> <Length>\n\n"
+ "Length - Number of bytes to send\n"
+ "Address - Address in RAM to store/load data\n"
+ "FilePath - Path to file to read/write data from/to\n"
+ "Offset - Offset from beggining of SPI flash to store/load data\n"
+ "Examples:\n"
+ "Check if there is response from SPI flash\n"
+ " sf probe\n"
+ "Read 32 bytes from 0xe00000 of SPI flash into RAM at address 0x100000\n"
+ " sf read 0x100000 0xe00000 32\n"
+ "Read 0x20 bytes from 0x200000 of SPI flash into RAM at address 0x300000\n"
+ " sf read 0x300000 0x200000 0x20\n"
+ "Erase 0x10000 bytes from offset 0x100000 of SPI flash\n"
+ " sf erase 0x100000 0x100000\n"
+ "Write 16 bytes from 0x200000 at RAM into SPI flash at address 0x4000000\n"
+ " sf write 0x200000 0x4000000 16\n"
+ "Update 100 bytes from 0x100000 at RAM in SPI flash at address 0xe00000\n"
+ " sf update 0x100000 0xe00000 100\n"
+ "Read 0x3000 bytes from 0x0 of SPI flash into file fs2:file.bin\n"
+ " sf readfile fs2:file.bin 0x0 0x3000 \n"
+ "Update data in SPI flash at 0x3000000 from file Linux.efi\n"
+ " sf updatefile Linux.efi 0x3000000\n"
+ );
+}
+
+STATIC
+EFI_STATUS
+OpenAndPrepareFile (
+ IN CHAR16 *FilePath,
+ SHELL_FILE_HANDLE *FileHandle
+ )
+{
+ EFI_STATUS Status;
+ UINT64 OpenMode;
+
+ OpenMode = EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE;
+
+ Status = ShellOpenFileByName (FilePath, FileHandle, OpenMode, 0);
+ if (EFI_ERROR (Status)) {
+ Print (L"sf: Cannot open file\n");
+ return Status;
+ }
+
+ Status = FileHandleSetPosition(*FileHandle, 0);
+
+ if (EFI_ERROR(Status)) {
+ Print (L"sf: Cannot set file position to first byte\n");
+ ShellCloseFile (FileHandle);
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+FlashProbe (
+ IN SPI_DEVICE *Slave
+ )
+{
+ EFI_STATUS Status;
+ UINT8 IdBuffer[4];
+ UINT32 Id, RefId;
+
+ Id = PcdGet32 (PcdSpiFlashId);
+
+ IdBuffer[0] = CMD_READ_ID;
+
+ SpiFlashProtocol->ReadId (
+ Slave,
+ 4,
+ IdBuffer
+ );
+
+ RefId = (IdBuffer[0] << 16) + (IdBuffer[1] << 8) + IdBuffer[2];
+
+ if (RefId == Id) {
+ Print (L"sf: Detected supported SPI flash with ID=%3x\n", RefId);
+ Status = SpiFlashProtocol->Init (SpiFlashProtocol, Slave);
+ if (EFI_ERROR(Status)) {
+ Print (L"sf: Cannot initialize flash device\n");
+ return SHELL_ABORTED;
+ }
+ InitFlag = 0;
+ return EFI_SUCCESS;
+ } else if (RefId != 0) {
+ Print (L"sf: Unsupported SPI flash detected with ID=%2x\n", RefId);
+ return SHELL_ABORTED;
+ }
+
+ Print (L"sf: No SPI flash detected");
+ return SHELL_ABORTED;
+}
+
+SHELL_STATUS
+EFIAPI
+ShellCommandRunSpiFlash (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+EFI_STATUS Status;
+ SPI_DEVICE *Slave;
+ LIST_ENTRY *CheckPackage;
+ EFI_PHYSICAL_ADDRESS Address = 0, Offset = 0;
+ SHELL_FILE_HANDLE FileHandle = NULL;
+ UINTN ByteCount, FileSize, I;
+ UINT8 *Buffer = NULL, *FileBuffer = NULL;
+ CHAR16 *ProblemParam, *FilePath;
+ CONST CHAR16 *AddressStr = NULL, *OffsetStr = NULL;
+ CONST CHAR16 *LengthStr = NULL, *FileStr = NULL;
+ BOOLEAN AddrFlag = FALSE, LengthFlag = TRUE, FileFlag = FALSE;
+ UINT8 Flag = 0, CheckFlag = 0;
+
+ Status = gBS->LocateProtocol (
+ &gMarvellSpiFlashProtocolGuid,
+ NULL,
+ (VOID **)&SpiFlashProtocol
+ );
+ if (EFI_ERROR(Status)) {
+ Print (L"sf: Cannot locate SpiFlash protocol\n");
+ return SHELL_ABORTED;
+ }
+
+ Status = gBS->LocateProtocol (
+ &gMarvellSpiMasterProtocolGuid,
+ NULL,
+ (VOID **)&SpiMasterProtocol
+ );
+ if (EFI_ERROR(Status)) {
+ Print (L"sf: Cannot locate SpiMaster protocol\n");
+ return SHELL_ABORTED;
+ }
+
+ // Parse Shell command line
+ Status = ShellInitialize ();
+ if (EFI_ERROR (Status)) {
+ Print (L"sf: Cannot initialize Shell\n");
+ ASSERT_EFI_ERROR (Status);
+ return SHELL_ABORTED;
+ }
+
+ Status = ShellCommandLineParse (ParamList, &CheckPackage, &ProblemParam, TRUE);
+ if (EFI_ERROR (Status)) {
+ Print (L"sf: Error while parsing command line\n");
+ return SHELL_ABORTED;
+ }
+
+ if (ShellCommandLineGetFlag (CheckPackage, L"help")) {
+ SfUsage();
+ return EFI_SUCCESS;
+ }
+
+ // Check flags provided by user
+ Flag |= (ShellCommandLineGetFlag (CheckPackage, L"probe") << 0);
+ Flag |= (ShellCommandLineGetFlag (CheckPackage, L"read") << 1);
+ Flag |= (ShellCommandLineGetFlag (CheckPackage, L"readfile") << 2);
+ Flag |= (ShellCommandLineGetFlag (CheckPackage, L"write") << 3);
+ Flag |= (ShellCommandLineGetFlag (CheckPackage, L"writefile") << 4);
+ Flag |= (ShellCommandLineGetFlag (CheckPackage, L"erase") << 5);
+ Flag |= (ShellCommandLineGetFlag (CheckPackage, L"update") << 6);
+ Flag |= (ShellCommandLineGetFlag (CheckPackage, L"updatefile") << 7);
+
+ if (InitFlag && !(Flag & PROBE)) {
+ Print (L"Please run sf probe\n");
+ return EFI_SUCCESS;
+ }
+
+ CheckFlag = Flag;
+ for (I = 0; CheckFlag; CheckFlag >>= 1) {
+ I += CheckFlag & 1;
+ if (I > 1) {
+ Print (L"sf: Too many flags\n");
+ SfUsage();
+ return SHELL_ABORTED;
+ }
+ }
+
+ // Setup new spi device
+ Slave = SpiMasterProtocol->SetupDevice (SpiMasterProtocol, 0, 0);
+ if (Slave == NULL) {
+ Print(L"sf: Cannot allocate SPI device!\n");
+ return SHELL_ABORTED;
+ }
+
+ switch (Flag) {
+ case PROBE:
+ // Probe spi bus
+ Status = FlashProbe (Slave);
+ if (EFI_ERROR(Status)) {
+ // No supported spi flash detected
+ return SHELL_ABORTED;
+ } else {
+ return Status;
+ }
+ break;
+ // Fall through
+ case READ:
+ case WRITE:
+ case UPDATE:
+ AddressStr = ShellCommandLineGetRawValue (CheckPackage, 1);
+ OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 2);
+ LengthStr = ShellCommandLineGetRawValue (CheckPackage, 3);
+ AddrFlag = TRUE;
+ break;
+ case ERASE:
+ OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 1);
+ LengthStr = ShellCommandLineGetRawValue (CheckPackage, 2);
+ break;
+ case READ_FILE:
+ FileStr = ShellCommandLineGetRawValue (CheckPackage, 1);
+ OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 2);
+ LengthStr = ShellCommandLineGetRawValue (CheckPackage, 3);
+ FileFlag = TRUE;
+ break;
+ case WRITE_FILE:
+ case UPDATE_FILE:
+ FileStr = ShellCommandLineGetRawValue (CheckPackage, 1);
+ OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 2);
+ LengthFlag = FALSE;
+ FileFlag = TRUE;
+ break;
+ }
+
+ // Read address parameter
+ if ((AddressStr == NULL) & AddrFlag) {
+ Print (L"sf: No address parameter!\n");
+ return SHELL_ABORTED;
+ } else if (AddrFlag) {
+ Address = ShellHexStrToUintn (AddressStr);
+ if (Address == (UINTN)(-1)) {
+ Print (L"sf: Wrong address parameter\n");
+ return SHELL_ABORTED;
+ }
+ }
+
+ // Read offset parameter
+ if (OffsetStr == NULL) {
+ Print (L"sf: No offset Parameter!\n");
+ return SHELL_ABORTED;
+ } else {
+ Offset = ShellHexStrToUintn (OffsetStr);
+ if (Offset < 0) {
+ Print (L"sf: Wrong offset parameter: %s", OffsetStr);
+ return SHELL_ABORTED;
+ }
+ }
+
+ // Read length parameter
+ if ((LengthStr == NULL) & LengthFlag) {
+ Print (L"sf: No lenght parameter!\n");
+ return SHELL_ABORTED;
+ } else if (LengthFlag) {
+ ByteCount = ShellStrToUintn (LengthStr);
+ if (ByteCount < 0) {
+ Print (L"sf: Wrong length parameter %s!\n", LengthStr);
+ return SHELL_ABORTED;
+ }
+ }
+
+ if (FileFlag) {
+ // Read FilePath parameter
+ if (FileStr == NULL) {
+ Print (L"sf: No FilePath parameter!\n");
+ return SHELL_ABORTED;
+ } else {
+ FilePath = (CHAR16 *) FileStr;
+ Status = ShellIsFile (FilePath);
+ // When read file into flash, file doesn't have to exist
+ if (EFI_ERROR(Status && !(Flag & READ_FILE))) {
+ Print (L"sf: Wrong FilePath parameter!\n");
+ return SHELL_ABORTED;
+ }
+ }
+
+ Status = OpenAndPrepareFile (FilePath, &FileHandle);
+ if (EFI_ERROR(Status)) {
+ Print (L"sf: Error while preparing file\n");
+ return SHELL_ABORTED;
+ }
+
+ // Get file size in order to check correctness at the end of transfer
+ if (Flag & (WRITE_FILE | UPDATE_FILE)) {
+ Status = FileHandleGetSize (FileHandle, &FileSize);
+ if (EFI_ERROR (Status)) {
+ Print (L"sf: Cannot get file size\n");
+ }
+ ByteCount = (UINTN) FileSize;
+ }
+
+ FileBuffer = AllocateZeroPool ((UINTN) ByteCount);
+ if (FileBuffer == NULL) {
+ Print (L"sf: Cannot allocate memory\n");
+ goto Error_Close_File;
+ }
+
+ // Read file content and store it in FileBuffer
+ if (Flag & (WRITE_FILE | UPDATE_FILE)) {
+ Status = FileHandleRead (FileHandle, &ByteCount, FileBuffer);
+ if (EFI_ERROR (Status)) {
+ Print (L"sf: Read from file error\n");
+ goto Error_Free_Buffer;
+ } else if (ByteCount != (UINTN) FileSize) {
+ Print (L"sf: Not whole file read. Abort\n");
+ goto Error_Free_Buffer;
+ }
+ }
+ }
+
+ Buffer = (UINT8 *) Address;
+ if (FileFlag) {
+ Buffer = FileBuffer;
+ }
+
+ switch (Flag) {
+ case READ:
+ case READ_FILE:
+ Status = SpiFlashProtocol->Read (Slave, Offset, ByteCount, Buffer);
+ break;
+ case ERASE:
+ Status = SpiFlashProtocol->Erase (Slave, Offset, ByteCount);
+ break;
+ case WRITE:
+ case WRITE_FILE:
+ Status = SpiFlashProtocol->Write (Slave, Offset, ByteCount, Buffer);
+ break;
+ case UPDATE:
+ case UPDATE_FILE:
+ Status = SpiFlashProtocol->Update (Slave, Offset, ByteCount, Buffer);
+ break;
+ }
+
+ SpiMasterProtocol->FreeDevice(Slave);
+
+ if (EFI_ERROR (Status)) {
+ Print (L"sf: Error while performing spi transfer\n");
+ return SHELL_ABORTED;
+ }
+
+ switch (Flag) {
+ case ERASE:
+ Print (L"sf: %d bytes succesfully erased at offset 0x%x\n", ByteCount,
+ Offset);
+ break;
+ case WRITE:
+ case WRITE_FILE:
+ Print (L"sf: Write %d bytes at offset 0x%x\n", ByteCount, Offset);
+ break;
+ case UPDATE:
+ case UPDATE_FILE:
+ Print (L"sf: Update %d bytes at offset 0x%x\n", ByteCount, Offset);
+ break;
+ case READ:
+ Print (L"sf: Read %d bytes from offset 0x%x\n", ByteCount, Offset);
+ break;
+ case READ_FILE:
+ Status = FileHandleWrite (FileHandle, &ByteCount, FileBuffer);
+ if (EFI_ERROR(Status)) {
+ Print (L"sf: Error while writing into file\n");
+ goto Error_Free_Buffer;
+ }
+ break;
+ }
+
+ if (FileFlag) {
+ FreePool (FileBuffer);
+
+ if (FileHandle != NULL) {
+ ShellCloseFile (&FileHandle);
+ }
+ }
+
+ return EFI_SUCCESS;
+
+Error_Free_Buffer:
+ FreePool (FileBuffer);
+Error_Close_File:
+ ShellCloseFile (&FileHandle);
+ return SHELL_ABORTED;
+}
+
+EFI_STATUS
+EFIAPI
+ShellSpiFlashLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ gShellSfHiiHandle = NULL;
+
+ gShellSfHiiHandle = HiiAddPackages (
+ &gShellSfHiiGuid, gImageHandle,
+ UefiShellSpiFlashLibStrings, NULL
+ );
+ if (gShellSfHiiHandle == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ ShellCommandRegisterCommandName (
+ L"sf", ShellCommandRunSpiFlash, ShellCommandGetManFileNameSpiFlash, 0,
+ L"sf", TRUE , gShellSfHiiHandle, STRING_TOKEN (STR_GET_HELP_SF)
+ );
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+ShellSpiFlashLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+
+ if (gShellSfHiiHandle != NULL) {
+ HiiRemovePackages (gShellSfHiiHandle);
+ }
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Marvell/Applications/SpiTool/SpiFlashCmd.inf b/Platform/Marvell/Applications/SpiTool/SpiFlashCmd.inf
new file mode 100644
index 0000000000..41b7b7cd85
--- /dev/null
+++ b/Platform/Marvell/Applications/SpiTool/SpiFlashCmd.inf
@@ -0,0 +1,75 @@
+#
+# Marvell BSD License Option
+#
+# If you received this File from Marvell, you may opt to use, redistribute
+# and/or modify this File under the following licensing terms.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Marvell nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+[Defines]
+ INF_VERSION = 0x00010006
+ BASE_NAME = UefiShellSpiFlashLib
+ FILE_GUID = 2f2dd8c9-221f-4acf-afe5-5897264c5774
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 0.1
+ LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER
+ CONSTRUCTOR = ShellSpiFlashLibConstructor
+ DESTRUCTOR = ShellSpiFlashLibDestructor
+
+[Sources]
+ SpiFlashCmd.c
+ SpiFlashCmd.uni
+
+[Packages]
+ MdePkg/MdePkg.dec
+ ShellPkg/ShellPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ Platform/Marvell/Marvell.dec
+
+[LibraryClasses]
+ UefiLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ ShellCommandLib
+ ShellLib
+ UefiLib
+ UefiRuntimeServicesTableLib
+ PcdLib
+ HiiLib
+ FileHandleLib
+
+[Pcd]
+ gMarvellTokenSpaceGuid.PcdSpiFlashId
+
+[Protocols]
+ gMarvellSpiFlashProtocolGuid
+ gMarvellSpiMasterProtocolGuid
+
+[Guids]
+ gShellSfHiiGuid
diff --git a/Platform/Marvell/Applications/SpiTool/SpiFlashCmd.uni b/Platform/Marvell/Applications/SpiTool/SpiFlashCmd.uni
new file mode 100644
index 0000000000..3f25663ed7
--- /dev/null
+++ b/Platform/Marvell/Applications/SpiTool/SpiFlashCmd.uni
Binary files differ
diff --git a/Platform/Marvell/Armada/Armada.dsc.inc b/Platform/Marvell/Armada/Armada.dsc.inc
new file mode 100644
index 0000000000..4e8f289fcb
--- /dev/null
+++ b/Platform/Marvell/Armada/Armada.dsc.inc
@@ -0,0 +1,482 @@
+#Copyright (C) 2016 Marvell International Ltd.
+#
+#Marvell BSD License Option
+#
+#If you received this File from Marvell, you may opt to use, redistribute and/or
+#modify this File under the following licensing terms.
+#Redistribution and use in source and binary forms, with or without modification,
+#are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Marvell nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+#ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+#WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+#DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+#ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+#(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+#ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+#SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+[LibraryClasses.common]
+ ArmPlatformLib|Platform/Marvell/Armada/Library/Armada70x0Lib/Armada70x0Lib.inf
+ ComPhyLib|Platform/Marvell/Library/ComPhyLib/ComPhyLib.inf
+ MppLib|Platform/Marvell/Library/MppLib/MppLib.inf
+ ParsePcdLib|Platform/Marvell/Library/ParsePcdLib/ParsePcdLib.inf
+ UtmiPhyLib|Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.inf
+
+ DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf
+ UncachedMemoryAllocationLib|ArmPkg/Library/UncachedMemoryAllocationLib/UncachedMemoryAllocationLib.inf
+ DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
+
+# Basic utility libraries
+ BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
+ SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf
+ PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf
+ PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
+ PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
+ PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf
+ IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
+ UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.inf
+ CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf
+ PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf
+ PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf
+
+# Basic UEFI services libraries
+ UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
+ HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
+ UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
+ DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
+ UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
+ DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf
+ DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf
+ ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf
+ UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
+ UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf
+ HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
+ UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf
+ UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
+ UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf
+
+ # Assume everything is fixed at build. do not use runtime PCD feature
+ PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+
+ BaseMemoryLib|MdePkg/Library/BaseMemoryLibOptDxe/BaseMemoryLibOptDxe.inf
+
+ # ARM Architectural Libraries
+ CacheMaintenanceLib|ArmPkg/Library/ArmCacheMaintenanceLib/ArmCacheMaintenanceLib.inf
+ DefaultExceptionHandlerLib|ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLib.inf
+ CpuExceptionHandlerLib|ArmPkg/Library/ArmExceptionLib/ArmExceptionLib.inf
+ ArmDisassemblerLib|ArmPkg/Library/ArmDisassemblerLib/ArmDisassemblerLib.inf
+ DmaLib|ArmPkg/Library/ArmDmaLib/ArmDmaLib.inf
+ ArmGicLib|ArmPkg/Drivers/ArmGic/ArmGicLib.inf
+ ArmGicArchLib|ArmPkg/Library/ArmGicArchLib/ArmGicArchLib.inf
+ ArmPlatformStackLib|ArmPlatformPkg/Library/ArmPlatformStackLib/ArmPlatformStackLib.inf
+ ArmSmcLib|ArmPkg/Library/ArmSmcLib/ArmSmcLib.inf
+ TimerLib|ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.inf
+ UefiScsiLib|MdePkg/Library/UefiScsiLib/UefiScsiLib.inf
+
+ # Serial port libraries
+ SerialPortLib|MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf
+ PlatformHookLib|MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf
+
+ # Reset and Time libraries
+ TimeBaseLib|EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.inf
+ RealTimeClockLib|Platform/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.inf
+ ResetSystemLib|ArmPkg/Library/ArmSmcPsciResetSystemLib/ArmSmcPsciResetSystemLib.inf
+
+ # Network support
+ NetLib|MdeModulePkg/Library/DxeNetLib/DxeNetLib.inf
+ IpIoLib|MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.inf
+ DpcLib|MdeModulePkg/Library/DxeDpcLib/DxeDpcLib.inf
+ UdpIoLib|MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf
+
+ # These libraries are used by the dynamic EFI Shell commands
+ ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf
+ FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf
+ SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
+
+ # EBL Related Libraries
+ EblCmdLib|ArmPlatformPkg/Library/EblCmdLib/EblCmdLib.inf
+ EfiFileLib|EmbeddedPkg/Library/EfiFileLib/EfiFileLib.inf
+ EblAddExternalCommandLib|EmbeddedPkg/Library/EblAddExternalCommandLib/EblAddExternalCommandLib.inf
+ EblNetworkLib|EmbeddedPkg/Library/EblNetworkLib/EblNetworkLib.inf
+
+ #
+ # Uncomment (and comment out the next line) For RealView Debugger. The Standard IO window
+ # in the debugger will show load and unload commands for symbols. You can cut and paste this
+ # into the command window to load symbols. We should be able to use a script to do this, but
+ # the version of RVD I have does not support scripts accessing system memory.
+ #
+ #PeCoffExtraActionLib|ArmPkg/Library/RvdPeCoffExtraActionLib/RvdPeCoffExtraActionLib.inf
+ PeCoffExtraActionLib|ArmPkg/Library/DebugPeCoffExtraActionLib/DebugPeCoffExtraActionLib.inf
+ #PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf
+
+ DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
+ DebugAgentTimerLib|EmbeddedPkg/Library/DebugAgentTimerLibNull/DebugAgentTimerLibNull.inf
+ # SemihostLib|ArmPkg/Library/SemihostLib/SemihostLib.inf
+
+ # BDS Libraries
+ CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf
+ GenericBdsLib|IntelFrameworkModulePkg/Library/GenericBdsLib/GenericBdsLib.inf
+ PlatformBdsLib|ArmPlatformPkg/Library/PlatformIntelBdsLib/PlatformIntelBdsLib.inf
+ CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
+ FdtLib|EmbeddedPkg/Library/FdtLib/FdtLib.inf
+
+[LibraryClasses.AARCH64]
+ ArmLib|ArmPkg/Library/ArmLib/ArmBaseLib.inf
+ ArmMmuLib|ArmPkg/Library/ArmMmuLib/ArmMmuBaseLib.inf
+ ArmGenericTimerCounterLib|ArmPkg/Library/ArmGenericTimerPhyCounterLib/ArmGenericTimerPhyCounterLib.inf
+ BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+
+[LibraryClasses.common.SEC]
+ DebugAgentLib|ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentSymbolsBaseLib.inf
+ DefaultExceptionHandlerLib|ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLibBase.inf
+
+ PrePiLib|EmbeddedPkg/Library/PrePiLib/PrePiLib.inf
+ ExtractGuidedSectionLib|EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf
+ LzmaDecompressLib|MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf
+ MemoryAllocationLib|EmbeddedPkg/Library/PrePiMemoryAllocationLib/PrePiMemoryAllocationLib.inf
+ HobLib|EmbeddedPkg/Library/PrePiHobLib/PrePiHobLib.inf
+ PrePiHobListPointerLib|ArmPlatformPkg/Library/PrePiHobListPointerLib/PrePiHobListPointerLib.inf
+ PlatformPeiLib|ArmPlatformPkg/PlatformPei/PlatformPeiLib.inf
+ ArmGicArchLib|ArmPkg/Library/ArmGicArchSecLib/ArmGicArchSecLib.inf
+
+[LibraryClasses.common.SEC, LibraryClasses.common.PEIM]
+ MemoryInitPeiLib|ArmPlatformPkg/MemoryInitPei/MemoryInitPeiLib.inf
+ BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+
+[LibraryClasses.common.DXE_CORE]
+ HobLib|MdePkg/Library/DxeCoreHobLib/DxeCoreHobLib.inf
+ MemoryAllocationLib|MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.inf
+ DxeCoreEntryPoint|MdePkg/Library/DxeCoreEntryPoint/DxeCoreEntryPoint.inf
+ ExtractGuidedSectionLib|MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGuidedSectionLib.inf
+ UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.inf
+ DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf
+ PerformanceLib|MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf
+
+[LibraryClasses.common.DXE_DRIVER]
+ DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf
+ SecurityManagementLib|MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf
+ PerformanceLib|MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+ NonDiscoverableDeviceRegistrationLib|MdeModulePkg/Library/NonDiscoverableDeviceRegistrationLib/NonDiscoverableDeviceRegistrationLib.inf
+
+[LibraryClasses.common.UEFI_APPLICATION]
+ UefiDecompressLib|IntelFrameworkModulePkg/Library/BaseUefiTianoCustomDecompressLib/BaseUefiTianoCustomDecompressLib.inf
+ PerformanceLib|MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+ HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
+
+[LibraryClasses.common.UEFI_DRIVER]
+ UefiDecompressLib|IntelFrameworkModulePkg/Library/BaseUefiTianoCustomDecompressLib/BaseUefiTianoCustomDecompressLib.inf
+ ExtractGuidedSectionLib|MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGuidedSectionLib.inf
+ PerformanceLib|MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+
+[LibraryClasses.common.DXE_RUNTIME_DRIVER]
+ HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+ CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf
+
+[LibraryClasses.ARM, LibraryClasses.AARCH64]
+ #
+ # It is not possible to prevent the ARM compiler for generic intrinsic functions.
+ # This library provides the instrinsic functions generate by a given compiler.
+ # [LibraryClasses.ARM] and NULL mean link this library into all ARM images.
+ #
+ NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf
+
+ # Add support for GCC stack protector
+ NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf
+
+################################################################################
+#
+# Pcd Section - list of all EDK II PCD Entries defined by this Platform
+#
+################################################################################
+
+[PcdsFeatureFlag.common]
+ gEfiMdePkgTokenSpaceGuid.PcdComponentNameDisable|TRUE
+ gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnosticsDisable|TRUE
+ gEfiMdePkgTokenSpaceGuid.PcdComponentName2Disable|TRUE
+ gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnostics2Disable|TRUE
+
+ #
+ # Control what commands are supported from the UI
+ # Turn these on and off to add features or save size
+ #
+ gEmbeddedTokenSpaceGuid.PcdEmbeddedMacBoot|TRUE
+ gEmbeddedTokenSpaceGuid.PcdEmbeddedDirCmd|TRUE
+ gEmbeddedTokenSpaceGuid.PcdEmbeddedHobCmd|TRUE
+ gEmbeddedTokenSpaceGuid.PcdEmbeddedHwDebugCmd|TRUE
+ gEmbeddedTokenSpaceGuid.PcdEmbeddedPciDebugCmd|TRUE
+ gEmbeddedTokenSpaceGuid.PcdEmbeddedIoEnable|FALSE
+ gEmbeddedTokenSpaceGuid.PcdEmbeddedScriptCmd|FALSE
+
+ gEmbeddedTokenSpaceGuid.PcdCacheEnable|TRUE
+
+ # Use the Vector Table location in CpuDxe.
+ # We will not copy the Vector Table at PcdCpuVectorBaseAddress
+ gArmTokenSpaceGuid.PcdRelocateVectorTable|FALSE
+
+ gEmbeddedTokenSpaceGuid.PcdPrePiProduceMemoryTypeInformationHob|TRUE
+
+ # If TRUE, Graphics Output Protocol will be installed on virtual
+ # handle created by ConsplitterDxe. It could be set FALSE to save size.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutGopSupport|TRUE
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutUgaSupport|FALSE
+
+ # USB support
+ gEfiMdeModulePkgTokenSpaceGuid.PcdTurnOffUsbLegacySupport|TRUE
+
+[PcdsFixedAtBuild.common]
+ gArmPlatformTokenSpaceGuid.PcdFirmwareVendor|"Marvell"
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString|L"MARVELL_EFI"
+ gArmPlatformTokenSpaceGuid.PcdCoreCount|4
+
+ ## Use the serial console (ConIn & ConOut) and the Graphic driver (ConOut)
+ gArmPlatformTokenSpaceGuid.PcdDefaultConOutPaths|L"VenHw(D3987D4B-971A-435F-8CAF-4967EB627241)/Uart(115200,8,N,1)/VenPcAnsi()"
+ gArmPlatformTokenSpaceGuid.PcdDefaultConInPaths|L"VenHw(D3987D4B-971A-435F-8CAF-4967EB627241)/Uart(115200,8,N,1)/VenPcAnsi()"
+
+ gEmbeddedTokenSpaceGuid.PcdEmbeddedPrompt|"Marvell>> "
+ gEfiMdePkgTokenSpaceGuid.PcdMaximumUnicodeStringLength|1000000
+ gEfiMdePkgTokenSpaceGuid.PcdMaximumAsciiStringLength|1000000
+ gEfiMdePkgTokenSpaceGuid.PcdMaximumLinkedListLength|1000000
+ gEfiMdePkgTokenSpaceGuid.PcdSpinLockTimeout|10000000
+ gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue|0xAF
+ gEfiMdePkgTokenSpaceGuid.PcdPerformanceLibraryPropertyMask|1
+ gEfiMdePkgTokenSpaceGuid.PcdPostCodePropertyMask|0
+ gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|320
+ gEfiMdePkgTokenSpaceGuid.PcdDefaultTerminalType|1
+ gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut|3
+
+ # Required for Intel BDS
+ gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdShellFile|{ 0x83, 0xA5, 0x04, 0x7C, 0x3E, 0x9E, 0x1C, 0x4F, 0xAD, 0x65, 0xE0, 0x52, 0x68, 0xD0, 0xB4, 0xD1 }
+
+ # ARM Generic Interrupt Controller
+ gArmTokenSpaceGuid.PcdGicDistributorBase|0xF0210000
+ gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase|0xF0220000
+
+ # ARM Architectural Timer Support
+ gArmTokenSpaceGuid.PcdArmArchTimerFreqInHz|25000000
+ gEmbeddedTokenSpaceGuid.PcdMetronomeTickPeriod|1000
+
+ # ARM SBSA Watchdog
+ gArmTokenSpaceGuid.PcdGenericWatchdogControlBase|0xF0620000
+ gArmTokenSpaceGuid.PcdGenericWatchdogRefreshBase|0xF0600000
+ gArmTokenSpaceGuid.PcdGenericWatchdogEl2IntrNum|34
+
+ # Serial
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseMmio|TRUE
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHardwareFlowControl|FALSE
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase|0xF0512000
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialBaudRate|115200
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate|200000000
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterStride|4
+
+ # DEBUG_ASSERT_ENABLED 0x01
+ # DEBUG_PRINT_ENABLED 0x02
+ # DEBUG_CODE_ENABLED 0x04
+ # CLEAR_MEMORY_ENABLED 0x08
+ # ASSERT_BREAKPOINT_ENABLED 0x10
+ # ASSERT_DEADLOOP_ENABLED 0x20
+
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x2f
+
+ # DEBUG_INIT 0x00000001 // Initialization
+ # DEBUG_WARN 0x00000002 // Warnings
+ # DEBUG_LOAD 0x00000004 // Load events
+ # DEBUG_FS 0x00000008 // EFI File system
+ # DEBUG_POOL 0x00000010 // Alloc & Free (pool)
+ # DEBUG_PAGE 0x00000020 // Alloc & Free (page)
+ # DEBUG_INFO 0x00000040 // Informational debug messages
+ # DEBUG_DISPATCH 0x00000080 // PEI/DXE/SMM Dispatchers
+ # DEBUG_VARIABLE 0x00000100 // Variable
+ # DEBUG_BM 0x00000400 // Boot Manager
+ # DEBUG_BLKIO 0x00001000 // BlkIo Driver
+ # DEBUG_NET 0x00004000 // SNP Driver
+ # DEBUG_UNDI 0x00010000 // UNDI Driver
+ # DEBUG_LOADFILE 0x00020000 // LoadFile
+ # DEBUG_EVENT 0x00080000 // Event messages
+ # DEBUG_GCD 0x00100000 // Global Coherency Database changes
+ # DEBUG_CACHE 0x00200000 // Memory range cachability changes
+ # DEBUG_VERBOSE 0x00400000 // Detailed debug messages that may
+ # // significantly impact boot performance
+ # DEBUG_ERROR 0x80000000 // Error
+
+!if $(TARGET) == RELEASE
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x80000000
+!else
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x8000000F
+!endif
+
+ gEmbeddedTokenSpaceGuid.PcdEmbeddedAutomaticBootCommand|""
+ gEmbeddedTokenSpaceGuid.PcdEmbeddedDefaultTextColor|0x07
+ gEmbeddedTokenSpaceGuid.PcdEmbeddedMemVariableStoreSize|0x10000
+
+ #
+ # Optional feature to help prevent EFI memory map fragments
+ # Turned on and off via: PcdPrePiProduceMemoryTypeInformationHob
+ # Values are in EFI Pages (4K). DXE Core will make sure that
+ # at least this much of each type of memory can be allocated
+ # from a single memory range. This way you only end up with
+ # maximum of two fragements for each type in the memory map
+ # (the memory used, and the free memory that was prereserved
+ # but not used).
+ #
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIReclaimMemory|0
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIMemoryNVS|0
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiReservedMemoryType|0
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesData|50
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesCode|20
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesCode|400
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesData|20000
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderCode|20
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderData|0
+
+ # We want to use the Shell Libraries but don't want it to initialise
+ # automatically. We initialise the libraries when the command is called by the
+ # Shell.
+ gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE
+
+ # ARM Pcds
+ gArmTokenSpaceGuid.PcdSystemMemoryBase|0
+ gArmTokenSpaceGuid.PcdSystemMemorySize|0x40000000
+ gArmTokenSpaceGuid.PcdArmScr|0x531
+
+################################################################################
+#
+# Components Section - list of all EDK II Modules needed by this Platform
+#
+################################################################################
+[Components.common]
+
+ # PEI Phase modules
+ ArmPlatformPkg/PrePi/PeiMPCore.inf
+
+ # DXE
+ MdeModulePkg/Core/Dxe/DxeMain.inf {
+ <LibraryClasses>
+ PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+ NULL|MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.inf
+ }
+
+ # Architectural Protocols DXE
+ ArmPkg/Drivers/CpuDxe/CpuDxe.inf
+ ArmPkg/Drivers/ArmGic/ArmGicDxe.inf
+ ArmPkg/Drivers/TimerDxe/TimerDxe.inf
+ ArmPkg/Drivers/GenericWatchdogDxe/GenericWatchdogDxe.inf
+
+ # Platform drivers
+ Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf
+ MdeModulePkg/Bus/I2c/I2cDxe/I2cDxe.inf
+ Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.inf
+ Platform/Marvell/Drivers/Spi/MvSpiDxe.inf
+ Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.inf
+
+ # Network support
+ MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.inf
+ MdeModulePkg/Universal/Network/DpcDxe/DpcDxe.inf
+ MdeModulePkg/Universal/Network/MnpDxe/MnpDxe.inf
+ MdeModulePkg/Universal/Network/VlanConfigDxe/VlanConfigDxe.inf
+ MdeModulePkg/Universal/Network/ArpDxe/ArpDxe.inf
+ MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Dxe.inf
+ MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Dxe.inf
+ MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Dxe.inf
+ MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf
+ MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dxe.inf
+ Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.inf
+ Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.inf
+ Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.inf
+
+ MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
+ MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
+ MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
+ MdeModulePkg/Universal/Variable/EmuRuntimeDxe/EmuVariableRuntimeDxe.inf
+
+ EmbeddedPkg/EmbeddedMonotonicCounter/EmbeddedMonotonicCounter.inf
+ MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf
+ EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClockRuntimeDxe.inf
+ EmbeddedPkg/MetronomeDxe/MetronomeDxe.inf
+
+ # PciEmulation
+ Platform/Marvell/PciEmulation/PciEmulation.inf
+ MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.inf
+
+ # SCSI
+ MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf
+ MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf
+
+ # SATA
+ MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf
+ MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf
+ OvmfPkg/SataControllerDxe/SataControllerDxe.inf
+
+ # USB
+ MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf
+ MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf
+ MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
+
+ # SD/MMC
+ MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf
+ MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf
+ Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.inf
+
+ # Console packages
+ MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf
+ MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf
+ MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf
+ MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf
+ MdeModulePkg/Universal/SerialDxe/SerialDxe.inf
+
+ # Human interface:
+ MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf
+
+ # FAT filesystem + GPT/MBR partitioning
+ MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
+ MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
+ MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
+
+ # Bds - Use Intel BDS
+ MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf
+ MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf
+ MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf
+ IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.inf
+
+ # UEFI application (Shell Embedded Boot Loader)
+ ShellPkg/Application/Shell/Shell.inf {
+ <LibraryClasses>
+ ShellCommandLib|ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf
+ NULL|ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.inf
+ NULL|Platform/Marvell/Applications/EepromCmd/EepromCmd.inf
+ NULL|Platform/Marvell/Applications/SpiTool/SpiFlashCmd.inf
+ NULL|Platform/Marvell/Applications/FirmwareUpdate/FUpdate.inf
+ HandleParsingLib|ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf
+ PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
+ BcfgCommandLib|ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.inf
+
+ <PcdsFixedAtBuild>
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xFF
+ gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE
+ gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|8000
+ }
diff --git a/Platform/Marvell/Armada/Armada70x0.dsc b/Platform/Marvell/Armada/Armada70x0.dsc
new file mode 100644
index 0000000000..3440038ff2
--- /dev/null
+++ b/Platform/Marvell/Armada/Armada70x0.dsc
@@ -0,0 +1,145 @@
+#Copyright (C) 2016 Marvell International Ltd.
+#
+#Marvell BSD License Option
+#
+#If you received this File from Marvell, you may opt to use, redistribute and/or
+#modify this File under the following licensing terms.
+#Redistribution and use in source and binary forms, with or without modification,
+#are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Marvell nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+#ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+#WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+#DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+#ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+#(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+#ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+#SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+################################################################################
+#
+# Defines Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+[Defines]
+ PLATFORM_NAME = Armada70x0
+ PLATFORM_GUID = f837e231-cfc7-4f56-9a0f-5b218d746ae3
+ PLATFORM_VERSION = 0.1
+ DSC_SPECIFICATION = 0x00010005
+ OUTPUT_DIRECTORY = Build/$(PLATFORM_NAME)
+ SUPPORTED_ARCHITECTURES = AARCH64
+ BUILD_TARGETS = DEBUG|RELEASE
+ SKUID_IDENTIFIER = DEFAULT
+ FLASH_DEFINITION = Platform/Marvell/Armada/Armada70x0.fdf
+
+!include Armada.dsc.inc
+
+################################################################################
+#
+# Pcd Section - list of all EDK II PCD Entries defined by this Platform
+#
+################################################################################
+[PcdsFixedAtBuild.common]
+ #MPP
+ gMarvellTokenSpaceGuid.PcdMppChipCount|2
+
+ # APN806-A0 MPP SET
+ gMarvellTokenSpaceGuid.PcdChip0MppReverseFlag|FALSE
+ gMarvellTokenSpaceGuid.PcdChip0MppBaseAddress|0xF06F4000
+ gMarvellTokenSpaceGuid.PcdChip0MppPinCount|20
+ gMarvellTokenSpaceGuid.PcdChip0MppSel0|{ 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }
+ gMarvellTokenSpaceGuid.PcdChip0MppSel1|{ 0x1, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3 }
+
+ # CP110 MPP SET - Router configuration
+ gMarvellTokenSpaceGuid.PcdChip1MppReverseFlag|FALSE
+ gMarvellTokenSpaceGuid.PcdChip1MppBaseAddress|0xF2440000
+ gMarvellTokenSpaceGuid.PcdChip1MppPinCount|64
+ gMarvellTokenSpaceGuid.PcdChip1MppSel0|{ 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4 }
+ gMarvellTokenSpaceGuid.PcdChip1MppSel1|{ 0x4, 0x4, 0x0, 0x3, 0x3, 0x3, 0x3, 0x0, 0x0, 0x0 }
+ gMarvellTokenSpaceGuid.PcdChip1MppSel2|{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9, 0xA }
+ gMarvellTokenSpaceGuid.PcdChip1MppSel3|{ 0xA, 0x0, 0x7, 0x0, 0x7, 0x7, 0x7, 0x2, 0x2, 0x0 }
+ gMarvellTokenSpaceGuid.PcdChip1MppSel4|{ 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }
+ gMarvellTokenSpaceGuid.PcdChip1MppSel5|{ 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0xE, 0xE, 0xE, 0xE }
+ gMarvellTokenSpaceGuid.PcdChip1MppSel6|{ 0xE, 0xE, 0xE, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+
+ # I2C
+ gMarvellTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x50, 0x57, 0x60 }
+ gMarvellTokenSpaceGuid.PcdI2cSlaveBuses|{ 0x0, 0x0, 0x0 }
+ gMarvellTokenSpaceGuid.PcdI2cBaseAddresses|L"0xF2701000;0xF2701100"
+ gMarvellTokenSpaceGuid.PcdEepromI2cAddresses|{ 0x50, 0x57 }
+ gMarvellTokenSpaceGuid.PcdEepromI2cBuses|{ 0x0, 0x0 }
+ gMarvellTokenSpaceGuid.PcdI2cClockFrequency|250000000
+ gMarvellTokenSpaceGuid.PcdI2cBaudRate|100000
+ gMarvellTokenSpaceGuid.PcdI2cBusCount|2
+
+ #SPI
+ gMarvellTokenSpaceGuid.PcdSpiRegBase|0xF2700680
+ gMarvellTokenSpaceGuid.PcdSpiMaxFrequency|10000000
+ gMarvellTokenSpaceGuid.PcdSpiClockFrequency|200000000
+
+ gMarvellTokenSpaceGuid.PcdSpiFlashPollCmd|0x70
+ gMarvellTokenSpaceGuid.PcdSpiFlashAddressCycles|3
+ gMarvellTokenSpaceGuid.PcdSpiFlashEraseSize|65536
+ gMarvellTokenSpaceGuid.PcdSpiFlashPageSize|256
+ gMarvellTokenSpaceGuid.PcdSpiFlashId|0x20BA18
+
+ #ComPhy
+ gMarvellTokenSpaceGuid.PcdComPhyDevices|{ 0x1 }
+ gMarvellTokenSpaceGuid.PcdChip0ComPhyTypes|L"SGMII1;USB3_HOST0;SGMII0;SATA1;USB3_HOST1;PCIE2"
+ gMarvellTokenSpaceGuid.PcdChip0ComPhySpeeds|L"3125;5000;1250;5000;5000;5000"
+
+ #UtmiPhy
+ gMarvellTokenSpaceGuid.PcdUtmiPhyCount|2
+ gMarvellTokenSpaceGuid.PcdUtmiPhyRegUsbCfg|L"0xF2440420;0xF2440420"
+ gMarvellTokenSpaceGuid.PcdUtmiPhyRegUtmiCfg|L"0xF2440440;0xF2440444"
+ gMarvellTokenSpaceGuid.PcdUtmiPhyRegUtmiUnit|L"0xF2580000;0xF2581000"
+ gMarvellTokenSpaceGuid.PcdUtmiPhyUtmiPort|L"0x0;0x1"
+
+ #MDIO
+ gMarvellTokenSpaceGuid.PcdMdioBaseAddress|0xF212A200
+
+ #PHY
+ gMarvellTokenSpaceGuid.PcdPhyConnectionTypes|{ 0x4, 0x4, 0x0 }
+ gMarvellTokenSpaceGuid.PcdPhyDeviceIds|{ 0x0, 0x0 }
+ gMarvellTokenSpaceGuid.PcdPhyStartupAutoneg|FALSE
+
+ #NET
+ gMarvellTokenSpaceGuid.PcdPhySmiAddresses|{ 0xff, 0x0, 0x1 }
+ gMarvellTokenSpaceGuid.PcdPp2ClockFrequency|333333333
+ gMarvellTokenSpaceGuid.PcdPp2GmacBaseAddress|0xf2130e00
+ gMarvellTokenSpaceGuid.PcdPp2GmacDevSize|0x1000
+ gMarvellTokenSpaceGuid.PcdPp2GopIndexes|{ 0x0, 0x2, 0x3 }
+ gMarvellTokenSpaceGuid.PcdPp2InterfaceAlwaysUp|{ 0x1, 0x1, 0x0 }
+ gMarvellTokenSpaceGuid.PcdPp2InterfaceSpeed|{ 0x3, 0x4, 0x3 }
+ gMarvellTokenSpaceGuid.PcdPp2NumPorts|3
+ gMarvellTokenSpaceGuid.PcdPp2PortIds|{ 0x0, 0x1, 0x2 }
+ gMarvellTokenSpaceGuid.PcdPp2Rfu1BaseAddress|0xf2441000
+ gMarvellTokenSpaceGuid.PcdPp2SharedAddress|0xf2000000
+ gMarvellTokenSpaceGuid.PcdPp2SmiBaseAddress|0xf212A200
+ gMarvellTokenSpaceGuid.PcdPp2XlgBaseAddress|0xf2130f00
+ gMarvellTokenSpaceGuid.PcdPp2XlgDevSize|0x1000
+
+ #PciEmulation
+ gMarvellTokenSpaceGuid.PcdPciEXhci|{ 0x1, 0x1, 0x0, 0x0 }
+ gMarvellTokenSpaceGuid.PcdPciEAhci|{ 0x1, 0x0 }
+ gMarvellTokenSpaceGuid.PcdPciESdhci|{ 0x1, 0x1 }
+
+ #ResetLib
+ gMarvellTokenSpaceGuid.PcdResetRegAddress|0xf06f0084
+ gMarvellTokenSpaceGuid.PcdResetRegMask|0x1
+
+ #RTC
+ gMarvellTokenSpaceGuid.PcdRtcEnabled|{ 0x1 }
diff --git a/Platform/Marvell/Armada/Armada70x0.fdf b/Platform/Marvell/Armada/Armada70x0.fdf
new file mode 100644
index 0000000000..c861e78a6f
--- /dev/null
+++ b/Platform/Marvell/Armada/Armada70x0.fdf
@@ -0,0 +1,304 @@
+#
+# Copyright (C) Marvell International Ltd. and its affiliates
+#
+# 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.
+#
+
+################################################################################
+#
+# FD Section
+# The [FD] Section is made up of the definition statements and a
+# description of what goes into the Flash Device Image. Each FD section
+# defines one flash "device" image. A flash device image may be one of
+# the following: Removable media bootable image (like a boot floppy
+# image,) an Option ROM image (that would be "flashed" into an add-in
+# card,) a System "Flash" image (that would be burned into a system's
+# flash) or an Update ("Capsule") image that will be used to update and
+# existing system flash.
+#
+################################################################################
+
+[FD.Armada70x0_EFI]
+BaseAddress = 0x00000000|gArmTokenSpaceGuid.PcdFdBaseAddress # The base address of the Firmware in NOR Flash.
+Size = 0x00400000|gArmTokenSpaceGuid.PcdFdSize # The size in bytes of the FLASH Device
+ErasePolarity = 1
+
+# This one is tricky, it must be: BlockSize * NumBlocks = Size
+BlockSize = 0x00001000
+NumBlocks = 0x400
+
+################################################################################
+#
+# Following are lists of FD Region layout which correspond to the locations of different
+# images within the flash device.
+#
+# Regions must be defined in ascending order and may not overlap.
+#
+# A Layout Region start with a eight digit hex offset (leading "0x" required) followed by
+# the pipe "|" character, followed by the size of the region, also in hex with the leading
+# "0x" characters. Like:
+# Offset|Size
+# PcdOffsetCName|PcdSizeCName
+# RegionType <FV, DATA, or FILE>
+#
+################################################################################
+
+0x00000000|0x00100000
+gArmTokenSpaceGuid.PcdFvBaseAddress|gArmTokenSpaceGuid.PcdFvSize
+FV = FVMAIN_COMPACT
+
+
+################################################################################
+#
+# FV Section
+#
+# [FV] section is used to define what components or modules are placed within a flash
+# device file. This section also defines order the components and modules are positioned
+# within the image. The [FV] section consists of define statements, set statements and
+# module statements.
+#
+################################################################################
+
+# DXE phase firmware volume
+[FV.FvMain]
+BlockSize = 0x40
+NumBlocks = 0 # This FV gets compressed so make it just big enough
+FvAlignment = 8 # FV alignment and FV attributes setting.
+ERASE_POLARITY = 1
+MEMORY_MAPPED = TRUE
+STICKY_WRITE = TRUE
+LOCK_CAP = TRUE
+LOCK_STATUS = TRUE
+WRITE_DISABLED_CAP = TRUE
+WRITE_ENABLED_CAP = TRUE
+WRITE_STATUS = TRUE
+WRITE_LOCK_CAP = TRUE
+WRITE_LOCK_STATUS = TRUE
+READ_DISABLED_CAP = TRUE
+READ_ENABLED_CAP = TRUE
+READ_STATUS = TRUE
+READ_LOCK_CAP = TRUE
+READ_LOCK_STATUS = TRUE
+FvNameGuid = 5eda4200-2c5f-43cb-9da3-0baf74b1b30c
+
+ INF MdeModulePkg/Core/Dxe/DxeMain.inf
+
+ # PI DXE Drivers producing Architectural Protocols (EFI Services)
+ INF ArmPkg/Drivers/CpuDxe/CpuDxe.inf
+ INF ArmPkg/Drivers/ArmGic/ArmGicDxe.inf
+ INF ArmPkg/Drivers/TimerDxe/TimerDxe.inf
+ INF ArmPkg/Drivers/GenericWatchdogDxe/GenericWatchdogDxe.inf
+ INF MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
+ INF MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
+ INF MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
+ INF MdeModulePkg/Universal/Variable/EmuRuntimeDxe/EmuVariableRuntimeDxe.inf
+ INF EmbeddedPkg/EmbeddedMonotonicCounter/EmbeddedMonotonicCounter.inf
+ INF MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf
+ INF EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClockRuntimeDxe.inf
+ INF EmbeddedPkg/MetronomeDxe/MetronomeDxe.inf
+ INF Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf
+ INF MdeModulePkg/Bus/I2c/I2cDxe/I2cDxe.inf
+ INF Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.inf
+ INF Platform/Marvell/Drivers/Spi/MvSpiDxe.inf
+ INF Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.inf
+
+ # Network support
+ INF MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.inf
+ INF MdeModulePkg/Universal/Network/DpcDxe/DpcDxe.inf
+ INF MdeModulePkg/Universal/Network/MnpDxe/MnpDxe.inf
+ INF MdeModulePkg/Universal/Network/VlanConfigDxe/VlanConfigDxe.inf
+ INF MdeModulePkg/Universal/Network/ArpDxe/ArpDxe.inf
+ INF MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Dxe.inf
+ INF MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf
+ INF MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dxe.inf
+ INF Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.inf
+ INF Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.inf
+ INF Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.inf
+
+ # PciEmulation
+ INF Platform/Marvell/PciEmulation/PciEmulation.inf
+ INF MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.inf
+
+ # SCSI
+ INF MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf
+ INF MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf
+
+ # SATA
+ INF MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf
+ INF MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf
+ INF OvmfPkg/SataControllerDxe/SataControllerDxe.inf
+
+ # USB
+ INF MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf
+ INF MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf
+ INF MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
+
+ # SD/MMC
+ INF MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf
+ INF MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf
+ INF Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.inf
+
+ # Multiple Console IO support
+ INF MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf
+ INF MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf
+ INF MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf
+ INF MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf
+ INF MdeModulePkg/Universal/SerialDxe/SerialDxe.inf
+
+ # Human interface
+ INF MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf
+
+ # FAT filesystem + GPT/MBR partitioning
+ INF MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
+ INF MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
+ INF FatBinPkg/EnhancedFatDxe/Fat.inf
+ INF MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
+
+ # UEFI application (Shell Embedded Boot Loader)
+ INF ShellPkg/Application/Shell/Shell.inf
+
+ # Bds
+ INF MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf
+ INF MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf
+ INF MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf
+ INF IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.inf
+
+
+# PEI phase firmware volume
+[FV.FVMAIN_COMPACT]
+FvAlignment = 8
+FvForceRebase = TRUE
+ERASE_POLARITY = 1
+MEMORY_MAPPED = TRUE
+STICKY_WRITE = TRUE
+LOCK_CAP = TRUE
+LOCK_STATUS = TRUE
+WRITE_DISABLED_CAP = TRUE
+WRITE_ENABLED_CAP = TRUE
+WRITE_STATUS = TRUE
+WRITE_LOCK_CAP = TRUE
+WRITE_LOCK_STATUS = TRUE
+READ_DISABLED_CAP = TRUE
+READ_ENABLED_CAP = TRUE
+READ_STATUS = TRUE
+READ_LOCK_CAP = TRUE
+READ_LOCK_STATUS = TRUE
+
+ INF ArmPlatformPkg/PrePi/PeiMPCore.inf
+
+ FILE FV_IMAGE = 9E21FD93-9C72-4c15-8C4B-E77F1DB2D792 {
+ SECTION GUIDED EE4E5898-3914-4259-9D6E-DC7BD79403CF PROCESSING_REQUIRED = TRUE {
+ SECTION FV_IMAGE = FVMAIN
+ }
+ }
+
+################################################################################
+#
+# Rules are use with the [FV] section's module INF type to define
+# how an FFS file is created for a given INF file. The following Rule are the default
+# rules for the different module type. User can add the customized rules to define the
+# content of the FFS file.
+#
+################################################################################
+
+
+############################################################################
+# Example of a DXE_DRIVER FFS file with a Checksum encapsulation section #
+############################################################################
+#
+#[Rule.Common.DXE_DRIVER]
+# FILE DRIVER = $(NAMED_GUID) {
+# DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
+# COMPRESS PI_STD {
+# GUIDED {
+# PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi
+# UI STRING="$(MODULE_NAME)" Optional
+# VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER)
+# }
+# }
+# }
+#
+############################################################################
+
+[Rule.ARM.SEC]
+ FILE SEC = $(NAMED_GUID) RELOCS_STRIPPED {
+ TE TE Align = 32 $(INF_OUTPUT)/$(MODULE_NAME).efi
+ }
+
+# The AArch64 Vector Table requires a 2K alignment that is not supported by the FDF specification.
+# It is the reason 4K is used instead of 2K for the module alignment.
+[Rule.AARCH64.SEC]
+ FILE SEC = $(NAMED_GUID) RELOCS_STRIPPED {
+ TE TE Align = 4K $(INF_OUTPUT)/$(MODULE_NAME).efi
+ }
+
+[Rule.Common.PEI_CORE]
+ FILE PEI_CORE = $(NAMED_GUID) {
+ TE TE $(INF_OUTPUT)/$(MODULE_NAME).efi
+ UI STRING ="$(MODULE_NAME)" Optional
+ }
+
+[Rule.Common.PEIM]
+ FILE PEIM = $(NAMED_GUID) {
+ PEI_DEPEX PEI_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
+ TE TE $(INF_OUTPUT)/$(MODULE_NAME).efi
+ UI STRING="$(MODULE_NAME)" Optional
+ }
+
+[Rule.Common.PEIM.TIANOCOMPRESSED]
+ FILE PEIM = $(NAMED_GUID) DEBUG_MYTOOLS_IA32 {
+ PEI_DEPEX PEI_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
+ GUIDED A31280AD-481E-41B6-95E8-127F4C984779 PROCESSING_REQUIRED = TRUE {
+ PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi
+ UI STRING="$(MODULE_NAME)" Optional
+ }
+ }
+
+[Rule.Common.DXE_CORE]
+ FILE DXE_CORE = $(NAMED_GUID) {
+ PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi
+ UI STRING="$(MODULE_NAME)" Optional
+ }
+
+[Rule.Common.UEFI_DRIVER]
+ FILE DRIVER = $(NAMED_GUID) {
+ DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
+ PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi
+ UI STRING="$(MODULE_NAME)" Optional
+ }
+
+[Rule.Common.UEFI_DRIVER.BINARY]
+ FILE DRIVER = $(NAMED_GUID) {
+ DXE_DEPEX DXE_DEPEX Optional |.depex
+ PE32 PE32 |.efi
+ UI STRING="$(MODULE_NAME)" Optional
+ VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER)
+ }
+
+[Rule.Common.DXE_DRIVER]
+ FILE DRIVER = $(NAMED_GUID) {
+ DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
+ PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi
+ UI STRING="$(MODULE_NAME)" Optional
+ }
+
+[Rule.Common.DXE_RUNTIME_DRIVER]
+ FILE DRIVER = $(NAMED_GUID) {
+ DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
+ PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi
+ UI STRING="$(MODULE_NAME)" Optional
+ }
+
+[Rule.Common.UEFI_APPLICATION]
+ FILE APPLICATION = $(NAMED_GUID) {
+ UI STRING ="$(MODULE_NAME)" Optional
+ PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi
+ }
diff --git a/Platform/Marvell/Armada/Library/Armada70x0Lib/AArch64/ArmPlatformHelper.S b/Platform/Marvell/Armada/Library/Armada70x0Lib/AArch64/ArmPlatformHelper.S
new file mode 100644
index 0000000000..9265636ca5
--- /dev/null
+++ b/Platform/Marvell/Armada/Library/Armada70x0Lib/AArch64/ArmPlatformHelper.S
@@ -0,0 +1,50 @@
+//Based on ArmPlatformPkg/Library/ArmPlatformLibNull/AArch64/ArmPlatformHelper.S
+//
+// Copyright (c) 2012-2013, ARM Limited. All rights reserved.
+// Copyright (c) 2016, Marvell. 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 <AsmMacroIoLibV8.h>
+#include <Library/ArmLib.h>
+
+ASM_FUNC(ArmPlatformPeiBootAction)
+ ret
+
+//UINTN
+//ArmPlatformGetCorePosition (
+// IN UINTN MpId
+// );
+// With this function: CorePos = (ClusterId * 4) + CoreId
+ASM_FUNC(ArmPlatformGetCorePosition)
+ and x1, x0, #ARM_CORE_MASK
+ and x0, x0, #ARM_CLUSTER_MASK
+ add x0, x1, x0, LSR #6
+ ret
+
+//UINTN
+//ArmPlatformGetPrimaryCoreMpId (
+// VOID
+// );
+ASM_FUNC(ArmPlatformGetPrimaryCoreMpId)
+ MOV32 (w0, FixedPcdGet32(PcdArmPrimaryCore))
+ ret
+
+//UINTN
+//ArmPlatformIsPrimaryCore (
+// IN UINTN MpId
+// );
+ASM_FUNC(ArmPlatformIsPrimaryCore)
+ MOV32 (w1, FixedPcdGet32(PcdArmPrimaryCoreMask))
+ and x0, x0, x1
+ MOV32 (w1, FixedPcdGet32(PcdArmPrimaryCore))
+ cmp w0, w1
+ cset x0, eq
+ ret
diff --git a/Platform/Marvell/Armada/Library/Armada70x0Lib/Armada70x0Lib.c b/Platform/Marvell/Armada/Library/Armada70x0Lib/Armada70x0Lib.c
new file mode 100644
index 0000000000..0ed310f8be
--- /dev/null
+++ b/Platform/Marvell/Armada/Library/Armada70x0Lib/Armada70x0Lib.c
@@ -0,0 +1,157 @@
+/**Based on ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.c
+*
+* Copyright (c) 2011-2012, ARM Limited. All rights reserved.
+* Copyright (c) 2016, Marvell International 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 <Library/ArmLib.h>
+#include <Library/ArmPlatformLib.h>
+#include <Library/MppLib.h>
+#include <Library/MvComPhyLib.h>
+#include <Library/UtmiPhyLib.h>
+#include <Ppi/ArmMpCoreInfo.h>
+
+
+ARM_CORE_INFO mArmada7040MpCoreInfoTable[] = {
+ {
+ // Cluster 0, Core 0
+ 0x0, 0x0,
+
+ // MP Core MailBox Set/Get/Clear Addresses and Clear Value
+ (EFI_PHYSICAL_ADDRESS)0,
+ (EFI_PHYSICAL_ADDRESS)0,
+ (EFI_PHYSICAL_ADDRESS)0,
+ (UINT64)0xFFFFFFFF
+ },
+ {
+ // Cluster 0, Core 1
+ 0x0, 0x1,
+
+ // MP Core MailBox Set/Get/Clear Addresses and Clear Value
+ (EFI_PHYSICAL_ADDRESS)0,
+ (EFI_PHYSICAL_ADDRESS)0,
+ (EFI_PHYSICAL_ADDRESS)0,
+ (UINT64)0xFFFFFFFF
+ },
+ {
+ // Cluster 0, Core 2
+ 0x0, 0x2,
+
+ // MP Core MailBox Set/Get/Clear Addresses and Clear Value
+ (EFI_PHYSICAL_ADDRESS)0,
+ (EFI_PHYSICAL_ADDRESS)0,
+ (EFI_PHYSICAL_ADDRESS)0,
+ (UINT64)0xFFFFFFFF
+ },
+ {
+ // Cluster 0, Core 3
+ 0x0, 0x3,
+
+ // MP Core MailBox Set/Get/Clear Addresses and Clear Value
+ (EFI_PHYSICAL_ADDRESS)0,
+ (EFI_PHYSICAL_ADDRESS)0,
+ (EFI_PHYSICAL_ADDRESS)0,
+ (UINT64)0xFFFFFFFF
+ }
+};
+
+/**
+ Return the current Boot Mode
+
+ This function returns the boot reason on the platform
+
+**/
+EFI_BOOT_MODE
+ArmPlatformGetBootMode (
+ VOID
+ )
+{
+ return BOOT_WITH_FULL_CONFIGURATION;
+}
+
+/**
+ Initialize controllers that must setup in the normal world
+
+ This function is called by the ArmPlatformPkg/PrePi or ArmPlatformPkg/PlatformPei
+ in the PEI phase.
+
+**/
+RETURN_STATUS
+ArmPlatformInitialize (
+ IN UINTN MpId
+ )
+{
+ if (!ArmPlatformIsPrimaryCore (MpId)) {
+ return RETURN_SUCCESS;
+ }
+
+ MvComPhyInit ();
+ UtmiPhyInit ();
+ MppInitialize ();
+ return RETURN_SUCCESS;
+}
+
+/**
+ Initialize the system (or sometimes called permanent) memory
+
+ This memory is generally represented by the DRAM.
+
+**/
+VOID
+ArmPlatformInitializeSystemMemory (
+ VOID
+ )
+{
+ //TODO: Initialize DRAM controller here
+}
+
+EFI_STATUS
+PrePeiCoreGetMpCoreInfo (
+ OUT UINTN *CoreCount,
+ OUT ARM_CORE_INFO **ArmCoreTable
+ )
+{
+ if (ArmIsMpCore()) {
+ *CoreCount = sizeof(mArmada7040MpCoreInfoTable) / sizeof(ARM_CORE_INFO);
+ *ArmCoreTable = mArmada7040MpCoreInfoTable;
+ return EFI_SUCCESS;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+}
+
+ARM_MP_CORE_INFO_PPI mMpCoreInfoPpi = { PrePeiCoreGetMpCoreInfo };
+
+EFI_PEI_PPI_DESCRIPTOR gPlatformPpiTable[] = {
+ {
+ EFI_PEI_PPI_DESCRIPTOR_PPI,
+ &gArmMpCoreInfoPpiGuid,
+ &mMpCoreInfoPpi
+ }
+};
+
+VOID
+ArmPlatformGetPlatformPpiList (
+ OUT UINTN *PpiListSize,
+ OUT EFI_PEI_PPI_DESCRIPTOR **PpiList
+ )
+{
+ if (ArmIsMpCore()) {
+ *PpiListSize = sizeof(gPlatformPpiTable);
+ *PpiList = gPlatformPpiTable;
+ } else {
+ *PpiListSize = 0;
+ *PpiList = NULL;
+ }
+}
+
+
diff --git a/Platform/Marvell/Armada/Library/Armada70x0Lib/Armada70x0Lib.inf b/Platform/Marvell/Armada/Library/Armada70x0Lib/Armada70x0Lib.inf
new file mode 100644
index 0000000000..2e198c3a0f
--- /dev/null
+++ b/Platform/Marvell/Armada/Library/Armada70x0Lib/Armada70x0Lib.inf
@@ -0,0 +1,71 @@
+# Copyright (C) 2016 Marvell International Ltd.
+#
+# Marvell BSD License Option
+#
+# If you received this File from Marvell, you may opt to use, redistribute
+# and/or modify this File under the following licensing terms.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Marvell nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Armada7040Lib
+ FILE_GUID = 3f29b642-4a49-4dfd-8f4a-205dd38432bb
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = ArmPlatformLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ ArmPkg/ArmPkg.dec
+ ArmPlatformPkg/ArmPlatformPkg.dec
+ Platform/Marvell/Marvell.dec
+
+[LibraryClasses]
+ ArmLib
+ ComPhyLib
+ DebugLib
+ MemoryAllocationLib
+ MppLib
+ UtmiPhyLib
+
+[Sources.common]
+ Armada70x0Lib.c
+ Armada70x0LibMem.c
+
+[Sources.AArch64]
+ AArch64/ArmPlatformHelper.S
+
+[FixedPcd]
+ gArmTokenSpaceGuid.PcdSystemMemoryBase
+ gArmTokenSpaceGuid.PcdSystemMemorySize
+
+ gArmTokenSpaceGuid.PcdArmPrimaryCoreMask
+ gArmTokenSpaceGuid.PcdArmPrimaryCore
+
+[Ppis]
+ gArmMpCoreInfoPpiGuid
diff --git a/Platform/Marvell/Armada/Library/Armada70x0Lib/Armada70x0LibMem.c b/Platform/Marvell/Armada/Library/Armada70x0Lib/Armada70x0LibMem.c
new file mode 100644
index 0000000000..74c99568f7
--- /dev/null
+++ b/Platform/Marvell/Armada/Library/Armada70x0Lib/Armada70x0LibMem.c
@@ -0,0 +1,93 @@
+/*******************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#include <Base.h>
+#include <Library/ArmPlatformLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+// The total number of descriptors, including the final "end-of-table" descriptor.
+#define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS 16
+
+// DDR attributes
+#define DDR_ATTRIBUTES_CACHED ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_BACK
+#define DDR_ATTRIBUTES_UNCACHED ARM_MEMORY_REGION_ATTRIBUTE_UNCACHED_UNBUFFERED
+
+/**
+ Return the Virtual Memory Map of your platform
+
+ This Virtual Memory Map is used by MemoryInitPei Module to initialize the MMU on your platform.
+
+ @param[out] VirtualMemoryMap Array of ARM_MEMORY_REGION_DESCRIPTOR describing a Physical-to-
+ Virtual Memory mapping. This array must be ended by a zero-filled
+ entry
+
+**/
+VOID
+ArmPlatformGetVirtualMemoryMap (
+ IN ARM_MEMORY_REGION_DESCRIPTOR** VirtualMemoryMap
+ )
+{
+ ARM_MEMORY_REGION_DESCRIPTOR *VirtualMemoryTable;
+ UINTN Index = 0;
+
+ ASSERT (VirtualMemoryMap != NULL);
+
+ VirtualMemoryTable = (ARM_MEMORY_REGION_DESCRIPTOR*)AllocatePages(EFI_SIZE_TO_PAGES (sizeof(ARM_MEMORY_REGION_DESCRIPTOR) * MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS));
+ if (VirtualMemoryTable == NULL) {
+ return;
+ }
+
+ // DDR
+ VirtualMemoryTable[Index].PhysicalBase = PcdGet64 (PcdSystemMemoryBase);
+ VirtualMemoryTable[Index].VirtualBase = PcdGet64 (PcdSystemMemoryBase);
+ VirtualMemoryTable[Index].Length = PcdGet64 (PcdSystemMemorySize);
+ VirtualMemoryTable[Index].Attributes = DDR_ATTRIBUTES_CACHED;
+
+ // Configuration space 0xF000_0000 - 0xFFFF_FFFF
+ VirtualMemoryTable[++Index].PhysicalBase = 0xF0000000;
+ VirtualMemoryTable[Index].VirtualBase = 0xF0000000;
+ VirtualMemoryTable[Index].Length = 0x10000000;
+ VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE;
+
+ // End of Table
+ VirtualMemoryTable[++Index].PhysicalBase = 0;
+ VirtualMemoryTable[Index].VirtualBase = 0;
+ VirtualMemoryTable[Index].Length = 0;
+ VirtualMemoryTable[Index].Attributes = 0;
+
+ ASSERT((Index + 1) <= MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS);
+
+ *VirtualMemoryMap = VirtualMemoryTable;
+}
diff --git a/Platform/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.c b/Platform/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.c
new file mode 100644
index 0000000000..d671b6adc1
--- /dev/null
+++ b/Platform/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.c
@@ -0,0 +1,335 @@
+/** @file
+ Implement EFI RealTimeClock runtime services via RTC Lib.
+
+ Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
+ Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
+ Copyright (c) 2017, Marvell International Ltd. All rights reserved.<BR>
+
+ 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.
+
+**/
+/**
+ Derived from:
+ ArmPlatformPkg/Library/PL031RealTimeClockLib/PL031RealTimeClockLib.c
+
+**/
+
+#include <PiDxe.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/TimeBaseLib.h>
+#include <Library/IoLib.h>
+#include <Library/MvHwDescLib.h>
+#include <Library/RealTimeClockLib.h>
+#include <Library/TimerLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Protocol/RealTimeClock.h>
+#include "RealTimeClockLib.h"
+
+DECLARE_A7K8K_RTC_TEMPLATE;
+STATIC EFI_EVENT mRtcVirtualAddrChangeEvent;
+STATIC UINTN mArmadaRtcBase;
+
+/**
+ According to errata FE-3124064, write to RTC TIME RTC_ALARMx registers
+ may fail. As a workaround, before actual writing to those registers,
+ issue a dummy write of 0x0 twice to RTC Status register.
+ Also, according to the datasheet, the OS should wait 5us after every
+ register write to the RTC hard macro, so that the required update
+ can occur without holding off the system bus.
+**/
+STATIC
+VOID
+RtcDelayedWrite (
+ IN UINT32 Offset,
+ IN UINT32 Value
+ )
+{
+ MmioWrite32 (mArmadaRtcBase + RTC_STATUS_REG, 0);
+ MmioWrite32 (mArmadaRtcBase + RTC_STATUS_REG, 0);
+ MmioWrite32 (mArmadaRtcBase + Offset, Value);
+ MicroSecondDelay (5);
+}
+
+/**
+ Returns the current time and date information, and the time-keeping capabilities
+ of the hardware platform.
+
+ @param Time A pointer to storage to receive a snapshot of the current time.
+ @param Capabilities An optional pointer to a buffer to receive the real time clock
+ device's capabilities.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER Time is NULL.
+ @retval EFI_DEVICE_ERROR The time could not be retrieved due to hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+LibGetTime (
+ OUT EFI_TIME *Time,
+ OUT EFI_TIME_CAPABILITIES *Capabilities
+ )
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ UINT32 RegVal;
+
+ RegVal = MmioRead32 (mArmadaRtcBase + RTC_TIME_REG);
+
+ // Convert from internal 32-bit time to UEFI time
+ EpochToEfiTime (RegVal, Time);
+
+ Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE;
+ Time->Daylight = 0;
+
+ return Status;
+}
+
+/**
+ Sets the current local time and date information.
+
+ @param Time A pointer to the current time.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER A time field is out of range.
+ @retval EFI_DEVICE_ERROR The time could not be set due due to hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+LibSetTime (
+ IN EFI_TIME *Time
+ )
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ UINT32 EpochSeconds;
+
+ // Check the input parameters are within the range specified by UEFI
+ if (!IsTimeValid (Time)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Convert time to raw seconds
+ EpochSeconds = EfiTimeToEpoch (Time);
+
+ // Issue delayed write to time register
+ RtcDelayedWrite (RTC_TIME_REG, EpochSeconds);
+
+ return Status;
+}
+
+/**
+ Returns the current wakeup alarm clock setting.
+
+ @param Enabled Indicates if the alarm is currently enabled or disabled.
+ @param Pending Indicates if the alarm signal is pending and requires acknowledgement.
+ @param Time The current alarm setting.
+
+ @retval EFI_SUCCESS The alarm settings were returned.
+ @retval EFI_INVALID_PARAMETER Any parameter is NULL.
+ @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to a hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+LibGetWakeupTime (
+ OUT BOOLEAN *Enabled,
+ OUT BOOLEAN *Pending,
+ OUT EFI_TIME *Time
+ )
+{
+ UINT32 WakeupSeconds;
+
+ *Enabled = MmioRead32 (mArmadaRtcBase + RTC_IRQ_2_CONFIG_REG) & RTC_IRQ_ALARM_EN;
+
+ *Pending = MmioRead32 (mArmadaRtcBase + RTC_IRQ_STATUS_REG) & RTC_IRQ_ALARM_MASK;
+ // Ack pending alarm
+ if (Pending) {
+ MmioWrite32 (mArmadaRtcBase + RTC_IRQ_STATUS_REG, RTC_IRQ_ALARM_MASK);
+ }
+
+ WakeupSeconds = MmioRead32 (mArmadaRtcBase + RTC_ALARM_2_REG);
+ EpochToEfiTime (WakeupSeconds, Time);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Sets the system wakeup alarm clock time.
+
+ @param Enabled Enable or disable the wakeup alarm.
+ @param Time If Enable is TRUE, the time to set the wakeup alarm for.
+
+ @retval EFI_SUCCESS If Enable is TRUE, then the wakeup alarm was enabled. If
+ Enable is FALSE, then the wakeup alarm was disabled.
+ @retval EFI_INVALID_PARAMETER A time field is out of range.
+ @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a hardware error.
+ @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform.
+
+**/
+EFI_STATUS
+EFIAPI
+LibSetWakeupTime (
+ IN BOOLEAN Enabled,
+ OUT EFI_TIME *Time
+ )
+{
+ UINT32 WakeupSeconds;
+
+ // Convert time to raw seconds
+ WakeupSeconds = EfiTimeToEpoch (Time);
+
+ // Issue delayed write to alarm register
+ RtcDelayedWrite (RTC_ALARM_2_REG, WakeupSeconds);
+
+ if (Enabled) {
+ MmioWrite32 (mArmadaRtcBase + RTC_IRQ_2_CONFIG_REG, RTC_IRQ_ALARM_EN);
+ } else {
+ MmioWrite32 (mArmadaRtcBase + RTC_IRQ_2_CONFIG_REG, 0);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This is the declaration of an EFI image entry point. This can be the entry point to an application
+ written to this specification, an EFI boot service driver, or an EFI runtime driver.
+
+ @param ImageHandle Handle that identifies the loaded image.
+ @param SystemTable System Table for this image.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+LibRtcInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ MVHW_RTC_DESC *Desc = &mA7k8kRtcDescTemplate;
+ UINT8 *RtcDeviceTable, Index;
+ EFI_HANDLE Handle;
+ EFI_STATUS Status;
+
+ // Pick RTC device and initialize its data
+ RtcDeviceTable = (UINT8 *) PcdGetPtr (PcdRtcEnabled);
+ if (RtcDeviceTable == NULL) {
+ DEBUG ((DEBUG_ERROR, "RTC: Missing PcdRtcEnabled\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Initialize only first of enabled controllers
+ for (Index = 0; Index < PcdGetSize (PcdRtcEnabled); Index++) {
+ if (MVHW_DEV_ENABLED (Rtc, Index)) {
+ DEBUG ((DEBUG_ERROR, "RTC: Initialize controller %d\n", Index));
+ mArmadaRtcBase = Desc->RtcBaseAddresses[Index];
+ break;
+ }
+ }
+
+ // Check if any of the controllers can be initialized
+ if (mArmadaRtcBase == 0) {
+ DEBUG ((DEBUG_ERROR, "RTC: None of controllers enabled\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Declare the controller as EFI_MEMORY_RUNTIME
+ Status = gDS->AddMemorySpace (
+ EfiGcdMemoryTypeMemoryMappedIo,
+ mArmadaRtcBase,
+ Desc->RtcMemSize[Index],
+ EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "RTC: Failed to add memory space\n"));
+ return Status;
+ }
+
+ Status = gDS->SetMemorySpaceAttributes (
+ mArmadaRtcBase,
+ Desc->RtcMemSize[Index],
+ EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "RTC: Failed to set memory attributes\n"));
+ goto ErrSetMem;
+ }
+
+ /* Update RTC-MBUS bridge timing parameters */
+ MmioAndThenOr32 (
+ mArmadaRtcBase + RTC_BRIDGE_TIMING_CTRL1_REG_OFFS,
+ ~RTC_READ_OUTPUT_DELAY_MASK,
+ RTC_READ_OUTPUT_DELAY_DEFAULT
+ );
+
+ // Install the protocol
+ Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiRealTimeClockArchProtocolGuid,
+ NULL,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "RTC: Failed to install the protocol\n"));
+ goto ErrSetMem;
+ }
+
+ // Register for the virtual address change event
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ LibRtcVirtualNotifyEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mRtcVirtualAddrChangeEvent
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "RTC: Failed to register virtual address change event\n"));
+ goto ErrEvent;
+ }
+
+ return Status;
+
+ErrEvent:
+ gBS->UninstallProtocolInterface (Handle, &gEfiRealTimeClockArchProtocolGuid, NULL);
+ErrSetMem:
+ gDS->RemoveMemorySpace (mArmadaRtcBase, Desc->RtcMemSize[Index]);
+
+ return Status;
+}
+
+
+/**
+ Fixup internal data so that EFI can be call in virtual mode.
+ Call the passed in Child Notify event and convert any pointers in
+ lib to virtual mode.
+
+ @param[in] Event The Event that is being processed
+ @param[in] Context Event Context
+**/
+VOID
+EFIAPI
+LibRtcVirtualNotifyEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // Only needed if you are going to support the OS calling RTC functions in virtual mode.
+ // You will need to call EfiConvertPointer (). To convert any stored physical addresses
+ // to virtual address. After the OS transistions to calling in virtual mode, all future
+ // runtime calls will be made in virtual mode.
+ //
+ EfiConvertPointer (0x0, (VOID**)&mArmadaRtcBase);
+}
diff --git a/Platform/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.h b/Platform/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.h
new file mode 100644
index 0000000000..922f959239
--- /dev/null
+++ b/Platform/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.h
@@ -0,0 +1,50 @@
+/********************************************************************************
+Copyright (C) 2017 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#ifndef __RTCLIB_H__
+#define __RTCLIB_H__
+
+/* Armada 70x0 SoC registers */
+#define RTC_STATUS_REG 0x0
+#define RTC_TIME_REG 0xC
+#define RTC_IRQ_2_CONFIG_REG 0x8
+#define RTC_IRQ_ALARM_EN 0x1
+#define RTC_ALARM_2_REG 0x14
+#define RTC_BRIDGE_TIMING_CTRL1_REG_OFFS 0x84
+#define RTC_IRQ_STATUS_REG 0x90
+#define RTC_IRQ_ALARM_MASK 0x1
+#define RTC_READ_OUTPUT_DELAY_MASK 0xFFFF
+#define RTC_READ_OUTPUT_DELAY_DEFAULT 0x1F
+
+#endif /* __RTCLIB_H__ */
diff --git a/Platform/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.inf b/Platform/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.inf
new file mode 100644
index 0000000000..01c25f53b7
--- /dev/null
+++ b/Platform/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.inf
@@ -0,0 +1,52 @@
+#/** @file
+#
+# Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
+# Copyright (c) 2017, Marvell International Ltd. All rights reserved.<BR>
+#
+# 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.
+#
+#**/
+#/**
+# Derived from:
+# ArmPlatformPkg/Library/PL031RealTimeClockLib/PL031RealTimeClockLib.inf
+#
+#**/
+
+
+[Defines]
+ INF_VERSION = 0x00010019
+ BASE_NAME = ArmadaRealTimeClockLib
+ FILE_GUID = fa81e889-045b-4c96-9093-742554fd0588
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = RealTimeClockLib
+
+[Sources.common]
+ RealTimeClockLib.c
+
+[Packages]
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Platform/Marvell/Marvell.dec
+
+[LibraryClasses]
+ DebugLib
+ DxeServicesTableLib
+ IoLib
+ PcdLib
+ TimeBaseLib
+ TimerLib
+ UefiRuntimeLib
+
+[Guids]
+ gEfiEventVirtualAddressChangeGuid
+
+[Pcd]
+ gMarvellTokenSpaceGuid.PcdRtcEnabled
diff --git a/Platform/Marvell/Documentation/Drivers/EepromDriver.txt b/Platform/Marvell/Documentation/Drivers/EepromDriver.txt
new file mode 100644
index 0000000000..d3b3b9f0d0
--- /dev/null
+++ b/Platform/Marvell/Documentation/Drivers/EepromDriver.txt
@@ -0,0 +1,96 @@
+1. Introduction
+---------------
+**MvEeprom** driver creates MARVELL_EEPROM_PROTOCOL, which
++is used for managing eeprom.
+
+2. MvEeprom driver design
+-------------------------
+Every I2C device driver should implement EFI_DRIVER_BINDING_PROTOCOL and
+consume EFI_I2C_IO_PROTOCOL for transactions on I2C bus. MvEeprom driver
+additionally implements MARVELL_EEPROM_PROTOCOL.
+
+ 2.1 EFI_DRIVER_BINDING_PROTOCOL
+ -------------------------------
+ Driver Binding protocol is extensively covered in UEFI documentation, as
+ it is not specific to I2C stack. The only difference is that Supported()
+ function should check if EFI_I2C_IO_PROTOCOL provides valid EFI_GUID and
+ DeviceIndex values.
+ Excerpt from MvEepromSupported():
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiI2cIoProtocolGuid,
+ (VOID **) &TmpI2cIo,
+ gImageHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR(Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ /* get EEPROM devices' addresses from PCD */
+ EepromAddresses = PcdGetPtr (PcdEepromI2cAddresses);
+ if (EepromAddresses == 0) {
+ Status = EFI_UNSUPPORTED;
+ goto out;
+ }
+
+ Status = EFI_UNSUPPORTED;
+ for (i = 0; EepromAddresses[i] != '\0'; i++) {
+ /* I2C guid must fit and valid DeviceIndex must be provided */
+ if (CompareGuid(TmpI2cIo->DeviceGuid, &I2cGuid) &&
+ TmpI2cIo->DeviceIndex == EepromAddresses[i]) {
+ DEBUG((DEBUG_INFO, "A8kEepromSupported: attached to EEPROM device\n"));
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+
+ 2.2 EFI_I2C_IO_PROTOCOL
+ -----------------------
+ This protocol is provided by generic I2C stack. Multiple drivers can use IO
+ protocol at once, as queueing is implemented.
+
+ QueueRequest is a routine that queues an I2C transaction to the I2C
+ controller for execution on the I2C bus.
+
+ 2.3 MARVELL_EEPROM_PROTOCOL
+ -----------------------
+ typedef struct _MARVELL_EEPROM_PROTOCOL MARVELL_EEPROM_PROTOCOL;
+
+ #define EEPROM_READ 0x1
+ #define EEPROM_WRITE 0x0
+ typedef
+ EFI_STATUS
+ (EFIAPI *EFI_EEPROM_TRANSFER) (
+ IN CONST MARVELL_EEPROM_PROTOCOL *This,
+ IN UINT16 Address,
+ IN UINT32 Length,
+ IN UINT8 *Buffer,
+ IN UINT8 Operation
+ );
+
+ struct _MARVELL_EEPROM_PROTOCOL {
+ EFI_EEPROM_TRANSFER Transfer;
+ UINT8 Identifier;
+ };
+
+3. Adding new I2C slave device drivers
+--------------------------------------
+In order to support I2C slave device other than EEPROM, new driver should
+be created. Required steps follow.
+
+ 1. Create driver directory (Platform/Marvell/Drivers/I2c/Devices/...).
+ 2. Create stubs of .inf and .c files (MvEeprom files are a reference),
+ include .inf file in platform .dsc and .fdf files.
+ 3. Implement EFI_DRIVER_BINDING_PROTOCOL - Start(), Stop(), Supported()
+ functions' implementation is a must. EFI_DRIVER_BINDING_PROTOCOL
+ should be installed at driver's entry point.
+ 4. Add I2C address of device to PcdI2cSlaveAddresses in .dsc file.
+ 5. Test available EFI_I2C_IO_PROTOCOLs in Supported() - find instance
+ with valid GUID and DeviceIndex (I2C slave address).
+ 6. Open EFI_I2C_IO_PROTOCOL for usage in Start(). After that, QueueRequest
+ function should be available.
+ 7. Implement core functionality of driver (using QueueRequest to access I2C).
+ 8. (not mandatory) Produce/consume additional protocols.
diff --git a/Platform/Marvell/Documentation/Drivers/I2cDriver.txt b/Platform/Marvell/Documentation/Drivers/I2cDriver.txt
new file mode 100644
index 0000000000..2f890de3db
--- /dev/null
+++ b/Platform/Marvell/Documentation/Drivers/I2cDriver.txt
@@ -0,0 +1,64 @@
+1. Introduction
+---------------
+**MvI2cDxe** is a driver supporting I2C controller on Marvell SOCs boards.
+It is connected through protocols to generic UEFI I2C stack, which exposes
+IO functionality to drivers of specific devices on I2C bus.
+
+2. MvI2cDxe driver design
+--------------------------
+MvI2cDxe produces several protocols from generic I2C stack:
+ - EFI_I2C_MASTER_PROTOCOL,
+ - EFI_I2C_ENUMERATE_PROTOCOL,
+ - EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL
+ - general-purpose EFI_DRIVER_BINDING_PROTOCOL.
+
+ 2.1 EFI_I2C_MASTER_PROTOCOL
+ ---------------------------
+ This is the most important protocol produced by MvI2cDxe. Following functions
+ are implemented:
+
+ ///
+ /// Reset the I2C host controller.
+ ///
+ EFI_I2C_MASTER_PROTOCOL_RESET Reset;
+
+ ///
+ /// Start an I2C transaction in master mode on the host controller.
+ ///
+ EFI_I2C_MASTER_PROTOCOL_START_REQUEST StartRequest;
+
+ StartRequest and Reset functions are used by I2cHost.
+ These should **not** be used by I2C device drivers - required
+ synchronization is not provided. Instead, members of EFI_I2C_IO_PROTOCOL
+ should be used.
+
+ 2.2 EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL
+ -------------------------------------------------
+ The only function exposed via this protocol is MvI2cEnableConf. It is
+ required by I2C stack in order to allow changing I2C bus configuration from
+ device drivers.
+
+ 2.3 EFI_I2C_ENUMERATE_PROTOCOL
+ ------------------------------
+ Provides Enumerate function, which is used by I2cBus code as an iterator over
+ devices on I2C bus.
+
+ typedef
+ EFI_STATUS
+ (EFIAPI *EFI_I2C_ENUMERATE_PROTOCOL_ENUMERATE) (
+ IN CONST EFI_I2C_ENUMERATE_PROTOCOL *This,
+ IN OUT CONST EFI_I2C_DEVICE **Device
+ );
+
+ ///
+ /// Traverse the set of I2C devices on an I2C bus. This routine
+ /// returns the next I2C device on an I2C bus.
+ ///
+ EFI_I2C_ENUMERATE_PROTOCOL_ENUMERATE Enumerate;
+
+ MvI2cDevice creates EFI_I2C_DEVICE structure for every device on the bus.
+ Due to the fact that hardware-based I2C enumeration isn't safe, information
+ about attached devices should be provided through PCDs. After EFI_I2C_DEVICE
+ structure is created and filled properly, it is returned to I2cBus. It is
+ followed by attachment of I2C device driver.
+
diff --git a/Platform/Marvell/Documentation/Drivers/SpiDriver.txt b/Platform/Marvell/Documentation/Drivers/SpiDriver.txt
new file mode 100644
index 0000000000..42b5e3ce3b
--- /dev/null
+++ b/Platform/Marvell/Documentation/Drivers/SpiDriver.txt
@@ -0,0 +1,116 @@
+1. Introduction
+---------------
+**SpiDxe** driver implements MARVELL_SPI_MASTER_PROTOCOL in order to manage SPI
+controller on Marvell A8k boards. It exposes below functionalities:
+ - create and setup SPI slaves
+ - raw transfer over SPI bus
+
+2. SpiDxe driver design
+-----------------------
+
+ 2.1 MARVELL_SPI_MASTER_PROTOCOL
+ -----------------------
+ First member of SPI_MASTER protocol is Init function, implemented for SPI
+ master controller initialization.
+
+ ->Init()
+
+ //
+ //Initializes the host controller to execute SPI commands.
+ //
+
+ param[IN] This Pointer to the MARVELL_SPI_MASTER_PROTOCOL instance
+
+ return EFI_SUCCESS Opcode initialization on the SPI host
+ controller completed.
+ return EFI_ACCESS_DENIED The SPI configuration interface is
+ locked.
+ return EFI_OUT_OF_RESOURCES Not enough resource available to
+ initialize the device.
+ return EFI_DEVICE_ERROR Device error, operation failed.
+
+ ********
+
+ SPI devices (slaves) do not support any kind of automatic discovery or
+ enumaration, so every device needs manual configuration, which may be done
+ with SetupDevice function.
+
+ ->SetupDevice()
+
+ //
+ //Allocate and zero all fields in the SPI_DEVICE struct. Set the chip
+ //select, max frequency and transfer mode supported by slave device.
+ //
+
+ param[IN] Cs Chip select ID of the slave chip.
+ param[IN] MaxFreq Maximum SCK rate in Hz.
+ param[IN] Mode Clock polarity and clock phase.
+
+ return *SPI_DEVICE Pointer to new allocated struct SPI_DEVICE.
+ return NULL NULL pointer if any eroor occured.
+
+ ********
+
+ Developers have to destroy all created SPI device structs (with FreeDevice
+ function) in order to prevent from memory leak.
+
+ ->FreeDevice()
+
+ //
+ //Free any memory associated with a SPI device.
+ //
+
+ param[in] SpiDev Pointer to the SPI_DEVICE struct.
+
+ return EFI_SUCCESS Memory fried succesfully.
+ return EFI_DEVICE_ERROR Device error, operation failed.
+
+ ********
+
+ Transfer function allows write/read raw bytes over SPI bus.
+
+ ->Transfer()
+
+ //
+ //Perform transfer over SPI bus
+ //
+ param[in] This Pointer to the MARVELL_SPI_MASTER_PROTOCOL
+ instance.
+ param[in] Slave Pointer to the SPI_DEVICE struct.
+ param[in] DataByteCount Number of bytes in the data portion of
+ the SPI cycle.
+ param[in] DataOut Pointer to caller-allocated buffer
+ containing the data to send.
+ param[out] DataIn Pointer to caller-allocated buffer
+ where received data will be placed.
+ param[in] Flag Flags which indicate state of CS line
+ during/after transfer (see file
+ Drivers/Spi/Devices/A8kSpiFlash.h)
+
+ return EFI_SUCCESS Memory fried succesfully.
+ return EFI_DEVICE_ERROR Device error, operation failed.
+
+ *********
+
+ When working with SPI devices it is often necessary to perform "command and
+ address" transactions. It may be done via ReadWrite function.
+
+ ->ReadWrite()
+
+ //
+ //Perform two steps transactions. First write Command, then read/write
+ //buffer
+ //
+
+ param[in] This Pointer to the MARVELL_SPI_MASTER_PROTOCOL
+ instance.
+ param[in] Slave Pointer to the SPI_DEVICE struct.
+ param[in] Cmd Pointer to caller-allocated buffer
+ containing the command to send.
+ param[in] CmdSize Size of command (in bytes).
+ param[in] DataOut Pointer to caller-allocated buffer
+ containing the data to send.
+ param[out] DataIn Pointer to caller-allocated buffer
+ where received data will be placed.
+ param[in] DataSize Number of bytes in the data portion of
+ the SPI cycle.
diff --git a/Platform/Marvell/Documentation/PortingGuide/ComPhy.txt b/Platform/Marvell/Documentation/PortingGuide/ComPhy.txt
new file mode 100644
index 0000000000..a96015e152
--- /dev/null
+++ b/Platform/Marvell/Documentation/PortingGuide/ComPhy.txt
@@ -0,0 +1,45 @@
+COMPHY configuration
+---------------------------
+In order to configure ComPhy library, following PCDs are available:
+
+ gMarvellTokenSpaceGuid.PcdComPhyDevices
+
+This array indicates, which ones of the ComPhy chips defined in
+MVHW_COMPHY_DESC template will be configured.
+
+Every ComPhy PCD has <Num> part where <Num> stands for chip ID (order is not
+important, but configuration will be set for first PcdComPhyChipCount chips).
+
+Every chip has 3 ComPhy PCDs and three of them comprise per-board lanes
+settings for this chip. Their format is unicode string, containing settings
+for up to 10 lanes. Setting for each one is separated with semicolon.
+These PCDs together describe outputs of PHY integrated in simple cihp.
+Below is example for the first chip (Chip0).
+
+ gMarvellTokenSpaceGuid.PcdChip0ComPhyTypes
+
+Unicode string indicating PHY types. Currently supported are:
+
+{ L"unconnected", L"PCIE0", L"PCIE1", L"PCIE2", L"PCIE3",
+L"SATA0", L"SATA1", L"SATA2", L"SATA3", L"SGMII0",
+L"SGMII1", L"SGMII2", L"SGMII3",
+L"USB3_HOST0", L"USB3_HOST1", L"USB3_DEVICE",
+L"RXAUI0", L"RXAUI1", L"SFI" }
+
+ gMarvellTokenSpaceGuid.PcdChip0ComPhySpeeds
+
+Indicates PHY speeds in MHz. Currently supported are:
+
+{ 1250, 1500, 2500, 3000, 3125, 5000, 6000, 6250, 10310 }
+
+ gMarvellTokenSpaceGuid.PcdChip0ComPhyInvFlags
+
+Indicates lane polarity invert.
+
+Example
+-------
+ #ComPhy
+ gMarvellTokenSpaceGuid.PcdComPhyDevices|{ 0x1 }
+ gMarvellTokenSpaceGuid.PcdChip0ComPhyTypes|L"SGMII1;USB3_HOST0;SFI;SATA1;USB3_HOST1;PCIE2"
+ gMarvellTokenSpaceGuid.PcdChip0ComPhySpeeds|L"1250;5000;10310;5000;5000;5000"
+
diff --git a/Platform/Marvell/Documentation/PortingGuide/I2c.txt b/Platform/Marvell/Documentation/PortingGuide/I2c.txt
new file mode 100644
index 0000000000..020ffb4f1b
--- /dev/null
+++ b/Platform/Marvell/Documentation/PortingGuide/I2c.txt
@@ -0,0 +1,20 @@
+1. Porting I2C driver to a new SOC
+----------------------------------
+In order to enable driver on a new platform, following steps need to be taken:
+ - add following line to .dsc file:
+ Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf
+ - add following line to .fdf file:
+ INF Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf
+ - add PCDs with relevant values to .dsc file:
+ gMarvellTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x50, 0x57 }
+ (addresses of I2C slave devices on bus)
+ gMarvellTokenSpaceGuid.PcdI2cSlaveBuses|{ 0x0, 0x0 }
+ (buses to which accoring slaves are attached)
+ gMarvellTokenSpaceGuid.PcdI2cBusCount|2
+ (number of SoC's I2C buses)
+ gMarvellTokenSpaceGuid.PcdI2cBaseAddresses|L"0xF2701000;0xF2701100"
+ (base addresses of I2C controller buses)
+ gMarvellTokenSpaceGuid.PcdI2cClockFrequency|200000000
+ (I2C host controller clock frequency)
+ gMarvellTokenSpaceGuid.PcdI2cBaudRate|100000
+ (baud rate used in I2C transmission)
diff --git a/Platform/Marvell/Documentation/PortingGuide/Mdio.txt b/Platform/Marvell/Documentation/PortingGuide/Mdio.txt
new file mode 100644
index 0000000000..c341d9e8d0
--- /dev/null
+++ b/Platform/Marvell/Documentation/PortingGuide/Mdio.txt
@@ -0,0 +1,7 @@
+MDIO driver configuration
+-------------------------
+MDIO driver provides access to network PHYs' registers via MARVELL_MDIO_READ and
+MARVELL_MDIO_WRITE functions (MARVELL_MDIO_PROTOCOL). Following PCD is required:
+
+ gMarvellTokenSpaceGuid.PcdMdioBaseAddress
+ (base address of SMI management register)
diff --git a/Platform/Marvell/Documentation/PortingGuide/Mpp.txt b/Platform/Marvell/Documentation/PortingGuide/Mpp.txt
new file mode 100644
index 0000000000..68f0e9d179
--- /dev/null
+++ b/Platform/Marvell/Documentation/PortingGuide/Mpp.txt
@@ -0,0 +1,48 @@
+MPP configuration
+-----------------
+Multi-Purpose Ports (MPP) are configurable through platform PCDs.
+In order to set desired pin multiplexing, .dsc file needs to be modified.
+(Platform/Marvell/Armada/{platform_name}.dsc - please refer to
+Documentation/Build.txt for currently supported {platftorm_name} )
+Following PCDs are available:
+
+ gMarvellTokenSpaceGuid.PcdMppChipCount
+
+Indicates how many different chips are placed on board. So far up to 4 chips
+are supported.
+
+Every MPP PCD has <Num> part where
+ <Num> stands for chip ID (order is not important, but configuration will be
+ set for first PcdMppChipCount chips).
+
+Below is example for the first chip (Chip0).
+
+ gMarvellTokenSpaceGuid.PcdChip0MppReverseFlag
+
+Indicates that register order is reversed. (Needs to be used only for AP806-Z1)
+
+ gMarvellTokenSpaceGuid.PcdChip0MppBaseAddress
+
+This is base address for MPP configuration register.
+
+ gMarvellTokenSpaceGuid.PcdChip0MppPinCount
+
+Defines how many MPP pins are available.
+
+ gMarvellTokenSpaceGuid.PcdChip0MppSel0
+ gMarvellTokenSpaceGuid.PcdChip0MppSel1
+ gMarvellTokenSpaceGuid.PcdChip0MppSel2
+
+This registers defines functions of 10 pins in ascending order.
+
+Examples
+--------
+#APN806-A0 MPP SET
+ gMarvellTokenSpaceGuid.PcdChip0MppReverseFlag|FALSE
+ gMarvellTokenSpaceGuid.PcdChip0MppBaseAddress|0xF06F4000
+ gMarvellTokenSpaceGuid.PcdChip0MppRegCount|3
+ gMarvellTokenSpaceGuid.PcdChip0MppSel0|{ 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0 }
+ gMarvellTokenSpaceGuid.PcdChip0MppSel1|{ 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+
+Set pin 6 and 7 to 0xa function:
+ gMarvellTokenSpaceGuid.PcdChip0MppSel0|{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0xa, 0x0, 0x0 }
diff --git a/Platform/Marvell/Documentation/PortingGuide/PciEmulation.txt b/Platform/Marvell/Documentation/PortingGuide/PciEmulation.txt
new file mode 100644
index 0000000000..ec1afbc7bf
--- /dev/null
+++ b/Platform/Marvell/Documentation/PortingGuide/PciEmulation.txt
@@ -0,0 +1,31 @@
+PciEmulation configuration
+--------------------------
+Installation of various NonDiscoverable devices via PciEmulation driver is performed
+via set of PCDs. Following are available:
+
+ gMarvellTokenSpaceGuid.PcdPciEXhci
+
+Indicates, which Xhci devices are used.
+
+ gMarvellTokenSpaceGuid.PcdPciEAhci
+
+Indicates, which Ahci devices are used.
+
+ gMarvellTokenSpaceGuid.PcdPciESdhci
+
+Indicates, which Sdhci devices are used.
+
+All above PCD's correspond to hardware description in a dedicated structure:
+
+STATIC PCI_E_PLATFORM_DESC A70x0PlatDescTemplate
+
+in Platforms/Marvell/PciEmulation/PciEmulation.c file. It comprises device
+count, base addresses, register region size and DMA-coherency type.
+
+Examples
+--------
+Assuming we want to enable second XHCI port and one SDHCI port on Armada
+70x0 board, following needs to be declared:
+
+ gMarvellTokenSpaceGuid.PcdPciEXhci|{ 0x0 0x1 }
+ gMarvellTokenSpaceGuid.PcdPciESdhci|{ 0x1 }
diff --git a/Platform/Marvell/Documentation/PortingGuide/Phy.txt b/Platform/Marvell/Documentation/PortingGuide/Phy.txt
new file mode 100644
index 0000000000..69dae02a3e
--- /dev/null
+++ b/Platform/Marvell/Documentation/PortingGuide/Phy.txt
@@ -0,0 +1,45 @@
+PHY driver configuration
+------------------------
+MvPhyDxe provides basic initialization and status routines for Marvell PHYs.
+Currently only 1512 series PHYs are supported. Following PCDs are required:
+
+ gMarvellTokenSpaceGuid.PcdPhyConnectionTypes
+ (list of values corresponding to PHY_CONNECTION enum)
+ gMarvellTokenSpaceGuid.PcdPhyStartupAutoneg
+ (boolean - if true, driver waits for autonegotiation on startup)
+ gMarvellTokenSpaceGuid.PcdPhyDeviceIds
+ (list of values corresponding to MV_PHY_DEVICE_ID enum)
+
+PHY_CONNECTION enum type is defined as follows:
+
+ typedef enum {
+0 PHY_CONNECTION_RGMII,
+1 PHY_CONNECTION_RGMII_ID,
+2 PHY_CONNECTION_RGMII_TXID,
+3 PHY_CONNECTION_RGMII_RXID,
+4 PHY_CONNECTION_SGMII,
+5 PHY_CONNECTION_RTBI,
+6 PHY_CONNECTION_XAUI,
+7 PHY_CONNECTION_RXAUI
+ } PHY_CONNECTION;
+
+MV_PHY_DEVICE_ID:
+
+ typedef enum {
+0 MV_PHY_DEVICE_1512,
+ } MV_PHY_DEVICE_ID;
+
+It should be extended when adding support for other PHY
+models.
+
+Thus in order to set RGMII for 1st PHY and SGMII for 2nd, PCD should be:
+
+ gMarvellTokenSpaceGuid.PcdPhyConnectionTypes|{ 0x0, 0x4 }
+
+with disabled autonegotiation:
+
+ gMarvellTokenSpaceGuid.PcdPhyStartupAutoneg|FALSE
+
+assuming, that PHY models are 1512:
+
+ gMarvellTokenSpaceGuid.PcdPhyDeviceIds|{ 0x0, 0x0 }
diff --git a/Platform/Marvell/Documentation/PortingGuide/Pp2.txt b/Platform/Marvell/Documentation/PortingGuide/Pp2.txt
new file mode 100644
index 0000000000..c1554a694e
--- /dev/null
+++ b/Platform/Marvell/Documentation/PortingGuide/Pp2.txt
@@ -0,0 +1,59 @@
+Pp2Dxe porting guide
+--------------------
+Pp2Dxe is driver supporting PP2 NIC on Marvell platforms. Following PCDs
+are required to operate:
+
+Number of ports/network interfaces:
+ gMarvellTokenSpaceGuid.PcdPp2NumPorts
+
+Addresses of PHY devices:
+ gMarvellTokenSpaceGuid.PcdPhySmiAddresses
+
+Identificators of PP2 ports:
+ gMarvellTokenSpaceGuid.PcdPp2PortIds
+
+Indexes used in GOP operation:
+ gMarvellTokenSpaceGuid.PcdPp2GopIndexes
+
+Set to 0x1 for always-up interface, 0x0 otherwise:
+ gMarvellTokenSpaceGuid.PcdPp2InterfaceAlwaysUp
+
+Values corresponding to PHY_SPEED enum:
+ gMarvellTokenSpaceGuid.PcdPp2InterfaceSpeed
+
+PHY_SPEED (in Mbps) is defined as follows:
+ typedef enum {
+ 0 NO_SPEED,
+ 1 SPEED_10,
+ 2 SPEED_100,
+ 3 SPEED_1000,
+ 4 SPEED_2500,
+ 5 SPEED_10000
+ } PHY_SPEED;
+
+Base address of shared register space of PP2:
+ gMarvellTokenSpaceGuid.PcdPp2SharedAddress
+
+Spacing between consecutive GMAC register spaces:
+ gMarvellTokenSpaceGuid.PcdPp2GmacDevSize
+
+Base address of GMAC:
+ gMarvellTokenSpaceGuid.PcdPp2GmacBaseAddress
+
+Spacing between consecutive XLG register spaces:
+ gMarvellTokenSpaceGuid.PcdPp2XlgDevSize
+
+Base address of XLG:
+ gMarvellTokenSpaceGuid.PcdPp2XlgBaseAddress
+
+Base address of RFU1:
+ gMarvellTokenSpaceGuid.PcdPp2Rfu1BaseAddress
+
+Base address of SMI:
+ gMarvellTokenSpaceGuid.PcdPp2SmiBaseAddress
+
+TCLK frequency in Hz:
+ gMarvellTokenSpaceGuid.PcdPp2ClockFrequency
+
+GMAC and XLG addresses are computed as follows:
+ address = base_address + dev_size * gop_index
diff --git a/Platform/Marvell/Documentation/PortingGuide/Reset.txt b/Platform/Marvell/Documentation/PortingGuide/Reset.txt
new file mode 100644
index 0000000000..30dec8612b
--- /dev/null
+++ b/Platform/Marvell/Documentation/PortingGuide/Reset.txt
@@ -0,0 +1,7 @@
+MarvellResetSystemLib configuration
+-----------------------------------
+This simple library allows to mask given bits in given reg at UEFI 'reset'
+command call. These variables are configurable through PCDs:
+
+ gMarvellTokenSpaceGuid.PcdResetRegAddress
+ gMarvellTokenSpaceGuid.PcdResetRegMask
diff --git a/Platform/Marvell/Documentation/PortingGuide/Spi.txt b/Platform/Marvell/Documentation/PortingGuide/Spi.txt
new file mode 100644
index 0000000000..be498a66a6
--- /dev/null
+++ b/Platform/Marvell/Documentation/PortingGuide/Spi.txt
@@ -0,0 +1,16 @@
+Spi driver configuration
+------------------------
+Following PCDs are available for configuration of spi driver:
+
+ gMarvellTokenSpaceGuid.PcdSpiClockFrequency
+
+Frequency (in Hz) of SPI clock
+
+ gMarvellTokenSpaceGuid.PcdSpiMaxFrequency
+
+Max SCLK line frequency (in Hz) (max transfer frequency)
+
+ gMarvellTokenSpaceGuid.PcdSpiDefaultMode
+
+default SCLK mode (see SPI_MODE enum in file
+Platform/Marvell/Drivers/Spi/MvSpi.h)
diff --git a/Platform/Marvell/Documentation/PortingGuide/SpiFlash.txt b/Platform/Marvell/Documentation/PortingGuide/SpiFlash.txt
new file mode 100644
index 0000000000..226db4001e
--- /dev/null
+++ b/Platform/Marvell/Documentation/PortingGuide/SpiFlash.txt
@@ -0,0 +1,23 @@
+SpiFlash driver configuration
+-----------------------------
+Folowing PCDs for spi flash driver configuration must be set properly:
+
+ gMarvellTokenSpaceGuid.PcdSpiFlashAddressCycles
+
+Size of SPI flash address in bytes (3 or 4)
+
+ gMarvellTokenSpaceGuid.PcdSpiFlashEraseSize
+
+Size of minimal erase block in bytes
+
+ gMarvellTokenSpaceGuid.PcdSpiFlashPageSize
+
+Size of SPI flash page
+
+ gMarvellTokenSpaceGuid.PcdSpiFlashId
+
+Id of SPI flash
+
+ gMarvellTokenSpaceGuid.PcdSpiFlashPollCmd
+
+Spi flash polling flag
diff --git a/Platform/Marvell/Documentation/PortingGuide/Utmi.txt b/Platform/Marvell/Documentation/PortingGuide/Utmi.txt
new file mode 100644
index 0000000000..cff4843da2
--- /dev/null
+++ b/Platform/Marvell/Documentation/PortingGuide/Utmi.txt
@@ -0,0 +1,35 @@
+UTMI PHY configuration
+----------------------
+In order to configure UTMI, following PCDs are available:
+
+ gMarvellTokenSpaceGuid.PcdUtmiPhyCount
+
+Indicates how many UTMI PHYs are available on platform.
+
+Next four PCDs are in unicode string format containing settings for all devices
+separated with semicolon.
+
+ gMarvellTokenSpaceGuid.PcdUtmiPhyRegUtmiUnit
+
+Indicates base address of the UTMI unit.
+
+ gMarvellTokenSpaceGuid.PcdUtmiPhyRegUsbCfg
+
+Indicates address of USB Configuration register.
+
+ gMarvellTokenSpaceGuid.PcdUtmiPhyRegUtmiCfg
+
+Indicates address of external UTMI configuration.
+
+ gMarvellTokenSpaceGuid.PcdUtmiPhyUtmiPort
+
+Indicates type of the connected USB port.
+
+Example
+-------
+#UtmiPhy
+ gMarvellTokenSpaceGuid.PcdUtmiPhyCount|2
+ gMarvellTokenSpaceGuid.PcdUtmiPhyRegUtmiUnit|L"0xF2580000;0xF2581000"
+ gMarvellTokenSpaceGuid.PcdUtmiPhyRegUsbCfg|L"0xF2440420;0xF2440420"
+ gMarvellTokenSpaceGuid.PcdUtmiPhyRegUtmiCfg|L"0xF2440440;0xF2440444"
+ gMarvellTokenSpaceGuid.PcdUtmiPhyUtmiPort|L"0x0;0x1"
diff --git a/Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.c b/Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.c
new file mode 100644
index 0000000000..d8fd1bfe62
--- /dev/null
+++ b/Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.c
@@ -0,0 +1,292 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#include <Protocol/DriverBinding.h>
+#include <Protocol/I2cIo.h>
+#include <Protocol/Eeprom.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <Pi/PiI2c.h>
+
+#include "MvEeprom.h"
+
+#define I2C_DEVICE_INDEX(bus, address) (((address) & 0xffff) | (bus) << 16)
+
+STATIC CONST EFI_GUID I2cGuid = I2C_GUID;
+
+EFI_DRIVER_BINDING_PROTOCOL gDriverBindingProtocol = {
+ MvEepromSupported,
+ MvEepromStart,
+ MvEepromStop
+};
+
+EFI_STATUS
+EFIAPI
+MvEepromSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status = EFI_UNSUPPORTED;
+ EFI_I2C_IO_PROTOCOL *TmpI2cIo;
+ UINT8 *EepromAddresses;
+ UINT8 *EepromBuses;
+ UINTN i;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiI2cIoProtocolGuid,
+ (VOID **) &TmpI2cIo,
+ gImageHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR(Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ /* get EEPROM devices' addresses from PCD */
+ EepromAddresses = PcdGetPtr (PcdEepromI2cAddresses);
+ EepromBuses = PcdGetPtr (PcdEepromI2cBuses);
+ if (EepromAddresses == 0) {
+ Status = EFI_UNSUPPORTED;
+ DEBUG((DEBUG_INFO, "MvEepromSupported: I2C device found, but it's not EEPROM\n"));
+ goto out;
+ }
+
+ Status = EFI_UNSUPPORTED;
+ for (i = 0; EepromAddresses[i] != '\0'; i++) {
+ /* I2C guid must fit and valid DeviceIndex must be provided */
+ if (CompareGuid(TmpI2cIo->DeviceGuid, &I2cGuid) &&
+ TmpI2cIo->DeviceIndex == I2C_DEVICE_INDEX(EepromBuses[i],
+ EepromAddresses[i])) {
+ DEBUG((DEBUG_INFO, "MvEepromSupported: attached to EEPROM device\n"));
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+
+out:
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiI2cIoProtocolGuid,
+ gImageHandle,
+ ControllerHandle
+ );
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+MvEepromTransfer (
+ IN CONST MARVELL_EEPROM_PROTOCOL *This,
+ IN UINT16 Address,
+ IN UINT32 Length,
+ IN UINT8 *Buffer,
+ IN UINT8 Operation
+ )
+{
+ EFI_I2C_REQUEST_PACKET *RequestPacket;
+ UINTN RequestPacketSize;
+ EFI_STATUS Status = EFI_SUCCESS;
+ EEPROM_CONTEXT *EepromContext = EEPROM_SC_FROM_EEPROM(This);
+ UINT32 BufferLength;
+ UINT32 Transmitted = 0;
+ UINT32 CurrentAddress = Address;
+
+ ASSERT(EepromContext != NULL);
+ ASSERT(EepromContext->I2cIo != NULL);
+
+ RequestPacketSize = sizeof(UINTN) + sizeof (EFI_I2C_OPERATION) * 2;
+ RequestPacket = AllocateZeroPool (RequestPacketSize);
+ if (RequestPacket == NULL)
+ return EFI_OUT_OF_RESOURCES;
+ /* First operation contains address, the second is buffer */
+ RequestPacket->OperationCount = 2;
+ RequestPacket->Operation[0].LengthInBytes = 2;
+ RequestPacket->Operation[0].Buffer = AllocateZeroPool ( RequestPacket->Operation[0].LengthInBytes );
+ if (RequestPacket->Operation[0].Buffer == NULL) {
+ FreePool(RequestPacket);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ RequestPacket->Operation[1].Flags = (Operation == EEPROM_READ ? I2C_FLAG_READ : I2C_FLAG_NORESTART);
+
+ while (Length > 0) {
+ CurrentAddress = Address + Transmitted;
+ BufferLength = (Length <= MAX_BUFFER_LENGTH ? Length : MAX_BUFFER_LENGTH);
+ RequestPacket->Operation[0].Buffer[0] = (CurrentAddress >> 8) & 0xff;
+ RequestPacket->Operation[0].Buffer[1] = CurrentAddress & 0xff;
+ RequestPacket->Operation[1].LengthInBytes = BufferLength;
+ RequestPacket->Operation[1].Buffer = Buffer + Transmitted;
+ Status = EepromContext->I2cIo->QueueRequest(EepromContext->I2cIo, 0, NULL, RequestPacket, NULL);
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "MvEepromTransfer: error %d during transmission\n", Status));
+ break;
+ }
+ Length -= BufferLength;
+ Transmitted += BufferLength;
+ }
+
+ FreePool(RequestPacket->Operation[0].Buffer);
+ FreePool(RequestPacket);
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+MvEepromStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ EEPROM_CONTEXT *EepromContext;
+
+ EepromContext = AllocateZeroPool (sizeof(EEPROM_CONTEXT));
+ if (EepromContext == NULL) {
+ DEBUG((DEBUG_ERROR, "MvEeprom: allocation fail\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ EepromContext->ControllerHandle = ControllerHandle;
+ EepromContext->Signature = EEPROM_SIGNATURE;
+ EepromContext->EepromProtocol.Transfer = MvEepromTransfer;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiI2cIoProtocolGuid,
+ (VOID **) &EepromContext->I2cIo,
+ gImageHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "MvEeprom: failed to open I2cIo\n"));
+ FreePool(EepromContext);
+ return EFI_UNSUPPORTED;
+ }
+
+ EepromContext->EepromProtocol.Identifier = EepromContext->I2cIo->DeviceIndex;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ControllerHandle,
+ &gMarvellEepromProtocolGuid, &EepromContext->EepromProtocol,
+ NULL
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "MvEeprom: failed to install EEPROM protocol\n"));
+ goto fail;
+ }
+
+ return Status;
+
+fail:
+ FreePool(EepromContext);
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiI2cIoProtocolGuid,
+ gImageHandle,
+ ControllerHandle
+ );
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+MvEepromStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
+ )
+{
+ MARVELL_EEPROM_PROTOCOL *EepromProtocol;
+ EFI_STATUS Status;
+ EEPROM_CONTEXT *EepromContext;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gMarvellEepromProtocolGuid,
+ (VOID **) &EepromProtocol,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ EepromContext = EEPROM_SC_FROM_EEPROM(EepromProtocol);
+
+ gBS->UninstallMultipleProtocolInterfaces (
+ &ControllerHandle,
+ &gMarvellEepromProtocolGuid, &EepromContext->EepromProtocol,
+ &gEfiDriverBindingProtocolGuid, &gDriverBindingProtocol,
+ NULL
+ );
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiI2cIoProtocolGuid,
+ gImageHandle,
+ ControllerHandle
+ );
+ FreePool(EepromContext);
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+MvEepromInitialise (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiDriverBindingProtocolGuid, &gDriverBindingProtocol,
+ NULL
+ );
+ return Status;
+}
diff --git a/Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.h b/Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.h
new file mode 100644
index 0000000000..b1af645050
--- /dev/null
+++ b/Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.h
@@ -0,0 +1,103 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#ifndef __MV_EEPROM_H__
+#define __MV_EEPROM_H__
+
+#include <Uefi.h>
+
+#define EEPROM_SIGNATURE SIGNATURE_32 ('E', 'E', 'P', 'R')
+
+#define MAX_BUFFER_LENGTH 64
+
+/*
+ * I2C_FLAG_NORESTART is not part of PI spec, it allows to continue
+ * transmission without repeated start operation.
+ * FIXME: This flag is also defined in Drivers/I2c/MvI2cDxe/MvI2cDxe.h
+ * and it's important to have both version synced. This solution is
+ * temporary and shared flag should be used by both files.
+ * Situation is analogous with I2C_GUID, which also should be common, but is
+ * for now defined same way in two header files.
+ */
+#define I2C_FLAG_NORESTART 0x00000002
+#define I2C_GUID \
+ { \
+ 0xadc1901b, 0xb83c, 0x4831, { 0x8f, 0x59, 0x70, 0x89, 0x8f, 0x26, 0x57, 0x1e } \
+ }
+
+typedef struct {
+ UINT32 Signature;
+ EFI_HANDLE ControllerHandle;
+ EFI_I2C_IO_PROTOCOL *I2cIo;
+ MARVELL_EEPROM_PROTOCOL EepromProtocol;
+} EEPROM_CONTEXT;
+
+#define EEPROM_SC_FROM_IO(a) CR (a, EEPROM_CONTEXT, I2cIo, EEPROM_SIGNATURE)
+#define EEPROM_SC_FROM_EEPROM(a) CR (a, EEPROM_CONTEXT, EepromProtocol, EEPROM_SIGNATURE)
+
+EFI_STATUS
+EFIAPI
+MvEepromSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+MvEepromStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+MvEepromStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+MvEepromTransfer (
+ IN CONST MARVELL_EEPROM_PROTOCOL *This,
+ IN UINT16 Address,
+ IN UINT32 Length,
+ IN UINT8 *Buffer,
+ IN UINT8 Operation
+ );
+#endif // __MV_EEPROM_H__
diff --git a/Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.inf b/Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.inf
new file mode 100644
index 0000000000..a50f8b9b4e
--- /dev/null
+++ b/Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.inf
@@ -0,0 +1,70 @@
+#
+# Marvell BSD License Option
+#
+# If you received this File from Marvell, you may opt to use, redistribute
+# and/or modify this File under the following licensing terms.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Marvell nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = MvEeprom
+ FILE_GUID = 59fc3843-d8d4-40aa-ae07-38967138509c
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = MvEepromInitialise
+
+[Sources.common]
+ MvEeprom.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ ArmPlatformPkg/ArmPlatformPkg.dec
+ ArmPkg/ArmPkg.dec
+ Platform/Marvell/Marvell.dec
+
+[LibraryClasses]
+ IoLib
+ PcdLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ UefiLib
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+
+[Protocols]
+ gEfiI2cIoProtocolGuid
+ gEfiDriverBindingProtocolGuid
+ gMarvellEepromProtocolGuid
+
+[Pcd]
+ gMarvellTokenSpaceGuid.PcdEepromI2cAddresses
+ gMarvellTokenSpaceGuid.PcdEepromI2cBuses
+
+[Depex]
+ TRUE
diff --git a/Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.c b/Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.c
new file mode 100755
index 0000000000..fa79ebccfa
--- /dev/null
+++ b/Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.c
@@ -0,0 +1,740 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#include <Protocol/I2cMaster.h>
+#include <Protocol/I2cEnumerate.h>
+#include <Protocol/I2cBusConfigurationManagement.h>
+#include <Protocol/DevicePath.h>
+
+#include <Library/BaseLib.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/ParsePcdLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "MvI2cDxe.h"
+
+STATIC MV_I2C_BAUD_RATE baud_rate;
+
+STATIC MV_I2C_DEVICE_PATH MvI2cDevicePathProtocol = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof(VENDOR_DEVICE_PATH)),
+ (UINT8) (sizeof(VENDOR_DEVICE_PATH) >> 8),
+ },
+ },
+ EFI_CALLER_ID_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ sizeof(EFI_DEVICE_PATH_PROTOCOL),
+ 0
+ }
+ }
+};
+
+STATIC
+UINT32
+I2C_READ(
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINTN off)
+{
+ ASSERT (I2cMasterContext != NULL);
+ return MmioRead32 (I2cMasterContext->BaseAddress + off);
+}
+
+STATIC
+EFI_STATUS
+I2C_WRITE (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINTN off,
+ IN UINT32 Value)
+{
+ ASSERT (I2cMasterContext != NULL);
+ return MmioWrite32 (I2cMasterContext->BaseAddress + off, Value);
+}
+
+EFI_STATUS
+EFIAPI
+MvI2cInitialiseController (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress
+ )
+{
+ EFI_STATUS Status;
+ I2C_MASTER_CONTEXT *I2cMasterContext;
+ STATIC INTN Bus = 0;
+ MV_I2C_DEVICE_PATH *DevicePath;
+
+ DevicePath = AllocateCopyPool (sizeof(MvI2cDevicePathProtocol),
+ &MvI2cDevicePathProtocol);
+ if (DevicePath == NULL) {
+ DEBUG((DEBUG_ERROR, "MvI2cDxe: I2C device path allocation failed\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ DevicePath->Guid.Guid.Data4[0] = Bus;
+
+ /* if attachment succeeds, this gets freed at ExitBootServices */
+ I2cMasterContext = AllocateZeroPool (sizeof (I2C_MASTER_CONTEXT));
+ if (I2cMasterContext == NULL) {
+ DEBUG((DEBUG_ERROR, "MvI2cDxe: I2C master context allocation failed\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ I2cMasterContext->Signature = I2C_MASTER_SIGNATURE;
+ I2cMasterContext->I2cMaster.Reset = MvI2cReset;
+ I2cMasterContext->I2cMaster.StartRequest = MvI2cStartRequest;
+ I2cMasterContext->I2cEnumerate.Enumerate = MvI2cEnumerate;
+ I2cMasterContext->I2cBusConf.EnableI2cBusConfiguration = MvI2cEnableConf;
+ I2cMasterContext->TclkFrequency = PcdGet32 (PcdI2cClockFrequency);
+ I2cMasterContext->BaseAddress = BaseAddress;
+ I2cMasterContext->Bus = Bus;
+ /* I2cMasterContext->Lock is responsible for serializing I2C operations */
+ EfiInitializeLock(&I2cMasterContext->Lock, TPL_NOTIFY);
+
+ MvI2cCalBaudRate( I2cMasterContext,
+ PcdGet32 (PcdI2cBaudRate),
+ &baud_rate,
+ I2cMasterContext->TclkFrequency
+ );
+
+ Status = gBS->InstallMultipleProtocolInterfaces(
+ &I2cMasterContext->Controller,
+ &gEfiI2cMasterProtocolGuid,
+ &I2cMasterContext->I2cMaster,
+ &gEfiI2cEnumerateProtocolGuid,
+ &I2cMasterContext->I2cEnumerate,
+ &gEfiI2cBusConfigurationManagementProtocolGuid,
+ &I2cMasterContext->I2cBusConf,
+ &gEfiDevicePathProtocolGuid,
+ (EFI_DEVICE_PATH_PROTOCOL *) DevicePath,
+ NULL);
+
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "MvI2cDxe: Installing protocol interfaces failed!\n"));
+ goto fail;
+ }
+ DEBUG((DEBUG_ERROR, "Succesfully installed controller %d at 0x%llx\n", Bus,
+ I2cMasterContext->BaseAddress));
+
+ Bus++;
+
+ return EFI_SUCCESS;
+
+fail:
+ FreePool(I2cMasterContext);
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+MvI2cInitialise (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BusCount;
+ EFI_PHYSICAL_ADDRESS I2cBaseAddresses[PcdGet32 (PcdI2cBusCount)];
+ INTN i;
+
+ BusCount = PcdGet32 (PcdI2cBusCount);
+ if (BusCount == 0)
+ return EFI_SUCCESS;
+
+ Status = ParsePcdString (
+ (CHAR16 *) PcdGetPtr (PcdI2cBaseAddresses),
+ BusCount,
+ I2cBaseAddresses,
+ NULL
+ );
+ if (EFI_ERROR(Status))
+ return Status;
+
+ for (i = 0; i < BusCount; i++) {
+ Status = MvI2cInitialiseController(
+ ImageHandle,
+ SystemTable,
+ I2cBaseAddresses[i]
+ );
+ if (EFI_ERROR(Status))
+ return Status;
+ }
+
+ return Status;
+}
+
+STATIC
+VOID
+MvI2cControlClear (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINT32 Mask)
+{
+ UINT32 Value;
+
+ /* clears given bits in I2C_CONTROL register */
+ Value = I2C_READ(I2cMasterContext, I2C_CONTROL);
+ Value &= ~Mask;
+ I2C_WRITE(I2cMasterContext, I2C_CONTROL, Value);
+}
+
+STATIC
+VOID
+MvI2cControlSet (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINT32 Mask)
+{
+ UINT32 Value;
+
+ /* sets given bits in I2C_CONTROL register */
+ Value = I2C_READ(I2cMasterContext, I2C_CONTROL);
+ Value |= Mask;
+ I2C_WRITE(I2cMasterContext, I2C_CONTROL, Value);
+}
+
+STATIC
+VOID
+MvI2cClearIflg (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext
+ )
+{
+ gBS->Stall(I2C_OPERATION_TIMEOUT);
+ MvI2cControlClear(I2cMasterContext, I2C_CONTROL_IFLG);
+ gBS->Stall(I2C_OPERATION_TIMEOUT);
+}
+
+/* Timeout is given in us */
+STATIC
+UINTN
+MvI2cPollCtrl (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINTN Timeout,
+ IN UINT32 Mask)
+{
+ Timeout /= 10;
+ while (!(I2C_READ(I2cMasterContext, I2C_CONTROL) & Mask)) {
+ gBS->Stall(10);
+ if (--Timeout == 0)
+ return (Timeout);
+ }
+ return (0);
+}
+
+/*
+ * 'Timeout' is given in us. Note also that Timeout handling is not exact --
+ * MvI2cLockedStart() total wait can be more than 2 x Timeout
+ * (MvI2cPollCtrl() is called twice). 'Mask' can be either I2C_STATUS_START
+ * or I2C_STATUS_RPTD_START
+ */
+STATIC
+EFI_STATUS
+MvI2cLockedStart (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN INT32 Mask,
+ IN UINT8 Slave,
+ IN UINTN Timeout
+ )
+{
+ UINTN ReadAccess, IflgSet = 0;
+ UINT32 I2cStatus;
+
+ if (Mask == I2C_STATUS_RPTD_START) {
+ /* read IFLG to know if it should be cleared later */
+ IflgSet = I2C_READ(I2cMasterContext, I2C_CONTROL) & I2C_CONTROL_IFLG;
+ }
+
+ MvI2cControlSet(I2cMasterContext, I2C_CONTROL_START);
+
+ if (Mask == I2C_STATUS_RPTD_START && IflgSet) {
+ DEBUG((DEBUG_INFO, "MvI2cDxe: IFLG set, clearing\n"));
+ MvI2cClearIflg(I2cMasterContext);
+ }
+
+ /* Without this delay we Timeout checking IFLG if the Timeout is 0 */
+ gBS->Stall(I2C_OPERATION_TIMEOUT);
+
+ if (MvI2cPollCtrl(I2cMasterContext, Timeout, I2C_CONTROL_IFLG)) {
+ DEBUG((DEBUG_ERROR, "MvI2cDxe: Timeout sending %sSTART condition\n",
+ Mask == I2C_STATUS_START ? "" : "repeated "));
+ return EFI_NO_RESPONSE;
+ }
+
+ I2cStatus = I2C_READ(I2cMasterContext, I2C_STATUS);
+ if (I2cStatus != Mask) {
+ DEBUG((DEBUG_ERROR, "MvI2cDxe: wrong I2cStatus (%02x) after sending %sSTART condition\n",
+ I2cStatus, Mask == I2C_STATUS_START ? "" : "repeated "));
+ return EFI_DEVICE_ERROR;
+ }
+
+ I2C_WRITE(I2cMasterContext, I2C_DATA, Slave);
+ gBS->Stall(I2C_OPERATION_TIMEOUT);
+ MvI2cClearIflg(I2cMasterContext);
+
+ if (MvI2cPollCtrl(I2cMasterContext, Timeout, I2C_CONTROL_IFLG)) {
+ DEBUG((DEBUG_ERROR, "MvI2cDxe: Timeout sending Slave address\n"));
+ return EFI_NO_RESPONSE;
+ }
+
+ ReadAccess = (Slave & 0x1) ? 1 : 0;
+ I2cStatus = I2C_READ(I2cMasterContext, I2C_STATUS);
+ if (I2cStatus != (ReadAccess ?
+ I2C_STATUS_ADDR_R_ACK : I2C_STATUS_ADDR_W_ACK)) {
+ DEBUG((DEBUG_ERROR, "MvI2cDxe: no ACK (I2cStatus: %02x) after sending Slave address\n",
+ I2cStatus));
+ return EFI_NO_RESPONSE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+#define ABSSUB(a,b) (((a) > (b)) ? (a) - (b) : (b) - (a))
+STATIC
+VOID
+MvI2cCalBaudRate (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN CONST UINT32 target,
+ IN OUT MV_I2C_BAUD_RATE *rate,
+ UINT32 clk
+ )
+{
+ UINT32 cur, diff, diff0, baud;
+ UINTN m, n, m0, n0;
+
+ /* Read initial m0, n0 values from register */
+ baud = I2C_READ(I2cMasterContext, I2C_BAUD_RATE);
+ m0 = I2C_M_FROM_BAUD(baud);
+ n0 = I2C_N_FROM_BAUD(baud);
+ /* Calculate baud rate. */
+ diff0 = 0xffffffff;
+
+ for (n = 0; n < 8; n++) {
+ for (m = 0; m < 16; m++) {
+ cur = I2C_BAUD_RATE_RAW(clk,m,n);
+ diff = ABSSUB(target, cur);
+ if (diff < diff0) {
+ m0 = m;
+ n0 = n;
+ diff0 = diff;
+ }
+ }
+ }
+ rate->raw = I2C_BAUD_RATE_RAW(clk, m0, n0);
+ rate->param = I2C_BAUD_RATE_PARAM(m0, n0);
+ rate->m = m0;
+ rate->n = n0;
+}
+
+EFI_STATUS
+EFIAPI
+MvI2cReset (
+ IN CONST EFI_I2C_MASTER_PROTOCOL *This
+ )
+{
+ UINT32 param;
+ I2C_MASTER_CONTEXT *I2cMasterContext = I2C_SC_FROM_MASTER(This);
+
+ param = baud_rate.param;
+
+ EfiAcquireLock (&I2cMasterContext->Lock);
+ I2C_WRITE(I2cMasterContext, I2C_SOFT_RESET, 0x0);
+ gBS->Stall(2 * I2C_OPERATION_TIMEOUT);
+ I2C_WRITE(I2cMasterContext, I2C_BAUD_RATE, param);
+ I2C_WRITE(I2cMasterContext, I2C_CONTROL, I2C_CONTROL_I2CEN | I2C_CONTROL_ACK);
+ gBS->Stall(I2C_OPERATION_TIMEOUT);
+ EfiReleaseLock (&I2cMasterContext->Lock);
+
+ return EFI_SUCCESS;
+}
+
+/*
+ * Timeout is given in us
+ */
+STATIC
+EFI_STATUS
+MvI2cRepeatedStart (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINT8 Slave,
+ IN UINTN Timeout
+ )
+{
+ EFI_STATUS Status;
+
+ EfiAcquireLock (&I2cMasterContext->Lock);
+ Status = MvI2cLockedStart(I2cMasterContext, I2C_STATUS_RPTD_START, Slave,
+ Timeout);
+ EfiReleaseLock (&I2cMasterContext->Lock);
+
+ if (EFI_ERROR(Status)) {
+ MvI2cStop(I2cMasterContext);
+ }
+ return Status;
+}
+
+/*
+ * Timeout is given in us
+ */
+STATIC
+EFI_STATUS
+MvI2cStart (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINT8 Slave,
+ IN UINTN Timeout
+ )
+{
+ EFI_STATUS Status;
+
+ EfiAcquireLock (&I2cMasterContext->Lock);
+ Status = MvI2cLockedStart(I2cMasterContext, I2C_STATUS_START, Slave, Timeout);
+ EfiReleaseLock (&I2cMasterContext->Lock);
+
+ if (EFI_ERROR(Status)) {
+ MvI2cStop(I2cMasterContext);
+ }
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+MvI2cStop (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext
+ )
+{
+ EfiAcquireLock (&I2cMasterContext->Lock);
+ MvI2cControlSet(I2cMasterContext, I2C_CONTROL_STOP);
+ gBS->Stall(I2C_OPERATION_TIMEOUT);
+ MvI2cClearIflg(I2cMasterContext);
+ EfiReleaseLock (&I2cMasterContext->Lock);
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+MvI2cRead (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN OUT UINT8 *Buf,
+ IN UINTN Length,
+ IN OUT UINTN *read,
+ IN UINTN last,
+ IN UINTN delay
+ )
+{
+ UINT32 I2cStatus;
+ UINTN LastByte;
+ EFI_STATUS Status;
+
+ EfiAcquireLock (&I2cMasterContext->Lock);
+ *read = 0;
+ while (*read < Length) {
+ /*
+ * Check if we are reading last byte of the last Buffer,
+ * do not send ACK then, per I2C specs
+ */
+ LastByte = ((*read == Length - 1) && last) ? 1 : 0;
+ if (LastByte)
+ MvI2cControlClear(I2cMasterContext, I2C_CONTROL_ACK);
+ else
+ MvI2cControlSet(I2cMasterContext, I2C_CONTROL_ACK);
+
+ gBS->Stall (I2C_OPERATION_TIMEOUT);
+ MvI2cClearIflg(I2cMasterContext);
+
+ if (MvI2cPollCtrl(I2cMasterContext, delay, I2C_CONTROL_IFLG)) {
+ DEBUG((DEBUG_ERROR, "MvI2cDxe: Timeout reading data\n"));
+ Status = EFI_NO_RESPONSE;
+ goto out;
+ }
+
+ I2cStatus = I2C_READ(I2cMasterContext, I2C_STATUS);
+ if (I2cStatus != (LastByte ?
+ I2C_STATUS_DATA_RD_NOACK : I2C_STATUS_DATA_RD_ACK)) {
+ DEBUG((DEBUG_ERROR, "MvI2cDxe: wrong I2cStatus (%02x) while reading\n", I2cStatus));
+ Status = EFI_DEVICE_ERROR;
+ goto out;
+ }
+
+ *Buf++ = I2C_READ(I2cMasterContext, I2C_DATA);
+ (*read)++;
+ }
+ Status = EFI_SUCCESS;
+out:
+ EfiReleaseLock (&I2cMasterContext->Lock);
+ return (Status);
+}
+
+STATIC
+EFI_STATUS
+MvI2cWrite (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN OUT CONST UINT8 *Buf,
+ IN UINTN Length,
+ IN OUT UINTN *Sent,
+ IN UINTN Timeout
+ )
+{
+ UINT32 status;
+ EFI_STATUS Status;
+
+ EfiAcquireLock (&I2cMasterContext->Lock);
+ *Sent = 0;
+ while (*Sent < Length) {
+ I2C_WRITE(I2cMasterContext, I2C_DATA, *Buf++);
+
+ MvI2cClearIflg(I2cMasterContext);
+ if (MvI2cPollCtrl(I2cMasterContext, Timeout, I2C_CONTROL_IFLG)) {
+ DEBUG((DEBUG_ERROR, "MvI2cDxe: Timeout writing data\n"));
+ Status = EFI_NO_RESPONSE;
+ goto out;
+ }
+
+ status = I2C_READ(I2cMasterContext, I2C_STATUS);
+ if (status != I2C_STATUS_DATA_WR_ACK) {
+ DEBUG((DEBUG_ERROR, "MvI2cDxe: wrong status (%02x) while writing\n", status));
+ Status = EFI_DEVICE_ERROR;
+ goto out;
+ }
+ (*Sent)++;
+ }
+ Status = EFI_SUCCESS;
+out:
+ EfiReleaseLock (&I2cMasterContext->Lock);
+ return (Status);
+}
+
+/*
+ * MvI2cStartRequest should be called only by I2cHost.
+ * I2C device drivers ought to use EFI_I2C_IO_PROTOCOL instead.
+ */
+STATIC
+EFI_STATUS
+MvI2cStartRequest (
+ IN CONST EFI_I2C_MASTER_PROTOCOL *This,
+ IN UINTN SlaveAddress,
+ IN EFI_I2C_REQUEST_PACKET *RequestPacket,
+ IN EFI_EVENT Event OPTIONAL,
+ OUT EFI_STATUS *I2cStatus OPTIONAL
+ )
+{
+ UINTN Count;
+ UINTN ReadMode;
+ UINTN Transmitted;
+ I2C_MASTER_CONTEXT *I2cMasterContext = I2C_SC_FROM_MASTER(This);
+ EFI_I2C_OPERATION *Operation;
+
+ ASSERT (RequestPacket != NULL);
+ ASSERT (I2cMasterContext != NULL);
+
+ for (Count = 0; Count < RequestPacket->OperationCount; Count++) {
+ Operation = &RequestPacket->Operation[Count];
+ ReadMode = Operation->Flags & I2C_FLAG_READ;
+
+ if (Count == 0) {
+ MvI2cStart ( I2cMasterContext,
+ (SlaveAddress << 1) | ReadMode,
+ I2C_TRANSFER_TIMEOUT
+ );
+ } else if (!(Operation->Flags & I2C_FLAG_NORESTART)) {
+ MvI2cRepeatedStart ( I2cMasterContext,
+ (SlaveAddress << 1) | ReadMode,
+ I2C_TRANSFER_TIMEOUT
+ );
+ }
+
+ if (ReadMode) {
+ MvI2cRead ( I2cMasterContext,
+ Operation->Buffer,
+ Operation->LengthInBytes,
+ &Transmitted,
+ Count == 1,
+ I2C_TRANSFER_TIMEOUT
+ );
+ } else {
+ MvI2cWrite ( I2cMasterContext,
+ Operation->Buffer,
+ Operation->LengthInBytes,
+ &Transmitted,
+ I2C_TRANSFER_TIMEOUT
+ );
+ }
+ if (Count == RequestPacket->OperationCount - 1) {
+ MvI2cStop ( I2cMasterContext );
+ }
+ }
+
+ if (I2cStatus != NULL)
+ I2cStatus = EFI_SUCCESS;
+ if (Event != NULL)
+ gBS->SignalEvent(Event);
+ return EFI_SUCCESS;
+}
+
+STATIC CONST EFI_GUID DevGuid = I2C_GUID;
+
+#define I2C_DEVICE_INDEX(bus, address) (((address) & 0xffff) | (bus) << 16)
+#define I2C_DEVICE_ADDRESS(index) ((index) & 0xffff)
+
+STATIC
+EFI_STATUS
+MvI2cAllocDevice (
+ IN UINT8 SlaveAddress,
+ IN UINT8 Bus,
+ IN OUT CONST EFI_I2C_DEVICE **Device
+ )
+{
+ EFI_STATUS Status;
+ EFI_I2C_DEVICE *Dev;
+ UINT32 *TmpSlaveArray;
+ EFI_GUID *TmpGuidP;
+
+ Status = gBS->AllocatePool ( EfiBootServicesData,
+ sizeof(EFI_I2C_DEVICE),
+ (VOID **) &Dev );
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "MvI2cDxe: I2C device memory allocation failed\n"));
+ return Status;
+ }
+ *Device = Dev;
+ Dev->DeviceIndex = SlaveAddress;
+ Dev->DeviceIndex = I2C_DEVICE_INDEX(Bus, SlaveAddress);
+ Dev->SlaveAddressCount = 1;
+ Dev->I2cBusConfiguration = 0;
+ Status = gBS->AllocatePool ( EfiBootServicesData,
+ sizeof(UINT32),
+ (VOID **) &TmpSlaveArray);
+ if (EFI_ERROR(Status)) {
+ goto fail1;
+ }
+ TmpSlaveArray[0] = SlaveAddress;
+ Dev->SlaveAddressArray = TmpSlaveArray;
+
+ Status = gBS->AllocatePool ( EfiBootServicesData,
+ sizeof(EFI_GUID),
+ (VOID **) &TmpGuidP);
+ if (EFI_ERROR(Status)) {
+ goto fail2;
+ }
+ *TmpGuidP = DevGuid;
+ Dev->DeviceGuid = TmpGuidP;
+
+ DEBUG((DEBUG_INFO, "MvI2c: allocated device with address %x\n", (UINTN)SlaveAddress));
+ return EFI_SUCCESS;
+
+fail2:
+ FreePool(TmpSlaveArray);
+fail1:
+ FreePool(Dev);
+
+ return Status;
+}
+
+/*
+ * It is called by I2cBus to enumerate devices on I2C bus. In this case,
+ * enumeration is based on PCD configuration - all Slave addresses specified
+ * in PCD get their corresponding EFI_I2C_DEVICE structures here.
+ *
+ * After enumeration succeeds, Supported() function of drivers that installed
+ * DriverBinding protocol is called.
+ */
+STATIC
+EFI_STATUS
+EFIAPI
+MvI2cEnumerate (
+ IN CONST EFI_I2C_ENUMERATE_PROTOCOL *This,
+ IN OUT CONST EFI_I2C_DEVICE **Device
+ )
+{
+ UINT8 *DevicesPcd;
+ UINT8 *DeviceBusPcd;
+ UINTN Index, NextIndex, DevCount;
+ UINT8 NextDeviceAddress;
+ I2C_MASTER_CONTEXT *I2cMasterContext = I2C_SC_FROM_ENUMERATE(This);
+
+ DevCount = PcdGetSize (PcdI2cSlaveAddresses);
+ DevicesPcd = PcdGetPtr (PcdI2cSlaveAddresses);
+ DeviceBusPcd = PcdGetPtr (PcdI2cSlaveBuses);
+ if (*Device == NULL) {
+ for (Index = 0; Index < DevCount ; Index++) {
+ if (DeviceBusPcd[Index] != I2cMasterContext->Bus)
+ continue;
+ if (Index < DevCount)
+ MvI2cAllocDevice (DevicesPcd[Index], I2cMasterContext->Bus, Device);
+ return EFI_SUCCESS;
+ }
+ } else {
+ /* Device is not NULL, so something was already allocated */
+ for (Index = 0; Index < DevCount; Index++) {
+ if (DeviceBusPcd[Index] != I2cMasterContext->Bus)
+ continue;
+ if (DevicesPcd[Index] == I2C_DEVICE_ADDRESS((*Device)->DeviceIndex)) {
+ for (NextIndex = Index + 1; NextIndex < DevCount; NextIndex++) {
+ if (DeviceBusPcd[NextIndex] != I2cMasterContext->Bus)
+ continue;
+ NextDeviceAddress = DevicesPcd[NextIndex];
+ if (NextIndex < DevCount)
+ MvI2cAllocDevice(NextDeviceAddress, I2cMasterContext->Bus, Device);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ *Device = NULL;
+ return EFI_SUCCESS;
+ }
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+MvI2cEnableConf (
+ IN CONST EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL *This,
+ IN UINTN I2cBusConfiguration,
+ IN EFI_EVENT Event OPTIONAL,
+ IN EFI_STATUS *I2cStatus OPTIONAL
+ )
+{
+ /* do nothing */
+ if (I2cStatus != NULL)
+ I2cStatus = EFI_SUCCESS;
+ if (Event != NULL)
+ gBS->SignalEvent(Event);
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.h b/Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.h
new file mode 100644
index 0000000000..028fd5461f
--- /dev/null
+++ b/Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.h
@@ -0,0 +1,269 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#ifndef __MV_I2C_H__
+#define __MV_I2C_H__
+
+#include <Uefi.h>
+
+#define I2C_BASE_ADDRESS 0xf0511000
+
+#define I2C_SLAVE_ADDR 0x00
+#define I2C_EXT_SLAVE_ADDR 0x10
+#define I2C_DATA 0x04
+
+#define I2C_CONTROL 0x08
+#define I2C_CONTROL_ACK (1 << 2)
+#define I2C_CONTROL_IFLG (1 << 3)
+#define I2C_CONTROL_STOP (1 << 4)
+#define I2C_CONTROL_START (1 << 5)
+#define I2C_CONTROL_I2CEN (1 << 6)
+#define I2C_CONTROL_INTEN (1 << 7)
+
+#define I2C_STATUS 0x0c
+#define I2C_STATUS_START 0x08
+#define I2C_STATUS_RPTD_START 0x10
+#define I2C_STATUS_ADDR_W_ACK 0x18
+#define I2C_STATUS_DATA_WR_ACK 0x28
+#define I2C_STATUS_ADDR_R_ACK 0x40
+#define I2C_STATUS_DATA_RD_ACK 0x50
+#define I2C_STATUS_DATA_RD_NOACK 0x58
+
+#define I2C_BAUD_RATE 0x0c
+#define I2C_BAUD_RATE_PARAM(M,N) ((((M) << 3) | ((N) & 0x7)) & 0x7f)
+#define I2C_BAUD_RATE_RAW(C,M,N) ((C)/((10*(M+1))<<(N+1)))
+#define I2C_M_FROM_BAUD(baud) (((baud) >> 3) & 0xf)
+#define I2C_N_FROM_BAUD(baud) ((baud) & 0x7)
+
+#define I2C_SOFT_RESET 0x1c
+#define I2C_TRANSFER_TIMEOUT 10000
+#define I2C_OPERATION_TIMEOUT 1000
+
+#define I2C_UNKNOWN 0x0
+#define I2C_SLOW 0x1
+#define I2C_FAST 0x2
+#define I2C_FASTEST 0x3
+
+/*
+ * I2C_FLAG_NORESTART is not part of PI spec, it allows to continue
+ * transmission without repeated start operation.
+ * FIXME: This flag is also defined in
+ * Platforms/Marvell/Include/Protocol/Eeprom.h and it's important to have both
+ * version synced. This solution is temporary and shared flag should be used by
+ * both files.
+ * Situation is analogous with I2C_GUID, which also should be common, but is
+ * for now defined same way in two header files.
+ */
+#define I2C_FLAG_NORESTART 0x00000002
+#define I2C_GUID \
+ { \
+ 0xadc1901b, 0xb83c, 0x4831, { 0x8f, 0x59, 0x70, 0x89, 0x8f, 0x26, 0x57, 0x1e } \
+ }
+
+#define I2C_MASTER_SIGNATURE SIGNATURE_32 ('I', '2', 'C', 'M')
+
+typedef struct {
+ UINT32 Signature;
+ EFI_HANDLE Controller;
+ EFI_LOCK Lock;
+ UINTN TclkFrequency;
+ UINTN BaseAddress;
+ INTN Bus;
+ EFI_I2C_MASTER_PROTOCOL I2cMaster;
+ EFI_I2C_ENUMERATE_PROTOCOL I2cEnumerate;
+ EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL I2cBusConf;
+} I2C_MASTER_CONTEXT;
+
+#define I2C_SC_FROM_MASTER(a) CR (a, I2C_MASTER_CONTEXT, I2cMaster, I2C_MASTER_SIGNATURE)
+#define I2C_SC_FROM_ENUMERATE(a) CR (a, I2C_MASTER_CONTEXT, I2cEnumerate, I2C_MASTER_SIGNATURE)
+#define I2C_SC_FROM_BUSCONF(a) CR (a, I2C_MASTER_CONTEXT, I2cBusConf, I2C_MASTER_SIGNATURE)
+
+typedef struct {
+ UINT32 raw;
+ UINTN param;
+ UINTN m;
+ UINTN n;
+} MV_I2C_BAUD_RATE;
+
+typedef struct {
+ VENDOR_DEVICE_PATH Guid;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} MV_I2C_DEVICE_PATH;
+
+STATIC
+UINT32
+I2C_READ(
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINTN off
+ );
+
+STATIC
+EFI_STATUS
+I2C_WRITE (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINTN off,
+ IN UINT32 val
+ );
+
+EFI_STATUS
+EFIAPI
+MvI2cInitialise (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+STATIC
+VOID
+MvI2cControlClear (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINT32 mask
+ );
+
+STATIC
+VOID
+MvI2cControlSet (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINT32 mask
+ );
+
+STATIC
+VOID
+MvI2cClearIflg (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext
+ );
+STATIC
+UINTN
+MvI2cPollCtrl (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINTN timeout,
+ IN UINT32 mask
+ );
+
+STATIC
+EFI_STATUS
+MvI2cLockedStart (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN INT32 mask,
+ IN UINT8 slave,
+ IN UINTN timeout
+ );
+
+STATIC
+VOID
+MvI2cCalBaudRate (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN CONST UINT32 target,
+ IN OUT MV_I2C_BAUD_RATE *rate,
+ UINT32 clk
+ );
+
+EFI_STATUS
+EFIAPI
+MvI2cReset (
+ IN CONST EFI_I2C_MASTER_PROTOCOL *This
+ );
+
+STATIC
+EFI_STATUS
+MvI2cRepeatedStart (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINT8 slave,
+ IN UINTN timeout
+ );
+
+STATIC
+EFI_STATUS
+MvI2cStart (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN UINT8 slave,
+ IN UINTN timeout
+ );
+
+STATIC
+EFI_STATUS
+MvI2cStop (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext
+ );
+
+STATIC
+EFI_STATUS
+MvI2cRead (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN OUT UINT8 *buf,
+ IN UINTN len,
+ IN OUT UINTN *read,
+ IN UINTN last,
+ IN UINTN delay
+ );
+
+STATIC
+EFI_STATUS
+MvI2cWrite (
+ IN I2C_MASTER_CONTEXT *I2cMasterContext,
+ IN OUT CONST UINT8 *buf,
+ IN UINTN len,
+ IN OUT UINTN *sent,
+ IN UINTN timeout
+ );
+
+STATIC
+EFI_STATUS
+EFIAPI
+MvI2cStartRequest (
+ IN CONST EFI_I2C_MASTER_PROTOCOL *This,
+ IN UINTN SlaveAddress,
+ IN EFI_I2C_REQUEST_PACKET *RequestPacket,
+ IN EFI_EVENT Event OPTIONAL,
+ OUT EFI_STATUS *I2cStatus OPTIONAL
+ );
+
+STATIC
+EFI_STATUS
+EFIAPI
+MvI2cEnumerate (
+ IN CONST EFI_I2C_ENUMERATE_PROTOCOL *This,
+ IN OUT CONST EFI_I2C_DEVICE **Device
+ );
+
+STATIC
+EFI_STATUS
+EFIAPI
+MvI2cEnableConf (
+ IN CONST EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL *This,
+ IN UINTN I2cBusConfiguration,
+ IN EFI_EVENT Event OPTIONAL,
+ IN EFI_STATUS *I2cStatus OPTIONAL
+ );
+
+#endif // __MV_I2C_H__
diff --git a/Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf b/Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf
new file mode 100755
index 0000000000..16374ef5e7
--- /dev/null
+++ b/Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf
@@ -0,0 +1,75 @@
+#
+# Marvell BSD License Option
+#
+# If you received this File from Marvell, you may opt to use, redistribute
+# and/or modify this File under the following licensing terms.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Marvell nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = MvI2cDxe
+ FILE_GUID = 59fc3843-d8d4-40aa-ae07-38967138509b
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = MvI2cInitialise
+
+[Sources.common]
+ MvI2cDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ ArmPlatformPkg/ArmPlatformPkg.dec
+ ArmPkg/ArmPkg.dec
+ Platform/Marvell/Marvell.dec
+
+[LibraryClasses]
+ IoLib
+ PcdLib
+ BaseLib
+ DebugLib
+ UefiLib
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ ParsePcdLib
+
+[Protocols]
+ gEfiI2cMasterProtocolGuid
+ gEfiDevicePathProtocolGuid
+ gEfiI2cEnumerateProtocolGuid
+ gEfiI2cBusConfigurationManagementProtocolGuid
+
+[Pcd]
+ gMarvellTokenSpaceGuid.PcdI2cSlaveAddresses
+ gMarvellTokenSpaceGuid.PcdI2cSlaveBuses
+ gMarvellTokenSpaceGuid.PcdI2cBaseAddresses
+ gMarvellTokenSpaceGuid.PcdI2cClockFrequency
+ gMarvellTokenSpaceGuid.PcdI2cBaudRate
+ gMarvellTokenSpaceGuid.PcdI2cBusCount
+
+[Depex]
+ TRUE
diff --git a/Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.c b/Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.c
new file mode 100644
index 0000000000..ae466d7019
--- /dev/null
+++ b/Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.c
@@ -0,0 +1,237 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#include <Protocol/DriverBinding.h>
+#include <Protocol/Mdio.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include "MvMdioDxe.h"
+
+UINT64 MdioBase = 0;
+
+STATIC
+EFI_STATUS
+MdioCheckParam (
+ INTN PhyAddr,
+ INTN RegOff
+ )
+{
+ if (PhyAddr > MVEBU_PHY_ADDR_MASK) {
+ DEBUG((DEBUG_ERROR, "Invalid PHY address %d\n", PhyAddr));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (RegOff > MVEBU_PHY_REG_MASK) {
+ DEBUG((DEBUG_ERROR, "Invalid register offset %d\n", RegOff));
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+MdioWaitReady (
+ VOID
+ )
+{
+ UINT32 Timeout = MVEBU_SMI_TIMEOUT;
+ UINT32 MdioReg;
+
+ /* wait till the SMI is not busy */
+ do {
+ /* read smi register */
+ MdioReg = MmioRead32(MdioBase);
+ if (Timeout-- == 0) {
+ DEBUG((DEBUG_ERROR, "SMI busy Timeout\n"));
+ return EFI_TIMEOUT;
+ }
+ } while (MdioReg & MVEBU_SMI_BUSY);
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+MdioWaitValid (
+ VOID
+ )
+{
+ UINT32 Timeout = MVEBU_SMI_TIMEOUT;
+ UINT32 MdioReg;
+
+ /* wait till read value is ready */
+ do {
+ /* read smi register */
+ MdioReg = MmioRead32 (MdioBase);
+ if (Timeout-- == 0) {
+ DEBUG((DEBUG_ERROR, "SMI read ready time-out\n"));
+ return EFI_TIMEOUT;
+ }
+ } while (!(MdioReg & MVEBU_SMI_READ_VALID));
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+MdioOperation (
+ IN CONST MARVELL_MDIO_PROTOCOL *This,
+ IN UINT32 PhyAddr,
+ IN UINT32 RegOff,
+ IN BOOLEAN Write,
+ IN OUT UINT32 *Data
+ )
+{
+ UINT32 MdioReg;
+ EFI_STATUS Status;
+
+ Status = MdioCheckParam (PhyAddr, RegOff);
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "MdioDxe: wrong parameters\n"));
+ return Status;
+ }
+
+ /* wait till the SMI is not busy */
+ Status = MdioWaitReady ();
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "MdioDxe: MdioWaitReady error\n"));
+ return Status;
+ }
+
+ /* fill the phy addr and reg offset and write opcode and data */
+ MdioReg = (PhyAddr << MVEBU_SMI_DEV_ADDR_OFFS)
+ | (RegOff << MVEBU_SMI_REG_ADDR_OFFS);
+ if (Write) {
+ MdioReg &= ~MVEBU_SMI_OPCODE_READ;
+ MdioReg |= (*Data << MVEBU_SMI_DATA_OFFS);
+ } else {
+ MdioReg |= MVEBU_SMI_OPCODE_READ;
+ }
+
+ /* write the smi register */
+ MdioRegWrite32 (MdioReg, MdioBase);
+
+ /* make sure that the write transaction is over */
+ Status = Write ? MdioWaitReady () : MdioWaitValid ();
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "MdioDxe: MdioWaitReady error\n"));
+ return Status;
+ }
+
+ if (!Write) {
+ *Data = MmioRead32 (MdioBase) & MVEBU_SMI_DATA_MASK;
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+MvMdioRead (
+ IN CONST MARVELL_MDIO_PROTOCOL *This,
+ IN UINT32 PhyAddr,
+ IN UINT32 RegOff,
+ IN UINT32 *Data
+ )
+{
+ EFI_STATUS Status;
+
+ Status = MdioOperation (
+ This,
+ PhyAddr,
+ RegOff,
+ FALSE,
+ Data
+ );
+
+ return Status;
+}
+
+EFI_STATUS
+MvMdioWrite (
+ IN CONST MARVELL_MDIO_PROTOCOL *This,
+ IN UINT32 PhyAddr,
+ IN UINT32 RegOff,
+ IN UINT32 Data
+ )
+{
+ return MdioOperation (
+ This,
+ PhyAddr,
+ RegOff,
+ TRUE,
+ &Data
+ );
+}
+
+EFI_STATUS
+EFIAPI
+MvMdioDxeInitialise (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ MARVELL_MDIO_PROTOCOL *Mdio;
+ EFI_STATUS Status;
+ EFI_HANDLE Handle = NULL;
+
+ Mdio = AllocateZeroPool (sizeof (MARVELL_MDIO_PROTOCOL));
+ Mdio->Read = MvMdioRead;
+ Mdio->Write = MvMdioWrite;
+ MdioBase = PcdGet64 (PcdMdioBaseAddress);
+ if (MdioBase == 0) {
+ DEBUG((DEBUG_ERROR, "MdioDxe: PcdMdioBaseAddress not set\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gMarvellMdioProtocolGuid, Mdio,
+ NULL
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "Failed to install interfaces\n"));
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.h b/Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.h
new file mode 100644
index 0000000000..b41a1e6fba
--- /dev/null
+++ b/Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.h
@@ -0,0 +1,57 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#ifndef __MDIO_DXE_H__
+#define __MDIO_DXE_H__
+
+#include <Uefi.h>
+
+#define MVEBU_SMI_TIMEOUT 10000
+
+/* SMI register fields */
+#define MVEBU_SMI_DATA_OFFS 0 /* Data */
+#define MVEBU_SMI_DATA_MASK (0xffff << MVEBU_SMI_DATA_OFFS)
+#define MVEBU_SMI_DEV_ADDR_OFFS 16 /* PHY device address */
+#define MVEBU_SMI_REG_ADDR_OFFS 21 /* PHY device reg addr*/
+#define MVEBU_SMI_OPCODE_OFFS 26 /* Write/Read opcode */
+#define MVEBU_SMI_OPCODE_READ (1 << MVEBU_SMI_OPCODE_OFFS)
+#define MVEBU_SMI_READ_VALID (1 << 27) /* Read Valid */
+#define MVEBU_SMI_BUSY (1 << 28) /* Busy */
+
+#define MVEBU_PHY_REG_MASK 0x1f
+#define MVEBU_PHY_ADDR_MASK 0x1f
+
+#define MdioRegWrite32(x, y) MmioWrite32((y), (x))
+
+#endif // __MDIO_DXE_H__
diff --git a/Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.inf b/Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.inf
new file mode 100644
index 0000000000..faab1f70d2
--- /dev/null
+++ b/Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.inf
@@ -0,0 +1,69 @@
+# Copyright (C) 2016 Marvell International Ltd.
+#
+# Marvell BSD License Option
+#
+# If you received this File from Marvell, you may opt to use, redistribute and/or
+# modify this File under the following licensing terms.
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Marvell nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = MdioDxe
+ FILE_GUID = 59fc3843-d8d4-40ba-ae07-38967138509c
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = MvMdioDxeInitialise
+
+[Sources.common]
+ MvMdioDxe.c
+ MvMdioDxe.h
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ ArmPlatformPkg/ArmPlatformPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Platform/Marvell/Marvell.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ IoLib
+ PcdLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+
+[Protocols]
+ gMarvellMdioProtocolGuid
+
+[Pcd]
+ gMarvellTokenSpaceGuid.PcdMdioBaseAddress
+
+[Depex]
+ TRUE
diff --git a/Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.c b/Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.c
new file mode 100644
index 0000000000..aeb6f7a01b
--- /dev/null
+++ b/Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.c
@@ -0,0 +1,438 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#include <Protocol/DriverBinding.h>
+#include <Protocol/Mdio.h>
+#include <Protocol/MvPhy.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include "MvPhyDxe.h"
+
+#define TIMEOUT 500
+
+STATIC MARVELL_MDIO_PROTOCOL *Mdio;
+
+STATIC MV_PHY_DEVICE MvPhyDevices[] = {
+ { MV_PHY_DEVICE_1512, MvPhyInit1512 },
+ { 0, NULL }
+};
+
+EFI_STATUS
+MvPhyStatus (
+ IN CONST MARVELL_PHY_PROTOCOL *This,
+ IN PHY_DEVICE *PhyDev
+ );
+
+EFI_STATUS
+MvPhyReset (
+ IN UINT32 PhyAddr
+ )
+{
+ UINT32 Reg = 0;
+ INTN timeout = TIMEOUT;
+
+ Mdio->Read(Mdio, PhyAddr, MII_BMCR, &Reg);
+ Reg |= BMCR_RESET;
+ Mdio->Write(Mdio, PhyAddr, MII_BMCR, Reg);
+
+ while ((Reg & BMCR_RESET) && timeout--) {
+ Mdio->Read(Mdio, PhyAddr, MII_BMCR, &Reg);
+ gBS->Stall(1000);
+ }
+
+ if (Reg & BMCR_RESET) {
+ DEBUG((DEBUG_ERROR, "PHY reset timed out\n"));
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/* Marvell 88E1111S */
+EFI_STATUS
+MvPhyM88e1111sConfig (
+ IN PHY_DEVICE *PhyDev
+ )
+{
+ UINT32 Reg;
+
+ if ((PhyDev->Connection == PHY_CONNECTION_RGMII) ||
+ (PhyDev->Connection == PHY_CONNECTION_RGMII_ID) ||
+ (PhyDev->Connection == PHY_CONNECTION_RGMII_RXID) ||
+ (PhyDev->Connection == PHY_CONNECTION_RGMII_TXID)) {
+ Mdio->Read(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_CR, &Reg);
+
+ if ((PhyDev->Connection == PHY_CONNECTION_RGMII) ||
+ (PhyDev->Connection == PHY_CONNECTION_RGMII_ID)) {
+ Reg |= (MIIM_88E1111_RX_DELAY | MIIM_88E1111_TX_DELAY);
+ } else if (PhyDev->Connection == PHY_CONNECTION_RGMII_RXID) {
+ Reg &= ~MIIM_88E1111_TX_DELAY;
+ Reg |= MIIM_88E1111_RX_DELAY;
+ } else if (PhyDev->Connection == PHY_CONNECTION_RGMII_TXID) {
+ Reg &= ~MIIM_88E1111_RX_DELAY;
+ Reg |= MIIM_88E1111_TX_DELAY;
+ }
+
+ Mdio->Write(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_CR, Reg);
+
+ Mdio->Read(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_SR, &Reg);
+
+ Reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK);
+
+ if (Reg & MIIM_88E1111_HWCFG_FIBER_COPPER_RES)
+ Reg |= MIIM_88E1111_HWCFG_MODE_FIBER_RGMII;
+ else
+ Reg |= MIIM_88E1111_HWCFG_MODE_COPPER_RGMII;
+
+ Mdio->Write(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_SR, Reg);
+ }
+
+ if (PhyDev->Connection == PHY_CONNECTION_SGMII) {
+ Mdio->Read(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_SR, &Reg);
+
+ Reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK);
+ Reg |= MIIM_88E1111_HWCFG_MODE_SGMII_NO_CLK;
+ Reg |= MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO;
+
+ Mdio->Write(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_SR, Reg);
+ }
+
+ if (PhyDev->Connection == PHY_CONNECTION_RTBI) {
+ Mdio->Read(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_CR, &Reg);
+ Reg |= (MIIM_88E1111_RX_DELAY | MIIM_88E1111_TX_DELAY);
+ Mdio->Write(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_CR, Reg);
+
+ Mdio->Read(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_SR, &Reg);
+ Reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK |
+ MIIM_88E1111_HWCFG_FIBER_COPPER_RES);
+ Reg |= 0x7 | MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO;
+ Mdio->Write(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_SR, Reg);
+
+ /* Soft reset */
+ MvPhyReset(PhyDev->Addr);
+
+ Mdio->Read(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_SR, &Reg);
+ Reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK |
+ MIIM_88E1111_HWCFG_FIBER_COPPER_RES);
+ Reg |= MIIM_88E1111_HWCFG_MODE_COPPER_RTBI |
+ MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO;
+ Mdio->Write(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_SR, Reg);
+ }
+
+ Mdio->Read(Mdio, PhyDev->Addr, MII_BMCR, &Reg);
+ Reg |= (BMCR_ANENABLE | BMCR_ANRESTART);
+ Reg &= ~BMCR_ISOLATE;
+ Mdio->Write(Mdio, PhyDev->Addr, MII_BMCR, Reg);
+
+ /* Soft reset */
+ MvPhyReset(PhyDev->Addr);
+
+ MvPhyReset(PhyDev->Addr);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+MvPhyParseStatus (
+ IN PHY_DEVICE *PhyDev
+ )
+{
+ UINT32 Data;
+ UINT32 Speed;
+
+ Mdio->Read(Mdio, PhyDev->Addr, MIIM_88E1xxx_PHY_STATUS, &Data);
+
+ if ((Data & MIIM_88E1xxx_PHYSTAT_LINK) &&
+ !(Data & MIIM_88E1xxx_PHYSTAT_SPDDONE)) {
+ INTN i = 0;
+
+ DEBUG((DEBUG_ERROR,"MvPhyDxe: Waiting for PHY realtime link"));
+ while (!(Data & MIIM_88E1xxx_PHYSTAT_SPDDONE)) {
+ if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
+ DEBUG((DEBUG_ERROR," TIMEOUT !\n"));
+ PhyDev->LinkUp = FALSE;
+ break;
+ }
+
+ if ((i++ % 1000) == 0)
+ DEBUG((DEBUG_ERROR, "."));
+ gBS->Stall(1000);
+ Mdio->Read(Mdio, PhyDev->Addr, MIIM_88E1xxx_PHY_STATUS, &Data);
+ }
+ DEBUG((DEBUG_ERROR," done\n"));
+ gBS->Stall(500000);
+ } else {
+ if (Data & MIIM_88E1xxx_PHYSTAT_LINK) {
+ DEBUG((DEBUG_ERROR, "MvPhyDxe: link up, "));
+ PhyDev->LinkUp = TRUE;
+ } else {
+ DEBUG((DEBUG_ERROR, "MvPhyDxe: link down, "));
+ PhyDev->LinkUp = FALSE;
+ }
+ }
+
+ if (Data & MIIM_88E1xxx_PHYSTAT_DUPLEX) {
+ DEBUG((DEBUG_ERROR, "full duplex, "));
+ PhyDev->FullDuplex = TRUE;
+ } else {
+ DEBUG((DEBUG_ERROR, "half duplex, "));
+ PhyDev->FullDuplex = FALSE;
+ }
+
+ Speed = Data & MIIM_88E1xxx_PHYSTAT_SPEED;
+
+ switch (Speed) {
+ case MIIM_88E1xxx_PHYSTAT_GBIT:
+ DEBUG((DEBUG_ERROR, "speed 1000\n"));
+ PhyDev->Speed = SPEED_1000;
+ break;
+ case MIIM_88E1xxx_PHYSTAT_100:
+ DEBUG((DEBUG_ERROR, "speed 100\n"));
+ PhyDev->Speed = SPEED_100;
+ break;
+ default:
+ DEBUG((DEBUG_ERROR, "speed 10\n"));
+ PhyDev->Speed = SPEED_10;
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+VOID
+MvPhy1512WriteBits (
+ IN UINT32 PhyAddr,
+ IN UINT8 RegNum,
+ IN UINT16 Offset,
+ IN UINT16 Len,
+ IN UINT16 Data)
+{
+ UINT32 Reg, Mask;
+
+ if ((Len + Offset) >= 16)
+ Mask = 0 - (1 << Offset);
+ else
+ Mask = (1 << (Len + Offset)) - (1 << Offset);
+
+ Mdio->Read(Mdio, PhyAddr, RegNum, &Reg);
+
+ Reg &= ~Mask;
+ Reg |= Data << Offset;
+
+ Mdio->Write(Mdio, PhyAddr, RegNum, Reg);
+}
+
+STATIC
+EFI_STATUS
+MvPhyInit1512 (
+ IN CONST MARVELL_PHY_PROTOCOL *Snp,
+ IN UINT32 PhyAddr,
+ IN OUT PHY_DEVICE *PhyDev
+ )
+{
+ UINT32 Data;
+ INTN i;
+
+ if (PhyDev->Connection == PHY_CONNECTION_SGMII) {
+ /* Select page 0xff and update configuration registers according to
+ * Marvell Release Notes - Alaska 88E1510/88E1518/88E1512 Rev A0,
+ * Errata Section 3.1 - needed in SGMII mode.
+ */
+ Mdio->Write(Mdio, PhyAddr, 22, 0x00ff);
+ Mdio->Write(Mdio, PhyAddr, 17, 0x214B);
+ Mdio->Write(Mdio, PhyAddr, 16, 0x2144);
+ Mdio->Write(Mdio, PhyAddr, 17, 0x0C28);
+ Mdio->Write(Mdio, PhyAddr, 16, 0x2146);
+ Mdio->Write(Mdio, PhyAddr, 17, 0xB233);
+ Mdio->Write(Mdio, PhyAddr, 16, 0x214D);
+ Mdio->Write(Mdio, PhyAddr, 17, 0xCC0C);
+ Mdio->Write(Mdio, PhyAddr, 16, 0x2159);
+
+ /* Reset page selection and select page 0x12 */
+ Mdio->Write(Mdio, PhyAddr, 22, 0x0000);
+ Mdio->Write(Mdio, PhyAddr, 22, 0x0012);
+
+ /* Write HWCFG_MODE = SGMII to Copper */
+ MvPhy1512WriteBits(PhyAddr, 20, 0, 3, 1);
+
+ /* Phy reset - necessary after changing mode */
+ MvPhy1512WriteBits(PhyAddr, 20, 15, 1, 1);
+
+ /* Reset page selection */
+ Mdio->Write(Mdio, PhyAddr, 22, 0x0000);
+ gBS->Stall(100);
+ }
+
+ MvPhyM88e1111sConfig (PhyDev);
+
+ /* autonegotiation on startup is not always required */
+ if (!PcdGetBool (PcdPhyStartupAutoneg))
+ return EFI_SUCCESS;
+
+ Mdio->Read(Mdio, PhyAddr, MII_BMSR, &Data);
+
+ if ((Data & BMSR_ANEGCAPABLE) && !(Data & BMSR_ANEGCOMPLETE)) {
+
+ DEBUG((DEBUG_ERROR, "MvPhyDxe: Waiting for PHY auto negotiation... "));
+ for (i = 0; !(Data & BMSR_ANEGCOMPLETE); i++) {
+ if (i > PHY_ANEG_TIMEOUT) {
+ DEBUG((DEBUG_ERROR, "timeout\n"));
+ PhyDev->LinkUp = FALSE;
+ return EFI_TIMEOUT;
+ }
+
+ gBS->Stall(1000); /* 1 ms */
+ Mdio->Read(Mdio, PhyAddr, MII_BMSR, &Data);
+ }
+ PhyDev->LinkUp = TRUE;
+ DEBUG((DEBUG_INFO, "MvPhyDxe: link up\n"));
+ } else {
+ Mdio->Read(Mdio, PhyAddr, MII_BMSR, &Data);
+
+ if (Data & BMSR_LSTATUS) {
+ PhyDev->LinkUp = TRUE;
+ DEBUG((DEBUG_INFO, "MvPhyDxe: link up\n"));
+ } else {
+ PhyDev->LinkUp = FALSE;
+ DEBUG((DEBUG_INFO, "MvPhyDxe: link down\n"));
+ }
+ }
+ MvPhyParseStatus (PhyDev);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+MvPhyInit (
+ IN CONST MARVELL_PHY_PROTOCOL *Snp,
+ IN UINT32 PhyAddr,
+ IN PHY_CONNECTION PhyConnection,
+ IN OUT PHY_DEVICE **OutPhyDev
+ )
+{
+ EFI_STATUS Status;
+ PHY_DEVICE *PhyDev;
+ UINT8 *DeviceIds;
+ INTN i;
+
+ Status = gBS->LocateProtocol (
+ &gMarvellMdioProtocolGuid,
+ NULL,
+ (VOID **) &Mdio
+ );
+ if (EFI_ERROR(Status))
+ return Status;
+
+ /* perform setup common for all PHYs */
+ PhyDev = AllocateZeroPool (sizeof (PHY_DEVICE));
+ PhyDev->Addr = PhyAddr;
+ PhyDev->Connection = PhyConnection;
+ DEBUG((DEBUG_INFO, "MvPhyDxe: PhyAddr is %d, connection %d\n",
+ PhyAddr, PhyConnection));
+ *OutPhyDev = PhyDev;
+
+ DeviceIds = PcdGetPtr (PcdPhyDeviceIds);
+ for (i = 0; i < PcdGetSize (PcdPhyDeviceIds); i++) {
+ /* find MvPhyDevices fitting entry */
+ if (MvPhyDevices[i].DevId == DeviceIds[i]) {
+ ASSERT (MvPhyDevices[i].DevInit != NULL);
+ /* proceed with PHY-specific initialization */
+ return MvPhyDevices[i].DevInit(Snp, PhyAddr, PhyDev);
+ }
+ }
+
+ /* if we are here, no matching DevId was found */
+ Status = EFI_INVALID_PARAMETER;
+ FreePool (PhyDev);
+ return Status;
+}
+
+EFI_STATUS
+MvPhyStatus (
+ IN CONST MARVELL_PHY_PROTOCOL *This,
+ IN PHY_DEVICE *PhyDev
+ )
+{
+ UINT32 Data;
+
+ Mdio->Read(Mdio, PhyDev->Addr, MII_BMSR, &Data);
+ Mdio->Read(Mdio, PhyDev->Addr, MII_BMSR, &Data);
+
+ if ((Data & BMSR_LSTATUS) == 0) {
+ PhyDev->LinkUp = FALSE;
+ } else {
+ PhyDev->LinkUp = TRUE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+MvPhyDxeInitialise (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ MARVELL_PHY_PROTOCOL *Phy;
+ EFI_STATUS Status;
+ EFI_HANDLE Handle = NULL;
+
+ Phy = AllocateZeroPool (sizeof (MARVELL_PHY_PROTOCOL));
+ Phy->Status = MvPhyStatus;
+ Phy->Init = MvPhyInit;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gMarvellPhyProtocolGuid, Phy,
+ NULL
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "Failed to install interfaces\n"));
+ return Status;
+ }
+ DEBUG((DEBUG_ERROR, "Succesfully installed protocol interfaces\n"));
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.h b/Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.h
new file mode 100644
index 0000000000..6bd06c52ed
--- /dev/null
+++ b/Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.h
@@ -0,0 +1,194 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+#ifndef __MV_PHY_DXE_H__
+#define __MV_PHY_DXE_H__
+
+#define MII_BMCR 0x00 /* Basic mode control Register */
+#define MII_BMSR 0x01 /* Basic mode status Register */
+#define MII_PHYSID1 0x02 /* PHYS ID 1 */
+#define MII_PHYSID2 0x03 /* PHYS ID 2 */
+#define MII_ADVERTISE 0x04 /* Advertisement control Reg */
+#define MII_LPA 0x05 /* Link partner ability Reg */
+#define MII_EXPANSION 0x06 /* Expansion Register */
+#define MII_CTRL1000 0x09 /* 1000BASE-T control */
+#define MII_STAT1000 0x0a /* 1000BASE-T status */
+#define MII_ESTATUS 0x0f /* Extended Status */
+#define MII_DCOUNTER 0x12 /* Disconnect counter */
+#define MII_FCSCOUNTER 0x13 /* False carrier counter */
+#define MII_NWAYTEST 0x14 /* N-way auto-neg test Reg */
+#define MII_RERRCOUNTER 0x15 /* Receive error counter */
+#define MII_SREVISION 0x16 /* Silicon revision */
+#define MII_RESV1 0x17 /* Reserved... */
+#define MII_LBRERROR 0x18 /* Lpback, rx, bypass error */
+#define MII_PHYADDR 0x19 /* PHY address */
+#define MII_RESV2 0x1a /* Reserved... */
+#define MII_TPISTATUS 0x1b /* TPI status for 10mbps */
+#define MII_NCONFIG 0x1c /* Network interface config */
+
+/* Basic mode control Register. */
+#define BMCR_RESV 0x003f /* Unused... */
+#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */
+#define BMCR_CTST 0x0080 /* Collision test */
+#define BMCR_FULLDPLX 0x0100 /* Full duplex */
+#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */
+#define BMCR_ISOLATE 0x0400 /* Disconnect DP83840 from MII */
+#define BMCR_PDOWN 0x0800 /* Powerdown the DP83840 */
+#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */
+#define BMCR_SPEED100 0x2000 /* Select 100Mbps */
+#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */
+#define BMCR_RESET 0x8000 /* Reset the DP83840 */
+
+/* Basic mode status Register. */
+#define BMSR_ERCAP 0x0001 /* Ext-Reg capability */
+#define BMSR_JCD 0x0002 /* Jabber detected */
+#define BMSR_LSTATUS 0x0004 /* Link status */
+#define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */
+#define BMSR_RFAULT 0x0010 /* Remote fault detected */
+#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */
+#define BMSR_RESV 0x00c0 /* Unused... */
+#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */
+#define BMSR_100HALF2 0x0200 /* Can do 100BASE-T2 HDX */
+#define BMSR_100FULL2 0x0400 /* Can do 100BASE-T2 FDX */
+#define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */
+#define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */
+#define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */
+#define BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */
+#define BMSR_100BASE4 0x8000 /* Can do 100mbps, 4k packets */
+
+#define PHY_ANEG_TIMEOUT 4000
+
+#define PHY_INTERFACE_MODE_RGMII 0
+#define PHY_INTERFACE_MODE_RGMII_ID 1
+#define PHY_INTERFACE_MODE_RGMII_RXID 2
+#define PHY_INTERFACE_MODE_RGMII_TXID 3
+#define PHY_INTERFACE_MODE_SGMII 4
+#define PHY_INTERFACE_MODE_RTBI 5
+
+#define PHY_AUTONEGOTIATE_TIMEOUT 5000
+
+/* 88E1011 PHY Status Register */
+#define MIIM_88E1xxx_PHY_STATUS 0x11
+#define MIIM_88E1xxx_PHYSTAT_SPEED 0xc000
+#define MIIM_88E1xxx_PHYSTAT_GBIT 0x8000
+#define MIIM_88E1xxx_PHYSTAT_100 0x4000
+#define MIIM_88E1xxx_PHYSTAT_DUPLEX 0x2000
+#define MIIM_88E1xxx_PHYSTAT_SPDDONE 0x0800
+#define MIIM_88E1xxx_PHYSTAT_LINK 0x0400
+
+#define MIIM_88E1xxx_PHY_SCR 0x10
+#define MIIM_88E1xxx_PHY_MDI_X_AUTO 0x0060
+
+/* 88E1111 PHY LED Control Register */
+#define MIIM_88E1111_PHY_LED_CONTROL 24
+#define MIIM_88E1111_PHY_LED_DIRECT 0x4100
+#define MIIM_88E1111_PHY_LED_COMBINE 0x411C
+
+/* 88E1111 Extended PHY Specific Control Register */
+#define MIIM_88E1111_PHY_EXT_CR 0x14
+#define MIIM_88E1111_RX_DELAY 0x80
+#define MIIM_88E1111_TX_DELAY 0x2
+
+/* 88E1111 Extended PHY Specific Status Register */
+#define MIIM_88E1111_PHY_EXT_SR 0x1b
+#define MIIM_88E1111_HWCFG_MODE_MASK 0xf
+#define MIIM_88E1111_HWCFG_MODE_COPPER_RGMII 0xb
+#define MIIM_88E1111_HWCFG_MODE_FIBER_RGMII 0x3
+#define MIIM_88E1111_HWCFG_MODE_SGMII_NO_CLK 0x4
+#define MIIM_88E1111_HWCFG_MODE_COPPER_RTBI 0x9
+#define MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO 0x8000
+#define MIIM_88E1111_HWCFG_FIBER_COPPER_RES 0x2000
+
+#define MIIM_88E1111_COPPER 0
+#define MIIM_88E1111_FIBER 1
+
+/* 88E1118 PHY defines */
+#define MIIM_88E1118_PHY_PAGE 22
+#define MIIM_88E1118_PHY_LED_PAGE 3
+
+/* 88E1121 PHY LED Control Register */
+#define MIIM_88E1121_PHY_LED_CTRL 16
+#define MIIM_88E1121_PHY_LED_PAGE 3
+#define MIIM_88E1121_PHY_LED_DEF 0x0030
+
+/* 88E1121 PHY IRQ Enable/Status Register */
+#define MIIM_88E1121_PHY_IRQ_EN 18
+#define MIIM_88E1121_PHY_IRQ_STATUS 19
+
+#define MIIM_88E1121_PHY_PAGE 22
+
+/* 88E1145 Extended PHY Specific Control Register */
+#define MIIM_88E1145_PHY_EXT_CR 20
+#define MIIM_M88E1145_RGMII_RX_DELAY 0x0080
+#define MIIM_M88E1145_RGMII_TX_DELAY 0x0002
+
+#define MIIM_88E1145_PHY_LED_CONTROL 24
+#define MIIM_88E1145_PHY_LED_DIRECT 0x4100
+
+#define MIIM_88E1145_PHY_PAGE 29
+#define MIIM_88E1145_PHY_CAL_OV 30
+
+#define MIIM_88E1149_PHY_PAGE 29
+
+/* 88E1310 PHY defines */
+#define MIIM_88E1310_PHY_LED_CTRL 16
+#define MIIM_88E1310_PHY_IRQ_EN 18
+#define MIIM_88E1310_PHY_RGMII_CTRL 21
+#define MIIM_88E1310_PHY_PAGE 22
+
+typedef enum {
+ MV_PHY_DEVICE_1512
+} MV_PHY_DEVICE_ID;
+
+typedef
+EFI_STATUS
+(*MV_PHY_DEVICE_INIT) (
+ IN CONST MARVELL_PHY_PROTOCOL *Snp,
+ IN UINT32 PhyAddr,
+ IN OUT PHY_DEVICE *PhyDev
+ );
+
+typedef struct {
+ MV_PHY_DEVICE_ID DevId;
+ MV_PHY_DEVICE_INIT DevInit;
+} MV_PHY_DEVICE;
+
+STATIC
+EFI_STATUS
+MvPhyInit1512 (
+ IN CONST MARVELL_PHY_PROTOCOL *Snp,
+ IN UINT32 PhyAddr,
+ IN OUT PHY_DEVICE *PhyDev
+ );
+
+#endif
diff --git a/Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.inf b/Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.inf
new file mode 100644
index 0000000000..c262ce42b5
--- /dev/null
+++ b/Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.inf
@@ -0,0 +1,71 @@
+# Copyright (C) 2016 Marvell International Ltd.
+#
+# Marvell BSD License Option
+#
+# If you received this File from Marvell, you may opt to use, redistribute and/or
+# modify this File under the following licensing terms.
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Marvell nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = MvPhyDxe
+ FILE_GUID = 5aac3843-d8d4-40ba-ae07-38967138509c
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = MvPhyDxeInitialise
+
+[Sources.common]
+ MvPhyDxe.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ ArmPlatformPkg/ArmPlatformPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Platform/Marvell/Marvell.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ IoLib
+ PcdLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+
+[Protocols]
+ gMarvellMdioProtocolGuid
+ gMarvellPhyProtocolGuid
+
+[Pcd]
+ gMarvellTokenSpaceGuid.PcdPhyConnectionTypes
+ gMarvellTokenSpaceGuid.PcdPhyDeviceIds
+ gMarvellTokenSpaceGuid.PcdPhyStartupAutoneg
+
+[Depex]
+ TRUE
diff --git a/Platform/Marvell/Drivers/Net/Pp2Dxe/Mvpp2Lib.c b/Platform/Marvell/Drivers/Net/Pp2Dxe/Mvpp2Lib.c
new file mode 100644
index 0000000000..cdd0979450
--- /dev/null
+++ b/Platform/Marvell/Drivers/Net/Pp2Dxe/Mvpp2Lib.c
@@ -0,0 +1,4839 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#include "Mvpp2Lib.h"
+#include "Mvpp2LibHw.h"
+#include "Pp2Dxe.h"
+
+/* Parser configuration routines */
+
+/* Update parser Tcam and Sram hw entries */
+STATIC
+INT32
+Mvpp2PrsHwWrite (
+ IN MVPP2_SHARED *Priv,
+ IN OUT MVPP2_PRS_ENTRY *Pe
+ )
+{
+ INT32 i;
+
+ if (Pe->Index > MVPP2_PRS_TCAM_SRAM_SIZE - 1) {
+ return MVPP2_EINVAL;
+ }
+
+ /* Clear entry invalidation bit */
+ Pe->Tcam.Word[MVPP2_PRS_TCAM_INV_WORD] &= ~MVPP2_PRS_TCAM_INV_MASK;
+
+ /* Write Tcam Index - indirect access */
+ Mvpp2Write (Priv, MVPP2_PRS_TCAM_IDX_REG, Pe->Index);
+ for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++) {
+ Mvpp2Write (Priv, MVPP2_PRS_TCAM_DATA_REG(i), Pe->Tcam.Word[i]);
+ }
+
+ /* Write Sram Index - indirect access */
+ Mvpp2Write (Priv, MVPP2_PRS_SRAM_IDX_REG, Pe->Index);
+ for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++) {
+ Mvpp2Write (Priv, MVPP2_PRS_SRAM_DATA_REG(i), Pe->Sram.Word[i]);
+ }
+
+ return 0;
+}
+
+/* Read Tcam entry from hw */
+STATIC
+INT32
+Mvpp2PrsHwRead (
+ IN MVPP2_SHARED *Priv,
+ IN OUT MVPP2_PRS_ENTRY *Pe
+ )
+{
+ INT32 i;
+
+ if (Pe->Index > MVPP2_PRS_TCAM_SRAM_SIZE - 1) {
+ return MVPP2_EINVAL;
+ }
+
+ /* Write Tcam Index - indirect access */
+ Mvpp2Write (Priv, MVPP2_PRS_TCAM_IDX_REG, Pe->Index);
+
+ Pe->Tcam.Word[MVPP2_PRS_TCAM_INV_WORD] =
+ Mvpp2Read (Priv, MVPP2_PRS_TCAM_DATA_REG(MVPP2_PRS_TCAM_INV_WORD));
+ if (Pe->Tcam.Word[MVPP2_PRS_TCAM_INV_WORD] & MVPP2_PRS_TCAM_INV_MASK) {
+ return MVPP2_PRS_TCAM_ENTRY_INVALID;
+ }
+
+ for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++) {
+ Pe->Tcam.Word[i] = Mvpp2Read (Priv, MVPP2_PRS_TCAM_DATA_REG(i));
+ }
+
+ /* Write Sram Index - indirect access */
+ Mvpp2Write (Priv, MVPP2_PRS_SRAM_IDX_REG, Pe->Index);
+ for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++) {
+ Pe->Sram.Word[i] = Mvpp2Read (Priv, MVPP2_PRS_SRAM_DATA_REG(i));
+ }
+
+ return 0;
+}
+
+/* Invalidate Tcam hw entry */
+STATIC
+VOID
+Mvpp2PrsHwInv (
+ IN MVPP2_SHARED *Priv,
+ IN INT32 Index
+ )
+{
+ /* Write Index - indirect access */
+ Mvpp2Write (Priv, MVPP2_PRS_TCAM_IDX_REG, Index);
+ Mvpp2Write (Priv, MVPP2_PRS_TCAM_DATA_REG(MVPP2_PRS_TCAM_INV_WORD),
+ MVPP2_PRS_TCAM_INV_MASK);
+}
+
+/* Enable shadow table entry and set its lookup ID */
+STATIC
+VOID
+Mvpp2PrsShadowSet (
+ IN MVPP2_SHARED *Priv,
+ IN INT32 Index,
+ IN INT32 Lu
+ )
+{
+ Priv->PrsShadow[Index].Valid = TRUE;
+ Priv->PrsShadow[Index].Lu = Lu;
+}
+
+/* Update Ri fields in shadow table entry */
+STATIC
+VOID
+Mvpp2PrsShadowRiSet (
+ IN MVPP2_SHARED *Priv,
+ IN INT32 Index,
+ IN UINT32 Ri,
+ IN UINT32 RiMask
+ )
+{
+ Priv->PrsShadow[Index].RiMask = RiMask;
+ Priv->PrsShadow[Index].Ri = Ri;
+}
+
+/* Update lookup field in Tcam sw entry */
+STATIC
+VOID
+Mvpp2PrsTcamLuSet (
+ IN OUT MVPP2_PRS_ENTRY *Pe,
+ IN UINT32 Lu
+ )
+{
+ INT32 EnableOff = MVPP2_PRS_TCAM_EN_OFFS (MVPP2_PRS_TCAM_LU_BYTE);
+
+ Pe->Tcam.Byte[MVPP2_PRS_TCAM_LU_BYTE] = Lu;
+ Pe->Tcam.Byte[EnableOff] = MVPP2_PRS_LU_MASK;
+}
+
+/* Update Mask for single Port in Tcam sw entry */
+STATIC
+VOID
+Mvpp2PrsTcamPortSet (
+ IN OUT MVPP2_PRS_ENTRY *Pe,
+ IN UINT32 PortId,
+ IN BOOLEAN Add
+ )
+{
+ INT32 EnableOff = MVPP2_PRS_TCAM_EN_OFFS (MVPP2_PRS_TCAM_PORT_BYTE);
+
+ if (Add) {
+ Pe->Tcam.Byte[EnableOff] &= ~(1 << PortId);
+ } else {
+ Pe->Tcam.Byte[EnableOff] |= 1 << PortId;
+ }
+}
+
+/* Update Port map in Tcam sw entry */
+STATIC
+VOID
+Mvpp2PrsTcamPortMapSet (
+ IN OUT MVPP2_PRS_ENTRY *Pe,
+ IN UINT32 PortMask
+ )
+{
+ INT32 EnableOff = MVPP2_PRS_TCAM_EN_OFFS (MVPP2_PRS_TCAM_PORT_BYTE);
+ UINT8 Mask = MVPP2_PRS_PORT_MASK;
+
+ Pe->Tcam.Byte[MVPP2_PRS_TCAM_PORT_BYTE] = 0;
+ Pe->Tcam.Byte[EnableOff] &= ~Mask;
+ Pe->Tcam.Byte[EnableOff] |= ~PortMask & MVPP2_PRS_PORT_MASK;
+}
+
+/* Obtain Port map from Tcam sw entry */
+STATIC
+UINT32
+Mvpp2PrsTcamPortMapGet (
+ IN MVPP2_PRS_ENTRY *Pe
+ )
+{
+ INT32 EnableOff = MVPP2_PRS_TCAM_EN_OFFS (MVPP2_PRS_TCAM_PORT_BYTE);
+
+ return ~(Pe->Tcam.Byte[EnableOff]) & MVPP2_PRS_PORT_MASK;
+}
+
+/* Set Byte of data and its enable bits in Tcam sw entry */
+STATIC
+VOID
+Mvpp2PrsTcamDataByteSet (
+ IN OUT MVPP2_PRS_ENTRY *Pe,
+ IN UINT32 Offs,
+ IN UINT8 Byte,
+ IN UINT8 Enable
+ )
+{
+ Pe->Tcam.Byte[MVPP2_PRS_TCAM_DATA_BYTE(Offs)] = Byte;
+ Pe->Tcam.Byte[MVPP2_PRS_TCAM_DATA_BYTE_EN(Offs)] = Enable;
+}
+
+/* Get Byte of data and its enable bits from Tcam sw entry */
+STATIC
+VOID
+Mvpp2PrsTcamDataByteGet (
+ IN MVPP2_PRS_ENTRY *Pe,
+ IN UINT32 Offs,
+ OUT UINT8 *Byte,
+ OUT UINT8 *Enable
+ )
+{
+ *Byte = Pe->Tcam.Byte[MVPP2_PRS_TCAM_DATA_BYTE(Offs)];
+ *Enable = Pe->Tcam.Byte[MVPP2_PRS_TCAM_DATA_BYTE_EN(Offs)];
+}
+
+/* Compare Tcam data bytes with a pattern */
+STATIC
+BOOLEAN
+Mvpp2PrsTcamDataCmp (
+ IN MVPP2_PRS_ENTRY *Pe,
+ IN INT32 Offset,
+ IN UINT16 Data
+ )
+{
+ INT32 ByteOffset = MVPP2_PRS_TCAM_DATA_BYTE(Offset);
+ UINT16 TcamData;
+
+ TcamData = (Pe->Tcam.Byte[ByteOffset + 1] << 8) | Pe->Tcam.Byte[ByteOffset];
+ if (TcamData != Data) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Update ai bits in Tcam sw entry */
+STATIC
+VOID
+Mvpp2PrsTcamAiUpdate (
+ IN OUT MVPP2_PRS_ENTRY *Pe,
+ IN UINT32 Bits,
+ IN UINT32 Enable
+ )
+{
+ INT32 i, AiIdx = MVPP2_PRS_TCAM_AI_BYTE;
+
+ for (i = 0; i < MVPP2_PRS_AI_BITS; i++) {
+
+ if (!(Enable & BIT (i))) {
+ continue;
+ }
+
+ if (Bits & BIT (i)) {
+ Pe->Tcam.Byte[AiIdx] |= 1 << i;
+ } else {
+ Pe->Tcam.Byte[AiIdx] &= ~(1 << i);
+ }
+ }
+
+ Pe->Tcam.Byte[MVPP2_PRS_TCAM_EN_OFFS (AiIdx)] |= Enable;
+}
+
+/* Get ai bits from Tcam sw entry */
+STATIC
+INT32
+Mvpp2PrsTcamAiGet (
+ IN MVPP2_PRS_ENTRY *Pe
+ )
+{
+ return Pe->Tcam.Byte[MVPP2_PRS_TCAM_AI_BYTE];
+}
+
+/* Get word of data and its enable bits from Tcam sw entry */
+STATIC
+VOID
+Mvpp2PrsTcamDataWordGet (
+ IN MVPP2_PRS_ENTRY *Pe,
+ IN UINT32 DataOffset,
+ OUT UINT32 *Word,
+ OUT UINT32 *Enable
+ )
+{
+ INT32 Index, Position;
+ UINT8 Byte, Mask;
+
+ for (Index = 0; Index < 4; Index++) {
+ Position = (DataOffset * sizeof (INT32)) + Index;
+ Mvpp2PrsTcamDataByteGet (Pe, Position, &Byte, &Mask);
+ ((UINT8 *)Word)[Index] = Byte;
+ ((UINT8 *)Enable)[Index] = Mask;
+ }
+}
+
+/* Set ethertype in Tcam sw entry */
+STATIC
+VOID
+Mvpp2PrsMatchEtype (
+ IN OUT MVPP2_PRS_ENTRY *Pe,
+ IN INT32 Offset,
+ IN UINT16 EtherType
+ )
+{
+ Mvpp2PrsTcamDataByteSet (Pe, Offset + 0, EtherType >> 8, 0xff);
+ Mvpp2PrsTcamDataByteSet (Pe, Offset + 1, EtherType & 0xff, 0xff);
+}
+
+/* Set bits in Sram sw entry */
+STATIC
+VOID
+Mvpp2PrsSramBitsSet (
+ IN OUT MVPP2_PRS_ENTRY *Pe,
+ IN INT32 BitNum,
+ IN INT32 Val
+ )
+{
+ Pe->Sram.Byte[MVPP2_BIT_TO_BYTE(BitNum)] |= (Val << (BitNum % 8));
+}
+
+/* Clear bits in Sram sw entry */
+STATIC
+VOID
+Mvpp2PrsSramBitsClear (
+ IN OUT MVPP2_PRS_ENTRY *Pe,
+ IN INT32 BitNum,
+ IN INT32 Val
+ )
+{
+ Pe->Sram.Byte[MVPP2_BIT_TO_BYTE(BitNum)] &= ~(Val << (BitNum % 8));
+}
+
+/* Update Ri bits in Sram sw entry */
+STATIC
+VOID
+Mvpp2PrsSramRiUpdate (
+ IN OUT MVPP2_PRS_ENTRY *Pe,
+ IN UINT32 bits,
+ IN UINT32 Mask
+ )
+{
+ UINT32 i;
+
+ for (i = 0; i < MVPP2_PRS_SRAM_RI_CTRL_BITS; i++) {
+ INT32 RiOff = MVPP2_PRS_SRAM_RI_OFFS;
+
+ if (!(Mask & BIT (i))) {
+ continue;
+ }
+
+ if (bits & BIT (i)) {
+ Mvpp2PrsSramBitsSet (Pe, RiOff + i, 1);
+ } else {
+ Mvpp2PrsSramBitsClear (Pe, RiOff + i, 1);
+ }
+
+ Mvpp2PrsSramBitsSet (Pe, MVPP2_PRS_SRAM_RI_CTRL_OFFS + i, 1);
+ }
+}
+
+/* Obtain Ri bits from Sram sw entry */
+STATIC
+INT32
+Mvpp2PrsSramRiGet (
+ IN MVPP2_PRS_ENTRY *Pe
+ )
+{
+ return Pe->Sram.Word[MVPP2_PRS_SRAM_RI_WORD];
+}
+
+/* Update ai bits in Sram sw entry */
+STATIC
+VOID
+Mvpp2PrsSramAiUpdate (
+ IN OUT MVPP2_PRS_ENTRY *Pe,
+ IN UINT32 Bits,
+ UINT32 Mask
+ )
+{
+ UINT32 i;
+ INT32 AiOff = MVPP2_PRS_SRAM_AI_OFFS;
+
+ for (i = 0; i < MVPP2_PRS_SRAM_AI_CTRL_BITS; i++) {
+
+ if (!(Mask & BIT (i))) {
+ continue;
+ }
+
+ if (Bits & BIT (i)) {
+ Mvpp2PrsSramBitsSet (Pe, AiOff + i, 1);
+ } else {
+ Mvpp2PrsSramBitsClear (Pe, AiOff + i, 1);
+ }
+
+ Mvpp2PrsSramBitsSet (Pe, MVPP2_PRS_SRAM_AI_CTRL_OFFS + i, 1);
+ }
+}
+
+/* Read ai bits from Sram sw entry */
+STATIC
+INT32
+Mvpp2PrsSramAiGet (
+ IN MVPP2_PRS_ENTRY *Pe
+ )
+{
+ UINT8 bits;
+ INT32 AiOff = MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_AI_OFFS);
+ INT32 AiEnOff = AiOff + 1;
+ INT32 AiShift = MVPP2_PRS_SRAM_AI_OFFS % 8;
+
+ bits = (Pe->Sram.Byte[AiOff] >> AiShift) |
+ (Pe->Sram.Byte[AiEnOff] << (8 - AiShift));
+
+ return bits;
+}
+
+/*
+ * In Sram sw entry set lookup ID field of the
+ * Tcam key to be used in the next lookup iteration
+ */
+STATIC
+VOID
+Mvpp2PrsSramNextLuSet (
+ IN OUT MVPP2_PRS_ENTRY *Pe,
+ IN UINT32 Lu
+ )
+{
+ INT32 SramNextOff = MVPP2_PRS_SRAM_NEXT_LU_OFFS;
+
+ Mvpp2PrsSramBitsClear (Pe, SramNextOff, MVPP2_PRS_SRAM_NEXT_LU_MASK);
+ Mvpp2PrsSramBitsSet (Pe, SramNextOff, Lu);
+}
+
+/*
+ * In the Sram sw entry set sign and value of the next lookup Offset
+ * and the Offset value generated to the classifier
+ */
+STATIC
+VOID
+Mvpp2PrsSramShiftSet (
+ IN OUT MVPP2_PRS_ENTRY *Pe,
+ IN INT32 Shift,
+ IN UINT32 Op
+ )
+{
+ /* Set sign */
+ if (Shift < 0) {
+ Mvpp2PrsSramBitsSet (Pe, MVPP2_PRS_SRAM_SHIFT_SIGN_BIT, 1);
+ Shift = -Shift;
+ } else {
+ Mvpp2PrsSramBitsClear (Pe, MVPP2_PRS_SRAM_SHIFT_SIGN_BIT, 1);
+ }
+
+ /* Set value */
+ Pe->Sram.Byte[MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_SHIFT_OFFS)] = (UINT8)Shift;
+
+ /* Reset and set operation */
+ Mvpp2PrsSramBitsClear (Pe, MVPP2_PRS_SRAM_OP_SEL_SHIFT_OFFS, MVPP2_PRS_SRAM_OP_SEL_SHIFT_MASK);
+ Mvpp2PrsSramBitsSet (Pe, MVPP2_PRS_SRAM_OP_SEL_SHIFT_OFFS, Op);
+
+ /* Set base Offset as current */
+ Mvpp2PrsSramBitsClear (Pe, MVPP2_PRS_SRAM_OP_SEL_BASE_OFFS, 1);
+}
+
+/*
+ * In the Sram sw entry set sign and value of the user defined offset
+ * generated for the classifier
+ */
+STATIC
+VOID
+Mvpp2PrsSramOffsetSet (
+ IN OUT MVPP2_PRS_ENTRY *Pe,
+ IN UINT32 Type,
+ IN INT32 Offset,
+ IN UINT32 Op
+ )
+{
+ UINT8 UdfByte = MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_UDF_OFFS + MVPP2_PRS_SRAM_UDF_BITS);
+ UINT8 UdfByteOffset = (8 - (MVPP2_PRS_SRAM_UDF_OFFS % 8));
+ UINT8 OpSelUdfByte = MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS + MVPP2_PRS_SRAM_OP_SEL_UDF_BITS);
+ UINT8 OpSelUdfByteOffset = (8 - (MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS % 8));
+
+ /* Set sign */
+ if (Offset < 0) {
+ Mvpp2PrsSramBitsSet (Pe, MVPP2_PRS_SRAM_UDF_SIGN_BIT, 1);
+ Offset = -Offset;
+ } else {
+ Mvpp2PrsSramBitsClear (Pe, MVPP2_PRS_SRAM_UDF_SIGN_BIT, 1);
+ }
+
+ /* Set value */
+ Mvpp2PrsSramBitsClear (Pe, MVPP2_PRS_SRAM_UDF_OFFS, MVPP2_PRS_SRAM_UDF_MASK);
+ Mvpp2PrsSramBitsSet (Pe, MVPP2_PRS_SRAM_UDF_OFFS, Offset);
+
+ Pe->Sram.Byte[UdfByte] &= ~(MVPP2_PRS_SRAM_UDF_MASK >> UdfByteOffset);
+ Pe->Sram.Byte[UdfByte] |= (Offset >> UdfByteOffset);
+
+ /* Set Offset Type */
+ Mvpp2PrsSramBitsClear (Pe, MVPP2_PRS_SRAM_UDF_TYPE_OFFS, MVPP2_PRS_SRAM_UDF_TYPE_MASK);
+ Mvpp2PrsSramBitsSet (Pe, MVPP2_PRS_SRAM_UDF_TYPE_OFFS, Type);
+
+ /* Set Offset operation */
+ Mvpp2PrsSramBitsClear (Pe, MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS, MVPP2_PRS_SRAM_OP_SEL_UDF_MASK);
+ Mvpp2PrsSramBitsSet (Pe, MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS, Op);
+
+ Pe->Sram.Byte[OpSelUdfByte] &= ~(MVPP2_PRS_SRAM_OP_SEL_UDF_MASK >> OpSelUdfByteOffset);
+ Pe->Sram.Byte[OpSelUdfByte] |= (Op >> OpSelUdfByteOffset);
+
+ /* Set base Offset as current */
+ Mvpp2PrsSramBitsClear (Pe, MVPP2_PRS_SRAM_OP_SEL_BASE_OFFS, 1);
+}
+
+/* Find parser Flow entry */
+STATIC
+MVPP2_PRS_ENTRY *
+Mvpp2PrsFlowFind (
+ IN MVPP2_SHARED *Priv,
+ IN INT32 Flow
+ )
+{
+ MVPP2_PRS_ENTRY *Pe;
+ INT32 Tid;
+ UINT32 Word, Enable;
+
+ Pe = Mvpp2Alloc (sizeof (*Pe));
+ if (Pe == NULL) {
+ return NULL;
+ }
+
+ Mvpp2PrsTcamLuSet (Pe, MVPP2_PRS_LU_FLOWS);
+
+ /* Go through the all entires with MVPP2_PRS_LU_FLOWS */
+ for (Tid = MVPP2_PRS_TCAM_SRAM_SIZE - 1; Tid >= 0; Tid--) {
+ UINT8 Bits;
+
+ if (!Priv->PrsShadow[Tid].Valid || Priv->PrsShadow[Tid].Lu != MVPP2_PRS_LU_FLOWS) {
+ continue;
+ }
+
+ Pe->Index = Tid;
+ Mvpp2PrsHwRead (Priv, Pe);
+
+ /*
+ * Check result info, because there maybe
+ * several TCAM lines to generate the same Flow
+ */
+ Mvpp2PrsTcamDataWordGet (Pe, 0, &Word, &Enable);
+ if ((Word != 0) || (Enable != 0)) {
+ continue;
+ }
+
+ Bits = Mvpp2PrsSramAiGet (Pe);
+
+ /* Sram store classification lookup ID in AI Bits [5:0] */
+ if ((Bits & MVPP2_PRS_FLOW_ID_MASK) == Flow) {
+ return Pe;
+ }
+ }
+
+ Mvpp2Free (Pe);
+
+ return NULL;
+}
+
+/* Return first free Tcam Index, seeking from start to end */
+STATIC
+INT32
+Mvpp2PrsTcamFirstFree (
+ IN MVPP2_SHARED *Priv,
+ IN UINT8 Start,
+ IN UINT8 End
+ )
+{
+ INT32 Tid;
+
+ if (Start > End) {
+ Mvpp2SwapVariables (Start, End);
+ }
+
+ if (End >= MVPP2_PRS_TCAM_SRAM_SIZE) {
+ End = MVPP2_PRS_TCAM_SRAM_SIZE - 1;
+ }
+
+ for (Tid = Start; Tid <= End; Tid++) {
+ if (!Priv->PrsShadow[Tid].Valid) {
+ return Tid;
+ }
+ }
+
+ return MVPP2_EINVAL;
+}
+
+/* Enable/disable dropping all mac Da's */
+STATIC
+VOID
+Mvpp2PrsMacDropAllSet (
+ IN MVPP2_SHARED *Priv,
+ IN INT32 PortId,
+ IN BOOLEAN Add
+ )
+{
+ MVPP2_PRS_ENTRY Pe;
+
+ if (Priv->PrsShadow[MVPP2_PE_DROP_ALL].Valid) {
+ /* Entry exist - update PortId only */
+ Pe.Index = MVPP2_PE_DROP_ALL;
+ Mvpp2PrsHwRead (Priv, &Pe);
+ } else {
+ /* Entry doesn't exist - create new */
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_MAC);
+ Pe.Index = MVPP2_PE_DROP_ALL;
+
+ /* Non-promiscuous mode for all Ports - DROP unknown packets */
+ Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_DROP_MASK, MVPP2_PRS_RI_DROP_MASK);
+
+ Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS);
+
+ /* Update shadow table */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_MAC);
+
+ /* Mask all Ports */
+ Mvpp2PrsTcamPortMapSet (&Pe, 0);
+ }
+
+ /* Update PortId Mask */
+ Mvpp2PrsTcamPortSet (&Pe, PortId, Add);
+
+ Mvpp2PrsHwWrite (Priv, &Pe);
+}
+
+/* Set port to promiscuous mode */
+VOID
+Mvpp2PrsMacPromiscSet (
+ IN MVPP2_SHARED *Priv,
+ IN INT32 PortId,
+ IN BOOLEAN Add
+ )
+{
+ MVPP2_PRS_ENTRY Pe;
+
+ /* Promiscuous mode - Accept unknown packets */
+
+ if (Priv->PrsShadow[MVPP2_PE_MAC_PROMISCUOUS].Valid) {
+ /* Entry exist - update port only */
+ Pe.Index = MVPP2_PE_MAC_PROMISCUOUS;
+ Mvpp2PrsHwRead (Priv, &Pe);
+ } else {
+ /* Entry doesn't exist - create new */
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_MAC);
+ Pe.Index = MVPP2_PE_MAC_PROMISCUOUS;
+
+ /* Continue - set next lookup */
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_DSA);
+
+ /* Set result info bits */
+ Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L2_UCAST, MVPP2_PRS_RI_L2_CAST_MASK);
+
+ /* Shift to ethertype with 2 of MAC Address length */
+ Mvpp2PrsSramShiftSet (&Pe, 2 * MV_ETH_ALEN, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
+
+ /* Mask all Ports */
+ Mvpp2PrsTcamPortMapSet (&Pe, 0);
+
+ /* Update shadow table */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_MAC);
+ }
+
+ /* Update port Mask */
+ Mvpp2PrsTcamPortSet (&Pe, PortId, Add);
+
+ Mvpp2PrsHwWrite (Priv, &Pe);
+}
+
+/* Accept multicast */
+VOID
+Mvpp2PrsMacMultiSet (
+ IN MVPP2_SHARED *Priv,
+ IN INT32 PortId,
+ IN INT32 Index,
+ IN BOOLEAN Add
+ )
+{
+ MVPP2_PRS_ENTRY Pe;
+ UINT8 DaMc;
+
+ /*
+ * Ethernet multicast Address first Byte is
+ * 0x01 for IPv4 and 0x33 for IPv6
+ */
+ DaMc = (Index == MVPP2_PE_MAC_MC_ALL) ? 0x01 : 0x33;
+
+ if (Priv->PrsShadow[Index].Valid) {
+ /* Entry exist - update port only */
+ Pe.Index = Index;
+ Mvpp2PrsHwRead (Priv, &Pe);
+ } else {
+ /* Entry doesn't exist - create new */
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_MAC);
+ Pe.Index = Index;
+
+ /* Continue - set next lookup */
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_DSA);
+
+ /* Set result info bits */
+ Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L2_MCAST, MVPP2_PRS_RI_L2_CAST_MASK);
+
+ /* Update Tcam entry data first Byte */
+ Mvpp2PrsTcamDataByteSet (&Pe, 0, DaMc, 0xff);
+
+ /* Shift to ethertype */
+ Mvpp2PrsSramShiftSet (&Pe, 2 * MV_ETH_ALEN, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
+
+ /* Mask all ports */
+ Mvpp2PrsTcamPortMapSet (&Pe, 0);
+
+ /* Update shadow table */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_MAC);
+ }
+
+ /* Update port Mask */
+ Mvpp2PrsTcamPortSet (&Pe, PortId, Add);
+
+ Mvpp2PrsHwWrite (Priv, &Pe);
+}
+
+/* Set entry for dsa packets */
+STATIC
+VOID
+Mvpp2PrsDsaTagSet (
+ IN MVPP2_SHARED *Priv,
+ IN INT32 PortId,
+ IN BOOLEAN Add,
+ IN BOOLEAN Tagged,
+ IN BOOLEAN Extend
+ )
+{
+ MVPP2_PRS_ENTRY Pe;
+ INT32 Tid, Shift;
+
+ if (Extend) {
+ Tid = Tagged ? MVPP2_PE_EDSA_TAGGED : MVPP2_PE_EDSA_UNTAGGED;
+ Shift = 8;
+ } else {
+ Tid = Tagged ? MVPP2_PE_DSA_TAGGED : MVPP2_PE_DSA_UNTAGGED;
+ Shift = 4;
+ }
+
+ if (Priv->PrsShadow[Tid].Valid) {
+ /* Entry exist - update port only */
+ Pe.Index = Tid;
+ Mvpp2PrsHwRead (Priv, &Pe);
+ } else {
+ /* Entry doesn't exist - create new */
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_DSA);
+ Pe.Index = Tid;
+
+ /* Shift 4 bytes if DSA tag or 8 bytes in case of EDSA tag*/
+ Mvpp2PrsSramShiftSet (&Pe, Shift, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
+
+ /* Update shadow table */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_DSA);
+
+ if (Tagged) {
+ /* Set Tagged bit in DSA tag */
+ Mvpp2PrsTcamDataByteSet (&Pe, 0, MVPP2_PRS_TCAM_DSA_TAGGED_BIT, MVPP2_PRS_TCAM_DSA_TAGGED_BIT);
+
+ /* Clear all ai bits for next iteration */
+ Mvpp2PrsSramAiUpdate (&Pe, 0, MVPP2_PRS_SRAM_AI_MASK);
+
+ /* If packet is Tagged continue check vlans */
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_VLAN);
+ } else {
+ /* Set result info bits to 'no vlans' */
+ Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_VLAN_NONE, MVPP2_PRS_RI_VLAN_MASK);
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_L2);
+ }
+
+ /* Mask all Ports */
+ Mvpp2PrsTcamPortMapSet (&Pe, 0);
+ }
+
+ /* Update port Mask */
+ Mvpp2PrsTcamPortSet (&Pe, PortId, Add);
+
+ Mvpp2PrsHwWrite (Priv, &Pe);
+}
+
+/* Set entry for dsa ethertype */
+STATIC
+VOID
+Mvpp2PrsDsaTagEthertypeSet (
+ IN MVPP2_SHARED *Priv,
+ IN INT32 PortId,
+ IN BOOLEAN Add,
+ IN BOOLEAN Tagged,
+ IN BOOLEAN Extend
+ )
+{
+ MVPP2_PRS_ENTRY Pe;
+ INT32 Tid, Shift, PortMask;
+
+ if (Extend) {
+ Tid = Tagged ? MVPP2_PE_ETYPE_EDSA_TAGGED : MVPP2_PE_ETYPE_EDSA_UNTAGGED;
+ PortMask = 0;
+ Shift = 8;
+ } else {
+ Tid = Tagged ? MVPP2_PE_ETYPE_DSA_TAGGED : MVPP2_PE_ETYPE_DSA_UNTAGGED;
+ PortMask = MVPP2_PRS_PORT_MASK;
+ Shift = 4;
+ }
+
+ if (Priv->PrsShadow[Tid].Valid) {
+ /* Entry exist - update PortId only */
+ Pe.Index = Tid;
+ Mvpp2PrsHwRead (Priv, &Pe);
+ } else {
+ /* Entry doesn't exist - create new */
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_DSA);
+ Pe.Index = Tid;
+
+ /*
+ * Set ethertype at offset 0 for DSA and
+ * clear it at offset 2 - obtained from Marvell.
+ */
+ Mvpp2PrsMatchEtype (&Pe, 0, MV_ETH_P_EDSA);
+ Mvpp2PrsMatchEtype (&Pe, 2, 0);
+
+ Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_DSA_MASK,
+ MVPP2_PRS_RI_DSA_MASK);
+
+ /* Shift ethertype + 2 Byte reserved + tag */
+ Mvpp2PrsSramShiftSet (&Pe, 2 + MVPP2_ETH_TYPE_LEN + Shift,
+ MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
+
+ /* Update shadow table */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_DSA);
+
+ if (Tagged) {
+ /* Set Tagged bit in DSA tag */
+ Mvpp2PrsTcamDataByteSet (
+ &Pe,
+ MVPP2_ETH_TYPE_LEN + 2 + 3,
+ MVPP2_PRS_TCAM_DSA_TAGGED_BIT,
+ MVPP2_PRS_TCAM_DSA_TAGGED_BIT
+ );
+
+ /* Clear all ai bits for next iteration */
+ Mvpp2PrsSramAiUpdate (&Pe, 0, MVPP2_PRS_SRAM_AI_MASK);
+
+ /* If packet is Tagged continue check vlans */
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_VLAN);
+ } else {
+ /* Set result info bits to 'no vlans' */
+ Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_VLAN_NONE, MVPP2_PRS_RI_VLAN_MASK);
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_L2);
+ }
+
+ /* Mask/unmask all ports, depending on dsa type */
+ Mvpp2PrsTcamPortMapSet (&Pe, PortMask);
+ }
+
+ /* Update port Mask */
+ Mvpp2PrsTcamPortSet (&Pe, PortId, Add);
+
+ Mvpp2PrsHwWrite (Priv, &Pe);
+}
+
+/* Search for existing single/triple vlan entry */
+STATIC
+MVPP2_PRS_ENTRY *
+Mvpp2PrsVlanFind (
+ IN MVPP2_SHARED *Priv,
+ IN UINT16 Tpid,
+ IN INT32 Ai
+ )
+{
+ MVPP2_PRS_ENTRY *Pe;
+ INT32 Tid;
+
+ Pe = Mvpp2Alloc (sizeof (*Pe));
+ if (Pe == NULL) {
+ return NULL;
+ }
+
+ Mvpp2PrsTcamLuSet (Pe, MVPP2_PRS_LU_VLAN);
+
+ /* Go through the all entries with MVPP2_PRS_LU_VLAN */
+ for (Tid = MVPP2_PE_FIRST_FREE_TID; Tid <= MVPP2_PE_LAST_FREE_TID; Tid++) {
+ UINT32 RiBits, AiBits;
+ BOOLEAN match;
+
+ if (!Priv->PrsShadow[Tid].Valid || Priv->PrsShadow[Tid].Lu != MVPP2_PRS_LU_VLAN) {
+ continue;
+ }
+
+ Pe->Index = Tid;
+
+ Mvpp2PrsHwRead (Priv, Pe);
+ match = Mvpp2PrsTcamDataCmp (Pe, 0, Mvpp2SwapBytes16 (Tpid));
+ if (!match) {
+ continue;
+ }
+
+ /* Get vlan type */
+ RiBits = Mvpp2PrsSramRiGet (Pe);
+ RiBits &= MVPP2_PRS_RI_VLAN_MASK;
+
+ /* Get current Ai value from Tcam */
+ AiBits = Mvpp2PrsTcamAiGet (Pe);
+
+ /* Clear double vlan bit */
+ AiBits &= ~MVPP2_PRS_DBL_VLAN_AI_BIT;
+
+ if (Ai != AiBits) {
+ continue;
+ }
+
+ if (RiBits == MVPP2_PRS_RI_VLAN_SINGLE || RiBits == MVPP2_PRS_RI_VLAN_TRIPLE) {
+ return Pe;
+ }
+ }
+
+ Mvpp2Free (Pe);
+
+ return NULL;
+}
+
+/* Add/update single/triple vlan entry */
+INT32
+Mvpp2PrsVlanAdd (
+ IN MVPP2_SHARED *Priv,
+ IN UINT16 Tpid,
+ IN INT32 Ai,
+ IN UINT32 PortMap
+ )
+{
+ MVPP2_PRS_ENTRY *Pe;
+ INT32 TidAux, Tid;
+ INT32 Ret = 0;
+
+ Pe = Mvpp2PrsVlanFind (Priv, Tpid, Ai);
+
+ if (!Pe) {
+ /* Create new Tcam entry */
+ Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_LAST_FREE_TID, MVPP2_PE_FIRST_FREE_TID);
+ if (Tid < 0) {
+ return Tid;
+ }
+
+ Pe = Mvpp2Alloc (sizeof (*Pe));
+ if (Pe == NULL) {
+ return MVPP2_ENOMEM;
+ }
+
+ /* Get last double vlan Tid */
+ for (TidAux = MVPP2_PE_LAST_FREE_TID; TidAux >= MVPP2_PE_FIRST_FREE_TID; TidAux--) {
+ UINT32 RiBits;
+
+ if (!Priv->PrsShadow[TidAux].Valid || Priv->PrsShadow[TidAux].Lu != MVPP2_PRS_LU_VLAN) {
+ continue;
+ }
+
+ Pe->Index = TidAux;
+ Mvpp2PrsHwRead (Priv, Pe);
+ RiBits = Mvpp2PrsSramRiGet (Pe);
+ if ((RiBits & MVPP2_PRS_RI_VLAN_MASK) == MVPP2_PRS_RI_VLAN_DOUBLE) {
+ break;
+ }
+ }
+
+ if (Tid <= TidAux) {
+ Ret = MVPP2_EINVAL;
+ goto error;
+ }
+
+ Mvpp2Memset (Pe, 0 , sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (Pe, MVPP2_PRS_LU_VLAN);
+ Pe->Index = Tid;
+
+ /* Set VLAN type's offset to 0 bytes - obtained from Marvell */
+ Mvpp2PrsMatchEtype (Pe, 0, Tpid);
+
+ Mvpp2PrsSramNextLuSet (Pe, MVPP2_PRS_LU_L2);
+
+ /* Shift 4 bytes - skip 1 vlan tag */
+ Mvpp2PrsSramShiftSet (Pe, MVPP2_VLAN_TAG_LEN,
+ MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
+
+ /* Clear all Ai bits for next iteration */
+ Mvpp2PrsSramAiUpdate (Pe, 0, MVPP2_PRS_SRAM_AI_MASK);
+
+ if (Ai == MVPP2_PRS_SINGLE_VLAN_AI) {
+ Mvpp2PrsSramRiUpdate (Pe, MVPP2_PRS_RI_VLAN_SINGLE, MVPP2_PRS_RI_VLAN_MASK);
+ } else {
+ Ai |= MVPP2_PRS_DBL_VLAN_AI_BIT;
+ Mvpp2PrsSramRiUpdate (Pe, MVPP2_PRS_RI_VLAN_TRIPLE, MVPP2_PRS_RI_VLAN_MASK);
+ }
+
+ Mvpp2PrsTcamAiUpdate (Pe, Ai, MVPP2_PRS_SRAM_AI_MASK);
+
+ Mvpp2PrsShadowSet (Priv, Pe->Index, MVPP2_PRS_LU_VLAN);
+ }
+
+ /* Update Ports' Mask */
+ Mvpp2PrsTcamPortMapSet (Pe, PortMap);
+ Mvpp2PrsHwWrite (Priv, Pe);
+
+error:
+ Mvpp2Free (Pe);
+
+ return Ret;
+}
+
+/* Get first free double vlan ai number */
+INT32
+Mvpp2PrsDoubleVlanAiFreeGet (
+ IN MVPP2_SHARED *Priv
+ )
+{
+ INT32 i;
+
+ for (i = 1; i < MVPP2_PRS_DBL_VLANS_MAX; i++) {
+ if (!Priv->PrsDoubleVlans[i]) {
+ return i;
+ }
+ }
+
+ return MVPP2_EINVAL;
+}
+
+/* Search for existing double vlan entry */
+MVPP2_PRS_ENTRY *Mvpp2PrsDoubleVlanFind (
+ IN MVPP2_SHARED *Priv,
+ IN UINT16 Tpid1,
+ IN UINT16 Tpid2
+ )
+{
+ MVPP2_PRS_ENTRY *Pe;
+ INT32 Tid;
+
+ Pe = Mvpp2Alloc (sizeof (*Pe));
+ if (Pe == NULL) {
+ return NULL;
+ }
+
+ Mvpp2PrsTcamLuSet (Pe, MVPP2_PRS_LU_VLAN);
+
+ /* Go through the all entries with MVPP2_PRS_LU_VLAN */
+ for (Tid = MVPP2_PE_FIRST_FREE_TID; Tid <= MVPP2_PE_LAST_FREE_TID; Tid++) {
+ UINT32 RiMask;
+ BOOLEAN match;
+
+ if (!Priv->PrsShadow[Tid].Valid || Priv->PrsShadow[Tid].Lu != MVPP2_PRS_LU_VLAN) {
+ continue;
+ }
+
+ Pe->Index = Tid;
+ Mvpp2PrsHwRead (Priv, Pe);
+
+ match = Mvpp2PrsTcamDataCmp (Pe, 0, Mvpp2SwapBytes16 (Tpid1)) &&
+ Mvpp2PrsTcamDataCmp (Pe, 4, Mvpp2SwapBytes16 (Tpid2));
+
+ if (!match) {
+ continue;
+ }
+
+ RiMask = Mvpp2PrsSramRiGet (Pe) & MVPP2_PRS_RI_VLAN_MASK;
+ if (RiMask == MVPP2_PRS_RI_VLAN_DOUBLE) {
+ return Pe;
+ }
+ }
+
+ Mvpp2Free (Pe);
+
+ return NULL;
+}
+
+/* Add or update double vlan entry */
+INT32
+Mvpp2PrsDoubleVlanAdd (
+ IN MVPP2_SHARED *Priv,
+ IN UINT16 Tpid1,
+ IN UINT16 Tpid2,
+ IN UINT32 PortMap
+ )
+{
+ MVPP2_PRS_ENTRY *Pe;
+ INT32 TidAux, Tid, Ai, Ret = 0;
+
+ Pe = Mvpp2PrsDoubleVlanFind (Priv, Tpid1, Tpid2);
+
+ if (!Pe) {
+ /* Create new Tcam entry */
+ Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
+ if (Tid < 0) {
+ return Tid;
+ }
+
+ Pe = Mvpp2Alloc (sizeof (*Pe));
+ if (Pe == NULL) {
+ return MVPP2_ENOMEM;
+ }
+
+ /* Set Ai value for new double vlan entry */
+ Ai = Mvpp2PrsDoubleVlanAiFreeGet (Priv);
+ if (Ai < 0) {
+ Ret = Ai;
+ goto error;
+ }
+
+ /* Get first single/triple vlan Tid */
+ for (TidAux = MVPP2_PE_FIRST_FREE_TID; TidAux <= MVPP2_PE_LAST_FREE_TID; TidAux++) {
+ UINT32 RiBits;
+
+ if (!Priv->PrsShadow[TidAux].Valid || Priv->PrsShadow[TidAux].Lu != MVPP2_PRS_LU_VLAN) {
+ continue;
+ }
+
+ Pe->Index = TidAux;
+ Mvpp2PrsHwRead (Priv, Pe);
+ RiBits = Mvpp2PrsSramRiGet (Pe);
+ RiBits &= MVPP2_PRS_RI_VLAN_MASK;
+
+ if (RiBits == MVPP2_PRS_RI_VLAN_SINGLE || RiBits == MVPP2_PRS_RI_VLAN_TRIPLE) {
+ break;
+ }
+ }
+
+ if (Tid >= TidAux) {
+ Ret = MVPP2_ERANGE;
+ goto error;
+ }
+
+ Mvpp2Memset (Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (Pe, MVPP2_PRS_LU_VLAN);
+ Pe->Index = Tid;
+
+ Priv->PrsDoubleVlans[Ai] = TRUE;
+
+ /* Set both VLAN types' offsets to 0 and 4 bytes - obtained from Marvell */
+ Mvpp2PrsMatchEtype (Pe, 0, Tpid1);
+ Mvpp2PrsMatchEtype (Pe, 4, Tpid2);
+
+ Mvpp2PrsSramNextLuSet (Pe, MVPP2_PRS_LU_VLAN);
+
+ /* Shift 8 bytes - skip 2 vlan tags */
+ Mvpp2PrsSramShiftSet (Pe, 2 * MVPP2_VLAN_TAG_LEN, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
+ Mvpp2PrsSramRiUpdate (Pe, MVPP2_PRS_RI_VLAN_DOUBLE, MVPP2_PRS_RI_VLAN_MASK);
+ Mvpp2PrsSramAiUpdate (Pe, Ai | MVPP2_PRS_DBL_VLAN_AI_BIT, MVPP2_PRS_SRAM_AI_MASK);
+
+ Mvpp2PrsShadowSet (Priv, Pe->Index, MVPP2_PRS_LU_VLAN);
+ }
+
+ /* Update Ports' Mask */
+ Mvpp2PrsTcamPortMapSet (Pe, PortMap);
+ Mvpp2PrsHwWrite (Priv, Pe);
+
+error:
+ Mvpp2Free (Pe);
+ return Ret;
+}
+
+/* IPv4 header parsing for fragmentation and L4 Offset */
+STATIC
+INT32
+Mvpp2PrsIp4Proto (
+ IN MVPP2_SHARED *Priv,
+ IN UINT16 Proto,
+ IN UINT32 Ri,
+ IN UINT32 RiMask
+ )
+{
+ MVPP2_PRS_ENTRY Pe;
+ INT32 Tid;
+
+ if ((Proto != MV_IPPR_TCP) && (Proto != MV_IPPR_UDP) && (Proto != MV_IPPR_IGMP)) {
+ return MVPP2_EINVAL;
+ }
+
+ /* Fragmented packet */
+ Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
+ if (Tid < 0) {
+ return Tid;
+ }
+
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP4);
+ Pe.Index = Tid;
+
+ /* Set next Lu to IPv4 - 12 bytes shift */
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_IP4);
+ Mvpp2PrsSramShiftSet (&Pe, 12, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
+
+ /* Set L4 offset 4 bytes relative IPv4 header size (current position) */
+ Mvpp2PrsSramOffsetSet (
+ &Pe,
+ MVPP2_PRS_SRAM_UDF_TYPE_L4,
+ sizeof (Mvpp2Iphdr) - 4,
+ MVPP2_PRS_SRAM_OP_SEL_UDF_ADD
+ );
+
+ Mvpp2PrsSramAiUpdate (&Pe, MVPP2_PRS_IPV4_DIP_AI_BIT, MVPP2_PRS_IPV4_DIP_AI_BIT);
+ Mvpp2PrsSramRiUpdate (&Pe, Ri | MVPP2_PRS_RI_IP_FRAG_MASK, RiMask | MVPP2_PRS_RI_IP_FRAG_MASK);
+
+ Mvpp2PrsTcamDataByteSet (&Pe, 5, Proto, MVPP2_PRS_TCAM_PROTO_MASK);
+ Mvpp2PrsTcamAiUpdate (&Pe, 0, MVPP2_PRS_IPV4_DIP_AI_BIT);
+
+ /* Unmask all Ports */
+ Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
+
+ /* Update shadow table and hw entry */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP4);
+ Mvpp2PrsHwWrite (Priv, &Pe);
+
+ /* Not fragmented packet */
+ Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
+ if (Tid < 0) {
+ return Tid;
+ }
+
+ Pe.Index = Tid;
+
+ /* Clear Ri before updating */
+ Pe.Sram.Word[MVPP2_PRS_SRAM_RI_WORD] = 0x0;
+ Pe.Sram.Word[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0;
+ Mvpp2PrsSramRiUpdate (&Pe, Ri, RiMask);
+
+ Mvpp2PrsTcamDataByteSet (&Pe, 2, 0x00, MVPP2_PRS_TCAM_PROTO_MASK_L);
+ Mvpp2PrsTcamDataByteSet (&Pe, 3, 0x00, MVPP2_PRS_TCAM_PROTO_MASK);
+
+ /* Update shadow table and hw entry */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP4);
+ Mvpp2PrsHwWrite (Priv, &Pe);
+
+ return 0;
+}
+
+/* IPv4 L3 multicast or broadcast */
+STATIC
+INT32
+Mvpp2PrsIp4Cast (
+ IN MVPP2_SHARED *Priv,
+ IN UINT16 L3Cast
+ )
+{
+ MVPP2_PRS_ENTRY Pe;
+ INT32 Mask, Tid;
+
+ Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
+ if (Tid < 0) {
+ return Tid;
+ }
+
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP4);
+ Pe.Index = Tid;
+
+ switch (L3Cast) {
+ case MVPP2_PRS_L3_MULTI_CAST:
+ Mvpp2PrsTcamDataByteSet (&Pe, 0, MVPP2_PRS_IPV4_MC, MVPP2_PRS_IPV4_MC_MASK);
+ Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_MCAST, MVPP2_PRS_RI_L3_ADDR_MASK);
+ break;
+ case MVPP2_PRS_L3_BROAD_CAST:
+ Mask = MVPP2_PRS_IPV4_BC_MASK;
+ Mvpp2PrsTcamDataByteSet (&Pe, 0, Mask, Mask);
+ Mvpp2PrsTcamDataByteSet (&Pe, 1, Mask, Mask);
+ Mvpp2PrsTcamDataByteSet (&Pe, 2, Mask, Mask);
+ Mvpp2PrsTcamDataByteSet (&Pe, 3, Mask, Mask);
+ Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_BCAST, MVPP2_PRS_RI_L3_ADDR_MASK);
+ break;
+ default:
+ return MVPP2_EINVAL;
+ }
+
+ /* Finished: go to Flowid generation */
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS);
+ Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
+
+ Mvpp2PrsTcamAiUpdate (&Pe, MVPP2_PRS_IPV4_DIP_AI_BIT, MVPP2_PRS_IPV4_DIP_AI_BIT);
+
+ /* Unmask all Ports */
+ Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
+
+ /* Update shadow table and hw entry */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP4);
+ Mvpp2PrsHwWrite (Priv, &Pe);
+
+ return 0;
+}
+
+/* Set entries for protocols over IPv6 */
+STATIC
+INT32
+Mvpp2PrsIp6Proto (
+ IN MVPP2_SHARED *Priv,
+ IN UINT16 Proto,
+ IN UINT32 Ri,
+ IN UINT32 RiMask
+ )
+{
+ MVPP2_PRS_ENTRY Pe;
+ INT32 Tid;
+
+ if ((Proto != MV_IPPR_TCP) && (Proto != MV_IPPR_UDP) &&
+ (Proto != MV_IPPR_ICMPV6) && (Proto != MV_IPPR_IPIP))
+ {
+ return MVPP2_EINVAL;
+ }
+
+ Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
+ if (Tid < 0) {
+ return Tid;
+ }
+
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP6);
+ Pe.Index = Tid;
+
+ /* Finished: go to Flowid generation */
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS);
+ Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
+ Mvpp2PrsSramRiUpdate (&Pe, Ri, RiMask);
+
+ /* Set offset for protocol 6 bytes relative to IPv6 header size */
+ Mvpp2PrsSramOffsetSet (
+ &Pe,
+ MVPP2_PRS_SRAM_UDF_TYPE_L4,
+ sizeof (Mvpp2Ipv6hdr) - 6,
+ MVPP2_PRS_SRAM_OP_SEL_UDF_ADD
+ );
+
+ Mvpp2PrsTcamDataByteSet (&Pe, 0, Proto, MVPP2_PRS_TCAM_PROTO_MASK);
+ Mvpp2PrsTcamAiUpdate (&Pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT, MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
+
+ /* Unmask all Ports */
+ Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
+
+ /* Write HW */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP6);
+ Mvpp2PrsHwWrite (Priv, &Pe);
+
+ return 0;
+}
+
+/* IPv6 L3 multicast entry */
+STATIC
+INT32
+Mvpp2PrsIp6Cast (
+ IN MVPP2_SHARED *Priv,
+ IN UINT16 L3Cast
+ )
+{
+ MVPP2_PRS_ENTRY Pe;
+ INT32 Tid;
+
+ if (L3Cast != MVPP2_PRS_L3_MULTI_CAST) {
+ return MVPP2_EINVAL;
+ }
+
+ Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
+ if (Tid < 0) {
+ return Tid;
+ }
+
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP6);
+ Pe.Index = Tid;
+
+ /* Finished: go to Flowid generation */
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_IP6);
+ Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_MCAST, MVPP2_PRS_RI_L3_ADDR_MASK);
+ Mvpp2PrsSramAiUpdate (&Pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT, MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
+
+ /* Shift back to IPv6 by 18 bytes - byte count provided by Marvell */
+ Mvpp2PrsSramShiftSet (&Pe, -18, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
+
+ Mvpp2PrsTcamDataByteSet (&Pe, 0, MVPP2_PRS_IPV6_MC, MVPP2_PRS_IPV6_MC_MASK);
+ Mvpp2PrsTcamAiUpdate (&Pe, 0, MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
+
+ /* Unmask all Ports */
+ Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
+
+ /* Update shadow table and hw entry */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP6);
+ Mvpp2PrsHwWrite (Priv, &Pe);
+
+ return 0;
+}
+
+/* Parser per-Port initialization */
+STATIC
+VOID
+Mvpp2PrsHwPortInit (
+ IN MVPP2_SHARED *Priv,
+ IN INT32 PortId,
+ IN INT32 LuFirst,
+ IN INT32 LuMax,
+ IN INT32 Offset
+ )
+{
+ UINT32 Val;
+
+ /* Set lookup ID */
+ Val = Mvpp2Read (Priv, MVPP2_PRS_INIT_LOOKUP_REG);
+ Val &= ~MVPP2_PRS_PORT_LU_MASK (PortId);
+ Val |= MVPP2_PRS_PORT_LU_VAL (PortId, LuFirst);
+ Mvpp2Write (Priv, MVPP2_PRS_INIT_LOOKUP_REG, Val);
+
+ /* Set maximum number of loops for packet received from PortId */
+ Val = Mvpp2Read (Priv, MVPP2_PRS_MAX_LOOP_REG(PortId));
+ Val &= ~MVPP2_PRS_MAX_LOOP_MASK (PortId);
+ Val |= MVPP2_PRS_MAX_LOOP_VAL (PortId, LuMax);
+ Mvpp2Write (Priv, MVPP2_PRS_MAX_LOOP_REG(PortId), Val);
+
+ /*
+ * Set initial Offset for packet header extraction for the first
+ * searching loop
+ */
+ Val = Mvpp2Read (Priv, MVPP2_PRS_INIT_OFFS_REG(PortId));
+ Val &= ~MVPP2_PRS_INIT_OFF_MASK (PortId);
+ Val |= MVPP2_PRS_INIT_OFF_VAL (PortId, Offset);
+ Mvpp2Write (Priv, MVPP2_PRS_INIT_OFFS_REG(PortId), Val);
+}
+
+/* Default Flow entries initialization for all Ports */
+STATIC
+VOID
+Mvpp2PrsDefFlowInit (
+ IN MVPP2_SHARED *Priv
+ )
+{
+ MVPP2_PRS_ENTRY Pe;
+ INT32 PortId;
+
+ for (PortId = 0; PortId < MVPP2_MAX_PORTS; PortId++) {
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_FLOWS);
+ Pe.Index = MVPP2_PE_FIRST_DEFAULT_FLOW - PortId;
+
+ /* Mask all Ports */
+ Mvpp2PrsTcamPortMapSet (&Pe, 0);
+
+ /* Set Flow ID*/
+ Mvpp2PrsSramAiUpdate (&Pe, PortId, MVPP2_PRS_FLOW_ID_MASK);
+ Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_DONE_BIT, 1);
+
+ /* Update shadow table and hw entry */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_FLOWS);
+ Mvpp2PrsHwWrite (Priv, &Pe);
+ }
+}
+
+/* Set default entry for Marvell Header field */
+STATIC
+VOID
+Mvpp2PrsMhInit (
+ IN MVPP2_SHARED *Priv
+ )
+{
+ MVPP2_PRS_ENTRY Pe;
+
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+
+ Pe.Index = MVPP2_PE_MH_DEFAULT;
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_MH);
+ Mvpp2PrsSramShiftSet (&Pe, MVPP2_MH_SIZE, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_MAC);
+
+ /* Unmask all Ports */
+ Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
+
+ /* Update shadow table and hw entry */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_MH);
+ Mvpp2PrsHwWrite (Priv, &Pe);
+}
+
+/*
+ * Set default entires (place holder) for promiscuous, non-promiscuous and
+ * multicast MAC Addresses
+ */
+STATIC
+VOID
+Mvpp2PrsMacInit (
+ IN MVPP2_SHARED *Priv
+ )
+{
+ MVPP2_PRS_ENTRY Pe;
+
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+
+ /* Non-promiscuous mode for all Ports - DROP unknown packets */
+ Pe.Index = MVPP2_PE_MAC_NON_PROMISCUOUS;
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_MAC);
+
+ Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_DROP_MASK, MVPP2_PRS_RI_DROP_MASK);
+ Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS);
+
+ /* Unmask all Ports */
+ Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
+
+ /* Update shadow table and hw entry */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_MAC);
+ Mvpp2PrsHwWrite (Priv, &Pe);
+
+ /* Place holders only - no Ports */
+ Mvpp2PrsMacDropAllSet (Priv, 0, FALSE);
+ Mvpp2PrsMacPromiscSet (Priv, 0, FALSE);
+ Mvpp2PrsMacMultiSet (Priv, MVPP2_PE_MAC_MC_ALL, 0, FALSE);
+ Mvpp2PrsMacMultiSet (Priv, MVPP2_PE_MAC_MC_IP6, 0, FALSE);
+}
+
+/* Set default entries for various types of dsa packets */
+STATIC
+VOID
+Mvpp2PrsDsaInit (
+ IN MVPP2_SHARED *Priv
+ )
+{
+ MVPP2_PRS_ENTRY Pe;
+
+ /* None tagged EDSA entry - place holder */
+ Mvpp2PrsDsaTagSet (Priv, 0, FALSE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
+
+ /* Tagged EDSA entry - place holder */
+ Mvpp2PrsDsaTagSet (Priv, 0, FALSE, MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
+
+ /* None tagged DSA entry - place holder */
+ Mvpp2PrsDsaTagSet (Priv, 0, FALSE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
+
+ /* Tagged DSA entry - place holder */
+ Mvpp2PrsDsaTagSet (Priv, 0, FALSE, MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
+
+ /* None tagged EDSA ethertype entry - place holder*/
+ Mvpp2PrsDsaTagEthertypeSet (Priv, 0, FALSE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
+
+ /* Tagged EDSA ethertype entry - place holder*/
+ Mvpp2PrsDsaTagEthertypeSet (Priv, 0, FALSE, MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
+
+ /* None tagged DSA ethertype entry */
+ Mvpp2PrsDsaTagEthertypeSet (Priv, 0, TRUE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
+
+ /* Tagged DSA ethertype entry */
+ Mvpp2PrsDsaTagEthertypeSet (Priv, 0, TRUE, MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
+
+ /* Set default entry, in case DSA or EDSA tag not found */
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_DSA);
+ Pe.Index = MVPP2_PE_DSA_DEFAULT;
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_VLAN);
+
+ /* Shift 0 bytes */
+ Mvpp2PrsSramShiftSet (&Pe, 0, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_MAC);
+
+ /* Clear all Sram ai bits for next iteration */
+ Mvpp2PrsSramAiUpdate (&Pe, 0, MVPP2_PRS_SRAM_AI_MASK);
+
+ /* Unmask all Ports */
+ Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
+
+ Mvpp2PrsHwWrite (Priv, &Pe);
+}
+
+/* Match basic ethertypes */
+STATIC
+INT32
+Mvpp2PrsEtypeInit (
+ IN MVPP2_SHARED *Priv
+ )
+{
+ MVPP2_PRS_ENTRY Pe;
+ INT32 Tid;
+
+ /* Ethertype: PPPoE */
+ Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
+ if (Tid < 0) {
+ return Tid;
+ }
+
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_L2);
+ Pe.Index = Tid;
+
+ /* Set PPPoE type offset to 0 - obtained from Marvell */
+ Mvpp2PrsMatchEtype (&Pe, 0, MV_ETH_P_PPP_SES);
+
+ Mvpp2PrsSramShiftSet (&Pe, MVPP2_PPPOE_HDR_SIZE, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_PPPOE);
+ Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_PPPOE_MASK, MVPP2_PRS_RI_PPPOE_MASK);
+
+ /* Update shadow table and hw entry */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_L2);
+ Priv->PrsShadow[Pe.Index].Udf = MVPP2_PRS_UDF_L2_DEF;
+ Priv->PrsShadow[Pe.Index].Finish = FALSE;
+ Mvpp2PrsShadowRiSet (Priv, Pe.Index, MVPP2_PRS_RI_PPPOE_MASK, MVPP2_PRS_RI_PPPOE_MASK);
+ Mvpp2PrsHwWrite (Priv, &Pe);
+
+ /* Ethertype: ARP */
+ Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
+ if (Tid < 0) {
+ return Tid;
+ }
+
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_L2);
+ Pe.Index = Tid;
+
+ /* Set ARP type offset to 0 - obtained from Marvell */
+ Mvpp2PrsMatchEtype (&Pe, 0, MV_ETH_P_ARP);
+
+ /* Generate Flow in the next iteration*/
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS);
+ Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
+ Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_ARP, MVPP2_PRS_RI_L3_PROTO_MASK);
+
+ /* Set L3 Offset */
+ Mvpp2PrsSramOffsetSet (&Pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
+
+ /* Update shadow table and hw entry */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_L2);
+ Priv->PrsShadow[Pe.Index].Udf = MVPP2_PRS_UDF_L2_DEF;
+ Priv->PrsShadow[Pe.Index].Finish = TRUE;
+ Mvpp2PrsShadowRiSet (Priv, Pe.Index, MVPP2_PRS_RI_L3_ARP, MVPP2_PRS_RI_L3_PROTO_MASK);
+ Mvpp2PrsHwWrite (Priv, &Pe);
+
+ /* Ethertype: LBTD */
+ Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
+ if (Tid < 0) {
+ return Tid;
+ }
+
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_L2);
+ Pe.Index = Tid;
+
+ /* Set LBTD type offset to 0 - obtained from Marvell */
+ Mvpp2PrsMatchEtype (&Pe, 0, MVPP2_IP_LBDT_TYPE);
+
+ /* Generate Flow in the next iteration*/
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS);
+ Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
+ Mvpp2PrsSramRiUpdate (
+ &Pe,
+ MVPP2_PRS_RI_CPU_CODE_RX_SPEC | MVPP2_PRS_RI_UDF3_RX_SPECIAL,
+ MVPP2_PRS_RI_CPU_CODE_MASK | MVPP2_PRS_RI_UDF3_MASK
+ );
+
+ /* Set L3 Offset */
+ Mvpp2PrsSramOffsetSet (&Pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
+
+ /* Update shadow table and hw entry */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_L2);
+ Priv->PrsShadow[Pe.Index].Udf = MVPP2_PRS_UDF_L2_DEF;
+ Priv->PrsShadow[Pe.Index].Finish = TRUE;
+ Mvpp2PrsShadowRiSet (
+ Priv,
+ Pe.Index,
+ MVPP2_PRS_RI_CPU_CODE_RX_SPEC | MVPP2_PRS_RI_UDF3_RX_SPECIAL,
+ MVPP2_PRS_RI_CPU_CODE_MASK | MVPP2_PRS_RI_UDF3_MASK
+ );
+
+ Mvpp2PrsHwWrite (Priv, &Pe);
+
+ /* Ethertype: IPv4 without options */
+ Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
+ if (Tid < 0) {
+ return Tid;
+ }
+
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_L2);
+ Pe.Index = Tid;
+
+ /* Set IPv4 type offset to 0 - obtained from Marvell */
+ Mvpp2PrsMatchEtype (&Pe, 0, MV_ETH_P_IP);
+ Mvpp2PrsTcamDataByteSet (
+ &Pe,
+ MVPP2_ETH_TYPE_LEN,
+ MVPP2_PRS_IPV4_HEAD | MVPP2_PRS_IPV4_IHL,
+ MVPP2_PRS_IPV4_HEAD_MASK | MVPP2_PRS_IPV4_IHL_MASK
+ );
+
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_IP4);
+ Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_IP4, MVPP2_PRS_RI_L3_PROTO_MASK);
+
+ /* Skip EthType + 4 bytes of IP header */
+ Mvpp2PrsSramShiftSet (&Pe, MVPP2_ETH_TYPE_LEN + 4, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
+
+ /* Set L3 Offset */
+ Mvpp2PrsSramOffsetSet (&Pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
+
+ /* Update shadow table and hw entry */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_L2);
+ Priv->PrsShadow[Pe.Index].Udf = MVPP2_PRS_UDF_L2_DEF;
+ Priv->PrsShadow[Pe.Index].Finish = FALSE;
+ Mvpp2PrsShadowRiSet (Priv, Pe.Index, MVPP2_PRS_RI_L3_IP4, MVPP2_PRS_RI_L3_PROTO_MASK);
+ Mvpp2PrsHwWrite (Priv, &Pe);
+
+ /* Ethertype: IPv4 with options */
+ Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
+ if (Tid < 0) {
+ return Tid;
+ }
+
+ Pe.Index = Tid;
+
+ /* Clear Tcam data before updating */
+ Pe.Tcam.Byte[MVPP2_PRS_TCAM_DATA_BYTE(MVPP2_ETH_TYPE_LEN)] = 0x0;
+ Pe.Tcam.Byte[MVPP2_PRS_TCAM_DATA_BYTE_EN(MVPP2_ETH_TYPE_LEN)] = 0x0;
+
+ Mvpp2PrsTcamDataByteSet (&Pe, MVPP2_ETH_TYPE_LEN, MVPP2_PRS_IPV4_HEAD, MVPP2_PRS_IPV4_HEAD_MASK);
+
+ /* Clear Ri before updating */
+ Pe.Sram.Word[MVPP2_PRS_SRAM_RI_WORD] = 0x0;
+ Pe.Sram.Word[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0;
+ Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_IP4_OPT, MVPP2_PRS_RI_L3_PROTO_MASK);
+
+ /* Update shadow table and hw entry */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_L2);
+ Priv->PrsShadow[Pe.Index].Udf = MVPP2_PRS_UDF_L2_DEF;
+ Priv->PrsShadow[Pe.Index].Finish = FALSE;
+ Mvpp2PrsShadowRiSet (Priv, Pe.Index, MVPP2_PRS_RI_L3_IP4_OPT, MVPP2_PRS_RI_L3_PROTO_MASK);
+ Mvpp2PrsHwWrite (Priv, &Pe);
+
+ /* Ethertype: IPv6 without options */
+ Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
+ if (Tid < 0) {
+ return Tid;
+ }
+
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_L2);
+ Pe.Index = Tid;
+
+ /* Set IPv6 type offset to 0 - obtained from Marvell */
+ Mvpp2PrsMatchEtype (&Pe, 0, MV_ETH_P_IPV6);
+
+ /* Skip DIP of IPV6 header - value provided by Marvell */
+ Mvpp2PrsSramShiftSet (&Pe, MVPP2_ETH_TYPE_LEN + 8 + MVPP2_MAX_L3_ADDR_SIZE, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_IP6);
+ Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_IP6, MVPP2_PRS_RI_L3_PROTO_MASK);
+
+ /* Set L3 Offset */
+ Mvpp2PrsSramOffsetSet (&Pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
+
+ /* Update shadow table and hw entry */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_L2);
+ Priv->PrsShadow[Pe.Index].Udf = MVPP2_PRS_UDF_L2_DEF;
+ Priv->PrsShadow[Pe.Index].Finish = FALSE;
+ Mvpp2PrsShadowRiSet (Priv, Pe.Index, MVPP2_PRS_RI_L3_IP6, MVPP2_PRS_RI_L3_PROTO_MASK);
+ Mvpp2PrsHwWrite (Priv, &Pe);
+
+ /* Default entry for MVPP2_PRS_LU_L2 - Unknown ethtype */
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_L2);
+ Pe.Index = MVPP2_PE_ETH_TYPE_UN;
+
+ /* Unmask all Ports */
+ Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
+
+ /* Generate Flow in the next iteration*/
+ Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS);
+ Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_UN, MVPP2_PRS_RI_L3_PROTO_MASK);
+
+ /* Set L3 Offset even it's unknown L3 */
+ Mvpp2PrsSramOffsetSet (&Pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
+
+ /* Update shadow table and hw entry */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_L2);
+ Priv->PrsShadow[Pe.Index].Udf = MVPP2_PRS_UDF_L2_DEF;
+ Priv->PrsShadow[Pe.Index].Finish = TRUE;
+ Mvpp2PrsShadowRiSet (Priv, Pe.Index, MVPP2_PRS_RI_L3_UN, MVPP2_PRS_RI_L3_PROTO_MASK);
+ Mvpp2PrsHwWrite (Priv, &Pe);
+
+ return 0;
+}
+
+/*
+ * Configure vlan entries and detect up to 2 successive VLAN tags.
+ * Possible options:
+ * 0x8100, 0x88A8
+ * 0x8100, 0x8100
+ * 0x8100, 0x88A8
+ */
+STATIC
+INT32
+Mvpp2PrsVlanInit (
+ IN MVPP2_SHARED *Priv
+ )
+{
+ MVPP2_PRS_ENTRY Pe;
+ INT32 Err;
+
+ /* Double VLAN: 0x8100, 0x88A8 */
+ Err = Mvpp2PrsDoubleVlanAdd (Priv, MV_ETH_P_8021Q, MV_ETH_P_8021AD, MVPP2_PRS_PORT_MASK);
+ if (Err != 0) {
+ return Err;
+ }
+
+ /* Double VLAN: 0x8100, 0x8100 */
+ Err = Mvpp2PrsDoubleVlanAdd (Priv, MV_ETH_P_8021Q, MV_ETH_P_8021Q, MVPP2_PRS_PORT_MASK);
+ if (Err != 0) {
+ return Err;
+ }
+
+ /* Single VLAN: 0x88a8 */
+ Err = Mvpp2PrsVlanAdd (Priv, MV_ETH_P_8021AD, MVPP2_PRS_SINGLE_VLAN_AI, MVPP2_PRS_PORT_MASK);
+ if (Err != 0) {
+ return Err;
+ }
+
+ /* Single VLAN: 0x8100 */
+ Err = Mvpp2PrsVlanAdd (Priv, MV_ETH_P_8021Q, MVPP2_PRS_SINGLE_VLAN_AI, MVPP2_PRS_PORT_MASK);
+ if (Err != 0) {
+ return Err;
+ }
+
+ /* Set default double vlan entry */
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_VLAN);
+ Pe.Index = MVPP2_PE_VLAN_DBL;
+
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_L2);
+
+ /* Clear ai for next iterations */
+ Mvpp2PrsSramAiUpdate (&Pe, 0, MVPP2_PRS_SRAM_AI_MASK);
+ Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_VLAN_DOUBLE, MVPP2_PRS_RI_VLAN_MASK);
+
+ Mvpp2PrsTcamAiUpdate (&Pe, MVPP2_PRS_DBL_VLAN_AI_BIT, MVPP2_PRS_DBL_VLAN_AI_BIT);
+
+ /* Unmask all Ports */
+ Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
+
+ /* Update shadow table and hw entry */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_VLAN);
+ Mvpp2PrsHwWrite (Priv, &Pe);
+
+ /* Set default vlan none entry */
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_VLAN);
+ Pe.Index = MVPP2_PE_VLAN_NONE;
+
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_L2);
+ Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_VLAN_NONE, MVPP2_PRS_RI_VLAN_MASK);
+
+ /* Unmask all Ports */
+ Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
+
+ /* Update shadow table and hw entry */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_VLAN);
+ Mvpp2PrsHwWrite (Priv, &Pe);
+
+ return 0;
+}
+
+/* Set entries for PPPoE ethertype */
+STATIC
+INT32
+Mvpp2PrsPppoeInit (
+ IN MVPP2_SHARED *Priv
+ )
+{
+ MVPP2_PRS_ENTRY Pe;
+ INT32 Tid;
+
+ /* IPv4 over PPPoE with options */
+ Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
+ if (Tid < 0) {
+ return Tid;
+ }
+
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_PPPOE);
+ Pe.Index = Tid;
+
+ /* Set IPv4 over PPPoE type offset to 0 - obtained from Marvell */
+ Mvpp2PrsMatchEtype (&Pe, 0, MV_PPP_IP);
+
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_IP4);
+ Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_IP4_OPT, MVPP2_PRS_RI_L3_PROTO_MASK);
+
+ /* Skip EthType + 4 bytes of IP header */
+ Mvpp2PrsSramShiftSet (&Pe, MVPP2_ETH_TYPE_LEN + 4, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
+
+ /* Set L3 Offset */
+ Mvpp2PrsSramOffsetSet (&Pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
+
+ /* Update shadow table and hw entry */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_PPPOE);
+ Mvpp2PrsHwWrite (Priv, &Pe);
+
+ /* IPv4 over PPPoE without options */
+ Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
+ if (Tid < 0) {
+ return Tid;
+ }
+
+ Pe.Index = Tid;
+
+ Mvpp2PrsTcamDataByteSet (
+ &Pe,
+ MVPP2_ETH_TYPE_LEN,
+ MVPP2_PRS_IPV4_HEAD | MVPP2_PRS_IPV4_IHL,
+ MVPP2_PRS_IPV4_HEAD_MASK | MVPP2_PRS_IPV4_IHL_MASK
+ );
+
+ /* Clear Ri before updating */
+ Pe.Sram.Word[MVPP2_PRS_SRAM_RI_WORD] = 0x0;
+ Pe.Sram.Word[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0;
+ Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_IP4, MVPP2_PRS_RI_L3_PROTO_MASK);
+
+ /* Update shadow table and hw entry */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_PPPOE);
+ Mvpp2PrsHwWrite (Priv, &Pe);
+
+ /* IPv6 over PPPoE */
+ Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
+ if (Tid < 0) {
+ return Tid;
+ }
+
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_PPPOE);
+ Pe.Index = Tid;
+
+ /* Set IPv6 over PPPoE type offset to 0 - obtained from Marvell */
+ Mvpp2PrsMatchEtype (&Pe, 0, MV_PPP_IPV6);
+
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_IP6);
+ Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_IP6, MVPP2_PRS_RI_L3_PROTO_MASK);
+
+ /* Skip EthType + 4 bytes of IPv6 header */
+ Mvpp2PrsSramShiftSet (&Pe, MVPP2_ETH_TYPE_LEN + 4, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
+
+ /* Set L3 Offset */
+ Mvpp2PrsSramOffsetSet (&Pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
+
+ /* Update shadow table and hw entry */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_PPPOE);
+ Mvpp2PrsHwWrite (Priv, &Pe);
+
+ /* Non-IP over PPPoE */
+ Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
+ if (Tid < 0) {
+ return Tid;
+ }
+
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_PPPOE);
+ Pe.Index = Tid;
+
+ Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_UN, MVPP2_PRS_RI_L3_PROTO_MASK);
+
+ /* Finished: go to Flowid generation */
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS);
+ Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
+
+ /* Set L3 Offset even if it's unknown L3 */
+ Mvpp2PrsSramOffsetSet (&Pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
+
+ /* Update shadow table and hw entry */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_PPPOE);
+ Mvpp2PrsHwWrite (Priv, &Pe);
+
+ return 0;
+}
+
+/* Initialize entries for IPv4 */
+STATIC
+INT32
+Mvpp2PrsIp4Init (
+ IN MVPP2_SHARED *Priv
+ )
+{
+ MVPP2_PRS_ENTRY Pe;
+ INT32 Err;
+
+ /* Set entries for TCP, UDP and IGMP over IPv4 */
+ Err = Mvpp2PrsIp4Proto (Priv, MV_IPPR_TCP, MVPP2_PRS_RI_L4_TCP, MVPP2_PRS_RI_L4_PROTO_MASK);
+ if (Err != 0) {
+ return Err;
+ }
+
+ Err = Mvpp2PrsIp4Proto (Priv, MV_IPPR_UDP, MVPP2_PRS_RI_L4_UDP, MVPP2_PRS_RI_L4_PROTO_MASK);
+ if (Err != 0) {
+ return Err;
+ }
+
+ Err = Mvpp2PrsIp4Proto (
+ Priv,
+ MV_IPPR_IGMP,
+ MVPP2_PRS_RI_CPU_CODE_RX_SPEC | MVPP2_PRS_RI_UDF3_RX_SPECIAL,
+ MVPP2_PRS_RI_CPU_CODE_MASK | MVPP2_PRS_RI_UDF3_MASK
+ );
+
+ if (Err != 0) {
+ return Err;
+ }
+
+ /* IPv4 Broadcast */
+ Err = Mvpp2PrsIp4Cast (Priv, MVPP2_PRS_L3_BROAD_CAST);
+ if (Err != 0) {
+ return Err;
+ }
+
+ /* IPv4 Multicast */
+ Err = Mvpp2PrsIp4Cast (Priv, MVPP2_PRS_L3_MULTI_CAST);
+ if (Err != 0) {
+ return Err;
+ }
+
+ /* Default IPv4 entry for unknown protocols */
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP4);
+ Pe.Index = MVPP2_PE_IP4_PROTO_UN;
+
+ /* Set next Lu to IPv4 and shift by 12 bytes - obtained from Marvell*/
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_IP4);
+ Mvpp2PrsSramShiftSet (&Pe, 12, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
+
+ /* Set L4 offset 4 bytes relative IPv4 header size (current position) */
+ Mvpp2PrsSramOffsetSet (
+ &Pe,
+ MVPP2_PRS_SRAM_UDF_TYPE_L4,
+ sizeof (Mvpp2Iphdr) - 4,
+ MVPP2_PRS_SRAM_OP_SEL_UDF_ADD
+ );
+
+ Mvpp2PrsSramAiUpdate (&Pe, MVPP2_PRS_IPV4_DIP_AI_BIT, MVPP2_PRS_IPV4_DIP_AI_BIT);
+ Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L4_OTHER, MVPP2_PRS_RI_L4_PROTO_MASK);
+
+ Mvpp2PrsTcamAiUpdate (&Pe, 0, MVPP2_PRS_IPV4_DIP_AI_BIT);
+
+ /* Unmask all Ports */
+ Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
+
+ /* Update shadow table and hw entry */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP4);
+ Mvpp2PrsHwWrite (Priv, &Pe);
+
+ /* Default IPv4 entry for unicast Address */
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP4);
+ Pe.Index = MVPP2_PE_IP4_ADDR_UN;
+
+ /* Finished: go to Flowid generation */
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS);
+ Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
+ Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_UCAST, MVPP2_PRS_RI_L3_ADDR_MASK);
+
+ Mvpp2PrsTcamAiUpdate (&Pe, MVPP2_PRS_IPV4_DIP_AI_BIT, MVPP2_PRS_IPV4_DIP_AI_BIT);
+
+ /* Unmask all Ports */
+ Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
+
+ /* Update shadow table and hw entry */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP4);
+ Mvpp2PrsHwWrite (Priv, &Pe);
+
+ return 0;
+}
+
+/* Initialize entries for IPv6 */
+STATIC
+INT32
+Mvpp2PrsIp6Init (
+ IN MVPP2_SHARED *Priv
+ )
+{
+ MVPP2_PRS_ENTRY Pe;
+ INT32 Tid, Err;
+
+ /* Set entries for TCP, UDP and ICMP over IPv6 */
+ Err = Mvpp2PrsIp6Proto (Priv, MV_IPPR_TCP, MVPP2_PRS_RI_L4_TCP, MVPP2_PRS_RI_L4_PROTO_MASK);
+ if (Err != 0) {
+ return Err;
+ }
+
+ Err = Mvpp2PrsIp6Proto (Priv, MV_IPPR_UDP, MVPP2_PRS_RI_L4_UDP, MVPP2_PRS_RI_L4_PROTO_MASK);
+ if (Err != 0) {
+ return Err;
+ }
+
+ Err = Mvpp2PrsIp6Proto (
+ Priv,
+ MV_IPPR_ICMPV6,
+ MVPP2_PRS_RI_CPU_CODE_RX_SPEC | MVPP2_PRS_RI_UDF3_RX_SPECIAL,
+ MVPP2_PRS_RI_CPU_CODE_MASK | MVPP2_PRS_RI_UDF3_MASK
+ );
+
+ if (Err != 0) {
+ return Err;
+ }
+
+ /*
+ * IPv4 is the last header. This is similar case as 6-TCP or 17-UDP
+ * Result Info: UDF7=1, DS lite
+ */
+ Err = Mvpp2PrsIp6Proto (Priv, MV_IPPR_IPIP, MVPP2_PRS_RI_UDF7_IP6_LITE, MVPP2_PRS_RI_UDF7_MASK);
+ if (Err != 0) {
+ return Err;
+ }
+
+ /* IPv6 multicast */
+ Err = Mvpp2PrsIp6Cast (Priv, MVPP2_PRS_L3_MULTI_CAST);
+ if (Err != 0) {
+ return Err;
+ }
+
+ /* Entry for checking hop limit */
+ Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
+ if (Tid < 0) {
+ return Tid;
+ }
+
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP6);
+ Pe.Index = Tid;
+
+ /* Finished: go to Flowid generation */
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS);
+ Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
+ Mvpp2PrsSramRiUpdate (
+ &Pe,
+ MVPP2_PRS_RI_L3_UN | MVPP2_PRS_RI_DROP_MASK,
+ MVPP2_PRS_RI_L3_PROTO_MASK | MVPP2_PRS_RI_DROP_MASK
+ );
+
+ Mvpp2PrsTcamDataByteSet (&Pe, 1, 0x00, MVPP2_PRS_IPV6_HOP_MASK);
+ Mvpp2PrsTcamAiUpdate (&Pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT, MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
+
+ /* Update shadow table and hw entry */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP4);
+ Mvpp2PrsHwWrite (Priv, &Pe);
+
+ /* Default IPv6 entry for unknown protocols */
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP6);
+ Pe.Index = MVPP2_PE_IP6_PROTO_UN;
+
+ /* Finished: go to Flowid generation */
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS);
+ Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
+ Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L4_OTHER, MVPP2_PRS_RI_L4_PROTO_MASK);
+
+ /* Set L4 offset 6 bytes relative IPv6 header size (current position) */
+ Mvpp2PrsSramOffsetSet (
+ &Pe,
+ MVPP2_PRS_SRAM_UDF_TYPE_L4,
+ sizeof (Mvpp2Ipv6hdr) - 6,
+ MVPP2_PRS_SRAM_OP_SEL_UDF_ADD
+ );
+
+ Mvpp2PrsTcamAiUpdate (&Pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT, MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
+
+ /* Unmask all Ports */
+ Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
+
+ /* Update shadow table and hw entry */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP4);
+ Mvpp2PrsHwWrite (Priv, &Pe);
+
+ /* Default IPv6 entry for unknown ext protocols */
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP6);
+ Pe.Index = MVPP2_PE_IP6_EXT_PROTO_UN;
+
+ /* Finished: go to Flowid generation */
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS);
+ Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
+ Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L4_OTHER, MVPP2_PRS_RI_L4_PROTO_MASK);
+
+ Mvpp2PrsTcamAiUpdate (&Pe, MVPP2_PRS_IPV6_EXT_AI_BIT, MVPP2_PRS_IPV6_EXT_AI_BIT);
+
+ /* Unmask all Ports */
+ Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
+
+ /* Update shadow table and hw entry */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP4);
+ Mvpp2PrsHwWrite (Priv, &Pe);
+
+ /* Default IPv6 entry for unicast Address */
+ Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
+ Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP6);
+ Pe.Index = MVPP2_PE_IP6_ADDR_UN;
+
+ /* Finished: go to IPv6 again */
+ Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_IP6);
+ Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_UCAST, MVPP2_PRS_RI_L3_ADDR_MASK);
+ Mvpp2PrsSramAiUpdate (&Pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT, MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
+
+ /* Shift back to IPv6 by 18 bytes - byte count provided by Marvell */
+ Mvpp2PrsSramShiftSet (&Pe, -18, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
+ Mvpp2PrsTcamAiUpdate (&Pe, 0, MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
+
+ /* Unmask all Ports */
+ Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
+
+ /* Update shadow table and hw entry */
+ Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP6);
+ Mvpp2PrsHwWrite (Priv, &Pe);
+
+ return 0;
+}
+
+/* Parser default initialization */
+INT32
+Mvpp2PrsDefaultInit (
+ IN MVPP2_SHARED *Priv
+ )
+{
+ INT32 Err, Index, i;
+
+ /* Enable Tcam table */
+ Mvpp2Write (Priv, MVPP2_PRS_TCAM_CTRL_REG, MVPP2_PRS_TCAM_EN_MASK);
+
+ /* Clear all Tcam and Sram entries */
+ for (Index = 0; Index < MVPP2_PRS_TCAM_SRAM_SIZE; Index++) {
+ Mvpp2Write (Priv, MVPP2_PRS_TCAM_IDX_REG, Index);
+ for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++) {
+ Mvpp2Write (Priv, MVPP2_PRS_TCAM_DATA_REG(i), 0);
+ }
+
+ Mvpp2Write (Priv, MVPP2_PRS_SRAM_IDX_REG, Index);
+ for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++) {
+ Mvpp2Write (Priv, MVPP2_PRS_SRAM_DATA_REG(i), 0);
+ }
+ }
+
+ /* Invalidate all Tcam entries */
+ for (Index = 0; Index < MVPP2_PRS_TCAM_SRAM_SIZE; Index++) {
+ Mvpp2PrsHwInv (Priv, Index);
+ }
+
+ /* Always start from lookup = 0 */
+ for (Index = 0; Index < MVPP2_MAX_PORTS; Index++) {
+ Mvpp2PrsHwPortInit (Priv, Index, MVPP2_PRS_LU_MH, MVPP2_PRS_PORT_LU_MAX, 0);
+ }
+
+ Mvpp2PrsDefFlowInit (Priv);
+
+ Mvpp2PrsMhInit (Priv);
+
+ Mvpp2PrsMacInit (Priv);
+
+ Mvpp2PrsDsaInit (Priv);
+
+ Err = Mvpp2PrsEtypeInit (Priv);
+ if (Err != 0) {
+ return Err;
+ }
+
+ Err = Mvpp2PrsVlanInit (Priv);
+ if (Err != 0) {
+ return Err;
+ }
+
+ Err = Mvpp2PrsPppoeInit (Priv);
+ if (Err != 0) {
+ return Err;
+ }
+
+ Err = Mvpp2PrsIp6Init (Priv);
+ if (Err != 0) {
+ return Err;
+ }
+
+ Err = Mvpp2PrsIp4Init (Priv);
+ if (Err != 0) {
+ return Err;
+ }
+
+ return 0;
+}
+
+/* Compare MAC DA with Tcam entry data */
+STATIC
+BOOLEAN
+Mvpp2PrsMacRangeEquals (
+ IN MVPP2_PRS_ENTRY *Pe,
+ IN const UINT8 *Da,
+ IN UINT8 *Mask
+ )
+{
+ UINT8 TcamByte, TcamMask;
+ INT32 Index;
+
+ for (Index = 0; Index < MV_ETH_ALEN; Index++) {
+ Mvpp2PrsTcamDataByteGet (Pe, Index, &TcamByte, &TcamMask);
+ if (TcamMask != Mask[Index]) {
+ return FALSE;
+ }
+
+ if ((TcamMask & TcamByte) != (Da[Index] & Mask[Index])) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/* Find Tcam entry with matched pair <MAC DA, Port> */
+STATIC
+MVPP2_PRS_ENTRY *
+Mvpp2PrsMacDaRangeFind (
+ IN MVPP2_SHARED *Priv,
+ IN INT32 Pmap,
+ IN const UINT8 *Da,
+ IN UINT8 *Mask,
+ IN INT32 UdfType
+ )
+{
+ MVPP2_PRS_ENTRY *Pe;
+ INT32 Tid;
+
+ Pe = Mvpp2Alloc (sizeof (*Pe));
+ if (Pe == NULL) {
+ return NULL;
+ }
+ Mvpp2PrsTcamLuSet (Pe, MVPP2_PRS_LU_MAC);
+
+ /* Go through the all entires with MVPP2_PRS_LU_MAC */
+ for (Tid = MVPP2_PE_FIRST_FREE_TID; Tid <= MVPP2_PE_LAST_FREE_TID; Tid++) {
+ UINT32 EntryPmap;
+
+ if (!Priv->PrsShadow[Tid].Valid ||
+ (Priv->PrsShadow[Tid].Lu != MVPP2_PRS_LU_MAC) ||
+ (Priv->PrsShadow[Tid].Udf != UdfType))
+ {
+ continue;
+ }
+
+ Pe->Index = Tid;
+ Mvpp2PrsHwRead (Priv, Pe);
+ EntryPmap = Mvpp2PrsTcamPortMapGet (Pe);
+
+ if (Mvpp2PrsMacRangeEquals (Pe, Da, Mask) && EntryPmap == Pmap) {
+ return Pe;
+ }
+ }
+
+ Mvpp2Free (Pe);
+
+ return NULL;
+}
+
+/* Update parser's mac Da entry */
+INT32
+Mvpp2PrsMacDaAccept (
+ IN MVPP2_SHARED *Priv,
+ IN INT32 PortId,
+ IN const UINT8 *Da,
+ IN BOOLEAN Add
+ )
+{
+ MVPP2_PRS_ENTRY *Pe;
+ UINT32 Pmap, Len, Ri;
+ UINT8 Mask[MV_ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ INT32 Tid;
+
+ /* Scan TCAM and see if entry with this <MAC DA, PortId> already exist */
+ Pe = Mvpp2PrsMacDaRangeFind (Priv, (1 << PortId), Da, Mask, MVPP2_PRS_UDF_MAC_DEF);
+
+ /* No such entry */
+ if (Pe == NULL) {
+ if (!Add) {
+ return 0;
+ }
+
+ /* Create new TCAM entry */
+ /* Find first range mac entry*/
+ for (Tid = MVPP2_PE_FIRST_FREE_TID; Tid <= MVPP2_PE_LAST_FREE_TID; Tid++) {
+ if (Priv->PrsShadow[Tid].Valid &&
+ (Priv->PrsShadow[Tid].Lu == MVPP2_PRS_LU_MAC) &&
+ (Priv->PrsShadow[Tid].Udf == MVPP2_PRS_UDF_MAC_RANGE))
+ {
+ break;
+ }
+ }
+
+
+ /* Go through the all entries from first to last */
+ Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, Tid - 1);
+ if (Tid < 0) {
+ return Tid;
+ }
+
+ Pe = Mvpp2Alloc (sizeof (*Pe));
+ if (Pe == NULL) {
+ return -1;
+ }
+
+ Mvpp2PrsTcamLuSet (Pe, MVPP2_PRS_LU_MAC);
+ Pe->Index = Tid;
+
+ /* Mask all Ports */
+ Mvpp2PrsTcamPortMapSet (Pe, 0);
+ }
+
+ /* Update PortId Mask */
+ Mvpp2PrsTcamPortSet (Pe, PortId, Add);
+
+ /* Invalidate the entry if no Ports are left enabled */
+ Pmap = Mvpp2PrsTcamPortMapGet (Pe);
+ if (Pmap == 0) {
+ if (Add) {
+ Mvpp2Free (Pe);
+ return -1;
+ }
+
+ Mvpp2PrsHwInv (Priv, Pe->Index);
+ Priv->PrsShadow[Pe->Index].Valid = FALSE;
+
+ Mvpp2Free (Pe);
+
+ return 0;
+ }
+
+ /* Continue - set next lookup */
+ Mvpp2PrsSramNextLuSet (Pe, MVPP2_PRS_LU_DSA);
+
+ /* Set match on DA */
+ Len = MV_ETH_ALEN;
+ while (Len--) {
+ Mvpp2PrsTcamDataByteSet (Pe, Len, Da[Len], 0xff);
+ }
+
+ /* Set result info bits */
+ if (Mvpp2IsBroadcastEtherAddr (Da)) {
+ Ri = MVPP2_PRS_RI_L2_BCAST;
+ } else if (Mvpp2IsMulticastEtherAddr (Da)) {
+ Ri = MVPP2_PRS_RI_L2_MCAST;
+ } else {
+ Ri = MVPP2_PRS_RI_L2_UCAST | MVPP2_PRS_RI_MAC_ME_MASK;
+ }
+
+ Mvpp2PrsSramRiUpdate (Pe, Ri, MVPP2_PRS_RI_L2_CAST_MASK | MVPP2_PRS_RI_MAC_ME_MASK);
+ Mvpp2PrsShadowRiSet (Priv, Pe->Index, Ri, MVPP2_PRS_RI_L2_CAST_MASK | MVPP2_PRS_RI_MAC_ME_MASK);
+
+ /* Shift to ethertype */
+ Mvpp2PrsSramShiftSet (Pe, 2 * MV_ETH_ALEN, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
+
+ /* Update shadow table and hw entry */
+ Priv->PrsShadow[Pe->Index].Udf = MVPP2_PRS_UDF_MAC_DEF;
+ Mvpp2PrsShadowSet (Priv, Pe->Index, MVPP2_PRS_LU_MAC);
+ Mvpp2PrsHwWrite (Priv, Pe);
+
+ Mvpp2Free (Pe);
+
+ return 0;
+}
+
+/* Delete all Port's multicast simple (not range) entries */
+VOID
+Mvpp2PrsMcastDelAll (
+ IN MVPP2_SHARED *Priv,
+ IN INT32 PortId
+ )
+{
+ MVPP2_PRS_ENTRY Pe;
+ INT32 Index, Tid;
+
+ for (Tid = MVPP2_PE_FIRST_FREE_TID; Tid <= MVPP2_PE_LAST_FREE_TID; Tid++) {
+ UINT8 Da[MV_ETH_ALEN], DaMask[MV_ETH_ALEN];
+
+ if (!Priv->PrsShadow[Tid].Valid ||
+ (Priv->PrsShadow[Tid].Lu != MVPP2_PRS_LU_MAC) ||
+ (Priv->PrsShadow[Tid].Udf != MVPP2_PRS_UDF_MAC_DEF))
+ {
+ continue;
+ }
+
+ /* Only simple mac entries */
+ Pe.Index = Tid;
+ Mvpp2PrsHwRead (Priv, &Pe);
+
+ /* Read mac Addr from entry */
+ for (Index = 0; Index < MV_ETH_ALEN; Index++) {
+ Mvpp2PrsTcamDataByteGet (&Pe, Index, &Da[Index], &DaMask[Index]);
+ }
+
+ if (Mvpp2IsMulticastEtherAddr (Da) && !Mvpp2IsBroadcastEtherAddr (Da)) {
+ /* Delete this entry */
+ Mvpp2PrsMacDaAccept (Priv, PortId, Da, FALSE);
+ }
+ }
+}
+
+INT32
+Mvpp2PrsTagModeSet (
+ IN MVPP2_SHARED *Priv,
+ IN INT32 PortId,
+ IN INT32 Type
+ )
+{
+ switch (Type) {
+ case MVPP2_TAG_TYPE_EDSA:
+ /* Add PortId to EDSA entries */
+ Mvpp2PrsDsaTagSet (Priv, PortId, TRUE, MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
+ Mvpp2PrsDsaTagSet (Priv, PortId, TRUE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
+ /* Remove PortId from DSA entries */
+ Mvpp2PrsDsaTagSet (Priv, PortId, FALSE, MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
+ Mvpp2PrsDsaTagSet (Priv, PortId, FALSE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
+ break;
+ case MVPP2_TAG_TYPE_DSA:
+ /* Add PortId to DSA entries */
+ Mvpp2PrsDsaTagSet (Priv, PortId, TRUE, MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
+ Mvpp2PrsDsaTagSet (Priv, PortId, TRUE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
+
+ /* Remove PortId from EDSA entries */
+ Mvpp2PrsDsaTagSet (Priv, PortId, FALSE, MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
+ Mvpp2PrsDsaTagSet (Priv, PortId, FALSE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
+ break;
+ case MVPP2_TAG_TYPE_MH:
+ case MVPP2_TAG_TYPE_NONE:
+ /* Remove PortId form EDSA and DSA entries */
+ Mvpp2PrsDsaTagSet (Priv, PortId, FALSE, MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
+ Mvpp2PrsDsaTagSet (Priv, PortId, FALSE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
+ Mvpp2PrsDsaTagSet (Priv, PortId, FALSE, MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
+ Mvpp2PrsDsaTagSet (Priv, PortId, FALSE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
+ break;
+ default:
+ if ((Type < 0) || (Type > MVPP2_TAG_TYPE_EDSA)) {
+ return MVPP2_EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+/* Set prs Flow for the Port */
+INT32
+Mvpp2PrsDefFlow (
+ IN PP2DXE_PORT *Port
+ )
+{
+ MVPP2_PRS_ENTRY *Pe;
+ INT32 Tid;
+
+ Pe = Mvpp2PrsFlowFind (Port->Priv, Port->Id);
+
+ /* Such entry not exist */
+ if (Pe == NULL) {
+ /* Go through the all entires from last to first */
+ Tid = Mvpp2PrsTcamFirstFree (Port->Priv, MVPP2_PE_LAST_FREE_TID, MVPP2_PE_FIRST_FREE_TID);
+ if (Tid < 0) {
+ return Tid;
+ }
+
+ Pe = Mvpp2Alloc (sizeof (*Pe));
+ if (Pe == NULL) {
+ return MVPP2_ENOMEM;
+ }
+
+ Mvpp2PrsTcamLuSet (Pe, MVPP2_PRS_LU_FLOWS);
+ Pe->Index = Tid;
+
+ /* Set Flow ID*/
+ Mvpp2PrsSramAiUpdate (Pe, Port->Id, MVPP2_PRS_FLOW_ID_MASK);
+ Mvpp2PrsSramBitsSet (Pe, MVPP2_PRS_SRAM_LU_DONE_BIT, 1);
+
+ /* Update shadow table */
+ Mvpp2PrsShadowSet (Port->Priv, Pe->Index, MVPP2_PRS_LU_FLOWS);
+ }
+
+ Mvpp2PrsTcamPortMapSet (Pe, (1 << Port->Id));
+ Mvpp2PrsHwWrite (Port->Priv, Pe);
+ Mvpp2Free (Pe);
+
+ return 0;
+}
+
+/* Classifier configuration routines */
+
+/* Update classification Flow table RegValisters */
+STATIC
+VOID
+Mvpp2ClsFlowWrite (
+ IN MVPP2_SHARED *Priv,
+ IN MVPP2_CLS_FLOW_ENTRY *Fe
+ )
+{
+ Mvpp2Write (Priv, MVPP2_CLS_FLOW_INDEX_REG, Fe->Index);
+ Mvpp2Write (Priv, MVPP2_CLS_FLOW_TBL0_REG, Fe->Data[0]);
+ Mvpp2Write (Priv, MVPP2_CLS_FLOW_TBL1_REG, Fe->Data[1]);
+ Mvpp2Write (Priv, MVPP2_CLS_FLOW_TBL2_REG, Fe->Data[2]);
+}
+
+/* Update classification lookup table RegValister */
+VOID
+Mvpp2ClsLookupWrite (
+ IN MVPP2_SHARED *Priv,
+ IN OUT MVPP2_CLS_LOOKUP_ENTRY *Le
+ )
+{
+ UINT32 Val;
+
+ Val = (Le->Way << MVPP2_CLS_LKP_INDEX_WAY_OFFS) | Le->Lkpid;
+ Mvpp2Write (Priv, MVPP2_CLS_LKP_INDEX_REG, Val);
+ Mvpp2Write (Priv, MVPP2_CLS_LKP_TBL_REG, Le->Data);
+}
+
+/* Classifier default initialization */
+VOID
+Mvpp2ClsInit (
+ IN MVPP2_SHARED *Priv
+ )
+{
+ MVPP2_CLS_LOOKUP_ENTRY Le;
+ MVPP2_CLS_FLOW_ENTRY Fe;
+ INT32 Index;
+
+ /* Enable classifier */
+ Mvpp2Write (Priv, MVPP2_CLS_MODE_REG, MVPP2_CLS_MODE_ACTIVE_MASK);
+
+ /* Clear classifier Flow table */
+ Mvpp2Memset (&Fe.Data, 0, MVPP2_CLS_FLOWS_TBL_DATA_WORDS);
+ for (Index = 0; Index < MVPP2_CLS_FLOWS_TBL_SIZE; Index++) {
+ Fe.Index = Index;
+ Mvpp2ClsFlowWrite (Priv, &Fe);
+ }
+
+ /* Clear classifier lookup table */
+ Le.Data = 0;
+ for (Index = 0; Index < MVPP2_CLS_LKP_TBL_SIZE; Index++) {
+ Le.Lkpid = Index;
+ Le.Way = 0;
+ Mvpp2ClsLookupWrite (Priv, &Le);
+
+ Le.Way = 1;
+ Mvpp2ClsLookupWrite (Priv, &Le);
+ }
+}
+
+VOID
+Mvpp2ClsPortConfig (
+ IN PP2DXE_PORT *Port
+ )
+{
+ MVPP2_CLS_LOOKUP_ENTRY Le;
+ UINT32 Val;
+
+ /* Set way for the Port */
+ Val = Mvpp2Read (Port->Priv, MVPP2_CLS_PORT_WAY_REG);
+ Val &= ~MVPP2_CLS_PORT_WAY_MASK (Port->Id);
+ Mvpp2Write (Port->Priv, MVPP2_CLS_PORT_WAY_REG, Val);
+
+ /*
+ * Pick the entry to be accessed in lookup ID decoding table
+ * according to the way and lkpid.
+ */
+ Le.Lkpid = Port->Id;
+ Le.Way = 0;
+ Le.Data = 0;
+
+ /* Set initial CPU Queue for receiving packets */
+ Le.Data &= ~MVPP2_CLS_LKP_TBL_RXQ_MASK;
+ Le.Data |= Port->FirstRxq;
+
+ /* Disable classification engines */
+ Le.Data &= ~MVPP2_CLS_LKP_TBL_LOOKUP_EN_MASK;
+
+ /* Update lookup ID table entry */
+ Mvpp2ClsLookupWrite (Port->Priv, &Le);
+}
+
+/* Set CPU Queue number for oversize packets */
+VOID
+Mvpp2ClsOversizeRxqSet (
+ IN PP2DXE_PORT *Port
+ )
+{
+
+ Mvpp2Write (
+ Port->Priv,
+ MVPP2_CLS_OVERSIZE_RXQ_LOW_REG(Port->Id),
+ Port->FirstRxq & MVPP2_CLS_OVERSIZE_RXQ_LOW_MASK
+ );
+}
+
+/* BM helper routines */
+
+VOID
+Mvpp2BmPoolHwCreate (
+ IN MVPP2_SHARED *Priv,
+ IN MVPP2_BMS_POOL *BmPool,
+ IN INT32 Size
+ )
+{
+ BmPool->Size = Size;
+
+ Mvpp2Write (Priv, MVPP2_BM_POOL_BASE_REG(BmPool->Id), Lower32Bits (BmPool->PhysAddr));
+ Mvpp2Write (Priv, MVPP22_BM_POOL_BASE_HIGH_REG, (Upper32Bits (BmPool->PhysAddr) & MVPP22_BM_POOL_BASE_HIGH_REG));
+ Mvpp2Write (Priv, MVPP2_BM_POOL_SIZE_REG(BmPool->Id), BmPool->Size);
+}
+
+/* Set Pool buffer Size */
+VOID
+Mvpp2BmPoolBufsizeSet (
+ IN MVPP2_SHARED *Priv,
+ IN MVPP2_BMS_POOL *BmPool,
+ IN INT32 BufSize
+ )
+{
+ UINT32 Val;
+
+ BmPool->BufSize = BufSize;
+
+ Val = MVPP2_ALIGN (BufSize, 1 << MVPP2_POOL_BUF_SIZE_OFFSET);
+ Mvpp2Write (Priv, MVPP2_POOL_BUF_SIZE_REG(BmPool->Id), Val);
+}
+
+VOID
+Mvpp2BmStop (
+ IN MVPP2_SHARED *Priv,
+ IN INT32 Pool
+ )
+{
+ UINT32 Val, i;
+
+ for (i = 0; i < MVPP2_BM_SIZE; i++) {
+ Mvpp2Read (Priv, MVPP2_BM_PHY_ALLOC_REG(0));
+ }
+
+ Val = Mvpp2Read (Priv, MVPP2_BM_POOL_CTRL_REG(Pool));
+ Val |= MVPP2_BM_STOP_MASK;
+ Mvpp2Write (Priv, MVPP2_BM_POOL_CTRL_REG(Pool), Val);
+}
+
+VOID
+Mvpp2BmIrqClear (
+ IN MVPP2_SHARED *Priv,
+ IN INT32 Pool
+ )
+{
+ /* Mask BM all interrupts */
+ Mvpp2Write (Priv, MVPP2_BM_INTR_MASK_REG(Pool), 0);
+
+ /* Clear BM cause RegValister */
+ Mvpp2Write (Priv, MVPP2_BM_INTR_CAUSE_REG(Pool), 0);
+}
+
+/* Attach long Pool to Rxq */
+VOID
+Mvpp2RxqLongPoolSet (
+ IN PP2DXE_PORT *Port,
+ IN INT32 Lrxq,
+ IN INT32 LongPool
+ )
+{
+ UINT32 Val;
+ INT32 Prxq;
+
+ /* Get Queue physical ID */
+ Prxq = Port->Rxqs[Lrxq].Id;
+
+ Val = Mvpp2Read (Port->Priv, MVPP2_RXQ_CONFIG_REG(Prxq));
+ Val &= ~MVPP2_RXQ_POOL_LONG_MASK;
+ Val |= ((LongPool << MVPP2_RXQ_POOL_LONG_OFFS) & MVPP2_RXQ_POOL_LONG_MASK);
+
+ Mvpp2Write (Port->Priv, MVPP2_RXQ_CONFIG_REG(Prxq), Val);
+}
+
+/* Attach short Pool to Rxq */
+VOID
+Mvpp2RxqShortPoolSet (
+ IN PP2DXE_PORT *Port,
+ IN INT32 Lrxq,
+ IN INT32 ShortPool
+ )
+{
+ UINT32 Val;
+ INT32 Prxq;
+
+ /* Get Queue physical ID */
+ Prxq = Port->Rxqs[Lrxq].Id;
+
+ Val = Mvpp2Read (Port->Priv, MVPP2_RXQ_CONFIG_REG(Prxq));
+ Val &= ~MVPP2_RXQ_POOL_SHORT_MASK;
+ Val |= ((ShortPool << MVPP2_RXQ_POOL_SHORT_OFFS) & MVPP2_RXQ_POOL_SHORT_MASK);
+
+ Mvpp2Write (Port->Priv, MVPP2_RXQ_CONFIG_REG(Prxq), Val);
+}
+
+/* Release multicast buffer */
+VOID
+Mvpp2BmPoolMcPut (
+ IN PP2DXE_PORT *Port,
+ IN INT32 Pool,
+ IN UINT32 BufPhysAddr,
+ IN UINT32 BufVirtAddr,
+ IN INT32 McId
+ )
+{
+ UINT32 Val = 0;
+
+ Val |= (McId & MVPP2_BM_MC_ID_MASK);
+ Mvpp2Write (Port->Priv, MVPP2_BM_MC_RLS_REG, Val);
+
+ Mvpp2BmPoolPut (Port->Priv, Pool, BufPhysAddr | MVPP2_BM_PHY_RLS_MC_BUFF_MASK, BufVirtAddr);
+}
+
+/* Refill BM Pool */
+VOID
+Mvpp2PoolRefill (
+ IN PP2DXE_PORT *Port,
+ IN UINT32 Bm,
+ IN UINT32 PhysAddr,
+ IN UINT32 cookie
+ )
+{
+ INT32 Pool = Mvpp2BmCookiePoolGet (Bm);
+
+ Mvpp2BmPoolPut (Port->Priv, Pool, PhysAddr, cookie);
+}
+
+INTN
+Mvpp2BmPoolCtrl (
+ IN MVPP2_SHARED *Priv,
+ IN INTN Pool,
+ IN enum Mvpp2Command Cmd
+ )
+{
+ UINT32 RegVal = 0;
+ RegVal = Mvpp2Read (Priv, MVPP2_BM_POOL_CTRL_REG(Pool));
+
+ switch (Cmd) {
+ case MVPP2_START:
+ RegVal |= MVPP2_BM_START_MASK;
+ break;
+
+ case MVPP2_STOP:
+ RegVal |= MVPP2_BM_STOP_MASK;
+ break;
+
+ default:
+ return -1;
+ }
+ Mvpp2Write (Priv, MVPP2_BM_POOL_CTRL_REG(Pool), RegVal);
+
+ return 0;
+}
+
+/* Mask the current CPU's Rx/Tx interrupts */
+VOID
+Mvpp2InterruptsMask (
+ IN VOID *arg
+ )
+{
+ PP2DXE_PORT *Port = arg;
+
+ Mvpp2Write (Port->Priv, MVPP2_ISR_RX_TX_MASK_REG(Port->Id), 0);
+}
+
+/* Unmask the current CPU's Rx/Tx interrupts */
+VOID
+Mvpp2InterruptsUnmask (
+ IN VOID *arg
+ )
+{
+ PP2DXE_PORT *Port = arg;
+
+ Mvpp2Write (
+ Port->Priv,
+ MVPP2_ISR_RX_TX_MASK_REG(Port->Id),
+ (MVPP2_CAUSE_MISC_SUM_MASK | MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK)
+ );
+}
+
+/* MAC configuration routines */
+
+STATIC
+VOID
+Mvpp2PortMiiSet (
+ IN PP2DXE_PORT *Port
+ )
+{
+ UINT32 Val;
+
+ Val = Mvpp2GmacRead (Port, MVPP2_GMAC_CTRL_2_REG);
+
+ switch (Port->PhyInterface) {
+ case MV_MODE_SGMII:
+ Val |= MVPP2_GMAC_INBAND_AN_MASK;
+ break;
+ case MV_MODE_RGMII:
+ Val |= MVPP2_GMAC_PORT_RGMII_MASK;
+ default:
+ Val &= ~MVPP2_GMAC_PCS_ENABLE_MASK;
+ }
+
+ Mvpp2GmacWrite (Port, MVPP2_GMAC_CTRL_2_REG, Val);
+}
+
+STATIC
+VOID Mvpp2PortFcAdvEnable (
+ IN PP2DXE_PORT *Port
+ )
+{
+ UINT32 Val;
+
+ Val = Mvpp2GmacRead (Port, MVPP2_GMAC_AUTONEG_CONFIG);
+ Val |= MVPP2_GMAC_FC_ADV_EN;
+ Mvpp2GmacWrite (Port, MVPP2_GMAC_AUTONEG_CONFIG, Val);
+}
+
+VOID
+Mvpp2PortEnable (
+ IN PP2DXE_PORT *Port
+ )
+{
+ UINT32 Val;
+
+ Val = Mvpp2GmacRead (Port, MVPP2_GMAC_CTRL_0_REG);
+ Val |= MVPP2_GMAC_PORT_EN_MASK;
+ Val |= MVPP2_GMAC_MIB_CNTR_EN_MASK;
+ Mvpp2GmacWrite (Port, MVPP2_GMAC_CTRL_0_REG, Val);
+}
+
+VOID
+Mvpp2PortDisable (
+ IN PP2DXE_PORT *Port
+ )
+{
+ UINT32 Val;
+
+ Val = Mvpp2GmacRead (Port, MVPP2_GMAC_CTRL_0_REG);
+ Val &= ~(MVPP2_GMAC_PORT_EN_MASK);
+ Mvpp2GmacWrite (Port, MVPP2_GMAC_CTRL_0_REG, Val);
+}
+
+/* Set IEEE 802.3x Flow Control Xon Packet Transmission Mode */
+STATIC
+VOID
+Mvpp2PortPeriodicXonDisable (
+ IN PP2DXE_PORT *Port
+ )
+{
+ UINT32 Val;
+
+ Val = Mvpp2GmacRead (Port, MVPP2_GMAC_CTRL_1_REG) & ~MVPP2_GMAC_PERIODIC_XON_EN_MASK;
+ Mvpp2GmacWrite (Port, MVPP2_GMAC_CTRL_1_REG, Val);
+}
+
+/* Configure loopback Port */
+STATIC
+VOID
+Mvpp2PortReset (
+ IN PP2DXE_PORT *Port
+ )
+{
+ UINT32 Val;
+
+ Val = Mvpp2GmacRead (Port, MVPP2_GMAC_CTRL_2_REG) & ~MVPP2_GMAC_PORT_RESET_MASK;
+ Mvpp2GmacWrite (Port, MVPP2_GMAC_CTRL_2_REG, Val);
+
+ while (Mvpp2GmacRead (Port, MVPP2_GMAC_CTRL_2_REG) & MVPP2_GMAC_PORT_RESET_MASK) {
+ continue;
+ }
+}
+
+/* Set defaults to the MVPP2 Port */
+VOID
+Mvpp2DefaultsSet (
+ IN PP2DXE_PORT *Port
+ )
+{
+ INT32 TxPortNum, Val, Queue, pTxq;
+
+ /* Disable Legacy WRR, Disable EJP, Release from Reset */
+ TxPortNum = Mvpp2EgressPort (Port);
+ Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, TxPortNum);
+ Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_CMD_1_REG, 0);
+
+ /* Close bandwidth for all Queues */
+ for (Queue = 0; Queue < MVPP2_MAX_TXQ; Queue++) {
+ pTxq = Mvpp2TxqPhys (Port->Id, Queue);
+ Mvpp2Write (Port->Priv, MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(pTxq), 0);
+ }
+
+
+ /* Set refill period to 1 Usec, refill tokens and bucket Size to maximum */
+ Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_PERIOD_REG, Port->Priv->Tclk / MVPP2_USEC_PER_SEC);
+ Val = Mvpp2Read (Port->Priv, MVPP2_TXP_SCHED_REFILL_REG);
+ Val &= ~MVPP2_TXP_REFILL_PERIOD_ALL_MASK;
+ Val |= MVPP2_TXP_REFILL_PERIOD_MASK (1);
+ Val |= MVPP2_TXP_REFILL_TOKENS_ALL_MASK;
+ Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_REFILL_REG, Val);
+ Val = MVPP2_TXP_TOKEN_SIZE_MAX;
+ Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_TOKEN_SIZE_REG, Val);
+
+ /* Set MaximumLowLatencyPacketSize value to 256 */
+ Mvpp2Write (
+ Port->Priv,
+ MVPP2_RX_CTRL_REG(Port->Id),
+ MVPP2_RX_USE_PSEUDO_FOR_CSUM_MASK | MVPP2_RX_LOW_LATENCY_PKT_SIZE (256)
+ );
+
+ /* Mask all interrupts to all present cpus */
+ Mvpp2InterruptsDisable (Port, 0x1);
+}
+
+/* Enable/disable receiving packets */
+VOID
+Mvpp2IngressEnable (
+ IN PP2DXE_PORT *Port
+ )
+{
+ UINT32 Val;
+ INT32 Lrxq, Queue;
+
+ for (Lrxq = 0; Lrxq < RxqNumber; Lrxq++) {
+ Queue = Port->Rxqs[Lrxq].Id;
+ Val = Mvpp2Read (Port->Priv, MVPP2_RXQ_CONFIG_REG(Queue));
+ Val &= ~MVPP2_RXQ_DISABLE_MASK;
+ Mvpp2Write (Port->Priv, MVPP2_RXQ_CONFIG_REG(Queue), Val);
+ }
+}
+
+VOID
+Mvpp2IngressDisable (
+ IN PP2DXE_PORT *Port
+ )
+{
+ UINT32 Val;
+ INT32 Lrxq, Queue;
+
+ for (Lrxq = 0; Lrxq < RxqNumber; Lrxq++) {
+ Queue = Port->Rxqs[Lrxq].Id;
+ Val = Mvpp2Read (Port->Priv, MVPP2_RXQ_CONFIG_REG(Queue));
+ Val |= MVPP2_RXQ_DISABLE_MASK;
+ Mvpp2Write (Port->Priv, MVPP2_RXQ_CONFIG_REG(Queue), Val);
+ }
+}
+
+/* Enable transmit via physical egress Queue - HW starts take descriptors from DRAM */
+VOID
+Mvpp2EgressEnable (
+ IN PP2DXE_PORT *Port
+ )
+{
+ UINT32 qmap;
+ INT32 Queue;
+ INT32 TxPortNum = Mvpp2EgressPort (Port);
+
+ /* Enable all initialized TXs. */
+ qmap = 0;
+ for (Queue = 0; Queue < TxqNumber; Queue++) {
+ MVPP2_TX_QUEUE *Txq = &Port->Txqs[Queue];
+
+ if (Txq->Descs != NULL) {
+ qmap |= (1 << Queue);
+ }
+ }
+
+ Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, TxPortNum);
+ Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_Q_CMD_REG, qmap);
+}
+
+/* Disable transmit via physical egress Queue - HW doesn't take descriptors from DRAM */
+VOID
+Mvpp2EgressDisable (
+ IN PP2DXE_PORT *Port
+ )
+{
+ UINT32 RegData;
+ INT32 Delay;
+ INT32 TxPortNum = Mvpp2EgressPort (Port);
+
+ /* Issue stop command for active channels only */
+ Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, TxPortNum);
+ RegData = (Mvpp2Read (Port->Priv, MVPP2_TXP_SCHED_Q_CMD_REG)) & MVPP2_TXP_SCHED_ENQ_MASK;
+ if (RegData != 0) {
+ Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_Q_CMD_REG, (RegData << MVPP2_TXP_SCHED_DISQ_OFFSET));
+ }
+
+ /* Wait for all Tx activity to terminate. */
+ Delay = 0;
+ do {
+ if (Delay >= MVPP2_TX_DISABLE_TIMEOUT_MSEC) {
+ Mvpp2Printf ("Tx stop timed out, status=0x%08x\n", RegData);
+ break;
+ }
+ Mvpp2Mdelay (1);
+ Delay++;
+
+ /* Check Port TX Command RegValister that all Tx Queues are stopped */
+ RegData = Mvpp2Read (Port->Priv, MVPP2_TXP_SCHED_Q_CMD_REG);
+ } while (RegData & MVPP2_TXP_SCHED_ENQ_MASK);
+}
+
+/* Rx descriptors helper methods */
+
+/* Set rx Queue Offset */
+STATIC
+VOID
+Mvpp2RxqOffsetSet (
+ IN PP2DXE_PORT *Port,
+ IN INT32 Prxq,
+ IN INT32 Offset
+ )
+{
+ UINT32 Val;
+
+ /* Convert Offset from bytes to units of 32 bytes */
+ Offset = Offset >> 5;
+
+ /* Clear previous value */
+ Val = Mvpp2Read (Port->Priv, MVPP2_RXQ_CONFIG_REG(Prxq));
+ Val &= ~MVPP2_RXQ_PACKET_OFFSET_MASK;
+
+ /* Update packet Offset in received buffer */
+ Val |= ((Offset << MVPP2_RXQ_PACKET_OFFSET_OFFS) & MVPP2_RXQ_PACKET_OFFSET_MASK);
+ Mvpp2Write (Port->Priv, MVPP2_RXQ_CONFIG_REG(Prxq), Val);
+}
+
+/* Obtain BM cookie information from descriptor */
+UINT32
+Mvpp2BmCookieBuild (
+ IN MVPP2_RX_DESC *RxDesc,
+ IN INT32 Cpu
+ )
+{
+ INT32 Pool;
+ UINT32 ret;
+
+ Pool = (RxDesc->status & MVPP2_RXD_BM_POOL_ID_MASK) >> MVPP2_RXD_BM_POOL_ID_OFFS;
+
+ ret = ((Pool & 0xFF) << MVPP2_BM_COOKIE_POOL_OFFS) | ((Cpu & 0xFF) << MVPP2_BM_COOKIE_CPU_OFFS);
+
+ return ret;
+}
+
+/* Tx descriptors helper methods */
+
+INT32
+Mvpp2TxqDrainSet (
+ IN PP2DXE_PORT *Port,
+ IN INT32 Txq,
+ IN BOOLEAN En
+ )
+{
+ UINT32 RegVal;
+ INT32 pTxq = Mvpp2TxqPhys (Port->Id, Txq);
+
+ Mvpp2Write (Port->Priv, MVPP2_TXQ_NUM_REG, pTxq);
+ RegVal = Mvpp2Read (Port->Priv, MVPP2_TXQ_PREF_BUF_REG);
+
+ if (En) {
+ RegVal |= MVPP2_TXQ_DRAIN_EN_MASK;
+ } else {
+ RegVal &= ~MVPP2_TXQ_DRAIN_EN_MASK;
+ }
+
+ Mvpp2Write (Port->Priv, MVPP2_TXQ_PREF_BUF_REG, RegVal);
+
+ return 0;
+}
+
+/* Get number of Tx descriptors waiting to be transmitted by HW */
+INT32
+Mvpp2TxqPendDescNumGet (
+ IN PP2DXE_PORT *Port,
+ IN MVPP2_TX_QUEUE *Txq
+ )
+{
+ UINT32 Val;
+
+ Mvpp2Write (Port->Priv, MVPP2_TXQ_NUM_REG, Txq->Id);
+ Val = Mvpp2Read (Port->Priv, MVPP2_TXQ_PENDING_REG);
+
+ return Val & MVPP2_TXQ_PENDING_MASK;
+}
+
+/* Get number of occupied aggRegValated Tx descriptors */
+UINT32
+Mvpp2AggrTxqPendDescNumGet (
+ IN MVPP2_SHARED *Priv,
+ IN INT32 Cpu
+ )
+{
+ UINT32 RegVal;
+
+ RegVal = Mvpp2Read (Priv, MVPP2_AGGR_TXQ_STATUS_REG(Cpu));
+
+ return RegVal & MVPP2_AGGR_TXQ_PENDING_MASK;
+}
+
+/* Get pointer to next Tx descriptor to be processed (send) by HW */
+MVPP2_TX_DESC *
+Mvpp2TxqNextDescGet (
+ MVPP2_TX_QUEUE *Txq
+ )
+{
+ INT32 TxDesc = Txq->NextDescToProc;
+
+ Txq->NextDescToProc = MVPP2_QUEUE_NEXT_DESC (Txq, TxDesc);
+
+ return Txq->Descs + TxDesc;
+}
+
+/* Update HW with number of aggRegValated Tx descriptors to be sent */
+VOID
+Mvpp2AggrTxqPendDescAdd (
+ IN PP2DXE_PORT *Port,
+ IN INT32 Pending
+ )
+{
+ /* AggRegValated access - relevant TXQ number is written in TX desc */
+ Mvpp2Write (Port->Priv, MVPP2_AGGR_TXQ_UPDATE_REG, Pending);
+}
+
+/*
+ * Check if there are enough free descriptors in aggRegValated Txq.
+ * If not, update the number of occupied descriptors and repeat the check.
+ */
+INT32
+Mvpp2AggrDescNumCheck (
+ IN MVPP2_SHARED *Priv,
+ IN MVPP2_TX_QUEUE *AggrTxq,
+ IN INT32 Num,
+ IN INT32 Cpu
+ )
+{
+ UINT32 Val;
+
+ if ((AggrTxq->count + Num) > AggrTxq->Size) {
+ /* Update number of occupied aggRegValated Tx descriptors */
+ Val = Mvpp2Read (Priv, MVPP2_AGGR_TXQ_STATUS_REG(Cpu));
+ AggrTxq->count = Val & MVPP2_AGGR_TXQ_PENDING_MASK;
+ }
+
+ if ((AggrTxq->count + Num) > AggrTxq->Size) {
+ return MVPP2_ENOMEM;
+ }
+
+ return 0;
+}
+
+/* Reserved Tx descriptors allocation request */
+INT32
+Mvpp2TxqAllocReservedDesc (
+ IN MVPP2_SHARED *Priv,
+ IN MVPP2_TX_QUEUE *Txq,
+ IN INT32 Num
+ )
+{
+ UINT32 Val;
+
+ Val = (Txq->Id << MVPP2_TXQ_RSVD_REQ_Q_OFFSET) | Num;
+ Mvpp2Write (Priv, MVPP2_TXQ_RSVD_REQ_REG, Val);
+
+ Val = Mvpp2Read (Priv, MVPP2_TXQ_RSVD_RSLT_REG);
+
+ return Val & MVPP2_TXQ_RSVD_RSLT_MASK;
+}
+
+/*
+ * Release the last allocated Tx descriptor. Useful to handle DMA
+ * mapping failures in the Tx path.
+ */
+VOID
+Mvpp2TxqDescPut (
+ IN MVPP2_TX_QUEUE *Txq
+ )
+{
+ if (Txq->NextDescToProc == 0) {
+ Txq->NextDescToProc = Txq->LastDesc - 1;
+ } else {
+ Txq->NextDescToProc--;
+ }
+}
+
+/* Set Tx descriptors fields relevant for CSUM calculation */
+UINT32
+Mvpp2TxqDescCsum (
+ IN INT32 L3Offs,
+ IN INT32 L3Proto,
+ IN INT32 IpHdrLen,
+ IN INT32 L4Proto
+ )
+{
+ UINT32 command;
+
+ /*
+ * Fields: L3_Offset, IP_hdrlen, L3_type, G_IPV4Chk,
+ * G_L4_chk, L4_type required only for checksum calculation
+ */
+ command = (L3Offs << MVPP2_TXD_L3_OFF_SHIFT);
+ command |= (IpHdrLen << MVPP2_TXD_IP_HLEN_SHIFT);
+ command |= MVPP2_TXD_IP_CSUM_DISABLE;
+
+ if (L3Proto == Mvpp2SwapBytes16 (MV_ETH_P_IP)) {
+ command &= ~MVPP2_TXD_IP_CSUM_DISABLE; /* enable IPv4 csum */
+ command &= ~MVPP2_TXD_L3_IP6; /* enable IPv4 */
+ } else {
+ command |= MVPP2_TXD_L3_IP6; /* enable IPv6 */
+ }
+
+ if (L4Proto == MV_IPPR_TCP) {
+ command &= ~MVPP2_TXD_L4_UDP; /* enable TCP */
+ command &= ~MVPP2_TXD_L4_CSUM_FRAG; /* generate L4 csum */
+ } else if (L4Proto == MV_IPPR_UDP) {
+ command |= MVPP2_TXD_L4_UDP; /* enable UDP */
+ command &= ~MVPP2_TXD_L4_CSUM_FRAG; /* generate L4 csum */
+ } else {
+ command |= MVPP2_TXD_L4_CSUM_NOT;
+ }
+
+ return command;
+}
+
+/* Clear counter of sent packets */
+VOID
+Mvpp2TxqSentCounterClear (
+ IN OUT VOID *arg
+ )
+{
+ PP2DXE_PORT *Port = arg;
+ INT32 Queue;
+
+ for (Queue = 0; Queue < TxqNumber; Queue++) {
+ INT32 Id = Port->Txqs[Queue].Id;
+
+ Mvpp2Read (Port->Priv, MVPP2_TXQ_SENT_REG(Id));
+ }
+}
+
+/* Change maximum receive Size of the Port */
+VOID
+Mvpp2GmacMaxRxSizeSet (
+ IN PP2DXE_PORT *Port
+ )
+{
+ UINT32 Val;
+
+ Val = Mvpp2GmacRead (Port, MVPP2_GMAC_CTRL_0_REG);
+ Val &= ~MVPP2_GMAC_MAX_RX_SIZE_MASK;
+ Val |= (((Port->PktSize - MVPP2_MH_SIZE) / 2) << MVPP2_GMAC_MAX_RX_SIZE_OFFS);
+ Mvpp2GmacWrite (Port, MVPP2_GMAC_CTRL_0_REG, Val);
+}
+
+/* Set max sizes for Tx Queues */
+VOID
+Mvpp2TxpMaxTxSizeSet (
+ IN PP2DXE_PORT *Port
+ )
+{
+ UINT32 Val, Size, mtu;
+ INT32 Txq, TxPortNum;
+
+ mtu = Port->PktSize * 8;
+ if (mtu > MVPP2_TXP_MTU_MAX) {
+ mtu = MVPP2_TXP_MTU_MAX;
+ }
+
+ /* WA for wrong Token bucket update: Set MTU value = 3*real MTU value */
+ mtu = 3 * mtu;
+
+ /* Indirect access to RegValisters */
+ TxPortNum = Mvpp2EgressPort (Port);
+ Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, TxPortNum);
+
+ /* Set MTU */
+ Val = Mvpp2Read (Port->Priv, MVPP2_TXP_SCHED_MTU_REG);
+ Val &= ~MVPP2_TXP_MTU_MAX;
+ Val |= mtu;
+ Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_MTU_REG, Val);
+
+ /* TXP token Size and all TXQs token Size must be larger that MTU */
+ Val = Mvpp2Read (Port->Priv, MVPP2_TXP_SCHED_TOKEN_SIZE_REG);
+ Size = Val & MVPP2_TXP_TOKEN_SIZE_MAX;
+ if (Size < mtu) {
+ Size = mtu;
+ Val &= ~MVPP2_TXP_TOKEN_SIZE_MAX;
+ Val |= Size;
+ Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_TOKEN_SIZE_REG, Val);
+ }
+
+ for (Txq = 0; Txq < TxqNumber; Txq++) {
+ Val = Mvpp2Read (Port->Priv, MVPP2_TXQ_SCHED_TOKEN_SIZE_REG(Txq));
+ Size = Val & MVPP2_TXQ_TOKEN_SIZE_MAX;
+
+ if (Size < mtu) {
+ Size = mtu;
+ Val &= ~MVPP2_TXQ_TOKEN_SIZE_MAX;
+ Val |= Size;
+ Mvpp2Write (Port->Priv, MVPP2_TXQ_SCHED_TOKEN_SIZE_REG(Txq), Val);
+ }
+ }
+}
+
+/*
+ * Set the number of packets that will be received before Rx interrupt
+ * will be generated by HW.
+ */
+VOID
+Mvpp2RxPktsCoalSet (
+ IN PP2DXE_PORT *Port,
+ IN OUT MVPP2_RX_QUEUE *Rxq,
+ IN UINT32 Pkts
+ )
+{
+ UINT32 Val;
+
+ Val = (Pkts & MVPP2_OCCUPIED_THRESH_MASK);
+ Mvpp2Write (Port->Priv, MVPP2_RXQ_NUM_REG, Rxq->Id);
+ Mvpp2Write (Port->Priv, MVPP2_RXQ_THRESH_REG, Val);
+
+ Rxq->PktsCoal = Pkts;
+}
+
+/* Set the time Delay in Usec before Rx INT32errupt */
+VOID
+Mvpp2RxTimeCoalSet (
+ IN PP2DXE_PORT *Port,
+ IN OUT MVPP2_RX_QUEUE *Rxq,
+ IN UINT32 Usec
+ )
+{
+ UINT32 Val;
+
+ Val = (Port->Priv->Tclk / MVPP2_USEC_PER_SEC) * Usec;
+ Mvpp2Write (Port->Priv, MVPP2_ISR_RX_THRESHOLD_REG(Rxq->Id), Val);
+
+ Rxq->TimeCoal = Usec;
+}
+
+/* Rx/Tx Queue initialization/cleanup methods */
+
+/* Configure RXQ's */
+VOID
+Mvpp2RxqHwInit (
+ IN PP2DXE_PORT *Port,
+ IN OUT MVPP2_RX_QUEUE *Rxq
+ )
+{
+ Rxq->LastDesc = Rxq->Size - 1;
+
+ /* Zero occupied and non-occupied counters - direct access */
+ Mvpp2Write (Port->Priv, MVPP2_RXQ_STATUS_REG(Rxq->Id), 0);
+
+ /* Set Rx descriptors Queue starting Address - indirect access */
+ Mvpp2Write (Port->Priv, MVPP2_RXQ_NUM_REG, Rxq->Id);
+ Mvpp2Write (Port->Priv, MVPP2_RXQ_DESC_ADDR_REG, Rxq->DescsPhys >> MVPP22_DESC_ADDR_SHIFT);
+ Mvpp2Write (Port->Priv, MVPP2_RXQ_DESC_SIZE_REG, Rxq->Size);
+ Mvpp2Write (Port->Priv, MVPP2_RXQ_INDEX_REG, 0);
+
+ /* Set Offset */
+ Mvpp2RxqOffsetSet (Port, Rxq->Id, MVPP2_RXQ_OFFSET);
+
+ /* Set coalescing pkts and time */
+ Mvpp2RxPktsCoalSet (Port, Rxq, MVPP2_RX_COAL_PKTS);
+ Mvpp2RxTimeCoalSet (Port, Rxq, Rxq->TimeCoal);
+
+ /* Add number of descriptors ready for receiving packets */
+ Mvpp2RxqStatusUpdate (Port, Rxq->Id, 0, Rxq->Size);
+}
+
+/* Push packets received by the RXQ to BM Pool */
+VOID
+Mvpp2RxqDropPkts (
+ IN PP2DXE_PORT *Port,
+ IN OUT MVPP2_RX_QUEUE *Rxq,
+ IN INT32 Cpu
+ )
+{
+ INT32 RxReceived;
+
+ RxReceived = Mvpp2RxqReceived (Port, Rxq->Id);
+ if (!RxReceived) {
+ return;
+ }
+
+ Mvpp2RxqStatusUpdate (Port, Rxq->Id, RxReceived, RxReceived);
+}
+
+VOID
+Mvpp2RxqHwDeinit (
+ IN PP2DXE_PORT *Port,
+ IN OUT MVPP2_RX_QUEUE *Rxq
+ )
+{
+ Rxq->Descs = NULL;
+ Rxq->LastDesc = 0;
+ Rxq->NextDescToProc = 0;
+ Rxq->DescsPhys = 0;
+
+ /*
+ * Clear Rx descriptors Queue starting Address and Size;
+ * free descriptor number
+ */
+ Mvpp2Write (Port->Priv, MVPP2_RXQ_STATUS_REG(Rxq->Id), 0);
+ Mvpp2Write (Port->Priv, MVPP2_RXQ_NUM_REG, Rxq->Id);
+ Mvpp2Write (Port->Priv, MVPP2_RXQ_DESC_ADDR_REG, 0);
+ Mvpp2Write (Port->Priv, MVPP2_RXQ_DESC_SIZE_REG, 0);
+}
+
+/* Configure TXQ's */
+VOID
+Mvpp2TxqHwInit (
+ IN PP2DXE_PORT *Port,
+ IN OUT MVPP2_TX_QUEUE *Txq
+ )
+{
+ INT32 Desc, DescPerTxq, TxPortNum;
+ UINT32 Val;
+
+ Txq->LastDesc = Txq->Size - 1;
+
+ /* Set Tx descriptors Queue starting Address - indirect access */
+ Mvpp2Write (Port->Priv, MVPP2_TXQ_NUM_REG, Txq->Id);
+ Mvpp2Write (Port->Priv, MVPP2_TXQ_DESC_ADDR_REG, Txq->DescsPhys);
+ Mvpp2Write (Port->Priv, MVPP2_TXQ_DESC_SIZE_REG, Txq->Size & MVPP2_TXQ_DESC_SIZE_MASK);
+ Mvpp2Write (Port->Priv, MVPP2_TXQ_INDEX_REG, 0);
+ Mvpp2Write (Port->Priv, MVPP2_TXQ_RSVD_CLR_REG, Txq->Id << MVPP2_TXQ_RSVD_CLR_OFFSET);
+ Val = Mvpp2Read (Port->Priv, MVPP2_TXQ_PENDING_REG);
+ Val &= ~MVPP2_TXQ_PENDING_MASK;
+ Mvpp2Write (Port->Priv, MVPP2_TXQ_PENDING_REG, Val);
+
+ /*
+ * Calculate base Address in prefetch buffer. We reserve 16 descriptors
+ * for each existing TXQ.
+ * TCONTS for PON Port must be continuous from 0 to MVPP2_MAX_TCONT
+ * GBE Ports assumed to be continious from 0 to MVPP2_MAX_PORTS
+ */
+ DescPerTxq = 16;
+ Desc = (Port->Id * MVPP2_MAX_TXQ * DescPerTxq) + (Txq->LogId * DescPerTxq);
+
+ Mvpp2Write (
+ Port->Priv,
+ MVPP2_TXQ_PREF_BUF_REG,
+ MVPP2_PREF_BUF_PTR (Desc) | MVPP2_PREF_BUF_SIZE_16 | MVPP2_PREF_BUF_THRESH (DescPerTxq/2)
+ );
+
+ /* WRR / EJP configuration - indirect access */
+ TxPortNum = Mvpp2EgressPort (Port);
+ Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, TxPortNum);
+
+ Val = Mvpp2Read (Port->Priv, MVPP2_TXQ_SCHED_REFILL_REG(Txq->LogId));
+ Val &= ~MVPP2_TXQ_REFILL_PERIOD_ALL_MASK;
+ Val |= MVPP2_TXQ_REFILL_PERIOD_MASK (1);
+ Val |= MVPP2_TXQ_REFILL_TOKENS_ALL_MASK;
+ Mvpp2Write (Port->Priv, MVPP2_TXQ_SCHED_REFILL_REG(Txq->LogId), Val);
+
+ Val = MVPP2_TXQ_TOKEN_SIZE_MAX;
+ Mvpp2Write (Port->Priv, MVPP2_TXQ_SCHED_TOKEN_SIZE_REG(Txq->LogId), Val);
+}
+
+VOID
+Mvpp2TxqHwDeinit (
+ IN PP2DXE_PORT *Port,
+ IN OUT MVPP2_TX_QUEUE *Txq
+ )
+{
+ Txq->Descs = NULL;
+ Txq->LastDesc = 0;
+ Txq->NextDescToProc = 0;
+ Txq->DescsPhys = 0;
+
+ /* Set minimum bandwidth for disabled TXQs */
+ Mvpp2Write (Port->Priv, MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(Txq->Id), 0);
+
+ /* Set Tx descriptors Queue starting Address and Size */
+ Mvpp2Write (Port->Priv, MVPP2_TXQ_NUM_REG, Txq->Id);
+ Mvpp2Write (Port->Priv, MVPP2_TXQ_DESC_ADDR_REG, 0);
+ Mvpp2Write (Port->Priv, MVPP2_TXQ_DESC_SIZE_REG, 0);
+}
+
+/* Allocate and initialize descriptors for aggr TXQ */
+VOID
+Mvpp2AggrTxqHwInit (
+ IN OUT MVPP2_TX_QUEUE *AggrTxq,
+ IN INT32 DescNum,
+ IN INT32 Cpu,
+ IN MVPP2_SHARED *Priv
+ )
+{
+ AggrTxq->LastDesc = AggrTxq->Size - 1;
+
+ /* Aggr TXQ no Reset WA */
+ AggrTxq->NextDescToProc = Mvpp2Read (Priv, MVPP2_AGGR_TXQ_INDEX_REG(Cpu));
+
+ /* Set Tx descriptors Queue starting Address (indirect access) */
+ Mvpp2Write (Priv, MVPP2_AGGR_TXQ_DESC_ADDR_REG(Cpu), AggrTxq->DescsPhys >> MVPP22_DESC_ADDR_SHIFT);
+ Mvpp2Write (Priv, MVPP2_AGGR_TXQ_DESC_SIZE_REG(Cpu), DescNum & MVPP2_AGGR_TXQ_DESC_SIZE_MASK);
+}
+
+/* Enable gmac */
+VOID
+Mvpp2PortPowerUp (
+ IN PP2DXE_PORT *Port
+ )
+{
+ Mvpp2PortMiiSet (Port);
+ Mvpp2PortPeriodicXonDisable (Port);
+ Mvpp2PortFcAdvEnable (Port);
+ Mvpp2PortReset (Port);
+}
+
+/* Initialize Rx FIFO's */
+VOID
+Mvpp2RxFifoInit (
+ IN MVPP2_SHARED *Priv
+ )
+{
+ INT32 PortId;
+
+ for (PortId = 0; PortId < MVPP2_MAX_PORTS; PortId++) {
+ Mvpp2Write (Priv, MVPP2_RX_DATA_FIFO_SIZE_REG(PortId), MVPP2_RX_FIFO_PORT_DATA_SIZE);
+ Mvpp2Write (Priv, MVPP2_RX_ATTR_FIFO_SIZE_REG(PortId), MVPP2_RX_FIFO_PORT_ATTR_SIZE);
+ }
+
+ Mvpp2Write (Priv, MVPP2_RX_MIN_PKT_SIZE_REG, MVPP2_RX_FIFO_PORT_MIN_PKT);
+ Mvpp2Write (Priv, MVPP2_RX_FIFO_INIT_REG, 0x1);
+}
+
+VOID
+MvGop110NetcActivePort (
+ IN PP2DXE_PORT *Port,
+ IN UINT32 PortId,
+ IN UINT32 Val
+ )
+{
+ UINT32 RegVal;
+
+ RegVal = Mvpp2Rfu1Read (Port->Priv, MV_NETCOMP_PORTS_CONTROL_1);
+ RegVal &= ~(NETC_PORTS_ACTIVE_MASK (PortId));
+
+ Val <<= NETC_PORTS_ACTIVE_OFFSET (PortId);
+ Val &= NETC_PORTS_ACTIVE_MASK (PortId);
+
+ RegVal |= Val;
+
+ Mvpp2Rfu1Write (Port->Priv, MV_NETCOMP_PORTS_CONTROL_1, RegVal);
+}
+
+STATIC
+VOID
+MvGop110NetcXauiEnable (
+ IN PP2DXE_PORT *Port,
+ IN UINT32 PortId,
+ IN UINT32 Val
+ )
+{
+ UINT32 RegVal;
+
+ RegVal = Mvpp2Rfu1Read (Port->Priv, SD1_CONTROL_1_REG);
+ RegVal &= ~SD1_CONTROL_XAUI_EN_MASK;
+
+ Val <<= SD1_CONTROL_XAUI_EN_OFFSET;
+ Val &= SD1_CONTROL_XAUI_EN_MASK;
+
+ RegVal |= Val;
+
+ Mvpp2Rfu1Write (Port->Priv, SD1_CONTROL_1_REG, RegVal);
+}
+
+STATIC
+VOID
+MvGop110NetcRxaui0Enable (
+ IN PP2DXE_PORT *Port,
+ IN UINT32 PortId,
+ IN UINT32 Val
+ )
+{
+ UINT32 RegVal;
+
+ RegVal = Mvpp2Rfu1Read (Port->Priv, SD1_CONTROL_1_REG);
+ RegVal &= ~SD1_CONTROL_RXAUI0_L23_EN_MASK;
+
+ Val <<= SD1_CONTROL_RXAUI0_L23_EN_OFFSET;
+ Val &= SD1_CONTROL_RXAUI0_L23_EN_MASK;
+
+ RegVal |= Val;
+
+ Mvpp2Rfu1Write (Port->Priv, SD1_CONTROL_1_REG, RegVal);
+}
+
+STATIC
+VOID
+MvGop110NetcRxaui1Enable (
+ IN PP2DXE_PORT *Port,
+ IN UINT32 PortId,
+ IN UINT32 Val
+ )
+{
+ UINT32 RegVal;
+
+ RegVal = Mvpp2Rfu1Read (Port->Priv, SD1_CONTROL_1_REG);
+ RegVal &= ~SD1_CONTROL_RXAUI1_L45_EN_MASK;
+
+ Val <<= SD1_CONTROL_RXAUI1_L45_EN_OFFSET;
+ Val &= SD1_CONTROL_RXAUI1_L45_EN_MASK;
+
+ RegVal |= Val;
+
+ Mvpp2Rfu1Write (Port->Priv, SD1_CONTROL_1_REG, RegVal);
+}
+
+STATIC
+VOID
+MvGop110NetcMiiMode (
+ IN PP2DXE_PORT *Port,
+ IN UINT32 PortId,
+ IN UINT32 Val
+ )
+{
+ UINT32 RegVal;
+
+ RegVal = Mvpp2Rfu1Read (Port->Priv, MV_NETCOMP_CONTROL_0);
+ RegVal &= ~NETC_GBE_PORT1_MII_MODE_MASK;
+
+ Val <<= NETC_GBE_PORT1_MII_MODE_OFFSET;
+ Val &= NETC_GBE_PORT1_MII_MODE_MASK;
+
+ RegVal |= Val;
+
+ Mvpp2Rfu1Write (Port->Priv, MV_NETCOMP_CONTROL_0, RegVal);
+}
+
+STATIC
+VOID
+MvGop110NetcGopReset (
+ IN PP2DXE_PORT *Port,
+ IN UINT32 Val
+ )
+{
+ UINT32 RegVal;
+
+ RegVal = Mvpp2Rfu1Read (Port->Priv, MV_GOP_SOFT_RESET_1_REG);
+ RegVal &= ~NETC_GOP_SOFT_RESET_MASK;
+
+ Val <<= NETC_GOP_SOFT_RESET_OFFSET;
+ Val &= NETC_GOP_SOFT_RESET_MASK;
+
+ RegVal |= Val;
+
+ Mvpp2Rfu1Write (Port->Priv, MV_GOP_SOFT_RESET_1_REG, RegVal);
+}
+
+STATIC
+VOID
+MvGop110NetcGopClockLogicSet (
+ IN PP2DXE_PORT *Port,
+ IN UINT32 Val
+ )
+{
+ UINT32 RegVal;
+
+ RegVal = Mvpp2Rfu1Read (Port->Priv, MV_NETCOMP_PORTS_CONTROL_0);
+ RegVal &= ~NETC_CLK_DIV_PHASE_MASK;
+
+ Val <<= NETC_CLK_DIV_PHASE_OFFSET;
+ Val &= NETC_CLK_DIV_PHASE_MASK;
+
+ RegVal |= Val;
+
+ Mvpp2Rfu1Write (Port->Priv, MV_NETCOMP_PORTS_CONTROL_0, RegVal);
+}
+
+STATIC
+VOID
+MvGop110NetcPortRfReset (
+ IN PP2DXE_PORT *Port,
+ IN UINT32 PortId,
+ IN UINT32 Val
+ )
+{
+ UINT32 RegVal;
+
+ RegVal = Mvpp2Rfu1Read (Port->Priv, MV_NETCOMP_PORTS_CONTROL_1);
+ RegVal &= ~(NETC_PORT_GIG_RF_RESET_MASK (PortId));
+
+ Val <<= NETC_PORT_GIG_RF_RESET_OFFSET (PortId);
+ Val &= NETC_PORT_GIG_RF_RESET_MASK (PortId);
+
+ RegVal |= Val;
+
+ Mvpp2Rfu1Write (Port->Priv, MV_NETCOMP_PORTS_CONTROL_1, RegVal);
+}
+
+STATIC
+VOID
+MvGop110NetcGbeSgmiiModeSelect (
+ IN PP2DXE_PORT *Port,
+ IN UINT32 PortId,
+ IN UINT32 Val
+ )
+{
+ UINT32 RegVal, Mask, Offset;
+
+ if (PortId == 2) {
+ Mask = NETC_GBE_PORT0_SGMII_MODE_MASK;
+ Offset = NETC_GBE_PORT0_SGMII_MODE_OFFSET;
+ } else {
+ Mask = NETC_GBE_PORT1_SGMII_MODE_MASK;
+ Offset = NETC_GBE_PORT1_SGMII_MODE_OFFSET;
+ }
+ RegVal = Mvpp2Rfu1Read (Port->Priv, MV_NETCOMP_CONTROL_0);
+ RegVal &= ~Mask;
+
+ Val <<= Offset;
+ Val &= Mask;
+
+ RegVal |= Val;
+
+ Mvpp2Rfu1Write (Port->Priv, MV_NETCOMP_CONTROL_0, RegVal);
+}
+
+STATIC
+VOID
+MvGop110NetcBusWidthSelect (
+ IN PP2DXE_PORT *Port,
+ IN UINT32 Val
+ )
+{
+ UINT32 RegVal;
+
+ RegVal = Mvpp2Rfu1Read (Port->Priv, MV_NETCOMP_PORTS_CONTROL_0);
+ RegVal &= ~NETC_BUS_WIDTH_SELECT_MASK;
+
+ Val <<= NETC_BUS_WIDTH_SELECT_OFFSET;
+ Val &= NETC_BUS_WIDTH_SELECT_MASK;
+
+ RegVal |= Val;
+
+ Mvpp2Rfu1Write (Port->Priv, MV_NETCOMP_PORTS_CONTROL_0, RegVal);
+}
+
+STATIC
+VOID
+MvGop110NetcSampleStagesTiming (
+ IN PP2DXE_PORT *Port,
+ IN UINT32 Val
+ )
+{
+ UINT32 RegVal;
+
+ RegVal = Mvpp2Rfu1Read (Port->Priv, MV_NETCOMP_PORTS_CONTROL_0);
+ RegVal &= ~NETC_GIG_RX_DATA_SAMPLE_MASK;
+
+ Val <<= NETC_GIG_RX_DATA_SAMPLE_OFFSET;
+ Val &= NETC_GIG_RX_DATA_SAMPLE_MASK;
+
+ RegVal |= Val;
+
+ Mvpp2Rfu1Write (Port->Priv, MV_NETCOMP_PORTS_CONTROL_0, RegVal);
+}
+
+STATIC
+VOID
+MvGop110NetcMacToXgmii (
+ IN PP2DXE_PORT *Port,
+ IN UINT32 PortId,
+ IN enum MvNetcPhase Phase
+ )
+{
+ switch (Phase) {
+ case MV_NETC_FIRST_PHASE:
+
+ /* Set Bus Width to HB mode = 1 */
+ MvGop110NetcBusWidthSelect (Port, 0x1);
+
+ /* Select RGMII mode */
+ MvGop110NetcGbeSgmiiModeSelect (Port, PortId, MV_NETC_GBE_XMII);
+ break;
+ case MV_NETC_SECOND_PHASE:
+
+ /* De-assert the relevant PortId HB Reset */
+ MvGop110NetcPortRfReset (Port, PortId, 0x1);
+ break;
+ }
+}
+
+STATIC
+VOID
+MvGop110NetcMacToSgmii (
+ IN PP2DXE_PORT *Port,
+ IN UINT32 PortId,
+ IN enum MvNetcPhase Phase
+ )
+{
+ switch (Phase) {
+ case MV_NETC_FIRST_PHASE:
+
+ /* Set Bus Width to HB mode = 1 */
+ MvGop110NetcBusWidthSelect (Port, 1);
+
+ /* Select SGMII mode */
+ if (PortId >= 1) {
+ MvGop110NetcGbeSgmiiModeSelect (Port, PortId, MV_NETC_GBE_SGMII);
+ }
+
+ /* Configure the sample stages */
+ MvGop110NetcSampleStagesTiming (Port, 0);
+ break;
+ case MV_NETC_SECOND_PHASE:
+
+ /* De-assert the relevant PortId HB Reset */
+ MvGop110NetcPortRfReset (Port, PortId, 1);
+ break;
+ }
+}
+
+STATIC
+VOID
+MvGop110NetcMacToRxaui (
+ IN PP2DXE_PORT *Port,
+ IN UINT32 PortId,
+ IN enum MvNetcPhase Phase,
+ IN enum MvNetcLanes Lanes
+ )
+{
+ /* Currently only RXAUI0 supPorted */
+ if (PortId != 0)
+ return;
+
+ switch (Phase) {
+ case MV_NETC_FIRST_PHASE:
+
+ /* RXAUI Serdes/s Clock alignment */
+ if (Lanes == MV_NETC_LANE_23) {
+ MvGop110NetcRxaui0Enable (Port, PortId, 1);
+ } else {
+ MvGop110NetcRxaui1Enable (Port, PortId, 1);
+ }
+ break;
+ case MV_NETC_SECOND_PHASE:
+
+ /* De-assert the relevant PortId HB Reset */
+ MvGop110NetcPortRfReset (Port, PortId, 1);
+ break;
+ }
+}
+
+STATIC
+VOID
+MvGop110NetcMacToXaui (
+ IN PP2DXE_PORT *Port,
+ IN UINT32 PortId,
+ IN enum MvNetcPhase Phase
+ )
+{
+ switch (Phase) {
+ case MV_NETC_FIRST_PHASE:
+
+ /* RXAUI Serdes/s Clock alignment */
+ MvGop110NetcXauiEnable (Port, PortId, 1);
+ break;
+ case MV_NETC_SECOND_PHASE:
+
+ /* De-assert the relevant PortId HB Reset */
+ MvGop110NetcPortRfReset (Port, PortId, 1);
+ break;
+ }
+}
+
+INT32
+MvGop110NetcInit (
+ IN PP2DXE_PORT *Port,
+ IN UINT32 NetCompConfig,
+ IN enum MvNetcPhase Phase
+ )
+{
+ UINT32 c = NetCompConfig;
+
+ if (c & MV_NETC_GE_MAC0_RXAUI_L23) {
+ MvGop110NetcMacToRxaui (Port, 0, Phase, MV_NETC_LANE_23);
+ }
+
+ if (c & MV_NETC_GE_MAC0_RXAUI_L45) {
+ MvGop110NetcMacToRxaui (Port, 0, Phase, MV_NETC_LANE_45);
+ }
+
+ if (c & MV_NETC_GE_MAC0_XAUI) {
+ MvGop110NetcMacToXaui (Port, 0, Phase);
+ }
+
+ if (c & MV_NETC_GE_MAC2_SGMII) {
+ MvGop110NetcMacToSgmii (Port, 2, Phase);
+ } else {
+ MvGop110NetcMacToXgmii (Port, 2, Phase);
+ }
+
+ if (c & MV_NETC_GE_MAC3_SGMII) {
+ MvGop110NetcMacToSgmii (Port, 3, Phase);
+ } else {
+ MvGop110NetcMacToXgmii (Port, 3, Phase);
+ if (c & MV_NETC_GE_MAC3_RGMII) {
+ MvGop110NetcMiiMode (Port, 3, MV_NETC_GBE_RGMII);
+ } else {
+ MvGop110NetcMiiMode (Port, 3, MV_NETC_GBE_MII);
+ }
+ }
+
+ /* Activate gop Ports 0, 2, 3 */
+ MvGop110NetcActivePort (Port, 0, 1);
+ MvGop110NetcActivePort (Port, 2, 1);
+ MvGop110NetcActivePort (Port, 3, 1);
+
+ if (Phase == MV_NETC_SECOND_PHASE) {
+
+ /* Enable the GOP internal clock logic */
+ MvGop110NetcGopClockLogicSet (Port, 1);
+
+ /* De-assert GOP unit Reset */
+ MvGop110NetcGopReset (Port, 1);
+ }
+
+ return 0;
+}
+
+UINT32
+MvpPp2xGop110NetcCfgCreate (
+ IN PP2DXE_PORT *Port
+ )
+{
+ UINT32 Val = 0;
+
+ if (Port->GopIndex == 0) {
+ if (Port->PhyInterface == MV_MODE_XAUI) {
+ Val |= MV_NETC_GE_MAC0_XAUI;
+ } else if (Port->PhyInterface == MV_MODE_RXAUI) {
+ Val |= MV_NETC_GE_MAC0_RXAUI_L23;
+ }
+ }
+
+ if (Port->GopIndex == 2) {
+ if (Port->PhyInterface == MV_MODE_SGMII) {
+ Val |= MV_NETC_GE_MAC2_SGMII;
+ }
+ }
+
+ if (Port->GopIndex == 3) {
+ if (Port->PhyInterface == MV_MODE_SGMII) {
+ Val |= MV_NETC_GE_MAC3_SGMII;
+ } else if (Port->PhyInterface == MV_MODE_RGMII) {
+ Val |= MV_NETC_GE_MAC3_RGMII;
+ }
+ }
+
+ return Val;
+}
+
+/*
+ * Initialize physical Port. Configure the Port mode and
+ * all its elements accordingly.
+ */
+INT32
+MvGop110PortInit (
+ IN PP2DXE_PORT *Port
+ )
+{
+
+ switch (Port->PhyInterface) {
+ case MV_MODE_RGMII:
+ MvGop110GmacReset (Port, RESET);
+
+ /* Configure PCS */
+ MvGop110GpcsModeCfg (Port, FALSE);
+ MvGop110BypassClkCfg (Port, TRUE);
+
+ /* Configure MAC */
+ MvGop110GmacModeCfg (Port);
+
+ /* PCS unreset */
+ MvGop110GpcsReset (Port, UNRESET);
+
+ /* MAC unreset */
+ MvGop110GmacReset (Port, UNRESET);
+ break;
+ case MV_MODE_SGMII:
+ case MV_MODE_QSGMII:
+
+ /* Configure PCS */
+ MvGop110GpcsModeCfg (Port, TRUE);
+
+ /* Configure MAC */
+ MvGop110GmacModeCfg (Port);
+
+ /* Select proper MAC mode */
+ MvGop110Xlg2GigMacCfg (Port);
+
+ /* PCS unreset */
+ MvGop110GpcsReset (Port, UNRESET);
+
+ /* MAC unreset */
+ MvGop110GmacReset (Port, UNRESET);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Set the MAC to Reset or exit from Reset */
+INT32
+MvGop110GmacReset (
+ IN PP2DXE_PORT *Port,
+ IN enum MvReset ResetCmd
+ )
+{
+ UINT32 RegAddr;
+ UINT32 Val;
+
+ RegAddr = MVPP2_PORT_CTRL2_REG;
+
+ Val = MvGop110GmacRead (Port, RegAddr);
+
+ if (ResetCmd == RESET) {
+ Val |= MVPP2_PORT_CTRL2_PORTMACRESET_MASK;
+ } else {
+ Val &= ~MVPP2_PORT_CTRL2_PORTMACRESET_MASK;
+ }
+
+ MvGop110GmacWrite (Port, RegAddr, Val);
+
+ return 0;
+}
+
+/* Enable/Disable Port to work with Gig PCS */
+INT32
+MvGop110GpcsModeCfg (
+ IN PP2DXE_PORT *Port,
+ BOOLEAN En
+ )
+{
+ UINT32 Val;
+
+ Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL2_REG);
+
+ if (En) {
+ Val |= MVPP2_PORT_CTRL2_PCS_EN_MASK;
+ } else {
+ Val &= ~MVPP2_PORT_CTRL2_PCS_EN_MASK;
+ }
+
+ MvGop110GmacWrite (Port, MVPP2_PORT_CTRL2_REG, Val);
+
+ return 0;
+}
+
+INT32
+MvGop110BypassClkCfg (
+ IN PP2DXE_PORT *Port,
+ IN BOOLEAN En
+ )
+{
+ UINT32 Val;
+
+ Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL2_REG);
+
+ if (En) {
+ Val |= MVPP2_PORT_CTRL2_CLK_125_BYPS_EN_MASK;
+ } else {
+ Val &= ~MVPP2_PORT_CTRL2_CLK_125_BYPS_EN_MASK;
+ }
+
+ MvGop110GmacWrite (Port, MVPP2_PORT_CTRL2_REG, Val);
+
+ return 0;
+}
+
+INT32
+MvGop110GpcsReset (
+ IN PP2DXE_PORT *Port,
+ IN enum MvReset ResetCmd
+ )
+{
+ UINT32 RegData;
+
+ RegData = MvGop110GmacRead (Port, MVPP2_PORT_CTRL2_REG);
+
+ if (ResetCmd == RESET) {
+ U32_SET_FIELD (
+ RegData,
+ MVPP2_PORT_CTRL2_SGMII_MODE_MASK,
+ 0
+ );
+
+ } else {
+ U32_SET_FIELD (
+ RegData,
+ MVPP2_PORT_CTRL2_SGMII_MODE_MASK,
+ 1 << MVPP2_PORT_CTRL2_SGMII_MODE_OFFS
+ );
+
+ }
+
+ MvGop110GmacWrite (Port, MVPP2_PORT_CTRL2_REG, RegData);
+
+ return 0;
+}
+
+VOID
+MvGop110Xlg2GigMacCfg (
+ IN PP2DXE_PORT *Port
+ )
+{
+ UINT32 RegVal;
+
+ /* Relevant only for MAC0 (XLG0 and GMAC0) */
+ if (Port->GopIndex > 0) {
+ return;
+ }
+
+ /* Configure 1Gig MAC mode */
+ RegVal = Mvpp2XlgRead (Port, MV_XLG_PORT_MAC_CTRL3_REG);
+ U32_SET_FIELD (
+ RegVal,
+ MV_XLG_MAC_CTRL3_MACMODESELECT_MASK,
+ (0 << MV_XLG_MAC_CTRL3_MACMODESELECT_OFFS)
+ );
+
+ Mvpp2XlgWrite (Port, MV_XLG_PORT_MAC_CTRL3_REG, RegVal);
+}
+
+/* Set the internal mux's to the required MAC in the GOP */
+INT32
+MvGop110GmacModeCfg (
+ IN PP2DXE_PORT *Port
+ )
+{
+ UINT32 RegAddr;
+ UINT32 Val;
+
+ /* Set TX FIFO thresholds */
+ switch (Port->PhyInterface) {
+ case MV_MODE_SGMII:
+ if (Port->Speed == MV_PORT_SPEED_2500) {
+ MvGop110GmacSgmii25Cfg (Port);
+ } else {
+ MvGop110GmacSgmiiCfg (Port);
+ }
+ break;
+ case MV_MODE_RGMII:
+ MvGop110GmacRgmiiCfg (Port);
+ break;
+ case MV_MODE_QSGMII:
+ MvGop110GmacQsgmiiCfg (Port);
+ break;
+ default:
+ return -1;
+ }
+
+ /* Jumbo frame supPort - 0x1400*2= 0x2800 bytes */
+ Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL0_REG);
+ U32_SET_FIELD (
+ Val,
+ MVPP2_PORT_CTRL0_FRAMESIZELIMIT_MASK,
+ (0x1400 << MVPP2_PORT_CTRL0_FRAMESIZELIMIT_OFFS)
+ );
+
+ MvGop110GmacWrite (Port, MVPP2_PORT_CTRL0_REG, Val);
+
+ /* PeriodicXonEn disable */
+ RegAddr = MVPP2_PORT_CTRL1_REG;
+ Val = MvGop110GmacRead (Port, RegAddr);
+ Val &= ~MVPP2_PORT_CTRL1_EN_PERIODIC_FC_XON_MASK;
+ MvGop110GmacWrite (Port, RegAddr, Val);
+
+ /* Mask all Ports interrupts */
+ MvGop110GmacPortLinkEventMask (Port);
+
+#if MV_PP2x_INTERRUPT
+ /* Unmask link change interrupt */
+ Val = MvGop110GmacRead (Port, MVPP2_INTERRUPT_MASK_REG);
+ Val |= MVPP2_INTERRUPT_CAUSE_LINK_CHANGE_MASK;
+ Val |= 1; /* Unmask summary bit */
+ MvGop110GmacWrite (Port, MVPP2_INTERRUPT_MASK_REG, Val);
+#endif
+
+ return 0;
+}
+
+VOID
+MvGop110GmacRgmiiCfg (
+ IN PP2DXE_PORT *Port
+ )
+{
+ UINT32 Val, thresh, an;
+
+ /* Configure minimal level of the Tx FIFO before the lower part starts to read a packet*/
+ thresh = MV_RGMII_TX_FIFO_MIN_TH;
+ Val = MvGop110GmacRead (Port, MVPP2_PORT_FIFO_CFG_1_REG);
+ U32_SET_FIELD (
+ Val,
+ MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_MASK,
+ (thresh << MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_OFFS)
+ );
+
+ MvGop110GmacWrite (Port, MVPP2_PORT_FIFO_CFG_1_REG, Val);
+
+ /* Disable bypass of sync module */
+ Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL4_REG);
+ Val |= MVPP2_PORT_CTRL4_SYNC_BYPASS_MASK;
+
+ /* Configure DP clock select according to mode */
+ Val &= ~MVPP2_PORT_CTRL4_DP_CLK_SEL_MASK;
+ Val |= MVPP2_PORT_CTRL4_QSGMII_BYPASS_ACTIVE_MASK;
+ Val |= MVPP2_PORT_CTRL4_EXT_PIN_GMII_SEL_MASK;
+ MvGop110GmacWrite (Port, MVPP2_PORT_CTRL4_REG, Val);
+
+ Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL2_REG);
+ Val &= ~MVPP2_PORT_CTRL2_DIS_PADING_OFFS;
+ MvGop110GmacWrite (Port, MVPP2_PORT_CTRL2_REG, Val);
+
+ /* Configure GIG MAC to SGMII mode */
+ Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL0_REG);
+ Val &= ~MVPP2_PORT_CTRL0_PORTTYPE_MASK;
+ MvGop110GmacWrite (Port, MVPP2_PORT_CTRL0_REG, Val);
+
+ /* configure AN 0xb8e8 */
+ an = MVPP2_PORT_AUTO_NEG_CFG_AN_BYPASS_EN_MASK |
+ MVPP2_PORT_AUTO_NEG_CFG_EN_AN_SPEED_MASK |
+ MVPP2_PORT_AUTO_NEG_CFG_EN_FC_AN_MASK |
+ MVPP2_PORT_AUTO_NEG_CFG_EN_FDX_AN_MASK |
+ MVPP2_PORT_AUTO_NEG_CFG_CHOOSE_SAMPLE_TX_CONFIG_MASK;
+ MvGop110GmacWrite (Port, MVPP2_PORT_AUTO_NEG_CFG_REG, an);
+}
+
+VOID
+MvGop110GmacSgmii25Cfg (
+ IN PP2DXE_PORT *Port
+ )
+{
+ UINT32 Val, thresh, an;
+
+ /*
+ * Configure minimal level of the Tx FIFO before
+ * the lower part starts to read a packet.
+ */
+ thresh = MV_SGMII2_5_TX_FIFO_MIN_TH;
+ Val = MvGop110GmacRead (Port, MVPP2_PORT_FIFO_CFG_1_REG);
+ U32_SET_FIELD (
+ Val,
+ MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_MASK,
+ (thresh << MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_OFFS)
+ );
+
+ MvGop110GmacWrite (Port, MVPP2_PORT_FIFO_CFG_1_REG, Val);
+
+ /* Disable bypass of sync module */
+ Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL4_REG);
+ Val |= MVPP2_PORT_CTRL4_SYNC_BYPASS_MASK;
+
+ /* Configure DP clock select according to mode */
+ Val |= MVPP2_PORT_CTRL4_DP_CLK_SEL_MASK;
+
+ /* Configure QSGMII bypass according to mode */
+ Val |= MVPP2_PORT_CTRL4_QSGMII_BYPASS_ACTIVE_MASK;
+ MvGop110GmacWrite (Port, MVPP2_PORT_CTRL4_REG, Val);
+
+ Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL2_REG);
+ Val |= MVPP2_PORT_CTRL2_DIS_PADING_OFFS;
+ MvGop110GmacWrite (Port, MVPP2_PORT_CTRL2_REG, Val);
+
+ /* Configure GIG MAC to 1000Base-X mode connected to a fiber transceiver */
+ Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL0_REG);
+ Val |= MVPP2_PORT_CTRL0_PORTTYPE_MASK;
+ MvGop110GmacWrite (Port, MVPP2_PORT_CTRL0_REG, Val);
+
+ /* configure AN 0x9268 */
+ an = MVPP2_PORT_AUTO_NEG_CFG_EN_PCS_AN_MASK |
+ MVPP2_PORT_AUTO_NEG_CFG_AN_BYPASS_EN_MASK |
+ MVPP2_PORT_AUTO_NEG_CFG_SET_MII_SPEED_MASK |
+ MVPP2_PORT_AUTO_NEG_CFG_SET_GMII_SPEED_MASK |
+ MVPP2_PORT_AUTO_NEG_CFG_ADV_PAUSE_MASK |
+ MVPP2_PORT_AUTO_NEG_CFG_SET_FULL_DX_MASK |
+ MVPP2_PORT_AUTO_NEG_CFG_CHOOSE_SAMPLE_TX_CONFIG_MASK;
+ MvGop110GmacWrite (Port, MVPP2_PORT_AUTO_NEG_CFG_REG, an);
+}
+
+VOID
+MvGop110GmacSgmiiCfg (
+ IN PP2DXE_PORT *Port
+ )
+{
+ UINT32 Val, thresh, an;
+
+ /*
+ * Configure minimal level of the Tx FIFO before
+ * the lower part starts to read a packet.
+ */
+ thresh = MV_SGMII_TX_FIFO_MIN_TH;
+ Val = MvGop110GmacRead (Port, MVPP2_PORT_FIFO_CFG_1_REG);
+ U32_SET_FIELD (Val, MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_MASK,
+ (thresh << MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_OFFS));
+ MvGop110GmacWrite (Port, MVPP2_PORT_FIFO_CFG_1_REG, Val);
+
+ /* Disable bypass of sync module */
+ Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL4_REG);
+ Val |= MVPP2_PORT_CTRL4_SYNC_BYPASS_MASK;
+
+ /* Configure DP clock select according to mode */
+ Val &= ~MVPP2_PORT_CTRL4_DP_CLK_SEL_MASK;
+
+ /* Configure QSGMII bypass according to mode */
+ Val |= MVPP2_PORT_CTRL4_QSGMII_BYPASS_ACTIVE_MASK;
+ MvGop110GmacWrite (Port, MVPP2_PORT_CTRL4_REG, Val);
+
+ Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL2_REG);
+ Val |= MVPP2_PORT_CTRL2_DIS_PADING_OFFS;
+ MvGop110GmacWrite (Port, MVPP2_PORT_CTRL2_REG, Val);
+
+ /* Configure GIG MAC to SGMII mode */
+ Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL0_REG);
+ Val &= ~MVPP2_PORT_CTRL0_PORTTYPE_MASK;
+ MvGop110GmacWrite (Port, MVPP2_PORT_CTRL0_REG, Val);
+
+ /* Configure AN */
+ an = MVPP2_PORT_AUTO_NEG_CFG_EN_PCS_AN_MASK |
+ MVPP2_PORT_AUTO_NEG_CFG_AN_BYPASS_EN_MASK |
+ MVPP2_PORT_AUTO_NEG_CFG_EN_AN_SPEED_MASK |
+ MVPP2_PORT_AUTO_NEG_CFG_EN_FC_AN_MASK |
+ MVPP2_PORT_AUTO_NEG_CFG_EN_FDX_AN_MASK |
+ MVPP2_PORT_AUTO_NEG_CFG_CHOOSE_SAMPLE_TX_CONFIG_MASK;
+ MvGop110GmacWrite (Port, MVPP2_PORT_AUTO_NEG_CFG_REG, an);
+}
+
+VOID
+MvGop110GmacQsgmiiCfg (
+ IN PP2DXE_PORT *Port
+ )
+{
+ UINT32 Val, thresh, an;
+
+ /*
+ * Configure minimal level of the Tx FIFO before
+ * the lower part starts to read a packet.
+ */
+ thresh = MV_SGMII_TX_FIFO_MIN_TH;
+ Val = MvGop110GmacRead (Port, MVPP2_PORT_FIFO_CFG_1_REG);
+ U32_SET_FIELD (
+ Val,
+ MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_MASK,
+ (thresh << MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_OFFS)
+ );
+
+ MvGop110GmacWrite (Port, MVPP2_PORT_FIFO_CFG_1_REG, Val);
+
+ /* Disable bypass of sync module */
+ Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL4_REG);
+ Val |= MVPP2_PORT_CTRL4_SYNC_BYPASS_MASK;
+
+ /* Configure DP clock select according to mode */
+ Val &= ~MVPP2_PORT_CTRL4_DP_CLK_SEL_MASK;
+ Val &= ~MVPP2_PORT_CTRL4_EXT_PIN_GMII_SEL_MASK;
+
+ /* Configure QSGMII bypass according to mode */
+ Val &= ~MVPP2_PORT_CTRL4_QSGMII_BYPASS_ACTIVE_MASK;
+ MvGop110GmacWrite (Port, MVPP2_PORT_CTRL4_REG, Val);
+
+ Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL2_REG);
+ Val &= ~MVPP2_PORT_CTRL2_DIS_PADING_OFFS;
+ MvGop110GmacWrite (Port, MVPP2_PORT_CTRL2_REG, Val);
+
+ /* Configure GIG MAC to SGMII mode */
+ Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL0_REG);
+ Val &= ~MVPP2_PORT_CTRL0_PORTTYPE_MASK;
+ MvGop110GmacWrite (Port, MVPP2_PORT_CTRL0_REG, Val);
+
+ /* Configure AN 0xB8EC */
+ an = MVPP2_PORT_AUTO_NEG_CFG_EN_PCS_AN_MASK |
+ MVPP2_PORT_AUTO_NEG_CFG_AN_BYPASS_EN_MASK |
+ MVPP2_PORT_AUTO_NEG_CFG_EN_AN_SPEED_MASK |
+ MVPP2_PORT_AUTO_NEG_CFG_EN_FC_AN_MASK |
+ MVPP2_PORT_AUTO_NEG_CFG_EN_FDX_AN_MASK |
+ MVPP2_PORT_AUTO_NEG_CFG_CHOOSE_SAMPLE_TX_CONFIG_MASK;
+ MvGop110GmacWrite (Port, MVPP2_PORT_AUTO_NEG_CFG_REG, an);
+}
+
+INT32
+Mvpp2SmiPhyAddrCfg (
+ IN PP2DXE_PORT *Port,
+ IN INT32 PortId,
+ IN INT32 Addr
+ )
+{
+ Mvpp2SmiWrite (Port->Priv, MV_SMI_PHY_ADDRESS_REG(PortId), Addr);
+
+ return 0;
+}
+
+BOOLEAN
+MvGop110PortIsLinkUp (
+ IN PP2DXE_PORT *Port
+ )
+{
+ switch (Port->PhyInterface) {
+ case MV_MODE_RGMII:
+ case MV_MODE_SGMII:
+ case MV_MODE_QSGMII:
+ return MvGop110GmacLinkStatusGet (Port);
+ case MV_MODE_XAUI:
+ case MV_MODE_RXAUI:
+ return FALSE;
+ default:
+ return FALSE;
+ }
+}
+
+/* Get MAC link status */
+BOOLEAN
+MvGop110GmacLinkStatusGet (
+ IN PP2DXE_PORT *Port
+ )
+{
+ UINT32 RegAddr;
+ UINT32 Val;
+
+ RegAddr = MVPP2_PORT_STATUS0_REG;
+
+ Val = MvGop110GmacRead (Port, RegAddr);
+
+ return (Val & 1) ? TRUE : FALSE;
+}
+
+VOID
+MvGop110PortDisable (
+ IN PP2DXE_PORT *Port
+ )
+{
+ switch (Port->PhyInterface) {
+ case MV_MODE_RGMII:
+ case MV_MODE_SGMII:
+ case MV_MODE_QSGMII:
+ MvGop110GmacPortDisable (Port);
+ break;
+ default:
+ return;
+ }
+}
+
+VOID
+MvGop110PortEnable (
+ IN PP2DXE_PORT *Port
+ )
+{
+ switch (Port->PhyInterface) {
+ case MV_MODE_RGMII:
+ case MV_MODE_SGMII:
+ case MV_MODE_QSGMII:
+ MvGop110GmacPortEnable (Port);
+ break;
+ default:
+ return;
+ }
+}
+
+/* Enable Port and MIB counters */
+VOID
+MvGop110GmacPortEnable (
+ IN PP2DXE_PORT *Port
+ )
+{
+ UINT32 RegVal;
+
+ RegVal = MvGop110GmacRead (Port, MVPP2_PORT_CTRL0_REG);
+ RegVal |= MVPP2_PORT_CTRL0_PORTEN_MASK;
+ RegVal |= MVPP2_PORT_CTRL0_COUNT_EN_MASK;
+
+ MvGop110GmacWrite (Port, MVPP2_PORT_CTRL0_REG, RegVal);
+}
+
+/* Disable Port */
+VOID
+MvGop110GmacPortDisable (
+ IN PP2DXE_PORT *Port
+ )
+{
+ UINT32 RegVal;
+
+ /* Mask all Ports interrupts */
+ MvGop110GmacPortLinkEventMask (Port);
+
+ RegVal = MvGop110GmacRead (Port, MVPP2_PORT_CTRL0_REG);
+ RegVal &= ~MVPP2_PORT_CTRL0_PORTEN_MASK;
+
+ MvGop110GmacWrite (Port, MVPP2_PORT_CTRL0_REG, RegVal);
+}
+
+VOID
+MvGop110GmacPortLinkEventMask (
+ IN PP2DXE_PORT *Port
+ )
+{
+ UINT32 RegVal;
+
+ RegVal = MvGop110GmacRead (Port, MV_GMAC_INTERRUPT_SUM_MASK_REG);
+ RegVal &= ~MV_GMAC_INTERRUPT_SUM_CAUSE_LINK_CHANGE_MASK;
+ MvGop110GmacWrite (Port, MV_GMAC_INTERRUPT_SUM_MASK_REG, RegVal);
+}
+
+INT32
+MvGop110PortEventsMask (
+ IN PP2DXE_PORT *Port
+ )
+{
+
+ switch (Port->PhyInterface) {
+ case MV_MODE_RGMII:
+ case MV_MODE_SGMII:
+ case MV_MODE_QSGMII:
+ MvGop110GmacPortLinkEventMask (Port);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+INT32
+MvGop110FlCfg (
+ IN PP2DXE_PORT *Port
+ )
+{
+ switch (Port->PhyInterface) {
+ case MV_MODE_RGMII:
+ case MV_MODE_SGMII:
+ case MV_MODE_QSGMII:
+ /* Disable AN */
+ MvGop110SpeedDuplexSet (Port, Port->Speed, MV_PORT_DUPLEX_FULL);
+ break;
+ case MV_MODE_XAUI:
+ case MV_MODE_RXAUI:
+ return 0;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Set Port Speed and Duplex */
+INT32
+MvGop110SpeedDuplexSet (
+ IN PP2DXE_PORT *Port,
+ IN INT32 Speed,
+ IN enum MvPortDuplex Duplex
+ )
+{
+ switch (Port->PhyInterface) {
+ case MV_MODE_RGMII:
+ case MV_MODE_SGMII:
+ case MV_MODE_QSGMII:
+ MvGop110GmacSpeedDuplexSet (Port, Speed, Duplex);
+ break;
+ case MV_MODE_XAUI:
+ case MV_MODE_RXAUI:
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Sets Port Speed to Auto Negotiation / 1000 / 100 / 10 Mbps.
+ * Sets Port Duplex to Auto Negotiation / Full / Half Duplex.
+ */
+INT32
+MvGop110GmacSpeedDuplexSet (
+ IN PP2DXE_PORT *Port,
+ IN INT32 Speed,
+ IN enum MvPortDuplex Duplex
+ )
+{
+ UINT32 RegVal;
+
+ RegVal = Mvpp2GmacRead (Port, MVPP2_PORT_AUTO_NEG_CFG_REG);
+
+ switch (Speed) {
+ case MV_PORT_SPEED_2500:
+ case MV_PORT_SPEED_1000:
+ RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_EN_AN_SPEED_MASK;
+ RegVal |= MVPP2_PORT_AUTO_NEG_CFG_SET_GMII_SPEED_MASK;
+ /* The 100/10 bit doesn't matter in this case */
+ break;
+ case MV_PORT_SPEED_100:
+ RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_EN_AN_SPEED_MASK;
+ RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_SET_GMII_SPEED_MASK;
+ RegVal |= MVPP2_PORT_AUTO_NEG_CFG_SET_MII_SPEED_MASK;
+ break;
+ case MV_PORT_SPEED_10:
+ RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_EN_AN_SPEED_MASK;
+ RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_SET_GMII_SPEED_MASK;
+ RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_SET_MII_SPEED_MASK;
+ break;
+ default:
+ return MVPP2_EINVAL;
+ }
+
+ switch (Duplex) {
+ case MV_PORT_DUPLEX_AN:
+ RegVal |= MVPP2_PORT_AUTO_NEG_CFG_EN_FDX_AN_MASK;
+ /* The other bits don't matter in this case */
+ break;
+ case MV_PORT_DUPLEX_HALF:
+ RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_EN_FDX_AN_MASK;
+ RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_SET_FULL_DX_MASK;
+ break;
+ case MV_PORT_DUPLEX_FULL:
+ RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_EN_FDX_AN_MASK;
+ RegVal |= MVPP2_PORT_AUTO_NEG_CFG_SET_FULL_DX_MASK;
+ break;
+ default:
+ return MVPP2_EINVAL;
+ }
+
+ Mvpp2GmacWrite (Port, MVPP2_PORT_AUTO_NEG_CFG_REG, RegVal);
+
+ return 0;
+}
+
+VOID
+Mvpp2AxiConfig (
+ IN MVPP2_SHARED *Priv
+ )
+{
+ /* Config AXI Read&Write Normal and Soop mode */
+ Mvpp2Write (Priv, MVPP22_AXI_BM_WR_ATTR_REG, MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT);
+ Mvpp2Write (Priv, MVPP22_AXI_BM_RD_ATTR_REG, MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT);
+ Mvpp2Write (Priv, MVPP22_AXI_AGGRQ_DESCR_RD_ATTR_REG, MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT);
+ Mvpp2Write (Priv, MVPP22_AXI_TXQ_DESCR_WR_ATTR_REG, MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT);
+ Mvpp2Write (Priv, MVPP22_AXI_TXQ_DESCR_RD_ATTR_REG, MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT);
+ Mvpp2Write (Priv, MVPP22_AXI_RXQ_DESCR_WR_ATTR_REG, MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT);
+ Mvpp2Write (Priv, MVPP22_AXI_RX_DATA_WR_ATTR_REG, MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT);
+ Mvpp2Write (Priv, MVPP22_AXI_TX_DATA_RD_ATTR_REG, MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT);
+}
+
+/* Cleanup Tx Ports */
+VOID
+Mvpp2TxpClean (
+ IN PP2DXE_PORT *Port,
+ IN INT32 Txp,
+ IN MVPP2_TX_QUEUE *Txq
+ )
+{
+ INT32 Delay, Pending;
+ UINT32 RegVal;
+
+ Mvpp2Write (Port->Priv, MVPP2_TXQ_NUM_REG, Txq->Id);
+ RegVal = Mvpp2Read (Port->Priv, MVPP2_TXQ_PREF_BUF_REG);
+ RegVal |= MVPP2_TXQ_DRAIN_EN_MASK;
+ Mvpp2Write (Port->Priv, MVPP2_TXQ_PREF_BUF_REG, RegVal);
+
+ /*
+ * The Queue has been stopped so wait for all packets
+ * to be transmitted.
+ */
+ Delay = 0;
+ do {
+ if (Delay >= MVPP2_TX_PENDING_TIMEOUT_MSEC) {
+ Mvpp2Printf ("Port %d: cleaning Queue %d timed out\n", Port->Id, Txq->LogId);
+ break;
+ }
+ Mvpp2Mdelay (1);
+ Delay++;
+
+ Pending = Mvpp2TxqPendDescNumGet (Port, Txq);
+ } while (Pending);
+
+ RegVal &= ~MVPP2_TXQ_DRAIN_EN_MASK;
+ Mvpp2Write (Port->Priv, MVPP2_TXQ_PREF_BUF_REG, RegVal);
+}
+
+/* Cleanup all Tx Queues */
+VOID
+Mvpp2CleanupTxqs (
+ IN PP2DXE_PORT *Port
+ )
+{
+ MVPP2_TX_QUEUE *Txq;
+ INT32 Txp, Queue;
+ UINT32 RegVal;
+
+ RegVal = Mvpp2Read (Port->Priv, MVPP2_TX_PORT_FLUSH_REG);
+
+ /* Reset Tx Ports and delete Tx Queues */
+ for (Txp = 0; Txp < Port->TxpNum; Txp++) {
+ RegVal |= MVPP2_TX_PORT_FLUSH_MASK (Port->Id);
+ Mvpp2Write (Port->Priv, MVPP2_TX_PORT_FLUSH_REG, RegVal);
+
+ for (Queue = 0; Queue < TxqNumber; Queue++) {
+ Txq = &Port->Txqs[Txp * TxqNumber + Queue];
+ Mvpp2TxpClean (Port, Txp, Txq);
+ Mvpp2TxqHwDeinit (Port, Txq);
+ }
+
+ RegVal &= ~MVPP2_TX_PORT_FLUSH_MASK (Port->Id);
+ Mvpp2Write (Port->Priv, MVPP2_TX_PORT_FLUSH_REG, RegVal);
+ }
+}
+
+/* Cleanup all Rx Queues */
+VOID
+Mvpp2CleanupRxqs (
+ IN PP2DXE_PORT *Port
+ )
+{
+ INT32 Queue;
+
+ for (Queue = 0; Queue < RxqNumber; Queue++) {
+ Mvpp2RxqHwDeinit (Port, &Port->Rxqs[Queue]);
+ }
+}
diff --git a/Platform/Marvell/Drivers/Net/Pp2Dxe/Mvpp2Lib.h b/Platform/Marvell/Drivers/Net/Pp2Dxe/Mvpp2Lib.h
new file mode 100644
index 0000000000..d7d5dcb283
--- /dev/null
+++ b/Platform/Marvell/Drivers/Net/Pp2Dxe/Mvpp2Lib.h
@@ -0,0 +1,726 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#ifndef __MVPP2_LIB_H__
+#define __MVPP2_LIB_H__
+
+#include "Mvpp2LibHw.h"
+#include "Pp2Dxe.h"
+
+/* number of RXQs used by single Port */
+STATIC INT32 RxqNumber = 1;
+/* number of TXQs used by single Port */
+STATIC INT32 TxqNumber = 1;
+
+VOID
+Mvpp2PrsMacPromiscSet (
+ IN MVPP2_SHARED *Priv,
+ IN INT32 PortId,
+ IN BOOLEAN Add
+ );
+
+VOID
+Mvpp2PrsMacMultiSet (
+ IN MVPP2_SHARED *Priv,
+ IN INT32 PortId,
+ IN INT32 Index,
+ IN BOOLEAN Add
+ );
+
+INT32
+Mvpp2PrsDefaultInit (
+ IN MVPP2_SHARED *Priv
+ );
+
+INT32
+Mvpp2PrsMacDaAccept (
+ IN MVPP2_SHARED *Priv,
+ IN INT32 PortId,
+ IN const UINT8 *Da,
+ IN BOOLEAN Add
+ );
+
+VOID
+Mvpp2PrsMcastDelAll (
+ IN MVPP2_SHARED *Priv,
+ IN INT32 PortId
+ );
+
+INT32
+Mvpp2PrsTagModeSet (
+ IN MVPP2_SHARED *Priv,
+ IN INT32 PortId,
+ IN INT32 type
+ );
+
+INT32
+Mvpp2PrsDefFlow (
+ IN PP2DXE_PORT *Port
+ );
+
+VOID
+Mvpp2ClsInit (
+ IN MVPP2_SHARED *Priv
+ );
+
+VOID
+Mvpp2ClsPortConfig (
+ IN PP2DXE_PORT *Port
+ );
+
+VOID
+Mvpp2ClsOversizeRxqSet (
+ IN PP2DXE_PORT *Port
+ );
+
+VOID
+Mvpp2BmPoolHwCreate (
+ IN MVPP2_SHARED *Priv,
+ IN MVPP2_BMS_POOL *BmPool,
+ IN INT32 Size
+ );
+
+VOID
+Mvpp2BmPoolBufsizeSet (
+ IN MVPP2_SHARED *Priv,
+ IN MVPP2_BMS_POOL *BmPool,
+ IN INT32 BufSize
+ );
+
+VOID
+Mvpp2BmStop (
+ IN MVPP2_SHARED *Priv,
+ IN INT32 Pool
+ );
+
+VOID
+Mvpp2BmIrqClear (
+ IN MVPP2_SHARED *Priv,
+ IN INT32 Pool
+ );
+
+VOID
+Mvpp2RxqLongPoolSet (
+ IN PP2DXE_PORT *Port,
+ IN INT32 Lrxq,
+ IN INT32 LongPool
+ );
+
+VOID
+Mvpp2RxqShortPoolSet (
+ IN PP2DXE_PORT *Port,
+ IN INT32 Lrxq,
+ IN INT32 ShortPool
+ );
+
+VOID
+Mvpp2BmPoolMcPut (
+ IN PP2DXE_PORT *Port,
+ IN INT32 Pool,
+ IN UINT32 BufPhysAddr,
+ IN UINT32 BufVirtAddr,
+ IN INT32 McId
+ );
+
+VOID
+Mvpp2PoolRefill (
+ IN PP2DXE_PORT *Port,
+ IN UINT32 Bm,
+ IN UINT32 PhysAddr,
+ IN UINT32 Cookie
+ );
+
+INTN
+Mvpp2BmPoolCtrl (
+ IN MVPP2_SHARED *Priv,
+ IN INTN Pool,
+ IN enum Mvpp2Command cmd
+ );
+
+VOID
+Mvpp2InterruptsMask (
+ IN VOID *arg
+ );
+
+VOID
+Mvpp2InterruptsUnmask (
+ IN VOID *arg
+ );
+
+VOID
+Mvpp2PortEnable (
+ IN PP2DXE_PORT *Port
+ );
+
+VOID
+Mvpp2PortDisable (
+ IN PP2DXE_PORT *Port
+ );
+
+VOID
+Mvpp2DefaultsSet (
+ IN PP2DXE_PORT *Port
+ );
+
+VOID
+Mvpp2IngressEnable (
+ IN PP2DXE_PORT *Port
+ );
+
+VOID
+Mvpp2IngressDisable (
+ IN PP2DXE_PORT *Port
+ );
+
+VOID
+Mvpp2EgressEnable (
+ IN PP2DXE_PORT *Port
+ );
+
+VOID
+Mvpp2EgressDisable (
+ IN PP2DXE_PORT *Port
+ );
+
+UINT32
+Mvpp2BmCookieBuild (
+ IN MVPP2_RX_DESC *RxDesc,
+ IN INT32 Cpu
+ );
+
+INT32
+Mvpp2TxqDrainSet (
+ IN PP2DXE_PORT *Port,
+ IN INT32 Txq,
+ IN BOOLEAN En
+ );
+
+INT32
+Mvpp2TxqPendDescNumGet (
+ IN PP2DXE_PORT *Port,
+ IN MVPP2_TX_QUEUE *Txq
+ );
+
+UINT32
+Mvpp2AggrTxqPendDescNumGet (
+ IN MVPP2_SHARED *Priv,
+ IN INT32 Cpu
+ );
+
+MVPP2_TX_DESC *
+Mvpp2TxqNextDescGet (
+ MVPP2_TX_QUEUE *Txq
+ );
+
+VOID
+Mvpp2AggrTxqPendDescAdd (
+ IN PP2DXE_PORT *Port,
+ IN INT32 Pending
+ );
+
+INT32
+Mvpp2AggrDescNumCheck (
+ IN MVPP2_SHARED *Priv,
+ IN MVPP2_TX_QUEUE *AggrTxq,
+ IN INT32 Num,
+ IN INT32 Cpu
+ );
+
+INT32
+Mvpp2TxqAllocReservedDesc (
+ IN MVPP2_SHARED *Priv,
+ IN MVPP2_TX_QUEUE *Txq,
+ IN INT32 Num
+ );
+
+VOID
+Mvpp2TxqDescPut (
+ IN MVPP2_TX_QUEUE *Txq
+ );
+
+UINT32
+Mvpp2TxqDescCsum (
+ IN INT32 L3Offs,
+ IN INT32 L3Proto,
+ IN INT32 IpHdrLen,
+ IN INT32 L4Proto
+ );
+
+VOID
+Mvpp2TxqSentCounterClear (
+ IN OUT VOID *arg
+ );
+
+VOID
+Mvpp2GmacMaxRxSizeSet (
+ IN PP2DXE_PORT *Port
+ );
+
+VOID
+Mvpp2TxpMaxTxSizeSet (
+ IN PP2DXE_PORT *Port
+ );
+
+VOID
+Mvpp2RxPktsCoalSet (
+ IN PP2DXE_PORT *Port,
+ IN OUT MVPP2_RX_QUEUE *Rxq,
+ IN UINT32 Pkts
+ );
+
+VOID
+Mvpp2RxTimeCoalSet (
+ IN PP2DXE_PORT *Port,
+ IN OUT MVPP2_RX_QUEUE *Rxq,
+ IN UINT32 Usec
+ );
+
+VOID
+Mvpp2AggrTxqHwInit (
+ IN OUT MVPP2_TX_QUEUE *AggrTxq,
+ IN INT32 DescNum,
+ IN INT32 Cpu,
+ IN MVPP2_SHARED *Priv
+ );
+
+VOID
+Mvpp2RxqHwInit (
+ IN PP2DXE_PORT *Port,
+ IN OUT MVPP2_RX_QUEUE *Rxq
+ );
+
+VOID
+Mvpp2RxqDropPkts (
+ IN PP2DXE_PORT *Port,
+ IN OUT MVPP2_RX_QUEUE *Rxq,
+ IN INT32 Cpu
+ );
+
+VOID
+Mvpp2TxqHwInit (
+ IN PP2DXE_PORT *Port,
+ IN OUT MVPP2_TX_QUEUE *Txq
+ );
+
+VOID
+Mvpp2TxqHwDeinit (
+ IN PP2DXE_PORT *Port,
+ IN OUT MVPP2_TX_QUEUE *Txq
+ );
+
+VOID
+Mvpp2PortPowerUp (
+ IN PP2DXE_PORT *Port
+ );
+
+VOID
+Mvpp2RxFifoInit (
+ IN MVPP2_SHARED *Priv
+ );
+
+VOID
+Mvpp2RxqHwDeinit (
+ IN PP2DXE_PORT *Port,
+ IN OUT MVPP2_RX_QUEUE *Rxq
+ );
+
+INT32
+MvGop110NetcInit (
+ IN PP2DXE_PORT *Port,
+ IN UINT32 NetCompConfig,
+ IN enum MvNetcPhase phase
+ );
+
+UINT32
+MvpPp2xGop110NetcCfgCreate (
+ IN PP2DXE_PORT *Port
+ );
+
+INT32
+MvGop110PortInit (
+ IN PP2DXE_PORT *Port
+ );
+
+INT32
+MvGop110GmacReset (
+ IN PP2DXE_PORT *Port,
+ IN enum MvReset ResetCmd
+ );
+
+INT32
+MvGop110GpcsModeCfg (
+ IN PP2DXE_PORT *Port,
+ BOOLEAN En
+ );
+
+INT32
+MvGop110BypassClkCfg (
+ IN PP2DXE_PORT *Port,
+ IN BOOLEAN En
+ );
+
+INT32
+MvGop110GpcsReset (
+ IN PP2DXE_PORT *Port,
+ IN enum MvReset ResetCmd
+ );
+
+VOID
+MvGop110Xlg2GigMacCfg (
+ IN PP2DXE_PORT *Port
+ );
+
+INT32
+MvGop110GmacModeCfg (
+ IN PP2DXE_PORT *Port
+ );
+
+VOID
+MvGop110GmacRgmiiCfg (
+ IN PP2DXE_PORT *Port
+ );
+
+VOID
+MvGop110GmacSgmii25Cfg (
+ IN PP2DXE_PORT *Port
+ );
+
+VOID
+MvGop110GmacSgmiiCfg (
+ IN PP2DXE_PORT *Port
+ );
+
+VOID
+MvGop110GmacQsgmiiCfg (
+ IN PP2DXE_PORT *Port
+ );
+
+INT32
+Mvpp2SmiPhyAddrCfg (
+ IN PP2DXE_PORT *Port,
+ IN INT32 PortId,
+ IN INT32 Addr
+ );
+
+BOOLEAN
+MvGop110PortIsLinkUp (
+ IN PP2DXE_PORT *Port
+ );
+
+BOOLEAN
+MvGop110GmacLinkStatusGet (
+ IN PP2DXE_PORT *Port
+ );
+
+VOID
+MvGop110PortDisable (
+ IN PP2DXE_PORT *Port
+ );
+
+VOID
+MvGop110PortEnable (
+ IN PP2DXE_PORT *Port
+ );
+
+VOID
+MvGop110GmacPortEnable (
+ IN PP2DXE_PORT *Port
+ );
+
+VOID
+MvGop110GmacPortDisable (
+ IN PP2DXE_PORT *Port
+ );
+
+VOID
+MvGop110GmacPortLinkEventMask (
+ IN PP2DXE_PORT *Port
+ );
+
+INT32
+MvGop110PortEventsMask (
+ IN PP2DXE_PORT *Port
+ );
+
+INT32
+MvGop110FlCfg (
+ IN PP2DXE_PORT *Port
+ );
+
+INT32
+MvGop110SpeedDuplexSet (
+ IN PP2DXE_PORT *Port,
+ IN INT32 Speed,
+ IN enum MvPortDuplex Duplex
+ );
+
+INT32
+MvGop110GmacSpeedDuplexSet (
+ IN PP2DXE_PORT *Port,
+ IN INT32 Speed,
+ IN enum MvPortDuplex Duplex
+ );
+
+VOID
+Mvpp2AxiConfig (
+ IN MVPP2_SHARED *Priv
+ );
+
+VOID
+Mvpp2TxpClean (
+ IN PP2DXE_PORT *Port,
+ IN INT32 Txp,
+ IN MVPP2_TX_QUEUE *Txq
+ );
+
+VOID
+Mvpp2CleanupTxqs (
+ IN PP2DXE_PORT *Port
+ );
+
+VOID
+Mvpp2CleanupRxqs (
+ IN PP2DXE_PORT *Port
+ );
+
+/* Get number of physical egress Port */
+STATIC
+inline
+INT32
+Mvpp2EgressPort (
+ IN PP2DXE_PORT *Port
+ )
+{
+ return MVPP2_MAX_TCONT + Port->Id;
+}
+
+/* Get number of physical TXQ */
+STATIC
+inline
+INT32
+Mvpp2TxqPhys (
+ IN INT32 PortId,
+ IN INT32 Txq
+ )
+{
+ return (MVPP2_MAX_TCONT + PortId) * MVPP2_MAX_TXQ + Txq;
+}
+
+/* Set Pool number in a BM Cookie */
+STATIC
+inline
+UINT32
+Mvpp2BmCookiePoolSet (
+ IN UINT32 Cookie,
+ IN INT32 Pool
+ )
+{
+ UINT32 Bm;
+
+ Bm = Cookie & ~(0xFF << MVPP2_BM_COOKIE_POOL_OFFS);
+ Bm |= ((Pool & 0xFF) << MVPP2_BM_COOKIE_POOL_OFFS);
+
+ return Bm;
+}
+
+/* Get Pool number from a BM Cookie */
+STATIC
+inline
+INT32
+Mvpp2BmCookiePoolGet (
+ IN UINT32 Cookie
+ )
+{
+ return (Cookie >> MVPP2_BM_COOKIE_POOL_OFFS) & 0xFF;
+}
+
+/* Release buffer to BM */
+STATIC
+inline
+VOID
+Mvpp2BmPoolPut (
+ IN MVPP2_SHARED *Priv,
+ IN INT32 Pool,
+ IN UINT64 BufPhysAddr,
+ IN UINT64 BufVirtAddr
+ )
+{
+ UINT32 Val = 0;
+
+ Val = (Upper32Bits(BufVirtAddr) & MVPP22_ADDR_HIGH_MASK) << MVPP22_BM_VIRT_HIGH_RLS_OFFST;
+ Val |= (Upper32Bits(BufPhysAddr) & MVPP22_ADDR_HIGH_MASK) << MVPP22_BM_PHY_HIGH_RLS_OFFSET;
+ Mvpp2Write(Priv, MVPP22_BM_PHY_VIRT_HIGH_RLS_REG, Val);
+ Mvpp2Write(Priv, MVPP2_BM_VIRT_RLS_REG, (UINT32)BufVirtAddr);
+ Mvpp2Write(Priv, MVPP2_BM_PHY_RLS_REG(Pool), (UINT32)BufPhysAddr);
+}
+
+STATIC
+inline
+VOID
+Mvpp2InterruptsEnable (
+ IN PP2DXE_PORT *Port,
+ IN INT32 CpuMask
+ )
+{
+ Mvpp2Write(Port->Priv, MVPP2_ISR_ENABLE_REG(Port->Id), MVPP2_ISR_ENABLE_INTERRUPT(CpuMask));
+}
+
+STATIC
+inline
+VOID
+Mvpp2InterruptsDisable (
+ IN PP2DXE_PORT *Port,
+ IN INT32 CpuMask
+ )
+{
+ Mvpp2Write(Port->Priv, MVPP2_ISR_ENABLE_REG(Port->Id), MVPP2_ISR_DISABLE_INTERRUPT(CpuMask));
+}
+
+/* Get number of Rx descriptors occupied by received packets */
+STATIC
+inline
+INT32
+Mvpp2RxqReceived (
+ IN PP2DXE_PORT *Port,
+ IN INT32 RxqId
+ )
+{
+ UINT32 Val = Mvpp2Read(Port->Priv, MVPP2_RXQ_STATUS_REG(RxqId));
+
+ return Val & MVPP2_RXQ_OCCUPIED_MASK;
+}
+
+/*
+ * Update Rx Queue status with the number of occupied and available
+ * Rx descriptor slots.
+ */
+STATIC
+inline
+VOID
+Mvpp2RxqStatusUpdate (
+ IN PP2DXE_PORT *Port,
+ IN INT32 RxqId,
+ IN INT32 UsedCount,
+ IN INT32 FreeCount
+ )
+{
+ /*
+ * Decrement the number of used descriptors and increment count
+ * increment the number of free descriptors.
+ */
+ UINT32 Val = UsedCount | (FreeCount << MVPP2_RXQ_NUM_NEW_OFFSET);
+
+ Mvpp2Write(Port->Priv, MVPP2_RXQ_STATUS_UPDATE_REG(RxqId), Val);
+}
+
+/* Get pointer to next RX descriptor to be processed by SW */
+STATIC
+inline
+MVPP2_RX_DESC *
+Mvpp2RxqNextDescGet (
+ IN MVPP2_RX_QUEUE *Rxq
+ )
+{
+ INT32 RxDesc = Rxq->NextDescToProc;
+
+ Rxq->NextDescToProc = MVPP2_QUEUE_NEXT_DESC(Rxq, RxDesc);
+ Mvpp2Prefetch(Rxq->Descs + Rxq->NextDescToProc);
+ return Rxq->Descs + RxDesc;
+}
+
+/*
+ * Get number of sent descriptors and decrement counter.
+ * The number of sent descriptors is returned.
+ * Per-CPU access
+ */
+STATIC
+inline
+INT32
+Mvpp2TxqSentDescProc (
+ IN PP2DXE_PORT *Port,
+ IN MVPP2_TX_QUEUE *Txq
+ )
+{
+ UINT32 Val;
+
+ /* Reading status reg resets transmitted descriptor counter */
+#ifdef MVPP2V1
+ Val = Mvpp2Read(Port->Priv, MVPP2_TXQ_SENT_REG(Txq->Id));
+#else
+ Val = Mvpp2Read(Port->Priv, MVPP22_TXQ_SENT_REG(Txq->Id));
+#endif
+
+ return (Val & MVPP2_TRANSMITTED_COUNT_MASK) >> MVPP2_TRANSMITTED_COUNT_OFFSET;
+}
+
+STATIC
+inline
+MVPP2_RX_QUEUE *
+Mvpp2GetRxQueue (
+ IN PP2DXE_PORT *Port,
+ IN UINT32 Cause
+ )
+{
+ INT32 Queue = Mvpp2Fls(Cause) - 1;
+
+ return &Port->Rxqs[Queue];
+}
+
+STATIC
+inline
+MVPP2_TX_QUEUE *
+Mvpp2GetTxQueue (
+ IN PP2DXE_PORT *Port,
+ IN UINT32 Cause
+ )
+{
+ INT32 Queue = Mvpp2Fls(Cause) - 1;
+
+ return &Port->Txqs[Queue];
+}
+
+STATIC
+inline
+void
+Mvpp2x2TxdescPhysAddrSet (
+ IN DmaAddrT PhysAddr,
+ IN MVPP2_TX_DESC *TxDesc
+ )
+{
+ UINT64 *BufPhysAddrP = &TxDesc->BufPhysAddrHwCmd2;
+
+ *BufPhysAddrP &= ~(MVPP22_ADDR_MASK);
+ *BufPhysAddrP |= PhysAddr & MVPP22_ADDR_MASK;
+}
+#endif /* __MVPP2_LIB_H__ */
diff --git a/Platform/Marvell/Drivers/Net/Pp2Dxe/Mvpp2LibHw.h b/Platform/Marvell/Drivers/Net/Pp2Dxe/Mvpp2LibHw.h
new file mode 100644
index 0000000000..f283db2d49
--- /dev/null
+++ b/Platform/Marvell/Drivers/Net/Pp2Dxe/Mvpp2LibHw.h
@@ -0,0 +1,1968 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#ifndef __MVPP2_LIB_HW__
+#define __MVPP2_LIB_HW__
+
+#ifndef BIT
+#define BIT(nr) (1 << (nr))
+#endif
+
+/* RX Fifo Registers */
+#define MVPP2_RX_DATA_FIFO_SIZE_REG(port) (0x00 + 4 * (port))
+#define MVPP2_RX_ATTR_FIFO_SIZE_REG(port) (0x20 + 4 * (port))
+#define MVPP2_RX_MIN_PKT_SIZE_REG 0x60
+#define MVPP2_RX_FIFO_INIT_REG 0x64
+
+/* RX DMA Top Registers */
+#define MVPP2_RX_CTRL_REG(port) (0x140 + 4 * (port))
+#define MVPP2_RX_LOW_LATENCY_PKT_SIZE(s) (((s) & 0xfff) << 16)
+#define MVPP2_RX_USE_PSEUDO_FOR_CSUM_MASK BIT(31)
+#define MVPP2_POOL_BUF_SIZE_REG(pool) (0x180 + 4 * (pool))
+#define MVPP2_POOL_BUF_SIZE_OFFSET 5
+#define MVPP2_RXQ_CONFIG_REG(rxq) (0x800 + 4 * (rxq))
+#define MVPP2_SNOOP_PKT_SIZE_MASK 0x1ff
+#define MVPP2_SNOOP_BUF_HDR_MASK BIT(9)
+#define MVPP2_RXQ_POOL_SHORT_OFFS 20
+#define MVPP2_RXQ_POOL_SHORT_MASK 0x700000
+#define MVPP2_RXQ_POOL_LONG_OFFS 24
+#define MVPP2_RXQ_POOL_LONG_MASK 0x7000000
+#define MVPP2_RXQ_PACKET_OFFSET_OFFS 28
+#define MVPP2_RXQ_PACKET_OFFSET_MASK 0x70000000
+#define MVPP2_RXQ_DISABLE_MASK BIT(31)
+
+/* Parser Registers */
+#define MVPP2_PRS_INIT_LOOKUP_REG 0x1000
+#define MVPP2_PRS_PORT_LU_MAX 0xf
+#define MVPP2_PRS_PORT_LU_MASK(port) (0xff << ((port) * 4))
+#define MVPP2_PRS_PORT_LU_VAL(port, val) ((val) << ((port) * 4))
+#define MVPP2_PRS_INIT_OFFS_REG(port) (0x1004 + ((port) & 4))
+#define MVPP2_PRS_INIT_OFF_MASK(port) (0x3f << (((port) % 4) * 8))
+#define MVPP2_PRS_INIT_OFF_VAL(port, val) ((val) << (((port) % 4) * 8))
+#define MVPP2_PRS_MAX_LOOP_REG(port) (0x100c + ((port) & 4))
+#define MVPP2_PRS_MAX_LOOP_MASK(port) (0xff << (((port) % 4) * 8))
+#define MVPP2_PRS_MAX_LOOP_VAL(port, val) ((val) << (((port) % 4) * 8))
+#define MVPP2_PRS_TCAM_IDX_REG 0x1100
+#define MVPP2_PRS_TCAM_DATA_REG(idx) (0x1104 + (idx) * 4)
+#define MVPP2_PRS_TCAM_INV_MASK BIT(31)
+#define MVPP2_PRS_SRAM_IDX_REG 0x1200
+#define MVPP2_PRS_SRAM_DATA_REG(idx) (0x1204 + (idx) * 4)
+#define MVPP2_PRS_TCAM_CTRL_REG 0x1230
+#define MVPP2_PRS_TCAM_EN_MASK BIT(0)
+
+/* Classifier Registers */
+#define MVPP2_CLS_MODE_REG 0x1800
+#define MVPP2_CLS_MODE_ACTIVE_MASK BIT(0)
+#define MVPP2_CLS_PORT_WAY_REG 0x1810
+#define MVPP2_CLS_PORT_WAY_MASK(port) (1 << (port))
+#define MVPP2_CLS_LKP_INDEX_REG 0x1814
+#define MVPP2_CLS_LKP_INDEX_WAY_OFFS 6
+#define MVPP2_CLS_LKP_TBL_REG 0x1818
+#define MVPP2_CLS_LKP_TBL_RXQ_MASK 0xff
+#define MVPP2_CLS_LKP_TBL_LOOKUP_EN_MASK BIT(25)
+#define MVPP2_CLS_FLOW_INDEX_REG 0x1820
+#define MVPP2_CLS_FLOW_TBL0_REG 0x1824
+#define MVPP2_CLS_FLOW_TBL1_REG 0x1828
+#define MVPP2_CLS_FLOW_TBL2_REG 0x182c
+#define MVPP2_CLS_OVERSIZE_RXQ_LOW_REG(port) (0x1980 + ((port) * 4))
+#define MVPP2_CLS_OVERSIZE_RXQ_LOW_BITS 3
+#define MVPP2_CLS_OVERSIZE_RXQ_LOW_MASK 0x7
+#define MVPP2_CLS_SWFWD_P2HQ_REG(port) (0x19b0 + ((port) * 4))
+#define MVPP2_CLS_SWFWD_PCTRL_REG 0x19d0
+#define MVPP2_CLS_SWFWD_PCTRL_MASK(port) (1 << (port))
+
+/* Descriptor Manager Top Registers */
+#define MVPP2_RXQ_NUM_REG 0x2040
+#define MVPP2_RXQ_DESC_ADDR_REG 0x2044
+#define MVPP2_RXQ_DESC_SIZE_REG 0x2048
+#define MVPP2_RXQ_DESC_SIZE_MASK 0x3ff0
+#define MVPP2_RXQ_STATUS_UPDATE_REG(rxq) (0x3000 + 4 * (rxq))
+#define MVPP2_RXQ_NUM_PROCESSED_OFFSET 0
+#define MVPP2_RXQ_NUM_NEW_OFFSET 16
+#define MVPP2_RXQ_STATUS_REG(rxq) (0x3400 + 4 * (rxq))
+#define MVPP2_RXQ_OCCUPIED_MASK 0x3fff
+#define MVPP2_RXQ_NON_OCCUPIED_OFFSET 16
+#define MVPP2_RXQ_NON_OCCUPIED_MASK 0x3fff0000
+#define MVPP2_RXQ_THRESH_REG 0x204c
+#define MVPP2_OCCUPIED_THRESH_OFFSET 0
+#define MVPP2_OCCUPIED_THRESH_MASK 0x3fff
+#define MVPP2_RXQ_INDEX_REG 0x2050
+#define MVPP2_TXQ_NUM_REG 0x2080
+#define MVPP2_TXQ_DESC_ADDR_REG 0x2084
+#define MVPP22_TXQ_DESC_ADDR_HIGH_REG 0x20a8
+#define MVPP22_TXQ_DESC_ADDR_HIGH_MASK 0xff
+#define MVPP2_TXQ_DESC_SIZE_REG 0x2088
+#define MVPP2_TXQ_DESC_SIZE_MASK 0x3ff0
+#define MVPP2_AGGR_TXQ_UPDATE_REG 0x2090
+#define MVPP2_TXQ_THRESH_REG 0x2094
+#define MVPP2_TRANSMITTED_THRESH_OFFSET 16
+#define MVPP2_TRANSMITTED_THRESH_MASK 0x3fff0000
+#define MVPP2_TXQ_INDEX_REG 0x2098
+#define MVPP2_TXQ_PREF_BUF_REG 0x209c
+#define MVPP2_PREF_BUF_PTR(desc) ((desc) & 0xfff)
+#define MVPP2_PREF_BUF_SIZE_4 (BIT(12) | BIT(13))
+#define MVPP2_PREF_BUF_SIZE_16 (BIT(12) | BIT(14))
+#define MVPP2_PREF_BUF_THRESH(val) ((val) << 17)
+#define MVPP2_TXQ_DRAIN_EN_MASK BIT(31)
+#define MVPP2_TXQ_PENDING_REG 0x20a0
+#define MVPP2_TXQ_PENDING_MASK 0x3fff
+#define MVPP2_TXQ_INT_STATUS_REG 0x20a4
+#define MVPP2_TXQ_SENT_REG(txq) (0x3c00 + 4 * (txq))
+#define MVPP22_TXQ_SENT_REG(txq) (0x3e00 + 4 * (txq-128))
+#define MVPP2_TRANSMITTED_COUNT_OFFSET 16
+#define MVPP2_TRANSMITTED_COUNT_MASK 0x3fff0000
+#define MVPP2_TXQ_RSVD_REQ_REG 0x20b0
+#define MVPP2_TXQ_RSVD_REQ_Q_OFFSET 16
+#define MVPP2_TXQ_RSVD_RSLT_REG 0x20b4
+#define MVPP2_TXQ_RSVD_RSLT_MASK 0x3fff
+#define MVPP2_TXQ_RSVD_CLR_REG 0x20b8
+#define MVPP2_TXQ_RSVD_CLR_OFFSET 16
+#define MVPP2_AGGR_TXQ_DESC_ADDR_REG(cpu) (0x2100 + 4 * (cpu))
+#define MVPP2_AGGR_TXQ_DESC_SIZE_REG(cpu) (0x2140 + 4 * (cpu))
+#define MVPP2_AGGR_TXQ_DESC_SIZE_MASK 0x3ff0
+#define MVPP2_AGGR_TXQ_STATUS_REG(cpu) (0x2180 + 4 * (cpu))
+#define MVPP2_AGGR_TXQ_PENDING_MASK 0x3fff
+#define MVPP2_AGGR_TXQ_INDEX_REG(cpu) (0x21c0 + 4 * (cpu))
+
+/* MBUS bridge registers */
+#define MVPP2_WIN_BASE(w) (0x4000 + ((w) << 2))
+#define MVPP2_WIN_SIZE(w) (0x4020 + ((w) << 2))
+#define MVPP2_WIN_REMAP(w) (0x4040 + ((w) << 2))
+#define MVPP2_BASE_ADDR_ENABLE 0x4060
+
+/* Interrupt Cause and Mask registers */
+#define MVPP2_ISR_RX_THRESHOLD_REG(rxq) (0x5200 + 4 * (rxq))
+#define MVPP2_ISR_RXQ_GROUP_REG(rxq) (0x5400 + 4 * (rxq))
+#define MVPP2_ISR_ENABLE_REG(port) (0x5420 + 4 * (port))
+#define MVPP2_ISR_ENABLE_INTERRUPT(mask) ((mask) & 0xffff)
+#define MVPP2_ISR_DISABLE_INTERRUPT(mask) (((mask) << 16) & 0xffff0000)
+#define MVPP2_ISR_RX_TX_CAUSE_REG(port) (0x5480 + 4 * (port))
+#define MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK 0xffff
+#define MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK 0xff0000
+#define MVPP2_CAUSE_RX_FIFO_OVERRUN_MASK BIT(24)
+#define MVPP2_CAUSE_FCS_ERR_MASK BIT(25)
+#define MVPP2_CAUSE_TX_FIFO_UNDERRUN_MASK BIT(26)
+#define MVPP2_CAUSE_TX_EXCEPTION_SUM_MASK BIT(29)
+#define MVPP2_CAUSE_RX_EXCEPTION_SUM_MASK BIT(30)
+#define MVPP2_CAUSE_MISC_SUM_MASK BIT(31)
+#define MVPP2_ISR_RX_TX_MASK_REG(port) (0x54a0 + 4 * (port))
+#define MVPP2_ISR_PON_RX_TX_MASK_REG 0x54bc
+#define MVPP2_PON_CAUSE_RXQ_OCCUP_DESC_ALL_MASK 0xffff
+#define MVPP2_PON_CAUSE_TXP_OCCUP_DESC_ALL_MASK 0x3fc00000
+#define MVPP2_PON_CAUSE_MISC_SUM_MASK BIT(31)
+#define MVPP2_ISR_MISC_CAUSE_REG 0x55b0
+
+/* Buffer Manager registers */
+#define MVPP2_BM_POOL_BASE_REG(pool) (0x6000 + ((pool) * 4))
+#define MVPP2_BM_POOL_BASE_ADDR_MASK 0xfffff80
+#define MVPP2_BM_POOL_SIZE_REG(pool) (0x6040 + ((pool) * 4))
+#define MVPP2_BM_POOL_SIZE_MASK 0xfff0
+#define MVPP2_BM_POOL_READ_PTR_REG(pool) (0x6080 + ((pool) * 4))
+#define MVPP2_BM_POOL_GET_READ_PTR_MASK 0xfff0
+#define MVPP2_BM_POOL_PTRS_NUM_REG(pool) (0x60c0 + ((pool) * 4))
+#define MVPP2_BM_POOL_PTRS_NUM_MASK 0xfff0
+#define MVPP2_BM_BPPI_READ_PTR_REG(pool) (0x6100 + ((pool) * 4))
+#define MVPP2_BM_BPPI_PTRS_NUM_REG(pool) (0x6140 + ((pool) * 4))
+#define MVPP2_BM_BPPI_PTR_NUM_MASK 0x7ff
+#define MVPP2_BM_BPPI_PREFETCH_FULL_MASK BIT(16)
+#define MVPP2_BM_POOL_CTRL_REG(pool) (0x6200 + ((pool) * 4))
+#define MVPP2_BM_START_MASK BIT(0)
+#define MVPP2_BM_STOP_MASK BIT(1)
+#define MVPP2_BM_STATE_MASK BIT(4)
+#define MVPP2_BM_LOW_THRESH_OFFS 8
+#define MVPP2_BM_LOW_THRESH_MASK 0x7f00
+#define MVPP2_BM_LOW_THRESH_VALUE(val) ((val) << MVPP2_BM_LOW_THRESH_OFFS)
+#define MVPP2_BM_HIGH_THRESH_OFFS 16
+#define MVPP2_BM_HIGH_THRESH_MASK 0x7f0000
+#define MVPP2_BM_HIGH_THRESH_VALUE(val) ((val) << MVPP2_BM_HIGH_THRESH_OFFS)
+#define MVPP2_BM_INTR_CAUSE_REG(pool) (0x6240 + ((pool) * 4))
+#define MVPP2_BM_RELEASED_DELAY_MASK BIT(0)
+#define MVPP2_BM_ALLOC_FAILED_MASK BIT(1)
+#define MVPP2_BM_BPPE_EMPTY_MASK BIT(2)
+#define MVPP2_BM_BPPE_FULL_MASK BIT(3)
+#define MVPP2_BM_AVAILABLE_BP_LOW_MASK BIT(4)
+#define MVPP2_BM_INTR_MASK_REG(pool) (0x6280 + ((pool) * 4))
+#define MVPP2_BM_PHY_ALLOC_REG(pool) (0x6400 + ((pool) * 4))
+#define MVPP2_BM_PHY_ALLOC_GRNTD_MASK BIT(0)
+#define MVPP2_BM_VIRT_ALLOC_REG 0x6440
+#define MVPP2_BM_PHY_RLS_REG(pool) (0x6480 + ((pool) * 4))
+#define MVPP2_BM_PHY_RLS_MC_BUFF_MASK BIT(0)
+#define MVPP2_BM_PHY_RLS_PRIO_EN_MASK BIT(1)
+#define MVPP2_BM_PHY_RLS_GRNTD_MASK BIT(2)
+#define MVPP2_BM_VIRT_RLS_REG 0x64c0
+#define MVPP2_BM_MC_RLS_REG 0x64c4
+#define MVPP2_BM_MC_ID_MASK 0xfff
+#define MVPP2_BM_FORCE_RELEASE_MASK BIT(12)
+
+#define MVPP22_BM_PHY_VIRT_HIGH_ALLOC_REG 0x6444
+#define MVPP22_BM_PHY_HIGH_ALLOC_OFFSET 0
+#define MVPP22_BM_VIRT_HIGH_ALLOC_OFFSET 8
+#define MVPP22_BM_VIRT_HIGH_ALLOC_MASK 0xff00
+
+#define MVPP22_BM_PHY_VIRT_HIGH_RLS_REG 0x64c4
+
+#define MVPP22_BM_PHY_HIGH_RLS_OFFSET 0
+#define MVPP22_BM_VIRT_HIGH_RLS_OFFST 8
+
+#define MVPP22_BM_POOL_BASE_HIGH_REG 0x6310
+#define MVPP22_BM_POOL_BASE_HIGH_MASK 0xff
+#define MVPP2_BM_PRIO_CTRL_REG 0x6800
+
+/* TX Scheduler registers */
+#define MVPP2_TXP_SCHED_PORT_INDEX_REG 0x8000
+#define MVPP2_TXP_SCHED_Q_CMD_REG 0x8004
+#define MVPP2_TXP_SCHED_ENQ_MASK 0xff
+#define MVPP2_TXP_SCHED_DISQ_OFFSET 8
+#define MVPP2_TXP_SCHED_CMD_1_REG 0x8010
+#define MVPP2_TXP_SCHED_PERIOD_REG 0x8018
+#define MVPP2_TXP_SCHED_MTU_REG 0x801c
+#define MVPP2_TXP_MTU_MAX 0x7FFFF
+#define MVPP2_TXP_SCHED_REFILL_REG 0x8020
+#define MVPP2_TXP_REFILL_TOKENS_ALL_MASK 0x7ffff
+#define MVPP2_TXP_REFILL_PERIOD_ALL_MASK 0x3ff00000
+#define MVPP2_TXP_REFILL_PERIOD_MASK(v) ((v) << 20)
+#define MVPP2_TXP_SCHED_TOKEN_SIZE_REG 0x8024
+#define MVPP2_TXP_TOKEN_SIZE_MAX 0xffffffff
+#define MVPP2_TXQ_SCHED_REFILL_REG(q) (0x8040 + ((q) << 2))
+#define MVPP2_TXQ_REFILL_TOKENS_ALL_MASK 0x7ffff
+#define MVPP2_TXQ_REFILL_PERIOD_ALL_MASK 0x3ff00000
+#define MVPP2_TXQ_REFILL_PERIOD_MASK(v) ((v) << 20)
+#define MVPP2_TXQ_SCHED_TOKEN_SIZE_REG(q) (0x8060 + ((q) << 2))
+#define MVPP2_TXQ_TOKEN_SIZE_MAX 0x7fffffff
+#define MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(q) (0x8080 + ((q) << 2))
+#define MVPP2_TXQ_TOKEN_CNTR_MAX 0xffffffff
+
+/* TX general registers */
+#define MVPP2_TX_SNOOP_REG 0x8800
+#define MVPP2_TX_PORT_FLUSH_REG 0x8810
+#define MVPP2_TX_PORT_FLUSH_MASK(port) (1 << (port))
+
+/* LMS registers */
+#define MVPP2_SRC_ADDR_MIDDLE 0x24
+#define MVPP2_SRC_ADDR_HIGH 0x28
+#define MVPP2_PHY_AN_CFG0_REG 0x34
+#define MVPP2_PHY_AN_STOP_SMI0_MASK BIT(7)
+#define MVPP2_MIB_COUNTERS_BASE(port) (0x1000 + ((port) >> 1) * 0x400 + (port) * 0x400)
+#define MVPP2_MIB_LATE_COLLISION 0x7c
+#define MVPP2_ISR_SUM_MASK_REG 0x220c
+#define MVPP2_MNG_EXTENDED_GLOBAL_CTRL_REG 0x305c
+#define MVPP2_EXT_GLOBAL_CTRL_DEFAULT 0x27
+
+/* Per-port registers */
+#define MVPP2_GMAC_CTRL_0_REG 0x0
+#define MVPP2_GMAC_PORT_EN_MASK BIT(0)
+#define MVPP2_GMAC_MAX_RX_SIZE_OFFS 2
+#define MVPP2_GMAC_MAX_RX_SIZE_MASK 0x7ffc
+#define MVPP2_GMAC_MIB_CNTR_EN_MASK BIT(15)
+#define MVPP2_GMAC_CTRL_1_REG 0x4
+#define MVPP2_GMAC_PERIODIC_XON_EN_MASK BIT(1)
+#define MVPP2_GMAC_GMII_LB_EN_MASK BIT(5)
+#define MVPP2_GMAC_PCS_LB_EN_BIT 6
+#define MVPP2_GMAC_PCS_LB_EN_MASK BIT(6)
+#define MVPP2_GMAC_SA_LOW_OFFS 7
+#define MVPP2_GMAC_CTRL_2_REG 0x8
+#define MVPP2_GMAC_INBAND_AN_MASK BIT(0)
+#define MVPP2_GMAC_PCS_ENABLE_MASK BIT(3)
+#define MVPP2_GMAC_PORT_RGMII_MASK BIT(4)
+#define MVPP2_GMAC_PORT_RESET_MASK BIT(6)
+#define MVPP2_GMAC_AUTONEG_CONFIG 0xc
+#define MVPP2_GMAC_FORCE_LINK_DOWN BIT(0)
+#define MVPP2_GMAC_FORCE_LINK_PASS BIT(1)
+#define MVPP2_GMAC_CONFIG_MII_SPEED BIT(5)
+#define MVPP2_GMAC_CONFIG_GMII_SPEED BIT(6)
+#define MVPP2_GMAC_AN_SPEED_EN BIT(7)
+#define MVPP2_GMAC_FC_ADV_EN BIT(9)
+#define MVPP2_GMAC_CONFIG_FULL_DUPLEX BIT(12)
+#define MVPP2_GMAC_AN_DUPLEX_EN BIT(13)
+#define MVPP2_GMAC_PORT_FIFO_CFG_1_REG 0x1c
+#define MVPP2_GMAC_TX_FIFO_MIN_TH_OFFS 6
+#define MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK 0x1fc0
+#define MVPP2_GMAC_TX_FIFO_MIN_TH_MASK(v) (((v) << 6) & MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK)
+
+/* Port Interrupts */
+#define MV_GMAC_INTERRUPT_CAUSE_REG (0x0020)
+#define MV_GMAC_INTERRUPT_MASK_REG (0x0024)
+#define MV_GMAC_INTERRUPT_CAUSE_LINK_CHANGE_OFFS 1
+#define MV_GMAC_INTERRUPT_CAUSE_LINK_CHANGE_MASK (0x1 << MV_GMAC_INTERRUPT_CAUSE_LINK_CHANGE_OFFS)
+
+/* Port Interrupt Summary */
+#define MV_GMAC_INTERRUPT_SUM_CAUSE_REG (0x00A0)
+#define MV_GMAC_INTERRUPT_SUM_MASK_REG (0x00A4)
+#define MV_GMAC_INTERRUPT_SUM_CAUSE_LINK_CHANGE_OFFS 1
+#define MV_GMAC_INTERRUPT_SUM_CAUSE_LINK_CHANGE_MASK (0x1 << MV_GMAC_INTERRUPT_SUM_CAUSE_LINK_CHANGE_OFFS)
+
+/* Port Mac Control0 */
+#define MVPP2_PORT_CTRL0_REG (0x0000)
+#define MVPP2_PORT_CTRL0_PORTEN_OFFS 0
+#define MVPP2_PORT_CTRL0_PORTEN_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL0_PORTEN_OFFS)
+
+#define MVPP2_PORT_CTRL0_PORTTYPE_OFFS 1
+#define MVPP2_PORT_CTRL0_PORTTYPE_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL0_PORTTYPE_OFFS)
+
+#define MVPP2_PORT_CTRL0_FRAMESIZELIMIT_OFFS 2
+#define MVPP2_PORT_CTRL0_FRAMESIZELIMIT_MASK \
+ (0x00001fff << MVPP2_PORT_CTRL0_FRAMESIZELIMIT_OFFS)
+
+#define MVPP2_PORT_CTRL0_COUNT_EN_OFFS 15
+#define MVPP2_PORT_CTRL0_COUNT_EN_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL0_COUNT_EN_OFFS)
+
+/* Port Mac Control1 */
+#define MVPP2_PORT_CTRL1_REG (0x0004)
+#define MVPP2_PORT_CTRL1_EN_RX_CRC_CHECK_OFFS 0
+#define MVPP2_PORT_CTRL1_EN_RX_CRC_CHECK_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL1_EN_RX_CRC_CHECK_OFFS)
+
+#define MVPP2_PORT_CTRL1_EN_PERIODIC_FC_XON_OFFS 1
+#define MVPP2_PORT_CTRL1_EN_PERIODIC_FC_XON_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL1_EN_PERIODIC_FC_XON_OFFS)
+
+#define MVPP2_PORT_CTRL1_MGMII_MODE_OFFS 2
+#define MVPP2_PORT_CTRL1_MGMII_MODE_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL1_MGMII_MODE_OFFS)
+
+#define MVPP2_PORT_CTRL1_PFC_CASCADE_PORT_ENABLE_OFFS 3
+#define MVPP2_PORT_CTRL1_PFC_CASCADE_PORT_ENABLE_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL1_PFC_CASCADE_PORT_ENABLE_OFFS)
+
+#define MVPP2_PORT_CTRL1_DIS_EXCESSIVE_COL_OFFS 4
+#define MVPP2_PORT_CTRL1_DIS_EXCESSIVE_COL_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL1_DIS_EXCESSIVE_COL_OFFS)
+
+#define MVPP2_PORT_CTRL1_GMII_LOOPBACK_OFFS 5
+#define MVPP2_PORT_CTRL1_GMII_LOOPBACK_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL1_GMII_LOOPBACK_OFFS)
+
+#define MVPP2_PORT_CTRL1_PCS_LOOPBACK_OFFS 6
+#define MVPP2_PORT_CTRL1_PCS_LOOPBACK_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL1_PCS_LOOPBACK_OFFS)
+
+#define MVPP2_PORT_CTRL1_FC_SA_ADDR_LO_OFFS 7
+#define MVPP2_PORT_CTRL1_FC_SA_ADDR_LO_MASK \
+ (0x000000ff << MVPP2_PORT_CTRL1_FC_SA_ADDR_LO_OFFS)
+
+#define MVPP2_PORT_CTRL1_EN_SHORT_PREAMBLE_OFFS 15
+#define MVPP2_PORT_CTRL1_EN_SHORT_PREAMBLE_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL1_EN_SHORT_PREAMBLE_OFFS)
+
+/* Port Mac Control2 */
+#define MVPP2_PORT_CTRL2_REG (0x0008)
+#define MVPP2_PORT_CTRL2_SGMII_MODE_OFFS 0
+#define MVPP2_PORT_CTRL2_SGMII_MODE_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL2_SGMII_MODE_OFFS)
+
+#define MVPP2_PORT_CTRL2_FC_MODE_OFFS 1
+#define MVPP2_PORT_CTRL2_FC_MODE_MASK \
+ (0x00000003 << MVPP2_PORT_CTRL2_FC_MODE_OFFS)
+
+#define MVPP2_PORT_CTRL2_PCS_EN_OFFS 3
+#define MVPP2_PORT_CTRL2_PCS_EN_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL2_PCS_EN_OFFS)
+
+#define MVPP2_PORT_CTRL2_RGMII_MODE_OFFS 4
+#define MVPP2_PORT_CTRL2_RGMII_MODE_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL2_RGMII_MODE_OFFS)
+
+#define MVPP2_PORT_CTRL2_DIS_PADING_OFFS 5
+#define MVPP2_PORT_CTRL2_DIS_PADING_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL2_DIS_PADING_OFFS)
+
+#define MVPP2_PORT_CTRL2_PORTMACRESET_OFFS 6
+#define MVPP2_PORT_CTRL2_PORTMACRESET_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL2_PORTMACRESET_OFFS)
+
+#define MVPP2_PORT_CTRL2_TX_DRAIN_OFFS 7
+#define MVPP2_PORT_CTRL2_TX_DRAIN_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL2_TX_DRAIN_OFFS)
+
+#define MVPP2_PORT_CTRL2_EN_MII_ODD_PRE_OFFS 8
+#define MVPP2_PORT_CTRL2_EN_MII_ODD_PRE_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL2_EN_MII_ODD_PRE_OFFS)
+
+#define MVPP2_PORT_CTRL2_CLK_125_BYPS_EN_OFFS 9
+#define MVPP2_PORT_CTRL2_CLK_125_BYPS_EN_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL2_CLK_125_BYPS_EN_OFFS)
+
+#define MVPP2_PORT_CTRL2_PRBS_CHECK_EN_OFFS 10
+#define MVPP2_PORT_CTRL2_PRBS_CHECK_EN_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL2_PRBS_CHECK_EN_OFFS)
+
+#define MVPP2_PORT_CTRL2_PRBS_GEN_EN_OFFS 11
+#define MVPP2_PORT_CTRL2_PRBS_GEN_EN_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL2_PRBS_GEN_EN_OFFS)
+
+#define MVPP2_PORT_CTRL2_SELECT_DATA_TO_TX_OFFS 12
+#define MVPP2_PORT_CTRL2_SELECT_DATA_TO_TX_MASK \
+ (0x00000003 << MVPP2_PORT_CTRL2_SELECT_DATA_TO_TX_OFFS)
+
+#define MVPP2_PORT_CTRL2_EN_COL_ON_BP_OFFS 14
+#define MVPP2_PORT_CTRL2_EN_COL_ON_BP_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL2_EN_COL_ON_BP_OFFS)
+
+#define MVPP2_PORT_CTRL2_EARLY_REJECT_MODE_OFFS 15
+#define MVPP2_PORT_CTRL2_EARLY_REJECT_MODE_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL2_EARLY_REJECT_MODE_OFFS)
+
+/* Port Auto-negotiation Configuration */
+#define MVPP2_PORT_AUTO_NEG_CFG_REG (0x000c)
+#define MVPP2_PORT_AUTO_NEG_CFG_FORCE_LINK_DOWN_OFFS 0
+#define MVPP2_PORT_AUTO_NEG_CFG_FORCE_LINK_DOWN_MASK \
+ (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_FORCE_LINK_DOWN_OFFS)
+
+#define MVPP2_PORT_AUTO_NEG_CFG_FORCE_LINK_UP_OFFS 1
+#define MVPP2_PORT_AUTO_NEG_CFG_FORCE_LINK_UP_MASK \
+ (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_FORCE_LINK_UP_OFFS)
+
+#define MVPP2_PORT_AUTO_NEG_CFG_EN_PCS_AN_OFFS 2
+#define MVPP2_PORT_AUTO_NEG_CFG_EN_PCS_AN_MASK \
+ (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_EN_PCS_AN_OFFS)
+
+#define MVPP2_PORT_AUTO_NEG_CFG_AN_BYPASS_EN_OFFS 3
+#define MVPP2_PORT_AUTO_NEG_CFG_AN_BYPASS_EN_MASK \
+ (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_AN_BYPASS_EN_OFFS)
+
+#define MVPP2_PORT_AUTO_NEG_CFG_INBAND_RESTARTAN_OFFS 4
+#define MVPP2_PORT_AUTO_NEG_CFG_INBAND_RESTARTAN_MASK \
+ (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_INBAND_RESTARTAN_OFFS)
+
+#define MVPP2_PORT_AUTO_NEG_CFG_SET_MII_SPEED_OFFS 5
+#define MVPP2_PORT_AUTO_NEG_CFG_SET_MII_SPEED_MASK \
+ (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_SET_MII_SPEED_OFFS)
+
+#define MVPP2_PORT_AUTO_NEG_CFG_SET_GMII_SPEED_OFFS 6
+#define MVPP2_PORT_AUTO_NEG_CFG_SET_GMII_SPEED_MASK \
+ (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_SET_GMII_SPEED_OFFS)
+
+#define MVPP2_PORT_AUTO_NEG_CFG_EN_AN_SPEED_OFFS 7
+#define MVPP2_PORT_AUTO_NEG_CFG_EN_AN_SPEED_MASK \
+ (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_EN_AN_SPEED_OFFS)
+
+#define MVPP2_PORT_AUTO_NEG_CFG_ADV_PAUSE_OFFS 9
+#define MVPP2_PORT_AUTO_NEG_CFG_ADV_PAUSE_MASK \
+ (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_ADV_PAUSE_OFFS)
+
+#define MVPP2_PORT_AUTO_NEG_CFG_ADV_ASM_PAUSE_OFFS 10
+#define MVPP2_PORT_AUTO_NEG_CFG_ADV_ASM_PAUSE_MASK \
+ (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_ADV_ASM_PAUSE_OFFS)
+
+#define MVPP2_PORT_AUTO_NEG_CFG_EN_FC_AN_OFFS 11
+#define MVPP2_PORT_AUTO_NEG_CFG_EN_FC_AN_MASK \
+ (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_EN_FC_AN_OFFS)
+
+#define MVPP2_PORT_AUTO_NEG_CFG_SET_FULL_DX_OFFS 12
+#define MVPP2_PORT_AUTO_NEG_CFG_SET_FULL_DX_MASK \
+ (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_SET_FULL_DX_OFFS)
+
+#define MVPP2_PORT_AUTO_NEG_CFG_EN_FDX_AN_OFFS 13
+#define MVPP2_PORT_AUTO_NEG_CFG_EN_FDX_AN_MASK \
+ (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_EN_FDX_AN_OFFS)
+
+#define MVPP2_PORT_AUTO_NEG_CFG_PHY_MODE_OFFS 14
+#define MVPP2_PORT_AUTO_NEG_CFG_PHY_MODE_MASK \
+ (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_PHY_MODE_OFFS)
+
+#define MVPP2_PORT_AUTO_NEG_CFG_CHOOSE_SAMPLE_TX_CONFIG_OFFS 15
+#define MVPP2_PORT_AUTO_NEG_CFG_CHOOSE_SAMPLE_TX_CONFIG_MASK \
+ (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_CHOOSE_SAMPLE_TX_CONFIG_OFFS)
+
+/* Port Status0 */
+#define MVPP2_PORT_STATUS0_REG (0x0010)
+#define MVPP2_PORT_STATUS0_LINKUP_OFFS 0
+#define MVPP2_PORT_STATUS0_LINKUP_MASK \
+ (0x00000001 << MVPP2_PORT_STATUS0_LINKUP_OFFS)
+
+#define MVPP2_PORT_STATUS0_GMIISPEED_OFFS 1
+#define MVPP2_PORT_STATUS0_GMIISPEED_MASK \
+ (0x00000001 << MVPP2_PORT_STATUS0_GMIISPEED_OFFS)
+
+#define MVPP2_PORT_STATUS0_MIISPEED_OFFS 2
+#define MVPP2_PORT_STATUS0_MIISPEED_MASK \
+ (0x00000001 << MVPP2_PORT_STATUS0_MIISPEED_OFFS)
+
+#define MVPP2_PORT_STATUS0_FULLDX_OFFS 3
+#define MVPP2_PORT_STATUS0_FULLDX_MASK \
+ (0x00000001 << MVPP2_PORT_STATUS0_FULLDX_OFFS)
+
+#define MVPP2_PORT_STATUS0_RXFCEN_OFFS 4
+#define MVPP2_PORT_STATUS0_RXFCEN_MASK \
+ (0x00000001 << MVPP2_PORT_STATUS0_RXFCEN_OFFS)
+
+#define MVPP2_PORT_STATUS0_TXFCEN_OFFS 5
+#define MVPP2_PORT_STATUS0_TXFCEN_MASK \
+ (0x00000001 << MVPP2_PORT_STATUS0_TXFCEN_OFFS)
+
+#define MVPP2_PORT_STATUS0_PORTRXPAUSE_OFFS 6
+#define MVPP2_PORT_STATUS0_PORTRXPAUSE_MASK \
+ (0x00000001 << MVPP2_PORT_STATUS0_PORTRXPAUSE_OFFS)
+
+#define MVPP2_PORT_STATUS0_PORTTXPAUSE_OFFS 7
+#define MVPP2_PORT_STATUS0_PORTTXPAUSE_MASK \
+ (0x00000001 << MVPP2_PORT_STATUS0_PORTTXPAUSE_OFFS)
+
+#define MVPP2_PORT_STATUS0_PORTIS_DOINGPRESSURE_OFFS 8
+#define MVPP2_PORT_STATUS0_PORTIS_DOINGPRESSURE_MASK \
+ (0x00000001 << MVPP2_PORT_STATUS0_PORTIS_DOINGPRESSURE_OFFS)
+
+#define MVPP2_PORT_STATUS0_PORTBUFFULL_OFFS 9
+#define MVPP2_PORT_STATUS0_PORTBUFFULL_MASK \
+ (0x00000001 << MVPP2_PORT_STATUS0_PORTBUFFULL_OFFS)
+
+#define MVPP2_PORT_STATUS0_SYNCFAIL10MS_OFFS 10
+#define MVPP2_PORT_STATUS0_SYNCFAIL10MS_MASK \
+ (0x00000001 << MVPP2_PORT_STATUS0_SYNCFAIL10MS_OFFS)
+
+#define MVPP2_PORT_STATUS0_ANDONE_OFFS 11
+#define MVPP2_PORT_STATUS0_ANDONE_MASK \
+ (0x00000001 << MVPP2_PORT_STATUS0_ANDONE_OFFS)
+
+#define MVPP2_PORT_STATUS0_INBAND_AUTONEG_BYPASSACT_OFFS 12
+#define MVPP2_PORT_STATUS0_INBAND_AUTONEG_BYPASSACT_MASK \
+ (0x00000001 << MVPP2_PORT_STATUS0_INBAND_AUTONEG_BYPASSACT_OFFS)
+
+#define MVPP2_PORT_STATUS0_SERDESPLL_LOCKED_OFFS 13
+#define MVPP2_PORT_STATUS0_SERDESPLL_LOCKED_MASK \
+ (0x00000001 << MVPP2_PORT_STATUS0_SERDESPLL_LOCKED_OFFS)
+
+#define MVPP2_PORT_STATUS0_SYNCOK_OFFS 14
+#define MVPP2_PORT_STATUS0_SYNCOK_MASK \
+ (0x00000001 << MVPP2_PORT_STATUS0_SYNCOK_OFFS)
+
+#define MVPP2_PORT_STATUS0_SQUELCHNOT_DETECTED_OFFS 15
+#define MVPP2_PORT_STATUS0_SQUELCHNOT_DETECTED_MASK \
+ (0x00000001 << MVPP2_PORT_STATUS0_SQUELCHNOT_DETECTED_OFFS)
+
+/* Port Serial Parameters Configuration */
+#define MVPP2_PORT_SERIAL_PARAM_CFG_REG (0x0014)
+#define MVPP2_PORT_SERIAL_PARAM_CFG_UNIDIRECTIONAL_ENABLE_OFFS 0
+#define MVPP2_PORT_SERIAL_PARAM_CFG_UNIDIRECTIONAL_ENABLE_MASK \
+ (0x00000001 << MVPP2_PORT_SERIAL_PARAM_CFG_UNIDIRECTIONAL_ENABLE_OFFS)
+
+#define MVPP2_PORT_SERIAL_PARAM_CFG_RETRANSMIT_COLLISION_DOMAIN_OFFS 1
+#define MVPP2_PORT_SERIAL_PARAM_CFG_RETRANSMIT_COLLISION_DOMAIN_MASK \
+ (0x00000001 << MVPP2_PORT_SERIAL_PARAM_CFG_RETRANSMIT_COLLISION_DOMAIN_OFFS)
+
+#define MVPP2_PORT_SERIAL_PARAM_CFG_PUMA2_BTS1444_EN_OFFS 2
+#define MVPP2_PORT_SERIAL_PARAM_CFG_PUMA2_BTS1444_EN_MASK \
+ (0x00000001 << MVPP2_PORT_SERIAL_PARAM_CFG_PUMA2_BTS1444_EN_OFFS)
+
+#define MVPP2_PORT_SERIAL_PARAM_CFG_FORWARD_802_3X_FC_EN_OFFS 3
+#define MVPP2_PORT_SERIAL_PARAM_CFG_FORWARD_802_3X_FC_EN_MASK \
+ (0x00000001 << MVPP2_PORT_SERIAL_PARAM_CFG_FORWARD_802_3X_FC_EN_OFFS)
+
+#define MVPP2_PORT_SERIAL_PARAM_CFG_BP_EN_OFFS 4
+#define MVPP2_PORT_SERIAL_PARAM_CFG_BP_EN_MASK \
+ (0x00000001 << MVPP2_PORT_SERIAL_PARAM_CFG_BP_EN_OFFS)
+
+#define MVPP2_PORT_SERIAL_PARAM_CFG_RX_NEGEDGE_SAMPLE_EN_OFFS 5
+#define MVPP2_PORT_SERIAL_PARAM_CFG_RX_NEGEDGE_SAMPLE_EN_MASK \
+ (0x00000001 << MVPP2_PORT_SERIAL_PARAM_CFG_RX_NEGEDGE_SAMPLE_EN_OFFS)
+
+#define MVPP2_PORT_SERIAL_PARAM_CFG_COL_DOMAIN_LIMIT_OFFS 6
+#define MVPP2_PORT_SERIAL_PARAM_CFG_COL_DOMAIN_LIMIT_MASK \
+ (0x0000003f << MVPP2_PORT_SERIAL_PARAM_CFG_COL_DOMAIN_LIMIT_OFFS)
+
+#define MVPP2_PORT_SERIAL_PARAM_CFG_PERIODIC_TYPE_SELECT_OFFS 12
+#define MVPP2_PORT_SERIAL_PARAM_CFG_PERIODIC_TYPE_SELECT_MASK \
+ (0x00000001 << MVPP2_PORT_SERIAL_PARAM_CFG_PERIODIC_TYPE_SELECT_OFFS)
+
+#define MVPP2_PORT_SERIAL_PARAM_CFG_PER_PRIORITY_FC_EN_OFFS 13
+#define MVPP2_PORT_SERIAL_PARAM_CFG_PER_PRIORITY_FC_EN_MASK \
+ (0x00000001 << MVPP2_PORT_SERIAL_PARAM_CFG_PER_PRIORITY_FC_EN_OFFS)
+
+#define MVPP2_PORT_SERIAL_PARAM_CFG_TX_STANDARD_PRBS7_OFFS 14
+#define MVPP2_PORT_SERIAL_PARAM_CFG_TX_STANDARD_PRBS7_MASK \
+ (0x00000001 << MVPP2_PORT_SERIAL_PARAM_CFG_TX_STANDARD_PRBS7_OFFS)
+
+#define MVPP2_PORT_SERIAL_PARAM_CFG_REVERSE_PRBS_RX_OFFS 15
+#define MVPP2_PORT_SERIAL_PARAM_CFG_REVERSE_PRBS_RX_MASK \
+ (0x00000001 << MVPP2_PORT_SERIAL_PARAM_CFG_REVERSE_PRBS_RX_OFFS)
+
+/* Port Fifo Configuration 0 */
+#define MVPP2_PORT_FIFO_CFG_0_REG (0x0018)
+#define MVPP2_PORT_FIFO_CFG_0_TX_FIFO_HIGH_WM_OFFS 0
+#define MVPP2_PORT_FIFO_CFG_0_TX_FIFO_HIGH_WM_MASK \
+ (0x000000ff << MVPP2_PORT_FIFO_CFG_0_TX_FIFO_HIGH_WM_OFFS)
+
+#define MVPP2_PORT_FIFO_CFG_0_TX_FIFO_LOW_WM_OFFS 8
+#define MVPP2_PORT_FIFO_CFG_0_TX_FIFO_LOW_WM_MASK \
+ (0x000000ff << MVPP2_PORT_FIFO_CFG_0_TX_FIFO_LOW_WM_OFFS)
+
+/* Port Fifo Configuration 1 */
+#define MVPP2_PORT_FIFO_CFG_1_REG (0x001c)
+#define MVPP2_PORT_FIFO_CFG_1_RX_FIFO_MAX_TH_OFFS 0
+#define MVPP2_PORT_FIFO_CFG_1_RX_FIFO_MAX_TH_MASK \
+ (0x0000003f << MVPP2_PORT_FIFO_CFG_1_RX_FIFO_MAX_TH_OFFS)
+
+#define MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_OFFS 6
+#define MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_MASK \
+ (0x000000ff << MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_OFFS)
+
+#define MVPP2_PORT_FIFO_CFG_1_PORT_EN_FIX_EN_OFFS 15
+#define MVPP2_PORT_FIFO_CFG_1_PORT_EN_FIX_EN_MASK \
+ (0x00000001 << MVPP2_PORT_FIFO_CFG_1_PORT_EN_FIX_EN_OFFS)
+
+/* Port Serdes Configuration0 */
+#define MVPP2_PORT_SERDES_CFG0_REG (0x0028)
+#define MVPP2_PORT_SERDES_CFG0_SERDESRESET_OFFS 0
+#define MVPP2_PORT_SERDES_CFG0_SERDESRESET_MASK \
+ (0x00000001 << MVPP2_PORT_SERDES_CFG0_SERDESRESET_OFFS)
+
+#define MVPP2_PORT_SERDES_CFG0_PU_TX_OFFS 1
+#define MVPP2_PORT_SERDES_CFG0_PU_TX_MASK \
+ (0x00000001 << MVPP2_PORT_SERDES_CFG0_PU_TX_OFFS)
+
+#define MVPP2_PORT_SERDES_CFG0_PU_RX_OFFS 2
+#define MVPP2_PORT_SERDES_CFG0_PU_RX_MASK \
+ (0x00000001 << MVPP2_PORT_SERDES_CFG0_PU_RX_OFFS)
+
+#define MVPP2_PORT_SERDES_CFG0_PU_PLL_OFFS 3
+#define MVPP2_PORT_SERDES_CFG0_PU_PLL_MASK \
+ (0x00000001 << MVPP2_PORT_SERDES_CFG0_PU_PLL_OFFS)
+
+#define MVPP2_PORT_SERDES_CFG0_PU_IVREF_OFFS 4
+#define MVPP2_PORT_SERDES_CFG0_PU_IVREF_MASK \
+ (0x00000001 << MVPP2_PORT_SERDES_CFG0_PU_IVREF_OFFS)
+
+#define MVPP2_PORT_SERDES_CFG0_TESTEN_OFFS 5
+#define MVPP2_PORT_SERDES_CFG0_TESTEN_MASK \
+ (0x00000001 << MVPP2_PORT_SERDES_CFG0_TESTEN_OFFS)
+
+#define MVPP2_PORT_SERDES_CFG0_DPHER_EN_OFFS 6
+#define MVPP2_PORT_SERDES_CFG0_DPHER_EN_MASK \
+ (0x00000001 << MVPP2_PORT_SERDES_CFG0_DPHER_EN_OFFS)
+
+#define MVPP2_PORT_SERDES_CFG0_RUDI_INVALID_ENABLE_OFFS 7
+#define MVPP2_PORT_SERDES_CFG0_RUDI_INVALID_ENABLE_MASK \
+ (0x00000001 << MVPP2_PORT_SERDES_CFG0_RUDI_INVALID_ENABLE_OFFS)
+
+#define MVPP2_PORT_SERDES_CFG0_ACK_OVERRIDE_ENABLE_OFFS 8
+#define MVPP2_PORT_SERDES_CFG0_ACK_OVERRIDE_ENABLE_MASK \
+ (0x00000001 << MVPP2_PORT_SERDES_CFG0_ACK_OVERRIDE_ENABLE_OFFS)
+
+#define MVPP2_PORT_SERDES_CFG0_CONFIG_WORD_ENABLE_OFFS 9
+#define MVPP2_PORT_SERDES_CFG0_CONFIG_WORD_ENABLE_MASK \
+ (0x00000001 << MVPP2_PORT_SERDES_CFG0_CONFIG_WORD_ENABLE_OFFS)
+
+#define MVPP2_PORT_SERDES_CFG0_SYNC_FAIL_INT_ENABLE_OFFS 10
+#define MVPP2_PORT_SERDES_CFG0_SYNC_FAIL_INT_ENABLE_MASK \
+ (0x00000001 << MVPP2_PORT_SERDES_CFG0_SYNC_FAIL_INT_ENABLE_OFFS)
+
+#define MVPP2_PORT_SERDES_CFG0_MASTER_MODE_ENABLE_OFFS 11
+#define MVPP2_PORT_SERDES_CFG0_MASTER_MODE_ENABLE_MASK \
+ (0x00000001 << MVPP2_PORT_SERDES_CFG0_MASTER_MODE_ENABLE_OFFS)
+
+#define MVPP2_PORT_SERDES_CFG0_TERM75_TX_OFFS 12
+#define MVPP2_PORT_SERDES_CFG0_TERM75_TX_MASK \
+ (0x00000001 << MVPP2_PORT_SERDES_CFG0_TERM75_TX_OFFS)
+
+#define MVPP2_PORT_SERDES_CFG0_OUTAMP_OFFS 13
+#define MVPP2_PORT_SERDES_CFG0_OUTAMP_MASK \
+ (0x00000001 << MVPP2_PORT_SERDES_CFG0_OUTAMP_OFFS)
+
+#define MVPP2_PORT_SERDES_CFG0_BTS712_FIX_EN_OFFS 14
+#define MVPP2_PORT_SERDES_CFG0_BTS712_FIX_EN_MASK \
+ (0x00000001 << MVPP2_PORT_SERDES_CFG0_BTS712_FIX_EN_OFFS)
+
+#define MVPP2_PORT_SERDES_CFG0_BTS156_FIX_EN_OFFS 15
+#define MVPP2_PORT_SERDES_CFG0_BTS156_FIX_EN_MASK \
+ (0x00000001 << MVPP2_PORT_SERDES_CFG0_BTS156_FIX_EN_OFFS)
+
+/* Port Serdes Configuration1 */
+#define MVPP2_PORT_SERDES_CFG1_REG (0x002c)
+#define MVPP2_PORT_SERDES_CFG1_SMII_RX_10MB_CLK_EDGE_SEL_OFFS 0
+#define MVPP2_PORT_SERDES_CFG1_SMII_RX_10MB_CLK_EDGE_SEL_MASK \
+ (0x00000001 << MVPP2_GMAC_PORT_SERDES_CFG1_SMII_RX_10MB_CLK_EDGE_SEL_OFFS)
+
+#define MVPP2_GMAC_PORT_SERDES_CFG1_SMII_TX_10MB_CLK_EDGE_SEL_OFFS 1
+#define MVPP2_GMAC_PORT_SERDES_CFG1_SMII_TX_10MB_CLK_EDGE_SEL_MASK \
+ (0x00000001 << MVPP2_GMAC_PORT_SERDES_CFG1_SMII_TX_10MB_CLK_EDGE_SEL_OFFS)
+
+#define MVPP2_GMAC_PORT_SERDES_CFG1_MEN_OFFS 2
+#define MVPP2_GMAC_PORT_SERDES_CFG1_MEN_MASK \
+ (0x00000003 << MVPP2_GMAC_PORT_SERDES_CFG1_MEN_OFFS)
+
+#define MVPP2_GMAC_PORT_SERDES_CFG1_VCMS_OFFS 4
+#define MVPP2_GMAC_PORT_SERDES_CFG1_VCMS_MASK \
+ (0x00000001 << MVPP2_GMAC_PORT_SERDES_CFG1_VCMS_OFFS)
+
+#define MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_USE_SIGDET_OFFS 5
+#define MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_USE_SIGDET_MASK \
+ (0x00000001 << MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_USE_SIGDET_OFFS)
+
+#define MVPP2_GMAC_PORT_SERDES_CFG1_EN_CRS_MASK_TX_OFFS 6
+#define MVPP2_GMAC_PORT_SERDES_CFG1_EN_CRS_MASK_TX_MASK \
+ (0x00000001 << MVPP2_GMAC_PORT_SERDES_CFG1_EN_CRS_MASK_TX_OFFS)
+
+#define MVPP2_GMAC_PORT_SERDES_CFG1_100FX_ENABLE_OFFS 7
+#define MVPP2_GMAC_PORT_SERDES_CFG1_100FX_ENABLE_MASK \
+ (0x00000001 << MVPP2_GMAC_PORT_SERDES_CFG1_100FX_ENABLE_OFFS)
+
+#define MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_PHY_ADDRESS_OFFS 8
+#define MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_PHY_ADDRESS_MASK \
+ (0x0000001f << MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_PHY_ADDRESS_OFFS)
+
+#define MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_SIGDET_POLARITY_OFFS 13
+#define MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_SIGDET_POLARITY_MASK \
+ (0x00000001 << MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_SIGDET_POLARITY_OFFS)
+
+#define MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_INTERRUPT_POLARITY_OFFS 14
+#define MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_INTERRUPT_POLARITY_MASK \
+ (0x00000001 << MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_INTERRUPT_POLARITY_OFFS)
+
+#define MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_SERDES_POLARITY_OFFS 15
+#define MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_SERDES_POLARITY_MASK \
+ (0x00000001 << MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_SERDES_POLARITY_OFFS)
+
+/* Port Serdes Configuration2 */
+#define MVPP2_PORT_SERDES_CFG2_REG (0x0030)
+#define MVPP2_PORT_SERDES_CFG2_AN_ADV_CONFIGURATION_OFFS 0
+#define MVPP2_PORT_SERDES_CFG2_AN_ADV_CONFIGURATION_MASK \
+ (0x0000ffff << MVPP2_PORT_SERDES_CFG2_AN_ADV_CONFIGURATION_OFFS)
+
+/* Port Serdes Configuration3 */
+#define MVPP2_PORT_SERDES_CFG3_REG (0x0034)
+#define MVPP2_PORT_SERDES_CFG3_ABILITY_MATCH_STATUS_OFFS 0
+#define MVPP2_PORT_SERDES_CFG3_ABILITY_MATCH_STATUS_MASK \
+ (0x0000ffff << MVPP2_PORT_SERDES_CFG3_ABILITY_MATCH_STATUS_OFFS)
+
+/* Port Prbs Status */
+#define MVPP2_PORT_PRBS_STATUS_REG (0x0038)
+#define MVPP2_PORT_PRBS_STATUS_PRBSCHECK_LOCKED_OFFS 0
+#define MVPP2_PORT_PRBS_STATUS_PRBSCHECK_LOCKED_MASK \
+ (0x00000001 << MVPP2_PORT_PRBS_STATUS_PRBSCHECK_LOCKED_OFFS)
+
+#define MVPP2_PORT_PRBS_STATUS_PRBSCHECKRDY_OFFS 1
+#define MVPP2_PORT_PRBS_STATUS_PRBSCHECKRDY_MASK \
+ (0x00000001 << MVPP2_PORT_PRBS_STATUS_PRBSCHECKRDY_OFFS)
+
+/* Port Prbs Error Counter */
+#define MVPP2_PORT_PRBS_ERR_CNTR_REG (0x003c)
+#define MVPP2_PORT_PRBS_ERR_CNTR_PRBSBITERRCNT_OFFS 0
+#define MVPP2_PORT_PRBS_ERR_CNTR_PRBSBITERRCNT_MASK \
+ (0x0000ffff << MVPP2_PORT_PRBS_ERR_CNTR_PRBSBITERRCNT_OFFS)
+
+/* Port Status1 */
+#define MVPP2_PORT_STATUS1_REG (0x0040)
+#define MVPP2_PORT_STATUS1_MEDIAACTIVE_OFFS 0
+#define MVPP2_PORT_STATUS1_MEDIAACTIVE_MASK \
+ (0x00000001 << MVPP2_PORT_STATUS1_MEDIAACTIVE_OFFS)
+
+/* Port Mib Counters Control */
+#define MVPP2_PORT_MIB_CNTRS_CTRL_REG (0x0044)
+#define MVPP2_PORT_MIB_CNTRS_CTRL_MIB_COPY_TRIGGER_OFFS 0
+#define MVPP2_PORT_MIB_CNTRS_CTRL_MIB_COPY_TRIGGER_MASK \
+ (0x00000001 << MVPP2_PORT_MIB_CNTRS_CTRL_MIB_COPY_TRIGGER_OFFS)
+
+#define MVPP2_PORT_MIB_CNTRS_CTRL_MIB_CLEAR_ON_READ__OFFS 1
+#define MVPP2_PORT_MIB_CNTRS_CTRL_MIB_CLEAR_ON_READ__MASK \
+ (0x00000001 << MVPP2_PORT_MIB_CNTRS_CTRL_MIB_CLEAR_ON_READ__OFFS)
+
+#define MVPP2_PORT_MIB_CNTRS_CTRL_RX_HISTOGRAM_EN_OFFS 2
+#define MVPP2_PORT_MIB_CNTRS_CTRL_RX_HISTOGRAM_EN_MASK \
+ (0x00000001 << MVPP2_PORT_MIB_CNTRS_CTRL_RX_HISTOGRAM_EN_OFFS)
+
+#define MVPP2_PORT_MIB_CNTRS_CTRL_TX_HISTOGRAM_EN_OFFS 3
+#define MVPP2_PORT_MIB_CNTRS_CTRL_TX_HISTOGRAM_EN_MASK \
+ (0x00000001 << MVPP2_PORT_MIB_CNTRS_CTRL_TX_HISTOGRAM_EN_OFFS)
+
+#define MVPP2_PORT_MIB_CNTRS_CTRL_MFA1_BTT940_FIX_ENABLE__OFFS 4
+#define MVPP2_PORT_MIB_CNTRS_CTRL_MFA1_BTT940_FIX_ENABLE__MASK \
+ (0x00000001 << MVPP2_PORT_MIB_CNTRS_CTRL_MFA1_BTT940_FIX_ENABLE__OFFS)
+
+#define MVPP2_PORT_MIB_CNTRS_CTRL_XCAT_BTS_340_EN__OFFS 5
+#define MVPP2_PORT_MIB_CNTRS_CTRL_XCAT_BTS_340_EN__MASK \
+ (0x00000001 << MVPP2_PORT_MIB_CNTRS_CTRL_XCAT_BTS_340_EN__OFFS)
+
+#define MVPP2_PORT_MIB_CNTRS_CTRL_MIB_4_COUNT_HIST_OFFS 6
+#define MVPP2_PORT_MIB_CNTRS_CTRL_MIB_4_COUNT_HIST_MASK \
+ (0x00000001 << MVPP2_PORT_MIB_CNTRS_CTRL_MIB_4_COUNT_HIST_OFFS)
+
+#define MVPP2_PORT_MIB_CNTRS_CTRL_MIB_4_LIMIT_1518_1522_OFFS 7
+#define MVPP2_PORT_MIB_CNTRS_CTRL_MIB_4_LIMIT_1518_1522_MASK \
+ (0x00000001 << MVPP2_PORT_MIB_CNTRS_CTRL_MIB_4_LIMIT_1518_1522_OFFS)
+
+/* Port Mac Control3 */
+#define MVPP2_PORT_CTRL3_REG (0x0048)
+#define MVPP2_PORT_CTRL3_BUF_SIZE_OFFS 0
+#define MVPP2_PORT_CTRL3_BUF_SIZE_MASK \
+ (0x0000003f << MVPP2_PORT_CTRL3_BUF_SIZE_OFFS)
+
+#define MVPP2_PORT_CTRL3_IPG_DATA_OFFS 6
+#define MVPP2_PORT_CTRL3_IPG_DATA_MASK \
+ (0x000001ff << MVPP2_PORT_CTRL3_IPG_DATA_OFFS)
+
+#define MVPP2_PORT_CTRL3_LLFC_GLOBAL_FC_ENABLE_OFFS 15
+#define MVPP2_PORT_CTRL3_LLFC_GLOBAL_FC_ENABLE_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL3_LLFC_GLOBAL_FC_ENABLE_OFFS)
+#define MVPP2_CAUSE_TXQ_SENT_DESC_ALL_MASK 0xff
+
+/* Port Mac Control4 */
+#define MVPP2_PORT_CTRL4_REG (0x0090)
+#define MVPP2_PORT_CTRL4_EXT_PIN_GMII_SEL_OFFS 0
+#define MVPP2_PORT_CTRL4_EXT_PIN_GMII_SEL_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL4_EXT_PIN_GMII_SEL_OFFS)
+
+#define MVPP2_PORT_CTRL4_PREAMBLE_FIX_OFFS 1
+#define MVPP2_PORT_CTRL4_PREAMBLE_FIX_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL4_PREAMBLE_FIX_OFFS)
+
+#define MVPP2_PORT_CTRL4_SQ_DETECT_FIX_EN_OFFS 2
+#define MVPP2_PORT_CTRL4_SQ_DETECT_FIX_EN_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL4_SQ_DETECT_FIX_EN_OFFS)
+
+#define MVPP2_PORT_CTRL4_FC_EN_RX_OFFS 3
+#define MVPP2_PORT_CTRL4_FC_EN_RX_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL4_FC_EN_RX_OFFS)
+
+#define MVPP2_PORT_CTRL4_FC_EN_TX_OFFS 4
+#define MVPP2_PORT_CTRL4_FC_EN_TX_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL4_FC_EN_TX_OFFS)
+
+#define MVPP2_PORT_CTRL4_DP_CLK_SEL_OFFS 5
+#define MVPP2_PORT_CTRL4_DP_CLK_SEL_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL4_DP_CLK_SEL_OFFS)
+
+#define MVPP2_PORT_CTRL4_SYNC_BYPASS_OFFS 6
+#define MVPP2_PORT_CTRL4_SYNC_BYPASS_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL4_SYNC_BYPASS_OFFS)
+
+#define MVPP2_PORT_CTRL4_QSGMII_BYPASS_ACTIVE_OFFS 7
+#define MVPP2_PORT_CTRL4_QSGMII_BYPASS_ACTIVE_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL4_QSGMII_BYPASS_ACTIVE_OFFS)
+
+#define MVPP2_PORT_CTRL4_COUNT_EXTERNAL_FC_EN_OFFS 8
+#define MVPP2_PORT_CTRL4_COUNT_EXTERNAL_FC_EN_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL4_COUNT_EXTERNAL_FC_EN_OFFS)
+
+#define MVPP2_PORT_CTRL4_MARVELL_HEADER_EN_OFFS 9
+#define MVPP2_PORT_CTRL4_MARVELL_HEADER_EN_MASK \
+ (0x00000001 << MVPP2_PORT_CTRL4_MARVELL_HEADER_EN_OFFS)
+
+#define MVPP2_PORT_CTRL4_LEDS_NUMBER_OFFS 10
+#define MVPP2_PORT_CTRL4_LEDS_NUMBER_MASK \
+ (0x0000003f << MVPP2_PORT_CTRL4_LEDS_NUMBER_OFFS)
+
+/* Descriptor ring Macros */
+#define MVPP2_QUEUE_NEXT_DESC(q, index) (((index) < (q)->LastDesc) ? ((index) + 1) : 0)
+
+/* Various constants */
+
+/* Coalescing */
+#define MVPP2_TXDONE_COAL_PKTS_THRESH 15
+#define MVPP2_TXDONE_HRTIMER_PERIOD_NS 1000000UL
+#define MVPP2_RX_COAL_PKTS 32
+#define MVPP2_RX_COAL_USEC 100
+
+/*
+ * The two bytes Marvell header. Either contains a special value used
+ * by Marvell switches when a specific hardware mode is enabled (not
+ * supported by this driver) or is filled automatically by zeroes on
+ * the RX side. Those two bytes being at the front of the Ethernet
+ * header, they allow to have the IP header aligned on a 4 bytes
+ * boundary automatically: the hardware skips those two bytes on its
+ * own.
+ */
+#define MVPP2_MH_SIZE 2
+#define MVPP2_ETH_TYPE_LEN 2
+#define MVPP2_PPPOE_HDR_SIZE 8
+#define MVPP2_VLAN_TAG_LEN 4
+
+/* Lbtd 802.3 type */
+#define MVPP2_IP_LBDT_TYPE 0xfffa
+
+#define MVPP2_CPU_D_CACHE_LINE_SIZE 32
+#define MVPP2_TX_CSUM_MAX_SIZE 9800
+
+/* Timeout constants */
+#define MVPP2_TX_DISABLE_TIMEOUT_MSEC 1000
+#define MVPP2_TX_PENDING_TIMEOUT_MSEC 1000
+
+#define MVPP2_TX_MTU_MAX 0x7ffff
+
+/* Maximum number of T-CONTs of PON port */
+#define MVPP2_MAX_TCONT 16
+
+/* Maximum number of supported ports */
+#define MVPP2_MAX_PORTS 4
+
+/* Maximum number of TXQs used by single port */
+#define MVPP2_MAX_TXQ 8
+
+/* Maximum number of RXQs used by single port */
+#define MVPP2_MAX_RXQ 8
+
+/* Dfault number of RXQs in use */
+#define MVPP2_DEFAULT_RXQ 4
+
+/* Total number of RXQs available to all ports */
+#define MVPP2_RXQ_TOTAL_NUM (MVPP2_MAX_PORTS * MVPP2_MAX_RXQ)
+
+/* Max number of Rx descriptors */
+#define MVPP2_MAX_RXD 32
+
+/* Max number of Tx descriptors */
+#define MVPP2_MAX_TXD 32
+
+/* Amount of Tx descriptors that can be reserved at once by CPU */
+#define MVPP2_CPU_DESC_CHUNK 64
+
+/* Max number of Tx descriptors in each aggregated queue */
+#define MVPP2_AGGR_TXQ_SIZE 256
+
+/* Descriptor aligned size */
+#define MVPP2_DESC_ALIGNED_SIZE 32
+
+/* Descriptor alignment mask */
+#define MVPP2_TX_DESC_ALIGN (MVPP2_DESC_ALIGNED_SIZE - 1)
+
+/* RX FIFO constants */
+#define MVPP2_RX_FIFO_PORT_DATA_SIZE 0x2000
+#define MVPP2_RX_FIFO_PORT_ATTR_SIZE 0x80
+#define MVPP2_RX_FIFO_PORT_MIN_PKT 0x80
+
+#define MVPP2_BIT_TO_BYTE(bit) ((bit) / 8)
+
+/* IPv6 max L3 address size */
+#define MVPP2_MAX_L3_ADDR_SIZE 16
+
+/* Port flags */
+#define MVPP2_F_LOOPBACK BIT(0)
+
+/* SD1 Control1 */
+#define SD1_CONTROL_1_REG (0x148)
+
+#define SD1_CONTROL_XAUI_EN_OFFSET 28
+#define SD1_CONTROL_XAUI_EN_MASK (0x1 << SD1_CONTROL_XAUI_EN_OFFSET)
+
+#define SD1_CONTROL_RXAUI0_L23_EN_OFFSET 27
+#define SD1_CONTROL_RXAUI0_L23_EN_MASK (0x1 << SD1_CONTROL_RXAUI0_L23_EN_OFFSET)
+
+#define SD1_CONTROL_RXAUI1_L45_EN_OFFSET 26
+#define SD1_CONTROL_RXAUI1_L45_EN_MASK (0x1 << SD1_CONTROL_RXAUI1_L45_EN_OFFSET)
+
+/* System Soft Reset 1 */
+#define MV_GOP_SOFT_RESET_1_REG (0x108)
+
+#define NETC_GOP_SOFT_RESET_OFFSET 6
+#define NETC_GOP_SOFT_RESET_MASK (0x1 << NETC_GOP_SOFT_RESET_OFFSET)
+
+/* Ports Control 0 */
+#define MV_NETCOMP_PORTS_CONTROL_0 (0x110)
+
+#define NETC_CLK_DIV_PHASE_OFFSET 31
+#define NETC_CLK_DIV_PHASE_MASK (0x1 << NETC_CLK_DIV_PHASE_OFFSET)
+
+#define NETC_GIG_RX_DATA_SAMPLE_OFFSET 29
+#define NETC_GIG_RX_DATA_SAMPLE_MASK (0x1 << NETC_GIG_RX_DATA_SAMPLE_OFFSET)
+
+#define NETC_BUS_WIDTH_SELECT_OFFSET 1
+#define NETC_BUS_WIDTH_SELECT_MASK (0x1 << NETC_BUS_WIDTH_SELECT_OFFSET)
+
+#define NETC_GOP_ENABLE_OFFSET 0
+#define NETC_GOP_ENABLE_MASK (0x1 << NETC_GOP_ENABLE_OFFSET)
+
+/* Ports Control 1 */
+#define MV_NETCOMP_PORTS_CONTROL_1 (0x114)
+
+#define NETC_PORT_GIG_RF_RESET_OFFSET(port) (28 + port)
+#define NETC_PORT_GIG_RF_RESET_MASK(port) (0x1 << NETC_PORT_GIG_RF_RESET_OFFSET(port))
+
+#define NETC_PORTS_ACTIVE_OFFSET(port) (0 + port)
+#define NETC_PORTS_ACTIVE_MASK(port) (0x1 << NETC_PORTS_ACTIVE_OFFSET(port))
+
+/* Ports Status */
+#define MV_NETCOMP_PORTS_STATUS (0x11C)
+#define NETC_PORTS_STATUS_OFFSET(port) (0 + port)
+#define NETC_PORTS_STATUS_MASK(port) (0x1 << NETC_PORTS_STATUS_OFFSET(port))
+
+/* Networking Complex Control 0 */
+#define MV_NETCOMP_CONTROL_0 (0x120)
+
+#define NETC_GBE_PORT1_MII_MODE_OFFSET 2
+#define NETC_GBE_PORT1_MII_MODE_MASK (0x1 << NETC_GBE_PORT1_MII_MODE_OFFSET)
+
+#define NETC_GBE_PORT1_SGMII_MODE_OFFSET 1
+#define NETC_GBE_PORT1_SGMII_MODE_MASK (0x1 << NETC_GBE_PORT1_SGMII_MODE_OFFSET)
+
+#define NETC_GBE_PORT0_SGMII_MODE_OFFSET 0
+#define NETC_GBE_PORT0_SGMII_MODE_MASK (0x1 << NETC_GBE_PORT0_SGMII_MODE_OFFSET)
+
+/* Port Mac Control0 */
+#define MV_XLG_PORT_MAC_CTRL0_REG ( 0x0000)
+#define MV_XLG_MAC_CTRL0_PORTEN_OFFS 0
+#define MV_XLG_MAC_CTRL0_PORTEN_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL0_PORTEN_OFFS)
+
+#define MV_XLG_MAC_CTRL0_MACRESETN_OFFS 1
+#define MV_XLG_MAC_CTRL0_MACRESETN_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL0_MACRESETN_OFFS)
+
+#define MV_XLG_MAC_CTRL0_FORCELINKDOWN_OFFS 2
+#define MV_XLG_MAC_CTRL0_FORCELINKDOWN_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL0_FORCELINKDOWN_OFFS)
+
+#define MV_XLG_MAC_CTRL0_FORCELINKPASS_OFFS 3
+#define MV_XLG_MAC_CTRL0_FORCELINKPASS_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL0_FORCELINKPASS_OFFS)
+
+#define MV_XLG_MAC_CTRL0_TXIPGMODE_OFFS 5
+#define MV_XLG_MAC_CTRL0_TXIPGMODE_MASK \
+ (0x00000003 << MV_XLG_MAC_CTRL0_TXIPGMODE_OFFS)
+
+#define MV_XLG_MAC_CTRL0_RXFCEN_OFFS 7
+#define MV_XLG_MAC_CTRL0_RXFCEN_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL0_RXFCEN_OFFS)
+
+#define MV_XLG_MAC_CTRL0_TXFCEN_OFFS 8
+#define MV_XLG_MAC_CTRL0_TXFCEN_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL0_TXFCEN_OFFS)
+
+#define MV_XLG_MAC_CTRL0_RXCRCCHECKEN_OFFS 9
+#define MV_XLG_MAC_CTRL0_RXCRCCHECKEN_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL0_RXCRCCHECKEN_OFFS)
+
+#define MV_XLG_MAC_CTRL0_PERIODICXONEN_OFFS 10
+#define MV_XLG_MAC_CTRL0_PERIODICXONEN_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL0_PERIODICXONEN_OFFS)
+
+#define MV_XLG_MAC_CTRL0_RXCRCSTRIPEN_OFFS 11
+#define MV_XLG_MAC_CTRL0_RXCRCSTRIPEN_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL0_RXCRCSTRIPEN_OFFS)
+
+#define MV_XLG_MAC_CTRL0_PADDINGDIS_OFFS 13
+#define MV_XLG_MAC_CTRL0_PADDINGDIS_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL0_PADDINGDIS_OFFS)
+
+#define MV_XLG_MAC_CTRL0_MIBCNTDIS_OFFS 14
+#define MV_XLG_MAC_CTRL0_MIBCNTDIS_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL0_MIBCNTDIS_OFFS)
+
+#define MV_XLG_MAC_CTRL0_PFC_CASCADE_PORT_ENABLE_OFFS 15
+#define MV_XLG_MAC_CTRL0_PFC_CASCADE_PORT_ENABLE_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL0_PFC_CASCADE_PORT_ENABLE_OFFS)
+
+/* Port Mac Control1 */
+#define MV_XLG_PORT_MAC_CTRL1_REG (0x0004)
+#define MV_XLG_MAC_CTRL1_FRAMESIZELIMIT_OFFS 0
+#define MV_XLG_MAC_CTRL1_FRAMESIZELIMIT_MASK \
+ (0x00001fff << MV_XLG_MAC_CTRL1_FRAMESIZELIMIT_OFFS)
+
+#define MV_XLG_MAC_CTRL1_MACLOOPBACKEN_OFFS 13
+#define MV_XLG_MAC_CTRL1_MACLOOPBACKEN_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL1_MACLOOPBACKEN_OFFS)
+
+#define MV_XLG_MAC_CTRL1_XGMIILOOPBACKEN_OFFS 14
+#define MV_XLG_MAC_CTRL1_XGMIILOOPBACKEN_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL1_XGMIILOOPBACKEN_OFFS)
+
+#define MV_XLG_MAC_CTRL1_LOOPBACKCLOCKSELECT_OFFS 15
+#define MV_XLG_MAC_CTRL1_LOOPBACKCLOCKSELECT_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL1_LOOPBACKCLOCKSELECT_OFFS)
+
+/* Port Mac Control2 */
+#define MV_XLG_PORT_MAC_CTRL2_REG (0x0008)
+#define MV_XLG_MAC_CTRL2_SALOW_7_0_OFFS 0
+#define MV_XLG_MAC_CTRL2_SALOW_7_0_MASK \
+ (0x000000ff << MV_XLG_MAC_CTRL2_SALOW_7_0_OFFS)
+
+#define MV_XLG_MAC_CTRL2_UNIDIRECTIONALEN_OFFS 8
+#define MV_XLG_MAC_CTRL2_UNIDIRECTIONALEN_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL2_UNIDIRECTIONALEN_OFFS)
+
+#define MV_XLG_MAC_CTRL2_FIXEDIPGBASE_OFFS 9
+#define MV_XLG_MAC_CTRL2_FIXEDIPGBASE_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL2_FIXEDIPGBASE_OFFS)
+
+#define MV_XLG_MAC_CTRL2_PERIODICXOFFEN_OFFS 10
+#define MV_XLG_MAC_CTRL2_PERIODICXOFFEN_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL2_PERIODICXOFFEN_OFFS)
+
+#define MV_XLG_MAC_CTRL2_SIMPLEXMODEEN_OFFS 13
+#define MV_XLG_MAC_CTRL2_SIMPLEXMODEEN_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL2_SIMPLEXMODEEN_OFFS)
+
+#define MV_XLG_MAC_CTRL2_FC_MODE_OFFS 14
+#define MV_XLG_MAC_CTRL2_FC_MODE_MASK \
+ (0x00000003 << MV_XLG_MAC_CTRL2_FC_MODE_OFFS)
+
+/* Port Status */
+#define MV_XLG_MAC_PORT_STATUS_REG (0x000c)
+#define MV_XLG_MAC_PORT_STATUS_LINKSTATUS_OFFS 0
+#define MV_XLG_MAC_PORT_STATUS_LINKSTATUS_MASK \
+ (0x00000001 << MV_XLG_MAC_PORT_STATUS_LINKSTATUS_OFFS)
+
+#define MV_XLG_MAC_PORT_STATUS_REMOTEFAULT_OFFS 1
+#define MV_XLG_MAC_PORT_STATUS_REMOTEFAULT_MASK \
+ (0x00000001 << MV_XLG_MAC_PORT_STATUS_REMOTEFAULT_OFFS)
+
+#define MV_XLG_MAC_PORT_STATUS_LOCALFAULT_OFFS 2
+#define MV_XLG_MAC_PORT_STATUS_LOCALFAULT_MASK \
+ (0x00000001 << MV_XLG_MAC_PORT_STATUS_LOCALFAULT_OFFS)
+
+#define MV_XLG_MAC_PORT_STATUS_LINKSTATUSCLEAN_OFFS 3
+#define MV_XLG_MAC_PORT_STATUS_LINKSTATUSCLEAN_MASK \
+ (0x00000001 << MV_XLG_MAC_PORT_STATUS_LINKSTATUSCLEAN_OFFS)
+
+#define MV_XLG_MAC_PORT_STATUS_LOCALFAULTCLEAN_OFFS 4
+#define MV_XLG_MAC_PORT_STATUS_LOCALFAULTCLEAN_MASK \
+ (0x00000001 << MV_XLG_MAC_PORT_STATUS_LOCALFAULTCLEAN_OFFS)
+
+#define MV_XLG_MAC_PORT_STATUS_REMOTEFAULTCLEAN_OFFS 5
+#define MV_XLG_MAC_PORT_STATUS_REMOTEFAULTCLEAN_MASK \
+ (0x00000001 << MV_XLG_MAC_PORT_STATUS_REMOTEFAULTCLEAN_OFFS)
+
+#define MV_XLG_MAC_PORT_STATUS_PORTRXPAUSE_OFFS 6
+#define MV_XLG_MAC_PORT_STATUS_PORTRXPAUSE_MASK \
+ (0x00000001 << MV_XLG_MAC_PORT_STATUS_PORTRXPAUSE_OFFS)
+
+#define MV_XLG_MAC_PORT_STATUS_PORTTXPAUSE_OFFS 7
+#define MV_XLG_MAC_PORT_STATUS_PORTTXPAUSE_MASK \
+ (0x00000001 << MV_XLG_MAC_PORT_STATUS_PORTTXPAUSE_OFFS)
+
+#define MV_XLG_MAC_PORT_STATUS_PFC_SYNC_FIFO_FULL_OFFS 8
+#define MV_XLG_MAC_PORT_STATUS_PFC_SYNC_FIFO_FULL_MASK \
+ (0x00000001 << MV_XLG_MAC_PORT_STATUS_PFC_SYNC_FIFO_FULL_OFFS)
+
+/* Port Fifos Thresholds Configuration */
+#define MV_XLG_PORT_FIFOS_THRS_CFG_REG (0x001)
+#define MV_XLG_MAC_PORT_FIFOS_THRS_CFG_RXFULLTHR_OFFS 0
+#define MV_XLG_MAC_PORT_FIFOS_THRS_CFG_RXFULLTHR_MASK \
+ (0x0000001f << MV_XLG_MAC_PORT_FIFOS_THRS_CFG_RXFULLTHR_OFFS)
+
+#define MV_XLG_MAC_PORT_FIFOS_THRS_CFG_TXFIFOSIZE_OFFS 5
+#define MV_XLG_MAC_PORT_FIFOS_THRS_CFG_TXFIFOSIZE_MASK \
+ (0x0000003f << MV_XLG_MAC_PORT_FIFOS_THRS_CFG_TXFIFOSIZE_OFFS)
+
+#define MV_XLG_MAC_PORT_FIFOS_THRS_CFG_TXRDTHR_OFFS 11
+#define MV_XLG_MAC_PORT_FIFOS_THRS_CFG_TXRDTHR_MASK \
+ (0x0000001f << MV_XLG_MAC_PORT_FIFOS_THRS_CFG_TXRDTHR_OFFS)
+
+/* Port Mac Control3 */
+#define MV_XLG_PORT_MAC_CTRL3_REG (0x001c)
+#define MV_XLG_MAC_CTRL3_BUFSIZE_OFFS 0
+#define MV_XLG_MAC_CTRL3_BUFSIZE_MASK \
+ (0x0000003f << MV_XLG_MAC_CTRL3_BUFSIZE_OFFS)
+
+#define MV_XLG_MAC_CTRL3_XTRAIPG_OFFS 6
+#define MV_XLG_MAC_CTRL3_XTRAIPG_MASK \
+ (0x0000007f << MV_XLG_MAC_CTRL3_XTRAIPG_OFFS)
+
+#define MV_XLG_MAC_CTRL3_MACMODESELECT_OFFS 13
+#define MV_XLG_MAC_CTRL3_MACMODESELECT_MASK \
+ (0x00000007 << MV_XLG_MAC_CTRL3_MACMODESELECT_OFFS)
+
+/* Port Per Prio Flow Control Status */
+#define MV_XLG_PORT_PER_PRIO_FLOW_CTRL_STATUS_REG (0x0020)
+#define MV_XLG_MAC_PORT_PER_PRIO_FLOW_CTRL_STATUS_PRIONSTATUS_OFFS 0
+#define MV_XLG_MAC_PORT_PER_PRIO_FLOW_CTRL_STATUS_PRIONSTATUS_MASK \
+ (0x00000001 << MV_XLG_MAC_PORT_PER_PRIO_FLOW_CTRL_STATUS_PRIONSTATUS_OFFS)
+
+/* Debug Bus Status */
+#define MV_XLG_DEBUG_BUS_STATUS_REG (0x0024)
+#define MV_XLG_MAC_DEBUG_BUS_STATUS_DEBUG_BUS_OFFS 0
+#define MV_XLG_MAC_DEBUG_BUS_STATUS_DEBUG_BUS_MASK \
+ (0x0000ffff << MV_XLG_MAC_DEBUG_BUS_STATUS_DEBUG_BUS_OFFS)
+
+/* Port Metal Fix */
+#define MV_XLG_PORT_METAL_FIX_REG (0x002c)
+#define MV_XLG_MAC_PORT_METAL_FIX_EN_EOP_IN_FIFO__OFFS 0
+#define MV_XLG_MAC_PORT_METAL_FIX_EN_EOP_IN_FIFO__MASK \
+ (0x00000001 << MV_XLG_MAC_PORT_METAL_FIX_EN_EOP_IN_FIFO__OFFS)
+
+#define MV_XLG_MAC_PORT_METAL_FIX_EN_LTF_FIX__OFFS 1
+#define MV_XLG_MAC_PORT_METAL_FIX_EN_LTF_FIX__MASK \
+ (0x00000001 << MV_XLG_MAC_PORT_METAL_FIX_EN_LTF_FIX__OFFS)
+
+#define MV_XLG_MAC_PORT_METAL_FIX_EN_HOLD_FIX__OFFS 2
+#define MV_XLG_MAC_PORT_METAL_FIX_EN_HOLD_FIX__MASK \
+ (0x00000001 << MV_XLG_MAC_PORT_METAL_FIX_EN_HOLD_FIX__OFFS)
+
+#define MV_XLG_MAC_PORT_METAL_FIX_EN_LED_FIX__OFFS 3
+#define MV_XLG_MAC_PORT_METAL_FIX_EN_LED_FIX__MASK \
+ (0x00000001 << MV_XLG_MAC_PORT_METAL_FIX_EN_LED_FIX__OFFS)
+
+#define MV_XLG_MAC_PORT_METAL_FIX_EN_PAD_PROTECT__OFFS 4
+#define MV_XLG_MAC_PORT_METAL_FIX_EN_PAD_PROTECT__MASK \
+ (0x00000001 << MV_XLG_MAC_PORT_METAL_FIX_EN_PAD_PROTECT__OFFS)
+
+#define MV_XLG_MAC_PORT_METAL_FIX_EN_NX_BTS44__OFFS 5
+#define MV_XLG_MAC_PORT_METAL_FIX_EN_NX_BTS44__MASK \
+ (0x00000001 << MV_XLG_MAC_PORT_METAL_FIX_EN_NX_BTS44__OFFS)
+
+#define MV_XLG_MAC_PORT_METAL_FIX_EN_NX_BTS42__OFFS 6
+#define MV_XLG_MAC_PORT_METAL_FIX_EN_NX_BTS42__MASK \
+ (0x00000001 << MV_XLG_MAC_PORT_METAL_FIX_EN_NX_BTS42__OFFS)
+
+#define MV_XLG_MAC_PORT_METAL_FIX_EN_FLUSH_FIX_OFFS 7
+#define MV_XLG_MAC_PORT_METAL_FIX_EN_FLUSH_FIX_MASK \
+ (0x00000001 << MV_XLG_MAC_PORT_METAL_FIX_EN_FLUSH_FIX_OFFS)
+
+#define MV_XLG_MAC_PORT_METAL_FIX_EN_PORT_EN_FIX_OFFS 8
+#define MV_XLG_MAC_PORT_METAL_FIX_EN_PORT_EN_FIX_MASK \
+ (0x00000001 << MV_XLG_MAC_PORT_METAL_FIX_EN_PORT_EN_FIX_OFFS)
+
+#define MV_XLG_MAC_PORT_METAL_FIX_SPARE_DEF0_BITS_OFFS 9
+#define MV_XLG_MAC_PORT_METAL_FIX_SPARE_DEF0_BITS_MASK \
+ (0x0000000f << MV_XLG_MAC_PORT_METAL_FIX_SPARE_DEF0_BITS_OFFS)
+
+#define MV_XLG_MAC_PORT_METAL_FIX_SPARE_DEF1_BITS_OFFS 13
+#define MV_XLG_MAC_PORT_METAL_FIX_SPARE_DEF1_BITS_MASK \
+ (0x00000007 << MV_XLG_MAC_PORT_METAL_FIX_SPARE_DEF1_BITS_OFFS)
+
+/* Xg Mib Counters Control */
+#define MV_XLG_MIB_CNTRS_CTRL_REG (0x0030)
+#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_XGCAPTURETRIGGER_OFFS 0
+#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_XGCAPTURETRIGGER_MASK \
+ (0x00000001 << MV_XLG_MAC_XG_MIB_CNTRS_CTRL_XGCAPTURETRIGGER_OFFS)
+
+#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_XGDONTCLEARAFTERREAD_OFFS 1
+#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_XGDONTCLEARAFTERREAD_MASK \
+ (0x00000001 << MV_XLG_MAC_XG_MIB_CNTRS_CTRL_XGDONTCLEARAFTERREAD_OFFS)
+
+#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_XGRXHISTOGRAMEN_OFFS 2
+#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_XGRXHISTOGRAMEN_MASK \
+ (0x00000001 << MV_XLG_MAC_XG_MIB_CNTRS_CTRL_XGRXHISTOGRAMEN_OFFS)
+
+#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_XGTXHISTOGRAMEN_OFFS 3
+#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_XGTXHISTOGRAMEN_MASK \
+ (0x00000001 << MV_XLG_MAC_XG_MIB_CNTRS_CTRL_XGTXHISTOGRAMEN_OFFS)
+
+#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_MFA1_BTT940_FIX_ENABLE__OFFS 4
+#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_MFA1_BTT940_FIX_ENABLE__MASK \
+ (0x00000001 << MV_XLG_MAC_XG_MIB_CNTRS_CTRL_MFA1_BTT940_FIX_ENABLE__OFFS)
+
+#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_LEDS_NUMBER_OFFS 5
+#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_LEDS_NUMBER_MASK \
+ (0x0000003f << MV_XLG_MAC_XG_MIB_CNTRS_CTRL_LEDS_NUMBER_OFFS)
+
+#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_MIB_4_COUNT_HIST_OFFS 11
+#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_MIB_4_COUNT_HIST_MASK \
+ (0x00000001 << MV_XLG_MAC_XG_MIB_CNTRS_CTRL_MIB_4_COUNT_HIST_OFFS)
+
+#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_MIB_4_LIMIT_1518_1522_OFFS 12
+#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_MIB_4_LIMIT_1518_1522_MASK \
+ (0x00000001 << MV_XLG_MAC_XG_MIB_CNTRS_CTRL_MIB_4_LIMIT_1518_1522_OFFS)
+
+/* Cn/ccfc Timer%i */
+#define MV_XLG_CNCCFC_TIMERI_REG(t) ((0x0038 + (t) * 4))
+#define MV_XLG_MAC_CNCCFC_TIMERI_PORTSPEEDTIMER_OFFS 0
+#define MV_XLG_MAC_CNCCFC_TIMERI_PORTSPEEDTIMER_MASK \
+ (0x0000ffff << MV_XLG_MAC_CNCCFC_TIMERI_PORTSPEEDTIMER_OFFS)
+
+/* Ppfc Control */
+#define MV_XLG_MAC_PPFC_CTRL_REG (0x0060)
+#define MV_XLG_MAC_PPFC_CTRL_GLOBAL_PAUSE_ENI_OFFS 0
+#define MV_XLG_MAC_PPFC_CTRL_GLOBAL_PAUSE_ENI_MASK \
+ (0x00000001 << MV_XLG_MAC_PPFC_CTRL_GLOBAL_PAUSE_ENI_OFFS)
+
+#define MV_XLG_MAC_PPFC_CTRL_DIP_BTS_677_EN_OFFS 9
+#define MV_XLG_MAC_PPFC_CTRL_DIP_BTS_677_EN_MASK \
+ (0x00000001 << MV_XLG_MAC_PPFC_CTRL_DIP_BTS_677_EN_OFFS)
+
+/* Fc Dsa Tag 0 */
+#define MV_XLG_MAC_FC_DSA_TAG_0_REG (0x0068)
+#define MV_XLG_MAC_FC_DSA_TAG_0_DSATAGREG0_OFFS 0
+#define MV_XLG_MAC_FC_DSA_TAG_0_DSATAGREG0_MASK \
+ (0x0000ffff << MV_XLG_MAC_FC_DSA_TAG_0_DSATAGREG0_OFFS)
+
+/* Fc Dsa Tag 1 */
+#define MV_XLG_MAC_FC_DSA_TAG_1_REG (0x006c)
+#define MV_XLG_MAC_FC_DSA_TAG_1_DSATAGREG1_OFFS 0
+#define MV_XLG_MAC_FC_DSA_TAG_1_DSATAGREG1_MASK \
+ (0x0000ffff << MV_XLG_MAC_FC_DSA_TAG_1_DSATAGREG1_OFFS)
+
+/* Fc Dsa Tag 2 */
+#define MV_XLG_MAC_FC_DSA_TAG_2_REG (0x0070)
+#define MV_XLG_MAC_FC_DSA_TAG_2_DSATAGREG2_OFFS 0
+#define MV_XLG_MAC_FC_DSA_TAG_2_DSATAGREG2_MASK \
+ (0x0000ffff << MV_XLG_MAC_FC_DSA_TAG_2_DSATAGREG2_OFFS)
+
+/* Fc Dsa Tag 3 */
+#define MV_XLG_MAC_FC_DSA_TAG_3_REG (0x0074)
+#define MV_XLG_MAC_FC_DSA_TAG_3_DSATAGREG3_OFFS 0
+#define MV_XLG_MAC_FC_DSA_TAG_3_DSATAGREG3_MASK \
+ (0x0000ffff << MV_XLG_MAC_FC_DSA_TAG_3_DSATAGREG3_OFFS)
+
+/* Dic Budget Compensation */
+#define MV_XLG_MAC_DIC_BUDGET_COMPENSATION_REG (0x0080)
+#define MV_XLG_MAC_DIC_BUDGET_COMPENSATION_DIC_COUNTER_TO_ADD_8BYTES_OFFS 0
+#define MV_XLG_MAC_DIC_BUDGET_COMPENSATION_DIC_COUNTER_TO_ADD_8BYTES_MASK \
+ (0x0000ffff << MV_XLG_MAC_DIC_BUDGET_COMPENSATION_DIC_COUNTER_TO_ADD_8BYTES_OFFS)
+
+/* Port Mac Control4 */
+#define MV_XLG_PORT_MAC_CTRL4_REG (0x0084)
+#define MV_XLG_MAC_CTRL4_LLFC_GLOBAL_FC_ENABLE_OFFS 0
+#define MV_XLG_MAC_CTRL4_LLFC_GLOBAL_FC_ENABLE_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL4_LLFC_GLOBAL_FC_ENABLE_OFFS)
+
+#define MV_XLG_MAC_CTRL4_LED_STREAM_SELECT_OFFS 1
+#define MV_XLG_MAC_CTRL4_LED_STREAM_SELECT_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL4_LED_STREAM_SELECT_OFFS)
+
+#define MV_XLG_MAC_CTRL4_DEBUG_BUS_SELECT_OFFS 2
+#define MV_XLG_MAC_CTRL4_DEBUG_BUS_SELECT_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL4_DEBUG_BUS_SELECT_OFFS)
+
+#define MV_XLG_MAC_CTRL4_MASK_PCS_RESET_OFFS 3
+#define MV_XLG_MAC_CTRL4_MASK_PCS_RESET_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL4_MASK_PCS_RESET_OFFS)
+
+#define MV_XLG_MAC_CTRL4_ENABLE_SHORT_PREAMBLE_FOR_XLG_OFFS 4
+#define MV_XLG_MAC_CTRL4_ENABLE_SHORT_PREAMBLE_FOR_XLG_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL4_ENABLE_SHORT_PREAMBLE_FOR_XLG_OFFS)
+
+#define MV_XLG_MAC_CTRL4_FORWARD_802_3X_FC_EN_OFFS 5
+#define MV_XLG_MAC_CTRL4_FORWARD_802_3X_FC_EN_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL4_FORWARD_802_3X_FC_EN_OFFS)
+
+#define MV_XLG_MAC_CTRL4_FORWARD_PFC_EN_OFFS 6
+#define MV_XLG_MAC_CTRL4_FORWARD_PFC_EN_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL4_FORWARD_PFC_EN_OFFS)
+
+#define MV_XLG_MAC_CTRL4_FORWARD_UNKNOWN_FC_EN_OFFS 7
+#define MV_XLG_MAC_CTRL4_FORWARD_UNKNOWN_FC_EN_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL4_FORWARD_UNKNOWN_FC_EN_OFFS)
+
+#define MV_XLG_MAC_CTRL4_USE_XPCS_OFFS 8
+#define MV_XLG_MAC_CTRL4_USE_XPCS_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL4_USE_XPCS_OFFS)
+
+#define MV_XLG_MAC_CTRL4_DMA_INTERFACE_IS_64_BIT_OFFS 9
+#define MV_XLG_MAC_CTRL4_DMA_INTERFACE_IS_64_BIT_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL4_DMA_INTERFACE_IS_64_BIT_OFFS)
+
+#define MV_XLG_MAC_CTRL4_TX_DMA_INTERFACE_BITS_OFFS 10
+#define MV_XLG_MAC_CTRL4_TX_DMA_INTERFACE_BITS_MASK \
+ (0x00000003 << MV_XLG_MAC_CTRL4_TX_DMA_INTERFACE_BITS_OFFS)
+
+#define MV_XLG_MAC_CTRL4_MAC_MODE_DMA_1G_OFFS 12
+#define MV_XLG_MAC_CTRL4_MAC_MODE_DMA_1G_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL4_MAC_MODE_DMA_1G_OFFS)
+
+/* Port Mac Control5 */
+#define MV_XLG_PORT_MAC_CTRL5_REG (0x0088)
+#define MV_XLG_MAC_CTRL5_TXIPGLENGTH_OFFS 0
+#define MV_XLG_MAC_CTRL5_TXIPGLENGTH_MASK \
+ (0x0000000f << MV_XLG_MAC_CTRL5_TXIPGLENGTH_OFFS)
+
+#define MV_XLG_MAC_CTRL5_PREAMBLELENGTHTX_OFFS 4
+#define MV_XLG_MAC_CTRL5_PREAMBLELENGTHTX_MASK \
+ (0x00000007 << MV_XLG_MAC_CTRL5_PREAMBLELENGTHTX_OFFS)
+
+#define MV_XLG_MAC_CTRL5_PREAMBLELENGTHRX_OFFS 7
+#define MV_XLG_MAC_CTRL5_PREAMBLELENGTHRX_MASK \
+ (0x00000007 << MV_XLG_MAC_CTRL5_PREAMBLELENGTHRX_OFFS)
+
+#define MV_XLG_MAC_CTRL5_TXNUMCRCBYTES_OFFS 10
+#define MV_XLG_MAC_CTRL5_TXNUMCRCBYTES_MASK \
+ (0x00000007 << MV_XLG_MAC_CTRL5_TXNUMCRCBYTES_OFFS)
+
+#define MV_XLG_MAC_CTRL5_RXNUMCRCBYTES_OFFS 13
+#define MV_XLG_MAC_CTRL5_RXNUMCRCBYTES_MASK \
+ (0x00000007 << MV_XLG_MAC_CTRL5_RXNUMCRCBYTES_OFFS)
+
+/* External Control */
+#define MV_XLG_MAC_EXT_CTRL_REG (0x0090)
+#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL0_OFFS 0
+#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL0_MASK \
+ (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL0_OFFS)
+
+#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL1_OFFS 1
+#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL1_MASK \
+ (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL1_OFFS)
+
+#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL2_OFFS 2
+#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL2_MASK \
+ (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL2_OFFS)
+
+#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL3_OFFS 3
+#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL3_MASK \
+ (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL3_OFFS)
+
+#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL4_OFFS 4
+#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL4_MASK \
+ (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL4_OFFS)
+
+#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL5_OFFS 5
+#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL5_MASK \
+ (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL5_OFFS)
+
+#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL6_OFFS 6
+#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL6_MASK \
+ (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL6_OFFS)
+
+#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL7_OFFS 7
+#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL7_MASK \
+ (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL7_OFFS)
+
+#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL8_OFFS 8
+#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL8_MASK \
+ (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL8_OFFS)
+
+#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL9_OFFS 9
+#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL9_MASK \
+ (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL9_OFFS)
+
+#define MV_XLG_MAC_EXT_CTRL_EXT_CTRL_10_OFFS 10
+#define MV_XLG_MAC_EXT_CTRL_EXT_CTRL_10_MASK \
+ (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXT_CTRL_10_OFFS)
+
+#define MV_XLG_MAC_EXT_CTRL_EXT_CTRL_11_OFFS 11
+#define MV_XLG_MAC_EXT_CTRL_EXT_CTRL_11_MASK \
+ (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXT_CTRL_11_OFFS)
+
+#define MV_XLG_MAC_EXT_CTRL_EXT_CTRL_12_OFFS 12
+#define MV_XLG_MAC_EXT_CTRL_EXT_CTRL_12_MASK \
+ (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXT_CTRL_12_OFFS)
+
+#define MV_XLG_MAC_EXT_CTRL_EXT_CTRL_13_OFFS 13
+#define MV_XLG_MAC_EXT_CTRL_EXT_CTRL_13_MASK \
+ (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXT_CTRL_13_OFFS)
+
+#define MV_XLG_MAC_EXT_CTRL_EXT_CTRL_14_OFFS 14
+#define MV_XLG_MAC_EXT_CTRL_EXT_CTRL_14_MASK \
+ (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXT_CTRL_14_OFFS)
+
+#define MV_XLG_MAC_EXT_CTRL_EXT_CTRL_15_OFFS 15
+#define MV_XLG_MAC_EXT_CTRL_EXT_CTRL_15_MASK \
+ (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXT_CTRL_15_OFFS)
+
+/* Macro Control */
+#define MV_XLG_MAC_MACRO_CTRL_REG (0x0094)
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_0_OFFS 0
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_0_MASK \
+ (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_0_OFFS)
+
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_1_OFFS 1
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_1_MASK \
+ (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_1_OFFS)
+
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_2_OFFS 2
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_2_MASK \
+ (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_2_OFFS)
+
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_3_OFFS 3
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_3_MASK \
+ (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_3_OFFS)
+
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_4_OFFS 4
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_4_MASK \
+ (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_4_OFFS)
+
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_5_OFFS 5
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_5_MASK \
+ (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_5_OFFS)
+
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_6_OFFS 6
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_6_MASK \
+ (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_6_OFFS)
+
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_7_OFFS 7
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_7_MASK \
+ (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_7_OFFS)
+
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_8_OFFS 8
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_8_MASK \
+ (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_8_OFFS)
+
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_9_OFFS 9
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_9_MASK \
+ (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_9_OFFS)
+
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_10_OFFS 10
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_10_MASK \
+ (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_10_OFFS)
+
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_11_OFFS 11
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_11_MASK \
+ (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_11_OFFS)
+
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_12_OFFS 12
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_12_MASK \
+ (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_12_OFFS)
+
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_13_OFFS 13
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_13_MASK \
+ (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_13_OFFS)
+
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_14_OFFS 14
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_14_MASK \
+ (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_14_OFFS)
+
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_15_OFFS 15
+#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_15_MASK \
+ (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_15_OFFS)
+
+#define MV_XLG_MAC_DIC_PPM_IPG_REDUCE_REG (0x0094)
+
+/* Port Interrupt Cause */
+#define MV_XLG_INTERRUPT_CAUSE_REG (0x0014)
+/* Port Interrupt Mask */
+#define MV_XLG_INTERRUPT_MASK_REG (0x0018)
+#define MV_XLG_INTERRUPT_LINK_CHANGE_OFFS 1
+#define MV_XLG_INTERRUPT_LINK_CHANGE_MASK \
+ (0x1 << MV_XLG_INTERRUPT_LINK_CHANGE_OFFS)
+
+/* Port Interrupt Summary Cause */
+#define MV_XLG_EXTERNAL_INTERRUPT_CAUSE_REG (0x0058)
+/* Port Interrupt Summary Mask */
+#define MV_XLG_EXTERNAL_INTERRUPT_MASK_REG (0x005C)
+#define MV_XLG_EXTERNAL_INTERRUPT_LINK_CHANGE_OFFS 1
+#define MV_XLG_EXTERNAL_INTERRUPT_LINK_CHANGE_MASK \
+ (0x1 << MV_XLG_EXTERNAL_INTERRUPT_LINK_CHANGE_OFFS)
+
+/*All PPV22 Addresses are 40-bit */
+#define MVPP22_ADDR_HIGH_SIZE 8
+#define MVPP22_ADDR_HIGH_MASK ((1<<MVPP22_ADDR_HIGH_SIZE) - 1)
+#define MVPP22_ADDR_MASK (0xFFFFFFFFFF)
+
+/* Desc addr shift */
+#define MVPP21_DESC_ADDR_SHIFT 0 /*Applies to RXQ, AGGR_TXQ*/
+#define MVPP22_DESC_ADDR_SHIFT 8 /*Applies to RXQ, AGGR_TXQ*/
+
+/* AXI Bridge Registers */
+#define MVPP22_AXI_BM_WR_ATTR_REG 0x4100
+#define MVPP22_AXI_BM_RD_ATTR_REG 0x4104
+#define MVPP22_AXI_AGGRQ_DESCR_RD_ATTR_REG 0x4110
+#define MVPP22_AXI_TXQ_DESCR_WR_ATTR_REG 0x4114
+#define MVPP22_AXI_TXQ_DESCR_RD_ATTR_REG 0x4118
+#define MVPP22_AXI_RXQ_DESCR_WR_ATTR_REG 0x411c
+#define MVPP22_AXI_RX_DATA_WR_ATTR_REG 0x4120
+#define MVPP22_AXI_TX_DATA_RD_ATTR_REG 0x4130
+#define MVPP22_AXI_RD_NORMAL_CODE_REG 0x4150
+#define MVPP22_AXI_RD_SNP_CODE_REG 0x4154
+#define MVPP22_AXI_WR_NORMAL_CODE_REG 0x4160
+#define MVPP22_AXI_WR_SNP_CODE_REG 0x4164
+
+#define MVPP22_AXI_RD_CODE_MASK 0x33
+#define MVPP22_AXI_WR_CODE_MASK 0x33
+
+#define MVPP22_AXI_ATTR_CACHE_OFFS 0
+#define MVPP22_AXI_ATTR_CACHE_SIZE 4
+#define MVPP22_AXI_ATTR_CACHE_MASK 0x0000000F
+
+#define MVPP22_AXI_ATTR_QOS_OFFS 4
+#define MVPP22_AXI_ATTR_QOS_SIZE 4
+#define MVPP22_AXI_ATTR_QOS_MASK 0x000000F0
+
+#define MVPP22_AXI_ATTR_TC_OFFS 8
+#define MVPP22_AXI_ATTR_TC_SIZE 4
+#define MVPP22_AXI_ATTR_TC_MASK 0x00000F00
+
+#define MVPP22_AXI_ATTR_DOMAIN_OFFS 12
+#define MVPP22_AXI_ATTR_DOMAIN_SIZE 2
+#define MVPP22_AXI_ATTR_DOMAIN_MASK 0x00003000
+
+#define MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT BIT(16)
+
+/* PHY address register */
+#define MV_SMI_PHY_ADDRESS_REG(n) (0xC + 0x4 * (n))
+#define MV_SMI_PHY_ADDRESS_PHYAD_OFFS 0
+#define MV_SMI_PHY_ADDRESS_PHYAD_MASK \
+ (0x1F << MV_SMI_PHY_ADDRESS_PHYAD_OFFS)
+
+/* Marvell tag types */
+enum Mvpp2TagType {
+ MVPP2_TAG_TYPE_NONE = 0,
+ MVPP2_TAG_TYPE_MH = 1,
+ MVPP2_TAG_TYPE_DSA = 2,
+ MVPP2_TAG_TYPE_EDSA = 3,
+ MVPP2_TAG_TYPE_VLAN = 4,
+ MVPP2_TAG_TYPE_LAST = 5
+};
+
+/* Parser constants */
+#define MVPP2_PRS_TCAM_SRAM_SIZE 256
+#define MVPP2_PRS_TCAM_WORDS 6
+#define MVPP2_PRS_SRAM_WORDS 4
+#define MVPP2_PRS_FLOW_ID_SIZE 64
+#define MVPP2_PRS_FLOW_ID_MASK 0x3f
+#define MVPP2_PRS_TCAM_ENTRY_INVALID 1
+#define MVPP2_PRS_TCAM_DSA_TAGGED_BIT BIT(5)
+#define MVPP2_PRS_IPV4_HEAD 0x40
+#define MVPP2_PRS_IPV4_HEAD_MASK 0xf0
+#define MVPP2_PRS_IPV4_MC 0xe0
+#define MVPP2_PRS_IPV4_MC_MASK 0xf0
+#define MVPP2_PRS_IPV4_BC_MASK 0xff
+#define MVPP2_PRS_IPV4_IHL 0x5
+#define MVPP2_PRS_IPV4_IHL_MASK 0xf
+#define MVPP2_PRS_IPV6_MC 0xff
+#define MVPP2_PRS_IPV6_MC_MASK 0xff
+#define MVPP2_PRS_IPV6_HOP_MASK 0xff
+#define MVPP2_PRS_TCAM_PROTO_MASK 0xff
+#define MVPP2_PRS_TCAM_PROTO_MASK_L 0x3f
+#define MVPP2_PRS_DBL_VLANS_MAX 100
+
+/*
+ * Tcam structure:
+ * - lookup ID - 4 bits
+ * - port ID - 1 byte
+ * - additional information - 1 byte
+ * - header data - 8 bytes
+ * The fields are represented by MVPP2_PRS_TCAM_DATA_REG(5)->(0).
+ */
+#define MVPP2_PRS_AI_BITS 8
+#define MVPP2_PRS_PORT_MASK 0xff
+#define MVPP2_PRS_LU_MASK 0xf
+#define MVPP2_PRS_TCAM_DATA_BYTE(offs) (((offs) - ((offs) % 2)) * 2 + ((offs) % 2))
+#define MVPP2_PRS_TCAM_DATA_BYTE_EN(offs) (((offs) * 2) - ((offs) % 2) + 2)
+#define MVPP2_PRS_TCAM_AI_BYTE 16
+#define MVPP2_PRS_TCAM_PORT_BYTE 17
+#define MVPP2_PRS_TCAM_LU_BYTE 20
+#define MVPP2_PRS_TCAM_EN_OFFS(offs) ((offs) + 2)
+#define MVPP2_PRS_TCAM_INV_WORD 5
+/* Tcam entries ID */
+#define MVPP2_PE_DROP_ALL 0
+#define MVPP2_PE_FIRST_FREE_TID 1
+#define MVPP2_PE_LAST_FREE_TID (MVPP2_PRS_TCAM_SRAM_SIZE - 31)
+#define MVPP2_PE_IP6_EXT_PROTO_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 30)
+#define MVPP2_PE_MAC_MC_IP6 (MVPP2_PRS_TCAM_SRAM_SIZE - 29)
+#define MVPP2_PE_IP6_ADDR_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 28)
+#define MVPP2_PE_IP4_ADDR_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 27)
+#define MVPP2_PE_LAST_DEFAULT_FLOW (MVPP2_PRS_TCAM_SRAM_SIZE - 26)
+#define MVPP2_PE_FIRST_DEFAULT_FLOW (MVPP2_PRS_TCAM_SRAM_SIZE - 19)
+#define MVPP2_PE_EDSA_TAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 18)
+#define MVPP2_PE_EDSA_UNTAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 17)
+#define MVPP2_PE_DSA_TAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 16)
+#define MVPP2_PE_DSA_UNTAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 15)
+#define MVPP2_PE_ETYPE_EDSA_TAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 14)
+#define MVPP2_PE_ETYPE_EDSA_UNTAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 13)
+#define MVPP2_PE_ETYPE_DSA_TAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 12)
+#define MVPP2_PE_ETYPE_DSA_UNTAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 11)
+#define MVPP2_PE_MH_DEFAULT (MVPP2_PRS_TCAM_SRAM_SIZE - 10)
+#define MVPP2_PE_DSA_DEFAULT (MVPP2_PRS_TCAM_SRAM_SIZE - 9)
+#define MVPP2_PE_IP6_PROTO_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 8)
+#define MVPP2_PE_IP4_PROTO_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 7)
+#define MVPP2_PE_ETH_TYPE_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 6)
+#define MVPP2_PE_VLAN_DBL (MVPP2_PRS_TCAM_SRAM_SIZE - 5)
+#define MVPP2_PE_VLAN_NONE (MVPP2_PRS_TCAM_SRAM_SIZE - 4)
+#define MVPP2_PE_MAC_MC_ALL (MVPP2_PRS_TCAM_SRAM_SIZE - 3)
+#define MVPP2_PE_MAC_PROMISCUOUS (MVPP2_PRS_TCAM_SRAM_SIZE - 2)
+#define MVPP2_PE_MAC_NON_PROMISCUOUS (MVPP2_PRS_TCAM_SRAM_SIZE - 1)
+
+/*
+ * Sram structure
+ * The fields are represented by MVPP2_PRS_TCAM_DATA_REG(3)->(0).
+ */
+#define MVPP2_PRS_SRAM_RI_OFFS 0
+#define MVPP2_PRS_SRAM_RI_WORD 0
+#define MVPP2_PRS_SRAM_RI_CTRL_OFFS 32
+#define MVPP2_PRS_SRAM_RI_CTRL_WORD 1
+#define MVPP2_PRS_SRAM_RI_CTRL_BITS 32
+#define MVPP2_PRS_SRAM_SHIFT_OFFS 64
+#define MVPP2_PRS_SRAM_SHIFT_SIGN_BIT 72
+#define MVPP2_PRS_SRAM_UDF_OFFS 73
+#define MVPP2_PRS_SRAM_UDF_BITS 8
+#define MVPP2_PRS_SRAM_UDF_MASK 0xff
+#define MVPP2_PRS_SRAM_UDF_SIGN_BIT 81
+#define MVPP2_PRS_SRAM_UDF_TYPE_OFFS 82
+#define MVPP2_PRS_SRAM_UDF_TYPE_MASK 0x7
+#define MVPP2_PRS_SRAM_UDF_TYPE_L3 1
+#define MVPP2_PRS_SRAM_UDF_TYPE_L4 4
+#define MVPP2_PRS_SRAM_OP_SEL_SHIFT_OFFS 85
+#define MVPP2_PRS_SRAM_OP_SEL_SHIFT_MASK 0x3
+#define MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD 1
+#define MVPP2_PRS_SRAM_OP_SEL_SHIFT_IP4_ADD 2
+#define MVPP2_PRS_SRAM_OP_SEL_SHIFT_IP6_ADD 3
+#define MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS 87
+#define MVPP2_PRS_SRAM_OP_SEL_UDF_BITS 2
+#define MVPP2_PRS_SRAM_OP_SEL_UDF_MASK 0x3
+#define MVPP2_PRS_SRAM_OP_SEL_UDF_ADD 0
+#define MVPP2_PRS_SRAM_OP_SEL_UDF_IP4_ADD 2
+#define MVPP2_PRS_SRAM_OP_SEL_UDF_IP6_ADD 3
+#define MVPP2_PRS_SRAM_OP_SEL_BASE_OFFS 89
+#define MVPP2_PRS_SRAM_AI_OFFS 90
+#define MVPP2_PRS_SRAM_AI_CTRL_OFFS 98
+#define MVPP2_PRS_SRAM_AI_CTRL_BITS 8
+#define MVPP2_PRS_SRAM_AI_MASK 0xff
+#define MVPP2_PRS_SRAM_NEXT_LU_OFFS 106
+#define MVPP2_PRS_SRAM_NEXT_LU_MASK 0xf
+#define MVPP2_PRS_SRAM_LU_DONE_BIT 110
+#define MVPP2_PRS_SRAM_LU_GEN_BIT 111
+
+/* Sram result info bits assignment */
+#define MVPP2_PRS_RI_MAC_ME_MASK 0x1
+#define MVPP2_PRS_RI_DSA_MASK 0x2
+#define MVPP2_PRS_RI_VLAN_MASK 0xc
+#define MVPP2_PRS_RI_VLAN_NONE ~(BIT(2) | BIT(3))
+#define MVPP2_PRS_RI_VLAN_SINGLE BIT(2)
+#define MVPP2_PRS_RI_VLAN_DOUBLE BIT(3)
+#define MVPP2_PRS_RI_VLAN_TRIPLE (BIT(2) | BIT(3))
+#define MVPP2_PRS_RI_CPU_CODE_MASK 0x70
+#define MVPP2_PRS_RI_CPU_CODE_RX_SPEC BIT(4)
+#define MVPP2_PRS_RI_L2_CAST_MASK 0x600
+#define MVPP2_PRS_RI_L2_UCAST ~(BIT(9) | BIT(10))
+#define MVPP2_PRS_RI_L2_MCAST BIT(9)
+#define MVPP2_PRS_RI_L2_BCAST BIT(10)
+#define MVPP2_PRS_RI_PPPOE_MASK 0x800
+#define MVPP2_PRS_RI_L3_PROTO_MASK 0x7000
+#define MVPP2_PRS_RI_L3_UN ~(BIT(12) | BIT(13) | BIT(14))
+#define MVPP2_PRS_RI_L3_IP4 BIT(12)
+#define MVPP2_PRS_RI_L3_IP4_OPT BIT(13)
+#define MVPP2_PRS_RI_L3_IP4_OTHER (BIT(12) | BIT(13))
+#define MVPP2_PRS_RI_L3_IP6 BIT(14)
+#define MVPP2_PRS_RI_L3_IP6_EXT (BIT(12) | BIT(14))
+#define MVPP2_PRS_RI_L3_ARP (BIT(13) | BIT(14))
+#define MVPP2_PRS_RI_L3_ADDR_MASK 0x18000
+#define MVPP2_PRS_RI_L3_UCAST ~(BIT(15) | BIT(16))
+#define MVPP2_PRS_RI_L3_MCAST BIT(15)
+#define MVPP2_PRS_RI_L3_BCAST (BIT(15) | BIT(16))
+#define MVPP2_PRS_RI_IP_FRAG_MASK 0x20000
+#define MVPP2_PRS_RI_UDF3_MASK 0x300000
+#define MVPP2_PRS_RI_UDF3_RX_SPECIAL BIT(21)
+#define MVPP2_PRS_RI_L4_PROTO_MASK 0x1c00000
+#define MVPP2_PRS_RI_L4_TCP BIT(22)
+#define MVPP2_PRS_RI_L4_UDP BIT(23)
+#define MVPP2_PRS_RI_L4_OTHER (BIT(22) | BIT(23))
+#define MVPP2_PRS_RI_UDF7_MASK 0x60000000
+#define MVPP2_PRS_RI_UDF7_IP6_LITE BIT(29)
+#define MVPP2_PRS_RI_DROP_MASK 0x80000000
+
+/* Sram additional info bits assignment */
+#define MVPP2_PRS_IPV4_DIP_AI_BIT BIT(0)
+#define MVPP2_PRS_IPV6_NO_EXT_AI_BIT BIT(0)
+#define MVPP2_PRS_IPV6_EXT_AI_BIT BIT(1)
+#define MVPP2_PRS_IPV6_EXT_AH_AI_BIT BIT(2)
+#define MVPP2_PRS_IPV6_EXT_AH_LEN_AI_BIT BIT(3)
+#define MVPP2_PRS_IPV6_EXT_AH_L4_AI_BIT BIT(4)
+#define MVPP2_PRS_SINGLE_VLAN_AI 0
+#define MVPP2_PRS_DBL_VLAN_AI_BIT BIT(7)
+
+/* DSA/EDSA type */
+#define MVPP2_PRS_TAGGED TRUE
+#define MVPP2_PRS_UNTAGGED FALSE
+#define MVPP2_PRS_EDSA TRUE
+#define MVPP2_PRS_DSA FALSE
+
+/* MAC entries, shadow udf */
+enum Mvpp2PrsUdf {
+ MVPP2_PRS_UDF_MAC_DEF,
+ MVPP2_PRS_UDF_MAC_RANGE,
+ MVPP2_PRS_UDF_L2_DEF,
+ MVPP2_PRS_UDF_L2_DEF_COPY,
+ MVPP2_PRS_UDF_L2_USER,
+};
+
+/* Lookup ID */
+enum Mvpp2PrsLookup {
+ MVPP2_PRS_LU_MH,
+ MVPP2_PRS_LU_MAC,
+ MVPP2_PRS_LU_DSA,
+ MVPP2_PRS_LU_VLAN,
+ MVPP2_PRS_LU_L2,
+ MVPP2_PRS_LU_PPPOE,
+ MVPP2_PRS_LU_IP4,
+ MVPP2_PRS_LU_IP6,
+ MVPP2_PRS_LU_FLOWS,
+ MVPP2_PRS_LU_LAST,
+};
+
+/* L3 cast enum */
+enum Mvpp2PrsL3Cast {
+ MVPP2_PRS_L3_UNI_CAST,
+ MVPP2_PRS_L3_MULTI_CAST,
+ MVPP2_PRS_L3_BROAD_CAST
+};
+
+/* Classifier constants */
+#define MVPP2_CLS_FLOWS_TBL_SIZE 512
+#define MVPP2_CLS_FLOWS_TBL_DATA_WORDS 3
+#define MVPP2_CLS_LKP_TBL_SIZE 64
+
+/* BM cookie (32 bits) definition */
+#define MVPP2_BM_COOKIE_POOL_OFFS 8
+#define MVPP2_BM_COOKIE_CPU_OFFS 24
+
+/*
+ * The MVPP2_TX_DESC and MVPP2_RX_DESC structures describe the
+ * layout of the transmit and reception DMA descriptors, and their
+ * layout is therefore defined by the hardware design
+ */
+#define MVPP2_TXD_L3_OFF_SHIFT 0
+#define MVPP2_TXD_IP_HLEN_SHIFT 8
+#define MVPP2_TXD_L4_CSUM_FRAG BIT(13)
+#define MVPP2_TXD_L4_CSUM_NOT BIT(14)
+#define MVPP2_TXD_IP_CSUM_DISABLE BIT(15)
+#define MVPP2_TXD_PADDING_DISABLE BIT(23)
+#define MVPP2_TXD_L4_UDP BIT(24)
+#define MVPP2_TXD_L3_IP6 BIT(26)
+#define MVPP2_TXD_L_DESC BIT(28)
+#define MVPP2_TXD_F_DESC BIT(29)
+
+#define MVPP2_RXD_ERR_SUMMARY BIT(15)
+#define MVPP2_RXD_ERR_CODE_MASK (BIT(13) | BIT(14))
+#define MVPP2_RXD_ERR_CRC 0x0
+#define MVPP2_RXD_ERR_OVERRUN BIT(13)
+#define MVPP2_RXD_ERR_RESOURCE (BIT(13) | BIT(14))
+#define MVPP2_RXD_BM_POOL_ID_OFFS 16
+#define MVPP2_RXD_BM_POOL_ID_MASK (BIT(16) | BIT(17) | BIT(18))
+#define MVPP2_RXD_HWF_SYNC BIT(21)
+#define MVPP2_RXD_L4_CSUM_OK BIT(22)
+#define MVPP2_RXD_IP4_HEADER_ERR BIT(24)
+#define MVPP2_RXD_L4_TCP BIT(25)
+#define MVPP2_RXD_L4_UDP BIT(26)
+#define MVPP2_RXD_L3_IP4 BIT(28)
+#define MVPP2_RXD_L3_IP6 BIT(30)
+#define MVPP2_RXD_BUF_HDR BIT(31)
+
+typedef struct {
+ UINT32 command; /* Options used by HW for packet transmitting.*/
+ UINT8 PacketOffset; /* the offset from the buffer beginning */
+ UINT8 PhysTxq; /* destination queue ID */
+ UINT16 DataSize; /* data size of transmitted packet in bytes */
+ UINT64 RsrvdHwCmd1; /* HwCmd (BM, PON, PNC) */
+ UINT64 BufPhysAddrHwCmd2;
+ UINT64 BufCookieBmQsetHwCmd3;
+} MVPP2_TX_DESC;
+
+typedef struct {
+ UINT32 status; /* info about received packet */
+ UINT16 reserved1; /* ParserInfo (for future use, PnC) */
+ UINT16 DataSize; /* size of received packet in bytes */
+ UINT16 RsrvdGem; /* GemPortId (for future use, PON) */
+ UINT16 RsrvdL4csum; /* CsumL4 (for future use, PnC) */
+ UINT32 RsrvdTimestamp;
+ UINT64 BufPhysAddrKeyHash;
+ UINT64 BufCookieBmQsetClsInfo;
+} MVPP2_RX_DESC;
+
+union Mvpp2PrsTcamEntry {
+ UINT32 Word[MVPP2_PRS_TCAM_WORDS];
+ UINT8 Byte[MVPP2_PRS_TCAM_WORDS * 4];
+};
+
+union Mvpp2PrsSramEntry {
+ UINT32 Word[MVPP2_PRS_SRAM_WORDS];
+ UINT8 Byte[MVPP2_PRS_SRAM_WORDS * 4];
+};
+
+typedef struct {
+ UINT32 Index;
+ union Mvpp2PrsTcamEntry Tcam;
+ union Mvpp2PrsSramEntry Sram;
+} MVPP2_PRS_ENTRY;
+
+typedef struct {
+ BOOLEAN Valid;
+ BOOLEAN Finish;
+
+ /* Lookup ID */
+ INT32 Lu;
+
+ /* User defined offset */
+ INT32 Udf;
+
+ /* Result info */
+ UINT32 Ri;
+ UINT32 RiMask;
+} MVPP2_PRS_SHADOW;
+
+typedef struct {
+ UINT32 Index;
+ UINT32 Data[MVPP2_CLS_FLOWS_TBL_DATA_WORDS];
+} MVPP2_CLS_FLOW_ENTRY;
+
+typedef struct {
+ UINT32 Lkpid;
+ UINT32 Way;
+ UINT32 Data;
+} MVPP2_CLS_LOOKUP_ENTRY;
+
+typedef struct {
+ UINT32 NextBuffPhysAddr;
+ UINT32 NextBuffVirtAddr;
+ UINT16 ByteCount;
+ UINT16 info;
+ UINT8 reserved1; /* BmQset (for future use, BM) */
+} MVPP2_BUFF_HDR;
+
+/* Buffer header info bits */
+#define MVPP2_B_HDR_INFO_MC_ID_MASK 0xfff
+#define MVPP2_B_HDR_INFO_MC_ID(info) ((info) & MVPP2_B_HDR_INFO_MC_ID_MASK)
+#define MVPP2_B_HDR_INFO_LAST_OFFS 12
+#define MVPP2_B_HDR_INFO_LAST_MASK BIT(12)
+#define MVPP2_B_HDR_INFO_IS_LAST(info) ((info & MVPP2_B_HDR_INFO_LAST_MASK) >> MVPP2_B_HDR_INFO_LAST_OFFS)
+
+/* Net Complex */
+enum MvNetcTopology {
+ MV_NETC_GE_MAC0_RXAUI_L23 = BIT(0),
+ MV_NETC_GE_MAC0_RXAUI_L45 = BIT(1),
+ MV_NETC_GE_MAC0_XAUI = BIT(2),
+ MV_NETC_GE_MAC2_SGMII = BIT(3),
+ MV_NETC_GE_MAC3_SGMII = BIT(4),
+ MV_NETC_GE_MAC3_RGMII = BIT(5),
+};
+
+enum MvNetcPhase {
+ MV_NETC_FIRST_PHASE,
+ MV_NETC_SECOND_PHASE,
+};
+
+enum MvNetcSgmiiXmiMode {
+ MV_NETC_GBE_SGMII,
+ MV_NETC_GBE_XMII,
+};
+
+enum MvNetcMiiMode {
+ MV_NETC_GBE_RGMII,
+ MV_NETC_GBE_MII,
+};
+
+enum MvNetcLanes {
+ MV_NETC_LANE_23,
+ MV_NETC_LANE_45,
+};
+
+/* Port related */
+enum MvReset {
+ RESET,
+ UNRESET
+};
+
+enum Mvpp2Command {
+ MVPP2_START, /* Start */
+ MVPP2_STOP, /* Stop */
+ MVPP2_PAUSE, /* Pause */
+ MVPP2_RESTART /* Restart */
+};
+
+enum MvPortDuplex {
+ MV_PORT_DUPLEX_AN,
+ MV_PORT_DUPLEX_HALF,
+ MV_PORT_DUPLEX_FULL
+};
+
+#endif /* __MVPP2_LIB_HW__ */
diff --git a/Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.c b/Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.c
new file mode 100644
index 0000000000..8de2473d09
--- /dev/null
+++ b/Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.c
@@ -0,0 +1,1271 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#include <Protocol/DevicePath.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/SimpleNetwork.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/NetLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include "Mvpp2LibHw.h"
+#include "Mvpp2Lib.h"
+#include "Pp2Dxe.h"
+
+#define ReturnUnlock(tpl, status) do { gBS->RestoreTPL (tpl); return (status); } while(0)
+
+STATIC MVPP2_SHARED *Mvpp2Shared;
+STATIC BUFFER_LOCATION BufferLocation;
+STATIC PP2_DEVICE_PATH Pp2DevicePathTemplate = {
+ {
+ {
+ MESSAGING_DEVICE_PATH,
+ MSG_MAC_ADDR_DP,
+ {
+ (UINT8) (sizeof(MAC_ADDR_DEVICE_PATH)),
+ (UINT8) ((sizeof(MAC_ADDR_DEVICE_PATH)) >> 8)
+ }
+ },
+ { { 0 } },
+ 0
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ { sizeof(EFI_DEVICE_PATH_PROTOCOL), 0 }
+ }
+};
+
+EFI_SIMPLE_NETWORK_PROTOCOL Pp2SnpTemplate = {
+ EFI_SIMPLE_NETWORK_PROTOCOL_REVISION, // Revision
+ Pp2SnpStart, // Start
+ Pp2SnpStop, // Stop
+ Pp2DxeSnpInitialize, // Initialize
+ Pp2SnpReset, // Reset
+ Pp2SnpShutdown, // Shutdown
+ Pp2SnpReceiveFilters, // ReceiveFilters
+ Pp2SnpStationAddress, // StationAddress
+ Pp2SnpNetStat, // Statistics
+ Pp2SnpIpToMac, // MCastIpToMac
+ NULL, // NvData
+ Pp2SnpGetStatus, // GetStatus
+ Pp2SnpTransmit, // Transmit
+ Pp2SnpReceive, // Receive
+ NULL, // WaitForPacket
+ NULL // Mode
+};
+
+EFI_SIMPLE_NETWORK_MODE Pp2SnpModeTemplate = {
+ EfiSimpleNetworkStopped, // State
+ NET_ETHER_ADDR_LEN, // HwAddressSize
+ sizeof (ETHER_HEAD), // MediaHeaderSize
+ EFI_PAGE_SIZE, // MaxPacketSize
+ 0, // NvRamSize
+ 0, // MvRamAccessSize
+ EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
+ EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
+ EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST |
+ EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS |
+ EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST, // ReceiveFilterMask
+ EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
+ EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
+ EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST, // ReceiveFilterSetting
+ MAX_MCAST_FILTER_CNT, // MacMCastFilterCount
+ 0, // MCastFilterCount
+ {
+ { { 0 } }
+ }, // MCastFilter
+ {
+ { 0 }
+ }, // CurrentAddress
+ {
+ { 0 }
+ }, // BroadcastAddress
+ {
+ { 0 }
+ }, // Permanent Address
+ NET_IFTYPE_ETHERNET, // IfType
+ TRUE, // MacAddressChangeable
+ FALSE, // MultipleTxSupported
+ TRUE, // MediaPresentSupported
+ FALSE // MediaPresent
+};
+
+#define QueueNext(off) ((((off) + 1) >= QUEUE_DEPTH) ? 0 : ((off) + 1))
+
+STATIC
+EFI_STATUS
+QueueInsert (
+ IN PP2DXE_CONTEXT *Pp2Context,
+ IN VOID *Buffer
+ )
+{
+
+ if (QueueNext (Pp2Context->CompletionQueueTail) == Pp2Context->CompletionQueueHead) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Pp2Context->CompletionQueue[Pp2Context->CompletionQueueTail] = Buffer;
+ Pp2Context->CompletionQueueTail = QueueNext (Pp2Context->CompletionQueueTail);
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+VOID *
+QueueRemove (
+ IN PP2DXE_CONTEXT *Pp2Context
+ )
+{
+ VOID *Buffer;
+
+ if (Pp2Context->CompletionQueueTail == Pp2Context->CompletionQueueHead) {
+ return NULL;
+ }
+
+ Buffer = Pp2Context->CompletionQueue[Pp2Context->CompletionQueueHead];
+ Pp2Context->CompletionQueue[Pp2Context->CompletionQueueHead] = NULL;
+ Pp2Context->CompletionQueueHead = QueueNext (Pp2Context->CompletionQueueHead);
+
+ return Buffer;
+}
+
+STATIC
+EFI_STATUS
+Pp2DxeBmPoolInit (
+ VOID
+ )
+{
+ INTN Index;
+ UINT8 *PoolAddr;
+ UINT32 PoolSize = (sizeof(VOID *) * MVPP2_BM_SIZE) * 2 + MVPP2_BM_POOL_PTR_ALIGN;
+
+ ASSERT(MVPP2_BM_POOL_PTR_ALIGN >= sizeof(UINTN));
+
+ PoolSize = (sizeof(VOID *) * MVPP2_BM_SIZE) * 2 + MVPP2_BM_POOL_PTR_ALIGN;
+
+ for (Index = 0; Index < MVPP2_BM_POOLS_NUM; Index++) {
+ /* BmIrqClear */
+ Mvpp2BmIrqClear(Mvpp2Shared, Index);
+ }
+
+ Mvpp2Shared->BmPools = AllocateZeroPool (sizeof(MVPP2_BMS_POOL));
+
+ if (Mvpp2Shared->BmPools == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PoolAddr = UncachedAllocateAlignedZeroPool (PoolSize, MVPP2_BM_POOL_PTR_ALIGN);
+ if (PoolAddr == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Mvpp2Shared->BmPools->Id = MVPP2_BM_POOL;
+ Mvpp2Shared->BmPools->VirtAddr = (UINT32 *)PoolAddr;
+ Mvpp2Shared->BmPools->PhysAddr = (UINTN)PoolAddr;
+
+ Mvpp2BmPoolHwCreate(Mvpp2Shared, Mvpp2Shared->BmPools, MVPP2_BM_SIZE);
+
+ return EFI_SUCCESS;
+}
+
+/* Enable and fill BM pool */
+STATIC
+EFI_STATUS
+Pp2DxeBmStart (
+ VOID
+ )
+{
+ UINT8 *Buff, *BuffPhys;
+ INTN Index;
+
+ ASSERT(BM_ALIGN >= sizeof(UINTN));
+
+ Mvpp2BmPoolCtrl(Mvpp2Shared, MVPP2_BM_POOL, MVPP2_START);
+ Mvpp2BmPoolBufsizeSet(Mvpp2Shared, Mvpp2Shared->BmPools, RX_BUFFER_SIZE);
+
+ /* Fill BM pool with Buffers */
+ for (Index = 0; Index < MVPP2_BM_SIZE; Index++) {
+ Buff = (UINT8 *)(BufferLocation.RxBuffers + (Index * RX_BUFFER_SIZE));
+ if (Buff == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ BuffPhys = ALIGN_POINTER(Buff, BM_ALIGN);
+ Mvpp2BmPoolPut(Mvpp2Shared, MVPP2_BM_POOL, (UINTN)BuffPhys, (UINTN)BuffPhys);
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+VOID
+Pp2DxeStartDev (
+ IN PP2DXE_CONTEXT *Pp2Context
+ )
+{
+ PP2DXE_PORT *Port = &Pp2Context->Port;
+
+ /* Config classifier decoding table */
+ Mvpp2ClsPortConfig(Port);
+ Mvpp2ClsOversizeRxqSet(Port);
+ MvGop110PortEventsMask(Port);
+ MvGop110PortEnable(Port);
+
+ /* Enable transmit and receive */
+ Mvpp2EgressEnable(Port);
+ Mvpp2IngressEnable(Port);
+}
+
+STATIC
+EFI_STATUS
+Pp2DxeSetupRxqs (
+ IN PP2DXE_CONTEXT *Pp2Context
+ )
+{
+ INTN Queue;
+ EFI_STATUS Status;
+ MVPP2_RX_QUEUE *Rxq;
+
+ for (Queue = 0; Queue < RxqNumber; Queue++) {
+ Rxq = &Pp2Context->Port.Rxqs[Queue];
+ Rxq->DescsPhys = (DmaAddrT)Rxq->Descs;
+ if (Rxq->Descs == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrCleanup;
+ }
+
+ Mvpp2RxqHwInit(&Pp2Context->Port, Rxq);
+ }
+
+ return EFI_SUCCESS;
+
+ErrCleanup:
+ Mvpp2CleanupRxqs(&Pp2Context->Port);
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+Pp2DxeSetupTxqs (
+ IN PP2DXE_CONTEXT *Pp2Context
+ )
+{
+ INTN Queue;
+ MVPP2_TX_QUEUE *Txq;
+ EFI_STATUS Status;
+
+ for (Queue = 0; Queue < TxqNumber; Queue++) {
+ Txq = &Pp2Context->Port.Txqs[Queue];
+ Txq->DescsPhys = (DmaAddrT)Txq->Descs;
+ if (Txq->Descs == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrCleanup;
+ }
+
+ Mvpp2TxqHwInit(&Pp2Context->Port, Txq);
+ }
+
+ return EFI_SUCCESS;
+
+ErrCleanup:
+ Mvpp2CleanupTxqs(&Pp2Context->Port);
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+Pp2DxeSetupAggrTxqs (
+ IN PP2DXE_CONTEXT *Pp2Context
+ )
+{
+ MVPP2_TX_QUEUE *AggrTxq;
+
+ AggrTxq = Mvpp2Shared->AggrTxqs;
+ AggrTxq->DescsPhys = (DmaAddrT)AggrTxq->Descs;
+ if (AggrTxq->Descs == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Mvpp2AggrTxqHwInit(AggrTxq, AggrTxq->Size, 0, Mvpp2Shared);
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+Pp2DxeOpen (
+ IN PP2DXE_CONTEXT *Pp2Context
+ )
+{
+ PP2DXE_PORT *Port = &Pp2Context->Port;
+ UINT8 MacBcast[NET_ETHER_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ UINT8 DevAddr[NET_ETHER_ADDR_LEN];
+ INTN Ret;
+ EFI_STATUS Status;
+
+ CopyMem (DevAddr, Pp2Context->Snp.Mode->CurrentAddress.Addr, NET_ETHER_ADDR_LEN);
+
+ Ret = Mvpp2PrsMacDaAccept(Mvpp2Shared, Port->Id, MacBcast, TRUE);
+ if (Ret != 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ Ret = Mvpp2PrsMacDaAccept(Mvpp2Shared, Port->Id, DevAddr, TRUE);
+ if (Ret != 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ Ret = Mvpp2PrsTagModeSet(Mvpp2Shared, Port->Id, MVPP2_TAG_TYPE_MH);
+ if (Ret != 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ Ret = Mvpp2PrsDefFlow(Port);
+ if (Ret != 0) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = Pp2DxeSetupRxqs(Pp2Context);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ Status = Pp2DxeSetupTxqs(Pp2Context);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ Status = Pp2DxeSetupAggrTxqs(Pp2Context);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ Pp2DxeStartDev(Pp2Context);
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+Pp2DxeLatePortInitialize (
+ IN PP2DXE_CONTEXT *Pp2Context
+ )
+{
+ PP2DXE_PORT *Port = &Pp2Context->Port;
+ INTN Queue;
+
+ Port->TxRingSize = MVPP2_MAX_TXD;
+ Port->RxRingSize = MVPP2_MAX_RXD;
+
+ Mvpp2EgressDisable(Port);
+ MvGop110PortEventsMask(Port);
+ MvGop110PortDisable(Port);
+
+ Port->Txqs = AllocateZeroPool (sizeof(MVPP2_TX_QUEUE) * TxqNumber);
+ if (Port->Txqs == NULL) {
+ DEBUG((DEBUG_ERROR, "Failed to allocate Txqs\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ /* Use preallocated area */
+ Port->Txqs[0].Descs = BufferLocation.TxDescs;
+
+ for (Queue = 0; Queue < TxqNumber; Queue++) {
+ MVPP2_TX_QUEUE *Txq = &Port->Txqs[Queue];
+
+ Txq->Id = Mvpp2TxqPhys(Port->Id, Queue);
+ Txq->LogId = Queue;
+ Txq->Size = Port->TxRingSize;
+ }
+
+ Port->Rxqs = AllocateZeroPool (sizeof(MVPP2_RX_QUEUE) * RxqNumber);
+ if (Port->Rxqs == NULL) {
+ DEBUG((DEBUG_ERROR, "Failed to allocate Rxqs\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Port->Rxqs[0].Descs = BufferLocation.RxDescs;
+
+ for (Queue = 0; Queue < TxqNumber; Queue++) {
+ MVPP2_RX_QUEUE *Rxq = &Port->Rxqs[Queue];
+
+ Rxq->Id = Queue + Port->FirstRxq;
+ Rxq->Size = Port->RxRingSize;
+ }
+
+ Mvpp2IngressDisable(Port);
+
+ Mvpp2DefaultsSet(Port);
+
+ return Pp2DxeOpen(Pp2Context);
+}
+
+STATIC
+EFI_STATUS
+Pp2DxeLateInitialize (
+ IN PP2DXE_CONTEXT *Pp2Context
+ )
+{
+ PP2DXE_PORT *Port = &Pp2Context->Port;
+ EFI_STATUS Status;
+
+ if (!Pp2Context->LateInitialized) {
+ /* Full init on first call */
+ Status = Pp2DxeLatePortInitialize(Pp2Context);
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "Pp2Dxe: late initialization failed\n"));
+ return Status;
+ }
+
+ /* Attach pool to Rxq */
+ Mvpp2RxqLongPoolSet(Port, 0, MVPP2_BM_POOL);
+ Mvpp2RxqShortPoolSet(Port, 0, MVPP2_BM_POOL);
+
+ /*
+ * Mark this port being fully initialized,
+ * otherwise it will be inited again
+ * during next networking transaction,
+ * including memory allocatation for
+ * TX/RX queue, PHY connect/configuration
+ * and address decode configuration.
+ */
+ Pp2Context->LateInitialized = TRUE;
+ } else {
+ /* Upon all following calls, this is enough */
+ MvGop110PortEventsMask(Port);
+ MvGop110PortEnable(Port);
+ }
+ return 0;
+}
+
+EFI_STATUS
+Pp2DxePhyInitialize (
+ PP2DXE_CONTEXT *Pp2Context
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *PhyAddresses;
+
+ PhyAddresses = PcdGetPtr (PcdPhySmiAddresses);
+ Status = gBS->LocateProtocol (
+ &gMarvellPhyProtocolGuid,
+ NULL,
+ (VOID **) &Pp2Context->Phy
+ );
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ if (PhyAddresses[Pp2Context->Instance] == 0xff) {
+ /* PHY iniitalization not required */
+ return EFI_SUCCESS;
+ }
+
+ Status = Pp2Context->Phy->Init(
+ Pp2Context->Phy,
+ PhyAddresses[Pp2Context->Instance],
+ Pp2Context->Port.PhyInterface,
+ &Pp2Context->PhyDev
+ );
+
+ if (EFI_ERROR(Status) && Status != EFI_TIMEOUT) {
+ return Status;
+ }
+
+ Pp2Context->Phy->Status(Pp2Context->Phy, Pp2Context->PhyDev);
+ Mvpp2SmiPhyAddrCfg(&Pp2Context->Port, Pp2Context->Port.GopIndex, Pp2Context->PhyDev->Addr);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+Pp2DxeSnpInitialize (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINTN ExtraRxBufferSize OPTIONAL,
+ IN UINTN ExtraTxBufferSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ PP2DXE_CONTEXT *Pp2Context;
+ Pp2Context = INSTANCE_FROM_SNP(This);
+ UINT32 State = This->Mode->State;
+ EFI_TPL SavedTpl;
+
+ if (ExtraRxBufferSize != 0 || ExtraTxBufferSize != 0) {
+ DEBUG((DEBUG_ERROR, "Pp2Dxe%d: non-zero buffer requests\n", Pp2Context->Instance));
+ return EFI_UNSUPPORTED;
+ }
+
+ SavedTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ if (State != EfiSimpleNetworkStarted) {
+ switch (State) {
+ case EfiSimpleNetworkInitialized:
+ DEBUG((DEBUG_WARN, "Pp2Dxe%d: already initialized\n", Pp2Context->Instance));
+ ReturnUnlock (SavedTpl, EFI_SUCCESS);
+ case EfiSimpleNetworkStopped:
+ DEBUG((DEBUG_WARN, "Pp2Dxe%d: network stopped\n", Pp2Context->Instance));
+ ReturnUnlock (SavedTpl, EFI_NOT_STARTED);
+ default:
+ DEBUG((DEBUG_ERROR, "Pp2Dxe%d: wrong state\n", Pp2Context->Instance));
+ ReturnUnlock (SavedTpl, EFI_DEVICE_ERROR);
+ }
+ }
+
+ /* Successfully started, change state to Initialized */
+ This->Mode->State = EfiSimpleNetworkInitialized;
+
+ if (Pp2Context->Initialized) {
+ ReturnUnlock(SavedTpl, EFI_SUCCESS);
+ }
+
+ Pp2Context->Initialized = TRUE;
+
+ Status = Pp2DxePhyInitialize(Pp2Context);
+ if (EFI_ERROR(Status)) {
+ ReturnUnlock (SavedTpl, Status);
+ }
+
+ Status = Pp2DxeLateInitialize(Pp2Context);
+ ReturnUnlock (SavedTpl, Status);
+}
+
+EFI_STATUS
+EFIAPI
+Pp2SnpStart (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+{
+ PP2DXE_CONTEXT *Pp2Context;
+ UINT32 State = This->Mode->State;
+ EFI_TPL SavedTpl;
+
+ SavedTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ Pp2Context = INSTANCE_FROM_SNP(This);
+
+ if (State != EfiSimpleNetworkStopped) {
+ switch (State) {
+ case EfiSimpleNetworkStarted:
+ case EfiSimpleNetworkInitialized:
+ DEBUG((DEBUG_WARN, "Pp2Dxe%d: already initialized\n", Pp2Context->Instance));
+ ReturnUnlock (SavedTpl, EFI_ALREADY_STARTED);
+ default:
+ DEBUG((DEBUG_ERROR, "Pp2Dxe%d: wrong state\n", Pp2Context->Instance));
+ ReturnUnlock (SavedTpl, EFI_DEVICE_ERROR);
+ }
+ }
+
+ This->Mode->State = EfiSimpleNetworkStarted;
+ ReturnUnlock (SavedTpl, EFI_SUCCESS);
+}
+
+EFI_STATUS
+EFIAPI
+Pp2SnpStop (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+{
+ EFI_TPL SavedTpl;
+ SavedTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ PP2DXE_CONTEXT *Pp2Context = INSTANCE_FROM_SNP(This);
+ UINT32 State = This->Mode->State;
+
+ if (State != EfiSimpleNetworkStarted && State != EfiSimpleNetworkInitialized) {
+ switch (State) {
+ case EfiSimpleNetworkStopped:
+ DEBUG((DEBUG_WARN, "Pp2Dxe%d: not started\n", Pp2Context->Instance));
+ ReturnUnlock (SavedTpl, EFI_NOT_STARTED);
+ default:
+ DEBUG((DEBUG_ERROR, "Pp2Dxe%d: wrong state\n", Pp2Context->Instance));
+ ReturnUnlock (SavedTpl, EFI_DEVICE_ERROR);
+ }
+ }
+
+ This->Mode->State = EfiSimpleNetworkStopped;
+ ReturnUnlock (SavedTpl, EFI_SUCCESS);
+}
+
+EFI_STATUS
+EFIAPI
+Pp2SnpReset (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ return EFI_SUCCESS;
+}
+
+VOID
+EFIAPI
+Pp2DxeHalt (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ PP2DXE_CONTEXT *Pp2Context = Context;
+ PP2DXE_PORT *Port = &Pp2Context->Port;
+ STATIC BOOLEAN CommonPartHalted = FALSE;
+
+ if (!CommonPartHalted) {
+ Mvpp2BmStop(Mvpp2Shared, MVPP2_BM_POOL);
+ CommonPartHalted = TRUE;
+ }
+
+ Mvpp2TxqDrainSet(Port, 0, TRUE);
+ Mvpp2IngressDisable(Port);
+ Mvpp2EgressDisable(Port);
+
+ MvGop110PortEventsMask(Port);
+ MvGop110PortDisable(Port);
+}
+
+EFI_STATUS
+EFIAPI
+Pp2SnpShutdown (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+{
+ EFI_TPL SavedTpl;
+ SavedTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ PP2DXE_CONTEXT *Pp2Context = INSTANCE_FROM_SNP(This);
+ UINT32 State = This->Mode->State;
+
+ if (State != EfiSimpleNetworkInitialized) {
+ switch (State) {
+ case EfiSimpleNetworkStopped:
+ DEBUG((DEBUG_WARN, "Pp2Dxe%d: not started\n", Pp2Context->Instance));
+ ReturnUnlock (SavedTpl, EFI_NOT_STARTED);
+ case EfiSimpleNetworkStarted:
+ /* Fall through */
+ default:
+ DEBUG((DEBUG_ERROR, "Pp2Dxe%d: wrong state\n", Pp2Context->Instance));
+ ReturnUnlock (SavedTpl, EFI_DEVICE_ERROR);
+ }
+ }
+
+ ReturnUnlock (SavedTpl, EFI_SUCCESS);
+}
+
+EFI_STATUS
+EFIAPI
+Pp2SnpReceiveFilters (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINT32 Enable,
+ IN UINT32 Disable,
+ IN BOOLEAN ResetMCastFilter,
+ IN UINTN MCastFilterCnt OPTIONAL,
+ IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL
+ )
+{
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+Pp2SnpStationAddress (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,
+ IN BOOLEAN Reset,
+ IN EFI_MAC_ADDRESS *NewMac
+)
+{
+ PP2DXE_CONTEXT *Pp2Context = INSTANCE_FROM_SNP(Snp);
+ PP2_DEVICE_PATH *Pp2DevicePath = Pp2Context->DevicePath;
+ PP2DXE_PORT *Port = &Pp2Context->Port;
+ UINT32 State = Snp->Mode->State;
+ EFI_TPL SavedTpl;
+ INTN Ret;
+
+ /* Check Snp instance */
+ ASSERT(Snp != NULL);
+
+ /* Serialize access to data and registers */
+ SavedTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ /* Check that driver was started and initialised */
+ if (State != EfiSimpleNetworkInitialized) {
+ switch (State) {
+ case EfiSimpleNetworkStopped:
+ DEBUG((DEBUG_WARN, "Pp2Dxe%d: not started\n", Pp2Context->Instance));
+ ReturnUnlock (SavedTpl, EFI_NOT_STARTED);
+ case EfiSimpleNetworkStarted:
+ /* Fall through */
+ default:
+ DEBUG((DEBUG_ERROR, "Pp2Dxe%d: wrong state\n", Pp2Context->Instance));
+ ReturnUnlock (SavedTpl, EFI_DEVICE_ERROR);
+ }
+ }
+
+ /* Invalidate old unicast address in parser */
+ Ret = Mvpp2PrsMacDaAccept(Mvpp2Shared, Port->Id, Snp->Mode->CurrentAddress.Addr, FALSE);
+ if (Ret != 0) {
+ DEBUG((DEBUG_ERROR, "Pp2SnpStationAddress - Fail\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (Reset) {
+ CopyMem (Snp->Mode->CurrentAddress.Addr, Snp->Mode->PermanentAddress.Addr, NET_ETHER_ADDR_LEN);
+ CopyMem (NewMac->Addr, Snp->Mode->PermanentAddress.Addr, NET_ETHER_ADDR_LEN);
+ CopyMem (Pp2DevicePath->Pp2Mac.MacAddress.Addr, Snp->Mode->PermanentAddress.Addr, NET_ETHER_ADDR_LEN);
+ } else {
+ if (NewMac == NULL) {
+ ReturnUnlock (SavedTpl, EFI_INVALID_PARAMETER);
+ }
+ CopyMem (Snp->Mode->CurrentAddress.Addr, NewMac->Addr, NET_ETHER_ADDR_LEN);
+ CopyMem (Pp2DevicePath->Pp2Mac.MacAddress.Addr, NewMac->Addr, NET_ETHER_ADDR_LEN);
+ }
+
+ /* Update parser with new unicast address */
+ Ret = Mvpp2PrsMacDaAccept(Mvpp2Shared, Port->Id, Snp->Mode->CurrentAddress.Addr, TRUE);
+ if (Ret != 0) {
+ DEBUG((DEBUG_ERROR, "Pp2SnpStationAddress - Fail\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ /* Restore TPL and return */
+ gBS->RestoreTPL (SavedTpl);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+Pp2SnpNetStat (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN Reset,
+ IN OUT UINTN *StatisticsSize OPTIONAL,
+ OUT EFI_NETWORK_STATISTICS *StatisticsTable OPTIONAL
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+EFIAPI
+Pp2SnpIpToMac (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN IPv6,
+ IN EFI_IP_ADDRESS *IP,
+ OUT EFI_MAC_ADDRESS *MAC
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+EFIAPI
+Pp2SnpNvData (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN ReadWrite,
+ IN UINTN Offset,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+EFIAPI
+Pp2SnpGetStatus (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,
+ OUT UINT32 *InterruptStatus OPTIONAL,
+ OUT VOID **TxBuf OPTIONAL
+ )
+{
+ PP2DXE_CONTEXT *Pp2Context = INSTANCE_FROM_SNP(Snp);
+ PP2DXE_PORT *Port = &Pp2Context->Port;
+ BOOLEAN LinkUp;
+ EFI_TPL SavedTpl;
+
+ SavedTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ if (!Pp2Context->Initialized)
+ ReturnUnlock(SavedTpl, EFI_NOT_READY);
+
+ LinkUp = Port->AlwaysUp ? TRUE : MvGop110PortIsLinkUp(Port);
+
+ if (LinkUp != Snp->Mode->MediaPresent) {
+ DEBUG((DEBUG_INFO, "Pp2Dxe%d: Link ", Pp2Context->Instance));
+ DEBUG((DEBUG_INFO, LinkUp ? "up\n" : "down\n"));
+ }
+ Snp->Mode->MediaPresent = LinkUp;
+
+ if (TxBuf != NULL) {
+ *TxBuf = QueueRemove (Pp2Context);
+ }
+
+ ReturnUnlock(SavedTpl, EFI_SUCCESS);
+}
+
+EFI_STATUS
+EFIAPI
+Pp2SnpTransmit (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINTN HeaderSize,
+ IN UINTN BufferSize,
+ IN VOID *Buffer,
+ IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
+ IN EFI_MAC_ADDRESS *DestAddr OPTIONAL,
+ IN UINT16 *EtherTypePtr OPTIONAL
+ )
+{
+ PP2DXE_CONTEXT *Pp2Context = INSTANCE_FROM_SNP(This);
+ PP2DXE_PORT *Port = &Pp2Context->Port;
+ MVPP2_TX_QUEUE *AggrTxq = Mvpp2Shared->AggrTxqs;
+ MVPP2_TX_DESC *TxDesc;
+ EFI_STATUS Status;
+ INTN PollingCount;
+ INTN TxSent;
+ UINT8 *DataPtr = Buffer;
+ UINT16 EtherType;
+ UINT32 State = This->Mode->State;
+ EFI_TPL SavedTpl;
+
+ if (This == NULL || Buffer == NULL) {
+ DEBUG((DEBUG_ERROR, "Pp2Dxe: NULL Snp or Buffer\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (HeaderSize != 0) {
+ ASSERT (HeaderSize == This->Mode->MediaHeaderSize);
+ ASSERT (EtherTypePtr != NULL);
+ ASSERT (DestAddr != NULL);
+ }
+
+ SavedTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ /* Check that driver was started and initialised */
+ if (State != EfiSimpleNetworkInitialized) {
+ switch (State) {
+ case EfiSimpleNetworkStopped:
+ DEBUG((DEBUG_WARN, "Pp2Dxe%d: not started\n", Pp2Context->Instance));
+ ReturnUnlock (SavedTpl, EFI_NOT_STARTED);
+ case EfiSimpleNetworkStarted:
+ /* Fall through */
+ default:
+ DEBUG((DEBUG_ERROR, "Pp2Dxe%d: wrong state\n", Pp2Context->Instance));
+ ReturnUnlock (SavedTpl, EFI_DEVICE_ERROR);
+ }
+ }
+
+ if (!This->Mode->MediaPresent) {
+ DEBUG((DEBUG_ERROR, "Pp2Dxe: link not ready\n"));
+ ReturnUnlock(SavedTpl, EFI_NOT_READY);
+ }
+
+ EtherType = HTONS (*EtherTypePtr);
+
+ /* Fetch next descriptor */
+ TxDesc = Mvpp2TxqNextDescGet(AggrTxq);
+
+ if (!TxDesc) {
+ DEBUG((DEBUG_ERROR, "No tx descriptor to use\n"));
+ ReturnUnlock(SavedTpl, EFI_OUT_OF_RESOURCES);
+ }
+
+ if (HeaderSize != 0) {
+ CopyMem(DataPtr, DestAddr, NET_ETHER_ADDR_LEN);
+
+ if (SrcAddr != NULL)
+ CopyMem(DataPtr + NET_ETHER_ADDR_LEN, SrcAddr, NET_ETHER_ADDR_LEN);
+ else
+ CopyMem(DataPtr + NET_ETHER_ADDR_LEN, &This->Mode->CurrentAddress, NET_ETHER_ADDR_LEN);
+
+ CopyMem(DataPtr + NET_ETHER_ADDR_LEN * 2, &EtherType, 2);
+ }
+
+ /* Set descriptor fields */
+ TxDesc->command = MVPP2_TXD_IP_CSUM_DISABLE | MVPP2_TXD_L4_CSUM_NOT |
+ MVPP2_TXD_F_DESC | MVPP2_TXD_L_DESC;
+ TxDesc->DataSize = BufferSize;
+ TxDesc->PacketOffset = (PhysAddrT)DataPtr & MVPP2_TX_DESC_ALIGN;
+ Mvpp2x2TxdescPhysAddrSet((PhysAddrT)DataPtr & ~MVPP2_TX_DESC_ALIGN, TxDesc);
+ TxDesc->PhysTxq = Mvpp2TxqPhys(Port->Id, 0);
+
+ InvalidateDataCacheRange (DataPtr, BufferSize);
+
+ /* Issue send */
+ Mvpp2AggrTxqPendDescAdd(Port, 1);
+
+ /*
+ * Egress processing:
+ * Wait until packet is passed from per-cpu aggregated queue
+ * to physical per-port TXQ.
+ */
+ PollingCount = 0;
+ TxSent = Mvpp2AggrTxqPendDescNumGet(Mvpp2Shared, 0);
+ do {
+ if (PollingCount++ > MVPP2_TX_SEND_MAX_POLLING_COUNT) {
+ DEBUG((DEBUG_ERROR, "Pp2Dxe: transmit polling failed\n"));
+ ReturnUnlock(SavedTpl, EFI_TIMEOUT);
+ }
+ TxSent = Mvpp2AggrTxqPendDescNumGet(Mvpp2Shared, 0);
+ } while (TxSent);
+
+ /* Wait for packet to be transmitted by hardware. */
+ PollingCount = 0;
+ TxSent = Mvpp2TxqSentDescProc(Port, &Port->Txqs[0]);
+ while (!TxSent) {
+ if (PollingCount++ > MVPP2_TX_SEND_MAX_POLLING_COUNT) {
+ DEBUG((DEBUG_ERROR, "Pp2Dxe: transmit polling failed\n"));
+ ReturnUnlock(SavedTpl, EFI_TIMEOUT);
+ }
+ TxSent = Mvpp2TxqSentDescProc(Port, &Port->Txqs[0]);
+ }
+
+ /*
+ * At this point TxSent has increased - HW sent the packet
+ * Add buffer to completion queue and return.
+ */
+ Status = QueueInsert (Pp2Context, Buffer);
+ ReturnUnlock (SavedTpl, Status);
+}
+
+EFI_STATUS
+EFIAPI
+Pp2SnpReceive (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ OUT UINTN *HeaderSize OPTIONAL,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer,
+ OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
+ OUT EFI_MAC_ADDRESS *DstAddr OPTIONAL,
+ OUT UINT16 *EtherType OPTIONAL
+ )
+{
+ INTN ReceivedPackets;
+ PP2DXE_CONTEXT *Pp2Context = INSTANCE_FROM_SNP(This);
+ PP2DXE_PORT *Port = &Pp2Context->Port;
+ UINTN PhysAddr, VirtAddr;
+ EFI_STATUS Status = EFI_SUCCESS;
+ EFI_TPL SavedTpl;
+ UINT32 StatusReg;
+ INTN PoolId;
+ UINTN PktLength;
+ UINT8 *DataPtr;
+ MVPP2_RX_DESC *RxDesc;
+ MVPP2_RX_QUEUE *Rxq = &Port->Rxqs[0];
+
+ ASSERT (Port != NULL);
+ ASSERT (Rxq != NULL);
+
+ SavedTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ ReceivedPackets = Mvpp2RxqReceived(Port, Rxq->Id);
+
+ if (ReceivedPackets == 0) {
+ ReturnUnlock(SavedTpl, EFI_NOT_READY);
+ }
+
+ /* Process one packet per call */
+ RxDesc = Mvpp2RxqNextDescGet(Rxq);
+ StatusReg = RxDesc->status;
+
+ /* extract addresses from descriptor */
+ PhysAddr = RxDesc->BufPhysAddrKeyHash & MVPP22_ADDR_MASK;
+ VirtAddr = RxDesc->BufCookieBmQsetClsInfo & MVPP22_ADDR_MASK;
+
+ /* Drop packets with error or with buffer header (MC, SG) */
+ if ((StatusReg & MVPP2_RXD_BUF_HDR) || (StatusReg & MVPP2_RXD_ERR_SUMMARY)) {
+ DEBUG((DEBUG_WARN, "Pp2Dxe: dropping packet\n"));
+ Status = EFI_DEVICE_ERROR;
+ goto drop;
+ }
+
+ PktLength = (UINTN) RxDesc->DataSize - 2;
+ if (PktLength > *BufferSize) {
+ *BufferSize = PktLength;
+ DEBUG((DEBUG_ERROR, "Pp2Dxe: buffer too small\n"));
+ ReturnUnlock(SavedTpl, EFI_BUFFER_TOO_SMALL);
+ }
+
+ CopyMem (Buffer, (VOID*) (PhysAddr + 2), PktLength);
+ *BufferSize = PktLength;
+
+ if (HeaderSize != NULL) {
+ *HeaderSize = Pp2Context->Snp.Mode->MediaHeaderSize;
+ }
+
+ DataPtr = Buffer;
+
+ /* Extract the destination address */
+ if (DstAddr != NULL) {
+ ZeroMem (DstAddr, sizeof(EFI_MAC_ADDRESS));
+ CopyMem (DstAddr, &DataPtr[0], NET_ETHER_ADDR_LEN);
+ }
+
+ /* Get the source address */
+ if (SrcAddr != NULL) {
+ ZeroMem (SrcAddr, sizeof(EFI_MAC_ADDRESS));
+ CopyMem (SrcAddr, &DataPtr[6], NET_ETHER_ADDR_LEN);
+ }
+
+ /* Obtain Ether Type */
+ if (EtherType != NULL) {
+ *EtherType = NTOHS (*(UINT16 *)(&DataPtr[12]));
+ }
+
+drop:
+ /* Refill: pass packet back to BM */
+ PoolId = (StatusReg & MVPP2_RXD_BM_POOL_ID_MASK) >> MVPP2_RXD_BM_POOL_ID_OFFS;
+ Mvpp2BmPoolPut(Mvpp2Shared, PoolId, PhysAddr, VirtAddr);
+
+ /* Update counters with 1 packet received and 1 packet refilled */
+ Mvpp2RxqStatusUpdate(Port, Rxq->Id, 1, 1);
+
+ ReturnUnlock(SavedTpl, Status);
+}
+
+EFI_STATUS
+Pp2DxeSnpInstall (
+ IN PP2DXE_CONTEXT *Pp2Context
+ )
+{
+ EFI_HANDLE Handle = NULL;
+ EFI_STATUS Status;
+ PP2_DEVICE_PATH *Pp2DevicePath;
+ EFI_SIMPLE_NETWORK_MODE *SnpMode;
+
+ Pp2DevicePath = AllocateCopyPool (sizeof (PP2_DEVICE_PATH), &Pp2DevicePathTemplate);
+ if (Pp2DevicePath == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SnpMode = AllocateZeroPool (sizeof (EFI_SIMPLE_NETWORK_MODE));
+ if (SnpMode == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ /* Copy SNP data from templates */
+ CopyMem (&Pp2Context->Snp, &Pp2SnpTemplate, sizeof (EFI_SIMPLE_NETWORK_PROTOCOL));
+ CopyMem (SnpMode, &Pp2SnpModeTemplate, sizeof (EFI_SIMPLE_NETWORK_MODE));
+
+ /* Handle device path of the controller */
+ Pp2DevicePath->Pp2Mac.MacAddress.Addr[5] = Pp2Context->Instance + 1;
+ Pp2Context->Signature = PP2DXE_SIGNATURE;
+ Pp2Context->DevicePath = Pp2DevicePath;
+ Pp2DevicePath->Pp2Mac.IfType = SnpMode->IfType;
+
+ /* Update SNP Mode */
+ CopyMem (SnpMode->CurrentAddress.Addr, Pp2DevicePath->Pp2Mac.MacAddress.Addr, NET_ETHER_ADDR_LEN);
+ CopyMem (SnpMode->PermanentAddress.Addr, Pp2DevicePath->Pp2Mac.MacAddress.Addr, NET_ETHER_ADDR_LEN);
+ ZeroMem (&SnpMode->MCastFilter, MAX_MCAST_FILTER_CNT * sizeof(EFI_MAC_ADDRESS));
+ SetMem (&SnpMode->BroadcastAddress, sizeof (EFI_MAC_ADDRESS), 0xFF);
+
+ Pp2Context->Snp.Mode = SnpMode;
+
+ /* Install protocol */
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiSimpleNetworkProtocolGuid, &Pp2Context->Snp,
+ &gEfiDevicePathProtocolGuid, Pp2DevicePath,
+ NULL
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "Failed to install protocols.\n"));
+ }
+
+ return Status;
+}
+
+STATIC
+VOID
+Pp2DxeParsePortPcd (
+ IN PP2DXE_CONTEXT *Pp2Context
+ )
+{
+ UINT8 *PortIds, *GopIndexes, *PhyConnectionTypes, *AlwaysUp, *Speed;
+
+ PortIds = PcdGetPtr (PcdPp2PortIds);
+ GopIndexes = PcdGetPtr (PcdPp2GopIndexes);
+ PhyConnectionTypes = PcdGetPtr (PcdPhyConnectionTypes);
+ AlwaysUp = PcdGetPtr (PcdPp2InterfaceAlwaysUp);
+ Speed = PcdGetPtr (PcdPp2InterfaceSpeed);
+
+ ASSERT (PcdGetSize (PcdPp2GopIndexes) == PcdGetSize (PcdPp2PortIds));
+ ASSERT (PcdGetSize (PcdPhyConnectionTypes) == PcdGetSize (PcdPp2PortIds));
+ ASSERT (PcdGetSize (PcdPp2InterfaceAlwaysUp) == PcdGetSize (PcdPp2PortIds));
+ ASSERT (PcdGetSize (PcdPp2InterfaceSpeed) == PcdGetSize (PcdPp2PortIds));
+
+ Pp2Context->Port.Id = PortIds[Pp2Context->Instance];
+ Pp2Context->Port.GopIndex = GopIndexes[Pp2Context->Instance];
+ Pp2Context->Port.PhyInterface = PhyConnectionTypes[Pp2Context->Instance];
+ Pp2Context->Port.AlwaysUp = AlwaysUp[Pp2Context->Instance];
+ Pp2Context->Port.Speed = Speed[Pp2Context->Instance];
+ Pp2Context->Port.GmacBase = PcdGet64 (PcdPp2GmacBaseAddress) +
+ PcdGet32 (PcdPp2GmacDevSize) * Pp2Context->Port.GopIndex;
+ Pp2Context->Port.XlgBase = PcdGet64 (PcdPp2XlgBaseAddress) +
+ PcdGet32 (PcdPp2XlgDevSize) * Pp2Context->Port.GopIndex;
+}
+
+EFI_STATUS
+EFIAPI
+Pp2DxeInitialise (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ PP2DXE_CONTEXT *Pp2Context = NULL;
+ EFI_STATUS Status;
+ INTN Index;
+ VOID *BufferSpace;
+ UINT32 NetCompConfig = 0;
+ UINT8 NumPorts = PcdGet32 (PcdPp2NumPorts);
+
+ if (NumPorts == 0) {
+ DEBUG((DEBUG_ERROR, "Pp2Dxe: port number set to 0\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ /* Initialize private data */
+ Mvpp2Shared = AllocateZeroPool (sizeof (MVPP2_SHARED));
+ if (Mvpp2Shared == NULL) {
+ DEBUG((DEBUG_ERROR, "Allocation fail.\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Mvpp2Shared->Base = PcdGet64 (PcdPp2SharedAddress);
+ Mvpp2Shared->Rfu1Base = PcdGet64 (PcdPp2Rfu1BaseAddress);
+ Mvpp2Shared->SmiBase = PcdGet64 (PcdPp2SmiBaseAddress);
+ Mvpp2Shared->Tclk = PcdGet32 (PcdPp2ClockFrequency);
+
+ /* Prepare buffers */
+ BufferSpace = UncachedAllocateAlignedZeroPool (BD_SPACE, MVPP2_BUFFER_ALIGN_SIZE);
+ if (BufferSpace == NULL) {
+ DEBUG((DEBUG_ERROR, "Failed to allocate buffer space\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ BufferLocation.TxDescs = BufferSpace;
+ BufferLocation.AggrTxDescs = (MVPP2_TX_DESC *)((UINTN)BufferSpace + MVPP2_MAX_TXD * sizeof(MVPP2_TX_DESC));
+ BufferLocation.RxDescs = (MVPP2_RX_DESC *)((UINTN)BufferSpace +
+ (MVPP2_MAX_TXD + MVPP2_AGGR_TXQ_SIZE) * sizeof(MVPP2_TX_DESC));
+ BufferLocation.RxBuffers = (DmaAddrT)(BufferSpace +
+ (MVPP2_MAX_TXD + MVPP2_AGGR_TXQ_SIZE) * sizeof(MVPP2_TX_DESC) +
+ MVPP2_MAX_RXD * sizeof(MVPP2_RX_DESC));
+
+ /* Initialize HW */
+ Mvpp2AxiConfig(Mvpp2Shared);
+ Pp2DxeBmPoolInit();
+ Mvpp2RxFifoInit(Mvpp2Shared);
+
+ Mvpp2Shared->PrsShadow = AllocateZeroPool (sizeof(MVPP2_PRS_SHADOW) * MVPP2_PRS_TCAM_SRAM_SIZE);
+ if (Mvpp2Shared->PrsShadow == NULL) {
+ DEBUG((DEBUG_ERROR, "Failed to allocate PrsShadow\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = Mvpp2PrsDefaultInit(Mvpp2Shared);
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "Failed to intialize prs\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ Mvpp2ClsInit(Mvpp2Shared);
+
+ Status = Pp2DxeBmStart();
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "Pp2Dxe: BM start error\n"));
+ return Status;
+ }
+
+ /* Initialize aggregated transmit queues */
+ Mvpp2Shared->AggrTxqs = AllocateZeroPool (sizeof(MVPP2_TX_QUEUE));
+ if (Mvpp2Shared->AggrTxqs == NULL) {
+ DEBUG((DEBUG_ERROR, "Failed to allocate aggregated Txqs\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Mvpp2Shared->AggrTxqs->Descs = BufferLocation.AggrTxDescs;
+ Mvpp2Shared->AggrTxqs->Id = 0;
+ Mvpp2Shared->AggrTxqs->LogId = 0;
+ Mvpp2Shared->AggrTxqs->Size = MVPP2_AGGR_TXQ_SIZE;
+
+ for (Index = 0; Index < NumPorts; Index++) {
+ Pp2Context = AllocateZeroPool (sizeof (PP2DXE_CONTEXT));
+ if (Pp2Context == NULL) {
+ /*
+ * If allocation fails, all resources allocated before will get freed
+ * at ExitBootServices, as only EfiBootServicesData is used.
+ */
+ DEBUG((DEBUG_ERROR, "Allocation fail.\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ /* Instances are enumerated from 0 */
+ Pp2Context->Instance = Index;
+
+ /* Install SNP protocol */
+ Status = Pp2DxeSnpInstall(Pp2Context);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ Pp2DxeParsePortPcd(Pp2Context);
+ Pp2Context->Port.TxpNum = 1;
+ Pp2Context->Port.Priv = Mvpp2Shared;
+ Pp2Context->Port.FirstRxq = 4 * Pp2Context->Instance;
+
+ /* Gather accumulated configuration data of all ports' MAC's */
+ NetCompConfig |= MvpPp2xGop110NetcCfgCreate(&Pp2Context->Port);
+
+ MvGop110PortInit(&Pp2Context->Port);
+ MvGop110FlCfg(&Pp2Context->Port);
+
+ Status = gBS->CreateEvent (
+ EVT_SIGNAL_EXIT_BOOT_SERVICES,
+ TPL_NOTIFY,
+ Pp2DxeHalt,
+ Pp2Context,
+ &Pp2Context->EfiExitBootServicesEvent
+ );
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ }
+
+ MvGop110NetcInit(&Pp2Context->Port, NetCompConfig, MV_NETC_FIRST_PHASE);
+ MvGop110NetcInit(&Pp2Context->Port, NetCompConfig, MV_NETC_SECOND_PHASE);
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.h b/Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.h
new file mode 100644
index 0000000000..3bb0c4a653
--- /dev/null
+++ b/Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.h
@@ -0,0 +1,614 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#ifndef __PP2_DXE_H__
+#define __PP2_DXE_H__
+
+#include <Protocol/Cpu.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/Ip4.h>
+#include <Protocol/Ip6.h>
+#include <Protocol/MvPhy.h>
+#include <Protocol/SimpleNetwork.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/NetLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UncachedMemoryAllocationLib.h>
+
+#include "Mvpp2LibHw.h"
+
+#define PP2DXE_SIGNATURE SIGNATURE_32('P', 'P', '2', 'D')
+#define INSTANCE_FROM_SNP(a) CR((a), PP2DXE_CONTEXT, Snp, PP2DXE_SIGNATURE)
+
+/* OS API */
+#define Mvpp2Alloc(v) AllocateZeroPool(v)
+#define Mvpp2Free(p) FreePool(p)
+#define Mvpp2Memset(a, v, s) SetMem((a), (s), (v))
+#define Mvpp2Mdelay(t) gBS->Stall((t) * 1000)
+#define Mvpp2Fls(v) 1
+#define Mvpp2IsBroadcastEtherAddr(da) 1
+#define Mvpp2IsMulticastEtherAddr(da) 1
+#define Mvpp2Prefetch(v) do {} while(0);
+#define Mvpp2Printf(...) do {} while(0);
+#define Mvpp2SwapVariables(a,b) do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0)
+#define Mvpp2SwapBytes16(x) SwapBytes16((x))
+#define Mvpp2Iphdr EFI_IP4_HEADER
+#define Mvpp2Ipv6hdr EFI_IP6_HEADER
+#define MVPP2_ALIGN(x, m) ALIGN_VALUE((x), (m))
+#define MVPP2_ENOMEM -1
+#define MVPP2_EINVAL -2
+#define MVPP2_ERANGE -3
+#define MVPP2_USEC_PER_SEC 1000000L
+
+#define DmaAddrT UINTN
+#define PhysAddrT UINTN
+
+#define Upper32Bits(n) ((UINT32)(((n) >> 16) >> 16))
+#define Lower32Bits(n) ((UINT32)(n))
+
+#define ARCH_DMA_MINALIGN 64
+
+/* Port speeds */
+#define MV_PORT_SPEED_10 SPEED_10
+#define MV_PORT_SPEED_100 SPEED_100
+#define MV_PORT_SPEED_1000 SPEED_1000
+#define MV_PORT_SPEED_2500 SPEED_2500
+#define MV_PORT_SPEED_10000 SPEED_10000
+
+/* L2 and L3 protocol macros */
+#define MV_IPPR_TCP 0
+#define MV_IPPR_UDP 1
+#define MV_IPPR_IPIP 2
+#define MV_IPPR_ICMPV6 3
+#define MV_IPPR_IGMP 4
+#define MV_ETH_P_IP 5
+#define MV_ETH_P_IPV6 6
+#define MV_ETH_P_PPP_SES 7
+#define MV_ETH_P_ARP 8
+#define MV_ETH_P_8021Q 9
+#define MV_ETH_P_8021AD 10
+#define MV_ETH_P_EDSA 11
+#define MV_PPP_IP 12
+#define MV_PPP_IPV6 13
+#define MV_ETH_ALEN NET_ETHER_ADDR_LEN
+
+/* PHY modes */
+#define MV_MODE_SGMII PHY_CONNECTION_SGMII
+#define MV_MODE_RGMII PHY_CONNECTION_RGMII
+#define MV_MODE_XAUI PHY_CONNECTION_XAUI
+#define MV_MODE_RXAUI PHY_CONNECTION_RXAUI
+#define MV_MODE_QSGMII 100
+#define PP2DXE_MAX_PHY 2
+
+/* Gop */
+/* Sets the field located at the specified in data */
+#define U32_SET_FIELD(data, mask, val) ((data) = (((data) & ~(mask)) | (val)))
+#define MV_RGMII_TX_FIFO_MIN_TH 0x41
+#define MV_SGMII_TX_FIFO_MIN_TH 0x5
+#define MV_SGMII2_5_TX_FIFO_MIN_TH 0xB
+
+/* BM constants */
+#define MVPP2_BM_POOLS_NUM 8
+#define MVPP2_BM_LONG_BUF_NUM 1024
+#define MVPP2_BM_SHORT_BUF_NUM 2048
+#define MVPP2_BM_POOL_SIZE_MAX (SIZE_16KB - MVPP2_BM_POOL_PTR_ALIGN/4)
+#define MVPP2_BM_POOL_PTR_ALIGN 128
+#define MVPP2_BM_SWF_LONG_POOL(Port) ((Port > 2) ? 2 : Port)
+#define MVPP2_BM_SWF_SHORT_POOL 3
+#define MVPP2_BM_POOL 0
+#define MVPP2_BM_SIZE 32
+
+/*
+ * BM short pool packet Size
+ * These value assure that for SWF the total number
+ * of bytes allocated for each buffer will be 512
+ */
+#define MVPP2_BM_SHORT_PKT_SIZE 512
+
+/*
+ * Page table entries are set to 1MB, or multiples of 1MB
+ * (not < 1MB). driver uses less bd's so use 1MB bdspace.
+ */
+#define BD_SPACE (1 << 20)
+
+/* Buffer has to be aligned to 1M */
+#define MVPP2_BUFFER_ALIGN_SIZE (1 << 20)
+
+/* RX constants */
+#define RX_BUFFER_SIZE (ALIGN_VALUE(MTU + WRAP, ARCH_DMA_MINALIGN))
+#define MVPP2_RXQ_OFFSET 0
+#define BUFF_HDR_OFFS 32
+#define BM_ALIGN 32
+#define ETH_HLEN 14
+
+/* 2(HW hdr) 14(MAC hdr) 4(CRC) 32(extra for cache prefetch) */
+#define WRAP (2 + ETH_HLEN + 4 + 32)
+#define MTU 1500
+
+/*
+ * Maximum retries of checking, wheter HW really sent the packet
+ * after it was done is software.
+ */
+#define MVPP2_TX_SEND_MAX_POLLING_COUNT 10000
+
+/* Structures */
+typedef struct {
+ /* Physical number of this Tx queue */
+ UINT8 Id;
+
+ /* Logical number of this Tx queue */
+ UINT8 LogId;
+
+ /* Number of Tx DMA descriptors in the descriptor ring */
+ INT32 Size;
+
+ /* Number of currently used Tx DMA descriptor in the descriptor ring */
+ INT32 count;
+
+ UINT32 DonePktsCoal;
+
+ /* Virtual address of thex Tx DMA descriptors array */
+ MVPP2_TX_DESC *Descs;
+
+ /* DMA address of the Tx DMA descriptors array */
+ DmaAddrT DescsPhys;
+
+ /* Index of the last Tx DMA descriptor */
+ INT32 LastDesc;
+
+ /* Index of the next Tx DMA descriptor to process */
+ INT32 NextDescToProc;
+} MVPP2_TX_QUEUE;
+
+typedef struct {
+ /* RX queue number, in the range 0-31 for physical RXQs */
+ UINT8 Id;
+
+ /* Num of rx descriptors in the rx descriptor ring */
+ INT32 Size;
+
+ UINT32 PktsCoal;
+ UINT32 TimeCoal;
+
+ /* Virtual address of the RX DMA descriptors array */
+ MVPP2_RX_DESC *Descs;
+
+ /* DMA address of the RX DMA descriptors array */
+ DmaAddrT DescsPhys;
+
+ /* Index of the last RX DMA descriptor */
+ INT32 LastDesc;
+
+ /* Index of the next RX DMA descriptor to process */
+ INT32 NextDescToProc;
+
+ /* ID of Port to which physical RXQ is mapped */
+ INT32 Port;
+
+ /* Port's logic RXQ number to which physical RXQ is mapped */
+ INT32 LogicRxq;
+} MVPP2_RX_QUEUE;
+
+enum Mvpp2BmType {
+ MVPP2_BM_FREE,
+ MVPP2_BM_SWF_LONG,
+ MVPP2_BM_SWF_SHORT
+};
+
+typedef struct {
+ /* Pool number in the range 0-7 */
+ INT32 Id;
+ enum Mvpp2BmType type;
+
+ /* Buffer Pointers Pool External (BPPE) Size */
+ INT32 Size;
+ /* Number of buffers for this pool */
+ INT32 BufNum;
+ /* Pool buffer Size */
+ INT32 BufSize;
+ /* Packet Size */
+ INT32 PktSize;
+
+ /* BPPE virtual base address */
+ UINT32 *VirtAddr;
+ /* BPPE physical base address */
+ DmaAddrT PhysAddr;
+
+ /* Ports using BM pool */
+ UINT32 PortMap;
+} MVPP2_BMS_POOL;
+
+typedef struct Pp2DxePort PP2DXE_PORT;
+
+/* Shared Packet Processor resources */
+typedef struct {
+ /* Shared registers' base addresses */
+ UINT64 Base;
+ UINT64 Rfu1Base;
+ UINT64 SmiBase;
+ VOID *LmsBase;
+
+ /* List of pointers to Port structures */
+ PP2DXE_PORT **PortList;
+
+ /* Aggregated TXQs */
+ MVPP2_TX_QUEUE *AggrTxqs;
+
+ /* BM pools */
+ MVPP2_BMS_POOL *BmPools;
+
+ /* PRS shadow table */
+ MVPP2_PRS_SHADOW *PrsShadow;
+ /* PRS auxiliary table for double vlan entries control */
+ BOOLEAN *PrsDoubleVlans;
+
+ /* Tclk value */
+ UINT32 Tclk;
+} MVPP2_SHARED;
+
+/* Individual Port structure */
+struct Pp2DxePort {
+ UINT8 Id;
+ UINT8 GopIndex;
+
+ INT32 Irq;
+
+ MVPP2_SHARED *Priv;
+
+ /* Per-Port registers' base address */
+ UINT64 GmacBase;
+ UINT64 XlgBase;
+
+ MVPP2_RX_QUEUE *Rxqs;
+ MVPP2_TX_QUEUE *Txqs;
+
+ INT32 PktSize;
+
+ UINT32 PendingCauseRx;
+
+ /* Flags */
+ UINTN Flags;
+
+ UINT16 TxRingSize;
+ UINT16 RxRingSize;
+
+ INT32 PhyInterface;
+ BOOLEAN Link;
+ BOOLEAN Duplex;
+ BOOLEAN AlwaysUp;
+ PHY_SPEED Speed;
+
+ MVPP2_BMS_POOL *PoolLong;
+ MVPP2_BMS_POOL *PoolShort;
+
+ UINT8 TxpNum;
+
+ /* Index of first Port's physical RXQ */
+ UINT8 FirstRxq;
+};
+
+/* Structure for preallocation for buffer */
+typedef struct {
+ MVPP2_TX_DESC *TxDescs;
+ MVPP2_TX_DESC *AggrTxDescs;
+ MVPP2_RX_DESC *RxDescs;
+ DmaAddrT RxBuffers;
+} BUFFER_LOCATION;
+
+typedef struct {
+ MAC_ADDR_DEVICE_PATH Pp2Mac;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} PP2_DEVICE_PATH;
+
+#define QUEUE_DEPTH 64
+typedef struct {
+ UINT32 Signature;
+ INTN Instance;
+ EFI_HANDLE Controller;
+ EFI_LOCK Lock;
+ EFI_SIMPLE_NETWORK_PROTOCOL Snp;
+ MARVELL_PHY_PROTOCOL *Phy;
+ PHY_DEVICE *PhyDev;
+ PP2DXE_PORT Port;
+ BOOLEAN Initialized;
+ BOOLEAN LateInitialized;
+ VOID *CompletionQueue[QUEUE_DEPTH];
+ UINTN CompletionQueueHead;
+ UINTN CompletionQueueTail;
+ EFI_EVENT EfiExitBootServicesEvent;
+ PP2_DEVICE_PATH *DevicePath;
+} PP2DXE_CONTEXT;
+
+/* Inline helpers */
+STATIC
+inline
+VOID
+Mvpp2Write (
+ IN MVPP2_SHARED *Priv,
+ IN UINT32 Offset,
+ IN UINT32 data
+ )
+{
+ ASSERT (Priv->Base != 0);
+ MmioWrite32 (Priv->Base + Offset, data);
+}
+
+STATIC
+inline
+UINT32
+Mvpp2Read (
+ IN MVPP2_SHARED *Priv,
+ IN UINT32 Offset
+ )
+{
+ ASSERT (Priv->Base != 0);
+ return MmioRead32 (Priv->Base + Offset);
+}
+
+STATIC
+inline
+UINT32
+Mvpp2Rfu1Read (
+ IN MVPP2_SHARED *Priv,
+ UINT32 Offset
+ )
+{
+ ASSERT (Priv->Rfu1Base != 0);
+ return MmioRead32 (Priv->Rfu1Base + Offset);
+}
+
+STATIC
+inline
+UINT32
+Mvpp2Rfu1Write (
+ IN MVPP2_SHARED *Priv,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ )
+{
+ ASSERT (Priv->Rfu1Base != 0);
+ return MmioWrite32 (Priv->Rfu1Base + Offset, Data);
+}
+
+STATIC
+inline
+UINT32
+Mvpp2SmiRead (
+ IN MVPP2_SHARED *Priv,
+ IN UINT32 Offset
+ )
+{
+ ASSERT (Priv->SmiBase != 0);
+ return MmioRead32 (Priv->SmiBase + Offset);
+}
+
+STATIC
+inline
+UINT32
+Mvpp2SmiWrite (
+ IN MVPP2_SHARED *Priv,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ )
+{
+ ASSERT (Priv->SmiBase != 0);
+ return MmioWrite32 (Priv->SmiBase + Offset, Data);
+}
+
+STATIC
+inline
+VOID
+Mvpp2GmacWrite (
+ IN PP2DXE_PORT *Port,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ )
+{
+ ASSERT (Port->Priv->Base != 0);
+ MmioWrite32 (Port->Priv->Base + Offset, Data);
+}
+
+STATIC
+inline
+UINT32
+Mvpp2GmacRead (
+ IN PP2DXE_PORT *Port,
+ IN UINT32 Offset
+ )
+{
+ ASSERT (Port->Priv->Base != 0);
+ return MmioRead32 (Port->Priv->Base + Offset);
+}
+
+STATIC
+inline
+VOID
+MvGop110GmacWrite (
+ IN PP2DXE_PORT *Port,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ )
+{
+ ASSERT (Port->GmacBase != 0);
+ MmioWrite32 (Port->GmacBase + Offset, Data);
+}
+
+STATIC
+inline
+UINT32
+MvGop110GmacRead (
+ IN PP2DXE_PORT *Port,
+ IN UINT32 Offset
+ )
+{
+ ASSERT (Port->GmacBase != 0);
+ return MmioRead32 (Port->GmacBase + Offset);
+}
+
+STATIC
+inline
+VOID
+Mvpp2XlgWrite (
+ IN PP2DXE_PORT *Port,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ )
+{
+ ASSERT (Port->XlgBase != 0);
+ MmioWrite32 (Port->XlgBase + Offset, Data);
+}
+
+STATIC
+inline
+UINT32
+Mvpp2XlgRead (
+ IN PP2DXE_PORT *Port,
+ IN UINT32 Offset
+ )
+{
+ ASSERT (Port->XlgBase != 0);
+ return MmioRead32 (Port->XlgBase + Offset);
+}
+
+/* SNP callbacks */
+EFI_STATUS
+EFIAPI
+Pp2SnpStart (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ );
+
+EFI_STATUS
+EFIAPI
+Pp2SnpStop (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ );
+
+EFI_STATUS
+EFIAPI
+Pp2DxeSnpInitialize (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINTN ExtraRxBufferSize OPTIONAL,
+ IN UINTN ExtraTxBufferSize OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+Pp2SnpReset (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+EFI_STATUS
+EFIAPI
+Pp2SnpShutdown (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ );
+
+EFI_STATUS
+EFIAPI
+Pp2SnpReceiveFilters (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINT32 Enable,
+ IN UINT32 Disable,
+ IN BOOLEAN ResetMCastFilter,
+ IN UINTN MCastFilterCnt OPTIONAL,
+ IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+Pp2SnpStationAddress (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,
+ IN BOOLEAN Reset,
+ IN EFI_MAC_ADDRESS *NewMac
+);
+
+EFI_STATUS
+EFIAPI
+Pp2SnpNetStat (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN Reset,
+ IN OUT UINTN *StatisticsSize OPTIONAL,
+ OUT EFI_NETWORK_STATISTICS *StatisticsTable OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+Pp2SnpIpToMac (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN IPv6,
+ IN EFI_IP_ADDRESS *IP,
+ OUT EFI_MAC_ADDRESS *MAC
+ );
+
+EFI_STATUS
+EFIAPI
+Pp2SnpGetStatus (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,
+ OUT UINT32 *InterruptStatus OPTIONAL,
+ OUT VOID **TxBuf OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+Pp2SnpTransmit (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINTN HeaderSize,
+ IN UINTN BufferSize,
+ IN VOID *Buffer,
+ IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
+ IN EFI_MAC_ADDRESS *DestAddr OPTIONAL,
+ IN UINT16 *EtherTypePtr OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+Pp2SnpReceive (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ OUT UINTN *HeaderSize OPTIONAL,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer,
+ OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
+ OUT EFI_MAC_ADDRESS *DstAddr OPTIONAL,
+ OUT UINT16 *EtherType OPTIONAL
+ );
+#endif
diff --git a/Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.inf b/Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.inf
new file mode 100644
index 0000000000..87cc5e8ded
--- /dev/null
+++ b/Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.inf
@@ -0,0 +1,91 @@
+# Copyright (C) 2016 Marvell International Ltd.
+#
+# Marvell BSD License Option
+#
+# If you received this File from Marvell, you may opt to use, redistribute and/or
+# modify this File under the following licensing terms.
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Marvell nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+[Defines]
+ INF_VERSION = 0x00010019
+ BASE_NAME = Pp2Dxe
+ FILE_GUID = 5ffc3843-d8d4-40ba-ae07-38967138509c
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = Pp2DxeInitialise
+
+[Sources.common]
+ Pp2Dxe.c
+ Mvpp2Lib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ ArmPlatformPkg/ArmPlatformPkg.dec
+ ArmPkg/ArmPkg.dec
+ Platform/Marvell/Marvell.dec
+
+[LibraryClasses]
+ IoLib
+ PcdLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ UefiLib
+ NetLib
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ UncachedMemoryAllocationLib
+ CacheMaintenanceLib
+
+[Protocols]
+ gEfiSimpleNetworkProtocolGuid
+ gEfiDevicePathProtocolGuid
+ gEfiCpuArchProtocolGuid
+ gMarvellMdioProtocolGuid
+ gMarvellPhyProtocolGuid
+
+[Pcd]
+ gMarvellTokenSpaceGuid.PcdPhyConnectionTypes
+ gMarvellTokenSpaceGuid.PcdPhySmiAddresses
+ gMarvellTokenSpaceGuid.PcdPp2ClockFrequency
+ gMarvellTokenSpaceGuid.PcdPp2GmacBaseAddress
+ gMarvellTokenSpaceGuid.PcdPp2GmacDevSize
+ gMarvellTokenSpaceGuid.PcdPp2GopIndexes
+ gMarvellTokenSpaceGuid.PcdPp2InterfaceAlwaysUp
+ gMarvellTokenSpaceGuid.PcdPp2InterfaceSpeed
+ gMarvellTokenSpaceGuid.PcdPp2NumPorts
+ gMarvellTokenSpaceGuid.PcdPp2PortIds
+ gMarvellTokenSpaceGuid.PcdPp2Rfu1BaseAddress
+ gMarvellTokenSpaceGuid.PcdPp2SharedAddress
+ gMarvellTokenSpaceGuid.PcdPp2SmiBaseAddress
+ gMarvellTokenSpaceGuid.PcdPp2XlgBaseAddress
+ gMarvellTokenSpaceGuid.PcdPp2XlgDevSize
+
+[Depex]
+ TRUE
diff --git a/Platform/Marvell/Drivers/SdMmc/XenonDxe/ComponentName.c b/Platform/Marvell/Drivers/SdMmc/XenonDxe/ComponentName.c
new file mode 100644
index 0000000000..3329929119
--- /dev/null
+++ b/Platform/Marvell/Drivers/SdMmc/XenonDxe/ComponentName.c
@@ -0,0 +1,211 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for SD/MMC host controller driver.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ 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 "SdMmcPciHcDxe.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gSdMmcPciHcComponentName = {
+ SdMmcPciHcComponentNameGetDriverName,
+ SdMmcPciHcComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSdMmcPciHcComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SdMmcPciHcComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SdMmcPciHcComponentNameGetControllerName,
+ "en"
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdMmcPciHcDriverNameTable[] = {
+ { "eng;en", L"Edkii Sd/Mmc Host Controller Driver" },
+ { NULL , NULL }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdMmcPciHcControllerNameTable[] = {
+ { "eng;en", L"Edkii Sd/Mmc Host Controller" },
+ { NULL , NULL }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPciHcComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mSdMmcPciHcDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gSdMmcPciHcComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPciHcComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle, OPTIONAL
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+
+ if (Language == NULL || ControllerName == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // This is a device driver, so ChildHandle must be NULL.
+ //
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Make sure this driver is currently managing ControllerHandle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gSdMmcPciHcDriverBinding.DriverBindingHandle,
+ &gEfiPciIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mSdMmcPciHcControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gSdMmcPciHcComponentName)
+ );
+}
diff --git a/Platform/Marvell/Drivers/SdMmc/XenonDxe/EmmcDevice.c b/Platform/Marvell/Drivers/SdMmc/XenonDxe/EmmcDevice.c
new file mode 100755
index 0000000000..3f73194da7
--- /dev/null
+++ b/Platform/Marvell/Drivers/SdMmc/XenonDxe/EmmcDevice.c
@@ -0,0 +1,1162 @@
+/** @file
+ This file provides some helper functions which are specific for EMMC device.
+
+ Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+ 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 "SdMmcPciHcDxe.h"
+
+/**
+ Send command GO_IDLE_STATE (CMD0 with argument of 0x00000000) to the device to
+ make it go to Idle State.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The EMMC device is reset correctly.
+ @retval Others The device reset fails.
+
+**/
+EFI_STATUS
+EmmcReset (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_GO_IDLE_STATE;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBc;
+ SdMmcCmdBlk.ResponseType = 0;
+ SdMmcCmdBlk.CommandArgument = 0;
+
+ gBS->Stall (1000);
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SEND_OP_COND to the EMMC device to get the data of the OCR register.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in, out] Argument On input, the argument of SEND_OP_COND is to send to the device.
+ On output, the argument is the value of OCR register.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcGetOcr (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN OUT UINT32 *Argument
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_OP_COND;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR3;
+ SdMmcCmdBlk.CommandArgument = *Argument;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ //
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
+ //
+ *Argument = SdMmcStatusBlk.Resp0;
+ }
+
+ return Status;
+}
+
+/**
+ Broadcast command ALL_SEND_CID to the bus to ask all the EMMC devices to send the
+ data of their CID registers.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcGetAllCid (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_ALL_SEND_CID;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
+ SdMmcCmdBlk.CommandArgument = 0;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SET_RELATIVE_ADDR to the EMMC device to assign a Relative device
+ Address (RCA).
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSetRca (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SET_RELATIVE_ADDR;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SEND_CSD to the EMMC device to get the data of the CSD register.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address of selected device.
+ @param[out] Csd The buffer to store the content of the CSD register.
+ Note the caller should ignore the lowest byte of this
+ buffer as the content of this byte is meaningless even
+ if the operation succeeds.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcGetCsd (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ OUT EMMC_CSD *Csd
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_CSD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ //
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
+ //
+ CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (EMMC_CSD) - 1);
+ }
+
+ return Status;
+}
+
+/**
+ Send command SELECT_DESELECT_CARD to the EMMC device to select/deselect it.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address of selected device.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSelect (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SELECT_DESELECT_CARD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SEND_EXT_CSD to the EMMC device to get the data of the EXT_CSD register.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[out] ExtCsd The buffer to store the content of the EXT_CSD register.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcGetExtCsd (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ OUT EMMC_EXT_CSD *ExtCsd
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_EXT_CSD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = 0x00000000;
+
+ Packet.InDataBuffer = ExtCsd;
+ Packet.InTransferLength = sizeof (EMMC_EXT_CSD);
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+ return Status;
+}
+
+/**
+ Send command SWITCH to the EMMC device to switch the mode of operation of the
+ selected Device or modifies the EXT_CSD registers.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Access The access mode of SWTICH command.
+ @param[in] Index The offset of the field to be access.
+ @param[in] Value The value to be set to the specified field of EXT_CSD register.
+ @param[in] CmdSet The value of CmdSet field of EXT_CSD register.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSwitch (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT8 Access,
+ IN UINT8 Index,
+ IN UINT8 Value,
+ IN UINT8 CmdSet
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SWITCH;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
+ SdMmcCmdBlk.CommandArgument = (Access << 24) | (Index << 16) | (Value << 8) | CmdSet;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SEND_STATUS to the addressed EMMC device to get its status register.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address of addressed device.
+ @param[out] DevStatus The returned device status.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSendStatus (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ OUT UINT32 *DevStatus
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_STATUS;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ *DevStatus = SdMmcStatusBlk.Resp0;
+ }
+
+ return Status;
+}
+
+/**
+ Send command SEND_TUNING_BLOCK to the EMMC device for HS200 optimal sampling point
+ detection.
+
+ It may be sent up to 40 times until the host finishes the tuning procedure.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] BusWidth The bus width to work.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSendTuningBlk (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT8 BusWidth
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+ UINT8 TuningBlock[128];
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_TUNING_BLOCK;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = 0;
+
+ Packet.InDataBuffer = TuningBlock;
+ if (BusWidth == 8) {
+ Packet.InTransferLength = sizeof (TuningBlock);
+ } else {
+ Packet.InTransferLength = 64;
+ }
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Tunning the clock to get HS200 optimal sampling point.
+
+ Command SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes the
+ tuning procedure.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller
+ Simplified Spec 3.0 Figure 2-29 for details.
+
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] BusWidth The bus width to work.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcTuningClkForHs200 (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT8 BusWidth
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HostCtrl2;
+ UINT8 Retry;
+
+ //
+ // Notify the host that the sampling clock tuning procedure starts.
+ //
+ HostCtrl2 = BIT6;
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Ask the device to send a sequence of tuning blocks till the tuning procedure is done.
+ //
+ Retry = 0;
+ do {
+ Status = EmmcSendTuningBlk (PassThru, Slot, BusWidth);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcTuningClkForHs200: Send tuning block fails with %r\n", Status));
+ return Status;
+ }
+
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((HostCtrl2 & (BIT6 | BIT7)) == 0) {
+ break;
+ }
+
+ if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {
+ return EFI_SUCCESS;
+ }
+ } while (++Retry < 40);
+
+ DEBUG ((DEBUG_ERROR, "EmmcTuningClkForHs200: Send tuning block fails at %d times with HostCtrl2 %02x\n", Retry, HostCtrl2));
+ //
+ // Abort the tuning procedure and reset the tuning circuit.
+ //
+ HostCtrl2 = (UINT8)~(BIT6 | BIT7);
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+ Switch the bus width to specified width.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.9 and SD Host Controller
+ Simplified Spec 3.0 Figure 3-7 for details.
+
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] IsDdr If TRUE, use dual data rate data simpling method. Otherwise
+ use single data rate data simpling method.
+ @param[in] BusWidth The bus width to be set, it could be 4 or 8.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSwitchBusWidth (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ IN BOOLEAN IsDdr,
+ IN UINT8 BusWidth
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Access;
+ UINT8 Index;
+ UINT8 Value;
+ UINT8 CmdSet;
+ UINT32 DevStatus;
+
+ //
+ // Write Byte, the Value field is written into the byte pointed by Index.
+ //
+ Access = 0x03;
+ Index = OFFSET_OF (EMMC_EXT_CSD, BusWidth);
+ if (BusWidth == 4) {
+ Value = 1;
+ } else if (BusWidth == 8) {
+ Value = 2;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IsDdr) {
+ Value += 4;
+ }
+
+ CmdSet = 0;
+ Status = EmmcSwitch (PassThru, Slot, Access, Index, Value, CmdSet);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcSwitchBusWidth: Switch to bus width %d fails with %r\n", BusWidth, Status));
+ return Status;
+ }
+
+ Status = EmmcSendStatus (PassThru, Slot, Rca, &DevStatus);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcSwitchBusWidth: Send status fails with %r\n", Status));
+ return Status;
+ }
+ //
+ // Check the switch operation is really successful or not.
+ //
+ if ((DevStatus & BIT7) != 0) {
+ DEBUG ((DEBUG_ERROR, "EmmcSwitchBusWidth: The switch operation fails as DevStatus is 0x%08x\n", DevStatus));
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = SdMmcHcSetBusWidth (PciIo, Slot, BusWidth);
+
+ return Status;
+}
+
+/**
+ Switch the clock frequency to the specified value.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6 and SD Host Controller
+ Simplified Spec 3.0 Figure 3-3 for details.
+
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] HsTiming The value to be written to HS_TIMING field of EXT_CSD register.
+ @param[in] ClockFreq The max clock frequency to be set, the unit is MHz.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSwitchClockFreq (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ IN UINT8 HsTiming,
+ IN UINT32 ClockFreq
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Access;
+ UINT8 Index;
+ UINT8 Value;
+ UINT8 CmdSet;
+ UINT32 DevStatus;
+ SD_MMC_HC_PRIVATE_DATA *Private;
+
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
+ //
+ // Write Byte, the Value field is written into the byte pointed by Index.
+ //
+ Access = 0x03;
+ Index = OFFSET_OF (EMMC_EXT_CSD, HsTiming);
+ Value = HsTiming;
+ CmdSet = 0;
+
+ Status = EmmcSwitch (PassThru, Slot, Access, Index, Value, CmdSet);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcSwitchClockFreq: Switch to hstiming %d fails with %r\n", HsTiming, Status));
+ return Status;
+ }
+
+ Status = EmmcSendStatus (PassThru, Slot, Rca, &DevStatus);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcSwitchClockFreq: Send status fails with %r\n", Status));
+ return Status;
+ }
+ //
+ // Check the switch operation is really successful or not.
+ //
+ if ((DevStatus & BIT7) != 0) {
+ DEBUG ((DEBUG_ERROR, "EmmcSwitchClockFreq: The switch operation fails as DevStatus is 0x%08x\n", DevStatus));
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Convert the clock freq unit from MHz to KHz.
+ //
+ Status = SdMmcHcClockSupply (PciIo, Slot, ClockFreq * 1000, Private->Capability[Slot]);
+
+ return Status;
+}
+
+/**
+ Switch to the High Speed timing according to request.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller
+ Simplified Spec 3.0 Figure 2-29 for details.
+
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] ClockFreq The max clock frequency to be set.
+ @param[in] IsDdr If TRUE, use dual data rate data simpling method. Otherwise
+ use single data rate data simpling method.
+ @param[in] BusWidth The bus width to be set, it could be 4 or 8.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSwitchToHighSpeed (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ IN UINT32 ClockFreq,
+ IN BOOLEAN IsDdr,
+ IN UINT8 BusWidth
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HsTiming;
+ UINT8 HostCtrl1;
+ UINT8 HostCtrl2;
+
+ Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, IsDdr, BusWidth);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Set to Hight Speed timing
+ //
+ HostCtrl1 = BIT2;
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Clean UHS Mode Select field of Host Control 2 reigster before update
+ //
+ HostCtrl2 = (UINT8)~0x7;
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Set UHS Mode Select field of Host Control 2 reigster to SDR12/25/50
+ //
+ if (IsDdr) {
+ HostCtrl2 = BIT2;
+ } else if (ClockFreq == 52) {
+ HostCtrl2 = BIT0;
+ } else {
+ HostCtrl2 = 0;
+ }
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ HsTiming = 1;
+ Status = EmmcSwitchClockFreq (PciIo, PassThru, Slot, Rca, HsTiming, ClockFreq);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return Status;
+}
+
+/**
+ Switch to the HS200 timing according to request.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller
+ Simplified Spec 3.0 Figure 2-29 for details.
+
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] ClockFreq The max clock frequency to be set.
+ @param[in] BusWidth The bus width to be set, it could be 4 or 8.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSwitchToHS200 (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ IN UINT32 ClockFreq,
+ IN UINT8 BusWidth
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HsTiming;
+ UINT8 HostCtrl2;
+ UINT16 ClockCtrl;
+
+ if ((BusWidth != 4) && (BusWidth != 8)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, FALSE, BusWidth);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Set to HS200/SDR104 timing
+ //
+ //
+ // Stop bus clock at first
+ //
+ Status = SdMmcHcStopClock (PciIo, Slot);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Clean UHS Mode Select field of Host Control 2 reigster before update
+ //
+ HostCtrl2 = (UINT8)~0x7;
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Set UHS Mode Select field of Host Control 2 reigster to SDR104
+ //
+ HostCtrl2 = BIT0 | BIT1;
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Wait Internal Clock Stable in the Clock Control register to be 1 before set SD Clock Enable bit
+ //
+ Status = SdMmcHcWaitMmioSet (
+ PciIo,
+ Slot,
+ SD_MMC_HC_CLOCK_CTRL,
+ sizeof (ClockCtrl),
+ BIT1,
+ BIT1,
+ SD_MMC_HC_GENERIC_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Set SD Clock Enable in the Clock Control register to 1
+ //
+ ClockCtrl = BIT2;
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);
+
+ HsTiming = 2;
+ Status = EmmcSwitchClockFreq (PciIo, PassThru, Slot, Rca, HsTiming, ClockFreq);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EmmcTuningClkForHs200 (PciIo, PassThru, Slot, BusWidth);
+
+ return Status;
+}
+
+/**
+ Switch to the HS400 timing according to request.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller
+ Simplified Spec 3.0 Figure 2-29 for details.
+
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] ClockFreq The max clock frequency to be set.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSwitchToHS400 (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ IN UINT32 ClockFreq
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HsTiming;
+ UINT8 HostCtrl2;
+
+ Status = EmmcSwitchToHS200 (PciIo, PassThru, Slot, Rca, ClockFreq, 8);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Set to Hight Speed timing and set the clock frequency to a value less than 52MHz.
+ //
+ HsTiming = 1;
+ Status = EmmcSwitchClockFreq (PciIo, PassThru, Slot, Rca, HsTiming, 52);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // HS400 mode must use 8 data lines.
+ //
+ Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, TRUE, 8);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Clean UHS Mode Select field of Host Control 2 reigster before update
+ //
+ HostCtrl2 = (UINT8)~0x7;
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Set UHS Mode Select field of Host Control 2 reigster to HS400
+ //
+ HostCtrl2 = BIT0 | BIT2;
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ HsTiming = 3;
+ Status = EmmcSwitchClockFreq (PciIo, PassThru, Slot, Rca, HsTiming, ClockFreq);
+
+ return Status;
+}
+
+/**
+ Switch the high speed timing according to request.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller
+ Simplified Spec 3.0 Figure 2-29 for details.
+
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSetBusMode (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca
+ )
+{
+ EFI_STATUS Status;
+ EMMC_CSD Csd;
+ EMMC_EXT_CSD ExtCsd;
+ UINT8 HsTiming;
+ BOOLEAN IsDdr;
+ UINT32 ClockFreq;
+ UINT8 BusWidth;
+ SD_MMC_HC_PRIVATE_DATA *Private;
+
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
+
+ Status = EmmcGetCsd (PassThru, Slot, Rca, &Csd);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: GetCsd fails with %r\n", Status));
+ return Status;
+ }
+
+ Status = EmmcSelect (PassThru, Slot, Rca);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: Select fails with %r\n", Status));
+ return Status;
+ }
+
+ ASSERT (Private->Capability[Slot].BaseClkFreq != 0);
+ //
+ // Check if the Host Controller support 8bits bus width.
+ //
+ if (Private->Capability[Slot].BusWidth8 != 0) {
+ BusWidth = 8;
+ } else {
+ BusWidth = 4;
+ }
+ //
+ // Get Deivce_Type from EXT_CSD register.
+ //
+ Status = EmmcGetExtCsd (PassThru, Slot, &ExtCsd);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: GetExtCsd fails with %r\n", Status));
+ return Status;
+ }
+ //
+ // Calculate supported bus speed/bus width/clock frequency.
+ //
+ HsTiming = 0;
+ IsDdr = FALSE;
+ ClockFreq = 0;
+ if (((ExtCsd.DeviceType & (BIT4 | BIT5)) != 0) && (Private->Capability[Slot].Sdr104 != 0)) {
+ HsTiming = 2;
+ IsDdr = FALSE;
+ ClockFreq = 200;
+ } else if (((ExtCsd.DeviceType & (BIT2 | BIT3)) != 0) && (Private->Capability[Slot].Ddr50 != 0)) {
+ HsTiming = 1;
+ IsDdr = TRUE;
+ ClockFreq = 52;
+ } else if (((ExtCsd.DeviceType & BIT1) != 0) && (Private->Capability[Slot].HighSpeed != 0)) {
+ HsTiming = 1;
+ IsDdr = FALSE;
+ ClockFreq = 52;
+ } else if (((ExtCsd.DeviceType & BIT0) != 0) && (Private->Capability[Slot].HighSpeed != 0)) {
+ HsTiming = 1;
+ IsDdr = FALSE;
+ ClockFreq = 26;
+ }
+ //
+ // Check if both of the device and the host controller support HS400 DDR mode.
+ //
+ if (((ExtCsd.DeviceType & (BIT6 | BIT7)) != 0) && (Private->Capability[Slot].Hs400 != 0)) {
+ //
+ // The host controller supports 8bits bus.
+ //
+ ASSERT (BusWidth == 8);
+ HsTiming = 3;
+ IsDdr = TRUE;
+ ClockFreq = 200;
+ }
+
+ if ((ClockFreq == 0) || (HsTiming == 0)) {
+ //
+ // Continue using default setting.
+ //
+ return EFI_SUCCESS;
+ }
+
+ DEBUG ((DEBUG_INFO, "EmmcSetBusMode: HsTiming %d ClockFreq %d BusWidth %d Ddr %a\n", HsTiming, ClockFreq, BusWidth, IsDdr ? "TRUE":"FALSE"));
+
+ if (HsTiming == 3) {
+ //
+ // Execute HS400 timing switch procedure
+ //
+ Status = EmmcSwitchToHS400 (PciIo, PassThru, Slot, Rca, ClockFreq);
+ } else if (HsTiming == 2) {
+ //
+ // Execute HS200 timing switch procedure
+ //
+ Status = EmmcSwitchToHS200 (PciIo, PassThru, Slot, Rca, ClockFreq, BusWidth);
+ } else {
+ //
+ // Execute High Speed timing switch procedure
+ //
+ Status = EmmcSwitchToHighSpeed (PciIo, PassThru, Slot, Rca, ClockFreq, IsDdr, BusWidth);
+ }
+
+ DEBUG ((DEBUG_INFO, "EmmcSetBusMode: Switch to %a %r\n", (HsTiming == 3) ? "HS400" : ((HsTiming == 2) ? "HS200" : "HighSpeed"), Status));
+
+ return Status;
+}
+
+/**
+ Execute EMMC device identification procedure.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS There is a EMMC card.
+ @retval Others There is not a EMMC card.
+
+**/
+EFI_STATUS
+EmmcIdentification (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ UINT32 Ocr;
+ UINT16 Rca;
+
+ PciIo = Private->PciIo;
+ PassThru = &Private->PassThru;
+
+ Status = EmmcReset (PassThru, Slot);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_VERBOSE, "EmmcIdentification: Executing Cmd0 fails with %r\n", Status));
+ return Status;
+ }
+
+ Ocr = 0;
+ do {
+ Status = EmmcGetOcr (PassThru, Slot, &Ocr);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_VERBOSE, "EmmcIdentification: Executing Cmd1 fails with %r\n", Status));
+ return Status;
+ }
+ Ocr |= BIT30;
+ } while ((Ocr & BIT31) == 0);
+
+ Status = EmmcGetAllCid (PassThru, Slot);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_VERBOSE, "EmmcIdentification: Executing Cmd2 fails with %r\n", Status));
+ return Status;
+ }
+ //
+ // Slot starts from 0 and valid RCA starts from 1.
+ // Here we takes a simple formula to calculate the RCA.
+ // Don't support multiple devices on the slot, that is
+ // shared bus slot feature.
+ //
+ Rca = Slot + 1;
+ Status = EmmcSetRca (PassThru, Slot, Rca);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcIdentification: Executing Cmd3 fails with %r\n", Status));
+ return Status;
+ }
+ //
+ // Enter Data Tranfer Mode.
+ //
+ DEBUG ((DEBUG_INFO, "EmmcIdentification: Found a EMMC device at slot [%d], RCA [%d]\n", Slot, Rca));
+ Private->Slot[Slot].CardType = EmmcCardType;
+
+ Status = EmmcSetBusMode (PciIo, PassThru, Slot, Rca);
+
+ return Status;
+}
+
diff --git a/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdDevice.c b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdDevice.c
new file mode 100644
index 0000000000..9122848021
--- /dev/null
+++ b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdDevice.c
@@ -0,0 +1,1190 @@
+/** @file
+ This file provides some helper functions which are specific for SD card device.
+
+ Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+ 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 "SdMmcPciHcDxe.h"
+
+/**
+ Send command GO_IDLE_STATE to the device to make it go to Idle State.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The SD device is reset correctly.
+ @retval Others The device reset fails.
+
+**/
+EFI_STATUS
+SdCardReset (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_GO_IDLE_STATE;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBc;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SEND_IF_COND to the device to inquiry the SD Memory Card interface
+ condition.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] SupplyVoltage The supplied voltage by the host.
+ @param[in] CheckPattern The check pattern to be sent to the device.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardVoltageCheck (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT8 SupplyVoltage,
+ IN UINT8 CheckPattern
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SEND_IF_COND;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR7;
+ SdMmcCmdBlk.CommandArgument = (SupplyVoltage << 8) | CheckPattern;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ if (!EFI_ERROR (Status)) {
+ if (SdMmcStatusBlk.Resp0 != SdMmcCmdBlk.CommandArgument) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Send command SDIO_SEND_OP_COND to the device to see whether it is SDIO device.
+
+ Refer to SDIO Simplified Spec 3 Section 3.2 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] VoltageWindow The supply voltage window.
+ @param[in] S18R The boolean to show if it should switch to 1.8v.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdioSendOpCond (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT32 VoltageWindow,
+ IN BOOLEAN S18R
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+ UINT32 Switch;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SDIO_SEND_OP_COND;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR4;
+
+ Switch = S18R ? BIT24 : 0;
+
+ SdMmcCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SD_SEND_OP_COND to the device to see whether it is SDIO device.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address of addressed device.
+ @param[in] VoltageWindow The supply voltage window.
+ @param[in] S18R The boolean to show if it should switch to 1.8v.
+ @param[in] Xpc The boolean to show if it should provide 0.36w power control.
+ @param[in] Hcs The boolean to show if it support host capacity info.
+ @param[out] Ocr The buffer to store returned OCR register value.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSendOpCond (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ IN UINT32 VoltageWindow,
+ IN BOOLEAN S18R,
+ IN BOOLEAN Xpc,
+ IN BOOLEAN Hcs,
+ OUT UINT32 *Ocr
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+ UINT32 Switch;
+ UINT32 MaxPower;
+ UINT32 HostCapacity;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_APP_CMD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ SdMmcCmdBlk.CommandIndex = SD_SEND_OP_COND;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR3;
+
+ Switch = S18R ? BIT24 : 0;
+ MaxPower = Xpc ? BIT28 : 0;
+ HostCapacity = Hcs ? BIT30 : 0;
+
+ SdMmcCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch | MaxPower | HostCapacity;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ //
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
+ //
+ *Ocr = SdMmcStatusBlk.Resp0;
+ }
+
+ return Status;
+}
+
+/**
+ Broadcast command ALL_SEND_CID to the bus to ask all the SD devices to send the
+ data of their CID registers.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardAllSendCid (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_ALL_SEND_CID;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SET_RELATIVE_ADDR to the SD device to assign a Relative device
+ Address (RCA).
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[out] Rca The relative device address to assign.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSetRca (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ OUT UINT16 *Rca
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR6;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ *Rca = (UINT16)(SdMmcStatusBlk.Resp0 >> 16);
+ }
+
+ return Status;
+}
+
+/**
+ Send command SEND_CSD to the SD device to get the data of the CSD register.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address of selected device.
+ @param[out] Csd The buffer to store the content of the CSD register.
+ Note the caller should ignore the lowest byte of this
+ buffer as the content of this byte is meaningless even
+ if the operation succeeds.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardGetCsd (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ OUT SD_CSD *Csd
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SEND_CSD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ //
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
+ //
+ CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CSD) - 1);
+ }
+
+ return Status;
+}
+
+/**
+ Send command SEND_CSD to the SD device to get the data of the CSD register.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address of selected device.
+ @param[out] Scr The buffer to store the content of the SCR register.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardGetScr (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ OUT SD_SCR *Scr
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_APP_CMD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ SdMmcCmdBlk.CommandIndex = SD_SEND_SCR;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+
+ Packet.InDataBuffer = Scr;
+ Packet.InTransferLength = sizeof (SD_SCR);
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SELECT_DESELECT_CARD to the SD device to select/deselect it.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address of selected device.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSelect (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ if (Rca != 0) {
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
+ }
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command VOLTAGE_SWITCH to the SD device to switch the voltage of the device.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardVoltageSwitch (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_VOLTAGE_SWITCH;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = 0;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SET_BUS_WIDTH to the SD device to set the bus width.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address of addressed device.
+ @param[in] BusWidth The bus width to be set, it could be 1 or 4.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSetBusWidth (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ IN UINT8 BusWidth
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+ UINT8 Value;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_APP_CMD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ SdMmcCmdBlk.CommandIndex = SD_SET_BUS_WIDTH;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+
+ if (BusWidth == 1) {
+ Value = 0;
+ } else if (BusWidth == 4) {
+ Value = 2;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SdMmcCmdBlk.CommandArgument = Value & 0x3;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+ return Status;
+}
+
+/**
+ Send command SWITCH_FUNC to the SD device to check switchable function or switch card function.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] AccessMode The value for access mode group.
+ @param[in] CommandSystem The value for command set group.
+ @param[in] DriveStrength The value for drive length group.
+ @param[in] PowerLimit The value for power limit group.
+ @param[in] Mode Switch or check function.
+ @param[out] SwitchResp The return switch function status.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSwitch (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT8 AccessMode,
+ IN UINT8 CommandSystem,
+ IN UINT8 DriveStrength,
+ IN UINT8 PowerLimit,
+ IN BOOLEAN Mode,
+ OUT UINT8 *SwitchResp
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+ UINT32 ModeValue;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SWITCH_FUNC;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+
+ ModeValue = Mode ? BIT31 : 0;
+ SdMmcCmdBlk.CommandArgument = (AccessMode & 0xF) | ((PowerLimit & 0xF) << 4) | \
+ ((DriveStrength & 0xF) << 8) | ((DriveStrength & 0xF) << 12) | \
+ ModeValue;
+
+ Packet.InDataBuffer = SwitchResp;
+ Packet.InTransferLength = 64;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SEND_STATUS to the addressed SD device to get its status register.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address of addressed device.
+ @param[out] DevStatus The returned device status.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSendStatus (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ OUT UINT32 *DevStatus
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SEND_STATUS;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ *DevStatus = SdMmcStatusBlk.Resp0;
+ }
+
+ return Status;
+}
+
+/**
+ Send command SEND_TUNING_BLOCK to the SD device for HS200 optimal sampling point
+ detection.
+
+ It may be sent up to 40 times until the host finishes the tuning procedure.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSendTuningBlk (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+ UINT8 TuningBlock[64];
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SEND_TUNING_BLOCK;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = 0;
+
+ Packet.InDataBuffer = TuningBlock;
+ Packet.InTransferLength = sizeof (TuningBlock);
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Tunning the sampling point of SDR104 or SDR50 bus speed mode.
+
+ Command SD_SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes the
+ tuning procedure.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and
+ SD Host Controller Simplified Spec 3.0 section Figure 3-7 for details.
+
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardTuningClock (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HostCtrl2;
+ UINT8 Retry;
+
+ //
+ // Notify the host that the sampling clock tuning procedure starts.
+ //
+ HostCtrl2 = BIT6;
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Ask the device to send a sequence of tuning blocks till the tuning procedure is done.
+ //
+ Retry = 0;
+ do {
+ Status = SdCardSendTuningBlk (PassThru, Slot);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "SdCardSendTuningBlk: Send tuning block fails with %r\n", Status));
+ return Status;
+ }
+
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((HostCtrl2 & (BIT6 | BIT7)) == 0) {
+ break;
+ }
+ if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {
+ return EFI_SUCCESS;
+ }
+ } while (++Retry < 40);
+
+ DEBUG ((DEBUG_ERROR, "SdCardTuningClock: Send tuning block fails at %d times with HostCtrl2 %02x\n", Retry, HostCtrl2));
+ //
+ // Abort the tuning procedure and reset the tuning circuit.
+ //
+ HostCtrl2 = (UINT8)~(BIT6 | BIT7);
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+ Switch the bus width to specified width.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and
+ SD Host Controller Simplified Spec 3.0 section Figure 3-7 for details.
+
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] BusWidth The bus width to be set, it could be 4 or 8.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSwitchBusWidth (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ IN UINT8 BusWidth
+ )
+{
+ EFI_STATUS Status;
+ UINT32 DevStatus;
+
+ Status = SdCardSetBusWidth (PassThru, Slot, Rca, BusWidth);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "SdCardSwitchBusWidth: Switch to bus width %d fails with %r\n", BusWidth, Status));
+ return Status;
+ }
+
+ Status = SdCardSendStatus (PassThru, Slot, Rca, &DevStatus);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "SdCardSwitchBusWidth: Send status fails with %r\n", Status));
+ return Status;
+ }
+ //
+ // Check the switch operation is really successful or not.
+ //
+ if ((DevStatus >> 16) != 0) {
+ DEBUG ((DEBUG_ERROR, "SdCardSwitchBusWidth: The switch operation fails as DevStatus is 0x%08x\n", DevStatus));
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = SdMmcHcSetBusWidth (PciIo, Slot, BusWidth);
+
+ return Status;
+}
+
+/**
+ Switch the high speed timing according to request.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and
+ SD Host Controller Simplified Spec 3.0 section Figure 2-29 for details.
+
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] S18A The boolean to show if it's a UHS-I SD card.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSetBusMode (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ IN BOOLEAN S18A
+ )
+{
+ EFI_STATUS Status;
+ SD_MMC_HC_SLOT_CAP *Capability;
+ UINT32 ClockFreq;
+ UINT8 BusWidth;
+ UINT8 AccessMode;
+ UINT8 HostCtrl1;
+ UINT8 HostCtrl2;
+ UINT8 SwitchResp[64];
+ SD_MMC_HC_PRIVATE_DATA *Private;
+
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
+
+ Capability = &Private->Capability[Slot];
+
+ Status = SdCardSelect (PassThru, Slot, Rca);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BusWidth = 4;
+
+ Status = SdCardSwitchBusWidth (PciIo, PassThru, Slot, Rca, BusWidth);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Get the supported bus speed from SWITCH cmd return data group #1.
+ //
+ Status = SdCardSwitch (PassThru, Slot, 0xF, 0xF, 0xF, 0xF, FALSE, SwitchResp);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Calculate supported bus speed/bus width/clock frequency by host and device capability.
+ //
+ ClockFreq = 0;
+ if (S18A && (Capability->Sdr104 != 0) && ((SwitchResp[13] & BIT3) != 0)) {
+ ClockFreq = 208;
+ AccessMode = 3;
+ } else if (S18A && (Capability->Sdr50 != 0) && ((SwitchResp[13] & BIT2) != 0)) {
+ ClockFreq = 100;
+ AccessMode = 2;
+ } else if (S18A && (Capability->Ddr50 != 0) && ((SwitchResp[13] & BIT4) != 0)) {
+ ClockFreq = 50;
+ AccessMode = 4;
+ } else if ((SwitchResp[13] & BIT1) != 0) {
+ ClockFreq = 50;
+ AccessMode = 1;
+ } else {
+ ClockFreq = 25;
+ AccessMode = 0;
+ }
+
+ Status = SdCardSwitch (PassThru, Slot, AccessMode, 0xF, 0xF, 0xF, TRUE, SwitchResp);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((SwitchResp[16] & 0xF) != AccessMode) {
+ DEBUG ((DEBUG_ERROR, "SdCardSetBusMode: Switch to AccessMode %d ClockFreq %d BusWidth %d fails! The Switch response is 0x%1x\n", AccessMode, ClockFreq, BusWidth, SwitchResp[16] & 0xF));
+ return EFI_DEVICE_ERROR;
+ }
+
+ DEBUG ((DEBUG_INFO, "SdCardSetBusMode: Switch to AccessMode %d ClockFreq %d BusWidth %d\n", AccessMode, ClockFreq, BusWidth));
+
+ //
+ // Set to Hight Speed timing
+ //
+ if (AccessMode == 1) {
+ HostCtrl1 = BIT2;
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ HostCtrl2 = (UINT8)~0x7;
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ HostCtrl2 = AccessMode;
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdMmcHcClockSupply (PciIo, Slot, ClockFreq * 1000, *Capability);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((AccessMode == 3) || ((AccessMode == 2) && (Capability->TuningSDR50 != 0))) {
+ Status = SdCardTuningClock (PciIo, PassThru, Slot);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Execute SD device identification procedure.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 3.6 for details.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS There is a SD card.
+ @retval Others There is not a SD card.
+
+**/
+EFI_STATUS
+SdCardIdentification (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ UINT32 Ocr;
+ UINT16 Rca;
+ BOOLEAN Xpc;
+ BOOLEAN S18r;
+ UINT64 MaxCurrent;
+ UINT16 ControllerVer;
+ UINT8 PowerCtrl;
+ UINT32 PresentState;
+ UINT8 HostCtrl2;
+
+ PciIo = Private->PciIo;
+ PassThru = &Private->PassThru;
+ //
+ // 1. Send Cmd0 to the device
+ //
+ Status = SdCardReset (PassThru, Slot);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "SdCardIdentification: Executing Cmd0 fails with %r\n", Status));
+ return Status;
+ }
+ //
+ // 2. Send Cmd8 to the device
+ //
+ Status = SdCardVoltageCheck (PassThru, Slot, 0x1, 0xFF);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "SdCardIdentification: Executing Cmd8 fails with %r\n", Status));
+ return Status;
+ }
+ //
+ // 3. Send SDIO Cmd5 to the device to the SDIO device OCR register.
+ //
+ Status = SdioSendOpCond (PassThru, Slot, 0, FALSE);
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "SdCardIdentification: Found SDIO device, ignore it as we don't support\n"));
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // 4. Send Acmd41 with voltage window 0 to the device
+ //
+ Status = SdCardSendOpCond (PassThru, Slot, 0, 0, FALSE, FALSE, FALSE, &Ocr);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "SdCardIdentification: Executing SdCardSendOpCond fails with %r\n", Status));
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (Private->Capability[Slot].Voltage33 != 0) {
+ //
+ // Support 3.3V
+ //
+ MaxCurrent = ((UINT32)Private->MaxCurrent[Slot] & 0xFF) * 4;
+ } else if (Private->Capability[Slot].Voltage30 != 0) {
+ //
+ // Support 3.0V
+ //
+ MaxCurrent = (((UINT32)Private->MaxCurrent[Slot] >> 8) & 0xFF) * 4;
+ } else if (Private->Capability[Slot].Voltage18 != 0) {
+ //
+ // Support 1.8V
+ //
+ MaxCurrent = (((UINT32)Private->MaxCurrent[Slot] >> 16) & 0xFF) * 4;
+ } else {
+ ASSERT (FALSE);
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (MaxCurrent >= 150) {
+ Xpc = TRUE;
+ } else {
+ Xpc = FALSE;
+ }
+
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((ControllerVer & 0xFF) == 2) {
+ S18r = TRUE;
+ } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) {
+ S18r = FALSE;
+ } else {
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // 5. Repeatly send Acmd41 with supply voltage window to the device.
+ // Note here we only support the cards complied with SD physical
+ // layer simplified spec version 2.0 and version 3.0 and above.
+ //
+ do {
+ Status = SdCardSendOpCond (PassThru, Slot, 0, Ocr, S18r, Xpc, TRUE, &Ocr);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "SdCardIdentification: SdCardSendOpCond fails with %r Ocr %x, S18r %x, Xpc %x\n", Status, Ocr, S18r, Xpc));
+ return EFI_DEVICE_ERROR;
+ }
+ } while ((Ocr & BIT31) == 0);
+
+ //
+ // 6. If the S18A bit is set and the Host Controller supports 1.8V signaling
+ // (One of support bits is set to 1: SDR50, SDR104 or DDR50 in the
+ // Capabilities register), switch its voltage to 1.8V.
+ //
+ if ((Private->Capability[Slot].Sdr50 != 0 ||
+ Private->Capability[Slot].Sdr104 != 0 ||
+ Private->Capability[Slot].Ddr50 != 0) &&
+ ((Ocr & BIT24) != 0)) {
+ Status = SdCardVoltageSwitch (PassThru, Slot);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "SdCardIdentification: Executing SdCardVoltageSwitch fails with %r\n", Status));
+ Status = EFI_DEVICE_ERROR;
+ goto Error;
+ } else {
+ Status = SdMmcHcStopClock (PciIo, Slot);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Error;
+ }
+
+ SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);
+ if (((PresentState >> 20) & 0xF) != 0) {
+ DEBUG ((DEBUG_ERROR, "SdCardIdentification: SwitchVoltage fails with PresentState = 0x%x\n", PresentState));
+ Status = EFI_DEVICE_ERROR;
+ goto Error;
+ }
+ HostCtrl2 = BIT3;
+ SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+
+ gBS->Stall (5000);
+
+ SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);
+ if ((HostCtrl2 & BIT3) == 0) {
+ DEBUG ((DEBUG_ERROR, "SdCardIdentification: SwitchVoltage fails with HostCtrl2 = 0x%x\n", HostCtrl2));
+ Status = EFI_DEVICE_ERROR;
+ goto Error;
+ }
+
+ SdMmcHcInitClockFreq (PciIo, Slot, Private->Capability[Slot]);
+
+ gBS->Stall (1000);
+
+ SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);
+ if (((PresentState >> 20) & 0xF) != 0xF) {
+ DEBUG ((DEBUG_ERROR, "SdCardIdentification: SwitchVoltage fails with PresentState = 0x%x, It should be 0xF\n", PresentState));
+ Status = EFI_DEVICE_ERROR;
+ goto Error;
+ }
+ }
+ DEBUG ((DEBUG_INFO, "SdCardIdentification: Switch to 1.8v signal voltage success\n"));
+ }
+
+ Status = SdCardAllSendCid (PassThru, Slot);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "SdCardIdentification: Executing SdCardAllSendCid fails with %r\n", Status));
+ return Status;
+ }
+
+ Status = SdCardSetRca (PassThru, Slot, &Rca);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "SdCardIdentification: Executing SdCardSetRca fails with %r\n", Status));
+ return Status;
+ }
+ //
+ // Enter Data Tranfer Mode.
+ //
+ DEBUG ((DEBUG_INFO, "SdCardIdentification: Found a SD device at slot [%d]\n", Slot));
+ Private->Slot[Slot].CardType = SdCardType;
+
+ Status = SdCardSetBusMode (PciIo, PassThru, Slot, Rca, ((Ocr & BIT24) != 0));
+
+ return Status;
+
+Error:
+ //
+ // Set SD Bus Power = 0
+ //
+ PowerCtrl = (UINT8)~BIT0;
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_POWER_CTRL, sizeof (PowerCtrl), &PowerCtrl);
+ return EFI_DEVICE_ERROR;
+}
+
diff --git a/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.c b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.c
new file mode 100644
index 0000000000..981eab58ec
--- /dev/null
+++ b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.c
@@ -0,0 +1,1315 @@
+/** @file
+ This driver is used to manage SD/MMC PCI host controllers which are compliance
+ with SD Host Controller Simplified Specification version 3.00.
+
+ It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use.
+
+ Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+ Copyright (C) 2016 Marvell International Ltd. All rigths reserved.<BR>
+
+ 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 "SdMmcPciHcDxe.h"
+#include "XenonSdhci.h"
+
+//
+// Driver Global Variables
+//
+EFI_DRIVER_BINDING_PROTOCOL gSdMmcPciHcDriverBinding = {
+ SdMmcPciHcDriverBindingSupported,
+ SdMmcPciHcDriverBindingStart,
+ SdMmcPciHcDriverBindingStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+//
+// Template for SD/MMC host controller private data.
+//
+SD_MMC_HC_PRIVATE_DATA gSdMmcPciHcTemplate = {
+ SD_MMC_HC_PRIVATE_SIGNATURE, // Signature
+ NULL, // ControllerHandle
+ NULL, // PciIo
+ { // PassThru
+ sizeof (UINT32),
+ SdMmcPassThruPassThru,
+ SdMmcPassThruGetNextSlot,
+ SdMmcPassThruBuildDevicePath,
+ SdMmcPassThruGetSlotNumber,
+ SdMmcPassThruResetDevice
+ },
+ 0, // PciAttributes
+ 0, // PreviousSlot
+ NULL, // TimerEvent
+ NULL, // ConnectEvent
+ // Queue
+ INITIALIZE_LIST_HEAD_VARIABLE (gSdMmcPciHcTemplate.Queue),
+ { // Slot
+ {0, UnknownSlot, 0, 0, 0}, {0, UnknownSlot, 0, 0, 0}, {0, UnknownSlot, 0, 0, 0},
+ {0, UnknownSlot, 0, 0, 0}, {0, UnknownSlot, 0, 0, 0}, {0, UnknownSlot, 0, 0, 0}
+ },
+ { // Capability
+ {0},
+ },
+ { // MaxCurrent
+ 0,
+ },
+ 0 // ControllerVersion
+};
+
+SD_DEVICE_PATH mSdDpTemplate = {
+ {
+ MESSAGING_DEVICE_PATH,
+ MSG_SD_DP,
+ {
+ (UINT8) (sizeof (SD_DEVICE_PATH)),
+ (UINT8) ((sizeof (SD_DEVICE_PATH)) >> 8)
+ }
+ },
+ 0
+};
+
+EMMC_DEVICE_PATH mEmmcDpTemplate = {
+ {
+ MESSAGING_DEVICE_PATH,
+ MSG_EMMC_DP,
+ {
+ (UINT8) (sizeof (EMMC_DEVICE_PATH)),
+ (UINT8) ((sizeof (EMMC_DEVICE_PATH)) >> 8)
+ }
+ },
+ 0
+};
+
+//
+// Prioritized function list to detect card type.
+// User could add other card detection logic here.
+//
+CARD_TYPE_DETECT_ROUTINE mCardTypeDetectRoutineTable[] = {
+ EmmcIdentification,
+ SdCardIdentification,
+ NULL
+};
+
+/**
+ The entry point for SD host controller driver, used to install this driver on the ImageHandle.
+
+ @param[in] ImageHandle The firmware allocated handle for this driver image.
+ @param[in] SystemTable Pointer to the EFI system table.
+
+ @retval EFI_SUCCESS Driver loaded.
+ @retval other Driver not loaded.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeSdMmcPciHcDxe (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gSdMmcPciHcDriverBinding,
+ ImageHandle,
+ &gSdMmcPciHcComponentName,
+ &gSdMmcPciHcComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Call back function when the timer event is signaled.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the
+ Event.
+
+**/
+VOID
+EFIAPI
+ProcessAsyncTaskList (
+ IN EFI_EVENT Event,
+ IN VOID* Context
+ )
+{
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ LIST_ENTRY *Link;
+ SD_MMC_HC_TRB *Trb;
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ BOOLEAN InfiniteWait;
+ EFI_EVENT TrbEvent;
+
+ Private = (SD_MMC_HC_PRIVATE_DATA*)Context;
+
+ //
+ // Check if the first entry in the async I/O queue is done or not.
+ //
+ Status = EFI_SUCCESS;
+ Trb = NULL;
+ Link = GetFirstNode (&Private->Queue);
+ if (!IsNull (&Private->Queue, Link)) {
+ Trb = SD_MMC_HC_TRB_FROM_THIS (Link);
+ if (!Private->Slot[Trb->Slot].MediaPresent) {
+ Status = EFI_NO_MEDIA;
+ goto Done;
+ }
+ if (!Trb->Started) {
+ //
+ // Check whether the cmd/data line is ready for transfer.
+ //
+ Status = SdMmcCheckTrbEnv (Private, Trb);
+ if (!EFI_ERROR (Status)) {
+ Trb->Started = TRUE;
+ Status = SdMmcExecTrb (Private, Trb);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ } else {
+ goto Done;
+ }
+ }
+ Status = SdMmcCheckTrbResult (Private, Trb);
+ }
+
+Done:
+ if ((Trb != NULL) && (Status == EFI_NOT_READY)) {
+ Packet = Trb->Packet;
+ if (Packet->Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+ if ((!InfiniteWait) && (Trb->Timeout-- == 0)) {
+ RemoveEntryList (Link);
+ Trb->Packet->TransactionStatus = EFI_TIMEOUT;
+ TrbEvent = Trb->Event;
+ SdMmcFreeTrb (Trb);
+ DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT\n", TrbEvent));
+ gBS->SignalEvent (TrbEvent);
+ return;
+ }
+ }
+ if ((Trb != NULL) && (Status != EFI_NOT_READY)) {
+ RemoveEntryList (Link);
+ Trb->Packet->TransactionStatus = Status;
+ TrbEvent = Trb->Event;
+ SdMmcFreeTrb (Trb);
+ DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p with %r\n", TrbEvent, Status));
+ gBS->SignalEvent (TrbEvent);
+ }
+ return;
+}
+
+/**
+ Sd removable device enumeration callback function when the timer event is signaled.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the
+ Event.
+
+**/
+VOID
+EFIAPI
+SdMmcPciHcEnumerateDevice (
+ IN EFI_EVENT Event,
+ IN VOID* Context
+ )
+{
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ EFI_STATUS Status;
+ UINT8 Slot;
+ BOOLEAN MediaPresent;
+ UINT32 RoutineNum;
+ CARD_TYPE_DETECT_ROUTINE *Routine;
+ UINTN Index;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NextLink;
+ SD_MMC_HC_TRB *Trb;
+ EFI_TPL OldTpl;
+
+ Private = (SD_MMC_HC_PRIVATE_DATA*)Context;
+
+ for (Slot = 0; Slot < SD_MMC_HC_MAX_SLOT; Slot++) {
+ if ((Private->Slot[Slot].Enable) && (Private->Slot[Slot].SlotType == RemovableSlot)) {
+ Status = SdMmcHcCardDetect (Private->PciIo, Slot, &MediaPresent);
+ if ((Status == EFI_MEDIA_CHANGED) && !MediaPresent) {
+ DEBUG ((DEBUG_INFO, "SdMmcPciHcEnumerateDevice: device disconnected at slot %d of pci %p\n", Slot, Private->PciIo));
+ Private->Slot[Slot].MediaPresent = FALSE;
+ Private->Slot[Slot].Initialized = FALSE;
+ //
+ // Signal all async task events at the slot with EFI_NO_MEDIA status.
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ for (Link = GetFirstNode (&Private->Queue);
+ !IsNull (&Private->Queue, Link);
+ Link = NextLink) {
+ NextLink = GetNextNode (&Private->Queue, Link);
+ Trb = SD_MMC_HC_TRB_FROM_THIS (Link);
+ if (Trb->Slot == Slot) {
+ RemoveEntryList (Link);
+ Trb->Packet->TransactionStatus = EFI_NO_MEDIA;
+ gBS->SignalEvent (Trb->Event);
+ SdMmcFreeTrb (Trb);
+ }
+ }
+ gBS->RestoreTPL (OldTpl);
+ //
+ // Notify the upper layer the connect state change through ReinstallProtocolInterface.
+ //
+ gBS->ReinstallProtocolInterface (
+ Private->ControllerHandle,
+ &gEfiSdMmcPassThruProtocolGuid,
+ &Private->PassThru,
+ &Private->PassThru
+ );
+ }
+ if ((Status == EFI_MEDIA_CHANGED) && MediaPresent) {
+ DEBUG ((DEBUG_INFO, "SdMmcPciHcEnumerateDevice: device connected at slot %d of pci %p\n", Slot, Private->PciIo));
+ //
+ // Reset the specified slot of the SD/MMC Pci Host Controller
+ //
+ Status = SdMmcHcReset (Private->PciIo, Slot);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ //
+ // Reinitialize slot and restart identification process for the new attached device
+ //
+ Status = SdMmcHcInitHost (Private->PciIo, Slot, Private->Capability[Slot]);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Private->Slot[Slot].MediaPresent = TRUE;
+ Private->Slot[Slot].Initialized = TRUE;
+ RoutineNum = sizeof (mCardTypeDetectRoutineTable) / sizeof (CARD_TYPE_DETECT_ROUTINE);
+ for (Index = 0; Index < RoutineNum; Index++) {
+ Routine = &mCardTypeDetectRoutineTable[Index];
+ if (*Routine != NULL) {
+ Status = (*Routine) (Private, Slot);
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ }
+ }
+ //
+ // This card doesn't get initialized correctly.
+ //
+ if (Index == RoutineNum) {
+ Private->Slot[Slot].Initialized = FALSE;
+ }
+
+ //
+ // Notify the upper layer the connect state change through ReinstallProtocolInterface.
+ //
+ gBS->ReinstallProtocolInterface (
+ Private->ControllerHandle,
+ &gEfiSdMmcPassThruProtocolGuid,
+ &Private->PassThru,
+ &Private->PassThru
+ );
+ }
+ }
+ }
+
+ return;
+}
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. This handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
+ parameter is ignored by device drivers, and is optional for bus
+ drivers. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPciHcDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 PciData;
+
+ PciIo = NULL;
+ ParentDevicePath = NULL;
+
+ //
+ // SdPciHcDxe is a device driver, and should ingore the
+ // "RemainingDevicePath" according to EFI spec.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID *) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // EFI_ALREADY_STARTED is also an error.
+ //
+ return Status;
+ }
+ //
+ // Close the protocol because we don't use it here.
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Now test the EfiPciIoProtocol.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Now further check the PCI header: Base class (offset 0x08) and
+ // Sub Class (offset 0x05). This controller should be an SD/MMC PCI
+ // Host Controller.
+ //
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0,
+ sizeof (PciData),
+ &PciData
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Since we already got the PciData, we can close protocol to avoid to carry it
+ // on for multiple exit points.
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Examine SD PCI Host Controller PCI Configuration table fields.
+ //
+ if ((PciData.Hdr.ClassCode[2] == PCI_CLASS_SYSTEM_PERIPHERAL) &&
+ (PciData.Hdr.ClassCode[1] == PCI_SUBCLASS_SD_HOST_CONTROLLER) &&
+ ((PciData.Hdr.ClassCode[0] == 0x00) || (PciData.Hdr.ClassCode[0] == 0x01))) {
+ return EFI_SUCCESS;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Starts a device controller or a bus controller.
+
+ The Start() function is designed to be invoked from the EFI boot service ConnectController().
+ As a result, much of the error checking on the parameters to Start() has been moved into this
+ common boot service. It is legal to call Start() from other locations,
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE.
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
+ EFI_DEVICE_PATH_PROTOCOL.
+ 3. Prior to calling Start(), the Supported() function for the driver specified by This must
+ have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to start. This handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
+ parameter is ignored by device drivers, and is optional for bus
+ drivers. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @retval EFI_SUCCESS The device was started.
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval Others The driver failded to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPciHcDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT64 Supports;
+ UINT64 PciAttributes;
+ UINT8 Slot;
+ UINT8 Index;
+ CARD_TYPE_DETECT_ROUTINE *Routine;
+ UINT32 RoutineNum;
+ BOOLEAN Support64BitDma;
+
+ DEBUG ((DEBUG_INFO, "SdMmcPciHcDriverBindingStart: Start\n"));
+
+ //
+ // Open PCI I/O Protocol and save pointer to open protocol
+ // in private data area.
+ //
+ PciIo = NULL;
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Enable the SD Host Controller MMIO space
+ //
+ Private = NULL;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationGet,
+ 0,
+ &PciAttributes
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ Supports,
+ NULL
+ );
+ } else {
+ goto Done;
+ }
+
+ Private = AllocateCopyPool (sizeof (SD_MMC_HC_PRIVATE_DATA), &gSdMmcPciHcTemplate);
+ if (Private == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ Private->ControllerHandle = Controller;
+ Private->PciIo = PciIo;
+ Private->PciAttributes = PciAttributes;
+ InitializeListHead (&Private->Queue);
+
+ Support64BitDma = TRUE;
+
+ //
+ // There is only one slot 0 on Xenon
+ //
+ Slot = 0;
+ Private->Slot[Slot].Enable = TRUE;
+
+ Status = SdMmcHcGetCapability (PciIo, Slot, &Private->Capability[Slot]);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Support64BitDma &= Private->Capability[Slot].SysBus64;
+
+ //
+ // Override capabilities structure - only 4 Bit width bus is supported
+ // by HW and also force using SDR25 mode
+ //
+ Private->Capability[Slot].Sdr104 = 0;
+ Private->Capability[Slot].Ddr50 = 0;
+ Private->Capability[Slot].Sdr50 = 0;
+ Private->Capability[Slot].BusWidth8 = 0;
+
+ if (Private->Capability[Slot].BaseClkFreq == 0) {
+ Private->Capability[Slot].BaseClkFreq = 0xff;
+ }
+
+ DumpCapabilityReg (Slot, &Private->Capability[Slot]);
+
+ Status = SdMmcHcGetMaxCurrent (PciIo, Slot, &Private->MaxCurrent[Slot]);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Private->Slot[Slot].SlotType = Private->Capability[Slot].SlotType;
+ if ((Private->Slot[Slot].SlotType != RemovableSlot) && (Private->Slot[Slot].SlotType != EmbeddedSlot)) {
+ DEBUG ((DEBUG_INFO, "SdMmcPciHcDxe doesn't support the slot type [%d]!!!\n", Private->Slot[Slot].SlotType));
+ return EFI_D_ERROR;
+ }
+
+ //
+ // Perform Xenon-specific init sequence
+ //
+ XenonInit (Private);
+
+ //
+ // Initialize HC timeout control
+ //
+ Status = SdMmcHcInitTimeoutCtrl (PciIo, Slot);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Private->Slot[Slot].MediaPresent = TRUE;
+ Private->Slot[Slot].Initialized = TRUE;
+ RoutineNum = sizeof (mCardTypeDetectRoutineTable) / sizeof (CARD_TYPE_DETECT_ROUTINE);
+ for (Index = 0; Index < RoutineNum; Index++) {
+ Routine = &mCardTypeDetectRoutineTable[Index];
+ if (*Routine != NULL) {
+ Status = (*Routine) (Private, Slot);
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ }
+ }
+ //
+ // This card doesn't get initialized correctly.
+ //
+ if (Index == RoutineNum) {
+ Private->Slot[Slot].Initialized = FALSE;
+ }
+
+ //
+ // Enable 64-bit DMA support in the PCI layer if this controller
+ // supports it.
+ //
+ if (Support64BitDma) {
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "SdMmcPciHcDriverBindingStart: failed to enable 64-bit DMA (%r)\n", Status));
+ }
+ }
+
+ //
+ // Start the asynchronous I/O monitor
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ ProcessAsyncTaskList,
+ Private,
+ &Private->TimerEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = gBS->SetTimer (Private->TimerEvent, TimerPeriodic, SD_MMC_HC_ASYNC_TIMER);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Start the Sd removable device connection enumeration
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ SdMmcPciHcEnumerateDevice,
+ Private,
+ &Private->ConnectEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = gBS->SetTimer (Private->ConnectEvent, TimerPeriodic, SD_MMC_HC_ENUM_TIMER);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ &(Private->PassThru),
+ NULL
+ );
+
+ DEBUG ((DEBUG_INFO, "SdMmcPciHcDriverBindingStart: %r End on %x\n", Status, Controller));
+
+Done:
+ if (EFI_ERROR (Status)) {
+ if ((Private != NULL) && (Private->PciAttributes != 0)) {
+ //
+ // Restore original PCI attributes
+ //
+ PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSet,
+ Private->PciAttributes,
+ NULL
+ );
+ }
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ if ((Private != NULL) && (Private->TimerEvent != NULL)) {
+ gBS->CloseEvent (Private->TimerEvent);
+ }
+
+ if ((Private != NULL) && (Private->ConnectEvent != NULL)) {
+ gBS->CloseEvent (Private->ConnectEvent);
+ }
+
+ if (Private != NULL) {
+ FreePool (Private);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Stops a device controller or a bus controller.
+
+ The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
+ As a result, much of the error checking on the parameters to Stop() has been moved
+ into this common boot service. It is legal to call Stop() from other locations,
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
+ same driver's Start() function.
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
+ EFI_HANDLE. In addition, all of these handles must have been created in this driver's
+ Start() function, and the Start() function must have called OpenProtocol() on
+ ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle A handle to the device being stopped. The handle must
+ support a bus specific I/O protocol for the driver
+ to use to stop the device.
+ @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
+ if NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPciHcDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NextLink;
+ SD_MMC_HC_TRB *Trb;
+
+ DEBUG ((DEBUG_INFO, "SdMmcPciHcDriverBindingStop: Start\n"));
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ (VOID**) &PassThru,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
+ //
+ // Close Non-Blocking timer and free Task list.
+ //
+ if (Private->TimerEvent != NULL) {
+ gBS->CloseEvent (Private->TimerEvent);
+ Private->TimerEvent = NULL;
+ }
+ if (Private->ConnectEvent != NULL) {
+ gBS->CloseEvent (Private->ConnectEvent);
+ Private->ConnectEvent = NULL;
+ }
+ //
+ // As the timer is closed, there is no needs to use TPL lock to
+ // protect the critical region "queue".
+ //
+ for (Link = GetFirstNode (&Private->Queue);
+ !IsNull (&Private->Queue, Link);
+ Link = NextLink) {
+ NextLink = GetNextNode (&Private->Queue, Link);
+ RemoveEntryList (Link);
+ Trb = SD_MMC_HC_TRB_FROM_THIS (Link);
+ Trb->Packet->TransactionStatus = EFI_ABORTED;
+ gBS->SignalEvent (Trb->Event);
+ SdMmcFreeTrb (Trb);
+ }
+
+ //
+ // Uninstall Block I/O protocol from the device handle
+ //
+ Status = gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ &(Private->PassThru)
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ //
+ // Restore original PCI attributes
+ //
+ PciIo = Private->PciIo;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSet,
+ Private->PciAttributes,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (Private);
+
+ DEBUG ((DEBUG_INFO, "SdMmcPciHcDriverBindingStop: End with %r\n", Status));
+
+ return Status;
+}
+
+/**
+ Sends SD command to an SD card that is attached to the SD controller.
+
+ The PassThru() function sends the SD command specified by Packet to the SD card
+ specified by Slot.
+
+ If Packet is successfully sent to the SD card, then EFI_SUCCESS is returned.
+
+ If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is returned.
+
+ If Slot is not in a valid range for the SD controller, then EFI_INVALID_PARAMETER
+ is returned.
+
+ If Packet defines a data command but both InDataBuffer and OutDataBuffer are NULL,
+ EFI_INVALID_PARAMETER is returned.
+
+ @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in,out] Packet A pointer to the SD command data structure.
+ @param[in] Event If Event is NULL, blocking I/O is performed. If Event is
+ not NULL, then nonblocking I/O is performed, and Event
+ will be signaled when the Packet completes.
+
+ @retval EFI_SUCCESS The SD Command Packet was sent by the host.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SD
+ command Packet.
+ @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is invalid.
+ @retval EFI_INVALID_PARAMETER Packet defines a data command but both InDataBuffer and
+ OutDataBuffer are NULL.
+ @retval EFI_NO_MEDIA SD Device not present in the Slot.
+ @retval EFI_UNSUPPORTED The command described by the SD Command Packet is not
+ supported by the host controller.
+ @retval EFI_BAD_BUFFER_SIZE The InTransferLength or OutTransferLength exceeds the
+ limit supported by SD card ( i.e. if the number of bytes
+ exceed the Last LBA).
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPassThruPassThru (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN UINT8 Slot,
+ IN OUT EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,
+ IN EFI_EVENT Event OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ SD_MMC_HC_TRB *Trb;
+ EFI_TPL OldTpl;
+
+ if ((This == NULL) || (Packet == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Packet->SdMmcCmdBlk == NULL) || (Packet->SdMmcStatusBlk == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Packet->OutDataBuffer == NULL) && (Packet->OutTransferLength != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Packet->InDataBuffer == NULL) && (Packet->InTransferLength != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (This);
+
+ if (!Private->Slot[Slot].Enable) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!Private->Slot[Slot].MediaPresent) {
+ return EFI_NO_MEDIA;
+ }
+
+ if (!Private->Slot[Slot].Initialized) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Trb = SdMmcCreateTrb (Private, Slot, Packet, Event);
+ if (Trb == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Immediately return for async I/O.
+ //
+ if (Event != NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Wait async I/O list is empty before execute sync I/O operation.
+ //
+ while (TRUE) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ if (IsListEmpty (&Private->Queue)) {
+ gBS->RestoreTPL (OldTpl);
+ break;
+ }
+ gBS->RestoreTPL (OldTpl);
+ }
+
+ Status = SdMmcWaitTrbEnv (Private, Trb);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = SdMmcExecTrb (Private, Trb);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = SdMmcWaitTrbResult (Private, Trb);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+Done:
+ if ((Trb != NULL) && (Trb->AdmaDesc != NULL)) {
+ FreePages (Trb->AdmaDesc, Trb->AdmaPages);
+ }
+
+ if (Trb != NULL) {
+ FreePool (Trb);
+ }
+
+ return Status;
+}
+
+/**
+ Used to retrieve next slot numbers supported by the SD controller. The function
+ returns information about all available slots (populated or not-populated).
+
+ The GetNextSlot() function retrieves the next slot number on an SD controller.
+ If on input Slot is 0xFF, then the slot number of the first slot on the SD controller
+ is returned.
+
+ If Slot is a slot number that was returned on a previous call to GetNextSlot(), then
+ the slot number of the next slot on the SD controller is returned.
+
+ If Slot is not 0xFF and Slot was not returned on a previous call to GetNextSlot(),
+ EFI_INVALID_PARAMETER is returned.
+
+ If Slot is the slot number of the last slot on the SD controller, then EFI_NOT_FOUND
+ is returned.
+
+ @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL instance.
+ @param[in,out] Slot On input, a pointer to a slot number on the SD controller.
+ On output, a pointer to the next slot number on the SD controller.
+ An input value of 0xFF retrieves the first slot number on the SD
+ controller.
+
+ @retval EFI_SUCCESS The next slot number on the SD controller was returned in Slot.
+ @retval EFI_NOT_FOUND There are no more slots on this SD controller.
+ @retval EFI_INVALID_PARAMETER Slot is not 0xFF and Slot was not returned on a previous call
+ to GetNextSlot().
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPassThruGetNextSlot (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN OUT UINT8 *Slot
+ )
+{
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ UINT8 Index;
+
+ if ((This == NULL) || (Slot == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (This);
+
+ if (*Slot == 0xFF) {
+ for (Index = 0; Index < SD_MMC_HC_MAX_SLOT; Index++) {
+ if (Private->Slot[Index].Enable) {
+ *Slot = Index;
+ Private->PreviousSlot = Index;
+ return EFI_SUCCESS;
+ }
+ }
+ return EFI_NOT_FOUND;
+ } else if (*Slot == Private->PreviousSlot) {
+ for (Index = *Slot + 1; Index < SD_MMC_HC_MAX_SLOT; Index++) {
+ if (Private->Slot[Index].Enable) {
+ *Slot = Index;
+ Private->PreviousSlot = Index;
+ return EFI_SUCCESS;
+ }
+ }
+ return EFI_NOT_FOUND;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+}
+
+/**
+ Used to allocate and build a device path node for an SD card on the SD controller.
+
+ The BuildDevicePath() function allocates and builds a single device node for the SD
+ card specified by Slot.
+
+ If the SD card specified by Slot is not present on the SD controller, then EFI_NOT_FOUND
+ is returned.
+
+ If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned.
+
+ If there are not enough resources to allocate the device path node, then EFI_OUT_OF_RESOURCES
+ is returned.
+
+ Otherwise, DevicePath is allocated with the boot service AllocatePool(), the contents of
+ DevicePath are initialized to describe the SD card specified by Slot, and EFI_SUCCESS is
+ returned.
+
+ @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot Specifies the slot number of the SD card for which a device
+ path node is to be allocated and built.
+ @param[in,out] DevicePath A pointer to a single device path node that describes the SD
+ card specified by Slot. This function is responsible for
+ allocating the buffer DevicePath with the boot service
+ AllocatePool(). It is the caller's responsibility to free
+ DevicePath when the caller is finished with DevicePath.
+
+ @retval EFI_SUCCESS The device path node that describes the SD card specified by
+ Slot was allocated and returned in DevicePath.
+ @retval EFI_NOT_FOUND The SD card specified by Slot does not exist on the SD controller.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate DevicePath.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPassThruBuildDevicePath (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN UINT8 Slot,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ SD_DEVICE_PATH *SdNode;
+ EMMC_DEVICE_PATH *EmmcNode;
+
+ if ((This == NULL) || (DevicePath == NULL) || (Slot >= SD_MMC_HC_MAX_SLOT)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (This);
+
+ if ((!Private->Slot[Slot].Enable) || (!Private->Slot[Slot].MediaPresent)) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (Private->Slot[Slot].CardType == SdCardType) {
+ SdNode = AllocateCopyPool (sizeof (SD_DEVICE_PATH), &mSdDpTemplate);
+ if (SdNode == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ SdNode->SlotNumber = Slot;
+
+ *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) SdNode;
+ } else if (Private->Slot[Slot].CardType == EmmcCardType) {
+ EmmcNode = AllocateCopyPool (sizeof (EMMC_DEVICE_PATH), &mEmmcDpTemplate);
+ if (EmmcNode == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ EmmcNode->SlotNumber = Slot;
+
+ *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) EmmcNode;
+ } else {
+ //
+ // Currently we only support SD and EMMC two device nodes.
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function retrieves an SD card slot number based on the input device path.
+
+ The GetSlotNumber() function retrieves slot number for the SD card specified by
+ the DevicePath node. If DevicePath is NULL, EFI_INVALID_PARAMETER is returned.
+
+ If DevicePath is not a device path node type that the SD Pass Thru driver supports,
+ EFI_UNSUPPORTED is returned.
+
+ @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] DevicePath A pointer to the device path node that describes a SD
+ card on the SD controller.
+ @param[out] Slot On return, points to the slot number of an SD card on
+ the SD controller.
+
+ @retval EFI_SUCCESS SD card slot number is returned in Slot.
+ @retval EFI_INVALID_PARAMETER Slot or DevicePath is NULL.
+ @retval EFI_UNSUPPORTED DevicePath is not a device path node type that the SD
+ Pass Thru driver supports.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPassThruGetSlotNumber (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINT8 *Slot
+ )
+{
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ SD_DEVICE_PATH *SdNode;
+ EMMC_DEVICE_PATH *EmmcNode;
+ UINT8 SlotNumber;
+
+ if ((This == NULL) || (DevicePath == NULL) || (Slot == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (This);
+
+ //
+ // Check whether the DevicePath belongs to SD_DEVICE_PATH or EMMC_DEVICE_PATH
+ //
+ if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||
+ ((DevicePath->SubType != MSG_SD_DP) &&
+ (DevicePath->SubType != MSG_EMMC_DP)) ||
+ (DevicePathNodeLength(DevicePath) != sizeof(SD_DEVICE_PATH)) ||
+ (DevicePathNodeLength(DevicePath) != sizeof(EMMC_DEVICE_PATH))) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (DevicePath->SubType == MSG_SD_DP) {
+ SdNode = (SD_DEVICE_PATH *) DevicePath;
+ SlotNumber = SdNode->SlotNumber;
+ } else {
+ EmmcNode = (EMMC_DEVICE_PATH *) DevicePath;
+ SlotNumber = EmmcNode->SlotNumber;
+ }
+
+ if (SlotNumber >= SD_MMC_HC_MAX_SLOT) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (Private->Slot[SlotNumber].Enable) {
+ *Slot = SlotNumber;
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+}
+
+/**
+ Resets an SD card that is connected to the SD controller.
+
+ The ResetDevice() function resets the SD card specified by Slot.
+
+ If this SD controller does not support a device reset operation, EFI_UNSUPPORTED is
+ returned.
+
+ If Slot is not in a valid slot number for this SD controller, EFI_INVALID_PARAMETER
+ is returned.
+
+ If the device reset operation is completed, EFI_SUCCESS is returned.
+
+ @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot Specifies the slot number of the SD card to be reset.
+
+ @retval EFI_SUCCESS The SD card specified by Slot was reset.
+ @retval EFI_UNSUPPORTED The SD controller does not support a device reset operation.
+ @retval EFI_INVALID_PARAMETER Slot number is invalid.
+ @retval EFI_NO_MEDIA SD Device not present in the Slot.
+ @retval EFI_DEVICE_ERROR The reset command failed due to a device error
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPassThruResetDevice (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN UINT8 Slot
+ )
+{
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NextLink;
+ SD_MMC_HC_TRB *Trb;
+ EFI_TPL OldTpl;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (This);
+
+ if (!Private->Slot[Slot].Enable) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!Private->Slot[Slot].MediaPresent) {
+ return EFI_NO_MEDIA;
+ }
+
+ if (!Private->Slot[Slot].Initialized) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Free all async I/O requests in the queue
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ for (Link = GetFirstNode (&Private->Queue);
+ !IsNull (&Private->Queue, Link);
+ Link = NextLink) {
+ NextLink = GetNextNode (&Private->Queue, Link);
+ RemoveEntryList (Link);
+ Trb = SD_MMC_HC_TRB_FROM_THIS (Link);
+ Trb->Packet->TransactionStatus = EFI_ABORTED;
+ gBS->SignalEvent (Trb->Event);
+ SdMmcFreeTrb (Trb);
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.h b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.h
new file mode 100644
index 0000000000..6a2a279699
--- /dev/null
+++ b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.h
@@ -0,0 +1,785 @@
+/** @file
+
+ Provides some data structure definitions used by the SD/MMC host controller driver.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+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.
+
+**/
+
+#ifndef _SD_MMC_PCI_HC_DXE_H_
+#define _SD_MMC_PCI_HC_DXE_H_
+
+#include <Uefi.h>
+
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/Emmc.h>
+#include <IndustryStandard/Sd.h>
+
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+
+#include <Protocol/DevicePath.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/SdMmcPassThru.h>
+
+#include "SdMmcPciHci.h"
+
+extern EFI_COMPONENT_NAME_PROTOCOL gSdMmcPciHcComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gSdMmcPciHcComponentName2;
+extern EFI_DRIVER_BINDING_PROTOCOL gSdMmcPciHcDriverBinding;
+
+#define SD_MMC_HC_PRIVATE_SIGNATURE SIGNATURE_32 ('s', 'd', 't', 'f')
+
+#define SD_MMC_HC_PRIVATE_FROM_THIS(a) \
+ CR(a, SD_MMC_HC_PRIVATE_DATA, PassThru, SD_MMC_HC_PRIVATE_SIGNATURE)
+
+//
+// Generic time out value, 1 microsecond as unit.
+//
+#define SD_MMC_HC_GENERIC_TIMEOUT 1 * 1000 * 1000
+
+//
+// SD/MMC async transfer timer interval, set by experience.
+// The unit is 100us, takes 1ms as interval.
+//
+#define SD_MMC_HC_ASYNC_TIMER EFI_TIMER_PERIOD_MILLISECONDS(1)
+//
+// SD/MMC removable device enumeration timer interval, set by experience.
+// The unit is 100us, takes 100ms as interval.
+//
+#define SD_MMC_HC_ENUM_TIMER EFI_TIMER_PERIOD_MILLISECONDS(100)
+
+typedef enum {
+ UnknownCardType,
+ SdCardType,
+ SdioCardType,
+ MmcCardType,
+ EmmcCardType
+} SD_MMC_CARD_TYPE;
+
+typedef enum {
+ RemovableSlot,
+ EmbeddedSlot,
+ SharedBusSlot,
+ UnknownSlot
+} EFI_SD_MMC_SLOT_TYPE;
+
+typedef struct {
+ BOOLEAN Enable;
+ EFI_SD_MMC_SLOT_TYPE SlotType;
+ BOOLEAN MediaPresent;
+ BOOLEAN Initialized;
+ SD_MMC_CARD_TYPE CardType;
+} SD_MMC_HC_SLOT;
+
+typedef struct {
+ UINTN Signature;
+
+ EFI_HANDLE ControllerHandle;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ EFI_SD_MMC_PASS_THRU_PROTOCOL PassThru;
+
+ UINT64 PciAttributes;
+ //
+ // The field is used to record the previous slot in GetNextSlot().
+ //
+ UINT8 PreviousSlot;
+ //
+ // For Non-blocking operation.
+ //
+ EFI_EVENT TimerEvent;
+ //
+ // For Sd removable device enumeration.
+ //
+ EFI_EVENT ConnectEvent;
+ LIST_ENTRY Queue;
+
+ SD_MMC_HC_SLOT Slot[SD_MMC_HC_MAX_SLOT];
+ SD_MMC_HC_SLOT_CAP Capability[SD_MMC_HC_MAX_SLOT];
+ UINT64 MaxCurrent[SD_MMC_HC_MAX_SLOT];
+
+ UINT32 ControllerVersion;
+} SD_MMC_HC_PRIVATE_DATA;
+
+#define SD_MMC_HC_TRB_SIG SIGNATURE_32 ('T', 'R', 'B', 'T')
+
+//
+// TRB (Transfer Request Block) contains information for the cmd request.
+//
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY TrbList;
+
+ UINT8 Slot;
+ UINT16 BlockSize;
+
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ VOID *Data;
+ UINT32 DataLen;
+ BOOLEAN Read;
+ EFI_PHYSICAL_ADDRESS DataPhy;
+ VOID *DataMap;
+ SD_MMC_HC_TRANSFER_MODE Mode;
+
+ EFI_EVENT Event;
+ BOOLEAN Started;
+ UINT64 Timeout;
+
+ SD_MMC_HC_ADMA_DESC_LINE *AdmaDesc;
+ EFI_PHYSICAL_ADDRESS AdmaDescPhy;
+ VOID *AdmaMap;
+ UINT32 AdmaPages;
+
+ SD_MMC_HC_PRIVATE_DATA *Private;
+} SD_MMC_HC_TRB;
+
+#define SD_MMC_HC_TRB_FROM_THIS(a) \
+ CR(a, SD_MMC_HC_TRB, TrbList, SD_MMC_HC_TRB_SIG)
+
+//
+// Task for Non-blocking mode.
+//
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+
+ UINT8 Slot;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ BOOLEAN IsStart;
+ EFI_EVENT Event;
+ UINT64 RetryTimes;
+ BOOLEAN InfiniteWait;
+ VOID *Map;
+ VOID *MapAddress;
+} SD_MMC_HC_QUEUE;
+
+//
+// Prototypes
+//
+/**
+ Execute card identification procedure.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The card is identified correctly.
+ @retval Others The card can't be identified.
+
+**/
+typedef
+EFI_STATUS
+(*CARD_TYPE_DETECT_ROUTINE) (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot
+ );
+
+/**
+ Sends SD command to an SD card that is attached to the SD controller.
+
+ The PassThru() function sends the SD command specified by Packet to the SD card
+ specified by Slot.
+
+ If Packet is successfully sent to the SD card, then EFI_SUCCESS is returned.
+
+ If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is returned.
+
+ If Slot is not in a valid range for the SD controller, then EFI_INVALID_PARAMETER
+ is returned.
+
+ If Packet defines a data command but both InDataBuffer and OutDataBuffer are NULL,
+ EFI_INVALID_PARAMETER is returned.
+
+ @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in,out] Packet A pointer to the SD command data structure.
+ @param[in] Event If Event is NULL, blocking I/O is performed. If Event is
+ not NULL, then nonblocking I/O is performed, and Event
+ will be signaled when the Packet completes.
+
+ @retval EFI_SUCCESS The SD Command Packet was sent by the host.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SD
+ command Packet.
+ @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is invalid.
+ @retval EFI_INVALID_PARAMETER Packet defines a data command but both InDataBuffer and
+ OutDataBuffer are NULL.
+ @retval EFI_NO_MEDIA SD Device not present in the Slot.
+ @retval EFI_UNSUPPORTED The command described by the SD Command Packet is not
+ supported by the host controller.
+ @retval EFI_BAD_BUFFER_SIZE The InTransferLength or OutTransferLength exceeds the
+ limit supported by SD card ( i.e. if the number of bytes
+ exceed the Last LBA).
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPassThruPassThru (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN UINT8 Slot,
+ IN OUT EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,
+ IN EFI_EVENT Event OPTIONAL
+ );
+
+/**
+ Used to retrieve next slot numbers supported by the SD controller. The function
+ returns information about all available slots (populated or not-populated).
+
+ The GetNextSlot() function retrieves the next slot number on an SD controller.
+ If on input Slot is 0xFF, then the slot number of the first slot on the SD controller
+ is returned.
+
+ If Slot is a slot number that was returned on a previous call to GetNextSlot(), then
+ the slot number of the next slot on the SD controller is returned.
+
+ If Slot is not 0xFF and Slot was not returned on a previous call to GetNextSlot(),
+ EFI_INVALID_PARAMETER is returned.
+
+ If Slot is the slot number of the last slot on the SD controller, then EFI_NOT_FOUND
+ is returned.
+
+ @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL instance.
+ @param[in,out] Slot On input, a pointer to a slot number on the SD controller.
+ On output, a pointer to the next slot number on the SD controller.
+ An input value of 0xFF retrieves the first slot number on the SD
+ controller.
+
+ @retval EFI_SUCCESS The next slot number on the SD controller was returned in Slot.
+ @retval EFI_NOT_FOUND There are no more slots on this SD controller.
+ @retval EFI_INVALID_PARAMETER Slot is not 0xFF and Slot was not returned on a previous call
+ to GetNextSlot().
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPassThruGetNextSlot (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN OUT UINT8 *Slot
+ );
+
+/**
+ Used to allocate and build a device path node for an SD card on the SD controller.
+
+ The BuildDevicePath() function allocates and builds a single device node for the SD
+ card specified by Slot.
+
+ If the SD card specified by Slot is not present on the SD controller, then EFI_NOT_FOUND
+ is returned.
+
+ If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned.
+
+ If there are not enough resources to allocate the device path node, then EFI_OUT_OF_RESOURCES
+ is returned.
+
+ Otherwise, DevicePath is allocated with the boot service AllocatePool(), the contents of
+ DevicePath are initialized to describe the SD card specified by Slot, and EFI_SUCCESS is
+ returned.
+
+ @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot Specifies the slot number of the SD card for which a device
+ path node is to be allocated and built.
+ @param[in,out] DevicePath A pointer to a single device path node that describes the SD
+ card specified by Slot. This function is responsible for
+ allocating the buffer DevicePath with the boot service
+ AllocatePool(). It is the caller's responsibility to free
+ DevicePath when the caller is finished with DevicePath.
+
+ @retval EFI_SUCCESS The device path node that describes the SD card specified by
+ Slot was allocated and returned in DevicePath.
+ @retval EFI_NOT_FOUND The SD card specified by Slot does not exist on the SD controller.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate DevicePath.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPassThruBuildDevicePath (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN UINT8 Slot,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ );
+
+/**
+ This function retrieves an SD card slot number based on the input device path.
+
+ The GetSlotNumber() function retrieves slot number for the SD card specified by
+ the DevicePath node. If DevicePath is NULL, EFI_INVALID_PARAMETER is returned.
+
+ If DevicePath is not a device path node type that the SD Pass Thru driver supports,
+ EFI_UNSUPPORTED is returned.
+
+ @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] DevicePath A pointer to the device path node that describes a SD
+ card on the SD controller.
+ @param[out] Slot On return, points to the slot number of an SD card on
+ the SD controller.
+
+ @retval EFI_SUCCESS SD card slot number is returned in Slot.
+ @retval EFI_INVALID_PARAMETER Slot or DevicePath is NULL.
+ @retval EFI_UNSUPPORTED DevicePath is not a device path node type that the SD
+ Pass Thru driver supports.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPassThruGetSlotNumber (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINT8 *Slot
+ );
+
+/**
+ Resets an SD card that is connected to the SD controller.
+
+ The ResetDevice() function resets the SD card specified by Slot.
+
+ If this SD controller does not support a device reset operation, EFI_UNSUPPORTED is
+ returned.
+
+ If Slot is not in a valid slot number for this SD controller, EFI_INVALID_PARAMETER
+ is returned.
+
+ If the device reset operation is completed, EFI_SUCCESS is returned.
+
+ @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot Specifies the slot number of the SD card to be reset.
+
+ @retval EFI_SUCCESS The SD card specified by Slot was reset.
+ @retval EFI_UNSUPPORTED The SD controller does not support a device reset operation.
+ @retval EFI_INVALID_PARAMETER Slot number is invalid.
+ @retval EFI_NO_MEDIA SD Device not present in the Slot.
+ @retval EFI_DEVICE_ERROR The reset command failed due to a device error
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPassThruResetDevice (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN UINT8 Slot
+ );
+
+//
+// Driver model protocol interfaces
+//
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. This handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
+ parameter is ignored by device drivers, and is optional for bus
+ drivers. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPciHcDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starts a device controller or a bus controller.
+
+ The Start() function is designed to be invoked from the EFI boot service ConnectController().
+ As a result, much of the error checking on the parameters to Start() has been moved into this
+ common boot service. It is legal to call Start() from other locations,
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE.
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
+ EFI_DEVICE_PATH_PROTOCOL.
+ 3. Prior to calling Start(), the Supported() function for the driver specified by This must
+ have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to start. This handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
+ parameter is ignored by device drivers, and is optional for bus
+ drivers. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @retval EFI_SUCCESS The device was started.
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval Others The driver failded to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPciHcDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stops a device controller or a bus controller.
+
+ The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
+ As a result, much of the error checking on the parameters to Stop() has been moved
+ into this common boot service. It is legal to call Stop() from other locations,
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
+ same driver's Start() function.
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
+ EFI_HANDLE. In addition, all of these handles must have been created in this driver's
+ Start() function, and the Start() function must have called OpenProtocol() on
+ ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle A handle to the device being stopped. The handle must
+ support a bus specific I/O protocol for the driver
+ to use to stop the device.
+ @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
+ if NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPciHcDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+//
+// EFI Component Name Functions
+//
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPciHcComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcPciHcComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle, OPTIONAL
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+/**
+ Create a new TRB for the SD/MMC cmd request.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Packet A pointer to the SD command data structure.
+ @param[in] Event If Event is NULL, blocking I/O is performed. If Event is
+ not NULL, then nonblocking I/O is performed, and Event
+ will be signaled when the Packet completes.
+
+ @return Created Trb or NULL.
+
+**/
+SD_MMC_HC_TRB *
+SdMmcCreateTrb (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot,
+ IN EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,
+ IN EFI_EVENT Event
+ );
+
+/**
+ Free the resource used by the TRB.
+
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+**/
+VOID
+SdMmcFreeTrb (
+ IN SD_MMC_HC_TRB *Trb
+ );
+
+/**
+ Check if the env is ready for execute specified TRB.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The env is ready for TRB execution.
+ @retval EFI_NOT_READY The env is not ready for TRB execution.
+ @retval Others Some erros happen.
+
+**/
+EFI_STATUS
+SdMmcCheckTrbEnv (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ );
+
+/**
+ Wait for the env to be ready for execute specified TRB.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The env is ready for TRB execution.
+ @retval EFI_TIMEOUT The env is not ready for TRB execution in time.
+ @retval Others Some erros happen.
+
+**/
+EFI_STATUS
+SdMmcWaitTrbEnv (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ );
+
+/**
+ Execute the specified TRB.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The TRB is sent to host controller successfully.
+ @retval Others Some erros happen when sending this request to the host controller.
+
+**/
+EFI_STATUS
+SdMmcExecTrb (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ );
+
+/**
+ Check the TRB execution result.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The TRB is executed successfully.
+ @retval EFI_NOT_READY The TRB is not completed for execution.
+ @retval Others Some erros happen when executing this request.
+
+**/
+EFI_STATUS
+SdMmcCheckTrbResult (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ );
+
+/**
+ Wait for the TRB execution result.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The TRB is executed successfully.
+ @retval Others Some erros happen when executing this request.
+
+**/
+EFI_STATUS
+SdMmcWaitTrbResult (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ );
+
+/**
+ Execute EMMC device identification procedure.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS There is a EMMC card.
+ @retval Others There is not a EMMC card.
+
+**/
+EFI_STATUS
+EmmcIdentification (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot
+ );
+
+/**
+ Execute EMMC device identification procedure.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS There is a EMMC card.
+ @retval Others There is not a EMMC card.
+
+**/
+EFI_STATUS
+SdCardIdentification (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot
+ );
+
+#endif
diff --git a/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.inf b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.inf
new file mode 100644
index 0000000000..fad9fc610e
--- /dev/null
+++ b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.inf
@@ -0,0 +1,64 @@
+## @file
+# SdMmcPciHcDxe driver is used to manage those host controllers which comply with SD
+# Host Controller Simplified Specifiction version 3.0.
+#
+# It will produce EFI_SD_MMC_PASS_THRU_PROTOCOL to allow sending SD/MMC/eMMC cmds
+# to specified devices from upper layer.
+#
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+# Copyright (C) 2016 Marvell International Ltd. All rights reserved.<BR>
+#
+# 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 = 0x00010019
+ BASE_NAME = XenonDxe
+ MODULE_UNI_FILE = SdMmcPciHcDxe.uni
+ FILE_GUID = 17f56b40-f7c1-435c-ab8d-404872da951e
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeSdMmcPciHcDxe
+
+[Sources]
+ ComponentName.c
+ EmmcDevice.c
+ SdDevice.c
+ SdMmcPciHcDxe.c
+ SdMmcPciHcDxe.h
+ SdMmcPciHci.c
+ SdMmcPciHci.h
+ XenonSdhci.c
+ XenonSdhci.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+ UefiRuntimeServicesTableLib
+
+[Protocols]
+ gEfiDevicePathProtocolGuid ## TO_START
+ gEfiPciIoProtocolGuid ## TO_START
+ gEfiSdMmcPassThruProtocolGuid ## BY_START
+
+# [Event]
+# EVENT_TYPE_PERIODIC_TIMER ## SOMETIMES_CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SdMmcPciHcDxeExtra.uni
diff --git a/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.uni b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.uni
new file mode 100644
index 0000000000..57f9fa76a1
--- /dev/null
+++ b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.uni
@@ -0,0 +1,23 @@
+// /** @file
+// SdMmcPciHcDxe driver is used to manage those host controllers which comply with SD
+// Host Controller Simplified Specifiction version 3.0.
+//
+// It will produce EFI_SD_MMC_PASS_THRU_PROTOCOL to allow sending SD/MMC/eMMC cmds
+// to specified devices from upper layer.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// 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.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "SD/MMC Pci Host Controller driver to manage SD/MMC host controllers"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver follows the UEFI driver model and produces SD/MMC Pass Thru protocol for upper layer bus driver."
+
diff --git a/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxeExtra.uni b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxeExtra.uni
new file mode 100644
index 0000000000..c7aedb4cda
--- /dev/null
+++ b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxeExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// SdMmcPciHcDxe Localized Strings and Content
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// 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.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"SD/MMC Pci Host Controller Driver"
+
+
diff --git a/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHci.c b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHci.c
new file mode 100644
index 0000000000..ccbf355016
--- /dev/null
+++ b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHci.c
@@ -0,0 +1,1923 @@
+/** @file
+ This driver is used to manage SD/MMC PCI host controllers which are compliance
+ with SD Host Controller Simplified Specification version 3.00.
+
+ It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use.
+
+ Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+ 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 "SdMmcPciHcDxe.h"
+
+/**
+ Dump the content of SD/MMC host controller's Capability Register.
+
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Capability The buffer to store the capability data.
+
+**/
+VOID
+DumpCapabilityReg (
+ IN UINT8 Slot,
+ IN SD_MMC_HC_SLOT_CAP *Capability
+ )
+{
+ //
+ // Dump Capability Data
+ //
+ DEBUG ((DEBUG_INFO, " == Slot [%d] Capability is 0x%x ==\n", Slot, Capability));
+ DEBUG ((DEBUG_INFO, " Timeout Clk Freq %d%a\n", Capability->TimeoutFreq, (Capability->TimeoutUnit) ? "MHz" : "KHz"));
+ DEBUG ((DEBUG_INFO, " Base Clk Freq %dMHz\n", Capability->BaseClkFreq));
+ DEBUG ((DEBUG_INFO, " Max Blk Len %dbytes\n", 512 * (1 << Capability->MaxBlkLen)));
+ DEBUG ((DEBUG_INFO, " 8-bit Support %a\n", Capability->BusWidth8 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " ADMA2 Support %a\n", Capability->Adma2 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " HighSpeed Support %a\n", Capability->HighSpeed ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " SDMA Support %a\n", Capability->Sdma ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Suspend/Resume %a\n", Capability->SuspRes ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Voltage 3.3 %a\n", Capability->Voltage33 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Voltage 3.0 %a\n", Capability->Voltage30 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Voltage 1.8 %a\n", Capability->Voltage18 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " 64-bit Sys Bus %a\n", Capability->SysBus64 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Async Interrupt %a\n", Capability->AsyncInt ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " SlotType "));
+ if (Capability->SlotType == 0x00) {
+ DEBUG ((DEBUG_INFO, "%a\n", "Removable Slot"));
+ } else if (Capability->SlotType == 0x01) {
+ DEBUG ((DEBUG_INFO, "%a\n", "Embedded Slot"));
+ } else if (Capability->SlotType == 0x02) {
+ DEBUG ((DEBUG_INFO, "%a\n", "Shared Bus Slot"));
+ } else {
+ DEBUG ((DEBUG_INFO, "%a\n", "Reserved"));
+ }
+ DEBUG ((DEBUG_INFO, " SDR50 Support %a\n", Capability->Sdr50 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " SDR104 Support %a\n", Capability->Sdr104 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " DDR50 Support %a\n", Capability->Ddr50 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Driver Type A %a\n", Capability->DriverTypeA ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Driver Type C %a\n", Capability->DriverTypeC ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Driver Type D %a\n", Capability->DriverTypeD ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Driver Type 4 %a\n", Capability->DriverType4 ? "TRUE" : "FALSE"));
+ if (Capability->TimerCount == 0) {
+ DEBUG ((DEBUG_INFO, " Retuning TimerCnt Disabled\n", 2 * (Capability->TimerCount - 1)));
+ } else {
+ DEBUG ((DEBUG_INFO, " Retuning TimerCnt %dseconds\n", 2 * (Capability->TimerCount - 1)));
+ }
+ DEBUG ((DEBUG_INFO, " SDR50 Tuning %a\n", Capability->TuningSDR50 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Retuning Mode Mode %d\n", Capability->RetuningMod + 1));
+ DEBUG ((DEBUG_INFO, " Clock Multiplier M = %d\n", Capability->ClkMultiplier + 1));
+ DEBUG ((DEBUG_INFO, " HS 400 %a\n", Capability->Hs400 ? "TRUE" : "FALSE"));
+ return;
+}
+
+/**
+ Read SlotInfo register from SD/MMC host controller pci config space.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[out] FirstBar The buffer to store the first BAR value.
+ @param[out] SlotNum The buffer to store the supported slot number.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcHcGetSlotInfo (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ OUT UINT8 *FirstBar,
+ OUT UINT8 *SlotNum
+ )
+{
+ EFI_STATUS Status;
+ SD_MMC_HC_SLOT_INFO SlotInfo;
+
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ SD_MMC_HC_SLOT_OFFSET,
+ sizeof (SlotInfo),
+ &SlotInfo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *FirstBar = SlotInfo.FirstBar;
+ *SlotNum = SlotInfo.SlotNum + 1;
+ ASSERT ((*FirstBar + *SlotNum) < SD_MMC_HC_MAX_SLOT);
+ return EFI_SUCCESS;
+}
+
+/**
+ Read/Write specified SD/MMC host controller mmio register.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] BarIndex The BAR index of the standard PCI Configuration
+ header to use as the base address for the memory
+ operation to perform.
+ @param[in] Offset The offset within the selected BAR to start the
+ memory operation.
+ @param[in] Read A boolean to indicate it's read or write operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2 , 4 or 8 bytes.
+ @param[in, out] Data For read operations, the destination buffer to store
+ the results. For write operations, the source buffer
+ to write data from. The caller is responsible for
+ having ownership of the data buffer and ensuring its
+ size not less than Count bytes.
+
+ @retval EFI_INVALID_PARAMETER The PciIo or Data is NULL or the Count is not valid.
+ @retval EFI_SUCCESS The read/write operation succeeds.
+ @retval Others The read/write operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcHcRwMmio (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN BOOLEAN Read,
+ IN UINT8 Count,
+ IN OUT VOID *Data
+ )
+{
+ EFI_STATUS Status;
+
+ if ((PciIo == NULL) || (Data == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Count != 1) && (Count != 2) && (Count != 4) && (Count != 8)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Read) {
+ Status = PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ BarIndex,
+ (UINT64) Offset,
+ Count,
+ Data
+ );
+ } else {
+ Status = PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ BarIndex,
+ (UINT64) Offset,
+ Count,
+ Data
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Do OR operation with the value of the specified SD/MMC host controller mmio register.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] BarIndex The BAR index of the standard PCI Configuration
+ header to use as the base address for the memory
+ operation to perform.
+ @param[in] Offset The offset within the selected BAR to start the
+ memory operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2 , 4 or 8 bytes.
+ @param[in] OrData The pointer to the data used to do OR operation.
+ The caller is responsible for having ownership of
+ the data buffer and ensuring its size not less than
+ Count bytes.
+
+ @retval EFI_INVALID_PARAMETER The PciIo or OrData is NULL or the Count is not valid.
+ @retval EFI_SUCCESS The OR operation succeeds.
+ @retval Others The OR operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcHcOrMmio (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN UINT8 Count,
+ IN VOID *OrData
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Data;
+ UINT64 Or;
+
+ Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, TRUE, Count, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Count == 1) {
+ Or = *(UINT8*) OrData;
+ } else if (Count == 2) {
+ Or = *(UINT16*) OrData;
+ } else if (Count == 4) {
+ Or = *(UINT32*) OrData;
+ } else if (Count == 8) {
+ Or = *(UINT64*) OrData;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Data |= Or;
+ Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, FALSE, Count, &Data);
+
+ return Status;
+}
+
+/**
+ Do AND operation with the value of the specified SD/MMC host controller mmio register.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] BarIndex The BAR index of the standard PCI Configuration
+ header to use as the base address for the memory
+ operation to perform.
+ @param[in] Offset The offset within the selected BAR to start the
+ memory operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2 , 4 or 8 bytes.
+ @param[in] AndData The pointer to the data used to do AND operation.
+ The caller is responsible for having ownership of
+ the data buffer and ensuring its size not less than
+ Count bytes.
+
+ @retval EFI_INVALID_PARAMETER The PciIo or AndData is NULL or the Count is not valid.
+ @retval EFI_SUCCESS The AND operation succeeds.
+ @retval Others The AND operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcHcAndMmio (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN UINT8 Count,
+ IN VOID *AndData
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Data;
+ UINT64 And;
+
+ Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, TRUE, Count, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Count == 1) {
+ And = *(UINT8*) AndData;
+ } else if (Count == 2) {
+ And = *(UINT16*) AndData;
+ } else if (Count == 4) {
+ And = *(UINT32*) AndData;
+ } else if (Count == 8) {
+ And = *(UINT64*) AndData;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Data &= And;
+ Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, FALSE, Count, &Data);
+
+ return Status;
+}
+
+/**
+ Wait for the value of the specified MMIO register set to the test value.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] BarIndex The BAR index of the standard PCI Configuration
+ header to use as the base address for the memory
+ operation to perform.
+ @param[in] Offset The offset within the selected BAR to start the
+ memory operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2, 4 or 8 bytes.
+ @param[in] MaskValue The mask value of memory.
+ @param[in] TestValue The test value of memory.
+
+ @retval EFI_NOT_READY The MMIO register hasn't set to the expected value.
+ @retval EFI_SUCCESS The MMIO register has expected value.
+ @retval Others The MMIO operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcHcCheckMmioSet (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN UINT8 Count,
+ IN UINT64 MaskValue,
+ IN UINT64 TestValue
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Value;
+
+ //
+ // Access PCI MMIO space to see if the value is the tested one.
+ //
+ Value = 0;
+ Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, TRUE, Count, &Value);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Value &= MaskValue;
+
+ if (Value == TestValue) {
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_READY;
+}
+
+/**
+ Wait for the value of the specified MMIO register set to the test value.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] BarIndex The BAR index of the standard PCI Configuration
+ header to use as the base address for the memory
+ operation to perform.
+ @param[in] Offset The offset within the selected BAR to start the
+ memory operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2, 4 or 8 bytes.
+ @param[in] MaskValue The mask value of memory.
+ @param[in] TestValue The test value of memory.
+ @param[in] Timeout The time out value for wait memory set, uses 1
+ microsecond as a unit.
+
+ @retval EFI_TIMEOUT The MMIO register hasn't expected value in timeout
+ range.
+ @retval EFI_SUCCESS The MMIO register has expected value.
+ @retval Others The MMIO operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcHcWaitMmioSet (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN UINT8 Count,
+ IN UINT64 MaskValue,
+ IN UINT64 TestValue,
+ IN UINT64 Timeout
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN InfiniteWait;
+
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ while (InfiniteWait || (Timeout > 0)) {
+ Status = SdMmcHcCheckMmioSet (
+ PciIo,
+ BarIndex,
+ Offset,
+ Count,
+ MaskValue,
+ TestValue
+ );
+ if (Status != EFI_NOT_READY) {
+ return Status;
+ }
+
+ //
+ // Stall for 1 microsecond.
+ //
+ gBS->Stall (1);
+
+ Timeout--;
+ }
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Software reset the specified SD/MMC host controller and enable all interrupts.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The software reset executes successfully.
+ @retval Others The software reset fails.
+
+**/
+EFI_STATUS
+SdMmcHcReset (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ )
+{
+ EFI_STATUS Status;
+ UINT8 SwReset;
+
+ SwReset = 0xFF;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_SW_RST, FALSE, sizeof (SwReset), &SwReset);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "SdMmcHcReset: write full 1 fails: %r\n", Status));
+ return Status;
+ }
+
+ Status = SdMmcHcWaitMmioSet (
+ PciIo,
+ Slot,
+ SD_MMC_HC_SW_RST,
+ sizeof (SwReset),
+ 0xFF,
+ 0x00,
+ SD_MMC_HC_GENERIC_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "SdMmcHcReset: reset done with %r\n", Status));
+ return Status;
+ }
+ //
+ // Enable all interrupt after reset all.
+ //
+ Status = SdMmcHcEnableInterrupt (PciIo, Slot);
+
+ return Status;
+}
+
+/**
+ Set all interrupt status bits in Normal and Error Interrupt Status Enable
+ register.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdMmcHcEnableInterrupt (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ )
+{
+ EFI_STATUS Status;
+ UINT16 IntStatus;
+
+ //
+ // Enable all bits in Error Interrupt Status Enable Register
+ //
+ IntStatus = 0xFFFF;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_ERR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Enable all bits in Normal Interrupt Status Enable Register
+ //
+ IntStatus = 0xFFFF;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_NOR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);
+
+ return Status;
+}
+
+/**
+ Get the capability data from the specified slot.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[out] Capability The buffer to store the capability data.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdMmcHcGetCapability (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ OUT SD_MMC_HC_SLOT_CAP *Capability
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Cap;
+
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CAP, TRUE, sizeof (Cap), &Cap);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CopyMem (Capability, &Cap, sizeof (Cap));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the maximum current capability data from the specified slot.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[out] MaxCurrent The buffer to store the maximum current capability data.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdMmcHcGetMaxCurrent (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ OUT UINT64 *MaxCurrent
+ )
+{
+ EFI_STATUS Status;
+
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_MAX_CURRENT_CAP, TRUE, sizeof (UINT64), MaxCurrent);
+
+ return Status;
+}
+
+/**
+ Detect whether there is a SD/MMC card attached at the specified SD/MMC host controller
+ slot.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[out] MediaPresent The pointer to the media present boolean value.
+
+ @retval EFI_SUCCESS There is no media change happened.
+ @retval EFI_MEDIA_CHANGED There is media change happened.
+ @retval Others The detection fails.
+
+**/
+EFI_STATUS
+SdMmcHcCardDetect (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ OUT BOOLEAN *MediaPresent
+ )
+{
+ EFI_STATUS Status;
+ UINT16 Data;
+ UINT32 PresentState;
+
+ //
+ // Check Present State Register to see if there is a card presented.
+ //
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((PresentState & BIT16) != 0) {
+ *MediaPresent = TRUE;
+ } else {
+ *MediaPresent = FALSE;
+ }
+
+ //
+ // Check Normal Interrupt Status Register
+ //
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_NOR_INT_STS, TRUE, sizeof (Data), &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((Data & (BIT6 | BIT7)) != 0) {
+ //
+ // Clear BIT6 and BIT7 by writing 1 to these two bits if set.
+ //
+ Data &= BIT6 | BIT7;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_NOR_INT_STS, FALSE, sizeof (Data), &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_MEDIA_CHANGED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Stop SD/MMC card clock.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS Succeed to stop SD/MMC clock.
+ @retval Others Fail to stop SD/MMC clock.
+
+**/
+EFI_STATUS
+SdMmcHcStopClock (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ )
+{
+ EFI_STATUS Status;
+ UINT32 PresentState;
+ UINT16 ClockCtrl;
+
+ //
+ // Ensure no SD transactions are occurring on the SD Bus by
+ // waiting for Command Inhibit (DAT) and Command Inhibit (CMD)
+ // in the Present State register to be 0.
+ //
+ Status = SdMmcHcWaitMmioSet (
+ PciIo,
+ Slot,
+ SD_MMC_HC_PRESENT_STATE,
+ sizeof (PresentState),
+ BIT0 | BIT1,
+ 0,
+ SD_MMC_HC_GENERIC_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Set SD Clock Enable in the Clock Control register to 0
+ //
+ ClockCtrl = (UINT16)~BIT2;
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);
+
+ return Status;
+}
+
+/**
+ SD/MMC card clock supply.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] ClockFreq The max clock frequency to be set. The unit is KHz.
+ @param[in] Capability The capability of the slot.
+
+ @retval EFI_SUCCESS The clock is supplied successfully.
+ @retval Others The clock isn't supplied successfully.
+
+**/
+EFI_STATUS
+SdMmcHcClockSupply (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN UINT64 ClockFreq,
+ IN SD_MMC_HC_SLOT_CAP Capability
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BaseClkFreq;
+ UINT32 SettingFreq;
+ UINT32 Divisor;
+ UINT32 Remainder;
+ UINT16 ControllerVer;
+ UINT16 ClockCtrl;
+
+ //
+ // Calculate a divisor for SD clock frequency
+ //
+ ASSERT (Capability.BaseClkFreq != 0);
+
+ BaseClkFreq = Capability.BaseClkFreq;
+ if (ClockFreq == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ClockFreq > (BaseClkFreq * 1000)) {
+ ClockFreq = BaseClkFreq * 1000;
+ }
+
+ //
+ // Calculate the divisor of base frequency.
+ //
+ Divisor = 0;
+ SettingFreq = BaseClkFreq * 1000;
+ while (ClockFreq < SettingFreq) {
+ Divisor++;
+
+ SettingFreq = (BaseClkFreq * 1000) / (2 * Divisor);
+ Remainder = (BaseClkFreq * 1000) % (2 * Divisor);
+ if ((ClockFreq == SettingFreq) && (Remainder == 0)) {
+ break;
+ }
+ if ((ClockFreq == SettingFreq) && (Remainder != 0)) {
+ SettingFreq ++;
+ }
+ }
+
+ DEBUG ((DEBUG_INFO, "BaseClkFreq %dMHz Divisor %d ClockFreq %dKhz\n", BaseClkFreq, Divisor, ClockFreq));
+
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Set SDCLK Frequency Select and Internal Clock Enable fields in Clock Control register.
+ //
+ if ((ControllerVer & 0xFF) == 2) {
+ ASSERT (Divisor <= 0x3FF);
+ ClockCtrl = ((Divisor & 0xFF) << 8) | ((Divisor & 0x300) >> 2);
+ } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) {
+ //
+ // Only the most significant bit can be used as divisor.
+ //
+ if (((Divisor - 1) & Divisor) != 0) {
+ Divisor = 1 << (HighBitSet32 (Divisor) + 1);
+ }
+ ASSERT (Divisor <= 0x80);
+ ClockCtrl = (Divisor & 0xFF) << 8;
+ } else {
+ DEBUG ((DEBUG_ERROR, "Unknown SD Host Controller Spec version [0x%x]!!!\n", ControllerVer));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Stop bus clock at first
+ //
+ Status = SdMmcHcStopClock (PciIo, Slot);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Supply clock frequency with specified divisor
+ //
+ ClockCtrl |= BIT0;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, FALSE, sizeof (ClockCtrl), &ClockCtrl);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Set SDCLK Frequency Select and Internal Clock Enable fields fails\n"));
+ return Status;
+ }
+
+ //
+ // Wait Internal Clock Stable in the Clock Control register to be 1
+ //
+ Status = SdMmcHcWaitMmioSet (
+ PciIo,
+ Slot,
+ SD_MMC_HC_CLOCK_CTRL,
+ sizeof (ClockCtrl),
+ BIT1,
+ BIT1,
+ SD_MMC_HC_GENERIC_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Set SD Clock Enable in the Clock Control register to 1
+ //
+ ClockCtrl = BIT2;
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);
+
+ return Status;
+}
+
+/**
+ SD/MMC bus power control.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] PowerCtrl The value setting to the power control register.
+
+ @retval TRUE There is a SD/MMC card attached.
+ @retval FALSE There is no a SD/MMC card attached.
+
+**/
+EFI_STATUS
+SdMmcHcPowerControl (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN UINT8 PowerCtrl
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Clr SD Bus Power
+ //
+ PowerCtrl &= (UINT8)~BIT0;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register
+ //
+ PowerCtrl |= BIT0;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);
+
+ return Status;
+}
+
+/**
+ Set the SD/MMC bus width.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] BusWidth The bus width used by the SD/MMC device, it must be 1, 4 or 8.
+
+ @retval EFI_SUCCESS The bus width is set successfully.
+ @retval Others The bus width isn't set successfully.
+
+**/
+EFI_STATUS
+SdMmcHcSetBusWidth (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN UINT16 BusWidth
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HostCtrl1;
+
+ if (BusWidth == 1) {
+ HostCtrl1 = (UINT8)~(BIT5 | BIT1);
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ } else if (BusWidth == 4) {
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ HostCtrl1 |= BIT1;
+ HostCtrl1 &= (UINT8)~BIT5;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);
+ } else if (BusWidth == 8) {
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ HostCtrl1 &= (UINT8)~BIT1;
+ HostCtrl1 |= BIT5;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);
+ } else {
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return Status;
+}
+
+/**
+ Supply SD/MMC card with lowest clock frequency at initialization.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Capability The capability of the slot.
+
+ @retval EFI_SUCCESS The clock is supplied successfully.
+ @retval Others The clock isn't supplied successfully.
+
+**/
+EFI_STATUS
+SdMmcHcInitClockFreq (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN SD_MMC_HC_SLOT_CAP Capability
+ )
+{
+ EFI_STATUS Status;
+ UINT32 InitFreq;
+
+ //
+ // Calculate a divisor for SD clock frequency
+ //
+ if (Capability.BaseClkFreq == 0) {
+ //
+ // Don't support get Base Clock Frequency information via another method
+ //
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Supply 400KHz clock frequency at initialization phase.
+ //
+ InitFreq = 400;
+ Status = SdMmcHcClockSupply (PciIo, Slot, InitFreq, Capability);
+ return Status;
+}
+
+/**
+ Supply SD/MMC card with maximum voltage at initialization.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Capability The capability of the slot.
+
+ @retval EFI_SUCCESS The voltage is supplied successfully.
+ @retval Others The voltage isn't supplied successfully.
+
+**/
+EFI_STATUS
+SdMmcHcInitPowerVoltage (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN SD_MMC_HC_SLOT_CAP Capability
+ )
+{
+ EFI_STATUS Status;
+ UINT8 MaxVoltage;
+ UINT8 HostCtrl2;
+
+ //
+ // Calculate supported maximum voltage according to SD Bus Voltage Select
+ //
+ if (Capability.Voltage33 != 0) {
+ //
+ // Support 3.3V
+ //
+ MaxVoltage = 0x0E;
+ } else if (Capability.Voltage30 != 0) {
+ //
+ // Support 3.0V
+ //
+ MaxVoltage = 0x0C;
+ } else if (Capability.Voltage18 != 0) {
+ //
+ // Support 1.8V
+ //
+ MaxVoltage = 0x0A;
+ HostCtrl2 = BIT3;
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ gBS->Stall (5000);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ ASSERT (FALSE);
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register
+ //
+ Status = SdMmcHcPowerControl (PciIo, Slot, MaxVoltage);
+
+ return Status;
+}
+
+/**
+ Initialize the Timeout Control register with most conservative value at initialization.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The timeout control register is configured successfully.
+ @retval Others The timeout control register isn't configured successfully.
+
+**/
+EFI_STATUS
+SdMmcHcInitTimeoutCtrl (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Timeout;
+
+ Timeout = 0x0E;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_TIMEOUT_CTRL, FALSE, sizeof (Timeout), &Timeout);
+
+ return Status;
+}
+
+/**
+ Initial SD/MMC host controller with lowest clock frequency, max power and max timeout value
+ at initialization.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Capability The capability of the slot.
+
+ @retval EFI_SUCCESS The host controller is initialized successfully.
+ @retval Others The host controller isn't initialized successfully.
+
+**/
+EFI_STATUS
+SdMmcHcInitHost (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN SD_MMC_HC_SLOT_CAP Capability
+ )
+{
+ EFI_STATUS Status;
+
+ Status = SdMmcHcInitClockFreq (PciIo, Slot, Capability);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdMmcHcInitPowerVoltage (PciIo, Slot, Capability);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdMmcHcInitTimeoutCtrl (PciIo, Slot);
+ return Status;
+}
+
+/**
+ Turn on/off LED.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] On The boolean to turn on/off LED.
+
+ @retval EFI_SUCCESS The LED is turned on/off successfully.
+ @retval Others The LED isn't turned on/off successfully.
+
+**/
+EFI_STATUS
+SdMmcHcLedOnOff (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN BOOLEAN On
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HostCtrl1;
+
+ if (On) {
+ HostCtrl1 = BIT0;
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ } else {
+ HostCtrl1 = (UINT8)~BIT0;
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ }
+
+ return Status;
+}
+
+/**
+ Build ADMA descriptor table for transfer.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 1.13 for details.
+
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The ADMA descriptor table is created successfully.
+ @retval Others The ADMA descriptor table isn't created successfully.
+
+**/
+EFI_STATUS
+BuildAdmaDescTable (
+ IN SD_MMC_HC_TRB *Trb
+ )
+{
+ EFI_PHYSICAL_ADDRESS Data;
+ UINT64 DataLen;
+ UINT64 Entries;
+ UINT32 Index;
+ UINT64 Remaining;
+ UINT32 Address;
+ UINTN TableSize;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+ UINTN Bytes;
+
+ Data = Trb->DataPhy;
+ DataLen = Trb->DataLen;
+ PciIo = Trb->Private->PciIo;
+ //
+ // Only support 32bit ADMA Descriptor Table
+ //
+ if ((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Address field shall be set on 32-bit boundary (Lower 2-bit is always set to 0)
+ // for 32-bit address descriptor table.
+ //
+ if ((Data & (BIT0 | BIT1)) != 0) {
+ DEBUG ((DEBUG_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 4 bytes boundary!\n", Data));
+ }
+
+ Entries = DivU64x32 ((DataLen + ADMA_MAX_DATA_PER_LINE - 1), ADMA_MAX_DATA_PER_LINE);
+ TableSize = (UINTN)MultU64x32 (Entries, sizeof (SD_MMC_HC_ADMA_DESC_LINE));
+ Trb->AdmaPages = (UINT32)EFI_SIZE_TO_PAGES (TableSize);
+ Status = PciIo->AllocateBuffer (
+ PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ EFI_SIZE_TO_PAGES (TableSize),
+ (VOID **)&Trb->AdmaDesc,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ZeroMem (Trb->AdmaDesc, TableSize);
+ Bytes = TableSize;
+ Status = PciIo->Map (
+ PciIo,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ Trb->AdmaDesc,
+ &Bytes,
+ &Trb->AdmaDescPhy,
+ &Trb->AdmaMap
+ );
+
+ if (EFI_ERROR (Status) || (Bytes != TableSize)) {
+ //
+ // Map error or unable to map the whole RFis buffer into a contiguous region.
+ //
+ PciIo->FreeBuffer (
+ PciIo,
+ EFI_SIZE_TO_PAGES (TableSize),
+ Trb->AdmaDesc
+ );
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if ((UINT64)(UINTN)Trb->AdmaDescPhy > 0x100000000ul) {
+ //
+ // The ADMA doesn't support 64bit addressing.
+ //
+ PciIo->Unmap (
+ PciIo,
+ Trb->AdmaMap
+ );
+ PciIo->FreeBuffer (
+ PciIo,
+ EFI_SIZE_TO_PAGES (TableSize),
+ Trb->AdmaDesc
+ );
+ return EFI_DEVICE_ERROR;
+ }
+
+ Remaining = DataLen;
+ Address = (UINT32)Data;
+ for (Index = 0; Index < Entries; Index++) {
+ if (Remaining <= ADMA_MAX_DATA_PER_LINE) {
+ Trb->AdmaDesc[Index].Valid = 1;
+ Trb->AdmaDesc[Index].Act = 2;
+ Trb->AdmaDesc[Index].Length = (UINT16)Remaining;
+ Trb->AdmaDesc[Index].Address = Address;
+ break;
+ } else {
+ Trb->AdmaDesc[Index].Valid = 1;
+ Trb->AdmaDesc[Index].Act = 2;
+ Trb->AdmaDesc[Index].Length = 0;
+ Trb->AdmaDesc[Index].Address = Address;
+ }
+
+ Remaining -= ADMA_MAX_DATA_PER_LINE;
+ Address += ADMA_MAX_DATA_PER_LINE;
+ }
+
+ //
+ // Set the last descriptor line as end of descriptor table
+ //
+ Trb->AdmaDesc[Index].End = 1;
+ return EFI_SUCCESS;
+}
+
+/**
+ Create a new TRB for the SD/MMC cmd request.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Packet A pointer to the SD command data structure.
+ @param[in] Event If Event is NULL, blocking I/O is performed. If Event is
+ not NULL, then nonblocking I/O is performed, and Event
+ will be signaled when the Packet completes.
+
+ @return Created Trb or NULL.
+
+**/
+SD_MMC_HC_TRB *
+SdMmcCreateTrb (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot,
+ IN EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,
+ IN EFI_EVENT Event
+ )
+{
+ SD_MMC_HC_TRB *Trb;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+ EFI_PCI_IO_PROTOCOL_OPERATION Flag;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINTN MapLength;
+
+ Trb = AllocateZeroPool (sizeof (SD_MMC_HC_TRB));
+ if (Trb == NULL) {
+ return NULL;
+ }
+
+ Trb->Signature = SD_MMC_HC_TRB_SIG;
+ Trb->Slot = Slot;
+ Trb->BlockSize = 0x200;
+ Trb->Packet = Packet;
+ Trb->Event = Event;
+ Trb->Started = FALSE;
+ Trb->Timeout = Packet->Timeout;
+ Trb->Private = Private;
+
+ if ((Packet->InTransferLength != 0) && (Packet->InDataBuffer != NULL)) {
+ Trb->Data = Packet->InDataBuffer;
+ Trb->DataLen = Packet->InTransferLength;
+ Trb->Read = TRUE;
+ } else if ((Packet->OutTransferLength != 0) && (Packet->OutDataBuffer != NULL)) {
+ Trb->Data = Packet->OutDataBuffer;
+ Trb->DataLen = Packet->OutTransferLength;
+ Trb->Read = FALSE;
+ } else if ((Packet->InTransferLength == 0) && (Packet->OutTransferLength == 0)) {
+ Trb->Data = NULL;
+ Trb->DataLen = 0;
+ } else {
+ goto Error;
+ }
+
+ if (Trb->DataLen < Trb->BlockSize) {
+ Trb->BlockSize = (UINT16)Trb->DataLen;
+ }
+
+ if (((Private->Slot[Trb->Slot].CardType == EmmcCardType) &&
+ (Packet->SdMmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK)) ||
+ ((Private->Slot[Trb->Slot].CardType == SdCardType) &&
+ (Packet->SdMmcCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK))) {
+ Trb->Mode = SdMmcPioMode;
+ } else {
+ if (Trb->Read) {
+ Flag = EfiPciIoOperationBusMasterWrite;
+ } else {
+ Flag = EfiPciIoOperationBusMasterRead;
+ }
+
+ PciIo = Private->PciIo;
+ if (Trb->DataLen != 0) {
+ MapLength = Trb->DataLen;
+ Status = PciIo->Map (
+ PciIo,
+ Flag,
+ Trb->Data,
+ &MapLength,
+ &Trb->DataPhy,
+ &Trb->DataMap
+ );
+ if (EFI_ERROR (Status) || (Trb->DataLen != MapLength)) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ goto Error;
+ }
+ }
+
+ if (Trb->DataLen == 0) {
+ Trb->Mode = SdMmcNoData;
+ } else if (Private->Capability[Slot].Adma2 != 0) {
+ Trb->Mode = SdMmcAdmaMode;
+ Status = BuildAdmaDescTable (Trb);
+ if (EFI_ERROR (Status)) {
+ PciIo->Unmap (PciIo, Trb->DataMap);
+ goto Error;
+ }
+ } else if (Private->Capability[Slot].Sdma != 0) {
+ Trb->Mode = SdMmcSdmaMode;
+ } else {
+ Trb->Mode = SdMmcPioMode;
+ }
+ }
+
+ if (Event != NULL) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Private->Queue, &Trb->TrbList);
+ gBS->RestoreTPL (OldTpl);
+ }
+
+ return Trb;
+
+Error:
+ SdMmcFreeTrb (Trb);
+ return NULL;
+}
+
+/**
+ Free the resource used by the TRB.
+
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+**/
+VOID
+SdMmcFreeTrb (
+ IN SD_MMC_HC_TRB *Trb
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ PciIo = Trb->Private->PciIo;
+
+ if (Trb->AdmaMap != NULL) {
+ PciIo->Unmap (
+ PciIo,
+ Trb->AdmaMap
+ );
+ }
+ if (Trb->AdmaDesc != NULL) {
+ PciIo->FreeBuffer (
+ PciIo,
+ Trb->AdmaPages,
+ Trb->AdmaDesc
+ );
+ }
+ if (Trb->DataMap != NULL) {
+ PciIo->Unmap (
+ PciIo,
+ Trb->DataMap
+ );
+ }
+ FreePool (Trb);
+ return;
+}
+
+/**
+ Check if the env is ready for execute specified TRB.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The env is ready for TRB execution.
+ @retval EFI_NOT_READY The env is not ready for TRB execution.
+ @retval Others Some erros happen.
+
+**/
+EFI_STATUS
+SdMmcCheckTrbEnv (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT32 PresentState;
+
+ Packet = Trb->Packet;
+
+ if ((Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAdtc) ||
+ (Packet->SdMmcCmdBlk->ResponseType == SdMmcResponseTypeR1b) ||
+ (Packet->SdMmcCmdBlk->ResponseType == SdMmcResponseTypeR5b)) {
+ //
+ // Wait Command Inhibit (CMD) and Command Inhibit (DAT) in
+ // the Present State register to be 0
+ //
+ PresentState = BIT0 | BIT1;
+ } else {
+ //
+ // Wait Command Inhibit (CMD) in the Present State register
+ // to be 0
+ //
+ PresentState = BIT0;
+ }
+
+ PciIo = Private->PciIo;
+ Status = SdMmcHcCheckMmioSet (
+ PciIo,
+ Trb->Slot,
+ SD_MMC_HC_PRESENT_STATE,
+ sizeof (PresentState),
+ PresentState,
+ 0
+ );
+
+ return Status;
+}
+
+/**
+ Wait for the env to be ready for execute specified TRB.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The env is ready for TRB execution.
+ @retval EFI_TIMEOUT The env is not ready for TRB execution in time.
+ @retval Others Some erros happen.
+
+**/
+EFI_STATUS
+SdMmcWaitTrbEnv (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ UINT64 Timeout;
+ BOOLEAN InfiniteWait;
+
+ //
+ // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register
+ //
+ Packet = Trb->Packet;
+ Timeout = Packet->Timeout;
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ while (InfiniteWait || (Timeout > 0)) {
+ //
+ // Check Trb execution result by reading Normal Interrupt Status register.
+ //
+ Status = SdMmcCheckTrbEnv (Private, Trb);
+ if (Status != EFI_NOT_READY) {
+ return Status;
+ }
+ //
+ // Stall for 1 microsecond.
+ //
+ gBS->Stall (1);
+
+ Timeout--;
+ }
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Execute the specified TRB.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The TRB is sent to host controller successfully.
+ @retval Others Some erros happen when sending this request to the host controller.
+
+**/
+EFI_STATUS
+SdMmcExecTrb (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT16 Cmd;
+ UINT16 IntStatus;
+ UINT32 Argument;
+ UINT16 BlkCount;
+ UINT16 BlkSize;
+ UINT16 TransMode;
+ UINT8 HostCtrl1;
+ UINT32 SdmaAddr;
+ UINT64 AdmaAddr;
+
+ Packet = Trb->Packet;
+ PciIo = Trb->Private->PciIo;
+ //
+ // Clear all bits in Error Interrupt Status Register
+ //
+ IntStatus = 0xFFFF;
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_ERR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Clear all bits in Normal Interrupt Status Register excepts for Card Removal & Card Insertion bits.
+ //
+ IntStatus = 0xFF3F;
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Set Host Control 1 register DMA Select field
+ //
+ if (Trb->Mode == SdMmcAdmaMode) {
+ HostCtrl1 = BIT4;
+ Status = SdMmcHcOrMmio (PciIo, Trb->Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ SdMmcHcLedOnOff (PciIo, Trb->Slot, TRUE);
+
+ if (Trb->Mode == SdMmcSdmaMode) {
+ if ((UINT64)(UINTN)Trb->DataPhy >= 0x100000000ul) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SdmaAddr = (UINT32)(UINTN)Trb->DataPhy;
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_SDMA_ADDR, FALSE, sizeof (SdmaAddr), &SdmaAddr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else if (Trb->Mode == SdMmcAdmaMode) {
+ AdmaAddr = (UINT64)(UINTN)Trb->AdmaDescPhy;
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_ADMA_SYS_ADDR, FALSE, sizeof (AdmaAddr), &AdmaAddr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ BlkSize = Trb->BlockSize;
+ if (Trb->Mode == SdMmcSdmaMode) {
+ //
+ // Set SDMA boundary to be 512K bytes.
+ //
+ BlkSize |= 0x7000;
+ }
+
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_BLK_SIZE, FALSE, sizeof (BlkSize), &BlkSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BlkCount = 0;
+ if (Trb->Mode != SdMmcNoData) {
+ //
+ // Calcuate Block Count.
+ //
+ BlkCount = (UINT16)(Trb->DataLen / Trb->BlockSize);
+ }
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_BLK_COUNT, FALSE, sizeof (BlkCount), &BlkCount);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Argument = Packet->SdMmcCmdBlk->CommandArgument;
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_ARG1, FALSE, sizeof (Argument), &Argument);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ TransMode = 0;
+ if (Trb->Mode != SdMmcNoData) {
+ if (Trb->Mode != SdMmcPioMode) {
+ TransMode |= BIT0;
+ }
+ if (Trb->Read) {
+ TransMode |= BIT4;
+ }
+ if (BlkCount > 1) {
+ TransMode |= BIT5 | BIT1;
+ }
+ //
+ // Only SD memory card needs to use AUTO CMD12 feature.
+ //
+ if (Private->Slot[Trb->Slot].CardType == SdCardType) {
+ if (BlkCount > 1) {
+ TransMode |= BIT2;
+ }
+ }
+ }
+
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_TRANS_MOD, FALSE, sizeof (TransMode), &TransMode);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Cmd = (UINT16)LShiftU64(Packet->SdMmcCmdBlk->CommandIndex, 8);
+ if (Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAdtc) {
+ Cmd |= BIT5;
+ }
+ //
+ // Convert ResponseType to value
+ //
+ if (Packet->SdMmcCmdBlk->CommandType != SdMmcCommandTypeBc) {
+ switch (Packet->SdMmcCmdBlk->ResponseType) {
+ case SdMmcResponseTypeR1:
+ case SdMmcResponseTypeR5:
+ case SdMmcResponseTypeR6:
+ case SdMmcResponseTypeR7:
+ Cmd |= (BIT1 | BIT3 | BIT4);
+ break;
+ case SdMmcResponseTypeR2:
+ Cmd |= (BIT0 | BIT3);
+ break;
+ case SdMmcResponseTypeR3:
+ case SdMmcResponseTypeR4:
+ Cmd |= BIT1;
+ break;
+ case SdMmcResponseTypeR1b:
+ case SdMmcResponseTypeR5b:
+ Cmd |= (BIT0 | BIT1 | BIT3 | BIT4);
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ }
+ //
+ // Execute cmd
+ //
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_COMMAND, FALSE, sizeof (Cmd), &Cmd);
+ return Status;
+}
+
+/**
+ Check the TRB execution result.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The TRB is executed successfully.
+ @retval EFI_NOT_READY The TRB is not completed for execution.
+ @retval Others Some erros happen when executing this request.
+
+**/
+EFI_STATUS
+SdMmcCheckTrbResult (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ UINT16 IntStatus;
+ UINT32 Response[4];
+ UINT32 SdmaAddr;
+ UINT8 Index;
+ UINT8 SwReset;
+ UINT32 PioLength;
+
+ SwReset = 0;
+ Packet = Trb->Packet;
+ //
+ // Check Trb execution result by reading Normal Interrupt Status register.
+ //
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Trb->Slot,
+ SD_MMC_HC_NOR_INT_STS,
+ TRUE,
+ sizeof (IntStatus),
+ &IntStatus
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Check Transfer Complete bit is set or not.
+ //
+ if ((IntStatus & BIT1) == BIT1) {
+ if ((IntStatus & BIT15) == BIT15) {
+ //
+ // Read Error Interrupt Status register to check if the error is
+ // Data Timeout Error.
+ // If yes, treat it as success as Transfer Complete has higher
+ // priority than Data Timeout Error.
+ //
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Trb->Slot,
+ SD_MMC_HC_ERR_INT_STS,
+ TRUE,
+ sizeof (IntStatus),
+ &IntStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ if ((IntStatus & BIT4) == BIT4) {
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+ }
+ }
+
+ goto Done;
+ }
+ //
+ // Check if there is a error happened during cmd execution.
+ // If yes, then do error recovery procedure to follow SD Host Controller
+ // Simplified Spec 3.0 section 3.10.1.
+ //
+ if ((IntStatus & BIT15) == BIT15) {
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Trb->Slot,
+ SD_MMC_HC_ERR_INT_STS,
+ TRUE,
+ sizeof (IntStatus),
+ &IntStatus
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if ((IntStatus & 0x0F) != 0) {
+ SwReset |= BIT1;
+ }
+ if ((IntStatus & 0xF0) != 0) {
+ SwReset |= BIT2;
+ }
+
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Trb->Slot,
+ SD_MMC_HC_SW_RST,
+ FALSE,
+ sizeof (SwReset),
+ &SwReset
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ Status = SdMmcHcWaitMmioSet (
+ Private->PciIo,
+ Trb->Slot,
+ SD_MMC_HC_SW_RST,
+ sizeof (SwReset),
+ 0xFF,
+ 0,
+ SD_MMC_HC_GENERIC_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+ //
+ // Check if DMA interrupt is signalled for the SDMA transfer.
+ //
+ if ((Trb->Mode == SdMmcSdmaMode) && ((IntStatus & BIT3) == BIT3)) {
+ //
+ // Clear DMA interrupt bit.
+ //
+ IntStatus = BIT3;
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Trb->Slot,
+ SD_MMC_HC_NOR_INT_STS,
+ FALSE,
+ sizeof (IntStatus),
+ &IntStatus
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Update SDMA Address register.
+ //
+ SdmaAddr = SD_MMC_SDMA_ROUND_UP ((UINT32)(UINTN)Trb->DataPhy, SD_MMC_SDMA_BOUNDARY);
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Trb->Slot,
+ SD_MMC_HC_SDMA_ADDR,
+ FALSE,
+ sizeof (UINT32),
+ &SdmaAddr
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ Trb->DataPhy = (UINT32)(UINTN)SdmaAddr;
+ }
+
+ if ((Packet->SdMmcCmdBlk->CommandType != SdMmcCommandTypeAdtc) &&
+ (Packet->SdMmcCmdBlk->ResponseType != SdMmcResponseTypeR1b) &&
+ (Packet->SdMmcCmdBlk->ResponseType != SdMmcResponseTypeR5b)) {
+ if ((IntStatus & BIT0) == BIT0) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+ }
+
+ if (((Private->Slot[Trb->Slot].CardType == EmmcCardType) &&
+ (Packet->SdMmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK)) ||
+ ((Private->Slot[Trb->Slot].CardType == SdCardType) &&
+ (Packet->SdMmcCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK))) {
+ //
+ // When performing tuning procedure (Execute Tuning is set to 1) through PIO mode,
+ // wait Buffer Read Ready bit of Normal Interrupt Status Register to be 1.
+ // Refer to SD Host Controller Simplified Specification 3.0 figure 2-29 for details.
+ //
+ if ((IntStatus & BIT5) == BIT5) {
+ //
+ // Clear Buffer Read Ready interrupt at first.
+ //
+ IntStatus = BIT5;
+ SdMmcHcRwMmio (Private->PciIo, Trb->Slot, SD_MMC_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);
+ //
+ // Read data out from Buffer Port register
+ //
+ for (PioLength = 0; PioLength < Trb->DataLen; PioLength += 4) {
+ SdMmcHcRwMmio (Private->PciIo, Trb->Slot, SD_MMC_HC_BUF_DAT_PORT, TRUE, 4, (UINT8*)Trb->Data + PioLength);
+ }
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+ }
+
+ Status = EFI_NOT_READY;
+Done:
+ //
+ // Get response data when the cmd is executed successfully.
+ //
+ if (!EFI_ERROR (Status)) {
+ if (Packet->SdMmcCmdBlk->CommandType != SdMmcCommandTypeBc) {
+ for (Index = 0; Index < 4; Index++) {
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Trb->Slot,
+ SD_MMC_HC_RESPONSE + Index * 4,
+ TRUE,
+ sizeof (UINT32),
+ &Response[Index]
+ );
+ if (EFI_ERROR (Status)) {
+ SdMmcHcLedOnOff (Private->PciIo, Trb->Slot, FALSE);
+ return Status;
+ }
+ }
+ CopyMem (Packet->SdMmcStatusBlk, Response, sizeof (Response));
+ }
+ }
+
+ if (Status != EFI_NOT_READY) {
+ SdMmcHcLedOnOff (Private->PciIo, Trb->Slot, FALSE);
+ }
+
+ return Status;
+}
+
+/**
+ Wait for the TRB execution result.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The TRB is executed successfully.
+ @retval Others Some erros happen when executing this request.
+
+**/
+EFI_STATUS
+SdMmcWaitTrbResult (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ UINT64 Timeout;
+ BOOLEAN InfiniteWait;
+
+ Packet = Trb->Packet;
+ //
+ // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register
+ //
+ Timeout = Packet->Timeout;
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ while (InfiniteWait || (Timeout > 0)) {
+ //
+ // Check Trb execution result by reading Normal Interrupt Status register.
+ //
+ Status = SdMmcCheckTrbResult (Private, Trb);
+ if (Status != EFI_NOT_READY) {
+ return Status;
+ }
+ //
+ // Stall for 1 microsecond.
+ //
+ gBS->Stall (1);
+
+ Timeout--;
+ }
+
+ return EFI_TIMEOUT;
+}
+
diff --git a/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHci.h b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHci.h
new file mode 100644
index 0000000000..fb62758602
--- /dev/null
+++ b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHci.h
@@ -0,0 +1,546 @@
+/** @file
+
+ Provides some data structure definitions used by the SD/MMC host controller driver.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+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.
+
+**/
+
+#ifndef _SD_MMC_PCI_HCI_H_
+#define _SD_MMC_PCI_HCI_H_
+
+//
+// SD Host Controller SlotInfo Register Offset
+//
+#define SD_MMC_HC_SLOT_OFFSET 0x40
+
+#define SD_MMC_HC_MAX_SLOT 6
+
+//
+// SD Host Controller MMIO Register Offset
+//
+#define SD_MMC_HC_SDMA_ADDR 0x00
+#define SD_MMC_HC_ARG2 0x00
+#define SD_MMC_HC_BLK_SIZE 0x04
+#define SD_MMC_HC_BLK_COUNT 0x06
+#define SD_MMC_HC_ARG1 0x08
+#define SD_MMC_HC_TRANS_MOD 0x0C
+#define SD_MMC_HC_COMMAND 0x0E
+#define SD_MMC_HC_RESPONSE 0x10
+#define SD_MMC_HC_BUF_DAT_PORT 0x20
+#define SD_MMC_HC_PRESENT_STATE 0x24
+#define SD_MMC_HC_HOST_CTRL1 0x28
+#define SD_MMC_HC_POWER_CTRL 0x29
+#define SD_MMC_HC_BLK_GAP_CTRL 0x2A
+#define SD_MMC_HC_WAKEUP_CTRL 0x2B
+#define SD_MMC_HC_CLOCK_CTRL 0x2C
+#define SD_MMC_HC_TIMEOUT_CTRL 0x2E
+#define SD_MMC_HC_SW_RST 0x2F
+#define SD_MMC_HC_NOR_INT_STS 0x30
+#define SD_MMC_HC_ERR_INT_STS 0x32
+#define SD_MMC_HC_NOR_INT_STS_EN 0x34
+#define SD_MMC_HC_ERR_INT_STS_EN 0x36
+#define SD_MMC_HC_NOR_INT_SIG_EN 0x38
+#define SD_MMC_HC_ERR_INT_SIG_EN 0x3A
+#define SD_MMC_HC_AUTO_CMD_ERR_STS 0x3C
+#define SD_MMC_HC_HOST_CTRL2 0x3E
+#define SD_MMC_HC_CAP 0x40
+#define SD_MMC_HC_MAX_CURRENT_CAP 0x48
+#define SD_MMC_HC_FORCE_EVT_AUTO_CMD 0x50
+#define SD_MMC_HC_FORCE_EVT_ERR_INT 0x52
+#define SD_MMC_HC_ADMA_ERR_STS 0x54
+#define SD_MMC_HC_ADMA_SYS_ADDR 0x58
+#define SD_MMC_HC_PRESET_VAL 0x60
+#define SD_MMC_HC_SHARED_BUS_CTRL 0xE0
+#define SD_MMC_HC_SLOT_INT_STS 0xFC
+#define SD_MMC_HC_CTRL_VER 0xFE
+
+//
+// The transfer modes supported by SD Host Controller
+// Simplified Spec 3.0 Table 1-2
+//
+typedef enum {
+ SdMmcNoData,
+ SdMmcPioMode,
+ SdMmcSdmaMode,
+ SdMmcAdmaMode
+} SD_MMC_HC_TRANSFER_MODE;
+
+//
+// The maximum data length of each descriptor line
+//
+#define ADMA_MAX_DATA_PER_LINE 0x10000
+
+typedef struct {
+ UINT32 Valid:1;
+ UINT32 End:1;
+ UINT32 Int:1;
+ UINT32 Reserved:1;
+ UINT32 Act:2;
+ UINT32 Reserved1:10;
+ UINT32 Length:16;
+ UINT32 Address;
+} SD_MMC_HC_ADMA_DESC_LINE;
+
+#define SD_MMC_SDMA_BOUNDARY 512 * 1024
+#define SD_MMC_SDMA_ROUND_UP(x, n) (((x) + n) & ~(n - 1))
+
+typedef struct {
+ UINT8 FirstBar:3; // bit 0:2
+ UINT8 Reserved:1; // bit 3
+ UINT8 SlotNum:3; // bit 4:6
+ UINT8 Reserved1:1; // bit 7
+} SD_MMC_HC_SLOT_INFO;
+
+typedef struct {
+ UINT32 TimeoutFreq:6; // bit 0:5
+ UINT32 Reserved:1; // bit 6
+ UINT32 TimeoutUnit:1; // bit 7
+ UINT32 BaseClkFreq:8; // bit 8:15
+ UINT32 MaxBlkLen:2; // bit 16:17
+ UINT32 BusWidth8:1; // bit 18
+ UINT32 Adma2:1; // bit 19
+ UINT32 Reserved2:1; // bit 20
+ UINT32 HighSpeed:1; // bit 21
+ UINT32 Sdma:1; // bit 22
+ UINT32 SuspRes:1; // bit 23
+ UINT32 Voltage33:1; // bit 24
+ UINT32 Voltage30:1; // bit 25
+ UINT32 Voltage18:1; // bit 26
+ UINT32 Reserved3:1; // bit 27
+ UINT32 SysBus64:1; // bit 28
+ UINT32 AsyncInt:1; // bit 29
+ UINT32 SlotType:2; // bit 30:31
+ UINT32 Sdr50:1; // bit 32
+ UINT32 Sdr104:1; // bit 33
+ UINT32 Ddr50:1; // bit 34
+ UINT32 Reserved4:1; // bit 35
+ UINT32 DriverTypeA:1; // bit 36
+ UINT32 DriverTypeC:1; // bit 37
+ UINT32 DriverTypeD:1; // bit 38
+ UINT32 DriverType4:1; // bit 39
+ UINT32 TimerCount:4; // bit 40:43
+ UINT32 Reserved5:1; // bit 44
+ UINT32 TuningSDR50:1; // bit 45
+ UINT32 RetuningMod:2; // bit 46:47
+ UINT32 ClkMultiplier:8; // bit 48:55
+ UINT32 Reserved6:7; // bit 56:62
+ UINT32 Hs400:1; // bit 63
+} SD_MMC_HC_SLOT_CAP;
+
+/**
+ Dump the content of SD/MMC host controller's Capability Register.
+
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Capability The buffer to store the capability data.
+
+**/
+VOID
+DumpCapabilityReg (
+ IN UINT8 Slot,
+ IN SD_MMC_HC_SLOT_CAP *Capability
+ );
+
+/**
+ Read SlotInfo register from SD/MMC host controller pci config space.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[out] FirstBar The buffer to store the first BAR value.
+ @param[out] SlotNum The buffer to store the supported slot number.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcHcGetSlotInfo (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ OUT UINT8 *FirstBar,
+ OUT UINT8 *SlotNum
+ );
+
+/**
+ Read/Write specified SD/MMC host controller mmio register.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] BarIndex The BAR index of the standard PCI Configuration
+ header to use as the base address for the memory
+ operation to perform.
+ @param[in] Offset The offset within the selected BAR to start the
+ memory operation.
+ @param[in] Read A boolean to indicate it's read or write operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2 , 4 or 8 bytes.
+ @param[in, out] Data For read operations, the destination buffer to store
+ the results. For write operations, the source buffer
+ to write data from. The caller is responsible for
+ having ownership of the data buffer and ensuring its
+ size not less than Count bytes.
+
+ @retval EFI_INVALID_PARAMETER The PciIo or Data is NULL or the Count is not valid.
+ @retval EFI_SUCCESS The read/write operation succeeds.
+ @retval Others The read/write operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcHcRwMmio (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN BOOLEAN Read,
+ IN UINT8 Count,
+ IN OUT VOID *Data
+ );
+
+/**
+ Do OR operation with the value of the specified SD/MMC host controller mmio register.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] BarIndex The BAR index of the standard PCI Configuration
+ header to use as the base address for the memory
+ operation to perform.
+ @param[in] Offset The offset within the selected BAR to start the
+ memory operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2 , 4 or 8 bytes.
+ @param[in] OrData The pointer to the data used to do OR operation.
+ The caller is responsible for having ownership of
+ the data buffer and ensuring its size not less than
+ Count bytes.
+
+ @retval EFI_INVALID_PARAMETER The PciIo or OrData is NULL or the Count is not valid.
+ @retval EFI_SUCCESS The OR operation succeeds.
+ @retval Others The OR operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcHcOrMmio (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN UINT8 Count,
+ IN VOID *OrData
+ );
+
+/**
+ Do AND operation with the value of the specified SD/MMC host controller mmio register.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] BarIndex The BAR index of the standard PCI Configuration
+ header to use as the base address for the memory
+ operation to perform.
+ @param[in] Offset The offset within the selected BAR to start the
+ memory operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2 , 4 or 8 bytes.
+ @param[in] AndData The pointer to the data used to do AND operation.
+ The caller is responsible for having ownership of
+ the data buffer and ensuring its size not less than
+ Count bytes.
+
+ @retval EFI_INVALID_PARAMETER The PciIo or AndData is NULL or the Count is not valid.
+ @retval EFI_SUCCESS The AND operation succeeds.
+ @retval Others The AND operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcHcAndMmio (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN UINT8 Count,
+ IN VOID *AndData
+ );
+
+/**
+ Wait for the value of the specified MMIO register set to the test value.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] BarIndex The BAR index of the standard PCI Configuration
+ header to use as the base address for the memory
+ operation to perform.
+ @param[in] Offset The offset within the selected BAR to start the
+ memory operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2, 4 or 8 bytes.
+ @param[in] MaskValue The mask value of memory.
+ @param[in] TestValue The test value of memory.
+ @param[in] Timeout The time out value for wait memory set, uses 1
+ microsecond as a unit.
+
+ @retval EFI_TIMEOUT The MMIO register hasn't expected value in timeout
+ range.
+ @retval EFI_SUCCESS The MMIO register has expected value.
+ @retval Others The MMIO operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcHcWaitMmioSet (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN UINT8 Count,
+ IN UINT64 MaskValue,
+ IN UINT64 TestValue,
+ IN UINT64 Timeout
+ );
+
+/**
+ Software reset the specified SD/MMC host controller.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The software reset executes successfully.
+ @retval Others The software reset fails.
+
+**/
+EFI_STATUS
+SdMmcHcReset (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ );
+
+/**
+ Set all interrupt status bits in Normal and Error Interrupt Status Enable
+ register.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdMmcHcEnableInterrupt (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ );
+
+/**
+ Get the capability data from the specified slot.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[out] Capability The buffer to store the capability data.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdMmcHcGetCapability (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ OUT SD_MMC_HC_SLOT_CAP *Capability
+ );
+
+/**
+ Get the maximum current capability data from the specified slot.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[out] MaxCurrent The buffer to store the maximum current capability data.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdMmcHcGetMaxCurrent (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ OUT UINT64 *MaxCurrent
+ );
+
+/**
+ Detect whether there is a SD/MMC card attached at the specified SD/MMC host controller
+ slot.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[out] MediaPresent The pointer to the media present boolean value.
+
+ @retval EFI_SUCCESS There is no media change happened.
+ @retval EFI_MEDIA_CHANGED There is media change happened.
+ @retval Others The detection fails.
+
+**/
+EFI_STATUS
+SdMmcHcCardDetect (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ OUT BOOLEAN *MediaPresent
+ );
+
+/**
+ Stop SD/MMC card clock.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS Succeed to stop SD/MMC clock.
+ @retval Others Fail to stop SD/MMC clock.
+
+**/
+EFI_STATUS
+SdMmcHcStopClock (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ );
+
+/**
+ SD/MMC card clock supply.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] ClockFreq The max clock frequency to be set. The unit is KHz.
+ @param[in] Capability The capability of the slot.
+
+ @retval EFI_SUCCESS The clock is supplied successfully.
+ @retval Others The clock isn't supplied successfully.
+
+**/
+EFI_STATUS
+SdMmcHcClockSupply (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN UINT64 ClockFreq,
+ IN SD_MMC_HC_SLOT_CAP Capability
+ );
+
+/**
+ SD/MMC bus power control.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] PowerCtrl The value setting to the power control register.
+
+ @retval TRUE There is a SD/MMC card attached.
+ @retval FALSE There is no a SD/MMC card attached.
+
+**/
+EFI_STATUS
+SdMmcHcPowerControl (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN UINT8 PowerCtrl
+ );
+
+/**
+ Set the SD/MMC bus width.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] BusWidth The bus width used by the SD/MMC device, it must be 1, 4 or 8.
+
+ @retval EFI_SUCCESS The bus width is set successfully.
+ @retval Others The bus width isn't set successfully.
+
+**/
+EFI_STATUS
+SdMmcHcSetBusWidth (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN UINT16 BusWidth
+ );
+
+/**
+ Supply SD/MMC card with lowest clock frequency at initialization.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Capability The capability of the slot.
+
+ @retval EFI_SUCCESS The clock is supplied successfully.
+ @retval Others The clock isn't supplied successfully.
+
+**/
+EFI_STATUS
+SdMmcHcInitClockFreq (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN SD_MMC_HC_SLOT_CAP Capability
+ );
+
+/**
+ Supply SD/MMC card with maximum voltage at initialization.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Capability The capability of the slot.
+
+ @retval EFI_SUCCESS The voltage is supplied successfully.
+ @retval Others The voltage isn't supplied successfully.
+
+**/
+EFI_STATUS
+SdMmcHcInitPowerVoltage (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN SD_MMC_HC_SLOT_CAP Capability
+ );
+
+/**
+ Initialize the Timeout Control register with most conservative value at initialization.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The timeout control register is configured successfully.
+ @retval Others The timeout control register isn't configured successfully.
+
+**/
+EFI_STATUS
+SdMmcHcInitTimeoutCtrl (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ );
+
+/**
+ Initial SD/MMC host controller with lowest clock frequency, max power and max timeout value
+ at initialization.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Capability The capability of the slot.
+
+ @retval EFI_SUCCESS The host controller is initialized successfully.
+ @retval Others The host controller isn't initialized successfully.
+
+**/
+EFI_STATUS
+SdMmcHcInitHost (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN SD_MMC_HC_SLOT_CAP Capability
+ );
+
+#endif
diff --git a/Platform/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.c b/Platform/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.c
new file mode 100755
index 0000000000..31f207eabf
--- /dev/null
+++ b/Platform/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.c
@@ -0,0 +1,665 @@
+/*******************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#include "XenonSdhci.h"
+
+STATIC
+VOID
+XenonReadVersion (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ OUT UINT32 *ControllerVersion
+ )
+{
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CTRL_VER, TRUE, SDHC_REG_SIZE_2B, ControllerVersion);
+}
+
+STATIC
+VOID
+XenonSetFifo (
+ IN EFI_PCI_IO_PROTOCOL *PciIo
+ )
+{
+ UINTN Data;
+
+ // Set FIFO_RTC, FIFO_WTC, FIFO_CS and FIFO_PDLVMC
+ Data = SDHC_SLOT_FIFO_DEFAULT_CONFIG;
+
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SLOT_FIFO_CTRL, FALSE, SDHC_REG_SIZE_4B, &Data);
+}
+
+// Auto Clock Gating
+STATIC
+VOID
+XenonSetAcg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN BOOLEAN Enable
+ )
+{
+ UINT32 Var;
+
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SYS_OP_CTRL, TRUE, SDHC_REG_SIZE_4B, &Var);
+
+ if (Enable) {
+ Var &= ~AUTO_CLKGATE_DISABLE_MASK;
+ } else {
+ Var |= AUTO_CLKGATE_DISABLE_MASK;
+ }
+
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SYS_OP_CTRL, FALSE, SDHC_REG_SIZE_4B, &Var);
+}
+
+STATIC
+VOID
+XenonSetSlot (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN BOOLEAN Enable
+ )
+{
+ UINT32 Var;
+
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SYS_OP_CTRL, TRUE, SDHC_REG_SIZE_4B, &Var);
+ if (Enable) {
+ Var |= ((0x1 << Slot) << SLOT_ENABLE_SHIFT);
+ } else {
+ Var &= ~((0x1 << Slot) << SLOT_ENABLE_SHIFT);
+ }
+
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SYS_OP_CTRL, FALSE, SDHC_REG_SIZE_4B, &Var);
+}
+
+//
+// Stub function, which will in future be responsible for
+// setting SDIO controller in either HIGH (if Voltage parameter
+// is equal 1) or LOW (if Voltage is equal 0)
+//
+STATIC
+VOID
+XenonSetSdio (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINTN Voltage
+ )
+{
+ // Currently SDIO isn't supported
+ return;
+}
+
+STATIC
+VOID
+XenonSetPower (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 Vcc,
+ IN UINT32 Vccq,
+ IN UINT8 Mode
+ )
+{
+ UINT8 Pwr = 0;
+ UINT32 Ctrl = 0;
+
+ // Below statement calls routine to set voltage for SDIO devices in either HIGH (1) or LOW (0) mode
+ switch (Vcc) {
+ case MMC_VDD_165_195:
+ Pwr = SDHCI_POWER_180;
+ if (Mode == XENON_MMC_MODE_SD_SDIO) {
+ XenonSetSdio (PciIo, 0);
+ }
+ break;
+ case MMC_VDD_29_30:
+ case MMC_VDD_30_31:
+ Pwr = SDHCI_POWER_300;
+ if (Mode == XENON_MMC_MODE_SD_SDIO) {
+ XenonSetSdio (PciIo, 1);
+ }
+ break;
+ case MMC_VDD_32_33:
+ case MMC_VDD_33_34:
+ Pwr = SDHCI_POWER_330;
+ if (Mode == XENON_MMC_MODE_SD_SDIO) {
+ XenonSetSdio (PciIo, 1);
+ }
+ break;
+ default:
+ DEBUG((DEBUG_ERROR, "SD/MMC: Does not support power mode(0x%X)\n", Vcc));
+ break;
+ }
+
+ if (Pwr == 0) {
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_POWER_CTRL, FALSE, SDHC_REG_SIZE_1B, &Pwr);
+ return;
+ }
+
+ Pwr |= SDHCI_POWER_ON;
+
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX,SD_MMC_HC_POWER_CTRL, FALSE, SDHC_REG_SIZE_1B, &Pwr);
+
+ // Set VCCQ
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SLOT_eMMC_CTRL, TRUE, SDHC_REG_SIZE_4B, &Ctrl);
+ Ctrl |= Vccq;
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SLOT_eMMC_CTRL, FALSE, SDHC_REG_SIZE_4B, &Ctrl);
+}
+
+UINTN
+XenonSetClk (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT32 Clock
+ )
+{
+ UINT32 Div;
+ UINT32 Clk;
+ UINT32 Retry;
+ UINT16 Value = 0;
+
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, SDHC_REG_SIZE_2B, &Value);
+
+ if (Clock == 0) {
+ return 0;
+ }
+
+ if (Private->ControllerVersion >= SDHCI_SPEC_300) {
+ // Version 3.00 Divisors must be a multiple of 2
+ if (XENON_MMC_MAX_CLK <= Clock) {
+ Div = 1;
+ } else {
+ for (Div = 2; Div < SDHCI_MAX_DIV_SPEC_300; Div += 2) {
+ if ((XENON_MMC_MAX_CLK / Div) <= Clock)
+ break;
+ }
+ }
+ } else {
+ // Version 2.00 Divisors must be a power of 2
+ for (Div = 1; Div < SDHCI_MAX_DIV_SPEC_200; Div *= 2) {
+ if ((XENON_MMC_MAX_CLK / Div) <= Clock)
+ break;
+ }
+ }
+ Div >>= 1;
+
+ Clk = (Div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
+ Clk |= ((Div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN) << SDHCI_DIVIDER_HI_SHIFT;
+ Clk |= SDHCI_CLOCK_INT_EN;
+
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, SDHC_REG_SIZE_2B, &Clk);
+
+ //
+ // Poll for internal controller clock to be stabilised
+ // Wait up to 200us for this to occur
+ //
+ Retry = 200;
+
+ do {
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, TRUE, SDHC_REG_SIZE_2B, &Clk);
+ if (Retry == 0) {
+ DEBUG((DEBUG_ERROR, "SD/MMC: Internal Clock never stabilised\n"));
+ return -1;
+ }
+
+ Retry--;
+
+ // Wait for internal clock to be stabilised
+ gBS->Stall (1);
+
+ } while (!(Clk & SDHCI_CLOCK_INT_STABLE));
+
+ Clk |= SDHCI_CLOCK_CARD_EN;
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, SDHC_REG_SIZE_2B, &Clk);
+
+ return 0;
+}
+
+VOID
+XenonPhyInit (
+ IN EFI_PCI_IO_PROTOCOL *PciIo
+ )
+{
+ UINT32 Var, Wait, Time;
+ UINT32 Clock = XENON_MMC_MAX_CLK;
+ UINT16 ClkCtrl;
+
+ // Need to disable the clock to set EMMC_PHY_TIMING_ADJUST register
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, TRUE, SDHC_REG_SIZE_2B, &ClkCtrl);
+ ClkCtrl &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN);
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, SDHC_REG_SIZE_2B, &ClkCtrl);
+
+ // Enable QSP PHASE SELECT
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, SDHC_REG_SIZE_4B, &Var);
+ Var |= SAMPL_INV_QSP_PHASE_SELECT;
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, FALSE, SDHC_REG_SIZE_4B, &Var);
+
+ // Enable internal clock
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, TRUE, SDHC_REG_SIZE_2B, &ClkCtrl);
+ ClkCtrl |= SDHCI_CLOCK_INT_EN;
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, SDHC_REG_SIZE_2B, &ClkCtrl);
+
+ //
+ // Poll for host MMC PHY clock init to be stable
+ // Wait up to 100us
+ //
+ Time = 100;
+ while (Time--) {
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, SDHC_REG_SIZE_4B, &Var);
+ if (Var & SDHCI_CLOCK_INT_STABLE) {
+ break;
+ }
+
+ // Poll interval for MMC PHY clock to be stable is 1us
+ gBS->Stall (1);
+ }
+ if (Time <= 0) {
+ DEBUG((DEBUG_ERROR, "SD/MMC: Failed to enable MMC internal clock in Time\n"));
+ return;
+ }
+
+ // Enable bus clock
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, TRUE, SDHC_REG_SIZE_2B, &ClkCtrl);
+ ClkCtrl |= SDHCI_CLOCK_CARD_EN;
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, SDHC_REG_SIZE_2B, &ClkCtrl);
+
+ // Delay 200us to wait for the completion of bus clock
+ gBS->Stall (200);
+
+ // Init PHY
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, SDHC_REG_SIZE_4B, &Var);
+ Var |= PHY_INITIALIZAION;
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, FALSE, SDHC_REG_SIZE_4B, &Var);
+
+ // Add duration of FC_SYNC_RST
+ Wait = ((Var >> FC_SYNC_RST_DURATION_SHIFT) & FC_SYNC_RST_DURATION_MASK);
+
+ // Add interval between FC_SYNC_EN and FC_SYNC_RST
+ Wait += ((Var >> FC_SYNC_RST_EN_DURATION_SHIFT) & FC_SYNC_RST_EN_DURATION_MASK);
+
+ // Add duration of asserting FC_SYNC_EN
+ Wait += ((Var >> FC_SYNC_EN_DURATION_SHIFT) & FC_SYNC_EN_DURATION_MASK);
+
+ // Add duration of Waiting for PHY
+ Wait += ((Var >> WAIT_CYCLE_BEFORE_USING_SHIFT) & WAIT_CYCLE_BEFORE_USING_MASK);
+
+ // 4 addtional bus clock and 4 AXI bus clock are required left shift 20 bits
+ Wait += 8;
+ Wait <<= 20;
+
+ // Use the possibly slowest bus frequency value
+ if (Clock == 0) {
+ Clock = XENON_MMC_MIN_CLK;
+ }
+
+ // Get the Wait Time in unit of ms
+ Wait = Wait / Clock;
+ Wait++;
+
+ // Poll for host eMMC PHY init to complete, wait up to 100us
+ Time = 100;
+ while (Time--) {
+ Var = SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, SDHC_REG_SIZE_4B, &Var);
+ Var &= PHY_INITIALIZAION;
+ if (!Var) {
+ break;
+ }
+
+ // Wait for host eMMC PHY init to complete
+ gBS->Stall (1);
+ }
+
+ if (Time <= 0) {
+ DEBUG((DEBUG_ERROR, "SD/MMC: Failed to init MMC PHY in Time\n"));
+ return;
+ }
+
+ return;
+}
+
+STATIC
+VOID
+XenonSetPhy (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ UINT8 Timing
+ )
+{
+ UINT32 Var = 0;
+
+ // Setup pad, set bit[30], bit[28] and bits[26:24]
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_PAD_CONTROL, TRUE, SDHC_REG_SIZE_4B, &Var);
+ Var |= (AUTO_RECEN_CTRL | OEN_QSN | FC_QSP_RECEN | FC_CMD_RECEN | FC_DQ_RECEN);
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_PAD_CONTROL, FALSE, SDHC_REG_SIZE_4B, &Var);
+
+ //
+ // If Timing belongs to high speed, set bit[17] of
+ // EMMC_PHY_TIMING_ADJUST register
+ //
+ if ((Timing == MMC_TIMING_MMC_HS400) ||
+ (Timing == MMC_TIMING_MMC_HS200) ||
+ (Timing == MMC_TIMING_UHS_SDR50) ||
+ (Timing == MMC_TIMING_UHS_SDR104) ||
+ (Timing == MMC_TIMING_UHS_DDR50) ||
+ (Timing == MMC_TIMING_UHS_SDR25)) {
+
+ SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, SDHC_REG_SIZE_4B, &Var);
+
+ // Set SLOW_MODE for PHY
+ Var |= OUTPUT_QSN_PHASE_SELECT | QSN_PHASE_SLOW_MODE_BIT;
+ SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, FALSE, SDHC_REG_SIZE_4B, &Var);
+ }
+
+ SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, TRUE, SDHC_REG_SIZE_4B, &Var);
+ Var |= (DQ_DDR_MODE_MASK << DQ_DDR_MODE_SHIFT) | CMD_DDR_MODE;
+ SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, FALSE, SDHC_REG_SIZE_4B, &Var);
+
+ if (Timing == MMC_TIMING_MMC_HS400) {
+ SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, TRUE, SDHC_REG_SIZE_4B, &Var);
+ Var &= ~DQ_ASYNC_MODE;
+ SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, FALSE, SDHC_REG_SIZE_4B, &Var);
+
+ Var = LOGIC_TIMING_VALUE;
+ SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_LOGIC_TIMING_ADJUST, FALSE, SDHC_REG_SIZE_4B, &Var);
+ }
+
+ XenonPhyInit (PciIo);
+}
+
+STATIC
+VOID
+XenonConfigureInterrupts (
+ IN EFI_PCI_IO_PROTOCOL *PciIo
+ )
+{
+ UINT32 Var;
+
+ // Clear interrupt status
+ Var = SDHC_CLR_ALL_IRQ_MASK;
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_NOR_INT_STS, FALSE, SDHC_REG_SIZE_4B, &Var);
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_NOR_INT_STS, FALSE, SDHC_REG_SIZE_4B, &Var);
+
+ // Enable only interrupts served by the SD controller
+ Var = SDHC_CLR_ALL_IRQ_MASK & ~(NOR_INT_STS_CARD_INS | NOR_INT_STS_CARD_INT);
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_NOR_INT_STS_EN, FALSE, SDHC_REG_SIZE_4B, &Var);
+
+ // Mask all sdhci interrupt sources
+ Var = SDHC_CLR_ALL_IRQ_MASK & ~NOR_INT_SIG_EN_CARD_INT;
+ SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_NOR_INT_SIG_EN, FALSE, SDHC_REG_SIZE_4B, &Var);
+}
+
+// Enable Parallel Transfer Mode
+STATIC
+VOID
+XenonSetParallelTransfer (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN BOOLEAN Enable
+ )
+{
+ UINT32 Var;
+
+ SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHC_SYS_EXT_OP_CTRL, TRUE, SDHC_REG_SIZE_4B, &Var);
+
+ if (Enable) {
+ Var |= (0x1 << Slot);
+ } else {
+ Var &= ~(0x1 << Slot);
+ }
+
+ SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHC_SYS_EXT_OP_CTRL, FALSE, SDHC_REG_SIZE_4B, &Var);
+}
+
+STATIC
+VOID
+XenonSetTuning (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN BOOLEAN Enable
+ )
+{
+ UINT32 Var;
+
+ // Set the Re-Tuning Request functionality
+ SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHC_SLOT_RETUNING_REQ_CTRL, TRUE, SDHC_REG_SIZE_4B, &Var);
+
+ if (Enable) {
+ Var |= RETUNING_COMPATIBLE;
+ } else {
+ Var &= ~RETUNING_COMPATIBLE;
+ }
+
+ SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHC_SLOT_RETUNING_REQ_CTRL, FALSE, SDHC_REG_SIZE_4B, &Var);
+
+ // Set the Re-tuning Event Signal Enable
+ SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHCI_SIGNAL_ENABLE, TRUE, SDHC_REG_SIZE_4B, &Var);
+
+ if (Enable) {
+ Var |= SDHCI_RETUNE_EVT_INTSIG;
+ } else {
+ Var &= ~SDHCI_RETUNE_EVT_INTSIG;
+ }
+
+ SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHCI_SIGNAL_ENABLE, FALSE, SDHC_REG_SIZE_4B, &Var);
+}
+
+VOID
+XenonReset (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot,
+ IN UINT8 Mask
+ )
+{
+ UINT32 Retry = 1000;
+ UINT8 SwReset;
+
+ SwReset = Mask;
+
+ SdMmcHcRwMmio (
+ Private->PciIo,
+ Slot,
+ SD_MMC_HC_SW_RST,
+ FALSE,
+ sizeof (SwReset),
+ &SwReset
+ );
+
+ SdMmcHcRwMmio (
+ Private->PciIo,
+ Slot,
+ SD_MMC_HC_SW_RST,
+ TRUE,
+ sizeof (SwReset),
+ &SwReset
+ );
+
+ while (SwReset & Mask) {
+ if (Retry == 0) {
+ DEBUG((DEBUG_ERROR, "SD/MMC: Reset never completed\n"));
+ return;
+ }
+
+ Retry--;
+
+ // Poll interval for SwReset is 100us according to SDHCI spec
+ gBS-> Stall (100);
+ SdMmcHcRwMmio (
+ Private->PciIo,
+ Slot,
+ SD_MMC_HC_SW_RST,
+ TRUE,
+ sizeof (SwReset),
+ &SwReset
+ );
+ }
+}
+
+STATIC
+VOID
+XenonTransferPio (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot,
+ IN OUT VOID *Buffer,
+ IN UINT16 BlockSize,
+ IN BOOLEAN Read
+ )
+{
+ UINTN Index;
+ UINT8 *Offs;
+
+ //
+ // SD stack's intrinsic functions cannot perform properly reading/writing from
+ // buffer register, that is why MmioRead/MmioWrite are used. It is temporary
+ // solution.
+ //
+ for (Index = 0; Index < BlockSize; Index += 4) {
+ Offs = Buffer + Index;
+ if (Read) {
+ *(UINT32 *)Offs = MmioRead32 (SDHC_DAT_BUF_PORT_ADDR);
+ } else {
+ MmioWrite32 (SDHC_DAT_BUF_PORT_ADDR, *(UINT32 *)Offs);
+ }
+ }
+}
+
+EFI_STATUS
+XenonTransferData (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot,
+ IN OUT VOID *Buffer,
+ IN UINT32 DataLen,
+ IN UINT16 BlockSize,
+ IN UINT16 Blocks,
+ IN BOOLEAN Read
+ )
+{
+ UINT32 IntStatus, PresentState, Rdy, Mask, Retry, Block = 0;
+
+ if (Buffer == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Retry = SDHC_INT_STATUS_POLL_RETRY_DATA_TRAN;
+ Rdy = NOR_INT_STS_TX_RDY | NOR_INT_STS_RX_RDY;
+ Mask = PRESENT_STATE_BUFFER_RD_EN | PRESENT_STATE_BUFFER_WR_EN;
+
+ do {
+ SdMmcHcRwMmio (
+ Private->PciIo,
+ Slot,
+ SD_MMC_HC_NOR_INT_STS,
+ TRUE,
+ sizeof (IntStatus),
+ &IntStatus
+ );
+
+ if (IntStatus & NOR_INT_STS_ERR_INT) {
+ DEBUG((DEBUG_INFO, "SD/MMC: Error detected in status %0x\n", IntStatus));
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (IntStatus & Rdy) {
+ SdMmcHcRwMmio (
+ Private->PciIo,
+ Slot,
+ SD_MMC_HC_PRESENT_STATE,
+ TRUE,
+ sizeof (PresentState),
+ &PresentState
+ );
+
+ if (!(PresentState & Mask)) {
+ continue;
+ }
+
+ SdMmcHcRwMmio (
+ Private->PciIo,
+ Slot,
+ SD_MMC_HC_NOR_INT_STS,
+ FALSE,
+ sizeof (Rdy),
+ &Rdy
+ );
+
+ XenonTransferPio (Private, Slot, Buffer, BlockSize, Read);
+
+ Buffer += BlockSize;
+ if (++Block >= Blocks) {
+ break;
+ }
+ }
+
+ if (Retry-- > 0) {
+
+ // Poll interval for data transfer complete bit in NOR_INT_STS register is 10us
+ gBS->Stall (10);
+ } else {
+ DEBUG((DEBUG_INFO, "SD/MMC: Transfer data timeout\n"));
+ return EFI_TIMEOUT;
+ }
+ } while (!(IntStatus & NOR_INT_STS_XFER_COMPLETE));
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+XenonInit (
+ IN SD_MMC_HC_PRIVATE_DATA *Private
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo = Private->PciIo;
+
+ // Read XENON version
+ XenonReadVersion (PciIo, &Private->ControllerVersion);
+
+ XenonSetFifo (PciIo);
+
+ // Disable auto clock generator
+ XenonSetAcg (PciIo, FALSE);
+
+ // XENON has only one port
+ XenonSetSlot (PciIo, XENON_MMC_SLOT_ID, TRUE);
+
+ XenonSetPower (PciIo, MMC_VDD_165_195, eMMC_VCCQ_1_8V, XENON_MMC_MODE_SD_SDIO);
+
+ // Set MAX_CLOCK for configuring PHY
+ XenonSetClk (PciIo, Private, XENON_MMC_MAX_CLK);
+ XenonSetPhy (PciIo, MMC_TIMING_UHS_SDR50);
+
+ XenonConfigureInterrupts (PciIo);
+
+ // Enable parallel transfer
+ XenonSetParallelTransfer (PciIo, XENON_MMC_SLOT_ID, TRUE);
+ XenonSetTuning (PciIo, XENON_MMC_SLOT_ID, FALSE);
+
+ // Enable auto clock generator
+ XenonSetAcg (PciIo, TRUE);
+
+ // Set proper clock for PHY configuration
+ XenonSetClk (PciIo, Private, XENON_MMC_BASE_CLK);
+ XenonPhyInit (PciIo);
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.h b/Platform/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.h
new file mode 100644
index 0000000000..2be0ee61e1
--- /dev/null
+++ b/Platform/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.h
@@ -0,0 +1,346 @@
+/*******************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#include "SdMmcPciHcDxe.h"
+
+#include <Library/IoLib.h>
+
+#define SD_BAR_INDEX 0
+
+#define SIZE_512B 0x200
+
+/* Register Offset of SD Host Controller SOCP self-defined register */
+
+#define SDHC_IPID 0x0100
+#define SDHC_SYS_CFG_INFO 0x0104
+#define SLOT_TYPE_SDIO_SHIFT 24
+#define SLOT_TYPE_EMMC_MASK 0xff
+#define SLOT_TYPE_EMMC_SHIFT 16
+#define SLOT_TYPE_SD_SDIO_MMC_MASK 0xff
+#define SLOT_TYPE_SD_SDIO_MMC_SHIFT 8
+
+#define SDHC_SYS_OP_CTRL 0x0108
+#define AUTO_CLKGATE_DISABLE_MASK (0x1<<20)
+#define SDCLK_IDLEOFF_ENABLE_SHIFT 8
+#define SLOT_ENABLE_SHIFT 0
+
+#define SDHC_SYS_EXT_OP_CTRL 0x010c
+#define SDHC_TEST_OUT 0x0110
+#define SDHC_TESTOUT_MUXSEL 0x0114
+
+#define SDHC_SLOT_EXT_INT_STATUS 0x0120
+#define SDHC_SLOT_EXT_ERR_STATUS 0x0122
+#define SDHC_SLOT_EXT_INT_STATUS_EN 0x0124
+#define SDHC_SLOT_EXT_ERR_STATUS_EN 0x0126
+
+#define SDHC_SLOT_OP_STATUS_CTRL 0x0128
+#define TUNING_PROG_FIXED_DELAY_MASK 0x7ff
+#define FORCE_SEL_INVERSE_CLK_SHIFT 11
+
+#define SDHC_SLOT_FIFO_CTRL 0x012c
+#define SDHC_SLOT_FIFO_DEFAULT_CONFIG 0x315
+
+#define SDHC_SLOT_eMMC_CTRL 0x0130
+#define ENABLE_DATA_STROBE_SHIFT 24
+#define SET_EMMC_RSTN_SHIFT 16
+#define eMMC_VCCQ_MASK 0x3
+#define eMMC_VCCQ_1_8V 0x1
+#define eMMC_VCCQ_1_2V 0x2
+#define eMMC_VCCQ_3_3V 0x3
+
+#define SDHC_SLOT_OUTPUT_DLY_CTRL 0x0134
+#define SDHC_SLOT_DCM_CTRL 0x0137
+
+#define SDHC_SLOT_DLL_CTRL 0x0138
+#define SELECT_DEF_DLL 0x1
+
+#define SDHC_SLOT_DLL_PHASE_SEL 0x013c
+#define DLL_UPDATE_STROBE 7
+
+#define SDHC_SLOT_STROBE_DLY_CTRL 0x0140
+#define STROBE_DELAY_FIXED_MASK 0xffff
+
+#define SDHC_SLOT_RETUNING_REQ_CTRL 0x0144
+#define RETUNING_COMPATIBLE 0x1
+
+#define SDHC_SLOT_AUTO_RETUNING_CTRL 0x0148
+#define ENABLE_AUTO_RETUNING 0x1
+
+#define SDHC_SLOT_EXT_PRESENT_STATE 0x014c
+#define SDHC_SLOT_DLL_CUR_DLY_VAL 0x0150
+#define SDHC_SLOT_TUNING_CUR_DLY_VAL 0x0154
+#define SDHC_SLOT_STROBE_CUR_DLY_VAL 0x0158
+#define SDHC_SLOT_SUB_CMD_STRL 0x015c
+
+#define SDHC_SLOT_CQ_TASK_INFO 0x0160
+
+#define SDHC_SLOT_TUNING_DEBUG_INFO 0x01f0
+#define SDHC_SLOT_DATAIN_DEBUG_INFO 0x01f4
+
+#define SDHC_CMD_RESET_BIT (1 << 1)
+#define SDHC_DATA_RESET_BIT (1 << 2)
+
+#define SDHC_CMD_INHIBIT (1 << 0)
+#define SDHC_DATA_INHIBIT (1 << 1)
+
+#define SDHC_REG_SIZE_1B 1
+#define SDHC_REG_SIZE_2B 2
+#define SDHC_REG_SIZE_4B 4
+
+#define SDHC_DAT_BUF_PORT_ADDR 0xF06E0020
+
+/* Command register bits description */
+#define RESP_TYPE_136_BITS (1 << 0)
+#define RESP_TYPE_48_BITS (1 << 1)
+#define RESP_TYPE_48_BITS_NO_CRC ((1 << 0) | (1 << 1))
+#define CMD_CRC_CHK_EN (1 << 3)
+#define CMD_INDEX_CHK_EN (1 << 4)
+#define DATA_PRESENT (1 << 5)
+
+/* Transfer mode register bits description */
+#define SDHC_TRNS_BLK_CNT_EN (1 << 1)
+#define SDHC_TRNS_MULTI_BLK_SEL (1 << 5)
+#define SDHC_TRNS_TO_HOST_DIR (1 << 4)
+
+/* Block size register bits description */
+#define BLK_SIZE_HOST_DMA_BDRY_OFFSET 12
+#define BLK_SIZE_512KB 0x7
+
+/* Int status register bits description */
+#define NOR_INT_STS_CMD_COMPLETE (1 << 0)
+#define NOR_INT_STS_XFER_COMPLETE (1 << 1)
+#define NOR_INT_STS_TX_RDY (1 << 4)
+#define NOR_INT_STS_RX_RDY (1 << 5)
+#define NOR_INT_STS_CARD_INS (1 << 6)
+#define NOR_INT_STS_CARD_INT (1 << 8)
+#define NOR_INT_STS_ERR_INT (1 << 15)
+#define ERR_INT_STS_CMD_TIMEOUT_ERR (1 << 16)
+#define ERR_INT_STS_DATA_TIMEOUT_ERR (1 << 20)
+
+#define NOR_INT_SIG_EN_CARD_INT (1 << 8)
+
+#define PRESENT_STATE_BUFFER_RD_EN (1 << 11)
+#define PRESENT_STATE_BUFFER_WR_EN (1 << 10)
+
+#define SDHC_CLR_IRQ_STS_MASK 0xFFFF
+#define SDHC_CLR_ALL_IRQ_MASK 0xFFFFFFFFUL
+
+/* Max clock in Hz */
+#define XENON_MMC_MAX_CLK 400000000
+#define XENON_MMC_CLK_RATIO 2046
+#define XENON_MMC_BASE_CLK XENON_MMC_MAX_CLK / XENON_MMC_CLK_RATIO
+#define XENON_MMC_MIN_CLK 100000
+
+#define XENON_MMC_CMD_MAX_TIMEOUT 3200
+#define XENON_MMC_CMD_DEFAULT_TIMEOUT 100
+
+/* Tuning Parameter */
+#define TMR_RETUN_NO_PRESENT 0xf
+#define XENON_MAX_TUN_COUNT 0xb
+
+#define EMMC_PHY_REG_BASE 0x170
+#define EMMC_PHY_TIMING_ADJUST EMMC_PHY_REG_BASE
+#define OUTPUT_QSN_PHASE_SELECT (1 << 17)
+#define SAMPL_INV_QSP_PHASE_SELECT (1 << 18)
+#define SAMPL_INV_QSP_PHASE_SELECT_SHIFT 18
+#define PHY_INITIALIZAION (1 << 31)
+#define WAIT_CYCLE_BEFORE_USING_MASK 0xf
+#define WAIT_CYCLE_BEFORE_USING_SHIFT 12
+#define FC_SYNC_EN_DURATION_MASK 0xf
+#define FC_SYNC_EN_DURATION_SHIFT 8
+#define FC_SYNC_RST_EN_DURATION_MASK 0xf
+#define FC_SYNC_RST_EN_DURATION_SHIFT 4
+#define FC_SYNC_RST_DURATION_MASK 0xf
+#define FC_SYNC_RST_DURATION_SHIFT 0
+
+#define EMMC_PHY_FUNC_CONTROL (EMMC_PHY_REG_BASE + 0x4)
+#define DQ_ASYNC_MODE (1 << 4)
+#define DQ_DDR_MODE_SHIFT 8
+#define DQ_DDR_MODE_MASK 0xff
+#define CMD_DDR_MODE (1 << 16)
+
+#define EMMC_PHY_PAD_CONTROL (EMMC_PHY_REG_BASE + 0x8)
+#define REC_EN_SHIFT 24
+#define REC_EN_MASK 0xf
+#define FC_DQ_RECEN (1 << 24)
+#define FC_CMD_RECEN (1 << 25)
+#define FC_QSP_RECEN (1 << 26)
+#define FC_QSN_RECEN (1 << 27)
+#define OEN_QSN (1 << 28)
+#define AUTO_RECEN_CTRL (1 << 30)
+
+#define EMMC_PHY_PAD_CONTROL1 (EMMC_PHY_REG_BASE + 0xc)
+#define EMMC_PHY_PAD_CONTROL2 (EMMC_PHY_REG_BASE + 0x10)
+#define EMMC_PHY_DLL_CONTROL (EMMC_PHY_REG_BASE + 0x14)
+#define DLL_DELAY_TEST_LOWER_SHIFT 8
+#define DLL_DELAY_TEST_LOWER_MASK 0xff
+#define DLL_BYPASS_EN 0x1
+
+#define EMMC_LOGIC_TIMING_ADJUST (EMMC_PHY_REG_BASE + 0x18)
+#define EMMC_LOGIC_TIMING_ADJUST_LOW (EMMC_PHY_REG_BASE + 0x1c)
+
+#define LOGIC_TIMING_VALUE 0x5a54 /* Recommend by HW team */
+
+#define QSN_PHASE_SLOW_MODE_BIT (1 << 29)
+
+/* XENON only have one slot 0 */
+#define XENON_MMC_SLOT_ID (0)
+
+#define MMC_TIMING_LEGACY 0
+#define MMC_TIMING_MMC_HS 1
+#define MMC_TIMING_SD_HS 2
+#define MMC_TIMING_UHS_SDR12 3
+#define MMC_TIMING_UHS_SDR25 4
+#define MMC_TIMING_UHS_SDR50 5
+#define MMC_TIMING_UHS_SDR104 6
+#define MMC_TIMING_UHS_DDR50 7
+#define MMC_TIMING_MMC_HS200 8
+#define MMC_TIMING_MMC_HS400 10
+
+/* Data time out default value 0xE: TMCLK x 227 */
+#define DATA_TIMEOUT_DEF_VAL 0xE
+
+/* Max retry count for INT status ready */
+#define SDHC_INT_STATUS_POLL_RETRY 1000
+#define SDHC_INT_STATUS_POLL_RETRY_DATA_TRAN 100000
+
+/* Take 2.5 seconds as generic time out value, 1 microsecond as unit */
+#define SD_GENERIC_TIMEOUT 2500 * 1000
+
+/* SDMA start address should allign with 0x8, align mask 0x7 */
+#define DMA_START_ADDR_ALIGN_MASK 0x7
+
+#define SDHCI_RETUNE_EVT_INTSIG 0x00001000
+
+/* MMC modes */
+#define XENON_MMC_MODE_EMMC 0
+#define XENON_MMC_MODE_SD_SDIO 1
+
+/* MMC Voltage */
+#define MMC_VDD_165_195 0x00000080 /* VDD voltage 1.65 - 1.95 */
+#define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */
+#define MMC_VDD_21_22 0x00000200 /* VDD voltage 2.1 ~ 2.2 */
+#define MMC_VDD_22_23 0x00000400 /* VDD voltage 2.2 ~ 2.3 */
+#define MMC_VDD_23_24 0x00000800 /* VDD voltage 2.3 ~ 2.4 */
+#define MMC_VDD_24_25 0x00001000 /* VDD voltage 2.4 ~ 2.5 */
+#define MMC_VDD_25_26 0x00002000 /* VDD voltage 2.5 ~ 2.6 */
+#define MMC_VDD_26_27 0x00004000 /* VDD voltage 2.6 ~ 2.7 */
+#define MMC_VDD_27_28 0x00008000 /* VDD voltage 2.7 ~ 2.8 */
+#define MMC_VDD_28_29 0x00010000 /* VDD voltage 2.8 ~ 2.9 */
+#define MMC_VDD_29_30 0x00020000 /* VDD voltage 2.9 ~ 3.0 */
+#define MMC_VDD_30_31 0x00040000 /* VDD voltage 3.0 ~ 3.1 */
+#define MMC_VDD_31_32 0x00080000 /* VDD voltage 3.1 ~ 3.2 */
+#define MMC_VDD_32_33 0x00100000 /* VDD voltage 3.2 ~ 3.3 */
+#define MMC_VDD_33_34 0x00200000 /* VDD voltage 3.3 ~ 3.4 */
+#define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */
+#define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */
+
+/* SDHCI FLAGS */
+#define SDHCI_POWER_ON 0x01
+#define SDHCI_POWER_180 0x0A
+#define SDHCI_POWER_300 0x0C
+#define SDHCI_POWER_330 0x0E
+
+#define SDHCI_DIVIDER_SHIFT 8
+#define SDHCI_DIVIDER_HI_SHIFT 6
+#define SDHCI_DIV_MASK 0xFF
+#define SDHCI_DIV_MASK_LEN 8
+#define SDHCI_DIV_HI_MASK 0x300
+#define SDHCI_CLOCK_CARD_EN 0x0004
+#define SDHCI_CLOCK_INT_STABLE 0x0002
+#define SDHCI_CLOCK_INT_EN 0x0001
+
+#define SDHCI_VENDOR_VER_MASK 0xFF00
+#define SDHCI_VENDOR_VER_SHIFT 8
+#define SDHCI_SPEC_VER_MASK 0x00FF
+#define SDHCI_SPEC_VER_SHIFT 0
+#define SDHCI_SPEC_100 0
+#define SDHCI_SPEC_200 1
+#define SDHCI_SPEC_300 2
+
+#define SDHCI_SIGNAL_ENABLE 0x38
+
+#define SDHCI_MAX_DIV_SPEC_200 256
+#define SDHCI_MAX_DIV_SPEC_300 2046
+
+/* SD DEVICE STATUS FLAGS */
+#define CURRENT_STATE_MASK (0xF << 9)
+#define CURRENT_STATE_N_READY_MASK (7 << 9)
+#define READY_FOR_DATA (1 << 8)
+#define CARD_STATUS_ERROR_MASK (~0x0206BF7F)
+
+#define RCA_BITS_OFFSET 16
+
+UINTN
+XenonSetClk (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT32 Clock
+ );
+
+VOID
+XenonPhyInit (
+ IN EFI_PCI_IO_PROTOCOL *PciIo
+ );
+
+VOID
+XenonReset (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot,
+ IN UINT8 Mask
+ );
+
+EFI_STATUS
+XenonTransferData (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot,
+ IN OUT VOID *Buffer,
+ IN UINT32 DataLen,
+ IN UINT16 BlockSize,
+ IN UINT16 Blocks,
+ IN BOOLEAN Read
+ );
+
+EFI_STATUS
+XenonInit (
+ IN SD_MMC_HC_PRIVATE_DATA *Private
+ );
+
+EFI_STATUS
+SdCardSendStatus (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ OUT UINT32 *DevStatus
+ );
diff --git a/Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.c b/Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.c
new file mode 100755
index 0000000000..9a04493895
--- /dev/null
+++ b/Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.c
@@ -0,0 +1,531 @@
+/*******************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+#include "MvSpiFlash.h"
+
+MARVELL_SPI_MASTER_PROTOCOL *SpiMasterProtocol;
+SPI_FLASH_INSTANCE *mSpiFlashInstance;
+
+STATIC
+VOID
+SpiFlashFormatAddress (
+ IN UINT32 Address,
+ IN UINT8 AddrSize,
+ IN OUT UINT8 *Cmd
+ )
+{
+ if (AddrSize == 4) {
+ Cmd[1] = Address >> 24;
+ Cmd[2] = Address >> 16;
+ Cmd[3] = Address >> 8;
+ Cmd[4] = Address;
+ } else {
+ Cmd[1] = Address >> 16;
+ Cmd[2] = Address >> 8;
+ Cmd[3] = Address;
+ }
+}
+
+STATIC
+EFI_STATUS
+MvSpiFlashReadCmd (
+ IN SPI_DEVICE *Slave,
+ IN UINT8 *Cmd,
+ IN UINTN CmdSize,
+ OUT UINT8 *DataIn,
+ IN UINTN DataSize
+ )
+{
+ EFI_STATUS Status;
+
+ // Send command and gather response
+ Status = SpiMasterProtocol->ReadWrite (SpiMasterProtocol, Slave, Cmd,
+ CmdSize, NULL, DataIn, DataSize);
+
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+MvSpiFlashWriteEnableCmd (
+ IN SPI_DEVICE *Slave
+ )
+{
+ EFI_STATUS Status;
+ UINT8 CmdEn = CMD_WRITE_ENABLE;
+
+ // Send write_enable command
+ Status = SpiMasterProtocol->Transfer (SpiMasterProtocol, Slave, 1,
+ &CmdEn, NULL, SPI_TRANSFER_BEGIN | SPI_TRANSFER_END);
+
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+MvSpiFlashWriteCommon (
+ IN SPI_DEVICE *Slave,
+ IN UINT8 *Cmd,
+ IN UINT32 Length,
+ IN UINT8* Buffer,
+ IN UINT32 BufferLength
+ )
+{
+ UINT8 CmdStatus = CMD_READ_STATUS;
+ UINT8 State;
+ UINT32 Counter = 0xFFFFF;
+ UINT8 poll_bit = STATUS_REG_POLL_WIP;
+ UINT8 check_status = 0x0;
+
+ CmdStatus = (UINT8)PcdGet32 (PcdSpiFlashPollCmd);
+ if (CmdStatus == CMD_FLAG_STATUS) {
+ poll_bit = STATUS_REG_POLL_PEC;
+ check_status = poll_bit;
+ }
+
+ // Send command
+ MvSpiFlashWriteEnableCmd (Slave);
+
+ // Write data
+ SpiMasterProtocol->ReadWrite (SpiMasterProtocol, Slave, Cmd, Length,
+ Buffer, NULL, BufferLength);
+
+ // Poll status register
+ SpiMasterProtocol->Transfer (SpiMasterProtocol, Slave, 1, &CmdStatus,
+ NULL, SPI_TRANSFER_BEGIN);
+ do {
+ SpiMasterProtocol->Transfer (SpiMasterProtocol, Slave, 1, NULL, &State,
+ 0);
+ Counter--;
+ if ((State & poll_bit) == check_status)
+ break;
+ } while (Counter > 0);
+ if (Counter == 0) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Timeout while writing to spi flash\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ // Deactivate CS
+ SpiMasterProtocol->Transfer (SpiMasterProtocol, Slave, 0, NULL, NULL, SPI_TRANSFER_END);
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+VOID
+SpiFlashCmdBankaddrWrite (
+ IN SPI_DEVICE *Slave,
+ IN UINT8 BankSel
+ )
+{
+ UINT8 Cmd = CMD_BANK_WRITE;
+
+ MvSpiFlashWriteCommon (Slave, &Cmd, 1, &BankSel, 1);
+}
+
+STATIC
+UINT8
+SpiFlashBank (
+ IN SPI_DEVICE *Slave,
+ IN UINT32 Offset
+ )
+{
+ UINT8 BankSel;
+
+ BankSel = Offset / SPI_FLASH_16MB_BOUN;
+
+ SpiFlashCmdBankaddrWrite (Slave, BankSel);
+
+ return BankSel;
+}
+
+EFI_STATUS
+MvSpiFlashErase (
+ IN SPI_DEVICE *Slave,
+ IN UINTN Offset,
+ IN UINTN Length
+ )
+{
+ EFI_STATUS Status;
+ UINT32 AddrSize, EraseAddr;
+ UINTN EraseSize;
+ UINT8 Cmd[5];
+
+ AddrSize = PcdGet32 (PcdSpiFlashAddressCycles);
+ EraseSize = PcdGet64 (PcdSpiFlashEraseSize);
+
+ // Check input parameters
+ if (Offset % EraseSize || Length % EraseSize) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Either erase offset or length "
+ "is not multiple of erase size\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ Cmd[0] = CMD_ERASE_64K;
+ while (Length) {
+ EraseAddr = Offset;
+
+ SpiFlashBank (Slave, EraseAddr);
+
+ SpiFlashFormatAddress (EraseAddr, AddrSize, Cmd);
+
+ // Programm proper erase address
+ Status = MvSpiFlashWriteCommon (Slave, Cmd, AddrSize + 1, NULL, 0);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Error while programming target address\n"));
+ return Status;
+ }
+
+ Offset += EraseSize;
+ Length -= EraseSize;
+ }
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+MvSpiFlashRead (
+ IN SPI_DEVICE *Slave,
+ IN UINT32 Offset,
+ IN UINTN Length,
+ IN VOID *Buf
+ )
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ UINT8 Cmd[6];
+ UINT32 AddrSize, ReadAddr, ReadLength, RemainLength;
+ UINTN BankSel = 0;
+
+ AddrSize = PcdGet32 (PcdSpiFlashAddressCycles);
+
+ Cmd[0] = CMD_READ_ARRAY_FAST;
+
+ // Sign end of address with 0 byte
+ Cmd[5] = 0;
+
+ while (Length) {
+ ReadAddr = Offset;
+
+ BankSel = SpiFlashBank (Slave, ReadAddr);
+
+ RemainLength = (SPI_FLASH_16MB_BOUN * (BankSel + 1)) - Offset;
+ if (Length < RemainLength) {
+ ReadLength = Length;
+ } else {
+ ReadLength = RemainLength;
+ }
+ SpiFlashFormatAddress (ReadAddr, AddrSize, Cmd);
+ // Program proper read address and read data
+ Status = MvSpiFlashReadCmd (Slave, Cmd, AddrSize + 2, Buf, Length);
+
+ Offset += ReadLength;
+ Length -= ReadLength;
+ Buf += ReadLength;
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+MvSpiFlashWrite (
+ IN SPI_DEVICE *Slave,
+ IN UINT32 Offset,
+ IN UINTN Length,
+ IN VOID *Buf
+ )
+{
+ EFI_STATUS Status;
+ UINTN ByteAddr, ChunkLength, ActualIndex, PageSize;
+ UINT32 WriteAddr;
+ UINT8 Cmd[5], AddrSize;
+
+ AddrSize = PcdGet32 (PcdSpiFlashAddressCycles);
+ PageSize = PcdGet32 (PcdSpiFlashPageSize);
+
+ Cmd[0] = CMD_PAGE_PROGRAM;
+
+ for (ActualIndex = 0; ActualIndex < Length; ActualIndex += ChunkLength) {
+ WriteAddr = Offset;
+
+ SpiFlashBank (Slave, WriteAddr);
+
+ ByteAddr = Offset % PageSize;
+
+ ChunkLength = MIN(Length - ActualIndex, (UINT64) (PageSize - ByteAddr));
+
+ SpiFlashFormatAddress (WriteAddr, AddrSize, Cmd);
+
+ // Program proper write address and write data
+ Status = MvSpiFlashWriteCommon (Slave, Cmd, AddrSize + 1, Buf + ActualIndex,
+ ChunkLength);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Error while programming write address\n"));
+ return Status;
+ }
+
+ Offset += ChunkLength;
+ }
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+MvSpiFlashUpdateBlock (
+ IN SPI_DEVICE *Slave,
+ IN UINT32 Offset,
+ IN UINTN ToUpdate,
+ IN UINT8 *Buf,
+ IN UINT8 *TmpBuf,
+ IN UINTN EraseSize
+ )
+{
+ EFI_STATUS Status;
+
+ // Read backup
+ Status = MvSpiFlashRead (Slave, Offset, EraseSize, TmpBuf);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Update: Error while reading old data\n"));
+ return Status;
+ }
+
+ // Erase entire sector
+ Status = MvSpiFlashErase (Slave, Offset, EraseSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Update: Error while erasing block\n"));
+ return Status;
+ }
+
+ // Write new data
+ MvSpiFlashWrite (Slave, Offset, ToUpdate, Buf);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Update: Error while writing new data\n"));
+ return Status;
+ }
+
+ // Write backup
+ if (ToUpdate != EraseSize) {
+ Status = MvSpiFlashWrite (Slave, Offset + ToUpdate, EraseSize - ToUpdate,
+ &TmpBuf[ToUpdate]);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Update: Error while writing backup\n"));
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+MvSpiFlashUpdate (
+ IN SPI_DEVICE *Slave,
+ IN UINT32 Offset,
+ IN UINTN ByteCount,
+ IN UINT8 *Buf
+ )
+{
+ EFI_STATUS Status;
+ UINT64 EraseSize, ToUpdate, Scale = 1;
+ UINT8 *TmpBuf, *End;
+
+ EraseSize = PcdGet64 (PcdSpiFlashEraseSize);
+
+ End = Buf + ByteCount;
+
+ TmpBuf = (UINT8 *)AllocateZeroPool (EraseSize);
+ if (TmpBuf == NULL) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Cannot allocate memory\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (End - Buf >= 200)
+ Scale = (End - Buf) / 100;
+
+ for (; Buf < End; Buf += ToUpdate, Offset += ToUpdate) {
+ ToUpdate = MIN((UINT64)(End - Buf), EraseSize);
+ Print (L" \rUpdating, %d%%", 100 - (End - Buf) / Scale);
+ Status = MvSpiFlashUpdateBlock (Slave, Offset, ToUpdate, Buf, TmpBuf, EraseSize);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Error while updating\n"));
+ return Status;
+ }
+ }
+
+ Print(L"\n");
+ FreePool (TmpBuf);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+MvSpiFlashReadId (
+ IN SPI_DEVICE *SpiDev,
+ IN UINT32 DataByteCount,
+ IN OUT UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *DataOut;
+
+ DataOut = (UINT8 *) AllocateZeroPool (DataByteCount);
+ if (DataOut == NULL) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Cannot allocate memory\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = SpiMasterProtocol->Transfer (SpiMasterProtocol, SpiDev,
+ DataByteCount, Buffer, DataOut, SPI_TRANSFER_BEGIN | SPI_TRANSFER_END);
+ if (EFI_ERROR(Status)) {
+ FreePool (DataOut);
+ DEBUG((DEBUG_ERROR, "SpiFlash: Spi transfer error\n"));
+ return Status;
+ }
+
+ // Bytes 1,2 and 3 contain SPI flash ID
+ Buffer[0] = DataOut[1];
+ Buffer[1] = DataOut[2];
+ Buffer[2] = DataOut[3];
+
+ FreePool (DataOut);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+MvSpiFlashInit (
+ IN MARVELL_SPI_FLASH_PROTOCOL *This,
+ IN SPI_DEVICE *Slave
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Cmd, StatusRegister;
+ UINT32 AddrSize;
+
+ AddrSize = PcdGet32 (PcdSpiFlashAddressCycles);
+
+ if (AddrSize == 4) {
+ // Set 4 byte address mode
+ Status = MvSpiFlashWriteEnableCmd (Slave);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Error while setting write_enable\n"));
+ return Status;
+ }
+
+ Cmd = CMD_4B_ADDR_ENABLE;
+ Status = SpiMasterProtocol->Transfer (SpiMasterProtocol, Slave, 1, &Cmd, NULL,
+ SPI_TRANSFER_BEGIN | SPI_TRANSFER_END);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Error while setting 4B address\n"));
+ return Status;
+ }
+ }
+
+ // Write flash status register
+ Status = MvSpiFlashWriteEnableCmd (Slave);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Error while setting write_enable\n"));
+ return Status;
+ }
+
+ Cmd = CMD_WRITE_STATUS_REG;
+ StatusRegister = 0x0;
+ Status = SpiMasterProtocol->ReadWrite (SpiMasterProtocol, Slave, &Cmd, 1,
+ &StatusRegister, NULL, 1);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Error with spi transfer\n"));
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+MvSpiFlashInitProtocol (
+ IN MARVELL_SPI_FLASH_PROTOCOL *SpiFlashProtocol
+ )
+{
+
+ SpiFlashProtocol->Init = MvSpiFlashInit;
+ SpiFlashProtocol->ReadId = MvSpiFlashReadId;
+ SpiFlashProtocol->Read = MvSpiFlashRead;
+ SpiFlashProtocol->Write = MvSpiFlashWrite;
+ SpiFlashProtocol->Erase = MvSpiFlashErase;
+ SpiFlashProtocol->Update = MvSpiFlashUpdate;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+MvSpiFlashEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->LocateProtocol (
+ &gMarvellSpiMasterProtocolGuid,
+ NULL,
+ (VOID **)&SpiMasterProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Cannot locate SPI Master protocol\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ mSpiFlashInstance = AllocateZeroPool (sizeof (SPI_FLASH_INSTANCE));
+
+ if (mSpiFlashInstance == NULL) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Cannot allocate memory\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ MvSpiFlashInitProtocol (&mSpiFlashInstance->SpiFlashProtocol);
+
+ mSpiFlashInstance->Signature = SPI_FLASH_SIGNATURE;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &(mSpiFlashInstance->Handle),
+ &gMarvellSpiFlashProtocolGuid,
+ &(mSpiFlashInstance->SpiFlashProtocol),
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (mSpiFlashInstance);
+ DEBUG((DEBUG_ERROR, "SpiFlash: Cannot install SPI flash protocol\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.h b/Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.h
new file mode 100755
index 0000000000..3889643aeb
--- /dev/null
+++ b/Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.h
@@ -0,0 +1,132 @@
+/*******************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+#ifndef __MV_SPI_FLASH_H__
+#define __MV_SPI_FLASH_H__
+
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <Protocol/Spi.h>
+#include <Protocol/SpiFlash.h>
+
+#define SPI_FLASH_SIGNATURE SIGNATURE_32 ('F', 'S', 'P', 'I')
+
+#define CMD_READ_ID 0x9f
+#define READ_STATUS_REG_CMD 0x0b
+#define CMD_WRITE_ENABLE 0x06
+#define CMD_READ_STATUS 0x05
+#define CMD_FLAG_STATUS 0x70
+#define CMD_WRITE_STATUS_REG 0x01
+#define CMD_READ_ARRAY_FAST 0x0b
+#define CMD_PAGE_PROGRAM 0x02
+#define CMD_BANK_WRITE 0xc5
+#define CMD_ERASE_64K 0xd8
+#define CMD_4B_ADDR_ENABLE 0xb7
+
+#define STATUS_REG_POLL_WIP (1 << 0)
+#define STATUS_REG_POLL_PEC (1 << 7)
+
+#define SPI_TRANSFER_BEGIN 0x01 // Assert CS before transfer
+#define SPI_TRANSFER_END 0x02 // Deassert CS after transfers
+
+#define SPI_FLASH_16MB_BOUN 0x1000000
+
+typedef enum {
+ SPI_FLASH_READ_ID,
+ SPI_FLASH_READ, // Read from SPI flash with address
+ SPI_FLASH_WRITE, // Write to SPI flash with address
+ SPI_FLASH_ERASE,
+ SPI_FLASH_UPDATE,
+ SPI_COMMAND_MAX
+} SPI_COMMAND;
+
+typedef struct {
+ MARVELL_SPI_FLASH_PROTOCOL SpiFlashProtocol;
+ UINTN Signature;
+ EFI_HANDLE Handle;
+} SPI_FLASH_INSTANCE;
+
+EFI_STATUS
+EFIAPI
+SpiFlashReadId (
+ IN SPI_DEVICE *SpiDev,
+ IN UINT32 DataByteCount,
+ IN OUT UINT8 *Buffer
+ );
+
+EFI_STATUS
+SpiFlashRead (
+ IN SPI_DEVICE *Slave,
+ IN UINT32 Offset,
+ IN UINTN Length,
+ IN VOID *Buf
+ );
+
+EFI_STATUS
+SpiFlashWrite (
+ IN SPI_DEVICE *Slave,
+ IN UINT32 Offset,
+ IN UINTN Length,
+ IN VOID *Buf
+ );
+
+EFI_STATUS
+SpiFlashUpdate (
+ IN SPI_DEVICE *Slave,
+ IN UINT32 Offset,
+ IN UINTN ByteCount,
+ IN UINT8 *Buf
+ );
+
+EFI_STATUS
+SpiFlashErase (
+ IN SPI_DEVICE *SpiDev,
+ IN UINTN Offset,
+ IN UINTN Length
+ );
+
+EFI_STATUS
+EFIAPI
+EfiSpiFlashInit (
+ IN MARVELL_SPI_FLASH_PROTOCOL *This,
+ IN SPI_DEVICE *Slave
+ );
+
+#endif // __MV_SPI_FLASH_H__
diff --git a/Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.inf b/Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.inf
new file mode 100644
index 0000000000..d035d47137
--- /dev/null
+++ b/Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.inf
@@ -0,0 +1,67 @@
+#
+# Marvell BSD License Option
+#
+# If you received this File from Marvell, you may opt to use, redistribute
+# and/or modify this File under the following licensing terms.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Marvell nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SpiFlashDxe
+ FILE_GUID = 49d7fb74-306d-42bd-94c8-c0c54b181dd7
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = MvSpiFlashEntryPoint
+
+[Sources]
+ MvSpiFlash.c
+ MvSpiFlash.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ Platform/Marvell/Marvell.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ TimerLib
+ UefiLib
+ DebugLib
+ MemoryAllocationLib
+
+[FixedPcd]
+ gMarvellTokenSpaceGuid.PcdSpiFlashAddressCycles
+ gMarvellTokenSpaceGuid.PcdSpiFlashEraseSize
+ gMarvellTokenSpaceGuid.PcdSpiFlashPageSize
+ gMarvellTokenSpaceGuid.PcdSpiFlashPollCmd
+
+[Protocols]
+ gMarvellSpiMasterProtocolGuid
+ gMarvellSpiFlashProtocolGuid
+
+[Depex]
+ TRUE
diff --git a/Platform/Marvell/Drivers/Spi/MvSpiDxe.c b/Platform/Marvell/Drivers/Spi/MvSpiDxe.c
new file mode 100755
index 0000000000..aab20fc9ac
--- /dev/null
+++ b/Platform/Marvell/Drivers/Spi/MvSpiDxe.c
@@ -0,0 +1,379 @@
+/*******************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+#include "MvSpiDxe.h"
+
+SPI_MASTER *mSpiMasterInstance;
+
+STATIC
+EFI_STATUS
+SpiSetBaudRate (
+ IN UINT32 CpuClock,
+ IN UINT32 MaxFreq
+ )
+{
+ UINT32 Spr, BestSpr, Sppr, BestSppr, ClockDivider, Match, Reg, MinBaudDiff;
+ UINTN SpiRegBase = PcdGet32 (PcdSpiRegBase);
+
+ MinBaudDiff = 0xFFFFFFFF;
+ BestSppr = 0;
+
+ //Spr is in range 1-15 and Sppr in range 0-8
+ for (Spr = 1; Spr <= 15; Spr++) {
+ for (Sppr = 0; Sppr <= 7; Sppr++) {
+ ClockDivider = Spr * (1 << Sppr);
+
+ if ((CpuClock / ClockDivider) > MaxFreq) {
+ continue;
+ }
+
+ if ((CpuClock / ClockDivider) == MaxFreq) {
+ BestSpr = Spr;
+ BestSppr = Sppr;
+ Match = 1;
+ break;
+ }
+
+ if ((MaxFreq - (CpuClock / ClockDivider)) < MinBaudDiff) {
+ MinBaudDiff = (MaxFreq - (CpuClock / ClockDivider));
+ BestSpr = Spr;
+ BestSppr = Sppr;
+ }
+ }
+
+ if (Match == 1) {
+ break;
+ }
+ }
+
+ if (BestSpr == 0) {
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ Reg = MmioRead32 (SpiRegBase + SPI_CONF_REG);
+ Reg &= ~(SPI_SPR_MASK | SPI_SPPR_0_MASK | SPI_SPPR_HI_MASK);
+ Reg |= (BestSpr << SPI_SPR_OFFSET) |
+ ((BestSppr & 0x1) << SPI_SPPR_0_OFFSET) |
+ ((BestSppr >> 1) << SPI_SPPR_HI_OFFSET);
+ MmioWrite32 (SpiRegBase + SPI_CONF_REG, Reg);
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+VOID
+SpiSetCs (
+ UINT8 CsId
+ )
+{
+ UINT32 Reg, SpiRegBase = PcdGet32 (PcdSpiRegBase);
+
+ Reg = MmioRead32 (SpiRegBase + SPI_CTRL_REG);
+ Reg &= ~SPI_CS_NUM_MASK;
+ Reg |= (CsId << SPI_CS_NUM_OFFSET);
+ MmioWrite32 (SpiRegBase + SPI_CTRL_REG, Reg);
+}
+
+STATIC
+VOID
+SpiActivateCs (
+ UINT8 IN CsId
+ )
+{
+ UINT32 Reg, SpiRegBase = PcdGet32 (PcdSpiRegBase);
+
+ SpiSetCs(CsId);
+ Reg = MmioRead32 (SpiRegBase + SPI_CTRL_REG);
+ Reg |= SPI_CS_EN_MASK;
+ MmioWrite32(SpiRegBase + SPI_CTRL_REG, Reg);
+}
+
+STATIC
+VOID
+SpiDeactivateCs (
+ VOID
+ )
+{
+ UINT32 Reg, SpiRegBase = PcdGet32 (PcdSpiRegBase);
+
+ Reg = MmioRead32 (SpiRegBase + SPI_CTRL_REG);
+ Reg &= ~SPI_CS_EN_MASK;
+ MmioWrite32(SpiRegBase + SPI_CTRL_REG, Reg);
+}
+
+STATIC
+VOID
+SpiSetupTransfer (
+ IN MARVELL_SPI_MASTER_PROTOCOL *This,
+ IN SPI_DEVICE *Slave
+ )
+{
+ SPI_MASTER *SpiMaster;
+ UINT32 Reg, SpiRegBase, CoreClock, SpiMaxFreq;
+
+ SpiMaster = SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This);
+
+ // Initialize values from PCDs
+ SpiRegBase = PcdGet32 (PcdSpiRegBase);
+ CoreClock = PcdGet32 (PcdSpiClockFrequency);
+ SpiMaxFreq = PcdGet32 (PcdSpiMaxFrequency);
+
+ EfiAcquireLock (&SpiMaster->Lock);
+
+ Reg = MmioRead32 (SpiRegBase + SPI_CONF_REG);
+ Reg |= SPI_BYTE_LENGTH;
+ MmioWrite32 (SpiRegBase + SPI_CONF_REG, Reg);
+
+ SpiSetCs(Slave->Cs);
+
+ SpiSetBaudRate (CoreClock, SpiMaxFreq);
+
+ Reg = MmioRead32 (SpiRegBase + SPI_CONF_REG);
+ Reg &= ~(SPI_CPOL_MASK | SPI_CPHA_MASK | SPI_TXLSBF_MASK | SPI_RXLSBF_MASK);
+
+ switch (Slave->Mode) {
+ case SPI_MODE0:
+ break;
+ case SPI_MODE1:
+ Reg |= SPI_CPHA_MASK;
+ break;
+ case SPI_MODE2:
+ Reg |= SPI_CPOL_MASK;
+ break;
+ case SPI_MODE3:
+ Reg |= SPI_CPOL_MASK;
+ Reg |= SPI_CPHA_MASK;
+ break;
+ }
+
+ MmioWrite32 (SpiRegBase + SPI_CONF_REG, Reg);
+
+ EfiReleaseLock (&SpiMaster->Lock);
+}
+
+EFI_STATUS
+EFIAPI
+MvSpiTransfer (
+ IN MARVELL_SPI_MASTER_PROTOCOL *This,
+ IN SPI_DEVICE *Slave,
+ IN UINTN DataByteCount,
+ IN VOID *DataOut,
+ IN VOID *DataIn,
+ IN UINTN Flag
+ )
+{
+ SPI_MASTER *SpiMaster;
+ UINT64 Length;
+ UINT32 Iterator, Reg, SpiRegBase;
+ UINT8 *DataOutPtr = (UINT8 *)DataOut;
+ UINT8 *DataInPtr = (UINT8 *)DataIn;
+ UINT8 DataToSend = 0;
+
+ SpiMaster = SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This);
+
+ SpiRegBase = PcdGet32 (PcdSpiRegBase);
+
+ Length = 8 * DataByteCount;
+
+ EfiAcquireLock (&SpiMaster->Lock);
+
+ if (Flag & SPI_TRANSFER_BEGIN) {
+ SpiActivateCs (Slave->Cs);
+ }
+
+ // Set 8-bit mode
+ Reg = MmioRead32 (SpiRegBase + SPI_CONF_REG);
+ Reg &= ~SPI_BYTE_LENGTH;
+ MmioWrite32 (SpiRegBase + SPI_CONF_REG, Reg);
+
+ while (Length > 0) {
+ if (DataOut != NULL) {
+ DataToSend = *DataOutPtr & 0xFF;
+ }
+ // Transmit Data
+ MmioWrite32 (SpiRegBase + SPI_INT_CAUSE_REG, 0x0);
+ MmioWrite32 (SpiRegBase + SPI_DATA_OUT_REG, DataToSend);
+ // Wait for memory ready
+ for (Iterator = 0; Iterator < SPI_TIMEOUT; Iterator++) {
+ if (MmioRead32 (SpiRegBase + SPI_INT_CAUSE_REG)) {
+ *DataInPtr = MmioRead32 (SpiRegBase + SPI_DATA_IN_REG);
+
+ if (DataInPtr != NULL) {
+ DataInPtr++;
+ }
+ if (DataOutPtr != NULL) {
+ DataOutPtr++;
+ }
+ Length -= 8;
+ break;
+ }
+ }
+
+ if (Iterator >= SPI_TIMEOUT) {
+ DEBUG ((DEBUG_ERROR, "Timeout\n"));
+ }
+ }
+
+ if (Flag & SPI_TRANSFER_END) {
+ SpiDeactivateCs ();
+ }
+
+ EfiReleaseLock (&SpiMaster->Lock);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+MvSpiReadWrite (
+ IN MARVELL_SPI_MASTER_PROTOCOL *This,
+ IN SPI_DEVICE *Slave,
+ IN UINT8 *Cmd,
+ IN UINTN CmdSize,
+ IN UINT8 *DataOut,
+ OUT UINT8 *DataIn,
+ IN UINTN DataSize
+ )
+{
+ EFI_STATUS Status;
+
+ Status = MvSpiTransfer (This, Slave, CmdSize, Cmd, NULL, SPI_TRANSFER_BEGIN);
+ if (EFI_ERROR (Status)) {
+ Print (L"Spi Transfer Error\n");
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = MvSpiTransfer (This, Slave, DataSize, DataOut, DataIn, SPI_TRANSFER_END);
+ if (EFI_ERROR (Status)) {
+ Print (L"Spi Transfer Error\n");
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+MvSpiInit (
+ IN MARVELL_SPI_MASTER_PROTOCOL * This
+ )
+{
+
+ return EFI_SUCCESS;
+}
+
+SPI_DEVICE *
+EFIAPI
+MvSpiSetupSlave (
+ IN MARVELL_SPI_MASTER_PROTOCOL *This,
+ IN UINTN Cs,
+ IN SPI_MODE Mode
+ )
+{
+ SPI_DEVICE *Slave;
+
+ Slave = AllocateZeroPool (sizeof(SPI_DEVICE));
+ if (Slave == NULL) {
+ DEBUG((DEBUG_ERROR, "Cannot allocate memory\n"));
+ return NULL;
+ }
+
+ Slave->Cs = Cs;
+ Slave->Mode = Mode;
+
+ SpiSetupTransfer (This, Slave);
+
+ return Slave;
+}
+
+EFI_STATUS
+EFIAPI
+MvSpiFreeSlave (
+ IN SPI_DEVICE *Slave
+ )
+{
+ FreePool (Slave);
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+SpiMasterInitProtocol (
+ IN MARVELL_SPI_MASTER_PROTOCOL *SpiMasterProtocol
+ )
+{
+
+ SpiMasterProtocol->Init = MvSpiInit;
+ SpiMasterProtocol->SetupDevice = MvSpiSetupSlave;
+ SpiMasterProtocol->FreeDevice = MvSpiFreeSlave;
+ SpiMasterProtocol->Transfer = MvSpiTransfer;
+ SpiMasterProtocol->ReadWrite = MvSpiReadWrite;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SpiMasterEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ mSpiMasterInstance = AllocateZeroPool (sizeof (SPI_MASTER));
+
+ if (mSpiMasterInstance == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ EfiInitializeLock (&mSpiMasterInstance->Lock, TPL_NOTIFY);
+
+ SpiMasterInitProtocol (&mSpiMasterInstance->SpiMasterProtocol);
+
+ mSpiMasterInstance->Signature = SPI_MASTER_SIGNATURE;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &(mSpiMasterInstance->Handle),
+ &gMarvellSpiMasterProtocolGuid,
+ &(mSpiMasterInstance->SpiMasterProtocol),
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (mSpiMasterInstance);
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Marvell/Drivers/Spi/MvSpiDxe.h b/Platform/Marvell/Drivers/Spi/MvSpiDxe.h
new file mode 100644
index 0000000000..1401f6207b
--- /dev/null
+++ b/Platform/Marvell/Drivers/Spi/MvSpiDxe.h
@@ -0,0 +1,145 @@
+/*******************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+#ifndef __SPI_MASTER_H__
+#define __SPI_MASTER_H__
+
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <Protocol/Spi.h>
+
+#define SPI_MASTER_SIGNATURE SIGNATURE_32 ('M', 'S', 'P', 'I')
+#define SPI_MASTER_FROM_SPI_MASTER_PROTOCOL(a) CR (a, SPI_MASTER, SpiMasterProtocol, SPI_MASTER_SIGNATURE)
+
+// Marvell Flash Device Controller Registers
+#define SPI_CTRL_REG (0x00)
+#define SPI_CONF_REG (0x04)
+#define SPI_DATA_OUT_REG (0x08)
+#define SPI_DATA_IN_REG (0x0c)
+#define SPI_INT_CAUSE_REG (0x10)
+
+// Serial Memory Interface Control Register Masks
+#define SPI_CS_NUM_OFFSET 2
+#define SPI_CS_NUM_MASK (0x7 << SPI_CS_NUM_OFFSET)
+#define SPI_MEM_READY_MASK (0x1 << 1)
+#define SPI_CS_EN_MASK (0x1 << 0)
+
+// Serial Memory Interface Configuration Register Masks
+#define SPI_BYTE_LENGTH_OFFSET 5
+#define SPI_BYTE_LENGTH (0x1 << SPI_BYTE_LENGTH_OFFSET)
+#define SPI_CPOL_OFFSET 11
+#define SPI_CPOL_MASK (0x1 << SPI_CPOL_OFFSET)
+#define SPI_CPHA_OFFSET 12
+#define SPI_CPHA_MASK (0x1 << SPI_CPHA_OFFSET)
+#define SPI_TXLSBF_OFFSET 13
+#define SPI_TXLSBF_MASK (0x1 << SPI_TXLSBF_OFFSET)
+#define SPI_RXLSBF_OFFSET 14
+#define SPI_RXLSBF_MASK (0x1 << SPI_RXLSBF_OFFSET)
+
+#define SPI_SPR_OFFSET 0
+#define SPI_SPR_MASK (0xf << SPI_SPR_OFFSET)
+#define SPI_SPPR_0_OFFSET 4
+#define SPI_SPPR_0_MASK (0x1 << SPI_SPPR_0_OFFSET)
+#define SPI_SPPR_HI_OFFSET 6
+#define SPI_SPPR_HI_MASK (0x3 << SPI_SPPR_HI_OFFSET)
+
+#define SPI_TRANSFER_BEGIN 0x01 // Assert CS before transfer
+#define SPI_TRANSFER_END 0x02 // Deassert CS after transfers
+
+#define SPI_TIMEOUT 100000
+
+typedef struct {
+ MARVELL_SPI_MASTER_PROTOCOL SpiMasterProtocol;
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ EFI_LOCK Lock;
+} SPI_MASTER;
+
+EFI_STATUS
+EFIAPI
+MvSpiTransfer (
+ IN MARVELL_SPI_MASTER_PROTOCOL *This,
+ IN SPI_DEVICE *Slave,
+ IN UINTN DataByteCount,
+ IN VOID *DataOut,
+ IN VOID *DataIn,
+ IN UINTN Flag
+ );
+
+EFI_STATUS
+EFIAPI
+MvSpiReadWrite (
+ IN MARVELL_SPI_MASTER_PROTOCOL *This,
+ IN SPI_DEVICE *Slave,
+ IN UINT8 *Cmd,
+ IN UINTN CmdSize,
+ IN UINT8 *DataOut,
+ OUT UINT8 *DataIn,
+ IN UINTN DataSize
+ );
+
+EFI_STATUS
+EFIAPI
+MvSpiInit (
+ IN MARVELL_SPI_MASTER_PROTOCOL * This
+ );
+
+SPI_DEVICE *
+EFIAPI
+MvSpiSetupSlave (
+ IN MARVELL_SPI_MASTER_PROTOCOL * This,
+ IN UINTN Cs,
+ IN SPI_MODE Mode
+ );
+
+EFI_STATUS
+EFIAPI
+MvSpiFreeSlave (
+ IN SPI_DEVICE *Slave
+ );
+
+EFI_STATUS
+EFIAPI
+SpiMasterEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+#endif // __SPI_MASTER_H__
diff --git a/Platform/Marvell/Drivers/Spi/MvSpiDxe.inf b/Platform/Marvell/Drivers/Spi/MvSpiDxe.inf
new file mode 100644
index 0000000000..d38d331f7c
--- /dev/null
+++ b/Platform/Marvell/Drivers/Spi/MvSpiDxe.inf
@@ -0,0 +1,66 @@
+#
+# Marvell BSD License Option
+#
+# If you received this File from Marvell, you may opt to use, redistribute
+# and/or modify this File under the following licensing terms.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Marvell nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SpiMasterDxe
+ FILE_GUID = c19dbc8a-f4f9-43b0-aee5-802e3ed03d15
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = SpiMasterEntryPoint
+
+[Sources]
+ MvSpiDxe.c
+ MvSpiDxe.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ Platform/Marvell/Marvell.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ TimerLib
+ UefiLib
+ DebugLib
+ MemoryAllocationLib
+ IoLib
+
+[FixedPcd]
+ gMarvellTokenSpaceGuid.PcdSpiRegBase
+ gMarvellTokenSpaceGuid.PcdSpiClockFrequency
+ gMarvellTokenSpaceGuid.PcdSpiMaxFrequency
+
+[Protocols]
+ gMarvellSpiMasterProtocolGuid
+
+[Depex]
+ TRUE
diff --git a/Platform/Marvell/Include/Library/MppLib.h b/Platform/Marvell/Include/Library/MppLib.h
new file mode 100644
index 0000000000..77c6cdb1c4
--- /dev/null
+++ b/Platform/Marvell/Include/Library/MppLib.h
@@ -0,0 +1,42 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#ifndef __MPPLIB_H__
+#define __MPPLIB_H__
+
+EFI_STATUS
+MppInitialize (
+ );
+
+#endif
diff --git a/Platform/Marvell/Include/Library/MvComPhyLib.h b/Platform/Marvell/Include/Library/MvComPhyLib.h
new file mode 100644
index 0000000000..6076ede613
--- /dev/null
+++ b/Platform/Marvell/Include/Library/MvComPhyLib.h
@@ -0,0 +1,48 @@
+/*******************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#ifndef __MVCOMPHYLIB_H__
+#define __MVCOMPHYLIB_H__
+
+typedef enum {
+ MvComPhyTypeCp110,
+ MvComPhyTypeMax,
+} MV_COMPHY_CHIP_TYPE;
+
+EFI_STATUS
+MvComPhyInit (
+ VOID
+ );
+
+#endif
diff --git a/Platform/Marvell/Include/Library/MvHwDescLib.h b/Platform/Marvell/Include/Library/MvHwDescLib.h
new file mode 100644
index 0000000000..ac8dc37006
--- /dev/null
+++ b/Platform/Marvell/Include/Library/MvHwDescLib.h
@@ -0,0 +1,169 @@
+/********************************************************************************
+Copyright (C) 2017 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#ifndef __MVHWDESCLIB_H__
+#define __MVHWDESCLIB_H__
+
+#include <Library/MvComPhyLib.h>
+#include <Library/NonDiscoverableDeviceRegistrationLib.h>
+
+//
+// Helper macros
+//
+
+// Check if device is enabled - it expects PCD to be read to '<type>DeviceTable' array
+#define MVHW_DEV_ENABLED(type, index) (type ## DeviceTable[index])
+
+//
+// CommonPhy devices description template definition
+//
+#define MVHW_MAX_COMPHY_DEVS 4
+
+typedef struct {
+ UINT8 ComPhyDevCount;
+ UINTN ComPhyBaseAddresses[MVHW_MAX_COMPHY_DEVS];
+ UINTN ComPhyHpipe3BaseAddresses[MVHW_MAX_COMPHY_DEVS];
+ UINTN ComPhyLaneCount[MVHW_MAX_COMPHY_DEVS];
+ UINTN ComPhyMuxBitCount[MVHW_MAX_COMPHY_DEVS];
+ MV_COMPHY_CHIP_TYPE ComPhyChipType[MVHW_MAX_COMPHY_DEVS];
+} MVHW_COMPHY_DESC;
+
+//
+// NonDiscoverable devices description template definition
+//
+#define MVHW_MAX_XHCI_DEVS 4
+#define MVHW_MAX_AHCI_DEVS 4
+#define MVHW_MAX_SDHCI_DEVS 4
+
+typedef struct {
+ // XHCI
+ UINT8 XhciDevCount;
+ UINTN XhciBaseAddresses[MVHW_MAX_XHCI_DEVS];
+ UINTN XhciMemSize[MVHW_MAX_XHCI_DEVS];
+ NON_DISCOVERABLE_DEVICE_DMA_TYPE XhciDmaType[MVHW_MAX_XHCI_DEVS];
+ // AHCI
+ UINT8 AhciDevCount;
+ UINTN AhciBaseAddresses[MVHW_MAX_AHCI_DEVS];
+ UINTN AhciMemSize[MVHW_MAX_AHCI_DEVS];
+ NON_DISCOVERABLE_DEVICE_DMA_TYPE AhciDmaType[MVHW_MAX_AHCI_DEVS];
+ // SDHCI
+ UINT8 SdhciDevCount;
+ UINTN SdhciBaseAddresses[MVHW_MAX_SDHCI_DEVS];
+ UINTN SdhciMemSize[MVHW_MAX_SDHCI_DEVS];
+ NON_DISCOVERABLE_DEVICE_DMA_TYPE SdhciDmaType[MVHW_MAX_SDHCI_DEVS];
+} MVHW_NONDISCOVERABLE_DESC;
+
+//
+// RealTimeClock devices description template definition
+//
+#define MVHW_MAX_RTC_DEVS 2
+
+typedef struct {
+ UINT8 RtcDevCount;
+ UINTN RtcBaseAddresses[MVHW_MAX_RTC_DEVS];
+ UINTN RtcMemSize[MVHW_MAX_RTC_DEVS];
+} MVHW_RTC_DESC;
+
+//
+// Platform description of CommonPhy devices
+//
+#define MVHW_CP0_COMPHY_BASE 0xF2441000
+#define MVHW_CP0_HPIPE3_BASE 0xF2120000
+#define MVHW_CP0_COMPHY_LANES 6
+#define MVHW_CP0_COMPHY_MUX_BITS 4
+#define MVHW_CP1_COMPHY_BASE 0xF4441000
+#define MVHW_CP1_HPIPE3_BASE 0xF4120000
+#define MVHW_CP1_COMPHY_LANES 6
+#define MVHW_CP1_COMPHY_MUX_BITS 4
+
+#define DECLARE_A7K8K_COMPHY_TEMPLATE \
+STATIC \
+MVHW_COMPHY_DESC mA7k8kComPhyDescTemplate = {\
+ 2,\
+ { MVHW_CP0_COMPHY_BASE, MVHW_CP1_COMPHY_BASE },\
+ { MVHW_CP0_HPIPE3_BASE, MVHW_CP1_HPIPE3_BASE },\
+ { MVHW_CP0_COMPHY_LANES, MVHW_CP1_COMPHY_LANES },\
+ { MVHW_CP0_COMPHY_MUX_BITS, MVHW_CP1_COMPHY_MUX_BITS },\
+ { MvComPhyTypeCp110, MvComPhyTypeCp110 }\
+}
+
+//
+// Platform description of NonDiscoverable devices
+//
+#define MVHW_CP0_XHCI0_BASE 0xF2500000
+#define MVHW_CP0_XHCI1_BASE 0xF2510000
+#define MVHW_CP1_XHCI0_BASE 0xF4500000
+#define MVHW_CP1_XHCI1_BASE 0xF4510000
+
+#define MVHW_CP0_AHCI0_BASE 0xF2540000
+#define MVHW_CP0_AHCI0_ID 0
+#define MVHW_CP1_AHCI0_BASE 0xF4540000
+#define MVHW_CP1_AHCI0_ID 1
+
+#define MVHW_AP0_SDHCI0_BASE 0xF06E0000
+#define MVHW_CP0_SDHCI0_BASE 0xF2780000
+
+#define DECLARE_A7K8K_NONDISCOVERABLE_TEMPLATE \
+STATIC \
+MVHW_NONDISCOVERABLE_DESC mA7k8kNonDiscoverableDescTemplate = {\
+ 4, /* XHCI */\
+ { MVHW_CP0_XHCI0_BASE, MVHW_CP0_XHCI1_BASE, MVHW_CP1_XHCI0_BASE, MVHW_CP1_XHCI1_BASE },\
+ { SIZE_16KB, SIZE_16KB, SIZE_16KB, SIZE_16KB },\
+ { NonDiscoverableDeviceDmaTypeCoherent, NonDiscoverableDeviceDmaTypeCoherent,\
+ NonDiscoverableDeviceDmaTypeCoherent, NonDiscoverableDeviceDmaTypeCoherent },\
+ 2, /* AHCI */\
+ { MVHW_CP0_AHCI0_BASE, MVHW_CP1_AHCI0_BASE },\
+ { SIZE_8KB, SIZE_8KB },\
+ { NonDiscoverableDeviceDmaTypeCoherent, NonDiscoverableDeviceDmaTypeCoherent },\
+ 2, /* SDHCI */\
+ { MVHW_AP0_SDHCI0_BASE, MVHW_CP0_SDHCI0_BASE },\
+ { SIZE_1KB, SIZE_1KB },\
+ { NonDiscoverableDeviceDmaTypeCoherent, NonDiscoverableDeviceDmaTypeCoherent }\
+}
+
+//
+// Platform description of RealTimeClock devices
+//
+#define MVHW_CP0_RTC0_BASE 0xF2284000
+#define MVHW_CP1_RTC0_BASE 0xF4284000
+
+#define DECLARE_A7K8K_RTC_TEMPLATE \
+STATIC \
+MVHW_RTC_DESC mA7k8kRtcDescTemplate = {\
+ 2,\
+ { MVHW_CP0_RTC0_BASE, MVHW_CP1_RTC0_BASE },\
+ { SIZE_4KB, SIZE_4KB }\
+}
+
+#endif /* __MVHWDESCLIB_H__ */
diff --git a/Platform/Marvell/Include/Library/ParsePcdLib.h b/Platform/Marvell/Include/Library/ParsePcdLib.h
new file mode 100644
index 0000000000..a255685018
--- /dev/null
+++ b/Platform/Marvell/Include/Library/ParsePcdLib.h
@@ -0,0 +1,46 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#ifndef __PARSEPCDLIB_H__
+#define __PARSEPCDLIB_H__
+
+EFI_STATUS
+ParsePcdString (
+ IN CHAR16 *PcdString,
+ IN UINT8 Count,
+ OUT UINTN *ValueTable,
+ OUT CHAR16 **StrTable
+ );
+
+#endif
diff --git a/Platform/Marvell/Include/Library/UtmiPhyLib.h b/Platform/Marvell/Include/Library/UtmiPhyLib.h
new file mode 100644
index 0000000000..7c62cbab20
--- /dev/null
+++ b/Platform/Marvell/Include/Library/UtmiPhyLib.h
@@ -0,0 +1,43 @@
+/*******************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#ifndef __UTMIPHYLIB_H__
+#define __UTMIPHYLIB_H__
+
+EFI_STATUS
+UtmiPhyInit (
+ VOID
+ );
+
+#endif
diff --git a/Platform/Marvell/Include/Protocol/Eeprom.h b/Platform/Marvell/Include/Protocol/Eeprom.h
new file mode 100644
index 0000000000..fbe4282b91
--- /dev/null
+++ b/Platform/Marvell/Include/Protocol/Eeprom.h
@@ -0,0 +1,60 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#ifndef __MARVELL_EEPROM_H__
+#define __MARVELL_EEPROM_H__
+
+#define MARVELL_EEPROM_PROTOCOL_GUID { 0x71954bda, 0x60d3, 0x4ef8, { 0x8e, 0x3c, 0x0e, 0x33, 0x9f, 0x3b, 0xc2, 0x2b }}
+
+typedef struct _MARVELL_EEPROM_PROTOCOL MARVELL_EEPROM_PROTOCOL;
+
+#define EEPROM_READ 0x1
+#define EEPROM_WRITE 0x0
+typedef
+EFI_STATUS
+(EFIAPI *EFI_EEPROM_TRANSFER) (
+ IN CONST MARVELL_EEPROM_PROTOCOL *This,
+ IN UINT16 Address,
+ IN UINT32 Length,
+ IN UINT8 *Buffer,
+ IN UINT8 Operation
+ );
+
+struct _MARVELL_EEPROM_PROTOCOL {
+ EFI_EEPROM_TRANSFER Transfer;
+ UINT32 Identifier;
+};
+
+extern EFI_GUID gMarvellEepromProtocolGuid;
+#endif
diff --git a/Platform/Marvell/Include/Protocol/Mdio.h b/Platform/Marvell/Include/Protocol/Mdio.h
new file mode 100644
index 0000000000..10acad4cc7
--- /dev/null
+++ b/Platform/Marvell/Include/Protocol/Mdio.h
@@ -0,0 +1,66 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#ifndef __MDIO_H__
+#define __MDIO_H__
+
+#define MARVELL_MDIO_PROTOCOL_GUID { 0x40010b03, 0x5f08, 0x496a, { 0xa2, 0x64, 0x10, 0x5e, 0x72, 0xd3, 0x71, 0xaa }}
+
+typedef struct _MARVELL_MDIO_PROTOCOL MARVELL_MDIO_PROTOCOL;
+
+typedef
+EFI_STATUS
+(EFIAPI *MARVELL_MDIO_READ) (
+ IN CONST MARVELL_MDIO_PROTOCOL *This,
+ IN UINT32 PhyAddr,
+ IN UINT32 RegOff,
+ IN UINT32 *Data
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *MARVELL_MDIO_WRITE) (
+ IN CONST MARVELL_MDIO_PROTOCOL *This,
+ IN UINT32 PhyAddr,
+ IN UINT32 RegOff,
+ IN UINT32 Data
+ );
+
+struct _MARVELL_MDIO_PROTOCOL {
+ MARVELL_MDIO_READ Read;
+ MARVELL_MDIO_WRITE Write;
+};
+
+extern EFI_GUID gMarvellMdioProtocolGuid;
+#endif
diff --git a/Platform/Marvell/Include/Protocol/MvPhy.h b/Platform/Marvell/Include/Protocol/MvPhy.h
new file mode 100644
index 0000000000..43a9e0b889
--- /dev/null
+++ b/Platform/Marvell/Include/Protocol/MvPhy.h
@@ -0,0 +1,103 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#ifndef __MV_PHY_H__
+#define __MV_PHY_H__
+
+#define MARVELL_PHY_PROTOCOL_GUID { 0x32f48a43, 0x37e3, 0x4acf, { 0x93, 0xc4, 0x3e, 0x57, 0xa7, 0xb0, 0xfb, 0xdc }}
+
+typedef struct _MARVELL_PHY_PROTOCOL MARVELL_PHY_PROTOCOL;
+
+typedef enum {
+ PHY_CONNECTION_RGMII,
+ PHY_CONNECTION_RGMII_ID,
+ PHY_CONNECTION_RGMII_TXID,
+ PHY_CONNECTION_RGMII_RXID,
+ PHY_CONNECTION_SGMII,
+ PHY_CONNECTION_RTBI,
+ PHY_CONNECTION_XAUI,
+ PHY_CONNECTION_RXAUI
+} PHY_CONNECTION;
+
+typedef enum {
+ NO_SPEED,
+ SPEED_10,
+ SPEED_100,
+ SPEED_1000,
+ SPEED_2500,
+ SPEED_10000
+} PHY_SPEED;
+
+typedef struct {
+ UINT32 Addr;
+ BOOLEAN LinkUp;
+ BOOLEAN FullDuplex;
+ BOOLEAN AutoNegotiation;
+ PHY_SPEED Speed;
+ PHY_CONNECTION Connection;
+} PHY_DEVICE;
+
+/*
+ * Before calling MARVELL_PHY_STATUS driver should request PHY_DEVICE structure by
+ * calling MARVELL_PHY_INIT. Pointer to that needs to be provided as an argument to
+ * MARVELL_PHY_STATUS.
+ */
+typedef
+EFI_STATUS
+(EFIAPI *MARVELL_PHY_STATUS) (
+ IN CONST MARVELL_PHY_PROTOCOL *This,
+ IN OUT PHY_DEVICE *PhyDev
+ );
+
+/*
+ * MARVELL_PHY_INIT allocates PhyDev and provides driver with pointer via **PhyDev.
+ * After it becomes unnecessary, PhyDev should be freed by a driver (or it will
+ * get freed at ExitBootServices).
+ */
+typedef
+EFI_STATUS
+(EFIAPI *MARVELL_PHY_INIT) (
+ IN CONST MARVELL_PHY_PROTOCOL *This,
+ IN UINT32 PhyAddr,
+ IN PHY_CONNECTION PhyConnection,
+ IN OUT PHY_DEVICE **PhyDev
+ );
+
+struct _MARVELL_PHY_PROTOCOL {
+ MARVELL_PHY_STATUS Status;
+ MARVELL_PHY_INIT Init;
+};
+
+extern EFI_GUID gMarvellPhyProtocolGuid;
+#endif
diff --git a/Platform/Marvell/Include/Protocol/Spi.h b/Platform/Marvell/Include/Protocol/Spi.h
new file mode 100644
index 0000000000..ae78a31ca0
--- /dev/null
+++ b/Platform/Marvell/Include/Protocol/Spi.h
@@ -0,0 +1,105 @@
+/*******************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+#ifndef __MARVELL_SPI_MASTER_PROTOCOL_H__
+#define __MARVELL_SPI_MASTER_PROTOCOL_H__
+
+extern EFI_GUID gMarvellSpiMasterProtocolGuid;
+
+typedef struct _MARVELL_SPI_MASTER_PROTOCOL MARVELL_SPI_MASTER_PROTOCOL;
+
+typedef enum {
+ SPI_MODE0, // CPOL = 0 & CPHA = 0
+ SPI_MODE1, // CPOL = 0 & CPHA = 1
+ SPI_MODE2, // CPOL = 1 & CPHA = 0
+ SPI_MODE3 // CPOL = 1 & CPHA = 1
+} SPI_MODE;
+
+typedef struct {
+ INTN Cs;
+ INTN MaxFreq;
+ SPI_MODE Mode;
+} SPI_DEVICE;
+
+typedef
+EFI_STATUS
+(EFIAPI *MV_SPI_INIT) (
+ IN MARVELL_SPI_MASTER_PROTOCOL *This
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *MV_SPI_TRANSFER) (
+ IN MARVELL_SPI_MASTER_PROTOCOL *This,
+ IN SPI_DEVICE *Slave,
+ IN UINTN DataByteCount,
+ IN VOID *DataOut,
+ IN VOID *DataIn,
+ IN UINTN Flag
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI * MV_SPI_READ_WRITE) (
+ IN MARVELL_SPI_MASTER_PROTOCOL *This,
+ IN SPI_DEVICE *Slave,
+ IN UINT8 *Cmd,
+ IN UINTN CmdSize,
+ IN UINT8 *DataOut,
+ OUT UINT8 *DataIn,
+ IN UINTN DataSize
+ );
+
+typedef
+SPI_DEVICE *
+(EFIAPI *MV_SPI_SETUP_DEVICE) (
+ IN MARVELL_SPI_MASTER_PROTOCOL *This,
+ IN UINTN Cs,
+ IN SPI_MODE Mode
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *MV_SPI_FREE_DEVICE) (
+ IN SPI_DEVICE *SpiDev
+ );
+
+struct _MARVELL_SPI_MASTER_PROTOCOL {
+ MV_SPI_INIT Init;
+ MV_SPI_READ_WRITE ReadWrite;
+ MV_SPI_TRANSFER Transfer;
+ MV_SPI_SETUP_DEVICE SetupDevice;
+ MV_SPI_FREE_DEVICE FreeDevice;
+};
+
+#endif // __MARVELL_SPI_MASTER_PROTOCOL_H__
diff --git a/Platform/Marvell/Include/Protocol/SpiFlash.h b/Platform/Marvell/Include/Protocol/SpiFlash.h
new file mode 100644
index 0000000000..743bb87553
--- /dev/null
+++ b/Platform/Marvell/Include/Protocol/SpiFlash.h
@@ -0,0 +1,113 @@
+/*******************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+#ifndef __MV_SPI_FLASH__
+#define __MV_SPI_FLASH__
+
+#include <Protocol/Spi.h>
+
+#define CMD_READ_ID 0x9f
+#define READ_STATUS_REG_CMD 0x0b
+#define CMD_WRITE_ENABLE 0x06
+#define CMD_FLAG_STATUS 0x70
+#define CMD_WRITE_STATUS_REG 0x01
+#define CMD_READ_ARRAY_FAST 0x0b
+#define CMD_PAGE_PROGRAM 0x02
+#define CMD_BANK_WRITE 0xc5
+#define CMD_ERASE_64K 0xd8
+#define CMD_4B_ADDR_ENABLE 0xb7
+
+extern EFI_GUID gMarvellSpiFlashProtocolGuid;
+
+typedef struct _MARVELL_SPI_FLASH_PROTOCOL MARVELL_SPI_FLASH_PROTOCOL;
+
+typedef
+EFI_STATUS
+(EFIAPI *MV_SPI_FLASH_INIT) (
+ IN MARVELL_SPI_FLASH_PROTOCOL *This,
+ IN SPI_DEVICE *SpiDev
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *MV_SPI_FLASH_READ_ID) (
+ IN SPI_DEVICE *SpiDev,
+ IN UINT32 DataByteCount,
+ IN OUT UINT8 *Buffer
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *MV_SPI_FLASH_READ) (
+ IN SPI_DEVICE *SpiDev,
+ IN UINT32 Address,
+ IN UINTN DataByteCount,
+ IN VOID *Buffer
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *MV_SPI_FLASH_WRITE) (
+ IN SPI_DEVICE *SpiDev,
+ IN UINT32 Address,
+ IN UINTN DataByteCount,
+ IN VOID *Buffer
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *MV_SPI_FLASH_ERASE) (
+ IN SPI_DEVICE *SpiDev,
+ IN UINTN Address,
+ IN UINTN DataByteCount
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *MV_SPI_FLASH_UPDATE) (
+ IN SPI_DEVICE *SpiDev,
+ IN UINT32 Address,
+ IN UINTN DataByteCount,
+ IN UINT8 *Buffer
+ );
+
+struct _MARVELL_SPI_FLASH_PROTOCOL {
+ MV_SPI_FLASH_INIT Init;
+ MV_SPI_FLASH_READ_ID ReadId;
+ MV_SPI_FLASH_READ Read;
+ MV_SPI_FLASH_WRITE Write;
+ MV_SPI_FLASH_ERASE Erase;
+ MV_SPI_FLASH_UPDATE Update;
+};
+
+#endif // __MV_SPI_FLASH__
diff --git a/Platform/Marvell/Library/ComPhyLib/ComPhyCp110.c b/Platform/Marvell/Library/ComPhyLib/ComPhyCp110.c
new file mode 100755
index 0000000000..40a7b9921c
--- /dev/null
+++ b/Platform/Marvell/Library/ComPhyLib/ComPhyCp110.c
@@ -0,0 +1,1853 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must Retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#include "ComPhyLib.h"
+#include <Library/MvHwDescLib.h>
+
+#define SD_LANE_ADDR_WIDTH 0x1000
+#define HPIPE_ADDR_OFFSET 0x800
+#define COMPHY_ADDR_LANE_WIDTH 0x28
+#define SD_ADDR(base, Lane) (base + SD_LANE_ADDR_WIDTH * Lane)
+#define HPIPE_ADDR(base, Lane) (SD_ADDR(base, Lane) + HPIPE_ADDR_OFFSET)
+#define COMPHY_ADDR(base, Lane) (base + COMPHY_ADDR_LANE_WIDTH * Lane)
+
+DECLARE_A7K8K_NONDISCOVERABLE_TEMPLATE;
+
+/*
+ * For CP-110 we have 2 Selector registers "PHY Selectors"
+ * and " PIPE Selectors".
+ * PIPE selector include USB and PCIe options.
+ * PHY selector include the Ethernet and SATA options, every Ethernet option
+ * has different options, for example: serdes Lane2 have option Eth_port_0
+ * that include (SGMII0, RXAUI0, SFI)
+ */
+COMPHY_MUX_DATA Cp110ComPhyMuxData[] = {
+ /* Lane 0 */
+ {4, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_SGMII1, 0x1},
+ {COMPHY_TYPE_SATA1, 0x4}, {COMPHY_TYPE_SATA3, 0x4}}},
+ /* Lane 1 */
+ {4, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_SGMII2, 0x1},
+ {COMPHY_TYPE_SATA0, 0x4}, {COMPHY_TYPE_SATA2, 0x4}}},
+ /* Lane 2 */
+ {6, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_SGMII0, 0x1},
+ {COMPHY_TYPE_RXAUI0, 0x1}, {COMPHY_TYPE_SFI, 0x1},
+ {COMPHY_TYPE_SATA0, 0x4}, {COMPHY_TYPE_SATA2, 0x4}}},
+ /* Lane 3 */
+ {8, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_RXAUI1, 0x1},
+ {COMPHY_TYPE_SGMII1, 0x2}, {COMPHY_TYPE_SATA1, 0x4},
+ {COMPHY_TYPE_SATA3, 0x4}}},
+ /* Lane 4 */
+ {7, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_SGMII0, 0x2},
+ {COMPHY_TYPE_RXAUI0, 0x2}, {COMPHY_TYPE_SFI, 0x2},
+ {COMPHY_TYPE_SGMII1, 0x1}}},
+ /* Lane 5 */
+ {6, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_SGMII2, 0x1},
+ {COMPHY_TYPE_RXAUI1, 0x2}, {COMPHY_TYPE_SATA1, 0x4},
+ {COMPHY_TYPE_SATA3, 0x4}}},
+};
+
+COMPHY_MUX_DATA Cp110ComPhyPipeMuxData[] = {
+ /* Lane 0 */
+ {2, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_PCIE0, 0x4}}},
+ /* Lane 1 */
+ {4, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_USB3_HOST0, 0x1},
+ {COMPHY_TYPE_USB3_DEVICE, 0x2}, {COMPHY_TYPE_PCIE0, 0x4}}},
+ /* Lane 2 */
+ {3, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_USB3_HOST0, 0x1},
+ {COMPHY_TYPE_PCIE0, 0x4}}},
+ /* Lane 3 */
+ {3, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_USB3_HOST1, 0x1},
+ {COMPHY_TYPE_PCIE0, 0x4}}},
+ /* Lane 4 */
+ {4, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_USB3_HOST1, 0x1},
+ {COMPHY_TYPE_USB3_DEVICE, 0x2}, {COMPHY_TYPE_PCIE1, 0x4}}},
+ /* Lane 5 */
+ {2, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_PCIE2, 0x4}}},
+};
+
+STATIC
+VOID
+ComPhyPcieRFUConfiguration (
+ IN EFI_PHYSICAL_ADDRESS ComPhyAddr
+)
+{
+ UINT32 Mask, Data;
+
+ /* RFU configurations - hard reset ComPhy */
+ Mask = COMMON_PHY_CFG1_PWR_UP_MASK;
+ Data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET;
+ Mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK;
+ Data |= 0x1 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET;
+ Mask |= COMMON_PHY_CFG1_PWR_ON_RESET_MASK;
+ Data |= 0x0 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET;
+ Mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK;
+ Data |= 0x0 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET;
+ Mask |= COMMON_PHY_PHY_MODE_MASK;
+ Data |= 0x0 << COMMON_PHY_PHY_MODE_OFFSET;
+ RegSet (ComPhyAddr + COMMON_PHY_CFG1_REG, Data, Mask);
+
+ /* Release from hard reset */
+ Mask = COMMON_PHY_CFG1_PWR_ON_RESET_MASK;
+ Data = 0x1 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET;
+ Mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK;
+ Data |= 0x1 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET;
+ RegSet (ComPhyAddr + COMMON_PHY_CFG1_REG, Data, Mask);
+
+ /* Wait 1ms - until band gap and ref clock ready */
+ MicroSecondDelay (1000);
+ MemoryFence ();
+}
+
+STATIC
+VOID
+ComPhyPciePhyConfiguration (
+ IN EFI_PHYSICAL_ADDRESS ComPhyAddr,
+ IN EFI_PHYSICAL_ADDRESS HpipeAddr
+)
+{
+ UINT32 Mask, Data, PcieClk = 0;
+
+ /* Set PIPE soft reset */
+ Mask = HPIPE_RST_CLK_CTRL_PIPE_RST_MASK;
+ Data = 0x1 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET;
+
+ /* Set PHY Datapath width mode for V0 */
+ Mask |= HPIPE_RST_CLK_CTRL_FIXED_PCLK_MASK;
+ Data |= 0x1 << HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET;
+
+ /* Set Data bus width USB mode for V0 */
+ Mask |= HPIPE_RST_CLK_CTRL_PIPE_WIDTH_MASK;
+ Data |= 0x0 << HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET;
+
+ /* Set CORE_CLK output frequency for 250Mhz */
+ Mask |= HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_MASK;
+ Data |= 0x0 << HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET;
+ RegSet (HpipeAddr + HPIPE_RST_CLK_CTRL_REG, Data, Mask);
+
+ /* Set PLL ready delay for 0x2 */
+ RegSet (HpipeAddr + HPIPE_CLK_SRC_LO_REG,
+ 0x2 << HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET,
+ HPIPE_CLK_SRC_LO_PLL_RDY_DL_MASK);
+
+ /* Set PIPE mode interface to PCIe3 - 0x1 */
+ RegSet (HpipeAddr + HPIPE_CLK_SRC_HI_REG,
+ 0x1 << HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET, HPIPE_CLK_SRC_HI_MODE_PIPE_MASK);
+
+ /* Config update polarity equalization */
+ RegSet (HpipeAddr + HPIPE_LANE_EQ_CFG1_REG,
+ 0x1 << HPIPE_CFG_UPDATE_POLARITY_OFFSET, HPIPE_CFG_UPDATE_POLARITY_MASK);
+
+ /* Set PIPE version 4 to mode enable */
+ RegSet (HpipeAddr + HPIPE_DFE_CTRL_28_REG,
+ 0x1 << HPIPE_DFE_CTRL_28_PIPE4_OFFSET, HPIPE_DFE_CTRL_28_PIPE4_MASK);
+
+ /* Enable PIN clock 100M_125M */
+ Mask = HPIPE_MISC_CLK100M_125M_MASK;
+ Data = 0x1 << HPIPE_MISC_CLK100M_125M_OFFSET;
+
+ /* Set PIN_TXDCLK_2X Clock Frequency Selection for outputs 500MHz clock */
+ Mask |= HPIPE_MISC_TXDCLK_2X_MASK;
+ Data |= 0x0 << HPIPE_MISC_TXDCLK_2X_OFFSET;
+
+ /* Enable 500MHz Clock */
+ Mask |= HPIPE_MISC_CLK500_EN_MASK;
+ Data |= 0x1 << HPIPE_MISC_CLK500_EN_OFFSET;
+
+ if (PcieClk) {
+ /* Set reference clock comes from group 1 */
+ Mask |= HPIPE_MISC_REFCLK_SEL_MASK;
+ Data |= 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET;
+ } else {
+ /* Set reference clock comes from group 2 */
+ Mask |= HPIPE_MISC_REFCLK_SEL_MASK;
+ Data |= 0x1 << HPIPE_MISC_REFCLK_SEL_OFFSET;
+ }
+
+ /* Force ICP */
+ Mask |= HPIPE_MISC_ICP_FORCE_MASK;
+ Data |= 0x1 << HPIPE_MISC_ICP_FORCE_OFFSET;
+ RegSet (HpipeAddr + HPIPE_MISC_REG, Data, Mask);
+
+ if (PcieClk) {
+ /* Set reference frequcency select - 0x2 for 25MHz*/
+ Mask = HPIPE_PWR_PLL_REF_FREQ_MASK;
+ Data = 0x2 << HPIPE_PWR_PLL_REF_FREQ_OFFSET;
+ } else {
+ /* Set reference frequcency select - 0x0 for 100MHz*/
+ Mask = HPIPE_PWR_PLL_REF_FREQ_MASK;
+ Data = 0x0 << HPIPE_PWR_PLL_REF_FREQ_OFFSET;
+ }
+
+ /* Set PHY mode to PCIe */
+ Mask |= HPIPE_PWR_PLL_PHY_MODE_MASK;
+ Data |= 0x3 << HPIPE_PWR_PLL_PHY_MODE_OFFSET;
+ RegSet (HpipeAddr + HPIPE_PWR_PLL_REG, Data, Mask);
+
+ /*
+ * Set the amount of time spent in the LoZ state - set
+ * for 0x7 only if the PCIe clock is output
+ */
+ if (PcieClk)
+ RegSet (HpipeAddr + HPIPE_GLOBAL_PM_CTRL,
+ 0x7 << HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET,
+ HPIPE_GLOBAL_PM_RXDLOZ_WAIT_MASK);
+
+ /* Set Maximal PHY Generation Setting (8Gbps) */
+ Mask = HPIPE_INTERFACE_GEN_MAX_MASK;
+ Data = 0x2 << HPIPE_INTERFACE_GEN_MAX_OFFSET;
+ /* Bypass frame detection and sync detection for RX DATA */
+ Mask |= HPIPE_INTERFACE_DET_BYPASS_MASK;
+ Data |= 0x1 << HPIPE_INTERFACE_DET_BYPASS_OFFSET;
+ /* Set Link Train Mode (Tx training control pins are used) */
+ Mask |= HPIPE_INTERFACE_LINK_TRAIN_MASK;
+ Data |= 0x1 << HPIPE_INTERFACE_LINK_TRAIN_OFFSET;
+ RegSet (HpipeAddr + HPIPE_INTERFACE_REG, Data, Mask);
+
+ /* Set Idle_sync enable */
+ Mask = HPIPE_PCIE_IDLE_SYNC_MASK;
+ Data = 0x1 << HPIPE_PCIE_IDLE_SYNC_OFFSET;
+
+ /* Select bits for PCIE Gen3(32bit) */
+ Mask |= HPIPE_PCIE_SEL_BITS_MASK;
+ Data |= 0x2 << HPIPE_PCIE_SEL_BITS_OFFSET;
+ RegSet (HpipeAddr + HPIPE_PCIE_REG0, Data, Mask);
+
+ /* Enable Tx_adapt_g1 */
+ Mask = HPIPE_TX_TRAIN_CTRL_G1_MASK;
+ Data = 0x1 << HPIPE_TX_TRAIN_CTRL_G1_OFFSET;
+
+ /* Enable Tx_adapt_gn1 */
+ Mask |= HPIPE_TX_TRAIN_CTRL_GN1_MASK;
+ Data |= 0x1 << HPIPE_TX_TRAIN_CTRL_GN1_OFFSET;
+
+ /* Disable Tx_adapt_g0 */
+ Mask |= HPIPE_TX_TRAIN_CTRL_G0_MASK;
+ Data |= 0x0 << HPIPE_TX_TRAIN_CTRL_G0_OFFSET;
+ RegSet (HpipeAddr + HPIPE_TX_TRAIN_CTRL_REG, Data, Mask);
+
+ /* Set reg_tx_train_chk_init */
+ Mask = HPIPE_TX_TRAIN_CHK_INIT_MASK;
+ Data = 0x0 << HPIPE_TX_TRAIN_CHK_INIT_OFFSET;
+
+ /* Enable TX_COE_FM_PIN_PCIE3_EN */
+ Mask |= HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_MASK;
+ Data |= 0x1 << HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET;
+ RegSet (HpipeAddr + HPIPE_TX_TRAIN_REG, Data, Mask);
+}
+
+STATIC
+VOID
+ComPhyPcieSetAnalogParameters (
+ IN EFI_PHYSICAL_ADDRESS HpipeAddr
+)
+{
+ UINT32 Data, Mask;
+
+ /* Set preset sweep configurations */
+ Mask = HPIPE_TX_TX_STATUS_CHECK_MODE_MASK |
+ HPIPE_TX_NUM_OF_PRESET_MASK |
+ HPIPE_TX_SWEEP_PRESET_EN_MASK;
+ Data = (0x1 << HPIPE_TX_STATUS_CHECK_MODE_OFFSET) |
+ (0x7 << HPIPE_TX_NUM_OF_PRESET_OFFSET) |
+ (0x1 << HPIPE_TX_SWEEP_PRESET_EN_OFFSET);
+ MmioAndThenOr32 (HpipeAddr + HPIPE_TX_TRAIN_CTRL_11_REG, ~Mask, Data);
+
+ /* Tx train start configuration */
+ Mask = HPIPE_TX_TRAIN_START_SQ_EN_MASK |
+ HPIPE_TX_TRAIN_START_FRM_DET_EN_MASK |
+ HPIPE_TX_TRAIN_START_FRM_LOCK_EN_MASK |
+ HPIPE_TX_TRAIN_WAIT_TIME_EN_MASK;
+ Data = (0x1 << HPIPE_TX_TRAIN_START_SQ_EN_OFFSET) |
+ (0x1 << HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET);
+ MmioAndThenOr32 (HpipeAddr + HPIPE_TX_TRAIN_CTRL_5_REG, ~Mask, Data);
+
+ /* Enable Tx train P2P */
+ MmioOr32 (HpipeAddr + HPIPE_TX_TRAIN_CTRL_0_REG, HPIPE_TX_TRAIN_P2P_HOLD_MASK);
+
+ /* Configure Tx train timeout */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_TX_TRAIN_CTRL_4_REG,
+ ~HPIPE_TRX_TRAIN_TIMER_MASK,
+ 0x17 << HPIPE_TRX_TRAIN_TIMER_OFFSET
+ );
+
+ /* Disable G0/G1/GN1 adaptation */
+ MmioAnd32 (
+ HpipeAddr + HPIPE_TX_TRAIN_CTRL_REG,
+ ~(HPIPE_TX_TRAIN_CTRL_G1_MASK | HPIPE_TX_TRAIN_CTRL_GN1_MASK | HPIPE_TX_TRAIN_CTRL_G0_OFFSET)
+ );
+
+ /* Disable DTL frequency loop */
+ MmioAnd32 (HpipeAddr + HPIPE_PWR_CTR_DTL_REG, ~HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK);
+
+ /* Configure Generation 3 DFE */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_G3_SET4_REG,
+ ~HPIPE_GX_SET4_DFE_RES_MASK,
+ 0x3 << HPIPE_GX_SET4_DFE_RES_OFFSET
+ );
+
+ /* Use TX/RX training result for DFE */
+ MmioAnd32 (HpipeAddr + HPIPE_DFE_REG0, ~HPIPE_DFE_RES_FORCE_MASK);
+
+ /* Configure initial and final coefficient value for receiver */
+ MmioAndThenOr32 (HpipeAddr + HPIPE_G3_SET1_REG, ~Mask, Data);
+ Mask = HPIPE_GX_SET1_RX_SELMUPI_MASK |
+ HPIPE_GX_SET1_RX_SELMUPP_MASK |
+ HPIPE_GX_SET1_SAMPLER_INPAIRX2_EN_MASK;
+ Data = 0x1 | (0x1 << HPIPE_GX_SET1_RX_SELMUPP_OFFSET);
+ MmioAndThenOr32 (HpipeAddr + HPIPE_G3_SET1_REG, ~Mask, Data);
+
+ /* Trigger sampler 5us enable pulse */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG,
+ ~HPIPE_SAMPLER_MASK,
+ 0x1 << HPIPE_SAMPLER_OFFSET
+ );
+ MicroSecondDelay (5);
+ MmioAnd32 (
+ HpipeAddr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG,
+ ~HPIPE_SAMPLER_MASK
+ );
+
+ /* FFE resistor tuning for different bandwidth */
+ Mask = HPIPE_GX_SET3_FFE_DEG_RES_LEVEL_MASK |
+ HPIPE_GX_SET3_FFE_LOAD_RES_LEVEL_MASK;
+ Data = (0x1 << HPIPE_GX_SET3_FFE_DEG_RES_LEVEL_OFFSET) |
+ (0x3 << HPIPE_GX_SET3_FFE_LOAD_RES_LEVEL_OFFSET);
+ MmioAndThenOr32 (HpipeAddr + HPIPE_G3_SET3_REG, ~Mask, Data);
+
+ /* Pattern lock lost timeout disable */
+ MmioAnd32 (HpipeAddr + HPIPE_FRAME_DETECT_CTRL_3_REG, ~HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_MASK);
+
+ /* Configure DFE adaptations */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_CDR_CONTROL_REG,
+ ~(HPIPE_CDR_MAX_DFE_ADAPT_1_MASK | HPIPE_CDR_MAX_DFE_ADAPT_0_MASK | HPIPE_CDR_RX_MAX_DFE_ADAPT_1_MASK),
+ 0x1 << HPIPE_CDR_MAX_DFE_ADAPT_1_OFFSET
+ );
+ MmioAnd32 (HpipeAddr + HPIPE_DFE_CONTROL_REG, ~HPIPE_DFE_TX_MAX_DFE_ADAPT_MASK);
+
+ /* Hpipe Generation 2 setting 1*/
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_G2_SET1_REG,
+ ~(HPIPE_GX_SET1_RX_SELMUPI_MASK | HPIPE_GX_SET1_RX_SELMUPP_MASK | HPIPE_GX_SET1_RX_SELMUFI_MASK),
+ 0x1 << HPIPE_GX_SET1_RX_SELMUPP_OFFSET
+ );
+
+ /* DFE enable */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_G2_SET4_REG,
+ ~HPIPE_GX_SET4_DFE_RES_MASK,
+ 0x3 << HPIPE_GX_SET4_DFE_RES_OFFSET
+ );
+
+ /* Configure DFE Resolution */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_LANE_CFG4_REG,
+ ~HPIPE_LANE_CFG4_DFE_EN_SEL_MASK,
+ 0x1 << HPIPE_LANE_CFG4_DFE_EN_SEL_OFFSET
+ );
+
+ /* VDD calibration control */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_VDD_CAL_CTRL_REG,
+ ~HPIPE_EXT_SELLV_RXSAMPL_MASK,
+ 0x16 << HPIPE_EXT_SELLV_RXSAMPL_OFFSET
+ );
+
+ /* Set PLL Charge-pump Current Control */
+ MmioAndThenOr32 (HpipeAddr + HPIPE_G3_SET5_REG, ~HPIPE_GX_SET5_ICP_MASK, 0x4);
+
+ /* Set lane rqualization remote setting */
+ Mask = HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_MASK |
+ HPIPE_LANE_CFG_FOM_ONLY_MODE_MASK |
+ HPIPE_LANE_CFG_FOM_PRESET_VECTOR_MASK;
+ Data = (0x1 << HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_OFFSET) |
+ (0x1 << HPIPE_LANE_CFG_FOM_ONLY_MODE_OFFFSET) |
+ (0x2 << HPIPE_LANE_CFG_FOM_PRESET_VECTOR_OFFSET);
+ MmioAndThenOr32 (HpipeAddr + HPIPE_LANE_EQ_REMOTE_SETTING_REG, ~Mask, Data);
+
+ /* Set phy in root complex mode */
+ MmioOr32 (HpipeAddr + HPIPE_LANE_EQU_CONFIG_0_REG, HPIPE_CFG_PHY_RC_EP_MASK);
+}
+
+STATIC
+VOID
+ComPhyPciePhyPowerUp (
+ IN EFI_PHYSICAL_ADDRESS HpipeAddr
+)
+{
+ /* Release from PIPE soft reset */
+ RegSet (HpipeAddr + HPIPE_RST_CLK_CTRL_REG,
+ 0x0 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET,
+ HPIPE_RST_CLK_CTRL_PIPE_RST_MASK);
+
+ /* Wait 15ms - for ComPhy calibration done */
+ MicroSecondDelay (15000);
+ MemoryFence ();
+}
+
+STATIC
+EFI_STATUS
+ComPhyPcieCheckPll (
+ IN EFI_PHYSICAL_ADDRESS HpipeAddr
+)
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ UINT32 Data;
+
+ /* Read Lane status */
+ Data = MmioRead32 (HpipeAddr + HPIPE_LANE_STATUS0_REG);
+ if ((Data & HPIPE_LANE_STATUS0_PCLK_EN_MASK) == 0) {
+ DEBUG((DEBUG_INFO, "ComPhy: Read from reg = %p - value = 0x%x\n",
+ HpipeAddr + HPIPE_LANE_STATUS0_REG, Data));
+ DEBUG((DEBUG_INFO, "ComPhy: HPIPE_LANE_STATUS0_PCLK_EN_MASK is 0\n"));
+ Status = EFI_D_ERROR;
+ }
+
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+ComPhyPciePowerUp (
+ IN UINT32 Lane,
+ IN UINT32 PcieBy4,
+ IN EFI_PHYSICAL_ADDRESS HpipeBase,
+ IN EFI_PHYSICAL_ADDRESS ComPhyBase
+ )
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ EFI_PHYSICAL_ADDRESS HpipeAddr = HPIPE_ADDR(HpipeBase, Lane);
+ EFI_PHYSICAL_ADDRESS ComPhyAddr = COMPHY_ADDR(ComPhyBase, Lane);
+
+ DEBUG((DEBUG_INFO, "ComPhy: stage: RFU configurations - hard reset ComPhy\n"));
+
+ ComPhyPcieRFUConfiguration (ComPhyAddr);
+
+ DEBUG((DEBUG_INFO, "ComPhy: stage: ComPhy configuration\n"));
+
+ ComPhyPciePhyConfiguration (ComPhyAddr, HpipeAddr);
+
+ DEBUG((DEBUG_INFO, "ComPhy: stage: Set analog paramters\n"));
+
+ ComPhyPcieSetAnalogParameters (HpipeAddr);
+
+ DEBUG((DEBUG_INFO, "ComPhy: stage: ComPhy power up\n"));
+
+ ComPhyPciePhyPowerUp (HpipeAddr);
+
+ DEBUG((DEBUG_INFO, "ComPhy: stage: Check PLL\n"));
+
+ Status = ComPhyPcieCheckPll (HpipeAddr);
+
+ return Status;
+}
+
+STATIC
+VOID
+ComPhyUsb3RFUConfiguration (
+ IN EFI_PHYSICAL_ADDRESS ComPhyAddr
+)
+{
+ UINT32 Mask, Data;
+
+ /* RFU configurations - hard reset ComPhy */
+ Mask = COMMON_PHY_CFG1_PWR_UP_MASK;
+ Data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET;
+ Mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK;
+ Data |= 0x1 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET;
+ Mask |= COMMON_PHY_CFG1_PWR_ON_RESET_MASK;
+ Data |= 0x0 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET;
+ Mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK;
+ Data |= 0x0 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET;
+ Mask |= COMMON_PHY_PHY_MODE_MASK;
+ Data |= 0x1 << COMMON_PHY_PHY_MODE_OFFSET;
+ RegSet (ComPhyAddr + COMMON_PHY_CFG1_REG, Data, Mask);
+
+ /* Release from hard reset */
+ Mask = COMMON_PHY_CFG1_PWR_ON_RESET_MASK;
+ Data = 0x1 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET;
+ Mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK;
+ Data |= 0x1 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET;
+ RegSet (ComPhyAddr + COMMON_PHY_CFG1_REG, Data, Mask);
+
+ /* Wait 1ms - until band gap and ref clock ready */
+ MicroSecondDelay (1000);
+ MemoryFence ();
+}
+
+STATIC
+VOID
+ComPhyUsb3PhyConfiguration (
+ IN EFI_PHYSICAL_ADDRESS HpipeAddr
+)
+{
+ UINT32 Mask, Data;
+
+ /* Set PIPE soft reset */
+ Mask = HPIPE_RST_CLK_CTRL_PIPE_RST_MASK;
+ Data = 0x1 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET;
+
+ /* Set PHY Datapath width mode for V0 */
+ Mask |= HPIPE_RST_CLK_CTRL_FIXED_PCLK_MASK;
+ Data |= 0x0 << HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET;
+
+ /* Set Data bus width USB mode for V0 */
+ Mask |= HPIPE_RST_CLK_CTRL_PIPE_WIDTH_MASK;
+ Data |= 0x0 << HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET;
+
+ /* Set CORE_CLK output frequency for 250Mhz */
+ Mask |= HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_MASK;
+ Data |= 0x0 << HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET;
+ RegSet (HpipeAddr + HPIPE_RST_CLK_CTRL_REG, Data, Mask);
+
+ /* Set PLL ready delay for 0x2 */
+ RegSet (HpipeAddr + HPIPE_CLK_SRC_LO_REG,
+ 0x2 << HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET,
+ HPIPE_CLK_SRC_LO_PLL_RDY_DL_MASK);
+
+ /* Set reference clock to come from group 1 - 25Mhz */
+ RegSet (HpipeAddr + HPIPE_MISC_REG, 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET,
+ HPIPE_MISC_REFCLK_SEL_MASK);
+
+ /* Set reference frequcency select - 0x2 */
+ Mask = HPIPE_PWR_PLL_REF_FREQ_MASK;
+ Data = 0x2 << HPIPE_PWR_PLL_REF_FREQ_OFFSET;
+
+ /* Set PHY mode to USB - 0x5 */
+ Mask |= HPIPE_PWR_PLL_PHY_MODE_MASK;
+ Data |= 0x5 << HPIPE_PWR_PLL_PHY_MODE_OFFSET;
+ RegSet (HpipeAddr + HPIPE_PWR_PLL_REG, Data, Mask);
+
+ /* Set the amount of time spent in the LoZ state - set for 0x7 */
+ RegSet (HpipeAddr + HPIPE_GLOBAL_PM_CTRL,
+ 0x7 << HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET,
+ HPIPE_GLOBAL_PM_RXDLOZ_WAIT_MASK);
+
+ /* Set max PHY generation setting - 5Gbps */
+ RegSet (HpipeAddr + HPIPE_INTERFACE_REG,
+ 0x1 << HPIPE_INTERFACE_GEN_MAX_OFFSET, HPIPE_INTERFACE_GEN_MAX_MASK);
+
+ /* Set select Data width 20Bit (SEL_BITS[2:0]) */
+ RegSet (HpipeAddr + HPIPE_LOOPBACK_REG,
+ 0x1 << HPIPE_LOOPBACK_SEL_OFFSET, HPIPE_LOOPBACK_SEL_MASK);
+}
+
+STATIC
+VOID
+ComPhyUsb3SetAnalogParameters (
+ IN EFI_PHYSICAL_ADDRESS HpipeAddr
+)
+{
+ UINT32 Data, Mask;
+
+ /* Set Pin DFE_PAT_DIS -> Bit[1]: PIN_DFE_PAT_DIS = 0x0 */
+ Mask = HPIPE_LANE_CFG4_DFE_CTRL_MASK;
+ Data = 0x1 << HPIPE_LANE_CFG4_DFE_CTRL_OFFSET;
+
+ /* Set Override PHY DFE control pins for 0x1 */
+ Mask |= HPIPE_LANE_CFG4_DFE_OVER_MASK;
+ Data |= 0x1 << HPIPE_LANE_CFG4_DFE_OVER_OFFSET;
+
+ /* Set Spread Spectrum Clock Enable fot 0x1 */
+ Mask |= HPIPE_LANE_CFG4_SSC_CTRL_MASK;
+ Data |= 0x1 << HPIPE_LANE_CFG4_SSC_CTRL_OFFSET;
+ RegSet (HpipeAddr + HPIPE_LANE_CFG4_REG, Data, Mask);
+}
+
+STATIC
+UINTN
+ComphyUsb3PowerUp (
+ UINT32 Lane,
+ EFI_PHYSICAL_ADDRESS HpipeBase,
+ EFI_PHYSICAL_ADDRESS ComPhyBase
+ )
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ UINT32 Data;
+ EFI_PHYSICAL_ADDRESS HpipeAddr = HPIPE_ADDR(HpipeBase, Lane);
+ EFI_PHYSICAL_ADDRESS ComPhyAddr = COMPHY_ADDR(ComPhyBase, Lane);
+
+ DEBUG((DEBUG_INFO, "ComPhy: stage: RFU configurations - hard reset ComPhy\n"));
+
+ ComPhyUsb3RFUConfiguration (ComPhyAddr);
+
+ /* Start ComPhy Configuration */
+ DEBUG((DEBUG_INFO, "stage: Comphy configuration\n"));
+
+ ComPhyUsb3PhyConfiguration (HpipeAddr);
+
+ /* Start analog paramters from ETP(HW) */
+ DEBUG((DEBUG_INFO, "ComPhy: stage: Analog paramters from ETP(HW)\n"));
+
+ ComPhyUsb3SetAnalogParameters (HpipeAddr);
+
+ DEBUG((DEBUG_INFO, "ComPhy: stage: Comphy power up\n"));
+
+ /* Release from PIPE soft reset */
+ RegSet (HpipeAddr + HPIPE_RST_CLK_CTRL_REG,
+ 0x0 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET,
+ HPIPE_RST_CLK_CTRL_PIPE_RST_MASK);
+
+ /* Wait 15ms - for ComPhy calibration done */
+ MicroSecondDelay (15000);
+ MemoryFence ();
+
+ DEBUG((DEBUG_INFO, "ComPhy: stage: Check PLL\n"));
+
+ /* Read Lane status */
+ Data = MmioRead32 (HpipeAddr + HPIPE_LANE_STATUS0_REG);
+ if ((Data & HPIPE_LANE_STATUS0_PCLK_EN_MASK) == 0) {
+ DEBUG((DEBUG_ERROR, "ComPhy: HPIPE_LANE_STATUS0_PCLK_EN_MASK is 0\n"));
+ Status = EFI_D_ERROR;
+ }
+
+ return Status;
+}
+
+STATIC
+UINT32
+PollingWithTimeout (
+ IN EFI_PHYSICAL_ADDRESS Addr,
+ IN UINT32 Val,
+ IN UINT32 Mask,
+ IN UINT64 Usec_timeout
+ )
+{
+ UINT32 Data;
+
+ do {
+ MicroSecondDelay(1);
+ Data = MmioRead32(Addr) & Mask;
+ } while (Data != Val && --Usec_timeout > 0);
+
+ if (Usec_timeout == 0)
+ return Data;
+ return 0;
+}
+
+STATIC
+VOID
+ComPhySataMacPowerDown (
+ IN EFI_PHYSICAL_ADDRESS SataBase
+)
+{
+ UINT32 Mask, Data;
+
+ /*
+ * MAC configuration - power down ComPhy
+ * Use indirect address for vendor specific SATA control register
+ */
+ RegSet (SataBase + SATA3_VENDOR_ADDRESS,
+ SATA_CONTROL_REG << SATA3_VENDOR_ADDR_OFSSET, SATA3_VENDOR_ADDR_MASK);
+
+ /* SATA 0 power down */
+ Mask = SATA3_CTRL_SATA0_PD_MASK;
+ Data = 0x1 << SATA3_CTRL_SATA0_PD_OFFSET;
+
+ /* SATA 1 power down */
+ Mask |= SATA3_CTRL_SATA1_PD_MASK;
+ Data |= 0x1 << SATA3_CTRL_SATA1_PD_OFFSET;
+
+ /* SATA SSU disable */
+ Mask |= SATA3_CTRL_SATA1_ENABLE_MASK;
+ Data |= 0x0 << SATA3_CTRL_SATA1_ENABLE_OFFSET;
+
+ /* SATA port 1 disable */
+ Mask |= SATA3_CTRL_SATA_SSU_MASK;
+ Data |= 0x0 << SATA3_CTRL_SATA_SSU_OFFSET;
+ RegSet (SataBase + SATA3_VENDOR_DATA, Data, Mask);
+}
+
+STATIC
+VOID
+ComPhySataRFUConfiguration (
+ IN EFI_PHYSICAL_ADDRESS ComPhyAddr,
+ IN EFI_PHYSICAL_ADDRESS SdIpAddr
+)
+{
+ UINT32 Mask, Data;
+
+ /* RFU configurations - hard reset ComPhy */
+ Mask = COMMON_PHY_CFG1_PWR_UP_MASK;
+ Data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET;
+ Mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK;
+ Data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET;
+ Mask |= COMMON_PHY_CFG1_PWR_ON_RESET_MASK;
+ Data |= 0x0 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET;
+ Mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK;
+ Data |= 0x0 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET;
+ RegSet (ComPhyAddr + COMMON_PHY_CFG1_REG, Data, Mask);
+
+ /* Set select Data width 40Bit - SATA mode only */
+ RegSet (ComPhyAddr + COMMON_PHY_CFG6_REG,
+ 0x1 << COMMON_PHY_CFG6_IF_40_SEL_OFFSET, COMMON_PHY_CFG6_IF_40_SEL_MASK);
+
+ /* Release from hard reset in SD external */
+ Mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
+ Data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
+ Mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
+ Data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
+ RegSet (SdIpAddr + SD_EXTERNAL_CONFIG1_REG, Data, Mask);
+
+ /* Wait 1ms - until band gap and ref clock ready */
+ MicroSecondDelay (1000);
+ MemoryFence ();
+}
+
+STATIC
+VOID
+ComPhySataPhyConfiguration (
+ IN EFI_PHYSICAL_ADDRESS HpipeAddr
+)
+{
+ UINT32 Mask, Data;
+
+ /* Set reference clock to comes from group 1 - choose 25Mhz */
+ RegSet (HpipeAddr + HPIPE_MISC_REG,
+ 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET, HPIPE_MISC_REFCLK_SEL_MASK);
+
+ /* Reference frequency select set 1 (for SATA = 25Mhz) */
+ Mask = HPIPE_PWR_PLL_REF_FREQ_MASK;
+ Data = 0x1 << HPIPE_PWR_PLL_REF_FREQ_OFFSET;
+
+ /* PHY mode select (set SATA = 0x0 */
+ Mask |= HPIPE_PWR_PLL_PHY_MODE_MASK;
+ Data |= 0x0 << HPIPE_PWR_PLL_PHY_MODE_OFFSET;
+ RegSet (HpipeAddr + HPIPE_PWR_PLL_REG, Data, Mask);
+
+ /* Set max PHY generation setting - 6Gbps */
+ RegSet (HpipeAddr + HPIPE_INTERFACE_REG,
+ 0x2 << HPIPE_INTERFACE_GEN_MAX_OFFSET, HPIPE_INTERFACE_GEN_MAX_MASK);
+
+ /* Set select Data width 40Bit (SEL_BITS[2:0]) */
+ RegSet (HpipeAddr + HPIPE_LOOPBACK_REG,
+ 0x2 << HPIPE_LOOPBACK_SEL_OFFSET, HPIPE_LOOPBACK_SEL_MASK);
+}
+
+STATIC
+VOID
+ComPhySataSetAnalogParameters (
+ IN EFI_PHYSICAL_ADDRESS HpipeAddr,
+ IN EFI_PHYSICAL_ADDRESS SdIpAddr
+)
+{
+ UINT32 Mask, Data;
+
+ /* Hpipe Generation 1 settings 1 */
+ Mask = HPIPE_GX_SET1_RX_SELMUPI_MASK |
+ HPIPE_GX_SET1_RX_SELMUPP_MASK |
+ HPIPE_GX_SET1_RX_SELMUFI_MASK |
+ HPIPE_GX_SET1_RX_SELMUFF_MASK |
+ HPIPE_GX_SET1_RX_DIGCK_DIV_MASK;
+ Data = (0x1 << HPIPE_GX_SET1_RX_SELMUPP_OFFSET) |
+ (0x3 << HPIPE_GX_SET1_RX_SELMUFF_OFFSET) |
+ (0x1 << HPIPE_GX_SET1_RX_DIGCK_DIV_OFFSET);
+ MmioAndThenOr32 (HpipeAddr + HPIPE_G1_SET1_REG, ~Mask, Data);
+
+ /* Hpipe Generation 1 settings 3 */
+ Mask = HPIPE_GX_SET3_FFE_CAP_SEL_MASK |
+ HPIPE_GX_SET3_FFE_RES_SEL_MASK |
+ HPIPE_GX_SET3_FFE_SETTING_FORCE_MASK |
+ HPIPE_GX_SET3_FFE_DEG_RES_LEVEL_MASK |
+ HPIPE_GX_SET3_FFE_LOAD_RES_LEVEL_MASK;
+ Data = 0xf |
+ (0x2 << HPIPE_GX_SET3_FFE_RES_SEL_OFFSET) |
+ (0x1 << HPIPE_GX_SET3_FFE_SETTING_FORCE_OFFSET) |
+ (0x1 << HPIPE_GX_SET3_FFE_DEG_RES_LEVEL_OFFSET) |
+ (0x1 << HPIPE_GX_SET3_FFE_LOAD_RES_LEVEL_OFFSET);
+ MmioAndThenOr32 (HpipeAddr + HPIPE_G1_SET3_REG, ~Mask, Data);
+
+ /* Hpipe Generation 2 settings 1 */
+ Mask = HPIPE_GX_SET1_RX_SELMUPI_MASK |
+ HPIPE_GX_SET1_RX_SELMUPP_MASK |
+ HPIPE_GX_SET1_RX_SELMUFI_MASK |
+ HPIPE_GX_SET1_RX_SELMUFF_MASK |
+ HPIPE_GX_SET1_RX_DIGCK_DIV_MASK;
+ Data = (0x1 << HPIPE_GX_SET1_RX_SELMUPP_OFFSET) |
+ (0x3 << HPIPE_GX_SET1_RX_SELMUFF_OFFSET) |
+ (0x1 << HPIPE_GX_SET1_RX_DIGCK_DIV_OFFSET);
+ MmioAndThenOr32 (HpipeAddr + HPIPE_G2_SET1_REG, ~Mask, Data);
+
+ /* Hpipe Generation 3 settings 1 */
+ Mask = HPIPE_GX_SET1_RX_SELMUPI_MASK |
+ HPIPE_GX_SET1_RX_SELMUPP_MASK |
+ HPIPE_GX_SET1_RX_SELMUFI_MASK |
+ HPIPE_GX_SET1_RX_SELMUFF_MASK |
+ HPIPE_GX_SET1_RX_DFE_EN_MASK |
+ HPIPE_GX_SET1_RX_DIGCK_DIV_MASK |
+ HPIPE_GX_SET1_SAMPLER_INPAIRX2_EN_MASK;
+ Data = 0x2 |
+ (0x2 << HPIPE_GX_SET1_RX_SELMUPP_OFFSET) |
+ (0x3 << HPIPE_GX_SET1_RX_SELMUFI_OFFSET) |
+ (0x3 << HPIPE_GX_SET1_RX_SELMUFF_OFFSET) |
+ (0x1 << HPIPE_GX_SET1_RX_DFE_EN_OFFSET) |
+ (0x2 << HPIPE_GX_SET1_RX_DIGCK_DIV_OFFSET);
+ MmioAndThenOr32 (HpipeAddr + HPIPE_G3_SET1_REG, ~Mask, Data);
+
+ /* DTL Control */
+ Mask = HPIPE_PWR_CTR_DTL_SQ_DET_EN_MASK |
+ HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_MASK |
+ HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK |
+ HPIPE_PWR_CTR_DTL_CLAMPING_SEL_MASK |
+ HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_MASK |
+ HPIPE_PWR_CTR_DTL_CLK_MODE_MASK |
+ HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_MASK;
+ Data = 0x1 |
+ (0x1 << HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_OFFSET) |
+ (0x1 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET) |
+ (0x1 << HPIPE_PWR_CTR_DTL_CLAMPING_SEL_OFFSET) |
+ (0x1 << HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_OFFSET) |
+ (0x1 << HPIPE_PWR_CTR_DTL_CLK_MODE_OFFSET) |
+ (0x1 << HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_OFFSET);
+ MmioAndThenOr32 (HpipeAddr + HPIPE_PWR_CTR_DTL_REG, ~Mask, Data);
+
+ /* Trigger sampler enable pulse (by toggling the bit) */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG,
+ ~HPIPE_SAMPLER_MASK,
+ 0x1 << HPIPE_SAMPLER_OFFSET
+ );
+ MmioAnd32 (
+ HpipeAddr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG,
+ ~HPIPE_SAMPLER_MASK
+ );
+
+ /* VDD Calibration Control 3 */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_VDD_CAL_CTRL_REG,
+ ~HPIPE_EXT_SELLV_RXSAMPL_MASK,
+ 0x10 << HPIPE_EXT_SELLV_RXSAMPL_OFFSET
+ );
+
+ /* DFE Resolution Control */
+ MmioOr32 (HpipeAddr + HPIPE_DFE_REG0, HPIPE_DFE_RES_FORCE_MASK);
+
+ /* DFE F3-F5 Coefficient Control */
+ MmioAnd32 (
+ HpipeAddr + HPIPE_DFE_F3_F5_REG,
+ ~(HPIPE_DFE_F3_F5_DFE_EN_MASK | HPIPE_DFE_F3_F5_DFE_CTRL_MASK)
+ );
+
+ /* Hpipe Generation 3 settings 3 */
+ Mask = HPIPE_GX_SET3_FFE_CAP_SEL_MASK |
+ HPIPE_GX_SET3_FFE_RES_SEL_MASK |
+ HPIPE_GX_SET3_FFE_SETTING_FORCE_MASK |
+ HPIPE_GX_SET3_FFE_DEG_RES_LEVEL_MASK |
+ HPIPE_GX_SET3_FFE_LOAD_RES_LEVEL_MASK;
+ Data = 0xf |
+ (0x4 << HPIPE_GX_SET3_FFE_RES_SEL_OFFSET) |
+ (0x1 << HPIPE_GX_SET3_FFE_SETTING_FORCE_OFFSET) |
+ (0x1 << HPIPE_GX_SET3_FFE_DEG_RES_LEVEL_OFFSET) |
+ (0x3 << HPIPE_GX_SET3_FFE_LOAD_RES_LEVEL_OFFSET);
+ MmioAndThenOr32 (HpipeAddr + HPIPE_G3_SET3_REG, ~Mask, Data);
+
+ /* Hpipe Generation 3 settings 4 */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_G3_SET4_REG,
+ ~HPIPE_GX_SET4_DFE_RES_MASK,
+ 0x2 << HPIPE_GX_SET4_DFE_RES_OFFSET
+ );
+
+ /* Offset Phase Control - force offset and toggle 'valid' bit */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_PHASE_CONTROL_REG,
+ ~(HPIPE_OS_PH_OFFSET_MASK | HPIPE_OS_PH_OFFSET_FORCE_MASK),
+ 0x5c | (0x1 << HPIPE_OS_PH_OFFSET_FORCE_OFFSET)
+ );
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_PHASE_CONTROL_REG,
+ ~HPIPE_OS_PH_VALID_MASK,
+ 0x1 << HPIPE_OS_PH_VALID_OFFSET
+ );
+ MmioAnd32 (
+ HpipeAddr + HPIPE_PHASE_CONTROL_REG,
+ ~HPIPE_OS_PH_VALID_MASK
+ );
+
+ /* Set G1 TX amplitude and TX post emphasis value */
+ Mask = HPIPE_GX_SET0_TX_AMP_MASK |
+ HPIPE_GX_SET0_TX_AMP_ADJ_MASK |
+ HPIPE_GX_SET0_TX_EMPH1_MASK |
+ HPIPE_GX_SET0_TX_EMPH1_EN_MASK;
+ Data = (0x8 << HPIPE_GX_SET0_TX_AMP_OFFSET) |
+ (0x1 << HPIPE_GX_SET0_TX_AMP_ADJ_OFFSET) |
+ (0x1 << HPIPE_GX_SET0_TX_EMPH1_OFFSET) |
+ (0x1 << HPIPE_GX_SET0_TX_EMPH1_EN_OFFSET);
+ MmioAndThenOr32 (HpipeAddr + HPIPE_G1_SET0_REG, ~Mask, Data);
+
+ /* Set G2 TX amplitude and TX post emphasis value */
+ Mask = HPIPE_GX_SET0_TX_AMP_MASK |
+ HPIPE_GX_SET0_TX_AMP_ADJ_MASK |
+ HPIPE_GX_SET0_TX_EMPH1_MASK |
+ HPIPE_GX_SET0_TX_EMPH1_EN_MASK;
+ Data = (0xa << HPIPE_GX_SET0_TX_AMP_OFFSET) |
+ (0x1 << HPIPE_GX_SET0_TX_AMP_ADJ_OFFSET) |
+ (0x2 << HPIPE_GX_SET0_TX_EMPH1_OFFSET) |
+ (0x1 << HPIPE_GX_SET0_TX_EMPH1_EN_OFFSET);
+ MmioAndThenOr32 (HpipeAddr + HPIPE_G2_SET0_REG, ~Mask, Data);
+
+ /* Set G3 TX amplitude and TX post emphasis value */
+ Mask = HPIPE_GX_SET0_TX_AMP_MASK |
+ HPIPE_GX_SET0_TX_AMP_ADJ_MASK |
+ HPIPE_GX_SET0_TX_EMPH1_MASK |
+ HPIPE_GX_SET0_TX_EMPH1_EN_MASK |
+ HPIPE_GX_SET0_TX_SLEW_RATE_SEL_MASK |
+ HPIPE_GX_SET0_TX_SLEW_CTRL_EN_MASK;
+ Data = (0xe << HPIPE_GX_SET0_TX_AMP_OFFSET) |
+ (0x1 << HPIPE_GX_SET0_TX_AMP_ADJ_OFFSET) |
+ (0x6 << HPIPE_GX_SET0_TX_EMPH1_OFFSET) |
+ (0x1 << HPIPE_GX_SET0_TX_EMPH1_EN_OFFSET) |
+ (0x4 << HPIPE_GX_SET0_TX_SLEW_RATE_SEL_OFFSET);
+ MmioAndThenOr32 (HpipeAddr + HPIPE_G3_SET0_REG, ~Mask, Data);
+
+ /* SERDES External Configuration 2 register - enable spread spectrum clock */
+ MmioOr32 (SdIpAddr + SD_EXTERNAL_CONFIG2_REG, SD_EXTERNAL_CONFIG2_SSC_ENABLE_MASK);
+
+ /* DFE reset sequence */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_PWR_CTR_REG,
+ ~HPIPE_PWR_CTR_RST_DFE_MASK,
+ 0x1
+ );
+ MmioAnd32 (
+ HpipeAddr + HPIPE_PWR_CTR_REG,
+ ~HPIPE_PWR_CTR_RST_DFE_MASK
+ );
+
+ /* SW reset for interupt logic */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_PWR_CTR_REG,
+ ~HPIPE_PWR_CTR_SFT_RST_MASK,
+ 0x1 << HPIPE_PWR_CTR_SFT_RST_OFFSET
+ );
+ MmioAnd32 (
+ HpipeAddr + HPIPE_PWR_CTR_REG,
+ ~HPIPE_PWR_CTR_SFT_RST_MASK
+ );
+}
+
+STATIC
+VOID
+ComPhySataPhyPowerUp (
+ IN EFI_PHYSICAL_ADDRESS SataBase
+)
+{
+ UINT32 Data, Mask;
+
+ /*
+ * MAC configuration - power up ComPhy - power up PLL/TX/RX
+ * Use indirect address for vendor specific SATA control register
+ */
+ RegSet (SataBase + SATA3_VENDOR_ADDRESS,
+ SATA_CONTROL_REG << SATA3_VENDOR_ADDR_OFSSET, SATA3_VENDOR_ADDR_MASK);
+
+ /* SATA 0 power up */
+ Mask = SATA3_CTRL_SATA0_PD_MASK;
+ Data = 0x0 << SATA3_CTRL_SATA0_PD_OFFSET;
+
+ /* SATA 1 power up */
+ Mask |= SATA3_CTRL_SATA1_PD_MASK;
+ Data |= 0x0 << SATA3_CTRL_SATA1_PD_OFFSET;
+
+ /* SATA SSU enable */
+ Mask |= SATA3_CTRL_SATA1_ENABLE_MASK;
+ Data |= 0x1 << SATA3_CTRL_SATA1_ENABLE_OFFSET;
+
+ /* SATA port 1 enable */
+ Mask |= SATA3_CTRL_SATA_SSU_MASK;
+ Data |= 0x1 << SATA3_CTRL_SATA_SSU_OFFSET;
+ RegSet (SataBase + SATA3_VENDOR_DATA, Data, Mask);
+
+ /* MBUS request size and interface select register */
+ RegSet (SataBase + SATA3_VENDOR_ADDRESS,
+ SATA_MBUS_SIZE_SELECT_REG << SATA3_VENDOR_ADDR_OFSSET,
+ SATA3_VENDOR_ADDR_MASK);
+
+ /* Mbus regret enable */
+ RegSet (SataBase + SATA3_VENDOR_DATA, 0x1 << SATA_MBUS_REGRET_EN_OFFSET,
+ SATA_MBUS_REGRET_EN_MASK);
+}
+
+STATIC
+EFI_STATUS
+ComPhySataCheckPll (
+ IN EFI_PHYSICAL_ADDRESS HpipeAddr,
+ IN EFI_PHYSICAL_ADDRESS SdIpAddr
+)
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ UINT32 Data,Mask;
+ IN EFI_PHYSICAL_ADDRESS Addr;
+
+ Addr = SdIpAddr + SD_EXTERNAL_STATUS0_REG;
+ Data = SD_EXTERNAL_STATUS0_PLL_TX_MASK & SD_EXTERNAL_STATUS0_PLL_RX_MASK;
+ Mask = Data;
+ Data = PollingWithTimeout (Addr, Data, Mask, 15000);
+
+ if (Data != 0) {
+ DEBUG((DEBUG_INFO, "ComPhy: Read from reg = %p - value = 0x%x\n",
+ HpipeAddr + HPIPE_LANE_STATUS0_REG, Data));
+ DEBUG((DEBUG_ERROR, "ComPhy: SD_EXTERNAL_STATUS0_PLL_TX is %d, SD_EXTERNAL_STATUS0_PLL_RX is %d\n",
+ (Data & SD_EXTERNAL_STATUS0_PLL_TX_MASK),
+ (Data & SD_EXTERNAL_STATUS0_PLL_RX_MASK)));
+ Status = EFI_D_ERROR;
+ }
+
+ return Status;
+}
+
+STATIC
+UINTN
+ComPhySataPowerUp (
+ IN UINT32 Lane,
+ IN EFI_PHYSICAL_ADDRESS HpipeBase,
+ IN EFI_PHYSICAL_ADDRESS ComPhyBase,
+ IN UINT8 SataHostId
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *SataDeviceTable;
+ MVHW_NONDISCOVERABLE_DESC *Desc = &mA7k8kNonDiscoverableDescTemplate;
+ EFI_PHYSICAL_ADDRESS HpipeAddr = HPIPE_ADDR(HpipeBase, Lane);
+ EFI_PHYSICAL_ADDRESS SdIpAddr = SD_ADDR(HpipeBase, Lane);
+ EFI_PHYSICAL_ADDRESS ComPhyAddr = COMPHY_ADDR(ComPhyBase, Lane);
+
+ SataDeviceTable = (UINT8 *) PcdGetPtr (PcdPciEAhci);
+
+ if (SataDeviceTable == NULL || SataHostId >= PcdGetSize (PcdPciEAhci)) {
+ DEBUG ((DEBUG_ERROR, "ComPhySata: Sata host %d is undefined\n", SataHostId));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!MVHW_DEV_ENABLED (Sata, SataHostId)) {
+ DEBUG ((DEBUG_ERROR, "ComPhySata: Sata host %d is disabled\n", SataHostId));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUG ((DEBUG_INFO, "ComPhySata: Initialize SATA PHYs\n"));
+
+ DEBUG((DEBUG_INFO, "ComPhySataPowerUp: stage: MAC configuration - power down ComPhy\n"));
+
+ ComPhySataMacPowerDown (Desc->AhciBaseAddresses[SataHostId]);
+
+ DEBUG((DEBUG_INFO, "ComPhy: stage: RFU configurations - hard reset ComPhy\n"));
+
+ ComPhySataRFUConfiguration (ComPhyAddr, SdIpAddr);
+
+ DEBUG((DEBUG_INFO, "ComPhy: stage: Comphy configuration\n"));
+
+ ComPhySataPhyConfiguration (HpipeAddr);
+
+ DEBUG((DEBUG_INFO, "ComPhy: stage: Analog paramters from ETP(HW)\n"));
+
+ ComPhySataSetAnalogParameters (HpipeAddr, SdIpAddr);
+
+ DEBUG((DEBUG_INFO, "ComPhy: stage: ComPhy power up\n"));
+
+ ComPhySataPhyPowerUp (Desc->AhciBaseAddresses[SataHostId]);
+
+ DEBUG((DEBUG_INFO, "ComPhy: stage: Check PLL\n"));
+
+ Status = ComPhySataCheckPll (HpipeAddr, SdIpAddr);
+
+ return Status;
+}
+
+STATIC
+VOID
+ComPhySgmiiRFUConfiguration (
+ IN EFI_PHYSICAL_ADDRESS ComPhyAddr,
+ IN EFI_PHYSICAL_ADDRESS SdIpAddr,
+ IN UINT32 SgmiiSpeed
+)
+{
+ UINT32 Mask, Data;
+
+ Mask = COMMON_PHY_CFG1_PWR_UP_MASK;
+ Data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET;
+ Mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK;
+ Data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET;
+ RegSet (ComPhyAddr + COMMON_PHY_CFG1_REG, Data, Mask);
+
+ /* Select Baud Rate of Comphy And PD_PLL/Tx/Rx */
+ Mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK;
+ Data = 0x0 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET;
+ Mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK;
+ Mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK;
+ if (SgmiiSpeed == COMPHY_SPEED_1_25G) {
+ Data |= 0x6 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET;
+ Data |= 0x6 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET;
+ } else {
+ /* 3.125G */
+ Data |= 0x8 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET;
+ Data |= 0x8 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET;
+ }
+ Mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK;
+ Data |= 0 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET;
+ Mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK;
+ Data |= 0 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET;
+ Mask |= SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK;
+ Data |= 1 << SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET;
+ RegSet (SdIpAddr + SD_EXTERNAL_CONFIG0_REG, Data, Mask);
+
+ /* Release from hard reset */
+ Mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
+ Data = 0x0 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
+ Mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
+ Data |= 0x0 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
+ Mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
+ Data |= 0x0 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
+ RegSet (SdIpAddr + SD_EXTERNAL_CONFIG1_REG, Data, Mask);
+
+ /* Release from hard reset */
+ Mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
+ Data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
+ Mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
+ Data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
+ RegSet (SdIpAddr+ SD_EXTERNAL_CONFIG1_REG, Data, Mask);
+
+ /* Wait 1ms - until band gap and ref clock ready */
+ MicroSecondDelay (1000);
+ MemoryFence ();
+}
+
+STATIC
+VOID
+ComPhySgmiiPhyConfiguration (
+ IN EFI_PHYSICAL_ADDRESS HpipeAddr
+)
+{
+ UINT32 Mask, Data;
+
+ /* Set reference clock */
+ Mask = HPIPE_MISC_REFCLK_SEL_MASK;
+ Data = 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET;
+ RegSet (HpipeAddr + HPIPE_MISC_REG, Data, Mask);
+
+ /* Power and PLL Control */
+ Mask = HPIPE_PWR_PLL_REF_FREQ_MASK;
+ Data = 0x1 << HPIPE_PWR_PLL_REF_FREQ_OFFSET;
+ Mask |= HPIPE_PWR_PLL_PHY_MODE_MASK;
+ Data |= 0x4 << HPIPE_PWR_PLL_PHY_MODE_OFFSET;
+ RegSet (HpipeAddr + HPIPE_PWR_PLL_REG, Data, Mask);
+
+ /* Loopback register */
+ Mask = HPIPE_LOOPBACK_SEL_MASK;
+ Data = 0x1 << HPIPE_LOOPBACK_SEL_OFFSET;
+ RegSet (HpipeAddr + HPIPE_LOOPBACK_REG, Data, Mask);
+
+ /* Rx control 1 */
+ Mask = HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK;
+ Data = 0x1 << HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET;
+ Mask |= HPIPE_RX_CONTROL_1_CLK8T_EN_MASK;
+ Data |= 0x0 << HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET;
+ RegSet (HpipeAddr + HPIPE_RX_CONTROL_1_REG, Data, Mask);
+
+ /* DTL Control */
+ Mask = HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK;
+ Data = 0x0 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET;
+ RegSet (HpipeAddr + HPIPE_PWR_CTR_DTL_REG, Data, Mask);
+}
+
+STATIC
+EFI_STATUS
+ComPhyEthCommonRFUPowerUp (
+ IN EFI_PHYSICAL_ADDRESS SdIpAddr
+)
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ UINT32 Mask, Data;
+ EFI_PHYSICAL_ADDRESS Addr;
+
+ /* SerDes External Configuration */
+ Mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK;
+ Data = 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET;
+ Mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK;
+ Data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET;
+ Mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK;
+ Data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET;
+ RegSet (SdIpAddr + SD_EXTERNAL_CONFIG0_REG, Data, Mask);
+
+ /* Check PLL rx & tx ready */
+ Addr = SdIpAddr + SD_EXTERNAL_STATUS0_REG;
+ Data = SD_EXTERNAL_STATUS0_PLL_RX_MASK | SD_EXTERNAL_STATUS0_PLL_TX_MASK;
+ Mask = Data;
+ Data = PollingWithTimeout (Addr, Data, Mask, 15000);
+ if (Data != 0) {
+ DEBUG((DEBUG_ERROR, "ComPhy: Read from reg = %p - value = 0x%x\n",
+ SdIpAddr + SD_EXTERNAL_STATUS0_REG, Data));
+ DEBUG((DEBUG_ERROR, "ComPhy: SD_EXTERNAL_STATUS0_PLL_RX is %d, SD_EXTERNAL_STATUS0_PLL_TX is %d\n",
+ (Data & SD_EXTERNAL_STATUS0_PLL_RX_MASK),
+ (Data & SD_EXTERNAL_STATUS0_PLL_TX_MASK)));
+ Status = EFI_D_ERROR;
+ }
+
+ /* RX init */
+ Mask = SD_EXTERNAL_CONFIG1_RX_INIT_MASK;
+ Data = 0x1 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET;
+ RegSet (SdIpAddr + SD_EXTERNAL_CONFIG1_REG, Data, Mask);
+
+ /* Check that RX init done */
+ Addr = SdIpAddr + SD_EXTERNAL_STATUS0_REG;
+ Data = SD_EXTERNAL_STATUS0_RX_INIT_MASK;
+ Mask = Data;
+ Data = PollingWithTimeout (Addr, Data, Mask, 100);
+ if (Data != 0) {
+ DEBUG((DEBUG_ERROR, "ComPhy: Read from reg = %p - value = 0x%x\n",
+ SdIpAddr + SD_EXTERNAL_STATUS0_REG, Data));
+ DEBUG((DEBUG_ERROR, "ComPhy: SD_EXTERNAL_STATUS0_RX_INIT is 0\n"));
+ Status = EFI_D_ERROR;
+ }
+ Mask = SD_EXTERNAL_CONFIG1_RX_INIT_MASK;
+ Data = 0x0 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET;
+ Mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
+ Data |= 0x1 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
+ RegSet (SdIpAddr + SD_EXTERNAL_CONFIG1_REG, Data, Mask);
+
+ return Status;
+}
+
+STATIC
+UINTN
+ComPhySgmiiPowerUp (
+ IN UINT32 Lane,
+ IN UINT32 SgmiiSpeed,
+ IN EFI_PHYSICAL_ADDRESS HpipeBase,
+ IN EFI_PHYSICAL_ADDRESS ComPhyBase
+ )
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ EFI_PHYSICAL_ADDRESS HpipeAddr = HPIPE_ADDR(HpipeBase, Lane);
+ EFI_PHYSICAL_ADDRESS SdIpAddr = SD_ADDR(HpipeBase, Lane);
+ EFI_PHYSICAL_ADDRESS ComPhyAddr = COMPHY_ADDR(ComPhyBase, Lane);
+
+ DEBUG((DEBUG_INFO, "ComPhy: stage: RFU configurations - hard reset ComPhy\n"));
+
+ ComPhySgmiiRFUConfiguration (ComPhyAddr, SdIpAddr, SgmiiSpeed);
+
+ DEBUG((DEBUG_INFO, "ComPhy: stage: ComPhy configuration\n"));
+
+ ComPhySgmiiPhyConfiguration (HpipeAddr);
+
+ /* Set analog paramters from ETP(HW) - for now use the default data */
+ DEBUG((DEBUG_INFO, "ComPhy: stage: Analog paramters from ETP(HW)\n"));
+
+ RegSet (HpipeAddr + HPIPE_G1_SET0_REG,
+ 0x1 << HPIPE_GX_SET0_TX_EMPH1_OFFSET, HPIPE_GX_SET0_TX_EMPH1_MASK);
+
+ DEBUG((DEBUG_INFO, "ComPhy: stage: RFU configurations - Power Up PLL,Tx,Rx\n"));
+
+ Status = ComPhyEthCommonRFUPowerUp (SdIpAddr);
+
+ return Status;
+}
+
+STATIC
+VOID
+ComPhySfiRFUConfiguration (
+ IN EFI_PHYSICAL_ADDRESS ComPhyAddr,
+ IN EFI_PHYSICAL_ADDRESS SdIpAddr
+)
+{
+ UINT32 Mask, Data;
+
+ MmioAndThenOr32 (
+ ComPhyAddr + COMMON_PHY_CFG1_REG,
+ ~(COMMON_PHY_CFG1_PWR_UP_MASK | COMMON_PHY_CFG1_PIPE_SELECT_MASK),
+ COMMON_PHY_CFG1_PWR_UP_MASK
+ );
+
+ /* Select Baud Rate of Comphy And PD_PLL/Tx/Rx */
+ Mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK |
+ SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK |
+ SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK |
+ SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK |
+ SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK |
+ SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK;
+ Data = (0xe << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET) |
+ (0xe << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET);
+ MmioAndThenOr32 (SdIpAddr + SD_EXTERNAL_CONFIG0_REG, ~Mask, Data);
+
+ /* Release from hard reset */
+ Mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK |
+ SD_EXTERNAL_CONFIG1_RESET_CORE_MASK |
+ SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
+ Data = SD_EXTERNAL_CONFIG1_RESET_IN_MASK |
+ SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
+ MmioAndThenOr32 (SdIpAddr + SD_EXTERNAL_CONFIG1_REG, ~Mask, Data);
+
+ /* Wait 1ms - until band gap and ref clock are ready */
+ MicroSecondDelay (1000);
+ MemoryFence ();
+}
+
+STATIC
+VOID
+ComPhySfiPhyConfiguration (
+ IN EFI_PHYSICAL_ADDRESS HpipeAddr,
+ IN UINT32 SfiSpeed
+)
+{
+ UINT32 Mask, Data;
+
+ /* Set reference clock */
+ Mask = HPIPE_MISC_ICP_FORCE_MASK | HPIPE_MISC_REFCLK_SEL_MASK;
+ Data = (SfiSpeed == COMPHY_SPEED_5_15625G) ?
+ (0x0 << HPIPE_MISC_ICP_FORCE_OFFSET) : (0x1 << HPIPE_MISC_ICP_FORCE_OFFSET);
+ MmioAndThenOr32 (HpipeAddr + HPIPE_MISC_REG, ~Mask, Data);
+
+ /* Power and PLL Control */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_PWR_PLL_REG,
+ ~(HPIPE_PWR_PLL_REF_FREQ_MASK | HPIPE_PWR_PLL_PHY_MODE_MASK),
+ 0x1 | (0x4 << HPIPE_PWR_PLL_PHY_MODE_OFFSET)
+ );
+
+ /* Loopback register */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_LOOPBACK_REG,
+ ~HPIPE_LOOPBACK_SEL_MASK,
+ 0x1 << HPIPE_LOOPBACK_SEL_OFFSET
+ );
+
+ /* Rx control 1 */
+ MmioOr32 (
+ HpipeAddr + HPIPE_RX_CONTROL_1_REG,
+ HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK | HPIPE_RX_CONTROL_1_CLK8T_EN_MASK
+ );
+
+ /* DTL Control */
+ MmioOr32 (HpipeAddr + HPIPE_PWR_CTR_DTL_REG, HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK);
+
+ /* Transmitter/Receiver Speed Divider Force */
+ if (SfiSpeed == COMPHY_SPEED_5_15625G) {
+ Mask = HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_MASK |
+ HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_MASK |
+ HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_MASK |
+ HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_MASK;
+ Data = (1 << HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_OFFSET) |
+ (1 << HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_OFFSET) |
+ (1 << HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_OFFSET) |
+ (1 << HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_OFFSET);
+ MmioAndThenOr32 (HpipeAddr + HPIPE_SPD_DIV_FORCE_REG, ~Mask, Data);
+ } else {
+ MmioOr32 (HpipeAddr + HPIPE_SPD_DIV_FORCE_REG, HPIPE_TXDIGCK_DIV_FORCE_MASK);
+ }
+}
+
+STATIC
+VOID
+ComPhySfiSetAnalogParameters (
+ IN EFI_PHYSICAL_ADDRESS HpipeAddr,
+ IN EFI_PHYSICAL_ADDRESS SdIpAddr,
+ IN UINT32 SfiSpeed
+)
+{
+ UINT32 Mask, Data;
+
+ /* SERDES External Configuration 2 */
+ MmioOr32 (SdIpAddr + SD_EXTERNAL_CONFIG2_REG, SD_EXTERNAL_CONFIG2_PIN_DFE_EN_MASK);
+
+ /* DFE Resolution control */
+ MmioOr32 (HpipeAddr + HPIPE_DFE_REG0, HPIPE_DFE_RES_FORCE_MASK);
+
+ /* Generation 1 setting_0 */
+ if (SfiSpeed == COMPHY_SPEED_5_15625G) {
+ Mask = HPIPE_GX_SET0_TX_EMPH1_MASK;
+ Data = 0x6 << HPIPE_GX_SET0_TX_EMPH1_OFFSET;
+ } else {
+ Mask = HPIPE_GX_SET0_TX_AMP_MASK | HPIPE_GX_SET0_TX_EMPH1_MASK;
+ Data = (0x1c << HPIPE_GX_SET0_TX_AMP_OFFSET) | (0xe << HPIPE_GX_SET0_TX_EMPH1_OFFSET);
+ }
+ MmioAndThenOr32 (HpipeAddr + HPIPE_G1_SET0_REG, ~Mask, Data);
+
+ /* Generation 1 setting 2 */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_GX_SET2_REG,
+ ~HPIPE_GX_SET2_TX_EMPH0_MASK,
+ HPIPE_GX_SET2_TX_EMPH0_EN_MASK
+ );
+
+ /* Transmitter Slew Rate Control register */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_TX_REG1_REG,
+ ~(HPIPE_TX_REG1_TX_EMPH_RES_MASK | HPIPE_TX_REG1_SLC_EN_MASK),
+ (0x3 << HPIPE_TX_REG1_TX_EMPH_RES_OFFSET) | (0x3f << HPIPE_TX_REG1_SLC_EN_OFFSET)
+ );
+
+ /* Impedance Calibration Control register */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_CAL_REG1_REG,
+ ~(HPIPE_CAL_REG_1_EXT_TXIMP_MASK | HPIPE_CAL_REG_1_EXT_TXIMP_EN_MASK),
+ (0xe << HPIPE_CAL_REG_1_EXT_TXIMP_OFFSET) | HPIPE_CAL_REG_1_EXT_TXIMP_EN_MASK
+ );
+
+ /* Generation 1 setting 5 */
+ MmioAnd32 (HpipeAddr + HPIPE_G1_SET5_REG, ~HPIPE_GX_SET5_ICP_MASK);
+
+ /* Generation 1 setting 1 */
+ if (SfiSpeed == COMPHY_SPEED_5_15625G) {
+ Mask = HPIPE_GX_SET1_RX_SELMUPI_MASK | HPIPE_GX_SET1_RX_SELMUPP_MASK;
+ Data = 0x1 | (0x1 << HPIPE_GX_SET1_RX_SELMUPP_OFFSET);
+ } else {
+ Mask = HPIPE_GX_SET1_RX_SELMUPI_MASK |
+ HPIPE_GX_SET1_RX_SELMUPP_MASK |
+ HPIPE_GX_SET1_RX_SELMUFI_MASK |
+ HPIPE_GX_SET1_RX_SELMUFF_MASK |
+ HPIPE_GX_SET1_RX_DIGCK_DIV_MASK;
+ Data = 0x2 |
+ (0x2 << HPIPE_GX_SET1_RX_SELMUPP_OFFSET) |
+ (0x1 << HPIPE_GX_SET1_RX_SELMUFF_OFFSET) |
+ (0x3 << HPIPE_GX_SET1_RX_DIGCK_DIV_OFFSET);
+ }
+ MmioAndThenOr32 (HpipeAddr + HPIPE_G1_SET1_REG, ~Mask, Data);
+ MmioOr32 (HpipeAddr + HPIPE_G1_SET1_REG, HPIPE_GX_SET1_RX_DFE_EN_MASK);
+
+ /* DFE F3-F5 Coefficient Control */
+ MmioAnd32 (
+ HpipeAddr + HPIPE_DFE_F3_F5_REG,
+ ~(HPIPE_DFE_F3_F5_DFE_EN_MASK | HPIPE_DFE_F3_F5_DFE_CTRL_MASK)
+ );
+
+ /* Configure Generation 1 setting 4 (DFE) */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_G1_SET4_REG,
+ ~HPIPE_GX_SET4_DFE_RES_MASK,
+ 0x1 << HPIPE_GX_SET4_DFE_RES_OFFSET
+ );
+
+ /* Generation 1 setting 3 */
+ MmioOr32 (HpipeAddr + HPIPE_G1_SET3_REG, HPIPE_GX_SET3_FBCK_SEL_MASK);
+
+ if (SfiSpeed == COMPHY_SPEED_5_15625G) {
+ /* Force FFE (Feed Forward Equalization) to 5G */
+ Mask = HPIPE_GX_SET3_FFE_CAP_SEL_MASK |
+ HPIPE_GX_SET3_FFE_RES_SEL_MASK |
+ HPIPE_GX_SET3_FFE_SETTING_FORCE_MASK;
+ Data = 0xf | (0x4 << HPIPE_GX_SET3_FFE_RES_SEL_OFFSET) | HPIPE_GX_SET3_FFE_SETTING_FORCE_MASK;
+ MmioAndThenOr32 (HpipeAddr + HPIPE_G1_SET3_REG, ~Mask, Data);
+ }
+
+ /* Configure RX training timer */
+ MmioAndThenOr32 (HpipeAddr + HPIPE_TX_TRAIN_CTRL_5_REG, ~HPIPE_RX_TRAIN_TIMER_MASK, 0x13);
+
+ /* Enable TX train peak to peak hold */
+ MmioOr32 (HpipeAddr + HPIPE_TX_TRAIN_CTRL_0_REG, HPIPE_TX_TRAIN_P2P_HOLD_MASK);
+
+ /* Configure TX preset index */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_TX_PRESET_INDEX_REG,
+ ~HPIPE_TX_PRESET_INDEX_MASK,
+ 0x2 << HPIPE_TX_PRESET_INDEX_OFFSET
+ );
+
+ /* Disable pattern lock lost timeout */
+ MmioAnd32 (HpipeAddr + HPIPE_FRAME_DETECT_CTRL_3_REG, ~HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_MASK);
+
+ /* Configure TX training pattern and TX training 16bit auto */
+ MmioOr32 (
+ HpipeAddr + HPIPE_TX_TRAIN_REG,
+ HPIPE_TX_TRAIN_16BIT_AUTO_EN_MASK | HPIPE_TX_TRAIN_PAT_SEL_MASK
+ );
+
+ /* Configure training pattern number */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_FRAME_DETECT_CTRL_0_REG,
+ ~HPIPE_TRAIN_PAT_NUM_MASK,
+ 0x88 << HPIPE_TRAIN_PAT_NUM_OFFSET
+ );
+
+ /* Configure differential manchester encoder to ethernet mode */
+ MmioOr32 (HpipeAddr + HPIPE_DME_REG, HPIPE_DME_ETHERNET_MODE_MASK);
+
+ /* Configure VDD Continuous Calibration */
+ MmioOr32 (HpipeAddr + HPIPE_VDD_CAL_0_REG, HPIPE_CAL_VDD_CONT_MODE_MASK);
+
+ /* Configure sampler gain */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG,
+ ~HPIPE_RX_SAMPLER_OS_GAIN_MASK,
+ 0x3 << HPIPE_RX_SAMPLER_OS_GAIN_OFFSET
+ );
+
+ /* Trigger sampler enable pulse (by toggling the bit) */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG,
+ ~HPIPE_SAMPLER_MASK,
+ 0x1 << HPIPE_SAMPLER_OFFSET
+ );
+ MmioAnd32 (
+ HpipeAddr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG,
+ ~HPIPE_SAMPLER_MASK
+ );
+
+ /* VDD calibration control */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_VDD_CAL_CTRL_REG,
+ ~HPIPE_EXT_SELLV_RXSAMPL_MASK,
+ 0x1a << HPIPE_EXT_SELLV_RXSAMPL_OFFSET
+ );
+}
+
+STATIC
+EFI_STATUS
+ComPhySfiPowerUp (
+ IN UINT32 Lane,
+ IN EFI_PHYSICAL_ADDRESS HpipeBase,
+ IN EFI_PHYSICAL_ADDRESS ComPhyBase,
+ IN UINT32 SfiSpeed
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS HpipeAddr = HPIPE_ADDR(HpipeBase, Lane);
+ EFI_PHYSICAL_ADDRESS SdIpAddr = SD_ADDR(HpipeBase, Lane);
+ EFI_PHYSICAL_ADDRESS ComPhyAddr = COMPHY_ADDR(ComPhyBase, Lane);
+
+ DEBUG ((DEBUG_INFO, "ComPhy: stage: RFU configurations - hard reset ComPhy\n"));
+
+ ComPhySfiRFUConfiguration (ComPhyAddr, SdIpAddr);
+
+ DEBUG ((DEBUG_INFO, "ComPhy: stage: ComPhy configuration\n"));
+
+ ComPhySfiPhyConfiguration (HpipeAddr, SfiSpeed);
+
+ DEBUG ((DEBUG_INFO, "ComPhy: stage: Set analog paramters\n"));
+
+ ComPhySfiSetAnalogParameters (HpipeAddr, SdIpAddr, SfiSpeed);
+
+ DEBUG ((DEBUG_INFO, "ComPhy: stage: RFU configurations - Power Up PLL,Tx,Rx\n"));
+
+ Status = ComPhyEthCommonRFUPowerUp (SdIpAddr);
+
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+ComPhyRxauiRFUConfiguration (
+ IN UINT32 Lane,
+ IN EFI_PHYSICAL_ADDRESS ComPhyAddr,
+ IN EFI_PHYSICAL_ADDRESS SdIpAddr
+)
+{
+ UINT32 Mask, Data;
+
+ MmioAndThenOr32 (
+ ComPhyAddr + COMMON_PHY_CFG1_REG,
+ ~(COMMON_PHY_CFG1_PWR_UP_MASK | COMMON_PHY_CFG1_PIPE_SELECT_MASK),
+ COMMON_PHY_CFG1_PWR_UP_MASK
+ );
+
+ switch (Lane) {
+ case 2:
+ case 4:
+ MmioOr32 (ComPhyAddr + COMMON_PHY_SD_CTRL1, COMMON_PHY_SD_CTRL1_RXAUI0_MASK);
+ case 3:
+ case 5:
+ MmioOr32 (ComPhyAddr + COMMON_PHY_SD_CTRL1, COMMON_PHY_SD_CTRL1_RXAUI1_MASK);
+ break;
+ default:
+ DEBUG ((DEBUG_ERROR, "RXAUI used on invalid lane %d\n", Lane));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ /* Select Baud Rate of Comphy And PD_PLL/Tx/Rx */
+ Mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK |
+ SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK |
+ SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK |
+ SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK |
+ SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK |
+ SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK |
+ SD_EXTERNAL_CONFIG0_MEDIA_MODE_MASK;
+ Data = (0xb << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET) |
+ (0xb << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET) |
+ (0x1 << SD_EXTERNAL_CONFIG0_MEDIA_MODE_OFFSET);
+ MmioAndThenOr32 (SdIpAddr + SD_EXTERNAL_CONFIG0_REG, ~Mask, Data);
+
+ /* Release from hard reset */
+ Mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK |
+ SD_EXTERNAL_CONFIG1_RESET_CORE_MASK |
+ SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
+ Data = SD_EXTERNAL_CONFIG1_RESET_IN_MASK |
+ SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
+ MmioAndThenOr32 (SdIpAddr + SD_EXTERNAL_CONFIG1_REG, ~Mask, Data);
+
+ /* Wait 1ms - until band gap and ref clock are ready */
+ MicroSecondDelay (1000);
+ MemoryFence ();
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+VOID
+ComPhyRxauiPhyConfiguration (
+ IN EFI_PHYSICAL_ADDRESS HpipeAddr
+)
+{
+ /* Set reference clock */
+ MmioAnd32 (HpipeAddr + HPIPE_MISC_REG, ~HPIPE_MISC_REFCLK_SEL_MASK);
+
+ /* Power and PLL Control */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_PWR_PLL_REG,
+ ~(HPIPE_PWR_PLL_REF_FREQ_MASK | HPIPE_PWR_PLL_PHY_MODE_MASK),
+ 0x1 | (0x4 << HPIPE_PWR_PLL_PHY_MODE_OFFSET)
+ );
+
+ /* Loopback register */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_LOOPBACK_REG,
+ ~HPIPE_LOOPBACK_SEL_MASK,
+ 0x1 << HPIPE_LOOPBACK_SEL_OFFSET
+ );
+
+ /* Rx control 1 */
+ MmioOr32 (
+ HpipeAddr + HPIPE_RX_CONTROL_1_REG,
+ HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK | HPIPE_RX_CONTROL_1_CLK8T_EN_MASK
+ );
+
+ /* DTL Control */
+ MmioAnd32 (HpipeAddr + HPIPE_PWR_CTR_DTL_REG, ~HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK);
+}
+
+STATIC
+VOID
+ComPhyRxauiSetAnalogParameters (
+ IN EFI_PHYSICAL_ADDRESS HpipeAddr,
+ IN EFI_PHYSICAL_ADDRESS SdIpAddr
+)
+{
+ UINT32 Mask, Data;
+
+ /* SERDES External Configuration 2 */
+ MmioOr32 (SdIpAddr + SD_EXTERNAL_CONFIG2_REG, SD_EXTERNAL_CONFIG2_PIN_DFE_EN_MASK);
+
+ /* DFE Resolution control */
+ MmioOr32 (HpipeAddr + HPIPE_DFE_REG0, HPIPE_DFE_RES_FORCE_MASK);
+
+ /* Generation 1 setting_0 */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_G1_SET0_REG,
+ ~HPIPE_GX_SET0_TX_EMPH1_MASK,
+ 0xe << HPIPE_GX_SET0_TX_EMPH1_OFFSET
+ );
+
+ /* Generation 1 setting 1 */
+ Mask = HPIPE_GX_SET1_RX_SELMUPI_MASK |
+ HPIPE_GX_SET1_RX_SELMUPP_MASK |
+ HPIPE_GX_SET1_RX_DFE_EN_MASK;
+ Data = 0x1 |
+ (0x1 << HPIPE_GX_SET1_RX_SELMUPP_OFFSET) |
+ (0x1 << HPIPE_GX_SET1_RX_DFE_EN_OFFSET);
+ MmioAndThenOr32 (HpipeAddr + HPIPE_G1_SET1_REG, ~Mask, Data);
+
+ /* DFE F3-F5 Coefficient Control */
+ MmioAnd32 (
+ HpipeAddr + HPIPE_DFE_F3_F5_REG,
+ ~(HPIPE_DFE_F3_F5_DFE_EN_MASK | HPIPE_DFE_F3_F5_DFE_CTRL_MASK)
+ );
+
+ /* Configure Generation 1 setting 4 (DFE) */
+ MmioAndThenOr32 (
+ HpipeAddr + HPIPE_G1_SET4_REG,
+ ~HPIPE_GX_SET4_DFE_RES_MASK,
+ 0x1 << HPIPE_GX_SET4_DFE_RES_OFFSET
+ );
+
+ /* Generation 1 setting 3 */
+ MmioOr32 (HpipeAddr + HPIPE_G1_SET3_REG, HPIPE_GX_SET3_FBCK_SEL_MASK);
+}
+
+STATIC
+EFI_STATUS
+ComPhyRxauiPowerUp (
+ IN UINT32 Lane,
+ IN EFI_PHYSICAL_ADDRESS HpipeBase,
+ IN EFI_PHYSICAL_ADDRESS ComPhyBase
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS HpipeAddr = HPIPE_ADDR(HpipeBase, Lane);
+ EFI_PHYSICAL_ADDRESS SdIpAddr = SD_ADDR(HpipeBase, Lane);
+ EFI_PHYSICAL_ADDRESS ComPhyAddr = COMPHY_ADDR(ComPhyBase, Lane);
+
+ DEBUG ((DEBUG_INFO, "ComPhy: stage: RFU configurations - hard reset ComPhy\n"));
+
+ Status = ComPhyRxauiRFUConfiguration (Lane, ComPhyAddr, SdIpAddr);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ DEBUG ((DEBUG_INFO, "ComPhy: stage: ComPhy configuration\n"));
+
+ ComPhyRxauiPhyConfiguration (HpipeAddr);
+
+ DEBUG ((DEBUG_INFO, "ComPhy: stage: Set analog paramters\n"));
+
+ ComPhyRxauiSetAnalogParameters (HpipeAddr, SdIpAddr);
+
+ DEBUG ((DEBUG_INFO, "ComPhy: stage: RFU configurations - Power Up PLL,Tx,Rx\n"));
+
+ Status = ComPhyEthCommonRFUPowerUp (SdIpAddr);
+
+ return Status;
+}
+
+STATIC
+VOID
+ComPhyMuxCp110 (
+ IN CHIP_COMPHY_CONFIG *PtrChipCfg,
+ IN COMPHY_MAP *SerdesMap
+ )
+{
+ EFI_PHYSICAL_ADDRESS ComPhyBaseAddr;
+ COMPHY_MAP ComPhyMapPipeData[MAX_LANE_OPTIONS];
+ COMPHY_MAP ComPhyMapPhyData[MAX_LANE_OPTIONS];
+ UINT32 Lane, ComPhyMaxCount;
+
+ ComPhyMaxCount = PtrChipCfg->LanesCount;
+ ComPhyBaseAddr = PtrChipCfg->ComPhyBaseAddr;
+
+ /*
+ * Copy the SerDes map configuration for PIPE map and PHY map.
+ * The ComPhyMuxInit modifies the Type of the Lane if the Type is not valid.
+ * Because we have 2 selectors, run the ComPhyMuxInit twice and after
+ * that, update the original SerdesMap.
+ */
+ for (Lane = 0; Lane < ComPhyMaxCount; Lane++) {
+ ComPhyMapPipeData[Lane].Type = SerdesMap[Lane].Type;
+ ComPhyMapPipeData[Lane].Speed = SerdesMap[Lane].Speed;
+ ComPhyMapPhyData[Lane].Type = SerdesMap[Lane].Type;
+ ComPhyMapPhyData[Lane].Speed = SerdesMap[Lane].Speed;
+ }
+ PtrChipCfg->MuxData = Cp110ComPhyMuxData;
+ ComPhyMuxInit(PtrChipCfg, ComPhyMapPhyData, ComPhyBaseAddr +
+ COMMON_SELECTOR_PHY_OFFSET);
+
+ PtrChipCfg->MuxData = Cp110ComPhyPipeMuxData;
+ ComPhyMuxInit(PtrChipCfg, ComPhyMapPipeData, ComPhyBaseAddr +
+ COMMON_SELECTOR_PIPE_OFFSET);
+
+ /* Fix the Type after check the PHY and PIPE configuration */
+ for (Lane = 0; Lane < ComPhyMaxCount; Lane++)
+ if ((ComPhyMapPipeData[Lane].Type == COMPHY_TYPE_UNCONNECTED) &&
+ (ComPhyMapPhyData[Lane].Type == COMPHY_TYPE_UNCONNECTED))
+ SerdesMap[Lane].Type = COMPHY_TYPE_UNCONNECTED;
+}
+
+VOID
+ComPhyCp110Init (
+ IN CHIP_COMPHY_CONFIG *PtrChipCfg
+ )
+{
+ EFI_STATUS Status;
+ COMPHY_MAP *PtrComPhyMap, *SerdesMap;
+ EFI_PHYSICAL_ADDRESS ComPhyBaseAddr, HpipeBaseAddr;
+ UINT32 ComPhyMaxCount, Lane;
+ UINT32 PcieBy4 = 1; // Indicating if first 4 lanes set to PCIE
+
+ ComPhyMaxCount = PtrChipCfg->LanesCount;
+ ComPhyBaseAddr = PtrChipCfg->ComPhyBaseAddr;
+ HpipeBaseAddr = PtrChipCfg->Hpipe3BaseAddr;
+ SerdesMap = PtrChipCfg->MapData;
+
+ /* Config Comphy mux configuration */
+ ComPhyMuxCp110(PtrChipCfg, SerdesMap);
+
+ /* Check if the first 4 Lanes configured as By-4 */
+ for (Lane = 0, PtrComPhyMap = SerdesMap; Lane < 4; Lane++, PtrComPhyMap++) {
+ if (PtrComPhyMap->Type != COMPHY_TYPE_PCIE0) {
+ PcieBy4 = 0;
+ break;
+ }
+ }
+
+ for (Lane = 0, PtrComPhyMap = SerdesMap; Lane < ComPhyMaxCount;
+ Lane++, PtrComPhyMap++) {
+ DEBUG((DEBUG_INFO, "ComPhy: Initialize serdes number %d\n", Lane));
+ DEBUG((DEBUG_INFO, "ComPhy: Serdes Type = 0x%x\n", PtrComPhyMap->Type));
+ switch (PtrComPhyMap->Type) {
+ case COMPHY_TYPE_UNCONNECTED:
+ continue;
+ break;
+ case COMPHY_TYPE_PCIE0:
+ case COMPHY_TYPE_PCIE1:
+ case COMPHY_TYPE_PCIE2:
+ case COMPHY_TYPE_PCIE3:
+ Status = ComPhyPciePowerUp(Lane, PcieBy4, HpipeBaseAddr, ComPhyBaseAddr);
+ break;
+ case COMPHY_TYPE_SATA0:
+ case COMPHY_TYPE_SATA1:
+ Status = ComPhySataPowerUp (Lane, HpipeBaseAddr, ComPhyBaseAddr, MVHW_CP0_AHCI0_ID);
+ break;
+ case COMPHY_TYPE_SATA2:
+ case COMPHY_TYPE_SATA3:
+ Status = ComPhySataPowerUp (Lane, HpipeBaseAddr, ComPhyBaseAddr, MVHW_CP1_AHCI0_ID);
+ break;
+ case COMPHY_TYPE_USB3_HOST0:
+ case COMPHY_TYPE_USB3_HOST1:
+ Status = ComphyUsb3PowerUp(Lane, HpipeBaseAddr, ComPhyBaseAddr);
+ break;
+ case COMPHY_TYPE_SGMII0:
+ case COMPHY_TYPE_SGMII1:
+ case COMPHY_TYPE_SGMII2:
+ case COMPHY_TYPE_SGMII3:
+ Status = ComPhySgmiiPowerUp(Lane, PtrComPhyMap->Speed, HpipeBaseAddr,
+ ComPhyBaseAddr);
+ break;
+ case COMPHY_TYPE_SFI:
+ Status = ComPhySfiPowerUp(Lane, HpipeBaseAddr, ComPhyBaseAddr, PtrComPhyMap->Speed);
+ break;
+ case COMPHY_TYPE_RXAUI0:
+ case COMPHY_TYPE_RXAUI1:
+ Status = ComPhyRxauiPowerUp(Lane, HpipeBaseAddr, ComPhyBaseAddr);
+ break;
+ default:
+ DEBUG((DEBUG_ERROR, "Unknown SerDes Type, skip initialize SerDes %d\n",
+ Lane));
+ Status = EFI_INVALID_PARAMETER;
+ ASSERT (FALSE);
+ break;
+ }
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to initialize Lane %d\n with Status = 0x%x", Lane, Status));
+ PtrComPhyMap->Type = COMPHY_TYPE_UNCONNECTED;
+ }
+ }
+}
diff --git a/Platform/Marvell/Library/ComPhyLib/ComPhyLib.c b/Platform/Marvell/Library/ComPhyLib/ComPhyLib.c
new file mode 100644
index 0000000000..3eb5d9f6a9
--- /dev/null
+++ b/Platform/Marvell/Library/ComPhyLib/ComPhyLib.c
@@ -0,0 +1,321 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#include "ComPhyLib.h"
+#include <Library/MvComPhyLib.h>
+#include <Library/MvHwDescLib.h>
+
+DECLARE_A7K8K_COMPHY_TEMPLATE;
+
+CHAR16 * TypeStringTable [] = {L"unconnected", L"PCIE0", L"PCIE1", L"PCIE2",
+ L"PCIE3", L"SATA0", L"SATA1", L"SATA2", L"SATA3",
+ L"SGMII0", L"SGMII1", L"SGMII2", L"SGMII3",
+ L"QSGMII", L"USB3_HOST0", L"USB3_HOST1",
+ L"USB3_DEVICE", L"XAUI0", L"XAUI1", L"XAUI2",
+ L"XAUI3", L"RXAUI0", L"RXAUI1", L"SFI"};
+
+CHAR16 * SpeedStringTable [] = {L"-", L"1.25 Gbps", L"1.5 Gbps", L"2.5 Gbps",
+ L"3.0 Gbps", L"3.125 Gbps", L"5 Gbps", L"5.156 Gbps",
+ L"6 Gbps", L"6.25 Gbps", L"10.31 Gbps"};
+
+CHIP_COMPHY_CONFIG ChipCfgTbl[] = {
+ {
+ .ChipType = MvComPhyTypeCp110,
+ .Init = ComPhyCp110Init
+ },
+};
+
+VOID
+RegSet (
+ IN EFI_PHYSICAL_ADDRESS Addr,
+ IN UINT32 Data,
+ IN UINT32 Mask
+ )
+{
+ DEBUG((DEBUG_INFO, "Write to address = %10x, data = %10x (mask = %10x)"
+ "- ", Addr, Data, Mask));
+ DEBUG((DEBUG_INFO, "old value = %10x ==> ", MmioRead32 (Addr)));
+ RegSetSilent (Addr, Data, Mask);
+ DEBUG((DEBUG_INFO, "new value %10x\n", MmioRead32 (Addr)));
+}
+
+VOID
+RegSetSilent (
+ IN EFI_PHYSICAL_ADDRESS Addr,
+ IN UINT32 Data,
+ IN UINT32 Mask
+ )
+{
+ UINT32 RegData;
+
+ RegData = MmioRead32 (Addr);
+ RegData &= ~Mask;
+ RegData |= Data;
+ MmioWrite32 (Addr, RegData);
+}
+
+VOID
+RegSet16 (
+ IN EFI_PHYSICAL_ADDRESS Addr,
+ IN UINT16 Data,
+ IN UINT16 Mask
+ )
+{
+ DEBUG((DEBUG_INFO, "Write to address = %#010lx, Data = %#06x (mask = %#06x)"
+ "- ", Addr, Data, Mask));
+ DEBUG((DEBUG_INFO, "old value = %#06x ==> ", MmioRead16 (Addr)));
+ RegSetSilent16 (Addr, Data, Mask);
+ DEBUG((DEBUG_INFO, "new value %#06x\n", MmioRead16 (Addr)));
+}
+
+VOID
+RegSetSilent16(
+ IN EFI_PHYSICAL_ADDRESS Addr,
+ IN UINT16 Data,
+ IN UINT16 Mask
+ )
+{
+ UINT16 RegData;
+ RegData = MmioRead16(Addr);
+ RegData &= ~Mask;
+ RegData |= Data;
+ MmioWrite16 (Addr, RegData);
+}
+
+/* This function returns enum with SerDesType */
+UINT32
+ParseSerdesTypeString (
+ CHAR16* String
+ )
+{
+ UINT32 i;
+
+ if (String == NULL)
+ return COMPHY_TYPE_INVALID;
+
+ for (i = 0; i < COMPHY_TYPE_MAX; i++) {
+ if (StrCmp (String, TypeStringTable[i]) == 0) {
+ return i;
+ }
+ }
+
+ /* PCD string doesn't match any supported SerDes Type */
+ return COMPHY_TYPE_INVALID;
+}
+
+/* This function converts SerDes speed in MHz to enum with SerDesSpeed */
+UINT32
+ParseSerdesSpeed (
+ UINT32 Value
+ )
+{
+ UINT32 i;
+ UINT32 ValueTable [] = {0, 1250, 1500, 2500, 3000, 3125,
+ 5000, 5156, 6000, 6250, 10310};
+
+ for (i = 0; i < COMPHY_SPEED_MAX; i++) {
+ if (Value == ValueTable[i]) {
+ return i;
+ }
+ }
+
+ /* PCD SerDes speed value doesn't match any supported SerDes speed */
+ return COMPHY_SPEED_INVALID;
+}
+
+CHAR16 *
+GetTypeString (
+ UINT32 Type
+ )
+{
+
+ if (Type < 0 || Type > COMPHY_TYPE_MAX) {
+ return L"invalid";
+ }
+
+ return TypeStringTable[Type];
+}
+
+CHAR16 *
+GetSpeedString (
+ UINT32 Speed
+ )
+{
+
+ if (Speed < 0 || Speed > 10) {
+ return L"invalid";
+ }
+
+ return SpeedStringTable[Speed];
+}
+
+VOID
+ComPhyPrint (
+ IN CHIP_COMPHY_CONFIG *PtrChipCfg
+ )
+{
+ UINT32 Lane;
+ CHAR16 *SpeedStr, *TypeStr;
+
+ for (Lane = 0; Lane < PtrChipCfg->LanesCount; Lane++) {
+ SpeedStr = GetSpeedString(PtrChipCfg->MapData[Lane].Speed);
+ TypeStr = GetTypeString(PtrChipCfg->MapData[Lane].Type);
+ DEBUG((DEBUG_ERROR, "Comphy-%d: %-13s %-10s\n", Lane, TypeStr, SpeedStr));
+ }
+
+ DEBUG((DEBUG_ERROR, "\n"));
+}
+
+EFI_STATUS
+GetChipComPhyInit (
+ IN CHIP_COMPHY_CONFIG *PtrChipCfg
+ )
+{
+ UINTN i, TblSize;
+
+
+ TblSize = sizeof(ChipCfgTbl) / sizeof(ChipCfgTbl[0]);
+
+ for (i = 0; i < TblSize ; i++) {
+ if (PtrChipCfg->ChipType == ChipCfgTbl[i].ChipType) {
+ PtrChipCfg->Init = ChipCfgTbl[i].Init;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_D_ERROR;
+}
+
+STATIC
+VOID
+InitComPhyConfig (
+ IN OUT CHIP_COMPHY_CONFIG *ChipConfig,
+ IN OUT PCD_LANE_MAP *LaneData,
+ IN UINT8 Id
+ )
+{
+ MVHW_COMPHY_DESC *Desc = &mA7k8kComPhyDescTemplate;
+
+ ChipConfig->ChipType = Desc->ComPhyChipType[Id];
+ ChipConfig->ComPhyBaseAddr = Desc->ComPhyBaseAddresses[Id];
+ ChipConfig->Hpipe3BaseAddr = Desc->ComPhyHpipe3BaseAddresses[Id];
+ ChipConfig->LanesCount = Desc->ComPhyLaneCount[Id];
+ ChipConfig->MuxBitCount = Desc->ComPhyMuxBitCount[Id];
+
+ /*
+ * Below macro contains variable name concatenation (used to form PCD's name).
+ */
+ switch (Id) {
+ case 0:
+ GetComPhyPcd (ChipConfig, LaneData, 0);
+ break;
+ case 1:
+ GetComPhyPcd (ChipConfig, LaneData, 1);
+ break;
+ case 2:
+ GetComPhyPcd (ChipConfig, LaneData, 2);
+ break;
+ case 3:
+ GetComPhyPcd (ChipConfig, LaneData, 3);
+ break;
+ }
+}
+
+EFI_STATUS
+MvComPhyInit (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ CHIP_COMPHY_CONFIG ChipConfig[MVHW_MAX_COMPHY_DEVS], *PtrChipCfg;
+ PCD_LANE_MAP LaneData[MVHW_MAX_COMPHY_DEVS];
+ UINT32 Lane, MaxComphyCount;
+ UINT8 *ComPhyDeviceTable, Index;
+
+ /* Obtain table with enabled ComPhy devices */
+ ComPhyDeviceTable = (UINT8 *)PcdGetPtr (PcdComPhyDevices);
+ if (ComPhyDeviceTable == NULL) {
+ DEBUG ((DEBUG_ERROR, "Missing PcdComPhyDevices\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (PcdGetSize (PcdComPhyDevices) > MVHW_MAX_COMPHY_DEVS) {
+ DEBUG ((DEBUG_ERROR, "Wrong PcdComPhyDevices format\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ /* Initialize enabled chips */
+ for (Index = 0; Index < PcdGetSize (PcdComPhyDevices); Index++) {
+ if (!MVHW_DEV_ENABLED (ComPhy, Index)) {
+ DEBUG ((DEBUG_ERROR, "Skip ComPhy chip %d\n", Index));
+ continue;
+ }
+
+ PtrChipCfg = &ChipConfig[Index];
+ InitComPhyConfig(PtrChipCfg, LaneData, Index);
+
+ /* Get the count of the SerDes of the specific chip */
+ MaxComphyCount = PtrChipCfg->LanesCount;
+ for (Lane = 0; Lane < MaxComphyCount; Lane++) {
+ /* Parse PCD with string indicating SerDes Type */
+ PtrChipCfg->MapData[Lane].Type =
+ ParseSerdesTypeString (LaneData[Index].TypeStr[Lane]);
+ PtrChipCfg->MapData[Lane].Speed =
+ ParseSerdesSpeed (LaneData[Index].SpeedValue[Lane]);
+ PtrChipCfg->MapData[Lane].Invert = (UINT32)LaneData[Index].InvFlag[Lane];
+
+ if ((PtrChipCfg->MapData[Lane].Speed == COMPHY_SPEED_INVALID) ||
+ (PtrChipCfg->MapData[Lane].Speed == COMPHY_SPEED_ERROR) ||
+ (PtrChipCfg->MapData[Lane].Type == COMPHY_TYPE_INVALID)) {
+ DEBUG((DEBUG_ERROR, "ComPhy: No valid phy speed or type for lane %d, "
+ "setting lane as unconnected\n", Lane + 1));
+ PtrChipCfg->MapData[Lane].Type = COMPHY_TYPE_UNCONNECTED;
+ PtrChipCfg->MapData[Lane].Speed = COMPHY_SPEED_INVALID;
+ }
+ };
+
+ Status = GetChipComPhyInit (PtrChipCfg);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "ComPhy: Invalid Chip%d type\n", Index));
+ return Status;
+ }
+
+ ComPhyPrint (PtrChipCfg);
+
+ /* PHY power UP sequence */
+ PtrChipCfg->Init (PtrChipCfg);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Marvell/Library/ComPhyLib/ComPhyLib.h b/Platform/Marvell/Library/ComPhyLib/ComPhyLib.h
new file mode 100644
index 0000000000..38989780ab
--- /dev/null
+++ b/Platform/Marvell/Library/ComPhyLib/ComPhyLib.h
@@ -0,0 +1,643 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#ifndef __COMPHY_H__
+#define __COMPHY_H__
+
+#include <Library/ArmLib.h>
+#include <Library/ArmPlatformLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/MvComPhyLib.h>
+#include <Library/IoLib.h>
+#include <Library/TimerLib.h>
+#include <Library/ParsePcdLib.h>
+
+#define MAX_LANE_OPTIONS 10
+
+/***** Parsing PCD *****/
+#define GET_LANE_TYPE(id) PcdGetPtr(PcdChip##id##ComPhyTypes)
+#define GET_LANE_SPEED(id) PcdGetPtr(PcdChip##id##ComPhySpeeds)
+#define GET_LANE_INV(id) PcdGetPtr(PcdChip##id##ComPhyInvFlags)
+
+#define FillLaneMap(chip_struct, lane_struct, id) { \
+ ParsePcdString((CHAR16 *) GET_LANE_TYPE(id), chip_struct[id].LanesCount, NULL, lane_struct[id].TypeStr); \
+ ParsePcdString((CHAR16 *) GET_LANE_SPEED(id), chip_struct[id].LanesCount, lane_struct[id].SpeedValue, NULL); \
+ ParsePcdString((CHAR16 *) GET_LANE_INV(id), chip_struct[id].LanesCount, lane_struct[id].InvFlag, NULL); \
+}
+
+#define GetComPhyPcd(chip_struct, lane_struct, id) { \
+ FillLaneMap(chip_struct, lane_struct, id); \
+}
+
+/***** ComPhy *****/
+#define COMPHY_SPEED_ERROR 0
+#define COMPHY_SPEED_1_25G 1
+#define COMPHY_SPEED_1_5G 2
+#define COMPHY_SPEED_2_5G 3
+#define COMPHY_SPEED_3G 4
+#define COMPHY_SPEED_3_125G 5
+#define COMPHY_SPEED_5G 6
+#define COMPHY_SPEED_5_15625G 7
+#define COMPHY_SPEED_6G 8
+#define COMPHY_SPEED_6_25G 9
+#define COMPHY_SPEED_10_3125G 10
+#define COMPHY_SPEED_MAX 11
+#define COMPHY_SPEED_INVALID 0xff
+
+#define COMPHY_TYPE_UNCONNECTED 0
+#define COMPHY_TYPE_PCIE0 1
+#define COMPHY_TYPE_PCIE1 2
+#define COMPHY_TYPE_PCIE2 3
+#define COMPHY_TYPE_PCIE3 4
+#define COMPHY_TYPE_SATA0 5
+#define COMPHY_TYPE_SATA1 6
+#define COMPHY_TYPE_SATA2 7
+#define COMPHY_TYPE_SATA3 8
+#define COMPHY_TYPE_SGMII0 9
+#define COMPHY_TYPE_SGMII1 10
+#define COMPHY_TYPE_SGMII2 11
+#define COMPHY_TYPE_SGMII3 12
+#define COMPHY_TYPE_QSGMII 13
+#define COMPHY_TYPE_USB3_HOST0 14
+#define COMPHY_TYPE_USB3_HOST1 15
+#define COMPHY_TYPE_USB3_DEVICE 16
+#define COMPHY_TYPE_XAUI0 17
+#define COMPHY_TYPE_XAUI1 18
+#define COMPHY_TYPE_XAUI2 19
+#define COMPHY_TYPE_XAUI3 20
+#define COMPHY_TYPE_RXAUI0 21
+#define COMPHY_TYPE_RXAUI1 22
+#define COMPHY_TYPE_SFI 23
+#define COMPHY_TYPE_MAX 24
+#define COMPHY_TYPE_INVALID 0xff
+
+#define COMPHY_POLARITY_NO_INVERT 0
+#define COMPHY_POLARITY_TXD_INVERT 1
+#define COMPHY_POLARITY_RXD_INVERT 2
+#define COMPHY_POLARITY_ALL_INVERT (COMPHY_POLARITY_TXD_INVERT | COMPHY_POLARITY_RXD_INVERT)
+
+/***** SerDes IP registers *****/
+#define SD_EXTERNAL_CONFIG0_REG 0
+#define SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET 1
+#define SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK (1 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET)
+#define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET 3
+#define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK (0xf << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET)
+#define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET 7
+#define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK (0xf << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET)
+#define SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET 11
+#define SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK (1 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET)
+#define SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET 12
+#define SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK (1 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET)
+#define SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET 14
+#define SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK (1 << SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET)
+#define SD_EXTERNAL_CONFIG0_MEDIA_MODE_OFFSET 15
+#define SD_EXTERNAL_CONFIG0_MEDIA_MODE_MASK (0x1 << SD_EXTERNAL_CONFIG0_MEDIA_MODE_OFFSET)
+
+#define SD_EXTERNAL_CONFIG1_REG 0x4
+#define SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET 3
+#define SD_EXTERNAL_CONFIG1_RESET_IN_MASK (0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET)
+#define SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET 4
+#define SD_EXTERNAL_CONFIG1_RX_INIT_MASK (0x1 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET)
+#define SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET 5
+#define SD_EXTERNAL_CONFIG1_RESET_CORE_MASK (0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET)
+#define SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET 6
+#define SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK (0x1 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET)
+
+#define SD_EXTERNAL_CONFIG2_REG 0x8
+#define SD_EXTERNAL_CONFIG2_PIN_DFE_EN_OFFSET 4
+#define SD_EXTERNAL_CONFIG2_PIN_DFE_EN_MASK (0x1 << SD_EXTERNAL_CONFIG2_PIN_DFE_EN_OFFSET)
+#define SD_EXTERNAL_CONFIG2_SSC_ENABLE_OFFSET 7
+#define SD_EXTERNAL_CONFIG2_SSC_ENABLE_MASK (0x1 << SD_EXTERNAL_CONFIG2_SSC_ENABLE_OFFSET)
+
+#define SD_EXTERNAL_STATUS0_REG 0x18
+#define SD_EXTERNAL_STATUS0_PLL_TX_OFFSET 2
+#define SD_EXTERNAL_STATUS0_PLL_TX_MASK (0x1 << SD_EXTERNAL_STATUS0_PLL_TX_OFFSET)
+#define SD_EXTERNAL_STATUS0_PLL_RX_OFFSET 3
+#define SD_EXTERNAL_STATUS0_PLL_RX_MASK (0x1 << SD_EXTERNAL_STATUS0_PLL_RX_OFFSET)
+#define SD_EXTERNAL_STATUS0_RX_INIT_OFFSET 4
+#define SD_EXTERNAL_STATUS0_RX_INIT_MASK (0x1 << SD_EXTERNAL_STATUS0_RX_INIT_OFFSET)
+
+/***** HPIPE registers *****/
+#define HPIPE_PWR_PLL_REG 0x4
+#define HPIPE_PWR_PLL_REF_FREQ_OFFSET 0
+#define HPIPE_PWR_PLL_REF_FREQ_MASK (0x1f << HPIPE_PWR_PLL_REF_FREQ_OFFSET)
+#define HPIPE_PWR_PLL_PHY_MODE_OFFSET 5
+#define HPIPE_PWR_PLL_PHY_MODE_MASK (0x7 << HPIPE_PWR_PLL_PHY_MODE_OFFSET)
+
+#define HPIPE_KVCO_CALIB_CTRL_REG 0x8
+#define HPIPE_KVCO_CALIB_CTRL_MAX_PLL_OFFSET 12
+#define HPIPE_KVCO_CALIB_CTRL_MAX_PLL_MASK (0x1 << HPIPE_KVCO_CALIB_CTRL_MAX_PLL_OFFSET)
+
+#define HPIPE_CAL_REG1_REG 0xc
+#define HPIPE_CAL_REG_1_EXT_TXIMP_OFFSET 10
+#define HPIPE_CAL_REG_1_EXT_TXIMP_MASK (0x1f << HPIPE_CAL_REG_1_EXT_TXIMP_OFFSET)
+#define HPIPE_CAL_REG_1_EXT_TXIMP_EN_OFFSET 15
+#define HPIPE_CAL_REG_1_EXT_TXIMP_EN_MASK (0x1 << HPIPE_CAL_REG_1_EXT_TXIMP_EN_OFFSET)
+
+#define HPIPE_SQUELCH_FFE_SETTING_REG 0x018
+
+#define HPIPE_DFE_REG0 0x01C
+#define HPIPE_DFE_RES_FORCE_OFFSET 15
+#define HPIPE_DFE_RES_FORCE_MASK (0x1 << HPIPE_DFE_RES_FORCE_OFFSET)
+
+#define HPIPE_DFE_F3_F5_REG 0x028
+#define HPIPE_DFE_F3_F5_DFE_EN_OFFSET 14
+#define HPIPE_DFE_F3_F5_DFE_EN_MASK (0x1 << HPIPE_DFE_F3_F5_DFE_EN_OFFSET)
+#define HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET 15
+#define HPIPE_DFE_F3_F5_DFE_CTRL_MASK (0x1 << HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET)
+
+#define HPIPE_G1_SET0_REG 0x034
+#define HPIPE_G2_SET0_REG 0x03c
+#define HPIPE_G3_SET0_REG 0x044
+#define HPIPE_GX_SET0_TX_AMP_OFFSET 1
+#define HPIPE_GX_SET0_TX_AMP_MASK (0x1f << HPIPE_GX_SET0_TX_AMP_OFFSET)
+#define HPIPE_GX_SET0_TX_AMP_ADJ_OFFSET 6
+#define HPIPE_GX_SET0_TX_AMP_ADJ_MASK (0x1 << HPIPE_GX_SET0_TX_AMP_ADJ_OFFSET)
+#define HPIPE_GX_SET0_TX_EMPH1_OFFSET 7
+#define HPIPE_GX_SET0_TX_EMPH1_MASK (0xf << HPIPE_GX_SET0_TX_EMPH1_OFFSET)
+#define HPIPE_GX_SET0_TX_EMPH1_EN_OFFSET 11
+#define HPIPE_GX_SET0_TX_EMPH1_EN_MASK (0x1 << HPIPE_GX_SET0_TX_EMPH1_EN_OFFSET)
+#define HPIPE_GX_SET0_TX_SLEW_RATE_SEL_OFFSET 12
+#define HPIPE_GX_SET0_TX_SLEW_RATE_SEL_MASK (0x7 << HPIPE_GX_SET0_TX_SLEW_RATE_SEL_OFFSET)
+#define HPIPE_GX_SET0_TX_SLEW_CTRL_EN_OFFSET 15
+#define HPIPE_GX_SET0_TX_SLEW_CTRL_EN_MASK (0x1 << HPIPE_GX_SET0_TX_SLEW_CTRL_EN_OFFSET)
+
+#define HPIPE_G1_SET1_REG 0x038
+#define HPIPE_G2_SET1_REG 0x040
+#define HPIPE_G3_SET1_REG 0x048
+#define HPIPE_GX_SET1_RX_SELMUPI_OFFSET 0
+#define HPIPE_GX_SET1_RX_SELMUPI_MASK (0x7 << HPIPE_GX_SET1_RX_SELMUPI_OFFSET)
+#define HPIPE_GX_SET1_RX_SELMUPP_OFFSET 3
+#define HPIPE_GX_SET1_RX_SELMUPP_MASK (0x7 << HPIPE_GX_SET1_RX_SELMUPP_OFFSET)
+#define HPIPE_GX_SET1_RX_SELMUFI_OFFSET 6
+#define HPIPE_GX_SET1_RX_SELMUFI_MASK (0x3 << HPIPE_GX_SET1_RX_SELMUFI_OFFSET)
+#define HPIPE_GX_SET1_RX_SELMUFF_OFFSET 8
+#define HPIPE_GX_SET1_RX_SELMUFF_MASK (0x3 << HPIPE_GX_SET1_RX_SELMUFF_OFFSET)
+#define HPIPE_GX_SET1_RX_DFE_EN_OFFSET 10
+#define HPIPE_GX_SET1_RX_DFE_EN_MASK (0x1 << HPIPE_GX_SET1_RX_DFE_EN_OFFSET)
+#define HPIPE_GX_SET1_RX_DIGCK_DIV_OFFSET 11
+#define HPIPE_GX_SET1_RX_DIGCK_DIV_MASK (0x3 << HPIPE_GX_SET1_RX_DIGCK_DIV_OFFSET)
+#define HPIPE_GX_SET1_SAMPLER_INPAIRX2_EN_OFFSET 13
+#define HPIPE_GX_SET1_SAMPLER_INPAIRX2_EN_MASK (0x1 << HPIPE_GX_SET1_SAMPLER_INPAIRX2_EN_OFFSET)
+
+#define HPIPE_LOOPBACK_REG 0x08c
+#define HPIPE_LOOPBACK_SEL_OFFSET 1
+#define HPIPE_LOOPBACK_SEL_MASK (0x7 << HPIPE_LOOPBACK_SEL_OFFSET)
+
+#define HPIPE_SYNC_PATTERN_REG 0x090
+
+#define HPIPE_INTERFACE_REG 0x94
+#define HPIPE_INTERFACE_GEN_MAX_OFFSET 10
+#define HPIPE_INTERFACE_GEN_MAX_MASK (0x3 << HPIPE_INTERFACE_GEN_MAX_OFFSET)
+#define HPIPE_INTERFACE_DET_BYPASS_OFFSET 12
+#define HPIPE_INTERFACE_DET_BYPASS_MASK (0x1 << HPIPE_INTERFACE_DET_BYPASS_OFFSET)
+#define HPIPE_INTERFACE_LINK_TRAIN_OFFSET 14
+#define HPIPE_INTERFACE_LINK_TRAIN_MASK (0x1 << HPIPE_INTERFACE_LINK_TRAIN_OFFSET)
+
+#define HPIPE_ISOLATE_MODE_REG 0x98
+#define HPIPE_ISOLATE_MODE_GEN_RX_OFFSET 0
+#define HPIPE_ISOLATE_MODE_GEN_RX_MASK (0xf << HPIPE_ISOLATE_MODE_GEN_RX_OFFSET)
+#define HPIPE_ISOLATE_MODE_GEN_TX_OFFSET 4
+#define HPIPE_ISOLATE_MODE_GEN_TX_MASK (0xf << HPIPE_ISOLATE_MODE_GEN_TX_OFFSET)
+
+#define HPIPE_GX_SET2_REG 0xf4
+#define HPIPE_GX_SET2_TX_EMPH0_OFFSET 0
+#define HPIPE_GX_SET2_TX_EMPH0_MASK (0xf << HPIPE_GX_SET2_TX_EMPH0_OFFSET)
+#define HPIPE_GX_SET2_TX_EMPH0_EN_OFFSET 4
+#define HPIPE_GX_SET2_TX_EMPH0_EN_MASK (0x1 << HPIPE_GX_SET2_TX_EMPH0_MASK)
+
+#define HPIPE_VTHIMPCAL_CTRL_REG 0x104
+
+#define HPIPE_VDD_CAL_CTRL_REG 0x114
+#define HPIPE_EXT_SELLV_RXSAMPL_OFFSET 5
+#define HPIPE_EXT_SELLV_RXSAMPL_MASK (0x1f << HPIPE_EXT_SELLV_RXSAMPL_OFFSET)
+
+#define HPIPE_VDD_CAL_0_REG 0x108
+#define HPIPE_CAL_VDD_CONT_MODE_OFFSET 15
+#define HPIPE_CAL_VDD_CONT_MODE_MASK (0x1 << HPIPE_CAL_VDD_CONT_MODE_OFFSET)
+
+#define HPIPE_PCIE_REG0 0x120
+#define HPIPE_PCIE_IDLE_SYNC_OFFSET 12
+#define HPIPE_PCIE_IDLE_SYNC_MASK (0x1 << HPIPE_PCIE_IDLE_SYNC_OFFSET)
+#define HPIPE_PCIE_SEL_BITS_OFFSET 13
+#define HPIPE_PCIE_SEL_BITS_MASK (0x3 << HPIPE_PCIE_SEL_BITS_OFFSET)
+
+#define HPIPE_LANE_ALIGN_REG 0x124
+#define HPIPE_LANE_ALIGN_OFF_OFFSET 12
+#define HPIPE_LANE_ALIGN_OFF_MASK (0x1 << HPIPE_LANE_ALIGN_OFF_OFFSET)
+
+#define HPIPE_MISC_REG 0x13C
+#define HPIPE_MISC_CLK100M_125M_OFFSET 4
+#define HPIPE_MISC_CLK100M_125M_MASK (0x1 << HPIPE_MISC_CLK100M_125M_OFFSET)
+#define HPIPE_MISC_ICP_FORCE_OFFSET 5
+#define HPIPE_MISC_ICP_FORCE_MASK (0x1 << HPIPE_MISC_ICP_FORCE_OFFSET)
+#define HPIPE_MISC_TXDCLK_2X_OFFSET 6
+#define HPIPE_MISC_TXDCLK_2X_MASK (0x1 << HPIPE_MISC_TXDCLK_2X_OFFSET)
+#define HPIPE_MISC_CLK500_EN_OFFSET 7
+#define HPIPE_MISC_CLK500_EN_MASK (0x1 << HPIPE_MISC_CLK500_EN_OFFSET)
+#define HPIPE_MISC_REFCLK_SEL_OFFSET 10
+#define HPIPE_MISC_REFCLK_SEL_MASK (0x1 << HPIPE_MISC_REFCLK_SEL_OFFSET)
+
+#define HPIPE_RX_CONTROL_1_REG 0x140
+#define HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET 11
+#define HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK (0x1 << HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET)
+#define HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET 12
+#define HPIPE_RX_CONTROL_1_CLK8T_EN_MASK (0x1 << HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET)
+
+#define HPIPE_PWR_CTR_REG 0x148
+#define HPIPE_PWR_CTR_RST_DFE_OFFSET 0
+#define HPIPE_PWR_CTR_RST_DFE_MASK (0x1 << HPIPE_PWR_CTR_RST_DFE_OFFSET)
+#define HPIPE_PWR_CTR_SFT_RST_OFFSET 10
+#define HPIPE_PWR_CTR_SFT_RST_MASK (0x1 << HPIPE_PWR_CTR_SFT_RST_OFFSET)
+
+#define HPIPE_PLLINTP_REG1 0x150
+
+#define HPIPE_SPD_DIV_FORCE_REG 0x154
+#define HPIPE_TXDIGCK_DIV_FORCE_OFFSET 7
+#define HPIPE_TXDIGCK_DIV_FORCE_MASK (0x1 << HPIPE_TXDIGCK_DIV_FORCE_OFFSET)
+#define HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_OFFSET 8
+#define HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_MASK (0x3 << HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_OFFSET)
+#define HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_OFFSET 10
+#define HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_MASK (0x1 << HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_OFFSET)
+#define HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_OFFSET 13
+#define HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_MASK (0x3 << HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_OFFSET)
+#define HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_OFFSET 15
+#define HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_MASK (0x1 << HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_OFFSET)
+
+#define HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG 0x16C
+#define HPIPE_RX_SAMPLER_OS_GAIN_OFFSET 6
+#define HPIPE_RX_SAMPLER_OS_GAIN_MASK (0x3 << HPIPE_RX_SAMPLER_OS_GAIN_OFFSET)
+#define HPIPE_SAMPLER_OFFSET 12
+#define HPIPE_SAMPLER_MASK (0x1 << HPIPE_SAMPLER_OFFSET)
+
+#define HPIPE_TX_REG1_REG 0x174
+#define HPIPE_TX_REG1_TX_EMPH_RES_OFFSET 5
+#define HPIPE_TX_REG1_TX_EMPH_RES_MASK (0x3 << HPIPE_TX_REG1_TX_EMPH_RES_OFFSET)
+#define HPIPE_TX_REG1_SLC_EN_OFFSET 10
+#define HPIPE_TX_REG1_SLC_EN_MASK (0x3f << HPIPE_TX_REG1_SLC_EN_OFFSET)
+
+#define HPIPE_TX_REG1_REG 0x174
+#define HPIPE_TX_REG1_TX_EMPH_RES_OFFSET 5
+#define HPIPE_TX_REG1_TX_EMPH_RES_MASK (0x3 << HPIPE_TX_REG1_TX_EMPH_RES_OFFSET)
+#define HPIPE_TX_REG1_SLC_EN_OFFSET 10
+#define HPIPE_TX_REG1_SLC_EN_MASK (0x3f << HPIPE_TX_REG1_SLC_EN_OFFSET)
+
+#define HPIPE_PWR_CTR_DTL_REG 0x184
+#define HPIPE_PWR_CTR_DTL_SQ_DET_EN_OFFSET 0
+#define HPIPE_PWR_CTR_DTL_SQ_DET_EN_MASK (0x1 << HPIPE_PWR_CTR_DTL_SQ_DET_EN_OFFSET)
+#define HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_OFFSET 1
+#define HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_MASK (0x1 << HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_OFFSET)
+#define HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET 2
+#define HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK (0x1 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET)
+#define HPIPE_PWR_CTR_DTL_CLAMPING_SEL_OFFSET 4
+#define HPIPE_PWR_CTR_DTL_CLAMPING_SEL_MASK (0x7 << HPIPE_PWR_CTR_DTL_CLAMPING_SEL_OFFSET)
+#define HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_OFFSET 10
+#define HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_MASK (0x1 << HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_OFFSET)
+#define HPIPE_PWR_CTR_DTL_CLK_MODE_OFFSET 12
+#define HPIPE_PWR_CTR_DTL_CLK_MODE_MASK (0x3 << HPIPE_PWR_CTR_DTL_CLK_MODE_OFFSET)
+#define HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_OFFSET 14
+#define HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_MASK (1 << HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_OFFSET)
+
+#define HPIPE_PHASE_CONTROL_REG 0x188
+#define HPIPE_OS_PH_OFFSET_OFFSET 0
+#define HPIPE_OS_PH_OFFSET_MASK (0x7f << HPIPE_OS_PH_OFFSET_OFFSET)
+#define HPIPE_OS_PH_OFFSET_FORCE_OFFSET 7
+#define HPIPE_OS_PH_OFFSET_FORCE_MASK (0x1 << HPIPE_OS_PH_OFFSET_FORCE_OFFSET)
+#define HPIPE_OS_PH_VALID_OFFSET 8
+#define HPIPE_OS_PH_VALID_MASK (0x1 << HPIPE_OS_PH_VALID_OFFSET)
+
+#define HPIPE_FRAME_DETECT_CTRL_0_REG 0x214
+#define HPIPE_TRAIN_PAT_NUM_OFFSET 0x7
+#define HPIPE_TRAIN_PAT_NUM_MASK (0x1FF << HPIPE_TRAIN_PAT_NUM_OFFSET)
+
+#define HPIPE_FRAME_DETECT_CTRL_3_REG 0x220
+#define HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_OFFSET 12
+#define HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_MASK (0x1 << HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_OFFSET)
+
+#define HPIPE_DME_REG 0x228
+#define HPIPE_DME_ETHERNET_MODE_OFFSET 7
+#define HPIPE_DME_ETHERNET_MODE_MASK (0x1 << HPIPE_DME_ETHERNET_MODE_OFFSET)
+
+#define HPIPE_TX_TRAIN_CTRL_0_REG 0x268
+#define HPIPE_TX_TRAIN_P2P_HOLD_OFFSET 15
+#define HPIPE_TX_TRAIN_P2P_HOLD_MASK (0x1 << HPIPE_TX_TRAIN_P2P_HOLD_OFFSET)
+
+#define HPIPE_TX_TRAIN_CTRL_REG 0x26C
+#define HPIPE_TX_TRAIN_CTRL_G1_OFFSET 0
+#define HPIPE_TX_TRAIN_CTRL_G1_MASK (0x1 << HPIPE_TX_TRAIN_CTRL_G1_OFFSET)
+#define HPIPE_TX_TRAIN_CTRL_GN1_OFFSET 1
+#define HPIPE_TX_TRAIN_CTRL_GN1_MASK (0x1 << HPIPE_TX_TRAIN_CTRL_GN1_OFFSET)
+#define HPIPE_TX_TRAIN_CTRL_G0_OFFSET 2
+#define HPIPE_TX_TRAIN_CTRL_G0_MASK (0x1 << HPIPE_TX_TRAIN_CTRL_G0_OFFSET)
+
+#define HPIPE_TX_TRAIN_CTRL_4_REG 0x278
+#define HPIPE_TRX_TRAIN_TIMER_OFFSET 0
+#define HPIPE_TRX_TRAIN_TIMER_MASK (0x3FF << HPIPE_TRX_TRAIN_TIMER_OFFSET)
+
+#define HPIPE_PCIE_REG1 0x288
+#define HPIPE_PCIE_REG3 0x290
+
+#define HPIPE_TX_TRAIN_CTRL_5_REG 0x2A4
+#define HPIPE_RX_TRAIN_TIMER_OFFSET 0
+#define HPIPE_RX_TRAIN_TIMER_MASK (0x3ff << HPIPE_RX_TRAIN_TIMER_OFFSET)
+#define HPIPE_TX_TRAIN_START_SQ_EN_OFFSET 11
+#define HPIPE_TX_TRAIN_START_SQ_EN_MASK (0x1 << HPIPE_TX_TRAIN_START_SQ_EN_OFFSET)
+#define HPIPE_TX_TRAIN_START_FRM_DET_EN_OFFSET 12
+#define HPIPE_TX_TRAIN_START_FRM_DET_EN_MASK (0x1 << HPIPE_TX_TRAIN_START_FRM_DET_EN_OFFSET)
+#define HPIPE_TX_TRAIN_START_FRM_LOCK_EN_OFFSET 13
+#define HPIPE_TX_TRAIN_START_FRM_LOCK_EN_MASK (0x1 << HPIPE_TX_TRAIN_START_FRM_LOCK_EN_OFFSET)
+#define HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET 14
+#define HPIPE_TX_TRAIN_WAIT_TIME_EN_MASK (0x1 << HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET)
+
+#define HPIPE_TX_TRAIN_REG 0x31C
+#define HPIPE_TX_TRAIN_CHK_INIT_OFFSET 4
+#define HPIPE_TX_TRAIN_CHK_INIT_MASK (0x1 << HPIPE_TX_TRAIN_CHK_INIT_OFFSET)
+#define HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET 7
+#define HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_MASK (0x1 << HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET)
+#define HPIPE_TX_TRAIN_16BIT_AUTO_EN_OFFSET 8
+#define HPIPE_TX_TRAIN_16BIT_AUTO_EN_MASK (0x1 << HPIPE_TX_TRAIN_16BIT_AUTO_EN_OFFSET)
+#define HPIPE_TX_TRAIN_PAT_SEL_OFFSET 9
+#define HPIPE_TX_TRAIN_PAT_SEL_MASK (0x1 << HPIPE_TX_TRAIN_PAT_SEL_OFFSET)
+
+#define HPIPE_CDR_CONTROL_REG 0x418
+#define HPIPE_CDR_MAX_DFE_ADAPT_1_OFFSET 6
+#define HPIPE_CDR_MAX_DFE_ADAPT_1_MASK (0x7 << HPIPE_CDR_MAX_DFE_ADAPT_1_OFFSET)
+#define HPIPE_CDR_MAX_DFE_ADAPT_0_OFFSET 9
+#define HPIPE_CDR_MAX_DFE_ADAPT_0_MASK (0x7 << HPIPE_CDR_MAX_DFE_ADAPT_0_OFFSET)
+#define HPIPE_CDR_RX_MAX_DFE_ADAPT_1_OFFSET 12
+#define HPIPE_CDR_RX_MAX_DFE_ADAPT_1_MASK (0x3 << HPIPE_CDR_RX_MAX_DFE_ADAPT_1_OFFSET)
+
+#define HPIPE_TX_TRAIN_CTRL_11_REG 0x438
+#define HPIPE_TX_STATUS_CHECK_MODE_OFFSET 6
+#define HPIPE_TX_TX_STATUS_CHECK_MODE_MASK (0x1 << HPIPE_TX_STATUS_CHECK_MODE_OFFSET)
+#define HPIPE_TX_NUM_OF_PRESET_OFFSET 10
+#define HPIPE_TX_NUM_OF_PRESET_MASK (0x7 << HPIPE_TX_NUM_OF_PRESET_OFFSET)
+#define HPIPE_TX_SWEEP_PRESET_EN_OFFSET 15
+#define HPIPE_TX_SWEEP_PRESET_EN_MASK (0x1 << HPIPE_TX_SWEEP_PRESET_EN_OFFSET)
+
+#define HPIPE_G1_SET3_REG 0x440
+#define HPIPE_G2_SET3_REG 0x448
+#define HPIPE_G3_SET3_REG 0x450
+#define HPIPE_GX_SET3_FFE_CAP_SEL_OFFSET 0
+#define HPIPE_GX_SET3_FFE_CAP_SEL_MASK (0xf << HPIPE_GX_SET3_FFE_CAP_SEL_OFFSET)
+#define HPIPE_GX_SET3_FFE_RES_SEL_OFFSET 4
+#define HPIPE_GX_SET3_FFE_RES_SEL_MASK (0x7 << HPIPE_GX_SET3_FFE_RES_SEL_OFFSET)
+#define HPIPE_GX_SET3_FFE_SETTING_FORCE_OFFSET 7
+#define HPIPE_GX_SET3_FFE_SETTING_FORCE_MASK (0x1 << HPIPE_GX_SET3_FFE_SETTING_FORCE_OFFSET)
+#define HPIPE_GX_SET3_FBCK_SEL_OFFSET 9
+#define HPIPE_GX_SET3_FBCK_SEL_MASK (0x1 << HPIPE_GX_SET3_FBCK_SEL_OFFSET)
+#define HPIPE_GX_SET3_FFE_DEG_RES_LEVEL_OFFSET 12
+#define HPIPE_GX_SET3_FFE_DEG_RES_LEVEL_MASK (0x3 << HPIPE_GX_SET3_FFE_DEG_RES_LEVEL_OFFSET)
+#define HPIPE_GX_SET3_FFE_LOAD_RES_LEVEL_OFFSET 14
+#define HPIPE_GX_SET3_FFE_LOAD_RES_LEVEL_MASK (0x3 << HPIPE_GX_SET3_FFE_LOAD_RES_LEVEL_OFFSET)
+
+#define HPIPE_G1_SET4_REG 0x444
+#define HPIPE_G2_SET4_REG 0x44C
+#define HPIPE_G3_SET4_REG 0x454
+#define HPIPE_GX_SET4_DFE_RES_OFFSET 8
+#define HPIPE_GX_SET4_DFE_RES_MASK (0x3 << HPIPE_GX_SET4_DFE_RES_OFFSET)
+
+#define HPIPE_TX_PRESET_INDEX_REG 0x468
+#define HPIPE_TX_PRESET_INDEX_OFFSET 0
+#define HPIPE_TX_PRESET_INDEX_MASK (0xf << HPIPE_TX_PRESET_INDEX_OFFSET)
+
+#define HPIPE_DFE_CONTROL_REG 0x470
+#define HPIPE_DFE_TX_MAX_DFE_ADAPT_OFFSET 14
+#define HPIPE_DFE_TX_MAX_DFE_ADAPT_MASK (0x3 << HPIPE_DFE_TX_MAX_DFE_ADAPT_OFFSET)
+
+#define HPIPE_DFE_CTRL_28_REG 0x49C
+#define HPIPE_DFE_CTRL_28_PIPE4_OFFSET 7
+#define HPIPE_DFE_CTRL_28_PIPE4_MASK (0x1 << HPIPE_DFE_CTRL_28_PIPE4_OFFSET)
+
+#define HPIPE_G1_SET5_REG 0x538
+#define HPIPE_G3_SET5_REG 0x548
+#define HPIPE_GX_SET5_ICP_OFFSET 0
+#define HPIPE_GX_SET5_ICP_MASK (0xf << HPIPE_GX_SET5_ICP_OFFSET)
+
+#define HPIPE_LANE_CONFIG0_REG 0x604
+#define HPIPE_LANE_CONFIG0_MAX_PLL_OFFSET 9
+#define HPIPE_LANE_CONFIG0_MAX_PLL_MASK (0x1 << HPIPE_LANE_CONFIG0_MAX_PLL_OFFSET)
+#define HPIPE_LANE_CONFIG0_GEN2_PLL_OFFSET 10
+#define HPIPE_LANE_CONFIG0_GEN2_PLL_MASK (0x1 << HPIPE_LANE_CONFIG0_GEN2_PLL_OFFSET)
+
+#define HPIPE_LANE_STATUS0_REG 0x60C
+#define HPIPE_LANE_STATUS0_PCLK_EN_OFFSET 0
+#define HPIPE_LANE_STATUS0_PCLK_EN_MASK (0x1 << HPIPE_LANE_STATUS0_PCLK_EN_OFFSET)
+
+#define HPIPE_LANE_CFG4_REG 0x620
+#define HPIPE_LANE_CFG4_DFE_CTRL_OFFSET 0
+#define HPIPE_LANE_CFG4_DFE_CTRL_MASK (0x7 << HPIPE_LANE_CFG4_DFE_CTRL_OFFSET)
+#define HPIPE_LANE_CFG4_DFE_EN_SEL_OFFSET 3
+#define HPIPE_LANE_CFG4_DFE_EN_SEL_MASK (0x1 << HPIPE_LANE_CFG4_DFE_EN_SEL_OFFSET)
+#define HPIPE_LANE_CFG4_DFE_OVER_OFFSET 6
+#define HPIPE_LANE_CFG4_DFE_OVER_MASK (0x1 << HPIPE_LANE_CFG4_DFE_OVER_OFFSET)
+#define HPIPE_LANE_CFG4_SSC_CTRL_OFFSET 7
+#define HPIPE_LANE_CFG4_SSC_CTRL_MASK (0x1 << HPIPE_LANE_CFG4_SSC_CTRL_OFFSET)
+
+#define HPIPE_LANE_EQU_CONFIG_0_REG 0x69C
+#define HPIPE_CFG_PHY_RC_EP_OFFSET 12
+#define HPIPE_CFG_PHY_RC_EP_MASK (0x1 << HPIPE_CFG_PHY_RC_EP_OFFSET)
+
+#define HPIPE_LANE_EQ_CFG1_REG 0x6a0
+#define HPIPE_CFG_UPDATE_POLARITY_OFFSET 12
+#define HPIPE_CFG_UPDATE_POLARITY_MASK (0x1 << HPIPE_CFG_UPDATE_POLARITY_OFFSET)
+
+#define HPIPE_LANE_EQ_REMOTE_SETTING_REG 0x6f8
+#define HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_OFFSET 0
+#define HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_MASK (0x1 << HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_OFFSET)
+#define HPIPE_LANE_CFG_FOM_ONLY_MODE_OFFFSET 1
+#define HPIPE_LANE_CFG_FOM_ONLY_MODE_MASK (0x1 << HPIPE_LANE_CFG_FOM_ONLY_MODE_OFFFSET)
+#define HPIPE_LANE_CFG_FOM_PRESET_VECTOR_OFFSET 2
+#define HPIPE_LANE_CFG_FOM_PRESET_VECTOR_MASK (0xf << HPIPE_LANE_CFG_FOM_PRESET_VECTOR_OFFSET)
+
+#define HPIPE_RST_CLK_CTRL_REG 0x704
+#define HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET 0
+#define HPIPE_RST_CLK_CTRL_PIPE_RST_MASK (0x1 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET)
+#define HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET 2
+#define HPIPE_RST_CLK_CTRL_FIXED_PCLK_MASK (0x1 << HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET)
+#define HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET 3
+#define HPIPE_RST_CLK_CTRL_PIPE_WIDTH_MASK (0x1 << HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET)
+#define HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET 9
+#define HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_MASK (0x1 << HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET)
+
+#define HPIPE_CLK_SRC_LO_REG 0x70c
+#define HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET 5
+#define HPIPE_CLK_SRC_LO_PLL_RDY_DL_MASK (0x7 << HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET)
+
+#define HPIPE_CLK_SRC_HI_REG 0x710
+#define HPIPE_CLK_SRC_HI_LANE_STRT_OFFSET 0
+#define HPIPE_CLK_SRC_HI_LANE_STRT_MASK (0x1 << HPIPE_CLK_SRC_HI_LANE_STRT_OFFSET)
+#define HPIPE_CLK_SRC_HI_LANE_BREAK_OFFSET 1
+#define HPIPE_CLK_SRC_HI_LANE_BREAK_MASK (0x1 << HPIPE_CLK_SRC_HI_LANE_BREAK_OFFSET)
+#define HPIPE_CLK_SRC_HI_LANE_MASTER_OFFSET 2
+#define HPIPE_CLK_SRC_HI_LANE_MASTER_MASK (0x1 << HPIPE_CLK_SRC_HI_LANE_MASTER_OFFSET)
+#define HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET 7
+#define HPIPE_CLK_SRC_HI_MODE_PIPE_MASK (0x1 << HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET)
+
+#define HPIPE_GLOBAL_MISC_CTRL 0x718
+#define HPIPE_GLOBAL_PM_CTRL 0x740
+#define HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET 0
+#define HPIPE_GLOBAL_PM_RXDLOZ_WAIT_MASK (0xFF << HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET)
+
+/***** COMPHY registers *****/
+#define COMMON_PHY_CFG1_REG 0x0
+#define COMMON_PHY_CFG1_PWR_UP_OFFSET 1
+#define COMMON_PHY_CFG1_PWR_UP_MASK (0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET)
+#define COMMON_PHY_CFG1_PIPE_SELECT_OFFSET 2
+#define COMMON_PHY_CFG1_PIPE_SELECT_MASK (0x1 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET)
+#define COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET 13
+#define COMMON_PHY_CFG1_PWR_ON_RESET_MASK (0x1 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET)
+#define COMMON_PHY_CFG1_CORE_RSTN_OFFSET 14
+#define COMMON_PHY_CFG1_CORE_RSTN_MASK (0x1 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET)
+#define COMMON_PHY_PHY_MODE_OFFSET 15
+#define COMMON_PHY_PHY_MODE_MASK (0x1 << COMMON_PHY_PHY_MODE_OFFSET)
+
+#define COMMON_PHY_CFG6_REG 0x14
+#define COMMON_PHY_CFG6_IF_40_SEL_OFFSET 18
+#define COMMON_PHY_CFG6_IF_40_SEL_MASK (0x1 << COMMON_PHY_CFG6_IF_40_SEL_OFFSET)
+
+#define COMMON_SELECTOR_PHY_OFFSET 0x140
+#define COMMON_SELECTOR_PIPE_OFFSET 0x144
+
+#define COMMON_PHY_SD_CTRL1 0x148
+#define COMMON_PHY_SD_CTRL1_RXAUI1_OFFSET 26
+#define COMMON_PHY_SD_CTRL1_RXAUI1_MASK (0x1 << COMMON_PHY_SD_CTRL1_RXAUI1_OFFSET)
+#define COMMON_PHY_SD_CTRL1_RXAUI0_OFFSET 27
+#define COMMON_PHY_SD_CTRL1_RXAUI0_MASK (0x1 << COMMON_PHY_SD_CTRL1_RXAUI0_OFFSET)
+
+/***** SATA registers *****/
+#define SATA3_VENDOR_ADDRESS 0xA0
+#define SATA3_VENDOR_ADDR_OFSSET 0
+#define SATA3_VENDOR_ADDR_MASK (0xFFFFFFFF << SATA3_VENDOR_ADDR_OFSSET)
+#define SATA3_VENDOR_DATA 0xA4
+
+#define SATA_CONTROL_REG 0x0
+#define SATA3_CTRL_SATA0_PD_OFFSET 6
+#define SATA3_CTRL_SATA0_PD_MASK (1 << SATA3_CTRL_SATA0_PD_OFFSET)
+#define SATA3_CTRL_SATA1_PD_OFFSET 14
+#define SATA3_CTRL_SATA1_PD_MASK (1 << SATA3_CTRL_SATA1_PD_OFFSET)
+#define SATA3_CTRL_SATA1_ENABLE_OFFSET 22
+#define SATA3_CTRL_SATA1_ENABLE_MASK (1 << SATA3_CTRL_SATA1_ENABLE_OFFSET)
+#define SATA3_CTRL_SATA_SSU_OFFSET 23
+#define SATA3_CTRL_SATA_SSU_MASK (1 << SATA3_CTRL_SATA_SSU_OFFSET)
+
+#define SATA_MBUS_SIZE_SELECT_REG 0x4
+#define SATA_MBUS_REGRET_EN_OFFSET 7
+#define SATA_MBUS_REGRET_EN_MASK (0x1 << SATA_MBUS_REGRET_EN_OFFSET)
+
+/***************************/
+
+typedef struct _CHIP_COMPHY_CONFIG CHIP_COMPHY_CONFIG;
+
+typedef struct {
+ UINT32 Type;
+ UINT32 MuxValue;
+} COMPHY_MUX_OPTIONS;
+
+typedef struct {
+ UINT32 MaxLaneValues;
+ COMPHY_MUX_OPTIONS MuxValues[MAX_LANE_OPTIONS];
+} COMPHY_MUX_DATA;
+
+typedef struct {
+ UINT32 Type;
+ UINT32 Speed;
+ UINT32 Invert;
+} COMPHY_MAP;
+
+typedef struct {
+ CHAR16 *TypeStr[MAX_LANE_OPTIONS];
+ UINTN SpeedValue[MAX_LANE_OPTIONS];
+ UINTN InvFlag[MAX_LANE_OPTIONS];
+} PCD_LANE_MAP;
+
+typedef
+VOID
+(*COMPHY_CHIP_INIT) (
+ IN CHIP_COMPHY_CONFIG *PtrChipCfg
+ );
+
+struct _CHIP_COMPHY_CONFIG {
+ MV_COMPHY_CHIP_TYPE ChipType;
+ COMPHY_MAP MapData[MAX_LANE_OPTIONS];
+ COMPHY_MUX_DATA *MuxData;
+ EFI_PHYSICAL_ADDRESS ComPhyBaseAddr;
+ EFI_PHYSICAL_ADDRESS Hpipe3BaseAddr;
+ COMPHY_CHIP_INIT Init;
+ UINT32 LanesCount;
+ UINT32 MuxBitCount;
+};
+
+VOID
+ComPhyMuxInit (
+ IN CHIP_COMPHY_CONFIG *PtrChipCfg,
+ IN COMPHY_MAP *ComPhyMapData,
+ IN EFI_PHYSICAL_ADDRESS SelectorBase
+ );
+
+VOID
+ComPhyCp110Init (
+ IN CHIP_COMPHY_CONFIG * First
+ );
+
+VOID
+RegSet (
+ IN EFI_PHYSICAL_ADDRESS Addr,
+ IN UINT32 Data,
+ IN UINT32 Mask
+ );
+
+VOID
+RegSetSilent (
+ IN EFI_PHYSICAL_ADDRESS Addr,
+ IN UINT32 Data,
+ IN UINT32 Mask
+ );
+
+VOID
+RegSet16 (
+ IN EFI_PHYSICAL_ADDRESS Addr,
+ IN UINT16 Data,
+ IN UINT16 Mask
+ );
+
+VOID
+RegSetSilent16(
+ IN EFI_PHYSICAL_ADDRESS Addr,
+ IN UINT16 Data,
+ IN UINT16 Mask
+ );
+#endif // __COMPHY_H__
diff --git a/Platform/Marvell/Library/ComPhyLib/ComPhyLib.inf b/Platform/Marvell/Library/ComPhyLib/ComPhyLib.inf
new file mode 100644
index 0000000000..e0f4634dca
--- /dev/null
+++ b/Platform/Marvell/Library/ComPhyLib/ComPhyLib.inf
@@ -0,0 +1,84 @@
+# Copyright (C) 2016 Marvell International Ltd.
+#
+# Marvell BSD License Option
+#
+# If you received this File from Marvell, you may opt to use, redistribute and/or
+# modify this File under the following licensing terms.
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Marvell nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = MarvellComPhyLib
+ FILE_GUID = 3314541a-9647-4a37-b8c6-24e000900e4e
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = ComPhyLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ ArmPkg/ArmPkg.dec
+ ArmPlatformPkg/ArmPlatformPkg.dec
+ Platform/Marvell/Marvell.dec
+
+[LibraryClasses]
+ ArmLib
+ DebugLib
+ MemoryAllocationLib
+ PcdLib
+ IoLib
+ ParsePcdLib
+
+[Sources.common]
+ ComPhyLib.c
+ ComPhyCp110.c
+ ComPhyMux.c
+
+[FixedPcd]
+ gMarvellTokenSpaceGuid.PcdComPhyDevices
+
+ #Chip0
+ gMarvellTokenSpaceGuid.PcdChip0ComPhyTypes
+ gMarvellTokenSpaceGuid.PcdChip0ComPhySpeeds
+ gMarvellTokenSpaceGuid.PcdChip0ComPhyInvFlags
+
+ #Chip1
+ gMarvellTokenSpaceGuid.PcdChip1ComPhyTypes
+ gMarvellTokenSpaceGuid.PcdChip1ComPhySpeeds
+ gMarvellTokenSpaceGuid.PcdChip1ComPhyInvFlags
+
+ #Chip2
+ gMarvellTokenSpaceGuid.PcdChip2ComPhyTypes
+ gMarvellTokenSpaceGuid.PcdChip2ComPhySpeeds
+ gMarvellTokenSpaceGuid.PcdChip2ComPhyInvFlags
+
+ #Chip3
+ gMarvellTokenSpaceGuid.PcdChip3ComPhyTypes
+ gMarvellTokenSpaceGuid.PcdChip3ComPhySpeeds
+ gMarvellTokenSpaceGuid.PcdChip3ComPhyInvFlags
+
+ gMarvellTokenSpaceGuid.PcdPciEAhci
diff --git a/Platform/Marvell/Library/ComPhyLib/ComPhyMux.c b/Platform/Marvell/Library/ComPhyLib/ComPhyMux.c
new file mode 100644
index 0000000000..6589fec9f0
--- /dev/null
+++ b/Platform/Marvell/Library/ComPhyLib/ComPhyMux.c
@@ -0,0 +1,132 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#include "ComPhyLib.h"
+
+STATIC
+VOID
+ComPhyMuxCheckConfig (
+ IN COMPHY_MUX_DATA *MuxData,
+ IN COMPHY_MAP *ComPhyMapData,
+ IN UINTN ComPhyMaxLanes
+ )
+{
+ COMPHY_MUX_OPTIONS *PtrMuxOpt;
+ UINTN Lane, Opt, Valid;
+
+ for (Lane = 0; Lane < ComPhyMaxLanes; Lane++, ComPhyMapData++, MuxData++) {
+ PtrMuxOpt = MuxData->MuxValues;
+ for (Opt = 0, Valid = 0; Opt < MuxData->MaxLaneValues; Opt++, PtrMuxOpt++) {
+ if (PtrMuxOpt->Type == ComPhyMapData->Type) {
+ Valid = 1;
+ break;
+ }
+ }
+ if (Valid == 0) {
+ DEBUG((DEBUG_INFO, "Lane number %d, had invalid Type %d\n", Lane,
+ ComPhyMapData->Type));
+ DEBUG((DEBUG_INFO, "Set Lane %d as Type %d\n", Lane,
+ COMPHY_TYPE_UNCONNECTED));
+ ComPhyMapData->Type = COMPHY_TYPE_UNCONNECTED;
+ } else {
+ DEBUG((DEBUG_INFO, "Lane number %d, has Type %d\n", Lane,
+ ComPhyMapData->Type));
+ }
+ }
+}
+
+STATIC
+UINT32
+ComPhyMuxGetMuxValue (
+ IN COMPHY_MUX_DATA *MuxData,
+ IN UINT32 Type,
+ IN UINTN Lane
+ )
+{
+ COMPHY_MUX_OPTIONS *PtrMuxOpt;
+ UINTN Opt;
+ UINT32 Value = 0;
+
+ PtrMuxOpt = MuxData->MuxValues;
+ for (Opt = 0 ; Opt < MuxData->MaxLaneValues; Opt++, PtrMuxOpt++)
+ if (PtrMuxOpt->Type == Type) {
+ Value = PtrMuxOpt->MuxValue;
+ break;
+ }
+
+ return Value;
+}
+
+STATIC
+VOID
+ComPhyMuxRegWrite (
+ IN COMPHY_MUX_DATA *MuxData,
+ IN COMPHY_MAP *ComPhyMapData,
+ IN UINTN ComPhyMaxLanes,
+ IN EFI_PHYSICAL_ADDRESS SelectorBase,
+ IN UINT32 BitCount
+ )
+{
+ UINT32 Lane, Value, Offset, Mask;
+
+ for (Lane = 0; Lane < ComPhyMaxLanes; Lane++, ComPhyMapData++, MuxData++) {
+ Offset = Lane * BitCount;
+ Mask = (((1 << BitCount) - 1) << Offset);
+ Value = (ComPhyMuxGetMuxValue (MuxData, ComPhyMapData->Type, Lane) <<
+ Offset);
+ RegSet (SelectorBase, Value, Mask);
+ }
+}
+
+VOID
+ComPhyMuxInit (
+ IN CHIP_COMPHY_CONFIG *PtrChipCfg,
+ IN COMPHY_MAP *ComPhyMapData,
+ IN EFI_PHYSICAL_ADDRESS SelectorBase
+ )
+{
+ COMPHY_MUX_DATA *MuxData;
+ UINT32 MuxBitCount;
+ UINT32 ComPhyMaxLanes;
+
+ ComPhyMaxLanes = PtrChipCfg->LanesCount;
+ MuxData = PtrChipCfg->MuxData;
+ MuxBitCount = PtrChipCfg->MuxBitCount;
+
+ /* Check if the configuration is valid */
+ ComPhyMuxCheckConfig (MuxData, ComPhyMapData, ComPhyMaxLanes);
+ /* Init COMPHY selectors */
+ ComPhyMuxRegWrite (MuxData, ComPhyMapData, ComPhyMaxLanes, SelectorBase,
+ MuxBitCount);
+}
diff --git a/Platform/Marvell/Library/MppLib/MppLib.c b/Platform/Marvell/Library/MppLib/MppLib.c
new file mode 100644
index 0000000000..c09acf95fe
--- /dev/null
+++ b/Platform/Marvell/Library/MppLib/MppLib.c
@@ -0,0 +1,216 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#include <Library/ArmLib.h>
+#include <Library/ArmPlatformLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/IoLib.h>
+
+#define MPP_PIN_VAL(pin,func) (((func) & 0xf) << ((pin) * 4))
+#define MPP_MAX_REGS 8
+#define MPP_PINS_PER_REG 8
+#define PCD_PINS_PER_GROUP 10
+
+#define SD_MMC_PHY_AP_MPP_OFFSET 0x100
+#define SD_MMC_PHY_CP0_MPP_OFFSET 0x424
+#define MPP_ON_SDPHY_ENABLE (1 << 0)
+
+#define MAX_CHIPS 4
+
+#define GET_PCD_PTR(id,num) PcdGetPtr(PcdChip##id##MppSel##num)
+#define GET_PIN_COUNT(id) PcdGet32(PcdChip##id##MppPinCount)
+#define GET_BASE(id) PcdGet64(PcdChip##id##MppBaseAddress)
+#define GET_REV_FLAG(id) PcdGetBool(PcdChip##id##MppReverseFlag)
+
+/* We get chip number */
+#define GetMppPcd(id) { \
+ PinCount[id] = GET_PIN_COUNT(id); \
+ MppRegPcd[id][7] = GET_PCD_PTR(id,7); \
+ MppRegPcd[id][6] = GET_PCD_PTR(id,6); \
+ MppRegPcd[id][5] = GET_PCD_PTR(id,5); \
+ MppRegPcd[id][4] = GET_PCD_PTR(id,4); \
+ MppRegPcd[id][3] = GET_PCD_PTR(id,3); \
+ MppRegPcd[id][2] = GET_PCD_PTR(id,2); \
+ MppRegPcd[id][1] = GET_PCD_PTR(id,1); \
+ MppRegPcd[id][0] = GET_PCD_PTR(id,0); \
+ BaseAddr[id] = GET_BASE(id); \
+ ReverseFlag[id] = GET_REV_FLAG(id); \
+}
+
+STATIC
+VOID
+SetRegisterValue (
+ UINT8 RegCount,
+ UINT8 **MppRegPcd,
+ UINTN BaseAddr,
+ BOOLEAN ReverseFlag
+ )
+{
+ UINT32 i, j, CtrlVal;
+ INTN Sign;
+
+ Sign = ReverseFlag ? -1 : 1;
+
+ for (i = 0; i < RegCount; i++) {
+ CtrlVal = 0;
+ for (j = 0; j < MPP_PINS_PER_REG; j++) {
+ CtrlVal |= MPP_PIN_VAL(7 * (UINTN) ReverseFlag + j * Sign,
+ MppRegPcd[i][7 * (UINTN) ReverseFlag + j * Sign]);
+ }
+ MmioWrite32 (BaseAddr + 4 * i * Sign, CtrlVal);
+ }
+}
+
+STATIC
+/* Transform PCD MPP group format into hardware register format */
+UINT8
+PcdToMppRegs (
+ UINTN PinCount,
+ UINT8 **MppRegPcd
+ )
+{
+ UINT8 MppRegPcdTmp[MPP_MAX_REGS][MPP_PINS_PER_REG];
+ UINT8 PcdGroupCount, MppRegCount;
+ UINTN i, j, k, l;
+
+ if (PinCount == 0) {
+ return 0;
+ }
+
+ PcdGroupCount = PinCount / PCD_PINS_PER_GROUP;
+ if ((PinCount % PCD_PINS_PER_GROUP) != 0) {
+ PcdGroupCount += 1;
+ }
+
+ MppRegCount = PinCount / MPP_PINS_PER_REG;
+ if ((PinCount % MPP_PINS_PER_REG) != 0) {
+ MppRegCount += 1;
+ }
+
+ /* Fill temporary table with data from PCD groups in HW format */
+ for (i = 0; i < PcdGroupCount; i++) {
+ for (j = 0; j < PCD_PINS_PER_GROUP; j++) {
+ k = (PCD_PINS_PER_GROUP * i + j) / MPP_PINS_PER_REG;
+ l = (PCD_PINS_PER_GROUP * i + j) % MPP_PINS_PER_REG;
+ MppRegPcdTmp[k][l] = MppRegPcd[i][j];
+ }
+ }
+
+ /* Update input table */
+ for (i = 0; i < MppRegCount; i++) {
+ for (j = 0; j < MPP_PINS_PER_REG; j++) {
+ MppRegPcd[i][j] = MppRegPcdTmp[i][j];
+ }
+ }
+
+ return MppRegCount;
+}
+
+STATIC
+VOID
+SetSdMmcPhyMpp (
+ UINTN BaseAddr,
+ UINT32 Index
+ )
+{
+ UINTN Size, Offset;
+ UINT8 *Ptr;
+ UINT32 Reg;
+
+ Size = PcdGetSize(PcdPciESdhci);
+ Ptr = (UINT8 *) PcdGetPtr(PcdPciESdhci);
+
+ if (Ptr == NULL || Index >= Size) {
+ return;
+ }
+
+ /* Check if SDHCI controller is enabled on the HW block */
+ if (Ptr[Index] != 1) {
+ return;
+ }
+
+ /* Choose adequate Offset */
+ switch (Index) {
+ case 0:
+ Offset = SD_MMC_PHY_AP_MPP_OFFSET;
+ break;
+ case 1:
+ Offset = SD_MMC_PHY_CP0_MPP_OFFSET;
+ break;
+ default:
+ return;
+ }
+
+ /*
+ * If there is SDHCI controller on platform, connect SD/MMC PHY to
+ * SD/MMC controller insted of using it as MPP multiplexer
+ */
+ Reg = MmioRead32 (BaseAddr + Offset);
+ Reg &= ~MPP_ON_SDPHY_ENABLE;
+ MmioWrite32 (BaseAddr + Offset, Reg);
+}
+
+EFI_STATUS
+MppInitialize (
+ )
+{
+ UINTN BaseAddr[MAX_CHIPS], PinCount[MAX_CHIPS], RegCount;
+ BOOLEAN ReverseFlag[MAX_CHIPS];
+ UINT8 *MppRegPcd[MAX_CHIPS][MPP_MAX_REGS];
+ UINT32 i, ChipCount;
+
+ ChipCount = PcdGet32 (PcdMppChipCount);
+
+ /* Read all needed PCD for MPP configuration */
+ GetMppPcd(0);
+ GetMppPcd(1);
+ GetMppPcd(2);
+ GetMppPcd(3);
+
+ for (i = 0; i < MAX_CHIPS; i++) {
+ if (i == ChipCount)
+ break;
+ RegCount = PcdToMppRegs (PinCount[i], MppRegPcd[i]);
+ SetRegisterValue (RegCount, MppRegPcd[i], BaseAddr[i], ReverseFlag[i]);
+
+ /*
+ * eMMC PHY IP has its own MPP configuration.
+ */
+ SetSdMmcPhyMpp (BaseAddr[i], i);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Marvell/Library/MppLib/MppLib.inf b/Platform/Marvell/Library/MppLib/MppLib.inf
new file mode 100644
index 0000000000..2de9cd0747
--- /dev/null
+++ b/Platform/Marvell/Library/MppLib/MppLib.inf
@@ -0,0 +1,108 @@
+#
+# Marvell BSD License Option
+#
+# If you received this File from Marvell, you may opt to use, redistribute
+# and/or modify this File under the following licensing terms.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Marvell nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = MarvellMppLib
+ FILE_GUID = 3f19b642-4a49-4dfd-8f4a-205dd38432bb
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = MppLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ ArmPkg/ArmPkg.dec
+ ArmPlatformPkg/ArmPlatformPkg.dec
+ Platform/Marvell/Marvell.dec
+
+[LibraryClasses]
+ ArmLib
+ DebugLib
+ MemoryAllocationLib
+ PcdLib
+ IoLib
+
+[Sources.common]
+ MppLib.c
+
+[FixedPcd]
+ gMarvellTokenSpaceGuid.PcdMppChipCount
+
+ gMarvellTokenSpaceGuid.PcdChip0MppReverseFlag
+ gMarvellTokenSpaceGuid.PcdChip0MppBaseAddress
+ gMarvellTokenSpaceGuid.PcdChip0MppPinCount
+ gMarvellTokenSpaceGuid.PcdChip0MppSel0
+ gMarvellTokenSpaceGuid.PcdChip0MppSel1
+ gMarvellTokenSpaceGuid.PcdChip0MppSel2
+ gMarvellTokenSpaceGuid.PcdChip0MppSel3
+ gMarvellTokenSpaceGuid.PcdChip0MppSel4
+ gMarvellTokenSpaceGuid.PcdChip0MppSel5
+ gMarvellTokenSpaceGuid.PcdChip0MppSel6
+ gMarvellTokenSpaceGuid.PcdChip0MppSel7
+
+ gMarvellTokenSpaceGuid.PcdChip1MppReverseFlag
+ gMarvellTokenSpaceGuid.PcdChip1MppBaseAddress
+ gMarvellTokenSpaceGuid.PcdChip1MppPinCount
+ gMarvellTokenSpaceGuid.PcdChip1MppSel0
+ gMarvellTokenSpaceGuid.PcdChip1MppSel1
+ gMarvellTokenSpaceGuid.PcdChip1MppSel2
+ gMarvellTokenSpaceGuid.PcdChip1MppSel3
+ gMarvellTokenSpaceGuid.PcdChip1MppSel4
+ gMarvellTokenSpaceGuid.PcdChip1MppSel5
+ gMarvellTokenSpaceGuid.PcdChip1MppSel6
+ gMarvellTokenSpaceGuid.PcdChip1MppSel7
+
+ gMarvellTokenSpaceGuid.PcdChip2MppReverseFlag
+ gMarvellTokenSpaceGuid.PcdChip2MppBaseAddress
+ gMarvellTokenSpaceGuid.PcdChip2MppPinCount
+ gMarvellTokenSpaceGuid.PcdChip2MppSel0
+ gMarvellTokenSpaceGuid.PcdChip2MppSel1
+ gMarvellTokenSpaceGuid.PcdChip2MppSel2
+ gMarvellTokenSpaceGuid.PcdChip2MppSel3
+ gMarvellTokenSpaceGuid.PcdChip2MppSel4
+ gMarvellTokenSpaceGuid.PcdChip2MppSel5
+ gMarvellTokenSpaceGuid.PcdChip2MppSel6
+ gMarvellTokenSpaceGuid.PcdChip2MppSel7
+
+ gMarvellTokenSpaceGuid.PcdChip3MppReverseFlag
+ gMarvellTokenSpaceGuid.PcdChip3MppBaseAddress
+ gMarvellTokenSpaceGuid.PcdChip3MppPinCount
+ gMarvellTokenSpaceGuid.PcdChip3MppSel0
+ gMarvellTokenSpaceGuid.PcdChip3MppSel1
+ gMarvellTokenSpaceGuid.PcdChip3MppSel2
+ gMarvellTokenSpaceGuid.PcdChip3MppSel3
+ gMarvellTokenSpaceGuid.PcdChip3MppSel4
+ gMarvellTokenSpaceGuid.PcdChip3MppSel5
+ gMarvellTokenSpaceGuid.PcdChip3MppSel6
+ gMarvellTokenSpaceGuid.PcdChip3MppSel7
+
+ gMarvellTokenSpaceGuid.PcdPciESdhci
diff --git a/Platform/Marvell/Library/ParsePcdLib/ParsePcdLib.c b/Platform/Marvell/Library/ParsePcdLib/ParsePcdLib.c
new file mode 100644
index 0000000000..9a4be8ee62
--- /dev/null
+++ b/Platform/Marvell/Library/ParsePcdLib/ParsePcdLib.c
@@ -0,0 +1,228 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must Retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+#define CHAR_NULL 0x0000
+
+#include <Library/BaseLib.h>
+#include <Uefi.h>
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+
+STATIC
+CHAR16
+CharToUpper (
+ IN CHAR16 Char
+ )
+{
+
+ if (Char >= L'a' && Char <= L'z') {
+ return (CHAR16) (Char - (L'a' - L'A'));
+ }
+
+ return Char;
+}
+
+STATIC
+BOOLEAN
+IsDecimalDigitChar (
+ IN CHAR16 Char
+ )
+{
+
+ return (BOOLEAN) (Char >= L'0' && Char <= L'9');
+}
+
+
+STATIC
+UINTN
+HexCharToUintn (
+ IN CHAR16 Char
+ )
+{
+ if (IsDecimalDigitChar (Char)) {
+ return Char - L'0';
+ }
+
+ return (UINTN) (10 + CharToUpper (Char) - L'A');
+}
+
+STATIC
+BOOLEAN
+IsHexDigitCharacter (
+ CHAR16 Char
+ )
+{
+
+ return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' &&
+ Char <= L'F') || (Char >= L'a' && Char <= L'f'));
+}
+
+STATIC
+UINTN
+HexStrToUintn (
+ CHAR16 *String
+ )
+{
+ UINTN Result = 0;
+
+ if (String == NULL || StrSize(String) == 0) {
+ return (UINTN)(-1);
+ }
+
+ // Ignore spaces and tabs
+ while ((*String == L' ') || (*String == L'\t')) {
+ String++;
+ }
+
+ // Ignore leading zeros after spaces
+ while (*String == L'0') {
+ String++;
+ }
+
+ if (CharToUpper (*String) != L'X') {
+ return (UINTN)(-1);
+ }
+
+ // Skip 'x'
+ String++;
+
+ while (IsHexDigitCharacter (*String)) {
+ Result <<= 4;
+ Result += HexCharToUintn (*String);
+ String++;
+ }
+
+ return (UINTN) Result;
+}
+
+STATIC
+UINTN
+DecimalStrToUintn (
+ CHAR16 *String
+ )
+{
+ UINTN Result = 0;
+
+ while (IsDecimalDigitChar (*String)) {
+ Result = 10 * Result + (*String - L'0');
+ String++;
+ }
+
+ return Result;
+}
+
+STATIC
+UINTN
+StrToUintn (
+ CHAR16 *String
+ )
+{
+ CHAR16 *Walker;
+
+ // Chop off leading spaces
+ for (Walker = String; Walker != NULL && *Walker != CHAR_NULL && *Walker == L' '; Walker++);
+
+ if (StrnCmp(Walker, L"0x", 2) == 0 || StrnCmp(Walker, L"0X", 2) == 0) {
+ return HexStrToUintn (Walker);
+ } else {
+ return DecimalStrToUintn (Walker);
+ }
+}
+
+EFI_STATUS
+ParsePcdString (
+ IN CHAR16 *PcdString,
+ IN UINT8 Count,
+ OUT UINTN *ValueTable,
+ OUT CHAR16 **StrTable
+ )
+{
+ BOOLEAN ValueFlag = FALSE;
+ CHAR16 *Walker;
+ UINTN i, Tmp = 0;
+
+ if (ValueTable != NULL) {
+ ValueFlag = TRUE;
+ }
+
+ // Set pointer at the end of PCD string
+ Walker = PcdString + StrLen (PcdString);
+ for (i = 0; i < Count; i++) {
+ while ((--Walker) >= PcdString) {
+ if (*Walker == L';') {
+ // Cut off parsed chunk from PCD string by replacing ';' with
+ // null-terminator
+ *Walker = '\0';
+ if (ValueFlag) {
+ Tmp = StrToUintn ((Walker + 1));
+ if ((UINTN)(-1) == Tmp) {
+ return EFI_INVALID_PARAMETER;
+ }
+ // Entry is parsed from the end to the beginning
+ // so fill table in the same manner
+ ValueTable[Count - (i + 1)] = Tmp;
+ } else {
+ StrTable[Count - (i + 1)] = Walker + 1;
+ }
+ Walker--;
+ break;
+ }
+ if (Walker == PcdString) {
+ if (ValueFlag) {
+ Tmp = StrToUintn ((Walker));
+ if (Tmp == (UINTN)(-1)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ // Last device's entry should be added to the table here.
+ // If not, return error
+ if (i != (Count - 1)) {
+ DEBUG((DEBUG_ERROR, "ParsePcdLib: Please set PCD value for every "
+ "device\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+ // We parse from the end to the beginning
+ // so fill table in the same manner
+ if (ValueFlag) {
+ ValueTable[Count - (i + 1)] = Tmp;
+ } else {
+ StrTable[Count - (i + 1)] = Walker;
+ }
+ // End both loops
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Marvell/Library/ParsePcdLib/ParsePcdLib.inf b/Platform/Marvell/Library/ParsePcdLib/ParsePcdLib.inf
new file mode 100644
index 0000000000..b4db6210f7
--- /dev/null
+++ b/Platform/Marvell/Library/ParsePcdLib/ParsePcdLib.inf
@@ -0,0 +1,50 @@
+# Copyright (C) 2016 Marvell International Ltd.
+#
+# Marvell BSD License Option
+#
+# If you received this File from Marvell, you may opt to use, redistribute and/or
+# modify this File under the following licensing terms.
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Marvell nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = ParsePcdLib
+ FILE_GUID = 698d85a0-a952-453e-b8a4-1d6ea338a38e
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = ParsePcdLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ ArmLib
+ DebugLib
+
+[Sources.common]
+ ParsePcdLib.c
diff --git a/Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.c b/Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.c
new file mode 100644
index 0000000000..95b5698909
--- /dev/null
+++ b/Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.c
@@ -0,0 +1,353 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must Retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#include "UtmiPhyLib.h"
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS UtmiBaseAddr;
+ EFI_PHYSICAL_ADDRESS UsbCfgAddr;
+ EFI_PHYSICAL_ADDRESS UtmiCfgAddr;
+ UINT32 UtmiPhyPort;
+} UTMI_PHY_DATA;
+
+STATIC
+VOID
+RegSetSilent (
+ IN EFI_PHYSICAL_ADDRESS Addr,
+ IN UINT32 Data,
+ IN UINT32 Mask
+ )
+{
+ UINT32 RegData;
+
+ RegData = MmioRead32 (Addr);
+ RegData &= ~Mask;
+ RegData |= Data;
+ MmioWrite32 (Addr, RegData);
+}
+
+STATIC
+VOID
+RegSet (
+ IN EFI_PHYSICAL_ADDRESS Addr,
+ IN UINT32 Data,
+ IN UINT32 Mask
+ )
+{
+ DEBUG((DEBUG_INFO, "Write to address = %10x, data = %10x (mask = %10x)-\n",
+ Addr, Data, Mask));
+ DEBUG((DEBUG_INFO, "old value = %10x ==>\n", MmioRead32 (Addr)));
+ RegSetSilent (Addr, Data, Mask);
+ DEBUG((DEBUG_INFO, "new value %10x\n", MmioRead32 (Addr)));
+}
+
+STATIC
+VOID
+UtmiPhyPowerDown (
+ IN UINT32 UtmiIndex,
+ IN EFI_PHYSICAL_ADDRESS UtmiBaseAddr,
+ IN EFI_PHYSICAL_ADDRESS UsbCfgAddr,
+ IN EFI_PHYSICAL_ADDRESS UtmiCfgAddr,
+ IN UINT32 UtmiPhyPort
+ )
+{
+ UINT32 Mask, Data;
+
+ DEBUG((DEBUG_INFO, "UtmiPhy: stage: UTMI %d - Power down transceiver(power down Phy)\n",
+ UtmiIndex));
+ DEBUG((DEBUG_INFO, "UtmiPhy: stage: Power down PLL, and SuspendDM\n"));
+ /* Power down UTMI PHY */
+ RegSet (UtmiCfgAddr, 0x0 << UTMI_PHY_CFG_PU_OFFSET, UTMI_PHY_CFG_PU_MASK);
+ /* Config USB3 Device UTMI enable */
+ Mask = UTMI_USB_CFG_DEVICE_EN_MASK;
+
+ /*
+ * Prior to PHY init, configure mux for Device
+ * (Device can be connected to UTMI0 or to UTMI1)
+ */
+ if (UtmiPhyPort == UTMI_PHY_TO_USB_DEVICE0) {
+ Data = 0x1 << UTMI_USB_CFG_DEVICE_EN_OFFSET;
+ /* Config USB3 Device UTMI MUX */
+ Mask |= UTMI_USB_CFG_DEVICE_MUX_MASK;
+ Data |= UtmiIndex << UTMI_USB_CFG_DEVICE_MUX_OFFSET;
+ } else {
+ Data = 0x0 << UTMI_USB_CFG_DEVICE_EN_OFFSET;
+ }
+
+ /* Set Test suspendm mode */
+ Mask = UTMI_CTRL_STATUS0_SUSPENDM_MASK;
+ Data = 0x1 << UTMI_CTRL_STATUS0_SUSPENDM_OFFSET;
+ /* Enable Test UTMI select */
+ Mask |= UTMI_CTRL_STATUS0_TEST_SEL_MASK;
+ Data |= 0x1 << UTMI_CTRL_STATUS0_TEST_SEL_OFFSET;
+ RegSet (UtmiBaseAddr + UTMI_CTRL_STATUS0_REG, Data, Mask);
+
+ /* Wait for UTMI power down */
+ MicroSecondDelay (1000);
+}
+
+STATIC
+VOID
+UtmiPhyConfig (
+ IN UINT32 UtmiIndex,
+ IN EFI_PHYSICAL_ADDRESS UtmiBaseAddr,
+ IN EFI_PHYSICAL_ADDRESS UsbCfgAddr,
+ IN EFI_PHYSICAL_ADDRESS UtmiCfgAddr,
+ IN UINT32 UtmiPhyPort
+ )
+{
+ UINT32 Mask, Data;
+
+ DEBUG((DEBUG_INFO, "UtmiPhy: stage: Configure UTMI PHY %d registers\n",
+ UtmiIndex));
+ /* Reference Clock Divider Select */
+ Mask = UTMI_PLL_CTRL_REFDIV_MASK;
+ Data = 0x5 << UTMI_PLL_CTRL_REFDIV_OFFSET;
+ /* Feedback Clock Divider Select - 90 for 25Mhz */
+ Mask |= UTMI_PLL_CTRL_FBDIV_MASK;
+ Data |= 0x60 << UTMI_PLL_CTRL_FBDIV_OFFSET;
+ /* Select LPFR - 0x0 for 25Mhz/5=5Mhz */
+ Mask |= UTMI_PLL_CTRL_SEL_LPFR_MASK;
+ Data |= 0x0 << UTMI_PLL_CTRL_SEL_LPFR_OFFSET;
+ RegSet (UtmiBaseAddr + UTMI_PLL_CTRL_REG, Data, Mask);
+
+ /* Impedance Calibration Threshold Setting */
+ RegSet (UtmiBaseAddr + UTMI_CALIB_CTRL_REG,
+ 0x6 << UTMI_CALIB_CTRL_IMPCAL_VTH_OFFSET,
+ UTMI_CALIB_CTRL_IMPCAL_VTH_MASK);
+
+ /* Set LS TX driver strength coarse control */
+ Mask = UTMI_TX_CH_CTRL_DRV_EN_LS_MASK;
+ Data = 0x3 << UTMI_TX_CH_CTRL_DRV_EN_LS_OFFSET;
+ /* Set LS TX driver fine adjustment */
+ Mask |= UTMI_TX_CH_CTRL_IMP_SEL_LS_MASK;
+ Data |= 0x3 << UTMI_TX_CH_CTRL_IMP_SEL_LS_OFFSET;
+ RegSet (UtmiBaseAddr + UTMI_TX_CH_CTRL_REG, Data, Mask);
+
+ /* Enable SQ */
+ Mask = UTMI_RX_CH_CTRL0_SQ_DET_MASK;
+ Data = 0x0 << UTMI_RX_CH_CTRL0_SQ_DET_OFFSET;
+ /* Enable analog squelch detect */
+ Mask |= UTMI_RX_CH_CTRL0_SQ_ANA_DTC_MASK;
+ Data |= 0x1 << UTMI_RX_CH_CTRL0_SQ_ANA_DTC_OFFSET;
+ RegSet (UtmiBaseAddr + UTMI_RX_CH_CTRL0_REG, Data, Mask);
+
+ /* Set External squelch calibration number */
+ Mask = UTMI_RX_CH_CTRL1_SQ_AMP_CAL_MASK;
+ Data = 0x1 << UTMI_RX_CH_CTRL1_SQ_AMP_CAL_OFFSET;
+ /* Enable the External squelch calibration */
+ Mask |= UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_MASK;
+ Data |= 0x1 << UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_OFFSET;
+ RegSet (UtmiBaseAddr + UTMI_RX_CH_CTRL1_REG, Data, Mask);
+
+ /* Set Control VDAT Reference Voltage - 0.325V */
+ Mask = UTMI_CHGDTC_CTRL_VDAT_MASK;
+ Data = 0x1 << UTMI_CHGDTC_CTRL_VDAT_OFFSET;
+ /* Set Control VSRC Reference Voltage - 0.6V */
+ Mask |= UTMI_CHGDTC_CTRL_VSRC_MASK;
+ Data |= 0x1 << UTMI_CHGDTC_CTRL_VSRC_OFFSET;
+ RegSet (UtmiBaseAddr + UTMI_CHGDTC_CTRL_REG, Data, Mask);
+}
+
+STATIC
+UINTN
+UtmiPhyPowerUp (
+ IN UINT32 UtmiIndex,
+ IN EFI_PHYSICAL_ADDRESS UtmiBaseAddr,
+ IN EFI_PHYSICAL_ADDRESS UsbCfgAddr,
+ IN EFI_PHYSICAL_ADDRESS UtmiCfgAddr,
+ IN UINT32 UtmiPhyPort
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Data;
+
+ DEBUG((DEBUG_INFO, "UtmiPhy: stage: UTMI %d - Power up transceiver(Power up Phy)\n",
+ UtmiIndex));
+ DEBUG((DEBUG_INFO, "UtmiPhy: stage: exit SuspendDM\n"));
+ /* Power up UTMI PHY */
+ RegSet (UtmiCfgAddr, 0x1 << UTMI_PHY_CFG_PU_OFFSET, UTMI_PHY_CFG_PU_MASK);
+ /* Disable Test UTMI select */
+ RegSet (UtmiBaseAddr + UTMI_CTRL_STATUS0_REG,
+ 0x0 << UTMI_CTRL_STATUS0_TEST_SEL_OFFSET,
+ UTMI_CTRL_STATUS0_TEST_SEL_MASK);
+
+ DEBUG((DEBUG_INFO, "UtmiPhy: stage: Wait for PLL and impedance calibration done, and PLL ready\n"));
+
+ /* Delay 10ms */
+ MicroSecondDelay (10000);
+
+ Data = MmioRead32 (UtmiBaseAddr + UTMI_CALIB_CTRL_REG);
+ if ((Data & UTMI_CALIB_CTRL_IMPCAL_DONE_MASK) == 0) {
+ DEBUG((DEBUG_ERROR, "UtmiPhy: Impedance calibration is not done\n"));
+ Status = EFI_D_ERROR;
+ }
+ if ((Data & UTMI_CALIB_CTRL_PLLCAL_DONE_MASK) == 0) {
+ DEBUG((DEBUG_ERROR, "UtmiPhy: PLL calibration is not done\n"));
+ Status = EFI_D_ERROR;
+ }
+ Data = MmioRead32 (UtmiBaseAddr + UTMI_PLL_CTRL_REG);
+ if ((Data & UTMI_PLL_CTRL_PLL_RDY_MASK) == 0) {
+ DEBUG((DEBUG_ERROR, "UtmiPhy: PLL is not ready\n"));
+ Status = EFI_D_ERROR;
+ }
+
+ return Status;
+}
+
+/*
+ * Cp110UtmiPhyInit initializes the UTMI PHY
+ * the init split in 3 parts:
+ * 1. Power down transceiver and PLL
+ * 2. UTMI PHY configure
+ * 3. Power up transceiver and PLL
+ */
+STATIC
+VOID
+Cp110UtmiPhyInit (
+ IN UINT32 UtmiPhyCount,
+ IN UTMI_PHY_DATA *UtmiData
+ )
+{
+ UINT32 i;
+
+ for (i = 0; i < UtmiPhyCount; i++) {
+ UtmiPhyPowerDown(i, UtmiData[i].UtmiBaseAddr,
+ UtmiData[i].UsbCfgAddr, UtmiData[i].UtmiCfgAddr,
+ UtmiData[i].UtmiPhyPort);
+ }
+
+ /* Power down PLL */
+ DEBUG((DEBUG_INFO, "UtmiPhy: stage: PHY power down PLL\n"));
+ RegSet (UtmiData[0].UsbCfgAddr, 0x0 << UTMI_USB_CFG_PLL_OFFSET,
+ UTMI_USB_CFG_PLL_MASK);
+
+ for (i = 0; i < UtmiPhyCount; i++) {
+ UtmiPhyConfig(i, UtmiData[i].UtmiBaseAddr,
+ UtmiData[i].UsbCfgAddr, UtmiData[i].UtmiCfgAddr,
+ UtmiData[i].UtmiPhyPort);
+ }
+
+ for (i = 0; i < UtmiPhyCount; i++) {
+ if (EFI_ERROR(UtmiPhyPowerUp(i, UtmiData[i].UtmiBaseAddr,
+ UtmiData[i].UsbCfgAddr, UtmiData[i].UtmiCfgAddr,
+ UtmiData[i].UtmiPhyPort))) {
+ DEBUG((DEBUG_ERROR, "UtmiPhy: Failed to initialize UTMI PHY %d\n", i));
+ continue;
+ }
+ DEBUG((DEBUG_ERROR, "UTMI PHY %d initialized to ", i));
+
+ if (UtmiData[i].UtmiPhyPort == UTMI_PHY_TO_USB_DEVICE0)
+ DEBUG((DEBUG_ERROR, "USB Device\n"));
+ else
+ DEBUG((DEBUG_ERROR, "USB Host%d\n", UtmiData[i].UtmiPhyPort));
+ }
+
+ /* Power up PLL */
+ DEBUG((DEBUG_INFO, "UtmiPhy: stage: PHY power up PLL\n"));
+ RegSet (UtmiData[0].UsbCfgAddr, 0x1 << UTMI_USB_CFG_PLL_OFFSET,
+ UTMI_USB_CFG_PLL_MASK);
+}
+
+EFI_STATUS
+UtmiPhyInit (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UTMI_PHY_DATA UtmiData[PcdGet32 (PcdUtmiPhyCount)];
+ EFI_PHYSICAL_ADDRESS RegUtmiUnit[PcdGet32 (PcdUtmiPhyCount)];
+ EFI_PHYSICAL_ADDRESS RegUsbCfg[PcdGet32 (PcdUtmiPhyCount)];
+ EFI_PHYSICAL_ADDRESS RegUtmiCfg[PcdGet32 (PcdUtmiPhyCount)];
+ UINTN UtmiPort[PcdGet32 (PcdUtmiPhyCount)];
+ UINTN i, Count;
+
+ Count = PcdGet32 (PcdUtmiPhyCount);
+ if (Count == 0) {
+ /* No UTMI PHY on platform */
+ return EFI_SUCCESS;
+ }
+
+ DEBUG((DEBUG_INFO, "UtmiPhy: Initialize USB UTMI PHYs\n"));
+ /* Parse UtmiPhy PCDs */
+ Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdUtmiPhyRegUtmiUnit),
+ Count, RegUtmiUnit, NULL);
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "UtmiPhy: Wrong PcdUtmiPhyRegUtmiUnit format\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdUtmiPhyRegUsbCfg),
+ Count, RegUsbCfg, NULL);
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "UtmiPhy: Wrong PcdUtmiPhyRegUsbCfg format\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdUtmiPhyRegUtmiCfg),
+ Count, RegUtmiCfg, NULL);
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "UtmiPhy: Wrong PcdUtmiPhyRegUtmiCfg format\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdUtmiPhyUtmiPort),
+ Count, UtmiPort, NULL);
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "UtmiPhy: Wrong PcdUtmiPhyUtmiPort format\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (i = 0 ; i < Count ; i++) {
+ /* Get base address of UTMI phy */
+ UtmiData[i].UtmiBaseAddr = RegUtmiUnit[i];
+
+ /* Get usb config address */
+ UtmiData[i].UsbCfgAddr = RegUsbCfg[i];
+
+ /* Get UTMI config address */
+ UtmiData[i].UtmiCfgAddr = RegUtmiCfg[i];
+
+ /*
+ * Get the usb port number, which will be used to check if
+ * the utmi connected to host or device
+ */
+ UtmiData[i].UtmiPhyPort = UtmiPort[i];
+ }
+
+ /* Currently only Cp110 is supported */
+ Cp110UtmiPhyInit (Count, UtmiData);
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.h b/Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.h
new file mode 100644
index 0000000000..f9b49339d0
--- /dev/null
+++ b/Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.h
@@ -0,0 +1,110 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#ifndef __UTMIPHY_H__
+#define __UTMIPHY_H__
+
+#include <Library/ArmLib.h>
+#include <Library/ArmPlatformLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/IoLib.h>
+#include <Library/TimerLib.h>
+#include <Library/ParsePcdLib.h>
+
+#define UTMI_USB_CFG_DEVICE_EN_OFFSET 0
+#define UTMI_USB_CFG_DEVICE_EN_MASK (0x1 << UTMI_USB_CFG_DEVICE_EN_OFFSET)
+#define UTMI_USB_CFG_DEVICE_MUX_OFFSET 1
+#define UTMI_USB_CFG_DEVICE_MUX_MASK (0x1 << UTMI_USB_CFG_DEVICE_MUX_OFFSET)
+#define UTMI_USB_CFG_PLL_OFFSET 25
+#define UTMI_USB_CFG_PLL_MASK (0x1 << UTMI_USB_CFG_PLL_OFFSET)
+
+#define UTMI_PHY_CFG_PU_OFFSET 5
+#define UTMI_PHY_CFG_PU_MASK (0x1 << UTMI_PHY_CFG_PU_OFFSET)
+
+#define UTMI_PLL_CTRL_REG 0x0
+#define UTMI_PLL_CTRL_REFDIV_OFFSET 0
+#define UTMI_PLL_CTRL_REFDIV_MASK (0x7f << UTMI_PLL_CTRL_REFDIV_OFFSET)
+#define UTMI_PLL_CTRL_FBDIV_OFFSET 16
+#define UTMI_PLL_CTRL_FBDIV_MASK (0x1FF << UTMI_PLL_CTRL_FBDIV_OFFSET)
+#define UTMI_PLL_CTRL_SEL_LPFR_OFFSET 28
+#define UTMI_PLL_CTRL_SEL_LPFR_MASK (0x3 << UTMI_PLL_CTRL_SEL_LPFR_OFFSET)
+#define UTMI_PLL_CTRL_PLL_RDY_OFFSET 31
+#define UTMI_PLL_CTRL_PLL_RDY_MASK (0x1 << UTMI_PLL_CTRL_PLL_RDY_OFFSET)
+
+#define UTMI_CALIB_CTRL_REG 0x8
+#define UTMI_CALIB_CTRL_IMPCAL_VTH_OFFSET 8
+#define UTMI_CALIB_CTRL_IMPCAL_VTH_MASK (0x7 << UTMI_CALIB_CTRL_IMPCAL_VTH_OFFSET)
+#define UTMI_CALIB_CTRL_IMPCAL_DONE_OFFSET 23
+#define UTMI_CALIB_CTRL_IMPCAL_DONE_MASK (0x1 << UTMI_CALIB_CTRL_IMPCAL_DONE_OFFSET)
+#define UTMI_CALIB_CTRL_PLLCAL_DONE_OFFSET 31
+#define UTMI_CALIB_CTRL_PLLCAL_DONE_MASK (0x1 << UTMI_CALIB_CTRL_PLLCAL_DONE_OFFSET)
+
+#define UTMI_TX_CH_CTRL_REG 0xC
+#define UTMI_TX_CH_CTRL_DRV_EN_LS_OFFSET 12
+#define UTMI_TX_CH_CTRL_DRV_EN_LS_MASK (0xf << UTMI_TX_CH_CTRL_DRV_EN_LS_OFFSET)
+#define UTMI_TX_CH_CTRL_IMP_SEL_LS_OFFSET 16
+#define UTMI_TX_CH_CTRL_IMP_SEL_LS_MASK (0xf << UTMI_TX_CH_CTRL_IMP_SEL_LS_OFFSET)
+
+#define UTMI_RX_CH_CTRL0_REG 0x14
+#define UTMI_RX_CH_CTRL0_SQ_DET_OFFSET 15
+#define UTMI_RX_CH_CTRL0_SQ_DET_MASK (0x1 << UTMI_RX_CH_CTRL0_SQ_DET_OFFSET)
+#define UTMI_RX_CH_CTRL0_SQ_ANA_DTC_OFFSET 28
+#define UTMI_RX_CH_CTRL0_SQ_ANA_DTC_MASK (0x1 << UTMI_RX_CH_CTRL0_SQ_ANA_DTC_OFFSET)
+
+#define UTMI_RX_CH_CTRL1_REG 0x18
+#define UTMI_RX_CH_CTRL1_SQ_AMP_CAL_OFFSET 0
+#define UTMI_RX_CH_CTRL1_SQ_AMP_CAL_MASK (0x3 << UTMI_RX_CH_CTRL1_SQ_AMP_CAL_OFFSET)
+#define UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_OFFSET 3
+#define UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_MASK (0x1 << UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_OFFSET)
+
+#define UTMI_CTRL_STATUS0_REG 0x24
+#define UTMI_CTRL_STATUS0_SUSPENDM_OFFSET 22
+#define UTMI_CTRL_STATUS0_SUSPENDM_MASK (0x1 << UTMI_CTRL_STATUS0_SUSPENDM_OFFSET)
+#define UTMI_CTRL_STATUS0_TEST_SEL_OFFSET 25
+#define UTMI_CTRL_STATUS0_TEST_SEL_MASK (0x1 << UTMI_CTRL_STATUS0_TEST_SEL_OFFSET)
+
+#define UTMI_CHGDTC_CTRL_REG 0x38
+#define UTMI_CHGDTC_CTRL_VDAT_OFFSET 8
+#define UTMI_CHGDTC_CTRL_VDAT_MASK (0x3 << UTMI_CHGDTC_CTRL_VDAT_OFFSET)
+#define UTMI_CHGDTC_CTRL_VSRC_OFFSET 10
+#define UTMI_CHGDTC_CTRL_VSRC_MASK (0x3 << UTMI_CHGDTC_CTRL_VSRC_OFFSET)
+
+#define UTMI_PHY_TO_USB_HOST0 0
+#define UTMI_PHY_TO_USB_HOST1 1
+#define UTMI_PHY_TO_USB_DEVICE0 2
+#define UTMI_PHY_INVALID 0xff
+
+#endif
diff --git a/Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.inf b/Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.inf
new file mode 100644
index 0000000000..f1e57f46f9
--- /dev/null
+++ b/Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.inf
@@ -0,0 +1,64 @@
+# Copyright (C) 2016 Marvell International Ltd.
+#
+# Marvell BSD License Option
+#
+# If you received this File from Marvell, you may opt to use, redistribute and/or
+# modify this File under the following licensing terms.
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Marvell nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+[Defines]
+ INF_VERSION = 0x00010019
+ BASE_NAME = MarvellUtmiPhyLib
+ FILE_GUID = e9adaac2-0443-4921-9367-5d575c3c91bc
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = UtmiPhyLib
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ ArmPlatformPkg/ArmPlatformPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Platform/Marvell/Marvell.dec
+
+[LibraryClasses]
+ ArmLib
+ DebugLib
+ IoLib
+ MemoryAllocationLib
+ ParsePcdLib
+ PcdLib
+
+[Sources.common]
+ UtmiPhyLib.c
+
+[FixedPcd]
+ gMarvellTokenSpaceGuid.PcdUtmiPhyCount
+ gMarvellTokenSpaceGuid.PcdUtmiPhyRegUsbCfg
+ gMarvellTokenSpaceGuid.PcdUtmiPhyRegUtmiCfg
+ gMarvellTokenSpaceGuid.PcdUtmiPhyRegUtmiUnit
+ gMarvellTokenSpaceGuid.PcdUtmiPhyUtmiPort
diff --git a/Platform/Marvell/Marvell.dec b/Platform/Marvell/Marvell.dec
new file mode 100644
index 0000000000..5cbf0c389f
--- /dev/null
+++ b/Platform/Marvell/Marvell.dec
@@ -0,0 +1,204 @@
+# Copyright (C) 2016 Marvell International Ltd.
+#
+# Marvell BSD License Option
+#
+# If you received this File from Marvell, you may opt to use, redistribute and/or
+# modify this File under the following licensing terms.
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+#* Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+#* Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+#* Neither the name of Marvell nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+[Defines]
+ DEC_SPECIFICATION = 0x00010005
+ PACKAGE_NAME = OpenPlatformMarvellPkg
+ PACKAGE_GUID = c372916e-83ad-4b2a-8410-bbc31bd9e68f
+ PACKAGE_VERSION = 0.1
+
+################################################################################
+#
+# Include Section - list of Include Paths that are provided by this package.
+# Comments are used for Keywords and Module Types.
+#
+# Supported Module Types:
+# BASE SEC PEI_CORE PEIM DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_SAL_DRIVER UEFI_DRIVER UEFI_APPLICATION
+#
+################################################################################
+
+[Includes]
+ Include
+
+[Guids.common]
+ gMarvellTokenSpaceGuid = { 0xf995c6c8, 0xbc9b, 0x4e93, { 0xbd, 0xcf, 0x49, 0x90, 0xc6, 0xe7, 0x8c, 0x7f } }
+
+ gShellEepromHiiGuid = { 0xb2f4c714, 0x147f, 0x4ff7, { 0x82, 0x1b, 0xce, 0x7b, 0x91, 0x7f, 0x5f, 0x2f } }
+ gShellFUpdateHiiGuid = { 0x9b5d2176, 0x590a, 0x49db, { 0x89, 0x5d, 0x4a, 0x70, 0xfe, 0xad, 0xbe, 0x24 } }
+ gShellSfHiiGuid = { 0x03a67756, 0x8cde, 0x4638, { 0x82, 0x34, 0x4a, 0x0f, 0x6d, 0x58, 0x81, 0x39 } }
+
+[PcdsFixedAtBuild.common]
+#MPP
+ gMarvellTokenSpaceGuid.PcdMppChipCount|0|UINT32|0x30000001
+
+ gMarvellTokenSpaceGuid.PcdChip0MppReverseFlag|FALSE|BOOLEAN|0x30000002
+ gMarvellTokenSpaceGuid.PcdChip0MppBaseAddress|0|UINT64|0x30000003
+ gMarvellTokenSpaceGuid.PcdChip0MppPinCount|0|UINT32|0x30000004
+ gMarvellTokenSpaceGuid.PcdChip0MppSel0|{ 0x0 }|VOID*|0x30000005
+ gMarvellTokenSpaceGuid.PcdChip0MppSel1|{ 0x0 }|VOID*|0x30000006
+ gMarvellTokenSpaceGuid.PcdChip0MppSel2|{ 0x0 }|VOID*|0x30000007
+ gMarvellTokenSpaceGuid.PcdChip0MppSel3|{ 0x0 }|VOID*|0x30000008
+ gMarvellTokenSpaceGuid.PcdChip0MppSel4|{ 0x0 }|VOID*|0x30000009
+ gMarvellTokenSpaceGuid.PcdChip0MppSel5|{ 0x0 }|VOID*|0x30000010
+ gMarvellTokenSpaceGuid.PcdChip0MppSel6|{ 0x0 }|VOID*|0x30000011
+ gMarvellTokenSpaceGuid.PcdChip0MppSel7|{ 0x0 }|VOID*|0x30000012
+
+ gMarvellTokenSpaceGuid.PcdChip1MppReverseFlag|FALSE|BOOLEAN|0x30000013
+ gMarvellTokenSpaceGuid.PcdChip1MppBaseAddress|0|UINT64|0x30000014
+ gMarvellTokenSpaceGuid.PcdChip1MppPinCount|0|UINT32|0x30000015
+ gMarvellTokenSpaceGuid.PcdChip1MppSel0|{ 0x0 }|VOID*|0x30000016
+ gMarvellTokenSpaceGuid.PcdChip1MppSel1|{ 0x0 }|VOID*|0x30000017
+ gMarvellTokenSpaceGuid.PcdChip1MppSel2|{ 0x0 }|VOID*|0x30000018
+ gMarvellTokenSpaceGuid.PcdChip1MppSel3|{ 0x0 }|VOID*|0x30000019
+ gMarvellTokenSpaceGuid.PcdChip1MppSel4|{ 0x0 }|VOID*|0x30000020
+ gMarvellTokenSpaceGuid.PcdChip1MppSel5|{ 0x0 }|VOID*|0x30000021
+ gMarvellTokenSpaceGuid.PcdChip1MppSel6|{ 0x0 }|VOID*|0x30000022
+ gMarvellTokenSpaceGuid.PcdChip1MppSel7|{ 0x0 }|VOID*|0x30000023
+
+ gMarvellTokenSpaceGuid.PcdChip2MppReverseFlag|FALSE|BOOLEAN|0x30000024
+ gMarvellTokenSpaceGuid.PcdChip2MppBaseAddress|0|UINT64|0x30000025
+ gMarvellTokenSpaceGuid.PcdChip2MppPinCount|0|UINT32|0x30000026
+ gMarvellTokenSpaceGuid.PcdChip2MppSel0|{ 0x0 }|VOID*|0x30000027
+ gMarvellTokenSpaceGuid.PcdChip2MppSel1|{ 0x0 }|VOID*|0x30000028
+ gMarvellTokenSpaceGuid.PcdChip2MppSel2|{ 0x0 }|VOID*|0x30000029
+ gMarvellTokenSpaceGuid.PcdChip2MppSel3|{ 0x0 }|VOID*|0x30000030
+ gMarvellTokenSpaceGuid.PcdChip2MppSel4|{ 0x0 }|VOID*|0x30000031
+ gMarvellTokenSpaceGuid.PcdChip2MppSel5|{ 0x0 }|VOID*|0x30000032
+ gMarvellTokenSpaceGuid.PcdChip2MppSel6|{ 0x0 }|VOID*|0x30000033
+ gMarvellTokenSpaceGuid.PcdChip2MppSel7|{ 0x0 }|VOID*|0x30000034
+
+ gMarvellTokenSpaceGuid.PcdChip3MppReverseFlag|FALSE|BOOLEAN|0x30000035
+ gMarvellTokenSpaceGuid.PcdChip3MppBaseAddress|0|UINT64|0x30000036
+ gMarvellTokenSpaceGuid.PcdChip3MppPinCount|0|UINT32|0x30000037
+ gMarvellTokenSpaceGuid.PcdChip3MppSel0|{ 0x0 }|VOID*|0x30000038
+ gMarvellTokenSpaceGuid.PcdChip3MppSel1|{ 0x0 }|VOID*|0x30000039
+ gMarvellTokenSpaceGuid.PcdChip3MppSel2|{ 0x0 }|VOID*|0x30000040
+ gMarvellTokenSpaceGuid.PcdChip3MppSel3|{ 0x0 }|VOID*|0x30000041
+ gMarvellTokenSpaceGuid.PcdChip3MppSel4|{ 0x0 }|VOID*|0x30000042
+ gMarvellTokenSpaceGuid.PcdChip3MppSel5|{ 0x0 }|VOID*|0x30000043
+ gMarvellTokenSpaceGuid.PcdChip3MppSel6|{ 0x0 }|VOID*|0x30000044
+ gMarvellTokenSpaceGuid.PcdChip3MppSel7|{ 0x0 }|VOID*|0x30000045
+
+#I2C
+ gMarvellTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x0 }|VOID*|0x3000046
+ gMarvellTokenSpaceGuid.PcdI2cSlaveBuses|{ 0x0 }|VOID*|0x3000184
+ gMarvellTokenSpaceGuid.PcdEepromI2cAddresses|{ 0x0 }|VOID*|0x3000050
+ gMarvellTokenSpaceGuid.PcdEepromI2cBuses|{ 0x0 }|VOID*|0x3000185
+ gMarvellTokenSpaceGuid.PcdI2cBaseAddresses|{ 0x0 }|VOID*|0x3000047
+ gMarvellTokenSpaceGuid.PcdI2cClockFrequency|0|UINT32|0x3000048
+ gMarvellTokenSpaceGuid.PcdI2cBaudRate|0|UINT32|0x3000049
+ gMarvellTokenSpaceGuid.PcdI2cBusCount|0|UINT32|0x3000183
+
+#SPI
+ gMarvellTokenSpaceGuid.PcdSpiRegBase|0|UINT32|0x3000051
+ gMarvellTokenSpaceGuid.PcdSpiMaxFrequency|0|UINT32|0x30000052
+ gMarvellTokenSpaceGuid.PcdSpiClockFrequency|0|UINT32|0x30000053
+
+ gMarvellTokenSpaceGuid.PcdSpiFlashPollCmd|0|UINT32|0x3000052
+ gMarvellTokenSpaceGuid.PcdSpiFlashAddressCycles|0|UINT32|0x3000053
+ gMarvellTokenSpaceGuid.PcdSpiFlashEraseSize|0|UINT64|0x3000054
+ gMarvellTokenSpaceGuid.PcdSpiFlashPageSize|0|UINT32|0x3000055
+ gMarvellTokenSpaceGuid.PcdSpiFlashId|0|UINT32|0x3000056
+
+#ComPhy
+ gMarvellTokenSpaceGuid.PcdComPhyDevices|{ 0x0 }|VOID*|0x30000098
+
+ #Chip0
+ gMarvellTokenSpaceGuid.PcdChip0ComPhyTypes|{ 0x0 }|VOID*|0x30000068
+ gMarvellTokenSpaceGuid.PcdChip0ComPhySpeeds|{ 0x0 }|VOID*|0x30000069
+ gMarvellTokenSpaceGuid.PcdChip0ComPhyInvFlags|{ 0x0 }|VOID*|0x30000070
+
+ #Chip1
+ gMarvellTokenSpaceGuid.PcdChip1ComPhyTypes|{ 0x0 }|VOID*|0x30000105
+ gMarvellTokenSpaceGuid.PcdChip1ComPhySpeeds|{ 0x0 }|VOID*|0x30000106
+ gMarvellTokenSpaceGuid.PcdChip1ComPhyInvFlags|{ 0x0 }|VOID*|0x30000107
+
+ #Chip2
+ gMarvellTokenSpaceGuid.PcdChip2ComPhyTypes|{ 0x0 }|VOID*|0x30000140
+ gMarvellTokenSpaceGuid.PcdChip2ComPhySpeeds|{ 0x0 }|VOID*|0x30000141
+ gMarvellTokenSpaceGuid.PcdChip2ComPhyInvFlags|{ 0x0 }|VOID*|0x30000142
+
+ #Chip3
+ gMarvellTokenSpaceGuid.PcdChip3ComPhyTypes|{ 0x0 }|VOID*|0x30000175
+ gMarvellTokenSpaceGuid.PcdChip3ComPhySpeeds|{ 0x0 }|VOID*|0x30000176
+ gMarvellTokenSpaceGuid.PcdChip3ComPhyInvFlags|{ 0x0 }|VOID*|0x30000177
+
+#UtmiPhy
+ gMarvellTokenSpaceGuid.PcdUtmiPhyCount|0|UINT32|0x30000205
+ gMarvellTokenSpaceGuid.PcdUtmiPhyRegUsbCfg|{ 0x0 }|VOID*|0x30000206
+ gMarvellTokenSpaceGuid.PcdUtmiPhyRegUtmiCfg|{ 0x0 }|VOID*|0x30000207
+ gMarvellTokenSpaceGuid.PcdUtmiPhyRegUtmiUnit|{ 0x0 }|VOID*|0x30000208
+ gMarvellTokenSpaceGuid.PcdUtmiPhyUtmiPort|{ 0x0 }|VOID*|0x30000209
+
+#MDIO
+ gMarvellTokenSpaceGuid.PcdMdioBaseAddress|0|UINT64|0x3000043
+
+#PHY
+ gMarvellTokenSpaceGuid.PcdPhyConnectionTypes|{ 0x0 }|VOID*|0x3000044
+ gMarvellTokenSpaceGuid.PcdPhyDeviceIds|{ 0x0 }|VOID*|0x3000095
+ gMarvellTokenSpaceGuid.PcdPhyStartupAutoneg|FALSE|BOOLEAN|0x3000070
+
+#NET
+ gMarvellTokenSpaceGuid.PcdPhySmiAddresses|{ 0x0 }|VOID*|0x3000024
+ gMarvellTokenSpaceGuid.PcdPp2ClockFrequency|0|UINT32|0x3000026
+ gMarvellTokenSpaceGuid.PcdPp2GmacBaseAddress|0|UINT64|0x3000027
+ gMarvellTokenSpaceGuid.PcdPp2GmacDevSize|0|UINT32|0x3000028
+ gMarvellTokenSpaceGuid.PcdPp2GopIndexes|{ 0x0 }|VOID*|0x3000029
+ gMarvellTokenSpaceGuid.PcdPp2InterfaceAlwaysUp|{ 0x0 }|VOID*|0x300002A
+ gMarvellTokenSpaceGuid.PcdPp2InterfaceSpeed|{ 0x0 }|VOID*|0x300002B
+ gMarvellTokenSpaceGuid.PcdPp2NumPorts|0|UINT32|0x300002D
+ gMarvellTokenSpaceGuid.PcdPp2PortIds|{ 0x0 }|VOID*|0x300002C
+ gMarvellTokenSpaceGuid.PcdPp2Rfu1BaseAddress|0|UINT64|0x300002E
+ gMarvellTokenSpaceGuid.PcdPp2SharedAddress|0|UINT64|0x300002F
+ gMarvellTokenSpaceGuid.PcdPp2SmiBaseAddress|0|UINT64|0x3000030
+ gMarvellTokenSpaceGuid.PcdPp2XlgBaseAddress|0|UINT64|0x3000031
+ gMarvellTokenSpaceGuid.PcdPp2XlgDevSize|0|UINT32|0x3000032
+
+#PciEmulation
+ gMarvellTokenSpaceGuid.PcdPciEXhci|{ 0x0 }|VOID*|0x3000033
+ gMarvellTokenSpaceGuid.PcdPciEAhci|{ 0x0 }|VOID*|0x3000034
+ gMarvellTokenSpaceGuid.PcdPciESdhci|{ 0x0 }|VOID*|0x3000035
+
+#ResetLib
+ gMarvellTokenSpaceGuid.PcdResetRegAddress|0|UINT64|0x40000050
+ gMarvellTokenSpaceGuid.PcdResetRegMask|0|UINT32|0x4000051
+
+#RTC
+ gMarvellTokenSpaceGuid.PcdRtcEnabled|{ 0x0 }|VOID*|0x40000052
+
+[Protocols]
+ gMarvellEepromProtocolGuid = { 0x71954bda, 0x60d3, 0x4ef8, { 0x8e, 0x3c, 0x0e, 0x33, 0x9f, 0x3b, 0xc2, 0x2b }}
+ gMarvellMdioProtocolGuid = { 0x40010b03, 0x5f08, 0x496a, { 0xa2, 0x64, 0x10, 0x5e, 0x72, 0xd3, 0x71, 0xaa }}
+ gMarvellPhyProtocolGuid = { 0x32f48a43, 0x37e3, 0x4acf, { 0x93, 0xc4, 0x3e, 0x57, 0xa7, 0xb0, 0xfb, 0xdc }}
+ gMarvellSpiMasterProtocolGuid = { 0x23de66a3, 0xf666, 0x4b3e, { 0xaa, 0xa2, 0x68, 0x9b, 0x18, 0xae, 0x2e, 0x19 }}
+ gMarvellSpiFlashProtocolGuid = { 0x9accb423, 0x5bd2, 0x4fca, { 0x9b, 0x4c, 0x2e, 0x65, 0xfc, 0x25, 0xdf, 0x21 }}
+
diff --git a/Platform/Marvell/PciEmulation/PciEmulation.c b/Platform/Marvell/PciEmulation/PciEmulation.c
new file mode 100644
index 0000000000..35f1a87d81
--- /dev/null
+++ b/Platform/Marvell/PciEmulation/PciEmulation.c
@@ -0,0 +1,195 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#include <PiDxe.h>
+
+#include <Library/DebugLib.h>
+#include <Library/MvHwDescLib.h>
+#include <Library/NonDiscoverableDeviceRegistrationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <Protocol/EmbeddedExternalDevice.h>
+
+DECLARE_A7K8K_NONDISCOVERABLE_TEMPLATE;
+
+//
+// Tables with used devices
+//
+STATIC UINT8 * CONST XhciDeviceTable = FixedPcdGetPtr (PcdPciEXhci);
+STATIC UINT8 * CONST AhciDeviceTable = FixedPcdGetPtr (PcdPciEAhci);
+STATIC UINT8 * CONST SdhciDeviceTable = FixedPcdGetPtr (PcdPciESdhci);
+
+//
+// NonDiscoverable devices registration
+//
+STATIC
+EFI_STATUS
+PciEmulationInitXhci (
+ )
+{
+ MVHW_NONDISCOVERABLE_DESC *Desc = &mA7k8kNonDiscoverableDescTemplate;
+ EFI_STATUS Status;
+ UINT8 i;
+
+ if (PcdGetSize (PcdPciEXhci) < Desc->XhciDevCount) {
+ DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEXhci format\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (i = 0; i < Desc->XhciDevCount; i++) {
+ if (!MVHW_DEV_ENABLED (Xhci, i)) {
+ continue;
+ }
+
+ Status = RegisterNonDiscoverableMmioDevice (
+ NonDiscoverableDeviceTypeXhci,
+ Desc->XhciDmaType[i],
+ NULL,
+ NULL,
+ 1,
+ Desc->XhciBaseAddresses[i], Desc->XhciMemSize[i]
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "PciEmulation: Cannot install Xhci device %d\n", i));
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+PciEmulationInitAhci (
+ )
+{
+ MVHW_NONDISCOVERABLE_DESC *Desc = &mA7k8kNonDiscoverableDescTemplate;
+ EFI_STATUS Status;
+ UINT8 i;
+
+ if (PcdGetSize (PcdPciEAhci) < Desc->AhciDevCount) {
+ DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEAhci format\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (i = 0; i < Desc->AhciDevCount; i++) {
+ if (!MVHW_DEV_ENABLED (Ahci, i)) {
+ continue;
+ }
+
+ Status = RegisterNonDiscoverableMmioDevice (
+ NonDiscoverableDeviceTypeAhci,
+ Desc->AhciDmaType[i],
+ NULL,
+ NULL,
+ 1,
+ Desc->AhciBaseAddresses[i], Desc->AhciMemSize[i]
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "PciEmulation: Cannot install Ahci device %d\n", i));
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+PciEmulationInitSdhci (
+ )
+{
+ MVHW_NONDISCOVERABLE_DESC *Desc = &mA7k8kNonDiscoverableDescTemplate;
+ EFI_STATUS Status;
+ UINT8 i;
+
+ if (PcdGetSize (PcdPciESdhci) < Desc->SdhciDevCount) {
+ DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciESdhci format\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (i = 0; i < Desc->SdhciDevCount; i++) {
+ if (!MVHW_DEV_ENABLED (Sdhci, i)) {
+ continue;
+ }
+
+ Status = RegisterNonDiscoverableMmioDevice (
+ NonDiscoverableDeviceTypeSdhci,
+ Desc->SdhciDmaType[i],
+ NULL,
+ NULL,
+ 1,
+ Desc->SdhciBaseAddresses[i], Desc->SdhciMemSize[i]
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "PciEmulation: Cannot install Sdhci device %d\n", i));
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+//
+// Entry point
+//
+EFI_STATUS
+EFIAPI
+PciEmulationEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = PciEmulationInitXhci();
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ Status = PciEmulationInitAhci();
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ Status = PciEmulationInitSdhci();
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Marvell/PciEmulation/PciEmulation.inf b/Platform/Marvell/PciEmulation/PciEmulation.inf
new file mode 100644
index 0000000000..45490ebe4c
--- /dev/null
+++ b/Platform/Marvell/PciEmulation/PciEmulation.inf
@@ -0,0 +1,61 @@
+# Copyright (C) 2016 Marvell International Ltd.
+#
+# Marvell BSD License Option
+#
+# If you received this File from Marvell, you may opt to use, redistribute and/or
+# modify this File under the following licensing terms.
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Marvell nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+[Defines]
+ INF_VERSION = 0x00010019
+ BASE_NAME = PciEmulation
+ FILE_GUID = 3dfa08da-923b-4841-9435-c77a604d7493
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = PciEmulationEntryPoint
+
+[Sources.common]
+ PciEmulation.c
+
+[Packages]
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Platform/Marvell/Marvell.dec
+
+[LibraryClasses]
+ NonDiscoverableDeviceRegistrationLib
+ UefiDriverEntryPoint
+
+[Pcd]
+ gMarvellTokenSpaceGuid.PcdPciEXhci
+ gMarvellTokenSpaceGuid.PcdPciEAhci
+ gMarvellTokenSpaceGuid.PcdPciESdhci
+
+[Depex]
+ TRUE