From 0189ff331b9bdd9353624bc7b509e53148976806 Mon Sep 17 00:00:00 2001 From: Leif Lindholm Date: Wed, 3 May 2017 17:47:23 +0100 Subject: Platform: import Marvell Armada support Import Armada 70x0 suppport from OpenPlatformPkg, together with its documentation and utilities. Imported from commit efd798c1eb of https://git.linaro.org/uefi/OpenPlatformPkg.git Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Leif Lindholm --- .../Marvell/Applications/EepromCmd/EepromCmd.c | 397 ++ .../Marvell/Applications/EepromCmd/EepromCmd.inf | 71 + .../Marvell/Applications/EepromCmd/EepromCmd.uni | Bin 0 -> 6816 bytes .../Marvell/Applications/FirmwareUpdate/FUpdate.c | 413 ++ .../Applications/FirmwareUpdate/FUpdate.inf | 75 + .../Applications/FirmwareUpdate/FUpdate.uni | Bin 0 -> 5146 bytes .../Marvell/Applications/SpiTool/SpiFlashCmd.c | 526 +++ .../Marvell/Applications/SpiTool/SpiFlashCmd.inf | 75 + .../Marvell/Applications/SpiTool/SpiFlashCmd.uni | Bin 0 -> 7216 bytes Platform/Marvell/Armada/Armada.dsc.inc | 482 ++ Platform/Marvell/Armada/Armada70x0.dsc | 145 + Platform/Marvell/Armada/Armada70x0.fdf | 304 ++ .../Armada70x0Lib/AArch64/ArmPlatformHelper.S | 50 + .../Armada/Library/Armada70x0Lib/Armada70x0Lib.c | 157 + .../Armada/Library/Armada70x0Lib/Armada70x0Lib.inf | 71 + .../Library/Armada70x0Lib/Armada70x0LibMem.c | 93 + .../Library/RealTimeClockLib/RealTimeClockLib.c | 335 ++ .../Library/RealTimeClockLib/RealTimeClockLib.h | 50 + .../Library/RealTimeClockLib/RealTimeClockLib.inf | 52 + .../Marvell/Documentation/Drivers/EepromDriver.txt | 96 + .../Marvell/Documentation/Drivers/I2cDriver.txt | 64 + .../Marvell/Documentation/Drivers/SpiDriver.txt | 116 + .../Marvell/Documentation/PortingGuide/ComPhy.txt | 45 + .../Marvell/Documentation/PortingGuide/I2c.txt | 20 + .../Marvell/Documentation/PortingGuide/Mdio.txt | 7 + .../Marvell/Documentation/PortingGuide/Mpp.txt | 48 + .../Documentation/PortingGuide/PciEmulation.txt | 31 + .../Marvell/Documentation/PortingGuide/Phy.txt | 45 + .../Marvell/Documentation/PortingGuide/Pp2.txt | 59 + .../Marvell/Documentation/PortingGuide/Reset.txt | 7 + .../Marvell/Documentation/PortingGuide/Spi.txt | 16 + .../Documentation/PortingGuide/SpiFlash.txt | 23 + .../Marvell/Documentation/PortingGuide/Utmi.txt | 35 + .../Drivers/I2c/Devices/MvEeprom/MvEeprom.c | 292 ++ .../Drivers/I2c/Devices/MvEeprom/MvEeprom.h | 103 + .../Drivers/I2c/Devices/MvEeprom/MvEeprom.inf | 70 + Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.c | 740 +++ Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.h | 269 ++ Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf | 75 + Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.c | 237 + Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.h | 57 + .../Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.inf | 69 + .../Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.c | 438 ++ .../Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.h | 194 + .../Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.inf | 71 + Platform/Marvell/Drivers/Net/Pp2Dxe/Mvpp2Lib.c | 4839 ++++++++++++++++++++ Platform/Marvell/Drivers/Net/Pp2Dxe/Mvpp2Lib.h | 726 +++ Platform/Marvell/Drivers/Net/Pp2Dxe/Mvpp2LibHw.h | 1968 ++++++++ Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.c | 1271 +++++ Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.h | 614 +++ Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.inf | 91 + .../Marvell/Drivers/SdMmc/XenonDxe/ComponentName.c | 211 + .../Marvell/Drivers/SdMmc/XenonDxe/EmmcDevice.c | 1162 +++++ Platform/Marvell/Drivers/SdMmc/XenonDxe/SdDevice.c | 1190 +++++ .../Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.c | 1315 ++++++ .../Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.h | 785 ++++ .../Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.inf | 64 + .../Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.uni | 23 + .../Drivers/SdMmc/XenonDxe/SdMmcPciHcDxeExtra.uni | 19 + .../Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHci.c | 1923 ++++++++ .../Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHci.h | 546 +++ .../Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.c | 665 +++ .../Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.h | 346 ++ Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.c | 531 +++ Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.h | 132 + .../Marvell/Drivers/Spi/Devices/MvSpiFlash.inf | 67 + Platform/Marvell/Drivers/Spi/MvSpiDxe.c | 379 ++ Platform/Marvell/Drivers/Spi/MvSpiDxe.h | 145 + Platform/Marvell/Drivers/Spi/MvSpiDxe.inf | 66 + Platform/Marvell/Include/Library/MppLib.h | 42 + Platform/Marvell/Include/Library/MvComPhyLib.h | 48 + Platform/Marvell/Include/Library/MvHwDescLib.h | 169 + Platform/Marvell/Include/Library/ParsePcdLib.h | 46 + Platform/Marvell/Include/Library/UtmiPhyLib.h | 43 + Platform/Marvell/Include/Protocol/Eeprom.h | 60 + Platform/Marvell/Include/Protocol/Mdio.h | 66 + Platform/Marvell/Include/Protocol/MvPhy.h | 103 + Platform/Marvell/Include/Protocol/Spi.h | 105 + Platform/Marvell/Include/Protocol/SpiFlash.h | 113 + Platform/Marvell/Library/ComPhyLib/ComPhyCp110.c | 1853 ++++++++ Platform/Marvell/Library/ComPhyLib/ComPhyLib.c | 321 ++ Platform/Marvell/Library/ComPhyLib/ComPhyLib.h | 643 +++ Platform/Marvell/Library/ComPhyLib/ComPhyLib.inf | 84 + Platform/Marvell/Library/ComPhyLib/ComPhyMux.c | 132 + Platform/Marvell/Library/MppLib/MppLib.c | 216 + Platform/Marvell/Library/MppLib/MppLib.inf | 108 + Platform/Marvell/Library/ParsePcdLib/ParsePcdLib.c | 228 + .../Marvell/Library/ParsePcdLib/ParsePcdLib.inf | 50 + Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.c | 353 ++ Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.h | 110 + Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.inf | 64 + Platform/Marvell/Marvell.dec | 204 + Platform/Marvell/PciEmulation/PciEmulation.c | 195 + Platform/Marvell/PciEmulation/PciEmulation.inf | 61 + 94 files changed, 31018 insertions(+) create mode 100644 Platform/Marvell/Applications/EepromCmd/EepromCmd.c create mode 100644 Platform/Marvell/Applications/EepromCmd/EepromCmd.inf create mode 100644 Platform/Marvell/Applications/EepromCmd/EepromCmd.uni create mode 100644 Platform/Marvell/Applications/FirmwareUpdate/FUpdate.c create mode 100644 Platform/Marvell/Applications/FirmwareUpdate/FUpdate.inf create mode 100644 Platform/Marvell/Applications/FirmwareUpdate/FUpdate.uni create mode 100644 Platform/Marvell/Applications/SpiTool/SpiFlashCmd.c create mode 100644 Platform/Marvell/Applications/SpiTool/SpiFlashCmd.inf create mode 100644 Platform/Marvell/Applications/SpiTool/SpiFlashCmd.uni create mode 100644 Platform/Marvell/Armada/Armada.dsc.inc create mode 100644 Platform/Marvell/Armada/Armada70x0.dsc create mode 100644 Platform/Marvell/Armada/Armada70x0.fdf create mode 100644 Platform/Marvell/Armada/Library/Armada70x0Lib/AArch64/ArmPlatformHelper.S create mode 100644 Platform/Marvell/Armada/Library/Armada70x0Lib/Armada70x0Lib.c create mode 100644 Platform/Marvell/Armada/Library/Armada70x0Lib/Armada70x0Lib.inf create mode 100644 Platform/Marvell/Armada/Library/Armada70x0Lib/Armada70x0LibMem.c create mode 100644 Platform/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.c create mode 100644 Platform/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.h create mode 100644 Platform/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.inf create mode 100644 Platform/Marvell/Documentation/Drivers/EepromDriver.txt create mode 100644 Platform/Marvell/Documentation/Drivers/I2cDriver.txt create mode 100644 Platform/Marvell/Documentation/Drivers/SpiDriver.txt create mode 100644 Platform/Marvell/Documentation/PortingGuide/ComPhy.txt create mode 100644 Platform/Marvell/Documentation/PortingGuide/I2c.txt create mode 100644 Platform/Marvell/Documentation/PortingGuide/Mdio.txt create mode 100644 Platform/Marvell/Documentation/PortingGuide/Mpp.txt create mode 100644 Platform/Marvell/Documentation/PortingGuide/PciEmulation.txt create mode 100644 Platform/Marvell/Documentation/PortingGuide/Phy.txt create mode 100644 Platform/Marvell/Documentation/PortingGuide/Pp2.txt create mode 100644 Platform/Marvell/Documentation/PortingGuide/Reset.txt create mode 100644 Platform/Marvell/Documentation/PortingGuide/Spi.txt create mode 100644 Platform/Marvell/Documentation/PortingGuide/SpiFlash.txt create mode 100644 Platform/Marvell/Documentation/PortingGuide/Utmi.txt create mode 100644 Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.c create mode 100644 Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.h create mode 100644 Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.inf create mode 100755 Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.c create mode 100644 Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.h create mode 100755 Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf create mode 100644 Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.c create mode 100644 Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.h create mode 100644 Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.inf create mode 100644 Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.c create mode 100644 Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.h create mode 100644 Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.inf create mode 100644 Platform/Marvell/Drivers/Net/Pp2Dxe/Mvpp2Lib.c create mode 100644 Platform/Marvell/Drivers/Net/Pp2Dxe/Mvpp2Lib.h create mode 100644 Platform/Marvell/Drivers/Net/Pp2Dxe/Mvpp2LibHw.h create mode 100644 Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.c create mode 100644 Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.h create mode 100644 Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.inf create mode 100644 Platform/Marvell/Drivers/SdMmc/XenonDxe/ComponentName.c create mode 100755 Platform/Marvell/Drivers/SdMmc/XenonDxe/EmmcDevice.c create mode 100644 Platform/Marvell/Drivers/SdMmc/XenonDxe/SdDevice.c create mode 100644 Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.c create mode 100644 Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.h create mode 100644 Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.inf create mode 100644 Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.uni create mode 100644 Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxeExtra.uni create mode 100644 Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHci.c create mode 100644 Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHci.h create mode 100755 Platform/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.c create mode 100644 Platform/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.h create mode 100755 Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.c create mode 100755 Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.h create mode 100644 Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.inf create mode 100755 Platform/Marvell/Drivers/Spi/MvSpiDxe.c create mode 100644 Platform/Marvell/Drivers/Spi/MvSpiDxe.h create mode 100644 Platform/Marvell/Drivers/Spi/MvSpiDxe.inf create mode 100644 Platform/Marvell/Include/Library/MppLib.h create mode 100644 Platform/Marvell/Include/Library/MvComPhyLib.h create mode 100644 Platform/Marvell/Include/Library/MvHwDescLib.h create mode 100644 Platform/Marvell/Include/Library/ParsePcdLib.h create mode 100644 Platform/Marvell/Include/Library/UtmiPhyLib.h create mode 100644 Platform/Marvell/Include/Protocol/Eeprom.h create mode 100644 Platform/Marvell/Include/Protocol/Mdio.h create mode 100644 Platform/Marvell/Include/Protocol/MvPhy.h create mode 100644 Platform/Marvell/Include/Protocol/Spi.h create mode 100644 Platform/Marvell/Include/Protocol/SpiFlash.h create mode 100755 Platform/Marvell/Library/ComPhyLib/ComPhyCp110.c create mode 100644 Platform/Marvell/Library/ComPhyLib/ComPhyLib.c create mode 100644 Platform/Marvell/Library/ComPhyLib/ComPhyLib.h create mode 100644 Platform/Marvell/Library/ComPhyLib/ComPhyLib.inf create mode 100644 Platform/Marvell/Library/ComPhyLib/ComPhyMux.c create mode 100644 Platform/Marvell/Library/MppLib/MppLib.c create mode 100644 Platform/Marvell/Library/MppLib/MppLib.inf create mode 100644 Platform/Marvell/Library/ParsePcdLib/ParsePcdLib.c create mode 100644 Platform/Marvell/Library/ParsePcdLib/ParsePcdLib.inf create mode 100644 Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.c create mode 100644 Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.h create mode 100644 Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.inf create mode 100644 Platform/Marvell/Marvell.dec create mode 100644 Platform/Marvell/PciEmulation/PciEmulation.c create mode 100644 Platform/Marvell/PciEmulation/PciEmulation.inf diff --git a/Platform/Marvell/Applications/EepromCmd/EepromCmd.c b/Platform/Marvell/Applications/EepromCmd/EepromCmd.c new file mode 100644 index 0000000000..f43e411067 --- /dev/null +++ b/Platform/Marvell/Applications/EepromCmd/EepromCmd.c @@ -0,0 +1,397 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#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] [] [][
] [] [-d ] [-m ]\n" + "All modes except 'list' require Address, Length and Chip set.\n\n" + "read - read from EEPROM\n" + "write - write Data to EEPROM, requires -d\n" + "list - list available EEPROM devices\n\n" + "-m - transfer from/to RAM memory\n\n" + "Chip - EEPROM bus address\n" + "Bus - I2C bus address\n" + "Address - address in EEPROM to read/write\n" + "Data - data byte to be written\n" + "Length - length of data to read/write/copy\n" + "Source - address of data in RAM to be copied\n" + "Examples:\n" + "List devices:\n" + " eeprom list\n" + "Read 16 bytes from address 0x0 in chip 0x57:\n" + " eeprom read 0x57 0x0 0x0 0x10\n" + "Fill 16 bytes with 0xab at address 0x0 in chip 0x57:\n" + " eeprom write 0x57 0x0 0x0 0x10 -d 0xab\n" + "Copy 32 bytes from 0x2000000 in RAM to EEPROM:\n" + " eeprom write 0x57 0x0 0x0 0x20 -m 0x2000000\n" + "Copy 32 bytes from EEPROM to RAM:\n" + " eeprom read 0x57 0x0 0x0 0x20 -m 0x2000000\n" + ); +} + +STATIC +EFI_STATUS +EepromList ( + ) +{ + EFI_HANDLE *HandleBuffer; + EFI_STATUS Status; + UINTN ProtocolCount; + MARVELL_EEPROM_PROTOCOL *EepromProtocol; + UINTN i; + Status = gBS->LocateHandleBuffer ( ByProtocol, + &gMarvellEepromProtocolGuid, + NULL, + &ProtocolCount, + &HandleBuffer + ); + if (ProtocolCount == 0) { + Print (L"0 devices found.\n"); + } else { + Print (L"%u devices found: ", ProtocolCount); + } + + for (i = 0; i < ProtocolCount; i++) { + Status = gBS->OpenProtocol ( + HandleBuffer[i], + &gMarvellEepromProtocolGuid, + (VOID **) &EepromProtocol, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL ); + Print (L"0x%x at bus %d\n", I2C_DEVICE_ADDRESS(EepromProtocol->Identifier), + I2C_DEVICE_BUS(EepromProtocol->Identifier)); + Status = gBS->CloseProtocol ( HandleBuffer[i], + &gMarvellEepromProtocolGuid, + gImageHandle, + NULL ); + } + Print (L"\n"); + return Status; +} + +STATIC +EFI_STATUS +EepromLocateProtocol ( + IN UINT32 Identifier, + OUT EFI_HANDLE *FoundHandle, + OUT MARVELL_EEPROM_PROTOCOL **FoundEepromProtocol + ) +{ + EFI_HANDLE *HandleBuffer; + EFI_STATUS Status; + UINTN ProtocolCount; + MARVELL_EEPROM_PROTOCOL *EepromProtocol; + UINTN i; + Status = gBS->LocateHandleBuffer ( ByProtocol, + &gMarvellEepromProtocolGuid, + NULL, + &ProtocolCount, + &HandleBuffer + ); + if (EFI_ERROR(Status)) + return Status; + + for (i = 0; i < ProtocolCount; i++) { + Status = gBS->OpenProtocol ( + HandleBuffer[i], + &gMarvellEepromProtocolGuid, + (VOID **) &EepromProtocol, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL ); + if (EepromProtocol->Identifier == Identifier) { + *FoundEepromProtocol = EepromProtocol; + *FoundHandle = HandleBuffer[i]; + return EFI_SUCCESS; + } + Status = gBS->CloseProtocol ( HandleBuffer[i], + &gMarvellEepromProtocolGuid, + gImageHandle, + NULL ); + } + *FoundEepromProtocol = NULL; + return EFI_UNSUPPORTED; +} + +SHELL_STATUS +EFIAPI +ShellCommandRunEeprom ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *CheckPackage; + CHAR16 *ProblemParam; + CONST CHAR16 *ValueStr; + UINTN Address, Length, Chip, Source, Bus; + UINT8 Data; + UINT8 *Buffer; + BOOLEAN ReadMode, MemMode; + EFI_HANDLE Handle, ProtHandle; + MARVELL_EEPROM_PROTOCOL *EepromProtocol = NULL; + UINTN Count, HandleSize; + + Handle = NULL; + Source = 0; + HandleSize = 2 * sizeof (EFI_HANDLE); + + Status = gBS->LocateHandle (ByProtocol, &gMarvellEepromProtocolGuid, NULL, + &HandleSize, &ProtHandle); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_INFO, "No Eeprom protocol, connect I2C stack\n")); + Status = gBS->LocateHandle (ByProtocol, &gEfiI2cMasterProtocolGuid, NULL, + &HandleSize, &ProtHandle); + if (EFI_ERROR(Status)) { + Print (L"Failed to locate I2cMaster protocol, abort!\n"); + return SHELL_ABORTED; + } + Status = gBS->ConnectController (ProtHandle, NULL, NULL, TRUE); + if (EFI_ERROR(Status)) { + Print (L"Cannot connect I2C stack, abort!\n"); + return SHELL_ABORTED; + } + } + + Status = ShellInitialize (); + if (EFI_ERROR (Status)) { + Print (L"Error - failed to initialize shell\n"); + return SHELL_ABORTED; + } + + Status = ShellCommandLineParse (ParamList, &CheckPackage, &ProblemParam, TRUE); + if (EFI_ERROR (Status)) { + Print (L"Error - failed to parse command line\n"); + return SHELL_ABORTED; + } + + if (ShellCommandLineGetFlag (CheckPackage, L"list")) { + EepromList(); + return SHELL_SUCCESS; + } + + if (ShellCommandLineGetFlag (CheckPackage, L"help")) { + Usage(); + return SHELL_SUCCESS; + } + + if (ShellCommandLineGetCount(CheckPackage) < 4) { + Print (L"Not enough arguments given.\n"); + Usage(); + } + + ReadMode = ShellCommandLineGetFlag (CheckPackage, L"read"); + if (ReadMode == ShellCommandLineGetFlag (CheckPackage, L"write")) { + Print (L"Error - type read, write, list or help.\n"); + return SHELL_INVALID_PARAMETER; + } + + MemMode = ShellCommandLineGetFlag (CheckPackage, L"-m"); + Data = 0; + if (!ReadMode && !MemMode) { + ValueStr = ShellCommandLineGetValue (CheckPackage, L"-d"); + if (ValueStr == NULL) { + Print (L"Error - no data to write.\n"); + return SHELL_INVALID_PARAMETER; + } + Data = ShellHexStrToUintn (ValueStr); + } + + ValueStr = ShellCommandLineGetRawValue(CheckPackage, 1); + Chip = ShellHexStrToUintn (ValueStr); + + ValueStr = ShellCommandLineGetRawValue(CheckPackage, 2); + Bus = ShellHexStrToUintn (ValueStr); + + ValueStr = ShellCommandLineGetRawValue(CheckPackage, 3); + Address = ShellHexStrToUintn (ValueStr); + + ValueStr = ShellCommandLineGetRawValue(CheckPackage, 4); + Length = ShellHexStrToUintn (ValueStr); + + if (MemMode) { + ValueStr = ShellCommandLineGetValue (CheckPackage, L"-m"); + if (ValueStr == NULL) { + Print (L"Error - no memory address given.\n"); + return SHELL_INVALID_PARAMETER; + } + Source = ShellHexStrToUintn (ValueStr); + } + + EepromLocateProtocol (I2C_DEVICE_INDEX(Bus, Chip), &Handle, &EepromProtocol); + if (EepromProtocol == NULL) { + Print (L"Failed to locate EEPROM protocol.\n"); + return SHELL_INVALID_PARAMETER; + } + + if (MemMode) { + Buffer = (VOID *) Source; + } else { + Buffer = AllocateZeroPool (Length); + if (Buffer == NULL) { + Status = SHELL_OUT_OF_RESOURCES; + Print (L"Error - out of resources.\n"); + goto out_close; + } + if (!ReadMode) { + for (Count = 0; Count < Length; Count++) + Buffer[Count] = Data; + } + } + EepromProtocol->Transfer(EepromProtocol, Address, Length, Buffer, + ReadMode ? EEPROM_READ : EEPROM_WRITE); + + if (MemMode) { + Print (L"Transfered succesfully.\n"); + } else { + Print (L"Transfered:\n"); + for (Count = 0; Count < Length; Count++) { + Print(L"0x%x ", Buffer[Count]); + if (Count % 8 == 7) + Print(L"\n"); + } + Print (L"\n"); + } + + Status = SHELL_SUCCESS; + + if (!MemMode) + FreePool(Buffer); +out_close: + gBS->CloseProtocol ( Handle, + &gMarvellEepromProtocolGuid, + gImageHandle, + NULL ); + + return Status; +} + +EFI_STATUS +EFIAPI +ShellEepromCmdLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + + ShellEepromHiiHandle = NULL; + + ShellEepromHiiHandle = HiiAddPackages ( + &gShellEepromHiiGuid, gImageHandle, + UefiShellEepromLibStrings, NULL + ); + if (ShellEepromHiiHandle == NULL) { + Print (L"Filed to add Hii package\n"); + return EFI_DEVICE_ERROR; + } + ShellCommandRegisterCommandName ( + L"eeprom", ShellCommandRunEeprom, ShellCommandGetManFileNameEeprom, 0, + L"eeprom", TRUE , ShellEepromHiiHandle, STRING_TOKEN (STR_GET_HELP_EEPROM) + ); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +ShellEepromCmdLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + + if (ShellEepromHiiHandle != NULL) { + HiiRemovePackages (ShellEepromHiiHandle); + } + return EFI_SUCCESS; +} diff --git a/Platform/Marvell/Applications/EepromCmd/EepromCmd.inf b/Platform/Marvell/Applications/EepromCmd/EepromCmd.inf new file mode 100644 index 0000000000..984e60f155 --- /dev/null +++ b/Platform/Marvell/Applications/EepromCmd/EepromCmd.inf @@ -0,0 +1,71 @@ +# +# Marvell BSD License Option +# +# If you received this File from Marvell, you may opt to use, redistribute +# and/or modify this File under the following licensing terms. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Marvell nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = UefiShellEepromLib + FILE_GUID = adf4b61c-2ca3-4e1a-9597-99282f5a4aa2 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 0.1 + LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = ShellEepromCmdLibConstructor + DESTRUCTOR = ShellEepromCmdLibDestructor + +[Sources] + EepromCmd.c + EepromCmd.uni + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + StdLib/StdLib.dec + MdeModulePkg/MdeModulePkg.dec + Platform/Marvell/Marvell.dec + +[LibraryClasses] + UefiLib + UefiBootServicesTableLib + MemoryAllocationLib + BaseLib + BaseMemoryLib + DebugLib + ShellCommandLib + ShellLib + UefiLib + UefiRuntimeServicesTableLib + PcdLib + +[Protocols] + gMarvellEepromProtocolGuid + gEfiI2cMasterProtocolGuid + +[Guids] + gShellEepromHiiGuid diff --git a/Platform/Marvell/Applications/EepromCmd/EepromCmd.uni b/Platform/Marvell/Applications/EepromCmd/EepromCmd.uni new file mode 100644 index 0000000000..e41c6d812e Binary files /dev/null and b/Platform/Marvell/Applications/EepromCmd/EepromCmd.uni differ diff --git a/Platform/Marvell/Applications/FirmwareUpdate/FUpdate.c b/Platform/Marvell/Applications/FirmwareUpdate/FUpdate.c new file mode 100644 index 0000000000..edb698610d --- /dev/null +++ b/Platform/Marvell/Applications/FirmwareUpdate/FUpdate.c @@ -0,0 +1,413 @@ +/******************************************************************************* +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define CMD_NAME_STRING L"fupdate" + +#define MAIN_HDR_MAGIC 0xB105B002 + +STATIC MARVELL_SPI_FLASH_PROTOCOL *SpiFlashProtocol; +STATIC MARVELL_SPI_MASTER_PROTOCOL *SpiMasterProtocol; + +STATIC CONST CHAR16 gShellFUpdateFileName[] = L"ShellCommands"; +STATIC EFI_HANDLE gShellFUpdateHiiHandle = NULL; + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"help", TypeFlag}, + {NULL , TypeMax} + }; + +typedef struct { // Bytes + UINT32 Magic; // 0-3 + UINT32 PrologSize; // 4-7 + UINT32 PrologChecksum; // 8-11 + UINT32 BootImageSize; // 12-15 + UINT32 BootImageChecksum; // 16-19 + UINT32 Reserved0; // 20-23 + UINT32 LoadAddr; // 24-27 + UINT32 ExecAddr; // 28-31 + UINT8 UartConfig; // 32 + UINT8 Baudrate; // 33 + UINT8 ExtCount; // 34 + UINT8 AuxFlags; // 35 + UINT32 IoArg0; // 36-39 + UINT32 IoArg1; // 40-43 + UINT32 IoArg2; // 43-47 + UINT32 IoArg3; // 48-51 + UINT32 Reserved1; // 52-55 + UINT32 Reserved2; // 56-59 + UINT32 Reserved3; // 60-63 +} MV_FIRMWARE_IMAGE_HEADER; + +STATIC +EFI_STATUS +SpiFlashProbe ( + IN SPI_DEVICE *Slave + ) +{ + EFI_STATUS Status; + UINT32 IdBuffer, Id, RefId; + + Id = PcdGet32 (PcdSpiFlashId); + + IdBuffer = CMD_READ_ID & 0xff; + + // Read SPI flash ID + SpiFlashProtocol->ReadId (Slave, sizeof (UINT32), (UINT8 *)&IdBuffer); + + // Swap and extract 3 bytes of the ID + RefId = SwapBytes32 (IdBuffer) >> 8; + + if (RefId == 0) { + Print (L"%s: No SPI flash detected"); + return EFI_DEVICE_ERROR; + } else if (RefId != Id) { + Print (L"%s: Unsupported SPI flash detected with ID=%2x\n", CMD_NAME_STRING, RefId); + return EFI_DEVICE_ERROR; + } + + Print (L"%s: Detected supported SPI flash with ID=%3x\n", CMD_NAME_STRING, RefId); + + Status = SpiFlashProtocol->Init (SpiFlashProtocol, Slave); + if (EFI_ERROR(Status)) { + Print (L"%s: Cannot initialize flash device\n", CMD_NAME_STRING); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +CheckImageHeader ( + IN OUT UINTN *ImageHeader + ) +{ + MV_FIRMWARE_IMAGE_HEADER *Header; + UINT32 HeaderLength, Checksum, ChecksumBackup; + + Header = (MV_FIRMWARE_IMAGE_HEADER *)ImageHeader; + HeaderLength = Header->PrologSize; + ChecksumBackup = Header->PrologChecksum; + + // Compare magic number + if (Header->Magic != MAIN_HDR_MAGIC) { + Print (L"%s: Bad Image magic 0x%08x != 0x%08x\n", CMD_NAME_STRING, Header->Magic, MAIN_HDR_MAGIC); + return EFI_DEVICE_ERROR; + } + + // The checksum field is discarded from calculation + Header->PrologChecksum = 0; + + Checksum = CalculateSum32 ((UINT32 *)Header, HeaderLength); + if (Checksum != ChecksumBackup) { + Print (L"%s: Bad Image checksum. 0x%x != 0x%x\n", CMD_NAME_STRING, Checksum, ChecksumBackup); + return EFI_DEVICE_ERROR; + } + + // Restore checksum backup + Header->PrologChecksum = ChecksumBackup; + + return 0; +} + +STATIC +EFI_STATUS +PrepareFirmwareImage ( + IN LIST_ENTRY *CheckPackage, + IN OUT SHELL_FILE_HANDLE *FileHandle, + IN OUT UINTN **FileBuffer, + IN OUT UINTN *FileSize + ) +{ + CONST CHAR16 *FileStr; + EFI_STATUS Status; + UINT64 OpenMode; + UINTN *Buffer; + + // Parse string from commandline + FileStr = ShellCommandLineGetRawValue (CheckPackage, 1); + if (FileStr == NULL) { + Print (L"%s: No image specified\n", CMD_NAME_STRING); + return EFI_INVALID_PARAMETER; + } else { + Status = ShellIsFile (FileStr); + if (EFI_ERROR(Status)) { + Print (L"%s: File not found\n", CMD_NAME_STRING); + return EFI_INVALID_PARAMETER; + } + } + + // Obtain file size + OpenMode = EFI_FILE_MODE_READ; + + Status = ShellOpenFileByName (FileStr, FileHandle, OpenMode, 0); + if (EFI_ERROR (Status)) { + Print (L"%s: Cannot open Image file\n", CMD_NAME_STRING); + return EFI_DEVICE_ERROR; + } + + Status = FileHandleGetSize (*FileHandle, FileSize); + if (EFI_ERROR (Status)) { + Print (L"%s: Cannot get Image file size\n", CMD_NAME_STRING); + } + + // Read Image header into buffer + Buffer = AllocateZeroPool (*FileSize); + + Status = FileHandleRead (*FileHandle, FileSize, Buffer); + if (EFI_ERROR (Status)) { + Print (L"%s: Cannot read Image file header\n", CMD_NAME_STRING); + ShellCloseFile (FileHandle); + FreePool (Buffer); + return EFI_DEVICE_ERROR; + } + + *FileBuffer = Buffer; + + return EFI_SUCCESS; +} + +/** + Return the file name of the help text file if not using HII. + + @return The string pointer to the file name. +**/ +STATIC +CONST CHAR16* +EFIAPI +ShellCommandGetManFileNameFUpdate ( + VOID + ) +{ + return gShellFUpdateFileName; +} + +STATIC +VOID +FUpdateUsage ( + VOID + ) +{ + Print (L"\nFirmware update command\n" + "fupdate \n\n" + "LocalFilePath - path to local firmware image file\n" + "Example:\n" + "Update firmware from file fs2:flash-image.bin\n" + " fupdate fs2:flash-image.bin\n" + ); +} + +STATIC +SHELL_STATUS +EFIAPI +ShellCommandRunFUpdate ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + IN SHELL_FILE_HANDLE FileHandle; + SPI_DEVICE *Slave; + UINTN FileSize; + UINTN *FileBuffer = NULL; + CHAR16 *ProblemParam; + LIST_ENTRY *CheckPackage; + EFI_STATUS Status; + + // Locate SPI protocols + Status = gBS->LocateProtocol ( + &gMarvellSpiFlashProtocolGuid, + NULL, + (VOID **)&SpiFlashProtocol + ); + + if (EFI_ERROR(Status)) { + Print (L"%s: Cannot locate SpiFlash protocol\n", CMD_NAME_STRING); + return SHELL_ABORTED; + } + + Status = gBS->LocateProtocol ( + &gMarvellSpiMasterProtocolGuid, + NULL, + (VOID **)&SpiMasterProtocol + ); + + if (EFI_ERROR(Status)) { + Print (L"%s: Cannot locate SpiMaster protocol\n", CMD_NAME_STRING); + return SHELL_ABORTED; + } + + // Parse command line + Status = ShellInitialize (); + if (EFI_ERROR (Status)) { + Print (L"%s: Error while initializing Shell\n", CMD_NAME_STRING); + ASSERT_EFI_ERROR (Status); + return SHELL_ABORTED; + } + + Status = ShellCommandLineParse (ParamList, &CheckPackage, &ProblemParam, TRUE); + if (EFI_ERROR (Status)) { + Print (L"%s: Invalid parameter\n", CMD_NAME_STRING); + return SHELL_ABORTED; + } + + if (ShellCommandLineGetFlag (CheckPackage, L"help")) { + FUpdateUsage(); + return EFI_SUCCESS; + } + + // Prepare local file to be burned into flash + Status = PrepareFirmwareImage (CheckPackage, &FileHandle, &FileBuffer, &FileSize); + if (EFI_ERROR(Status)) { + return SHELL_ABORTED; + } + + // Check image checksum and magic + Status = CheckImageHeader (FileBuffer); + if (EFI_ERROR(Status)) { + goto HeaderError; + } + + // Setup and probe SPI flash + Slave = SpiMasterProtocol->SetupDevice (SpiMasterProtocol, 0, 0); + if (Slave == NULL) { + Print(L"%s: Cannot allocate SPI device!\n", CMD_NAME_STRING); + goto HeaderError; + } + + Status = SpiFlashProbe (Slave); + if (EFI_ERROR(Status)) { + Print (L"%s: Error while performing SPI flash probe\n", CMD_NAME_STRING); + goto FlashProbeError; + } + + // Update firmware image in flash at offset 0x0 + Status = SpiFlashProtocol->Update (Slave, 0, FileSize, (UINT8 *)FileBuffer); + + // Release resources + SpiMasterProtocol->FreeDevice(Slave); + FreePool (FileBuffer); + ShellCloseFile (&FileHandle); + + if (EFI_ERROR(Status)) { + Print (L"%s: Error while performing flash update\n", CMD_NAME_STRING); + return SHELL_ABORTED; + } + + Print (L"%s: Update %d bytes at offset 0x0 succeeded!\n", CMD_NAME_STRING, FileSize); + + return EFI_SUCCESS; + +FlashProbeError: + SpiMasterProtocol->FreeDevice(Slave); +HeaderError: + FreePool (FileBuffer); + ShellCloseFile (&FileHandle); + + return SHELL_ABORTED; +} + +EFI_STATUS +EFIAPI +ShellFUpdateCommandConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + gShellFUpdateHiiHandle = NULL; + + gShellFUpdateHiiHandle = HiiAddPackages ( + &gShellFUpdateHiiGuid, + gImageHandle, + UefiShellFUpdateCommandLibStrings, + NULL + ); + + if (gShellFUpdateHiiHandle == NULL) { + Print (L"%s: Cannot add Hii package\n", CMD_NAME_STRING); + return EFI_DEVICE_ERROR; + } + + Status = ShellCommandRegisterCommandName ( + CMD_NAME_STRING, + ShellCommandRunFUpdate, + ShellCommandGetManFileNameFUpdate, + 0, + CMD_NAME_STRING, + TRUE, + gShellFUpdateHiiHandle, + STRING_TOKEN (STR_GET_HELP_FUPDATE) + ); + + if (EFI_ERROR(Status)) { + Print (L"%s: Error while registering command\n", CMD_NAME_STRING); + return SHELL_ABORTED; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +ShellFUpdateCommandDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + + if (gShellFUpdateHiiHandle != NULL) { + HiiRemovePackages (gShellFUpdateHiiHandle); + } + + return EFI_SUCCESS; +} diff --git a/Platform/Marvell/Applications/FirmwareUpdate/FUpdate.inf b/Platform/Marvell/Applications/FirmwareUpdate/FUpdate.inf new file mode 100644 index 0000000000..92c3333137 --- /dev/null +++ b/Platform/Marvell/Applications/FirmwareUpdate/FUpdate.inf @@ -0,0 +1,75 @@ +# +# Marvell BSD License Option +# +# If you received this File from Marvell, you may opt to use, redistribute +# and/or modify this File under the following licensing terms. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Marvell nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = UefiShellFUpdateCommandLib + FILE_GUID = 470292b2-926b-4ed8-8080-be7a260db627 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 0.1 + LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = ShellFUpdateCommandConstructor + DESTRUCTOR = ShellFUpdateCommandDestructor + +[Sources] + FUpdate.c + FUpdate.uni + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Platform/Marvell/Marvell.dec + ShellPkg/ShellPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + FileHandleLib + HiiLib + MemoryAllocationLib + PcdLib + ShellCommandLib + ShellLib + UefiBootServicesTableLib + UefiLib + UefiLib + UefiRuntimeServicesTableLib + +[Pcd] + gMarvellTokenSpaceGuid.PcdSpiFlashId + +[Protocols] + gMarvellSpiFlashProtocolGuid + gMarvellSpiMasterProtocolGuid + +[Guids] + gShellFUpdateHiiGuid diff --git a/Platform/Marvell/Applications/FirmwareUpdate/FUpdate.uni b/Platform/Marvell/Applications/FirmwareUpdate/FUpdate.uni new file mode 100644 index 0000000000..9d52e590c6 Binary files /dev/null and b/Platform/Marvell/Applications/FirmwareUpdate/FUpdate.uni differ diff --git a/Platform/Marvell/Applications/SpiTool/SpiFlashCmd.c b/Platform/Marvell/Applications/SpiTool/SpiFlashCmd.c new file mode 100644 index 0000000000..184e3d7f54 --- /dev/null +++ b/Platform/Marvell/Applications/SpiTool/SpiFlashCmd.c @@ -0,0 +1,526 @@ +/******************************************************************************* +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +MARVELL_SPI_FLASH_PROTOCOL *SpiFlashProtocol; +MARVELL_SPI_MASTER_PROTOCOL *SpiMasterProtocol; + +CONST CHAR16 gShellSpiFlashFileName[] = L"ShellCommand"; +EFI_HANDLE gShellSfHiiHandle = NULL; + +BOOLEAN InitFlag = 1; + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"read", TypeFlag}, + {L"readfile", TypeFlag}, + {L"write", TypeFlag}, + {L"writefile", TypeFlag}, + {L"erase", TypeFlag}, + {L"update", TypeFlag}, + {L"updatefile", TypeFlag}, + {L"probe", TypeFlag}, + {L"help", TypeFlag}, + {NULL , TypeMax} + }; + +typedef enum { + PROBE = 1, + READ = 2, + READ_FILE = 4, + WRITE = 8, + WRITE_FILE = 16, + ERASE = 32, + UPDATE = 64, + UPDATE_FILE = 128, +} Flags; + +/** + Return the file name of the help text file if not using HII. + + @return The string pointer to the file name. +**/ +CONST CHAR16* +EFIAPI +ShellCommandGetManFileNameSpiFlash ( + VOID + ) +{ + + return gShellSpiFlashFileName; +} + +VOID +SfUsage ( + VOID + ) +{ + Print (L"\nBasic SPI command\n" + "sf [probe | read | readfile | write | writefile | erase |" + "update | updatefile]" + "[
| ] \n\n" + "Length - Number of bytes to send\n" + "Address - Address in RAM to store/load data\n" + "FilePath - Path to file to read/write data from/to\n" + "Offset - Offset from beggining of SPI flash to store/load data\n" + "Examples:\n" + "Check if there is response from SPI flash\n" + " sf probe\n" + "Read 32 bytes from 0xe00000 of SPI flash into RAM at address 0x100000\n" + " sf read 0x100000 0xe00000 32\n" + "Read 0x20 bytes from 0x200000 of SPI flash into RAM at address 0x300000\n" + " sf read 0x300000 0x200000 0x20\n" + "Erase 0x10000 bytes from offset 0x100000 of SPI flash\n" + " sf erase 0x100000 0x100000\n" + "Write 16 bytes from 0x200000 at RAM into SPI flash at address 0x4000000\n" + " sf write 0x200000 0x4000000 16\n" + "Update 100 bytes from 0x100000 at RAM in SPI flash at address 0xe00000\n" + " sf update 0x100000 0xe00000 100\n" + "Read 0x3000 bytes from 0x0 of SPI flash into file fs2:file.bin\n" + " sf readfile fs2:file.bin 0x0 0x3000 \n" + "Update data in SPI flash at 0x3000000 from file Linux.efi\n" + " sf updatefile Linux.efi 0x3000000\n" + ); +} + +STATIC +EFI_STATUS +OpenAndPrepareFile ( + IN CHAR16 *FilePath, + SHELL_FILE_HANDLE *FileHandle + ) +{ + EFI_STATUS Status; + UINT64 OpenMode; + + OpenMode = EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE; + + Status = ShellOpenFileByName (FilePath, FileHandle, OpenMode, 0); + if (EFI_ERROR (Status)) { + Print (L"sf: Cannot open file\n"); + return Status; + } + + Status = FileHandleSetPosition(*FileHandle, 0); + + if (EFI_ERROR(Status)) { + Print (L"sf: Cannot set file position to first byte\n"); + ShellCloseFile (FileHandle); + return Status; + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +FlashProbe ( + IN SPI_DEVICE *Slave + ) +{ + EFI_STATUS Status; + UINT8 IdBuffer[4]; + UINT32 Id, RefId; + + Id = PcdGet32 (PcdSpiFlashId); + + IdBuffer[0] = CMD_READ_ID; + + SpiFlashProtocol->ReadId ( + Slave, + 4, + IdBuffer + ); + + RefId = (IdBuffer[0] << 16) + (IdBuffer[1] << 8) + IdBuffer[2]; + + if (RefId == Id) { + Print (L"sf: Detected supported SPI flash with ID=%3x\n", RefId); + Status = SpiFlashProtocol->Init (SpiFlashProtocol, Slave); + if (EFI_ERROR(Status)) { + Print (L"sf: Cannot initialize flash device\n"); + return SHELL_ABORTED; + } + InitFlag = 0; + return EFI_SUCCESS; + } else if (RefId != 0) { + Print (L"sf: Unsupported SPI flash detected with ID=%2x\n", RefId); + return SHELL_ABORTED; + } + + Print (L"sf: No SPI flash detected"); + return SHELL_ABORTED; +} + +SHELL_STATUS +EFIAPI +ShellCommandRunSpiFlash ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ +EFI_STATUS Status; + SPI_DEVICE *Slave; + LIST_ENTRY *CheckPackage; + EFI_PHYSICAL_ADDRESS Address = 0, Offset = 0; + SHELL_FILE_HANDLE FileHandle = NULL; + UINTN ByteCount, FileSize, I; + UINT8 *Buffer = NULL, *FileBuffer = NULL; + CHAR16 *ProblemParam, *FilePath; + CONST CHAR16 *AddressStr = NULL, *OffsetStr = NULL; + CONST CHAR16 *LengthStr = NULL, *FileStr = NULL; + BOOLEAN AddrFlag = FALSE, LengthFlag = TRUE, FileFlag = FALSE; + UINT8 Flag = 0, CheckFlag = 0; + + Status = gBS->LocateProtocol ( + &gMarvellSpiFlashProtocolGuid, + NULL, + (VOID **)&SpiFlashProtocol + ); + if (EFI_ERROR(Status)) { + Print (L"sf: Cannot locate SpiFlash protocol\n"); + return SHELL_ABORTED; + } + + Status = gBS->LocateProtocol ( + &gMarvellSpiMasterProtocolGuid, + NULL, + (VOID **)&SpiMasterProtocol + ); + if (EFI_ERROR(Status)) { + Print (L"sf: Cannot locate SpiMaster protocol\n"); + return SHELL_ABORTED; + } + + // Parse Shell command line + Status = ShellInitialize (); + if (EFI_ERROR (Status)) { + Print (L"sf: Cannot initialize Shell\n"); + ASSERT_EFI_ERROR (Status); + return SHELL_ABORTED; + } + + Status = ShellCommandLineParse (ParamList, &CheckPackage, &ProblemParam, TRUE); + if (EFI_ERROR (Status)) { + Print (L"sf: Error while parsing command line\n"); + return SHELL_ABORTED; + } + + if (ShellCommandLineGetFlag (CheckPackage, L"help")) { + SfUsage(); + return EFI_SUCCESS; + } + + // Check flags provided by user + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"probe") << 0); + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"read") << 1); + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"readfile") << 2); + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"write") << 3); + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"writefile") << 4); + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"erase") << 5); + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"update") << 6); + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"updatefile") << 7); + + if (InitFlag && !(Flag & PROBE)) { + Print (L"Please run sf probe\n"); + return EFI_SUCCESS; + } + + CheckFlag = Flag; + for (I = 0; CheckFlag; CheckFlag >>= 1) { + I += CheckFlag & 1; + if (I > 1) { + Print (L"sf: Too many flags\n"); + SfUsage(); + return SHELL_ABORTED; + } + } + + // Setup new spi device + Slave = SpiMasterProtocol->SetupDevice (SpiMasterProtocol, 0, 0); + if (Slave == NULL) { + Print(L"sf: Cannot allocate SPI device!\n"); + return SHELL_ABORTED; + } + + switch (Flag) { + case PROBE: + // Probe spi bus + Status = FlashProbe (Slave); + if (EFI_ERROR(Status)) { + // No supported spi flash detected + return SHELL_ABORTED; + } else { + return Status; + } + break; + // Fall through + case READ: + case WRITE: + case UPDATE: + AddressStr = ShellCommandLineGetRawValue (CheckPackage, 1); + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 2); + LengthStr = ShellCommandLineGetRawValue (CheckPackage, 3); + AddrFlag = TRUE; + break; + case ERASE: + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 1); + LengthStr = ShellCommandLineGetRawValue (CheckPackage, 2); + break; + case READ_FILE: + FileStr = ShellCommandLineGetRawValue (CheckPackage, 1); + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 2); + LengthStr = ShellCommandLineGetRawValue (CheckPackage, 3); + FileFlag = TRUE; + break; + case WRITE_FILE: + case UPDATE_FILE: + FileStr = ShellCommandLineGetRawValue (CheckPackage, 1); + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 2); + LengthFlag = FALSE; + FileFlag = TRUE; + break; + } + + // Read address parameter + if ((AddressStr == NULL) & AddrFlag) { + Print (L"sf: No address parameter!\n"); + return SHELL_ABORTED; + } else if (AddrFlag) { + Address = ShellHexStrToUintn (AddressStr); + if (Address == (UINTN)(-1)) { + Print (L"sf: Wrong address parameter\n"); + return SHELL_ABORTED; + } + } + + // Read offset parameter + if (OffsetStr == NULL) { + Print (L"sf: No offset Parameter!\n"); + return SHELL_ABORTED; + } else { + Offset = ShellHexStrToUintn (OffsetStr); + if (Offset < 0) { + Print (L"sf: Wrong offset parameter: %s", OffsetStr); + return SHELL_ABORTED; + } + } + + // Read length parameter + if ((LengthStr == NULL) & LengthFlag) { + Print (L"sf: No lenght parameter!\n"); + return SHELL_ABORTED; + } else if (LengthFlag) { + ByteCount = ShellStrToUintn (LengthStr); + if (ByteCount < 0) { + Print (L"sf: Wrong length parameter %s!\n", LengthStr); + return SHELL_ABORTED; + } + } + + if (FileFlag) { + // Read FilePath parameter + if (FileStr == NULL) { + Print (L"sf: No FilePath parameter!\n"); + return SHELL_ABORTED; + } else { + FilePath = (CHAR16 *) FileStr; + Status = ShellIsFile (FilePath); + // When read file into flash, file doesn't have to exist + if (EFI_ERROR(Status && !(Flag & READ_FILE))) { + Print (L"sf: Wrong FilePath parameter!\n"); + return SHELL_ABORTED; + } + } + + Status = OpenAndPrepareFile (FilePath, &FileHandle); + if (EFI_ERROR(Status)) { + Print (L"sf: Error while preparing file\n"); + return SHELL_ABORTED; + } + + // Get file size in order to check correctness at the end of transfer + if (Flag & (WRITE_FILE | UPDATE_FILE)) { + Status = FileHandleGetSize (FileHandle, &FileSize); + if (EFI_ERROR (Status)) { + Print (L"sf: Cannot get file size\n"); + } + ByteCount = (UINTN) FileSize; + } + + FileBuffer = AllocateZeroPool ((UINTN) ByteCount); + if (FileBuffer == NULL) { + Print (L"sf: Cannot allocate memory\n"); + goto Error_Close_File; + } + + // Read file content and store it in FileBuffer + if (Flag & (WRITE_FILE | UPDATE_FILE)) { + Status = FileHandleRead (FileHandle, &ByteCount, FileBuffer); + if (EFI_ERROR (Status)) { + Print (L"sf: Read from file error\n"); + goto Error_Free_Buffer; + } else if (ByteCount != (UINTN) FileSize) { + Print (L"sf: Not whole file read. Abort\n"); + goto Error_Free_Buffer; + } + } + } + + Buffer = (UINT8 *) Address; + if (FileFlag) { + Buffer = FileBuffer; + } + + switch (Flag) { + case READ: + case READ_FILE: + Status = SpiFlashProtocol->Read (Slave, Offset, ByteCount, Buffer); + break; + case ERASE: + Status = SpiFlashProtocol->Erase (Slave, Offset, ByteCount); + break; + case WRITE: + case WRITE_FILE: + Status = SpiFlashProtocol->Write (Slave, Offset, ByteCount, Buffer); + break; + case UPDATE: + case UPDATE_FILE: + Status = SpiFlashProtocol->Update (Slave, Offset, ByteCount, Buffer); + break; + } + + SpiMasterProtocol->FreeDevice(Slave); + + if (EFI_ERROR (Status)) { + Print (L"sf: Error while performing spi transfer\n"); + return SHELL_ABORTED; + } + + switch (Flag) { + case ERASE: + Print (L"sf: %d bytes succesfully erased at offset 0x%x\n", ByteCount, + Offset); + break; + case WRITE: + case WRITE_FILE: + Print (L"sf: Write %d bytes at offset 0x%x\n", ByteCount, Offset); + break; + case UPDATE: + case UPDATE_FILE: + Print (L"sf: Update %d bytes at offset 0x%x\n", ByteCount, Offset); + break; + case READ: + Print (L"sf: Read %d bytes from offset 0x%x\n", ByteCount, Offset); + break; + case READ_FILE: + Status = FileHandleWrite (FileHandle, &ByteCount, FileBuffer); + if (EFI_ERROR(Status)) { + Print (L"sf: Error while writing into file\n"); + goto Error_Free_Buffer; + } + break; + } + + if (FileFlag) { + FreePool (FileBuffer); + + if (FileHandle != NULL) { + ShellCloseFile (&FileHandle); + } + } + + return EFI_SUCCESS; + +Error_Free_Buffer: + FreePool (FileBuffer); +Error_Close_File: + ShellCloseFile (&FileHandle); + return SHELL_ABORTED; +} + +EFI_STATUS +EFIAPI +ShellSpiFlashLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + gShellSfHiiHandle = NULL; + + gShellSfHiiHandle = HiiAddPackages ( + &gShellSfHiiGuid, gImageHandle, + UefiShellSpiFlashLibStrings, NULL + ); + if (gShellSfHiiHandle == NULL) { + return EFI_DEVICE_ERROR; + } + + ShellCommandRegisterCommandName ( + L"sf", ShellCommandRunSpiFlash, ShellCommandGetManFileNameSpiFlash, 0, + L"sf", TRUE , gShellSfHiiHandle, STRING_TOKEN (STR_GET_HELP_SF) + ); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +ShellSpiFlashLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + + if (gShellSfHiiHandle != NULL) { + HiiRemovePackages (gShellSfHiiHandle); + } + return EFI_SUCCESS; +} diff --git a/Platform/Marvell/Applications/SpiTool/SpiFlashCmd.inf b/Platform/Marvell/Applications/SpiTool/SpiFlashCmd.inf new file mode 100644 index 0000000000..41b7b7cd85 --- /dev/null +++ b/Platform/Marvell/Applications/SpiTool/SpiFlashCmd.inf @@ -0,0 +1,75 @@ +# +# Marvell BSD License Option +# +# If you received this File from Marvell, you may opt to use, redistribute +# and/or modify this File under the following licensing terms. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Marvell nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = UefiShellSpiFlashLib + FILE_GUID = 2f2dd8c9-221f-4acf-afe5-5897264c5774 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 0.1 + LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = ShellSpiFlashLibConstructor + DESTRUCTOR = ShellSpiFlashLibDestructor + +[Sources] + SpiFlashCmd.c + SpiFlashCmd.uni + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + Platform/Marvell/Marvell.dec + +[LibraryClasses] + UefiLib + UefiBootServicesTableLib + MemoryAllocationLib + BaseLib + BaseMemoryLib + DebugLib + ShellCommandLib + ShellLib + UefiLib + UefiRuntimeServicesTableLib + PcdLib + HiiLib + FileHandleLib + +[Pcd] + gMarvellTokenSpaceGuid.PcdSpiFlashId + +[Protocols] + gMarvellSpiFlashProtocolGuid + gMarvellSpiMasterProtocolGuid + +[Guids] + gShellSfHiiGuid diff --git a/Platform/Marvell/Applications/SpiTool/SpiFlashCmd.uni b/Platform/Marvell/Applications/SpiTool/SpiFlashCmd.uni new file mode 100644 index 0000000000..3f25663ed7 Binary files /dev/null and b/Platform/Marvell/Applications/SpiTool/SpiFlashCmd.uni differ diff --git a/Platform/Marvell/Armada/Armada.dsc.inc b/Platform/Marvell/Armada/Armada.dsc.inc new file mode 100644 index 0000000000..4e8f289fcb --- /dev/null +++ b/Platform/Marvell/Armada/Armada.dsc.inc @@ -0,0 +1,482 @@ +#Copyright (C) 2016 Marvell International Ltd. +# +#Marvell BSD License Option +# +#If you received this File from Marvell, you may opt to use, redistribute and/or +#modify this File under the following licensing terms. +#Redistribution and use in source and binary forms, with or without modification, +#are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Marvell nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +#ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +#WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +#DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +#ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +#(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +#ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +#(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +#SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +[LibraryClasses.common] + ArmPlatformLib|Platform/Marvell/Armada/Library/Armada70x0Lib/Armada70x0Lib.inf + ComPhyLib|Platform/Marvell/Library/ComPhyLib/ComPhyLib.inf + MppLib|Platform/Marvell/Library/MppLib/MppLib.inf + ParsePcdLib|Platform/Marvell/Library/ParsePcdLib/ParsePcdLib.inf + UtmiPhyLib|Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.inf + + DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf + UncachedMemoryAllocationLib|ArmPkg/Library/UncachedMemoryAllocationLib/UncachedMemoryAllocationLib.inf + DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf + +# Basic utility libraries + BaseLib|MdePkg/Library/BaseLib/BaseLib.inf + SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf + PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf + PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf + PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf + UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.inf + CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf + PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf + PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf + +# Basic UEFI services libraries + UefiLib|MdePkg/Library/UefiLib/UefiLib.inf + HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf + UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf + DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf + UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf + DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf + DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf + ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf + UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf + UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf + HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf + UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf + UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf + UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf + + # Assume everything is fixed at build. do not use runtime PCD feature + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf + + BaseMemoryLib|MdePkg/Library/BaseMemoryLibOptDxe/BaseMemoryLibOptDxe.inf + + # ARM Architectural Libraries + CacheMaintenanceLib|ArmPkg/Library/ArmCacheMaintenanceLib/ArmCacheMaintenanceLib.inf + DefaultExceptionHandlerLib|ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLib.inf + CpuExceptionHandlerLib|ArmPkg/Library/ArmExceptionLib/ArmExceptionLib.inf + ArmDisassemblerLib|ArmPkg/Library/ArmDisassemblerLib/ArmDisassemblerLib.inf + DmaLib|ArmPkg/Library/ArmDmaLib/ArmDmaLib.inf + ArmGicLib|ArmPkg/Drivers/ArmGic/ArmGicLib.inf + ArmGicArchLib|ArmPkg/Library/ArmGicArchLib/ArmGicArchLib.inf + ArmPlatformStackLib|ArmPlatformPkg/Library/ArmPlatformStackLib/ArmPlatformStackLib.inf + ArmSmcLib|ArmPkg/Library/ArmSmcLib/ArmSmcLib.inf + TimerLib|ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.inf + UefiScsiLib|MdePkg/Library/UefiScsiLib/UefiScsiLib.inf + + # Serial port libraries + SerialPortLib|MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf + PlatformHookLib|MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf + + # Reset and Time libraries + TimeBaseLib|EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.inf + RealTimeClockLib|Platform/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.inf + ResetSystemLib|ArmPkg/Library/ArmSmcPsciResetSystemLib/ArmSmcPsciResetSystemLib.inf + + # Network support + NetLib|MdeModulePkg/Library/DxeNetLib/DxeNetLib.inf + IpIoLib|MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.inf + DpcLib|MdeModulePkg/Library/DxeDpcLib/DxeDpcLib.inf + UdpIoLib|MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf + + # These libraries are used by the dynamic EFI Shell commands + ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf + FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf + SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf + + # EBL Related Libraries + EblCmdLib|ArmPlatformPkg/Library/EblCmdLib/EblCmdLib.inf + EfiFileLib|EmbeddedPkg/Library/EfiFileLib/EfiFileLib.inf + EblAddExternalCommandLib|EmbeddedPkg/Library/EblAddExternalCommandLib/EblAddExternalCommandLib.inf + EblNetworkLib|EmbeddedPkg/Library/EblNetworkLib/EblNetworkLib.inf + + # + # Uncomment (and comment out the next line) For RealView Debugger. The Standard IO window + # in the debugger will show load and unload commands for symbols. You can cut and paste this + # into the command window to load symbols. We should be able to use a script to do this, but + # the version of RVD I have does not support scripts accessing system memory. + # + #PeCoffExtraActionLib|ArmPkg/Library/RvdPeCoffExtraActionLib/RvdPeCoffExtraActionLib.inf + PeCoffExtraActionLib|ArmPkg/Library/DebugPeCoffExtraActionLib/DebugPeCoffExtraActionLib.inf + #PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf + + DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf + DebugAgentTimerLib|EmbeddedPkg/Library/DebugAgentTimerLibNull/DebugAgentTimerLibNull.inf + # SemihostLib|ArmPkg/Library/SemihostLib/SemihostLib.inf + + # BDS Libraries + CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf + GenericBdsLib|IntelFrameworkModulePkg/Library/GenericBdsLib/GenericBdsLib.inf + PlatformBdsLib|ArmPlatformPkg/Library/PlatformIntelBdsLib/PlatformIntelBdsLib.inf + CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf + FdtLib|EmbeddedPkg/Library/FdtLib/FdtLib.inf + +[LibraryClasses.AARCH64] + ArmLib|ArmPkg/Library/ArmLib/ArmBaseLib.inf + ArmMmuLib|ArmPkg/Library/ArmMmuLib/ArmMmuBaseLib.inf + ArmGenericTimerCounterLib|ArmPkg/Library/ArmGenericTimerPhyCounterLib/ArmGenericTimerPhyCounterLib.inf + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf + +[LibraryClasses.common.SEC] + DebugAgentLib|ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentSymbolsBaseLib.inf + DefaultExceptionHandlerLib|ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLibBase.inf + + PrePiLib|EmbeddedPkg/Library/PrePiLib/PrePiLib.inf + ExtractGuidedSectionLib|EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf + LzmaDecompressLib|MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf + MemoryAllocationLib|EmbeddedPkg/Library/PrePiMemoryAllocationLib/PrePiMemoryAllocationLib.inf + HobLib|EmbeddedPkg/Library/PrePiHobLib/PrePiHobLib.inf + PrePiHobListPointerLib|ArmPlatformPkg/Library/PrePiHobListPointerLib/PrePiHobListPointerLib.inf + PlatformPeiLib|ArmPlatformPkg/PlatformPei/PlatformPeiLib.inf + ArmGicArchLib|ArmPkg/Library/ArmGicArchSecLib/ArmGicArchSecLib.inf + +[LibraryClasses.common.SEC, LibraryClasses.common.PEIM] + MemoryInitPeiLib|ArmPlatformPkg/MemoryInitPei/MemoryInitPeiLib.inf + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf + +[LibraryClasses.common.DXE_CORE] + HobLib|MdePkg/Library/DxeCoreHobLib/DxeCoreHobLib.inf + MemoryAllocationLib|MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.inf + DxeCoreEntryPoint|MdePkg/Library/DxeCoreEntryPoint/DxeCoreEntryPoint.inf + ExtractGuidedSectionLib|MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGuidedSectionLib.inf + UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.inf + DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf + PerformanceLib|MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf + +[LibraryClasses.common.DXE_DRIVER] + DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf + SecurityManagementLib|MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf + PerformanceLib|MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + NonDiscoverableDeviceRegistrationLib|MdeModulePkg/Library/NonDiscoverableDeviceRegistrationLib/NonDiscoverableDeviceRegistrationLib.inf + +[LibraryClasses.common.UEFI_APPLICATION] + UefiDecompressLib|IntelFrameworkModulePkg/Library/BaseUefiTianoCustomDecompressLib/BaseUefiTianoCustomDecompressLib.inf + PerformanceLib|MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf + +[LibraryClasses.common.UEFI_DRIVER] + UefiDecompressLib|IntelFrameworkModulePkg/Library/BaseUefiTianoCustomDecompressLib/BaseUefiTianoCustomDecompressLib.inf + ExtractGuidedSectionLib|MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGuidedSectionLib.inf + PerformanceLib|MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + +[LibraryClasses.common.DXE_RUNTIME_DRIVER] + HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf + +[LibraryClasses.ARM, LibraryClasses.AARCH64] + # + # It is not possible to prevent the ARM compiler for generic intrinsic functions. + # This library provides the instrinsic functions generate by a given compiler. + # [LibraryClasses.ARM] and NULL mean link this library into all ARM images. + # + NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf + + # Add support for GCC stack protector + NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf + +################################################################################ +# +# Pcd Section - list of all EDK II PCD Entries defined by this Platform +# +################################################################################ + +[PcdsFeatureFlag.common] + gEfiMdePkgTokenSpaceGuid.PcdComponentNameDisable|TRUE + gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnosticsDisable|TRUE + gEfiMdePkgTokenSpaceGuid.PcdComponentName2Disable|TRUE + gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnostics2Disable|TRUE + + # + # Control what commands are supported from the UI + # Turn these on and off to add features or save size + # + gEmbeddedTokenSpaceGuid.PcdEmbeddedMacBoot|TRUE + gEmbeddedTokenSpaceGuid.PcdEmbeddedDirCmd|TRUE + gEmbeddedTokenSpaceGuid.PcdEmbeddedHobCmd|TRUE + gEmbeddedTokenSpaceGuid.PcdEmbeddedHwDebugCmd|TRUE + gEmbeddedTokenSpaceGuid.PcdEmbeddedPciDebugCmd|TRUE + gEmbeddedTokenSpaceGuid.PcdEmbeddedIoEnable|FALSE + gEmbeddedTokenSpaceGuid.PcdEmbeddedScriptCmd|FALSE + + gEmbeddedTokenSpaceGuid.PcdCacheEnable|TRUE + + # Use the Vector Table location in CpuDxe. + # We will not copy the Vector Table at PcdCpuVectorBaseAddress + gArmTokenSpaceGuid.PcdRelocateVectorTable|FALSE + + gEmbeddedTokenSpaceGuid.PcdPrePiProduceMemoryTypeInformationHob|TRUE + + # If TRUE, Graphics Output Protocol will be installed on virtual + # handle created by ConsplitterDxe. It could be set FALSE to save size. + gEfiMdeModulePkgTokenSpaceGuid.PcdConOutGopSupport|TRUE + gEfiMdeModulePkgTokenSpaceGuid.PcdConOutUgaSupport|FALSE + + # USB support + gEfiMdeModulePkgTokenSpaceGuid.PcdTurnOffUsbLegacySupport|TRUE + +[PcdsFixedAtBuild.common] + gArmPlatformTokenSpaceGuid.PcdFirmwareVendor|"Marvell" + gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString|L"MARVELL_EFI" + gArmPlatformTokenSpaceGuid.PcdCoreCount|4 + + ## Use the serial console (ConIn & ConOut) and the Graphic driver (ConOut) + gArmPlatformTokenSpaceGuid.PcdDefaultConOutPaths|L"VenHw(D3987D4B-971A-435F-8CAF-4967EB627241)/Uart(115200,8,N,1)/VenPcAnsi()" + gArmPlatformTokenSpaceGuid.PcdDefaultConInPaths|L"VenHw(D3987D4B-971A-435F-8CAF-4967EB627241)/Uart(115200,8,N,1)/VenPcAnsi()" + + gEmbeddedTokenSpaceGuid.PcdEmbeddedPrompt|"Marvell>> " + gEfiMdePkgTokenSpaceGuid.PcdMaximumUnicodeStringLength|1000000 + gEfiMdePkgTokenSpaceGuid.PcdMaximumAsciiStringLength|1000000 + gEfiMdePkgTokenSpaceGuid.PcdMaximumLinkedListLength|1000000 + gEfiMdePkgTokenSpaceGuid.PcdSpinLockTimeout|10000000 + gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue|0xAF + gEfiMdePkgTokenSpaceGuid.PcdPerformanceLibraryPropertyMask|1 + gEfiMdePkgTokenSpaceGuid.PcdPostCodePropertyMask|0 + gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|320 + gEfiMdePkgTokenSpaceGuid.PcdDefaultTerminalType|1 + gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut|3 + + # Required for Intel BDS + gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE + gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdShellFile|{ 0x83, 0xA5, 0x04, 0x7C, 0x3E, 0x9E, 0x1C, 0x4F, 0xAD, 0x65, 0xE0, 0x52, 0x68, 0xD0, 0xB4, 0xD1 } + + # ARM Generic Interrupt Controller + gArmTokenSpaceGuid.PcdGicDistributorBase|0xF0210000 + gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase|0xF0220000 + + # ARM Architectural Timer Support + gArmTokenSpaceGuid.PcdArmArchTimerFreqInHz|25000000 + gEmbeddedTokenSpaceGuid.PcdMetronomeTickPeriod|1000 + + # ARM SBSA Watchdog + gArmTokenSpaceGuid.PcdGenericWatchdogControlBase|0xF0620000 + gArmTokenSpaceGuid.PcdGenericWatchdogRefreshBase|0xF0600000 + gArmTokenSpaceGuid.PcdGenericWatchdogEl2IntrNum|34 + + # Serial + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseMmio|TRUE + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHardwareFlowControl|FALSE + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase|0xF0512000 + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialBaudRate|115200 + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate|200000000 + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterStride|4 + + # DEBUG_ASSERT_ENABLED 0x01 + # DEBUG_PRINT_ENABLED 0x02 + # DEBUG_CODE_ENABLED 0x04 + # CLEAR_MEMORY_ENABLED 0x08 + # ASSERT_BREAKPOINT_ENABLED 0x10 + # ASSERT_DEADLOOP_ENABLED 0x20 + + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x2f + + # DEBUG_INIT 0x00000001 // Initialization + # DEBUG_WARN 0x00000002 // Warnings + # DEBUG_LOAD 0x00000004 // Load events + # DEBUG_FS 0x00000008 // EFI File system + # DEBUG_POOL 0x00000010 // Alloc & Free (pool) + # DEBUG_PAGE 0x00000020 // Alloc & Free (page) + # DEBUG_INFO 0x00000040 // Informational debug messages + # DEBUG_DISPATCH 0x00000080 // PEI/DXE/SMM Dispatchers + # DEBUG_VARIABLE 0x00000100 // Variable + # DEBUG_BM 0x00000400 // Boot Manager + # DEBUG_BLKIO 0x00001000 // BlkIo Driver + # DEBUG_NET 0x00004000 // SNP Driver + # DEBUG_UNDI 0x00010000 // UNDI Driver + # DEBUG_LOADFILE 0x00020000 // LoadFile + # DEBUG_EVENT 0x00080000 // Event messages + # DEBUG_GCD 0x00100000 // Global Coherency Database changes + # DEBUG_CACHE 0x00200000 // Memory range cachability changes + # DEBUG_VERBOSE 0x00400000 // Detailed debug messages that may + # // significantly impact boot performance + # DEBUG_ERROR 0x80000000 // Error + +!if $(TARGET) == RELEASE + gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x80000000 +!else + gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x8000000F +!endif + + gEmbeddedTokenSpaceGuid.PcdEmbeddedAutomaticBootCommand|"" + gEmbeddedTokenSpaceGuid.PcdEmbeddedDefaultTextColor|0x07 + gEmbeddedTokenSpaceGuid.PcdEmbeddedMemVariableStoreSize|0x10000 + + # + # Optional feature to help prevent EFI memory map fragments + # Turned on and off via: PcdPrePiProduceMemoryTypeInformationHob + # Values are in EFI Pages (4K). DXE Core will make sure that + # at least this much of each type of memory can be allocated + # from a single memory range. This way you only end up with + # maximum of two fragements for each type in the memory map + # (the memory used, and the free memory that was prereserved + # but not used). + # + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIReclaimMemory|0 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIMemoryNVS|0 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiReservedMemoryType|0 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesData|50 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesCode|20 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesCode|400 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesData|20000 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderCode|20 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderData|0 + + # We want to use the Shell Libraries but don't want it to initialise + # automatically. We initialise the libraries when the command is called by the + # Shell. + gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE + + # ARM Pcds + gArmTokenSpaceGuid.PcdSystemMemoryBase|0 + gArmTokenSpaceGuid.PcdSystemMemorySize|0x40000000 + gArmTokenSpaceGuid.PcdArmScr|0x531 + +################################################################################ +# +# Components Section - list of all EDK II Modules needed by this Platform +# +################################################################################ +[Components.common] + + # PEI Phase modules + ArmPlatformPkg/PrePi/PeiMPCore.inf + + # DXE + MdeModulePkg/Core/Dxe/DxeMain.inf { + + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf + NULL|MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.inf + } + + # Architectural Protocols DXE + ArmPkg/Drivers/CpuDxe/CpuDxe.inf + ArmPkg/Drivers/ArmGic/ArmGicDxe.inf + ArmPkg/Drivers/TimerDxe/TimerDxe.inf + ArmPkg/Drivers/GenericWatchdogDxe/GenericWatchdogDxe.inf + + # Platform drivers + Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf + MdeModulePkg/Bus/I2c/I2cDxe/I2cDxe.inf + Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.inf + Platform/Marvell/Drivers/Spi/MvSpiDxe.inf + Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.inf + + # Network support + MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.inf + MdeModulePkg/Universal/Network/DpcDxe/DpcDxe.inf + MdeModulePkg/Universal/Network/MnpDxe/MnpDxe.inf + MdeModulePkg/Universal/Network/VlanConfigDxe/VlanConfigDxe.inf + MdeModulePkg/Universal/Network/ArpDxe/ArpDxe.inf + MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Dxe.inf + MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Dxe.inf + MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Dxe.inf + MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf + MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dxe.inf + Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.inf + Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.inf + Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.inf + + MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf + MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf + MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf + MdeModulePkg/Universal/Variable/EmuRuntimeDxe/EmuVariableRuntimeDxe.inf + + EmbeddedPkg/EmbeddedMonotonicCounter/EmbeddedMonotonicCounter.inf + MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf + EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClockRuntimeDxe.inf + EmbeddedPkg/MetronomeDxe/MetronomeDxe.inf + + # PciEmulation + Platform/Marvell/PciEmulation/PciEmulation.inf + MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.inf + + # SCSI + MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf + MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf + + # SATA + MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf + MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf + OvmfPkg/SataControllerDxe/SataControllerDxe.inf + + # USB + MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf + MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf + MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf + + # SD/MMC + MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf + MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf + Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.inf + + # Console packages + MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf + MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf + MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf + MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf + MdeModulePkg/Universal/SerialDxe/SerialDxe.inf + + # Human interface: + MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf + + # FAT filesystem + GPT/MBR partitioning + MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf + MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf + MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf + + # Bds - Use Intel BDS + MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf + MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf + MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf + IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.inf + + # UEFI application (Shell Embedded Boot Loader) + ShellPkg/Application/Shell/Shell.inf { + + ShellCommandLib|ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf + NULL|ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf + NULL|ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.inf + NULL|ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf + NULL|ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.inf + NULL|ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf + NULL|ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLib.inf + NULL|ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.inf + NULL|ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.inf + NULL|Platform/Marvell/Applications/EepromCmd/EepromCmd.inf + NULL|Platform/Marvell/Applications/SpiTool/SpiFlashCmd.inf + NULL|Platform/Marvell/Applications/FirmwareUpdate/FUpdate.inf + HandleParsingLib|ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf + BcfgCommandLib|ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.inf + + + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xFF + gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE + gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|8000 + } diff --git a/Platform/Marvell/Armada/Armada70x0.dsc b/Platform/Marvell/Armada/Armada70x0.dsc new file mode 100644 index 0000000000..3440038ff2 --- /dev/null +++ b/Platform/Marvell/Armada/Armada70x0.dsc @@ -0,0 +1,145 @@ +#Copyright (C) 2016 Marvell International Ltd. +# +#Marvell BSD License Option +# +#If you received this File from Marvell, you may opt to use, redistribute and/or +#modify this File under the following licensing terms. +#Redistribution and use in source and binary forms, with or without modification, +#are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Marvell nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +#ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +#WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +#DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +#ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +#(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +#ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +#(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +#SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + PLATFORM_NAME = Armada70x0 + PLATFORM_GUID = f837e231-cfc7-4f56-9a0f-5b218d746ae3 + PLATFORM_VERSION = 0.1 + DSC_SPECIFICATION = 0x00010005 + OUTPUT_DIRECTORY = Build/$(PLATFORM_NAME) + SUPPORTED_ARCHITECTURES = AARCH64 + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + FLASH_DEFINITION = Platform/Marvell/Armada/Armada70x0.fdf + +!include Armada.dsc.inc + +################################################################################ +# +# Pcd Section - list of all EDK II PCD Entries defined by this Platform +# +################################################################################ +[PcdsFixedAtBuild.common] + #MPP + gMarvellTokenSpaceGuid.PcdMppChipCount|2 + + # APN806-A0 MPP SET + gMarvellTokenSpaceGuid.PcdChip0MppReverseFlag|FALSE + gMarvellTokenSpaceGuid.PcdChip0MppBaseAddress|0xF06F4000 + gMarvellTokenSpaceGuid.PcdChip0MppPinCount|20 + gMarvellTokenSpaceGuid.PcdChip0MppSel0|{ 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 } + gMarvellTokenSpaceGuid.PcdChip0MppSel1|{ 0x1, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3 } + + # CP110 MPP SET - Router configuration + gMarvellTokenSpaceGuid.PcdChip1MppReverseFlag|FALSE + gMarvellTokenSpaceGuid.PcdChip1MppBaseAddress|0xF2440000 + gMarvellTokenSpaceGuid.PcdChip1MppPinCount|64 + gMarvellTokenSpaceGuid.PcdChip1MppSel0|{ 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4 } + gMarvellTokenSpaceGuid.PcdChip1MppSel1|{ 0x4, 0x4, 0x0, 0x3, 0x3, 0x3, 0x3, 0x0, 0x0, 0x0 } + gMarvellTokenSpaceGuid.PcdChip1MppSel2|{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9, 0xA } + gMarvellTokenSpaceGuid.PcdChip1MppSel3|{ 0xA, 0x0, 0x7, 0x0, 0x7, 0x7, 0x7, 0x2, 0x2, 0x0 } + gMarvellTokenSpaceGuid.PcdChip1MppSel4|{ 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 } + gMarvellTokenSpaceGuid.PcdChip1MppSel5|{ 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0xE, 0xE, 0xE, 0xE } + gMarvellTokenSpaceGuid.PcdChip1MppSel6|{ 0xE, 0xE, 0xE, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } + + # I2C + gMarvellTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x50, 0x57, 0x60 } + gMarvellTokenSpaceGuid.PcdI2cSlaveBuses|{ 0x0, 0x0, 0x0 } + gMarvellTokenSpaceGuid.PcdI2cBaseAddresses|L"0xF2701000;0xF2701100" + gMarvellTokenSpaceGuid.PcdEepromI2cAddresses|{ 0x50, 0x57 } + gMarvellTokenSpaceGuid.PcdEepromI2cBuses|{ 0x0, 0x0 } + gMarvellTokenSpaceGuid.PcdI2cClockFrequency|250000000 + gMarvellTokenSpaceGuid.PcdI2cBaudRate|100000 + gMarvellTokenSpaceGuid.PcdI2cBusCount|2 + + #SPI + gMarvellTokenSpaceGuid.PcdSpiRegBase|0xF2700680 + gMarvellTokenSpaceGuid.PcdSpiMaxFrequency|10000000 + gMarvellTokenSpaceGuid.PcdSpiClockFrequency|200000000 + + gMarvellTokenSpaceGuid.PcdSpiFlashPollCmd|0x70 + gMarvellTokenSpaceGuid.PcdSpiFlashAddressCycles|3 + gMarvellTokenSpaceGuid.PcdSpiFlashEraseSize|65536 + gMarvellTokenSpaceGuid.PcdSpiFlashPageSize|256 + gMarvellTokenSpaceGuid.PcdSpiFlashId|0x20BA18 + + #ComPhy + gMarvellTokenSpaceGuid.PcdComPhyDevices|{ 0x1 } + gMarvellTokenSpaceGuid.PcdChip0ComPhyTypes|L"SGMII1;USB3_HOST0;SGMII0;SATA1;USB3_HOST1;PCIE2" + gMarvellTokenSpaceGuid.PcdChip0ComPhySpeeds|L"3125;5000;1250;5000;5000;5000" + + #UtmiPhy + gMarvellTokenSpaceGuid.PcdUtmiPhyCount|2 + gMarvellTokenSpaceGuid.PcdUtmiPhyRegUsbCfg|L"0xF2440420;0xF2440420" + gMarvellTokenSpaceGuid.PcdUtmiPhyRegUtmiCfg|L"0xF2440440;0xF2440444" + gMarvellTokenSpaceGuid.PcdUtmiPhyRegUtmiUnit|L"0xF2580000;0xF2581000" + gMarvellTokenSpaceGuid.PcdUtmiPhyUtmiPort|L"0x0;0x1" + + #MDIO + gMarvellTokenSpaceGuid.PcdMdioBaseAddress|0xF212A200 + + #PHY + gMarvellTokenSpaceGuid.PcdPhyConnectionTypes|{ 0x4, 0x4, 0x0 } + gMarvellTokenSpaceGuid.PcdPhyDeviceIds|{ 0x0, 0x0 } + gMarvellTokenSpaceGuid.PcdPhyStartupAutoneg|FALSE + + #NET + gMarvellTokenSpaceGuid.PcdPhySmiAddresses|{ 0xff, 0x0, 0x1 } + gMarvellTokenSpaceGuid.PcdPp2ClockFrequency|333333333 + gMarvellTokenSpaceGuid.PcdPp2GmacBaseAddress|0xf2130e00 + gMarvellTokenSpaceGuid.PcdPp2GmacDevSize|0x1000 + gMarvellTokenSpaceGuid.PcdPp2GopIndexes|{ 0x0, 0x2, 0x3 } + gMarvellTokenSpaceGuid.PcdPp2InterfaceAlwaysUp|{ 0x1, 0x1, 0x0 } + gMarvellTokenSpaceGuid.PcdPp2InterfaceSpeed|{ 0x3, 0x4, 0x3 } + gMarvellTokenSpaceGuid.PcdPp2NumPorts|3 + gMarvellTokenSpaceGuid.PcdPp2PortIds|{ 0x0, 0x1, 0x2 } + gMarvellTokenSpaceGuid.PcdPp2Rfu1BaseAddress|0xf2441000 + gMarvellTokenSpaceGuid.PcdPp2SharedAddress|0xf2000000 + gMarvellTokenSpaceGuid.PcdPp2SmiBaseAddress|0xf212A200 + gMarvellTokenSpaceGuid.PcdPp2XlgBaseAddress|0xf2130f00 + gMarvellTokenSpaceGuid.PcdPp2XlgDevSize|0x1000 + + #PciEmulation + gMarvellTokenSpaceGuid.PcdPciEXhci|{ 0x1, 0x1, 0x0, 0x0 } + gMarvellTokenSpaceGuid.PcdPciEAhci|{ 0x1, 0x0 } + gMarvellTokenSpaceGuid.PcdPciESdhci|{ 0x1, 0x1 } + + #ResetLib + gMarvellTokenSpaceGuid.PcdResetRegAddress|0xf06f0084 + gMarvellTokenSpaceGuid.PcdResetRegMask|0x1 + + #RTC + gMarvellTokenSpaceGuid.PcdRtcEnabled|{ 0x1 } diff --git a/Platform/Marvell/Armada/Armada70x0.fdf b/Platform/Marvell/Armada/Armada70x0.fdf new file mode 100644 index 0000000000..c861e78a6f --- /dev/null +++ b/Platform/Marvell/Armada/Armada70x0.fdf @@ -0,0 +1,304 @@ +# +# Copyright (C) Marvell International Ltd. and its affiliates +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# + +################################################################################ +# +# FD Section +# The [FD] Section is made up of the definition statements and a +# description of what goes into the Flash Device Image. Each FD section +# defines one flash "device" image. A flash device image may be one of +# the following: Removable media bootable image (like a boot floppy +# image,) an Option ROM image (that would be "flashed" into an add-in +# card,) a System "Flash" image (that would be burned into a system's +# flash) or an Update ("Capsule") image that will be used to update and +# existing system flash. +# +################################################################################ + +[FD.Armada70x0_EFI] +BaseAddress = 0x00000000|gArmTokenSpaceGuid.PcdFdBaseAddress # The base address of the Firmware in NOR Flash. +Size = 0x00400000|gArmTokenSpaceGuid.PcdFdSize # The size in bytes of the FLASH Device +ErasePolarity = 1 + +# This one is tricky, it must be: BlockSize * NumBlocks = Size +BlockSize = 0x00001000 +NumBlocks = 0x400 + +################################################################################ +# +# Following are lists of FD Region layout which correspond to the locations of different +# images within the flash device. +# +# Regions must be defined in ascending order and may not overlap. +# +# A Layout Region start with a eight digit hex offset (leading "0x" required) followed by +# the pipe "|" character, followed by the size of the region, also in hex with the leading +# "0x" characters. Like: +# Offset|Size +# PcdOffsetCName|PcdSizeCName +# RegionType +# +################################################################################ + +0x00000000|0x00100000 +gArmTokenSpaceGuid.PcdFvBaseAddress|gArmTokenSpaceGuid.PcdFvSize +FV = FVMAIN_COMPACT + + +################################################################################ +# +# FV Section +# +# [FV] section is used to define what components or modules are placed within a flash +# device file. This section also defines order the components and modules are positioned +# within the image. The [FV] section consists of define statements, set statements and +# module statements. +# +################################################################################ + +# DXE phase firmware volume +[FV.FvMain] +BlockSize = 0x40 +NumBlocks = 0 # This FV gets compressed so make it just big enough +FvAlignment = 8 # FV alignment and FV attributes setting. +ERASE_POLARITY = 1 +MEMORY_MAPPED = TRUE +STICKY_WRITE = TRUE +LOCK_CAP = TRUE +LOCK_STATUS = TRUE +WRITE_DISABLED_CAP = TRUE +WRITE_ENABLED_CAP = TRUE +WRITE_STATUS = TRUE +WRITE_LOCK_CAP = TRUE +WRITE_LOCK_STATUS = TRUE +READ_DISABLED_CAP = TRUE +READ_ENABLED_CAP = TRUE +READ_STATUS = TRUE +READ_LOCK_CAP = TRUE +READ_LOCK_STATUS = TRUE +FvNameGuid = 5eda4200-2c5f-43cb-9da3-0baf74b1b30c + + INF MdeModulePkg/Core/Dxe/DxeMain.inf + + # PI DXE Drivers producing Architectural Protocols (EFI Services) + INF ArmPkg/Drivers/CpuDxe/CpuDxe.inf + INF ArmPkg/Drivers/ArmGic/ArmGicDxe.inf + INF ArmPkg/Drivers/TimerDxe/TimerDxe.inf + INF ArmPkg/Drivers/GenericWatchdogDxe/GenericWatchdogDxe.inf + INF MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf + INF MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf + INF MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf + INF MdeModulePkg/Universal/Variable/EmuRuntimeDxe/EmuVariableRuntimeDxe.inf + INF EmbeddedPkg/EmbeddedMonotonicCounter/EmbeddedMonotonicCounter.inf + INF MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf + INF EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClockRuntimeDxe.inf + INF EmbeddedPkg/MetronomeDxe/MetronomeDxe.inf + INF Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf + INF MdeModulePkg/Bus/I2c/I2cDxe/I2cDxe.inf + INF Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.inf + INF Platform/Marvell/Drivers/Spi/MvSpiDxe.inf + INF Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.inf + + # Network support + INF MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.inf + INF MdeModulePkg/Universal/Network/DpcDxe/DpcDxe.inf + INF MdeModulePkg/Universal/Network/MnpDxe/MnpDxe.inf + INF MdeModulePkg/Universal/Network/VlanConfigDxe/VlanConfigDxe.inf + INF MdeModulePkg/Universal/Network/ArpDxe/ArpDxe.inf + INF MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Dxe.inf + INF MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Dxe.inf + INF MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Dxe.inf + INF MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf + INF MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dxe.inf + INF Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.inf + INF Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.inf + INF Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.inf + + # PciEmulation + INF Platform/Marvell/PciEmulation/PciEmulation.inf + INF MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.inf + + # SCSI + INF MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf + INF MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf + + # SATA + INF MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf + INF MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf + INF OvmfPkg/SataControllerDxe/SataControllerDxe.inf + + # USB + INF MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf + INF MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf + INF MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf + + # SD/MMC + INF MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf + INF MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf + INF Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.inf + + # Multiple Console IO support + INF MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf + INF MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf + INF MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf + INF MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf + INF MdeModulePkg/Universal/SerialDxe/SerialDxe.inf + + # Human interface + INF MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf + + # FAT filesystem + GPT/MBR partitioning + INF MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf + INF MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf + INF FatBinPkg/EnhancedFatDxe/Fat.inf + INF MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf + + # UEFI application (Shell Embedded Boot Loader) + INF ShellPkg/Application/Shell/Shell.inf + + # Bds + INF MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf + INF MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf + INF MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf + INF IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.inf + + +# PEI phase firmware volume +[FV.FVMAIN_COMPACT] +FvAlignment = 8 +FvForceRebase = TRUE +ERASE_POLARITY = 1 +MEMORY_MAPPED = TRUE +STICKY_WRITE = TRUE +LOCK_CAP = TRUE +LOCK_STATUS = TRUE +WRITE_DISABLED_CAP = TRUE +WRITE_ENABLED_CAP = TRUE +WRITE_STATUS = TRUE +WRITE_LOCK_CAP = TRUE +WRITE_LOCK_STATUS = TRUE +READ_DISABLED_CAP = TRUE +READ_ENABLED_CAP = TRUE +READ_STATUS = TRUE +READ_LOCK_CAP = TRUE +READ_LOCK_STATUS = TRUE + + INF ArmPlatformPkg/PrePi/PeiMPCore.inf + + FILE FV_IMAGE = 9E21FD93-9C72-4c15-8C4B-E77F1DB2D792 { + SECTION GUIDED EE4E5898-3914-4259-9D6E-DC7BD79403CF PROCESSING_REQUIRED = TRUE { + SECTION FV_IMAGE = FVMAIN + } + } + +################################################################################ +# +# Rules are use with the [FV] section's module INF type to define +# how an FFS file is created for a given INF file. The following Rule are the default +# rules for the different module type. User can add the customized rules to define the +# content of the FFS file. +# +################################################################################ + + +############################################################################ +# Example of a DXE_DRIVER FFS file with a Checksum encapsulation section # +############################################################################ +# +#[Rule.Common.DXE_DRIVER] +# FILE DRIVER = $(NAMED_GUID) { +# DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex +# COMPRESS PI_STD { +# GUIDED { +# PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi +# UI STRING="$(MODULE_NAME)" Optional +# VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) +# } +# } +# } +# +############################################################################ + +[Rule.ARM.SEC] + FILE SEC = $(NAMED_GUID) RELOCS_STRIPPED { + TE TE Align = 32 $(INF_OUTPUT)/$(MODULE_NAME).efi + } + +# The AArch64 Vector Table requires a 2K alignment that is not supported by the FDF specification. +# It is the reason 4K is used instead of 2K for the module alignment. +[Rule.AARCH64.SEC] + FILE SEC = $(NAMED_GUID) RELOCS_STRIPPED { + TE TE Align = 4K $(INF_OUTPUT)/$(MODULE_NAME).efi + } + +[Rule.Common.PEI_CORE] + FILE PEI_CORE = $(NAMED_GUID) { + TE TE $(INF_OUTPUT)/$(MODULE_NAME).efi + UI STRING ="$(MODULE_NAME)" Optional + } + +[Rule.Common.PEIM] + FILE PEIM = $(NAMED_GUID) { + PEI_DEPEX PEI_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex + TE TE $(INF_OUTPUT)/$(MODULE_NAME).efi + UI STRING="$(MODULE_NAME)" Optional + } + +[Rule.Common.PEIM.TIANOCOMPRESSED] + FILE PEIM = $(NAMED_GUID) DEBUG_MYTOOLS_IA32 { + PEI_DEPEX PEI_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex + GUIDED A31280AD-481E-41B6-95E8-127F4C984779 PROCESSING_REQUIRED = TRUE { + PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi + UI STRING="$(MODULE_NAME)" Optional + } + } + +[Rule.Common.DXE_CORE] + FILE DXE_CORE = $(NAMED_GUID) { + PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi + UI STRING="$(MODULE_NAME)" Optional + } + +[Rule.Common.UEFI_DRIVER] + FILE DRIVER = $(NAMED_GUID) { + DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex + PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi + UI STRING="$(MODULE_NAME)" Optional + } + +[Rule.Common.UEFI_DRIVER.BINARY] + FILE DRIVER = $(NAMED_GUID) { + DXE_DEPEX DXE_DEPEX Optional |.depex + PE32 PE32 |.efi + UI STRING="$(MODULE_NAME)" Optional + VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) + } + +[Rule.Common.DXE_DRIVER] + FILE DRIVER = $(NAMED_GUID) { + DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex + PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi + UI STRING="$(MODULE_NAME)" Optional + } + +[Rule.Common.DXE_RUNTIME_DRIVER] + FILE DRIVER = $(NAMED_GUID) { + DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex + PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi + UI STRING="$(MODULE_NAME)" Optional + } + +[Rule.Common.UEFI_APPLICATION] + FILE APPLICATION = $(NAMED_GUID) { + UI STRING ="$(MODULE_NAME)" Optional + PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi + } diff --git a/Platform/Marvell/Armada/Library/Armada70x0Lib/AArch64/ArmPlatformHelper.S b/Platform/Marvell/Armada/Library/Armada70x0Lib/AArch64/ArmPlatformHelper.S new file mode 100644 index 0000000000..9265636ca5 --- /dev/null +++ b/Platform/Marvell/Armada/Library/Armada70x0Lib/AArch64/ArmPlatformHelper.S @@ -0,0 +1,50 @@ +//Based on ArmPlatformPkg/Library/ArmPlatformLibNull/AArch64/ArmPlatformHelper.S +// +// Copyright (c) 2012-2013, ARM Limited. All rights reserved. +// Copyright (c) 2016, Marvell. All rights reserved. +// +// This program and the accompanying materials are licensed and made available +// under the terms and conditions of the BSD License which accompanies this +// distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED +// + +#include +#include + +ASM_FUNC(ArmPlatformPeiBootAction) + ret + +//UINTN +//ArmPlatformGetCorePosition ( +// IN UINTN MpId +// ); +// With this function: CorePos = (ClusterId * 4) + CoreId +ASM_FUNC(ArmPlatformGetCorePosition) + and x1, x0, #ARM_CORE_MASK + and x0, x0, #ARM_CLUSTER_MASK + add x0, x1, x0, LSR #6 + ret + +//UINTN +//ArmPlatformGetPrimaryCoreMpId ( +// VOID +// ); +ASM_FUNC(ArmPlatformGetPrimaryCoreMpId) + MOV32 (w0, FixedPcdGet32(PcdArmPrimaryCore)) + ret + +//UINTN +//ArmPlatformIsPrimaryCore ( +// IN UINTN MpId +// ); +ASM_FUNC(ArmPlatformIsPrimaryCore) + MOV32 (w1, FixedPcdGet32(PcdArmPrimaryCoreMask)) + and x0, x0, x1 + MOV32 (w1, FixedPcdGet32(PcdArmPrimaryCore)) + cmp w0, w1 + cset x0, eq + ret diff --git a/Platform/Marvell/Armada/Library/Armada70x0Lib/Armada70x0Lib.c b/Platform/Marvell/Armada/Library/Armada70x0Lib/Armada70x0Lib.c new file mode 100644 index 0000000000..0ed310f8be --- /dev/null +++ b/Platform/Marvell/Armada/Library/Armada70x0Lib/Armada70x0Lib.c @@ -0,0 +1,157 @@ +/**Based on ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.c +* +* Copyright (c) 2011-2012, ARM Limited. All rights reserved. +* Copyright (c) 2016, Marvell International Ltd. All rights reserved. +* +* This program and the accompanying materials are licensed and made available +* under the terms and conditions of the BSD License which accompanies this +* distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#include +#include +#include +#include +#include +#include + + +ARM_CORE_INFO mArmada7040MpCoreInfoTable[] = { + { + // Cluster 0, Core 0 + 0x0, 0x0, + + // MP Core MailBox Set/Get/Clear Addresses and Clear Value + (EFI_PHYSICAL_ADDRESS)0, + (EFI_PHYSICAL_ADDRESS)0, + (EFI_PHYSICAL_ADDRESS)0, + (UINT64)0xFFFFFFFF + }, + { + // Cluster 0, Core 1 + 0x0, 0x1, + + // MP Core MailBox Set/Get/Clear Addresses and Clear Value + (EFI_PHYSICAL_ADDRESS)0, + (EFI_PHYSICAL_ADDRESS)0, + (EFI_PHYSICAL_ADDRESS)0, + (UINT64)0xFFFFFFFF + }, + { + // Cluster 0, Core 2 + 0x0, 0x2, + + // MP Core MailBox Set/Get/Clear Addresses and Clear Value + (EFI_PHYSICAL_ADDRESS)0, + (EFI_PHYSICAL_ADDRESS)0, + (EFI_PHYSICAL_ADDRESS)0, + (UINT64)0xFFFFFFFF + }, + { + // Cluster 0, Core 3 + 0x0, 0x3, + + // MP Core MailBox Set/Get/Clear Addresses and Clear Value + (EFI_PHYSICAL_ADDRESS)0, + (EFI_PHYSICAL_ADDRESS)0, + (EFI_PHYSICAL_ADDRESS)0, + (UINT64)0xFFFFFFFF + } +}; + +/** + Return the current Boot Mode + + This function returns the boot reason on the platform + +**/ +EFI_BOOT_MODE +ArmPlatformGetBootMode ( + VOID + ) +{ + return BOOT_WITH_FULL_CONFIGURATION; +} + +/** + Initialize controllers that must setup in the normal world + + This function is called by the ArmPlatformPkg/PrePi or ArmPlatformPkg/PlatformPei + in the PEI phase. + +**/ +RETURN_STATUS +ArmPlatformInitialize ( + IN UINTN MpId + ) +{ + if (!ArmPlatformIsPrimaryCore (MpId)) { + return RETURN_SUCCESS; + } + + MvComPhyInit (); + UtmiPhyInit (); + MppInitialize (); + return RETURN_SUCCESS; +} + +/** + Initialize the system (or sometimes called permanent) memory + + This memory is generally represented by the DRAM. + +**/ +VOID +ArmPlatformInitializeSystemMemory ( + VOID + ) +{ + //TODO: Initialize DRAM controller here +} + +EFI_STATUS +PrePeiCoreGetMpCoreInfo ( + OUT UINTN *CoreCount, + OUT ARM_CORE_INFO **ArmCoreTable + ) +{ + if (ArmIsMpCore()) { + *CoreCount = sizeof(mArmada7040MpCoreInfoTable) / sizeof(ARM_CORE_INFO); + *ArmCoreTable = mArmada7040MpCoreInfoTable; + return EFI_SUCCESS; + } else { + return EFI_UNSUPPORTED; + } +} + +ARM_MP_CORE_INFO_PPI mMpCoreInfoPpi = { PrePeiCoreGetMpCoreInfo }; + +EFI_PEI_PPI_DESCRIPTOR gPlatformPpiTable[] = { + { + EFI_PEI_PPI_DESCRIPTOR_PPI, + &gArmMpCoreInfoPpiGuid, + &mMpCoreInfoPpi + } +}; + +VOID +ArmPlatformGetPlatformPpiList ( + OUT UINTN *PpiListSize, + OUT EFI_PEI_PPI_DESCRIPTOR **PpiList + ) +{ + if (ArmIsMpCore()) { + *PpiListSize = sizeof(gPlatformPpiTable); + *PpiList = gPlatformPpiTable; + } else { + *PpiListSize = 0; + *PpiList = NULL; + } +} + + diff --git a/Platform/Marvell/Armada/Library/Armada70x0Lib/Armada70x0Lib.inf b/Platform/Marvell/Armada/Library/Armada70x0Lib/Armada70x0Lib.inf new file mode 100644 index 0000000000..2e198c3a0f --- /dev/null +++ b/Platform/Marvell/Armada/Library/Armada70x0Lib/Armada70x0Lib.inf @@ -0,0 +1,71 @@ +# Copyright (C) 2016 Marvell International Ltd. +# +# Marvell BSD License Option +# +# If you received this File from Marvell, you may opt to use, redistribute +# and/or modify this File under the following licensing terms. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Marvell nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Armada7040Lib + FILE_GUID = 3f29b642-4a49-4dfd-8f4a-205dd38432bb + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = ArmPlatformLib + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + Platform/Marvell/Marvell.dec + +[LibraryClasses] + ArmLib + ComPhyLib + DebugLib + MemoryAllocationLib + MppLib + UtmiPhyLib + +[Sources.common] + Armada70x0Lib.c + Armada70x0LibMem.c + +[Sources.AArch64] + AArch64/ArmPlatformHelper.S + +[FixedPcd] + gArmTokenSpaceGuid.PcdSystemMemoryBase + gArmTokenSpaceGuid.PcdSystemMemorySize + + gArmTokenSpaceGuid.PcdArmPrimaryCoreMask + gArmTokenSpaceGuid.PcdArmPrimaryCore + +[Ppis] + gArmMpCoreInfoPpiGuid diff --git a/Platform/Marvell/Armada/Library/Armada70x0Lib/Armada70x0LibMem.c b/Platform/Marvell/Armada/Library/Armada70x0Lib/Armada70x0LibMem.c new file mode 100644 index 0000000000..74c99568f7 --- /dev/null +++ b/Platform/Marvell/Armada/Library/Armada70x0Lib/Armada70x0LibMem.c @@ -0,0 +1,93 @@ +/******************************************************************************* +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include +#include +#include +#include + +// The total number of descriptors, including the final "end-of-table" descriptor. +#define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS 16 + +// DDR attributes +#define DDR_ATTRIBUTES_CACHED ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_BACK +#define DDR_ATTRIBUTES_UNCACHED ARM_MEMORY_REGION_ATTRIBUTE_UNCACHED_UNBUFFERED + +/** + Return the Virtual Memory Map of your platform + + This Virtual Memory Map is used by MemoryInitPei Module to initialize the MMU on your platform. + + @param[out] VirtualMemoryMap Array of ARM_MEMORY_REGION_DESCRIPTOR describing a Physical-to- + Virtual Memory mapping. This array must be ended by a zero-filled + entry + +**/ +VOID +ArmPlatformGetVirtualMemoryMap ( + IN ARM_MEMORY_REGION_DESCRIPTOR** VirtualMemoryMap + ) +{ + ARM_MEMORY_REGION_DESCRIPTOR *VirtualMemoryTable; + UINTN Index = 0; + + ASSERT (VirtualMemoryMap != NULL); + + VirtualMemoryTable = (ARM_MEMORY_REGION_DESCRIPTOR*)AllocatePages(EFI_SIZE_TO_PAGES (sizeof(ARM_MEMORY_REGION_DESCRIPTOR) * MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS)); + if (VirtualMemoryTable == NULL) { + return; + } + + // DDR + VirtualMemoryTable[Index].PhysicalBase = PcdGet64 (PcdSystemMemoryBase); + VirtualMemoryTable[Index].VirtualBase = PcdGet64 (PcdSystemMemoryBase); + VirtualMemoryTable[Index].Length = PcdGet64 (PcdSystemMemorySize); + VirtualMemoryTable[Index].Attributes = DDR_ATTRIBUTES_CACHED; + + // Configuration space 0xF000_0000 - 0xFFFF_FFFF + VirtualMemoryTable[++Index].PhysicalBase = 0xF0000000; + VirtualMemoryTable[Index].VirtualBase = 0xF0000000; + VirtualMemoryTable[Index].Length = 0x10000000; + VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE; + + // End of Table + VirtualMemoryTable[++Index].PhysicalBase = 0; + VirtualMemoryTable[Index].VirtualBase = 0; + VirtualMemoryTable[Index].Length = 0; + VirtualMemoryTable[Index].Attributes = 0; + + ASSERT((Index + 1) <= MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS); + + *VirtualMemoryMap = VirtualMemoryTable; +} diff --git a/Platform/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.c b/Platform/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.c new file mode 100644 index 0000000000..d671b6adc1 --- /dev/null +++ b/Platform/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.c @@ -0,0 +1,335 @@ +/** @file + Implement EFI RealTimeClock runtime services via RTC Lib. + + Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+ Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.
+ Copyright (c) 2017, 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. + +**/ +/** + Derived from: + ArmPlatformPkg/Library/PL031RealTimeClockLib/PL031RealTimeClockLib.c + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "RealTimeClockLib.h" + +DECLARE_A7K8K_RTC_TEMPLATE; +STATIC EFI_EVENT mRtcVirtualAddrChangeEvent; +STATIC UINTN mArmadaRtcBase; + +/** + According to errata FE-3124064, write to RTC TIME RTC_ALARMx registers + may fail. As a workaround, before actual writing to those registers, + issue a dummy write of 0x0 twice to RTC Status register. + Also, according to the datasheet, the OS should wait 5us after every + register write to the RTC hard macro, so that the required update + can occur without holding off the system bus. +**/ +STATIC +VOID +RtcDelayedWrite ( + IN UINT32 Offset, + IN UINT32 Value + ) +{ + MmioWrite32 (mArmadaRtcBase + RTC_STATUS_REG, 0); + MmioWrite32 (mArmadaRtcBase + RTC_STATUS_REG, 0); + MmioWrite32 (mArmadaRtcBase + Offset, Value); + MicroSecondDelay (5); +} + +/** + Returns the current time and date information, and the time-keeping capabilities + of the hardware platform. + + @param Time A pointer to storage to receive a snapshot of the current time. + @param Capabilities An optional pointer to a buffer to receive the real time clock + device's capabilities. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER Time is NULL. + @retval EFI_DEVICE_ERROR The time could not be retrieved due to hardware error. + +**/ +EFI_STATUS +EFIAPI +LibGetTime ( + OUT EFI_TIME *Time, + OUT EFI_TIME_CAPABILITIES *Capabilities + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINT32 RegVal; + + RegVal = MmioRead32 (mArmadaRtcBase + RTC_TIME_REG); + + // Convert from internal 32-bit time to UEFI time + EpochToEfiTime (RegVal, Time); + + Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE; + Time->Daylight = 0; + + return Status; +} + +/** + Sets the current local time and date information. + + @param Time A pointer to the current time. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER A time field is out of range. + @retval EFI_DEVICE_ERROR The time could not be set due due to hardware error. + +**/ +EFI_STATUS +EFIAPI +LibSetTime ( + IN EFI_TIME *Time + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINT32 EpochSeconds; + + // Check the input parameters are within the range specified by UEFI + if (!IsTimeValid (Time)) { + return EFI_INVALID_PARAMETER; + } + + // Convert time to raw seconds + EpochSeconds = EfiTimeToEpoch (Time); + + // Issue delayed write to time register + RtcDelayedWrite (RTC_TIME_REG, EpochSeconds); + + return Status; +} + +/** + Returns the current wakeup alarm clock setting. + + @param Enabled Indicates if the alarm is currently enabled or disabled. + @param Pending Indicates if the alarm signal is pending and requires acknowledgement. + @param Time The current alarm setting. + + @retval EFI_SUCCESS The alarm settings were returned. + @retval EFI_INVALID_PARAMETER Any parameter is NULL. + @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to a hardware error. + +**/ +EFI_STATUS +EFIAPI +LibGetWakeupTime ( + OUT BOOLEAN *Enabled, + OUT BOOLEAN *Pending, + OUT EFI_TIME *Time + ) +{ + UINT32 WakeupSeconds; + + *Enabled = MmioRead32 (mArmadaRtcBase + RTC_IRQ_2_CONFIG_REG) & RTC_IRQ_ALARM_EN; + + *Pending = MmioRead32 (mArmadaRtcBase + RTC_IRQ_STATUS_REG) & RTC_IRQ_ALARM_MASK; + // Ack pending alarm + if (Pending) { + MmioWrite32 (mArmadaRtcBase + RTC_IRQ_STATUS_REG, RTC_IRQ_ALARM_MASK); + } + + WakeupSeconds = MmioRead32 (mArmadaRtcBase + RTC_ALARM_2_REG); + EpochToEfiTime (WakeupSeconds, Time); + + return EFI_SUCCESS; +} + +/** + Sets the system wakeup alarm clock time. + + @param Enabled Enable or disable the wakeup alarm. + @param Time If Enable is TRUE, the time to set the wakeup alarm for. + + @retval EFI_SUCCESS If Enable is TRUE, then the wakeup alarm was enabled. If + Enable is FALSE, then the wakeup alarm was disabled. + @retval EFI_INVALID_PARAMETER A time field is out of range. + @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a hardware error. + @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform. + +**/ +EFI_STATUS +EFIAPI +LibSetWakeupTime ( + IN BOOLEAN Enabled, + OUT EFI_TIME *Time + ) +{ + UINT32 WakeupSeconds; + + // Convert time to raw seconds + WakeupSeconds = EfiTimeToEpoch (Time); + + // Issue delayed write to alarm register + RtcDelayedWrite (RTC_ALARM_2_REG, WakeupSeconds); + + if (Enabled) { + MmioWrite32 (mArmadaRtcBase + RTC_IRQ_2_CONFIG_REG, RTC_IRQ_ALARM_EN); + } else { + MmioWrite32 (mArmadaRtcBase + RTC_IRQ_2_CONFIG_REG, 0); + } + + return EFI_SUCCESS; +} + +/** + This is the declaration of an EFI image entry point. This can be the entry point to an application + written to this specification, an EFI boot service driver, or an EFI runtime driver. + + @param ImageHandle Handle that identifies the loaded image. + @param SystemTable System Table for this image. + + @retval EFI_SUCCESS The operation completed successfully. + +**/ +EFI_STATUS +EFIAPI +LibRtcInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + MVHW_RTC_DESC *Desc = &mA7k8kRtcDescTemplate; + UINT8 *RtcDeviceTable, Index; + EFI_HANDLE Handle; + EFI_STATUS Status; + + // Pick RTC device and initialize its data + RtcDeviceTable = (UINT8 *) PcdGetPtr (PcdRtcEnabled); + if (RtcDeviceTable == NULL) { + DEBUG ((DEBUG_ERROR, "RTC: Missing PcdRtcEnabled\n")); + return EFI_INVALID_PARAMETER; + } + + // Initialize only first of enabled controllers + for (Index = 0; Index < PcdGetSize (PcdRtcEnabled); Index++) { + if (MVHW_DEV_ENABLED (Rtc, Index)) { + DEBUG ((DEBUG_ERROR, "RTC: Initialize controller %d\n", Index)); + mArmadaRtcBase = Desc->RtcBaseAddresses[Index]; + break; + } + } + + // Check if any of the controllers can be initialized + if (mArmadaRtcBase == 0) { + DEBUG ((DEBUG_ERROR, "RTC: None of controllers enabled\n")); + return EFI_INVALID_PARAMETER; + } + + // Declare the controller as EFI_MEMORY_RUNTIME + Status = gDS->AddMemorySpace ( + EfiGcdMemoryTypeMemoryMappedIo, + mArmadaRtcBase, + Desc->RtcMemSize[Index], + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "RTC: Failed to add memory space\n")); + return Status; + } + + Status = gDS->SetMemorySpaceAttributes ( + mArmadaRtcBase, + Desc->RtcMemSize[Index], + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "RTC: Failed to set memory attributes\n")); + goto ErrSetMem; + } + + /* Update RTC-MBUS bridge timing parameters */ + MmioAndThenOr32 ( + mArmadaRtcBase + RTC_BRIDGE_TIMING_CTRL1_REG_OFFS, + ~RTC_READ_OUTPUT_DELAY_MASK, + RTC_READ_OUTPUT_DELAY_DEFAULT + ); + + // Install the protocol + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiRealTimeClockArchProtocolGuid, + NULL, + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "RTC: Failed to install the protocol\n")); + goto ErrSetMem; + } + + // Register for the virtual address change event + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + LibRtcVirtualNotifyEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &mRtcVirtualAddrChangeEvent + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "RTC: Failed to register virtual address change event\n")); + goto ErrEvent; + } + + return Status; + +ErrEvent: + gBS->UninstallProtocolInterface (Handle, &gEfiRealTimeClockArchProtocolGuid, NULL); +ErrSetMem: + gDS->RemoveMemorySpace (mArmadaRtcBase, Desc->RtcMemSize[Index]); + + return Status; +} + + +/** + Fixup internal data so that EFI can be call in virtual mode. + Call the passed in Child Notify event and convert any pointers in + lib to virtual mode. + + @param[in] Event The Event that is being processed + @param[in] Context Event Context +**/ +VOID +EFIAPI +LibRtcVirtualNotifyEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // + // Only needed if you are going to support the OS calling RTC functions in virtual mode. + // You will need to call EfiConvertPointer (). To convert any stored physical addresses + // to virtual address. After the OS transistions to calling in virtual mode, all future + // runtime calls will be made in virtual mode. + // + EfiConvertPointer (0x0, (VOID**)&mArmadaRtcBase); +} diff --git a/Platform/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.h b/Platform/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.h new file mode 100644 index 0000000000..922f959239 --- /dev/null +++ b/Platform/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.h @@ -0,0 +1,50 @@ +/******************************************************************************** +Copyright (C) 2017 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __RTCLIB_H__ +#define __RTCLIB_H__ + +/* Armada 70x0 SoC registers */ +#define RTC_STATUS_REG 0x0 +#define RTC_TIME_REG 0xC +#define RTC_IRQ_2_CONFIG_REG 0x8 +#define RTC_IRQ_ALARM_EN 0x1 +#define RTC_ALARM_2_REG 0x14 +#define RTC_BRIDGE_TIMING_CTRL1_REG_OFFS 0x84 +#define RTC_IRQ_STATUS_REG 0x90 +#define RTC_IRQ_ALARM_MASK 0x1 +#define RTC_READ_OUTPUT_DELAY_MASK 0xFFFF +#define RTC_READ_OUTPUT_DELAY_DEFAULT 0x1F + +#endif /* __RTCLIB_H__ */ diff --git a/Platform/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.inf b/Platform/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.inf new file mode 100644 index 0000000000..01c25f53b7 --- /dev/null +++ b/Platform/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.inf @@ -0,0 +1,52 @@ +#/** @file +# +# Copyright (c) 2006, Intel Corporation. All rights reserved.
+# Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.
+# Copyright (c) 2017, 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. +# +#**/ +#/** +# Derived from: +# ArmPlatformPkg/Library/PL031RealTimeClockLib/PL031RealTimeClockLib.inf +# +#**/ + + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = ArmadaRealTimeClockLib + FILE_GUID = fa81e889-045b-4c96-9093-742554fd0588 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RealTimeClockLib + +[Sources.common] + RealTimeClockLib.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Platform/Marvell/Marvell.dec + +[LibraryClasses] + DebugLib + DxeServicesTableLib + IoLib + PcdLib + TimeBaseLib + TimerLib + UefiRuntimeLib + +[Guids] + gEfiEventVirtualAddressChangeGuid + +[Pcd] + gMarvellTokenSpaceGuid.PcdRtcEnabled diff --git a/Platform/Marvell/Documentation/Drivers/EepromDriver.txt b/Platform/Marvell/Documentation/Drivers/EepromDriver.txt new file mode 100644 index 0000000000..d3b3b9f0d0 --- /dev/null +++ b/Platform/Marvell/Documentation/Drivers/EepromDriver.txt @@ -0,0 +1,96 @@ +1. Introduction +--------------- +**MvEeprom** driver creates MARVELL_EEPROM_PROTOCOL, which ++is used for managing eeprom. + +2. MvEeprom driver design +------------------------- +Every I2C device driver should implement EFI_DRIVER_BINDING_PROTOCOL and +consume EFI_I2C_IO_PROTOCOL for transactions on I2C bus. MvEeprom driver +additionally implements MARVELL_EEPROM_PROTOCOL. + + 2.1 EFI_DRIVER_BINDING_PROTOCOL + ------------------------------- + Driver Binding protocol is extensively covered in UEFI documentation, as + it is not specific to I2C stack. The only difference is that Supported() + function should check if EFI_I2C_IO_PROTOCOL provides valid EFI_GUID and + DeviceIndex values. + Excerpt from MvEepromSupported(): + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiI2cIoProtocolGuid, + (VOID **) &TmpI2cIo, + gImageHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR(Status)) { + return EFI_UNSUPPORTED; + } + + /* get EEPROM devices' addresses from PCD */ + EepromAddresses = PcdGetPtr (PcdEepromI2cAddresses); + if (EepromAddresses == 0) { + Status = EFI_UNSUPPORTED; + goto out; + } + + Status = EFI_UNSUPPORTED; + for (i = 0; EepromAddresses[i] != '\0'; i++) { + /* I2C guid must fit and valid DeviceIndex must be provided */ + if (CompareGuid(TmpI2cIo->DeviceGuid, &I2cGuid) && + TmpI2cIo->DeviceIndex == EepromAddresses[i]) { + DEBUG((DEBUG_INFO, "A8kEepromSupported: attached to EEPROM device\n")); + Status = EFI_SUCCESS; + break; + } + } + + 2.2 EFI_I2C_IO_PROTOCOL + ----------------------- + This protocol is provided by generic I2C stack. Multiple drivers can use IO + protocol at once, as queueing is implemented. + + QueueRequest is a routine that queues an I2C transaction to the I2C + controller for execution on the I2C bus. + + 2.3 MARVELL_EEPROM_PROTOCOL + ----------------------- + typedef struct _MARVELL_EEPROM_PROTOCOL MARVELL_EEPROM_PROTOCOL; + + #define EEPROM_READ 0x1 + #define EEPROM_WRITE 0x0 + typedef + EFI_STATUS + (EFIAPI *EFI_EEPROM_TRANSFER) ( + IN CONST MARVELL_EEPROM_PROTOCOL *This, + IN UINT16 Address, + IN UINT32 Length, + IN UINT8 *Buffer, + IN UINT8 Operation + ); + + struct _MARVELL_EEPROM_PROTOCOL { + EFI_EEPROM_TRANSFER Transfer; + UINT8 Identifier; + }; + +3. Adding new I2C slave device drivers +-------------------------------------- +In order to support I2C slave device other than EEPROM, new driver should +be created. Required steps follow. + + 1. Create driver directory (Platform/Marvell/Drivers/I2c/Devices/...). + 2. Create stubs of .inf and .c files (MvEeprom files are a reference), + include .inf file in platform .dsc and .fdf files. + 3. Implement EFI_DRIVER_BINDING_PROTOCOL - Start(), Stop(), Supported() + functions' implementation is a must. EFI_DRIVER_BINDING_PROTOCOL + should be installed at driver's entry point. + 4. Add I2C address of device to PcdI2cSlaveAddresses in .dsc file. + 5. Test available EFI_I2C_IO_PROTOCOLs in Supported() - find instance + with valid GUID and DeviceIndex (I2C slave address). + 6. Open EFI_I2C_IO_PROTOCOL for usage in Start(). After that, QueueRequest + function should be available. + 7. Implement core functionality of driver (using QueueRequest to access I2C). + 8. (not mandatory) Produce/consume additional protocols. diff --git a/Platform/Marvell/Documentation/Drivers/I2cDriver.txt b/Platform/Marvell/Documentation/Drivers/I2cDriver.txt new file mode 100644 index 0000000000..2f890de3db --- /dev/null +++ b/Platform/Marvell/Documentation/Drivers/I2cDriver.txt @@ -0,0 +1,64 @@ +1. Introduction +--------------- +**MvI2cDxe** is a driver supporting I2C controller on Marvell SOCs boards. +It is connected through protocols to generic UEFI I2C stack, which exposes +IO functionality to drivers of specific devices on I2C bus. + +2. MvI2cDxe driver design +-------------------------- +MvI2cDxe produces several protocols from generic I2C stack: + - EFI_I2C_MASTER_PROTOCOL, + - EFI_I2C_ENUMERATE_PROTOCOL, + - EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL + - general-purpose EFI_DRIVER_BINDING_PROTOCOL. + + 2.1 EFI_I2C_MASTER_PROTOCOL + --------------------------- + This is the most important protocol produced by MvI2cDxe. Following functions + are implemented: + + /// + /// Reset the I2C host controller. + /// + EFI_I2C_MASTER_PROTOCOL_RESET Reset; + + /// + /// Start an I2C transaction in master mode on the host controller. + /// + EFI_I2C_MASTER_PROTOCOL_START_REQUEST StartRequest; + + StartRequest and Reset functions are used by I2cHost. + These should **not** be used by I2C device drivers - required + synchronization is not provided. Instead, members of EFI_I2C_IO_PROTOCOL + should be used. + + 2.2 EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL + ------------------------------------------------- + The only function exposed via this protocol is MvI2cEnableConf. It is + required by I2C stack in order to allow changing I2C bus configuration from + device drivers. + + 2.3 EFI_I2C_ENUMERATE_PROTOCOL + ------------------------------ + Provides Enumerate function, which is used by I2cBus code as an iterator over + devices on I2C bus. + + typedef + EFI_STATUS + (EFIAPI *EFI_I2C_ENUMERATE_PROTOCOL_ENUMERATE) ( + IN CONST EFI_I2C_ENUMERATE_PROTOCOL *This, + IN OUT CONST EFI_I2C_DEVICE **Device + ); + + /// + /// Traverse the set of I2C devices on an I2C bus. This routine + /// returns the next I2C device on an I2C bus. + /// + EFI_I2C_ENUMERATE_PROTOCOL_ENUMERATE Enumerate; + + MvI2cDevice creates EFI_I2C_DEVICE structure for every device on the bus. + Due to the fact that hardware-based I2C enumeration isn't safe, information + about attached devices should be provided through PCDs. After EFI_I2C_DEVICE + structure is created and filled properly, it is returned to I2cBus. It is + followed by attachment of I2C device driver. + diff --git a/Platform/Marvell/Documentation/Drivers/SpiDriver.txt b/Platform/Marvell/Documentation/Drivers/SpiDriver.txt new file mode 100644 index 0000000000..42b5e3ce3b --- /dev/null +++ b/Platform/Marvell/Documentation/Drivers/SpiDriver.txt @@ -0,0 +1,116 @@ +1. Introduction +--------------- +**SpiDxe** driver implements MARVELL_SPI_MASTER_PROTOCOL in order to manage SPI +controller on Marvell A8k boards. It exposes below functionalities: + - create and setup SPI slaves + - raw transfer over SPI bus + +2. SpiDxe driver design +----------------------- + + 2.1 MARVELL_SPI_MASTER_PROTOCOL + ----------------------- + First member of SPI_MASTER protocol is Init function, implemented for SPI + master controller initialization. + + ->Init() + + // + //Initializes the host controller to execute SPI commands. + // + + param[IN] This Pointer to the MARVELL_SPI_MASTER_PROTOCOL instance + + return EFI_SUCCESS Opcode initialization on the SPI host + controller completed. + return EFI_ACCESS_DENIED The SPI configuration interface is + locked. + return EFI_OUT_OF_RESOURCES Not enough resource available to + initialize the device. + return EFI_DEVICE_ERROR Device error, operation failed. + + ******** + + SPI devices (slaves) do not support any kind of automatic discovery or + enumaration, so every device needs manual configuration, which may be done + with SetupDevice function. + + ->SetupDevice() + + // + //Allocate and zero all fields in the SPI_DEVICE struct. Set the chip + //select, max frequency and transfer mode supported by slave device. + // + + param[IN] Cs Chip select ID of the slave chip. + param[IN] MaxFreq Maximum SCK rate in Hz. + param[IN] Mode Clock polarity and clock phase. + + return *SPI_DEVICE Pointer to new allocated struct SPI_DEVICE. + return NULL NULL pointer if any eroor occured. + + ******** + + Developers have to destroy all created SPI device structs (with FreeDevice + function) in order to prevent from memory leak. + + ->FreeDevice() + + // + //Free any memory associated with a SPI device. + // + + param[in] SpiDev Pointer to the SPI_DEVICE struct. + + return EFI_SUCCESS Memory fried succesfully. + return EFI_DEVICE_ERROR Device error, operation failed. + + ******** + + Transfer function allows write/read raw bytes over SPI bus. + + ->Transfer() + + // + //Perform transfer over SPI bus + // + param[in] This Pointer to the MARVELL_SPI_MASTER_PROTOCOL + instance. + param[in] Slave Pointer to the SPI_DEVICE struct. + param[in] DataByteCount Number of bytes in the data portion of + the SPI cycle. + param[in] DataOut Pointer to caller-allocated buffer + containing the data to send. + param[out] DataIn Pointer to caller-allocated buffer + where received data will be placed. + param[in] Flag Flags which indicate state of CS line + during/after transfer (see file + Drivers/Spi/Devices/A8kSpiFlash.h) + + return EFI_SUCCESS Memory fried succesfully. + return EFI_DEVICE_ERROR Device error, operation failed. + + ********* + + When working with SPI devices it is often necessary to perform "command and + address" transactions. It may be done via ReadWrite function. + + ->ReadWrite() + + // + //Perform two steps transactions. First write Command, then read/write + //buffer + // + + param[in] This Pointer to the MARVELL_SPI_MASTER_PROTOCOL + instance. + param[in] Slave Pointer to the SPI_DEVICE struct. + param[in] Cmd Pointer to caller-allocated buffer + containing the command to send. + param[in] CmdSize Size of command (in bytes). + param[in] DataOut Pointer to caller-allocated buffer + containing the data to send. + param[out] DataIn Pointer to caller-allocated buffer + where received data will be placed. + param[in] DataSize Number of bytes in the data portion of + the SPI cycle. diff --git a/Platform/Marvell/Documentation/PortingGuide/ComPhy.txt b/Platform/Marvell/Documentation/PortingGuide/ComPhy.txt new file mode 100644 index 0000000000..a96015e152 --- /dev/null +++ b/Platform/Marvell/Documentation/PortingGuide/ComPhy.txt @@ -0,0 +1,45 @@ +COMPHY configuration +--------------------------- +In order to configure ComPhy library, following PCDs are available: + + gMarvellTokenSpaceGuid.PcdComPhyDevices + +This array indicates, which ones of the ComPhy chips defined in +MVHW_COMPHY_DESC template will be configured. + +Every ComPhy PCD has part where stands for chip ID (order is not +important, but configuration will be set for first PcdComPhyChipCount chips). + +Every chip has 3 ComPhy PCDs and three of them comprise per-board lanes +settings for this chip. Their format is unicode string, containing settings +for up to 10 lanes. Setting for each one is separated with semicolon. +These PCDs together describe outputs of PHY integrated in simple cihp. +Below is example for the first chip (Chip0). + + gMarvellTokenSpaceGuid.PcdChip0ComPhyTypes + +Unicode string indicating PHY types. Currently supported are: + +{ L"unconnected", L"PCIE0", L"PCIE1", L"PCIE2", L"PCIE3", +L"SATA0", L"SATA1", L"SATA2", L"SATA3", L"SGMII0", +L"SGMII1", L"SGMII2", L"SGMII3", +L"USB3_HOST0", L"USB3_HOST1", L"USB3_DEVICE", +L"RXAUI0", L"RXAUI1", L"SFI" } + + gMarvellTokenSpaceGuid.PcdChip0ComPhySpeeds + +Indicates PHY speeds in MHz. Currently supported are: + +{ 1250, 1500, 2500, 3000, 3125, 5000, 6000, 6250, 10310 } + + gMarvellTokenSpaceGuid.PcdChip0ComPhyInvFlags + +Indicates lane polarity invert. + +Example +------- + #ComPhy + gMarvellTokenSpaceGuid.PcdComPhyDevices|{ 0x1 } + gMarvellTokenSpaceGuid.PcdChip0ComPhyTypes|L"SGMII1;USB3_HOST0;SFI;SATA1;USB3_HOST1;PCIE2" + gMarvellTokenSpaceGuid.PcdChip0ComPhySpeeds|L"1250;5000;10310;5000;5000;5000" + diff --git a/Platform/Marvell/Documentation/PortingGuide/I2c.txt b/Platform/Marvell/Documentation/PortingGuide/I2c.txt new file mode 100644 index 0000000000..020ffb4f1b --- /dev/null +++ b/Platform/Marvell/Documentation/PortingGuide/I2c.txt @@ -0,0 +1,20 @@ +1. Porting I2C driver to a new SOC +---------------------------------- +In order to enable driver on a new platform, following steps need to be taken: + - add following line to .dsc file: + Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf + - add following line to .fdf file: + INF Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf + - add PCDs with relevant values to .dsc file: + gMarvellTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x50, 0x57 } + (addresses of I2C slave devices on bus) + gMarvellTokenSpaceGuid.PcdI2cSlaveBuses|{ 0x0, 0x0 } + (buses to which accoring slaves are attached) + gMarvellTokenSpaceGuid.PcdI2cBusCount|2 + (number of SoC's I2C buses) + gMarvellTokenSpaceGuid.PcdI2cBaseAddresses|L"0xF2701000;0xF2701100" + (base addresses of I2C controller buses) + gMarvellTokenSpaceGuid.PcdI2cClockFrequency|200000000 + (I2C host controller clock frequency) + gMarvellTokenSpaceGuid.PcdI2cBaudRate|100000 + (baud rate used in I2C transmission) diff --git a/Platform/Marvell/Documentation/PortingGuide/Mdio.txt b/Platform/Marvell/Documentation/PortingGuide/Mdio.txt new file mode 100644 index 0000000000..c341d9e8d0 --- /dev/null +++ b/Platform/Marvell/Documentation/PortingGuide/Mdio.txt @@ -0,0 +1,7 @@ +MDIO driver configuration +------------------------- +MDIO driver provides access to network PHYs' registers via MARVELL_MDIO_READ and +MARVELL_MDIO_WRITE functions (MARVELL_MDIO_PROTOCOL). Following PCD is required: + + gMarvellTokenSpaceGuid.PcdMdioBaseAddress + (base address of SMI management register) diff --git a/Platform/Marvell/Documentation/PortingGuide/Mpp.txt b/Platform/Marvell/Documentation/PortingGuide/Mpp.txt new file mode 100644 index 0000000000..68f0e9d179 --- /dev/null +++ b/Platform/Marvell/Documentation/PortingGuide/Mpp.txt @@ -0,0 +1,48 @@ +MPP configuration +----------------- +Multi-Purpose Ports (MPP) are configurable through platform PCDs. +In order to set desired pin multiplexing, .dsc file needs to be modified. +(Platform/Marvell/Armada/{platform_name}.dsc - please refer to +Documentation/Build.txt for currently supported {platftorm_name} ) +Following PCDs are available: + + gMarvellTokenSpaceGuid.PcdMppChipCount + +Indicates how many different chips are placed on board. So far up to 4 chips +are supported. + +Every MPP PCD has part where + stands for chip ID (order is not important, but configuration will be + set for first PcdMppChipCount chips). + +Below is example for the first chip (Chip0). + + gMarvellTokenSpaceGuid.PcdChip0MppReverseFlag + +Indicates that register order is reversed. (Needs to be used only for AP806-Z1) + + gMarvellTokenSpaceGuid.PcdChip0MppBaseAddress + +This is base address for MPP configuration register. + + gMarvellTokenSpaceGuid.PcdChip0MppPinCount + +Defines how many MPP pins are available. + + gMarvellTokenSpaceGuid.PcdChip0MppSel0 + gMarvellTokenSpaceGuid.PcdChip0MppSel1 + gMarvellTokenSpaceGuid.PcdChip0MppSel2 + +This registers defines functions of 10 pins in ascending order. + +Examples +-------- +#APN806-A0 MPP SET + gMarvellTokenSpaceGuid.PcdChip0MppReverseFlag|FALSE + gMarvellTokenSpaceGuid.PcdChip0MppBaseAddress|0xF06F4000 + gMarvellTokenSpaceGuid.PcdChip0MppRegCount|3 + gMarvellTokenSpaceGuid.PcdChip0MppSel0|{ 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0 } + gMarvellTokenSpaceGuid.PcdChip0MppSel1|{ 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } + +Set pin 6 and 7 to 0xa function: + gMarvellTokenSpaceGuid.PcdChip0MppSel0|{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0xa, 0x0, 0x0 } diff --git a/Platform/Marvell/Documentation/PortingGuide/PciEmulation.txt b/Platform/Marvell/Documentation/PortingGuide/PciEmulation.txt new file mode 100644 index 0000000000..ec1afbc7bf --- /dev/null +++ b/Platform/Marvell/Documentation/PortingGuide/PciEmulation.txt @@ -0,0 +1,31 @@ +PciEmulation configuration +-------------------------- +Installation of various NonDiscoverable devices via PciEmulation driver is performed +via set of PCDs. Following are available: + + gMarvellTokenSpaceGuid.PcdPciEXhci + +Indicates, which Xhci devices are used. + + gMarvellTokenSpaceGuid.PcdPciEAhci + +Indicates, which Ahci devices are used. + + gMarvellTokenSpaceGuid.PcdPciESdhci + +Indicates, which Sdhci devices are used. + +All above PCD's correspond to hardware description in a dedicated structure: + +STATIC PCI_E_PLATFORM_DESC A70x0PlatDescTemplate + +in Platforms/Marvell/PciEmulation/PciEmulation.c file. It comprises device +count, base addresses, register region size and DMA-coherency type. + +Examples +-------- +Assuming we want to enable second XHCI port and one SDHCI port on Armada +70x0 board, following needs to be declared: + + gMarvellTokenSpaceGuid.PcdPciEXhci|{ 0x0 0x1 } + gMarvellTokenSpaceGuid.PcdPciESdhci|{ 0x1 } diff --git a/Platform/Marvell/Documentation/PortingGuide/Phy.txt b/Platform/Marvell/Documentation/PortingGuide/Phy.txt new file mode 100644 index 0000000000..69dae02a3e --- /dev/null +++ b/Platform/Marvell/Documentation/PortingGuide/Phy.txt @@ -0,0 +1,45 @@ +PHY driver configuration +------------------------ +MvPhyDxe provides basic initialization and status routines for Marvell PHYs. +Currently only 1512 series PHYs are supported. Following PCDs are required: + + gMarvellTokenSpaceGuid.PcdPhyConnectionTypes + (list of values corresponding to PHY_CONNECTION enum) + gMarvellTokenSpaceGuid.PcdPhyStartupAutoneg + (boolean - if true, driver waits for autonegotiation on startup) + gMarvellTokenSpaceGuid.PcdPhyDeviceIds + (list of values corresponding to MV_PHY_DEVICE_ID enum) + +PHY_CONNECTION enum type is defined as follows: + + typedef enum { +0 PHY_CONNECTION_RGMII, +1 PHY_CONNECTION_RGMII_ID, +2 PHY_CONNECTION_RGMII_TXID, +3 PHY_CONNECTION_RGMII_RXID, +4 PHY_CONNECTION_SGMII, +5 PHY_CONNECTION_RTBI, +6 PHY_CONNECTION_XAUI, +7 PHY_CONNECTION_RXAUI + } PHY_CONNECTION; + +MV_PHY_DEVICE_ID: + + typedef enum { +0 MV_PHY_DEVICE_1512, + } MV_PHY_DEVICE_ID; + +It should be extended when adding support for other PHY +models. + +Thus in order to set RGMII for 1st PHY and SGMII for 2nd, PCD should be: + + gMarvellTokenSpaceGuid.PcdPhyConnectionTypes|{ 0x0, 0x4 } + +with disabled autonegotiation: + + gMarvellTokenSpaceGuid.PcdPhyStartupAutoneg|FALSE + +assuming, that PHY models are 1512: + + gMarvellTokenSpaceGuid.PcdPhyDeviceIds|{ 0x0, 0x0 } diff --git a/Platform/Marvell/Documentation/PortingGuide/Pp2.txt b/Platform/Marvell/Documentation/PortingGuide/Pp2.txt new file mode 100644 index 0000000000..c1554a694e --- /dev/null +++ b/Platform/Marvell/Documentation/PortingGuide/Pp2.txt @@ -0,0 +1,59 @@ +Pp2Dxe porting guide +-------------------- +Pp2Dxe is driver supporting PP2 NIC on Marvell platforms. Following PCDs +are required to operate: + +Number of ports/network interfaces: + gMarvellTokenSpaceGuid.PcdPp2NumPorts + +Addresses of PHY devices: + gMarvellTokenSpaceGuid.PcdPhySmiAddresses + +Identificators of PP2 ports: + gMarvellTokenSpaceGuid.PcdPp2PortIds + +Indexes used in GOP operation: + gMarvellTokenSpaceGuid.PcdPp2GopIndexes + +Set to 0x1 for always-up interface, 0x0 otherwise: + gMarvellTokenSpaceGuid.PcdPp2InterfaceAlwaysUp + +Values corresponding to PHY_SPEED enum: + gMarvellTokenSpaceGuid.PcdPp2InterfaceSpeed + +PHY_SPEED (in Mbps) is defined as follows: + typedef enum { + 0 NO_SPEED, + 1 SPEED_10, + 2 SPEED_100, + 3 SPEED_1000, + 4 SPEED_2500, + 5 SPEED_10000 + } PHY_SPEED; + +Base address of shared register space of PP2: + gMarvellTokenSpaceGuid.PcdPp2SharedAddress + +Spacing between consecutive GMAC register spaces: + gMarvellTokenSpaceGuid.PcdPp2GmacDevSize + +Base address of GMAC: + gMarvellTokenSpaceGuid.PcdPp2GmacBaseAddress + +Spacing between consecutive XLG register spaces: + gMarvellTokenSpaceGuid.PcdPp2XlgDevSize + +Base address of XLG: + gMarvellTokenSpaceGuid.PcdPp2XlgBaseAddress + +Base address of RFU1: + gMarvellTokenSpaceGuid.PcdPp2Rfu1BaseAddress + +Base address of SMI: + gMarvellTokenSpaceGuid.PcdPp2SmiBaseAddress + +TCLK frequency in Hz: + gMarvellTokenSpaceGuid.PcdPp2ClockFrequency + +GMAC and XLG addresses are computed as follows: + address = base_address + dev_size * gop_index diff --git a/Platform/Marvell/Documentation/PortingGuide/Reset.txt b/Platform/Marvell/Documentation/PortingGuide/Reset.txt new file mode 100644 index 0000000000..30dec8612b --- /dev/null +++ b/Platform/Marvell/Documentation/PortingGuide/Reset.txt @@ -0,0 +1,7 @@ +MarvellResetSystemLib configuration +----------------------------------- +This simple library allows to mask given bits in given reg at UEFI 'reset' +command call. These variables are configurable through PCDs: + + gMarvellTokenSpaceGuid.PcdResetRegAddress + gMarvellTokenSpaceGuid.PcdResetRegMask diff --git a/Platform/Marvell/Documentation/PortingGuide/Spi.txt b/Platform/Marvell/Documentation/PortingGuide/Spi.txt new file mode 100644 index 0000000000..be498a66a6 --- /dev/null +++ b/Platform/Marvell/Documentation/PortingGuide/Spi.txt @@ -0,0 +1,16 @@ +Spi driver configuration +------------------------ +Following PCDs are available for configuration of spi driver: + + gMarvellTokenSpaceGuid.PcdSpiClockFrequency + +Frequency (in Hz) of SPI clock + + gMarvellTokenSpaceGuid.PcdSpiMaxFrequency + +Max SCLK line frequency (in Hz) (max transfer frequency) + + gMarvellTokenSpaceGuid.PcdSpiDefaultMode + +default SCLK mode (see SPI_MODE enum in file +Platform/Marvell/Drivers/Spi/MvSpi.h) diff --git a/Platform/Marvell/Documentation/PortingGuide/SpiFlash.txt b/Platform/Marvell/Documentation/PortingGuide/SpiFlash.txt new file mode 100644 index 0000000000..226db4001e --- /dev/null +++ b/Platform/Marvell/Documentation/PortingGuide/SpiFlash.txt @@ -0,0 +1,23 @@ +SpiFlash driver configuration +----------------------------- +Folowing PCDs for spi flash driver configuration must be set properly: + + gMarvellTokenSpaceGuid.PcdSpiFlashAddressCycles + +Size of SPI flash address in bytes (3 or 4) + + gMarvellTokenSpaceGuid.PcdSpiFlashEraseSize + +Size of minimal erase block in bytes + + gMarvellTokenSpaceGuid.PcdSpiFlashPageSize + +Size of SPI flash page + + gMarvellTokenSpaceGuid.PcdSpiFlashId + +Id of SPI flash + + gMarvellTokenSpaceGuid.PcdSpiFlashPollCmd + +Spi flash polling flag diff --git a/Platform/Marvell/Documentation/PortingGuide/Utmi.txt b/Platform/Marvell/Documentation/PortingGuide/Utmi.txt new file mode 100644 index 0000000000..cff4843da2 --- /dev/null +++ b/Platform/Marvell/Documentation/PortingGuide/Utmi.txt @@ -0,0 +1,35 @@ +UTMI PHY configuration +---------------------- +In order to configure UTMI, following PCDs are available: + + gMarvellTokenSpaceGuid.PcdUtmiPhyCount + +Indicates how many UTMI PHYs are available on platform. + +Next four PCDs are in unicode string format containing settings for all devices +separated with semicolon. + + gMarvellTokenSpaceGuid.PcdUtmiPhyRegUtmiUnit + +Indicates base address of the UTMI unit. + + gMarvellTokenSpaceGuid.PcdUtmiPhyRegUsbCfg + +Indicates address of USB Configuration register. + + gMarvellTokenSpaceGuid.PcdUtmiPhyRegUtmiCfg + +Indicates address of external UTMI configuration. + + gMarvellTokenSpaceGuid.PcdUtmiPhyUtmiPort + +Indicates type of the connected USB port. + +Example +------- +#UtmiPhy + gMarvellTokenSpaceGuid.PcdUtmiPhyCount|2 + gMarvellTokenSpaceGuid.PcdUtmiPhyRegUtmiUnit|L"0xF2580000;0xF2581000" + gMarvellTokenSpaceGuid.PcdUtmiPhyRegUsbCfg|L"0xF2440420;0xF2440420" + gMarvellTokenSpaceGuid.PcdUtmiPhyRegUtmiCfg|L"0xF2440440;0xF2440444" + gMarvellTokenSpaceGuid.PcdUtmiPhyUtmiPort|L"0x0;0x1" diff --git a/Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.c b/Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.c new file mode 100644 index 0000000000..d8fd1bfe62 --- /dev/null +++ b/Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.c @@ -0,0 +1,292 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "MvEeprom.h" + +#define I2C_DEVICE_INDEX(bus, address) (((address) & 0xffff) | (bus) << 16) + +STATIC CONST EFI_GUID I2cGuid = I2C_GUID; + +EFI_DRIVER_BINDING_PROTOCOL gDriverBindingProtocol = { + MvEepromSupported, + MvEepromStart, + MvEepromStop +}; + +EFI_STATUS +EFIAPI +MvEepromSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + EFI_STATUS Status = EFI_UNSUPPORTED; + EFI_I2C_IO_PROTOCOL *TmpI2cIo; + UINT8 *EepromAddresses; + UINT8 *EepromBuses; + UINTN i; + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiI2cIoProtocolGuid, + (VOID **) &TmpI2cIo, + gImageHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR(Status)) { + return EFI_UNSUPPORTED; + } + + /* get EEPROM devices' addresses from PCD */ + EepromAddresses = PcdGetPtr (PcdEepromI2cAddresses); + EepromBuses = PcdGetPtr (PcdEepromI2cBuses); + if (EepromAddresses == 0) { + Status = EFI_UNSUPPORTED; + DEBUG((DEBUG_INFO, "MvEepromSupported: I2C device found, but it's not EEPROM\n")); + goto out; + } + + Status = EFI_UNSUPPORTED; + for (i = 0; EepromAddresses[i] != '\0'; i++) { + /* I2C guid must fit and valid DeviceIndex must be provided */ + if (CompareGuid(TmpI2cIo->DeviceGuid, &I2cGuid) && + TmpI2cIo->DeviceIndex == I2C_DEVICE_INDEX(EepromBuses[i], + EepromAddresses[i])) { + DEBUG((DEBUG_INFO, "MvEepromSupported: attached to EEPROM device\n")); + Status = EFI_SUCCESS; + break; + } + } + +out: + gBS->CloseProtocol ( + ControllerHandle, + &gEfiI2cIoProtocolGuid, + gImageHandle, + ControllerHandle + ); + return Status; +} + +EFI_STATUS +EFIAPI +MvEepromTransfer ( + IN CONST MARVELL_EEPROM_PROTOCOL *This, + IN UINT16 Address, + IN UINT32 Length, + IN UINT8 *Buffer, + IN UINT8 Operation + ) +{ + EFI_I2C_REQUEST_PACKET *RequestPacket; + UINTN RequestPacketSize; + EFI_STATUS Status = EFI_SUCCESS; + EEPROM_CONTEXT *EepromContext = EEPROM_SC_FROM_EEPROM(This); + UINT32 BufferLength; + UINT32 Transmitted = 0; + UINT32 CurrentAddress = Address; + + ASSERT(EepromContext != NULL); + ASSERT(EepromContext->I2cIo != NULL); + + RequestPacketSize = sizeof(UINTN) + sizeof (EFI_I2C_OPERATION) * 2; + RequestPacket = AllocateZeroPool (RequestPacketSize); + if (RequestPacket == NULL) + return EFI_OUT_OF_RESOURCES; + /* First operation contains address, the second is buffer */ + RequestPacket->OperationCount = 2; + RequestPacket->Operation[0].LengthInBytes = 2; + RequestPacket->Operation[0].Buffer = AllocateZeroPool ( RequestPacket->Operation[0].LengthInBytes ); + if (RequestPacket->Operation[0].Buffer == NULL) { + FreePool(RequestPacket); + return EFI_OUT_OF_RESOURCES; + } + RequestPacket->Operation[1].Flags = (Operation == EEPROM_READ ? I2C_FLAG_READ : I2C_FLAG_NORESTART); + + while (Length > 0) { + CurrentAddress = Address + Transmitted; + BufferLength = (Length <= MAX_BUFFER_LENGTH ? Length : MAX_BUFFER_LENGTH); + RequestPacket->Operation[0].Buffer[0] = (CurrentAddress >> 8) & 0xff; + RequestPacket->Operation[0].Buffer[1] = CurrentAddress & 0xff; + RequestPacket->Operation[1].LengthInBytes = BufferLength; + RequestPacket->Operation[1].Buffer = Buffer + Transmitted; + Status = EepromContext->I2cIo->QueueRequest(EepromContext->I2cIo, 0, NULL, RequestPacket, NULL); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "MvEepromTransfer: error %d during transmission\n", Status)); + break; + } + Length -= BufferLength; + Transmitted += BufferLength; + } + + FreePool(RequestPacket->Operation[0].Buffer); + FreePool(RequestPacket); + return Status; +} + +EFI_STATUS +EFIAPI +MvEepromStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + EEPROM_CONTEXT *EepromContext; + + EepromContext = AllocateZeroPool (sizeof(EEPROM_CONTEXT)); + if (EepromContext == NULL) { + DEBUG((DEBUG_ERROR, "MvEeprom: allocation fail\n")); + return EFI_OUT_OF_RESOURCES; + } + + EepromContext->ControllerHandle = ControllerHandle; + EepromContext->Signature = EEPROM_SIGNATURE; + EepromContext->EepromProtocol.Transfer = MvEepromTransfer; + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiI2cIoProtocolGuid, + (VOID **) &EepromContext->I2cIo, + gImageHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "MvEeprom: failed to open I2cIo\n")); + FreePool(EepromContext); + return EFI_UNSUPPORTED; + } + + EepromContext->EepromProtocol.Identifier = EepromContext->I2cIo->DeviceIndex; + Status = gBS->InstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gMarvellEepromProtocolGuid, &EepromContext->EepromProtocol, + NULL + ); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "MvEeprom: failed to install EEPROM protocol\n")); + goto fail; + } + + return Status; + +fail: + FreePool(EepromContext); + gBS->CloseProtocol ( + ControllerHandle, + &gEfiI2cIoProtocolGuid, + gImageHandle, + ControllerHandle + ); + + return Status; +} + +EFI_STATUS +EFIAPI +MvEepromStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ) +{ + MARVELL_EEPROM_PROTOCOL *EepromProtocol; + EFI_STATUS Status; + EEPROM_CONTEXT *EepromContext; + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gMarvellEepromProtocolGuid, + (VOID **) &EepromProtocol, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + EepromContext = EEPROM_SC_FROM_EEPROM(EepromProtocol); + + gBS->UninstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gMarvellEepromProtocolGuid, &EepromContext->EepromProtocol, + &gEfiDriverBindingProtocolGuid, &gDriverBindingProtocol, + NULL + ); + gBS->CloseProtocol ( + ControllerHandle, + &gEfiI2cIoProtocolGuid, + gImageHandle, + ControllerHandle + ); + FreePool(EepromContext); + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +MvEepromInitialise ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiDriverBindingProtocolGuid, &gDriverBindingProtocol, + NULL + ); + return Status; +} diff --git a/Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.h b/Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.h new file mode 100644 index 0000000000..b1af645050 --- /dev/null +++ b/Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.h @@ -0,0 +1,103 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __MV_EEPROM_H__ +#define __MV_EEPROM_H__ + +#include + +#define EEPROM_SIGNATURE SIGNATURE_32 ('E', 'E', 'P', 'R') + +#define MAX_BUFFER_LENGTH 64 + +/* + * I2C_FLAG_NORESTART is not part of PI spec, it allows to continue + * transmission without repeated start operation. + * FIXME: This flag is also defined in Drivers/I2c/MvI2cDxe/MvI2cDxe.h + * and it's important to have both version synced. This solution is + * temporary and shared flag should be used by both files. + * Situation is analogous with I2C_GUID, which also should be common, but is + * for now defined same way in two header files. + */ +#define I2C_FLAG_NORESTART 0x00000002 +#define I2C_GUID \ + { \ + 0xadc1901b, 0xb83c, 0x4831, { 0x8f, 0x59, 0x70, 0x89, 0x8f, 0x26, 0x57, 0x1e } \ + } + +typedef struct { + UINT32 Signature; + EFI_HANDLE ControllerHandle; + EFI_I2C_IO_PROTOCOL *I2cIo; + MARVELL_EEPROM_PROTOCOL EepromProtocol; +} EEPROM_CONTEXT; + +#define EEPROM_SC_FROM_IO(a) CR (a, EEPROM_CONTEXT, I2cIo, EEPROM_SIGNATURE) +#define EEPROM_SC_FROM_EEPROM(a) CR (a, EEPROM_CONTEXT, EepromProtocol, EEPROM_SIGNATURE) + +EFI_STATUS +EFIAPI +MvEepromSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +EFI_STATUS +EFIAPI +MvEepromStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +EFI_STATUS +EFIAPI +MvEepromStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ); + +EFI_STATUS +EFIAPI +MvEepromTransfer ( + IN CONST MARVELL_EEPROM_PROTOCOL *This, + IN UINT16 Address, + IN UINT32 Length, + IN UINT8 *Buffer, + IN UINT8 Operation + ); +#endif // __MV_EEPROM_H__ diff --git a/Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.inf b/Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.inf new file mode 100644 index 0000000000..a50f8b9b4e --- /dev/null +++ b/Platform/Marvell/Drivers/I2c/Devices/MvEeprom/MvEeprom.inf @@ -0,0 +1,70 @@ +# +# Marvell BSD License Option +# +# If you received this File from Marvell, you may opt to use, redistribute +# and/or modify this File under the following licensing terms. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Marvell nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = MvEeprom + FILE_GUID = 59fc3843-d8d4-40aa-ae07-38967138509c + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = MvEepromInitialise + +[Sources.common] + MvEeprom.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + ArmPkg/ArmPkg.dec + Platform/Marvell/Marvell.dec + +[LibraryClasses] + IoLib + PcdLib + BaseLib + BaseMemoryLib + DebugLib + UefiLib + UefiDriverEntryPoint + UefiBootServicesTableLib + +[Protocols] + gEfiI2cIoProtocolGuid + gEfiDriverBindingProtocolGuid + gMarvellEepromProtocolGuid + +[Pcd] + gMarvellTokenSpaceGuid.PcdEepromI2cAddresses + gMarvellTokenSpaceGuid.PcdEepromI2cBuses + +[Depex] + TRUE diff --git a/Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.c b/Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.c new file mode 100755 index 0000000000..fa79ebccfa --- /dev/null +++ b/Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.c @@ -0,0 +1,740 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MvI2cDxe.h" + +STATIC MV_I2C_BAUD_RATE baud_rate; + +STATIC MV_I2C_DEVICE_PATH MvI2cDevicePathProtocol = { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8) (sizeof(VENDOR_DEVICE_PATH)), + (UINT8) (sizeof(VENDOR_DEVICE_PATH) >> 8), + }, + }, + EFI_CALLER_ID_GUID + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + sizeof(EFI_DEVICE_PATH_PROTOCOL), + 0 + } + } +}; + +STATIC +UINT32 +I2C_READ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINTN off) +{ + ASSERT (I2cMasterContext != NULL); + return MmioRead32 (I2cMasterContext->BaseAddress + off); +} + +STATIC +EFI_STATUS +I2C_WRITE ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINTN off, + IN UINT32 Value) +{ + ASSERT (I2cMasterContext != NULL); + return MmioWrite32 (I2cMasterContext->BaseAddress + off, Value); +} + +EFI_STATUS +EFIAPI +MvI2cInitialiseController ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable, + IN EFI_PHYSICAL_ADDRESS BaseAddress + ) +{ + EFI_STATUS Status; + I2C_MASTER_CONTEXT *I2cMasterContext; + STATIC INTN Bus = 0; + MV_I2C_DEVICE_PATH *DevicePath; + + DevicePath = AllocateCopyPool (sizeof(MvI2cDevicePathProtocol), + &MvI2cDevicePathProtocol); + if (DevicePath == NULL) { + DEBUG((DEBUG_ERROR, "MvI2cDxe: I2C device path allocation failed\n")); + return EFI_OUT_OF_RESOURCES; + } + DevicePath->Guid.Guid.Data4[0] = Bus; + + /* if attachment succeeds, this gets freed at ExitBootServices */ + I2cMasterContext = AllocateZeroPool (sizeof (I2C_MASTER_CONTEXT)); + if (I2cMasterContext == NULL) { + DEBUG((DEBUG_ERROR, "MvI2cDxe: I2C master context allocation failed\n")); + return EFI_OUT_OF_RESOURCES; + } + I2cMasterContext->Signature = I2C_MASTER_SIGNATURE; + I2cMasterContext->I2cMaster.Reset = MvI2cReset; + I2cMasterContext->I2cMaster.StartRequest = MvI2cStartRequest; + I2cMasterContext->I2cEnumerate.Enumerate = MvI2cEnumerate; + I2cMasterContext->I2cBusConf.EnableI2cBusConfiguration = MvI2cEnableConf; + I2cMasterContext->TclkFrequency = PcdGet32 (PcdI2cClockFrequency); + I2cMasterContext->BaseAddress = BaseAddress; + I2cMasterContext->Bus = Bus; + /* I2cMasterContext->Lock is responsible for serializing I2C operations */ + EfiInitializeLock(&I2cMasterContext->Lock, TPL_NOTIFY); + + MvI2cCalBaudRate( I2cMasterContext, + PcdGet32 (PcdI2cBaudRate), + &baud_rate, + I2cMasterContext->TclkFrequency + ); + + Status = gBS->InstallMultipleProtocolInterfaces( + &I2cMasterContext->Controller, + &gEfiI2cMasterProtocolGuid, + &I2cMasterContext->I2cMaster, + &gEfiI2cEnumerateProtocolGuid, + &I2cMasterContext->I2cEnumerate, + &gEfiI2cBusConfigurationManagementProtocolGuid, + &I2cMasterContext->I2cBusConf, + &gEfiDevicePathProtocolGuid, + (EFI_DEVICE_PATH_PROTOCOL *) DevicePath, + NULL); + + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "MvI2cDxe: Installing protocol interfaces failed!\n")); + goto fail; + } + DEBUG((DEBUG_ERROR, "Succesfully installed controller %d at 0x%llx\n", Bus, + I2cMasterContext->BaseAddress)); + + Bus++; + + return EFI_SUCCESS; + +fail: + FreePool(I2cMasterContext); + return Status; +} + +EFI_STATUS +EFIAPI +MvI2cInitialise ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + UINT32 BusCount; + EFI_PHYSICAL_ADDRESS I2cBaseAddresses[PcdGet32 (PcdI2cBusCount)]; + INTN i; + + BusCount = PcdGet32 (PcdI2cBusCount); + if (BusCount == 0) + return EFI_SUCCESS; + + Status = ParsePcdString ( + (CHAR16 *) PcdGetPtr (PcdI2cBaseAddresses), + BusCount, + I2cBaseAddresses, + NULL + ); + if (EFI_ERROR(Status)) + return Status; + + for (i = 0; i < BusCount; i++) { + Status = MvI2cInitialiseController( + ImageHandle, + SystemTable, + I2cBaseAddresses[i] + ); + if (EFI_ERROR(Status)) + return Status; + } + + return Status; +} + +STATIC +VOID +MvI2cControlClear ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINT32 Mask) +{ + UINT32 Value; + + /* clears given bits in I2C_CONTROL register */ + Value = I2C_READ(I2cMasterContext, I2C_CONTROL); + Value &= ~Mask; + I2C_WRITE(I2cMasterContext, I2C_CONTROL, Value); +} + +STATIC +VOID +MvI2cControlSet ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINT32 Mask) +{ + UINT32 Value; + + /* sets given bits in I2C_CONTROL register */ + Value = I2C_READ(I2cMasterContext, I2C_CONTROL); + Value |= Mask; + I2C_WRITE(I2cMasterContext, I2C_CONTROL, Value); +} + +STATIC +VOID +MvI2cClearIflg ( + IN I2C_MASTER_CONTEXT *I2cMasterContext + ) +{ + gBS->Stall(I2C_OPERATION_TIMEOUT); + MvI2cControlClear(I2cMasterContext, I2C_CONTROL_IFLG); + gBS->Stall(I2C_OPERATION_TIMEOUT); +} + +/* Timeout is given in us */ +STATIC +UINTN +MvI2cPollCtrl ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINTN Timeout, + IN UINT32 Mask) +{ + Timeout /= 10; + while (!(I2C_READ(I2cMasterContext, I2C_CONTROL) & Mask)) { + gBS->Stall(10); + if (--Timeout == 0) + return (Timeout); + } + return (0); +} + +/* + * 'Timeout' is given in us. Note also that Timeout handling is not exact -- + * MvI2cLockedStart() total wait can be more than 2 x Timeout + * (MvI2cPollCtrl() is called twice). 'Mask' can be either I2C_STATUS_START + * or I2C_STATUS_RPTD_START + */ +STATIC +EFI_STATUS +MvI2cLockedStart ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN INT32 Mask, + IN UINT8 Slave, + IN UINTN Timeout + ) +{ + UINTN ReadAccess, IflgSet = 0; + UINT32 I2cStatus; + + if (Mask == I2C_STATUS_RPTD_START) { + /* read IFLG to know if it should be cleared later */ + IflgSet = I2C_READ(I2cMasterContext, I2C_CONTROL) & I2C_CONTROL_IFLG; + } + + MvI2cControlSet(I2cMasterContext, I2C_CONTROL_START); + + if (Mask == I2C_STATUS_RPTD_START && IflgSet) { + DEBUG((DEBUG_INFO, "MvI2cDxe: IFLG set, clearing\n")); + MvI2cClearIflg(I2cMasterContext); + } + + /* Without this delay we Timeout checking IFLG if the Timeout is 0 */ + gBS->Stall(I2C_OPERATION_TIMEOUT); + + if (MvI2cPollCtrl(I2cMasterContext, Timeout, I2C_CONTROL_IFLG)) { + DEBUG((DEBUG_ERROR, "MvI2cDxe: Timeout sending %sSTART condition\n", + Mask == I2C_STATUS_START ? "" : "repeated ")); + return EFI_NO_RESPONSE; + } + + I2cStatus = I2C_READ(I2cMasterContext, I2C_STATUS); + if (I2cStatus != Mask) { + DEBUG((DEBUG_ERROR, "MvI2cDxe: wrong I2cStatus (%02x) after sending %sSTART condition\n", + I2cStatus, Mask == I2C_STATUS_START ? "" : "repeated ")); + return EFI_DEVICE_ERROR; + } + + I2C_WRITE(I2cMasterContext, I2C_DATA, Slave); + gBS->Stall(I2C_OPERATION_TIMEOUT); + MvI2cClearIflg(I2cMasterContext); + + if (MvI2cPollCtrl(I2cMasterContext, Timeout, I2C_CONTROL_IFLG)) { + DEBUG((DEBUG_ERROR, "MvI2cDxe: Timeout sending Slave address\n")); + return EFI_NO_RESPONSE; + } + + ReadAccess = (Slave & 0x1) ? 1 : 0; + I2cStatus = I2C_READ(I2cMasterContext, I2C_STATUS); + if (I2cStatus != (ReadAccess ? + I2C_STATUS_ADDR_R_ACK : I2C_STATUS_ADDR_W_ACK)) { + DEBUG((DEBUG_ERROR, "MvI2cDxe: no ACK (I2cStatus: %02x) after sending Slave address\n", + I2cStatus)); + return EFI_NO_RESPONSE; + } + + return EFI_SUCCESS; +} + +#define ABSSUB(a,b) (((a) > (b)) ? (a) - (b) : (b) - (a)) +STATIC +VOID +MvI2cCalBaudRate ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN CONST UINT32 target, + IN OUT MV_I2C_BAUD_RATE *rate, + UINT32 clk + ) +{ + UINT32 cur, diff, diff0, baud; + UINTN m, n, m0, n0; + + /* Read initial m0, n0 values from register */ + baud = I2C_READ(I2cMasterContext, I2C_BAUD_RATE); + m0 = I2C_M_FROM_BAUD(baud); + n0 = I2C_N_FROM_BAUD(baud); + /* Calculate baud rate. */ + diff0 = 0xffffffff; + + for (n = 0; n < 8; n++) { + for (m = 0; m < 16; m++) { + cur = I2C_BAUD_RATE_RAW(clk,m,n); + diff = ABSSUB(target, cur); + if (diff < diff0) { + m0 = m; + n0 = n; + diff0 = diff; + } + } + } + rate->raw = I2C_BAUD_RATE_RAW(clk, m0, n0); + rate->param = I2C_BAUD_RATE_PARAM(m0, n0); + rate->m = m0; + rate->n = n0; +} + +EFI_STATUS +EFIAPI +MvI2cReset ( + IN CONST EFI_I2C_MASTER_PROTOCOL *This + ) +{ + UINT32 param; + I2C_MASTER_CONTEXT *I2cMasterContext = I2C_SC_FROM_MASTER(This); + + param = baud_rate.param; + + EfiAcquireLock (&I2cMasterContext->Lock); + I2C_WRITE(I2cMasterContext, I2C_SOFT_RESET, 0x0); + gBS->Stall(2 * I2C_OPERATION_TIMEOUT); + I2C_WRITE(I2cMasterContext, I2C_BAUD_RATE, param); + I2C_WRITE(I2cMasterContext, I2C_CONTROL, I2C_CONTROL_I2CEN | I2C_CONTROL_ACK); + gBS->Stall(I2C_OPERATION_TIMEOUT); + EfiReleaseLock (&I2cMasterContext->Lock); + + return EFI_SUCCESS; +} + +/* + * Timeout is given in us + */ +STATIC +EFI_STATUS +MvI2cRepeatedStart ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINT8 Slave, + IN UINTN Timeout + ) +{ + EFI_STATUS Status; + + EfiAcquireLock (&I2cMasterContext->Lock); + Status = MvI2cLockedStart(I2cMasterContext, I2C_STATUS_RPTD_START, Slave, + Timeout); + EfiReleaseLock (&I2cMasterContext->Lock); + + if (EFI_ERROR(Status)) { + MvI2cStop(I2cMasterContext); + } + return Status; +} + +/* + * Timeout is given in us + */ +STATIC +EFI_STATUS +MvI2cStart ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINT8 Slave, + IN UINTN Timeout + ) +{ + EFI_STATUS Status; + + EfiAcquireLock (&I2cMasterContext->Lock); + Status = MvI2cLockedStart(I2cMasterContext, I2C_STATUS_START, Slave, Timeout); + EfiReleaseLock (&I2cMasterContext->Lock); + + if (EFI_ERROR(Status)) { + MvI2cStop(I2cMasterContext); + } + return Status; +} + +STATIC +EFI_STATUS +MvI2cStop ( + IN I2C_MASTER_CONTEXT *I2cMasterContext + ) +{ + EfiAcquireLock (&I2cMasterContext->Lock); + MvI2cControlSet(I2cMasterContext, I2C_CONTROL_STOP); + gBS->Stall(I2C_OPERATION_TIMEOUT); + MvI2cClearIflg(I2cMasterContext); + EfiReleaseLock (&I2cMasterContext->Lock); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +MvI2cRead ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN OUT UINT8 *Buf, + IN UINTN Length, + IN OUT UINTN *read, + IN UINTN last, + IN UINTN delay + ) +{ + UINT32 I2cStatus; + UINTN LastByte; + EFI_STATUS Status; + + EfiAcquireLock (&I2cMasterContext->Lock); + *read = 0; + while (*read < Length) { + /* + * Check if we are reading last byte of the last Buffer, + * do not send ACK then, per I2C specs + */ + LastByte = ((*read == Length - 1) && last) ? 1 : 0; + if (LastByte) + MvI2cControlClear(I2cMasterContext, I2C_CONTROL_ACK); + else + MvI2cControlSet(I2cMasterContext, I2C_CONTROL_ACK); + + gBS->Stall (I2C_OPERATION_TIMEOUT); + MvI2cClearIflg(I2cMasterContext); + + if (MvI2cPollCtrl(I2cMasterContext, delay, I2C_CONTROL_IFLG)) { + DEBUG((DEBUG_ERROR, "MvI2cDxe: Timeout reading data\n")); + Status = EFI_NO_RESPONSE; + goto out; + } + + I2cStatus = I2C_READ(I2cMasterContext, I2C_STATUS); + if (I2cStatus != (LastByte ? + I2C_STATUS_DATA_RD_NOACK : I2C_STATUS_DATA_RD_ACK)) { + DEBUG((DEBUG_ERROR, "MvI2cDxe: wrong I2cStatus (%02x) while reading\n", I2cStatus)); + Status = EFI_DEVICE_ERROR; + goto out; + } + + *Buf++ = I2C_READ(I2cMasterContext, I2C_DATA); + (*read)++; + } + Status = EFI_SUCCESS; +out: + EfiReleaseLock (&I2cMasterContext->Lock); + return (Status); +} + +STATIC +EFI_STATUS +MvI2cWrite ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN OUT CONST UINT8 *Buf, + IN UINTN Length, + IN OUT UINTN *Sent, + IN UINTN Timeout + ) +{ + UINT32 status; + EFI_STATUS Status; + + EfiAcquireLock (&I2cMasterContext->Lock); + *Sent = 0; + while (*Sent < Length) { + I2C_WRITE(I2cMasterContext, I2C_DATA, *Buf++); + + MvI2cClearIflg(I2cMasterContext); + if (MvI2cPollCtrl(I2cMasterContext, Timeout, I2C_CONTROL_IFLG)) { + DEBUG((DEBUG_ERROR, "MvI2cDxe: Timeout writing data\n")); + Status = EFI_NO_RESPONSE; + goto out; + } + + status = I2C_READ(I2cMasterContext, I2C_STATUS); + if (status != I2C_STATUS_DATA_WR_ACK) { + DEBUG((DEBUG_ERROR, "MvI2cDxe: wrong status (%02x) while writing\n", status)); + Status = EFI_DEVICE_ERROR; + goto out; + } + (*Sent)++; + } + Status = EFI_SUCCESS; +out: + EfiReleaseLock (&I2cMasterContext->Lock); + return (Status); +} + +/* + * MvI2cStartRequest should be called only by I2cHost. + * I2C device drivers ought to use EFI_I2C_IO_PROTOCOL instead. + */ +STATIC +EFI_STATUS +MvI2cStartRequest ( + IN CONST EFI_I2C_MASTER_PROTOCOL *This, + IN UINTN SlaveAddress, + IN EFI_I2C_REQUEST_PACKET *RequestPacket, + IN EFI_EVENT Event OPTIONAL, + OUT EFI_STATUS *I2cStatus OPTIONAL + ) +{ + UINTN Count; + UINTN ReadMode; + UINTN Transmitted; + I2C_MASTER_CONTEXT *I2cMasterContext = I2C_SC_FROM_MASTER(This); + EFI_I2C_OPERATION *Operation; + + ASSERT (RequestPacket != NULL); + ASSERT (I2cMasterContext != NULL); + + for (Count = 0; Count < RequestPacket->OperationCount; Count++) { + Operation = &RequestPacket->Operation[Count]; + ReadMode = Operation->Flags & I2C_FLAG_READ; + + if (Count == 0) { + MvI2cStart ( I2cMasterContext, + (SlaveAddress << 1) | ReadMode, + I2C_TRANSFER_TIMEOUT + ); + } else if (!(Operation->Flags & I2C_FLAG_NORESTART)) { + MvI2cRepeatedStart ( I2cMasterContext, + (SlaveAddress << 1) | ReadMode, + I2C_TRANSFER_TIMEOUT + ); + } + + if (ReadMode) { + MvI2cRead ( I2cMasterContext, + Operation->Buffer, + Operation->LengthInBytes, + &Transmitted, + Count == 1, + I2C_TRANSFER_TIMEOUT + ); + } else { + MvI2cWrite ( I2cMasterContext, + Operation->Buffer, + Operation->LengthInBytes, + &Transmitted, + I2C_TRANSFER_TIMEOUT + ); + } + if (Count == RequestPacket->OperationCount - 1) { + MvI2cStop ( I2cMasterContext ); + } + } + + if (I2cStatus != NULL) + I2cStatus = EFI_SUCCESS; + if (Event != NULL) + gBS->SignalEvent(Event); + return EFI_SUCCESS; +} + +STATIC CONST EFI_GUID DevGuid = I2C_GUID; + +#define I2C_DEVICE_INDEX(bus, address) (((address) & 0xffff) | (bus) << 16) +#define I2C_DEVICE_ADDRESS(index) ((index) & 0xffff) + +STATIC +EFI_STATUS +MvI2cAllocDevice ( + IN UINT8 SlaveAddress, + IN UINT8 Bus, + IN OUT CONST EFI_I2C_DEVICE **Device + ) +{ + EFI_STATUS Status; + EFI_I2C_DEVICE *Dev; + UINT32 *TmpSlaveArray; + EFI_GUID *TmpGuidP; + + Status = gBS->AllocatePool ( EfiBootServicesData, + sizeof(EFI_I2C_DEVICE), + (VOID **) &Dev ); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "MvI2cDxe: I2C device memory allocation failed\n")); + return Status; + } + *Device = Dev; + Dev->DeviceIndex = SlaveAddress; + Dev->DeviceIndex = I2C_DEVICE_INDEX(Bus, SlaveAddress); + Dev->SlaveAddressCount = 1; + Dev->I2cBusConfiguration = 0; + Status = gBS->AllocatePool ( EfiBootServicesData, + sizeof(UINT32), + (VOID **) &TmpSlaveArray); + if (EFI_ERROR(Status)) { + goto fail1; + } + TmpSlaveArray[0] = SlaveAddress; + Dev->SlaveAddressArray = TmpSlaveArray; + + Status = gBS->AllocatePool ( EfiBootServicesData, + sizeof(EFI_GUID), + (VOID **) &TmpGuidP); + if (EFI_ERROR(Status)) { + goto fail2; + } + *TmpGuidP = DevGuid; + Dev->DeviceGuid = TmpGuidP; + + DEBUG((DEBUG_INFO, "MvI2c: allocated device with address %x\n", (UINTN)SlaveAddress)); + return EFI_SUCCESS; + +fail2: + FreePool(TmpSlaveArray); +fail1: + FreePool(Dev); + + return Status; +} + +/* + * It is called by I2cBus to enumerate devices on I2C bus. In this case, + * enumeration is based on PCD configuration - all Slave addresses specified + * in PCD get their corresponding EFI_I2C_DEVICE structures here. + * + * After enumeration succeeds, Supported() function of drivers that installed + * DriverBinding protocol is called. + */ +STATIC +EFI_STATUS +EFIAPI +MvI2cEnumerate ( + IN CONST EFI_I2C_ENUMERATE_PROTOCOL *This, + IN OUT CONST EFI_I2C_DEVICE **Device + ) +{ + UINT8 *DevicesPcd; + UINT8 *DeviceBusPcd; + UINTN Index, NextIndex, DevCount; + UINT8 NextDeviceAddress; + I2C_MASTER_CONTEXT *I2cMasterContext = I2C_SC_FROM_ENUMERATE(This); + + DevCount = PcdGetSize (PcdI2cSlaveAddresses); + DevicesPcd = PcdGetPtr (PcdI2cSlaveAddresses); + DeviceBusPcd = PcdGetPtr (PcdI2cSlaveBuses); + if (*Device == NULL) { + for (Index = 0; Index < DevCount ; Index++) { + if (DeviceBusPcd[Index] != I2cMasterContext->Bus) + continue; + if (Index < DevCount) + MvI2cAllocDevice (DevicesPcd[Index], I2cMasterContext->Bus, Device); + return EFI_SUCCESS; + } + } else { + /* Device is not NULL, so something was already allocated */ + for (Index = 0; Index < DevCount; Index++) { + if (DeviceBusPcd[Index] != I2cMasterContext->Bus) + continue; + if (DevicesPcd[Index] == I2C_DEVICE_ADDRESS((*Device)->DeviceIndex)) { + for (NextIndex = Index + 1; NextIndex < DevCount; NextIndex++) { + if (DeviceBusPcd[NextIndex] != I2cMasterContext->Bus) + continue; + NextDeviceAddress = DevicesPcd[NextIndex]; + if (NextIndex < DevCount) + MvI2cAllocDevice(NextDeviceAddress, I2cMasterContext->Bus, Device); + return EFI_SUCCESS; + } + } + } + *Device = NULL; + return EFI_SUCCESS; + } + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +MvI2cEnableConf ( + IN CONST EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL *This, + IN UINTN I2cBusConfiguration, + IN EFI_EVENT Event OPTIONAL, + IN EFI_STATUS *I2cStatus OPTIONAL + ) +{ + /* do nothing */ + if (I2cStatus != NULL) + I2cStatus = EFI_SUCCESS; + if (Event != NULL) + gBS->SignalEvent(Event); + return EFI_SUCCESS; +} diff --git a/Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.h b/Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.h new file mode 100644 index 0000000000..028fd5461f --- /dev/null +++ b/Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.h @@ -0,0 +1,269 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __MV_I2C_H__ +#define __MV_I2C_H__ + +#include + +#define I2C_BASE_ADDRESS 0xf0511000 + +#define I2C_SLAVE_ADDR 0x00 +#define I2C_EXT_SLAVE_ADDR 0x10 +#define I2C_DATA 0x04 + +#define I2C_CONTROL 0x08 +#define I2C_CONTROL_ACK (1 << 2) +#define I2C_CONTROL_IFLG (1 << 3) +#define I2C_CONTROL_STOP (1 << 4) +#define I2C_CONTROL_START (1 << 5) +#define I2C_CONTROL_I2CEN (1 << 6) +#define I2C_CONTROL_INTEN (1 << 7) + +#define I2C_STATUS 0x0c +#define I2C_STATUS_START 0x08 +#define I2C_STATUS_RPTD_START 0x10 +#define I2C_STATUS_ADDR_W_ACK 0x18 +#define I2C_STATUS_DATA_WR_ACK 0x28 +#define I2C_STATUS_ADDR_R_ACK 0x40 +#define I2C_STATUS_DATA_RD_ACK 0x50 +#define I2C_STATUS_DATA_RD_NOACK 0x58 + +#define I2C_BAUD_RATE 0x0c +#define I2C_BAUD_RATE_PARAM(M,N) ((((M) << 3) | ((N) & 0x7)) & 0x7f) +#define I2C_BAUD_RATE_RAW(C,M,N) ((C)/((10*(M+1))<<(N+1))) +#define I2C_M_FROM_BAUD(baud) (((baud) >> 3) & 0xf) +#define I2C_N_FROM_BAUD(baud) ((baud) & 0x7) + +#define I2C_SOFT_RESET 0x1c +#define I2C_TRANSFER_TIMEOUT 10000 +#define I2C_OPERATION_TIMEOUT 1000 + +#define I2C_UNKNOWN 0x0 +#define I2C_SLOW 0x1 +#define I2C_FAST 0x2 +#define I2C_FASTEST 0x3 + +/* + * I2C_FLAG_NORESTART is not part of PI spec, it allows to continue + * transmission without repeated start operation. + * FIXME: This flag is also defined in + * Platforms/Marvell/Include/Protocol/Eeprom.h and it's important to have both + * version synced. This solution is temporary and shared flag should be used by + * both files. + * Situation is analogous with I2C_GUID, which also should be common, but is + * for now defined same way in two header files. + */ +#define I2C_FLAG_NORESTART 0x00000002 +#define I2C_GUID \ + { \ + 0xadc1901b, 0xb83c, 0x4831, { 0x8f, 0x59, 0x70, 0x89, 0x8f, 0x26, 0x57, 0x1e } \ + } + +#define I2C_MASTER_SIGNATURE SIGNATURE_32 ('I', '2', 'C', 'M') + +typedef struct { + UINT32 Signature; + EFI_HANDLE Controller; + EFI_LOCK Lock; + UINTN TclkFrequency; + UINTN BaseAddress; + INTN Bus; + EFI_I2C_MASTER_PROTOCOL I2cMaster; + EFI_I2C_ENUMERATE_PROTOCOL I2cEnumerate; + EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL I2cBusConf; +} I2C_MASTER_CONTEXT; + +#define I2C_SC_FROM_MASTER(a) CR (a, I2C_MASTER_CONTEXT, I2cMaster, I2C_MASTER_SIGNATURE) +#define I2C_SC_FROM_ENUMERATE(a) CR (a, I2C_MASTER_CONTEXT, I2cEnumerate, I2C_MASTER_SIGNATURE) +#define I2C_SC_FROM_BUSCONF(a) CR (a, I2C_MASTER_CONTEXT, I2cBusConf, I2C_MASTER_SIGNATURE) + +typedef struct { + UINT32 raw; + UINTN param; + UINTN m; + UINTN n; +} MV_I2C_BAUD_RATE; + +typedef struct { + VENDOR_DEVICE_PATH Guid; + EFI_DEVICE_PATH_PROTOCOL End; +} MV_I2C_DEVICE_PATH; + +STATIC +UINT32 +I2C_READ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINTN off + ); + +STATIC +EFI_STATUS +I2C_WRITE ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINTN off, + IN UINT32 val + ); + +EFI_STATUS +EFIAPI +MvI2cInitialise ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +STATIC +VOID +MvI2cControlClear ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINT32 mask + ); + +STATIC +VOID +MvI2cControlSet ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINT32 mask + ); + +STATIC +VOID +MvI2cClearIflg ( + IN I2C_MASTER_CONTEXT *I2cMasterContext + ); +STATIC +UINTN +MvI2cPollCtrl ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINTN timeout, + IN UINT32 mask + ); + +STATIC +EFI_STATUS +MvI2cLockedStart ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN INT32 mask, + IN UINT8 slave, + IN UINTN timeout + ); + +STATIC +VOID +MvI2cCalBaudRate ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN CONST UINT32 target, + IN OUT MV_I2C_BAUD_RATE *rate, + UINT32 clk + ); + +EFI_STATUS +EFIAPI +MvI2cReset ( + IN CONST EFI_I2C_MASTER_PROTOCOL *This + ); + +STATIC +EFI_STATUS +MvI2cRepeatedStart ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINT8 slave, + IN UINTN timeout + ); + +STATIC +EFI_STATUS +MvI2cStart ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINT8 slave, + IN UINTN timeout + ); + +STATIC +EFI_STATUS +MvI2cStop ( + IN I2C_MASTER_CONTEXT *I2cMasterContext + ); + +STATIC +EFI_STATUS +MvI2cRead ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN OUT UINT8 *buf, + IN UINTN len, + IN OUT UINTN *read, + IN UINTN last, + IN UINTN delay + ); + +STATIC +EFI_STATUS +MvI2cWrite ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN OUT CONST UINT8 *buf, + IN UINTN len, + IN OUT UINTN *sent, + IN UINTN timeout + ); + +STATIC +EFI_STATUS +EFIAPI +MvI2cStartRequest ( + IN CONST EFI_I2C_MASTER_PROTOCOL *This, + IN UINTN SlaveAddress, + IN EFI_I2C_REQUEST_PACKET *RequestPacket, + IN EFI_EVENT Event OPTIONAL, + OUT EFI_STATUS *I2cStatus OPTIONAL + ); + +STATIC +EFI_STATUS +EFIAPI +MvI2cEnumerate ( + IN CONST EFI_I2C_ENUMERATE_PROTOCOL *This, + IN OUT CONST EFI_I2C_DEVICE **Device + ); + +STATIC +EFI_STATUS +EFIAPI +MvI2cEnableConf ( + IN CONST EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL *This, + IN UINTN I2cBusConfiguration, + IN EFI_EVENT Event OPTIONAL, + IN EFI_STATUS *I2cStatus OPTIONAL + ); + +#endif // __MV_I2C_H__ diff --git a/Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf b/Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf new file mode 100755 index 0000000000..16374ef5e7 --- /dev/null +++ b/Platform/Marvell/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf @@ -0,0 +1,75 @@ +# +# Marvell BSD License Option +# +# If you received this File from Marvell, you may opt to use, redistribute +# and/or modify this File under the following licensing terms. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Marvell nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = MvI2cDxe + FILE_GUID = 59fc3843-d8d4-40aa-ae07-38967138509b + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = MvI2cInitialise + +[Sources.common] + MvI2cDxe.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + ArmPkg/ArmPkg.dec + Platform/Marvell/Marvell.dec + +[LibraryClasses] + IoLib + PcdLib + BaseLib + DebugLib + UefiLib + UefiDriverEntryPoint + UefiBootServicesTableLib + ParsePcdLib + +[Protocols] + gEfiI2cMasterProtocolGuid + gEfiDevicePathProtocolGuid + gEfiI2cEnumerateProtocolGuid + gEfiI2cBusConfigurationManagementProtocolGuid + +[Pcd] + gMarvellTokenSpaceGuid.PcdI2cSlaveAddresses + gMarvellTokenSpaceGuid.PcdI2cSlaveBuses + gMarvellTokenSpaceGuid.PcdI2cBaseAddresses + gMarvellTokenSpaceGuid.PcdI2cClockFrequency + gMarvellTokenSpaceGuid.PcdI2cBaudRate + gMarvellTokenSpaceGuid.PcdI2cBusCount + +[Depex] + TRUE diff --git a/Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.c b/Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.c new file mode 100644 index 0000000000..ae466d7019 --- /dev/null +++ b/Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.c @@ -0,0 +1,237 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MvMdioDxe.h" + +UINT64 MdioBase = 0; + +STATIC +EFI_STATUS +MdioCheckParam ( + INTN PhyAddr, + INTN RegOff + ) +{ + if (PhyAddr > MVEBU_PHY_ADDR_MASK) { + DEBUG((DEBUG_ERROR, "Invalid PHY address %d\n", PhyAddr)); + return EFI_INVALID_PARAMETER; + } + + if (RegOff > MVEBU_PHY_REG_MASK) { + DEBUG((DEBUG_ERROR, "Invalid register offset %d\n", RegOff)); + return EFI_INVALID_PARAMETER; + } + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +MdioWaitReady ( + VOID + ) +{ + UINT32 Timeout = MVEBU_SMI_TIMEOUT; + UINT32 MdioReg; + + /* wait till the SMI is not busy */ + do { + /* read smi register */ + MdioReg = MmioRead32(MdioBase); + if (Timeout-- == 0) { + DEBUG((DEBUG_ERROR, "SMI busy Timeout\n")); + return EFI_TIMEOUT; + } + } while (MdioReg & MVEBU_SMI_BUSY); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +MdioWaitValid ( + VOID + ) +{ + UINT32 Timeout = MVEBU_SMI_TIMEOUT; + UINT32 MdioReg; + + /* wait till read value is ready */ + do { + /* read smi register */ + MdioReg = MmioRead32 (MdioBase); + if (Timeout-- == 0) { + DEBUG((DEBUG_ERROR, "SMI read ready time-out\n")); + return EFI_TIMEOUT; + } + } while (!(MdioReg & MVEBU_SMI_READ_VALID)); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +MdioOperation ( + IN CONST MARVELL_MDIO_PROTOCOL *This, + IN UINT32 PhyAddr, + IN UINT32 RegOff, + IN BOOLEAN Write, + IN OUT UINT32 *Data + ) +{ + UINT32 MdioReg; + EFI_STATUS Status; + + Status = MdioCheckParam (PhyAddr, RegOff); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "MdioDxe: wrong parameters\n")); + return Status; + } + + /* wait till the SMI is not busy */ + Status = MdioWaitReady (); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "MdioDxe: MdioWaitReady error\n")); + return Status; + } + + /* fill the phy addr and reg offset and write opcode and data */ + MdioReg = (PhyAddr << MVEBU_SMI_DEV_ADDR_OFFS) + | (RegOff << MVEBU_SMI_REG_ADDR_OFFS); + if (Write) { + MdioReg &= ~MVEBU_SMI_OPCODE_READ; + MdioReg |= (*Data << MVEBU_SMI_DATA_OFFS); + } else { + MdioReg |= MVEBU_SMI_OPCODE_READ; + } + + /* write the smi register */ + MdioRegWrite32 (MdioReg, MdioBase); + + /* make sure that the write transaction is over */ + Status = Write ? MdioWaitReady () : MdioWaitValid (); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "MdioDxe: MdioWaitReady error\n")); + return Status; + } + + if (!Write) { + *Data = MmioRead32 (MdioBase) & MVEBU_SMI_DATA_MASK; + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +MvMdioRead ( + IN CONST MARVELL_MDIO_PROTOCOL *This, + IN UINT32 PhyAddr, + IN UINT32 RegOff, + IN UINT32 *Data + ) +{ + EFI_STATUS Status; + + Status = MdioOperation ( + This, + PhyAddr, + RegOff, + FALSE, + Data + ); + + return Status; +} + +EFI_STATUS +MvMdioWrite ( + IN CONST MARVELL_MDIO_PROTOCOL *This, + IN UINT32 PhyAddr, + IN UINT32 RegOff, + IN UINT32 Data + ) +{ + return MdioOperation ( + This, + PhyAddr, + RegOff, + TRUE, + &Data + ); +} + +EFI_STATUS +EFIAPI +MvMdioDxeInitialise ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + MARVELL_MDIO_PROTOCOL *Mdio; + EFI_STATUS Status; + EFI_HANDLE Handle = NULL; + + Mdio = AllocateZeroPool (sizeof (MARVELL_MDIO_PROTOCOL)); + Mdio->Read = MvMdioRead; + Mdio->Write = MvMdioWrite; + MdioBase = PcdGet64 (PcdMdioBaseAddress); + if (MdioBase == 0) { + DEBUG((DEBUG_ERROR, "MdioDxe: PcdMdioBaseAddress not set\n")); + return EFI_INVALID_PARAMETER; + } + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gMarvellMdioProtocolGuid, Mdio, + NULL + ); + + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "Failed to install interfaces\n")); + return Status; + } + + return EFI_SUCCESS; +} diff --git a/Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.h b/Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.h new file mode 100644 index 0000000000..b41a1e6fba --- /dev/null +++ b/Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.h @@ -0,0 +1,57 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __MDIO_DXE_H__ +#define __MDIO_DXE_H__ + +#include + +#define MVEBU_SMI_TIMEOUT 10000 + +/* SMI register fields */ +#define MVEBU_SMI_DATA_OFFS 0 /* Data */ +#define MVEBU_SMI_DATA_MASK (0xffff << MVEBU_SMI_DATA_OFFS) +#define MVEBU_SMI_DEV_ADDR_OFFS 16 /* PHY device address */ +#define MVEBU_SMI_REG_ADDR_OFFS 21 /* PHY device reg addr*/ +#define MVEBU_SMI_OPCODE_OFFS 26 /* Write/Read opcode */ +#define MVEBU_SMI_OPCODE_READ (1 << MVEBU_SMI_OPCODE_OFFS) +#define MVEBU_SMI_READ_VALID (1 << 27) /* Read Valid */ +#define MVEBU_SMI_BUSY (1 << 28) /* Busy */ + +#define MVEBU_PHY_REG_MASK 0x1f +#define MVEBU_PHY_ADDR_MASK 0x1f + +#define MdioRegWrite32(x, y) MmioWrite32((y), (x)) + +#endif // __MDIO_DXE_H__ diff --git a/Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.inf b/Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.inf new file mode 100644 index 0000000000..faab1f70d2 --- /dev/null +++ b/Platform/Marvell/Drivers/Net/MvMdioDxe/MvMdioDxe.inf @@ -0,0 +1,69 @@ +# Copyright (C) 2016 Marvell International Ltd. +# +# Marvell BSD License Option +# +# If you received this File from Marvell, you may opt to use, redistribute and/or +# modify this File under the following licensing terms. +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Marvell nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = MdioDxe + FILE_GUID = 59fc3843-d8d4-40ba-ae07-38967138509c + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = MvMdioDxeInitialise + +[Sources.common] + MvMdioDxe.c + MvMdioDxe.h + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Platform/Marvell/Marvell.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + IoLib + PcdLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + +[Protocols] + gMarvellMdioProtocolGuid + +[Pcd] + gMarvellTokenSpaceGuid.PcdMdioBaseAddress + +[Depex] + TRUE diff --git a/Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.c b/Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.c new file mode 100644 index 0000000000..aeb6f7a01b --- /dev/null +++ b/Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.c @@ -0,0 +1,438 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MvPhyDxe.h" + +#define TIMEOUT 500 + +STATIC MARVELL_MDIO_PROTOCOL *Mdio; + +STATIC MV_PHY_DEVICE MvPhyDevices[] = { + { MV_PHY_DEVICE_1512, MvPhyInit1512 }, + { 0, NULL } +}; + +EFI_STATUS +MvPhyStatus ( + IN CONST MARVELL_PHY_PROTOCOL *This, + IN PHY_DEVICE *PhyDev + ); + +EFI_STATUS +MvPhyReset ( + IN UINT32 PhyAddr + ) +{ + UINT32 Reg = 0; + INTN timeout = TIMEOUT; + + Mdio->Read(Mdio, PhyAddr, MII_BMCR, &Reg); + Reg |= BMCR_RESET; + Mdio->Write(Mdio, PhyAddr, MII_BMCR, Reg); + + while ((Reg & BMCR_RESET) && timeout--) { + Mdio->Read(Mdio, PhyAddr, MII_BMCR, &Reg); + gBS->Stall(1000); + } + + if (Reg & BMCR_RESET) { + DEBUG((DEBUG_ERROR, "PHY reset timed out\n")); + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +/* Marvell 88E1111S */ +EFI_STATUS +MvPhyM88e1111sConfig ( + IN PHY_DEVICE *PhyDev + ) +{ + UINT32 Reg; + + if ((PhyDev->Connection == PHY_CONNECTION_RGMII) || + (PhyDev->Connection == PHY_CONNECTION_RGMII_ID) || + (PhyDev->Connection == PHY_CONNECTION_RGMII_RXID) || + (PhyDev->Connection == PHY_CONNECTION_RGMII_TXID)) { + Mdio->Read(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_CR, &Reg); + + if ((PhyDev->Connection == PHY_CONNECTION_RGMII) || + (PhyDev->Connection == PHY_CONNECTION_RGMII_ID)) { + Reg |= (MIIM_88E1111_RX_DELAY | MIIM_88E1111_TX_DELAY); + } else if (PhyDev->Connection == PHY_CONNECTION_RGMII_RXID) { + Reg &= ~MIIM_88E1111_TX_DELAY; + Reg |= MIIM_88E1111_RX_DELAY; + } else if (PhyDev->Connection == PHY_CONNECTION_RGMII_TXID) { + Reg &= ~MIIM_88E1111_RX_DELAY; + Reg |= MIIM_88E1111_TX_DELAY; + } + + Mdio->Write(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_CR, Reg); + + Mdio->Read(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_SR, &Reg); + + Reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK); + + if (Reg & MIIM_88E1111_HWCFG_FIBER_COPPER_RES) + Reg |= MIIM_88E1111_HWCFG_MODE_FIBER_RGMII; + else + Reg |= MIIM_88E1111_HWCFG_MODE_COPPER_RGMII; + + Mdio->Write(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_SR, Reg); + } + + if (PhyDev->Connection == PHY_CONNECTION_SGMII) { + Mdio->Read(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_SR, &Reg); + + Reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK); + Reg |= MIIM_88E1111_HWCFG_MODE_SGMII_NO_CLK; + Reg |= MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO; + + Mdio->Write(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_SR, Reg); + } + + if (PhyDev->Connection == PHY_CONNECTION_RTBI) { + Mdio->Read(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_CR, &Reg); + Reg |= (MIIM_88E1111_RX_DELAY | MIIM_88E1111_TX_DELAY); + Mdio->Write(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_CR, Reg); + + Mdio->Read(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_SR, &Reg); + Reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK | + MIIM_88E1111_HWCFG_FIBER_COPPER_RES); + Reg |= 0x7 | MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO; + Mdio->Write(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_SR, Reg); + + /* Soft reset */ + MvPhyReset(PhyDev->Addr); + + Mdio->Read(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_SR, &Reg); + Reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK | + MIIM_88E1111_HWCFG_FIBER_COPPER_RES); + Reg |= MIIM_88E1111_HWCFG_MODE_COPPER_RTBI | + MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO; + Mdio->Write(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_SR, Reg); + } + + Mdio->Read(Mdio, PhyDev->Addr, MII_BMCR, &Reg); + Reg |= (BMCR_ANENABLE | BMCR_ANRESTART); + Reg &= ~BMCR_ISOLATE; + Mdio->Write(Mdio, PhyDev->Addr, MII_BMCR, Reg); + + /* Soft reset */ + MvPhyReset(PhyDev->Addr); + + MvPhyReset(PhyDev->Addr); + + return EFI_SUCCESS; +} + +EFI_STATUS +MvPhyParseStatus ( + IN PHY_DEVICE *PhyDev + ) +{ + UINT32 Data; + UINT32 Speed; + + Mdio->Read(Mdio, PhyDev->Addr, MIIM_88E1xxx_PHY_STATUS, &Data); + + if ((Data & MIIM_88E1xxx_PHYSTAT_LINK) && + !(Data & MIIM_88E1xxx_PHYSTAT_SPDDONE)) { + INTN i = 0; + + DEBUG((DEBUG_ERROR,"MvPhyDxe: Waiting for PHY realtime link")); + while (!(Data & MIIM_88E1xxx_PHYSTAT_SPDDONE)) { + if (i > PHY_AUTONEGOTIATE_TIMEOUT) { + DEBUG((DEBUG_ERROR," TIMEOUT !\n")); + PhyDev->LinkUp = FALSE; + break; + } + + if ((i++ % 1000) == 0) + DEBUG((DEBUG_ERROR, ".")); + gBS->Stall(1000); + Mdio->Read(Mdio, PhyDev->Addr, MIIM_88E1xxx_PHY_STATUS, &Data); + } + DEBUG((DEBUG_ERROR," done\n")); + gBS->Stall(500000); + } else { + if (Data & MIIM_88E1xxx_PHYSTAT_LINK) { + DEBUG((DEBUG_ERROR, "MvPhyDxe: link up, ")); + PhyDev->LinkUp = TRUE; + } else { + DEBUG((DEBUG_ERROR, "MvPhyDxe: link down, ")); + PhyDev->LinkUp = FALSE; + } + } + + if (Data & MIIM_88E1xxx_PHYSTAT_DUPLEX) { + DEBUG((DEBUG_ERROR, "full duplex, ")); + PhyDev->FullDuplex = TRUE; + } else { + DEBUG((DEBUG_ERROR, "half duplex, ")); + PhyDev->FullDuplex = FALSE; + } + + Speed = Data & MIIM_88E1xxx_PHYSTAT_SPEED; + + switch (Speed) { + case MIIM_88E1xxx_PHYSTAT_GBIT: + DEBUG((DEBUG_ERROR, "speed 1000\n")); + PhyDev->Speed = SPEED_1000; + break; + case MIIM_88E1xxx_PHYSTAT_100: + DEBUG((DEBUG_ERROR, "speed 100\n")); + PhyDev->Speed = SPEED_100; + break; + default: + DEBUG((DEBUG_ERROR, "speed 10\n")); + PhyDev->Speed = SPEED_10; + break; + } + + return EFI_SUCCESS; +} + +STATIC +VOID +MvPhy1512WriteBits ( + IN UINT32 PhyAddr, + IN UINT8 RegNum, + IN UINT16 Offset, + IN UINT16 Len, + IN UINT16 Data) +{ + UINT32 Reg, Mask; + + if ((Len + Offset) >= 16) + Mask = 0 - (1 << Offset); + else + Mask = (1 << (Len + Offset)) - (1 << Offset); + + Mdio->Read(Mdio, PhyAddr, RegNum, &Reg); + + Reg &= ~Mask; + Reg |= Data << Offset; + + Mdio->Write(Mdio, PhyAddr, RegNum, Reg); +} + +STATIC +EFI_STATUS +MvPhyInit1512 ( + IN CONST MARVELL_PHY_PROTOCOL *Snp, + IN UINT32 PhyAddr, + IN OUT PHY_DEVICE *PhyDev + ) +{ + UINT32 Data; + INTN i; + + if (PhyDev->Connection == PHY_CONNECTION_SGMII) { + /* Select page 0xff and update configuration registers according to + * Marvell Release Notes - Alaska 88E1510/88E1518/88E1512 Rev A0, + * Errata Section 3.1 - needed in SGMII mode. + */ + Mdio->Write(Mdio, PhyAddr, 22, 0x00ff); + Mdio->Write(Mdio, PhyAddr, 17, 0x214B); + Mdio->Write(Mdio, PhyAddr, 16, 0x2144); + Mdio->Write(Mdio, PhyAddr, 17, 0x0C28); + Mdio->Write(Mdio, PhyAddr, 16, 0x2146); + Mdio->Write(Mdio, PhyAddr, 17, 0xB233); + Mdio->Write(Mdio, PhyAddr, 16, 0x214D); + Mdio->Write(Mdio, PhyAddr, 17, 0xCC0C); + Mdio->Write(Mdio, PhyAddr, 16, 0x2159); + + /* Reset page selection and select page 0x12 */ + Mdio->Write(Mdio, PhyAddr, 22, 0x0000); + Mdio->Write(Mdio, PhyAddr, 22, 0x0012); + + /* Write HWCFG_MODE = SGMII to Copper */ + MvPhy1512WriteBits(PhyAddr, 20, 0, 3, 1); + + /* Phy reset - necessary after changing mode */ + MvPhy1512WriteBits(PhyAddr, 20, 15, 1, 1); + + /* Reset page selection */ + Mdio->Write(Mdio, PhyAddr, 22, 0x0000); + gBS->Stall(100); + } + + MvPhyM88e1111sConfig (PhyDev); + + /* autonegotiation on startup is not always required */ + if (!PcdGetBool (PcdPhyStartupAutoneg)) + return EFI_SUCCESS; + + Mdio->Read(Mdio, PhyAddr, MII_BMSR, &Data); + + if ((Data & BMSR_ANEGCAPABLE) && !(Data & BMSR_ANEGCOMPLETE)) { + + DEBUG((DEBUG_ERROR, "MvPhyDxe: Waiting for PHY auto negotiation... ")); + for (i = 0; !(Data & BMSR_ANEGCOMPLETE); i++) { + if (i > PHY_ANEG_TIMEOUT) { + DEBUG((DEBUG_ERROR, "timeout\n")); + PhyDev->LinkUp = FALSE; + return EFI_TIMEOUT; + } + + gBS->Stall(1000); /* 1 ms */ + Mdio->Read(Mdio, PhyAddr, MII_BMSR, &Data); + } + PhyDev->LinkUp = TRUE; + DEBUG((DEBUG_INFO, "MvPhyDxe: link up\n")); + } else { + Mdio->Read(Mdio, PhyAddr, MII_BMSR, &Data); + + if (Data & BMSR_LSTATUS) { + PhyDev->LinkUp = TRUE; + DEBUG((DEBUG_INFO, "MvPhyDxe: link up\n")); + } else { + PhyDev->LinkUp = FALSE; + DEBUG((DEBUG_INFO, "MvPhyDxe: link down\n")); + } + } + MvPhyParseStatus (PhyDev); + + return EFI_SUCCESS; +} + +EFI_STATUS +MvPhyInit ( + IN CONST MARVELL_PHY_PROTOCOL *Snp, + IN UINT32 PhyAddr, + IN PHY_CONNECTION PhyConnection, + IN OUT PHY_DEVICE **OutPhyDev + ) +{ + EFI_STATUS Status; + PHY_DEVICE *PhyDev; + UINT8 *DeviceIds; + INTN i; + + Status = gBS->LocateProtocol ( + &gMarvellMdioProtocolGuid, + NULL, + (VOID **) &Mdio + ); + if (EFI_ERROR(Status)) + return Status; + + /* perform setup common for all PHYs */ + PhyDev = AllocateZeroPool (sizeof (PHY_DEVICE)); + PhyDev->Addr = PhyAddr; + PhyDev->Connection = PhyConnection; + DEBUG((DEBUG_INFO, "MvPhyDxe: PhyAddr is %d, connection %d\n", + PhyAddr, PhyConnection)); + *OutPhyDev = PhyDev; + + DeviceIds = PcdGetPtr (PcdPhyDeviceIds); + for (i = 0; i < PcdGetSize (PcdPhyDeviceIds); i++) { + /* find MvPhyDevices fitting entry */ + if (MvPhyDevices[i].DevId == DeviceIds[i]) { + ASSERT (MvPhyDevices[i].DevInit != NULL); + /* proceed with PHY-specific initialization */ + return MvPhyDevices[i].DevInit(Snp, PhyAddr, PhyDev); + } + } + + /* if we are here, no matching DevId was found */ + Status = EFI_INVALID_PARAMETER; + FreePool (PhyDev); + return Status; +} + +EFI_STATUS +MvPhyStatus ( + IN CONST MARVELL_PHY_PROTOCOL *This, + IN PHY_DEVICE *PhyDev + ) +{ + UINT32 Data; + + Mdio->Read(Mdio, PhyDev->Addr, MII_BMSR, &Data); + Mdio->Read(Mdio, PhyDev->Addr, MII_BMSR, &Data); + + if ((Data & BMSR_LSTATUS) == 0) { + PhyDev->LinkUp = FALSE; + } else { + PhyDev->LinkUp = TRUE; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +MvPhyDxeInitialise ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + MARVELL_PHY_PROTOCOL *Phy; + EFI_STATUS Status; + EFI_HANDLE Handle = NULL; + + Phy = AllocateZeroPool (sizeof (MARVELL_PHY_PROTOCOL)); + Phy->Status = MvPhyStatus; + Phy->Init = MvPhyInit; + + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gMarvellPhyProtocolGuid, Phy, + NULL + ); + + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "Failed to install interfaces\n")); + return Status; + } + DEBUG((DEBUG_ERROR, "Succesfully installed protocol interfaces\n")); + + return EFI_SUCCESS; +} diff --git a/Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.h b/Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.h new file mode 100644 index 0000000000..6bd06c52ed --- /dev/null +++ b/Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.h @@ -0,0 +1,194 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ +#ifndef __MV_PHY_DXE_H__ +#define __MV_PHY_DXE_H__ + +#define MII_BMCR 0x00 /* Basic mode control Register */ +#define MII_BMSR 0x01 /* Basic mode status Register */ +#define MII_PHYSID1 0x02 /* PHYS ID 1 */ +#define MII_PHYSID2 0x03 /* PHYS ID 2 */ +#define MII_ADVERTISE 0x04 /* Advertisement control Reg */ +#define MII_LPA 0x05 /* Link partner ability Reg */ +#define MII_EXPANSION 0x06 /* Expansion Register */ +#define MII_CTRL1000 0x09 /* 1000BASE-T control */ +#define MII_STAT1000 0x0a /* 1000BASE-T status */ +#define MII_ESTATUS 0x0f /* Extended Status */ +#define MII_DCOUNTER 0x12 /* Disconnect counter */ +#define MII_FCSCOUNTER 0x13 /* False carrier counter */ +#define MII_NWAYTEST 0x14 /* N-way auto-neg test Reg */ +#define MII_RERRCOUNTER 0x15 /* Receive error counter */ +#define MII_SREVISION 0x16 /* Silicon revision */ +#define MII_RESV1 0x17 /* Reserved... */ +#define MII_LBRERROR 0x18 /* Lpback, rx, bypass error */ +#define MII_PHYADDR 0x19 /* PHY address */ +#define MII_RESV2 0x1a /* Reserved... */ +#define MII_TPISTATUS 0x1b /* TPI status for 10mbps */ +#define MII_NCONFIG 0x1c /* Network interface config */ + +/* Basic mode control Register. */ +#define BMCR_RESV 0x003f /* Unused... */ +#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */ +#define BMCR_CTST 0x0080 /* Collision test */ +#define BMCR_FULLDPLX 0x0100 /* Full duplex */ +#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */ +#define BMCR_ISOLATE 0x0400 /* Disconnect DP83840 from MII */ +#define BMCR_PDOWN 0x0800 /* Powerdown the DP83840 */ +#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */ +#define BMCR_SPEED100 0x2000 /* Select 100Mbps */ +#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */ +#define BMCR_RESET 0x8000 /* Reset the DP83840 */ + +/* Basic mode status Register. */ +#define BMSR_ERCAP 0x0001 /* Ext-Reg capability */ +#define BMSR_JCD 0x0002 /* Jabber detected */ +#define BMSR_LSTATUS 0x0004 /* Link status */ +#define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */ +#define BMSR_RFAULT 0x0010 /* Remote fault detected */ +#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */ +#define BMSR_RESV 0x00c0 /* Unused... */ +#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */ +#define BMSR_100HALF2 0x0200 /* Can do 100BASE-T2 HDX */ +#define BMSR_100FULL2 0x0400 /* Can do 100BASE-T2 FDX */ +#define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */ +#define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */ +#define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */ +#define BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */ +#define BMSR_100BASE4 0x8000 /* Can do 100mbps, 4k packets */ + +#define PHY_ANEG_TIMEOUT 4000 + +#define PHY_INTERFACE_MODE_RGMII 0 +#define PHY_INTERFACE_MODE_RGMII_ID 1 +#define PHY_INTERFACE_MODE_RGMII_RXID 2 +#define PHY_INTERFACE_MODE_RGMII_TXID 3 +#define PHY_INTERFACE_MODE_SGMII 4 +#define PHY_INTERFACE_MODE_RTBI 5 + +#define PHY_AUTONEGOTIATE_TIMEOUT 5000 + +/* 88E1011 PHY Status Register */ +#define MIIM_88E1xxx_PHY_STATUS 0x11 +#define MIIM_88E1xxx_PHYSTAT_SPEED 0xc000 +#define MIIM_88E1xxx_PHYSTAT_GBIT 0x8000 +#define MIIM_88E1xxx_PHYSTAT_100 0x4000 +#define MIIM_88E1xxx_PHYSTAT_DUPLEX 0x2000 +#define MIIM_88E1xxx_PHYSTAT_SPDDONE 0x0800 +#define MIIM_88E1xxx_PHYSTAT_LINK 0x0400 + +#define MIIM_88E1xxx_PHY_SCR 0x10 +#define MIIM_88E1xxx_PHY_MDI_X_AUTO 0x0060 + +/* 88E1111 PHY LED Control Register */ +#define MIIM_88E1111_PHY_LED_CONTROL 24 +#define MIIM_88E1111_PHY_LED_DIRECT 0x4100 +#define MIIM_88E1111_PHY_LED_COMBINE 0x411C + +/* 88E1111 Extended PHY Specific Control Register */ +#define MIIM_88E1111_PHY_EXT_CR 0x14 +#define MIIM_88E1111_RX_DELAY 0x80 +#define MIIM_88E1111_TX_DELAY 0x2 + +/* 88E1111 Extended PHY Specific Status Register */ +#define MIIM_88E1111_PHY_EXT_SR 0x1b +#define MIIM_88E1111_HWCFG_MODE_MASK 0xf +#define MIIM_88E1111_HWCFG_MODE_COPPER_RGMII 0xb +#define MIIM_88E1111_HWCFG_MODE_FIBER_RGMII 0x3 +#define MIIM_88E1111_HWCFG_MODE_SGMII_NO_CLK 0x4 +#define MIIM_88E1111_HWCFG_MODE_COPPER_RTBI 0x9 +#define MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO 0x8000 +#define MIIM_88E1111_HWCFG_FIBER_COPPER_RES 0x2000 + +#define MIIM_88E1111_COPPER 0 +#define MIIM_88E1111_FIBER 1 + +/* 88E1118 PHY defines */ +#define MIIM_88E1118_PHY_PAGE 22 +#define MIIM_88E1118_PHY_LED_PAGE 3 + +/* 88E1121 PHY LED Control Register */ +#define MIIM_88E1121_PHY_LED_CTRL 16 +#define MIIM_88E1121_PHY_LED_PAGE 3 +#define MIIM_88E1121_PHY_LED_DEF 0x0030 + +/* 88E1121 PHY IRQ Enable/Status Register */ +#define MIIM_88E1121_PHY_IRQ_EN 18 +#define MIIM_88E1121_PHY_IRQ_STATUS 19 + +#define MIIM_88E1121_PHY_PAGE 22 + +/* 88E1145 Extended PHY Specific Control Register */ +#define MIIM_88E1145_PHY_EXT_CR 20 +#define MIIM_M88E1145_RGMII_RX_DELAY 0x0080 +#define MIIM_M88E1145_RGMII_TX_DELAY 0x0002 + +#define MIIM_88E1145_PHY_LED_CONTROL 24 +#define MIIM_88E1145_PHY_LED_DIRECT 0x4100 + +#define MIIM_88E1145_PHY_PAGE 29 +#define MIIM_88E1145_PHY_CAL_OV 30 + +#define MIIM_88E1149_PHY_PAGE 29 + +/* 88E1310 PHY defines */ +#define MIIM_88E1310_PHY_LED_CTRL 16 +#define MIIM_88E1310_PHY_IRQ_EN 18 +#define MIIM_88E1310_PHY_RGMII_CTRL 21 +#define MIIM_88E1310_PHY_PAGE 22 + +typedef enum { + MV_PHY_DEVICE_1512 +} MV_PHY_DEVICE_ID; + +typedef +EFI_STATUS +(*MV_PHY_DEVICE_INIT) ( + IN CONST MARVELL_PHY_PROTOCOL *Snp, + IN UINT32 PhyAddr, + IN OUT PHY_DEVICE *PhyDev + ); + +typedef struct { + MV_PHY_DEVICE_ID DevId; + MV_PHY_DEVICE_INIT DevInit; +} MV_PHY_DEVICE; + +STATIC +EFI_STATUS +MvPhyInit1512 ( + IN CONST MARVELL_PHY_PROTOCOL *Snp, + IN UINT32 PhyAddr, + IN OUT PHY_DEVICE *PhyDev + ); + +#endif diff --git a/Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.inf b/Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.inf new file mode 100644 index 0000000000..c262ce42b5 --- /dev/null +++ b/Platform/Marvell/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.inf @@ -0,0 +1,71 @@ +# Copyright (C) 2016 Marvell International Ltd. +# +# Marvell BSD License Option +# +# If you received this File from Marvell, you may opt to use, redistribute and/or +# modify this File under the following licensing terms. +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Marvell nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = MvPhyDxe + FILE_GUID = 5aac3843-d8d4-40ba-ae07-38967138509c + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = MvPhyDxeInitialise + +[Sources.common] + MvPhyDxe.c + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Platform/Marvell/Marvell.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + IoLib + PcdLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + +[Protocols] + gMarvellMdioProtocolGuid + gMarvellPhyProtocolGuid + +[Pcd] + gMarvellTokenSpaceGuid.PcdPhyConnectionTypes + gMarvellTokenSpaceGuid.PcdPhyDeviceIds + gMarvellTokenSpaceGuid.PcdPhyStartupAutoneg + +[Depex] + TRUE diff --git a/Platform/Marvell/Drivers/Net/Pp2Dxe/Mvpp2Lib.c b/Platform/Marvell/Drivers/Net/Pp2Dxe/Mvpp2Lib.c new file mode 100644 index 0000000000..cdd0979450 --- /dev/null +++ b/Platform/Marvell/Drivers/Net/Pp2Dxe/Mvpp2Lib.c @@ -0,0 +1,4839 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include "Mvpp2Lib.h" +#include "Mvpp2LibHw.h" +#include "Pp2Dxe.h" + +/* Parser configuration routines */ + +/* Update parser Tcam and Sram hw entries */ +STATIC +INT32 +Mvpp2PrsHwWrite ( + IN MVPP2_SHARED *Priv, + IN OUT MVPP2_PRS_ENTRY *Pe + ) +{ + INT32 i; + + if (Pe->Index > MVPP2_PRS_TCAM_SRAM_SIZE - 1) { + return MVPP2_EINVAL; + } + + /* Clear entry invalidation bit */ + Pe->Tcam.Word[MVPP2_PRS_TCAM_INV_WORD] &= ~MVPP2_PRS_TCAM_INV_MASK; + + /* Write Tcam Index - indirect access */ + Mvpp2Write (Priv, MVPP2_PRS_TCAM_IDX_REG, Pe->Index); + for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++) { + Mvpp2Write (Priv, MVPP2_PRS_TCAM_DATA_REG(i), Pe->Tcam.Word[i]); + } + + /* Write Sram Index - indirect access */ + Mvpp2Write (Priv, MVPP2_PRS_SRAM_IDX_REG, Pe->Index); + for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++) { + Mvpp2Write (Priv, MVPP2_PRS_SRAM_DATA_REG(i), Pe->Sram.Word[i]); + } + + return 0; +} + +/* Read Tcam entry from hw */ +STATIC +INT32 +Mvpp2PrsHwRead ( + IN MVPP2_SHARED *Priv, + IN OUT MVPP2_PRS_ENTRY *Pe + ) +{ + INT32 i; + + if (Pe->Index > MVPP2_PRS_TCAM_SRAM_SIZE - 1) { + return MVPP2_EINVAL; + } + + /* Write Tcam Index - indirect access */ + Mvpp2Write (Priv, MVPP2_PRS_TCAM_IDX_REG, Pe->Index); + + Pe->Tcam.Word[MVPP2_PRS_TCAM_INV_WORD] = + Mvpp2Read (Priv, MVPP2_PRS_TCAM_DATA_REG(MVPP2_PRS_TCAM_INV_WORD)); + if (Pe->Tcam.Word[MVPP2_PRS_TCAM_INV_WORD] & MVPP2_PRS_TCAM_INV_MASK) { + return MVPP2_PRS_TCAM_ENTRY_INVALID; + } + + for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++) { + Pe->Tcam.Word[i] = Mvpp2Read (Priv, MVPP2_PRS_TCAM_DATA_REG(i)); + } + + /* Write Sram Index - indirect access */ + Mvpp2Write (Priv, MVPP2_PRS_SRAM_IDX_REG, Pe->Index); + for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++) { + Pe->Sram.Word[i] = Mvpp2Read (Priv, MVPP2_PRS_SRAM_DATA_REG(i)); + } + + return 0; +} + +/* Invalidate Tcam hw entry */ +STATIC +VOID +Mvpp2PrsHwInv ( + IN MVPP2_SHARED *Priv, + IN INT32 Index + ) +{ + /* Write Index - indirect access */ + Mvpp2Write (Priv, MVPP2_PRS_TCAM_IDX_REG, Index); + Mvpp2Write (Priv, MVPP2_PRS_TCAM_DATA_REG(MVPP2_PRS_TCAM_INV_WORD), + MVPP2_PRS_TCAM_INV_MASK); +} + +/* Enable shadow table entry and set its lookup ID */ +STATIC +VOID +Mvpp2PrsShadowSet ( + IN MVPP2_SHARED *Priv, + IN INT32 Index, + IN INT32 Lu + ) +{ + Priv->PrsShadow[Index].Valid = TRUE; + Priv->PrsShadow[Index].Lu = Lu; +} + +/* Update Ri fields in shadow table entry */ +STATIC +VOID +Mvpp2PrsShadowRiSet ( + IN MVPP2_SHARED *Priv, + IN INT32 Index, + IN UINT32 Ri, + IN UINT32 RiMask + ) +{ + Priv->PrsShadow[Index].RiMask = RiMask; + Priv->PrsShadow[Index].Ri = Ri; +} + +/* Update lookup field in Tcam sw entry */ +STATIC +VOID +Mvpp2PrsTcamLuSet ( + IN OUT MVPP2_PRS_ENTRY *Pe, + IN UINT32 Lu + ) +{ + INT32 EnableOff = MVPP2_PRS_TCAM_EN_OFFS (MVPP2_PRS_TCAM_LU_BYTE); + + Pe->Tcam.Byte[MVPP2_PRS_TCAM_LU_BYTE] = Lu; + Pe->Tcam.Byte[EnableOff] = MVPP2_PRS_LU_MASK; +} + +/* Update Mask for single Port in Tcam sw entry */ +STATIC +VOID +Mvpp2PrsTcamPortSet ( + IN OUT MVPP2_PRS_ENTRY *Pe, + IN UINT32 PortId, + IN BOOLEAN Add + ) +{ + INT32 EnableOff = MVPP2_PRS_TCAM_EN_OFFS (MVPP2_PRS_TCAM_PORT_BYTE); + + if (Add) { + Pe->Tcam.Byte[EnableOff] &= ~(1 << PortId); + } else { + Pe->Tcam.Byte[EnableOff] |= 1 << PortId; + } +} + +/* Update Port map in Tcam sw entry */ +STATIC +VOID +Mvpp2PrsTcamPortMapSet ( + IN OUT MVPP2_PRS_ENTRY *Pe, + IN UINT32 PortMask + ) +{ + INT32 EnableOff = MVPP2_PRS_TCAM_EN_OFFS (MVPP2_PRS_TCAM_PORT_BYTE); + UINT8 Mask = MVPP2_PRS_PORT_MASK; + + Pe->Tcam.Byte[MVPP2_PRS_TCAM_PORT_BYTE] = 0; + Pe->Tcam.Byte[EnableOff] &= ~Mask; + Pe->Tcam.Byte[EnableOff] |= ~PortMask & MVPP2_PRS_PORT_MASK; +} + +/* Obtain Port map from Tcam sw entry */ +STATIC +UINT32 +Mvpp2PrsTcamPortMapGet ( + IN MVPP2_PRS_ENTRY *Pe + ) +{ + INT32 EnableOff = MVPP2_PRS_TCAM_EN_OFFS (MVPP2_PRS_TCAM_PORT_BYTE); + + return ~(Pe->Tcam.Byte[EnableOff]) & MVPP2_PRS_PORT_MASK; +} + +/* Set Byte of data and its enable bits in Tcam sw entry */ +STATIC +VOID +Mvpp2PrsTcamDataByteSet ( + IN OUT MVPP2_PRS_ENTRY *Pe, + IN UINT32 Offs, + IN UINT8 Byte, + IN UINT8 Enable + ) +{ + Pe->Tcam.Byte[MVPP2_PRS_TCAM_DATA_BYTE(Offs)] = Byte; + Pe->Tcam.Byte[MVPP2_PRS_TCAM_DATA_BYTE_EN(Offs)] = Enable; +} + +/* Get Byte of data and its enable bits from Tcam sw entry */ +STATIC +VOID +Mvpp2PrsTcamDataByteGet ( + IN MVPP2_PRS_ENTRY *Pe, + IN UINT32 Offs, + OUT UINT8 *Byte, + OUT UINT8 *Enable + ) +{ + *Byte = Pe->Tcam.Byte[MVPP2_PRS_TCAM_DATA_BYTE(Offs)]; + *Enable = Pe->Tcam.Byte[MVPP2_PRS_TCAM_DATA_BYTE_EN(Offs)]; +} + +/* Compare Tcam data bytes with a pattern */ +STATIC +BOOLEAN +Mvpp2PrsTcamDataCmp ( + IN MVPP2_PRS_ENTRY *Pe, + IN INT32 Offset, + IN UINT16 Data + ) +{ + INT32 ByteOffset = MVPP2_PRS_TCAM_DATA_BYTE(Offset); + UINT16 TcamData; + + TcamData = (Pe->Tcam.Byte[ByteOffset + 1] << 8) | Pe->Tcam.Byte[ByteOffset]; + if (TcamData != Data) { + return FALSE; + } + + return TRUE; +} + +/* Update ai bits in Tcam sw entry */ +STATIC +VOID +Mvpp2PrsTcamAiUpdate ( + IN OUT MVPP2_PRS_ENTRY *Pe, + IN UINT32 Bits, + IN UINT32 Enable + ) +{ + INT32 i, AiIdx = MVPP2_PRS_TCAM_AI_BYTE; + + for (i = 0; i < MVPP2_PRS_AI_BITS; i++) { + + if (!(Enable & BIT (i))) { + continue; + } + + if (Bits & BIT (i)) { + Pe->Tcam.Byte[AiIdx] |= 1 << i; + } else { + Pe->Tcam.Byte[AiIdx] &= ~(1 << i); + } + } + + Pe->Tcam.Byte[MVPP2_PRS_TCAM_EN_OFFS (AiIdx)] |= Enable; +} + +/* Get ai bits from Tcam sw entry */ +STATIC +INT32 +Mvpp2PrsTcamAiGet ( + IN MVPP2_PRS_ENTRY *Pe + ) +{ + return Pe->Tcam.Byte[MVPP2_PRS_TCAM_AI_BYTE]; +} + +/* Get word of data and its enable bits from Tcam sw entry */ +STATIC +VOID +Mvpp2PrsTcamDataWordGet ( + IN MVPP2_PRS_ENTRY *Pe, + IN UINT32 DataOffset, + OUT UINT32 *Word, + OUT UINT32 *Enable + ) +{ + INT32 Index, Position; + UINT8 Byte, Mask; + + for (Index = 0; Index < 4; Index++) { + Position = (DataOffset * sizeof (INT32)) + Index; + Mvpp2PrsTcamDataByteGet (Pe, Position, &Byte, &Mask); + ((UINT8 *)Word)[Index] = Byte; + ((UINT8 *)Enable)[Index] = Mask; + } +} + +/* Set ethertype in Tcam sw entry */ +STATIC +VOID +Mvpp2PrsMatchEtype ( + IN OUT MVPP2_PRS_ENTRY *Pe, + IN INT32 Offset, + IN UINT16 EtherType + ) +{ + Mvpp2PrsTcamDataByteSet (Pe, Offset + 0, EtherType >> 8, 0xff); + Mvpp2PrsTcamDataByteSet (Pe, Offset + 1, EtherType & 0xff, 0xff); +} + +/* Set bits in Sram sw entry */ +STATIC +VOID +Mvpp2PrsSramBitsSet ( + IN OUT MVPP2_PRS_ENTRY *Pe, + IN INT32 BitNum, + IN INT32 Val + ) +{ + Pe->Sram.Byte[MVPP2_BIT_TO_BYTE(BitNum)] |= (Val << (BitNum % 8)); +} + +/* Clear bits in Sram sw entry */ +STATIC +VOID +Mvpp2PrsSramBitsClear ( + IN OUT MVPP2_PRS_ENTRY *Pe, + IN INT32 BitNum, + IN INT32 Val + ) +{ + Pe->Sram.Byte[MVPP2_BIT_TO_BYTE(BitNum)] &= ~(Val << (BitNum % 8)); +} + +/* Update Ri bits in Sram sw entry */ +STATIC +VOID +Mvpp2PrsSramRiUpdate ( + IN OUT MVPP2_PRS_ENTRY *Pe, + IN UINT32 bits, + IN UINT32 Mask + ) +{ + UINT32 i; + + for (i = 0; i < MVPP2_PRS_SRAM_RI_CTRL_BITS; i++) { + INT32 RiOff = MVPP2_PRS_SRAM_RI_OFFS; + + if (!(Mask & BIT (i))) { + continue; + } + + if (bits & BIT (i)) { + Mvpp2PrsSramBitsSet (Pe, RiOff + i, 1); + } else { + Mvpp2PrsSramBitsClear (Pe, RiOff + i, 1); + } + + Mvpp2PrsSramBitsSet (Pe, MVPP2_PRS_SRAM_RI_CTRL_OFFS + i, 1); + } +} + +/* Obtain Ri bits from Sram sw entry */ +STATIC +INT32 +Mvpp2PrsSramRiGet ( + IN MVPP2_PRS_ENTRY *Pe + ) +{ + return Pe->Sram.Word[MVPP2_PRS_SRAM_RI_WORD]; +} + +/* Update ai bits in Sram sw entry */ +STATIC +VOID +Mvpp2PrsSramAiUpdate ( + IN OUT MVPP2_PRS_ENTRY *Pe, + IN UINT32 Bits, + UINT32 Mask + ) +{ + UINT32 i; + INT32 AiOff = MVPP2_PRS_SRAM_AI_OFFS; + + for (i = 0; i < MVPP2_PRS_SRAM_AI_CTRL_BITS; i++) { + + if (!(Mask & BIT (i))) { + continue; + } + + if (Bits & BIT (i)) { + Mvpp2PrsSramBitsSet (Pe, AiOff + i, 1); + } else { + Mvpp2PrsSramBitsClear (Pe, AiOff + i, 1); + } + + Mvpp2PrsSramBitsSet (Pe, MVPP2_PRS_SRAM_AI_CTRL_OFFS + i, 1); + } +} + +/* Read ai bits from Sram sw entry */ +STATIC +INT32 +Mvpp2PrsSramAiGet ( + IN MVPP2_PRS_ENTRY *Pe + ) +{ + UINT8 bits; + INT32 AiOff = MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_AI_OFFS); + INT32 AiEnOff = AiOff + 1; + INT32 AiShift = MVPP2_PRS_SRAM_AI_OFFS % 8; + + bits = (Pe->Sram.Byte[AiOff] >> AiShift) | + (Pe->Sram.Byte[AiEnOff] << (8 - AiShift)); + + return bits; +} + +/* + * In Sram sw entry set lookup ID field of the + * Tcam key to be used in the next lookup iteration + */ +STATIC +VOID +Mvpp2PrsSramNextLuSet ( + IN OUT MVPP2_PRS_ENTRY *Pe, + IN UINT32 Lu + ) +{ + INT32 SramNextOff = MVPP2_PRS_SRAM_NEXT_LU_OFFS; + + Mvpp2PrsSramBitsClear (Pe, SramNextOff, MVPP2_PRS_SRAM_NEXT_LU_MASK); + Mvpp2PrsSramBitsSet (Pe, SramNextOff, Lu); +} + +/* + * In the Sram sw entry set sign and value of the next lookup Offset + * and the Offset value generated to the classifier + */ +STATIC +VOID +Mvpp2PrsSramShiftSet ( + IN OUT MVPP2_PRS_ENTRY *Pe, + IN INT32 Shift, + IN UINT32 Op + ) +{ + /* Set sign */ + if (Shift < 0) { + Mvpp2PrsSramBitsSet (Pe, MVPP2_PRS_SRAM_SHIFT_SIGN_BIT, 1); + Shift = -Shift; + } else { + Mvpp2PrsSramBitsClear (Pe, MVPP2_PRS_SRAM_SHIFT_SIGN_BIT, 1); + } + + /* Set value */ + Pe->Sram.Byte[MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_SHIFT_OFFS)] = (UINT8)Shift; + + /* Reset and set operation */ + Mvpp2PrsSramBitsClear (Pe, MVPP2_PRS_SRAM_OP_SEL_SHIFT_OFFS, MVPP2_PRS_SRAM_OP_SEL_SHIFT_MASK); + Mvpp2PrsSramBitsSet (Pe, MVPP2_PRS_SRAM_OP_SEL_SHIFT_OFFS, Op); + + /* Set base Offset as current */ + Mvpp2PrsSramBitsClear (Pe, MVPP2_PRS_SRAM_OP_SEL_BASE_OFFS, 1); +} + +/* + * In the Sram sw entry set sign and value of the user defined offset + * generated for the classifier + */ +STATIC +VOID +Mvpp2PrsSramOffsetSet ( + IN OUT MVPP2_PRS_ENTRY *Pe, + IN UINT32 Type, + IN INT32 Offset, + IN UINT32 Op + ) +{ + UINT8 UdfByte = MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_UDF_OFFS + MVPP2_PRS_SRAM_UDF_BITS); + UINT8 UdfByteOffset = (8 - (MVPP2_PRS_SRAM_UDF_OFFS % 8)); + UINT8 OpSelUdfByte = MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS + MVPP2_PRS_SRAM_OP_SEL_UDF_BITS); + UINT8 OpSelUdfByteOffset = (8 - (MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS % 8)); + + /* Set sign */ + if (Offset < 0) { + Mvpp2PrsSramBitsSet (Pe, MVPP2_PRS_SRAM_UDF_SIGN_BIT, 1); + Offset = -Offset; + } else { + Mvpp2PrsSramBitsClear (Pe, MVPP2_PRS_SRAM_UDF_SIGN_BIT, 1); + } + + /* Set value */ + Mvpp2PrsSramBitsClear (Pe, MVPP2_PRS_SRAM_UDF_OFFS, MVPP2_PRS_SRAM_UDF_MASK); + Mvpp2PrsSramBitsSet (Pe, MVPP2_PRS_SRAM_UDF_OFFS, Offset); + + Pe->Sram.Byte[UdfByte] &= ~(MVPP2_PRS_SRAM_UDF_MASK >> UdfByteOffset); + Pe->Sram.Byte[UdfByte] |= (Offset >> UdfByteOffset); + + /* Set Offset Type */ + Mvpp2PrsSramBitsClear (Pe, MVPP2_PRS_SRAM_UDF_TYPE_OFFS, MVPP2_PRS_SRAM_UDF_TYPE_MASK); + Mvpp2PrsSramBitsSet (Pe, MVPP2_PRS_SRAM_UDF_TYPE_OFFS, Type); + + /* Set Offset operation */ + Mvpp2PrsSramBitsClear (Pe, MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS, MVPP2_PRS_SRAM_OP_SEL_UDF_MASK); + Mvpp2PrsSramBitsSet (Pe, MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS, Op); + + Pe->Sram.Byte[OpSelUdfByte] &= ~(MVPP2_PRS_SRAM_OP_SEL_UDF_MASK >> OpSelUdfByteOffset); + Pe->Sram.Byte[OpSelUdfByte] |= (Op >> OpSelUdfByteOffset); + + /* Set base Offset as current */ + Mvpp2PrsSramBitsClear (Pe, MVPP2_PRS_SRAM_OP_SEL_BASE_OFFS, 1); +} + +/* Find parser Flow entry */ +STATIC +MVPP2_PRS_ENTRY * +Mvpp2PrsFlowFind ( + IN MVPP2_SHARED *Priv, + IN INT32 Flow + ) +{ + MVPP2_PRS_ENTRY *Pe; + INT32 Tid; + UINT32 Word, Enable; + + Pe = Mvpp2Alloc (sizeof (*Pe)); + if (Pe == NULL) { + return NULL; + } + + Mvpp2PrsTcamLuSet (Pe, MVPP2_PRS_LU_FLOWS); + + /* Go through the all entires with MVPP2_PRS_LU_FLOWS */ + for (Tid = MVPP2_PRS_TCAM_SRAM_SIZE - 1; Tid >= 0; Tid--) { + UINT8 Bits; + + if (!Priv->PrsShadow[Tid].Valid || Priv->PrsShadow[Tid].Lu != MVPP2_PRS_LU_FLOWS) { + continue; + } + + Pe->Index = Tid; + Mvpp2PrsHwRead (Priv, Pe); + + /* + * Check result info, because there maybe + * several TCAM lines to generate the same Flow + */ + Mvpp2PrsTcamDataWordGet (Pe, 0, &Word, &Enable); + if ((Word != 0) || (Enable != 0)) { + continue; + } + + Bits = Mvpp2PrsSramAiGet (Pe); + + /* Sram store classification lookup ID in AI Bits [5:0] */ + if ((Bits & MVPP2_PRS_FLOW_ID_MASK) == Flow) { + return Pe; + } + } + + Mvpp2Free (Pe); + + return NULL; +} + +/* Return first free Tcam Index, seeking from start to end */ +STATIC +INT32 +Mvpp2PrsTcamFirstFree ( + IN MVPP2_SHARED *Priv, + IN UINT8 Start, + IN UINT8 End + ) +{ + INT32 Tid; + + if (Start > End) { + Mvpp2SwapVariables (Start, End); + } + + if (End >= MVPP2_PRS_TCAM_SRAM_SIZE) { + End = MVPP2_PRS_TCAM_SRAM_SIZE - 1; + } + + for (Tid = Start; Tid <= End; Tid++) { + if (!Priv->PrsShadow[Tid].Valid) { + return Tid; + } + } + + return MVPP2_EINVAL; +} + +/* Enable/disable dropping all mac Da's */ +STATIC +VOID +Mvpp2PrsMacDropAllSet ( + IN MVPP2_SHARED *Priv, + IN INT32 PortId, + IN BOOLEAN Add + ) +{ + MVPP2_PRS_ENTRY Pe; + + if (Priv->PrsShadow[MVPP2_PE_DROP_ALL].Valid) { + /* Entry exist - update PortId only */ + Pe.Index = MVPP2_PE_DROP_ALL; + Mvpp2PrsHwRead (Priv, &Pe); + } else { + /* Entry doesn't exist - create new */ + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_MAC); + Pe.Index = MVPP2_PE_DROP_ALL; + + /* Non-promiscuous mode for all Ports - DROP unknown packets */ + Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_DROP_MASK, MVPP2_PRS_RI_DROP_MASK); + + Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1); + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS); + + /* Update shadow table */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_MAC); + + /* Mask all Ports */ + Mvpp2PrsTcamPortMapSet (&Pe, 0); + } + + /* Update PortId Mask */ + Mvpp2PrsTcamPortSet (&Pe, PortId, Add); + + Mvpp2PrsHwWrite (Priv, &Pe); +} + +/* Set port to promiscuous mode */ +VOID +Mvpp2PrsMacPromiscSet ( + IN MVPP2_SHARED *Priv, + IN INT32 PortId, + IN BOOLEAN Add + ) +{ + MVPP2_PRS_ENTRY Pe; + + /* Promiscuous mode - Accept unknown packets */ + + if (Priv->PrsShadow[MVPP2_PE_MAC_PROMISCUOUS].Valid) { + /* Entry exist - update port only */ + Pe.Index = MVPP2_PE_MAC_PROMISCUOUS; + Mvpp2PrsHwRead (Priv, &Pe); + } else { + /* Entry doesn't exist - create new */ + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_MAC); + Pe.Index = MVPP2_PE_MAC_PROMISCUOUS; + + /* Continue - set next lookup */ + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_DSA); + + /* Set result info bits */ + Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L2_UCAST, MVPP2_PRS_RI_L2_CAST_MASK); + + /* Shift to ethertype with 2 of MAC Address length */ + Mvpp2PrsSramShiftSet (&Pe, 2 * MV_ETH_ALEN, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + + /* Mask all Ports */ + Mvpp2PrsTcamPortMapSet (&Pe, 0); + + /* Update shadow table */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_MAC); + } + + /* Update port Mask */ + Mvpp2PrsTcamPortSet (&Pe, PortId, Add); + + Mvpp2PrsHwWrite (Priv, &Pe); +} + +/* Accept multicast */ +VOID +Mvpp2PrsMacMultiSet ( + IN MVPP2_SHARED *Priv, + IN INT32 PortId, + IN INT32 Index, + IN BOOLEAN Add + ) +{ + MVPP2_PRS_ENTRY Pe; + UINT8 DaMc; + + /* + * Ethernet multicast Address first Byte is + * 0x01 for IPv4 and 0x33 for IPv6 + */ + DaMc = (Index == MVPP2_PE_MAC_MC_ALL) ? 0x01 : 0x33; + + if (Priv->PrsShadow[Index].Valid) { + /* Entry exist - update port only */ + Pe.Index = Index; + Mvpp2PrsHwRead (Priv, &Pe); + } else { + /* Entry doesn't exist - create new */ + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_MAC); + Pe.Index = Index; + + /* Continue - set next lookup */ + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_DSA); + + /* Set result info bits */ + Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L2_MCAST, MVPP2_PRS_RI_L2_CAST_MASK); + + /* Update Tcam entry data first Byte */ + Mvpp2PrsTcamDataByteSet (&Pe, 0, DaMc, 0xff); + + /* Shift to ethertype */ + Mvpp2PrsSramShiftSet (&Pe, 2 * MV_ETH_ALEN, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + + /* Mask all ports */ + Mvpp2PrsTcamPortMapSet (&Pe, 0); + + /* Update shadow table */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_MAC); + } + + /* Update port Mask */ + Mvpp2PrsTcamPortSet (&Pe, PortId, Add); + + Mvpp2PrsHwWrite (Priv, &Pe); +} + +/* Set entry for dsa packets */ +STATIC +VOID +Mvpp2PrsDsaTagSet ( + IN MVPP2_SHARED *Priv, + IN INT32 PortId, + IN BOOLEAN Add, + IN BOOLEAN Tagged, + IN BOOLEAN Extend + ) +{ + MVPP2_PRS_ENTRY Pe; + INT32 Tid, Shift; + + if (Extend) { + Tid = Tagged ? MVPP2_PE_EDSA_TAGGED : MVPP2_PE_EDSA_UNTAGGED; + Shift = 8; + } else { + Tid = Tagged ? MVPP2_PE_DSA_TAGGED : MVPP2_PE_DSA_UNTAGGED; + Shift = 4; + } + + if (Priv->PrsShadow[Tid].Valid) { + /* Entry exist - update port only */ + Pe.Index = Tid; + Mvpp2PrsHwRead (Priv, &Pe); + } else { + /* Entry doesn't exist - create new */ + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_DSA); + Pe.Index = Tid; + + /* Shift 4 bytes if DSA tag or 8 bytes in case of EDSA tag*/ + Mvpp2PrsSramShiftSet (&Pe, Shift, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + + /* Update shadow table */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_DSA); + + if (Tagged) { + /* Set Tagged bit in DSA tag */ + Mvpp2PrsTcamDataByteSet (&Pe, 0, MVPP2_PRS_TCAM_DSA_TAGGED_BIT, MVPP2_PRS_TCAM_DSA_TAGGED_BIT); + + /* Clear all ai bits for next iteration */ + Mvpp2PrsSramAiUpdate (&Pe, 0, MVPP2_PRS_SRAM_AI_MASK); + + /* If packet is Tagged continue check vlans */ + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_VLAN); + } else { + /* Set result info bits to 'no vlans' */ + Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_VLAN_NONE, MVPP2_PRS_RI_VLAN_MASK); + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_L2); + } + + /* Mask all Ports */ + Mvpp2PrsTcamPortMapSet (&Pe, 0); + } + + /* Update port Mask */ + Mvpp2PrsTcamPortSet (&Pe, PortId, Add); + + Mvpp2PrsHwWrite (Priv, &Pe); +} + +/* Set entry for dsa ethertype */ +STATIC +VOID +Mvpp2PrsDsaTagEthertypeSet ( + IN MVPP2_SHARED *Priv, + IN INT32 PortId, + IN BOOLEAN Add, + IN BOOLEAN Tagged, + IN BOOLEAN Extend + ) +{ + MVPP2_PRS_ENTRY Pe; + INT32 Tid, Shift, PortMask; + + if (Extend) { + Tid = Tagged ? MVPP2_PE_ETYPE_EDSA_TAGGED : MVPP2_PE_ETYPE_EDSA_UNTAGGED; + PortMask = 0; + Shift = 8; + } else { + Tid = Tagged ? MVPP2_PE_ETYPE_DSA_TAGGED : MVPP2_PE_ETYPE_DSA_UNTAGGED; + PortMask = MVPP2_PRS_PORT_MASK; + Shift = 4; + } + + if (Priv->PrsShadow[Tid].Valid) { + /* Entry exist - update PortId only */ + Pe.Index = Tid; + Mvpp2PrsHwRead (Priv, &Pe); + } else { + /* Entry doesn't exist - create new */ + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_DSA); + Pe.Index = Tid; + + /* + * Set ethertype at offset 0 for DSA and + * clear it at offset 2 - obtained from Marvell. + */ + Mvpp2PrsMatchEtype (&Pe, 0, MV_ETH_P_EDSA); + Mvpp2PrsMatchEtype (&Pe, 2, 0); + + Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_DSA_MASK, + MVPP2_PRS_RI_DSA_MASK); + + /* Shift ethertype + 2 Byte reserved + tag */ + Mvpp2PrsSramShiftSet (&Pe, 2 + MVPP2_ETH_TYPE_LEN + Shift, + MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + + /* Update shadow table */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_DSA); + + if (Tagged) { + /* Set Tagged bit in DSA tag */ + Mvpp2PrsTcamDataByteSet ( + &Pe, + MVPP2_ETH_TYPE_LEN + 2 + 3, + MVPP2_PRS_TCAM_DSA_TAGGED_BIT, + MVPP2_PRS_TCAM_DSA_TAGGED_BIT + ); + + /* Clear all ai bits for next iteration */ + Mvpp2PrsSramAiUpdate (&Pe, 0, MVPP2_PRS_SRAM_AI_MASK); + + /* If packet is Tagged continue check vlans */ + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_VLAN); + } else { + /* Set result info bits to 'no vlans' */ + Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_VLAN_NONE, MVPP2_PRS_RI_VLAN_MASK); + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_L2); + } + + /* Mask/unmask all ports, depending on dsa type */ + Mvpp2PrsTcamPortMapSet (&Pe, PortMask); + } + + /* Update port Mask */ + Mvpp2PrsTcamPortSet (&Pe, PortId, Add); + + Mvpp2PrsHwWrite (Priv, &Pe); +} + +/* Search for existing single/triple vlan entry */ +STATIC +MVPP2_PRS_ENTRY * +Mvpp2PrsVlanFind ( + IN MVPP2_SHARED *Priv, + IN UINT16 Tpid, + IN INT32 Ai + ) +{ + MVPP2_PRS_ENTRY *Pe; + INT32 Tid; + + Pe = Mvpp2Alloc (sizeof (*Pe)); + if (Pe == NULL) { + return NULL; + } + + Mvpp2PrsTcamLuSet (Pe, MVPP2_PRS_LU_VLAN); + + /* Go through the all entries with MVPP2_PRS_LU_VLAN */ + for (Tid = MVPP2_PE_FIRST_FREE_TID; Tid <= MVPP2_PE_LAST_FREE_TID; Tid++) { + UINT32 RiBits, AiBits; + BOOLEAN match; + + if (!Priv->PrsShadow[Tid].Valid || Priv->PrsShadow[Tid].Lu != MVPP2_PRS_LU_VLAN) { + continue; + } + + Pe->Index = Tid; + + Mvpp2PrsHwRead (Priv, Pe); + match = Mvpp2PrsTcamDataCmp (Pe, 0, Mvpp2SwapBytes16 (Tpid)); + if (!match) { + continue; + } + + /* Get vlan type */ + RiBits = Mvpp2PrsSramRiGet (Pe); + RiBits &= MVPP2_PRS_RI_VLAN_MASK; + + /* Get current Ai value from Tcam */ + AiBits = Mvpp2PrsTcamAiGet (Pe); + + /* Clear double vlan bit */ + AiBits &= ~MVPP2_PRS_DBL_VLAN_AI_BIT; + + if (Ai != AiBits) { + continue; + } + + if (RiBits == MVPP2_PRS_RI_VLAN_SINGLE || RiBits == MVPP2_PRS_RI_VLAN_TRIPLE) { + return Pe; + } + } + + Mvpp2Free (Pe); + + return NULL; +} + +/* Add/update single/triple vlan entry */ +INT32 +Mvpp2PrsVlanAdd ( + IN MVPP2_SHARED *Priv, + IN UINT16 Tpid, + IN INT32 Ai, + IN UINT32 PortMap + ) +{ + MVPP2_PRS_ENTRY *Pe; + INT32 TidAux, Tid; + INT32 Ret = 0; + + Pe = Mvpp2PrsVlanFind (Priv, Tpid, Ai); + + if (!Pe) { + /* Create new Tcam entry */ + Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_LAST_FREE_TID, MVPP2_PE_FIRST_FREE_TID); + if (Tid < 0) { + return Tid; + } + + Pe = Mvpp2Alloc (sizeof (*Pe)); + if (Pe == NULL) { + return MVPP2_ENOMEM; + } + + /* Get last double vlan Tid */ + for (TidAux = MVPP2_PE_LAST_FREE_TID; TidAux >= MVPP2_PE_FIRST_FREE_TID; TidAux--) { + UINT32 RiBits; + + if (!Priv->PrsShadow[TidAux].Valid || Priv->PrsShadow[TidAux].Lu != MVPP2_PRS_LU_VLAN) { + continue; + } + + Pe->Index = TidAux; + Mvpp2PrsHwRead (Priv, Pe); + RiBits = Mvpp2PrsSramRiGet (Pe); + if ((RiBits & MVPP2_PRS_RI_VLAN_MASK) == MVPP2_PRS_RI_VLAN_DOUBLE) { + break; + } + } + + if (Tid <= TidAux) { + Ret = MVPP2_EINVAL; + goto error; + } + + Mvpp2Memset (Pe, 0 , sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (Pe, MVPP2_PRS_LU_VLAN); + Pe->Index = Tid; + + /* Set VLAN type's offset to 0 bytes - obtained from Marvell */ + Mvpp2PrsMatchEtype (Pe, 0, Tpid); + + Mvpp2PrsSramNextLuSet (Pe, MVPP2_PRS_LU_L2); + + /* Shift 4 bytes - skip 1 vlan tag */ + Mvpp2PrsSramShiftSet (Pe, MVPP2_VLAN_TAG_LEN, + MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + + /* Clear all Ai bits for next iteration */ + Mvpp2PrsSramAiUpdate (Pe, 0, MVPP2_PRS_SRAM_AI_MASK); + + if (Ai == MVPP2_PRS_SINGLE_VLAN_AI) { + Mvpp2PrsSramRiUpdate (Pe, MVPP2_PRS_RI_VLAN_SINGLE, MVPP2_PRS_RI_VLAN_MASK); + } else { + Ai |= MVPP2_PRS_DBL_VLAN_AI_BIT; + Mvpp2PrsSramRiUpdate (Pe, MVPP2_PRS_RI_VLAN_TRIPLE, MVPP2_PRS_RI_VLAN_MASK); + } + + Mvpp2PrsTcamAiUpdate (Pe, Ai, MVPP2_PRS_SRAM_AI_MASK); + + Mvpp2PrsShadowSet (Priv, Pe->Index, MVPP2_PRS_LU_VLAN); + } + + /* Update Ports' Mask */ + Mvpp2PrsTcamPortMapSet (Pe, PortMap); + Mvpp2PrsHwWrite (Priv, Pe); + +error: + Mvpp2Free (Pe); + + return Ret; +} + +/* Get first free double vlan ai number */ +INT32 +Mvpp2PrsDoubleVlanAiFreeGet ( + IN MVPP2_SHARED *Priv + ) +{ + INT32 i; + + for (i = 1; i < MVPP2_PRS_DBL_VLANS_MAX; i++) { + if (!Priv->PrsDoubleVlans[i]) { + return i; + } + } + + return MVPP2_EINVAL; +} + +/* Search for existing double vlan entry */ +MVPP2_PRS_ENTRY *Mvpp2PrsDoubleVlanFind ( + IN MVPP2_SHARED *Priv, + IN UINT16 Tpid1, + IN UINT16 Tpid2 + ) +{ + MVPP2_PRS_ENTRY *Pe; + INT32 Tid; + + Pe = Mvpp2Alloc (sizeof (*Pe)); + if (Pe == NULL) { + return NULL; + } + + Mvpp2PrsTcamLuSet (Pe, MVPP2_PRS_LU_VLAN); + + /* Go through the all entries with MVPP2_PRS_LU_VLAN */ + for (Tid = MVPP2_PE_FIRST_FREE_TID; Tid <= MVPP2_PE_LAST_FREE_TID; Tid++) { + UINT32 RiMask; + BOOLEAN match; + + if (!Priv->PrsShadow[Tid].Valid || Priv->PrsShadow[Tid].Lu != MVPP2_PRS_LU_VLAN) { + continue; + } + + Pe->Index = Tid; + Mvpp2PrsHwRead (Priv, Pe); + + match = Mvpp2PrsTcamDataCmp (Pe, 0, Mvpp2SwapBytes16 (Tpid1)) && + Mvpp2PrsTcamDataCmp (Pe, 4, Mvpp2SwapBytes16 (Tpid2)); + + if (!match) { + continue; + } + + RiMask = Mvpp2PrsSramRiGet (Pe) & MVPP2_PRS_RI_VLAN_MASK; + if (RiMask == MVPP2_PRS_RI_VLAN_DOUBLE) { + return Pe; + } + } + + Mvpp2Free (Pe); + + return NULL; +} + +/* Add or update double vlan entry */ +INT32 +Mvpp2PrsDoubleVlanAdd ( + IN MVPP2_SHARED *Priv, + IN UINT16 Tpid1, + IN UINT16 Tpid2, + IN UINT32 PortMap + ) +{ + MVPP2_PRS_ENTRY *Pe; + INT32 TidAux, Tid, Ai, Ret = 0; + + Pe = Mvpp2PrsDoubleVlanFind (Priv, Tpid1, Tpid2); + + if (!Pe) { + /* Create new Tcam entry */ + Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID); + if (Tid < 0) { + return Tid; + } + + Pe = Mvpp2Alloc (sizeof (*Pe)); + if (Pe == NULL) { + return MVPP2_ENOMEM; + } + + /* Set Ai value for new double vlan entry */ + Ai = Mvpp2PrsDoubleVlanAiFreeGet (Priv); + if (Ai < 0) { + Ret = Ai; + goto error; + } + + /* Get first single/triple vlan Tid */ + for (TidAux = MVPP2_PE_FIRST_FREE_TID; TidAux <= MVPP2_PE_LAST_FREE_TID; TidAux++) { + UINT32 RiBits; + + if (!Priv->PrsShadow[TidAux].Valid || Priv->PrsShadow[TidAux].Lu != MVPP2_PRS_LU_VLAN) { + continue; + } + + Pe->Index = TidAux; + Mvpp2PrsHwRead (Priv, Pe); + RiBits = Mvpp2PrsSramRiGet (Pe); + RiBits &= MVPP2_PRS_RI_VLAN_MASK; + + if (RiBits == MVPP2_PRS_RI_VLAN_SINGLE || RiBits == MVPP2_PRS_RI_VLAN_TRIPLE) { + break; + } + } + + if (Tid >= TidAux) { + Ret = MVPP2_ERANGE; + goto error; + } + + Mvpp2Memset (Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (Pe, MVPP2_PRS_LU_VLAN); + Pe->Index = Tid; + + Priv->PrsDoubleVlans[Ai] = TRUE; + + /* Set both VLAN types' offsets to 0 and 4 bytes - obtained from Marvell */ + Mvpp2PrsMatchEtype (Pe, 0, Tpid1); + Mvpp2PrsMatchEtype (Pe, 4, Tpid2); + + Mvpp2PrsSramNextLuSet (Pe, MVPP2_PRS_LU_VLAN); + + /* Shift 8 bytes - skip 2 vlan tags */ + Mvpp2PrsSramShiftSet (Pe, 2 * MVPP2_VLAN_TAG_LEN, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + Mvpp2PrsSramRiUpdate (Pe, MVPP2_PRS_RI_VLAN_DOUBLE, MVPP2_PRS_RI_VLAN_MASK); + Mvpp2PrsSramAiUpdate (Pe, Ai | MVPP2_PRS_DBL_VLAN_AI_BIT, MVPP2_PRS_SRAM_AI_MASK); + + Mvpp2PrsShadowSet (Priv, Pe->Index, MVPP2_PRS_LU_VLAN); + } + + /* Update Ports' Mask */ + Mvpp2PrsTcamPortMapSet (Pe, PortMap); + Mvpp2PrsHwWrite (Priv, Pe); + +error: + Mvpp2Free (Pe); + return Ret; +} + +/* IPv4 header parsing for fragmentation and L4 Offset */ +STATIC +INT32 +Mvpp2PrsIp4Proto ( + IN MVPP2_SHARED *Priv, + IN UINT16 Proto, + IN UINT32 Ri, + IN UINT32 RiMask + ) +{ + MVPP2_PRS_ENTRY Pe; + INT32 Tid; + + if ((Proto != MV_IPPR_TCP) && (Proto != MV_IPPR_UDP) && (Proto != MV_IPPR_IGMP)) { + return MVPP2_EINVAL; + } + + /* Fragmented packet */ + Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID); + if (Tid < 0) { + return Tid; + } + + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP4); + Pe.Index = Tid; + + /* Set next Lu to IPv4 - 12 bytes shift */ + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_IP4); + Mvpp2PrsSramShiftSet (&Pe, 12, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + + /* Set L4 offset 4 bytes relative IPv4 header size (current position) */ + Mvpp2PrsSramOffsetSet ( + &Pe, + MVPP2_PRS_SRAM_UDF_TYPE_L4, + sizeof (Mvpp2Iphdr) - 4, + MVPP2_PRS_SRAM_OP_SEL_UDF_ADD + ); + + Mvpp2PrsSramAiUpdate (&Pe, MVPP2_PRS_IPV4_DIP_AI_BIT, MVPP2_PRS_IPV4_DIP_AI_BIT); + Mvpp2PrsSramRiUpdate (&Pe, Ri | MVPP2_PRS_RI_IP_FRAG_MASK, RiMask | MVPP2_PRS_RI_IP_FRAG_MASK); + + Mvpp2PrsTcamDataByteSet (&Pe, 5, Proto, MVPP2_PRS_TCAM_PROTO_MASK); + Mvpp2PrsTcamAiUpdate (&Pe, 0, MVPP2_PRS_IPV4_DIP_AI_BIT); + + /* Unmask all Ports */ + Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK); + + /* Update shadow table and hw entry */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP4); + Mvpp2PrsHwWrite (Priv, &Pe); + + /* Not fragmented packet */ + Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID); + if (Tid < 0) { + return Tid; + } + + Pe.Index = Tid; + + /* Clear Ri before updating */ + Pe.Sram.Word[MVPP2_PRS_SRAM_RI_WORD] = 0x0; + Pe.Sram.Word[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0; + Mvpp2PrsSramRiUpdate (&Pe, Ri, RiMask); + + Mvpp2PrsTcamDataByteSet (&Pe, 2, 0x00, MVPP2_PRS_TCAM_PROTO_MASK_L); + Mvpp2PrsTcamDataByteSet (&Pe, 3, 0x00, MVPP2_PRS_TCAM_PROTO_MASK); + + /* Update shadow table and hw entry */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP4); + Mvpp2PrsHwWrite (Priv, &Pe); + + return 0; +} + +/* IPv4 L3 multicast or broadcast */ +STATIC +INT32 +Mvpp2PrsIp4Cast ( + IN MVPP2_SHARED *Priv, + IN UINT16 L3Cast + ) +{ + MVPP2_PRS_ENTRY Pe; + INT32 Mask, Tid; + + Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID); + if (Tid < 0) { + return Tid; + } + + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP4); + Pe.Index = Tid; + + switch (L3Cast) { + case MVPP2_PRS_L3_MULTI_CAST: + Mvpp2PrsTcamDataByteSet (&Pe, 0, MVPP2_PRS_IPV4_MC, MVPP2_PRS_IPV4_MC_MASK); + Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_MCAST, MVPP2_PRS_RI_L3_ADDR_MASK); + break; + case MVPP2_PRS_L3_BROAD_CAST: + Mask = MVPP2_PRS_IPV4_BC_MASK; + Mvpp2PrsTcamDataByteSet (&Pe, 0, Mask, Mask); + Mvpp2PrsTcamDataByteSet (&Pe, 1, Mask, Mask); + Mvpp2PrsTcamDataByteSet (&Pe, 2, Mask, Mask); + Mvpp2PrsTcamDataByteSet (&Pe, 3, Mask, Mask); + Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_BCAST, MVPP2_PRS_RI_L3_ADDR_MASK); + break; + default: + return MVPP2_EINVAL; + } + + /* Finished: go to Flowid generation */ + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS); + Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1); + + Mvpp2PrsTcamAiUpdate (&Pe, MVPP2_PRS_IPV4_DIP_AI_BIT, MVPP2_PRS_IPV4_DIP_AI_BIT); + + /* Unmask all Ports */ + Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK); + + /* Update shadow table and hw entry */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP4); + Mvpp2PrsHwWrite (Priv, &Pe); + + return 0; +} + +/* Set entries for protocols over IPv6 */ +STATIC +INT32 +Mvpp2PrsIp6Proto ( + IN MVPP2_SHARED *Priv, + IN UINT16 Proto, + IN UINT32 Ri, + IN UINT32 RiMask + ) +{ + MVPP2_PRS_ENTRY Pe; + INT32 Tid; + + if ((Proto != MV_IPPR_TCP) && (Proto != MV_IPPR_UDP) && + (Proto != MV_IPPR_ICMPV6) && (Proto != MV_IPPR_IPIP)) + { + return MVPP2_EINVAL; + } + + Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID); + if (Tid < 0) { + return Tid; + } + + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP6); + Pe.Index = Tid; + + /* Finished: go to Flowid generation */ + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS); + Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1); + Mvpp2PrsSramRiUpdate (&Pe, Ri, RiMask); + + /* Set offset for protocol 6 bytes relative to IPv6 header size */ + Mvpp2PrsSramOffsetSet ( + &Pe, + MVPP2_PRS_SRAM_UDF_TYPE_L4, + sizeof (Mvpp2Ipv6hdr) - 6, + MVPP2_PRS_SRAM_OP_SEL_UDF_ADD + ); + + Mvpp2PrsTcamDataByteSet (&Pe, 0, Proto, MVPP2_PRS_TCAM_PROTO_MASK); + Mvpp2PrsTcamAiUpdate (&Pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT, MVPP2_PRS_IPV6_NO_EXT_AI_BIT); + + /* Unmask all Ports */ + Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK); + + /* Write HW */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP6); + Mvpp2PrsHwWrite (Priv, &Pe); + + return 0; +} + +/* IPv6 L3 multicast entry */ +STATIC +INT32 +Mvpp2PrsIp6Cast ( + IN MVPP2_SHARED *Priv, + IN UINT16 L3Cast + ) +{ + MVPP2_PRS_ENTRY Pe; + INT32 Tid; + + if (L3Cast != MVPP2_PRS_L3_MULTI_CAST) { + return MVPP2_EINVAL; + } + + Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID); + if (Tid < 0) { + return Tid; + } + + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP6); + Pe.Index = Tid; + + /* Finished: go to Flowid generation */ + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_IP6); + Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_MCAST, MVPP2_PRS_RI_L3_ADDR_MASK); + Mvpp2PrsSramAiUpdate (&Pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT, MVPP2_PRS_IPV6_NO_EXT_AI_BIT); + + /* Shift back to IPv6 by 18 bytes - byte count provided by Marvell */ + Mvpp2PrsSramShiftSet (&Pe, -18, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + + Mvpp2PrsTcamDataByteSet (&Pe, 0, MVPP2_PRS_IPV6_MC, MVPP2_PRS_IPV6_MC_MASK); + Mvpp2PrsTcamAiUpdate (&Pe, 0, MVPP2_PRS_IPV6_NO_EXT_AI_BIT); + + /* Unmask all Ports */ + Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK); + + /* Update shadow table and hw entry */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP6); + Mvpp2PrsHwWrite (Priv, &Pe); + + return 0; +} + +/* Parser per-Port initialization */ +STATIC +VOID +Mvpp2PrsHwPortInit ( + IN MVPP2_SHARED *Priv, + IN INT32 PortId, + IN INT32 LuFirst, + IN INT32 LuMax, + IN INT32 Offset + ) +{ + UINT32 Val; + + /* Set lookup ID */ + Val = Mvpp2Read (Priv, MVPP2_PRS_INIT_LOOKUP_REG); + Val &= ~MVPP2_PRS_PORT_LU_MASK (PortId); + Val |= MVPP2_PRS_PORT_LU_VAL (PortId, LuFirst); + Mvpp2Write (Priv, MVPP2_PRS_INIT_LOOKUP_REG, Val); + + /* Set maximum number of loops for packet received from PortId */ + Val = Mvpp2Read (Priv, MVPP2_PRS_MAX_LOOP_REG(PortId)); + Val &= ~MVPP2_PRS_MAX_LOOP_MASK (PortId); + Val |= MVPP2_PRS_MAX_LOOP_VAL (PortId, LuMax); + Mvpp2Write (Priv, MVPP2_PRS_MAX_LOOP_REG(PortId), Val); + + /* + * Set initial Offset for packet header extraction for the first + * searching loop + */ + Val = Mvpp2Read (Priv, MVPP2_PRS_INIT_OFFS_REG(PortId)); + Val &= ~MVPP2_PRS_INIT_OFF_MASK (PortId); + Val |= MVPP2_PRS_INIT_OFF_VAL (PortId, Offset); + Mvpp2Write (Priv, MVPP2_PRS_INIT_OFFS_REG(PortId), Val); +} + +/* Default Flow entries initialization for all Ports */ +STATIC +VOID +Mvpp2PrsDefFlowInit ( + IN MVPP2_SHARED *Priv + ) +{ + MVPP2_PRS_ENTRY Pe; + INT32 PortId; + + for (PortId = 0; PortId < MVPP2_MAX_PORTS; PortId++) { + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_FLOWS); + Pe.Index = MVPP2_PE_FIRST_DEFAULT_FLOW - PortId; + + /* Mask all Ports */ + Mvpp2PrsTcamPortMapSet (&Pe, 0); + + /* Set Flow ID*/ + Mvpp2PrsSramAiUpdate (&Pe, PortId, MVPP2_PRS_FLOW_ID_MASK); + Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_DONE_BIT, 1); + + /* Update shadow table and hw entry */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_FLOWS); + Mvpp2PrsHwWrite (Priv, &Pe); + } +} + +/* Set default entry for Marvell Header field */ +STATIC +VOID +Mvpp2PrsMhInit ( + IN MVPP2_SHARED *Priv + ) +{ + MVPP2_PRS_ENTRY Pe; + + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + + Pe.Index = MVPP2_PE_MH_DEFAULT; + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_MH); + Mvpp2PrsSramShiftSet (&Pe, MVPP2_MH_SIZE, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_MAC); + + /* Unmask all Ports */ + Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK); + + /* Update shadow table and hw entry */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_MH); + Mvpp2PrsHwWrite (Priv, &Pe); +} + +/* + * Set default entires (place holder) for promiscuous, non-promiscuous and + * multicast MAC Addresses + */ +STATIC +VOID +Mvpp2PrsMacInit ( + IN MVPP2_SHARED *Priv + ) +{ + MVPP2_PRS_ENTRY Pe; + + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + + /* Non-promiscuous mode for all Ports - DROP unknown packets */ + Pe.Index = MVPP2_PE_MAC_NON_PROMISCUOUS; + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_MAC); + + Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_DROP_MASK, MVPP2_PRS_RI_DROP_MASK); + Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1); + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS); + + /* Unmask all Ports */ + Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK); + + /* Update shadow table and hw entry */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_MAC); + Mvpp2PrsHwWrite (Priv, &Pe); + + /* Place holders only - no Ports */ + Mvpp2PrsMacDropAllSet (Priv, 0, FALSE); + Mvpp2PrsMacPromiscSet (Priv, 0, FALSE); + Mvpp2PrsMacMultiSet (Priv, MVPP2_PE_MAC_MC_ALL, 0, FALSE); + Mvpp2PrsMacMultiSet (Priv, MVPP2_PE_MAC_MC_IP6, 0, FALSE); +} + +/* Set default entries for various types of dsa packets */ +STATIC +VOID +Mvpp2PrsDsaInit ( + IN MVPP2_SHARED *Priv + ) +{ + MVPP2_PRS_ENTRY Pe; + + /* None tagged EDSA entry - place holder */ + Mvpp2PrsDsaTagSet (Priv, 0, FALSE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA); + + /* Tagged EDSA entry - place holder */ + Mvpp2PrsDsaTagSet (Priv, 0, FALSE, MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA); + + /* None tagged DSA entry - place holder */ + Mvpp2PrsDsaTagSet (Priv, 0, FALSE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA); + + /* Tagged DSA entry - place holder */ + Mvpp2PrsDsaTagSet (Priv, 0, FALSE, MVPP2_PRS_TAGGED, MVPP2_PRS_DSA); + + /* None tagged EDSA ethertype entry - place holder*/ + Mvpp2PrsDsaTagEthertypeSet (Priv, 0, FALSE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA); + + /* Tagged EDSA ethertype entry - place holder*/ + Mvpp2PrsDsaTagEthertypeSet (Priv, 0, FALSE, MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA); + + /* None tagged DSA ethertype entry */ + Mvpp2PrsDsaTagEthertypeSet (Priv, 0, TRUE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA); + + /* Tagged DSA ethertype entry */ + Mvpp2PrsDsaTagEthertypeSet (Priv, 0, TRUE, MVPP2_PRS_TAGGED, MVPP2_PRS_DSA); + + /* Set default entry, in case DSA or EDSA tag not found */ + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_DSA); + Pe.Index = MVPP2_PE_DSA_DEFAULT; + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_VLAN); + + /* Shift 0 bytes */ + Mvpp2PrsSramShiftSet (&Pe, 0, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_MAC); + + /* Clear all Sram ai bits for next iteration */ + Mvpp2PrsSramAiUpdate (&Pe, 0, MVPP2_PRS_SRAM_AI_MASK); + + /* Unmask all Ports */ + Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK); + + Mvpp2PrsHwWrite (Priv, &Pe); +} + +/* Match basic ethertypes */ +STATIC +INT32 +Mvpp2PrsEtypeInit ( + IN MVPP2_SHARED *Priv + ) +{ + MVPP2_PRS_ENTRY Pe; + INT32 Tid; + + /* Ethertype: PPPoE */ + Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID); + if (Tid < 0) { + return Tid; + } + + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_L2); + Pe.Index = Tid; + + /* Set PPPoE type offset to 0 - obtained from Marvell */ + Mvpp2PrsMatchEtype (&Pe, 0, MV_ETH_P_PPP_SES); + + Mvpp2PrsSramShiftSet (&Pe, MVPP2_PPPOE_HDR_SIZE, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_PPPOE); + Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_PPPOE_MASK, MVPP2_PRS_RI_PPPOE_MASK); + + /* Update shadow table and hw entry */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_L2); + Priv->PrsShadow[Pe.Index].Udf = MVPP2_PRS_UDF_L2_DEF; + Priv->PrsShadow[Pe.Index].Finish = FALSE; + Mvpp2PrsShadowRiSet (Priv, Pe.Index, MVPP2_PRS_RI_PPPOE_MASK, MVPP2_PRS_RI_PPPOE_MASK); + Mvpp2PrsHwWrite (Priv, &Pe); + + /* Ethertype: ARP */ + Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID); + if (Tid < 0) { + return Tid; + } + + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_L2); + Pe.Index = Tid; + + /* Set ARP type offset to 0 - obtained from Marvell */ + Mvpp2PrsMatchEtype (&Pe, 0, MV_ETH_P_ARP); + + /* Generate Flow in the next iteration*/ + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS); + Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1); + Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_ARP, MVPP2_PRS_RI_L3_PROTO_MASK); + + /* Set L3 Offset */ + Mvpp2PrsSramOffsetSet (&Pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD); + + /* Update shadow table and hw entry */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_L2); + Priv->PrsShadow[Pe.Index].Udf = MVPP2_PRS_UDF_L2_DEF; + Priv->PrsShadow[Pe.Index].Finish = TRUE; + Mvpp2PrsShadowRiSet (Priv, Pe.Index, MVPP2_PRS_RI_L3_ARP, MVPP2_PRS_RI_L3_PROTO_MASK); + Mvpp2PrsHwWrite (Priv, &Pe); + + /* Ethertype: LBTD */ + Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID); + if (Tid < 0) { + return Tid; + } + + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_L2); + Pe.Index = Tid; + + /* Set LBTD type offset to 0 - obtained from Marvell */ + Mvpp2PrsMatchEtype (&Pe, 0, MVPP2_IP_LBDT_TYPE); + + /* Generate Flow in the next iteration*/ + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS); + Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1); + Mvpp2PrsSramRiUpdate ( + &Pe, + MVPP2_PRS_RI_CPU_CODE_RX_SPEC | MVPP2_PRS_RI_UDF3_RX_SPECIAL, + MVPP2_PRS_RI_CPU_CODE_MASK | MVPP2_PRS_RI_UDF3_MASK + ); + + /* Set L3 Offset */ + Mvpp2PrsSramOffsetSet (&Pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD); + + /* Update shadow table and hw entry */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_L2); + Priv->PrsShadow[Pe.Index].Udf = MVPP2_PRS_UDF_L2_DEF; + Priv->PrsShadow[Pe.Index].Finish = TRUE; + Mvpp2PrsShadowRiSet ( + Priv, + Pe.Index, + MVPP2_PRS_RI_CPU_CODE_RX_SPEC | MVPP2_PRS_RI_UDF3_RX_SPECIAL, + MVPP2_PRS_RI_CPU_CODE_MASK | MVPP2_PRS_RI_UDF3_MASK + ); + + Mvpp2PrsHwWrite (Priv, &Pe); + + /* Ethertype: IPv4 without options */ + Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID); + if (Tid < 0) { + return Tid; + } + + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_L2); + Pe.Index = Tid; + + /* Set IPv4 type offset to 0 - obtained from Marvell */ + Mvpp2PrsMatchEtype (&Pe, 0, MV_ETH_P_IP); + Mvpp2PrsTcamDataByteSet ( + &Pe, + MVPP2_ETH_TYPE_LEN, + MVPP2_PRS_IPV4_HEAD | MVPP2_PRS_IPV4_IHL, + MVPP2_PRS_IPV4_HEAD_MASK | MVPP2_PRS_IPV4_IHL_MASK + ); + + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_IP4); + Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_IP4, MVPP2_PRS_RI_L3_PROTO_MASK); + + /* Skip EthType + 4 bytes of IP header */ + Mvpp2PrsSramShiftSet (&Pe, MVPP2_ETH_TYPE_LEN + 4, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + + /* Set L3 Offset */ + Mvpp2PrsSramOffsetSet (&Pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD); + + /* Update shadow table and hw entry */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_L2); + Priv->PrsShadow[Pe.Index].Udf = MVPP2_PRS_UDF_L2_DEF; + Priv->PrsShadow[Pe.Index].Finish = FALSE; + Mvpp2PrsShadowRiSet (Priv, Pe.Index, MVPP2_PRS_RI_L3_IP4, MVPP2_PRS_RI_L3_PROTO_MASK); + Mvpp2PrsHwWrite (Priv, &Pe); + + /* Ethertype: IPv4 with options */ + Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID); + if (Tid < 0) { + return Tid; + } + + Pe.Index = Tid; + + /* Clear Tcam data before updating */ + Pe.Tcam.Byte[MVPP2_PRS_TCAM_DATA_BYTE(MVPP2_ETH_TYPE_LEN)] = 0x0; + Pe.Tcam.Byte[MVPP2_PRS_TCAM_DATA_BYTE_EN(MVPP2_ETH_TYPE_LEN)] = 0x0; + + Mvpp2PrsTcamDataByteSet (&Pe, MVPP2_ETH_TYPE_LEN, MVPP2_PRS_IPV4_HEAD, MVPP2_PRS_IPV4_HEAD_MASK); + + /* Clear Ri before updating */ + Pe.Sram.Word[MVPP2_PRS_SRAM_RI_WORD] = 0x0; + Pe.Sram.Word[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0; + Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_IP4_OPT, MVPP2_PRS_RI_L3_PROTO_MASK); + + /* Update shadow table and hw entry */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_L2); + Priv->PrsShadow[Pe.Index].Udf = MVPP2_PRS_UDF_L2_DEF; + Priv->PrsShadow[Pe.Index].Finish = FALSE; + Mvpp2PrsShadowRiSet (Priv, Pe.Index, MVPP2_PRS_RI_L3_IP4_OPT, MVPP2_PRS_RI_L3_PROTO_MASK); + Mvpp2PrsHwWrite (Priv, &Pe); + + /* Ethertype: IPv6 without options */ + Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID); + if (Tid < 0) { + return Tid; + } + + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_L2); + Pe.Index = Tid; + + /* Set IPv6 type offset to 0 - obtained from Marvell */ + Mvpp2PrsMatchEtype (&Pe, 0, MV_ETH_P_IPV6); + + /* Skip DIP of IPV6 header - value provided by Marvell */ + Mvpp2PrsSramShiftSet (&Pe, MVPP2_ETH_TYPE_LEN + 8 + MVPP2_MAX_L3_ADDR_SIZE, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_IP6); + Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_IP6, MVPP2_PRS_RI_L3_PROTO_MASK); + + /* Set L3 Offset */ + Mvpp2PrsSramOffsetSet (&Pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD); + + /* Update shadow table and hw entry */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_L2); + Priv->PrsShadow[Pe.Index].Udf = MVPP2_PRS_UDF_L2_DEF; + Priv->PrsShadow[Pe.Index].Finish = FALSE; + Mvpp2PrsShadowRiSet (Priv, Pe.Index, MVPP2_PRS_RI_L3_IP6, MVPP2_PRS_RI_L3_PROTO_MASK); + Mvpp2PrsHwWrite (Priv, &Pe); + + /* Default entry for MVPP2_PRS_LU_L2 - Unknown ethtype */ + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_L2); + Pe.Index = MVPP2_PE_ETH_TYPE_UN; + + /* Unmask all Ports */ + Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK); + + /* Generate Flow in the next iteration*/ + Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1); + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS); + Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_UN, MVPP2_PRS_RI_L3_PROTO_MASK); + + /* Set L3 Offset even it's unknown L3 */ + Mvpp2PrsSramOffsetSet (&Pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD); + + /* Update shadow table and hw entry */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_L2); + Priv->PrsShadow[Pe.Index].Udf = MVPP2_PRS_UDF_L2_DEF; + Priv->PrsShadow[Pe.Index].Finish = TRUE; + Mvpp2PrsShadowRiSet (Priv, Pe.Index, MVPP2_PRS_RI_L3_UN, MVPP2_PRS_RI_L3_PROTO_MASK); + Mvpp2PrsHwWrite (Priv, &Pe); + + return 0; +} + +/* + * Configure vlan entries and detect up to 2 successive VLAN tags. + * Possible options: + * 0x8100, 0x88A8 + * 0x8100, 0x8100 + * 0x8100, 0x88A8 + */ +STATIC +INT32 +Mvpp2PrsVlanInit ( + IN MVPP2_SHARED *Priv + ) +{ + MVPP2_PRS_ENTRY Pe; + INT32 Err; + + /* Double VLAN: 0x8100, 0x88A8 */ + Err = Mvpp2PrsDoubleVlanAdd (Priv, MV_ETH_P_8021Q, MV_ETH_P_8021AD, MVPP2_PRS_PORT_MASK); + if (Err != 0) { + return Err; + } + + /* Double VLAN: 0x8100, 0x8100 */ + Err = Mvpp2PrsDoubleVlanAdd (Priv, MV_ETH_P_8021Q, MV_ETH_P_8021Q, MVPP2_PRS_PORT_MASK); + if (Err != 0) { + return Err; + } + + /* Single VLAN: 0x88a8 */ + Err = Mvpp2PrsVlanAdd (Priv, MV_ETH_P_8021AD, MVPP2_PRS_SINGLE_VLAN_AI, MVPP2_PRS_PORT_MASK); + if (Err != 0) { + return Err; + } + + /* Single VLAN: 0x8100 */ + Err = Mvpp2PrsVlanAdd (Priv, MV_ETH_P_8021Q, MVPP2_PRS_SINGLE_VLAN_AI, MVPP2_PRS_PORT_MASK); + if (Err != 0) { + return Err; + } + + /* Set default double vlan entry */ + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_VLAN); + Pe.Index = MVPP2_PE_VLAN_DBL; + + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_L2); + + /* Clear ai for next iterations */ + Mvpp2PrsSramAiUpdate (&Pe, 0, MVPP2_PRS_SRAM_AI_MASK); + Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_VLAN_DOUBLE, MVPP2_PRS_RI_VLAN_MASK); + + Mvpp2PrsTcamAiUpdate (&Pe, MVPP2_PRS_DBL_VLAN_AI_BIT, MVPP2_PRS_DBL_VLAN_AI_BIT); + + /* Unmask all Ports */ + Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK); + + /* Update shadow table and hw entry */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_VLAN); + Mvpp2PrsHwWrite (Priv, &Pe); + + /* Set default vlan none entry */ + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_VLAN); + Pe.Index = MVPP2_PE_VLAN_NONE; + + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_L2); + Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_VLAN_NONE, MVPP2_PRS_RI_VLAN_MASK); + + /* Unmask all Ports */ + Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK); + + /* Update shadow table and hw entry */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_VLAN); + Mvpp2PrsHwWrite (Priv, &Pe); + + return 0; +} + +/* Set entries for PPPoE ethertype */ +STATIC +INT32 +Mvpp2PrsPppoeInit ( + IN MVPP2_SHARED *Priv + ) +{ + MVPP2_PRS_ENTRY Pe; + INT32 Tid; + + /* IPv4 over PPPoE with options */ + Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID); + if (Tid < 0) { + return Tid; + } + + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_PPPOE); + Pe.Index = Tid; + + /* Set IPv4 over PPPoE type offset to 0 - obtained from Marvell */ + Mvpp2PrsMatchEtype (&Pe, 0, MV_PPP_IP); + + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_IP4); + Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_IP4_OPT, MVPP2_PRS_RI_L3_PROTO_MASK); + + /* Skip EthType + 4 bytes of IP header */ + Mvpp2PrsSramShiftSet (&Pe, MVPP2_ETH_TYPE_LEN + 4, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + + /* Set L3 Offset */ + Mvpp2PrsSramOffsetSet (&Pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD); + + /* Update shadow table and hw entry */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_PPPOE); + Mvpp2PrsHwWrite (Priv, &Pe); + + /* IPv4 over PPPoE without options */ + Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID); + if (Tid < 0) { + return Tid; + } + + Pe.Index = Tid; + + Mvpp2PrsTcamDataByteSet ( + &Pe, + MVPP2_ETH_TYPE_LEN, + MVPP2_PRS_IPV4_HEAD | MVPP2_PRS_IPV4_IHL, + MVPP2_PRS_IPV4_HEAD_MASK | MVPP2_PRS_IPV4_IHL_MASK + ); + + /* Clear Ri before updating */ + Pe.Sram.Word[MVPP2_PRS_SRAM_RI_WORD] = 0x0; + Pe.Sram.Word[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0; + Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_IP4, MVPP2_PRS_RI_L3_PROTO_MASK); + + /* Update shadow table and hw entry */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_PPPOE); + Mvpp2PrsHwWrite (Priv, &Pe); + + /* IPv6 over PPPoE */ + Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID); + if (Tid < 0) { + return Tid; + } + + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_PPPOE); + Pe.Index = Tid; + + /* Set IPv6 over PPPoE type offset to 0 - obtained from Marvell */ + Mvpp2PrsMatchEtype (&Pe, 0, MV_PPP_IPV6); + + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_IP6); + Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_IP6, MVPP2_PRS_RI_L3_PROTO_MASK); + + /* Skip EthType + 4 bytes of IPv6 header */ + Mvpp2PrsSramShiftSet (&Pe, MVPP2_ETH_TYPE_LEN + 4, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + + /* Set L3 Offset */ + Mvpp2PrsSramOffsetSet (&Pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD); + + /* Update shadow table and hw entry */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_PPPOE); + Mvpp2PrsHwWrite (Priv, &Pe); + + /* Non-IP over PPPoE */ + Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID); + if (Tid < 0) { + return Tid; + } + + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_PPPOE); + Pe.Index = Tid; + + Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_UN, MVPP2_PRS_RI_L3_PROTO_MASK); + + /* Finished: go to Flowid generation */ + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS); + Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1); + + /* Set L3 Offset even if it's unknown L3 */ + Mvpp2PrsSramOffsetSet (&Pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD); + + /* Update shadow table and hw entry */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_PPPOE); + Mvpp2PrsHwWrite (Priv, &Pe); + + return 0; +} + +/* Initialize entries for IPv4 */ +STATIC +INT32 +Mvpp2PrsIp4Init ( + IN MVPP2_SHARED *Priv + ) +{ + MVPP2_PRS_ENTRY Pe; + INT32 Err; + + /* Set entries for TCP, UDP and IGMP over IPv4 */ + Err = Mvpp2PrsIp4Proto (Priv, MV_IPPR_TCP, MVPP2_PRS_RI_L4_TCP, MVPP2_PRS_RI_L4_PROTO_MASK); + if (Err != 0) { + return Err; + } + + Err = Mvpp2PrsIp4Proto (Priv, MV_IPPR_UDP, MVPP2_PRS_RI_L4_UDP, MVPP2_PRS_RI_L4_PROTO_MASK); + if (Err != 0) { + return Err; + } + + Err = Mvpp2PrsIp4Proto ( + Priv, + MV_IPPR_IGMP, + MVPP2_PRS_RI_CPU_CODE_RX_SPEC | MVPP2_PRS_RI_UDF3_RX_SPECIAL, + MVPP2_PRS_RI_CPU_CODE_MASK | MVPP2_PRS_RI_UDF3_MASK + ); + + if (Err != 0) { + return Err; + } + + /* IPv4 Broadcast */ + Err = Mvpp2PrsIp4Cast (Priv, MVPP2_PRS_L3_BROAD_CAST); + if (Err != 0) { + return Err; + } + + /* IPv4 Multicast */ + Err = Mvpp2PrsIp4Cast (Priv, MVPP2_PRS_L3_MULTI_CAST); + if (Err != 0) { + return Err; + } + + /* Default IPv4 entry for unknown protocols */ + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP4); + Pe.Index = MVPP2_PE_IP4_PROTO_UN; + + /* Set next Lu to IPv4 and shift by 12 bytes - obtained from Marvell*/ + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_IP4); + Mvpp2PrsSramShiftSet (&Pe, 12, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + + /* Set L4 offset 4 bytes relative IPv4 header size (current position) */ + Mvpp2PrsSramOffsetSet ( + &Pe, + MVPP2_PRS_SRAM_UDF_TYPE_L4, + sizeof (Mvpp2Iphdr) - 4, + MVPP2_PRS_SRAM_OP_SEL_UDF_ADD + ); + + Mvpp2PrsSramAiUpdate (&Pe, MVPP2_PRS_IPV4_DIP_AI_BIT, MVPP2_PRS_IPV4_DIP_AI_BIT); + Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L4_OTHER, MVPP2_PRS_RI_L4_PROTO_MASK); + + Mvpp2PrsTcamAiUpdate (&Pe, 0, MVPP2_PRS_IPV4_DIP_AI_BIT); + + /* Unmask all Ports */ + Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK); + + /* Update shadow table and hw entry */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP4); + Mvpp2PrsHwWrite (Priv, &Pe); + + /* Default IPv4 entry for unicast Address */ + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP4); + Pe.Index = MVPP2_PE_IP4_ADDR_UN; + + /* Finished: go to Flowid generation */ + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS); + Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1); + Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_UCAST, MVPP2_PRS_RI_L3_ADDR_MASK); + + Mvpp2PrsTcamAiUpdate (&Pe, MVPP2_PRS_IPV4_DIP_AI_BIT, MVPP2_PRS_IPV4_DIP_AI_BIT); + + /* Unmask all Ports */ + Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK); + + /* Update shadow table and hw entry */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP4); + Mvpp2PrsHwWrite (Priv, &Pe); + + return 0; +} + +/* Initialize entries for IPv6 */ +STATIC +INT32 +Mvpp2PrsIp6Init ( + IN MVPP2_SHARED *Priv + ) +{ + MVPP2_PRS_ENTRY Pe; + INT32 Tid, Err; + + /* Set entries for TCP, UDP and ICMP over IPv6 */ + Err = Mvpp2PrsIp6Proto (Priv, MV_IPPR_TCP, MVPP2_PRS_RI_L4_TCP, MVPP2_PRS_RI_L4_PROTO_MASK); + if (Err != 0) { + return Err; + } + + Err = Mvpp2PrsIp6Proto (Priv, MV_IPPR_UDP, MVPP2_PRS_RI_L4_UDP, MVPP2_PRS_RI_L4_PROTO_MASK); + if (Err != 0) { + return Err; + } + + Err = Mvpp2PrsIp6Proto ( + Priv, + MV_IPPR_ICMPV6, + MVPP2_PRS_RI_CPU_CODE_RX_SPEC | MVPP2_PRS_RI_UDF3_RX_SPECIAL, + MVPP2_PRS_RI_CPU_CODE_MASK | MVPP2_PRS_RI_UDF3_MASK + ); + + if (Err != 0) { + return Err; + } + + /* + * IPv4 is the last header. This is similar case as 6-TCP or 17-UDP + * Result Info: UDF7=1, DS lite + */ + Err = Mvpp2PrsIp6Proto (Priv, MV_IPPR_IPIP, MVPP2_PRS_RI_UDF7_IP6_LITE, MVPP2_PRS_RI_UDF7_MASK); + if (Err != 0) { + return Err; + } + + /* IPv6 multicast */ + Err = Mvpp2PrsIp6Cast (Priv, MVPP2_PRS_L3_MULTI_CAST); + if (Err != 0) { + return Err; + } + + /* Entry for checking hop limit */ + Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID); + if (Tid < 0) { + return Tid; + } + + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP6); + Pe.Index = Tid; + + /* Finished: go to Flowid generation */ + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS); + Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1); + Mvpp2PrsSramRiUpdate ( + &Pe, + MVPP2_PRS_RI_L3_UN | MVPP2_PRS_RI_DROP_MASK, + MVPP2_PRS_RI_L3_PROTO_MASK | MVPP2_PRS_RI_DROP_MASK + ); + + Mvpp2PrsTcamDataByteSet (&Pe, 1, 0x00, MVPP2_PRS_IPV6_HOP_MASK); + Mvpp2PrsTcamAiUpdate (&Pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT, MVPP2_PRS_IPV6_NO_EXT_AI_BIT); + + /* Update shadow table and hw entry */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP4); + Mvpp2PrsHwWrite (Priv, &Pe); + + /* Default IPv6 entry for unknown protocols */ + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP6); + Pe.Index = MVPP2_PE_IP6_PROTO_UN; + + /* Finished: go to Flowid generation */ + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS); + Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1); + Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L4_OTHER, MVPP2_PRS_RI_L4_PROTO_MASK); + + /* Set L4 offset 6 bytes relative IPv6 header size (current position) */ + Mvpp2PrsSramOffsetSet ( + &Pe, + MVPP2_PRS_SRAM_UDF_TYPE_L4, + sizeof (Mvpp2Ipv6hdr) - 6, + MVPP2_PRS_SRAM_OP_SEL_UDF_ADD + ); + + Mvpp2PrsTcamAiUpdate (&Pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT, MVPP2_PRS_IPV6_NO_EXT_AI_BIT); + + /* Unmask all Ports */ + Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK); + + /* Update shadow table and hw entry */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP4); + Mvpp2PrsHwWrite (Priv, &Pe); + + /* Default IPv6 entry for unknown ext protocols */ + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP6); + Pe.Index = MVPP2_PE_IP6_EXT_PROTO_UN; + + /* Finished: go to Flowid generation */ + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS); + Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1); + Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L4_OTHER, MVPP2_PRS_RI_L4_PROTO_MASK); + + Mvpp2PrsTcamAiUpdate (&Pe, MVPP2_PRS_IPV6_EXT_AI_BIT, MVPP2_PRS_IPV6_EXT_AI_BIT); + + /* Unmask all Ports */ + Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK); + + /* Update shadow table and hw entry */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP4); + Mvpp2PrsHwWrite (Priv, &Pe); + + /* Default IPv6 entry for unicast Address */ + Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY)); + Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP6); + Pe.Index = MVPP2_PE_IP6_ADDR_UN; + + /* Finished: go to IPv6 again */ + Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_IP6); + Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_UCAST, MVPP2_PRS_RI_L3_ADDR_MASK); + Mvpp2PrsSramAiUpdate (&Pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT, MVPP2_PRS_IPV6_NO_EXT_AI_BIT); + + /* Shift back to IPv6 by 18 bytes - byte count provided by Marvell */ + Mvpp2PrsSramShiftSet (&Pe, -18, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + Mvpp2PrsTcamAiUpdate (&Pe, 0, MVPP2_PRS_IPV6_NO_EXT_AI_BIT); + + /* Unmask all Ports */ + Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK); + + /* Update shadow table and hw entry */ + Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP6); + Mvpp2PrsHwWrite (Priv, &Pe); + + return 0; +} + +/* Parser default initialization */ +INT32 +Mvpp2PrsDefaultInit ( + IN MVPP2_SHARED *Priv + ) +{ + INT32 Err, Index, i; + + /* Enable Tcam table */ + Mvpp2Write (Priv, MVPP2_PRS_TCAM_CTRL_REG, MVPP2_PRS_TCAM_EN_MASK); + + /* Clear all Tcam and Sram entries */ + for (Index = 0; Index < MVPP2_PRS_TCAM_SRAM_SIZE; Index++) { + Mvpp2Write (Priv, MVPP2_PRS_TCAM_IDX_REG, Index); + for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++) { + Mvpp2Write (Priv, MVPP2_PRS_TCAM_DATA_REG(i), 0); + } + + Mvpp2Write (Priv, MVPP2_PRS_SRAM_IDX_REG, Index); + for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++) { + Mvpp2Write (Priv, MVPP2_PRS_SRAM_DATA_REG(i), 0); + } + } + + /* Invalidate all Tcam entries */ + for (Index = 0; Index < MVPP2_PRS_TCAM_SRAM_SIZE; Index++) { + Mvpp2PrsHwInv (Priv, Index); + } + + /* Always start from lookup = 0 */ + for (Index = 0; Index < MVPP2_MAX_PORTS; Index++) { + Mvpp2PrsHwPortInit (Priv, Index, MVPP2_PRS_LU_MH, MVPP2_PRS_PORT_LU_MAX, 0); + } + + Mvpp2PrsDefFlowInit (Priv); + + Mvpp2PrsMhInit (Priv); + + Mvpp2PrsMacInit (Priv); + + Mvpp2PrsDsaInit (Priv); + + Err = Mvpp2PrsEtypeInit (Priv); + if (Err != 0) { + return Err; + } + + Err = Mvpp2PrsVlanInit (Priv); + if (Err != 0) { + return Err; + } + + Err = Mvpp2PrsPppoeInit (Priv); + if (Err != 0) { + return Err; + } + + Err = Mvpp2PrsIp6Init (Priv); + if (Err != 0) { + return Err; + } + + Err = Mvpp2PrsIp4Init (Priv); + if (Err != 0) { + return Err; + } + + return 0; +} + +/* Compare MAC DA with Tcam entry data */ +STATIC +BOOLEAN +Mvpp2PrsMacRangeEquals ( + IN MVPP2_PRS_ENTRY *Pe, + IN const UINT8 *Da, + IN UINT8 *Mask + ) +{ + UINT8 TcamByte, TcamMask; + INT32 Index; + + for (Index = 0; Index < MV_ETH_ALEN; Index++) { + Mvpp2PrsTcamDataByteGet (Pe, Index, &TcamByte, &TcamMask); + if (TcamMask != Mask[Index]) { + return FALSE; + } + + if ((TcamMask & TcamByte) != (Da[Index] & Mask[Index])) { + return FALSE; + } + } + + return TRUE; +} + +/* Find Tcam entry with matched pair */ +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 already exist */ + Pe = Mvpp2PrsMacDaRangeFind (Priv, (1 << PortId), Da, Mask, MVPP2_PRS_UDF_MAC_DEF); + + /* No such entry */ + if (Pe == NULL) { + if (!Add) { + return 0; + } + + /* Create new TCAM entry */ + /* Find first range mac entry*/ + for (Tid = MVPP2_PE_FIRST_FREE_TID; Tid <= MVPP2_PE_LAST_FREE_TID; Tid++) { + if (Priv->PrsShadow[Tid].Valid && + (Priv->PrsShadow[Tid].Lu == MVPP2_PRS_LU_MAC) && + (Priv->PrsShadow[Tid].Udf == MVPP2_PRS_UDF_MAC_RANGE)) + { + break; + } + } + + + /* Go through the all entries from first to last */ + Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, Tid - 1); + if (Tid < 0) { + return Tid; + } + + Pe = Mvpp2Alloc (sizeof (*Pe)); + if (Pe == NULL) { + return -1; + } + + Mvpp2PrsTcamLuSet (Pe, MVPP2_PRS_LU_MAC); + Pe->Index = Tid; + + /* Mask all Ports */ + Mvpp2PrsTcamPortMapSet (Pe, 0); + } + + /* Update PortId Mask */ + Mvpp2PrsTcamPortSet (Pe, PortId, Add); + + /* Invalidate the entry if no Ports are left enabled */ + Pmap = Mvpp2PrsTcamPortMapGet (Pe); + if (Pmap == 0) { + if (Add) { + Mvpp2Free (Pe); + return -1; + } + + Mvpp2PrsHwInv (Priv, Pe->Index); + Priv->PrsShadow[Pe->Index].Valid = FALSE; + + Mvpp2Free (Pe); + + return 0; + } + + /* Continue - set next lookup */ + Mvpp2PrsSramNextLuSet (Pe, MVPP2_PRS_LU_DSA); + + /* Set match on DA */ + Len = MV_ETH_ALEN; + while (Len--) { + Mvpp2PrsTcamDataByteSet (Pe, Len, Da[Len], 0xff); + } + + /* Set result info bits */ + if (Mvpp2IsBroadcastEtherAddr (Da)) { + Ri = MVPP2_PRS_RI_L2_BCAST; + } else if (Mvpp2IsMulticastEtherAddr (Da)) { + Ri = MVPP2_PRS_RI_L2_MCAST; + } else { + Ri = MVPP2_PRS_RI_L2_UCAST | MVPP2_PRS_RI_MAC_ME_MASK; + } + + Mvpp2PrsSramRiUpdate (Pe, Ri, MVPP2_PRS_RI_L2_CAST_MASK | MVPP2_PRS_RI_MAC_ME_MASK); + Mvpp2PrsShadowRiSet (Priv, Pe->Index, Ri, MVPP2_PRS_RI_L2_CAST_MASK | MVPP2_PRS_RI_MAC_ME_MASK); + + /* Shift to ethertype */ + Mvpp2PrsSramShiftSet (Pe, 2 * MV_ETH_ALEN, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + + /* Update shadow table and hw entry */ + Priv->PrsShadow[Pe->Index].Udf = MVPP2_PRS_UDF_MAC_DEF; + Mvpp2PrsShadowSet (Priv, Pe->Index, MVPP2_PRS_LU_MAC); + Mvpp2PrsHwWrite (Priv, Pe); + + Mvpp2Free (Pe); + + return 0; +} + +/* Delete all Port's multicast simple (not range) entries */ +VOID +Mvpp2PrsMcastDelAll ( + IN MVPP2_SHARED *Priv, + IN INT32 PortId + ) +{ + MVPP2_PRS_ENTRY Pe; + INT32 Index, Tid; + + for (Tid = MVPP2_PE_FIRST_FREE_TID; Tid <= MVPP2_PE_LAST_FREE_TID; Tid++) { + UINT8 Da[MV_ETH_ALEN], DaMask[MV_ETH_ALEN]; + + if (!Priv->PrsShadow[Tid].Valid || + (Priv->PrsShadow[Tid].Lu != MVPP2_PRS_LU_MAC) || + (Priv->PrsShadow[Tid].Udf != MVPP2_PRS_UDF_MAC_DEF)) + { + continue; + } + + /* Only simple mac entries */ + Pe.Index = Tid; + Mvpp2PrsHwRead (Priv, &Pe); + + /* Read mac Addr from entry */ + for (Index = 0; Index < MV_ETH_ALEN; Index++) { + Mvpp2PrsTcamDataByteGet (&Pe, Index, &Da[Index], &DaMask[Index]); + } + + if (Mvpp2IsMulticastEtherAddr (Da) && !Mvpp2IsBroadcastEtherAddr (Da)) { + /* Delete this entry */ + Mvpp2PrsMacDaAccept (Priv, PortId, Da, FALSE); + } + } +} + +INT32 +Mvpp2PrsTagModeSet ( + IN MVPP2_SHARED *Priv, + IN INT32 PortId, + IN INT32 Type + ) +{ + switch (Type) { + case MVPP2_TAG_TYPE_EDSA: + /* Add PortId to EDSA entries */ + Mvpp2PrsDsaTagSet (Priv, PortId, TRUE, MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA); + Mvpp2PrsDsaTagSet (Priv, PortId, TRUE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA); + /* Remove PortId from DSA entries */ + Mvpp2PrsDsaTagSet (Priv, PortId, FALSE, MVPP2_PRS_TAGGED, MVPP2_PRS_DSA); + Mvpp2PrsDsaTagSet (Priv, PortId, FALSE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA); + break; + case MVPP2_TAG_TYPE_DSA: + /* Add PortId to DSA entries */ + Mvpp2PrsDsaTagSet (Priv, PortId, TRUE, MVPP2_PRS_TAGGED, MVPP2_PRS_DSA); + Mvpp2PrsDsaTagSet (Priv, PortId, TRUE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA); + + /* Remove PortId from EDSA entries */ + Mvpp2PrsDsaTagSet (Priv, PortId, FALSE, MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA); + Mvpp2PrsDsaTagSet (Priv, PortId, FALSE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA); + break; + case MVPP2_TAG_TYPE_MH: + case MVPP2_TAG_TYPE_NONE: + /* Remove PortId form EDSA and DSA entries */ + Mvpp2PrsDsaTagSet (Priv, PortId, FALSE, MVPP2_PRS_TAGGED, MVPP2_PRS_DSA); + Mvpp2PrsDsaTagSet (Priv, PortId, FALSE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA); + Mvpp2PrsDsaTagSet (Priv, PortId, FALSE, MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA); + Mvpp2PrsDsaTagSet (Priv, PortId, FALSE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA); + break; + default: + if ((Type < 0) || (Type > MVPP2_TAG_TYPE_EDSA)) { + return MVPP2_EINVAL; + } + } + + return 0; +} + +/* Set prs Flow for the Port */ +INT32 +Mvpp2PrsDefFlow ( + IN PP2DXE_PORT *Port + ) +{ + MVPP2_PRS_ENTRY *Pe; + INT32 Tid; + + Pe = Mvpp2PrsFlowFind (Port->Priv, Port->Id); + + /* Such entry not exist */ + if (Pe == NULL) { + /* Go through the all entires from last to first */ + Tid = Mvpp2PrsTcamFirstFree (Port->Priv, MVPP2_PE_LAST_FREE_TID, MVPP2_PE_FIRST_FREE_TID); + if (Tid < 0) { + return Tid; + } + + Pe = Mvpp2Alloc (sizeof (*Pe)); + if (Pe == NULL) { + return MVPP2_ENOMEM; + } + + Mvpp2PrsTcamLuSet (Pe, MVPP2_PRS_LU_FLOWS); + Pe->Index = Tid; + + /* Set Flow ID*/ + Mvpp2PrsSramAiUpdate (Pe, Port->Id, MVPP2_PRS_FLOW_ID_MASK); + Mvpp2PrsSramBitsSet (Pe, MVPP2_PRS_SRAM_LU_DONE_BIT, 1); + + /* Update shadow table */ + Mvpp2PrsShadowSet (Port->Priv, Pe->Index, MVPP2_PRS_LU_FLOWS); + } + + Mvpp2PrsTcamPortMapSet (Pe, (1 << Port->Id)); + Mvpp2PrsHwWrite (Port->Priv, Pe); + Mvpp2Free (Pe); + + return 0; +} + +/* Classifier configuration routines */ + +/* Update classification Flow table RegValisters */ +STATIC +VOID +Mvpp2ClsFlowWrite ( + IN MVPP2_SHARED *Priv, + IN MVPP2_CLS_FLOW_ENTRY *Fe + ) +{ + Mvpp2Write (Priv, MVPP2_CLS_FLOW_INDEX_REG, Fe->Index); + Mvpp2Write (Priv, MVPP2_CLS_FLOW_TBL0_REG, Fe->Data[0]); + Mvpp2Write (Priv, MVPP2_CLS_FLOW_TBL1_REG, Fe->Data[1]); + Mvpp2Write (Priv, MVPP2_CLS_FLOW_TBL2_REG, Fe->Data[2]); +} + +/* Update classification lookup table RegValister */ +VOID +Mvpp2ClsLookupWrite ( + IN MVPP2_SHARED *Priv, + IN OUT MVPP2_CLS_LOOKUP_ENTRY *Le + ) +{ + UINT32 Val; + + Val = (Le->Way << MVPP2_CLS_LKP_INDEX_WAY_OFFS) | Le->Lkpid; + Mvpp2Write (Priv, MVPP2_CLS_LKP_INDEX_REG, Val); + Mvpp2Write (Priv, MVPP2_CLS_LKP_TBL_REG, Le->Data); +} + +/* Classifier default initialization */ +VOID +Mvpp2ClsInit ( + IN MVPP2_SHARED *Priv + ) +{ + MVPP2_CLS_LOOKUP_ENTRY Le; + MVPP2_CLS_FLOW_ENTRY Fe; + INT32 Index; + + /* Enable classifier */ + Mvpp2Write (Priv, MVPP2_CLS_MODE_REG, MVPP2_CLS_MODE_ACTIVE_MASK); + + /* Clear classifier Flow table */ + Mvpp2Memset (&Fe.Data, 0, MVPP2_CLS_FLOWS_TBL_DATA_WORDS); + for (Index = 0; Index < MVPP2_CLS_FLOWS_TBL_SIZE; Index++) { + Fe.Index = Index; + Mvpp2ClsFlowWrite (Priv, &Fe); + } + + /* Clear classifier lookup table */ + Le.Data = 0; + for (Index = 0; Index < MVPP2_CLS_LKP_TBL_SIZE; Index++) { + Le.Lkpid = Index; + Le.Way = 0; + Mvpp2ClsLookupWrite (Priv, &Le); + + Le.Way = 1; + Mvpp2ClsLookupWrite (Priv, &Le); + } +} + +VOID +Mvpp2ClsPortConfig ( + IN PP2DXE_PORT *Port + ) +{ + MVPP2_CLS_LOOKUP_ENTRY Le; + UINT32 Val; + + /* Set way for the Port */ + Val = Mvpp2Read (Port->Priv, MVPP2_CLS_PORT_WAY_REG); + Val &= ~MVPP2_CLS_PORT_WAY_MASK (Port->Id); + Mvpp2Write (Port->Priv, MVPP2_CLS_PORT_WAY_REG, Val); + + /* + * Pick the entry to be accessed in lookup ID decoding table + * according to the way and lkpid. + */ + Le.Lkpid = Port->Id; + Le.Way = 0; + Le.Data = 0; + + /* Set initial CPU Queue for receiving packets */ + Le.Data &= ~MVPP2_CLS_LKP_TBL_RXQ_MASK; + Le.Data |= Port->FirstRxq; + + /* Disable classification engines */ + Le.Data &= ~MVPP2_CLS_LKP_TBL_LOOKUP_EN_MASK; + + /* Update lookup ID table entry */ + Mvpp2ClsLookupWrite (Port->Priv, &Le); +} + +/* Set CPU Queue number for oversize packets */ +VOID +Mvpp2ClsOversizeRxqSet ( + IN PP2DXE_PORT *Port + ) +{ + + Mvpp2Write ( + Port->Priv, + MVPP2_CLS_OVERSIZE_RXQ_LOW_REG(Port->Id), + Port->FirstRxq & MVPP2_CLS_OVERSIZE_RXQ_LOW_MASK + ); +} + +/* BM helper routines */ + +VOID +Mvpp2BmPoolHwCreate ( + IN MVPP2_SHARED *Priv, + IN MVPP2_BMS_POOL *BmPool, + IN INT32 Size + ) +{ + BmPool->Size = Size; + + Mvpp2Write (Priv, MVPP2_BM_POOL_BASE_REG(BmPool->Id), Lower32Bits (BmPool->PhysAddr)); + Mvpp2Write (Priv, MVPP22_BM_POOL_BASE_HIGH_REG, (Upper32Bits (BmPool->PhysAddr) & MVPP22_BM_POOL_BASE_HIGH_REG)); + Mvpp2Write (Priv, MVPP2_BM_POOL_SIZE_REG(BmPool->Id), BmPool->Size); +} + +/* Set Pool buffer Size */ +VOID +Mvpp2BmPoolBufsizeSet ( + IN MVPP2_SHARED *Priv, + IN MVPP2_BMS_POOL *BmPool, + IN INT32 BufSize + ) +{ + UINT32 Val; + + BmPool->BufSize = BufSize; + + Val = MVPP2_ALIGN (BufSize, 1 << MVPP2_POOL_BUF_SIZE_OFFSET); + Mvpp2Write (Priv, MVPP2_POOL_BUF_SIZE_REG(BmPool->Id), Val); +} + +VOID +Mvpp2BmStop ( + IN MVPP2_SHARED *Priv, + IN INT32 Pool + ) +{ + UINT32 Val, i; + + for (i = 0; i < MVPP2_BM_SIZE; i++) { + Mvpp2Read (Priv, MVPP2_BM_PHY_ALLOC_REG(0)); + } + + Val = Mvpp2Read (Priv, MVPP2_BM_POOL_CTRL_REG(Pool)); + Val |= MVPP2_BM_STOP_MASK; + Mvpp2Write (Priv, MVPP2_BM_POOL_CTRL_REG(Pool), Val); +} + +VOID +Mvpp2BmIrqClear ( + IN MVPP2_SHARED *Priv, + IN INT32 Pool + ) +{ + /* Mask BM all interrupts */ + Mvpp2Write (Priv, MVPP2_BM_INTR_MASK_REG(Pool), 0); + + /* Clear BM cause RegValister */ + Mvpp2Write (Priv, MVPP2_BM_INTR_CAUSE_REG(Pool), 0); +} + +/* Attach long Pool to Rxq */ +VOID +Mvpp2RxqLongPoolSet ( + IN PP2DXE_PORT *Port, + IN INT32 Lrxq, + IN INT32 LongPool + ) +{ + UINT32 Val; + INT32 Prxq; + + /* Get Queue physical ID */ + Prxq = Port->Rxqs[Lrxq].Id; + + Val = Mvpp2Read (Port->Priv, MVPP2_RXQ_CONFIG_REG(Prxq)); + Val &= ~MVPP2_RXQ_POOL_LONG_MASK; + Val |= ((LongPool << MVPP2_RXQ_POOL_LONG_OFFS) & MVPP2_RXQ_POOL_LONG_MASK); + + Mvpp2Write (Port->Priv, MVPP2_RXQ_CONFIG_REG(Prxq), Val); +} + +/* Attach short Pool to Rxq */ +VOID +Mvpp2RxqShortPoolSet ( + IN PP2DXE_PORT *Port, + IN INT32 Lrxq, + IN INT32 ShortPool + ) +{ + UINT32 Val; + INT32 Prxq; + + /* Get Queue physical ID */ + Prxq = Port->Rxqs[Lrxq].Id; + + Val = Mvpp2Read (Port->Priv, MVPP2_RXQ_CONFIG_REG(Prxq)); + Val &= ~MVPP2_RXQ_POOL_SHORT_MASK; + Val |= ((ShortPool << MVPP2_RXQ_POOL_SHORT_OFFS) & MVPP2_RXQ_POOL_SHORT_MASK); + + Mvpp2Write (Port->Priv, MVPP2_RXQ_CONFIG_REG(Prxq), Val); +} + +/* Release multicast buffer */ +VOID +Mvpp2BmPoolMcPut ( + IN PP2DXE_PORT *Port, + IN INT32 Pool, + IN UINT32 BufPhysAddr, + IN UINT32 BufVirtAddr, + IN INT32 McId + ) +{ + UINT32 Val = 0; + + Val |= (McId & MVPP2_BM_MC_ID_MASK); + Mvpp2Write (Port->Priv, MVPP2_BM_MC_RLS_REG, Val); + + Mvpp2BmPoolPut (Port->Priv, Pool, BufPhysAddr | MVPP2_BM_PHY_RLS_MC_BUFF_MASK, BufVirtAddr); +} + +/* Refill BM Pool */ +VOID +Mvpp2PoolRefill ( + IN PP2DXE_PORT *Port, + IN UINT32 Bm, + IN UINT32 PhysAddr, + IN UINT32 cookie + ) +{ + INT32 Pool = Mvpp2BmCookiePoolGet (Bm); + + Mvpp2BmPoolPut (Port->Priv, Pool, PhysAddr, cookie); +} + +INTN +Mvpp2BmPoolCtrl ( + IN MVPP2_SHARED *Priv, + IN INTN Pool, + IN enum Mvpp2Command Cmd + ) +{ + UINT32 RegVal = 0; + RegVal = Mvpp2Read (Priv, MVPP2_BM_POOL_CTRL_REG(Pool)); + + switch (Cmd) { + case MVPP2_START: + RegVal |= MVPP2_BM_START_MASK; + break; + + case MVPP2_STOP: + RegVal |= MVPP2_BM_STOP_MASK; + break; + + default: + return -1; + } + Mvpp2Write (Priv, MVPP2_BM_POOL_CTRL_REG(Pool), RegVal); + + return 0; +} + +/* Mask the current CPU's Rx/Tx interrupts */ +VOID +Mvpp2InterruptsMask ( + IN VOID *arg + ) +{ + PP2DXE_PORT *Port = arg; + + Mvpp2Write (Port->Priv, MVPP2_ISR_RX_TX_MASK_REG(Port->Id), 0); +} + +/* Unmask the current CPU's Rx/Tx interrupts */ +VOID +Mvpp2InterruptsUnmask ( + IN VOID *arg + ) +{ + PP2DXE_PORT *Port = arg; + + Mvpp2Write ( + Port->Priv, + MVPP2_ISR_RX_TX_MASK_REG(Port->Id), + (MVPP2_CAUSE_MISC_SUM_MASK | MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK) + ); +} + +/* MAC configuration routines */ + +STATIC +VOID +Mvpp2PortMiiSet ( + IN PP2DXE_PORT *Port + ) +{ + UINT32 Val; + + Val = Mvpp2GmacRead (Port, MVPP2_GMAC_CTRL_2_REG); + + switch (Port->PhyInterface) { + case MV_MODE_SGMII: + Val |= MVPP2_GMAC_INBAND_AN_MASK; + break; + case MV_MODE_RGMII: + Val |= MVPP2_GMAC_PORT_RGMII_MASK; + default: + Val &= ~MVPP2_GMAC_PCS_ENABLE_MASK; + } + + Mvpp2GmacWrite (Port, MVPP2_GMAC_CTRL_2_REG, Val); +} + +STATIC +VOID Mvpp2PortFcAdvEnable ( + IN PP2DXE_PORT *Port + ) +{ + UINT32 Val; + + Val = Mvpp2GmacRead (Port, MVPP2_GMAC_AUTONEG_CONFIG); + Val |= MVPP2_GMAC_FC_ADV_EN; + Mvpp2GmacWrite (Port, MVPP2_GMAC_AUTONEG_CONFIG, Val); +} + +VOID +Mvpp2PortEnable ( + IN PP2DXE_PORT *Port + ) +{ + UINT32 Val; + + Val = Mvpp2GmacRead (Port, MVPP2_GMAC_CTRL_0_REG); + Val |= MVPP2_GMAC_PORT_EN_MASK; + Val |= MVPP2_GMAC_MIB_CNTR_EN_MASK; + Mvpp2GmacWrite (Port, MVPP2_GMAC_CTRL_0_REG, Val); +} + +VOID +Mvpp2PortDisable ( + IN PP2DXE_PORT *Port + ) +{ + UINT32 Val; + + Val = Mvpp2GmacRead (Port, MVPP2_GMAC_CTRL_0_REG); + Val &= ~(MVPP2_GMAC_PORT_EN_MASK); + Mvpp2GmacWrite (Port, MVPP2_GMAC_CTRL_0_REG, Val); +} + +/* Set IEEE 802.3x Flow Control Xon Packet Transmission Mode */ +STATIC +VOID +Mvpp2PortPeriodicXonDisable ( + IN PP2DXE_PORT *Port + ) +{ + UINT32 Val; + + Val = Mvpp2GmacRead (Port, MVPP2_GMAC_CTRL_1_REG) & ~MVPP2_GMAC_PERIODIC_XON_EN_MASK; + Mvpp2GmacWrite (Port, MVPP2_GMAC_CTRL_1_REG, Val); +} + +/* Configure loopback Port */ +STATIC +VOID +Mvpp2PortReset ( + IN PP2DXE_PORT *Port + ) +{ + UINT32 Val; + + Val = Mvpp2GmacRead (Port, MVPP2_GMAC_CTRL_2_REG) & ~MVPP2_GMAC_PORT_RESET_MASK; + Mvpp2GmacWrite (Port, MVPP2_GMAC_CTRL_2_REG, Val); + + while (Mvpp2GmacRead (Port, MVPP2_GMAC_CTRL_2_REG) & MVPP2_GMAC_PORT_RESET_MASK) { + continue; + } +} + +/* Set defaults to the MVPP2 Port */ +VOID +Mvpp2DefaultsSet ( + IN PP2DXE_PORT *Port + ) +{ + INT32 TxPortNum, Val, Queue, pTxq; + + /* Disable Legacy WRR, Disable EJP, Release from Reset */ + TxPortNum = Mvpp2EgressPort (Port); + Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, TxPortNum); + Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_CMD_1_REG, 0); + + /* Close bandwidth for all Queues */ + for (Queue = 0; Queue < MVPP2_MAX_TXQ; Queue++) { + pTxq = Mvpp2TxqPhys (Port->Id, Queue); + Mvpp2Write (Port->Priv, MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(pTxq), 0); + } + + + /* Set refill period to 1 Usec, refill tokens and bucket Size to maximum */ + Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_PERIOD_REG, Port->Priv->Tclk / MVPP2_USEC_PER_SEC); + Val = Mvpp2Read (Port->Priv, MVPP2_TXP_SCHED_REFILL_REG); + Val &= ~MVPP2_TXP_REFILL_PERIOD_ALL_MASK; + Val |= MVPP2_TXP_REFILL_PERIOD_MASK (1); + Val |= MVPP2_TXP_REFILL_TOKENS_ALL_MASK; + Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_REFILL_REG, Val); + Val = MVPP2_TXP_TOKEN_SIZE_MAX; + Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_TOKEN_SIZE_REG, Val); + + /* Set MaximumLowLatencyPacketSize value to 256 */ + Mvpp2Write ( + Port->Priv, + MVPP2_RX_CTRL_REG(Port->Id), + MVPP2_RX_USE_PSEUDO_FOR_CSUM_MASK | MVPP2_RX_LOW_LATENCY_PKT_SIZE (256) + ); + + /* Mask all interrupts to all present cpus */ + Mvpp2InterruptsDisable (Port, 0x1); +} + +/* Enable/disable receiving packets */ +VOID +Mvpp2IngressEnable ( + IN PP2DXE_PORT *Port + ) +{ + UINT32 Val; + INT32 Lrxq, Queue; + + for (Lrxq = 0; Lrxq < RxqNumber; Lrxq++) { + Queue = Port->Rxqs[Lrxq].Id; + Val = Mvpp2Read (Port->Priv, MVPP2_RXQ_CONFIG_REG(Queue)); + Val &= ~MVPP2_RXQ_DISABLE_MASK; + Mvpp2Write (Port->Priv, MVPP2_RXQ_CONFIG_REG(Queue), Val); + } +} + +VOID +Mvpp2IngressDisable ( + IN PP2DXE_PORT *Port + ) +{ + UINT32 Val; + INT32 Lrxq, Queue; + + for (Lrxq = 0; Lrxq < RxqNumber; Lrxq++) { + Queue = Port->Rxqs[Lrxq].Id; + Val = Mvpp2Read (Port->Priv, MVPP2_RXQ_CONFIG_REG(Queue)); + Val |= MVPP2_RXQ_DISABLE_MASK; + Mvpp2Write (Port->Priv, MVPP2_RXQ_CONFIG_REG(Queue), Val); + } +} + +/* Enable transmit via physical egress Queue - HW starts take descriptors from DRAM */ +VOID +Mvpp2EgressEnable ( + IN PP2DXE_PORT *Port + ) +{ + UINT32 qmap; + INT32 Queue; + INT32 TxPortNum = Mvpp2EgressPort (Port); + + /* Enable all initialized TXs. */ + qmap = 0; + for (Queue = 0; Queue < TxqNumber; Queue++) { + MVPP2_TX_QUEUE *Txq = &Port->Txqs[Queue]; + + if (Txq->Descs != NULL) { + qmap |= (1 << Queue); + } + } + + Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, TxPortNum); + Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_Q_CMD_REG, qmap); +} + +/* Disable transmit via physical egress Queue - HW doesn't take descriptors from DRAM */ +VOID +Mvpp2EgressDisable ( + IN PP2DXE_PORT *Port + ) +{ + UINT32 RegData; + INT32 Delay; + INT32 TxPortNum = Mvpp2EgressPort (Port); + + /* Issue stop command for active channels only */ + Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, TxPortNum); + RegData = (Mvpp2Read (Port->Priv, MVPP2_TXP_SCHED_Q_CMD_REG)) & MVPP2_TXP_SCHED_ENQ_MASK; + if (RegData != 0) { + Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_Q_CMD_REG, (RegData << MVPP2_TXP_SCHED_DISQ_OFFSET)); + } + + /* Wait for all Tx activity to terminate. */ + Delay = 0; + do { + if (Delay >= MVPP2_TX_DISABLE_TIMEOUT_MSEC) { + Mvpp2Printf ("Tx stop timed out, status=0x%08x\n", RegData); + break; + } + Mvpp2Mdelay (1); + Delay++; + + /* Check Port TX Command RegValister that all Tx Queues are stopped */ + RegData = Mvpp2Read (Port->Priv, MVPP2_TXP_SCHED_Q_CMD_REG); + } while (RegData & MVPP2_TXP_SCHED_ENQ_MASK); +} + +/* Rx descriptors helper methods */ + +/* Set rx Queue Offset */ +STATIC +VOID +Mvpp2RxqOffsetSet ( + IN PP2DXE_PORT *Port, + IN INT32 Prxq, + IN INT32 Offset + ) +{ + UINT32 Val; + + /* Convert Offset from bytes to units of 32 bytes */ + Offset = Offset >> 5; + + /* Clear previous value */ + Val = Mvpp2Read (Port->Priv, MVPP2_RXQ_CONFIG_REG(Prxq)); + Val &= ~MVPP2_RXQ_PACKET_OFFSET_MASK; + + /* Update packet Offset in received buffer */ + Val |= ((Offset << MVPP2_RXQ_PACKET_OFFSET_OFFS) & MVPP2_RXQ_PACKET_OFFSET_MASK); + Mvpp2Write (Port->Priv, MVPP2_RXQ_CONFIG_REG(Prxq), Val); +} + +/* Obtain BM cookie information from descriptor */ +UINT32 +Mvpp2BmCookieBuild ( + IN MVPP2_RX_DESC *RxDesc, + IN INT32 Cpu + ) +{ + INT32 Pool; + UINT32 ret; + + Pool = (RxDesc->status & MVPP2_RXD_BM_POOL_ID_MASK) >> MVPP2_RXD_BM_POOL_ID_OFFS; + + ret = ((Pool & 0xFF) << MVPP2_BM_COOKIE_POOL_OFFS) | ((Cpu & 0xFF) << MVPP2_BM_COOKIE_CPU_OFFS); + + return ret; +} + +/* Tx descriptors helper methods */ + +INT32 +Mvpp2TxqDrainSet ( + IN PP2DXE_PORT *Port, + IN INT32 Txq, + IN BOOLEAN En + ) +{ + UINT32 RegVal; + INT32 pTxq = Mvpp2TxqPhys (Port->Id, Txq); + + Mvpp2Write (Port->Priv, MVPP2_TXQ_NUM_REG, pTxq); + RegVal = Mvpp2Read (Port->Priv, MVPP2_TXQ_PREF_BUF_REG); + + if (En) { + RegVal |= MVPP2_TXQ_DRAIN_EN_MASK; + } else { + RegVal &= ~MVPP2_TXQ_DRAIN_EN_MASK; + } + + Mvpp2Write (Port->Priv, MVPP2_TXQ_PREF_BUF_REG, RegVal); + + return 0; +} + +/* Get number of Tx descriptors waiting to be transmitted by HW */ +INT32 +Mvpp2TxqPendDescNumGet ( + IN PP2DXE_PORT *Port, + IN MVPP2_TX_QUEUE *Txq + ) +{ + UINT32 Val; + + Mvpp2Write (Port->Priv, MVPP2_TXQ_NUM_REG, Txq->Id); + Val = Mvpp2Read (Port->Priv, MVPP2_TXQ_PENDING_REG); + + return Val & MVPP2_TXQ_PENDING_MASK; +} + +/* Get number of occupied aggRegValated Tx descriptors */ +UINT32 +Mvpp2AggrTxqPendDescNumGet ( + IN MVPP2_SHARED *Priv, + IN INT32 Cpu + ) +{ + UINT32 RegVal; + + RegVal = Mvpp2Read (Priv, MVPP2_AGGR_TXQ_STATUS_REG(Cpu)); + + return RegVal & MVPP2_AGGR_TXQ_PENDING_MASK; +} + +/* Get pointer to next Tx descriptor to be processed (send) by HW */ +MVPP2_TX_DESC * +Mvpp2TxqNextDescGet ( + MVPP2_TX_QUEUE *Txq + ) +{ + INT32 TxDesc = Txq->NextDescToProc; + + Txq->NextDescToProc = MVPP2_QUEUE_NEXT_DESC (Txq, TxDesc); + + return Txq->Descs + TxDesc; +} + +/* Update HW with number of aggRegValated Tx descriptors to be sent */ +VOID +Mvpp2AggrTxqPendDescAdd ( + IN PP2DXE_PORT *Port, + IN INT32 Pending + ) +{ + /* AggRegValated access - relevant TXQ number is written in TX desc */ + Mvpp2Write (Port->Priv, MVPP2_AGGR_TXQ_UPDATE_REG, Pending); +} + +/* + * Check if there are enough free descriptors in aggRegValated Txq. + * If not, update the number of occupied descriptors and repeat the check. + */ +INT32 +Mvpp2AggrDescNumCheck ( + IN MVPP2_SHARED *Priv, + IN MVPP2_TX_QUEUE *AggrTxq, + IN INT32 Num, + IN INT32 Cpu + ) +{ + UINT32 Val; + + if ((AggrTxq->count + Num) > AggrTxq->Size) { + /* Update number of occupied aggRegValated Tx descriptors */ + Val = Mvpp2Read (Priv, MVPP2_AGGR_TXQ_STATUS_REG(Cpu)); + AggrTxq->count = Val & MVPP2_AGGR_TXQ_PENDING_MASK; + } + + if ((AggrTxq->count + Num) > AggrTxq->Size) { + return MVPP2_ENOMEM; + } + + return 0; +} + +/* Reserved Tx descriptors allocation request */ +INT32 +Mvpp2TxqAllocReservedDesc ( + IN MVPP2_SHARED *Priv, + IN MVPP2_TX_QUEUE *Txq, + IN INT32 Num + ) +{ + UINT32 Val; + + Val = (Txq->Id << MVPP2_TXQ_RSVD_REQ_Q_OFFSET) | Num; + Mvpp2Write (Priv, MVPP2_TXQ_RSVD_REQ_REG, Val); + + Val = Mvpp2Read (Priv, MVPP2_TXQ_RSVD_RSLT_REG); + + return Val & MVPP2_TXQ_RSVD_RSLT_MASK; +} + +/* + * Release the last allocated Tx descriptor. Useful to handle DMA + * mapping failures in the Tx path. + */ +VOID +Mvpp2TxqDescPut ( + IN MVPP2_TX_QUEUE *Txq + ) +{ + if (Txq->NextDescToProc == 0) { + Txq->NextDescToProc = Txq->LastDesc - 1; + } else { + Txq->NextDescToProc--; + } +} + +/* Set Tx descriptors fields relevant for CSUM calculation */ +UINT32 +Mvpp2TxqDescCsum ( + IN INT32 L3Offs, + IN INT32 L3Proto, + IN INT32 IpHdrLen, + IN INT32 L4Proto + ) +{ + UINT32 command; + + /* + * Fields: L3_Offset, IP_hdrlen, L3_type, G_IPV4Chk, + * G_L4_chk, L4_type required only for checksum calculation + */ + command = (L3Offs << MVPP2_TXD_L3_OFF_SHIFT); + command |= (IpHdrLen << MVPP2_TXD_IP_HLEN_SHIFT); + command |= MVPP2_TXD_IP_CSUM_DISABLE; + + if (L3Proto == Mvpp2SwapBytes16 (MV_ETH_P_IP)) { + command &= ~MVPP2_TXD_IP_CSUM_DISABLE; /* enable IPv4 csum */ + command &= ~MVPP2_TXD_L3_IP6; /* enable IPv4 */ + } else { + command |= MVPP2_TXD_L3_IP6; /* enable IPv6 */ + } + + if (L4Proto == MV_IPPR_TCP) { + command &= ~MVPP2_TXD_L4_UDP; /* enable TCP */ + command &= ~MVPP2_TXD_L4_CSUM_FRAG; /* generate L4 csum */ + } else if (L4Proto == MV_IPPR_UDP) { + command |= MVPP2_TXD_L4_UDP; /* enable UDP */ + command &= ~MVPP2_TXD_L4_CSUM_FRAG; /* generate L4 csum */ + } else { + command |= MVPP2_TXD_L4_CSUM_NOT; + } + + return command; +} + +/* Clear counter of sent packets */ +VOID +Mvpp2TxqSentCounterClear ( + IN OUT VOID *arg + ) +{ + PP2DXE_PORT *Port = arg; + INT32 Queue; + + for (Queue = 0; Queue < TxqNumber; Queue++) { + INT32 Id = Port->Txqs[Queue].Id; + + Mvpp2Read (Port->Priv, MVPP2_TXQ_SENT_REG(Id)); + } +} + +/* Change maximum receive Size of the Port */ +VOID +Mvpp2GmacMaxRxSizeSet ( + IN PP2DXE_PORT *Port + ) +{ + UINT32 Val; + + Val = Mvpp2GmacRead (Port, MVPP2_GMAC_CTRL_0_REG); + Val &= ~MVPP2_GMAC_MAX_RX_SIZE_MASK; + Val |= (((Port->PktSize - MVPP2_MH_SIZE) / 2) << MVPP2_GMAC_MAX_RX_SIZE_OFFS); + Mvpp2GmacWrite (Port, MVPP2_GMAC_CTRL_0_REG, Val); +} + +/* Set max sizes for Tx Queues */ +VOID +Mvpp2TxpMaxTxSizeSet ( + IN PP2DXE_PORT *Port + ) +{ + UINT32 Val, Size, mtu; + INT32 Txq, TxPortNum; + + mtu = Port->PktSize * 8; + if (mtu > MVPP2_TXP_MTU_MAX) { + mtu = MVPP2_TXP_MTU_MAX; + } + + /* WA for wrong Token bucket update: Set MTU value = 3*real MTU value */ + mtu = 3 * mtu; + + /* Indirect access to RegValisters */ + TxPortNum = Mvpp2EgressPort (Port); + Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, TxPortNum); + + /* Set MTU */ + Val = Mvpp2Read (Port->Priv, MVPP2_TXP_SCHED_MTU_REG); + Val &= ~MVPP2_TXP_MTU_MAX; + Val |= mtu; + Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_MTU_REG, Val); + + /* TXP token Size and all TXQs token Size must be larger that MTU */ + Val = Mvpp2Read (Port->Priv, MVPP2_TXP_SCHED_TOKEN_SIZE_REG); + Size = Val & MVPP2_TXP_TOKEN_SIZE_MAX; + if (Size < mtu) { + Size = mtu; + Val &= ~MVPP2_TXP_TOKEN_SIZE_MAX; + Val |= Size; + Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_TOKEN_SIZE_REG, Val); + } + + for (Txq = 0; Txq < TxqNumber; Txq++) { + Val = Mvpp2Read (Port->Priv, MVPP2_TXQ_SCHED_TOKEN_SIZE_REG(Txq)); + Size = Val & MVPP2_TXQ_TOKEN_SIZE_MAX; + + if (Size < mtu) { + Size = mtu; + Val &= ~MVPP2_TXQ_TOKEN_SIZE_MAX; + Val |= Size; + Mvpp2Write (Port->Priv, MVPP2_TXQ_SCHED_TOKEN_SIZE_REG(Txq), Val); + } + } +} + +/* + * Set the number of packets that will be received before Rx interrupt + * will be generated by HW. + */ +VOID +Mvpp2RxPktsCoalSet ( + IN PP2DXE_PORT *Port, + IN OUT MVPP2_RX_QUEUE *Rxq, + IN UINT32 Pkts + ) +{ + UINT32 Val; + + Val = (Pkts & MVPP2_OCCUPIED_THRESH_MASK); + Mvpp2Write (Port->Priv, MVPP2_RXQ_NUM_REG, Rxq->Id); + Mvpp2Write (Port->Priv, MVPP2_RXQ_THRESH_REG, Val); + + Rxq->PktsCoal = Pkts; +} + +/* Set the time Delay in Usec before Rx INT32errupt */ +VOID +Mvpp2RxTimeCoalSet ( + IN PP2DXE_PORT *Port, + IN OUT MVPP2_RX_QUEUE *Rxq, + IN UINT32 Usec + ) +{ + UINT32 Val; + + Val = (Port->Priv->Tclk / MVPP2_USEC_PER_SEC) * Usec; + Mvpp2Write (Port->Priv, MVPP2_ISR_RX_THRESHOLD_REG(Rxq->Id), Val); + + Rxq->TimeCoal = Usec; +} + +/* Rx/Tx Queue initialization/cleanup methods */ + +/* Configure RXQ's */ +VOID +Mvpp2RxqHwInit ( + IN PP2DXE_PORT *Port, + IN OUT MVPP2_RX_QUEUE *Rxq + ) +{ + Rxq->LastDesc = Rxq->Size - 1; + + /* Zero occupied and non-occupied counters - direct access */ + Mvpp2Write (Port->Priv, MVPP2_RXQ_STATUS_REG(Rxq->Id), 0); + + /* Set Rx descriptors Queue starting Address - indirect access */ + Mvpp2Write (Port->Priv, MVPP2_RXQ_NUM_REG, Rxq->Id); + Mvpp2Write (Port->Priv, MVPP2_RXQ_DESC_ADDR_REG, Rxq->DescsPhys >> MVPP22_DESC_ADDR_SHIFT); + Mvpp2Write (Port->Priv, MVPP2_RXQ_DESC_SIZE_REG, Rxq->Size); + Mvpp2Write (Port->Priv, MVPP2_RXQ_INDEX_REG, 0); + + /* Set Offset */ + Mvpp2RxqOffsetSet (Port, Rxq->Id, MVPP2_RXQ_OFFSET); + + /* Set coalescing pkts and time */ + Mvpp2RxPktsCoalSet (Port, Rxq, MVPP2_RX_COAL_PKTS); + Mvpp2RxTimeCoalSet (Port, Rxq, Rxq->TimeCoal); + + /* Add number of descriptors ready for receiving packets */ + Mvpp2RxqStatusUpdate (Port, Rxq->Id, 0, Rxq->Size); +} + +/* Push packets received by the RXQ to BM Pool */ +VOID +Mvpp2RxqDropPkts ( + IN PP2DXE_PORT *Port, + IN OUT MVPP2_RX_QUEUE *Rxq, + IN INT32 Cpu + ) +{ + INT32 RxReceived; + + RxReceived = Mvpp2RxqReceived (Port, Rxq->Id); + if (!RxReceived) { + return; + } + + Mvpp2RxqStatusUpdate (Port, Rxq->Id, RxReceived, RxReceived); +} + +VOID +Mvpp2RxqHwDeinit ( + IN PP2DXE_PORT *Port, + IN OUT MVPP2_RX_QUEUE *Rxq + ) +{ + Rxq->Descs = NULL; + Rxq->LastDesc = 0; + Rxq->NextDescToProc = 0; + Rxq->DescsPhys = 0; + + /* + * Clear Rx descriptors Queue starting Address and Size; + * free descriptor number + */ + Mvpp2Write (Port->Priv, MVPP2_RXQ_STATUS_REG(Rxq->Id), 0); + Mvpp2Write (Port->Priv, MVPP2_RXQ_NUM_REG, Rxq->Id); + Mvpp2Write (Port->Priv, MVPP2_RXQ_DESC_ADDR_REG, 0); + Mvpp2Write (Port->Priv, MVPP2_RXQ_DESC_SIZE_REG, 0); +} + +/* Configure TXQ's */ +VOID +Mvpp2TxqHwInit ( + IN PP2DXE_PORT *Port, + IN OUT MVPP2_TX_QUEUE *Txq + ) +{ + INT32 Desc, DescPerTxq, TxPortNum; + UINT32 Val; + + Txq->LastDesc = Txq->Size - 1; + + /* Set Tx descriptors Queue starting Address - indirect access */ + Mvpp2Write (Port->Priv, MVPP2_TXQ_NUM_REG, Txq->Id); + Mvpp2Write (Port->Priv, MVPP2_TXQ_DESC_ADDR_REG, Txq->DescsPhys); + Mvpp2Write (Port->Priv, MVPP2_TXQ_DESC_SIZE_REG, Txq->Size & MVPP2_TXQ_DESC_SIZE_MASK); + Mvpp2Write (Port->Priv, MVPP2_TXQ_INDEX_REG, 0); + Mvpp2Write (Port->Priv, MVPP2_TXQ_RSVD_CLR_REG, Txq->Id << MVPP2_TXQ_RSVD_CLR_OFFSET); + Val = Mvpp2Read (Port->Priv, MVPP2_TXQ_PENDING_REG); + Val &= ~MVPP2_TXQ_PENDING_MASK; + Mvpp2Write (Port->Priv, MVPP2_TXQ_PENDING_REG, Val); + + /* + * Calculate base Address in prefetch buffer. We reserve 16 descriptors + * for each existing TXQ. + * TCONTS for PON Port must be continuous from 0 to MVPP2_MAX_TCONT + * GBE Ports assumed to be continious from 0 to MVPP2_MAX_PORTS + */ + DescPerTxq = 16; + Desc = (Port->Id * MVPP2_MAX_TXQ * DescPerTxq) + (Txq->LogId * DescPerTxq); + + Mvpp2Write ( + Port->Priv, + MVPP2_TXQ_PREF_BUF_REG, + MVPP2_PREF_BUF_PTR (Desc) | MVPP2_PREF_BUF_SIZE_16 | MVPP2_PREF_BUF_THRESH (DescPerTxq/2) + ); + + /* WRR / EJP configuration - indirect access */ + TxPortNum = Mvpp2EgressPort (Port); + Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, TxPortNum); + + Val = Mvpp2Read (Port->Priv, MVPP2_TXQ_SCHED_REFILL_REG(Txq->LogId)); + Val &= ~MVPP2_TXQ_REFILL_PERIOD_ALL_MASK; + Val |= MVPP2_TXQ_REFILL_PERIOD_MASK (1); + Val |= MVPP2_TXQ_REFILL_TOKENS_ALL_MASK; + Mvpp2Write (Port->Priv, MVPP2_TXQ_SCHED_REFILL_REG(Txq->LogId), Val); + + Val = MVPP2_TXQ_TOKEN_SIZE_MAX; + Mvpp2Write (Port->Priv, MVPP2_TXQ_SCHED_TOKEN_SIZE_REG(Txq->LogId), Val); +} + +VOID +Mvpp2TxqHwDeinit ( + IN PP2DXE_PORT *Port, + IN OUT MVPP2_TX_QUEUE *Txq + ) +{ + Txq->Descs = NULL; + Txq->LastDesc = 0; + Txq->NextDescToProc = 0; + Txq->DescsPhys = 0; + + /* Set minimum bandwidth for disabled TXQs */ + Mvpp2Write (Port->Priv, MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(Txq->Id), 0); + + /* Set Tx descriptors Queue starting Address and Size */ + Mvpp2Write (Port->Priv, MVPP2_TXQ_NUM_REG, Txq->Id); + Mvpp2Write (Port->Priv, MVPP2_TXQ_DESC_ADDR_REG, 0); + Mvpp2Write (Port->Priv, MVPP2_TXQ_DESC_SIZE_REG, 0); +} + +/* Allocate and initialize descriptors for aggr TXQ */ +VOID +Mvpp2AggrTxqHwInit ( + IN OUT MVPP2_TX_QUEUE *AggrTxq, + IN INT32 DescNum, + IN INT32 Cpu, + IN MVPP2_SHARED *Priv + ) +{ + AggrTxq->LastDesc = AggrTxq->Size - 1; + + /* Aggr TXQ no Reset WA */ + AggrTxq->NextDescToProc = Mvpp2Read (Priv, MVPP2_AGGR_TXQ_INDEX_REG(Cpu)); + + /* Set Tx descriptors Queue starting Address (indirect access) */ + Mvpp2Write (Priv, MVPP2_AGGR_TXQ_DESC_ADDR_REG(Cpu), AggrTxq->DescsPhys >> MVPP22_DESC_ADDR_SHIFT); + Mvpp2Write (Priv, MVPP2_AGGR_TXQ_DESC_SIZE_REG(Cpu), DescNum & MVPP2_AGGR_TXQ_DESC_SIZE_MASK); +} + +/* Enable gmac */ +VOID +Mvpp2PortPowerUp ( + IN PP2DXE_PORT *Port + ) +{ + Mvpp2PortMiiSet (Port); + Mvpp2PortPeriodicXonDisable (Port); + Mvpp2PortFcAdvEnable (Port); + Mvpp2PortReset (Port); +} + +/* Initialize Rx FIFO's */ +VOID +Mvpp2RxFifoInit ( + IN MVPP2_SHARED *Priv + ) +{ + INT32 PortId; + + for (PortId = 0; PortId < MVPP2_MAX_PORTS; PortId++) { + Mvpp2Write (Priv, MVPP2_RX_DATA_FIFO_SIZE_REG(PortId), MVPP2_RX_FIFO_PORT_DATA_SIZE); + Mvpp2Write (Priv, MVPP2_RX_ATTR_FIFO_SIZE_REG(PortId), MVPP2_RX_FIFO_PORT_ATTR_SIZE); + } + + Mvpp2Write (Priv, MVPP2_RX_MIN_PKT_SIZE_REG, MVPP2_RX_FIFO_PORT_MIN_PKT); + Mvpp2Write (Priv, MVPP2_RX_FIFO_INIT_REG, 0x1); +} + +VOID +MvGop110NetcActivePort ( + IN PP2DXE_PORT *Port, + IN UINT32 PortId, + IN UINT32 Val + ) +{ + UINT32 RegVal; + + RegVal = Mvpp2Rfu1Read (Port->Priv, MV_NETCOMP_PORTS_CONTROL_1); + RegVal &= ~(NETC_PORTS_ACTIVE_MASK (PortId)); + + Val <<= NETC_PORTS_ACTIVE_OFFSET (PortId); + Val &= NETC_PORTS_ACTIVE_MASK (PortId); + + RegVal |= Val; + + Mvpp2Rfu1Write (Port->Priv, MV_NETCOMP_PORTS_CONTROL_1, RegVal); +} + +STATIC +VOID +MvGop110NetcXauiEnable ( + IN PP2DXE_PORT *Port, + IN UINT32 PortId, + IN UINT32 Val + ) +{ + UINT32 RegVal; + + RegVal = Mvpp2Rfu1Read (Port->Priv, SD1_CONTROL_1_REG); + RegVal &= ~SD1_CONTROL_XAUI_EN_MASK; + + Val <<= SD1_CONTROL_XAUI_EN_OFFSET; + Val &= SD1_CONTROL_XAUI_EN_MASK; + + RegVal |= Val; + + Mvpp2Rfu1Write (Port->Priv, SD1_CONTROL_1_REG, RegVal); +} + +STATIC +VOID +MvGop110NetcRxaui0Enable ( + IN PP2DXE_PORT *Port, + IN UINT32 PortId, + IN UINT32 Val + ) +{ + UINT32 RegVal; + + RegVal = Mvpp2Rfu1Read (Port->Priv, SD1_CONTROL_1_REG); + RegVal &= ~SD1_CONTROL_RXAUI0_L23_EN_MASK; + + Val <<= SD1_CONTROL_RXAUI0_L23_EN_OFFSET; + Val &= SD1_CONTROL_RXAUI0_L23_EN_MASK; + + RegVal |= Val; + + Mvpp2Rfu1Write (Port->Priv, SD1_CONTROL_1_REG, RegVal); +} + +STATIC +VOID +MvGop110NetcRxaui1Enable ( + IN PP2DXE_PORT *Port, + IN UINT32 PortId, + IN UINT32 Val + ) +{ + UINT32 RegVal; + + RegVal = Mvpp2Rfu1Read (Port->Priv, SD1_CONTROL_1_REG); + RegVal &= ~SD1_CONTROL_RXAUI1_L45_EN_MASK; + + Val <<= SD1_CONTROL_RXAUI1_L45_EN_OFFSET; + Val &= SD1_CONTROL_RXAUI1_L45_EN_MASK; + + RegVal |= Val; + + Mvpp2Rfu1Write (Port->Priv, SD1_CONTROL_1_REG, RegVal); +} + +STATIC +VOID +MvGop110NetcMiiMode ( + IN PP2DXE_PORT *Port, + IN UINT32 PortId, + IN UINT32 Val + ) +{ + UINT32 RegVal; + + RegVal = Mvpp2Rfu1Read (Port->Priv, MV_NETCOMP_CONTROL_0); + RegVal &= ~NETC_GBE_PORT1_MII_MODE_MASK; + + Val <<= NETC_GBE_PORT1_MII_MODE_OFFSET; + Val &= NETC_GBE_PORT1_MII_MODE_MASK; + + RegVal |= Val; + + Mvpp2Rfu1Write (Port->Priv, MV_NETCOMP_CONTROL_0, RegVal); +} + +STATIC +VOID +MvGop110NetcGopReset ( + IN PP2DXE_PORT *Port, + IN UINT32 Val + ) +{ + UINT32 RegVal; + + RegVal = Mvpp2Rfu1Read (Port->Priv, MV_GOP_SOFT_RESET_1_REG); + RegVal &= ~NETC_GOP_SOFT_RESET_MASK; + + Val <<= NETC_GOP_SOFT_RESET_OFFSET; + Val &= NETC_GOP_SOFT_RESET_MASK; + + RegVal |= Val; + + Mvpp2Rfu1Write (Port->Priv, MV_GOP_SOFT_RESET_1_REG, RegVal); +} + +STATIC +VOID +MvGop110NetcGopClockLogicSet ( + IN PP2DXE_PORT *Port, + IN UINT32 Val + ) +{ + UINT32 RegVal; + + RegVal = Mvpp2Rfu1Read (Port->Priv, MV_NETCOMP_PORTS_CONTROL_0); + RegVal &= ~NETC_CLK_DIV_PHASE_MASK; + + Val <<= NETC_CLK_DIV_PHASE_OFFSET; + Val &= NETC_CLK_DIV_PHASE_MASK; + + RegVal |= Val; + + Mvpp2Rfu1Write (Port->Priv, MV_NETCOMP_PORTS_CONTROL_0, RegVal); +} + +STATIC +VOID +MvGop110NetcPortRfReset ( + IN PP2DXE_PORT *Port, + IN UINT32 PortId, + IN UINT32 Val + ) +{ + UINT32 RegVal; + + RegVal = Mvpp2Rfu1Read (Port->Priv, MV_NETCOMP_PORTS_CONTROL_1); + RegVal &= ~(NETC_PORT_GIG_RF_RESET_MASK (PortId)); + + Val <<= NETC_PORT_GIG_RF_RESET_OFFSET (PortId); + Val &= NETC_PORT_GIG_RF_RESET_MASK (PortId); + + RegVal |= Val; + + Mvpp2Rfu1Write (Port->Priv, MV_NETCOMP_PORTS_CONTROL_1, RegVal); +} + +STATIC +VOID +MvGop110NetcGbeSgmiiModeSelect ( + IN PP2DXE_PORT *Port, + IN UINT32 PortId, + IN UINT32 Val + ) +{ + UINT32 RegVal, Mask, Offset; + + if (PortId == 2) { + Mask = NETC_GBE_PORT0_SGMII_MODE_MASK; + Offset = NETC_GBE_PORT0_SGMII_MODE_OFFSET; + } else { + Mask = NETC_GBE_PORT1_SGMII_MODE_MASK; + Offset = NETC_GBE_PORT1_SGMII_MODE_OFFSET; + } + RegVal = Mvpp2Rfu1Read (Port->Priv, MV_NETCOMP_CONTROL_0); + RegVal &= ~Mask; + + Val <<= Offset; + Val &= Mask; + + RegVal |= Val; + + Mvpp2Rfu1Write (Port->Priv, MV_NETCOMP_CONTROL_0, RegVal); +} + +STATIC +VOID +MvGop110NetcBusWidthSelect ( + IN PP2DXE_PORT *Port, + IN UINT32 Val + ) +{ + UINT32 RegVal; + + RegVal = Mvpp2Rfu1Read (Port->Priv, MV_NETCOMP_PORTS_CONTROL_0); + RegVal &= ~NETC_BUS_WIDTH_SELECT_MASK; + + Val <<= NETC_BUS_WIDTH_SELECT_OFFSET; + Val &= NETC_BUS_WIDTH_SELECT_MASK; + + RegVal |= Val; + + Mvpp2Rfu1Write (Port->Priv, MV_NETCOMP_PORTS_CONTROL_0, RegVal); +} + +STATIC +VOID +MvGop110NetcSampleStagesTiming ( + IN PP2DXE_PORT *Port, + IN UINT32 Val + ) +{ + UINT32 RegVal; + + RegVal = Mvpp2Rfu1Read (Port->Priv, MV_NETCOMP_PORTS_CONTROL_0); + RegVal &= ~NETC_GIG_RX_DATA_SAMPLE_MASK; + + Val <<= NETC_GIG_RX_DATA_SAMPLE_OFFSET; + Val &= NETC_GIG_RX_DATA_SAMPLE_MASK; + + RegVal |= Val; + + Mvpp2Rfu1Write (Port->Priv, MV_NETCOMP_PORTS_CONTROL_0, RegVal); +} + +STATIC +VOID +MvGop110NetcMacToXgmii ( + IN PP2DXE_PORT *Port, + IN UINT32 PortId, + IN enum MvNetcPhase Phase + ) +{ + switch (Phase) { + case MV_NETC_FIRST_PHASE: + + /* Set Bus Width to HB mode = 1 */ + MvGop110NetcBusWidthSelect (Port, 0x1); + + /* Select RGMII mode */ + MvGop110NetcGbeSgmiiModeSelect (Port, PortId, MV_NETC_GBE_XMII); + break; + case MV_NETC_SECOND_PHASE: + + /* De-assert the relevant PortId HB Reset */ + MvGop110NetcPortRfReset (Port, PortId, 0x1); + break; + } +} + +STATIC +VOID +MvGop110NetcMacToSgmii ( + IN PP2DXE_PORT *Port, + IN UINT32 PortId, + IN enum MvNetcPhase Phase + ) +{ + switch (Phase) { + case MV_NETC_FIRST_PHASE: + + /* Set Bus Width to HB mode = 1 */ + MvGop110NetcBusWidthSelect (Port, 1); + + /* Select SGMII mode */ + if (PortId >= 1) { + MvGop110NetcGbeSgmiiModeSelect (Port, PortId, MV_NETC_GBE_SGMII); + } + + /* Configure the sample stages */ + MvGop110NetcSampleStagesTiming (Port, 0); + break; + case MV_NETC_SECOND_PHASE: + + /* De-assert the relevant PortId HB Reset */ + MvGop110NetcPortRfReset (Port, PortId, 1); + break; + } +} + +STATIC +VOID +MvGop110NetcMacToRxaui ( + IN PP2DXE_PORT *Port, + IN UINT32 PortId, + IN enum MvNetcPhase Phase, + IN enum MvNetcLanes Lanes + ) +{ + /* Currently only RXAUI0 supPorted */ + if (PortId != 0) + return; + + switch (Phase) { + case MV_NETC_FIRST_PHASE: + + /* RXAUI Serdes/s Clock alignment */ + if (Lanes == MV_NETC_LANE_23) { + MvGop110NetcRxaui0Enable (Port, PortId, 1); + } else { + MvGop110NetcRxaui1Enable (Port, PortId, 1); + } + break; + case MV_NETC_SECOND_PHASE: + + /* De-assert the relevant PortId HB Reset */ + MvGop110NetcPortRfReset (Port, PortId, 1); + break; + } +} + +STATIC +VOID +MvGop110NetcMacToXaui ( + IN PP2DXE_PORT *Port, + IN UINT32 PortId, + IN enum MvNetcPhase Phase + ) +{ + switch (Phase) { + case MV_NETC_FIRST_PHASE: + + /* RXAUI Serdes/s Clock alignment */ + MvGop110NetcXauiEnable (Port, PortId, 1); + break; + case MV_NETC_SECOND_PHASE: + + /* De-assert the relevant PortId HB Reset */ + MvGop110NetcPortRfReset (Port, PortId, 1); + break; + } +} + +INT32 +MvGop110NetcInit ( + IN PP2DXE_PORT *Port, + IN UINT32 NetCompConfig, + IN enum MvNetcPhase Phase + ) +{ + UINT32 c = NetCompConfig; + + if (c & MV_NETC_GE_MAC0_RXAUI_L23) { + MvGop110NetcMacToRxaui (Port, 0, Phase, MV_NETC_LANE_23); + } + + if (c & MV_NETC_GE_MAC0_RXAUI_L45) { + MvGop110NetcMacToRxaui (Port, 0, Phase, MV_NETC_LANE_45); + } + + if (c & MV_NETC_GE_MAC0_XAUI) { + MvGop110NetcMacToXaui (Port, 0, Phase); + } + + if (c & MV_NETC_GE_MAC2_SGMII) { + MvGop110NetcMacToSgmii (Port, 2, Phase); + } else { + MvGop110NetcMacToXgmii (Port, 2, Phase); + } + + if (c & MV_NETC_GE_MAC3_SGMII) { + MvGop110NetcMacToSgmii (Port, 3, Phase); + } else { + MvGop110NetcMacToXgmii (Port, 3, Phase); + if (c & MV_NETC_GE_MAC3_RGMII) { + MvGop110NetcMiiMode (Port, 3, MV_NETC_GBE_RGMII); + } else { + MvGop110NetcMiiMode (Port, 3, MV_NETC_GBE_MII); + } + } + + /* Activate gop Ports 0, 2, 3 */ + MvGop110NetcActivePort (Port, 0, 1); + MvGop110NetcActivePort (Port, 2, 1); + MvGop110NetcActivePort (Port, 3, 1); + + if (Phase == MV_NETC_SECOND_PHASE) { + + /* Enable the GOP internal clock logic */ + MvGop110NetcGopClockLogicSet (Port, 1); + + /* De-assert GOP unit Reset */ + MvGop110NetcGopReset (Port, 1); + } + + return 0; +} + +UINT32 +MvpPp2xGop110NetcCfgCreate ( + IN PP2DXE_PORT *Port + ) +{ + UINT32 Val = 0; + + if (Port->GopIndex == 0) { + if (Port->PhyInterface == MV_MODE_XAUI) { + Val |= MV_NETC_GE_MAC0_XAUI; + } else if (Port->PhyInterface == MV_MODE_RXAUI) { + Val |= MV_NETC_GE_MAC0_RXAUI_L23; + } + } + + if (Port->GopIndex == 2) { + if (Port->PhyInterface == MV_MODE_SGMII) { + Val |= MV_NETC_GE_MAC2_SGMII; + } + } + + if (Port->GopIndex == 3) { + if (Port->PhyInterface == MV_MODE_SGMII) { + Val |= MV_NETC_GE_MAC3_SGMII; + } else if (Port->PhyInterface == MV_MODE_RGMII) { + Val |= MV_NETC_GE_MAC3_RGMII; + } + } + + return Val; +} + +/* + * Initialize physical Port. Configure the Port mode and + * all its elements accordingly. + */ +INT32 +MvGop110PortInit ( + IN PP2DXE_PORT *Port + ) +{ + + switch (Port->PhyInterface) { + case MV_MODE_RGMII: + MvGop110GmacReset (Port, RESET); + + /* Configure PCS */ + MvGop110GpcsModeCfg (Port, FALSE); + MvGop110BypassClkCfg (Port, TRUE); + + /* Configure MAC */ + MvGop110GmacModeCfg (Port); + + /* PCS unreset */ + MvGop110GpcsReset (Port, UNRESET); + + /* MAC unreset */ + MvGop110GmacReset (Port, UNRESET); + break; + case MV_MODE_SGMII: + case MV_MODE_QSGMII: + + /* Configure PCS */ + MvGop110GpcsModeCfg (Port, TRUE); + + /* Configure MAC */ + MvGop110GmacModeCfg (Port); + + /* Select proper MAC mode */ + MvGop110Xlg2GigMacCfg (Port); + + /* PCS unreset */ + MvGop110GpcsReset (Port, UNRESET); + + /* MAC unreset */ + MvGop110GmacReset (Port, UNRESET); + break; + default: + return -1; + } + + return 0; +} + +/* Set the MAC to Reset or exit from Reset */ +INT32 +MvGop110GmacReset ( + IN PP2DXE_PORT *Port, + IN enum MvReset ResetCmd + ) +{ + UINT32 RegAddr; + UINT32 Val; + + RegAddr = MVPP2_PORT_CTRL2_REG; + + Val = MvGop110GmacRead (Port, RegAddr); + + if (ResetCmd == RESET) { + Val |= MVPP2_PORT_CTRL2_PORTMACRESET_MASK; + } else { + Val &= ~MVPP2_PORT_CTRL2_PORTMACRESET_MASK; + } + + MvGop110GmacWrite (Port, RegAddr, Val); + + return 0; +} + +/* Enable/Disable Port to work with Gig PCS */ +INT32 +MvGop110GpcsModeCfg ( + IN PP2DXE_PORT *Port, + BOOLEAN En + ) +{ + UINT32 Val; + + Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL2_REG); + + if (En) { + Val |= MVPP2_PORT_CTRL2_PCS_EN_MASK; + } else { + Val &= ~MVPP2_PORT_CTRL2_PCS_EN_MASK; + } + + MvGop110GmacWrite (Port, MVPP2_PORT_CTRL2_REG, Val); + + return 0; +} + +INT32 +MvGop110BypassClkCfg ( + IN PP2DXE_PORT *Port, + IN BOOLEAN En + ) +{ + UINT32 Val; + + Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL2_REG); + + if (En) { + Val |= MVPP2_PORT_CTRL2_CLK_125_BYPS_EN_MASK; + } else { + Val &= ~MVPP2_PORT_CTRL2_CLK_125_BYPS_EN_MASK; + } + + MvGop110GmacWrite (Port, MVPP2_PORT_CTRL2_REG, Val); + + return 0; +} + +INT32 +MvGop110GpcsReset ( + IN PP2DXE_PORT *Port, + IN enum MvReset ResetCmd + ) +{ + UINT32 RegData; + + RegData = MvGop110GmacRead (Port, MVPP2_PORT_CTRL2_REG); + + if (ResetCmd == RESET) { + U32_SET_FIELD ( + RegData, + MVPP2_PORT_CTRL2_SGMII_MODE_MASK, + 0 + ); + + } else { + U32_SET_FIELD ( + RegData, + MVPP2_PORT_CTRL2_SGMII_MODE_MASK, + 1 << MVPP2_PORT_CTRL2_SGMII_MODE_OFFS + ); + + } + + MvGop110GmacWrite (Port, MVPP2_PORT_CTRL2_REG, RegData); + + return 0; +} + +VOID +MvGop110Xlg2GigMacCfg ( + IN PP2DXE_PORT *Port + ) +{ + UINT32 RegVal; + + /* Relevant only for MAC0 (XLG0 and GMAC0) */ + if (Port->GopIndex > 0) { + return; + } + + /* Configure 1Gig MAC mode */ + RegVal = Mvpp2XlgRead (Port, MV_XLG_PORT_MAC_CTRL3_REG); + U32_SET_FIELD ( + RegVal, + MV_XLG_MAC_CTRL3_MACMODESELECT_MASK, + (0 << MV_XLG_MAC_CTRL3_MACMODESELECT_OFFS) + ); + + Mvpp2XlgWrite (Port, MV_XLG_PORT_MAC_CTRL3_REG, RegVal); +} + +/* Set the internal mux's to the required MAC in the GOP */ +INT32 +MvGop110GmacModeCfg ( + IN PP2DXE_PORT *Port + ) +{ + UINT32 RegAddr; + UINT32 Val; + + /* Set TX FIFO thresholds */ + switch (Port->PhyInterface) { + case MV_MODE_SGMII: + if (Port->Speed == MV_PORT_SPEED_2500) { + MvGop110GmacSgmii25Cfg (Port); + } else { + MvGop110GmacSgmiiCfg (Port); + } + break; + case MV_MODE_RGMII: + MvGop110GmacRgmiiCfg (Port); + break; + case MV_MODE_QSGMII: + MvGop110GmacQsgmiiCfg (Port); + break; + default: + return -1; + } + + /* Jumbo frame supPort - 0x1400*2= 0x2800 bytes */ + Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL0_REG); + U32_SET_FIELD ( + Val, + MVPP2_PORT_CTRL0_FRAMESIZELIMIT_MASK, + (0x1400 << MVPP2_PORT_CTRL0_FRAMESIZELIMIT_OFFS) + ); + + MvGop110GmacWrite (Port, MVPP2_PORT_CTRL0_REG, Val); + + /* PeriodicXonEn disable */ + RegAddr = MVPP2_PORT_CTRL1_REG; + Val = MvGop110GmacRead (Port, RegAddr); + Val &= ~MVPP2_PORT_CTRL1_EN_PERIODIC_FC_XON_MASK; + MvGop110GmacWrite (Port, RegAddr, Val); + + /* Mask all Ports interrupts */ + MvGop110GmacPortLinkEventMask (Port); + +#if MV_PP2x_INTERRUPT + /* Unmask link change interrupt */ + Val = MvGop110GmacRead (Port, MVPP2_INTERRUPT_MASK_REG); + Val |= MVPP2_INTERRUPT_CAUSE_LINK_CHANGE_MASK; + Val |= 1; /* Unmask summary bit */ + MvGop110GmacWrite (Port, MVPP2_INTERRUPT_MASK_REG, Val); +#endif + + return 0; +} + +VOID +MvGop110GmacRgmiiCfg ( + IN PP2DXE_PORT *Port + ) +{ + UINT32 Val, thresh, an; + + /* Configure minimal level of the Tx FIFO before the lower part starts to read a packet*/ + thresh = MV_RGMII_TX_FIFO_MIN_TH; + Val = MvGop110GmacRead (Port, MVPP2_PORT_FIFO_CFG_1_REG); + U32_SET_FIELD ( + Val, + MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_MASK, + (thresh << MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_OFFS) + ); + + MvGop110GmacWrite (Port, MVPP2_PORT_FIFO_CFG_1_REG, Val); + + /* Disable bypass of sync module */ + Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL4_REG); + Val |= MVPP2_PORT_CTRL4_SYNC_BYPASS_MASK; + + /* Configure DP clock select according to mode */ + Val &= ~MVPP2_PORT_CTRL4_DP_CLK_SEL_MASK; + Val |= MVPP2_PORT_CTRL4_QSGMII_BYPASS_ACTIVE_MASK; + Val |= MVPP2_PORT_CTRL4_EXT_PIN_GMII_SEL_MASK; + MvGop110GmacWrite (Port, MVPP2_PORT_CTRL4_REG, Val); + + Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL2_REG); + Val &= ~MVPP2_PORT_CTRL2_DIS_PADING_OFFS; + MvGop110GmacWrite (Port, MVPP2_PORT_CTRL2_REG, Val); + + /* Configure GIG MAC to SGMII mode */ + Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL0_REG); + Val &= ~MVPP2_PORT_CTRL0_PORTTYPE_MASK; + MvGop110GmacWrite (Port, MVPP2_PORT_CTRL0_REG, Val); + + /* configure AN 0xb8e8 */ + an = MVPP2_PORT_AUTO_NEG_CFG_AN_BYPASS_EN_MASK | + MVPP2_PORT_AUTO_NEG_CFG_EN_AN_SPEED_MASK | + MVPP2_PORT_AUTO_NEG_CFG_EN_FC_AN_MASK | + MVPP2_PORT_AUTO_NEG_CFG_EN_FDX_AN_MASK | + MVPP2_PORT_AUTO_NEG_CFG_CHOOSE_SAMPLE_TX_CONFIG_MASK; + MvGop110GmacWrite (Port, MVPP2_PORT_AUTO_NEG_CFG_REG, an); +} + +VOID +MvGop110GmacSgmii25Cfg ( + IN PP2DXE_PORT *Port + ) +{ + UINT32 Val, thresh, an; + + /* + * Configure minimal level of the Tx FIFO before + * the lower part starts to read a packet. + */ + thresh = MV_SGMII2_5_TX_FIFO_MIN_TH; + Val = MvGop110GmacRead (Port, MVPP2_PORT_FIFO_CFG_1_REG); + U32_SET_FIELD ( + Val, + MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_MASK, + (thresh << MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_OFFS) + ); + + MvGop110GmacWrite (Port, MVPP2_PORT_FIFO_CFG_1_REG, Val); + + /* Disable bypass of sync module */ + Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL4_REG); + Val |= MVPP2_PORT_CTRL4_SYNC_BYPASS_MASK; + + /* Configure DP clock select according to mode */ + Val |= MVPP2_PORT_CTRL4_DP_CLK_SEL_MASK; + + /* Configure QSGMII bypass according to mode */ + Val |= MVPP2_PORT_CTRL4_QSGMII_BYPASS_ACTIVE_MASK; + MvGop110GmacWrite (Port, MVPP2_PORT_CTRL4_REG, Val); + + Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL2_REG); + Val |= MVPP2_PORT_CTRL2_DIS_PADING_OFFS; + MvGop110GmacWrite (Port, MVPP2_PORT_CTRL2_REG, Val); + + /* Configure GIG MAC to 1000Base-X mode connected to a fiber transceiver */ + Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL0_REG); + Val |= MVPP2_PORT_CTRL0_PORTTYPE_MASK; + MvGop110GmacWrite (Port, MVPP2_PORT_CTRL0_REG, Val); + + /* configure AN 0x9268 */ + an = MVPP2_PORT_AUTO_NEG_CFG_EN_PCS_AN_MASK | + MVPP2_PORT_AUTO_NEG_CFG_AN_BYPASS_EN_MASK | + MVPP2_PORT_AUTO_NEG_CFG_SET_MII_SPEED_MASK | + MVPP2_PORT_AUTO_NEG_CFG_SET_GMII_SPEED_MASK | + MVPP2_PORT_AUTO_NEG_CFG_ADV_PAUSE_MASK | + MVPP2_PORT_AUTO_NEG_CFG_SET_FULL_DX_MASK | + MVPP2_PORT_AUTO_NEG_CFG_CHOOSE_SAMPLE_TX_CONFIG_MASK; + MvGop110GmacWrite (Port, MVPP2_PORT_AUTO_NEG_CFG_REG, an); +} + +VOID +MvGop110GmacSgmiiCfg ( + IN PP2DXE_PORT *Port + ) +{ + UINT32 Val, thresh, an; + + /* + * Configure minimal level of the Tx FIFO before + * the lower part starts to read a packet. + */ + thresh = MV_SGMII_TX_FIFO_MIN_TH; + Val = MvGop110GmacRead (Port, MVPP2_PORT_FIFO_CFG_1_REG); + U32_SET_FIELD (Val, MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_MASK, + (thresh << MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_OFFS)); + MvGop110GmacWrite (Port, MVPP2_PORT_FIFO_CFG_1_REG, Val); + + /* Disable bypass of sync module */ + Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL4_REG); + Val |= MVPP2_PORT_CTRL4_SYNC_BYPASS_MASK; + + /* Configure DP clock select according to mode */ + Val &= ~MVPP2_PORT_CTRL4_DP_CLK_SEL_MASK; + + /* Configure QSGMII bypass according to mode */ + Val |= MVPP2_PORT_CTRL4_QSGMII_BYPASS_ACTIVE_MASK; + MvGop110GmacWrite (Port, MVPP2_PORT_CTRL4_REG, Val); + + Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL2_REG); + Val |= MVPP2_PORT_CTRL2_DIS_PADING_OFFS; + MvGop110GmacWrite (Port, MVPP2_PORT_CTRL2_REG, Val); + + /* Configure GIG MAC to SGMII mode */ + Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL0_REG); + Val &= ~MVPP2_PORT_CTRL0_PORTTYPE_MASK; + MvGop110GmacWrite (Port, MVPP2_PORT_CTRL0_REG, Val); + + /* Configure AN */ + an = MVPP2_PORT_AUTO_NEG_CFG_EN_PCS_AN_MASK | + MVPP2_PORT_AUTO_NEG_CFG_AN_BYPASS_EN_MASK | + MVPP2_PORT_AUTO_NEG_CFG_EN_AN_SPEED_MASK | + MVPP2_PORT_AUTO_NEG_CFG_EN_FC_AN_MASK | + MVPP2_PORT_AUTO_NEG_CFG_EN_FDX_AN_MASK | + MVPP2_PORT_AUTO_NEG_CFG_CHOOSE_SAMPLE_TX_CONFIG_MASK; + MvGop110GmacWrite (Port, MVPP2_PORT_AUTO_NEG_CFG_REG, an); +} + +VOID +MvGop110GmacQsgmiiCfg ( + IN PP2DXE_PORT *Port + ) +{ + UINT32 Val, thresh, an; + + /* + * Configure minimal level of the Tx FIFO before + * the lower part starts to read a packet. + */ + thresh = MV_SGMII_TX_FIFO_MIN_TH; + Val = MvGop110GmacRead (Port, MVPP2_PORT_FIFO_CFG_1_REG); + U32_SET_FIELD ( + Val, + MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_MASK, + (thresh << MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_OFFS) + ); + + MvGop110GmacWrite (Port, MVPP2_PORT_FIFO_CFG_1_REG, Val); + + /* Disable bypass of sync module */ + Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL4_REG); + Val |= MVPP2_PORT_CTRL4_SYNC_BYPASS_MASK; + + /* Configure DP clock select according to mode */ + Val &= ~MVPP2_PORT_CTRL4_DP_CLK_SEL_MASK; + Val &= ~MVPP2_PORT_CTRL4_EXT_PIN_GMII_SEL_MASK; + + /* Configure QSGMII bypass according to mode */ + Val &= ~MVPP2_PORT_CTRL4_QSGMII_BYPASS_ACTIVE_MASK; + MvGop110GmacWrite (Port, MVPP2_PORT_CTRL4_REG, Val); + + Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL2_REG); + Val &= ~MVPP2_PORT_CTRL2_DIS_PADING_OFFS; + MvGop110GmacWrite (Port, MVPP2_PORT_CTRL2_REG, Val); + + /* Configure GIG MAC to SGMII mode */ + Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL0_REG); + Val &= ~MVPP2_PORT_CTRL0_PORTTYPE_MASK; + MvGop110GmacWrite (Port, MVPP2_PORT_CTRL0_REG, Val); + + /* Configure AN 0xB8EC */ + an = MVPP2_PORT_AUTO_NEG_CFG_EN_PCS_AN_MASK | + MVPP2_PORT_AUTO_NEG_CFG_AN_BYPASS_EN_MASK | + MVPP2_PORT_AUTO_NEG_CFG_EN_AN_SPEED_MASK | + MVPP2_PORT_AUTO_NEG_CFG_EN_FC_AN_MASK | + MVPP2_PORT_AUTO_NEG_CFG_EN_FDX_AN_MASK | + MVPP2_PORT_AUTO_NEG_CFG_CHOOSE_SAMPLE_TX_CONFIG_MASK; + MvGop110GmacWrite (Port, MVPP2_PORT_AUTO_NEG_CFG_REG, an); +} + +INT32 +Mvpp2SmiPhyAddrCfg ( + IN PP2DXE_PORT *Port, + IN INT32 PortId, + IN INT32 Addr + ) +{ + Mvpp2SmiWrite (Port->Priv, MV_SMI_PHY_ADDRESS_REG(PortId), Addr); + + return 0; +} + +BOOLEAN +MvGop110PortIsLinkUp ( + IN PP2DXE_PORT *Port + ) +{ + switch (Port->PhyInterface) { + case MV_MODE_RGMII: + case MV_MODE_SGMII: + case MV_MODE_QSGMII: + return MvGop110GmacLinkStatusGet (Port); + case MV_MODE_XAUI: + case MV_MODE_RXAUI: + return FALSE; + default: + return FALSE; + } +} + +/* Get MAC link status */ +BOOLEAN +MvGop110GmacLinkStatusGet ( + IN PP2DXE_PORT *Port + ) +{ + UINT32 RegAddr; + UINT32 Val; + + RegAddr = MVPP2_PORT_STATUS0_REG; + + Val = MvGop110GmacRead (Port, RegAddr); + + return (Val & 1) ? TRUE : FALSE; +} + +VOID +MvGop110PortDisable ( + IN PP2DXE_PORT *Port + ) +{ + switch (Port->PhyInterface) { + case MV_MODE_RGMII: + case MV_MODE_SGMII: + case MV_MODE_QSGMII: + MvGop110GmacPortDisable (Port); + break; + default: + return; + } +} + +VOID +MvGop110PortEnable ( + IN PP2DXE_PORT *Port + ) +{ + switch (Port->PhyInterface) { + case MV_MODE_RGMII: + case MV_MODE_SGMII: + case MV_MODE_QSGMII: + MvGop110GmacPortEnable (Port); + break; + default: + return; + } +} + +/* Enable Port and MIB counters */ +VOID +MvGop110GmacPortEnable ( + IN PP2DXE_PORT *Port + ) +{ + UINT32 RegVal; + + RegVal = MvGop110GmacRead (Port, MVPP2_PORT_CTRL0_REG); + RegVal |= MVPP2_PORT_CTRL0_PORTEN_MASK; + RegVal |= MVPP2_PORT_CTRL0_COUNT_EN_MASK; + + MvGop110GmacWrite (Port, MVPP2_PORT_CTRL0_REG, RegVal); +} + +/* Disable Port */ +VOID +MvGop110GmacPortDisable ( + IN PP2DXE_PORT *Port + ) +{ + UINT32 RegVal; + + /* Mask all Ports interrupts */ + MvGop110GmacPortLinkEventMask (Port); + + RegVal = MvGop110GmacRead (Port, MVPP2_PORT_CTRL0_REG); + RegVal &= ~MVPP2_PORT_CTRL0_PORTEN_MASK; + + MvGop110GmacWrite (Port, MVPP2_PORT_CTRL0_REG, RegVal); +} + +VOID +MvGop110GmacPortLinkEventMask ( + IN PP2DXE_PORT *Port + ) +{ + UINT32 RegVal; + + RegVal = MvGop110GmacRead (Port, MV_GMAC_INTERRUPT_SUM_MASK_REG); + RegVal &= ~MV_GMAC_INTERRUPT_SUM_CAUSE_LINK_CHANGE_MASK; + MvGop110GmacWrite (Port, MV_GMAC_INTERRUPT_SUM_MASK_REG, RegVal); +} + +INT32 +MvGop110PortEventsMask ( + IN PP2DXE_PORT *Port + ) +{ + + switch (Port->PhyInterface) { + case MV_MODE_RGMII: + case MV_MODE_SGMII: + case MV_MODE_QSGMII: + MvGop110GmacPortLinkEventMask (Port); + break; + default: + return -1; + } + + return 0; +} + +INT32 +MvGop110FlCfg ( + IN PP2DXE_PORT *Port + ) +{ + switch (Port->PhyInterface) { + case MV_MODE_RGMII: + case MV_MODE_SGMII: + case MV_MODE_QSGMII: + /* Disable AN */ + MvGop110SpeedDuplexSet (Port, Port->Speed, MV_PORT_DUPLEX_FULL); + break; + case MV_MODE_XAUI: + case MV_MODE_RXAUI: + return 0; + default: + return -1; + } + + return 0; +} + +/* Set Port Speed and Duplex */ +INT32 +MvGop110SpeedDuplexSet ( + IN PP2DXE_PORT *Port, + IN INT32 Speed, + IN enum MvPortDuplex Duplex + ) +{ + switch (Port->PhyInterface) { + case MV_MODE_RGMII: + case MV_MODE_SGMII: + case MV_MODE_QSGMII: + MvGop110GmacSpeedDuplexSet (Port, Speed, Duplex); + break; + case MV_MODE_XAUI: + case MV_MODE_RXAUI: + break; + default: + return -1; + } + + return 0; +} + +/* + * Sets Port Speed to Auto Negotiation / 1000 / 100 / 10 Mbps. + * Sets Port Duplex to Auto Negotiation / Full / Half Duplex. + */ +INT32 +MvGop110GmacSpeedDuplexSet ( + IN PP2DXE_PORT *Port, + IN INT32 Speed, + IN enum MvPortDuplex Duplex + ) +{ + UINT32 RegVal; + + RegVal = Mvpp2GmacRead (Port, MVPP2_PORT_AUTO_NEG_CFG_REG); + + switch (Speed) { + case MV_PORT_SPEED_2500: + case MV_PORT_SPEED_1000: + RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_EN_AN_SPEED_MASK; + RegVal |= MVPP2_PORT_AUTO_NEG_CFG_SET_GMII_SPEED_MASK; + /* The 100/10 bit doesn't matter in this case */ + break; + case MV_PORT_SPEED_100: + RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_EN_AN_SPEED_MASK; + RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_SET_GMII_SPEED_MASK; + RegVal |= MVPP2_PORT_AUTO_NEG_CFG_SET_MII_SPEED_MASK; + break; + case MV_PORT_SPEED_10: + RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_EN_AN_SPEED_MASK; + RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_SET_GMII_SPEED_MASK; + RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_SET_MII_SPEED_MASK; + break; + default: + return MVPP2_EINVAL; + } + + switch (Duplex) { + case MV_PORT_DUPLEX_AN: + RegVal |= MVPP2_PORT_AUTO_NEG_CFG_EN_FDX_AN_MASK; + /* The other bits don't matter in this case */ + break; + case MV_PORT_DUPLEX_HALF: + RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_EN_FDX_AN_MASK; + RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_SET_FULL_DX_MASK; + break; + case MV_PORT_DUPLEX_FULL: + RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_EN_FDX_AN_MASK; + RegVal |= MVPP2_PORT_AUTO_NEG_CFG_SET_FULL_DX_MASK; + break; + default: + return MVPP2_EINVAL; + } + + Mvpp2GmacWrite (Port, MVPP2_PORT_AUTO_NEG_CFG_REG, RegVal); + + return 0; +} + +VOID +Mvpp2AxiConfig ( + IN MVPP2_SHARED *Priv + ) +{ + /* Config AXI Read&Write Normal and Soop mode */ + Mvpp2Write (Priv, MVPP22_AXI_BM_WR_ATTR_REG, MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT); + Mvpp2Write (Priv, MVPP22_AXI_BM_RD_ATTR_REG, MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT); + Mvpp2Write (Priv, MVPP22_AXI_AGGRQ_DESCR_RD_ATTR_REG, MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT); + Mvpp2Write (Priv, MVPP22_AXI_TXQ_DESCR_WR_ATTR_REG, MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT); + Mvpp2Write (Priv, MVPP22_AXI_TXQ_DESCR_RD_ATTR_REG, MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT); + Mvpp2Write (Priv, MVPP22_AXI_RXQ_DESCR_WR_ATTR_REG, MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT); + Mvpp2Write (Priv, MVPP22_AXI_RX_DATA_WR_ATTR_REG, MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT); + Mvpp2Write (Priv, MVPP22_AXI_TX_DATA_RD_ATTR_REG, MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT); +} + +/* Cleanup Tx Ports */ +VOID +Mvpp2TxpClean ( + IN PP2DXE_PORT *Port, + IN INT32 Txp, + IN MVPP2_TX_QUEUE *Txq + ) +{ + INT32 Delay, Pending; + UINT32 RegVal; + + Mvpp2Write (Port->Priv, MVPP2_TXQ_NUM_REG, Txq->Id); + RegVal = Mvpp2Read (Port->Priv, MVPP2_TXQ_PREF_BUF_REG); + RegVal |= MVPP2_TXQ_DRAIN_EN_MASK; + Mvpp2Write (Port->Priv, MVPP2_TXQ_PREF_BUF_REG, RegVal); + + /* + * The Queue has been stopped so wait for all packets + * to be transmitted. + */ + Delay = 0; + do { + if (Delay >= MVPP2_TX_PENDING_TIMEOUT_MSEC) { + Mvpp2Printf ("Port %d: cleaning Queue %d timed out\n", Port->Id, Txq->LogId); + break; + } + Mvpp2Mdelay (1); + Delay++; + + Pending = Mvpp2TxqPendDescNumGet (Port, Txq); + } while (Pending); + + RegVal &= ~MVPP2_TXQ_DRAIN_EN_MASK; + Mvpp2Write (Port->Priv, MVPP2_TXQ_PREF_BUF_REG, RegVal); +} + +/* Cleanup all Tx Queues */ +VOID +Mvpp2CleanupTxqs ( + IN PP2DXE_PORT *Port + ) +{ + MVPP2_TX_QUEUE *Txq; + INT32 Txp, Queue; + UINT32 RegVal; + + RegVal = Mvpp2Read (Port->Priv, MVPP2_TX_PORT_FLUSH_REG); + + /* Reset Tx Ports and delete Tx Queues */ + for (Txp = 0; Txp < Port->TxpNum; Txp++) { + RegVal |= MVPP2_TX_PORT_FLUSH_MASK (Port->Id); + Mvpp2Write (Port->Priv, MVPP2_TX_PORT_FLUSH_REG, RegVal); + + for (Queue = 0; Queue < TxqNumber; Queue++) { + Txq = &Port->Txqs[Txp * TxqNumber + Queue]; + Mvpp2TxpClean (Port, Txp, Txq); + Mvpp2TxqHwDeinit (Port, Txq); + } + + RegVal &= ~MVPP2_TX_PORT_FLUSH_MASK (Port->Id); + Mvpp2Write (Port->Priv, MVPP2_TX_PORT_FLUSH_REG, RegVal); + } +} + +/* Cleanup all Rx Queues */ +VOID +Mvpp2CleanupRxqs ( + IN PP2DXE_PORT *Port + ) +{ + INT32 Queue; + + for (Queue = 0; Queue < RxqNumber; Queue++) { + Mvpp2RxqHwDeinit (Port, &Port->Rxqs[Queue]); + } +} diff --git a/Platform/Marvell/Drivers/Net/Pp2Dxe/Mvpp2Lib.h b/Platform/Marvell/Drivers/Net/Pp2Dxe/Mvpp2Lib.h new file mode 100644 index 0000000000..d7d5dcb283 --- /dev/null +++ b/Platform/Marvell/Drivers/Net/Pp2Dxe/Mvpp2Lib.h @@ -0,0 +1,726 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __MVPP2_LIB_H__ +#define __MVPP2_LIB_H__ + +#include "Mvpp2LibHw.h" +#include "Pp2Dxe.h" + +/* number of RXQs used by single Port */ +STATIC INT32 RxqNumber = 1; +/* number of TXQs used by single Port */ +STATIC INT32 TxqNumber = 1; + +VOID +Mvpp2PrsMacPromiscSet ( + IN MVPP2_SHARED *Priv, + IN INT32 PortId, + IN BOOLEAN Add + ); + +VOID +Mvpp2PrsMacMultiSet ( + IN MVPP2_SHARED *Priv, + IN INT32 PortId, + IN INT32 Index, + IN BOOLEAN Add + ); + +INT32 +Mvpp2PrsDefaultInit ( + IN MVPP2_SHARED *Priv + ); + +INT32 +Mvpp2PrsMacDaAccept ( + IN MVPP2_SHARED *Priv, + IN INT32 PortId, + IN const UINT8 *Da, + IN BOOLEAN Add + ); + +VOID +Mvpp2PrsMcastDelAll ( + IN MVPP2_SHARED *Priv, + IN INT32 PortId + ); + +INT32 +Mvpp2PrsTagModeSet ( + IN MVPP2_SHARED *Priv, + IN INT32 PortId, + IN INT32 type + ); + +INT32 +Mvpp2PrsDefFlow ( + IN PP2DXE_PORT *Port + ); + +VOID +Mvpp2ClsInit ( + IN MVPP2_SHARED *Priv + ); + +VOID +Mvpp2ClsPortConfig ( + IN PP2DXE_PORT *Port + ); + +VOID +Mvpp2ClsOversizeRxqSet ( + IN PP2DXE_PORT *Port + ); + +VOID +Mvpp2BmPoolHwCreate ( + IN MVPP2_SHARED *Priv, + IN MVPP2_BMS_POOL *BmPool, + IN INT32 Size + ); + +VOID +Mvpp2BmPoolBufsizeSet ( + IN MVPP2_SHARED *Priv, + IN MVPP2_BMS_POOL *BmPool, + IN INT32 BufSize + ); + +VOID +Mvpp2BmStop ( + IN MVPP2_SHARED *Priv, + IN INT32 Pool + ); + +VOID +Mvpp2BmIrqClear ( + IN MVPP2_SHARED *Priv, + IN INT32 Pool + ); + +VOID +Mvpp2RxqLongPoolSet ( + IN PP2DXE_PORT *Port, + IN INT32 Lrxq, + IN INT32 LongPool + ); + +VOID +Mvpp2RxqShortPoolSet ( + IN PP2DXE_PORT *Port, + IN INT32 Lrxq, + IN INT32 ShortPool + ); + +VOID +Mvpp2BmPoolMcPut ( + IN PP2DXE_PORT *Port, + IN INT32 Pool, + IN UINT32 BufPhysAddr, + IN UINT32 BufVirtAddr, + IN INT32 McId + ); + +VOID +Mvpp2PoolRefill ( + IN PP2DXE_PORT *Port, + IN UINT32 Bm, + IN UINT32 PhysAddr, + IN UINT32 Cookie + ); + +INTN +Mvpp2BmPoolCtrl ( + IN MVPP2_SHARED *Priv, + IN INTN Pool, + IN enum Mvpp2Command cmd + ); + +VOID +Mvpp2InterruptsMask ( + IN VOID *arg + ); + +VOID +Mvpp2InterruptsUnmask ( + IN VOID *arg + ); + +VOID +Mvpp2PortEnable ( + IN PP2DXE_PORT *Port + ); + +VOID +Mvpp2PortDisable ( + IN PP2DXE_PORT *Port + ); + +VOID +Mvpp2DefaultsSet ( + IN PP2DXE_PORT *Port + ); + +VOID +Mvpp2IngressEnable ( + IN PP2DXE_PORT *Port + ); + +VOID +Mvpp2IngressDisable ( + IN PP2DXE_PORT *Port + ); + +VOID +Mvpp2EgressEnable ( + IN PP2DXE_PORT *Port + ); + +VOID +Mvpp2EgressDisable ( + IN PP2DXE_PORT *Port + ); + +UINT32 +Mvpp2BmCookieBuild ( + IN MVPP2_RX_DESC *RxDesc, + IN INT32 Cpu + ); + +INT32 +Mvpp2TxqDrainSet ( + IN PP2DXE_PORT *Port, + IN INT32 Txq, + IN BOOLEAN En + ); + +INT32 +Mvpp2TxqPendDescNumGet ( + IN PP2DXE_PORT *Port, + IN MVPP2_TX_QUEUE *Txq + ); + +UINT32 +Mvpp2AggrTxqPendDescNumGet ( + IN MVPP2_SHARED *Priv, + IN INT32 Cpu + ); + +MVPP2_TX_DESC * +Mvpp2TxqNextDescGet ( + MVPP2_TX_QUEUE *Txq + ); + +VOID +Mvpp2AggrTxqPendDescAdd ( + IN PP2DXE_PORT *Port, + IN INT32 Pending + ); + +INT32 +Mvpp2AggrDescNumCheck ( + IN MVPP2_SHARED *Priv, + IN MVPP2_TX_QUEUE *AggrTxq, + IN INT32 Num, + IN INT32 Cpu + ); + +INT32 +Mvpp2TxqAllocReservedDesc ( + IN MVPP2_SHARED *Priv, + IN MVPP2_TX_QUEUE *Txq, + IN INT32 Num + ); + +VOID +Mvpp2TxqDescPut ( + IN MVPP2_TX_QUEUE *Txq + ); + +UINT32 +Mvpp2TxqDescCsum ( + IN INT32 L3Offs, + IN INT32 L3Proto, + IN INT32 IpHdrLen, + IN INT32 L4Proto + ); + +VOID +Mvpp2TxqSentCounterClear ( + IN OUT VOID *arg + ); + +VOID +Mvpp2GmacMaxRxSizeSet ( + IN PP2DXE_PORT *Port + ); + +VOID +Mvpp2TxpMaxTxSizeSet ( + IN PP2DXE_PORT *Port + ); + +VOID +Mvpp2RxPktsCoalSet ( + IN PP2DXE_PORT *Port, + IN OUT MVPP2_RX_QUEUE *Rxq, + IN UINT32 Pkts + ); + +VOID +Mvpp2RxTimeCoalSet ( + IN PP2DXE_PORT *Port, + IN OUT MVPP2_RX_QUEUE *Rxq, + IN UINT32 Usec + ); + +VOID +Mvpp2AggrTxqHwInit ( + IN OUT MVPP2_TX_QUEUE *AggrTxq, + IN INT32 DescNum, + IN INT32 Cpu, + IN MVPP2_SHARED *Priv + ); + +VOID +Mvpp2RxqHwInit ( + IN PP2DXE_PORT *Port, + IN OUT MVPP2_RX_QUEUE *Rxq + ); + +VOID +Mvpp2RxqDropPkts ( + IN PP2DXE_PORT *Port, + IN OUT MVPP2_RX_QUEUE *Rxq, + IN INT32 Cpu + ); + +VOID +Mvpp2TxqHwInit ( + IN PP2DXE_PORT *Port, + IN OUT MVPP2_TX_QUEUE *Txq + ); + +VOID +Mvpp2TxqHwDeinit ( + IN PP2DXE_PORT *Port, + IN OUT MVPP2_TX_QUEUE *Txq + ); + +VOID +Mvpp2PortPowerUp ( + IN PP2DXE_PORT *Port + ); + +VOID +Mvpp2RxFifoInit ( + IN MVPP2_SHARED *Priv + ); + +VOID +Mvpp2RxqHwDeinit ( + IN PP2DXE_PORT *Port, + IN OUT MVPP2_RX_QUEUE *Rxq + ); + +INT32 +MvGop110NetcInit ( + IN PP2DXE_PORT *Port, + IN UINT32 NetCompConfig, + IN enum MvNetcPhase phase + ); + +UINT32 +MvpPp2xGop110NetcCfgCreate ( + IN PP2DXE_PORT *Port + ); + +INT32 +MvGop110PortInit ( + IN PP2DXE_PORT *Port + ); + +INT32 +MvGop110GmacReset ( + IN PP2DXE_PORT *Port, + IN enum MvReset ResetCmd + ); + +INT32 +MvGop110GpcsModeCfg ( + IN PP2DXE_PORT *Port, + BOOLEAN En + ); + +INT32 +MvGop110BypassClkCfg ( + IN PP2DXE_PORT *Port, + IN BOOLEAN En + ); + +INT32 +MvGop110GpcsReset ( + IN PP2DXE_PORT *Port, + IN enum MvReset ResetCmd + ); + +VOID +MvGop110Xlg2GigMacCfg ( + IN PP2DXE_PORT *Port + ); + +INT32 +MvGop110GmacModeCfg ( + IN PP2DXE_PORT *Port + ); + +VOID +MvGop110GmacRgmiiCfg ( + IN PP2DXE_PORT *Port + ); + +VOID +MvGop110GmacSgmii25Cfg ( + IN PP2DXE_PORT *Port + ); + +VOID +MvGop110GmacSgmiiCfg ( + IN PP2DXE_PORT *Port + ); + +VOID +MvGop110GmacQsgmiiCfg ( + IN PP2DXE_PORT *Port + ); + +INT32 +Mvpp2SmiPhyAddrCfg ( + IN PP2DXE_PORT *Port, + IN INT32 PortId, + IN INT32 Addr + ); + +BOOLEAN +MvGop110PortIsLinkUp ( + IN PP2DXE_PORT *Port + ); + +BOOLEAN +MvGop110GmacLinkStatusGet ( + IN PP2DXE_PORT *Port + ); + +VOID +MvGop110PortDisable ( + IN PP2DXE_PORT *Port + ); + +VOID +MvGop110PortEnable ( + IN PP2DXE_PORT *Port + ); + +VOID +MvGop110GmacPortEnable ( + IN PP2DXE_PORT *Port + ); + +VOID +MvGop110GmacPortDisable ( + IN PP2DXE_PORT *Port + ); + +VOID +MvGop110GmacPortLinkEventMask ( + IN PP2DXE_PORT *Port + ); + +INT32 +MvGop110PortEventsMask ( + IN PP2DXE_PORT *Port + ); + +INT32 +MvGop110FlCfg ( + IN PP2DXE_PORT *Port + ); + +INT32 +MvGop110SpeedDuplexSet ( + IN PP2DXE_PORT *Port, + IN INT32 Speed, + IN enum MvPortDuplex Duplex + ); + +INT32 +MvGop110GmacSpeedDuplexSet ( + IN PP2DXE_PORT *Port, + IN INT32 Speed, + IN enum MvPortDuplex Duplex + ); + +VOID +Mvpp2AxiConfig ( + IN MVPP2_SHARED *Priv + ); + +VOID +Mvpp2TxpClean ( + IN PP2DXE_PORT *Port, + IN INT32 Txp, + IN MVPP2_TX_QUEUE *Txq + ); + +VOID +Mvpp2CleanupTxqs ( + IN PP2DXE_PORT *Port + ); + +VOID +Mvpp2CleanupRxqs ( + IN PP2DXE_PORT *Port + ); + +/* Get number of physical egress Port */ +STATIC +inline +INT32 +Mvpp2EgressPort ( + IN PP2DXE_PORT *Port + ) +{ + return MVPP2_MAX_TCONT + Port->Id; +} + +/* Get number of physical TXQ */ +STATIC +inline +INT32 +Mvpp2TxqPhys ( + IN INT32 PortId, + IN INT32 Txq + ) +{ + return (MVPP2_MAX_TCONT + PortId) * MVPP2_MAX_TXQ + Txq; +} + +/* Set Pool number in a BM Cookie */ +STATIC +inline +UINT32 +Mvpp2BmCookiePoolSet ( + IN UINT32 Cookie, + IN INT32 Pool + ) +{ + UINT32 Bm; + + Bm = Cookie & ~(0xFF << MVPP2_BM_COOKIE_POOL_OFFS); + Bm |= ((Pool & 0xFF) << MVPP2_BM_COOKIE_POOL_OFFS); + + return Bm; +} + +/* Get Pool number from a BM Cookie */ +STATIC +inline +INT32 +Mvpp2BmCookiePoolGet ( + IN UINT32 Cookie + ) +{ + return (Cookie >> MVPP2_BM_COOKIE_POOL_OFFS) & 0xFF; +} + +/* Release buffer to BM */ +STATIC +inline +VOID +Mvpp2BmPoolPut ( + IN MVPP2_SHARED *Priv, + IN INT32 Pool, + IN UINT64 BufPhysAddr, + IN UINT64 BufVirtAddr + ) +{ + UINT32 Val = 0; + + Val = (Upper32Bits(BufVirtAddr) & MVPP22_ADDR_HIGH_MASK) << MVPP22_BM_VIRT_HIGH_RLS_OFFST; + Val |= (Upper32Bits(BufPhysAddr) & MVPP22_ADDR_HIGH_MASK) << MVPP22_BM_PHY_HIGH_RLS_OFFSET; + Mvpp2Write(Priv, MVPP22_BM_PHY_VIRT_HIGH_RLS_REG, Val); + Mvpp2Write(Priv, MVPP2_BM_VIRT_RLS_REG, (UINT32)BufVirtAddr); + Mvpp2Write(Priv, MVPP2_BM_PHY_RLS_REG(Pool), (UINT32)BufPhysAddr); +} + +STATIC +inline +VOID +Mvpp2InterruptsEnable ( + IN PP2DXE_PORT *Port, + IN INT32 CpuMask + ) +{ + Mvpp2Write(Port->Priv, MVPP2_ISR_ENABLE_REG(Port->Id), MVPP2_ISR_ENABLE_INTERRUPT(CpuMask)); +} + +STATIC +inline +VOID +Mvpp2InterruptsDisable ( + IN PP2DXE_PORT *Port, + IN INT32 CpuMask + ) +{ + Mvpp2Write(Port->Priv, MVPP2_ISR_ENABLE_REG(Port->Id), MVPP2_ISR_DISABLE_INTERRUPT(CpuMask)); +} + +/* Get number of Rx descriptors occupied by received packets */ +STATIC +inline +INT32 +Mvpp2RxqReceived ( + IN PP2DXE_PORT *Port, + IN INT32 RxqId + ) +{ + UINT32 Val = Mvpp2Read(Port->Priv, MVPP2_RXQ_STATUS_REG(RxqId)); + + return Val & MVPP2_RXQ_OCCUPIED_MASK; +} + +/* + * Update Rx Queue status with the number of occupied and available + * Rx descriptor slots. + */ +STATIC +inline +VOID +Mvpp2RxqStatusUpdate ( + IN PP2DXE_PORT *Port, + IN INT32 RxqId, + IN INT32 UsedCount, + IN INT32 FreeCount + ) +{ + /* + * Decrement the number of used descriptors and increment count + * increment the number of free descriptors. + */ + UINT32 Val = UsedCount | (FreeCount << MVPP2_RXQ_NUM_NEW_OFFSET); + + Mvpp2Write(Port->Priv, MVPP2_RXQ_STATUS_UPDATE_REG(RxqId), Val); +} + +/* Get pointer to next RX descriptor to be processed by SW */ +STATIC +inline +MVPP2_RX_DESC * +Mvpp2RxqNextDescGet ( + IN MVPP2_RX_QUEUE *Rxq + ) +{ + INT32 RxDesc = Rxq->NextDescToProc; + + Rxq->NextDescToProc = MVPP2_QUEUE_NEXT_DESC(Rxq, RxDesc); + Mvpp2Prefetch(Rxq->Descs + Rxq->NextDescToProc); + return Rxq->Descs + RxDesc; +} + +/* + * Get number of sent descriptors and decrement counter. + * The number of sent descriptors is returned. + * Per-CPU access + */ +STATIC +inline +INT32 +Mvpp2TxqSentDescProc ( + IN PP2DXE_PORT *Port, + IN MVPP2_TX_QUEUE *Txq + ) +{ + UINT32 Val; + + /* Reading status reg resets transmitted descriptor counter */ +#ifdef MVPP2V1 + Val = Mvpp2Read(Port->Priv, MVPP2_TXQ_SENT_REG(Txq->Id)); +#else + Val = Mvpp2Read(Port->Priv, MVPP22_TXQ_SENT_REG(Txq->Id)); +#endif + + return (Val & MVPP2_TRANSMITTED_COUNT_MASK) >> MVPP2_TRANSMITTED_COUNT_OFFSET; +} + +STATIC +inline +MVPP2_RX_QUEUE * +Mvpp2GetRxQueue ( + IN PP2DXE_PORT *Port, + IN UINT32 Cause + ) +{ + INT32 Queue = Mvpp2Fls(Cause) - 1; + + return &Port->Rxqs[Queue]; +} + +STATIC +inline +MVPP2_TX_QUEUE * +Mvpp2GetTxQueue ( + IN PP2DXE_PORT *Port, + IN UINT32 Cause + ) +{ + INT32 Queue = Mvpp2Fls(Cause) - 1; + + return &Port->Txqs[Queue]; +} + +STATIC +inline +void +Mvpp2x2TxdescPhysAddrSet ( + IN DmaAddrT PhysAddr, + IN MVPP2_TX_DESC *TxDesc + ) +{ + UINT64 *BufPhysAddrP = &TxDesc->BufPhysAddrHwCmd2; + + *BufPhysAddrP &= ~(MVPP22_ADDR_MASK); + *BufPhysAddrP |= PhysAddr & MVPP22_ADDR_MASK; +} +#endif /* __MVPP2_LIB_H__ */ diff --git a/Platform/Marvell/Drivers/Net/Pp2Dxe/Mvpp2LibHw.h b/Platform/Marvell/Drivers/Net/Pp2Dxe/Mvpp2LibHw.h new file mode 100644 index 0000000000..f283db2d49 --- /dev/null +++ b/Platform/Marvell/Drivers/Net/Pp2Dxe/Mvpp2LibHw.h @@ -0,0 +1,1968 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __MVPP2_LIB_HW__ +#define __MVPP2_LIB_HW__ + +#ifndef BIT +#define BIT(nr) (1 << (nr)) +#endif + +/* RX Fifo Registers */ +#define MVPP2_RX_DATA_FIFO_SIZE_REG(port) (0x00 + 4 * (port)) +#define MVPP2_RX_ATTR_FIFO_SIZE_REG(port) (0x20 + 4 * (port)) +#define MVPP2_RX_MIN_PKT_SIZE_REG 0x60 +#define MVPP2_RX_FIFO_INIT_REG 0x64 + +/* RX DMA Top Registers */ +#define MVPP2_RX_CTRL_REG(port) (0x140 + 4 * (port)) +#define MVPP2_RX_LOW_LATENCY_PKT_SIZE(s) (((s) & 0xfff) << 16) +#define MVPP2_RX_USE_PSEUDO_FOR_CSUM_MASK BIT(31) +#define MVPP2_POOL_BUF_SIZE_REG(pool) (0x180 + 4 * (pool)) +#define MVPP2_POOL_BUF_SIZE_OFFSET 5 +#define MVPP2_RXQ_CONFIG_REG(rxq) (0x800 + 4 * (rxq)) +#define MVPP2_SNOOP_PKT_SIZE_MASK 0x1ff +#define MVPP2_SNOOP_BUF_HDR_MASK BIT(9) +#define MVPP2_RXQ_POOL_SHORT_OFFS 20 +#define MVPP2_RXQ_POOL_SHORT_MASK 0x700000 +#define MVPP2_RXQ_POOL_LONG_OFFS 24 +#define MVPP2_RXQ_POOL_LONG_MASK 0x7000000 +#define MVPP2_RXQ_PACKET_OFFSET_OFFS 28 +#define MVPP2_RXQ_PACKET_OFFSET_MASK 0x70000000 +#define MVPP2_RXQ_DISABLE_MASK BIT(31) + +/* Parser Registers */ +#define MVPP2_PRS_INIT_LOOKUP_REG 0x1000 +#define MVPP2_PRS_PORT_LU_MAX 0xf +#define MVPP2_PRS_PORT_LU_MASK(port) (0xff << ((port) * 4)) +#define MVPP2_PRS_PORT_LU_VAL(port, val) ((val) << ((port) * 4)) +#define MVPP2_PRS_INIT_OFFS_REG(port) (0x1004 + ((port) & 4)) +#define MVPP2_PRS_INIT_OFF_MASK(port) (0x3f << (((port) % 4) * 8)) +#define MVPP2_PRS_INIT_OFF_VAL(port, val) ((val) << (((port) % 4) * 8)) +#define MVPP2_PRS_MAX_LOOP_REG(port) (0x100c + ((port) & 4)) +#define MVPP2_PRS_MAX_LOOP_MASK(port) (0xff << (((port) % 4) * 8)) +#define MVPP2_PRS_MAX_LOOP_VAL(port, val) ((val) << (((port) % 4) * 8)) +#define MVPP2_PRS_TCAM_IDX_REG 0x1100 +#define MVPP2_PRS_TCAM_DATA_REG(idx) (0x1104 + (idx) * 4) +#define MVPP2_PRS_TCAM_INV_MASK BIT(31) +#define MVPP2_PRS_SRAM_IDX_REG 0x1200 +#define MVPP2_PRS_SRAM_DATA_REG(idx) (0x1204 + (idx) * 4) +#define MVPP2_PRS_TCAM_CTRL_REG 0x1230 +#define MVPP2_PRS_TCAM_EN_MASK BIT(0) + +/* Classifier Registers */ +#define MVPP2_CLS_MODE_REG 0x1800 +#define MVPP2_CLS_MODE_ACTIVE_MASK BIT(0) +#define MVPP2_CLS_PORT_WAY_REG 0x1810 +#define MVPP2_CLS_PORT_WAY_MASK(port) (1 << (port)) +#define MVPP2_CLS_LKP_INDEX_REG 0x1814 +#define MVPP2_CLS_LKP_INDEX_WAY_OFFS 6 +#define MVPP2_CLS_LKP_TBL_REG 0x1818 +#define MVPP2_CLS_LKP_TBL_RXQ_MASK 0xff +#define MVPP2_CLS_LKP_TBL_LOOKUP_EN_MASK BIT(25) +#define MVPP2_CLS_FLOW_INDEX_REG 0x1820 +#define MVPP2_CLS_FLOW_TBL0_REG 0x1824 +#define MVPP2_CLS_FLOW_TBL1_REG 0x1828 +#define MVPP2_CLS_FLOW_TBL2_REG 0x182c +#define MVPP2_CLS_OVERSIZE_RXQ_LOW_REG(port) (0x1980 + ((port) * 4)) +#define MVPP2_CLS_OVERSIZE_RXQ_LOW_BITS 3 +#define MVPP2_CLS_OVERSIZE_RXQ_LOW_MASK 0x7 +#define MVPP2_CLS_SWFWD_P2HQ_REG(port) (0x19b0 + ((port) * 4)) +#define MVPP2_CLS_SWFWD_PCTRL_REG 0x19d0 +#define MVPP2_CLS_SWFWD_PCTRL_MASK(port) (1 << (port)) + +/* Descriptor Manager Top Registers */ +#define MVPP2_RXQ_NUM_REG 0x2040 +#define MVPP2_RXQ_DESC_ADDR_REG 0x2044 +#define MVPP2_RXQ_DESC_SIZE_REG 0x2048 +#define MVPP2_RXQ_DESC_SIZE_MASK 0x3ff0 +#define MVPP2_RXQ_STATUS_UPDATE_REG(rxq) (0x3000 + 4 * (rxq)) +#define MVPP2_RXQ_NUM_PROCESSED_OFFSET 0 +#define MVPP2_RXQ_NUM_NEW_OFFSET 16 +#define MVPP2_RXQ_STATUS_REG(rxq) (0x3400 + 4 * (rxq)) +#define MVPP2_RXQ_OCCUPIED_MASK 0x3fff +#define MVPP2_RXQ_NON_OCCUPIED_OFFSET 16 +#define MVPP2_RXQ_NON_OCCUPIED_MASK 0x3fff0000 +#define MVPP2_RXQ_THRESH_REG 0x204c +#define MVPP2_OCCUPIED_THRESH_OFFSET 0 +#define MVPP2_OCCUPIED_THRESH_MASK 0x3fff +#define MVPP2_RXQ_INDEX_REG 0x2050 +#define MVPP2_TXQ_NUM_REG 0x2080 +#define MVPP2_TXQ_DESC_ADDR_REG 0x2084 +#define MVPP22_TXQ_DESC_ADDR_HIGH_REG 0x20a8 +#define MVPP22_TXQ_DESC_ADDR_HIGH_MASK 0xff +#define MVPP2_TXQ_DESC_SIZE_REG 0x2088 +#define MVPP2_TXQ_DESC_SIZE_MASK 0x3ff0 +#define MVPP2_AGGR_TXQ_UPDATE_REG 0x2090 +#define MVPP2_TXQ_THRESH_REG 0x2094 +#define MVPP2_TRANSMITTED_THRESH_OFFSET 16 +#define MVPP2_TRANSMITTED_THRESH_MASK 0x3fff0000 +#define MVPP2_TXQ_INDEX_REG 0x2098 +#define MVPP2_TXQ_PREF_BUF_REG 0x209c +#define MVPP2_PREF_BUF_PTR(desc) ((desc) & 0xfff) +#define MVPP2_PREF_BUF_SIZE_4 (BIT(12) | BIT(13)) +#define MVPP2_PREF_BUF_SIZE_16 (BIT(12) | BIT(14)) +#define MVPP2_PREF_BUF_THRESH(val) ((val) << 17) +#define MVPP2_TXQ_DRAIN_EN_MASK BIT(31) +#define MVPP2_TXQ_PENDING_REG 0x20a0 +#define MVPP2_TXQ_PENDING_MASK 0x3fff +#define MVPP2_TXQ_INT_STATUS_REG 0x20a4 +#define MVPP2_TXQ_SENT_REG(txq) (0x3c00 + 4 * (txq)) +#define MVPP22_TXQ_SENT_REG(txq) (0x3e00 + 4 * (txq-128)) +#define MVPP2_TRANSMITTED_COUNT_OFFSET 16 +#define MVPP2_TRANSMITTED_COUNT_MASK 0x3fff0000 +#define MVPP2_TXQ_RSVD_REQ_REG 0x20b0 +#define MVPP2_TXQ_RSVD_REQ_Q_OFFSET 16 +#define MVPP2_TXQ_RSVD_RSLT_REG 0x20b4 +#define MVPP2_TXQ_RSVD_RSLT_MASK 0x3fff +#define MVPP2_TXQ_RSVD_CLR_REG 0x20b8 +#define MVPP2_TXQ_RSVD_CLR_OFFSET 16 +#define MVPP2_AGGR_TXQ_DESC_ADDR_REG(cpu) (0x2100 + 4 * (cpu)) +#define MVPP2_AGGR_TXQ_DESC_SIZE_REG(cpu) (0x2140 + 4 * (cpu)) +#define MVPP2_AGGR_TXQ_DESC_SIZE_MASK 0x3ff0 +#define MVPP2_AGGR_TXQ_STATUS_REG(cpu) (0x2180 + 4 * (cpu)) +#define MVPP2_AGGR_TXQ_PENDING_MASK 0x3fff +#define MVPP2_AGGR_TXQ_INDEX_REG(cpu) (0x21c0 + 4 * (cpu)) + +/* MBUS bridge registers */ +#define MVPP2_WIN_BASE(w) (0x4000 + ((w) << 2)) +#define MVPP2_WIN_SIZE(w) (0x4020 + ((w) << 2)) +#define MVPP2_WIN_REMAP(w) (0x4040 + ((w) << 2)) +#define MVPP2_BASE_ADDR_ENABLE 0x4060 + +/* Interrupt Cause and Mask registers */ +#define MVPP2_ISR_RX_THRESHOLD_REG(rxq) (0x5200 + 4 * (rxq)) +#define MVPP2_ISR_RXQ_GROUP_REG(rxq) (0x5400 + 4 * (rxq)) +#define MVPP2_ISR_ENABLE_REG(port) (0x5420 + 4 * (port)) +#define MVPP2_ISR_ENABLE_INTERRUPT(mask) ((mask) & 0xffff) +#define MVPP2_ISR_DISABLE_INTERRUPT(mask) (((mask) << 16) & 0xffff0000) +#define MVPP2_ISR_RX_TX_CAUSE_REG(port) (0x5480 + 4 * (port)) +#define MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK 0xffff +#define MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK 0xff0000 +#define MVPP2_CAUSE_RX_FIFO_OVERRUN_MASK BIT(24) +#define MVPP2_CAUSE_FCS_ERR_MASK BIT(25) +#define MVPP2_CAUSE_TX_FIFO_UNDERRUN_MASK BIT(26) +#define MVPP2_CAUSE_TX_EXCEPTION_SUM_MASK BIT(29) +#define MVPP2_CAUSE_RX_EXCEPTION_SUM_MASK BIT(30) +#define MVPP2_CAUSE_MISC_SUM_MASK BIT(31) +#define MVPP2_ISR_RX_TX_MASK_REG(port) (0x54a0 + 4 * (port)) +#define MVPP2_ISR_PON_RX_TX_MASK_REG 0x54bc +#define MVPP2_PON_CAUSE_RXQ_OCCUP_DESC_ALL_MASK 0xffff +#define MVPP2_PON_CAUSE_TXP_OCCUP_DESC_ALL_MASK 0x3fc00000 +#define MVPP2_PON_CAUSE_MISC_SUM_MASK BIT(31) +#define MVPP2_ISR_MISC_CAUSE_REG 0x55b0 + +/* Buffer Manager registers */ +#define MVPP2_BM_POOL_BASE_REG(pool) (0x6000 + ((pool) * 4)) +#define MVPP2_BM_POOL_BASE_ADDR_MASK 0xfffff80 +#define MVPP2_BM_POOL_SIZE_REG(pool) (0x6040 + ((pool) * 4)) +#define MVPP2_BM_POOL_SIZE_MASK 0xfff0 +#define MVPP2_BM_POOL_READ_PTR_REG(pool) (0x6080 + ((pool) * 4)) +#define MVPP2_BM_POOL_GET_READ_PTR_MASK 0xfff0 +#define MVPP2_BM_POOL_PTRS_NUM_REG(pool) (0x60c0 + ((pool) * 4)) +#define MVPP2_BM_POOL_PTRS_NUM_MASK 0xfff0 +#define MVPP2_BM_BPPI_READ_PTR_REG(pool) (0x6100 + ((pool) * 4)) +#define MVPP2_BM_BPPI_PTRS_NUM_REG(pool) (0x6140 + ((pool) * 4)) +#define MVPP2_BM_BPPI_PTR_NUM_MASK 0x7ff +#define MVPP2_BM_BPPI_PREFETCH_FULL_MASK BIT(16) +#define MVPP2_BM_POOL_CTRL_REG(pool) (0x6200 + ((pool) * 4)) +#define MVPP2_BM_START_MASK BIT(0) +#define MVPP2_BM_STOP_MASK BIT(1) +#define MVPP2_BM_STATE_MASK BIT(4) +#define MVPP2_BM_LOW_THRESH_OFFS 8 +#define MVPP2_BM_LOW_THRESH_MASK 0x7f00 +#define MVPP2_BM_LOW_THRESH_VALUE(val) ((val) << MVPP2_BM_LOW_THRESH_OFFS) +#define MVPP2_BM_HIGH_THRESH_OFFS 16 +#define MVPP2_BM_HIGH_THRESH_MASK 0x7f0000 +#define MVPP2_BM_HIGH_THRESH_VALUE(val) ((val) << MVPP2_BM_HIGH_THRESH_OFFS) +#define MVPP2_BM_INTR_CAUSE_REG(pool) (0x6240 + ((pool) * 4)) +#define MVPP2_BM_RELEASED_DELAY_MASK BIT(0) +#define MVPP2_BM_ALLOC_FAILED_MASK BIT(1) +#define MVPP2_BM_BPPE_EMPTY_MASK BIT(2) +#define MVPP2_BM_BPPE_FULL_MASK BIT(3) +#define MVPP2_BM_AVAILABLE_BP_LOW_MASK BIT(4) +#define MVPP2_BM_INTR_MASK_REG(pool) (0x6280 + ((pool) * 4)) +#define MVPP2_BM_PHY_ALLOC_REG(pool) (0x6400 + ((pool) * 4)) +#define MVPP2_BM_PHY_ALLOC_GRNTD_MASK BIT(0) +#define MVPP2_BM_VIRT_ALLOC_REG 0x6440 +#define MVPP2_BM_PHY_RLS_REG(pool) (0x6480 + ((pool) * 4)) +#define MVPP2_BM_PHY_RLS_MC_BUFF_MASK BIT(0) +#define MVPP2_BM_PHY_RLS_PRIO_EN_MASK BIT(1) +#define MVPP2_BM_PHY_RLS_GRNTD_MASK BIT(2) +#define MVPP2_BM_VIRT_RLS_REG 0x64c0 +#define MVPP2_BM_MC_RLS_REG 0x64c4 +#define MVPP2_BM_MC_ID_MASK 0xfff +#define MVPP2_BM_FORCE_RELEASE_MASK BIT(12) + +#define MVPP22_BM_PHY_VIRT_HIGH_ALLOC_REG 0x6444 +#define MVPP22_BM_PHY_HIGH_ALLOC_OFFSET 0 +#define MVPP22_BM_VIRT_HIGH_ALLOC_OFFSET 8 +#define MVPP22_BM_VIRT_HIGH_ALLOC_MASK 0xff00 + +#define MVPP22_BM_PHY_VIRT_HIGH_RLS_REG 0x64c4 + +#define MVPP22_BM_PHY_HIGH_RLS_OFFSET 0 +#define MVPP22_BM_VIRT_HIGH_RLS_OFFST 8 + +#define MVPP22_BM_POOL_BASE_HIGH_REG 0x6310 +#define MVPP22_BM_POOL_BASE_HIGH_MASK 0xff +#define MVPP2_BM_PRIO_CTRL_REG 0x6800 + +/* TX Scheduler registers */ +#define MVPP2_TXP_SCHED_PORT_INDEX_REG 0x8000 +#define MVPP2_TXP_SCHED_Q_CMD_REG 0x8004 +#define MVPP2_TXP_SCHED_ENQ_MASK 0xff +#define MVPP2_TXP_SCHED_DISQ_OFFSET 8 +#define MVPP2_TXP_SCHED_CMD_1_REG 0x8010 +#define MVPP2_TXP_SCHED_PERIOD_REG 0x8018 +#define MVPP2_TXP_SCHED_MTU_REG 0x801c +#define MVPP2_TXP_MTU_MAX 0x7FFFF +#define MVPP2_TXP_SCHED_REFILL_REG 0x8020 +#define MVPP2_TXP_REFILL_TOKENS_ALL_MASK 0x7ffff +#define MVPP2_TXP_REFILL_PERIOD_ALL_MASK 0x3ff00000 +#define MVPP2_TXP_REFILL_PERIOD_MASK(v) ((v) << 20) +#define MVPP2_TXP_SCHED_TOKEN_SIZE_REG 0x8024 +#define MVPP2_TXP_TOKEN_SIZE_MAX 0xffffffff +#define MVPP2_TXQ_SCHED_REFILL_REG(q) (0x8040 + ((q) << 2)) +#define MVPP2_TXQ_REFILL_TOKENS_ALL_MASK 0x7ffff +#define MVPP2_TXQ_REFILL_PERIOD_ALL_MASK 0x3ff00000 +#define MVPP2_TXQ_REFILL_PERIOD_MASK(v) ((v) << 20) +#define MVPP2_TXQ_SCHED_TOKEN_SIZE_REG(q) (0x8060 + ((q) << 2)) +#define MVPP2_TXQ_TOKEN_SIZE_MAX 0x7fffffff +#define MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(q) (0x8080 + ((q) << 2)) +#define MVPP2_TXQ_TOKEN_CNTR_MAX 0xffffffff + +/* TX general registers */ +#define MVPP2_TX_SNOOP_REG 0x8800 +#define MVPP2_TX_PORT_FLUSH_REG 0x8810 +#define MVPP2_TX_PORT_FLUSH_MASK(port) (1 << (port)) + +/* LMS registers */ +#define MVPP2_SRC_ADDR_MIDDLE 0x24 +#define MVPP2_SRC_ADDR_HIGH 0x28 +#define MVPP2_PHY_AN_CFG0_REG 0x34 +#define MVPP2_PHY_AN_STOP_SMI0_MASK BIT(7) +#define MVPP2_MIB_COUNTERS_BASE(port) (0x1000 + ((port) >> 1) * 0x400 + (port) * 0x400) +#define MVPP2_MIB_LATE_COLLISION 0x7c +#define MVPP2_ISR_SUM_MASK_REG 0x220c +#define MVPP2_MNG_EXTENDED_GLOBAL_CTRL_REG 0x305c +#define MVPP2_EXT_GLOBAL_CTRL_DEFAULT 0x27 + +/* Per-port registers */ +#define MVPP2_GMAC_CTRL_0_REG 0x0 +#define MVPP2_GMAC_PORT_EN_MASK BIT(0) +#define MVPP2_GMAC_MAX_RX_SIZE_OFFS 2 +#define MVPP2_GMAC_MAX_RX_SIZE_MASK 0x7ffc +#define MVPP2_GMAC_MIB_CNTR_EN_MASK BIT(15) +#define MVPP2_GMAC_CTRL_1_REG 0x4 +#define MVPP2_GMAC_PERIODIC_XON_EN_MASK BIT(1) +#define MVPP2_GMAC_GMII_LB_EN_MASK BIT(5) +#define MVPP2_GMAC_PCS_LB_EN_BIT 6 +#define MVPP2_GMAC_PCS_LB_EN_MASK BIT(6) +#define MVPP2_GMAC_SA_LOW_OFFS 7 +#define MVPP2_GMAC_CTRL_2_REG 0x8 +#define MVPP2_GMAC_INBAND_AN_MASK BIT(0) +#define MVPP2_GMAC_PCS_ENABLE_MASK BIT(3) +#define MVPP2_GMAC_PORT_RGMII_MASK BIT(4) +#define MVPP2_GMAC_PORT_RESET_MASK BIT(6) +#define MVPP2_GMAC_AUTONEG_CONFIG 0xc +#define MVPP2_GMAC_FORCE_LINK_DOWN BIT(0) +#define MVPP2_GMAC_FORCE_LINK_PASS BIT(1) +#define MVPP2_GMAC_CONFIG_MII_SPEED BIT(5) +#define MVPP2_GMAC_CONFIG_GMII_SPEED BIT(6) +#define MVPP2_GMAC_AN_SPEED_EN BIT(7) +#define MVPP2_GMAC_FC_ADV_EN BIT(9) +#define MVPP2_GMAC_CONFIG_FULL_DUPLEX BIT(12) +#define MVPP2_GMAC_AN_DUPLEX_EN BIT(13) +#define MVPP2_GMAC_PORT_FIFO_CFG_1_REG 0x1c +#define MVPP2_GMAC_TX_FIFO_MIN_TH_OFFS 6 +#define MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK 0x1fc0 +#define MVPP2_GMAC_TX_FIFO_MIN_TH_MASK(v) (((v) << 6) & MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK) + +/* Port Interrupts */ +#define MV_GMAC_INTERRUPT_CAUSE_REG (0x0020) +#define MV_GMAC_INTERRUPT_MASK_REG (0x0024) +#define MV_GMAC_INTERRUPT_CAUSE_LINK_CHANGE_OFFS 1 +#define MV_GMAC_INTERRUPT_CAUSE_LINK_CHANGE_MASK (0x1 << MV_GMAC_INTERRUPT_CAUSE_LINK_CHANGE_OFFS) + +/* Port Interrupt Summary */ +#define MV_GMAC_INTERRUPT_SUM_CAUSE_REG (0x00A0) +#define MV_GMAC_INTERRUPT_SUM_MASK_REG (0x00A4) +#define MV_GMAC_INTERRUPT_SUM_CAUSE_LINK_CHANGE_OFFS 1 +#define MV_GMAC_INTERRUPT_SUM_CAUSE_LINK_CHANGE_MASK (0x1 << MV_GMAC_INTERRUPT_SUM_CAUSE_LINK_CHANGE_OFFS) + +/* Port Mac Control0 */ +#define MVPP2_PORT_CTRL0_REG (0x0000) +#define MVPP2_PORT_CTRL0_PORTEN_OFFS 0 +#define MVPP2_PORT_CTRL0_PORTEN_MASK \ + (0x00000001 << MVPP2_PORT_CTRL0_PORTEN_OFFS) + +#define MVPP2_PORT_CTRL0_PORTTYPE_OFFS 1 +#define MVPP2_PORT_CTRL0_PORTTYPE_MASK \ + (0x00000001 << MVPP2_PORT_CTRL0_PORTTYPE_OFFS) + +#define MVPP2_PORT_CTRL0_FRAMESIZELIMIT_OFFS 2 +#define MVPP2_PORT_CTRL0_FRAMESIZELIMIT_MASK \ + (0x00001fff << MVPP2_PORT_CTRL0_FRAMESIZELIMIT_OFFS) + +#define MVPP2_PORT_CTRL0_COUNT_EN_OFFS 15 +#define MVPP2_PORT_CTRL0_COUNT_EN_MASK \ + (0x00000001 << MVPP2_PORT_CTRL0_COUNT_EN_OFFS) + +/* Port Mac Control1 */ +#define MVPP2_PORT_CTRL1_REG (0x0004) +#define MVPP2_PORT_CTRL1_EN_RX_CRC_CHECK_OFFS 0 +#define MVPP2_PORT_CTRL1_EN_RX_CRC_CHECK_MASK \ + (0x00000001 << MVPP2_PORT_CTRL1_EN_RX_CRC_CHECK_OFFS) + +#define MVPP2_PORT_CTRL1_EN_PERIODIC_FC_XON_OFFS 1 +#define MVPP2_PORT_CTRL1_EN_PERIODIC_FC_XON_MASK \ + (0x00000001 << MVPP2_PORT_CTRL1_EN_PERIODIC_FC_XON_OFFS) + +#define MVPP2_PORT_CTRL1_MGMII_MODE_OFFS 2 +#define MVPP2_PORT_CTRL1_MGMII_MODE_MASK \ + (0x00000001 << MVPP2_PORT_CTRL1_MGMII_MODE_OFFS) + +#define MVPP2_PORT_CTRL1_PFC_CASCADE_PORT_ENABLE_OFFS 3 +#define MVPP2_PORT_CTRL1_PFC_CASCADE_PORT_ENABLE_MASK \ + (0x00000001 << MVPP2_PORT_CTRL1_PFC_CASCADE_PORT_ENABLE_OFFS) + +#define MVPP2_PORT_CTRL1_DIS_EXCESSIVE_COL_OFFS 4 +#define MVPP2_PORT_CTRL1_DIS_EXCESSIVE_COL_MASK \ + (0x00000001 << MVPP2_PORT_CTRL1_DIS_EXCESSIVE_COL_OFFS) + +#define MVPP2_PORT_CTRL1_GMII_LOOPBACK_OFFS 5 +#define MVPP2_PORT_CTRL1_GMII_LOOPBACK_MASK \ + (0x00000001 << MVPP2_PORT_CTRL1_GMII_LOOPBACK_OFFS) + +#define MVPP2_PORT_CTRL1_PCS_LOOPBACK_OFFS 6 +#define MVPP2_PORT_CTRL1_PCS_LOOPBACK_MASK \ + (0x00000001 << MVPP2_PORT_CTRL1_PCS_LOOPBACK_OFFS) + +#define MVPP2_PORT_CTRL1_FC_SA_ADDR_LO_OFFS 7 +#define MVPP2_PORT_CTRL1_FC_SA_ADDR_LO_MASK \ + (0x000000ff << MVPP2_PORT_CTRL1_FC_SA_ADDR_LO_OFFS) + +#define MVPP2_PORT_CTRL1_EN_SHORT_PREAMBLE_OFFS 15 +#define MVPP2_PORT_CTRL1_EN_SHORT_PREAMBLE_MASK \ + (0x00000001 << MVPP2_PORT_CTRL1_EN_SHORT_PREAMBLE_OFFS) + +/* Port Mac Control2 */ +#define MVPP2_PORT_CTRL2_REG (0x0008) +#define MVPP2_PORT_CTRL2_SGMII_MODE_OFFS 0 +#define MVPP2_PORT_CTRL2_SGMII_MODE_MASK \ + (0x00000001 << MVPP2_PORT_CTRL2_SGMII_MODE_OFFS) + +#define MVPP2_PORT_CTRL2_FC_MODE_OFFS 1 +#define MVPP2_PORT_CTRL2_FC_MODE_MASK \ + (0x00000003 << MVPP2_PORT_CTRL2_FC_MODE_OFFS) + +#define MVPP2_PORT_CTRL2_PCS_EN_OFFS 3 +#define MVPP2_PORT_CTRL2_PCS_EN_MASK \ + (0x00000001 << MVPP2_PORT_CTRL2_PCS_EN_OFFS) + +#define MVPP2_PORT_CTRL2_RGMII_MODE_OFFS 4 +#define MVPP2_PORT_CTRL2_RGMII_MODE_MASK \ + (0x00000001 << MVPP2_PORT_CTRL2_RGMII_MODE_OFFS) + +#define MVPP2_PORT_CTRL2_DIS_PADING_OFFS 5 +#define MVPP2_PORT_CTRL2_DIS_PADING_MASK \ + (0x00000001 << MVPP2_PORT_CTRL2_DIS_PADING_OFFS) + +#define MVPP2_PORT_CTRL2_PORTMACRESET_OFFS 6 +#define MVPP2_PORT_CTRL2_PORTMACRESET_MASK \ + (0x00000001 << MVPP2_PORT_CTRL2_PORTMACRESET_OFFS) + +#define MVPP2_PORT_CTRL2_TX_DRAIN_OFFS 7 +#define MVPP2_PORT_CTRL2_TX_DRAIN_MASK \ + (0x00000001 << MVPP2_PORT_CTRL2_TX_DRAIN_OFFS) + +#define MVPP2_PORT_CTRL2_EN_MII_ODD_PRE_OFFS 8 +#define MVPP2_PORT_CTRL2_EN_MII_ODD_PRE_MASK \ + (0x00000001 << MVPP2_PORT_CTRL2_EN_MII_ODD_PRE_OFFS) + +#define MVPP2_PORT_CTRL2_CLK_125_BYPS_EN_OFFS 9 +#define MVPP2_PORT_CTRL2_CLK_125_BYPS_EN_MASK \ + (0x00000001 << MVPP2_PORT_CTRL2_CLK_125_BYPS_EN_OFFS) + +#define MVPP2_PORT_CTRL2_PRBS_CHECK_EN_OFFS 10 +#define MVPP2_PORT_CTRL2_PRBS_CHECK_EN_MASK \ + (0x00000001 << MVPP2_PORT_CTRL2_PRBS_CHECK_EN_OFFS) + +#define MVPP2_PORT_CTRL2_PRBS_GEN_EN_OFFS 11 +#define MVPP2_PORT_CTRL2_PRBS_GEN_EN_MASK \ + (0x00000001 << MVPP2_PORT_CTRL2_PRBS_GEN_EN_OFFS) + +#define MVPP2_PORT_CTRL2_SELECT_DATA_TO_TX_OFFS 12 +#define MVPP2_PORT_CTRL2_SELECT_DATA_TO_TX_MASK \ + (0x00000003 << MVPP2_PORT_CTRL2_SELECT_DATA_TO_TX_OFFS) + +#define MVPP2_PORT_CTRL2_EN_COL_ON_BP_OFFS 14 +#define MVPP2_PORT_CTRL2_EN_COL_ON_BP_MASK \ + (0x00000001 << MVPP2_PORT_CTRL2_EN_COL_ON_BP_OFFS) + +#define MVPP2_PORT_CTRL2_EARLY_REJECT_MODE_OFFS 15 +#define MVPP2_PORT_CTRL2_EARLY_REJECT_MODE_MASK \ + (0x00000001 << MVPP2_PORT_CTRL2_EARLY_REJECT_MODE_OFFS) + +/* Port Auto-negotiation Configuration */ +#define MVPP2_PORT_AUTO_NEG_CFG_REG (0x000c) +#define MVPP2_PORT_AUTO_NEG_CFG_FORCE_LINK_DOWN_OFFS 0 +#define MVPP2_PORT_AUTO_NEG_CFG_FORCE_LINK_DOWN_MASK \ + (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_FORCE_LINK_DOWN_OFFS) + +#define MVPP2_PORT_AUTO_NEG_CFG_FORCE_LINK_UP_OFFS 1 +#define MVPP2_PORT_AUTO_NEG_CFG_FORCE_LINK_UP_MASK \ + (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_FORCE_LINK_UP_OFFS) + +#define MVPP2_PORT_AUTO_NEG_CFG_EN_PCS_AN_OFFS 2 +#define MVPP2_PORT_AUTO_NEG_CFG_EN_PCS_AN_MASK \ + (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_EN_PCS_AN_OFFS) + +#define MVPP2_PORT_AUTO_NEG_CFG_AN_BYPASS_EN_OFFS 3 +#define MVPP2_PORT_AUTO_NEG_CFG_AN_BYPASS_EN_MASK \ + (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_AN_BYPASS_EN_OFFS) + +#define MVPP2_PORT_AUTO_NEG_CFG_INBAND_RESTARTAN_OFFS 4 +#define MVPP2_PORT_AUTO_NEG_CFG_INBAND_RESTARTAN_MASK \ + (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_INBAND_RESTARTAN_OFFS) + +#define MVPP2_PORT_AUTO_NEG_CFG_SET_MII_SPEED_OFFS 5 +#define MVPP2_PORT_AUTO_NEG_CFG_SET_MII_SPEED_MASK \ + (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_SET_MII_SPEED_OFFS) + +#define MVPP2_PORT_AUTO_NEG_CFG_SET_GMII_SPEED_OFFS 6 +#define MVPP2_PORT_AUTO_NEG_CFG_SET_GMII_SPEED_MASK \ + (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_SET_GMII_SPEED_OFFS) + +#define MVPP2_PORT_AUTO_NEG_CFG_EN_AN_SPEED_OFFS 7 +#define MVPP2_PORT_AUTO_NEG_CFG_EN_AN_SPEED_MASK \ + (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_EN_AN_SPEED_OFFS) + +#define MVPP2_PORT_AUTO_NEG_CFG_ADV_PAUSE_OFFS 9 +#define MVPP2_PORT_AUTO_NEG_CFG_ADV_PAUSE_MASK \ + (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_ADV_PAUSE_OFFS) + +#define MVPP2_PORT_AUTO_NEG_CFG_ADV_ASM_PAUSE_OFFS 10 +#define MVPP2_PORT_AUTO_NEG_CFG_ADV_ASM_PAUSE_MASK \ + (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_ADV_ASM_PAUSE_OFFS) + +#define MVPP2_PORT_AUTO_NEG_CFG_EN_FC_AN_OFFS 11 +#define MVPP2_PORT_AUTO_NEG_CFG_EN_FC_AN_MASK \ + (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_EN_FC_AN_OFFS) + +#define MVPP2_PORT_AUTO_NEG_CFG_SET_FULL_DX_OFFS 12 +#define MVPP2_PORT_AUTO_NEG_CFG_SET_FULL_DX_MASK \ + (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_SET_FULL_DX_OFFS) + +#define MVPP2_PORT_AUTO_NEG_CFG_EN_FDX_AN_OFFS 13 +#define MVPP2_PORT_AUTO_NEG_CFG_EN_FDX_AN_MASK \ + (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_EN_FDX_AN_OFFS) + +#define MVPP2_PORT_AUTO_NEG_CFG_PHY_MODE_OFFS 14 +#define MVPP2_PORT_AUTO_NEG_CFG_PHY_MODE_MASK \ + (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_PHY_MODE_OFFS) + +#define MVPP2_PORT_AUTO_NEG_CFG_CHOOSE_SAMPLE_TX_CONFIG_OFFS 15 +#define MVPP2_PORT_AUTO_NEG_CFG_CHOOSE_SAMPLE_TX_CONFIG_MASK \ + (0x00000001 << MVPP2_PORT_AUTO_NEG_CFG_CHOOSE_SAMPLE_TX_CONFIG_OFFS) + +/* Port Status0 */ +#define MVPP2_PORT_STATUS0_REG (0x0010) +#define MVPP2_PORT_STATUS0_LINKUP_OFFS 0 +#define MVPP2_PORT_STATUS0_LINKUP_MASK \ + (0x00000001 << MVPP2_PORT_STATUS0_LINKUP_OFFS) + +#define MVPP2_PORT_STATUS0_GMIISPEED_OFFS 1 +#define MVPP2_PORT_STATUS0_GMIISPEED_MASK \ + (0x00000001 << MVPP2_PORT_STATUS0_GMIISPEED_OFFS) + +#define MVPP2_PORT_STATUS0_MIISPEED_OFFS 2 +#define MVPP2_PORT_STATUS0_MIISPEED_MASK \ + (0x00000001 << MVPP2_PORT_STATUS0_MIISPEED_OFFS) + +#define MVPP2_PORT_STATUS0_FULLDX_OFFS 3 +#define MVPP2_PORT_STATUS0_FULLDX_MASK \ + (0x00000001 << MVPP2_PORT_STATUS0_FULLDX_OFFS) + +#define MVPP2_PORT_STATUS0_RXFCEN_OFFS 4 +#define MVPP2_PORT_STATUS0_RXFCEN_MASK \ + (0x00000001 << MVPP2_PORT_STATUS0_RXFCEN_OFFS) + +#define MVPP2_PORT_STATUS0_TXFCEN_OFFS 5 +#define MVPP2_PORT_STATUS0_TXFCEN_MASK \ + (0x00000001 << MVPP2_PORT_STATUS0_TXFCEN_OFFS) + +#define MVPP2_PORT_STATUS0_PORTRXPAUSE_OFFS 6 +#define MVPP2_PORT_STATUS0_PORTRXPAUSE_MASK \ + (0x00000001 << MVPP2_PORT_STATUS0_PORTRXPAUSE_OFFS) + +#define MVPP2_PORT_STATUS0_PORTTXPAUSE_OFFS 7 +#define MVPP2_PORT_STATUS0_PORTTXPAUSE_MASK \ + (0x00000001 << MVPP2_PORT_STATUS0_PORTTXPAUSE_OFFS) + +#define MVPP2_PORT_STATUS0_PORTIS_DOINGPRESSURE_OFFS 8 +#define MVPP2_PORT_STATUS0_PORTIS_DOINGPRESSURE_MASK \ + (0x00000001 << MVPP2_PORT_STATUS0_PORTIS_DOINGPRESSURE_OFFS) + +#define MVPP2_PORT_STATUS0_PORTBUFFULL_OFFS 9 +#define MVPP2_PORT_STATUS0_PORTBUFFULL_MASK \ + (0x00000001 << MVPP2_PORT_STATUS0_PORTBUFFULL_OFFS) + +#define MVPP2_PORT_STATUS0_SYNCFAIL10MS_OFFS 10 +#define MVPP2_PORT_STATUS0_SYNCFAIL10MS_MASK \ + (0x00000001 << MVPP2_PORT_STATUS0_SYNCFAIL10MS_OFFS) + +#define MVPP2_PORT_STATUS0_ANDONE_OFFS 11 +#define MVPP2_PORT_STATUS0_ANDONE_MASK \ + (0x00000001 << MVPP2_PORT_STATUS0_ANDONE_OFFS) + +#define MVPP2_PORT_STATUS0_INBAND_AUTONEG_BYPASSACT_OFFS 12 +#define MVPP2_PORT_STATUS0_INBAND_AUTONEG_BYPASSACT_MASK \ + (0x00000001 << MVPP2_PORT_STATUS0_INBAND_AUTONEG_BYPASSACT_OFFS) + +#define MVPP2_PORT_STATUS0_SERDESPLL_LOCKED_OFFS 13 +#define MVPP2_PORT_STATUS0_SERDESPLL_LOCKED_MASK \ + (0x00000001 << MVPP2_PORT_STATUS0_SERDESPLL_LOCKED_OFFS) + +#define MVPP2_PORT_STATUS0_SYNCOK_OFFS 14 +#define MVPP2_PORT_STATUS0_SYNCOK_MASK \ + (0x00000001 << MVPP2_PORT_STATUS0_SYNCOK_OFFS) + +#define MVPP2_PORT_STATUS0_SQUELCHNOT_DETECTED_OFFS 15 +#define MVPP2_PORT_STATUS0_SQUELCHNOT_DETECTED_MASK \ + (0x00000001 << MVPP2_PORT_STATUS0_SQUELCHNOT_DETECTED_OFFS) + +/* Port Serial Parameters Configuration */ +#define MVPP2_PORT_SERIAL_PARAM_CFG_REG (0x0014) +#define MVPP2_PORT_SERIAL_PARAM_CFG_UNIDIRECTIONAL_ENABLE_OFFS 0 +#define MVPP2_PORT_SERIAL_PARAM_CFG_UNIDIRECTIONAL_ENABLE_MASK \ + (0x00000001 << MVPP2_PORT_SERIAL_PARAM_CFG_UNIDIRECTIONAL_ENABLE_OFFS) + +#define MVPP2_PORT_SERIAL_PARAM_CFG_RETRANSMIT_COLLISION_DOMAIN_OFFS 1 +#define MVPP2_PORT_SERIAL_PARAM_CFG_RETRANSMIT_COLLISION_DOMAIN_MASK \ + (0x00000001 << MVPP2_PORT_SERIAL_PARAM_CFG_RETRANSMIT_COLLISION_DOMAIN_OFFS) + +#define MVPP2_PORT_SERIAL_PARAM_CFG_PUMA2_BTS1444_EN_OFFS 2 +#define MVPP2_PORT_SERIAL_PARAM_CFG_PUMA2_BTS1444_EN_MASK \ + (0x00000001 << MVPP2_PORT_SERIAL_PARAM_CFG_PUMA2_BTS1444_EN_OFFS) + +#define MVPP2_PORT_SERIAL_PARAM_CFG_FORWARD_802_3X_FC_EN_OFFS 3 +#define MVPP2_PORT_SERIAL_PARAM_CFG_FORWARD_802_3X_FC_EN_MASK \ + (0x00000001 << MVPP2_PORT_SERIAL_PARAM_CFG_FORWARD_802_3X_FC_EN_OFFS) + +#define MVPP2_PORT_SERIAL_PARAM_CFG_BP_EN_OFFS 4 +#define MVPP2_PORT_SERIAL_PARAM_CFG_BP_EN_MASK \ + (0x00000001 << MVPP2_PORT_SERIAL_PARAM_CFG_BP_EN_OFFS) + +#define MVPP2_PORT_SERIAL_PARAM_CFG_RX_NEGEDGE_SAMPLE_EN_OFFS 5 +#define MVPP2_PORT_SERIAL_PARAM_CFG_RX_NEGEDGE_SAMPLE_EN_MASK \ + (0x00000001 << MVPP2_PORT_SERIAL_PARAM_CFG_RX_NEGEDGE_SAMPLE_EN_OFFS) + +#define MVPP2_PORT_SERIAL_PARAM_CFG_COL_DOMAIN_LIMIT_OFFS 6 +#define MVPP2_PORT_SERIAL_PARAM_CFG_COL_DOMAIN_LIMIT_MASK \ + (0x0000003f << MVPP2_PORT_SERIAL_PARAM_CFG_COL_DOMAIN_LIMIT_OFFS) + +#define MVPP2_PORT_SERIAL_PARAM_CFG_PERIODIC_TYPE_SELECT_OFFS 12 +#define MVPP2_PORT_SERIAL_PARAM_CFG_PERIODIC_TYPE_SELECT_MASK \ + (0x00000001 << MVPP2_PORT_SERIAL_PARAM_CFG_PERIODIC_TYPE_SELECT_OFFS) + +#define MVPP2_PORT_SERIAL_PARAM_CFG_PER_PRIORITY_FC_EN_OFFS 13 +#define MVPP2_PORT_SERIAL_PARAM_CFG_PER_PRIORITY_FC_EN_MASK \ + (0x00000001 << MVPP2_PORT_SERIAL_PARAM_CFG_PER_PRIORITY_FC_EN_OFFS) + +#define MVPP2_PORT_SERIAL_PARAM_CFG_TX_STANDARD_PRBS7_OFFS 14 +#define MVPP2_PORT_SERIAL_PARAM_CFG_TX_STANDARD_PRBS7_MASK \ + (0x00000001 << MVPP2_PORT_SERIAL_PARAM_CFG_TX_STANDARD_PRBS7_OFFS) + +#define MVPP2_PORT_SERIAL_PARAM_CFG_REVERSE_PRBS_RX_OFFS 15 +#define MVPP2_PORT_SERIAL_PARAM_CFG_REVERSE_PRBS_RX_MASK \ + (0x00000001 << MVPP2_PORT_SERIAL_PARAM_CFG_REVERSE_PRBS_RX_OFFS) + +/* Port Fifo Configuration 0 */ +#define MVPP2_PORT_FIFO_CFG_0_REG (0x0018) +#define MVPP2_PORT_FIFO_CFG_0_TX_FIFO_HIGH_WM_OFFS 0 +#define MVPP2_PORT_FIFO_CFG_0_TX_FIFO_HIGH_WM_MASK \ + (0x000000ff << MVPP2_PORT_FIFO_CFG_0_TX_FIFO_HIGH_WM_OFFS) + +#define MVPP2_PORT_FIFO_CFG_0_TX_FIFO_LOW_WM_OFFS 8 +#define MVPP2_PORT_FIFO_CFG_0_TX_FIFO_LOW_WM_MASK \ + (0x000000ff << MVPP2_PORT_FIFO_CFG_0_TX_FIFO_LOW_WM_OFFS) + +/* Port Fifo Configuration 1 */ +#define MVPP2_PORT_FIFO_CFG_1_REG (0x001c) +#define MVPP2_PORT_FIFO_CFG_1_RX_FIFO_MAX_TH_OFFS 0 +#define MVPP2_PORT_FIFO_CFG_1_RX_FIFO_MAX_TH_MASK \ + (0x0000003f << MVPP2_PORT_FIFO_CFG_1_RX_FIFO_MAX_TH_OFFS) + +#define MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_OFFS 6 +#define MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_MASK \ + (0x000000ff << MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_OFFS) + +#define MVPP2_PORT_FIFO_CFG_1_PORT_EN_FIX_EN_OFFS 15 +#define MVPP2_PORT_FIFO_CFG_1_PORT_EN_FIX_EN_MASK \ + (0x00000001 << MVPP2_PORT_FIFO_CFG_1_PORT_EN_FIX_EN_OFFS) + +/* Port Serdes Configuration0 */ +#define MVPP2_PORT_SERDES_CFG0_REG (0x0028) +#define MVPP2_PORT_SERDES_CFG0_SERDESRESET_OFFS 0 +#define MVPP2_PORT_SERDES_CFG0_SERDESRESET_MASK \ + (0x00000001 << MVPP2_PORT_SERDES_CFG0_SERDESRESET_OFFS) + +#define MVPP2_PORT_SERDES_CFG0_PU_TX_OFFS 1 +#define MVPP2_PORT_SERDES_CFG0_PU_TX_MASK \ + (0x00000001 << MVPP2_PORT_SERDES_CFG0_PU_TX_OFFS) + +#define MVPP2_PORT_SERDES_CFG0_PU_RX_OFFS 2 +#define MVPP2_PORT_SERDES_CFG0_PU_RX_MASK \ + (0x00000001 << MVPP2_PORT_SERDES_CFG0_PU_RX_OFFS) + +#define MVPP2_PORT_SERDES_CFG0_PU_PLL_OFFS 3 +#define MVPP2_PORT_SERDES_CFG0_PU_PLL_MASK \ + (0x00000001 << MVPP2_PORT_SERDES_CFG0_PU_PLL_OFFS) + +#define MVPP2_PORT_SERDES_CFG0_PU_IVREF_OFFS 4 +#define MVPP2_PORT_SERDES_CFG0_PU_IVREF_MASK \ + (0x00000001 << MVPP2_PORT_SERDES_CFG0_PU_IVREF_OFFS) + +#define MVPP2_PORT_SERDES_CFG0_TESTEN_OFFS 5 +#define MVPP2_PORT_SERDES_CFG0_TESTEN_MASK \ + (0x00000001 << MVPP2_PORT_SERDES_CFG0_TESTEN_OFFS) + +#define MVPP2_PORT_SERDES_CFG0_DPHER_EN_OFFS 6 +#define MVPP2_PORT_SERDES_CFG0_DPHER_EN_MASK \ + (0x00000001 << MVPP2_PORT_SERDES_CFG0_DPHER_EN_OFFS) + +#define MVPP2_PORT_SERDES_CFG0_RUDI_INVALID_ENABLE_OFFS 7 +#define MVPP2_PORT_SERDES_CFG0_RUDI_INVALID_ENABLE_MASK \ + (0x00000001 << MVPP2_PORT_SERDES_CFG0_RUDI_INVALID_ENABLE_OFFS) + +#define MVPP2_PORT_SERDES_CFG0_ACK_OVERRIDE_ENABLE_OFFS 8 +#define MVPP2_PORT_SERDES_CFG0_ACK_OVERRIDE_ENABLE_MASK \ + (0x00000001 << MVPP2_PORT_SERDES_CFG0_ACK_OVERRIDE_ENABLE_OFFS) + +#define MVPP2_PORT_SERDES_CFG0_CONFIG_WORD_ENABLE_OFFS 9 +#define MVPP2_PORT_SERDES_CFG0_CONFIG_WORD_ENABLE_MASK \ + (0x00000001 << MVPP2_PORT_SERDES_CFG0_CONFIG_WORD_ENABLE_OFFS) + +#define MVPP2_PORT_SERDES_CFG0_SYNC_FAIL_INT_ENABLE_OFFS 10 +#define MVPP2_PORT_SERDES_CFG0_SYNC_FAIL_INT_ENABLE_MASK \ + (0x00000001 << MVPP2_PORT_SERDES_CFG0_SYNC_FAIL_INT_ENABLE_OFFS) + +#define MVPP2_PORT_SERDES_CFG0_MASTER_MODE_ENABLE_OFFS 11 +#define MVPP2_PORT_SERDES_CFG0_MASTER_MODE_ENABLE_MASK \ + (0x00000001 << MVPP2_PORT_SERDES_CFG0_MASTER_MODE_ENABLE_OFFS) + +#define MVPP2_PORT_SERDES_CFG0_TERM75_TX_OFFS 12 +#define MVPP2_PORT_SERDES_CFG0_TERM75_TX_MASK \ + (0x00000001 << MVPP2_PORT_SERDES_CFG0_TERM75_TX_OFFS) + +#define MVPP2_PORT_SERDES_CFG0_OUTAMP_OFFS 13 +#define MVPP2_PORT_SERDES_CFG0_OUTAMP_MASK \ + (0x00000001 << MVPP2_PORT_SERDES_CFG0_OUTAMP_OFFS) + +#define MVPP2_PORT_SERDES_CFG0_BTS712_FIX_EN_OFFS 14 +#define MVPP2_PORT_SERDES_CFG0_BTS712_FIX_EN_MASK \ + (0x00000001 << MVPP2_PORT_SERDES_CFG0_BTS712_FIX_EN_OFFS) + +#define MVPP2_PORT_SERDES_CFG0_BTS156_FIX_EN_OFFS 15 +#define MVPP2_PORT_SERDES_CFG0_BTS156_FIX_EN_MASK \ + (0x00000001 << MVPP2_PORT_SERDES_CFG0_BTS156_FIX_EN_OFFS) + +/* Port Serdes Configuration1 */ +#define MVPP2_PORT_SERDES_CFG1_REG (0x002c) +#define MVPP2_PORT_SERDES_CFG1_SMII_RX_10MB_CLK_EDGE_SEL_OFFS 0 +#define MVPP2_PORT_SERDES_CFG1_SMII_RX_10MB_CLK_EDGE_SEL_MASK \ + (0x00000001 << MVPP2_GMAC_PORT_SERDES_CFG1_SMII_RX_10MB_CLK_EDGE_SEL_OFFS) + +#define MVPP2_GMAC_PORT_SERDES_CFG1_SMII_TX_10MB_CLK_EDGE_SEL_OFFS 1 +#define MVPP2_GMAC_PORT_SERDES_CFG1_SMII_TX_10MB_CLK_EDGE_SEL_MASK \ + (0x00000001 << MVPP2_GMAC_PORT_SERDES_CFG1_SMII_TX_10MB_CLK_EDGE_SEL_OFFS) + +#define MVPP2_GMAC_PORT_SERDES_CFG1_MEN_OFFS 2 +#define MVPP2_GMAC_PORT_SERDES_CFG1_MEN_MASK \ + (0x00000003 << MVPP2_GMAC_PORT_SERDES_CFG1_MEN_OFFS) + +#define MVPP2_GMAC_PORT_SERDES_CFG1_VCMS_OFFS 4 +#define MVPP2_GMAC_PORT_SERDES_CFG1_VCMS_MASK \ + (0x00000001 << MVPP2_GMAC_PORT_SERDES_CFG1_VCMS_OFFS) + +#define MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_USE_SIGDET_OFFS 5 +#define MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_USE_SIGDET_MASK \ + (0x00000001 << MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_USE_SIGDET_OFFS) + +#define MVPP2_GMAC_PORT_SERDES_CFG1_EN_CRS_MASK_TX_OFFS 6 +#define MVPP2_GMAC_PORT_SERDES_CFG1_EN_CRS_MASK_TX_MASK \ + (0x00000001 << MVPP2_GMAC_PORT_SERDES_CFG1_EN_CRS_MASK_TX_OFFS) + +#define MVPP2_GMAC_PORT_SERDES_CFG1_100FX_ENABLE_OFFS 7 +#define MVPP2_GMAC_PORT_SERDES_CFG1_100FX_ENABLE_MASK \ + (0x00000001 << MVPP2_GMAC_PORT_SERDES_CFG1_100FX_ENABLE_OFFS) + +#define MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_PHY_ADDRESS_OFFS 8 +#define MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_PHY_ADDRESS_MASK \ + (0x0000001f << MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_PHY_ADDRESS_OFFS) + +#define MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_SIGDET_POLARITY_OFFS 13 +#define MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_SIGDET_POLARITY_MASK \ + (0x00000001 << MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_SIGDET_POLARITY_OFFS) + +#define MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_INTERRUPT_POLARITY_OFFS 14 +#define MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_INTERRUPT_POLARITY_MASK \ + (0x00000001 << MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_INTERRUPT_POLARITY_OFFS) + +#define MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_SERDES_POLARITY_OFFS 15 +#define MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_SERDES_POLARITY_MASK \ + (0x00000001 << MVPP2_GMAC_PORT_SERDES_CFG1_100FX_PCS_SERDES_POLARITY_OFFS) + +/* Port Serdes Configuration2 */ +#define MVPP2_PORT_SERDES_CFG2_REG (0x0030) +#define MVPP2_PORT_SERDES_CFG2_AN_ADV_CONFIGURATION_OFFS 0 +#define MVPP2_PORT_SERDES_CFG2_AN_ADV_CONFIGURATION_MASK \ + (0x0000ffff << MVPP2_PORT_SERDES_CFG2_AN_ADV_CONFIGURATION_OFFS) + +/* Port Serdes Configuration3 */ +#define MVPP2_PORT_SERDES_CFG3_REG (0x0034) +#define MVPP2_PORT_SERDES_CFG3_ABILITY_MATCH_STATUS_OFFS 0 +#define MVPP2_PORT_SERDES_CFG3_ABILITY_MATCH_STATUS_MASK \ + (0x0000ffff << MVPP2_PORT_SERDES_CFG3_ABILITY_MATCH_STATUS_OFFS) + +/* Port Prbs Status */ +#define MVPP2_PORT_PRBS_STATUS_REG (0x0038) +#define MVPP2_PORT_PRBS_STATUS_PRBSCHECK_LOCKED_OFFS 0 +#define MVPP2_PORT_PRBS_STATUS_PRBSCHECK_LOCKED_MASK \ + (0x00000001 << MVPP2_PORT_PRBS_STATUS_PRBSCHECK_LOCKED_OFFS) + +#define MVPP2_PORT_PRBS_STATUS_PRBSCHECKRDY_OFFS 1 +#define MVPP2_PORT_PRBS_STATUS_PRBSCHECKRDY_MASK \ + (0x00000001 << MVPP2_PORT_PRBS_STATUS_PRBSCHECKRDY_OFFS) + +/* Port Prbs Error Counter */ +#define MVPP2_PORT_PRBS_ERR_CNTR_REG (0x003c) +#define MVPP2_PORT_PRBS_ERR_CNTR_PRBSBITERRCNT_OFFS 0 +#define MVPP2_PORT_PRBS_ERR_CNTR_PRBSBITERRCNT_MASK \ + (0x0000ffff << MVPP2_PORT_PRBS_ERR_CNTR_PRBSBITERRCNT_OFFS) + +/* Port Status1 */ +#define MVPP2_PORT_STATUS1_REG (0x0040) +#define MVPP2_PORT_STATUS1_MEDIAACTIVE_OFFS 0 +#define MVPP2_PORT_STATUS1_MEDIAACTIVE_MASK \ + (0x00000001 << MVPP2_PORT_STATUS1_MEDIAACTIVE_OFFS) + +/* Port Mib Counters Control */ +#define MVPP2_PORT_MIB_CNTRS_CTRL_REG (0x0044) +#define MVPP2_PORT_MIB_CNTRS_CTRL_MIB_COPY_TRIGGER_OFFS 0 +#define MVPP2_PORT_MIB_CNTRS_CTRL_MIB_COPY_TRIGGER_MASK \ + (0x00000001 << MVPP2_PORT_MIB_CNTRS_CTRL_MIB_COPY_TRIGGER_OFFS) + +#define MVPP2_PORT_MIB_CNTRS_CTRL_MIB_CLEAR_ON_READ__OFFS 1 +#define MVPP2_PORT_MIB_CNTRS_CTRL_MIB_CLEAR_ON_READ__MASK \ + (0x00000001 << MVPP2_PORT_MIB_CNTRS_CTRL_MIB_CLEAR_ON_READ__OFFS) + +#define MVPP2_PORT_MIB_CNTRS_CTRL_RX_HISTOGRAM_EN_OFFS 2 +#define MVPP2_PORT_MIB_CNTRS_CTRL_RX_HISTOGRAM_EN_MASK \ + (0x00000001 << MVPP2_PORT_MIB_CNTRS_CTRL_RX_HISTOGRAM_EN_OFFS) + +#define MVPP2_PORT_MIB_CNTRS_CTRL_TX_HISTOGRAM_EN_OFFS 3 +#define MVPP2_PORT_MIB_CNTRS_CTRL_TX_HISTOGRAM_EN_MASK \ + (0x00000001 << MVPP2_PORT_MIB_CNTRS_CTRL_TX_HISTOGRAM_EN_OFFS) + +#define MVPP2_PORT_MIB_CNTRS_CTRL_MFA1_BTT940_FIX_ENABLE__OFFS 4 +#define MVPP2_PORT_MIB_CNTRS_CTRL_MFA1_BTT940_FIX_ENABLE__MASK \ + (0x00000001 << MVPP2_PORT_MIB_CNTRS_CTRL_MFA1_BTT940_FIX_ENABLE__OFFS) + +#define MVPP2_PORT_MIB_CNTRS_CTRL_XCAT_BTS_340_EN__OFFS 5 +#define MVPP2_PORT_MIB_CNTRS_CTRL_XCAT_BTS_340_EN__MASK \ + (0x00000001 << MVPP2_PORT_MIB_CNTRS_CTRL_XCAT_BTS_340_EN__OFFS) + +#define MVPP2_PORT_MIB_CNTRS_CTRL_MIB_4_COUNT_HIST_OFFS 6 +#define MVPP2_PORT_MIB_CNTRS_CTRL_MIB_4_COUNT_HIST_MASK \ + (0x00000001 << MVPP2_PORT_MIB_CNTRS_CTRL_MIB_4_COUNT_HIST_OFFS) + +#define MVPP2_PORT_MIB_CNTRS_CTRL_MIB_4_LIMIT_1518_1522_OFFS 7 +#define MVPP2_PORT_MIB_CNTRS_CTRL_MIB_4_LIMIT_1518_1522_MASK \ + (0x00000001 << MVPP2_PORT_MIB_CNTRS_CTRL_MIB_4_LIMIT_1518_1522_OFFS) + +/* Port Mac Control3 */ +#define MVPP2_PORT_CTRL3_REG (0x0048) +#define MVPP2_PORT_CTRL3_BUF_SIZE_OFFS 0 +#define MVPP2_PORT_CTRL3_BUF_SIZE_MASK \ + (0x0000003f << MVPP2_PORT_CTRL3_BUF_SIZE_OFFS) + +#define MVPP2_PORT_CTRL3_IPG_DATA_OFFS 6 +#define MVPP2_PORT_CTRL3_IPG_DATA_MASK \ + (0x000001ff << MVPP2_PORT_CTRL3_IPG_DATA_OFFS) + +#define MVPP2_PORT_CTRL3_LLFC_GLOBAL_FC_ENABLE_OFFS 15 +#define MVPP2_PORT_CTRL3_LLFC_GLOBAL_FC_ENABLE_MASK \ + (0x00000001 << MVPP2_PORT_CTRL3_LLFC_GLOBAL_FC_ENABLE_OFFS) +#define MVPP2_CAUSE_TXQ_SENT_DESC_ALL_MASK 0xff + +/* Port Mac Control4 */ +#define MVPP2_PORT_CTRL4_REG (0x0090) +#define MVPP2_PORT_CTRL4_EXT_PIN_GMII_SEL_OFFS 0 +#define MVPP2_PORT_CTRL4_EXT_PIN_GMII_SEL_MASK \ + (0x00000001 << MVPP2_PORT_CTRL4_EXT_PIN_GMII_SEL_OFFS) + +#define MVPP2_PORT_CTRL4_PREAMBLE_FIX_OFFS 1 +#define MVPP2_PORT_CTRL4_PREAMBLE_FIX_MASK \ + (0x00000001 << MVPP2_PORT_CTRL4_PREAMBLE_FIX_OFFS) + +#define MVPP2_PORT_CTRL4_SQ_DETECT_FIX_EN_OFFS 2 +#define MVPP2_PORT_CTRL4_SQ_DETECT_FIX_EN_MASK \ + (0x00000001 << MVPP2_PORT_CTRL4_SQ_DETECT_FIX_EN_OFFS) + +#define MVPP2_PORT_CTRL4_FC_EN_RX_OFFS 3 +#define MVPP2_PORT_CTRL4_FC_EN_RX_MASK \ + (0x00000001 << MVPP2_PORT_CTRL4_FC_EN_RX_OFFS) + +#define MVPP2_PORT_CTRL4_FC_EN_TX_OFFS 4 +#define MVPP2_PORT_CTRL4_FC_EN_TX_MASK \ + (0x00000001 << MVPP2_PORT_CTRL4_FC_EN_TX_OFFS) + +#define MVPP2_PORT_CTRL4_DP_CLK_SEL_OFFS 5 +#define MVPP2_PORT_CTRL4_DP_CLK_SEL_MASK \ + (0x00000001 << MVPP2_PORT_CTRL4_DP_CLK_SEL_OFFS) + +#define MVPP2_PORT_CTRL4_SYNC_BYPASS_OFFS 6 +#define MVPP2_PORT_CTRL4_SYNC_BYPASS_MASK \ + (0x00000001 << MVPP2_PORT_CTRL4_SYNC_BYPASS_OFFS) + +#define MVPP2_PORT_CTRL4_QSGMII_BYPASS_ACTIVE_OFFS 7 +#define MVPP2_PORT_CTRL4_QSGMII_BYPASS_ACTIVE_MASK \ + (0x00000001 << MVPP2_PORT_CTRL4_QSGMII_BYPASS_ACTIVE_OFFS) + +#define MVPP2_PORT_CTRL4_COUNT_EXTERNAL_FC_EN_OFFS 8 +#define MVPP2_PORT_CTRL4_COUNT_EXTERNAL_FC_EN_MASK \ + (0x00000001 << MVPP2_PORT_CTRL4_COUNT_EXTERNAL_FC_EN_OFFS) + +#define MVPP2_PORT_CTRL4_MARVELL_HEADER_EN_OFFS 9 +#define MVPP2_PORT_CTRL4_MARVELL_HEADER_EN_MASK \ + (0x00000001 << MVPP2_PORT_CTRL4_MARVELL_HEADER_EN_OFFS) + +#define MVPP2_PORT_CTRL4_LEDS_NUMBER_OFFS 10 +#define MVPP2_PORT_CTRL4_LEDS_NUMBER_MASK \ + (0x0000003f << MVPP2_PORT_CTRL4_LEDS_NUMBER_OFFS) + +/* Descriptor ring Macros */ +#define MVPP2_QUEUE_NEXT_DESC(q, index) (((index) < (q)->LastDesc) ? ((index) + 1) : 0) + +/* Various constants */ + +/* Coalescing */ +#define MVPP2_TXDONE_COAL_PKTS_THRESH 15 +#define MVPP2_TXDONE_HRTIMER_PERIOD_NS 1000000UL +#define MVPP2_RX_COAL_PKTS 32 +#define MVPP2_RX_COAL_USEC 100 + +/* + * The two bytes Marvell header. Either contains a special value used + * by Marvell switches when a specific hardware mode is enabled (not + * supported by this driver) or is filled automatically by zeroes on + * the RX side. Those two bytes being at the front of the Ethernet + * header, they allow to have the IP header aligned on a 4 bytes + * boundary automatically: the hardware skips those two bytes on its + * own. + */ +#define MVPP2_MH_SIZE 2 +#define MVPP2_ETH_TYPE_LEN 2 +#define MVPP2_PPPOE_HDR_SIZE 8 +#define MVPP2_VLAN_TAG_LEN 4 + +/* Lbtd 802.3 type */ +#define MVPP2_IP_LBDT_TYPE 0xfffa + +#define MVPP2_CPU_D_CACHE_LINE_SIZE 32 +#define MVPP2_TX_CSUM_MAX_SIZE 9800 + +/* Timeout constants */ +#define MVPP2_TX_DISABLE_TIMEOUT_MSEC 1000 +#define MVPP2_TX_PENDING_TIMEOUT_MSEC 1000 + +#define MVPP2_TX_MTU_MAX 0x7ffff + +/* Maximum number of T-CONTs of PON port */ +#define MVPP2_MAX_TCONT 16 + +/* Maximum number of supported ports */ +#define MVPP2_MAX_PORTS 4 + +/* Maximum number of TXQs used by single port */ +#define MVPP2_MAX_TXQ 8 + +/* Maximum number of RXQs used by single port */ +#define MVPP2_MAX_RXQ 8 + +/* Dfault number of RXQs in use */ +#define MVPP2_DEFAULT_RXQ 4 + +/* Total number of RXQs available to all ports */ +#define MVPP2_RXQ_TOTAL_NUM (MVPP2_MAX_PORTS * MVPP2_MAX_RXQ) + +/* Max number of Rx descriptors */ +#define MVPP2_MAX_RXD 32 + +/* Max number of Tx descriptors */ +#define MVPP2_MAX_TXD 32 + +/* Amount of Tx descriptors that can be reserved at once by CPU */ +#define MVPP2_CPU_DESC_CHUNK 64 + +/* Max number of Tx descriptors in each aggregated queue */ +#define MVPP2_AGGR_TXQ_SIZE 256 + +/* Descriptor aligned size */ +#define MVPP2_DESC_ALIGNED_SIZE 32 + +/* Descriptor alignment mask */ +#define MVPP2_TX_DESC_ALIGN (MVPP2_DESC_ALIGNED_SIZE - 1) + +/* RX FIFO constants */ +#define MVPP2_RX_FIFO_PORT_DATA_SIZE 0x2000 +#define MVPP2_RX_FIFO_PORT_ATTR_SIZE 0x80 +#define MVPP2_RX_FIFO_PORT_MIN_PKT 0x80 + +#define MVPP2_BIT_TO_BYTE(bit) ((bit) / 8) + +/* IPv6 max L3 address size */ +#define MVPP2_MAX_L3_ADDR_SIZE 16 + +/* Port flags */ +#define MVPP2_F_LOOPBACK BIT(0) + +/* SD1 Control1 */ +#define SD1_CONTROL_1_REG (0x148) + +#define SD1_CONTROL_XAUI_EN_OFFSET 28 +#define SD1_CONTROL_XAUI_EN_MASK (0x1 << SD1_CONTROL_XAUI_EN_OFFSET) + +#define SD1_CONTROL_RXAUI0_L23_EN_OFFSET 27 +#define SD1_CONTROL_RXAUI0_L23_EN_MASK (0x1 << SD1_CONTROL_RXAUI0_L23_EN_OFFSET) + +#define SD1_CONTROL_RXAUI1_L45_EN_OFFSET 26 +#define SD1_CONTROL_RXAUI1_L45_EN_MASK (0x1 << SD1_CONTROL_RXAUI1_L45_EN_OFFSET) + +/* System Soft Reset 1 */ +#define MV_GOP_SOFT_RESET_1_REG (0x108) + +#define NETC_GOP_SOFT_RESET_OFFSET 6 +#define NETC_GOP_SOFT_RESET_MASK (0x1 << NETC_GOP_SOFT_RESET_OFFSET) + +/* Ports Control 0 */ +#define MV_NETCOMP_PORTS_CONTROL_0 (0x110) + +#define NETC_CLK_DIV_PHASE_OFFSET 31 +#define NETC_CLK_DIV_PHASE_MASK (0x1 << NETC_CLK_DIV_PHASE_OFFSET) + +#define NETC_GIG_RX_DATA_SAMPLE_OFFSET 29 +#define NETC_GIG_RX_DATA_SAMPLE_MASK (0x1 << NETC_GIG_RX_DATA_SAMPLE_OFFSET) + +#define NETC_BUS_WIDTH_SELECT_OFFSET 1 +#define NETC_BUS_WIDTH_SELECT_MASK (0x1 << NETC_BUS_WIDTH_SELECT_OFFSET) + +#define NETC_GOP_ENABLE_OFFSET 0 +#define NETC_GOP_ENABLE_MASK (0x1 << NETC_GOP_ENABLE_OFFSET) + +/* Ports Control 1 */ +#define MV_NETCOMP_PORTS_CONTROL_1 (0x114) + +#define NETC_PORT_GIG_RF_RESET_OFFSET(port) (28 + port) +#define NETC_PORT_GIG_RF_RESET_MASK(port) (0x1 << NETC_PORT_GIG_RF_RESET_OFFSET(port)) + +#define NETC_PORTS_ACTIVE_OFFSET(port) (0 + port) +#define NETC_PORTS_ACTIVE_MASK(port) (0x1 << NETC_PORTS_ACTIVE_OFFSET(port)) + +/* Ports Status */ +#define MV_NETCOMP_PORTS_STATUS (0x11C) +#define NETC_PORTS_STATUS_OFFSET(port) (0 + port) +#define NETC_PORTS_STATUS_MASK(port) (0x1 << NETC_PORTS_STATUS_OFFSET(port)) + +/* Networking Complex Control 0 */ +#define MV_NETCOMP_CONTROL_0 (0x120) + +#define NETC_GBE_PORT1_MII_MODE_OFFSET 2 +#define NETC_GBE_PORT1_MII_MODE_MASK (0x1 << NETC_GBE_PORT1_MII_MODE_OFFSET) + +#define NETC_GBE_PORT1_SGMII_MODE_OFFSET 1 +#define NETC_GBE_PORT1_SGMII_MODE_MASK (0x1 << NETC_GBE_PORT1_SGMII_MODE_OFFSET) + +#define NETC_GBE_PORT0_SGMII_MODE_OFFSET 0 +#define NETC_GBE_PORT0_SGMII_MODE_MASK (0x1 << NETC_GBE_PORT0_SGMII_MODE_OFFSET) + +/* Port Mac Control0 */ +#define MV_XLG_PORT_MAC_CTRL0_REG ( 0x0000) +#define MV_XLG_MAC_CTRL0_PORTEN_OFFS 0 +#define MV_XLG_MAC_CTRL0_PORTEN_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL0_PORTEN_OFFS) + +#define MV_XLG_MAC_CTRL0_MACRESETN_OFFS 1 +#define MV_XLG_MAC_CTRL0_MACRESETN_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL0_MACRESETN_OFFS) + +#define MV_XLG_MAC_CTRL0_FORCELINKDOWN_OFFS 2 +#define MV_XLG_MAC_CTRL0_FORCELINKDOWN_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL0_FORCELINKDOWN_OFFS) + +#define MV_XLG_MAC_CTRL0_FORCELINKPASS_OFFS 3 +#define MV_XLG_MAC_CTRL0_FORCELINKPASS_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL0_FORCELINKPASS_OFFS) + +#define MV_XLG_MAC_CTRL0_TXIPGMODE_OFFS 5 +#define MV_XLG_MAC_CTRL0_TXIPGMODE_MASK \ + (0x00000003 << MV_XLG_MAC_CTRL0_TXIPGMODE_OFFS) + +#define MV_XLG_MAC_CTRL0_RXFCEN_OFFS 7 +#define MV_XLG_MAC_CTRL0_RXFCEN_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL0_RXFCEN_OFFS) + +#define MV_XLG_MAC_CTRL0_TXFCEN_OFFS 8 +#define MV_XLG_MAC_CTRL0_TXFCEN_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL0_TXFCEN_OFFS) + +#define MV_XLG_MAC_CTRL0_RXCRCCHECKEN_OFFS 9 +#define MV_XLG_MAC_CTRL0_RXCRCCHECKEN_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL0_RXCRCCHECKEN_OFFS) + +#define MV_XLG_MAC_CTRL0_PERIODICXONEN_OFFS 10 +#define MV_XLG_MAC_CTRL0_PERIODICXONEN_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL0_PERIODICXONEN_OFFS) + +#define MV_XLG_MAC_CTRL0_RXCRCSTRIPEN_OFFS 11 +#define MV_XLG_MAC_CTRL0_RXCRCSTRIPEN_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL0_RXCRCSTRIPEN_OFFS) + +#define MV_XLG_MAC_CTRL0_PADDINGDIS_OFFS 13 +#define MV_XLG_MAC_CTRL0_PADDINGDIS_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL0_PADDINGDIS_OFFS) + +#define MV_XLG_MAC_CTRL0_MIBCNTDIS_OFFS 14 +#define MV_XLG_MAC_CTRL0_MIBCNTDIS_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL0_MIBCNTDIS_OFFS) + +#define MV_XLG_MAC_CTRL0_PFC_CASCADE_PORT_ENABLE_OFFS 15 +#define MV_XLG_MAC_CTRL0_PFC_CASCADE_PORT_ENABLE_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL0_PFC_CASCADE_PORT_ENABLE_OFFS) + +/* Port Mac Control1 */ +#define MV_XLG_PORT_MAC_CTRL1_REG (0x0004) +#define MV_XLG_MAC_CTRL1_FRAMESIZELIMIT_OFFS 0 +#define MV_XLG_MAC_CTRL1_FRAMESIZELIMIT_MASK \ + (0x00001fff << MV_XLG_MAC_CTRL1_FRAMESIZELIMIT_OFFS) + +#define MV_XLG_MAC_CTRL1_MACLOOPBACKEN_OFFS 13 +#define MV_XLG_MAC_CTRL1_MACLOOPBACKEN_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL1_MACLOOPBACKEN_OFFS) + +#define MV_XLG_MAC_CTRL1_XGMIILOOPBACKEN_OFFS 14 +#define MV_XLG_MAC_CTRL1_XGMIILOOPBACKEN_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL1_XGMIILOOPBACKEN_OFFS) + +#define MV_XLG_MAC_CTRL1_LOOPBACKCLOCKSELECT_OFFS 15 +#define MV_XLG_MAC_CTRL1_LOOPBACKCLOCKSELECT_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL1_LOOPBACKCLOCKSELECT_OFFS) + +/* Port Mac Control2 */ +#define MV_XLG_PORT_MAC_CTRL2_REG (0x0008) +#define MV_XLG_MAC_CTRL2_SALOW_7_0_OFFS 0 +#define MV_XLG_MAC_CTRL2_SALOW_7_0_MASK \ + (0x000000ff << MV_XLG_MAC_CTRL2_SALOW_7_0_OFFS) + +#define MV_XLG_MAC_CTRL2_UNIDIRECTIONALEN_OFFS 8 +#define MV_XLG_MAC_CTRL2_UNIDIRECTIONALEN_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL2_UNIDIRECTIONALEN_OFFS) + +#define MV_XLG_MAC_CTRL2_FIXEDIPGBASE_OFFS 9 +#define MV_XLG_MAC_CTRL2_FIXEDIPGBASE_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL2_FIXEDIPGBASE_OFFS) + +#define MV_XLG_MAC_CTRL2_PERIODICXOFFEN_OFFS 10 +#define MV_XLG_MAC_CTRL2_PERIODICXOFFEN_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL2_PERIODICXOFFEN_OFFS) + +#define MV_XLG_MAC_CTRL2_SIMPLEXMODEEN_OFFS 13 +#define MV_XLG_MAC_CTRL2_SIMPLEXMODEEN_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL2_SIMPLEXMODEEN_OFFS) + +#define MV_XLG_MAC_CTRL2_FC_MODE_OFFS 14 +#define MV_XLG_MAC_CTRL2_FC_MODE_MASK \ + (0x00000003 << MV_XLG_MAC_CTRL2_FC_MODE_OFFS) + +/* Port Status */ +#define MV_XLG_MAC_PORT_STATUS_REG (0x000c) +#define MV_XLG_MAC_PORT_STATUS_LINKSTATUS_OFFS 0 +#define MV_XLG_MAC_PORT_STATUS_LINKSTATUS_MASK \ + (0x00000001 << MV_XLG_MAC_PORT_STATUS_LINKSTATUS_OFFS) + +#define MV_XLG_MAC_PORT_STATUS_REMOTEFAULT_OFFS 1 +#define MV_XLG_MAC_PORT_STATUS_REMOTEFAULT_MASK \ + (0x00000001 << MV_XLG_MAC_PORT_STATUS_REMOTEFAULT_OFFS) + +#define MV_XLG_MAC_PORT_STATUS_LOCALFAULT_OFFS 2 +#define MV_XLG_MAC_PORT_STATUS_LOCALFAULT_MASK \ + (0x00000001 << MV_XLG_MAC_PORT_STATUS_LOCALFAULT_OFFS) + +#define MV_XLG_MAC_PORT_STATUS_LINKSTATUSCLEAN_OFFS 3 +#define MV_XLG_MAC_PORT_STATUS_LINKSTATUSCLEAN_MASK \ + (0x00000001 << MV_XLG_MAC_PORT_STATUS_LINKSTATUSCLEAN_OFFS) + +#define MV_XLG_MAC_PORT_STATUS_LOCALFAULTCLEAN_OFFS 4 +#define MV_XLG_MAC_PORT_STATUS_LOCALFAULTCLEAN_MASK \ + (0x00000001 << MV_XLG_MAC_PORT_STATUS_LOCALFAULTCLEAN_OFFS) + +#define MV_XLG_MAC_PORT_STATUS_REMOTEFAULTCLEAN_OFFS 5 +#define MV_XLG_MAC_PORT_STATUS_REMOTEFAULTCLEAN_MASK \ + (0x00000001 << MV_XLG_MAC_PORT_STATUS_REMOTEFAULTCLEAN_OFFS) + +#define MV_XLG_MAC_PORT_STATUS_PORTRXPAUSE_OFFS 6 +#define MV_XLG_MAC_PORT_STATUS_PORTRXPAUSE_MASK \ + (0x00000001 << MV_XLG_MAC_PORT_STATUS_PORTRXPAUSE_OFFS) + +#define MV_XLG_MAC_PORT_STATUS_PORTTXPAUSE_OFFS 7 +#define MV_XLG_MAC_PORT_STATUS_PORTTXPAUSE_MASK \ + (0x00000001 << MV_XLG_MAC_PORT_STATUS_PORTTXPAUSE_OFFS) + +#define MV_XLG_MAC_PORT_STATUS_PFC_SYNC_FIFO_FULL_OFFS 8 +#define MV_XLG_MAC_PORT_STATUS_PFC_SYNC_FIFO_FULL_MASK \ + (0x00000001 << MV_XLG_MAC_PORT_STATUS_PFC_SYNC_FIFO_FULL_OFFS) + +/* Port Fifos Thresholds Configuration */ +#define MV_XLG_PORT_FIFOS_THRS_CFG_REG (0x001) +#define MV_XLG_MAC_PORT_FIFOS_THRS_CFG_RXFULLTHR_OFFS 0 +#define MV_XLG_MAC_PORT_FIFOS_THRS_CFG_RXFULLTHR_MASK \ + (0x0000001f << MV_XLG_MAC_PORT_FIFOS_THRS_CFG_RXFULLTHR_OFFS) + +#define MV_XLG_MAC_PORT_FIFOS_THRS_CFG_TXFIFOSIZE_OFFS 5 +#define MV_XLG_MAC_PORT_FIFOS_THRS_CFG_TXFIFOSIZE_MASK \ + (0x0000003f << MV_XLG_MAC_PORT_FIFOS_THRS_CFG_TXFIFOSIZE_OFFS) + +#define MV_XLG_MAC_PORT_FIFOS_THRS_CFG_TXRDTHR_OFFS 11 +#define MV_XLG_MAC_PORT_FIFOS_THRS_CFG_TXRDTHR_MASK \ + (0x0000001f << MV_XLG_MAC_PORT_FIFOS_THRS_CFG_TXRDTHR_OFFS) + +/* Port Mac Control3 */ +#define MV_XLG_PORT_MAC_CTRL3_REG (0x001c) +#define MV_XLG_MAC_CTRL3_BUFSIZE_OFFS 0 +#define MV_XLG_MAC_CTRL3_BUFSIZE_MASK \ + (0x0000003f << MV_XLG_MAC_CTRL3_BUFSIZE_OFFS) + +#define MV_XLG_MAC_CTRL3_XTRAIPG_OFFS 6 +#define MV_XLG_MAC_CTRL3_XTRAIPG_MASK \ + (0x0000007f << MV_XLG_MAC_CTRL3_XTRAIPG_OFFS) + +#define MV_XLG_MAC_CTRL3_MACMODESELECT_OFFS 13 +#define MV_XLG_MAC_CTRL3_MACMODESELECT_MASK \ + (0x00000007 << MV_XLG_MAC_CTRL3_MACMODESELECT_OFFS) + +/* Port Per Prio Flow Control Status */ +#define MV_XLG_PORT_PER_PRIO_FLOW_CTRL_STATUS_REG (0x0020) +#define MV_XLG_MAC_PORT_PER_PRIO_FLOW_CTRL_STATUS_PRIONSTATUS_OFFS 0 +#define MV_XLG_MAC_PORT_PER_PRIO_FLOW_CTRL_STATUS_PRIONSTATUS_MASK \ + (0x00000001 << MV_XLG_MAC_PORT_PER_PRIO_FLOW_CTRL_STATUS_PRIONSTATUS_OFFS) + +/* Debug Bus Status */ +#define MV_XLG_DEBUG_BUS_STATUS_REG (0x0024) +#define MV_XLG_MAC_DEBUG_BUS_STATUS_DEBUG_BUS_OFFS 0 +#define MV_XLG_MAC_DEBUG_BUS_STATUS_DEBUG_BUS_MASK \ + (0x0000ffff << MV_XLG_MAC_DEBUG_BUS_STATUS_DEBUG_BUS_OFFS) + +/* Port Metal Fix */ +#define MV_XLG_PORT_METAL_FIX_REG (0x002c) +#define MV_XLG_MAC_PORT_METAL_FIX_EN_EOP_IN_FIFO__OFFS 0 +#define MV_XLG_MAC_PORT_METAL_FIX_EN_EOP_IN_FIFO__MASK \ + (0x00000001 << MV_XLG_MAC_PORT_METAL_FIX_EN_EOP_IN_FIFO__OFFS) + +#define MV_XLG_MAC_PORT_METAL_FIX_EN_LTF_FIX__OFFS 1 +#define MV_XLG_MAC_PORT_METAL_FIX_EN_LTF_FIX__MASK \ + (0x00000001 << MV_XLG_MAC_PORT_METAL_FIX_EN_LTF_FIX__OFFS) + +#define MV_XLG_MAC_PORT_METAL_FIX_EN_HOLD_FIX__OFFS 2 +#define MV_XLG_MAC_PORT_METAL_FIX_EN_HOLD_FIX__MASK \ + (0x00000001 << MV_XLG_MAC_PORT_METAL_FIX_EN_HOLD_FIX__OFFS) + +#define MV_XLG_MAC_PORT_METAL_FIX_EN_LED_FIX__OFFS 3 +#define MV_XLG_MAC_PORT_METAL_FIX_EN_LED_FIX__MASK \ + (0x00000001 << MV_XLG_MAC_PORT_METAL_FIX_EN_LED_FIX__OFFS) + +#define MV_XLG_MAC_PORT_METAL_FIX_EN_PAD_PROTECT__OFFS 4 +#define MV_XLG_MAC_PORT_METAL_FIX_EN_PAD_PROTECT__MASK \ + (0x00000001 << MV_XLG_MAC_PORT_METAL_FIX_EN_PAD_PROTECT__OFFS) + +#define MV_XLG_MAC_PORT_METAL_FIX_EN_NX_BTS44__OFFS 5 +#define MV_XLG_MAC_PORT_METAL_FIX_EN_NX_BTS44__MASK \ + (0x00000001 << MV_XLG_MAC_PORT_METAL_FIX_EN_NX_BTS44__OFFS) + +#define MV_XLG_MAC_PORT_METAL_FIX_EN_NX_BTS42__OFFS 6 +#define MV_XLG_MAC_PORT_METAL_FIX_EN_NX_BTS42__MASK \ + (0x00000001 << MV_XLG_MAC_PORT_METAL_FIX_EN_NX_BTS42__OFFS) + +#define MV_XLG_MAC_PORT_METAL_FIX_EN_FLUSH_FIX_OFFS 7 +#define MV_XLG_MAC_PORT_METAL_FIX_EN_FLUSH_FIX_MASK \ + (0x00000001 << MV_XLG_MAC_PORT_METAL_FIX_EN_FLUSH_FIX_OFFS) + +#define MV_XLG_MAC_PORT_METAL_FIX_EN_PORT_EN_FIX_OFFS 8 +#define MV_XLG_MAC_PORT_METAL_FIX_EN_PORT_EN_FIX_MASK \ + (0x00000001 << MV_XLG_MAC_PORT_METAL_FIX_EN_PORT_EN_FIX_OFFS) + +#define MV_XLG_MAC_PORT_METAL_FIX_SPARE_DEF0_BITS_OFFS 9 +#define MV_XLG_MAC_PORT_METAL_FIX_SPARE_DEF0_BITS_MASK \ + (0x0000000f << MV_XLG_MAC_PORT_METAL_FIX_SPARE_DEF0_BITS_OFFS) + +#define MV_XLG_MAC_PORT_METAL_FIX_SPARE_DEF1_BITS_OFFS 13 +#define MV_XLG_MAC_PORT_METAL_FIX_SPARE_DEF1_BITS_MASK \ + (0x00000007 << MV_XLG_MAC_PORT_METAL_FIX_SPARE_DEF1_BITS_OFFS) + +/* Xg Mib Counters Control */ +#define MV_XLG_MIB_CNTRS_CTRL_REG (0x0030) +#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_XGCAPTURETRIGGER_OFFS 0 +#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_XGCAPTURETRIGGER_MASK \ + (0x00000001 << MV_XLG_MAC_XG_MIB_CNTRS_CTRL_XGCAPTURETRIGGER_OFFS) + +#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_XGDONTCLEARAFTERREAD_OFFS 1 +#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_XGDONTCLEARAFTERREAD_MASK \ + (0x00000001 << MV_XLG_MAC_XG_MIB_CNTRS_CTRL_XGDONTCLEARAFTERREAD_OFFS) + +#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_XGRXHISTOGRAMEN_OFFS 2 +#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_XGRXHISTOGRAMEN_MASK \ + (0x00000001 << MV_XLG_MAC_XG_MIB_CNTRS_CTRL_XGRXHISTOGRAMEN_OFFS) + +#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_XGTXHISTOGRAMEN_OFFS 3 +#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_XGTXHISTOGRAMEN_MASK \ + (0x00000001 << MV_XLG_MAC_XG_MIB_CNTRS_CTRL_XGTXHISTOGRAMEN_OFFS) + +#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_MFA1_BTT940_FIX_ENABLE__OFFS 4 +#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_MFA1_BTT940_FIX_ENABLE__MASK \ + (0x00000001 << MV_XLG_MAC_XG_MIB_CNTRS_CTRL_MFA1_BTT940_FIX_ENABLE__OFFS) + +#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_LEDS_NUMBER_OFFS 5 +#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_LEDS_NUMBER_MASK \ + (0x0000003f << MV_XLG_MAC_XG_MIB_CNTRS_CTRL_LEDS_NUMBER_OFFS) + +#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_MIB_4_COUNT_HIST_OFFS 11 +#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_MIB_4_COUNT_HIST_MASK \ + (0x00000001 << MV_XLG_MAC_XG_MIB_CNTRS_CTRL_MIB_4_COUNT_HIST_OFFS) + +#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_MIB_4_LIMIT_1518_1522_OFFS 12 +#define MV_XLG_MAC_XG_MIB_CNTRS_CTRL_MIB_4_LIMIT_1518_1522_MASK \ + (0x00000001 << MV_XLG_MAC_XG_MIB_CNTRS_CTRL_MIB_4_LIMIT_1518_1522_OFFS) + +/* Cn/ccfc Timer%i */ +#define MV_XLG_CNCCFC_TIMERI_REG(t) ((0x0038 + (t) * 4)) +#define MV_XLG_MAC_CNCCFC_TIMERI_PORTSPEEDTIMER_OFFS 0 +#define MV_XLG_MAC_CNCCFC_TIMERI_PORTSPEEDTIMER_MASK \ + (0x0000ffff << MV_XLG_MAC_CNCCFC_TIMERI_PORTSPEEDTIMER_OFFS) + +/* Ppfc Control */ +#define MV_XLG_MAC_PPFC_CTRL_REG (0x0060) +#define MV_XLG_MAC_PPFC_CTRL_GLOBAL_PAUSE_ENI_OFFS 0 +#define MV_XLG_MAC_PPFC_CTRL_GLOBAL_PAUSE_ENI_MASK \ + (0x00000001 << MV_XLG_MAC_PPFC_CTRL_GLOBAL_PAUSE_ENI_OFFS) + +#define MV_XLG_MAC_PPFC_CTRL_DIP_BTS_677_EN_OFFS 9 +#define MV_XLG_MAC_PPFC_CTRL_DIP_BTS_677_EN_MASK \ + (0x00000001 << MV_XLG_MAC_PPFC_CTRL_DIP_BTS_677_EN_OFFS) + +/* Fc Dsa Tag 0 */ +#define MV_XLG_MAC_FC_DSA_TAG_0_REG (0x0068) +#define MV_XLG_MAC_FC_DSA_TAG_0_DSATAGREG0_OFFS 0 +#define MV_XLG_MAC_FC_DSA_TAG_0_DSATAGREG0_MASK \ + (0x0000ffff << MV_XLG_MAC_FC_DSA_TAG_0_DSATAGREG0_OFFS) + +/* Fc Dsa Tag 1 */ +#define MV_XLG_MAC_FC_DSA_TAG_1_REG (0x006c) +#define MV_XLG_MAC_FC_DSA_TAG_1_DSATAGREG1_OFFS 0 +#define MV_XLG_MAC_FC_DSA_TAG_1_DSATAGREG1_MASK \ + (0x0000ffff << MV_XLG_MAC_FC_DSA_TAG_1_DSATAGREG1_OFFS) + +/* Fc Dsa Tag 2 */ +#define MV_XLG_MAC_FC_DSA_TAG_2_REG (0x0070) +#define MV_XLG_MAC_FC_DSA_TAG_2_DSATAGREG2_OFFS 0 +#define MV_XLG_MAC_FC_DSA_TAG_2_DSATAGREG2_MASK \ + (0x0000ffff << MV_XLG_MAC_FC_DSA_TAG_2_DSATAGREG2_OFFS) + +/* Fc Dsa Tag 3 */ +#define MV_XLG_MAC_FC_DSA_TAG_3_REG (0x0074) +#define MV_XLG_MAC_FC_DSA_TAG_3_DSATAGREG3_OFFS 0 +#define MV_XLG_MAC_FC_DSA_TAG_3_DSATAGREG3_MASK \ + (0x0000ffff << MV_XLG_MAC_FC_DSA_TAG_3_DSATAGREG3_OFFS) + +/* Dic Budget Compensation */ +#define MV_XLG_MAC_DIC_BUDGET_COMPENSATION_REG (0x0080) +#define MV_XLG_MAC_DIC_BUDGET_COMPENSATION_DIC_COUNTER_TO_ADD_8BYTES_OFFS 0 +#define MV_XLG_MAC_DIC_BUDGET_COMPENSATION_DIC_COUNTER_TO_ADD_8BYTES_MASK \ + (0x0000ffff << MV_XLG_MAC_DIC_BUDGET_COMPENSATION_DIC_COUNTER_TO_ADD_8BYTES_OFFS) + +/* Port Mac Control4 */ +#define MV_XLG_PORT_MAC_CTRL4_REG (0x0084) +#define MV_XLG_MAC_CTRL4_LLFC_GLOBAL_FC_ENABLE_OFFS 0 +#define MV_XLG_MAC_CTRL4_LLFC_GLOBAL_FC_ENABLE_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL4_LLFC_GLOBAL_FC_ENABLE_OFFS) + +#define MV_XLG_MAC_CTRL4_LED_STREAM_SELECT_OFFS 1 +#define MV_XLG_MAC_CTRL4_LED_STREAM_SELECT_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL4_LED_STREAM_SELECT_OFFS) + +#define MV_XLG_MAC_CTRL4_DEBUG_BUS_SELECT_OFFS 2 +#define MV_XLG_MAC_CTRL4_DEBUG_BUS_SELECT_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL4_DEBUG_BUS_SELECT_OFFS) + +#define MV_XLG_MAC_CTRL4_MASK_PCS_RESET_OFFS 3 +#define MV_XLG_MAC_CTRL4_MASK_PCS_RESET_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL4_MASK_PCS_RESET_OFFS) + +#define MV_XLG_MAC_CTRL4_ENABLE_SHORT_PREAMBLE_FOR_XLG_OFFS 4 +#define MV_XLG_MAC_CTRL4_ENABLE_SHORT_PREAMBLE_FOR_XLG_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL4_ENABLE_SHORT_PREAMBLE_FOR_XLG_OFFS) + +#define MV_XLG_MAC_CTRL4_FORWARD_802_3X_FC_EN_OFFS 5 +#define MV_XLG_MAC_CTRL4_FORWARD_802_3X_FC_EN_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL4_FORWARD_802_3X_FC_EN_OFFS) + +#define MV_XLG_MAC_CTRL4_FORWARD_PFC_EN_OFFS 6 +#define MV_XLG_MAC_CTRL4_FORWARD_PFC_EN_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL4_FORWARD_PFC_EN_OFFS) + +#define MV_XLG_MAC_CTRL4_FORWARD_UNKNOWN_FC_EN_OFFS 7 +#define MV_XLG_MAC_CTRL4_FORWARD_UNKNOWN_FC_EN_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL4_FORWARD_UNKNOWN_FC_EN_OFFS) + +#define MV_XLG_MAC_CTRL4_USE_XPCS_OFFS 8 +#define MV_XLG_MAC_CTRL4_USE_XPCS_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL4_USE_XPCS_OFFS) + +#define MV_XLG_MAC_CTRL4_DMA_INTERFACE_IS_64_BIT_OFFS 9 +#define MV_XLG_MAC_CTRL4_DMA_INTERFACE_IS_64_BIT_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL4_DMA_INTERFACE_IS_64_BIT_OFFS) + +#define MV_XLG_MAC_CTRL4_TX_DMA_INTERFACE_BITS_OFFS 10 +#define MV_XLG_MAC_CTRL4_TX_DMA_INTERFACE_BITS_MASK \ + (0x00000003 << MV_XLG_MAC_CTRL4_TX_DMA_INTERFACE_BITS_OFFS) + +#define MV_XLG_MAC_CTRL4_MAC_MODE_DMA_1G_OFFS 12 +#define MV_XLG_MAC_CTRL4_MAC_MODE_DMA_1G_MASK \ + (0x00000001 << MV_XLG_MAC_CTRL4_MAC_MODE_DMA_1G_OFFS) + +/* Port Mac Control5 */ +#define MV_XLG_PORT_MAC_CTRL5_REG (0x0088) +#define MV_XLG_MAC_CTRL5_TXIPGLENGTH_OFFS 0 +#define MV_XLG_MAC_CTRL5_TXIPGLENGTH_MASK \ + (0x0000000f << MV_XLG_MAC_CTRL5_TXIPGLENGTH_OFFS) + +#define MV_XLG_MAC_CTRL5_PREAMBLELENGTHTX_OFFS 4 +#define MV_XLG_MAC_CTRL5_PREAMBLELENGTHTX_MASK \ + (0x00000007 << MV_XLG_MAC_CTRL5_PREAMBLELENGTHTX_OFFS) + +#define MV_XLG_MAC_CTRL5_PREAMBLELENGTHRX_OFFS 7 +#define MV_XLG_MAC_CTRL5_PREAMBLELENGTHRX_MASK \ + (0x00000007 << MV_XLG_MAC_CTRL5_PREAMBLELENGTHRX_OFFS) + +#define MV_XLG_MAC_CTRL5_TXNUMCRCBYTES_OFFS 10 +#define MV_XLG_MAC_CTRL5_TXNUMCRCBYTES_MASK \ + (0x00000007 << MV_XLG_MAC_CTRL5_TXNUMCRCBYTES_OFFS) + +#define MV_XLG_MAC_CTRL5_RXNUMCRCBYTES_OFFS 13 +#define MV_XLG_MAC_CTRL5_RXNUMCRCBYTES_MASK \ + (0x00000007 << MV_XLG_MAC_CTRL5_RXNUMCRCBYTES_OFFS) + +/* External Control */ +#define MV_XLG_MAC_EXT_CTRL_REG (0x0090) +#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL0_OFFS 0 +#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL0_MASK \ + (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL0_OFFS) + +#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL1_OFFS 1 +#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL1_MASK \ + (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL1_OFFS) + +#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL2_OFFS 2 +#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL2_MASK \ + (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL2_OFFS) + +#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL3_OFFS 3 +#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL3_MASK \ + (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL3_OFFS) + +#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL4_OFFS 4 +#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL4_MASK \ + (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL4_OFFS) + +#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL5_OFFS 5 +#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL5_MASK \ + (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL5_OFFS) + +#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL6_OFFS 6 +#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL6_MASK \ + (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL6_OFFS) + +#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL7_OFFS 7 +#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL7_MASK \ + (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL7_OFFS) + +#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL8_OFFS 8 +#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL8_MASK \ + (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL8_OFFS) + +#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL9_OFFS 9 +#define MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL9_MASK \ + (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXTERNAL_CTRL9_OFFS) + +#define MV_XLG_MAC_EXT_CTRL_EXT_CTRL_10_OFFS 10 +#define MV_XLG_MAC_EXT_CTRL_EXT_CTRL_10_MASK \ + (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXT_CTRL_10_OFFS) + +#define MV_XLG_MAC_EXT_CTRL_EXT_CTRL_11_OFFS 11 +#define MV_XLG_MAC_EXT_CTRL_EXT_CTRL_11_MASK \ + (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXT_CTRL_11_OFFS) + +#define MV_XLG_MAC_EXT_CTRL_EXT_CTRL_12_OFFS 12 +#define MV_XLG_MAC_EXT_CTRL_EXT_CTRL_12_MASK \ + (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXT_CTRL_12_OFFS) + +#define MV_XLG_MAC_EXT_CTRL_EXT_CTRL_13_OFFS 13 +#define MV_XLG_MAC_EXT_CTRL_EXT_CTRL_13_MASK \ + (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXT_CTRL_13_OFFS) + +#define MV_XLG_MAC_EXT_CTRL_EXT_CTRL_14_OFFS 14 +#define MV_XLG_MAC_EXT_CTRL_EXT_CTRL_14_MASK \ + (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXT_CTRL_14_OFFS) + +#define MV_XLG_MAC_EXT_CTRL_EXT_CTRL_15_OFFS 15 +#define MV_XLG_MAC_EXT_CTRL_EXT_CTRL_15_MASK \ + (0x00000001 << MV_XLG_MAC_EXT_CTRL_EXT_CTRL_15_OFFS) + +/* Macro Control */ +#define MV_XLG_MAC_MACRO_CTRL_REG (0x0094) +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_0_OFFS 0 +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_0_MASK \ + (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_0_OFFS) + +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_1_OFFS 1 +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_1_MASK \ + (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_1_OFFS) + +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_2_OFFS 2 +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_2_MASK \ + (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_2_OFFS) + +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_3_OFFS 3 +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_3_MASK \ + (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_3_OFFS) + +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_4_OFFS 4 +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_4_MASK \ + (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_4_OFFS) + +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_5_OFFS 5 +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_5_MASK \ + (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_5_OFFS) + +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_6_OFFS 6 +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_6_MASK \ + (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_6_OFFS) + +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_7_OFFS 7 +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_7_MASK \ + (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_7_OFFS) + +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_8_OFFS 8 +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_8_MASK \ + (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_8_OFFS) + +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_9_OFFS 9 +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_9_MASK \ + (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_9_OFFS) + +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_10_OFFS 10 +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_10_MASK \ + (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_10_OFFS) + +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_11_OFFS 11 +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_11_MASK \ + (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_11_OFFS) + +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_12_OFFS 12 +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_12_MASK \ + (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_12_OFFS) + +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_13_OFFS 13 +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_13_MASK \ + (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_13_OFFS) + +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_14_OFFS 14 +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_14_MASK \ + (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_14_OFFS) + +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_15_OFFS 15 +#define MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_15_MASK \ + (0x00000001 << MV_XLG_MAC_MACRO_CTRL_MACRO_CTRL_15_OFFS) + +#define MV_XLG_MAC_DIC_PPM_IPG_REDUCE_REG (0x0094) + +/* Port Interrupt Cause */ +#define MV_XLG_INTERRUPT_CAUSE_REG (0x0014) +/* Port Interrupt Mask */ +#define MV_XLG_INTERRUPT_MASK_REG (0x0018) +#define MV_XLG_INTERRUPT_LINK_CHANGE_OFFS 1 +#define MV_XLG_INTERRUPT_LINK_CHANGE_MASK \ + (0x1 << MV_XLG_INTERRUPT_LINK_CHANGE_OFFS) + +/* Port Interrupt Summary Cause */ +#define MV_XLG_EXTERNAL_INTERRUPT_CAUSE_REG (0x0058) +/* Port Interrupt Summary Mask */ +#define MV_XLG_EXTERNAL_INTERRUPT_MASK_REG (0x005C) +#define MV_XLG_EXTERNAL_INTERRUPT_LINK_CHANGE_OFFS 1 +#define MV_XLG_EXTERNAL_INTERRUPT_LINK_CHANGE_MASK \ + (0x1 << MV_XLG_EXTERNAL_INTERRUPT_LINK_CHANGE_OFFS) + +/*All PPV22 Addresses are 40-bit */ +#define MVPP22_ADDR_HIGH_SIZE 8 +#define MVPP22_ADDR_HIGH_MASK ((1<(0). + */ +#define MVPP2_PRS_AI_BITS 8 +#define MVPP2_PRS_PORT_MASK 0xff +#define MVPP2_PRS_LU_MASK 0xf +#define MVPP2_PRS_TCAM_DATA_BYTE(offs) (((offs) - ((offs) % 2)) * 2 + ((offs) % 2)) +#define MVPP2_PRS_TCAM_DATA_BYTE_EN(offs) (((offs) * 2) - ((offs) % 2) + 2) +#define MVPP2_PRS_TCAM_AI_BYTE 16 +#define MVPP2_PRS_TCAM_PORT_BYTE 17 +#define MVPP2_PRS_TCAM_LU_BYTE 20 +#define MVPP2_PRS_TCAM_EN_OFFS(offs) ((offs) + 2) +#define MVPP2_PRS_TCAM_INV_WORD 5 +/* Tcam entries ID */ +#define MVPP2_PE_DROP_ALL 0 +#define MVPP2_PE_FIRST_FREE_TID 1 +#define MVPP2_PE_LAST_FREE_TID (MVPP2_PRS_TCAM_SRAM_SIZE - 31) +#define MVPP2_PE_IP6_EXT_PROTO_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 30) +#define MVPP2_PE_MAC_MC_IP6 (MVPP2_PRS_TCAM_SRAM_SIZE - 29) +#define MVPP2_PE_IP6_ADDR_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 28) +#define MVPP2_PE_IP4_ADDR_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 27) +#define MVPP2_PE_LAST_DEFAULT_FLOW (MVPP2_PRS_TCAM_SRAM_SIZE - 26) +#define MVPP2_PE_FIRST_DEFAULT_FLOW (MVPP2_PRS_TCAM_SRAM_SIZE - 19) +#define MVPP2_PE_EDSA_TAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 18) +#define MVPP2_PE_EDSA_UNTAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 17) +#define MVPP2_PE_DSA_TAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 16) +#define MVPP2_PE_DSA_UNTAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 15) +#define MVPP2_PE_ETYPE_EDSA_TAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 14) +#define MVPP2_PE_ETYPE_EDSA_UNTAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 13) +#define MVPP2_PE_ETYPE_DSA_TAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 12) +#define MVPP2_PE_ETYPE_DSA_UNTAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 11) +#define MVPP2_PE_MH_DEFAULT (MVPP2_PRS_TCAM_SRAM_SIZE - 10) +#define MVPP2_PE_DSA_DEFAULT (MVPP2_PRS_TCAM_SRAM_SIZE - 9) +#define MVPP2_PE_IP6_PROTO_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 8) +#define MVPP2_PE_IP4_PROTO_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 7) +#define MVPP2_PE_ETH_TYPE_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 6) +#define MVPP2_PE_VLAN_DBL (MVPP2_PRS_TCAM_SRAM_SIZE - 5) +#define MVPP2_PE_VLAN_NONE (MVPP2_PRS_TCAM_SRAM_SIZE - 4) +#define MVPP2_PE_MAC_MC_ALL (MVPP2_PRS_TCAM_SRAM_SIZE - 3) +#define MVPP2_PE_MAC_PROMISCUOUS (MVPP2_PRS_TCAM_SRAM_SIZE - 2) +#define MVPP2_PE_MAC_NON_PROMISCUOUS (MVPP2_PRS_TCAM_SRAM_SIZE - 1) + +/* + * Sram structure + * The fields are represented by MVPP2_PRS_TCAM_DATA_REG(3)->(0). + */ +#define MVPP2_PRS_SRAM_RI_OFFS 0 +#define MVPP2_PRS_SRAM_RI_WORD 0 +#define MVPP2_PRS_SRAM_RI_CTRL_OFFS 32 +#define MVPP2_PRS_SRAM_RI_CTRL_WORD 1 +#define MVPP2_PRS_SRAM_RI_CTRL_BITS 32 +#define MVPP2_PRS_SRAM_SHIFT_OFFS 64 +#define MVPP2_PRS_SRAM_SHIFT_SIGN_BIT 72 +#define MVPP2_PRS_SRAM_UDF_OFFS 73 +#define MVPP2_PRS_SRAM_UDF_BITS 8 +#define MVPP2_PRS_SRAM_UDF_MASK 0xff +#define MVPP2_PRS_SRAM_UDF_SIGN_BIT 81 +#define MVPP2_PRS_SRAM_UDF_TYPE_OFFS 82 +#define MVPP2_PRS_SRAM_UDF_TYPE_MASK 0x7 +#define MVPP2_PRS_SRAM_UDF_TYPE_L3 1 +#define MVPP2_PRS_SRAM_UDF_TYPE_L4 4 +#define MVPP2_PRS_SRAM_OP_SEL_SHIFT_OFFS 85 +#define MVPP2_PRS_SRAM_OP_SEL_SHIFT_MASK 0x3 +#define MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD 1 +#define MVPP2_PRS_SRAM_OP_SEL_SHIFT_IP4_ADD 2 +#define MVPP2_PRS_SRAM_OP_SEL_SHIFT_IP6_ADD 3 +#define MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS 87 +#define MVPP2_PRS_SRAM_OP_SEL_UDF_BITS 2 +#define MVPP2_PRS_SRAM_OP_SEL_UDF_MASK 0x3 +#define MVPP2_PRS_SRAM_OP_SEL_UDF_ADD 0 +#define MVPP2_PRS_SRAM_OP_SEL_UDF_IP4_ADD 2 +#define MVPP2_PRS_SRAM_OP_SEL_UDF_IP6_ADD 3 +#define MVPP2_PRS_SRAM_OP_SEL_BASE_OFFS 89 +#define MVPP2_PRS_SRAM_AI_OFFS 90 +#define MVPP2_PRS_SRAM_AI_CTRL_OFFS 98 +#define MVPP2_PRS_SRAM_AI_CTRL_BITS 8 +#define MVPP2_PRS_SRAM_AI_MASK 0xff +#define MVPP2_PRS_SRAM_NEXT_LU_OFFS 106 +#define MVPP2_PRS_SRAM_NEXT_LU_MASK 0xf +#define MVPP2_PRS_SRAM_LU_DONE_BIT 110 +#define MVPP2_PRS_SRAM_LU_GEN_BIT 111 + +/* Sram result info bits assignment */ +#define MVPP2_PRS_RI_MAC_ME_MASK 0x1 +#define MVPP2_PRS_RI_DSA_MASK 0x2 +#define MVPP2_PRS_RI_VLAN_MASK 0xc +#define MVPP2_PRS_RI_VLAN_NONE ~(BIT(2) | BIT(3)) +#define MVPP2_PRS_RI_VLAN_SINGLE BIT(2) +#define MVPP2_PRS_RI_VLAN_DOUBLE BIT(3) +#define MVPP2_PRS_RI_VLAN_TRIPLE (BIT(2) | BIT(3)) +#define MVPP2_PRS_RI_CPU_CODE_MASK 0x70 +#define MVPP2_PRS_RI_CPU_CODE_RX_SPEC BIT(4) +#define MVPP2_PRS_RI_L2_CAST_MASK 0x600 +#define MVPP2_PRS_RI_L2_UCAST ~(BIT(9) | BIT(10)) +#define MVPP2_PRS_RI_L2_MCAST BIT(9) +#define MVPP2_PRS_RI_L2_BCAST BIT(10) +#define MVPP2_PRS_RI_PPPOE_MASK 0x800 +#define MVPP2_PRS_RI_L3_PROTO_MASK 0x7000 +#define MVPP2_PRS_RI_L3_UN ~(BIT(12) | BIT(13) | BIT(14)) +#define MVPP2_PRS_RI_L3_IP4 BIT(12) +#define MVPP2_PRS_RI_L3_IP4_OPT BIT(13) +#define MVPP2_PRS_RI_L3_IP4_OTHER (BIT(12) | BIT(13)) +#define MVPP2_PRS_RI_L3_IP6 BIT(14) +#define MVPP2_PRS_RI_L3_IP6_EXT (BIT(12) | BIT(14)) +#define MVPP2_PRS_RI_L3_ARP (BIT(13) | BIT(14)) +#define MVPP2_PRS_RI_L3_ADDR_MASK 0x18000 +#define MVPP2_PRS_RI_L3_UCAST ~(BIT(15) | BIT(16)) +#define MVPP2_PRS_RI_L3_MCAST BIT(15) +#define MVPP2_PRS_RI_L3_BCAST (BIT(15) | BIT(16)) +#define MVPP2_PRS_RI_IP_FRAG_MASK 0x20000 +#define MVPP2_PRS_RI_UDF3_MASK 0x300000 +#define MVPP2_PRS_RI_UDF3_RX_SPECIAL BIT(21) +#define MVPP2_PRS_RI_L4_PROTO_MASK 0x1c00000 +#define MVPP2_PRS_RI_L4_TCP BIT(22) +#define MVPP2_PRS_RI_L4_UDP BIT(23) +#define MVPP2_PRS_RI_L4_OTHER (BIT(22) | BIT(23)) +#define MVPP2_PRS_RI_UDF7_MASK 0x60000000 +#define MVPP2_PRS_RI_UDF7_IP6_LITE BIT(29) +#define MVPP2_PRS_RI_DROP_MASK 0x80000000 + +/* Sram additional info bits assignment */ +#define MVPP2_PRS_IPV4_DIP_AI_BIT BIT(0) +#define MVPP2_PRS_IPV6_NO_EXT_AI_BIT BIT(0) +#define MVPP2_PRS_IPV6_EXT_AI_BIT BIT(1) +#define MVPP2_PRS_IPV6_EXT_AH_AI_BIT BIT(2) +#define MVPP2_PRS_IPV6_EXT_AH_LEN_AI_BIT BIT(3) +#define MVPP2_PRS_IPV6_EXT_AH_L4_AI_BIT BIT(4) +#define MVPP2_PRS_SINGLE_VLAN_AI 0 +#define MVPP2_PRS_DBL_VLAN_AI_BIT BIT(7) + +/* DSA/EDSA type */ +#define MVPP2_PRS_TAGGED TRUE +#define MVPP2_PRS_UNTAGGED FALSE +#define MVPP2_PRS_EDSA TRUE +#define MVPP2_PRS_DSA FALSE + +/* MAC entries, shadow udf */ +enum Mvpp2PrsUdf { + MVPP2_PRS_UDF_MAC_DEF, + MVPP2_PRS_UDF_MAC_RANGE, + MVPP2_PRS_UDF_L2_DEF, + MVPP2_PRS_UDF_L2_DEF_COPY, + MVPP2_PRS_UDF_L2_USER, +}; + +/* Lookup ID */ +enum Mvpp2PrsLookup { + MVPP2_PRS_LU_MH, + MVPP2_PRS_LU_MAC, + MVPP2_PRS_LU_DSA, + MVPP2_PRS_LU_VLAN, + MVPP2_PRS_LU_L2, + MVPP2_PRS_LU_PPPOE, + MVPP2_PRS_LU_IP4, + MVPP2_PRS_LU_IP6, + MVPP2_PRS_LU_FLOWS, + MVPP2_PRS_LU_LAST, +}; + +/* L3 cast enum */ +enum Mvpp2PrsL3Cast { + MVPP2_PRS_L3_UNI_CAST, + MVPP2_PRS_L3_MULTI_CAST, + MVPP2_PRS_L3_BROAD_CAST +}; + +/* Classifier constants */ +#define MVPP2_CLS_FLOWS_TBL_SIZE 512 +#define MVPP2_CLS_FLOWS_TBL_DATA_WORDS 3 +#define MVPP2_CLS_LKP_TBL_SIZE 64 + +/* BM cookie (32 bits) definition */ +#define MVPP2_BM_COOKIE_POOL_OFFS 8 +#define MVPP2_BM_COOKIE_CPU_OFFS 24 + +/* + * The MVPP2_TX_DESC and MVPP2_RX_DESC structures describe the + * layout of the transmit and reception DMA descriptors, and their + * layout is therefore defined by the hardware design + */ +#define MVPP2_TXD_L3_OFF_SHIFT 0 +#define MVPP2_TXD_IP_HLEN_SHIFT 8 +#define MVPP2_TXD_L4_CSUM_FRAG BIT(13) +#define MVPP2_TXD_L4_CSUM_NOT BIT(14) +#define MVPP2_TXD_IP_CSUM_DISABLE BIT(15) +#define MVPP2_TXD_PADDING_DISABLE BIT(23) +#define MVPP2_TXD_L4_UDP BIT(24) +#define MVPP2_TXD_L3_IP6 BIT(26) +#define MVPP2_TXD_L_DESC BIT(28) +#define MVPP2_TXD_F_DESC BIT(29) + +#define MVPP2_RXD_ERR_SUMMARY BIT(15) +#define MVPP2_RXD_ERR_CODE_MASK (BIT(13) | BIT(14)) +#define MVPP2_RXD_ERR_CRC 0x0 +#define MVPP2_RXD_ERR_OVERRUN BIT(13) +#define MVPP2_RXD_ERR_RESOURCE (BIT(13) | BIT(14)) +#define MVPP2_RXD_BM_POOL_ID_OFFS 16 +#define MVPP2_RXD_BM_POOL_ID_MASK (BIT(16) | BIT(17) | BIT(18)) +#define MVPP2_RXD_HWF_SYNC BIT(21) +#define MVPP2_RXD_L4_CSUM_OK BIT(22) +#define MVPP2_RXD_IP4_HEADER_ERR BIT(24) +#define MVPP2_RXD_L4_TCP BIT(25) +#define MVPP2_RXD_L4_UDP BIT(26) +#define MVPP2_RXD_L3_IP4 BIT(28) +#define MVPP2_RXD_L3_IP6 BIT(30) +#define MVPP2_RXD_BUF_HDR BIT(31) + +typedef struct { + UINT32 command; /* Options used by HW for packet transmitting.*/ + UINT8 PacketOffset; /* the offset from the buffer beginning */ + UINT8 PhysTxq; /* destination queue ID */ + UINT16 DataSize; /* data size of transmitted packet in bytes */ + UINT64 RsrvdHwCmd1; /* HwCmd (BM, PON, PNC) */ + UINT64 BufPhysAddrHwCmd2; + UINT64 BufCookieBmQsetHwCmd3; +} MVPP2_TX_DESC; + +typedef struct { + UINT32 status; /* info about received packet */ + UINT16 reserved1; /* ParserInfo (for future use, PnC) */ + UINT16 DataSize; /* size of received packet in bytes */ + UINT16 RsrvdGem; /* GemPortId (for future use, PON) */ + UINT16 RsrvdL4csum; /* CsumL4 (for future use, PnC) */ + UINT32 RsrvdTimestamp; + UINT64 BufPhysAddrKeyHash; + UINT64 BufCookieBmQsetClsInfo; +} MVPP2_RX_DESC; + +union Mvpp2PrsTcamEntry { + UINT32 Word[MVPP2_PRS_TCAM_WORDS]; + UINT8 Byte[MVPP2_PRS_TCAM_WORDS * 4]; +}; + +union Mvpp2PrsSramEntry { + UINT32 Word[MVPP2_PRS_SRAM_WORDS]; + UINT8 Byte[MVPP2_PRS_SRAM_WORDS * 4]; +}; + +typedef struct { + UINT32 Index; + union Mvpp2PrsTcamEntry Tcam; + union Mvpp2PrsSramEntry Sram; +} MVPP2_PRS_ENTRY; + +typedef struct { + BOOLEAN Valid; + BOOLEAN Finish; + + /* Lookup ID */ + INT32 Lu; + + /* User defined offset */ + INT32 Udf; + + /* Result info */ + UINT32 Ri; + UINT32 RiMask; +} MVPP2_PRS_SHADOW; + +typedef struct { + UINT32 Index; + UINT32 Data[MVPP2_CLS_FLOWS_TBL_DATA_WORDS]; +} MVPP2_CLS_FLOW_ENTRY; + +typedef struct { + UINT32 Lkpid; + UINT32 Way; + UINT32 Data; +} MVPP2_CLS_LOOKUP_ENTRY; + +typedef struct { + UINT32 NextBuffPhysAddr; + UINT32 NextBuffVirtAddr; + UINT16 ByteCount; + UINT16 info; + UINT8 reserved1; /* BmQset (for future use, BM) */ +} MVPP2_BUFF_HDR; + +/* Buffer header info bits */ +#define MVPP2_B_HDR_INFO_MC_ID_MASK 0xfff +#define MVPP2_B_HDR_INFO_MC_ID(info) ((info) & MVPP2_B_HDR_INFO_MC_ID_MASK) +#define MVPP2_B_HDR_INFO_LAST_OFFS 12 +#define MVPP2_B_HDR_INFO_LAST_MASK BIT(12) +#define MVPP2_B_HDR_INFO_IS_LAST(info) ((info & MVPP2_B_HDR_INFO_LAST_MASK) >> MVPP2_B_HDR_INFO_LAST_OFFS) + +/* Net Complex */ +enum MvNetcTopology { + MV_NETC_GE_MAC0_RXAUI_L23 = BIT(0), + MV_NETC_GE_MAC0_RXAUI_L45 = BIT(1), + MV_NETC_GE_MAC0_XAUI = BIT(2), + MV_NETC_GE_MAC2_SGMII = BIT(3), + MV_NETC_GE_MAC3_SGMII = BIT(4), + MV_NETC_GE_MAC3_RGMII = BIT(5), +}; + +enum MvNetcPhase { + MV_NETC_FIRST_PHASE, + MV_NETC_SECOND_PHASE, +}; + +enum MvNetcSgmiiXmiMode { + MV_NETC_GBE_SGMII, + MV_NETC_GBE_XMII, +}; + +enum MvNetcMiiMode { + MV_NETC_GBE_RGMII, + MV_NETC_GBE_MII, +}; + +enum MvNetcLanes { + MV_NETC_LANE_23, + MV_NETC_LANE_45, +}; + +/* Port related */ +enum MvReset { + RESET, + UNRESET +}; + +enum Mvpp2Command { + MVPP2_START, /* Start */ + MVPP2_STOP, /* Stop */ + MVPP2_PAUSE, /* Pause */ + MVPP2_RESTART /* Restart */ +}; + +enum MvPortDuplex { + MV_PORT_DUPLEX_AN, + MV_PORT_DUPLEX_HALF, + MV_PORT_DUPLEX_FULL +}; + +#endif /* __MVPP2_LIB_HW__ */ diff --git a/Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.c b/Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.c new file mode 100644 index 0000000000..8de2473d09 --- /dev/null +++ b/Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.c @@ -0,0 +1,1271 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Mvpp2LibHw.h" +#include "Mvpp2Lib.h" +#include "Pp2Dxe.h" + +#define ReturnUnlock(tpl, status) do { gBS->RestoreTPL (tpl); return (status); } while(0) + +STATIC MVPP2_SHARED *Mvpp2Shared; +STATIC BUFFER_LOCATION BufferLocation; +STATIC PP2_DEVICE_PATH Pp2DevicePathTemplate = { + { + { + MESSAGING_DEVICE_PATH, + MSG_MAC_ADDR_DP, + { + (UINT8) (sizeof(MAC_ADDR_DEVICE_PATH)), + (UINT8) ((sizeof(MAC_ADDR_DEVICE_PATH)) >> 8) + } + }, + { { 0 } }, + 0 + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { sizeof(EFI_DEVICE_PATH_PROTOCOL), 0 } + } +}; + +EFI_SIMPLE_NETWORK_PROTOCOL Pp2SnpTemplate = { + EFI_SIMPLE_NETWORK_PROTOCOL_REVISION, // Revision + Pp2SnpStart, // Start + Pp2SnpStop, // Stop + Pp2DxeSnpInitialize, // Initialize + Pp2SnpReset, // Reset + Pp2SnpShutdown, // Shutdown + Pp2SnpReceiveFilters, // ReceiveFilters + Pp2SnpStationAddress, // StationAddress + Pp2SnpNetStat, // Statistics + Pp2SnpIpToMac, // MCastIpToMac + NULL, // NvData + Pp2SnpGetStatus, // GetStatus + Pp2SnpTransmit, // Transmit + Pp2SnpReceive, // Receive + NULL, // WaitForPacket + NULL // Mode +}; + +EFI_SIMPLE_NETWORK_MODE Pp2SnpModeTemplate = { + EfiSimpleNetworkStopped, // State + NET_ETHER_ADDR_LEN, // HwAddressSize + sizeof (ETHER_HEAD), // MediaHeaderSize + EFI_PAGE_SIZE, // MaxPacketSize + 0, // NvRamSize + 0, // MvRamAccessSize + EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | + EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST | + EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST | + EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS | + EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST, // ReceiveFilterMask + EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | + EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST | + EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST, // ReceiveFilterSetting + MAX_MCAST_FILTER_CNT, // MacMCastFilterCount + 0, // MCastFilterCount + { + { { 0 } } + }, // MCastFilter + { + { 0 } + }, // CurrentAddress + { + { 0 } + }, // BroadcastAddress + { + { 0 } + }, // Permanent Address + NET_IFTYPE_ETHERNET, // IfType + TRUE, // MacAddressChangeable + FALSE, // MultipleTxSupported + TRUE, // MediaPresentSupported + FALSE // MediaPresent +}; + +#define QueueNext(off) ((((off) + 1) >= QUEUE_DEPTH) ? 0 : ((off) + 1)) + +STATIC +EFI_STATUS +QueueInsert ( + IN PP2DXE_CONTEXT *Pp2Context, + IN VOID *Buffer + ) +{ + + if (QueueNext (Pp2Context->CompletionQueueTail) == Pp2Context->CompletionQueueHead) { + return EFI_OUT_OF_RESOURCES; + } + + Pp2Context->CompletionQueue[Pp2Context->CompletionQueueTail] = Buffer; + Pp2Context->CompletionQueueTail = QueueNext (Pp2Context->CompletionQueueTail); + + return EFI_SUCCESS; +} + +STATIC +VOID * +QueueRemove ( + IN PP2DXE_CONTEXT *Pp2Context + ) +{ + VOID *Buffer; + + if (Pp2Context->CompletionQueueTail == Pp2Context->CompletionQueueHead) { + return NULL; + } + + Buffer = Pp2Context->CompletionQueue[Pp2Context->CompletionQueueHead]; + Pp2Context->CompletionQueue[Pp2Context->CompletionQueueHead] = NULL; + Pp2Context->CompletionQueueHead = QueueNext (Pp2Context->CompletionQueueHead); + + return Buffer; +} + +STATIC +EFI_STATUS +Pp2DxeBmPoolInit ( + VOID + ) +{ + INTN Index; + UINT8 *PoolAddr; + UINT32 PoolSize = (sizeof(VOID *) * MVPP2_BM_SIZE) * 2 + MVPP2_BM_POOL_PTR_ALIGN; + + ASSERT(MVPP2_BM_POOL_PTR_ALIGN >= sizeof(UINTN)); + + PoolSize = (sizeof(VOID *) * MVPP2_BM_SIZE) * 2 + MVPP2_BM_POOL_PTR_ALIGN; + + for (Index = 0; Index < MVPP2_BM_POOLS_NUM; Index++) { + /* BmIrqClear */ + Mvpp2BmIrqClear(Mvpp2Shared, Index); + } + + Mvpp2Shared->BmPools = AllocateZeroPool (sizeof(MVPP2_BMS_POOL)); + + if (Mvpp2Shared->BmPools == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + PoolAddr = UncachedAllocateAlignedZeroPool (PoolSize, MVPP2_BM_POOL_PTR_ALIGN); + if (PoolAddr == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Mvpp2Shared->BmPools->Id = MVPP2_BM_POOL; + Mvpp2Shared->BmPools->VirtAddr = (UINT32 *)PoolAddr; + Mvpp2Shared->BmPools->PhysAddr = (UINTN)PoolAddr; + + Mvpp2BmPoolHwCreate(Mvpp2Shared, Mvpp2Shared->BmPools, MVPP2_BM_SIZE); + + return EFI_SUCCESS; +} + +/* Enable and fill BM pool */ +STATIC +EFI_STATUS +Pp2DxeBmStart ( + VOID + ) +{ + UINT8 *Buff, *BuffPhys; + INTN Index; + + ASSERT(BM_ALIGN >= sizeof(UINTN)); + + Mvpp2BmPoolCtrl(Mvpp2Shared, MVPP2_BM_POOL, MVPP2_START); + Mvpp2BmPoolBufsizeSet(Mvpp2Shared, Mvpp2Shared->BmPools, RX_BUFFER_SIZE); + + /* Fill BM pool with Buffers */ + for (Index = 0; Index < MVPP2_BM_SIZE; Index++) { + Buff = (UINT8 *)(BufferLocation.RxBuffers + (Index * RX_BUFFER_SIZE)); + if (Buff == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + BuffPhys = ALIGN_POINTER(Buff, BM_ALIGN); + Mvpp2BmPoolPut(Mvpp2Shared, MVPP2_BM_POOL, (UINTN)BuffPhys, (UINTN)BuffPhys); + } + + return EFI_SUCCESS; +} + +STATIC +VOID +Pp2DxeStartDev ( + IN PP2DXE_CONTEXT *Pp2Context + ) +{ + PP2DXE_PORT *Port = &Pp2Context->Port; + + /* Config classifier decoding table */ + Mvpp2ClsPortConfig(Port); + Mvpp2ClsOversizeRxqSet(Port); + MvGop110PortEventsMask(Port); + MvGop110PortEnable(Port); + + /* Enable transmit and receive */ + Mvpp2EgressEnable(Port); + Mvpp2IngressEnable(Port); +} + +STATIC +EFI_STATUS +Pp2DxeSetupRxqs ( + IN PP2DXE_CONTEXT *Pp2Context + ) +{ + INTN Queue; + EFI_STATUS Status; + MVPP2_RX_QUEUE *Rxq; + + for (Queue = 0; Queue < RxqNumber; Queue++) { + Rxq = &Pp2Context->Port.Rxqs[Queue]; + Rxq->DescsPhys = (DmaAddrT)Rxq->Descs; + if (Rxq->Descs == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrCleanup; + } + + Mvpp2RxqHwInit(&Pp2Context->Port, Rxq); + } + + return EFI_SUCCESS; + +ErrCleanup: + Mvpp2CleanupRxqs(&Pp2Context->Port); + return Status; +} + +STATIC +EFI_STATUS +Pp2DxeSetupTxqs ( + IN PP2DXE_CONTEXT *Pp2Context + ) +{ + INTN Queue; + MVPP2_TX_QUEUE *Txq; + EFI_STATUS Status; + + for (Queue = 0; Queue < TxqNumber; Queue++) { + Txq = &Pp2Context->Port.Txqs[Queue]; + Txq->DescsPhys = (DmaAddrT)Txq->Descs; + if (Txq->Descs == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrCleanup; + } + + Mvpp2TxqHwInit(&Pp2Context->Port, Txq); + } + + return EFI_SUCCESS; + +ErrCleanup: + Mvpp2CleanupTxqs(&Pp2Context->Port); + return Status; +} + +STATIC +EFI_STATUS +Pp2DxeSetupAggrTxqs ( + IN PP2DXE_CONTEXT *Pp2Context + ) +{ + MVPP2_TX_QUEUE *AggrTxq; + + AggrTxq = Mvpp2Shared->AggrTxqs; + AggrTxq->DescsPhys = (DmaAddrT)AggrTxq->Descs; + if (AggrTxq->Descs == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Mvpp2AggrTxqHwInit(AggrTxq, AggrTxq->Size, 0, Mvpp2Shared); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +Pp2DxeOpen ( + IN PP2DXE_CONTEXT *Pp2Context + ) +{ + PP2DXE_PORT *Port = &Pp2Context->Port; + UINT8 MacBcast[NET_ETHER_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + UINT8 DevAddr[NET_ETHER_ADDR_LEN]; + INTN Ret; + EFI_STATUS Status; + + CopyMem (DevAddr, Pp2Context->Snp.Mode->CurrentAddress.Addr, NET_ETHER_ADDR_LEN); + + Ret = Mvpp2PrsMacDaAccept(Mvpp2Shared, Port->Id, MacBcast, TRUE); + if (Ret != 0) { + return EFI_DEVICE_ERROR; + } + Ret = Mvpp2PrsMacDaAccept(Mvpp2Shared, Port->Id, DevAddr, TRUE); + if (Ret != 0) { + return EFI_DEVICE_ERROR; + } + Ret = Mvpp2PrsTagModeSet(Mvpp2Shared, Port->Id, MVPP2_TAG_TYPE_MH); + if (Ret != 0) { + return EFI_DEVICE_ERROR; + } + Ret = Mvpp2PrsDefFlow(Port); + if (Ret != 0) { + return EFI_DEVICE_ERROR; + } + + Status = Pp2DxeSetupRxqs(Pp2Context); + if (EFI_ERROR(Status)) { + return Status; + } + + Status = Pp2DxeSetupTxqs(Pp2Context); + if (EFI_ERROR(Status)) { + return Status; + } + + Status = Pp2DxeSetupAggrTxqs(Pp2Context); + if (EFI_ERROR(Status)) { + return Status; + } + + Pp2DxeStartDev(Pp2Context); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +Pp2DxeLatePortInitialize ( + IN PP2DXE_CONTEXT *Pp2Context + ) +{ + PP2DXE_PORT *Port = &Pp2Context->Port; + INTN Queue; + + Port->TxRingSize = MVPP2_MAX_TXD; + Port->RxRingSize = MVPP2_MAX_RXD; + + Mvpp2EgressDisable(Port); + MvGop110PortEventsMask(Port); + MvGop110PortDisable(Port); + + Port->Txqs = AllocateZeroPool (sizeof(MVPP2_TX_QUEUE) * TxqNumber); + if (Port->Txqs == NULL) { + DEBUG((DEBUG_ERROR, "Failed to allocate Txqs\n")); + return EFI_OUT_OF_RESOURCES; + } + + /* Use preallocated area */ + Port->Txqs[0].Descs = BufferLocation.TxDescs; + + for (Queue = 0; Queue < TxqNumber; Queue++) { + MVPP2_TX_QUEUE *Txq = &Port->Txqs[Queue]; + + Txq->Id = Mvpp2TxqPhys(Port->Id, Queue); + Txq->LogId = Queue; + Txq->Size = Port->TxRingSize; + } + + Port->Rxqs = AllocateZeroPool (sizeof(MVPP2_RX_QUEUE) * RxqNumber); + if (Port->Rxqs == NULL) { + DEBUG((DEBUG_ERROR, "Failed to allocate Rxqs\n")); + return EFI_OUT_OF_RESOURCES; + } + + Port->Rxqs[0].Descs = BufferLocation.RxDescs; + + for (Queue = 0; Queue < TxqNumber; Queue++) { + MVPP2_RX_QUEUE *Rxq = &Port->Rxqs[Queue]; + + Rxq->Id = Queue + Port->FirstRxq; + Rxq->Size = Port->RxRingSize; + } + + Mvpp2IngressDisable(Port); + + Mvpp2DefaultsSet(Port); + + return Pp2DxeOpen(Pp2Context); +} + +STATIC +EFI_STATUS +Pp2DxeLateInitialize ( + IN PP2DXE_CONTEXT *Pp2Context + ) +{ + PP2DXE_PORT *Port = &Pp2Context->Port; + EFI_STATUS Status; + + if (!Pp2Context->LateInitialized) { + /* Full init on first call */ + Status = Pp2DxeLatePortInitialize(Pp2Context); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "Pp2Dxe: late initialization failed\n")); + return Status; + } + + /* Attach pool to Rxq */ + Mvpp2RxqLongPoolSet(Port, 0, MVPP2_BM_POOL); + Mvpp2RxqShortPoolSet(Port, 0, MVPP2_BM_POOL); + + /* + * Mark this port being fully initialized, + * otherwise it will be inited again + * during next networking transaction, + * including memory allocatation for + * TX/RX queue, PHY connect/configuration + * and address decode configuration. + */ + Pp2Context->LateInitialized = TRUE; + } else { + /* Upon all following calls, this is enough */ + MvGop110PortEventsMask(Port); + MvGop110PortEnable(Port); + } + return 0; +} + +EFI_STATUS +Pp2DxePhyInitialize ( + PP2DXE_CONTEXT *Pp2Context + ) +{ + EFI_STATUS Status; + UINT8 *PhyAddresses; + + PhyAddresses = PcdGetPtr (PcdPhySmiAddresses); + Status = gBS->LocateProtocol ( + &gMarvellPhyProtocolGuid, + NULL, + (VOID **) &Pp2Context->Phy + ); + + if (EFI_ERROR(Status)) { + return Status; + } + + if (PhyAddresses[Pp2Context->Instance] == 0xff) { + /* PHY iniitalization not required */ + return EFI_SUCCESS; + } + + Status = Pp2Context->Phy->Init( + Pp2Context->Phy, + PhyAddresses[Pp2Context->Instance], + Pp2Context->Port.PhyInterface, + &Pp2Context->PhyDev + ); + + if (EFI_ERROR(Status) && Status != EFI_TIMEOUT) { + return Status; + } + + Pp2Context->Phy->Status(Pp2Context->Phy, Pp2Context->PhyDev); + Mvpp2SmiPhyAddrCfg(&Pp2Context->Port, Pp2Context->Port.GopIndex, Pp2Context->PhyDev->Addr); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +Pp2DxeSnpInitialize ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN UINTN ExtraRxBufferSize OPTIONAL, + IN UINTN ExtraTxBufferSize OPTIONAL + ) +{ + EFI_STATUS Status; + PP2DXE_CONTEXT *Pp2Context; + Pp2Context = INSTANCE_FROM_SNP(This); + UINT32 State = This->Mode->State; + EFI_TPL SavedTpl; + + if (ExtraRxBufferSize != 0 || ExtraTxBufferSize != 0) { + DEBUG((DEBUG_ERROR, "Pp2Dxe%d: non-zero buffer requests\n", Pp2Context->Instance)); + return EFI_UNSUPPORTED; + } + + SavedTpl = gBS->RaiseTPL (TPL_CALLBACK); + + if (State != EfiSimpleNetworkStarted) { + switch (State) { + case EfiSimpleNetworkInitialized: + DEBUG((DEBUG_WARN, "Pp2Dxe%d: already initialized\n", Pp2Context->Instance)); + ReturnUnlock (SavedTpl, EFI_SUCCESS); + case EfiSimpleNetworkStopped: + DEBUG((DEBUG_WARN, "Pp2Dxe%d: network stopped\n", Pp2Context->Instance)); + ReturnUnlock (SavedTpl, EFI_NOT_STARTED); + default: + DEBUG((DEBUG_ERROR, "Pp2Dxe%d: wrong state\n", Pp2Context->Instance)); + ReturnUnlock (SavedTpl, EFI_DEVICE_ERROR); + } + } + + /* Successfully started, change state to Initialized */ + This->Mode->State = EfiSimpleNetworkInitialized; + + if (Pp2Context->Initialized) { + ReturnUnlock(SavedTpl, EFI_SUCCESS); + } + + Pp2Context->Initialized = TRUE; + + Status = Pp2DxePhyInitialize(Pp2Context); + if (EFI_ERROR(Status)) { + ReturnUnlock (SavedTpl, Status); + } + + Status = Pp2DxeLateInitialize(Pp2Context); + ReturnUnlock (SavedTpl, Status); +} + +EFI_STATUS +EFIAPI +Pp2SnpStart ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This + ) +{ + PP2DXE_CONTEXT *Pp2Context; + UINT32 State = This->Mode->State; + EFI_TPL SavedTpl; + + SavedTpl = gBS->RaiseTPL (TPL_CALLBACK); + Pp2Context = INSTANCE_FROM_SNP(This); + + if (State != EfiSimpleNetworkStopped) { + switch (State) { + case EfiSimpleNetworkStarted: + case EfiSimpleNetworkInitialized: + DEBUG((DEBUG_WARN, "Pp2Dxe%d: already initialized\n", Pp2Context->Instance)); + ReturnUnlock (SavedTpl, EFI_ALREADY_STARTED); + default: + DEBUG((DEBUG_ERROR, "Pp2Dxe%d: wrong state\n", Pp2Context->Instance)); + ReturnUnlock (SavedTpl, EFI_DEVICE_ERROR); + } + } + + This->Mode->State = EfiSimpleNetworkStarted; + ReturnUnlock (SavedTpl, EFI_SUCCESS); +} + +EFI_STATUS +EFIAPI +Pp2SnpStop ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This + ) +{ + EFI_TPL SavedTpl; + SavedTpl = gBS->RaiseTPL (TPL_CALLBACK); + PP2DXE_CONTEXT *Pp2Context = INSTANCE_FROM_SNP(This); + UINT32 State = This->Mode->State; + + if (State != EfiSimpleNetworkStarted && State != EfiSimpleNetworkInitialized) { + switch (State) { + case EfiSimpleNetworkStopped: + DEBUG((DEBUG_WARN, "Pp2Dxe%d: not started\n", Pp2Context->Instance)); + ReturnUnlock (SavedTpl, EFI_NOT_STARTED); + default: + DEBUG((DEBUG_ERROR, "Pp2Dxe%d: wrong state\n", Pp2Context->Instance)); + ReturnUnlock (SavedTpl, EFI_DEVICE_ERROR); + } + } + + This->Mode->State = EfiSimpleNetworkStopped; + ReturnUnlock (SavedTpl, EFI_SUCCESS); +} + +EFI_STATUS +EFIAPI +Pp2SnpReset ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + return EFI_SUCCESS; +} + +VOID +EFIAPI +Pp2DxeHalt ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + PP2DXE_CONTEXT *Pp2Context = Context; + PP2DXE_PORT *Port = &Pp2Context->Port; + STATIC BOOLEAN CommonPartHalted = FALSE; + + if (!CommonPartHalted) { + Mvpp2BmStop(Mvpp2Shared, MVPP2_BM_POOL); + CommonPartHalted = TRUE; + } + + Mvpp2TxqDrainSet(Port, 0, TRUE); + Mvpp2IngressDisable(Port); + Mvpp2EgressDisable(Port); + + MvGop110PortEventsMask(Port); + MvGop110PortDisable(Port); +} + +EFI_STATUS +EFIAPI +Pp2SnpShutdown ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This + ) +{ + EFI_TPL SavedTpl; + SavedTpl = gBS->RaiseTPL (TPL_CALLBACK); + PP2DXE_CONTEXT *Pp2Context = INSTANCE_FROM_SNP(This); + UINT32 State = This->Mode->State; + + if (State != EfiSimpleNetworkInitialized) { + switch (State) { + case EfiSimpleNetworkStopped: + DEBUG((DEBUG_WARN, "Pp2Dxe%d: not started\n", Pp2Context->Instance)); + ReturnUnlock (SavedTpl, EFI_NOT_STARTED); + case EfiSimpleNetworkStarted: + /* Fall through */ + default: + DEBUG((DEBUG_ERROR, "Pp2Dxe%d: wrong state\n", Pp2Context->Instance)); + ReturnUnlock (SavedTpl, EFI_DEVICE_ERROR); + } + } + + ReturnUnlock (SavedTpl, EFI_SUCCESS); +} + +EFI_STATUS +EFIAPI +Pp2SnpReceiveFilters ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN UINT32 Enable, + IN UINT32 Disable, + IN BOOLEAN ResetMCastFilter, + IN UINTN MCastFilterCnt OPTIONAL, + IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL + ) +{ + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +Pp2SnpStationAddress ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + IN BOOLEAN Reset, + IN EFI_MAC_ADDRESS *NewMac +) +{ + PP2DXE_CONTEXT *Pp2Context = INSTANCE_FROM_SNP(Snp); + PP2_DEVICE_PATH *Pp2DevicePath = Pp2Context->DevicePath; + PP2DXE_PORT *Port = &Pp2Context->Port; + UINT32 State = Snp->Mode->State; + EFI_TPL SavedTpl; + INTN Ret; + + /* Check Snp instance */ + ASSERT(Snp != NULL); + + /* Serialize access to data and registers */ + SavedTpl = gBS->RaiseTPL (TPL_CALLBACK); + + /* Check that driver was started and initialised */ + if (State != EfiSimpleNetworkInitialized) { + switch (State) { + case EfiSimpleNetworkStopped: + DEBUG((DEBUG_WARN, "Pp2Dxe%d: not started\n", Pp2Context->Instance)); + ReturnUnlock (SavedTpl, EFI_NOT_STARTED); + case EfiSimpleNetworkStarted: + /* Fall through */ + default: + DEBUG((DEBUG_ERROR, "Pp2Dxe%d: wrong state\n", Pp2Context->Instance)); + ReturnUnlock (SavedTpl, EFI_DEVICE_ERROR); + } + } + + /* Invalidate old unicast address in parser */ + Ret = Mvpp2PrsMacDaAccept(Mvpp2Shared, Port->Id, Snp->Mode->CurrentAddress.Addr, FALSE); + if (Ret != 0) { + DEBUG((DEBUG_ERROR, "Pp2SnpStationAddress - Fail\n")); + return EFI_DEVICE_ERROR; + } + + if (Reset) { + CopyMem (Snp->Mode->CurrentAddress.Addr, Snp->Mode->PermanentAddress.Addr, NET_ETHER_ADDR_LEN); + CopyMem (NewMac->Addr, Snp->Mode->PermanentAddress.Addr, NET_ETHER_ADDR_LEN); + CopyMem (Pp2DevicePath->Pp2Mac.MacAddress.Addr, Snp->Mode->PermanentAddress.Addr, NET_ETHER_ADDR_LEN); + } else { + if (NewMac == NULL) { + ReturnUnlock (SavedTpl, EFI_INVALID_PARAMETER); + } + CopyMem (Snp->Mode->CurrentAddress.Addr, NewMac->Addr, NET_ETHER_ADDR_LEN); + CopyMem (Pp2DevicePath->Pp2Mac.MacAddress.Addr, NewMac->Addr, NET_ETHER_ADDR_LEN); + } + + /* Update parser with new unicast address */ + Ret = Mvpp2PrsMacDaAccept(Mvpp2Shared, Port->Id, Snp->Mode->CurrentAddress.Addr, TRUE); + if (Ret != 0) { + DEBUG((DEBUG_ERROR, "Pp2SnpStationAddress - Fail\n")); + return EFI_DEVICE_ERROR; + } + + /* Restore TPL and return */ + gBS->RestoreTPL (SavedTpl); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +Pp2SnpNetStat ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN BOOLEAN Reset, + IN OUT UINTN *StatisticsSize OPTIONAL, + OUT EFI_NETWORK_STATISTICS *StatisticsTable OPTIONAL + ) +{ + return EFI_UNSUPPORTED; +} + +EFI_STATUS +EFIAPI +Pp2SnpIpToMac ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN BOOLEAN IPv6, + IN EFI_IP_ADDRESS *IP, + OUT EFI_MAC_ADDRESS *MAC + ) +{ + return EFI_UNSUPPORTED; +} + +EFI_STATUS +EFIAPI +Pp2SnpNvData ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN BOOLEAN ReadWrite, + IN UINTN Offset, + IN UINTN BufferSize, + IN OUT VOID *Buffer + ) +{ + return EFI_UNSUPPORTED; +} + +EFI_STATUS +EFIAPI +Pp2SnpGetStatus ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + OUT UINT32 *InterruptStatus OPTIONAL, + OUT VOID **TxBuf OPTIONAL + ) +{ + PP2DXE_CONTEXT *Pp2Context = INSTANCE_FROM_SNP(Snp); + PP2DXE_PORT *Port = &Pp2Context->Port; + BOOLEAN LinkUp; + EFI_TPL SavedTpl; + + SavedTpl = gBS->RaiseTPL (TPL_CALLBACK); + + if (!Pp2Context->Initialized) + ReturnUnlock(SavedTpl, EFI_NOT_READY); + + LinkUp = Port->AlwaysUp ? TRUE : MvGop110PortIsLinkUp(Port); + + if (LinkUp != Snp->Mode->MediaPresent) { + DEBUG((DEBUG_INFO, "Pp2Dxe%d: Link ", Pp2Context->Instance)); + DEBUG((DEBUG_INFO, LinkUp ? "up\n" : "down\n")); + } + Snp->Mode->MediaPresent = LinkUp; + + if (TxBuf != NULL) { + *TxBuf = QueueRemove (Pp2Context); + } + + ReturnUnlock(SavedTpl, EFI_SUCCESS); +} + +EFI_STATUS +EFIAPI +Pp2SnpTransmit ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN UINTN HeaderSize, + IN UINTN BufferSize, + IN VOID *Buffer, + IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + IN EFI_MAC_ADDRESS *DestAddr OPTIONAL, + IN UINT16 *EtherTypePtr OPTIONAL + ) +{ + PP2DXE_CONTEXT *Pp2Context = INSTANCE_FROM_SNP(This); + PP2DXE_PORT *Port = &Pp2Context->Port; + MVPP2_TX_QUEUE *AggrTxq = Mvpp2Shared->AggrTxqs; + MVPP2_TX_DESC *TxDesc; + EFI_STATUS Status; + INTN PollingCount; + INTN TxSent; + UINT8 *DataPtr = Buffer; + UINT16 EtherType; + UINT32 State = This->Mode->State; + EFI_TPL SavedTpl; + + if (This == NULL || Buffer == NULL) { + DEBUG((DEBUG_ERROR, "Pp2Dxe: NULL Snp or Buffer\n")); + return EFI_INVALID_PARAMETER; + } + + if (HeaderSize != 0) { + ASSERT (HeaderSize == This->Mode->MediaHeaderSize); + ASSERT (EtherTypePtr != NULL); + ASSERT (DestAddr != NULL); + } + + SavedTpl = gBS->RaiseTPL (TPL_CALLBACK); + + /* Check that driver was started and initialised */ + if (State != EfiSimpleNetworkInitialized) { + switch (State) { + case EfiSimpleNetworkStopped: + DEBUG((DEBUG_WARN, "Pp2Dxe%d: not started\n", Pp2Context->Instance)); + ReturnUnlock (SavedTpl, EFI_NOT_STARTED); + case EfiSimpleNetworkStarted: + /* Fall through */ + default: + DEBUG((DEBUG_ERROR, "Pp2Dxe%d: wrong state\n", Pp2Context->Instance)); + ReturnUnlock (SavedTpl, EFI_DEVICE_ERROR); + } + } + + if (!This->Mode->MediaPresent) { + DEBUG((DEBUG_ERROR, "Pp2Dxe: link not ready\n")); + ReturnUnlock(SavedTpl, EFI_NOT_READY); + } + + EtherType = HTONS (*EtherTypePtr); + + /* Fetch next descriptor */ + TxDesc = Mvpp2TxqNextDescGet(AggrTxq); + + if (!TxDesc) { + DEBUG((DEBUG_ERROR, "No tx descriptor to use\n")); + ReturnUnlock(SavedTpl, EFI_OUT_OF_RESOURCES); + } + + if (HeaderSize != 0) { + CopyMem(DataPtr, DestAddr, NET_ETHER_ADDR_LEN); + + if (SrcAddr != NULL) + CopyMem(DataPtr + NET_ETHER_ADDR_LEN, SrcAddr, NET_ETHER_ADDR_LEN); + else + CopyMem(DataPtr + NET_ETHER_ADDR_LEN, &This->Mode->CurrentAddress, NET_ETHER_ADDR_LEN); + + CopyMem(DataPtr + NET_ETHER_ADDR_LEN * 2, &EtherType, 2); + } + + /* Set descriptor fields */ + TxDesc->command = MVPP2_TXD_IP_CSUM_DISABLE | MVPP2_TXD_L4_CSUM_NOT | + MVPP2_TXD_F_DESC | MVPP2_TXD_L_DESC; + TxDesc->DataSize = BufferSize; + TxDesc->PacketOffset = (PhysAddrT)DataPtr & MVPP2_TX_DESC_ALIGN; + Mvpp2x2TxdescPhysAddrSet((PhysAddrT)DataPtr & ~MVPP2_TX_DESC_ALIGN, TxDesc); + TxDesc->PhysTxq = Mvpp2TxqPhys(Port->Id, 0); + + InvalidateDataCacheRange (DataPtr, BufferSize); + + /* Issue send */ + Mvpp2AggrTxqPendDescAdd(Port, 1); + + /* + * Egress processing: + * Wait until packet is passed from per-cpu aggregated queue + * to physical per-port TXQ. + */ + PollingCount = 0; + TxSent = Mvpp2AggrTxqPendDescNumGet(Mvpp2Shared, 0); + do { + if (PollingCount++ > MVPP2_TX_SEND_MAX_POLLING_COUNT) { + DEBUG((DEBUG_ERROR, "Pp2Dxe: transmit polling failed\n")); + ReturnUnlock(SavedTpl, EFI_TIMEOUT); + } + TxSent = Mvpp2AggrTxqPendDescNumGet(Mvpp2Shared, 0); + } while (TxSent); + + /* Wait for packet to be transmitted by hardware. */ + PollingCount = 0; + TxSent = Mvpp2TxqSentDescProc(Port, &Port->Txqs[0]); + while (!TxSent) { + if (PollingCount++ > MVPP2_TX_SEND_MAX_POLLING_COUNT) { + DEBUG((DEBUG_ERROR, "Pp2Dxe: transmit polling failed\n")); + ReturnUnlock(SavedTpl, EFI_TIMEOUT); + } + TxSent = Mvpp2TxqSentDescProc(Port, &Port->Txqs[0]); + } + + /* + * At this point TxSent has increased - HW sent the packet + * Add buffer to completion queue and return. + */ + Status = QueueInsert (Pp2Context, Buffer); + ReturnUnlock (SavedTpl, Status); +} + +EFI_STATUS +EFIAPI +Pp2SnpReceive ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + OUT UINTN *HeaderSize OPTIONAL, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer, + OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + OUT EFI_MAC_ADDRESS *DstAddr OPTIONAL, + OUT UINT16 *EtherType OPTIONAL + ) +{ + INTN ReceivedPackets; + PP2DXE_CONTEXT *Pp2Context = INSTANCE_FROM_SNP(This); + PP2DXE_PORT *Port = &Pp2Context->Port; + UINTN PhysAddr, VirtAddr; + EFI_STATUS Status = EFI_SUCCESS; + EFI_TPL SavedTpl; + UINT32 StatusReg; + INTN PoolId; + UINTN PktLength; + UINT8 *DataPtr; + MVPP2_RX_DESC *RxDesc; + MVPP2_RX_QUEUE *Rxq = &Port->Rxqs[0]; + + ASSERT (Port != NULL); + ASSERT (Rxq != NULL); + + SavedTpl = gBS->RaiseTPL (TPL_CALLBACK); + ReceivedPackets = Mvpp2RxqReceived(Port, Rxq->Id); + + if (ReceivedPackets == 0) { + ReturnUnlock(SavedTpl, EFI_NOT_READY); + } + + /* Process one packet per call */ + RxDesc = Mvpp2RxqNextDescGet(Rxq); + StatusReg = RxDesc->status; + + /* extract addresses from descriptor */ + PhysAddr = RxDesc->BufPhysAddrKeyHash & MVPP22_ADDR_MASK; + VirtAddr = RxDesc->BufCookieBmQsetClsInfo & MVPP22_ADDR_MASK; + + /* Drop packets with error or with buffer header (MC, SG) */ + if ((StatusReg & MVPP2_RXD_BUF_HDR) || (StatusReg & MVPP2_RXD_ERR_SUMMARY)) { + DEBUG((DEBUG_WARN, "Pp2Dxe: dropping packet\n")); + Status = EFI_DEVICE_ERROR; + goto drop; + } + + PktLength = (UINTN) RxDesc->DataSize - 2; + if (PktLength > *BufferSize) { + *BufferSize = PktLength; + DEBUG((DEBUG_ERROR, "Pp2Dxe: buffer too small\n")); + ReturnUnlock(SavedTpl, EFI_BUFFER_TOO_SMALL); + } + + CopyMem (Buffer, (VOID*) (PhysAddr + 2), PktLength); + *BufferSize = PktLength; + + if (HeaderSize != NULL) { + *HeaderSize = Pp2Context->Snp.Mode->MediaHeaderSize; + } + + DataPtr = Buffer; + + /* Extract the destination address */ + if (DstAddr != NULL) { + ZeroMem (DstAddr, sizeof(EFI_MAC_ADDRESS)); + CopyMem (DstAddr, &DataPtr[0], NET_ETHER_ADDR_LEN); + } + + /* Get the source address */ + if (SrcAddr != NULL) { + ZeroMem (SrcAddr, sizeof(EFI_MAC_ADDRESS)); + CopyMem (SrcAddr, &DataPtr[6], NET_ETHER_ADDR_LEN); + } + + /* Obtain Ether Type */ + if (EtherType != NULL) { + *EtherType = NTOHS (*(UINT16 *)(&DataPtr[12])); + } + +drop: + /* Refill: pass packet back to BM */ + PoolId = (StatusReg & MVPP2_RXD_BM_POOL_ID_MASK) >> MVPP2_RXD_BM_POOL_ID_OFFS; + Mvpp2BmPoolPut(Mvpp2Shared, PoolId, PhysAddr, VirtAddr); + + /* Update counters with 1 packet received and 1 packet refilled */ + Mvpp2RxqStatusUpdate(Port, Rxq->Id, 1, 1); + + ReturnUnlock(SavedTpl, Status); +} + +EFI_STATUS +Pp2DxeSnpInstall ( + IN PP2DXE_CONTEXT *Pp2Context + ) +{ + EFI_HANDLE Handle = NULL; + EFI_STATUS Status; + PP2_DEVICE_PATH *Pp2DevicePath; + EFI_SIMPLE_NETWORK_MODE *SnpMode; + + Pp2DevicePath = AllocateCopyPool (sizeof (PP2_DEVICE_PATH), &Pp2DevicePathTemplate); + if (Pp2DevicePath == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + SnpMode = AllocateZeroPool (sizeof (EFI_SIMPLE_NETWORK_MODE)); + if (SnpMode == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + /* Copy SNP data from templates */ + CopyMem (&Pp2Context->Snp, &Pp2SnpTemplate, sizeof (EFI_SIMPLE_NETWORK_PROTOCOL)); + CopyMem (SnpMode, &Pp2SnpModeTemplate, sizeof (EFI_SIMPLE_NETWORK_MODE)); + + /* Handle device path of the controller */ + Pp2DevicePath->Pp2Mac.MacAddress.Addr[5] = Pp2Context->Instance + 1; + Pp2Context->Signature = PP2DXE_SIGNATURE; + Pp2Context->DevicePath = Pp2DevicePath; + Pp2DevicePath->Pp2Mac.IfType = SnpMode->IfType; + + /* Update SNP Mode */ + CopyMem (SnpMode->CurrentAddress.Addr, Pp2DevicePath->Pp2Mac.MacAddress.Addr, NET_ETHER_ADDR_LEN); + CopyMem (SnpMode->PermanentAddress.Addr, Pp2DevicePath->Pp2Mac.MacAddress.Addr, NET_ETHER_ADDR_LEN); + ZeroMem (&SnpMode->MCastFilter, MAX_MCAST_FILTER_CNT * sizeof(EFI_MAC_ADDRESS)); + SetMem (&SnpMode->BroadcastAddress, sizeof (EFI_MAC_ADDRESS), 0xFF); + + Pp2Context->Snp.Mode = SnpMode; + + /* Install protocol */ + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiSimpleNetworkProtocolGuid, &Pp2Context->Snp, + &gEfiDevicePathProtocolGuid, Pp2DevicePath, + NULL + ); + + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "Failed to install protocols.\n")); + } + + return Status; +} + +STATIC +VOID +Pp2DxeParsePortPcd ( + IN PP2DXE_CONTEXT *Pp2Context + ) +{ + UINT8 *PortIds, *GopIndexes, *PhyConnectionTypes, *AlwaysUp, *Speed; + + PortIds = PcdGetPtr (PcdPp2PortIds); + GopIndexes = PcdGetPtr (PcdPp2GopIndexes); + PhyConnectionTypes = PcdGetPtr (PcdPhyConnectionTypes); + AlwaysUp = PcdGetPtr (PcdPp2InterfaceAlwaysUp); + Speed = PcdGetPtr (PcdPp2InterfaceSpeed); + + ASSERT (PcdGetSize (PcdPp2GopIndexes) == PcdGetSize (PcdPp2PortIds)); + ASSERT (PcdGetSize (PcdPhyConnectionTypes) == PcdGetSize (PcdPp2PortIds)); + ASSERT (PcdGetSize (PcdPp2InterfaceAlwaysUp) == PcdGetSize (PcdPp2PortIds)); + ASSERT (PcdGetSize (PcdPp2InterfaceSpeed) == PcdGetSize (PcdPp2PortIds)); + + Pp2Context->Port.Id = PortIds[Pp2Context->Instance]; + Pp2Context->Port.GopIndex = GopIndexes[Pp2Context->Instance]; + Pp2Context->Port.PhyInterface = PhyConnectionTypes[Pp2Context->Instance]; + Pp2Context->Port.AlwaysUp = AlwaysUp[Pp2Context->Instance]; + Pp2Context->Port.Speed = Speed[Pp2Context->Instance]; + Pp2Context->Port.GmacBase = PcdGet64 (PcdPp2GmacBaseAddress) + + PcdGet32 (PcdPp2GmacDevSize) * Pp2Context->Port.GopIndex; + Pp2Context->Port.XlgBase = PcdGet64 (PcdPp2XlgBaseAddress) + + PcdGet32 (PcdPp2XlgDevSize) * Pp2Context->Port.GopIndex; +} + +EFI_STATUS +EFIAPI +Pp2DxeInitialise ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + PP2DXE_CONTEXT *Pp2Context = NULL; + EFI_STATUS Status; + INTN Index; + VOID *BufferSpace; + UINT32 NetCompConfig = 0; + UINT8 NumPorts = PcdGet32 (PcdPp2NumPorts); + + if (NumPorts == 0) { + DEBUG((DEBUG_ERROR, "Pp2Dxe: port number set to 0\n")); + return EFI_INVALID_PARAMETER; + } + + /* Initialize private data */ + Mvpp2Shared = AllocateZeroPool (sizeof (MVPP2_SHARED)); + if (Mvpp2Shared == NULL) { + DEBUG((DEBUG_ERROR, "Allocation fail.\n")); + return EFI_OUT_OF_RESOURCES; + } + + Mvpp2Shared->Base = PcdGet64 (PcdPp2SharedAddress); + Mvpp2Shared->Rfu1Base = PcdGet64 (PcdPp2Rfu1BaseAddress); + Mvpp2Shared->SmiBase = PcdGet64 (PcdPp2SmiBaseAddress); + Mvpp2Shared->Tclk = PcdGet32 (PcdPp2ClockFrequency); + + /* Prepare buffers */ + BufferSpace = UncachedAllocateAlignedZeroPool (BD_SPACE, MVPP2_BUFFER_ALIGN_SIZE); + if (BufferSpace == NULL) { + DEBUG((DEBUG_ERROR, "Failed to allocate buffer space\n")); + return EFI_OUT_OF_RESOURCES; + } + + BufferLocation.TxDescs = BufferSpace; + BufferLocation.AggrTxDescs = (MVPP2_TX_DESC *)((UINTN)BufferSpace + MVPP2_MAX_TXD * sizeof(MVPP2_TX_DESC)); + BufferLocation.RxDescs = (MVPP2_RX_DESC *)((UINTN)BufferSpace + + (MVPP2_MAX_TXD + MVPP2_AGGR_TXQ_SIZE) * sizeof(MVPP2_TX_DESC)); + BufferLocation.RxBuffers = (DmaAddrT)(BufferSpace + + (MVPP2_MAX_TXD + MVPP2_AGGR_TXQ_SIZE) * sizeof(MVPP2_TX_DESC) + + MVPP2_MAX_RXD * sizeof(MVPP2_RX_DESC)); + + /* Initialize HW */ + Mvpp2AxiConfig(Mvpp2Shared); + Pp2DxeBmPoolInit(); + Mvpp2RxFifoInit(Mvpp2Shared); + + Mvpp2Shared->PrsShadow = AllocateZeroPool (sizeof(MVPP2_PRS_SHADOW) * MVPP2_PRS_TCAM_SRAM_SIZE); + if (Mvpp2Shared->PrsShadow == NULL) { + DEBUG((DEBUG_ERROR, "Failed to allocate PrsShadow\n")); + return EFI_OUT_OF_RESOURCES; + } + + Status = Mvpp2PrsDefaultInit(Mvpp2Shared); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "Failed to intialize prs\n")); + return EFI_DEVICE_ERROR; + } + + Mvpp2ClsInit(Mvpp2Shared); + + Status = Pp2DxeBmStart(); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "Pp2Dxe: BM start error\n")); + return Status; + } + + /* Initialize aggregated transmit queues */ + Mvpp2Shared->AggrTxqs = AllocateZeroPool (sizeof(MVPP2_TX_QUEUE)); + if (Mvpp2Shared->AggrTxqs == NULL) { + DEBUG((DEBUG_ERROR, "Failed to allocate aggregated Txqs\n")); + return EFI_OUT_OF_RESOURCES; + } + + Mvpp2Shared->AggrTxqs->Descs = BufferLocation.AggrTxDescs; + Mvpp2Shared->AggrTxqs->Id = 0; + Mvpp2Shared->AggrTxqs->LogId = 0; + Mvpp2Shared->AggrTxqs->Size = MVPP2_AGGR_TXQ_SIZE; + + for (Index = 0; Index < NumPorts; Index++) { + Pp2Context = AllocateZeroPool (sizeof (PP2DXE_CONTEXT)); + if (Pp2Context == NULL) { + /* + * If allocation fails, all resources allocated before will get freed + * at ExitBootServices, as only EfiBootServicesData is used. + */ + DEBUG((DEBUG_ERROR, "Allocation fail.\n")); + return EFI_OUT_OF_RESOURCES; + } + + /* Instances are enumerated from 0 */ + Pp2Context->Instance = Index; + + /* Install SNP protocol */ + Status = Pp2DxeSnpInstall(Pp2Context); + if (EFI_ERROR(Status)) { + return Status; + } + + Pp2DxeParsePortPcd(Pp2Context); + Pp2Context->Port.TxpNum = 1; + Pp2Context->Port.Priv = Mvpp2Shared; + Pp2Context->Port.FirstRxq = 4 * Pp2Context->Instance; + + /* Gather accumulated configuration data of all ports' MAC's */ + NetCompConfig |= MvpPp2xGop110NetcCfgCreate(&Pp2Context->Port); + + MvGop110PortInit(&Pp2Context->Port); + MvGop110FlCfg(&Pp2Context->Port); + + Status = gBS->CreateEvent ( + EVT_SIGNAL_EXIT_BOOT_SERVICES, + TPL_NOTIFY, + Pp2DxeHalt, + Pp2Context, + &Pp2Context->EfiExitBootServicesEvent + ); + + if (EFI_ERROR(Status)) { + return Status; + } + } + + MvGop110NetcInit(&Pp2Context->Port, NetCompConfig, MV_NETC_FIRST_PHASE); + MvGop110NetcInit(&Pp2Context->Port, NetCompConfig, MV_NETC_SECOND_PHASE); + + return EFI_SUCCESS; +} diff --git a/Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.h b/Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.h new file mode 100644 index 0000000000..3bb0c4a653 --- /dev/null +++ b/Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.h @@ -0,0 +1,614 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __PP2_DXE_H__ +#define __PP2_DXE_H__ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Mvpp2LibHw.h" + +#define PP2DXE_SIGNATURE SIGNATURE_32('P', 'P', '2', 'D') +#define INSTANCE_FROM_SNP(a) CR((a), PP2DXE_CONTEXT, Snp, PP2DXE_SIGNATURE) + +/* OS API */ +#define Mvpp2Alloc(v) AllocateZeroPool(v) +#define Mvpp2Free(p) FreePool(p) +#define Mvpp2Memset(a, v, s) SetMem((a), (s), (v)) +#define Mvpp2Mdelay(t) gBS->Stall((t) * 1000) +#define Mvpp2Fls(v) 1 +#define Mvpp2IsBroadcastEtherAddr(da) 1 +#define Mvpp2IsMulticastEtherAddr(da) 1 +#define Mvpp2Prefetch(v) do {} while(0); +#define Mvpp2Printf(...) do {} while(0); +#define Mvpp2SwapVariables(a,b) do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0) +#define Mvpp2SwapBytes16(x) SwapBytes16((x)) +#define Mvpp2Iphdr EFI_IP4_HEADER +#define Mvpp2Ipv6hdr EFI_IP6_HEADER +#define MVPP2_ALIGN(x, m) ALIGN_VALUE((x), (m)) +#define MVPP2_ENOMEM -1 +#define MVPP2_EINVAL -2 +#define MVPP2_ERANGE -3 +#define MVPP2_USEC_PER_SEC 1000000L + +#define DmaAddrT UINTN +#define PhysAddrT UINTN + +#define Upper32Bits(n) ((UINT32)(((n) >> 16) >> 16)) +#define Lower32Bits(n) ((UINT32)(n)) + +#define ARCH_DMA_MINALIGN 64 + +/* Port speeds */ +#define MV_PORT_SPEED_10 SPEED_10 +#define MV_PORT_SPEED_100 SPEED_100 +#define MV_PORT_SPEED_1000 SPEED_1000 +#define MV_PORT_SPEED_2500 SPEED_2500 +#define MV_PORT_SPEED_10000 SPEED_10000 + +/* L2 and L3 protocol macros */ +#define MV_IPPR_TCP 0 +#define MV_IPPR_UDP 1 +#define MV_IPPR_IPIP 2 +#define MV_IPPR_ICMPV6 3 +#define MV_IPPR_IGMP 4 +#define MV_ETH_P_IP 5 +#define MV_ETH_P_IPV6 6 +#define MV_ETH_P_PPP_SES 7 +#define MV_ETH_P_ARP 8 +#define MV_ETH_P_8021Q 9 +#define MV_ETH_P_8021AD 10 +#define MV_ETH_P_EDSA 11 +#define MV_PPP_IP 12 +#define MV_PPP_IPV6 13 +#define MV_ETH_ALEN NET_ETHER_ADDR_LEN + +/* PHY modes */ +#define MV_MODE_SGMII PHY_CONNECTION_SGMII +#define MV_MODE_RGMII PHY_CONNECTION_RGMII +#define MV_MODE_XAUI PHY_CONNECTION_XAUI +#define MV_MODE_RXAUI PHY_CONNECTION_RXAUI +#define MV_MODE_QSGMII 100 +#define PP2DXE_MAX_PHY 2 + +/* Gop */ +/* Sets the field located at the specified in data */ +#define U32_SET_FIELD(data, mask, val) ((data) = (((data) & ~(mask)) | (val))) +#define MV_RGMII_TX_FIFO_MIN_TH 0x41 +#define MV_SGMII_TX_FIFO_MIN_TH 0x5 +#define MV_SGMII2_5_TX_FIFO_MIN_TH 0xB + +/* BM constants */ +#define MVPP2_BM_POOLS_NUM 8 +#define MVPP2_BM_LONG_BUF_NUM 1024 +#define MVPP2_BM_SHORT_BUF_NUM 2048 +#define MVPP2_BM_POOL_SIZE_MAX (SIZE_16KB - MVPP2_BM_POOL_PTR_ALIGN/4) +#define MVPP2_BM_POOL_PTR_ALIGN 128 +#define MVPP2_BM_SWF_LONG_POOL(Port) ((Port > 2) ? 2 : Port) +#define MVPP2_BM_SWF_SHORT_POOL 3 +#define MVPP2_BM_POOL 0 +#define MVPP2_BM_SIZE 32 + +/* + * BM short pool packet Size + * These value assure that for SWF the total number + * of bytes allocated for each buffer will be 512 + */ +#define MVPP2_BM_SHORT_PKT_SIZE 512 + +/* + * Page table entries are set to 1MB, or multiples of 1MB + * (not < 1MB). driver uses less bd's so use 1MB bdspace. + */ +#define BD_SPACE (1 << 20) + +/* Buffer has to be aligned to 1M */ +#define MVPP2_BUFFER_ALIGN_SIZE (1 << 20) + +/* RX constants */ +#define RX_BUFFER_SIZE (ALIGN_VALUE(MTU + WRAP, ARCH_DMA_MINALIGN)) +#define MVPP2_RXQ_OFFSET 0 +#define BUFF_HDR_OFFS 32 +#define BM_ALIGN 32 +#define ETH_HLEN 14 + +/* 2(HW hdr) 14(MAC hdr) 4(CRC) 32(extra for cache prefetch) */ +#define WRAP (2 + ETH_HLEN + 4 + 32) +#define MTU 1500 + +/* + * Maximum retries of checking, wheter HW really sent the packet + * after it was done is software. + */ +#define MVPP2_TX_SEND_MAX_POLLING_COUNT 10000 + +/* Structures */ +typedef struct { + /* Physical number of this Tx queue */ + UINT8 Id; + + /* Logical number of this Tx queue */ + UINT8 LogId; + + /* Number of Tx DMA descriptors in the descriptor ring */ + INT32 Size; + + /* Number of currently used Tx DMA descriptor in the descriptor ring */ + INT32 count; + + UINT32 DonePktsCoal; + + /* Virtual address of thex Tx DMA descriptors array */ + MVPP2_TX_DESC *Descs; + + /* DMA address of the Tx DMA descriptors array */ + DmaAddrT DescsPhys; + + /* Index of the last Tx DMA descriptor */ + INT32 LastDesc; + + /* Index of the next Tx DMA descriptor to process */ + INT32 NextDescToProc; +} MVPP2_TX_QUEUE; + +typedef struct { + /* RX queue number, in the range 0-31 for physical RXQs */ + UINT8 Id; + + /* Num of rx descriptors in the rx descriptor ring */ + INT32 Size; + + UINT32 PktsCoal; + UINT32 TimeCoal; + + /* Virtual address of the RX DMA descriptors array */ + MVPP2_RX_DESC *Descs; + + /* DMA address of the RX DMA descriptors array */ + DmaAddrT DescsPhys; + + /* Index of the last RX DMA descriptor */ + INT32 LastDesc; + + /* Index of the next RX DMA descriptor to process */ + INT32 NextDescToProc; + + /* ID of Port to which physical RXQ is mapped */ + INT32 Port; + + /* Port's logic RXQ number to which physical RXQ is mapped */ + INT32 LogicRxq; +} MVPP2_RX_QUEUE; + +enum Mvpp2BmType { + MVPP2_BM_FREE, + MVPP2_BM_SWF_LONG, + MVPP2_BM_SWF_SHORT +}; + +typedef struct { + /* Pool number in the range 0-7 */ + INT32 Id; + enum Mvpp2BmType type; + + /* Buffer Pointers Pool External (BPPE) Size */ + INT32 Size; + /* Number of buffers for this pool */ + INT32 BufNum; + /* Pool buffer Size */ + INT32 BufSize; + /* Packet Size */ + INT32 PktSize; + + /* BPPE virtual base address */ + UINT32 *VirtAddr; + /* BPPE physical base address */ + DmaAddrT PhysAddr; + + /* Ports using BM pool */ + UINT32 PortMap; +} MVPP2_BMS_POOL; + +typedef struct Pp2DxePort PP2DXE_PORT; + +/* Shared Packet Processor resources */ +typedef struct { + /* Shared registers' base addresses */ + UINT64 Base; + UINT64 Rfu1Base; + UINT64 SmiBase; + VOID *LmsBase; + + /* List of pointers to Port structures */ + PP2DXE_PORT **PortList; + + /* Aggregated TXQs */ + MVPP2_TX_QUEUE *AggrTxqs; + + /* BM pools */ + MVPP2_BMS_POOL *BmPools; + + /* PRS shadow table */ + MVPP2_PRS_SHADOW *PrsShadow; + /* PRS auxiliary table for double vlan entries control */ + BOOLEAN *PrsDoubleVlans; + + /* Tclk value */ + UINT32 Tclk; +} MVPP2_SHARED; + +/* Individual Port structure */ +struct Pp2DxePort { + UINT8 Id; + UINT8 GopIndex; + + INT32 Irq; + + MVPP2_SHARED *Priv; + + /* Per-Port registers' base address */ + UINT64 GmacBase; + UINT64 XlgBase; + + MVPP2_RX_QUEUE *Rxqs; + MVPP2_TX_QUEUE *Txqs; + + INT32 PktSize; + + UINT32 PendingCauseRx; + + /* Flags */ + UINTN Flags; + + UINT16 TxRingSize; + UINT16 RxRingSize; + + INT32 PhyInterface; + BOOLEAN Link; + BOOLEAN Duplex; + BOOLEAN AlwaysUp; + PHY_SPEED Speed; + + MVPP2_BMS_POOL *PoolLong; + MVPP2_BMS_POOL *PoolShort; + + UINT8 TxpNum; + + /* Index of first Port's physical RXQ */ + UINT8 FirstRxq; +}; + +/* Structure for preallocation for buffer */ +typedef struct { + MVPP2_TX_DESC *TxDescs; + MVPP2_TX_DESC *AggrTxDescs; + MVPP2_RX_DESC *RxDescs; + DmaAddrT RxBuffers; +} BUFFER_LOCATION; + +typedef struct { + MAC_ADDR_DEVICE_PATH Pp2Mac; + EFI_DEVICE_PATH_PROTOCOL End; +} PP2_DEVICE_PATH; + +#define QUEUE_DEPTH 64 +typedef struct { + UINT32 Signature; + INTN Instance; + EFI_HANDLE Controller; + EFI_LOCK Lock; + EFI_SIMPLE_NETWORK_PROTOCOL Snp; + MARVELL_PHY_PROTOCOL *Phy; + PHY_DEVICE *PhyDev; + PP2DXE_PORT Port; + BOOLEAN Initialized; + BOOLEAN LateInitialized; + VOID *CompletionQueue[QUEUE_DEPTH]; + UINTN CompletionQueueHead; + UINTN CompletionQueueTail; + EFI_EVENT EfiExitBootServicesEvent; + PP2_DEVICE_PATH *DevicePath; +} PP2DXE_CONTEXT; + +/* Inline helpers */ +STATIC +inline +VOID +Mvpp2Write ( + IN MVPP2_SHARED *Priv, + IN UINT32 Offset, + IN UINT32 data + ) +{ + ASSERT (Priv->Base != 0); + MmioWrite32 (Priv->Base + Offset, data); +} + +STATIC +inline +UINT32 +Mvpp2Read ( + IN MVPP2_SHARED *Priv, + IN UINT32 Offset + ) +{ + ASSERT (Priv->Base != 0); + return MmioRead32 (Priv->Base + Offset); +} + +STATIC +inline +UINT32 +Mvpp2Rfu1Read ( + IN MVPP2_SHARED *Priv, + UINT32 Offset + ) +{ + ASSERT (Priv->Rfu1Base != 0); + return MmioRead32 (Priv->Rfu1Base + Offset); +} + +STATIC +inline +UINT32 +Mvpp2Rfu1Write ( + IN MVPP2_SHARED *Priv, + IN UINT32 Offset, + IN UINT32 Data + ) +{ + ASSERT (Priv->Rfu1Base != 0); + return MmioWrite32 (Priv->Rfu1Base + Offset, Data); +} + +STATIC +inline +UINT32 +Mvpp2SmiRead ( + IN MVPP2_SHARED *Priv, + IN UINT32 Offset + ) +{ + ASSERT (Priv->SmiBase != 0); + return MmioRead32 (Priv->SmiBase + Offset); +} + +STATIC +inline +UINT32 +Mvpp2SmiWrite ( + IN MVPP2_SHARED *Priv, + IN UINT32 Offset, + IN UINT32 Data + ) +{ + ASSERT (Priv->SmiBase != 0); + return MmioWrite32 (Priv->SmiBase + Offset, Data); +} + +STATIC +inline +VOID +Mvpp2GmacWrite ( + IN PP2DXE_PORT *Port, + IN UINT32 Offset, + IN UINT32 Data + ) +{ + ASSERT (Port->Priv->Base != 0); + MmioWrite32 (Port->Priv->Base + Offset, Data); +} + +STATIC +inline +UINT32 +Mvpp2GmacRead ( + IN PP2DXE_PORT *Port, + IN UINT32 Offset + ) +{ + ASSERT (Port->Priv->Base != 0); + return MmioRead32 (Port->Priv->Base + Offset); +} + +STATIC +inline +VOID +MvGop110GmacWrite ( + IN PP2DXE_PORT *Port, + IN UINT32 Offset, + IN UINT32 Data + ) +{ + ASSERT (Port->GmacBase != 0); + MmioWrite32 (Port->GmacBase + Offset, Data); +} + +STATIC +inline +UINT32 +MvGop110GmacRead ( + IN PP2DXE_PORT *Port, + IN UINT32 Offset + ) +{ + ASSERT (Port->GmacBase != 0); + return MmioRead32 (Port->GmacBase + Offset); +} + +STATIC +inline +VOID +Mvpp2XlgWrite ( + IN PP2DXE_PORT *Port, + IN UINT32 Offset, + IN UINT32 Data + ) +{ + ASSERT (Port->XlgBase != 0); + MmioWrite32 (Port->XlgBase + Offset, Data); +} + +STATIC +inline +UINT32 +Mvpp2XlgRead ( + IN PP2DXE_PORT *Port, + IN UINT32 Offset + ) +{ + ASSERT (Port->XlgBase != 0); + return MmioRead32 (Port->XlgBase + Offset); +} + +/* SNP callbacks */ +EFI_STATUS +EFIAPI +Pp2SnpStart ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This + ); + +EFI_STATUS +EFIAPI +Pp2SnpStop ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This + ); + +EFI_STATUS +EFIAPI +Pp2DxeSnpInitialize ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN UINTN ExtraRxBufferSize OPTIONAL, + IN UINTN ExtraTxBufferSize OPTIONAL + ); + +EFI_STATUS +EFIAPI +Pp2SnpReset ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +EFI_STATUS +EFIAPI +Pp2SnpShutdown ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This + ); + +EFI_STATUS +EFIAPI +Pp2SnpReceiveFilters ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN UINT32 Enable, + IN UINT32 Disable, + IN BOOLEAN ResetMCastFilter, + IN UINTN MCastFilterCnt OPTIONAL, + IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL + ); + +EFI_STATUS +EFIAPI +Pp2SnpStationAddress ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + IN BOOLEAN Reset, + IN EFI_MAC_ADDRESS *NewMac +); + +EFI_STATUS +EFIAPI +Pp2SnpNetStat ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN BOOLEAN Reset, + IN OUT UINTN *StatisticsSize OPTIONAL, + OUT EFI_NETWORK_STATISTICS *StatisticsTable OPTIONAL + ); + +EFI_STATUS +EFIAPI +Pp2SnpIpToMac ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN BOOLEAN IPv6, + IN EFI_IP_ADDRESS *IP, + OUT EFI_MAC_ADDRESS *MAC + ); + +EFI_STATUS +EFIAPI +Pp2SnpGetStatus ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + OUT UINT32 *InterruptStatus OPTIONAL, + OUT VOID **TxBuf OPTIONAL + ); + +EFI_STATUS +EFIAPI +Pp2SnpTransmit ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN UINTN HeaderSize, + IN UINTN BufferSize, + IN VOID *Buffer, + IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + IN EFI_MAC_ADDRESS *DestAddr OPTIONAL, + IN UINT16 *EtherTypePtr OPTIONAL + ); + +EFI_STATUS +EFIAPI +Pp2SnpReceive ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + OUT UINTN *HeaderSize OPTIONAL, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer, + OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + OUT EFI_MAC_ADDRESS *DstAddr OPTIONAL, + OUT UINT16 *EtherType OPTIONAL + ); +#endif diff --git a/Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.inf b/Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.inf new file mode 100644 index 0000000000..87cc5e8ded --- /dev/null +++ b/Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.inf @@ -0,0 +1,91 @@ +# Copyright (C) 2016 Marvell International Ltd. +# +# Marvell BSD License Option +# +# If you received this File from Marvell, you may opt to use, redistribute and/or +# modify this File under the following licensing terms. +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Marvell nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = Pp2Dxe + FILE_GUID = 5ffc3843-d8d4-40ba-ae07-38967138509c + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = Pp2DxeInitialise + +[Sources.common] + Pp2Dxe.c + Mvpp2Lib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + ArmPkg/ArmPkg.dec + Platform/Marvell/Marvell.dec + +[LibraryClasses] + IoLib + PcdLib + BaseLib + BaseMemoryLib + DebugLib + UefiLib + NetLib + UefiDriverEntryPoint + UefiBootServicesTableLib + MemoryAllocationLib + UncachedMemoryAllocationLib + CacheMaintenanceLib + +[Protocols] + gEfiSimpleNetworkProtocolGuid + gEfiDevicePathProtocolGuid + gEfiCpuArchProtocolGuid + gMarvellMdioProtocolGuid + gMarvellPhyProtocolGuid + +[Pcd] + gMarvellTokenSpaceGuid.PcdPhyConnectionTypes + gMarvellTokenSpaceGuid.PcdPhySmiAddresses + gMarvellTokenSpaceGuid.PcdPp2ClockFrequency + gMarvellTokenSpaceGuid.PcdPp2GmacBaseAddress + gMarvellTokenSpaceGuid.PcdPp2GmacDevSize + gMarvellTokenSpaceGuid.PcdPp2GopIndexes + gMarvellTokenSpaceGuid.PcdPp2InterfaceAlwaysUp + gMarvellTokenSpaceGuid.PcdPp2InterfaceSpeed + gMarvellTokenSpaceGuid.PcdPp2NumPorts + gMarvellTokenSpaceGuid.PcdPp2PortIds + gMarvellTokenSpaceGuid.PcdPp2Rfu1BaseAddress + gMarvellTokenSpaceGuid.PcdPp2SharedAddress + gMarvellTokenSpaceGuid.PcdPp2SmiBaseAddress + gMarvellTokenSpaceGuid.PcdPp2XlgBaseAddress + gMarvellTokenSpaceGuid.PcdPp2XlgDevSize + +[Depex] + TRUE diff --git a/Platform/Marvell/Drivers/SdMmc/XenonDxe/ComponentName.c b/Platform/Marvell/Drivers/SdMmc/XenonDxe/ComponentName.c new file mode 100644 index 0000000000..3329929119 --- /dev/null +++ b/Platform/Marvell/Drivers/SdMmc/XenonDxe/ComponentName.c @@ -0,0 +1,211 @@ +/** @file + UEFI Component Name(2) protocol implementation for SD/MMC host controller driver. + + Copyright (c) 2015, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "SdMmcPciHcDxe.h" + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gSdMmcPciHcComponentName = { + SdMmcPciHcComponentNameGetDriverName, + SdMmcPciHcComponentNameGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSdMmcPciHcComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SdMmcPciHcComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SdMmcPciHcComponentNameGetControllerName, + "en" +}; + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdMmcPciHcDriverNameTable[] = { + { "eng;en", L"Edkii Sd/Mmc Host Controller Driver" }, + { NULL , NULL } +}; + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdMmcPciHcControllerNameTable[] = { + { "eng;en", L"Edkii Sd/Mmc Host Controller" }, + { NULL , NULL } +}; + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +SdMmcPciHcComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mSdMmcPciHcDriverNameTable, + DriverName, + (BOOLEAN)(This == &gSdMmcPciHcComponentName) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +SdMmcPciHcComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle, OPTIONAL + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + EFI_STATUS Status; + + if (Language == NULL || ControllerName == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // This is a device driver, so ChildHandle must be NULL. + // + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + // + // Make sure this driver is currently managing ControllerHandle + // + Status = EfiTestManagedDevice ( + ControllerHandle, + gSdMmcPciHcDriverBinding.DriverBindingHandle, + &gEfiPciIoProtocolGuid + ); + if (EFI_ERROR (Status)) { + return Status; + } + + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mSdMmcPciHcControllerNameTable, + ControllerName, + (BOOLEAN)(This == &gSdMmcPciHcComponentName) + ); +} diff --git a/Platform/Marvell/Drivers/SdMmc/XenonDxe/EmmcDevice.c b/Platform/Marvell/Drivers/SdMmc/XenonDxe/EmmcDevice.c new file mode 100755 index 0000000000..3f73194da7 --- /dev/null +++ b/Platform/Marvell/Drivers/SdMmc/XenonDxe/EmmcDevice.c @@ -0,0 +1,1162 @@ +/** @file + This file provides some helper functions which are specific for EMMC device. + + Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "SdMmcPciHcDxe.h" + +/** + Send command GO_IDLE_STATE (CMD0 with argument of 0x00000000) to the device to + make it go to Idle State. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS The EMMC device is reset correctly. + @retval Others The device reset fails. + +**/ +EFI_STATUS +EmmcReset ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = EMMC_GO_IDLE_STATE; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBc; + SdMmcCmdBlk.ResponseType = 0; + SdMmcCmdBlk.CommandArgument = 0; + + gBS->Stall (1000); + + Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); + + return Status; +} + +/** + Send command SEND_OP_COND to the EMMC device to get the data of the OCR register. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in, out] Argument On input, the argument of SEND_OP_COND is to send to the device. + On output, the argument is the value of OCR register. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcGetOcr ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + IN OUT UINT32 *Argument + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = EMMC_SEND_OP_COND; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR3; + SdMmcCmdBlk.CommandArgument = *Argument; + + Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); + if (!EFI_ERROR (Status)) { + // + // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12. + // + *Argument = SdMmcStatusBlk.Resp0; + } + + return Status; +} + +/** + Broadcast command ALL_SEND_CID to the bus to ask all the EMMC devices to send the + data of their CID registers. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcGetAllCid ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = EMMC_ALL_SEND_CID; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2; + SdMmcCmdBlk.CommandArgument = 0; + + Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); + + return Status; +} + +/** + Send command SET_RELATIVE_ADDR to the EMMC device to assign a Relative device + Address (RCA). + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Rca The relative device address to be assigned. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcSetRca ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + IN UINT16 Rca + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = EMMC_SET_RELATIVE_ADDR; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); + + return Status; +} + +/** + Send command SEND_CSD to the EMMC device to get the data of the CSD register. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Rca The relative device address of selected device. + @param[out] Csd The buffer to store the content of the CSD register. + Note the caller should ignore the lowest byte of this + buffer as the content of this byte is meaningless even + if the operation succeeds. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcGetCsd ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + IN UINT16 Rca, + OUT EMMC_CSD *Csd + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = EMMC_SEND_CSD; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2; + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); + if (!EFI_ERROR (Status)) { + // + // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12. + // + CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (EMMC_CSD) - 1); + } + + return Status; +} + +/** + Send command SELECT_DESELECT_CARD to the EMMC device to select/deselect it. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Rca The relative device address of selected device. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcSelect ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + IN UINT16 Rca + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = EMMC_SELECT_DESELECT_CARD; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); + + return Status; +} + +/** + Send command SEND_EXT_CSD to the EMMC device to get the data of the EXT_CSD register. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[out] ExtCsd The buffer to store the content of the EXT_CSD register. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcGetExtCsd ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + OUT EMMC_EXT_CSD *ExtCsd + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = EMMC_SEND_EXT_CSD; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + SdMmcCmdBlk.CommandArgument = 0x00000000; + + Packet.InDataBuffer = ExtCsd; + Packet.InTransferLength = sizeof (EMMC_EXT_CSD); + + Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); + return Status; +} + +/** + Send command SWITCH to the EMMC device to switch the mode of operation of the + selected Device or modifies the EXT_CSD registers. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Access The access mode of SWTICH command. + @param[in] Index The offset of the field to be access. + @param[in] Value The value to be set to the specified field of EXT_CSD register. + @param[in] CmdSet The value of CmdSet field of EXT_CSD register. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcSwitch ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + IN UINT8 Access, + IN UINT8 Index, + IN UINT8 Value, + IN UINT8 CmdSet + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = EMMC_SWITCH; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b; + SdMmcCmdBlk.CommandArgument = (Access << 24) | (Index << 16) | (Value << 8) | CmdSet; + + Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); + + return Status; +} + +/** + Send command SEND_STATUS to the addressed EMMC device to get its status register. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Rca The relative device address of addressed device. + @param[out] DevStatus The returned device status. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcSendStatus ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + IN UINT16 Rca, + OUT UINT32 *DevStatus + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = EMMC_SEND_STATUS; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); + if (!EFI_ERROR (Status)) { + *DevStatus = SdMmcStatusBlk.Resp0; + } + + return Status; +} + +/** + Send command SEND_TUNING_BLOCK to the EMMC device for HS200 optimal sampling point + detection. + + It may be sent up to 40 times until the host finishes the tuning procedure. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] BusWidth The bus width to work. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcSendTuningBlk ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + IN UINT8 BusWidth + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + UINT8 TuningBlock[128]; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = EMMC_SEND_TUNING_BLOCK; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + SdMmcCmdBlk.CommandArgument = 0; + + Packet.InDataBuffer = TuningBlock; + if (BusWidth == 8) { + Packet.InTransferLength = sizeof (TuningBlock); + } else { + Packet.InTransferLength = 64; + } + + Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); + + return Status; +} + +/** + Tunning the clock to get HS200 optimal sampling point. + + Command SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes the + tuning procedure. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller + Simplified Spec 3.0 Figure 2-29 for details. + + @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] BusWidth The bus width to work. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcTuningClkForHs200 ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + IN UINT8 BusWidth + ) +{ + EFI_STATUS Status; + UINT8 HostCtrl2; + UINT8 Retry; + + // + // Notify the host that the sampling clock tuning procedure starts. + // + HostCtrl2 = BIT6; + Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Ask the device to send a sequence of tuning blocks till the tuning procedure is done. + // + Retry = 0; + do { + Status = EmmcSendTuningBlk (PassThru, Slot, BusWidth); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "EmmcTuningClkForHs200: Send tuning block fails with %r\n", Status)); + return Status; + } + + Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((HostCtrl2 & (BIT6 | BIT7)) == 0) { + break; + } + + if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) { + return EFI_SUCCESS; + } + } while (++Retry < 40); + + DEBUG ((DEBUG_ERROR, "EmmcTuningClkForHs200: Send tuning block fails at %d times with HostCtrl2 %02x\n", Retry, HostCtrl2)); + // + // Abort the tuning procedure and reset the tuning circuit. + // + HostCtrl2 = (UINT8)~(BIT6 | BIT7); + Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + return EFI_DEVICE_ERROR; +} + +/** + Switch the bus width to specified width. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.9 and SD Host Controller + Simplified Spec 3.0 Figure 3-7 for details. + + @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Rca The relative device address to be assigned. + @param[in] IsDdr If TRUE, use dual data rate data simpling method. Otherwise + use single data rate data simpling method. + @param[in] BusWidth The bus width to be set, it could be 4 or 8. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcSwitchBusWidth ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + IN UINT16 Rca, + IN BOOLEAN IsDdr, + IN UINT8 BusWidth + ) +{ + EFI_STATUS Status; + UINT8 Access; + UINT8 Index; + UINT8 Value; + UINT8 CmdSet; + UINT32 DevStatus; + + // + // Write Byte, the Value field is written into the byte pointed by Index. + // + Access = 0x03; + Index = OFFSET_OF (EMMC_EXT_CSD, BusWidth); + if (BusWidth == 4) { + Value = 1; + } else if (BusWidth == 8) { + Value = 2; + } else { + return EFI_INVALID_PARAMETER; + } + + if (IsDdr) { + Value += 4; + } + + CmdSet = 0; + Status = EmmcSwitch (PassThru, Slot, Access, Index, Value, CmdSet); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "EmmcSwitchBusWidth: Switch to bus width %d fails with %r\n", BusWidth, Status)); + return Status; + } + + Status = EmmcSendStatus (PassThru, Slot, Rca, &DevStatus); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "EmmcSwitchBusWidth: Send status fails with %r\n", Status)); + return Status; + } + // + // Check the switch operation is really successful or not. + // + if ((DevStatus & BIT7) != 0) { + DEBUG ((DEBUG_ERROR, "EmmcSwitchBusWidth: The switch operation fails as DevStatus is 0x%08x\n", DevStatus)); + return EFI_DEVICE_ERROR; + } + + Status = SdMmcHcSetBusWidth (PciIo, Slot, BusWidth); + + return Status; +} + +/** + Switch the clock frequency to the specified value. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6 and SD Host Controller + Simplified Spec 3.0 Figure 3-3 for details. + + @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Rca The relative device address to be assigned. + @param[in] HsTiming The value to be written to HS_TIMING field of EXT_CSD register. + @param[in] ClockFreq The max clock frequency to be set, the unit is MHz. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcSwitchClockFreq ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + IN UINT16 Rca, + IN UINT8 HsTiming, + IN UINT32 ClockFreq + ) +{ + EFI_STATUS Status; + UINT8 Access; + UINT8 Index; + UINT8 Value; + UINT8 CmdSet; + UINT32 DevStatus; + SD_MMC_HC_PRIVATE_DATA *Private; + + Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru); + // + // Write Byte, the Value field is written into the byte pointed by Index. + // + Access = 0x03; + Index = OFFSET_OF (EMMC_EXT_CSD, HsTiming); + Value = HsTiming; + CmdSet = 0; + + Status = EmmcSwitch (PassThru, Slot, Access, Index, Value, CmdSet); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "EmmcSwitchClockFreq: Switch to hstiming %d fails with %r\n", HsTiming, Status)); + return Status; + } + + Status = EmmcSendStatus (PassThru, Slot, Rca, &DevStatus); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "EmmcSwitchClockFreq: Send status fails with %r\n", Status)); + return Status; + } + // + // Check the switch operation is really successful or not. + // + if ((DevStatus & BIT7) != 0) { + DEBUG ((DEBUG_ERROR, "EmmcSwitchClockFreq: The switch operation fails as DevStatus is 0x%08x\n", DevStatus)); + return EFI_DEVICE_ERROR; + } + // + // Convert the clock freq unit from MHz to KHz. + // + Status = SdMmcHcClockSupply (PciIo, Slot, ClockFreq * 1000, Private->Capability[Slot]); + + return Status; +} + +/** + Switch to the High Speed timing according to request. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller + Simplified Spec 3.0 Figure 2-29 for details. + + @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Rca The relative device address to be assigned. + @param[in] ClockFreq The max clock frequency to be set. + @param[in] IsDdr If TRUE, use dual data rate data simpling method. Otherwise + use single data rate data simpling method. + @param[in] BusWidth The bus width to be set, it could be 4 or 8. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcSwitchToHighSpeed ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + IN UINT16 Rca, + IN UINT32 ClockFreq, + IN BOOLEAN IsDdr, + IN UINT8 BusWidth + ) +{ + EFI_STATUS Status; + UINT8 HsTiming; + UINT8 HostCtrl1; + UINT8 HostCtrl2; + + Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, IsDdr, BusWidth); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Set to Hight Speed timing + // + HostCtrl1 = BIT2; + Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Clean UHS Mode Select field of Host Control 2 reigster before update + // + HostCtrl2 = (UINT8)~0x7; + Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Set UHS Mode Select field of Host Control 2 reigster to SDR12/25/50 + // + if (IsDdr) { + HostCtrl2 = BIT2; + } else if (ClockFreq == 52) { + HostCtrl2 = BIT0; + } else { + HostCtrl2 = 0; + } + Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + + HsTiming = 1; + Status = EmmcSwitchClockFreq (PciIo, PassThru, Slot, Rca, HsTiming, ClockFreq); + if (EFI_ERROR (Status)) { + return Status; + } + + return Status; +} + +/** + Switch to the HS200 timing according to request. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller + Simplified Spec 3.0 Figure 2-29 for details. + + @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Rca The relative device address to be assigned. + @param[in] ClockFreq The max clock frequency to be set. + @param[in] BusWidth The bus width to be set, it could be 4 or 8. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcSwitchToHS200 ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + IN UINT16 Rca, + IN UINT32 ClockFreq, + IN UINT8 BusWidth + ) +{ + EFI_STATUS Status; + UINT8 HsTiming; + UINT8 HostCtrl2; + UINT16 ClockCtrl; + + if ((BusWidth != 4) && (BusWidth != 8)) { + return EFI_INVALID_PARAMETER; + } + + Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, FALSE, BusWidth); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Set to HS200/SDR104 timing + // + // + // Stop bus clock at first + // + Status = SdMmcHcStopClock (PciIo, Slot); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Clean UHS Mode Select field of Host Control 2 reigster before update + // + HostCtrl2 = (UINT8)~0x7; + Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Set UHS Mode Select field of Host Control 2 reigster to SDR104 + // + HostCtrl2 = BIT0 | BIT1; + Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Wait Internal Clock Stable in the Clock Control register to be 1 before set SD Clock Enable bit + // + Status = SdMmcHcWaitMmioSet ( + PciIo, + Slot, + SD_MMC_HC_CLOCK_CTRL, + sizeof (ClockCtrl), + BIT1, + BIT1, + SD_MMC_HC_GENERIC_TIMEOUT + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Set SD Clock Enable in the Clock Control register to 1 + // + ClockCtrl = BIT2; + Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl); + + HsTiming = 2; + Status = EmmcSwitchClockFreq (PciIo, PassThru, Slot, Rca, HsTiming, ClockFreq); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = EmmcTuningClkForHs200 (PciIo, PassThru, Slot, BusWidth); + + return Status; +} + +/** + Switch to the HS400 timing according to request. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller + Simplified Spec 3.0 Figure 2-29 for details. + + @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Rca The relative device address to be assigned. + @param[in] ClockFreq The max clock frequency to be set. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcSwitchToHS400 ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + IN UINT16 Rca, + IN UINT32 ClockFreq + ) +{ + EFI_STATUS Status; + UINT8 HsTiming; + UINT8 HostCtrl2; + + Status = EmmcSwitchToHS200 (PciIo, PassThru, Slot, Rca, ClockFreq, 8); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Set to Hight Speed timing and set the clock frequency to a value less than 52MHz. + // + HsTiming = 1; + Status = EmmcSwitchClockFreq (PciIo, PassThru, Slot, Rca, HsTiming, 52); + if (EFI_ERROR (Status)) { + return Status; + } + // + // HS400 mode must use 8 data lines. + // + Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, TRUE, 8); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Clean UHS Mode Select field of Host Control 2 reigster before update + // + HostCtrl2 = (UINT8)~0x7; + Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Set UHS Mode Select field of Host Control 2 reigster to HS400 + // + HostCtrl2 = BIT0 | BIT2; + Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + + HsTiming = 3; + Status = EmmcSwitchClockFreq (PciIo, PassThru, Slot, Rca, HsTiming, ClockFreq); + + return Status; +} + +/** + Switch the high speed timing according to request. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller + Simplified Spec 3.0 Figure 2-29 for details. + + @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Rca The relative device address to be assigned. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcSetBusMode ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + IN UINT16 Rca + ) +{ + EFI_STATUS Status; + EMMC_CSD Csd; + EMMC_EXT_CSD ExtCsd; + UINT8 HsTiming; + BOOLEAN IsDdr; + UINT32 ClockFreq; + UINT8 BusWidth; + SD_MMC_HC_PRIVATE_DATA *Private; + + Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru); + + Status = EmmcGetCsd (PassThru, Slot, Rca, &Csd); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: GetCsd fails with %r\n", Status)); + return Status; + } + + Status = EmmcSelect (PassThru, Slot, Rca); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: Select fails with %r\n", Status)); + return Status; + } + + ASSERT (Private->Capability[Slot].BaseClkFreq != 0); + // + // Check if the Host Controller support 8bits bus width. + // + if (Private->Capability[Slot].BusWidth8 != 0) { + BusWidth = 8; + } else { + BusWidth = 4; + } + // + // Get Deivce_Type from EXT_CSD register. + // + Status = EmmcGetExtCsd (PassThru, Slot, &ExtCsd); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: GetExtCsd fails with %r\n", Status)); + return Status; + } + // + // Calculate supported bus speed/bus width/clock frequency. + // + HsTiming = 0; + IsDdr = FALSE; + ClockFreq = 0; + if (((ExtCsd.DeviceType & (BIT4 | BIT5)) != 0) && (Private->Capability[Slot].Sdr104 != 0)) { + HsTiming = 2; + IsDdr = FALSE; + ClockFreq = 200; + } else if (((ExtCsd.DeviceType & (BIT2 | BIT3)) != 0) && (Private->Capability[Slot].Ddr50 != 0)) { + HsTiming = 1; + IsDdr = TRUE; + ClockFreq = 52; + } else if (((ExtCsd.DeviceType & BIT1) != 0) && (Private->Capability[Slot].HighSpeed != 0)) { + HsTiming = 1; + IsDdr = FALSE; + ClockFreq = 52; + } else if (((ExtCsd.DeviceType & BIT0) != 0) && (Private->Capability[Slot].HighSpeed != 0)) { + HsTiming = 1; + IsDdr = FALSE; + ClockFreq = 26; + } + // + // Check if both of the device and the host controller support HS400 DDR mode. + // + if (((ExtCsd.DeviceType & (BIT6 | BIT7)) != 0) && (Private->Capability[Slot].Hs400 != 0)) { + // + // The host controller supports 8bits bus. + // + ASSERT (BusWidth == 8); + HsTiming = 3; + IsDdr = TRUE; + ClockFreq = 200; + } + + if ((ClockFreq == 0) || (HsTiming == 0)) { + // + // Continue using default setting. + // + return EFI_SUCCESS; + } + + DEBUG ((DEBUG_INFO, "EmmcSetBusMode: HsTiming %d ClockFreq %d BusWidth %d Ddr %a\n", HsTiming, ClockFreq, BusWidth, IsDdr ? "TRUE":"FALSE")); + + if (HsTiming == 3) { + // + // Execute HS400 timing switch procedure + // + Status = EmmcSwitchToHS400 (PciIo, PassThru, Slot, Rca, ClockFreq); + } else if (HsTiming == 2) { + // + // Execute HS200 timing switch procedure + // + Status = EmmcSwitchToHS200 (PciIo, PassThru, Slot, Rca, ClockFreq, BusWidth); + } else { + // + // Execute High Speed timing switch procedure + // + Status = EmmcSwitchToHighSpeed (PciIo, PassThru, Slot, Rca, ClockFreq, IsDdr, BusWidth); + } + + DEBUG ((DEBUG_INFO, "EmmcSetBusMode: Switch to %a %r\n", (HsTiming == 3) ? "HS400" : ((HsTiming == 2) ? "HS200" : "HighSpeed"), Status)); + + return Status; +} + +/** + Execute EMMC device identification procedure. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details. + + @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance. + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS There is a EMMC card. + @retval Others There is not a EMMC card. + +**/ +EFI_STATUS +EmmcIdentification ( + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN UINT8 Slot + ) +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru; + UINT32 Ocr; + UINT16 Rca; + + PciIo = Private->PciIo; + PassThru = &Private->PassThru; + + Status = EmmcReset (PassThru, Slot); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_VERBOSE, "EmmcIdentification: Executing Cmd0 fails with %r\n", Status)); + return Status; + } + + Ocr = 0; + do { + Status = EmmcGetOcr (PassThru, Slot, &Ocr); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_VERBOSE, "EmmcIdentification: Executing Cmd1 fails with %r\n", Status)); + return Status; + } + Ocr |= BIT30; + } while ((Ocr & BIT31) == 0); + + Status = EmmcGetAllCid (PassThru, Slot); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_VERBOSE, "EmmcIdentification: Executing Cmd2 fails with %r\n", Status)); + return Status; + } + // + // Slot starts from 0 and valid RCA starts from 1. + // Here we takes a simple formula to calculate the RCA. + // Don't support multiple devices on the slot, that is + // shared bus slot feature. + // + Rca = Slot + 1; + Status = EmmcSetRca (PassThru, Slot, Rca); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "EmmcIdentification: Executing Cmd3 fails with %r\n", Status)); + return Status; + } + // + // Enter Data Tranfer Mode. + // + DEBUG ((DEBUG_INFO, "EmmcIdentification: Found a EMMC device at slot [%d], RCA [%d]\n", Slot, Rca)); + Private->Slot[Slot].CardType = EmmcCardType; + + Status = EmmcSetBusMode (PciIo, PassThru, Slot, Rca); + + return Status; +} + diff --git a/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdDevice.c b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdDevice.c new file mode 100644 index 0000000000..9122848021 --- /dev/null +++ b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdDevice.c @@ -0,0 +1,1190 @@ +/** @file + This file provides some helper functions which are specific for SD card device. + + Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "SdMmcPciHcDxe.h" + +/** + Send command GO_IDLE_STATE to the device to make it go to Idle State. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS The SD device is reset correctly. + @retval Others The device reset fails. + +**/ +EFI_STATUS +SdCardReset ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_GO_IDLE_STATE; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBc; + + Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); + + return Status; +} + +/** + Send command SEND_IF_COND to the device to inquiry the SD Memory Card interface + condition. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] SupplyVoltage The supplied voltage by the host. + @param[in] CheckPattern The check pattern to be sent to the device. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardVoltageCheck ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + IN UINT8 SupplyVoltage, + IN UINT8 CheckPattern + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_SEND_IF_COND; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR7; + SdMmcCmdBlk.CommandArgument = (SupplyVoltage << 8) | CheckPattern; + + Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); + + if (!EFI_ERROR (Status)) { + if (SdMmcStatusBlk.Resp0 != SdMmcCmdBlk.CommandArgument) { + return EFI_DEVICE_ERROR; + } + } + + return Status; +} + +/** + Send command SDIO_SEND_OP_COND to the device to see whether it is SDIO device. + + Refer to SDIO Simplified Spec 3 Section 3.2 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] VoltageWindow The supply voltage window. + @param[in] S18R The boolean to show if it should switch to 1.8v. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdioSendOpCond ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + IN UINT32 VoltageWindow, + IN BOOLEAN S18R + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + UINT32 Switch; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SDIO_SEND_OP_COND; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR4; + + Switch = S18R ? BIT24 : 0; + + SdMmcCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch; + + Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); + + return Status; +} + +/** + Send command SD_SEND_OP_COND to the device to see whether it is SDIO device. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Rca The relative device address of addressed device. + @param[in] VoltageWindow The supply voltage window. + @param[in] S18R The boolean to show if it should switch to 1.8v. + @param[in] Xpc The boolean to show if it should provide 0.36w power control. + @param[in] Hcs The boolean to show if it support host capacity info. + @param[out] Ocr The buffer to store returned OCR register value. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardSendOpCond ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + IN UINT16 Rca, + IN UINT32 VoltageWindow, + IN BOOLEAN S18R, + IN BOOLEAN Xpc, + IN BOOLEAN Hcs, + OUT UINT32 *Ocr + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + UINT32 Switch; + UINT32 MaxPower; + UINT32 HostCapacity; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_APP_CMD; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + SdMmcCmdBlk.CommandIndex = SD_SEND_OP_COND; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR3; + + Switch = S18R ? BIT24 : 0; + MaxPower = Xpc ? BIT28 : 0; + HostCapacity = Hcs ? BIT30 : 0; + + SdMmcCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch | MaxPower | HostCapacity; + + Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); + if (!EFI_ERROR (Status)) { + // + // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12. + // + *Ocr = SdMmcStatusBlk.Resp0; + } + + return Status; +} + +/** + Broadcast command ALL_SEND_CID to the bus to ask all the SD devices to send the + data of their CID registers. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardAllSendCid ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_ALL_SEND_CID; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2; + + Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); + + return Status; +} + +/** + Send command SET_RELATIVE_ADDR to the SD device to assign a Relative device + Address (RCA). + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[out] Rca The relative device address to assign. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardSetRca ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + OUT UINT16 *Rca + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR6; + + Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); + if (!EFI_ERROR (Status)) { + *Rca = (UINT16)(SdMmcStatusBlk.Resp0 >> 16); + } + + return Status; +} + +/** + Send command SEND_CSD to the SD device to get the data of the CSD register. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Rca The relative device address of selected device. + @param[out] Csd The buffer to store the content of the CSD register. + Note the caller should ignore the lowest byte of this + buffer as the content of this byte is meaningless even + if the operation succeeds. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardGetCsd ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + IN UINT16 Rca, + OUT SD_CSD *Csd + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_SEND_CSD; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2; + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); + if (!EFI_ERROR (Status)) { + // + // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12. + // + CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CSD) - 1); + } + + return Status; +} + +/** + Send command SEND_CSD to the SD device to get the data of the CSD register. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Rca The relative device address of selected device. + @param[out] Scr The buffer to store the content of the SCR register. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardGetScr ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + IN UINT16 Rca, + OUT SD_SCR *Scr + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_APP_CMD; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + SdMmcCmdBlk.CommandIndex = SD_SEND_SCR; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + + Packet.InDataBuffer = Scr; + Packet.InTransferLength = sizeof (SD_SCR); + + Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); + + return Status; +} + +/** + Send command SELECT_DESELECT_CARD to the SD device to select/deselect it. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Rca The relative device address of selected device. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardSelect ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + IN UINT16 Rca + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + if (Rca != 0) { + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b; + } + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); + + return Status; +} + +/** + Send command VOLTAGE_SWITCH to the SD device to switch the voltage of the device. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardVoltageSwitch ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_VOLTAGE_SWITCH; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + SdMmcCmdBlk.CommandArgument = 0; + + Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); + + return Status; +} + +/** + Send command SET_BUS_WIDTH to the SD device to set the bus width. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Rca The relative device address of addressed device. + @param[in] BusWidth The bus width to be set, it could be 1 or 4. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardSetBusWidth ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + IN UINT16 Rca, + IN UINT8 BusWidth + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + UINT8 Value; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_APP_CMD; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + SdMmcCmdBlk.CommandIndex = SD_SET_BUS_WIDTH; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + + if (BusWidth == 1) { + Value = 0; + } else if (BusWidth == 4) { + Value = 2; + } else { + return EFI_INVALID_PARAMETER; + } + + SdMmcCmdBlk.CommandArgument = Value & 0x3; + + Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); + return Status; +} + +/** + Send command SWITCH_FUNC to the SD device to check switchable function or switch card function. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] AccessMode The value for access mode group. + @param[in] CommandSystem The value for command set group. + @param[in] DriveStrength The value for drive length group. + @param[in] PowerLimit The value for power limit group. + @param[in] Mode Switch or check function. + @param[out] SwitchResp The return switch function status. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardSwitch ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + IN UINT8 AccessMode, + IN UINT8 CommandSystem, + IN UINT8 DriveStrength, + IN UINT8 PowerLimit, + IN BOOLEAN Mode, + OUT UINT8 *SwitchResp + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + UINT32 ModeValue; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_SWITCH_FUNC; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + + ModeValue = Mode ? BIT31 : 0; + SdMmcCmdBlk.CommandArgument = (AccessMode & 0xF) | ((PowerLimit & 0xF) << 4) | \ + ((DriveStrength & 0xF) << 8) | ((DriveStrength & 0xF) << 12) | \ + ModeValue; + + Packet.InDataBuffer = SwitchResp; + Packet.InTransferLength = 64; + + Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); + + return Status; +} + +/** + Send command SEND_STATUS to the addressed SD device to get its status register. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Rca The relative device address of addressed device. + @param[out] DevStatus The returned device status. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardSendStatus ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + IN UINT16 Rca, + OUT UINT32 *DevStatus + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_SEND_STATUS; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); + if (!EFI_ERROR (Status)) { + *DevStatus = SdMmcStatusBlk.Resp0; + } + + return Status; +} + +/** + Send command SEND_TUNING_BLOCK to the SD device for HS200 optimal sampling point + detection. + + It may be sent up to 40 times until the host finishes the tuning procedure. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardSendTuningBlk ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + UINT8 TuningBlock[64]; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_SEND_TUNING_BLOCK; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + SdMmcCmdBlk.CommandArgument = 0; + + Packet.InDataBuffer = TuningBlock; + Packet.InTransferLength = sizeof (TuningBlock); + + Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); + + return Status; +} + +/** + Tunning the sampling point of SDR104 or SDR50 bus speed mode. + + Command SD_SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes the + tuning procedure. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and + SD Host Controller Simplified Spec 3.0 section Figure 3-7 for details. + + @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardTuningClock ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot + ) +{ + EFI_STATUS Status; + UINT8 HostCtrl2; + UINT8 Retry; + + // + // Notify the host that the sampling clock tuning procedure starts. + // + HostCtrl2 = BIT6; + Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Ask the device to send a sequence of tuning blocks till the tuning procedure is done. + // + Retry = 0; + do { + Status = SdCardSendTuningBlk (PassThru, Slot); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SdCardSendTuningBlk: Send tuning block fails with %r\n", Status)); + return Status; + } + + Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((HostCtrl2 & (BIT6 | BIT7)) == 0) { + break; + } + if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) { + return EFI_SUCCESS; + } + } while (++Retry < 40); + + DEBUG ((DEBUG_ERROR, "SdCardTuningClock: Send tuning block fails at %d times with HostCtrl2 %02x\n", Retry, HostCtrl2)); + // + // Abort the tuning procedure and reset the tuning circuit. + // + HostCtrl2 = (UINT8)~(BIT6 | BIT7); + Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + return EFI_DEVICE_ERROR; +} + +/** + Switch the bus width to specified width. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and + SD Host Controller Simplified Spec 3.0 section Figure 3-7 for details. + + @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Rca The relative device address to be assigned. + @param[in] BusWidth The bus width to be set, it could be 4 or 8. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardSwitchBusWidth ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + IN UINT16 Rca, + IN UINT8 BusWidth + ) +{ + EFI_STATUS Status; + UINT32 DevStatus; + + Status = SdCardSetBusWidth (PassThru, Slot, Rca, BusWidth); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SdCardSwitchBusWidth: Switch to bus width %d fails with %r\n", BusWidth, Status)); + return Status; + } + + Status = SdCardSendStatus (PassThru, Slot, Rca, &DevStatus); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SdCardSwitchBusWidth: Send status fails with %r\n", Status)); + return Status; + } + // + // Check the switch operation is really successful or not. + // + if ((DevStatus >> 16) != 0) { + DEBUG ((DEBUG_ERROR, "SdCardSwitchBusWidth: The switch operation fails as DevStatus is 0x%08x\n", DevStatus)); + return EFI_DEVICE_ERROR; + } + + Status = SdMmcHcSetBusWidth (PciIo, Slot, BusWidth); + + return Status; +} + +/** + Switch the high speed timing according to request. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and + SD Host Controller Simplified Spec 3.0 section Figure 2-29 for details. + + @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Rca The relative device address to be assigned. + @param[in] S18A The boolean to show if it's a UHS-I SD card. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardSetBusMode ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + IN UINT16 Rca, + IN BOOLEAN S18A + ) +{ + EFI_STATUS Status; + SD_MMC_HC_SLOT_CAP *Capability; + UINT32 ClockFreq; + UINT8 BusWidth; + UINT8 AccessMode; + UINT8 HostCtrl1; + UINT8 HostCtrl2; + UINT8 SwitchResp[64]; + SD_MMC_HC_PRIVATE_DATA *Private; + + Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru); + + Capability = &Private->Capability[Slot]; + + Status = SdCardSelect (PassThru, Slot, Rca); + if (EFI_ERROR (Status)) { + return Status; + } + + BusWidth = 4; + + Status = SdCardSwitchBusWidth (PciIo, PassThru, Slot, Rca, BusWidth); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Get the supported bus speed from SWITCH cmd return data group #1. + // + Status = SdCardSwitch (PassThru, Slot, 0xF, 0xF, 0xF, 0xF, FALSE, SwitchResp); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Calculate supported bus speed/bus width/clock frequency by host and device capability. + // + ClockFreq = 0; + if (S18A && (Capability->Sdr104 != 0) && ((SwitchResp[13] & BIT3) != 0)) { + ClockFreq = 208; + AccessMode = 3; + } else if (S18A && (Capability->Sdr50 != 0) && ((SwitchResp[13] & BIT2) != 0)) { + ClockFreq = 100; + AccessMode = 2; + } else if (S18A && (Capability->Ddr50 != 0) && ((SwitchResp[13] & BIT4) != 0)) { + ClockFreq = 50; + AccessMode = 4; + } else if ((SwitchResp[13] & BIT1) != 0) { + ClockFreq = 50; + AccessMode = 1; + } else { + ClockFreq = 25; + AccessMode = 0; + } + + Status = SdCardSwitch (PassThru, Slot, AccessMode, 0xF, 0xF, 0xF, TRUE, SwitchResp); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((SwitchResp[16] & 0xF) != AccessMode) { + DEBUG ((DEBUG_ERROR, "SdCardSetBusMode: Switch to AccessMode %d ClockFreq %d BusWidth %d fails! The Switch response is 0x%1x\n", AccessMode, ClockFreq, BusWidth, SwitchResp[16] & 0xF)); + return EFI_DEVICE_ERROR; + } + + DEBUG ((DEBUG_INFO, "SdCardSetBusMode: Switch to AccessMode %d ClockFreq %d BusWidth %d\n", AccessMode, ClockFreq, BusWidth)); + + // + // Set to Hight Speed timing + // + if (AccessMode == 1) { + HostCtrl1 = BIT2; + Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1); + if (EFI_ERROR (Status)) { + return Status; + } + } + + HostCtrl2 = (UINT8)~0x7; + Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + HostCtrl2 = AccessMode; + Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = SdMmcHcClockSupply (PciIo, Slot, ClockFreq * 1000, *Capability); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((AccessMode == 3) || ((AccessMode == 2) && (Capability->TuningSDR50 != 0))) { + Status = SdCardTuningClock (PciIo, PassThru, Slot); + if (EFI_ERROR (Status)) { + return Status; + } + } + + return Status; +} + +/** + Execute SD device identification procedure. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 3.6 for details. + + @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance. + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS There is a SD card. + @retval Others There is not a SD card. + +**/ +EFI_STATUS +SdCardIdentification ( + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN UINT8 Slot + ) +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru; + UINT32 Ocr; + UINT16 Rca; + BOOLEAN Xpc; + BOOLEAN S18r; + UINT64 MaxCurrent; + UINT16 ControllerVer; + UINT8 PowerCtrl; + UINT32 PresentState; + UINT8 HostCtrl2; + + PciIo = Private->PciIo; + PassThru = &Private->PassThru; + // + // 1. Send Cmd0 to the device + // + Status = SdCardReset (PassThru, Slot); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "SdCardIdentification: Executing Cmd0 fails with %r\n", Status)); + return Status; + } + // + // 2. Send Cmd8 to the device + // + Status = SdCardVoltageCheck (PassThru, Slot, 0x1, 0xFF); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "SdCardIdentification: Executing Cmd8 fails with %r\n", Status)); + return Status; + } + // + // 3. Send SDIO Cmd5 to the device to the SDIO device OCR register. + // + Status = SdioSendOpCond (PassThru, Slot, 0, FALSE); + if (!EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "SdCardIdentification: Found SDIO device, ignore it as we don't support\n")); + return EFI_DEVICE_ERROR; + } + // + // 4. Send Acmd41 with voltage window 0 to the device + // + Status = SdCardSendOpCond (PassThru, Slot, 0, 0, FALSE, FALSE, FALSE, &Ocr); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "SdCardIdentification: Executing SdCardSendOpCond fails with %r\n", Status)); + return EFI_DEVICE_ERROR; + } + + if (Private->Capability[Slot].Voltage33 != 0) { + // + // Support 3.3V + // + MaxCurrent = ((UINT32)Private->MaxCurrent[Slot] & 0xFF) * 4; + } else if (Private->Capability[Slot].Voltage30 != 0) { + // + // Support 3.0V + // + MaxCurrent = (((UINT32)Private->MaxCurrent[Slot] >> 8) & 0xFF) * 4; + } else if (Private->Capability[Slot].Voltage18 != 0) { + // + // Support 1.8V + // + MaxCurrent = (((UINT32)Private->MaxCurrent[Slot] >> 16) & 0xFF) * 4; + } else { + ASSERT (FALSE); + return EFI_DEVICE_ERROR; + } + + if (MaxCurrent >= 150) { + Xpc = TRUE; + } else { + Xpc = FALSE; + } + + Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((ControllerVer & 0xFF) == 2) { + S18r = TRUE; + } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) { + S18r = FALSE; + } else { + ASSERT (FALSE); + return EFI_UNSUPPORTED; + } + // + // 5. Repeatly send Acmd41 with supply voltage window to the device. + // Note here we only support the cards complied with SD physical + // layer simplified spec version 2.0 and version 3.0 and above. + // + do { + Status = SdCardSendOpCond (PassThru, Slot, 0, Ocr, S18r, Xpc, TRUE, &Ocr); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SdCardIdentification: SdCardSendOpCond fails with %r Ocr %x, S18r %x, Xpc %x\n", Status, Ocr, S18r, Xpc)); + return EFI_DEVICE_ERROR; + } + } while ((Ocr & BIT31) == 0); + + // + // 6. If the S18A bit is set and the Host Controller supports 1.8V signaling + // (One of support bits is set to 1: SDR50, SDR104 or DDR50 in the + // Capabilities register), switch its voltage to 1.8V. + // + if ((Private->Capability[Slot].Sdr50 != 0 || + Private->Capability[Slot].Sdr104 != 0 || + Private->Capability[Slot].Ddr50 != 0) && + ((Ocr & BIT24) != 0)) { + Status = SdCardVoltageSwitch (PassThru, Slot); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SdCardIdentification: Executing SdCardVoltageSwitch fails with %r\n", Status)); + Status = EFI_DEVICE_ERROR; + goto Error; + } else { + Status = SdMmcHcStopClock (PciIo, Slot); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto Error; + } + + SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState); + if (((PresentState >> 20) & 0xF) != 0) { + DEBUG ((DEBUG_ERROR, "SdCardIdentification: SwitchVoltage fails with PresentState = 0x%x\n", PresentState)); + Status = EFI_DEVICE_ERROR; + goto Error; + } + HostCtrl2 = BIT3; + SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + + gBS->Stall (5000); + + SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2); + if ((HostCtrl2 & BIT3) == 0) { + DEBUG ((DEBUG_ERROR, "SdCardIdentification: SwitchVoltage fails with HostCtrl2 = 0x%x\n", HostCtrl2)); + Status = EFI_DEVICE_ERROR; + goto Error; + } + + SdMmcHcInitClockFreq (PciIo, Slot, Private->Capability[Slot]); + + gBS->Stall (1000); + + SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState); + if (((PresentState >> 20) & 0xF) != 0xF) { + DEBUG ((DEBUG_ERROR, "SdCardIdentification: SwitchVoltage fails with PresentState = 0x%x, It should be 0xF\n", PresentState)); + Status = EFI_DEVICE_ERROR; + goto Error; + } + } + DEBUG ((DEBUG_INFO, "SdCardIdentification: Switch to 1.8v signal voltage success\n")); + } + + Status = SdCardAllSendCid (PassThru, Slot); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SdCardIdentification: Executing SdCardAllSendCid fails with %r\n", Status)); + return Status; + } + + Status = SdCardSetRca (PassThru, Slot, &Rca); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SdCardIdentification: Executing SdCardSetRca fails with %r\n", Status)); + return Status; + } + // + // Enter Data Tranfer Mode. + // + DEBUG ((DEBUG_INFO, "SdCardIdentification: Found a SD device at slot [%d]\n", Slot)); + Private->Slot[Slot].CardType = SdCardType; + + Status = SdCardSetBusMode (PciIo, PassThru, Slot, Rca, ((Ocr & BIT24) != 0)); + + return Status; + +Error: + // + // Set SD Bus Power = 0 + // + PowerCtrl = (UINT8)~BIT0; + Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_POWER_CTRL, sizeof (PowerCtrl), &PowerCtrl); + return EFI_DEVICE_ERROR; +} + diff --git a/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.c b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.c new file mode 100644 index 0000000000..981eab58ec --- /dev/null +++ b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.c @@ -0,0 +1,1315 @@ +/** @file + This driver is used to manage SD/MMC PCI host controllers which are compliance + with SD Host Controller Simplified Specification version 3.00. + + It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use. + + Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.
+ Copyright (C) 2016 Marvell International Ltd. All rigths 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 "SdMmcPciHcDxe.h" +#include "XenonSdhci.h" + +// +// Driver Global Variables +// +EFI_DRIVER_BINDING_PROTOCOL gSdMmcPciHcDriverBinding = { + SdMmcPciHcDriverBindingSupported, + SdMmcPciHcDriverBindingStart, + SdMmcPciHcDriverBindingStop, + 0x10, + NULL, + NULL +}; + +// +// Template for SD/MMC host controller private data. +// +SD_MMC_HC_PRIVATE_DATA gSdMmcPciHcTemplate = { + SD_MMC_HC_PRIVATE_SIGNATURE, // Signature + NULL, // ControllerHandle + NULL, // PciIo + { // PassThru + sizeof (UINT32), + SdMmcPassThruPassThru, + SdMmcPassThruGetNextSlot, + SdMmcPassThruBuildDevicePath, + SdMmcPassThruGetSlotNumber, + SdMmcPassThruResetDevice + }, + 0, // PciAttributes + 0, // PreviousSlot + NULL, // TimerEvent + NULL, // ConnectEvent + // Queue + INITIALIZE_LIST_HEAD_VARIABLE (gSdMmcPciHcTemplate.Queue), + { // Slot + {0, UnknownSlot, 0, 0, 0}, {0, UnknownSlot, 0, 0, 0}, {0, UnknownSlot, 0, 0, 0}, + {0, UnknownSlot, 0, 0, 0}, {0, UnknownSlot, 0, 0, 0}, {0, UnknownSlot, 0, 0, 0} + }, + { // Capability + {0}, + }, + { // MaxCurrent + 0, + }, + 0 // ControllerVersion +}; + +SD_DEVICE_PATH mSdDpTemplate = { + { + MESSAGING_DEVICE_PATH, + MSG_SD_DP, + { + (UINT8) (sizeof (SD_DEVICE_PATH)), + (UINT8) ((sizeof (SD_DEVICE_PATH)) >> 8) + } + }, + 0 +}; + +EMMC_DEVICE_PATH mEmmcDpTemplate = { + { + MESSAGING_DEVICE_PATH, + MSG_EMMC_DP, + { + (UINT8) (sizeof (EMMC_DEVICE_PATH)), + (UINT8) ((sizeof (EMMC_DEVICE_PATH)) >> 8) + } + }, + 0 +}; + +// +// Prioritized function list to detect card type. +// User could add other card detection logic here. +// +CARD_TYPE_DETECT_ROUTINE mCardTypeDetectRoutineTable[] = { + EmmcIdentification, + SdCardIdentification, + NULL +}; + +/** + The entry point for SD host controller driver, used to install this driver on the ImageHandle. + + @param[in] ImageHandle The firmware allocated handle for this driver image. + @param[in] SystemTable Pointer to the EFI system table. + + @retval EFI_SUCCESS Driver loaded. + @retval other Driver not loaded. + +**/ +EFI_STATUS +EFIAPI +InitializeSdMmcPciHcDxe ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gSdMmcPciHcDriverBinding, + ImageHandle, + &gSdMmcPciHcComponentName, + &gSdMmcPciHcComponentName2 + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + Call back function when the timer event is signaled. + + @param[in] Event The Event this notify function registered to. + @param[in] Context Pointer to the context data registered to the + Event. + +**/ +VOID +EFIAPI +ProcessAsyncTaskList ( + IN EFI_EVENT Event, + IN VOID* Context + ) +{ + SD_MMC_HC_PRIVATE_DATA *Private; + LIST_ENTRY *Link; + SD_MMC_HC_TRB *Trb; + EFI_STATUS Status; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet; + BOOLEAN InfiniteWait; + EFI_EVENT TrbEvent; + + Private = (SD_MMC_HC_PRIVATE_DATA*)Context; + + // + // Check if the first entry in the async I/O queue is done or not. + // + Status = EFI_SUCCESS; + Trb = NULL; + Link = GetFirstNode (&Private->Queue); + if (!IsNull (&Private->Queue, Link)) { + Trb = SD_MMC_HC_TRB_FROM_THIS (Link); + if (!Private->Slot[Trb->Slot].MediaPresent) { + Status = EFI_NO_MEDIA; + goto Done; + } + if (!Trb->Started) { + // + // Check whether the cmd/data line is ready for transfer. + // + Status = SdMmcCheckTrbEnv (Private, Trb); + if (!EFI_ERROR (Status)) { + Trb->Started = TRUE; + Status = SdMmcExecTrb (Private, Trb); + if (EFI_ERROR (Status)) { + goto Done; + } + } else { + goto Done; + } + } + Status = SdMmcCheckTrbResult (Private, Trb); + } + +Done: + if ((Trb != NULL) && (Status == EFI_NOT_READY)) { + Packet = Trb->Packet; + if (Packet->Timeout == 0) { + InfiniteWait = TRUE; + } else { + InfiniteWait = FALSE; + } + if ((!InfiniteWait) && (Trb->Timeout-- == 0)) { + RemoveEntryList (Link); + Trb->Packet->TransactionStatus = EFI_TIMEOUT; + TrbEvent = Trb->Event; + SdMmcFreeTrb (Trb); + DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT\n", TrbEvent)); + gBS->SignalEvent (TrbEvent); + return; + } + } + if ((Trb != NULL) && (Status != EFI_NOT_READY)) { + RemoveEntryList (Link); + Trb->Packet->TransactionStatus = Status; + TrbEvent = Trb->Event; + SdMmcFreeTrb (Trb); + DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p with %r\n", TrbEvent, Status)); + gBS->SignalEvent (TrbEvent); + } + return; +} + +/** + Sd removable device enumeration callback function when the timer event is signaled. + + @param[in] Event The Event this notify function registered to. + @param[in] Context Pointer to the context data registered to the + Event. + +**/ +VOID +EFIAPI +SdMmcPciHcEnumerateDevice ( + IN EFI_EVENT Event, + IN VOID* Context + ) +{ + SD_MMC_HC_PRIVATE_DATA *Private; + EFI_STATUS Status; + UINT8 Slot; + BOOLEAN MediaPresent; + UINT32 RoutineNum; + CARD_TYPE_DETECT_ROUTINE *Routine; + UINTN Index; + LIST_ENTRY *Link; + LIST_ENTRY *NextLink; + SD_MMC_HC_TRB *Trb; + EFI_TPL OldTpl; + + Private = (SD_MMC_HC_PRIVATE_DATA*)Context; + + for (Slot = 0; Slot < SD_MMC_HC_MAX_SLOT; Slot++) { + if ((Private->Slot[Slot].Enable) && (Private->Slot[Slot].SlotType == RemovableSlot)) { + Status = SdMmcHcCardDetect (Private->PciIo, Slot, &MediaPresent); + if ((Status == EFI_MEDIA_CHANGED) && !MediaPresent) { + DEBUG ((DEBUG_INFO, "SdMmcPciHcEnumerateDevice: device disconnected at slot %d of pci %p\n", Slot, Private->PciIo)); + Private->Slot[Slot].MediaPresent = FALSE; + Private->Slot[Slot].Initialized = FALSE; + // + // Signal all async task events at the slot with EFI_NO_MEDIA status. + // + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + for (Link = GetFirstNode (&Private->Queue); + !IsNull (&Private->Queue, Link); + Link = NextLink) { + NextLink = GetNextNode (&Private->Queue, Link); + Trb = SD_MMC_HC_TRB_FROM_THIS (Link); + if (Trb->Slot == Slot) { + RemoveEntryList (Link); + Trb->Packet->TransactionStatus = EFI_NO_MEDIA; + gBS->SignalEvent (Trb->Event); + SdMmcFreeTrb (Trb); + } + } + gBS->RestoreTPL (OldTpl); + // + // Notify the upper layer the connect state change through ReinstallProtocolInterface. + // + gBS->ReinstallProtocolInterface ( + Private->ControllerHandle, + &gEfiSdMmcPassThruProtocolGuid, + &Private->PassThru, + &Private->PassThru + ); + } + if ((Status == EFI_MEDIA_CHANGED) && MediaPresent) { + DEBUG ((DEBUG_INFO, "SdMmcPciHcEnumerateDevice: device connected at slot %d of pci %p\n", Slot, Private->PciIo)); + // + // Reset the specified slot of the SD/MMC Pci Host Controller + // + Status = SdMmcHcReset (Private->PciIo, Slot); + if (EFI_ERROR (Status)) { + continue; + } + // + // Reinitialize slot and restart identification process for the new attached device + // + Status = SdMmcHcInitHost (Private->PciIo, Slot, Private->Capability[Slot]); + if (EFI_ERROR (Status)) { + continue; + } + + Private->Slot[Slot].MediaPresent = TRUE; + Private->Slot[Slot].Initialized = TRUE; + RoutineNum = sizeof (mCardTypeDetectRoutineTable) / sizeof (CARD_TYPE_DETECT_ROUTINE); + for (Index = 0; Index < RoutineNum; Index++) { + Routine = &mCardTypeDetectRoutineTable[Index]; + if (*Routine != NULL) { + Status = (*Routine) (Private, Slot); + if (!EFI_ERROR (Status)) { + break; + } + } + } + // + // This card doesn't get initialized correctly. + // + if (Index == RoutineNum) { + Private->Slot[Slot].Initialized = FALSE; + } + + // + // Notify the upper layer the connect state change through ReinstallProtocolInterface. + // + gBS->ReinstallProtocolInterface ( + Private->ControllerHandle, + &gEfiSdMmcPassThruProtocolGuid, + &Private->PassThru, + &Private->PassThru + ); + } + } + } + + return; +} +/** + Tests to see if this driver supports a given controller. If a child device is provided, + it further tests to see if this driver supports creating a handle for the specified child device. + + This function checks to see if the driver specified by This supports the device specified by + ControllerHandle. Drivers will typically use the device path attached to + ControllerHandle and/or the services from the bus I/O abstraction attached to + ControllerHandle to determine if the driver supports ControllerHandle. This function + may be called many times during platform initialization. In order to reduce boot times, the tests + performed by this function must be very small, and take as little time as possible to execute. This + function must not change the state of any hardware devices, and this function must be aware that the + device specified by ControllerHandle may already be managed by the same driver or a + different driver. This function must match its calls to AllocatePages() with FreePages(), + AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol(). + Since ControllerHandle may have been previously started by the same driver, if a protocol is + already in the opened state, then it must not be closed with CloseProtocol(). This is required + to guarantee the state of ControllerHandle is not modified by this function. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to test. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For bus drivers, if this parameter is not NULL, then + the bus driver must determine if the bus controller specified + by ControllerHandle and the child controller specified + by RemainingDevicePath are both supported by this + bus driver. + + @retval EFI_SUCCESS The device specified by ControllerHandle and + RemainingDevicePath is supported by the driver specified by This. + @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by the driver + specified by This. + @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by a different + driver or an application that requires exclusive access. + Currently not implemented. + @retval EFI_UNSUPPORTED The device specified by ControllerHandle and + RemainingDevicePath is not supported by the driver specified by This. +**/ +EFI_STATUS +EFIAPI +SdMmcPciHcDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_PCI_IO_PROTOCOL *PciIo; + PCI_TYPE00 PciData; + + PciIo = NULL; + ParentDevicePath = NULL; + + // + // SdPciHcDxe is a device driver, and should ingore the + // "RemainingDevicePath" according to EFI spec. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID *) &ParentDevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + // + // EFI_ALREADY_STARTED is also an error. + // + return Status; + } + // + // Close the protocol because we don't use it here. + // + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + // + // Now test the EfiPciIoProtocol. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Now further check the PCI header: Base class (offset 0x08) and + // Sub Class (offset 0x05). This controller should be an SD/MMC PCI + // Host Controller. + // + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint8, + 0, + sizeof (PciData), + &PciData + ); + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return EFI_UNSUPPORTED; + } + // + // Since we already got the PciData, we can close protocol to avoid to carry it + // on for multiple exit points. + // + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + // + // Examine SD PCI Host Controller PCI Configuration table fields. + // + if ((PciData.Hdr.ClassCode[2] == PCI_CLASS_SYSTEM_PERIPHERAL) && + (PciData.Hdr.ClassCode[1] == PCI_SUBCLASS_SD_HOST_CONTROLLER) && + ((PciData.Hdr.ClassCode[0] == 0x00) || (PciData.Hdr.ClassCode[0] == 0x01))) { + return EFI_SUCCESS; + } + + return EFI_UNSUPPORTED; +} + +/** + Starts a device controller or a bus controller. + + The Start() function is designed to be invoked from the EFI boot service ConnectController(). + As a result, much of the error checking on the parameters to Start() has been moved into this + common boot service. It is legal to call Start() from other locations, + but the following calling restrictions must be followed or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE. + 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned + EFI_DEVICE_PATH_PROTOCOL. + 3. Prior to calling Start(), the Supported() function for the driver specified by This must + have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to start. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For a bus driver, if this parameter is NULL, then handles + for all the children of Controller are created by this driver. + If this parameter is not NULL and the first Device Path Node is + not the End of Device Path Node, then only the handle for the + child device specified by the first Device Path Node of + RemainingDevicePath is created by this driver. + If the first Device Path Node of RemainingDevicePath is + the End of Device Path Node, no child handle is created by this + driver. + + @retval EFI_SUCCESS The device was started. + @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval Others The driver failded to start the device. + +**/ +EFI_STATUS +EFIAPI +SdMmcPciHcDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + SD_MMC_HC_PRIVATE_DATA *Private; + EFI_PCI_IO_PROTOCOL *PciIo; + UINT64 Supports; + UINT64 PciAttributes; + UINT8 Slot; + UINT8 Index; + CARD_TYPE_DETECT_ROUTINE *Routine; + UINT32 RoutineNum; + BOOLEAN Support64BitDma; + + DEBUG ((DEBUG_INFO, "SdMmcPciHcDriverBindingStart: Start\n")); + + // + // Open PCI I/O Protocol and save pointer to open protocol + // in private data area. + // + PciIo = NULL; + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Enable the SD Host Controller MMIO space + // + Private = NULL; + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationGet, + 0, + &PciAttributes + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationSupported, + 0, + &Supports + ); + + if (!EFI_ERROR (Status)) { + Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE; + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationEnable, + Supports, + NULL + ); + } else { + goto Done; + } + + Private = AllocateCopyPool (sizeof (SD_MMC_HC_PRIVATE_DATA), &gSdMmcPciHcTemplate); + if (Private == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + Private->ControllerHandle = Controller; + Private->PciIo = PciIo; + Private->PciAttributes = PciAttributes; + InitializeListHead (&Private->Queue); + + Support64BitDma = TRUE; + + // + // There is only one slot 0 on Xenon + // + Slot = 0; + Private->Slot[Slot].Enable = TRUE; + + Status = SdMmcHcGetCapability (PciIo, Slot, &Private->Capability[Slot]); + if (EFI_ERROR (Status)) { + return Status; + } + + Support64BitDma &= Private->Capability[Slot].SysBus64; + + // + // Override capabilities structure - only 4 Bit width bus is supported + // by HW and also force using SDR25 mode + // + Private->Capability[Slot].Sdr104 = 0; + Private->Capability[Slot].Ddr50 = 0; + Private->Capability[Slot].Sdr50 = 0; + Private->Capability[Slot].BusWidth8 = 0; + + if (Private->Capability[Slot].BaseClkFreq == 0) { + Private->Capability[Slot].BaseClkFreq = 0xff; + } + + DumpCapabilityReg (Slot, &Private->Capability[Slot]); + + Status = SdMmcHcGetMaxCurrent (PciIo, Slot, &Private->MaxCurrent[Slot]); + if (EFI_ERROR (Status)) { + return Status; + } + + Private->Slot[Slot].SlotType = Private->Capability[Slot].SlotType; + if ((Private->Slot[Slot].SlotType != RemovableSlot) && (Private->Slot[Slot].SlotType != EmbeddedSlot)) { + DEBUG ((DEBUG_INFO, "SdMmcPciHcDxe doesn't support the slot type [%d]!!!\n", Private->Slot[Slot].SlotType)); + return EFI_D_ERROR; + } + + // + // Perform Xenon-specific init sequence + // + XenonInit (Private); + + // + // Initialize HC timeout control + // + Status = SdMmcHcInitTimeoutCtrl (PciIo, Slot); + if (EFI_ERROR (Status)) { + return Status; + } + + Private->Slot[Slot].MediaPresent = TRUE; + Private->Slot[Slot].Initialized = TRUE; + RoutineNum = sizeof (mCardTypeDetectRoutineTable) / sizeof (CARD_TYPE_DETECT_ROUTINE); + for (Index = 0; Index < RoutineNum; Index++) { + Routine = &mCardTypeDetectRoutineTable[Index]; + if (*Routine != NULL) { + Status = (*Routine) (Private, Slot); + if (!EFI_ERROR (Status)) { + break; + } + } + } + // + // This card doesn't get initialized correctly. + // + if (Index == RoutineNum) { + Private->Slot[Slot].Initialized = FALSE; + } + + // + // Enable 64-bit DMA support in the PCI layer if this controller + // supports it. + // + if (Support64BitDma) { + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationEnable, + EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE, + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "SdMmcPciHcDriverBindingStart: failed to enable 64-bit DMA (%r)\n", Status)); + } + } + + // + // Start the asynchronous I/O monitor + // + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + ProcessAsyncTaskList, + Private, + &Private->TimerEvent + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = gBS->SetTimer (Private->TimerEvent, TimerPeriodic, SD_MMC_HC_ASYNC_TIMER); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Start the Sd removable device connection enumeration + // + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + SdMmcPciHcEnumerateDevice, + Private, + &Private->ConnectEvent + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = gBS->SetTimer (Private->ConnectEvent, TimerPeriodic, SD_MMC_HC_ENUM_TIMER); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = gBS->InstallMultipleProtocolInterfaces ( + &Controller, + &gEfiSdMmcPassThruProtocolGuid, + &(Private->PassThru), + NULL + ); + + DEBUG ((DEBUG_INFO, "SdMmcPciHcDriverBindingStart: %r End on %x\n", Status, Controller)); + +Done: + if (EFI_ERROR (Status)) { + if ((Private != NULL) && (Private->PciAttributes != 0)) { + // + // Restore original PCI attributes + // + PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationSet, + Private->PciAttributes, + NULL + ); + } + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + if ((Private != NULL) && (Private->TimerEvent != NULL)) { + gBS->CloseEvent (Private->TimerEvent); + } + + if ((Private != NULL) && (Private->ConnectEvent != NULL)) { + gBS->CloseEvent (Private->ConnectEvent); + } + + if (Private != NULL) { + FreePool (Private); + } + } + + return Status; +} + +/** + Stops a device controller or a bus controller. + + The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). + As a result, much of the error checking on the parameters to Stop() has been moved + into this common boot service. It is legal to call Stop() from other locations, + but the following calling restrictions must be followed or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this + same driver's Start() function. + 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid + EFI_HANDLE. In addition, all of these handles must have been created in this driver's + Start() function, and the Start() function must have called OpenProtocol() on + ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle A handle to the device being stopped. The handle must + support a bus specific I/O protocol for the driver + to use to stop the device. + @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer. + @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL + if NumberOfChildren is 0. + + @retval EFI_SUCCESS The device was stopped. + @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. + +**/ +EFI_STATUS +EFIAPI +SdMmcPciHcDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + EFI_STATUS Status; + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru; + SD_MMC_HC_PRIVATE_DATA *Private; + EFI_PCI_IO_PROTOCOL *PciIo; + LIST_ENTRY *Link; + LIST_ENTRY *NextLink; + SD_MMC_HC_TRB *Trb; + + DEBUG ((DEBUG_INFO, "SdMmcPciHcDriverBindingStop: Start\n")); + + Status = gBS->OpenProtocol ( + Controller, + &gEfiSdMmcPassThruProtocolGuid, + (VOID**) &PassThru, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru); + // + // Close Non-Blocking timer and free Task list. + // + if (Private->TimerEvent != NULL) { + gBS->CloseEvent (Private->TimerEvent); + Private->TimerEvent = NULL; + } + if (Private->ConnectEvent != NULL) { + gBS->CloseEvent (Private->ConnectEvent); + Private->ConnectEvent = NULL; + } + // + // As the timer is closed, there is no needs to use TPL lock to + // protect the critical region "queue". + // + for (Link = GetFirstNode (&Private->Queue); + !IsNull (&Private->Queue, Link); + Link = NextLink) { + NextLink = GetNextNode (&Private->Queue, Link); + RemoveEntryList (Link); + Trb = SD_MMC_HC_TRB_FROM_THIS (Link); + Trb->Packet->TransactionStatus = EFI_ABORTED; + gBS->SignalEvent (Trb->Event); + SdMmcFreeTrb (Trb); + } + + // + // Uninstall Block I/O protocol from the device handle + // + Status = gBS->UninstallProtocolInterface ( + Controller, + &gEfiSdMmcPassThruProtocolGuid, + &(Private->PassThru) + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + // + // Restore original PCI attributes + // + PciIo = Private->PciIo; + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationSet, + Private->PciAttributes, + NULL + ); + ASSERT_EFI_ERROR (Status); + + FreePool (Private); + + DEBUG ((DEBUG_INFO, "SdMmcPciHcDriverBindingStop: End with %r\n", Status)); + + return Status; +} + +/** + Sends SD command to an SD card that is attached to the SD controller. + + The PassThru() function sends the SD command specified by Packet to the SD card + specified by Slot. + + If Packet is successfully sent to the SD card, then EFI_SUCCESS is returned. + + If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is returned. + + If Slot is not in a valid range for the SD controller, then EFI_INVALID_PARAMETER + is returned. + + If Packet defines a data command but both InDataBuffer and OutDataBuffer are NULL, + EFI_INVALID_PARAMETER is returned. + + @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in,out] Packet A pointer to the SD command data structure. + @param[in] Event If Event is NULL, blocking I/O is performed. If Event is + not NULL, then nonblocking I/O is performed, and Event + will be signaled when the Packet completes. + + @retval EFI_SUCCESS The SD Command Packet was sent by the host. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SD + command Packet. + @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is invalid. + @retval EFI_INVALID_PARAMETER Packet defines a data command but both InDataBuffer and + OutDataBuffer are NULL. + @retval EFI_NO_MEDIA SD Device not present in the Slot. + @retval EFI_UNSUPPORTED The command described by the SD Command Packet is not + supported by the host controller. + @retval EFI_BAD_BUFFER_SIZE The InTransferLength or OutTransferLength exceeds the + limit supported by SD card ( i.e. if the number of bytes + exceed the Last LBA). + +**/ +EFI_STATUS +EFIAPI +SdMmcPassThruPassThru ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, + IN UINT8 Slot, + IN OUT EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet, + IN EFI_EVENT Event OPTIONAL + ) +{ + EFI_STATUS Status; + SD_MMC_HC_PRIVATE_DATA *Private; + SD_MMC_HC_TRB *Trb; + EFI_TPL OldTpl; + + if ((This == NULL) || (Packet == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((Packet->SdMmcCmdBlk == NULL) || (Packet->SdMmcStatusBlk == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((Packet->OutDataBuffer == NULL) && (Packet->OutTransferLength != 0)) { + return EFI_INVALID_PARAMETER; + } + + if ((Packet->InDataBuffer == NULL) && (Packet->InTransferLength != 0)) { + return EFI_INVALID_PARAMETER; + } + + Private = SD_MMC_HC_PRIVATE_FROM_THIS (This); + + if (!Private->Slot[Slot].Enable) { + return EFI_INVALID_PARAMETER; + } + + if (!Private->Slot[Slot].MediaPresent) { + return EFI_NO_MEDIA; + } + + if (!Private->Slot[Slot].Initialized) { + return EFI_DEVICE_ERROR; + } + + Trb = SdMmcCreateTrb (Private, Slot, Packet, Event); + if (Trb == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Immediately return for async I/O. + // + if (Event != NULL) { + return EFI_SUCCESS; + } + + // + // Wait async I/O list is empty before execute sync I/O operation. + // + while (TRUE) { + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + if (IsListEmpty (&Private->Queue)) { + gBS->RestoreTPL (OldTpl); + break; + } + gBS->RestoreTPL (OldTpl); + } + + Status = SdMmcWaitTrbEnv (Private, Trb); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = SdMmcExecTrb (Private, Trb); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = SdMmcWaitTrbResult (Private, Trb); + if (EFI_ERROR (Status)) { + goto Done; + } + +Done: + if ((Trb != NULL) && (Trb->AdmaDesc != NULL)) { + FreePages (Trb->AdmaDesc, Trb->AdmaPages); + } + + if (Trb != NULL) { + FreePool (Trb); + } + + return Status; +} + +/** + Used to retrieve next slot numbers supported by the SD controller. The function + returns information about all available slots (populated or not-populated). + + The GetNextSlot() function retrieves the next slot number on an SD controller. + If on input Slot is 0xFF, then the slot number of the first slot on the SD controller + is returned. + + If Slot is a slot number that was returned on a previous call to GetNextSlot(), then + the slot number of the next slot on the SD controller is returned. + + If Slot is not 0xFF and Slot was not returned on a previous call to GetNextSlot(), + EFI_INVALID_PARAMETER is returned. + + If Slot is the slot number of the last slot on the SD controller, then EFI_NOT_FOUND + is returned. + + @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL instance. + @param[in,out] Slot On input, a pointer to a slot number on the SD controller. + On output, a pointer to the next slot number on the SD controller. + An input value of 0xFF retrieves the first slot number on the SD + controller. + + @retval EFI_SUCCESS The next slot number on the SD controller was returned in Slot. + @retval EFI_NOT_FOUND There are no more slots on this SD controller. + @retval EFI_INVALID_PARAMETER Slot is not 0xFF and Slot was not returned on a previous call + to GetNextSlot(). + +**/ +EFI_STATUS +EFIAPI +SdMmcPassThruGetNextSlot ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, + IN OUT UINT8 *Slot + ) +{ + SD_MMC_HC_PRIVATE_DATA *Private; + UINT8 Index; + + if ((This == NULL) || (Slot == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Private = SD_MMC_HC_PRIVATE_FROM_THIS (This); + + if (*Slot == 0xFF) { + for (Index = 0; Index < SD_MMC_HC_MAX_SLOT; Index++) { + if (Private->Slot[Index].Enable) { + *Slot = Index; + Private->PreviousSlot = Index; + return EFI_SUCCESS; + } + } + return EFI_NOT_FOUND; + } else if (*Slot == Private->PreviousSlot) { + for (Index = *Slot + 1; Index < SD_MMC_HC_MAX_SLOT; Index++) { + if (Private->Slot[Index].Enable) { + *Slot = Index; + Private->PreviousSlot = Index; + return EFI_SUCCESS; + } + } + return EFI_NOT_FOUND; + } else { + return EFI_INVALID_PARAMETER; + } +} + +/** + Used to allocate and build a device path node for an SD card on the SD controller. + + The BuildDevicePath() function allocates and builds a single device node for the SD + card specified by Slot. + + If the SD card specified by Slot is not present on the SD controller, then EFI_NOT_FOUND + is returned. + + If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned. + + If there are not enough resources to allocate the device path node, then EFI_OUT_OF_RESOURCES + is returned. + + Otherwise, DevicePath is allocated with the boot service AllocatePool(), the contents of + DevicePath are initialized to describe the SD card specified by Slot, and EFI_SUCCESS is + returned. + + @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot Specifies the slot number of the SD card for which a device + path node is to be allocated and built. + @param[in,out] DevicePath A pointer to a single device path node that describes the SD + card specified by Slot. This function is responsible for + allocating the buffer DevicePath with the boot service + AllocatePool(). It is the caller's responsibility to free + DevicePath when the caller is finished with DevicePath. + + @retval EFI_SUCCESS The device path node that describes the SD card specified by + Slot was allocated and returned in DevicePath. + @retval EFI_NOT_FOUND The SD card specified by Slot does not exist on the SD controller. + @retval EFI_INVALID_PARAMETER DevicePath is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate DevicePath. + +**/ +EFI_STATUS +EFIAPI +SdMmcPassThruBuildDevicePath ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, + IN UINT8 Slot, + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath + ) +{ + SD_MMC_HC_PRIVATE_DATA *Private; + SD_DEVICE_PATH *SdNode; + EMMC_DEVICE_PATH *EmmcNode; + + if ((This == NULL) || (DevicePath == NULL) || (Slot >= SD_MMC_HC_MAX_SLOT)) { + return EFI_INVALID_PARAMETER; + } + + Private = SD_MMC_HC_PRIVATE_FROM_THIS (This); + + if ((!Private->Slot[Slot].Enable) || (!Private->Slot[Slot].MediaPresent)) { + return EFI_NOT_FOUND; + } + + if (Private->Slot[Slot].CardType == SdCardType) { + SdNode = AllocateCopyPool (sizeof (SD_DEVICE_PATH), &mSdDpTemplate); + if (SdNode == NULL) { + return EFI_OUT_OF_RESOURCES; + } + SdNode->SlotNumber = Slot; + + *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) SdNode; + } else if (Private->Slot[Slot].CardType == EmmcCardType) { + EmmcNode = AllocateCopyPool (sizeof (EMMC_DEVICE_PATH), &mEmmcDpTemplate); + if (EmmcNode == NULL) { + return EFI_OUT_OF_RESOURCES; + } + EmmcNode->SlotNumber = Slot; + + *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) EmmcNode; + } else { + // + // Currently we only support SD and EMMC two device nodes. + // + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + +/** + This function retrieves an SD card slot number based on the input device path. + + The GetSlotNumber() function retrieves slot number for the SD card specified by + the DevicePath node. If DevicePath is NULL, EFI_INVALID_PARAMETER is returned. + + If DevicePath is not a device path node type that the SD Pass Thru driver supports, + EFI_UNSUPPORTED is returned. + + @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] DevicePath A pointer to the device path node that describes a SD + card on the SD controller. + @param[out] Slot On return, points to the slot number of an SD card on + the SD controller. + + @retval EFI_SUCCESS SD card slot number is returned in Slot. + @retval EFI_INVALID_PARAMETER Slot or DevicePath is NULL. + @retval EFI_UNSUPPORTED DevicePath is not a device path node type that the SD + Pass Thru driver supports. + +**/ +EFI_STATUS +EFIAPI +SdMmcPassThruGetSlotNumber ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT UINT8 *Slot + ) +{ + SD_MMC_HC_PRIVATE_DATA *Private; + SD_DEVICE_PATH *SdNode; + EMMC_DEVICE_PATH *EmmcNode; + UINT8 SlotNumber; + + if ((This == NULL) || (DevicePath == NULL) || (Slot == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Private = SD_MMC_HC_PRIVATE_FROM_THIS (This); + + // + // Check whether the DevicePath belongs to SD_DEVICE_PATH or EMMC_DEVICE_PATH + // + if ((DevicePath->Type != MESSAGING_DEVICE_PATH) || + ((DevicePath->SubType != MSG_SD_DP) && + (DevicePath->SubType != MSG_EMMC_DP)) || + (DevicePathNodeLength(DevicePath) != sizeof(SD_DEVICE_PATH)) || + (DevicePathNodeLength(DevicePath) != sizeof(EMMC_DEVICE_PATH))) { + return EFI_UNSUPPORTED; + } + + if (DevicePath->SubType == MSG_SD_DP) { + SdNode = (SD_DEVICE_PATH *) DevicePath; + SlotNumber = SdNode->SlotNumber; + } else { + EmmcNode = (EMMC_DEVICE_PATH *) DevicePath; + SlotNumber = EmmcNode->SlotNumber; + } + + if (SlotNumber >= SD_MMC_HC_MAX_SLOT) { + return EFI_NOT_FOUND; + } + + if (Private->Slot[SlotNumber].Enable) { + *Slot = SlotNumber; + return EFI_SUCCESS; + } else { + return EFI_NOT_FOUND; + } +} + +/** + Resets an SD card that is connected to the SD controller. + + The ResetDevice() function resets the SD card specified by Slot. + + If this SD controller does not support a device reset operation, EFI_UNSUPPORTED is + returned. + + If Slot is not in a valid slot number for this SD controller, EFI_INVALID_PARAMETER + is returned. + + If the device reset operation is completed, EFI_SUCCESS is returned. + + @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot Specifies the slot number of the SD card to be reset. + + @retval EFI_SUCCESS The SD card specified by Slot was reset. + @retval EFI_UNSUPPORTED The SD controller does not support a device reset operation. + @retval EFI_INVALID_PARAMETER Slot number is invalid. + @retval EFI_NO_MEDIA SD Device not present in the Slot. + @retval EFI_DEVICE_ERROR The reset command failed due to a device error + +**/ +EFI_STATUS +EFIAPI +SdMmcPassThruResetDevice ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, + IN UINT8 Slot + ) +{ + SD_MMC_HC_PRIVATE_DATA *Private; + LIST_ENTRY *Link; + LIST_ENTRY *NextLink; + SD_MMC_HC_TRB *Trb; + EFI_TPL OldTpl; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + Private = SD_MMC_HC_PRIVATE_FROM_THIS (This); + + if (!Private->Slot[Slot].Enable) { + return EFI_INVALID_PARAMETER; + } + + if (!Private->Slot[Slot].MediaPresent) { + return EFI_NO_MEDIA; + } + + if (!Private->Slot[Slot].Initialized) { + return EFI_DEVICE_ERROR; + } + // + // Free all async I/O requests in the queue + // + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + + for (Link = GetFirstNode (&Private->Queue); + !IsNull (&Private->Queue, Link); + Link = NextLink) { + NextLink = GetNextNode (&Private->Queue, Link); + RemoveEntryList (Link); + Trb = SD_MMC_HC_TRB_FROM_THIS (Link); + Trb->Packet->TransactionStatus = EFI_ABORTED; + gBS->SignalEvent (Trb->Event); + SdMmcFreeTrb (Trb); + } + + gBS->RestoreTPL (OldTpl); + + return EFI_SUCCESS; +} + diff --git a/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.h b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.h new file mode 100644 index 0000000000..6a2a279699 --- /dev/null +++ b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.h @@ -0,0 +1,785 @@ +/** @file + + Provides some data structure definitions used by the SD/MMC host controller driver. + +Copyright (c) 2015, Intel Corporation. All rights reserved.
+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 + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "SdMmcPciHci.h" + +extern EFI_COMPONENT_NAME_PROTOCOL gSdMmcPciHcComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gSdMmcPciHcComponentName2; +extern EFI_DRIVER_BINDING_PROTOCOL gSdMmcPciHcDriverBinding; + +#define SD_MMC_HC_PRIVATE_SIGNATURE SIGNATURE_32 ('s', 'd', 't', 'f') + +#define SD_MMC_HC_PRIVATE_FROM_THIS(a) \ + CR(a, SD_MMC_HC_PRIVATE_DATA, PassThru, SD_MMC_HC_PRIVATE_SIGNATURE) + +// +// Generic time out value, 1 microsecond as unit. +// +#define SD_MMC_HC_GENERIC_TIMEOUT 1 * 1000 * 1000 + +// +// SD/MMC async transfer timer interval, set by experience. +// The unit is 100us, takes 1ms as interval. +// +#define SD_MMC_HC_ASYNC_TIMER EFI_TIMER_PERIOD_MILLISECONDS(1) +// +// SD/MMC removable device enumeration timer interval, set by experience. +// The unit is 100us, takes 100ms as interval. +// +#define SD_MMC_HC_ENUM_TIMER EFI_TIMER_PERIOD_MILLISECONDS(100) + +typedef enum { + UnknownCardType, + SdCardType, + SdioCardType, + MmcCardType, + EmmcCardType +} SD_MMC_CARD_TYPE; + +typedef enum { + RemovableSlot, + EmbeddedSlot, + SharedBusSlot, + UnknownSlot +} EFI_SD_MMC_SLOT_TYPE; + +typedef struct { + BOOLEAN Enable; + EFI_SD_MMC_SLOT_TYPE SlotType; + BOOLEAN MediaPresent; + BOOLEAN Initialized; + SD_MMC_CARD_TYPE CardType; +} SD_MMC_HC_SLOT; + +typedef struct { + UINTN Signature; + + EFI_HANDLE ControllerHandle; + EFI_PCI_IO_PROTOCOL *PciIo; + + EFI_SD_MMC_PASS_THRU_PROTOCOL PassThru; + + UINT64 PciAttributes; + // + // The field is used to record the previous slot in GetNextSlot(). + // + UINT8 PreviousSlot; + // + // For Non-blocking operation. + // + EFI_EVENT TimerEvent; + // + // For Sd removable device enumeration. + // + EFI_EVENT ConnectEvent; + LIST_ENTRY Queue; + + SD_MMC_HC_SLOT Slot[SD_MMC_HC_MAX_SLOT]; + SD_MMC_HC_SLOT_CAP Capability[SD_MMC_HC_MAX_SLOT]; + UINT64 MaxCurrent[SD_MMC_HC_MAX_SLOT]; + + UINT32 ControllerVersion; +} SD_MMC_HC_PRIVATE_DATA; + +#define SD_MMC_HC_TRB_SIG SIGNATURE_32 ('T', 'R', 'B', 'T') + +// +// TRB (Transfer Request Block) contains information for the cmd request. +// +typedef struct { + UINT32 Signature; + LIST_ENTRY TrbList; + + UINT8 Slot; + UINT16 BlockSize; + + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet; + VOID *Data; + UINT32 DataLen; + BOOLEAN Read; + EFI_PHYSICAL_ADDRESS DataPhy; + VOID *DataMap; + SD_MMC_HC_TRANSFER_MODE Mode; + + EFI_EVENT Event; + BOOLEAN Started; + UINT64 Timeout; + + SD_MMC_HC_ADMA_DESC_LINE *AdmaDesc; + EFI_PHYSICAL_ADDRESS AdmaDescPhy; + VOID *AdmaMap; + UINT32 AdmaPages; + + SD_MMC_HC_PRIVATE_DATA *Private; +} SD_MMC_HC_TRB; + +#define SD_MMC_HC_TRB_FROM_THIS(a) \ + CR(a, SD_MMC_HC_TRB, TrbList, SD_MMC_HC_TRB_SIG) + +// +// Task for Non-blocking mode. +// +typedef struct { + UINT32 Signature; + LIST_ENTRY Link; + + UINT8 Slot; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet; + BOOLEAN IsStart; + EFI_EVENT Event; + UINT64 RetryTimes; + BOOLEAN InfiniteWait; + VOID *Map; + VOID *MapAddress; +} SD_MMC_HC_QUEUE; + +// +// Prototypes +// +/** + Execute card identification procedure. + + @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance. + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS The card is identified correctly. + @retval Others The card can't be identified. + +**/ +typedef +EFI_STATUS +(*CARD_TYPE_DETECT_ROUTINE) ( + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN UINT8 Slot + ); + +/** + Sends SD command to an SD card that is attached to the SD controller. + + The PassThru() function sends the SD command specified by Packet to the SD card + specified by Slot. + + If Packet is successfully sent to the SD card, then EFI_SUCCESS is returned. + + If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is returned. + + If Slot is not in a valid range for the SD controller, then EFI_INVALID_PARAMETER + is returned. + + If Packet defines a data command but both InDataBuffer and OutDataBuffer are NULL, + EFI_INVALID_PARAMETER is returned. + + @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in,out] Packet A pointer to the SD command data structure. + @param[in] Event If Event is NULL, blocking I/O is performed. If Event is + not NULL, then nonblocking I/O is performed, and Event + will be signaled when the Packet completes. + + @retval EFI_SUCCESS The SD Command Packet was sent by the host. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SD + command Packet. + @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is invalid. + @retval EFI_INVALID_PARAMETER Packet defines a data command but both InDataBuffer and + OutDataBuffer are NULL. + @retval EFI_NO_MEDIA SD Device not present in the Slot. + @retval EFI_UNSUPPORTED The command described by the SD Command Packet is not + supported by the host controller. + @retval EFI_BAD_BUFFER_SIZE The InTransferLength or OutTransferLength exceeds the + limit supported by SD card ( i.e. if the number of bytes + exceed the Last LBA). + +**/ +EFI_STATUS +EFIAPI +SdMmcPassThruPassThru ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, + IN UINT8 Slot, + IN OUT EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet, + IN EFI_EVENT Event OPTIONAL + ); + +/** + Used to retrieve next slot numbers supported by the SD controller. The function + returns information about all available slots (populated or not-populated). + + The GetNextSlot() function retrieves the next slot number on an SD controller. + If on input Slot is 0xFF, then the slot number of the first slot on the SD controller + is returned. + + If Slot is a slot number that was returned on a previous call to GetNextSlot(), then + the slot number of the next slot on the SD controller is returned. + + If Slot is not 0xFF and Slot was not returned on a previous call to GetNextSlot(), + EFI_INVALID_PARAMETER is returned. + + If Slot is the slot number of the last slot on the SD controller, then EFI_NOT_FOUND + is returned. + + @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL instance. + @param[in,out] Slot On input, a pointer to a slot number on the SD controller. + On output, a pointer to the next slot number on the SD controller. + An input value of 0xFF retrieves the first slot number on the SD + controller. + + @retval EFI_SUCCESS The next slot number on the SD controller was returned in Slot. + @retval EFI_NOT_FOUND There are no more slots on this SD controller. + @retval EFI_INVALID_PARAMETER Slot is not 0xFF and Slot was not returned on a previous call + to GetNextSlot(). + +**/ +EFI_STATUS +EFIAPI +SdMmcPassThruGetNextSlot ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, + IN OUT UINT8 *Slot + ); + +/** + Used to allocate and build a device path node for an SD card on the SD controller. + + The BuildDevicePath() function allocates and builds a single device node for the SD + card specified by Slot. + + If the SD card specified by Slot is not present on the SD controller, then EFI_NOT_FOUND + is returned. + + If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned. + + If there are not enough resources to allocate the device path node, then EFI_OUT_OF_RESOURCES + is returned. + + Otherwise, DevicePath is allocated with the boot service AllocatePool(), the contents of + DevicePath are initialized to describe the SD card specified by Slot, and EFI_SUCCESS is + returned. + + @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot Specifies the slot number of the SD card for which a device + path node is to be allocated and built. + @param[in,out] DevicePath A pointer to a single device path node that describes the SD + card specified by Slot. This function is responsible for + allocating the buffer DevicePath with the boot service + AllocatePool(). It is the caller's responsibility to free + DevicePath when the caller is finished with DevicePath. + + @retval EFI_SUCCESS The device path node that describes the SD card specified by + Slot was allocated and returned in DevicePath. + @retval EFI_NOT_FOUND The SD card specified by Slot does not exist on the SD controller. + @retval EFI_INVALID_PARAMETER DevicePath is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate DevicePath. + +**/ +EFI_STATUS +EFIAPI +SdMmcPassThruBuildDevicePath ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, + IN UINT8 Slot, + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath + ); + +/** + This function retrieves an SD card slot number based on the input device path. + + The GetSlotNumber() function retrieves slot number for the SD card specified by + the DevicePath node. If DevicePath is NULL, EFI_INVALID_PARAMETER is returned. + + If DevicePath is not a device path node type that the SD Pass Thru driver supports, + EFI_UNSUPPORTED is returned. + + @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] DevicePath A pointer to the device path node that describes a SD + card on the SD controller. + @param[out] Slot On return, points to the slot number of an SD card on + the SD controller. + + @retval EFI_SUCCESS SD card slot number is returned in Slot. + @retval EFI_INVALID_PARAMETER Slot or DevicePath is NULL. + @retval EFI_UNSUPPORTED DevicePath is not a device path node type that the SD + Pass Thru driver supports. + +**/ +EFI_STATUS +EFIAPI +SdMmcPassThruGetSlotNumber ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT UINT8 *Slot + ); + +/** + Resets an SD card that is connected to the SD controller. + + The ResetDevice() function resets the SD card specified by Slot. + + If this SD controller does not support a device reset operation, EFI_UNSUPPORTED is + returned. + + If Slot is not in a valid slot number for this SD controller, EFI_INVALID_PARAMETER + is returned. + + If the device reset operation is completed, EFI_SUCCESS is returned. + + @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance. + @param[in] Slot Specifies the slot number of the SD card to be reset. + + @retval EFI_SUCCESS The SD card specified by Slot was reset. + @retval EFI_UNSUPPORTED The SD controller does not support a device reset operation. + @retval EFI_INVALID_PARAMETER Slot number is invalid. + @retval EFI_NO_MEDIA SD Device not present in the Slot. + @retval EFI_DEVICE_ERROR The reset command failed due to a device error + +**/ +EFI_STATUS +EFIAPI +SdMmcPassThruResetDevice ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, + IN UINT8 Slot + ); + +// +// Driver model protocol interfaces +// +/** + Tests to see if this driver supports a given controller. If a child device is provided, + it further tests to see if this driver supports creating a handle for the specified child device. + + This function checks to see if the driver specified by This supports the device specified by + ControllerHandle. Drivers will typically use the device path attached to + ControllerHandle and/or the services from the bus I/O abstraction attached to + ControllerHandle to determine if the driver supports ControllerHandle. This function + may be called many times during platform initialization. In order to reduce boot times, the tests + performed by this function must be very small, and take as little time as possible to execute. This + function must not change the state of any hardware devices, and this function must be aware that the + device specified by ControllerHandle may already be managed by the same driver or a + different driver. This function must match its calls to AllocatePages() with FreePages(), + AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol(). + Since ControllerHandle may have been previously started by the same driver, if a protocol is + already in the opened state, then it must not be closed with CloseProtocol(). This is required + to guarantee the state of ControllerHandle is not modified by this function. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to test. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For bus drivers, if this parameter is not NULL, then + the bus driver must determine if the bus controller specified + by ControllerHandle and the child controller specified + by RemainingDevicePath are both supported by this + bus driver. + + @retval EFI_SUCCESS The device specified by ControllerHandle and + RemainingDevicePath is supported by the driver specified by This. + @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by the driver + specified by This. + @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by a different + driver or an application that requires exclusive access. + Currently not implemented. + @retval EFI_UNSUPPORTED The device specified by ControllerHandle and + RemainingDevicePath is not supported by the driver specified by This. +**/ +EFI_STATUS +EFIAPI +SdMmcPciHcDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + Starts a device controller or a bus controller. + + The Start() function is designed to be invoked from the EFI boot service ConnectController(). + As a result, much of the error checking on the parameters to Start() has been moved into this + common boot service. It is legal to call Start() from other locations, + but the following calling restrictions must be followed or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE. + 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned + EFI_DEVICE_PATH_PROTOCOL. + 3. Prior to calling Start(), the Supported() function for the driver specified by This must + have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to start. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For a bus driver, if this parameter is NULL, then handles + for all the children of Controller are created by this driver. + If this parameter is not NULL and the first Device Path Node is + not the End of Device Path Node, then only the handle for the + child device specified by the first Device Path Node of + RemainingDevicePath is created by this driver. + If the first Device Path Node of RemainingDevicePath is + the End of Device Path Node, no child handle is created by this + driver. + + @retval EFI_SUCCESS The device was started. + @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval Others The driver failded to start the device. + +**/ +EFI_STATUS +EFIAPI +SdMmcPciHcDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + Stops a device controller or a bus controller. + + The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). + As a result, much of the error checking on the parameters to Stop() has been moved + into this common boot service. It is legal to call Stop() from other locations, + but the following calling restrictions must be followed or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this + same driver's Start() function. + 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid + EFI_HANDLE. In addition, all of these handles must have been created in this driver's + Start() function, and the Start() function must have called OpenProtocol() on + ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle A handle to the device being stopped. The handle must + support a bus specific I/O protocol for the driver + to use to stop the device. + @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer. + @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL + if NumberOfChildren is 0. + + @retval EFI_SUCCESS The device was stopped. + @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. + +**/ +EFI_STATUS +EFIAPI +SdMmcPciHcDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +// +// EFI Component Name Functions +// +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +SdMmcPciHcComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +SdMmcPciHcComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle, OPTIONAL + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +/** + Create a new TRB for the SD/MMC cmd request. + + @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Packet A pointer to the SD command data structure. + @param[in] Event If Event is NULL, blocking I/O is performed. If Event is + not NULL, then nonblocking I/O is performed, and Event + will be signaled when the Packet completes. + + @return Created Trb or NULL. + +**/ +SD_MMC_HC_TRB * +SdMmcCreateTrb ( + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN UINT8 Slot, + IN EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet, + IN EFI_EVENT Event + ); + +/** + Free the resource used by the TRB. + + @param[in] Trb The pointer to the SD_MMC_HC_TRB instance. + +**/ +VOID +SdMmcFreeTrb ( + IN SD_MMC_HC_TRB *Trb + ); + +/** + Check if the env is ready for execute specified TRB. + + @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance. + @param[in] Trb The pointer to the SD_MMC_HC_TRB instance. + + @retval EFI_SUCCESS The env is ready for TRB execution. + @retval EFI_NOT_READY The env is not ready for TRB execution. + @retval Others Some erros happen. + +**/ +EFI_STATUS +SdMmcCheckTrbEnv ( + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN SD_MMC_HC_TRB *Trb + ); + +/** + Wait for the env to be ready for execute specified TRB. + + @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance. + @param[in] Trb The pointer to the SD_MMC_HC_TRB instance. + + @retval EFI_SUCCESS The env is ready for TRB execution. + @retval EFI_TIMEOUT The env is not ready for TRB execution in time. + @retval Others Some erros happen. + +**/ +EFI_STATUS +SdMmcWaitTrbEnv ( + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN SD_MMC_HC_TRB *Trb + ); + +/** + Execute the specified TRB. + + @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance. + @param[in] Trb The pointer to the SD_MMC_HC_TRB instance. + + @retval EFI_SUCCESS The TRB is sent to host controller successfully. + @retval Others Some erros happen when sending this request to the host controller. + +**/ +EFI_STATUS +SdMmcExecTrb ( + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN SD_MMC_HC_TRB *Trb + ); + +/** + Check the TRB execution result. + + @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance. + @param[in] Trb The pointer to the SD_MMC_HC_TRB instance. + + @retval EFI_SUCCESS The TRB is executed successfully. + @retval EFI_NOT_READY The TRB is not completed for execution. + @retval Others Some erros happen when executing this request. + +**/ +EFI_STATUS +SdMmcCheckTrbResult ( + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN SD_MMC_HC_TRB *Trb + ); + +/** + Wait for the TRB execution result. + + @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance. + @param[in] Trb The pointer to the SD_MMC_HC_TRB instance. + + @retval EFI_SUCCESS The TRB is executed successfully. + @retval Others Some erros happen when executing this request. + +**/ +EFI_STATUS +SdMmcWaitTrbResult ( + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN SD_MMC_HC_TRB *Trb + ); + +/** + Execute EMMC device identification procedure. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details. + + @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance. + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS There is a EMMC card. + @retval Others There is not a EMMC card. + +**/ +EFI_STATUS +EmmcIdentification ( + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN UINT8 Slot + ); + +/** + Execute EMMC device identification procedure. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details. + + @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance. + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS There is a EMMC card. + @retval Others There is not a EMMC card. + +**/ +EFI_STATUS +SdCardIdentification ( + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN UINT8 Slot + ); + +#endif diff --git a/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.inf b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.inf new file mode 100644 index 0000000000..fad9fc610e --- /dev/null +++ b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.inf @@ -0,0 +1,64 @@ +## @file +# SdMmcPciHcDxe driver is used to manage those host controllers which comply with SD +# Host Controller Simplified Specifiction version 3.0. +# +# It will produce EFI_SD_MMC_PASS_THRU_PROTOCOL to allow sending SD/MMC/eMMC cmds +# to specified devices from upper layer. +# +# Copyright (c) 2015, Intel Corporation. All rights reserved.
+# 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. +# +# +## + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = XenonDxe + MODULE_UNI_FILE = SdMmcPciHcDxe.uni + FILE_GUID = 17f56b40-f7c1-435c-ab8d-404872da951e + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeSdMmcPciHcDxe + +[Sources] + ComponentName.c + EmmcDevice.c + SdDevice.c + SdMmcPciHcDxe.c + SdMmcPciHcDxe.h + SdMmcPciHci.c + SdMmcPciHci.h + XenonSdhci.c + XenonSdhci.h + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + DevicePathLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + UefiRuntimeServicesTableLib + +[Protocols] + gEfiDevicePathProtocolGuid ## TO_START + gEfiPciIoProtocolGuid ## TO_START + gEfiSdMmcPassThruProtocolGuid ## BY_START + +# [Event] +# EVENT_TYPE_PERIODIC_TIMER ## SOMETIMES_CONSUMES + +[UserExtensions.TianoCore."ExtraFiles"] + SdMmcPciHcDxeExtra.uni diff --git a/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.uni b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.uni new file mode 100644 index 0000000000..57f9fa76a1 --- /dev/null +++ b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxe.uni @@ -0,0 +1,23 @@ +// /** @file +// SdMmcPciHcDxe driver is used to manage those host controllers which comply with SD +// Host Controller Simplified Specifiction version 3.0. +// +// It will produce EFI_SD_MMC_PASS_THRU_PROTOCOL to allow sending SD/MMC/eMMC cmds +// to specified devices from upper layer. +// +// Copyright (c) 2015, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "SD/MMC Pci Host Controller driver to manage SD/MMC host controllers" + +#string STR_MODULE_DESCRIPTION #language en-US "This driver follows the UEFI driver model and produces SD/MMC Pass Thru protocol for upper layer bus driver." + diff --git a/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxeExtra.uni b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxeExtra.uni new file mode 100644 index 0000000000..c7aedb4cda --- /dev/null +++ b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHcDxeExtra.uni @@ -0,0 +1,19 @@ +// /** @file +// SdMmcPciHcDxe Localized Strings and Content +// +// Copyright (c) 2015, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"SD/MMC Pci Host Controller Driver" + + diff --git a/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHci.c b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHci.c new file mode 100644 index 0000000000..ccbf355016 --- /dev/null +++ b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHci.c @@ -0,0 +1,1923 @@ +/** @file + This driver is used to manage SD/MMC PCI host controllers which are compliance + with SD Host Controller Simplified Specification version 3.00. + + It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use. + + Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "SdMmcPciHcDxe.h" + +/** + Dump the content of SD/MMC host controller's Capability Register. + + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Capability The buffer to store the capability data. + +**/ +VOID +DumpCapabilityReg ( + IN UINT8 Slot, + IN SD_MMC_HC_SLOT_CAP *Capability + ) +{ + // + // Dump Capability Data + // + DEBUG ((DEBUG_INFO, " == Slot [%d] Capability is 0x%x ==\n", Slot, Capability)); + DEBUG ((DEBUG_INFO, " Timeout Clk Freq %d%a\n", Capability->TimeoutFreq, (Capability->TimeoutUnit) ? "MHz" : "KHz")); + DEBUG ((DEBUG_INFO, " Base Clk Freq %dMHz\n", Capability->BaseClkFreq)); + DEBUG ((DEBUG_INFO, " Max Blk Len %dbytes\n", 512 * (1 << Capability->MaxBlkLen))); + DEBUG ((DEBUG_INFO, " 8-bit Support %a\n", Capability->BusWidth8 ? "TRUE" : "FALSE")); + DEBUG ((DEBUG_INFO, " ADMA2 Support %a\n", Capability->Adma2 ? "TRUE" : "FALSE")); + DEBUG ((DEBUG_INFO, " HighSpeed Support %a\n", Capability->HighSpeed ? "TRUE" : "FALSE")); + DEBUG ((DEBUG_INFO, " SDMA Support %a\n", Capability->Sdma ? "TRUE" : "FALSE")); + DEBUG ((DEBUG_INFO, " Suspend/Resume %a\n", Capability->SuspRes ? "TRUE" : "FALSE")); + DEBUG ((DEBUG_INFO, " Voltage 3.3 %a\n", Capability->Voltage33 ? "TRUE" : "FALSE")); + DEBUG ((DEBUG_INFO, " Voltage 3.0 %a\n", Capability->Voltage30 ? "TRUE" : "FALSE")); + DEBUG ((DEBUG_INFO, " Voltage 1.8 %a\n", Capability->Voltage18 ? "TRUE" : "FALSE")); + DEBUG ((DEBUG_INFO, " 64-bit Sys Bus %a\n", Capability->SysBus64 ? "TRUE" : "FALSE")); + DEBUG ((DEBUG_INFO, " Async Interrupt %a\n", Capability->AsyncInt ? "TRUE" : "FALSE")); + DEBUG ((DEBUG_INFO, " SlotType ")); + if (Capability->SlotType == 0x00) { + DEBUG ((DEBUG_INFO, "%a\n", "Removable Slot")); + } else if (Capability->SlotType == 0x01) { + DEBUG ((DEBUG_INFO, "%a\n", "Embedded Slot")); + } else if (Capability->SlotType == 0x02) { + DEBUG ((DEBUG_INFO, "%a\n", "Shared Bus Slot")); + } else { + DEBUG ((DEBUG_INFO, "%a\n", "Reserved")); + } + DEBUG ((DEBUG_INFO, " SDR50 Support %a\n", Capability->Sdr50 ? "TRUE" : "FALSE")); + DEBUG ((DEBUG_INFO, " SDR104 Support %a\n", Capability->Sdr104 ? "TRUE" : "FALSE")); + DEBUG ((DEBUG_INFO, " DDR50 Support %a\n", Capability->Ddr50 ? "TRUE" : "FALSE")); + DEBUG ((DEBUG_INFO, " Driver Type A %a\n", Capability->DriverTypeA ? "TRUE" : "FALSE")); + DEBUG ((DEBUG_INFO, " Driver Type C %a\n", Capability->DriverTypeC ? "TRUE" : "FALSE")); + DEBUG ((DEBUG_INFO, " Driver Type D %a\n", Capability->DriverTypeD ? "TRUE" : "FALSE")); + DEBUG ((DEBUG_INFO, " Driver Type 4 %a\n", Capability->DriverType4 ? "TRUE" : "FALSE")); + if (Capability->TimerCount == 0) { + DEBUG ((DEBUG_INFO, " Retuning TimerCnt Disabled\n", 2 * (Capability->TimerCount - 1))); + } else { + DEBUG ((DEBUG_INFO, " Retuning TimerCnt %dseconds\n", 2 * (Capability->TimerCount - 1))); + } + DEBUG ((DEBUG_INFO, " SDR50 Tuning %a\n", Capability->TuningSDR50 ? "TRUE" : "FALSE")); + DEBUG ((DEBUG_INFO, " Retuning Mode Mode %d\n", Capability->RetuningMod + 1)); + DEBUG ((DEBUG_INFO, " Clock Multiplier M = %d\n", Capability->ClkMultiplier + 1)); + DEBUG ((DEBUG_INFO, " HS 400 %a\n", Capability->Hs400 ? "TRUE" : "FALSE")); + return; +} + +/** + Read SlotInfo register from SD/MMC host controller pci config space. + + @param[in] PciIo The PCI IO protocol instance. + @param[out] FirstBar The buffer to store the first BAR value. + @param[out] SlotNum The buffer to store the supported slot number. + + @retval EFI_SUCCESS The operation succeeds. + @retval Others The operation fails. + +**/ +EFI_STATUS +EFIAPI +SdMmcHcGetSlotInfo ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + OUT UINT8 *FirstBar, + OUT UINT8 *SlotNum + ) +{ + EFI_STATUS Status; + SD_MMC_HC_SLOT_INFO SlotInfo; + + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint8, + SD_MMC_HC_SLOT_OFFSET, + sizeof (SlotInfo), + &SlotInfo + ); + if (EFI_ERROR (Status)) { + return Status; + } + + *FirstBar = SlotInfo.FirstBar; + *SlotNum = SlotInfo.SlotNum + 1; + ASSERT ((*FirstBar + *SlotNum) < SD_MMC_HC_MAX_SLOT); + return EFI_SUCCESS; +} + +/** + Read/Write specified SD/MMC host controller mmio register. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] BarIndex The BAR index of the standard PCI Configuration + header to use as the base address for the memory + operation to perform. + @param[in] Offset The offset within the selected BAR to start the + memory operation. + @param[in] Read A boolean to indicate it's read or write operation. + @param[in] Count The width of the mmio register in bytes. + Must be 1, 2 , 4 or 8 bytes. + @param[in, out] Data For read operations, the destination buffer to store + the results. For write operations, the source buffer + to write data from. The caller is responsible for + having ownership of the data buffer and ensuring its + size not less than Count bytes. + + @retval EFI_INVALID_PARAMETER The PciIo or Data is NULL or the Count is not valid. + @retval EFI_SUCCESS The read/write operation succeeds. + @retval Others The read/write operation fails. + +**/ +EFI_STATUS +EFIAPI +SdMmcHcRwMmio ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 BarIndex, + IN UINT32 Offset, + IN BOOLEAN Read, + IN UINT8 Count, + IN OUT VOID *Data + ) +{ + EFI_STATUS Status; + + if ((PciIo == NULL) || (Data == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((Count != 1) && (Count != 2) && (Count != 4) && (Count != 8)) { + return EFI_INVALID_PARAMETER; + } + + if (Read) { + Status = PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint8, + BarIndex, + (UINT64) Offset, + Count, + Data + ); + } else { + Status = PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint8, + BarIndex, + (UINT64) Offset, + Count, + Data + ); + } + + return Status; +} + +/** + Do OR operation with the value of the specified SD/MMC host controller mmio register. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] BarIndex The BAR index of the standard PCI Configuration + header to use as the base address for the memory + operation to perform. + @param[in] Offset The offset within the selected BAR to start the + memory operation. + @param[in] Count The width of the mmio register in bytes. + Must be 1, 2 , 4 or 8 bytes. + @param[in] OrData The pointer to the data used to do OR operation. + The caller is responsible for having ownership of + the data buffer and ensuring its size not less than + Count bytes. + + @retval EFI_INVALID_PARAMETER The PciIo or OrData is NULL or the Count is not valid. + @retval EFI_SUCCESS The OR operation succeeds. + @retval Others The OR operation fails. + +**/ +EFI_STATUS +EFIAPI +SdMmcHcOrMmio ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 BarIndex, + IN UINT32 Offset, + IN UINT8 Count, + IN VOID *OrData + ) +{ + EFI_STATUS Status; + UINT64 Data; + UINT64 Or; + + Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, TRUE, Count, &Data); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Count == 1) { + Or = *(UINT8*) OrData; + } else if (Count == 2) { + Or = *(UINT16*) OrData; + } else if (Count == 4) { + Or = *(UINT32*) OrData; + } else if (Count == 8) { + Or = *(UINT64*) OrData; + } else { + return EFI_INVALID_PARAMETER; + } + + Data |= Or; + Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, FALSE, Count, &Data); + + return Status; +} + +/** + Do AND operation with the value of the specified SD/MMC host controller mmio register. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] BarIndex The BAR index of the standard PCI Configuration + header to use as the base address for the memory + operation to perform. + @param[in] Offset The offset within the selected BAR to start the + memory operation. + @param[in] Count The width of the mmio register in bytes. + Must be 1, 2 , 4 or 8 bytes. + @param[in] AndData The pointer to the data used to do AND operation. + The caller is responsible for having ownership of + the data buffer and ensuring its size not less than + Count bytes. + + @retval EFI_INVALID_PARAMETER The PciIo or AndData is NULL or the Count is not valid. + @retval EFI_SUCCESS The AND operation succeeds. + @retval Others The AND operation fails. + +**/ +EFI_STATUS +EFIAPI +SdMmcHcAndMmio ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 BarIndex, + IN UINT32 Offset, + IN UINT8 Count, + IN VOID *AndData + ) +{ + EFI_STATUS Status; + UINT64 Data; + UINT64 And; + + Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, TRUE, Count, &Data); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Count == 1) { + And = *(UINT8*) AndData; + } else if (Count == 2) { + And = *(UINT16*) AndData; + } else if (Count == 4) { + And = *(UINT32*) AndData; + } else if (Count == 8) { + And = *(UINT64*) AndData; + } else { + return EFI_INVALID_PARAMETER; + } + + Data &= And; + Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, FALSE, Count, &Data); + + return Status; +} + +/** + Wait for the value of the specified MMIO register set to the test value. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] BarIndex The BAR index of the standard PCI Configuration + header to use as the base address for the memory + operation to perform. + @param[in] Offset The offset within the selected BAR to start the + memory operation. + @param[in] Count The width of the mmio register in bytes. + Must be 1, 2, 4 or 8 bytes. + @param[in] MaskValue The mask value of memory. + @param[in] TestValue The test value of memory. + + @retval EFI_NOT_READY The MMIO register hasn't set to the expected value. + @retval EFI_SUCCESS The MMIO register has expected value. + @retval Others The MMIO operation fails. + +**/ +EFI_STATUS +EFIAPI +SdMmcHcCheckMmioSet ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 BarIndex, + IN UINT32 Offset, + IN UINT8 Count, + IN UINT64 MaskValue, + IN UINT64 TestValue + ) +{ + EFI_STATUS Status; + UINT64 Value; + + // + // Access PCI MMIO space to see if the value is the tested one. + // + Value = 0; + Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, TRUE, Count, &Value); + if (EFI_ERROR (Status)) { + return Status; + } + + Value &= MaskValue; + + if (Value == TestValue) { + return EFI_SUCCESS; + } + + return EFI_NOT_READY; +} + +/** + Wait for the value of the specified MMIO register set to the test value. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] BarIndex The BAR index of the standard PCI Configuration + header to use as the base address for the memory + operation to perform. + @param[in] Offset The offset within the selected BAR to start the + memory operation. + @param[in] Count The width of the mmio register in bytes. + Must be 1, 2, 4 or 8 bytes. + @param[in] MaskValue The mask value of memory. + @param[in] TestValue The test value of memory. + @param[in] Timeout The time out value for wait memory set, uses 1 + microsecond as a unit. + + @retval EFI_TIMEOUT The MMIO register hasn't expected value in timeout + range. + @retval EFI_SUCCESS The MMIO register has expected value. + @retval Others The MMIO operation fails. + +**/ +EFI_STATUS +EFIAPI +SdMmcHcWaitMmioSet ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 BarIndex, + IN UINT32 Offset, + IN UINT8 Count, + IN UINT64 MaskValue, + IN UINT64 TestValue, + IN UINT64 Timeout + ) +{ + EFI_STATUS Status; + BOOLEAN InfiniteWait; + + if (Timeout == 0) { + InfiniteWait = TRUE; + } else { + InfiniteWait = FALSE; + } + + while (InfiniteWait || (Timeout > 0)) { + Status = SdMmcHcCheckMmioSet ( + PciIo, + BarIndex, + Offset, + Count, + MaskValue, + TestValue + ); + if (Status != EFI_NOT_READY) { + return Status; + } + + // + // Stall for 1 microsecond. + // + gBS->Stall (1); + + Timeout--; + } + + return EFI_TIMEOUT; +} + +/** + Software reset the specified SD/MMC host controller and enable all interrupts. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS The software reset executes successfully. + @retval Others The software reset fails. + +**/ +EFI_STATUS +SdMmcHcReset ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot + ) +{ + EFI_STATUS Status; + UINT8 SwReset; + + SwReset = 0xFF; + Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_SW_RST, FALSE, sizeof (SwReset), &SwReset); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SdMmcHcReset: write full 1 fails: %r\n", Status)); + return Status; + } + + Status = SdMmcHcWaitMmioSet ( + PciIo, + Slot, + SD_MMC_HC_SW_RST, + sizeof (SwReset), + 0xFF, + 0x00, + SD_MMC_HC_GENERIC_TIMEOUT + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "SdMmcHcReset: reset done with %r\n", Status)); + return Status; + } + // + // Enable all interrupt after reset all. + // + Status = SdMmcHcEnableInterrupt (PciIo, Slot); + + return Status; +} + +/** + Set all interrupt status bits in Normal and Error Interrupt Status Enable + register. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS The operation executes successfully. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdMmcHcEnableInterrupt ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot + ) +{ + EFI_STATUS Status; + UINT16 IntStatus; + + // + // Enable all bits in Error Interrupt Status Enable Register + // + IntStatus = 0xFFFF; + Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_ERR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Enable all bits in Normal Interrupt Status Enable Register + // + IntStatus = 0xFFFF; + Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_NOR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus); + + return Status; +} + +/** + Get the capability data from the specified slot. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[out] Capability The buffer to store the capability data. + + @retval EFI_SUCCESS The operation executes successfully. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdMmcHcGetCapability ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + OUT SD_MMC_HC_SLOT_CAP *Capability + ) +{ + EFI_STATUS Status; + UINT64 Cap; + + Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CAP, TRUE, sizeof (Cap), &Cap); + if (EFI_ERROR (Status)) { + return Status; + } + + CopyMem (Capability, &Cap, sizeof (Cap)); + + return EFI_SUCCESS; +} + +/** + Get the maximum current capability data from the specified slot. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[out] MaxCurrent The buffer to store the maximum current capability data. + + @retval EFI_SUCCESS The operation executes successfully. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdMmcHcGetMaxCurrent ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + OUT UINT64 *MaxCurrent + ) +{ + EFI_STATUS Status; + + Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_MAX_CURRENT_CAP, TRUE, sizeof (UINT64), MaxCurrent); + + return Status; +} + +/** + Detect whether there is a SD/MMC card attached at the specified SD/MMC host controller + slot. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[out] MediaPresent The pointer to the media present boolean value. + + @retval EFI_SUCCESS There is no media change happened. + @retval EFI_MEDIA_CHANGED There is media change happened. + @retval Others The detection fails. + +**/ +EFI_STATUS +SdMmcHcCardDetect ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + OUT BOOLEAN *MediaPresent + ) +{ + EFI_STATUS Status; + UINT16 Data; + UINT32 PresentState; + + // + // Check Present State Register to see if there is a card presented. + // + Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((PresentState & BIT16) != 0) { + *MediaPresent = TRUE; + } else { + *MediaPresent = FALSE; + } + + // + // Check Normal Interrupt Status Register + // + Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_NOR_INT_STS, TRUE, sizeof (Data), &Data); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((Data & (BIT6 | BIT7)) != 0) { + // + // Clear BIT6 and BIT7 by writing 1 to these two bits if set. + // + Data &= BIT6 | BIT7; + Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_NOR_INT_STS, FALSE, sizeof (Data), &Data); + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_MEDIA_CHANGED; + } + + return EFI_SUCCESS; +} + +/** + Stop SD/MMC card clock. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS Succeed to stop SD/MMC clock. + @retval Others Fail to stop SD/MMC clock. + +**/ +EFI_STATUS +SdMmcHcStopClock ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot + ) +{ + EFI_STATUS Status; + UINT32 PresentState; + UINT16 ClockCtrl; + + // + // Ensure no SD transactions are occurring on the SD Bus by + // waiting for Command Inhibit (DAT) and Command Inhibit (CMD) + // in the Present State register to be 0. + // + Status = SdMmcHcWaitMmioSet ( + PciIo, + Slot, + SD_MMC_HC_PRESENT_STATE, + sizeof (PresentState), + BIT0 | BIT1, + 0, + SD_MMC_HC_GENERIC_TIMEOUT + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Set SD Clock Enable in the Clock Control register to 0 + // + ClockCtrl = (UINT16)~BIT2; + Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl); + + return Status; +} + +/** + SD/MMC card clock supply. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] ClockFreq The max clock frequency to be set. The unit is KHz. + @param[in] Capability The capability of the slot. + + @retval EFI_SUCCESS The clock is supplied successfully. + @retval Others The clock isn't supplied successfully. + +**/ +EFI_STATUS +SdMmcHcClockSupply ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN UINT64 ClockFreq, + IN SD_MMC_HC_SLOT_CAP Capability + ) +{ + EFI_STATUS Status; + UINT32 BaseClkFreq; + UINT32 SettingFreq; + UINT32 Divisor; + UINT32 Remainder; + UINT16 ControllerVer; + UINT16 ClockCtrl; + + // + // Calculate a divisor for SD clock frequency + // + ASSERT (Capability.BaseClkFreq != 0); + + BaseClkFreq = Capability.BaseClkFreq; + if (ClockFreq == 0) { + return EFI_INVALID_PARAMETER; + } + + if (ClockFreq > (BaseClkFreq * 1000)) { + ClockFreq = BaseClkFreq * 1000; + } + + // + // Calculate the divisor of base frequency. + // + Divisor = 0; + SettingFreq = BaseClkFreq * 1000; + while (ClockFreq < SettingFreq) { + Divisor++; + + SettingFreq = (BaseClkFreq * 1000) / (2 * Divisor); + Remainder = (BaseClkFreq * 1000) % (2 * Divisor); + if ((ClockFreq == SettingFreq) && (Remainder == 0)) { + break; + } + if ((ClockFreq == SettingFreq) && (Remainder != 0)) { + SettingFreq ++; + } + } + + DEBUG ((DEBUG_INFO, "BaseClkFreq %dMHz Divisor %d ClockFreq %dKhz\n", BaseClkFreq, Divisor, ClockFreq)); + + Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Set SDCLK Frequency Select and Internal Clock Enable fields in Clock Control register. + // + if ((ControllerVer & 0xFF) == 2) { + ASSERT (Divisor <= 0x3FF); + ClockCtrl = ((Divisor & 0xFF) << 8) | ((Divisor & 0x300) >> 2); + } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) { + // + // Only the most significant bit can be used as divisor. + // + if (((Divisor - 1) & Divisor) != 0) { + Divisor = 1 << (HighBitSet32 (Divisor) + 1); + } + ASSERT (Divisor <= 0x80); + ClockCtrl = (Divisor & 0xFF) << 8; + } else { + DEBUG ((DEBUG_ERROR, "Unknown SD Host Controller Spec version [0x%x]!!!\n", ControllerVer)); + return EFI_UNSUPPORTED; + } + + // + // Stop bus clock at first + // + Status = SdMmcHcStopClock (PciIo, Slot); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Supply clock frequency with specified divisor + // + ClockCtrl |= BIT0; + Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, FALSE, sizeof (ClockCtrl), &ClockCtrl); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Set SDCLK Frequency Select and Internal Clock Enable fields fails\n")); + return Status; + } + + // + // Wait Internal Clock Stable in the Clock Control register to be 1 + // + Status = SdMmcHcWaitMmioSet ( + PciIo, + Slot, + SD_MMC_HC_CLOCK_CTRL, + sizeof (ClockCtrl), + BIT1, + BIT1, + SD_MMC_HC_GENERIC_TIMEOUT + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Set SD Clock Enable in the Clock Control register to 1 + // + ClockCtrl = BIT2; + Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl); + + return Status; +} + +/** + SD/MMC bus power control. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] PowerCtrl The value setting to the power control register. + + @retval TRUE There is a SD/MMC card attached. + @retval FALSE There is no a SD/MMC card attached. + +**/ +EFI_STATUS +SdMmcHcPowerControl ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN UINT8 PowerCtrl + ) +{ + EFI_STATUS Status; + + // + // Clr SD Bus Power + // + PowerCtrl &= (UINT8)~BIT0; + Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register + // + PowerCtrl |= BIT0; + Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl); + + return Status; +} + +/** + Set the SD/MMC bus width. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] BusWidth The bus width used by the SD/MMC device, it must be 1, 4 or 8. + + @retval EFI_SUCCESS The bus width is set successfully. + @retval Others The bus width isn't set successfully. + +**/ +EFI_STATUS +SdMmcHcSetBusWidth ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN UINT16 BusWidth + ) +{ + EFI_STATUS Status; + UINT8 HostCtrl1; + + if (BusWidth == 1) { + HostCtrl1 = (UINT8)~(BIT5 | BIT1); + Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1); + } else if (BusWidth == 4) { + Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1); + if (EFI_ERROR (Status)) { + return Status; + } + HostCtrl1 |= BIT1; + HostCtrl1 &= (UINT8)~BIT5; + Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1); + } else if (BusWidth == 8) { + Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1); + if (EFI_ERROR (Status)) { + return Status; + } + HostCtrl1 &= (UINT8)~BIT1; + HostCtrl1 |= BIT5; + Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1); + } else { + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + return Status; +} + +/** + Supply SD/MMC card with lowest clock frequency at initialization. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Capability The capability of the slot. + + @retval EFI_SUCCESS The clock is supplied successfully. + @retval Others The clock isn't supplied successfully. + +**/ +EFI_STATUS +SdMmcHcInitClockFreq ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN SD_MMC_HC_SLOT_CAP Capability + ) +{ + EFI_STATUS Status; + UINT32 InitFreq; + + // + // Calculate a divisor for SD clock frequency + // + if (Capability.BaseClkFreq == 0) { + // + // Don't support get Base Clock Frequency information via another method + // + return EFI_UNSUPPORTED; + } + // + // Supply 400KHz clock frequency at initialization phase. + // + InitFreq = 400; + Status = SdMmcHcClockSupply (PciIo, Slot, InitFreq, Capability); + return Status; +} + +/** + Supply SD/MMC card with maximum voltage at initialization. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Capability The capability of the slot. + + @retval EFI_SUCCESS The voltage is supplied successfully. + @retval Others The voltage isn't supplied successfully. + +**/ +EFI_STATUS +SdMmcHcInitPowerVoltage ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN SD_MMC_HC_SLOT_CAP Capability + ) +{ + EFI_STATUS Status; + UINT8 MaxVoltage; + UINT8 HostCtrl2; + + // + // Calculate supported maximum voltage according to SD Bus Voltage Select + // + if (Capability.Voltage33 != 0) { + // + // Support 3.3V + // + MaxVoltage = 0x0E; + } else if (Capability.Voltage30 != 0) { + // + // Support 3.0V + // + MaxVoltage = 0x0C; + } else if (Capability.Voltage18 != 0) { + // + // Support 1.8V + // + MaxVoltage = 0x0A; + HostCtrl2 = BIT3; + Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + gBS->Stall (5000); + if (EFI_ERROR (Status)) { + return Status; + } + } else { + ASSERT (FALSE); + return EFI_DEVICE_ERROR; + } + + // + // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register + // + Status = SdMmcHcPowerControl (PciIo, Slot, MaxVoltage); + + return Status; +} + +/** + Initialize the Timeout Control register with most conservative value at initialization. + + Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS The timeout control register is configured successfully. + @retval Others The timeout control register isn't configured successfully. + +**/ +EFI_STATUS +SdMmcHcInitTimeoutCtrl ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot + ) +{ + EFI_STATUS Status; + UINT8 Timeout; + + Timeout = 0x0E; + Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_TIMEOUT_CTRL, FALSE, sizeof (Timeout), &Timeout); + + return Status; +} + +/** + Initial SD/MMC host controller with lowest clock frequency, max power and max timeout value + at initialization. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Capability The capability of the slot. + + @retval EFI_SUCCESS The host controller is initialized successfully. + @retval Others The host controller isn't initialized successfully. + +**/ +EFI_STATUS +SdMmcHcInitHost ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN SD_MMC_HC_SLOT_CAP Capability + ) +{ + EFI_STATUS Status; + + Status = SdMmcHcInitClockFreq (PciIo, Slot, Capability); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = SdMmcHcInitPowerVoltage (PciIo, Slot, Capability); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = SdMmcHcInitTimeoutCtrl (PciIo, Slot); + return Status; +} + +/** + Turn on/off LED. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] On The boolean to turn on/off LED. + + @retval EFI_SUCCESS The LED is turned on/off successfully. + @retval Others The LED isn't turned on/off successfully. + +**/ +EFI_STATUS +SdMmcHcLedOnOff ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN BOOLEAN On + ) +{ + EFI_STATUS Status; + UINT8 HostCtrl1; + + if (On) { + HostCtrl1 = BIT0; + Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1); + } else { + HostCtrl1 = (UINT8)~BIT0; + Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1); + } + + return Status; +} + +/** + Build ADMA descriptor table for transfer. + + Refer to SD Host Controller Simplified spec 3.0 Section 1.13 for details. + + @param[in] Trb The pointer to the SD_MMC_HC_TRB instance. + + @retval EFI_SUCCESS The ADMA descriptor table is created successfully. + @retval Others The ADMA descriptor table isn't created successfully. + +**/ +EFI_STATUS +BuildAdmaDescTable ( + IN SD_MMC_HC_TRB *Trb + ) +{ + EFI_PHYSICAL_ADDRESS Data; + UINT64 DataLen; + UINT64 Entries; + UINT32 Index; + UINT64 Remaining; + UINT32 Address; + UINTN TableSize; + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_STATUS Status; + UINTN Bytes; + + Data = Trb->DataPhy; + DataLen = Trb->DataLen; + PciIo = Trb->Private->PciIo; + // + // Only support 32bit ADMA Descriptor Table + // + if ((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul)) { + return EFI_INVALID_PARAMETER; + } + // + // Address field shall be set on 32-bit boundary (Lower 2-bit is always set to 0) + // for 32-bit address descriptor table. + // + if ((Data & (BIT0 | BIT1)) != 0) { + DEBUG ((DEBUG_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 4 bytes boundary!\n", Data)); + } + + Entries = DivU64x32 ((DataLen + ADMA_MAX_DATA_PER_LINE - 1), ADMA_MAX_DATA_PER_LINE); + TableSize = (UINTN)MultU64x32 (Entries, sizeof (SD_MMC_HC_ADMA_DESC_LINE)); + Trb->AdmaPages = (UINT32)EFI_SIZE_TO_PAGES (TableSize); + Status = PciIo->AllocateBuffer ( + PciIo, + AllocateAnyPages, + EfiBootServicesData, + EFI_SIZE_TO_PAGES (TableSize), + (VOID **)&Trb->AdmaDesc, + 0 + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + ZeroMem (Trb->AdmaDesc, TableSize); + Bytes = TableSize; + Status = PciIo->Map ( + PciIo, + EfiPciIoOperationBusMasterCommonBuffer, + Trb->AdmaDesc, + &Bytes, + &Trb->AdmaDescPhy, + &Trb->AdmaMap + ); + + if (EFI_ERROR (Status) || (Bytes != TableSize)) { + // + // Map error or unable to map the whole RFis buffer into a contiguous region. + // + PciIo->FreeBuffer ( + PciIo, + EFI_SIZE_TO_PAGES (TableSize), + Trb->AdmaDesc + ); + return EFI_OUT_OF_RESOURCES; + } + + if ((UINT64)(UINTN)Trb->AdmaDescPhy > 0x100000000ul) { + // + // The ADMA doesn't support 64bit addressing. + // + PciIo->Unmap ( + PciIo, + Trb->AdmaMap + ); + PciIo->FreeBuffer ( + PciIo, + EFI_SIZE_TO_PAGES (TableSize), + Trb->AdmaDesc + ); + return EFI_DEVICE_ERROR; + } + + Remaining = DataLen; + Address = (UINT32)Data; + for (Index = 0; Index < Entries; Index++) { + if (Remaining <= ADMA_MAX_DATA_PER_LINE) { + Trb->AdmaDesc[Index].Valid = 1; + Trb->AdmaDesc[Index].Act = 2; + Trb->AdmaDesc[Index].Length = (UINT16)Remaining; + Trb->AdmaDesc[Index].Address = Address; + break; + } else { + Trb->AdmaDesc[Index].Valid = 1; + Trb->AdmaDesc[Index].Act = 2; + Trb->AdmaDesc[Index].Length = 0; + Trb->AdmaDesc[Index].Address = Address; + } + + Remaining -= ADMA_MAX_DATA_PER_LINE; + Address += ADMA_MAX_DATA_PER_LINE; + } + + // + // Set the last descriptor line as end of descriptor table + // + Trb->AdmaDesc[Index].End = 1; + return EFI_SUCCESS; +} + +/** + Create a new TRB for the SD/MMC cmd request. + + @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Packet A pointer to the SD command data structure. + @param[in] Event If Event is NULL, blocking I/O is performed. If Event is + not NULL, then nonblocking I/O is performed, and Event + will be signaled when the Packet completes. + + @return Created Trb or NULL. + +**/ +SD_MMC_HC_TRB * +SdMmcCreateTrb ( + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN UINT8 Slot, + IN EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet, + IN EFI_EVENT Event + ) +{ + SD_MMC_HC_TRB *Trb; + EFI_STATUS Status; + EFI_TPL OldTpl; + EFI_PCI_IO_PROTOCOL_OPERATION Flag; + EFI_PCI_IO_PROTOCOL *PciIo; + UINTN MapLength; + + Trb = AllocateZeroPool (sizeof (SD_MMC_HC_TRB)); + if (Trb == NULL) { + return NULL; + } + + Trb->Signature = SD_MMC_HC_TRB_SIG; + Trb->Slot = Slot; + Trb->BlockSize = 0x200; + Trb->Packet = Packet; + Trb->Event = Event; + Trb->Started = FALSE; + Trb->Timeout = Packet->Timeout; + Trb->Private = Private; + + if ((Packet->InTransferLength != 0) && (Packet->InDataBuffer != NULL)) { + Trb->Data = Packet->InDataBuffer; + Trb->DataLen = Packet->InTransferLength; + Trb->Read = TRUE; + } else if ((Packet->OutTransferLength != 0) && (Packet->OutDataBuffer != NULL)) { + Trb->Data = Packet->OutDataBuffer; + Trb->DataLen = Packet->OutTransferLength; + Trb->Read = FALSE; + } else if ((Packet->InTransferLength == 0) && (Packet->OutTransferLength == 0)) { + Trb->Data = NULL; + Trb->DataLen = 0; + } else { + goto Error; + } + + if (Trb->DataLen < Trb->BlockSize) { + Trb->BlockSize = (UINT16)Trb->DataLen; + } + + if (((Private->Slot[Trb->Slot].CardType == EmmcCardType) && + (Packet->SdMmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK)) || + ((Private->Slot[Trb->Slot].CardType == SdCardType) && + (Packet->SdMmcCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK))) { + Trb->Mode = SdMmcPioMode; + } else { + if (Trb->Read) { + Flag = EfiPciIoOperationBusMasterWrite; + } else { + Flag = EfiPciIoOperationBusMasterRead; + } + + PciIo = Private->PciIo; + if (Trb->DataLen != 0) { + MapLength = Trb->DataLen; + Status = PciIo->Map ( + PciIo, + Flag, + Trb->Data, + &MapLength, + &Trb->DataPhy, + &Trb->DataMap + ); + if (EFI_ERROR (Status) || (Trb->DataLen != MapLength)) { + Status = EFI_BAD_BUFFER_SIZE; + goto Error; + } + } + + if (Trb->DataLen == 0) { + Trb->Mode = SdMmcNoData; + } else if (Private->Capability[Slot].Adma2 != 0) { + Trb->Mode = SdMmcAdmaMode; + Status = BuildAdmaDescTable (Trb); + if (EFI_ERROR (Status)) { + PciIo->Unmap (PciIo, Trb->DataMap); + goto Error; + } + } else if (Private->Capability[Slot].Sdma != 0) { + Trb->Mode = SdMmcSdmaMode; + } else { + Trb->Mode = SdMmcPioMode; + } + } + + if (Event != NULL) { + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + InsertTailList (&Private->Queue, &Trb->TrbList); + gBS->RestoreTPL (OldTpl); + } + + return Trb; + +Error: + SdMmcFreeTrb (Trb); + return NULL; +} + +/** + Free the resource used by the TRB. + + @param[in] Trb The pointer to the SD_MMC_HC_TRB instance. + +**/ +VOID +SdMmcFreeTrb ( + IN SD_MMC_HC_TRB *Trb + ) +{ + EFI_PCI_IO_PROTOCOL *PciIo; + + PciIo = Trb->Private->PciIo; + + if (Trb->AdmaMap != NULL) { + PciIo->Unmap ( + PciIo, + Trb->AdmaMap + ); + } + if (Trb->AdmaDesc != NULL) { + PciIo->FreeBuffer ( + PciIo, + Trb->AdmaPages, + Trb->AdmaDesc + ); + } + if (Trb->DataMap != NULL) { + PciIo->Unmap ( + PciIo, + Trb->DataMap + ); + } + FreePool (Trb); + return; +} + +/** + Check if the env is ready for execute specified TRB. + + @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance. + @param[in] Trb The pointer to the SD_MMC_HC_TRB instance. + + @retval EFI_SUCCESS The env is ready for TRB execution. + @retval EFI_NOT_READY The env is not ready for TRB execution. + @retval Others Some erros happen. + +**/ +EFI_STATUS +SdMmcCheckTrbEnv ( + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN SD_MMC_HC_TRB *Trb + ) +{ + EFI_STATUS Status; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet; + EFI_PCI_IO_PROTOCOL *PciIo; + UINT32 PresentState; + + Packet = Trb->Packet; + + if ((Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAdtc) || + (Packet->SdMmcCmdBlk->ResponseType == SdMmcResponseTypeR1b) || + (Packet->SdMmcCmdBlk->ResponseType == SdMmcResponseTypeR5b)) { + // + // Wait Command Inhibit (CMD) and Command Inhibit (DAT) in + // the Present State register to be 0 + // + PresentState = BIT0 | BIT1; + } else { + // + // Wait Command Inhibit (CMD) in the Present State register + // to be 0 + // + PresentState = BIT0; + } + + PciIo = Private->PciIo; + Status = SdMmcHcCheckMmioSet ( + PciIo, + Trb->Slot, + SD_MMC_HC_PRESENT_STATE, + sizeof (PresentState), + PresentState, + 0 + ); + + return Status; +} + +/** + Wait for the env to be ready for execute specified TRB. + + @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance. + @param[in] Trb The pointer to the SD_MMC_HC_TRB instance. + + @retval EFI_SUCCESS The env is ready for TRB execution. + @retval EFI_TIMEOUT The env is not ready for TRB execution in time. + @retval Others Some erros happen. + +**/ +EFI_STATUS +SdMmcWaitTrbEnv ( + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN SD_MMC_HC_TRB *Trb + ) +{ + EFI_STATUS Status; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet; + UINT64 Timeout; + BOOLEAN InfiniteWait; + + // + // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register + // + Packet = Trb->Packet; + Timeout = Packet->Timeout; + if (Timeout == 0) { + InfiniteWait = TRUE; + } else { + InfiniteWait = FALSE; + } + + while (InfiniteWait || (Timeout > 0)) { + // + // Check Trb execution result by reading Normal Interrupt Status register. + // + Status = SdMmcCheckTrbEnv (Private, Trb); + if (Status != EFI_NOT_READY) { + return Status; + } + // + // Stall for 1 microsecond. + // + gBS->Stall (1); + + Timeout--; + } + + return EFI_TIMEOUT; +} + +/** + Execute the specified TRB. + + @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance. + @param[in] Trb The pointer to the SD_MMC_HC_TRB instance. + + @retval EFI_SUCCESS The TRB is sent to host controller successfully. + @retval Others Some erros happen when sending this request to the host controller. + +**/ +EFI_STATUS +SdMmcExecTrb ( + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN SD_MMC_HC_TRB *Trb + ) +{ + EFI_STATUS Status; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet; + EFI_PCI_IO_PROTOCOL *PciIo; + UINT16 Cmd; + UINT16 IntStatus; + UINT32 Argument; + UINT16 BlkCount; + UINT16 BlkSize; + UINT16 TransMode; + UINT8 HostCtrl1; + UINT32 SdmaAddr; + UINT64 AdmaAddr; + + Packet = Trb->Packet; + PciIo = Trb->Private->PciIo; + // + // Clear all bits in Error Interrupt Status Register + // + IntStatus = 0xFFFF; + Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_ERR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Clear all bits in Normal Interrupt Status Register excepts for Card Removal & Card Insertion bits. + // + IntStatus = 0xFF3F; + Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Set Host Control 1 register DMA Select field + // + if (Trb->Mode == SdMmcAdmaMode) { + HostCtrl1 = BIT4; + Status = SdMmcHcOrMmio (PciIo, Trb->Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1); + if (EFI_ERROR (Status)) { + return Status; + } + } + + SdMmcHcLedOnOff (PciIo, Trb->Slot, TRUE); + + if (Trb->Mode == SdMmcSdmaMode) { + if ((UINT64)(UINTN)Trb->DataPhy >= 0x100000000ul) { + return EFI_INVALID_PARAMETER; + } + + SdmaAddr = (UINT32)(UINTN)Trb->DataPhy; + Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_SDMA_ADDR, FALSE, sizeof (SdmaAddr), &SdmaAddr); + if (EFI_ERROR (Status)) { + return Status; + } + } else if (Trb->Mode == SdMmcAdmaMode) { + AdmaAddr = (UINT64)(UINTN)Trb->AdmaDescPhy; + Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_ADMA_SYS_ADDR, FALSE, sizeof (AdmaAddr), &AdmaAddr); + if (EFI_ERROR (Status)) { + return Status; + } + } + + BlkSize = Trb->BlockSize; + if (Trb->Mode == SdMmcSdmaMode) { + // + // Set SDMA boundary to be 512K bytes. + // + BlkSize |= 0x7000; + } + + Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_BLK_SIZE, FALSE, sizeof (BlkSize), &BlkSize); + if (EFI_ERROR (Status)) { + return Status; + } + + BlkCount = 0; + if (Trb->Mode != SdMmcNoData) { + // + // Calcuate Block Count. + // + BlkCount = (UINT16)(Trb->DataLen / Trb->BlockSize); + } + Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_BLK_COUNT, FALSE, sizeof (BlkCount), &BlkCount); + if (EFI_ERROR (Status)) { + return Status; + } + + Argument = Packet->SdMmcCmdBlk->CommandArgument; + Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_ARG1, FALSE, sizeof (Argument), &Argument); + if (EFI_ERROR (Status)) { + return Status; + } + + TransMode = 0; + if (Trb->Mode != SdMmcNoData) { + if (Trb->Mode != SdMmcPioMode) { + TransMode |= BIT0; + } + if (Trb->Read) { + TransMode |= BIT4; + } + if (BlkCount > 1) { + TransMode |= BIT5 | BIT1; + } + // + // Only SD memory card needs to use AUTO CMD12 feature. + // + if (Private->Slot[Trb->Slot].CardType == SdCardType) { + if (BlkCount > 1) { + TransMode |= BIT2; + } + } + } + + Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_TRANS_MOD, FALSE, sizeof (TransMode), &TransMode); + if (EFI_ERROR (Status)) { + return Status; + } + + Cmd = (UINT16)LShiftU64(Packet->SdMmcCmdBlk->CommandIndex, 8); + if (Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAdtc) { + Cmd |= BIT5; + } + // + // Convert ResponseType to value + // + if (Packet->SdMmcCmdBlk->CommandType != SdMmcCommandTypeBc) { + switch (Packet->SdMmcCmdBlk->ResponseType) { + case SdMmcResponseTypeR1: + case SdMmcResponseTypeR5: + case SdMmcResponseTypeR6: + case SdMmcResponseTypeR7: + Cmd |= (BIT1 | BIT3 | BIT4); + break; + case SdMmcResponseTypeR2: + Cmd |= (BIT0 | BIT3); + break; + case SdMmcResponseTypeR3: + case SdMmcResponseTypeR4: + Cmd |= BIT1; + break; + case SdMmcResponseTypeR1b: + case SdMmcResponseTypeR5b: + Cmd |= (BIT0 | BIT1 | BIT3 | BIT4); + break; + default: + ASSERT (FALSE); + break; + } + } + // + // Execute cmd + // + Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_COMMAND, FALSE, sizeof (Cmd), &Cmd); + return Status; +} + +/** + Check the TRB execution result. + + @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance. + @param[in] Trb The pointer to the SD_MMC_HC_TRB instance. + + @retval EFI_SUCCESS The TRB is executed successfully. + @retval EFI_NOT_READY The TRB is not completed for execution. + @retval Others Some erros happen when executing this request. + +**/ +EFI_STATUS +SdMmcCheckTrbResult ( + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN SD_MMC_HC_TRB *Trb + ) +{ + EFI_STATUS Status; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet; + UINT16 IntStatus; + UINT32 Response[4]; + UINT32 SdmaAddr; + UINT8 Index; + UINT8 SwReset; + UINT32 PioLength; + + SwReset = 0; + Packet = Trb->Packet; + // + // Check Trb execution result by reading Normal Interrupt Status register. + // + Status = SdMmcHcRwMmio ( + Private->PciIo, + Trb->Slot, + SD_MMC_HC_NOR_INT_STS, + TRUE, + sizeof (IntStatus), + &IntStatus + ); + if (EFI_ERROR (Status)) { + goto Done; + } + // + // Check Transfer Complete bit is set or not. + // + if ((IntStatus & BIT1) == BIT1) { + if ((IntStatus & BIT15) == BIT15) { + // + // Read Error Interrupt Status register to check if the error is + // Data Timeout Error. + // If yes, treat it as success as Transfer Complete has higher + // priority than Data Timeout Error. + // + Status = SdMmcHcRwMmio ( + Private->PciIo, + Trb->Slot, + SD_MMC_HC_ERR_INT_STS, + TRUE, + sizeof (IntStatus), + &IntStatus + ); + if (!EFI_ERROR (Status)) { + if ((IntStatus & BIT4) == BIT4) { + Status = EFI_SUCCESS; + } else { + Status = EFI_DEVICE_ERROR; + } + } + } + + goto Done; + } + // + // Check if there is a error happened during cmd execution. + // If yes, then do error recovery procedure to follow SD Host Controller + // Simplified Spec 3.0 section 3.10.1. + // + if ((IntStatus & BIT15) == BIT15) { + Status = SdMmcHcRwMmio ( + Private->PciIo, + Trb->Slot, + SD_MMC_HC_ERR_INT_STS, + TRUE, + sizeof (IntStatus), + &IntStatus + ); + if (EFI_ERROR (Status)) { + goto Done; + } + if ((IntStatus & 0x0F) != 0) { + SwReset |= BIT1; + } + if ((IntStatus & 0xF0) != 0) { + SwReset |= BIT2; + } + + Status = SdMmcHcRwMmio ( + Private->PciIo, + Trb->Slot, + SD_MMC_HC_SW_RST, + FALSE, + sizeof (SwReset), + &SwReset + ); + if (EFI_ERROR (Status)) { + goto Done; + } + Status = SdMmcHcWaitMmioSet ( + Private->PciIo, + Trb->Slot, + SD_MMC_HC_SW_RST, + sizeof (SwReset), + 0xFF, + 0, + SD_MMC_HC_GENERIC_TIMEOUT + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = EFI_DEVICE_ERROR; + goto Done; + } + // + // Check if DMA interrupt is signalled for the SDMA transfer. + // + if ((Trb->Mode == SdMmcSdmaMode) && ((IntStatus & BIT3) == BIT3)) { + // + // Clear DMA interrupt bit. + // + IntStatus = BIT3; + Status = SdMmcHcRwMmio ( + Private->PciIo, + Trb->Slot, + SD_MMC_HC_NOR_INT_STS, + FALSE, + sizeof (IntStatus), + &IntStatus + ); + if (EFI_ERROR (Status)) { + goto Done; + } + // + // Update SDMA Address register. + // + SdmaAddr = SD_MMC_SDMA_ROUND_UP ((UINT32)(UINTN)Trb->DataPhy, SD_MMC_SDMA_BOUNDARY); + Status = SdMmcHcRwMmio ( + Private->PciIo, + Trb->Slot, + SD_MMC_HC_SDMA_ADDR, + FALSE, + sizeof (UINT32), + &SdmaAddr + ); + if (EFI_ERROR (Status)) { + goto Done; + } + Trb->DataPhy = (UINT32)(UINTN)SdmaAddr; + } + + if ((Packet->SdMmcCmdBlk->CommandType != SdMmcCommandTypeAdtc) && + (Packet->SdMmcCmdBlk->ResponseType != SdMmcResponseTypeR1b) && + (Packet->SdMmcCmdBlk->ResponseType != SdMmcResponseTypeR5b)) { + if ((IntStatus & BIT0) == BIT0) { + Status = EFI_SUCCESS; + goto Done; + } + } + + if (((Private->Slot[Trb->Slot].CardType == EmmcCardType) && + (Packet->SdMmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK)) || + ((Private->Slot[Trb->Slot].CardType == SdCardType) && + (Packet->SdMmcCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK))) { + // + // When performing tuning procedure (Execute Tuning is set to 1) through PIO mode, + // wait Buffer Read Ready bit of Normal Interrupt Status Register to be 1. + // Refer to SD Host Controller Simplified Specification 3.0 figure 2-29 for details. + // + if ((IntStatus & BIT5) == BIT5) { + // + // Clear Buffer Read Ready interrupt at first. + // + IntStatus = BIT5; + SdMmcHcRwMmio (Private->PciIo, Trb->Slot, SD_MMC_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus); + // + // Read data out from Buffer Port register + // + for (PioLength = 0; PioLength < Trb->DataLen; PioLength += 4) { + SdMmcHcRwMmio (Private->PciIo, Trb->Slot, SD_MMC_HC_BUF_DAT_PORT, TRUE, 4, (UINT8*)Trb->Data + PioLength); + } + Status = EFI_SUCCESS; + goto Done; + } + } + + Status = EFI_NOT_READY; +Done: + // + // Get response data when the cmd is executed successfully. + // + if (!EFI_ERROR (Status)) { + if (Packet->SdMmcCmdBlk->CommandType != SdMmcCommandTypeBc) { + for (Index = 0; Index < 4; Index++) { + Status = SdMmcHcRwMmio ( + Private->PciIo, + Trb->Slot, + SD_MMC_HC_RESPONSE + Index * 4, + TRUE, + sizeof (UINT32), + &Response[Index] + ); + if (EFI_ERROR (Status)) { + SdMmcHcLedOnOff (Private->PciIo, Trb->Slot, FALSE); + return Status; + } + } + CopyMem (Packet->SdMmcStatusBlk, Response, sizeof (Response)); + } + } + + if (Status != EFI_NOT_READY) { + SdMmcHcLedOnOff (Private->PciIo, Trb->Slot, FALSE); + } + + return Status; +} + +/** + Wait for the TRB execution result. + + @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance. + @param[in] Trb The pointer to the SD_MMC_HC_TRB instance. + + @retval EFI_SUCCESS The TRB is executed successfully. + @retval Others Some erros happen when executing this request. + +**/ +EFI_STATUS +SdMmcWaitTrbResult ( + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN SD_MMC_HC_TRB *Trb + ) +{ + EFI_STATUS Status; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet; + UINT64 Timeout; + BOOLEAN InfiniteWait; + + Packet = Trb->Packet; + // + // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register + // + Timeout = Packet->Timeout; + if (Timeout == 0) { + InfiniteWait = TRUE; + } else { + InfiniteWait = FALSE; + } + + while (InfiniteWait || (Timeout > 0)) { + // + // Check Trb execution result by reading Normal Interrupt Status register. + // + Status = SdMmcCheckTrbResult (Private, Trb); + if (Status != EFI_NOT_READY) { + return Status; + } + // + // Stall for 1 microsecond. + // + gBS->Stall (1); + + Timeout--; + } + + return EFI_TIMEOUT; +} + diff --git a/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHci.h b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHci.h new file mode 100644 index 0000000000..fb62758602 --- /dev/null +++ b/Platform/Marvell/Drivers/SdMmc/XenonDxe/SdMmcPciHci.h @@ -0,0 +1,546 @@ +/** @file + + Provides some data structure definitions used by the SD/MMC host controller driver. + +Copyright (c) 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _SD_MMC_PCI_HCI_H_ +#define _SD_MMC_PCI_HCI_H_ + +// +// SD Host Controller SlotInfo Register Offset +// +#define SD_MMC_HC_SLOT_OFFSET 0x40 + +#define SD_MMC_HC_MAX_SLOT 6 + +// +// SD Host Controller MMIO Register Offset +// +#define SD_MMC_HC_SDMA_ADDR 0x00 +#define SD_MMC_HC_ARG2 0x00 +#define SD_MMC_HC_BLK_SIZE 0x04 +#define SD_MMC_HC_BLK_COUNT 0x06 +#define SD_MMC_HC_ARG1 0x08 +#define SD_MMC_HC_TRANS_MOD 0x0C +#define SD_MMC_HC_COMMAND 0x0E +#define SD_MMC_HC_RESPONSE 0x10 +#define SD_MMC_HC_BUF_DAT_PORT 0x20 +#define SD_MMC_HC_PRESENT_STATE 0x24 +#define SD_MMC_HC_HOST_CTRL1 0x28 +#define SD_MMC_HC_POWER_CTRL 0x29 +#define SD_MMC_HC_BLK_GAP_CTRL 0x2A +#define SD_MMC_HC_WAKEUP_CTRL 0x2B +#define SD_MMC_HC_CLOCK_CTRL 0x2C +#define SD_MMC_HC_TIMEOUT_CTRL 0x2E +#define SD_MMC_HC_SW_RST 0x2F +#define SD_MMC_HC_NOR_INT_STS 0x30 +#define SD_MMC_HC_ERR_INT_STS 0x32 +#define SD_MMC_HC_NOR_INT_STS_EN 0x34 +#define SD_MMC_HC_ERR_INT_STS_EN 0x36 +#define SD_MMC_HC_NOR_INT_SIG_EN 0x38 +#define SD_MMC_HC_ERR_INT_SIG_EN 0x3A +#define SD_MMC_HC_AUTO_CMD_ERR_STS 0x3C +#define SD_MMC_HC_HOST_CTRL2 0x3E +#define SD_MMC_HC_CAP 0x40 +#define SD_MMC_HC_MAX_CURRENT_CAP 0x48 +#define SD_MMC_HC_FORCE_EVT_AUTO_CMD 0x50 +#define SD_MMC_HC_FORCE_EVT_ERR_INT 0x52 +#define SD_MMC_HC_ADMA_ERR_STS 0x54 +#define SD_MMC_HC_ADMA_SYS_ADDR 0x58 +#define SD_MMC_HC_PRESET_VAL 0x60 +#define SD_MMC_HC_SHARED_BUS_CTRL 0xE0 +#define SD_MMC_HC_SLOT_INT_STS 0xFC +#define SD_MMC_HC_CTRL_VER 0xFE + +// +// The transfer modes supported by SD Host Controller +// Simplified Spec 3.0 Table 1-2 +// +typedef enum { + SdMmcNoData, + SdMmcPioMode, + SdMmcSdmaMode, + SdMmcAdmaMode +} SD_MMC_HC_TRANSFER_MODE; + +// +// The maximum data length of each descriptor line +// +#define ADMA_MAX_DATA_PER_LINE 0x10000 + +typedef struct { + UINT32 Valid:1; + UINT32 End:1; + UINT32 Int:1; + UINT32 Reserved:1; + UINT32 Act:2; + UINT32 Reserved1:10; + UINT32 Length:16; + UINT32 Address; +} SD_MMC_HC_ADMA_DESC_LINE; + +#define SD_MMC_SDMA_BOUNDARY 512 * 1024 +#define SD_MMC_SDMA_ROUND_UP(x, n) (((x) + n) & ~(n - 1)) + +typedef struct { + UINT8 FirstBar:3; // bit 0:2 + UINT8 Reserved:1; // bit 3 + UINT8 SlotNum:3; // bit 4:6 + UINT8 Reserved1:1; // bit 7 +} SD_MMC_HC_SLOT_INFO; + +typedef struct { + UINT32 TimeoutFreq:6; // bit 0:5 + UINT32 Reserved:1; // bit 6 + UINT32 TimeoutUnit:1; // bit 7 + UINT32 BaseClkFreq:8; // bit 8:15 + UINT32 MaxBlkLen:2; // bit 16:17 + UINT32 BusWidth8:1; // bit 18 + UINT32 Adma2:1; // bit 19 + UINT32 Reserved2:1; // bit 20 + UINT32 HighSpeed:1; // bit 21 + UINT32 Sdma:1; // bit 22 + UINT32 SuspRes:1; // bit 23 + UINT32 Voltage33:1; // bit 24 + UINT32 Voltage30:1; // bit 25 + UINT32 Voltage18:1; // bit 26 + UINT32 Reserved3:1; // bit 27 + UINT32 SysBus64:1; // bit 28 + UINT32 AsyncInt:1; // bit 29 + UINT32 SlotType:2; // bit 30:31 + UINT32 Sdr50:1; // bit 32 + UINT32 Sdr104:1; // bit 33 + UINT32 Ddr50:1; // bit 34 + UINT32 Reserved4:1; // bit 35 + UINT32 DriverTypeA:1; // bit 36 + UINT32 DriverTypeC:1; // bit 37 + UINT32 DriverTypeD:1; // bit 38 + UINT32 DriverType4:1; // bit 39 + UINT32 TimerCount:4; // bit 40:43 + UINT32 Reserved5:1; // bit 44 + UINT32 TuningSDR50:1; // bit 45 + UINT32 RetuningMod:2; // bit 46:47 + UINT32 ClkMultiplier:8; // bit 48:55 + UINT32 Reserved6:7; // bit 56:62 + UINT32 Hs400:1; // bit 63 +} SD_MMC_HC_SLOT_CAP; + +/** + Dump the content of SD/MMC host controller's Capability Register. + + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Capability The buffer to store the capability data. + +**/ +VOID +DumpCapabilityReg ( + IN UINT8 Slot, + IN SD_MMC_HC_SLOT_CAP *Capability + ); + +/** + Read SlotInfo register from SD/MMC host controller pci config space. + + @param[in] PciIo The PCI IO protocol instance. + @param[out] FirstBar The buffer to store the first BAR value. + @param[out] SlotNum The buffer to store the supported slot number. + + @retval EFI_SUCCESS The operation succeeds. + @retval Others The operation fails. + +**/ +EFI_STATUS +EFIAPI +SdMmcHcGetSlotInfo ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + OUT UINT8 *FirstBar, + OUT UINT8 *SlotNum + ); + +/** + Read/Write specified SD/MMC host controller mmio register. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] BarIndex The BAR index of the standard PCI Configuration + header to use as the base address for the memory + operation to perform. + @param[in] Offset The offset within the selected BAR to start the + memory operation. + @param[in] Read A boolean to indicate it's read or write operation. + @param[in] Count The width of the mmio register in bytes. + Must be 1, 2 , 4 or 8 bytes. + @param[in, out] Data For read operations, the destination buffer to store + the results. For write operations, the source buffer + to write data from. The caller is responsible for + having ownership of the data buffer and ensuring its + size not less than Count bytes. + + @retval EFI_INVALID_PARAMETER The PciIo or Data is NULL or the Count is not valid. + @retval EFI_SUCCESS The read/write operation succeeds. + @retval Others The read/write operation fails. + +**/ +EFI_STATUS +EFIAPI +SdMmcHcRwMmio ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 BarIndex, + IN UINT32 Offset, + IN BOOLEAN Read, + IN UINT8 Count, + IN OUT VOID *Data + ); + +/** + Do OR operation with the value of the specified SD/MMC host controller mmio register. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] BarIndex The BAR index of the standard PCI Configuration + header to use as the base address for the memory + operation to perform. + @param[in] Offset The offset within the selected BAR to start the + memory operation. + @param[in] Count The width of the mmio register in bytes. + Must be 1, 2 , 4 or 8 bytes. + @param[in] OrData The pointer to the data used to do OR operation. + The caller is responsible for having ownership of + the data buffer and ensuring its size not less than + Count bytes. + + @retval EFI_INVALID_PARAMETER The PciIo or OrData is NULL or the Count is not valid. + @retval EFI_SUCCESS The OR operation succeeds. + @retval Others The OR operation fails. + +**/ +EFI_STATUS +EFIAPI +SdMmcHcOrMmio ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 BarIndex, + IN UINT32 Offset, + IN UINT8 Count, + IN VOID *OrData + ); + +/** + Do AND operation with the value of the specified SD/MMC host controller mmio register. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] BarIndex The BAR index of the standard PCI Configuration + header to use as the base address for the memory + operation to perform. + @param[in] Offset The offset within the selected BAR to start the + memory operation. + @param[in] Count The width of the mmio register in bytes. + Must be 1, 2 , 4 or 8 bytes. + @param[in] AndData The pointer to the data used to do AND operation. + The caller is responsible for having ownership of + the data buffer and ensuring its size not less than + Count bytes. + + @retval EFI_INVALID_PARAMETER The PciIo or AndData is NULL or the Count is not valid. + @retval EFI_SUCCESS The AND operation succeeds. + @retval Others The AND operation fails. + +**/ +EFI_STATUS +EFIAPI +SdMmcHcAndMmio ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 BarIndex, + IN UINT32 Offset, + IN UINT8 Count, + IN VOID *AndData + ); + +/** + Wait for the value of the specified MMIO register set to the test value. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] BarIndex The BAR index of the standard PCI Configuration + header to use as the base address for the memory + operation to perform. + @param[in] Offset The offset within the selected BAR to start the + memory operation. + @param[in] Count The width of the mmio register in bytes. + Must be 1, 2, 4 or 8 bytes. + @param[in] MaskValue The mask value of memory. + @param[in] TestValue The test value of memory. + @param[in] Timeout The time out value for wait memory set, uses 1 + microsecond as a unit. + + @retval EFI_TIMEOUT The MMIO register hasn't expected value in timeout + range. + @retval EFI_SUCCESS The MMIO register has expected value. + @retval Others The MMIO operation fails. + +**/ +EFI_STATUS +EFIAPI +SdMmcHcWaitMmioSet ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 BarIndex, + IN UINT32 Offset, + IN UINT8 Count, + IN UINT64 MaskValue, + IN UINT64 TestValue, + IN UINT64 Timeout + ); + +/** + Software reset the specified SD/MMC host controller. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS The software reset executes successfully. + @retval Others The software reset fails. + +**/ +EFI_STATUS +SdMmcHcReset ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot + ); + +/** + Set all interrupt status bits in Normal and Error Interrupt Status Enable + register. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS The operation executes successfully. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdMmcHcEnableInterrupt ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot + ); + +/** + Get the capability data from the specified slot. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[out] Capability The buffer to store the capability data. + + @retval EFI_SUCCESS The operation executes successfully. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdMmcHcGetCapability ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + OUT SD_MMC_HC_SLOT_CAP *Capability + ); + +/** + Get the maximum current capability data from the specified slot. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[out] MaxCurrent The buffer to store the maximum current capability data. + + @retval EFI_SUCCESS The operation executes successfully. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdMmcHcGetMaxCurrent ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + OUT UINT64 *MaxCurrent + ); + +/** + Detect whether there is a SD/MMC card attached at the specified SD/MMC host controller + slot. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[out] MediaPresent The pointer to the media present boolean value. + + @retval EFI_SUCCESS There is no media change happened. + @retval EFI_MEDIA_CHANGED There is media change happened. + @retval Others The detection fails. + +**/ +EFI_STATUS +SdMmcHcCardDetect ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + OUT BOOLEAN *MediaPresent + ); + +/** + Stop SD/MMC card clock. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS Succeed to stop SD/MMC clock. + @retval Others Fail to stop SD/MMC clock. + +**/ +EFI_STATUS +SdMmcHcStopClock ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot + ); + +/** + SD/MMC card clock supply. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] ClockFreq The max clock frequency to be set. The unit is KHz. + @param[in] Capability The capability of the slot. + + @retval EFI_SUCCESS The clock is supplied successfully. + @retval Others The clock isn't supplied successfully. + +**/ +EFI_STATUS +SdMmcHcClockSupply ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN UINT64 ClockFreq, + IN SD_MMC_HC_SLOT_CAP Capability + ); + +/** + SD/MMC bus power control. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] PowerCtrl The value setting to the power control register. + + @retval TRUE There is a SD/MMC card attached. + @retval FALSE There is no a SD/MMC card attached. + +**/ +EFI_STATUS +SdMmcHcPowerControl ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN UINT8 PowerCtrl + ); + +/** + Set the SD/MMC bus width. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] BusWidth The bus width used by the SD/MMC device, it must be 1, 4 or 8. + + @retval EFI_SUCCESS The bus width is set successfully. + @retval Others The bus width isn't set successfully. + +**/ +EFI_STATUS +SdMmcHcSetBusWidth ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN UINT16 BusWidth + ); + +/** + Supply SD/MMC card with lowest clock frequency at initialization. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Capability The capability of the slot. + + @retval EFI_SUCCESS The clock is supplied successfully. + @retval Others The clock isn't supplied successfully. + +**/ +EFI_STATUS +SdMmcHcInitClockFreq ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN SD_MMC_HC_SLOT_CAP Capability + ); + +/** + Supply SD/MMC card with maximum voltage at initialization. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Capability The capability of the slot. + + @retval EFI_SUCCESS The voltage is supplied successfully. + @retval Others The voltage isn't supplied successfully. + +**/ +EFI_STATUS +SdMmcHcInitPowerVoltage ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN SD_MMC_HC_SLOT_CAP Capability + ); + +/** + Initialize the Timeout Control register with most conservative value at initialization. + + Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS The timeout control register is configured successfully. + @retval Others The timeout control register isn't configured successfully. + +**/ +EFI_STATUS +SdMmcHcInitTimeoutCtrl ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot + ); + +/** + Initial SD/MMC host controller with lowest clock frequency, max power and max timeout value + at initialization. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Capability The capability of the slot. + + @retval EFI_SUCCESS The host controller is initialized successfully. + @retval Others The host controller isn't initialized successfully. + +**/ +EFI_STATUS +SdMmcHcInitHost ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN SD_MMC_HC_SLOT_CAP Capability + ); + +#endif diff --git a/Platform/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.c b/Platform/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.c new file mode 100755 index 0000000000..31f207eabf --- /dev/null +++ b/Platform/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.c @@ -0,0 +1,665 @@ +/******************************************************************************* +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include "XenonSdhci.h" + +STATIC +VOID +XenonReadVersion ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + OUT UINT32 *ControllerVersion + ) +{ + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CTRL_VER, TRUE, SDHC_REG_SIZE_2B, ControllerVersion); +} + +STATIC +VOID +XenonSetFifo ( + IN EFI_PCI_IO_PROTOCOL *PciIo + ) +{ + UINTN Data; + + // Set FIFO_RTC, FIFO_WTC, FIFO_CS and FIFO_PDLVMC + Data = SDHC_SLOT_FIFO_DEFAULT_CONFIG; + + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SLOT_FIFO_CTRL, FALSE, SDHC_REG_SIZE_4B, &Data); +} + +// Auto Clock Gating +STATIC +VOID +XenonSetAcg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN BOOLEAN Enable + ) +{ + UINT32 Var; + + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SYS_OP_CTRL, TRUE, SDHC_REG_SIZE_4B, &Var); + + if (Enable) { + Var &= ~AUTO_CLKGATE_DISABLE_MASK; + } else { + Var |= AUTO_CLKGATE_DISABLE_MASK; + } + + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SYS_OP_CTRL, FALSE, SDHC_REG_SIZE_4B, &Var); +} + +STATIC +VOID +XenonSetSlot ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN BOOLEAN Enable + ) +{ + UINT32 Var; + + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SYS_OP_CTRL, TRUE, SDHC_REG_SIZE_4B, &Var); + if (Enable) { + Var |= ((0x1 << Slot) << SLOT_ENABLE_SHIFT); + } else { + Var &= ~((0x1 << Slot) << SLOT_ENABLE_SHIFT); + } + + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SYS_OP_CTRL, FALSE, SDHC_REG_SIZE_4B, &Var); +} + +// +// Stub function, which will in future be responsible for +// setting SDIO controller in either HIGH (if Voltage parameter +// is equal 1) or LOW (if Voltage is equal 0) +// +STATIC +VOID +XenonSetSdio ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINTN Voltage + ) +{ + // Currently SDIO isn't supported + return; +} + +STATIC +VOID +XenonSetPower ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 Vcc, + IN UINT32 Vccq, + IN UINT8 Mode + ) +{ + UINT8 Pwr = 0; + UINT32 Ctrl = 0; + + // Below statement calls routine to set voltage for SDIO devices in either HIGH (1) or LOW (0) mode + switch (Vcc) { + case MMC_VDD_165_195: + Pwr = SDHCI_POWER_180; + if (Mode == XENON_MMC_MODE_SD_SDIO) { + XenonSetSdio (PciIo, 0); + } + break; + case MMC_VDD_29_30: + case MMC_VDD_30_31: + Pwr = SDHCI_POWER_300; + if (Mode == XENON_MMC_MODE_SD_SDIO) { + XenonSetSdio (PciIo, 1); + } + break; + case MMC_VDD_32_33: + case MMC_VDD_33_34: + Pwr = SDHCI_POWER_330; + if (Mode == XENON_MMC_MODE_SD_SDIO) { + XenonSetSdio (PciIo, 1); + } + break; + default: + DEBUG((DEBUG_ERROR, "SD/MMC: Does not support power mode(0x%X)\n", Vcc)); + break; + } + + if (Pwr == 0) { + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_POWER_CTRL, FALSE, SDHC_REG_SIZE_1B, &Pwr); + return; + } + + Pwr |= SDHCI_POWER_ON; + + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX,SD_MMC_HC_POWER_CTRL, FALSE, SDHC_REG_SIZE_1B, &Pwr); + + // Set VCCQ + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SLOT_eMMC_CTRL, TRUE, SDHC_REG_SIZE_4B, &Ctrl); + Ctrl |= Vccq; + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SLOT_eMMC_CTRL, FALSE, SDHC_REG_SIZE_4B, &Ctrl); +} + +UINTN +XenonSetClk ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN UINT32 Clock + ) +{ + UINT32 Div; + UINT32 Clk; + UINT32 Retry; + UINT16 Value = 0; + + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, SDHC_REG_SIZE_2B, &Value); + + if (Clock == 0) { + return 0; + } + + if (Private->ControllerVersion >= SDHCI_SPEC_300) { + // Version 3.00 Divisors must be a multiple of 2 + if (XENON_MMC_MAX_CLK <= Clock) { + Div = 1; + } else { + for (Div = 2; Div < SDHCI_MAX_DIV_SPEC_300; Div += 2) { + if ((XENON_MMC_MAX_CLK / Div) <= Clock) + break; + } + } + } else { + // Version 2.00 Divisors must be a power of 2 + for (Div = 1; Div < SDHCI_MAX_DIV_SPEC_200; Div *= 2) { + if ((XENON_MMC_MAX_CLK / Div) <= Clock) + break; + } + } + Div >>= 1; + + Clk = (Div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT; + Clk |= ((Div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN) << SDHCI_DIVIDER_HI_SHIFT; + Clk |= SDHCI_CLOCK_INT_EN; + + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, SDHC_REG_SIZE_2B, &Clk); + + // + // Poll for internal controller clock to be stabilised + // Wait up to 200us for this to occur + // + Retry = 200; + + do { + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, TRUE, SDHC_REG_SIZE_2B, &Clk); + if (Retry == 0) { + DEBUG((DEBUG_ERROR, "SD/MMC: Internal Clock never stabilised\n")); + return -1; + } + + Retry--; + + // Wait for internal clock to be stabilised + gBS->Stall (1); + + } while (!(Clk & SDHCI_CLOCK_INT_STABLE)); + + Clk |= SDHCI_CLOCK_CARD_EN; + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, SDHC_REG_SIZE_2B, &Clk); + + return 0; +} + +VOID +XenonPhyInit ( + IN EFI_PCI_IO_PROTOCOL *PciIo + ) +{ + UINT32 Var, Wait, Time; + UINT32 Clock = XENON_MMC_MAX_CLK; + UINT16 ClkCtrl; + + // Need to disable the clock to set EMMC_PHY_TIMING_ADJUST register + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, TRUE, SDHC_REG_SIZE_2B, &ClkCtrl); + ClkCtrl &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN); + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, SDHC_REG_SIZE_2B, &ClkCtrl); + + // Enable QSP PHASE SELECT + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, SDHC_REG_SIZE_4B, &Var); + Var |= SAMPL_INV_QSP_PHASE_SELECT; + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, FALSE, SDHC_REG_SIZE_4B, &Var); + + // Enable internal clock + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, TRUE, SDHC_REG_SIZE_2B, &ClkCtrl); + ClkCtrl |= SDHCI_CLOCK_INT_EN; + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, SDHC_REG_SIZE_2B, &ClkCtrl); + + // + // Poll for host MMC PHY clock init to be stable + // Wait up to 100us + // + Time = 100; + while (Time--) { + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, SDHC_REG_SIZE_4B, &Var); + if (Var & SDHCI_CLOCK_INT_STABLE) { + break; + } + + // Poll interval for MMC PHY clock to be stable is 1us + gBS->Stall (1); + } + if (Time <= 0) { + DEBUG((DEBUG_ERROR, "SD/MMC: Failed to enable MMC internal clock in Time\n")); + return; + } + + // Enable bus clock + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, TRUE, SDHC_REG_SIZE_2B, &ClkCtrl); + ClkCtrl |= SDHCI_CLOCK_CARD_EN; + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, SDHC_REG_SIZE_2B, &ClkCtrl); + + // Delay 200us to wait for the completion of bus clock + gBS->Stall (200); + + // Init PHY + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, SDHC_REG_SIZE_4B, &Var); + Var |= PHY_INITIALIZAION; + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, FALSE, SDHC_REG_SIZE_4B, &Var); + + // Add duration of FC_SYNC_RST + Wait = ((Var >> FC_SYNC_RST_DURATION_SHIFT) & FC_SYNC_RST_DURATION_MASK); + + // Add interval between FC_SYNC_EN and FC_SYNC_RST + Wait += ((Var >> FC_SYNC_RST_EN_DURATION_SHIFT) & FC_SYNC_RST_EN_DURATION_MASK); + + // Add duration of asserting FC_SYNC_EN + Wait += ((Var >> FC_SYNC_EN_DURATION_SHIFT) & FC_SYNC_EN_DURATION_MASK); + + // Add duration of Waiting for PHY + Wait += ((Var >> WAIT_CYCLE_BEFORE_USING_SHIFT) & WAIT_CYCLE_BEFORE_USING_MASK); + + // 4 addtional bus clock and 4 AXI bus clock are required left shift 20 bits + Wait += 8; + Wait <<= 20; + + // Use the possibly slowest bus frequency value + if (Clock == 0) { + Clock = XENON_MMC_MIN_CLK; + } + + // Get the Wait Time in unit of ms + Wait = Wait / Clock; + Wait++; + + // Poll for host eMMC PHY init to complete, wait up to 100us + Time = 100; + while (Time--) { + Var = SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, SDHC_REG_SIZE_4B, &Var); + Var &= PHY_INITIALIZAION; + if (!Var) { + break; + } + + // Wait for host eMMC PHY init to complete + gBS->Stall (1); + } + + if (Time <= 0) { + DEBUG((DEBUG_ERROR, "SD/MMC: Failed to init MMC PHY in Time\n")); + return; + } + + return; +} + +STATIC +VOID +XenonSetPhy ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + UINT8 Timing + ) +{ + UINT32 Var = 0; + + // Setup pad, set bit[30], bit[28] and bits[26:24] + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_PAD_CONTROL, TRUE, SDHC_REG_SIZE_4B, &Var); + Var |= (AUTO_RECEN_CTRL | OEN_QSN | FC_QSP_RECEN | FC_CMD_RECEN | FC_DQ_RECEN); + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_PAD_CONTROL, FALSE, SDHC_REG_SIZE_4B, &Var); + + // + // If Timing belongs to high speed, set bit[17] of + // EMMC_PHY_TIMING_ADJUST register + // + if ((Timing == MMC_TIMING_MMC_HS400) || + (Timing == MMC_TIMING_MMC_HS200) || + (Timing == MMC_TIMING_UHS_SDR50) || + (Timing == MMC_TIMING_UHS_SDR104) || + (Timing == MMC_TIMING_UHS_DDR50) || + (Timing == MMC_TIMING_UHS_SDR25)) { + + SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, SDHC_REG_SIZE_4B, &Var); + + // Set SLOW_MODE for PHY + Var |= OUTPUT_QSN_PHASE_SELECT | QSN_PHASE_SLOW_MODE_BIT; + SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, FALSE, SDHC_REG_SIZE_4B, &Var); + } + + SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, TRUE, SDHC_REG_SIZE_4B, &Var); + Var |= (DQ_DDR_MODE_MASK << DQ_DDR_MODE_SHIFT) | CMD_DDR_MODE; + SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, FALSE, SDHC_REG_SIZE_4B, &Var); + + if (Timing == MMC_TIMING_MMC_HS400) { + SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, TRUE, SDHC_REG_SIZE_4B, &Var); + Var &= ~DQ_ASYNC_MODE; + SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, FALSE, SDHC_REG_SIZE_4B, &Var); + + Var = LOGIC_TIMING_VALUE; + SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_LOGIC_TIMING_ADJUST, FALSE, SDHC_REG_SIZE_4B, &Var); + } + + XenonPhyInit (PciIo); +} + +STATIC +VOID +XenonConfigureInterrupts ( + IN EFI_PCI_IO_PROTOCOL *PciIo + ) +{ + UINT32 Var; + + // Clear interrupt status + Var = SDHC_CLR_ALL_IRQ_MASK; + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_NOR_INT_STS, FALSE, SDHC_REG_SIZE_4B, &Var); + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_NOR_INT_STS, FALSE, SDHC_REG_SIZE_4B, &Var); + + // Enable only interrupts served by the SD controller + Var = SDHC_CLR_ALL_IRQ_MASK & ~(NOR_INT_STS_CARD_INS | NOR_INT_STS_CARD_INT); + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_NOR_INT_STS_EN, FALSE, SDHC_REG_SIZE_4B, &Var); + + // Mask all sdhci interrupt sources + Var = SDHC_CLR_ALL_IRQ_MASK & ~NOR_INT_SIG_EN_CARD_INT; + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_NOR_INT_SIG_EN, FALSE, SDHC_REG_SIZE_4B, &Var); +} + +// Enable Parallel Transfer Mode +STATIC +VOID +XenonSetParallelTransfer ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN BOOLEAN Enable + ) +{ + UINT32 Var; + + SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHC_SYS_EXT_OP_CTRL, TRUE, SDHC_REG_SIZE_4B, &Var); + + if (Enable) { + Var |= (0x1 << Slot); + } else { + Var &= ~(0x1 << Slot); + } + + SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHC_SYS_EXT_OP_CTRL, FALSE, SDHC_REG_SIZE_4B, &Var); +} + +STATIC +VOID +XenonSetTuning ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN BOOLEAN Enable + ) +{ + UINT32 Var; + + // Set the Re-Tuning Request functionality + SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHC_SLOT_RETUNING_REQ_CTRL, TRUE, SDHC_REG_SIZE_4B, &Var); + + if (Enable) { + Var |= RETUNING_COMPATIBLE; + } else { + Var &= ~RETUNING_COMPATIBLE; + } + + SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHC_SLOT_RETUNING_REQ_CTRL, FALSE, SDHC_REG_SIZE_4B, &Var); + + // Set the Re-tuning Event Signal Enable + SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHCI_SIGNAL_ENABLE, TRUE, SDHC_REG_SIZE_4B, &Var); + + if (Enable) { + Var |= SDHCI_RETUNE_EVT_INTSIG; + } else { + Var &= ~SDHCI_RETUNE_EVT_INTSIG; + } + + SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHCI_SIGNAL_ENABLE, FALSE, SDHC_REG_SIZE_4B, &Var); +} + +VOID +XenonReset ( + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN UINT8 Slot, + IN UINT8 Mask + ) +{ + UINT32 Retry = 1000; + UINT8 SwReset; + + SwReset = Mask; + + SdMmcHcRwMmio ( + Private->PciIo, + Slot, + SD_MMC_HC_SW_RST, + FALSE, + sizeof (SwReset), + &SwReset + ); + + SdMmcHcRwMmio ( + Private->PciIo, + Slot, + SD_MMC_HC_SW_RST, + TRUE, + sizeof (SwReset), + &SwReset + ); + + while (SwReset & Mask) { + if (Retry == 0) { + DEBUG((DEBUG_ERROR, "SD/MMC: Reset never completed\n")); + return; + } + + Retry--; + + // Poll interval for SwReset is 100us according to SDHCI spec + gBS-> Stall (100); + SdMmcHcRwMmio ( + Private->PciIo, + Slot, + SD_MMC_HC_SW_RST, + TRUE, + sizeof (SwReset), + &SwReset + ); + } +} + +STATIC +VOID +XenonTransferPio ( + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN UINT8 Slot, + IN OUT VOID *Buffer, + IN UINT16 BlockSize, + IN BOOLEAN Read + ) +{ + UINTN Index; + UINT8 *Offs; + + // + // SD stack's intrinsic functions cannot perform properly reading/writing from + // buffer register, that is why MmioRead/MmioWrite are used. It is temporary + // solution. + // + for (Index = 0; Index < BlockSize; Index += 4) { + Offs = Buffer + Index; + if (Read) { + *(UINT32 *)Offs = MmioRead32 (SDHC_DAT_BUF_PORT_ADDR); + } else { + MmioWrite32 (SDHC_DAT_BUF_PORT_ADDR, *(UINT32 *)Offs); + } + } +} + +EFI_STATUS +XenonTransferData ( + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN UINT8 Slot, + IN OUT VOID *Buffer, + IN UINT32 DataLen, + IN UINT16 BlockSize, + IN UINT16 Blocks, + IN BOOLEAN Read + ) +{ + UINT32 IntStatus, PresentState, Rdy, Mask, Retry, Block = 0; + + if (Buffer == NULL) { + return EFI_DEVICE_ERROR; + } + + Retry = SDHC_INT_STATUS_POLL_RETRY_DATA_TRAN; + Rdy = NOR_INT_STS_TX_RDY | NOR_INT_STS_RX_RDY; + Mask = PRESENT_STATE_BUFFER_RD_EN | PRESENT_STATE_BUFFER_WR_EN; + + do { + SdMmcHcRwMmio ( + Private->PciIo, + Slot, + SD_MMC_HC_NOR_INT_STS, + TRUE, + sizeof (IntStatus), + &IntStatus + ); + + if (IntStatus & NOR_INT_STS_ERR_INT) { + DEBUG((DEBUG_INFO, "SD/MMC: Error detected in status %0x\n", IntStatus)); + return EFI_DEVICE_ERROR; + } + + if (IntStatus & Rdy) { + SdMmcHcRwMmio ( + Private->PciIo, + Slot, + SD_MMC_HC_PRESENT_STATE, + TRUE, + sizeof (PresentState), + &PresentState + ); + + if (!(PresentState & Mask)) { + continue; + } + + SdMmcHcRwMmio ( + Private->PciIo, + Slot, + SD_MMC_HC_NOR_INT_STS, + FALSE, + sizeof (Rdy), + &Rdy + ); + + XenonTransferPio (Private, Slot, Buffer, BlockSize, Read); + + Buffer += BlockSize; + if (++Block >= Blocks) { + break; + } + } + + if (Retry-- > 0) { + + // Poll interval for data transfer complete bit in NOR_INT_STS register is 10us + gBS->Stall (10); + } else { + DEBUG((DEBUG_INFO, "SD/MMC: Transfer data timeout\n")); + return EFI_TIMEOUT; + } + } while (!(IntStatus & NOR_INT_STS_XFER_COMPLETE)); + + return EFI_SUCCESS; +} + +EFI_STATUS +XenonInit ( + IN SD_MMC_HC_PRIVATE_DATA *Private + ) +{ + EFI_PCI_IO_PROTOCOL *PciIo = Private->PciIo; + + // Read XENON version + XenonReadVersion (PciIo, &Private->ControllerVersion); + + XenonSetFifo (PciIo); + + // Disable auto clock generator + XenonSetAcg (PciIo, FALSE); + + // XENON has only one port + XenonSetSlot (PciIo, XENON_MMC_SLOT_ID, TRUE); + + XenonSetPower (PciIo, MMC_VDD_165_195, eMMC_VCCQ_1_8V, XENON_MMC_MODE_SD_SDIO); + + // Set MAX_CLOCK for configuring PHY + XenonSetClk (PciIo, Private, XENON_MMC_MAX_CLK); + XenonSetPhy (PciIo, MMC_TIMING_UHS_SDR50); + + XenonConfigureInterrupts (PciIo); + + // Enable parallel transfer + XenonSetParallelTransfer (PciIo, XENON_MMC_SLOT_ID, TRUE); + XenonSetTuning (PciIo, XENON_MMC_SLOT_ID, FALSE); + + // Enable auto clock generator + XenonSetAcg (PciIo, TRUE); + + // Set proper clock for PHY configuration + XenonSetClk (PciIo, Private, XENON_MMC_BASE_CLK); + XenonPhyInit (PciIo); + + return EFI_SUCCESS; +} diff --git a/Platform/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.h b/Platform/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.h new file mode 100644 index 0000000000..2be0ee61e1 --- /dev/null +++ b/Platform/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.h @@ -0,0 +1,346 @@ +/******************************************************************************* +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include "SdMmcPciHcDxe.h" + +#include + +#define SD_BAR_INDEX 0 + +#define SIZE_512B 0x200 + +/* Register Offset of SD Host Controller SOCP self-defined register */ + +#define SDHC_IPID 0x0100 +#define SDHC_SYS_CFG_INFO 0x0104 +#define SLOT_TYPE_SDIO_SHIFT 24 +#define SLOT_TYPE_EMMC_MASK 0xff +#define SLOT_TYPE_EMMC_SHIFT 16 +#define SLOT_TYPE_SD_SDIO_MMC_MASK 0xff +#define SLOT_TYPE_SD_SDIO_MMC_SHIFT 8 + +#define SDHC_SYS_OP_CTRL 0x0108 +#define AUTO_CLKGATE_DISABLE_MASK (0x1<<20) +#define SDCLK_IDLEOFF_ENABLE_SHIFT 8 +#define SLOT_ENABLE_SHIFT 0 + +#define SDHC_SYS_EXT_OP_CTRL 0x010c +#define SDHC_TEST_OUT 0x0110 +#define SDHC_TESTOUT_MUXSEL 0x0114 + +#define SDHC_SLOT_EXT_INT_STATUS 0x0120 +#define SDHC_SLOT_EXT_ERR_STATUS 0x0122 +#define SDHC_SLOT_EXT_INT_STATUS_EN 0x0124 +#define SDHC_SLOT_EXT_ERR_STATUS_EN 0x0126 + +#define SDHC_SLOT_OP_STATUS_CTRL 0x0128 +#define TUNING_PROG_FIXED_DELAY_MASK 0x7ff +#define FORCE_SEL_INVERSE_CLK_SHIFT 11 + +#define SDHC_SLOT_FIFO_CTRL 0x012c +#define SDHC_SLOT_FIFO_DEFAULT_CONFIG 0x315 + +#define SDHC_SLOT_eMMC_CTRL 0x0130 +#define ENABLE_DATA_STROBE_SHIFT 24 +#define SET_EMMC_RSTN_SHIFT 16 +#define eMMC_VCCQ_MASK 0x3 +#define eMMC_VCCQ_1_8V 0x1 +#define eMMC_VCCQ_1_2V 0x2 +#define eMMC_VCCQ_3_3V 0x3 + +#define SDHC_SLOT_OUTPUT_DLY_CTRL 0x0134 +#define SDHC_SLOT_DCM_CTRL 0x0137 + +#define SDHC_SLOT_DLL_CTRL 0x0138 +#define SELECT_DEF_DLL 0x1 + +#define SDHC_SLOT_DLL_PHASE_SEL 0x013c +#define DLL_UPDATE_STROBE 7 + +#define SDHC_SLOT_STROBE_DLY_CTRL 0x0140 +#define STROBE_DELAY_FIXED_MASK 0xffff + +#define SDHC_SLOT_RETUNING_REQ_CTRL 0x0144 +#define RETUNING_COMPATIBLE 0x1 + +#define SDHC_SLOT_AUTO_RETUNING_CTRL 0x0148 +#define ENABLE_AUTO_RETUNING 0x1 + +#define SDHC_SLOT_EXT_PRESENT_STATE 0x014c +#define SDHC_SLOT_DLL_CUR_DLY_VAL 0x0150 +#define SDHC_SLOT_TUNING_CUR_DLY_VAL 0x0154 +#define SDHC_SLOT_STROBE_CUR_DLY_VAL 0x0158 +#define SDHC_SLOT_SUB_CMD_STRL 0x015c + +#define SDHC_SLOT_CQ_TASK_INFO 0x0160 + +#define SDHC_SLOT_TUNING_DEBUG_INFO 0x01f0 +#define SDHC_SLOT_DATAIN_DEBUG_INFO 0x01f4 + +#define SDHC_CMD_RESET_BIT (1 << 1) +#define SDHC_DATA_RESET_BIT (1 << 2) + +#define SDHC_CMD_INHIBIT (1 << 0) +#define SDHC_DATA_INHIBIT (1 << 1) + +#define SDHC_REG_SIZE_1B 1 +#define SDHC_REG_SIZE_2B 2 +#define SDHC_REG_SIZE_4B 4 + +#define SDHC_DAT_BUF_PORT_ADDR 0xF06E0020 + +/* Command register bits description */ +#define RESP_TYPE_136_BITS (1 << 0) +#define RESP_TYPE_48_BITS (1 << 1) +#define RESP_TYPE_48_BITS_NO_CRC ((1 << 0) | (1 << 1)) +#define CMD_CRC_CHK_EN (1 << 3) +#define CMD_INDEX_CHK_EN (1 << 4) +#define DATA_PRESENT (1 << 5) + +/* Transfer mode register bits description */ +#define SDHC_TRNS_BLK_CNT_EN (1 << 1) +#define SDHC_TRNS_MULTI_BLK_SEL (1 << 5) +#define SDHC_TRNS_TO_HOST_DIR (1 << 4) + +/* Block size register bits description */ +#define BLK_SIZE_HOST_DMA_BDRY_OFFSET 12 +#define BLK_SIZE_512KB 0x7 + +/* Int status register bits description */ +#define NOR_INT_STS_CMD_COMPLETE (1 << 0) +#define NOR_INT_STS_XFER_COMPLETE (1 << 1) +#define NOR_INT_STS_TX_RDY (1 << 4) +#define NOR_INT_STS_RX_RDY (1 << 5) +#define NOR_INT_STS_CARD_INS (1 << 6) +#define NOR_INT_STS_CARD_INT (1 << 8) +#define NOR_INT_STS_ERR_INT (1 << 15) +#define ERR_INT_STS_CMD_TIMEOUT_ERR (1 << 16) +#define ERR_INT_STS_DATA_TIMEOUT_ERR (1 << 20) + +#define NOR_INT_SIG_EN_CARD_INT (1 << 8) + +#define PRESENT_STATE_BUFFER_RD_EN (1 << 11) +#define PRESENT_STATE_BUFFER_WR_EN (1 << 10) + +#define SDHC_CLR_IRQ_STS_MASK 0xFFFF +#define SDHC_CLR_ALL_IRQ_MASK 0xFFFFFFFFUL + +/* Max clock in Hz */ +#define XENON_MMC_MAX_CLK 400000000 +#define XENON_MMC_CLK_RATIO 2046 +#define XENON_MMC_BASE_CLK XENON_MMC_MAX_CLK / XENON_MMC_CLK_RATIO +#define XENON_MMC_MIN_CLK 100000 + +#define XENON_MMC_CMD_MAX_TIMEOUT 3200 +#define XENON_MMC_CMD_DEFAULT_TIMEOUT 100 + +/* Tuning Parameter */ +#define TMR_RETUN_NO_PRESENT 0xf +#define XENON_MAX_TUN_COUNT 0xb + +#define EMMC_PHY_REG_BASE 0x170 +#define EMMC_PHY_TIMING_ADJUST EMMC_PHY_REG_BASE +#define OUTPUT_QSN_PHASE_SELECT (1 << 17) +#define SAMPL_INV_QSP_PHASE_SELECT (1 << 18) +#define SAMPL_INV_QSP_PHASE_SELECT_SHIFT 18 +#define PHY_INITIALIZAION (1 << 31) +#define WAIT_CYCLE_BEFORE_USING_MASK 0xf +#define WAIT_CYCLE_BEFORE_USING_SHIFT 12 +#define FC_SYNC_EN_DURATION_MASK 0xf +#define FC_SYNC_EN_DURATION_SHIFT 8 +#define FC_SYNC_RST_EN_DURATION_MASK 0xf +#define FC_SYNC_RST_EN_DURATION_SHIFT 4 +#define FC_SYNC_RST_DURATION_MASK 0xf +#define FC_SYNC_RST_DURATION_SHIFT 0 + +#define EMMC_PHY_FUNC_CONTROL (EMMC_PHY_REG_BASE + 0x4) +#define DQ_ASYNC_MODE (1 << 4) +#define DQ_DDR_MODE_SHIFT 8 +#define DQ_DDR_MODE_MASK 0xff +#define CMD_DDR_MODE (1 << 16) + +#define EMMC_PHY_PAD_CONTROL (EMMC_PHY_REG_BASE + 0x8) +#define REC_EN_SHIFT 24 +#define REC_EN_MASK 0xf +#define FC_DQ_RECEN (1 << 24) +#define FC_CMD_RECEN (1 << 25) +#define FC_QSP_RECEN (1 << 26) +#define FC_QSN_RECEN (1 << 27) +#define OEN_QSN (1 << 28) +#define AUTO_RECEN_CTRL (1 << 30) + +#define EMMC_PHY_PAD_CONTROL1 (EMMC_PHY_REG_BASE + 0xc) +#define EMMC_PHY_PAD_CONTROL2 (EMMC_PHY_REG_BASE + 0x10) +#define EMMC_PHY_DLL_CONTROL (EMMC_PHY_REG_BASE + 0x14) +#define DLL_DELAY_TEST_LOWER_SHIFT 8 +#define DLL_DELAY_TEST_LOWER_MASK 0xff +#define DLL_BYPASS_EN 0x1 + +#define EMMC_LOGIC_TIMING_ADJUST (EMMC_PHY_REG_BASE + 0x18) +#define EMMC_LOGIC_TIMING_ADJUST_LOW (EMMC_PHY_REG_BASE + 0x1c) + +#define LOGIC_TIMING_VALUE 0x5a54 /* Recommend by HW team */ + +#define QSN_PHASE_SLOW_MODE_BIT (1 << 29) + +/* XENON only have one slot 0 */ +#define XENON_MMC_SLOT_ID (0) + +#define MMC_TIMING_LEGACY 0 +#define MMC_TIMING_MMC_HS 1 +#define MMC_TIMING_SD_HS 2 +#define MMC_TIMING_UHS_SDR12 3 +#define MMC_TIMING_UHS_SDR25 4 +#define MMC_TIMING_UHS_SDR50 5 +#define MMC_TIMING_UHS_SDR104 6 +#define MMC_TIMING_UHS_DDR50 7 +#define MMC_TIMING_MMC_HS200 8 +#define MMC_TIMING_MMC_HS400 10 + +/* Data time out default value 0xE: TMCLK x 227 */ +#define DATA_TIMEOUT_DEF_VAL 0xE + +/* Max retry count for INT status ready */ +#define SDHC_INT_STATUS_POLL_RETRY 1000 +#define SDHC_INT_STATUS_POLL_RETRY_DATA_TRAN 100000 + +/* Take 2.5 seconds as generic time out value, 1 microsecond as unit */ +#define SD_GENERIC_TIMEOUT 2500 * 1000 + +/* SDMA start address should allign with 0x8, align mask 0x7 */ +#define DMA_START_ADDR_ALIGN_MASK 0x7 + +#define SDHCI_RETUNE_EVT_INTSIG 0x00001000 + +/* MMC modes */ +#define XENON_MMC_MODE_EMMC 0 +#define XENON_MMC_MODE_SD_SDIO 1 + +/* MMC Voltage */ +#define MMC_VDD_165_195 0x00000080 /* VDD voltage 1.65 - 1.95 */ +#define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */ +#define MMC_VDD_21_22 0x00000200 /* VDD voltage 2.1 ~ 2.2 */ +#define MMC_VDD_22_23 0x00000400 /* VDD voltage 2.2 ~ 2.3 */ +#define MMC_VDD_23_24 0x00000800 /* VDD voltage 2.3 ~ 2.4 */ +#define MMC_VDD_24_25 0x00001000 /* VDD voltage 2.4 ~ 2.5 */ +#define MMC_VDD_25_26 0x00002000 /* VDD voltage 2.5 ~ 2.6 */ +#define MMC_VDD_26_27 0x00004000 /* VDD voltage 2.6 ~ 2.7 */ +#define MMC_VDD_27_28 0x00008000 /* VDD voltage 2.7 ~ 2.8 */ +#define MMC_VDD_28_29 0x00010000 /* VDD voltage 2.8 ~ 2.9 */ +#define MMC_VDD_29_30 0x00020000 /* VDD voltage 2.9 ~ 3.0 */ +#define MMC_VDD_30_31 0x00040000 /* VDD voltage 3.0 ~ 3.1 */ +#define MMC_VDD_31_32 0x00080000 /* VDD voltage 3.1 ~ 3.2 */ +#define MMC_VDD_32_33 0x00100000 /* VDD voltage 3.2 ~ 3.3 */ +#define MMC_VDD_33_34 0x00200000 /* VDD voltage 3.3 ~ 3.4 */ +#define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */ +#define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */ + +/* SDHCI FLAGS */ +#define SDHCI_POWER_ON 0x01 +#define SDHCI_POWER_180 0x0A +#define SDHCI_POWER_300 0x0C +#define SDHCI_POWER_330 0x0E + +#define SDHCI_DIVIDER_SHIFT 8 +#define SDHCI_DIVIDER_HI_SHIFT 6 +#define SDHCI_DIV_MASK 0xFF +#define SDHCI_DIV_MASK_LEN 8 +#define SDHCI_DIV_HI_MASK 0x300 +#define SDHCI_CLOCK_CARD_EN 0x0004 +#define SDHCI_CLOCK_INT_STABLE 0x0002 +#define SDHCI_CLOCK_INT_EN 0x0001 + +#define SDHCI_VENDOR_VER_MASK 0xFF00 +#define SDHCI_VENDOR_VER_SHIFT 8 +#define SDHCI_SPEC_VER_MASK 0x00FF +#define SDHCI_SPEC_VER_SHIFT 0 +#define SDHCI_SPEC_100 0 +#define SDHCI_SPEC_200 1 +#define SDHCI_SPEC_300 2 + +#define SDHCI_SIGNAL_ENABLE 0x38 + +#define SDHCI_MAX_DIV_SPEC_200 256 +#define SDHCI_MAX_DIV_SPEC_300 2046 + +/* SD DEVICE STATUS FLAGS */ +#define CURRENT_STATE_MASK (0xF << 9) +#define CURRENT_STATE_N_READY_MASK (7 << 9) +#define READY_FOR_DATA (1 << 8) +#define CARD_STATUS_ERROR_MASK (~0x0206BF7F) + +#define RCA_BITS_OFFSET 16 + +UINTN +XenonSetClk ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN UINT32 Clock + ); + +VOID +XenonPhyInit ( + IN EFI_PCI_IO_PROTOCOL *PciIo + ); + +VOID +XenonReset ( + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN UINT8 Slot, + IN UINT8 Mask + ); + +EFI_STATUS +XenonTransferData ( + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN UINT8 Slot, + IN OUT VOID *Buffer, + IN UINT32 DataLen, + IN UINT16 BlockSize, + IN UINT16 Blocks, + IN BOOLEAN Read + ); + +EFI_STATUS +XenonInit ( + IN SD_MMC_HC_PRIVATE_DATA *Private + ); + +EFI_STATUS +SdCardSendStatus ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Slot, + IN UINT16 Rca, + OUT UINT32 *DevStatus + ); diff --git a/Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.c b/Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.c new file mode 100755 index 0000000000..9a04493895 --- /dev/null +++ b/Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.c @@ -0,0 +1,531 @@ +/******************************************************************************* +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ +#include "MvSpiFlash.h" + +MARVELL_SPI_MASTER_PROTOCOL *SpiMasterProtocol; +SPI_FLASH_INSTANCE *mSpiFlashInstance; + +STATIC +VOID +SpiFlashFormatAddress ( + IN UINT32 Address, + IN UINT8 AddrSize, + IN OUT UINT8 *Cmd + ) +{ + if (AddrSize == 4) { + Cmd[1] = Address >> 24; + Cmd[2] = Address >> 16; + Cmd[3] = Address >> 8; + Cmd[4] = Address; + } else { + Cmd[1] = Address >> 16; + Cmd[2] = Address >> 8; + Cmd[3] = Address; + } +} + +STATIC +EFI_STATUS +MvSpiFlashReadCmd ( + IN SPI_DEVICE *Slave, + IN UINT8 *Cmd, + IN UINTN CmdSize, + OUT UINT8 *DataIn, + IN UINTN DataSize + ) +{ + EFI_STATUS Status; + + // Send command and gather response + Status = SpiMasterProtocol->ReadWrite (SpiMasterProtocol, Slave, Cmd, + CmdSize, NULL, DataIn, DataSize); + + return Status; +} + +STATIC +EFI_STATUS +MvSpiFlashWriteEnableCmd ( + IN SPI_DEVICE *Slave + ) +{ + EFI_STATUS Status; + UINT8 CmdEn = CMD_WRITE_ENABLE; + + // Send write_enable command + Status = SpiMasterProtocol->Transfer (SpiMasterProtocol, Slave, 1, + &CmdEn, NULL, SPI_TRANSFER_BEGIN | SPI_TRANSFER_END); + + return Status; +} + +STATIC +EFI_STATUS +MvSpiFlashWriteCommon ( + IN SPI_DEVICE *Slave, + IN UINT8 *Cmd, + IN UINT32 Length, + IN UINT8* Buffer, + IN UINT32 BufferLength + ) +{ + UINT8 CmdStatus = CMD_READ_STATUS; + UINT8 State; + UINT32 Counter = 0xFFFFF; + UINT8 poll_bit = STATUS_REG_POLL_WIP; + UINT8 check_status = 0x0; + + CmdStatus = (UINT8)PcdGet32 (PcdSpiFlashPollCmd); + if (CmdStatus == CMD_FLAG_STATUS) { + poll_bit = STATUS_REG_POLL_PEC; + check_status = poll_bit; + } + + // Send command + MvSpiFlashWriteEnableCmd (Slave); + + // Write data + SpiMasterProtocol->ReadWrite (SpiMasterProtocol, Slave, Cmd, Length, + Buffer, NULL, BufferLength); + + // Poll status register + SpiMasterProtocol->Transfer (SpiMasterProtocol, Slave, 1, &CmdStatus, + NULL, SPI_TRANSFER_BEGIN); + do { + SpiMasterProtocol->Transfer (SpiMasterProtocol, Slave, 1, NULL, &State, + 0); + Counter--; + if ((State & poll_bit) == check_status) + break; + } while (Counter > 0); + if (Counter == 0) { + DEBUG((DEBUG_ERROR, "SpiFlash: Timeout while writing to spi flash\n")); + return EFI_DEVICE_ERROR; + } + + // Deactivate CS + SpiMasterProtocol->Transfer (SpiMasterProtocol, Slave, 0, NULL, NULL, SPI_TRANSFER_END); + + return EFI_SUCCESS; +} + +STATIC +VOID +SpiFlashCmdBankaddrWrite ( + IN SPI_DEVICE *Slave, + IN UINT8 BankSel + ) +{ + UINT8 Cmd = CMD_BANK_WRITE; + + MvSpiFlashWriteCommon (Slave, &Cmd, 1, &BankSel, 1); +} + +STATIC +UINT8 +SpiFlashBank ( + IN SPI_DEVICE *Slave, + IN UINT32 Offset + ) +{ + UINT8 BankSel; + + BankSel = Offset / SPI_FLASH_16MB_BOUN; + + SpiFlashCmdBankaddrWrite (Slave, BankSel); + + return BankSel; +} + +EFI_STATUS +MvSpiFlashErase ( + IN SPI_DEVICE *Slave, + IN UINTN Offset, + IN UINTN Length + ) +{ + EFI_STATUS Status; + UINT32 AddrSize, EraseAddr; + UINTN EraseSize; + UINT8 Cmd[5]; + + AddrSize = PcdGet32 (PcdSpiFlashAddressCycles); + EraseSize = PcdGet64 (PcdSpiFlashEraseSize); + + // Check input parameters + if (Offset % EraseSize || Length % EraseSize) { + DEBUG((DEBUG_ERROR, "SpiFlash: Either erase offset or length " + "is not multiple of erase size\n")); + return EFI_DEVICE_ERROR; + } + + Cmd[0] = CMD_ERASE_64K; + while (Length) { + EraseAddr = Offset; + + SpiFlashBank (Slave, EraseAddr); + + SpiFlashFormatAddress (EraseAddr, AddrSize, Cmd); + + // Programm proper erase address + Status = MvSpiFlashWriteCommon (Slave, Cmd, AddrSize + 1, NULL, 0); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "SpiFlash: Error while programming target address\n")); + return Status; + } + + Offset += EraseSize; + Length -= EraseSize; + } + return EFI_SUCCESS; +} + +EFI_STATUS +MvSpiFlashRead ( + IN SPI_DEVICE *Slave, + IN UINT32 Offset, + IN UINTN Length, + IN VOID *Buf + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINT8 Cmd[6]; + UINT32 AddrSize, ReadAddr, ReadLength, RemainLength; + UINTN BankSel = 0; + + AddrSize = PcdGet32 (PcdSpiFlashAddressCycles); + + Cmd[0] = CMD_READ_ARRAY_FAST; + + // Sign end of address with 0 byte + Cmd[5] = 0; + + while (Length) { + ReadAddr = Offset; + + BankSel = SpiFlashBank (Slave, ReadAddr); + + RemainLength = (SPI_FLASH_16MB_BOUN * (BankSel + 1)) - Offset; + if (Length < RemainLength) { + ReadLength = Length; + } else { + ReadLength = RemainLength; + } + SpiFlashFormatAddress (ReadAddr, AddrSize, Cmd); + // Program proper read address and read data + Status = MvSpiFlashReadCmd (Slave, Cmd, AddrSize + 2, Buf, Length); + + Offset += ReadLength; + Length -= ReadLength; + Buf += ReadLength; + } + + return Status; +} + +EFI_STATUS +MvSpiFlashWrite ( + IN SPI_DEVICE *Slave, + IN UINT32 Offset, + IN UINTN Length, + IN VOID *Buf + ) +{ + EFI_STATUS Status; + UINTN ByteAddr, ChunkLength, ActualIndex, PageSize; + UINT32 WriteAddr; + UINT8 Cmd[5], AddrSize; + + AddrSize = PcdGet32 (PcdSpiFlashAddressCycles); + PageSize = PcdGet32 (PcdSpiFlashPageSize); + + Cmd[0] = CMD_PAGE_PROGRAM; + + for (ActualIndex = 0; ActualIndex < Length; ActualIndex += ChunkLength) { + WriteAddr = Offset; + + SpiFlashBank (Slave, WriteAddr); + + ByteAddr = Offset % PageSize; + + ChunkLength = MIN(Length - ActualIndex, (UINT64) (PageSize - ByteAddr)); + + SpiFlashFormatAddress (WriteAddr, AddrSize, Cmd); + + // Program proper write address and write data + Status = MvSpiFlashWriteCommon (Slave, Cmd, AddrSize + 1, Buf + ActualIndex, + ChunkLength); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "SpiFlash: Error while programming write address\n")); + return Status; + } + + Offset += ChunkLength; + } + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +MvSpiFlashUpdateBlock ( + IN SPI_DEVICE *Slave, + IN UINT32 Offset, + IN UINTN ToUpdate, + IN UINT8 *Buf, + IN UINT8 *TmpBuf, + IN UINTN EraseSize + ) +{ + EFI_STATUS Status; + + // Read backup + Status = MvSpiFlashRead (Slave, Offset, EraseSize, TmpBuf); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "SpiFlash: Update: Error while reading old data\n")); + return Status; + } + + // Erase entire sector + Status = MvSpiFlashErase (Slave, Offset, EraseSize); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "SpiFlash: Update: Error while erasing block\n")); + return Status; + } + + // Write new data + MvSpiFlashWrite (Slave, Offset, ToUpdate, Buf); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "SpiFlash: Update: Error while writing new data\n")); + return Status; + } + + // Write backup + if (ToUpdate != EraseSize) { + Status = MvSpiFlashWrite (Slave, Offset + ToUpdate, EraseSize - ToUpdate, + &TmpBuf[ToUpdate]); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "SpiFlash: Update: Error while writing backup\n")); + return Status; + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +MvSpiFlashUpdate ( + IN SPI_DEVICE *Slave, + IN UINT32 Offset, + IN UINTN ByteCount, + IN UINT8 *Buf + ) +{ + EFI_STATUS Status; + UINT64 EraseSize, ToUpdate, Scale = 1; + UINT8 *TmpBuf, *End; + + EraseSize = PcdGet64 (PcdSpiFlashEraseSize); + + End = Buf + ByteCount; + + TmpBuf = (UINT8 *)AllocateZeroPool (EraseSize); + if (TmpBuf == NULL) { + DEBUG((DEBUG_ERROR, "SpiFlash: Cannot allocate memory\n")); + return EFI_OUT_OF_RESOURCES; + } + + if (End - Buf >= 200) + Scale = (End - Buf) / 100; + + for (; Buf < End; Buf += ToUpdate, Offset += ToUpdate) { + ToUpdate = MIN((UINT64)(End - Buf), EraseSize); + Print (L" \rUpdating, %d%%", 100 - (End - Buf) / Scale); + Status = MvSpiFlashUpdateBlock (Slave, Offset, ToUpdate, Buf, TmpBuf, EraseSize); + + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "SpiFlash: Error while updating\n")); + return Status; + } + } + + Print(L"\n"); + FreePool (TmpBuf); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +MvSpiFlashReadId ( + IN SPI_DEVICE *SpiDev, + IN UINT32 DataByteCount, + IN OUT UINT8 *Buffer + ) +{ + EFI_STATUS Status; + UINT8 *DataOut; + + DataOut = (UINT8 *) AllocateZeroPool (DataByteCount); + if (DataOut == NULL) { + DEBUG((DEBUG_ERROR, "SpiFlash: Cannot allocate memory\n")); + return EFI_OUT_OF_RESOURCES; + } + Status = SpiMasterProtocol->Transfer (SpiMasterProtocol, SpiDev, + DataByteCount, Buffer, DataOut, SPI_TRANSFER_BEGIN | SPI_TRANSFER_END); + if (EFI_ERROR(Status)) { + FreePool (DataOut); + DEBUG((DEBUG_ERROR, "SpiFlash: Spi transfer error\n")); + return Status; + } + + // Bytes 1,2 and 3 contain SPI flash ID + Buffer[0] = DataOut[1]; + Buffer[1] = DataOut[2]; + Buffer[2] = DataOut[3]; + + FreePool (DataOut); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +MvSpiFlashInit ( + IN MARVELL_SPI_FLASH_PROTOCOL *This, + IN SPI_DEVICE *Slave + ) +{ + EFI_STATUS Status; + UINT8 Cmd, StatusRegister; + UINT32 AddrSize; + + AddrSize = PcdGet32 (PcdSpiFlashAddressCycles); + + if (AddrSize == 4) { + // Set 4 byte address mode + Status = MvSpiFlashWriteEnableCmd (Slave); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "SpiFlash: Error while setting write_enable\n")); + return Status; + } + + Cmd = CMD_4B_ADDR_ENABLE; + Status = SpiMasterProtocol->Transfer (SpiMasterProtocol, Slave, 1, &Cmd, NULL, + SPI_TRANSFER_BEGIN | SPI_TRANSFER_END); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "SpiFlash: Error while setting 4B address\n")); + return Status; + } + } + + // Write flash status register + Status = MvSpiFlashWriteEnableCmd (Slave); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "SpiFlash: Error while setting write_enable\n")); + return Status; + } + + Cmd = CMD_WRITE_STATUS_REG; + StatusRegister = 0x0; + Status = SpiMasterProtocol->ReadWrite (SpiMasterProtocol, Slave, &Cmd, 1, + &StatusRegister, NULL, 1); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "SpiFlash: Error with spi transfer\n")); + return Status; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +MvSpiFlashInitProtocol ( + IN MARVELL_SPI_FLASH_PROTOCOL *SpiFlashProtocol + ) +{ + + SpiFlashProtocol->Init = MvSpiFlashInit; + SpiFlashProtocol->ReadId = MvSpiFlashReadId; + SpiFlashProtocol->Read = MvSpiFlashRead; + SpiFlashProtocol->Write = MvSpiFlashWrite; + SpiFlashProtocol->Erase = MvSpiFlashErase; + SpiFlashProtocol->Update = MvSpiFlashUpdate; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +MvSpiFlashEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = gBS->LocateProtocol ( + &gMarvellSpiMasterProtocolGuid, + NULL, + (VOID **)&SpiMasterProtocol + ); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "SpiFlash: Cannot locate SPI Master protocol\n")); + return EFI_DEVICE_ERROR; + } + + mSpiFlashInstance = AllocateZeroPool (sizeof (SPI_FLASH_INSTANCE)); + + if (mSpiFlashInstance == NULL) { + DEBUG((DEBUG_ERROR, "SpiFlash: Cannot allocate memory\n")); + return EFI_OUT_OF_RESOURCES; + } + + MvSpiFlashInitProtocol (&mSpiFlashInstance->SpiFlashProtocol); + + mSpiFlashInstance->Signature = SPI_FLASH_SIGNATURE; + + Status = gBS->InstallMultipleProtocolInterfaces ( + &(mSpiFlashInstance->Handle), + &gMarvellSpiFlashProtocolGuid, + &(mSpiFlashInstance->SpiFlashProtocol), + NULL + ); + if (EFI_ERROR (Status)) { + FreePool (mSpiFlashInstance); + DEBUG((DEBUG_ERROR, "SpiFlash: Cannot install SPI flash protocol\n")); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} diff --git a/Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.h b/Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.h new file mode 100755 index 0000000000..3889643aeb --- /dev/null +++ b/Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.h @@ -0,0 +1,132 @@ +/******************************************************************************* +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ +#ifndef __MV_SPI_FLASH_H__ +#define __MV_SPI_FLASH_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define SPI_FLASH_SIGNATURE SIGNATURE_32 ('F', 'S', 'P', 'I') + +#define CMD_READ_ID 0x9f +#define READ_STATUS_REG_CMD 0x0b +#define CMD_WRITE_ENABLE 0x06 +#define CMD_READ_STATUS 0x05 +#define CMD_FLAG_STATUS 0x70 +#define CMD_WRITE_STATUS_REG 0x01 +#define CMD_READ_ARRAY_FAST 0x0b +#define CMD_PAGE_PROGRAM 0x02 +#define CMD_BANK_WRITE 0xc5 +#define CMD_ERASE_64K 0xd8 +#define CMD_4B_ADDR_ENABLE 0xb7 + +#define STATUS_REG_POLL_WIP (1 << 0) +#define STATUS_REG_POLL_PEC (1 << 7) + +#define SPI_TRANSFER_BEGIN 0x01 // Assert CS before transfer +#define SPI_TRANSFER_END 0x02 // Deassert CS after transfers + +#define SPI_FLASH_16MB_BOUN 0x1000000 + +typedef enum { + SPI_FLASH_READ_ID, + SPI_FLASH_READ, // Read from SPI flash with address + SPI_FLASH_WRITE, // Write to SPI flash with address + SPI_FLASH_ERASE, + SPI_FLASH_UPDATE, + SPI_COMMAND_MAX +} SPI_COMMAND; + +typedef struct { + MARVELL_SPI_FLASH_PROTOCOL SpiFlashProtocol; + UINTN Signature; + EFI_HANDLE Handle; +} SPI_FLASH_INSTANCE; + +EFI_STATUS +EFIAPI +SpiFlashReadId ( + IN SPI_DEVICE *SpiDev, + IN UINT32 DataByteCount, + IN OUT UINT8 *Buffer + ); + +EFI_STATUS +SpiFlashRead ( + IN SPI_DEVICE *Slave, + IN UINT32 Offset, + IN UINTN Length, + IN VOID *Buf + ); + +EFI_STATUS +SpiFlashWrite ( + IN SPI_DEVICE *Slave, + IN UINT32 Offset, + IN UINTN Length, + IN VOID *Buf + ); + +EFI_STATUS +SpiFlashUpdate ( + IN SPI_DEVICE *Slave, + IN UINT32 Offset, + IN UINTN ByteCount, + IN UINT8 *Buf + ); + +EFI_STATUS +SpiFlashErase ( + IN SPI_DEVICE *SpiDev, + IN UINTN Offset, + IN UINTN Length + ); + +EFI_STATUS +EFIAPI +EfiSpiFlashInit ( + IN MARVELL_SPI_FLASH_PROTOCOL *This, + IN SPI_DEVICE *Slave + ); + +#endif // __MV_SPI_FLASH_H__ diff --git a/Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.inf b/Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.inf new file mode 100644 index 0000000000..d035d47137 --- /dev/null +++ b/Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.inf @@ -0,0 +1,67 @@ +# +# Marvell BSD License Option +# +# If you received this File from Marvell, you may opt to use, redistribute +# and/or modify this File under the following licensing terms. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Marvell nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SpiFlashDxe + FILE_GUID = 49d7fb74-306d-42bd-94c8-c0c54b181dd7 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = MvSpiFlashEntryPoint + +[Sources] + MvSpiFlash.c + MvSpiFlash.h + +[Packages] + MdePkg/MdePkg.dec + Platform/Marvell/Marvell.dec + +[LibraryClasses] + UefiBootServicesTableLib + UefiDriverEntryPoint + TimerLib + UefiLib + DebugLib + MemoryAllocationLib + +[FixedPcd] + gMarvellTokenSpaceGuid.PcdSpiFlashAddressCycles + gMarvellTokenSpaceGuid.PcdSpiFlashEraseSize + gMarvellTokenSpaceGuid.PcdSpiFlashPageSize + gMarvellTokenSpaceGuid.PcdSpiFlashPollCmd + +[Protocols] + gMarvellSpiMasterProtocolGuid + gMarvellSpiFlashProtocolGuid + +[Depex] + TRUE diff --git a/Platform/Marvell/Drivers/Spi/MvSpiDxe.c b/Platform/Marvell/Drivers/Spi/MvSpiDxe.c new file mode 100755 index 0000000000..aab20fc9ac --- /dev/null +++ b/Platform/Marvell/Drivers/Spi/MvSpiDxe.c @@ -0,0 +1,379 @@ +/******************************************************************************* +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ +#include "MvSpiDxe.h" + +SPI_MASTER *mSpiMasterInstance; + +STATIC +EFI_STATUS +SpiSetBaudRate ( + IN UINT32 CpuClock, + IN UINT32 MaxFreq + ) +{ + UINT32 Spr, BestSpr, Sppr, BestSppr, ClockDivider, Match, Reg, MinBaudDiff; + UINTN SpiRegBase = PcdGet32 (PcdSpiRegBase); + + MinBaudDiff = 0xFFFFFFFF; + BestSppr = 0; + + //Spr is in range 1-15 and Sppr in range 0-8 + for (Spr = 1; Spr <= 15; Spr++) { + for (Sppr = 0; Sppr <= 7; Sppr++) { + ClockDivider = Spr * (1 << Sppr); + + if ((CpuClock / ClockDivider) > MaxFreq) { + continue; + } + + if ((CpuClock / ClockDivider) == MaxFreq) { + BestSpr = Spr; + BestSppr = Sppr; + Match = 1; + break; + } + + if ((MaxFreq - (CpuClock / ClockDivider)) < MinBaudDiff) { + MinBaudDiff = (MaxFreq - (CpuClock / ClockDivider)); + BestSpr = Spr; + BestSppr = Sppr; + } + } + + if (Match == 1) { + break; + } + } + + if (BestSpr == 0) { + return (EFI_INVALID_PARAMETER); + } + + Reg = MmioRead32 (SpiRegBase + SPI_CONF_REG); + Reg &= ~(SPI_SPR_MASK | SPI_SPPR_0_MASK | SPI_SPPR_HI_MASK); + Reg |= (BestSpr << SPI_SPR_OFFSET) | + ((BestSppr & 0x1) << SPI_SPPR_0_OFFSET) | + ((BestSppr >> 1) << SPI_SPPR_HI_OFFSET); + MmioWrite32 (SpiRegBase + SPI_CONF_REG, Reg); + + return EFI_SUCCESS; +} + +STATIC +VOID +SpiSetCs ( + UINT8 CsId + ) +{ + UINT32 Reg, SpiRegBase = PcdGet32 (PcdSpiRegBase); + + Reg = MmioRead32 (SpiRegBase + SPI_CTRL_REG); + Reg &= ~SPI_CS_NUM_MASK; + Reg |= (CsId << SPI_CS_NUM_OFFSET); + MmioWrite32 (SpiRegBase + SPI_CTRL_REG, Reg); +} + +STATIC +VOID +SpiActivateCs ( + UINT8 IN CsId + ) +{ + UINT32 Reg, SpiRegBase = PcdGet32 (PcdSpiRegBase); + + SpiSetCs(CsId); + Reg = MmioRead32 (SpiRegBase + SPI_CTRL_REG); + Reg |= SPI_CS_EN_MASK; + MmioWrite32(SpiRegBase + SPI_CTRL_REG, Reg); +} + +STATIC +VOID +SpiDeactivateCs ( + VOID + ) +{ + UINT32 Reg, SpiRegBase = PcdGet32 (PcdSpiRegBase); + + Reg = MmioRead32 (SpiRegBase + SPI_CTRL_REG); + Reg &= ~SPI_CS_EN_MASK; + MmioWrite32(SpiRegBase + SPI_CTRL_REG, Reg); +} + +STATIC +VOID +SpiSetupTransfer ( + IN MARVELL_SPI_MASTER_PROTOCOL *This, + IN SPI_DEVICE *Slave + ) +{ + SPI_MASTER *SpiMaster; + UINT32 Reg, SpiRegBase, CoreClock, SpiMaxFreq; + + SpiMaster = SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This); + + // Initialize values from PCDs + SpiRegBase = PcdGet32 (PcdSpiRegBase); + CoreClock = PcdGet32 (PcdSpiClockFrequency); + SpiMaxFreq = PcdGet32 (PcdSpiMaxFrequency); + + EfiAcquireLock (&SpiMaster->Lock); + + Reg = MmioRead32 (SpiRegBase + SPI_CONF_REG); + Reg |= SPI_BYTE_LENGTH; + MmioWrite32 (SpiRegBase + SPI_CONF_REG, Reg); + + SpiSetCs(Slave->Cs); + + SpiSetBaudRate (CoreClock, SpiMaxFreq); + + Reg = MmioRead32 (SpiRegBase + SPI_CONF_REG); + Reg &= ~(SPI_CPOL_MASK | SPI_CPHA_MASK | SPI_TXLSBF_MASK | SPI_RXLSBF_MASK); + + switch (Slave->Mode) { + case SPI_MODE0: + break; + case SPI_MODE1: + Reg |= SPI_CPHA_MASK; + break; + case SPI_MODE2: + Reg |= SPI_CPOL_MASK; + break; + case SPI_MODE3: + Reg |= SPI_CPOL_MASK; + Reg |= SPI_CPHA_MASK; + break; + } + + MmioWrite32 (SpiRegBase + SPI_CONF_REG, Reg); + + EfiReleaseLock (&SpiMaster->Lock); +} + +EFI_STATUS +EFIAPI +MvSpiTransfer ( + IN MARVELL_SPI_MASTER_PROTOCOL *This, + IN SPI_DEVICE *Slave, + IN UINTN DataByteCount, + IN VOID *DataOut, + IN VOID *DataIn, + IN UINTN Flag + ) +{ + SPI_MASTER *SpiMaster; + UINT64 Length; + UINT32 Iterator, Reg, SpiRegBase; + UINT8 *DataOutPtr = (UINT8 *)DataOut; + UINT8 *DataInPtr = (UINT8 *)DataIn; + UINT8 DataToSend = 0; + + SpiMaster = SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This); + + SpiRegBase = PcdGet32 (PcdSpiRegBase); + + Length = 8 * DataByteCount; + + EfiAcquireLock (&SpiMaster->Lock); + + if (Flag & SPI_TRANSFER_BEGIN) { + SpiActivateCs (Slave->Cs); + } + + // Set 8-bit mode + Reg = MmioRead32 (SpiRegBase + SPI_CONF_REG); + Reg &= ~SPI_BYTE_LENGTH; + MmioWrite32 (SpiRegBase + SPI_CONF_REG, Reg); + + while (Length > 0) { + if (DataOut != NULL) { + DataToSend = *DataOutPtr & 0xFF; + } + // Transmit Data + MmioWrite32 (SpiRegBase + SPI_INT_CAUSE_REG, 0x0); + MmioWrite32 (SpiRegBase + SPI_DATA_OUT_REG, DataToSend); + // Wait for memory ready + for (Iterator = 0; Iterator < SPI_TIMEOUT; Iterator++) { + if (MmioRead32 (SpiRegBase + SPI_INT_CAUSE_REG)) { + *DataInPtr = MmioRead32 (SpiRegBase + SPI_DATA_IN_REG); + + if (DataInPtr != NULL) { + DataInPtr++; + } + if (DataOutPtr != NULL) { + DataOutPtr++; + } + Length -= 8; + break; + } + } + + if (Iterator >= SPI_TIMEOUT) { + DEBUG ((DEBUG_ERROR, "Timeout\n")); + } + } + + if (Flag & SPI_TRANSFER_END) { + SpiDeactivateCs (); + } + + EfiReleaseLock (&SpiMaster->Lock); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +MvSpiReadWrite ( + IN MARVELL_SPI_MASTER_PROTOCOL *This, + IN SPI_DEVICE *Slave, + IN UINT8 *Cmd, + IN UINTN CmdSize, + IN UINT8 *DataOut, + OUT UINT8 *DataIn, + IN UINTN DataSize + ) +{ + EFI_STATUS Status; + + Status = MvSpiTransfer (This, Slave, CmdSize, Cmd, NULL, SPI_TRANSFER_BEGIN); + if (EFI_ERROR (Status)) { + Print (L"Spi Transfer Error\n"); + return EFI_DEVICE_ERROR; + } + + Status = MvSpiTransfer (This, Slave, DataSize, DataOut, DataIn, SPI_TRANSFER_END); + if (EFI_ERROR (Status)) { + Print (L"Spi Transfer Error\n"); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +MvSpiInit ( + IN MARVELL_SPI_MASTER_PROTOCOL * This + ) +{ + + return EFI_SUCCESS; +} + +SPI_DEVICE * +EFIAPI +MvSpiSetupSlave ( + IN MARVELL_SPI_MASTER_PROTOCOL *This, + IN UINTN Cs, + IN SPI_MODE Mode + ) +{ + SPI_DEVICE *Slave; + + Slave = AllocateZeroPool (sizeof(SPI_DEVICE)); + if (Slave == NULL) { + DEBUG((DEBUG_ERROR, "Cannot allocate memory\n")); + return NULL; + } + + Slave->Cs = Cs; + Slave->Mode = Mode; + + SpiSetupTransfer (This, Slave); + + return Slave; +} + +EFI_STATUS +EFIAPI +MvSpiFreeSlave ( + IN SPI_DEVICE *Slave + ) +{ + FreePool (Slave); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +SpiMasterInitProtocol ( + IN MARVELL_SPI_MASTER_PROTOCOL *SpiMasterProtocol + ) +{ + + SpiMasterProtocol->Init = MvSpiInit; + SpiMasterProtocol->SetupDevice = MvSpiSetupSlave; + SpiMasterProtocol->FreeDevice = MvSpiFreeSlave; + SpiMasterProtocol->Transfer = MvSpiTransfer; + SpiMasterProtocol->ReadWrite = MvSpiReadWrite; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +SpiMasterEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + mSpiMasterInstance = AllocateZeroPool (sizeof (SPI_MASTER)); + + if (mSpiMasterInstance == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + EfiInitializeLock (&mSpiMasterInstance->Lock, TPL_NOTIFY); + + SpiMasterInitProtocol (&mSpiMasterInstance->SpiMasterProtocol); + + mSpiMasterInstance->Signature = SPI_MASTER_SIGNATURE; + + Status = gBS->InstallMultipleProtocolInterfaces ( + &(mSpiMasterInstance->Handle), + &gMarvellSpiMasterProtocolGuid, + &(mSpiMasterInstance->SpiMasterProtocol), + NULL + ); + if (EFI_ERROR (Status)) { + FreePool (mSpiMasterInstance); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} diff --git a/Platform/Marvell/Drivers/Spi/MvSpiDxe.h b/Platform/Marvell/Drivers/Spi/MvSpiDxe.h new file mode 100644 index 0000000000..1401f6207b --- /dev/null +++ b/Platform/Marvell/Drivers/Spi/MvSpiDxe.h @@ -0,0 +1,145 @@ +/******************************************************************************* +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ +#ifndef __SPI_MASTER_H__ +#define __SPI_MASTER_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define SPI_MASTER_SIGNATURE SIGNATURE_32 ('M', 'S', 'P', 'I') +#define SPI_MASTER_FROM_SPI_MASTER_PROTOCOL(a) CR (a, SPI_MASTER, SpiMasterProtocol, SPI_MASTER_SIGNATURE) + +// Marvell Flash Device Controller Registers +#define SPI_CTRL_REG (0x00) +#define SPI_CONF_REG (0x04) +#define SPI_DATA_OUT_REG (0x08) +#define SPI_DATA_IN_REG (0x0c) +#define SPI_INT_CAUSE_REG (0x10) + +// Serial Memory Interface Control Register Masks +#define SPI_CS_NUM_OFFSET 2 +#define SPI_CS_NUM_MASK (0x7 << SPI_CS_NUM_OFFSET) +#define SPI_MEM_READY_MASK (0x1 << 1) +#define SPI_CS_EN_MASK (0x1 << 0) + +// Serial Memory Interface Configuration Register Masks +#define SPI_BYTE_LENGTH_OFFSET 5 +#define SPI_BYTE_LENGTH (0x1 << SPI_BYTE_LENGTH_OFFSET) +#define SPI_CPOL_OFFSET 11 +#define SPI_CPOL_MASK (0x1 << SPI_CPOL_OFFSET) +#define SPI_CPHA_OFFSET 12 +#define SPI_CPHA_MASK (0x1 << SPI_CPHA_OFFSET) +#define SPI_TXLSBF_OFFSET 13 +#define SPI_TXLSBF_MASK (0x1 << SPI_TXLSBF_OFFSET) +#define SPI_RXLSBF_OFFSET 14 +#define SPI_RXLSBF_MASK (0x1 << SPI_RXLSBF_OFFSET) + +#define SPI_SPR_OFFSET 0 +#define SPI_SPR_MASK (0xf << SPI_SPR_OFFSET) +#define SPI_SPPR_0_OFFSET 4 +#define SPI_SPPR_0_MASK (0x1 << SPI_SPPR_0_OFFSET) +#define SPI_SPPR_HI_OFFSET 6 +#define SPI_SPPR_HI_MASK (0x3 << SPI_SPPR_HI_OFFSET) + +#define SPI_TRANSFER_BEGIN 0x01 // Assert CS before transfer +#define SPI_TRANSFER_END 0x02 // Deassert CS after transfers + +#define SPI_TIMEOUT 100000 + +typedef struct { + MARVELL_SPI_MASTER_PROTOCOL SpiMasterProtocol; + UINTN Signature; + EFI_HANDLE Handle; + EFI_LOCK Lock; +} SPI_MASTER; + +EFI_STATUS +EFIAPI +MvSpiTransfer ( + IN MARVELL_SPI_MASTER_PROTOCOL *This, + IN SPI_DEVICE *Slave, + IN UINTN DataByteCount, + IN VOID *DataOut, + IN VOID *DataIn, + IN UINTN Flag + ); + +EFI_STATUS +EFIAPI +MvSpiReadWrite ( + IN MARVELL_SPI_MASTER_PROTOCOL *This, + IN SPI_DEVICE *Slave, + IN UINT8 *Cmd, + IN UINTN CmdSize, + IN UINT8 *DataOut, + OUT UINT8 *DataIn, + IN UINTN DataSize + ); + +EFI_STATUS +EFIAPI +MvSpiInit ( + IN MARVELL_SPI_MASTER_PROTOCOL * This + ); + +SPI_DEVICE * +EFIAPI +MvSpiSetupSlave ( + IN MARVELL_SPI_MASTER_PROTOCOL * This, + IN UINTN Cs, + IN SPI_MODE Mode + ); + +EFI_STATUS +EFIAPI +MvSpiFreeSlave ( + IN SPI_DEVICE *Slave + ); + +EFI_STATUS +EFIAPI +SpiMasterEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +#endif // __SPI_MASTER_H__ diff --git a/Platform/Marvell/Drivers/Spi/MvSpiDxe.inf b/Platform/Marvell/Drivers/Spi/MvSpiDxe.inf new file mode 100644 index 0000000000..d38d331f7c --- /dev/null +++ b/Platform/Marvell/Drivers/Spi/MvSpiDxe.inf @@ -0,0 +1,66 @@ +# +# Marvell BSD License Option +# +# If you received this File from Marvell, you may opt to use, redistribute +# and/or modify this File under the following licensing terms. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Marvell nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SpiMasterDxe + FILE_GUID = c19dbc8a-f4f9-43b0-aee5-802e3ed03d15 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = SpiMasterEntryPoint + +[Sources] + MvSpiDxe.c + MvSpiDxe.h + +[Packages] + MdePkg/MdePkg.dec + Platform/Marvell/Marvell.dec + +[LibraryClasses] + UefiBootServicesTableLib + UefiDriverEntryPoint + TimerLib + UefiLib + DebugLib + MemoryAllocationLib + IoLib + +[FixedPcd] + gMarvellTokenSpaceGuid.PcdSpiRegBase + gMarvellTokenSpaceGuid.PcdSpiClockFrequency + gMarvellTokenSpaceGuid.PcdSpiMaxFrequency + +[Protocols] + gMarvellSpiMasterProtocolGuid + +[Depex] + TRUE diff --git a/Platform/Marvell/Include/Library/MppLib.h b/Platform/Marvell/Include/Library/MppLib.h new file mode 100644 index 0000000000..77c6cdb1c4 --- /dev/null +++ b/Platform/Marvell/Include/Library/MppLib.h @@ -0,0 +1,42 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __MPPLIB_H__ +#define __MPPLIB_H__ + +EFI_STATUS +MppInitialize ( + ); + +#endif diff --git a/Platform/Marvell/Include/Library/MvComPhyLib.h b/Platform/Marvell/Include/Library/MvComPhyLib.h new file mode 100644 index 0000000000..6076ede613 --- /dev/null +++ b/Platform/Marvell/Include/Library/MvComPhyLib.h @@ -0,0 +1,48 @@ +/******************************************************************************* +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __MVCOMPHYLIB_H__ +#define __MVCOMPHYLIB_H__ + +typedef enum { + MvComPhyTypeCp110, + MvComPhyTypeMax, +} MV_COMPHY_CHIP_TYPE; + +EFI_STATUS +MvComPhyInit ( + VOID + ); + +#endif diff --git a/Platform/Marvell/Include/Library/MvHwDescLib.h b/Platform/Marvell/Include/Library/MvHwDescLib.h new file mode 100644 index 0000000000..ac8dc37006 --- /dev/null +++ b/Platform/Marvell/Include/Library/MvHwDescLib.h @@ -0,0 +1,169 @@ +/******************************************************************************** +Copyright (C) 2017 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __MVHWDESCLIB_H__ +#define __MVHWDESCLIB_H__ + +#include +#include + +// +// Helper macros +// + +// Check if device is enabled - it expects PCD to be read to 'DeviceTable' array +#define MVHW_DEV_ENABLED(type, index) (type ## DeviceTable[index]) + +// +// CommonPhy devices description template definition +// +#define MVHW_MAX_COMPHY_DEVS 4 + +typedef struct { + UINT8 ComPhyDevCount; + UINTN ComPhyBaseAddresses[MVHW_MAX_COMPHY_DEVS]; + UINTN ComPhyHpipe3BaseAddresses[MVHW_MAX_COMPHY_DEVS]; + UINTN ComPhyLaneCount[MVHW_MAX_COMPHY_DEVS]; + UINTN ComPhyMuxBitCount[MVHW_MAX_COMPHY_DEVS]; + MV_COMPHY_CHIP_TYPE ComPhyChipType[MVHW_MAX_COMPHY_DEVS]; +} MVHW_COMPHY_DESC; + +// +// NonDiscoverable devices description template definition +// +#define MVHW_MAX_XHCI_DEVS 4 +#define MVHW_MAX_AHCI_DEVS 4 +#define MVHW_MAX_SDHCI_DEVS 4 + +typedef struct { + // XHCI + UINT8 XhciDevCount; + UINTN XhciBaseAddresses[MVHW_MAX_XHCI_DEVS]; + UINTN XhciMemSize[MVHW_MAX_XHCI_DEVS]; + NON_DISCOVERABLE_DEVICE_DMA_TYPE XhciDmaType[MVHW_MAX_XHCI_DEVS]; + // AHCI + UINT8 AhciDevCount; + UINTN AhciBaseAddresses[MVHW_MAX_AHCI_DEVS]; + UINTN AhciMemSize[MVHW_MAX_AHCI_DEVS]; + NON_DISCOVERABLE_DEVICE_DMA_TYPE AhciDmaType[MVHW_MAX_AHCI_DEVS]; + // SDHCI + UINT8 SdhciDevCount; + UINTN SdhciBaseAddresses[MVHW_MAX_SDHCI_DEVS]; + UINTN SdhciMemSize[MVHW_MAX_SDHCI_DEVS]; + NON_DISCOVERABLE_DEVICE_DMA_TYPE SdhciDmaType[MVHW_MAX_SDHCI_DEVS]; +} MVHW_NONDISCOVERABLE_DESC; + +// +// RealTimeClock devices description template definition +// +#define MVHW_MAX_RTC_DEVS 2 + +typedef struct { + UINT8 RtcDevCount; + UINTN RtcBaseAddresses[MVHW_MAX_RTC_DEVS]; + UINTN RtcMemSize[MVHW_MAX_RTC_DEVS]; +} MVHW_RTC_DESC; + +// +// Platform description of CommonPhy devices +// +#define MVHW_CP0_COMPHY_BASE 0xF2441000 +#define MVHW_CP0_HPIPE3_BASE 0xF2120000 +#define MVHW_CP0_COMPHY_LANES 6 +#define MVHW_CP0_COMPHY_MUX_BITS 4 +#define MVHW_CP1_COMPHY_BASE 0xF4441000 +#define MVHW_CP1_HPIPE3_BASE 0xF4120000 +#define MVHW_CP1_COMPHY_LANES 6 +#define MVHW_CP1_COMPHY_MUX_BITS 4 + +#define DECLARE_A7K8K_COMPHY_TEMPLATE \ +STATIC \ +MVHW_COMPHY_DESC mA7k8kComPhyDescTemplate = {\ + 2,\ + { MVHW_CP0_COMPHY_BASE, MVHW_CP1_COMPHY_BASE },\ + { MVHW_CP0_HPIPE3_BASE, MVHW_CP1_HPIPE3_BASE },\ + { MVHW_CP0_COMPHY_LANES, MVHW_CP1_COMPHY_LANES },\ + { MVHW_CP0_COMPHY_MUX_BITS, MVHW_CP1_COMPHY_MUX_BITS },\ + { MvComPhyTypeCp110, MvComPhyTypeCp110 }\ +} + +// +// Platform description of NonDiscoverable devices +// +#define MVHW_CP0_XHCI0_BASE 0xF2500000 +#define MVHW_CP0_XHCI1_BASE 0xF2510000 +#define MVHW_CP1_XHCI0_BASE 0xF4500000 +#define MVHW_CP1_XHCI1_BASE 0xF4510000 + +#define MVHW_CP0_AHCI0_BASE 0xF2540000 +#define MVHW_CP0_AHCI0_ID 0 +#define MVHW_CP1_AHCI0_BASE 0xF4540000 +#define MVHW_CP1_AHCI0_ID 1 + +#define MVHW_AP0_SDHCI0_BASE 0xF06E0000 +#define MVHW_CP0_SDHCI0_BASE 0xF2780000 + +#define DECLARE_A7K8K_NONDISCOVERABLE_TEMPLATE \ +STATIC \ +MVHW_NONDISCOVERABLE_DESC mA7k8kNonDiscoverableDescTemplate = {\ + 4, /* XHCI */\ + { MVHW_CP0_XHCI0_BASE, MVHW_CP0_XHCI1_BASE, MVHW_CP1_XHCI0_BASE, MVHW_CP1_XHCI1_BASE },\ + { SIZE_16KB, SIZE_16KB, SIZE_16KB, SIZE_16KB },\ + { NonDiscoverableDeviceDmaTypeCoherent, NonDiscoverableDeviceDmaTypeCoherent,\ + NonDiscoverableDeviceDmaTypeCoherent, NonDiscoverableDeviceDmaTypeCoherent },\ + 2, /* AHCI */\ + { MVHW_CP0_AHCI0_BASE, MVHW_CP1_AHCI0_BASE },\ + { SIZE_8KB, SIZE_8KB },\ + { NonDiscoverableDeviceDmaTypeCoherent, NonDiscoverableDeviceDmaTypeCoherent },\ + 2, /* SDHCI */\ + { MVHW_AP0_SDHCI0_BASE, MVHW_CP0_SDHCI0_BASE },\ + { SIZE_1KB, SIZE_1KB },\ + { NonDiscoverableDeviceDmaTypeCoherent, NonDiscoverableDeviceDmaTypeCoherent }\ +} + +// +// Platform description of RealTimeClock devices +// +#define MVHW_CP0_RTC0_BASE 0xF2284000 +#define MVHW_CP1_RTC0_BASE 0xF4284000 + +#define DECLARE_A7K8K_RTC_TEMPLATE \ +STATIC \ +MVHW_RTC_DESC mA7k8kRtcDescTemplate = {\ + 2,\ + { MVHW_CP0_RTC0_BASE, MVHW_CP1_RTC0_BASE },\ + { SIZE_4KB, SIZE_4KB }\ +} + +#endif /* __MVHWDESCLIB_H__ */ diff --git a/Platform/Marvell/Include/Library/ParsePcdLib.h b/Platform/Marvell/Include/Library/ParsePcdLib.h new file mode 100644 index 0000000000..a255685018 --- /dev/null +++ b/Platform/Marvell/Include/Library/ParsePcdLib.h @@ -0,0 +1,46 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __PARSEPCDLIB_H__ +#define __PARSEPCDLIB_H__ + +EFI_STATUS +ParsePcdString ( + IN CHAR16 *PcdString, + IN UINT8 Count, + OUT UINTN *ValueTable, + OUT CHAR16 **StrTable + ); + +#endif diff --git a/Platform/Marvell/Include/Library/UtmiPhyLib.h b/Platform/Marvell/Include/Library/UtmiPhyLib.h new file mode 100644 index 0000000000..7c62cbab20 --- /dev/null +++ b/Platform/Marvell/Include/Library/UtmiPhyLib.h @@ -0,0 +1,43 @@ +/******************************************************************************* +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __UTMIPHYLIB_H__ +#define __UTMIPHYLIB_H__ + +EFI_STATUS +UtmiPhyInit ( + VOID + ); + +#endif diff --git a/Platform/Marvell/Include/Protocol/Eeprom.h b/Platform/Marvell/Include/Protocol/Eeprom.h new file mode 100644 index 0000000000..fbe4282b91 --- /dev/null +++ b/Platform/Marvell/Include/Protocol/Eeprom.h @@ -0,0 +1,60 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __MARVELL_EEPROM_H__ +#define __MARVELL_EEPROM_H__ + +#define MARVELL_EEPROM_PROTOCOL_GUID { 0x71954bda, 0x60d3, 0x4ef8, { 0x8e, 0x3c, 0x0e, 0x33, 0x9f, 0x3b, 0xc2, 0x2b }} + +typedef struct _MARVELL_EEPROM_PROTOCOL MARVELL_EEPROM_PROTOCOL; + +#define EEPROM_READ 0x1 +#define EEPROM_WRITE 0x0 +typedef +EFI_STATUS +(EFIAPI *EFI_EEPROM_TRANSFER) ( + IN CONST MARVELL_EEPROM_PROTOCOL *This, + IN UINT16 Address, + IN UINT32 Length, + IN UINT8 *Buffer, + IN UINT8 Operation + ); + +struct _MARVELL_EEPROM_PROTOCOL { + EFI_EEPROM_TRANSFER Transfer; + UINT32 Identifier; +}; + +extern EFI_GUID gMarvellEepromProtocolGuid; +#endif diff --git a/Platform/Marvell/Include/Protocol/Mdio.h b/Platform/Marvell/Include/Protocol/Mdio.h new file mode 100644 index 0000000000..10acad4cc7 --- /dev/null +++ b/Platform/Marvell/Include/Protocol/Mdio.h @@ -0,0 +1,66 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __MDIO_H__ +#define __MDIO_H__ + +#define MARVELL_MDIO_PROTOCOL_GUID { 0x40010b03, 0x5f08, 0x496a, { 0xa2, 0x64, 0x10, 0x5e, 0x72, 0xd3, 0x71, 0xaa }} + +typedef struct _MARVELL_MDIO_PROTOCOL MARVELL_MDIO_PROTOCOL; + +typedef +EFI_STATUS +(EFIAPI *MARVELL_MDIO_READ) ( + IN CONST MARVELL_MDIO_PROTOCOL *This, + IN UINT32 PhyAddr, + IN UINT32 RegOff, + IN UINT32 *Data + ); + +typedef +EFI_STATUS +(EFIAPI *MARVELL_MDIO_WRITE) ( + IN CONST MARVELL_MDIO_PROTOCOL *This, + IN UINT32 PhyAddr, + IN UINT32 RegOff, + IN UINT32 Data + ); + +struct _MARVELL_MDIO_PROTOCOL { + MARVELL_MDIO_READ Read; + MARVELL_MDIO_WRITE Write; +}; + +extern EFI_GUID gMarvellMdioProtocolGuid; +#endif diff --git a/Platform/Marvell/Include/Protocol/MvPhy.h b/Platform/Marvell/Include/Protocol/MvPhy.h new file mode 100644 index 0000000000..43a9e0b889 --- /dev/null +++ b/Platform/Marvell/Include/Protocol/MvPhy.h @@ -0,0 +1,103 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __MV_PHY_H__ +#define __MV_PHY_H__ + +#define MARVELL_PHY_PROTOCOL_GUID { 0x32f48a43, 0x37e3, 0x4acf, { 0x93, 0xc4, 0x3e, 0x57, 0xa7, 0xb0, 0xfb, 0xdc }} + +typedef struct _MARVELL_PHY_PROTOCOL MARVELL_PHY_PROTOCOL; + +typedef enum { + PHY_CONNECTION_RGMII, + PHY_CONNECTION_RGMII_ID, + PHY_CONNECTION_RGMII_TXID, + PHY_CONNECTION_RGMII_RXID, + PHY_CONNECTION_SGMII, + PHY_CONNECTION_RTBI, + PHY_CONNECTION_XAUI, + PHY_CONNECTION_RXAUI +} PHY_CONNECTION; + +typedef enum { + NO_SPEED, + SPEED_10, + SPEED_100, + SPEED_1000, + SPEED_2500, + SPEED_10000 +} PHY_SPEED; + +typedef struct { + UINT32 Addr; + BOOLEAN LinkUp; + BOOLEAN FullDuplex; + BOOLEAN AutoNegotiation; + PHY_SPEED Speed; + PHY_CONNECTION Connection; +} PHY_DEVICE; + +/* + * Before calling MARVELL_PHY_STATUS driver should request PHY_DEVICE structure by + * calling MARVELL_PHY_INIT. Pointer to that needs to be provided as an argument to + * MARVELL_PHY_STATUS. + */ +typedef +EFI_STATUS +(EFIAPI *MARVELL_PHY_STATUS) ( + IN CONST MARVELL_PHY_PROTOCOL *This, + IN OUT PHY_DEVICE *PhyDev + ); + +/* + * MARVELL_PHY_INIT allocates PhyDev and provides driver with pointer via **PhyDev. + * After it becomes unnecessary, PhyDev should be freed by a driver (or it will + * get freed at ExitBootServices). + */ +typedef +EFI_STATUS +(EFIAPI *MARVELL_PHY_INIT) ( + IN CONST MARVELL_PHY_PROTOCOL *This, + IN UINT32 PhyAddr, + IN PHY_CONNECTION PhyConnection, + IN OUT PHY_DEVICE **PhyDev + ); + +struct _MARVELL_PHY_PROTOCOL { + MARVELL_PHY_STATUS Status; + MARVELL_PHY_INIT Init; +}; + +extern EFI_GUID gMarvellPhyProtocolGuid; +#endif diff --git a/Platform/Marvell/Include/Protocol/Spi.h b/Platform/Marvell/Include/Protocol/Spi.h new file mode 100644 index 0000000000..ae78a31ca0 --- /dev/null +++ b/Platform/Marvell/Include/Protocol/Spi.h @@ -0,0 +1,105 @@ +/******************************************************************************* +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ +#ifndef __MARVELL_SPI_MASTER_PROTOCOL_H__ +#define __MARVELL_SPI_MASTER_PROTOCOL_H__ + +extern EFI_GUID gMarvellSpiMasterProtocolGuid; + +typedef struct _MARVELL_SPI_MASTER_PROTOCOL MARVELL_SPI_MASTER_PROTOCOL; + +typedef enum { + SPI_MODE0, // CPOL = 0 & CPHA = 0 + SPI_MODE1, // CPOL = 0 & CPHA = 1 + SPI_MODE2, // CPOL = 1 & CPHA = 0 + SPI_MODE3 // CPOL = 1 & CPHA = 1 +} SPI_MODE; + +typedef struct { + INTN Cs; + INTN MaxFreq; + SPI_MODE Mode; +} SPI_DEVICE; + +typedef +EFI_STATUS +(EFIAPI *MV_SPI_INIT) ( + IN MARVELL_SPI_MASTER_PROTOCOL *This + ); + +typedef +EFI_STATUS +(EFIAPI *MV_SPI_TRANSFER) ( + IN MARVELL_SPI_MASTER_PROTOCOL *This, + IN SPI_DEVICE *Slave, + IN UINTN DataByteCount, + IN VOID *DataOut, + IN VOID *DataIn, + IN UINTN Flag + ); + +typedef +EFI_STATUS +(EFIAPI * MV_SPI_READ_WRITE) ( + IN MARVELL_SPI_MASTER_PROTOCOL *This, + IN SPI_DEVICE *Slave, + IN UINT8 *Cmd, + IN UINTN CmdSize, + IN UINT8 *DataOut, + OUT UINT8 *DataIn, + IN UINTN DataSize + ); + +typedef +SPI_DEVICE * +(EFIAPI *MV_SPI_SETUP_DEVICE) ( + IN MARVELL_SPI_MASTER_PROTOCOL *This, + IN UINTN Cs, + IN SPI_MODE Mode + ); + +typedef +EFI_STATUS +(EFIAPI *MV_SPI_FREE_DEVICE) ( + IN SPI_DEVICE *SpiDev + ); + +struct _MARVELL_SPI_MASTER_PROTOCOL { + MV_SPI_INIT Init; + MV_SPI_READ_WRITE ReadWrite; + MV_SPI_TRANSFER Transfer; + MV_SPI_SETUP_DEVICE SetupDevice; + MV_SPI_FREE_DEVICE FreeDevice; +}; + +#endif // __MARVELL_SPI_MASTER_PROTOCOL_H__ diff --git a/Platform/Marvell/Include/Protocol/SpiFlash.h b/Platform/Marvell/Include/Protocol/SpiFlash.h new file mode 100644 index 0000000000..743bb87553 --- /dev/null +++ b/Platform/Marvell/Include/Protocol/SpiFlash.h @@ -0,0 +1,113 @@ +/******************************************************************************* +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ +#ifndef __MV_SPI_FLASH__ +#define __MV_SPI_FLASH__ + +#include + +#define CMD_READ_ID 0x9f +#define READ_STATUS_REG_CMD 0x0b +#define CMD_WRITE_ENABLE 0x06 +#define CMD_FLAG_STATUS 0x70 +#define CMD_WRITE_STATUS_REG 0x01 +#define CMD_READ_ARRAY_FAST 0x0b +#define CMD_PAGE_PROGRAM 0x02 +#define CMD_BANK_WRITE 0xc5 +#define CMD_ERASE_64K 0xd8 +#define CMD_4B_ADDR_ENABLE 0xb7 + +extern EFI_GUID gMarvellSpiFlashProtocolGuid; + +typedef struct _MARVELL_SPI_FLASH_PROTOCOL MARVELL_SPI_FLASH_PROTOCOL; + +typedef +EFI_STATUS +(EFIAPI *MV_SPI_FLASH_INIT) ( + IN MARVELL_SPI_FLASH_PROTOCOL *This, + IN SPI_DEVICE *SpiDev + ); + +typedef +EFI_STATUS +(EFIAPI *MV_SPI_FLASH_READ_ID) ( + IN SPI_DEVICE *SpiDev, + IN UINT32 DataByteCount, + IN OUT UINT8 *Buffer + ); + +typedef +EFI_STATUS +(EFIAPI *MV_SPI_FLASH_READ) ( + IN SPI_DEVICE *SpiDev, + IN UINT32 Address, + IN UINTN DataByteCount, + IN VOID *Buffer + ); + +typedef +EFI_STATUS +(EFIAPI *MV_SPI_FLASH_WRITE) ( + IN SPI_DEVICE *SpiDev, + IN UINT32 Address, + IN UINTN DataByteCount, + IN VOID *Buffer + ); + +typedef +EFI_STATUS +(EFIAPI *MV_SPI_FLASH_ERASE) ( + IN SPI_DEVICE *SpiDev, + IN UINTN Address, + IN UINTN DataByteCount + ); + +typedef +EFI_STATUS +(EFIAPI *MV_SPI_FLASH_UPDATE) ( + IN SPI_DEVICE *SpiDev, + IN UINT32 Address, + IN UINTN DataByteCount, + IN UINT8 *Buffer + ); + +struct _MARVELL_SPI_FLASH_PROTOCOL { + MV_SPI_FLASH_INIT Init; + MV_SPI_FLASH_READ_ID ReadId; + MV_SPI_FLASH_READ Read; + MV_SPI_FLASH_WRITE Write; + MV_SPI_FLASH_ERASE Erase; + MV_SPI_FLASH_UPDATE Update; +}; + +#endif // __MV_SPI_FLASH__ diff --git a/Platform/Marvell/Library/ComPhyLib/ComPhyCp110.c b/Platform/Marvell/Library/ComPhyLib/ComPhyCp110.c new file mode 100755 index 0000000000..40a7b9921c --- /dev/null +++ b/Platform/Marvell/Library/ComPhyLib/ComPhyCp110.c @@ -0,0 +1,1853 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must Retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include "ComPhyLib.h" +#include + +#define SD_LANE_ADDR_WIDTH 0x1000 +#define HPIPE_ADDR_OFFSET 0x800 +#define COMPHY_ADDR_LANE_WIDTH 0x28 +#define SD_ADDR(base, Lane) (base + SD_LANE_ADDR_WIDTH * Lane) +#define HPIPE_ADDR(base, Lane) (SD_ADDR(base, Lane) + HPIPE_ADDR_OFFSET) +#define COMPHY_ADDR(base, Lane) (base + COMPHY_ADDR_LANE_WIDTH * Lane) + +DECLARE_A7K8K_NONDISCOVERABLE_TEMPLATE; + +/* + * For CP-110 we have 2 Selector registers "PHY Selectors" + * and " PIPE Selectors". + * PIPE selector include USB and PCIe options. + * PHY selector include the Ethernet and SATA options, every Ethernet option + * has different options, for example: serdes Lane2 have option Eth_port_0 + * that include (SGMII0, RXAUI0, SFI) + */ +COMPHY_MUX_DATA Cp110ComPhyMuxData[] = { + /* Lane 0 */ + {4, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_SGMII1, 0x1}, + {COMPHY_TYPE_SATA1, 0x4}, {COMPHY_TYPE_SATA3, 0x4}}}, + /* Lane 1 */ + {4, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_SGMII2, 0x1}, + {COMPHY_TYPE_SATA0, 0x4}, {COMPHY_TYPE_SATA2, 0x4}}}, + /* Lane 2 */ + {6, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_SGMII0, 0x1}, + {COMPHY_TYPE_RXAUI0, 0x1}, {COMPHY_TYPE_SFI, 0x1}, + {COMPHY_TYPE_SATA0, 0x4}, {COMPHY_TYPE_SATA2, 0x4}}}, + /* Lane 3 */ + {8, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_RXAUI1, 0x1}, + {COMPHY_TYPE_SGMII1, 0x2}, {COMPHY_TYPE_SATA1, 0x4}, + {COMPHY_TYPE_SATA3, 0x4}}}, + /* Lane 4 */ + {7, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_SGMII0, 0x2}, + {COMPHY_TYPE_RXAUI0, 0x2}, {COMPHY_TYPE_SFI, 0x2}, + {COMPHY_TYPE_SGMII1, 0x1}}}, + /* Lane 5 */ + {6, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_SGMII2, 0x1}, + {COMPHY_TYPE_RXAUI1, 0x2}, {COMPHY_TYPE_SATA1, 0x4}, + {COMPHY_TYPE_SATA3, 0x4}}}, +}; + +COMPHY_MUX_DATA Cp110ComPhyPipeMuxData[] = { + /* Lane 0 */ + {2, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_PCIE0, 0x4}}}, + /* Lane 1 */ + {4, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_USB3_HOST0, 0x1}, + {COMPHY_TYPE_USB3_DEVICE, 0x2}, {COMPHY_TYPE_PCIE0, 0x4}}}, + /* Lane 2 */ + {3, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_USB3_HOST0, 0x1}, + {COMPHY_TYPE_PCIE0, 0x4}}}, + /* Lane 3 */ + {3, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_USB3_HOST1, 0x1}, + {COMPHY_TYPE_PCIE0, 0x4}}}, + /* Lane 4 */ + {4, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_USB3_HOST1, 0x1}, + {COMPHY_TYPE_USB3_DEVICE, 0x2}, {COMPHY_TYPE_PCIE1, 0x4}}}, + /* Lane 5 */ + {2, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_PCIE2, 0x4}}}, +}; + +STATIC +VOID +ComPhyPcieRFUConfiguration ( + IN EFI_PHYSICAL_ADDRESS ComPhyAddr +) +{ + UINT32 Mask, Data; + + /* RFU configurations - hard reset ComPhy */ + Mask = COMMON_PHY_CFG1_PWR_UP_MASK; + Data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET; + Mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK; + Data |= 0x1 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET; + Mask |= COMMON_PHY_CFG1_PWR_ON_RESET_MASK; + Data |= 0x0 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET; + Mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK; + Data |= 0x0 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET; + Mask |= COMMON_PHY_PHY_MODE_MASK; + Data |= 0x0 << COMMON_PHY_PHY_MODE_OFFSET; + RegSet (ComPhyAddr + COMMON_PHY_CFG1_REG, Data, Mask); + + /* Release from hard reset */ + Mask = COMMON_PHY_CFG1_PWR_ON_RESET_MASK; + Data = 0x1 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET; + Mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK; + Data |= 0x1 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET; + RegSet (ComPhyAddr + COMMON_PHY_CFG1_REG, Data, Mask); + + /* Wait 1ms - until band gap and ref clock ready */ + MicroSecondDelay (1000); + MemoryFence (); +} + +STATIC +VOID +ComPhyPciePhyConfiguration ( + IN EFI_PHYSICAL_ADDRESS ComPhyAddr, + IN EFI_PHYSICAL_ADDRESS HpipeAddr +) +{ + UINT32 Mask, Data, PcieClk = 0; + + /* Set PIPE soft reset */ + Mask = HPIPE_RST_CLK_CTRL_PIPE_RST_MASK; + Data = 0x1 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET; + + /* Set PHY Datapath width mode for V0 */ + Mask |= HPIPE_RST_CLK_CTRL_FIXED_PCLK_MASK; + Data |= 0x1 << HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET; + + /* Set Data bus width USB mode for V0 */ + Mask |= HPIPE_RST_CLK_CTRL_PIPE_WIDTH_MASK; + Data |= 0x0 << HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET; + + /* Set CORE_CLK output frequency for 250Mhz */ + Mask |= HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_MASK; + Data |= 0x0 << HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET; + RegSet (HpipeAddr + HPIPE_RST_CLK_CTRL_REG, Data, Mask); + + /* Set PLL ready delay for 0x2 */ + RegSet (HpipeAddr + HPIPE_CLK_SRC_LO_REG, + 0x2 << HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET, + HPIPE_CLK_SRC_LO_PLL_RDY_DL_MASK); + + /* Set PIPE mode interface to PCIe3 - 0x1 */ + RegSet (HpipeAddr + HPIPE_CLK_SRC_HI_REG, + 0x1 << HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET, HPIPE_CLK_SRC_HI_MODE_PIPE_MASK); + + /* Config update polarity equalization */ + RegSet (HpipeAddr + HPIPE_LANE_EQ_CFG1_REG, + 0x1 << HPIPE_CFG_UPDATE_POLARITY_OFFSET, HPIPE_CFG_UPDATE_POLARITY_MASK); + + /* Set PIPE version 4 to mode enable */ + RegSet (HpipeAddr + HPIPE_DFE_CTRL_28_REG, + 0x1 << HPIPE_DFE_CTRL_28_PIPE4_OFFSET, HPIPE_DFE_CTRL_28_PIPE4_MASK); + + /* Enable PIN clock 100M_125M */ + Mask = HPIPE_MISC_CLK100M_125M_MASK; + Data = 0x1 << HPIPE_MISC_CLK100M_125M_OFFSET; + + /* Set PIN_TXDCLK_2X Clock Frequency Selection for outputs 500MHz clock */ + Mask |= HPIPE_MISC_TXDCLK_2X_MASK; + Data |= 0x0 << HPIPE_MISC_TXDCLK_2X_OFFSET; + + /* Enable 500MHz Clock */ + Mask |= HPIPE_MISC_CLK500_EN_MASK; + Data |= 0x1 << HPIPE_MISC_CLK500_EN_OFFSET; + + if (PcieClk) { + /* Set reference clock comes from group 1 */ + Mask |= HPIPE_MISC_REFCLK_SEL_MASK; + Data |= 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET; + } else { + /* Set reference clock comes from group 2 */ + Mask |= HPIPE_MISC_REFCLK_SEL_MASK; + Data |= 0x1 << HPIPE_MISC_REFCLK_SEL_OFFSET; + } + + /* Force ICP */ + Mask |= HPIPE_MISC_ICP_FORCE_MASK; + Data |= 0x1 << HPIPE_MISC_ICP_FORCE_OFFSET; + RegSet (HpipeAddr + HPIPE_MISC_REG, Data, Mask); + + if (PcieClk) { + /* Set reference frequcency select - 0x2 for 25MHz*/ + Mask = HPIPE_PWR_PLL_REF_FREQ_MASK; + Data = 0x2 << HPIPE_PWR_PLL_REF_FREQ_OFFSET; + } else { + /* Set reference frequcency select - 0x0 for 100MHz*/ + Mask = HPIPE_PWR_PLL_REF_FREQ_MASK; + Data = 0x0 << HPIPE_PWR_PLL_REF_FREQ_OFFSET; + } + + /* Set PHY mode to PCIe */ + Mask |= HPIPE_PWR_PLL_PHY_MODE_MASK; + Data |= 0x3 << HPIPE_PWR_PLL_PHY_MODE_OFFSET; + RegSet (HpipeAddr + HPIPE_PWR_PLL_REG, Data, Mask); + + /* + * Set the amount of time spent in the LoZ state - set + * for 0x7 only if the PCIe clock is output + */ + if (PcieClk) + RegSet (HpipeAddr + HPIPE_GLOBAL_PM_CTRL, + 0x7 << HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET, + HPIPE_GLOBAL_PM_RXDLOZ_WAIT_MASK); + + /* Set Maximal PHY Generation Setting (8Gbps) */ + Mask = HPIPE_INTERFACE_GEN_MAX_MASK; + Data = 0x2 << HPIPE_INTERFACE_GEN_MAX_OFFSET; + /* Bypass frame detection and sync detection for RX DATA */ + Mask |= HPIPE_INTERFACE_DET_BYPASS_MASK; + Data |= 0x1 << HPIPE_INTERFACE_DET_BYPASS_OFFSET; + /* Set Link Train Mode (Tx training control pins are used) */ + Mask |= HPIPE_INTERFACE_LINK_TRAIN_MASK; + Data |= 0x1 << HPIPE_INTERFACE_LINK_TRAIN_OFFSET; + RegSet (HpipeAddr + HPIPE_INTERFACE_REG, Data, Mask); + + /* Set Idle_sync enable */ + Mask = HPIPE_PCIE_IDLE_SYNC_MASK; + Data = 0x1 << HPIPE_PCIE_IDLE_SYNC_OFFSET; + + /* Select bits for PCIE Gen3(32bit) */ + Mask |= HPIPE_PCIE_SEL_BITS_MASK; + Data |= 0x2 << HPIPE_PCIE_SEL_BITS_OFFSET; + RegSet (HpipeAddr + HPIPE_PCIE_REG0, Data, Mask); + + /* Enable Tx_adapt_g1 */ + Mask = HPIPE_TX_TRAIN_CTRL_G1_MASK; + Data = 0x1 << HPIPE_TX_TRAIN_CTRL_G1_OFFSET; + + /* Enable Tx_adapt_gn1 */ + Mask |= HPIPE_TX_TRAIN_CTRL_GN1_MASK; + Data |= 0x1 << HPIPE_TX_TRAIN_CTRL_GN1_OFFSET; + + /* Disable Tx_adapt_g0 */ + Mask |= HPIPE_TX_TRAIN_CTRL_G0_MASK; + Data |= 0x0 << HPIPE_TX_TRAIN_CTRL_G0_OFFSET; + RegSet (HpipeAddr + HPIPE_TX_TRAIN_CTRL_REG, Data, Mask); + + /* Set reg_tx_train_chk_init */ + Mask = HPIPE_TX_TRAIN_CHK_INIT_MASK; + Data = 0x0 << HPIPE_TX_TRAIN_CHK_INIT_OFFSET; + + /* Enable TX_COE_FM_PIN_PCIE3_EN */ + Mask |= HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_MASK; + Data |= 0x1 << HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET; + RegSet (HpipeAddr + HPIPE_TX_TRAIN_REG, Data, Mask); +} + +STATIC +VOID +ComPhyPcieSetAnalogParameters ( + IN EFI_PHYSICAL_ADDRESS HpipeAddr +) +{ + UINT32 Data, Mask; + + /* Set preset sweep configurations */ + Mask = HPIPE_TX_TX_STATUS_CHECK_MODE_MASK | + HPIPE_TX_NUM_OF_PRESET_MASK | + HPIPE_TX_SWEEP_PRESET_EN_MASK; + Data = (0x1 << HPIPE_TX_STATUS_CHECK_MODE_OFFSET) | + (0x7 << HPIPE_TX_NUM_OF_PRESET_OFFSET) | + (0x1 << HPIPE_TX_SWEEP_PRESET_EN_OFFSET); + MmioAndThenOr32 (HpipeAddr + HPIPE_TX_TRAIN_CTRL_11_REG, ~Mask, Data); + + /* Tx train start configuration */ + Mask = HPIPE_TX_TRAIN_START_SQ_EN_MASK | + HPIPE_TX_TRAIN_START_FRM_DET_EN_MASK | + HPIPE_TX_TRAIN_START_FRM_LOCK_EN_MASK | + HPIPE_TX_TRAIN_WAIT_TIME_EN_MASK; + Data = (0x1 << HPIPE_TX_TRAIN_START_SQ_EN_OFFSET) | + (0x1 << HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET); + MmioAndThenOr32 (HpipeAddr + HPIPE_TX_TRAIN_CTRL_5_REG, ~Mask, Data); + + /* Enable Tx train P2P */ + MmioOr32 (HpipeAddr + HPIPE_TX_TRAIN_CTRL_0_REG, HPIPE_TX_TRAIN_P2P_HOLD_MASK); + + /* Configure Tx train timeout */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_TX_TRAIN_CTRL_4_REG, + ~HPIPE_TRX_TRAIN_TIMER_MASK, + 0x17 << HPIPE_TRX_TRAIN_TIMER_OFFSET + ); + + /* Disable G0/G1/GN1 adaptation */ + MmioAnd32 ( + HpipeAddr + HPIPE_TX_TRAIN_CTRL_REG, + ~(HPIPE_TX_TRAIN_CTRL_G1_MASK | HPIPE_TX_TRAIN_CTRL_GN1_MASK | HPIPE_TX_TRAIN_CTRL_G0_OFFSET) + ); + + /* Disable DTL frequency loop */ + MmioAnd32 (HpipeAddr + HPIPE_PWR_CTR_DTL_REG, ~HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK); + + /* Configure Generation 3 DFE */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_G3_SET4_REG, + ~HPIPE_GX_SET4_DFE_RES_MASK, + 0x3 << HPIPE_GX_SET4_DFE_RES_OFFSET + ); + + /* Use TX/RX training result for DFE */ + MmioAnd32 (HpipeAddr + HPIPE_DFE_REG0, ~HPIPE_DFE_RES_FORCE_MASK); + + /* Configure initial and final coefficient value for receiver */ + MmioAndThenOr32 (HpipeAddr + HPIPE_G3_SET1_REG, ~Mask, Data); + Mask = HPIPE_GX_SET1_RX_SELMUPI_MASK | + HPIPE_GX_SET1_RX_SELMUPP_MASK | + HPIPE_GX_SET1_SAMPLER_INPAIRX2_EN_MASK; + Data = 0x1 | (0x1 << HPIPE_GX_SET1_RX_SELMUPP_OFFSET); + MmioAndThenOr32 (HpipeAddr + HPIPE_G3_SET1_REG, ~Mask, Data); + + /* Trigger sampler 5us enable pulse */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, + ~HPIPE_SAMPLER_MASK, + 0x1 << HPIPE_SAMPLER_OFFSET + ); + MicroSecondDelay (5); + MmioAnd32 ( + HpipeAddr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, + ~HPIPE_SAMPLER_MASK + ); + + /* FFE resistor tuning for different bandwidth */ + Mask = HPIPE_GX_SET3_FFE_DEG_RES_LEVEL_MASK | + HPIPE_GX_SET3_FFE_LOAD_RES_LEVEL_MASK; + Data = (0x1 << HPIPE_GX_SET3_FFE_DEG_RES_LEVEL_OFFSET) | + (0x3 << HPIPE_GX_SET3_FFE_LOAD_RES_LEVEL_OFFSET); + MmioAndThenOr32 (HpipeAddr + HPIPE_G3_SET3_REG, ~Mask, Data); + + /* Pattern lock lost timeout disable */ + MmioAnd32 (HpipeAddr + HPIPE_FRAME_DETECT_CTRL_3_REG, ~HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_MASK); + + /* Configure DFE adaptations */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_CDR_CONTROL_REG, + ~(HPIPE_CDR_MAX_DFE_ADAPT_1_MASK | HPIPE_CDR_MAX_DFE_ADAPT_0_MASK | HPIPE_CDR_RX_MAX_DFE_ADAPT_1_MASK), + 0x1 << HPIPE_CDR_MAX_DFE_ADAPT_1_OFFSET + ); + MmioAnd32 (HpipeAddr + HPIPE_DFE_CONTROL_REG, ~HPIPE_DFE_TX_MAX_DFE_ADAPT_MASK); + + /* Hpipe Generation 2 setting 1*/ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_G2_SET1_REG, + ~(HPIPE_GX_SET1_RX_SELMUPI_MASK | HPIPE_GX_SET1_RX_SELMUPP_MASK | HPIPE_GX_SET1_RX_SELMUFI_MASK), + 0x1 << HPIPE_GX_SET1_RX_SELMUPP_OFFSET + ); + + /* DFE enable */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_G2_SET4_REG, + ~HPIPE_GX_SET4_DFE_RES_MASK, + 0x3 << HPIPE_GX_SET4_DFE_RES_OFFSET + ); + + /* Configure DFE Resolution */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_LANE_CFG4_REG, + ~HPIPE_LANE_CFG4_DFE_EN_SEL_MASK, + 0x1 << HPIPE_LANE_CFG4_DFE_EN_SEL_OFFSET + ); + + /* VDD calibration control */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_VDD_CAL_CTRL_REG, + ~HPIPE_EXT_SELLV_RXSAMPL_MASK, + 0x16 << HPIPE_EXT_SELLV_RXSAMPL_OFFSET + ); + + /* Set PLL Charge-pump Current Control */ + MmioAndThenOr32 (HpipeAddr + HPIPE_G3_SET5_REG, ~HPIPE_GX_SET5_ICP_MASK, 0x4); + + /* Set lane rqualization remote setting */ + Mask = HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_MASK | + HPIPE_LANE_CFG_FOM_ONLY_MODE_MASK | + HPIPE_LANE_CFG_FOM_PRESET_VECTOR_MASK; + Data = (0x1 << HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_OFFSET) | + (0x1 << HPIPE_LANE_CFG_FOM_ONLY_MODE_OFFFSET) | + (0x2 << HPIPE_LANE_CFG_FOM_PRESET_VECTOR_OFFSET); + MmioAndThenOr32 (HpipeAddr + HPIPE_LANE_EQ_REMOTE_SETTING_REG, ~Mask, Data); + + /* Set phy in root complex mode */ + MmioOr32 (HpipeAddr + HPIPE_LANE_EQU_CONFIG_0_REG, HPIPE_CFG_PHY_RC_EP_MASK); +} + +STATIC +VOID +ComPhyPciePhyPowerUp ( + IN EFI_PHYSICAL_ADDRESS HpipeAddr +) +{ + /* Release from PIPE soft reset */ + RegSet (HpipeAddr + HPIPE_RST_CLK_CTRL_REG, + 0x0 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET, + HPIPE_RST_CLK_CTRL_PIPE_RST_MASK); + + /* Wait 15ms - for ComPhy calibration done */ + MicroSecondDelay (15000); + MemoryFence (); +} + +STATIC +EFI_STATUS +ComPhyPcieCheckPll ( + IN EFI_PHYSICAL_ADDRESS HpipeAddr +) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINT32 Data; + + /* Read Lane status */ + Data = MmioRead32 (HpipeAddr + HPIPE_LANE_STATUS0_REG); + if ((Data & HPIPE_LANE_STATUS0_PCLK_EN_MASK) == 0) { + DEBUG((DEBUG_INFO, "ComPhy: Read from reg = %p - value = 0x%x\n", + HpipeAddr + HPIPE_LANE_STATUS0_REG, Data)); + DEBUG((DEBUG_INFO, "ComPhy: HPIPE_LANE_STATUS0_PCLK_EN_MASK is 0\n")); + Status = EFI_D_ERROR; + } + + return Status; +} + +STATIC +EFI_STATUS +ComPhyPciePowerUp ( + IN UINT32 Lane, + IN UINT32 PcieBy4, + IN EFI_PHYSICAL_ADDRESS HpipeBase, + IN EFI_PHYSICAL_ADDRESS ComPhyBase + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + EFI_PHYSICAL_ADDRESS HpipeAddr = HPIPE_ADDR(HpipeBase, Lane); + EFI_PHYSICAL_ADDRESS ComPhyAddr = COMPHY_ADDR(ComPhyBase, Lane); + + DEBUG((DEBUG_INFO, "ComPhy: stage: RFU configurations - hard reset ComPhy\n")); + + ComPhyPcieRFUConfiguration (ComPhyAddr); + + DEBUG((DEBUG_INFO, "ComPhy: stage: ComPhy configuration\n")); + + ComPhyPciePhyConfiguration (ComPhyAddr, HpipeAddr); + + DEBUG((DEBUG_INFO, "ComPhy: stage: Set analog paramters\n")); + + ComPhyPcieSetAnalogParameters (HpipeAddr); + + DEBUG((DEBUG_INFO, "ComPhy: stage: ComPhy power up\n")); + + ComPhyPciePhyPowerUp (HpipeAddr); + + DEBUG((DEBUG_INFO, "ComPhy: stage: Check PLL\n")); + + Status = ComPhyPcieCheckPll (HpipeAddr); + + return Status; +} + +STATIC +VOID +ComPhyUsb3RFUConfiguration ( + IN EFI_PHYSICAL_ADDRESS ComPhyAddr +) +{ + UINT32 Mask, Data; + + /* RFU configurations - hard reset ComPhy */ + Mask = COMMON_PHY_CFG1_PWR_UP_MASK; + Data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET; + Mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK; + Data |= 0x1 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET; + Mask |= COMMON_PHY_CFG1_PWR_ON_RESET_MASK; + Data |= 0x0 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET; + Mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK; + Data |= 0x0 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET; + Mask |= COMMON_PHY_PHY_MODE_MASK; + Data |= 0x1 << COMMON_PHY_PHY_MODE_OFFSET; + RegSet (ComPhyAddr + COMMON_PHY_CFG1_REG, Data, Mask); + + /* Release from hard reset */ + Mask = COMMON_PHY_CFG1_PWR_ON_RESET_MASK; + Data = 0x1 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET; + Mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK; + Data |= 0x1 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET; + RegSet (ComPhyAddr + COMMON_PHY_CFG1_REG, Data, Mask); + + /* Wait 1ms - until band gap and ref clock ready */ + MicroSecondDelay (1000); + MemoryFence (); +} + +STATIC +VOID +ComPhyUsb3PhyConfiguration ( + IN EFI_PHYSICAL_ADDRESS HpipeAddr +) +{ + UINT32 Mask, Data; + + /* Set PIPE soft reset */ + Mask = HPIPE_RST_CLK_CTRL_PIPE_RST_MASK; + Data = 0x1 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET; + + /* Set PHY Datapath width mode for V0 */ + Mask |= HPIPE_RST_CLK_CTRL_FIXED_PCLK_MASK; + Data |= 0x0 << HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET; + + /* Set Data bus width USB mode for V0 */ + Mask |= HPIPE_RST_CLK_CTRL_PIPE_WIDTH_MASK; + Data |= 0x0 << HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET; + + /* Set CORE_CLK output frequency for 250Mhz */ + Mask |= HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_MASK; + Data |= 0x0 << HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET; + RegSet (HpipeAddr + HPIPE_RST_CLK_CTRL_REG, Data, Mask); + + /* Set PLL ready delay for 0x2 */ + RegSet (HpipeAddr + HPIPE_CLK_SRC_LO_REG, + 0x2 << HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET, + HPIPE_CLK_SRC_LO_PLL_RDY_DL_MASK); + + /* Set reference clock to come from group 1 - 25Mhz */ + RegSet (HpipeAddr + HPIPE_MISC_REG, 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET, + HPIPE_MISC_REFCLK_SEL_MASK); + + /* Set reference frequcency select - 0x2 */ + Mask = HPIPE_PWR_PLL_REF_FREQ_MASK; + Data = 0x2 << HPIPE_PWR_PLL_REF_FREQ_OFFSET; + + /* Set PHY mode to USB - 0x5 */ + Mask |= HPIPE_PWR_PLL_PHY_MODE_MASK; + Data |= 0x5 << HPIPE_PWR_PLL_PHY_MODE_OFFSET; + RegSet (HpipeAddr + HPIPE_PWR_PLL_REG, Data, Mask); + + /* Set the amount of time spent in the LoZ state - set for 0x7 */ + RegSet (HpipeAddr + HPIPE_GLOBAL_PM_CTRL, + 0x7 << HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET, + HPIPE_GLOBAL_PM_RXDLOZ_WAIT_MASK); + + /* Set max PHY generation setting - 5Gbps */ + RegSet (HpipeAddr + HPIPE_INTERFACE_REG, + 0x1 << HPIPE_INTERFACE_GEN_MAX_OFFSET, HPIPE_INTERFACE_GEN_MAX_MASK); + + /* Set select Data width 20Bit (SEL_BITS[2:0]) */ + RegSet (HpipeAddr + HPIPE_LOOPBACK_REG, + 0x1 << HPIPE_LOOPBACK_SEL_OFFSET, HPIPE_LOOPBACK_SEL_MASK); +} + +STATIC +VOID +ComPhyUsb3SetAnalogParameters ( + IN EFI_PHYSICAL_ADDRESS HpipeAddr +) +{ + UINT32 Data, Mask; + + /* Set Pin DFE_PAT_DIS -> Bit[1]: PIN_DFE_PAT_DIS = 0x0 */ + Mask = HPIPE_LANE_CFG4_DFE_CTRL_MASK; + Data = 0x1 << HPIPE_LANE_CFG4_DFE_CTRL_OFFSET; + + /* Set Override PHY DFE control pins for 0x1 */ + Mask |= HPIPE_LANE_CFG4_DFE_OVER_MASK; + Data |= 0x1 << HPIPE_LANE_CFG4_DFE_OVER_OFFSET; + + /* Set Spread Spectrum Clock Enable fot 0x1 */ + Mask |= HPIPE_LANE_CFG4_SSC_CTRL_MASK; + Data |= 0x1 << HPIPE_LANE_CFG4_SSC_CTRL_OFFSET; + RegSet (HpipeAddr + HPIPE_LANE_CFG4_REG, Data, Mask); +} + +STATIC +UINTN +ComphyUsb3PowerUp ( + UINT32 Lane, + EFI_PHYSICAL_ADDRESS HpipeBase, + EFI_PHYSICAL_ADDRESS ComPhyBase + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINT32 Data; + EFI_PHYSICAL_ADDRESS HpipeAddr = HPIPE_ADDR(HpipeBase, Lane); + EFI_PHYSICAL_ADDRESS ComPhyAddr = COMPHY_ADDR(ComPhyBase, Lane); + + DEBUG((DEBUG_INFO, "ComPhy: stage: RFU configurations - hard reset ComPhy\n")); + + ComPhyUsb3RFUConfiguration (ComPhyAddr); + + /* Start ComPhy Configuration */ + DEBUG((DEBUG_INFO, "stage: Comphy configuration\n")); + + ComPhyUsb3PhyConfiguration (HpipeAddr); + + /* Start analog paramters from ETP(HW) */ + DEBUG((DEBUG_INFO, "ComPhy: stage: Analog paramters from ETP(HW)\n")); + + ComPhyUsb3SetAnalogParameters (HpipeAddr); + + DEBUG((DEBUG_INFO, "ComPhy: stage: Comphy power up\n")); + + /* Release from PIPE soft reset */ + RegSet (HpipeAddr + HPIPE_RST_CLK_CTRL_REG, + 0x0 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET, + HPIPE_RST_CLK_CTRL_PIPE_RST_MASK); + + /* Wait 15ms - for ComPhy calibration done */ + MicroSecondDelay (15000); + MemoryFence (); + + DEBUG((DEBUG_INFO, "ComPhy: stage: Check PLL\n")); + + /* Read Lane status */ + Data = MmioRead32 (HpipeAddr + HPIPE_LANE_STATUS0_REG); + if ((Data & HPIPE_LANE_STATUS0_PCLK_EN_MASK) == 0) { + DEBUG((DEBUG_ERROR, "ComPhy: HPIPE_LANE_STATUS0_PCLK_EN_MASK is 0\n")); + Status = EFI_D_ERROR; + } + + return Status; +} + +STATIC +UINT32 +PollingWithTimeout ( + IN EFI_PHYSICAL_ADDRESS Addr, + IN UINT32 Val, + IN UINT32 Mask, + IN UINT64 Usec_timeout + ) +{ + UINT32 Data; + + do { + MicroSecondDelay(1); + Data = MmioRead32(Addr) & Mask; + } while (Data != Val && --Usec_timeout > 0); + + if (Usec_timeout == 0) + return Data; + return 0; +} + +STATIC +VOID +ComPhySataMacPowerDown ( + IN EFI_PHYSICAL_ADDRESS SataBase +) +{ + UINT32 Mask, Data; + + /* + * MAC configuration - power down ComPhy + * Use indirect address for vendor specific SATA control register + */ + RegSet (SataBase + SATA3_VENDOR_ADDRESS, + SATA_CONTROL_REG << SATA3_VENDOR_ADDR_OFSSET, SATA3_VENDOR_ADDR_MASK); + + /* SATA 0 power down */ + Mask = SATA3_CTRL_SATA0_PD_MASK; + Data = 0x1 << SATA3_CTRL_SATA0_PD_OFFSET; + + /* SATA 1 power down */ + Mask |= SATA3_CTRL_SATA1_PD_MASK; + Data |= 0x1 << SATA3_CTRL_SATA1_PD_OFFSET; + + /* SATA SSU disable */ + Mask |= SATA3_CTRL_SATA1_ENABLE_MASK; + Data |= 0x0 << SATA3_CTRL_SATA1_ENABLE_OFFSET; + + /* SATA port 1 disable */ + Mask |= SATA3_CTRL_SATA_SSU_MASK; + Data |= 0x0 << SATA3_CTRL_SATA_SSU_OFFSET; + RegSet (SataBase + SATA3_VENDOR_DATA, Data, Mask); +} + +STATIC +VOID +ComPhySataRFUConfiguration ( + IN EFI_PHYSICAL_ADDRESS ComPhyAddr, + IN EFI_PHYSICAL_ADDRESS SdIpAddr +) +{ + UINT32 Mask, Data; + + /* RFU configurations - hard reset ComPhy */ + Mask = COMMON_PHY_CFG1_PWR_UP_MASK; + Data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET; + Mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK; + Data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET; + Mask |= COMMON_PHY_CFG1_PWR_ON_RESET_MASK; + Data |= 0x0 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET; + Mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK; + Data |= 0x0 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET; + RegSet (ComPhyAddr + COMMON_PHY_CFG1_REG, Data, Mask); + + /* Set select Data width 40Bit - SATA mode only */ + RegSet (ComPhyAddr + COMMON_PHY_CFG6_REG, + 0x1 << COMMON_PHY_CFG6_IF_40_SEL_OFFSET, COMMON_PHY_CFG6_IF_40_SEL_MASK); + + /* Release from hard reset in SD external */ + Mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK; + Data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET; + Mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK; + Data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET; + RegSet (SdIpAddr + SD_EXTERNAL_CONFIG1_REG, Data, Mask); + + /* Wait 1ms - until band gap and ref clock ready */ + MicroSecondDelay (1000); + MemoryFence (); +} + +STATIC +VOID +ComPhySataPhyConfiguration ( + IN EFI_PHYSICAL_ADDRESS HpipeAddr +) +{ + UINT32 Mask, Data; + + /* Set reference clock to comes from group 1 - choose 25Mhz */ + RegSet (HpipeAddr + HPIPE_MISC_REG, + 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET, HPIPE_MISC_REFCLK_SEL_MASK); + + /* Reference frequency select set 1 (for SATA = 25Mhz) */ + Mask = HPIPE_PWR_PLL_REF_FREQ_MASK; + Data = 0x1 << HPIPE_PWR_PLL_REF_FREQ_OFFSET; + + /* PHY mode select (set SATA = 0x0 */ + Mask |= HPIPE_PWR_PLL_PHY_MODE_MASK; + Data |= 0x0 << HPIPE_PWR_PLL_PHY_MODE_OFFSET; + RegSet (HpipeAddr + HPIPE_PWR_PLL_REG, Data, Mask); + + /* Set max PHY generation setting - 6Gbps */ + RegSet (HpipeAddr + HPIPE_INTERFACE_REG, + 0x2 << HPIPE_INTERFACE_GEN_MAX_OFFSET, HPIPE_INTERFACE_GEN_MAX_MASK); + + /* Set select Data width 40Bit (SEL_BITS[2:0]) */ + RegSet (HpipeAddr + HPIPE_LOOPBACK_REG, + 0x2 << HPIPE_LOOPBACK_SEL_OFFSET, HPIPE_LOOPBACK_SEL_MASK); +} + +STATIC +VOID +ComPhySataSetAnalogParameters ( + IN EFI_PHYSICAL_ADDRESS HpipeAddr, + IN EFI_PHYSICAL_ADDRESS SdIpAddr +) +{ + UINT32 Mask, Data; + + /* Hpipe Generation 1 settings 1 */ + Mask = HPIPE_GX_SET1_RX_SELMUPI_MASK | + HPIPE_GX_SET1_RX_SELMUPP_MASK | + HPIPE_GX_SET1_RX_SELMUFI_MASK | + HPIPE_GX_SET1_RX_SELMUFF_MASK | + HPIPE_GX_SET1_RX_DIGCK_DIV_MASK; + Data = (0x1 << HPIPE_GX_SET1_RX_SELMUPP_OFFSET) | + (0x3 << HPIPE_GX_SET1_RX_SELMUFF_OFFSET) | + (0x1 << HPIPE_GX_SET1_RX_DIGCK_DIV_OFFSET); + MmioAndThenOr32 (HpipeAddr + HPIPE_G1_SET1_REG, ~Mask, Data); + + /* Hpipe Generation 1 settings 3 */ + Mask = HPIPE_GX_SET3_FFE_CAP_SEL_MASK | + HPIPE_GX_SET3_FFE_RES_SEL_MASK | + HPIPE_GX_SET3_FFE_SETTING_FORCE_MASK | + HPIPE_GX_SET3_FFE_DEG_RES_LEVEL_MASK | + HPIPE_GX_SET3_FFE_LOAD_RES_LEVEL_MASK; + Data = 0xf | + (0x2 << HPIPE_GX_SET3_FFE_RES_SEL_OFFSET) | + (0x1 << HPIPE_GX_SET3_FFE_SETTING_FORCE_OFFSET) | + (0x1 << HPIPE_GX_SET3_FFE_DEG_RES_LEVEL_OFFSET) | + (0x1 << HPIPE_GX_SET3_FFE_LOAD_RES_LEVEL_OFFSET); + MmioAndThenOr32 (HpipeAddr + HPIPE_G1_SET3_REG, ~Mask, Data); + + /* Hpipe Generation 2 settings 1 */ + Mask = HPIPE_GX_SET1_RX_SELMUPI_MASK | + HPIPE_GX_SET1_RX_SELMUPP_MASK | + HPIPE_GX_SET1_RX_SELMUFI_MASK | + HPIPE_GX_SET1_RX_SELMUFF_MASK | + HPIPE_GX_SET1_RX_DIGCK_DIV_MASK; + Data = (0x1 << HPIPE_GX_SET1_RX_SELMUPP_OFFSET) | + (0x3 << HPIPE_GX_SET1_RX_SELMUFF_OFFSET) | + (0x1 << HPIPE_GX_SET1_RX_DIGCK_DIV_OFFSET); + MmioAndThenOr32 (HpipeAddr + HPIPE_G2_SET1_REG, ~Mask, Data); + + /* Hpipe Generation 3 settings 1 */ + Mask = HPIPE_GX_SET1_RX_SELMUPI_MASK | + HPIPE_GX_SET1_RX_SELMUPP_MASK | + HPIPE_GX_SET1_RX_SELMUFI_MASK | + HPIPE_GX_SET1_RX_SELMUFF_MASK | + HPIPE_GX_SET1_RX_DFE_EN_MASK | + HPIPE_GX_SET1_RX_DIGCK_DIV_MASK | + HPIPE_GX_SET1_SAMPLER_INPAIRX2_EN_MASK; + Data = 0x2 | + (0x2 << HPIPE_GX_SET1_RX_SELMUPP_OFFSET) | + (0x3 << HPIPE_GX_SET1_RX_SELMUFI_OFFSET) | + (0x3 << HPIPE_GX_SET1_RX_SELMUFF_OFFSET) | + (0x1 << HPIPE_GX_SET1_RX_DFE_EN_OFFSET) | + (0x2 << HPIPE_GX_SET1_RX_DIGCK_DIV_OFFSET); + MmioAndThenOr32 (HpipeAddr + HPIPE_G3_SET1_REG, ~Mask, Data); + + /* DTL Control */ + Mask = HPIPE_PWR_CTR_DTL_SQ_DET_EN_MASK | + HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_MASK | + HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK | + HPIPE_PWR_CTR_DTL_CLAMPING_SEL_MASK | + HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_MASK | + HPIPE_PWR_CTR_DTL_CLK_MODE_MASK | + HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_MASK; + Data = 0x1 | + (0x1 << HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_OFFSET) | + (0x1 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET) | + (0x1 << HPIPE_PWR_CTR_DTL_CLAMPING_SEL_OFFSET) | + (0x1 << HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_OFFSET) | + (0x1 << HPIPE_PWR_CTR_DTL_CLK_MODE_OFFSET) | + (0x1 << HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_OFFSET); + MmioAndThenOr32 (HpipeAddr + HPIPE_PWR_CTR_DTL_REG, ~Mask, Data); + + /* Trigger sampler enable pulse (by toggling the bit) */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, + ~HPIPE_SAMPLER_MASK, + 0x1 << HPIPE_SAMPLER_OFFSET + ); + MmioAnd32 ( + HpipeAddr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, + ~HPIPE_SAMPLER_MASK + ); + + /* VDD Calibration Control 3 */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_VDD_CAL_CTRL_REG, + ~HPIPE_EXT_SELLV_RXSAMPL_MASK, + 0x10 << HPIPE_EXT_SELLV_RXSAMPL_OFFSET + ); + + /* DFE Resolution Control */ + MmioOr32 (HpipeAddr + HPIPE_DFE_REG0, HPIPE_DFE_RES_FORCE_MASK); + + /* DFE F3-F5 Coefficient Control */ + MmioAnd32 ( + HpipeAddr + HPIPE_DFE_F3_F5_REG, + ~(HPIPE_DFE_F3_F5_DFE_EN_MASK | HPIPE_DFE_F3_F5_DFE_CTRL_MASK) + ); + + /* Hpipe Generation 3 settings 3 */ + Mask = HPIPE_GX_SET3_FFE_CAP_SEL_MASK | + HPIPE_GX_SET3_FFE_RES_SEL_MASK | + HPIPE_GX_SET3_FFE_SETTING_FORCE_MASK | + HPIPE_GX_SET3_FFE_DEG_RES_LEVEL_MASK | + HPIPE_GX_SET3_FFE_LOAD_RES_LEVEL_MASK; + Data = 0xf | + (0x4 << HPIPE_GX_SET3_FFE_RES_SEL_OFFSET) | + (0x1 << HPIPE_GX_SET3_FFE_SETTING_FORCE_OFFSET) | + (0x1 << HPIPE_GX_SET3_FFE_DEG_RES_LEVEL_OFFSET) | + (0x3 << HPIPE_GX_SET3_FFE_LOAD_RES_LEVEL_OFFSET); + MmioAndThenOr32 (HpipeAddr + HPIPE_G3_SET3_REG, ~Mask, Data); + + /* Hpipe Generation 3 settings 4 */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_G3_SET4_REG, + ~HPIPE_GX_SET4_DFE_RES_MASK, + 0x2 << HPIPE_GX_SET4_DFE_RES_OFFSET + ); + + /* Offset Phase Control - force offset and toggle 'valid' bit */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_PHASE_CONTROL_REG, + ~(HPIPE_OS_PH_OFFSET_MASK | HPIPE_OS_PH_OFFSET_FORCE_MASK), + 0x5c | (0x1 << HPIPE_OS_PH_OFFSET_FORCE_OFFSET) + ); + MmioAndThenOr32 ( + HpipeAddr + HPIPE_PHASE_CONTROL_REG, + ~HPIPE_OS_PH_VALID_MASK, + 0x1 << HPIPE_OS_PH_VALID_OFFSET + ); + MmioAnd32 ( + HpipeAddr + HPIPE_PHASE_CONTROL_REG, + ~HPIPE_OS_PH_VALID_MASK + ); + + /* Set G1 TX amplitude and TX post emphasis value */ + Mask = HPIPE_GX_SET0_TX_AMP_MASK | + HPIPE_GX_SET0_TX_AMP_ADJ_MASK | + HPIPE_GX_SET0_TX_EMPH1_MASK | + HPIPE_GX_SET0_TX_EMPH1_EN_MASK; + Data = (0x8 << HPIPE_GX_SET0_TX_AMP_OFFSET) | + (0x1 << HPIPE_GX_SET0_TX_AMP_ADJ_OFFSET) | + (0x1 << HPIPE_GX_SET0_TX_EMPH1_OFFSET) | + (0x1 << HPIPE_GX_SET0_TX_EMPH1_EN_OFFSET); + MmioAndThenOr32 (HpipeAddr + HPIPE_G1_SET0_REG, ~Mask, Data); + + /* Set G2 TX amplitude and TX post emphasis value */ + Mask = HPIPE_GX_SET0_TX_AMP_MASK | + HPIPE_GX_SET0_TX_AMP_ADJ_MASK | + HPIPE_GX_SET0_TX_EMPH1_MASK | + HPIPE_GX_SET0_TX_EMPH1_EN_MASK; + Data = (0xa << HPIPE_GX_SET0_TX_AMP_OFFSET) | + (0x1 << HPIPE_GX_SET0_TX_AMP_ADJ_OFFSET) | + (0x2 << HPIPE_GX_SET0_TX_EMPH1_OFFSET) | + (0x1 << HPIPE_GX_SET0_TX_EMPH1_EN_OFFSET); + MmioAndThenOr32 (HpipeAddr + HPIPE_G2_SET0_REG, ~Mask, Data); + + /* Set G3 TX amplitude and TX post emphasis value */ + Mask = HPIPE_GX_SET0_TX_AMP_MASK | + HPIPE_GX_SET0_TX_AMP_ADJ_MASK | + HPIPE_GX_SET0_TX_EMPH1_MASK | + HPIPE_GX_SET0_TX_EMPH1_EN_MASK | + HPIPE_GX_SET0_TX_SLEW_RATE_SEL_MASK | + HPIPE_GX_SET0_TX_SLEW_CTRL_EN_MASK; + Data = (0xe << HPIPE_GX_SET0_TX_AMP_OFFSET) | + (0x1 << HPIPE_GX_SET0_TX_AMP_ADJ_OFFSET) | + (0x6 << HPIPE_GX_SET0_TX_EMPH1_OFFSET) | + (0x1 << HPIPE_GX_SET0_TX_EMPH1_EN_OFFSET) | + (0x4 << HPIPE_GX_SET0_TX_SLEW_RATE_SEL_OFFSET); + MmioAndThenOr32 (HpipeAddr + HPIPE_G3_SET0_REG, ~Mask, Data); + + /* SERDES External Configuration 2 register - enable spread spectrum clock */ + MmioOr32 (SdIpAddr + SD_EXTERNAL_CONFIG2_REG, SD_EXTERNAL_CONFIG2_SSC_ENABLE_MASK); + + /* DFE reset sequence */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_PWR_CTR_REG, + ~HPIPE_PWR_CTR_RST_DFE_MASK, + 0x1 + ); + MmioAnd32 ( + HpipeAddr + HPIPE_PWR_CTR_REG, + ~HPIPE_PWR_CTR_RST_DFE_MASK + ); + + /* SW reset for interupt logic */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_PWR_CTR_REG, + ~HPIPE_PWR_CTR_SFT_RST_MASK, + 0x1 << HPIPE_PWR_CTR_SFT_RST_OFFSET + ); + MmioAnd32 ( + HpipeAddr + HPIPE_PWR_CTR_REG, + ~HPIPE_PWR_CTR_SFT_RST_MASK + ); +} + +STATIC +VOID +ComPhySataPhyPowerUp ( + IN EFI_PHYSICAL_ADDRESS SataBase +) +{ + UINT32 Data, Mask; + + /* + * MAC configuration - power up ComPhy - power up PLL/TX/RX + * Use indirect address for vendor specific SATA control register + */ + RegSet (SataBase + SATA3_VENDOR_ADDRESS, + SATA_CONTROL_REG << SATA3_VENDOR_ADDR_OFSSET, SATA3_VENDOR_ADDR_MASK); + + /* SATA 0 power up */ + Mask = SATA3_CTRL_SATA0_PD_MASK; + Data = 0x0 << SATA3_CTRL_SATA0_PD_OFFSET; + + /* SATA 1 power up */ + Mask |= SATA3_CTRL_SATA1_PD_MASK; + Data |= 0x0 << SATA3_CTRL_SATA1_PD_OFFSET; + + /* SATA SSU enable */ + Mask |= SATA3_CTRL_SATA1_ENABLE_MASK; + Data |= 0x1 << SATA3_CTRL_SATA1_ENABLE_OFFSET; + + /* SATA port 1 enable */ + Mask |= SATA3_CTRL_SATA_SSU_MASK; + Data |= 0x1 << SATA3_CTRL_SATA_SSU_OFFSET; + RegSet (SataBase + SATA3_VENDOR_DATA, Data, Mask); + + /* MBUS request size and interface select register */ + RegSet (SataBase + SATA3_VENDOR_ADDRESS, + SATA_MBUS_SIZE_SELECT_REG << SATA3_VENDOR_ADDR_OFSSET, + SATA3_VENDOR_ADDR_MASK); + + /* Mbus regret enable */ + RegSet (SataBase + SATA3_VENDOR_DATA, 0x1 << SATA_MBUS_REGRET_EN_OFFSET, + SATA_MBUS_REGRET_EN_MASK); +} + +STATIC +EFI_STATUS +ComPhySataCheckPll ( + IN EFI_PHYSICAL_ADDRESS HpipeAddr, + IN EFI_PHYSICAL_ADDRESS SdIpAddr +) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINT32 Data,Mask; + IN EFI_PHYSICAL_ADDRESS Addr; + + Addr = SdIpAddr + SD_EXTERNAL_STATUS0_REG; + Data = SD_EXTERNAL_STATUS0_PLL_TX_MASK & SD_EXTERNAL_STATUS0_PLL_RX_MASK; + Mask = Data; + Data = PollingWithTimeout (Addr, Data, Mask, 15000); + + if (Data != 0) { + DEBUG((DEBUG_INFO, "ComPhy: Read from reg = %p - value = 0x%x\n", + HpipeAddr + HPIPE_LANE_STATUS0_REG, Data)); + DEBUG((DEBUG_ERROR, "ComPhy: SD_EXTERNAL_STATUS0_PLL_TX is %d, SD_EXTERNAL_STATUS0_PLL_RX is %d\n", + (Data & SD_EXTERNAL_STATUS0_PLL_TX_MASK), + (Data & SD_EXTERNAL_STATUS0_PLL_RX_MASK))); + Status = EFI_D_ERROR; + } + + return Status; +} + +STATIC +UINTN +ComPhySataPowerUp ( + IN UINT32 Lane, + IN EFI_PHYSICAL_ADDRESS HpipeBase, + IN EFI_PHYSICAL_ADDRESS ComPhyBase, + IN UINT8 SataHostId + ) +{ + EFI_STATUS Status; + UINT8 *SataDeviceTable; + MVHW_NONDISCOVERABLE_DESC *Desc = &mA7k8kNonDiscoverableDescTemplate; + EFI_PHYSICAL_ADDRESS HpipeAddr = HPIPE_ADDR(HpipeBase, Lane); + EFI_PHYSICAL_ADDRESS SdIpAddr = SD_ADDR(HpipeBase, Lane); + EFI_PHYSICAL_ADDRESS ComPhyAddr = COMPHY_ADDR(ComPhyBase, Lane); + + SataDeviceTable = (UINT8 *) PcdGetPtr (PcdPciEAhci); + + if (SataDeviceTable == NULL || SataHostId >= PcdGetSize (PcdPciEAhci)) { + DEBUG ((DEBUG_ERROR, "ComPhySata: Sata host %d is undefined\n", SataHostId)); + return EFI_INVALID_PARAMETER; + } + + if (!MVHW_DEV_ENABLED (Sata, SataHostId)) { + DEBUG ((DEBUG_ERROR, "ComPhySata: Sata host %d is disabled\n", SataHostId)); + return EFI_INVALID_PARAMETER; + } + + DEBUG ((DEBUG_INFO, "ComPhySata: Initialize SATA PHYs\n")); + + DEBUG((DEBUG_INFO, "ComPhySataPowerUp: stage: MAC configuration - power down ComPhy\n")); + + ComPhySataMacPowerDown (Desc->AhciBaseAddresses[SataHostId]); + + DEBUG((DEBUG_INFO, "ComPhy: stage: RFU configurations - hard reset ComPhy\n")); + + ComPhySataRFUConfiguration (ComPhyAddr, SdIpAddr); + + DEBUG((DEBUG_INFO, "ComPhy: stage: Comphy configuration\n")); + + ComPhySataPhyConfiguration (HpipeAddr); + + DEBUG((DEBUG_INFO, "ComPhy: stage: Analog paramters from ETP(HW)\n")); + + ComPhySataSetAnalogParameters (HpipeAddr, SdIpAddr); + + DEBUG((DEBUG_INFO, "ComPhy: stage: ComPhy power up\n")); + + ComPhySataPhyPowerUp (Desc->AhciBaseAddresses[SataHostId]); + + DEBUG((DEBUG_INFO, "ComPhy: stage: Check PLL\n")); + + Status = ComPhySataCheckPll (HpipeAddr, SdIpAddr); + + return Status; +} + +STATIC +VOID +ComPhySgmiiRFUConfiguration ( + IN EFI_PHYSICAL_ADDRESS ComPhyAddr, + IN EFI_PHYSICAL_ADDRESS SdIpAddr, + IN UINT32 SgmiiSpeed +) +{ + UINT32 Mask, Data; + + Mask = COMMON_PHY_CFG1_PWR_UP_MASK; + Data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET; + Mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK; + Data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET; + RegSet (ComPhyAddr + COMMON_PHY_CFG1_REG, Data, Mask); + + /* Select Baud Rate of Comphy And PD_PLL/Tx/Rx */ + Mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK; + Data = 0x0 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET; + Mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK; + Mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK; + if (SgmiiSpeed == COMPHY_SPEED_1_25G) { + Data |= 0x6 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET; + Data |= 0x6 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET; + } else { + /* 3.125G */ + Data |= 0x8 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET; + Data |= 0x8 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET; + } + Mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK; + Data |= 0 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET; + Mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK; + Data |= 0 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET; + Mask |= SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK; + Data |= 1 << SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET; + RegSet (SdIpAddr + SD_EXTERNAL_CONFIG0_REG, Data, Mask); + + /* Release from hard reset */ + Mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK; + Data = 0x0 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET; + Mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK; + Data |= 0x0 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET; + Mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK; + Data |= 0x0 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET; + RegSet (SdIpAddr + SD_EXTERNAL_CONFIG1_REG, Data, Mask); + + /* Release from hard reset */ + Mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK; + Data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET; + Mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK; + Data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET; + RegSet (SdIpAddr+ SD_EXTERNAL_CONFIG1_REG, Data, Mask); + + /* Wait 1ms - until band gap and ref clock ready */ + MicroSecondDelay (1000); + MemoryFence (); +} + +STATIC +VOID +ComPhySgmiiPhyConfiguration ( + IN EFI_PHYSICAL_ADDRESS HpipeAddr +) +{ + UINT32 Mask, Data; + + /* Set reference clock */ + Mask = HPIPE_MISC_REFCLK_SEL_MASK; + Data = 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET; + RegSet (HpipeAddr + HPIPE_MISC_REG, Data, Mask); + + /* Power and PLL Control */ + Mask = HPIPE_PWR_PLL_REF_FREQ_MASK; + Data = 0x1 << HPIPE_PWR_PLL_REF_FREQ_OFFSET; + Mask |= HPIPE_PWR_PLL_PHY_MODE_MASK; + Data |= 0x4 << HPIPE_PWR_PLL_PHY_MODE_OFFSET; + RegSet (HpipeAddr + HPIPE_PWR_PLL_REG, Data, Mask); + + /* Loopback register */ + Mask = HPIPE_LOOPBACK_SEL_MASK; + Data = 0x1 << HPIPE_LOOPBACK_SEL_OFFSET; + RegSet (HpipeAddr + HPIPE_LOOPBACK_REG, Data, Mask); + + /* Rx control 1 */ + Mask = HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK; + Data = 0x1 << HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET; + Mask |= HPIPE_RX_CONTROL_1_CLK8T_EN_MASK; + Data |= 0x0 << HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET; + RegSet (HpipeAddr + HPIPE_RX_CONTROL_1_REG, Data, Mask); + + /* DTL Control */ + Mask = HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK; + Data = 0x0 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET; + RegSet (HpipeAddr + HPIPE_PWR_CTR_DTL_REG, Data, Mask); +} + +STATIC +EFI_STATUS +ComPhyEthCommonRFUPowerUp ( + IN EFI_PHYSICAL_ADDRESS SdIpAddr +) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINT32 Mask, Data; + EFI_PHYSICAL_ADDRESS Addr; + + /* SerDes External Configuration */ + Mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK; + Data = 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET; + Mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK; + Data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET; + Mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK; + Data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET; + RegSet (SdIpAddr + SD_EXTERNAL_CONFIG0_REG, Data, Mask); + + /* Check PLL rx & tx ready */ + Addr = SdIpAddr + SD_EXTERNAL_STATUS0_REG; + Data = SD_EXTERNAL_STATUS0_PLL_RX_MASK | SD_EXTERNAL_STATUS0_PLL_TX_MASK; + Mask = Data; + Data = PollingWithTimeout (Addr, Data, Mask, 15000); + if (Data != 0) { + DEBUG((DEBUG_ERROR, "ComPhy: Read from reg = %p - value = 0x%x\n", + SdIpAddr + SD_EXTERNAL_STATUS0_REG, Data)); + DEBUG((DEBUG_ERROR, "ComPhy: SD_EXTERNAL_STATUS0_PLL_RX is %d, SD_EXTERNAL_STATUS0_PLL_TX is %d\n", + (Data & SD_EXTERNAL_STATUS0_PLL_RX_MASK), + (Data & SD_EXTERNAL_STATUS0_PLL_TX_MASK))); + Status = EFI_D_ERROR; + } + + /* RX init */ + Mask = SD_EXTERNAL_CONFIG1_RX_INIT_MASK; + Data = 0x1 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET; + RegSet (SdIpAddr + SD_EXTERNAL_CONFIG1_REG, Data, Mask); + + /* Check that RX init done */ + Addr = SdIpAddr + SD_EXTERNAL_STATUS0_REG; + Data = SD_EXTERNAL_STATUS0_RX_INIT_MASK; + Mask = Data; + Data = PollingWithTimeout (Addr, Data, Mask, 100); + if (Data != 0) { + DEBUG((DEBUG_ERROR, "ComPhy: Read from reg = %p - value = 0x%x\n", + SdIpAddr + SD_EXTERNAL_STATUS0_REG, Data)); + DEBUG((DEBUG_ERROR, "ComPhy: SD_EXTERNAL_STATUS0_RX_INIT is 0\n")); + Status = EFI_D_ERROR; + } + Mask = SD_EXTERNAL_CONFIG1_RX_INIT_MASK; + Data = 0x0 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET; + Mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK; + Data |= 0x1 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET; + RegSet (SdIpAddr + SD_EXTERNAL_CONFIG1_REG, Data, Mask); + + return Status; +} + +STATIC +UINTN +ComPhySgmiiPowerUp ( + IN UINT32 Lane, + IN UINT32 SgmiiSpeed, + IN EFI_PHYSICAL_ADDRESS HpipeBase, + IN EFI_PHYSICAL_ADDRESS ComPhyBase + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + EFI_PHYSICAL_ADDRESS HpipeAddr = HPIPE_ADDR(HpipeBase, Lane); + EFI_PHYSICAL_ADDRESS SdIpAddr = SD_ADDR(HpipeBase, Lane); + EFI_PHYSICAL_ADDRESS ComPhyAddr = COMPHY_ADDR(ComPhyBase, Lane); + + DEBUG((DEBUG_INFO, "ComPhy: stage: RFU configurations - hard reset ComPhy\n")); + + ComPhySgmiiRFUConfiguration (ComPhyAddr, SdIpAddr, SgmiiSpeed); + + DEBUG((DEBUG_INFO, "ComPhy: stage: ComPhy configuration\n")); + + ComPhySgmiiPhyConfiguration (HpipeAddr); + + /* Set analog paramters from ETP(HW) - for now use the default data */ + DEBUG((DEBUG_INFO, "ComPhy: stage: Analog paramters from ETP(HW)\n")); + + RegSet (HpipeAddr + HPIPE_G1_SET0_REG, + 0x1 << HPIPE_GX_SET0_TX_EMPH1_OFFSET, HPIPE_GX_SET0_TX_EMPH1_MASK); + + DEBUG((DEBUG_INFO, "ComPhy: stage: RFU configurations - Power Up PLL,Tx,Rx\n")); + + Status = ComPhyEthCommonRFUPowerUp (SdIpAddr); + + return Status; +} + +STATIC +VOID +ComPhySfiRFUConfiguration ( + IN EFI_PHYSICAL_ADDRESS ComPhyAddr, + IN EFI_PHYSICAL_ADDRESS SdIpAddr +) +{ + UINT32 Mask, Data; + + MmioAndThenOr32 ( + ComPhyAddr + COMMON_PHY_CFG1_REG, + ~(COMMON_PHY_CFG1_PWR_UP_MASK | COMMON_PHY_CFG1_PIPE_SELECT_MASK), + COMMON_PHY_CFG1_PWR_UP_MASK + ); + + /* Select Baud Rate of Comphy And PD_PLL/Tx/Rx */ + Mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK | + SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK | + SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK | + SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK | + SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK | + SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK; + Data = (0xe << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET) | + (0xe << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET); + MmioAndThenOr32 (SdIpAddr + SD_EXTERNAL_CONFIG0_REG, ~Mask, Data); + + /* Release from hard reset */ + Mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK | + SD_EXTERNAL_CONFIG1_RESET_CORE_MASK | + SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK; + Data = SD_EXTERNAL_CONFIG1_RESET_IN_MASK | + SD_EXTERNAL_CONFIG1_RESET_CORE_MASK; + MmioAndThenOr32 (SdIpAddr + SD_EXTERNAL_CONFIG1_REG, ~Mask, Data); + + /* Wait 1ms - until band gap and ref clock are ready */ + MicroSecondDelay (1000); + MemoryFence (); +} + +STATIC +VOID +ComPhySfiPhyConfiguration ( + IN EFI_PHYSICAL_ADDRESS HpipeAddr, + IN UINT32 SfiSpeed +) +{ + UINT32 Mask, Data; + + /* Set reference clock */ + Mask = HPIPE_MISC_ICP_FORCE_MASK | HPIPE_MISC_REFCLK_SEL_MASK; + Data = (SfiSpeed == COMPHY_SPEED_5_15625G) ? + (0x0 << HPIPE_MISC_ICP_FORCE_OFFSET) : (0x1 << HPIPE_MISC_ICP_FORCE_OFFSET); + MmioAndThenOr32 (HpipeAddr + HPIPE_MISC_REG, ~Mask, Data); + + /* Power and PLL Control */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_PWR_PLL_REG, + ~(HPIPE_PWR_PLL_REF_FREQ_MASK | HPIPE_PWR_PLL_PHY_MODE_MASK), + 0x1 | (0x4 << HPIPE_PWR_PLL_PHY_MODE_OFFSET) + ); + + /* Loopback register */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_LOOPBACK_REG, + ~HPIPE_LOOPBACK_SEL_MASK, + 0x1 << HPIPE_LOOPBACK_SEL_OFFSET + ); + + /* Rx control 1 */ + MmioOr32 ( + HpipeAddr + HPIPE_RX_CONTROL_1_REG, + HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK | HPIPE_RX_CONTROL_1_CLK8T_EN_MASK + ); + + /* DTL Control */ + MmioOr32 (HpipeAddr + HPIPE_PWR_CTR_DTL_REG, HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK); + + /* Transmitter/Receiver Speed Divider Force */ + if (SfiSpeed == COMPHY_SPEED_5_15625G) { + Mask = HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_MASK | + HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_MASK | + HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_MASK | + HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_MASK; + Data = (1 << HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_OFFSET) | + (1 << HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_OFFSET) | + (1 << HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_OFFSET) | + (1 << HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_OFFSET); + MmioAndThenOr32 (HpipeAddr + HPIPE_SPD_DIV_FORCE_REG, ~Mask, Data); + } else { + MmioOr32 (HpipeAddr + HPIPE_SPD_DIV_FORCE_REG, HPIPE_TXDIGCK_DIV_FORCE_MASK); + } +} + +STATIC +VOID +ComPhySfiSetAnalogParameters ( + IN EFI_PHYSICAL_ADDRESS HpipeAddr, + IN EFI_PHYSICAL_ADDRESS SdIpAddr, + IN UINT32 SfiSpeed +) +{ + UINT32 Mask, Data; + + /* SERDES External Configuration 2 */ + MmioOr32 (SdIpAddr + SD_EXTERNAL_CONFIG2_REG, SD_EXTERNAL_CONFIG2_PIN_DFE_EN_MASK); + + /* DFE Resolution control */ + MmioOr32 (HpipeAddr + HPIPE_DFE_REG0, HPIPE_DFE_RES_FORCE_MASK); + + /* Generation 1 setting_0 */ + if (SfiSpeed == COMPHY_SPEED_5_15625G) { + Mask = HPIPE_GX_SET0_TX_EMPH1_MASK; + Data = 0x6 << HPIPE_GX_SET0_TX_EMPH1_OFFSET; + } else { + Mask = HPIPE_GX_SET0_TX_AMP_MASK | HPIPE_GX_SET0_TX_EMPH1_MASK; + Data = (0x1c << HPIPE_GX_SET0_TX_AMP_OFFSET) | (0xe << HPIPE_GX_SET0_TX_EMPH1_OFFSET); + } + MmioAndThenOr32 (HpipeAddr + HPIPE_G1_SET0_REG, ~Mask, Data); + + /* Generation 1 setting 2 */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_GX_SET2_REG, + ~HPIPE_GX_SET2_TX_EMPH0_MASK, + HPIPE_GX_SET2_TX_EMPH0_EN_MASK + ); + + /* Transmitter Slew Rate Control register */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_TX_REG1_REG, + ~(HPIPE_TX_REG1_TX_EMPH_RES_MASK | HPIPE_TX_REG1_SLC_EN_MASK), + (0x3 << HPIPE_TX_REG1_TX_EMPH_RES_OFFSET) | (0x3f << HPIPE_TX_REG1_SLC_EN_OFFSET) + ); + + /* Impedance Calibration Control register */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_CAL_REG1_REG, + ~(HPIPE_CAL_REG_1_EXT_TXIMP_MASK | HPIPE_CAL_REG_1_EXT_TXIMP_EN_MASK), + (0xe << HPIPE_CAL_REG_1_EXT_TXIMP_OFFSET) | HPIPE_CAL_REG_1_EXT_TXIMP_EN_MASK + ); + + /* Generation 1 setting 5 */ + MmioAnd32 (HpipeAddr + HPIPE_G1_SET5_REG, ~HPIPE_GX_SET5_ICP_MASK); + + /* Generation 1 setting 1 */ + if (SfiSpeed == COMPHY_SPEED_5_15625G) { + Mask = HPIPE_GX_SET1_RX_SELMUPI_MASK | HPIPE_GX_SET1_RX_SELMUPP_MASK; + Data = 0x1 | (0x1 << HPIPE_GX_SET1_RX_SELMUPP_OFFSET); + } else { + Mask = HPIPE_GX_SET1_RX_SELMUPI_MASK | + HPIPE_GX_SET1_RX_SELMUPP_MASK | + HPIPE_GX_SET1_RX_SELMUFI_MASK | + HPIPE_GX_SET1_RX_SELMUFF_MASK | + HPIPE_GX_SET1_RX_DIGCK_DIV_MASK; + Data = 0x2 | + (0x2 << HPIPE_GX_SET1_RX_SELMUPP_OFFSET) | + (0x1 << HPIPE_GX_SET1_RX_SELMUFF_OFFSET) | + (0x3 << HPIPE_GX_SET1_RX_DIGCK_DIV_OFFSET); + } + MmioAndThenOr32 (HpipeAddr + HPIPE_G1_SET1_REG, ~Mask, Data); + MmioOr32 (HpipeAddr + HPIPE_G1_SET1_REG, HPIPE_GX_SET1_RX_DFE_EN_MASK); + + /* DFE F3-F5 Coefficient Control */ + MmioAnd32 ( + HpipeAddr + HPIPE_DFE_F3_F5_REG, + ~(HPIPE_DFE_F3_F5_DFE_EN_MASK | HPIPE_DFE_F3_F5_DFE_CTRL_MASK) + ); + + /* Configure Generation 1 setting 4 (DFE) */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_G1_SET4_REG, + ~HPIPE_GX_SET4_DFE_RES_MASK, + 0x1 << HPIPE_GX_SET4_DFE_RES_OFFSET + ); + + /* Generation 1 setting 3 */ + MmioOr32 (HpipeAddr + HPIPE_G1_SET3_REG, HPIPE_GX_SET3_FBCK_SEL_MASK); + + if (SfiSpeed == COMPHY_SPEED_5_15625G) { + /* Force FFE (Feed Forward Equalization) to 5G */ + Mask = HPIPE_GX_SET3_FFE_CAP_SEL_MASK | + HPIPE_GX_SET3_FFE_RES_SEL_MASK | + HPIPE_GX_SET3_FFE_SETTING_FORCE_MASK; + Data = 0xf | (0x4 << HPIPE_GX_SET3_FFE_RES_SEL_OFFSET) | HPIPE_GX_SET3_FFE_SETTING_FORCE_MASK; + MmioAndThenOr32 (HpipeAddr + HPIPE_G1_SET3_REG, ~Mask, Data); + } + + /* Configure RX training timer */ + MmioAndThenOr32 (HpipeAddr + HPIPE_TX_TRAIN_CTRL_5_REG, ~HPIPE_RX_TRAIN_TIMER_MASK, 0x13); + + /* Enable TX train peak to peak hold */ + MmioOr32 (HpipeAddr + HPIPE_TX_TRAIN_CTRL_0_REG, HPIPE_TX_TRAIN_P2P_HOLD_MASK); + + /* Configure TX preset index */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_TX_PRESET_INDEX_REG, + ~HPIPE_TX_PRESET_INDEX_MASK, + 0x2 << HPIPE_TX_PRESET_INDEX_OFFSET + ); + + /* Disable pattern lock lost timeout */ + MmioAnd32 (HpipeAddr + HPIPE_FRAME_DETECT_CTRL_3_REG, ~HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_MASK); + + /* Configure TX training pattern and TX training 16bit auto */ + MmioOr32 ( + HpipeAddr + HPIPE_TX_TRAIN_REG, + HPIPE_TX_TRAIN_16BIT_AUTO_EN_MASK | HPIPE_TX_TRAIN_PAT_SEL_MASK + ); + + /* Configure training pattern number */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_FRAME_DETECT_CTRL_0_REG, + ~HPIPE_TRAIN_PAT_NUM_MASK, + 0x88 << HPIPE_TRAIN_PAT_NUM_OFFSET + ); + + /* Configure differential manchester encoder to ethernet mode */ + MmioOr32 (HpipeAddr + HPIPE_DME_REG, HPIPE_DME_ETHERNET_MODE_MASK); + + /* Configure VDD Continuous Calibration */ + MmioOr32 (HpipeAddr + HPIPE_VDD_CAL_0_REG, HPIPE_CAL_VDD_CONT_MODE_MASK); + + /* Configure sampler gain */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, + ~HPIPE_RX_SAMPLER_OS_GAIN_MASK, + 0x3 << HPIPE_RX_SAMPLER_OS_GAIN_OFFSET + ); + + /* Trigger sampler enable pulse (by toggling the bit) */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, + ~HPIPE_SAMPLER_MASK, + 0x1 << HPIPE_SAMPLER_OFFSET + ); + MmioAnd32 ( + HpipeAddr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, + ~HPIPE_SAMPLER_MASK + ); + + /* VDD calibration control */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_VDD_CAL_CTRL_REG, + ~HPIPE_EXT_SELLV_RXSAMPL_MASK, + 0x1a << HPIPE_EXT_SELLV_RXSAMPL_OFFSET + ); +} + +STATIC +EFI_STATUS +ComPhySfiPowerUp ( + IN UINT32 Lane, + IN EFI_PHYSICAL_ADDRESS HpipeBase, + IN EFI_PHYSICAL_ADDRESS ComPhyBase, + IN UINT32 SfiSpeed + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS HpipeAddr = HPIPE_ADDR(HpipeBase, Lane); + EFI_PHYSICAL_ADDRESS SdIpAddr = SD_ADDR(HpipeBase, Lane); + EFI_PHYSICAL_ADDRESS ComPhyAddr = COMPHY_ADDR(ComPhyBase, Lane); + + DEBUG ((DEBUG_INFO, "ComPhy: stage: RFU configurations - hard reset ComPhy\n")); + + ComPhySfiRFUConfiguration (ComPhyAddr, SdIpAddr); + + DEBUG ((DEBUG_INFO, "ComPhy: stage: ComPhy configuration\n")); + + ComPhySfiPhyConfiguration (HpipeAddr, SfiSpeed); + + DEBUG ((DEBUG_INFO, "ComPhy: stage: Set analog paramters\n")); + + ComPhySfiSetAnalogParameters (HpipeAddr, SdIpAddr, SfiSpeed); + + DEBUG ((DEBUG_INFO, "ComPhy: stage: RFU configurations - Power Up PLL,Tx,Rx\n")); + + Status = ComPhyEthCommonRFUPowerUp (SdIpAddr); + + return Status; +} + +STATIC +EFI_STATUS +ComPhyRxauiRFUConfiguration ( + IN UINT32 Lane, + IN EFI_PHYSICAL_ADDRESS ComPhyAddr, + IN EFI_PHYSICAL_ADDRESS SdIpAddr +) +{ + UINT32 Mask, Data; + + MmioAndThenOr32 ( + ComPhyAddr + COMMON_PHY_CFG1_REG, + ~(COMMON_PHY_CFG1_PWR_UP_MASK | COMMON_PHY_CFG1_PIPE_SELECT_MASK), + COMMON_PHY_CFG1_PWR_UP_MASK + ); + + switch (Lane) { + case 2: + case 4: + MmioOr32 (ComPhyAddr + COMMON_PHY_SD_CTRL1, COMMON_PHY_SD_CTRL1_RXAUI0_MASK); + case 3: + case 5: + MmioOr32 (ComPhyAddr + COMMON_PHY_SD_CTRL1, COMMON_PHY_SD_CTRL1_RXAUI1_MASK); + break; + default: + DEBUG ((DEBUG_ERROR, "RXAUI used on invalid lane %d\n", Lane)); + return EFI_INVALID_PARAMETER; + } + + /* Select Baud Rate of Comphy And PD_PLL/Tx/Rx */ + Mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK | + SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK | + SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK | + SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK | + SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK | + SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK | + SD_EXTERNAL_CONFIG0_MEDIA_MODE_MASK; + Data = (0xb << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET) | + (0xb << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET) | + (0x1 << SD_EXTERNAL_CONFIG0_MEDIA_MODE_OFFSET); + MmioAndThenOr32 (SdIpAddr + SD_EXTERNAL_CONFIG0_REG, ~Mask, Data); + + /* Release from hard reset */ + Mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK | + SD_EXTERNAL_CONFIG1_RESET_CORE_MASK | + SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK; + Data = SD_EXTERNAL_CONFIG1_RESET_IN_MASK | + SD_EXTERNAL_CONFIG1_RESET_CORE_MASK; + MmioAndThenOr32 (SdIpAddr + SD_EXTERNAL_CONFIG1_REG, ~Mask, Data); + + /* Wait 1ms - until band gap and ref clock are ready */ + MicroSecondDelay (1000); + MemoryFence (); + + return EFI_SUCCESS; +} + +STATIC +VOID +ComPhyRxauiPhyConfiguration ( + IN EFI_PHYSICAL_ADDRESS HpipeAddr +) +{ + /* Set reference clock */ + MmioAnd32 (HpipeAddr + HPIPE_MISC_REG, ~HPIPE_MISC_REFCLK_SEL_MASK); + + /* Power and PLL Control */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_PWR_PLL_REG, + ~(HPIPE_PWR_PLL_REF_FREQ_MASK | HPIPE_PWR_PLL_PHY_MODE_MASK), + 0x1 | (0x4 << HPIPE_PWR_PLL_PHY_MODE_OFFSET) + ); + + /* Loopback register */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_LOOPBACK_REG, + ~HPIPE_LOOPBACK_SEL_MASK, + 0x1 << HPIPE_LOOPBACK_SEL_OFFSET + ); + + /* Rx control 1 */ + MmioOr32 ( + HpipeAddr + HPIPE_RX_CONTROL_1_REG, + HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK | HPIPE_RX_CONTROL_1_CLK8T_EN_MASK + ); + + /* DTL Control */ + MmioAnd32 (HpipeAddr + HPIPE_PWR_CTR_DTL_REG, ~HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK); +} + +STATIC +VOID +ComPhyRxauiSetAnalogParameters ( + IN EFI_PHYSICAL_ADDRESS HpipeAddr, + IN EFI_PHYSICAL_ADDRESS SdIpAddr +) +{ + UINT32 Mask, Data; + + /* SERDES External Configuration 2 */ + MmioOr32 (SdIpAddr + SD_EXTERNAL_CONFIG2_REG, SD_EXTERNAL_CONFIG2_PIN_DFE_EN_MASK); + + /* DFE Resolution control */ + MmioOr32 (HpipeAddr + HPIPE_DFE_REG0, HPIPE_DFE_RES_FORCE_MASK); + + /* Generation 1 setting_0 */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_G1_SET0_REG, + ~HPIPE_GX_SET0_TX_EMPH1_MASK, + 0xe << HPIPE_GX_SET0_TX_EMPH1_OFFSET + ); + + /* Generation 1 setting 1 */ + Mask = HPIPE_GX_SET1_RX_SELMUPI_MASK | + HPIPE_GX_SET1_RX_SELMUPP_MASK | + HPIPE_GX_SET1_RX_DFE_EN_MASK; + Data = 0x1 | + (0x1 << HPIPE_GX_SET1_RX_SELMUPP_OFFSET) | + (0x1 << HPIPE_GX_SET1_RX_DFE_EN_OFFSET); + MmioAndThenOr32 (HpipeAddr + HPIPE_G1_SET1_REG, ~Mask, Data); + + /* DFE F3-F5 Coefficient Control */ + MmioAnd32 ( + HpipeAddr + HPIPE_DFE_F3_F5_REG, + ~(HPIPE_DFE_F3_F5_DFE_EN_MASK | HPIPE_DFE_F3_F5_DFE_CTRL_MASK) + ); + + /* Configure Generation 1 setting 4 (DFE) */ + MmioAndThenOr32 ( + HpipeAddr + HPIPE_G1_SET4_REG, + ~HPIPE_GX_SET4_DFE_RES_MASK, + 0x1 << HPIPE_GX_SET4_DFE_RES_OFFSET + ); + + /* Generation 1 setting 3 */ + MmioOr32 (HpipeAddr + HPIPE_G1_SET3_REG, HPIPE_GX_SET3_FBCK_SEL_MASK); +} + +STATIC +EFI_STATUS +ComPhyRxauiPowerUp ( + IN UINT32 Lane, + IN EFI_PHYSICAL_ADDRESS HpipeBase, + IN EFI_PHYSICAL_ADDRESS ComPhyBase + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS HpipeAddr = HPIPE_ADDR(HpipeBase, Lane); + EFI_PHYSICAL_ADDRESS SdIpAddr = SD_ADDR(HpipeBase, Lane); + EFI_PHYSICAL_ADDRESS ComPhyAddr = COMPHY_ADDR(ComPhyBase, Lane); + + DEBUG ((DEBUG_INFO, "ComPhy: stage: RFU configurations - hard reset ComPhy\n")); + + Status = ComPhyRxauiRFUConfiguration (Lane, ComPhyAddr, SdIpAddr); + if (EFI_ERROR(Status)) { + return Status; + } + + DEBUG ((DEBUG_INFO, "ComPhy: stage: ComPhy configuration\n")); + + ComPhyRxauiPhyConfiguration (HpipeAddr); + + DEBUG ((DEBUG_INFO, "ComPhy: stage: Set analog paramters\n")); + + ComPhyRxauiSetAnalogParameters (HpipeAddr, SdIpAddr); + + DEBUG ((DEBUG_INFO, "ComPhy: stage: RFU configurations - Power Up PLL,Tx,Rx\n")); + + Status = ComPhyEthCommonRFUPowerUp (SdIpAddr); + + return Status; +} + +STATIC +VOID +ComPhyMuxCp110 ( + IN CHIP_COMPHY_CONFIG *PtrChipCfg, + IN COMPHY_MAP *SerdesMap + ) +{ + EFI_PHYSICAL_ADDRESS ComPhyBaseAddr; + COMPHY_MAP ComPhyMapPipeData[MAX_LANE_OPTIONS]; + COMPHY_MAP ComPhyMapPhyData[MAX_LANE_OPTIONS]; + UINT32 Lane, ComPhyMaxCount; + + ComPhyMaxCount = PtrChipCfg->LanesCount; + ComPhyBaseAddr = PtrChipCfg->ComPhyBaseAddr; + + /* + * Copy the SerDes map configuration for PIPE map and PHY map. + * The ComPhyMuxInit modifies the Type of the Lane if the Type is not valid. + * Because we have 2 selectors, run the ComPhyMuxInit twice and after + * that, update the original SerdesMap. + */ + for (Lane = 0; Lane < ComPhyMaxCount; Lane++) { + ComPhyMapPipeData[Lane].Type = SerdesMap[Lane].Type; + ComPhyMapPipeData[Lane].Speed = SerdesMap[Lane].Speed; + ComPhyMapPhyData[Lane].Type = SerdesMap[Lane].Type; + ComPhyMapPhyData[Lane].Speed = SerdesMap[Lane].Speed; + } + PtrChipCfg->MuxData = Cp110ComPhyMuxData; + ComPhyMuxInit(PtrChipCfg, ComPhyMapPhyData, ComPhyBaseAddr + + COMMON_SELECTOR_PHY_OFFSET); + + PtrChipCfg->MuxData = Cp110ComPhyPipeMuxData; + ComPhyMuxInit(PtrChipCfg, ComPhyMapPipeData, ComPhyBaseAddr + + COMMON_SELECTOR_PIPE_OFFSET); + + /* Fix the Type after check the PHY and PIPE configuration */ + for (Lane = 0; Lane < ComPhyMaxCount; Lane++) + if ((ComPhyMapPipeData[Lane].Type == COMPHY_TYPE_UNCONNECTED) && + (ComPhyMapPhyData[Lane].Type == COMPHY_TYPE_UNCONNECTED)) + SerdesMap[Lane].Type = COMPHY_TYPE_UNCONNECTED; +} + +VOID +ComPhyCp110Init ( + IN CHIP_COMPHY_CONFIG *PtrChipCfg + ) +{ + EFI_STATUS Status; + COMPHY_MAP *PtrComPhyMap, *SerdesMap; + EFI_PHYSICAL_ADDRESS ComPhyBaseAddr, HpipeBaseAddr; + UINT32 ComPhyMaxCount, Lane; + UINT32 PcieBy4 = 1; // Indicating if first 4 lanes set to PCIE + + ComPhyMaxCount = PtrChipCfg->LanesCount; + ComPhyBaseAddr = PtrChipCfg->ComPhyBaseAddr; + HpipeBaseAddr = PtrChipCfg->Hpipe3BaseAddr; + SerdesMap = PtrChipCfg->MapData; + + /* Config Comphy mux configuration */ + ComPhyMuxCp110(PtrChipCfg, SerdesMap); + + /* Check if the first 4 Lanes configured as By-4 */ + for (Lane = 0, PtrComPhyMap = SerdesMap; Lane < 4; Lane++, PtrComPhyMap++) { + if (PtrComPhyMap->Type != COMPHY_TYPE_PCIE0) { + PcieBy4 = 0; + break; + } + } + + for (Lane = 0, PtrComPhyMap = SerdesMap; Lane < ComPhyMaxCount; + Lane++, PtrComPhyMap++) { + DEBUG((DEBUG_INFO, "ComPhy: Initialize serdes number %d\n", Lane)); + DEBUG((DEBUG_INFO, "ComPhy: Serdes Type = 0x%x\n", PtrComPhyMap->Type)); + switch (PtrComPhyMap->Type) { + case COMPHY_TYPE_UNCONNECTED: + continue; + break; + case COMPHY_TYPE_PCIE0: + case COMPHY_TYPE_PCIE1: + case COMPHY_TYPE_PCIE2: + case COMPHY_TYPE_PCIE3: + Status = ComPhyPciePowerUp(Lane, PcieBy4, HpipeBaseAddr, ComPhyBaseAddr); + break; + case COMPHY_TYPE_SATA0: + case COMPHY_TYPE_SATA1: + Status = ComPhySataPowerUp (Lane, HpipeBaseAddr, ComPhyBaseAddr, MVHW_CP0_AHCI0_ID); + break; + case COMPHY_TYPE_SATA2: + case COMPHY_TYPE_SATA3: + Status = ComPhySataPowerUp (Lane, HpipeBaseAddr, ComPhyBaseAddr, MVHW_CP1_AHCI0_ID); + break; + case COMPHY_TYPE_USB3_HOST0: + case COMPHY_TYPE_USB3_HOST1: + Status = ComphyUsb3PowerUp(Lane, HpipeBaseAddr, ComPhyBaseAddr); + break; + case COMPHY_TYPE_SGMII0: + case COMPHY_TYPE_SGMII1: + case COMPHY_TYPE_SGMII2: + case COMPHY_TYPE_SGMII3: + Status = ComPhySgmiiPowerUp(Lane, PtrComPhyMap->Speed, HpipeBaseAddr, + ComPhyBaseAddr); + break; + case COMPHY_TYPE_SFI: + Status = ComPhySfiPowerUp(Lane, HpipeBaseAddr, ComPhyBaseAddr, PtrComPhyMap->Speed); + break; + case COMPHY_TYPE_RXAUI0: + case COMPHY_TYPE_RXAUI1: + Status = ComPhyRxauiPowerUp(Lane, HpipeBaseAddr, ComPhyBaseAddr); + break; + default: + DEBUG((DEBUG_ERROR, "Unknown SerDes Type, skip initialize SerDes %d\n", + Lane)); + Status = EFI_INVALID_PARAMETER; + ASSERT (FALSE); + break; + } + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "Failed to initialize Lane %d\n with Status = 0x%x", Lane, Status)); + PtrComPhyMap->Type = COMPHY_TYPE_UNCONNECTED; + } + } +} diff --git a/Platform/Marvell/Library/ComPhyLib/ComPhyLib.c b/Platform/Marvell/Library/ComPhyLib/ComPhyLib.c new file mode 100644 index 0000000000..3eb5d9f6a9 --- /dev/null +++ b/Platform/Marvell/Library/ComPhyLib/ComPhyLib.c @@ -0,0 +1,321 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include "ComPhyLib.h" +#include +#include + +DECLARE_A7K8K_COMPHY_TEMPLATE; + +CHAR16 * TypeStringTable [] = {L"unconnected", L"PCIE0", L"PCIE1", L"PCIE2", + L"PCIE3", L"SATA0", L"SATA1", L"SATA2", L"SATA3", + L"SGMII0", L"SGMII1", L"SGMII2", L"SGMII3", + L"QSGMII", L"USB3_HOST0", L"USB3_HOST1", + L"USB3_DEVICE", L"XAUI0", L"XAUI1", L"XAUI2", + L"XAUI3", L"RXAUI0", L"RXAUI1", L"SFI"}; + +CHAR16 * SpeedStringTable [] = {L"-", L"1.25 Gbps", L"1.5 Gbps", L"2.5 Gbps", + L"3.0 Gbps", L"3.125 Gbps", L"5 Gbps", L"5.156 Gbps", + L"6 Gbps", L"6.25 Gbps", L"10.31 Gbps"}; + +CHIP_COMPHY_CONFIG ChipCfgTbl[] = { + { + .ChipType = MvComPhyTypeCp110, + .Init = ComPhyCp110Init + }, +}; + +VOID +RegSet ( + IN EFI_PHYSICAL_ADDRESS Addr, + IN UINT32 Data, + IN UINT32 Mask + ) +{ + DEBUG((DEBUG_INFO, "Write to address = %10x, data = %10x (mask = %10x)" + "- ", Addr, Data, Mask)); + DEBUG((DEBUG_INFO, "old value = %10x ==> ", MmioRead32 (Addr))); + RegSetSilent (Addr, Data, Mask); + DEBUG((DEBUG_INFO, "new value %10x\n", MmioRead32 (Addr))); +} + +VOID +RegSetSilent ( + IN EFI_PHYSICAL_ADDRESS Addr, + IN UINT32 Data, + IN UINT32 Mask + ) +{ + UINT32 RegData; + + RegData = MmioRead32 (Addr); + RegData &= ~Mask; + RegData |= Data; + MmioWrite32 (Addr, RegData); +} + +VOID +RegSet16 ( + IN EFI_PHYSICAL_ADDRESS Addr, + IN UINT16 Data, + IN UINT16 Mask + ) +{ + DEBUG((DEBUG_INFO, "Write to address = %#010lx, Data = %#06x (mask = %#06x)" + "- ", Addr, Data, Mask)); + DEBUG((DEBUG_INFO, "old value = %#06x ==> ", MmioRead16 (Addr))); + RegSetSilent16 (Addr, Data, Mask); + DEBUG((DEBUG_INFO, "new value %#06x\n", MmioRead16 (Addr))); +} + +VOID +RegSetSilent16( + IN EFI_PHYSICAL_ADDRESS Addr, + IN UINT16 Data, + IN UINT16 Mask + ) +{ + UINT16 RegData; + RegData = MmioRead16(Addr); + RegData &= ~Mask; + RegData |= Data; + MmioWrite16 (Addr, RegData); +} + +/* This function returns enum with SerDesType */ +UINT32 +ParseSerdesTypeString ( + CHAR16* String + ) +{ + UINT32 i; + + if (String == NULL) + return COMPHY_TYPE_INVALID; + + for (i = 0; i < COMPHY_TYPE_MAX; i++) { + if (StrCmp (String, TypeStringTable[i]) == 0) { + return i; + } + } + + /* PCD string doesn't match any supported SerDes Type */ + return COMPHY_TYPE_INVALID; +} + +/* This function converts SerDes speed in MHz to enum with SerDesSpeed */ +UINT32 +ParseSerdesSpeed ( + UINT32 Value + ) +{ + UINT32 i; + UINT32 ValueTable [] = {0, 1250, 1500, 2500, 3000, 3125, + 5000, 5156, 6000, 6250, 10310}; + + for (i = 0; i < COMPHY_SPEED_MAX; i++) { + if (Value == ValueTable[i]) { + return i; + } + } + + /* PCD SerDes speed value doesn't match any supported SerDes speed */ + return COMPHY_SPEED_INVALID; +} + +CHAR16 * +GetTypeString ( + UINT32 Type + ) +{ + + if (Type < 0 || Type > COMPHY_TYPE_MAX) { + return L"invalid"; + } + + return TypeStringTable[Type]; +} + +CHAR16 * +GetSpeedString ( + UINT32 Speed + ) +{ + + if (Speed < 0 || Speed > 10) { + return L"invalid"; + } + + return SpeedStringTable[Speed]; +} + +VOID +ComPhyPrint ( + IN CHIP_COMPHY_CONFIG *PtrChipCfg + ) +{ + UINT32 Lane; + CHAR16 *SpeedStr, *TypeStr; + + for (Lane = 0; Lane < PtrChipCfg->LanesCount; Lane++) { + SpeedStr = GetSpeedString(PtrChipCfg->MapData[Lane].Speed); + TypeStr = GetTypeString(PtrChipCfg->MapData[Lane].Type); + DEBUG((DEBUG_ERROR, "Comphy-%d: %-13s %-10s\n", Lane, TypeStr, SpeedStr)); + } + + DEBUG((DEBUG_ERROR, "\n")); +} + +EFI_STATUS +GetChipComPhyInit ( + IN CHIP_COMPHY_CONFIG *PtrChipCfg + ) +{ + UINTN i, TblSize; + + + TblSize = sizeof(ChipCfgTbl) / sizeof(ChipCfgTbl[0]); + + for (i = 0; i < TblSize ; i++) { + if (PtrChipCfg->ChipType == ChipCfgTbl[i].ChipType) { + PtrChipCfg->Init = ChipCfgTbl[i].Init; + return EFI_SUCCESS; + } + } + + return EFI_D_ERROR; +} + +STATIC +VOID +InitComPhyConfig ( + IN OUT CHIP_COMPHY_CONFIG *ChipConfig, + IN OUT PCD_LANE_MAP *LaneData, + IN UINT8 Id + ) +{ + MVHW_COMPHY_DESC *Desc = &mA7k8kComPhyDescTemplate; + + ChipConfig->ChipType = Desc->ComPhyChipType[Id]; + ChipConfig->ComPhyBaseAddr = Desc->ComPhyBaseAddresses[Id]; + ChipConfig->Hpipe3BaseAddr = Desc->ComPhyHpipe3BaseAddresses[Id]; + ChipConfig->LanesCount = Desc->ComPhyLaneCount[Id]; + ChipConfig->MuxBitCount = Desc->ComPhyMuxBitCount[Id]; + + /* + * Below macro contains variable name concatenation (used to form PCD's name). + */ + switch (Id) { + case 0: + GetComPhyPcd (ChipConfig, LaneData, 0); + break; + case 1: + GetComPhyPcd (ChipConfig, LaneData, 1); + break; + case 2: + GetComPhyPcd (ChipConfig, LaneData, 2); + break; + case 3: + GetComPhyPcd (ChipConfig, LaneData, 3); + break; + } +} + +EFI_STATUS +MvComPhyInit ( + VOID + ) +{ + EFI_STATUS Status; + CHIP_COMPHY_CONFIG ChipConfig[MVHW_MAX_COMPHY_DEVS], *PtrChipCfg; + PCD_LANE_MAP LaneData[MVHW_MAX_COMPHY_DEVS]; + UINT32 Lane, MaxComphyCount; + UINT8 *ComPhyDeviceTable, Index; + + /* Obtain table with enabled ComPhy devices */ + ComPhyDeviceTable = (UINT8 *)PcdGetPtr (PcdComPhyDevices); + if (ComPhyDeviceTable == NULL) { + DEBUG ((DEBUG_ERROR, "Missing PcdComPhyDevices\n")); + return EFI_INVALID_PARAMETER; + } + + if (PcdGetSize (PcdComPhyDevices) > MVHW_MAX_COMPHY_DEVS) { + DEBUG ((DEBUG_ERROR, "Wrong PcdComPhyDevices format\n")); + return EFI_INVALID_PARAMETER; + } + + /* Initialize enabled chips */ + for (Index = 0; Index < PcdGetSize (PcdComPhyDevices); Index++) { + if (!MVHW_DEV_ENABLED (ComPhy, Index)) { + DEBUG ((DEBUG_ERROR, "Skip ComPhy chip %d\n", Index)); + continue; + } + + PtrChipCfg = &ChipConfig[Index]; + InitComPhyConfig(PtrChipCfg, LaneData, Index); + + /* Get the count of the SerDes of the specific chip */ + MaxComphyCount = PtrChipCfg->LanesCount; + for (Lane = 0; Lane < MaxComphyCount; Lane++) { + /* Parse PCD with string indicating SerDes Type */ + PtrChipCfg->MapData[Lane].Type = + ParseSerdesTypeString (LaneData[Index].TypeStr[Lane]); + PtrChipCfg->MapData[Lane].Speed = + ParseSerdesSpeed (LaneData[Index].SpeedValue[Lane]); + PtrChipCfg->MapData[Lane].Invert = (UINT32)LaneData[Index].InvFlag[Lane]; + + if ((PtrChipCfg->MapData[Lane].Speed == COMPHY_SPEED_INVALID) || + (PtrChipCfg->MapData[Lane].Speed == COMPHY_SPEED_ERROR) || + (PtrChipCfg->MapData[Lane].Type == COMPHY_TYPE_INVALID)) { + DEBUG((DEBUG_ERROR, "ComPhy: No valid phy speed or type for lane %d, " + "setting lane as unconnected\n", Lane + 1)); + PtrChipCfg->MapData[Lane].Type = COMPHY_TYPE_UNCONNECTED; + PtrChipCfg->MapData[Lane].Speed = COMPHY_SPEED_INVALID; + } + }; + + Status = GetChipComPhyInit (PtrChipCfg); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "ComPhy: Invalid Chip%d type\n", Index)); + return Status; + } + + ComPhyPrint (PtrChipCfg); + + /* PHY power UP sequence */ + PtrChipCfg->Init (PtrChipCfg); + } + + return EFI_SUCCESS; +} diff --git a/Platform/Marvell/Library/ComPhyLib/ComPhyLib.h b/Platform/Marvell/Library/ComPhyLib/ComPhyLib.h new file mode 100644 index 0000000000..38989780ab --- /dev/null +++ b/Platform/Marvell/Library/ComPhyLib/ComPhyLib.h @@ -0,0 +1,643 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __COMPHY_H__ +#define __COMPHY_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_LANE_OPTIONS 10 + +/***** Parsing PCD *****/ +#define GET_LANE_TYPE(id) PcdGetPtr(PcdChip##id##ComPhyTypes) +#define GET_LANE_SPEED(id) PcdGetPtr(PcdChip##id##ComPhySpeeds) +#define GET_LANE_INV(id) PcdGetPtr(PcdChip##id##ComPhyInvFlags) + +#define FillLaneMap(chip_struct, lane_struct, id) { \ + ParsePcdString((CHAR16 *) GET_LANE_TYPE(id), chip_struct[id].LanesCount, NULL, lane_struct[id].TypeStr); \ + ParsePcdString((CHAR16 *) GET_LANE_SPEED(id), chip_struct[id].LanesCount, lane_struct[id].SpeedValue, NULL); \ + ParsePcdString((CHAR16 *) GET_LANE_INV(id), chip_struct[id].LanesCount, lane_struct[id].InvFlag, NULL); \ +} + +#define GetComPhyPcd(chip_struct, lane_struct, id) { \ + FillLaneMap(chip_struct, lane_struct, id); \ +} + +/***** ComPhy *****/ +#define COMPHY_SPEED_ERROR 0 +#define COMPHY_SPEED_1_25G 1 +#define COMPHY_SPEED_1_5G 2 +#define COMPHY_SPEED_2_5G 3 +#define COMPHY_SPEED_3G 4 +#define COMPHY_SPEED_3_125G 5 +#define COMPHY_SPEED_5G 6 +#define COMPHY_SPEED_5_15625G 7 +#define COMPHY_SPEED_6G 8 +#define COMPHY_SPEED_6_25G 9 +#define COMPHY_SPEED_10_3125G 10 +#define COMPHY_SPEED_MAX 11 +#define COMPHY_SPEED_INVALID 0xff + +#define COMPHY_TYPE_UNCONNECTED 0 +#define COMPHY_TYPE_PCIE0 1 +#define COMPHY_TYPE_PCIE1 2 +#define COMPHY_TYPE_PCIE2 3 +#define COMPHY_TYPE_PCIE3 4 +#define COMPHY_TYPE_SATA0 5 +#define COMPHY_TYPE_SATA1 6 +#define COMPHY_TYPE_SATA2 7 +#define COMPHY_TYPE_SATA3 8 +#define COMPHY_TYPE_SGMII0 9 +#define COMPHY_TYPE_SGMII1 10 +#define COMPHY_TYPE_SGMII2 11 +#define COMPHY_TYPE_SGMII3 12 +#define COMPHY_TYPE_QSGMII 13 +#define COMPHY_TYPE_USB3_HOST0 14 +#define COMPHY_TYPE_USB3_HOST1 15 +#define COMPHY_TYPE_USB3_DEVICE 16 +#define COMPHY_TYPE_XAUI0 17 +#define COMPHY_TYPE_XAUI1 18 +#define COMPHY_TYPE_XAUI2 19 +#define COMPHY_TYPE_XAUI3 20 +#define COMPHY_TYPE_RXAUI0 21 +#define COMPHY_TYPE_RXAUI1 22 +#define COMPHY_TYPE_SFI 23 +#define COMPHY_TYPE_MAX 24 +#define COMPHY_TYPE_INVALID 0xff + +#define COMPHY_POLARITY_NO_INVERT 0 +#define COMPHY_POLARITY_TXD_INVERT 1 +#define COMPHY_POLARITY_RXD_INVERT 2 +#define COMPHY_POLARITY_ALL_INVERT (COMPHY_POLARITY_TXD_INVERT | COMPHY_POLARITY_RXD_INVERT) + +/***** SerDes IP registers *****/ +#define SD_EXTERNAL_CONFIG0_REG 0 +#define SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET 1 +#define SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK (1 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET) +#define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET 3 +#define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK (0xf << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET) +#define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET 7 +#define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK (0xf << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET) +#define SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET 11 +#define SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK (1 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET) +#define SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET 12 +#define SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK (1 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET) +#define SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET 14 +#define SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK (1 << SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET) +#define SD_EXTERNAL_CONFIG0_MEDIA_MODE_OFFSET 15 +#define SD_EXTERNAL_CONFIG0_MEDIA_MODE_MASK (0x1 << SD_EXTERNAL_CONFIG0_MEDIA_MODE_OFFSET) + +#define SD_EXTERNAL_CONFIG1_REG 0x4 +#define SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET 3 +#define SD_EXTERNAL_CONFIG1_RESET_IN_MASK (0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET) +#define SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET 4 +#define SD_EXTERNAL_CONFIG1_RX_INIT_MASK (0x1 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET) +#define SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET 5 +#define SD_EXTERNAL_CONFIG1_RESET_CORE_MASK (0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET) +#define SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET 6 +#define SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK (0x1 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET) + +#define SD_EXTERNAL_CONFIG2_REG 0x8 +#define SD_EXTERNAL_CONFIG2_PIN_DFE_EN_OFFSET 4 +#define SD_EXTERNAL_CONFIG2_PIN_DFE_EN_MASK (0x1 << SD_EXTERNAL_CONFIG2_PIN_DFE_EN_OFFSET) +#define SD_EXTERNAL_CONFIG2_SSC_ENABLE_OFFSET 7 +#define SD_EXTERNAL_CONFIG2_SSC_ENABLE_MASK (0x1 << SD_EXTERNAL_CONFIG2_SSC_ENABLE_OFFSET) + +#define SD_EXTERNAL_STATUS0_REG 0x18 +#define SD_EXTERNAL_STATUS0_PLL_TX_OFFSET 2 +#define SD_EXTERNAL_STATUS0_PLL_TX_MASK (0x1 << SD_EXTERNAL_STATUS0_PLL_TX_OFFSET) +#define SD_EXTERNAL_STATUS0_PLL_RX_OFFSET 3 +#define SD_EXTERNAL_STATUS0_PLL_RX_MASK (0x1 << SD_EXTERNAL_STATUS0_PLL_RX_OFFSET) +#define SD_EXTERNAL_STATUS0_RX_INIT_OFFSET 4 +#define SD_EXTERNAL_STATUS0_RX_INIT_MASK (0x1 << SD_EXTERNAL_STATUS0_RX_INIT_OFFSET) + +/***** HPIPE registers *****/ +#define HPIPE_PWR_PLL_REG 0x4 +#define HPIPE_PWR_PLL_REF_FREQ_OFFSET 0 +#define HPIPE_PWR_PLL_REF_FREQ_MASK (0x1f << HPIPE_PWR_PLL_REF_FREQ_OFFSET) +#define HPIPE_PWR_PLL_PHY_MODE_OFFSET 5 +#define HPIPE_PWR_PLL_PHY_MODE_MASK (0x7 << HPIPE_PWR_PLL_PHY_MODE_OFFSET) + +#define HPIPE_KVCO_CALIB_CTRL_REG 0x8 +#define HPIPE_KVCO_CALIB_CTRL_MAX_PLL_OFFSET 12 +#define HPIPE_KVCO_CALIB_CTRL_MAX_PLL_MASK (0x1 << HPIPE_KVCO_CALIB_CTRL_MAX_PLL_OFFSET) + +#define HPIPE_CAL_REG1_REG 0xc +#define HPIPE_CAL_REG_1_EXT_TXIMP_OFFSET 10 +#define HPIPE_CAL_REG_1_EXT_TXIMP_MASK (0x1f << HPIPE_CAL_REG_1_EXT_TXIMP_OFFSET) +#define HPIPE_CAL_REG_1_EXT_TXIMP_EN_OFFSET 15 +#define HPIPE_CAL_REG_1_EXT_TXIMP_EN_MASK (0x1 << HPIPE_CAL_REG_1_EXT_TXIMP_EN_OFFSET) + +#define HPIPE_SQUELCH_FFE_SETTING_REG 0x018 + +#define HPIPE_DFE_REG0 0x01C +#define HPIPE_DFE_RES_FORCE_OFFSET 15 +#define HPIPE_DFE_RES_FORCE_MASK (0x1 << HPIPE_DFE_RES_FORCE_OFFSET) + +#define HPIPE_DFE_F3_F5_REG 0x028 +#define HPIPE_DFE_F3_F5_DFE_EN_OFFSET 14 +#define HPIPE_DFE_F3_F5_DFE_EN_MASK (0x1 << HPIPE_DFE_F3_F5_DFE_EN_OFFSET) +#define HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET 15 +#define HPIPE_DFE_F3_F5_DFE_CTRL_MASK (0x1 << HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET) + +#define HPIPE_G1_SET0_REG 0x034 +#define HPIPE_G2_SET0_REG 0x03c +#define HPIPE_G3_SET0_REG 0x044 +#define HPIPE_GX_SET0_TX_AMP_OFFSET 1 +#define HPIPE_GX_SET0_TX_AMP_MASK (0x1f << HPIPE_GX_SET0_TX_AMP_OFFSET) +#define HPIPE_GX_SET0_TX_AMP_ADJ_OFFSET 6 +#define HPIPE_GX_SET0_TX_AMP_ADJ_MASK (0x1 << HPIPE_GX_SET0_TX_AMP_ADJ_OFFSET) +#define HPIPE_GX_SET0_TX_EMPH1_OFFSET 7 +#define HPIPE_GX_SET0_TX_EMPH1_MASK (0xf << HPIPE_GX_SET0_TX_EMPH1_OFFSET) +#define HPIPE_GX_SET0_TX_EMPH1_EN_OFFSET 11 +#define HPIPE_GX_SET0_TX_EMPH1_EN_MASK (0x1 << HPIPE_GX_SET0_TX_EMPH1_EN_OFFSET) +#define HPIPE_GX_SET0_TX_SLEW_RATE_SEL_OFFSET 12 +#define HPIPE_GX_SET0_TX_SLEW_RATE_SEL_MASK (0x7 << HPIPE_GX_SET0_TX_SLEW_RATE_SEL_OFFSET) +#define HPIPE_GX_SET0_TX_SLEW_CTRL_EN_OFFSET 15 +#define HPIPE_GX_SET0_TX_SLEW_CTRL_EN_MASK (0x1 << HPIPE_GX_SET0_TX_SLEW_CTRL_EN_OFFSET) + +#define HPIPE_G1_SET1_REG 0x038 +#define HPIPE_G2_SET1_REG 0x040 +#define HPIPE_G3_SET1_REG 0x048 +#define HPIPE_GX_SET1_RX_SELMUPI_OFFSET 0 +#define HPIPE_GX_SET1_RX_SELMUPI_MASK (0x7 << HPIPE_GX_SET1_RX_SELMUPI_OFFSET) +#define HPIPE_GX_SET1_RX_SELMUPP_OFFSET 3 +#define HPIPE_GX_SET1_RX_SELMUPP_MASK (0x7 << HPIPE_GX_SET1_RX_SELMUPP_OFFSET) +#define HPIPE_GX_SET1_RX_SELMUFI_OFFSET 6 +#define HPIPE_GX_SET1_RX_SELMUFI_MASK (0x3 << HPIPE_GX_SET1_RX_SELMUFI_OFFSET) +#define HPIPE_GX_SET1_RX_SELMUFF_OFFSET 8 +#define HPIPE_GX_SET1_RX_SELMUFF_MASK (0x3 << HPIPE_GX_SET1_RX_SELMUFF_OFFSET) +#define HPIPE_GX_SET1_RX_DFE_EN_OFFSET 10 +#define HPIPE_GX_SET1_RX_DFE_EN_MASK (0x1 << HPIPE_GX_SET1_RX_DFE_EN_OFFSET) +#define HPIPE_GX_SET1_RX_DIGCK_DIV_OFFSET 11 +#define HPIPE_GX_SET1_RX_DIGCK_DIV_MASK (0x3 << HPIPE_GX_SET1_RX_DIGCK_DIV_OFFSET) +#define HPIPE_GX_SET1_SAMPLER_INPAIRX2_EN_OFFSET 13 +#define HPIPE_GX_SET1_SAMPLER_INPAIRX2_EN_MASK (0x1 << HPIPE_GX_SET1_SAMPLER_INPAIRX2_EN_OFFSET) + +#define HPIPE_LOOPBACK_REG 0x08c +#define HPIPE_LOOPBACK_SEL_OFFSET 1 +#define HPIPE_LOOPBACK_SEL_MASK (0x7 << HPIPE_LOOPBACK_SEL_OFFSET) + +#define HPIPE_SYNC_PATTERN_REG 0x090 + +#define HPIPE_INTERFACE_REG 0x94 +#define HPIPE_INTERFACE_GEN_MAX_OFFSET 10 +#define HPIPE_INTERFACE_GEN_MAX_MASK (0x3 << HPIPE_INTERFACE_GEN_MAX_OFFSET) +#define HPIPE_INTERFACE_DET_BYPASS_OFFSET 12 +#define HPIPE_INTERFACE_DET_BYPASS_MASK (0x1 << HPIPE_INTERFACE_DET_BYPASS_OFFSET) +#define HPIPE_INTERFACE_LINK_TRAIN_OFFSET 14 +#define HPIPE_INTERFACE_LINK_TRAIN_MASK (0x1 << HPIPE_INTERFACE_LINK_TRAIN_OFFSET) + +#define HPIPE_ISOLATE_MODE_REG 0x98 +#define HPIPE_ISOLATE_MODE_GEN_RX_OFFSET 0 +#define HPIPE_ISOLATE_MODE_GEN_RX_MASK (0xf << HPIPE_ISOLATE_MODE_GEN_RX_OFFSET) +#define HPIPE_ISOLATE_MODE_GEN_TX_OFFSET 4 +#define HPIPE_ISOLATE_MODE_GEN_TX_MASK (0xf << HPIPE_ISOLATE_MODE_GEN_TX_OFFSET) + +#define HPIPE_GX_SET2_REG 0xf4 +#define HPIPE_GX_SET2_TX_EMPH0_OFFSET 0 +#define HPIPE_GX_SET2_TX_EMPH0_MASK (0xf << HPIPE_GX_SET2_TX_EMPH0_OFFSET) +#define HPIPE_GX_SET2_TX_EMPH0_EN_OFFSET 4 +#define HPIPE_GX_SET2_TX_EMPH0_EN_MASK (0x1 << HPIPE_GX_SET2_TX_EMPH0_MASK) + +#define HPIPE_VTHIMPCAL_CTRL_REG 0x104 + +#define HPIPE_VDD_CAL_CTRL_REG 0x114 +#define HPIPE_EXT_SELLV_RXSAMPL_OFFSET 5 +#define HPIPE_EXT_SELLV_RXSAMPL_MASK (0x1f << HPIPE_EXT_SELLV_RXSAMPL_OFFSET) + +#define HPIPE_VDD_CAL_0_REG 0x108 +#define HPIPE_CAL_VDD_CONT_MODE_OFFSET 15 +#define HPIPE_CAL_VDD_CONT_MODE_MASK (0x1 << HPIPE_CAL_VDD_CONT_MODE_OFFSET) + +#define HPIPE_PCIE_REG0 0x120 +#define HPIPE_PCIE_IDLE_SYNC_OFFSET 12 +#define HPIPE_PCIE_IDLE_SYNC_MASK (0x1 << HPIPE_PCIE_IDLE_SYNC_OFFSET) +#define HPIPE_PCIE_SEL_BITS_OFFSET 13 +#define HPIPE_PCIE_SEL_BITS_MASK (0x3 << HPIPE_PCIE_SEL_BITS_OFFSET) + +#define HPIPE_LANE_ALIGN_REG 0x124 +#define HPIPE_LANE_ALIGN_OFF_OFFSET 12 +#define HPIPE_LANE_ALIGN_OFF_MASK (0x1 << HPIPE_LANE_ALIGN_OFF_OFFSET) + +#define HPIPE_MISC_REG 0x13C +#define HPIPE_MISC_CLK100M_125M_OFFSET 4 +#define HPIPE_MISC_CLK100M_125M_MASK (0x1 << HPIPE_MISC_CLK100M_125M_OFFSET) +#define HPIPE_MISC_ICP_FORCE_OFFSET 5 +#define HPIPE_MISC_ICP_FORCE_MASK (0x1 << HPIPE_MISC_ICP_FORCE_OFFSET) +#define HPIPE_MISC_TXDCLK_2X_OFFSET 6 +#define HPIPE_MISC_TXDCLK_2X_MASK (0x1 << HPIPE_MISC_TXDCLK_2X_OFFSET) +#define HPIPE_MISC_CLK500_EN_OFFSET 7 +#define HPIPE_MISC_CLK500_EN_MASK (0x1 << HPIPE_MISC_CLK500_EN_OFFSET) +#define HPIPE_MISC_REFCLK_SEL_OFFSET 10 +#define HPIPE_MISC_REFCLK_SEL_MASK (0x1 << HPIPE_MISC_REFCLK_SEL_OFFSET) + +#define HPIPE_RX_CONTROL_1_REG 0x140 +#define HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET 11 +#define HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK (0x1 << HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET) +#define HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET 12 +#define HPIPE_RX_CONTROL_1_CLK8T_EN_MASK (0x1 << HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET) + +#define HPIPE_PWR_CTR_REG 0x148 +#define HPIPE_PWR_CTR_RST_DFE_OFFSET 0 +#define HPIPE_PWR_CTR_RST_DFE_MASK (0x1 << HPIPE_PWR_CTR_RST_DFE_OFFSET) +#define HPIPE_PWR_CTR_SFT_RST_OFFSET 10 +#define HPIPE_PWR_CTR_SFT_RST_MASK (0x1 << HPIPE_PWR_CTR_SFT_RST_OFFSET) + +#define HPIPE_PLLINTP_REG1 0x150 + +#define HPIPE_SPD_DIV_FORCE_REG 0x154 +#define HPIPE_TXDIGCK_DIV_FORCE_OFFSET 7 +#define HPIPE_TXDIGCK_DIV_FORCE_MASK (0x1 << HPIPE_TXDIGCK_DIV_FORCE_OFFSET) +#define HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_OFFSET 8 +#define HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_MASK (0x3 << HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_OFFSET) +#define HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_OFFSET 10 +#define HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_MASK (0x1 << HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_OFFSET) +#define HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_OFFSET 13 +#define HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_MASK (0x3 << HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_OFFSET) +#define HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_OFFSET 15 +#define HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_MASK (0x1 << HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_OFFSET) + +#define HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG 0x16C +#define HPIPE_RX_SAMPLER_OS_GAIN_OFFSET 6 +#define HPIPE_RX_SAMPLER_OS_GAIN_MASK (0x3 << HPIPE_RX_SAMPLER_OS_GAIN_OFFSET) +#define HPIPE_SAMPLER_OFFSET 12 +#define HPIPE_SAMPLER_MASK (0x1 << HPIPE_SAMPLER_OFFSET) + +#define HPIPE_TX_REG1_REG 0x174 +#define HPIPE_TX_REG1_TX_EMPH_RES_OFFSET 5 +#define HPIPE_TX_REG1_TX_EMPH_RES_MASK (0x3 << HPIPE_TX_REG1_TX_EMPH_RES_OFFSET) +#define HPIPE_TX_REG1_SLC_EN_OFFSET 10 +#define HPIPE_TX_REG1_SLC_EN_MASK (0x3f << HPIPE_TX_REG1_SLC_EN_OFFSET) + +#define HPIPE_TX_REG1_REG 0x174 +#define HPIPE_TX_REG1_TX_EMPH_RES_OFFSET 5 +#define HPIPE_TX_REG1_TX_EMPH_RES_MASK (0x3 << HPIPE_TX_REG1_TX_EMPH_RES_OFFSET) +#define HPIPE_TX_REG1_SLC_EN_OFFSET 10 +#define HPIPE_TX_REG1_SLC_EN_MASK (0x3f << HPIPE_TX_REG1_SLC_EN_OFFSET) + +#define HPIPE_PWR_CTR_DTL_REG 0x184 +#define HPIPE_PWR_CTR_DTL_SQ_DET_EN_OFFSET 0 +#define HPIPE_PWR_CTR_DTL_SQ_DET_EN_MASK (0x1 << HPIPE_PWR_CTR_DTL_SQ_DET_EN_OFFSET) +#define HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_OFFSET 1 +#define HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_MASK (0x1 << HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_OFFSET) +#define HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET 2 +#define HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK (0x1 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET) +#define HPIPE_PWR_CTR_DTL_CLAMPING_SEL_OFFSET 4 +#define HPIPE_PWR_CTR_DTL_CLAMPING_SEL_MASK (0x7 << HPIPE_PWR_CTR_DTL_CLAMPING_SEL_OFFSET) +#define HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_OFFSET 10 +#define HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_MASK (0x1 << HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_OFFSET) +#define HPIPE_PWR_CTR_DTL_CLK_MODE_OFFSET 12 +#define HPIPE_PWR_CTR_DTL_CLK_MODE_MASK (0x3 << HPIPE_PWR_CTR_DTL_CLK_MODE_OFFSET) +#define HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_OFFSET 14 +#define HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_MASK (1 << HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_OFFSET) + +#define HPIPE_PHASE_CONTROL_REG 0x188 +#define HPIPE_OS_PH_OFFSET_OFFSET 0 +#define HPIPE_OS_PH_OFFSET_MASK (0x7f << HPIPE_OS_PH_OFFSET_OFFSET) +#define HPIPE_OS_PH_OFFSET_FORCE_OFFSET 7 +#define HPIPE_OS_PH_OFFSET_FORCE_MASK (0x1 << HPIPE_OS_PH_OFFSET_FORCE_OFFSET) +#define HPIPE_OS_PH_VALID_OFFSET 8 +#define HPIPE_OS_PH_VALID_MASK (0x1 << HPIPE_OS_PH_VALID_OFFSET) + +#define HPIPE_FRAME_DETECT_CTRL_0_REG 0x214 +#define HPIPE_TRAIN_PAT_NUM_OFFSET 0x7 +#define HPIPE_TRAIN_PAT_NUM_MASK (0x1FF << HPIPE_TRAIN_PAT_NUM_OFFSET) + +#define HPIPE_FRAME_DETECT_CTRL_3_REG 0x220 +#define HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_OFFSET 12 +#define HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_MASK (0x1 << HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_OFFSET) + +#define HPIPE_DME_REG 0x228 +#define HPIPE_DME_ETHERNET_MODE_OFFSET 7 +#define HPIPE_DME_ETHERNET_MODE_MASK (0x1 << HPIPE_DME_ETHERNET_MODE_OFFSET) + +#define HPIPE_TX_TRAIN_CTRL_0_REG 0x268 +#define HPIPE_TX_TRAIN_P2P_HOLD_OFFSET 15 +#define HPIPE_TX_TRAIN_P2P_HOLD_MASK (0x1 << HPIPE_TX_TRAIN_P2P_HOLD_OFFSET) + +#define HPIPE_TX_TRAIN_CTRL_REG 0x26C +#define HPIPE_TX_TRAIN_CTRL_G1_OFFSET 0 +#define HPIPE_TX_TRAIN_CTRL_G1_MASK (0x1 << HPIPE_TX_TRAIN_CTRL_G1_OFFSET) +#define HPIPE_TX_TRAIN_CTRL_GN1_OFFSET 1 +#define HPIPE_TX_TRAIN_CTRL_GN1_MASK (0x1 << HPIPE_TX_TRAIN_CTRL_GN1_OFFSET) +#define HPIPE_TX_TRAIN_CTRL_G0_OFFSET 2 +#define HPIPE_TX_TRAIN_CTRL_G0_MASK (0x1 << HPIPE_TX_TRAIN_CTRL_G0_OFFSET) + +#define HPIPE_TX_TRAIN_CTRL_4_REG 0x278 +#define HPIPE_TRX_TRAIN_TIMER_OFFSET 0 +#define HPIPE_TRX_TRAIN_TIMER_MASK (0x3FF << HPIPE_TRX_TRAIN_TIMER_OFFSET) + +#define HPIPE_PCIE_REG1 0x288 +#define HPIPE_PCIE_REG3 0x290 + +#define HPIPE_TX_TRAIN_CTRL_5_REG 0x2A4 +#define HPIPE_RX_TRAIN_TIMER_OFFSET 0 +#define HPIPE_RX_TRAIN_TIMER_MASK (0x3ff << HPIPE_RX_TRAIN_TIMER_OFFSET) +#define HPIPE_TX_TRAIN_START_SQ_EN_OFFSET 11 +#define HPIPE_TX_TRAIN_START_SQ_EN_MASK (0x1 << HPIPE_TX_TRAIN_START_SQ_EN_OFFSET) +#define HPIPE_TX_TRAIN_START_FRM_DET_EN_OFFSET 12 +#define HPIPE_TX_TRAIN_START_FRM_DET_EN_MASK (0x1 << HPIPE_TX_TRAIN_START_FRM_DET_EN_OFFSET) +#define HPIPE_TX_TRAIN_START_FRM_LOCK_EN_OFFSET 13 +#define HPIPE_TX_TRAIN_START_FRM_LOCK_EN_MASK (0x1 << HPIPE_TX_TRAIN_START_FRM_LOCK_EN_OFFSET) +#define HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET 14 +#define HPIPE_TX_TRAIN_WAIT_TIME_EN_MASK (0x1 << HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET) + +#define HPIPE_TX_TRAIN_REG 0x31C +#define HPIPE_TX_TRAIN_CHK_INIT_OFFSET 4 +#define HPIPE_TX_TRAIN_CHK_INIT_MASK (0x1 << HPIPE_TX_TRAIN_CHK_INIT_OFFSET) +#define HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET 7 +#define HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_MASK (0x1 << HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET) +#define HPIPE_TX_TRAIN_16BIT_AUTO_EN_OFFSET 8 +#define HPIPE_TX_TRAIN_16BIT_AUTO_EN_MASK (0x1 << HPIPE_TX_TRAIN_16BIT_AUTO_EN_OFFSET) +#define HPIPE_TX_TRAIN_PAT_SEL_OFFSET 9 +#define HPIPE_TX_TRAIN_PAT_SEL_MASK (0x1 << HPIPE_TX_TRAIN_PAT_SEL_OFFSET) + +#define HPIPE_CDR_CONTROL_REG 0x418 +#define HPIPE_CDR_MAX_DFE_ADAPT_1_OFFSET 6 +#define HPIPE_CDR_MAX_DFE_ADAPT_1_MASK (0x7 << HPIPE_CDR_MAX_DFE_ADAPT_1_OFFSET) +#define HPIPE_CDR_MAX_DFE_ADAPT_0_OFFSET 9 +#define HPIPE_CDR_MAX_DFE_ADAPT_0_MASK (0x7 << HPIPE_CDR_MAX_DFE_ADAPT_0_OFFSET) +#define HPIPE_CDR_RX_MAX_DFE_ADAPT_1_OFFSET 12 +#define HPIPE_CDR_RX_MAX_DFE_ADAPT_1_MASK (0x3 << HPIPE_CDR_RX_MAX_DFE_ADAPT_1_OFFSET) + +#define HPIPE_TX_TRAIN_CTRL_11_REG 0x438 +#define HPIPE_TX_STATUS_CHECK_MODE_OFFSET 6 +#define HPIPE_TX_TX_STATUS_CHECK_MODE_MASK (0x1 << HPIPE_TX_STATUS_CHECK_MODE_OFFSET) +#define HPIPE_TX_NUM_OF_PRESET_OFFSET 10 +#define HPIPE_TX_NUM_OF_PRESET_MASK (0x7 << HPIPE_TX_NUM_OF_PRESET_OFFSET) +#define HPIPE_TX_SWEEP_PRESET_EN_OFFSET 15 +#define HPIPE_TX_SWEEP_PRESET_EN_MASK (0x1 << HPIPE_TX_SWEEP_PRESET_EN_OFFSET) + +#define HPIPE_G1_SET3_REG 0x440 +#define HPIPE_G2_SET3_REG 0x448 +#define HPIPE_G3_SET3_REG 0x450 +#define HPIPE_GX_SET3_FFE_CAP_SEL_OFFSET 0 +#define HPIPE_GX_SET3_FFE_CAP_SEL_MASK (0xf << HPIPE_GX_SET3_FFE_CAP_SEL_OFFSET) +#define HPIPE_GX_SET3_FFE_RES_SEL_OFFSET 4 +#define HPIPE_GX_SET3_FFE_RES_SEL_MASK (0x7 << HPIPE_GX_SET3_FFE_RES_SEL_OFFSET) +#define HPIPE_GX_SET3_FFE_SETTING_FORCE_OFFSET 7 +#define HPIPE_GX_SET3_FFE_SETTING_FORCE_MASK (0x1 << HPIPE_GX_SET3_FFE_SETTING_FORCE_OFFSET) +#define HPIPE_GX_SET3_FBCK_SEL_OFFSET 9 +#define HPIPE_GX_SET3_FBCK_SEL_MASK (0x1 << HPIPE_GX_SET3_FBCK_SEL_OFFSET) +#define HPIPE_GX_SET3_FFE_DEG_RES_LEVEL_OFFSET 12 +#define HPIPE_GX_SET3_FFE_DEG_RES_LEVEL_MASK (0x3 << HPIPE_GX_SET3_FFE_DEG_RES_LEVEL_OFFSET) +#define HPIPE_GX_SET3_FFE_LOAD_RES_LEVEL_OFFSET 14 +#define HPIPE_GX_SET3_FFE_LOAD_RES_LEVEL_MASK (0x3 << HPIPE_GX_SET3_FFE_LOAD_RES_LEVEL_OFFSET) + +#define HPIPE_G1_SET4_REG 0x444 +#define HPIPE_G2_SET4_REG 0x44C +#define HPIPE_G3_SET4_REG 0x454 +#define HPIPE_GX_SET4_DFE_RES_OFFSET 8 +#define HPIPE_GX_SET4_DFE_RES_MASK (0x3 << HPIPE_GX_SET4_DFE_RES_OFFSET) + +#define HPIPE_TX_PRESET_INDEX_REG 0x468 +#define HPIPE_TX_PRESET_INDEX_OFFSET 0 +#define HPIPE_TX_PRESET_INDEX_MASK (0xf << HPIPE_TX_PRESET_INDEX_OFFSET) + +#define HPIPE_DFE_CONTROL_REG 0x470 +#define HPIPE_DFE_TX_MAX_DFE_ADAPT_OFFSET 14 +#define HPIPE_DFE_TX_MAX_DFE_ADAPT_MASK (0x3 << HPIPE_DFE_TX_MAX_DFE_ADAPT_OFFSET) + +#define HPIPE_DFE_CTRL_28_REG 0x49C +#define HPIPE_DFE_CTRL_28_PIPE4_OFFSET 7 +#define HPIPE_DFE_CTRL_28_PIPE4_MASK (0x1 << HPIPE_DFE_CTRL_28_PIPE4_OFFSET) + +#define HPIPE_G1_SET5_REG 0x538 +#define HPIPE_G3_SET5_REG 0x548 +#define HPIPE_GX_SET5_ICP_OFFSET 0 +#define HPIPE_GX_SET5_ICP_MASK (0xf << HPIPE_GX_SET5_ICP_OFFSET) + +#define HPIPE_LANE_CONFIG0_REG 0x604 +#define HPIPE_LANE_CONFIG0_MAX_PLL_OFFSET 9 +#define HPIPE_LANE_CONFIG0_MAX_PLL_MASK (0x1 << HPIPE_LANE_CONFIG0_MAX_PLL_OFFSET) +#define HPIPE_LANE_CONFIG0_GEN2_PLL_OFFSET 10 +#define HPIPE_LANE_CONFIG0_GEN2_PLL_MASK (0x1 << HPIPE_LANE_CONFIG0_GEN2_PLL_OFFSET) + +#define HPIPE_LANE_STATUS0_REG 0x60C +#define HPIPE_LANE_STATUS0_PCLK_EN_OFFSET 0 +#define HPIPE_LANE_STATUS0_PCLK_EN_MASK (0x1 << HPIPE_LANE_STATUS0_PCLK_EN_OFFSET) + +#define HPIPE_LANE_CFG4_REG 0x620 +#define HPIPE_LANE_CFG4_DFE_CTRL_OFFSET 0 +#define HPIPE_LANE_CFG4_DFE_CTRL_MASK (0x7 << HPIPE_LANE_CFG4_DFE_CTRL_OFFSET) +#define HPIPE_LANE_CFG4_DFE_EN_SEL_OFFSET 3 +#define HPIPE_LANE_CFG4_DFE_EN_SEL_MASK (0x1 << HPIPE_LANE_CFG4_DFE_EN_SEL_OFFSET) +#define HPIPE_LANE_CFG4_DFE_OVER_OFFSET 6 +#define HPIPE_LANE_CFG4_DFE_OVER_MASK (0x1 << HPIPE_LANE_CFG4_DFE_OVER_OFFSET) +#define HPIPE_LANE_CFG4_SSC_CTRL_OFFSET 7 +#define HPIPE_LANE_CFG4_SSC_CTRL_MASK (0x1 << HPIPE_LANE_CFG4_SSC_CTRL_OFFSET) + +#define HPIPE_LANE_EQU_CONFIG_0_REG 0x69C +#define HPIPE_CFG_PHY_RC_EP_OFFSET 12 +#define HPIPE_CFG_PHY_RC_EP_MASK (0x1 << HPIPE_CFG_PHY_RC_EP_OFFSET) + +#define HPIPE_LANE_EQ_CFG1_REG 0x6a0 +#define HPIPE_CFG_UPDATE_POLARITY_OFFSET 12 +#define HPIPE_CFG_UPDATE_POLARITY_MASK (0x1 << HPIPE_CFG_UPDATE_POLARITY_OFFSET) + +#define HPIPE_LANE_EQ_REMOTE_SETTING_REG 0x6f8 +#define HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_OFFSET 0 +#define HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_MASK (0x1 << HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_OFFSET) +#define HPIPE_LANE_CFG_FOM_ONLY_MODE_OFFFSET 1 +#define HPIPE_LANE_CFG_FOM_ONLY_MODE_MASK (0x1 << HPIPE_LANE_CFG_FOM_ONLY_MODE_OFFFSET) +#define HPIPE_LANE_CFG_FOM_PRESET_VECTOR_OFFSET 2 +#define HPIPE_LANE_CFG_FOM_PRESET_VECTOR_MASK (0xf << HPIPE_LANE_CFG_FOM_PRESET_VECTOR_OFFSET) + +#define HPIPE_RST_CLK_CTRL_REG 0x704 +#define HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET 0 +#define HPIPE_RST_CLK_CTRL_PIPE_RST_MASK (0x1 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET) +#define HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET 2 +#define HPIPE_RST_CLK_CTRL_FIXED_PCLK_MASK (0x1 << HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET) +#define HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET 3 +#define HPIPE_RST_CLK_CTRL_PIPE_WIDTH_MASK (0x1 << HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET) +#define HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET 9 +#define HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_MASK (0x1 << HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET) + +#define HPIPE_CLK_SRC_LO_REG 0x70c +#define HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET 5 +#define HPIPE_CLK_SRC_LO_PLL_RDY_DL_MASK (0x7 << HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET) + +#define HPIPE_CLK_SRC_HI_REG 0x710 +#define HPIPE_CLK_SRC_HI_LANE_STRT_OFFSET 0 +#define HPIPE_CLK_SRC_HI_LANE_STRT_MASK (0x1 << HPIPE_CLK_SRC_HI_LANE_STRT_OFFSET) +#define HPIPE_CLK_SRC_HI_LANE_BREAK_OFFSET 1 +#define HPIPE_CLK_SRC_HI_LANE_BREAK_MASK (0x1 << HPIPE_CLK_SRC_HI_LANE_BREAK_OFFSET) +#define HPIPE_CLK_SRC_HI_LANE_MASTER_OFFSET 2 +#define HPIPE_CLK_SRC_HI_LANE_MASTER_MASK (0x1 << HPIPE_CLK_SRC_HI_LANE_MASTER_OFFSET) +#define HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET 7 +#define HPIPE_CLK_SRC_HI_MODE_PIPE_MASK (0x1 << HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET) + +#define HPIPE_GLOBAL_MISC_CTRL 0x718 +#define HPIPE_GLOBAL_PM_CTRL 0x740 +#define HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET 0 +#define HPIPE_GLOBAL_PM_RXDLOZ_WAIT_MASK (0xFF << HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET) + +/***** COMPHY registers *****/ +#define COMMON_PHY_CFG1_REG 0x0 +#define COMMON_PHY_CFG1_PWR_UP_OFFSET 1 +#define COMMON_PHY_CFG1_PWR_UP_MASK (0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET) +#define COMMON_PHY_CFG1_PIPE_SELECT_OFFSET 2 +#define COMMON_PHY_CFG1_PIPE_SELECT_MASK (0x1 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET) +#define COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET 13 +#define COMMON_PHY_CFG1_PWR_ON_RESET_MASK (0x1 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET) +#define COMMON_PHY_CFG1_CORE_RSTN_OFFSET 14 +#define COMMON_PHY_CFG1_CORE_RSTN_MASK (0x1 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET) +#define COMMON_PHY_PHY_MODE_OFFSET 15 +#define COMMON_PHY_PHY_MODE_MASK (0x1 << COMMON_PHY_PHY_MODE_OFFSET) + +#define COMMON_PHY_CFG6_REG 0x14 +#define COMMON_PHY_CFG6_IF_40_SEL_OFFSET 18 +#define COMMON_PHY_CFG6_IF_40_SEL_MASK (0x1 << COMMON_PHY_CFG6_IF_40_SEL_OFFSET) + +#define COMMON_SELECTOR_PHY_OFFSET 0x140 +#define COMMON_SELECTOR_PIPE_OFFSET 0x144 + +#define COMMON_PHY_SD_CTRL1 0x148 +#define COMMON_PHY_SD_CTRL1_RXAUI1_OFFSET 26 +#define COMMON_PHY_SD_CTRL1_RXAUI1_MASK (0x1 << COMMON_PHY_SD_CTRL1_RXAUI1_OFFSET) +#define COMMON_PHY_SD_CTRL1_RXAUI0_OFFSET 27 +#define COMMON_PHY_SD_CTRL1_RXAUI0_MASK (0x1 << COMMON_PHY_SD_CTRL1_RXAUI0_OFFSET) + +/***** SATA registers *****/ +#define SATA3_VENDOR_ADDRESS 0xA0 +#define SATA3_VENDOR_ADDR_OFSSET 0 +#define SATA3_VENDOR_ADDR_MASK (0xFFFFFFFF << SATA3_VENDOR_ADDR_OFSSET) +#define SATA3_VENDOR_DATA 0xA4 + +#define SATA_CONTROL_REG 0x0 +#define SATA3_CTRL_SATA0_PD_OFFSET 6 +#define SATA3_CTRL_SATA0_PD_MASK (1 << SATA3_CTRL_SATA0_PD_OFFSET) +#define SATA3_CTRL_SATA1_PD_OFFSET 14 +#define SATA3_CTRL_SATA1_PD_MASK (1 << SATA3_CTRL_SATA1_PD_OFFSET) +#define SATA3_CTRL_SATA1_ENABLE_OFFSET 22 +#define SATA3_CTRL_SATA1_ENABLE_MASK (1 << SATA3_CTRL_SATA1_ENABLE_OFFSET) +#define SATA3_CTRL_SATA_SSU_OFFSET 23 +#define SATA3_CTRL_SATA_SSU_MASK (1 << SATA3_CTRL_SATA_SSU_OFFSET) + +#define SATA_MBUS_SIZE_SELECT_REG 0x4 +#define SATA_MBUS_REGRET_EN_OFFSET 7 +#define SATA_MBUS_REGRET_EN_MASK (0x1 << SATA_MBUS_REGRET_EN_OFFSET) + +/***************************/ + +typedef struct _CHIP_COMPHY_CONFIG CHIP_COMPHY_CONFIG; + +typedef struct { + UINT32 Type; + UINT32 MuxValue; +} COMPHY_MUX_OPTIONS; + +typedef struct { + UINT32 MaxLaneValues; + COMPHY_MUX_OPTIONS MuxValues[MAX_LANE_OPTIONS]; +} COMPHY_MUX_DATA; + +typedef struct { + UINT32 Type; + UINT32 Speed; + UINT32 Invert; +} COMPHY_MAP; + +typedef struct { + CHAR16 *TypeStr[MAX_LANE_OPTIONS]; + UINTN SpeedValue[MAX_LANE_OPTIONS]; + UINTN InvFlag[MAX_LANE_OPTIONS]; +} PCD_LANE_MAP; + +typedef +VOID +(*COMPHY_CHIP_INIT) ( + IN CHIP_COMPHY_CONFIG *PtrChipCfg + ); + +struct _CHIP_COMPHY_CONFIG { + MV_COMPHY_CHIP_TYPE ChipType; + COMPHY_MAP MapData[MAX_LANE_OPTIONS]; + COMPHY_MUX_DATA *MuxData; + EFI_PHYSICAL_ADDRESS ComPhyBaseAddr; + EFI_PHYSICAL_ADDRESS Hpipe3BaseAddr; + COMPHY_CHIP_INIT Init; + UINT32 LanesCount; + UINT32 MuxBitCount; +}; + +VOID +ComPhyMuxInit ( + IN CHIP_COMPHY_CONFIG *PtrChipCfg, + IN COMPHY_MAP *ComPhyMapData, + IN EFI_PHYSICAL_ADDRESS SelectorBase + ); + +VOID +ComPhyCp110Init ( + IN CHIP_COMPHY_CONFIG * First + ); + +VOID +RegSet ( + IN EFI_PHYSICAL_ADDRESS Addr, + IN UINT32 Data, + IN UINT32 Mask + ); + +VOID +RegSetSilent ( + IN EFI_PHYSICAL_ADDRESS Addr, + IN UINT32 Data, + IN UINT32 Mask + ); + +VOID +RegSet16 ( + IN EFI_PHYSICAL_ADDRESS Addr, + IN UINT16 Data, + IN UINT16 Mask + ); + +VOID +RegSetSilent16( + IN EFI_PHYSICAL_ADDRESS Addr, + IN UINT16 Data, + IN UINT16 Mask + ); +#endif // __COMPHY_H__ diff --git a/Platform/Marvell/Library/ComPhyLib/ComPhyLib.inf b/Platform/Marvell/Library/ComPhyLib/ComPhyLib.inf new file mode 100644 index 0000000000..e0f4634dca --- /dev/null +++ b/Platform/Marvell/Library/ComPhyLib/ComPhyLib.inf @@ -0,0 +1,84 @@ +# Copyright (C) 2016 Marvell International Ltd. +# +# Marvell BSD License Option +# +# If you received this File from Marvell, you may opt to use, redistribute and/or +# modify this File under the following licensing terms. +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Marvell nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = MarvellComPhyLib + FILE_GUID = 3314541a-9647-4a37-b8c6-24e000900e4e + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = ComPhyLib + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + Platform/Marvell/Marvell.dec + +[LibraryClasses] + ArmLib + DebugLib + MemoryAllocationLib + PcdLib + IoLib + ParsePcdLib + +[Sources.common] + ComPhyLib.c + ComPhyCp110.c + ComPhyMux.c + +[FixedPcd] + gMarvellTokenSpaceGuid.PcdComPhyDevices + + #Chip0 + gMarvellTokenSpaceGuid.PcdChip0ComPhyTypes + gMarvellTokenSpaceGuid.PcdChip0ComPhySpeeds + gMarvellTokenSpaceGuid.PcdChip0ComPhyInvFlags + + #Chip1 + gMarvellTokenSpaceGuid.PcdChip1ComPhyTypes + gMarvellTokenSpaceGuid.PcdChip1ComPhySpeeds + gMarvellTokenSpaceGuid.PcdChip1ComPhyInvFlags + + #Chip2 + gMarvellTokenSpaceGuid.PcdChip2ComPhyTypes + gMarvellTokenSpaceGuid.PcdChip2ComPhySpeeds + gMarvellTokenSpaceGuid.PcdChip2ComPhyInvFlags + + #Chip3 + gMarvellTokenSpaceGuid.PcdChip3ComPhyTypes + gMarvellTokenSpaceGuid.PcdChip3ComPhySpeeds + gMarvellTokenSpaceGuid.PcdChip3ComPhyInvFlags + + gMarvellTokenSpaceGuid.PcdPciEAhci diff --git a/Platform/Marvell/Library/ComPhyLib/ComPhyMux.c b/Platform/Marvell/Library/ComPhyLib/ComPhyMux.c new file mode 100644 index 0000000000..6589fec9f0 --- /dev/null +++ b/Platform/Marvell/Library/ComPhyLib/ComPhyMux.c @@ -0,0 +1,132 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include "ComPhyLib.h" + +STATIC +VOID +ComPhyMuxCheckConfig ( + IN COMPHY_MUX_DATA *MuxData, + IN COMPHY_MAP *ComPhyMapData, + IN UINTN ComPhyMaxLanes + ) +{ + COMPHY_MUX_OPTIONS *PtrMuxOpt; + UINTN Lane, Opt, Valid; + + for (Lane = 0; Lane < ComPhyMaxLanes; Lane++, ComPhyMapData++, MuxData++) { + PtrMuxOpt = MuxData->MuxValues; + for (Opt = 0, Valid = 0; Opt < MuxData->MaxLaneValues; Opt++, PtrMuxOpt++) { + if (PtrMuxOpt->Type == ComPhyMapData->Type) { + Valid = 1; + break; + } + } + if (Valid == 0) { + DEBUG((DEBUG_INFO, "Lane number %d, had invalid Type %d\n", Lane, + ComPhyMapData->Type)); + DEBUG((DEBUG_INFO, "Set Lane %d as Type %d\n", Lane, + COMPHY_TYPE_UNCONNECTED)); + ComPhyMapData->Type = COMPHY_TYPE_UNCONNECTED; + } else { + DEBUG((DEBUG_INFO, "Lane number %d, has Type %d\n", Lane, + ComPhyMapData->Type)); + } + } +} + +STATIC +UINT32 +ComPhyMuxGetMuxValue ( + IN COMPHY_MUX_DATA *MuxData, + IN UINT32 Type, + IN UINTN Lane + ) +{ + COMPHY_MUX_OPTIONS *PtrMuxOpt; + UINTN Opt; + UINT32 Value = 0; + + PtrMuxOpt = MuxData->MuxValues; + for (Opt = 0 ; Opt < MuxData->MaxLaneValues; Opt++, PtrMuxOpt++) + if (PtrMuxOpt->Type == Type) { + Value = PtrMuxOpt->MuxValue; + break; + } + + return Value; +} + +STATIC +VOID +ComPhyMuxRegWrite ( + IN COMPHY_MUX_DATA *MuxData, + IN COMPHY_MAP *ComPhyMapData, + IN UINTN ComPhyMaxLanes, + IN EFI_PHYSICAL_ADDRESS SelectorBase, + IN UINT32 BitCount + ) +{ + UINT32 Lane, Value, Offset, Mask; + + for (Lane = 0; Lane < ComPhyMaxLanes; Lane++, ComPhyMapData++, MuxData++) { + Offset = Lane * BitCount; + Mask = (((1 << BitCount) - 1) << Offset); + Value = (ComPhyMuxGetMuxValue (MuxData, ComPhyMapData->Type, Lane) << + Offset); + RegSet (SelectorBase, Value, Mask); + } +} + +VOID +ComPhyMuxInit ( + IN CHIP_COMPHY_CONFIG *PtrChipCfg, + IN COMPHY_MAP *ComPhyMapData, + IN EFI_PHYSICAL_ADDRESS SelectorBase + ) +{ + COMPHY_MUX_DATA *MuxData; + UINT32 MuxBitCount; + UINT32 ComPhyMaxLanes; + + ComPhyMaxLanes = PtrChipCfg->LanesCount; + MuxData = PtrChipCfg->MuxData; + MuxBitCount = PtrChipCfg->MuxBitCount; + + /* Check if the configuration is valid */ + ComPhyMuxCheckConfig (MuxData, ComPhyMapData, ComPhyMaxLanes); + /* Init COMPHY selectors */ + ComPhyMuxRegWrite (MuxData, ComPhyMapData, ComPhyMaxLanes, SelectorBase, + MuxBitCount); +} diff --git a/Platform/Marvell/Library/MppLib/MppLib.c b/Platform/Marvell/Library/MppLib/MppLib.c new file mode 100644 index 0000000000..c09acf95fe --- /dev/null +++ b/Platform/Marvell/Library/MppLib/MppLib.c @@ -0,0 +1,216 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#define MPP_PIN_VAL(pin,func) (((func) & 0xf) << ((pin) * 4)) +#define MPP_MAX_REGS 8 +#define MPP_PINS_PER_REG 8 +#define PCD_PINS_PER_GROUP 10 + +#define SD_MMC_PHY_AP_MPP_OFFSET 0x100 +#define SD_MMC_PHY_CP0_MPP_OFFSET 0x424 +#define MPP_ON_SDPHY_ENABLE (1 << 0) + +#define MAX_CHIPS 4 + +#define GET_PCD_PTR(id,num) PcdGetPtr(PcdChip##id##MppSel##num) +#define GET_PIN_COUNT(id) PcdGet32(PcdChip##id##MppPinCount) +#define GET_BASE(id) PcdGet64(PcdChip##id##MppBaseAddress) +#define GET_REV_FLAG(id) PcdGetBool(PcdChip##id##MppReverseFlag) + +/* We get chip number */ +#define GetMppPcd(id) { \ + PinCount[id] = GET_PIN_COUNT(id); \ + MppRegPcd[id][7] = GET_PCD_PTR(id,7); \ + MppRegPcd[id][6] = GET_PCD_PTR(id,6); \ + MppRegPcd[id][5] = GET_PCD_PTR(id,5); \ + MppRegPcd[id][4] = GET_PCD_PTR(id,4); \ + MppRegPcd[id][3] = GET_PCD_PTR(id,3); \ + MppRegPcd[id][2] = GET_PCD_PTR(id,2); \ + MppRegPcd[id][1] = GET_PCD_PTR(id,1); \ + MppRegPcd[id][0] = GET_PCD_PTR(id,0); \ + BaseAddr[id] = GET_BASE(id); \ + ReverseFlag[id] = GET_REV_FLAG(id); \ +} + +STATIC +VOID +SetRegisterValue ( + UINT8 RegCount, + UINT8 **MppRegPcd, + UINTN BaseAddr, + BOOLEAN ReverseFlag + ) +{ + UINT32 i, j, CtrlVal; + INTN Sign; + + Sign = ReverseFlag ? -1 : 1; + + for (i = 0; i < RegCount; i++) { + CtrlVal = 0; + for (j = 0; j < MPP_PINS_PER_REG; j++) { + CtrlVal |= MPP_PIN_VAL(7 * (UINTN) ReverseFlag + j * Sign, + MppRegPcd[i][7 * (UINTN) ReverseFlag + j * Sign]); + } + MmioWrite32 (BaseAddr + 4 * i * Sign, CtrlVal); + } +} + +STATIC +/* Transform PCD MPP group format into hardware register format */ +UINT8 +PcdToMppRegs ( + UINTN PinCount, + UINT8 **MppRegPcd + ) +{ + UINT8 MppRegPcdTmp[MPP_MAX_REGS][MPP_PINS_PER_REG]; + UINT8 PcdGroupCount, MppRegCount; + UINTN i, j, k, l; + + if (PinCount == 0) { + return 0; + } + + PcdGroupCount = PinCount / PCD_PINS_PER_GROUP; + if ((PinCount % PCD_PINS_PER_GROUP) != 0) { + PcdGroupCount += 1; + } + + MppRegCount = PinCount / MPP_PINS_PER_REG; + if ((PinCount % MPP_PINS_PER_REG) != 0) { + MppRegCount += 1; + } + + /* Fill temporary table with data from PCD groups in HW format */ + for (i = 0; i < PcdGroupCount; i++) { + for (j = 0; j < PCD_PINS_PER_GROUP; j++) { + k = (PCD_PINS_PER_GROUP * i + j) / MPP_PINS_PER_REG; + l = (PCD_PINS_PER_GROUP * i + j) % MPP_PINS_PER_REG; + MppRegPcdTmp[k][l] = MppRegPcd[i][j]; + } + } + + /* Update input table */ + for (i = 0; i < MppRegCount; i++) { + for (j = 0; j < MPP_PINS_PER_REG; j++) { + MppRegPcd[i][j] = MppRegPcdTmp[i][j]; + } + } + + return MppRegCount; +} + +STATIC +VOID +SetSdMmcPhyMpp ( + UINTN BaseAddr, + UINT32 Index + ) +{ + UINTN Size, Offset; + UINT8 *Ptr; + UINT32 Reg; + + Size = PcdGetSize(PcdPciESdhci); + Ptr = (UINT8 *) PcdGetPtr(PcdPciESdhci); + + if (Ptr == NULL || Index >= Size) { + return; + } + + /* Check if SDHCI controller is enabled on the HW block */ + if (Ptr[Index] != 1) { + return; + } + + /* Choose adequate Offset */ + switch (Index) { + case 0: + Offset = SD_MMC_PHY_AP_MPP_OFFSET; + break; + case 1: + Offset = SD_MMC_PHY_CP0_MPP_OFFSET; + break; + default: + return; + } + + /* + * If there is SDHCI controller on platform, connect SD/MMC PHY to + * SD/MMC controller insted of using it as MPP multiplexer + */ + Reg = MmioRead32 (BaseAddr + Offset); + Reg &= ~MPP_ON_SDPHY_ENABLE; + MmioWrite32 (BaseAddr + Offset, Reg); +} + +EFI_STATUS +MppInitialize ( + ) +{ + UINTN BaseAddr[MAX_CHIPS], PinCount[MAX_CHIPS], RegCount; + BOOLEAN ReverseFlag[MAX_CHIPS]; + UINT8 *MppRegPcd[MAX_CHIPS][MPP_MAX_REGS]; + UINT32 i, ChipCount; + + ChipCount = PcdGet32 (PcdMppChipCount); + + /* Read all needed PCD for MPP configuration */ + GetMppPcd(0); + GetMppPcd(1); + GetMppPcd(2); + GetMppPcd(3); + + for (i = 0; i < MAX_CHIPS; i++) { + if (i == ChipCount) + break; + RegCount = PcdToMppRegs (PinCount[i], MppRegPcd[i]); + SetRegisterValue (RegCount, MppRegPcd[i], BaseAddr[i], ReverseFlag[i]); + + /* + * eMMC PHY IP has its own MPP configuration. + */ + SetSdMmcPhyMpp (BaseAddr[i], i); + } + + return EFI_SUCCESS; +} diff --git a/Platform/Marvell/Library/MppLib/MppLib.inf b/Platform/Marvell/Library/MppLib/MppLib.inf new file mode 100644 index 0000000000..2de9cd0747 --- /dev/null +++ b/Platform/Marvell/Library/MppLib/MppLib.inf @@ -0,0 +1,108 @@ +# +# Marvell BSD License Option +# +# If you received this File from Marvell, you may opt to use, redistribute +# and/or modify this File under the following licensing terms. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Marvell nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = MarvellMppLib + FILE_GUID = 3f19b642-4a49-4dfd-8f4a-205dd38432bb + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = MppLib + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + Platform/Marvell/Marvell.dec + +[LibraryClasses] + ArmLib + DebugLib + MemoryAllocationLib + PcdLib + IoLib + +[Sources.common] + MppLib.c + +[FixedPcd] + gMarvellTokenSpaceGuid.PcdMppChipCount + + gMarvellTokenSpaceGuid.PcdChip0MppReverseFlag + gMarvellTokenSpaceGuid.PcdChip0MppBaseAddress + gMarvellTokenSpaceGuid.PcdChip0MppPinCount + gMarvellTokenSpaceGuid.PcdChip0MppSel0 + gMarvellTokenSpaceGuid.PcdChip0MppSel1 + gMarvellTokenSpaceGuid.PcdChip0MppSel2 + gMarvellTokenSpaceGuid.PcdChip0MppSel3 + gMarvellTokenSpaceGuid.PcdChip0MppSel4 + gMarvellTokenSpaceGuid.PcdChip0MppSel5 + gMarvellTokenSpaceGuid.PcdChip0MppSel6 + gMarvellTokenSpaceGuid.PcdChip0MppSel7 + + gMarvellTokenSpaceGuid.PcdChip1MppReverseFlag + gMarvellTokenSpaceGuid.PcdChip1MppBaseAddress + gMarvellTokenSpaceGuid.PcdChip1MppPinCount + gMarvellTokenSpaceGuid.PcdChip1MppSel0 + gMarvellTokenSpaceGuid.PcdChip1MppSel1 + gMarvellTokenSpaceGuid.PcdChip1MppSel2 + gMarvellTokenSpaceGuid.PcdChip1MppSel3 + gMarvellTokenSpaceGuid.PcdChip1MppSel4 + gMarvellTokenSpaceGuid.PcdChip1MppSel5 + gMarvellTokenSpaceGuid.PcdChip1MppSel6 + gMarvellTokenSpaceGuid.PcdChip1MppSel7 + + gMarvellTokenSpaceGuid.PcdChip2MppReverseFlag + gMarvellTokenSpaceGuid.PcdChip2MppBaseAddress + gMarvellTokenSpaceGuid.PcdChip2MppPinCount + gMarvellTokenSpaceGuid.PcdChip2MppSel0 + gMarvellTokenSpaceGuid.PcdChip2MppSel1 + gMarvellTokenSpaceGuid.PcdChip2MppSel2 + gMarvellTokenSpaceGuid.PcdChip2MppSel3 + gMarvellTokenSpaceGuid.PcdChip2MppSel4 + gMarvellTokenSpaceGuid.PcdChip2MppSel5 + gMarvellTokenSpaceGuid.PcdChip2MppSel6 + gMarvellTokenSpaceGuid.PcdChip2MppSel7 + + gMarvellTokenSpaceGuid.PcdChip3MppReverseFlag + gMarvellTokenSpaceGuid.PcdChip3MppBaseAddress + gMarvellTokenSpaceGuid.PcdChip3MppPinCount + gMarvellTokenSpaceGuid.PcdChip3MppSel0 + gMarvellTokenSpaceGuid.PcdChip3MppSel1 + gMarvellTokenSpaceGuid.PcdChip3MppSel2 + gMarvellTokenSpaceGuid.PcdChip3MppSel3 + gMarvellTokenSpaceGuid.PcdChip3MppSel4 + gMarvellTokenSpaceGuid.PcdChip3MppSel5 + gMarvellTokenSpaceGuid.PcdChip3MppSel6 + gMarvellTokenSpaceGuid.PcdChip3MppSel7 + + gMarvellTokenSpaceGuid.PcdPciESdhci diff --git a/Platform/Marvell/Library/ParsePcdLib/ParsePcdLib.c b/Platform/Marvell/Library/ParsePcdLib/ParsePcdLib.c new file mode 100644 index 0000000000..9a4be8ee62 --- /dev/null +++ b/Platform/Marvell/Library/ParsePcdLib/ParsePcdLib.c @@ -0,0 +1,228 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must Retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ +#define CHAR_NULL 0x0000 + +#include +#include +#include +#include + +STATIC +CHAR16 +CharToUpper ( + IN CHAR16 Char + ) +{ + + if (Char >= L'a' && Char <= L'z') { + return (CHAR16) (Char - (L'a' - L'A')); + } + + return Char; +} + +STATIC +BOOLEAN +IsDecimalDigitChar ( + IN CHAR16 Char + ) +{ + + return (BOOLEAN) (Char >= L'0' && Char <= L'9'); +} + + +STATIC +UINTN +HexCharToUintn ( + IN CHAR16 Char + ) +{ + if (IsDecimalDigitChar (Char)) { + return Char - L'0'; + } + + return (UINTN) (10 + CharToUpper (Char) - L'A'); +} + +STATIC +BOOLEAN +IsHexDigitCharacter ( + CHAR16 Char + ) +{ + + return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && + Char <= L'F') || (Char >= L'a' && Char <= L'f')); +} + +STATIC +UINTN +HexStrToUintn ( + CHAR16 *String + ) +{ + UINTN Result = 0; + + if (String == NULL || StrSize(String) == 0) { + return (UINTN)(-1); + } + + // Ignore spaces and tabs + while ((*String == L' ') || (*String == L'\t')) { + String++; + } + + // Ignore leading zeros after spaces + while (*String == L'0') { + String++; + } + + if (CharToUpper (*String) != L'X') { + return (UINTN)(-1); + } + + // Skip 'x' + String++; + + while (IsHexDigitCharacter (*String)) { + Result <<= 4; + Result += HexCharToUintn (*String); + String++; + } + + return (UINTN) Result; +} + +STATIC +UINTN +DecimalStrToUintn ( + CHAR16 *String + ) +{ + UINTN Result = 0; + + while (IsDecimalDigitChar (*String)) { + Result = 10 * Result + (*String - L'0'); + String++; + } + + return Result; +} + +STATIC +UINTN +StrToUintn ( + CHAR16 *String + ) +{ + CHAR16 *Walker; + + // Chop off leading spaces + for (Walker = String; Walker != NULL && *Walker != CHAR_NULL && *Walker == L' '; Walker++); + + if (StrnCmp(Walker, L"0x", 2) == 0 || StrnCmp(Walker, L"0X", 2) == 0) { + return HexStrToUintn (Walker); + } else { + return DecimalStrToUintn (Walker); + } +} + +EFI_STATUS +ParsePcdString ( + IN CHAR16 *PcdString, + IN UINT8 Count, + OUT UINTN *ValueTable, + OUT CHAR16 **StrTable + ) +{ + BOOLEAN ValueFlag = FALSE; + CHAR16 *Walker; + UINTN i, Tmp = 0; + + if (ValueTable != NULL) { + ValueFlag = TRUE; + } + + // Set pointer at the end of PCD string + Walker = PcdString + StrLen (PcdString); + for (i = 0; i < Count; i++) { + while ((--Walker) >= PcdString) { + if (*Walker == L';') { + // Cut off parsed chunk from PCD string by replacing ';' with + // null-terminator + *Walker = '\0'; + if (ValueFlag) { + Tmp = StrToUintn ((Walker + 1)); + if ((UINTN)(-1) == Tmp) { + return EFI_INVALID_PARAMETER; + } + // Entry is parsed from the end to the beginning + // so fill table in the same manner + ValueTable[Count - (i + 1)] = Tmp; + } else { + StrTable[Count - (i + 1)] = Walker + 1; + } + Walker--; + break; + } + if (Walker == PcdString) { + if (ValueFlag) { + Tmp = StrToUintn ((Walker)); + if (Tmp == (UINTN)(-1)) { + return EFI_INVALID_PARAMETER; + } + } + // Last device's entry should be added to the table here. + // If not, return error + if (i != (Count - 1)) { + DEBUG((DEBUG_ERROR, "ParsePcdLib: Please set PCD value for every " + "device\n")); + return EFI_INVALID_PARAMETER; + } + // We parse from the end to the beginning + // so fill table in the same manner + if (ValueFlag) { + ValueTable[Count - (i + 1)] = Tmp; + } else { + StrTable[Count - (i + 1)] = Walker; + } + // End both loops + return EFI_SUCCESS; + } + } + } + + return EFI_SUCCESS; +} diff --git a/Platform/Marvell/Library/ParsePcdLib/ParsePcdLib.inf b/Platform/Marvell/Library/ParsePcdLib/ParsePcdLib.inf new file mode 100644 index 0000000000..b4db6210f7 --- /dev/null +++ b/Platform/Marvell/Library/ParsePcdLib/ParsePcdLib.inf @@ -0,0 +1,50 @@ +# Copyright (C) 2016 Marvell International Ltd. +# +# Marvell BSD License Option +# +# If you received this File from Marvell, you may opt to use, redistribute and/or +# modify this File under the following licensing terms. +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Marvell nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = ParsePcdLib + FILE_GUID = 698d85a0-a952-453e-b8a4-1d6ea338a38e + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = ParsePcdLib + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + ArmLib + DebugLib + +[Sources.common] + ParsePcdLib.c diff --git a/Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.c b/Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.c new file mode 100644 index 0000000000..95b5698909 --- /dev/null +++ b/Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.c @@ -0,0 +1,353 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must Retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include "UtmiPhyLib.h" + +typedef struct { + EFI_PHYSICAL_ADDRESS UtmiBaseAddr; + EFI_PHYSICAL_ADDRESS UsbCfgAddr; + EFI_PHYSICAL_ADDRESS UtmiCfgAddr; + UINT32 UtmiPhyPort; +} UTMI_PHY_DATA; + +STATIC +VOID +RegSetSilent ( + IN EFI_PHYSICAL_ADDRESS Addr, + IN UINT32 Data, + IN UINT32 Mask + ) +{ + UINT32 RegData; + + RegData = MmioRead32 (Addr); + RegData &= ~Mask; + RegData |= Data; + MmioWrite32 (Addr, RegData); +} + +STATIC +VOID +RegSet ( + IN EFI_PHYSICAL_ADDRESS Addr, + IN UINT32 Data, + IN UINT32 Mask + ) +{ + DEBUG((DEBUG_INFO, "Write to address = %10x, data = %10x (mask = %10x)-\n", + Addr, Data, Mask)); + DEBUG((DEBUG_INFO, "old value = %10x ==>\n", MmioRead32 (Addr))); + RegSetSilent (Addr, Data, Mask); + DEBUG((DEBUG_INFO, "new value %10x\n", MmioRead32 (Addr))); +} + +STATIC +VOID +UtmiPhyPowerDown ( + IN UINT32 UtmiIndex, + IN EFI_PHYSICAL_ADDRESS UtmiBaseAddr, + IN EFI_PHYSICAL_ADDRESS UsbCfgAddr, + IN EFI_PHYSICAL_ADDRESS UtmiCfgAddr, + IN UINT32 UtmiPhyPort + ) +{ + UINT32 Mask, Data; + + DEBUG((DEBUG_INFO, "UtmiPhy: stage: UTMI %d - Power down transceiver(power down Phy)\n", + UtmiIndex)); + DEBUG((DEBUG_INFO, "UtmiPhy: stage: Power down PLL, and SuspendDM\n")); + /* Power down UTMI PHY */ + RegSet (UtmiCfgAddr, 0x0 << UTMI_PHY_CFG_PU_OFFSET, UTMI_PHY_CFG_PU_MASK); + /* Config USB3 Device UTMI enable */ + Mask = UTMI_USB_CFG_DEVICE_EN_MASK; + + /* + * Prior to PHY init, configure mux for Device + * (Device can be connected to UTMI0 or to UTMI1) + */ + if (UtmiPhyPort == UTMI_PHY_TO_USB_DEVICE0) { + Data = 0x1 << UTMI_USB_CFG_DEVICE_EN_OFFSET; + /* Config USB3 Device UTMI MUX */ + Mask |= UTMI_USB_CFG_DEVICE_MUX_MASK; + Data |= UtmiIndex << UTMI_USB_CFG_DEVICE_MUX_OFFSET; + } else { + Data = 0x0 << UTMI_USB_CFG_DEVICE_EN_OFFSET; + } + + /* Set Test suspendm mode */ + Mask = UTMI_CTRL_STATUS0_SUSPENDM_MASK; + Data = 0x1 << UTMI_CTRL_STATUS0_SUSPENDM_OFFSET; + /* Enable Test UTMI select */ + Mask |= UTMI_CTRL_STATUS0_TEST_SEL_MASK; + Data |= 0x1 << UTMI_CTRL_STATUS0_TEST_SEL_OFFSET; + RegSet (UtmiBaseAddr + UTMI_CTRL_STATUS0_REG, Data, Mask); + + /* Wait for UTMI power down */ + MicroSecondDelay (1000); +} + +STATIC +VOID +UtmiPhyConfig ( + IN UINT32 UtmiIndex, + IN EFI_PHYSICAL_ADDRESS UtmiBaseAddr, + IN EFI_PHYSICAL_ADDRESS UsbCfgAddr, + IN EFI_PHYSICAL_ADDRESS UtmiCfgAddr, + IN UINT32 UtmiPhyPort + ) +{ + UINT32 Mask, Data; + + DEBUG((DEBUG_INFO, "UtmiPhy: stage: Configure UTMI PHY %d registers\n", + UtmiIndex)); + /* Reference Clock Divider Select */ + Mask = UTMI_PLL_CTRL_REFDIV_MASK; + Data = 0x5 << UTMI_PLL_CTRL_REFDIV_OFFSET; + /* Feedback Clock Divider Select - 90 for 25Mhz */ + Mask |= UTMI_PLL_CTRL_FBDIV_MASK; + Data |= 0x60 << UTMI_PLL_CTRL_FBDIV_OFFSET; + /* Select LPFR - 0x0 for 25Mhz/5=5Mhz */ + Mask |= UTMI_PLL_CTRL_SEL_LPFR_MASK; + Data |= 0x0 << UTMI_PLL_CTRL_SEL_LPFR_OFFSET; + RegSet (UtmiBaseAddr + UTMI_PLL_CTRL_REG, Data, Mask); + + /* Impedance Calibration Threshold Setting */ + RegSet (UtmiBaseAddr + UTMI_CALIB_CTRL_REG, + 0x6 << UTMI_CALIB_CTRL_IMPCAL_VTH_OFFSET, + UTMI_CALIB_CTRL_IMPCAL_VTH_MASK); + + /* Set LS TX driver strength coarse control */ + Mask = UTMI_TX_CH_CTRL_DRV_EN_LS_MASK; + Data = 0x3 << UTMI_TX_CH_CTRL_DRV_EN_LS_OFFSET; + /* Set LS TX driver fine adjustment */ + Mask |= UTMI_TX_CH_CTRL_IMP_SEL_LS_MASK; + Data |= 0x3 << UTMI_TX_CH_CTRL_IMP_SEL_LS_OFFSET; + RegSet (UtmiBaseAddr + UTMI_TX_CH_CTRL_REG, Data, Mask); + + /* Enable SQ */ + Mask = UTMI_RX_CH_CTRL0_SQ_DET_MASK; + Data = 0x0 << UTMI_RX_CH_CTRL0_SQ_DET_OFFSET; + /* Enable analog squelch detect */ + Mask |= UTMI_RX_CH_CTRL0_SQ_ANA_DTC_MASK; + Data |= 0x1 << UTMI_RX_CH_CTRL0_SQ_ANA_DTC_OFFSET; + RegSet (UtmiBaseAddr + UTMI_RX_CH_CTRL0_REG, Data, Mask); + + /* Set External squelch calibration number */ + Mask = UTMI_RX_CH_CTRL1_SQ_AMP_CAL_MASK; + Data = 0x1 << UTMI_RX_CH_CTRL1_SQ_AMP_CAL_OFFSET; + /* Enable the External squelch calibration */ + Mask |= UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_MASK; + Data |= 0x1 << UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_OFFSET; + RegSet (UtmiBaseAddr + UTMI_RX_CH_CTRL1_REG, Data, Mask); + + /* Set Control VDAT Reference Voltage - 0.325V */ + Mask = UTMI_CHGDTC_CTRL_VDAT_MASK; + Data = 0x1 << UTMI_CHGDTC_CTRL_VDAT_OFFSET; + /* Set Control VSRC Reference Voltage - 0.6V */ + Mask |= UTMI_CHGDTC_CTRL_VSRC_MASK; + Data |= 0x1 << UTMI_CHGDTC_CTRL_VSRC_OFFSET; + RegSet (UtmiBaseAddr + UTMI_CHGDTC_CTRL_REG, Data, Mask); +} + +STATIC +UINTN +UtmiPhyPowerUp ( + IN UINT32 UtmiIndex, + IN EFI_PHYSICAL_ADDRESS UtmiBaseAddr, + IN EFI_PHYSICAL_ADDRESS UsbCfgAddr, + IN EFI_PHYSICAL_ADDRESS UtmiCfgAddr, + IN UINT32 UtmiPhyPort + ) +{ + EFI_STATUS Status; + UINT32 Data; + + DEBUG((DEBUG_INFO, "UtmiPhy: stage: UTMI %d - Power up transceiver(Power up Phy)\n", + UtmiIndex)); + DEBUG((DEBUG_INFO, "UtmiPhy: stage: exit SuspendDM\n")); + /* Power up UTMI PHY */ + RegSet (UtmiCfgAddr, 0x1 << UTMI_PHY_CFG_PU_OFFSET, UTMI_PHY_CFG_PU_MASK); + /* Disable Test UTMI select */ + RegSet (UtmiBaseAddr + UTMI_CTRL_STATUS0_REG, + 0x0 << UTMI_CTRL_STATUS0_TEST_SEL_OFFSET, + UTMI_CTRL_STATUS0_TEST_SEL_MASK); + + DEBUG((DEBUG_INFO, "UtmiPhy: stage: Wait for PLL and impedance calibration done, and PLL ready\n")); + + /* Delay 10ms */ + MicroSecondDelay (10000); + + Data = MmioRead32 (UtmiBaseAddr + UTMI_CALIB_CTRL_REG); + if ((Data & UTMI_CALIB_CTRL_IMPCAL_DONE_MASK) == 0) { + DEBUG((DEBUG_ERROR, "UtmiPhy: Impedance calibration is not done\n")); + Status = EFI_D_ERROR; + } + if ((Data & UTMI_CALIB_CTRL_PLLCAL_DONE_MASK) == 0) { + DEBUG((DEBUG_ERROR, "UtmiPhy: PLL calibration is not done\n")); + Status = EFI_D_ERROR; + } + Data = MmioRead32 (UtmiBaseAddr + UTMI_PLL_CTRL_REG); + if ((Data & UTMI_PLL_CTRL_PLL_RDY_MASK) == 0) { + DEBUG((DEBUG_ERROR, "UtmiPhy: PLL is not ready\n")); + Status = EFI_D_ERROR; + } + + return Status; +} + +/* + * Cp110UtmiPhyInit initializes the UTMI PHY + * the init split in 3 parts: + * 1. Power down transceiver and PLL + * 2. UTMI PHY configure + * 3. Power up transceiver and PLL + */ +STATIC +VOID +Cp110UtmiPhyInit ( + IN UINT32 UtmiPhyCount, + IN UTMI_PHY_DATA *UtmiData + ) +{ + UINT32 i; + + for (i = 0; i < UtmiPhyCount; i++) { + UtmiPhyPowerDown(i, UtmiData[i].UtmiBaseAddr, + UtmiData[i].UsbCfgAddr, UtmiData[i].UtmiCfgAddr, + UtmiData[i].UtmiPhyPort); + } + + /* Power down PLL */ + DEBUG((DEBUG_INFO, "UtmiPhy: stage: PHY power down PLL\n")); + RegSet (UtmiData[0].UsbCfgAddr, 0x0 << UTMI_USB_CFG_PLL_OFFSET, + UTMI_USB_CFG_PLL_MASK); + + for (i = 0; i < UtmiPhyCount; i++) { + UtmiPhyConfig(i, UtmiData[i].UtmiBaseAddr, + UtmiData[i].UsbCfgAddr, UtmiData[i].UtmiCfgAddr, + UtmiData[i].UtmiPhyPort); + } + + for (i = 0; i < UtmiPhyCount; i++) { + if (EFI_ERROR(UtmiPhyPowerUp(i, UtmiData[i].UtmiBaseAddr, + UtmiData[i].UsbCfgAddr, UtmiData[i].UtmiCfgAddr, + UtmiData[i].UtmiPhyPort))) { + DEBUG((DEBUG_ERROR, "UtmiPhy: Failed to initialize UTMI PHY %d\n", i)); + continue; + } + DEBUG((DEBUG_ERROR, "UTMI PHY %d initialized to ", i)); + + if (UtmiData[i].UtmiPhyPort == UTMI_PHY_TO_USB_DEVICE0) + DEBUG((DEBUG_ERROR, "USB Device\n")); + else + DEBUG((DEBUG_ERROR, "USB Host%d\n", UtmiData[i].UtmiPhyPort)); + } + + /* Power up PLL */ + DEBUG((DEBUG_INFO, "UtmiPhy: stage: PHY power up PLL\n")); + RegSet (UtmiData[0].UsbCfgAddr, 0x1 << UTMI_USB_CFG_PLL_OFFSET, + UTMI_USB_CFG_PLL_MASK); +} + +EFI_STATUS +UtmiPhyInit ( + VOID + ) +{ + EFI_STATUS Status; + UTMI_PHY_DATA UtmiData[PcdGet32 (PcdUtmiPhyCount)]; + EFI_PHYSICAL_ADDRESS RegUtmiUnit[PcdGet32 (PcdUtmiPhyCount)]; + EFI_PHYSICAL_ADDRESS RegUsbCfg[PcdGet32 (PcdUtmiPhyCount)]; + EFI_PHYSICAL_ADDRESS RegUtmiCfg[PcdGet32 (PcdUtmiPhyCount)]; + UINTN UtmiPort[PcdGet32 (PcdUtmiPhyCount)]; + UINTN i, Count; + + Count = PcdGet32 (PcdUtmiPhyCount); + if (Count == 0) { + /* No UTMI PHY on platform */ + return EFI_SUCCESS; + } + + DEBUG((DEBUG_INFO, "UtmiPhy: Initialize USB UTMI PHYs\n")); + /* Parse UtmiPhy PCDs */ + Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdUtmiPhyRegUtmiUnit), + Count, RegUtmiUnit, NULL); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "UtmiPhy: Wrong PcdUtmiPhyRegUtmiUnit format\n")); + return EFI_INVALID_PARAMETER; + } + + Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdUtmiPhyRegUsbCfg), + Count, RegUsbCfg, NULL); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "UtmiPhy: Wrong PcdUtmiPhyRegUsbCfg format\n")); + return EFI_INVALID_PARAMETER; + } + + Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdUtmiPhyRegUtmiCfg), + Count, RegUtmiCfg, NULL); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "UtmiPhy: Wrong PcdUtmiPhyRegUtmiCfg format\n")); + return EFI_INVALID_PARAMETER; + } + + Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdUtmiPhyUtmiPort), + Count, UtmiPort, NULL); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "UtmiPhy: Wrong PcdUtmiPhyUtmiPort format\n")); + return EFI_INVALID_PARAMETER; + } + + for (i = 0 ; i < Count ; i++) { + /* Get base address of UTMI phy */ + UtmiData[i].UtmiBaseAddr = RegUtmiUnit[i]; + + /* Get usb config address */ + UtmiData[i].UsbCfgAddr = RegUsbCfg[i]; + + /* Get UTMI config address */ + UtmiData[i].UtmiCfgAddr = RegUtmiCfg[i]; + + /* + * Get the usb port number, which will be used to check if + * the utmi connected to host or device + */ + UtmiData[i].UtmiPhyPort = UtmiPort[i]; + } + + /* Currently only Cp110 is supported */ + Cp110UtmiPhyInit (Count, UtmiData); + + return EFI_SUCCESS; +} diff --git a/Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.h b/Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.h new file mode 100644 index 0000000000..f9b49339d0 --- /dev/null +++ b/Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.h @@ -0,0 +1,110 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __UTMIPHY_H__ +#define __UTMIPHY_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define UTMI_USB_CFG_DEVICE_EN_OFFSET 0 +#define UTMI_USB_CFG_DEVICE_EN_MASK (0x1 << UTMI_USB_CFG_DEVICE_EN_OFFSET) +#define UTMI_USB_CFG_DEVICE_MUX_OFFSET 1 +#define UTMI_USB_CFG_DEVICE_MUX_MASK (0x1 << UTMI_USB_CFG_DEVICE_MUX_OFFSET) +#define UTMI_USB_CFG_PLL_OFFSET 25 +#define UTMI_USB_CFG_PLL_MASK (0x1 << UTMI_USB_CFG_PLL_OFFSET) + +#define UTMI_PHY_CFG_PU_OFFSET 5 +#define UTMI_PHY_CFG_PU_MASK (0x1 << UTMI_PHY_CFG_PU_OFFSET) + +#define UTMI_PLL_CTRL_REG 0x0 +#define UTMI_PLL_CTRL_REFDIV_OFFSET 0 +#define UTMI_PLL_CTRL_REFDIV_MASK (0x7f << UTMI_PLL_CTRL_REFDIV_OFFSET) +#define UTMI_PLL_CTRL_FBDIV_OFFSET 16 +#define UTMI_PLL_CTRL_FBDIV_MASK (0x1FF << UTMI_PLL_CTRL_FBDIV_OFFSET) +#define UTMI_PLL_CTRL_SEL_LPFR_OFFSET 28 +#define UTMI_PLL_CTRL_SEL_LPFR_MASK (0x3 << UTMI_PLL_CTRL_SEL_LPFR_OFFSET) +#define UTMI_PLL_CTRL_PLL_RDY_OFFSET 31 +#define UTMI_PLL_CTRL_PLL_RDY_MASK (0x1 << UTMI_PLL_CTRL_PLL_RDY_OFFSET) + +#define UTMI_CALIB_CTRL_REG 0x8 +#define UTMI_CALIB_CTRL_IMPCAL_VTH_OFFSET 8 +#define UTMI_CALIB_CTRL_IMPCAL_VTH_MASK (0x7 << UTMI_CALIB_CTRL_IMPCAL_VTH_OFFSET) +#define UTMI_CALIB_CTRL_IMPCAL_DONE_OFFSET 23 +#define UTMI_CALIB_CTRL_IMPCAL_DONE_MASK (0x1 << UTMI_CALIB_CTRL_IMPCAL_DONE_OFFSET) +#define UTMI_CALIB_CTRL_PLLCAL_DONE_OFFSET 31 +#define UTMI_CALIB_CTRL_PLLCAL_DONE_MASK (0x1 << UTMI_CALIB_CTRL_PLLCAL_DONE_OFFSET) + +#define UTMI_TX_CH_CTRL_REG 0xC +#define UTMI_TX_CH_CTRL_DRV_EN_LS_OFFSET 12 +#define UTMI_TX_CH_CTRL_DRV_EN_LS_MASK (0xf << UTMI_TX_CH_CTRL_DRV_EN_LS_OFFSET) +#define UTMI_TX_CH_CTRL_IMP_SEL_LS_OFFSET 16 +#define UTMI_TX_CH_CTRL_IMP_SEL_LS_MASK (0xf << UTMI_TX_CH_CTRL_IMP_SEL_LS_OFFSET) + +#define UTMI_RX_CH_CTRL0_REG 0x14 +#define UTMI_RX_CH_CTRL0_SQ_DET_OFFSET 15 +#define UTMI_RX_CH_CTRL0_SQ_DET_MASK (0x1 << UTMI_RX_CH_CTRL0_SQ_DET_OFFSET) +#define UTMI_RX_CH_CTRL0_SQ_ANA_DTC_OFFSET 28 +#define UTMI_RX_CH_CTRL0_SQ_ANA_DTC_MASK (0x1 << UTMI_RX_CH_CTRL0_SQ_ANA_DTC_OFFSET) + +#define UTMI_RX_CH_CTRL1_REG 0x18 +#define UTMI_RX_CH_CTRL1_SQ_AMP_CAL_OFFSET 0 +#define UTMI_RX_CH_CTRL1_SQ_AMP_CAL_MASK (0x3 << UTMI_RX_CH_CTRL1_SQ_AMP_CAL_OFFSET) +#define UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_OFFSET 3 +#define UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_MASK (0x1 << UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_OFFSET) + +#define UTMI_CTRL_STATUS0_REG 0x24 +#define UTMI_CTRL_STATUS0_SUSPENDM_OFFSET 22 +#define UTMI_CTRL_STATUS0_SUSPENDM_MASK (0x1 << UTMI_CTRL_STATUS0_SUSPENDM_OFFSET) +#define UTMI_CTRL_STATUS0_TEST_SEL_OFFSET 25 +#define UTMI_CTRL_STATUS0_TEST_SEL_MASK (0x1 << UTMI_CTRL_STATUS0_TEST_SEL_OFFSET) + +#define UTMI_CHGDTC_CTRL_REG 0x38 +#define UTMI_CHGDTC_CTRL_VDAT_OFFSET 8 +#define UTMI_CHGDTC_CTRL_VDAT_MASK (0x3 << UTMI_CHGDTC_CTRL_VDAT_OFFSET) +#define UTMI_CHGDTC_CTRL_VSRC_OFFSET 10 +#define UTMI_CHGDTC_CTRL_VSRC_MASK (0x3 << UTMI_CHGDTC_CTRL_VSRC_OFFSET) + +#define UTMI_PHY_TO_USB_HOST0 0 +#define UTMI_PHY_TO_USB_HOST1 1 +#define UTMI_PHY_TO_USB_DEVICE0 2 +#define UTMI_PHY_INVALID 0xff + +#endif diff --git a/Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.inf b/Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.inf new file mode 100644 index 0000000000..f1e57f46f9 --- /dev/null +++ b/Platform/Marvell/Library/UtmiPhyLib/UtmiPhyLib.inf @@ -0,0 +1,64 @@ +# Copyright (C) 2016 Marvell International Ltd. +# +# Marvell BSD License Option +# +# If you received this File from Marvell, you may opt to use, redistribute and/or +# modify this File under the following licensing terms. +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Marvell nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = MarvellUtmiPhyLib + FILE_GUID = e9adaac2-0443-4921-9367-5d575c3c91bc + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = UtmiPhyLib + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Platform/Marvell/Marvell.dec + +[LibraryClasses] + ArmLib + DebugLib + IoLib + MemoryAllocationLib + ParsePcdLib + PcdLib + +[Sources.common] + UtmiPhyLib.c + +[FixedPcd] + gMarvellTokenSpaceGuid.PcdUtmiPhyCount + gMarvellTokenSpaceGuid.PcdUtmiPhyRegUsbCfg + gMarvellTokenSpaceGuid.PcdUtmiPhyRegUtmiCfg + gMarvellTokenSpaceGuid.PcdUtmiPhyRegUtmiUnit + gMarvellTokenSpaceGuid.PcdUtmiPhyUtmiPort diff --git a/Platform/Marvell/Marvell.dec b/Platform/Marvell/Marvell.dec new file mode 100644 index 0000000000..5cbf0c389f --- /dev/null +++ b/Platform/Marvell/Marvell.dec @@ -0,0 +1,204 @@ +# Copyright (C) 2016 Marvell International Ltd. +# +# Marvell BSD License Option +# +# If you received this File from Marvell, you may opt to use, redistribute and/or +# modify this File under the following licensing terms. +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +#* Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +#* Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +#* Neither the name of Marvell nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +[Defines] + DEC_SPECIFICATION = 0x00010005 + PACKAGE_NAME = OpenPlatformMarvellPkg + PACKAGE_GUID = c372916e-83ad-4b2a-8410-bbc31bd9e68f + PACKAGE_VERSION = 0.1 + +################################################################################ +# +# Include Section - list of Include Paths that are provided by this package. +# Comments are used for Keywords and Module Types. +# +# Supported Module Types: +# BASE SEC PEI_CORE PEIM DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_SAL_DRIVER UEFI_DRIVER UEFI_APPLICATION +# +################################################################################ + +[Includes] + Include + +[Guids.common] + gMarvellTokenSpaceGuid = { 0xf995c6c8, 0xbc9b, 0x4e93, { 0xbd, 0xcf, 0x49, 0x90, 0xc6, 0xe7, 0x8c, 0x7f } } + + gShellEepromHiiGuid = { 0xb2f4c714, 0x147f, 0x4ff7, { 0x82, 0x1b, 0xce, 0x7b, 0x91, 0x7f, 0x5f, 0x2f } } + gShellFUpdateHiiGuid = { 0x9b5d2176, 0x590a, 0x49db, { 0x89, 0x5d, 0x4a, 0x70, 0xfe, 0xad, 0xbe, 0x24 } } + gShellSfHiiGuid = { 0x03a67756, 0x8cde, 0x4638, { 0x82, 0x34, 0x4a, 0x0f, 0x6d, 0x58, 0x81, 0x39 } } + +[PcdsFixedAtBuild.common] +#MPP + gMarvellTokenSpaceGuid.PcdMppChipCount|0|UINT32|0x30000001 + + gMarvellTokenSpaceGuid.PcdChip0MppReverseFlag|FALSE|BOOLEAN|0x30000002 + gMarvellTokenSpaceGuid.PcdChip0MppBaseAddress|0|UINT64|0x30000003 + gMarvellTokenSpaceGuid.PcdChip0MppPinCount|0|UINT32|0x30000004 + gMarvellTokenSpaceGuid.PcdChip0MppSel0|{ 0x0 }|VOID*|0x30000005 + gMarvellTokenSpaceGuid.PcdChip0MppSel1|{ 0x0 }|VOID*|0x30000006 + gMarvellTokenSpaceGuid.PcdChip0MppSel2|{ 0x0 }|VOID*|0x30000007 + gMarvellTokenSpaceGuid.PcdChip0MppSel3|{ 0x0 }|VOID*|0x30000008 + gMarvellTokenSpaceGuid.PcdChip0MppSel4|{ 0x0 }|VOID*|0x30000009 + gMarvellTokenSpaceGuid.PcdChip0MppSel5|{ 0x0 }|VOID*|0x30000010 + gMarvellTokenSpaceGuid.PcdChip0MppSel6|{ 0x0 }|VOID*|0x30000011 + gMarvellTokenSpaceGuid.PcdChip0MppSel7|{ 0x0 }|VOID*|0x30000012 + + gMarvellTokenSpaceGuid.PcdChip1MppReverseFlag|FALSE|BOOLEAN|0x30000013 + gMarvellTokenSpaceGuid.PcdChip1MppBaseAddress|0|UINT64|0x30000014 + gMarvellTokenSpaceGuid.PcdChip1MppPinCount|0|UINT32|0x30000015 + gMarvellTokenSpaceGuid.PcdChip1MppSel0|{ 0x0 }|VOID*|0x30000016 + gMarvellTokenSpaceGuid.PcdChip1MppSel1|{ 0x0 }|VOID*|0x30000017 + gMarvellTokenSpaceGuid.PcdChip1MppSel2|{ 0x0 }|VOID*|0x30000018 + gMarvellTokenSpaceGuid.PcdChip1MppSel3|{ 0x0 }|VOID*|0x30000019 + gMarvellTokenSpaceGuid.PcdChip1MppSel4|{ 0x0 }|VOID*|0x30000020 + gMarvellTokenSpaceGuid.PcdChip1MppSel5|{ 0x0 }|VOID*|0x30000021 + gMarvellTokenSpaceGuid.PcdChip1MppSel6|{ 0x0 }|VOID*|0x30000022 + gMarvellTokenSpaceGuid.PcdChip1MppSel7|{ 0x0 }|VOID*|0x30000023 + + gMarvellTokenSpaceGuid.PcdChip2MppReverseFlag|FALSE|BOOLEAN|0x30000024 + gMarvellTokenSpaceGuid.PcdChip2MppBaseAddress|0|UINT64|0x30000025 + gMarvellTokenSpaceGuid.PcdChip2MppPinCount|0|UINT32|0x30000026 + gMarvellTokenSpaceGuid.PcdChip2MppSel0|{ 0x0 }|VOID*|0x30000027 + gMarvellTokenSpaceGuid.PcdChip2MppSel1|{ 0x0 }|VOID*|0x30000028 + gMarvellTokenSpaceGuid.PcdChip2MppSel2|{ 0x0 }|VOID*|0x30000029 + gMarvellTokenSpaceGuid.PcdChip2MppSel3|{ 0x0 }|VOID*|0x30000030 + gMarvellTokenSpaceGuid.PcdChip2MppSel4|{ 0x0 }|VOID*|0x30000031 + gMarvellTokenSpaceGuid.PcdChip2MppSel5|{ 0x0 }|VOID*|0x30000032 + gMarvellTokenSpaceGuid.PcdChip2MppSel6|{ 0x0 }|VOID*|0x30000033 + gMarvellTokenSpaceGuid.PcdChip2MppSel7|{ 0x0 }|VOID*|0x30000034 + + gMarvellTokenSpaceGuid.PcdChip3MppReverseFlag|FALSE|BOOLEAN|0x30000035 + gMarvellTokenSpaceGuid.PcdChip3MppBaseAddress|0|UINT64|0x30000036 + gMarvellTokenSpaceGuid.PcdChip3MppPinCount|0|UINT32|0x30000037 + gMarvellTokenSpaceGuid.PcdChip3MppSel0|{ 0x0 }|VOID*|0x30000038 + gMarvellTokenSpaceGuid.PcdChip3MppSel1|{ 0x0 }|VOID*|0x30000039 + gMarvellTokenSpaceGuid.PcdChip3MppSel2|{ 0x0 }|VOID*|0x30000040 + gMarvellTokenSpaceGuid.PcdChip3MppSel3|{ 0x0 }|VOID*|0x30000041 + gMarvellTokenSpaceGuid.PcdChip3MppSel4|{ 0x0 }|VOID*|0x30000042 + gMarvellTokenSpaceGuid.PcdChip3MppSel5|{ 0x0 }|VOID*|0x30000043 + gMarvellTokenSpaceGuid.PcdChip3MppSel6|{ 0x0 }|VOID*|0x30000044 + gMarvellTokenSpaceGuid.PcdChip3MppSel7|{ 0x0 }|VOID*|0x30000045 + +#I2C + gMarvellTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x0 }|VOID*|0x3000046 + gMarvellTokenSpaceGuid.PcdI2cSlaveBuses|{ 0x0 }|VOID*|0x3000184 + gMarvellTokenSpaceGuid.PcdEepromI2cAddresses|{ 0x0 }|VOID*|0x3000050 + gMarvellTokenSpaceGuid.PcdEepromI2cBuses|{ 0x0 }|VOID*|0x3000185 + gMarvellTokenSpaceGuid.PcdI2cBaseAddresses|{ 0x0 }|VOID*|0x3000047 + gMarvellTokenSpaceGuid.PcdI2cClockFrequency|0|UINT32|0x3000048 + gMarvellTokenSpaceGuid.PcdI2cBaudRate|0|UINT32|0x3000049 + gMarvellTokenSpaceGuid.PcdI2cBusCount|0|UINT32|0x3000183 + +#SPI + gMarvellTokenSpaceGuid.PcdSpiRegBase|0|UINT32|0x3000051 + gMarvellTokenSpaceGuid.PcdSpiMaxFrequency|0|UINT32|0x30000052 + gMarvellTokenSpaceGuid.PcdSpiClockFrequency|0|UINT32|0x30000053 + + gMarvellTokenSpaceGuid.PcdSpiFlashPollCmd|0|UINT32|0x3000052 + gMarvellTokenSpaceGuid.PcdSpiFlashAddressCycles|0|UINT32|0x3000053 + gMarvellTokenSpaceGuid.PcdSpiFlashEraseSize|0|UINT64|0x3000054 + gMarvellTokenSpaceGuid.PcdSpiFlashPageSize|0|UINT32|0x3000055 + gMarvellTokenSpaceGuid.PcdSpiFlashId|0|UINT32|0x3000056 + +#ComPhy + gMarvellTokenSpaceGuid.PcdComPhyDevices|{ 0x0 }|VOID*|0x30000098 + + #Chip0 + gMarvellTokenSpaceGuid.PcdChip0ComPhyTypes|{ 0x0 }|VOID*|0x30000068 + gMarvellTokenSpaceGuid.PcdChip0ComPhySpeeds|{ 0x0 }|VOID*|0x30000069 + gMarvellTokenSpaceGuid.PcdChip0ComPhyInvFlags|{ 0x0 }|VOID*|0x30000070 + + #Chip1 + gMarvellTokenSpaceGuid.PcdChip1ComPhyTypes|{ 0x0 }|VOID*|0x30000105 + gMarvellTokenSpaceGuid.PcdChip1ComPhySpeeds|{ 0x0 }|VOID*|0x30000106 + gMarvellTokenSpaceGuid.PcdChip1ComPhyInvFlags|{ 0x0 }|VOID*|0x30000107 + + #Chip2 + gMarvellTokenSpaceGuid.PcdChip2ComPhyTypes|{ 0x0 }|VOID*|0x30000140 + gMarvellTokenSpaceGuid.PcdChip2ComPhySpeeds|{ 0x0 }|VOID*|0x30000141 + gMarvellTokenSpaceGuid.PcdChip2ComPhyInvFlags|{ 0x0 }|VOID*|0x30000142 + + #Chip3 + gMarvellTokenSpaceGuid.PcdChip3ComPhyTypes|{ 0x0 }|VOID*|0x30000175 + gMarvellTokenSpaceGuid.PcdChip3ComPhySpeeds|{ 0x0 }|VOID*|0x30000176 + gMarvellTokenSpaceGuid.PcdChip3ComPhyInvFlags|{ 0x0 }|VOID*|0x30000177 + +#UtmiPhy + gMarvellTokenSpaceGuid.PcdUtmiPhyCount|0|UINT32|0x30000205 + gMarvellTokenSpaceGuid.PcdUtmiPhyRegUsbCfg|{ 0x0 }|VOID*|0x30000206 + gMarvellTokenSpaceGuid.PcdUtmiPhyRegUtmiCfg|{ 0x0 }|VOID*|0x30000207 + gMarvellTokenSpaceGuid.PcdUtmiPhyRegUtmiUnit|{ 0x0 }|VOID*|0x30000208 + gMarvellTokenSpaceGuid.PcdUtmiPhyUtmiPort|{ 0x0 }|VOID*|0x30000209 + +#MDIO + gMarvellTokenSpaceGuid.PcdMdioBaseAddress|0|UINT64|0x3000043 + +#PHY + gMarvellTokenSpaceGuid.PcdPhyConnectionTypes|{ 0x0 }|VOID*|0x3000044 + gMarvellTokenSpaceGuid.PcdPhyDeviceIds|{ 0x0 }|VOID*|0x3000095 + gMarvellTokenSpaceGuid.PcdPhyStartupAutoneg|FALSE|BOOLEAN|0x3000070 + +#NET + gMarvellTokenSpaceGuid.PcdPhySmiAddresses|{ 0x0 }|VOID*|0x3000024 + gMarvellTokenSpaceGuid.PcdPp2ClockFrequency|0|UINT32|0x3000026 + gMarvellTokenSpaceGuid.PcdPp2GmacBaseAddress|0|UINT64|0x3000027 + gMarvellTokenSpaceGuid.PcdPp2GmacDevSize|0|UINT32|0x3000028 + gMarvellTokenSpaceGuid.PcdPp2GopIndexes|{ 0x0 }|VOID*|0x3000029 + gMarvellTokenSpaceGuid.PcdPp2InterfaceAlwaysUp|{ 0x0 }|VOID*|0x300002A + gMarvellTokenSpaceGuid.PcdPp2InterfaceSpeed|{ 0x0 }|VOID*|0x300002B + gMarvellTokenSpaceGuid.PcdPp2NumPorts|0|UINT32|0x300002D + gMarvellTokenSpaceGuid.PcdPp2PortIds|{ 0x0 }|VOID*|0x300002C + gMarvellTokenSpaceGuid.PcdPp2Rfu1BaseAddress|0|UINT64|0x300002E + gMarvellTokenSpaceGuid.PcdPp2SharedAddress|0|UINT64|0x300002F + gMarvellTokenSpaceGuid.PcdPp2SmiBaseAddress|0|UINT64|0x3000030 + gMarvellTokenSpaceGuid.PcdPp2XlgBaseAddress|0|UINT64|0x3000031 + gMarvellTokenSpaceGuid.PcdPp2XlgDevSize|0|UINT32|0x3000032 + +#PciEmulation + gMarvellTokenSpaceGuid.PcdPciEXhci|{ 0x0 }|VOID*|0x3000033 + gMarvellTokenSpaceGuid.PcdPciEAhci|{ 0x0 }|VOID*|0x3000034 + gMarvellTokenSpaceGuid.PcdPciESdhci|{ 0x0 }|VOID*|0x3000035 + +#ResetLib + gMarvellTokenSpaceGuid.PcdResetRegAddress|0|UINT64|0x40000050 + gMarvellTokenSpaceGuid.PcdResetRegMask|0|UINT32|0x4000051 + +#RTC + gMarvellTokenSpaceGuid.PcdRtcEnabled|{ 0x0 }|VOID*|0x40000052 + +[Protocols] + gMarvellEepromProtocolGuid = { 0x71954bda, 0x60d3, 0x4ef8, { 0x8e, 0x3c, 0x0e, 0x33, 0x9f, 0x3b, 0xc2, 0x2b }} + gMarvellMdioProtocolGuid = { 0x40010b03, 0x5f08, 0x496a, { 0xa2, 0x64, 0x10, 0x5e, 0x72, 0xd3, 0x71, 0xaa }} + gMarvellPhyProtocolGuid = { 0x32f48a43, 0x37e3, 0x4acf, { 0x93, 0xc4, 0x3e, 0x57, 0xa7, 0xb0, 0xfb, 0xdc }} + gMarvellSpiMasterProtocolGuid = { 0x23de66a3, 0xf666, 0x4b3e, { 0xaa, 0xa2, 0x68, 0x9b, 0x18, 0xae, 0x2e, 0x19 }} + gMarvellSpiFlashProtocolGuid = { 0x9accb423, 0x5bd2, 0x4fca, { 0x9b, 0x4c, 0x2e, 0x65, 0xfc, 0x25, 0xdf, 0x21 }} + diff --git a/Platform/Marvell/PciEmulation/PciEmulation.c b/Platform/Marvell/PciEmulation/PciEmulation.c new file mode 100644 index 0000000000..35f1a87d81 --- /dev/null +++ b/Platform/Marvell/PciEmulation/PciEmulation.c @@ -0,0 +1,195 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include + +#include +#include +#include +#include + +#include + +DECLARE_A7K8K_NONDISCOVERABLE_TEMPLATE; + +// +// Tables with used devices +// +STATIC UINT8 * CONST XhciDeviceTable = FixedPcdGetPtr (PcdPciEXhci); +STATIC UINT8 * CONST AhciDeviceTable = FixedPcdGetPtr (PcdPciEAhci); +STATIC UINT8 * CONST SdhciDeviceTable = FixedPcdGetPtr (PcdPciESdhci); + +// +// NonDiscoverable devices registration +// +STATIC +EFI_STATUS +PciEmulationInitXhci ( + ) +{ + MVHW_NONDISCOVERABLE_DESC *Desc = &mA7k8kNonDiscoverableDescTemplate; + EFI_STATUS Status; + UINT8 i; + + if (PcdGetSize (PcdPciEXhci) < Desc->XhciDevCount) { + DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEXhci format\n")); + return EFI_INVALID_PARAMETER; + } + + for (i = 0; i < Desc->XhciDevCount; i++) { + if (!MVHW_DEV_ENABLED (Xhci, i)) { + continue; + } + + Status = RegisterNonDiscoverableMmioDevice ( + NonDiscoverableDeviceTypeXhci, + Desc->XhciDmaType[i], + NULL, + NULL, + 1, + Desc->XhciBaseAddresses[i], Desc->XhciMemSize[i] + ); + + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "PciEmulation: Cannot install Xhci device %d\n", i)); + return Status; + } + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +PciEmulationInitAhci ( + ) +{ + MVHW_NONDISCOVERABLE_DESC *Desc = &mA7k8kNonDiscoverableDescTemplate; + EFI_STATUS Status; + UINT8 i; + + if (PcdGetSize (PcdPciEAhci) < Desc->AhciDevCount) { + DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEAhci format\n")); + return EFI_INVALID_PARAMETER; + } + + for (i = 0; i < Desc->AhciDevCount; i++) { + if (!MVHW_DEV_ENABLED (Ahci, i)) { + continue; + } + + Status = RegisterNonDiscoverableMmioDevice ( + NonDiscoverableDeviceTypeAhci, + Desc->AhciDmaType[i], + NULL, + NULL, + 1, + Desc->AhciBaseAddresses[i], Desc->AhciMemSize[i] + ); + + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "PciEmulation: Cannot install Ahci device %d\n", i)); + return Status; + } + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +PciEmulationInitSdhci ( + ) +{ + MVHW_NONDISCOVERABLE_DESC *Desc = &mA7k8kNonDiscoverableDescTemplate; + EFI_STATUS Status; + UINT8 i; + + if (PcdGetSize (PcdPciESdhci) < Desc->SdhciDevCount) { + DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciESdhci format\n")); + return EFI_INVALID_PARAMETER; + } + + for (i = 0; i < Desc->SdhciDevCount; i++) { + if (!MVHW_DEV_ENABLED (Sdhci, i)) { + continue; + } + + Status = RegisterNonDiscoverableMmioDevice ( + NonDiscoverableDeviceTypeSdhci, + Desc->SdhciDmaType[i], + NULL, + NULL, + 1, + Desc->SdhciBaseAddresses[i], Desc->SdhciMemSize[i] + ); + + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "PciEmulation: Cannot install Sdhci device %d\n", i)); + return Status; + } + } + + return EFI_SUCCESS; +} + +// +// Entry point +// +EFI_STATUS +EFIAPI +PciEmulationEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = PciEmulationInitXhci(); + if (EFI_ERROR(Status)) { + return Status; + } + + Status = PciEmulationInitAhci(); + if (EFI_ERROR(Status)) { + return Status; + } + + Status = PciEmulationInitSdhci(); + if (EFI_ERROR(Status)) { + return Status; + } + + return EFI_SUCCESS; +} diff --git a/Platform/Marvell/PciEmulation/PciEmulation.inf b/Platform/Marvell/PciEmulation/PciEmulation.inf new file mode 100644 index 0000000000..45490ebe4c --- /dev/null +++ b/Platform/Marvell/PciEmulation/PciEmulation.inf @@ -0,0 +1,61 @@ +# Copyright (C) 2016 Marvell International Ltd. +# +# Marvell BSD License Option +# +# If you received this File from Marvell, you may opt to use, redistribute and/or +# modify this File under the following licensing terms. +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Marvell nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = PciEmulation + FILE_GUID = 3dfa08da-923b-4841-9435-c77a604d7493 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = PciEmulationEntryPoint + +[Sources.common] + PciEmulation.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Platform/Marvell/Marvell.dec + +[LibraryClasses] + NonDiscoverableDeviceRegistrationLib + UefiDriverEntryPoint + +[Pcd] + gMarvellTokenSpaceGuid.PcdPciEXhci + gMarvellTokenSpaceGuid.PcdPciEAhci + gMarvellTokenSpaceGuid.PcdPciESdhci + +[Depex] + TRUE -- cgit v1.2.3