Hello,
Since v4 of basic support is on its way to the lists and it may take some time to get it merged, we decided to send RFC version of remaining drivers and libraries. It is divided into two parts - high speed and network. The purpose of sending those patchsets now is to give an opportunity to discuss if general directions (like protocols, pcie emulation driver, etc.) are acceptable. This way, once the basic support gets accepted, it would be possible to submit more mature version beginning from the v1.
This patchset can be analyzed in three blocks: * Small libraries like ResetSystemLib, IcuLib and ParsePcdLib. The latter one enables flexible parsing of data stored in PCD's in a string format, due to limitations for multi-byte numbers' arrays. It is used by PcieEmulation, ComPhy and Utmi, which have all a significant amount of entries. Thanks to strings their number could be reduced, which simplifies PCD description and processing in drivers/libraries.
* PcieEmulation driver as a base for support of XHCI, AHCI and SD/MMC
* Libraries that support SerDes PHY's settings and lanes' multiplexing (ComPhyLib) as well as USB2.0 PHY's configuration (UtmiLib)
Any comments or remarks would be welcome.
Best regards, Marcin
Bartosz Szczepanek (2): Platforms/Marvell: Add ResetSystemLib Platforms/Marvell: Enable MarvellResetSystemLib
Jan Dąbroś (19): Platforms/Marvell: Create Armada7040IcuLib Platforms/Marvell: Add IcuInit call for Armada7040 platforms Platforms/Marvell: Create ParsePcdLib Platforms/Marvell: Enable ParsePcdLib for Armada7040 boards Platforms/Marvell: Add PciEmulation driver Platforms/Marvell: Enable PciEmulation driver for Armada7040 platforms Platforms/Marvell: Enable USB stack for Armada7040 platforms Platforms/Marvell: Enable two xHCI ports for Armada7040_rz board Platforms/Marvell: Add support for SATA devices in PciEmulation Platforms/Marvell: Enable SATA stack for Armada7040_rz platform Platforms/Marvell: Enable SATA port for Armada7040_rz board Drivers/Sd: Add MvSdMmcPciHcDxe driver Platforms/Marvell: Add support for SD/MMC devices in PciEmulation Platforms/Marvell: Enable SD/MMC stack for Armada7040 platforms Platforms/Marvell: Enable SD/MMC controller for Armada70x0 board Platforms/Marvell: Create ComPhyLib Platforms/Marvell: Enable ComPhy Lib for Armada7040 platforms Platforms/Marvell: Add UtmiPhyLib Platforms/Marvell: Enable UtmiPhyLib for Armada7040 Platforms
Documentation/Marvell/PortingGuide/ComPhy.txt | 77 ++ Documentation/Marvell/PortingGuide/IcuLib.txt | 15 + .../Marvell/PortingGuide/PciEmulation.txt | 53 + Documentation/Marvell/PortingGuide/Reset.txt | 7 + Documentation/Marvell/PortingGuide/Sata.txt | 16 + Documentation/Marvell/PortingGuide/Utmi.txt | 35 + Documentation/Marvell/UserGuide.txt | 7 + Drivers/Sd/MvSdMmcPciHcDxe.c | 1268 ++++++++++++++++++++ Drivers/Sd/MvSdMmcPciHcDxe.inf | 75 ++ Drivers/Sd/XenonSdhci.c | 424 +++++++ Drivers/Sd/XenonSdhci.h | 301 +++++ Platforms/Marvell/Armada/Apn806.dsc | 12 + Platforms/Marvell/Armada/Armada.dsc.inc | 27 +- Platforms/Marvell/Armada/Armada7040.fdf | 22 +- Platforms/Marvell/Armada/Armada7040_rz.dsc | 44 + Platforms/Marvell/Armada/Armada70x0.dsc | 14 +- .../Library/Armada7040Lib/Armada7040IcuLib.c | 253 ++++ .../Library/Armada7040Lib/Armada7040IcuLib.h | 83 ++ .../Armada/Library/Armada7040Lib/Armada7040Lib.c | 9 +- .../Armada/Library/Armada7040Lib/Armada7040Lib.inf | 7 + .../MarvellResetSystemLib/MarvellResetSystemLib.c | 85 ++ .../MarvellResetSystemLib.inf | 56 + Platforms/Marvell/Include/Library/ComPhyLib.h | 43 + Platforms/Marvell/Include/Library/ParsePcdLib.h | 46 + Platforms/Marvell/Include/Library/UtmiPhyLib.h | 43 + Platforms/Marvell/Library/ComPhyLib/ComPhyAp806.c | 290 +++++ Platforms/Marvell/Library/ComPhyLib/ComPhyCp110.c | 811 +++++++++++++ Platforms/Marvell/Library/ComPhyLib/ComPhyLib.c | 277 +++++ Platforms/Marvell/Library/ComPhyLib/ComPhyLib.h | 457 +++++++ Platforms/Marvell/Library/ComPhyLib/ComPhyLib.inf | 110 ++ Platforms/Marvell/Library/ComPhyLib/ComPhyMux.c | 132 ++ .../Marvell/Library/ParsePcdLib/ParsePcdLib.c | 228 ++++ .../Marvell/Library/ParsePcdLib/ParsePcdLib.inf | 50 + Platforms/Marvell/Library/UtmiPhyLib/UtmiPhyLib.c | 352 ++++++ Platforms/Marvell/Library/UtmiPhyLib/UtmiPhyLib.h | 110 ++ .../Marvell/Library/UtmiPhyLib/UtmiPhyLib.inf | 64 + Platforms/Marvell/Marvell.dec | 75 ++ Platforms/Marvell/PciEmulation/PciEmulation.c | 704 +++++++++++ Platforms/Marvell/PciEmulation/PciEmulation.h | 283 +++++ Platforms/Marvell/PciEmulation/PciEmulation.inf | 67 ++ Platforms/Marvell/PciEmulation/PciRootBridgeIo.c | 300 +++++ 41 files changed, 7320 insertions(+), 12 deletions(-) create mode 100644 Documentation/Marvell/PortingGuide/ComPhy.txt create mode 100644 Documentation/Marvell/PortingGuide/IcuLib.txt create mode 100644 Documentation/Marvell/PortingGuide/PciEmulation.txt create mode 100644 Documentation/Marvell/PortingGuide/Reset.txt create mode 100644 Documentation/Marvell/PortingGuide/Sata.txt create mode 100644 Documentation/Marvell/PortingGuide/Utmi.txt create mode 100644 Drivers/Sd/MvSdMmcPciHcDxe.c create mode 100644 Drivers/Sd/MvSdMmcPciHcDxe.inf create mode 100644 Drivers/Sd/XenonSdhci.c create mode 100644 Drivers/Sd/XenonSdhci.h create mode 100644 Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040IcuLib.c create mode 100644 Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040IcuLib.h create mode 100644 Platforms/Marvell/Armada/Library/MarvellResetSystemLib/MarvellResetSystemLib.c create mode 100644 Platforms/Marvell/Armada/Library/MarvellResetSystemLib/MarvellResetSystemLib.inf create mode 100644 Platforms/Marvell/Include/Library/ComPhyLib.h create mode 100644 Platforms/Marvell/Include/Library/ParsePcdLib.h create mode 100644 Platforms/Marvell/Include/Library/UtmiPhyLib.h create mode 100644 Platforms/Marvell/Library/ComPhyLib/ComPhyAp806.c create mode 100644 Platforms/Marvell/Library/ComPhyLib/ComPhyCp110.c create mode 100644 Platforms/Marvell/Library/ComPhyLib/ComPhyLib.c create mode 100644 Platforms/Marvell/Library/ComPhyLib/ComPhyLib.h create mode 100644 Platforms/Marvell/Library/ComPhyLib/ComPhyLib.inf create mode 100644 Platforms/Marvell/Library/ComPhyLib/ComPhyMux.c create mode 100644 Platforms/Marvell/Library/ParsePcdLib/ParsePcdLib.c create mode 100644 Platforms/Marvell/Library/ParsePcdLib/ParsePcdLib.inf create mode 100644 Platforms/Marvell/Library/UtmiPhyLib/UtmiPhyLib.c create mode 100644 Platforms/Marvell/Library/UtmiPhyLib/UtmiPhyLib.h create mode 100644 Platforms/Marvell/Library/UtmiPhyLib/UtmiPhyLib.inf create mode 100644 Platforms/Marvell/PciEmulation/PciEmulation.c create mode 100644 Platforms/Marvell/PciEmulation/PciEmulation.h create mode 100644 Platforms/Marvell/PciEmulation/PciEmulation.inf create mode 100644 Platforms/Marvell/PciEmulation/PciRootBridgeIo.c
From: Bartosz Szczepanek bsz@semihalf.com
MarvellResetSystemLib implements functionality required to restart the platform.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Bartosz Szczepanek bsz@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- Documentation/Marvell/PortingGuide/Reset.txt | 7 ++ Documentation/Marvell/UserGuide.txt | 1 + Platforms/Marvell/Armada/Armada7040_rz.dsc | 4 + .../MarvellResetSystemLib/MarvellResetSystemLib.c | 85 ++++++++++++++++++++++ .../MarvellResetSystemLib.inf | 56 ++++++++++++++ Platforms/Marvell/Marvell.dec | 4 + 6 files changed, 157 insertions(+) create mode 100644 Documentation/Marvell/PortingGuide/Reset.txt create mode 100644 Platforms/Marvell/Armada/Library/MarvellResetSystemLib/MarvellResetSystemLib.c create mode 100644 Platforms/Marvell/Armada/Library/MarvellResetSystemLib/MarvellResetSystemLib.inf
diff --git a/Documentation/Marvell/PortingGuide/Reset.txt b/Documentation/Marvell/PortingGuide/Reset.txt new file mode 100644 index 0000000..1430fc0 --- /dev/null +++ b/Documentation/Marvell/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/Documentation/Marvell/UserGuide.txt b/Documentation/Marvell/UserGuide.txt index 28f78dc..9b2e9a8 100644 --- a/Documentation/Marvell/UserGuide.txt +++ b/Documentation/Marvell/UserGuide.txt @@ -10,6 +10,7 @@ Table of contents: i2c - PortingGuide/I2c.txt mpp - PortingGuide/Mpp.txt ramdisk - PortingGuide/Ramdisk.txt + reset library - PortingGuide/Reset.txt spi - PortingGuide/Spi.txt spi flash - PortingGuide/SpiFlash.txt
diff --git a/Platforms/Marvell/Armada/Armada7040_rz.dsc b/Platforms/Marvell/Armada/Armada7040_rz.dsc index 24ab412..b8926ef 100644 --- a/Platforms/Marvell/Armada/Armada7040_rz.dsc +++ b/Platforms/Marvell/Armada/Armada7040_rz.dsc @@ -94,3 +94,7 @@
#RamDisk gMarvellTokenSpaceGuid.PcdRamDiskSize|64 #64MB + + #ResetLib + gMarvellTokenSpaceGuid.PcdResetRegAddress|0xf06f0084 + gMarvellTokenSpaceGuid.PcdResetRegMask|0x1 diff --git a/Platforms/Marvell/Armada/Library/MarvellResetSystemLib/MarvellResetSystemLib.c b/Platforms/Marvell/Armada/Library/MarvellResetSystemLib/MarvellResetSystemLib.c new file mode 100644 index 0000000..f9dbd5d --- /dev/null +++ b/Platforms/Marvell/Armada/Library/MarvellResetSystemLib/MarvellResetSystemLib.c @@ -0,0 +1,85 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +#include <PiDxe.h> + +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/IoLib.h> +#include <Library/EfiResetSystemLib.h> + +EFI_STATUS +EFIAPI +LibResetSystem ( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN CHAR16 *ResetData OPTIONAL + ) +{ + UINT64 Address; + UINT32 Data; + + + DEBUG((DEBUG_WARN, "reset system\n")); + switch (ResetType) { + case EfiResetCold: + case EfiResetWarm: + Address = PcdGet64 (PcdResetRegAddress); + Data = MmioRead32 (Address); + Data &= ~PcdGet32 (PcdResetRegMask); + MmioWrite32 (Address, Data); + break; + case EfiResetShutdown: + return EFI_UNSUPPORTED; + break; + + default: + return EFI_INVALID_PARAMETER; + } + + return EFI_DEVICE_ERROR; +} + +EFI_STATUS +EFIAPI +LibInitializeResetSystem ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return EFI_SUCCESS; +} + diff --git a/Platforms/Marvell/Armada/Library/MarvellResetSystemLib/MarvellResetSystemLib.inf b/Platforms/Marvell/Armada/Library/MarvellResetSystemLib/MarvellResetSystemLib.inf new file mode 100644 index 0000000..089f65b --- /dev/null +++ b/Platforms/Marvell/Armada/Library/MarvellResetSystemLib/MarvellResetSystemLib.inf @@ -0,0 +1,56 @@ +# 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 = MarvellResetSystemLib + FILE_GUID = 13370566-097f-4ff6-ad24-c818f1b47a88 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = EfiResetSystemLib + + +[Sources.common] + MarvellResetSystemLib.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + OpenPlatformPkg/Platforms/Marvell/Marvell.dec + +[LibraryClasses] + IoLib + DebugLib + +[Pcd] + gMarvellTokenSpaceGuid.PcdResetRegAddress + gMarvellTokenSpaceGuid.PcdResetRegMask diff --git a/Platforms/Marvell/Marvell.dec b/Platforms/Marvell/Marvell.dec index 788e56b..6ef6ec1 100644 --- a/Platforms/Marvell/Marvell.dec +++ b/Platforms/Marvell/Marvell.dec @@ -128,6 +128,10 @@ #Ramdisk gMarvellTokenSpaceGuid.PcdRamDiskSize|0|UINT32|0x23000057 #MB
+#ResetLib + gMarvellTokenSpaceGuid.PcdResetRegAddress|0|UINT64|0x40000050 + gMarvellTokenSpaceGuid.PcdResetRegMask|0|UINT32|0x4000051 + [Protocols] gEfiEepromProtocolGuid = { 0xcd728a1f, 0x45b5, 0x4feb, { 0x98, 0xc8, 0x31, 0x3d, 0xa8, 0x11, 0x74, 0x62 }} gEfiSpiMasterProtocolGuid = { 0x23de66a3, 0xf666, 0x4b3e, { 0xaa, 0xa2, 0x68, 0x9b, 0x18, 0xae, 0x2e, 0x19 }}
On 29 April 2016 at 02:23, Marcin Wojtas mw@semihalf.com wrote:
From: Bartosz Szczepanek bsz@semihalf.com
MarvellResetSystemLib implements functionality required to restart the platform.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Bartosz Szczepanek bsz@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com
I don't see any virtual remapping code in this library. Does this library implement reset in a way that is compatible with the ResetSystem() runtime service?
Documentation/Marvell/PortingGuide/Reset.txt | 7 ++ Documentation/Marvell/UserGuide.txt | 1 + Platforms/Marvell/Armada/Armada7040_rz.dsc | 4 + .../MarvellResetSystemLib/MarvellResetSystemLib.c | 85 ++++++++++++++++++++++ .../MarvellResetSystemLib.inf | 56 ++++++++++++++ Platforms/Marvell/Marvell.dec | 4 + 6 files changed, 157 insertions(+) create mode 100644 Documentation/Marvell/PortingGuide/Reset.txt create mode 100644 Platforms/Marvell/Armada/Library/MarvellResetSystemLib/MarvellResetSystemLib.c create mode 100644 Platforms/Marvell/Armada/Library/MarvellResetSystemLib/MarvellResetSystemLib.inf
diff --git a/Documentation/Marvell/PortingGuide/Reset.txt b/Documentation/Marvell/PortingGuide/Reset.txt new file mode 100644 index 0000000..1430fc0 --- /dev/null +++ b/Documentation/Marvell/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/Documentation/Marvell/UserGuide.txt b/Documentation/Marvell/UserGuide.txt index 28f78dc..9b2e9a8 100644 --- a/Documentation/Marvell/UserGuide.txt +++ b/Documentation/Marvell/UserGuide.txt @@ -10,6 +10,7 @@ Table of contents: i2c - PortingGuide/I2c.txt mpp - PortingGuide/Mpp.txt ramdisk - PortingGuide/Ramdisk.txt
- reset library - PortingGuide/Reset.txt spi - PortingGuide/Spi.txt spi flash - PortingGuide/SpiFlash.txt
diff --git a/Platforms/Marvell/Armada/Armada7040_rz.dsc b/Platforms/Marvell/Armada/Armada7040_rz.dsc index 24ab412..b8926ef 100644 --- a/Platforms/Marvell/Armada/Armada7040_rz.dsc +++ b/Platforms/Marvell/Armada/Armada7040_rz.dsc @@ -94,3 +94,7 @@
#RamDisk gMarvellTokenSpaceGuid.PcdRamDiskSize|64 #64MB
- #ResetLib
- gMarvellTokenSpaceGuid.PcdResetRegAddress|0xf06f0084
- gMarvellTokenSpaceGuid.PcdResetRegMask|0x1
diff --git a/Platforms/Marvell/Armada/Library/MarvellResetSystemLib/MarvellResetSystemLib.c b/Platforms/Marvell/Armada/Library/MarvellResetSystemLib/MarvellResetSystemLib.c new file mode 100644 index 0000000..f9dbd5d --- /dev/null +++ b/Platforms/Marvell/Armada/Library/MarvellResetSystemLib/MarvellResetSystemLib.c @@ -0,0 +1,85 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd.
+Marvell BSD License Option
+If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- Neither the name of Marvell nor the names of its contributors may be
- used to endorse or promote products derived from this software without
- specific prior written permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+#include <PiDxe.h>
+#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/IoLib.h> +#include <Library/EfiResetSystemLib.h>
+EFI_STATUS +EFIAPI +LibResetSystem (
- IN EFI_RESET_TYPE ResetType,
- IN EFI_STATUS ResetStatus,
- IN UINTN DataSize,
- IN CHAR16 *ResetData OPTIONAL
- )
+{
- UINT64 Address;
- UINT32 Data;
- DEBUG((DEBUG_WARN, "reset system\n"));
- switch (ResetType) {
- case EfiResetCold:
- case EfiResetWarm:
- Address = PcdGet64 (PcdResetRegAddress);
- Data = MmioRead32 (Address);
- Data &= ~PcdGet32 (PcdResetRegMask);
- MmioWrite32 (Address, Data);
- break;
- case EfiResetShutdown:
- return EFI_UNSUPPORTED;
- break;
- default:
- return EFI_INVALID_PARAMETER;
- }
- return EFI_DEVICE_ERROR;
+}
+EFI_STATUS +EFIAPI +LibInitializeResetSystem (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
+{
- return EFI_SUCCESS;
+}
diff --git a/Platforms/Marvell/Armada/Library/MarvellResetSystemLib/MarvellResetSystemLib.inf b/Platforms/Marvell/Armada/Library/MarvellResetSystemLib/MarvellResetSystemLib.inf new file mode 100644 index 0000000..089f65b --- /dev/null +++ b/Platforms/Marvell/Armada/Library/MarvellResetSystemLib/MarvellResetSystemLib.inf @@ -0,0 +1,56 @@ +# 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 = MarvellResetSystemLib
- FILE_GUID = 13370566-097f-4ff6-ad24-c818f1b47a88
- MODULE_TYPE = BASE
- VERSION_STRING = 1.0
- LIBRARY_CLASS = EfiResetSystemLib
+[Sources.common]
- MarvellResetSystemLib.c
+[Packages]
- MdePkg/MdePkg.dec
- EmbeddedPkg/EmbeddedPkg.dec
- OpenPlatformPkg/Platforms/Marvell/Marvell.dec
+[LibraryClasses]
- IoLib
- DebugLib
+[Pcd]
- gMarvellTokenSpaceGuid.PcdResetRegAddress
- gMarvellTokenSpaceGuid.PcdResetRegMask
diff --git a/Platforms/Marvell/Marvell.dec b/Platforms/Marvell/Marvell.dec index 788e56b..6ef6ec1 100644 --- a/Platforms/Marvell/Marvell.dec +++ b/Platforms/Marvell/Marvell.dec @@ -128,6 +128,10 @@ #Ramdisk gMarvellTokenSpaceGuid.PcdRamDiskSize|0|UINT32|0x23000057 #MB
+#ResetLib
- gMarvellTokenSpaceGuid.PcdResetRegAddress|0|UINT64|0x40000050
- gMarvellTokenSpaceGuid.PcdResetRegMask|0|UINT32|0x4000051
[Protocols] gEfiEepromProtocolGuid = { 0xcd728a1f, 0x45b5, 0x4feb, { 0x98, 0xc8, 0x31, 0x3d, 0xa8, 0x11, 0x74, 0x62 }} gEfiSpiMasterProtocolGuid = { 0x23de66a3, 0xf666, 0x4b3e, { 0xaa, 0xa2, 0x68, 0x9b, 0x18, 0xae, 0x2e, 0x19 }} -- 1.8.3.1
From: Bartosz Szczepanek bsz@semihalf.com
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Bartosz Szczepanek bsz@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- Platforms/Marvell/Armada/Armada.dsc.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Platforms/Marvell/Armada/Armada.dsc.inc b/Platforms/Marvell/Armada/Armada.dsc.inc index ed4a7cc..e9ce4cc 100644 --- a/Platforms/Marvell/Armada/Armada.dsc.inc +++ b/Platforms/Marvell/Armada/Armada.dsc.inc @@ -87,7 +87,7 @@ PlatformHookLib|MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf
# Reset and Time libraries - EfiResetSystemLib|EmbeddedPkg/Library/TemplateResetSystemLib/TemplateResetSystemLib.inf + EfiResetSystemLib|OpenPlatformPkg/Platforms/Marvell/Armada/Library/MarvellResetSystemLib/MarvellResetSystemLib.inf RealTimeClockLib|EmbeddedPkg/Library/TemplateRealTimeClockLib/TemplateRealTimeClockLib.inf
# Networking Requirements for ArmPlatformPkg/Bds
From: Jan Dąbroś jsd@semihalf.com
This library performs basic ICU initialization for Armada7040 boards. It is necessary for interrupts in order to working properly in Linux.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- Documentation/Marvell/PortingGuide/IcuLib.txt | 15 ++ Documentation/Marvell/UserGuide.txt | 1 + .../Library/Armada7040Lib/Armada7040IcuLib.c | 253 +++++++++++++++++++++ .../Library/Armada7040Lib/Armada7040IcuLib.h | 83 +++++++ Platforms/Marvell/Marvell.dec | 5 + 5 files changed, 357 insertions(+) create mode 100644 Documentation/Marvell/PortingGuide/IcuLib.txt create mode 100644 Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040IcuLib.c create mode 100644 Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040IcuLib.h
diff --git a/Documentation/Marvell/PortingGuide/IcuLib.txt b/Documentation/Marvell/PortingGuide/IcuLib.txt new file mode 100644 index 0000000..ae8526f --- /dev/null +++ b/Documentation/Marvell/PortingGuide/IcuLib.txt @@ -0,0 +1,15 @@ +IcuLib configuration +-------------------- +Interrupt Controller Unit Library is configured via set of PCDs: + + gMarvellTokenSpaceGuid.PcdIcuCpBase + +Indicates register base address of Cp chip. + + gMarvellTokenSpaceGuid.PcdIcuSpiBase + +Indicates base of the SPI id in the MSI message generated by the ICU. + + gMarvellTokenSpaceGuid.PcdIcuSpiOffset + +Used to shift the multi instance interrupts between CP-0 and CP-1. diff --git a/Documentation/Marvell/UserGuide.txt b/Documentation/Marvell/UserGuide.txt index 9b2e9a8..fcd5b0b 100644 --- a/Documentation/Marvell/UserGuide.txt +++ b/Documentation/Marvell/UserGuide.txt @@ -8,6 +8,7 @@ Table of contents:
2. Porting guide i2c - PortingGuide/I2c.txt + icu - PortingGuide/IcuLib.txt mpp - PortingGuide/Mpp.txt ramdisk - PortingGuide/Ramdisk.txt reset library - PortingGuide/Reset.txt diff --git a/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040IcuLib.c b/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040IcuLib.c new file mode 100644 index 0000000..8cb0a33 --- /dev/null +++ b/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040IcuLib.c @@ -0,0 +1,253 @@ +/******************************************************************************** +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 "Armada7040IcuLib.h" + +/* + * Allocate the MSI address per interrupt group, + * unsupported groups get NULL address + */ +STATIC ICU_MSI MsiAddr[ICU_GRP_MAX] = { + {ICU_GRP_NSR, 0xf03f0040, 0xf03f0048}, /* Non secure interrupts*/ + {ICU_GRP_SR, 0, 0x0}, /* Secure interrupts */ + {ICU_GRP_LPI, 0x0, 0x0}, /* LPI interrupts */ + {ICU_GRP_VLPI, 0x0, 0x0}, /* Virtual LPI interrupts */ + {ICU_GRP_SEI, 0xf03f0230, 0x0}, /* System error interrupts */ + {ICU_GRP_REI, 0xf03f0270, 0x0}, /* RAM error interrupts */ +}; + +/* Multi instance sources, multiplied in dual CP mode */ +STATIC ICU_IRQ IrqMapNsMulti[NS_MULTI_IRQS] = { + {22, 0, 0}, /* PCIx4 INT A interrupt */ + {23, 1, 0}, /* PCIx1 INT A interrupt */ + {24, 2, 0}, /* PCIx1 INT A interrupt */ + + {33, 3, 0}, /* PPv2 DBG AXI monitor */ + {34, 3, 0}, /* HB1 AXI monitor */ + {35, 3, 0}, /* AP AXI monitor */ + {36, 3, 0}, /* PPv2 AXI monitor */ + + {38, 4, 0}, /* PPv2 Misc */ + + {39, 5, 0}, /* PPv2 Irq */ + {40, 6, 0}, /* PPv2 Irq */ + {41, 7, 0}, /* PPv2 Irq */ + {42, 8, 0}, /* PPv2 Irq */ + {43, 9, 0}, /* PPv2 Irq */ + {44, 10, 0}, /* PPv2 Irq */ + {45, 11, 0}, /* PPv2 Irq */ + {46, 12, 0}, /* PPv2 Irq */ + {47, 13, 0}, /* PPv2 Irq */ + {48, 14, 0}, /* PPv2 Irq */ + {49, 15, 0}, /* PPv2 Irq */ + {50, 16, 0}, /* PPv2 Irq */ + {51, 17, 0}, /* PPv2 Irq */ + {52, 18, 0}, /* PPv2 Irq */ + {53, 19, 0}, /* PPv2 Irq */ + {54, 20, 0}, /* PPv2 Irq */ + + {78, 21, 0}, /* MG Irq */ + {88, 22, 0}, /* EIP-197 ring-0 */ + {89, 23, 0}, /* EIP-197 ring-1 */ + {90, 24, 0}, /* EIP-197 ring-2 */ + {91, 25, 0}, /* EIP-197 ring-3 */ + {92, 26, 0}, /* EIP-197 UINTN */ + {95, 27, 0}, /* EIP-150 Irq */ + {102, 28, 0}, /* USB3 Device Irq */ + {105, 29, 0}, /* USB3 Host-1 Irq */ + {106, 30, 0}, /* USB3 Host-0 Irq */ + {107, 31, 0}, /* SATA Host-1 Irq */ + {109, 31, 0}, /* SATA Host-0 Irq */ + {126, 33, 0}, /* PTP Irq */ + {127, 34, 0}, /* GOP-3 Irq */ + {128, 35, 0}, /* GOP-2 Irq */ + {129, 36, 0}, /* GOP-0 Irq */ +}; + +/* Single instance sources, not multiplies in dual CP mode */ +STATIC ICU_IRQ IrqMapNsSingle[NS_SINGLE_IRQS] = { + {27, 37, 0}, /* SD/MMC */ + {76, 38, 0}, /* Audio */ + {77, 39, 0}, /* MSS RTC */ + {79, 40, 0}, /* GPIO 56-63 */ + {80, 41, 0}, /* GPIO 48-55 */ + {81, 42, 0}, /* GPIO 40-47 */ + {82, 43, 0}, /* GPIO 32-39 */ + {83, 44, 0}, /* GPIO 24-31 */ + {84, 45, 0}, /* GPIO 16-23 */ + {85, 46, 0}, /* GPIO 8-15 */ + {86, 47, 0}, /* GPIO 0-7 */ + {111, 48, 0}, /* TDM-MC func 1 */ + {112, 49, 0}, /* TDM-MC func 0 */ + {113, 50, 0}, /* TDM-MC Irq */ + {115, 51, 0}, /* NAND Irq */ + {117, 52, 0}, /* SPI-1 Irq */ + {118, 53, 0}, /* SPI-0 Irq */ + {120, 54, 0}, /* I2C 0 Irq */ + {121, 55, 0}, /* I2C 1 Irq */ + {122, 56, 0}, /* UART 0 Irq */ + {123, 57, 0}, /* UART 1 Irq */ + {124, 58, 0}, /* UART 2 Irq */ + {125, 59, 0}, /* UART 3 Irq */ +}; + +/* SEI - System Error Interrupts */ +STATIC ICU_IRQ IrqMapSei[SEI_IRQS] = { + {11, 0, 0}, /* SEI error CP-2-CP */ + {15, 1, 0}, /* PIDI-64 SOC */ + {16, 2, 0}, /* D2D error Irq */ + {17, 3, 0}, /* D2D Irq */ + {18, 4, 0}, /* NAND error */ + {19, 5, 0}, /* PCIx4 error */ + {20, 6, 0}, /* PCIx1_0 error */ + {21, 7, 0}, /* PCIx1_1 error */ + {25, 8, 0}, /* SDIO reg error */ + {75, 9, 0}, /* IOB error */ + {94, 10, 0}, /* EIP150 error */ + {97, 11, 0}, /* XOR-1 system error */ + {99, 12, 0}, /* XOR-0 system error */ + {108, 13, 0}, /* SATA-1 error */ + {110, 14, 0}, /* SATA-0 error */ + {114, 15, 0}, /* TDM-MC error */ + {116, 16, 0}, /* DFX server Irq */ + {117, 17, 0}, /* Device bus error */ + {147, 18, 0}, /* Audio error */ + {171, 19, 0}, /* PIDI Sync error */ +}; + +/* REI - RAM Error Interrupts */ +STATIC ICU_IRQ IrqMapRei[REI_IRQS] = { + {12, 0, 0}, /* REI error CP-2-CP */ + {26, 1, 0}, /* SDIO memory error */ + {87, 2, 0}, /* EIP-197 ECC error */ + {93, 3, 0}, /* EIP-150 RAM error */ + {96, 4, 0}, /* XOR-1 memory Irq */ + {98, 5, 0}, /* XOR-0 memory Irq */ + {100, 6, 0}, /* USB3 device tx parity */ + {101, 7, 0}, /* USB3 device rq parity */ + {103, 8, 0}, /* USB3H-1 RAM error */ + {104, 9, 0}, /* USB3H-0 RAM error */ +}; + +STATIC +VOID +IcuClearIrq ( + IN UINTN IcuBase, + IN UINTN Nbr + ) +{ + + MmioWrite32 (IcuBase + ICU_INT_CFG(Nbr), 0); +} + +STATIC +VOID +IcuSetIrq ( + IN UINTN IcuBase, + IN ICU_IRQ *Irq, + IN UINT32 SpiBase, + IN ICU_GROUP Group + ) +{ + UINT32 IcuInt; + + IcuInt = (Irq->SpiId + SpiBase) | (1 << ICU_INT_ENABLE_OFFSET); + IcuInt |= Irq->IsEdge << ICU_IS_EDGE_OFFSET; + IcuInt |= Group << ICU_GROUP_OFFSET; + + MmioWrite32 (IcuBase + ICU_INT_CFG(Irq->IcuId), IcuInt); +} + +/* + * This function uses 2 spi values to initialize the ICU + * SpiBase: used to set the base of the SPI id in the MSI message + * generated by the ICU. AP806-Z1 required SpiBase=64 while + * AP806-A0 uses SpiBase=0 + * SpiOffset: used to shift the multi instance interrupts between CP-0 + * and CP-1 + */ +VOID +IcuInit ( + VOID + ) +{ + UINTN i, CpBase, SpiBase, SpiOffset, IcuBase; + ICU_IRQ *Irq; + ICU_MSI *Msi; + + CpBase = PcdGet64 (PcdIcuCpBase); + + /* Prevent execution on Apn806 board */ + if (CpBase == 0) { + return; + } + + SpiBase = PcdGet64 (PcdIcuSpiBase); + SpiOffset = PcdGet64 (PcdIcuSpiOffset); + + IcuBase = CpBase + ICU_REG_BASE; + + /* Set the addres for SET_SPI and CLR_SPI registers in AP */ + Msi = MsiAddr; + for (i = 0; i < ICU_GRP_MAX; i++, Msi++) { + MmioWrite32 (IcuBase + ICU_SET_SPI_AL(Msi->Group), Msi->SetSpiAddr & + 0xFFFFFFFF); + MmioWrite32 (IcuBase + ICU_SET_SPI_AH(Msi->Group), Msi->SetSpiAddr >> 32); + MmioWrite32 (IcuBase + ICU_CLR_SPI_AL(Msi->Group), Msi->ClrSpiAddr & + 0xFFFFFFFF); + MmioWrite32 (IcuBase + ICU_CLR_SPI_AH(Msi->Group), Msi->ClrSpiAddr >> 32); + } + + /* Mask all ICU interrupts */ + for (i = 0; i < MAX_ICU_IRQS; i++) + IcuClearIrq(IcuBase, i); + + /* Configure the ICU interrupt lines */ + /* Multi instance interrupts use different SPI ID for CP-1 */ + Irq = IrqMapNsMulti; + for (i = 0; i < NS_MULTI_IRQS; i++, Irq++) + IcuSetIrq (IcuBase, Irq, SpiBase + SpiOffset, ICU_GRP_NSR); + + Irq = IrqMapNsSingle; + for (i = 0; i < NS_MULTI_IRQS; i++, Irq++) + IcuSetIrq (IcuBase, Irq, SpiBase, ICU_GRP_NSR); + + Irq = IrqMapSei; + for (i = 0; i < NS_MULTI_IRQS; i++, Irq++) + IcuSetIrq (IcuBase, Irq, SpiBase, ICU_GRP_SEI); + + Irq = IrqMapRei; + for (i = 0; i < NS_MULTI_IRQS; i++, Irq++) + IcuSetIrq (IcuBase, Irq, SpiBase, ICU_GRP_REI); +} diff --git a/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040IcuLib.h b/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040IcuLib.h new file mode 100644 index 0000000..41bd9a2 --- /dev/null +++ b/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040IcuLib.h @@ -0,0 +1,83 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include <Library/IoLib.h> +#include <Library/PcdLib.h> +#include <Library/ArmLib.h> + +#define ICU_REG_BASE 0x1E0000 + +#define ICU_AXI_ATTR 0x0 +#define ICU_SET_SPI_AL(x) (0x10 + (0x10 * x)) +#define ICU_SET_SPI_AH(x) (0x14 + (0x10 * x)) +#define ICU_CLR_SPI_AL(x) (0x18 + (0x10 * x)) +#define ICU_CLR_SPI_AH(x) (0x1c + (0x10 * x)) +#define ICU_INT_CFG(x) (0x100 + 4 * x) + +#define ICU_INT_ENABLE_OFFSET (24) +#define ICU_IS_EDGE_OFFSET (28) +#define ICU_GROUP_OFFSET (29) + +#define NS_MULTI_IRQS 40 +#define NS_SINGLE_IRQS 23 +#define REI_IRQS 10 +#define SEI_IRQS 20 +#define MAX_ICU_IRQS 207 + +typedef enum { + ICU_GRP_NSR = 0, + ICU_GRP_SR = 1, + ICU_GRP_LPI = 2, + ICU_GRP_VLPI = 3, + ICU_GRP_SEI = 4, + ICU_GRP_REI = 5, + ICU_GRP_MAX, +} ICU_GROUP; + +typedef struct { + UINT8 IcuId; + UINT8 SpiId; + UINT8 IsEdge; +} ICU_IRQ; + +typedef struct { + ICU_GROUP Group; + UINTN SetSpiAddr; + UINTN ClrSpiAddr; +} ICU_MSI; + +VOID +IcuInit ( + VOID + ); diff --git a/Platforms/Marvell/Marvell.dec b/Platforms/Marvell/Marvell.dec index 6ef6ec1..7a53961 100644 --- a/Platforms/Marvell/Marvell.dec +++ b/Platforms/Marvell/Marvell.dec @@ -132,6 +132,11 @@ gMarvellTokenSpaceGuid.PcdResetRegAddress|0|UINT64|0x40000050 gMarvellTokenSpaceGuid.PcdResetRegMask|0|UINT32|0x4000051
+#IcuLib + gMarvellTokenSpaceGuid.PcdIcuCpBase|0|UINT64|0x30000210 + gMarvellTokenSpaceGuid.PcdIcuSpiBase|0|UINT64|0x30000211 + gMarvellTokenSpaceGuid.PcdIcuSpiOffset|0|UINT64|0x30000212 + [Protocols] gEfiEepromProtocolGuid = { 0xcd728a1f, 0x45b5, 0x4feb, { 0x98, 0xc8, 0x31, 0x3d, 0xa8, 0x11, 0x74, 0x62 }} gEfiSpiMasterProtocolGuid = { 0x23de66a3, 0xf666, 0x4b3e, { 0xaa, 0xa2, 0x68, 0x9b, 0x18, 0xae, 0x2e, 0x19 }}
From: Jan Dąbroś jsd@semihalf.com
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- Platforms/Marvell/Armada/Armada7040_rz.dsc | 5 +++++ Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.c | 5 ++--- Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.inf | 5 +++++ 3 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/Platforms/Marvell/Armada/Armada7040_rz.dsc b/Platforms/Marvell/Armada/Armada7040_rz.dsc index b8926ef..0bdf506 100644 --- a/Platforms/Marvell/Armada/Armada7040_rz.dsc +++ b/Platforms/Marvell/Armada/Armada7040_rz.dsc @@ -98,3 +98,8 @@ #ResetLib gMarvellTokenSpaceGuid.PcdResetRegAddress|0xf06f0084 gMarvellTokenSpaceGuid.PcdResetRegMask|0x1 + + #IcuLib + gMarvellTokenSpaceGuid.PcdIcuCpBase|0xF2000000 + gMarvellTokenSpaceGuid.PcdIcuSpiBase|64 + gMarvellTokenSpaceGuid.PcdIcuSpiOffset|0 diff --git a/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.c b/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.c index 2a34455..fa480a5 100644 --- a/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.c +++ b/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.c @@ -16,7 +16,7 @@ #include <Library/ArmPlatformLib.h> #include <Library/MppLib.h> #include <Ppi/ArmMpCoreInfo.h> - +#include "Armada7040IcuLib.h"
ARM_CORE_INFO mArmPlatformNullMpCoreInfoTable[] = { { @@ -91,8 +91,7 @@ ArmPlatformInitialize ( return RETURN_SUCCESS; }
- //TODO: Add basic platfrom initialization - + IcuInit (); MppInitialize (); return RETURN_SUCCESS; } diff --git a/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.inf b/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.inf index f586e65..6c1fde6 100644 --- a/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.inf +++ b/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.inf @@ -35,6 +35,7 @@ [Sources.common] Armada7040Lib.c Armada7040LibMem.c + Armada7040IcuLib.c
[Sources.AArch64] AArch64/ArmPlatformHelper.S @@ -45,3 +46,7 @@
gArmTokenSpaceGuid.PcdArmPrimaryCoreMask gArmTokenSpaceGuid.PcdArmPrimaryCore + + gMarvellTokenSpaceGuid.PcdIcuCpBase + gMarvellTokenSpaceGuid.PcdIcuSpiBase + gMarvellTokenSpaceGuid.PcdIcuSpiOffset
From: Jan Dąbroś jsd@semihalf.com
Since PCD tables are byte arrays, it is impossible to provide big values (e.g. memory addresses) for multiple devices in simple PCD entry. In order to overcome this, strings may be used. ParsePcdLib allows parsing PCD string entry.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- Platforms/Marvell/Include/Library/ParsePcdLib.h | 46 +++++ .../Marvell/Library/ParsePcdLib/ParsePcdLib.c | 228 +++++++++++++++++++++ .../Marvell/Library/ParsePcdLib/ParsePcdLib.inf | 50 +++++ 3 files changed, 324 insertions(+) create mode 100644 Platforms/Marvell/Include/Library/ParsePcdLib.h create mode 100644 Platforms/Marvell/Library/ParsePcdLib/ParsePcdLib.c create mode 100644 Platforms/Marvell/Library/ParsePcdLib/ParsePcdLib.inf
diff --git a/Platforms/Marvell/Include/Library/ParsePcdLib.h b/Platforms/Marvell/Include/Library/ParsePcdLib.h new file mode 100644 index 0000000..a255685 --- /dev/null +++ b/Platforms/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/Platforms/Marvell/Library/ParsePcdLib/ParsePcdLib.c b/Platforms/Marvell/Library/ParsePcdLib/ParsePcdLib.c new file mode 100644 index 0000000..9a4be8e --- /dev/null +++ b/Platforms/Marvell/Library/ParsePcdLib/ParsePcdLib.c @@ -0,0 +1,228 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must Retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ +#define CHAR_NULL 0x0000 + +#include <Library/BaseLib.h> +#include <Uefi.h> +#include <Library/UefiLib.h> +#include <Library/DebugLib.h> + +STATIC +CHAR16 +CharToUpper ( + IN CHAR16 Char + ) +{ + + if (Char >= L'a' && Char <= L'z') { + return (CHAR16) (Char - (L'a' - L'A')); + } + + return Char; +} + +STATIC +BOOLEAN +IsDecimalDigitChar ( + IN CHAR16 Char + ) +{ + + return (BOOLEAN) (Char >= L'0' && Char <= L'9'); +} + + +STATIC +UINTN +HexCharToUintn ( + IN CHAR16 Char + ) +{ + if (IsDecimalDigitChar (Char)) { + return Char - L'0'; + } + + return (UINTN) (10 + CharToUpper (Char) - L'A'); +} + +STATIC +BOOLEAN +IsHexDigitCharacter ( + CHAR16 Char + ) +{ + + return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && + Char <= L'F') || (Char >= L'a' && Char <= L'f')); +} + +STATIC +UINTN +HexStrToUintn ( + CHAR16 *String + ) +{ + UINTN Result = 0; + + if (String == NULL || StrSize(String) == 0) { + return (UINTN)(-1); + } + + // Ignore spaces and tabs + while ((*String == L' ') || (*String == L'\t')) { + String++; + } + + // Ignore leading zeros after spaces + while (*String == L'0') { + String++; + } + + if (CharToUpper (*String) != L'X') { + return (UINTN)(-1); + } + + // Skip 'x' + String++; + + while (IsHexDigitCharacter (*String)) { + Result <<= 4; + Result += HexCharToUintn (*String); + String++; + } + + return (UINTN) Result; +} + +STATIC +UINTN +DecimalStrToUintn ( + CHAR16 *String + ) +{ + UINTN Result = 0; + + while (IsDecimalDigitChar (*String)) { + Result = 10 * Result + (*String - L'0'); + String++; + } + + return Result; +} + +STATIC +UINTN +StrToUintn ( + CHAR16 *String + ) +{ + CHAR16 *Walker; + + // Chop off leading spaces + for (Walker = String; Walker != NULL && *Walker != CHAR_NULL && *Walker == L' '; Walker++); + + if (StrnCmp(Walker, L"0x", 2) == 0 || StrnCmp(Walker, L"0X", 2) == 0) { + return HexStrToUintn (Walker); + } else { + return DecimalStrToUintn (Walker); + } +} + +EFI_STATUS +ParsePcdString ( + IN CHAR16 *PcdString, + IN UINT8 Count, + OUT UINTN *ValueTable, + OUT CHAR16 **StrTable + ) +{ + BOOLEAN ValueFlag = FALSE; + CHAR16 *Walker; + UINTN i, Tmp = 0; + + if (ValueTable != NULL) { + ValueFlag = TRUE; + } + + // Set pointer at the end of PCD string + Walker = PcdString + StrLen (PcdString); + for (i = 0; i < Count; i++) { + while ((--Walker) >= PcdString) { + if (*Walker == L';') { + // Cut off parsed chunk from PCD string by replacing ';' with + // null-terminator + *Walker = '\0'; + if (ValueFlag) { + Tmp = StrToUintn ((Walker + 1)); + if ((UINTN)(-1) == Tmp) { + return EFI_INVALID_PARAMETER; + } + // Entry is parsed from the end to the beginning + // so fill table in the same manner + ValueTable[Count - (i + 1)] = Tmp; + } else { + StrTable[Count - (i + 1)] = Walker + 1; + } + Walker--; + break; + } + if (Walker == PcdString) { + if (ValueFlag) { + Tmp = StrToUintn ((Walker)); + if (Tmp == (UINTN)(-1)) { + return EFI_INVALID_PARAMETER; + } + } + // Last device's entry should be added to the table here. + // If not, return error + if (i != (Count - 1)) { + DEBUG((DEBUG_ERROR, "ParsePcdLib: Please set PCD value for every " + "device\n")); + return EFI_INVALID_PARAMETER; + } + // We parse from the end to the beginning + // so fill table in the same manner + if (ValueFlag) { + ValueTable[Count - (i + 1)] = Tmp; + } else { + StrTable[Count - (i + 1)] = Walker; + } + // End both loops + return EFI_SUCCESS; + } + } + } + + return EFI_SUCCESS; +} diff --git a/Platforms/Marvell/Library/ParsePcdLib/ParsePcdLib.inf b/Platforms/Marvell/Library/ParsePcdLib/ParsePcdLib.inf new file mode 100644 index 0000000..b4db621 --- /dev/null +++ b/Platforms/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
From: Jan Dąbroś jsd@semihalf.com
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- Platforms/Marvell/Armada/Armada.dsc.inc | 1 + 1 file changed, 1 insertion(+)
diff --git a/Platforms/Marvell/Armada/Armada.dsc.inc b/Platforms/Marvell/Armada/Armada.dsc.inc index e9ce4cc..837f1b1 100644 --- a/Platforms/Marvell/Armada/Armada.dsc.inc +++ b/Platforms/Marvell/Armada/Armada.dsc.inc @@ -32,6 +32,7 @@ [LibraryClasses.common] ArmPlatformLib|OpenPlatformPkg/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.inf MppLib|OpenPlatformPkg/Platforms/Marvell/Library/MppLib/MppLib.inf + ParsePcdLib|OpenPlatformPkg/Platforms/Marvell/Library/ParsePcdLib/ParsePcdLib.inf
DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf UncachedMemoryAllocationLib|ArmPkg/Library/UncachedMemoryAllocationLib/UncachedMemoryAllocationLib.inf
From: Jan Dąbroś jsd@semihalf.com
In order to use numerous UEFI drivers based on PCI bus, PciEmulation driver is implemented. This solution is based on Chips/TexasInstruments/Omap35xx/PciEmulation/ Configuring fake devices is performed via PCD.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- .../Marvell/PortingGuide/PciEmulation.txt | 53 ++ Platforms/Marvell/Marvell.dec | 8 + Platforms/Marvell/PciEmulation/PciEmulation.c | 648 +++++++++++++++++++++ Platforms/Marvell/PciEmulation/PciEmulation.h | 275 +++++++++ Platforms/Marvell/PciEmulation/PciEmulation.inf | 65 +++ Platforms/Marvell/PciEmulation/PciRootBridgeIo.c | 300 ++++++++++ 6 files changed, 1349 insertions(+) create mode 100644 Documentation/Marvell/PortingGuide/PciEmulation.txt create mode 100644 Platforms/Marvell/PciEmulation/PciEmulation.c create mode 100644 Platforms/Marvell/PciEmulation/PciEmulation.h create mode 100644 Platforms/Marvell/PciEmulation/PciEmulation.inf create mode 100644 Platforms/Marvell/PciEmulation/PciRootBridgeIo.c
diff --git a/Documentation/Marvell/PortingGuide/PciEmulation.txt b/Documentation/Marvell/PortingGuide/PciEmulation.txt new file mode 100644 index 0000000..6fa33ac --- /dev/null +++ b/Documentation/Marvell/PortingGuide/PciEmulation.txt @@ -0,0 +1,53 @@ +PciEmulation configuration +-------------------------- +Instalation of various Pci devices via PciEmulation driver is performed via set +of PCDs. Following are available: + + gMarvellTokenSpaceGuid.PcdPciEDevCount + +Indicates how many fake Pci devices are placed on board. + +Next five PCDs are in unicode string format containing settings for all devices +separated with semicolon. + + gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress + +Indicates base address of Pci device register space. + + gMarvellTokenSpaceGuid.PcdPciEDevRegSize + +Indicates size of Pci device register space. + + gMarvellTokenSpaceGuid.PcdPciEDevClassCode1 + +Indicates device subclass code. + + gMarvellTokenSpaceGuid.PcdPciEDevClassCode2 + +Indicates device class code. + + gMarvellTokenSpaceGuid.PcdPciEDevClassCode3 + +Indicates Pci device class code. + +Examples +-------- +Assuming that there is two fake Pci xHCI controllers with register space +0xF2500000 - 0xF2510000 and 0xF2510000 - 0xF2520000 following PCDs values should +be set: + + gMarvellTokenSpaceGuid.PcdPciEDevCount|2 + gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress|L"0xF2500000;0xF2510000" + gMarvellTokenSpaceGuid.PcdPciEDevRegSize|L"0x10000;0x10000" + ## XHCI subclass + gMarvellTokenSpaceGuid.PcdPciEDevClassCode1|L"0x30;0x30" + ## USB controller class + gMarvellTokenSpaceGuid.PcdPciEDevClassCode2|L"0x03;0x03" + ## Serial bus controller Pci device class + gMarvellTokenSpaceGuid.PcdPciEDevClassCode3|L"0x0C;0x0C" + +Notes +----- +1.In order to find proper values for Pci class codes, please refer to + PCI Local Bus Specification. +2.PCDs are configured via UNICODE strings - remember to add L marker. diff --git a/Platforms/Marvell/Marvell.dec b/Platforms/Marvell/Marvell.dec index 7a53961..30275f5 100644 --- a/Platforms/Marvell/Marvell.dec +++ b/Platforms/Marvell/Marvell.dec @@ -137,6 +137,14 @@ gMarvellTokenSpaceGuid.PcdIcuSpiBase|0|UINT64|0x30000211 gMarvellTokenSpaceGuid.PcdIcuSpiOffset|0|UINT64|0x30000212
+#PciEmulation + gMarvellTokenSpaceGuid.PcdPciEDevCount|0|UINT32|0x30000058 + gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress|{ 0 }|VOID*|0x30000059 + gMarvellTokenSpaceGuid.PcdPciEDevRegSize|{ 0 }|VOID*|0x30000060 + gMarvellTokenSpaceGuid.PcdPciEDevClassCode1|{ 0 }|VOID*|0x30000061 + gMarvellTokenSpaceGuid.PcdPciEDevClassCode2|{ 0 }|VOID*|0x30000062 + gMarvellTokenSpaceGuid.PcdPciEDevClassCode3|{ 0 }|VOID*|0x30000063 + [Protocols] gEfiEepromProtocolGuid = { 0xcd728a1f, 0x45b5, 0x4feb, { 0x98, 0xc8, 0x31, 0x3d, 0xa8, 0x11, 0x74, 0x62 }} gEfiSpiMasterProtocolGuid = { 0x23de66a3, 0xf666, 0x4b3e, { 0xaa, 0xa2, 0x68, 0x9b, 0x18, 0xae, 0x2e, 0x19 }} diff --git a/Platforms/Marvell/PciEmulation/PciEmulation.c b/Platforms/Marvell/PciEmulation/PciEmulation.c new file mode 100644 index 0000000..586bb86 --- /dev/null +++ b/Platforms/Marvell/PciEmulation/PciEmulation.c @@ -0,0 +1,648 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> + 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 "PciEmulation.h" + +typedef struct { + ACPI_HID_DEVICE_PATH AcpiDevicePath; + PCI_DEVICE_PATH PciDevicePath; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +} EFI_PCI_IO_DEVICE_PATH; + +typedef struct { + UINT32 Signature; + EFI_PCI_IO_DEVICE_PATH DevicePath; + EFI_PCI_IO_PROTOCOL PciIoProtocol; + PCI_TYPE00 *ConfigSpace; + PCI_ROOT_BRIDGE RootBridge; + UINTN Segment; +} EFI_PCI_IO_PRIVATE_DATA; + +#define EFI_PCI_IO_PRIVATE_DATA_SIGNATURE SIGNATURE_32('p', 'c', 'i', 'o') +#define EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(a) CR(a, EFI_PCI_IO_PRIVATE_DATA, PciIoProtocol, EFI_PCI_IO_PRIVATE_DATA_SIGNATURE) + +EFI_PCI_IO_DEVICE_PATH PciIoDevicePathTemplate = +{ + { + { + ACPI_DEVICE_PATH, + ACPI_DP, + { + sizeof (ACPI_HID_DEVICE_PATH), + 0 + } + }, + EISA_PNP_ID(0x0A03), // HID + 0 // UID + }, + { + { + HARDWARE_DEVICE_PATH, + HW_PCI_DP, + { + sizeof (PCI_DEVICE_PATH), + 0 + } + }, + 0, + 0 + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + sizeof (EFI_DEVICE_PATH_PROTOCOL), + 0 + } + } +}; + +EFI_STATUS +PciIoPollMem ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + +EFI_STATUS +PciIoPollIo ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + +EFI_STATUS +PciIoMemRead ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This); + + return PciRootBridgeIoMemRead (&Private->RootBridge.Io, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Private->ConfigSpace->Device.Bar[BarIndex] + Offset, + Count, + Buffer); +} + +EFI_STATUS +PciIoMemWrite ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This); + + return PciRootBridgeIoMemWrite (&Private->RootBridge.Io, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Private->ConfigSpace->Device.Bar[BarIndex] + Offset, + Count, + Buffer); +} + +EFI_STATUS +PciIoIoRead ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + +EFI_STATUS +PciIoIoWrite ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + +/** + Enable a PCI driver to read PCI controller registers in PCI configuration space. + + @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param[in] Width Signifies the width of the memory operations. + @param[in] Offset The offset within the PCI configuration space for + the PCI controller. + @param[in] Count The number of PCI configuration operations to + perform. Bytes moved is Width size * Count, + starting at Offset. + + @param[in out] Buffer The destination buffer to store the results. + + @retval EFI_SUCCESS The data was read from the PCI controller. + @retval EFI_INVALID_PARAMETER "Width" is invalid. + @retval EFI_INVALID_PARAMETER "Buffer" is NULL. + +**/ +EFI_STATUS +PciIoPciRead ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT32 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This); + EFI_STATUS Status; + + if ((Width < 0) || (Width >= EfiPciIoWidthMaximum) || (Buffer == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Status = PciRootBridgeIoMemRW ( + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)Width, + Count, + TRUE, + (PTR)(UINTN)Buffer, + TRUE, + (PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset)); + + return Status; +} + +/** + Enable a PCI driver to write PCI controller registers in PCI configuration space. + + @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param[in] Width Signifies the width of the memory operations. + @param[in] Offset The offset within the PCI configuration space for + the PCI controller. + @param[in] Count The number of PCI configuration operations to + perform. Bytes moved is Width size * Count, + starting at Offset. + + @param[in out] Buffer The source buffer to write data from. + + @retval EFI_SUCCESS The data was read from the PCI controller. + @retval EFI_INVALID_PARAMETER "Width" is invalid. + @retval EFI_INVALID_PARAMETER "Buffer" is NULL. + +**/ +EFI_STATUS +PciIoPciWrite ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT32 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This); + + if ((Width < 0) || (Width >= EfiPciIoWidthMaximum) || (Buffer == NULL)) { + return EFI_INVALID_PARAMETER; + } + + return PciRootBridgeIoMemRW ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Count, + TRUE, + (PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset), + TRUE, + (PTR)(UINTN)Buffer); +} + +EFI_STATUS +PciIoCopyMem ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 DestBarIndex, + IN UINT64 DestOffset, + IN UINT8 SrcBarIndex, + IN UINT64 SrcOffset, + IN UINTN Count + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + +EFI_STATUS +PciIoMap ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +{ + DMA_MAP_OPERATION DmaOperation; + + if (Operation == EfiPciIoOperationBusMasterRead) { + DmaOperation = MapOperationBusMasterRead; + } else if (Operation == EfiPciIoOperationBusMasterWrite) { + DmaOperation = MapOperationBusMasterWrite; + } else if (Operation == EfiPciIoOperationBusMasterCommonBuffer) { + DmaOperation = MapOperationBusMasterCommonBuffer; + } else { + return EFI_INVALID_PARAMETER; + } + return DmaMap (DmaOperation, HostAddress, NumberOfBytes, DeviceAddress, + Mapping); +} + +EFI_STATUS +PciIoUnmap ( + IN EFI_PCI_IO_PROTOCOL *This, + IN VOID *Mapping + ) +{ + return DmaUnmap (Mapping); +} + +/** + Allocate pages that are suitable for an EfiPciIoOperationBusMasterCommonBuffer + mapping. + + @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param[in] Type This parameter is not used and must be ignored. + @param[in] MemoryType The type of memory to allocate, EfiBootServicesData or + EfiRuntimeServicesData. + @param[in] Pages The number of pages to allocate. + @param[out] HostAddress A pointer to store the base system memory address of + the allocated range. + @param[in] Attributes The requested bit mask of attributes for the allocated + range. Only the attributes, + EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE and + EFI_PCI_ATTRIBUTE_MEMORY_CACHED may be used with this + function. If any other bits are set, then EFI_UNSUPPORTED + is returned. This function ignores this bit mask. + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_INVALID_PARAMETER HostAddress is NULL. + @retval EFI_INVALID_PARAMETER MemoryType is invalid. + @retval EFI_UNSUPPORTED Attributes is unsupported. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +EFI_STATUS +PciIoAllocateBuffer ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress, + IN UINT64 Attributes + ) +{ + if (Attributes & + (~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | + EFI_PCI_ATTRIBUTE_MEMORY_CACHED ))) { + return EFI_UNSUPPORTED; + } + + return DmaAllocateBuffer (MemoryType, Pages, HostAddress); +} + + +EFI_STATUS +PciIoFreeBuffer ( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINTN Pages, + IN VOID *HostAddress + ) +{ + return DmaFreeBuffer (Pages, HostAddress); +} + + +EFI_STATUS +PciIoFlush ( + IN EFI_PCI_IO_PROTOCOL *This + ) +{ + return EFI_SUCCESS; +} + +/** + Retrieves this PCI controller's current PCI bus number, device number, and function number. + + @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param[out] SegmentNumber The PCI controller's current PCI segment number. + @param[out] BusNumber The PCI controller's current PCI bus number. + @param[out] DeviceNumber The PCI controller's current PCI device number. + @param[out] FunctionNumber The PCI controller’s current PCI function number. + + @retval EFI_SUCCESS The PCI controller location was returned. + @retval EFI_INVALID_PARAMETER At least one out of the four output parameters is + a NULL pointer. +**/ +EFI_STATUS +PciIoGetLocation ( + IN EFI_PCI_IO_PROTOCOL *This, + OUT UINTN *SegmentNumber, + OUT UINTN *BusNumber, + OUT UINTN *DeviceNumber, + OUT UINTN *FunctionNumber + ) +{ + EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This); + + if ((SegmentNumber == NULL) || (BusNumber == NULL) || + (DeviceNumber == NULL) || (FunctionNumber == NULL) ) { + return EFI_INVALID_PARAMETER; + } + + *SegmentNumber = Private->Segment; + *BusNumber = 0xff; + *DeviceNumber = 0; + *FunctionNumber = 0; + + return EFI_SUCCESS; +} + +/** + Performs an operation on the attributes that this PCI controller supports. + + The operations include getting the set of supported attributes, retrieving + the current attributes, setting the current attributes, enabling attributes, + and disabling attributes. + + @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param[in] Operation The operation to perform on the attributes for this + PCI controller. + @param[in] Attributes The mask of attributes that are used for Set, + Enable and Disable operations. + @param[out] Result A pointer to the result mask of attributes that are + returned for the Get and Supported operations. This + is an optional parameter that may be NULL for the + Set, Enable, and Disable operations. + + @retval EFI_SUCCESS The operation on the PCI controller's + attributes was completed. If the operation + was Get or Supported, then the attribute mask + is returned in Result. + @retval EFI_INVALID_PARAMETER Operation is greater than or equal to + EfiPciIoAttributeOperationMaximum. + @retval EFI_INVALID_PARAMETER Operation is Get and Result is NULL. + @retval EFI_INVALID_PARAMETER Operation is Supported and Result is NULL. + +**/ +EFI_STATUS +PciIoAttributes ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation, + IN UINT64 Attributes, + OUT UINT64 *Result OPTIONAL + ) +{ + switch (Operation) { + case EfiPciIoAttributeOperationGet: + case EfiPciIoAttributeOperationSupported: + if (Result == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // We are not a real PCI device so just say things we kind of do + // + *Result = EFI_PCI_DEVICE_ENABLE; + break; + + case EfiPciIoAttributeOperationSet: + case EfiPciIoAttributeOperationEnable: + case EfiPciIoAttributeOperationDisable: + if (Attributes & (~EFI_PCI_DEVICE_ENABLE)) { + return EFI_UNSUPPORTED; + } + // Since we are not a real PCI device no enable/set or disable operations exist. + return EFI_SUCCESS; + + default: + return EFI_INVALID_PARAMETER; + }; + return EFI_SUCCESS; +} + +EFI_STATUS +PciIoGetBarAttributes ( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINT8 BarIndex, + OUT UINT64 *Supports, OPTIONAL + OUT VOID **Resources OPTIONAL + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + +EFI_STATUS +PciIoSetBarAttributes ( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN UINT8 BarIndex, + IN OUT UINT64 *Offset, + IN OUT UINT64 *Length + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + +EFI_PCI_IO_PROTOCOL PciIoTemplate = +{ + PciIoPollMem, + PciIoPollIo, + { PciIoMemRead, PciIoMemWrite }, + { PciIoIoRead, PciIoIoWrite }, + { PciIoPciRead, PciIoPciWrite }, + PciIoCopyMem, + PciIoMap, + PciIoUnmap, + PciIoAllocateBuffer, + PciIoFreeBuffer, + PciIoFlush, + PciIoGetLocation, + PciIoAttributes, + PciIoGetBarAttributes, + PciIoSetBarAttributes, + 0, + 0 +}; + +STATIC +EFI_STATUS +EFIAPI +InstallDevices ( + IN UINTN DeviceId, + IN UINTN BaseAddr, + IN UINTN AddressSpaceSize, + IN UINTN ClassCode1, + IN UINTN ClassCode2, + IN UINTN ClassCode3 + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + EFI_PCI_IO_PRIVATE_DATA *Private; + + // Create a private structure + Private = AllocatePool(sizeof(EFI_PCI_IO_PRIVATE_DATA)); + if (Private == NULL) { + Status = EFI_OUT_OF_RESOURCES; + return Status; + } + + Private->Signature = EFI_PCI_IO_PRIVATE_DATA_SIGNATURE; // Fill in signature + Private->RootBridge.Signature = PCI_ROOT_BRIDGE_SIGNATURE; // Fake Root Bridge structure needs a signature too + Private->RootBridge.MemoryStart = BaseAddr; // Get the register base + Private->Segment = 0; // Default to segment zero + + // Calculate the total size of device registers. + Private->RootBridge.MemorySize = AddressSpaceSize; + + // Create fake PCI config space. + Private->ConfigSpace = AllocateZeroPool(sizeof(PCI_TYPE00)); + if (Private->ConfigSpace == NULL) { + Status = EFI_OUT_OF_RESOURCES; + FreePool(Private); + return Status; + } + + // Configure PCI config space + Private->ConfigSpace->Hdr.VendorId = 0xFFFF; // Invalid vendor Id as it is not an actual device. + Private->ConfigSpace->Hdr.DeviceId = 0x0000; // Not relevant as the vendor id is not valid. + Private->ConfigSpace->Hdr.ClassCode[0] = ClassCode1; + Private->ConfigSpace->Hdr.ClassCode[1] = ClassCode2; + Private->ConfigSpace->Hdr.ClassCode[2] = ClassCode3; + Private->ConfigSpace->Device.Bar[0] = Private->RootBridge.MemoryStart; + + Handle = NULL; + + // Unique device path. + CopyMem(&Private->DevicePath, &PciIoDevicePathTemplate, + sizeof(PciIoDevicePathTemplate)); + Private->DevicePath.AcpiDevicePath.UID = 0; + Private->DevicePath.PciDevicePath.Device = DeviceId; + + // Copy protocol structure + CopyMem(&Private->PciIoProtocol, &PciIoTemplate, sizeof(PciIoTemplate)); + + Status = gBS->InstallMultipleProtocolInterfaces(&Handle, + &gEfiPciIoProtocolGuid, + &Private->PciIoProtocol, + &gEfiDevicePathProtocolGuid, + &Private->DevicePath, + NULL); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR, "PciEmulation: InstallMultipleProtocolInterfaces" + "failed\n")); + } + + return Status; +} + +EFI_STATUS +EFIAPI +PciEmulationEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + UINT8 i, DevCount; + UINTN BaseAddrTable[PcdGet32 (PcdPciEDevCount)]; + UINTN RegSizeTable[PcdGet32 (PcdPciEDevCount)]; + UINTN DevClass1Table[PcdGet32 (PcdPciEDevCount)]; + UINTN DevClass2Table[PcdGet32 (PcdPciEDevCount)]; + UINTN DevClass3Table[PcdGet32 (PcdPciEDevCount)]; + + DevCount = PcdGet32 (PcdPciEDevCount); + + Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevBaseAddress), + DevCount, BaseAddrTable, NULL); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevBaseAddress format\n")); + return EFI_INVALID_PARAMETER; + } + + Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevRegSize), DevCount, + RegSizeTable, NULL); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevRegSize format\n")); + return EFI_INVALID_PARAMETER; + } + + Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevClassCode1), + DevCount, DevClass1Table, NULL); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevClassCode1 format\n")); + return EFI_INVALID_PARAMETER; + } + + Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevClassCode2), + DevCount, DevClass2Table, NULL); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevClassCode2 format\n")); + return EFI_INVALID_PARAMETER; + } + + Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevClassCode3), + DevCount, DevClass3Table, NULL); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevClassCode3 format\n")); + return EFI_INVALID_PARAMETER; + } + + for (i = 0; i < DevCount; i++) { + Status = InstallDevices (i, BaseAddrTable[i], RegSizeTable[i], + DevClass1Table[i], DevClass2Table[i], DevClass3Table[i]); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "PciEmulation: Cannot install device with ID=%d\n", + i)); + } + } + + return Status; +} diff --git a/Platforms/Marvell/PciEmulation/PciEmulation.h b/Platforms/Marvell/PciEmulation/PciEmulation.h new file mode 100644 index 0000000..536b236 --- /dev/null +++ b/Platforms/Marvell/PciEmulation/PciEmulation.h @@ -0,0 +1,275 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> + 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. + +**/ + +#ifndef _PCI_ROOT_BRIDGE_H_ +#define _PCI_ROOT_BRIDGE_H_ + +#include <PiDxe.h> + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/DxeServicesTableLib.h> +#include <Library/IoLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/PciLib.h> +#include <Library/UefiLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/DmaLib.h> +#include <Library/PcdLib.h> +#include <Library/ParsePcdLib.h> + +#include <Protocol/EmbeddedExternalDevice.h> +#include <Protocol/DevicePath.h> +#include <Protocol/PciIo.h> +#include <Protocol/PciRootBridgeIo.h> +#include <Protocol/PciHostBridgeResourceAllocation.h> + +#include <IndustryStandard/Pci22.h> +#include <IndustryStandard/Acpi.h> +#include <IndustryStandard/PciCodeId.h> + +#define EFI_RESOURCE_NONEXISTENT 0xFFFFFFFFFFFFFFFFULL +#define EFI_RESOURCE_LESS 0xFFFFFFFFFFFFFFFEULL +#define EFI_RESOURCE_SATISFIED 0x0000000000000000ULL + +typedef struct { + ACPI_HID_DEVICE_PATH AcpiDevicePath; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH; + +#define ACPI_CONFIG_IO 0 +#define ACPI_CONFIG_MMIO 1 +#define ACPI_CONFIG_BUS 2 + +typedef struct { + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR Desc[3]; + EFI_ACPI_END_TAG_DESCRIPTOR EndDesc; +} ACPI_CONFIG_INFO; + +#define PCI_ROOT_BRIDGE_SIGNATURE SIGNATURE_32 ('P', 'c', 'i', 'F') + +typedef struct { + UINT32 Signature; + EFI_HANDLE Handle; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL Io; + EFI_PCI_ROOT_BRIDGE_DEVICE_PATH DevicePath; + + UINT8 StartBus; + UINT8 EndBus; + UINT16 Type; + UINT32 MemoryStart; + UINT32 MemorySize; + UINTN IoOffset; + UINT32 IoStart; + UINT32 IoSize; + UINT64 PciAttributes; + + ACPI_CONFIG_INFO *Config; + +} PCI_ROOT_BRIDGE; + +#define INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(a) CR (a, PCI_ROOT_BRIDGE, Io, PCI_ROOT_BRIDGE_SIGNATURE) + +typedef union { + UINT8 volatile *buf; + UINT8 volatile *ui8; + UINT16 volatile *ui16; + UINT32 volatile *ui32; + UINT64 volatile *ui64; + UINTN volatile ui; +} PTR; + +EFI_STATUS +EFIAPI +PciRootBridgeIoPollMem ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoPollIo ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoMemRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoMemWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoIoRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoIoWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoCopyMem ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 DestAddress, + IN UINT64 SrcAddress, + IN UINTN Count + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoPciRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoPciWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoMap ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoUnmap ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN VOID *Mapping + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoAllocateBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress, + IN UINT64 Attributes + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoFreeBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINTN Pages, + OUT VOID *HostAddress + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoFlush ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoGetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT UINT64 *Supported, + OUT UINT64 *Attributes + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoSetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN OUT UINT64 *ResourceBase, + IN OUT UINT64 *ResourceLength + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoConfiguration ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT VOID **Resources + ); + +// +// Private Function Prototypes +// +EFI_STATUS +EFIAPI +PciRootBridgeIoMemRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINTN Count, + IN BOOLEAN InStrideFlag, + IN PTR In, + IN BOOLEAN OutStrideFlag, + OUT PTR Out + ); + +BOOLEAN +PciIoMemAddressValid ( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINT64 Address + ); +#endif diff --git a/Platforms/Marvell/PciEmulation/PciEmulation.inf b/Platforms/Marvell/PciEmulation/PciEmulation.inf new file mode 100644 index 0000000..59a0650 --- /dev/null +++ b/Platforms/Marvell/PciEmulation/PciEmulation.inf @@ -0,0 +1,65 @@ +/** @file + + Copyright (c) 2009, Apple Inc. All rights reserved.<BR> + 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. + +**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PciEmulation + FILE_GUID = 3dfa08da-923b-4841-9435-c77a604d7493 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = PciEmulationEntryPoint + +[Sources.common] + PciRootBridgeIo.c + PciEmulation.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + ArmPkg/ArmPkg.dec + ShellPkg/ShellPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + OpenPlatformPkg/Platforms/Marvell/Marvell.dec + +[LibraryClasses] + BaseLib + DxeServicesTableLib + UefiLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + ParsePcdLib + IoLib + DmaLib + +[Protocols] + gEfiPciRootBridgeIoProtocolGuid + gEfiDevicePathProtocolGuid + gEfiPciHostBridgeResourceAllocationProtocolGuid + gEfiPciIoProtocolGuid + gEmbeddedExternalDeviceProtocolGuid + +[Pcd] + gMarvellTokenSpaceGuid.PcdPciEDevCount + gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress + gMarvellTokenSpaceGuid.PcdPciEDevRegSize + gMarvellTokenSpaceGuid.PcdPciEDevClassCode1 + gMarvellTokenSpaceGuid.PcdPciEDevClassCode2 + gMarvellTokenSpaceGuid.PcdPciEDevClassCode3 + +[Depex] + TRUE diff --git a/Platforms/Marvell/PciEmulation/PciRootBridgeIo.c b/Platforms/Marvell/PciEmulation/PciRootBridgeIo.c new file mode 100644 index 0000000..4b2ca88 --- /dev/null +++ b/Platforms/Marvell/PciEmulation/PciRootBridgeIo.c @@ -0,0 +1,300 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> + 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 "PciEmulation.h" + +BOOLEAN +PciRootBridgeMemAddressValid ( + IN PCI_ROOT_BRIDGE *Private, + IN UINT64 Address + ) +{ + if ((Address >= Private->MemoryStart) && (Address < (Private->MemoryStart + Private->MemorySize))) { + return TRUE; + } + + return FALSE; +} + +EFI_STATUS +PciRootBridgeIoMemRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINTN Count, + IN BOOLEAN InStrideFlag, + IN PTR In, + IN BOOLEAN OutStrideFlag, + OUT PTR Out + ) +{ + UINTN Stride; + UINTN InStride; + UINTN OutStride; + + + Width = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) (Width & 0x03); + Stride = (UINTN)1 << Width; + InStride = InStrideFlag ? Stride : 0; + OutStride = OutStrideFlag ? Stride : 0; + + // + // Loop for each iteration and move the data + // + switch (Width) { + case EfiPciWidthUint8: + for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) { + *In.ui8 = *Out.ui8; + } + break; + case EfiPciWidthUint16: + for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) { + *In.ui16 = *Out.ui16; + } + break; + case EfiPciWidthUint32: + for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) { + *In.ui32 = *Out.ui32; + } + break; + default: + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +PciRootBridgeIoPciRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN BOOLEAN Write, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ) +{ + return EFI_SUCCESS; +} + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Width Signifies the width of the memory operations. + @param Address The base address of the memory operations. + @param Count The number of memory operations to perform. + @param Buffer For read operations, the destination buffer to store the results. For write + operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoMemRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + PCI_ROOT_BRIDGE *Private; + UINTN AlignMask; + PTR In; + PTR Out; + + if ( Buffer == NULL ) { + return EFI_INVALID_PARAMETER; + } + + Private = INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This); + + if (!PciRootBridgeMemAddressValid (Private, Address)) { + return EFI_INVALID_PARAMETER; + } + + AlignMask = (1 << (Width & 0x03)) - 1; + if (Address & AlignMask) { + return EFI_INVALID_PARAMETER; + } + + In.buf = Buffer; + Out.buf = (VOID *)(UINTN) Address; + + switch (Width) { + case EfiPciWidthUint8: + case EfiPciWidthUint16: + case EfiPciWidthUint32: + case EfiPciWidthUint64: + return PciRootBridgeIoMemRW (Width, Count, TRUE, In, TRUE, Out); + + case EfiPciWidthFifoUint8: + case EfiPciWidthFifoUint16: + case EfiPciWidthFifoUint32: + case EfiPciWidthFifoUint64: + return PciRootBridgeIoMemRW (Width, Count, TRUE, In, FALSE, Out); + + case EfiPciWidthFillUint8: + case EfiPciWidthFillUint16: + case EfiPciWidthFillUint32: + case EfiPciWidthFillUint64: + return PciRootBridgeIoMemRW (Width, Count, FALSE, In, TRUE, Out); + + default: + break; + } + + return EFI_INVALID_PARAMETER; +} + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Width Signifies the width of the memory operations. + @param Address The base address of the memory operations. + @param Count The number of memory operations to perform. + @param Buffer For read operations, the destination buffer to store the results. For write + operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoMemWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + PCI_ROOT_BRIDGE *Private; + UINTN AlignMask; + PTR In; + PTR Out; + + if ( Buffer == NULL ) { + return EFI_INVALID_PARAMETER; + } + + Private = INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This); + + if (!PciRootBridgeMemAddressValid (Private, Address)) { + return EFI_INVALID_PARAMETER; + } + + AlignMask = (1 << (Width & 0x03)) - 1; + if (Address & AlignMask) { + return EFI_INVALID_PARAMETER; + } + + In.buf = (VOID *)(UINTN) Address; + Out.buf = Buffer; + + switch (Width) { + case EfiPciWidthUint8: + case EfiPciWidthUint16: + case EfiPciWidthUint32: + case EfiPciWidthUint64: + return PciRootBridgeIoMemRW (Width, Count, TRUE, In, TRUE, Out); + + case EfiPciWidthFifoUint8: + case EfiPciWidthFifoUint16: + case EfiPciWidthFifoUint32: + case EfiPciWidthFifoUint64: + return PciRootBridgeIoMemRW (Width, Count, FALSE, In, TRUE, Out); + + case EfiPciWidthFillUint8: + case EfiPciWidthFillUint16: + case EfiPciWidthFillUint32: + case EfiPciWidthFillUint64: + return PciRootBridgeIoMemRW (Width, Count, TRUE, In, FALSE, Out); + + default: + break; + } + + return EFI_INVALID_PARAMETER; +} + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Width Signifies the width of the memory operations. + @param Address The base address of the memory operations. + @param Count The number of memory operations to perform. + @param Buffer For read operations, the destination buffer to store the results. For write + operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoPciRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + return PciRootBridgeIoPciRW (This, FALSE, Width, Address, Count, Buffer); +} + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Width Signifies the width of the memory operations. + @param Address The base address of the memory operations. + @param Count The number of memory operations to perform. + @param Buffer For read operations, the destination buffer to store the results. For write + operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoPciWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + return PciRootBridgeIoPciRW (This, TRUE, Width, Address, Count, Buffer); +}
From: Jan Dąbroś jsd@semihalf.com
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- Platforms/Marvell/Armada/Armada.dsc.inc | 2 ++ Platforms/Marvell/Armada/Armada7040.fdf | 3 +++ 2 files changed, 5 insertions(+)
diff --git a/Platforms/Marvell/Armada/Armada.dsc.inc b/Platforms/Marvell/Armada/Armada.dsc.inc index 837f1b1..5d0be44 100644 --- a/Platforms/Marvell/Armada/Armada.dsc.inc +++ b/Platforms/Marvell/Armada/Armada.dsc.inc @@ -404,6 +404,8 @@
OpenPlatformPkg/Drivers/Ramdisk/Ramdisk.inf
+ OpenPlatformPkg/Platforms/Marvell/PciEmulation/PciEmulation.inf + # Console packages MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf diff --git a/Platforms/Marvell/Armada/Armada7040.fdf b/Platforms/Marvell/Armada/Armada7040.fdf index 537e637..66e6732 100644 --- a/Platforms/Marvell/Armada/Armada7040.fdf +++ b/Platforms/Marvell/Armada/Armada7040.fdf @@ -109,6 +109,9 @@ FvNameGuid = 5eda4200-2c5f-43cb-9da3-0baf74b1b30c INF OpenPlatformPkg/Drivers/Spi/Devices/MvSpiFlash.inf INF OpenPlatformPkg/Drivers/Ramdisk/Ramdisk.inf
+ # PciEmulation + INF OpenPlatformPkg/Platforms/Marvell/PciEmulation/PciEmulation.inf + # Multiple Console IO support INF MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf INF MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf
From: Jan Dąbroś jsd@semihalf.com
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- Platforms/Marvell/Armada/Armada.dsc.inc | 5 +++++ Platforms/Marvell/Armada/Armada7040.fdf | 5 +++++ 2 files changed, 10 insertions(+)
diff --git a/Platforms/Marvell/Armada/Armada.dsc.inc b/Platforms/Marvell/Armada/Armada.dsc.inc index 5d0be44..cacf124 100644 --- a/Platforms/Marvell/Armada/Armada.dsc.inc +++ b/Platforms/Marvell/Armada/Armada.dsc.inc @@ -406,6 +406,11 @@
OpenPlatformPkg/Platforms/Marvell/PciEmulation/PciEmulation.inf
+ # USB + MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf + MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf + MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf + # Console packages MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf diff --git a/Platforms/Marvell/Armada/Armada7040.fdf b/Platforms/Marvell/Armada/Armada7040.fdf index 66e6732..e3d5883 100644 --- a/Platforms/Marvell/Armada/Armada7040.fdf +++ b/Platforms/Marvell/Armada/Armada7040.fdf @@ -112,6 +112,11 @@ FvNameGuid = 5eda4200-2c5f-43cb-9da3-0baf74b1b30c # PciEmulation INF OpenPlatformPkg/Platforms/Marvell/PciEmulation/PciEmulation.inf
+ # USB + INF MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf + INF MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf + INF MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf + # Multiple Console IO support INF MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf INF MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf
From: Jan Dąbroś jsd@semihalf.com
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- Documentation/Marvell/UserGuide.txt | 1 + Platforms/Marvell/Armada/Armada7040_rz.dsc | 12 ++++++++++++ 2 files changed, 13 insertions(+)
diff --git a/Documentation/Marvell/UserGuide.txt b/Documentation/Marvell/UserGuide.txt index fcd5b0b..27a23f3 100644 --- a/Documentation/Marvell/UserGuide.txt +++ b/Documentation/Marvell/UserGuide.txt @@ -14,6 +14,7 @@ Table of contents: reset library - PortingGuide/Reset.txt spi - PortingGuide/Spi.txt spi flash - PortingGuide/SpiFlash.txt + usb - PortingGuide/PciEmulation.txt
3. Drivers guidelines eeprom - Drivers/EepromDriver.txt diff --git a/Platforms/Marvell/Armada/Armada7040_rz.dsc b/Platforms/Marvell/Armada/Armada7040_rz.dsc index 0bdf506..41a0d30 100644 --- a/Platforms/Marvell/Armada/Armada7040_rz.dsc +++ b/Platforms/Marvell/Armada/Armada7040_rz.dsc @@ -103,3 +103,15 @@ gMarvellTokenSpaceGuid.PcdIcuCpBase|0xF2000000 gMarvellTokenSpaceGuid.PcdIcuSpiBase|64 gMarvellTokenSpaceGuid.PcdIcuSpiOffset|0 + + #PciEmulation + gMarvellTokenSpaceGuid.PcdPciEDevCount|2 + ## XHCI1 XHCI2 + gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress|L"0xF2500000;0xF2510000" + gMarvellTokenSpaceGuid.PcdPciEDevRegSize|L"0x10000;0x10000" + ## ClassCode1 + gMarvellTokenSpaceGuid.PcdPciEDevClassCode1|L"0x30;0x30" + ## ClassCode2 + gMarvellTokenSpaceGuid.PcdPciEDevClassCode2|L"0x03;0x03" + ## ClassCode3 + gMarvellTokenSpaceGuid.PcdPciEDevClassCode3|L"0x0C;0x0C"
From: Jan Dąbroś jsd@semihalf.com
Improve PciEmulation driver in order to support SATA controllers. This patch also add workaround for Cp110 chip, where SATA controller isn't fully compatible with AHCI standard.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- Documentation/Marvell/PortingGuide/Sata.txt | 16 ++++++++ Documentation/Marvell/UserGuide.txt | 1 + Platforms/Marvell/Marvell.dec | 4 ++ Platforms/Marvell/PciEmulation/PciEmulation.c | 54 ++++++++++++++++++++++++- Platforms/Marvell/PciEmulation/PciEmulation.h | 6 +++ Platforms/Marvell/PciEmulation/PciEmulation.inf | 2 + 6 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 Documentation/Marvell/PortingGuide/Sata.txt
diff --git a/Documentation/Marvell/PortingGuide/Sata.txt b/Documentation/Marvell/PortingGuide/Sata.txt new file mode 100644 index 0000000..f76923d --- /dev/null +++ b/Documentation/Marvell/PortingGuide/Sata.txt @@ -0,0 +1,16 @@ +SATA configuration +------------------ +In order to add new SATA device, please refer to document describing +PciEmulation - /path/to/opp/Documenation/Marvell/PortingGuide/PciEmulation.txt + +There are also two additional PCDs: + + gMarvellTokenSpaceGuid.PcdSataBaseAddress + +Base address of SATA controller register space - used in SATA ComPhy init +sequence. + + gMarvellTokenSpaceGuid.PcdSataMapPortAddress + +Boolean indicating if controller on platform needs specific address mapping for +SATA ports. diff --git a/Documentation/Marvell/UserGuide.txt b/Documentation/Marvell/UserGuide.txt index 27a23f3..5d3612e 100644 --- a/Documentation/Marvell/UserGuide.txt +++ b/Documentation/Marvell/UserGuide.txt @@ -12,6 +12,7 @@ Table of contents: mpp - PortingGuide/Mpp.txt ramdisk - PortingGuide/Ramdisk.txt reset library - PortingGuide/Reset.txt + sata - PortingGuide/Sata.txt spi - PortingGuide/Spi.txt spi flash - PortingGuide/SpiFlash.txt usb - PortingGuide/PciEmulation.txt diff --git a/Platforms/Marvell/Marvell.dec b/Platforms/Marvell/Marvell.dec index 30275f5..6df6268 100644 --- a/Platforms/Marvell/Marvell.dec +++ b/Platforms/Marvell/Marvell.dec @@ -145,6 +145,10 @@ gMarvellTokenSpaceGuid.PcdPciEDevClassCode2|{ 0 }|VOID*|0x30000062 gMarvellTokenSpaceGuid.PcdPciEDevClassCode3|{ 0 }|VOID*|0x30000063
+#SATA + gMarvellTokenSpaceGuid.PcdSataBaseAddress|0|UINT32|0x4000052 + gMarvellTokenSpaceGuid.PcdSataMapPortAddress|FALSE|BOOLEAN|0x4000053 + [Protocols] gEfiEepromProtocolGuid = { 0xcd728a1f, 0x45b5, 0x4feb, { 0x98, 0xc8, 0x31, 0x3d, 0xa8, 0x11, 0x74, 0x62 }} gEfiSpiMasterProtocolGuid = { 0x23de66a3, 0xf666, 0x4b3e, { 0xaa, 0xa2, 0x68, 0x9b, 0x18, 0xae, 0x2e, 0x19 }} diff --git a/Platforms/Marvell/PciEmulation/PciEmulation.c b/Platforms/Marvell/PciEmulation/PciEmulation.c index 586bb86..236838a 100644 --- a/Platforms/Marvell/PciEmulation/PciEmulation.c +++ b/Platforms/Marvell/PciEmulation/PciEmulation.c @@ -69,6 +69,30 @@ EFI_PCI_IO_DEVICE_PATH PciIoDevicePathTemplate = } };
+STATIC +UINT64 +MapSataPortAddress ( + IN UINT64 Offset + ) +{ + + // + // Since AHCI controller in CP110 isn't compatible with AHCI specification, + // below workaround is necessary. It maps PORT address' offsets. + // + // PORT | AHCI port offset | CP110 port offset + // -------------------------------------------------------- + // 1 | 100h - 180h | 10000h - 1080h + // 2 | 180h - 260h | 20000h - 2080h + // + if ((Offset > 0x100) && (Offset < 0x180)) + Offset = (Offset - 0x100) + 0x10000; + if ((Offset > 0x180) && (Offset < 0x260)) + Offset = (Offset - 0x180) + 0x20000; + + return Offset; +} + EFI_STATUS PciIoPollMem ( IN EFI_PCI_IO_PROTOCOL *This, @@ -113,6 +137,10 @@ PciIoMemRead ( { EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);
+ if (BarIndex == EFI_AHCI_BAR_INDEX && PcdGetBool (PcdSataMapPortAddress)) { + Offset = MapSataPortAddress (Offset); + } + return PciRootBridgeIoMemRead (&Private->RootBridge.Io, (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, Private->ConfigSpace->Device.Bar[BarIndex] + Offset, @@ -132,6 +160,10 @@ PciIoMemWrite ( { EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);
+ if (BarIndex == EFI_AHCI_BAR_INDEX && PcdGetBool (PcdSataMapPortAddress)) { + Offset = MapSataPortAddress (Offset); + } + return PciRootBridgeIoMemWrite (&Private->RootBridge.Io, (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, Private->ConfigSpace->Device.Bar[BarIndex] + Offset, @@ -526,6 +558,7 @@ InstallDevices ( EFI_STATUS Status; EFI_HANDLE Handle; EFI_PCI_IO_PRIVATE_DATA *Private; + UINT32 ClassCodes;
// Create a private structure Private = AllocatePool(sizeof(EFI_PCI_IO_PRIVATE_DATA)); @@ -556,7 +589,26 @@ InstallDevices ( Private->ConfigSpace->Hdr.ClassCode[0] = ClassCode1; Private->ConfigSpace->Hdr.ClassCode[1] = ClassCode2; Private->ConfigSpace->Hdr.ClassCode[2] = ClassCode3; - Private->ConfigSpace->Device.Bar[0] = Private->RootBridge.MemoryStart; + + // + // Concatenate ClassCodes into single number, which will be next used to + // recognize device add fill proper BAR + // + ClassCodes = (ClassCode1 << 16) + (ClassCode2 << 8) + ClassCode3; + + switch (ClassCodes) { + case XHCI_PCI_CLASS_CODE_NR: + Private->ConfigSpace->Device.Bar[EFI_XHCI_BAR_INDEX] = + Private->RootBridge.MemoryStart; + break; + case AHCI_PCI_CLASS_CODE_NR: + Private->ConfigSpace->Device.Bar[EFI_AHCI_BAR_INDEX] = + Private->RootBridge.MemoryStart; + break; + default: + DEBUG((EFI_D_ERROR, "PciEmulation: Unknown PCI device. Abort.\n")); + return EFI_D_ERROR; + }
Handle = NULL;
diff --git a/Platforms/Marvell/PciEmulation/PciEmulation.h b/Platforms/Marvell/PciEmulation/PciEmulation.h index 536b236..9dcd7e3 100644 --- a/Platforms/Marvell/PciEmulation/PciEmulation.h +++ b/Platforms/Marvell/PciEmulation/PciEmulation.h @@ -45,6 +45,12 @@ #define EFI_RESOURCE_LESS 0xFFFFFFFFFFFFFFFEULL #define EFI_RESOURCE_SATISFIED 0x0000000000000000ULL
+#define XHCI_PCI_CLASS_CODE_NR 0x30030C +#define AHCI_PCI_CLASS_CODE_NR 0x010601 + +#define EFI_XHCI_BAR_INDEX 0x0 +#define EFI_AHCI_BAR_INDEX 0x5 + typedef struct { ACPI_HID_DEVICE_PATH AcpiDevicePath; EFI_DEVICE_PATH_PROTOCOL EndDevicePath; diff --git a/Platforms/Marvell/PciEmulation/PciEmulation.inf b/Platforms/Marvell/PciEmulation/PciEmulation.inf index 59a0650..0df9eb1 100644 --- a/Platforms/Marvell/PciEmulation/PciEmulation.inf +++ b/Platforms/Marvell/PciEmulation/PciEmulation.inf @@ -61,5 +61,7 @@ gMarvellTokenSpaceGuid.PcdPciEDevClassCode2 gMarvellTokenSpaceGuid.PcdPciEDevClassCode3
+ gMarvellTokenSpaceGuid.PcdSataMapPortAddress + [Depex] TRUE
From: Jan Dąbroś jsd@semihalf.com
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- Platforms/Marvell/Armada/Armada.dsc.inc | 10 ++++++++++ Platforms/Marvell/Armada/Armada7040.fdf | 7 +++++++ 2 files changed, 17 insertions(+)
diff --git a/Platforms/Marvell/Armada/Armada.dsc.inc b/Platforms/Marvell/Armada/Armada.dsc.inc index cacf124..743c396 100644 --- a/Platforms/Marvell/Armada/Armada.dsc.inc +++ b/Platforms/Marvell/Armada/Armada.dsc.inc @@ -82,6 +82,7 @@ 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 @@ -406,6 +407,15 @@
OpenPlatformPkg/Platforms/Marvell/PciEmulation/PciEmulation.inf
+ #SCSI + MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf + MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf + + # SATA + OvmfPkg/SataControllerDxe/SataControllerDxe.inf + MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf + MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf + # USB MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf diff --git a/Platforms/Marvell/Armada/Armada7040.fdf b/Platforms/Marvell/Armada/Armada7040.fdf index e3d5883..8182777 100644 --- a/Platforms/Marvell/Armada/Armada7040.fdf +++ b/Platforms/Marvell/Armada/Armada7040.fdf @@ -111,6 +111,13 @@ FvNameGuid = 5eda4200-2c5f-43cb-9da3-0baf74b1b30c
# PciEmulation INF OpenPlatformPkg/Platforms/Marvell/PciEmulation/PciEmulation.inf + + INF MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf + INF MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf + + INF OvmfPkg/SataControllerDxe/SataControllerDxe.inf + INF MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf + INF MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf
# USB INF MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf
From: Jan Dąbroś jsd@semihalf.com
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- Platforms/Marvell/Armada/Armada7040_rz.dsc | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/Platforms/Marvell/Armada/Armada7040_rz.dsc b/Platforms/Marvell/Armada/Armada7040_rz.dsc index 41a0d30..a0cca95 100644 --- a/Platforms/Marvell/Armada/Armada7040_rz.dsc +++ b/Platforms/Marvell/Armada/Armada7040_rz.dsc @@ -105,13 +105,17 @@ gMarvellTokenSpaceGuid.PcdIcuSpiOffset|0
#PciEmulation - gMarvellTokenSpaceGuid.PcdPciEDevCount|2 - ## XHCI1 XHCI2 - gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress|L"0xF2500000;0xF2510000" - gMarvellTokenSpaceGuid.PcdPciEDevRegSize|L"0x10000;0x10000" + gMarvellTokenSpaceGuid.PcdPciEDevCount|3 + ## XHCI1 XHCI2 SATA + gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress|L"0xF2500000;0xF2510000;0xF2540000" + gMarvellTokenSpaceGuid.PcdPciEDevRegSize|L"0x10000;0x10000;0x30000" ## ClassCode1 - gMarvellTokenSpaceGuid.PcdPciEDevClassCode1|L"0x30;0x30" + gMarvellTokenSpaceGuid.PcdPciEDevClassCode1|L"0x30;0x30;0x01" ## ClassCode2 - gMarvellTokenSpaceGuid.PcdPciEDevClassCode2|L"0x03;0x03" + gMarvellTokenSpaceGuid.PcdPciEDevClassCode2|L"0x03;0x03;0x06" ## ClassCode3 - gMarvellTokenSpaceGuid.PcdPciEDevClassCode3|L"0x0C;0x0C" + gMarvellTokenSpaceGuid.PcdPciEDevClassCode3|L"0x0C;0x0C;0x01" + + #SATA + gMarvellTokenSpaceGuid.PcdSataBaseAddress|0xF2540000 + gMarvellTokenSpaceGuid.PcdSataMapPortAddress|TRUE
From: Jan Dąbroś jsd@semihalf.com
MvSdMmcPciHcDxe driver allows managing XENON controller produces EFI_SD_MMC_PASS_THRU_PROTOCOL to allow sending SD/MMC commands to specified devices from upper layer. This solution is based on SdMmcPciHcDxe from MdeModulePkg.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- Documentation/Marvell/UserGuide.txt | 1 + Drivers/Sd/MvSdMmcPciHcDxe.c | 1268 +++++++++++++++++++++++++++++++++++ Drivers/Sd/MvSdMmcPciHcDxe.inf | 75 +++ Drivers/Sd/XenonSdhci.c | 424 ++++++++++++ Drivers/Sd/XenonSdhci.h | 301 +++++++++ 5 files changed, 2069 insertions(+) create mode 100644 Drivers/Sd/MvSdMmcPciHcDxe.c create mode 100644 Drivers/Sd/MvSdMmcPciHcDxe.inf create mode 100644 Drivers/Sd/XenonSdhci.c create mode 100644 Drivers/Sd/XenonSdhci.h
diff --git a/Documentation/Marvell/UserGuide.txt b/Documentation/Marvell/UserGuide.txt index 5d3612e..6def7d8 100644 --- a/Documentation/Marvell/UserGuide.txt +++ b/Documentation/Marvell/UserGuide.txt @@ -13,6 +13,7 @@ Table of contents: ramdisk - PortingGuide/Ramdisk.txt reset library - PortingGuide/Reset.txt sata - PortingGuide/Sata.txt + sd/mmc - PortingGuide/PciEmulation.txt spi - PortingGuide/Spi.txt spi flash - PortingGuide/SpiFlash.txt usb - PortingGuide/PciEmulation.txt diff --git a/Drivers/Sd/MvSdMmcPciHcDxe.c b/Drivers/Sd/MvSdMmcPciHcDxe.c new file mode 100644 index 0000000..b1a4d71 --- /dev/null +++ b/Drivers/Sd/MvSdMmcPciHcDxe.c @@ -0,0 +1,1268 @@ +/** @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, Intel Corporation. All rights reserved.<BR> + Copyright (c) 2016, Marvell. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "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, UnknownSlot, 0, 0}, {0, UnknownSlot, 0, 0}, + {0, UnknownSlot, 0, 0}, {0, UnknownSlot, 0, 0}, {0, UnknownSlot, 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 == FALSE) { + 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 ((EFI_D_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 ((EFI_D_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; + + 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 == FALSE)) { + DEBUG ((EFI_D_INFO, "SdMmcPciHcEnumerateDevice: device disconnected at slot %d of pci %p\n", Slot, Private->PciIo)); + Private->Slot[Slot].MediaPresent = FALSE; + // + // Signal all async task events at the slot with EFI_NO_MEDIA status. + // + 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); + } + } + // + // 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 == TRUE)) { + DEBUG ((EFI_D_INFO, "SdMmcPciHcEnumerateDevice: device connected at slot %d of pci %p\n", Slot, Private->PciIo)); + // + // 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; + 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; + } + } + } + + // + // 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; + + DEBUG ((EFI_D_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); + + XenonReadVersion (PciIo, &Private->ControllerVersion); + + XenonSetFifo (PciIo); + + XenonSetAcg (PciIo, FALSE); + + // Hyperion has only one port + XenonSetSlot (PciIo, XENON_MMC_SLOT_ID_HYPERION, TRUE); + + XenonSetPower (PciIo, MMC_VDD_32_33, eMMC_VCCQ_3_3V, XENON_MMC_MODE_SD_SDIO); + + XenonSetClk (PciIo, Private, XENON_MMC_MAX_CLK); + + XenonSetPhy (PciIo, MMC_TIMING_UHS_SDR50); + + XenonConfigureInterrupts (PciIo); + + // Enable parallel transfer + XenonSetParallelTransfer (PciIo, XENON_MMC_SLOT_ID_HYPERION, TRUE); + + XenonSetTuning (PciIo, XENON_MMC_SLOT_ID_HYPERION, FALSE); + + XenonSetAcg (PciIo, TRUE); + + for (Slot = 0; Slot < (XENON_MMC_SLOT_ID_HYPERION + 1); Slot++) { + Private->Slot[Slot].Enable = TRUE; + + Status = SdMmcHcGetCapability (PciIo, Slot, &Private->Capability[Slot]); + if (EFI_ERROR (Status)) { + continue; + } + DumpCapabilityReg (Slot, &Private->Capability[Slot]); + + Status = SdMmcHcGetMaxCurrent (PciIo, Slot, &Private->MaxCurrent[Slot]); + if (EFI_ERROR (Status)) { + continue; + } + + Private->Slot[Slot].SlotType = Private->Capability[Slot].SlotType; + if ((Private->Slot[Slot].SlotType != RemovableSlot) && (Private->Slot[Slot].SlotType != EmbeddedSlot)) { + DEBUG ((EFI_D_INFO, "SdMmcPciHcDxe doesn't support the slot type [%d]!!!\n", Private->Slot[Slot].SlotType)); + continue; + } + + // + // Reset the specified slot of the SD/MMC Pci Host Controller + // + Status = SdMmcHcReset (PciIo, Slot); + if (EFI_ERROR (Status)) { + continue; + } + + Status = SdMmcHcInitHost (PciIo, Slot, Private->Capability[Slot]); + if (EFI_ERROR (Status)) { + continue; + } + + Private->Slot[Slot].MediaPresent = 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; + } + } + } + } + + // + // Start the asynchronous I/O monitor + // + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + 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 ((EFI_D_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 ((EFI_D_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 ((EFI_D_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; + } + + 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_CALLBACK); + 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; + } + // + // Free all async I/O requests in the queue + // + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + 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/Drivers/Sd/MvSdMmcPciHcDxe.inf b/Drivers/Sd/MvSdMmcPciHcDxe.inf new file mode 100644 index 0000000..e52188f --- /dev/null +++ b/Drivers/Sd/MvSdMmcPciHcDxe.inf @@ -0,0 +1,75 @@ +#/******************************************************************************* +#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 = MvSdMmcPciHcDxe + MODULE_UNI_FILE = ../../../MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.uni + FILE_GUID = 5b5b83b8-52b8-4d02-b92b-c84a4dfb539d + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeSdMmcPciHcDxe + +[Sources] + ../../../MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h + MvSdMmcPciHcDxe.c + ../../../MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c + ../../../MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdDevice.c + ../../../MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.h + ../../../MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c + ../../../MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/ComponentName.c + XenonSdhci.c + XenonSdhci.h + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + DevicePathLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + MemoryAllocationLib + BaseMemoryLib + UefiLib + BaseLib + UefiDriverEntryPoint + DebugLib + +[Protocols] + gEfiDevicePathProtocolGuid ## TO_START + gEfiPciIoProtocolGuid ## TO_START + gEfiSdMmcPassThruProtocolGuid ## BY_START + +[UserExtensions.TianoCore."ExtraFiles"] + SdMmcPciHcDxeExtra.uni diff --git a/Drivers/Sd/XenonSdhci.c b/Drivers/Sd/XenonSdhci.c new file mode 100644 index 0000000..a6f891c --- /dev/null +++ b/Drivers/Sd/XenonSdhci.c @@ -0,0 +1,424 @@ +/******************************************************************************* +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" + +VOID +XenonReadVersion ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + OUT UINT32 *ControllerVersion + ) +{ + + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX,SD_MMC_HC_CTRL_VER, TRUE, 2, ControllerVersion); +} + +VOID +XenonSetFifo ( + IN EFI_PCI_IO_PROTOCOL *PciIo + ) +{ + UINTN Data = 0x315; + + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SLOT_FIFO_CTRL, FALSE, 4, &Data); +} + +// Auto Clock Gating +VOID +XenonSetAcg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN BOOLEAN Enable + ) +{ + UINT32 Var; + + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SYS_OP_CTRL, TRUE, 4, &Var); + + if (Enable) { + Var |= AUTO_CLKGATE_DISABLE_MASK; + } else { + Var |= ~AUTO_CLKGATE_DISABLE_MASK; + } + + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SYS_OP_CTRL, FALSE, 4, &Var); +} + +VOID +XenonSetSlot ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN BOOLEAN Enable + ) +{ + UINT32 Var; + + Var = SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SYS_OP_CTRL, TRUE, 4, &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, 4, &Var); +} + +STATIC +VOID +XenonSetSdio ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINTN Voltage + ) +{ + + return; +} + +VOID +XenonSetPower ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 Vcc, + IN UINT32 Vccq, + IN UINT8 Mode + ) +{ + UINT8 Pwr = 0; + UINT32 Ctrl = 0; + + // Set VCC + 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, "Does not support power mode(0x%X)\n", Vcc)); + break; + } + + if (Pwr == 0) { + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_POWER_CTRL, FALSE, 1, &Pwr); + return; + } + + Pwr |= SDHCI_POWER_ON; + + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX,SD_MMC_HC_POWER_CTRL, FALSE, 1, &Pwr); + + // Set VCCQ + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SLOT_eMMC_CTRL, TRUE, 4, &Ctrl); + Ctrl |= Vccq; + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SLOT_eMMC_CTRL, FALSE, 4, &Ctrl); +} + +UINTN +XenonSetClk ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN UINT32 Clock + ) +{ + UINT32 Div; + UINT32 Clk; + UINT32 Timeout; + UINT16 Value = 0; + + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, 2, &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, 2, &Clk); + + // Wait max 20 ms + Timeout = 200; + + do { + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, TRUE, 2, &Clk); + if (Timeout == 0) { + DEBUG((DEBUG_ERROR, "SD/MMC: Internal Clock never stabilised\n")); + return -1; + } + Timeout--; + 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, 2, &Clk); + + return 0; +} + +STATIC +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, 2, &ClkCtrl); + ClkCtrl &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN); + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, 2, &ClkCtrl); + + // Enable QSP PHASE SELECT + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, 4, &Var); + Var |= SAMPL_INV_QSP_PHASE_SELECT; + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, FALSE, 4, &Var); + + // Enable internal clock + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, TRUE, 2, &ClkCtrl); + ClkCtrl |= SDHCI_CLOCK_INT_EN; + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, 2, &ClkCtrl); + + // + // Poll for host MMC PHY clock init to be stable + // Wait up to 10ms + // + Time = 100; + while (Time--) { + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, 4, &Var); + if (Var & SDHCI_CLOCK_INT_STABLE) + break; + + gBS->Stall (1); + } + if (Time <= 0) { + DEBUG((DEBUG_ERROR, "Failed to enable MMC internal clock in Time\n")); + return; + } + + // Enable bus clock + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, TRUE, 2, &ClkCtrl); + ClkCtrl |= SDHCI_CLOCK_CARD_EN; + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, 2, &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, 4, &Var); + Var |= PHY_INITIALIZAION; + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, FALSE, 4, &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); + // + // According to Moyang, 4 addtional bus clock and 4 AXI bus clock are required + // left shift 20 bits + Wait += 8; + Wait <<= 20; + + if (Clock == 0) + // Use the possibly slowest bus frequency value + Clock = 100000; + // Get the Wait Time in unit of ms + Wait = Wait / Clock; + Wait++; + + // + // Poll for host eMMC PHY init to complete + // Wait up to 10ms + // + Time = 100; + while (Time--) { + Var = SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, 4, &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; +} + +VOID +XenonSetPhy ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + UINT8 Timing + ) +{ + UINT32 Var; + + // Setup pad, set bit[30], bit[28] and bits[26:24] + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_PAD_CONTROL, TRUE, 4, &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, 4, &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, 4, &Var); + + Var |= OUTPUT_QSN_PHASE_SELECT; + SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, FALSE, 4, &Var); + } + + SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, TRUE, 4, &Var); + Var |= (DQ_DDR_MODE_MASK << DQ_DDR_MODE_SHIFT) | CMD_DDR_MODE; + SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, FALSE, 4, &Var); + + if (Timing == MMC_TIMING_MMC_HS400) { + SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, TRUE, 4, &Var); + Var &= ~DQ_ASYNC_MODE; + SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, FALSE, 4, &Var); + + Var = LOGIC_TIMING_VALUE; + SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_LOGIC_TIMING_ADJUST, FALSE, 4, &Var); + } + + XenonPhyInit (PciIo); +} + +VOID +XenonConfigureInterrupts ( + IN EFI_PCI_IO_PROTOCOL *PciIo + ) +{ + UINT32 Var; + + // Clear interrupt status + Var = 0xFFFFFFFF; + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_NOR_INT_STS, FALSE, 4, &Var); + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_NOR_INT_STS, FALSE, 4, &Var); + + // Enable only interrupts served by the SD controller + Var = 0xFFFFFEBF; + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_NOR_INT_STS_EN, FALSE, 4, &Var); + + // Mask all sdhci interrupt sources + Var = 0xFFFFFEFF; + SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_NOR_INT_SIG_EN, FALSE, 4, &Var); +} + +// Enable Parallel Transfer Mode +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, 4, &Var); + if (Enable) + Var |= (0x1 << Slot); + else + Var &= ~(0x1 << Slot); + SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHC_SYS_EXT_OP_CTRL, FALSE, 4, &Var); +} + +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, 4, &Var); + if (Enable) + Var |= RETUNING_COMPATIBLE; + else + Var &= ~RETUNING_COMPATIBLE; + SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHC_SYS_EXT_OP_CTRL, FALSE, 4, &Var); + + // Set the Re-tuning Event Signal Enable + SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHCI_SIGNAL_ENABLE, TRUE, 4, &Var); + if (Enable) + Var |= SDHCI_RETUNE_EVT_INTSIG; + else + Var &= ~SDHCI_RETUNE_EVT_INTSIG; + SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHC_SYS_EXT_OP_CTRL, FALSE, 4, &Var); +} diff --git a/Drivers/Sd/XenonSdhci.h b/Drivers/Sd/XenonSdhci.h new file mode 100644 index 0000000..00c1ad9 --- /dev/null +++ b/Drivers/Sd/XenonSdhci.h @@ -0,0 +1,301 @@ +/******************************************************************************* +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 "../../../MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h" + +#define SD_BAR_INDEX 0 + +/* 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_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 +/* retuning compatible */ +#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 XENON_MMC_MAX_CLK (400000000) + +#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 */ + +/* Hyperion only have one slot 0 */ +#define XENON_MMC_SLOT_ID_HYPERION (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 + +/* 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 + +VOID +XenonReadVersion ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + OUT UINT32 *ControllerVersion + ); + +VOID +XenonSetFifo ( + IN EFI_PCI_IO_PROTOCOL *PciIo + ); + +VOID +XenonSetSlot ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN BOOLEAN Enable + ); + +VOID +XenonSetAcg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN BOOLEAN Enable + ); + +VOID +XenonSetSlot ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN BOOLEAN Enable + ); + +VOID +XenonSetPower ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 Vcc, + IN UINT32 Vccq, + IN UINT8 Mode + ); + +UINTN +XenonSetClk ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN SD_MMC_HC_PRIVATE_DATA *Private, + IN UINT32 Clock + ); + +VOID +XenonSetPhy ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + UINT8 Timing + ); + +VOID +XenonSetTuning ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN BOOLEAN Enable + ); + +VOID +XenonConfigureInterrupts ( + IN EFI_PCI_IO_PROTOCOL *PciIo + ); + +VOID +XenonSetParallelTransfer ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN BOOLEAN Enable + );
From: Jan Dąbroś jsd@semihalf.com
Improve PciEmulation driver in order to support SD/MMC controllers.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- Platforms/Marvell/PciEmulation/PciEmulation.c | 4 ++++ Platforms/Marvell/PciEmulation/PciEmulation.h | 2 ++ 2 files changed, 6 insertions(+)
diff --git a/Platforms/Marvell/PciEmulation/PciEmulation.c b/Platforms/Marvell/PciEmulation/PciEmulation.c index 236838a..2d7c0d1 100644 --- a/Platforms/Marvell/PciEmulation/PciEmulation.c +++ b/Platforms/Marvell/PciEmulation/PciEmulation.c @@ -605,6 +605,10 @@ InstallDevices ( Private->ConfigSpace->Device.Bar[EFI_AHCI_BAR_INDEX] = Private->RootBridge.MemoryStart; break; + case SD_MMC_PCI_CLASS_CODE_NR: + Private->ConfigSpace->Device.Bar[EFI_SD_MMC_BAR_INDEX] = + Private->RootBridge.MemoryStart; + break; default: DEBUG((EFI_D_ERROR, "PciEmulation: Unknown PCI device. Abort.\n")); return EFI_D_ERROR; diff --git a/Platforms/Marvell/PciEmulation/PciEmulation.h b/Platforms/Marvell/PciEmulation/PciEmulation.h index 9dcd7e3..89b1858 100644 --- a/Platforms/Marvell/PciEmulation/PciEmulation.h +++ b/Platforms/Marvell/PciEmulation/PciEmulation.h @@ -47,9 +47,11 @@
#define XHCI_PCI_CLASS_CODE_NR 0x30030C #define AHCI_PCI_CLASS_CODE_NR 0x010601 +#define SD_MMC_PCI_CLASS_CODE_NR 0x010508
#define EFI_XHCI_BAR_INDEX 0x0 #define EFI_AHCI_BAR_INDEX 0x5 +#define EFI_SD_MMC_BAR_INDEX 0x0
typedef struct { ACPI_HID_DEVICE_PATH AcpiDevicePath;
From: Jan Dąbroś jsd@semihalf.com
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- Platforms/Marvell/Armada/Armada.dsc.inc | 5 +++++ Platforms/Marvell/Armada/Armada7040.fdf | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/Platforms/Marvell/Armada/Armada.dsc.inc b/Platforms/Marvell/Armada/Armada.dsc.inc index 743c396..9a15087 100644 --- a/Platforms/Marvell/Armada/Armada.dsc.inc +++ b/Platforms/Marvell/Armada/Armada.dsc.inc @@ -421,6 +421,11 @@ MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
+ # SD/MMC + OpenPlatformPkg/Drivers/Sd/MvSdMmcPciHcDxe.inf + MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf + MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf + # Console packages MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf diff --git a/Platforms/Marvell/Armada/Armada7040.fdf b/Platforms/Marvell/Armada/Armada7040.fdf index 8182777..27b2b58 100644 --- a/Platforms/Marvell/Armada/Armada7040.fdf +++ b/Platforms/Marvell/Armada/Armada7040.fdf @@ -49,7 +49,7 @@ NumBlocks = 0x400 # ################################################################################
-0x00000000|0x000E0000 +0x00000000|0x000E6000 gArmTokenSpaceGuid.PcdFvBaseAddress|gArmTokenSpaceGuid.PcdFvSize FV = FVMAIN_COMPACT
@@ -124,6 +124,11 @@ FvNameGuid = 5eda4200-2c5f-43cb-9da3-0baf74b1b30c INF MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf INF MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
+ # SD/MMC + INF OpenPlatformPkg/Drivers/Sd/MvSdMmcPciHcDxe.inf + INF MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf + INF MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf + # Multiple Console IO support INF MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf INF MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf
From: Jan Dąbroś jsd@semihalf.com
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- Platforms/Marvell/Armada/Armada70x0.dsc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/Platforms/Marvell/Armada/Armada70x0.dsc b/Platforms/Marvell/Armada/Armada70x0.dsc index ebe609e..f5c5dd7 100644 --- a/Platforms/Marvell/Armada/Armada70x0.dsc +++ b/Platforms/Marvell/Armada/Armada70x0.dsc @@ -96,16 +96,16 @@ gMarvellTokenSpaceGuid.PcdRamDiskSize|64 #64MB
#PciEmulation - gMarvellTokenSpaceGuid.PcdPciEDevCount|3 - ## XHCI1 XHCI2 SATA - gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress|L"0xF2500000;0xF2510000;0xF2540000" - gMarvellTokenSpaceGuid.PcdPciEDevRegSize|L"0x10000;0x10000;0x30000" + gMarvellTokenSpaceGuid.PcdPciEDevCount|4 + ## XHCI1 XHCI2 SATA MMC + gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress|L"0xF2500000;0xF2510000;0xF2540000;0xF06E0000" + gMarvellTokenSpaceGuid.PcdPciEDevRegSize|L"0x10000;0x10000;0x30000;0x300" ## ClassCode1 - gMarvellTokenSpaceGuid.PcdPciEDevClassCode1|L"0x30;0x30;0x01" + gMarvellTokenSpaceGuid.PcdPciEDevClassCode1|L"0x30;0x30;0x01;0x01" ## ClassCode2 - gMarvellTokenSpaceGuid.PcdPciEDevClassCode2|L"0x03;0x03;0x06" + gMarvellTokenSpaceGuid.PcdPciEDevClassCode2|L"0x03;0x03;0x06;0x05" ## ClassCode3 - gMarvellTokenSpaceGuid.PcdPciEDevClassCode3|L"0x0C;0x0C;0x01" + gMarvellTokenSpaceGuid.PcdPciEDevClassCode3|L"0x0C;0x0C;0x01;0x08"
#ComPhy gMarvellTokenSpaceGuid.PcdComPhyChipCount|1
From: Jan Dąbroś jsd@semihalf.com
Marvell SoC's comprise multiplexed pins for SerDes lanes (XHCI, AHCI, SGMII, PCIe) called ComPhy.
ComPhyLib initialize ComPhy and ComPhy Mux. All configurable parameters are provided via set of PCDs.
In order to satisfy preprocessor demands, there are ComPhy PCDs for all of 4 possible chips.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- Documentation/Marvell/PortingGuide/ComPhy.txt | 77 ++ Documentation/Marvell/UserGuide.txt | 1 + Platforms/Marvell/Include/Library/ComPhyLib.h | 43 ++ Platforms/Marvell/Library/ComPhyLib/ComPhyAp806.c | 290 ++++++++ Platforms/Marvell/Library/ComPhyLib/ComPhyCp110.c | 811 ++++++++++++++++++++++ Platforms/Marvell/Library/ComPhyLib/ComPhyLib.c | 277 ++++++++ Platforms/Marvell/Library/ComPhyLib/ComPhyLib.h | 457 ++++++++++++ Platforms/Marvell/Library/ComPhyLib/ComPhyLib.inf | 110 +++ Platforms/Marvell/Library/ComPhyLib/ComPhyMux.c | 132 ++++ Platforms/Marvell/Marvell.dec | 47 ++ 10 files changed, 2245 insertions(+) create mode 100644 Documentation/Marvell/PortingGuide/ComPhy.txt create mode 100644 Platforms/Marvell/Include/Library/ComPhyLib.h create mode 100644 Platforms/Marvell/Library/ComPhyLib/ComPhyAp806.c create mode 100644 Platforms/Marvell/Library/ComPhyLib/ComPhyCp110.c create mode 100644 Platforms/Marvell/Library/ComPhyLib/ComPhyLib.c create mode 100644 Platforms/Marvell/Library/ComPhyLib/ComPhyLib.h create mode 100644 Platforms/Marvell/Library/ComPhyLib/ComPhyLib.inf create mode 100644 Platforms/Marvell/Library/ComPhyLib/ComPhyMux.c
diff --git a/Documentation/Marvell/PortingGuide/ComPhy.txt b/Documentation/Marvell/PortingGuide/ComPhy.txt new file mode 100644 index 0000000..29383d4 --- /dev/null +++ b/Documentation/Marvell/PortingGuide/ComPhy.txt @@ -0,0 +1,77 @@ +COMPHY configuration +--------------------------- +In order to configure ComPhy library, following PCDs are available: + + gMarvellTokenSpaceGuid.PcdComPhyChipCount + +Indicates how many different chips are placed on board. So far, up to 4 chips +are supported. + +Every ComPhy PCD has <Num> part where <Num> stands for chip ID (order is not +important, but configuration will be set for first PcdComPhyChipCount chips). + +Every chip has 8 ComPhy PCDs and three of them concern lanes settings for this +chip. Below is example for the first chip (Chip0). + +General PCDs: + + gMarvellTokenSpaceGuid.PcdChip0Compatible + +Unicode string indicating type of chip - currently supported are +{ L"Ap806", L"Cp110"} + + gMarvellTokenSpaceGuid.PcdChip0ComPhyBaseAddress + +Indicates COMPHY unit base address. + + gMarvellTokenSpaceGuid.PcdChip0Hpipe3BaseAddress + +Indicates Hpipe3 unit base address. + + gMarvellTokenSpaceGuid.PcdChip0ComPhyMuxBitCount + +Indicates number of bits that are allocated for every MUX in the +COMPHY-selector register. + + gMarvellTokenSpaceGuid.PcdChip0ComPhyMaxLanes + +Indicates maximum ComPhy lanes number. + +Next three PCDs are in unicode string format containing settings for up to 10 +lanes. Setting for each one is separated with semicolon. 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"QSGMII", +L"USB3_HOST0", L"USB3_HOST1", L"USB3_DEVICE", +L"XAUI0", L"XAUI1", L"XAUI2", L"XAUI3", L"RXAUI0", +L"RXAUI1", L"KR" } + + gMarvellTokenSpaceGuid.PcdChip0ComPhySpeeds + +Indicates PHY speeds in MHz. Currently supported are: + +{ 1250, 1500, 2500, 3000, 3125, 5000, 6000, 6250, 1031 } + + gMarvellTokenSpaceGuid.PcdChip0ComPhyInvFlags + +Indicates lane polarity invert. + +Example +------- + #ComPhy + gMarvellTokenSpaceGuid.PcdComPhyChipCount|1 + + gMarvellTokenSpaceGuid.PcdChip0ComPhyMaxLanes|6 + gMarvellTokenSpaceGuid.PcdChip0ComPhyBaseAddress|0xF2441000 + gMarvellTokenSpaceGuid.PcdChip0Hpipe3BaseAddress|0xF2120000 + gMarvellTokenSpaceGuid.PcdChip0ComPhyMuxBitCount|4 + gMarvellTokenSpaceGuid.PcdChip0Compatible|L"Cp110" + + gMarvellTokenSpaceGuid.PcdChip0ComPhyTypes|L"SGMII2;USB3_HOST0;SGMII0;SATA1;USB3_HOST1;PCIE2" + gMarvellTokenSpaceGuid.PcdChip0ComPhySpeeds|L"1250;5000;1250;5000;5000;5000" diff --git a/Documentation/Marvell/UserGuide.txt b/Documentation/Marvell/UserGuide.txt index 6def7d8..cb9838a 100644 --- a/Documentation/Marvell/UserGuide.txt +++ b/Documentation/Marvell/UserGuide.txt @@ -7,6 +7,7 @@ Table of contents: Build.txt
2. Porting guide + comphy - PortingGuide/ComPhy.txt i2c - PortingGuide/I2c.txt icu - PortingGuide/IcuLib.txt mpp - PortingGuide/Mpp.txt diff --git a/Platforms/Marvell/Include/Library/ComPhyLib.h b/Platforms/Marvell/Include/Library/ComPhyLib.h new file mode 100644 index 0000000..d63a19d --- /dev/null +++ b/Platforms/Marvell/Include/Library/ComPhyLib.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 __COMPHYLIB_H__ +#define __COMPHYLIB_H__ + +EFI_STATUS +ComPhyInit ( + VOID + ); + +#endif diff --git a/Platforms/Marvell/Library/ComPhyLib/ComPhyAp806.c b/Platforms/Marvell/Library/ComPhyLib/ComPhyAp806.c new file mode 100644 index 0000000..d0fad1e --- /dev/null +++ b/Platforms/Marvell/Library/ComPhyLib/ComPhyAp806.c @@ -0,0 +1,290 @@ +/******************************************************************************** +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" + +#define HPIPE_ADDR(base, lane) (base + 0x800 * lane) +#define COMPHY_RESET_REG 0x120 + +#define COMPHY_RESET_SW_OFFSET 14 +#define COMPHY_RESET_SW_MASK (1 << COMPHY_RESET_SW_OFFSET) +#define COMPHY_RESET_CORE_OFFSET 13 +#define COMPHY_RESET_CORE_MASK (1 << COMPHY_RESET_CORE_OFFSET) + +#define COMPHY_PCI_MAC_CTRL 0x200 + +#define COMPHY_PCI_EN_OFFSET 0 +#define COMPHY_PCI_EN_MASK (0x1 << COMPHY_PCI_EN_OFFSET) +#define COMPHY_PCI_AXI_CACHE_OFFSET 8 +#define COMPHY_PCI_AXI_CACHE_MASK (0xF << COMPHY_PCI_AXI_CACHE_OFFSET) +#define COMPHY_PCI_COHERENT 0x7 +#define COMPHY_PCI_X1_EN_OFFSET 14 +#define COMPHY_PCI_X1_EN_MASK (0x1 << COMPHY_PCI_X1_EN_OFFSET) + +STATIC +VOID +ComPhyPcieReleaseSoftReset ( + IN EFI_PHYSICAL_ADDRESS HpipeAddr + ) +{ + /* Set MAX PLL Calibration */ + RegSet (HpipeAddr + HPIPE_KVCO_CALIB_CTRL_REG, + 0x1 << HPIPE_KVCO_CALIB_CTRL_MAX_PLL_OFFSET, + HPIPE_KVCO_CALIB_CTRL_MAX_PLL_MASK); + RegSet (HpipeAddr + HPIPE_LANE_CONFIG0_REG, + 0x1 << HPIPE_LANE_CONFIG0_MAX_PLL_OFFSET, + HPIPE_LANE_CONFIG0_MAX_PLL_MASK); + RegSet (HpipeAddr + HPIPE_LANE_CONFIG0_REG, + 0x1 << HPIPE_LANE_CONFIG0_GEN2_PLL_OFFSET, + HPIPE_LANE_CONFIG0_GEN2_PLL_MASK); + + /* DFE reset sequence */ + RegSet (HpipeAddr + HPIPE_PWR_CTR_REG, + 0x1 << HPIPE_PWR_CTR_RST_DFE_OFFSET, HPIPE_PWR_CTR_RST_DFE_MASK); + MicroSecondDelay (10); + RegSet (HpipeAddr + HPIPE_PWR_CTR_REG, + 0x0 << HPIPE_PWR_CTR_RST_DFE_OFFSET, HPIPE_PWR_CTR_RST_DFE_MASK); + + /* SW reset for interrupt logic */ + RegSet (HpipeAddr + HPIPE_PWR_CTR_REG, + 0x1 << HPIPE_PWR_CTR_SFT_RST_OFFSET, HPIPE_PWR_CTR_SFT_RST_MASK); + MicroSecondDelay (10); + RegSet (HpipeAddr + HPIPE_PWR_CTR_REG, + 0x0 << HPIPE_PWR_CTR_SFT_RST_OFFSET, HPIPE_PWR_CTR_SFT_RST_MASK); +} + +STATIC +EFI_STATUS +ComPhyPciePowerUp ( + IN UINT32 Lane, + IN UINT32 PcieBy4, + IN EFI_PHYSICAL_ADDRESS HpipeAddr + ) +{ + UINT32 StartVal, BreakVal, MasterVal; + + /* Enable CLK 500 */ + RegSet (HpipeAddr + HPIPE_MISC_REG, 0x1 << HPIPE_MISC_CLK500_EN_OFFSET, + HPIPE_MISC_CLK500_EN_MASK); + /* Clear lane align off */ + if (PcieBy4) + RegSet (HpipeAddr + HPIPE_LANE_ALIGN_REG, + 0x0 << HPIPE_LANE_ALIGN_OFF_OFFSET, HPIPE_LANE_ALIGN_OFF_MASK); + /* Reference Frequency Select set 0 (for PCIe 0 = 100Mhz) */ + RegSet (HpipeAddr + HPIPE_PWR_PLL_REG, 0x0 << HPIPE_PWR_PLL_REF_FREQ_OFFSET, + HPIPE_PWR_PLL_REF_FREQ_MASK); + /* PHY Mode Select (set PCIe = 0x3) */ + RegSet (HpipeAddr + HPIPE_PWR_PLL_REG, 0x3 << HPIPE_PWR_PLL_PHY_MODE_OFFSET, + HPIPE_PWR_PLL_PHY_MODE_MASK); + /* Set PIPE RESET - SW reset for the PIPE */ + RegSet (HpipeAddr + HPIPE_RST_CLK_CTRL_REG, + 0x1 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET, + HPIPE_RST_CLK_CTRL_PIPE_RST_MASK); + /* Set PCIe fixed mode to 8 bit @ 250 Mhz */ + RegSet (HpipeAddr + HPIPE_RST_CLK_CTRL_REG, + 0x1 << HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET, + HPIPE_RST_CLK_CTRL_FIXED_PCLK_MASK); + /* Set 5Gbps for RX and TX */ + RegSet (HpipeAddr + HPIPE_ISOLATE_MODE_REG, + 0x1 << HPIPE_ISOLATE_MODE_GEN_RX_OFFSET, HPIPE_ISOLATE_MODE_GEN_RX_MASK); + RegSet (HpipeAddr + HPIPE_ISOLATE_MODE_REG, + 0x1 << HPIPE_ISOLATE_MODE_GEN_TX_OFFSET, HPIPE_ISOLATE_MODE_GEN_TX_MASK); + /* Set Max PHY generation setting - 5GBps */ + RegSet (HpipeAddr + HPIPE_INTERFACE_REG, + 0x1 << HPIPE_INTERFACE_GEN_MAX_OFFSET, HPIPE_INTERFACE_GEN_MAX_MASK); + /* + * Set Lane Break/Start/Master: + * master - Provide RefClock to MAC + * start - Start of providing RefClock + * break - Stop passing the RefClock + */ + if (PcieBy4) { + /* + * If By4 Lane 0 - is master and start PHY + * Lane 1-2 - pass refclock to next phy + * Lane 3 - stop passing refclock + */ + if (Lane == 0) { + StartVal = 0x1; + BreakVal = 0x0; + MasterVal = 0x1; + } else if (Lane == 3) { + StartVal = 0x0; + BreakVal = 0x1; + MasterVal = 0x0; + } else { + StartVal = 0x0; + BreakVal = 0x0; + MasterVal = 0x0; + } + } else { + StartVal = 0x1; + BreakVal = 0x1; + MasterVal = 0x1; + } + RegSet (HpipeAddr + HPIPE_CLK_SRC_HI_REG, + StartVal << HPIPE_CLK_SRC_HI_LANE_STRT_OFFSET, + HPIPE_CLK_SRC_HI_LANE_STRT_MASK); + RegSet (HpipeAddr + HPIPE_CLK_SRC_HI_REG, + BreakVal << HPIPE_CLK_SRC_HI_LANE_BREAK_OFFSET, + HPIPE_CLK_SRC_HI_LANE_BREAK_MASK); + RegSet (HpipeAddr + HPIPE_CLK_SRC_HI_REG, + MasterVal << HPIPE_CLK_SRC_HI_LANE_MASTER_OFFSET, + HPIPE_CLK_SRC_HI_LANE_MASTER_MASK); + + /* For PCIe by4 need to reset after configure all 4 Lanes */ + if (PcieBy4) { + return EFI_SUCCESS; + } + + ComPhyPcieReleaseSoftReset(HpipeAddr); + /* Release PIPE RESET - release PHY from reset */ + RegSet (HpipeAddr + HPIPE_RST_CLK_CTRL_REG, + 0x0 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET, + HPIPE_RST_CLK_CTRL_PIPE_RST_MASK); + + MicroSecondDelay (20000); + + /* Return the status of the PLL */ + return (EFI_STATUS) (MmioRead32 (HpipeAddr + HPIPE_LANE_STATUS0_REG) & + HPIPE_LANE_STATUS0_PCLK_EN_MASK); +} + +EFI_STATUS +ComPhyAp806Init ( + IN CHIP_COMPHY_CONFIG *PtrChipCfg + ) +{ + EFI_STATUS Status; + COMPHY_MAP *PtrComPhyMap, *SerdesMap; + EFI_PHYSICAL_ADDRESS ComPhyBaseAddr, HpipeBaseAddr; + UINT32 ComPhyMaxCount, Lane; + UINT32 PcieBy4 = 1; + + ComPhyBaseAddr = PtrChipCfg->ComPhyBaseAddr; + ComPhyMaxCount = PtrChipCfg->LanesCount; + HpipeBaseAddr = PtrChipCfg->Hpipe3BaseAddr; + SerdesMap = PtrChipCfg->MapData; + + /* Set PHY to Normal mode */ + RegSet (ComPhyBaseAddr + COMPHY_RESET_REG, 1 << COMPHY_RESET_SW_OFFSET, + COMPHY_RESET_SW_MASK); + RegSet (ComPhyBaseAddr + COMPHY_RESET_REG, 1 << COMPHY_RESET_CORE_OFFSET, + COMPHY_RESET_CORE_MASK); + + /* Check if the first 4 Lanes configured as By-4 */ + for (Lane = 0, PtrComPhyMap = SerdesMap; Lane < 4; Lane++, PtrComPhyMap++) { + if (PtrComPhyMap->Type != PHY_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 PHY_TYPE_UNCONNECTED: + continue; + break; + case PHY_TYPE_PCIE0: + case PHY_TYPE_PCIE1: + case PHY_TYPE_PCIE2: + case PHY_TYPE_PCIE3: + Status = ComPhyPciePowerUp (Lane, PcieBy4, HPIPE_ADDR(HpipeBaseAddr, + Lane)); + MicroSecondDelay (20); + break; + default: + DEBUG((DEBUG_INFO, "ComPhy: Unknown SerDes Type, skip initialize " + "SerDes %d\n", Lane)); + break; + } + if (EFI_ERROR(Status)) + DEBUG((DEBUG_ERROR, "ComPhy: PLL is not locked - Failed to initialize " + "Lane %d\n", Lane)); + } + + /* SW reset for PCIe for all Lanes after power up */ + if (PcieBy4) { + for (Lane = 0; Lane < 4; Lane++) { + ComPhyPcieReleaseSoftReset (HPIPE_ADDR(HpipeBaseAddr, Lane)); + } + + /* + * Release PIPE RESET - release PHY from reset + * need to release the Lanes without delay between them + */ + DEBUG((DEBUG_INFO, "ComPhy: Release PIPE reset for PCIe-By4, write to " + "Reset Clock control register\n")); + for (Lane = 0; Lane < 4; Lane++) { + RegSetSilent(HPIPE_ADDR(HpipeBaseAddr, Lane) + HPIPE_RST_CLK_CTRL_REG, + 0x0 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET, + HPIPE_RST_CLK_CTRL_PIPE_RST_MASK); + } + + MicroSecondDelay (20000); + for (Lane = 0; Lane < 4; Lane++) { + Status = (EFI_STATUS) MmioRead32 (HPIPE_ADDR(HpipeBaseAddr, Lane) + + HPIPE_LANE_STATUS0_REG) & HPIPE_LANE_STATUS0_PCLK_EN_MASK; + if (EFI_ERROR(Status)) + DEBUG((DEBUG_ERROR, "ComPhy: PLL is not locked - Failed to initialize " + "Lane %d\n", Lane)); + } + } + + /* + * Set PCIe transactions towards A2 as: + * - read allocate + * - write non alocate + * - outer sharable + */ + RegSet (ComPhyBaseAddr + COMPHY_PCI_MAC_CTRL, COMPHY_PCI_COHERENT << + COMPHY_PCI_AXI_CACHE_OFFSET, COMPHY_PCI_AXI_CACHE_MASK); + + /* Set the Port x1 */ + if (PcieBy4) + RegSet (ComPhyBaseAddr + COMPHY_PCI_MAC_CTRL, 0 << COMPHY_PCI_X1_EN_OFFSET, + COMPHY_PCI_X1_EN_MASK); + else + RegSet (ComPhyBaseAddr + COMPHY_PCI_MAC_CTRL, 1 << COMPHY_PCI_X1_EN_OFFSET, + COMPHY_PCI_X1_EN_MASK); + + /* Enable PCIe unit */ + RegSet (ComPhyBaseAddr + COMPHY_PCI_MAC_CTRL, 1 << COMPHY_PCI_EN_OFFSET, + COMPHY_PCI_EN_MASK); + + return EFI_SUCCESS; +} diff --git a/Platforms/Marvell/Library/ComPhyLib/ComPhyCp110.c b/Platforms/Marvell/Library/ComPhyLib/ComPhyCp110.c new file mode 100644 index 0000000..b500064 --- /dev/null +++ b/Platforms/Marvell/Library/ComPhyLib/ComPhyCp110.c @@ -0,0 +1,811 @@ +/******************************************************************************** +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" + +#define SD_ADDR(base, Lane) (base + 0x1000 * Lane) +#define HPIPE_ADDR(base, Lane) (SD_ADDR(base, Lane) + 0x800) +#define COMPHY_ADDR(base, Lane) (base + 0x28 * Lane) + +/* + * 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 had option Eth_port_0 + * that include (SGMII0, XAUI0, RXAUI0, KR) + */ +COMPHY_MUX_DATA Cp110ComPhyMuxData[] = { + /* Lane 0 */ + {4, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_SGMII2, 0x1}, + {PHY_TYPE_XAUI2, 0x1}, {PHY_TYPE_SATA1, 0x4} } }, + /* Lane 1 */ + {4, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_SGMII3, 0x1}, + {PHY_TYPE_XAUI3, 0x1}, {PHY_TYPE_SATA1, 0x4} } }, + /* Lane 2 */ + {6, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_SGMII0, 0x1}, + {PHY_TYPE_XAUI0, 0x1}, {PHY_TYPE_RXAUI0, 0x1}, {PHY_TYPE_KR, 0x1}, + {PHY_TYPE_SATA0, 0x4} } }, + /* Lane 3 */ + {8, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_SGMII0, 0x1}, + {PHY_TYPE_XAUI0, 0x1}, {PHY_TYPE_RXAUI0, 0x1}, {PHY_TYPE_KR, 0x1}, + {PHY_TYPE_XAUI1, 0x1}, {PHY_TYPE_RXAUI1, 0x1}, {PHY_TYPE_SATA1, 0x4} } }, + /* Lane 4 */ + {7, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_SGMII0, 0x2}, + {PHY_TYPE_XAUI0, 0x1}, {PHY_TYPE_RXAUI0, 0x1}, {PHY_TYPE_KR, 0x1}, + {PHY_TYPE_SGMII2, 0x1}, {PHY_TYPE_XAUI2, 0x1} } }, + /* Lane 5 */ + {6, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_XAUI1, 0x1}, + {PHY_TYPE_RXAUI1, 0x1}, {PHY_TYPE_SGMII3, 0x1}, {PHY_TYPE_XAUI3, 0x1}, + {PHY_TYPE_SATA1, 0x4} } }, +}; + +COMPHY_MUX_DATA Cp110ComPhyPipeMuxData[] = { + /* Lane 0 */ + {2, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_PCIE0, 0x4} } }, + /* Lane 1 */ + {4, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_USB3_HOST0, 0x1}, + {PHY_TYPE_USB3_DEVICE, 0x2}, {PHY_TYPE_PCIE0, 0x4} } }, + /* Lane 2 */ + {3, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_USB3_HOST0, 0x1}, + {PHY_TYPE_PCIE0, 0x4} } }, + /* Lane 3 */ + {3, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_USB3_HOST1, 0x1}, + {PHY_TYPE_PCIE0, 0x4} } }, + /* Lane 4 */ + {4, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_USB3_HOST1, 0x1}, + {PHY_TYPE_USB3_DEVICE, 0x2}, {PHY_TYPE_PCIE1, 0x4} } }, + /* Lane 5 */ + {2, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_PCIE2, 0x4} } }, +}; + +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; + UINT32 Mask, Data, PcieClk = 0; + 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")); + /* 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); + + /* Start ComPhy Configuration */ + DEBUG((DEBUG_INFO, "ComPhy: stage: ComPhy configuration\n")); + /* 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; + } + 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; + /* 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); + + 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); + + 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_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 +UINTN +ComphyUsb3PowerUp ( + UINT32 Lane, + EFI_PHYSICAL_ADDRESS HpipeBase, + EFI_PHYSICAL_ADDRESS ComPhyBase + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINT32 Mask, 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")); + /* 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); + + /* Start ComPhy Configuration */ + DEBUG((DEBUG_INFO, "stage: Comphy configuration\n")); + /* 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); + + /* Start analog paramters from ETP(HW) */ + DEBUG((DEBUG_INFO, "ComPhy: stage: Analog paramters from ETP(HW)\n")); + /* 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); + /* End of analog parameters */ + + 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); + + 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 +UINTN +ComPhySataPowerUp ( + IN UINT32 Lane, + IN EFI_PHYSICAL_ADDRESS HpipeBase, + IN EFI_PHYSICAL_ADDRESS ComPhyBase + ) +{ + EFI_STATUS Status; + UINT32 Mask, Data; + EFI_PHYSICAL_ADDRESS HpipeAddr = HPIPE_ADDR(HpipeBase, Lane); + EFI_PHYSICAL_ADDRESS SdIpAddr = SD_ADDR(HpipeBase, Lane); + EFI_PHYSICAL_ADDRESS ComPhyAddr = COMPHY_ADDR(ComPhyBase, Lane); + EFI_PHYSICAL_ADDRESS SataBase; + + SataBase = PcdGet32 (PcdSataBaseAddress); + if (SataBase == 0) { + DEBUG((DEBUG_INFO, "ComPhy: SATA address not found in FDT\n")); + return EFI_D_ERROR; + } + + DEBUG((DEBUG_INFO, "ComPhy: stage: MAC configuration - power down " + "ComPhy\n")); + /* + * 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); + + DEBUG((DEBUG_INFO, "ComPhy: stage: RFU configurations - hard reset " + "ComPhy\n")); + /* 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); + + DEBUG((DEBUG_INFO, "ComPhy: stage: Comphy configuration\n")); + /* Start ComPhy Configuration */ + /* 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); + + DEBUG((DEBUG_INFO, "ComPhy: stage: Analog paramters from ETP(HW)\n")); + + /* DFE reset sequence */ + RegSet (HpipeAddr + HPIPE_PWR_CTR_REG, + 0x1 << HPIPE_PWR_CTR_RST_DFE_OFFSET, HPIPE_PWR_CTR_RST_DFE_MASK); + RegSet (HpipeAddr + HPIPE_PWR_CTR_REG, + 0x0 << HPIPE_PWR_CTR_RST_DFE_OFFSET, HPIPE_PWR_CTR_RST_DFE_MASK); + /* SW reset for interupt logic */ + RegSet (HpipeAddr + HPIPE_PWR_CTR_REG, + 0x1 << HPIPE_PWR_CTR_SFT_RST_OFFSET, HPIPE_PWR_CTR_SFT_RST_MASK); + RegSet (HpipeAddr + HPIPE_PWR_CTR_REG, + 0x0 << HPIPE_PWR_CTR_SFT_RST_OFFSET, HPIPE_PWR_CTR_SFT_RST_MASK); + + DEBUG((DEBUG_INFO, "ComPhy: stage: ComPhy power up\n")); + /* + * 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); + + /* Wait 15ms - Wait for ComPhy calibration done */ + MicroSecondDelay (15000); + + /* + * Reduce read & write burst size to 64 byte due to bug in + * AP-806-Z Aurora 2 that prohibits writes larger than 64 byte + */ + MmioWrite32(SataBase + SATA3_VENDOR_ADDRESS, 0x4); + Mask = 0x77; + Data = 0x44; /* 4 = 64 bytes burst */ + 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); + + DEBUG((DEBUG_INFO, "ComPhy: stage: Check PLL\n")); + Data = MmioRead32(SdIpAddr + SD_EXTERNAL_STATUS0_REG); + + /* Check the PLL TX */ + if ((Data & SD_EXTERNAL_STATUS0_PLL_TX_MASK) == 0) { + DEBUG((DEBUG_ERROR, "ComPhy: SD_EXTERNAL_STATUS0_PLL_TX is 0\n")); + Status = EFI_D_ERROR; + } + + /* Check the PLL RX */ + if ((Data & SD_EXTERNAL_STATUS0_PLL_RX_MASK) == 0) { + DEBUG((DEBUG_ERROR, "ComPhy: SD_EXTERNAL_STATUS0_PLL_RX is 0\n")); + Status = EFI_D_ERROR; + } + + 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; + UINT32 Mask, Data; + EFI_PHYSICAL_ADDRESS HpipeAddr = HPIPE_ADDR(HpipeBase, Lane); + EFI_PHYSICAL_ADDRESS SdIpAddr = SD_ADDR(HpipeBase, Lane); + EFI_PHYSICAL_ADDRESS ComPhyAddr = COMPHY_ADDR(ComPhyBase, Lane); + EFI_PHYSICAL_ADDRESS Addr; + + DEBUG((DEBUG_INFO, "ComPhy: stage: RFU configurations - hard reset " + "ComPhy\n")); + /* 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; + 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 == PHY_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); + + /* Start ComPhy Configuration */ + DEBUG((DEBUG_INFO, "ComPhy: stage: ComPhy configuration\n")); + /* 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); + + /* 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_SET_0_REG, + 0x1 << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET, HPIPE_G1_SET_0_G1_TX_EMPH1_MASK); + + DEBUG((DEBUG_INFO, "ComPhy: stage: RFU configurations - Power Up " + "PLL,Tx,Rx\n")); + /* 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 +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 == PHY_TYPE_UNCONNECTED) && + (ComPhyMapPhyData[Lane].Type == PHY_TYPE_UNCONNECTED)) + SerdesMap[Lane].Type = PHY_TYPE_UNCONNECTED; +} + +EFI_STATUS +ComPhyCp110Init ( + IN CHIP_COMPHY_CONFIG *PtrChipCfg + ) +{ + EFI_STATUS Status; + COMPHY_MAP *PtrComPhyMap, *SerdesMap; + EFI_PHYSICAL_ADDRESS ComPhyBaseAddr, HpipeBaseAddr; + UINT32 ComPhyMaxCount, Lane; + UINT32 PcieBy4 = 1; + + 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 != PHY_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 PHY_TYPE_UNCONNECTED: + continue; + break; + case PHY_TYPE_PCIE0: + case PHY_TYPE_PCIE1: + case PHY_TYPE_PCIE2: + case PHY_TYPE_PCIE3: + Status = ComPhyPciePowerUp(Lane, PcieBy4, HpipeBaseAddr, ComPhyBaseAddr); + break; + case PHY_TYPE_SATA0: + case PHY_TYPE_SATA1: + case PHY_TYPE_SATA2: + case PHY_TYPE_SATA3: + Status = ComPhySataPowerUp(Lane, HpipeBaseAddr, ComPhyBaseAddr); + break; + case PHY_TYPE_USB3_HOST0: + case PHY_TYPE_USB3_HOST1: + Status = ComphyUsb3PowerUp(Lane, HpipeBaseAddr, ComPhyBaseAddr); + break; + case PHY_TYPE_SGMII0: + case PHY_TYPE_SGMII1: + case PHY_TYPE_SGMII2: + Status = ComPhySgmiiPowerUp(Lane, PtrComPhyMap->Speed, HpipeBaseAddr, + ComPhyBaseAddr); + break; + default: + DEBUG((DEBUG_ERROR, "Unknown SerDes Type, skip initialize SerDes %d\n", + Lane)); + break; + } + if (EFI_ERROR(Status)) + DEBUG((DEBUG_ERROR, "PLL is not locked - Failed to initialize Lane %d\n", + Lane)); + } + + return EFI_SUCCESS; +} diff --git a/Platforms/Marvell/Library/ComPhyLib/ComPhyLib.c b/Platforms/Marvell/Library/ComPhyLib/ComPhyLib.c new file mode 100644 index 0000000..12b7d73 --- /dev/null +++ b/Platforms/Marvell/Library/ComPhyLib/ComPhyLib.c @@ -0,0 +1,277 @@ +/******************************************************************************** +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" + +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"KR"}; + +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"6 Gbps", L"6.25 Gbps", L"10.31 Gbps"}; + +CHIP_COMPHY_CONFIG ChipCfgTbl[] = { + { + .ChipType = L"Ap806", + .Init = ComPhyAp806Init + }, + { + .ChipType = L"Cp110", + .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 PHY_TYPE_INVALID; + + for (i = 0; i < PHY_TYPE_MAX; i++) { + if (StrCmp (String, TypeStringTable[i]) == 0) { + return i; + } + } + + /* PCD string doesn't match any supported SerDes Type */ + return PHY_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, 6000, 6250, 1031}; + + for (i = 0; i < 10; i++) { + if (Value == ValueTable[i]) { + return i; + } + } + + /* PCD SerDes speed value doesn't match any supported SerDes speed */ + return PHY_SPEED_INVALID; +} + +CHAR16 * +GetTypeString ( + UINT32 Type + ) +{ + + if (Type < 0 || Type > PHY_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 (StrCmp (PtrChipCfg->ChipType, ChipCfgTbl[i].ChipType) == 0) { + PtrChipCfg->Init = ChipCfgTbl[i].Init; + return EFI_SUCCESS; + } + } + + DEBUG((DEBUG_ERROR, "ComPhy: Empty ChipType string\n")); + return EFI_D_ERROR; +} + +EFI_STATUS +ComPhyInit ( + VOID + ) +{ + EFI_STATUS Status; + CHIP_COMPHY_CONFIG ChipConfig[MAX_CHIPS], *PtrChipCfg; + PCD_LANE_MAP LaneData[MAX_CHIPS]; + UINT32 Lane, ChipCount, i, MaxComphyCount; + + ChipCount = PcdGet32 (PcdComPhyChipCount); + + GetComPhyPcd(0); + GetComPhyPcd(1); + GetComPhyPcd(2); + GetComPhyPcd(3); + + if (ChipCount <= 0) + return EFI_INVALID_PARAMETER; + + for (i = 0; i < ChipCount ; i++) { + PtrChipCfg = &ChipConfig[i]; + + /* 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[i].TypeStr[Lane]); + PtrChipCfg->MapData[Lane].Speed = + ParseSerdesSpeed (LaneData[i].SpeedValue[Lane]); + PtrChipCfg->MapData[Lane].Invert = (UINT32) LaneData[i].InvFlag[Lane]; + + if ((PtrChipCfg->MapData[Lane].Speed == PHY_SPEED_INVALID) || + (PtrChipCfg->MapData[Lane].Speed == PHY_SPEED_ERROR) || + (PtrChipCfg->MapData[Lane].Type == PHY_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 = PHY_TYPE_UNCONNECTED; + PtrChipCfg->MapData[Lane].Speed = PHY_SPEED_INVALID; + } + }; + + Status = GetChipComPhyInit (PtrChipCfg); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "ComPhy: Invalid Chip%dType name\n", i)); + return Status; + } + + ComPhyPrint (PtrChipCfg); + + /* PHY power UP sequence */ + PtrChipCfg->Init (PtrChipCfg); + } + + return EFI_SUCCESS; +} diff --git a/Platforms/Marvell/Library/ComPhyLib/ComPhyLib.h b/Platforms/Marvell/Library/ComPhyLib/ComPhyLib.h new file mode 100644 index 0000000..51a3e42 --- /dev/null +++ b/Platforms/Marvell/Library/ComPhyLib/ComPhyLib.h @@ -0,0 +1,457 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __COMPHY_H__ +#define __COMPHY_H__ + +#include <Library/ArmLib.h> +#include <Library/ArmPlatformLib.h> +#include <Library/DebugLib.h> +#include <Library/PcdLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/IoLib.h> +#include <Library/TimerLib.h> +#include <Library/ParsePcdLib.h> + +#define MAX_LANE_OPTIONS 10 +#define MAX_CHIPS 4 + +/***** Parsing PCD *****/ +#define GET_TYPE_STRING(id) _PCD_GET_MODE_PTR_PcdChip##id##Compatible +#define GET_LANE_TYPE(id) _PCD_GET_MODE_PTR_PcdChip##id##ComPhyTypes +#define GET_LANE_SPEED(id) _PCD_GET_MODE_PTR_PcdChip##id##ComPhySpeeds +#define GET_LANE_INV(id) _PCD_GET_MODE_PTR_PcdChip##id##ComPhyInvFlags +#define GET_COMPHY_BASE_ADDR(id) _PCD_GET_MODE_64_PcdChip##id##ComPhyBaseAddress +#define GET_HPIPE3_BASE_ADDR(id) _PCD_GET_MODE_64_PcdChip##id##Hpipe3BaseAddress +#define GET_MUX_BIT_COUNT(id) _PCD_GET_MODE_32_PcdChip##id##ComPhyMuxBitCount +#define GET_MAX_LANES(id) _PCD_GET_MODE_32_PcdChip##id##ComPhyMaxLanes + +#define FillLaneMap(id) { \ + ParsePcdString((CHAR16 *) GET_LANE_TYPE(id), ChipConfig[id].LanesCount, NULL, LaneData[id].TypeStr); \ + ParsePcdString((CHAR16 *) GET_LANE_SPEED(id), ChipConfig[id].LanesCount, LaneData[id].SpeedValue, NULL); \ + ParsePcdString((CHAR16 *) GET_LANE_INV(id), ChipConfig[id].LanesCount, LaneData[id].InvFlag, NULL); \ +} + +#define GetComPhyPcd(id) { \ + ChipConfig[id].ChipType = (CHAR16 *) GET_TYPE_STRING(id); \ + ChipConfig[id].ComPhyBaseAddr = GET_COMPHY_BASE_ADDR(id); \ + ChipConfig[id].Hpipe3BaseAddr = GET_HPIPE3_BASE_ADDR(id); \ + ChipConfig[id].MuxBitCount = GET_MUX_BIT_COUNT(id); \ + ChipConfig[id].LanesCount = GET_MAX_LANES(id); \ + FillLaneMap(id); \ +} + +/***** ComPhy *****/ +#define PHY_SPEED_ERROR 0 +#define PHY_SPEED_1_25G 1 +#define PHY_SPEED_1_5G 2 +#define PHY_SPEED_2_5G 3 +#define PHY_SPEED_3G 4 +#define PHY_SPEED_3_125G 5 +#define PHY_SPEED_5G 6 +#define PHY_SPEED_6G 7 +#define PHY_SPEED_6_25G 8 +#define PHY_SPEED_10_3125G 9 +#define PHY_SPEED_MAX 10 +#define PHY_SPEED_INVALID 0xff + +#define PHY_TYPE_UNCONNECTED 0 +#define PHY_TYPE_PCIE0 1 +#define PHY_TYPE_PCIE1 2 +#define PHY_TYPE_PCIE2 3 +#define PHY_TYPE_PCIE3 4 +#define PHY_TYPE_SATA0 5 +#define PHY_TYPE_SATA1 6 +#define PHY_TYPE_SATA2 7 +#define PHY_TYPE_SATA3 8 +#define PHY_TYPE_SGMII0 9 +#define PHY_TYPE_SGMII1 10 +#define PHY_TYPE_SGMII2 11 +#define PHY_TYPE_SGMII3 12 +#define PHY_TYPE_QSGMII 13 +#define PHY_TYPE_USB3_HOST0 14 +#define PHY_TYPE_USB3_HOST1 15 +#define PHY_TYPE_USB3_DEVICE 16 +#define PHY_TYPE_XAUI0 17 +#define PHY_TYPE_XAUI1 18 +#define PHY_TYPE_XAUI2 19 +#define PHY_TYPE_XAUI3 20 +#define PHY_TYPE_RXAUI0 21 +#define PHY_TYPE_RXAUI1 22 +#define PHY_TYPE_KR 23 +#define PHY_TYPE_MAX 24 +#define PHY_TYPE_INVALID 0xff + +#define PHY_POLARITY_NO_INVERT 0 +#define PHY_POLARITY_TXD_INVERT 1 +#define PHY_POLARITY_RXD_INVERT 2 +#define PHY_POLARITY_ALL_INVERT (PHY_POLARITY_TXD_INVERT | PHY_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_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_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_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_SET_0_REG 0x034 +#define HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET 7 +#define HPIPE_G1_SET_0_G1_TX_EMPH1_MASK (0xf << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET) + +#define HPIPE_G1_SET_1_REG 0x038 +#define HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET 0 +#define HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK (0x7 << HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET) +#define HPIPE_G1_SET_1_G1_RX_SELMUPP_OFFSET 3 +#define HPIPE_G1_SET_1_G1_RX_SELMUPP_MASK (0x7 << HPIPE_G1_SET_1_G1_RX_SELMUPP_OFFSET) +#define HPIPE_G1_SET_1_G1_RX_DFE_EN_OFFSET 10 +#define HPIPE_G1_SET_1_G1_RX_DFE_EN_MASK (0x1 << HPIPE_G1_SET_1_G1_RX_DFE_EN_OFFSET) + +#define HPIPE_G2_SETTINGS_1_REG 0x040 + +#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_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_VTHIMPCAL_CTRL_REG 0x104 + +#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_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_PWR_CTR_DTL_REG 0x184 +#define HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET 0x2 +#define HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK (0x1 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET) + +#define HPIPE_RX_REG3 0x188 + +#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_PCIE_REG1 0x288 +#define HPIPE_PCIE_REG3 0x290 + +#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_G1_SETTINGS_3_REG 0x440 +#define HPIPE_G1_SETTINGS_4_REG 0x444 +#define HPIPE_G2_SETTINGS_3_REG 0x448 +#define HPIPE_G2_SETTINGS_4_REG 0x44C + +#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_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_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_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_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 + +/***** 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 +EFI_STATUS +(*COMPHY_CHIP_INIT) ( + IN CHIP_COMPHY_CONFIG *PtrChipCfg + ); + +struct _CHIP_COMPHY_CONFIG { + CHAR16* 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 + ); + +EFI_STATUS +ComPhyAp806Init ( + IN CHIP_COMPHY_CONFIG * First + ); + +EFI_STATUS +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/Platforms/Marvell/Library/ComPhyLib/ComPhyLib.inf b/Platforms/Marvell/Library/ComPhyLib/ComPhyLib.inf new file mode 100644 index 0000000..80f7d34 --- /dev/null +++ b/Platforms/Marvell/Library/ComPhyLib/ComPhyLib.inf @@ -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. +# + +[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 + OpenPlatformPkg/Platforms/Marvell/Marvell.dec + +[LibraryClasses] + ArmLib + DebugLib + MemoryAllocationLib + PcdLib + IoLib + ParsePcdLib + +[Sources.common] + ComPhyLib.c + ComPhyCp110.c + ComPhyAp806.c + ComPhyMux.c + +[FixedPcd] + gMarvellTokenSpaceGuid.PcdComPhyChipCount + + #Chip0 + gMarvellTokenSpaceGuid.PcdChip0Compatible + gMarvellTokenSpaceGuid.PcdChip0ComPhyBaseAddress + gMarvellTokenSpaceGuid.PcdChip0Hpipe3BaseAddress + gMarvellTokenSpaceGuid.PcdChip0ComPhyMuxBitCount + gMarvellTokenSpaceGuid.PcdChip0ComPhyMaxLanes + + gMarvellTokenSpaceGuid.PcdChip0ComPhyTypes + gMarvellTokenSpaceGuid.PcdChip0ComPhySpeeds + gMarvellTokenSpaceGuid.PcdChip0ComPhyInvFlags + + #Chip1 + gMarvellTokenSpaceGuid.PcdChip1Compatible + gMarvellTokenSpaceGuid.PcdChip1ComPhyBaseAddress + gMarvellTokenSpaceGuid.PcdChip1Hpipe3BaseAddress + gMarvellTokenSpaceGuid.PcdChip1ComPhyMuxBitCount + gMarvellTokenSpaceGuid.PcdChip1ComPhyMaxLanes + + gMarvellTokenSpaceGuid.PcdChip1ComPhyTypes + gMarvellTokenSpaceGuid.PcdChip1ComPhySpeeds + gMarvellTokenSpaceGuid.PcdChip1ComPhyInvFlags + + #Chip2 + gMarvellTokenSpaceGuid.PcdChip2Compatible + gMarvellTokenSpaceGuid.PcdChip2ComPhyBaseAddress + gMarvellTokenSpaceGuid.PcdChip2Hpipe3BaseAddress + gMarvellTokenSpaceGuid.PcdChip2ComPhyMuxBitCount + gMarvellTokenSpaceGuid.PcdChip2ComPhyMaxLanes + + gMarvellTokenSpaceGuid.PcdChip2ComPhyTypes + gMarvellTokenSpaceGuid.PcdChip2ComPhySpeeds + gMarvellTokenSpaceGuid.PcdChip2ComPhyInvFlags + + #Chip3 + gMarvellTokenSpaceGuid.PcdChip3Compatible + gMarvellTokenSpaceGuid.PcdChip3ComPhyBaseAddress + gMarvellTokenSpaceGuid.PcdChip3Hpipe3BaseAddress + gMarvellTokenSpaceGuid.PcdChip3ComPhyMuxBitCount + gMarvellTokenSpaceGuid.PcdChip3ComPhyMaxLanes + + gMarvellTokenSpaceGuid.PcdChip3ComPhyTypes + gMarvellTokenSpaceGuid.PcdChip3ComPhySpeeds + gMarvellTokenSpaceGuid.PcdChip3ComPhyInvFlags + + #SATA + gMarvellTokenSpaceGuid.PcdSataBaseAddress diff --git a/Platforms/Marvell/Library/ComPhyLib/ComPhyMux.c b/Platforms/Marvell/Library/ComPhyLib/ComPhyMux.c new file mode 100644 index 0000000..595745b --- /dev/null +++ b/Platforms/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, + PHY_TYPE_UNCONNECTED)); + ComPhyMapData->Type = PHY_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/Platforms/Marvell/Marvell.dec b/Platforms/Marvell/Marvell.dec index 6df6268..3876249 100644 --- a/Platforms/Marvell/Marvell.dec +++ b/Platforms/Marvell/Marvell.dec @@ -149,6 +149,53 @@ gMarvellTokenSpaceGuid.PcdSataBaseAddress|0|UINT32|0x4000052 gMarvellTokenSpaceGuid.PcdSataMapPortAddress|FALSE|BOOLEAN|0x4000053
+#ComPhy + #Chip0 + gMarvellTokenSpaceGuid.PcdComPhyChipCount|0|UINT32|0x30000098 + + gMarvellTokenSpaceGuid.PcdChip0Compatible|{ 0 }|VOID*|0x30000064 + gMarvellTokenSpaceGuid.PcdChip0ComPhyBaseAddress|0|UINT64|0x30000065 + gMarvellTokenSpaceGuid.PcdChip0Hpipe3BaseAddress|0|UINT64|0x30000066 + gMarvellTokenSpaceGuid.PcdChip0ComPhyMuxBitCount|0|UINT32|0x30000067 + gMarvellTokenSpaceGuid.PcdChip0ComPhyMaxLanes|0|UINT32|0x30001267 + + gMarvellTokenSpaceGuid.PcdChip0ComPhyTypes|{ 0 }|VOID*|0x30000068 + gMarvellTokenSpaceGuid.PcdChip0ComPhySpeeds|{ 0 }|VOID*|0x30000069 + gMarvellTokenSpaceGuid.PcdChip0ComPhyInvFlags|{ 0 }|VOID*|0x30000070 + + #Chip1 + gMarvellTokenSpaceGuid.PcdChip1Compatible|{ 0 }|VOID*|0x30000100 + gMarvellTokenSpaceGuid.PcdChip1ComPhyBaseAddress|0|UINT64|0x30000101 + gMarvellTokenSpaceGuid.PcdChip1Hpipe3BaseAddress|0|UINT64|0x30000102 + gMarvellTokenSpaceGuid.PcdChip1ComPhyMuxBitCount|0|UINT32|0x30000103 + gMarvellTokenSpaceGuid.PcdChip1ComPhyMaxLanes|0|UINT32|0x30001304 + + gMarvellTokenSpaceGuid.PcdChip1ComPhyTypes|{ 0 }|VOID*|0x30000105 + gMarvellTokenSpaceGuid.PcdChip1ComPhySpeeds|{ 0 }|VOID*|0x30000106 + gMarvellTokenSpaceGuid.PcdChip1ComPhyInvFlags|{ 0 }|VOID*|0x30000107 + + #Chip2 + gMarvellTokenSpaceGuid.PcdChip2Compatible|{ 0 }|VOID*|0x30000135 + gMarvellTokenSpaceGuid.PcdChip2ComPhyBaseAddress|0|UINT64|0x30000136 + gMarvellTokenSpaceGuid.PcdChip2Hpipe3BaseAddress|0|UINT64|0x30000137 + gMarvellTokenSpaceGuid.PcdChip2ComPhyMuxBitCount|0|UINT32|0x30000138 + gMarvellTokenSpaceGuid.PcdChip2ComPhyMaxLanes|0|UINT32|0x30000139 + + gMarvellTokenSpaceGuid.PcdChip2ComPhyTypes|{ 0 }|VOID*|0x30000140 + gMarvellTokenSpaceGuid.PcdChip2ComPhySpeeds|{ 0 }|VOID*|0x30000141 + gMarvellTokenSpaceGuid.PcdChip2ComPhyInvFlags|{ 0 }|VOID*|0x30000142 + + #Chip3 + gMarvellTokenSpaceGuid.PcdChip3Compatible|{ 0 }|VOID*|0x30000170 + gMarvellTokenSpaceGuid.PcdChip3ComPhyBaseAddress|0|UINT64|0x30000171 + gMarvellTokenSpaceGuid.PcdChip3Hpipe3BaseAddress|0|UINT64|0x30000172 + gMarvellTokenSpaceGuid.PcdChip3ComPhyMuxBitCount|0|UINT32|0x30000173 + gMarvellTokenSpaceGuid.PcdChip3ComPhyMaxLanes|0|UINT32|0x30000174 + + gMarvellTokenSpaceGuid.PcdChip3ComPhyTypes|{ 0 }|VOID*|0x30000175 + gMarvellTokenSpaceGuid.PcdChip3ComPhySpeeds|{ 0 }|VOID*|0x30000176 + gMarvellTokenSpaceGuid.PcdChip3ComPhyInvFlags|{ 0 }|VOID*|0x30000177 + [Protocols] gEfiEepromProtocolGuid = { 0xcd728a1f, 0x45b5, 0x4feb, { 0x98, 0xc8, 0x31, 0x3d, 0xa8, 0x11, 0x74, 0x62 }} gEfiSpiMasterProtocolGuid = { 0x23de66a3, 0xf666, 0x4b3e, { 0xaa, 0xa2, 0x68, 0x9b, 0x18, 0xae, 0x2e, 0x19 }}
From: Jan Dąbroś jsd@semihalf.com
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- Platforms/Marvell/Armada/Apn806.dsc | 12 ++++++++++++ Platforms/Marvell/Armada/Armada.dsc.inc | 1 + Platforms/Marvell/Armada/Armada7040_rz.dsc | 12 ++++++++++++ .../Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.c | 2 ++ .../Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.inf | 1 + 5 files changed, 28 insertions(+)
diff --git a/Platforms/Marvell/Armada/Apn806.dsc b/Platforms/Marvell/Armada/Apn806.dsc index 65f895f..1c74416 100644 --- a/Platforms/Marvell/Armada/Apn806.dsc +++ b/Platforms/Marvell/Armada/Apn806.dsc @@ -82,3 +82,15 @@
#RamDisk gMarvellTokenSpaceGuid.PcdRamDiskSize|64 #64MB + + #ComPhy + gMarvellTokenSpaceGuid.PcdComPhyChipCount|1 + + gMarvellTokenSpaceGuid.PcdChip0ComPhyMaxLanes|4 + gMarvellTokenSpaceGuid.PcdChip0ComPhyBaseAddress|0xF06F0000 + gMarvellTokenSpaceGuid.PcdChip0Hpipe3BaseAddress|0xF0070000 + gMarvellTokenSpaceGuid.PcdChip0ComPhyMuxBitCount|1 + gMarvellTokenSpaceGuid.PcdChip0Compatible|L"Ap806" + + gMarvellTokenSpaceGuid.PcdChip0ComPhyTypes|L"PCIE0;PCIE0;PCIE0;PCIE0" + gMarvellTokenSpaceGuid.PcdChip0ComPhySpeeds|L"5000;5000;5000;5000" diff --git a/Platforms/Marvell/Armada/Armada.dsc.inc b/Platforms/Marvell/Armada/Armada.dsc.inc index 9a15087..f309073 100644 --- a/Platforms/Marvell/Armada/Armada.dsc.inc +++ b/Platforms/Marvell/Armada/Armada.dsc.inc @@ -31,6 +31,7 @@ # [LibraryClasses.common] ArmPlatformLib|OpenPlatformPkg/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.inf + ComPhyLib|OpenPlatformPkg/Platforms/Marvell/Library/ComPhyLib/ComPhyLib.inf MppLib|OpenPlatformPkg/Platforms/Marvell/Library/MppLib/MppLib.inf ParsePcdLib|OpenPlatformPkg/Platforms/Marvell/Library/ParsePcdLib/ParsePcdLib.inf
diff --git a/Platforms/Marvell/Armada/Armada7040_rz.dsc b/Platforms/Marvell/Armada/Armada7040_rz.dsc index a0cca95..a0d5a3a 100644 --- a/Platforms/Marvell/Armada/Armada7040_rz.dsc +++ b/Platforms/Marvell/Armada/Armada7040_rz.dsc @@ -119,3 +119,15 @@ #SATA gMarvellTokenSpaceGuid.PcdSataBaseAddress|0xF2540000 gMarvellTokenSpaceGuid.PcdSataMapPortAddress|TRUE + + #ComPhy + gMarvellTokenSpaceGuid.PcdComPhyChipCount|1 + + gMarvellTokenSpaceGuid.PcdChip0ComPhyMaxLanes|6 + gMarvellTokenSpaceGuid.PcdChip0ComPhyBaseAddress|0xF2441000 + gMarvellTokenSpaceGuid.PcdChip0Hpipe3BaseAddress|0xF2120000 + gMarvellTokenSpaceGuid.PcdChip0ComPhyMuxBitCount|4 + gMarvellTokenSpaceGuid.PcdChip0Compatible|L"Cp110" + + gMarvellTokenSpaceGuid.PcdChip0ComPhyTypes|L"SGMII2;USB3_HOST0;SGMII0;SATA1;USB3_HOST1;PCIE2" + gMarvellTokenSpaceGuid.PcdChip0ComPhySpeeds|L"1250;5000;1250;5000;5000;5000" diff --git a/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.c b/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.c index fa480a5..7721a97 100644 --- a/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.c +++ b/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.c @@ -15,6 +15,7 @@ #include <Library/ArmLib.h> #include <Library/ArmPlatformLib.h> #include <Library/MppLib.h> +#include <Library/ComPhyLib.h> #include <Ppi/ArmMpCoreInfo.h> #include "Armada7040IcuLib.h"
@@ -92,6 +93,7 @@ ArmPlatformInitialize ( }
IcuInit (); + ComPhyInit (); MppInitialize (); return RETURN_SUCCESS; } diff --git a/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.inf b/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.inf index 6c1fde6..4d04dbd 100644 --- a/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.inf +++ b/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.inf @@ -28,6 +28,7 @@
[LibraryClasses] ArmLib + ComPhyLib DebugLib MemoryAllocationLib MppLib
From: Jan Dąbroś jsd@semihalf.com
UTMI PHY must be configured properly in order to enable USB2.0 usage on platforms.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- Documentation/Marvell/PortingGuide/Utmi.txt | 35 ++ Documentation/Marvell/UserGuide.txt | 1 + Platforms/Marvell/Include/Library/UtmiPhyLib.h | 43 +++ Platforms/Marvell/Library/UtmiPhyLib/UtmiPhyLib.c | 352 +++++++++++++++++++++ Platforms/Marvell/Library/UtmiPhyLib/UtmiPhyLib.h | 110 +++++++ .../Marvell/Library/UtmiPhyLib/UtmiPhyLib.inf | 64 ++++ Platforms/Marvell/Marvell.dec | 7 + 7 files changed, 612 insertions(+) create mode 100644 Documentation/Marvell/PortingGuide/Utmi.txt create mode 100644 Platforms/Marvell/Include/Library/UtmiPhyLib.h create mode 100644 Platforms/Marvell/Library/UtmiPhyLib/UtmiPhyLib.c create mode 100644 Platforms/Marvell/Library/UtmiPhyLib/UtmiPhyLib.h create mode 100644 Platforms/Marvell/Library/UtmiPhyLib/UtmiPhyLib.inf
diff --git a/Documentation/Marvell/PortingGuide/Utmi.txt b/Documentation/Marvell/PortingGuide/Utmi.txt new file mode 100644 index 0000000..cff4843 --- /dev/null +++ b/Documentation/Marvell/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/Documentation/Marvell/UserGuide.txt b/Documentation/Marvell/UserGuide.txt index cb9838a..b868eda 100644 --- a/Documentation/Marvell/UserGuide.txt +++ b/Documentation/Marvell/UserGuide.txt @@ -18,6 +18,7 @@ Table of contents: spi - PortingGuide/Spi.txt spi flash - PortingGuide/SpiFlash.txt usb - PortingGuide/PciEmulation.txt + utmi - PortingGuide/Utmi.txt
3. Drivers guidelines eeprom - Drivers/EepromDriver.txt diff --git a/Platforms/Marvell/Include/Library/UtmiPhyLib.h b/Platforms/Marvell/Include/Library/UtmiPhyLib.h new file mode 100644 index 0000000..1863f30 --- /dev/null +++ b/Platforms/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/Platforms/Marvell/Library/UtmiPhyLib/UtmiPhyLib.c b/Platforms/Marvell/Library/UtmiPhyLib/UtmiPhyLib.c new file mode 100644 index 0000000..c89601e --- /dev/null +++ b/Platforms/Marvell/Library/UtmiPhyLib/UtmiPhyLib.c @@ -0,0 +1,352 @@ +/******************************************************************************** +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)" + "- ", Addr, Data, Mask)); + DEBUG((DEBUG_INFO, "old value = %10x ==> ", 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), Power down PLL, and SuspendDM\n", UtmiIndex)); + /* 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), and exit SuspendDM\n", UtmiIndex)); + /* 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 done\n")); + + /* Delay 10ms */ + MicroSecondDelay (10000); + + DEBUG((DEBUG_ERROR, "UtmiPhy: stage: Check PLL.. ")); + 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; + } + + if (EFI_ERROR(Status)) + DEBUG((DEBUG_ERROR, "\n")); + else + DEBUG((DEBUG_ERROR, "Passed\n")); + + 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 port number (to check if the utmi connected to host/device) */ + UtmiData[i].UtmiPhyPort = UtmiPort[i]; + } + /* Currently only Cp110 is supported */ + Cp110UtmiPhyInit (Count, UtmiData); + + return EFI_SUCCESS; +} diff --git a/Platforms/Marvell/Library/UtmiPhyLib/UtmiPhyLib.h b/Platforms/Marvell/Library/UtmiPhyLib/UtmiPhyLib.h new file mode 100644 index 0000000..f23c387 --- /dev/null +++ b/Platforms/Marvell/Library/UtmiPhyLib/UtmiPhyLib.h @@ -0,0 +1,110 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __UTMIPHY_H__ +#define __UTMIPHY_H__ + +#include <Library/ArmLib.h> +#include <Library/ArmPlatformLib.h> +#include <Library/DebugLib.h> +#include <Library/PcdLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/IoLib.h> +#include <Library/TimerLib.h> +#include <Library/ParsePcdLib.h> + +#define UTMI_USB_CFG_DEVICE_EN_OFFSET 0 +#define UTMI_USB_CFG_DEVICE_EN_MASK (0x1 << UTMI_USB_CFG_DEVICE_EN_OFFSET) +#define UTMI_USB_CFG_DEVICE_MUX_OFFSET 1 +#define UTMI_USB_CFG_DEVICE_MUX_MASK (0x1 << UTMI_USB_CFG_DEVICE_MUX_OFFSET) +#define UTMI_USB_CFG_PLL_OFFSET 25 +#define UTMI_USB_CFG_PLL_MASK (0x1 << UTMI_USB_CFG_PLL_OFFSET) + +#define UTMI_PHY_CFG_PU_OFFSET 5 +#define UTMI_PHY_CFG_PU_MASK (0x1 << UTMI_PHY_CFG_PU_OFFSET) + +#define UTMI_PLL_CTRL_REG 0x0 +#define UTMI_PLL_CTRL_REFDIV_OFFSET 0 +#define UTMI_PLL_CTRL_REFDIV_MASK (0x7f << UTMI_PLL_CTRL_REFDIV_OFFSET) +#define UTMI_PLL_CTRL_FBDIV_OFFSET 16 +#define UTMI_PLL_CTRL_FBDIV_MASK (0x1FF << UTMI_PLL_CTRL_FBDIV_OFFSET) +#define UTMI_PLL_CTRL_SEL_LPFR_OFFSET 28 +#define UTMI_PLL_CTRL_SEL_LPFR_MASK (0x3 << UTMI_PLL_CTRL_SEL_LPFR_OFFSET) +#define UTMI_PLL_CTRL_PLL_RDY_OFFSET 31 +#define UTMI_PLL_CTRL_PLL_RDY_MASK (0x1 << UTMI_PLL_CTRL_PLL_RDY_OFFSET) + +#define UTMI_CALIB_CTRL_REG 0x8 +#define UTMI_CALIB_CTRL_IMPCAL_VTH_OFFSET 8 +#define UTMI_CALIB_CTRL_IMPCAL_VTH_MASK (0x7 << UTMI_CALIB_CTRL_IMPCAL_VTH_OFFSET) +#define UTMI_CALIB_CTRL_IMPCAL_DONE_OFFSET 23 +#define UTMI_CALIB_CTRL_IMPCAL_DONE_MASK (0x1 << UTMI_CALIB_CTRL_IMPCAL_DONE_OFFSET) +#define UTMI_CALIB_CTRL_PLLCAL_DONE_OFFSET 31 +#define UTMI_CALIB_CTRL_PLLCAL_DONE_MASK (0x1 << UTMI_CALIB_CTRL_PLLCAL_DONE_OFFSET) + +#define UTMI_TX_CH_CTRL_REG 0xC +#define UTMI_TX_CH_CTRL_DRV_EN_LS_OFFSET 12 +#define UTMI_TX_CH_CTRL_DRV_EN_LS_MASK (0xf << UTMI_TX_CH_CTRL_DRV_EN_LS_OFFSET) +#define UTMI_TX_CH_CTRL_IMP_SEL_LS_OFFSET 16 +#define UTMI_TX_CH_CTRL_IMP_SEL_LS_MASK (0xf << UTMI_TX_CH_CTRL_IMP_SEL_LS_OFFSET) + +#define UTMI_RX_CH_CTRL0_REG 0x14 +#define UTMI_RX_CH_CTRL0_SQ_DET_OFFSET 15 +#define UTMI_RX_CH_CTRL0_SQ_DET_MASK (0x1 << UTMI_RX_CH_CTRL0_SQ_DET_OFFSET) +#define UTMI_RX_CH_CTRL0_SQ_ANA_DTC_OFFSET 28 +#define UTMI_RX_CH_CTRL0_SQ_ANA_DTC_MASK (0x1 << UTMI_RX_CH_CTRL0_SQ_ANA_DTC_OFFSET) + +#define UTMI_RX_CH_CTRL1_REG 0x18 +#define UTMI_RX_CH_CTRL1_SQ_AMP_CAL_OFFSET 0 +#define UTMI_RX_CH_CTRL1_SQ_AMP_CAL_MASK (0x3 << UTMI_RX_CH_CTRL1_SQ_AMP_CAL_OFFSET) +#define UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_OFFSET 3 +#define UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_MASK (0x1 << UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_OFFSET) + +#define UTMI_CTRL_STATUS0_REG 0x24 +#define UTMI_CTRL_STATUS0_SUSPENDM_OFFSET 22 +#define UTMI_CTRL_STATUS0_SUSPENDM_MASK (0x1 << UTMI_CTRL_STATUS0_SUSPENDM_OFFSET) +#define UTMI_CTRL_STATUS0_TEST_SEL_OFFSET 25 +#define UTMI_CTRL_STATUS0_TEST_SEL_MASK (0x1 << UTMI_CTRL_STATUS0_TEST_SEL_OFFSET) + +#define UTMI_CHGDTC_CTRL_REG 0x38 +#define UTMI_CHGDTC_CTRL_VDAT_OFFSET 8 +#define UTMI_CHGDTC_CTRL_VDAT_MASK (0x3 << UTMI_CHGDTC_CTRL_VDAT_OFFSET) +#define UTMI_CHGDTC_CTRL_VSRC_OFFSET 10 +#define UTMI_CHGDTC_CTRL_VSRC_MASK (0x3 << UTMI_CHGDTC_CTRL_VSRC_OFFSET) + +#define UTMI_PHY_TO_USB_HOST0 0 +#define UTMI_PHY_TO_USB_HOST1 1 +#define UTMI_PHY_TO_USB_DEVICE0 2 +#define UTMI_PHY_INVALID 0xff + +#endif diff --git a/Platforms/Marvell/Library/UtmiPhyLib/UtmiPhyLib.inf b/Platforms/Marvell/Library/UtmiPhyLib/UtmiPhyLib.inf new file mode 100644 index 0000000..59e576e --- /dev/null +++ b/Platforms/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 = 0x00010005 + BASE_NAME = MarvellUtmiPhyLib + FILE_GUID = e9adaac2-0443-4921-9367-5d575c3c91bc + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = UtmiPhyLib + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + OpenPlatformPkg/Platforms/Marvell/Marvell.dec + +[LibraryClasses] + ArmLib + DebugLib + MemoryAllocationLib + PcdLib + IoLib + ParsePcdLib + +[Sources.common] + UtmiPhyLib.c + +[FixedPcd] + gMarvellTokenSpaceGuid.PcdUtmiPhyCount + gMarvellTokenSpaceGuid.PcdUtmiPhyRegUtmiUnit + gMarvellTokenSpaceGuid.PcdUtmiPhyRegUsbCfg + gMarvellTokenSpaceGuid.PcdUtmiPhyRegUtmiCfg + gMarvellTokenSpaceGuid.PcdUtmiPhyUtmiPort diff --git a/Platforms/Marvell/Marvell.dec b/Platforms/Marvell/Marvell.dec index 3876249..6ee90e0 100644 --- a/Platforms/Marvell/Marvell.dec +++ b/Platforms/Marvell/Marvell.dec @@ -196,6 +196,13 @@ gMarvellTokenSpaceGuid.PcdChip3ComPhySpeeds|{ 0 }|VOID*|0x30000176 gMarvellTokenSpaceGuid.PcdChip3ComPhyInvFlags|{ 0 }|VOID*|0x30000177
+ #UtmiPhy + gMarvellTokenSpaceGuid.PcdUtmiPhyCount|0|UINT32|0x30000205 + gMarvellTokenSpaceGuid.PcdUtmiPhyRegUtmiUnit|{ 0 }|VOID*|0x30000206 + gMarvellTokenSpaceGuid.PcdUtmiPhyRegUsbCfg|{ 0 }|VOID*|0x30000207 + gMarvellTokenSpaceGuid.PcdUtmiPhyRegUtmiCfg|{ 0 }|VOID*|0x30000208 + gMarvellTokenSpaceGuid.PcdUtmiPhyUtmiPort|{ 0 }|VOID*|0x30000209 + [Protocols] gEfiEepromProtocolGuid = { 0xcd728a1f, 0x45b5, 0x4feb, { 0x98, 0xc8, 0x31, 0x3d, 0xa8, 0x11, 0x74, 0x62 }} gEfiSpiMasterProtocolGuid = { 0x23de66a3, 0xf666, 0x4b3e, { 0xaa, 0xa2, 0x68, 0x9b, 0x18, 0xae, 0x2e, 0x19 }}
From: Jan Dąbroś jsd@semihalf.com
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- Platforms/Marvell/Armada/Armada.dsc.inc | 1 + Platforms/Marvell/Armada/Armada7040_rz.dsc | 7 +++++++ Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.c | 2 ++ Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.inf | 1 + 4 files changed, 11 insertions(+)
diff --git a/Platforms/Marvell/Armada/Armada.dsc.inc b/Platforms/Marvell/Armada/Armada.dsc.inc index f309073..1ac3971 100644 --- a/Platforms/Marvell/Armada/Armada.dsc.inc +++ b/Platforms/Marvell/Armada/Armada.dsc.inc @@ -34,6 +34,7 @@ ComPhyLib|OpenPlatformPkg/Platforms/Marvell/Library/ComPhyLib/ComPhyLib.inf MppLib|OpenPlatformPkg/Platforms/Marvell/Library/MppLib/MppLib.inf ParsePcdLib|OpenPlatformPkg/Platforms/Marvell/Library/ParsePcdLib/ParsePcdLib.inf + UtmiPhyLib|OpenPlatformPkg/Platforms/Marvell/Library/UtmiPhyLib/UtmiPhyLib.inf
DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf UncachedMemoryAllocationLib|ArmPkg/Library/UncachedMemoryAllocationLib/UncachedMemoryAllocationLib.inf diff --git a/Platforms/Marvell/Armada/Armada7040_rz.dsc b/Platforms/Marvell/Armada/Armada7040_rz.dsc index a0d5a3a..f631618 100644 --- a/Platforms/Marvell/Armada/Armada7040_rz.dsc +++ b/Platforms/Marvell/Armada/Armada7040_rz.dsc @@ -131,3 +131,10 @@
gMarvellTokenSpaceGuid.PcdChip0ComPhyTypes|L"SGMII2;USB3_HOST0;SGMII0;SATA1;USB3_HOST1;PCIE2" gMarvellTokenSpaceGuid.PcdChip0ComPhySpeeds|L"1250;5000;1250;5000;5000;5000" + + #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/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.c b/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.c index 7721a97..c3fe795 100644 --- a/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.c +++ b/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.c @@ -16,6 +16,7 @@ #include <Library/ArmPlatformLib.h> #include <Library/MppLib.h> #include <Library/ComPhyLib.h> +#include <Library/UtmiPhyLib.h> #include <Ppi/ArmMpCoreInfo.h> #include "Armada7040IcuLib.h"
@@ -94,6 +95,7 @@ ArmPlatformInitialize (
IcuInit (); ComPhyInit (); + UtmiPhyInit (); MppInitialize (); return RETURN_SUCCESS; } diff --git a/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.inf b/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.inf index 4d04dbd..1fdf184 100644 --- a/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.inf +++ b/Platforms/Marvell/Armada/Library/Armada7040Lib/Armada7040Lib.inf @@ -32,6 +32,7 @@ DebugLib MemoryAllocationLib MppLib + UtmiPhyLib
[Sources.common] Armada7040Lib.c