From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=2a00:1450:4864:20::441; helo=mail-wr1-x441.google.com; envelope-from=leif.lindholm@linaro.org; receiver=edk2-devel@lists.01.org Received: from mail-wr1-x441.google.com (mail-wr1-x441.google.com [IPv6:2a00:1450:4864:20::441]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 5F5AC21191F29 for ; Wed, 5 Dec 2018 02:32:02 -0800 (PST) Received: by mail-wr1-x441.google.com with SMTP id b14so5501130wru.12 for ; Wed, 05 Dec 2018 02:32:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to:user-agent; bh=3kd1D+x7R0Qo0s5pmg5OFDJ+1teYhJqvL4oRNJIjJrE=; b=ZSpOw1OC+kC6VQAzYjodalzD7u1ZiHvVsourzBldqRoBPQatKciac2M5KogFy9zqnf ukOU9CFjrfzZW3NBK4L37ue1WOyCIA5H9zq4Bm6R5JdleSkYrGMN8aft+7hkHXfW16Xd sz1HARU6rdFB/SwJHc9a34dd0zZRw6ZH2f33o= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=3kd1D+x7R0Qo0s5pmg5OFDJ+1teYhJqvL4oRNJIjJrE=; b=BWKqoQngfx4oj+6fkgg9xnBlOD//z58L+sIePSYIKlNf95Nl0rwqHP1PToZzOPBZMS ASztBH4VrksmUxb8TQd3WvSJ6gJj2lWQfOBmohb4XJqHI5p7g8zIP86elOnwt5urJ+hq VXv9KP4NDHmjRbi51mA3sjEiZUXCOqhqaNSF6p3qcxrwJTzD0r+ZSCm6PuFQ13m5lvad 4GKr0kwmIYMo2XnSIGOo7pl0cBRR/VOik8LQ3wDCvDrlgd4qNCr8RUXixIT+FuFMh5bG uOQwo9He/oOLQe33D6QYCJq1duntI0OzOAhxJhQGPXFLdZPfVnX6tL5Rw8aLKvswvi0T 1MfA== X-Gm-Message-State: AA+aEWY3O7o7yUVylJyRVUbaH0KLajRGDnobtmNnoYb4rAt6EMmjFf+P RinFc6Ex3QX+C3jWgeswDFzzrg== X-Google-Smtp-Source: AFSGD/W4g6UnEqrfVx24LWOMofKWqr6JaRJCcrMLxEEDh03CgtnaSGqyAxXutRKOUCglPZZBH1N5tw== X-Received: by 2002:a5d:568c:: with SMTP id f12mr19876140wrv.101.1544005920339; Wed, 05 Dec 2018 02:32:00 -0800 (PST) Received: from bivouac.eciton.net (bivouac.eciton.net. [2a00:1098:0:86:1000:23:0:2]) by smtp.gmail.com with ESMTPSA id q12sm17718512wrx.31.2018.12.05.02.31.58 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Wed, 05 Dec 2018 02:31:58 -0800 (PST) Date: Wed, 5 Dec 2018 10:31:57 +0000 From: Leif Lindholm To: Chris Co Cc: "edk2-devel@lists.01.org" , Ard Biesheuvel , Michael D Kinney Message-ID: <20181205103157.h4hbxm3yw2qnmjle@bivouac.eciton.net> References: <20180921082542.35768-1-christopher.co@microsoft.com> <20180921082542.35768-14-christopher.co@microsoft.com> MIME-Version: 1.0 In-Reply-To: <20180921082542.35768-14-christopher.co@microsoft.com> User-Agent: NeoMutt/20170113 (1.7.2) Subject: Re: [PATCH edk2-platforms 13/27] Silicon/NXP: Add support for iMX SDHC X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 05 Dec 2018 10:32:03 -0000 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Fri, Sep 21, 2018 at 08:26:04AM +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 > Cc: Ard Biesheuvel > Cc: Leif Lindholm > Cc: Michael D Kinney > --- > Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.c | 1246 ++++++++++++++++++++ > Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.h | 81 ++ > Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.inf | 70 ++ > Silicon/NXP/iMXPlatformPkg/Include/iMXuSdhc.h | 277 +++++ > 4 files changed, 1674 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..9fe0bc3792a9 > --- /dev/null > +++ b/Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.c > @@ -0,0 +1,1246 @@ > +/** @file > +* > +* Copyright (c) 2018 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 > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include "SdhcDxe.h" > + > +VOID > +DumpState ( > + IN USDHC_PRIVATE_CONTEXT *SdhcCtx > + ) > +{ > + DEBUG_CODE_BEGIN (); > + > + USDHC_REGISTERS *Reg; Reg->Registers. Alternatively, could just call it Controller. The fact that they're registers is less interesting than whose registers they are. > + USDHC_BLK_ATT_REG BlkAtt; > + UINT32 CmdArg; > + USDHC_CMD_XFR_TYP_REG CmdXfrTyp; > + UINT32 IntSignalEn; > + USDHC_INT_STATUS_REG IntStatus; > + UINT32 IntStatusEn; > + USDHC_MIX_CTRL_REG MixCtrl; > + UINT32 MmcBoot; > + USDHC_PRES_STATE_REG PresState; > + USDHC_PROT_CTRL_REG ProtCtrl; > + USDHC_WTMK_LVL_REG WtmkLvl; > + UINT32 VendSpec; > + UINT32 VendSpec2; > + > + Reg = SdhcCtx->RegistersBase; > + BlkAtt.AsUint32 = MmioRead32 ((UINTN)&Reg->BLK_ATT); > + CmdArg = MmioRead32 ((UINTN)&Reg->CMD_ARG); > + CmdXfrTyp.AsUint32 = MmioRead32 ((UINTN)&Reg->CMD_XFR_TYP); > + ProtCtrl.AsUint32 = MmioRead32 ((UINTN)&Reg->PROT_CTRL); > + WtmkLvl.AsUint32 = MmioRead32 ((UINTN)&Reg->WTMK_LVL); > + MixCtrl.AsUint32 = MmioRead32 ((UINTN)&Reg->MIX_CTRL); > + IntStatusEn = MmioRead32 ((UINTN)&Reg->INT_STATUS_EN); > + IntSignalEn = MmioRead32 ((UINTN)&Reg->INT_SIGNAL_EN); > + VendSpec = MmioRead32 ((UINTN)&Reg->VEND_SPEC); > + MmcBoot = MmioRead32 ((UINTN)&Reg->MMC_BOOT); > + VendSpec2 = MmioRead32 ((UINTN)&Reg->VEND_SPEC2); > + IntStatus.AsUint32 = MmioRead32 ((UINTN)&Reg->INT_STATUS); > + 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; > + USDHC_INT_STATUS_REG IntStatus; > + UINT32 Retry; > + > + Reg = SdhcCtx->RegistersBase; > + IntStatus.AsUint32 = MmioRead32 ((UINTN)&Reg->INT_STATUS); > + 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; > + USDHC_INT_STATUS_REG IntStatus; > + UINT32 Retry; > + > + Reg = SdhcCtx->RegistersBase; > + IntStatus.AsUint32 = MmioRead32 ((UINTN)&Reg->INT_STATUS) ; > + 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 > + ) > +{ > + USDHC_REGISTERS *Reg; > + USDHC_INT_STATUS_REG IntStatus; > + USDHC_PRES_STATE_REG PresState; > + UINT32 Retry; > + 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: Guessing these could be substituted for CMD0, CMD12, CMD13, CMD52? > + WaitForDataLine = FALSE; > + break; > + default: > + WaitForDataLine = TRUE; > + } > + } > + > + Reg = SdhcCtx->RegistersBase; > + PresState.AsUint32 = MmioRead32 ((UINTN)&Reg->PRES_STATE); > + IntStatus.AsUint32 = MmioRead32 ((UINTN)&Reg->INT_STATUS) ; > + 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; > + USDHC_INT_STATUS_REG IntStatus; > + UINT32 Retry; > + > + Reg = SdhcCtx->RegistersBase; > + IntStatus.AsUint32 = MmioRead32 ((UINTN)&Reg->INT_STATUS) ; > + 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_REGISTERS *Reg; > + USDHC_PRIVATE_CONTEXT *SdhcCtx; > + USDHC_PROT_CTRL_REG ProtCtrl; > + > + SdhcCtx = (USDHC_PRIVATE_CONTEXT *)This->PrivateContext; > + Reg = SdhcCtx->RegistersBase; > + 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_REGISTERS *Reg; > + USDHC_PRIVATE_CONTEXT *SdhcCtx; > + UINT32 BestDivisor; > + UINT32 BestPrescaler; > + UINT32 Divisor; > + UINT32 FreqDistance; > + UINT32 MinFreqDistance; > + USDHC_MIX_CTRL_REG MixCtrl; > + UINT32 Prescaler; > + USDHC_PRES_STATE_REG PresState; > + UINT32 Retry; > + UINT32 SdClk; > + USDHC_SYS_CTRL_REG SysCtrl; > + > + SdhcCtx = (USDHC_PRIVATE_CONTEXT *)This->PrivateContext; > + LOG_TRACE ("SdhcSetClock(%dHz)", TargetFreqHz); > + > + Reg = SdhcCtx->RegistersBase; > + SysCtrl.AsUint32 = MmioRead32 ((UINTN)&Reg->SYS_CTRL); > + > + // SdClk = (Base Clock) / (prescaler x divisor) > + 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; > + MinFreqDistance = MAX_UINT32; > + BestPrescaler = 0; > + 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 > + PresState.AsUint32 = MmioRead32 ((UINTN)&Reg->PRES_STATE); > + 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_REGISTERS *Reg; > + USDHC_PRIVATE_CONTEXT *SdhcCtx; > + IMX_GPIO_VALUE CardDetectLevel; > + BOOLEAN IsCardPresent; > + USDHC_PRES_STATE_REG PresState; > + > + SdhcCtx = (USDHC_PRIVATE_CONTEXT *)This->PrivateContext; > + if (SdhcCtx->CardDetectSignal == USDHC_SIGNAL_INTERNAL_PIN) { > + Reg = SdhcCtx->RegistersBase; > + PresState.AsUint32 = MmioRead32 ((UINTN)&Reg->PRES_STATE); > + IsCardPresent = (PresState.Fields.CINST == 1); > + } else { > + 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); > + } > + > + LOG_TRACE ("SdhcIsCardPresent(): %d", IsCardPresent); > + > + return IsCardPresent; > +} > + > +BOOLEAN > +SdhcIsReadOnly ( > + IN EFI_SDHC_PROTOCOL *This > + ) > +{ > + USDHC_REGISTERS *Reg; > + USDHC_PRIVATE_CONTEXT *SdhcCtx; > + BOOLEAN IsReadOnly; > + USDHC_PRES_STATE_REG PresState; > + IMX_GPIO_VALUE WriteProtectLevel; > + > + SdhcCtx = (USDHC_PRIVATE_CONTEXT *)This->PrivateContext; > + > + if (SdhcCtx->WriteProtectSignal == USDHC_SIGNAL_INTERNAL_PIN) { > + Reg = SdhcCtx->RegistersBase; > + PresState.AsUint32 = MmioRead32 ((UINTN)&Reg->PRES_STATE); > + IsReadOnly = (PresState.Fields.WPSPL == 0); > + } else { > + 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 > + ) > +{ > + USDHC_PRIVATE_CONTEXT *SdhcCtx; > + USDHC_REGISTERS *Reg; > + USDHC_BLK_ATT_REG BlkAtt; > + USDHC_CMD_XFR_TYP_REG CmdXfrTyp; > + USDHC_MIX_CTRL_REG MixCtrl; > + EFI_STATUS Status; > + USDHC_WTMK_LVL_REG WtmkLvl; > + UINT32 WtmkThreshold; > + > + SdhcCtx = (USDHC_PRIVATE_CONTEXT *)This->PrivateContext; > + 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 > + BlkAtt.AsUint32 = 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 > + MixCtrl.AsUint32 = 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); > + > + WtmkLvl.AsUint32 = 0; > + > + 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 > + CmdXfrTyp.AsUint32 = 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_REGISTERS *Reg; > + USDHC_PRIVATE_CONTEXT *SdhcCtx; > + > + SdhcCtx = (USDHC_PRIVATE_CONTEXT *)This->PrivateContext; > + > + if (Buffer == NULL) { > + LOG_ERROR ("Input Buffer is NULL"); > + return EFI_INVALID_PARAMETER; > + } > + > + 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_REGISTERS *Reg; > + USDHC_PRIVATE_CONTEXT *SdhcCtx; > + UINT32 FifoWords; > + UINTN NumWords; > + EFI_STATUS Status; > + UINTN WordIdx; > + USDHC_WTMK_LVL_REG WtmkLvl; > + > + 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); > + > + WordIdx = 0; > + NumWords = LengthInBytes / sizeof (UINT32); > + Reg = SdhcCtx->RegistersBase; > + WtmkLvl.AsUint32 = MmioRead32 ((UINTN)&Reg->WTMK_LVL); > + > + 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_REGISTERS *Reg; > + USDHC_PRIVATE_CONTEXT *SdhcCtx; > + USDHC_INT_STATUS_REG IntStatus; > + UINTN NumBlocks; > + USDHC_PRES_STATE_REG PresState; > + UINTN RemainingWords; > + INT32 Retry; > + > + 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); > + NumBlocks = LengthInBytes / USDHC_BLOCK_LENGTH_BYTES; > + Reg = SdhcCtx->RegistersBase; > + Retry = 100000; > + > + while (NumBlocks > 0) { > + RemainingWords = BlockWordCount; > + IntStatus.AsUint32 = MmioRead32 ((UINTN)&Reg->INT_STATUS); > + PresState.AsUint32 = MmioRead32 ((UINTN)&Reg->PRES_STATE); > + while (!PresState.Fields.BWEN && --Retry); > + if (Retry <= 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_REGISTERS *Reg; > + USDHC_PRIVATE_CONTEXT *SdhcCtx; > + USDHC_PROT_CTRL_REG ProtCtrl; > + UINT32 Retry; > + EFI_STATUS Status; > + USDHC_SYS_CTRL_REG SysCtrl; > + > + SdhcCtx = (USDHC_PRIVATE_CONTEXT *)This->PrivateContext; > + Reg = SdhcCtx->RegistersBase; > + > + if (ResetType == SdhcResetTypeAll) { > + LOG_TRACE ("SdhcSoftwareReset(ALL)"); > + // Software reset for ALL > + 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; Why use the prefix -- when the evaluation order doesn't matter? This is inconsistent with other uses in this file, other than ... exactly this pattern seen across several functions. Can this (and any other repeating patterns I haven't spotted) be broken out into STATIC helper functions instead of duplicated? > + 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 > + 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; What does this 1 mean? Can a descriptive #define clarify? > + 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); > + > + ProtCtrl.AsUint32 = 0; > + ProtCtrl.Fields.EMODE = USDHC_PROT_CTRL_EMODE_LITTLE_ENDIAN; > + ProtCtrl.Fields.LCTL = 1; What does this 1 mean? Can a descriptive #define clarify? > + MmioWrite32 ((UINTN)&Reg->PROT_CTRL, ProtCtrl.AsUint32); > + > + LOG_TRACE ("Reset ALL complete"); > + > + } else if (ResetType == SdhcResetTypeCmd) { > + LOG_TRACE ("SdhcSoftwareReset(CMD)"); > + // > + // Software reset for CMD > + // > + SysCtrl.AsUint32 = MmioRead32 ((UINTN)&Reg->SYS_CTRL); > + SysCtrl.Fields.RSTC = 1; What does this 1 mean? Can a descriptive #define clarify? (I'll stop repeating here, but you get the point. Please try to get rid of live-coded numbers.) > + 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 > + 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; Why set this to NULL immediately before freeing the struct containing it? > + } > + > + FreePool (This); > +} > + > +VOID > +SdhcGetCapabilities ( > + IN EFI_SDHC_PROTOCOL *This, > + OUT SDHC_CAPABILITIES *Capabilities > + ) > +{ > + USDHC_REGISTERS *Reg; > + USDHC_PRIVATE_CONTEXT *SdhcCtx; > + USDHC_HOST_CTRL_CAP_REG Caps; > + > + SdhcCtx = (USDHC_PRIVATE_CONTEXT *)This->PrivateContext; > + Reg = SdhcCtx->RegistersBase; > + Caps.AsUint32 = MmioRead32 ((UINTN)&Reg->HOST_CTRL_CAP); > + Capabilities->MaximumBlockSize = (UINT32) (512 << Caps.Fields.MBL); > + Capabilities->MaximumBlockCount = 0xFFFF; > +} > + > +static EFI_SDHC_PROTOCOL mSdhcProtocolTemplate = { STATIC > + SDHC_PROTOCOL_INTERFACE_REVISION, // Revision > + 0, // DeviceId > + NULL, // PrivateContext > + SdhcGetCapabilities, > + SdhcSoftwareReset, > + SdhcSetClock, > + SdhcSetBusWidth, > + SdhcIsCardPresent, > + SdhcIsReadOnly, > + SdhcSendCommand, > + SdhcReceiveResponse, > + SdhcReadBlockData, > + SdhcWriteBlockData, > + SdhcCleanup > +}; > + > +EFI_STATUS > +SdhcDeviceRegister ( > + IN EFI_HANDLE ImageHandle, > + IN UINT32 SdhcId, > + IN VOID *RegistersBase, > + IN USDHC_SIGNAL_SOURCE CardDetectSignal, > + IN USDHC_SIGNAL_SOURCE WriteProtectSignal > + ) > +{ > + USDHC_PRIVATE_CONTEXT *SdhcCtx; > + EFI_SDHC_PROTOCOL *SdhcProtocol; > + EFI_STATUS Status; > + > + SdhcProtocol = NULL; > + 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), > + &mSdhcProtocolTemplate); > + 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); > + } > + Pleas break from here > + 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); > + } to here into a static helper function. > + > + Status = gBS->InstallMultipleProtocolInterfaces ( > + &SdhcCtx->SdhcProtocolHandle, > + &gEfiSdhcProtocolGuid, > + SdhcProtocol, > + NULL); > + if (EFI_ERROR (Status)) { > + LOG_ERROR ("InstallMultipleProtocolInterfaces failed. %r", Status); > + goto Exit; That goto seems excessive. > + } > + > +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; > + } Why not call SdhcCleanup? > + } > + > + return Status; > +} > + > +EFI_STATUS > +SdhcInitialize ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ) > +{ > + UINT32 SdhcRegisteredCount; > + EFI_STATUS Status; > + > + Status = EFI_SUCCESS; > + SdhcRegisteredCount = 0; > + > + // Register uSDHC1 through uSDHC4 if their base address is non-zero > + > + // uSDHC1 > + if (FixedPcdGet32 (PcdSdhc1Enable)) { > + Status = SdhcDeviceRegister ( > + ImageHandle, > + 1, > + (VOID *)FixedPcdGet32 (PcdSdhc1Base), > + FixedPcdGet32 (PcdSdhc1CardDetectSignal), > + FixedPcdGet32 (PcdSdhc1WriteProtectSignal)); > + if (!EFI_ERROR (Status)) { > + ++SdhcRegisteredCount; > + } > + } > + > + // uSDHC2 > + if (FixedPcdGet32 (PcdSdhc2Enable)) { > + Status = SdhcDeviceRegister ( > + ImageHandle, > + 2, > + (VOID *)FixedPcdGet32 (PcdSdhc2Base), > + FixedPcdGet32 (PcdSdhc2CardDetectSignal), > + FixedPcdGet32 (PcdSdhc2WriteProtectSignal)); > + if (!EFI_ERROR (Status)) { > + ++SdhcRegisteredCount; > + } > + } > + > + // uSDHC3 > + if (FixedPcdGet32 (PcdSdhc3Enable)) { > + Status = SdhcDeviceRegister ( > + ImageHandle, > + 3, > + (VOID *)FixedPcdGet32 (PcdSdhc3Base), > + FixedPcdGet32 (PcdSdhc3CardDetectSignal), > + FixedPcdGet32 (PcdSdhc3WriteProtectSignal)); > + if (!EFI_ERROR (Status)) { > + ++SdhcRegisteredCount; > + } > + } > + > + // uSDHC4 > + if (FixedPcdGet32 (PcdSdhc4Enable)) { > + Status = SdhcDeviceRegister ( > + ImageHandle, > + 4, > + (VOID *)FixedPcdGet32 (PcdSdhc4Base), > + FixedPcdGet32 (PcdSdhc4CardDetectSignal), > + FixedPcdGet32 (PcdSdhc4WriteProtectSignal)); > + if (!EFI_ERROR (Status)) { > + ++SdhcRegisteredCount; > + } > + } > + The above needs to be converted into non-discoverable devices and UEFI driver model. > + // Succeed driver loading if at least one enabled uSDHC got registered successfully > + if ((Status != EFI_SUCCESS) && (SdhcRegisteredCount > 0)) { > + Status = EFI_SUCCESS; > + } > + > + return Status; > +} > diff --git a/Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.h b/Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.h > new file mode 100644 > index 000000000000..e3f7fe62b0b6 > --- /dev/null > +++ b/Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.h Ah yeah, this would have helped to see before. Hence the sortOrder file. The whole driver should probablt be renamed iMXSdhcDxe, and files follow form. > @@ -0,0 +1,81 @@ > +/** @file > +* > +* Copyright (c) 2018 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 _SDHC_DXE_H_ > +#define _SDHC_DXE_H_ And include guard IMX_. > + > +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") > + > +// 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 > + > +#endif // _SDHC_DXE_H_ > diff --git a/Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.inf b/Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.inf > new file mode 100644 > index 000000000000..5f29b7a7b7c8 > --- /dev/null > +++ b/Silicon/NXP/iMXPlatformPkg/Drivers/SdhcDxe/SdhcDxe.inf > @@ -0,0 +1,70 @@ > +## @file > +# > +# Copyright (c) 2018 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 = 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] > + EmbeddedPkg/EmbeddedPkg.dec > + MdePkg/MdePkg.dec > + Platform/Microsoft/MsPkg.dec > + Silicon/NXP/iMXPlatformPkg/iMXPlatformPkg.dec > + > +[LibraryClasses] > + iMXIoMuxLib > + IoLib > + MemoryAllocationLib > + PcdLib > + UefiLib > + UefiDriverEntryPoint > + > +[Guids] > + > +[Protocols] > + gEfiSdhcProtocolGuid > + > +[Pcd] > + giMXPlatformTokenSpaceGuid.PcdSdhc1Base > + giMXPlatformTokenSpaceGuid.PcdSdhc1CardDetectSignal > + giMXPlatformTokenSpaceGuid.PcdSdhc1Enable > + giMXPlatformTokenSpaceGuid.PcdSdhc1WriteProtectSignal > + > + giMXPlatformTokenSpaceGuid.PcdSdhc2Base > + giMXPlatformTokenSpaceGuid.PcdSdhc2CardDetectSignal > + giMXPlatformTokenSpaceGuid.PcdSdhc2Enable > + giMXPlatformTokenSpaceGuid.PcdSdhc2WriteProtectSignal > + > + giMXPlatformTokenSpaceGuid.PcdSdhc3Base > + giMXPlatformTokenSpaceGuid.PcdSdhc3CardDetectSignal > + giMXPlatformTokenSpaceGuid.PcdSdhc3Enable > + giMXPlatformTokenSpaceGuid.PcdSdhc3WriteProtectSignal > + > + giMXPlatformTokenSpaceGuid.PcdSdhc4Base > + giMXPlatformTokenSpaceGuid.PcdSdhc4CardDetectSignal > + giMXPlatformTokenSpaceGuid.PcdSdhc4Enable > + giMXPlatformTokenSpaceGuid.PcdSdhc4WriteProtectSignal > + > +[FixedPcd] > + giMXPlatformTokenSpaceGuid.PcdGpioBankMemoryRange > + > +[depex] > + TRUE > diff --git a/Silicon/NXP/iMXPlatformPkg/Include/iMXuSdhc.h b/Silicon/NXP/iMXPlatformPkg/Include/iMXuSdhc.h > new file mode 100644 > index 000000000000..df57159d9d41 > --- /dev/null > +++ b/Silicon/NXP/iMXPlatformPkg/Include/iMXuSdhc.h > @@ -0,0 +1,277 @@ > +/** @file > +* > +* Copyright (c) 2018 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; Struct members should be renamed to CamelCase, throughout. > +} USDHC_REGISTERS; > + > +// > +// Block Attributes uSDHCx_BLK_ATT fields > +// > +typedef union { > + UINT32 AsUint32; Raw, or Data, throughout. / Leif > + 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 >