summaryrefslogtreecommitdiff
path: root/Silicon/Marvell
diff options
context:
space:
mode:
authorMarcin Wojtas <mw@semihalf.com>2017-12-08 15:57:31 +0100
committerArd Biesheuvel <ard.biesheuvel@linaro.org>2017-12-08 15:21:34 +0000
commita9ac0c46818954873134960d6bb304c743869327 (patch)
tree8b15278ad8bd631ed4f65daee577b7b36384fcde /Silicon/Marvell
parent993deafa1fd81b260ae28fff3db851c6b0aa9d74 (diff)
downloadedk2-platforms-a9ac0c46818954873134960d6bb304c743869327.tar.xz
Marvell: Reorganize file structure
In edk2-platforms it is expected to provide a separation between SoC and boards files in 'Silicon' and 'Platform' directories accordingly. This patch aligns Marvell code to this requirement with no functional changes in the actual source files, unless required due to modified paths. Change the supported board's files names to proper Armada70x0Db. Also rename 'Armada' directory to 'Armada7k8k' in order to properly refer to the SoC family and prevent confusion in future, when adding new Armada machines. On the occasion add ARM copyright, which was wrongly missing in the dsc.inc file. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Marcin Wojtas <mw@semihalf.com> Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Diffstat (limited to 'Silicon/Marvell')
-rw-r--r--Silicon/Marvell/Applications/EepromCmd/EepromCmd.c397
-rw-r--r--Silicon/Marvell/Applications/EepromCmd/EepromCmd.inf71
-rw-r--r--Silicon/Marvell/Applications/EepromCmd/EepromCmd.unibin0 -> 6816 bytes
-rw-r--r--Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.c398
-rw-r--r--Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.inf73
-rw-r--r--Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.unibin0 -> 5190 bytes
-rw-r--r--Silicon/Marvell/Applications/SpiTool/SpiFlashCmd.c516
-rw-r--r--Silicon/Marvell/Applications/SpiTool/SpiFlashCmd.inf77
-rw-r--r--Silicon/Marvell/Applications/SpiTool/SpiFlashCmd.unibin0 -> 7216 bytes
-rw-r--r--Silicon/Marvell/Armada7k8k/Armada7k8k.dsc.inc605
-rw-r--r--Silicon/Marvell/Armada7k8k/Drivers/Armada70x0RngDxe/Armada70x0RngDxe.c255
-rw-r--r--Silicon/Marvell/Armada7k8k/Drivers/Armada70x0RngDxe/Armada70x0RngDxe.inf47
-rw-r--r--Silicon/Marvell/Armada7k8k/Drivers/PlatInitDxe/PlatInitDxe.c45
-rw-r--r--Silicon/Marvell/Armada7k8k/Drivers/PlatInitDxe/PlatInitDxe.inf45
-rw-r--r--Silicon/Marvell/Armada7k8k/Library/Armada70x0Lib/AArch64/ArmPlatformHelper.S51
-rw-r--r--Silicon/Marvell/Armada7k8k/Library/Armada70x0Lib/ARM/ArmPlatformHelper.S77
-rw-r--r--Silicon/Marvell/Armada7k8k/Library/Armada70x0Lib/Armada70x0Lib.c132
-rw-r--r--Silicon/Marvell/Armada7k8k/Library/Armada70x0Lib/Armada70x0Lib.inf76
-rw-r--r--Silicon/Marvell/Armada7k8k/Library/Armada70x0Lib/Armada70x0LibMem.c204
-rw-r--r--Silicon/Marvell/Armada7k8k/Library/Armada70x0Lib/Armada70x0LibMem.h73
-rw-r--r--Silicon/Marvell/Armada7k8k/Library/Armada70x0MemoryInitPeiLib/Armada70x0MemoryInitPeiLib.c158
-rw-r--r--Silicon/Marvell/Armada7k8k/Library/Armada70x0MemoryInitPeiLib/Armada70x0MemoryInitPeiLib.inf46
-rw-r--r--Silicon/Marvell/Armada7k8k/Library/RealTimeClockLib/RealTimeClockLib.c335
-rw-r--r--Silicon/Marvell/Armada7k8k/Library/RealTimeClockLib/RealTimeClockLib.h50
-rw-r--r--Silicon/Marvell/Armada7k8k/Library/RealTimeClockLib/RealTimeClockLib.inf52
-rw-r--r--Silicon/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.c292
-rw-r--r--Silicon/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.h103
-rw-r--r--Silicon/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.inf70
-rwxr-xr-xSilicon/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.c762
-rw-r--r--Silicon/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.h269
-rwxr-xr-xSilicon/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf74
-rw-r--r--Silicon/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.c252
-rw-r--r--Silicon/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.h57
-rw-r--r--Silicon/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.inf66
-rw-r--r--Silicon/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.c460
-rw-r--r--Silicon/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.h100
-rw-r--r--Silicon/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.inf73
-rw-r--r--Silicon/Marvell/Drivers/Net/Pp2Dxe/Mvpp2Lib.c5023
-rw-r--r--Silicon/Marvell/Drivers/Net/Pp2Dxe/Mvpp2Lib.h762
-rw-r--r--Silicon/Marvell/Drivers/Net/Pp2Dxe/Mvpp2LibHw.h2015
-rw-r--r--Silicon/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.c1396
-rw-r--r--Silicon/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.h622
-rw-r--r--Silicon/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.inf84
-rw-r--r--Silicon/Marvell/Drivers/SdMmc/XenonDxe/ComponentName.c211
-rwxr-xr-xSilicon/Marvell/Drivers/SdMmc/XenonDxe/EmmcDevice.c1164
-rw-r--r--Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdDevice.c1190
-rw-r--r--Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.c1320
-rw-r--r--Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.h791
-rw-r--r--Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.inf64
-rw-r--r--Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.uni23
-rw-r--r--Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxeExtra.uni19
-rw-r--r--Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHci.c1928
-rw-r--r--Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHci.h550
-rwxr-xr-xSilicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.c649
-rw-r--r--Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.h346
-rwxr-xr-xSilicon/Marvell/Drivers/Spi/Devices/MvSpiFlash.c599
-rwxr-xr-xSilicon/Marvell/Drivers/Spi/Devices/MvSpiFlash.h138
-rw-r--r--Silicon/Marvell/Drivers/Spi/Devices/MvSpiFlash.inf70
-rwxr-xr-xSilicon/Marvell/Drivers/Spi/MvSpiDxe.c432
-rw-r--r--Silicon/Marvell/Drivers/Spi/MvSpiDxe.h148
-rw-r--r--Silicon/Marvell/Drivers/Spi/MvSpiDxe.inf73
-rw-r--r--Silicon/Marvell/Drivers/Spi/Variables/MvFvbDxe.c1138
-rw-r--r--Silicon/Marvell/Drivers/Spi/Variables/MvFvbDxe.h128
-rw-r--r--Silicon/Marvell/Drivers/Spi/Variables/MvFvbDxe.inf91
-rw-r--r--Silicon/Marvell/Include/Library/MppLib.h42
-rw-r--r--Silicon/Marvell/Include/Library/MvComPhyLib.h48
-rw-r--r--Silicon/Marvell/Include/Library/MvHwDescLib.h290
-rw-r--r--Silicon/Marvell/Include/Library/UtmiPhyLib.h43
-rw-r--r--Silicon/Marvell/Include/Protocol/Eeprom.h60
-rw-r--r--Silicon/Marvell/Include/Protocol/Mdio.h72
-rw-r--r--Silicon/Marvell/Include/Protocol/MvPhy.h105
-rw-r--r--Silicon/Marvell/Include/Protocol/Spi.h119
-rw-r--r--Silicon/Marvell/Include/Protocol/SpiFlash.h101
-rwxr-xr-xSilicon/Marvell/Library/ComPhyLib/ComPhyCp110.c1853
-rw-r--r--Silicon/Marvell/Library/ComPhyLib/ComPhyLib.c278
-rw-r--r--Silicon/Marvell/Library/ComPhyLib/ComPhyLib.h638
-rw-r--r--Silicon/Marvell/Library/ComPhyLib/ComPhyLib.inf83
-rw-r--r--Silicon/Marvell/Library/ComPhyLib/ComPhyMux.c132
-rw-r--r--Silicon/Marvell/Library/MppLib/MppLib.c217
-rw-r--r--Silicon/Marvell/Library/MppLib/MppLib.inf111
-rw-r--r--Silicon/Marvell/Library/UtmiPhyLib/UtmiPhyLib.c354
-rw-r--r--Silicon/Marvell/Library/UtmiPhyLib/UtmiPhyLib.h109
-rw-r--r--Silicon/Marvell/Library/UtmiPhyLib/UtmiPhyLib.inf61
-rw-r--r--Silicon/Marvell/Marvell.dec212
-rw-r--r--Silicon/Marvell/PciEmulation/PciEmulation.c195
-rw-r--r--Silicon/Marvell/PciEmulation/PciEmulation.inf61
86 files changed, 32519 insertions, 0 deletions
diff --git a/Silicon/Marvell/Applications/EepromCmd/EepromCmd.c b/Silicon/Marvell/Applications/EepromCmd/EepromCmd.c
new file mode 100644
index 0000000000..f43e411067
--- /dev/null
+++ b/Silicon/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/Silicon/Marvell/Applications/EepromCmd/EepromCmd.inf b/Silicon/Marvell/Applications/EepromCmd/EepromCmd.inf
new file mode 100644
index 0000000000..c86ead1b7d
--- /dev/null
+++ b/Silicon/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
+ Silicon/Marvell/Marvell.dec
+
+[LibraryClasses]
+ UefiLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ ShellCommandLib
+ ShellLib
+ UefiLib
+ UefiRuntimeServicesTableLib
+ PcdLib
+
+[Protocols]
+ gMarvellEepromProtocolGuid
+ gEfiI2cMasterProtocolGuid
+
+[Guids]
+ gShellEepromHiiGuid
diff --git a/Silicon/Marvell/Applications/EepromCmd/EepromCmd.uni b/Silicon/Marvell/Applications/EepromCmd/EepromCmd.uni
new file mode 100644
index 0000000000..e41c6d812e
--- /dev/null
+++ b/Silicon/Marvell/Applications/EepromCmd/EepromCmd.uni
Binary files differ
diff --git a/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.c b/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.c
new file mode 100644
index 0000000000..9ccb1c749b
--- /dev/null
+++ b/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.c
@@ -0,0 +1,398 @@
+/*******************************************************************************
+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;
+
+ // Read SPI flash ID
+ Status = SpiFlashProtocol->ReadId (Slave, FALSE);
+ if (EFI_ERROR (Status)) {
+ return SHELL_ABORTED;
+ }
+
+ 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 UINT64 *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, (UINTN *)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 = NULL;
+ UINT64 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, Slave, 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/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.inf b/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.inf
new file mode 100644
index 0000000000..69ee0f8308
--- /dev/null
+++ b/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.inf
@@ -0,0 +1,73 @@
+#
+# 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]
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/Marvell/Marvell.dec
+ ShellPkg/ShellPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ FileHandleLib
+ HiiLib
+ MemoryAllocationLib
+ PcdLib
+ ShellCommandLib
+ ShellLib
+ UefiBootServicesTableLib
+ UefiLib
+ UefiLib
+ UefiRuntimeServicesTableLib
+
+[Protocols]
+ gMarvellSpiFlashProtocolGuid
+ gMarvellSpiMasterProtocolGuid
+
+[Guids]
+ gShellFUpdateHiiGuid
diff --git a/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.uni b/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.uni
new file mode 100644
index 0000000000..146f624737
--- /dev/null
+++ b/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.uni
Binary files differ
diff --git a/Silicon/Marvell/Applications/SpiTool/SpiFlashCmd.c b/Silicon/Marvell/Applications/SpiTool/SpiFlashCmd.c
new file mode 100644
index 0000000000..cf91581dcf
--- /dev/null
+++ b/Silicon/Marvell/Applications/SpiTool/SpiFlashCmd.c
@@ -0,0 +1,516 @@
+/*******************************************************************************
+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 SPI_DEVICE *mSlave;
+
+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;
+
+ Status = SpiFlashProtocol->ReadId (Slave, FALSE);
+ if (EFI_ERROR (Status)) {
+ return SHELL_ABORTED;
+ }
+
+ Status = SpiFlashProtocol->Init (SpiFlashProtocol, Slave);
+ if (EFI_ERROR (Status)) {
+ Print (L"sf: Cannot initialize flash device\n");
+ return SHELL_ABORTED;
+ }
+
+ InitFlag = 0;
+
+ return SHELL_SUCCESS;
+}
+
+SHELL_STATUS
+EFIAPI
+ShellCommandRunSpiFlash (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+EFI_STATUS Status;
+ LIST_ENTRY *CheckPackage;
+ EFI_PHYSICAL_ADDRESS Address = 0, Offset = 0;
+ SHELL_FILE_HANDLE FileHandle = NULL;
+ UINTN ByteCount, I;
+ UINT64 FileSize;
+ 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;
+ UINT8 Mode, Cs;
+
+ 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;
+ }
+ }
+
+ Mode = PcdGet32 (PcdSpiFlashMode);
+ Cs = PcdGet32 (PcdSpiFlashCs);
+
+ // Setup new spi device
+ mSlave = SpiMasterProtocol->SetupDevice (SpiMasterProtocol, mSlave, Cs, Mode);
+ if (mSlave == NULL) {
+ Print(L"sf: Cannot allocate SPI device!\n");
+ return SHELL_ABORTED;
+ }
+
+ switch (Flag) {
+ case PROBE:
+ // Probe spi bus
+ Status = FlashProbe (mSlave);
+ if (EFI_ERROR(Status)) {
+ // No supported spi flash detected
+ SpiMasterProtocol->FreeDevice(mSlave);
+ mSlave = NULL;
+ 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 *)(UINTN)Address;
+ if (FileFlag) {
+ Buffer = FileBuffer;
+ }
+
+ switch (Flag) {
+ case READ:
+ case READ_FILE:
+ Status = SpiFlashProtocol->Read (mSlave, Offset, ByteCount, Buffer);
+ break;
+ case ERASE:
+ Status = SpiFlashProtocol->Erase (mSlave, Offset, ByteCount);
+ break;
+ case WRITE:
+ case WRITE_FILE:
+ Status = SpiFlashProtocol->Write (mSlave, Offset, ByteCount, Buffer);
+ break;
+ case UPDATE:
+ case UPDATE_FILE:
+ Status = SpiFlashProtocol->Update (mSlave, Offset, ByteCount, Buffer);
+ break;
+ }
+
+ 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/Silicon/Marvell/Applications/SpiTool/SpiFlashCmd.inf b/Silicon/Marvell/Applications/SpiTool/SpiFlashCmd.inf
new file mode 100644
index 0000000000..647ab506b3
--- /dev/null
+++ b/Silicon/Marvell/Applications/SpiTool/SpiFlashCmd.inf
@@ -0,0 +1,77 @@
+#
+# 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]
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdePkg/MdePkg.dec
+ ShellPkg/ShellPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ Silicon/Marvell/Marvell.dec
+
+[LibraryClasses]
+ UefiLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ ShellCommandLib
+ ShellLib
+ UefiLib
+ UefiRuntimeServicesTableLib
+ PcdLib
+ HiiLib
+ FileHandleLib
+
+[Pcd]
+ gMarvellTokenSpaceGuid.PcdSpiFlashCs
+ gMarvellTokenSpaceGuid.PcdSpiFlashMode
+
+[Protocols]
+ gMarvellSpiFlashProtocolGuid
+ gMarvellSpiMasterProtocolGuid
+
+[Guids]
+ gShellSfHiiGuid
diff --git a/Silicon/Marvell/Applications/SpiTool/SpiFlashCmd.uni b/Silicon/Marvell/Applications/SpiTool/SpiFlashCmd.uni
new file mode 100644
index 0000000000..3f25663ed7
--- /dev/null
+++ b/Silicon/Marvell/Applications/SpiTool/SpiFlashCmd.uni
Binary files differ
diff --git a/Silicon/Marvell/Armada7k8k/Armada7k8k.dsc.inc b/Silicon/Marvell/Armada7k8k/Armada7k8k.dsc.inc
new file mode 100644
index 0000000000..75717e915b
--- /dev/null
+++ b/Silicon/Marvell/Armada7k8k/Armada7k8k.dsc.inc
@@ -0,0 +1,605 @@
+#
+#Copyright (c) 2011-2012, ARM Limited. All rights reserved.
+#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|Silicon/Marvell/Armada7k8k/Library/Armada70x0Lib/Armada70x0Lib.inf
+ ComPhyLib|Silicon/Marvell/Library/ComPhyLib/ComPhyLib.inf
+ MppLib|Silicon/Marvell/Library/MppLib/MppLib.inf
+ NorFlashInfoLib|EmbeddedPkg/Library/NorFlashInfoLib/NorFlashInfoLib.inf
+ UtmiPhyLib|Silicon/Marvell/Library/UtmiPhyLib/UtmiPhyLib.inf
+
+ DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.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
+
+ PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.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|EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.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|Silicon/Marvell/Armada7k8k/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
+
+ #
+ # 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
+ BootLogoLib|MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf
+ FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf
+ PlatformBootManagerLib|ArmPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
+ CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
+ FdtLib|EmbeddedPkg/Library/FdtLib/FdtLib.inf
+
+ 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
+ PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+
+[LibraryClasses.common.SEC, LibraryClasses.common.PEIM]
+ MemoryInitPeiLib|Silicon/Marvell/Armada7k8k/Library/Armada70x0MemoryInitPeiLib/Armada70x0MemoryInitPeiLib.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]
+
+ #
+ # 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()"
+
+ gEfiMdePkgTokenSpaceGuid.PcdMaximumUnicodeStringLength|1000000
+ gEfiMdePkgTokenSpaceGuid.PcdMaximumAsciiStringLength|1000000
+ gEfiMdePkgTokenSpaceGuid.PcdMaximumLinkedListLength|1000000
+ gEfiMdePkgTokenSpaceGuid.PcdSpinLockTimeout|10000000
+ gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue|0xAF
+ 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
+
+ #
+ # NOTE: the GIC architecture mandates that the CPU interface, which consists
+ # of 2 consecutive 4 KB frames, can be mapped using separate mappings.
+ # Since this is problematic on 64 KB pages, the MMU-400 aliases each frame
+ # 16 times, and the two consecutive frames can be found at offset 0xf000
+ #
+ gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase|0xF022F000
+
+ # ARM Architectural Timer Support
+ gArmTokenSpaceGuid.PcdArmArchTimerFreqInHz|25000000
+ gEmbeddedTokenSpaceGuid.PcdMetronomeTickPeriod|1000
+
+ # ARM SBSA Watchdog
+ gArmTokenSpaceGuid.PcdGenericWatchdogControlBase|0xF0610000
+ 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|1000
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesCode|1000
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesCode|2000
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesData|35000
+ 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
+
+ # GUID of the generic BDS UiApp
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBootManagerMenuFile|{ 0x21, 0xaa, 0x2c, 0x46, 0x14, 0x76, 0x03, 0x45, 0x83, 0x6e, 0x8a, 0xb6, 0xf4, 0x66, 0x23, 0x31 }
+
+ # use the 'TTYTERM' terminal type for optimal compatibility with Linux terminal emulators
+ gEfiMdePkgTokenSpaceGuid.PcdDefaultTerminalType|4
+
+ # ARM Pcds
+ gArmTokenSpaceGuid.PcdSystemMemoryBase|0
+ gArmTokenSpaceGuid.PcdSystemMemorySize|0x40000000
+ gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize|36
+
+ # Secure region reservation
+ gMarvellTokenSpaceGuid.PcdSecureRegionBase|0x4000000
+ gMarvellTokenSpaceGuid.PcdSecureRegionSize|0x0200000
+
+ # TRNG
+ gMarvellTokenSpaceGuid.PcdEip76TrngBaseAddress|0xF2760000
+
+ #
+ # Variable store - default values
+ #
+ gMarvellTokenSpaceGuid.PcdSpiMemoryBase|0xF9000000
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase|0xF93C0000
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize|0x00010000
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase|0xF93D0000
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize|0x00010000
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase|0xF93E0000
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize|0x00010000
+
+################################################################################
+#
+# Components Section - list of all EDK II Modules needed by this Platform
+#
+################################################################################
+[Components.common]
+
+ # PEI Phase modules
+ ArmPlatformPkg/PrePi/PeiUniCore.inf
+
+ # DXE
+ MdeModulePkg/Core/Dxe/DxeMain.inf {
+ <LibraryClasses>
+ NULL|MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.inf
+ }
+
+ MdeModulePkg/Universal/PCD/Dxe/Pcd.inf {
+ <LibraryClasses>
+ PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.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 Initialization
+ Silicon/Marvell/Armada7k8k/Drivers/PlatInitDxe/PlatInitDxe.inf
+
+ # Platform drivers
+ Silicon/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf
+ MdeModulePkg/Bus/I2c/I2cDxe/I2cDxe.inf
+ Silicon/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.inf
+ Silicon/Marvell/Drivers/Spi/MvSpiDxe.inf
+ Silicon/Marvell/Drivers/Spi/Devices/MvSpiFlash.inf
+ Silicon/Marvell/Armada7k8k/Drivers/Armada70x0RngDxe/Armada70x0RngDxe.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
+ MdeModulePkg/Universal/Network/UefiPxeBcDxe/UefiPxeBcDxe.inf
+ Silicon/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.inf
+ Silicon/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.inf
+ Silicon/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.inf
+
+ MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
+ MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
+ MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
+
+ EmbeddedPkg/EmbeddedMonotonicCounter/EmbeddedMonotonicCounter.inf
+ MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf
+ EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClockRuntimeDxe.inf
+ EmbeddedPkg/MetronomeDxe/MetronomeDxe.inf
+
+ # PciEmulation
+ Silicon/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
+ Silicon/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
+ MdeModulePkg/Universal/BdsDxe/BdsDxe.inf
+ MdeModulePkg/Application/UiApp/UiApp.inf {
+ <LibraryClasses>
+ NULL|MdeModulePkg/Library/DeviceManagerUiLib/DeviceManagerUiLib.inf
+ NULL|MdeModulePkg/Library/BootManagerUiLib/BootManagerUiLib.inf
+ NULL|MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerUiLib.inf
+ }
+
+ #
+ # Variable services
+ #
+ Silicon/Marvell/Drivers/Spi/Variables/MvFvbDxe.inf
+ MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
+ MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf {
+ <LibraryClasses>
+ AuthVariableLib|MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf
+ NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
+ TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
+ VarCheckLib|MdeModulePkg/Library/VarCheckLib/VarCheckLib.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|Silicon/Marvell/Applications/EepromCmd/EepromCmd.inf
+ NULL|Silicon/Marvell/Applications/SpiTool/SpiFlashCmd.inf
+ NULL|Silicon/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
+ }
+
+!ifdef $(INCLUDE_TFTP_COMMAND)
+ ShellPkg/DynamicCommand/TftpDynamicCommand/TftpDynamicCommand.inf
+!endif #$(INCLUDE_TFTP_COMMAND)
+
+[BuildOptions.common.EDKII.DXE_CORE,BuildOptions.common.EDKII.DXE_DRIVER,BuildOptions.common.EDKII.UEFI_DRIVER,BuildOptions.common.EDKII.UEFI_APPLICATION]
+ GCC:*_*_*_DLINK_FLAGS = -z common-page-size=0x1000
+
+[BuildOptions.common.EDKII.DXE_RUNTIME_DRIVER]
+ GCC:*_*_*_DLINK_FLAGS = -z common-page-size=0x10000
+
+################################################################################
+#
+# Defines - platform description macros
+#
+################################################################################
+[Defines]
+ # ComPhy speed
+ DEFINE CP_1_25G = 0x1
+ DEFINE CP_1_5G = 0x2
+ DEFINE CP_2_5G = 0x3
+ DEFINE CP_3G = 0x4
+ DEFINE CP_3_125G = 0x5
+ DEFINE CP_5G = 0x6
+ DEFINE CP_5_15625G = 0x7
+ DEFINE CP_6G = 0x8
+ DEFINE CP_6_25G = 0x9
+ DEFINE CP_10_3125G = 0xA
+
+ # ComPhy type
+ DEFINE CP_UNCONNECTED = 0x0
+ DEFINE CP_PCIE0 = 0x1
+ DEFINE CP_PCIE1 = 0x2
+ DEFINE CP_PCIE2 = 0x3
+ DEFINE CP_PCIE3 = 0x4
+ DEFINE CP_SATA0 = 0x5
+ DEFINE CP_SATA1 = 0x6
+ DEFINE CP_SATA2 = 0x7
+ DEFINE CP_SATA3 = 0x8
+ DEFINE CP_SGMII0 = 0x9
+ DEFINE CP_SGMII1 = 0xA
+ DEFINE CP_SGMII2 = 0xB
+ DEFINE CP_SGMII3 = 0xC
+ DEFINE CP_QSGMII = 0xD
+ DEFINE CP_USB3_HOST0 = 0xE
+ DEFINE CP_USB3_HOST1 = 0xF
+ DEFINE CP_USB3_DEVICE = 0x10
+ DEFINE CP_XAUI0 = 0x11
+ DEFINE CP_XAUI1 = 0x12
+ DEFINE CP_XAUI2 = 0x13
+ DEFINE CP_XAUI3 = 0x14
+ DEFINE CP_RXAUI0 = 0x15
+ DEFINE CP_RXAUI1 = 0x16
+ DEFINE CP_SFI = 0x17
+
+ #Network interface speed
+ DEFINE PHY_SPEED_10 = 0x1
+ DEFINE PHY_SPEED_100 = 0x2
+ DEFINE PHY_SPEED_1000 = 0x3
+ DEFINE PHY_SPEED_2500 = 0x4
+ DEFINE PHY_SPEED_10000 = 0x5
+
+ #Network PHY type
+ DEFINE PHY_RGMII = 0x0
+ DEFINE PHY_RGMII_ID = 0x1
+ DEFINE PHY_RGMII_TXID = 0x2
+ DEFINE PHY_RGMII_RXID = 0x3
+ DEFINE PHY_SGMII = 0x4
+ DEFINE PHY_RTBI = 0x5
+ DEFINE PHY_XAUI = 0x6
+ DEFINE PHY_RXAUI = 0x7
+ DEFINE PHY_SFI = 0x8
+
+ #UTMI PHY connection type
+ DEFINE UTMI_USB_HOST0 = 0x0
+ DEFINE UTMI_USB_HOST1 = 0x1
+ DEFINE UTMI_USB_DEVICE0 = 0x2
diff --git a/Silicon/Marvell/Armada7k8k/Drivers/Armada70x0RngDxe/Armada70x0RngDxe.c b/Silicon/Marvell/Armada7k8k/Drivers/Armada70x0RngDxe/Armada70x0RngDxe.c
new file mode 100644
index 0000000000..014443d130
--- /dev/null
+++ b/Silicon/Marvell/Armada7k8k/Drivers/Armada70x0RngDxe/Armada70x0RngDxe.c
@@ -0,0 +1,255 @@
+/** @file
+
+ This driver produces an EFI_RNG_PROTOCOL instance for the Armada 70x0 TRNG
+
+ Copyright (C) 2017, Linaro 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.
+
+**/
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <Protocol/Rng.h>
+
+#define TRNG_OUTPUT_REG mTrngBaseAddress
+#define TRNG_OUTPUT_SIZE 0x10
+
+#define TRNG_STATUS_REG (mTrngBaseAddress + 0x10)
+#define TRNG_STATUS_READY BIT0
+
+#define TRNG_INTACK_REG (mTrngBaseAddress + 0x10)
+#define TRNG_INTACK_READY BIT0
+
+#define TRNG_CONTROL_REG (mTrngBaseAddress + 0x14)
+#define TRNG_CONTROL_REG_ENABLE BIT10
+
+#define TRNG_CONFIG_REG (mTrngBaseAddress + 0x18)
+#define __MIN_REFILL_SHIFT 0
+#define __MAX_REFILL_SHIFT 16
+#define TRNG_CONFIG_MIN_REFILL_CYCLES (0x05 << __MIN_REFILL_SHIFT)
+#define TRNG_CONFIG_MAX_REFILL_CYCLES (0x22 << __MAX_REFILL_SHIFT)
+
+#define TRNG_FRODETUNE_REG (mTrngBaseAddress + 0x24)
+#define TRNG_FRODETUNE_MASK 0x0
+
+#define TRNG_FROENABLE_REG (mTrngBaseAddress + 0x20)
+#define TRNG_FROENABLE_MASK 0xffffff
+
+#define TRNG_MAX_RETRIES 20
+
+STATIC EFI_PHYSICAL_ADDRESS mTrngBaseAddress;
+
+/**
+ Returns information about the random number generation implementation.
+
+ @param[in] This A pointer to the EFI_RNG_PROTOCOL
+ instance.
+ @param[in,out] RNGAlgorithmListSize On input, the size in bytes of
+ RNGAlgorithmList.
+ On output with a return code of
+ EFI_SUCCESS, the size in bytes of the
+ data returned in RNGAlgorithmList. On
+ output with a return code of
+ EFI_BUFFER_TOO_SMALL, the size of
+ RNGAlgorithmList required to obtain the
+ list.
+ @param[out] RNGAlgorithmList A caller-allocated memory buffer filled
+ by the driver with one EFI_RNG_ALGORITHM
+ element for each supported RNG algorithm.
+ The list must not change across multiple
+ calls to the same driver. The first
+ algorithm in the list is the default
+ algorithm for the driver.
+
+ @retval EFI_SUCCESS The RNG algorithm list was returned
+ successfully.
+ @retval EFI_UNSUPPORTED The services is not supported by this
+ driver.
+ @retval EFI_DEVICE_ERROR The list of algorithms could not be
+ retrieved due to a hardware or firmware
+ error.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters are
+ incorrect.
+ @retval EFI_BUFFER_TOO_SMALL The buffer RNGAlgorithmList is too small
+ to hold the result.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+Armada70x0RngGetInfo (
+ IN EFI_RNG_PROTOCOL *This,
+ IN OUT UINTN *RNGAlgorithmListSize,
+ OUT EFI_RNG_ALGORITHM *RNGAlgorithmList
+ )
+{
+ if (This == NULL || RNGAlgorithmListSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*RNGAlgorithmListSize < sizeof (EFI_RNG_ALGORITHM)) {
+ *RNGAlgorithmListSize = sizeof (EFI_RNG_ALGORITHM);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ if (RNGAlgorithmList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *RNGAlgorithmListSize = sizeof (EFI_RNG_ALGORITHM);
+ CopyGuid (RNGAlgorithmList, &gEfiRngAlgorithmRaw);
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+GetTrngData (
+ IN UINTN Length,
+ OUT UINT8 *Bits
+ )
+{
+ UINTN Tries;
+ UINT32 Buf[TRNG_OUTPUT_SIZE / sizeof (UINT32)];
+ UINTN Index;
+
+ for (Tries = 0; Tries < TRNG_MAX_RETRIES; Tries++) {
+ if (MmioRead32 (TRNG_STATUS_REG) & TRNG_STATUS_READY) {
+ for (Index = 0; Index < ARRAY_SIZE (Buf); Index++) {
+ Buf[Index] = MmioRead32 (TRNG_OUTPUT_REG + Index * sizeof (UINT32));
+ }
+ CopyMem (Bits, Buf, Length);
+ MmioWrite32 (TRNG_INTACK_REG, TRNG_INTACK_READY);
+
+ return EFI_SUCCESS;
+ }
+ // Wait for more TRNG data to arrive
+ gBS->Stall (10);
+ }
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+ Produces and returns an RNG value using either the default or specified RNG
+ algorithm.
+
+ @param[in] This A pointer to the EFI_RNG_PROTOCOL
+ instance.
+ @param[in] RNGAlgorithm A pointer to the EFI_RNG_ALGORITHM that
+ identifies the RNG algorithm to use. May
+ be NULL in which case the function will
+ use its default RNG algorithm.
+ @param[in] RNGValueLength The length in bytes of the memory buffer
+ pointed to by RNGValue. The driver shall
+ return exactly this numbers of bytes.
+ @param[out] RNGValue A caller-allocated memory buffer filled
+ by the driver with the resulting RNG
+ value.
+
+ @retval EFI_SUCCESS The RNG value was returned successfully.
+ @retval EFI_UNSUPPORTED The algorithm specified by RNGAlgorithm
+ is not supported by this driver.
+ @retval EFI_DEVICE_ERROR An RNG value could not be retrieved due
+ to a hardware or firmware error.
+ @retval EFI_NOT_READY There is not enough random data available
+ to satisfy the length requested by
+ RNGValueLength.
+ @retval EFI_INVALID_PARAMETER RNGValue is NULL or RNGValueLength is
+ zero.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+Armada70x0RngGetRNG (
+ IN EFI_RNG_PROTOCOL *This,
+ IN EFI_RNG_ALGORITHM *RNGAlgorithm, OPTIONAL
+ IN UINTN RNGValueLength,
+ OUT UINT8 *RNGValue
+ )
+{
+ UINTN Length;
+ EFI_STATUS Status;
+
+ if (This == NULL || RNGValueLength == 0 || RNGValue == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // We only support the raw algorithm, so reject requests for anything else
+ //
+ if (RNGAlgorithm != NULL &&
+ !CompareGuid (RNGAlgorithm, &gEfiRngAlgorithmRaw)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ do {
+ Length = MIN (RNGValueLength, TRNG_OUTPUT_SIZE);
+ Status = GetTrngData (Length, RNGValue);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ RNGValue += Length;
+ RNGValueLength -= Length;
+ } while (RNGValueLength > 0);
+
+ return EFI_SUCCESS;
+}
+
+STATIC EFI_RNG_PROTOCOL mArmada70x0RngProtocol = {
+ Armada70x0RngGetInfo,
+ Armada70x0RngGetRNG
+};
+
+//
+// Entry point of this driver.
+//
+EFI_STATUS
+EFIAPI
+Armada70x0RngDxeEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ mTrngBaseAddress = PcdGet64 (PcdEip76TrngBaseAddress);
+
+ //
+ // Disable the TRNG before updating its configuration
+ //
+ MmioAnd32 (TRNG_CONTROL_REG, ~TRNG_CONTROL_REG_ENABLE);
+
+ //
+ // Configure the internal conditioning parameters of the TRNG
+ //
+ MmioWrite32 (TRNG_CONFIG_REG, TRNG_CONFIG_MIN_REFILL_CYCLES |
+ TRNG_CONFIG_MAX_REFILL_CYCLES);
+
+ //
+ // Configure the FROs
+ //
+ MmioWrite32 (TRNG_FRODETUNE_REG, TRNG_FRODETUNE_MASK);
+ MmioWrite32 (TRNG_FROENABLE_REG, TRNG_FROENABLE_MASK);
+
+ //
+ // Enable the TRNG
+ //
+ MmioOr32 (TRNG_CONTROL_REG, TRNG_CONTROL_REG_ENABLE);
+
+ return SystemTable->BootServices->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiRngProtocolGuid,
+ &mArmada70x0RngProtocol,
+ NULL
+ );
+}
diff --git a/Silicon/Marvell/Armada7k8k/Drivers/Armada70x0RngDxe/Armada70x0RngDxe.inf b/Silicon/Marvell/Armada7k8k/Drivers/Armada70x0RngDxe/Armada70x0RngDxe.inf
new file mode 100644
index 0000000000..3d74c8e965
--- /dev/null
+++ b/Silicon/Marvell/Armada7k8k/Drivers/Armada70x0RngDxe/Armada70x0RngDxe.inf
@@ -0,0 +1,47 @@
+## @file
+# This driver produces an EFI_RNG_PROTOCOL instance for the Armada 70x0 TRNG
+#
+# Copyright (C) 2017, Linaro 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 = Armada70x0RngDxe
+ FILE_GUID = dd87096a-cae5-4328-bec1-2ddb755f2e08
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = Armada70x0RngDxeEntryPoint
+
+[Sources]
+ Armada70x0RngDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ Silicon/Marvell/Marvell.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ IoLib
+ PcdLib
+ UefiDriverEntryPoint
+
+[Pcd]
+ gMarvellTokenSpaceGuid.PcdEip76TrngBaseAddress
+
+[Protocols]
+ gEfiRngProtocolGuid ## PRODUCES
+
+[Guids]
+ gEfiRngAlgorithmRaw
+
+[Depex]
+ TRUE
diff --git a/Silicon/Marvell/Armada7k8k/Drivers/PlatInitDxe/PlatInitDxe.c b/Silicon/Marvell/Armada7k8k/Drivers/PlatInitDxe/PlatInitDxe.c
new file mode 100644
index 0000000000..1efad77854
--- /dev/null
+++ b/Silicon/Marvell/Armada7k8k/Drivers/PlatInitDxe/PlatInitDxe.c
@@ -0,0 +1,45 @@
+/** @file
+ Copyright (c) 2017, Linaro Limited. All rights reserved.
+ Copyright (c) 2017, 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.
+
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/MppLib.h>
+#include <Library/MvComPhyLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UtmiPhyLib.h>
+
+EFI_STATUS
+EFIAPI
+ArmadaPlatInitDxeEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ DEBUG ((DEBUG_ERROR, "\nArmada Platform Init\n\n"));
+
+ Status = gBS->InstallProtocolInterface (&ImageHandle,
+ &gMarvellPlatformInitCompleteProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ MvComPhyInit ();
+ UtmiPhyInit ();
+ MppInitialize ();
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/Marvell/Armada7k8k/Drivers/PlatInitDxe/PlatInitDxe.inf b/Silicon/Marvell/Armada7k8k/Drivers/PlatInitDxe/PlatInitDxe.inf
new file mode 100644
index 0000000000..803dc6ede6
--- /dev/null
+++ b/Silicon/Marvell/Armada7k8k/Drivers/PlatInitDxe/PlatInitDxe.inf
@@ -0,0 +1,45 @@
+#/* @file
+# Copyright (c) 2017, Linaro Limited. All rights reserved.
+# Copyright (c) 2017, 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.
+#
+#*/
+
+[Defines]
+ INF_VERSION = 0x00010019
+ BASE_NAME = PlatInitDxe
+ FILE_GUID = 8c66f65b-08a6-4c91-b993-ff81e0adf818
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = ArmadaPlatInitDxeEntryPoint
+
+[Sources]
+ PlatInitDxe.c
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/Marvell/Marvell.dec
+
+[LibraryClasses]
+ ComPhyLib
+ DebugLib
+ MppLib
+ PcdLib
+ TimerLib
+ UefiDriverEntryPoint
+ UtmiPhyLib
+
+[Protocols]
+ gMarvellPlatformInitCompleteProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE
diff --git a/Silicon/Marvell/Armada7k8k/Library/Armada70x0Lib/AArch64/ArmPlatformHelper.S b/Silicon/Marvell/Armada7k8k/Library/Armada70x0Lib/AArch64/ArmPlatformHelper.S
new file mode 100644
index 0000000000..72f8cfce77
--- /dev/null
+++ b/Silicon/Marvell/Armada7k8k/Library/Armada70x0Lib/AArch64/ArmPlatformHelper.S
@@ -0,0 +1,51 @@
+//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)
+ mov x29, xzr
+ 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/Silicon/Marvell/Armada7k8k/Library/Armada70x0Lib/ARM/ArmPlatformHelper.S b/Silicon/Marvell/Armada7k8k/Library/Armada70x0Lib/ARM/ArmPlatformHelper.S
new file mode 100644
index 0000000000..21459e50a7
--- /dev/null
+++ b/Silicon/Marvell/Armada7k8k/Library/Armada70x0Lib/ARM/ArmPlatformHelper.S
@@ -0,0 +1,77 @@
+//Based on ArmPlatformPkg/Library/ArmPlatformLibNull/AArch64/ArmPlatformHelper.S
+//
+// Copyright (c) 2012-2013, ARM Limited. All rights reserved.
+// Copyright (c) 2016, Marvell. All rights reserved.
+// Copyright (c) 2017, Linaro Limited. 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 <AsmMacroIoLib.h>
+#include <Library/ArmLib.h>
+
+#define CCU_MC_BASE 0xF0001700
+#define CCU_MC_RCR_OFFSET 0x0
+#define CCU_MC_RCR_REMAP_EN BIT0
+#define CCU_MC_RCR_REMAP_SIZE(Size) (((Size) - 1) ^ (SIZE_1MB - 1))
+
+#define CCU_MC_RSBR_OFFSET 0x4
+#define CCU_MC_RSBR_SOURCE_BASE(Base) (((Base) >> 20) << 10)
+#define CCU_MC_RTBR_OFFSET 0x8
+#define CCU_MC_RTBR_TARGET_BASE(Base) (((Base) >> 20) << 10)
+
+ASM_FUNC(ArmPlatformPeiBootAction)
+ .if FixedPcdGet64 (PcdSystemMemoryBase) != 0
+ .err PcdSystemMemoryBase should be 0x0 on this platform!
+ .endif
+
+ .if FixedPcdGet64 (PcdSystemMemorySize) > FixedPcdGet32 (PcdDramRemapTarget)
+ //
+ // Use the low range for UEFI itself. The remaining memory will be mapped
+ // and added to the GCD map later.
+ //
+ ADRL (r0, mSystemMemoryEnd)
+ MOV32 (r2, FixedPcdGet32 (PcdDramRemapTarget) - 1)
+ mov r3, #0
+ strd r2, r3, [r0]
+ .endif
+
+ bx lr
+
+//UINTN
+//ArmPlatformGetCorePosition (
+// IN UINTN MpId
+// );
+// With this function: CorePos = (ClusterId * 2) + CoreId
+ASM_FUNC(ArmPlatformGetCorePosition)
+ and r1, r0, #ARM_CORE_MASK
+ and r0, r0, #ARM_CLUSTER_MASK
+ add r0, r1, r0, LSR #7
+ bx lr
+
+//UINTN
+//ArmPlatformGetPrimaryCoreMpId (
+// VOID
+// );
+ASM_FUNC(ArmPlatformGetPrimaryCoreMpId)
+ MOV32 (r0, FixedPcdGet32(PcdArmPrimaryCore))
+ bx lr
+
+//UINTN
+//ArmPlatformIsPrimaryCore (
+// IN UINTN MpId
+// );
+ASM_FUNC(ArmPlatformIsPrimaryCore)
+ MOV32 (r1, FixedPcdGet32(PcdArmPrimaryCoreMask))
+ and r0, r0, r1
+ MOV32 (r1, FixedPcdGet32(PcdArmPrimaryCore))
+ cmp r0, r1
+ moveq r0, #1
+ movne r0, #0
+ bx lr
diff --git a/Silicon/Marvell/Armada7k8k/Library/Armada70x0Lib/Armada70x0Lib.c b/Silicon/Marvell/Armada7k8k/Library/Armada70x0Lib/Armada70x0Lib.c
new file mode 100644
index 0000000000..b2b415571c
--- /dev/null
+++ b/Silicon/Marvell/Armada7k8k/Library/Armada70x0Lib/Armada70x0Lib.c
@@ -0,0 +1,132 @@
+/**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 <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
+ )
+{
+ return RETURN_SUCCESS;
+}
+
+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/Silicon/Marvell/Armada7k8k/Library/Armada70x0Lib/Armada70x0Lib.inf b/Silicon/Marvell/Armada7k8k/Library/Armada70x0Lib/Armada70x0Lib.inf
new file mode 100644
index 0000000000..4d4edc8565
--- /dev/null
+++ b/Silicon/Marvell/Armada7k8k/Library/Armada70x0Lib/Armada70x0Lib.inf
@@ -0,0 +1,76 @@
+# 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
+ Silicon/Marvell/Marvell.dec
+
+[LibraryClasses]
+ ArmLib
+ ComPhyLib
+ DebugLib
+ MemoryAllocationLib
+ MppLib
+ UtmiPhyLib
+
+[Sources.common]
+ Armada70x0Lib.c
+ Armada70x0LibMem.c
+
+[Sources.AArch64]
+ AArch64/ArmPlatformHelper.S
+
+[Sources.ARM]
+ ARM/ArmPlatformHelper.S
+
+[FixedPcd]
+ gArmTokenSpaceGuid.PcdSystemMemoryBase
+ gArmTokenSpaceGuid.PcdSystemMemorySize
+
+ gArmTokenSpaceGuid.PcdArmPrimaryCoreMask
+ gArmTokenSpaceGuid.PcdArmPrimaryCore
+
+ gMarvellTokenSpaceGuid.PcdConfigSpaceBaseAddress
+
+[Ppis]
+ gArmMpCoreInfoPpiGuid
diff --git a/Silicon/Marvell/Armada7k8k/Library/Armada70x0Lib/Armada70x0LibMem.c b/Silicon/Marvell/Armada7k8k/Library/Armada70x0Lib/Armada70x0LibMem.c
new file mode 100644
index 0000000000..f384415d7a
--- /dev/null
+++ b/Silicon/Marvell/Armada7k8k/Library/Armada70x0Lib/Armada70x0LibMem.c
@@ -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.
+
+*******************************************************************************/
+
+#include <Base.h>
+#include <Library/ArmPlatformLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include "Armada70x0LibMem.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
+
+STATIC ARM_MEMORY_REGION_DESCRIPTOR mVirtualMemoryTable[MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS];
+
+// Obtain DRAM size basing on register values filled by early firmware.
+STATIC
+UINT64
+GetDramSize (
+ IN OUT UINT64 *MemSize
+ )
+{
+ UINT64 BaseAddr;
+ UINT8 RegionCode;
+ UINT8 Cs;
+
+ *MemSize = 0;
+
+ for (Cs = 0; Cs < DRAM_MAX_CS_NUM; Cs++) {
+
+ /* Exit loop on first disabled DRAM CS */
+ if (!DRAM_CS_ENABLED (Cs)) {
+ break;
+ }
+
+ /*
+ * Sanity check for base address of next DRAM block.
+ * Only continuous space will be used.
+ */
+ BaseAddr = GET_DRAM_REGION_BASE (Cs);
+ if (BaseAddr != *MemSize) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: DRAM blocks are not contiguous, limit size to 0x%llx\n",
+ __FUNCTION__,
+ *MemSize));
+ return EFI_SUCCESS;
+ }
+
+ /* Decode area length for current CS from register value */
+ RegionCode = GET_DRAM_REGION_SIZE_CODE (Cs);
+
+ if (DRAM_REGION_SIZE_EVEN (RegionCode)) {
+ *MemSize += GET_DRAM_REGION_SIZE_EVEN (RegionCode);
+ } else if (DRAM_REGION_SIZE_ODD (RegionCode)) {
+ *MemSize += GET_DRAM_REGION_SIZE_ODD (RegionCode);
+ } else {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Invalid memory region code (0x%x) for CS#%d\n",
+ __FUNCTION__,
+ RegionCode,
+ Cs));
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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
+ )
+{
+ UINTN Index = 0;
+ UINT64 MemSize;
+ UINT64 MemLowSize;
+ UINT64 MemHighStart;
+ UINT64 MemHighSize;
+ UINT64 ConfigSpaceBaseAddr;
+ EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttributes;
+ EFI_STATUS Status;
+
+ ASSERT (VirtualMemoryMap != NULL);
+
+ ConfigSpaceBaseAddr = FixedPcdGet64 (PcdConfigSpaceBaseAddress);
+
+ // Obtain total memory size from the hardware.
+ Status = GetDramSize (&MemSize);
+ if (EFI_ERROR (Status)) {
+ MemSize = FixedPcdGet64 (PcdSystemMemorySize);
+ DEBUG ((DEBUG_ERROR, "Limit total memory size to %d MB\n", MemSize / 1024 / 1024));
+ }
+
+ if (DRAM_REMAP_ENABLED) {
+ MemLowSize = MIN (DRAM_REMAP_TARGET, MemSize);
+ MemHighStart = (UINT64)DRAM_REMAP_TARGET + DRAM_REMAP_SIZE;
+ MemHighSize = MemSize - MemLowSize;
+ } else {
+ MemLowSize = MIN (ConfigSpaceBaseAddr, MemSize);
+ }
+
+ ResourceAttributes = (
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_TESTED
+ );
+
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_SYSTEM_MEMORY,
+ ResourceAttributes,
+ FixedPcdGet64 (PcdSystemMemoryBase),
+ MemLowSize
+ );
+
+ // DDR
+ mVirtualMemoryTable[Index].PhysicalBase = FixedPcdGet64 (PcdSystemMemoryBase);
+ mVirtualMemoryTable[Index].VirtualBase = FixedPcdGet64 (PcdSystemMemoryBase);
+ mVirtualMemoryTable[Index].Length = MemLowSize;
+ mVirtualMemoryTable[Index].Attributes = DDR_ATTRIBUTES_CACHED;
+
+ // Configuration space
+ mVirtualMemoryTable[++Index].PhysicalBase = ConfigSpaceBaseAddr;
+ mVirtualMemoryTable[Index].VirtualBase = ConfigSpaceBaseAddr;
+ mVirtualMemoryTable[Index].Length = SIZE_4GB - ConfigSpaceBaseAddr;
+ mVirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE;
+
+ if (MemSize > MemLowSize) {
+ //
+ // If we have more than MemLowSize worth of DRAM, the remainder will be
+ // mapped at the top of the remapped window.
+ //
+ mVirtualMemoryTable[++Index].PhysicalBase = MemHighStart;
+ mVirtualMemoryTable[Index].VirtualBase = MemHighStart;
+ mVirtualMemoryTable[Index].Length = MemHighSize;
+ mVirtualMemoryTable[Index].Attributes = DDR_ATTRIBUTES_CACHED;
+
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_SYSTEM_MEMORY,
+ ResourceAttributes,
+ MemHighStart,
+ MemHighSize
+ );
+ }
+
+ // End of Table
+ mVirtualMemoryTable[++Index].PhysicalBase = 0;
+ mVirtualMemoryTable[Index].VirtualBase = 0;
+ mVirtualMemoryTable[Index].Length = 0;
+ mVirtualMemoryTable[Index].Attributes = 0;
+
+ ASSERT((Index + 1) <= MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS);
+
+ *VirtualMemoryMap = mVirtualMemoryTable;
+}
diff --git a/Silicon/Marvell/Armada7k8k/Library/Armada70x0Lib/Armada70x0LibMem.h b/Silicon/Marvell/Armada7k8k/Library/Armada70x0Lib/Armada70x0LibMem.h
new file mode 100644
index 0000000000..cc30e4aeed
--- /dev/null
+++ b/Silicon/Marvell/Armada7k8k/Library/Armada70x0Lib/Armada70x0LibMem.h
@@ -0,0 +1,73 @@
+/*******************************************************************************
+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.
+
+*******************************************************************************/
+
+#define CCU_MC_RCR_REG 0xf0001700
+#define REMAP_EN_MASK 0x1
+#define REMAP_SIZE_OFFS 20
+#define REMAP_SIZE_MASK (0xfff << REMAP_SIZE_OFFS)
+#define CCU_MC_RTBR_REG 0xf0001708
+#define TARGET_BASE_OFFS 10
+#define TARGET_BASE_MASK (0xfffff << TARGET_BASE_OFFS)
+
+#define DRAM_REMAP_ENABLED \
+ (MmioRead32 (CCU_MC_RCR_REG) & REMAP_EN_MASK)
+#define DRAM_REMAP_SIZE \
+ (MmioRead32 (CCU_MC_RCR_REG) & REMAP_SIZE_MASK) + SIZE_1MB
+#define DRAM_REMAP_TARGET \
+ (MmioRead32 (CCU_MC_RTBR_REG) << TARGET_BASE_OFFS)
+
+#define DRAM_CH0_MMAP_LOW_REG(cs) (0xf0020200 + (cs) * 0x8)
+#define DRAM_CS_VALID_ENABLED_MASK 0x1
+#define DRAM_AREA_LENGTH_OFFS 16
+#define DRAM_AREA_LENGTH_MASK (0x1f << DRAM_AREA_LENGTH_OFFS)
+#define DRAM_START_ADDRESS_L_OFFS 23
+#define DRAM_START_ADDRESS_L_MASK (0x1ff << DRAM_START_ADDRESS_L_OFFS)
+#define DRAM_CH0_MMAP_HIGH_REG(cs) (0xf0020204 + (cs) * 0x8)
+#define DRAM_START_ADDR_HTOL_OFFS 32
+
+#define DRAM_MAX_CS_NUM 8
+
+#define DRAM_CS_ENABLED(Cs) \
+ (MmioRead32 (DRAM_CH0_MMAP_LOW_REG (Cs)) & DRAM_CS_VALID_ENABLED_MASK)
+#define GET_DRAM_REGION_BASE(Cs) \
+ ((UINT64)MmioRead32 (DRAM_CH0_MMAP_HIGH_REG ((Cs))) << \
+ DRAM_START_ADDR_HTOL_OFFS) | \
+ (MmioRead32 (DRAM_CH0_MMAP_LOW_REG (Cs)) & DRAM_START_ADDRESS_L_MASK);
+#define GET_DRAM_REGION_SIZE_CODE(Cs) \
+ (MmioRead32 (DRAM_CH0_MMAP_LOW_REG ((Cs))) & \
+ DRAM_AREA_LENGTH_MASK) >> DRAM_AREA_LENGTH_OFFS
+#define DRAM_REGION_SIZE_EVEN(C) (((C) >= 7) && ((C) <= 26))
+#define GET_DRAM_REGION_SIZE_EVEN(C) ((UINT64)1 << ((C) + 16))
+#define DRAM_REGION_SIZE_ODD(C) ((C) <= 4)
+#define GET_DRAM_REGION_SIZE_ODD(C) ((UINT64)0x18000000 << (C))
diff --git a/Silicon/Marvell/Armada7k8k/Library/Armada70x0MemoryInitPeiLib/Armada70x0MemoryInitPeiLib.c b/Silicon/Marvell/Armada7k8k/Library/Armada70x0MemoryInitPeiLib/Armada70x0MemoryInitPeiLib.c
new file mode 100644
index 0000000000..53119f4150
--- /dev/null
+++ b/Silicon/Marvell/Armada7k8k/Library/Armada70x0MemoryInitPeiLib/Armada70x0MemoryInitPeiLib.c
@@ -0,0 +1,158 @@
+/** @file
+*
+* Copyright (c) 2011-2015, ARM Limited. All rights reserved.
+* Copyright (c) 2017, ARM Limited. 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 <PiPei.h>
+
+#include <Library/ArmMmuLib.h>
+#include <Library/ArmPlatformLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/PcdLib.h>
+
+VOID
+BuildMemoryTypeInformationHob (
+ VOID
+ );
+
+STATIC
+VOID
+InitMmu (
+ IN ARM_MEMORY_REGION_DESCRIPTOR *MemoryTable
+ )
+{
+
+ VOID *TranslationTableBase;
+ UINTN TranslationTableSize;
+ RETURN_STATUS Status;
+
+ Status = ArmConfigureMmu (MemoryTable,
+ &TranslationTableBase,
+ &TranslationTableSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Error: Failed to enable MMU\n"));
+ }
+}
+
+/*++
+
+Routine Description:
+
+
+
+Arguments:
+
+ FileHandle - Handle of the file being invoked.
+ PeiServices - Describes the list of possible PEI Services.
+
+Returns:
+
+ Status - EFI_SUCCESS if the boot mode could be set
+
+--*/
+EFI_STATUS
+EFIAPI
+MemoryPeim (
+ IN EFI_PHYSICAL_ADDRESS UefiMemoryBase,
+ IN UINT64 UefiMemorySize
+ )
+{
+ ARM_MEMORY_REGION_DESCRIPTOR *MemoryTable;
+ EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttributes;
+ UINT64 ResourceLength;
+ EFI_PEI_HOB_POINTERS NextHob;
+ EFI_PHYSICAL_ADDRESS SecureTop;
+ EFI_PHYSICAL_ADDRESS ResourceTop;
+
+ // Get Virtual Memory Map from the Platform Library
+ ArmPlatformGetVirtualMemoryMap (&MemoryTable);
+
+ SecureTop = (EFI_PHYSICAL_ADDRESS)FixedPcdGet64 (PcdSecureRegionBase) +
+ FixedPcdGet32 (PcdSecureRegionSize);
+
+ //
+ // Search for System Memory Hob that covers the secure firmware,
+ // and punch a hole in it
+ //
+ for (NextHob.Raw = GetHobList ();
+ NextHob.Raw != NULL;
+ NextHob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR,
+ NextHob.Raw)) {
+
+ if ((NextHob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&
+ (FixedPcdGet64 (PcdSecureRegionBase) >= NextHob.ResourceDescriptor->PhysicalStart) &&
+ (SecureTop <= NextHob.ResourceDescriptor->PhysicalStart +
+ NextHob.ResourceDescriptor->ResourceLength))
+ {
+ ResourceAttributes = NextHob.ResourceDescriptor->ResourceAttribute;
+ ResourceLength = NextHob.ResourceDescriptor->ResourceLength;
+ ResourceTop = NextHob.ResourceDescriptor->PhysicalStart + ResourceLength;
+
+ if (FixedPcdGet64 (PcdSecureRegionBase) == NextHob.ResourceDescriptor->PhysicalStart) {
+ //
+ // This region starts right at the start of the reserved region, so we
+ // can simply move its start pointer and reduce its length by the same
+ // value
+ //
+ NextHob.ResourceDescriptor->PhysicalStart += FixedPcdGet32 (PcdSecureRegionSize);
+ NextHob.ResourceDescriptor->ResourceLength -= FixedPcdGet32 (PcdSecureRegionSize);
+
+ } else if ((NextHob.ResourceDescriptor->PhysicalStart +
+ NextHob.ResourceDescriptor->ResourceLength) == SecureTop) {
+
+ //
+ // This region ends right at the end of the reserved region, so we
+ // can simply reduce its length by the size of the region.
+ //
+ NextHob.ResourceDescriptor->ResourceLength -= FixedPcdGet32 (PcdSecureRegionSize);
+
+ } else {
+ //
+ // This region covers the reserved region. So split it into two regions,
+ // each one touching the reserved region at either end, but not covering
+ // it.
+ //
+ NextHob.ResourceDescriptor->ResourceLength = FixedPcdGet64 (PcdSecureRegionBase) -
+ NextHob.ResourceDescriptor->PhysicalStart;
+
+ // Create the System Memory HOB for the remaining region (top of the FD)
+ BuildResourceDescriptorHob (EFI_RESOURCE_SYSTEM_MEMORY,
+ ResourceAttributes,
+ SecureTop,
+ ResourceTop - SecureTop);
+ }
+
+ //
+ // Reserve the memory space occupied by the secure firmware
+ //
+ BuildResourceDescriptorHob (EFI_RESOURCE_MEMORY_RESERVED,
+ 0,
+ FixedPcdGet64 (PcdSecureRegionBase),
+ FixedPcdGet32 (PcdSecureRegionSize));
+
+ break;
+ }
+ NextHob.Raw = GET_NEXT_HOB (NextHob);
+ }
+
+ // Build Memory Allocation Hob
+ InitMmu (MemoryTable);
+
+ if (FeaturePcdGet (PcdPrePiProduceMemoryTypeInformationHob)) {
+ // Optional feature that helps prevent EFI memory map fragmentation.
+ BuildMemoryTypeInformationHob ();
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/Marvell/Armada7k8k/Library/Armada70x0MemoryInitPeiLib/Armada70x0MemoryInitPeiLib.inf b/Silicon/Marvell/Armada7k8k/Library/Armada70x0MemoryInitPeiLib/Armada70x0MemoryInitPeiLib.inf
new file mode 100644
index 0000000000..adc5b9ac8d
--- /dev/null
+++ b/Silicon/Marvell/Armada7k8k/Library/Armada70x0MemoryInitPeiLib/Armada70x0MemoryInitPeiLib.inf
@@ -0,0 +1,46 @@
+#/** @file
+#
+# Copyright (c) 2011-2014, ARM Ltd. All rights reserved.<BR>
+# Copyright (c) 2017, Linaro 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 = Armada70x0MemoryInitPeiLib
+ FILE_GUID = abc4e8a7-89a7-4aea-92bc-0e9421c4a473
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = MemoryInitPeiLib|SEC PEIM
+
+[Sources]
+ Armada70x0MemoryInitPeiLib.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ ArmPlatformPkg/ArmPlatformPkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/Marvell/Marvell.dec
+
+[LibraryClasses]
+ ArmPlatformLib
+ DebugLib
+ HobLib
+ ArmMmuLib
+
+[FeaturePcd]
+ gEmbeddedTokenSpaceGuid.PcdPrePiProduceMemoryTypeInformationHob
+
+[FixedPcd]
+ gMarvellTokenSpaceGuid.PcdSecureRegionBase
+ gMarvellTokenSpaceGuid.PcdSecureRegionSize
diff --git a/Silicon/Marvell/Armada7k8k/Library/RealTimeClockLib/RealTimeClockLib.c b/Silicon/Marvell/Armada7k8k/Library/RealTimeClockLib/RealTimeClockLib.c
new file mode 100644
index 0000000000..d671b6adc1
--- /dev/null
+++ b/Silicon/Marvell/Armada7k8k/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/Silicon/Marvell/Armada7k8k/Library/RealTimeClockLib/RealTimeClockLib.h b/Silicon/Marvell/Armada7k8k/Library/RealTimeClockLib/RealTimeClockLib.h
new file mode 100644
index 0000000000..922f959239
--- /dev/null
+++ b/Silicon/Marvell/Armada7k8k/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/Silicon/Marvell/Armada7k8k/Library/RealTimeClockLib/RealTimeClockLib.inf b/Silicon/Marvell/Armada7k8k/Library/RealTimeClockLib/RealTimeClockLib.inf
new file mode 100644
index 0000000000..2f842e8abf
--- /dev/null
+++ b/Silicon/Marvell/Armada7k8k/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
+ Silicon/Marvell/Marvell.dec
+
+[LibraryClasses]
+ DebugLib
+ DxeServicesTableLib
+ IoLib
+ PcdLib
+ TimeBaseLib
+ TimerLib
+ UefiRuntimeLib
+
+[Guids]
+ gEfiEventVirtualAddressChangeGuid
+
+[Pcd]
+ gMarvellTokenSpaceGuid.PcdRtcEnabled
diff --git a/Silicon/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.c b/Silicon/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.c
new file mode 100644
index 0000000000..d8fd1bfe62
--- /dev/null
+++ b/Silicon/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/Silicon/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.h b/Silicon/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.h
new file mode 100644
index 0000000000..b1af645050
--- /dev/null
+++ b/Silicon/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/Silicon/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.inf b/Silicon/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.inf
new file mode 100644
index 0000000000..510b5502dc
--- /dev/null
+++ b/Silicon/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
+ Silicon/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/Silicon/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.c b/Silicon/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.c
new file mode 100755
index 0000000000..d6f590d5bf
--- /dev/null
+++ b/Silicon/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.c
@@ -0,0 +1,762 @@
+/********************************************************************************
+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/MemoryAllocationLib.h>
+#include <Library/MvHwDescLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "MvI2cDxe.h"
+
+DECLARE_A7K8K_I2C_TEMPLATE;
+
+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
+ )
+{
+ MVHW_I2C_DESC *Desc = &mA7k8kI2cDescTemplate;
+ UINT8 *I2cDeviceTable, Index;
+ EFI_STATUS Status;
+
+ /* Obtain table with enabled I2c devices */
+ I2cDeviceTable = (UINT8 *)PcdGetPtr (PcdI2cControllersEnabled);
+ if (I2cDeviceTable == NULL) {
+ DEBUG ((DEBUG_ERROR, "Missing PcdI2cControllersEnabled\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (PcdGetSize (PcdI2cControllersEnabled) > MVHW_MAX_I2C_DEVS) {
+ DEBUG ((DEBUG_ERROR, "Wrong PcdI2cControllersEnabled format\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ /* Initialize enabled chips */
+ for (Index = 0; Index < PcdGetSize (PcdI2cControllersEnabled); Index++) {
+ if (!MVHW_DEV_ENABLED (I2c, Index)) {
+ DEBUG ((DEBUG_ERROR, "Skip I2c chip %d\n", Index));
+ continue;
+ }
+
+ Status = MvI2cInitialiseController(
+ ImageHandle,
+ SystemTable,
+ Desc->I2cBaseAddresses[Index]
+ );
+ if (EFI_ERROR(Status))
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+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
+ )
+{
+ MvI2cPollCtrl (I2cMasterContext, I2C_OPERATION_TIMEOUT, I2C_CONTROL_IFLG);
+ MvI2cControlClear(I2cMasterContext, I2C_CONTROL_IFLG);
+}
+
+/* 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);
+ }
+
+ 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;
+ EFI_STATUS Status = EFI_SUCCESS;
+
+ 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) {
+ Status = MvI2cStart (I2cMasterContext,
+ (SlaveAddress << 1) | ReadMode,
+ I2C_TRANSFER_TIMEOUT);
+ } else if (!(Operation->Flags & I2C_FLAG_NORESTART)) {
+ Status = MvI2cRepeatedStart (I2cMasterContext,
+ (SlaveAddress << 1) | ReadMode,
+ I2C_TRANSFER_TIMEOUT);
+ }
+
+ /* I2C transaction was aborted, so stop further transactions */
+ if (EFI_ERROR (Status)) {
+ MvI2cStop (I2cMasterContext);
+ break;
+ }
+
+ /*
+ * If sending the slave address was successful,
+ * proceed to read or write section.
+ */
+ if (ReadMode) {
+ Status = MvI2cRead (I2cMasterContext,
+ Operation->Buffer,
+ Operation->LengthInBytes,
+ &Transmitted,
+ Count == 1,
+ I2C_TRANSFER_TIMEOUT);
+ Operation->LengthInBytes = Transmitted;
+ } else {
+ Status = MvI2cWrite (I2cMasterContext,
+ Operation->Buffer,
+ Operation->LengthInBytes,
+ &Transmitted,
+ I2C_TRANSFER_TIMEOUT);
+ Operation->LengthInBytes = Transmitted;
+ }
+
+ /*
+ * The I2C read or write transaction failed.
+ * Stop the I2C transaction.
+ */
+ if (EFI_ERROR (Status)) {
+ MvI2cStop (I2cMasterContext);
+ break;
+ }
+
+ /* Check if there is any more data to be sent */
+ 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/Silicon/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.h b/Silicon/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.h
new file mode 100644
index 0000000000..3c9beaf967
--- /dev/null
+++ b/Silicon/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 100
+
+#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/Silicon/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf b/Silicon/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf
new file mode 100755
index 0000000000..a7cf52e7e1
--- /dev/null
+++ b/Silicon/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf
@@ -0,0 +1,74 @@
+#
+# 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
+ Silicon/Marvell/Marvell.dec
+
+[LibraryClasses]
+ IoLib
+ PcdLib
+ BaseLib
+ DebugLib
+ UefiLib
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+
+[Protocols]
+ gEfiI2cMasterProtocolGuid
+ gEfiDevicePathProtocolGuid
+ gEfiI2cEnumerateProtocolGuid
+ gEfiI2cBusConfigurationManagementProtocolGuid
+
+[Pcd]
+ gMarvellTokenSpaceGuid.PcdI2cSlaveAddresses
+ gMarvellTokenSpaceGuid.PcdI2cSlaveBuses
+ gMarvellTokenSpaceGuid.PcdI2cControllersEnabled
+ gMarvellTokenSpaceGuid.PcdI2cClockFrequency
+ gMarvellTokenSpaceGuid.PcdI2cBaudRate
+ gMarvellTokenSpaceGuid.PcdI2cBusCount
+
+[Depex]
+ TRUE
diff --git a/Silicon/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.c b/Silicon/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.c
new file mode 100644
index 0000000000..12aabad0f3
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.c
@@ -0,0 +1,252 @@
+/********************************************************************************
+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"
+
+DECLARE_A7K8K_MDIO_TEMPLATE;
+
+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 (
+ UINT32 MdioBase
+ )
+{
+ 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 (
+ UINT32 MdioBase
+ )
+{
+ 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 MdioIndex,
+ IN UINT32 RegOff,
+ IN BOOLEAN Write,
+ IN OUT UINT32 *Data
+ )
+{
+ UINT32 MdioBase = This->BaseAddresses[MdioIndex];
+ 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 (MdioBase);
+ 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 (MdioBase) : MdioWaitValid (MdioBase);
+ 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 MdioIndex,
+ IN UINT32 RegOff,
+ IN UINT32 *Data
+ )
+{
+ EFI_STATUS Status;
+
+ Status = MdioOperation (
+ This,
+ PhyAddr,
+ MdioIndex,
+ RegOff,
+ FALSE,
+ Data
+ );
+
+ return Status;
+}
+
+EFI_STATUS
+MvMdioWrite (
+ IN CONST MARVELL_MDIO_PROTOCOL *This,
+ IN UINT32 PhyAddr,
+ IN UINT32 MdioIndex,
+ IN UINT32 RegOff,
+ IN UINT32 Data
+ )
+{
+ return MdioOperation (
+ This,
+ PhyAddr,
+ MdioIndex,
+ RegOff,
+ TRUE,
+ &Data
+ );
+}
+
+EFI_STATUS
+EFIAPI
+MvMdioDxeInitialise (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ MVHW_MDIO_DESC *Desc = &mA7k8kMdioDescTemplate;
+ UINT8 Index;
+ MARVELL_MDIO_PROTOCOL *Mdio;
+ EFI_STATUS Status;
+ EFI_HANDLE Handle = NULL;
+
+ Mdio = AllocateZeroPool (sizeof (MARVELL_MDIO_PROTOCOL));
+ if (Mdio == NULL) {
+ DEBUG ((DEBUG_ERROR, "MdioDxe: Protocol allocation failed\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ /* Obtain base addresses of all possible controllers */
+ for (Index = 0; Index < Desc->MdioDevCount; Index++) {
+ Mdio->BaseAddresses[Index] = Desc->MdioBaseAddresses[Index];
+ }
+
+ Mdio->ControllerCount = Desc->MdioDevCount;
+ Mdio->Read = MvMdioRead;
+ Mdio->Write = MvMdioWrite;
+
+ 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/Silicon/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.h b/Silicon/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.h
new file mode 100644
index 0000000000..b41a1e6fba
--- /dev/null
+++ b/Silicon/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/Silicon/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.inf b/Silicon/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.inf
new file mode 100644
index 0000000000..c070785e6e
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.inf
@@ -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.
+#
+
+[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
+ Silicon/Marvell/Marvell.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ IoLib
+ PcdLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+
+[Protocols]
+ gMarvellMdioProtocolGuid
+
+[Depex]
+ TRUE
diff --git a/Silicon/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.c b/Silicon/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.c
new file mode 100644
index 0000000000..dd2edaec36
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.c
@@ -0,0 +1,460 @@
+/********************************************************************************
+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/MvHwDescLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include "MvPhyDxe.h"
+
+#define TIMEOUT 500
+
+STATIC MARVELL_MDIO_PROTOCOL *Mdio;
+
+//
+// Table with available Mdio controllers
+//
+STATIC UINT8 * CONST MdioDeviceTable = PcdGetPtr (PcdMdioControllersEnabled);
+//
+// Table with PHY to Mdio controller mappings
+//
+STATIC UINT8 * CONST Phy2MdioController = PcdGetPtr (PcdPhy2MdioController);
+//
+// Table with PHYs' SMI addresses
+//
+STATIC UINT8 * CONST PhySmiAddresses = PcdGetPtr (PcdPhySmiAddresses);
+
+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 PHY_DEVICE *PhyDev
+ )
+{
+ UINT32 Reg = 0;
+ INTN timeout = TIMEOUT;
+
+ Mdio->Read (Mdio, PhyDev->Addr, PhyDev->MdioIndex, MII_BMCR, &Reg);
+ Reg |= BMCR_RESET;
+ Mdio->Write (Mdio, PhyDev->Addr, PhyDev->MdioIndex, MII_BMCR, Reg);
+
+ while ((Reg & BMCR_RESET) && timeout--) {
+ Mdio->Read (Mdio, PhyDev->Addr, PhyDev->MdioIndex, 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, PhyDev->MdioIndex, 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, PhyDev->MdioIndex, MIIM_88E1111_PHY_EXT_CR, Reg);
+
+ Mdio->Read (Mdio, PhyDev->Addr, PhyDev->MdioIndex, 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, PhyDev->MdioIndex, MIIM_88E1111_PHY_EXT_SR, Reg);
+ }
+
+ if (PhyDev->Connection == PHY_CONNECTION_SGMII) {
+ Mdio->Read (Mdio, PhyDev->Addr, PhyDev->MdioIndex, 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, PhyDev->MdioIndex, MIIM_88E1111_PHY_EXT_SR, Reg);
+ }
+
+ if (PhyDev->Connection == PHY_CONNECTION_RTBI) {
+ Mdio->Read (Mdio, PhyDev->Addr, PhyDev->MdioIndex, MIIM_88E1111_PHY_EXT_CR, &Reg);
+ Reg |= (MIIM_88E1111_RX_DELAY | MIIM_88E1111_TX_DELAY);
+ Mdio->Write (Mdio, PhyDev->Addr, PhyDev->MdioIndex, MIIM_88E1111_PHY_EXT_CR, Reg);
+
+ Mdio->Read (Mdio, PhyDev->Addr, PhyDev->MdioIndex, 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, PhyDev->MdioIndex, MIIM_88E1111_PHY_EXT_SR, Reg);
+
+ /* Soft reset */
+ MvPhyReset (PhyDev);
+
+ Mdio->Read (Mdio, PhyDev->Addr, PhyDev->MdioIndex, 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, PhyDev->MdioIndex, MIIM_88E1111_PHY_EXT_SR, Reg);
+ }
+
+ Mdio->Read (Mdio, PhyDev->Addr, PhyDev->MdioIndex, MII_BMCR, &Reg);
+ Reg |= (BMCR_ANENABLE | BMCR_ANRESTART);
+ Reg &= ~BMCR_ISOLATE;
+ Mdio->Write (Mdio, PhyDev->Addr, PhyDev->MdioIndex, MII_BMCR, Reg);
+
+ /* Soft reset */
+ MvPhyReset (PhyDev);
+
+ MvPhyReset (PhyDev);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+MvPhyParseStatus (
+ IN PHY_DEVICE *PhyDev
+ )
+{
+ UINT32 Data;
+ UINT32 Speed;
+
+ Mdio->Read (Mdio, PhyDev->Addr, PhyDev->MdioIndex, 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, PhyDev->MdioIndex, 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 PHY_DEVICE *PhyDev,
+ 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, PhyDev->Addr, PhyDev->MdioIndex, RegNum, &Reg);
+
+ Reg &= ~Mask;
+ Reg |= Data << Offset;
+
+ Mdio->Write (Mdio, PhyDev->Addr, PhyDev->MdioIndex, RegNum, Reg);
+}
+
+STATIC
+EFI_STATUS
+MvPhyInit1512 (
+ IN CONST MARVELL_PHY_PROTOCOL *Snp,
+ 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, PhyDev->Addr, PhyDev->MdioIndex, 22, 0x00ff);
+ Mdio->Write (Mdio, PhyDev->Addr, PhyDev->MdioIndex, 17, 0x214B);
+ Mdio->Write (Mdio, PhyDev->Addr, PhyDev->MdioIndex, 16, 0x2144);
+ Mdio->Write (Mdio, PhyDev->Addr, PhyDev->MdioIndex, 17, 0x0C28);
+ Mdio->Write (Mdio, PhyDev->Addr, PhyDev->MdioIndex, 16, 0x2146);
+ Mdio->Write (Mdio, PhyDev->Addr, PhyDev->MdioIndex, 17, 0xB233);
+ Mdio->Write (Mdio, PhyDev->Addr, PhyDev->MdioIndex, 16, 0x214D);
+ Mdio->Write (Mdio, PhyDev->Addr, PhyDev->MdioIndex, 17, 0xCC0C);
+ Mdio->Write (Mdio, PhyDev->Addr, PhyDev->MdioIndex, 16, 0x2159);
+
+ /* Reset page selection and select page 0x12 */
+ Mdio->Write (Mdio, PhyDev->Addr, PhyDev->MdioIndex, 22, 0x0000);
+ Mdio->Write (Mdio, PhyDev->Addr, PhyDev->MdioIndex, 22, 0x0012);
+
+ /* Write HWCFG_MODE = SGMII to Copper */
+ MvPhy1512WriteBits(PhyDev, 20, 0, 3, 1);
+
+ /* Phy reset - necessary after changing mode */
+ MvPhy1512WriteBits(PhyDev, 20, 15, 1, 1);
+
+ /* Reset page selection */
+ Mdio->Write (Mdio, PhyDev->Addr, PhyDev->MdioIndex, 22, 0x0000);
+ gBS->Stall(100);
+ }
+
+ MvPhyM88e1111sConfig (PhyDev);
+
+ /* autonegotiation on startup is not always required */
+ if (!PcdGetBool (PcdPhyStartupAutoneg))
+ return EFI_SUCCESS;
+
+ Mdio->Read (Mdio, PhyDev->Addr, PhyDev->MdioIndex, 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_AUTONEGOTIATE_TIMEOUT) {
+ DEBUG((DEBUG_ERROR, "timeout\n"));
+ PhyDev->LinkUp = FALSE;
+ return EFI_TIMEOUT;
+ }
+
+ gBS->Stall(1000); /* 1 ms */
+ Mdio->Read (Mdio, PhyDev->Addr, PhyDev->MdioIndex, MII_BMSR, &Data);
+ }
+ PhyDev->LinkUp = TRUE;
+ DEBUG((DEBUG_INFO, "MvPhyDxe: link up\n"));
+ } else {
+ Mdio->Read (Mdio, PhyDev->Addr, PhyDev->MdioIndex, 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 PhyIndex,
+ IN PHY_CONNECTION PhyConnection,
+ IN OUT PHY_DEVICE **OutPhyDev
+ )
+{
+ EFI_STATUS Status;
+ PHY_DEVICE *PhyDev;
+ UINT8 *DeviceIds;
+ UINT8 MdioIndex;
+ INTN i;
+
+ Status = gBS->LocateProtocol (
+ &gMarvellMdioProtocolGuid,
+ NULL,
+ (VOID **) &Mdio
+ );
+ if (EFI_ERROR(Status))
+ return Status;
+
+ MdioIndex = Phy2MdioController[PhyIndex];
+
+ /* Verify correctness of PHY <-> MDIO assignment */
+ if (!MVHW_DEV_ENABLED (Mdio, MdioIndex) || MdioIndex >= Mdio->ControllerCount) {
+ DEBUG ((DEBUG_ERROR, "MvPhyDxe: Incorrect Mdio controller assignment for PHY#%d", PhyIndex));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ /* perform setup common for all PHYs */
+ PhyDev = AllocateZeroPool (sizeof (PHY_DEVICE));
+ PhyDev->Addr = PhySmiAddresses[PhyIndex];
+ PhyDev->Connection = PhyConnection;
+ DEBUG((DEBUG_INFO, "MvPhyDxe: PhyAddr is %d, connection %d\n",
+ PhyDev->Addr, 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, 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, PhyDev->MdioIndex, MII_BMSR, &Data);
+ Mdio->Read (Mdio, PhyDev->Addr, PhyDev->MdioIndex, 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/Silicon/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.h b/Silicon/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.h
new file mode 100644
index 0000000000..66974bba4b
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.h
@@ -0,0 +1,100 @@
+/********************************************************************************
+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 */
+
+/* BMCR */
+#define BMCR_ANRESTART 0x0200 /* 1 = Restart autonegotiation */
+#define BMCR_ISOLATE 0x0400 /* 0 = Isolate PHY */
+#define BMCR_ANENABLE 0x1000 /* 1 = Enable autonegotiation */
+#define BMCR_RESET 0x8000 /* 1 = Reset the PHY */
+
+/* BSMR */
+#define BMSR_LSTATUS 0x0004 /* 1 = Link up */
+#define BMSR_ANEGCAPABLE 0x0008 /* 1 = Able to perform auto-neg */
+#define BMSR_ANEGCOMPLETE 0x0020 /* 1 = Auto-neg complete */
+
+#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
+
+/* 88E1111 Extended PHY Specific Control Register */
+#define MIIM_88E1111_PHY_EXT_CR 0x14
+#define MIIM_88E1111_RX_DELAY 0x80
+#define MIIM_88E1111_TX_DELAY 0x02
+
+/* 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
+
+typedef enum {
+ MV_PHY_DEVICE_1512
+} MV_PHY_DEVICE_ID;
+
+typedef
+EFI_STATUS
+(*MV_PHY_DEVICE_INIT) (
+ IN CONST MARVELL_PHY_PROTOCOL *Snp,
+ 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 OUT PHY_DEVICE *PhyDev
+ );
+
+#endif
diff --git a/Silicon/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.inf b/Silicon/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.inf
new file mode 100644
index 0000000000..fe0f55478b
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.inf
@@ -0,0 +1,73 @@
+# 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
+ Silicon/Marvell/Marvell.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ IoLib
+ PcdLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+
+[Protocols]
+ gMarvellMdioProtocolGuid
+ gMarvellPhyProtocolGuid
+
+[Pcd]
+ gMarvellTokenSpaceGuid.PcdMdioControllersEnabled
+ gMarvellTokenSpaceGuid.PcdPhy2MdioController
+ gMarvellTokenSpaceGuid.PcdPhyDeviceIds
+ gMarvellTokenSpaceGuid.PcdPhySmiAddresses
+ gMarvellTokenSpaceGuid.PcdPhyStartupAutoneg
+
+[Depex]
+ TRUE
diff --git a/Silicon/Marvell/Drivers/Net/Pp2Dxe/Mvpp2Lib.c b/Silicon/Marvell/Drivers/Net/Pp2Dxe/Mvpp2Lib.c
new file mode 100644
index 0000000000..0c9f00c04a
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Net/Pp2Dxe/Mvpp2Lib.c
@@ -0,0 +1,5023 @@
+/********************************************************************************
+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(Pool));
+ }
+
+ 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;
+ case MV_MODE_SFI:
+ /* Configure PCS */
+ MvGopXpcsModeCfg (Port, MVPP2_SFI_LANE_COUNT);
+
+ MvGopMpcsModeCfg (Port);
+
+ /* Configure MAC */
+ MvGopXlgMacModeCfg (Port);
+
+ /* PCS unreset */
+ MvGopXpcsUnreset (Port);
+
+ /* MAC unreset */
+ MvGopXlgMacUnreset (Port);
+ 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;
+}
+
+/* Set the internal mux's to the required PCS */
+EFI_STATUS
+MvGopXpcsModeCfg (
+ IN PP2DXE_PORT *Port,
+ IN INT32 NumOfLanes
+ )
+{
+ UINT8 LaneCoeff;
+
+ switch (NumOfLanes) {
+ case 1:
+ case 2:
+ case 4:
+ LaneCoeff = NumOfLanes >> 1;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ /* Configure XG MAC mode */
+ MmioAndThenOr32 (Port->Priv->XpcsBase + MVPP22_XPCS_GLOBAL_CFG_0_REG,
+ ~(MVPP22_XPCS_PCSMODE_MASK | MVPP22_XPCS_LANEACTIVE_MASK),
+ LaneCoeff << MVPP22_XPCS_LANEACTIVE_OFFS);
+
+ return EFI_SUCCESS;
+}
+
+VOID
+MvGopMpcsModeCfg (
+ IN PP2DXE_PORT *Port
+ )
+{
+ /* Configure MPCS40G COMMON CONTROL */
+ MmioAnd32 (Port->Priv->MpcsBase + MVPP22_MPCS40G_COMMON_CONTROL,
+ ~MVPP22_MPCS_FORWARD_ERROR_CORRECTION_MASK);
+
+ /* Configure MPCS CLOCK RESET */
+ MmioAndThenOr32 (Port->Priv->MpcsBase + MVPP22_MPCS_CLOCK_RESET,
+ ~(MVPP22_MPCS_CLK_DIVISION_RATIO_MASK | MVPP22_MPCS_CLK_DIV_PHASE_SET_MASK),
+ MVPP22_MPCS_CLK_DIVISION_RATIO_DEFAULT | MVPP22_MPCS_MAC_CLK_RESET_MASK |
+ MVPP22_MPCS_RX_SD_CLK_RESET_MASK | MVPP22_MPCS_TX_SD_CLK_RESET_MASK);
+}
+
+/* Set the internal mux's to the required MAC in the GOP */
+VOID
+MvGopXlgMacModeCfg (
+ IN PP2DXE_PORT *Port
+ )
+{
+ /* Configure 10G MAC mode */
+ MmioOr32 (Port->XlgBase + MV_XLG_PORT_MAC_CTRL0_REG, MV_XLG_MAC_CTRL0_RXFCEN_MASK);
+
+ MmioAndThenOr32 (Port->XlgBase + MV_XLG_PORT_MAC_CTRL3_REG,
+ ~MV_XLG_MAC_CTRL3_MACMODESELECT_MASK,
+ MV_XLG_MAC_CTRL3_MACMODESELECT_10G);
+
+ MmioAndThenOr32 (Port->XlgBase + MV_XLG_PORT_MAC_CTRL4_REG,
+ ~(MV_XLG_MAC_CTRL4_MAC_MODE_DMA_1G_MASK | MV_XLG_MAC_CTRL4_EN_IDLE_CHECK_FOR_LINK_MASK),
+ MV_XLG_MAC_CTRL4_FORWARD_PFC_EN_MASK | MV_XLG_MAC_CTRL4_FORWARD_802_3X_FC_EN_MASK);
+
+ /* Configure frame size limit */
+ MmioAndThenOr32 (Port->XlgBase + MV_XLG_PORT_MAC_CTRL1_REG,
+ ~MV_XLG_MAC_CTRL1_FRAMESIZELIMIT_MASK,
+ MV_XLG_MAC_CTRL1_FRAMESIZELIMIT_DEFAULT);
+
+ /* Mask all port's external interrupts */
+ MvGop110XlgPortLinkEventMask (Port);
+
+ /* Unmask link change interrupt - enable automatic status update */
+ MmioOr32 (Port->XlgBase + MV_XLG_INTERRUPT_MASK_REG,
+ MV_XLG_INTERRUPT_LINK_CHANGE_MASK | MV_XLG_SUMMARY_INTERRUPT_MASK);
+}
+
+/* Set PCS to exit from reset */
+VOID
+MvGopXpcsUnreset (
+ IN PP2DXE_PORT *Port
+ )
+{
+ MmioOr32 (Port->Priv->XpcsBase + MVPP22_XPCS_GLOBAL_CFG_0_REG, MVPP22_XPCS_PCSRESET);
+}
+
+/* Set the MAC to exit from reset */
+VOID
+MvGopXlgMacUnreset (
+ IN PP2DXE_PORT *Port
+ )
+{
+ MmioOr32 (Port->XlgBase + MV_XLG_PORT_MAC_CTRL0_REG, MV_XLG_MAC_CTRL0_MACRESETN_MASK);
+}
+
+BOOLEAN
+MvGop110XlgLinkStatusGet (
+ IN PP2DXE_PORT *Port
+ )
+{
+ return MmioRead32 (Port->XlgBase + MV_XLG_MAC_PORT_STATUS_REG) & MV_XLG_MAC_PORT_STATUS_LINKSTATUS_MASK;
+}
+
+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_SFI:
+ return MvGop110XlgLinkStatusGet (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;
+}
+
+STATIC
+VOID
+MvGop110XlgPortEnable (
+ IN PP2DXE_PORT *Port
+ )
+{
+ /* Enable port and MIB counters update */
+ MmioAndThenOr32 (Port->XlgBase + MV_XLG_PORT_MAC_CTRL0_REG,
+ ~MV_XLG_MAC_CTRL0_MIBCNTDIS_MASK,
+ MV_XLG_MAC_CTRL0_PORTEN_MASK);
+}
+
+STATIC
+VOID
+MvGop110XlgPortDisable (
+ IN PP2DXE_PORT *Port
+ )
+{
+ /* Mask all port's external interrupts */
+ MvGop110XlgPortLinkEventMask (Port);
+
+ MmioAnd32 (Port->XlgBase + MV_XLG_PORT_MAC_CTRL0_REG, ~MV_XLG_MAC_CTRL0_PORTEN_MASK);
+}
+
+VOID
+MvGop110PortDisable (
+ IN PP2DXE_PORT *Port
+ )
+{
+ switch (Port->PhyInterface) {
+ case MV_MODE_RGMII:
+ case MV_MODE_SGMII:
+ case MV_MODE_QSGMII:
+ MvGop110GmacPortDisable (Port);
+ break;
+ case MV_MODE_XAUI:
+ case MV_MODE_RXAUI:
+ case MV_MODE_SFI:
+ MvGop110XlgPortDisable (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;
+ case MV_MODE_XAUI:
+ case MV_MODE_RXAUI:
+ case MV_MODE_SFI:
+ MvGop110XlgPortEnable (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);
+}
+
+VOID
+MvGop110XlgPortLinkEventMask (
+ IN PP2DXE_PORT *Port
+ )
+{
+ MmioAnd32 (Port->XlgBase + MV_XLG_EXTERNAL_INTERRUPT_MASK_REG,
+ ~MV_XLG_EXTERNAL_INTERRUPT_LINK_CHANGE_MASK);
+}
+
+INT32
+MvGop110PortEventsMask (
+ IN PP2DXE_PORT *Port
+ )
+{
+
+ switch (Port->PhyInterface) {
+ case MV_MODE_RGMII:
+ case MV_MODE_SGMII:
+ case MV_MODE_QSGMII:
+ MvGop110GmacPortLinkEventMask (Port);
+ break;
+ case MV_MODE_XAUI:
+ case MV_MODE_RXAUI:
+ case MV_MODE_SFI:
+ MvGop110XlgPortLinkEventMask (Port);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Sets "Force Link Pass" and clears "Do Not Force Link Fail" bits.
+ * This function should only be called when the port is disabled.
+ */
+VOID
+MvGop110GmacForceLinkUp (
+ IN PP2DXE_PORT *Port
+ )
+{
+ UINT32 RegVal;
+
+ RegVal = MvGop110GmacRead (Port, MVPP2_PORT_AUTO_NEG_CFG_REG);
+
+ RegVal |= MVPP2_PORT_AUTO_NEG_CFG_FORCE_LINK_UP_MASK;
+ RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_FORCE_LINK_DOWN_MASK;
+
+ MvGop110GmacWrite (Port, MVPP2_PORT_AUTO_NEG_CFG_REG, RegVal);
+}
+
+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:
+ case MV_MODE_SFI:
+ 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:
+ case MV_MODE_SFI:
+ 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/Silicon/Marvell/Drivers/Net/Pp2Dxe/Mvpp2Lib.h b/Silicon/Marvell/Drivers/Net/Pp2Dxe/Mvpp2Lib.h
new file mode 100644
index 0000000000..3dc9ecdd20
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Net/Pp2Dxe/Mvpp2Lib.h
@@ -0,0 +1,762 @@
+/********************************************************************************
+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
+ );
+
+EFI_STATUS
+MvGopXpcsModeCfg (
+ IN PP2DXE_PORT *Port,
+ IN INT32 NumOfLanes
+ );
+
+VOID
+MvGopMpcsModeCfg (
+ IN PP2DXE_PORT *Port
+ );
+
+VOID
+MvGopXlgMacModeCfg (
+ IN PP2DXE_PORT *Port
+ );
+
+VOID
+MvGopXpcsUnreset (
+ IN PP2DXE_PORT *Port
+ );
+
+VOID
+MvGopXlgMacUnreset (
+ IN PP2DXE_PORT *Port
+ );
+
+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
+ );
+
+VOID
+MvGop110XlgPortLinkEventMask (
+ IN PP2DXE_PORT *Port
+ );
+
+VOID
+MvGop110GmacForceLinkUp (
+ 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/Silicon/Marvell/Drivers/Net/Pp2Dxe/Mvpp2LibHw.h b/Silicon/Marvell/Drivers/Net/Pp2Dxe/Mvpp2LibHw.h
new file mode 100644
index 0000000000..0ebf9367bb
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Net/Pp2Dxe/Mvpp2LibHw.h
@@ -0,0 +1,2015 @@
+/********************************************************************************
+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
+
+/* PP2v2 registers offsets */
+#define MVPP22_SMI_OFFSET 0x12a200
+#define MVPP22_MPCS_OFFSET 0x130000
+#define MVPP22_XPCS_OFFSET 0x130400
+#define MVPP22_GMAC_OFFSET 0x130e00
+#define MVPP22_GMAC_REG_SIZE 0x1000
+#define MVPP22_XLG_OFFSET 0x130f00
+#define MVPP22_XLG_REG_SIZE 0x1000
+#define MVPP22_RFU1_OFFSET 0x441000
+
+/* 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)
+
+/* XPCS registers */
+
+/* Global Configuration 0 */
+#define MVPP22_XPCS_GLOBAL_CFG_0_REG 0x0
+#define MVPP22_XPCS_PCSRESET BIT(0)
+#define MVPP22_XPCS_PCSMODE_OFFS 3
+#define MVPP22_XPCS_PCSMODE_MASK (0x3 << MVPP22_XPCS_PCSMODE_OFFS)
+#define MVPP22_XPCS_LANEACTIVE_OFFS 5
+#define MVPP22_XPCS_LANEACTIVE_MASK (0x3 << MVPP22_XPCS_LANEACTIVE_OFFS)
+
+/* MPCS registers */
+
+#define MVPP22_MPCS40G_COMMON_CONTROL 0x14
+#define MVPP22_MPCS_FORWARD_ERROR_CORRECTION_MASK BIT(10)
+
+#define MVPP22_MPCS_CLOCK_RESET 0x14c
+#define MVPP22_MPCS_TX_SD_CLK_RESET_MASK BIT(0)
+#define MVPP22_MPCS_RX_SD_CLK_RESET_MASK BIT(1)
+#define MVPP22_MPCS_MAC_CLK_RESET_MASK BIT(2)
+#define MVPP22_MPCS_CLK_DIVISION_RATIO_OFFS 4
+#define MVPP22_MPCS_CLK_DIVISION_RATIO_MASK (0x7 << MVPP22_MPCS_CLK_DIVISION_RATIO_OFFS)
+#define MVPP22_MPCS_CLK_DIVISION_RATIO_DEFAULT (0x1 << MVPP22_MPCS_CLK_DIVISION_RATIO_OFFS)
+#define MVPP22_MPCS_CLK_DIV_PHASE_SET_MASK BIT(11)
+
+/* 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 64
+
+/* 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_FRAMESIZELIMIT_DEFAULT 0x1400
+
+#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 (0x0010)
+#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)
+#define MV_XLG_MAC_CTRL3_MACMODESELECT_10G \
+ (0x00000001 << 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)
+
+#define MV_XLG_MAC_CTRL4_EN_IDLE_CHECK_FOR_LINK 14
+#define MV_XLG_MAC_CTRL4_EN_IDLE_CHECK_FOR_LINK_MASK \
+ (0x00000001 << MV_XLG_MAC_CTRL4_EN_IDLE_CHECK_FOR_LINK)
+
+/* 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_SUMMARY_INTERRUPT_OFFSET 0
+#define MV_XLG_SUMMARY_INTERRUPT_MASK \
+ (0x1 << MV_XLG_SUMMARY_INTERRUPT_OFFSET)
+#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)
+
+/* SerDes */
+#define MVPP2_SFI_LANE_COUNT 1
+
+/* 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/Silicon/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.c b/Silicon/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.c
new file mode 100644
index 0000000000..b0a38b3c90
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.c
@@ -0,0 +1,1396 @@
+/********************************************************************************
+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/MvHwDescLib.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)
+
+DECLARE_A7K8K_PP2_TEMPLATE;
+
+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 (
+ MVPP2_SHARED *Mvpp2Shared
+ )
+{
+ INTN Index;
+ UINT8 *PoolAddr;
+ UINT32 PoolSize;
+ EFI_STATUS Status;
+
+ 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);
+ }
+
+ for (Index = 0; Index < MVPP2_MAX_PORT; Index++) {
+ Mvpp2Shared->BmPools[Index] = AllocateZeroPool (sizeof(MVPP2_BMS_POOL));
+
+ if (Mvpp2Shared->BmPools[Index] == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto FreePools;
+ }
+
+ Status = DmaAllocateAlignedBuffer (EfiBootServicesData,
+ EFI_SIZE_TO_PAGES (PoolSize),
+ MVPP2_BM_POOL_PTR_ALIGN,
+ (VOID **)&PoolAddr);
+ if (EFI_ERROR (Status)) {
+ goto FreeBmPools;
+ }
+
+ ZeroMem (PoolAddr, PoolSize);
+
+ Mvpp2Shared->BmPools[Index]->Id = Index;
+ Mvpp2Shared->BmPools[Index]->VirtAddr = (UINT32 *)PoolAddr;
+ Mvpp2Shared->BmPools[Index]->PhysAddr = (UINTN)PoolAddr;
+
+ Mvpp2BmPoolHwCreate(Mvpp2Shared, Mvpp2Shared->BmPools[Index], MVPP2_BM_SIZE);
+ }
+
+ return EFI_SUCCESS;
+
+FreeBmPools:
+ FreePool (Mvpp2Shared->BmPools[Index]);
+FreePools:
+ while (Index-- >= 0) {
+ FreePool (Mvpp2Shared->BmPools[Index]);
+ DmaFreeBuffer (
+ EFI_SIZE_TO_PAGES (PoolSize),
+ Mvpp2Shared->BmPools[Index]->VirtAddr
+ );
+ }
+ return Status;
+}
+
+/* Enable and fill BM pool */
+STATIC
+EFI_STATUS
+Pp2DxeBmStart (
+ MVPP2_SHARED *Mvpp2Shared
+ )
+{
+ UINT8 *Buff, *BuffPhys;
+ INTN Index, Pool;
+
+ ASSERT(BM_ALIGN >= sizeof(UINTN));
+
+ for (Pool = 0; Pool < MVPP2_MAX_PORT; Pool++) {
+ Mvpp2BmPoolCtrl(Mvpp2Shared, Pool, MVPP2_START);
+ Mvpp2BmPoolBufsizeSet(Mvpp2Shared, Mvpp2Shared->BmPools[Pool], RX_BUFFER_SIZE);
+
+ /* Fill BM pool with Buffers */
+ for (Index = 0; Index < MVPP2_BM_SIZE; Index++) {
+ Buff = (UINT8 *)(Mvpp2Shared->BufferLocation.RxBuffers[Pool] + (Index * RX_BUFFER_SIZE));
+ if (Buff == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ BuffPhys = ALIGN_POINTER(Buff, BM_ALIGN);
+ Mvpp2BmPoolPut(Mvpp2Shared, 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;
+ MVPP2_SHARED *Mvpp2Shared = Pp2Context->Port.Priv;
+
+ 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;
+ MVPP2_SHARED *Mvpp2Shared = Pp2Context->Port.Priv;
+ 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;
+ MVPP2_SHARED *Mvpp2Shared = Pp2Context->Port.Priv;
+ 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 = Mvpp2Shared->BufferLocation.TxDescs[Port->Id];
+
+ 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 = Mvpp2Shared->BufferLocation.RxDescs[Port->Id];
+
+ 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, Port->Id);
+ Mvpp2RxqShortPoolSet(Port, 0, Port->Id);
+
+ /*
+ * 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;
+
+ Status = gBS->LocateProtocol (
+ &gMarvellPhyProtocolGuid,
+ NULL,
+ (VOID **) &Pp2Context->Phy
+ );
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ if (Pp2Context->Port.PhyIndex == 0xff) {
+ /* PHY iniitalization not required */
+ return EFI_SUCCESS;
+ }
+
+ Status = Pp2Context->Phy->Init(
+ Pp2Context->Phy,
+ Pp2Context->Port.PhyIndex,
+ 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;
+ MVPP2_SHARED *Mvpp2Shared = Pp2Context->Port.Priv;
+ STATIC BOOLEAN CommonPartHalted = FALSE;
+ INTN Index;
+
+ if (!CommonPartHalted) {
+ for (Index = 0; Index < MVPP2_MAX_PORT; Index++) {
+ Mvpp2BmStop(Mvpp2Shared, Index);
+ }
+
+ 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;
+ MVPP2_SHARED *Mvpp2Shared = Pp2Context->Port.Priv;
+ 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_SHARED *Mvpp2Shared = Pp2Context->Port.Priv;
+ 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;
+ MVPP2_SHARED *Mvpp2Shared = Pp2Context->Port.Priv;
+ 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,
+ IN INTN Index
+ )
+{
+ UINT8 *PortIds, *GopIndexes, *PhyConnectionTypes, *AlwaysUp, *Speed, *PhyIndexes;
+
+ PortIds = PcdGetPtr (PcdPp2PortIds);
+ GopIndexes = PcdGetPtr (PcdPp2GopIndexes);
+ PhyConnectionTypes = PcdGetPtr (PcdPp2PhyConnectionTypes);
+ PhyIndexes = PcdGetPtr (PcdPp2PhyIndexes);
+ AlwaysUp = PcdGetPtr (PcdPp2InterfaceAlwaysUp);
+ Speed = PcdGetPtr (PcdPp2InterfaceSpeed);
+
+ ASSERT (PcdGetSize (PcdPp2GopIndexes) == PcdGetSize (PcdPp2PortIds));
+ ASSERT (PcdGetSize (PcdPp2PhyConnectionTypes) == PcdGetSize (PcdPp2PortIds));
+ ASSERT (PcdGetSize (PcdPp2InterfaceAlwaysUp) == PcdGetSize (PcdPp2PortIds));
+ ASSERT (PcdGetSize (PcdPp2InterfaceSpeed) == PcdGetSize (PcdPp2PortIds));
+ ASSERT (PcdGetSize (PcdPp2PhyIndexes) == PcdGetSize (PcdPp2PortIds));
+
+ Pp2Context->Port.Id = PortIds[Index];
+ Pp2Context->Port.GopIndex = GopIndexes[Index];
+ Pp2Context->Port.PhyInterface = PhyConnectionTypes[Index];
+ Pp2Context->Port.PhyIndex = PhyIndexes[Index];
+ Pp2Context->Port.AlwaysUp = AlwaysUp[Index];
+ Pp2Context->Port.Speed = Speed[Index];
+}
+
+STATIC
+EFI_STATUS
+Pp2DxeInitialiseController (
+ IN UINT8 ControllerIndex,
+ IN MVPP2_SHARED *Mvpp2Shared,
+ IN UINTN BaseAddress,
+ IN UINTN ClockFrequency
+ )
+{
+ PP2DXE_CONTEXT *Pp2Context = NULL;
+ EFI_STATUS Status;
+ INTN Index;
+ INTN PortIndex = 0;
+ VOID *BufferSpace;
+ UINT32 NetCompConfig = 0;
+ STATIC UINT8 DeviceInstance;
+ UINT8 *Pp2PortMappingTable;
+
+ Mvpp2Shared->Base = BaseAddress;
+ Mvpp2Shared->Rfu1Base = Mvpp2Shared->Base + MVPP22_RFU1_OFFSET;
+ Mvpp2Shared->XpcsBase = Mvpp2Shared->Base + MVPP22_XPCS_OFFSET;
+ Mvpp2Shared->MpcsBase = Mvpp2Shared->Base + MVPP22_MPCS_OFFSET;
+ Mvpp2Shared->SmiBase = Mvpp2Shared->Base + MVPP22_SMI_OFFSET;
+ Mvpp2Shared->Tclk = ClockFrequency;
+
+ /* Prepare buffers */
+ Status = DmaAllocateAlignedBuffer (EfiBootServicesData,
+ EFI_SIZE_TO_PAGES (BD_SPACE),
+ MVPP2_BUFFER_ALIGN_SIZE,
+ &BufferSpace);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to allocate buffer space\n"));
+ return Status;
+ }
+
+ ZeroMem (BufferSpace, BD_SPACE);
+
+ for (Index = 0; Index < MVPP2_MAX_PORT; Index++) {
+ Mvpp2Shared->BufferLocation.TxDescs[Index] = (MVPP2_TX_DESC *)
+ (BufferSpace + Index * MVPP2_MAX_TXD * sizeof(MVPP2_TX_DESC));
+ }
+
+ Mvpp2Shared->BufferLocation.AggrTxDescs = (MVPP2_TX_DESC *)
+ ((UINTN)BufferSpace + MVPP2_MAX_TXD * MVPP2_MAX_PORT * sizeof(MVPP2_TX_DESC));
+
+ for (Index = 0; Index < MVPP2_MAX_PORT; Index++) {
+ Mvpp2Shared->BufferLocation.RxDescs[Index] = (MVPP2_RX_DESC *)
+ ((UINTN)BufferSpace + (MVPP2_MAX_TXD * MVPP2_MAX_PORT + MVPP2_AGGR_TXQ_SIZE) *
+ sizeof(MVPP2_TX_DESC) + Index * MVPP2_MAX_RXD * sizeof(MVPP2_RX_DESC));
+ }
+
+ for (Index = 0; Index < MVPP2_MAX_PORT; Index++) {
+ Mvpp2Shared->BufferLocation.RxBuffers[Index] = (DmaAddrT)
+ (BufferSpace + (MVPP2_MAX_TXD * MVPP2_MAX_PORT + MVPP2_AGGR_TXQ_SIZE) *
+ sizeof(MVPP2_TX_DESC) + MVPP2_MAX_RXD * MVPP2_MAX_PORT * sizeof(MVPP2_RX_DESC) +
+ Index * MVPP2_BM_SIZE * RX_BUFFER_SIZE);
+ }
+
+ /* Initialize HW */
+ Mvpp2AxiConfig(Mvpp2Shared);
+ Pp2DxeBmPoolInit (Mvpp2Shared);
+ 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 (Mvpp2Shared);
+ 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 = Mvpp2Shared->BufferLocation.AggrTxDescs;
+ Mvpp2Shared->AggrTxqs->Id = 0;
+ Mvpp2Shared->AggrTxqs->LogId = 0;
+ Mvpp2Shared->AggrTxqs->Size = MVPP2_AGGR_TXQ_SIZE;
+
+ Pp2PortMappingTable = (UINT8 *)PcdGetPtr (PcdPp2Port2Controller);
+
+ for (Index = 0; Index < PcdGetSize (PcdPp2Port2Controller); Index++) {
+ if (Pp2PortMappingTable[Index] != ControllerIndex) {
+ continue;
+ }
+
+ if (PortIndex++ > MVPP2_MAX_PORT) {
+ DEBUG ((DEBUG_ERROR, "Pp2Dxe: Wrong too many ports for single controller\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ 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 = DeviceInstance;
+ DeviceInstance++;
+
+ /* Install SNP protocol */
+ Status = Pp2DxeSnpInstall(Pp2Context);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ Pp2DxeParsePortPcd(Pp2Context, Index);
+ Pp2Context->Port.TxpNum = 1;
+ Pp2Context->Port.Priv = Mvpp2Shared;
+ Pp2Context->Port.FirstRxq = 4 * (PortIndex - 1);
+ Pp2Context->Port.GmacBase = Mvpp2Shared->Base + MVPP22_GMAC_OFFSET +
+ MVPP22_GMAC_REG_SIZE * Pp2Context->Port.GopIndex;
+ Pp2Context->Port.XlgBase = Mvpp2Shared->Base + MVPP22_XLG_OFFSET +
+ MVPP22_XLG_REG_SIZE * Pp2Context->Port.GopIndex;
+
+ /* Gather accumulated configuration data of all ports' MAC's */
+ NetCompConfig |= MvpPp2xGop110NetcCfgCreate(&Pp2Context->Port);
+
+ MvGop110PortInit(&Pp2Context->Port);
+
+ if (Pp2Context->Port.AlwaysUp == TRUE) {
+ MvGop110GmacForceLinkUp (&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;
+}
+
+EFI_STATUS
+EFIAPI
+Pp2DxeInitialise (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ MVHW_PP2_DESC *Desc = &mA7k8kPp2DescTemplate;
+ UINT8 *Pp2DeviceTable, Index;
+ MVPP2_SHARED *Mvpp2Shared;
+ EFI_STATUS Status;
+
+ /* Obtain table with enabled Pp2 devices */
+ Pp2DeviceTable = (UINT8 *)PcdGetPtr (PcdPp2Controllers);
+ if (Pp2DeviceTable == NULL) {
+ DEBUG ((DEBUG_ERROR, "Missing PcdPp2Controllers\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (PcdGetSize (PcdPp2Controllers) > MVHW_MAX_PP2_DEVS) {
+ DEBUG ((DEBUG_ERROR, "Wrong PcdPp2Controllers format\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ /* Check amount of declared ports */
+ if (PcdGetSize (PcdPp2Port2Controller) > Desc->Pp2DevCount * MVPP2_MAX_PORT) {
+ DEBUG ((DEBUG_ERROR, "Pp2Dxe: Wrong too many ports declared\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ /* Initialize enabled chips */
+ for (Index = 0; Index < PcdGetSize (PcdPp2Controllers); Index++) {
+ if (!MVHW_DEV_ENABLED (Pp2, Index)) {
+ DEBUG ((DEBUG_ERROR, "Skip Pp2 controller %d\n", Index));
+ continue;
+ }
+
+ /* Initialize private data */
+ Mvpp2Shared = AllocateZeroPool (sizeof (MVPP2_SHARED));
+ if (Mvpp2Shared == NULL) {
+ DEBUG ((DEBUG_ERROR, "Pp2Dxe #%d: Mvpp2Shared allocation fail\n", Index));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = Pp2DxeInitialiseController (
+ Index,
+ Mvpp2Shared,
+ Desc->Pp2BaseAddresses[Index],
+ Desc->Pp2ClockFrequency[Index]
+ );
+ if (EFI_ERROR(Status)) {
+ FreePool (Mvpp2Shared);
+ DEBUG ((DEBUG_ERROR, "Pp2Dxe #%d: Controller initialisation fail\n", Index));
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.h b/Silicon/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.h
new file mode 100644
index 0000000000..60f40be1f5
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.h
@@ -0,0 +1,622 @@
+/********************************************************************************
+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/DmaLib.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"
+
+#define MVPP2_MAX_PORT 3
+
+#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_SFI PHY_CONNECTION_SFI
+#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 64
+
+/*
+ * 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;
+
+/* Structure for preallocation for buffer */
+typedef struct {
+ MVPP2_TX_DESC *TxDescs[MVPP2_MAX_PORT];
+ MVPP2_TX_DESC *AggrTxDescs;
+ MVPP2_RX_DESC *RxDescs[MVPP2_MAX_PORT];
+ DmaAddrT RxBuffers[MVPP2_MAX_PORT];
+} BUFFER_LOCATION;
+
+/* Shared Packet Processor resources */
+typedef struct {
+ /* Shared registers' base addresses */
+ UINT64 Base;
+ UINT64 MpcsBase;
+ UINT64 Rfu1Base;
+ UINT64 SmiBase;
+ UINT64 XpcsBase;
+
+ /* Preallocated buffers */
+ BUFFER_LOCATION BufferLocation;
+
+ /* List of pointers to Port structures */
+ PP2DXE_PORT **PortList;
+
+ /* Aggregated TXQs */
+ MVPP2_TX_QUEUE *AggrTxqs;
+
+ /* BM pools */
+ MVPP2_BMS_POOL *BmPools[MVPP2_MAX_PORT];
+
+ /* 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;
+ UINT32 PhyIndex;
+ 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;
+};
+
+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/Silicon/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.inf b/Silicon/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.inf
new file mode 100644
index 0000000000..fcd0611b4d
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.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 = 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]
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ ArmPkg/ArmPkg.dec
+ Silicon/Marvell/Marvell.dec
+
+[LibraryClasses]
+ DmaLib
+ IoLib
+ PcdLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ UefiLib
+ NetLib
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ CacheMaintenanceLib
+
+[Protocols]
+ gEfiSimpleNetworkProtocolGuid
+ gEfiDevicePathProtocolGuid
+ gEfiCpuArchProtocolGuid
+ gMarvellMdioProtocolGuid
+ gMarvellPhyProtocolGuid
+
+[Pcd]
+ gMarvellTokenSpaceGuid.PcdPp2Controllers
+ gMarvellTokenSpaceGuid.PcdPp2GopIndexes
+ gMarvellTokenSpaceGuid.PcdPp2InterfaceAlwaysUp
+ gMarvellTokenSpaceGuid.PcdPp2InterfaceSpeed
+ gMarvellTokenSpaceGuid.PcdPp2PhyConnectionTypes
+ gMarvellTokenSpaceGuid.PcdPp2PhyIndexes
+ gMarvellTokenSpaceGuid.PcdPp2Port2Controller
+ gMarvellTokenSpaceGuid.PcdPp2PortIds
+
+[Depex]
+ TRUE
diff --git a/Silicon/Marvell/Drivers/SdMmc/XenonDxe/ComponentName.c b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/ComponentName.c
new file mode 100644
index 0000000000..3329929119
--- /dev/null
+++ b/Silicon/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/Silicon/Marvell/Drivers/SdMmc/XenonDxe/EmmcDevice.c b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/EmmcDevice.c
new file mode 100755
index 0000000000..530a01ccdc
--- /dev/null
+++ b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/EmmcDevice.c
@@ -0,0 +1,1164 @@
+/** @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->BaseClkFreq[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 = BIT1;
+ } else if (ClockFreq == 26) {
+ 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->BaseClkFreq[Slot] != 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/Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdDevice.c b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdDevice.c
new file mode 100644
index 0000000000..ea7eed717f
--- /dev/null
+++ b/Silicon/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, Private->BaseClkFreq[Slot]);
+ 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->BaseClkFreq[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/Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.c b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.c
new file mode 100644
index 0000000000..80159a4f5d
--- /dev/null
+++ b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.c
@@ -0,0 +1,1320 @@
+/** @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],
+ Private->BaseClkFreq[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;
+
+ //
+ // Override inappropriate base clock frequency from Capabilities Register 1.
+ // Actual clock speed of Xenon controller is 400MHz.
+ //
+ Private->BaseClkFreq[Slot] = XENON_MMC_MAX_CLK / 1000 / 1000;
+
+ DumpCapabilityReg (Slot, &Private->Capability[Slot], Private->BaseClkFreq[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/Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.h b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.h
new file mode 100644
index 0000000000..067b9acf61
--- /dev/null
+++ b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.h
@@ -0,0 +1,791 @@
+/** @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;
+
+ //
+ // Some controllers may require to override base clock frequency
+ // value stored in Capabilities Register 1.
+ //
+ UINT32 BaseClkFreq[SD_MMC_HC_MAX_SLOT];
+} 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/Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.inf b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.inf
new file mode 100644
index 0000000000..fad9fc610e
--- /dev/null
+++ b/Silicon/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/Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.uni b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.uni
new file mode 100644
index 0000000000..57f9fa76a1
--- /dev/null
+++ b/Silicon/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/Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxeExtra.uni b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxeExtra.uni
new file mode 100644
index 0000000000..c7aedb4cda
--- /dev/null
+++ b/Silicon/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/Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHci.c b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHci.c
new file mode 100644
index 0000000000..1f4abd18a6
--- /dev/null
+++ b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHci.c
@@ -0,0 +1,1928 @@
+/** @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.
+ @param[in] BaseClkFreq The base clock frequency of host controller in MHz.
+
+**/
+VOID
+DumpCapabilityReg (
+ IN UINT8 Slot,
+ IN SD_MMC_HC_SLOT_CAP *Capability,
+ IN UINT32 BaseClkFreq
+ )
+{
+ //
+ // 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"));
+ if (Capability->BaseClkFreq != BaseClkFreq) {
+ DEBUG ((DEBUG_INFO, " Controller register value overriden:\n"));
+ }
+ DEBUG ((DEBUG_INFO, " Base Clk Freq %dMHz\n", 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] BaseClkFreq The base clock frequency of host controller in MHz.
+
+ @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 UINT32 BaseClkFreq
+ )
+{
+ EFI_STATUS Status;
+ UINT32 SettingFreq;
+ UINT32 Divisor;
+ UINT32 Remainder;
+ UINT16 ControllerVer;
+ UINT16 ClockCtrl;
+
+ //
+ // Calculate a divisor for SD clock frequency
+ //
+ ASSERT (BaseClkFreq != 0);
+
+ 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] BaseClkFreq The base clock frequency of host controller in MHz.
+
+ @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 UINT32 BaseClkFreq
+ )
+{
+ EFI_STATUS Status;
+ UINT32 InitFreq;
+
+ //
+ // Calculate a divisor for SD clock frequency
+ //
+ if (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, BaseClkFreq);
+ 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.
+ @param[in] BaseClkFreq The base clock frequency of host controller in MHz.
+
+ @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,
+ IN UINT32 BaseClkFreq
+ )
+{
+ EFI_STATUS Status;
+
+ Status = SdMmcHcInitClockFreq (PciIo, Slot, BaseClkFreq);
+ 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/Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHci.h b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHci.h
new file mode 100644
index 0000000000..533f37c79f
--- /dev/null
+++ b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHci.h
@@ -0,0 +1,550 @@
+/** @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.
+ @param[in] BaseClkFreq The base clock frequency of host controller in MHz.
+
+**/
+VOID
+DumpCapabilityReg (
+ IN UINT8 Slot,
+ IN SD_MMC_HC_SLOT_CAP *Capability,
+ IN UINT32 BaseClkFreq
+ );
+
+/**
+ 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] BaseClkFreq The base clock frequency of host controller in MHz.
+
+ @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 UINT32 BaseClkFreq
+ );
+
+/**
+ 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] BaseClkFreq The base clock frequency of host controller in MHz.
+
+ @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 UINT32 BaseClkFreq
+ );
+
+/**
+ 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.
+ @param[in] BaseClkFreq The base clock frequency of host controller in MHz.
+
+ @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,
+ IN UINT32 BaseClkFreq
+ );
+
+#endif
diff --git a/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.c b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.c
new file mode 100755
index 0000000000..6bbe5bc675
--- /dev/null
+++ b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.c
@@ -0,0 +1,649 @@
+/*******************************************************************************
+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);
+}
+
+// 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);
+
+ // 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/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.h b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.h
new file mode 100644
index 0000000000..2be0ee61e1
--- /dev/null
+++ b/Silicon/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/Silicon/Marvell/Drivers/Spi/Devices/MvSpiFlash.c b/Silicon/Marvell/Drivers/Spi/Devices/MvSpiFlash.c
new file mode 100755
index 0000000000..6886d0104a
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Spi/Devices/MvSpiFlash.c
@@ -0,0 +1,599 @@
+/*******************************************************************************
+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"
+
+STATIC EFI_EVENT mMvSpiFlashVirtualAddrChangeEvent;
+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 PollBit = STATUS_REG_POLL_WIP;
+ UINT8 CheckStatus = 0x0;
+
+ if (Slave->Info->Flags & NOR_FLASH_WRITE_FSR) {
+ CmdStatus = CMD_FLAG_STATUS;
+ PollBit = STATUS_REG_POLL_PEC;
+ CheckStatus = STATUS_REG_POLL_PEC;
+ }
+
+ // 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 & PollBit) == CheckStatus)
+ 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;
+
+ /* Update bank selection command for Spansion */
+ if (Slave->Info->Id[0] == NOR_FLASH_ID_SPANSION) {
+ Cmd = CMD_BANKADDR_BRWR;
+ }
+
+ 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 EraseAddr;
+ UINTN EraseSize;
+ UINT8 Cmd[5];
+
+ if (Slave->Info->Flags & NOR_FLASH_ERASE_4K) {
+ Cmd[0] = CMD_ERASE_4K;
+ EraseSize = SIZE_4KB;
+ } else if (Slave->Info->Flags & NOR_FLASH_ERASE_32K) {
+ Cmd[0] = CMD_ERASE_32K;
+ EraseSize = SIZE_32KB;
+ } else {
+ Cmd[0] = CMD_ERASE_64K;
+ EraseSize = Slave->Info->SectorSize;
+ }
+
+ // 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;
+ }
+
+ while (Length) {
+ EraseAddr = Offset;
+
+ SpiFlashBank (Slave, EraseAddr);
+
+ SpiFlashFormatAddress (EraseAddr, Slave->AddrSize, Cmd);
+
+ // Programm proper erase address
+ Status = MvSpiFlashWriteCommon (Slave, Cmd, Slave->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 ReadAddr, ReadLength, RemainLength;
+ UINTN BankSel = 0;
+
+ 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, Slave->AddrSize, Cmd);
+ // Program proper read address and read data
+ Status = MvSpiFlashReadCmd (Slave, Cmd, Slave->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];
+
+ PageSize = Slave->Info->PageSize;
+
+ 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, Slave->AddrSize, Cmd);
+
+ // Program proper write address and write data
+ Status = MvSpiFlashWriteCommon (Slave, Cmd, Slave->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 SectorSize, ToUpdate, Scale = 1;
+ UINT8 *TmpBuf, *End;
+
+ SectorSize = Slave->Info->SectorSize;
+
+ End = Buf + ByteCount;
+
+ TmpBuf = (UINT8 *)AllocateZeroPool (SectorSize);
+ 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), SectorSize);
+ Print (L" \rUpdating, %d%%", 100 - (End - Buf) / Scale);
+ Status = MvSpiFlashUpdateBlock (Slave, Offset, ToUpdate, Buf, TmpBuf, SectorSize);
+
+ 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 BOOLEAN UseInRuntime
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Id[NOR_FLASH_MAX_ID_LEN];
+ UINT8 Cmd;
+
+ Cmd = CMD_READ_ID;
+ Status = SpiMasterProtocol->ReadWrite (SpiMasterProtocol,
+ SpiDev,
+ &Cmd,
+ SPI_CMD_LEN,
+ NULL,
+ Id,
+ NOR_FLASH_MAX_ID_LEN);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ReadId: Spi transfer error\n"));
+ return Status;
+ }
+
+ Status = NorFlashGetInfo (Id, &SpiDev->Info, UseInRuntime);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Unrecognized JEDEC Id bytes: 0x%02x%02x%02x\n",
+ __FUNCTION__,
+ Id[0],
+ Id[1],
+ Id[2]));
+ return Status;
+ }
+
+ NorFlashPrintInfo (SpiDev->Info);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+MvSpiFlashInit (
+ IN MARVELL_SPI_FLASH_PROTOCOL *This,
+ IN SPI_DEVICE *Slave
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Cmd, StatusRegister;
+
+ if (Slave->Info->Flags & NOR_FLASH_4B_ADDR) {
+ Slave->AddrSize = 4;
+ } else {
+ Slave->AddrSize = 3;
+ }
+
+ if (Slave->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;
+}
+
+/**
+ 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
+**/
+STATIC
+VOID
+EFIAPI
+MvSpiFlashVirtualNotifyEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // Convert SpiMasterProtocol callbacks in MvSpiFlashErase and
+ // MvSpiFlashWrite required by runtime variable support.
+ //
+ EfiConvertPointer (0x0, (VOID**)&SpiMasterProtocol->ReadWrite);
+ EfiConvertPointer (0x0, (VOID**)&SpiMasterProtocol->Transfer);
+ EfiConvertPointer (0x0, (VOID**)&SpiMasterProtocol);
+
+ return;
+}
+
+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 = AllocateRuntimeZeroPool (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)) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Cannot install SPI flash protocol\n"));
+ goto ErrorInstallProto;
+ }
+
+ //
+ // Register for the virtual address change event
+ //
+ Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ MvSpiFlashVirtualNotifyEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mMvSpiFlashVirtualAddrChangeEvent);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to register VA change event\n", __FUNCTION__));
+ goto ErrorCreateEvent;
+ }
+
+ return EFI_SUCCESS;
+
+ErrorCreateEvent:
+ gBS->UninstallMultipleProtocolInterfaces (&mSpiFlashInstance->Handle,
+ &gMarvellSpiFlashProtocolGuid,
+ NULL);
+
+ErrorInstallProto:
+ FreePool (mSpiFlashInstance);
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/Marvell/Drivers/Spi/Devices/MvSpiFlash.h b/Silicon/Marvell/Drivers/Spi/Devices/MvSpiFlash.h
new file mode 100755
index 0000000000..f69c562190
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Spi/Devices/MvSpiFlash.h
@@ -0,0 +1,138 @@
+/*******************************************************************************
+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 <Library/UefiRuntimeLib.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_BANKADDR_BRWR 0x17
+#define CMD_ERASE_4K 0x20
+#define CMD_ERASE_32K 0x52
+#define CMD_ERASE_64K 0xd8
+#define CMD_4B_ADDR_ENABLE 0xb7
+
+#define SPI_CMD_LEN 1
+
+#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/Silicon/Marvell/Drivers/Spi/Devices/MvSpiFlash.inf b/Silicon/Marvell/Drivers/Spi/Devices/MvSpiFlash.inf
new file mode 100644
index 0000000000..bc88a7ea98
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Spi/Devices/MvSpiFlash.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 = SpiFlashDxe
+ FILE_GUID = 49d7fb74-306d-42bd-94c8-c0c54b181dd7
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = MvSpiFlashEntryPoint
+
+[Sources]
+ MvSpiFlash.c
+ MvSpiFlash.h
+
+[Packages]
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/Marvell/Marvell.dec
+
+[LibraryClasses]
+ NorFlashInfoLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ TimerLib
+ UefiLib
+ DebugLib
+ MemoryAllocationLib
+ UefiRuntimeLib
+
+[Guids]
+ gEfiEventVirtualAddressChangeGuid
+
+[Protocols]
+ gMarvellSpiMasterProtocolGuid
+ gMarvellSpiFlashProtocolGuid
+
+[Depex]
+ #
+ # MvSpiFlashDxe must be loaded prior to variables driver MvFvbDxe
+ #
+ BEFORE gMarvellFvbDxeGuid
diff --git a/Silicon/Marvell/Drivers/Spi/MvSpiDxe.c b/Silicon/Marvell/Drivers/Spi/MvSpiDxe.c
new file mode 100755
index 0000000000..bab6cf4d56
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Spi/MvSpiDxe.c
@@ -0,0 +1,432 @@
+/*******************************************************************************
+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 SPI_DEVICE *Slave,
+ IN UINT32 CpuClock,
+ IN UINT32 MaxFreq
+ )
+{
+ UINT32 Spr, BestSpr, Sppr, BestSppr, ClockDivider, Match, Reg, MinBaudDiff;
+ UINTN SpiRegBase = Slave->HostRegisterBaseAddress;
+
+ 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 (
+ IN SPI_DEVICE *Slave
+ )
+{
+ UINT32 Reg;
+ UINTN SpiRegBase = Slave->HostRegisterBaseAddress;
+
+ Reg = MmioRead32 (SpiRegBase + SPI_CTRL_REG);
+ Reg &= ~SPI_CS_NUM_MASK;
+ Reg |= (Slave->Cs << SPI_CS_NUM_OFFSET);
+ MmioWrite32 (SpiRegBase + SPI_CTRL_REG, Reg);
+}
+
+STATIC
+VOID
+SpiActivateCs (
+ IN SPI_DEVICE *Slave
+ )
+{
+ UINT32 Reg;
+ UINTN SpiRegBase = Slave->HostRegisterBaseAddress;
+
+ SpiSetCs(Slave);
+ Reg = MmioRead32 (SpiRegBase + SPI_CTRL_REG);
+ Reg |= SPI_CS_EN_MASK;
+ MmioWrite32(SpiRegBase + SPI_CTRL_REG, Reg);
+}
+
+STATIC
+VOID
+SpiDeactivateCs (
+ IN SPI_DEVICE *Slave
+ )
+{
+ UINT32 Reg;
+ UINTN SpiRegBase = Slave->HostRegisterBaseAddress;
+
+ 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, CoreClock, SpiMaxFreq;
+ UINTN SpiRegBase;
+
+ SpiMaster = SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This);
+
+ // Initialize values from PCDs
+ SpiRegBase = Slave->HostRegisterBaseAddress;
+ CoreClock = Slave->CoreClock;
+ SpiMaxFreq = Slave->MaxFreq;
+
+ EfiAcquireLock (&SpiMaster->Lock);
+
+ Reg = MmioRead32 (SpiRegBase + SPI_CONF_REG);
+ Reg |= SPI_BYTE_LENGTH;
+ MmioWrite32 (SpiRegBase + SPI_CONF_REG, Reg);
+
+ SpiSetCs(Slave);
+
+ SpiSetBaudRate (Slave, 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;
+ UINT8 *DataOutPtr = (UINT8 *)DataOut;
+ UINT8 *DataInPtr = (UINT8 *)DataIn;
+ UINT8 DataToSend = 0;
+ UINTN SpiRegBase;
+
+ SpiMaster = SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This);
+
+ SpiRegBase = Slave->HostRegisterBaseAddress;
+
+ Length = 8 * DataByteCount;
+
+ if (!EfiAtRuntime ()) {
+ EfiAcquireLock (&SpiMaster->Lock);
+ }
+
+ if (Flag & SPI_TRANSFER_BEGIN) {
+ SpiActivateCs (Slave);
+ }
+
+ // 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)) {
+ if (DataInPtr != NULL) {
+ *DataInPtr = MmioRead32 (SpiRegBase + SPI_DATA_IN_REG);
+ DataInPtr++;
+ }
+ if (DataOutPtr != NULL) {
+ DataOutPtr++;
+ }
+ Length -= 8;
+ break;
+ }
+ }
+
+ if (Iterator >= SPI_TIMEOUT) {
+ DEBUG ((DEBUG_ERROR, "%a: Timeout\n", __FUNCTION__));
+ return EFI_TIMEOUT;
+ }
+ }
+
+ if (Flag & SPI_TRANSFER_END) {
+ SpiDeactivateCs (Slave);
+ }
+
+ if (!EfiAtRuntime ()) {
+ 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 SPI_DEVICE *Slave,
+ IN UINTN Cs,
+ IN SPI_MODE Mode
+ )
+{
+ if (!Slave) {
+ Slave = AllocateZeroPool (sizeof(SPI_DEVICE));
+ if (Slave == NULL) {
+ DEBUG((DEBUG_ERROR, "Cannot allocate memory\n"));
+ return NULL;
+ }
+
+ Slave->Cs = Cs;
+ Slave->Mode = Mode;
+ }
+
+ Slave->HostRegisterBaseAddress = PcdGet32 (PcdSpiRegBase);
+ Slave->CoreClock = PcdGet32 (PcdSpiClockFrequency);
+ Slave->MaxFreq = PcdGet32 (PcdSpiMaxFrequency);
+
+ SpiSetupTransfer (This, Slave);
+
+ return Slave;
+}
+
+EFI_STATUS
+EFIAPI
+MvSpiFreeSlave (
+ IN SPI_DEVICE *Slave
+ )
+{
+ FreePool (Slave);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+MvSpiConfigRuntime (
+ IN SPI_DEVICE *Slave
+ )
+{
+ EFI_STATUS Status;
+ UINTN AlignedAddress;
+
+ //
+ // Host register base may be not aligned to the page size,
+ // which is not accepted when setting memory space attributes.
+ // Add one aligned page of memory space which covers the host
+ // controller registers.
+ //
+ AlignedAddress = Slave->HostRegisterBaseAddress & ~(SIZE_4KB - 1);
+
+ Status = gDS->AddMemorySpace (EfiGcdMemoryTypeMemoryMappedIo,
+ AlignedAddress,
+ SIZE_4KB,
+ EFI_MEMORY_UC | EFI_MEMORY_RUNTIME);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to add memory space\n", __FUNCTION__));
+ return Status;
+ }
+
+ Status = gDS->SetMemorySpaceAttributes (AlignedAddress,
+ SIZE_4KB,
+ EFI_MEMORY_UC | EFI_MEMORY_RUNTIME);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to set memory attributes\n", __FUNCTION__));
+ gDS->RemoveMemorySpace (AlignedAddress, SIZE_4KB);
+ return Status;
+ }
+
+ 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;
+ SpiMasterProtocol->ConfigRuntime = MvSpiConfigRuntime;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SpiMasterEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ mSpiMasterInstance = AllocateRuntimeZeroPool (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/Silicon/Marvell/Drivers/Spi/MvSpiDxe.h b/Silicon/Marvell/Drivers/Spi/MvSpiDxe.h
new file mode 100644
index 0000000000..50cdc025c7
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Spi/MvSpiDxe.h
@@ -0,0 +1,148 @@
+/*******************************************************************************
+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/DxeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeLib.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 SPI_DEVICE *Slave,
+ 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/Silicon/Marvell/Drivers/Spi/MvSpiDxe.inf b/Silicon/Marvell/Drivers/Spi/MvSpiDxe.inf
new file mode 100644
index 0000000000..e7bc170e64
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Spi/MvSpiDxe.inf
@@ -0,0 +1,73 @@
+#
+# 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_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = SpiMasterEntryPoint
+
+[Sources]
+ MvSpiDxe.c
+ MvSpiDxe.h
+
+[Packages]
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/Marvell/Marvell.dec
+
+[LibraryClasses]
+ NorFlashInfoLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ TimerLib
+ UefiLib
+ DebugLib
+ DxeServicesTableLib
+ MemoryAllocationLib
+ IoLib
+ UefiRuntimeLib
+
+[FixedPcd]
+ gMarvellTokenSpaceGuid.PcdSpiRegBase
+ gMarvellTokenSpaceGuid.PcdSpiClockFrequency
+ gMarvellTokenSpaceGuid.PcdSpiMaxFrequency
+
+[Protocols]
+ gMarvellSpiMasterProtocolGuid
+
+[Depex]
+ #
+ # MvSpiDxe must be loaded prior to MvSpiFlash driver
+ #
+ BEFORE gMarvellSpiFlashDxeGuid
diff --git a/Silicon/Marvell/Drivers/Spi/Variables/MvFvbDxe.c b/Silicon/Marvell/Drivers/Spi/Variables/MvFvbDxe.c
new file mode 100644
index 0000000000..252ef67566
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Spi/Variables/MvFvbDxe.c
@@ -0,0 +1,1138 @@
+/*++ @file MvFvbDxe.c
+
+ Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
+ Copyright (c) 2017 Marvell International Ltd.<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 <PiDxe.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeLib.h>
+
+#include <Guid/SystemNvDataGuid.h>
+#include <Guid/VariableFormat.h>
+
+#include "MvFvbDxe.h"
+
+STATIC EFI_EVENT mFvbVirtualAddrChangeEvent;
+STATIC FVB_DEVICE *mFvbDevice;
+
+STATIC CONST FVB_DEVICE mMvFvbFlashInstanceTemplate = {
+ {
+ 0, // SpiFlash Chip Select ... NEED TO BE FILLED
+ 0, // SpiFlash Maximum Frequency ... NEED TO BE FILLED
+ 0, // SpiFlash Transfer Mode ... NEED TO BE FILLED
+ 0, // SpiFlash Address Size ... NEED TO BE FILLED
+ NULL, // SpiFlash detailed information ... NEED TO BE FILLED
+ 0, // HostRegisterBaseAddress ... NEED TO BE FILLED
+ 0, // CoreClock ... NEED TO BE FILLED
+ }, // SpiDevice
+
+ NULL, // SpiFlashProtocol ... NEED TO BE FILLED
+ NULL, // SpiMasterProtocol ... NEED TO BE FILLED
+ NULL, // Handle ... NEED TO BE FILLED
+
+ FVB_FLASH_SIGNATURE, // Signature
+
+ 0, // DeviceBaseAddress ... NEED TO BE FILLED
+ 0, // RegionBaseAddress ... NEED TO BE FILLED
+ SIZE_256KB, // Size
+ 0, // FvbOffset ... NEED TO BE FILLED
+ 0, // FvbSize ... NEED TO BE FILLED
+ 0, // StartLba
+
+ {
+ 0, // MediaId ... NEED TO BE FILLED
+ FALSE, // RemovableMedia
+ TRUE, // MediaPresent
+ FALSE, // LogicalPartition
+ FALSE, // ReadOnly
+ FALSE, // WriteCaching;
+ 0, // BlockSize ... NEED TO BE FILLED
+ 4, // IoAlign
+ 0, // LastBlock ... NEED TO BE FILLED
+ 0, // LowestAlignedLba
+ 1, // LogicalBlocksPerPhysicalBlock
+ }, //Media;
+
+ {
+ MvFvbGetAttributes, // GetAttributes
+ MvFvbSetAttributes, // SetAttributes
+ MvFvbGetPhysicalAddress, // GetPhysicalAddress
+ MvFvbGetBlockSize, // GetBlockSize
+ MvFvbRead, // Read
+ MvFvbWrite, // Write
+ MvFvbEraseBlocks, // EraseBlocks
+ NULL, // ParentHandle
+ }, // FvbProtocol;
+
+ {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8)sizeof (VENDOR_DEVICE_PATH),
+ (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ { 0xfc0cb972, 0x21df, 0x44d2, { 0x92, 0xa5, 0x78, 0x98, 0x99, 0xcb, 0xf6, 0x61 } }
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
+ }
+ } // DevicePath
+};
+
+//
+// The Firmware Volume Block Protocol is the low-level interface
+// to a firmware volume. File-level access to a firmware volume
+// should not be done using the Firmware Volume Block Protocol.
+// Normal access to a firmware volume must use the Firmware
+// Volume Protocol. Typically, only the file system driver that
+// produces the Firmware Volume Protocol will bind to the
+// Firmware Volume Block Protocol.
+//
+
+/**
+ Initialises the FV Header and Variable Store Header
+ to support variable operations.
+
+ @param[in] Ptr - Location to initialise the headers
+
+**/
+STATIC
+EFI_STATUS
+MvFvbInitFvAndVariableStoreHeaders (
+ IN FVB_DEVICE *FlashInstance
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *FirmwareVolumeHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ EFI_STATUS Status;
+ VOID* Headers;
+ UINTN HeadersLength;
+ UINTN BlockSize;
+
+ HeadersLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER) +
+ sizeof (EFI_FV_BLOCK_MAP_ENTRY) +
+ sizeof (VARIABLE_STORE_HEADER);
+ Headers = AllocateZeroPool (HeadersLength);
+
+ BlockSize = FlashInstance->Media.BlockSize;
+
+ //
+ // FirmwareVolumeHeader->FvLength is declared to have the Variable area
+ // AND the FTW working area AND the FTW Spare contiguous.
+ //
+ ASSERT (PcdGet32 (PcdFlashNvStorageVariableBase) +
+ PcdGet32 (PcdFlashNvStorageVariableSize) ==
+ PcdGet32 (PcdFlashNvStorageFtwWorkingBase));
+ ASSERT (PcdGet32 (PcdFlashNvStorageFtwWorkingBase) +
+ PcdGet32 (PcdFlashNvStorageFtwWorkingSize) ==
+ PcdGet32 (PcdFlashNvStorageFtwSpareBase));
+
+ // Check if the size of the area is at least one block size
+ ASSERT ((PcdGet32 (PcdFlashNvStorageVariableSize) > 0) &&
+ (PcdGet32 (PcdFlashNvStorageVariableSize) / BlockSize > 0));
+ ASSERT ((PcdGet32 (PcdFlashNvStorageFtwWorkingSize) > 0) &&
+ (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) / BlockSize > 0));
+ ASSERT ((PcdGet32 (PcdFlashNvStorageFtwSpareSize) > 0) &&
+ (PcdGet32 (PcdFlashNvStorageFtwSpareSize) / BlockSize > 0));
+
+ // Ensure the Variable areas are aligned on block size boundaries
+ ASSERT ((PcdGet32 (PcdFlashNvStorageVariableBase) % BlockSize) == 0);
+ ASSERT ((PcdGet32 (PcdFlashNvStorageFtwWorkingBase) % BlockSize) == 0);
+ ASSERT ((PcdGet32 (PcdFlashNvStorageFtwSpareBase) % BlockSize) == 0);
+
+ //
+ // EFI_FIRMWARE_VOLUME_HEADER
+ //
+ FirmwareVolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Headers;
+ CopyGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid);
+ FirmwareVolumeHeader->FvLength = FlashInstance->FvbSize;
+ FirmwareVolumeHeader->Signature = EFI_FVH_SIGNATURE;
+ FirmwareVolumeHeader->Attributes = EFI_FVB2_READ_ENABLED_CAP |
+ EFI_FVB2_READ_STATUS |
+ EFI_FVB2_STICKY_WRITE |
+ EFI_FVB2_MEMORY_MAPPED |
+ EFI_FVB2_ERASE_POLARITY |
+ EFI_FVB2_WRITE_STATUS |
+ EFI_FVB2_WRITE_ENABLED_CAP;
+
+ FirmwareVolumeHeader->HeaderLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER) +
+ sizeof (EFI_FV_BLOCK_MAP_ENTRY);
+ FirmwareVolumeHeader->Revision = EFI_FVH_REVISION;
+ FirmwareVolumeHeader->BlockMap[0].NumBlocks = FlashInstance->Media.LastBlock + 1;
+ FirmwareVolumeHeader->BlockMap[0].Length = FlashInstance->Media.BlockSize;
+ FirmwareVolumeHeader->BlockMap[1].NumBlocks = 0;
+ FirmwareVolumeHeader->BlockMap[1].Length = 0;
+ FirmwareVolumeHeader->Checksum = CalculateCheckSum16 (
+ (UINT16 *)FirmwareVolumeHeader,
+ FirmwareVolumeHeader->HeaderLength);
+
+ //
+ // VARIABLE_STORE_HEADER
+ //
+ VariableStoreHeader = (VOID *)((UINTN)Headers +
+ FirmwareVolumeHeader->HeaderLength);
+ CopyGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid);
+ VariableStoreHeader->Size = PcdGet32(PcdFlashNvStorageVariableSize) -
+ FirmwareVolumeHeader->HeaderLength;
+ VariableStoreHeader->Format = VARIABLE_STORE_FORMATTED;
+ VariableStoreHeader->State = VARIABLE_STORE_HEALTHY;
+
+ // Install the combined super-header in the flash device
+ Status = MvFvbWrite (&FlashInstance->FvbProtocol, 0, 0, &HeadersLength, Headers);
+
+ FreePool (Headers);
+
+ return Status;
+}
+
+/**
+ Check the integrity of firmware volume header.
+
+ @param[in] FwVolHeader - A pointer to a firmware volume header
+
+ @retval EFI_SUCCESS - The firmware volume is consistent
+ @retval EFI_NOT_FOUND - The firmware volume has been corrupted.
+
+**/
+STATIC
+EFI_STATUS
+MvFvbValidateFvHeader (
+ IN FVB_DEVICE *FlashInstance
+ )
+{
+ UINT16 Checksum;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINTN VariableStoreLength;
+
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FlashInstance->RegionBaseAddress;
+
+ // Verify the header revision, header signature, length
+ if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||
+ (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
+ (FwVolHeader->FvLength != FlashInstance->FvbSize)) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: No Firmware Volume header present\n",
+ __FUNCTION__));
+ return EFI_NOT_FOUND;
+ }
+
+ // Check the Firmware Volume Guid
+ if (!CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid)) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Firmware Volume Guid non-compatible\n",
+ __FUNCTION__));
+ return EFI_NOT_FOUND;
+ }
+
+ // Verify the header checksum
+ Checksum = CalculateSum16 ((UINT16 *)FwVolHeader, FwVolHeader->HeaderLength);
+ if (Checksum != 0) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: FV checksum is invalid (Checksum:0x%x)\n",
+ __FUNCTION__,
+ Checksum));
+ return EFI_NOT_FOUND;
+ }
+
+ VariableStoreHeader = (VOID *)((UINTN)FwVolHeader + FwVolHeader->HeaderLength);
+
+ // Check the Variable Store Guid
+ if (!CompareGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid) &&
+ !CompareGuid (&VariableStoreHeader->Signature,
+ &gEfiAuthenticatedVariableGuid)) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Variable Store Guid non-compatible\n",
+ __FUNCTION__));
+ return EFI_NOT_FOUND;
+ }
+
+ VariableStoreLength = PcdGet32 (PcdFlashNvStorageVariableSize) -
+ FwVolHeader->HeaderLength;
+ if (VariableStoreHeader->Size != VariableStoreLength) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Variable Store Length does not match\n",
+ __FUNCTION__));
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The GetAttributes() function retrieves the attributes and
+ current settings of the block.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the attributes and
+ current settings are returned.
+ Type EFI_FVB_ATTRIBUTES_2 is defined in
+ EFI_FIRMWARE_VOLUME_HEADER.
+
+ @retval EFI_SUCCESS The firmware volume attributes were returned.
+
+ **/
+EFI_STATUS
+EFIAPI
+MvFvbGetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ EFI_FVB_ATTRIBUTES_2 *FlashFvbAttributes;
+ FVB_DEVICE *FlashInstance;
+
+ FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FlashInstance->RegionBaseAddress;
+ FlashFvbAttributes = (EFI_FVB_ATTRIBUTES_2 *)&(FwVolHeader->Attributes);
+
+ *Attributes = *FlashFvbAttributes;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The SetAttributes() function sets configurable firmware volume attributes
+ and returns the new settings of the firmware volume.
+
+
+ @param This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Attributes On input, Attributes is a pointer to
+ EFI_FVB_ATTRIBUTES_2 that contains the desired
+ firmware volume settings.
+ On successful return, it contains the new
+ settings of the firmware volume.
+
+ @retval EFI_SUCCESS The firmware volume attributes were returned.
+
+ @retval EFI_INVALID_PARAMETER The attributes requested are in conflict with
+ the capabilities as declared in the firmware
+ volume header.
+
+ **/
+EFI_STATUS
+EFIAPI
+MvFvbSetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+{
+ EFI_FVB_ATTRIBUTES_2 OldAttributes;
+ EFI_FVB_ATTRIBUTES_2 FlashFvbAttributes;
+ EFI_FVB_ATTRIBUTES_2 UnchangedAttributes;
+ UINT32 Capabilities;
+ UINT32 OldStatus;
+ UINT32 NewStatus;
+
+ //
+ // Obtain attributes from FVB header
+ //
+ MvFvbGetAttributes (This, &FlashFvbAttributes);
+
+ OldAttributes = FlashFvbAttributes;
+ Capabilities = OldAttributes & EFI_FVB2_CAPABILITIES;
+ OldStatus = OldAttributes & EFI_FVB2_STATUS;
+ NewStatus = *Attributes & EFI_FVB2_STATUS;
+
+ UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP | \
+ EFI_FVB2_READ_ENABLED_CAP | \
+ EFI_FVB2_WRITE_DISABLED_CAP | \
+ EFI_FVB2_WRITE_ENABLED_CAP | \
+ EFI_FVB2_LOCK_CAP | \
+ EFI_FVB2_STICKY_WRITE | \
+ EFI_FVB2_MEMORY_MAPPED | \
+ EFI_FVB2_ERASE_POLARITY | \
+ EFI_FVB2_READ_LOCK_CAP | \
+ EFI_FVB2_WRITE_LOCK_CAP | \
+ EFI_FVB2_ALIGNMENT;
+
+ //
+ // Some attributes of FV is read only can *not* be set
+ //
+ if ((OldAttributes & UnchangedAttributes) ^
+ (*Attributes & UnchangedAttributes)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // If firmware volume is locked, no status bit can be updated
+ //
+ if (OldAttributes & EFI_FVB2_LOCK_STATUS) {
+ if (OldStatus ^ NewStatus) {
+ return EFI_ACCESS_DENIED;
+ }
+ }
+ //
+ // Test read disable
+ //
+ if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
+ if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Test read enable
+ //
+ if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
+ if (NewStatus & EFI_FVB2_READ_STATUS) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Test write disable
+ //
+ if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
+ if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Test write enable
+ //
+ if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
+ if (NewStatus & EFI_FVB2_WRITE_STATUS) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Test lock
+ //
+ if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
+ if (NewStatus & EFI_FVB2_LOCK_STATUS) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ FlashFvbAttributes = FlashFvbAttributes & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
+ FlashFvbAttributes = FlashFvbAttributes | NewStatus;
+ *Attributes = FlashFvbAttributes;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The GetPhysicalAddress() function retrieves the base address of
+ a memory-mapped firmware volume. This function should be called
+ only for memory-mapped firmware volumes.
+
+ @param This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Address Pointer to a caller-allocated
+ EFI_PHYSICAL_ADDRESS that, on successful
+ return from GetPhysicalAddress(), contains the
+ base address of the firmware volume.
+
+ @retval EFI_SUCCESS The firmware volume base address was returned.
+
+ @retval EFI_NOT_SUPPORTED The firmware volume is not memory mapped.
+
+ **/
+EFI_STATUS
+EFIAPI
+MvFvbGetPhysicalAddress (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ OUT EFI_PHYSICAL_ADDRESS *Address
+ )
+{
+ FVB_DEVICE *FlashInstance;
+
+ ASSERT (Address != NULL);
+
+ FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+ *Address = FlashInstance->RegionBaseAddress;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The GetBlockSize() function retrieves the size of the requested
+ block. It also returns the number of additional blocks with
+ the identical size. The GetBlockSize() function is used to
+ retrieve the block map (see EFI_FIRMWARE_VOLUME_HEADER).
+
+
+ @param This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Lba Indicates the block whose size to return
+
+ @param BlockSize Pointer to a caller-allocated UINTN in which
+ the size of the block is returned.
+
+ @param NumberOfBlocks Pointer to a caller-allocated UINTN in
+ which the number of consecutive blocks,
+ starting with Lba, is returned. All
+ blocks in this range have a size of
+ BlockSize.
+
+
+ @retval EFI_SUCCESS The firmware volume base address was returned.
+
+ @retval EFI_INVALID_PARAMETER The requested LBA is out of range.
+
+ **/
+EFI_STATUS
+EFIAPI
+MvFvbGetBlockSize (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ OUT UINTN *BlockSize,
+ OUT UINTN *NumberOfBlocks
+ )
+{
+ FVB_DEVICE *FlashInstance;
+
+ FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+ if (Lba > FlashInstance->Media.LastBlock) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Error: Requested LBA %ld is beyond the last available LBA (%ld).\n",
+ __FUNCTION__,
+ Lba,
+ FlashInstance->Media.LastBlock));
+ return EFI_INVALID_PARAMETER;
+ } else {
+ // Assume equal sized blocks in all flash devices
+ *BlockSize = (UINTN)FlashInstance->Media.BlockSize;
+ *NumberOfBlocks = (UINTN)(FlashInstance->Media.LastBlock - Lba + 1);
+
+ return EFI_SUCCESS;
+ }
+}
+
+/**
+ Reads the specified number of bytes into a buffer from the specified block.
+
+ The Read() function reads the requested number of bytes from the
+ requested block and stores them in the provided buffer.
+ Implementations should be mindful that the firmware volume
+ might be in the ReadDisabled state. If it is in this state,
+ the Read() function must return the status code
+ EFI_ACCESS_DENIED without modifying the contents of the
+ buffer. The Read() function must also prevent spanning block
+ boundaries. If a read is requested that would span a block
+ boundary, the read must read up to the boundary but not
+ beyond. The output parameter NumBytes must be set to correctly
+ indicate the number of bytes actually read. The caller must be
+ aware that a read may be partially completed.
+
+ @param This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Lba The starting logical block index from which to read
+
+ @param Offset Offset into the block at which to begin reading.
+
+ @param NumBytes Pointer to a UINTN.
+ At entry, *NumBytes contains the total size of the
+ buffer.
+ At exit, *NumBytes contains the total number of
+ bytes read.
+
+ @param Buffer Pointer to a caller-allocated buffer that will be
+ used to hold the data that is read.
+
+ @retval EFI_SUCCESS The firmware volume was read successfully, and
+ contents are in Buffer.
+
+ @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA boundary.
+ On output, NumBytes contains the total number of
+ bytes returned in Buffer.
+
+ @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state.
+
+ @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
+ could not be read.
+
+ **/
+EFI_STATUS
+EFIAPI
+MvFvbRead (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN OUT UINT8 *Buffer
+ )
+{
+ FVB_DEVICE *FlashInstance;
+ UINTN BlockSize;
+ UINTN DataOffset;
+
+ FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+
+ // Cache the block size to avoid de-referencing pointers all the time
+ BlockSize = FlashInstance->Media.BlockSize;
+
+ //
+ // The read must not span block boundaries.
+ // We need to check each variable individually because adding two large
+ // values together overflows.
+ //
+ if (Offset >= BlockSize ||
+ *NumBytes > BlockSize ||
+ (Offset + *NumBytes) > BlockSize) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Wrong buffer size: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n",
+ __FUNCTION__,
+ Offset,
+ *NumBytes,
+ BlockSize));
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ // No bytes to read
+ if (*NumBytes == 0) {
+ return EFI_SUCCESS;
+ }
+
+ DataOffset = GET_DATA_OFFSET (FlashInstance->RegionBaseAddress + Offset,
+ FlashInstance->StartLba + Lba,
+ FlashInstance->Media.BlockSize);
+
+ // Read the memory-mapped data
+ CopyMem (Buffer, (UINTN *)DataOffset, *NumBytes);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Writes the specified number of bytes from the input buffer to the block.
+
+ The Write() function writes the specified number of bytes from
+ the provided buffer to the specified block and offset. If the
+ firmware volume is sticky write, the caller must ensure that
+ all the bits of the specified range to write are in the
+ EFI_FVB_ERASE_POLARITY state before calling the Write()
+ function, or else the result will be unpredictable. This
+ unpredictability arises because, for a sticky-write firmware
+ volume, a write may negate a bit in the EFI_FVB_ERASE_POLARITY
+ state but cannot flip it back again. Before calling the
+ Write() function, it is recommended for the caller to first call
+ the EraseBlocks() function to erase the specified block to
+ write. A block erase cycle will transition bits from the
+ (NOT)EFI_FVB_ERASE_POLARITY state back to the
+ EFI_FVB_ERASE_POLARITY state. Implementations should be
+ mindful that the firmware volume might be in the WriteDisabled
+ state. If it is in this state, the Write() function must
+ return the status code EFI_ACCESS_DENIED without modifying the
+ contents of the firmware volume. The Write() function must
+ also prevent spanning block boundaries. If a write is
+ requested that spans a block boundary, the write must store up
+ to the boundary but not beyond. The output parameter NumBytes
+ must be set to correctly indicate the number of bytes actually
+ written. The caller must be aware that a write may be
+ partially completed. All writes, partial or otherwise, must be
+ fully flushed to the hardware before the Write() service
+ returns.
+
+ @param This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Lba The starting logical block index to write to.
+
+ @param Offset Offset into the block at which to begin writing.
+
+ @param NumBytes The pointer to a UINTN.
+ At entry, *NumBytes contains the total size of the
+ buffer.
+ At exit, *NumBytes contains the total number of
+ bytes actually written.
+
+ @param Buffer The pointer to a caller-allocated buffer that
+ contains the source for the write.
+
+ @retval EFI_SUCCESS The firmware volume was written successfully.
+
+ @retval EFI_BAD_BUFFER_SIZE The write was attempted across an LBA boundary.
+ On output, NumBytes contains the total number of
+ bytes actually written.
+
+ @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state.
+
+ @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not be
+ written.
+
+
+ **/
+EFI_STATUS
+EFIAPI
+MvFvbWrite (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer
+ )
+{
+ FVB_DEVICE *FlashInstance;
+ UINTN DataOffset;
+
+ FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+ DataOffset = GET_DATA_OFFSET (FlashInstance->FvbOffset + Offset,
+ FlashInstance->StartLba + Lba,
+ FlashInstance->Media.BlockSize);
+
+ return FlashInstance->SpiFlashProtocol->Write (&FlashInstance->SpiDevice,
+ DataOffset,
+ *NumBytes,
+ Buffer);
+}
+
+/**
+ Erases and initialises a firmware volume block.
+
+ The EraseBlocks() function erases one or more blocks as denoted
+ by the variable argument list. The entire parameter list of
+ blocks must be verified before erasing any blocks. If a block is
+ requested that does not exist within the associated firmware
+ volume (it has a larger index than the last block of the
+ firmware volume), the EraseBlocks() function must return the
+ status code EFI_INVALID_PARAMETER without modifying the contents
+ of the firmware volume. Implementations should be mindful that
+ the firmware volume might be in the WriteDisabled state. If it
+ is in this state, the EraseBlocks() function must return the
+ status code EFI_ACCESS_DENIED without modifying the contents of
+ the firmware volume. All calls to EraseBlocks() must be fully
+ flushed to the hardware before the EraseBlocks() service
+ returns.
+
+ @param This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
+ instance.
+
+ @param ... The variable argument list is a list of tuples.
+ Each tuple describes a range of LBAs to erase
+ and consists of the following:
+ - An EFI_LBA that indicates the starting LBA
+ - A UINTN that indicates the number of blocks
+ to erase.
+
+ The list is terminated with an
+ EFI_LBA_LIST_TERMINATOR.
+
+ @retval EFI_SUCCESS The erase request successfully completed.
+
+ @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled
+ state.
+
+ @retval EFI_DEVICE_ERROR The block device is not functioning correctly
+ and could not be written.
+ The firmware device may have been partially
+ erased.
+
+ @retval EFI_INVALID_PARAMETER One or more of the LBAs listed in the variable
+ argument list do not exist in the firmware
+ volume.
+
+ **/
+EFI_STATUS
+EFIAPI
+MvFvbEraseBlocks (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ ...
+ )
+{
+ EFI_FVB_ATTRIBUTES_2 FlashFvbAttributes;
+ FVB_DEVICE *FlashInstance;
+ EFI_STATUS Status;
+ VA_LIST Args;
+ UINTN BlockAddress; // Physical address of Lba to erase
+ EFI_LBA StartingLba; // Lba from which we start erasing
+ UINTN NumOfLba; // Number of Lba blocks to erase
+
+ FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+ Status = EFI_SUCCESS;
+
+ // Detect WriteDisabled state
+ MvFvbGetAttributes (This, &FlashFvbAttributes);
+ if ((FlashFvbAttributes & EFI_FVB2_WRITE_STATUS) == 0) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Device is in WriteDisabled state.\n",
+ __FUNCTION__));
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Before erasing, check the entire list of parameters to ensure
+ // all specified blocks are valid.
+ //
+ VA_START (Args, This);
+ do {
+ // Get the Lba from which we start erasing
+ StartingLba = VA_ARG (Args, EFI_LBA);
+
+ // Have we reached the end of the list?
+ if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
+ //Exit the while loop
+ break;
+ }
+
+ // How many Lba blocks are we requested to erase?
+ NumOfLba = VA_ARG (Args, UINT32);
+
+ // All blocks must be within range
+ if (NumOfLba == 0 ||
+ (FlashInstance->StartLba + StartingLba + NumOfLba - 1) >
+ FlashInstance->Media.LastBlock) {
+
+ DEBUG ((DEBUG_ERROR,
+ "%a: Error: Requested LBA are beyond the last available LBA (%ld).\n",
+ __FUNCTION__,
+ FlashInstance->Media.LastBlock));
+
+ VA_END (Args);
+
+ return EFI_INVALID_PARAMETER;
+ }
+ } while (TRUE);
+ VA_END (Args);
+
+ //
+ // Start erasing
+ //
+ VA_START (Args, This);
+ do {
+ // Get the Lba from which we start erasing
+ StartingLba = VA_ARG (Args, EFI_LBA);
+
+ // Have we reached the end of the list?
+ if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
+ // Exit the while loop
+ break;
+ }
+
+ // How many Lba blocks are we requested to erase?
+ NumOfLba = VA_ARG (Args, UINT32);
+
+ // Go through each one and erase it
+ while (NumOfLba > 0) {
+
+ // Get the physical address of Lba to erase
+ BlockAddress = GET_DATA_OFFSET (FlashInstance->FvbOffset,
+ FlashInstance->StartLba + StartingLba,
+ FlashInstance->Media.BlockSize);
+
+ // Erase single block
+ Status = FlashInstance->SpiFlashProtocol->Erase (&FlashInstance->SpiDevice,
+ BlockAddress,
+ FlashInstance->Media.BlockSize);
+ if (EFI_ERROR (Status)) {
+ VA_END (Args);
+ return EFI_DEVICE_ERROR;
+ }
+
+ // Move to the next Lba
+ StartingLba++;
+ NumOfLba--;
+ }
+ } while (TRUE);
+ VA_END (Args);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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
+**/
+STATIC
+VOID
+EFIAPI
+MvFvbVirtualNotifyEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ // Convert SPI memory mapped region
+ EfiConvertPointer (0x0, (VOID**)&mFvbDevice->RegionBaseAddress);
+
+ // Convert SPI device description
+ EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiDevice.Info);
+ EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiDevice.HostRegisterBaseAddress);
+ EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiDevice);
+
+ // Convert SpiFlashProtocol
+ EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiFlashProtocol->Erase);
+ EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiFlashProtocol->Write);
+ EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiFlashProtocol);
+
+ return;
+}
+
+STATIC
+EFI_STATUS
+MvFvbFlashProbe (
+ IN FVB_DEVICE *FlashInstance
+ )
+{
+ MARVELL_SPI_FLASH_PROTOCOL *SpiFlashProtocol;
+ EFI_STATUS Status;
+
+ SpiFlashProtocol = FlashInstance->SpiFlashProtocol;
+
+ // Read SPI flash ID
+ Status = SpiFlashProtocol->ReadId (&FlashInstance->SpiDevice, TRUE);
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = SpiFlashProtocol->Init (SpiFlashProtocol, &FlashInstance->SpiDevice);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Cannot initialize flash device\n", __FUNCTION__));
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // SPI flash may require 20ms interval between enabling it and
+ // accessing in Direct Mode to its memory mapped content.
+ //
+ gBS->Stall (20000);
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+MvFvbPrepareFvHeader (
+ IN FVB_DEVICE *FlashInstance
+ )
+{
+ EFI_BOOT_MODE BootMode;
+ EFI_STATUS Status;
+
+ // Check if it is required to use default environment
+ BootMode = GetBootModeHob ();
+ if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) {
+ Status = EFI_INVALID_PARAMETER;
+ } else {
+ // Validate header at the beginning of FV region
+ Status = MvFvbValidateFvHeader (FlashInstance);
+ }
+
+ // Install the default FVB header if required
+ if (EFI_ERROR (Status)) {
+ // There is no valid header, so time to install one.
+ DEBUG ((DEBUG_ERROR, "%a: The FVB Header is not valid.\n", __FUNCTION__));
+ DEBUG ((DEBUG_ERROR,
+ "%a: Installing a correct one for this volume.\n",
+ __FUNCTION__));
+
+ // Erase entire region that is reserved for variable storage
+ Status = FlashInstance->SpiFlashProtocol->Erase (&FlashInstance->SpiDevice,
+ FlashInstance->FvbOffset,
+ FlashInstance->FvbSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Install all appropriate headers
+ Status = MvFvbInitFvAndVariableStoreHeaders (FlashInstance);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+MvFvbConfigureFlashInstance (
+ IN OUT FVB_DEVICE *FlashInstance
+ )
+{
+ EFI_STATUS Status;
+
+
+ // Locate SPI protocols
+ Status = gBS->LocateProtocol (&gMarvellSpiFlashProtocolGuid,
+ NULL,
+ (VOID **)&FlashInstance->SpiFlashProtocol);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Cannot locate SpiFlash protocol\n", __FUNCTION__));
+ return Status;
+ }
+
+ Status = gBS->LocateProtocol (&gMarvellSpiMasterProtocolGuid,
+ NULL,
+ (VOID **)&FlashInstance->SpiMasterProtocol);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Cannot locate SpiMaster protocol\n", __FUNCTION__));
+ return Status;
+ }
+
+ // Setup and probe SPI flash
+ FlashInstance->SpiMasterProtocol->SetupDevice (FlashInstance->SpiMasterProtocol,
+ &FlashInstance->SpiDevice,
+ 0,
+ 0);
+
+ Status = MvFvbFlashProbe (FlashInstance);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Error while performing SPI flash probe\n",
+ __FUNCTION__));
+ return Status;
+ }
+
+ // Fill remaining flash description
+ FlashInstance->DeviceBaseAddress = PcdGet32 (PcdSpiMemoryBase);
+ FlashInstance->RegionBaseAddress = FixedPcdGet32 (PcdFlashNvStorageVariableBase);
+ FlashInstance->FvbOffset = FlashInstance->RegionBaseAddress -
+ FlashInstance->DeviceBaseAddress;
+ FlashInstance->FvbSize = PcdGet32(PcdFlashNvStorageVariableSize) +
+ PcdGet32(PcdFlashNvStorageFtwWorkingSize) +
+ PcdGet32(PcdFlashNvStorageFtwSpareSize);
+
+ FlashInstance->Media.MediaId = 0;
+ FlashInstance->Media.BlockSize = FlashInstance->SpiDevice.Info->SectorSize;
+ FlashInstance->Media.LastBlock = FlashInstance->Size /
+ FlashInstance->Media.BlockSize - 1;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (&FlashInstance->Handle,
+ &gEfiDevicePathProtocolGuid, &FlashInstance->DevicePath,
+ &gEfiFirmwareVolumeBlockProtocolGuid, &FlashInstance->FvbProtocol,
+ NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = MvFvbPrepareFvHeader (FlashInstance);
+ if (EFI_ERROR (Status)) {
+ goto ErrorPrepareFvbHeader;
+ }
+
+ return EFI_SUCCESS;
+
+ErrorPrepareFvbHeader:
+ gBS->UninstallMultipleProtocolInterfaces (&FlashInstance->Handle,
+ &gEfiDevicePathProtocolGuid,
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ NULL);
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+MvFvbEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINTN RuntimeMmioRegionSize;
+ UINTN RegionBaseAddress;
+
+ //
+ // Create FVB flash device
+ //
+ mFvbDevice = AllocateRuntimeCopyPool (sizeof (mMvFvbFlashInstanceTemplate),
+ &mMvFvbFlashInstanceTemplate);
+ if (mFvbDevice == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: Cannot allocate memory\n", __FUNCTION__));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Detect and configure flash device
+ //
+ Status = MvFvbConfigureFlashInstance (mFvbDevice);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to configure Fvb SPI device\n", __FUNCTION__));
+ goto ErrorConfigureFlash;
+ }
+
+ //
+ // Declare the Non-Volatile storage as EFI_MEMORY_RUNTIME
+ //
+ RuntimeMmioRegionSize = mFvbDevice->FvbSize;
+ RegionBaseAddress = mFvbDevice->RegionBaseAddress;
+
+ Status = gDS->AddMemorySpace (EfiGcdMemoryTypeMemoryMappedIo,
+ RegionBaseAddress,
+ RuntimeMmioRegionSize,
+ EFI_MEMORY_UC | EFI_MEMORY_RUNTIME);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to add memory space\n", __FUNCTION__));
+ goto ErrorAddSpace;
+ }
+
+ Status = gDS->SetMemorySpaceAttributes (RegionBaseAddress,
+ RuntimeMmioRegionSize,
+ EFI_MEMORY_UC | EFI_MEMORY_RUNTIME);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to set memory attributes\n", __FUNCTION__));
+ goto ErrorSetMemAttr;
+ }
+
+ //
+ // Register for the virtual address change event
+ //
+ Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ MvFvbVirtualNotifyEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mFvbVirtualAddrChangeEvent);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to register VA change event\n", __FUNCTION__));
+ goto ErrorSetMemAttr;
+ }
+
+ //
+ // Configure runtime access to host controller registers
+ //
+ Status = mFvbDevice->SpiMasterProtocol->ConfigRuntime (&mFvbDevice->SpiDevice);
+ if (EFI_ERROR (Status)) {
+ goto ErrorSetMemAttr;
+ }
+
+ return Status;
+
+ErrorSetMemAttr:
+ gDS->RemoveMemorySpace (RegionBaseAddress, RuntimeMmioRegionSize);
+
+ErrorAddSpace:
+ gBS->UninstallMultipleProtocolInterfaces (&mFvbDevice->Handle,
+ &gEfiDevicePathProtocolGuid,
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ NULL);
+
+ErrorConfigureFlash:
+ FreePool (mFvbDevice);
+
+ return Status;
+}
diff --git a/Silicon/Marvell/Drivers/Spi/Variables/MvFvbDxe.h b/Silicon/Marvell/Drivers/Spi/Variables/MvFvbDxe.h
new file mode 100644
index 0000000000..31e6e444be
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Spi/Variables/MvFvbDxe.h
@@ -0,0 +1,128 @@
+/** @file MvFvbDxe.h
+
+ Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
+ Copyright (c) 2017 Marvell International Ltd.<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 __FVB_FLASH_DXE_H__
+#define __FVB_FLASH_DXE_H__
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+#include <Protocol/Spi.h>
+#include <Protocol/SpiFlash.h>
+
+#define GET_DATA_OFFSET(BaseAddr, Lba, LbaSize) ((BaseAddr) + (UINTN)((Lba) * (LbaSize)))
+
+#define FVB_FLASH_SIGNATURE SIGNATURE_32('S', 'n', 'o', 'r')
+#define INSTANCE_FROM_FVB_THIS(a) CR(a, FVB_DEVICE, FvbProtocol, FVB_FLASH_SIGNATURE)
+
+//
+// Define two helper macro to extract the Capability field or Status field in FVB
+// bit fields.
+//
+#define EFI_FVB2_CAPABILITIES (EFI_FVB2_READ_DISABLED_CAP | \
+ EFI_FVB2_READ_ENABLED_CAP | \
+ EFI_FVB2_WRITE_DISABLED_CAP | \
+ EFI_FVB2_WRITE_ENABLED_CAP | \
+ EFI_FVB2_LOCK_CAP)
+
+#define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | \
+ EFI_FVB2_WRITE_STATUS | \
+ EFI_FVB2_LOCK_STATUS)
+
+typedef struct {
+ VENDOR_DEVICE_PATH Vendor;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} FVB_DEVICE_PATH;
+
+typedef struct {
+ SPI_DEVICE SpiDevice;
+
+ MARVELL_SPI_FLASH_PROTOCOL *SpiFlashProtocol;
+ MARVELL_SPI_MASTER_PROTOCOL *SpiMasterProtocol;
+
+ EFI_HANDLE Handle;
+
+ UINT32 Signature;
+
+ UINTN DeviceBaseAddress;
+ UINTN RegionBaseAddress;
+ UINTN Size;
+ UINTN FvbOffset;
+ UINTN FvbSize;
+ EFI_LBA StartLba;
+
+ EFI_BLOCK_IO_MEDIA Media;
+ EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL FvbProtocol;
+
+ FVB_DEVICE_PATH DevicePath;
+} FVB_DEVICE;
+
+EFI_STATUS
+EFIAPI
+MvFvbGetAttributes(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL* This,
+ OUT EFI_FVB_ATTRIBUTES_2* Attributes
+);
+
+EFI_STATUS
+EFIAPI
+MvFvbSetAttributes(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL* This,
+ IN OUT EFI_FVB_ATTRIBUTES_2* Attributes
+);
+
+EFI_STATUS
+EFIAPI
+MvFvbGetPhysicalAddress(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL* This,
+ OUT EFI_PHYSICAL_ADDRESS* Address
+);
+
+EFI_STATUS
+EFIAPI
+MvFvbGetBlockSize(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL* This,
+ IN EFI_LBA Lba,
+ OUT UINTN* BlockSize,
+ OUT UINTN* NumberOfBlocks
+);
+
+EFI_STATUS
+EFIAPI
+MvFvbRead(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL* This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN* NumBytes,
+ IN OUT UINT8* Buffer
+);
+
+EFI_STATUS
+EFIAPI
+MvFvbWrite(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL* This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN* NumBytes,
+ IN UINT8* Buffer
+);
+
+EFI_STATUS
+EFIAPI
+MvFvbEraseBlocks(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL* This,
+ ...
+);
+
+#endif /* __FVB_FLASH_DXE_H__ */
diff --git a/Silicon/Marvell/Drivers/Spi/Variables/MvFvbDxe.inf b/Silicon/Marvell/Drivers/Spi/Variables/MvFvbDxe.inf
new file mode 100644
index 0000000000..117fe8bdd6
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Spi/Variables/MvFvbDxe.inf
@@ -0,0 +1,91 @@
+#
+# 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 = 0x0001001A
+ BASE_NAME = MvFvbDxe
+ FILE_GUID = 42903750-7e61-4aaf-8329-bf42364e2485
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 0.1
+ ENTRY_POINT = MvFvbEntryPoint
+
+[Sources]
+ MvFvbDxe.c
+
+[Packages]
+ ArmPlatformPkg/ArmPlatformPkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/Marvell/Marvell.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ DxeServicesTableLib
+ HobLib
+ IoLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+ UefiRuntimeLib
+ UefiRuntimeServicesTableLib
+
+[Guids]
+ gEfiAuthenticatedVariableGuid
+ gEfiEventVirtualAddressChangeGuid
+ gEfiSystemNvDataFvGuid
+ gEfiVariableGuid
+
+[Protocols]
+ gEfiDevicePathProtocolGuid
+ gEfiFirmwareVolumeBlockProtocolGuid
+ gMarvellSpiFlashProtocolGuid
+ gMarvellSpiMasterProtocolGuid
+
+[FixedPcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
+ gMarvellTokenSpaceGuid.PcdSpiMemoryBase
+
+[Depex]
+ #
+ # MvFvbDxe must be loaded before VariableRuntimeDxe in case empty
+ # flash needs populating with default values.
+ #
+ BEFORE gVariableRuntimeDxeFileGuid
diff --git a/Silicon/Marvell/Include/Library/MppLib.h b/Silicon/Marvell/Include/Library/MppLib.h
new file mode 100644
index 0000000000..77c6cdb1c4
--- /dev/null
+++ b/Silicon/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/Silicon/Marvell/Include/Library/MvComPhyLib.h b/Silicon/Marvell/Include/Library/MvComPhyLib.h
new file mode 100644
index 0000000000..6076ede613
--- /dev/null
+++ b/Silicon/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/Silicon/Marvell/Include/Library/MvHwDescLib.h b/Silicon/Marvell/Include/Library/MvHwDescLib.h
new file mode 100644
index 0000000000..9ae03d0bbd
--- /dev/null
+++ b/Silicon/Marvell/Include/Library/MvHwDescLib.h
@@ -0,0 +1,290 @@
+/********************************************************************************
+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;
+
+//
+// I2C devices description template definition
+//
+#define MVHW_MAX_I2C_DEVS 4
+
+typedef struct {
+ UINT8 I2cDevCount;
+ UINTN I2cBaseAddresses[MVHW_MAX_I2C_DEVS];
+} MVHW_I2C_DESC;
+
+//
+// MDIO devices description template definition
+//
+#define MVHW_MAX_MDIO_DEVS 2
+
+typedef struct {
+ UINT8 MdioDevCount;
+ UINTN MdioBaseAddresses[MVHW_MAX_MDIO_DEVS];
+} MVHW_MDIO_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;
+
+//
+// PP2 NIC devices description template definition
+//
+#define MVHW_MAX_PP2_DEVS 4
+
+typedef struct {
+ UINT8 Pp2DevCount;
+ UINTN Pp2BaseAddresses[MVHW_MAX_PP2_DEVS];
+ UINTN Pp2ClockFrequency[MVHW_MAX_PP2_DEVS];
+} MVHW_PP2_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;
+
+//
+// UTMI PHY's description template definition
+//
+
+typedef struct {
+ UINT8 UtmiDevCount;
+ UINT32 UtmiPhyId[MVHW_MAX_XHCI_DEVS];
+ UINTN UtmiBaseAddresses[MVHW_MAX_XHCI_DEVS];
+ UINTN UtmiConfigAddresses[MVHW_MAX_XHCI_DEVS];
+ UINTN UtmiUsbConfigAddresses[MVHW_MAX_XHCI_DEVS];
+ UINTN UtmiMuxBitCount[MVHW_MAX_XHCI_DEVS];
+} MVHW_UTMI_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 I2C devices
+//
+#define MVHW_CP0_I2C0_BASE 0xF2701000
+#define MVHW_CP0_I2C1_BASE 0xF2701100
+#define MVHW_CP1_I2C0_BASE 0xF4701000
+#define MVHW_CP1_I2C1_BASE 0xF4701100
+
+#define DECLARE_A7K8K_I2C_TEMPLATE \
+STATIC \
+MVHW_I2C_DESC mA7k8kI2cDescTemplate = {\
+ 4,\
+ { MVHW_CP0_I2C0_BASE, MVHW_CP0_I2C1_BASE, MVHW_CP1_I2C0_BASE, MVHW_CP1_I2C1_BASE }\
+}
+
+//
+// Platform description of MDIO devices
+//
+#define MVHW_CP0_MDIO_BASE 0xF212A200
+#define MVHW_CP1_MDIO_BASE 0xF412A200
+
+#define DECLARE_A7K8K_MDIO_TEMPLATE \
+STATIC \
+MVHW_MDIO_DESC mA7k8kMdioDescTemplate = {\
+ 2,\
+ { MVHW_CP0_MDIO_BASE, MVHW_CP1_MDIO_BASE }\
+}
+
+//
+// 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 Pp2 NIC devices
+//
+#define MVHW_CP0_PP2_BASE 0xF2000000
+#define MVHW_CP1_PP2_BASE 0xF4000000
+#define MVHW_PP2_CLK_FREQ 333333333
+
+#define DECLARE_A7K8K_PP2_TEMPLATE \
+STATIC \
+MVHW_PP2_DESC mA7k8kPp2DescTemplate = {\
+ 2,\
+ { MVHW_CP0_PP2_BASE, MVHW_CP1_PP2_BASE },\
+ { MVHW_PP2_CLK_FREQ, MVHW_PP2_CLK_FREQ } \
+}
+
+//
+// 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 }\
+}
+
+//
+// Platform description of UTMI PHY's
+//
+#define MVHW_CP0_UTMI0_BASE 0xF2580000
+#define MVHW_CP0_UTMI0_CFG_BASE 0xF2440440
+#define MVHW_CP0_UTMI0_USB_CFG_BASE 0xF2440420
+#define MVHW_CP0_UTMI0_ID 0x0
+#define MVHW_CP0_UTMI1_BASE 0xF2581000
+#define MVHW_CP0_UTMI1_CFG_BASE 0xF2440444
+#define MVHW_CP0_UTMI1_USB_CFG_BASE 0xF2440420
+#define MVHW_CP0_UTMI1_ID 0x1
+#define MVHW_CP1_UTMI0_BASE 0xF4580000
+#define MVHW_CP1_UTMI0_CFG_BASE 0xF4440440
+#define MVHW_CP1_UTMI0_USB_CFG_BASE 0xF4440420
+#define MVHW_CP1_UTMI0_ID 0x0
+#define MVHW_CP1_UTMI1_BASE 0xF4581000
+#define MVHW_CP1_UTMI1_CFG_BASE 0xF4440444
+#define MVHW_CP1_UTMI1_USB_CFG_BASE 0xF4440420
+#define MVHW_CP1_UTMI1_ID 0x1
+
+#define DECLARE_A7K8K_UTMI_TEMPLATE \
+STATIC \
+MVHW_UTMI_DESC mA7k8kUtmiDescTemplate = {\
+ 4,\
+ { MVHW_CP0_UTMI0_ID, MVHW_CP0_UTMI1_ID,\
+ MVHW_CP1_UTMI0_ID, MVHW_CP1_UTMI1_ID },\
+ { MVHW_CP0_UTMI0_BASE, MVHW_CP0_UTMI1_BASE,\
+ MVHW_CP1_UTMI0_BASE, MVHW_CP1_UTMI1_BASE },\
+ { MVHW_CP0_UTMI0_CFG_BASE, MVHW_CP0_UTMI1_CFG_BASE,\
+ MVHW_CP1_UTMI0_CFG_BASE, MVHW_CP1_UTMI1_CFG_BASE },\
+ { MVHW_CP0_UTMI0_USB_CFG_BASE, MVHW_CP0_UTMI1_USB_CFG_BASE,\
+ MVHW_CP1_UTMI0_USB_CFG_BASE, MVHW_CP1_UTMI1_USB_CFG_BASE }\
+}
+
+#endif /* __MVHWDESCLIB_H__ */
diff --git a/Silicon/Marvell/Include/Library/UtmiPhyLib.h b/Silicon/Marvell/Include/Library/UtmiPhyLib.h
new file mode 100644
index 0000000000..7c62cbab20
--- /dev/null
+++ b/Silicon/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/Silicon/Marvell/Include/Protocol/Eeprom.h b/Silicon/Marvell/Include/Protocol/Eeprom.h
new file mode 100644
index 0000000000..fbe4282b91
--- /dev/null
+++ b/Silicon/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/Silicon/Marvell/Include/Protocol/Mdio.h b/Silicon/Marvell/Include/Protocol/Mdio.h
new file mode 100644
index 0000000000..d077a8f74f
--- /dev/null
+++ b/Silicon/Marvell/Include/Protocol/Mdio.h
@@ -0,0 +1,72 @@
+/********************************************************************************
+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__
+
+#include <Library/MvHwDescLib.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 MdioIndex,
+ IN UINT32 RegOff,
+ IN UINT32 *Data
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *MARVELL_MDIO_WRITE) (
+ IN CONST MARVELL_MDIO_PROTOCOL *This,
+ IN UINT32 PhyAddr,
+ IN UINT32 MdioIndex,
+ IN UINT32 RegOff,
+ IN UINT32 Data
+ );
+
+struct _MARVELL_MDIO_PROTOCOL {
+ MARVELL_MDIO_READ Read;
+ MARVELL_MDIO_WRITE Write;
+ UINTN BaseAddresses[MVHW_MAX_MDIO_DEVS];
+ UINTN ControllerCount;
+};
+
+extern EFI_GUID gMarvellMdioProtocolGuid;
+#endif
diff --git a/Silicon/Marvell/Include/Protocol/MvPhy.h b/Silicon/Marvell/Include/Protocol/MvPhy.h
new file mode 100644
index 0000000000..99c75b36a8
--- /dev/null
+++ b/Silicon/Marvell/Include/Protocol/MvPhy.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 __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_SFI
+} PHY_CONNECTION;
+
+typedef enum {
+ NO_SPEED,
+ SPEED_10,
+ SPEED_100,
+ SPEED_1000,
+ SPEED_2500,
+ SPEED_10000
+} PHY_SPEED;
+
+typedef struct {
+ UINT32 Addr;
+ UINT8 MdioIndex;
+ 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/Silicon/Marvell/Include/Protocol/Spi.h b/Silicon/Marvell/Include/Protocol/Spi.h
new file mode 100644
index 0000000000..abbad19749
--- /dev/null
+++ b/Silicon/Marvell/Include/Protocol/Spi.h
@@ -0,0 +1,119 @@
+/*******************************************************************************
+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__
+
+#include <Library/NorFlashInfoLib.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;
+ UINT32 AddrSize;
+ NOR_FLASH_INFO *Info;
+ UINTN HostRegisterBaseAddress;
+ UINTN CoreClock;
+} 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 SPI_DEVICE *Slave,
+ IN UINTN Cs,
+ IN SPI_MODE Mode
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *MV_SPI_FREE_DEVICE) (
+ IN SPI_DEVICE *SpiDev
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *MV_SPI_CONFIG_RT) (
+ 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;
+ MV_SPI_CONFIG_RT ConfigRuntime;
+};
+
+#endif // __MARVELL_SPI_MASTER_PROTOCOL_H__
diff --git a/Silicon/Marvell/Include/Protocol/SpiFlash.h b/Silicon/Marvell/Include/Protocol/SpiFlash.h
new file mode 100644
index 0000000000..4ba29ba769
--- /dev/null
+++ b/Silicon/Marvell/Include/Protocol/SpiFlash.h
@@ -0,0 +1,101 @@
+/*******************************************************************************
+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>
+
+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 BOOLEAN UseInRuntime
+ );
+
+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/Silicon/Marvell/Library/ComPhyLib/ComPhyCp110.c b/Silicon/Marvell/Library/ComPhyLib/ComPhyCp110.c
new file mode 100755
index 0000000000..40a7b9921c
--- /dev/null
+++ b/Silicon/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/Silicon/Marvell/Library/ComPhyLib/ComPhyLib.c b/Silicon/Marvell/Library/ComPhyLib/ComPhyLib.c
new file mode 100644
index 0000000000..bf21dca3fb
--- /dev/null
+++ b/Silicon/Marvell/Library/ComPhyLib/ComPhyLib.c
@@ -0,0 +1,278 @@
+/********************************************************************************
+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);
+}
+
+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,
+ IN UINT8 Index
+ )
+{
+ 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-%d: %-13s %-10s\n", Index, 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 (LaneData, 0);
+ break;
+ case 1:
+ GetComPhyPcd (LaneData, 1);
+ break;
+ case 2:
+ GetComPhyPcd (LaneData, 2);
+ break;
+ case 3:
+ GetComPhyPcd (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++) {
+ PtrChipCfg->MapData[Lane].Type = LaneData[Index].Type[Lane];
+ PtrChipCfg->MapData[Lane].Speed = LaneData[Index].SpeedValue[Lane];
+ PtrChipCfg->MapData[Lane].Invert = 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, Index);
+
+ /* PHY power UP sequence */
+ PtrChipCfg->Init (PtrChipCfg);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/Marvell/Library/ComPhyLib/ComPhyLib.h b/Silicon/Marvell/Library/ComPhyLib/ComPhyLib.h
new file mode 100644
index 0000000000..5899a4ac25
--- /dev/null
+++ b/Silicon/Marvell/Library/ComPhyLib/ComPhyLib.h
@@ -0,0 +1,638 @@
+/********************************************************************************
+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>
+
+#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 GetComPhyPcd(lane_struct, id) { \
+ lane_struct[id].Type = (UINT8 *)GET_LANE_TYPE(id); \
+ lane_struct[id].SpeedValue = (UINT8 *)GET_LANE_SPEED(id); \
+ lane_struct[id].InvFlag = (UINT8 *)GET_LANE_SPEED(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 {
+ UINT8 Type;
+ UINT8 Speed;
+ UINT8 Invert;
+} COMPHY_MAP;
+
+typedef struct {
+ UINT8 *Type;
+ UINT8 *SpeedValue;
+ UINT8 *InvFlag;
+} 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/Silicon/Marvell/Library/ComPhyLib/ComPhyLib.inf b/Silicon/Marvell/Library/ComPhyLib/ComPhyLib.inf
new file mode 100644
index 0000000000..a1584b4cfc
--- /dev/null
+++ b/Silicon/Marvell/Library/ComPhyLib/ComPhyLib.inf
@@ -0,0 +1,83 @@
+# 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
+ Silicon/Marvell/Marvell.dec
+
+[LibraryClasses]
+ ArmLib
+ DebugLib
+ MemoryAllocationLib
+ PcdLib
+ IoLib
+
+[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/Silicon/Marvell/Library/ComPhyLib/ComPhyMux.c b/Silicon/Marvell/Library/ComPhyLib/ComPhyMux.c
new file mode 100644
index 0000000000..6589fec9f0
--- /dev/null
+++ b/Silicon/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/Silicon/Marvell/Library/MppLib/MppLib.c b/Silicon/Marvell/Library/MppLib/MppLib.c
new file mode 100644
index 0000000000..297725f6af
--- /dev/null
+++ b/Silicon/Marvell/Library/MppLib/MppLib.c
@@ -0,0 +1,217 @@
+/********************************************************************************
+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[][MPP_PINS_PER_REG],
+ UINTN BaseAddr,
+ BOOLEAN ReverseFlag
+ )
+{
+ UINT32 i, j, CtrlVal, CtrlMask, PinIndex;
+ INTN Sign;
+
+ Sign = ReverseFlag ? -1 : 1;
+
+ for (i = 0; i < RegCount; i++) {
+ CtrlVal = 0;
+ CtrlMask = 0;
+ for (j = 0; j < MPP_PINS_PER_REG; j++) {
+
+ PinIndex = 7 * (UINTN)ReverseFlag + j * Sign;
+
+ if (MppRegPcd[i][PinIndex] != 0xff) {
+ CtrlVal |= MPP_PIN_VAL(PinIndex, MppRegPcd[i][PinIndex]);
+ CtrlMask |= MPP_PIN_VAL(PinIndex, 0xf);
+ }
+ }
+ MmioAndThenOr32 (BaseAddr + 4 * i * Sign, ~CtrlMask, CtrlVal);
+ }
+}
+
+STATIC
+/* Transform PCD MPP group format into hardware register format */
+UINT8
+PcdToMppRegs (
+ UINTN PinCount,
+ UINT8 **MppRegPcd,
+ UINT8 MppRegPcdTmp[][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] = (UINT8)MppRegPcd[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;
+ UINT8 TmpMppValue[MPP_MAX_REGS][MPP_PINS_PER_REG];
+
+ 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], TmpMppValue);
+ SetRegisterValue (RegCount, TmpMppValue, BaseAddr[i], ReverseFlag[i]);
+
+ /*
+ * eMMC PHY IP has its own MPP configuration.
+ */
+ SetSdMmcPhyMpp (BaseAddr[i], i);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/Marvell/Library/MppLib/MppLib.inf b/Silicon/Marvell/Library/MppLib/MppLib.inf
new file mode 100644
index 0000000000..9d7e9f0914
--- /dev/null
+++ b/Silicon/Marvell/Library/MppLib/MppLib.inf
@@ -0,0 +1,111 @@
+#
+# 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
+ Silicon/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
+
+[BuildOptions]
+ *_*_*_CC_FLAGS = -fno-stack-protector
diff --git a/Silicon/Marvell/Library/UtmiPhyLib/UtmiPhyLib.c b/Silicon/Marvell/Library/UtmiPhyLib/UtmiPhyLib.c
new file mode 100644
index 0000000000..2cd9cfa88f
--- /dev/null
+++ b/Silicon/Marvell/Library/UtmiPhyLib/UtmiPhyLib.c
@@ -0,0 +1,354 @@
+/********************************************************************************
+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"
+#include <Library/MvHwDescLib.h>
+
+DECLARE_A7K8K_UTMI_TEMPLATE;
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS UtmiBaseAddr;
+ EFI_PHYSICAL_ADDRESS UsbCfgAddr;
+ EFI_PHYSICAL_ADDRESS UtmiCfgAddr;
+ UINT32 UtmiPhyPort;
+ UINT32 PhyId;
+} 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 UTMI_PHY_DATA *UtmiData
+ )
+{
+ EFI_STATUS Status;
+
+ UtmiPhyPowerDown (UtmiData->PhyId,
+ UtmiData->UtmiBaseAddr,
+ UtmiData->UsbCfgAddr,
+ UtmiData->UtmiCfgAddr,
+ UtmiData->UtmiPhyPort);
+
+ /* Power down PLL */
+ DEBUG((DEBUG_INFO, "UtmiPhy: stage: PHY power down PLL\n"));
+ MmioAnd32 (UtmiData->UsbCfgAddr, ~UTMI_USB_CFG_PLL_MASK);
+
+ UtmiPhyConfig (UtmiData->PhyId,
+ UtmiData->UtmiBaseAddr,
+ UtmiData->UsbCfgAddr,
+ UtmiData->UtmiCfgAddr,
+ UtmiData->UtmiPhyPort);
+
+ Status = UtmiPhyPowerUp (UtmiData->PhyId,
+ UtmiData->UtmiBaseAddr,
+ UtmiData->UsbCfgAddr,
+ UtmiData->UtmiCfgAddr,
+ UtmiData->UtmiPhyPort);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "UtmiPhy: Failed to initialize UTMI PHY %d\n", UtmiData->PhyId));
+ return;
+ }
+
+ DEBUG ((DEBUG_ERROR, "UTMI PHY %d initialized to ", UtmiData->PhyId));
+ if (UtmiData->UtmiPhyPort == UTMI_PHY_TO_USB_DEVICE0) {
+ DEBUG ((DEBUG_ERROR, "USB Device\n"));
+ } else {
+ DEBUG ((DEBUG_ERROR, "USB Host%d\n", UtmiData->UtmiPhyPort));
+ }
+
+ /* Power up PLL */
+ DEBUG((DEBUG_INFO, "UtmiPhy: stage: PHY power up PLL\n"));
+ MmioOr32 (UtmiData->UsbCfgAddr, UTMI_USB_CFG_PLL_MASK);
+}
+
+EFI_STATUS
+UtmiPhyInit (
+ VOID
+ )
+{
+ UTMI_PHY_DATA UtmiData;
+ UINT8 *UtmiDeviceTable, *XhciDeviceTable, *UtmiPortType, Index;
+ MVHW_UTMI_DESC *Desc = &mA7k8kUtmiDescTemplate;
+
+ /* Obtain table with enabled Utmi PHY's*/
+ UtmiDeviceTable = (UINT8 *)PcdGetPtr (PcdUtmiControllersEnabled);
+ if (UtmiDeviceTable == NULL) {
+ /* No UTMI PHY on platform */
+ return EFI_SUCCESS;
+ }
+
+ if (PcdGetSize (PcdUtmiControllersEnabled) > MVHW_MAX_XHCI_DEVS) {
+ DEBUG ((DEBUG_ERROR, "UTMI: Wrong PcdUtmiControllersEnabled format\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ /* Make sure XHCI controllers table is present */
+ XhciDeviceTable = (UINT8 *)PcdGetPtr (PcdPciEXhci);
+ if (XhciDeviceTable == NULL) {
+ DEBUG ((DEBUG_ERROR, "UTMI: Missing PcdPciEXhci\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ /* Obtain port type table */
+ UtmiPortType = (UINT8 *)PcdGetPtr (PcdUtmiPortType);
+ if (UtmiPortType == NULL ||
+ PcdGetSize (PcdUtmiPortType) != PcdGetSize (PcdUtmiControllersEnabled)) {
+ DEBUG ((DEBUG_ERROR, "UTMI: Wrong PcdUtmiPortType format\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ /* Initialize enabled chips */
+ for (Index = 0; Index < PcdGetSize (PcdUtmiControllersEnabled); Index++) {
+ if (!MVHW_DEV_ENABLED (Utmi, Index)) {
+ continue;
+ }
+
+ /* UTMI PHY without enabled XHCI controller is useless */
+ if (!MVHW_DEV_ENABLED (Xhci, Index)) {
+ DEBUG ((DEBUG_ERROR, "UTMI: Disabled Xhci controller %d\n", Index));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ /* Get base address of UTMI phy */
+ UtmiData.UtmiBaseAddr = Desc->UtmiBaseAddresses[Index];
+
+ /* Get usb config address */
+ UtmiData.UsbCfgAddr = Desc->UtmiUsbConfigAddresses[Index];
+
+ /* Get UTMI config address */
+ UtmiData.UtmiCfgAddr = Desc->UtmiConfigAddresses[Index];
+
+ /* Get UTMI PHY ID */
+ UtmiData.PhyId = Desc->UtmiPhyId[Index];
+
+ /* Get the usb port type */
+ UtmiData.UtmiPhyPort = UtmiPortType[Index];
+
+ /* Currently only Cp110 is supported */
+ Cp110UtmiPhyInit (&UtmiData);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/Marvell/Library/UtmiPhyLib/UtmiPhyLib.h b/Silicon/Marvell/Library/UtmiPhyLib/UtmiPhyLib.h
new file mode 100644
index 0000000000..0d7d72e72b
--- /dev/null
+++ b/Silicon/Marvell/Library/UtmiPhyLib/UtmiPhyLib.h
@@ -0,0 +1,109 @@
+/********************************************************************************
+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>
+
+#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/Silicon/Marvell/Library/UtmiPhyLib/UtmiPhyLib.inf b/Silicon/Marvell/Library/UtmiPhyLib/UtmiPhyLib.inf
new file mode 100644
index 0000000000..0876879e7d
--- /dev/null
+++ b/Silicon/Marvell/Library/UtmiPhyLib/UtmiPhyLib.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 = 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
+ Silicon/Marvell/Marvell.dec
+
+[LibraryClasses]
+ ArmLib
+ DebugLib
+ IoLib
+ MemoryAllocationLib
+ PcdLib
+
+[Sources.common]
+ UtmiPhyLib.c
+
+[Pcd]
+ gMarvellTokenSpaceGuid.PcdUtmiControllersEnabled
+ gMarvellTokenSpaceGuid.PcdUtmiPortType
+ gMarvellTokenSpaceGuid.PcdPciEXhci
diff --git a/Silicon/Marvell/Marvell.dec b/Silicon/Marvell/Marvell.dec
new file mode 100644
index 0000000000..2eb62388a1
--- /dev/null
+++ b/Silicon/Marvell/Marvell.dec
@@ -0,0 +1,212 @@
+# 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 } }
+
+ gMarvellFvbDxeGuid = { 0x42903750, 0x7e61, 0x4aaf, { 0x83, 0x29, 0xbf, 0x42, 0x36, 0x4e, 0x24, 0x85 } }
+ gMarvellSpiFlashDxeGuid = { 0x49d7fb74, 0x306d, 0x42bd, { 0x94, 0xc8, 0xc0, 0xc5, 0x4b, 0x18, 0x1d, 0xd7 } }
+
+[Protocols]
+ # installed as a protocol by PlatInitDxe to force ordering between DXE drivers
+ # that depend on the lowlevel platform initialization having been completed
+ gMarvellPlatformInitCompleteProtocolGuid = { 0x465b8cf7, 0x016f, 0x4ba6, { 0xbe, 0x6b, 0x28, 0x0e, 0x3a, 0x7d, 0x38, 0x6f } }
+
+[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.PcdI2cControllersEnabled|{ 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.PcdSpiMemoryBase|0|UINT32|0x3000059
+ gMarvellTokenSpaceGuid.PcdSpiMaxFrequency|0|UINT32|0x30000052
+ gMarvellTokenSpaceGuid.PcdSpiClockFrequency|0|UINT32|0x30000053
+
+ gMarvellTokenSpaceGuid.PcdSpiFlashCs|0|UINT32|0x3000057
+ gMarvellTokenSpaceGuid.PcdSpiFlashMode|0|UINT32|0x3000058
+
+#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.PcdUtmiControllersEnabled|{ 0x0 }|VOID*|0x30000206
+ gMarvellTokenSpaceGuid.PcdUtmiPortType|{ 0x0 }|VOID*|0x30000207
+
+#MDIO
+ gMarvellTokenSpaceGuid.PcdMdioControllersEnabled|{ 0x0 }|VOID*|0x3000043
+
+#PHY
+ gMarvellTokenSpaceGuid.PcdPhy2MdioController|{ 0x0 }|VOID*|0x3000027
+ gMarvellTokenSpaceGuid.PcdPhyDeviceIds|{ 0x0 }|VOID*|0x3000095
+ gMarvellTokenSpaceGuid.PcdPhySmiAddresses|{ 0x0 }|VOID*|0x3000024
+ gMarvellTokenSpaceGuid.PcdPhyStartupAutoneg|FALSE|BOOLEAN|0x3000070
+
+#NET
+ gMarvellTokenSpaceGuid.PcdPp2Controllers|{ 0x0 }|VOID*|0x3000028
+ gMarvellTokenSpaceGuid.PcdPp2GopIndexes|{ 0x0 }|VOID*|0x3000029
+ gMarvellTokenSpaceGuid.PcdPp2InterfaceAlwaysUp|{ 0x0 }|VOID*|0x300002A
+ gMarvellTokenSpaceGuid.PcdPp2InterfaceSpeed|{ 0x0 }|VOID*|0x300002B
+ gMarvellTokenSpaceGuid.PcdPp2PhyConnectionTypes|{ 0x0 }|VOID*|0x3000044
+ gMarvellTokenSpaceGuid.PcdPp2PhyIndexes|{ 0x0 }|VOID*|0x3000045
+ gMarvellTokenSpaceGuid.PcdPp2Port2Controller|{ 0x0 }|VOID*|0x300002D
+ gMarvellTokenSpaceGuid.PcdPp2PortIds|{ 0x0 }|VOID*|0x300002C
+
+#PciEmulation
+ gMarvellTokenSpaceGuid.PcdPciEXhci|{ 0x0 }|VOID*|0x3000033
+ gMarvellTokenSpaceGuid.PcdPciEAhci|{ 0x0 }|VOID*|0x3000034
+ gMarvellTokenSpaceGuid.PcdPciESdhci|{ 0x0 }|VOID*|0x3000035
+
+#RTC
+ gMarvellTokenSpaceGuid.PcdRtcEnabled|{ 0x0 }|VOID*|0x40000052
+
+#TRNG
+ gMarvellTokenSpaceGuid.PcdEip76TrngBaseAddress|0x0|UINT64|0x50000053
+
+#Configuration space
+ gMarvellTokenSpaceGuid.PcdConfigSpaceBaseAddress|0xF0000000|UINT64|0x50000054
+
+ #
+ # The secure firmware may occupy a DRAM region that is accessible by the
+ # normal world. These PCDs describe such a region, which will be converted
+ # to 'reserved' memory before DXE is entered.
+ #
+ gMarvellTokenSpaceGuid.PcdSecureRegionBase|0x0|UINT64|0x50000000
+ gMarvellTokenSpaceGuid.PcdSecureRegionSize|0x0|UINT32|0x50000001
+
+[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/Silicon/Marvell/PciEmulation/PciEmulation.c b/Silicon/Marvell/PciEmulation/PciEmulation.c
new file mode 100644
index 0000000000..35f1a87d81
--- /dev/null
+++ b/Silicon/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/Silicon/Marvell/PciEmulation/PciEmulation.inf b/Silicon/Marvell/PciEmulation/PciEmulation.inf
new file mode 100644
index 0000000000..c6a3c99827
--- /dev/null
+++ b/Silicon/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
+ Silicon/Marvell/Marvell.dec
+
+[LibraryClasses]
+ NonDiscoverableDeviceRegistrationLib
+ UefiDriverEntryPoint
+
+[Pcd]
+ gMarvellTokenSpaceGuid.PcdPciEXhci
+ gMarvellTokenSpaceGuid.PcdPciEAhci
+ gMarvellTokenSpaceGuid.PcdPciESdhci
+
+[Depex]
+ TRUE