public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH edk2-platforms 0/7] Silicon/NXP: Import NXP i.MX platform package
@ 2018-07-19  4:11 Chris Co
  2018-07-19  4:11 ` [PATCH edk2-platforms 1/7] Silicon/NXP: Add support for iMX SDHC Chris Co
                   ` (6 more replies)
  0 siblings, 7 replies; 10+ messages in thread
From: Chris Co @ 2018-07-19  4:11 UTC (permalink / raw)
  To: edk2-devel@lists.01.org; +Cc: Ard Biesheuvel, Leif Lindholm, Michael D Kinney

REF: https://github.com/christopherco/edk2-platforms/tree/import_imxplat_v1

This patch set is the 2nd in the overall series of patches to bring up
Windows 10 IoT Core on Solidrun's Hummingboard Edge board running NXP's
i.MX6Q SoC.

Patch Series:
1. import Platform/Microsoft
2. import Silicon/NXP/iMXPlatformPkg
3. import Silicon/NXP/iMX6Pkg
4. import Platform/Solidrun/HummingboardEdge_iMX6Q_2GB

This patch set imports our iMXPlatformPkg, which contains modules that
are NXP i.MX specific but generic across the different i.MX SoC families.
These modules are used in the iMX6Pkg and HummingboardEdge board
packages.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Christopher Co <christopher.co@microsoft.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Michael D Kinney <michael.d.kinney@intel.com>

Christopher Co (7):
  Silicon/NXP: Add support for iMX SDHC
  Silicon/NXP: Add iMX display library support
  Silicon/NXP: Add I2C library support for iMX platforms
  Silicon/NXP: Add UART library support for iMX platforms
  Silicon/NXP: Add Virtual RTC support for IMX platform
  Silicon/NXP: Add iMXPlatformPkg dec
  Silicon/NXP: Add headers for other iMX packages to use

 Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.c                                   | 1356 ++++++++++++++++++++
 Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.inf                                 |   67 +
 Silicon/NXP/iMXPlatformPkg/Include/Platform.h                                          |   86 ++
 Silicon/NXP/iMXPlatformPkg/Include/common_macros.h                                     |  561 ++++++++
 Silicon/NXP/iMXPlatformPkg/Include/iMXDisplay.h                                        |   95 ++
 Silicon/NXP/iMXPlatformPkg/Include/iMXGpio.h                                           |  101 ++
 Silicon/NXP/iMXPlatformPkg/Include/iMXI2cLib.h                                         |  158 +++
 Silicon/NXP/iMXPlatformPkg/Include/iMXIoMux.h                                          |   24 +
 Silicon/NXP/iMXPlatformPkg/Include/iMXUart.h                                           |  225 ++++
 Silicon/NXP/iMXPlatformPkg/Include/iMXuSdhc.h                                          |  277 ++++
 Silicon/NXP/iMXPlatformPkg/Library/UartSerialPortLib/UartSerialPortLib.c               |  242 ++++
 Silicon/NXP/iMXPlatformPkg/Library/UartSerialPortLib/UartSerialPortLib.inf             |   41 +
 Silicon/NXP/iMXPlatformPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c   |  251 ++++
 Silicon/NXP/iMXPlatformPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.inf |   37 +
 Silicon/NXP/iMXPlatformPkg/Library/iMXDisplayLib/iMXDisplayLib.c                       |  125 ++
 Silicon/NXP/iMXPlatformPkg/Library/iMXDisplayLib/iMXDisplayLib.inf                     |   31 +
 Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.c                               |  524 ++++++++
 Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.inf                             |   35 +
 Silicon/NXP/iMXPlatformPkg/iMXPlatformPkg.dec                                          |  117 ++
 19 files changed, 4353 insertions(+)
 create mode 100644 Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.c
 create mode 100644 Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.inf
 create mode 100644 Silicon/NXP/iMXPlatformPkg/Include/Platform.h
 create mode 100644 Silicon/NXP/iMXPlatformPkg/Include/common_macros.h
 create mode 100644 Silicon/NXP/iMXPlatformPkg/Include/iMXDisplay.h
 create mode 100644 Silicon/NXP/iMXPlatformPkg/Include/iMXGpio.h
 create mode 100644 Silicon/NXP/iMXPlatformPkg/Include/iMXI2cLib.h
 create mode 100644 Silicon/NXP/iMXPlatformPkg/Include/iMXIoMux.h
 create mode 100644 Silicon/NXP/iMXPlatformPkg/Include/iMXUart.h
 create mode 100644 Silicon/NXP/iMXPlatformPkg/Include/iMXuSdhc.h
 create mode 100644 Silicon/NXP/iMXPlatformPkg/Library/UartSerialPortLib/UartSerialPortLib.c
 create mode 100644 Silicon/NXP/iMXPlatformPkg/Library/UartSerialPortLib/UartSerialPortLib.inf
 create mode 100644 Silicon/NXP/iMXPlatformPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c
 create mode 100644 Silicon/NXP/iMXPlatformPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.inf
 create mode 100644 Silicon/NXP/iMXPlatformPkg/Library/iMXDisplayLib/iMXDisplayLib.c
 create mode 100644 Silicon/NXP/iMXPlatformPkg/Library/iMXDisplayLib/iMXDisplayLib.inf
 create mode 100644 Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.c
 create mode 100644 Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.inf
 create mode 100644 Silicon/NXP/iMXPlatformPkg/iMXPlatformPkg.dec

-- 
2.16.2.gvfs.1.33.gf5370f1



^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH edk2-platforms 1/7] Silicon/NXP: Add support for iMX SDHC
  2018-07-19  4:11 [PATCH edk2-platforms 0/7] Silicon/NXP: Import NXP i.MX platform package Chris Co
@ 2018-07-19  4:11 ` Chris Co
  2018-08-01 16:15   ` Leif Lindholm
  2018-07-19  4:11 ` [PATCH edk2-platforms 2/7] Silicon/NXP: Add iMX display library support Chris Co
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 10+ messages in thread
From: Chris Co @ 2018-07-19  4:11 UTC (permalink / raw)
  To: edk2-devel@lists.01.org; +Cc: Ard Biesheuvel, Leif Lindholm, Michael D Kinney

This adds support for using the SD host controller on
NXP i.MX platforms.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Christopher Co <christopher.co@microsoft.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
---
 Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.c   | 1356 ++++++++++++++++++++
 Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.inf |   67 +
 Silicon/NXP/iMXPlatformPkg/Include/iMXGpio.h           |  101 ++
 Silicon/NXP/iMXPlatformPkg/Include/iMXuSdhc.h          |  277 ++++
 4 files changed, 1801 insertions(+)

diff --git a/Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.c b/Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.c
new file mode 100644
index 000000000000..5f087f8a28b9
--- /dev/null
+++ b/Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.c
@@ -0,0 +1,1356 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DmaLib.h>
+#include <Library/TimerLib.h>
+
+#include <Protocol/EmbeddedExternalDevice.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/Sdhc.h>
+
+#include <iMXuSdhc.h>
+#include <iMXGpio.h>
+
+typedef struct {
+    UINT32 IoNumber;
+    IMX_GPIO_BANK Bank;
+} IMX_GPIO_PIN;
+
+#define PCD_GPIO_PIN_IO_NUMBER(X)   ((X) & 0xFF)
+#define PCD_GPIO_PIN_BANK(X)        (((X) >> 8) & 0xFF)
+
+//
+// A special value to indicate that GPIO is not the signal source for either
+// CardDetect or WriteProtect
+//
+typedef enum {
+    USDHC_SIGNAL_GPIO_START = 0x000,
+    USDHC_SIGNAL_GPIO_END = 0xFF00,
+    USDHC_SIGNAL_OVERRIDE_PIN_LOW = 0xFF00,
+    USDHC_SIGNAL_OVERRIDE_PIN_HIGH = 0xFF01,
+    USDHC_SIGNAL_INTERNAL_PIN = 0xFFFF
+} USDHC_SIGNAL_SOURCE;
+
+#define USDHC_IS_GPIO_SIGNAL_SOURCE(X)  \
+    (((X) >= USDHC_SIGNAL_GPIO_START) && ((X) < USDHC_SIGNAL_GPIO_END))
+
+typedef struct {
+    UINT32 SdhcId;
+    EFI_HANDLE SdhcProtocolHandle;
+    USDHC_REGISTERS *RegistersBase;
+    USDHC_SIGNAL_SOURCE CardDetectSignal;
+    USDHC_SIGNAL_SOURCE WriteProtectSignal;
+    IMX_GPIO_PIN CardDetectGpioPin;
+    IMX_GPIO_PIN WriteProtectGpioPin;
+} USDHC_PRIVATE_CONTEXT;
+
+#define LOG_FMT_HELPER(FMT, ...) \
+    "SDHC%d:" FMT "%a\n", ((SdhcCtx != NULL) ? SdhcCtx->SdhcId : -1), __VA_ARGS__
+
+#define LOG_INFO(...) \
+    DEBUG((DEBUG_INFO | DEBUG_BLKIO, LOG_FMT_HELPER(__VA_ARGS__, "")))
+
+#define LOG_TRACE(...) \
+    DEBUG((DEBUG_VERBOSE | DEBUG_BLKIO, LOG_FMT_HELPER(__VA_ARGS__, "")))
+
+#define LOG_ERROR(...) \
+    DEBUG((DEBUG_ERROR | DEBUG_BLKIO, LOG_FMT_HELPER(__VA_ARGS__, "")))
+
+#define LOG_ASSERT(TXT) \
+    ASSERT(!"Sdhc: " TXT "\n")
+
+#ifdef MIN
+#undef MIN
+#define MIN(x,y) ((x) > (y) ? (y) : (x))
+#endif // MIN
+
+//
+// uSDHC read/write FIFO is 128x32-bit
+//
+#define USDHC_FIFO_MAX_WORD_COUNT       128
+
+//
+// Max block count allowed in a single transfer
+//
+#define USDHC_MAX_BLOCK_COUNT           0xFFFF
+
+//
+// Number of register maximum polls
+//
+#define USDHC_POLL_RETRY_COUNT          100000
+
+//
+// Waits between each registry poll
+//
+#define USDHC_POLL_WAIT_US              20
+
+//
+// uSDHC input clock. Ideally, should query it from clock manager
+//
+#define USDHC_BASE_CLOCK_FREQ_HZ        198000000
+
+#define USDHC_BLOCK_LENGTH_BYTES               512
+
+VOID
+DumpState(
+    IN USDHC_PRIVATE_CONTEXT *SdhcCtx
+    )
+{
+DEBUG_CODE_BEGIN ();
+
+    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
+
+    USDHC_BLK_ATT_REG BlkAtt; BlkAtt.AsUint32 = MmioRead32((UINTN)&Reg->BLK_ATT);
+    UINT32 CmdArg; CmdArg = MmioRead32((UINTN)&Reg->CMD_ARG);
+    USDHC_CMD_XFR_TYP_REG CmdXfrTyp; CmdXfrTyp.AsUint32 = MmioRead32((UINTN)&Reg->CMD_XFR_TYP);
+    USDHC_PROT_CTRL_REG ProtCtrl; ProtCtrl.AsUint32 = MmioRead32((UINTN)&Reg->PROT_CTRL);
+    USDHC_WTMK_LVL_REG WtmkLvl; WtmkLvl.AsUint32 = MmioRead32((UINTN)&Reg->WTMK_LVL);
+    USDHC_MIX_CTRL_REG MixCtrl; MixCtrl.AsUint32 = MmioRead32((UINTN)&Reg->MIX_CTRL);
+    UINT32 IntStatusEn = MmioRead32((UINTN)&Reg->INT_STATUS_EN);
+    UINT32 IntSignalEn = MmioRead32((UINTN)&Reg->INT_SIGNAL_EN);
+    UINT32 VendSpec = MmioRead32((UINTN)&Reg->VEND_SPEC);
+    UINT32 MmcBoot = MmioRead32((UINTN)&Reg->MMC_BOOT);
+    UINT32 VendSpec2 = MmioRead32((UINTN)&Reg->VEND_SPEC2);
+    USDHC_INT_STATUS_REG IntStatus; IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS);
+    USDHC_PRES_STATE_REG PresState; PresState.AsUint32 = MmioRead32((UINTN)&Reg->PRES_STATE);
+
+    LOG_INFO(
+        " - BLK_ATT\t:0x%08x BLKSIZE:0x%x BLKCNT:0x%08x",
+        BlkAtt.AsUint32,
+        BlkAtt.Fields.BLKSIZE,
+        BlkAtt.Fields.BLKCNT);
+
+    LOG_INFO(" - CMD_ARG\t:0x%08x", CmdArg);
+
+    LOG_INFO(
+        " - CMD_XFR_TYP\t:0x%08x RSPTYP:%d CCCEN:%d CICEN:%d DPSEL:%d CMDTYP:%d CMDINX:%d",
+        CmdXfrTyp.AsUint32,
+        CmdXfrTyp.Fields.RSPTYP,
+        CmdXfrTyp.Fields.CCCEN,
+        CmdXfrTyp.Fields.CICEN,
+        CmdXfrTyp.Fields.DPSEL,
+        CmdXfrTyp.Fields.CMDTYP,
+        CmdXfrTyp.Fields.CMDINX);
+
+    LOG_INFO(
+        " - PROT_CTRL\t:0x%08x DTW:%d D3CD:%d CDSS:%d EMODE:%d DMASEL:%d SABGREQ:%d BURST_LEN_EN:%d",
+        ProtCtrl.AsUint32,
+        ProtCtrl.Fields.DTW,
+        ProtCtrl.Fields.D3CD,
+        ProtCtrl.Fields.CDSS,
+        ProtCtrl.Fields.EMODE,
+        ProtCtrl.Fields.DMASEL,
+        ProtCtrl.Fields.SABGREQ,
+        ProtCtrl.Fields.BURST_LEN_EN);
+
+    LOG_INFO(
+        " - WTMK_LVL\t:0x%08x RD_WML:%d RD_BRST_LEN:%d WR_WML:%d WR_BRST_LEN:%d",
+        WtmkLvl.AsUint32,
+        WtmkLvl.Fields.RD_WML,
+        WtmkLvl.Fields.RD_BRST_LEN,
+        WtmkLvl.Fields.WR_WML,
+        WtmkLvl.Fields.WR_BRST_LEN);
+
+    LOG_INFO(
+        " - MIX_CTRL\t:0x%08x DMAEN:%d BCEN:%d AC12EN:%d DTDSEL:%d MSBSEL:%d AC23EN:%d FBCLK_SEL:%d",
+        MixCtrl.AsUint32,
+        MixCtrl.Fields.DMAEN,
+        MixCtrl.Fields.BCEN,
+        MixCtrl.Fields.AC12EN,
+        MixCtrl.Fields.DTDSEL,
+        MixCtrl.Fields.MSBSEL,
+        MixCtrl.Fields.AC23EN,
+        MixCtrl.Fields.FBCLK_SEL);
+
+    LOG_INFO(" - INT_STATUS_EN\t:0x%08x", IntStatusEn);
+    LOG_INFO(" - INT_SIGNAL_EN\t:0x%08x", IntSignalEn);
+    LOG_INFO(" - VEND_SPEC\t:0x%08x", VendSpec);
+    LOG_INFO(" - MMC_BOOT\t:0x%08x", MmcBoot);
+    LOG_INFO(" - VEND_SPEC2\t:0x%08x", VendSpec2);
+
+    LOG_INFO(
+        " - INT_STATUS\t:0x%08x CC:%d TC:%d BWR:%d BRR:%d CTOE:%d CCE:%d CEBE:%d CIE:%d DTOE:%d DCE:%d DEBE:%d",
+        IntStatus.AsUint32,
+        IntStatus.Fields.CC,
+        IntStatus.Fields.TC,
+        IntStatus.Fields.BWR,
+        IntStatus.Fields.BRR,
+        IntStatus.Fields.CTOE,
+        IntStatus.Fields.CCE,
+        IntStatus.Fields.CEBE,
+        IntStatus.Fields.CIE,
+        IntStatus.Fields.DTOE,
+        IntStatus.Fields.DCE,
+        IntStatus.Fields.DEBE);
+
+    LOG_INFO(
+        " - PRES_STATE\t:0x%08x CIHB:%d CDIHB:%d DLA:%d WTA:%d RTA:%d BWEN:%d BREN:%d CINST:%d DLSL:0x%x",
+        PresState.AsUint32,
+        PresState.Fields.CIHB,
+        PresState.Fields.CDIHB,
+        PresState.Fields.DLA,
+        PresState.Fields.WTA,
+        PresState.Fields.RTA,
+        PresState.Fields.BWEN,
+        PresState.Fields.BREN,
+        PresState.Fields.CINST,
+        PresState.Fields.DLSL);
+
+DEBUG_CODE_END ();
+}
+
+EFI_STATUS
+WaitForReadFifo(
+    IN USDHC_PRIVATE_CONTEXT *SdhcCtx
+    )
+{
+    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
+    USDHC_INT_STATUS_REG IntStatus; IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS);
+    UINT32 Retry = USDHC_POLL_RETRY_COUNT;
+
+    while (!IntStatus.Fields.BRR &&
+        !(IntStatus.AsUint32 & USDHC_INT_STATUS_ERROR) &&
+        Retry) {
+       --Retry;
+       gBS->Stall(USDHC_POLL_WAIT_US);
+       IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS);
+    }
+
+    if (IntStatus.AsUint32 & USDHC_INT_STATUS_ERROR) {
+        LOG_ERROR("Error detected");
+        DumpState(SdhcCtx);
+        return EFI_DEVICE_ERROR;
+    } else if (IntStatus.Fields.BRR) {
+        MmioWrite32((UINTN)&Reg->INT_STATUS, IntStatus.AsUint32);
+        return EFI_SUCCESS;
+    } else {
+        ASSERT(!Retry);
+        LOG_ERROR("Time-out waiting on read FIFO");
+        DumpState(SdhcCtx);
+        return EFI_TIMEOUT;
+     }
+}
+
+EFI_STATUS
+WaitForWriteFifo(
+    IN USDHC_PRIVATE_CONTEXT *SdhcCtx
+    )
+{
+    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
+    USDHC_INT_STATUS_REG IntStatus; IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS) ;
+    UINT32 Retry = USDHC_POLL_RETRY_COUNT;
+
+    while (!IntStatus.Fields.BWR &&
+        !(IntStatus.AsUint32 & USDHC_INT_STATUS_ERROR) &&
+        Retry) {
+       --Retry;
+       gBS->Stall(USDHC_POLL_WAIT_US);
+       IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS);
+    }
+
+    if (IntStatus.AsUint32 & USDHC_INT_STATUS_ERROR) {
+        LOG_ERROR("Error detected");
+        DumpState(SdhcCtx);
+        return EFI_DEVICE_ERROR;
+    } else if (IntStatus.Fields.BWR) {
+        MmioWrite32((UINTN)&Reg->INT_STATUS, IntStatus.AsUint32);
+        return EFI_SUCCESS;
+    } else {
+        ASSERT(!Retry);
+        LOG_ERROR("Time-out waiting on write FIFO");
+        DumpState(SdhcCtx);
+        return EFI_TIMEOUT;
+    }
+}
+
+EFI_STATUS
+WaitForCmdAndOrDataLine(
+    IN USDHC_PRIVATE_CONTEXT *SdhcCtx,
+    IN const SD_COMMAND *Cmd
+    )
+{
+    BOOLEAN WaitForDataLine;
+
+    //
+    // Waiting on the DATA lines is the default behavior if no CMD is specified
+    //
+    if (Cmd == NULL) {
+        WaitForDataLine = TRUE;
+    } else {
+        //
+        // Per datasheet, the SDHC can isssue CMD0, CMD12, CMD13 and CMD52
+        // when the DATA lines are busy during a data transfer. Other commands
+        // should wait on the DATA lines before issuing
+        //
+        switch (Cmd->Index) {
+        case 0:
+        case 12:
+        case 13:
+        case 52:
+            WaitForDataLine = FALSE;
+            break;
+        default:
+            WaitForDataLine = TRUE;
+        }
+    }
+
+    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
+    USDHC_PRES_STATE_REG PresState; PresState.AsUint32 = MmioRead32((UINTN)&Reg->PRES_STATE);
+    USDHC_INT_STATUS_REG IntStatus; IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS) ;
+    UINT32 Retry = USDHC_POLL_RETRY_COUNT;
+
+    while (PresState.Fields.CIHB &&
+           (!WaitForDataLine || PresState.Fields.CDIHB) &&
+           !(IntStatus.AsUint32 & USDHC_INT_STATUS_ERROR) &&
+           Retry) {
+        gBS->Stall(USDHC_POLL_WAIT_US);
+        --Retry;
+        PresState.AsUint32 = MmioRead32((UINTN)&Reg->PRES_STATE);
+        IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS);
+    }
+
+    if (IntStatus.AsUint32 & USDHC_INT_STATUS_ERROR) {
+        LOG_ERROR("Error detected");
+        DumpState(SdhcCtx);
+        return EFI_DEVICE_ERROR;
+    } else if (!(PresState.Fields.CIHB &&
+           (!WaitForDataLine || PresState.Fields.CDIHB))) {
+           return EFI_SUCCESS;
+    } else {
+        ASSERT(!Retry);
+        LOG_ERROR("Time-out waiting on CMD and/or DATA lines");
+        DumpState(SdhcCtx);
+        return EFI_TIMEOUT;
+    }
+}
+
+EFI_STATUS
+WaitForCmdResponse(
+    IN USDHC_PRIVATE_CONTEXT *SdhcCtx
+    )
+{
+    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
+    USDHC_INT_STATUS_REG IntStatus; IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS) ;
+    UINT32 Retry = USDHC_POLL_RETRY_COUNT;
+
+    //
+    // Wait for command to finish execution either with success or failure
+    //
+    while (!IntStatus.Fields.CC &&
+           !(IntStatus.AsUint32 & USDHC_INT_STATUS_ERROR) &&
+           Retry) {
+        gBS->Stall(USDHC_POLL_WAIT_US);
+        --Retry;
+        IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS);
+    }
+
+    if (IntStatus.AsUint32 & USDHC_INT_STATUS_ERROR) {
+        LOG_ERROR("Error detected");
+        DumpState(SdhcCtx);
+        return EFI_DEVICE_ERROR;
+    } else if (IntStatus.Fields.CC) {
+        MmioWrite32((UINTN)&Reg->INT_STATUS, IntStatus.AsUint32);
+        return EFI_SUCCESS;
+    } else {
+        ASSERT(!Retry);
+        LOG_ERROR("Time-out waiting on command completion");
+        DumpState(SdhcCtx);
+        return EFI_TIMEOUT;
+    }
+}
+
+EFI_STATUS
+SdhcSetBusWidth(
+  IN EFI_SDHC_PROTOCOL *This,
+  IN SD_BUS_WIDTH BusWidth
+  )
+{
+    USDHC_PRIVATE_CONTEXT *SdhcCtx = (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
+    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
+    USDHC_PROT_CTRL_REG ProtCtrl; ProtCtrl.AsUint32 = MmioRead32((UINTN)&Reg->PROT_CTRL);
+
+    LOG_TRACE("SdhcSetBusWidth(%d)", BusWidth);
+
+    switch (BusWidth) {
+    case SdBusWidth1Bit:
+        ProtCtrl.Fields.DTW = USDHC_PROT_CTRL_DTW_1BIT;
+        break;
+    case SdBusWidth4Bit:
+        ProtCtrl.Fields.DTW = USDHC_PROT_CTRL_DTW_4BIT;
+        break;
+    case SdBusWidth8Bit:
+        ProtCtrl.Fields.DTW = USDHC_PROT_CTRL_DTW_8BIT;
+        break;
+    default:
+        LOG_ASSERT("Invalid bus width");
+        return EFI_INVALID_PARAMETER;
+    }
+
+    MmioWrite32((UINTN)&Reg->PROT_CTRL, ProtCtrl.AsUint32);
+
+    return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSetClock(
+    IN EFI_SDHC_PROTOCOL *This,
+    IN UINT32 TargetFreqHz
+    )
+{
+    USDHC_PRIVATE_CONTEXT *SdhcCtx = (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
+
+    LOG_TRACE("SdhcSetClock(%dHz)", TargetFreqHz);
+
+    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
+    USDHC_SYS_CTRL_REG SysCtrl; SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
+
+    //
+    // SDCLK = (Base Clock) / (prescaler x divisor)
+    //
+    UINT32 Prescaler;
+    UINT32 Divisor;
+    UINT32 SDCLK;
+
+    USDHC_MIX_CTRL_REG MixCtrl; MixCtrl.AsUint32 = MmioRead32((UINTN)&Reg->MIX_CTRL);
+
+    //
+    // Bruteforce to find the best prescaler and divisor that result
+    // in SDCLK less than or equal to the requested frequency
+    //
+    // Allowed |Base clock divided By
+    // SDCLKFS |DDR_EN=0   |DDR_EN=1
+    // 80h      256         512
+    // 40h      128         256
+    // 20h      64          128
+    // 10h      32          64
+    // 08h      16          32
+    // 04h      8           16
+    // 02h      4           8
+    // 01h      2           4
+    // 00h      1           2
+    //
+    const UINT32 PRESCALER_MIN = (MixCtrl.Fields.DDR_EN ? 2 : 1);
+    const UINT32 PRESCALER_MAX = (MixCtrl.Fields.DDR_EN ? 512 : 256);;
+    const UINT32 DIVISOR_MIN = 1;
+    const UINT32 DIVISOR_MAX = 16;
+    UINT32 MinFreqDistance = 0xFFFFFFFF;
+    UINT32 FreqDistance;
+    UINT32 BestPrescaler = 0;
+    UINT32 BestDivisor = 0;
+
+    //
+    // Bruteforce to find the best prescaler and divisor that result
+    // in SDCLK less than or equal to the requested frequency
+    //
+    for (Prescaler = PRESCALER_MAX; Prescaler >= PRESCALER_MIN; Prescaler /= 2) {
+        for (Divisor = DIVISOR_MIN; Divisor <= DIVISOR_MAX; ++Divisor) {
+            SDCLK = USDHC_BASE_CLOCK_FREQ_HZ / (Prescaler * Divisor);
+
+            //
+            // We are not willing to choose clocks higher than the target one
+            // to avoid exceeding device limits
+            //
+            if (SDCLK > TargetFreqHz) {
+                continue;
+            } else if (SDCLK == TargetFreqHz) {
+                BestPrescaler = Prescaler;
+                BestDivisor = Divisor;
+                break;
+            } else {
+                FreqDistance = TargetFreqHz - SDCLK;
+                if (FreqDistance < MinFreqDistance) {
+                    MinFreqDistance = FreqDistance;
+                    BestPrescaler = Prescaler;
+                    BestDivisor = Divisor;
+                }
+            }
+        }
+    }
+
+    //
+    // Wait for clock to become stable before any modifications
+    //
+    USDHC_PRES_STATE_REG PresState; PresState.AsUint32 = MmioRead32((UINTN)&Reg->PRES_STATE);
+    UINT32 Retry = USDHC_POLL_RETRY_COUNT;
+
+    while (!PresState.Fields.SDSTB &&
+           Retry) {
+        gBS->Stall(USDHC_POLL_WAIT_US);
+        --Retry;
+        PresState.AsUint32 = MmioRead32((UINTN)&Reg->PRES_STATE);
+    }
+
+    if (!PresState.Fields.SDSTB) {
+        ASSERT(!Retry);
+        LOG_ERROR("Time-out waiting on SD clock to stabilize");
+        DumpState(SdhcCtx);
+        return EFI_TIMEOUT;
+    }
+
+    SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
+    SysCtrl.Fields.SDCLKFS = BestPrescaler / (MixCtrl.Fields.DDR_EN ? 4 : 2);
+    SysCtrl.Fields.DVS = BestDivisor - 1;
+
+    MmioWrite32((UINTN)&Reg->SYS_CTRL, SysCtrl.AsUint32);
+
+    SDCLK = USDHC_BASE_CLOCK_FREQ_HZ / (BestPrescaler * BestDivisor);
+
+    LOG_TRACE(
+        "Current SDCLK:%dHz SDCLKFS:0x%x DVS:0x%x",
+        SDCLK,
+        (UINT32)SysCtrl.Fields.SDCLKFS,
+        (UINT32)SysCtrl.Fields.DVS);
+
+    return EFI_SUCCESS;
+}
+
+BOOLEAN
+SdhcIsCardPresent(
+    IN EFI_SDHC_PROTOCOL *This
+    )
+{
+    USDHC_PRIVATE_CONTEXT *SdhcCtx = (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
+    BOOLEAN IsCardPresent;
+
+    if (SdhcCtx->CardDetectSignal == USDHC_SIGNAL_INTERNAL_PIN) {
+        USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
+        USDHC_PRES_STATE_REG PresState; PresState.AsUint32 = MmioRead32((UINTN)&Reg->PRES_STATE);
+        IsCardPresent = (PresState.Fields.CINST == 1);
+    } else {
+        IMX_GPIO_VALUE CardDetectLevel;
+        if (USDHC_IS_GPIO_SIGNAL_SOURCE(SdhcCtx->CardDetectSignal)) {
+            //
+            //Read the state of  CD_B pin for the card socket
+            //
+            CardDetectLevel =
+                ImxGpioRead(
+                    SdhcCtx->CardDetectGpioPin.Bank,
+                    SdhcCtx->CardDetectGpioPin.IoNumber);
+        } else if (SdhcCtx->CardDetectSignal == USDHC_SIGNAL_OVERRIDE_PIN_LOW) {
+            CardDetectLevel = IMX_GPIO_LOW;
+        } else if (SdhcCtx->CardDetectSignal == USDHC_SIGNAL_OVERRIDE_PIN_HIGH) {
+            CardDetectLevel = IMX_GPIO_HIGH;
+        } else {
+            ASSERT(!"Invalid CardDetect signal source");
+            CardDetectLevel = IMX_GPIO_LOW;
+        }
+
+        //
+        // When no card is present,  CD_B is pulled-high, and the SDCard when
+        // inserted will pull CD_B low
+        // CD_B=0 means card present, while CD_B=1 means card not present
+        //
+        IsCardPresent = (CardDetectLevel == IMX_GPIO_LOW);
+    }
+
+  // Enable if needed while trace debugging, otherwise this will flood the debug
+  // console due to being called periodically every second for each SDHC
+#if 0
+  LOG_TRACE("SdhcIsCardPresent(): %d", IsCardPresent);
+#endif
+
+    return IsCardPresent;
+}
+
+BOOLEAN
+SdhcIsReadOnly(
+    IN EFI_SDHC_PROTOCOL *This
+    )
+{
+    USDHC_PRIVATE_CONTEXT *SdhcCtx = (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
+    BOOLEAN IsReadOnly;
+
+    if (SdhcCtx->WriteProtectSignal == USDHC_SIGNAL_INTERNAL_PIN) {
+        USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
+        USDHC_PRES_STATE_REG PresState; PresState.AsUint32 = MmioRead32((UINTN)&Reg->PRES_STATE);
+        IsReadOnly = (PresState.Fields.WPSPL == 0);
+    } else {
+        IMX_GPIO_VALUE WriteProtectLevel;
+        if (USDHC_IS_GPIO_SIGNAL_SOURCE(SdhcCtx->WriteProtectSignal)) {
+            //
+            //Read the state of  WP pin for the card socket
+            //
+            WriteProtectLevel =
+                ImxGpioRead(
+                    SdhcCtx->WriteProtectGpioPin.Bank,
+                    SdhcCtx->WriteProtectGpioPin.IoNumber);
+        } else if (SdhcCtx->WriteProtectSignal == USDHC_SIGNAL_OVERRIDE_PIN_LOW) {
+            WriteProtectLevel = IMX_GPIO_LOW;
+        } else if (SdhcCtx->WriteProtectSignal == USDHC_SIGNAL_OVERRIDE_PIN_HIGH) {
+            WriteProtectLevel = IMX_GPIO_HIGH;
+        } else {
+            ASSERT(!"Invalid WriteProtect signal source");
+            WriteProtectLevel = IMX_GPIO_LOW;
+        }
+
+        //
+        // When no card is present,  WP is pulled-high, and the SDCard when
+        // inserted will pull WP low if WP switch is configured to write enable
+        // the SDCard, otherwise it WP will stay pulled-high
+        // WP=0 means write enabled, while WP=1 means write protected
+        //
+         IsReadOnly = (WriteProtectLevel != IMX_GPIO_LOW);
+    }
+
+    LOG_TRACE("SdhcIsReadOnly(): %d", IsReadOnly);
+    return IsReadOnly;
+}
+
+EFI_STATUS
+SdhcSendCommand(
+    IN EFI_SDHC_PROTOCOL *This,
+    IN const SD_COMMAND *Cmd,
+    IN UINT32 Argument,
+    IN OPTIONAL const SD_COMMAND_XFR_INFO *XfrInfo
+    )
+{
+    EFI_STATUS Status;
+    USDHC_PRIVATE_CONTEXT *SdhcCtx = (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
+    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
+
+    LOG_TRACE(
+        "SdhcSendCommand(%cCMD%d, %08x)",
+        ((Cmd->Class == SdCommandClassApp) ? 'A' : ' '),
+        (UINT32)Cmd->Index,
+        Argument);
+
+    Status = WaitForCmdAndOrDataLine(SdhcCtx, Cmd);
+    if (Status != EFI_SUCCESS) {
+        LOG_ERROR("SdhcWaitForCmdAndDataLine failed");
+        return Status;
+    }
+
+    //
+    // Clear Interrupt status
+    //
+    MmioWrite32((UINTN)&Reg->INT_STATUS, (UINT32)~0);
+
+    //
+    // Setup data transfer command
+    //
+    if (XfrInfo) {
+        if (XfrInfo->BlockCount > USDHC_MAX_BLOCK_COUNT) {
+            LOG_ERROR(
+                "Provided %d block count while SDHC max block count is %d",
+                XfrInfo->BlockCount,
+                USDHC_MAX_BLOCK_COUNT);
+            return EFI_INVALID_PARAMETER;
+        }
+
+        //
+        // Set block size and count
+        //
+        USDHC_BLK_ATT_REG BlkAtt = { 0 };
+        BlkAtt.Fields.BLKSIZE = XfrInfo->BlockSize;
+        ASSERT (XfrInfo->BlockCount > 0);
+        BlkAtt.Fields.BLKCNT = XfrInfo->BlockCount;
+        MmioWrite32((UINTN)&Reg->BLK_ATT, BlkAtt.AsUint32);
+
+        //
+        // Set transfer parameters
+        //
+        USDHC_MIX_CTRL_REG MixCtrl = { 0 };
+        if (Cmd->TransferDirection == SdTransferDirectionRead) {
+            MixCtrl.Fields.DTDSEL = 1;
+        }
+
+        if (XfrInfo->BlockCount > 1) {
+            ASSERT((Cmd->TransferType == SdTransferTypeMultiBlock) ||
+                (Cmd->TransferType == SdTransferTypeMultiBlockNoStop));
+            MixCtrl.Fields.MSBSEL = 1;
+            MixCtrl.Fields.BCEN = 1;
+        }
+
+        MmioWrite32((UINTN)&Reg->MIX_CTRL, MixCtrl.AsUint32);
+
+        USDHC_WTMK_LVL_REG WtmkLvl = { 0 };
+
+#if 0
+        //
+        // Set FIFO watermarks
+        //
+        // Configure FIFO watermark levels to 1/2 the FIFO capacity for read,
+        // and 1/3 the FIFO capacity for write.
+        // In case the whole transfer can fit in the FIFO, then use
+        // the whole transfer length as the FIFO threshold, so we do
+        // the read/write in one-shot
+        //
+
+        UINT32 FifoThresholdWordCount;
+        if (Cmd->TransferDirection == SdTransferDirectionRead) {
+            FifoThresholdWordCount = USDHC_FIFO_MAX_WORD_COUNT / 2;
+        } else {
+            FifoThresholdWordCount = USDHC_FIFO_MAX_WORD_COUNT / 3;
+        }
+
+        ASSERT(XfrInfo->BlockSize % sizeof(UINT32) == 0);
+        UINT32 TransferByteLength = XfrInfo->BlockSize * XfrInfo->BlockCount;
+        const UINT32 TransferWordCount = TransferByteLength / sizeof(UINT32);
+        FifoThresholdWordCount = MIN(TransferWordCount, FifoThresholdWordCount);
+
+        ASSERT(FifoThresholdWordCount <= 0xFFFF);
+        const UINT16 Wml = (UINT16)FifoThresholdWordCount;
+        ASSERT(Wml <= USDHC_FIFO_MAX_WORD_COUNT);
+
+        if (Cmd->TransferDirection == SdTransferDirectionRead) {
+            WtmkLvl.Fields.RD_WML = (UINT8)Wml;
+            WtmkLvl.Fields.RD_BRST_LEN = MIN(Wml, 8);
+        } else {
+            WtmkLvl.Fields.WR_WML = (UINT8)Wml;
+            WtmkLvl.Fields.WR_BRST_LEN = MIN(Wml, 8);;
+        }
+#endif
+
+#if 0
+        WtmkLvl.Fields.RD_WML = 64;
+        WtmkLvl.Fields.RD_BRST_LEN = 16;
+        WtmkLvl.Fields.WR_WML = 64;
+        WtmkLvl.Fields.WR_BRST_LEN = 16;
+#endif
+
+        UINT32 WtmkThreshold = USDHC_BLOCK_LENGTH_BYTES / 4;
+        if (Cmd->TransferDirection == SdTransferDirectionRead) {
+            if (WtmkThreshold > USDHC_WTMK_RD_WML_MAX_VAL) {
+                WtmkThreshold = USDHC_WTMK_RD_WML_MAX_VAL;
+            }
+            WtmkLvl.Fields.RD_WML = WtmkThreshold;
+        } else {
+            if (WtmkThreshold > USDHC_WTMK_WR_WML_MAX_VAL) {
+                WtmkThreshold = USDHC_WTMK_WR_WML_MAX_VAL;
+            }
+            WtmkLvl.Fields.WR_WML = WtmkThreshold;
+        }
+
+        MmioWrite32((UINTN)&Reg->WTMK_LVL, WtmkLvl.AsUint32);
+    }
+
+    //
+    // Set CMD parameters
+    //
+    USDHC_CMD_XFR_TYP_REG CmdXfrTyp = { 0 };
+    CmdXfrTyp.Fields.CMDINX = Cmd->Index;
+
+    switch (Cmd->ResponseType) {
+    case SdResponseTypeNone:
+        break;
+
+    case SdResponseTypeR1:
+    case SdResponseTypeR5:
+    case SdResponseTypeR6:
+        CmdXfrTyp.Fields.RSPTYP = USDHC_CMD_XFR_TYP_RSPTYP_RSP_48;
+        CmdXfrTyp.Fields.CICEN = 1;
+        CmdXfrTyp.Fields.CCCEN = 1;
+        break;
+
+    case SdResponseTypeR1B:
+    case SdResponseTypeR5B:
+        CmdXfrTyp.Fields.RSPTYP = USDHC_CMD_XFR_TYP_RSPTYP_RSP_48_CHK_BSY;
+        CmdXfrTyp.Fields.CICEN = 1;
+        CmdXfrTyp.Fields.CCCEN = 1;
+        break;
+
+    case SdResponseTypeR2:
+        CmdXfrTyp.Fields.RSPTYP = USDHC_CMD_XFR_TYP_RSPTYP_RSP_136;
+        CmdXfrTyp.Fields.CCCEN = 1;
+        break;
+
+    case SdResponseTypeR3:
+    case SdResponseTypeR4:
+        CmdXfrTyp.Fields.RSPTYP = USDHC_CMD_XFR_TYP_RSPTYP_RSP_48;
+        break;
+
+    default:
+        LOG_ASSERT("SdhcSendCommand(): Invalid response type");
+        return EFI_INVALID_PARAMETER;
+    }
+
+    if (Cmd->Type == SdCommandTypeAbort) {
+        CmdXfrTyp.Fields.CMDTYP = USDHC_CMD_XFR_TYP_CMDTYP_ABORT;
+    }
+
+    if (XfrInfo) {
+        CmdXfrTyp.Fields.DPSEL = 1;
+    }
+
+    //
+    // Send command and wait for response
+    //
+    MmioWrite32((UINTN)&Reg->CMD_ARG, Argument);
+    MmioWrite32((UINTN)&Reg->CMD_XFR_TYP, CmdXfrTyp.AsUint32);
+
+    Status = WaitForCmdResponse(SdhcCtx);
+    if (EFI_ERROR(Status)) {
+        LOG_ERROR("WaitForCmdResponse() failed. %r", Status);
+        return Status;
+    }
+
+    return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcReceiveResponse(
+    IN EFI_SDHC_PROTOCOL *This,
+    IN const SD_COMMAND *Cmd,
+    OUT UINT32 *Buffer
+    )
+{
+
+    USDHC_PRIVATE_CONTEXT *SdhcCtx = (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
+
+    if (Buffer == NULL) {
+        LOG_ERROR("Input Buffer is NULL");
+        return EFI_INVALID_PARAMETER;
+    }
+
+    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
+
+    switch (Cmd->ResponseType) {
+    case SdResponseTypeNone:
+        break;
+    case SdResponseTypeR1:
+    case SdResponseTypeR1B:
+    case SdResponseTypeR3:
+    case SdResponseTypeR4:
+    case SdResponseTypeR5:
+    case SdResponseTypeR5B:
+    case SdResponseTypeR6:
+        Buffer[0] = MmioRead32((UINTN)&Reg->CMD_RSP0);
+        LOG_TRACE(
+            "SdhcReceiveResponse(Type: %x), Buffer[0]: %08x",
+            Cmd->ResponseType,
+            Buffer[0]);
+        break;
+    case SdResponseTypeR2:
+        Buffer[0] = MmioRead32((UINTN)&Reg->CMD_RSP0);
+        Buffer[1] = MmioRead32((UINTN)&Reg->CMD_RSP1);
+        Buffer[2] = MmioRead32((UINTN)&Reg->CMD_RSP2);
+        Buffer[3] = MmioRead32((UINTN)&Reg->CMD_RSP3);
+
+        LOG_TRACE(
+            "SdhcReceiveResponse(Type: %x), Buffer[0-3]: %08x, %08x, %08x, %08x",
+            Cmd->ResponseType,
+            Buffer[0],
+            Buffer[1],
+            Buffer[2],
+            Buffer[3]);
+        break;
+    default:
+        LOG_ASSERT("SdhcReceiveResponse(): Invalid response type");
+        return EFI_INVALID_PARAMETER;
+    }
+
+    return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcReadBlockData(
+    IN EFI_SDHC_PROTOCOL *This,
+    IN UINTN LengthInBytes,
+    OUT UINT32* Buffer
+    )
+{
+    USDHC_PRIVATE_CONTEXT *SdhcCtx = (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
+
+    LOG_TRACE(
+        "SdhcReadBlockData(LengthInBytes: 0x%x, Buffer: 0x%x)",
+        LengthInBytes,
+        Buffer);
+
+    ASSERT(Buffer != NULL);
+    ASSERT(LengthInBytes % sizeof(UINT32) == 0);
+
+    UINTN WordIdx = 0;
+    UINTN NumWords = LengthInBytes / sizeof(UINT32);
+    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
+    USDHC_WTMK_LVL_REG WtmkLvl; WtmkLvl.AsUint32 = MmioRead32((UINTN)&Reg->WTMK_LVL);
+    UINT32 FifoWords;
+    EFI_STATUS Status;
+
+    ASSERT(WtmkLvl.Fields.RD_WML > 0);
+
+    while (WordIdx < NumWords) {
+        Status = WaitForReadFifo(SdhcCtx);
+        if (EFI_ERROR(Status)) {
+            LOG_ERROR(
+                "WaitForReadFifo() failed at Word%d. %r",
+                (UINT32)WordIdx,
+                Status);
+            return Status;
+        }
+
+        FifoWords = WtmkLvl.Fields.RD_WML;
+        while (WordIdx < NumWords && FifoWords--) {
+            Buffer[WordIdx] = MmioRead32((UINTN)&Reg->DATA_BUFF_ACC_PORT);
+            ++WordIdx;
+        }
+    }
+
+    return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcWriteBlockData(
+    IN EFI_SDHC_PROTOCOL *This,
+    IN UINTN LengthInBytes,
+    IN const UINT32* Buffer
+    )
+{
+    USDHC_PRIVATE_CONTEXT *SdhcCtx = (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
+
+    LOG_TRACE(
+        "SdhcWriteBlockData(LengthInBytes: 0x%x, Buffer: 0x%x)",
+        LengthInBytes,
+        Buffer);
+
+    ASSERT(Buffer != NULL);
+    ASSERT(LengthInBytes % USDHC_BLOCK_LENGTH_BYTES == 0);
+
+    const UINTN BlockWordCount = USDHC_BLOCK_LENGTH_BYTES / sizeof(UINT32);
+    UINTN NumBlocks = LengthInBytes / USDHC_BLOCK_LENGTH_BYTES;
+    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
+    USDHC_INT_STATUS_REG IntStatus;
+    USDHC_PRES_STATE_REG PresState;
+    INT32 Timeout = 100000; // Nothing special about that constant
+
+    while (NumBlocks > 0) {
+        UINTN RemainingWords = BlockWordCount;
+        IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS);
+        PresState.AsUint32 = MmioRead32((UINTN)&Reg->PRES_STATE);
+        while (!PresState.Fields.BWEN && --Timeout);
+        if (Timeout <= 0) {
+            LOG_ERROR ("Timeout waiting for FIFO PRES_STATE.BWEN flag");
+            return EFI_TIMEOUT;
+        }
+
+        while (RemainingWords > 0 && !IntStatus.Fields.TC) {
+            MicroSecondDelay (100);
+            IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS);
+            MmioWrite32((UINTN)&Reg->DATA_BUFF_ACC_PORT, *Buffer);
+            Buffer++;
+            RemainingWords--;
+        }
+        NumBlocks--;
+    }
+
+    return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSoftwareReset(
+    IN EFI_SDHC_PROTOCOL *This,
+    IN SDHC_RESET_TYPE ResetType
+    )
+{
+    USDHC_PRIVATE_CONTEXT *SdhcCtx = (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
+    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
+
+    UINT32 Retry;
+
+    if (ResetType == SdhcResetTypeAll) {
+        LOG_TRACE("SdhcSoftwareReset(ALL)");
+        //
+        // Software reset for ALL
+        //
+        USDHC_SYS_CTRL_REG SysCtrl; SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
+        SysCtrl.Fields.RSTA = 1;
+        MmioWrite32((UINTN)&Reg->SYS_CTRL, SysCtrl.AsUint32);
+        Retry = USDHC_POLL_RETRY_COUNT;
+        //
+        // Wait for reset to complete
+        //
+        while (SysCtrl.Fields.RSTA && Retry) {
+            --Retry;
+            gBS->Stall(USDHC_POLL_WAIT_US);
+            SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
+        }
+
+        if (SysCtrl.Fields.RSTA) {
+            ASSERT(!Retry);
+            LOG_ERROR("Time-out waiting on RSTA for self-clear");
+            return EFI_TIMEOUT;
+        }
+
+        //
+        // Disconnect interrupt signals between SDHC and GIC
+        //
+        MmioWrite32((UINTN)&Reg->INT_SIGNAL_EN, 0);
+
+        //
+        // Clear and Enable all interrupts
+        //
+        MmioWrite32((UINTN)&Reg->INT_STATUS, (UINT32)~0);
+        MmioWrite32((UINTN)&Reg->INT_STATUS_EN, (UINT32)~0);
+
+        LOG_TRACE("Waiting for CMD and DATA lines");
+
+        //
+        // Wait for CMD and DATA lines to become available
+        //
+        EFI_STATUS Status = WaitForCmdAndOrDataLine(SdhcCtx, NULL);
+        if (Status != EFI_SUCCESS) {
+            LOG_ERROR("SdhcWaitForCmdAndDataLine() failed. %r", Status);
+            return Status;
+        }
+
+        //
+        // Send 80 clock ticks to power-up the card
+        //
+        SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
+        SysCtrl.Fields.INITA = 1;
+        MmioWrite32((UINTN)&Reg->SYS_CTRL, SysCtrl.AsUint32);
+        Retry = USDHC_POLL_RETRY_COUNT;
+
+        //
+        // Wait for the 80 clock ticks to complete
+        //
+        while (SysCtrl.Fields.INITA && Retry) {
+            --Retry;
+            gBS->Stall(USDHC_POLL_WAIT_US);
+            SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
+        }
+
+        if (SysCtrl.Fields.INITA) {
+            ASSERT(!Retry);
+            LOG_ERROR("Time-out waiting on INITA for self-clear");
+            return EFI_TIMEOUT;
+        }
+
+        LOG_TRACE("Card power-up complete");
+
+        //
+        // Set max data-timout counter value
+        //
+        SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
+        SysCtrl.Fields.DTOCV = 0xF;
+        MmioWrite32((UINTN)&Reg->SYS_CTRL, SysCtrl.AsUint32);
+
+        //
+        // Reset Mixer Control
+        //
+        MmioWrite32((UINTN)&Reg->MIX_CTRL, 0);
+
+        USDHC_PROT_CTRL_REG ProtCtrl = { 0 };
+        ProtCtrl.Fields.EMODE = USDHC_PROT_CTRL_EMODE_LITTLE_ENDIAN;
+        ProtCtrl.Fields.LCTL = 1;
+        MmioWrite32((UINTN)&Reg->PROT_CTRL, ProtCtrl.AsUint32);
+
+        LOG_TRACE("Reset ALL complete");
+
+    }else if (ResetType == SdhcResetTypeCmd) {
+        LOG_TRACE("SdhcSoftwareReset(CMD)");
+        //
+        // Software reset for CMD
+        //
+        USDHC_SYS_CTRL_REG SysCtrl; SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
+        SysCtrl.Fields.RSTC = 1;
+        MmioWrite32((UINTN)&Reg->SYS_CTRL, SysCtrl.AsUint32);
+        Retry = USDHC_POLL_RETRY_COUNT;
+
+        //
+        // Wait for reset to complete
+        //
+        while (SysCtrl.Fields.RSTC && Retry) {
+            --Retry;
+            gBS->Stall(USDHC_POLL_WAIT_US);
+            SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
+        }
+
+        if (SysCtrl.Fields.RSTC) {
+            ASSERT(!Retry);
+            LOG_ERROR("Time-out waiting on RSTC for self-clear");
+            return EFI_TIMEOUT;
+        }
+
+        MmioWrite32((UINTN)&Reg->INT_STATUS, (UINT32)~0);
+
+        LOG_TRACE("Reset CMD complete");
+
+    } else if (ResetType == SdhcResetTypeData) {
+        LOG_TRACE("SdhcSoftwareReset(DAT)");
+        //
+        // Software reset for DAT
+        //
+        USDHC_SYS_CTRL_REG SysCtrl; SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
+        SysCtrl.Fields.RSTD = 1;
+        MmioWrite32((UINTN)&Reg->SYS_CTRL, SysCtrl.AsUint32);
+        Retry = USDHC_POLL_RETRY_COUNT;
+
+        //
+        // Wait for reset to complete
+        //
+        while (SysCtrl.Fields.RSTD && Retry) {
+            --Retry;
+            gBS->Stall(USDHC_POLL_WAIT_US);
+            SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
+        }
+
+        if (SysCtrl.Fields.RSTD) {
+            ASSERT(!Retry);
+            LOG_ERROR("Time-out waiting on RSTD for self-clear");
+            return EFI_TIMEOUT;
+        }
+
+        MmioWrite32((UINTN)&Reg->INT_STATUS, (UINT32)~0);
+
+        LOG_TRACE("Reset DAT complete");
+
+    } else {
+        return EFI_INVALID_PARAMETER;
+    }
+
+    return EFI_SUCCESS;
+}
+
+VOID
+SdhcCleanup(
+    IN EFI_SDHC_PROTOCOL *This
+    )
+{
+    if (This->PrivateContext != NULL) {
+        FreePool(This->PrivateContext);
+        This->PrivateContext = NULL;
+    }
+
+    FreePool(This);
+
+    //
+    // Any SDHC protocol call to this instance is illegal beyond this point
+    //
+}
+
+VOID
+SdhcGetCapabilities(
+    IN EFI_SDHC_PROTOCOL *This,
+    OUT SDHC_CAPABILITIES *Capabilities
+  )
+{
+    USDHC_PRIVATE_CONTEXT *SdhcCtx = (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
+    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
+
+    USDHC_HOST_CTRL_CAP_REG Caps; Caps.AsUint32 = MmioRead32((UINTN)&Reg->HOST_CTRL_CAP);
+
+    Capabilities->MaximumBlockSize = (UINT32)(512 << Caps.Fields.MBL);
+    Capabilities->MaximumBlockCount = 0xFFFF; // UINT16_MAX
+}
+
+
+EFI_SDHC_PROTOCOL gSdhcProtocolTemplate =
+{
+    SDHC_PROTOCOL_INTERFACE_REVISION,   // Revision
+    0,                                  // DeviceId
+    NULL,                               // PrivateContext
+    SdhcGetCapabilities,
+    SdhcSoftwareReset,
+    SdhcSetClock,
+    SdhcSetBusWidth,
+    SdhcIsCardPresent,
+    SdhcIsReadOnly,
+    SdhcSendCommand,
+    SdhcReceiveResponse,
+    SdhcReadBlockData,
+    SdhcWriteBlockData,
+    SdhcCleanup
+};
+
+EFI_STATUS
+uSdhcDeviceRegister(
+    IN EFI_HANDLE ImageHandle,
+    IN UINT32 SdhcId,
+    IN VOID* RegistersBase,
+    IN USDHC_SIGNAL_SOURCE CardDetectSignal,
+    IN USDHC_SIGNAL_SOURCE WriteProtectSignal
+    )
+{
+    EFI_STATUS Status;
+    EFI_SDHC_PROTOCOL *SdhcProtocol = NULL;
+    USDHC_PRIVATE_CONTEXT *SdhcCtx = NULL;
+
+    if (ImageHandle == NULL ||
+        RegistersBase == NULL) {
+        Status = EFI_INVALID_PARAMETER;
+        goto Exit;
+    }
+
+    //
+    // Allocate per-device SDHC protocol and private context storage
+    //
+
+    SdhcProtocol = AllocateCopyPool(sizeof(EFI_SDHC_PROTOCOL), &gSdhcProtocolTemplate);
+    if (SdhcProtocol == NULL) {
+        Status =  EFI_OUT_OF_RESOURCES;
+        goto Exit;
+    }
+    SdhcProtocol->SdhcId = SdhcId;
+    SdhcProtocol->PrivateContext = AllocateZeroPool(sizeof(USDHC_PRIVATE_CONTEXT));
+    if (SdhcProtocol->PrivateContext == NULL) {
+        Status = EFI_OUT_OF_RESOURCES;
+        goto Exit;
+    }
+
+    SdhcCtx = (USDHC_PRIVATE_CONTEXT*)SdhcProtocol->PrivateContext;
+    SdhcCtx->SdhcId = SdhcId;
+    SdhcCtx->RegistersBase = (USDHC_REGISTERS*)RegistersBase;
+    SdhcCtx->CardDetectSignal = CardDetectSignal;
+    if (USDHC_IS_GPIO_SIGNAL_SOURCE(SdhcCtx->CardDetectSignal)) {
+        SdhcCtx->CardDetectGpioPin.IoNumber = PCD_GPIO_PIN_IO_NUMBER((UINT16)CardDetectSignal);
+        SdhcCtx->CardDetectGpioPin.Bank = PCD_GPIO_PIN_BANK(CardDetectSignal);
+    }
+
+    SdhcCtx->WriteProtectSignal= WriteProtectSignal;
+    if (USDHC_IS_GPIO_SIGNAL_SOURCE(SdhcCtx->WriteProtectSignal)) {
+        SdhcCtx->WriteProtectGpioPin.IoNumber = PCD_GPIO_PIN_IO_NUMBER((UINT16)WriteProtectSignal);
+        SdhcCtx->WriteProtectGpioPin.Bank = PCD_GPIO_PIN_BANK(WriteProtectSignal);
+    }
+
+    LOG_INFO(
+        "Initializing uSDHC%d @%p GPIO CD?:%d WP?:%d",
+        SdhcId,
+        RegistersBase,
+        (USDHC_IS_GPIO_SIGNAL_SOURCE(SdhcCtx->CardDetectSignal) ? 1 : 0),
+        (USDHC_IS_GPIO_SIGNAL_SOURCE(SdhcCtx->WriteProtectSignal) ? 1 : 0));
+
+    if (USDHC_IS_GPIO_SIGNAL_SOURCE(SdhcCtx->CardDetectSignal)) {
+      LOG_INFO(
+          "Using GPIO%d_IO%d for CardDetect",
+          SdhcCtx->CardDetectGpioPin.Bank,
+          SdhcCtx->CardDetectGpioPin.IoNumber);
+    }
+
+    if (USDHC_IS_GPIO_SIGNAL_SOURCE(SdhcCtx->WriteProtectSignal)) {
+      LOG_INFO(
+          "Using GPIO%d_IO%d for WriteProtect",
+          SdhcCtx->WriteProtectGpioPin.Bank,
+          SdhcCtx->WriteProtectGpioPin.IoNumber);
+    }
+
+    Status = gBS->InstallMultipleProtocolInterfaces(
+                                                &SdhcCtx->SdhcProtocolHandle,
+                                                &gEfiSdhcProtocolGuid,
+                                                SdhcProtocol,
+                                                NULL);
+    if (EFI_ERROR(Status)) {
+        LOG_ERROR("InstallMultipleProtocolInterfaces failed. %r", Status);
+        goto Exit;
+    }
+
+Exit:
+    if (EFI_ERROR(Status)) {
+        LOG_ERROR("Failed to register and initialize uSDHC%d", SdhcId);
+
+        if (SdhcProtocol != NULL && SdhcProtocol->PrivateContext != NULL) {
+            FreePool(SdhcProtocol->PrivateContext);
+            SdhcProtocol->PrivateContext = NULL;
+        }
+
+        if (SdhcProtocol != NULL) {
+            FreePool(SdhcProtocol);
+            SdhcProtocol = NULL;
+        }
+    }
+
+    return Status;
+}
+
+EFI_STATUS
+SdhcInitialize(
+    IN EFI_HANDLE ImageHandle,
+    IN EFI_SYSTEM_TABLE *SystemTable
+    )
+{
+    EFI_STATUS Status = EFI_SUCCESS;
+    UINT32 uSdhcRegisteredCount = 0;
+
+    //
+    // Register uSDHC1 through uSDHC4 if their base address is non-zero
+    //
+
+    //
+    // uSDHC1
+    //
+    if (FixedPcdGet32(PcdSdhc1Enable)) {
+        Status = uSdhcDeviceRegister(
+            ImageHandle,
+            1,
+            (VOID*)FixedPcdGet32(PcdSdhc1Base),
+            FixedPcdGet32(PcdSdhc1CardDetectSignal),
+            FixedPcdGet32(PcdSdhc1WriteProtectSignal));
+        if (!EFI_ERROR(Status)) {
+            ++uSdhcRegisteredCount;
+        }
+    }
+
+    //
+    // uSDHC2
+    //
+    if (FixedPcdGet32(PcdSdhc2Enable)) {
+        Status = uSdhcDeviceRegister(
+            ImageHandle,
+            2,
+            (VOID*)FixedPcdGet32(PcdSdhc2Base),
+            FixedPcdGet32(PcdSdhc2CardDetectSignal),
+            FixedPcdGet32(PcdSdhc2WriteProtectSignal));
+        if (!EFI_ERROR(Status)) {
+            ++uSdhcRegisteredCount;
+        }
+    }
+
+    //
+    // uSDHC3
+    //
+    if (FixedPcdGet32(PcdSdhc3Enable)) {
+        Status = uSdhcDeviceRegister(
+            ImageHandle,
+            3,
+            (VOID*)FixedPcdGet32(PcdSdhc3Base),
+            FixedPcdGet32(PcdSdhc3CardDetectSignal),
+            FixedPcdGet32(PcdSdhc3WriteProtectSignal));
+        if (!EFI_ERROR(Status)) {
+            ++uSdhcRegisteredCount;
+        }
+    }
+
+    //
+    // uSDHC4
+    //
+    if (FixedPcdGet32(PcdSdhc4Enable)) {
+        Status = uSdhcDeviceRegister(
+            ImageHandle,
+            4,
+            (VOID*)FixedPcdGet32(PcdSdhc4Base),
+            FixedPcdGet32(PcdSdhc4CardDetectSignal),
+            FixedPcdGet32(PcdSdhc4WriteProtectSignal));
+        if (!EFI_ERROR(Status)) {
+            ++uSdhcRegisteredCount;
+        }
+    }
+
+    //
+    // Succeed driver loading if at least one enabled uSDHC got registered successfully
+    //
+    if ((Status != EFI_SUCCESS) && (uSdhcRegisteredCount > 0)) {
+        Status = EFI_SUCCESS;
+    }
+
+    return Status;
+}
diff --git a/Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.inf b/Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.inf
new file mode 100644
index 000000000000..5aee8b2ffbde
--- /dev/null
+++ b/Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.inf
@@ -0,0 +1,67 @@
+## @file
+#
+#  Copyright (c) Microsoft Corporation. All rights reserved.
+#
+#  This program and the accompanying materials
+#  are licensed and made available under the terms and conditions of the BSD License
+#  which accompanies this distribution.  The full text of the license may be found at
+#  http://opensource.org/licenses/bsd-license.php
+#
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = SdhcDxe
+  FILE_GUID                      = A9945BAB-78C9-43C9-9175-F576CA189870
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = SdhcInitialize
+
+[Sources.common]
+  SdhcDxe.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  Silicon/NXP/iMXPlatformPkg/iMXPlatformPkg.dec
+  Platform/Microsoft/MsPkg.dec
+
+[LibraryClasses]
+  PcdLib
+  UefiLib
+  UefiDriverEntryPoint
+  MemoryAllocationLib
+  IoLib
+  iMXIoMuxLib
+
+[Guids]
+
+[Protocols]
+  gEfiSdhcProtocolGuid
+
+[Pcd]
+  giMXPlatformTokenSpaceGuid.PcdSdhc1Base
+  giMXPlatformTokenSpaceGuid.PcdSdhc2Base
+  giMXPlatformTokenSpaceGuid.PcdSdhc3Base
+  giMXPlatformTokenSpaceGuid.PcdSdhc4Base
+  giMXPlatformTokenSpaceGuid.PcdSdhc1Enable
+  giMXPlatformTokenSpaceGuid.PcdSdhc2Enable
+  giMXPlatformTokenSpaceGuid.PcdSdhc3Enable
+  giMXPlatformTokenSpaceGuid.PcdSdhc4Enable
+  giMXPlatformTokenSpaceGuid.PcdSdhc1CardDetectSignal
+  giMXPlatformTokenSpaceGuid.PcdSdhc1WriteProtectSignal
+  giMXPlatformTokenSpaceGuid.PcdSdhc2CardDetectSignal
+  giMXPlatformTokenSpaceGuid.PcdSdhc2WriteProtectSignal
+  giMXPlatformTokenSpaceGuid.PcdSdhc3CardDetectSignal
+  giMXPlatformTokenSpaceGuid.PcdSdhc3WriteProtectSignal
+  giMXPlatformTokenSpaceGuid.PcdSdhc4CardDetectSignal
+  giMXPlatformTokenSpaceGuid.PcdSdhc4WriteProtectSignal
+
+[FixedPcd]
+  giMXPlatformTokenSpaceGuid.PcdGpioBankMemoryRange
+
+[depex]
+  TRUE
diff --git a/Silicon/NXP/iMXPlatformPkg/Include/iMXGpio.h b/Silicon/NXP/iMXPlatformPkg/Include/iMXGpio.h
new file mode 100644
index 000000000000..c75b543c8bb4
--- /dev/null
+++ b/Silicon/NXP/iMXPlatformPkg/Include/iMXGpio.h
@@ -0,0 +1,101 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef _IMX_GPIO_H_
+#define _IMX_GPIO_H_
+
+#include <Library/PcdLib.h>
+
+#ifndef C_ASSERT
+#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
+#endif // C_ASSERT
+
+typedef enum {
+    IMX_GPIO_LOW = 0,
+    IMX_GPIO_HIGH = 1
+} IMX_GPIO_VALUE;
+
+typedef enum {
+    IMX_GPIO_DIR_INPUT,
+    IMX_GPIO_DIR_OUTPUT
+} IMX_GPIO_DIR;
+
+typedef enum {
+    IMX_GPIO_BANK1 = 1,
+    IMX_GPIO_BANK2,
+    IMX_GPIO_BANK3,
+    IMX_GPIO_BANK4,
+    IMX_GPIO_BANK5,
+    IMX_GPIO_BANK6,
+    IMX_GPIO_BANK7,
+} IMX_GPIO_BANK;
+
+#pragma pack(push, 1)
+
+//
+// GPIO reserved size is based on total size minus 8 DWORD of standard GPIO reg
+//
+C_ASSERT((FixedPcdGet32(PcdGpioBankMemoryRange) % 4) == 0);
+
+#define GPIO_RESERVED_SIZE \
+    ((FixedPcdGet32(PcdGpioBankMemoryRange) / 4) - 8)
+
+typedef struct {
+    UINT32 DR;                            // 0x00 GPIO data register (GPIO1_DR)
+    UINT32 GDIR;                          // 0x04 GPIO direction register (GPIO1_GDIR)
+    UINT32 PSR;                           // 0x08 GPIO pad status register (GPIO1_PSR)
+    UINT32 ICR1;                          // 0x0C GPIO interrupt configuration register1 (GPIO1_ICR1)
+    UINT32 ICR2;                          // 0x10 GPIO interrupt configuration register2 (GPIO1_ICR2)
+    UINT32 IMR;                           // 0x14 GPIO interrupt mask register (GPIO1_IMR)
+    UINT32 ISR;                           // 0x18 GPIO interrupt status register (GPIO1_ISR)
+    UINT32 EDGE_SEL;                      // 0x1C GPIO edge select register (GPIO1_EDGE_SEL)
+    UINT32 reserved[GPIO_RESERVED_SIZE];
+} IMX_GPIO_BANK_REGISTERS;
+
+#pragma pack(pop)
+
+typedef struct {
+    IMX_GPIO_BANK_REGISTERS Banks[7];
+} IMX_GPIO_REGISTERS;
+
+/**
+    Set the specified GPIO to the specified direction.
+**/
+VOID
+ImxGpioDirection (
+    IMX_GPIO_BANK Bank,
+    UINT32 IoNumber,
+    IMX_GPIO_DIR Direction
+    );
+
+/**
+    Write a value to a GPIO pin.
+**/
+VOID
+ImxGpioWrite (
+    IMX_GPIO_BANK Bank,
+    UINT32 IoNumber,
+    IMX_GPIO_VALUE Value
+    );
+
+/**
+    Read a GPIO pin input value.
+**/
+IMX_GPIO_VALUE
+ImxGpioRead (
+    IMX_GPIO_BANK Bank,
+    UINT32 IoNumber
+    );
+
+#endif
diff --git a/Silicon/NXP/iMXPlatformPkg/Include/iMXuSdhc.h b/Silicon/NXP/iMXPlatformPkg/Include/iMXuSdhc.h
new file mode 100644
index 000000000000..acdbcd324631
--- /dev/null
+++ b/Silicon/NXP/iMXPlatformPkg/Include/iMXuSdhc.h
@@ -0,0 +1,277 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef __IMX_USDHC_H__
+#define __IMX_USDHC_H__
+
+//
+// uSDHCx Registers Layout
+//
+typedef struct {
+    UINT32 DS_ADDR;
+    UINT32 BLK_ATT;
+    UINT32 CMD_ARG;
+    UINT32 CMD_XFR_TYP;
+    UINT32 CMD_RSP0;
+    UINT32 CMD_RSP1;
+    UINT32 CMD_RSP2;
+    UINT32 CMD_RSP3;
+    UINT32 DATA_BUFF_ACC_PORT;
+    UINT32 PRES_STATE;
+    UINT32 PROT_CTRL;
+    UINT32 SYS_CTRL;
+    UINT32 INT_STATUS;
+    UINT32 INT_STATUS_EN;
+    UINT32 INT_SIGNAL_EN;
+    UINT32 AUTOCMD12_ERR_STATUS;
+    UINT32 HOST_CTRL_CAP;
+    UINT32 WTMK_LVL;
+    UINT32 MIX_CTRL;
+    UINT32 _pad0;
+    UINT32 FORCE_EVENT;
+    UINT32 ADMA_ERR_STATUS;
+    UINT32 ADMA_SYS_ADDR;
+    UINT32 _pad1;
+    UINT32 DLL_CTRL;
+    UINT32 DLL_STATUS;
+    UINT32 CLK_TUNE_CTRL_STATUS;
+    UINT32 _pad2[21];
+    UINT32 VEND_SPEC;
+    UINT32 MMC_BOOT;
+    UINT32 VEND_SPEC2;
+} USDHC_REGISTERS;
+
+//
+// Block Attributes uSDHCx_BLK_ATT fields
+//
+typedef union {
+   UINT32 AsUint32;
+   struct {
+      UINT32 BLKSIZE    : 13; // 0:12
+      UINT32 _reserved0 : 3;  // 13:15
+      UINT32 BLKCNT     : 16; // 16:31
+   } Fields;
+} USDHC_BLK_ATT_REG;
+
+//
+// Command Transfer Type uSDHCx_CMD_XFR_TYP fields
+//
+typedef union {
+    UINT32 AsUint32;
+    struct {
+        UINT32 _reserved0   : 16; // 0:15
+        UINT32 RSPTYP       : 2; // 16:17
+        UINT32 _reserved1   : 1; // 18
+        UINT32 CCCEN        : 1; // 19
+        UINT32 CICEN        : 1; // 20
+        UINT32 DPSEL        : 1; // 21
+        UINT32 CMDTYP       : 2; // 22:23
+        UINT32 CMDINX       : 6; // 24:29
+        UINT32 _reserved2   : 2; // 30:31
+    } Fields;
+} USDHC_CMD_XFR_TYP_REG;
+
+#define USDHC_CMD_XFR_TYP_RSPTYP_NO_RSP          0
+#define USDHC_CMD_XFR_TYP_RSPTYP_RSP_136         1
+#define USDHC_CMD_XFR_TYP_RSPTYP_RSP_48          2
+#define USDHC_CMD_XFR_TYP_RSPTYP_RSP_48_CHK_BSY  3
+#define USDHC_CMD_XFR_TYP_CMDTYP_ABORT           3
+
+//
+// System Control uSDHCx_SYS_CTRL fields
+//
+typedef union {
+    UINT32 AsUint32;
+    struct {
+        UINT32 _reserved0   : 4; // 0:3
+        UINT32 DVS          : 4; // 4:7
+        UINT32 SDCLKFS      : 8; // 8:15
+        UINT32 DTOCV        : 4; // 16:19
+        UINT32 _reserved1   : 3; // 20:22
+        UINT32 IPP_RST_N    : 1; // 23
+        UINT32 RSTA         : 1; // 24
+        UINT32 RSTC         : 1; // 25
+        UINT32 RSTD         : 1; // 26
+        UINT32 INITA        : 1; // 27
+        UINT32 _reserved2   : 4; // 28-31
+    } Fields;
+} USDHC_SYS_CTRL_REG;
+
+//
+// Host Controller Capabilities Register uSDHCx_HOST_CTRL_CAP fields
+//
+typedef union {
+    UINT32 AsUint32;
+    struct {
+        UINT32 _reserved0       : 16; // 0:15
+        UINT32 MBL              : 3; // 16:18
+        UINT32 _reserved1       : 1; // 19
+        UINT32 ADMAS            : 1; // 20
+        UINT32 HSS              : 1; // 21
+        UINT32 DMAS             : 1; // 22
+        UINT32 SRS              : 1; // 23
+        UINT32 VS33             : 1; // 24
+        UINT32 VS30             : 1; // 25
+        UINT32 VS18             : 1; // 26
+        UINT32 _reserved2       : 5; // 27:31
+    } Fields;
+} USDHC_HOST_CTRL_CAP_REG;
+
+//
+// Watermark Level uSDHCx_WTMK_LVL
+//
+typedef union {
+    UINT32 AsUint32;
+    struct {
+        UINT32 RD_WML           : 8; // 0:7
+        UINT32 RD_BRST_LEN      : 5; // 8:12
+        UINT32 _reserved0       : 3; // 13:15
+        UINT32 WR_WML           : 8; // 16:23
+        UINT32 WR_BRST_LEN      : 5; // 24:28
+        UINT32 _reserved1       : 3; // 29:31
+    } Fields;
+} USDHC_WTMK_LVL_REG;
+
+#define USDHC_WTMK_RD_WML_MAX_VAL   0x10
+#define USDHC_WTMK_WR_WML_MAX_VAL   0x80
+
+//
+// Mixer Control uSDHCx_MIX_CTRL fields
+//
+typedef union {
+    UINT32 AsUint32;
+    struct {
+        UINT32 DMAEN          : 1; // 0
+        UINT32 BCEN           : 1; // 1
+        UINT32 AC12EN         : 1; // 2
+        UINT32 DDR_EN         : 1; // 3
+        UINT32 DTDSEL         : 1; // 4
+        UINT32 MSBSEL         : 1; // 5
+        UINT32 NIBBLE_POS     : 1; // 6
+        UINT32 AC23EN         : 1; // 7
+        UINT32 _reserved0     : 14; // 8:21
+        UINT32 EXE_TUNE       : 1; // 22
+        UINT32 SMP_CLK_SEL    : 1; // 23
+        UINT32 AUTO_TUNE_EN   : 1; //24
+        UINT32 FBCLK_SEL      : 1; // 25
+        UINT32 _reserved1     : 6; // 26-31
+    } Fields;
+} USDHC_MIX_CTRL_REG;
+
+//
+// Present State uSDHCx_PRES_STATE fields
+//
+typedef union {
+    UINT32 AsUint32;
+    struct {
+        UINT32 CIHB         : 1; // 0
+        UINT32 CDIHB        : 1; // 1
+        UINT32 DLA          : 1; // 2
+        UINT32 SDSTB        : 1; // 3
+        UINT32 IPGOFF       : 1; // 4
+        UINT32 HCKOFF       : 1; // 5
+        UINT32 PEROFF       : 1; // 6
+        UINT32 SDOFF        : 1; // 7
+        UINT32 WTA          : 1; // 8
+        UINT32 RTA          : 1; // 9
+        UINT32 BWEN         : 1; // 10
+        UINT32 BREN         : 1; // 11
+        UINT32 PTR          : 1; // 12
+        UINT32 _reserved0   : 3; // 13:15
+        UINT32 CINST        : 1; // 16
+        UINT32 _reserved1   : 1; // 17
+        UINT32 CDPL         : 1; // 18
+        UINT32 WPSPL        : 1; // 19
+        UINT32 _reserved2   : 3; // 20:22
+        UINT32 CLSL         : 1; // 23
+        UINT32 DLSL         : 8; // 24:31
+    } Fields;
+} USDHC_PRES_STATE_REG;
+
+//
+// Present State uSDHCx_PROT_CTRL fields
+//
+typedef union {
+    UINT32 AsUint32;
+    struct {
+        UINT32 LCTL             : 1; // 0
+        UINT32 DTW              : 2; // 1:2
+        UINT32 D3CD             : 1; // 3
+        UINT32 EMODE            : 2; // 4:5
+        UINT32 CDTL             : 1; // 6
+        UINT32 CDSS             : 1; // 7
+        UINT32 DMASEL           : 2; // 8:9
+        UINT32 _reserved0       : 6; // 10:15
+        UINT32 SABGREQ          : 1; // 16
+        UINT32 CREQ             : 1; // 17
+        UINT32 RWCTL            : 1; // 18
+        UINT32 IABG             : 1; // 19
+        UINT32 RD_DONE_NO_8CLK  : 1; // 20
+        UINT32 _reserved1       : 3; // 21:23
+        UINT32 WECINT           : 1; // 24
+        UINT32 WECINS           : 1; // 25
+        UINT32 WECRM            : 1; // 26
+        UINT32 BURST_LEN_EN     : 3; // 27:29
+        UINT32 NON_EXACT_BLK_RD : 1; // 30
+        UINT32 _reserved2       : 1; // 31
+    } Fields;
+} USDHC_PROT_CTRL_REG;
+
+#define USDHC_PROT_CTRL_DTW_1BIT             0x0
+#define USDHC_PROT_CTRL_DTW_4BIT             0x1
+#define USDHC_PROT_CTRL_DTW_8BIT             0x2
+#define USDHC_PROT_CTRL_EMODE_LITTLE_ENDIAN  0x2
+
+//
+// Interrupt Status uSDHCx_INT_STATUS fields
+//
+typedef union {
+    UINT32 AsUint32;
+    struct {
+        UINT32 CC           : 1; // 0
+        UINT32 TC           : 1; // 1
+        UINT32 BGE          : 1; // 2
+        UINT32 DINT         : 1; // 3
+        UINT32 BWR          : 1; // 4
+        UINT32 BRR          : 1; // 5
+        UINT32 CINS         : 1; // 6
+        UINT32 CRM          : 1; // 7
+        UINT32 CINT         : 1; // 8
+        UINT32 _reserved0   : 3; // 9:11
+        UINT32 RTE          : 1; // 12
+        UINT32 _reserved1   : 1; // 13
+        UINT32 TP           : 1; // 14
+        UINT32 _reserved2   : 1; // 15
+        UINT32 CTOE         : 1; // 16
+        UINT32 CCE          : 1; // 17
+        UINT32 CEBE         : 1; // 18
+        UINT32 CIE          : 1; // 19
+        UINT32 DTOE         : 1; // 20
+        UINT32 DCE          : 1; // 21
+        UINT32 DEBE         : 1; // 22
+        UINT32 _reserved3   : 1; // 23
+        UINT32 AC12E        : 1; // 24
+        UINT32 _reserved4   : 1; // 25
+        UINT32 TNE          : 1; // 26
+        UINT32 _reserved5   : 1; // 27
+        UINT32 DMAE         : 1; // 28
+        UINT32 _reserved6   : 3; // 29:31
+    } Fields;
+} USDHC_INT_STATUS_REG;
+
+#define USDHC_INT_STATUS_CMD_ERROR   (BIT16 | BIT17 | BIT18 | BIT19)
+#define USDHC_INT_STATUS_DATA_ERROR  (BIT20 | BIT21 | BIT22)
+#define USDHC_INT_STATUS_ERROR       (USDHC_INT_STATUS_CMD_ERROR | USDHC_INT_STATUS_DATA_ERROR)
+
+#endif // __IMX_USDHC_H__
-- 
2.16.2.gvfs.1.33.gf5370f1



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH edk2-platforms 2/7] Silicon/NXP: Add iMX display library support
  2018-07-19  4:11 [PATCH edk2-platforms 0/7] Silicon/NXP: Import NXP i.MX platform package Chris Co
  2018-07-19  4:11 ` [PATCH edk2-platforms 1/7] Silicon/NXP: Add support for iMX SDHC Chris Co
@ 2018-07-19  4:11 ` Chris Co
  2018-07-19  4:11 ` [PATCH edk2-platforms 3/7] Silicon/NXP: Add I2C library support for iMX platforms Chris Co
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Chris Co @ 2018-07-19  4:11 UTC (permalink / raw)
  To: edk2-devel@lists.01.org; +Cc: Ard Biesheuvel, Leif Lindholm, Michael D Kinney

This adds support for processing EDID data on NXP i.MX platforms.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Christopher Co <christopher.co@microsoft.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
---
 Silicon/NXP/iMXPlatformPkg/Include/iMXDisplay.h                    |  95 +++++++++++++++
 Silicon/NXP/iMXPlatformPkg/Library/iMXDisplayLib/iMXDisplayLib.c   | 125 ++++++++++++++++++++
 Silicon/NXP/iMXPlatformPkg/Library/iMXDisplayLib/iMXDisplayLib.inf |  31 +++++
 3 files changed, 251 insertions(+)

diff --git a/Silicon/NXP/iMXPlatformPkg/Include/iMXDisplay.h b/Silicon/NXP/iMXPlatformPkg/Include/iMXDisplay.h
new file mode 100644
index 000000000000..d805c6b4bc39
--- /dev/null
+++ b/Silicon/NXP/iMXPlatformPkg/Include/iMXDisplay.h
@@ -0,0 +1,95 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef __IMX_DISPLAY_H__
+#define __IMX_DISPLAY_H__
+
+#define EDID_MIN_SIZE       128
+#define EDID_I2C_ADDRESS    0x50
+
+//
+// The first DTD is the preferred timing, refer to 3.1 VESA EDID spec.
+//
+#define EDID_DTD_1_OFFSET   0x36
+#define EDID_DTD_2_OFFSET   0x48
+#define EDID_DTD_3_OFFSET   0x5A
+#define EDID_DTD_4_OFFSET   0x6C
+
+typedef enum {
+    PIXEL_FORMAT_ARGB32,
+    PIXEL_FORMAT_BGRA32,
+} PIXEL_FORMAT;
+
+typedef struct _DISPLAY_TIMING {
+    UINT32 PixelClock;
+    UINT32 HActive;
+    UINT32 HBlank;
+    UINT32 VActive;
+    UINT32 VBlank;
+    UINT32 HSync;
+    UINT32 VSync;
+    UINT32 HSyncOffset;
+    UINT32 VSyncOffset;
+    UINT32 HImageSize;
+    UINT32 VImageSize;
+    UINT32 HBorder;
+    UINT32 VBorder;
+    UINT32 EdidFlags;
+    UINT32 Flags;
+    UINT32 PixelRepetition;
+    UINT32 Bpp;
+    PIXEL_FORMAT PixelFormat;
+} DISPLAY_TIMING, *PDISPLAY_TIMING, DTD;
+
+typedef struct _DETAILED_TIMING_DESCRIPTOR {
+    UINT8 PixelClock[2];
+    UINT8 HActive;
+    UINT8 HBlank;
+    UINT8 HActiveBlank;
+    UINT8 VActive;
+    UINT8 VBlank;
+    UINT8 VActiveBlank;
+    UINT8 HSyncOffset;
+    UINT8 HSyncWidth;
+    UINT8 VSyncOffsetWidth;
+    UINT8 HVOffsetWidth;
+    UINT8 HImageSize;
+    UINT8 VImageSize;
+    UINT8 HVImageSize;
+    UINT8 HBorder;
+    UINT8 VBorder;
+    UINT8 EdidFlags;
+} DETAILED_TIMING_DESCRIPTOR, *PDETAILED_TIMING_DESCRIPTOR;
+
+//
+// Convert detailed timing descriptor to display timing format
+//
+EFI_STATUS
+ConvertDTDToDisplayTiming (
+    DETAILED_TIMING_DESCRIPTOR* DTDPtr,
+    DISPLAY_TIMING* DisplayTimingPtr
+    );
+
+VOID
+PrintDisplayTiming (
+    char *DisplayTimingName,
+    DISPLAY_TIMING* DisplayTimingPtr
+    );
+
+EFI_STATUS
+ValidateEdidData (
+    UINT8* EdidDataPtr
+    );
+
+#endif // __IMX_DISPLAY_H__
diff --git a/Silicon/NXP/iMXPlatformPkg/Library/iMXDisplayLib/iMXDisplayLib.c b/Silicon/NXP/iMXPlatformPkg/Library/iMXDisplayLib/iMXDisplayLib.c
new file mode 100644
index 000000000000..67f3cd074cb5
--- /dev/null
+++ b/Silicon/NXP/iMXPlatformPkg/Library/iMXDisplayLib/iMXDisplayLib.c
@@ -0,0 +1,125 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include <Uefi.h>
+#include <Library/DebugLib.h>
+
+#include <iMXDisplay.h>
+
+EFI_STATUS
+ConvertDTDToDisplayTiming(
+    DETAILED_TIMING_DESCRIPTOR* DTDPtr,
+    DISPLAY_TIMING* DisplayTimingPtr
+    )
+{
+    DEBUG((DEBUG_INFO,"++ConvertDTDToDisplayTiming()\r\n"));
+    // Refer to 3.10.2 VESA EDID spec
+    UINT32 edidPixelClock =
+        (DTDPtr->PixelClock[0] | (DTDPtr->PixelClock[1] << 8));
+
+    DisplayTimingPtr->PixelClock = edidPixelClock * 10000;
+    DisplayTimingPtr->HActive = (DTDPtr->HActiveBlank & 0xF0);
+    DisplayTimingPtr->HActive = (DisplayTimingPtr->HActive << 4) | DTDPtr->HActive;
+    DisplayTimingPtr->HBlank = (DTDPtr->HActiveBlank & 0x0F);
+    DisplayTimingPtr->HBlank = (DisplayTimingPtr->HBlank << 8) | DTDPtr->HBlank;
+    DisplayTimingPtr->VActive = (DTDPtr->VActiveBlank & 0xF0);
+    DisplayTimingPtr->VActive = (DisplayTimingPtr->VActive << 4) | DTDPtr->VActive;
+    DisplayTimingPtr->VBlank = (DTDPtr->VActiveBlank & 0x0F);
+    DisplayTimingPtr->VBlank = (DisplayTimingPtr->VBlank << 8) | DTDPtr->VBlank;
+    DisplayTimingPtr->HSyncOffset = (DTDPtr->HVOffsetWidth & 0xC0);
+    DisplayTimingPtr->HSyncOffset = (DisplayTimingPtr->HSyncOffset << 2) | DTDPtr->HSyncOffset;
+    DisplayTimingPtr->VSyncOffset = (DTDPtr->HVOffsetWidth & 0x0C);
+    DisplayTimingPtr->VSyncOffset = (DisplayTimingPtr->VSyncOffset << 2) | ((DTDPtr->VSyncOffsetWidth & 0xF0) >> 4);
+    DisplayTimingPtr->HSync = (DTDPtr->HVOffsetWidth & 0x30);
+    DisplayTimingPtr->HSync = (DisplayTimingPtr->HSync << 4) | DTDPtr->HSyncWidth;
+    DisplayTimingPtr->VSync = (DTDPtr->HVOffsetWidth & 0x03);
+    DisplayTimingPtr->VSync = (DisplayTimingPtr->VSync << 4) | (DTDPtr->VSyncOffsetWidth & 0x0F);
+    DisplayTimingPtr->HImageSize = ((DTDPtr->HVImageSize & 0xF0) << 4) | DTDPtr->HImageSize;
+    DisplayTimingPtr->VImageSize = ((DTDPtr->HVImageSize & 0x0F) << 8) | DTDPtr->VImageSize;
+    DisplayTimingPtr->HBorder = DTDPtr->HBorder;
+    DisplayTimingPtr->VBorder = DTDPtr->VBorder;
+    DisplayTimingPtr->EdidFlags = DTDPtr->EdidFlags;
+    DisplayTimingPtr->Flags = 0;
+    DEBUG((DEBUG_INFO,"--ConvertDTDToDisplayTiming()=ok\r\n"));
+    return EFI_SUCCESS;
+}
+
+VOID
+PrintDisplayTiming (
+    char *DisplayTimingNamePtr,
+    DISPLAY_TIMING* DisplayTimingPtr
+    )
+{
+    DEBUG((DEBUG_INFO, "**********************\n"));
+    DEBUG((DEBUG_INFO, "%a\n", DisplayTimingNamePtr));
+    DEBUG((DEBUG_INFO, "**********************\n"));
+    DEBUG((DEBUG_INFO, "PixelClock %d\n", DisplayTimingPtr->PixelClock));
+    DEBUG((DEBUG_INFO, "HActive %d\n", DisplayTimingPtr->HActive));
+    DEBUG((DEBUG_INFO, "HBlank %d\n", DisplayTimingPtr->HBlank));
+    DEBUG((DEBUG_INFO, "VActive %d\n", DisplayTimingPtr->VActive));
+    DEBUG((DEBUG_INFO, "VBlank %d\n", DisplayTimingPtr->VBlank));
+    DEBUG((DEBUG_INFO, "HSync %d\n", DisplayTimingPtr->HSync));
+    DEBUG((DEBUG_INFO, "VSync %d\n", DisplayTimingPtr->VSync));
+    DEBUG((DEBUG_INFO, "HSyncOffset %d\n", DisplayTimingPtr->HSyncOffset));
+    DEBUG((DEBUG_INFO, "VSyncOffset %d\n", DisplayTimingPtr->VSyncOffset));
+    DEBUG((DEBUG_INFO, "HBorder %d\n", DisplayTimingPtr->HBorder));
+    DEBUG((DEBUG_INFO, "VBorder %d\n", DisplayTimingPtr->VBorder));
+    DEBUG((DEBUG_INFO, "EdidFlags %d\n", DisplayTimingPtr->EdidFlags));
+    DEBUG((DEBUG_INFO, "Flags %d\n", DisplayTimingPtr->Flags));
+    DEBUG((DEBUG_INFO, "PixelRepetition %d\n", DisplayTimingPtr->PixelRepetition));
+    DEBUG((DEBUG_INFO, "BPP %d\n", DisplayTimingPtr->Bpp));
+    DEBUG((DEBUG_INFO, "PixelFormat %d\n", DisplayTimingPtr->PixelFormat));
+    DEBUG((DEBUG_INFO, "**********************\n"));
+}
+
+EFI_STATUS
+ValidateEdidData (
+    UINT8* EdidDataPtr
+    )
+{
+    UINT8 checksum, index;
+    DEBUG((DEBUG_INFO,"++ValidateEdidData()\r\n"));
+
+    //
+    // Check if the EDID header matches
+    //
+    if (EdidDataPtr[0] != 0x00 ||
+        EdidDataPtr[1] != 0xFF ||
+        EdidDataPtr[2] != 0xFF ||
+        EdidDataPtr[3] != 0xFF ||
+        EdidDataPtr[4] != 0xFF ||
+        EdidDataPtr[5] != 0xFF ||
+        EdidDataPtr[6] != 0xFF ||
+        EdidDataPtr[7] != 0x00) {
+
+        DEBUG((DEBUG_ERROR, "Invalid EDID header\n"));
+        return EFI_INVALID_PARAMETER;
+    }
+
+    //
+    // Validate EDID checksum
+    //
+    checksum = 0;
+    for (index = 0; index < EDID_MIN_SIZE; index++) {
+        checksum += EdidDataPtr[index];
+    }
+
+    if (checksum != 0) {
+
+        DEBUG((DEBUG_ERROR, "Invalid EDID checksum\n"));
+        return EFI_INVALID_PARAMETER;
+    }
+    DEBUG((DEBUG_INFO,"--ValidateEdidData()=ok\r\n"));
+    return EFI_SUCCESS;
+}
diff --git a/Silicon/NXP/iMXPlatformPkg/Library/iMXDisplayLib/iMXDisplayLib.inf b/Silicon/NXP/iMXPlatformPkg/Library/iMXDisplayLib/iMXDisplayLib.inf
new file mode 100644
index 000000000000..06a6ebaa10f9
--- /dev/null
+++ b/Silicon/NXP/iMXPlatformPkg/Library/iMXDisplayLib/iMXDisplayLib.inf
@@ -0,0 +1,31 @@
+## @file
+#
+#  Copyright (c) Microsoft Corporation. All rights reserved.
+#
+#  This program and the accompanying materials
+#  are licensed and made available under the terms and conditions of the BSD License
+#  which accompanies this distribution.  The full text of the license may be found at
+#  http://opensource.org/licenses/bsd-license.php
+#
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = iMXDisplayLib
+  FILE_GUID                      = C0408490-F09B-4CFA-9A2F-5159F2705323
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = iMXDisplayLib
+
+[Packages]
+  MdePkg/MdePkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  Silicon/NXP/iMXPlatformPkg/iMXPlatformPkg.dec
+
+[LibraryClasses]
+
+[Sources.common]
+  iMXDisplayLib.c
-- 
2.16.2.gvfs.1.33.gf5370f1



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH edk2-platforms 3/7] Silicon/NXP: Add I2C library support for iMX platforms
  2018-07-19  4:11 [PATCH edk2-platforms 0/7] Silicon/NXP: Import NXP i.MX platform package Chris Co
  2018-07-19  4:11 ` [PATCH edk2-platforms 1/7] Silicon/NXP: Add support for iMX SDHC Chris Co
  2018-07-19  4:11 ` [PATCH edk2-platforms 2/7] Silicon/NXP: Add iMX display library support Chris Co
@ 2018-07-19  4:11 ` Chris Co
  2018-07-19  4:11 ` [PATCH edk2-platforms 4/7] Silicon/NXP: Add UART " Chris Co
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Chris Co @ 2018-07-19  4:11 UTC (permalink / raw)
  To: edk2-devel@lists.01.org; +Cc: Ard Biesheuvel, Leif Lindholm, Michael D Kinney

This adds support for I2C controller on NXP i.MX platforms.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Christopher Co <christopher.co@microsoft.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
---
 Silicon/NXP/iMXPlatformPkg/Include/iMXI2cLib.h             | 158 ++++++
 Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.c   | 524 ++++++++++++++++++++
 Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.inf |  35 ++
 3 files changed, 717 insertions(+)

diff --git a/Silicon/NXP/iMXPlatformPkg/Include/iMXI2cLib.h b/Silicon/NXP/iMXPlatformPkg/Include/iMXI2cLib.h
new file mode 100644
index 000000000000..e0688d7aa89f
--- /dev/null
+++ b/Silicon/NXP/iMXPlatformPkg/Include/iMXI2cLib.h
@@ -0,0 +1,158 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef _IMX_I2C_H_
+#define _IMX_I2C_H_
+
+#pragma pack(push, 1)
+
+typedef union {
+  UINT16 AsUint16;
+  struct {
+    UINT16 Reserved0 : 1;
+    UINT16 ADR : 7;
+    UINT16 Reserved1 : 8;
+  };
+} IMX_I2C_IADR_REG;
+
+typedef union {
+  UINT16 AsUint16;
+  struct {
+    UINT16 IC : 6;
+    UINT16 Reserved0 : 10;
+  };
+} IMX_I2C_IFDR_REG;
+
+
+typedef union {
+  UINT16 AsUint16;
+  struct {
+    UINT16 Reserved0 : 2;
+    UINT16 RSTA : 1;
+    UINT16 TXAK : 1;
+    UINT16 MTX : 1;
+    UINT16 MSTA : 1;
+    UINT16 IIEN : 1;
+    UINT16 IEN : 1;
+    UINT16 Reserved1 : 8;
+  };
+} IMX_I2C_I2CR_REG;
+
+#define IMX_I2C_I2SR_RXAK        0x0001
+#define IMX_I2C_I2SR_IIF         0x0002
+#define IMX_I2C_I2SR_SRW         0x0004
+#define IMX_I2C_I2SR_IAL         0x0010
+#define IMX_I2C_I2SR_IBB         0x0020
+#define IMX_I2C_I2SR_IAAS        0x0040
+#define IMX_I2C_I2SR_ICF         0x0080
+
+typedef union {
+  UINT16 AsUint16;
+  struct {
+    UINT16 RXAK : 1;
+    UINT16 IIF : 1;
+    UINT16 SRW : 1;
+    UINT16 Reserved0 : 1;
+    UINT16 IAL : 1;
+    UINT16 IBB : 1;
+    UINT16 IAAS : 1;
+    UINT16 ICF : 1;
+    UINT16 Reserved1 : 8;
+  };
+} IMX_I2C_I2SR_REG;
+
+typedef union {
+  UINT16 AsUint16;
+  struct {
+    UINT16 DATA : 8;
+    UINT16 Reserved0 : 8;
+  };
+} IMX_I2C_I2DR_REG;
+
+typedef struct {
+  IMX_I2C_IADR_REG IADR;
+  UINT16 Pad0;
+  IMX_I2C_IFDR_REG IFDR;
+  UINT16 Pad1;
+  IMX_I2C_I2CR_REG I2CR;
+  UINT16 Pad2;
+  IMX_I2C_I2DR_REG I2SR;
+  UINT16 Pad3;
+  IMX_I2C_I2DR_REG I2DR;
+  UINT16 Pad4;
+} IMX_I2C_REGS;
+
+#pragma pack(pop)
+
+typedef struct {
+  UINT32 ControllerAddress;
+  UINT32 ControllerSlaveAddress;
+  UINT32 ReferenceFreq;
+  UINT32 TargetFreq;
+  UINT32 SlaveAddress;
+  UINT32 TimeoutInUs;
+} IMX_I2C_CONFIG;
+
+/** Performs i2c read operation.
+
+  The iMXI2cRead perform i2c read operation by programming the i2c controller.
+  The caller is responsible to provide i2c controller configuration.
+
+  @param[in] IMX_I2C_CONFIG* Structure containing the targeted i2c controller
+  to be used for i2c operation. The structure contains important information
+  such as the controller base address, reference frequency.
+  @param[in] RegisterAddress Targeted device register address to start read.
+  @param[out] ReadBufferPtr Caller supplied buffer that would be written into
+  with data from the read operation.
+  @param[in] ReadBufferSize Size of caller supplied buffer.
+
+  @retval EFI_SUCCESS i2c Read operation succeed.
+  @retval !EFI_SUCCESS Failure.
+
+--*/
+RETURN_STATUS
+iMXI2cRead (
+  IN IMX_I2C_CONFIG*  I2cConfigPtr,
+  IN UINT8            RegisterAddress,
+  OUT UINT8*          ReadBufferPtr,
+  IN UINT32           ReadBufferSize
+  );
+
+/** Performs i2c write operation.
+
+  The iMXI2cWrite perform i2c write operation by programming the i2c
+  controller. The caller is responsible to provide i2c controller
+  configuration.
+
+  @param[in] IMX_I2C_CONFIG* Structure containing the targeted i2c controller
+  to be used for i2c operation. The structure contains important information
+  such as the controller base address, reference frequency.
+  @param[in] RegisterAddress Targeted device register address to start write.
+  @param[out] WriteBufferPtr Caller supplied buffer that contained data that
+  would be read from for i2c write operation..
+  @param[in] WriteBufferSize Size of caller supplied buffer.
+
+  @retval EFI_SUCCESS i2c Write operation succeed.
+  @retval !EFI_SUCCESS Failure.
+
+--*/
+RETURN_STATUS
+iMXI2cWrite (
+  IN IMX_I2C_CONFIG*  I2cConfigPtr,
+  IN UINT8            RegisterAddress,
+  IN UINT8*           WriteBufferPtr,
+  IN UINT32           WriteBufferSize
+  );
+
+#endif
diff --git a/Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.c b/Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.c
new file mode 100644
index 000000000000..00da831ae6b6
--- /dev/null
+++ b/Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.c
@@ -0,0 +1,524 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include <Uefi.h>
+#include <Base.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/IoLib.h>
+#include <Library/TimerLib.h>
+#include <Library/DebugLib.h>
+
+#include <iMXI2cLib.h>
+
+typedef struct {
+  UINT32 Divider;
+  UINT32 IC;
+} IMX_I2C_DIVIDER;
+
+IMX_I2C_DIVIDER DividerValue[] = {
+  { 22, 0x20, },
+  { 24, 0x21, },
+  { 26, 0x22, },
+  { 28, 0x23, },
+  { 30, 0x00, },
+  { 32, 0x24, },
+  { 36, 0x25, },
+  { 40, 0x26, },
+  { 42, 0x03, },
+  { 44, 0x27, },
+  { 48, 0x28, },
+  { 52, 0x05, },
+  { 56, 0x29, },
+  { 60, 0x06, },
+  { 64, 0x2A, },
+  { 72, 0x2B, },
+  { 80, 0x2C, },
+  { 88, 0x09, },
+  { 96, 0x2D, },
+  { 104, 0x0A, },
+  { 112, 0x2E, },
+  { 128, 0x2F, },
+  { 144, 0x0C, },
+  { 160, 0x30, },
+  { 192, 0x31, },
+  { 224, 0x32, },
+  { 240, 0x0F, },
+  { 256, 0x33, },
+  { 288, 0x10, },
+  { 320, 0x34, },
+  { 384, 0x35, },
+  { 448, 0x36, },
+  { 480, 0x13, },
+  { 512, 0x37, },
+  { 576, 0x14, },
+  { 640, 0x38, },
+  { 768, 0x39, },
+  { 896, 0x3A, },
+  { 960, 0x17, },
+  { 1024, 0x3B, },
+  { 1152, 0x18, },
+  { 1280, 0x3C, },
+  { 1536, 0x3D, },
+  { 1792, 0x3E, },
+  { 1920, 0x1B, },
+  { 2048, 0x3F, },
+  { 2304, 0x1C, },
+  { 2560, 0x1D, },
+  { 3072, 0x1E, },
+  { 3840, 0x1F, },
+};
+
+#define DIVIDER_VALUE_TOTAL (sizeof(DividerValue) / sizeof(DividerValue[0]))
+
+BOOLEAN
+iMXI2cWaitStatusSet (
+  IMX_I2C_CONFIG* I2cConfigPtr,
+  UINT16          StatusBits
+  )
+{
+  UINT32 counter = I2cConfigPtr->TimeoutInUs;
+  IMX_I2C_REGS* i2cRegsPtr = (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddress;
+
+  while (counter) {
+    IMX_I2C_I2SR_REG i2srReg = { MmioRead16((UINTN)&i2cRegsPtr->I2SR) };
+
+    if ((i2srReg.AsUint16 & StatusBits) == StatusBits) {
+      return TRUE;
+    }
+
+    MicroSecondDelay(1);
+    --counter;
+  }
+
+  return FALSE;
+}
+
+BOOLEAN
+iMXI2cWaitStatusUnSet (
+  IMX_I2C_CONFIG* I2cConfigPtr,
+  UINT16          StatusBits
+)
+{
+  UINT32 counter = I2cConfigPtr->TimeoutInUs;
+  IMX_I2C_REGS* i2cRegsPtr = (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddress;
+
+  while (counter) {
+    IMX_I2C_I2SR_REG i2srReg = { MmioRead16((UINTN)&i2cRegsPtr->I2SR) };
+
+    if ((i2srReg.AsUint16 & StatusBits) == 0) {
+      return TRUE;
+    }
+
+    MicroSecondDelay(1);
+    --counter;
+  }
+
+  return FALSE;;
+}
+
+BOOLEAN
+iMXI2cSendByte (
+  IMX_I2C_CONFIG* I2cConfigPtr,
+  UINT8           Data
+)
+{
+  UINT16 sendData = Data;
+  UINT32 counter = I2cConfigPtr->TimeoutInUs;
+  IMX_I2C_REGS* i2cRegsPtr = (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddress;
+
+  //
+  // Clear status
+  //
+  MmioWrite16((UINTN)&i2cRegsPtr->I2SR, 0);
+
+  //
+  // Transfer byte
+  //
+  MmioWrite16((UINTN)&i2cRegsPtr->I2DR, sendData);
+
+  while (counter) {
+    IMX_I2C_I2SR_REG i2srReg = { MmioRead16((UINTN)&i2cRegsPtr->I2SR) };
+
+    if (i2srReg.IIF == 1) {
+      return TRUE;
+    }
+    else if (i2srReg.IAL == 1) {
+
+      DEBUG((
+        DEBUG_ERROR,
+        "iMXI2cSendByte: fail 0x%04x\n",
+        i2srReg.AsUint16));
+      return FALSE;
+    }
+
+    MicroSecondDelay(1);
+    --counter;
+  }
+
+  DEBUG((DEBUG_ERROR, "iMXI2cSendByte: Fail timeout\n"));
+
+  return FALSE;
+}
+
+RETURN_STATUS
+iMXI2cSetupController (
+  IMX_I2C_CONFIG* I2cConfigPtr,
+  UINT8           RegisterAddress
+  )
+{
+  IMX_I2C_REGS* i2cRegsPtr = (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddress;
+
+  //
+  // Disable controller and clear any pending interrupt
+  //
+  MmioWrite16((UINTN)&i2cRegsPtr->I2CR, 0);
+  MmioWrite16((UINTN)&i2cRegsPtr->I2SR, 0);
+
+  //
+  // Setup divider if reference freq is provided. If no use value setup by
+  // 1st boot loader
+  //
+  if (I2cConfigPtr->ReferenceFreq != 0) {
+
+    UINT32 ifdrDiv = 0;
+    UINT32 dividerCount;
+    UINT32 divider = I2cConfigPtr->ReferenceFreq / I2cConfigPtr->TargetFreq;
+
+    for (dividerCount = 0;
+      dividerCount < DIVIDER_VALUE_TOTAL;
+      ++dividerCount) {
+
+      if (DividerValue[dividerCount].Divider >= divider) {
+
+        DEBUG((
+          DEBUG_INFO,
+          "iMXI2cSetupController: divider %d IC 0x%02x\n",
+          DividerValue[dividerCount].Divider,
+          DividerValue[dividerCount].IC));
+
+        ifdrDiv = DividerValue[dividerCount].IC;
+        break;
+      }
+    }
+
+    if (ifdrDiv == 0) {
+      DEBUG((
+        DEBUG_ERROR,
+        "iMXI2cSetupController: could not find divider for %d\n",
+        divider));
+      return RETURN_INVALID_PARAMETER;
+    }
+
+    MmioWrite16((UINTN)&i2cRegsPtr->IFDR, ifdrDiv);
+  }
+
+  //
+  // Setup slave address
+  //
+  MmioWrite16((UINTN)&i2cRegsPtr->IADR, (I2cConfigPtr->ControllerSlaveAddress << 1));
+
+  //
+  // Enable controller and set to master mode.
+  //
+  {
+    IMX_I2C_I2CR_REG i2crReg = { MmioRead16((UINTN)&i2cRegsPtr->I2CR) };
+
+    //
+    // This bit must be set before any other I2C_I2CR bits have an effect
+    //
+    i2crReg.IEN = 1;
+    MmioWrite16((UINTN)&i2cRegsPtr->I2CR, i2crReg.AsUint16);
+    MicroSecondDelay(100);
+
+    MmioWrite16((UINTN)&i2cRegsPtr->I2SR, 0);
+
+    //
+    // Wait for bus to be idle
+    //
+    if (iMXI2cWaitStatusUnSet(I2cConfigPtr, IMX_I2C_I2SR_IBB) == FALSE) {
+      DEBUG((DEBUG_ERROR, "iMXI2cGenerateStart: Controller remains busy\n"));
+      return RETURN_DEVICE_ERROR;
+    }
+
+    i2crReg.MSTA = 1;
+    MmioWrite16((UINTN)&i2cRegsPtr->I2CR, i2crReg.AsUint16);
+
+    //
+    // Now wait for bus to be busy
+    //
+    if (iMXI2cWaitStatusSet(I2cConfigPtr, IMX_I2C_I2SR_IBB) == FALSE) {
+      DEBUG((DEBUG_ERROR, "iMXI2cGenerateStart: Controller remains idle\n"));
+      return RETURN_DEVICE_ERROR;
+    }
+  }
+
+  return RETURN_SUCCESS;
+}
+
+RETURN_STATUS
+iMXI2cGenerateStart (
+  IMX_I2C_CONFIG* I2cConfigPtr,
+  UINT8           RegisterAddress,
+  BOOLEAN         Read
+  )
+{
+  BOOLEAN result;
+  RETURN_STATUS status;
+  IMX_I2C_REGS* i2cRegsPtr = (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddress;
+
+  status = iMXI2cSetupController(
+    I2cConfigPtr,
+    RegisterAddress);
+  if (RETURN_ERROR(status)) {
+    DEBUG((DEBUG_ERROR, "iMXI2cGenerateStart: Fail to setup controller %r\n", status));
+    return status;
+  }
+
+  //
+  // Send slave address so set controller to transmit mode
+  //
+  {
+    IMX_I2C_I2CR_REG i2crReg = { MmioRead16((UINTN)&i2cRegsPtr->I2CR) };
+
+    i2crReg.MTX = 1;
+    MmioWrite16((UINTN)&i2cRegsPtr->I2CR, i2crReg.AsUint16);
+  }
+
+  result = iMXI2cSendByte(
+    I2cConfigPtr,
+    (I2cConfigPtr->SlaveAddress << 1));
+  if (result == FALSE) {
+    DEBUG((
+      DEBUG_ERROR,
+      "iMXI2cGenerateStart: Slave address transfer fail 0x%04x\n",
+      MmioRead16((UINTN)&i2cRegsPtr->I2SR)));
+    return RETURN_DEVICE_ERROR;
+  }
+
+  //
+  // Send slave register
+  //
+  result = iMXI2cSendByte(
+    I2cConfigPtr,
+    RegisterAddress);
+  if (result == FALSE) {
+    DEBUG((
+      DEBUG_ERROR,
+      "iMXI2cGenerateStart: Slave register address transfer fail 0x%04x\n",
+      MmioRead16((UINTN)&i2cRegsPtr->I2SR)));
+    return RETURN_DEVICE_ERROR;
+  }
+
+  return RETURN_SUCCESS;
+}
+
+RETURN_STATUS
+iMXI2cGenerateStop (
+  IMX_I2C_CONFIG* I2cConfigPtr
+  )
+{
+  IMX_I2C_REGS* i2cRegsPtr = (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddress;
+  IMX_I2C_I2CR_REG i2crReg = { MmioRead16((UINTN)&i2cRegsPtr->I2CR) };
+
+  i2crReg.MSTA = 0;
+  i2crReg.MTX = 0;
+  MmioWrite16((UINTN)&i2cRegsPtr->I2CR, i2crReg.AsUint16);
+
+  //
+  // Bus should go idle
+  //
+  if (iMXI2cWaitStatusUnSet(I2cConfigPtr, IMX_I2C_I2SR_IBB) == FALSE) {
+    DEBUG((DEBUG_ERROR, "iMXI2cGenerateStop: Controller remains busy\n"));
+    return RETURN_DEVICE_ERROR;
+  }
+
+  return RETURN_SUCCESS;
+}
+
+RETURN_STATUS
+iMXI2cRead (
+  IN IMX_I2C_CONFIG*  I2cConfigPtr,
+  IN UINT8            RegisterAddress,
+  OUT UINT8*          ReadBufferPtr,
+  IN UINT32           ReadBufferSize
+  )
+{
+  RETURN_STATUS status;
+  IMX_I2C_REGS* i2cRegsPtr = (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddress;
+
+  status = iMXI2cGenerateStart(
+    I2cConfigPtr,
+    RegisterAddress,
+    TRUE);
+  if (RETURN_ERROR(status)) {
+    DEBUG((DEBUG_ERROR, "iMXI2cRead: iMXI2cGenerateStart failed %r\n", status));
+    goto Exit;
+  }
+
+  //
+  // Send slave address again to begin read
+  //
+  {
+    BOOLEAN result;
+    IMX_I2C_I2CR_REG i2crReg = { MmioRead16((UINTN)&i2cRegsPtr->I2CR) };
+
+    i2crReg.RSTA = 1; // Repeated start
+    MmioWrite16((UINTN)&i2cRegsPtr->I2CR, i2crReg.AsUint16);
+
+    result = iMXI2cSendByte(
+      I2cConfigPtr,
+      (I2cConfigPtr->SlaveAddress << 1 | 1));
+    if (result == FALSE) {
+      DEBUG((
+        DEBUG_ERROR,
+        "iMXI2cRead: 2nd Slave address transfer failed 0x%04x\n",
+        MmioRead16((UINTN)&i2cRegsPtr->I2SR)));
+      status = RETURN_DEVICE_ERROR;
+      goto Exit;
+    }
+  }
+
+  //
+  // Disable master mode
+  //
+  {
+    IMX_I2C_I2CR_REG i2crReg = { MmioRead16((UINTN)&i2cRegsPtr->I2CR) };
+
+    //
+    // NXP application note AN4481
+    // Only one byte so do not send acknowledge
+    //
+    if (ReadBufferSize == 1) {
+      i2crReg.TXAK = 1;
+    }
+    else {
+      i2crReg.TXAK = 0;
+    }
+
+    i2crReg.MTX = 0;
+    MmioWrite16((UINTN)&i2cRegsPtr->I2CR, i2crReg.AsUint16);
+  }
+
+  //
+  // A data transfer can now be initiated by a read from I2C_I2DR in Slave
+  // Receive mode.
+  //
+  {
+    MmioWrite16((UINTN)&i2cRegsPtr->I2SR, 0);
+    MmioRead16((UINTN)&i2cRegsPtr->I2DR);
+  }
+
+  do {
+    //
+    // Wait for transfer to complete
+    //
+    if (iMXI2cWaitStatusSet(I2cConfigPtr, IMX_I2C_I2SR_IIF) == FALSE) {
+      DEBUG((DEBUG_ERROR, "iMXI2cRead: waiting for read fail\n"));
+      status = RETURN_DEVICE_ERROR;
+      goto Exit;
+    }
+
+    if (iMXI2cWaitStatusSet(I2cConfigPtr, IMX_I2C_I2SR_ICF) == FALSE) {
+      DEBUG((DEBUG_ERROR, "iMXI2cRead: waiting for read fail\n"));
+      status = RETURN_DEVICE_ERROR;
+      goto Exit;
+    }
+
+    //
+    // Per spec. Before the last byte is read, a Stop signal must be generated
+    //
+    if (ReadBufferSize == 1) {
+
+      status = iMXI2cGenerateStop(
+        I2cConfigPtr);
+      if (RETURN_ERROR(status)) {
+        DEBUG((DEBUG_ERROR, "iMXI2cRead: iMXI2cGenerateStop fail %r\n", status));
+        goto Exit;
+      }
+    }
+
+    if (ReadBufferSize == 2) {
+      IMX_I2C_I2CR_REG i2crReg = { MmioRead16((UINTN)&i2cRegsPtr->I2CR) };
+
+      i2crReg.TXAK = 1;
+      MmioWrite16((UINTN)&i2cRegsPtr->I2CR, i2crReg.AsUint16);
+    }
+
+    MmioWrite16((UINTN)&i2cRegsPtr->I2SR, 0);
+
+    *ReadBufferPtr = MmioRead8((UINTN)&i2cRegsPtr->I2DR);
+
+    ++ReadBufferPtr;
+    --ReadBufferSize;
+
+  } while (ReadBufferSize > 0);
+
+Exit:
+  status = iMXI2cGenerateStop(
+    I2cConfigPtr);
+  if (RETURN_ERROR(status)) {
+    DEBUG((DEBUG_ERROR, "iMXI2cRead: Final iMXI2cGenerateStop fail %r\n", status));
+  }
+
+  return status;
+}
+
+RETURN_STATUS
+iMXI2cWrite (
+  IN IMX_I2C_CONFIG*  I2cConfigPtr,
+  IN UINT8            RegisterAddress,
+  IN UINT8*           WriteBufferPtr,
+  IN UINT32           WriteBufferSize
+  )
+{
+  RETURN_STATUS status;
+  IMX_I2C_REGS* i2cRegsPtr = (IMX_I2C_REGS*)I2cConfigPtr->ControllerAddress;
+
+  status = iMXI2cGenerateStart(
+    I2cConfigPtr,
+    RegisterAddress,
+    FALSE);
+  if (RETURN_ERROR(status)) {
+    DEBUG((DEBUG_ERROR, "iMXI2cWrite: iMXI2cGenerateStart fail %r\n", status));
+    goto Exit;
+  }
+
+  while (WriteBufferSize > 0) {
+
+    BOOLEAN result = iMXI2cSendByte(
+      I2cConfigPtr,
+      *WriteBufferPtr);
+    if (result == FALSE) {
+      DEBUG((
+        DEBUG_ERROR,
+        "iMXI2cWrite: Slave address transfer fail 0x%04x\n",
+        MmioRead16((UINTN)&i2cRegsPtr->I2SR)));
+      status = RETURN_DEVICE_ERROR;
+      goto Exit;
+    }
+
+    ++WriteBufferPtr;
+    --WriteBufferSize;
+  }
+
+Exit:
+  status = iMXI2cGenerateStop(
+    I2cConfigPtr);
+  if (RETURN_ERROR(status)) {
+    DEBUG((DEBUG_ERROR, "iMXI2cWrite: iMXI2cGenerateStop fail %r\n", status));
+  }
+
+  return status;
+}
diff --git a/Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.inf b/Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.inf
new file mode 100644
index 000000000000..409fc8f14166
--- /dev/null
+++ b/Silicon/NXP/iMXPlatformPkg/Library/iMXI2cLib/iMXI2cLib.inf
@@ -0,0 +1,35 @@
+## @file
+#
+#  Copyright (c) Microsoft Corporation. All rights reserved.
+#
+#  This program and the accompanying materials
+#  are licensed and made available under the terms and conditions of the BSD License
+#  which accompanies this distribution.  The full text of the license may be found at
+#  http://opensource.org/licenses/bsd-license.php
+#
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = iMXI2cLib
+  FILE_GUID                      = C4E4A003-8AEB-4C9B-8E72-D2BAD2134BDE
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = iMXI2cLib
+
+[Packages]
+  MdePkg/MdePkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  Silicon/NXP/iMXPlatformPkg/iMXPlatformPkg.dec
+
+[LibraryClasses]
+  DebugLib
+  IoLib
+  TimerLib
+  BaseMemoryLib
+
+[Sources.common]
+  iMXI2cLib.c
-- 
2.16.2.gvfs.1.33.gf5370f1



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH edk2-platforms 4/7] Silicon/NXP: Add UART library support for iMX platforms
  2018-07-19  4:11 [PATCH edk2-platforms 0/7] Silicon/NXP: Import NXP i.MX platform package Chris Co
                   ` (2 preceding siblings ...)
  2018-07-19  4:11 ` [PATCH edk2-platforms 3/7] Silicon/NXP: Add I2C library support for iMX platforms Chris Co
@ 2018-07-19  4:11 ` Chris Co
  2018-07-19  4:11 ` [PATCH edk2-platforms 5/7] Silicon/NXP: Add Virtual RTC support for IMX platform Chris Co
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Chris Co @ 2018-07-19  4:11 UTC (permalink / raw)
  To: edk2-devel@lists.01.org; +Cc: Ard Biesheuvel, Leif Lindholm, Michael D Kinney

This adds support for interact with the UART controller on
NXP i.MX platforms.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Christopher Co <christopher.co@microsoft.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
---
 Silicon/NXP/iMXPlatformPkg/Include/iMXUart.h                               | 225 ++++++++++++++++++
 Silicon/NXP/iMXPlatformPkg/Library/UartSerialPortLib/UartSerialPortLib.c   | 242 ++++++++++++++++++++
 Silicon/NXP/iMXPlatformPkg/Library/UartSerialPortLib/UartSerialPortLib.inf |  41 ++++
 3 files changed, 508 insertions(+)

diff --git a/Silicon/NXP/iMXPlatformPkg/Include/iMXUart.h b/Silicon/NXP/iMXPlatformPkg/Include/iMXUart.h
new file mode 100644
index 000000000000..56b286e6250f
--- /dev/null
+++ b/Silicon/NXP/iMXPlatformPkg/Include/iMXUart.h
@@ -0,0 +1,225 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef _IMXUART_H_
+#define _IMXUART_H_
+
+//
+// UART Receiver Register bit definitions
+//
+enum MX6UART_RXD {
+    MX6UART_RXD_RX_DATA_MASK =      (0xff << 0),
+    MX6UART_RXD_PRERR =             (1 << 10),
+    MX6UART_RXD_BRK =               (1 << 11),
+    MX6UART_RXD_FRMERR =            (1 << 12),
+    MX6UART_RXD_OVRRUN =            (1 << 13),
+    MX6UART_RXD_ERR =               (1 << 14),
+    MX6UART_RXD_CHARRDY =           (1 << 15),
+};
+
+//
+// UART Control Register 1 bit definitions
+//
+enum MX6UART_UCR1 {
+    MX6UART_UCR1_UARTEN =           (1 << 0),
+    MX6UART_UCR1_DOZE =             (1 << 1),
+    MX6UART_UCR1_ATDMAEN =          (1 << 2),
+    MX6UART_UCR1_TXDMAEN =          (1 << 3),
+    MX6UART_UCR1_SNDBRK =           (1 << 4),
+    MX6UART_UCR1_RTSDEN =           (1 << 5),
+    MX6UART_UCR1_TXMPTYEN =         (1 << 6),
+    MX6UART_UCR1_IREN =             (1 << 7),
+    MX6UART_UCR1_RXDMAEN =          (1 << 8),
+    MX6UART_UCR1_RRDYEN =           (1 << 9),
+    MX6UART_UCR1_ICD_MASK =         (3 << 10),
+    MX6UART_UCR1_ICD_4 =            (0 << 10),
+    MX6UART_UCR1_ICD_8 =            (1 << 10),
+    MX6UART_UCR1_ICD_16 =           (2 << 10),
+    MX6UART_UCR1_ICD_32 =           (3 << 10),
+    MX6UART_UCR1_IDEN =             (1 << 12),
+    MX6UART_UCR1_TRDYEN =           (1 << 13),
+    MX6UART_UCR1_ADBR =             (1 << 14),
+    MX6UART_UCR1_ADEN =             (1 << 15),
+};
+
+//
+// UART Control Register 2 bit definitions
+//
+enum MX6UART_UCR2 {
+    MX6UART_UCR2_SRST =             (1 << 0),
+    MX6UART_UCR2_RXEN =             (1 << 1),
+    MX6UART_UCR2_TXEN =             (1 << 2),
+    MX6UART_UCR2_ATEN =             (1 << 3),
+    MX6UART_UCR2_RTSEN =            (1 << 4),
+    MX6UART_UCR2_WS =               (1 << 5),
+    MX6UART_UCR2_STPB =             (1 << 6),
+    MX6UART_UCR2_PROE =             (1 << 7),
+    MX6UART_UCR2_PREN =             (1 << 8),
+    MX6UART_UCR2_RTEC_MASK =        (3 << 9),
+    MX6UART_UCR2_RTEC_RISING =      (0 << 9),
+    MX6UART_UCR2_RTEC_FALLING =     (1 << 9),
+    MX6UART_UCR2_RTEC_BOTH =        (2 << 9),
+    MX6UART_UCR2_ESCEN =            (1 << 11),
+    MX6UART_UCR2_CTS =              (1 << 12),
+    MX6UART_UCR2_CTSC =             (1 << 13),
+    MX6UART_UCR2_IRTS =             (1 << 14),
+    MX6UART_UCR2_ESCI =             (1 << 15),
+};
+
+//
+// UART Control Register 3 bit definitions
+//
+enum MX6UART_UCR3 {
+    MX6UART_UCR3_ACIEN =            (1 << 0),
+    MX6UART_UCR3_INVT =             (1 << 1),
+    MX6UART_UCR3_RXDMUXSEL =        (1 << 2),
+    MX6UART_UCR3_DTRDEN =           (1 << 3),
+    MX6UART_UCR3_AWAKEN =           (1 << 4),
+    MX6UART_UCR3_AIRINTEN =         (1 << 5),
+    MX6UART_UCR3_RXDSEN =           (1 << 6),
+    MX6UART_UCR3_ADNIMP =           (1 << 7),
+    MX6UART_UCR3_RI =               (1 << 8),
+    MX6UART_UCR3_DCD =              (1 << 9),
+    MX6UART_UCR3_DSR =              (1 << 10),
+    MX6UART_UCR3_FRAERREN =         (1 << 11),
+    MX6UART_UCR3_PARERREN =         (1 << 12),
+    MX6UART_UCR3_DTREN =            (1 << 13),
+    MX6UART_UCR3_DPEC_MASK =        (3 << 14),
+    MX6UART_UCR3_DPEC_RISING =      (0 << 14),
+    MX6UART_UCR3_DPEC_FALLING =     (1 << 14),
+    MX6UART_UCR3_DPEC_BOTH =        (2 << 14),
+};
+
+//
+// UART Control Register 4 bit definitions
+//
+enum MX6UART_UCR4 {
+    MX6UART_UCR4_DREN =             (1 << 0),
+    MX6UART_UCR4_OREN =             (1 << 1),
+    MX6UART_UCR4_BKEN =             (1 << 2),
+    MX6UART_UCR4_TCEN =             (1 << 3),
+    MX6UART_UCR4_LPBYP =            (1 << 4),
+    MX6UART_UCR4_IRSC =             (1 << 5),
+    MX6UART_UCR4_IDDMAEN =          (1 << 6),
+    MX6UART_UCR4_WKEN =             (1 << 7),
+    MX6UART_UCR4_ENIRI =            (1 << 8),
+    MX6UART_UCR4_INVR =             (1 << 9),
+    MX6UART_UCR4_CTSTL_MASK =       (0x3f << 10),
+    MX6UART_UCR4_CTSTL_SHIFT =      10,
+};
+
+//
+// UART FIFO Control Register bit definitions
+//
+enum MX6UART_UFCR {
+    MX6UART_UFCR_RXTL_MASK =        (0x3f << 0),
+    MX6UART_UFCR_RXTL_SHIFT =       0,
+    MX6UART_UFCR_DCEDTE =           (1 << 6),
+    MX6UART_UFCR_RFDIV_MASK =       (7 << 7),
+    MX6UART_UFCR_RFDIV_6 =          (0 << 7),
+    MX6UART_UFCR_RFDIV_5 =          (1 << 7),
+    MX6UART_UFCR_RFDIV_4 =          (2 << 7),
+    MX6UART_UFCR_RFDIV_3 =          (3 << 7),
+    MX6UART_UFCR_RFDIV_2 =          (4 << 7),
+    MX6UART_UFCR_RFDIV_1 =          (5 << 7),
+    MX6UART_UFCR_RFDIV_7 =          (6 << 7),
+    MX6UART_UFCR_TXTL_MASK =        (0x3f << 10),
+    MX6UART_UFCR_TXTL_SHIFT =       10,
+};
+
+//
+// UART Status Register 1 bit definitions
+//
+enum MX6UART_USR1 {
+    MX6UART_USR1_SAD =              (1 << 3),
+    MX6UART_USR1_AWAKE =            (1 << 4),
+    MX6UART_USR1_AIRINT =           (1 << 5),
+    MX6UART_USR1_RXDS =             (1 << 6),
+    MX6UART_USR1_DTRD =             (1 << 7),
+    MX6UART_USR1_AGTIM =            (1 << 8),
+    MX6UART_USR1_RRDY =             (1 << 9),
+    MX6UART_USR1_FRAMERR =          (1 << 10),
+    MX6UART_USR1_ESCF =             (1 << 11),
+    MX6UART_USR1_RTSD =             (1 << 12),
+    MX6UART_USR1_TRDY =             (1 << 13),
+    MX6UART_USR1_RTSS =             (1 << 14),
+    MX6UART_USR1_PARITYERR =        (1 << 15),
+};
+
+//
+// UART Status Register 2 bit definitions
+//
+enum MX6UART_USR2 {
+    MX6UART_USR2_RDR =              (1 << 0),
+    MX6UART_USR2_ORE =              (1 << 1),
+    MX6UART_USR2_BRCD =             (1 << 2),
+    MX6UART_USR2_TXDC =             (1 << 3),
+    MX6UART_USR2_RTSF =             (1 << 4),
+    MX6UART_USR2_DCDIN =            (1 << 5),
+    MX6UART_USR2_DCDDELT =          (1 << 6),
+    MX6UART_USR2_WAKE =             (1 << 7),
+    MX6UART_USR2_IRINT =            (1 << 8),
+    MX6UART_USR2_RIIN =             (1 << 9),
+    MX6UART_USR2_RIDLET =           (1 << 10),
+    MX6UART_USR2_ACST =             (1 << 11),
+    MX6UART_USR2_IDLE =             (1 << 12),
+    MX6UART_USR2_DTRF =             (1 << 13),
+    MX6UART_USR2_TXFE =             (1 << 14),
+    MX6UART_USR2_ADET =             (1 << 15),
+};
+
+//
+// UART Test Register bit definitions
+//
+enum MX6UART_UTS {
+    MX6UART_UTS_SOFTRST =           (1 << 0),
+    MX6UART_UTS_RXFULL =            (1 << 3),
+    MX6UART_UTS_TXFULL =            (1 << 4),
+    MX6UART_UTS_RXEMPTY =           (1 << 5),
+    MX6UART_UTS_TXEMPTY =           (1 << 6),
+    MX6UART_UTS_RXDBG =             (1 << 9),
+    MX6UART_UTS_LOOPIR =            (1 << 10),
+    MX6UART_UTS_DBGEN =             (1 << 11),
+    MX6UART_UTS_LOOP =              (1 << 12),
+    MX6UART_UTS_FRCPERR =           (1 << 13),
+};
+
+//
+// Size of RX and TX FIFOs
+//
+enum { MX6UART_FIFO_COUNT = 32 };
+
+typedef struct _MX6UART_REGISTERS {
+    UINT32 Rxd;                  // 0x00: UART Receiver Register
+    UINT32 reserved1[15];
+    UINT32 Txd;                  // 0x40: UART Transmitter Register
+    UINT32 reserved2[15];
+    UINT32 Ucr1;                 // 0x80: UART Control Register 1
+    UINT32 Ucr2;                 // 0x84: UART Control Register 2
+    UINT32 Ucr3;                 // 0x88: UART Control Register 3
+    UINT32 Ucr4;                 // 0x8C: UART Control Register 4
+    UINT32 Ufcr;                 // 0x90: UART FIFO Control Register
+    UINT32 Usr1;                 // 0x94: UART Status Register 1
+    UINT32 Usr2;                 // 0x98: UART Status Register 2
+    UINT32 Uesc;                 // 0x9C: UART Escape Character Register
+    UINT32 Utim;                 // 0xA0: UART Escape Timer Register
+    UINT32 Ubir;                 // 0xA4: UART BRM Incremental Register
+    UINT32 Ubmr;                 // 0xA8: UART BRM Modulator Register (UART1_UBMR)
+    UINT32 Ubrc;                 // 0xAC: UART Baud Rate Count Register
+    UINT32 Onems;                // 0xB0: UART One Millisecond Register
+    UINT32 Uts;                  // 0xB4: UART Test Register
+    UINT32 Umcr;                 // 0xB8: UART RS-485 Mode Control Register
+} MX6UART_REGISTERS;
+
+#endif // _IMXUART_H_
diff --git a/Silicon/NXP/iMXPlatformPkg/Library/UartSerialPortLib/UartSerialPortLib.c b/Silicon/NXP/iMXPlatformPkg/Library/UartSerialPortLib/UartSerialPortLib.c
new file mode 100644
index 000000000000..f591fe7967b9
--- /dev/null
+++ b/Silicon/NXP/iMXPlatformPkg/Library/UartSerialPortLib/UartSerialPortLib.c
@@ -0,0 +1,242 @@
+/** @file
+
+  Copyright (c) 2006 - 2008, Intel Corporation
+  Copyright (c) Microsoft Corporation. All rights reserved.
+
+  All rights reserved. This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/IoLib.h>
+#include <Library/SerialPortLib.h>
+#include <iMXUart.h>
+
+
+/**
+  Initialize the serial device hardware.
+
+  If no initialization is required, then return RETURN_SUCCESS.
+  If the serial device was successfully initialized, then return RETURN_SUCCESS.
+  If the serial device could not be initialized, then return RETURN_DEVICE_ERROR.
+
+  @retval RETURN_SUCCESS        The serial device was initialized.
+  @retval RETURN_DEVICE_ERROR   The serial device could not be initialized.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerialPortInitialize (
+  VOID
+  )
+{
+    MX6UART_REGISTERS *UartBase =
+        (MX6UART_REGISTERS *)FixedPcdGet32(PcdSerialRegisterBase);
+
+    UINT32 Ucr1 = MmioRead32 ((UINTN)&UartBase->Ucr1);
+    if ((Ucr1 & MX6UART_UCR1_UARTEN) == 0) {
+        // UART should have been initialized by previous boot stage
+        return RETURN_DEVICE_ERROR;
+    }
+
+    return RETURN_SUCCESS;
+}
+
+/**
+  Write data from buffer to serial device.
+
+  Writes NumberOfBytes data bytes from Buffer to the serial device.
+  The number of bytes actually written to the serial device is returned.
+  If the return value is less than NumberOfBytes, then the write operation failed.
+  If Buffer is NULL, then ASSERT().
+  If NumberOfBytes is zero, then return 0.
+
+  @param  Buffer           Pointer to the data buffer to be written.
+  @param  NumberOfBytes    Number of bytes to written to the serial device.
+
+  @retval 0                NumberOfBytes is 0.
+  @retval >0               The number of bytes written to the serial device.
+                           If this value is less than NumberOfBytes, then the read operation failed.
+
+**/
+UINTN
+EFIAPI
+SerialPortWrite (
+  IN  UINT8 *Buffer,
+  IN  UINTN NumberOfBytes
+  )
+{
+    MX6UART_REGISTERS *UartBase =
+        (MX6UART_REGISTERS *)FixedPcdGet32(PcdSerialRegisterBase);
+
+    UINTN BytesSent = 0;
+
+    while (BytesSent < NumberOfBytes) {
+
+        // Check if FIFO is full and wait if it is.
+        while ((MmioRead32 ((UINTN)&UartBase->Uts) & MX6UART_UTS_TXFULL) != 0);
+
+        MmioWrite32 ((UINTN)&UartBase->Txd, Buffer[BytesSent]);
+        BytesSent++;
+    }
+
+    return BytesSent;
+}
+
+
+/**
+  Read data from serial device and save the datas in buffer.
+
+  Reads NumberOfBytes data bytes from a serial device into the buffer
+  specified by Buffer. The number of bytes actually read is returned.
+  If the return value is less than NumberOfBytes, then the rest operation failed.
+  If Buffer is NULL, then ASSERT().
+  If NumberOfBytes is zero, then return 0.
+
+  @param  Buffer           Pointer to the data buffer to store the data read from the serial device.
+  @param  NumberOfBytes    Number of bytes which will be read.
+
+  @retval 0                Read data failed, No data is to be read.
+  @retval >0               Aactual number of bytes read from serial device.
+
+**/
+UINTN
+EFIAPI
+SerialPortRead (
+  OUT UINT8 *Buffer,
+  IN  UINTN NumberOfBytes
+  )
+{
+    MX6UART_REGISTERS *UartBase =
+        (MX6UART_REGISTERS *)FixedPcdGet32(PcdSerialRegisterBase);
+
+    UINTN BytesRead = 0;
+    UINT32 Rxd;
+
+    while (BytesRead < NumberOfBytes) {
+        Rxd = MmioRead32 ((UINTN)&UartBase->Rxd);
+        if ((Rxd & MX6UART_RXD_CHARRDY) == 0) {
+            break;
+        }
+
+        Buffer[BytesRead] = (UINT8)(Rxd & MX6UART_RXD_RX_DATA_MASK);
+        BytesRead++;
+    }
+
+    return BytesRead;
+}
+
+/**
+  Polls a serial device to see if there is any data waiting to be read.
+
+  Polls a serial device to see if there is any data waiting to be read.
+  If there is data waiting to be read from the serial device, then TRUE is returned.
+  If there is no data waiting to be read from the serial device, then FALSE is returned.
+
+  @retval TRUE             Data is waiting to be read from the serial device.
+  @retval FALSE            There is no data waiting to be read from the serial device.
+
+**/
+BOOLEAN
+EFIAPI
+SerialPortPoll (
+  VOID
+  )
+{
+    MX6UART_REGISTERS *UartBase =
+        (MX6UART_REGISTERS *)FixedPcdGet32(PcdSerialRegisterBase);
+
+    UINT32 Usr2 = MmioRead32 ((UINTN)&UartBase->Usr2);
+
+    return (Usr2 & MX6UART_USR2_RDR) != 0;
+}
+/**
+  Sets the control bits on a serial device.
+
+  @param Control                Sets the bits of Control that are settable.
+
+  @retval RETURN_SUCCESS        The new control bits were set on the serial device.
+  @retval RETURN_UNSUPPORTED    The serial device does not support this operation.
+  @retval RETURN_DEVICE_ERROR   The serial device is not functioning correctly.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerialPortSetControl (
+  IN UINT32 Control
+  )
+{
+  return RETURN_UNSUPPORTED;
+}
+
+/**
+  Retrieve the status of the control bits on a serial device.
+
+  @param Control                A pointer to return the current control signals from the serial device.
+
+  @retval RETURN_SUCCESS        The control bits were read from the serial device.
+  @retval RETURN_UNSUPPORTED    The serial device does not support this operation.
+  @retval RETURN_DEVICE_ERROR   The serial device is not functioning correctly.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerialPortGetControl (
+  OUT UINT32 *Control
+  )
+{
+  return RETURN_UNSUPPORTED;
+}
+
+/**
+  Sets the baud rate, receive FIFO depth, transmit/receice time out, parity,
+  data bits, and stop bits on a serial device.
+
+  @param BaudRate           The requested baud rate. A BaudRate value of 0 will use the
+                            device's default interface speed.
+                            On output, the value actually set.
+  @param ReveiveFifoDepth   The requested depth of the FIFO on the receive side of the
+                            serial interface. A ReceiveFifoDepth value of 0 will use
+                            the device's default FIFO depth.
+                            On output, the value actually set.
+  @param Timeout            The requested time out for a single character in microseconds.
+                            This timeout applies to both the transmit and receive side of the
+                            interface. A Timeout value of 0 will use the device's default time
+                            out value.
+                            On output, the value actually set.
+  @param Parity             The type of parity to use on this serial device. A Parity value of
+                            DefaultParity will use the device's default parity value.
+                            On output, the value actually set.
+  @param DataBits           The number of data bits to use on the serial device. A DataBits
+                            vaule of 0 will use the device's default data bit setting.
+                            On output, the value actually set.
+  @param StopBits           The number of stop bits to use on this serial device. A StopBits
+                            value of DefaultStopBits will use the device's default number of
+                            stop bits.
+                            On output, the value actually set.
+
+  @retval RETURN_SUCCESS            The new attributes were set on the serial device.
+  @retval RETURN_UNSUPPORTED        The serial device does not support this operation.
+  @retval RETURN_INVALID_PARAMETER  One or more of the attributes has an unsupported value.
+  @retval RETURN_DEVICE_ERROR       The serial device is not functioning correctly.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerialPortSetAttributes (
+  IN OUT UINT64             *BaudRate,
+  IN OUT UINT32             *ReceiveFifoDepth,
+  IN OUT UINT32             *Timeout,
+  IN OUT EFI_PARITY_TYPE    *Parity,
+  IN OUT UINT8              *DataBits,
+  IN OUT EFI_STOP_BITS_TYPE *StopBits
+  )
+{
+  return RETURN_UNSUPPORTED;
+}
diff --git a/Silicon/NXP/iMXPlatformPkg/Library/UartSerialPortLib/UartSerialPortLib.inf b/Silicon/NXP/iMXPlatformPkg/Library/UartSerialPortLib/UartSerialPortLib.inf
new file mode 100644
index 000000000000..3fc4f587e65c
--- /dev/null
+++ b/Silicon/NXP/iMXPlatformPkg/Library/UartSerialPortLib/UartSerialPortLib.inf
@@ -0,0 +1,41 @@
+## @file
+#
+#  Copyright (c) Microsoft Corporation. All rights reserved.
+#
+#  This program and the accompanying materials
+#  are licensed and made available under the terms and conditions of the BSD License
+#  which accompanies this distribution.  The full text of the license may be found at
+#  http://opensource.org/licenses/bsd-license.php
+#
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = SerialPortLib
+  FILE_GUID                      = C22D85E6-8B3E-4c05-AA5B-5732F3ACD055
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = SerialPortLib
+
+[Sources.common]
+  UartSerialPortLib.c
+
+[LibraryClasses]
+  PcdLib
+  BaseMemoryLib
+  CacheMaintenanceLib
+  IoLib
+  TimerLib
+  ArmLib
+
+[Packages]
+  ArmPkg/ArmPkg.dec
+  ArmPlatformPkg/ArmPlatformPkg.dec
+  MdePkg/MdePkg.dec
+  Silicon/NXP/iMXPlatformPkg/iMXPlatformPkg.dec
+
+[FixedPcd]
+  giMXPlatformTokenSpaceGuid.PcdSerialRegisterBase
-- 
2.16.2.gvfs.1.33.gf5370f1



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH edk2-platforms 5/7] Silicon/NXP: Add Virtual RTC support for IMX platform
  2018-07-19  4:11 [PATCH edk2-platforms 0/7] Silicon/NXP: Import NXP i.MX platform package Chris Co
                   ` (3 preceding siblings ...)
  2018-07-19  4:11 ` [PATCH edk2-platforms 4/7] Silicon/NXP: Add UART " Chris Co
@ 2018-07-19  4:11 ` Chris Co
  2018-07-19  4:11 ` [PATCH edk2-platforms 6/7] Silicon/NXP: Add iMXPlatformPkg dec Chris Co
  2018-07-19  4:11 ` [PATCH edk2-platforms 7/7] Silicon/NXP: Add headers for other iMX packages to use Chris Co
  6 siblings, 0 replies; 10+ messages in thread
From: Chris Co @ 2018-07-19  4:11 UTC (permalink / raw)
  To: edk2-devel@lists.01.org; +Cc: Ard Biesheuvel, Leif Lindholm, Michael D Kinney

This adds a virtual RTC library that implements EFI RTC runtime services
based on the ARM performance counter.  It should only be used for relative
time measurement, such as for Windows Boot Manager.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Christopher Co <christopher.co@microsoft.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
---
 Silicon/NXP/iMXPlatformPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c   | 251 ++++++++++++++++++++
 Silicon/NXP/iMXPlatformPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.inf |  37 +++
 2 files changed, 288 insertions(+)

diff --git a/Silicon/NXP/iMXPlatformPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c b/Silicon/NXP/iMXPlatformPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c
new file mode 100644
index 000000000000..c4c9efb48f61
--- /dev/null
+++ b/Silicon/NXP/iMXPlatformPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c
@@ -0,0 +1,251 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+/**
+*  Implement EFI RealTimeClock runtime services based on ARM Performance Counter.
+*
+*  Currently this driver does not support time setting, alarms, runtime virtual calling
+*
+*  IMPORTANT NOTES:
+*  - This special library is NOT meant to replace a HW RTC implementation to measure date/time.
+*  - Use this library ONLY to measure relative time between two EFI_GET_TIME readings.
+*  - The performance counter will wrap-around eventually after a long time, make sure to consider
+*    this limitation if you are depending on this library for relative
+*    time measurement. e.g.  For the ARM 64-bit counter with 19.2MHz frequency, the counter
+*    will wrap-around after approximately 30465 year.
+**/
+
+#include <PiDxe.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/RealTimeClockLib.h>
+#include <Library/TimerLib.h>
+
+#define LOG_FMT_HELPER(FMT, ...) \
+    "VirtualRealTimeClock:" FMT "%a\n", __VA_ARGS__
+
+#define LOG_TRACE(...) \
+    DEBUG((DEBUG_BLKIO, LOG_FMT_HELPER(__VA_ARGS__, "")))
+
+
+/**
+  Returns the current time and date information, and the time-keeping capabilities
+  of the virtual RTC.
+
+  For simplicity, this LibGetTime does not report Years/Months, instead it will only report current
+  Day, Hours, Minutes and Seconds starting from the begining of CPU up-time. Otherwise, a more
+  complex logic will be required to account for leap years and days/month differences.
+
+  @param  Time                  A pointer to storage to receive a snapshot of the current time.
+  @param  Capabilities          An optional pointer to a buffer to receive the real time clock
+                                device's capabilities.
+
+  @retval EFI_SUCCESS           The operation completed successfully.
+  @retval EFI_INVALID_PARAMETER Time is NULL.
+  @retval EFI_DEVICE_ERROR      The time could not be retrieved due to hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+LibGetTime (
+  OUT EFI_TIME *Time,
+  OUT EFI_TIME_CAPABILITIES *Capabilities
+  )
+{
+  UINT64 TimerFreq;
+
+  if (Time == NULL)
+   return EFI_INVALID_PARAMETER;
+
+  //
+  // Depend on ARM ARCH Timer (i.e. performance counter) to report date/time
+  // relative to the start of CPU timer counting where date and time will always
+  // be relative to the date/time 1/1/1900 00H:00M:00S
+  //
+
+  if (PcdGet32 (PcdArmArchTimerFreqInHz) > 0) {
+     TimerFreq = PcdGet32 (PcdArmArchTimerFreqInHz);
+  } else {
+     TimerFreq = GetPerformanceCounterProperties (NULL, NULL);
+  }
+
+  ASSERT(TimerFreq > 0);
+  if (TimerFreq == 0)
+   return EFI_DEVICE_ERROR;
+
+  if (Capabilities) {
+     Capabilities->Accuracy = 0;
+     Capabilities->Resolution = TimerFreq;
+     Capabilities->SetsToZero = FALSE;
+  }
+
+  UINT64 ElapsedSeconds = GetPerformanceCounter () / TimerFreq;
+
+  //
+  // Don't report Year/Month since Leap Year logic is not implemented. This should be
+  // fine since the sole purpose of this special implementation is to be used for relative time
+  // measurement. e.g. Windows Boot Manager.
+  //
+
+  Time->Year = 0;
+  Time->Month = 0;
+
+  const UINT64 SECONDS_PER_DAY = 24 * 60 * 60;
+  Time->Day = (ElapsedSeconds / SECONDS_PER_DAY);
+  ElapsedSeconds %= SECONDS_PER_DAY;
+
+  const UINT64 SECONDS_PER_HOUR = 60 * 60;
+  Time->Hour = (ElapsedSeconds / SECONDS_PER_HOUR);
+  ElapsedSeconds %= SECONDS_PER_HOUR;
+
+  const UINT64 SECONDS_PER_MINUTE = 60;
+  Time->Minute = (ElapsedSeconds / SECONDS_PER_MINUTE);
+  ElapsedSeconds %= SECONDS_PER_MINUTE;
+
+  Time->Second = ElapsedSeconds;
+
+  //
+  // Not required to report in our special case
+  //
+
+  Time->Nanosecond = 0;
+  Time->TimeZone = 0;
+  Time->Daylight = 0;
+
+  LOG_TRACE(
+    "Time Elapsed Since Power-On: Day%d %dh:%dm:%ds",
+    (UINT32)Time->Day,
+    (UINT32)Time->Hour,
+    (UINT32)Time->Minute,
+    (UINT32)Time->Second);
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Sets the current local time and date information.
+
+  @param  Time                  A pointer to the current time.
+
+  @retval EFI_SUCCESS           The operation completed successfully.
+  @retval EFI_INVALID_PARAMETER A time field is out of range.
+  @retval EFI_DEVICE_ERROR      The time could not be set due due to hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+LibSetTime (
+  IN EFI_TIME *Time
+  )
+{
+  //
+  // The virtual clock is read-only.
+  //
+  return EFI_UNSUPPORTED;
+}
+
+
+/**
+  Returns the current wakeup alarm clock setting.
+
+  @param  Enabled               Indicates if the alarm is currently enabled or disabled.
+  @param  Pending               Indicates if the alarm signal is pending and requires acknowledgement.
+  @param  Time                  The current alarm setting.
+
+  @retval EFI_SUCCESS           The alarm settings were returned.
+  @retval EFI_INVALID_PARAMETER Any parameter is NULL.
+  @retval EFI_DEVICE_ERROR      The wakeup time could not be retrieved due to a hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+LibGetWakeupTime (
+  OUT BOOLEAN *Enabled,
+  OUT BOOLEAN *Pending,
+  OUT EFI_TIME *Time
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+
+/**
+  Sets the system wakeup alarm clock time.
+
+  @param  Enabled               Enable or disable the wakeup alarm.
+  @param  Time                  If Enable is TRUE, the time to set the wakeup alarm for.
+
+  @retval EFI_SUCCESS           If Enable is TRUE, then the wakeup alarm was enabled. If
+                                Enable is FALSE, then the wakeup alarm was disabled.
+  @retval EFI_INVALID_PARAMETER A time field is out of range.
+  @retval EFI_DEVICE_ERROR      The wakeup time could not be set due to a hardware error.
+  @retval EFI_UNSUPPORTED       A wakeup timer is not supported on this platform.
+
+**/
+EFI_STATUS
+EFIAPI
+LibSetWakeupTime (
+  IN BOOLEAN Enabled,
+  OUT EFI_TIME *Time
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+
+/**
+  This is the declaration of an EFI image entry point. This can be the entry point to an application
+  written to this specification, an EFI boot service driver, or an EFI runtime driver.
+
+  @param  ImageHandle           Handle that identifies the loaded image.
+  @param  SystemTable           System Table for this image.
+
+  @retval EFI_SUCCESS           The operation completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+LibRtcInitialize (
+  IN EFI_HANDLE ImageHandle,
+  IN EFI_SYSTEM_TABLE *SystemTable
+  )
+{
+  //
+  // ARM ARCH Timer is already initialized in the SEC/PEI phase.
+  //
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Fixup internal data so that EFI can be call in virtual mode.
+  Call the passed in Child Notify event and convert any pointers in
+  lib to virtual mode.
+
+  @param[in]    Event   The Event that is being processed
+  @param[in]    Context Event Context
+**/
+VOID
+EFIAPI
+LibRtcVirtualNotifyEvent (
+  IN EFI_EVENT Event,
+  IN VOID *Context
+  )
+{
+  //
+  // Not supporting OS calling RTC functions in virtual mode.
+  //
+  return;
+}
diff --git a/Silicon/NXP/iMXPlatformPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.inf b/Silicon/NXP/iMXPlatformPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.inf
new file mode 100644
index 000000000000..e3eb9e2f3148
--- /dev/null
+++ b/Silicon/NXP/iMXPlatformPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.inf
@@ -0,0 +1,37 @@
+## @file
+#
+#  Copyright (c) Microsoft Corporation. All rights reserved.
+#
+#  This program and the accompanying materials
+#  are licensed and made available under the terms and conditions of the BSD License
+#  which accompanies this distribution.  The full text of the license may be found at
+#  http://opensource.org/licenses/bsd-license.php
+#
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = VirtualRealTimeClockLib
+  FILE_GUID                      = 1E27D461-78F3-4F7D-B1C2-F72384F13A6E
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = RealTimeClockLib
+
+[Sources.common]
+  VirtualRealTimeClockLib.c
+
+[Packages]
+  ArmPkg/ArmPkg.dec
+  MdePkg/MdePkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+
+[LibraryClasses]
+  IoLib
+  DebugLib
+  TimerLib
+
+[FixedPcd]
+  gArmTokenSpaceGuid.PcdArmArchTimerFreqInHz
-- 
2.16.2.gvfs.1.33.gf5370f1



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH edk2-platforms 6/7] Silicon/NXP: Add iMXPlatformPkg dec
  2018-07-19  4:11 [PATCH edk2-platforms 0/7] Silicon/NXP: Import NXP i.MX platform package Chris Co
                   ` (4 preceding siblings ...)
  2018-07-19  4:11 ` [PATCH edk2-platforms 5/7] Silicon/NXP: Add Virtual RTC support for IMX platform Chris Co
@ 2018-07-19  4:11 ` Chris Co
  2018-07-19  4:11 ` [PATCH edk2-platforms 7/7] Silicon/NXP: Add headers for other iMX packages to use Chris Co
  6 siblings, 0 replies; 10+ messages in thread
From: Chris Co @ 2018-07-19  4:11 UTC (permalink / raw)
  To: edk2-devel@lists.01.org; +Cc: Ard Biesheuvel, Leif Lindholm, Michael D Kinney

iMXPlatformPkg holds drivers, libraries, and include files that are common
across the NXP i.MX line of SoCs.  This commit defines iMXPlatform PCDs.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Christopher Co <christopher.co@microsoft.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
---
 Silicon/NXP/iMXPlatformPkg/iMXPlatformPkg.dec | 117 ++++++++++++++++++++
 1 file changed, 117 insertions(+)

diff --git a/Silicon/NXP/iMXPlatformPkg/iMXPlatformPkg.dec b/Silicon/NXP/iMXPlatformPkg/iMXPlatformPkg.dec
new file mode 100644
index 000000000000..fd71bcd82032
--- /dev/null
+++ b/Silicon/NXP/iMXPlatformPkg/iMXPlatformPkg.dec
@@ -0,0 +1,117 @@
+## @file
+#
+#  Copyright (c) Microsoft Corporation. All rights reserved.
+#
+#  This program and the accompanying materials
+#  are licensed and made available under the terms and conditions of the BSD License
+#  which accompanies this distribution.  The full text of the license may be found at
+#  http://opensource.org/licenses/bsd-license.php
+#
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+  DEC_SPECIFICATION              = 0x00010005
+  PACKAGE_NAME                   = iMXPlatformPkg
+  PACKAGE_GUID                   = 6eba6648-d853-4eb3-9761-528b82d5ab04
+  PACKAGE_VERSION                = 0.1
+
+################################################################################
+#
+# Include Section - list of Include Paths that are provided by this package.
+#                   Comments are used for Keywords and Module Types.
+#
+# Supported Module Types:
+#  BASE SEC PEI_CORE PEIM DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_SAL_DRIVER UEFI_DRIVER UEFI_APPLICATION
+#
+################################################################################
+[Includes.common]
+  Include                        # Root include for the package
+
+[LibraryClasses]
+
+[Guids.common]
+  giMXPlatformTokenSpaceGuid    =  { 0x24b09abe, 0x4e47, 0x481c, { 0xa9, 0xad, 0xce, 0xf1, 0x2c, 0x39, 0x23, 0x27} }
+
+[PcdsFixedAtBuild.common]
+  #
+  # Default base address based that needs to be defined per platform
+  #
+  giMXPlatformTokenSpaceGuid.PcdSdhc1Base|0x02190000|UINT32|0x00
+  giMXPlatformTokenSpaceGuid.PcdSdhc2Base|0x02194000|UINT32|0x01
+  giMXPlatformTokenSpaceGuid.PcdSdhc3Base|0x02198000|UINT32|0x02
+  giMXPlatformTokenSpaceGuid.PcdSdhc4Base|0x0219C000|UINT32|0x03
+
+  #
+  # Enabled uSDHCx will be registered as a BlockIo device
+  #
+  giMXPlatformTokenSpaceGuid.PcdSdhc1Enable|FALSE|BOOLEAN|0x04
+  giMXPlatformTokenSpaceGuid.PcdSdhc2Enable|FALSE|BOOLEAN|0x05
+  giMXPlatformTokenSpaceGuid.PcdSdhc3Enable|FALSE|BOOLEAN|0x06
+  giMXPlatformTokenSpaceGuid.PcdSdhc4Enable|FALSE|BOOLEAN|0x07
+
+  #
+  # Slot CardDetect and WriteProtect signals source
+  #
+  # Legal values are as follows:
+  #
+  # [0x0000, 0xFEFF]
+  # Use a value in the range from 0x0 to 0xFEFF exclusive to indicate
+  # GPIO as signal source, use MSB byte as GPIO bank number, and LSB byte
+  # as IO number both in 1-based numbering fashion. e.g. 0x0201 means GPIO2_IO1
+  #
+  # 0xFF00  -USDHC_SIGNAL_OVERRIDE_PIN_LOW
+  # Override signal source to always read LOW
+  # NOTE: CD_B=0 means card present, while WP=0 means write enabled
+  #
+  # 0xFF01 - USDHC_SIGNAL_OVERRIDE_PIN_HIGH
+  # Override signal source to always read HIGH
+  # NOTE: CD_B=1 means card not present, while WP=1 means write protected
+  #
+  # 0xFFFF - USDHC_SIGNAL_INTERNAL_PIN
+  # Signal is connected directly to the SDHC block. Which means use th SDHC
+  # internal FSM for interpreting card detect CD_B and write protect WP signals
+  # from the slot
+  #
+  # Default signals to LOW to force card present and write enabled
+  #
+  giMXPlatformTokenSpaceGuid.PcdSdhc1CardDetectSignal|0xFF00|UINT16|0x08
+  giMXPlatformTokenSpaceGuid.PcdSdhc1WriteProtectSignal|0xFF01|UINT16|0x09
+
+  giMXPlatformTokenSpaceGuid.PcdSdhc2CardDetectSignal|0xFF00|UINT16|0x0A
+  giMXPlatformTokenSpaceGuid.PcdSdhc2WriteProtectSignal|0xFF01|UINT16|0x0B
+
+  giMXPlatformTokenSpaceGuid.PcdSdhc3CardDetectSignal|0xFF00|UINT16|0x0C
+  giMXPlatformTokenSpaceGuid.PcdSdhc3WriteProtectSignal|0xFF01|UINT16|0x0D
+
+  giMXPlatformTokenSpaceGuid.PcdSdhc4CardDetectSignal|0xFF00|UINT16|0x0E
+  giMXPlatformTokenSpaceGuid.PcdSdhc4WriteProtectSignal|0xFF01|UINT16|0x0F
+
+  #
+  # iMX UART configuration
+  #
+  # PcdSerialRegisterBase   - Define a base address of UEFI console UART
+  # PcdKdUartInstance - UART instance that should be used for Windows
+  #                     Kernel debugger. 1, 2, 3, 4, or 5
+  #
+  giMXPlatformTokenSpaceGuid.PcdSerialRegisterBase|0x00000000|UINT32|0x11
+  giMXPlatformTokenSpaceGuid.PcdKdUartInstance|1|UINT32|0x12
+
+  #
+  # iMX GPIO configuration
+  #
+  # PcdGpioBankMemoryRange - The memory range for 1 GPIO bank register (default 16KB)
+  #
+  giMXPlatformTokenSpaceGuid.PcdGpioBankMemoryRange|16384|UINT32|0x15
+
+  #
+  # Global data area
+  # The PcdGlobalDataBaseAddress and PcdGlobalDataSize have to be set by each
+  # platform based on the memory layout.
+  #
+  giMXPlatformTokenSpaceGuid.PcdGlobalDataBaseAddress|0x00000000|UINT32|0x17
+  giMXPlatformTokenSpaceGuid.PcdGlobalDataSize|0x1000|UINT32|0x18
+
+[PcdsFeatureFlag.common]
-- 
2.16.2.gvfs.1.33.gf5370f1



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH edk2-platforms 7/7] Silicon/NXP: Add headers for other iMX packages to use
  2018-07-19  4:11 [PATCH edk2-platforms 0/7] Silicon/NXP: Import NXP i.MX platform package Chris Co
                   ` (5 preceding siblings ...)
  2018-07-19  4:11 ` [PATCH edk2-platforms 6/7] Silicon/NXP: Add iMXPlatformPkg dec Chris Co
@ 2018-07-19  4:11 ` Chris Co
  6 siblings, 0 replies; 10+ messages in thread
From: Chris Co @ 2018-07-19  4:11 UTC (permalink / raw)
  To: edk2-devel@lists.01.org; +Cc: Ard Biesheuvel, Leif Lindholm, Michael D Kinney

This adds common headers for NXP i.MX platforms. More specifically,
common i.MX platform definitions and macros.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Christopher Co <christopher.co@microsoft.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
---
 Silicon/NXP/iMXPlatformPkg/Include/Platform.h      |  86 +++
 Silicon/NXP/iMXPlatformPkg/Include/common_macros.h | 561 ++++++++++++++++++++
 Silicon/NXP/iMXPlatformPkg/Include/iMXIoMux.h      |  24 +
 3 files changed, 671 insertions(+)

diff --git a/Silicon/NXP/iMXPlatformPkg/Include/Platform.h b/Silicon/NXP/iMXPlatformPkg/Include/Platform.h
new file mode 100644
index 000000000000..7fb3bdfacf7c
--- /dev/null
+++ b/Silicon/NXP/iMXPlatformPkg/Include/Platform.h
@@ -0,0 +1,86 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+//
+//  Freescale i.MX Platform specific defines for constructing ACPI tables
+//
+
+#ifndef _PLATFORM_IMX_H_
+#define _PLATFORM_IMX_H_
+
+#include <IndustryStandard/Acpi50.h>
+
+#define EFI_ACPI_OEM_ID                         {'M','C','R','S','F','T'}   // OEMID 6 bytes long
+
+#define EFI_ACPI_VENDOR_ID                      SIGNATURE_32('M','S','F','T')
+#define EFI_ACPI_CSRT_REVISION                  0x00000005
+
+#define EFI_ACPI_5_0_CSRT_REVISION              0x00000000
+
+//
+// Resource Descriptor Types
+//
+
+#define EFI_ACPI_CSRT_RD_TYPE_INTERRUPT 1
+#define EFI_ACPI_CSRT_RD_TYPE_TIMER 2
+#define EFI_ACPI_CSRT_RD_TYPE_DMA 3
+#define EFI_ACPI_CSRT_RD_TYPE_CACHE 4
+
+//
+// Resource Descriptor Subtypes
+//
+
+#define EFI_ACPI_CSRT_RD_SUBTYPE_INTERRUPT_LINES 0
+#define EFI_ACPI_CSRT_RD_SUBTYPE_INTERRUPT_CONTROLLER 1
+#define EFI_ACPI_CSRT_RD_SUBTYPE_TIMER 0
+#define EFI_ACPI_CSRT_RD_SUBTYPE_DMA_CHANNEL 0
+#define EFI_ACPI_CSRT_RD_SUBTYPE_DMA_CONTROLLER 1
+#define EFI_ACPI_CSRT_RD_SUBTYPE_CACHE 0
+
+//
+// Fixed device IDs
+//
+
+#define EFI_ACPI_CSRT_DEVICE_ID_DMA 0x00000009
+
+#pragma pack(push, 1)
+
+//------------------------------------------------------------------------
+// CSRT Resource Group header 24 bytes long
+//------------------------------------------------------------------------
+typedef struct
+{
+   UINT32 Length;           // Length
+   UINT32 VendorID;         // 4 bytes
+   UINT32 SubVendorId;         // 4 bytes
+   UINT16 DeviceId;         // 2 bytes
+   UINT16 SubdeviceId;         // 2 bytes
+   UINT16 Revision;         // 2 bytes
+   UINT16 Reserved;         // 2 bytes
+   UINT32 SharedInfoLength;   // 4 bytes
+} EFI_ACPI_5_0_CSRT_RESOURCE_GROUP_HEADER;
+
+//------------------------------------------------------------------------
+// CSRT Resource Descriptor 12 bytes total
+//------------------------------------------------------------------------
+typedef struct
+{
+   UINT32 Length;       // 4 bytes
+   UINT16 ResourceType; // 2 bytes
+   UINT16 ResourceSubType; // 2 bytes
+   UINT32 UID;          // 4 bytes
+} EFI_ACPI_5_0_CSRT_RESOURCE_DESCRIPTOR_HEADER;
+
+#pragma pack (pop)
+
+#endif // !_PLATFORM_IMX_H_
diff --git a/Silicon/NXP/iMXPlatformPkg/Include/common_macros.h b/Silicon/NXP/iMXPlatformPkg/Include/common_macros.h
new file mode 100644
index 000000000000..5f28f31050c6
--- /dev/null
+++ b/Silicon/NXP/iMXPlatformPkg/Include/common_macros.h
@@ -0,0 +1,561 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+//-----------------------------------------------------------------------------
+//
+//  Header:  common_macros.h
+//
+//  Provides common macro definitions SOC/BSP code development.
+//
+//------------------------------------------------------------------------------
+//
+// Copyright (C) 2007-2010, Freescale Semiconductor, Inc. All Rights Reserved.
+// THIS SOURCE CODE, AND ITS USE AND DISTRIBUTION, IS SUBJECT TO THE TERMS
+// AND CONDITIONS OF THE APPLICABLE LICENSE AGREEMENT
+//
+//------------------------------------------------------------------------------
+
+#ifndef __SOCARM_MACROS_H__
+#define __SOCARM_MACROS_H__
+
+// Bitfield macros that use rely on bitfield width/shift information
+// defined in SOC header files
+#define CSP_BITFMASK(bit) (((1U << (bit ## _WID)) - 1) << (bit ## _LSH))
+#define CSP_BITFVAL(bit, val) ((val) << (bit ## _LSH))
+
+// Undefine previous implementations of peripheral access macros since
+// we want to "own" the definitions and avoid redefinition warnings
+// resulting from source code that includes oal_io.h
+#undef INREG8
+#undef OUTREG8
+#undef SETREG8
+#undef CLRREG8
+#undef INREG16
+#undef OUTREG16
+#undef SETREG16
+#undef CLRREG16
+#undef INREG32
+#undef OUTREG32
+#undef SETREG32
+#undef CLRREG32
+
+#define READ_REGISTER_ULONG(reg) \
+    (*(volatile unsigned long * const)(reg))
+
+#define WRITE_REGISTER_ULONG(reg, val) \
+    (*(volatile unsigned long * const)(reg)) = (val)
+
+#define READ_REGISTER_USHORT(reg) \
+    (*(volatile unsigned short * const)(reg))
+
+#define WRITE_REGISTER_USHORT(reg, val) \
+    (*(volatile unsigned short * const)(reg)) = (val)
+
+#define READ_REGISTER_UCHAR(reg) \
+    (*(volatile unsigned char * const)(reg))
+
+#define WRITE_REGISTER_UCHAR(reg, val) \
+    (*(volatile unsigned char * const)(reg)) = (val)
+
+
+// Macros for accessing peripheral registers using DDK macros/functions
+#define INREG8(x)           READ_REGISTER_UCHAR((UCHAR*)(x))
+#define OUTREG8(x, y)       WRITE_REGISTER_UCHAR((UCHAR*)(x), (UCHAR)(y))
+#define SETREG8(x, y)       OUTREG8(x, INREG8(x)|(y))
+#define CLRREG8(x, y)       OUTREG8(x, INREG8(x)&~(y))
+#define INSREG8(addr, mask, val) OUTREG8(addr, ((INREG8(addr)&(~(mask))) | val))
+#define EXTREG8(addr, mask, lsh) ((INREG8(addr) & mask) >> lsh)
+#define EXTREG8BF(addr, bit) (EXTREG8(addr, CSP_BITFMASK(bit), (bit ## _LSH)))
+#define INSREG8BF(addr, bit, val) (INSREG8(addr, CSP_BITFMASK(bit), CSP_BITFVAL(bit, val)))
+
+#define INREG16(x)          READ_REGISTER_USHORT((USHORT*)(x))
+#define OUTREG16(x, y)      WRITE_REGISTER_USHORT((USHORT*)(x),(USHORT)(y))
+#define SETREG16(x, y)      OUTREG16(x, INREG16(x)|(y))
+#define CLRREG16(x, y)      OUTREG16(x, INREG16(x)&~(y))
+#define INSREG16(addr, mask, val) OUTREG16(addr, ((INREG16(addr)&(~(mask))) | val))
+#define EXTREG16(addr, mask, lsh) ((INREG16(addr) & mask) >> lsh)
+#define EXTREG16BF(addr, bit) (EXTREG16(addr, CSP_BITFMASK(bit), (bit ## _LSH)))
+#define INSREG16BF(addr, bit, val) (INSREG16(addr, CSP_BITFMASK(bit), CSP_BITFVAL(bit, val)))
+
+#define INREG32(x)          READ_REGISTER_ULONG((long*)(x))
+#define OUTREG32(x, y)      WRITE_REGISTER_ULONG((long*)(x), (long)(y))
+#define SETREG32(x, y)      OUTREG32(x, INREG32(x)|(y))
+#define CLRREG32(x, y)      OUTREG32(x, INREG32(x)&~(y))
+#define INSREG32(addr, mask, val) OUTREG32(addr, ((INREG32(addr)&(~(mask))) | val))
+#define EXTREG32(addr, mask, lsh) ((INREG32(addr) & mask) >> lsh)
+#define EXTREG32BF(addr, bit) (EXTREG32(addr, CSP_BITFMASK(bit), (bit ## _LSH)))
+#define INSREG32BF(addr, bit, val) (INSREG32(addr, CSP_BITFMASK(bit), CSP_BITFVAL(bit, val)))
+
+// macros for pin mux
+#define OAL_IOMUX_SET_MUX(pIOMUX, pin, muxmode, sion) \
+    OUTREG32(&pIOMUX->SW_MUX_CTL[pin], (muxmode | sion))
+
+#define OAL_IOMUX_SET_PAD(pIOMUX, pad, slew, drive, openDrain, pull, hysteresis, inputMode, outputVolt) \
+    OUTREG32(&pIOMUX->SW_PAD_CTL[pad], (slew | drive | openDrain | pull | hysteresis | inputMode | outputVolt))
+
+
+// Macros for bitfield operations on data variables.  DO NOT use for peripheral
+// register accesses.  Use the INREG/OUTREG based macros above for peripheral
+// accesses.
+#define CSP_BITFEXT(var, bit) ((var & CSP_BITFMASK(bit)) >> (bit ## _LSH))
+
+#define CSP_BITFCLR(var, bit) (var &= (~CSP_BITFMASK(bit)))
+
+#define CSP_BITFINS(var, bit, val) \
+    (CSP_BITFCLR(var, bit)); (var |= CSP_BITFVAL(bit, val))
+
+// Macros for generating 64-bit IRQ masks
+#define CSP_IRQMASK(irq) (((ULONGLONG) 1)  << irq)
+
+// Macros to create Unicode function name
+#define WIDEN2(x) L ## x
+#define WIDEN(x) WIDEN2(x)
+#define __WFUNCTION__ WIDEN(__FUNCTION__)
+
+// Macros for function tracing (better to use debug zones as these
+// macros will be phases out)
+#define CSP_FUNC_TRACE_ENTRY() \
+    DEBUGMSG(1, (TEXT("+%s\r\n"), __WFUNCTION__))
+
+#define CSP_FUNC_TRACE_EXIT() \
+    DEBUGMSG(1, (TEXT("-%s\r\n"), __WFUNCTION__))
+
+// Macros for importing/exporting DLL interface
+#define DllExport __declspec( dllexport )
+
+
+//STMP macros for single instance registers
+#define BF_SET(reg, field)       HW_ ## reg ## _SET(BM_ ## reg ## _ ## field)
+#define BF_CLR(reg, field)       HW_ ## reg ## _CLR(BM_ ## reg ## _ ## field)
+#define BF_TOG(reg, field)       HW_ ## reg ## _TOG(BM_ ## reg ## _ ## field)
+
+#define BF_SETV(reg, field, v)   HW_ ## reg ## _SET(BF_ ## reg ## _ ## field(v))
+#define BF_CLRV(reg, field, v)   HW_ ## reg ## _CLR(BF_ ## reg ## _ ## field(v))
+#define BF_TOGV(reg, field, v)   HW_ ## reg ## _TOG(BF_ ## reg ## _ ## field(v))
+
+#define BV_FLD(reg, field, sym)  BF_ ## reg ## _ ## field(BV_ ## reg ## _ ## field ## __ ## sym)
+#define BV_VAL(reg, field, sym)  BV_ ## reg ## _ ## field ## __ ## sym
+
+#define BF_RD(reg, field)        HW_ ## reg.B.field
+#define BF_WR(reg, field, v)     BW_ ## reg ## _ ## field(v)
+
+#define BF_CS1(reg, f1, v1)  \
+    (HW_ ## reg ## _CLR(BM_ ## reg ## _ ## f1),      \
+     HW_ ## reg ## _SET(BF_ ## reg ## _ ## f1(v1)))
+
+#define BF_CS2(reg, f1, v1, f2, v2)  \
+    (HW_ ## reg ## _CLR(BM_ ## reg ## _ ## f1 |      \
+                        BM_ ## reg ## _ ## f2),      \
+     HW_ ## reg ## _SET(BF_ ## reg ## _ ## f1(v1) |  \
+                        BF_ ## reg ## _ ## f2(v2)))
+
+#define BF_CS3(reg, f1, v1, f2, v2, f3, v3)  \
+    (HW_ ## reg ## _CLR(BM_ ## reg ## _ ## f1 |      \
+                        BM_ ## reg ## _ ## f2 |      \
+                        BM_ ## reg ## _ ## f3),      \
+     HW_ ## reg ## _SET(BF_ ## reg ## _ ## f1(v1) |  \
+                        BF_ ## reg ## _ ## f2(v2) |  \
+                        BF_ ## reg ## _ ## f3(v3)))
+
+#define BF_CS4(reg, f1, v1, f2, v2, f3, v3, f4, v4)  \
+    (HW_ ## reg ## _CLR(BM_ ## reg ## _ ## f1 |      \
+                        BM_ ## reg ## _ ## f2 |      \
+                        BM_ ## reg ## _ ## f3 |      \
+                        BM_ ## reg ## _ ## f4),      \
+     HW_ ## reg ## _SET(BF_ ## reg ## _ ## f1(v1) |  \
+                        BF_ ## reg ## _ ## f2(v2) |  \
+                        BF_ ## reg ## _ ## f3(v3) |  \
+                        BF_ ## reg ## _ ## f4(v4)))
+
+#define BF_CS5(reg, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5)  \
+    (HW_ ## reg ## _CLR(BM_ ## reg ## _ ## f1 |      \
+                        BM_ ## reg ## _ ## f2 |      \
+                        BM_ ## reg ## _ ## f3 |      \
+                        BM_ ## reg ## _ ## f4 |      \
+                        BM_ ## reg ## _ ## f5),      \
+     HW_ ## reg ## _SET(BF_ ## reg ## _ ## f1(v1) |  \
+                        BF_ ## reg ## _ ## f2(v2) |  \
+                        BF_ ## reg ## _ ## f3(v3) |  \
+                        BF_ ## reg ## _ ## f4(v4) |  \
+                        BF_ ## reg ## _ ## f5(v5)))
+
+#define BF_CS6(reg, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6)  \
+    (HW_ ## reg ## _CLR(BM_ ## reg ## _ ## f1 |      \
+                        BM_ ## reg ## _ ## f2 |      \
+                        BM_ ## reg ## _ ## f3 |      \
+                        BM_ ## reg ## _ ## f4 |      \
+                        BM_ ## reg ## _ ## f5 |      \
+                        BM_ ## reg ## _ ## f6),      \
+     HW_ ## reg ## _SET(BF_ ## reg ## _ ## f1(v1) |  \
+                        BF_ ## reg ## _ ## f2(v2) |  \
+                        BF_ ## reg ## _ ## f3(v3) |  \
+                        BF_ ## reg ## _ ## f4(v4) |  \
+                        BF_ ## reg ## _ ## f5(v5) |  \
+                        BF_ ## reg ## _ ## f6(v6)))
+
+#define BF_CS7(reg, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7)  \
+    (HW_ ## reg ## _CLR(BM_ ## reg ## _ ## f1 |      \
+                        BM_ ## reg ## _ ## f2 |      \
+                        BM_ ## reg ## _ ## f3 |      \
+                        BM_ ## reg ## _ ## f4 |      \
+                        BM_ ## reg ## _ ## f5 |      \
+                        BM_ ## reg ## _ ## f6 |      \
+                        BM_ ## reg ## _ ## f7),      \
+     HW_ ## reg ## _SET(BF_ ## reg ## _ ## f1(v1) |  \
+                        BF_ ## reg ## _ ## f2(v2) |  \
+                        BF_ ## reg ## _ ## f3(v3) |  \
+                        BF_ ## reg ## _ ## f4(v4) |  \
+                        BF_ ## reg ## _ ## f5(v5) |  \
+                        BF_ ## reg ## _ ## f6(v6) |  \
+                        BF_ ## reg ## _ ## f7(v7)))
+
+#define BF_CS8(reg, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7, f8, v8)  \
+    (HW_ ## reg ## _CLR(BM_ ## reg ## _ ## f1 |      \
+                        BM_ ## reg ## _ ## f2 |      \
+                        BM_ ## reg ## _ ## f3 |      \
+                        BM_ ## reg ## _ ## f4 |      \
+                        BM_ ## reg ## _ ## f5 |      \
+                        BM_ ## reg ## _ ## f6 |      \
+                        BM_ ## reg ## _ ## f7 |      \
+                        BM_ ## reg ## _ ## f8),      \
+     HW_ ## reg ## _SET(BF_ ## reg ## _ ## f1(v1) |  \
+                        BF_ ## reg ## _ ## f2(v2) |  \
+                        BF_ ## reg ## _ ## f3(v3) |  \
+                        BF_ ## reg ## _ ## f4(v4) |  \
+                        BF_ ## reg ## _ ## f5(v5) |  \
+                        BF_ ## reg ## _ ## f6(v6) |  \
+                        BF_ ## reg ## _ ## f7(v7) |  \
+                        BF_ ## reg ## _ ## f8(v8)))
+
+
+//
+// macros for multiple instance registers
+//
+
+#define BF_SETn(reg, n, field)       HW_ ## reg ## _SET(n, BM_ ## reg ## _ ## field)
+#define BF_CLRn(reg, n, field)       HW_ ## reg ## _CLR(n, BM_ ## reg ## _ ## field)
+#define BF_TOGn(reg, n, field)       HW_ ## reg ## _TOG(n, BM_ ## reg ## _ ## field)
+
+#define BF_SETVn(reg, n, field, v)   HW_ ## reg ## _SET(n, BF_ ## reg ## _ ## field(v))
+#define BF_CLRVn(reg, n, field, v)   HW_ ## reg ## _CLR(n, BF_ ## reg ## _ ## field(v))
+#define BF_TOGVn(reg, n, field, v)   HW_ ## reg ## _TOG(n, BF_ ## reg ## _ ## field(v))
+
+#define BV_FLDn(reg, n, field, sym)  BF_ ## reg ## _ ## field(BV_ ## reg ## _ ## field ## __ ## sym)
+#define BV_VALn(reg, n, field, sym)  BV_ ## reg ## _ ## field ## __ ## sym
+
+#define BF_RDn(reg, n, field)        HW_ ## reg(n).B.field
+#define BF_WRn(reg, n, field, v)     BW_ ## reg ## _ ## field(n, v)
+
+#define BF_CS1n(reg, n, f1, v1)  \
+    (HW_ ## reg ## _CLR(n, (BM_ ## reg ## _ ## f1)),      \
+     HW_ ## reg ## _SET(n, (BF_ ## reg ## _ ## f1(v1))))
+
+#define BF_CS2n(reg, n, f1, v1, f2, v2)  \
+    (HW_ ## reg ## _CLR(n, (BM_ ## reg ## _ ## f1 |       \
+                            BM_ ## reg ## _ ## f2)),      \
+     HW_ ## reg ## _SET(n, (BF_ ## reg ## _ ## f1(v1) |   \
+                            BF_ ## reg ## _ ## f2(v2))))
+
+#define BF_CS3n(reg, n, f1, v1, f2, v2, f3, v3)  \
+    (HW_ ## reg ## _CLR(n, (BM_ ## reg ## _ ## f1 |       \
+                            BM_ ## reg ## _ ## f2 |       \
+                            BM_ ## reg ## _ ## f3)),      \
+     HW_ ## reg ## _SET(n, (BF_ ## reg ## _ ## f1(v1) |   \
+                            BF_ ## reg ## _ ## f2(v2) |   \
+                            BF_ ## reg ## _ ## f3(v3))))
+
+#define BF_CS4n(reg, n, f1, v1, f2, v2, f3, v3, f4, v4)  \
+    (HW_ ## reg ## _CLR(n, (BM_ ## reg ## _ ## f1 |       \
+                            BM_ ## reg ## _ ## f2 |       \
+                            BM_ ## reg ## _ ## f3 |       \
+                            BM_ ## reg ## _ ## f4)),      \
+     HW_ ## reg ## _SET(n, (BF_ ## reg ## _ ## f1(v1) |   \
+                            BF_ ## reg ## _ ## f2(v2) |   \
+                            BF_ ## reg ## _ ## f3(v3) |   \
+                            BF_ ## reg ## _ ## f4(v4))))
+
+#define BF_CS5n(reg, n, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5)  \
+    (HW_ ## reg ## _CLR(n, (BM_ ## reg ## _ ## f1 |       \
+                            BM_ ## reg ## _ ## f2 |       \
+                            BM_ ## reg ## _ ## f3 |       \
+                            BM_ ## reg ## _ ## f4 |       \
+                            BM_ ## reg ## _ ## f5)),      \
+     HW_ ## reg ## _SET(n, (BF_ ## reg ## _ ## f1(v1) |   \
+                            BF_ ## reg ## _ ## f2(v2) |   \
+                            BF_ ## reg ## _ ## f3(v3) |   \
+                            BF_ ## reg ## _ ## f4(v4) |   \
+                            BF_ ## reg ## _ ## f5(v5))))
+
+#define BF_CS6n(reg, n, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6)  \
+    (HW_ ## reg ## _CLR(n, (BM_ ## reg ## _ ## f1 |       \
+                            BM_ ## reg ## _ ## f2 |       \
+                            BM_ ## reg ## _ ## f3 |       \
+                            BM_ ## reg ## _ ## f4 |       \
+                            BM_ ## reg ## _ ## f5 |       \
+                            BM_ ## reg ## _ ## f6)),      \
+     HW_ ## reg ## _SET(n, (BF_ ## reg ## _ ## f1(v1) |   \
+                            BF_ ## reg ## _ ## f2(v2) |   \
+                            BF_ ## reg ## _ ## f3(v3) |   \
+                            BF_ ## reg ## _ ## f4(v4) |   \
+                            BF_ ## reg ## _ ## f5(v5) |   \
+                            BF_ ## reg ## _ ## f6(v6))))
+
+#define BF_CS7n(reg, n, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7)  \
+    (HW_ ## reg ## _CLR(n, (BM_ ## reg ## _ ## f1 |       \
+                            BM_ ## reg ## _ ## f2 |       \
+                            BM_ ## reg ## _ ## f3 |       \
+                            BM_ ## reg ## _ ## f4 |       \
+                            BM_ ## reg ## _ ## f5 |       \
+                            BM_ ## reg ## _ ## f6 |       \
+                            BM_ ## reg ## _ ## f7)),      \
+     HW_ ## reg ## _SET(n, (BF_ ## reg ## _ ## f1(v1) |   \
+                            BF_ ## reg ## _ ## f2(v2) |   \
+                            BF_ ## reg ## _ ## f3(v3) |   \
+                            BF_ ## reg ## _ ## f4(v4) |   \
+                            BF_ ## reg ## _ ## f5(v5) |   \
+                            BF_ ## reg ## _ ## f6(v6) |   \
+                            BF_ ## reg ## _ ## f7(v7))))
+
+#define BF_CS8n(reg, n, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7, f8, v8)  \
+    (HW_ ## reg ## _CLR(n, (BM_ ## reg ## _ ## f1 |       \
+                            BM_ ## reg ## _ ## f2 |       \
+                            BM_ ## reg ## _ ## f3 |       \
+                            BM_ ## reg ## _ ## f4 |       \
+                            BM_ ## reg ## _ ## f5 |       \
+                            BM_ ## reg ## _ ## f6 |       \
+                            BM_ ## reg ## _ ## f7 |       \
+                            BM_ ## reg ## _ ## f8)),      \
+     HW_ ## reg ## _SET(n, (BF_ ## reg ## _ ## f1(v1) |   \
+                            BF_ ## reg ## _ ## f2(v2) |   \
+                            BF_ ## reg ## _ ## f3(v3) |   \
+                            BF_ ## reg ## _ ## f4(v4) |   \
+                            BF_ ## reg ## _ ## f5(v5) |   \
+                            BF_ ## reg ## _ ## f6(v6) |   \
+                            BF_ ## reg ## _ ## f7(v7) |   \
+                            BF_ ## reg ## _ ## f8(v8))))
+
+///////
+
+//
+// macros for single instance registers
+//
+
+#define BFi_SET(i, reg, field)       HWi_ ## reg ## _SET(i, BM_ ## reg ## _ ## field)
+#define BFi_CLR(i, reg, field)       HWi_ ## reg ## _CLR(i, BM_ ## reg ## _ ## field)
+#define BFi_TOG(i, reg, field)       HWi_ ## reg ## _TOG(i, BM_ ## reg ## _ ## field)
+
+#define BFi_SETV(i, reg, field, v)   HWi_ ## reg ## _SET(i, BF_ ## reg ## _ ## field(v))
+#define BFi_CLRV(i, reg, field, v)   HWi_ ## reg ## _CLR(i, BF_ ## reg ## _ ## field(v))
+#define BFi_TOGV(i, reg, field, v)   HWi_ ## reg ## _TOG(i, BF_ ## reg ## _ ## field(v))
+
+#define BFi_RD(i, reg, field)        HWi_ ## reg(i).B.field
+#define BFi_WR(i, reg, field, v)     BWi_ ## reg ## _ ## field(i, v)
+
+#define BFi_CS1(i, reg, f1, v1)  \
+    (HWi_ ## reg ## _CLR(i, BM_ ## reg ## _ ## f1),      \
+     HWi_ ## reg ## _SET(i, BF_ ## reg ## _ ## f1(v1)))
+
+#define BFi_CS2(i, reg, f1, v1, f2, v2)  \
+    (HWi_ ## reg ## _CLR(i, BM_ ## reg ## _ ## f1 |      \
+                         BM_ ## reg ## _ ## f2),      \
+     HWi_ ## reg ## _SET(i, BF_ ## reg ## _ ## f1(v1) |  \
+                         BF_ ## reg ## _ ## f2(v2)))
+
+#define BFi_CS3(i, reg, f1, v1, f2, v2, f3, v3)  \
+    (HWi_ ## reg ## _CLR(i, BM_ ## reg ## _ ## f1 |      \
+                         BM_ ## reg ## _ ## f2 |      \
+                         BM_ ## reg ## _ ## f3),      \
+     HWi_ ## reg ## _SET(i, BF_ ## reg ## _ ## f1(v1) |  \
+                         BF_ ## reg ## _ ## f2(v2) |  \
+                         BF_ ## reg ## _ ## f3(v3)))
+
+#define BFi_CS4(i, reg, f1, v1, f2, v2, f3, v3, f4, v4)  \
+    (HWi_ ## reg ## _CLR(i, BM_ ## reg ## _ ## f1 |      \
+                         BM_ ## reg ## _ ## f2 |      \
+                         BM_ ## reg ## _ ## f3 |      \
+                         BM_ ## reg ## _ ## f4),      \
+     HWi_ ## reg ## _SET(i, BF_ ## reg ## _ ## f1(v1) |  \
+                         BF_ ## reg ## _ ## f2(v2) |  \
+                         BF_ ## reg ## _ ## f3(v3) |  \
+                         BF_ ## reg ## _ ## f4(v4)))
+
+#define BFi_CS5(i, reg, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5)  \
+    (HWi_ ## reg ## _CLR(i, BM_ ## reg ## _ ## f1 |      \
+                         BM_ ## reg ## _ ## f2 |      \
+                         BM_ ## reg ## _ ## f3 |      \
+                         BM_ ## reg ## _ ## f4 |      \
+                         BM_ ## reg ## _ ## f5),      \
+     HWi_ ## reg ## _SET(i, BF_ ## reg ## _ ## f1(v1) |  \
+                         BF_ ## reg ## _ ## f2(v2) |  \
+                         BF_ ## reg ## _ ## f3(v3) |  \
+                         BF_ ## reg ## _ ## f4(v4) |  \
+                         BF_ ## reg ## _ ## f5(v5)))
+
+#define BFi_CS6(i, reg, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6)  \
+    (HWi_ ## reg ## _CLR(i, BM_ ## reg ## _ ## f1 |      \
+                         BM_ ## reg ## _ ## f2 |      \
+                         BM_ ## reg ## _ ## f3 |      \
+                         BM_ ## reg ## _ ## f4 |      \
+                         BM_ ## reg ## _ ## f5 |      \
+                         BM_ ## reg ## _ ## f6),      \
+     HWi_ ## reg ## _SET(i, BF_ ## reg ## _ ## f1(v1) |  \
+                         BF_ ## reg ## _ ## f2(v2) |  \
+                         BF_ ## reg ## _ ## f3(v3) |  \
+                         BF_ ## reg ## _ ## f4(v4) |  \
+                         BF_ ## reg ## _ ## f5(v5) |  \
+                         BF_ ## reg ## _ ## f6(v6)))
+
+#define BFi_CS7(i, reg, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7)  \
+    (HWi_ ## reg ## _CLR(i, BM_ ## reg ## _ ## f1 |      \
+                         BM_ ## reg ## _ ## f2 |      \
+                         BM_ ## reg ## _ ## f3 |      \
+                         BM_ ## reg ## _ ## f4 |      \
+                         BM_ ## reg ## _ ## f5 |      \
+                         BM_ ## reg ## _ ## f6 |      \
+                         BM_ ## reg ## _ ## f7),      \
+     HWi_ ## reg ## _SET(i, BF_ ## reg ## _ ## f1(v1) |  \
+                         BF_ ## reg ## _ ## f2(v2) |  \
+                         BF_ ## reg ## _ ## f3(v3) |  \
+                         BF_ ## reg ## _ ## f4(v4) |  \
+                         BF_ ## reg ## _ ## f5(v5) |  \
+                         BF_ ## reg ## _ ## f6(v6) |  \
+                         BF_ ## reg ## _ ## f7(v7)))
+
+#define BFi_CS8(i, reg, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7, f8, v8)  \
+    (HWi_ ## reg ## _CLR(i, BM_ ## reg ## _ ## f1 |      \
+                         BM_ ## reg ## _ ## f2 |      \
+                         BM_ ## reg ## _ ## f3 |      \
+                         BM_ ## reg ## _ ## f4 |      \
+                         BM_ ## reg ## _ ## f5 |      \
+                         BM_ ## reg ## _ ## f6 |      \
+                         BM_ ## reg ## _ ## f7 |      \
+                         BM_ ## reg ## _ ## f8),      \
+     HWi_ ## reg ## _SET(i, BF_ ## reg ## _ ## f1(v1) |  \
+                         BF_ ## reg ## _ ## f2(v2) |  \
+                         BF_ ## reg ## _ ## f3(v3) |  \
+                         BF_ ## reg ## _ ## f4(v4) |  \
+                         BF_ ## reg ## _ ## f5(v5) |  \
+                         BF_ ## reg ## _ ## f6(v6) |  \
+                         BF_ ## reg ## _ ## f7(v7) |  \
+                         BF_ ## reg ## _ ## f8(v8)))
+
+
+//
+// macros for multiple instance registers
+//
+
+#define BFi_SETn(i, reg, n, field)       HWi_ ## reg ## _SET(i, n, BM_ ## reg ## _ ## field)
+#define BFi_CLRn(i, reg, n, field)       HWi_ ## reg ## _CLR(i, n, BM_ ## reg ## _ ## field)
+#define BFi_TOGn(i, reg, n, field)       HWi_ ## reg ## _TOG(i, n, BM_ ## reg ## _ ## field)
+
+#define BFi_SETVn(i, reg, n, field, v)   HWi_ ## reg ## _SET(i, n, BF_ ## reg ## _ ## field(v))
+#define BFi_CLRVn(i, reg, n, field, v)   HWi_ ## reg ## _CLR(i, n, BF_ ## reg ## _ ## field(v))
+#define BFi_TOGVn(i, reg, n, field, v)   HWi_ ## reg ## _TOG(i, n, BF_ ## reg ## _ ## field(v))
+
+#define BFi_RDn(i, reg, n, field)        HWi_ ## reg(i, n).B.field
+#define BFi_WRn(i, reg, n, field, v)     BWi_ ## reg ## _ ## field(i, n, v)
+
+#define BFi_CS1n(i, reg, n, f1, v1)  \
+    (HWi_ ## reg ## _CLR(i, n, (BM_ ## reg ## _ ## f1)),      \
+     HWi_ ## reg ## _SET(i, n, (BF_ ## reg ## _ ## f1(v1))))
+
+#define BFi_CS2n(i, reg, n, f1, v1, f2, v2)  \
+    (HWi_ ## reg ## _CLR(i, n, (BM_ ## reg ## _ ## f1 |       \
+                                BM_ ## reg ## _ ## f2)),      \
+     HWi_ ## reg ## _SET(i, n, (BF_ ## reg ## _ ## f1(v1) |   \
+                                BF_ ## reg ## _ ## f2(v2))))
+
+#define BFi_CS3n(i, reg, n, f1, v1, f2, v2, f3, v3)  \
+    (HWi_ ## reg ## _CLR(i, n, (BM_ ## reg ## _ ## f1 |       \
+                                BM_ ## reg ## _ ## f2 |       \
+                                BM_ ## reg ## _ ## f3)),      \
+     HWi_ ## reg ## _SET(i, n, (BF_ ## reg ## _ ## f1(v1) |   \
+                                BF_ ## reg ## _ ## f2(v2) |   \
+                                BF_ ## reg ## _ ## f3(v3))))
+
+#define BFi_CS4n(i, reg, n, f1, v1, f2, v2, f3, v3, f4, v4)  \
+    (HWi_ ## reg ## _CLR(i, n, (BM_ ## reg ## _ ## f1 |       \
+                                BM_ ## reg ## _ ## f2 |       \
+                                BM_ ## reg ## _ ## f3 |       \
+                                BM_ ## reg ## _ ## f4)),      \
+     HWi_ ## reg ## _SET(i, n, (BF_ ## reg ## _ ## f1(v1) |   \
+                                BF_ ## reg ## _ ## f2(v2) |   \
+                                BF_ ## reg ## _ ## f3(v3) |   \
+                                BF_ ## reg ## _ ## f4(v4))))
+
+#define BFi_CS5n(i, reg, n, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5)  \
+    (HWi_ ## reg ## _CLR(i, n, (BM_ ## reg ## _ ## f1 |       \
+                                BM_ ## reg ## _ ## f2 |       \
+                                BM_ ## reg ## _ ## f3 |       \
+                                BM_ ## reg ## _ ## f4 |       \
+                                BM_ ## reg ## _ ## f5)),      \
+     HWi_ ## reg ## _SET(i, n, (BF_ ## reg ## _ ## f1(v1) |   \
+                                BF_ ## reg ## _ ## f2(v2) |   \
+                                BF_ ## reg ## _ ## f3(v3) |   \
+                                BF_ ## reg ## _ ## f4(v4) |   \
+                                BF_ ## reg ## _ ## f5(v5))))
+
+#define BFi_CS6n(i, reg, n, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6)  \
+    (HWi_ ## reg ## _CLR(i, n, (BM_ ## reg ## _ ## f1 |       \
+                                BM_ ## reg ## _ ## f2 |       \
+                                BM_ ## reg ## _ ## f3 |       \
+                                BM_ ## reg ## _ ## f4 |       \
+                                BM_ ## reg ## _ ## f5 |       \
+                                BM_ ## reg ## _ ## f6)),      \
+     HWi_ ## reg ## _SET(i, n, (BF_ ## reg ## _ ## f1(v1) |   \
+                                BF_ ## reg ## _ ## f2(v2) |   \
+                                BF_ ## reg ## _ ## f3(v3) |   \
+                                BF_ ## reg ## _ ## f4(v4) |   \
+                                BF_ ## reg ## _ ## f5(v5) |   \
+                                BF_ ## reg ## _ ## f6(v6))))
+
+#define BFi_CS7n(i, reg, n, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7)  \
+    (HWi_ ## reg ## _CLR(i, n, (BM_ ## reg ## _ ## f1 |       \
+                                BM_ ## reg ## _ ## f2 |       \
+                                BM_ ## reg ## _ ## f3 |       \
+                                BM_ ## reg ## _ ## f4 |       \
+                                BM_ ## reg ## _ ## f5 |       \
+                                BM_ ## reg ## _ ## f6 |       \
+                                BM_ ## reg ## _ ## f7)),      \
+     HWi_ ## reg ## _SET(i, n, (BF_ ## reg ## _ ## f1(v1) |   \
+                                BF_ ## reg ## _ ## f2(v2) |   \
+                                BF_ ## reg ## _ ## f3(v3) |   \
+                                BF_ ## reg ## _ ## f4(v4) |   \
+                                BF_ ## reg ## _ ## f5(v5) |   \
+                                BF_ ## reg ## _ ## f6(v6) |   \
+                                BF_ ## reg ## _ ## f7(v7))))
+
+#define BFi_CS8n(i, reg, n, f1, v1, f2, v2, f3, v3, f4, v4, f5, v5, f6, v6, f7, v7, f8, v8)  \
+    (HWi_ ## reg ## _CLR(i, n, (BM_ ## reg ## _ ## f1 |       \
+                                BM_ ## reg ## _ ## f2 |       \
+                                BM_ ## reg ## _ ## f3 |       \
+                                BM_ ## reg ## _ ## f4 |       \
+                                BM_ ## reg ## _ ## f5 |       \
+                                BM_ ## reg ## _ ## f6 |       \
+                                BM_ ## reg ## _ ## f7 |       \
+                                BM_ ## reg ## _ ## f8)),      \
+     HWi_ ## reg ## _SET(i, n, (BF_ ## reg ## _ ## f1(v1) |   \
+                                BF_ ## reg ## _ ## f2(v2) |   \
+                                BF_ ## reg ## _ ## f3(v3) |   \
+                                BF_ ## reg ## _ ## f4(v4) |   \
+                                BF_ ## reg ## _ ## f5(v5) |   \
+                                BF_ ## reg ## _ ## f6(v6) |   \
+                                BF_ ## reg ## _ ## f7(v7) |   \
+                                BF_ ## reg ## _ ## f8(v8))))
+// Macros to create Unicode function name
+#define WIDEN2(x) L ## x
+#define WIDEN(x) WIDEN2(x)
+#define __WFUNCTION__ WIDEN(__FUNCTION__)
+
+
+#endif // __SOCARM_MACROS_H__
diff --git a/Silicon/NXP/iMXPlatformPkg/Include/iMXIoMux.h b/Silicon/NXP/iMXPlatformPkg/Include/iMXIoMux.h
new file mode 100644
index 000000000000..b7ff96926639
--- /dev/null
+++ b/Silicon/NXP/iMXPlatformPkg/Include/iMXIoMux.h
@@ -0,0 +1,24 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef _IMX_IO_MUX_H_
+#define _IMX_IO_MUX_H_
+
+#define _IMX_PAD(CtlRegOffset, MuxRegOffset) \
+  ((((CtlRegOffset) & 0xffff) << 16) | ((MuxRegOffset) & 0xffff))
+
+#define _IMX_PAD_CTL_OFFSET(ImxPadVal) ((ImxPadVal) >> 16)
+#define _IMX_PAD_MUX_OFFSET(ImxPadVal) ((ImxPadVal) & 0xffff)
+
+#endif // _IMX_IO_MUX_H_
-- 
2.16.2.gvfs.1.33.gf5370f1



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH edk2-platforms 1/7] Silicon/NXP: Add support for iMX SDHC
  2018-07-19  4:11 ` [PATCH edk2-platforms 1/7] Silicon/NXP: Add support for iMX SDHC Chris Co
@ 2018-08-01 16:15   ` Leif Lindholm
  2018-08-01 23:59     ` Chris Co
  0 siblings, 1 reply; 10+ messages in thread
From: Leif Lindholm @ 2018-08-01 16:15 UTC (permalink / raw)
  To: Chris Co; +Cc: edk2-devel@lists.01.org, Ard Biesheuvel, Michael D Kinney

On Thu, Jul 19, 2018 at 04:11:18AM +0000, Chris Co wrote:
> This adds support for using the SD host controller on
> NXP i.MX platforms.
> 
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Christopher Co <christopher.co@microsoft.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Leif Lindholm <leif.lindholm@linaro.org>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>

Trying to build the code[1] in this patch throws up issues due to
(initially) a missing dependency on a iMXIoMuxLib mapping. Which is
not introduced in this set at all.

Could you bring these sets together into a single (huge) one,
ensuring that code is introduced in dependency order?

It will be no more unwieldy (I can push patches from the front as they
merit it), and will make my life a _lot_ easier.

If you can also address the items I point out as "address throughout"
below, for all the patches, that will reduce churn.

[1] By hacking the .inf into EmbeddedPkg/EmbeddedPkg.dsc, since the
    i.MX one is also not included in this set.

> ---
>  Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.c   | 1356 ++++++++++++++++++++
>  Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.inf |   67 +
>  Silicon/NXP/iMXPlatformPkg/Include/iMXGpio.h           |  101 ++
>  Silicon/NXP/iMXPlatformPkg/Include/iMXuSdhc.h          |  277 ++++
>  4 files changed, 1801 insertions(+)
> 
> diff --git a/Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.c b/Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.c
> new file mode 100644
> index 000000000000..5f087f8a28b9
> --- /dev/null
> +++ b/Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.c
> @@ -0,0 +1,1356 @@
> +/** @file
> +*
> +*  Copyright (c) Microsoft Corporation. All rights reserved.

Please add copyright year throughout all patches.

> +*
> +*  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 <Uefi.h>
> +#include <Library/BaseLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/IoLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DmaLib.h>
> +#include <Library/TimerLib.h>
> +
> +#include <Protocol/EmbeddedExternalDevice.h>
> +#include <Protocol/BlockIo.h>
> +#include <Protocol/DevicePath.h>
> +#include <Protocol/Sdhc.h>

Please sort includes alphabetically.

> +
> +#include <iMXuSdhc.h>
> +#include <iMXGpio.h>
> +
> +typedef struct {
> +    UINT32 IoNumber;
> +    IMX_GPIO_BANK Bank;
> +} IMX_GPIO_PIN;
> +
> +#define PCD_GPIO_PIN_IO_NUMBER(X)   ((X) & 0xFF)
> +#define PCD_GPIO_PIN_BANK(X)        (((X) >> 8) & 0xFF)
> +
> +//
> +// A special value to indicate that GPIO is not the signal source for either
> +// CardDetect or WriteProtect
> +//
> +typedef enum {
> +    USDHC_SIGNAL_GPIO_START = 0x000,
> +    USDHC_SIGNAL_GPIO_END = 0xFF00,
> +    USDHC_SIGNAL_OVERRIDE_PIN_LOW = 0xFF00,

Are the above two lines intentionally assigning the same value?

> +    USDHC_SIGNAL_OVERRIDE_PIN_HIGH = 0xFF01,
> +    USDHC_SIGNAL_INTERNAL_PIN = 0xFFFF
> +} USDHC_SIGNAL_SOURCE;
> +
> +#define USDHC_IS_GPIO_SIGNAL_SOURCE(X)  \
> +    (((X) >= USDHC_SIGNAL_GPIO_START) && ((X) < USDHC_SIGNAL_GPIO_END))
> +
> +typedef struct {
> +    UINT32 SdhcId;
> +    EFI_HANDLE SdhcProtocolHandle;
> +    USDHC_REGISTERS *RegistersBase;
> +    USDHC_SIGNAL_SOURCE CardDetectSignal;
> +    USDHC_SIGNAL_SOURCE WriteProtectSignal;
> +    IMX_GPIO_PIN CardDetectGpioPin;
> +    IMX_GPIO_PIN WriteProtectGpioPin;
> +} USDHC_PRIVATE_CONTEXT;
> +
> +#define LOG_FMT_HELPER(FMT, ...) \
> +    "SDHC%d:" FMT "%a\n", ((SdhcCtx != NULL) ? SdhcCtx->SdhcId : -1), __VA_ARGS__
> +
> +#define LOG_INFO(...) \
> +    DEBUG((DEBUG_INFO | DEBUG_BLKIO, LOG_FMT_HELPER(__VA_ARGS__, "")))
> +
> +#define LOG_TRACE(...) \
> +    DEBUG((DEBUG_VERBOSE | DEBUG_BLKIO, LOG_FMT_HELPER(__VA_ARGS__, "")))
> +
> +#define LOG_ERROR(...) \
> +    DEBUG((DEBUG_ERROR | DEBUG_BLKIO, LOG_FMT_HELPER(__VA_ARGS__, "")))
> +
> +#define LOG_ASSERT(TXT) \
> +    ASSERT(!"Sdhc: " TXT "\n")
> +
> +#ifdef MIN
> +#undef MIN
> +#define MIN(x,y) ((x) > (y) ? (y) : (x))
> +#endif // MIN

Please remove - the MIN macro has existed in Base.h since at least
2007. It does not need local redefinition.

> +
> +//
> +// uSDHC read/write FIFO is 128x32-bit
> +//
> +#define USDHC_FIFO_MAX_WORD_COUNT       128
> +
> +//
> +// Max block count allowed in a single transfer
> +//
> +#define USDHC_MAX_BLOCK_COUNT           0xFFFF
> +
> +//
> +// Number of register maximum polls
> +//
> +#define USDHC_POLL_RETRY_COUNT          100000
> +
> +//
> +// Waits between each registry poll
> +//
> +#define USDHC_POLL_WAIT_US              20
> +
> +//
> +// uSDHC input clock. Ideally, should query it from clock manager
> +//
> +#define USDHC_BASE_CLOCK_FREQ_HZ        198000000
> +
> +#define USDHC_BLOCK_LENGTH_BYTES               512
> +

Can all of the above #defines, enums and structs be moved to a local
"SdhcDxe.h"?

> +VOID
> +DumpState(
> +    IN USDHC_PRIVATE_CONTEXT *SdhcCtx
> +    )

Base indentation is always 2 spaces. (applies throughout)

> +{
> +DEBUG_CODE_BEGIN ();
> +
> +    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> +
> +    USDHC_BLK_ATT_REG BlkAtt; BlkAtt.AsUint32 = MmioRead32((UINTN)&Reg->BLK_ATT);

Please never put multiple statements on same line. (applies throughout)

Space between function name and opening parentheses (applies
throughout).

> +    UINT32 CmdArg; CmdArg = MmioRead32((UINTN)&Reg->CMD_ARG);
> +    USDHC_CMD_XFR_TYP_REG CmdXfrTyp; CmdXfrTyp.AsUint32 = MmioRead32((UINTN)&Reg->CMD_XFR_TYP);
> +    USDHC_PROT_CTRL_REG ProtCtrl; ProtCtrl.AsUint32 = MmioRead32((UINTN)&Reg->PROT_CTRL);
> +    USDHC_WTMK_LVL_REG WtmkLvl; WtmkLvl.AsUint32 = MmioRead32((UINTN)&Reg->WTMK_LVL);
> +    USDHC_MIX_CTRL_REG MixCtrl; MixCtrl.AsUint32 = MmioRead32((UINTN)&Reg->MIX_CTRL);
> +    UINT32 IntStatusEn = MmioRead32((UINTN)&Reg->INT_STATUS_EN);
> +    UINT32 IntSignalEn = MmioRead32((UINTN)&Reg->INT_SIGNAL_EN);
> +    UINT32 VendSpec = MmioRead32((UINTN)&Reg->VEND_SPEC);
> +    UINT32 MmcBoot = MmioRead32((UINTN)&Reg->MMC_BOOT);
> +    UINT32 VendSpec2 = MmioRead32((UINTN)&Reg->VEND_SPEC2);
> +    USDHC_INT_STATUS_REG IntStatus; IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS);
> +    USDHC_PRES_STATE_REG PresState; PresState.AsUint32 = MmioRead32((UINTN)&Reg->PRES_STATE);
> +
> +    LOG_INFO(
> +        " - BLK_ATT\t:0x%08x BLKSIZE:0x%x BLKCNT:0x%08x",
> +        BlkAtt.AsUint32,
> +        BlkAtt.Fields.BLKSIZE,
> +        BlkAtt.Fields.BLKCNT);
> +
> +    LOG_INFO(" - CMD_ARG\t:0x%08x", CmdArg);
> +
> +    LOG_INFO(
> +        " - CMD_XFR_TYP\t:0x%08x RSPTYP:%d CCCEN:%d CICEN:%d DPSEL:%d CMDTYP:%d CMDINX:%d",
> +        CmdXfrTyp.AsUint32,
> +        CmdXfrTyp.Fields.RSPTYP,
> +        CmdXfrTyp.Fields.CCCEN,
> +        CmdXfrTyp.Fields.CICEN,
> +        CmdXfrTyp.Fields.DPSEL,
> +        CmdXfrTyp.Fields.CMDTYP,
> +        CmdXfrTyp.Fields.CMDINX);
> +
> +    LOG_INFO(
> +        " - PROT_CTRL\t:0x%08x DTW:%d D3CD:%d CDSS:%d EMODE:%d DMASEL:%d SABGREQ:%d BURST_LEN_EN:%d",
> +        ProtCtrl.AsUint32,
> +        ProtCtrl.Fields.DTW,
> +        ProtCtrl.Fields.D3CD,
> +        ProtCtrl.Fields.CDSS,
> +        ProtCtrl.Fields.EMODE,
> +        ProtCtrl.Fields.DMASEL,
> +        ProtCtrl.Fields.SABGREQ,
> +        ProtCtrl.Fields.BURST_LEN_EN);
> +
> +    LOG_INFO(
> +        " - WTMK_LVL\t:0x%08x RD_WML:%d RD_BRST_LEN:%d WR_WML:%d WR_BRST_LEN:%d",
> +        WtmkLvl.AsUint32,
> +        WtmkLvl.Fields.RD_WML,
> +        WtmkLvl.Fields.RD_BRST_LEN,
> +        WtmkLvl.Fields.WR_WML,
> +        WtmkLvl.Fields.WR_BRST_LEN);
> +
> +    LOG_INFO(
> +        " - MIX_CTRL\t:0x%08x DMAEN:%d BCEN:%d AC12EN:%d DTDSEL:%d MSBSEL:%d AC23EN:%d FBCLK_SEL:%d",
> +        MixCtrl.AsUint32,
> +        MixCtrl.Fields.DMAEN,
> +        MixCtrl.Fields.BCEN,
> +        MixCtrl.Fields.AC12EN,
> +        MixCtrl.Fields.DTDSEL,
> +        MixCtrl.Fields.MSBSEL,
> +        MixCtrl.Fields.AC23EN,
> +        MixCtrl.Fields.FBCLK_SEL);
> +
> +    LOG_INFO(" - INT_STATUS_EN\t:0x%08x", IntStatusEn);
> +    LOG_INFO(" - INT_SIGNAL_EN\t:0x%08x", IntSignalEn);
> +    LOG_INFO(" - VEND_SPEC\t:0x%08x", VendSpec);
> +    LOG_INFO(" - MMC_BOOT\t:0x%08x", MmcBoot);
> +    LOG_INFO(" - VEND_SPEC2\t:0x%08x", VendSpec2);
> +
> +    LOG_INFO(
> +        " - INT_STATUS\t:0x%08x CC:%d TC:%d BWR:%d BRR:%d CTOE:%d CCE:%d CEBE:%d CIE:%d DTOE:%d DCE:%d DEBE:%d",
> +        IntStatus.AsUint32,
> +        IntStatus.Fields.CC,
> +        IntStatus.Fields.TC,
> +        IntStatus.Fields.BWR,
> +        IntStatus.Fields.BRR,
> +        IntStatus.Fields.CTOE,
> +        IntStatus.Fields.CCE,
> +        IntStatus.Fields.CEBE,
> +        IntStatus.Fields.CIE,
> +        IntStatus.Fields.DTOE,
> +        IntStatus.Fields.DCE,
> +        IntStatus.Fields.DEBE);
> +
> +    LOG_INFO(
> +        " - PRES_STATE\t:0x%08x CIHB:%d CDIHB:%d DLA:%d WTA:%d RTA:%d BWEN:%d BREN:%d CINST:%d DLSL:0x%x",
> +        PresState.AsUint32,
> +        PresState.Fields.CIHB,
> +        PresState.Fields.CDIHB,
> +        PresState.Fields.DLA,
> +        PresState.Fields.WTA,
> +        PresState.Fields.RTA,
> +        PresState.Fields.BWEN,
> +        PresState.Fields.BREN,
> +        PresState.Fields.CINST,
> +        PresState.Fields.DLSL);
> +
> +DEBUG_CODE_END ();
> +}
> +
> +EFI_STATUS
> +WaitForReadFifo(
> +    IN USDHC_PRIVATE_CONTEXT *SdhcCtx
> +    )
> +{
> +    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> +    USDHC_INT_STATUS_REG IntStatus; IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS);
> +    UINT32 Retry = USDHC_POLL_RETRY_COUNT;
> +
> +    while (!IntStatus.Fields.BRR &&
> +        !(IntStatus.AsUint32 & USDHC_INT_STATUS_ERROR) &&
> +        Retry) {

Would looke better with all tests horizontally aligned.

> +       --Retry;
> +       gBS->Stall(USDHC_POLL_WAIT_US);
> +       IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS);
> +    }
> +
> +    if (IntStatus.AsUint32 & USDHC_INT_STATUS_ERROR) {
> +        LOG_ERROR("Error detected");
> +        DumpState(SdhcCtx);
> +        return EFI_DEVICE_ERROR;
> +    } else if (IntStatus.Fields.BRR) {
> +        MmioWrite32((UINTN)&Reg->INT_STATUS, IntStatus.AsUint32);
> +        return EFI_SUCCESS;
> +    } else {
> +        ASSERT(!Retry);
> +        LOG_ERROR("Time-out waiting on read FIFO");
> +        DumpState(SdhcCtx);
> +        return EFI_TIMEOUT;
> +     }
> +}
> +
> +EFI_STATUS
> +WaitForWriteFifo(
> +    IN USDHC_PRIVATE_CONTEXT *SdhcCtx
> +    )
> +{
> +    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> +    USDHC_INT_STATUS_REG IntStatus; IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS) ;
> +    UINT32 Retry = USDHC_POLL_RETRY_COUNT;
> +
> +    while (!IntStatus.Fields.BWR &&
> +        !(IntStatus.AsUint32 & USDHC_INT_STATUS_ERROR) &&
> +        Retry) {
> +       --Retry;
> +       gBS->Stall(USDHC_POLL_WAIT_US);
> +       IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS);
> +    }
> +
> +    if (IntStatus.AsUint32 & USDHC_INT_STATUS_ERROR) {
> +        LOG_ERROR("Error detected");
> +        DumpState(SdhcCtx);
> +        return EFI_DEVICE_ERROR;
> +    } else if (IntStatus.Fields.BWR) {
> +        MmioWrite32((UINTN)&Reg->INT_STATUS, IntStatus.AsUint32);
> +        return EFI_SUCCESS;
> +    } else {
> +        ASSERT(!Retry);
> +        LOG_ERROR("Time-out waiting on write FIFO");
> +        DumpState(SdhcCtx);
> +        return EFI_TIMEOUT;
> +    }
> +}
> +
> +EFI_STATUS
> +WaitForCmdAndOrDataLine(
> +    IN USDHC_PRIVATE_CONTEXT *SdhcCtx,
> +    IN const SD_COMMAND *Cmd
> +    )
> +{
> +    BOOLEAN WaitForDataLine;
> +
> +    //
> +    // Waiting on the DATA lines is the default behavior if no CMD is specified
> +    //
> +    if (Cmd == NULL) {
> +        WaitForDataLine = TRUE;
> +    } else {
> +        //
> +        // Per datasheet, the SDHC can isssue CMD0, CMD12, CMD13 and CMD52
> +        // when the DATA lines are busy during a data transfer. Other commands
> +        // should wait on the DATA lines before issuing
> +        //
> +        switch (Cmd->Index) {
> +        case 0:
> +        case 12:
> +        case 13:
> +        case 52:
> +            WaitForDataLine = FALSE;
> +            break;
> +        default:
> +            WaitForDataLine = TRUE;
> +        }
> +    }
> +
> +    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> +    USDHC_PRES_STATE_REG PresState; PresState.AsUint32 = MmioRead32((UINTN)&Reg->PRES_STATE);
> +    USDHC_INT_STATUS_REG IntStatus; IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS) ;
> +    UINT32 Retry = USDHC_POLL_RETRY_COUNT;
> +
> +    while (PresState.Fields.CIHB &&
> +           (!WaitForDataLine || PresState.Fields.CDIHB) &&
> +           !(IntStatus.AsUint32 & USDHC_INT_STATUS_ERROR) &&
> +           Retry) {
> +        gBS->Stall(USDHC_POLL_WAIT_US);
> +        --Retry;
> +        PresState.AsUint32 = MmioRead32((UINTN)&Reg->PRES_STATE);
> +        IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS);
> +    }
> +
> +    if (IntStatus.AsUint32 & USDHC_INT_STATUS_ERROR) {
> +        LOG_ERROR("Error detected");
> +        DumpState(SdhcCtx);
> +        return EFI_DEVICE_ERROR;
> +    } else if (!(PresState.Fields.CIHB &&
> +           (!WaitForDataLine || PresState.Fields.CDIHB))) {
> +           return EFI_SUCCESS;
> +    } else {
> +        ASSERT(!Retry);
> +        LOG_ERROR("Time-out waiting on CMD and/or DATA lines");
> +        DumpState(SdhcCtx);
> +        return EFI_TIMEOUT;
> +    }
> +}
> +
> +EFI_STATUS
> +WaitForCmdResponse(
> +    IN USDHC_PRIVATE_CONTEXT *SdhcCtx
> +    )
> +{
> +    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> +    USDHC_INT_STATUS_REG IntStatus; IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS) ;
> +    UINT32 Retry = USDHC_POLL_RETRY_COUNT;
> +
> +    //
> +    // Wait for command to finish execution either with success or failure
> +    //
> +    while (!IntStatus.Fields.CC &&
> +           !(IntStatus.AsUint32 & USDHC_INT_STATUS_ERROR) &&
> +           Retry) {
> +        gBS->Stall(USDHC_POLL_WAIT_US);
> +        --Retry;
> +        IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS);
> +    }
> +
> +    if (IntStatus.AsUint32 & USDHC_INT_STATUS_ERROR) {
> +        LOG_ERROR("Error detected");
> +        DumpState(SdhcCtx);
> +        return EFI_DEVICE_ERROR;
> +    } else if (IntStatus.Fields.CC) {
> +        MmioWrite32((UINTN)&Reg->INT_STATUS, IntStatus.AsUint32);
> +        return EFI_SUCCESS;
> +    } else {
> +        ASSERT(!Retry);
> +        LOG_ERROR("Time-out waiting on command completion");
> +        DumpState(SdhcCtx);
> +        return EFI_TIMEOUT;
> +    }
> +}
> +
> +EFI_STATUS
> +SdhcSetBusWidth(
> +  IN EFI_SDHC_PROTOCOL *This,
> +  IN SD_BUS_WIDTH BusWidth
> +  )
> +{
> +    USDHC_PRIVATE_CONTEXT *SdhcCtx = (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
> +    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> +    USDHC_PROT_CTRL_REG ProtCtrl; ProtCtrl.AsUint32 = MmioRead32((UINTN)&Reg->PROT_CTRL);
> +
> +    LOG_TRACE("SdhcSetBusWidth(%d)", BusWidth);
> +
> +    switch (BusWidth) {
> +    case SdBusWidth1Bit:
> +        ProtCtrl.Fields.DTW = USDHC_PROT_CTRL_DTW_1BIT;
> +        break;
> +    case SdBusWidth4Bit:
> +        ProtCtrl.Fields.DTW = USDHC_PROT_CTRL_DTW_4BIT;
> +        break;
> +    case SdBusWidth8Bit:
> +        ProtCtrl.Fields.DTW = USDHC_PROT_CTRL_DTW_8BIT;
> +        break;
> +    default:
> +        LOG_ASSERT("Invalid bus width");
> +        return EFI_INVALID_PARAMETER;
> +    }
> +
> +    MmioWrite32((UINTN)&Reg->PROT_CTRL, ProtCtrl.AsUint32);
> +
> +    return EFI_SUCCESS;
> +}
> +
> +EFI_STATUS
> +SdhcSetClock(
> +    IN EFI_SDHC_PROTOCOL *This,
> +    IN UINT32 TargetFreqHz
> +    )
> +{
> +    USDHC_PRIVATE_CONTEXT *SdhcCtx = (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
> +
> +    LOG_TRACE("SdhcSetClock(%dHz)", TargetFreqHz);
> +
> +    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> +    USDHC_SYS_CTRL_REG SysCtrl; SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
> +
> +    //
> +    // SDCLK = (Base Clock) / (prescaler x divisor)
> +    //
> +    UINT32 Prescaler;
> +    UINT32 Divisor;
> +    UINT32 SDCLK;
> +
> +    USDHC_MIX_CTRL_REG MixCtrl; MixCtrl.AsUint32 = MmioRead32((UINTN)&Reg->MIX_CTRL);
> +
> +    //
> +    // Bruteforce to find the best prescaler and divisor that result
> +    // in SDCLK less than or equal to the requested frequency
> +    //
> +    // Allowed |Base clock divided By
> +    // SDCLKFS |DDR_EN=0   |DDR_EN=1
> +    // 80h      256         512
> +    // 40h      128         256
> +    // 20h      64          128
> +    // 10h      32          64
> +    // 08h      16          32
> +    // 04h      8           16
> +    // 02h      4           8
> +    // 01h      2           4
> +    // 00h      1           2
> +    //
> +    const UINT32 PRESCALER_MIN = (MixCtrl.Fields.DDR_EN ? 2 : 1);
> +    const UINT32 PRESCALER_MAX = (MixCtrl.Fields.DDR_EN ? 512 : 256);;
> +    const UINT32 DIVISOR_MIN = 1;
> +    const UINT32 DIVISOR_MAX = 16;

CONST

> +    UINT32 MinFreqDistance = 0xFFFFFFFF;

MAX_UINT32?

> +    UINT32 FreqDistance;
> +    UINT32 BestPrescaler = 0;
> +    UINT32 BestDivisor = 0;
> +
> +    //
> +    // Bruteforce to find the best prescaler and divisor that result
> +    // in SDCLK less than or equal to the requested frequency
> +    //
> +    for (Prescaler = PRESCALER_MAX; Prescaler >= PRESCALER_MIN; Prescaler /= 2) {
> +        for (Divisor = DIVISOR_MIN; Divisor <= DIVISOR_MAX; ++Divisor) {
> +            SDCLK = USDHC_BASE_CLOCK_FREQ_HZ / (Prescaler * Divisor);
> +
> +            //
> +            // We are not willing to choose clocks higher than the target one
> +            // to avoid exceeding device limits
> +            //
> +            if (SDCLK > TargetFreqHz) {
> +                continue;
> +            } else if (SDCLK == TargetFreqHz) {
> +                BestPrescaler = Prescaler;
> +                BestDivisor = Divisor;
> +                break;
> +            } else {
> +                FreqDistance = TargetFreqHz - SDCLK;
> +                if (FreqDistance < MinFreqDistance) {
> +                    MinFreqDistance = FreqDistance;
> +                    BestPrescaler = Prescaler;
> +                    BestDivisor = Divisor;
> +                }
> +            }
> +        }
> +    }
> +
> +    //
> +    // Wait for clock to become stable before any modifications
> +    //
> +    USDHC_PRES_STATE_REG PresState; PresState.AsUint32 = MmioRead32((UINTN)&Reg->PRES_STATE);
> +    UINT32 Retry = USDHC_POLL_RETRY_COUNT;
> +
> +    while (!PresState.Fields.SDSTB &&
> +           Retry) {
> +        gBS->Stall(USDHC_POLL_WAIT_US);
> +        --Retry;
> +        PresState.AsUint32 = MmioRead32((UINTN)&Reg->PRES_STATE);
> +    }
> +
> +    if (!PresState.Fields.SDSTB) {
> +        ASSERT(!Retry);
> +        LOG_ERROR("Time-out waiting on SD clock to stabilize");
> +        DumpState(SdhcCtx);
> +        return EFI_TIMEOUT;
> +    }
> +
> +    SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
> +    SysCtrl.Fields.SDCLKFS = BestPrescaler / (MixCtrl.Fields.DDR_EN ? 4 : 2);
> +    SysCtrl.Fields.DVS = BestDivisor - 1;
> +
> +    MmioWrite32((UINTN)&Reg->SYS_CTRL, SysCtrl.AsUint32);
> +
> +    SDCLK = USDHC_BASE_CLOCK_FREQ_HZ / (BestPrescaler * BestDivisor);
> +
> +    LOG_TRACE(
> +        "Current SDCLK:%dHz SDCLKFS:0x%x DVS:0x%x",
> +        SDCLK,
> +        (UINT32)SysCtrl.Fields.SDCLKFS,
> +        (UINT32)SysCtrl.Fields.DVS);
> +
> +    return EFI_SUCCESS;
> +}
> +
> +BOOLEAN
> +SdhcIsCardPresent(
> +    IN EFI_SDHC_PROTOCOL *This
> +    )
> +{
> +    USDHC_PRIVATE_CONTEXT *SdhcCtx = (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
> +    BOOLEAN IsCardPresent;
> +
> +    if (SdhcCtx->CardDetectSignal == USDHC_SIGNAL_INTERNAL_PIN) {
> +        USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> +        USDHC_PRES_STATE_REG PresState; PresState.AsUint32 = MmioRead32((UINTN)&Reg->PRES_STATE);
> +        IsCardPresent = (PresState.Fields.CINST == 1);
> +    } else {
> +        IMX_GPIO_VALUE CardDetectLevel;
> +        if (USDHC_IS_GPIO_SIGNAL_SOURCE(SdhcCtx->CardDetectSignal)) {
> +            //
> +            //Read the state of  CD_B pin for the card socket
> +            //
> +            CardDetectLevel =
> +                ImxGpioRead(
> +                    SdhcCtx->CardDetectGpioPin.Bank,
> +                    SdhcCtx->CardDetectGpioPin.IoNumber);
> +        } else if (SdhcCtx->CardDetectSignal == USDHC_SIGNAL_OVERRIDE_PIN_LOW) {
> +            CardDetectLevel = IMX_GPIO_LOW;
> +        } else if (SdhcCtx->CardDetectSignal == USDHC_SIGNAL_OVERRIDE_PIN_HIGH) {
> +            CardDetectLevel = IMX_GPIO_HIGH;
> +        } else {
> +            ASSERT(!"Invalid CardDetect signal source");
> +            CardDetectLevel = IMX_GPIO_LOW;
> +        }
> +
> +        //
> +        // When no card is present,  CD_B is pulled-high, and the SDCard when
> +        // inserted will pull CD_B low
> +        // CD_B=0 means card present, while CD_B=1 means card not present
> +        //
> +        IsCardPresent = (CardDetectLevel == IMX_GPIO_LOW);
> +    }
> +
> +  // Enable if needed while trace debugging, otherwise this will flood the debug
> +  // console due to being called periodically every second for each SDHC
> +#if 0
> +  LOG_TRACE("SdhcIsCardPresent(): %d", IsCardPresent);
> +#endif

That sounds like something to be filtered by setting it to
DEBUG_VERBOSE, which LOG_TRACE already does.

> +
> +    return IsCardPresent;
> +}
> +
> +BOOLEAN
> +SdhcIsReadOnly(
> +    IN EFI_SDHC_PROTOCOL *This
> +    )
> +{
> +    USDHC_PRIVATE_CONTEXT *SdhcCtx = (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
> +    BOOLEAN IsReadOnly;
> +
> +    if (SdhcCtx->WriteProtectSignal == USDHC_SIGNAL_INTERNAL_PIN) {
> +        USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> +        USDHC_PRES_STATE_REG PresState; PresState.AsUint32 = MmioRead32((UINTN)&Reg->PRES_STATE);
> +        IsReadOnly = (PresState.Fields.WPSPL == 0);
> +    } else {
> +        IMX_GPIO_VALUE WriteProtectLevel;
> +        if (USDHC_IS_GPIO_SIGNAL_SOURCE(SdhcCtx->WriteProtectSignal)) {
> +            //
> +            //Read the state of  WP pin for the card socket
> +            //
> +            WriteProtectLevel =
> +                ImxGpioRead(
> +                    SdhcCtx->WriteProtectGpioPin.Bank,
> +                    SdhcCtx->WriteProtectGpioPin.IoNumber);
> +        } else if (SdhcCtx->WriteProtectSignal == USDHC_SIGNAL_OVERRIDE_PIN_LOW) {
> +            WriteProtectLevel = IMX_GPIO_LOW;
> +        } else if (SdhcCtx->WriteProtectSignal == USDHC_SIGNAL_OVERRIDE_PIN_HIGH) {
> +            WriteProtectLevel = IMX_GPIO_HIGH;
> +        } else {
> +            ASSERT(!"Invalid WriteProtect signal source");
> +            WriteProtectLevel = IMX_GPIO_LOW;
> +        }
> +
> +        //
> +        // When no card is present,  WP is pulled-high, and the SDCard when
> +        // inserted will pull WP low if WP switch is configured to write enable
> +        // the SDCard, otherwise it WP will stay pulled-high
> +        // WP=0 means write enabled, while WP=1 means write protected
> +        //
> +         IsReadOnly = (WriteProtectLevel != IMX_GPIO_LOW);

Indentation (relative to comment).

> +    }
> +
> +    LOG_TRACE("SdhcIsReadOnly(): %d", IsReadOnly);
> +    return IsReadOnly;
> +}
> +
> +EFI_STATUS
> +SdhcSendCommand(
> +    IN EFI_SDHC_PROTOCOL *This,
> +    IN const SD_COMMAND *Cmd,
> +    IN UINT32 Argument,
> +    IN OPTIONAL const SD_COMMAND_XFR_INFO *XfrInfo
> +    )
> +{
> +    EFI_STATUS Status;
> +    USDHC_PRIVATE_CONTEXT *SdhcCtx = (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
> +    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> +
> +    LOG_TRACE(
> +        "SdhcSendCommand(%cCMD%d, %08x)",
> +        ((Cmd->Class == SdCommandClassApp) ? 'A' : ' '),
> +        (UINT32)Cmd->Index,
> +        Argument);
> +
> +    Status = WaitForCmdAndOrDataLine(SdhcCtx, Cmd);
> +    if (Status != EFI_SUCCESS) {
> +        LOG_ERROR("SdhcWaitForCmdAndDataLine failed");
> +        return Status;
> +    }
> +
> +    //
> +    // Clear Interrupt status
> +    //
> +    MmioWrite32((UINTN)&Reg->INT_STATUS, (UINT32)~0);
> +
> +    //
> +    // Setup data transfer command
> +    //
> +    if (XfrInfo) {
> +        if (XfrInfo->BlockCount > USDHC_MAX_BLOCK_COUNT) {
> +            LOG_ERROR(
> +                "Provided %d block count while SDHC max block count is %d",
> +                XfrInfo->BlockCount,
> +                USDHC_MAX_BLOCK_COUNT);
> +            return EFI_INVALID_PARAMETER;
> +        }
> +
> +        //
> +        // Set block size and count
> +        //
> +        USDHC_BLK_ATT_REG BlkAtt = { 0 };
> +        BlkAtt.Fields.BLKSIZE = XfrInfo->BlockSize;
> +        ASSERT (XfrInfo->BlockCount > 0);
> +        BlkAtt.Fields.BLKCNT = XfrInfo->BlockCount;
> +        MmioWrite32((UINTN)&Reg->BLK_ATT, BlkAtt.AsUint32);
> +
> +        //
> +        // Set transfer parameters
> +        //
> +        USDHC_MIX_CTRL_REG MixCtrl = { 0 };
> +        if (Cmd->TransferDirection == SdTransferDirectionRead) {
> +            MixCtrl.Fields.DTDSEL = 1;
> +        }
> +
> +        if (XfrInfo->BlockCount > 1) {
> +            ASSERT((Cmd->TransferType == SdTransferTypeMultiBlock) ||
> +                (Cmd->TransferType == SdTransferTypeMultiBlockNoStop));
> +            MixCtrl.Fields.MSBSEL = 1;
> +            MixCtrl.Fields.BCEN = 1;
> +        }
> +
> +        MmioWrite32((UINTN)&Reg->MIX_CTRL, MixCtrl.AsUint32);
> +
> +        USDHC_WTMK_LVL_REG WtmkLvl = { 0 };
> +
> +#if 0

No #if 0 upstream.

> +        //
> +        // Set FIFO watermarks
> +        //
> +        // Configure FIFO watermark levels to 1/2 the FIFO capacity for read,
> +        // and 1/3 the FIFO capacity for write.
> +        // In case the whole transfer can fit in the FIFO, then use
> +        // the whole transfer length as the FIFO threshold, so we do
> +        // the read/write in one-shot
> +        //
> +
> +        UINT32 FifoThresholdWordCount;
> +        if (Cmd->TransferDirection == SdTransferDirectionRead) {
> +            FifoThresholdWordCount = USDHC_FIFO_MAX_WORD_COUNT / 2;
> +        } else {
> +            FifoThresholdWordCount = USDHC_FIFO_MAX_WORD_COUNT / 3;
> +        }
> +
> +        ASSERT(XfrInfo->BlockSize % sizeof(UINT32) == 0);
> +        UINT32 TransferByteLength = XfrInfo->BlockSize * XfrInfo->BlockCount;
> +        const UINT32 TransferWordCount = TransferByteLength / sizeof(UINT32);
> +        FifoThresholdWordCount = MIN(TransferWordCount, FifoThresholdWordCount);
> +
> +        ASSERT(FifoThresholdWordCount <= 0xFFFF);
> +        const UINT16 Wml = (UINT16)FifoThresholdWordCount;
> +        ASSERT(Wml <= USDHC_FIFO_MAX_WORD_COUNT);
> +
> +        if (Cmd->TransferDirection == SdTransferDirectionRead) {
> +            WtmkLvl.Fields.RD_WML = (UINT8)Wml;
> +            WtmkLvl.Fields.RD_BRST_LEN = MIN(Wml, 8);
> +        } else {
> +            WtmkLvl.Fields.WR_WML = (UINT8)Wml;
> +            WtmkLvl.Fields.WR_BRST_LEN = MIN(Wml, 8);;
> +        }
> +#endif
> +
> +#if 0
> +        WtmkLvl.Fields.RD_WML = 64;
> +        WtmkLvl.Fields.RD_BRST_LEN = 16;
> +        WtmkLvl.Fields.WR_WML = 64;
> +        WtmkLvl.Fields.WR_BRST_LEN = 16;
> +#endif
> +
> +        UINT32 WtmkThreshold = USDHC_BLOCK_LENGTH_BYTES / 4;
> +        if (Cmd->TransferDirection == SdTransferDirectionRead) {
> +            if (WtmkThreshold > USDHC_WTMK_RD_WML_MAX_VAL) {
> +                WtmkThreshold = USDHC_WTMK_RD_WML_MAX_VAL;
> +            }
> +            WtmkLvl.Fields.RD_WML = WtmkThreshold;
> +        } else {
> +            if (WtmkThreshold > USDHC_WTMK_WR_WML_MAX_VAL) {
> +                WtmkThreshold = USDHC_WTMK_WR_WML_MAX_VAL;
> +            }
> +            WtmkLvl.Fields.WR_WML = WtmkThreshold;
> +        }
> +
> +        MmioWrite32((UINTN)&Reg->WTMK_LVL, WtmkLvl.AsUint32);
> +    }
> +
> +    //
> +    // Set CMD parameters
> +    //
> +    USDHC_CMD_XFR_TYP_REG CmdXfrTyp = { 0 };
> +    CmdXfrTyp.Fields.CMDINX = Cmd->Index;
> +
> +    switch (Cmd->ResponseType) {
> +    case SdResponseTypeNone:
> +        break;
> +
> +    case SdResponseTypeR1:
> +    case SdResponseTypeR5:
> +    case SdResponseTypeR6:
> +        CmdXfrTyp.Fields.RSPTYP = USDHC_CMD_XFR_TYP_RSPTYP_RSP_48;
> +        CmdXfrTyp.Fields.CICEN = 1;
> +        CmdXfrTyp.Fields.CCCEN = 1;
> +        break;
> +
> +    case SdResponseTypeR1B:
> +    case SdResponseTypeR5B:
> +        CmdXfrTyp.Fields.RSPTYP = USDHC_CMD_XFR_TYP_RSPTYP_RSP_48_CHK_BSY;
> +        CmdXfrTyp.Fields.CICEN = 1;
> +        CmdXfrTyp.Fields.CCCEN = 1;
> +        break;
> +
> +    case SdResponseTypeR2:
> +        CmdXfrTyp.Fields.RSPTYP = USDHC_CMD_XFR_TYP_RSPTYP_RSP_136;
> +        CmdXfrTyp.Fields.CCCEN = 1;
> +        break;
> +
> +    case SdResponseTypeR3:
> +    case SdResponseTypeR4:
> +        CmdXfrTyp.Fields.RSPTYP = USDHC_CMD_XFR_TYP_RSPTYP_RSP_48;
> +        break;
> +
> +    default:
> +        LOG_ASSERT("SdhcSendCommand(): Invalid response type");
> +        return EFI_INVALID_PARAMETER;
> +    }
> +
> +    if (Cmd->Type == SdCommandTypeAbort) {
> +        CmdXfrTyp.Fields.CMDTYP = USDHC_CMD_XFR_TYP_CMDTYP_ABORT;
> +    }
> +
> +    if (XfrInfo) {
> +        CmdXfrTyp.Fields.DPSEL = 1;
> +    }
> +
> +    //
> +    // Send command and wait for response
> +    //
> +    MmioWrite32((UINTN)&Reg->CMD_ARG, Argument);
> +    MmioWrite32((UINTN)&Reg->CMD_XFR_TYP, CmdXfrTyp.AsUint32);
> +
> +    Status = WaitForCmdResponse(SdhcCtx);
> +    if (EFI_ERROR(Status)) {
> +        LOG_ERROR("WaitForCmdResponse() failed. %r", Status);
> +        return Status;
> +    }
> +
> +    return EFI_SUCCESS;
> +}
> +
> +EFI_STATUS
> +SdhcReceiveResponse(
> +    IN EFI_SDHC_PROTOCOL *This,
> +    IN const SD_COMMAND *Cmd,
> +    OUT UINT32 *Buffer
> +    )
> +{
> +
> +    USDHC_PRIVATE_CONTEXT *SdhcCtx = (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
> +
> +    if (Buffer == NULL) {
> +        LOG_ERROR("Input Buffer is NULL");
> +        return EFI_INVALID_PARAMETER;
> +    }
> +
> +    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> +
> +    switch (Cmd->ResponseType) {
> +    case SdResponseTypeNone:
> +        break;
> +    case SdResponseTypeR1:
> +    case SdResponseTypeR1B:
> +    case SdResponseTypeR3:
> +    case SdResponseTypeR4:
> +    case SdResponseTypeR5:
> +    case SdResponseTypeR5B:
> +    case SdResponseTypeR6:
> +        Buffer[0] = MmioRead32((UINTN)&Reg->CMD_RSP0);
> +        LOG_TRACE(
> +            "SdhcReceiveResponse(Type: %x), Buffer[0]: %08x",
> +            Cmd->ResponseType,
> +            Buffer[0]);
> +        break;
> +    case SdResponseTypeR2:
> +        Buffer[0] = MmioRead32((UINTN)&Reg->CMD_RSP0);
> +        Buffer[1] = MmioRead32((UINTN)&Reg->CMD_RSP1);
> +        Buffer[2] = MmioRead32((UINTN)&Reg->CMD_RSP2);
> +        Buffer[3] = MmioRead32((UINTN)&Reg->CMD_RSP3);
> +
> +        LOG_TRACE(
> +            "SdhcReceiveResponse(Type: %x), Buffer[0-3]: %08x, %08x, %08x, %08x",
> +            Cmd->ResponseType,
> +            Buffer[0],
> +            Buffer[1],
> +            Buffer[2],
> +            Buffer[3]);
> +        break;
> +    default:
> +        LOG_ASSERT("SdhcReceiveResponse(): Invalid response type");
> +        return EFI_INVALID_PARAMETER;
> +    }
> +
> +    return EFI_SUCCESS;
> +}
> +
> +EFI_STATUS
> +SdhcReadBlockData(
> +    IN EFI_SDHC_PROTOCOL *This,
> +    IN UINTN LengthInBytes,
> +    OUT UINT32* Buffer
> +    )
> +{
> +    USDHC_PRIVATE_CONTEXT *SdhcCtx = (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
> +
> +    LOG_TRACE(
> +        "SdhcReadBlockData(LengthInBytes: 0x%x, Buffer: 0x%x)",
> +        LengthInBytes,
> +        Buffer);
> +
> +    ASSERT(Buffer != NULL);
> +    ASSERT(LengthInBytes % sizeof(UINT32) == 0);
> +
> +    UINTN WordIdx = 0;
> +    UINTN NumWords = LengthInBytes / sizeof(UINT32);
> +    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> +    USDHC_WTMK_LVL_REG WtmkLvl; WtmkLvl.AsUint32 = MmioRead32((UINTN)&Reg->WTMK_LVL);
> +    UINT32 FifoWords;
> +    EFI_STATUS Status;
> +
> +    ASSERT(WtmkLvl.Fields.RD_WML > 0);
> +
> +    while (WordIdx < NumWords) {
> +        Status = WaitForReadFifo(SdhcCtx);
> +        if (EFI_ERROR(Status)) {
> +            LOG_ERROR(
> +                "WaitForReadFifo() failed at Word%d. %r",
> +                (UINT32)WordIdx,
> +                Status);
> +            return Status;
> +        }
> +
> +        FifoWords = WtmkLvl.Fields.RD_WML;
> +        while (WordIdx < NumWords && FifoWords--) {
> +            Buffer[WordIdx] = MmioRead32((UINTN)&Reg->DATA_BUFF_ACC_PORT);
> +            ++WordIdx;
> +        }
> +    }
> +
> +    return EFI_SUCCESS;
> +}
> +
> +EFI_STATUS
> +SdhcWriteBlockData(
> +    IN EFI_SDHC_PROTOCOL *This,
> +    IN UINTN LengthInBytes,
> +    IN const UINT32* Buffer
> +    )
> +{
> +    USDHC_PRIVATE_CONTEXT *SdhcCtx = (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
> +
> +    LOG_TRACE(
> +        "SdhcWriteBlockData(LengthInBytes: 0x%x, Buffer: 0x%x)",
> +        LengthInBytes,
> +        Buffer);
> +
> +    ASSERT(Buffer != NULL);
> +    ASSERT(LengthInBytes % USDHC_BLOCK_LENGTH_BYTES == 0);
> +
> +    const UINTN BlockWordCount = USDHC_BLOCK_LENGTH_BYTES / sizeof(UINT32);
> +    UINTN NumBlocks = LengthInBytes / USDHC_BLOCK_LENGTH_BYTES;
> +    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> +    USDHC_INT_STATUS_REG IntStatus;
> +    USDHC_PRES_STATE_REG PresState;
> +    INT32 Timeout = 100000; // Nothing special about that constant

More of a retry than a timeout?

> +
> +    while (NumBlocks > 0) {
> +        UINTN RemainingWords = BlockWordCount;
> +        IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS);
> +        PresState.AsUint32 = MmioRead32((UINTN)&Reg->PRES_STATE);
> +        while (!PresState.Fields.BWEN && --Timeout);

Does this need a MemoryFence()?

> +        if (Timeout <= 0) {
> +            LOG_ERROR ("Timeout waiting for FIFO PRES_STATE.BWEN flag");
> +            return EFI_TIMEOUT;
> +        }
> +
> +        while (RemainingWords > 0 && !IntStatus.Fields.TC) {
> +            MicroSecondDelay (100);

Does this need a MemoryFence()?

> +            IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS);
> +            MmioWrite32((UINTN)&Reg->DATA_BUFF_ACC_PORT, *Buffer);
> +            Buffer++;
> +            RemainingWords--;
> +        }
> +        NumBlocks--;
> +    }
> +
> +    return EFI_SUCCESS;
> +}
> +
> +EFI_STATUS
> +SdhcSoftwareReset(
> +    IN EFI_SDHC_PROTOCOL *This,
> +    IN SDHC_RESET_TYPE ResetType
> +    )
> +{
> +    USDHC_PRIVATE_CONTEXT *SdhcCtx = (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
> +    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> +
> +    UINT32 Retry;
> +
> +    if (ResetType == SdhcResetTypeAll) {
> +        LOG_TRACE("SdhcSoftwareReset(ALL)");
> +        //
> +        // Software reset for ALL
> +        //
> +        USDHC_SYS_CTRL_REG SysCtrl; SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
> +        SysCtrl.Fields.RSTA = 1;
> +        MmioWrite32((UINTN)&Reg->SYS_CTRL, SysCtrl.AsUint32);
> +        Retry = USDHC_POLL_RETRY_COUNT;
> +        //
> +        // Wait for reset to complete
> +        //
> +        while (SysCtrl.Fields.RSTA && Retry) {
> +            --Retry;
> +            gBS->Stall(USDHC_POLL_WAIT_US);
> +            SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
> +        }
> +
> +        if (SysCtrl.Fields.RSTA) {
> +            ASSERT(!Retry);
> +            LOG_ERROR("Time-out waiting on RSTA for self-clear");
> +            return EFI_TIMEOUT;
> +        }
> +
> +        //
> +        // Disconnect interrupt signals between SDHC and GIC
> +        //
> +        MmioWrite32((UINTN)&Reg->INT_SIGNAL_EN, 0);
> +
> +        //
> +        // Clear and Enable all interrupts
> +        //
> +        MmioWrite32((UINTN)&Reg->INT_STATUS, (UINT32)~0);
> +        MmioWrite32((UINTN)&Reg->INT_STATUS_EN, (UINT32)~0);
> +
> +        LOG_TRACE("Waiting for CMD and DATA lines");
> +
> +        //
> +        // Wait for CMD and DATA lines to become available
> +        //
> +        EFI_STATUS Status = WaitForCmdAndOrDataLine(SdhcCtx, NULL);
> +        if (Status != EFI_SUCCESS) {
> +            LOG_ERROR("SdhcWaitForCmdAndDataLine() failed. %r", Status);
> +            return Status;
> +        }
> +
> +        //
> +        // Send 80 clock ticks to power-up the card
> +        //
> +        SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
> +        SysCtrl.Fields.INITA = 1;
> +        MmioWrite32((UINTN)&Reg->SYS_CTRL, SysCtrl.AsUint32);
> +        Retry = USDHC_POLL_RETRY_COUNT;
> +
> +        //
> +        // Wait for the 80 clock ticks to complete
> +        //
> +        while (SysCtrl.Fields.INITA && Retry) {
> +            --Retry;
> +            gBS->Stall(USDHC_POLL_WAIT_US);
> +            SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
> +        }
> +
> +        if (SysCtrl.Fields.INITA) {
> +            ASSERT(!Retry);
> +            LOG_ERROR("Time-out waiting on INITA for self-clear");
> +            return EFI_TIMEOUT;
> +        }
> +
> +        LOG_TRACE("Card power-up complete");
> +
> +        //
> +        // Set max data-timout counter value
> +        //
> +        SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
> +        SysCtrl.Fields.DTOCV = 0xF;
> +        MmioWrite32((UINTN)&Reg->SYS_CTRL, SysCtrl.AsUint32);
> +
> +        //
> +        // Reset Mixer Control
> +        //
> +        MmioWrite32((UINTN)&Reg->MIX_CTRL, 0);
> +
> +        USDHC_PROT_CTRL_REG ProtCtrl = { 0 };
> +        ProtCtrl.Fields.EMODE = USDHC_PROT_CTRL_EMODE_LITTLE_ENDIAN;
> +        ProtCtrl.Fields.LCTL = 1;
> +        MmioWrite32((UINTN)&Reg->PROT_CTRL, ProtCtrl.AsUint32);
> +
> +        LOG_TRACE("Reset ALL complete");
> +
> +    }else if (ResetType == SdhcResetTypeCmd) {
> +        LOG_TRACE("SdhcSoftwareReset(CMD)");
> +        //
> +        // Software reset for CMD
> +        //
> +        USDHC_SYS_CTRL_REG SysCtrl; SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
> +        SysCtrl.Fields.RSTC = 1;
> +        MmioWrite32((UINTN)&Reg->SYS_CTRL, SysCtrl.AsUint32);
> +        Retry = USDHC_POLL_RETRY_COUNT;
> +
> +        //
> +        // Wait for reset to complete
> +        //
> +        while (SysCtrl.Fields.RSTC && Retry) {
> +            --Retry;
> +            gBS->Stall(USDHC_POLL_WAIT_US);
> +            SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
> +        }
> +
> +        if (SysCtrl.Fields.RSTC) {
> +            ASSERT(!Retry);
> +            LOG_ERROR("Time-out waiting on RSTC for self-clear");
> +            return EFI_TIMEOUT;
> +        }
> +
> +        MmioWrite32((UINTN)&Reg->INT_STATUS, (UINT32)~0);
> +
> +        LOG_TRACE("Reset CMD complete");
> +
> +    } else if (ResetType == SdhcResetTypeData) {
> +        LOG_TRACE("SdhcSoftwareReset(DAT)");
> +        //
> +        // Software reset for DAT
> +        //
> +        USDHC_SYS_CTRL_REG SysCtrl; SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
> +        SysCtrl.Fields.RSTD = 1;
> +        MmioWrite32((UINTN)&Reg->SYS_CTRL, SysCtrl.AsUint32);
> +        Retry = USDHC_POLL_RETRY_COUNT;
> +
> +        //
> +        // Wait for reset to complete
> +        //
> +        while (SysCtrl.Fields.RSTD && Retry) {
> +            --Retry;
> +            gBS->Stall(USDHC_POLL_WAIT_US);
> +            SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
> +        }
> +
> +        if (SysCtrl.Fields.RSTD) {
> +            ASSERT(!Retry);
> +            LOG_ERROR("Time-out waiting on RSTD for self-clear");
> +            return EFI_TIMEOUT;
> +        }
> +
> +        MmioWrite32((UINTN)&Reg->INT_STATUS, (UINT32)~0);
> +
> +        LOG_TRACE("Reset DAT complete");
> +
> +    } else {
> +        return EFI_INVALID_PARAMETER;
> +    }
> +
> +    return EFI_SUCCESS;
> +}
> +
> +VOID
> +SdhcCleanup(
> +    IN EFI_SDHC_PROTOCOL *This
> +    )
> +{
> +    if (This->PrivateContext != NULL) {
> +        FreePool(This->PrivateContext);
> +        This->PrivateContext = NULL;
> +    }
> +
> +    FreePool(This);
> +
> +    //
> +    // Any SDHC protocol call to this instance is illegal beyond this point
> +    //
> +}
> +
> +VOID
> +SdhcGetCapabilities(
> +    IN EFI_SDHC_PROTOCOL *This,
> +    OUT SDHC_CAPABILITIES *Capabilities
> +  )
> +{
> +    USDHC_PRIVATE_CONTEXT *SdhcCtx = (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
> +    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> +
> +    USDHC_HOST_CTRL_CAP_REG Caps; Caps.AsUint32 = MmioRead32((UINTN)&Reg->HOST_CTRL_CAP);
> +
> +    Capabilities->MaximumBlockSize = (UINT32)(512 << Caps.Fields.MBL);
> +    Capabilities->MaximumBlockCount = 0xFFFF; // UINT16_MAX
> +}
> +
> +
> +EFI_SDHC_PROTOCOL gSdhcProtocolTemplate =

g - is this really supposed to be globally visible to external
modules? Or could this be m for module-level visibility?

It looks like it is only used in this file in fact, so could it be STATIC?

> +{

On previous line?

> +    SDHC_PROTOCOL_INTERFACE_REVISION,   // Revision
> +    0,                                  // DeviceId
> +    NULL,                               // PrivateContext
> +    SdhcGetCapabilities,
> +    SdhcSoftwareReset,
> +    SdhcSetClock,
> +    SdhcSetBusWidth,
> +    SdhcIsCardPresent,
> +    SdhcIsReadOnly,
> +    SdhcSendCommand,
> +    SdhcReceiveResponse,
> +    SdhcReadBlockData,
> +    SdhcWriteBlockData,
> +    SdhcCleanup
> +};
> +
> +EFI_STATUS
> +uSdhcDeviceRegister(
> +    IN EFI_HANDLE ImageHandle,
> +    IN UINT32 SdhcId,
> +    IN VOID* RegistersBase,
> +    IN USDHC_SIGNAL_SOURCE CardDetectSignal,
> +    IN USDHC_SIGNAL_SOURCE WriteProtectSignal
> +    )
> +{
> +    EFI_STATUS Status;
> +    EFI_SDHC_PROTOCOL *SdhcProtocol = NULL;
> +    USDHC_PRIVATE_CONTEXT *SdhcCtx = NULL;
> +
> +    if (ImageHandle == NULL ||
> +        RegistersBase == NULL) {
> +        Status = EFI_INVALID_PARAMETER;
> +        goto Exit;
> +    }
> +
> +    //
> +    // Allocate per-device SDHC protocol and private context storage
> +    //
> +
> +    SdhcProtocol = AllocateCopyPool(sizeof(EFI_SDHC_PROTOCOL), &gSdhcProtocolTemplate);

Some very long lines in this function.
Please break at 80 characters (where readability is not obviously
improved by keeping longer line - such as for keeping output strings
searchable).

> +    if (SdhcProtocol == NULL) {
> +        Status =  EFI_OUT_OF_RESOURCES;
> +        goto Exit;
> +    }
> +    SdhcProtocol->SdhcId = SdhcId;
> +    SdhcProtocol->PrivateContext = AllocateZeroPool(sizeof(USDHC_PRIVATE_CONTEXT));
> +    if (SdhcProtocol->PrivateContext == NULL) {
> +        Status = EFI_OUT_OF_RESOURCES;
> +        goto Exit;
> +    }
> +
> +    SdhcCtx = (USDHC_PRIVATE_CONTEXT*)SdhcProtocol->PrivateContext;
> +    SdhcCtx->SdhcId = SdhcId;
> +    SdhcCtx->RegistersBase = (USDHC_REGISTERS*)RegistersBase;
> +    SdhcCtx->CardDetectSignal = CardDetectSignal;
> +    if (USDHC_IS_GPIO_SIGNAL_SOURCE(SdhcCtx->CardDetectSignal)) {
> +        SdhcCtx->CardDetectGpioPin.IoNumber = PCD_GPIO_PIN_IO_NUMBER((UINT16)CardDetectSignal);
> +        SdhcCtx->CardDetectGpioPin.Bank = PCD_GPIO_PIN_BANK(CardDetectSignal);
> +    }
> +
> +    SdhcCtx->WriteProtectSignal= WriteProtectSignal;
> +    if (USDHC_IS_GPIO_SIGNAL_SOURCE(SdhcCtx->WriteProtectSignal)) {
> +        SdhcCtx->WriteProtectGpioPin.IoNumber = PCD_GPIO_PIN_IO_NUMBER((UINT16)WriteProtectSignal);
> +        SdhcCtx->WriteProtectGpioPin.Bank = PCD_GPIO_PIN_BANK(WriteProtectSignal);
> +    }
> +
> +    LOG_INFO(
> +        "Initializing uSDHC%d @%p GPIO CD?:%d WP?:%d",
> +        SdhcId,
> +        RegistersBase,
> +        (USDHC_IS_GPIO_SIGNAL_SOURCE(SdhcCtx->CardDetectSignal) ? 1 : 0),
> +        (USDHC_IS_GPIO_SIGNAL_SOURCE(SdhcCtx->WriteProtectSignal) ? 1 : 0));
> +
> +    if (USDHC_IS_GPIO_SIGNAL_SOURCE(SdhcCtx->CardDetectSignal)) {
> +      LOG_INFO(
> +          "Using GPIO%d_IO%d for CardDetect",
> +          SdhcCtx->CardDetectGpioPin.Bank,
> +          SdhcCtx->CardDetectGpioPin.IoNumber);
> +    }
> +
> +    if (USDHC_IS_GPIO_SIGNAL_SOURCE(SdhcCtx->WriteProtectSignal)) {
> +      LOG_INFO(
> +          "Using GPIO%d_IO%d for WriteProtect",
> +          SdhcCtx->WriteProtectGpioPin.Bank,
> +          SdhcCtx->WriteProtectGpioPin.IoNumber);
> +    }
> +
> +    Status = gBS->InstallMultipleProtocolInterfaces(
> +                                                &SdhcCtx->SdhcProtocolHandle,
> +                                                &gEfiSdhcProtocolGuid,
> +                                                SdhcProtocol,
> +                                                NULL);
> +    if (EFI_ERROR(Status)) {
> +        LOG_ERROR("InstallMultipleProtocolInterfaces failed. %r", Status);
> +        goto Exit;
> +    }
> +
> +Exit:
> +    if (EFI_ERROR(Status)) {
> +        LOG_ERROR("Failed to register and initialize uSDHC%d", SdhcId);
> +
> +        if (SdhcProtocol != NULL && SdhcProtocol->PrivateContext != NULL) {
> +            FreePool(SdhcProtocol->PrivateContext);
> +            SdhcProtocol->PrivateContext = NULL;
> +        }
> +
> +        if (SdhcProtocol != NULL) {
> +            FreePool(SdhcProtocol);
> +            SdhcProtocol = NULL;
> +        }
> +    }
> +
> +    return Status;
> +}
> +
> +EFI_STATUS
> +SdhcInitialize(
> +    IN EFI_HANDLE ImageHandle,
> +    IN EFI_SYSTEM_TABLE *SystemTable
> +    )
> +{
> +    EFI_STATUS Status = EFI_SUCCESS;
> +    UINT32 uSdhcRegisteredCount = 0;
> +
> +    //
> +    // Register uSDHC1 through uSDHC4 if their base address is non-zero
> +    //

Can this hardwiring be moved out of the driver and into platform init
code using NonDiscoverableDeviceRegistrationLib, as per this
(unrelated) thread from earlier this year:
https://lists.01.org/pipermail/edk2-devel/2018-April/023922.html
?

> +
> +    //
> +    // uSDHC1
> +    //
> +    if (FixedPcdGet32(PcdSdhc1Enable)) {
> +        Status = uSdhcDeviceRegister(
> +            ImageHandle,
> +            1,
> +            (VOID*)FixedPcdGet32(PcdSdhc1Base),
> +            FixedPcdGet32(PcdSdhc1CardDetectSignal),
> +            FixedPcdGet32(PcdSdhc1WriteProtectSignal));
> +        if (!EFI_ERROR(Status)) {
> +            ++uSdhcRegisteredCount;
> +        }
> +    }
> +
> +    //
> +    // uSDHC2
> +    //
> +    if (FixedPcdGet32(PcdSdhc2Enable)) {
> +        Status = uSdhcDeviceRegister(
> +            ImageHandle,
> +            2,
> +            (VOID*)FixedPcdGet32(PcdSdhc2Base),
> +            FixedPcdGet32(PcdSdhc2CardDetectSignal),
> +            FixedPcdGet32(PcdSdhc2WriteProtectSignal));
> +        if (!EFI_ERROR(Status)) {
> +            ++uSdhcRegisteredCount;
> +        }
> +    }
> +
> +    //
> +    // uSDHC3
> +    //
> +    if (FixedPcdGet32(PcdSdhc3Enable)) {
> +        Status = uSdhcDeviceRegister(
> +            ImageHandle,
> +            3,
> +            (VOID*)FixedPcdGet32(PcdSdhc3Base),
> +            FixedPcdGet32(PcdSdhc3CardDetectSignal),
> +            FixedPcdGet32(PcdSdhc3WriteProtectSignal));
> +        if (!EFI_ERROR(Status)) {
> +            ++uSdhcRegisteredCount;
> +        }
> +    }
> +
> +    //
> +    // uSDHC4
> +    //
> +    if (FixedPcdGet32(PcdSdhc4Enable)) {
> +        Status = uSdhcDeviceRegister(
> +            ImageHandle,
> +            4,
> +            (VOID*)FixedPcdGet32(PcdSdhc4Base),
> +            FixedPcdGet32(PcdSdhc4CardDetectSignal),
> +            FixedPcdGet32(PcdSdhc4WriteProtectSignal));
> +        if (!EFI_ERROR(Status)) {
> +            ++uSdhcRegisteredCount;
> +        }
> +    }
> +
> +    //
> +    // Succeed driver loading if at least one enabled uSDHC got registered successfully
> +    //
> +    if ((Status != EFI_SUCCESS) && (uSdhcRegisteredCount > 0)) {
> +        Status = EFI_SUCCESS;
> +    }
> +
> +    return Status;
> +}
> diff --git a/Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.inf b/Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.inf
> new file mode 100644
> index 000000000000..5aee8b2ffbde
> --- /dev/null
> +++ b/Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.inf
> @@ -0,0 +1,67 @@
> +## @file
> +#
> +#  Copyright (c) Microsoft Corporation. All rights reserved.
> +#
> +#  This program and the accompanying materials
> +#  are licensed and made available under the terms and conditions of the BSD License
> +#  which accompanies this distribution.  The full text of the license may be found at
> +#  http://opensource.org/licenses/bsd-license.php
> +#
> +#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005

0x0001001a

> +  BASE_NAME                      = SdhcDxe
> +  FILE_GUID                      = A9945BAB-78C9-43C9-9175-F576CA189870
> +  MODULE_TYPE                    = DXE_DRIVER
> +  VERSION_STRING                 = 1.0
> +  ENTRY_POINT                    = SdhcInitialize
> +
> +[Sources.common]
> +  SdhcDxe.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  EmbeddedPkg/EmbeddedPkg.dec
> +  Silicon/NXP/iMXPlatformPkg/iMXPlatformPkg.dec
> +  Platform/Microsoft/MsPkg.dec

Sorted alphabetically, please.

> +
> +[LibraryClasses]
> +  PcdLib
> +  UefiLib
> +  UefiDriverEntryPoint
> +  MemoryAllocationLib
> +  IoLib
> +  iMXIoMuxLib

Sorted alphabetically, please.

> +
> +[Guids]
> +
> +[Protocols]
> +  gEfiSdhcProtocolGuid
> +
> +[Pcd]
> +  giMXPlatformTokenSpaceGuid.PcdSdhc1Base
> +  giMXPlatformTokenSpaceGuid.PcdSdhc2Base
> +  giMXPlatformTokenSpaceGuid.PcdSdhc3Base
> +  giMXPlatformTokenSpaceGuid.PcdSdhc4Base
> +  giMXPlatformTokenSpaceGuid.PcdSdhc1Enable
> +  giMXPlatformTokenSpaceGuid.PcdSdhc2Enable
> +  giMXPlatformTokenSpaceGuid.PcdSdhc3Enable
> +  giMXPlatformTokenSpaceGuid.PcdSdhc4Enable
> +  giMXPlatformTokenSpaceGuid.PcdSdhc1CardDetectSignal
> +  giMXPlatformTokenSpaceGuid.PcdSdhc1WriteProtectSignal
> +  giMXPlatformTokenSpaceGuid.PcdSdhc2CardDetectSignal
> +  giMXPlatformTokenSpaceGuid.PcdSdhc2WriteProtectSignal
> +  giMXPlatformTokenSpaceGuid.PcdSdhc3CardDetectSignal
> +  giMXPlatformTokenSpaceGuid.PcdSdhc3WriteProtectSignal
> +  giMXPlatformTokenSpaceGuid.PcdSdhc4CardDetectSignal
> +  giMXPlatformTokenSpaceGuid.PcdSdhc4WriteProtectSignal
> +
> +[FixedPcd]
> +  giMXPlatformTokenSpaceGuid.PcdGpioBankMemoryRange
> +
> +[depex]
> +  TRUE
> diff --git a/Silicon/NXP/iMXPlatformPkg/Include/iMXGpio.h b/Silicon/NXP/iMXPlatformPkg/Include/iMXGpio.h
> new file mode 100644
> index 000000000000..c75b543c8bb4
> --- /dev/null
> +++ b/Silicon/NXP/iMXPlatformPkg/Include/iMXGpio.h
> @@ -0,0 +1,101 @@
> +/** @file
> +*
> +*  Copyright (c) Microsoft Corporation. All rights reserved.
> +*
> +*  This program and the accompanying materials
> +*  are licensed and made available under the terms and conditions of the BSD License
> +*  which accompanies this distribution.  The full text of the license may be found at
> +*  http://opensource.org/licenses/bsd-license.php
> +*
> +*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +*
> +**/
> +
> +#ifndef _IMX_GPIO_H_
> +#define _IMX_GPIO_H_
> +
> +#include <Library/PcdLib.h>
> +
> +#ifndef C_ASSERT
> +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
> +#endif // C_ASSERT

What's wrong with normal ASSERT?

> +
> +typedef enum {
> +    IMX_GPIO_LOW = 0,
> +    IMX_GPIO_HIGH = 1
> +} IMX_GPIO_VALUE;
> +
> +typedef enum {
> +    IMX_GPIO_DIR_INPUT,
> +    IMX_GPIO_DIR_OUTPUT
> +} IMX_GPIO_DIR;
> +
> +typedef enum {
> +    IMX_GPIO_BANK1 = 1,
> +    IMX_GPIO_BANK2,
> +    IMX_GPIO_BANK3,
> +    IMX_GPIO_BANK4,
> +    IMX_GPIO_BANK5,
> +    IMX_GPIO_BANK6,
> +    IMX_GPIO_BANK7,
> +} IMX_GPIO_BANK;
> +
> +#pragma pack(push, 1)
> +
> +//
> +// GPIO reserved size is based on total size minus 8 DWORD of standard GPIO reg
> +//
> +C_ASSERT((FixedPcdGet32(PcdGpioBankMemoryRange) % 4) == 0);
> +
> +#define GPIO_RESERVED_SIZE \
> +    ((FixedPcdGet32(PcdGpioBankMemoryRange) / 4) - 8)
> +
> +typedef struct {
> +    UINT32 DR;                            // 0x00 GPIO data register (GPIO1_DR)
> +    UINT32 GDIR;                          // 0x04 GPIO direction register (GPIO1_GDIR)
> +    UINT32 PSR;                           // 0x08 GPIO pad status register (GPIO1_PSR)
> +    UINT32 ICR1;                          // 0x0C GPIO interrupt configuration register1 (GPIO1_ICR1)
> +    UINT32 ICR2;                          // 0x10 GPIO interrupt configuration register2 (GPIO1_ICR2)
> +    UINT32 IMR;                           // 0x14 GPIO interrupt mask register (GPIO1_IMR)
> +    UINT32 ISR;                           // 0x18 GPIO interrupt status register (GPIO1_ISR)
> +    UINT32 EDGE_SEL;                      // 0x1C GPIO edge select register (GPIO1_EDGE_SEL)
> +    UINT32 reserved[GPIO_RESERVED_SIZE];
> +} IMX_GPIO_BANK_REGISTERS;
> +
> +#pragma pack(pop)
> +
> +typedef struct {
> +    IMX_GPIO_BANK_REGISTERS Banks[7];
> +} IMX_GPIO_REGISTERS;
> +
> +/**
> +    Set the specified GPIO to the specified direction.
> +**/
> +VOID
> +ImxGpioDirection (
> +    IMX_GPIO_BANK Bank,
> +    UINT32 IoNumber,
> +    IMX_GPIO_DIR Direction
> +    );
> +
> +/**
> +    Write a value to a GPIO pin.
> +**/
> +VOID
> +ImxGpioWrite (
> +    IMX_GPIO_BANK Bank,
> +    UINT32 IoNumber,
> +    IMX_GPIO_VALUE Value
> +    );
> +
> +/**
> +    Read a GPIO pin input value.
> +**/
> +IMX_GPIO_VALUE
> +ImxGpioRead (
> +    IMX_GPIO_BANK Bank,
> +    UINT32 IoNumber
> +    );
> +
> +#endif
> diff --git a/Silicon/NXP/iMXPlatformPkg/Include/iMXuSdhc.h b/Silicon/NXP/iMXPlatformPkg/Include/iMXuSdhc.h
> new file mode 100644
> index 000000000000..acdbcd324631
> --- /dev/null
> +++ b/Silicon/NXP/iMXPlatformPkg/Include/iMXuSdhc.h
> @@ -0,0 +1,277 @@
> +/** @file
> +*
> +*  Copyright (c) Microsoft Corporation. All rights reserved.
> +*
> +*  This program and the accompanying materials
> +*  are licensed and made available under the terms and conditions of the BSD License
> +*  which accompanies this distribution.  The full text of the license may be found at
> +*  http://opensource.org/licenses/bsd-license.php
> +*
> +*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +*
> +**/
> +
> +#ifndef __IMX_USDHC_H__
> +#define __IMX_USDHC_H__
> +
> +//
> +// uSDHCx Registers Layout
> +//
> +typedef struct {
> +    UINT32 DS_ADDR;
> +    UINT32 BLK_ATT;
> +    UINT32 CMD_ARG;
> +    UINT32 CMD_XFR_TYP;
> +    UINT32 CMD_RSP0;
> +    UINT32 CMD_RSP1;
> +    UINT32 CMD_RSP2;
> +    UINT32 CMD_RSP3;
> +    UINT32 DATA_BUFF_ACC_PORT;
> +    UINT32 PRES_STATE;
> +    UINT32 PROT_CTRL;
> +    UINT32 SYS_CTRL;
> +    UINT32 INT_STATUS;
> +    UINT32 INT_STATUS_EN;
> +    UINT32 INT_SIGNAL_EN;
> +    UINT32 AUTOCMD12_ERR_STATUS;
> +    UINT32 HOST_CTRL_CAP;
> +    UINT32 WTMK_LVL;
> +    UINT32 MIX_CTRL;
> +    UINT32 _pad0;
> +    UINT32 FORCE_EVENT;
> +    UINT32 ADMA_ERR_STATUS;
> +    UINT32 ADMA_SYS_ADDR;
> +    UINT32 _pad1;
> +    UINT32 DLL_CTRL;
> +    UINT32 DLL_STATUS;
> +    UINT32 CLK_TUNE_CTRL_STATUS;
> +    UINT32 _pad2[21];
> +    UINT32 VEND_SPEC;
> +    UINT32 MMC_BOOT;
> +    UINT32 VEND_SPEC2;
> +} USDHC_REGISTERS;
> +
> +//
> +// Block Attributes uSDHCx_BLK_ATT fields
> +//
> +typedef union {
> +   UINT32 AsUint32;
> +   struct {
> +      UINT32 BLKSIZE    : 13; // 0:12
> +      UINT32 _reserved0 : 3;  // 13:15
> +      UINT32 BLKCNT     : 16; // 16:31
> +   } Fields;
> +} USDHC_BLK_ATT_REG;
> +
> +//
> +// Command Transfer Type uSDHCx_CMD_XFR_TYP fields
> +//
> +typedef union {
> +    UINT32 AsUint32;
> +    struct {
> +        UINT32 _reserved0   : 16; // 0:15
> +        UINT32 RSPTYP       : 2; // 16:17
> +        UINT32 _reserved1   : 1; // 18
> +        UINT32 CCCEN        : 1; // 19
> +        UINT32 CICEN        : 1; // 20
> +        UINT32 DPSEL        : 1; // 21
> +        UINT32 CMDTYP       : 2; // 22:23
> +        UINT32 CMDINX       : 6; // 24:29
> +        UINT32 _reserved2   : 2; // 30:31
> +    } Fields;
> +} USDHC_CMD_XFR_TYP_REG;
> +
> +#define USDHC_CMD_XFR_TYP_RSPTYP_NO_RSP          0
> +#define USDHC_CMD_XFR_TYP_RSPTYP_RSP_136         1
> +#define USDHC_CMD_XFR_TYP_RSPTYP_RSP_48          2
> +#define USDHC_CMD_XFR_TYP_RSPTYP_RSP_48_CHK_BSY  3
> +#define USDHC_CMD_XFR_TYP_CMDTYP_ABORT           3
> +
> +//
> +// System Control uSDHCx_SYS_CTRL fields
> +//
> +typedef union {
> +    UINT32 AsUint32;
> +    struct {
> +        UINT32 _reserved0   : 4; // 0:3
> +        UINT32 DVS          : 4; // 4:7
> +        UINT32 SDCLKFS      : 8; // 8:15
> +        UINT32 DTOCV        : 4; // 16:19
> +        UINT32 _reserved1   : 3; // 20:22
> +        UINT32 IPP_RST_N    : 1; // 23
> +        UINT32 RSTA         : 1; // 24
> +        UINT32 RSTC         : 1; // 25
> +        UINT32 RSTD         : 1; // 26
> +        UINT32 INITA        : 1; // 27
> +        UINT32 _reserved2   : 4; // 28-31
> +    } Fields;
> +} USDHC_SYS_CTRL_REG;
> +
> +//
> +// Host Controller Capabilities Register uSDHCx_HOST_CTRL_CAP fields
> +//
> +typedef union {
> +    UINT32 AsUint32;
> +    struct {
> +        UINT32 _reserved0       : 16; // 0:15
> +        UINT32 MBL              : 3; // 16:18
> +        UINT32 _reserved1       : 1; // 19
> +        UINT32 ADMAS            : 1; // 20
> +        UINT32 HSS              : 1; // 21
> +        UINT32 DMAS             : 1; // 22
> +        UINT32 SRS              : 1; // 23
> +        UINT32 VS33             : 1; // 24
> +        UINT32 VS30             : 1; // 25
> +        UINT32 VS18             : 1; // 26
> +        UINT32 _reserved2       : 5; // 27:31
> +    } Fields;
> +} USDHC_HOST_CTRL_CAP_REG;
> +
> +//
> +// Watermark Level uSDHCx_WTMK_LVL
> +//
> +typedef union {
> +    UINT32 AsUint32;
> +    struct {
> +        UINT32 RD_WML           : 8; // 0:7
> +        UINT32 RD_BRST_LEN      : 5; // 8:12
> +        UINT32 _reserved0       : 3; // 13:15
> +        UINT32 WR_WML           : 8; // 16:23
> +        UINT32 WR_BRST_LEN      : 5; // 24:28
> +        UINT32 _reserved1       : 3; // 29:31
> +    } Fields;
> +} USDHC_WTMK_LVL_REG;
> +
> +#define USDHC_WTMK_RD_WML_MAX_VAL   0x10
> +#define USDHC_WTMK_WR_WML_MAX_VAL   0x80
> +
> +//
> +// Mixer Control uSDHCx_MIX_CTRL fields
> +//
> +typedef union {
> +    UINT32 AsUint32;
> +    struct {
> +        UINT32 DMAEN          : 1; // 0
> +        UINT32 BCEN           : 1; // 1
> +        UINT32 AC12EN         : 1; // 2
> +        UINT32 DDR_EN         : 1; // 3
> +        UINT32 DTDSEL         : 1; // 4
> +        UINT32 MSBSEL         : 1; // 5
> +        UINT32 NIBBLE_POS     : 1; // 6
> +        UINT32 AC23EN         : 1; // 7
> +        UINT32 _reserved0     : 14; // 8:21
> +        UINT32 EXE_TUNE       : 1; // 22
> +        UINT32 SMP_CLK_SEL    : 1; // 23
> +        UINT32 AUTO_TUNE_EN   : 1; //24
> +        UINT32 FBCLK_SEL      : 1; // 25
> +        UINT32 _reserved1     : 6; // 26-31
> +    } Fields;
> +} USDHC_MIX_CTRL_REG;
> +
> +//
> +// Present State uSDHCx_PRES_STATE fields
> +//
> +typedef union {
> +    UINT32 AsUint32;
> +    struct {
> +        UINT32 CIHB         : 1; // 0
> +        UINT32 CDIHB        : 1; // 1
> +        UINT32 DLA          : 1; // 2
> +        UINT32 SDSTB        : 1; // 3
> +        UINT32 IPGOFF       : 1; // 4
> +        UINT32 HCKOFF       : 1; // 5
> +        UINT32 PEROFF       : 1; // 6
> +        UINT32 SDOFF        : 1; // 7
> +        UINT32 WTA          : 1; // 8
> +        UINT32 RTA          : 1; // 9
> +        UINT32 BWEN         : 1; // 10
> +        UINT32 BREN         : 1; // 11
> +        UINT32 PTR          : 1; // 12
> +        UINT32 _reserved0   : 3; // 13:15
> +        UINT32 CINST        : 1; // 16
> +        UINT32 _reserved1   : 1; // 17
> +        UINT32 CDPL         : 1; // 18
> +        UINT32 WPSPL        : 1; // 19
> +        UINT32 _reserved2   : 3; // 20:22
> +        UINT32 CLSL         : 1; // 23
> +        UINT32 DLSL         : 8; // 24:31
> +    } Fields;
> +} USDHC_PRES_STATE_REG;
> +
> +//
> +// Present State uSDHCx_PROT_CTRL fields
> +//
> +typedef union {
> +    UINT32 AsUint32;
> +    struct {
> +        UINT32 LCTL             : 1; // 0
> +        UINT32 DTW              : 2; // 1:2
> +        UINT32 D3CD             : 1; // 3
> +        UINT32 EMODE            : 2; // 4:5
> +        UINT32 CDTL             : 1; // 6
> +        UINT32 CDSS             : 1; // 7
> +        UINT32 DMASEL           : 2; // 8:9
> +        UINT32 _reserved0       : 6; // 10:15
> +        UINT32 SABGREQ          : 1; // 16
> +        UINT32 CREQ             : 1; // 17
> +        UINT32 RWCTL            : 1; // 18
> +        UINT32 IABG             : 1; // 19
> +        UINT32 RD_DONE_NO_8CLK  : 1; // 20
> +        UINT32 _reserved1       : 3; // 21:23
> +        UINT32 WECINT           : 1; // 24
> +        UINT32 WECINS           : 1; // 25
> +        UINT32 WECRM            : 1; // 26
> +        UINT32 BURST_LEN_EN     : 3; // 27:29
> +        UINT32 NON_EXACT_BLK_RD : 1; // 30
> +        UINT32 _reserved2       : 1; // 31
> +    } Fields;
> +} USDHC_PROT_CTRL_REG;
> +
> +#define USDHC_PROT_CTRL_DTW_1BIT             0x0
> +#define USDHC_PROT_CTRL_DTW_4BIT             0x1
> +#define USDHC_PROT_CTRL_DTW_8BIT             0x2
> +#define USDHC_PROT_CTRL_EMODE_LITTLE_ENDIAN  0x2
> +
> +//
> +// Interrupt Status uSDHCx_INT_STATUS fields
> +//
> +typedef union {
> +    UINT32 AsUint32;
> +    struct {
> +        UINT32 CC           : 1; // 0
> +        UINT32 TC           : 1; // 1
> +        UINT32 BGE          : 1; // 2
> +        UINT32 DINT         : 1; // 3
> +        UINT32 BWR          : 1; // 4
> +        UINT32 BRR          : 1; // 5
> +        UINT32 CINS         : 1; // 6
> +        UINT32 CRM          : 1; // 7
> +        UINT32 CINT         : 1; // 8
> +        UINT32 _reserved0   : 3; // 9:11
> +        UINT32 RTE          : 1; // 12
> +        UINT32 _reserved1   : 1; // 13
> +        UINT32 TP           : 1; // 14
> +        UINT32 _reserved2   : 1; // 15
> +        UINT32 CTOE         : 1; // 16
> +        UINT32 CCE          : 1; // 17
> +        UINT32 CEBE         : 1; // 18
> +        UINT32 CIE          : 1; // 19
> +        UINT32 DTOE         : 1; // 20
> +        UINT32 DCE          : 1; // 21
> +        UINT32 DEBE         : 1; // 22
> +        UINT32 _reserved3   : 1; // 23
> +        UINT32 AC12E        : 1; // 24
> +        UINT32 _reserved4   : 1; // 25
> +        UINT32 TNE          : 1; // 26
> +        UINT32 _reserved5   : 1; // 27
> +        UINT32 DMAE         : 1; // 28
> +        UINT32 _reserved6   : 3; // 29:31
> +    } Fields;
> +} USDHC_INT_STATUS_REG;
> +
> +#define USDHC_INT_STATUS_CMD_ERROR   (BIT16 | BIT17 | BIT18 | BIT19)
> +#define USDHC_INT_STATUS_DATA_ERROR  (BIT20 | BIT21 | BIT22)
> +#define USDHC_INT_STATUS_ERROR       (USDHC_INT_STATUS_CMD_ERROR | USDHC_INT_STATUS_DATA_ERROR)
> +
> +#endif // __IMX_USDHC_H__
> -- 
> 2.16.2.gvfs.1.33.gf5370f1
> 


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH edk2-platforms 1/7] Silicon/NXP: Add support for iMX SDHC
  2018-08-01 16:15   ` Leif Lindholm
@ 2018-08-01 23:59     ` Chris Co
  0 siblings, 0 replies; 10+ messages in thread
From: Chris Co @ 2018-08-01 23:59 UTC (permalink / raw)
  To: Leif Lindholm; +Cc: edk2-devel@lists.01.org, Ard Biesheuvel, Michael D Kinney

Hi Leif,

Thank you for the initial feedback.  I will address the items on all the patches and resubmit as one set.

Chris

> -----Original Message-----
> From: Leif Lindholm <leif.lindholm@linaro.org>
> Sent: Wednesday, August 1, 2018 9:15 AM
> To: Chris Co <Christopher.Co@microsoft.com>
> Cc: edk2-devel@lists.01.org; Ard Biesheuvel <ard.biesheuvel@linaro.org>;
> Michael D Kinney <michael.d.kinney@intel.com>
> Subject: Re: [PATCH edk2-platforms 1/7] Silicon/NXP: Add support for iMX
> SDHC
> 
> On Thu, Jul 19, 2018 at 04:11:18AM +0000, Chris Co wrote:
> > This adds support for using the SD host controller on
> > NXP i.MX platforms.
> >
> > Contributed-under: TianoCore Contribution Agreement 1.1
> > Signed-off-by: Christopher Co <christopher.co@microsoft.com>
> > Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> > Cc: Leif Lindholm <leif.lindholm@linaro.org>
> > Cc: Michael D Kinney <michael.d.kinney@intel.com>
> 
> Trying to build the code[1] in this patch throws up issues due to
> (initially) a missing dependency on a iMXIoMuxLib mapping. Which is
> not introduced in this set at all.
> 
> Could you bring these sets together into a single (huge) one,
> ensuring that code is introduced in dependency order?
> 
> It will be no more unwieldy (I can push patches from the front as they
> merit it), and will make my life a _lot_ easier.
> 
> If you can also address the items I point out as "address throughout"
> below, for all the patches, that will reduce churn.
> 
> [1] By hacking the .inf into EmbeddedPkg/EmbeddedPkg.dsc, since the
>     i.MX one is also not included in this set.
> 
> > ---
> >  Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.c   | 1356
> ++++++++++++++++++++
> >  Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.inf |   67 +
> >  Silicon/NXP/iMXPlatformPkg/Include/iMXGpio.h           |  101 ++
> >  Silicon/NXP/iMXPlatformPkg/Include/iMXuSdhc.h          |  277 ++++
> >  4 files changed, 1801 insertions(+)
> >
> > diff --git a/Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.c
> b/Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.c
> > new file mode 100644
> > index 000000000000..5f087f8a28b9
> > --- /dev/null
> > +++ b/Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.c
> > @@ -0,0 +1,1356 @@
> > +/** @file
> > +*
> > +*  Copyright (c) Microsoft Corporation. All rights reserved.
> 
> Please add copyright year throughout all patches.
> 
> > +*
> > +*  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
> > +*
> https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fopenso
> urce.org%2Flicenses%2Fbsd-
> license.php&amp;data=02%7C01%7CChristopher.Co%40microsoft.com%7Cc0
> f078beab2c4534017c08d5f7c9f5f5%7C72f988bf86f141af91ab2d7cd011db47%7
> C1%7C0%7C636687369157661520&amp;sdata=noPZDlLAGlOgwhpiKbfxZk%2B
> OPT6KNdeBtEi8VELsugQ%3D&amp;reserved=0
> > +*
> > +*  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 <Uefi.h>
> > +#include <Library/BaseLib.h>
> > +#include <Library/MemoryAllocationLib.h>
> > +#include <Library/DebugLib.h>
> > +#include <Library/DevicePathLib.h>
> > +#include <Library/IoLib.h>
> > +#include <Library/PcdLib.h>
> > +#include <Library/UefiBootServicesTableLib.h>
> > +#include <Library/BaseMemoryLib.h>
> > +#include <Library/DmaLib.h>
> > +#include <Library/TimerLib.h>
> > +
> > +#include <Protocol/EmbeddedExternalDevice.h>
> > +#include <Protocol/BlockIo.h>
> > +#include <Protocol/DevicePath.h>
> > +#include <Protocol/Sdhc.h>
> 
> Please sort includes alphabetically.
> 
> > +
> > +#include <iMXuSdhc.h>
> > +#include <iMXGpio.h>
> > +
> > +typedef struct {
> > +    UINT32 IoNumber;
> > +    IMX_GPIO_BANK Bank;
> > +} IMX_GPIO_PIN;
> > +
> > +#define PCD_GPIO_PIN_IO_NUMBER(X)   ((X) & 0xFF)
> > +#define PCD_GPIO_PIN_BANK(X)        (((X) >> 8) & 0xFF)
> > +
> > +//
> > +// A special value to indicate that GPIO is not the signal source for either
> > +// CardDetect or WriteProtect
> > +//
> > +typedef enum {
> > +    USDHC_SIGNAL_GPIO_START = 0x000,
> > +    USDHC_SIGNAL_GPIO_END = 0xFF00,
> > +    USDHC_SIGNAL_OVERRIDE_PIN_LOW = 0xFF00,
> 
> Are the above two lines intentionally assigning the same value?
> 
> > +    USDHC_SIGNAL_OVERRIDE_PIN_HIGH = 0xFF01,
> > +    USDHC_SIGNAL_INTERNAL_PIN = 0xFFFF
> > +} USDHC_SIGNAL_SOURCE;
> > +
> > +#define USDHC_IS_GPIO_SIGNAL_SOURCE(X)  \
> > +    (((X) >= USDHC_SIGNAL_GPIO_START) && ((X) <
> USDHC_SIGNAL_GPIO_END))
> > +
> > +typedef struct {
> > +    UINT32 SdhcId;
> > +    EFI_HANDLE SdhcProtocolHandle;
> > +    USDHC_REGISTERS *RegistersBase;
> > +    USDHC_SIGNAL_SOURCE CardDetectSignal;
> > +    USDHC_SIGNAL_SOURCE WriteProtectSignal;
> > +    IMX_GPIO_PIN CardDetectGpioPin;
> > +    IMX_GPIO_PIN WriteProtectGpioPin;
> > +} USDHC_PRIVATE_CONTEXT;
> > +
> > +#define LOG_FMT_HELPER(FMT, ...) \
> > +    "SDHC%d:" FMT "%a\n", ((SdhcCtx != NULL) ? SdhcCtx->SdhcId : -1),
> __VA_ARGS__
> > +
> > +#define LOG_INFO(...) \
> > +    DEBUG((DEBUG_INFO | DEBUG_BLKIO,
> LOG_FMT_HELPER(__VA_ARGS__, "")))
> > +
> > +#define LOG_TRACE(...) \
> > +    DEBUG((DEBUG_VERBOSE | DEBUG_BLKIO,
> LOG_FMT_HELPER(__VA_ARGS__, "")))
> > +
> > +#define LOG_ERROR(...) \
> > +    DEBUG((DEBUG_ERROR | DEBUG_BLKIO,
> LOG_FMT_HELPER(__VA_ARGS__, "")))
> > +
> > +#define LOG_ASSERT(TXT) \
> > +    ASSERT(!"Sdhc: " TXT "\n")
> > +
> > +#ifdef MIN
> > +#undef MIN
> > +#define MIN(x,y) ((x) > (y) ? (y) : (x))
> > +#endif // MIN
> 
> Please remove - the MIN macro has existed in Base.h since at least
> 2007. It does not need local redefinition.
> 
> > +
> > +//
> > +// uSDHC read/write FIFO is 128x32-bit
> > +//
> > +#define USDHC_FIFO_MAX_WORD_COUNT       128
> > +
> > +//
> > +// Max block count allowed in a single transfer
> > +//
> > +#define USDHC_MAX_BLOCK_COUNT           0xFFFF
> > +
> > +//
> > +// Number of register maximum polls
> > +//
> > +#define USDHC_POLL_RETRY_COUNT          100000
> > +
> > +//
> > +// Waits between each registry poll
> > +//
> > +#define USDHC_POLL_WAIT_US              20
> > +
> > +//
> > +// uSDHC input clock. Ideally, should query it from clock manager
> > +//
> > +#define USDHC_BASE_CLOCK_FREQ_HZ        198000000
> > +
> > +#define USDHC_BLOCK_LENGTH_BYTES               512
> > +
> 
> Can all of the above #defines, enums and structs be moved to a local
> "SdhcDxe.h"?
> 
> > +VOID
> > +DumpState(
> > +    IN USDHC_PRIVATE_CONTEXT *SdhcCtx
> > +    )
> 
> Base indentation is always 2 spaces. (applies throughout)
> 
> > +{
> > +DEBUG_CODE_BEGIN ();
> > +
> > +    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> > +
> > +    USDHC_BLK_ATT_REG BlkAtt; BlkAtt.AsUint32 =
> MmioRead32((UINTN)&Reg->BLK_ATT);
> 
> Please never put multiple statements on same line. (applies throughout)
> 
> Space between function name and opening parentheses (applies
> throughout).
> 
> > +    UINT32 CmdArg; CmdArg = MmioRead32((UINTN)&Reg->CMD_ARG);
> > +    USDHC_CMD_XFR_TYP_REG CmdXfrTyp; CmdXfrTyp.AsUint32 =
> MmioRead32((UINTN)&Reg->CMD_XFR_TYP);
> > +    USDHC_PROT_CTRL_REG ProtCtrl; ProtCtrl.AsUint32 =
> MmioRead32((UINTN)&Reg->PROT_CTRL);
> > +    USDHC_WTMK_LVL_REG WtmkLvl; WtmkLvl.AsUint32 =
> MmioRead32((UINTN)&Reg->WTMK_LVL);
> > +    USDHC_MIX_CTRL_REG MixCtrl; MixCtrl.AsUint32 =
> MmioRead32((UINTN)&Reg->MIX_CTRL);
> > +    UINT32 IntStatusEn = MmioRead32((UINTN)&Reg->INT_STATUS_EN);
> > +    UINT32 IntSignalEn = MmioRead32((UINTN)&Reg->INT_SIGNAL_EN);
> > +    UINT32 VendSpec = MmioRead32((UINTN)&Reg->VEND_SPEC);
> > +    UINT32 MmcBoot = MmioRead32((UINTN)&Reg->MMC_BOOT);
> > +    UINT32 VendSpec2 = MmioRead32((UINTN)&Reg->VEND_SPEC2);
> > +    USDHC_INT_STATUS_REG IntStatus; IntStatus.AsUint32 =
> MmioRead32((UINTN)&Reg->INT_STATUS);
> > +    USDHC_PRES_STATE_REG PresState; PresState.AsUint32 =
> MmioRead32((UINTN)&Reg->PRES_STATE);
> > +
> > +    LOG_INFO(
> > +        " - BLK_ATT\t:0x%08x BLKSIZE:0x%x BLKCNT:0x%08x",
> > +        BlkAtt.AsUint32,
> > +        BlkAtt.Fields.BLKSIZE,
> > +        BlkAtt.Fields.BLKCNT);
> > +
> > +    LOG_INFO(" - CMD_ARG\t:0x%08x", CmdArg);
> > +
> > +    LOG_INFO(
> > +        " - CMD_XFR_TYP\t:0x%08x RSPTYP:%d CCCEN:%d CICEN:%d
> DPSEL:%d CMDTYP:%d CMDINX:%d",
> > +        CmdXfrTyp.AsUint32,
> > +        CmdXfrTyp.Fields.RSPTYP,
> > +        CmdXfrTyp.Fields.CCCEN,
> > +        CmdXfrTyp.Fields.CICEN,
> > +        CmdXfrTyp.Fields.DPSEL,
> > +        CmdXfrTyp.Fields.CMDTYP,
> > +        CmdXfrTyp.Fields.CMDINX);
> > +
> > +    LOG_INFO(
> > +        " - PROT_CTRL\t:0x%08x DTW:%d D3CD:%d CDSS:%d EMODE:%d
> DMASEL:%d SABGREQ:%d BURST_LEN_EN:%d",
> > +        ProtCtrl.AsUint32,
> > +        ProtCtrl.Fields.DTW,
> > +        ProtCtrl.Fields.D3CD,
> > +        ProtCtrl.Fields.CDSS,
> > +        ProtCtrl.Fields.EMODE,
> > +        ProtCtrl.Fields.DMASEL,
> > +        ProtCtrl.Fields.SABGREQ,
> > +        ProtCtrl.Fields.BURST_LEN_EN);
> > +
> > +    LOG_INFO(
> > +        " - WTMK_LVL\t:0x%08x RD_WML:%d RD_BRST_LEN:%d
> WR_WML:%d WR_BRST_LEN:%d",
> > +        WtmkLvl.AsUint32,
> > +        WtmkLvl.Fields.RD_WML,
> > +        WtmkLvl.Fields.RD_BRST_LEN,
> > +        WtmkLvl.Fields.WR_WML,
> > +        WtmkLvl.Fields.WR_BRST_LEN);
> > +
> > +    LOG_INFO(
> > +        " - MIX_CTRL\t:0x%08x DMAEN:%d BCEN:%d AC12EN:%d DTDSEL:%d
> MSBSEL:%d AC23EN:%d FBCLK_SEL:%d",
> > +        MixCtrl.AsUint32,
> > +        MixCtrl.Fields.DMAEN,
> > +        MixCtrl.Fields.BCEN,
> > +        MixCtrl.Fields.AC12EN,
> > +        MixCtrl.Fields.DTDSEL,
> > +        MixCtrl.Fields.MSBSEL,
> > +        MixCtrl.Fields.AC23EN,
> > +        MixCtrl.Fields.FBCLK_SEL);
> > +
> > +    LOG_INFO(" - INT_STATUS_EN\t:0x%08x", IntStatusEn);
> > +    LOG_INFO(" - INT_SIGNAL_EN\t:0x%08x", IntSignalEn);
> > +    LOG_INFO(" - VEND_SPEC\t:0x%08x", VendSpec);
> > +    LOG_INFO(" - MMC_BOOT\t:0x%08x", MmcBoot);
> > +    LOG_INFO(" - VEND_SPEC2\t:0x%08x", VendSpec2);
> > +
> > +    LOG_INFO(
> > +        " - INT_STATUS\t:0x%08x CC:%d TC:%d BWR:%d BRR:%d CTOE:%d
> CCE:%d CEBE:%d CIE:%d DTOE:%d DCE:%d DEBE:%d",
> > +        IntStatus.AsUint32,
> > +        IntStatus.Fields.CC,
> > +        IntStatus.Fields.TC,
> > +        IntStatus.Fields.BWR,
> > +        IntStatus.Fields.BRR,
> > +        IntStatus.Fields.CTOE,
> > +        IntStatus.Fields.CCE,
> > +        IntStatus.Fields.CEBE,
> > +        IntStatus.Fields.CIE,
> > +        IntStatus.Fields.DTOE,
> > +        IntStatus.Fields.DCE,
> > +        IntStatus.Fields.DEBE);
> > +
> > +    LOG_INFO(
> > +        " - PRES_STATE\t:0x%08x CIHB:%d CDIHB:%d DLA:%d WTA:%d RTA:%d
> BWEN:%d BREN:%d CINST:%d DLSL:0x%x",
> > +        PresState.AsUint32,
> > +        PresState.Fields.CIHB,
> > +        PresState.Fields.CDIHB,
> > +        PresState.Fields.DLA,
> > +        PresState.Fields.WTA,
> > +        PresState.Fields.RTA,
> > +        PresState.Fields.BWEN,
> > +        PresState.Fields.BREN,
> > +        PresState.Fields.CINST,
> > +        PresState.Fields.DLSL);
> > +
> > +DEBUG_CODE_END ();
> > +}
> > +
> > +EFI_STATUS
> > +WaitForReadFifo(
> > +    IN USDHC_PRIVATE_CONTEXT *SdhcCtx
> > +    )
> > +{
> > +    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> > +    USDHC_INT_STATUS_REG IntStatus; IntStatus.AsUint32 =
> MmioRead32((UINTN)&Reg->INT_STATUS);
> > +    UINT32 Retry = USDHC_POLL_RETRY_COUNT;
> > +
> > +    while (!IntStatus.Fields.BRR &&
> > +        !(IntStatus.AsUint32 & USDHC_INT_STATUS_ERROR) &&
> > +        Retry) {
> 
> Would looke better with all tests horizontally aligned.
> 
> > +       --Retry;
> > +       gBS->Stall(USDHC_POLL_WAIT_US);
> > +       IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS);
> > +    }
> > +
> > +    if (IntStatus.AsUint32 & USDHC_INT_STATUS_ERROR) {
> > +        LOG_ERROR("Error detected");
> > +        DumpState(SdhcCtx);
> > +        return EFI_DEVICE_ERROR;
> > +    } else if (IntStatus.Fields.BRR) {
> > +        MmioWrite32((UINTN)&Reg->INT_STATUS, IntStatus.AsUint32);
> > +        return EFI_SUCCESS;
> > +    } else {
> > +        ASSERT(!Retry);
> > +        LOG_ERROR("Time-out waiting on read FIFO");
> > +        DumpState(SdhcCtx);
> > +        return EFI_TIMEOUT;
> > +     }
> > +}
> > +
> > +EFI_STATUS
> > +WaitForWriteFifo(
> > +    IN USDHC_PRIVATE_CONTEXT *SdhcCtx
> > +    )
> > +{
> > +    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> > +    USDHC_INT_STATUS_REG IntStatus; IntStatus.AsUint32 =
> MmioRead32((UINTN)&Reg->INT_STATUS) ;
> > +    UINT32 Retry = USDHC_POLL_RETRY_COUNT;
> > +
> > +    while (!IntStatus.Fields.BWR &&
> > +        !(IntStatus.AsUint32 & USDHC_INT_STATUS_ERROR) &&
> > +        Retry) {
> > +       --Retry;
> > +       gBS->Stall(USDHC_POLL_WAIT_US);
> > +       IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS);
> > +    }
> > +
> > +    if (IntStatus.AsUint32 & USDHC_INT_STATUS_ERROR) {
> > +        LOG_ERROR("Error detected");
> > +        DumpState(SdhcCtx);
> > +        return EFI_DEVICE_ERROR;
> > +    } else if (IntStatus.Fields.BWR) {
> > +        MmioWrite32((UINTN)&Reg->INT_STATUS, IntStatus.AsUint32);
> > +        return EFI_SUCCESS;
> > +    } else {
> > +        ASSERT(!Retry);
> > +        LOG_ERROR("Time-out waiting on write FIFO");
> > +        DumpState(SdhcCtx);
> > +        return EFI_TIMEOUT;
> > +    }
> > +}
> > +
> > +EFI_STATUS
> > +WaitForCmdAndOrDataLine(
> > +    IN USDHC_PRIVATE_CONTEXT *SdhcCtx,
> > +    IN const SD_COMMAND *Cmd
> > +    )
> > +{
> > +    BOOLEAN WaitForDataLine;
> > +
> > +    //
> > +    // Waiting on the DATA lines is the default behavior if no CMD is
> specified
> > +    //
> > +    if (Cmd == NULL) {
> > +        WaitForDataLine = TRUE;
> > +    } else {
> > +        //
> > +        // Per datasheet, the SDHC can isssue CMD0, CMD12, CMD13 and
> CMD52
> > +        // when the DATA lines are busy during a data transfer. Other
> commands
> > +        // should wait on the DATA lines before issuing
> > +        //
> > +        switch (Cmd->Index) {
> > +        case 0:
> > +        case 12:
> > +        case 13:
> > +        case 52:
> > +            WaitForDataLine = FALSE;
> > +            break;
> > +        default:
> > +            WaitForDataLine = TRUE;
> > +        }
> > +    }
> > +
> > +    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> > +    USDHC_PRES_STATE_REG PresState; PresState.AsUint32 =
> MmioRead32((UINTN)&Reg->PRES_STATE);
> > +    USDHC_INT_STATUS_REG IntStatus; IntStatus.AsUint32 =
> MmioRead32((UINTN)&Reg->INT_STATUS) ;
> > +    UINT32 Retry = USDHC_POLL_RETRY_COUNT;
> > +
> > +    while (PresState.Fields.CIHB &&
> > +           (!WaitForDataLine || PresState.Fields.CDIHB) &&
> > +           !(IntStatus.AsUint32 & USDHC_INT_STATUS_ERROR) &&
> > +           Retry) {
> > +        gBS->Stall(USDHC_POLL_WAIT_US);
> > +        --Retry;
> > +        PresState.AsUint32 = MmioRead32((UINTN)&Reg->PRES_STATE);
> > +        IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS);
> > +    }
> > +
> > +    if (IntStatus.AsUint32 & USDHC_INT_STATUS_ERROR) {
> > +        LOG_ERROR("Error detected");
> > +        DumpState(SdhcCtx);
> > +        return EFI_DEVICE_ERROR;
> > +    } else if (!(PresState.Fields.CIHB &&
> > +           (!WaitForDataLine || PresState.Fields.CDIHB))) {
> > +           return EFI_SUCCESS;
> > +    } else {
> > +        ASSERT(!Retry);
> > +        LOG_ERROR("Time-out waiting on CMD and/or DATA lines");
> > +        DumpState(SdhcCtx);
> > +        return EFI_TIMEOUT;
> > +    }
> > +}
> > +
> > +EFI_STATUS
> > +WaitForCmdResponse(
> > +    IN USDHC_PRIVATE_CONTEXT *SdhcCtx
> > +    )
> > +{
> > +    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> > +    USDHC_INT_STATUS_REG IntStatus; IntStatus.AsUint32 =
> MmioRead32((UINTN)&Reg->INT_STATUS) ;
> > +    UINT32 Retry = USDHC_POLL_RETRY_COUNT;
> > +
> > +    //
> > +    // Wait for command to finish execution either with success or failure
> > +    //
> > +    while (!IntStatus.Fields.CC &&
> > +           !(IntStatus.AsUint32 & USDHC_INT_STATUS_ERROR) &&
> > +           Retry) {
> > +        gBS->Stall(USDHC_POLL_WAIT_US);
> > +        --Retry;
> > +        IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS);
> > +    }
> > +
> > +    if (IntStatus.AsUint32 & USDHC_INT_STATUS_ERROR) {
> > +        LOG_ERROR("Error detected");
> > +        DumpState(SdhcCtx);
> > +        return EFI_DEVICE_ERROR;
> > +    } else if (IntStatus.Fields.CC) {
> > +        MmioWrite32((UINTN)&Reg->INT_STATUS, IntStatus.AsUint32);
> > +        return EFI_SUCCESS;
> > +    } else {
> > +        ASSERT(!Retry);
> > +        LOG_ERROR("Time-out waiting on command completion");
> > +        DumpState(SdhcCtx);
> > +        return EFI_TIMEOUT;
> > +    }
> > +}
> > +
> > +EFI_STATUS
> > +SdhcSetBusWidth(
> > +  IN EFI_SDHC_PROTOCOL *This,
> > +  IN SD_BUS_WIDTH BusWidth
> > +  )
> > +{
> > +    USDHC_PRIVATE_CONTEXT *SdhcCtx =
> (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
> > +    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> > +    USDHC_PROT_CTRL_REG ProtCtrl; ProtCtrl.AsUint32 =
> MmioRead32((UINTN)&Reg->PROT_CTRL);
> > +
> > +    LOG_TRACE("SdhcSetBusWidth(%d)", BusWidth);
> > +
> > +    switch (BusWidth) {
> > +    case SdBusWidth1Bit:
> > +        ProtCtrl.Fields.DTW = USDHC_PROT_CTRL_DTW_1BIT;
> > +        break;
> > +    case SdBusWidth4Bit:
> > +        ProtCtrl.Fields.DTW = USDHC_PROT_CTRL_DTW_4BIT;
> > +        break;
> > +    case SdBusWidth8Bit:
> > +        ProtCtrl.Fields.DTW = USDHC_PROT_CTRL_DTW_8BIT;
> > +        break;
> > +    default:
> > +        LOG_ASSERT("Invalid bus width");
> > +        return EFI_INVALID_PARAMETER;
> > +    }
> > +
> > +    MmioWrite32((UINTN)&Reg->PROT_CTRL, ProtCtrl.AsUint32);
> > +
> > +    return EFI_SUCCESS;
> > +}
> > +
> > +EFI_STATUS
> > +SdhcSetClock(
> > +    IN EFI_SDHC_PROTOCOL *This,
> > +    IN UINT32 TargetFreqHz
> > +    )
> > +{
> > +    USDHC_PRIVATE_CONTEXT *SdhcCtx =
> (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
> > +
> > +    LOG_TRACE("SdhcSetClock(%dHz)", TargetFreqHz);
> > +
> > +    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> > +    USDHC_SYS_CTRL_REG SysCtrl; SysCtrl.AsUint32 =
> MmioRead32((UINTN)&Reg->SYS_CTRL);
> > +
> > +    //
> > +    // SDCLK = (Base Clock) / (prescaler x divisor)
> > +    //
> > +    UINT32 Prescaler;
> > +    UINT32 Divisor;
> > +    UINT32 SDCLK;
> > +
> > +    USDHC_MIX_CTRL_REG MixCtrl; MixCtrl.AsUint32 =
> MmioRead32((UINTN)&Reg->MIX_CTRL);
> > +
> > +    //
> > +    // Bruteforce to find the best prescaler and divisor that result
> > +    // in SDCLK less than or equal to the requested frequency
> > +    //
> > +    // Allowed |Base clock divided By
> > +    // SDCLKFS |DDR_EN=0   |DDR_EN=1
> > +    // 80h      256         512
> > +    // 40h      128         256
> > +    // 20h      64          128
> > +    // 10h      32          64
> > +    // 08h      16          32
> > +    // 04h      8           16
> > +    // 02h      4           8
> > +    // 01h      2           4
> > +    // 00h      1           2
> > +    //
> > +    const UINT32 PRESCALER_MIN = (MixCtrl.Fields.DDR_EN ? 2 : 1);
> > +    const UINT32 PRESCALER_MAX = (MixCtrl.Fields.DDR_EN ? 512 : 256);;
> > +    const UINT32 DIVISOR_MIN = 1;
> > +    const UINT32 DIVISOR_MAX = 16;
> 
> CONST
> 
> > +    UINT32 MinFreqDistance = 0xFFFFFFFF;
> 
> MAX_UINT32?
> 
> > +    UINT32 FreqDistance;
> > +    UINT32 BestPrescaler = 0;
> > +    UINT32 BestDivisor = 0;
> > +
> > +    //
> > +    // Bruteforce to find the best prescaler and divisor that result
> > +    // in SDCLK less than or equal to the requested frequency
> > +    //
> > +    for (Prescaler = PRESCALER_MAX; Prescaler >= PRESCALER_MIN;
> Prescaler /= 2) {
> > +        for (Divisor = DIVISOR_MIN; Divisor <= DIVISOR_MAX; ++Divisor) {
> > +            SDCLK = USDHC_BASE_CLOCK_FREQ_HZ / (Prescaler * Divisor);
> > +
> > +            //
> > +            // We are not willing to choose clocks higher than the target one
> > +            // to avoid exceeding device limits
> > +            //
> > +            if (SDCLK > TargetFreqHz) {
> > +                continue;
> > +            } else if (SDCLK == TargetFreqHz) {
> > +                BestPrescaler = Prescaler;
> > +                BestDivisor = Divisor;
> > +                break;
> > +            } else {
> > +                FreqDistance = TargetFreqHz - SDCLK;
> > +                if (FreqDistance < MinFreqDistance) {
> > +                    MinFreqDistance = FreqDistance;
> > +                    BestPrescaler = Prescaler;
> > +                    BestDivisor = Divisor;
> > +                }
> > +            }
> > +        }
> > +    }
> > +
> > +    //
> > +    // Wait for clock to become stable before any modifications
> > +    //
> > +    USDHC_PRES_STATE_REG PresState; PresState.AsUint32 =
> MmioRead32((UINTN)&Reg->PRES_STATE);
> > +    UINT32 Retry = USDHC_POLL_RETRY_COUNT;
> > +
> > +    while (!PresState.Fields.SDSTB &&
> > +           Retry) {
> > +        gBS->Stall(USDHC_POLL_WAIT_US);
> > +        --Retry;
> > +        PresState.AsUint32 = MmioRead32((UINTN)&Reg->PRES_STATE);
> > +    }
> > +
> > +    if (!PresState.Fields.SDSTB) {
> > +        ASSERT(!Retry);
> > +        LOG_ERROR("Time-out waiting on SD clock to stabilize");
> > +        DumpState(SdhcCtx);
> > +        return EFI_TIMEOUT;
> > +    }
> > +
> > +    SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
> > +    SysCtrl.Fields.SDCLKFS = BestPrescaler / (MixCtrl.Fields.DDR_EN ? 4 : 2);
> > +    SysCtrl.Fields.DVS = BestDivisor - 1;
> > +
> > +    MmioWrite32((UINTN)&Reg->SYS_CTRL, SysCtrl.AsUint32);
> > +
> > +    SDCLK = USDHC_BASE_CLOCK_FREQ_HZ / (BestPrescaler * BestDivisor);
> > +
> > +    LOG_TRACE(
> > +        "Current SDCLK:%dHz SDCLKFS:0x%x DVS:0x%x",
> > +        SDCLK,
> > +        (UINT32)SysCtrl.Fields.SDCLKFS,
> > +        (UINT32)SysCtrl.Fields.DVS);
> > +
> > +    return EFI_SUCCESS;
> > +}
> > +
> > +BOOLEAN
> > +SdhcIsCardPresent(
> > +    IN EFI_SDHC_PROTOCOL *This
> > +    )
> > +{
> > +    USDHC_PRIVATE_CONTEXT *SdhcCtx =
> (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
> > +    BOOLEAN IsCardPresent;
> > +
> > +    if (SdhcCtx->CardDetectSignal == USDHC_SIGNAL_INTERNAL_PIN) {
> > +        USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> > +        USDHC_PRES_STATE_REG PresState; PresState.AsUint32 =
> MmioRead32((UINTN)&Reg->PRES_STATE);
> > +        IsCardPresent = (PresState.Fields.CINST == 1);
> > +    } else {
> > +        IMX_GPIO_VALUE CardDetectLevel;
> > +        if (USDHC_IS_GPIO_SIGNAL_SOURCE(SdhcCtx->CardDetectSignal)) {
> > +            //
> > +            //Read the state of  CD_B pin for the card socket
> > +            //
> > +            CardDetectLevel =
> > +                ImxGpioRead(
> > +                    SdhcCtx->CardDetectGpioPin.Bank,
> > +                    SdhcCtx->CardDetectGpioPin.IoNumber);
> > +        } else if (SdhcCtx->CardDetectSignal ==
> USDHC_SIGNAL_OVERRIDE_PIN_LOW) {
> > +            CardDetectLevel = IMX_GPIO_LOW;
> > +        } else if (SdhcCtx->CardDetectSignal ==
> USDHC_SIGNAL_OVERRIDE_PIN_HIGH) {
> > +            CardDetectLevel = IMX_GPIO_HIGH;
> > +        } else {
> > +            ASSERT(!"Invalid CardDetect signal source");
> > +            CardDetectLevel = IMX_GPIO_LOW;
> > +        }
> > +
> > +        //
> > +        // When no card is present,  CD_B is pulled-high, and the SDCard
> when
> > +        // inserted will pull CD_B low
> > +        // CD_B=0 means card present, while CD_B=1 means card not present
> > +        //
> > +        IsCardPresent = (CardDetectLevel == IMX_GPIO_LOW);
> > +    }
> > +
> > +  // Enable if needed while trace debugging, otherwise this will flood the
> debug
> > +  // console due to being called periodically every second for each SDHC
> > +#if 0
> > +  LOG_TRACE("SdhcIsCardPresent(): %d", IsCardPresent);
> > +#endif
> 
> That sounds like something to be filtered by setting it to
> DEBUG_VERBOSE, which LOG_TRACE already does.
> 
> > +
> > +    return IsCardPresent;
> > +}
> > +
> > +BOOLEAN
> > +SdhcIsReadOnly(
> > +    IN EFI_SDHC_PROTOCOL *This
> > +    )
> > +{
> > +    USDHC_PRIVATE_CONTEXT *SdhcCtx =
> (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
> > +    BOOLEAN IsReadOnly;
> > +
> > +    if (SdhcCtx->WriteProtectSignal == USDHC_SIGNAL_INTERNAL_PIN) {
> > +        USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> > +        USDHC_PRES_STATE_REG PresState; PresState.AsUint32 =
> MmioRead32((UINTN)&Reg->PRES_STATE);
> > +        IsReadOnly = (PresState.Fields.WPSPL == 0);
> > +    } else {
> > +        IMX_GPIO_VALUE WriteProtectLevel;
> > +        if (USDHC_IS_GPIO_SIGNAL_SOURCE(SdhcCtx->WriteProtectSignal))
> {
> > +            //
> > +            //Read the state of  WP pin for the card socket
> > +            //
> > +            WriteProtectLevel =
> > +                ImxGpioRead(
> > +                    SdhcCtx->WriteProtectGpioPin.Bank,
> > +                    SdhcCtx->WriteProtectGpioPin.IoNumber);
> > +        } else if (SdhcCtx->WriteProtectSignal ==
> USDHC_SIGNAL_OVERRIDE_PIN_LOW) {
> > +            WriteProtectLevel = IMX_GPIO_LOW;
> > +        } else if (SdhcCtx->WriteProtectSignal ==
> USDHC_SIGNAL_OVERRIDE_PIN_HIGH) {
> > +            WriteProtectLevel = IMX_GPIO_HIGH;
> > +        } else {
> > +            ASSERT(!"Invalid WriteProtect signal source");
> > +            WriteProtectLevel = IMX_GPIO_LOW;
> > +        }
> > +
> > +        //
> > +        // When no card is present,  WP is pulled-high, and the SDCard when
> > +        // inserted will pull WP low if WP switch is configured to write enable
> > +        // the SDCard, otherwise it WP will stay pulled-high
> > +        // WP=0 means write enabled, while WP=1 means write protected
> > +        //
> > +         IsReadOnly = (WriteProtectLevel != IMX_GPIO_LOW);
> 
> Indentation (relative to comment).
> 
> > +    }
> > +
> > +    LOG_TRACE("SdhcIsReadOnly(): %d", IsReadOnly);
> > +    return IsReadOnly;
> > +}
> > +
> > +EFI_STATUS
> > +SdhcSendCommand(
> > +    IN EFI_SDHC_PROTOCOL *This,
> > +    IN const SD_COMMAND *Cmd,
> > +    IN UINT32 Argument,
> > +    IN OPTIONAL const SD_COMMAND_XFR_INFO *XfrInfo
> > +    )
> > +{
> > +    EFI_STATUS Status;
> > +    USDHC_PRIVATE_CONTEXT *SdhcCtx =
> (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
> > +    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> > +
> > +    LOG_TRACE(
> > +        "SdhcSendCommand(%cCMD%d, %08x)",
> > +        ((Cmd->Class == SdCommandClassApp) ? 'A' : ' '),
> > +        (UINT32)Cmd->Index,
> > +        Argument);
> > +
> > +    Status = WaitForCmdAndOrDataLine(SdhcCtx, Cmd);
> > +    if (Status != EFI_SUCCESS) {
> > +        LOG_ERROR("SdhcWaitForCmdAndDataLine failed");
> > +        return Status;
> > +    }
> > +
> > +    //
> > +    // Clear Interrupt status
> > +    //
> > +    MmioWrite32((UINTN)&Reg->INT_STATUS, (UINT32)~0);
> > +
> > +    //
> > +    // Setup data transfer command
> > +    //
> > +    if (XfrInfo) {
> > +        if (XfrInfo->BlockCount > USDHC_MAX_BLOCK_COUNT) {
> > +            LOG_ERROR(
> > +                "Provided %d block count while SDHC max block count is %d",
> > +                XfrInfo->BlockCount,
> > +                USDHC_MAX_BLOCK_COUNT);
> > +            return EFI_INVALID_PARAMETER;
> > +        }
> > +
> > +        //
> > +        // Set block size and count
> > +        //
> > +        USDHC_BLK_ATT_REG BlkAtt = { 0 };
> > +        BlkAtt.Fields.BLKSIZE = XfrInfo->BlockSize;
> > +        ASSERT (XfrInfo->BlockCount > 0);
> > +        BlkAtt.Fields.BLKCNT = XfrInfo->BlockCount;
> > +        MmioWrite32((UINTN)&Reg->BLK_ATT, BlkAtt.AsUint32);
> > +
> > +        //
> > +        // Set transfer parameters
> > +        //
> > +        USDHC_MIX_CTRL_REG MixCtrl = { 0 };
> > +        if (Cmd->TransferDirection == SdTransferDirectionRead) {
> > +            MixCtrl.Fields.DTDSEL = 1;
> > +        }
> > +
> > +        if (XfrInfo->BlockCount > 1) {
> > +            ASSERT((Cmd->TransferType == SdTransferTypeMultiBlock) ||
> > +                (Cmd->TransferType == SdTransferTypeMultiBlockNoStop));
> > +            MixCtrl.Fields.MSBSEL = 1;
> > +            MixCtrl.Fields.BCEN = 1;
> > +        }
> > +
> > +        MmioWrite32((UINTN)&Reg->MIX_CTRL, MixCtrl.AsUint32);
> > +
> > +        USDHC_WTMK_LVL_REG WtmkLvl = { 0 };
> > +
> > +#if 0
> 
> No #if 0 upstream.
> 
> > +        //
> > +        // Set FIFO watermarks
> > +        //
> > +        // Configure FIFO watermark levels to 1/2 the FIFO capacity for read,
> > +        // and 1/3 the FIFO capacity for write.
> > +        // In case the whole transfer can fit in the FIFO, then use
> > +        // the whole transfer length as the FIFO threshold, so we do
> > +        // the read/write in one-shot
> > +        //
> > +
> > +        UINT32 FifoThresholdWordCount;
> > +        if (Cmd->TransferDirection == SdTransferDirectionRead) {
> > +            FifoThresholdWordCount = USDHC_FIFO_MAX_WORD_COUNT / 2;
> > +        } else {
> > +            FifoThresholdWordCount = USDHC_FIFO_MAX_WORD_COUNT / 3;
> > +        }
> > +
> > +        ASSERT(XfrInfo->BlockSize % sizeof(UINT32) == 0);
> > +        UINT32 TransferByteLength = XfrInfo->BlockSize * XfrInfo-
> >BlockCount;
> > +        const UINT32 TransferWordCount = TransferByteLength /
> sizeof(UINT32);
> > +        FifoThresholdWordCount = MIN(TransferWordCount,
> FifoThresholdWordCount);
> > +
> > +        ASSERT(FifoThresholdWordCount <= 0xFFFF);
> > +        const UINT16 Wml = (UINT16)FifoThresholdWordCount;
> > +        ASSERT(Wml <= USDHC_FIFO_MAX_WORD_COUNT);
> > +
> > +        if (Cmd->TransferDirection == SdTransferDirectionRead) {
> > +            WtmkLvl.Fields.RD_WML = (UINT8)Wml;
> > +            WtmkLvl.Fields.RD_BRST_LEN = MIN(Wml, 8);
> > +        } else {
> > +            WtmkLvl.Fields.WR_WML = (UINT8)Wml;
> > +            WtmkLvl.Fields.WR_BRST_LEN = MIN(Wml, 8);;
> > +        }
> > +#endif
> > +
> > +#if 0
> > +        WtmkLvl.Fields.RD_WML = 64;
> > +        WtmkLvl.Fields.RD_BRST_LEN = 16;
> > +        WtmkLvl.Fields.WR_WML = 64;
> > +        WtmkLvl.Fields.WR_BRST_LEN = 16;
> > +#endif
> > +
> > +        UINT32 WtmkThreshold = USDHC_BLOCK_LENGTH_BYTES / 4;
> > +        if (Cmd->TransferDirection == SdTransferDirectionRead) {
> > +            if (WtmkThreshold > USDHC_WTMK_RD_WML_MAX_VAL) {
> > +                WtmkThreshold = USDHC_WTMK_RD_WML_MAX_VAL;
> > +            }
> > +            WtmkLvl.Fields.RD_WML = WtmkThreshold;
> > +        } else {
> > +            if (WtmkThreshold > USDHC_WTMK_WR_WML_MAX_VAL) {
> > +                WtmkThreshold = USDHC_WTMK_WR_WML_MAX_VAL;
> > +            }
> > +            WtmkLvl.Fields.WR_WML = WtmkThreshold;
> > +        }
> > +
> > +        MmioWrite32((UINTN)&Reg->WTMK_LVL, WtmkLvl.AsUint32);
> > +    }
> > +
> > +    //
> > +    // Set CMD parameters
> > +    //
> > +    USDHC_CMD_XFR_TYP_REG CmdXfrTyp = { 0 };
> > +    CmdXfrTyp.Fields.CMDINX = Cmd->Index;
> > +
> > +    switch (Cmd->ResponseType) {
> > +    case SdResponseTypeNone:
> > +        break;
> > +
> > +    case SdResponseTypeR1:
> > +    case SdResponseTypeR5:
> > +    case SdResponseTypeR6:
> > +        CmdXfrTyp.Fields.RSPTYP = USDHC_CMD_XFR_TYP_RSPTYP_RSP_48;
> > +        CmdXfrTyp.Fields.CICEN = 1;
> > +        CmdXfrTyp.Fields.CCCEN = 1;
> > +        break;
> > +
> > +    case SdResponseTypeR1B:
> > +    case SdResponseTypeR5B:
> > +        CmdXfrTyp.Fields.RSPTYP =
> USDHC_CMD_XFR_TYP_RSPTYP_RSP_48_CHK_BSY;
> > +        CmdXfrTyp.Fields.CICEN = 1;
> > +        CmdXfrTyp.Fields.CCCEN = 1;
> > +        break;
> > +
> > +    case SdResponseTypeR2:
> > +        CmdXfrTyp.Fields.RSPTYP =
> USDHC_CMD_XFR_TYP_RSPTYP_RSP_136;
> > +        CmdXfrTyp.Fields.CCCEN = 1;
> > +        break;
> > +
> > +    case SdResponseTypeR3:
> > +    case SdResponseTypeR4:
> > +        CmdXfrTyp.Fields.RSPTYP = USDHC_CMD_XFR_TYP_RSPTYP_RSP_48;
> > +        break;
> > +
> > +    default:
> > +        LOG_ASSERT("SdhcSendCommand(): Invalid response type");
> > +        return EFI_INVALID_PARAMETER;
> > +    }
> > +
> > +    if (Cmd->Type == SdCommandTypeAbort) {
> > +        CmdXfrTyp.Fields.CMDTYP =
> USDHC_CMD_XFR_TYP_CMDTYP_ABORT;
> > +    }
> > +
> > +    if (XfrInfo) {
> > +        CmdXfrTyp.Fields.DPSEL = 1;
> > +    }
> > +
> > +    //
> > +    // Send command and wait for response
> > +    //
> > +    MmioWrite32((UINTN)&Reg->CMD_ARG, Argument);
> > +    MmioWrite32((UINTN)&Reg->CMD_XFR_TYP, CmdXfrTyp.AsUint32);
> > +
> > +    Status = WaitForCmdResponse(SdhcCtx);
> > +    if (EFI_ERROR(Status)) {
> > +        LOG_ERROR("WaitForCmdResponse() failed. %r", Status);
> > +        return Status;
> > +    }
> > +
> > +    return EFI_SUCCESS;
> > +}
> > +
> > +EFI_STATUS
> > +SdhcReceiveResponse(
> > +    IN EFI_SDHC_PROTOCOL *This,
> > +    IN const SD_COMMAND *Cmd,
> > +    OUT UINT32 *Buffer
> > +    )
> > +{
> > +
> > +    USDHC_PRIVATE_CONTEXT *SdhcCtx =
> (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
> > +
> > +    if (Buffer == NULL) {
> > +        LOG_ERROR("Input Buffer is NULL");
> > +        return EFI_INVALID_PARAMETER;
> > +    }
> > +
> > +    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> > +
> > +    switch (Cmd->ResponseType) {
> > +    case SdResponseTypeNone:
> > +        break;
> > +    case SdResponseTypeR1:
> > +    case SdResponseTypeR1B:
> > +    case SdResponseTypeR3:
> > +    case SdResponseTypeR4:
> > +    case SdResponseTypeR5:
> > +    case SdResponseTypeR5B:
> > +    case SdResponseTypeR6:
> > +        Buffer[0] = MmioRead32((UINTN)&Reg->CMD_RSP0);
> > +        LOG_TRACE(
> > +            "SdhcReceiveResponse(Type: %x), Buffer[0]: %08x",
> > +            Cmd->ResponseType,
> > +            Buffer[0]);
> > +        break;
> > +    case SdResponseTypeR2:
> > +        Buffer[0] = MmioRead32((UINTN)&Reg->CMD_RSP0);
> > +        Buffer[1] = MmioRead32((UINTN)&Reg->CMD_RSP1);
> > +        Buffer[2] = MmioRead32((UINTN)&Reg->CMD_RSP2);
> > +        Buffer[3] = MmioRead32((UINTN)&Reg->CMD_RSP3);
> > +
> > +        LOG_TRACE(
> > +            "SdhcReceiveResponse(Type: %x), Buffer[0-3]: %08x, %08x, %08x,
> %08x",
> > +            Cmd->ResponseType,
> > +            Buffer[0],
> > +            Buffer[1],
> > +            Buffer[2],
> > +            Buffer[3]);
> > +        break;
> > +    default:
> > +        LOG_ASSERT("SdhcReceiveResponse(): Invalid response type");
> > +        return EFI_INVALID_PARAMETER;
> > +    }
> > +
> > +    return EFI_SUCCESS;
> > +}
> > +
> > +EFI_STATUS
> > +SdhcReadBlockData(
> > +    IN EFI_SDHC_PROTOCOL *This,
> > +    IN UINTN LengthInBytes,
> > +    OUT UINT32* Buffer
> > +    )
> > +{
> > +    USDHC_PRIVATE_CONTEXT *SdhcCtx =
> (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
> > +
> > +    LOG_TRACE(
> > +        "SdhcReadBlockData(LengthInBytes: 0x%x, Buffer: 0x%x)",
> > +        LengthInBytes,
> > +        Buffer);
> > +
> > +    ASSERT(Buffer != NULL);
> > +    ASSERT(LengthInBytes % sizeof(UINT32) == 0);
> > +
> > +    UINTN WordIdx = 0;
> > +    UINTN NumWords = LengthInBytes / sizeof(UINT32);
> > +    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> > +    USDHC_WTMK_LVL_REG WtmkLvl; WtmkLvl.AsUint32 =
> MmioRead32((UINTN)&Reg->WTMK_LVL);
> > +    UINT32 FifoWords;
> > +    EFI_STATUS Status;
> > +
> > +    ASSERT(WtmkLvl.Fields.RD_WML > 0);
> > +
> > +    while (WordIdx < NumWords) {
> > +        Status = WaitForReadFifo(SdhcCtx);
> > +        if (EFI_ERROR(Status)) {
> > +            LOG_ERROR(
> > +                "WaitForReadFifo() failed at Word%d. %r",
> > +                (UINT32)WordIdx,
> > +                Status);
> > +            return Status;
> > +        }
> > +
> > +        FifoWords = WtmkLvl.Fields.RD_WML;
> > +        while (WordIdx < NumWords && FifoWords--) {
> > +            Buffer[WordIdx] = MmioRead32((UINTN)&Reg-
> >DATA_BUFF_ACC_PORT);
> > +            ++WordIdx;
> > +        }
> > +    }
> > +
> > +    return EFI_SUCCESS;
> > +}
> > +
> > +EFI_STATUS
> > +SdhcWriteBlockData(
> > +    IN EFI_SDHC_PROTOCOL *This,
> > +    IN UINTN LengthInBytes,
> > +    IN const UINT32* Buffer
> > +    )
> > +{
> > +    USDHC_PRIVATE_CONTEXT *SdhcCtx =
> (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
> > +
> > +    LOG_TRACE(
> > +        "SdhcWriteBlockData(LengthInBytes: 0x%x, Buffer: 0x%x)",
> > +        LengthInBytes,
> > +        Buffer);
> > +
> > +    ASSERT(Buffer != NULL);
> > +    ASSERT(LengthInBytes % USDHC_BLOCK_LENGTH_BYTES == 0);
> > +
> > +    const UINTN BlockWordCount = USDHC_BLOCK_LENGTH_BYTES /
> sizeof(UINT32);
> > +    UINTN NumBlocks = LengthInBytes / USDHC_BLOCK_LENGTH_BYTES;
> > +    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> > +    USDHC_INT_STATUS_REG IntStatus;
> > +    USDHC_PRES_STATE_REG PresState;
> > +    INT32 Timeout = 100000; // Nothing special about that constant
> 
> More of a retry than a timeout?
> 
> > +
> > +    while (NumBlocks > 0) {
> > +        UINTN RemainingWords = BlockWordCount;
> > +        IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS);
> > +        PresState.AsUint32 = MmioRead32((UINTN)&Reg->PRES_STATE);
> > +        while (!PresState.Fields.BWEN && --Timeout);
> 
> Does this need a MemoryFence()?
> 
> > +        if (Timeout <= 0) {
> > +            LOG_ERROR ("Timeout waiting for FIFO PRES_STATE.BWEN flag");
> > +            return EFI_TIMEOUT;
> > +        }
> > +
> > +        while (RemainingWords > 0 && !IntStatus.Fields.TC) {
> > +            MicroSecondDelay (100);
> 
> Does this need a MemoryFence()?
> 
> > +            IntStatus.AsUint32 = MmioRead32((UINTN)&Reg->INT_STATUS);
> > +            MmioWrite32((UINTN)&Reg->DATA_BUFF_ACC_PORT, *Buffer);
> > +            Buffer++;
> > +            RemainingWords--;
> > +        }
> > +        NumBlocks--;
> > +    }
> > +
> > +    return EFI_SUCCESS;
> > +}
> > +
> > +EFI_STATUS
> > +SdhcSoftwareReset(
> > +    IN EFI_SDHC_PROTOCOL *This,
> > +    IN SDHC_RESET_TYPE ResetType
> > +    )
> > +{
> > +    USDHC_PRIVATE_CONTEXT *SdhcCtx =
> (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
> > +    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> > +
> > +    UINT32 Retry;
> > +
> > +    if (ResetType == SdhcResetTypeAll) {
> > +        LOG_TRACE("SdhcSoftwareReset(ALL)");
> > +        //
> > +        // Software reset for ALL
> > +        //
> > +        USDHC_SYS_CTRL_REG SysCtrl; SysCtrl.AsUint32 =
> MmioRead32((UINTN)&Reg->SYS_CTRL);
> > +        SysCtrl.Fields.RSTA = 1;
> > +        MmioWrite32((UINTN)&Reg->SYS_CTRL, SysCtrl.AsUint32);
> > +        Retry = USDHC_POLL_RETRY_COUNT;
> > +        //
> > +        // Wait for reset to complete
> > +        //
> > +        while (SysCtrl.Fields.RSTA && Retry) {
> > +            --Retry;
> > +            gBS->Stall(USDHC_POLL_WAIT_US);
> > +            SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
> > +        }
> > +
> > +        if (SysCtrl.Fields.RSTA) {
> > +            ASSERT(!Retry);
> > +            LOG_ERROR("Time-out waiting on RSTA for self-clear");
> > +            return EFI_TIMEOUT;
> > +        }
> > +
> > +        //
> > +        // Disconnect interrupt signals between SDHC and GIC
> > +        //
> > +        MmioWrite32((UINTN)&Reg->INT_SIGNAL_EN, 0);
> > +
> > +        //
> > +        // Clear and Enable all interrupts
> > +        //
> > +        MmioWrite32((UINTN)&Reg->INT_STATUS, (UINT32)~0);
> > +        MmioWrite32((UINTN)&Reg->INT_STATUS_EN, (UINT32)~0);
> > +
> > +        LOG_TRACE("Waiting for CMD and DATA lines");
> > +
> > +        //
> > +        // Wait for CMD and DATA lines to become available
> > +        //
> > +        EFI_STATUS Status = WaitForCmdAndOrDataLine(SdhcCtx, NULL);
> > +        if (Status != EFI_SUCCESS) {
> > +            LOG_ERROR("SdhcWaitForCmdAndDataLine() failed. %r", Status);
> > +            return Status;
> > +        }
> > +
> > +        //
> > +        // Send 80 clock ticks to power-up the card
> > +        //
> > +        SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
> > +        SysCtrl.Fields.INITA = 1;
> > +        MmioWrite32((UINTN)&Reg->SYS_CTRL, SysCtrl.AsUint32);
> > +        Retry = USDHC_POLL_RETRY_COUNT;
> > +
> > +        //
> > +        // Wait for the 80 clock ticks to complete
> > +        //
> > +        while (SysCtrl.Fields.INITA && Retry) {
> > +            --Retry;
> > +            gBS->Stall(USDHC_POLL_WAIT_US);
> > +            SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
> > +        }
> > +
> > +        if (SysCtrl.Fields.INITA) {
> > +            ASSERT(!Retry);
> > +            LOG_ERROR("Time-out waiting on INITA for self-clear");
> > +            return EFI_TIMEOUT;
> > +        }
> > +
> > +        LOG_TRACE("Card power-up complete");
> > +
> > +        //
> > +        // Set max data-timout counter value
> > +        //
> > +        SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
> > +        SysCtrl.Fields.DTOCV = 0xF;
> > +        MmioWrite32((UINTN)&Reg->SYS_CTRL, SysCtrl.AsUint32);
> > +
> > +        //
> > +        // Reset Mixer Control
> > +        //
> > +        MmioWrite32((UINTN)&Reg->MIX_CTRL, 0);
> > +
> > +        USDHC_PROT_CTRL_REG ProtCtrl = { 0 };
> > +        ProtCtrl.Fields.EMODE =
> USDHC_PROT_CTRL_EMODE_LITTLE_ENDIAN;
> > +        ProtCtrl.Fields.LCTL = 1;
> > +        MmioWrite32((UINTN)&Reg->PROT_CTRL, ProtCtrl.AsUint32);
> > +
> > +        LOG_TRACE("Reset ALL complete");
> > +
> > +    }else if (ResetType == SdhcResetTypeCmd) {
> > +        LOG_TRACE("SdhcSoftwareReset(CMD)");
> > +        //
> > +        // Software reset for CMD
> > +        //
> > +        USDHC_SYS_CTRL_REG SysCtrl; SysCtrl.AsUint32 =
> MmioRead32((UINTN)&Reg->SYS_CTRL);
> > +        SysCtrl.Fields.RSTC = 1;
> > +        MmioWrite32((UINTN)&Reg->SYS_CTRL, SysCtrl.AsUint32);
> > +        Retry = USDHC_POLL_RETRY_COUNT;
> > +
> > +        //
> > +        // Wait for reset to complete
> > +        //
> > +        while (SysCtrl.Fields.RSTC && Retry) {
> > +            --Retry;
> > +            gBS->Stall(USDHC_POLL_WAIT_US);
> > +            SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
> > +        }
> > +
> > +        if (SysCtrl.Fields.RSTC) {
> > +            ASSERT(!Retry);
> > +            LOG_ERROR("Time-out waiting on RSTC for self-clear");
> > +            return EFI_TIMEOUT;
> > +        }
> > +
> > +        MmioWrite32((UINTN)&Reg->INT_STATUS, (UINT32)~0);
> > +
> > +        LOG_TRACE("Reset CMD complete");
> > +
> > +    } else if (ResetType == SdhcResetTypeData) {
> > +        LOG_TRACE("SdhcSoftwareReset(DAT)");
> > +        //
> > +        // Software reset for DAT
> > +        //
> > +        USDHC_SYS_CTRL_REG SysCtrl; SysCtrl.AsUint32 =
> MmioRead32((UINTN)&Reg->SYS_CTRL);
> > +        SysCtrl.Fields.RSTD = 1;
> > +        MmioWrite32((UINTN)&Reg->SYS_CTRL, SysCtrl.AsUint32);
> > +        Retry = USDHC_POLL_RETRY_COUNT;
> > +
> > +        //
> > +        // Wait for reset to complete
> > +        //
> > +        while (SysCtrl.Fields.RSTD && Retry) {
> > +            --Retry;
> > +            gBS->Stall(USDHC_POLL_WAIT_US);
> > +            SysCtrl.AsUint32 = MmioRead32((UINTN)&Reg->SYS_CTRL);
> > +        }
> > +
> > +        if (SysCtrl.Fields.RSTD) {
> > +            ASSERT(!Retry);
> > +            LOG_ERROR("Time-out waiting on RSTD for self-clear");
> > +            return EFI_TIMEOUT;
> > +        }
> > +
> > +        MmioWrite32((UINTN)&Reg->INT_STATUS, (UINT32)~0);
> > +
> > +        LOG_TRACE("Reset DAT complete");
> > +
> > +    } else {
> > +        return EFI_INVALID_PARAMETER;
> > +    }
> > +
> > +    return EFI_SUCCESS;
> > +}
> > +
> > +VOID
> > +SdhcCleanup(
> > +    IN EFI_SDHC_PROTOCOL *This
> > +    )
> > +{
> > +    if (This->PrivateContext != NULL) {
> > +        FreePool(This->PrivateContext);
> > +        This->PrivateContext = NULL;
> > +    }
> > +
> > +    FreePool(This);
> > +
> > +    //
> > +    // Any SDHC protocol call to this instance is illegal beyond this point
> > +    //
> > +}
> > +
> > +VOID
> > +SdhcGetCapabilities(
> > +    IN EFI_SDHC_PROTOCOL *This,
> > +    OUT SDHC_CAPABILITIES *Capabilities
> > +  )
> > +{
> > +    USDHC_PRIVATE_CONTEXT *SdhcCtx =
> (USDHC_PRIVATE_CONTEXT*)This->PrivateContext;
> > +    USDHC_REGISTERS *Reg = SdhcCtx->RegistersBase;
> > +
> > +    USDHC_HOST_CTRL_CAP_REG Caps; Caps.AsUint32 =
> MmioRead32((UINTN)&Reg->HOST_CTRL_CAP);
> > +
> > +    Capabilities->MaximumBlockSize = (UINT32)(512 << Caps.Fields.MBL);
> > +    Capabilities->MaximumBlockCount = 0xFFFF; // UINT16_MAX
> > +}
> > +
> > +
> > +EFI_SDHC_PROTOCOL gSdhcProtocolTemplate =
> 
> g - is this really supposed to be globally visible to external
> modules? Or could this be m for module-level visibility?
> 
> It looks like it is only used in this file in fact, so could it be STATIC?
> 
> > +{
> 
> On previous line?
> 
> > +    SDHC_PROTOCOL_INTERFACE_REVISION,   // Revision
> > +    0,                                  // DeviceId
> > +    NULL,                               // PrivateContext
> > +    SdhcGetCapabilities,
> > +    SdhcSoftwareReset,
> > +    SdhcSetClock,
> > +    SdhcSetBusWidth,
> > +    SdhcIsCardPresent,
> > +    SdhcIsReadOnly,
> > +    SdhcSendCommand,
> > +    SdhcReceiveResponse,
> > +    SdhcReadBlockData,
> > +    SdhcWriteBlockData,
> > +    SdhcCleanup
> > +};
> > +
> > +EFI_STATUS
> > +uSdhcDeviceRegister(
> > +    IN EFI_HANDLE ImageHandle,
> > +    IN UINT32 SdhcId,
> > +    IN VOID* RegistersBase,
> > +    IN USDHC_SIGNAL_SOURCE CardDetectSignal,
> > +    IN USDHC_SIGNAL_SOURCE WriteProtectSignal
> > +    )
> > +{
> > +    EFI_STATUS Status;
> > +    EFI_SDHC_PROTOCOL *SdhcProtocol = NULL;
> > +    USDHC_PRIVATE_CONTEXT *SdhcCtx = NULL;
> > +
> > +    if (ImageHandle == NULL ||
> > +        RegistersBase == NULL) {
> > +        Status = EFI_INVALID_PARAMETER;
> > +        goto Exit;
> > +    }
> > +
> > +    //
> > +    // Allocate per-device SDHC protocol and private context storage
> > +    //
> > +
> > +    SdhcProtocol = AllocateCopyPool(sizeof(EFI_SDHC_PROTOCOL),
> &gSdhcProtocolTemplate);
> 
> Some very long lines in this function.
> Please break at 80 characters (where readability is not obviously
> improved by keeping longer line - such as for keeping output strings
> searchable).
> 
> > +    if (SdhcProtocol == NULL) {
> > +        Status =  EFI_OUT_OF_RESOURCES;
> > +        goto Exit;
> > +    }
> > +    SdhcProtocol->SdhcId = SdhcId;
> > +    SdhcProtocol->PrivateContext =
> AllocateZeroPool(sizeof(USDHC_PRIVATE_CONTEXT));
> > +    if (SdhcProtocol->PrivateContext == NULL) {
> > +        Status = EFI_OUT_OF_RESOURCES;
> > +        goto Exit;
> > +    }
> > +
> > +    SdhcCtx = (USDHC_PRIVATE_CONTEXT*)SdhcProtocol->PrivateContext;
> > +    SdhcCtx->SdhcId = SdhcId;
> > +    SdhcCtx->RegistersBase = (USDHC_REGISTERS*)RegistersBase;
> > +    SdhcCtx->CardDetectSignal = CardDetectSignal;
> > +    if (USDHC_IS_GPIO_SIGNAL_SOURCE(SdhcCtx->CardDetectSignal)) {
> > +        SdhcCtx->CardDetectGpioPin.IoNumber =
> PCD_GPIO_PIN_IO_NUMBER((UINT16)CardDetectSignal);
> > +        SdhcCtx->CardDetectGpioPin.Bank =
> PCD_GPIO_PIN_BANK(CardDetectSignal);
> > +    }
> > +
> > +    SdhcCtx->WriteProtectSignal= WriteProtectSignal;
> > +    if (USDHC_IS_GPIO_SIGNAL_SOURCE(SdhcCtx->WriteProtectSignal)) {
> > +        SdhcCtx->WriteProtectGpioPin.IoNumber =
> PCD_GPIO_PIN_IO_NUMBER((UINT16)WriteProtectSignal);
> > +        SdhcCtx->WriteProtectGpioPin.Bank =
> PCD_GPIO_PIN_BANK(WriteProtectSignal);
> > +    }
> > +
> > +    LOG_INFO(
> > +        "Initializing uSDHC%d @%p GPIO CD?:%d WP?:%d",
> > +        SdhcId,
> > +        RegistersBase,
> > +        (USDHC_IS_GPIO_SIGNAL_SOURCE(SdhcCtx->CardDetectSignal) ? 1 :
> 0),
> > +        (USDHC_IS_GPIO_SIGNAL_SOURCE(SdhcCtx->WriteProtectSignal) ? 1
> : 0));
> > +
> > +    if (USDHC_IS_GPIO_SIGNAL_SOURCE(SdhcCtx->CardDetectSignal)) {
> > +      LOG_INFO(
> > +          "Using GPIO%d_IO%d for CardDetect",
> > +          SdhcCtx->CardDetectGpioPin.Bank,
> > +          SdhcCtx->CardDetectGpioPin.IoNumber);
> > +    }
> > +
> > +    if (USDHC_IS_GPIO_SIGNAL_SOURCE(SdhcCtx->WriteProtectSignal)) {
> > +      LOG_INFO(
> > +          "Using GPIO%d_IO%d for WriteProtect",
> > +          SdhcCtx->WriteProtectGpioPin.Bank,
> > +          SdhcCtx->WriteProtectGpioPin.IoNumber);
> > +    }
> > +
> > +    Status = gBS->InstallMultipleProtocolInterfaces(
> > +                                                &SdhcCtx->SdhcProtocolHandle,
> > +                                                &gEfiSdhcProtocolGuid,
> > +                                                SdhcProtocol,
> > +                                                NULL);
> > +    if (EFI_ERROR(Status)) {
> > +        LOG_ERROR("InstallMultipleProtocolInterfaces failed. %r", Status);
> > +        goto Exit;
> > +    }
> > +
> > +Exit:
> > +    if (EFI_ERROR(Status)) {
> > +        LOG_ERROR("Failed to register and initialize uSDHC%d", SdhcId);
> > +
> > +        if (SdhcProtocol != NULL && SdhcProtocol->PrivateContext != NULL) {
> > +            FreePool(SdhcProtocol->PrivateContext);
> > +            SdhcProtocol->PrivateContext = NULL;
> > +        }
> > +
> > +        if (SdhcProtocol != NULL) {
> > +            FreePool(SdhcProtocol);
> > +            SdhcProtocol = NULL;
> > +        }
> > +    }
> > +
> > +    return Status;
> > +}
> > +
> > +EFI_STATUS
> > +SdhcInitialize(
> > +    IN EFI_HANDLE ImageHandle,
> > +    IN EFI_SYSTEM_TABLE *SystemTable
> > +    )
> > +{
> > +    EFI_STATUS Status = EFI_SUCCESS;
> > +    UINT32 uSdhcRegisteredCount = 0;
> > +
> > +    //
> > +    // Register uSDHC1 through uSDHC4 if their base address is non-zero
> > +    //
> 
> Can this hardwiring be moved out of the driver and into platform init
> code using NonDiscoverableDeviceRegistrationLib, as per this
> (unrelated) thread from earlier this year:
> https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flists.01
> .org%2Fpipermail%2Fedk2-devel%2F2018-
> April%2F023922.html&amp;data=02%7C01%7CChristopher.Co%40microsoft.c
> om%7Cc0f078beab2c4534017c08d5f7c9f5f5%7C72f988bf86f141af91ab2d7cd0
> 11db47%7C1%7C0%7C636687369157661520&amp;sdata=XJZ6%2BU7ZlTuv8f7
> 5Si5LLthif2Q4bnBbF13Gdbu6sXY%3D&amp;reserved=0
> ?
> 
> > +
> > +    //
> > +    // uSDHC1
> > +    //
> > +    if (FixedPcdGet32(PcdSdhc1Enable)) {
> > +        Status = uSdhcDeviceRegister(
> > +            ImageHandle,
> > +            1,
> > +            (VOID*)FixedPcdGet32(PcdSdhc1Base),
> > +            FixedPcdGet32(PcdSdhc1CardDetectSignal),
> > +            FixedPcdGet32(PcdSdhc1WriteProtectSignal));
> > +        if (!EFI_ERROR(Status)) {
> > +            ++uSdhcRegisteredCount;
> > +        }
> > +    }
> > +
> > +    //
> > +    // uSDHC2
> > +    //
> > +    if (FixedPcdGet32(PcdSdhc2Enable)) {
> > +        Status = uSdhcDeviceRegister(
> > +            ImageHandle,
> > +            2,
> > +            (VOID*)FixedPcdGet32(PcdSdhc2Base),
> > +            FixedPcdGet32(PcdSdhc2CardDetectSignal),
> > +            FixedPcdGet32(PcdSdhc2WriteProtectSignal));
> > +        if (!EFI_ERROR(Status)) {
> > +            ++uSdhcRegisteredCount;
> > +        }
> > +    }
> > +
> > +    //
> > +    // uSDHC3
> > +    //
> > +    if (FixedPcdGet32(PcdSdhc3Enable)) {
> > +        Status = uSdhcDeviceRegister(
> > +            ImageHandle,
> > +            3,
> > +            (VOID*)FixedPcdGet32(PcdSdhc3Base),
> > +            FixedPcdGet32(PcdSdhc3CardDetectSignal),
> > +            FixedPcdGet32(PcdSdhc3WriteProtectSignal));
> > +        if (!EFI_ERROR(Status)) {
> > +            ++uSdhcRegisteredCount;
> > +        }
> > +    }
> > +
> > +    //
> > +    // uSDHC4
> > +    //
> > +    if (FixedPcdGet32(PcdSdhc4Enable)) {
> > +        Status = uSdhcDeviceRegister(
> > +            ImageHandle,
> > +            4,
> > +            (VOID*)FixedPcdGet32(PcdSdhc4Base),
> > +            FixedPcdGet32(PcdSdhc4CardDetectSignal),
> > +            FixedPcdGet32(PcdSdhc4WriteProtectSignal));
> > +        if (!EFI_ERROR(Status)) {
> > +            ++uSdhcRegisteredCount;
> > +        }
> > +    }
> > +
> > +    //
> > +    // Succeed driver loading if at least one enabled uSDHC got registered
> successfully
> > +    //
> > +    if ((Status != EFI_SUCCESS) && (uSdhcRegisteredCount > 0)) {
> > +        Status = EFI_SUCCESS;
> > +    }
> > +
> > +    return Status;
> > +}
> > diff --git a/Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.inf
> b/Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.inf
> > new file mode 100644
> > index 000000000000..5aee8b2ffbde
> > --- /dev/null
> > +++ b/Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.inf
> > @@ -0,0 +1,67 @@
> > +## @file
> > +#
> > +#  Copyright (c) Microsoft Corporation. All rights reserved.
> > +#
> > +#  This program and the accompanying materials
> > +#  are licensed and made available under the terms and conditions of the
> BSD License
> > +#  which accompanies this distribution.  The full text of the license may be
> found at
> > +#
> https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fopenso
> urce.org%2Flicenses%2Fbsd-
> license.php&amp;data=02%7C01%7CChristopher.Co%40microsoft.com%7Cc0
> f078beab2c4534017c08d5f7c9f5f5%7C72f988bf86f141af91ab2d7cd011db47%7
> C1%7C0%7C636687369157661520&amp;sdata=noPZDlLAGlOgwhpiKbfxZk%2B
> OPT6KNdeBtEi8VELsugQ%3D&amp;reserved=0
> > +#
> > +#  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
> 
> 0x0001001a
> 
> > +  BASE_NAME                      = SdhcDxe
> > +  FILE_GUID                      = A9945BAB-78C9-43C9-9175-F576CA189870
> > +  MODULE_TYPE                    = DXE_DRIVER
> > +  VERSION_STRING                 = 1.0
> > +  ENTRY_POINT                    = SdhcInitialize
> > +
> > +[Sources.common]
> > +  SdhcDxe.c
> > +
> > +[Packages]
> > +  MdePkg/MdePkg.dec
> > +  EmbeddedPkg/EmbeddedPkg.dec
> > +  Silicon/NXP/iMXPlatformPkg/iMXPlatformPkg.dec
> > +  Platform/Microsoft/MsPkg.dec
> 
> Sorted alphabetically, please.
> 
> > +
> > +[LibraryClasses]
> > +  PcdLib
> > +  UefiLib
> > +  UefiDriverEntryPoint
> > +  MemoryAllocationLib
> > +  IoLib
> > +  iMXIoMuxLib
> 
> Sorted alphabetically, please.
> 
> > +
> > +[Guids]
> > +
> > +[Protocols]
> > +  gEfiSdhcProtocolGuid
> > +
> > +[Pcd]
> > +  giMXPlatformTokenSpaceGuid.PcdSdhc1Base
> > +  giMXPlatformTokenSpaceGuid.PcdSdhc2Base
> > +  giMXPlatformTokenSpaceGuid.PcdSdhc3Base
> > +  giMXPlatformTokenSpaceGuid.PcdSdhc4Base
> > +  giMXPlatformTokenSpaceGuid.PcdSdhc1Enable
> > +  giMXPlatformTokenSpaceGuid.PcdSdhc2Enable
> > +  giMXPlatformTokenSpaceGuid.PcdSdhc3Enable
> > +  giMXPlatformTokenSpaceGuid.PcdSdhc4Enable
> > +  giMXPlatformTokenSpaceGuid.PcdSdhc1CardDetectSignal
> > +  giMXPlatformTokenSpaceGuid.PcdSdhc1WriteProtectSignal
> > +  giMXPlatformTokenSpaceGuid.PcdSdhc2CardDetectSignal
> > +  giMXPlatformTokenSpaceGuid.PcdSdhc2WriteProtectSignal
> > +  giMXPlatformTokenSpaceGuid.PcdSdhc3CardDetectSignal
> > +  giMXPlatformTokenSpaceGuid.PcdSdhc3WriteProtectSignal
> > +  giMXPlatformTokenSpaceGuid.PcdSdhc4CardDetectSignal
> > +  giMXPlatformTokenSpaceGuid.PcdSdhc4WriteProtectSignal
> > +
> > +[FixedPcd]
> > +  giMXPlatformTokenSpaceGuid.PcdGpioBankMemoryRange
> > +
> > +[depex]
> > +  TRUE
> > diff --git a/Silicon/NXP/iMXPlatformPkg/Include/iMXGpio.h
> b/Silicon/NXP/iMXPlatformPkg/Include/iMXGpio.h
> > new file mode 100644
> > index 000000000000..c75b543c8bb4
> > --- /dev/null
> > +++ b/Silicon/NXP/iMXPlatformPkg/Include/iMXGpio.h
> > @@ -0,0 +1,101 @@
> > +/** @file
> > +*
> > +*  Copyright (c) Microsoft Corporation. All rights reserved.
> > +*
> > +*  This program and the accompanying materials
> > +*  are licensed and made available under the terms and conditions of the
> BSD License
> > +*  which accompanies this distribution.  The full text of the license may be
> found at
> > +*
> https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fopenso
> urce.org%2Flicenses%2Fbsd-
> license.php&amp;data=02%7C01%7CChristopher.Co%40microsoft.com%7Cc0
> f078beab2c4534017c08d5f7c9f5f5%7C72f988bf86f141af91ab2d7cd011db47%7
> C1%7C0%7C636687369157661520&amp;sdata=noPZDlLAGlOgwhpiKbfxZk%2B
> OPT6KNdeBtEi8VELsugQ%3D&amp;reserved=0
> > +*
> > +*  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 _IMX_GPIO_H_
> > +#define _IMX_GPIO_H_
> > +
> > +#include <Library/PcdLib.h>
> > +
> > +#ifndef C_ASSERT
> > +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
> > +#endif // C_ASSERT
> 
> What's wrong with normal ASSERT?
> 
> > +
> > +typedef enum {
> > +    IMX_GPIO_LOW = 0,
> > +    IMX_GPIO_HIGH = 1
> > +} IMX_GPIO_VALUE;
> > +
> > +typedef enum {
> > +    IMX_GPIO_DIR_INPUT,
> > +    IMX_GPIO_DIR_OUTPUT
> > +} IMX_GPIO_DIR;
> > +
> > +typedef enum {
> > +    IMX_GPIO_BANK1 = 1,
> > +    IMX_GPIO_BANK2,
> > +    IMX_GPIO_BANK3,
> > +    IMX_GPIO_BANK4,
> > +    IMX_GPIO_BANK5,
> > +    IMX_GPIO_BANK6,
> > +    IMX_GPIO_BANK7,
> > +} IMX_GPIO_BANK;
> > +
> > +#pragma pack(push, 1)
> > +
> > +//
> > +// GPIO reserved size is based on total size minus 8 DWORD of standard
> GPIO reg
> > +//
> > +C_ASSERT((FixedPcdGet32(PcdGpioBankMemoryRange) % 4) == 0);
> > +
> > +#define GPIO_RESERVED_SIZE \
> > +    ((FixedPcdGet32(PcdGpioBankMemoryRange) / 4) - 8)
> > +
> > +typedef struct {
> > +    UINT32 DR;                            // 0x00 GPIO data register (GPIO1_DR)
> > +    UINT32 GDIR;                          // 0x04 GPIO direction register (GPIO1_GDIR)
> > +    UINT32 PSR;                           // 0x08 GPIO pad status register (GPIO1_PSR)
> > +    UINT32 ICR1;                          // 0x0C GPIO interrupt configuration register1
> (GPIO1_ICR1)
> > +    UINT32 ICR2;                          // 0x10 GPIO interrupt configuration register2
> (GPIO1_ICR2)
> > +    UINT32 IMR;                           // 0x14 GPIO interrupt mask register
> (GPIO1_IMR)
> > +    UINT32 ISR;                           // 0x18 GPIO interrupt status register
> (GPIO1_ISR)
> > +    UINT32 EDGE_SEL;                      // 0x1C GPIO edge select register
> (GPIO1_EDGE_SEL)
> > +    UINT32 reserved[GPIO_RESERVED_SIZE];
> > +} IMX_GPIO_BANK_REGISTERS;
> > +
> > +#pragma pack(pop)
> > +
> > +typedef struct {
> > +    IMX_GPIO_BANK_REGISTERS Banks[7];
> > +} IMX_GPIO_REGISTERS;
> > +
> > +/**
> > +    Set the specified GPIO to the specified direction.
> > +**/
> > +VOID
> > +ImxGpioDirection (
> > +    IMX_GPIO_BANK Bank,
> > +    UINT32 IoNumber,
> > +    IMX_GPIO_DIR Direction
> > +    );
> > +
> > +/**
> > +    Write a value to a GPIO pin.
> > +**/
> > +VOID
> > +ImxGpioWrite (
> > +    IMX_GPIO_BANK Bank,
> > +    UINT32 IoNumber,
> > +    IMX_GPIO_VALUE Value
> > +    );
> > +
> > +/**
> > +    Read a GPIO pin input value.
> > +**/
> > +IMX_GPIO_VALUE
> > +ImxGpioRead (
> > +    IMX_GPIO_BANK Bank,
> > +    UINT32 IoNumber
> > +    );
> > +
> > +#endif
> > diff --git a/Silicon/NXP/iMXPlatformPkg/Include/iMXuSdhc.h
> b/Silicon/NXP/iMXPlatformPkg/Include/iMXuSdhc.h
> > new file mode 100644
> > index 000000000000..acdbcd324631
> > --- /dev/null
> > +++ b/Silicon/NXP/iMXPlatformPkg/Include/iMXuSdhc.h
> > @@ -0,0 +1,277 @@
> > +/** @file
> > +*
> > +*  Copyright (c) Microsoft Corporation. All rights reserved.
> > +*
> > +*  This program and the accompanying materials
> > +*  are licensed and made available under the terms and conditions of the
> BSD License
> > +*  which accompanies this distribution.  The full text of the license may be
> found at
> > +*
> https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fopenso
> urce.org%2Flicenses%2Fbsd-
> license.php&amp;data=02%7C01%7CChristopher.Co%40microsoft.com%7Cc0
> f078beab2c4534017c08d5f7c9f5f5%7C72f988bf86f141af91ab2d7cd011db47%7
> C1%7C0%7C636687369157661520&amp;sdata=noPZDlLAGlOgwhpiKbfxZk%2B
> OPT6KNdeBtEi8VELsugQ%3D&amp;reserved=0
> > +*
> > +*  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 __IMX_USDHC_H__
> > +#define __IMX_USDHC_H__
> > +
> > +//
> > +// uSDHCx Registers Layout
> > +//
> > +typedef struct {
> > +    UINT32 DS_ADDR;
> > +    UINT32 BLK_ATT;
> > +    UINT32 CMD_ARG;
> > +    UINT32 CMD_XFR_TYP;
> > +    UINT32 CMD_RSP0;
> > +    UINT32 CMD_RSP1;
> > +    UINT32 CMD_RSP2;
> > +    UINT32 CMD_RSP3;
> > +    UINT32 DATA_BUFF_ACC_PORT;
> > +    UINT32 PRES_STATE;
> > +    UINT32 PROT_CTRL;
> > +    UINT32 SYS_CTRL;
> > +    UINT32 INT_STATUS;
> > +    UINT32 INT_STATUS_EN;
> > +    UINT32 INT_SIGNAL_EN;
> > +    UINT32 AUTOCMD12_ERR_STATUS;
> > +    UINT32 HOST_CTRL_CAP;
> > +    UINT32 WTMK_LVL;
> > +    UINT32 MIX_CTRL;
> > +    UINT32 _pad0;
> > +    UINT32 FORCE_EVENT;
> > +    UINT32 ADMA_ERR_STATUS;
> > +    UINT32 ADMA_SYS_ADDR;
> > +    UINT32 _pad1;
> > +    UINT32 DLL_CTRL;
> > +    UINT32 DLL_STATUS;
> > +    UINT32 CLK_TUNE_CTRL_STATUS;
> > +    UINT32 _pad2[21];
> > +    UINT32 VEND_SPEC;
> > +    UINT32 MMC_BOOT;
> > +    UINT32 VEND_SPEC2;
> > +} USDHC_REGISTERS;
> > +
> > +//
> > +// Block Attributes uSDHCx_BLK_ATT fields
> > +//
> > +typedef union {
> > +   UINT32 AsUint32;
> > +   struct {
> > +      UINT32 BLKSIZE    : 13; // 0:12
> > +      UINT32 _reserved0 : 3;  // 13:15
> > +      UINT32 BLKCNT     : 16; // 16:31
> > +   } Fields;
> > +} USDHC_BLK_ATT_REG;
> > +
> > +//
> > +// Command Transfer Type uSDHCx_CMD_XFR_TYP fields
> > +//
> > +typedef union {
> > +    UINT32 AsUint32;
> > +    struct {
> > +        UINT32 _reserved0   : 16; // 0:15
> > +        UINT32 RSPTYP       : 2; // 16:17
> > +        UINT32 _reserved1   : 1; // 18
> > +        UINT32 CCCEN        : 1; // 19
> > +        UINT32 CICEN        : 1; // 20
> > +        UINT32 DPSEL        : 1; // 21
> > +        UINT32 CMDTYP       : 2; // 22:23
> > +        UINT32 CMDINX       : 6; // 24:29
> > +        UINT32 _reserved2   : 2; // 30:31
> > +    } Fields;
> > +} USDHC_CMD_XFR_TYP_REG;
> > +
> > +#define USDHC_CMD_XFR_TYP_RSPTYP_NO_RSP          0
> > +#define USDHC_CMD_XFR_TYP_RSPTYP_RSP_136         1
> > +#define USDHC_CMD_XFR_TYP_RSPTYP_RSP_48          2
> > +#define USDHC_CMD_XFR_TYP_RSPTYP_RSP_48_CHK_BSY  3
> > +#define USDHC_CMD_XFR_TYP_CMDTYP_ABORT           3
> > +
> > +//
> > +// System Control uSDHCx_SYS_CTRL fields
> > +//
> > +typedef union {
> > +    UINT32 AsUint32;
> > +    struct {
> > +        UINT32 _reserved0   : 4; // 0:3
> > +        UINT32 DVS          : 4; // 4:7
> > +        UINT32 SDCLKFS      : 8; // 8:15
> > +        UINT32 DTOCV        : 4; // 16:19
> > +        UINT32 _reserved1   : 3; // 20:22
> > +        UINT32 IPP_RST_N    : 1; // 23
> > +        UINT32 RSTA         : 1; // 24
> > +        UINT32 RSTC         : 1; // 25
> > +        UINT32 RSTD         : 1; // 26
> > +        UINT32 INITA        : 1; // 27
> > +        UINT32 _reserved2   : 4; // 28-31
> > +    } Fields;
> > +} USDHC_SYS_CTRL_REG;
> > +
> > +//
> > +// Host Controller Capabilities Register uSDHCx_HOST_CTRL_CAP fields
> > +//
> > +typedef union {
> > +    UINT32 AsUint32;
> > +    struct {
> > +        UINT32 _reserved0       : 16; // 0:15
> > +        UINT32 MBL              : 3; // 16:18
> > +        UINT32 _reserved1       : 1; // 19
> > +        UINT32 ADMAS            : 1; // 20
> > +        UINT32 HSS              : 1; // 21
> > +        UINT32 DMAS             : 1; // 22
> > +        UINT32 SRS              : 1; // 23
> > +        UINT32 VS33             : 1; // 24
> > +        UINT32 VS30             : 1; // 25
> > +        UINT32 VS18             : 1; // 26
> > +        UINT32 _reserved2       : 5; // 27:31
> > +    } Fields;
> > +} USDHC_HOST_CTRL_CAP_REG;
> > +
> > +//
> > +// Watermark Level uSDHCx_WTMK_LVL
> > +//
> > +typedef union {
> > +    UINT32 AsUint32;
> > +    struct {
> > +        UINT32 RD_WML           : 8; // 0:7
> > +        UINT32 RD_BRST_LEN      : 5; // 8:12
> > +        UINT32 _reserved0       : 3; // 13:15
> > +        UINT32 WR_WML           : 8; // 16:23
> > +        UINT32 WR_BRST_LEN      : 5; // 24:28
> > +        UINT32 _reserved1       : 3; // 29:31
> > +    } Fields;
> > +} USDHC_WTMK_LVL_REG;
> > +
> > +#define USDHC_WTMK_RD_WML_MAX_VAL   0x10
> > +#define USDHC_WTMK_WR_WML_MAX_VAL   0x80
> > +
> > +//
> > +// Mixer Control uSDHCx_MIX_CTRL fields
> > +//
> > +typedef union {
> > +    UINT32 AsUint32;
> > +    struct {
> > +        UINT32 DMAEN          : 1; // 0
> > +        UINT32 BCEN           : 1; // 1
> > +        UINT32 AC12EN         : 1; // 2
> > +        UINT32 DDR_EN         : 1; // 3
> > +        UINT32 DTDSEL         : 1; // 4
> > +        UINT32 MSBSEL         : 1; // 5
> > +        UINT32 NIBBLE_POS     : 1; // 6
> > +        UINT32 AC23EN         : 1; // 7
> > +        UINT32 _reserved0     : 14; // 8:21
> > +        UINT32 EXE_TUNE       : 1; // 22
> > +        UINT32 SMP_CLK_SEL    : 1; // 23
> > +        UINT32 AUTO_TUNE_EN   : 1; //24
> > +        UINT32 FBCLK_SEL      : 1; // 25
> > +        UINT32 _reserved1     : 6; // 26-31
> > +    } Fields;
> > +} USDHC_MIX_CTRL_REG;
> > +
> > +//
> > +// Present State uSDHCx_PRES_STATE fields
> > +//
> > +typedef union {
> > +    UINT32 AsUint32;
> > +    struct {
> > +        UINT32 CIHB         : 1; // 0
> > +        UINT32 CDIHB        : 1; // 1
> > +        UINT32 DLA          : 1; // 2
> > +        UINT32 SDSTB        : 1; // 3
> > +        UINT32 IPGOFF       : 1; // 4
> > +        UINT32 HCKOFF       : 1; // 5
> > +        UINT32 PEROFF       : 1; // 6
> > +        UINT32 SDOFF        : 1; // 7
> > +        UINT32 WTA          : 1; // 8
> > +        UINT32 RTA          : 1; // 9
> > +        UINT32 BWEN         : 1; // 10
> > +        UINT32 BREN         : 1; // 11
> > +        UINT32 PTR          : 1; // 12
> > +        UINT32 _reserved0   : 3; // 13:15
> > +        UINT32 CINST        : 1; // 16
> > +        UINT32 _reserved1   : 1; // 17
> > +        UINT32 CDPL         : 1; // 18
> > +        UINT32 WPSPL        : 1; // 19
> > +        UINT32 _reserved2   : 3; // 20:22
> > +        UINT32 CLSL         : 1; // 23
> > +        UINT32 DLSL         : 8; // 24:31
> > +    } Fields;
> > +} USDHC_PRES_STATE_REG;
> > +
> > +//
> > +// Present State uSDHCx_PROT_CTRL fields
> > +//
> > +typedef union {
> > +    UINT32 AsUint32;
> > +    struct {
> > +        UINT32 LCTL             : 1; // 0
> > +        UINT32 DTW              : 2; // 1:2
> > +        UINT32 D3CD             : 1; // 3
> > +        UINT32 EMODE            : 2; // 4:5
> > +        UINT32 CDTL             : 1; // 6
> > +        UINT32 CDSS             : 1; // 7
> > +        UINT32 DMASEL           : 2; // 8:9
> > +        UINT32 _reserved0       : 6; // 10:15
> > +        UINT32 SABGREQ          : 1; // 16
> > +        UINT32 CREQ             : 1; // 17
> > +        UINT32 RWCTL            : 1; // 18
> > +        UINT32 IABG             : 1; // 19
> > +        UINT32 RD_DONE_NO_8CLK  : 1; // 20
> > +        UINT32 _reserved1       : 3; // 21:23
> > +        UINT32 WECINT           : 1; // 24
> > +        UINT32 WECINS           : 1; // 25
> > +        UINT32 WECRM            : 1; // 26
> > +        UINT32 BURST_LEN_EN     : 3; // 27:29
> > +        UINT32 NON_EXACT_BLK_RD : 1; // 30
> > +        UINT32 _reserved2       : 1; // 31
> > +    } Fields;
> > +} USDHC_PROT_CTRL_REG;
> > +
> > +#define USDHC_PROT_CTRL_DTW_1BIT             0x0
> > +#define USDHC_PROT_CTRL_DTW_4BIT             0x1
> > +#define USDHC_PROT_CTRL_DTW_8BIT             0x2
> > +#define USDHC_PROT_CTRL_EMODE_LITTLE_ENDIAN  0x2
> > +
> > +//
> > +// Interrupt Status uSDHCx_INT_STATUS fields
> > +//
> > +typedef union {
> > +    UINT32 AsUint32;
> > +    struct {
> > +        UINT32 CC           : 1; // 0
> > +        UINT32 TC           : 1; // 1
> > +        UINT32 BGE          : 1; // 2
> > +        UINT32 DINT         : 1; // 3
> > +        UINT32 BWR          : 1; // 4
> > +        UINT32 BRR          : 1; // 5
> > +        UINT32 CINS         : 1; // 6
> > +        UINT32 CRM          : 1; // 7
> > +        UINT32 CINT         : 1; // 8
> > +        UINT32 _reserved0   : 3; // 9:11
> > +        UINT32 RTE          : 1; // 12
> > +        UINT32 _reserved1   : 1; // 13
> > +        UINT32 TP           : 1; // 14
> > +        UINT32 _reserved2   : 1; // 15
> > +        UINT32 CTOE         : 1; // 16
> > +        UINT32 CCE          : 1; // 17
> > +        UINT32 CEBE         : 1; // 18
> > +        UINT32 CIE          : 1; // 19
> > +        UINT32 DTOE         : 1; // 20
> > +        UINT32 DCE          : 1; // 21
> > +        UINT32 DEBE         : 1; // 22
> > +        UINT32 _reserved3   : 1; // 23
> > +        UINT32 AC12E        : 1; // 24
> > +        UINT32 _reserved4   : 1; // 25
> > +        UINT32 TNE          : 1; // 26
> > +        UINT32 _reserved5   : 1; // 27
> > +        UINT32 DMAE         : 1; // 28
> > +        UINT32 _reserved6   : 3; // 29:31
> > +    } Fields;
> > +} USDHC_INT_STATUS_REG;
> > +
> > +#define USDHC_INT_STATUS_CMD_ERROR   (BIT16 | BIT17 | BIT18 |
> BIT19)
> > +#define USDHC_INT_STATUS_DATA_ERROR  (BIT20 | BIT21 | BIT22)
> > +#define USDHC_INT_STATUS_ERROR
> (USDHC_INT_STATUS_CMD_ERROR | USDHC_INT_STATUS_DATA_ERROR)
> > +
> > +#endif // __IMX_USDHC_H__
> > --
> > 2.16.2.gvfs.1.33.gf5370f1
> >


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2018-08-01 23:59 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-07-19  4:11 [PATCH edk2-platforms 0/7] Silicon/NXP: Import NXP i.MX platform package Chris Co
2018-07-19  4:11 ` [PATCH edk2-platforms 1/7] Silicon/NXP: Add support for iMX SDHC Chris Co
2018-08-01 16:15   ` Leif Lindholm
2018-08-01 23:59     ` Chris Co
2018-07-19  4:11 ` [PATCH edk2-platforms 2/7] Silicon/NXP: Add iMX display library support Chris Co
2018-07-19  4:11 ` [PATCH edk2-platforms 3/7] Silicon/NXP: Add I2C library support for iMX platforms Chris Co
2018-07-19  4:11 ` [PATCH edk2-platforms 4/7] Silicon/NXP: Add UART " Chris Co
2018-07-19  4:11 ` [PATCH edk2-platforms 5/7] Silicon/NXP: Add Virtual RTC support for IMX platform Chris Co
2018-07-19  4:11 ` [PATCH edk2-platforms 6/7] Silicon/NXP: Add iMXPlatformPkg dec Chris Co
2018-07-19  4:11 ` [PATCH edk2-platforms 7/7] Silicon/NXP: Add headers for other iMX packages to use Chris Co

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox